[
  {
    "path": ".gitattributes",
    "content": "# see http://robots.thoughtbot.com/xcode-and-git-bridging-the-gap\n\n*.pbxproj binary merge=union\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue.md",
    "content": "---\nname: Issue\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nHi!  Please don't ask questions about how to use SLiM on GitHub; instead, please go to the slim-discuss mailing list at https://groups.google.com/g/slim-discuss.  If you have a bug report or feature request, on the other hand, you have found the right place.  Please provide any information that will allow us to reproduce the bug, including a complete SLiM script (if appropriate) that is self-contained, with all defined constants set up in script rather than needing to be passed on the command line.  If the script requires any external files to run, please attach those too, or provide a link to where they can be downloaded.\n\nFor more guidance on how to file a good bug report, you might read \"Ten simple rules for reporting a bug\" (https://doi.org/10.1371/journal.pcbi.1010540).\n\nIncidentally, if you are a new SLiM user and have not yet done the SLiM Workshop, it is highly recommended to get through the initial learning curve.  It is available for free online at http://benhaller.com/workshops/workshops.html.\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: tests\non:\n  # Run tests on every push to the main branch,\n  # on every pull request, and once a week (every monday at 05:00)\n  push:\n  pull_request:\n  schedule:\n    - cron: \"0 5 * * 1\"\njobs:\n  canceller:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Cancel previous runs\n        uses: styfle/cancel-workflow-action@0.12.1\n  coverage:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    runs-on: ubuntu-24.04\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Set up GCC\n        run: |\n          sudo apt-get install gcc-12 g++-12 && \\\n          sudo update-alternatives \\\n            --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 \\\n            --slave /usr/bin/g++ g++ /usr/bin/g++-12\n      - name: Build with coverage\n        run: |\n          mkdir Coverage && cd Coverage && \\\n          cmake -DCMAKE_BUILD_TYPE=Debug -DCOVERAGE=ON .. && \\\n          make -j 2 && \\\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n      - name: Generate coverage report\n        run: |\n          sudo apt-get update && \\\n          sudo apt-get install -y lcov && \\\n          lcov --gcov-tool gcov-12 --ignore-errors gcov,mismatch --rc geninfo_unexecuted_blocks=1 --capture --directory Coverage --output-file coverage.info && \\\n          lcov --gcov-tool gcov-12 --ignore-errors gcov,mismatch,unused --remove coverage.info '/usr/*' '*/gsl/*' '*/eidos_zlib/*' --output-file coverage.info\n      - name: Upload coverage reports to Codecov\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          files: coverage.info\n          fail_ci_if_error: true\n  tests-Unix-CLI:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # Ubuntu with the oldest supported GCC\n          # BCH 2/12/2025: Ubuntu 22.04 is being discontinued, shifting forward\n          - { os: ubuntu-22.04, gcc: 9, python: 3.9 }\n          - { os: ubuntu-24.04, gcc: 12, python: 3.12 }\n          # macOS, oldest supported version\n          # (macos-10.15, macos-11, macos-12, and macos-13 were removed by GitHub)\n          - { os: macos-14, python: 3.9 }\n          # macOS, newest supported version\n          - { os: macos-26, python: 3.13 }\n\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Setup Miniforge\n        uses: conda-incubator/setup-miniconda@v3\n        with:\n          miniforge-version: latest\n          activate-environment: anaconda-client-env\n          python-version: ${{ matrix.python }}\n      - name: Get Date\n        id: get-date\n        run: echo \"today=$(/bin/date -u '+%Y%m%d')\" >> $GITHUB_OUTPUT\n        shell: bash\n      - name: Cache Conda env\n        uses: actions/cache@v3\n        with:\n          path: ${{ env.CONDA }}/envs\n          key:\n            conda-${{ runner.os }}--python-${{ matrix.python }}--${{ runner.arch }}--${{\n            steps.get-date.outputs.today }}-${{\n            hashFiles('treerec/tests/environment.yml') }}-${{ env.CACHE_NUMBER}}\n        env:\n          # Increase this value to reset cache if\n          # treerec/tests/environment.yml has not changed\n          CACHE_NUMBER: 0\n        id: cache\n      - name: Update environment\n        run: conda env update -n anaconda-client-env -f treerec/tests/environment.yml\n        if: steps.cache.outputs.cache-hit != 'true'\n      - name: Workaround for gcc-11\n        if: startsWith(matrix.os, 'ubuntu') && matrix.gcc == 11\n        run: |\n          sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && \\\n          sudo apt-get update -y\n      - name: Set up default GCC (in Ubuntu)\n        if: startsWith(matrix.os, 'ubuntu')\n        run: |\n          sudo apt-get install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} && \\\n          sudo update-alternatives \\\n            --install /usr/bin/gcc gcc /usr/bin/gcc-${{ matrix.gcc }} 100 \\\n            --slave /usr/bin/g++ g++ /usr/bin/g++-${{ matrix.gcc }}\n      - name: Build and test (Debug)\n        run: |\n          mkdir Debug && \\\n          cd Debug && \\\n          cmake -DCMAKE_BUILD_TYPE=Debug .. && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n      - name: Build and test (Release)\n        run: |\n          mkdir Release && \\\n          cd Release && \\\n          cmake -DCMAKE_BUILD_TYPE=Release .. && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n      - name: Treesequence tests\n        shell: bash -el {0}\n        run: |\n          conda activate anaconda-client-env && \\\n          export PATH=$PATH:$PWD/Release && \\\n          echo $PATH && \\\n          cd treerec/tests && python -m pytest -xv\n          \n  tests-Windows-CLI:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    runs-on: windows-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - { sys: mingw64, env: x86_64, python: 3.9 }\n          - { sys: ucrt64, env: ucrt-x86_64, python: 3.9 }\n    defaults:\n      run:\n        shell: msys2 {0}\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Setup MSYS2 ${{matrix.sys}}\n        uses: msys2/setup-msys2@v2\n        with:\n          msystem: ${{matrix.sys}}\n          update: true\n          install: >-\n            git\n            base-devel\n            msys2-devel\n            mingw-w64-${{matrix.env}}-toolchain\n            mingw-w64-${{matrix.env}}-cmake\n      - name: Setup Miniforge\n        uses: conda-incubator/setup-miniconda@v3\n        with:\n          miniforge-version: latest\n          activate-environment: anaconda-client-env\n          auto-update-conda: true\n          python-version: ${{ matrix.python }}\n      - name: Get Date\n        id: get-date\n        run: echo \"today=$(/bin/date -u '+%Y%m%d')\" >> $GITHUB_OUTPUT\n        shell: bash\n      - name: Cache Conda env\n        uses: actions/cache@v3\n        env:\n          # Increase this value to reset cache if treerec/tests/environment.yml has not changed\n          CACHE_NUMBER: 0\n        with:\n          # Use faster GNU tar\n          enableCrossOsArchive: true\n          path: D:\\conda_pkgs_dir\n          key:\n            conda-${{ runner.os }}--python-${{ matrix.python }}--${{ runner.arch }}--${{\n            steps.get-date.outputs.today }}-${{\n            hashFiles('treerec/tests/environment.yml') }}-${{ env.CACHE_NUMBER}}\n        id: cache\n      - uses: conda-incubator/setup-miniconda@v3\n        with:\n          activate-environment: anaconda-client-env\n          environment-file: treerec/tests/environment.yml\n          pkgs-dirs: D:\\conda_pkgs_dir\n      - name: Update environment\n        shell: bash -el {0}\n        run: conda env update -n anaconda-client-env -f treerec/tests/environment.yml\n        if: steps.cache.outputs.cache-hit != 'true'\n      - name: Build and test (Debug)\n        run: |\n          cd windows_compat/gnulib && \\\n          touch --date=\"`date`\" aclocal.m4 Makefile.am configure configure.ac config.h.in Makefile.in && \\\n          cd ../.. && \\\n          mkdir Debug && \\\n          cd Debug && \\\n          cmake -G\"MSYS Makefiles\" -DCMAKE_BUILD_TYPE=Debug .. && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n      - name: Build and test (Release)\n        run: |\n          cd windows_compat/gnulib && \\\n          touch --date=\"`date`\" aclocal.m4 Makefile.am configure configure.ac config.h.in Makefile.in && \\\n          cd ../.. && \\\n          mkdir Release && \\\n          cd Release && \\\n          cmake -G\"MSYS Makefiles\" -DCMAKE_BUILD_TYPE=Release .. && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n      - name: Treesequence tests\n        shell: bash -el {0}\n        run: |\n          conda activate anaconda-client-env && \\\n          export PATH=$PATH:$PWD/Release && \\\n          echo $PATH && \\\n          cd treerec/tests && python -m pytest -xv\n\n  tests-Unix-GUI:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # BCH 2/12/2025: Ubuntu 22.04 is being discontinued, shifting forward\n          # Ubuntu 22.04 with the oldest supported Qt5 and GCC.\n          - { os: ubuntu-22.04, qt: 5.9.5, gcc: 9 }\n          # Ubuntu 22.04 with last official LTS Qt5 and GCC.\n          - { os: ubuntu-22.04, qt: 5.15.2, gcc: 12 }\n          # Ubuntu 24.04 with the most recent Qt6 and GCC.\n          - { os: ubuntu-22.04, qt: 6.8.2, gcc: 12 }\n          # macos-12 and macos-13 were removed by GitHub,\n          # so we can't CI with Qt 5.X on macOS any more, oh well\n          # old macOS with last official LTS Qt5\n          #- { os: macos-13, qt: 5.15.2 }\n          # old macOS ARM64 with older Qt6\n          - { os: macos-14, qt: 6.7.3 }\n          # macOS Intel with older Qt6\n          - { os: macos-15-intel, qt: 6.7.3 }\n          # new macOS with a very recent Qt6\n          - { os: macos-26, qt: 6.9.2 }\n    runs-on: ${{ matrix.os }}\n    env:\n      CXXFLAGS: -D NO_QT_VERSION_ERROR\n    defaults:\n      run:\n        shell: bash\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Workaround for gcc-11\n        if: startsWith(matrix.os, 'ubuntu') && matrix.gcc == 11\n        run: |\n          sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && \\\n          sudo apt-get update -y\n      - name: Set up default GCC (in Ubuntu)\n        if: startsWith(matrix.os, 'ubuntu')\n        run: |\n          sudo apt-get install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} && \\\n          sudo update-alternatives \\\n            --install /usr/bin/gcc gcc /usr/bin/gcc-${{ matrix.gcc }} 100 \\\n            --slave /usr/bin/g++ g++ /usr/bin/g++-${{ matrix.gcc }}\n\n      - name: Install Qt\n        uses: jurplel/install-qt-action@v4\n        with:\n          version: ${{ matrix.qt }}\n      - name: Release build with SLiMGUI\n        run: |\n          mkdir Release && \\\n          cd Release  && \\\n          cmake -D BUILD_SLIMGUI=ON -DCMAKE_BUILD_TYPE=Release ..  && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n\n  tests-Windows-GUI:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - { sys: mingw64, env: x86_64 }\n          - { sys: ucrt64, env: ucrt-x86_64 }\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: msys2 {0}\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Setup MSYS2 ${{matrix.sys}}\n        uses: msys2/setup-msys2@v2\n        with:\n          msystem: ${{matrix.sys}}\n          update: true\n          install: >-\n            git\n            base-devel\n            msys2-devel\n            mingw-w64-${{matrix.env}}-toolchain\n            mingw-w64-${{matrix.env}}-cmake\n            mingw-w64-${{matrix.env}}-qt5-base\n      - name: Release build\n        run: |\n          cd . && \\\n          cd windows_compat/gnulib && \\\n          touch --date=\"`date`\" aclocal.m4 Makefile.am configure configure.ac config.h.in Makefile.in && \\\n          cd ../.. && \\\n          mkdir Release && \\\n          cd Release && \\\n          cmake -G\"MSYS Makefiles\" -DBUILD_SLIMGUI=ON -DCMAKE_BUILD_TYPE=Release .. && \\\n          make -j 2 && \\\n          # Show any output from the test program whenever the test fails\n          env CTEST_OUTPUT_ON_FAILURE=1 make test\n  tests-windows-latest-pacman:\n    if: github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository == 'messerlab/slim')\n    runs-on: windows-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - { sys: mingw64, env: x86_64 }\n          - { sys: ucrt64, env: ucrt-x86_64 }\n    defaults:\n      run:\n        shell: msys2 {0}\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v4\n      - name: Setup MSYS2 ${{matrix.sys}}\n        uses: msys2/setup-msys2@v2\n        with:\n          msystem: ${{matrix.sys}}\n          update: true\n          install: >-\n            mingw-w64-${{matrix.env}}-slim-simulator\n      - name: Test\n        run: |\n          eidos -testEidos\n          slim -testEidos\n          slim -testSLiM\n"
  },
  {
    "path": ".gitignore",
    "content": "#########################\n# .gitignore file for Xcode4 and Xcode5 Source projects\n#\n# Apple bugs, waiting for Apple to fix/respond:\n#\n#    15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation?\n#\n# Version 2.3\n# For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects\n#\n# 2014 updates:\n# - appended non-standard items DISABLED by default (uncomment if you use those tools)\n# - removed the edit that an SO.com moderator made without bothering to ask me\n# - researched CocoaPods .lock more carefully, thanks to Gokhan Celiker\n# 2013 updates:\n# - fixed the broken \"save personal Schemes\"\n# - added line-by-line explanations for EVERYTHING (some were missing)\n#\n# NB: if you are storing \"built\" products, this WILL NOT WORK,\n# and you should use a different .gitignore (or none at all)\n# This file is for SOURCE projects, where there are many extra\n# files that we want to exclude\n#\n#########################\n\n#####\n# OS X temporary files that should never be committed\n#\n# c.f. http://www.westwind.com/reference/os-x/invisibles.html\n\n.DS_Store\n\n# c.f. http://www.westwind.com/reference/os-x/invisibles.html\n\n.Trashes\n\n# c.f. http://www.westwind.com/reference/os-x/invisibles.html\n\n*.swp\n\n#\n# *.lock - this is used and abused by many editors for many different things.\n#    For the main ones I use (e.g. Eclipse), it should be excluded \n#    from source-control, but YMMV.\n#   (lock files are usually local-only file-synchronization on the local FS that should NOT go in git)\n# c.f. the \"OPTIONAL\" section at bottom though, for tool-specific variations!\n\n*.lock\n\n\n#\n# profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?)\n#profile\n\n\n####\n# Xcode temporary files that should never be committed\n# \n# NB: NIB/XIB files still exist even on Storyboard projects, so we want this...\n\n*~.nib\n\n\n####\n# Xcode build files -\n#\n# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named \"DerivedData\"\n\nDerivedData/\n\n# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named \"build\"\n\nbuild/\n\n\n#####\n# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)\n#\n# This is complicated:\n#\n# SOMETIMES you need to put this file in version control.\n# Apple designed it poorly - if you use \"custom executables\", they are\n#  saved in this file.\n# 99% of projects do NOT use those, so they do NOT want to version control this file.\n#  ..but if you're in the 1%, comment out the line \"*.pbxuser\"\n\n# .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html\n\n*.pbxuser\n\n# .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html\n\n*.mode1v3\n\n# .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html\n\n*.mode2v3\n\n# .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file\n\n*.perspectivev3\n\n#    NB: also, whitelist the default ones, some projects need to use these\n!default.pbxuser\n!default.mode1v3\n!default.mode2v3\n!default.perspectivev3\n\n\n####\n# Xcode 4 - semi-personal settings\n#\n#\n# OPTION 1: ---------------------------------\n#     throw away ALL personal settings (including custom schemes!\n#     - unless they are \"shared\")\n#\n# NB: this is exclusive with OPTION 2 below\nxcuserdata\n\n# OPTION 2: ---------------------------------\n#     get rid of ALL personal settings, but KEEP SOME OF THEM\n#     - NB: you must manually uncomment the bits you want to keep\n#\n# NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X,\n#    or manually install git over the top of the OS X version\n# NB: this is exclusive with OPTION 1 above\n#\n#xcuserdata/**/*\n\n#     (requires option 2 above): Personal Schemes\n#\n#!xcuserdata/**/xcschemes/*\n\n####\n# XCode 4 workspaces - more detailed\n#\n# Workspaces are important! They are a core feature of Xcode - don't exclude them :)\n#\n# Workspace layout is quite spammy. For reference:\n#\n# /(root)/\n#   /(project-name).xcodeproj/\n#     project.pbxproj\n#     /project.xcworkspace/\n#       contents.xcworkspacedata\n#       /xcuserdata/\n#         /(your name)/xcuserdatad/\n#           UserInterfaceState.xcuserstate\n#     /xcsshareddata/\n#       /xcschemes/\n#         (shared scheme name).xcscheme\n#     /xcuserdata/\n#       /(your name)/xcuserdatad/\n#         (private scheme).xcscheme\n#         xcschememanagement.plist\n#\n#\n\n####\n# Xcode 4 - Deprecated classes\n#\n# Allegedly, if you manually \"deprecate\" your classes, they get moved here.\n#\n# We're using source-control, so this is a \"feature\" that we do not want!\n\n*.moved-aside\n\n####\n# OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development\n#\n# NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow\n#     modular gitignore: you have to put EVERYTHING in one file.\n#\n# COCOAPODS:\n#\n# c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock\n# c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n#\n#!Podfile.lock\n#\n# RUBY:\n#\n# c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/\n#\n#!Gemfile.lock\n#\n# IDEA:\n#\n#.idea\n#\n# TEXTMATE:\n#\n# -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422\n#\n#tm_build_errors\n\n####\n# UNKNOWN: recommended by others, but I can't discover what these files are\n#\n# Community suggestions (unverified, no evidence available - DISABLED by default)\n#\n# 1. Xcode 5 - VCS file\n#\n# \"The data in this file not represent state of your project.\n# If you'll leave this file in git - you will have merge conflicts during \n# pull your cahnges to other's repo\"\n#\n*.xccheckout\n\n####\n# My Own\n#\n# This keeps a built executable of slim, or a bin directory, from getting added\nslim\nbin\n\n####\n# SonarCloud cruft\nbw-output\n.scannerwork\n\n####\n# Qt cruft from here on down\n\n# C++ objects and libs\n*.slo\n*.lo\n*.o\n*.a\n*.la\n*.lai\n*.so\n*.dll\n*.dylib\n\n# Qt-es\nobject_script.*.Release\nobject_script.*.Debug\n*_plugin_import.cpp\n/.qmake.cache\n/.qmake.stash\n*.pro.user\n*.pro.user.*\n*.qbs.user\n*.qbs.user.*\n*.moc\nmoc_*.cpp\nmoc_*.h\nqrc_*.cpp\nui_*.h\n*.qmlc\n*.jsc\nMakefile*\n*build-*\n!windows_compat/gnulib/build-aux\n!windows_compat/gnulib/Makefile*\n!windows_compat/gnulib/gllib/Makefile*\n!windows_compat/gnulib/glm4/Makefile*\n\n## gnulib\nwindows_compat/gnulib/autom4te.cache\nwindows_compat/gnulib/configure~\n\n# Qt unit tests\ntarget_wrapper.*\n\n# QtCreator\n*.autosave\n\n# QtCreator Qml\n*.qmlproject.user\n*.qmlproject.user.*\n\n# QtCreator CMake\nCMakeLists.txt.user*\n\n# QtCreator 4.8< compilation database \ncompile_commands.json\n\n# QtCreator local machine specific files for imported projects\n*creator.user*\n\n# VSCode\n.vscode"
  },
  {
    "path": ".travis.yml",
    "content": "# the Qt stuff is adapted from https://github.com/VioletGiraffe/file-commander/blob/master/.travis.yml\n# there seems to be no simple solution to building Qt5 apps on travis; you have to install all this stuff\nlanguage: cpp\n\nmatrix:\n  include:\n    - os: osx\n      osx_image: xcode9.4\n      compiler: clang\n    - os: linux\n      dist: xenial\n      compiler: gcc\n\nbefore_install:\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then brew update; fi\n  # C++17\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test; fi\n\ninstall: \n  # C++17\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo add-apt-repository -y ppa:beineri/opt-qt-5.12.3-xenial; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo apt-get -qy update; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo apt-get install -qq g++-8 gcc-8; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 90; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 90; fi\n  # Qt5\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then brew install qt5; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then brew link --force qt5; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then export QMAKE=/usr/local/bin/qmake; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then export PATH=/usr/local/opt/qt5/bin:$PATH; fi\n  \n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo apt-get install -qq qt512-meta-minimal; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then sudo apt-get install -qq libx11-xcb-dev libglu1-mesa-dev; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then export QMAKE=/opt/qt512/bin/qmake; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then export PATH=/opt/qt512/bin/:$PATH; fi\n\n# set up build directories for Release and Debug builds and run cmake in each; \"make\" should then work\n# note that we start out in /home/travis/build/MesserLab/SLiM here, and end in /home/travis/build/MesserLab\nbefore_script:\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then gcc --version; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then g++ --version; fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then clang --version; fi\n\n  - cd ..\n  - mkdir Release\n  - cd Release\n  - cmake -D BUILD_SLIMGUI=ON -D CMAKE_BUILD_TYPE=Release ../SLiM\n  - cd ..\n  - mkdir Debug\n  - cd Debug\n  - cmake -D BUILD_SLIMGUI=ON -D CMAKE_BUILD_TYPE=Debug ../SLiM\n  - cd ..\n\n# build using make, then run Eidos and SLiM tests; do for each of Release and Debug\n# builds can take more than 10 minutes so we use travis_wait\nscript:\n  - cd Release\n  - travis_wait make VERBOSE=1 -j 5 eidos\n  - travis_wait make VERBOSE=1 -j 5 slim\n  - travis_wait make VERBOSE=1 -j 5 SLiMgui\n  - ./eidos -testEidos\n  - ./slim -testEidos\n  - ./slim -testSLiM\n  - cd ../Debug\n  - travis_wait make VERBOSE=1 -j 5 eidos\n  - travis_wait make VERBOSE=1 -j 5 slim\n  - travis_wait make VERBOSE=1 -j 5 SLiMgui\n  - ./eidos -testEidos\n  - ./slim -testEidos\n  - ./slim -testSLiM\n\n# test only the master branch for now; add other branches as needed\nbranches:\n  only:\n    - master\n\n# notify me by email after all builds\nnotifications:\n  email:\n    on_success: always\n    on_failure: always\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# To use CMake to build SLiM, create a new subdirectory alongside your source directory (assumed here\n# to be named SLiM), e.g., \"build\", then run the following commands:\n#\n#   cd build\n#   cmake ../SLiM\n#   make -j10\n#\n# This will make a Release build, with optimization and without debugging symbols, by default.\n# The built executables will be placed in the build directory upon successful completion. The optional\n# -j argument specifies the number of threads to use for the build, which should be a value related \n# to the number of cores available on your machine (typically less than or equal to the number of cores).\n# \n# You can also explicitly make a Release build; this is typically done in a directory named \"Release\"\n# instead of \"build\":\n#\n#   mkdir Release\n#   cd Release\n#   cmake -D CMAKE_BUILD_TYPE=Release ../SLiM\n#   make \n#\n# Or you can make a Debug build (without optimization, with debugging symbols):\n#\n#   mkdir Debug\n#   cd Debug\n#   cmake -D CMAKE_BUILD_TYPE=Debug ../SLiM\n#   make \n#\n# To build the Qt5-based GUI, make sure you have the Qt5 Widgets, Core, and Gui libraries installed,\n# then configure with:\n#   cd build\n#   cmake -D BUILD_SLIMGUI=ON ../SLiM\n#   make -j10\n#\n# In all cases the concept is the same: make a build directory of some name, cd into it, run cmake\n# to set up the build (with a CMAKE_BUILD_TYPE flag if desired, otherwise Release will be used by\n# default), then run make to actually do the build.  This setup (1) keeps all build products out of\n# your source tree, which is generally a good idea, and (2) allows you to have both Release and\n# Debug builds going simultaneously.\n#\n# You can do \"make VERBOSE=1\" instead of just \"make\" to see the full command lines used.  There are\n# also various targets defined by cmake for make, such as \"slim\", \"eidos\", \"clean\", \"all\", etc.  To\n# rebuild all of cmake's internal caches etc. (which is generally a good idea after a \"git pull\",\n# for example, or after the addition or removal of source files), the simplest thing is generally\n# to touch the CMakeLists.txt file in the source tree top-level directory:\n#\n#   touch ../SLiM/CMakeLists.txt\n#\n# Then you can just do \"make\"; cmake will automatically be re-run by make since the CMakeLists.txt\n# file has changed.\n\n\n# This syntax sets the minimum version to 2.8.12, for compatibility with very old installs, but\n# sets the \"policy max\" to 4.0.  It's hard to tell from the CMake doc whether the \"policy\" changes\n# that actually signs us up for matter (wow, CMake is complicated!); but we're not doing anything\n# fancy, so it's hard to imagine it matters.  Be careful to add the 4.0 policy max everywhere that\n# cmake_minimum_required is set.  BCH 4/12/2025\ncmake_minimum_required (VERSION 2.8.12...4.0 FATAL_ERROR)\n\n\n# clang-tidy support (for internal development); must come before the project() line\n# note that the hard-coded paths below will need to be fixed for other platforms\noption(TIDY \"Run clang-tidy on SLiM (for development)\" OFF)\n\nif(TIDY)\n\t# cmake_minimum_required(VERSION 3.6...4.0 FATAL_ERROR)\n  if(CMAKE_VERSION VERSION_LESS \"3.6\")\n    message(FATAL_ERROR \"To use the clang-tidy wrapper TIDY in this project you will need a version of CMake at least as new as 3.6.\")\n  endif()\n\tmessage(STATUS \"TIDY is ${TIDY}; building with clang-tidy (for development)\")\n\tset(CMAKE_C_COMPILER \"/opt/local/libexec/llvm-17/bin/clang\")\n\tset(CMAKE_CXX_COMPILER \"/opt/local/libexec/llvm-17/bin/clang++\")\n\tfind_program(CLANG_TIDY_EXE NAMES \"clang-tidy\" PATHS \"/opt/local/libexec/llvm-17/bin/\" NO_DEFAULT_PATH REQUIRED)\n\tset(CLANG_TIDY_COMMAND \"${CLANG_TIDY_EXE}\" \"-checks=-*,modernize-*,-modernize-redundant-void-arg,-modernize-use-trailing-return-type,-modernize-use-auto,-modernize-avoid-c-arrays,-modernize-use-equals-default,-modernize-deprecated-headers,-modernize-use-nullptr,-modernize-return-braced-init-list,-modernize-use-using,bugprone-*,-bugprone-narrowing-conversions,-bugprone-easily-swappable-parameters,-bugprone-reserved-identifier,-bugprone-suspicious-include,performance-*,-performance-avoid-endl,-performance-inefficient-string-concatenation\")\n\tmessage(STATUS \"+++ clang-tidy is at ${CLANG_TIDY_EXE}\")\n\tmessage(STATUS \"+++ CLANG_TIDY_COMMAND is ${CLANG_TIDY_COMMAND}\")\nendif()\n\n\n# cppcheck support (for internal development)\n# for now this processes one file at a time; there is an alternative approach that\n# outputs a project file with CMAKE_EXPORT_COMPILE_COMMANDS and then runs cppcheck\n# on that, but I'm not sure how to do it within cmake so for now I'm punting on it\noption(CPPCHECK \"Run cppcheck on SLiM (for development)\" OFF)\n\nif(CPPCHECK)\n  if(CMAKE_VERSION VERSION_LESS \"3.10\")\n    message(FATAL_ERROR \"To use the cppcheck wrapper CPPCHECK in this project you will need a version of CMake at least as new as 3.10.\")\n  endif()\n  \n  find_program(CPPCHECK_EXECUTABLE cppcheck)\n  if (CPPCHECK_EXECUTABLE)\n    message(STATUS \"CPPCHECK is ${CPPCHECK}; building with cppcheck (for development)\")\n    set(CPPCHECK_COMMAND \"${CPPCHECK_EXECUTABLE}\" \"--enable=all;--suppress=missingIncludeSystem;--suppress=syntaxError;--suppress=unmatchedSuppression;--inline-suppr;--std=c++11;--quiet;--suppress=*:robin_hood.h;--suppress=*:lodepng.cpp;--suppress=*:pcg_extras.hpp;--suppress=*:pcg_random.hpp;--suppress=checkersReport;--suppress=*:eidos_openmp.h;--suppress=unusedFunction\")\n    message(STATUS \"+++ cppcheck is at ${CPPCHECK_EXECUTABLE}\")\n    message(STATUS \"+++ CPPCHECK_COMMAND is ${CPPCHECK_COMMAND}\")\n  else()\n    message(FATAL_ERROR \"The CPPCHECK option could be enabled because the cppcheck command could not be found.\")\n  endif()\nendif()\n\n# Support a COVERAGE flag for Codecov; see the GitHub Actions YAML file for the use of this\noption(COVERAGE \"Enable code coverage\" OFF)\nif(COVERAGE)\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} --coverage\")\n  set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} --coverage\")\nendif()\n\nproject(SLiM)\nif(WIN32)\n    include(ExternalProject)\nendif()\n\n\n#\n#\tBUILD OPTIONS\n#\n\n# Make a Release build by default\nif(NOT CMAKE_BUILD_TYPE) \n    set(CMAKE_BUILD_TYPE Release)\nendif(NOT CMAKE_BUILD_TYPE)\n\n# Add \"-D BUILD_SLIMGUI=ON\" to the CMake command to build SLiMgui\n# This requires that Qt, a widget framework, is installed\noption(BUILD_SLIMGUI \"Build the Qt-based GUI for SLiM\" OFF)\n\n# Add \"-D ASAN=ON\" to the CMake command to build with ASan runtime checking\noption(ASAN \"Build with ASan runtime checking\" OFF)\n\n# Add \"-D UBSAN=ON\" to the CMake command to build with ASan runtime checking\noption(UBSAN \"Build with UBSan runtime checking\" OFF)\n\n# Add \"-D PARALLEL=ON\" to the CMake command to make a parallel (multi-threaded) build\n# This is supported only for the command-line tools, not for SLiMgui; do not set BUILD_SLIMGUI\noption(PARALLEL \"Build parallel versions of eidos and slim\" OFF)\n\nif(PARALLEL)\n\t# BCH 12/4/2023: Parallel SLiM is presently unreleased and unsupported.  Caveat lector.\n\tmessage(FATAL_ERROR \"Multithreaded SLiM is not released, not thoroughly tested, and generally not yet ready for prime time.  It is not recommended for end-user use, especially not for 'production' runs, and the documentation for it is not yet public.  Please do not ask for any kind of support for this feature if you choose to experiment with it.\" )\nendif(PARALLEL)\n\n# Add \"-D PROFILE=ON\" to the CMake command to make a build of command-line slim with runtime profiling\n# This makes SLiM slower, so it is not for production use.  It may be set ON only for Release builds.\noption(PROFILE \"Build slim for runtime profiling\" OFF)\n\n# Add \"-D BUILD_NATIVE=ON\" to build natively for the build machine's architecture\n# this can result in better optimization, but the executable will only run on the build machine,\n# so it should only be enabled when you are building on the same machine you will do your runs on\noption(BUILD_NATIVE \"Build native for the build machine\" OFF)\n\n# Add \"-D BUILD_LTO=ON\" to enable link-time optimization; this may improve performance slightly,\n# but fails (see issue #33) on some machines with incompatible toolchains (so then don't enable it)\noption(BUILD_LTO \"Build with link-time optimization\" OFF)\n\n\n# obtain the Git commit SHA-1; see ./cmake/_README.txt and https://stackoverflow.com/a/4318642/2752221\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake/\")\ninclude(GetGitRevisionDescription)\nget_git_head_revision(GIT_REFSPEC GIT_SHA1)\n#message(STATUS \"GIT_SHA1 is ${GIT_SHA1}\")\n\n\n# Use the flags below for [all / Debug / Release] builds; these flags are built in to cmake\n# Note that -fno-math-errno is deliberately set for C++ (for eidos and slim) but not for C (for gsl, eidos_zlib, kastore, tables)\nset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -std=c11 -Wno-attributes -Wunused-label -Wimplicit -Wunused-variable -Wunused-value -Wno-pragmas -Wempty-body -Wshadow -Wparentheses -Wmissing-prototypes -Wswitch -Wpointer-sign -Wsign-compare -Wstrict-prototypes -Wno-sign-conversion -Wuninitialized\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -Wunused-label -Wunused-variable -Wunused-value -Wno-pragmas -Wempty-body -Wshadow -Wparentheses -Wswitch -Wsign-compare -Wno-sign-conversion -Wuninitialized -fno-math-errno\")\n\n# Add -march=native if requested\nif(BUILD_NATIVE)\n\tmessage(STATUS \"BUILD_NATIVE is ${BUILD_NATIVE}; building native (for this machine only)\")\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -march=native\")\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -march=native\")\nendif()\n\n# Windows specific flags and variables\nif(WIN32)\n    set(CMAKE_CXX_STANDARD_LIBRARIES \"-static-libgcc -static-libstdc++ -lwsock32 -lws2_32 ${CMAKE_CXX_STANDARD_LIBRARIES}\")\n    set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive\")\n    set(GNULIB_NAMESPACE_SOURCES \"${PROJECT_SOURCE_DIR}/core/chromosome.cpp\" \n        \"${PROJECT_SOURCE_DIR}/core/haplosome.cpp\" \n        \"${PROJECT_SOURCE_DIR}/core/individual.cpp\" \n        \"${PROJECT_SOURCE_DIR}/core/population.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/slim_globals.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/slim_sim_eidos.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/slim_sim.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/species.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/species_eidos.cpp\"\n        \"${PROJECT_SOURCE_DIR}/core/subpopulation.cpp\"\n        \"${PROJECT_SOURCE_DIR}/eidos/eidos_functions_files.cpp\"\n        \"${PROJECT_SOURCE_DIR}/eidos/eidos_functions_other.cpp\"\n        \"${PROJECT_SOURCE_DIR}/eidos/eidos_globals.cpp\"\n        \"${PROJECT_SOURCE_DIR}/eidos/eidos_class_DataFrame.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMAbout.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMAppDelegate.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMFindRecipe.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMGraphView.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMHaplotypeOptions.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMHelpWindow.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMScriptTextEdit.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMVariableBrowser.cpp\"\n        \"${PROJECT_SOURCE_DIR}/QtSLiM/QtSLiMWindow.cpp\")\nendif()\n\nset(CMAKE_C_FLAGS_DEBUG \"${CMAKE_C_FLAGS_DEBUG} -g -Og -DDEBUG=1\")\nset(CMAKE_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG} -g -Og -DDEBUG=1\")\n\nset(CMAKE_C_FLAGS_RELEASE \"${CMAKE_C_FLAGS_RELEASE} -O3\")\nset(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -O3\")\n\n# Build with ASan enabled if requested\nif(ASAN)\n\tmessage(STATUS \"ASAN is ${ASAN}\")\n\tadd_compile_options(-fsanitize=address -fno-omit-frame-pointer) # -fno-omit-frame-pointer for better stack traces\n\tadd_link_options(-fsanitize=address)\nelse()\n\tmessage(STATUS \"ASAN is ${ASAN}; use -DASAN=ON to enable ASan run-time checking\")\nendif(ASAN)\n\n# Build with UBSan enabled if requested\nif(UBSAN)\n\tmessage(STATUS \"UBSAN is ${UBSAN}\")\n\tadd_compile_options(-fsanitize=undefined -fno-omit-frame-pointer) # -fno-omit-frame-pointer for better stack traces\n\tadd_link_options(-fsanitize=undefined)\nelse()\n\tmessage(STATUS \"UBSAN is ${UBSAN}; use -DUBSAN=ON to enable UBSan run-time checking\")\nendif(UBSAN)\n\n# Report whether the build is parallel or not\nif(PARALLEL)\n\t# -Xclang is also needed on macOS; it is not set here since macOS builds are done in Xcode\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -fopenmp\")\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fopenmp\")\n\tlink_directories(/usr/local/lib/)\n\tmessage(STATUS \"PARALLEL is ${PARALLEL}\")\nelse()\n\t# At least for now, I don't want to advertise the existence of this flag\n\t#message(STATUS \"PARALLEL is ${PARALLEL}; use -DPARALLEL=ON to enable OpenMP parallelization\")\nendif(PARALLEL)\n\n# Report whether the build has runtime profiling support or not\nif(PROFILE)\n\t# compile flags for this get set at the end of this script\n\tmessage(STATUS \"PROFILE is ${PROFILE}\")\nelse()\n\t# At least for now, I don't want to advertise the existence of this flag\n\t#message(STATUS \"PROFILE is ${PROFILE}; use -PROFILE=ON to enable runtime profiling\")\nendif(PROFILE)\n\n# Report the build type and SLiMgui build status\nmessage(STATUS \"CMAKE_BUILD_TYPE is ${CMAKE_BUILD_TYPE}\")\n\nif(BUILD_SLIMGUI)\n\tmessage(STATUS \"BUILD_SLIMGUI is ${BUILD_SLIMGUI}\")\nelse()\n\tmessage(STATUS \"BUILD_SLIMGUI is ${BUILD_SLIMGUI}; use -DBUILD_SLIMGUI=ON to enable building SLiMgui\")\nendif()\n\n# Windows compat\nif(WIN32)\n    set(GNU_DIR ${CMAKE_CURRENT_BINARY_DIR}/libgnu-prefix/src/libgnu-build)\n    set(GNU_STATIC_LIB ${GNU_DIR}/gllib/libgnu.a)\n    set(GNU_INCLUDES ${GNU_DIR}/gllib)\n\n    file(MAKE_DIRECTORY ${GNU_INCLUDES})\n\n    ExternalProject_Add(libgnu\n        SOURCE_DIR ${PROJECT_SOURCE_DIR}/windows_compat/gnulib\n        CONFIGURE_COMMAND ${PROJECT_SOURCE_DIR}/windows_compat/gnulib/configure\n        BUILD_COMMAND ${MAKE}\n        BUILD_BYPRODUCTS ${GNU_STATIC_LIB})\n\n    add_library(gnu STATIC IMPORTED GLOBAL)\n    add_dependencies(gnu libgnu)\n    set_target_properties(gnu PROPERTIES IMPORTED_LOCATION ${GNU_STATIC_LIB})\n    set_target_properties(gnu PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${GNU_INCLUDES})\n    set_target_properties(gnu PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES ${GNU_INCLUDES})\nendif()\n\n# Do link-time optimization with -flto if requested and supported\nif(BUILD_LTO)\n    include(CheckCXXCompilerFlag)\n    include(CheckCCompilerFlag)\n    CHECK_CXX_COMPILER_FLAG(-flto CXX_SUPPORTS_FLTO)\n    CHECK_C_COMPILER_FLAG(-flto C_SUPPORTS_FLTO)\n    if(CXX_SUPPORTS_FLTO AND C_SUPPORTS_FLTO)\n        message(STATUS \"BUILD_LTO is ${BUILD_LTO}; building with link-time optimization\")\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -flto\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -flto\")\n        set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -flto\")\n    else()\n        message(AUTHOR_WARNING \"BUILD_LTO is ${BUILD_LTO} but -flto is not supported by the compiler\")\n    endif()\nendif()\n\n#\n# SIMD SUPPORT (independent of OpenMP)\n#\n\n# Option to disable SIMD entirely\noption(USE_SIMD \"Enable SIMD optimizations (SSE4.2/AVX2 on x86_64, NEON on ARM64)\" ON)\n\n# Check architecture\n# CMAKE_SYSTEM_PROCESSOR is \"x86_64\" on Intel Macs and Linux x86_64, \"arm64\"/\"aarch64\" on ARM\nset(IS_X86_64 FALSE)\nset(IS_ARM64 FALSE)\nif(CMAKE_SYSTEM_PROCESSOR MATCHES \"x86_64|AMD64|amd64|i686|i386\")\n    set(IS_X86_64 TRUE)\nelseif(CMAKE_SYSTEM_PROCESSOR MATCHES \"arm64|aarch64|ARM64\")\n    set(IS_ARM64 TRUE)\nendif()\n\nif(USE_SIMD AND NOT WIN32 AND IS_X86_64)\n    include(CheckCXXCompilerFlag)\n\n    # Check for AVX2 support\n    check_cxx_compiler_flag(\"-mavx2\" COMPILER_SUPPORTS_AVX2)\n    check_cxx_compiler_flag(\"-msse4.2\" COMPILER_SUPPORTS_SSE42)\n    check_cxx_compiler_flag(\"-mfma\" COMPILER_SUPPORTS_FMA)\n\n    if(COMPILER_SUPPORTS_AVX2)\n        message(STATUS \"SIMD: AVX2 support detected\")\n        add_compile_definitions(EIDOS_HAS_AVX2=1)\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -mavx2\")\n        if(COMPILER_SUPPORTS_FMA)\n            message(STATUS \"SIMD: FMA support detected\")\n            add_compile_definitions(EIDOS_HAS_FMA=1)\n            set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -mfma\")\n        endif()\n    elseif(COMPILER_SUPPORTS_SSE42)\n        message(STATUS \"SIMD: SSE4.2 support detected (no AVX2)\")\n        add_compile_definitions(EIDOS_HAS_SSE42=1)\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -msse4.2\")\n    else()\n        message(STATUS \"SIMD: No x86 SIMD support detected, using scalar fallback\")\n    endif()\nelseif(USE_SIMD AND NOT WIN32 AND IS_ARM64)\n    # ARM64 NEON is always available on ARM64, no compiler flag needed\n    message(STATUS \"SIMD: ARM64 NEON support enabled\")\n    add_compile_definitions(EIDOS_HAS_NEON=1)\nelseif(USE_SIMD AND NOT WIN32)\n    message(STATUS \"SIMD: Unknown architecture (${CMAKE_SYSTEM_PROCESSOR}), using scalar fallback\")\nelseif(USE_SIMD AND WIN32)\n    # Windows SIMD detection - MinGW uses GCC, so we can use the same flags as Linux\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" OR CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n        include(CheckCXXCompilerFlag)\n        check_cxx_compiler_flag(\"-mavx2\" COMPILER_SUPPORTS_AVX2_WIN)\n        check_cxx_compiler_flag(\"-mfma\" COMPILER_SUPPORTS_FMA_WIN)\n\n        if(COMPILER_SUPPORTS_AVX2_WIN)\n            message(STATUS \"SIMD: AVX2 support detected (Windows/MinGW)\")\n            add_compile_definitions(EIDOS_HAS_AVX2=1)\n            set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -mavx2\")\n            if(COMPILER_SUPPORTS_FMA_WIN)\n                message(STATUS \"SIMD: FMA support detected (Windows/MinGW)\")\n                add_compile_definitions(EIDOS_HAS_FMA=1)\n                set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -mfma\")\n            endif()\n        else()\n            message(STATUS \"SIMD: No AVX2 support on Windows/MinGW, using scalar fallback\")\n        endif()\n    else()\n        # MSVC path - not currently used but could be added in the future\n        message(STATUS \"SIMD: MSVC SIMD detection not yet implemented, using scalar fallback\")\n    endif()\nelse()\n    message(STATUS \"SIMD: Disabled by user\")\nendif()\n\n# GSL - adding /usr/local/include so all targets that use GSL_INCLUDES get omp.h\nset(TARGET_NAME_GSL gsl)\nfile(GLOB_RECURSE GSL_SOURCES ${PROJECT_SOURCE_DIR}/gsl/*.c ${PROJECT_SOURCE_DIR}/gsl/*/*.c)\nset(GSL_INCLUDES ${PROJECT_SOURCE_DIR}/gsl ${PROJECT_SOURCE_DIR}/gsl/specfunc ${PROJECT_SOURCE_DIR}/gsl/blas ${PROJECT_SOURCE_DIR}/gsl/rng ${PROJECT_SOURCE_DIR}/gsl/cdf ${PROJECT_SOURCE_DIR}/gsl/vector ${PROJECT_SOURCE_DIR}/gsl/err ${PROJECT_SOURCE_DIR}/gsl/sys ${PROJECT_SOURCE_DIR}/gsl/randist ${PROJECT_SOURCE_DIR}/gsl/matrix ${PROJECT_SOURCE_DIR}/gsl/cblas ${PROJECT_SOURCE_DIR}/gsl/complex ${PROJECT_SOURCE_DIR}/gsl/block ${PROJECT_SOURCE_DIR}/gsl/interpolation ${PROJECT_SOURCE_DIR}/gsl/linalg ${PROJECT_SOURCE_DIR}/gsl/permutation /usr/local/include)\nadd_library(${TARGET_NAME_GSL} STATIC ${GSL_SOURCES})\ntarget_include_directories(${TARGET_NAME_GSL} PUBLIC ${GSL_INCLUDES})\n\n# ZLIB\nset(TARGET_NAME_ZLIB eidos_zlib)\nfile(GLOB_RECURSE ZLIB_SOURCES ${PROJECT_SOURCE_DIR}/eidos_zlib/*.c)\nset(ZLIB_INCLUDES ${PROJECT_SOURCE_DIR}/eidos_zlib)\nadd_library(${TARGET_NAME_ZLIB} STATIC ${ZLIB_SOURCES})\ntarget_include_directories(${TARGET_NAME_ZLIB} PUBLIC)\n\n# KASTORE\nset(TARGET_NAME_KASTORE kastore)\nfile(GLOB_RECURSE KASTORE_SOURCES ${PROJECT_SOURCE_DIR}/treerec/tskit/kastore/*.c)\nset(KASTORE_INCLUDES ${PROJECT_SOURCE_DIR}/treerec/tskit/kastore)\nadd_library(${TARGET_NAME_KASTORE} STATIC ${KASTORE_SOURCES})\ntarget_include_directories(${TARGET_NAME_KASTORE} PUBLIC)\n\n# TSKIT\nset(TARGET_NAME_TSKIT tables)\nfile(GLOB_RECURSE TABLE_SOURCES ${PROJECT_SOURCE_DIR}/treerec/tskit/*.c)\nset(TSKIT_INCLUDES ${PROJECT_SOURCE_DIR}/treerec)\nadd_library(${TARGET_NAME_TSKIT} STATIC ${TABLE_SOURCES})\ntarget_include_directories(${TARGET_NAME_TSKIT} PRIVATE ${GSL_INCLUDES} ${KASTORE_INCLUDES})\ntarget_include_directories(${TARGET_NAME_TSKIT} PUBLIC ${KASTORE_INCLUDES} ${TSKIT_INCLUDES})\nif(WIN32)\n    target_link_libraries(${TARGET_NAME_TSKIT} PUBLIC gnu)\nendif()\n\n# SLIM\nif(PARALLEL)\n\tset(TARGET_NAME_SLIM slim_multi)\nelse()\n\tset(TARGET_NAME_SLIM slim)\nendif(PARALLEL)\nfile(GLOB_RECURSE SLIM_SOURCES ${PROJECT_SOURCE_DIR}/core/*.cpp ${PROJECT_SOURCE_DIR}/eidos/*.cpp)\n\n# use the Git commit SHA-1 obtained above\nconfigure_file(\"${PROJECT_SOURCE_DIR}/cmake/GitSHA1.cpp.in\" \"${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp\" @ONLY)\nlist(APPEND SLIM_SOURCES \"${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp\" ${PROJECT_SOURCE_DIR}/cmake/GitSHA1.h)\n\nadd_executable(${TARGET_NAME_SLIM} ${SLIM_SOURCES})\ntarget_include_directories(${TARGET_NAME_SLIM} PRIVATE ${GSL_INCLUDES} \"${PROJECT_SOURCE_DIR}/core\" \"${PROJECT_SOURCE_DIR}/eidos\")\ntarget_link_libraries(${TARGET_NAME_SLIM} PUBLIC gsl eidos_zlib tables)\nif(PARALLEL)\n\t# linking in the OpenMP library is maybe automatic with gcc?\n\t#target_link_libraries(${TARGET_NAME_SLIM} PUBLIC omp)\nendif()\nif(WIN32)\n    set_source_files_properties(${SLIM_SOURCES} PROPERTIES COMPILE_FLAGS \"-include config.h\")\n    set_source_files_properties(${GNULIB_NAMESPACE_SOURCES} TARGET_DIRECTORY slim PROPERTIES COMPILE_FLAGS \"-include config.h -DGNULIB_NAMESPACE=gnulib\")\n    target_include_directories(${TARGET_NAME_SLIM} BEFORE PUBLIC ${GNU_DIR})\n    target_link_libraries(${TARGET_NAME_SLIM} PUBLIC gnu PRIVATE bcrypt)\nendif()\n\n# EIDOS\nif(PARALLEL)\n\tset(TARGET_NAME_EIDOS eidos_multi)\nelse()\n\tset(TARGET_NAME_EIDOS eidos)\nendif(PARALLEL)\n\nfile(GLOB_RECURSE EIDOS_SOURCES  ${PROJECT_SOURCE_DIR}/eidos/*.cpp  ${PROJECT_SOURCE_DIR}/eidostool/*.cpp)\nadd_executable(${TARGET_NAME_EIDOS} ${EIDOS_SOURCES})\ntarget_include_directories(${TARGET_NAME_EIDOS} PRIVATE ${GSL_INCLUDES} \"${PROJECT_SOURCE_DIR}/eidos\")\ntarget_link_libraries(${TARGET_NAME_EIDOS} PUBLIC gsl eidos_zlib tables)\nif(PARALLEL)\n\t# linking in the OpenMP library is maybe automatic with gcc?\n\t#target_link_libraries(${TARGET_NAME_EIDOS} PUBLIC omp)\nendif()\nif(WIN32)\n    set_source_files_properties(${EIDOS_SOURCES} PROPERTIES COMPILE_FLAGS \"-include config.h\")\n    set_source_files_properties(${GNULIB_NAMESPACE_SOURCES} TARGET_DIRECTORY slim eidos PROPERTIES COMPILE_FLAGS \"-include config.h -DGNULIB_NAMESPACE=gnulib\")\n    target_include_directories(${TARGET_NAME_EIDOS} BEFORE PUBLIC ${GNU_DIR})\n    target_link_libraries(${TARGET_NAME_EIDOS} PUBLIC gnu PRIVATE bcrypt)\nendif()\n\nif(PARALLEL)\n\tinstall(TARGETS slim_multi eidos_multi DESTINATION bin)\nelse()\n\tinstall(TARGETS slim eidos DESTINATION bin)\nendif(PARALLEL)\n\n# SLiMgui -- this can be enabled with the -DBUILD_SLIMGUI=ON option to cmake\nif(BUILD_SLIMGUI)\n  cmake_minimum_required (VERSION 3.1.0...4.0 FATAL_ERROR)\n  set(TARGET_NAME_SLIMGUI SLiMgui)\n  find_package(OpenGL REQUIRED)\n\n  # Default to Qt6 if available, fall back to Qt5; this defines QT_VERSION_MAJOR to be either 5 or 6\n  # This is complicated slightly by the modules needed differing between Qt5 and Qt6\n  # see https://doc.qt.io/qt-6/cmake-qt5-and-qt6-compatibility.html\n  # I found that find_package(QT NAMES Qt6 Qt5 ...) was behaving oddly, so I shifted to the below\n  find_package(Qt6 COMPONENTS Core Gui Widgets OpenGLWidgets)\n  if(Qt6_FOUND)\n    set(QT_VERSION_MAJOR 6)\n    message(STATUS \"Found Qt6 (${Qt6_VERSION}) at ${QT6_INSTALL_PREFIX}\")\n  else()\n    find_package(Qt5 COMPONENTS Core Gui Widgets)\n    if(Qt5_FOUND)\n      set(QT_VERSION_MAJOR 5)\n      message(STATUS \"Could not find Qt6; if this is unexpected, you may wish to set Qt6_DIR and/or CMAKE_PREFIX_PATH\")\n      message(STATUS \"Found Qt5 (${Qt5_VERSION}) at ${Qt5_DIR}\")\n      # note that on macOS, Qt5 has only the x86_64 architecture, so if you are on macOS-arm64 your build will fail\n      # you can supply -D CMAKE_OSX_ARCHITECTURES=\"x86_64\" at the command line and it should build for x86_64\n    else()\n      message(FATAL_ERROR \"Could not find Qt5 or Qt6; you may wish to set Qt6_DIR, Qt5_DIR, and/or CMAKE_PREFIX_PATH\")\n    endif()\n  endif()\n  \n  # a useful bit of debugging code that prints all defined variables\n  #get_cmake_property(_variableNames VARIABLES)\n  #list (SORT _variableNames)\n  #foreach (_variableName ${_variableNames})\n  #  message(STATUS \"${_variableName}=${${_variableName}}\")\n  #endforeach()\n\n  if(WIN32)\n    set_source_files_properties(\"${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME_SLIMGUI}_autogen/mocs_compilation.cpp\" PROPERTIES COMPILE_FLAGS \"-include config.h -DGNULIB_NAMESPACE=gnulib\")\n  endif()\n\n  set(CMAKE_AUTOMOC ON)\n  set(CMAKE_AUTORCC ON)\n  set(CMAKE_AUTOUIC ON)\n  list(REMOVE_ITEM SLIM_SOURCES ${PROJECT_SOURCE_DIR}/core/main.cpp)\n  file(GLOB_RECURSE QTSLIM_SOURCES ${PROJECT_SOURCE_DIR}/QtSLiM/*.cpp ${PROJECT_SOURCE_DIR}/QtSLiM/*.qrc ${PROJECT_SOURCE_DIR}/eidos/*.cpp)\n  add_executable(${TARGET_NAME_SLIMGUI} \"${QTSLIM_SOURCES}\" \"${SLIM_SOURCES}\")\n  set_target_properties( ${TARGET_NAME_SLIMGUI} PROPERTIES LINKER_LANGUAGE CXX)\n  target_compile_definitions( ${TARGET_NAME_SLIMGUI} PRIVATE EIDOSGUI=1 SLIMGUI=1)\n  target_include_directories(${TARGET_NAME_SLIMGUI} PUBLIC ${GSL_INCLUDES} \"${PROJECT_SOURCE_DIR}/QtSLiM\" \"${PROJECT_SOURCE_DIR}/eidos\" \"${PROJECT_SOURCE_DIR}/core\" \"${PROJECT_SOURCE_DIR}/treerec\" \"${PROJECT_SOURCE_DIR}/treerec/tskit/kastore\")\n  \n  # Qt dependencies, which depend on the Qt version used.  For Qt6, we also need C++17; the last -std flag supplied ought to take priority.\n  if(${QT_VERSION_MAJOR} EQUAL 5)\n    target_link_libraries( ${TARGET_NAME_SLIMGUI} PUBLIC Qt5::Widgets Qt5::Core Qt5::Gui )\n  else()\n    target_link_libraries( ${TARGET_NAME_SLIMGUI} PUBLIC Qt6::Widgets Qt6::Core Qt6::Gui Qt6::OpenGLWidgets )\n    set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -std=c17\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++17\")\n  endif()\n  \n  # Operating System-specific install stuff.\n  if(APPLE)\n    target_link_libraries( ${TARGET_NAME_SLIMGUI} PUBLIC OpenGL::GL gsl tables eidos_zlib )\n  else()\n    if(WIN32)\n      set_source_files_properties(${QTSLIM_SOURCES} PROPERTIES COMPILE_FLAGS \"-include config.h\")\n      set_source_files_properties(${GNULIB_NAMESPACE_SOURCES} TARGET_DIRECTORY slim eidos SLiMgui PROPERTIES COMPILE_FLAGS \"-include config.h -DGNULIB_NAMESPACE=gnulib\")\n      target_include_directories(${TARGET_NAME_SLIMGUI} BEFORE PUBLIC ${GNU_DIR})\n      target_link_libraries(${TARGET_NAME_SLIMGUI} PUBLIC OpenGL::GL gsl tables eidos_zlib gnu PRIVATE bcrypt)\n    else()\n      target_link_libraries( ${TARGET_NAME_SLIMGUI} PUBLIC OpenGL::GL gsl tables eidos_zlib )\n\n      # Install icons and desktop files to the data root directory (usually /usr/local/share, or /usr/share).\n      if(CMAKE_VERSION VERSION_GREATER_EQUAL \"3.14\")\n        install(DIRECTORY data/ TYPE DATA)\n      else()\n        message(WARNING \"The CMake version is less than 3.14, so installation of icons, desktop files, mime types, etc. must occur manually.\")\n      endif()\n    endif()\n  endif()\n\n  install(TARGETS ${TARGET_NAME_SLIMGUI} DESTINATION bin)\nendif(BUILD_SLIMGUI)\n\n\n# Deal with the PROFILE and PARALLEL flags, which interact and are handled in a complex way.\n#\n# For SLiMgui, profiling is always on for Release builds, always off for Debug builds; PROFILE does not affect it\n# For slim, profiling follows the PROFILE setting for Release builds, but in Debug builds it is an error for PROFILE to be on\n# For eidos, profiling is always off; the eidos command-line tool does not support profiling on its own, only in SLiM\n#\n# Note that SLiMgui cannot be built parallel; if you want to build parallel, do not set BUILD_SLIMGUI\n\nif(PROFILE)\n\tif(CMAKE_BUILD_TYPE STREQUAL Debug)\n\t\tmessage(FATAL_ERROR \"PROFILE is not allowed for Debug builds\")\n\tendif()\n\n\tif(PARALLEL)\n\t\ttarget_compile_definitions( eidos_multi PRIVATE SLIMPROFILING=0)\n\t\ttarget_compile_definitions( slim_multi PRIVATE SLIMPROFILING=1)\n\telse()\n\t\ttarget_compile_definitions( eidos PRIVATE SLIMPROFILING=0)\n\t\ttarget_compile_definitions( slim PRIVATE SLIMPROFILING=1)\n\tendif(PARALLEL)\nelse()\n\tif(PARALLEL)\n\t\ttarget_compile_definitions( eidos_multi PRIVATE SLIMPROFILING=0)\n\t\ttarget_compile_definitions( slim_multi PRIVATE SLIMPROFILING=0)\n\telse()\n\t\ttarget_compile_definitions( eidos PRIVATE SLIMPROFILING=0)\n\t\ttarget_compile_definitions( slim PRIVATE SLIMPROFILING=0)\n\tendif(PARALLEL)\nendif(PROFILE)\n\nif(BUILD_SLIMGUI)\n\tif(CMAKE_BUILD_TYPE STREQUAL Release)\n\t\ttarget_compile_definitions( SLiMgui PRIVATE SLIMPROFILING=1)\n\telse()\n\t\ttarget_compile_definitions( SLiMgui PRIVATE SLIMPROFILING=0)\n\tendif(CMAKE_BUILD_TYPE STREQUAL Release)\n\n\tif(PARALLEL)\n\t\tmessage(FATAL_ERROR \"PARALLEL is not allowed for SLiMgui; running SLiMgui multi-threaded is not supported.  If you wish to build SLiM parallel, do not set BUILD_SLIMGUI for that build.\")\n\tendif()\nendif(BUILD_SLIMGUI)\n\n# implement clang-tidy for all end-user targets (not for gsl, zlib, kastore, tskit)\nif(TIDY)\n\tif(PARALLEL)\n\t\tset_target_properties(eidos_multi PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_COMMAND}\")\n\t\tset_target_properties(slim_multi PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_COMMAND}\")\n\telse()\n\t\tset_target_properties(eidos PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_COMMAND}\")\n\t\tset_target_properties(slim PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_COMMAND}\")\n\tendif(PARALLEL)\n\tif(BUILD_SLIMGUI)\n\t\tset_target_properties(SLiMgui PROPERTIES CXX_CLANG_TIDY \"${CLANG_TIDY_COMMAND}\")\n\tendif(BUILD_SLIMGUI)\nendif()\n\n# implement cppcheck for all end-user targets (not for gsl, zlib, kastore, tskit)\nif(CPPCHECK)\n\tif(PARALLEL)\n\t\tset_target_properties(eidos_multi PROPERTIES CXX_CPPCHECK \"${CPPCHECK_COMMAND}\")\n\t\tset_target_properties(slim_multi PROPERTIES CXX_CPPCHECK \"${CPPCHECK_COMMAND}\")\n\telse()\n\t\tset_target_properties(eidos PROPERTIES CXX_CPPCHECK \"${CPPCHECK_COMMAND}\")\n\t\tset_target_properties(slim PROPERTIES CXX_CPPCHECK \"${CPPCHECK_COMMAND}\")\n\tendif(PARALLEL)\n\tif(BUILD_SLIMGUI)\n\t\tset_target_properties(SLiMgui PROPERTIES CXX_CPPCHECK \"${CPPCHECK_COMMAND}\")\n\tendif(BUILD_SLIMGUI)\nendif()\n\n# add testing so it can be called using make test\nenable_testing()\n\n# test SLiM\nadd_test(\n  NAME testSLiM\n  COMMAND ${TARGET_NAME_SLIM} -testSLiM\n)\n# test Eidos from SLiM\nadd_test(\n  NAME testEidosSLiM\n  COMMAND ${TARGET_NAME_SLIM} -testEidos\n)\n\n# test Eidos from Eidos\nadd_test(\n  NAME testEidosEidos\n  COMMAND ${TARGET_NAME_EIDOS} -testEidos\n)\n"
  },
  {
    "path": "CONTENTS.txt",
    "content": "This file briefly describes the top-level contents of this repository, for reference.\nIf new files/directories are added to the top level, please add a description of them here.\n\n\nEIDOS SOURCE FILES\n------------------\neidos/ : the Eidos language interpreter\neidostool/ : the `eidos` command-line tool\neidos_zlib/ : a modified copy of the open-source `zlib` library, used by Eidos\ngsl/ :  a modified copy of the open-source Gnu Scientific Library, used by Eidos\nwindows_compat/ : gnulib sources providing APIs (POSIX etc.) needed to build on Windows\nEidosScribe/ : a macOS-only app based on Cocoa, for interactive Eidos programming\n\n\nSLiM SOURCE FILES\n-----------------\ncore/ : the SLiM core; main.cpp is for the `slim` command-line tool\ntreerec/ : a copy of the open-source tskit and kastore libraries, used by SLiM, with tests\nQtSLiM/ : the modern cross-platform SLiMgui app based on Qt\nSLiMgui/ : the old macOS-only SLiMgui app based on Cocoa, now called SLiMguiLegacy\n\n\nPROJECT FILES\n-------------\nSLiM.xcodeproj/ : Xcode project files, used for development on macOS\nCMakeLists.txt : CMake build configuration, for building at the command line\nSLiM.pro : qmake / Qt Creator build configuration, for making QtSLiM; see other .pro files also\n\n\nGIT AND GITHUB FILES\n--------------------\n.github/ : GitHub issue templaces, GitHub Actions workflows\n.gitattributes : git configuration file\n.gitignore : git configuration file\nREADME.md : the README information visible on SLiM GitHub home page\n\n\nDISTRIBUTION FILES\n------------------\norg.messerlab.* : files used by Linux packages for desktop configuration; see\n                  freedesktop.org for more information about these files.\ndebian/ : files used by Debian and Debian-derived Linux distributions for\n          creating deb source and binary packages. See the \"Guide for Debian Maintainers\"\n          and \"Debian Developer's Reference\" for more information:\n          https://www.debian.org/doc/devel-manuals.\nSLiM-3.7.1.spec : \"a recipe that the rpmbuild utility uses to build an RPM,\" as\n                  described by the Red Hat documentation in the\n                  \"PACKAGING AND DISTRIBUTING SOFTWARE\" section of the RHEL 8 manual.\n\nMISCELLANEOUS FILES\n-------------------\n.travis.yml : configuration for Travis-CI; not currently used, kept for posterity\nsonar-project.properties : configuration for a code linting tool called Sonar\nEidosSLiMTests/ : a test harness used inside Xcode; not used much, not maintained\nLICENSE : the legal licence document for Eidos and SLiM (GNU General Public License 3.0)\nTO_DO : misnamed; actually a list of command-line stuff that I have found useful when developing\nVERSIONS : a log of significant changes made in each version of SLiM, back to 2.0\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to SLiM\n\nWelcome!  This document outlines some guidelines and procedures for participating in and contributing to the SLiM community.  You can read about SLiM at the [<u>SLiM home page</u>](https://messerlab.org/slim/).\n\n\n## Code of conduct\n\nBe polite, kind, and considerate.  Do not spam, advertise, or proselytize.\n\n**AI-generated contributions violate the code of conduct.**  An exception is made for the use of AI to translate text from another language.\n\n\n## Getting started with SLiM\n\nIf you're a **new user wondering how to get started**, the [<u>SLiM home page</u>](https://messerlab.org/slim/) is a good place to start.  It provides a quick overview of what SLiM is, with links to a couple of podcast episodes in which SLiM was discussed.  Downloadable manuals for Eidos and SLiM are available there.\n\nIt also has a section about the **SLiM Workshop**, a tutorial process we have developed for new users.  The [<u>SLiM Workshop</u>](https://messerlab.org/slim/#Workshops) is probably the best way to get into SLiM; you can register to take it in person when it is offered, or download the free online materials for the workshop and do it on your own time.  The in-person workshops generally fill up quickly, so you would want to register for them soon after they are posted.  You can see announcements of new workshops on the [<u>slim-discuss list</u>](https://groups.google.com/g/slim-discuss), or the [<u>slim-announce list</u>](https://groups.google.com/g/slim-announce) if you only want to see announcements (not questions).  **If you wish to join slim-discuss, you must use an institutional email address (.edu, .gov, etc.), state your institution, and supply a SLiM-related \"reason for joining\" in your request.**\n\n\n## Bug reports and feature requests\n\nIf you think you're seeing **a bug in SLiM or Eidos**, or you have a **feature request for SLiM or Eidos**, please open a new issue on [<u>SLiM's GitHub repository</u>](https://github.com/MesserLab/SLiM/issues).  For **bugs or feature requests pyslim**, please open an issue in the [<u>pyslim repository</u>](https://github.com/tskit-dev/pyslim/issues).  Please first search for similar issues, to save yourself and others time.  For bugs in other parts of the software ecosystem, such as msprime or tskit, please use a search engine to find the correct process; please do *not* ask us for support for that software.\n\nWriting up **a good bug report** is an art form, and it is greatly appreciated by us, the developers, on the other end – and it makes it much more likely that your bug will actually get fixed.  For further guidance on writing a good bug report, please consult the paper [<u>Ten simple rules on reporting a bug</u>](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1010540).  Particularly important is constructing a **minimal reproducible example**; without that, it is often difficult for us to do much with your bug report. If you're not sure what a minimal reproducible example is, please read that paper.\n\n\n## Asking a question\n\nIf you want to ask a question about SLiM, Eidos, or pyslim, please do not file an issue on GitHub.  Instead, join the [<u>slim-discuss list</u>](https://groups.google.com/g/slim-discuss) and ask it there.  Please search first to see whether others have already asked the same question.  Note that slim-discuss is frequently targeted by spammers, and is therefore heavily moderated.  **If you wish to join slim-discuss, you must use an institutional email address (.edu, .gov, etc.), state your institution, and supply a SLiM-related \"reason for joining\" in your request.**\n\nIf your question is about a specific model that you're working on, then the guidelines for asking a good question are similar to filing a good bug report, so again, please read the paper [<u>Ten simple rules on reporting a bug</u>](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1010540). For example: search slim-discuss for previous answers to your question; try to answer your question yourself using the manual first; whittle down your model to a minimal reproducible example; post the complete model code so that we can see what you're actually doing; clearly state what you're trying to do and why; if you're getting an error message, copy/paste that error message rather than just saying \"I got an error\"; and so forth. Be specific and give us the information we will need to answer your question; don't make us guess.\n\nA particularly common type of question is along the lines of:\n\n#### \"Why doesn't my model's behavior match theory?\"\n\nThese questions can be tricky to answer.  The reason they are tricky is because \"theory\" can mean a lot of different things, and for that matter, so can \"match\". So, this sort of question is much more likely to get a useful and interesting answer if it includes:\n\n* an explicit description of what the theoretical result is\n\n* a plot of the observed and expected values as they change with some parameter\n\n* citation of somewhere that explains/derives the theoretical result\n\n* ideally, an overview of what assumptions and approximations underly the result (e.g., \"under the WF model for large N with infinite sites mutations\")\n\n* a high-level description of the SLiM model and how the relevant statistics are calculated\nthe SLiM recipe and other code, ideally set up to run without command-line arguments or input files on someone else's computer, made as simple as possible\n\nThese sorts of questions are pretty common, and natural, and it's not obvious to many people how a question like this can be hard to answer without additional information of this sort.\n\nOften the results from simulation don't match theory because they're not *expected* to match theory; the simulation violates assumptions used by the theory in important ways, or the theory is known to be limited or biased or approximate, or the simulations – being stochastic – don't exactly match theory simply due to stochasticity. Try to think about these possibilities and rule them out before asking us. We don't want to discourage relevant questions, but keep in mind that we're here to answer questions about our software, not to provide general consulting services for any and all questions about population genetics. :->\n\n\n## Opening a discussion\n\nIf you want to start a conversation with the SLiM community about an idea, perhaps the best place for it is the new [<u>slim-community organization</u>](https://github.com/slim-community) on GitHub.  Just click the \"Request to Join\" button to join, and once you receive your invite from a community moderator, you're good to go!  To give your discussion visibility, please feel free to post, *just once*, on slim-discuss to tell people that your discussion is there.\n\nThe slim-discuss mailing list might also be a good place to post, but please do be aware that hundreds of people subscribe to that mailing list; think about whether you really want to put something in all those people's inboxes, or whether you might want to just bounce the idea off of the developers – us – in a GitHub issue, or make a slim-community discussion that people can join in on. But if you think your idea is really appropriate for the mailing list, then go for it!\n\n\n## SLiM-related job postings\n\nIf you are looking to hire someone with SLiM skills, or you have SLiM skills and you're looking to get hired, please post in the [<u>slim-community organization</u>](https://github.com/slim-community), specifically in the [<u>Jobs discussion area</u>](https://github.com/orgs/slim-community/discussions/categories/jobs).\n\nThe [<u>EvolDir mailing list</u>](https://evol.mcmaster.ca/evoldir.html) is also a good place to watch for job listings (or post your own), and does sometimes have listings that specifically mention SLiM.\n\nGood luck!\n\n\n## Contributing code\n\n**First of all, all contributions to SLiM must be human-authored in accordance with the code of conduct.**  It is acceptable to use AI as a reference tool, to essentially provide documentation that you consult while working.  It is *not* acceptable to use AI to write code, documentation, or any other part of a PR that you submit to the SLiM repository.  PRs that incorporate AI-generated content will be rejected, with reference to this policy.  Repeated attempts will result in blocking.  Thank you for understanding and complying with this policy.\n\nIf you wish to make a contribution to SLiM, it would be a good idea to open an issue and get feedback first.  This repository is under intensive development, with specific goals in mind; contributions that don't fit with the overall vision of SLiM, or that conflict heavily with other changes underway or planned, may be rejected.  Discussing your planned changes before you make them would help you to craft a contribution that would be accepted.  That said, PRs that make a useful contribution, such as adding a new function into Eidos, are quite welcome!\n\nThe standard workflow for contributions is to fork and open a pull request (PR) based upon a branch in your fork.\n\n\n## Contributing documentation and recipes.\n\n**First of all, all contributions to SLiM must be human-authored in accordance with the code of conduct.**  That said, if you wish to make contributions to SLiM's documentation, such as edits or new recipes, that's great.  SLiM's documentation is kept in a macOS app called Pages that stores its data in binary form, so the doc is not available online in its original form, and pull requests against it are not possible.  In general the best approach is thus to open a new issue and provide a description of the edits you would suggest, with a rationale for them.\n\nFor new recipes/models, unless you believe that they are of sufficient general interest to belong in the SLiM manual itself, the best place to contribute is probably the [<u>SLiM-Extras repository</u>](https://github.com/MesserLab/SLiM-Extras).  New pull requests for SLiM-Extras are generally welcome.  Please edit the appropriate README files to add a mention of your contribution, and please provide a credit to yourself, including your name, institution, and an email address.\n\n\n## Contributing whole repositories\n\nIf you have a contribution that is large enough to make sense as its own standalone repository, such as a new software tool that could join the SLiM ecosystem, the best home is the [<u>slim-community organization</u>](https://github.com/slim-community) on GitHub.  You can request to join that organization by clicking the big \"Request to Join\" button, and you can see some existing contributed repositories there.\n\n\n## Closing remarks\n\nThanks for reading this and thinking about the best way to engage; we appreciate it.\n\nAnd thanks for being a part of the SLiM community!  Happy SLiMulating!\n\n*&mdash; Ben Haller, 30 December 2025*\n"
  },
  {
    "path": "EidosSLiMTests/EidosTests.mm",
    "content": "//\n//  EidosTests.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/27/17.\n//  Copyright (c) 2017-2022 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <XCTest/XCTest.h>\n\n#import \"eidos_test.h\"\n\n\n@interface EidosTests : XCTestCase\n\n@end\n\n@implementation EidosTests\n\n- (void)setUp {\n    [super setUp];\n\t\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n\t\n#ifdef _OPENMP\n\tEidos_WarmUpOpenMP(&SLIM_ERRSTREAM, changed_max_thread_count, (int)max_thread_count, true, /* max per-task thread counts */ \"maxThreads\");\n#endif\n\tEidos_WarmUp();\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n\t\n    [super tearDown];\n}\n\n- (void)testEidos {\n\t// Since we roll our own testing code, for testability by the user, we don't fit very well into\n\t// the Xcode testing framework.  We make no attempt here to split the individual tests into their\n\t// own methods, or to call Xcode's assert functions to assert failures, or anything like that.\n\t// The point of having these tests at all is to be able to assess test code coverage in Xcode.\n\tRunEidosTests();\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosSLiMTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "EidosSLiMTests/SLiMTests.mm",
    "content": "//\n//  SLiMTests.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/27/17.\n//  Copyright (c) 2017-2022 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <XCTest/XCTest.h>\n\n#import \"slim_test.h\"\n#import \"individual.h\"\n#import \"mutation.h\"\n\n\n@interface SLiMTests : XCTestCase\n\n@end\n\n@implementation SLiMTests\n\n- (void)setUp {\n    [super setUp];\n\t\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n\t\n#ifdef _OPENMP\n\tEidos_WarmUpOpenMP(&SLIM_ERRSTREAM, changed_max_thread_count, (int)max_thread_count, true, /* max per-task thread counts */ \"maxThreads\");\n#endif\n\tSLiM_ConfigureContext();\n\tEidos_WarmUp();\n\tSLiM_WarmUp();\n\t\n\t// our self-tests run in SLiMgui, but eidosConsoleWindowControllerDidExecuteScript: puts nasty values into\n\t// these variables to help find bugs, and we run our tests outside of any SLiMgui window so the nasty\n\t// values bite us...\n\t\n\tgSLiM_next_pedigree_id = 0;\n\tgSLiM_next_mutation_id = 0;\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testSLiM {\n\t// Since we roll our own testing code, for testability by the user, we don't fit very well into\n\t// the Xcode testing framework.  We make no attempt here to split the individual tests into their\n\t// own methods, or to call Xcode's assert functions to assert failures, or anything like that.\n\t// The point of having these tests at all is to be able to assess test code coverage in Xcode.\n\tRunSLiMTests();\n}\n\n@end\n"
  },
  {
    "path": "EidosScribe/Base.lproj/EidosAboutWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"EidosAppDelegate\">\n            <connections>\n                <outlet property=\"aboutVersionTextField\" destination=\"WB2-cU-hkd\" id=\"CNZ-WA-EUh\"/>\n                <outlet property=\"aboutWindow\" destination=\"QvC-M9-y7g\" id=\"7vI-I4-hc5\"/>\n                <outlet property=\"benHallerLineTextField\" destination=\"9KH-lz-tf6\" id=\"Zig-Fg-zlN\"/>\n                <outlet property=\"licenseTextField\" destination=\"l8N-rU-b5f\" id=\"Zcf-DJ-9Qb\"/>\n                <outlet property=\"messerLabLineTextField\" destination=\"C4q-EC-cXM\" id=\"QJz-7b-zmA\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"745\" width=\"621\" height=\"449\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1417\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"621\" height=\"436\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CxN-ue-roS\">\n                        <rect key=\"frame\" x=\"20\" y=\"288\" width=\"128\" height=\"128\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"128\" id=\"rVI-r9-sd7\"/>\n                            <constraint firstAttribute=\"width\" constant=\"128\" id=\"sfg-xt-7oO\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"NSApplicationIcon\" id=\"6vw-j2-cwW\"/>\n                    </imageView>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wDw-79-A4b\">\n                        <rect key=\"frame\" x=\"175\" y=\"377\" width=\"317\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"EidosScribe : An interactive interpreter for Eidos\" id=\"sJB-jI-icR\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9KH-lz-tf6\">\n                        <rect key=\"frame\" x=\"175\" y=\"312\" width=\"267\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"By Benjamin C. Haller, http://benhaller.com/\" id=\"cag-MY-und\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"C4q-EC-cXM\">\n                        <rect key=\"frame\" x=\"175\" y=\"353\" width=\"351\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Messer Lab, Cornell University, http://messerlab.org/slim/\" id=\"jqg-yt-Wpi\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cD8-Mz-qIr\">\n                        <rect key=\"frame\" x=\"175\" y=\"336\" width=\"389\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Copyright © 2016-2025 Benjamin C. Haller.  All rights reserved.\" id=\"jZm-bw-sGW\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WB2-cU-hkd\">\n                        <rect key=\"frame\" x=\"409\" y=\"409\" width=\"204\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"200\" id=\"SBS-mC-L6n\"/>\n                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"kLz-az-BTI\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"version\" id=\"15F-WF-Zi9\">\n                            <font key=\"font\" metaFont=\"palette\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l8N-rU-b5f\">\n                        <rect key=\"frame\" x=\"46\" y=\"40\" width=\"529\" height=\"208\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"525\" id=\"3Yu-Qt-RPr\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"efh-34-WId\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">Eidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with Eidos. If not, see http://www.gnu.org/licenses/.\n\nPlease see the Eidos manual for credits and license information for code that has been incorporated into Eidos from other authors.</string>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"centerX\" secondItem=\"l8N-rU-b5f\" secondAttribute=\"centerX\" id=\"1Cg-63-tUN\"/>\n                    <constraint firstItem=\"WB2-cU-hkd\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"48\" id=\"5Le-7s-1Mx\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"WB2-cU-hkd\" secondAttribute=\"trailing\" constant=\"10\" id=\"DNR-LT-Q4b\"/>\n                    <constraint firstItem=\"l8N-rU-b5f\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"48\" id=\"Ezq-W1-pcW\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"l8N-rU-b5f\" secondAttribute=\"trailing\" constant=\"48\" id=\"FWS-3s-vOF\"/>\n                    <constraint firstItem=\"C4q-EC-cXM\" firstAttribute=\"leading\" secondItem=\"wDw-79-A4b\" secondAttribute=\"leading\" id=\"HW0-by-DLL\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"leading\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"leading\" id=\"JdI-QS-ppx\"/>\n                    <constraint firstItem=\"WB2-cU-hkd\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"10\" id=\"Jzj-ki-KJ3\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"cD8-Mz-qIr\" secondAttribute=\"trailing\" constant=\"48\" id=\"OWe-in-0wJ\"/>\n                    <constraint firstItem=\"l8N-rU-b5f\" firstAttribute=\"top\" secondItem=\"CxN-ue-roS\" secondAttribute=\"bottom\" constant=\"40\" id=\"RQp-J8-UKb\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"trailing\" constant=\"48\" id=\"S7y-0f-9dX\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"top\" secondItem=\"wDw-79-A4b\" secondAttribute=\"bottom\" constant=\"-39\" id=\"SgS-FZ-ZOF\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"wDw-79-A4b\" secondAttribute=\"trailing\" constant=\"48\" id=\"TdM-xv-1bc\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"top\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"bottom\" constant=\"1\" id=\"TsK-bf-Azp\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"9KH-lz-tf6\" secondAttribute=\"trailing\" constant=\"48\" id=\"UpT-bU-Yhx\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"b1f-cV-8HA\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"leading\" secondItem=\"9KH-lz-tf6\" secondAttribute=\"leading\" id=\"chO-2v-wka\"/>\n                    <constraint firstItem=\"C4q-EC-cXM\" firstAttribute=\"top\" secondItem=\"wDw-79-A4b\" secondAttribute=\"bottom\" constant=\"8\" id=\"iNQ-B5-u82\"/>\n                    <constraint firstItem=\"9KH-lz-tf6\" firstAttribute=\"top\" secondItem=\"cD8-Mz-qIr\" secondAttribute=\"bottom\" constant=\"8\" id=\"sch-36-LNf\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"l8N-rU-b5f\" secondAttribute=\"bottom\" constant=\"40\" id=\"viU-bB-jpP\"/>\n                    <constraint firstItem=\"wDw-79-A4b\" firstAttribute=\"leading\" secondItem=\"CxN-ue-roS\" secondAttribute=\"trailing\" constant=\"29\" id=\"z2U-EL-tOb\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"zxo-Hp-C8e\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"695.5\" y=\"791\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSApplicationIcon\" width=\"32\" height=\"32\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "EidosScribe/Base.lproj/EidosConsoleWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16F73\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"EidosAppDelegate\">\n            <connections>\n                <outlet property=\"consoleController\" destination=\"Oju-rn-RJg\" id=\"hsy-zU-QJf\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Variable Browser\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"Variable Browser\" animationBehavior=\"default\" id=\"NRo-a8-DAD\" userLabel=\"Variable Browser\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"348\" width=\"800\" height=\"302\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n            <value key=\"minSize\" type=\"size\" width=\"480\" height=\"302\"/>\n            <view key=\"contentView\" id=\"ejJ-lZ-DxP\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"302\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qvW-Jg-Zwc\">\n                        <rect key=\"frame\" x=\"-1\" y=\"-1\" width=\"802\" height=\"304\"/>\n                        <clipView key=\"contentView\" id=\"VOu-3p-vVw\">\n                            <rect key=\"frame\" x=\"1\" y=\"0.0\" width=\"800\" height=\"303\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                            <subviews>\n                                <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveName=\"Variable Browser Table\" headerView=\"Rl0-FI-YeK\" indentationPerLevel=\"10\" outlineTableColumn=\"o39-eJ-hfF\" id=\"hH1-M5-dOk\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"280\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"Symbol\" editable=\"NO\" width=\"200\" minWidth=\"150\" maxWidth=\"300\" id=\"o39-eJ-hfF\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Symbol\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"9Vv-BG-fxg\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"Type\" editable=\"NO\" width=\"160\" minWidth=\"100\" maxWidth=\"200\" id=\"nDl-km-47h\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Type\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"CCq-mB-oXu\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"Size\" editable=\"NO\" width=\"75\" minWidth=\"50\" maxWidth=\"100\" id=\"abz-vU-rF5\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"Size\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"fOH-A2-iVH\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"Values\" editable=\"NO\" width=\"353\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"se1-Pr-NhJ\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Values\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"eCU-C2-6sg\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <outlet property=\"dataSource\" destination=\"TRR-E4-jMc\" id=\"SZj-X3-dO6\"/>\n                                        <outlet property=\"delegate\" destination=\"TRR-E4-jMc\" id=\"nnK-FE-EtW\"/>\n                                    </connections>\n                                </outlineView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"4QD-0H-9dl\">\n                            <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"Xbj-Tw-H7p\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" id=\"Rl0-FI-YeK\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"23\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                    </scrollView>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"qvW-Jg-Zwc\" secondAttribute=\"bottom\" constant=\"-1\" id=\"1A9-lF-9MS\"/>\n                    <constraint firstItem=\"qvW-Jg-Zwc\" firstAttribute=\"leading\" secondItem=\"ejJ-lZ-DxP\" secondAttribute=\"leading\" constant=\"-1\" id=\"iNF-y5-R83\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"qvW-Jg-Zwc\" secondAttribute=\"trailing\" constant=\"-1\" id=\"ndG-gV-7eY\"/>\n                    <constraint firstItem=\"qvW-Jg-Zwc\" firstAttribute=\"top\" secondItem=\"ejJ-lZ-DxP\" secondAttribute=\"top\" constant=\"-1\" id=\"w77-04-8d6\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"TRR-E4-jMc\" id=\"Lnn-0E-hDR\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"1659\" y=\"1709\"/>\n        </window>\n        <customObject id=\"Oju-rn-RJg\" customClass=\"EidosConsoleWindowController\">\n            <connections>\n                <outlet property=\"bottomSplitView\" destination=\"OgO-Qu-oJA\" id=\"l2V-EH-mNW\"/>\n                <outlet property=\"browserController\" destination=\"TRR-E4-jMc\" id=\"Gvk-P5-BrF\"/>\n                <outlet property=\"browserToggleButton\" destination=\"mJ2-l4-FOc\" id=\"6Va-LI-Rha\"/>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"IxL-BB-3pl\"/>\n                <outlet property=\"outputTextView\" destination=\"hNz-Jr-UfL\" id=\"MKo-wH-BBs\"/>\n                <outlet property=\"scriptTextView\" destination=\"g30-Kl-eb2\" id=\"28b-x3-Gzp\"/>\n                <outlet property=\"scriptWindow\" destination=\"X56-a6-BnZ\" id=\"ipo-Vc-kut\"/>\n                <outlet property=\"statusTextField\" destination=\"kY6-al-Llg\" id=\"P64-k9-Ec6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"TRR-E4-jMc\" customClass=\"EidosVariableBrowserController\">\n            <connections>\n                <outlet property=\"browserOutline\" destination=\"hH1-M5-dOk\" id=\"28G-hv-ZE9\"/>\n                <outlet property=\"browserWindow\" destination=\"NRo-a8-DAD\" id=\"NkH-rE-hzf\"/>\n                <outlet property=\"delegate\" destination=\"Oju-rn-RJg\" id=\"dtc-qA-VZ2\"/>\n                <outlet property=\"sizeColumn\" destination=\"abz-vU-rF5\" id=\"0TH-Is-lmp\"/>\n                <outlet property=\"symbolColumn\" destination=\"o39-eJ-hfF\" id=\"12u-JE-0c6\"/>\n                <outlet property=\"typeColumn\" destination=\"nDl-km-47h\" id=\"5JW-50-dhX\"/>\n                <outlet property=\"valueColumn\" destination=\"se1-Pr-NhJ\" id=\"VwY-ut-Skf\"/>\n            </connections>\n        </customObject>\n        <window title=\"Eidos Console\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"Eidos Console\" animationBehavior=\"default\" id=\"X56-a6-BnZ\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"335\" y=\"390\" width=\"1024\" height=\"768\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n            <value key=\"minSize\" type=\"size\" width=\"512\" height=\"384\"/>\n            <view key=\"contentView\" id=\"P8Z-tg-7Uc\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1024\" height=\"768\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <splitView autosaveName=\"\" dividerStyle=\"paneSplitter\" vertical=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OgO-Qu-oJA\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"21\" width=\"1024\" height=\"747\"/>\n                        <subviews>\n                            <customView id=\"jpo-0u-yWF\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"509\" height=\"747\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jiy-7p-SlJ\" userLabel=\"Bordered Scroll View - Eidos Text View\">\n                                        <rect key=\"frame\" x=\"-1\" y=\"-1\" width=\"511\" height=\"722\"/>\n                                        <clipView key=\"contentView\" id=\"lvd-Kf-Kub\">\n                                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"494\" height=\"720\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <textView importsGraphics=\"NO\" richText=\"NO\" findStyle=\"bar\" allowsUndo=\"YES\" id=\"g30-Kl-eb2\" userLabel=\"Eidos Text View\" customClass=\"EidosTextView\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"494\" height=\"720\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                    <size key=\"minSize\" width=\"494\" height=\"720\"/>\n                                                    <size key=\"maxSize\" width=\"511\" height=\"10000000\"/>\n                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <connections>\n                                                        <outlet property=\"delegate\" destination=\"Oju-rn-RJg\" id=\"dx7-li-RZ7\"/>\n                                                    </connections>\n                                                </textView>\n                                            </subviews>\n                                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </clipView>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"2ZQ-St-go0\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"gcg-FA-r6d\">\n                                            <rect key=\"frame\" x=\"495\" y=\"1\" width=\"15\" height=\"720\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rnZ-Mh-Tla\">\n                                        <rect key=\"frame\" x=\"100\" y=\"725\" width=\"44\" height=\"17\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Eidos:\" id=\"76g-uR-h73\">\n                                            <font key=\"font\" metaFont=\"systemBold\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <button toolTip=\"check script syntax\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"amy-dn-iKo\" userLabel=\"Check Script Button\">\n                                        <rect key=\"frame\" x=\"4\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"3an-II-wZO\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"uxJ-PS-NXl\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"check\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"check_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"U0A-ch-QMD\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"checkScript:\" target=\"Oju-rn-RJg\" id=\"e5U-vL-Zwb\"/>\n                                            <binding destination=\"Oju-rn-RJg\" name=\"enabled\" keyPath=\"interfaceEnabled\" id=\"hjH-3M-ZLi\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"Eidos scripting help\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VKv-8h-11O\" userLabel=\"Show Script Help Button\">\n                                        <rect key=\"frame\" x=\"50\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"Jfh-eS-JIk\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"LK3-eV-s44\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"syntax_help\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"syntax_help_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Prc-Ou-8n9\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"showScriptHelp:\" target=\"Oju-rn-RJg\" id=\"zGL-JW-RJ5\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"execute selection\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"W1d-Ym-5da\" userLabel=\"Execute Selection Button\">\n                                        <rect key=\"frame\" x=\"461\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"ITg-vv-RXo\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"WQ1-PJ-kWJ\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"execute_selection\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"execute_selection_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"sMe-l0-1zl\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"executeSelection:\" target=\"Oju-rn-RJg\" id=\"D5M-Ws-oTD\"/>\n                                            <binding destination=\"Oju-rn-RJg\" name=\"enabled\" keyPath=\"interfaceEnabled\" id=\"nql-q0-njy\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"execute full script\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yTp-UR-uIs\" userLabel=\"Execute All Button\">\n                                        <rect key=\"frame\" x=\"484\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"Lmg-Mh-ixY\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"bTI-Jb-10A\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"execute_script\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"execute_script_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Plf-Gr-RsW\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"executeAll:\" target=\"Oju-rn-RJg\" id=\"WUD-LX-wuw\"/>\n                                            <binding destination=\"Oju-rn-RJg\" name=\"enabled\" keyPath=\"interfaceEnabled\" id=\"XOs-f5-IAU\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"show/hide variable browser\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mJ2-l4-FOc\" userLabel=\"Variable Browser Button\">\n                                        <rect key=\"frame\" x=\"73\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"383-La-boA\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"gQB-QY-zb8\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_browser\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"show_browser_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"UAT-l6-bUr\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"toggleBrowserVisibility:\" target=\"TRR-E4-jMc\" id=\"OeH-bG-5cJ\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"prettyprint script\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BWk-qv-CwE\" userLabel=\"Prettyprint Script Button\">\n                                        <rect key=\"frame\" x=\"27\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"s1k-CW-lnN\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"xDu-lO-8Mn\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"prettyprint\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"prettyprint_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"MQa-8V-iyM\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"prettyprintScript:\" target=\"Oju-rn-RJg\" id=\"BfZ-wF-F3E\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"mJ2-l4-FOc\" firstAttribute=\"bottom\" secondItem=\"VKv-8h-11O\" secondAttribute=\"bottom\" id=\"3Yl-TY-Hm4\"/>\n                                    <constraint firstItem=\"W1d-Ym-5da\" firstAttribute=\"bottom\" secondItem=\"VKv-8h-11O\" secondAttribute=\"bottom\" id=\"6VP-RB-FQ3\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"jiy-7p-SlJ\" secondAttribute=\"trailing\" constant=\"-1\" id=\"7Ec-8S-0iR\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"yTp-UR-uIs\" secondAttribute=\"trailing\" constant=\"5\" id=\"Akv-z6-RM5\"/>\n                                    <constraint firstItem=\"VKv-8h-11O\" firstAttribute=\"leading\" secondItem=\"BWk-qv-CwE\" secondAttribute=\"trailing\" constant=\"3\" id=\"CqY-tt-Gic\"/>\n                                    <constraint firstItem=\"BWk-qv-CwE\" firstAttribute=\"leading\" secondItem=\"amy-dn-iKo\" secondAttribute=\"trailing\" constant=\"3\" id=\"Hs5-Yf-ZAs\"/>\n                                    <constraint firstItem=\"jiy-7p-SlJ\" firstAttribute=\"top\" secondItem=\"jpo-0u-yWF\" secondAttribute=\"top\" constant=\"26\" id=\"I3K-Xy-WtF\"/>\n                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"240\" id=\"JrP-yY-HG3\"/>\n                                    <constraint firstItem=\"mJ2-l4-FOc\" firstAttribute=\"leading\" secondItem=\"VKv-8h-11O\" secondAttribute=\"trailing\" constant=\"3\" id=\"KOc-pc-r5c\"/>\n                                    <constraint firstItem=\"jiy-7p-SlJ\" firstAttribute=\"leading\" secondItem=\"jpo-0u-yWF\" secondAttribute=\"leading\" constant=\"-1\" id=\"X77-W5-84M\"/>\n                                    <constraint firstItem=\"rnZ-Mh-Tla\" firstAttribute=\"top\" secondItem=\"jpo-0u-yWF\" secondAttribute=\"top\" constant=\"5\" id=\"Z8f-q2-M2Z\"/>\n                                    <constraint firstItem=\"BWk-qv-CwE\" firstAttribute=\"bottom\" secondItem=\"amy-dn-iKo\" secondAttribute=\"bottom\" id=\"fg1-xK-15q\"/>\n                                    <constraint firstItem=\"W1d-Ym-5da\" firstAttribute=\"bottom\" secondItem=\"yTp-UR-uIs\" secondAttribute=\"bottom\" id=\"j6J-aS-BSL\"/>\n                                    <constraint firstItem=\"rnZ-Mh-Tla\" firstAttribute=\"leading\" secondItem=\"mJ2-l4-FOc\" secondAttribute=\"trailing\" constant=\"9\" id=\"jWR-ck-dDy\"/>\n                                    <constraint firstItem=\"amy-dn-iKo\" firstAttribute=\"top\" secondItem=\"jpo-0u-yWF\" secondAttribute=\"top\" constant=\"2\" id=\"jte-EU-DWo\"/>\n                                    <constraint firstItem=\"yTp-UR-uIs\" firstAttribute=\"leading\" secondItem=\"W1d-Ym-5da\" secondAttribute=\"trailing\" constant=\"3\" id=\"ksC-pj-3KH\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"jiy-7p-SlJ\" secondAttribute=\"bottom\" constant=\"-1\" id=\"mmg-h7-Qwn\"/>\n                                    <constraint firstItem=\"BWk-qv-CwE\" firstAttribute=\"bottom\" secondItem=\"VKv-8h-11O\" secondAttribute=\"bottom\" id=\"to7-lC-TcY\"/>\n                                    <constraint firstItem=\"amy-dn-iKo\" firstAttribute=\"leading\" secondItem=\"jpo-0u-yWF\" secondAttribute=\"leading\" constant=\"4\" id=\"xNq-Qu-Dqs\"/>\n                                </constraints>\n                            </customView>\n                            <customView id=\"jtP-eN-5EP\">\n                                <rect key=\"frame\" x=\"519\" y=\"0.0\" width=\"505\" height=\"747\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bzX-Ky-sCf\">\n                                        <rect key=\"frame\" x=\"-1\" y=\"-1\" width=\"507\" height=\"722\"/>\n                                        <clipView key=\"contentView\" id=\"JJ3-E5-rlu\">\n                                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"490\" height=\"720\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <textView importsGraphics=\"NO\" richText=\"NO\" findStyle=\"bar\" allowsUndo=\"YES\" allowsNonContiguousLayout=\"YES\" id=\"hNz-Jr-UfL\" customClass=\"EidosConsoleTextView\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"490\" height=\"720\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                    <size key=\"minSize\" width=\"490\" height=\"720\"/>\n                                                    <size key=\"maxSize\" width=\"507\" height=\"10000000\"/>\n                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <connections>\n                                                        <binding destination=\"Oju-rn-RJg\" name=\"editable\" keyPath=\"interfaceEnabled\" id=\"LC7-Wc-q8E\"/>\n                                                        <outlet property=\"delegate\" destination=\"Oju-rn-RJg\" id=\"kGW-mp-3ID\"/>\n                                                    </connections>\n                                                </textView>\n                                            </subviews>\n                                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </clipView>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"MVN-jY-ZKp\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"ZeK-tm-lkG\">\n                                            <rect key=\"frame\" x=\"491\" y=\"1\" width=\"15\" height=\"720\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cRw-Sd-hbx\">\n                                        <rect key=\"frame\" x=\"31\" y=\"725\" width=\"61\" height=\"17\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Console:\" id=\"ktz-TJ-uHg\">\n                                            <font key=\"font\" metaFont=\"systemBold\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <button toolTip=\"clear console\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ei6-h4-XuP\" userLabel=\"Clear Output Button\">\n                                        <rect key=\"frame\" x=\"4\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"0CS-O6-ZiP\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"jXE-v8-Tj2\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"delete\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"delete_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1E9-ch-Ks0\">\n                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"clearOutput:\" target=\"Oju-rn-RJg\" id=\"sJV-Fb-cn0\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"show tokens\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"urT-CI-yd4\" userLabel=\"Show Tokens Button\">\n                                        <rect key=\"frame\" x=\"434\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"Op1-Yn-asL\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"oJ2-j1-BHT\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_tokens\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"show_tokens_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"sBQ-y3-MVt\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"LR2-bE-pWf\" name=\"value\" keyPath=\"values.EidosShowTokens\" id=\"ZM2-vA-yDl\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"show parse tree\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cEY-2Y-8z7\" userLabel=\"Show AST Button\">\n                                        <rect key=\"frame\" x=\"457\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"r3C-ZO-Yf6\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"xUD-qe-CJY\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_parse\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"show_parse_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"7vC-Ab-MFu\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"LR2-bE-pWf\" name=\"value\" keyPath=\"values.EidosShowParse\" id=\"W8J-Ko-z7R\"/>\n                                        </connections>\n                                    </button>\n                                    <button toolTip=\"show execution\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"P85-4x-4pc\" userLabel=\"Show Execution Button\">\n                                        <rect key=\"frame\" x=\"480\" y=\"723\" width=\"20\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"Prl-BH-SZw\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"SCG-uE-42c\"/>\n                                        </constraints>\n                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_execution\" imagePosition=\"overlaps\" alignment=\"center\" alternateImage=\"show_execution_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"WD2-8B-ncG\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"LR2-bE-pWf\" name=\"value\" keyPath=\"values.EidosShowExecution\" id=\"w1y-IU-Wo5\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"cEY-2Y-8z7\" firstAttribute=\"bottom\" secondItem=\"P85-4x-4pc\" secondAttribute=\"bottom\" id=\"D6c-wg-ngh\"/>\n                                    <constraint firstItem=\"cEY-2Y-8z7\" firstAttribute=\"leading\" secondItem=\"urT-CI-yd4\" secondAttribute=\"trailing\" constant=\"3\" id=\"LRo-dB-XMw\"/>\n                                    <constraint firstItem=\"cRw-Sd-hbx\" firstAttribute=\"leading\" secondItem=\"Ei6-h4-XuP\" secondAttribute=\"trailing\" constant=\"9\" id=\"Nnj-zC-ecJ\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"P85-4x-4pc\" secondAttribute=\"trailing\" constant=\"5\" id=\"Voh-PT-9jv\"/>\n                                    <constraint firstItem=\"Ei6-h4-XuP\" firstAttribute=\"leading\" secondItem=\"jtP-eN-5EP\" secondAttribute=\"leading\" constant=\"4\" id=\"bP2-VB-3xI\"/>\n                                    <constraint firstItem=\"bzX-Ky-sCf\" firstAttribute=\"top\" secondItem=\"jtP-eN-5EP\" secondAttribute=\"top\" constant=\"26\" id=\"cnU-lf-DNj\"/>\n                                    <constraint firstItem=\"Ei6-h4-XuP\" firstAttribute=\"bottom\" secondItem=\"urT-CI-yd4\" secondAttribute=\"bottom\" id=\"cug-PI-EgA\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"bzX-Ky-sCf\" secondAttribute=\"trailing\" constant=\"-1\" id=\"ewS-fL-hYK\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"bzX-Ky-sCf\" secondAttribute=\"bottom\" constant=\"-1\" id=\"nBp-f6-4Pu\"/>\n                                    <constraint firstItem=\"urT-CI-yd4\" firstAttribute=\"bottom\" secondItem=\"cEY-2Y-8z7\" secondAttribute=\"bottom\" id=\"o7b-dN-oGF\"/>\n                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"240\" id=\"pHx-Wz-5wY\"/>\n                                    <constraint firstItem=\"P85-4x-4pc\" firstAttribute=\"leading\" secondItem=\"cEY-2Y-8z7\" secondAttribute=\"trailing\" constant=\"3\" id=\"pdT-Jt-UT6\"/>\n                                    <constraint firstItem=\"bzX-Ky-sCf\" firstAttribute=\"leading\" secondItem=\"jtP-eN-5EP\" secondAttribute=\"leading\" constant=\"-1\" id=\"q9Y-1h-EuG\"/>\n                                    <constraint firstItem=\"Ei6-h4-XuP\" firstAttribute=\"top\" secondItem=\"jtP-eN-5EP\" secondAttribute=\"top\" constant=\"2\" id=\"y45-9V-Tzy\"/>\n                                </constraints>\n                            </customView>\n                        </subviews>\n                        <constraints>\n                            <constraint firstItem=\"cRw-Sd-hbx\" firstAttribute=\"baseline\" secondItem=\"rnZ-Mh-Tla\" secondAttribute=\"baseline\" id=\"EjO-Wt-C4y\"/>\n                        </constraints>\n                        <holdingPriorities>\n                            <real value=\"250\"/>\n                            <real value=\"250\"/>\n                        </holdingPriorities>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"Oju-rn-RJg\" id=\"Xd8-B9-hAA\"/>\n                        </connections>\n                    </splitView>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"150\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kY6-al-Llg\">\n                        <rect key=\"frame\" x=\"-1\" y=\"-1\" width=\"1026\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" refusesFirstResponder=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"zbW-4w-iUT\">\n                            <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"kY6-al-Llg\" secondAttribute=\"trailing\" constant=\"-1\" id=\"AkE-Jj-3Sg\"/>\n                    <constraint firstItem=\"OgO-Qu-oJA\" firstAttribute=\"top\" secondItem=\"P8Z-tg-7Uc\" secondAttribute=\"top\" id=\"B2z-Dm-Aak\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"OgO-Qu-oJA\" secondAttribute=\"trailing\" id=\"Cmc-ke-CJZ\"/>\n                    <constraint firstItem=\"kY6-al-Llg\" firstAttribute=\"top\" secondItem=\"OgO-Qu-oJA\" secondAttribute=\"bottom\" id=\"EGD-ym-hwS\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"kY6-al-Llg\" secondAttribute=\"bottom\" constant=\"-1\" id=\"Yq9-xn-Xpf\"/>\n                    <constraint firstItem=\"OgO-Qu-oJA\" firstAttribute=\"leading\" secondItem=\"P8Z-tg-7Uc\" secondAttribute=\"leading\" id=\"g6f-12-OWu\"/>\n                    <constraint firstItem=\"kY6-al-Llg\" firstAttribute=\"leading\" secondItem=\"P8Z-tg-7Uc\" secondAttribute=\"leading\" constant=\"-1\" id=\"oAn-a3-pd5\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"Oju-rn-RJg\" id=\"IPT-YX-WCW\"/>\n                <outlet property=\"initialFirstResponder\" destination=\"hNz-Jr-UfL\" id=\"VYj-Y2-E15\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"1547\" y=\"1065\"/>\n        </window>\n        <userDefaultsController representsSharedInstance=\"YES\" id=\"LR2-bE-pWf\"/>\n    </objects>\n    <resources>\n        <image name=\"check\" width=\"137\" height=\"137\"/>\n        <image name=\"check_H\" width=\"137\" height=\"137\"/>\n        <image name=\"delete\" width=\"137\" height=\"137\"/>\n        <image name=\"delete_H\" width=\"137\" height=\"137\"/>\n        <image name=\"execute_script\" width=\"137\" height=\"137\"/>\n        <image name=\"execute_script_H\" width=\"137\" height=\"137\"/>\n        <image name=\"execute_selection\" width=\"137\" height=\"137\"/>\n        <image name=\"execute_selection_H\" width=\"137\" height=\"137\"/>\n        <image name=\"prettyprint\" width=\"137\" height=\"137\"/>\n        <image name=\"prettyprint_H\" width=\"137\" height=\"137\"/>\n        <image name=\"show_browser\" width=\"137\" height=\"137\"/>\n        <image name=\"show_browser_H\" width=\"137\" height=\"137\"/>\n        <image name=\"show_execution\" width=\"137\" height=\"137\"/>\n        <image name=\"show_execution_H\" width=\"137\" height=\"137\"/>\n        <image name=\"show_parse\" width=\"137\" height=\"137\"/>\n        <image name=\"show_parse_H\" width=\"137\" height=\"137\"/>\n        <image name=\"show_tokens\" width=\"137\" height=\"137\"/>\n        <image name=\"show_tokens_H\" width=\"137\" height=\"137\"/>\n        <image name=\"syntax_help\" width=\"137\" height=\"137\"/>\n        <image name=\"syntax_help_H\" width=\"137\" height=\"137\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "EidosScribe/Base.lproj/EidosHelpWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16G1114\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"EidosHelpController\">\n            <connections>\n                <outlet property=\"descriptionTextView\" destination=\"epD-FJ-chU\" id=\"Jdq-D0-856\"/>\n                <outlet property=\"helpWindow\" destination=\"QvC-M9-y7g\" id=\"SL9-Lx-Rjt\"/>\n                <outlet property=\"searchField\" destination=\"48u-tK-QYT\" id=\"kme-3a-V2h\"/>\n                <outlet property=\"topicOutlineView\" destination=\"yPI-dd-eV7\" id=\"vDU-32-S1i\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Scripting Help\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"Scripting Help\" animationBehavior=\"default\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"535\" height=\"437\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1057\"/>\n            <value key=\"minSize\" type=\"size\" width=\"470\" height=\"200\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"535\" height=\"437\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <searchField wantsLayer=\"YES\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"48u-tK-QYT\">\n                        <rect key=\"frame\" x=\"5\" y=\"410\" width=\"525\" height=\"22\"/>\n                        <searchFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" borderStyle=\"bezel\" usesSingleLineMode=\"YES\" bezelStyle=\"round\" sendsWholeSearchString=\"YES\" id=\"NYP-eg-QGP\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </searchFieldCell>\n                        <connections>\n                            <action selector=\"searchFieldChanged:\" target=\"-2\" id=\"fey-tJ-m87\"/>\n                            <outlet property=\"searchMenuTemplate\" destination=\"ceq-BX-yvq\" id=\"kdb-E5-ycC\"/>\n                        </connections>\n                    </searchField>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3b8-ab-BQk\">\n                        <rect key=\"frame\" x=\"5\" y=\"5\" width=\"280\" height=\"400\"/>\n                        <clipView key=\"contentView\" id=\"rzI-9X-67k\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"278\" height=\"398\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnReordering=\"NO\" columnResizing=\"NO\" autosaveColumns=\"NO\" indentationPerLevel=\"13\" outlineTableColumn=\"KFM-B1-pe4\" id=\"yPI-dd-eV7\" customClass=\"EidosHelpOutlineView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"278\" height=\"398\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn editable=\"NO\" width=\"275\" minWidth=\"40\" maxWidth=\"1000\" id=\"KFM-B1-pe4\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"Ls2-xz-2Zq\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"chc-b3-IWD\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"1nF-eU-uK4\"/>\n                                    </connections>\n                                </outlineView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"280\" id=\"c3J-bk-dBM\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"MAw-EU-Gqy\">\n                            <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"Ltl-g7-QUD\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sOA-J4-ETm\">\n                        <rect key=\"frame\" x=\"290\" y=\"5\" width=\"240\" height=\"400\"/>\n                        <clipView key=\"contentView\" id=\"xXL-p2-gUm\" customClass=\"EidosLockingClipView\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"238\" height=\"398\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView editable=\"NO\" importsGraphics=\"NO\" findStyle=\"bar\" id=\"epD-FJ-chU\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"238\" height=\"398\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    <size key=\"minSize\" width=\"238\" height=\"398\"/>\n                                    <size key=\"maxSize\" width=\"463\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"1IA-4f-s3z\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"xy9-Nz-80K\">\n                            <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"3b8-ab-BQk\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"5\" id=\"24y-tA-Bja\"/>\n                    <constraint firstItem=\"48u-tK-QYT\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"5\" id=\"5wZ-yY-XfS\"/>\n                    <constraint firstItem=\"sOA-J4-ETm\" firstAttribute=\"top\" secondItem=\"48u-tK-QYT\" secondAttribute=\"bottom\" constant=\"5\" id=\"5yf-tx-PCh\"/>\n                    <constraint firstItem=\"48u-tK-QYT\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"5\" id=\"IZh-pF-YaK\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"3b8-ab-BQk\" secondAttribute=\"bottom\" constant=\"5\" id=\"LLa-EK-5OH\"/>\n                    <constraint firstItem=\"3b8-ab-BQk\" firstAttribute=\"top\" secondItem=\"48u-tK-QYT\" secondAttribute=\"bottom\" constant=\"5\" id=\"MCp-Sb-e4S\"/>\n                    <constraint firstItem=\"sOA-J4-ETm\" firstAttribute=\"leading\" secondItem=\"3b8-ab-BQk\" secondAttribute=\"trailing\" constant=\"5\" id=\"Utv-n2-kg2\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"sOA-J4-ETm\" secondAttribute=\"trailing\" constant=\"5\" id=\"dZ1-rQ-VZP\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"sOA-J4-ETm\" secondAttribute=\"bottom\" constant=\"5\" id=\"hIE-5J-s42\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"48u-tK-QYT\" secondAttribute=\"trailing\" constant=\"5\" id=\"mVp-tB-tYb\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"1168.5\" y=\"833.5\"/>\n        </window>\n        <menu id=\"ceq-BX-yvq\">\n            <items>\n                <menuItem title=\"Title\" state=\"on\" id=\"eVK-eE-BOo\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"searchTypeChanged:\" target=\"-2\" id=\"XrO-YK-Xs6\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Content\" tag=\"1\" id=\"jRV-MC-W2J\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"searchTypeChanged:\" target=\"-2\" id=\"lwi-MT-nOr\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"780.5\" y=\"1326.5\"/>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "EidosScribe/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16G29\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"EidosAppDelegate\"/>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"EidosScribe\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"EidosScribe\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About EidosScribe\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showAboutWindow:\" target=\"Voe-Tx-rLC\" id=\"taZ-Y1-5v7\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide EidosScribe\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit EidosScribe\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                        <items>\n                            <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                <connections>\n                                    <action selector=\"newDocument:\" target=\"-1\" id=\"4Si-XN-c54\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                <connections>\n                                    <action selector=\"openDocument:\" target=\"-1\" id=\"bVn-NM-KNZ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                    <items>\n                                        <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"clearRecentDocuments:\" target=\"-1\" id=\"Daa-9d-B3U\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                            <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                <connections>\n                                    <action selector=\"performClose:\" target=\"-1\" id=\"HmO-Ls-i7Q\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                <connections>\n                                    <action selector=\"saveDocument:\" target=\"-1\" id=\"teZ-XB-qJY\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                <connections>\n                                    <action selector=\"saveDocumentAs:\" target=\"-1\" id=\"mDf-zr-I0C\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Revert to Saved\" id=\"KaW-ft-85H\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"revertDocumentToSaved:\" target=\"-1\" id=\"iJ3-Pv-kwq\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                            <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"runPageLayout:\" target=\"-1\" id=\"Din-rz-gC5\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                <connections>\n                                    <action selector=\"print:\" target=\"-1\" id=\"qaZ-4w-aoO\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy As Paragraph\" alternate=\"YES\" keyEquivalent=\"c\" id=\"uOX-3J-tcu\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"copyAsParagraph:\" target=\"-1\" id=\"1rs-pZ-xWU\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cD7-Qs-BN4\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"NDo-RZ-v9R\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"HOh-sY-3ay\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"sPh-Tk-edu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"iUZ-b5-hil\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"26H-TL-nsh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"Ag7-ud-N8J\"/>\n                            <menuItem title=\"Shift Left\" keyEquivalent=\"[\" id=\"7fU-LO-jP2\">\n                                <connections>\n                                    <action selector=\"shiftSelectionLeft:\" target=\"-1\" id=\"kmf-It-iLJ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Shift Right\" keyEquivalent=\"]\" id=\"yAi-3e-02u\">\n                                <connections>\n                                    <action selector=\"shiftSelectionRight:\" target=\"-1\" id=\"4jm-Ja-yAY\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Comment / Uncomment\" keyEquivalent=\"/\" id=\"N0Z-N1-zHP\">\n                                <connections>\n                                    <action selector=\"commentUncommentSelection:\" target=\"-1\" id=\"jBS-dk-5Yh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Script\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Script\" id=\"HyV-fh-RgO\">\n                        <items>\n                            <menuItem title=\"Check Script\" keyEquivalent=\"=\" id=\"oBK-h1-E5p\">\n                                <connections>\n                                    <action selector=\"checkScript:\" target=\"-1\" id=\"fIe-hN-GV1\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Prettyprint Script\" keyEquivalent=\"=\" id=\"M4t-xf-YMI\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"prettyprintScript:\" target=\"-1\" id=\"Cl2-28-Aba\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show Script Help\" id=\"L5L-eY-gNf\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showScriptHelp:\" target=\"-1\" id=\"67M-ye-fxJ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"Rfr-hn-vm4\"/>\n                            <menuItem title=\"Show Variable Browser\" keyEquivalent=\"b\" id=\"bJP-6x-Daf\">\n                                <connections>\n                                    <action selector=\"toggleBrowserVisibility:\" target=\"-1\" id=\"bXj-SN-Sy7\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"dWD-BF-u08\"/>\n                            <menuItem title=\"Clear Output\" keyEquivalent=\"k\" id=\"8MA-dW-zyg\">\n                                <connections>\n                                    <action selector=\"clearOutput:\" target=\"-1\" id=\"qed-2e-cTt\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"QuT-O5-C72\"/>\n                            <menuItem title=\"Execute Selection\" id=\"00O-MD-1Dr\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                                <connections>\n                                    <action selector=\"executeSelection:\" target=\"-1\" id=\"uCs-T3-UxN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Execute All\" id=\"53Q-z8-qs4\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"executeAll:\" target=\"-1\" id=\"APe-d5-Lrd\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"Uxv-x6-dpe\"/>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"epM-So-x5W\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"dWG-0V-0LE\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                        <items>\n                            <menuItem title=\"EidosScribe Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                <connections>\n                                    <action selector=\"showHelp:\" target=\"Voe-Tx-rLC\" id=\"x5Z-K0-5y8\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"02i-M1-lDI\"/>\n                            <menuItem title=\"Send Feedback on Eidos\" id=\"Rb2-Li-Na8\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"sendFeedback:\" target=\"Voe-Tx-rLC\" id=\"ydd-9q-9Dh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"fIh-ql-Nxy\"/>\n                            <menuItem title=\"Eidos Home Page\" id=\"chy-2l-Hqa\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showEidosHomePage:\" target=\"Voe-Tx-rLC\" id=\"6nZ-1y-OgL\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About the Messer Lab\" id=\"zdG-NR-pNh\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showMesserLab:\" target=\"Voe-Tx-rLC\" id=\"6aq-iQ-YKj\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About Ben Haller\" id=\"yhH-YO-dTk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showBenHaller:\" target=\"Voe-Tx-rLC\" id=\"7q5-Xb-pG8\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About Stick Software\" id=\"Bk3-8O-YRs\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showStickSoftware:\" target=\"Voe-Tx-rLC\" id=\"c54-Y3-5BK\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n            </items>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "EidosScribe/EidosAppDelegate.h",
    "content": "//\n//  EidosAppDelegate.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n@class EidosConsoleWindowController;\n\n\n/*\n \n EidosAppDelegate is an NSApplication delegate for EidosScribe that provides some behavior for menu items and such.\n If you make your own Context app, you are unlikely to want to reuse this class, although it might illustrate\n how to set up an EidosConsoleWindowController.\n \n */\n\n\n@interface EidosAppDelegate : NSObject\n{\n}\n\n// An outlet for the console controller, associated with EidosConsoleWindow.xib\n@property (nonatomic, retain) IBOutlet EidosConsoleWindowController *consoleController;\n\n// Actions for menu commands in MainMenu.xib\n- (IBAction)showAboutWindow:(id)sender;\n\n- (IBAction)sendFeedback:(id)sender;\n- (IBAction)showMesserLab:(id)sender;\n- (IBAction)showBenHaller:(id)sender;\n- (IBAction)showStickSoftware:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosAppDelegate.mm",
    "content": "//\n//  EidosAppDelegate.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosAppDelegate.h\"\n#import \"EidosTextView.h\"\n#import \"EidosValueWrapper.h\"\n#import \"EidosConsoleWindowController.h\"\n#import \"EidosConsoleWindowControllerDelegate.h\"\n#import \"EidosHelpController.h\"\n#import \"EidosCocoaExtra.h\"\n#import \"eidos_beep.h\"\n\n#include \"eidos_globals.h\"\n#include \"eidos_test.h\"\n\n#include <stdexcept>\n\n\n@interface EidosAppDelegate () <NSApplicationDelegate, EidosConsoleWindowControllerDelegate>\n{\n\t// About window outlets associated with EidosAboutWindow.xib\n\tIBOutlet NSWindow *aboutWindow;\n\tIBOutlet NSTextField *aboutVersionTextField;\n\tIBOutlet NSTextField *messerLabLineTextField;\n\tIBOutlet NSTextField *benHallerLineTextField;\n\tIBOutlet NSTextField *licenseTextField;\n}\n@end\n\n\n@implementation EidosAppDelegate\n\n- (void)dealloc\n{\n\t// Ask the console controller to forget us as its delegate, to avoid a stale pointer\n\t[_consoleController setDelegate:nil];\n\t\n\t[self setConsoleController:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)applicationWillFinishLaunching:(NSNotification *)aNotification\n{\n    // Require light appearance, at least for now; supporting dark mode would require custom art etc.\n    if ([NSApp respondsToSelector:@selector(setAppearance:)])\n        [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];\n    \n\t// Install our custom beep handler\n\tEidos_Beep = &Eidos_Beep_MACOS;\n\t\n\t// Warm up our back end before anything else happens\n#ifdef _OPENMP\n\t// Multithreading in EidosScribe is not for end user use; this is for testing/debugging only.\n\t// We always use 4 threads; we don't want to hog the whole machine, just run with a couple threads.\n\t// We pass false for active_threads to let the worker threads sleep, otherwise the CPU is pegged\n\t// the whole time EidosScribe is running, even when sitting idle.\n\tEidos_WarmUpOpenMP(&std::cout, true, 4, false, /* default per-task thread counts */ \"\");\n#endif\n\t\n\tEidos_WarmUp();\n}\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification\n{\n\t// Load our console window nib; we are set up as the delegate in the nib\n\t[[NSBundle mainBundle] loadNibNamed:@\"EidosConsoleWindow\" owner:self topLevelObjects:NULL];\n\t\n\t// Make the console window visible\n\t[_consoleController showWindow];\n\t\n\t// Show a status message\n\t[_consoleController displayStartupMessage];\n}\n\n\n//\n//\tActions\n//\n#pragma mark -\n#pragma mark Actions\n\n- (IBAction)showAboutWindow:(id)sender\n{\n\t[[NSBundle mainBundle] loadNibNamed:@\"EidosAboutWindow\" owner:self topLevelObjects:NULL];\n\t\n\t// The window is the top-level object in this nib.  It will release itself when closed, so we will retain it on its behalf here.\n\t// Note that the aboutWindow and aboutWebView outlets do not get zeroed out when the about window closes; but we only use them here.\n\t// This is not very clean programming practice – just a quick and dirty hack – so don't emulate this code.  :->\n\t[aboutWindow retain];\n\t\n\t// Set our version number string\n\tNSString *bundleVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"CFBundleShortVersionString\"];\n\tNSString *versionString = [NSString stringWithFormat:@\"version %@\", bundleVersionString];\n\t\n\t[aboutVersionTextField setStringValue:versionString];\n\t\n\t// Fix up hyperlinks\n\t[messerLabLineTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://messerlab.org/slim/\"] onText:@\"http://messerlab.org/slim/\"];\n\t[benHallerLineTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://benhaller.com/\"] onText:@\"http://benhaller.com/\"];\n\t[licenseTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://www.gnu.org/licenses/\"] onText:@\"http://www.gnu.org/licenses/\"];\n\t\n\t// Now that everything is set up, show the window\n\t[aboutWindow makeKeyAndOrderFront:nil];\n}\n\n- (IBAction)sendFeedback:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"mailto:philipp.messer@gmail.com?subject=Eidos%20Feedback\"]];\n}\n\n- (IBAction)showEidosHomePage:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://benhaller.com/eidos.html\"]];\n}\n\n- (IBAction)showMesserLab:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://messerlab.org/\"]];\n}\n\n- (IBAction)showBenHaller:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://www.benhaller.com/\"]];\n}\n\n- (IBAction)showStickSoftware:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://www.sticksoftware.com/\"]];\n}\n\n- (IBAction)showHelp:(id)sender\n{\n\t[[EidosHelpController sharedController] showWindow];\n}\n\n// Dummy actions; see validateMenuItem:\n- (IBAction)toggleConsoleVisibility:(id)sender {}\n- (IBAction)toggleBrowserVisibility:(id)sender {}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\t// Handle validation for menu items that really belong to the console window.  This provides a default validation\n\t// for these menu items when no console window is receiving.\n\tif (sel == @selector(toggleConsoleVisibility:))\n\t{\n\t\t[menuItem setTitle:@\"Show Eidos Console\"];\n\t\treturn NO;\n\t}\n\tif (sel == @selector(toggleBrowserVisibility:))\n\t{\n\t\t[menuItem setTitle:@\"Show Variable Browser\"];\n\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n\n//\n//\tEidosConsoleWindowControllerDelegate methods\n//\n#pragma mark -\n#pragma mark EidosConsoleWindowControllerDelegate\n\n- (void)eidosConsoleWindowControllerAppendWelcomeMessageAddendum:(EidosConsoleWindowController *)eidosConsoleController\n{\n\t// EidosScribe runs the standard Eidos test suite on launch if the option key is down.\n\t// You would probably not want to do this in your own Context.\n\tif ([NSEvent modifierFlags] & NSEventModifierFlagOption)\n\t\tRunEidosTests();\n}\n\n- (void)eidosConsoleWindowControllerConsoleWindowWillClose:(EidosConsoleWindowController *)eidosConsoleController\n{\n\t// EidosScribe quits when its console window is closed, but that\n\t// behavior is not in any way required or expected.\n\tNSApplication *app = [NSApplication sharedApplication];\n\t\n\t[app terminate:nil];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosCocoaExtra.h",
    "content": "//\n//  EidosCocoaExtra.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#include <string>\n\nclass EidosCallSignature;\nclass EidosPropertySignature;\n\n\n/*\n \n Some Cocoa utility categories for working with Eidos.  Note that this header uses Objective-C++, so it can only be imported by\n Objective-C++ compilations (.mm files instead of .m files).  The hope is that the use of Objective-C++ in EidosScribe headers\n can be limited mostly to this file and a few others, so that reuse of main EidosScribe UI classes in a new Context does not\n force the entire project to be Objective-C++.\n \n */\n\n\n@interface NSAttributedString (EidosAdditions)\n\n// This provides a nicely syntax-colored call signature string for use in the console window status bar and such places.\n+ (NSAttributedString *)eidosAttributedStringForCallSignature:(const EidosCallSignature *)signature size:(double)fontSize;\n+ (NSAttributedString *)eidosAttributedStringForPropertySignature:(const EidosPropertySignature *)signature size:(double)fontSize;\n\n@end\n\n@interface NSMutableAttributedString (EidosAdditions)\n\n// A shorthand to avoid having to construct autoreleased temporary attributed strings\n- (void)eidosAppendString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs;\n\n@end\n\n\n@interface NSDictionary (EidosAdditions)\n\n// The standard font (Menlo 11 with 3-space tabs) with a given color, used to assemble attributed strings\n+ (NSDictionary *)eidosTextAttributesWithColor:(NSColor *)textColor size:(double)fontSize;\n\n// Some standard attribute dictionaries for Eidos syntax coloring\n+ (NSDictionary *)eidosPromptAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosInputAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosOutputAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosErrorAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosTokensAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosParseAttrsWithSize:(double)fontSize;\n+ (NSDictionary *)eidosExecutionAttrsWithSize:(double)fontSize;\n\n// Add a hyperlink to an existing attribute dictionary\n+ (NSDictionary *)eidosBaseAttributes:(NSDictionary *)baseAttrs withHyperlink:(NSString *)link;\n\n@end\n\n\n@interface NSSplitView (EidosAdditions)\n\n// A bug fix to make NSSplitView correctly restore its position/layout.\n// Borrowed from http://stackoverflow.com/questions/16587058/nssplitview-auto-saving-divider-positions-doesnt-work-with-auto-layout-enable\n// Ah, NSSplitView, how I love thee?  Let me count the ways.  OK, I'm done counting.\n\n// BCH 25 April 2017: added the autosaveName parameter so that we can restore from our autosave before setting\n// the autosave name on the splitview, because Apple has broken NSSplitView even more severely than before...\n- (void)eidosRestoreAutosavedPositionsWithName:(NSString *)autosaveName;\n\n@end\n\n\n@interface NSTextField (EidosAdditions)\n\n- (void)eidosSetHyperlink:(NSURL *)url onText:(NSString *)text;\n\n@end\n\n@interface NSString (EidosAdditions)\n\n- (int64_t)eidosScoreAsCompletionOfString:(NSString *)completionBase;\n\n@end\n\n\nextern std::string Eidos_Beep_MACOS(const std::string &p_sound_name);\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosCocoaExtra.mm",
    "content": "//\n//  EidosCocoaExtra.m\n//  SLiM\n//\n//  Created by Ben Haller on 9/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosCocoaExtra.h\"\n\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_value.h\"\n#include \"eidos_beep.h\"\n\n\n@implementation NSAttributedString (EidosAdditions)\n\n+ (NSAttributedString *)eidosAttributedStringForCallSignature:(const EidosCallSignature *)signature size:(double)fontSize\n{\n\tif (signature)\n\t{\n\t\t//\n\t\t//\tNote this logic is paralleled in the function operator<<(ostream &, const EidosCallSignature &).\n\t\t//\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n\t\t//\n\t\t\n\t\t// Build an attributed string showing the call signature with syntax coloring for its parts\n\t\tNSMutableAttributedString *attrStr = [[[NSMutableAttributedString alloc] init] autorelease];\n\t\t\n\t\tstd::string &&prefix_string = signature->CallPrefix();\n\t\tNSString *prefixString = [NSString stringWithUTF8String:prefix_string.c_str()];\t// \"\", \"–\\u00A0\", or \"+\\u00A0\"\n\t\tstd::string &&return_type_string = StringForEidosValueMask(signature->return_mask_, signature->return_class_, \"\", nullptr);\n\t\tNSString *returnTypeString = [NSString stringWithUTF8String:return_type_string.c_str()];\n\t\tNSString *functionNameString = [NSString stringWithUTF8String:signature->call_name_.c_str()];\n\t\t\n\t\tNSDictionary *plainAttrs = [NSDictionary eidosOutputAttrsWithSize:fontSize];\n\t\tNSDictionary *typeAttrs = [NSDictionary eidosInputAttrsWithSize:fontSize];\n\t\tNSDictionary *functionAttrs = [NSDictionary eidosParseAttrsWithSize:fontSize];\n\t\tNSDictionary *paramAttrs = [NSDictionary eidosPromptAttrsWithSize:fontSize];\n\t\t\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:prefixString attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"(\" attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:returnTypeString attributes:typeAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\")\" attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:functionNameString attributes:functionAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"(\" attributes:plainAttrs] autorelease]];\n\t\t\n\t\tint arg_mask_count = (int)signature->arg_masks_.size();\n\t\t\n\t\tif (arg_mask_count == 0)\n\t\t{\n\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"void\" attributes:typeAttrs] autorelease]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (int arg_index = 0; arg_index < arg_mask_count; ++arg_index)\n\t\t\t{\n\t\t\t\tEidosValueMask type_mask = signature->arg_masks_[arg_index];\n\t\t\t\tconst std::string &arg_name = signature->arg_names_[arg_index];\n\t\t\t\tconst EidosClass *arg_obj_class = signature->arg_classes_[arg_index];\n\t\t\t\tEidosValue_SP arg_default = signature->arg_defaults_[arg_index];\n\t\t\t\t\n\t\t\t\t// skip private arguments\n\t\t\t\tif ((arg_name.length() >= 1) && (arg_name[0] == '_'))\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tif (arg_index > 0)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\", \" attributes:plainAttrs] autorelease]];\n\t\t\t\t\n\t\t\t\t//\n\t\t\t\t//\tNote this logic is paralleled in the function StringForEidosValueMask().\n\t\t\t\t//\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n\t\t\t\t//\n\t\t\t\tif (arg_name == gEidosStr_ELLIPSIS)\n\t\t\t\t{\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"...\" attributes:plainAttrs] autorelease]];\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbool is_optional = !!(type_mask & kEidosValueMaskOptional);\n\t\t\t\tbool requires_singleton = !!(type_mask & kEidosValueMaskSingleton);\n\t\t\t\tEidosValueMask stripped_mask = type_mask & kEidosValueMaskFlagStrip;\n\t\t\t\t\n\t\t\t\tif (is_optional)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"[\" attributes:plainAttrs] autorelease]];\n\t\t\t\t\n\t\t\t\tif (stripped_mask == kEidosValueMaskNone)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"?\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskAny)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"*\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskAnyBase)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"+\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskVOID)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"void\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskNULL)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"NULL\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskLogical)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"logical\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskString)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"string\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskInt)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"integer\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskFloat)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"float\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskObject)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"object\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse if (stripped_mask == kEidosValueMaskNumeric)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"numeric\" attributes:typeAttrs] autorelease]];\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskVOID)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"v\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskNULL)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"N\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskLogical)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"l\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskInt)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"i\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskFloat)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"f\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskString)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"s\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\tif (stripped_mask & kEidosValueMaskObject)\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"o\" attributes:typeAttrs] autorelease]];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (arg_obj_class && (stripped_mask & kEidosValueMaskObject))\n\t\t\t\t{\n\t\t\t\t\tconst std::string &obj_type_name = arg_obj_class->ClassNameForDisplay();\n\t\t\t\t\tNSString *objTypeName = [NSString stringWithUTF8String:obj_type_name.c_str()];\n\t\t\t\t\t\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"<\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:objTypeName attributes:typeAttrs] autorelease]];\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\">\" attributes:typeAttrs] autorelease]];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (requires_singleton)\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"$\" attributes:typeAttrs] autorelease]];\n\t\t\t\t\n\t\t\t\tif (arg_name.length() > 0)\n\t\t\t\t{\n\t\t\t\t\tNSString *argName = [NSString stringWithUTF8String:arg_name.c_str()];\n\t\t\t\t\t\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"\\u00A0\" attributes:plainAttrs] autorelease]];\t// non-breaking space\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:argName attributes:paramAttrs] autorelease]];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (is_optional)\n\t\t\t\t{\n\t\t\t\t\tif (arg_default && (arg_default != gStaticEidosValueNULLInvisible.get()))\n\t\t\t\t\t{\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"\\u00A0=\\u00A0\" attributes:plainAttrs] autorelease]];\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::ostringstream default_string_stream;\n\t\t\t\t\t\t\n\t\t\t\t\t\targ_default->Print(default_string_stream);\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string &&default_string = default_string_stream.str();\n\t\t\t\t\t\tNSString *defaultString = [NSString stringWithUTF8String:default_string.c_str()];\n\t\t\t\t\t\t\n\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:defaultString attributes:plainAttrs] autorelease]];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"]\" attributes:plainAttrs] autorelease]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\")\" attributes:plainAttrs] autorelease]];\n\t\t\n\t\t// if the function is provided by a delegate, show the delegate's name\n\t\t//p_outstream << p_signature.CallDelegate();\n\t\t\n\t\t[attrStr addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [attrStr length])];\n\t\t\n\t\treturn attrStr;\n\t}\n\t\n\treturn [[[NSAttributedString alloc] init] autorelease];\n}\n\n+ (NSAttributedString *)eidosAttributedStringForPropertySignature:(const EidosPropertySignature *)signature size:(double)fontSize\n{\n\tif (signature)\n\t{\n\t\t//\n\t\t//\tNote this logic is paralleled in the function operator<<(ostream &, const EidosPropertySignature &).\n\t\t//\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n\t\t//\n\t\t\n\t\t// Build an attributed string showing the call signature with syntax coloring for its parts\n\t\tNSMutableAttributedString *attrStr = [[[NSMutableAttributedString alloc] init] autorelease];\n\t\t\n\t\tstd::string &&connector_string = signature->PropertySymbol();\n\t\tNSString *connectorString = [NSString stringWithUTF8String:connector_string.c_str()];\t// \"<–>\" or \"=>\"\n\t\tstd::string &&value_type_string = StringForEidosValueMask(signature->value_mask_, signature->value_class_, \"\", nullptr);\n\t\tNSString *valueTypeString = [NSString stringWithUTF8String:value_type_string.c_str()];\n\t\tNSString *propertyNameString = [NSString stringWithUTF8String:signature->property_name_.c_str()];\n\t\t\n\t\tNSDictionary *plainAttrs = [NSDictionary eidosOutputAttrsWithSize:fontSize];\n\t\tNSDictionary *typeAttrs = [NSDictionary eidosInputAttrsWithSize:fontSize];\n\t\tNSDictionary *functionAttrs = [NSDictionary eidosParseAttrsWithSize:fontSize];\n\t\t\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:propertyNameString attributes:functionAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\" \" attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:connectorString attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\" (\" attributes:plainAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:valueTypeString attributes:typeAttrs] autorelease]];\n\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\")\" attributes:plainAttrs] autorelease]];\n\t\t\n\t\t[attrStr addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [attrStr length])];\n\t\t\n\t\treturn attrStr;\n\t}\n\t\n\treturn [[[NSAttributedString alloc] init] autorelease];\n}\n\n@end\n\n@implementation NSMutableAttributedString (EidosAdditions)\n\n// A shorthand to avoid having to construct autoreleased temporary attributed strings\n- (void)eidosAppendString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs\n{\n\tNSAttributedString *tempString = [[NSAttributedString alloc] initWithString:str attributes:attrs];\n\t\n\t[self appendAttributedString:tempString];\n\t[tempString release];\n}\n\n@end\n\n\n@implementation NSDictionary (EidosAdditions)\n\n+ (NSDictionary *)eidosTextAttributesWithColor:(NSColor *)textColor size:(double)fontSize\n{\n\tstatic double menloFontSize = 0.0;\n\tstatic NSFont *menloFont = nil;\n\tstatic NSMutableParagraphStyle *paragraphStyle = nil;\n\tbool recachedFont = false;\n\t\n\tif (!menloFont || (menloFontSize != fontSize))\n\t{\n\t\tif (menloFont)\n\t\t\t[menloFont release];\n\t\t\n\t\tmenloFont = [[NSFont fontWithName:@\"Menlo\" size:fontSize] retain];\n\t\trecachedFont = true;\n\t}\n\t\n\tif (!paragraphStyle || recachedFont)\n\t{\n\t\tif (paragraphStyle)\n\t\t\t[paragraphStyle release];\n\t\t\n\t\tparagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];\n\t\t\n\t\tCGFloat tabInterval = [menloFont maximumAdvancement].width * 3;\n\t\tNSMutableArray *tabs = [NSMutableArray array];\n\t\t\n\t\t[paragraphStyle setDefaultTabInterval:tabInterval];\n\t\t\n\t\tfor (int tabStop = 1; tabStop <= 20; ++tabStop)\n\t\t\t[tabs addObject:[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:tabInterval * tabStop options:@{}]];\t// @{} suppresses a non-null warning, but should not be necessary; Apple header bug\n\t\t\n\t\t[paragraphStyle setTabStops:tabs];\n\t}\n\t\n\tmenloFontSize = fontSize;\n\t\n\tif (textColor)\n\t\treturn @{NSForegroundColorAttributeName : textColor, NSFontAttributeName : menloFont, NSParagraphStyleAttributeName : paragraphStyle};\n\telse\n\t\treturn @{NSFontAttributeName : menloFont, NSParagraphStyleAttributeName : paragraphStyle};\n}\n\n+ (NSDictionary *)eidosPromptAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *promptAttrs = nil;\n\t\n\tif (!promptAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (promptAttrs)\n\t\t\t[promptAttrs release];\n\t\t\n\t\tpromptAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:170/255.0 green:13/255.0 blue:145/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn promptAttrs;\n}\n\n+ (NSDictionary *)eidosInputAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *inputAttrs = nil;\n\t\n\tif (!inputAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (inputAttrs)\n\t\t\t[inputAttrs release];\n\t\t\n\t\tinputAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:28/255.0 green:0/255.0 blue:207/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn inputAttrs;\n}\n\n+ (NSDictionary *)eidosOutputAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *outputAttrs = nil;\n\t\n\tif (!outputAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (outputAttrs)\n\t\t\t[outputAttrs release];\n\t\t\n\t\toutputAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn outputAttrs;\n}\n\n+ (NSDictionary *)eidosErrorAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *errorAttrs = nil;\n\t\n\tif (!errorAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (errorAttrs)\n\t\t\t[errorAttrs release];\n\t\t\n\t\terrorAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:196/255.0 green:26/255.0 blue:22/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn errorAttrs;\n}\n\n+ (NSDictionary *)eidosTokensAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *tokensAttrs = nil;\n\t\n\tif (!tokensAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (tokensAttrs)\n\t\t\t[tokensAttrs release];\n\t\t\n\t\ttokensAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:100/255.0 green:56/255.0 blue:32/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn tokensAttrs;\n}\n\n+ (NSDictionary *)eidosParseAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *parseAttrs = nil;\n\t\n\tif (!parseAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (parseAttrs)\n\t\t\t[parseAttrs release];\n\t\t\n\t\tparseAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:0/255.0 green:116/255.0 blue:0/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn parseAttrs;\n}\n\n+ (NSDictionary *)eidosExecutionAttrsWithSize:(double)fontSize\n{\n\tstatic double cachedFontSize = 0.0;\n\tstatic NSDictionary *executionAttrs = nil;\n\t\n\tif (!executionAttrs || (fontSize != cachedFontSize))\n\t{\n\t\tif (executionAttrs)\n\t\t\t[executionAttrs release];\n\t\t\n\t\texecutionAttrs = [[NSDictionary eidosTextAttributesWithColor:[NSColor colorWithCalibratedRed:63/255.0 green:110/255.0 blue:116/255.0 alpha:1.0] size:fontSize] retain];\n\t}\n\t\n\treturn executionAttrs;\n}\n\n+ (NSDictionary *)eidosBaseAttributes:(NSDictionary *)baseAttrs withHyperlink:(NSString *)link\n{\n\tNSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithDictionary:baseAttrs];\n\t\n\t[attrs setObject:link forKey:NSLinkAttributeName];\n\t\n\treturn attrs;\n}\n\n@end\n\n\n@implementation NSSplitView (EidosAdditions)\n\n- (void)eidosRestoreAutosavedPositionsWithName:(NSString *)autosaveName\n{\n\tNSString *key = [NSString stringWithFormat:@\"NSSplitView Subview Frames %@\", autosaveName];\n\tNSArray *subviewFrames = [[NSUserDefaults standardUserDefaults] valueForKey:key];\n\t\n\t// the last frame is skipped because I have one less divider than I have frames\n\tfor (NSUInteger i = 0; i < subviewFrames.count; i++)\n\t{\n\t\tif (i < self.subviews.count)\t // safety-check (in case number of views have been removed while dev)\n\t\t{\n\t\t\t// this is the saved frame data - it's an NSString\n\t\t\tNSString *frameString = subviewFrames[i];\n\t\t\tNSArray *components = [frameString componentsSeparatedByString:@\", \"];\n\t\t\t\n\t\t\t// Manage the 'hidden state' per view\n\t\t\tBOOL hidden = [components[4] boolValue];\n\t\t\tNSView *subView = [self subviews][i];\n\t\t\t[subView setHidden:hidden];\n\t\t\t\n\t\t\t// Set height (horizontal) or width (vertical)\n\t\t\tif (![self isVertical])\t\t// BCH 4/7/2016: vertical property not available in 10.9\n\t\t\t{\n\t\t\t\tCGFloat height = [components[3] floatValue];\n\t\t\t\t[subView setFrameSize:NSMakeSize(subView.frame.size.width, height)];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCGFloat width = [components[2] floatValue];\n\t\t\t\t[subView setFrameSize:NSMakeSize(width, subView.frame.size.height)];\n\t\t\t}\n\t\t}\n\t}\n}\n\n@end\n\n\n@implementation NSTextField (EidosAdditions)\n\n- (void)eidosSetHyperlink:(NSURL *)url onText:(NSString *)text\n{\n\tNSMutableAttributedString *attrString = [[self attributedStringValue] mutableCopy];\n\tNSString *string = [attrString string];\n\tNSRange range = [string rangeOfString:text];\n\t\n\tif (range.location != NSNotFound)\n\t{\n\t\t// Apple sez: both are needed, otherwise hyperlink won't accept mousedown\n\t\t[self setAllowsEditingTextAttributes: YES];\n\t\t[self setSelectable: YES];\n\t\t\n\t\t// Add the link attribute\n\t\t[attrString beginEditing];\n\t\t\n\t\t[attrString addAttribute:NSLinkAttributeName value:[url absoluteString] range:range];\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// link\n\t\t[attrString addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.7 alpha:1.0] range:range];\t\t// dark blue\n\t\t[attrString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:range];\t\t\t\t\t\t\t// underlined\n\t\t\n\t\t[attrString endEditing];\n\t\t\n\t\t[self setAttributedStringValue:attrString];\n\t}\n\t\n\t[attrString release];\n}\n\n@end\n\n\n// Eidos_Beep() is declared in eidos_beep.h, with a default implementation; in the GUI case (EidosScribe and SLiMgui)\n// it is redefined here, because we want to be able to use Objective-C and Cocoa.\nstd::string Eidos_Beep_MACOS(const std::string &p_sound_name)\n{\n\tNSString *soundName = [NSString stringWithUTF8String:p_sound_name.c_str()];\n\t\n\tif (!soundName || ![soundName length])\n\t\tsoundName = @\"Pop\";\n\t\n\tstatic NSSound *cachedSound = nil;\n\tstatic NSTimeInterval cachedSoundDuration = 0;\n\tstatic NSString *cachedSoundName = nil;\n\tstatic NSDate *playFinishDate = nil;\n\t\n\tstd::string return_string;\n\t\n\t// If playFinishDate is non-nil, we started playing a sound before, and we need to wait synchronously here for it to finish\n\tif (playFinishDate)\n\t{\n\t\tNSTimeInterval remainingTime = [playFinishDate timeIntervalSinceNow];\n\t\t\n\t\tif (remainingTime > 0)\n\t\t\tusleep((useconds_t)(remainingTime * 1000000.0));\n\t\t\n\t\t[playFinishDate release];\n\t\tplayFinishDate = nil;\n\t}\n\t\n\t// If cachedSound is non-nil, we played it in the past, and we should now make sure that it is stopped, otherwise it ignores -play\n\tif (cachedSound)\n\t\t[cachedSound stop];\n\t\n\t// Now we switch cachedSound over to the requested sound\n\tif (!cachedSound || ![soundName isEqualToString:cachedSoundName])\n\t{\n\t\t[cachedSound release];\n\t\t[cachedSoundName release];\n\t\t\n\t\tcachedSound = [[NSSound soundNamed:soundName] retain];\n\t\t\n\t\t// If the requested sound did not exist, we fall back on the default, which ought to always exist\n\t\tif (!cachedSound)\n\t\t{\n\t\t\treturn_string = \"#WARNING (Eidos_Beep): function beep() could not find the requested sound.\";\n\t\t\t\n\t\t\tsoundName = @\"Pop\";\n\t\t\tcachedSound = [[NSSound soundNamed:soundName] retain];\n\t\t}\n\t\t\n\t\tcachedSoundName = [soundName retain];\n\t\tcachedSoundDuration = [cachedSound duration];\n\t}\n\t\n\t// Start playing our sound.  We return immediately, but we make a note of when we expect the sound to stop playing.  If we get called\n\t// again to play a sound before the current one has finished, we will synchronously wait the remaining time, above.\n\t[cachedSound play];\n\tplayFinishDate = [[NSDate dateWithTimeIntervalSinceNow:cachedSoundDuration] retain];\n\t\n\treturn return_string;\n}\n\n\n@implementation NSString (EidosAdditions)\n\n- (int64_t)eidosScoreAsCompletionOfString:(NSString *)base\n{\n\t// Evaluate the quality of the target as a completion for completionBase and return a score.\n\t// We look for each character of completionBase in self, in order, case-insensitive; all\n\t// characters must be present in order for the target to be a completion at all.  Beyond that,\n\t// a higher score is garnered if the matches in self are (1) either uppercase or the 0th character,\n\t// and (2) if they are relatively near the beginning, and (3) if they occur contiguously.\n\tint64_t score = 0;\n\tNSUInteger selfLength = [self length], baseLength = [base length];\n\t\n\t// Do the comparison scan; find a match for each composed character sequence in base.  We work\n\t// with composed character sequences and use rangeOfString: to do searches, to avoid issues with\n\t// diacritical marks, alternative composition sequences, casing, etc.\n\tNSUInteger firstUnusedIndex = 0, firstUnmatchedIndex = 0;\n\t\n\tdo\n\t{\n\t\tNSRange baseRangeToMatch = [base rangeOfComposedCharacterSequenceAtIndex:firstUnmatchedIndex];\n\t\tNSString *stringToMatch = [base substringWithRange:baseRangeToMatch];\n\t\tNSString *uppercaseStringToMatch = [stringToMatch uppercaseString];\n\t\tNSRange selfMatchRange;\n\t\t\n\t\tif ([stringToMatch isEqualToString:uppercaseStringToMatch] && (firstUnmatchedIndex != 0))\n\t\t{\n\t\t\t// If the character in base is uppercase, we only want to match an uppercase character in self.\n\t\t\t// The exception is the first character of base; WTF should match writeTempFile() well.\n\t\t\tselfMatchRange = [self rangeOfString:stringToMatch\n\t\t\t\t\t\t\t\t\t\t options:(NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch)\n\t\t\t\t\t\t\t\t\t\t   range:NSMakeRange(firstUnusedIndex, selfLength - firstUnusedIndex)];\n\t\t\tscore += 1000;\t// uppercase match\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the character in base is not uppercase, we will match any case in self, but we prefer a\n\t\t\t// lowercase character if it matches the very next part of self, otherwise we prefer uppercase.\n\t\t\tselfMatchRange = [self rangeOfString:stringToMatch\n\t\t\t\t\t\t\t\t\t\t options:(NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch)\n\t\t\t\t\t\t\t\t\t\t   range:NSMakeRange(firstUnusedIndex, selfLength - firstUnusedIndex)];\n\t\t\t\n\t\t\tif (selfMatchRange.location == firstUnusedIndex)\n\t\t\t{\n\t\t\t\tscore += 2000;\t// next-character match is even better than upper-case; continuity trumps camelcase\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tNSRange uppercaseMatchRange = [self rangeOfString:uppercaseStringToMatch\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  options:(NSDiacriticInsensitiveSearch | NSWidthInsensitiveSearch)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trange:NSMakeRange(firstUnusedIndex, selfLength - firstUnusedIndex)];\n\t\t\t\t\n\t\t\t\tif (uppercaseMatchRange.location != NSNotFound)\n\t\t\t\t{\n\t\t\t\t\tselfMatchRange = uppercaseMatchRange;\n\t\t\t\t\tscore += 1000;\t// uppercase match\n\t\t\t\t}\n\t\t\t\telse if (firstUnusedIndex > 0)\n\t\t\t\t{\n\t\t\t\t\t// This match is crap; we're jumping forward to a lowercase letter, so it's unlikely to be what\n\t\t\t\t\t// the user wants.  So we bail.  This can be commented out to return lower-quality matches.\n\t\t\t\t\treturn INT64_MIN;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// no match in self for the composed character sequence in base; self is not a good completion of base\n\t\tif (selfMatchRange.location == NSNotFound)\n\t\t\treturn INT64_MIN;\n\t\t\n\t\t// matching the very beginning of self is very good; we really want to match the start of a candidate\n\t\t// otherwise, earlier matches are better; a match at position 0 gets the largest score increment\n\t\tif (selfMatchRange.location == 0)\n\t\t\tscore += 100000;\n\t\telse\n\t\t\tscore -= selfMatchRange.location;\n\t\t\n\t\t// move firstUnusedIndex to follow the matched range in self\n\t\tfirstUnusedIndex = selfMatchRange.location + selfMatchRange.length;\n\t\t\n\t\t// move to the next composed character sequence in base\n\t\tfirstUnmatchedIndex = baseRangeToMatch.location + baseRangeToMatch.length;\n\t\tif (firstUnmatchedIndex >= baseLength)\n\t\t\tbreak;\n\t}\n\twhile (YES);\n\t\n\t// We want argument-name matches to be at the top, always, when they are available, so bump their score\n\tif ([self hasSuffix:@\"=\"])\n\t\tscore += 1000000;\n\t\n\treturn score;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleTextView.h",
    "content": "//\n//  EidosConsoleTextView.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 4/8/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#import \"EidosTextView.h\"\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n@protocol EidosConsoleTextViewDelegate;\n\n\n/*\n \n EidosConsoleTextView provides a standard Eidos console textview.  It is integrated into EidosConsoleWindowController,\n so if you use that class you get a console textview for free, and do not have to use this class directly.  If you\n build your own Eidos UI, you might wish to use this class to provide a console.\n \n */\n\n\n@interface EidosConsoleTextView : EidosTextView\n{\n@public\n\tNSRange lastPromptRange;\n\t\n\tNSMutableArray *history;\n\tNSUInteger historyIndex;\n\tBOOL lastHistoryItemIsProvisional;\t// got added to the history by a moveUp: event but is not an executed command\n}\n\n// A delegate for Eidos functionality; this is the same object as the NSText/NSTextView delegate, and is not declared explicitly\n// here because overriding properties with a different type doesn't really work.  So when you call setDelegate: on EidosTextView,\n// you will not get the proper type-checking, and you will get a runtime error if your delegate object does not in fact conform\n// to the EidosTextViewDelegate protocol.  But if you declare your conformance to the protocol, you should be fine.  This is a\n// little weird, but the only good alternative is to have a separate delegate object for Eidos, which would just be annoying and\n// confusing.\n//\n//@property (nonatomic, assign) id<EidosConsoleTextViewDelegate> delegate;\n\n// Initializers are inherited from NSTextView\n//- (instancetype)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container NS_DESIGNATED_INITIALIZER;\n//- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;\n\n// The character position following the current Eidos prompt; user input starts at this character position\n- (NSUInteger)promptRangeEnd;\n- (void)setPromptRangeEnd:(NSUInteger)promptEnd;\n\n// Can be called to show the standard Eidos welcome message in the console\n- (void)showWelcomeMessage;\n\n// Adds a new Eidos prompt to the console, on the assumption that output is finished and the console is ready for input\n- (void)showPrompt;\n- (void)showPrompt:(unichar)promptChar;\n\n// Adds a thin spacer line to the console's output text; this provides nicer formatting for output\n- (void)appendSpacer;\n\n// Clears output in the console\n- (void)clearOutputToPosition:(NSUInteger)clearPosition;\n\n// This adds a command to the console window's history; it should be called to register all commands executed\n// in the console, including commands sent to the delegate to execute by -eidosConsoleTextViewExecuteInput:,\n// since the console does not assume that that call results in successful execution.\n- (void)registerNewHistoryItem:(NSString *)newItem;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleTextView.mm",
    "content": "//\n//  EidosConsoleTextView.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 4/8/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosConsoleTextView.h\"\n#import \"EidosConsoleTextViewDelegate.h\"\n#import \"EidosCocoaExtra.h\"\n#include \"eidos_globals.h\"\n\n\n@implementation EidosConsoleTextView\n\n- (void)dealloc\n{\n\t[history release];\n\thistory = nil;\n\t\n\t[super dealloc];\n}\n\n// The method signature is inherited from NSTextView, but we want to check that the delegate follows our delegate protocol\n- (void)setDelegate:(id<NSTextViewDelegate>)delegate\n{\n\tif (delegate && ![delegate conformsToProtocol:@protocol(EidosConsoleTextViewDelegate)])\n\t\tNSLog(@\"Delegate %@ assigned to EidosConsoleTextView %p does not conform to the EidosConsoleTextViewDelegate protocol!\", delegate, self);\n\t\n\t[super setDelegate:delegate];\n}\n\n- (void)insertNewline:(id)sender\n{\n\tid delegate = [self delegate];\n\t\n\tif ([delegate respondsToSelector:@selector(eidosConsoleTextViewExecuteInput:)])\n\t\t[delegate eidosConsoleTextViewExecuteInput:self];\n}\n\n// This is option-return or option-enter; we deliberately let it go, to let people put newlines into their input\n//- (void)insertNewlineIgnoringFieldEditor:(id)sender\n//{\n//}\n\n- (NSString *)currentCommandAtPrompt\n{\n\tNSString *outputString = [self string];\n\tNSString *commandString = [outputString substringFromIndex:[self promptRangeEnd]];\n\t\n\treturn commandString;\n}\n\n- (void)setCommandAtPrompt:(NSString *)newCommand\n{\n\tNSTextStorage *ts = [self textStorage];\n\tNSUInteger promptEnd = [self promptRangeEnd];\n\tNSDictionary *inputAttrs = [NSDictionary eidosInputAttrsWithSize:[self displayFontSize]];\n\tNSAttributedString *newAttrCommand = [[NSAttributedString alloc] initWithString:newCommand attributes:inputAttrs];\n\t\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:NSMakeRange(promptEnd, [ts length] - promptEnd) withAttributedString:newAttrCommand];\n\t[ts endEditing];\n\t\n\t[newAttrCommand release];\n\t\n\t[self setSelectedRange:NSMakeRange([[self string] length], 0)];\n\t[self setTypingAttributes:inputAttrs];\n\t[self scrollRangeToVisible:NSMakeRange([[self string] length], 0)];\n}\n\n- (void)moveUp:(id)sender\n{\n\tif (history && (historyIndex > 0))\n\t{\n\t\t// If the user has typed at the current prompt and it is unsaved, save it in the history before going up\n\t\tif (historyIndex == [history count])\n\t\t{\n\t\t\tNSString *commandString = [self currentCommandAtPrompt];\n\t\t\t\n\t\t\tif ([commandString length] > 0)\n\t\t\t{\n\t\t\t\t// If there is a provisional item on the top of the stack, get rid of it and replace it\n\t\t\t\tif (lastHistoryItemIsProvisional)\n\t\t\t\t{\n\t\t\t\t\t[history removeLastObject];\n\t\t\t\t\tlastHistoryItemIsProvisional = NO;\n\t\t\t\t\t--historyIndex;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t[history addObject:commandString];\n\t\t\t\tlastHistoryItemIsProvisional = YES;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if the only item on the stack was provisional, and we just replaced it, we may have nowhere up to go\n\t\tif (historyIndex > 0)\n\t\t{\n\t\t\t--historyIndex;\n\t\t\n\t\t\t[self setCommandAtPrompt:[history objectAtIndex:historyIndex]];\n\t\t}\n\t\t\n\t\t//NSLog(@\"moveUp: end:\\nhistory = %@\\nhistoryIndex = %d\\nlastHistoryItemIsProvisional = %@\", history, historyIndex, lastHistoryItemIsProvisional ? @\"YES\" : @\"NO\");\n\t}\n}\n\n- (void)moveDown:(id)sender\n{\n\tif (historyIndex <= [history count])\n\t{\n\t\t// If the user has typed at the current prompt and it is unsaved, save it in the history before going down\n\t\tif (historyIndex == [history count])\n\t\t{\n\t\t\tNSString *commandString = [self currentCommandAtPrompt];\n\t\t\t\n\t\t\tif ([commandString length] > 0)\n\t\t\t{\n\t\t\t\t// If there is a provisional item on the top of the stack, get rid of it and replace it\n\t\t\t\tif (lastHistoryItemIsProvisional)\n\t\t\t\t{\n\t\t\t\t\t[history removeLastObject];\n\t\t\t\t\tlastHistoryItemIsProvisional = NO;\n\t\t\t\t\t--historyIndex;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!history)\n\t\t\t\t\thistory = [[NSMutableArray alloc] init];\n\t\t\t\t\n\t\t\t\t[history addObject:commandString];\n\t\t\t\tlastHistoryItemIsProvisional = YES;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn;\n\t\t}\n\t\t\n\t\t++historyIndex;\n\t\t\n\t\tif (historyIndex == [history count])\n\t\t\t[self setCommandAtPrompt:@\"\"];\n\t\telse\n\t\t\t[self setCommandAtPrompt:[history objectAtIndex:historyIndex]];\n\t\t\n\t\t//NSLog(@\"moveDown: end:\\nhistory = %@\\nhistoryIndex = %d\\nlastHistoryItemIsProvisional = %@\", history, historyIndex, lastHistoryItemIsProvisional ? @\"YES\" : @\"NO\");\n\t}\n}\n\n- (void)registerNewHistoryItem:(NSString *)newItem\n{\n\tif (!history)\n\t\thistory = [[NSMutableArray alloc] init];\n\t\n\t// If there is a provisional item on the top of the stack, get rid of it and replace it\n\tif (lastHistoryItemIsProvisional)\n\t{\n\t\t[history removeLastObject];\n\t\tlastHistoryItemIsProvisional = NO;\n\t}\n\t\n\t[history addObject:newItem];\n\thistoryIndex = (int)[history count];\t// a new prompt, one beyond the last history item\n\t\n\t//NSLog(@\"registerNewHistoryItem: end:\\nhistory = %@\\nhistoryIndex = %d\\nlastHistoryItemIsProvisional = %@\", history, historyIndex, lastHistoryItemIsProvisional ? @\"YES\" : @\"NO\");\n}\n\n- (NSUInteger)promptRangeEnd\n{\n\treturn lastPromptRange.location + lastPromptRange.length;\n}\n\n- (void)setPromptRangeEnd:(NSUInteger)promptEnd\n{\n\tlastPromptRange.location = promptEnd - lastPromptRange.length;\n}\n\n- (NSUInteger)rangeOffsetForCompletionRange\n{\n\treturn [self promptRangeEnd];\n}\n\n- (void)showWelcomeMessage\n{\n\tNSTextStorage *ts = [self textStorage];\n\tNSDictionary *outputAttrs = [NSDictionary eidosOutputAttrsWithSize:[self displayFontSize]];\n\t\n\tNSString *versionString = [NSString stringWithFormat:@\"Eidos version %s\\n\\nBy Benjamin C. Haller (\", EIDOS_VERSION_STRING];\n\tNSAttributedString *welcomeString1 = [[NSAttributedString alloc] initWithString:versionString attributes:outputAttrs];\t\t// EIDOS VERSION\n\tNSAttributedString *welcomeString2 = [[NSAttributedString alloc] initWithString:@\"http://benhaller.com/\" attributes:[NSDictionary eidosBaseAttributes:outputAttrs withHyperlink:@\"http://benhaller.com/\"]];\n\tNSAttributedString *welcomeString3 = [[NSAttributedString alloc] initWithString:@\").\\nCopyright (c) 2016–2026 Benjamin C. Haller.\\nAll rights reserved.\\n\\nEidos is free software with ABSOLUTELY NO WARRANTY.\\nType license() for license and distribution details.\\n\\nGo to \" attributes:outputAttrs];\n\tNSAttributedString *welcomeString4 = [[NSAttributedString alloc] initWithString:@\"https://github.com/MesserLab/SLiM\" attributes:[NSDictionary eidosBaseAttributes:outputAttrs withHyperlink:@\"https://github.com/MesserLab/SLiM\"]];\n\tNSAttributedString *welcomeString5 = [[NSAttributedString alloc] initWithString:@\" for source\\ncode, documentation, examples, and other information.\\n\\nWelcome to Eidos!\\n\\n-----------------------------------------------------\\n\\n\" attributes:outputAttrs];\n\t\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:welcomeString1];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:welcomeString2];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:welcomeString3];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:welcomeString4];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:welcomeString5];\n\t[ts endEditing];\n\t\n\t[welcomeString1 release];\n\t[welcomeString2 release];\n\t[welcomeString3 release];\n\t[welcomeString4 release];\n\t[welcomeString5 release];\n}\n\n- (void)showPrompt:(unichar)promptChar\n{\n\tNSTextStorage *ts = [self textStorage];\n\tNSDictionary *promptAttrs = [NSDictionary eidosPromptAttrsWithSize:[self displayFontSize]];\n\tNSDictionary *inputAttrs = [NSDictionary eidosInputAttrsWithSize:[self displayFontSize]];\n\t\n\t// The prompt uses the inputAttrs for the second (space) character, to make sure typing attributes are always correct\n\tNSString *prompt = [NSString stringWithCharacters:&promptChar length:1];\n\tNSAttributedString *promptString1 = [[NSAttributedString alloc] initWithString:prompt attributes:promptAttrs];\n\tNSAttributedString *promptString2 = [[NSAttributedString alloc] initWithString:@\" \" attributes:inputAttrs];\n\t\n\t// We remember the prompt range for various purposes such as uneditability of old content\n\tlastPromptRange = NSMakeRange([[self string] length], 2);\n\t\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:NSMakeRange(lastPromptRange.location, 0) withAttributedString:promptString1];\n\t[ts replaceCharactersInRange:NSMakeRange(lastPromptRange.location + 1, 0) withAttributedString:promptString2];\n\t[ts endEditing];\n\t\n\t[promptString1 release];\n\t[promptString2 release];\n\t\n\t[self setSelectedRange:NSMakeRange(lastPromptRange.location + 2, 0)];\n\t[self setTypingAttributes:inputAttrs];\n\t[self scrollRangeToVisible:NSMakeRange([[self string] length], 0)];\n}\n\n- (void)showPrompt\n{\n\t[self showPrompt:'>'];\n}\n\n- (void)appendSpacer\n{\n\tstatic NSAttributedString *spacerString = nil;\n\t\n\tif (!spacerString)\n\t\tspacerString = [[NSAttributedString alloc] initWithString:@\"\\n\" attributes:@{NSForegroundColorAttributeName : [NSColor blackColor], NSFontAttributeName : [NSFont fontWithName:@\"Menlo\" size:3.0]}];\n\t\n\tNSTextStorage *ts = [self textStorage];\n\t\n\t// we only add a spacer newline if the current contents already end in a newline; we don't introduce new breaks\n\tif ([[ts string] characterAtIndex:[ts length] - 1] == '\\n')\n\t{\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:spacerString];\n\t\t[ts endEditing];\n\t}\n}\n\n- (void)clearOutputToPosition:(NSUInteger)clearPosition\n{\n\tNSTextStorage *ts = [self textStorage];\n\tNSRange selectedRange = [self selectedRange];\n\tNSRange rangeToClear = NSMakeRange(0, clearPosition);\n\t\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:rangeToClear withString:@\"\"];\n\t[ts endEditing];\n\t\n\tlastPromptRange.location -= clearPosition;\n\t\n\tif (selectedRange.location + selectedRange.length <= rangeToClear.location + rangeToClear.length)\n\t{\n\t\t// the selection was entirely in the deleted range, so reset it to the end of the textview\n\t\tselectedRange = NSMakeRange([ts length], 0);\n\t}\n\telse if (selectedRange.location <= rangeToClear.location + rangeToClear.length)\n\t{\n\t\t// the selected range started in the deleted range but extended into the undeleted range, so preserve the remaining portion\n\t\tunsigned long deletedLength = rangeToClear.location + rangeToClear.length - selectedRange.location;\n\t\t\n\t\tselectedRange.location = 0;\n\t\tselectedRange.length -= deletedLength;\n\t}\n\telse\n\t{\n\t\t// the selected range was entirely beyond the deleted range, so preserve the whole thing\n\t\tselectedRange.location -= rangeToClear.length;\n\t}\n\t\n\t[self setSelectedRange:selectedRange];\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\tif ((sel == @selector(shiftSelectionLeft:)) || (sel == @selector(shiftSelectionRight:)) || (sel == @selector(commentUncommentSelection:)))\n\t\treturn NO;\n\t\n\treturn [super validateMenuItem:menuItem];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleTextViewDelegate.h",
    "content": "//\n//  EidosConsoleTextViewDelegate.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n@class EidosConsoleTextView;\n\n\n// A protocol that the delegate should respond to, to be notified when the user presses return/enter; this should\n// trigger execution of the current line of input (i.e., all text after -promptRangeEnd).\n@protocol EidosConsoleTextViewDelegate <EidosTextViewDelegate>\n@required\n\n- (void)eidosConsoleTextViewExecuteInput:(EidosConsoleTextView *)textView;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleWindowController.h",
    "content": "//\n//  EidosConsoleWindowController.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/13/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#import \"EidosConsoleTextView.h\"\n#import \"EidosVariableBrowserController.h\"\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n@protocol EidosConsoleWindowControllerDelegate;\n\n\n/*\n \n EidosConsoleWindowController provides a prefab Eidos console window containing a script view, a console\n view, a status bar, and various toolbar buttons.  It can be reused in Context code if you just want\n a standard Eidos console, and can be customized by supplying a delegate to it.\n \n */\n\n\n// Defaults keys used to control various aspects of the user experience\nextern NSString *EidosDefaultsShowTokensKey;\nextern NSString *EidosDefaultsShowParseKey;\nextern NSString *EidosDefaultsShowExecutionKey;\nextern NSString *EidosDefaultsSuppressScriptCheckSuccessPanelKey;\n\n\n@interface EidosConsoleWindowController : NSObject\n{\n\t// ivars for handling input continuation\n\tBOOL isContinuationPrompt;\n\tNSUInteger originalPromptEnd;\n}\n\n// A delegate may be provided to customize various aspects of this class; see EidosConsoleWindowControllerDelegate.h\n@property (nonatomic, assign) IBOutlet NSObject<EidosConsoleWindowControllerDelegate> *delegate;\n\n// This property controls the enable state of UI that depends on the state of Eidos or its Context.  Some of\n// the console window's UI does not; you can show/hide script help at any time, even if Eidos or its Context\n// is in an invalid state, for example.  Other UI does; you can't execute if things are in an invalid state.\n@property (nonatomic) BOOL interfaceEnabled;\n\n\n// Outlets from EidosConsoleWindow.xib; it is unlikely that client code will need to access these\n@property (nonatomic, retain) IBOutlet EidosVariableBrowserController *browserController;\n\n@property (nonatomic, retain) IBOutlet NSWindow *scriptWindow;\n@property (nonatomic, assign) IBOutlet NSSplitView *bottomSplitView;\n@property (nonatomic, assign) IBOutlet EidosTextView *scriptTextView;\n@property (nonatomic, assign) IBOutlet EidosConsoleTextView *outputTextView;\n@property (nonatomic, assign) IBOutlet NSTextField *statusTextField;\n\n@property (nonatomic, assign) IBOutlet NSButton *browserToggleButton;\n\n// Normally EidosConsoleWindowController is instantiated in the EidosConsoleWindow.xib nib\n- (instancetype)init NS_DESIGNATED_INITIALIZER;\n\n// Show the console window and make the console output first responder\n- (void)showWindow;\n- (void)hideWindow;\n\n- (void)displayStartupMessage;\n\n// Tell the controller that the console window should be disposed of, not just closed; breaks retain loops\n- (void)cleanup;\n\n// Get the console textview; this can be used to append new output in the console, for example\n- (EidosConsoleTextView *)textView;\n\n// Throw away the current symbol table\n- (void)invalidateSymbolTableAndFunctionMap;\n\n// Make a new symbol table from our delegate's current state; this actually executes a minimal script, \";\",\n// to produce the symbol table as a side effect of setting up for the script's execution\n- (void)validateSymbolTableAndFunctionMap;\n\n// Execute the given script string, with the terminating semicolon being optional if requested\n- (void)executeScriptString:(NSString *)scriptString withOptionalSemicolon:(BOOL)semicolonOptional;\n\n\n// Actions used by EidosConsoleWindow.xib; may be called directly\n\n// Check the syntax of the current script; will call eidosConsoleWindowController:checkScriptDidSucceed:\n// if implemented by the delegate\n- (IBAction)checkScript:(id)sender;\n\n// Prettyprint the current script (after checking its syntax)\n- (IBAction)prettyprintScript:(id)sender;\n\n// Shows the shared script help window\n- (IBAction)showScriptHelp:(id)sender;\n\n// Clears all output in the console textview\n- (IBAction)clearOutput:(id)sender;\n\n// Executes all script currently in the script textview\n- (IBAction)executeAll:(id)sender;\n\n// Executes the line(s) containing the selection in the script textview\n- (IBAction)executeSelection:(id)sender;\n\n// Toggles the visibility of the console window\n- (IBAction)toggleConsoleVisibility:(id)sender;\n\n// Toggles the visibility of the variables browser\n- (IBAction)toggleBrowserVisibility:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleWindowController.mm",
    "content": "//\n//  EidosConsoleWindowController.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/13/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosConsoleWindowController.h\"\n#import \"EidosConsoleWindowControllerDelegate.h\"\n#import \"EidosTextView.h\"\n#import \"EidosCocoaExtra.h\"\n#import \"EidosVariableBrowserControllerDelegate.h\"\n#import \"EidosTextViewDelegate.h\"\n#import \"EidosConsoleTextViewDelegate.h\"\n#import \"EidosHelpController.h\"\n#import \"EidosPrettyprinter.h\"\n\n#include \"eidos_script.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n\n#include <iostream>\n#include <sstream>\n#include <stdexcept>\n#include <csignal>\n\n\n// User defaults keys\nNSString *EidosDefaultsShowTokensKey = @\"EidosShowTokens\";\nNSString *EidosDefaultsShowParseKey = @\"EidosShowParse\";\nNSString *EidosDefaultsShowExecutionKey = @\"EidosShowExecution\";\nNSString *EidosDefaultsSuppressScriptCheckSuccessPanelKey = @\"EidosSuppressScriptCheckSuccessPanel\";\n\n\n@interface EidosConsoleWindowController () <EidosVariableBrowserControllerDelegate, EidosConsoleTextViewDelegate>\n{\n\t// The symbol table for the console interpreter; needs to be wiped whenever the symbol table changes\n\tEidosSymbolTable *global_symbols;\n\t\n\t// The function map for the console interpreter; carries over from invocation to invocation\n\tEidosFunctionMap *global_function_map;\n\tBOOL global_function_map_owned;\t\t\t// if our delegate gave us a map, it owns it; if we made one, we own it\n}\n@end\n\n\n@implementation EidosConsoleWindowController\n\n@synthesize delegate, browserController, scriptWindow, bottomSplitView, scriptTextView, outputTextView, statusTextField;\n\n+ (void)initialize\n{\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:@{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  EidosDefaultsShowTokensKey : @NO,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  EidosDefaultsShowParseKey : @NO,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  EidosDefaultsShowExecutionKey : @NO,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  EidosDefaultsSuppressScriptCheckSuccessPanelKey : @NO\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  }];\n}\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\t[self setInterfaceEnabled:YES];\n\t\t\n\t\t// Observe notifications to keep our variable browser toggle button up to date\n\t\t[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(browserWillShow:) name:EidosVariableBrowserWillShowNotification object:nil];\n\t\t[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(browserWillHide:) name:EidosVariableBrowserWillHideNotification object:nil];\n\t}\n\t\n\treturn self;\n}\n\n- (void)awakeFromNib\n{\n\t[self setInterfaceEnabled:YES];\n\t\n\t// Tell Cocoa that we can go full-screen\n\t[scriptWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];\n\t\n\t// Fix our splitview's position restore, which NSSplitView sometimes screws up\n\t[bottomSplitView eidosRestoreAutosavedPositionsWithName:@\"Eidos Console Splitter\"];\n\t\n\t// THEN set the autosave names on the splitviews; this prevents NSSplitView from getting confused\n\t[bottomSplitView setAutosaveName:@\"Eidos Console Splitter\"];\n\t\n\t// Show a welcome message\n\t[outputTextView showWelcomeMessage];\n\t\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerAppendWelcomeMessageAddendum:)])\n\t\t[delegate eidosConsoleWindowControllerAppendWelcomeMessageAddendum:self];\n\t\n\t// And show our prompt\n\t[outputTextView showPrompt];\n\t\n\t// Set up syntax coloring for the script view; note the console view's coloring is handled internally by us\n\t[scriptTextView setSyntaxColoring:kEidosSyntaxColoringEidos];\n\t\n\t// Execute a null statement to get our symbols set up, for code completion etc.\n\t// Note this has the side effect of creating a random number generator gEidos_RNG for our use.\n\t[self validateSymbolTableAndFunctionMap];\n}\n\n- (void)dealloc\n{\n\t//NSLog(@\"EidosConsoleWindowController dealloc\");\n\t\n\t[[NSNotificationCenter defaultCenter] removeObserver:self];\n\t\n\t[self cleanup];\n\t\n\t[self setBottomSplitView:nil];\n\t[self setScriptTextView:nil];\n\t[self setOutputTextView:nil];\n\t[self setStatusTextField:nil];\n\t[self setBrowserToggleButton:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)setDelegate:(NSObject<EidosConsoleWindowControllerDelegate> *)newDelegate\n{\n\tif (newDelegate && ![newDelegate conformsToProtocol:@protocol(EidosConsoleWindowControllerDelegate)])\n\t\tNSLog(@\"Delegate %@ assigned to EidosConsoleWindowController %p does not conform to the EidosConsoleWindowControllerDelegate protocol!\", newDelegate, self);\n\t\n\tdelegate = newDelegate;\t// nonatomic, assign\n}\n\n- (NSObject<EidosConsoleWindowControllerDelegate> *)delegate\n{\n\treturn delegate;\n}\n\n- (void)browserWillShow:(NSNotification *)note\n{\n\tif ([note object] == browserController)\n\t\t[_browserToggleButton setState:NSOnState];\n}\n\n- (void)browserWillHide:(NSNotification *)note\n{\n\tif ([note object] == browserController)\n\t\t[_browserToggleButton setState:NSOffState];\n}\n\n- (void)showWindow\n{\n\t[scriptWindow makeKeyAndOrderFront:nil];\n\t[scriptWindow makeFirstResponder:outputTextView];\n}\n\n- (void)hideWindow\n{\n\t[scriptWindow performClose:nil];\n}\n\n- (void)displayStartupMessage\n{\n\tNSDictionary *statusAttrs = [NSDictionary eidosTextAttributesWithColor:[NSColor textColor] size:11.0];\n\tNSString *statusString = [NSString stringWithFormat:@\"Eidos %s, %@ build.\", EIDOS_VERSION_STRING,\n#if DEBUG\n\t\t\t\t\t\t\t  @\"debug\"\n#else\n\t\t\t\t\t\t\t  @\"release\"\n#endif\n\t\t\t\t\t\t\t  ];\n\t\n#ifdef _OPENMP\n\tstatusString = [statusString stringByAppendingFormat:@\"  Running Eidos in parallel with %d threads maximum.\", gEidosMaxThreads];\n#endif\n\t\n\tNSMutableAttributedString *statusAttrString = [[[NSMutableAttributedString alloc] initWithString:statusString attributes:statusAttrs] autorelease];\n\t\n\t[statusAttrString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [statusAttrString length])];\n\t[statusTextField setAttributedStringValue:statusAttrString];\n}\n\n- (void)cleanup\n{\n\tdelete global_symbols;\n\tglobal_symbols = nil;\n\t\n\tif (global_function_map_owned)\n\t\tdelete global_function_map;\n\tglobal_function_map = nil;\n\t\n\t[bottomSplitView setDelegate:nil];\n\t[self setBottomSplitView:nil];\n\t\n\t[scriptWindow setDelegate:nil];\n\t[self setScriptWindow:nil];\n\t\n\t[browserController cleanup];\n\t[self setBrowserController:nil];\n\t\n\t[self setDelegate:nil];\n}\n\n- (EidosConsoleTextView *)textView;\n{\n\treturn outputTextView;\n}\n\n- (void)invalidateSymbolTableAndFunctionMap\n{\n\tif (global_symbols)\n\t{\n\t\tdelete global_symbols;\n\t\tglobal_symbols = nil;\n\t}\n\t\n\tif (global_function_map)\n\t{\n\t\tif (global_function_map_owned)\n\t\t\tdelete global_function_map;\n\t\tglobal_function_map = nil;\n\t}\n\t\n\t[browserController reloadBrowser];\n}\n\n- (void)validateSymbolTableAndFunctionMap\n{\n\tif (!global_symbols || !global_function_map)\n\t{\n\t\tNSString *errorString = nil;\n\t\t\n\t\t[self _executeScriptString:@\";\" tokenString:NULL parseString:NULL executionString:NULL errorString:&errorString withOptionalSemicolon:NO];\n\t\t\n\t\tif (errorString)\n\t\t\tNSLog(@\"Error in validateSymbolTableAndFunctionMap: %@\", errorString);\n\t}\n\t\n\t[browserController reloadBrowser];\n}\n\n- (NSString *)_executeScriptString:(NSString *)scriptString tokenString:(NSString **)tokenString parseString:(NSString **)parseString executionString:(NSString **)executionString errorString:(NSString **)errorString withOptionalSemicolon:(BOOL)semicolonOptional\n{\n\tstd::string script_string([scriptString UTF8String]);\n\tEidosScript script(script_string);\n\tstd::string output;\n\t\n\t// Unfortunately, running readFromPopulationFile() is too much of a shock for SLiMgui.  It invalidates variables that are being displayed in\n\t// the variable browser, in such an abrupt way that it causes a crash.  Basically, the code in readFromPopulationFile() that \"cleans\" all\n\t// references to mutations and such does not have any way to clean SLiMgui's references, and so those stale references cause a crash.\n\t// There is probably a better solution, but for now, we look for code containing readFromPopulationFile() and special-case it.  The user\n\t// could circumvent this and trigger a crash, so this is just a band-aid; a proper solution is needed.  Another problem with this band-aid\n\t// is that SLiMgui's display does not refresh to show the new population state.  Indeed, that is an issue with anything that changes the\n\t// visible state, such as adding new mutations.  There needs to be some way for Eidos code to tell SLiMgui that UI refreshing is needed,\n\t// and to clean references to variables that are about to invalidated.  FIXME\n\tBOOL safeguardReferences = NO;\n\t\n\tif (scriptString && ([scriptString rangeOfString:@\"readFromPopulationFile\"].location != NSNotFound))\t// BCH 4/7/2016: containsString: added in 10.10\n\t\tsafeguardReferences = YES;\n\t\n\tif (safeguardReferences)\n\t\t[self invalidateSymbolTableAndFunctionMap];\n\t\n\t// Make the final semicolon optional if requested; this allows input like \"6+7\" in the console\n\tif (semicolonOptional)\n\t\tscript.SetFinalSemicolonOptional(true);\n\t\n\t// Tokenize\n\ttry\n\t{\n\t\tscript.Tokenize();\n\t\t\n\t\tif (tokenString)\n\t\t{\n\t\t\tstd::ostringstream token_stream;\n\t\t\t\n\t\t\tscript.PrintTokens(token_stream);\n\t\t\t\n\t\t\tstd::string &&token_string = token_stream.str();\n\t\t\t*tokenString = [NSString stringWithUTF8String:token_string.c_str()];\n\t\t\t\n#if 0\n\t\t\t// Do a checkback on UTF8 token ranges versus UTF16 token ranges by replicating the token string using the UTF16 ranges\n\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\tNSMutableString *replicateTokenString = [NSMutableString string];\n\t\t\tBOOL firstToken = YES;\n\t\t\t\n\t\t\tfor (const EidosToken &token : tokens)\n\t\t\t{\n\t\t\t\tint32_t token_UTF16_start = token.token_UTF16_start_;\n\t\t\t\tint32_t token_UTF16_end = token.token_UTF16_end_;\n\t\t\t\tNSRange tokenRange = NSMakeRange(token_UTF16_start, token_UTF16_end - token_UTF16_start + 1);\n\t\t\t\t\n\t\t\t\tif (!firstToken)\n\t\t\t\t\t[replicateTokenString appendString:@\" \"];\n\t\t\t\t\n\t\t\t\tif (tokenRange.location == [scriptString length])\n\t\t\t\t\t[replicateTokenString appendString:@\"<EOF>\"];\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[replicateTokenString appendString:@\"<\"];\n\t\t\t\t\t[replicateTokenString appendString:[scriptString substringWithRange:tokenRange]];\n\t\t\t\t\t[replicateTokenString appendString:@\">\"];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfirstToken = NO;\n\t\t\t}\n\t\t\t\n\t\t\t[replicateTokenString appendString:@\"\\n\"];\n\t\t\t*tokenString = [*tokenString stringByAppendingString:replicateTokenString];\n#endif\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tstd::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n\t\t*errorString = [NSString stringWithUTF8String:error_string.c_str()];\n\t\t\n\t\t// move the error outside of the currentScript context if possible; the ranges\n\t\t// should have already been moved by TranslateErrorContextToUserScript()\n\t\tif (gEidosErrorContext.currentScript == &script)\n\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in tokenization.\" << std::endl;\n#endif\n\t\t\tgEidosErrorContext.currentScript = nullptr;\n\t\t}\n\t\telse if (gEidosErrorContext.currentScript)\n\t\t{\n\t\t\t// The error got translated to a script we don't recognize; clear the error info,\n\t\t\t// all we can do is show the error string to the user, with no position\n\t\t\t*errorString = [@\"A tokenization error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\" stringByAppendingString:*errorString];\n\t\t\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in tokenization traced to a different script; clearing all error info.\" << std::endl;\n#endif\n\t\t\tClearErrorContext();\n\t\t}\n\t\t\n\t\treturn nil;\n\t}\n\t\n\t// Parse, an \"interpreter block\" bounded by an EOF rather than a \"script block\" that requires braces\n\ttry\n\t{\n\t\tscript.ParseInterpreterBlockToAST(true);\n\t\t\n\t\tif (parseString)\n\t\t{\n\t\t\tstd::ostringstream parse_stream;\n\t\t\t\n\t\t\tscript.PrintAST(parse_stream);\n\t\t\t\n\t\t\tstd::string &&parse_string = parse_stream.str();\n\t\t\t*parseString = [NSString stringWithUTF8String:parse_string.c_str()];\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tstd::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n\t\t*errorString = [NSString stringWithUTF8String:error_string.c_str()];\n\t\t\n\t\t// move the error outside of the currentScript context if possible; the ranges\n\t\t// should have already been moved by TranslateErrorContextToUserScript()\n\t\tif (gEidosErrorContext.currentScript == &script)\n\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in parsing.\" << std::endl;\n#endif\n\t\t\tgEidosErrorContext.currentScript = nullptr;\n\t\t}\n\t\telse if (gEidosErrorContext.currentScript)\n\t\t{\n\t\t\t// The error got translated to a script we don't recognize; clear the error info,\n\t\t\t// all we can do is show the error string to the user, with no position\n\t\t\t*errorString = [@\"A parsing error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\" stringByAppendingString:*errorString];\n\t\t\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in parsing traced to a different script; clearing all error info.\" << std::endl;\n#endif\n\t\t\tClearErrorContext();\n\t\t}\n\t\t\n\t\treturn nil;\n\t}\n\t\n\t// Get a symbol table and let our delegate add symbols to it\n\tif (!global_symbols)\n\t{\n\t\tglobal_symbols = gEidosConstantsSymbolTable;\n\t\t\n\t\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowController:symbolsFromBaseSymbols:)])\n\t\t\tglobal_symbols = [delegate eidosConsoleWindowController:self symbolsFromBaseSymbols:global_symbols];\n\t\t\n\t\t// With the advant of global versus local symbol tables, the semantics here have gotten a little tricky.  In EidosScribe\n\t\t// we want the console to work in the global variables table directly, which we need to create; that will be our symbol\n\t\t// table.  In SLiM, we want the console to work in a local variables table; SLiM has its own global variables table,\n\t\t// which we don't want to clutter up, just as if were were in a callback.  So here, we now check whether a global variables\n\t\t// table is already in the chain, and if so, we create a local variables table; otherwise we create a global variables table.\n\t\tbool global_variables_table_exists = false;\n\t\tEidosSymbolTable *scan_table = global_symbols;\n\t\t\n\t\twhile (scan_table)\n\t\t{\n\t\t\tif (scan_table->TableType() == EidosSymbolTableType::kGlobalVariablesTable)\n\t\t\t{\n\t\t\t\tglobal_variables_table_exists = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tscan_table = scan_table->ChainSymbolTable();\n\t\t}\n\t\t\n\t\tEidosSymbolTableType console_table_type = global_variables_table_exists ? EidosSymbolTableType::kLocalVariablesTable : EidosSymbolTableType::kGlobalVariablesTable;\n\t\t\n\t\tglobal_symbols = new EidosSymbolTable(console_table_type, global_symbols);\t// add a table for script-defined variables on top\n\t}\n\t\n\t// Get a function map from our delegate, or make one ourselves\n\tif (!global_function_map)\n\t{\n\t\tglobal_function_map_owned = NO;\n\t\t\n\t\tif ([delegate respondsToSelector:@selector(functionMapForEidosConsoleWindowController:)])\n\t\t\tglobal_function_map = [delegate functionMapForEidosConsoleWindowController:self];\n\t\t\n\t\tif (!global_function_map)\n\t\t{\n\t\t\tglobal_function_map = new EidosFunctionMap(*EidosInterpreter::BuiltInFunctionMap());\n\t\t\tglobal_function_map_owned = YES;\n\t\t}\n\t}\n\t\n\t// Get the EidosContext, if any, from the delegate\n\tEidosContext *eidos_context = nullptr;\n\t\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerEidosContext:)])\n\t\teidos_context = [delegate eidosConsoleWindowControllerEidosContext:self];\n\t\n\t// Interpret the parsed block\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerWillExecuteScript:)])\n\t\t[delegate eidosConsoleWindowControllerWillExecuteScript:self];\n\t\n\tstd::ostringstream outstream;\t// in SLiMguiLegacy, one output stream for both types of output\n\tEidosInterpreter interpreter(script, *global_symbols, *global_function_map, eidos_context, outstream, outstream\n#ifdef SLIMGUI\n\t\t\t, true\n#endif\n\t\t\t);\n\t\n\ttry\n\t{\n\t\tif (executionString)\n\t\t\tinterpreter.SetShouldLogExecution(true);\n\t\t\n\t\tEidosValue_SP result = interpreter.EvaluateInterpreterBlock(true, true);\t// print output, return the last statement value (result not used)\n\t\toutput = outstream.str();\n\t\t\n\t\t// reload outline view to show new global symbols, in case they have changed\n\t\t[browserController reloadBrowser];\n\t\t\n\t\tif (executionString)\n\t\t{\n\t\t\tstd::string &&execution_string = interpreter.ExecutionLog();\n\t\t\t*executionString = [NSString stringWithUTF8String:execution_string.c_str()];\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerDidExecuteScript:)])\n\t\t\t[delegate eidosConsoleWindowControllerDidExecuteScript:self];\n\t\t\n\t\toutput = outstream.str();\n\t\t\n\t\tstd::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n\t\t*errorString = [NSString stringWithUTF8String:error_string.c_str()];\n\t\t\n\t\t// move the error outside of the currentScript context if possible; the ranges\n\t\t// should have already been moved by TranslateErrorContextToUserScript()\n\t\tif (gEidosErrorContext.currentScript == &script)\n\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in execution.\" << std::endl;\n#endif\n\t\t\tgEidosErrorContext.currentScript = nullptr;\n\t\t}\n\t\telse if (gEidosErrorContext.currentScript)\n\t\t{\n\t\t\t// The error got translated to a script we don't recognize; clear the error info,\n\t\t\t// all we can do is show the error string to the user, with no position\n\t\t\t*errorString = [@\"An execution error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\" stringByAppendingString:*errorString];\n\t\t\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in execution traced to a different script; clearing all error info.\" << std::endl;\n#endif\n\t\t\tClearErrorContext();\n\t\t}\n\t\t\n\t\treturn [NSString stringWithUTF8String:output.c_str()];\n\t}\n\t\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerDidExecuteScript:)])\n\t\t[delegate eidosConsoleWindowControllerDidExecuteScript:self];\n\t\n\t// See comment on safeguardReferences above\n\tif (safeguardReferences)\n\t\t[self validateSymbolTableAndFunctionMap];\n\t\n\t// Flush buffered output to files after every script execution, so the user sees the results\n\t// NOTE THAT THE WORKING DIRECTORY HAS BEEN CHANGED BACK AT THIS POINT!\n\tif (!Eidos_FlushFiles())\n\t\traise(SIGTRAP);\t\t\t// could be improved, but for SLiMguiLegacy this is OK\n\t\n\treturn [NSString stringWithUTF8String:output.c_str()];\n}\n\n- (void)executeScriptString:(NSString *)scriptString withOptionalSemicolon:(BOOL)semicolonOptional\n{\n\tNSTextStorage *ts = [outputTextView textStorage];\n\tdouble fontSize = [outputTextView displayFontSize];\n\tNSString *tokenString = nil, *parseString = nil, *executionString = nil, *errorString = nil;\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\tBOOL showTokens = [defaults boolForKey:EidosDefaultsShowTokensKey];\n\tBOOL showParse = [defaults boolForKey:EidosDefaultsShowParseKey];\n\tBOOL showExecution = [defaults boolForKey:EidosDefaultsShowExecutionKey];\n\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\tNSRange scriptRange = NSMakeRange(promptEnd, [scriptString length]);\n\t\n\tNSString *result = [self _executeScriptString:scriptString\n\t\t\t\t\t\t\t\t\t  tokenString:(showTokens ? &tokenString : NULL)\n\t\t\t\t\t\t\t\t\t  parseString:(showParse ? &parseString : NULL)\n\t\t\t\t\t\t\t\t  executionString:(showExecution ? &executionString : NULL)\n\t\t\t\t\t\t\t\t\t  errorString:&errorString\n\t\t\t\t\t\t\twithOptionalSemicolon:semicolonOptional];\n\t\n\tif (errorString && ([errorString rangeOfString:@\"unexpected token 'EOF'\"].location != NSNotFound))\t// BCH 4/7/2016: containsString: added in 10.10\n\t{\n\t\t// The user has entered an incomplete script line, so we need to append a newline...\n\t\tNSAttributedString *outputString1 = [[NSAttributedString alloc] initWithString:@\"\\n\" attributes:[NSDictionary eidosInputAttrsWithSize:fontSize]];\n\t\t\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:outputString1];\n\t\t[ts endEditing];\n\t\t\n\t\t[outputString1 release];\n\t\t\n\t\t// ...and issue a continuation prompt to await further input\n\t\t[outputTextView showPrompt:'+'];\n\t\toriginalPromptEnd = promptEnd;\n\t\tisContinuationPrompt = YES;\n\t}\n\telse\n\t{\n\t\t// make the attributed strings we will append\n\t\tNSAttributedString *outputString1 = [[NSAttributedString alloc] initWithString:@\"\\n\" attributes:[NSDictionary eidosInputAttrsWithSize:fontSize]];\n\t\tNSAttributedString *outputString2 = (result ? [[NSAttributedString alloc] initWithString:result attributes:[NSDictionary eidosOutputAttrsWithSize:fontSize]] : nil);\n\t\tNSAttributedString *errorAttrString = (errorString ? [[NSAttributedString alloc] initWithString:errorString attributes:[NSDictionary eidosErrorAttrsWithSize:fontSize]] : nil);\n\t\tNSAttributedString *tokenAttrString = (tokenString ? [[NSAttributedString alloc] initWithString:tokenString attributes:[NSDictionary eidosTokensAttrsWithSize:fontSize]] : nil);\n\t\tNSAttributedString *parseAttrString = (parseString ? [[NSAttributedString alloc] initWithString:parseString attributes:[NSDictionary eidosParseAttrsWithSize:fontSize]] : nil);\n\t\tNSAttributedString *executionAttrString = (executionString ? [[NSAttributedString alloc] initWithString:executionString attributes:[NSDictionary eidosExecutionAttrsWithSize:fontSize]] : nil);;\n\t\t\n\t\t// do the editing\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:outputString1];\n\t\t[outputTextView appendSpacer];\n\t\t\n\t\tif (tokenAttrString)\n\t\t{\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:tokenAttrString];\n\t\t\t[outputTextView appendSpacer];\n\t\t}\n\t\tif (parseAttrString)\n\t\t{\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:parseAttrString];\n\t\t\t[outputTextView appendSpacer];\n\t\t}\n\t\tif (executionAttrString)\n\t\t{\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:executionAttrString];\n\t\t\t[outputTextView appendSpacer];\n\t\t}\n\t\tif ([outputString2 length])\n\t\t{\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:outputString2];\n\t\t\t[outputTextView appendSpacer];\n\t\t}\n\t\tif (errorAttrString)\n\t\t{\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:errorAttrString];\n\t\t\t[outputTextView appendSpacer];\n\t\t}\n\t\t\n\t\t// If we have an error, it is in the user script, and it has a valid position, then we can try to\n\t\t// highlight it in the input.  Note that gEidosErrorContext.currentScript is nullptr in the console.\n\t\tif (errorString)\n\t\t{\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == 0))\n\t\t\t{\n\t\t\t\tif ((gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 >= 0) &&\n\t\t\t\t\t(gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 >= gEidosErrorContext.errorPosition.characterStartOfErrorUTF16) &&\n\t\t\t\t\t(scriptRange.location != NSNotFound))\n\t\t\t\t{\n\t\t\t\t\tint errorTokenStart = gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 + (int)scriptRange.location;\n\t\t\t\t\tint errorTokenEnd = gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 + (int)scriptRange.location;\n\t\t\t\t\t\n\t\t\t\t\tNSRange charRange = NSMakeRange(errorTokenStart, errorTokenEnd - errorTokenStart + 1);\n\t\t\t\t\t\n\t\t\t\t\t[ts addAttribute:NSBackgroundColorAttributeName value:[NSColor redColor] range:charRange];\n\t\t\t\t\t[ts addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor] range:charRange];\n\t\t\t\t}\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstd::cout << \"-[EidosConsoleWindowController executeScriptString:...]: an error occurred, but the error range is unusable\" << std::endl;\n\t\t\t\t}\n#endif\n\t\t\t}\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::cout << \"-[EidosConsoleWindowController executeScriptString:...]: an error occurred, but the script context is unusable\" << std::endl;\n\t\t\t}\n#endif\n\t\t}\n\t\t\n\t\t[ts endEditing];\n\t\t\n\t\t// clean up\n\t\t[outputString1 release];\n\t\t[tokenAttrString release];\n\t\t[parseAttrString release];\n\t\t[executionAttrString release];\n\t\t[outputString2 release];\n\t\t[errorAttrString release];\n\t\t\n\t\t// and show a new prompt\n\t\t[outputTextView showPrompt];\n\t}\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\tBOOL uiEnabled = [self interfaceEnabled];\n\t\n\tif (sel == @selector(checkScript:))\n\t\treturn uiEnabled;\n\tif (sel == @selector(prettyprintScript:))\n\t\treturn uiEnabled;\n\tif (sel == @selector(executeAll:))\n\t\treturn uiEnabled;\n\tif (sel == @selector(executeSelection:))\n\t\treturn uiEnabled;\n\tif (sel == @selector(toggleConsoleVisibility:))\n\t\t[menuItem setTitle:([scriptWindow isVisible] ? @\"Hide Eidos Console\" : @\"Show Eidos Console\")];\n\tif (sel == @selector(toggleBrowserVisibility:))\n\t\treturn [browserController validateMenuItem:menuItem];\n\t\n\treturn YES;\n}\n\n\n//\n//\tActions\n//\n#pragma mark -\n#pragma mark Actions\n\n- (BOOL)checkScriptSuppressSuccessResponse:(BOOL)suppressSuccessResponse\n{\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\tNSString *scriptString = [scriptTextView string];\n\tconst char *cstr = [scriptString UTF8String];\n\tNSString *errorDiagnostic = nil;\n\t\n\tif (!cstr)\n\t{\n\t\terrorDiagnostic = [@\"The script string could not be read, possibly due to an encoding problem.\" retain];\n\t}\n\telse\n\t{\n\t\tEidosScript script(cstr);\n\t\t\n\t\ttry {\n\t\t\tscript.Tokenize();\n\t\t\tscript.ParseInterpreterBlockToAST(true);\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tstd::string &&error_diagnostic = Eidos_GetTrimmedRaiseMessage();\n\t\t\terrorDiagnostic = [[NSString stringWithUTF8String:error_diagnostic.c_str()] retain];\n\t\t\t\n\t\t\t// move the error outside of the currentScript context if possible; the ranges\n\t\t\t// should have already been moved by TranslateErrorContextToUserScript()\n\t\t\tif (gEidosErrorContext.currentScript == &script)\n\t\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\t\tstd::cout << \"-[EidosConsoleWindowController checkScriptSuppressSuccessResponse:]: clearing gEidosErrorContext.currentScript after error in script check.\" << std::endl;\n#endif\n\t\t\t\tgEidosErrorContext.currentScript = nullptr;\n\t\t\t}\n\t\t\telse if (gEidosErrorContext.currentScript)\n\t\t\t{\n\t\t\t\t// The error got translated to a script we don't recognize; clear the error info,\n\t\t\t\t// all we can do is show the error string to the user, with no position\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\t\tstd::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in script check traced to a different script; clearing all error info.\" << std::endl;\n#endif\n\t\t\t\tClearErrorContext();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tBOOL checkDidSucceed = !errorDiagnostic;\n\t\n\tif (!checkDidSucceed || !suppressSuccessResponse)\n\t{\n\t\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowController:checkScriptDidSucceed:)])\n\t\t\t[delegate eidosConsoleWindowController:self checkScriptDidSucceed:checkDidSucceed];\n\t\telse\n\t\t\t[[NSSound soundNamed:(checkDidSucceed ? @\"Bottle\" : @\"Ping\")] play];\n\t\t\n\t\tif (!checkDidSucceed)\n\t\t{\n\t\t\t// On failure, we show an alert describing the error, and highlight the relevant script line\n\t\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\t\n\t\t\t[alert setAlertStyle:NSAlertStyleWarning];\n\t\t\t[alert setMessageText:@\"Script error\"];\n\t\t\t[alert setInformativeText:errorDiagnostic];\n\t\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t\t\n\t\t\t[alert beginSheetModalForWindow:scriptWindow completionHandler:^(NSModalResponse returnCode) { [alert autorelease]; }];\n\t\t\t\n\t\t\t[scriptTextView selectErrorRange];\n\t\t\t\n\t\t\t// Show the error in the status bar also\n\t\t\tNSString *trimmedError = [errorDiagnostic stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n\t\t\tNSDictionary *errorAttrs = [NSDictionary eidosTextAttributesWithColor:[NSColor redColor] size:11.0];\n\t\t\tNSMutableAttributedString *errorAttrString = [[[NSMutableAttributedString alloc] initWithString:trimmedError attributes:errorAttrs] autorelease];\n\t\t\t\n\t\t\t[errorAttrString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [errorAttrString length])];\n\t\t\t[statusTextField setAttributedStringValue:errorAttrString];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// On success, we optionally show a success alert sheet\n\t\t\tif (![defaults boolForKey:EidosDefaultsSuppressScriptCheckSuccessPanelKey])\n\t\t\t{\n\t\t\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\t\t\n\t\t\t\t[alert setAlertStyle:NSAlertStyleInformational];\n\t\t\t\t[alert setMessageText:@\"No script errors\"];\n\t\t\t\t[alert setInformativeText:@\"No errors found.\"];\n\t\t\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t\t\t[alert setShowsSuppressionButton:YES];\n\t\t\t\t\n\t\t\t\t[alert beginSheetModalForWindow:scriptWindow completionHandler:^(NSModalResponse returnCode) {\n\t\t\t\t\tif ([[alert suppressionButton] state] == NSOnState)\n\t\t\t\t\t\t[defaults setBool:YES forKey:EidosDefaultsSuppressScriptCheckSuccessPanelKey];\n\t\t\t\t\t[alert autorelease];\n\t\t\t\t}];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t[errorDiagnostic release];\n\t\n\treturn checkDidSucceed;\n}\n\n- (IBAction)checkScript:(id)sender\n{\n\t[self checkScriptSuppressSuccessResponse:NO];\n}\n\n- (IBAction)prettyprintScript:(id)sender\n{\n\tif ([scriptTextView isEditable])\n\t{\n\t\tif ([self checkScriptSuppressSuccessResponse:YES])\n\t\t{\n\t\t\t// We know the script is syntactically correct, so we can tokenize and parse it without worries\n\t\t\tNSString *scriptString = [scriptTextView string];\n\t\t\tconst char *cstr = [scriptString UTF8String];\n\t\t\tEidosScript script(cstr);\n\t\t\t\n\t\t\tscript.Tokenize(false, true);\t// get whitespace and comment tokens\n\t\t\t\n\t\t\t// Then generate a new script string that is prettyprinted\n\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\tNSMutableString *pretty = [NSMutableString string];\n\t\t\t\n\t\t\tif ([EidosPrettyprinter prettyprintTokens:tokens fromScript:script intoString:pretty])\n\t\t\t{\n\t\t\t\tif ([scriptTextView shouldChangeTextInRange:NSMakeRange(0, [[scriptTextView string] length]) replacementString:pretty])\n\t\t\t\t{\n\t\t\t\t\t[scriptTextView setString:pretty];\n\t\t\t\t\t[scriptTextView didChangeText];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSBeep();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tNSBeep();\n\t\t}\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (IBAction)showScriptHelp:(id)sender\n{\n\t[[EidosHelpController sharedController] showWindow];\n}\n\n- (IBAction)clearOutput:(id)sender\n{\n\tif (isContinuationPrompt)\n\t{\n\t\t[outputTextView clearOutputToPosition:originalPromptEnd - 2];\n\t\toriginalPromptEnd = 2;\n\t}\n\telse\n\t{\n\t\t[outputTextView clearOutputToPosition:outputTextView->lastPromptRange.location];\n\t}\n}\n\n- (void)fixDumbSelectionBug:(id)unused\n{\n\t// See comment below in toggleConsoleVisibility:\n\t[outputTextView setSelectable:YES];\n\t[outputTextView setEditable:YES];\n\t[scriptWindow makeFirstResponder:outputTextView];\n}\n\n- (IBAction)toggleConsoleVisibility:(id)sender\n{\n\tif ([scriptWindow isVisible])\n\t\t[scriptWindow performClose:nil];\n\telse\n\t{\n\t\t[scriptWindow makeKeyAndOrderFront:nil];\n\t\t\n\t\t// I have no idea what the heck is going on here, but without this code, the console window comes up – in SLiMgui only – with\n\t\t// the insertion point blinking several lines up from the prompt, in a nonsensical position.  It looks to me like an AppKit bug;\n\t\t// I think the Kit is deciding where the insertion point is prior to some view resize or relayout operation, and the position\n\t\t// isn't getting recalculated after that resize/relayout.  I couldn't figure out why it was doing that, or why it happens only\n\t\t// in SLiMgui, and this is the cleanest workaround I could find.  Sheesh.  BCH 9 February 2016.\n\t\t[outputTextView setSelectable:NO];\n\t\t[scriptWindow makeFirstResponder:nil];\n\t\t[self performSelector:@selector(fixDumbSelectionBug:) withObject:nil afterDelay:0.0];\n\t}\n}\n\n- (IBAction)toggleBrowserVisibility:(id)sender\n{\n\t[browserController toggleBrowserVisibility:nil];\n}\n\n- (void)elideContinuationPrompt\n{\n\t// This replaces the continuation prompt, if there is one, with a space, and switches the active prompt back to the original prompt;\n\t// the net effect is as if the user entered a newline and two spaces at the original prompt, with no continuation.  Note that the\n\t// two spaces at the beginning of continuation lines is mirrored in fullInputString, below.\n\tif (isContinuationPrompt)\n\t{\n\t\tNSTextStorage *ts = [outputTextView textStorage];\n\t\tNSDictionary *inputAttrs = [NSDictionary eidosInputAttrsWithSize:[outputTextView displayFontSize]];\n\t\tNSAttributedString *promptString1 = [[NSAttributedString alloc] initWithString:@\" \" attributes:inputAttrs];\n\t\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\t\t\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange(promptEnd - 2, 1) withAttributedString:promptString1];\n\t\t[ts endEditing];\n\t\t\n\t\t[outputTextView setPromptRangeEnd:originalPromptEnd];\n\t\tisContinuationPrompt = NO;\n\t\t\n\t\t[promptString1 release];\n\t}\n}\n\n- (NSString *)fullInputString\n{\n\t[self elideContinuationPrompt];\n\t\n\tNSString *fullInputString = [outputTextView string];\n\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\t\n\treturn [fullInputString substringFromIndex:promptEnd];\n}\n\n- (IBAction)executeAll:(id)sender\n{\n\tNSTextStorage *ts = [outputTextView textStorage];\n\tNSDictionary *inputAttrs = [NSDictionary eidosInputAttrsWithSize:[outputTextView displayFontSize]];\n\tNSString *fullScriptString = [scriptTextView string];\n\tNSAttributedString *scriptAttrString = [[[NSAttributedString alloc] initWithString:fullScriptString attributes:inputAttrs] autorelease];\n\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\t\n\t// The contents of the current prompt line get replaced by the execution block\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:NSMakeRange(promptEnd, [ts length] - promptEnd) withAttributedString:scriptAttrString];\n\t[ts endEditing];\n\t\n\t// The current prompt might be a continuation prompt, so now we get the full input string from the original prompt\n\tNSString *executionString = [self fullInputString];\n\t\n\t[outputTextView registerNewHistoryItem:executionString];\n\t[self executeScriptString:executionString withOptionalSemicolon:YES];\n}\n\n- (IBAction)executeSelection:(id)sender\n{\n\tNSTextStorage *ts = [outputTextView textStorage];\n\tNSString *fullScriptString = [scriptTextView string];\n\tNSUInteger scriptLength = [fullScriptString length];\n\tNSRange selectedRange = [scriptTextView selectedRange];\n\tNSCharacterSet *newlineChars = [NSCharacterSet newlineCharacterSet];\n\tNSRange executionRange = selectedRange;\t// indices of the first and last characters to execute\n\t\n\t// If the selection is an insertion point, execute the whole line\n\tif (executionRange.length == 0)\n\t{\n\t\t// start at the start of the selection and move backwards to the beginning of the line\n\t\twhile (executionRange.location > 0)\n\t\t{\n\t\t\tunichar ch = [fullScriptString characterAtIndex:executionRange.location - 1];\n\t\t\t\n\t\t\tif ([newlineChars characterIsMember:ch])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--executionRange.location;\n\t\t\t++executionRange.length;\n\t\t}\n\t\t\n\t\t// now move the end of the selection backwards to remove any newlines from the end of the range to execute\n\t\twhile (executionRange.length > 0)\n\t\t{\n\t\t\tunichar ch = [fullScriptString characterAtIndex:executionRange.location + executionRange.length - 1];\n\t\t\t\n\t\t\tif (![newlineChars characterIsMember:ch])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--executionRange.length;\n\t\t}\n\t\t\n\t\t// now move the end of the selection forwards to the end of the line, not including the newline\n\t\twhile (executionRange.location + executionRange.length < scriptLength)\n\t\t{\n\t\t\tunichar ch = [fullScriptString characterAtIndex:executionRange.location + executionRange.length];\n\t\t\t\n\t\t\tif ([newlineChars characterIsMember:ch])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t++executionRange.length;\n\t\t}\n\t}\n\t\n\t// now execute the range we have found\n\tif (executionRange.length > 0)\n\t{\n\t\tNSString *scriptString = [fullScriptString substringWithRange:executionRange];\n\t\tNSDictionary *inputAttrs = [NSDictionary eidosInputAttrsWithSize:[outputTextView displayFontSize]];\n\t\tNSAttributedString *scriptAttrString = [[[NSAttributedString alloc] initWithString:scriptString attributes:inputAttrs] autorelease];\n\t\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\t\t\n\t\t// The contents of the current prompt line get replaced by the execution line\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange(promptEnd, [ts length] - promptEnd) withAttributedString:scriptAttrString];\n\t\t[ts endEditing];\n\t\t\n\t\t// The current prompt might be a continuation prompt, so now we get the full input string from the original prompt\n\t\tNSString *executionString = [self fullInputString];\n\t\t\n\t\t[outputTextView registerNewHistoryItem:executionString];\n\t\t[self executeScriptString:executionString withOptionalSemicolon:YES];\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n\n//\n//\tVariableBrowserControllerDelegate methods\n//\n#pragma mark -\n#pragma mark VariableBrowserControllerDelegate\n\n- (EidosSymbolTable *)symbolTableForEidosVariableBrowserController:(EidosVariableBrowserController *)browserController\n{\n\treturn global_symbols;\n}\n\n\n//\n//\tNSTextViewDelegate methods\n//\n#pragma mark -\n#pragma mark NSTextViewDelegate\n\n- (NSRange)textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldRange toCharacterRange:(NSRange)newRange\n{\n\tif (textView == outputTextView)\n\t{\n\t\t// prevent a zero-length selection (i.e. an insertion point) in the history\n\t\tif ((newRange.length == 0) && (newRange.location < [outputTextView promptRangeEnd]))\n\t\t\treturn NSMakeRange([[outputTextView string] length], 0);\n\t}\n\t\n\treturn newRange;\n}\n\n- (BOOL)textView:(NSTextView *)textView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString\n{\n\tif (textView == outputTextView)\n\t{\n\t\t// prevent the user from changing anything above the current prompt\n\t\tif (affectedCharRange.location < [outputTextView promptRangeEnd])\n\t\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n\n//\n//\tEidosConsoleTextViewDelegate methods\n//\n#pragma mark -\n#pragma mark EidosConsoleTextViewDelegate\n\n- (void)eidosConsoleTextViewExecuteInput:(EidosConsoleTextView *)textView\n{\n\tif (textView == outputTextView)\n\t{\n\t\tif (isContinuationPrompt && ([[outputTextView string] length] == [outputTextView promptRangeEnd]))\n\t\t{\n\t\t\t// If the user has hit return at an empty continuation prompt, we take that as a sign that they want to get out of it\n\t\t\tNSString *executionString = [self fullInputString];\n\t\t\t\n\t\t\t[outputTextView registerNewHistoryItem:executionString];\n\t\t\t\n\t\t\tNSTextStorage *ts = [outputTextView textStorage];\n\t\t\tNSAttributedString *outputString1 = [[NSAttributedString alloc] initWithString:@\"\\n\" attributes:[NSDictionary eidosInputAttrsWithSize:[outputTextView displayFontSize]]];\n\t\t\t\n\t\t\t[ts beginEditing];\n\t\t\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:outputString1];\n\t\t\t[ts endEditing];\n\t\t\t\n\t\t\t[outputString1 release];\n\t\t\t\n\t\t\t// show a new prompt\n\t\t\t[outputTextView showPrompt];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The current prompt might be a non-empty continuation prompt, so now we get the full input string from the original prompt\n\t\t\tNSString *executionString = [self fullInputString];\n\t\t\t\n\t\t\t[outputTextView registerNewHistoryItem:executionString];\n\t\t\t[self executeScriptString:executionString withOptionalSemicolon:YES];\n\t\t}\n\t}\n}\n\n\n//\n//\tEidosTextViewDelegate methods\n//\n#pragma mark -\n#pragma mark EidosTextViewDelegate\n\n- (EidosSymbolTable *)eidosTextView:(EidosTextView *)eidosTextView symbolsFromBaseSymbols:(EidosSymbolTable *)baseSymbols\n{\n\treturn global_symbols;\t// we keep our own symbol table, so we don't call our delegate here\n}\n\n- (EidosFunctionMap *)functionMapForEidosTextView:(EidosTextView *)eidosTextView\n{\n\t// If we have a delegate that has its own function map, use that, otherwise use ours\n\tif ([delegate respondsToSelector:@selector(functionMapForEidosConsoleWindowController:)])\n\t\treturn [delegate functionMapForEidosConsoleWindowController:self];\n\telse\n\t\treturn global_function_map;\n}\n\n- (void)eidosTextView:(EidosTextView *)eidosTextView addOptionalFunctionsToMap:(EidosFunctionMap *)functionMap\n{\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowController:addOptionalFunctionsToMap:)])\n\t\t[delegate eidosConsoleWindowController:self addOptionalFunctionsToMap:functionMap];\n}\n\n- (EidosSyntaxHighlightType)eidosTextView:(EidosTextView *)eidosTextView tokenStringIsSpecialIdentifier:(const std::string &)token_string\n{\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowController:tokenStringIsSpecialIdentifier:)])\n\t\treturn [delegate eidosConsoleWindowController:self tokenStringIsSpecialIdentifier:token_string];\n\telse\n\t\treturn EidosSyntaxHighlightType::kNoSyntaxHighlight;\n}\n\n- (NSString *)eidosTextView:(EidosTextView *)eidosTextView helpTextForClickedText:(NSString *)clickedText\n{\n\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowController:helpTextForClickedText:)])\n\t\treturn [delegate eidosConsoleWindowController:self helpTextForClickedText:clickedText];\n\telse\n\t\treturn nil;\n}\n\n- (void)textViewDidChangeSelection:(NSNotification *)notification\n{\n\tNSTextView *textView = (NSTextView *)[notification object];\n\t\n\tif (textView == outputTextView)\n\t{\n\t\tNSUInteger promptEnd = [outputTextView promptRangeEnd];\n\t\tNSRange selectedRange = [outputTextView selectedRange];\n\t\t\n\t\tif ((promptEnd > 0) && (selectedRange.location >= promptEnd))\n\t\t{\n\t\t\tNSString *outputString = [outputTextView string];\n\t\t\tNSString *scriptString = [outputString substringFromIndex:promptEnd];\n\t\t\t\n\t\t\tselectedRange.location -= promptEnd;\n\t\t\t\n\t\t\t[statusTextField setAttributedStringValue:[outputTextView attributedSignatureForScriptString:scriptString selection:selectedRange]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[statusTextField setStringValue:@\"\"];\n\t\t}\n\t}\n\telse if (textView == scriptTextView)\n\t{\n\t\t[statusTextField setAttributedStringValue:[scriptTextView attributedSignatureForScriptString:[scriptTextView string] selection:[scriptTextView selectedRange]]];\n\t}\n}\n\n\n//\n//\tNSWindow delegate methods\n//\n#pragma mark -\n#pragma mark NSWindow delegate\n\n- (void)windowWillClose:(NSNotification *)notification\n{\n\tNSWindow *closingWindow = [notification object];\n\t\n\tif (closingWindow == scriptWindow)\n\t{\n\t\t// The variable browser is an inspector on our state, but we don't close it here.  In EidosScribe,\n\t\t// we are quitting at this point anyway, so it doesn't matter.  In SLiMgui, the var browser is\n\t\t// still meaningful even with our window closed, since it shows the current simulation state.\n\t\t// This may need to be revisited for other Contexts.\n\t\t\n\t\t//if ([[browserController browserWindow] isVisible])\n\t\t//\t[browserController toggleBrowserVisibility:self];\n\t\t\n\t\t// Let our delegate do something; EidosScribe quits, SLiMgui toggles its console button\n\t\tif ([delegate respondsToSelector:@selector(eidosConsoleWindowControllerConsoleWindowWillClose:)])\n\t\t\t[delegate eidosConsoleWindowControllerConsoleWindowWillClose:self];\n\t}\n}\n\n\n//\n//\tNSSplitView delegate methods\n//\n#pragma mark -\n#pragma mark NSSplitView delegate\n\n- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview\n{\n\treturn YES;\n}\n\n// NSSplitView doesn't like delegates to implement these methods any more; it logs if you do.  We can achieve the same\n// effect using constraints in the nib, which is the new way to do things, so that's what we do now.\n\n/*\n- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex\n{\n\treturn proposedMax - 230;\n}\n\n- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex\n{\n\treturn proposedMin + 230;\n}\n*/\n\n@end\n\n@implementation EidosConsoleWindowController (CxxAdditions)\n\n// provides access to the symbol table of the console window, sometimes used by the Context for completion or other tasks\n- (EidosSymbolTable *)symbols\n{\n\treturn global_symbols;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosConsoleWindowControllerDelegate.h",
    "content": "//\n//  EidosConsoleWindowControllerDelegate.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 9/10/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include <vector>\n#include <string>\n\n#include \"eidos_interpreter.h\"\n#include \"EidosTextViewDelegate.h\"\n\n@class EidosConsoleWindowController;\n\n\n/*\n \n This is an Objective-C++ header, and so can only be included by Objective-C++ compilations (.mm files instead of .m files).\n You should not need to include this header in your .h files, since you can declare protocol conformance in a class-continuation\n category in your .m file, so only classes that conform to this protocol should need to be Objective-C++.\n \n EidosConsoleWindowControllerDelegate is a protocol of optional methods that EidosConsoleWindowController's delegate can\n implement, to provide various Context-defined behaviors and modifications.\n\n */\n\n@protocol EidosConsoleWindowControllerDelegate\n@optional\n\n// If provided, this context object will be handed to EidosInterpreter objects created by the console\n// controller when interpreting Eidos code; the context can then be obtained by Context implementations\n// of functions and method using EidosInterpreter::Context(), to recover the context object for their own use\n- (EidosContext *)eidosConsoleWindowControllerEidosContext:(EidosConsoleWindowController *)eidosConsoleController;\n\n// This allows the Context to append its own welcome message to the console window on startup\n- (void)eidosConsoleWindowControllerAppendWelcomeMessageAddendum:(EidosConsoleWindowController *)eidosConsoleController;\n\n// This allows the Context to define its own symbols beyond those in Eidos itself\n- (EidosSymbolTable *)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController symbolsFromBaseSymbols:(EidosSymbolTable *)baseSymbols;\n\n// This allows the Context to define its own functions beyond those in Eidos itself\n// The returned symbol table is not freed by the caller, since it is assumed to be\n// an existing object with a lifetime managed by the callee.\n- (EidosFunctionMap *)functionMapForEidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController;\n\n// The functionMapForEidosConsoleWindowController: delegate method returns the current function map\n// from the state of the delegate.  That may not include some optional functions, such as SLiM's\n// zero-generation functions, that EidosConsoleWindowController wants to know about in some situations.\n// This delegate method requests those optional functions to be added.\n- (void)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController addOptionalFunctionsToMap:(EidosFunctionMap *)functionMap;\n\n// This notifies the delegate that a script check operation did or did not succeed, allowing custom UI\n- (void)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController checkScriptDidSucceed:(BOOL)succeeded;\n\n// This delegate method is called immediately before a script block is executed, allowing custom setup\n- (void)eidosConsoleWindowControllerWillExecuteScript:(EidosConsoleWindowController *)eidosConsoleController;\n\n// This delegate method is called immediately after a script block is executed, allowing custom tear-down\n- (void)eidosConsoleWindowControllerDidExecuteScript:(EidosConsoleWindowController *)eidosConsoleController;\n\n// This delegate method is called just before a console window is closed\n- (void)eidosConsoleWindowControllerConsoleWindowWillClose:(EidosConsoleWindowController *)eidosConsoleController;\n\n// messages from EidosTextViewDelegate that we essentially forward on to our delegate; see EidosTextView.h\n- (EidosSyntaxHighlightType)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController tokenStringIsSpecialIdentifier:(const std::string &)token_string;\n- (NSString *)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController helpTextForClickedText:(NSString *)clickedText;\n\n@end\n\n\n// We also provide here a method on EidosConsoleWindowController that returns a C++ object and thus cannot be declared\n// in the main header.  If you need to call this method, you can simply include this header to get its interface.\n\n@interface EidosConsoleWindowController (CxxAdditions)\n\n// provides access to the symbol table of the console window, sometimes used by the Context for completion or other tasks\n- (EidosSymbolTable *)symbols;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosHelpClasses.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2709\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Bold;\\f1\\fswiss\\fcharset0 Optima-Italic;\\f2\\fnil\\fcharset0 Menlo-Italic;\n\\f3\\fnil\\fcharset0 Menlo-Regular;\\f4\\fswiss\\fcharset0 Optima-Regular;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.1  Class Object\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf2 5.1.1  \n\\f2\\fs18 Object\n\\f1\\fs22  properties\\\n5.1.2  \n\\f2\\fs18 Object\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 +\\'a0(integer$)length(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the size (e.g., length) of the receiving object.  This is equivalent to the \n\\f3\\fs18 length()\n\\f4\\fs20  (or \n\\f3\\fs18 size()\n\\f4\\fs20 ) function; in other words, for any \n\\f3\\fs18 object\n\\f4\\fs20  \n\\f3\\fs18 x\n\\f4\\fs20 , the return value of the function call \n\\f3\\fs18 length(x)\n\\f4\\fs20  equals the return value of the class method call \n\\f3\\fs18 x.length()\n\\f4\\fs20 .  This method is provided solely for syntactic convenience.  Note that \n\\f3\\fs18 +length()\n\\f4\\fs20  is a synonym for \n\\f3\\fs18 +size()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(void)methodSignature([Ns$\\'a0methodName\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Prints the method signature for the method specified by \n\\f3\\fs18 methodName\n\\f4\\fs20 , or for all methods supported by the receiving object if \n\\f3\\fs18 methodName\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(void)propertySignature([Ns$\\'a0propertyName\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Prints the property signature for the property specified by \n\\f3\\fs18 propertyName\n\\f4\\fs20 , or for all properties supported by the receiving object if \n\\f3\\fs18 propertyName\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(integer$)size(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the size of the receiving object.  This is equivalent to the \n\\f3\\fs18 size()\n\\f4\\fs20  (or \n\\f3\\fs18 length()\n\\f4\\fs20 ) function; in other words, for any \n\\f3\\fs18 object\n\\f4\\fs20  \n\\f3\\fs18 x\n\\f4\\fs20 , the return value of the function call \n\\f3\\fs18 size(x)\n\\f4\\fs20  equals the return value of the class method call \n\\f3\\fs18 x.size()\n\\f4\\fs20 .  This method is provided solely for syntactic convenience.  Note that \n\\f3\\fs18 +length()\n\\f4\\fs20  is a synonym for \n\\f3\\fs18 +size()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)str(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Prints the internal property structure of the receiving object; in particular, the element type of the object is printed, followed, on successive lines, by all of the properties supported by the object, their types, and a sample of their values.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(string$)stringRepresentation(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a singleton \n\\f3\\fs18 string\n\\f4\\fs20  value that represents the receiving object.  By default, this is simply the name of the class of the receiving object; however, many subclasses of \n\\f3\\fs18 Object\n\\f4\\fs20  provide a different string representation.  The value returned by \n\\f3\\fs18 stringRepresentation()\n\\f4\\fs20  is the same string that would be printed by \n\\f3\\fs18 print()\n\\f4\\fs20  for the object, so \n\\f3\\fs18 stringRepresentation()\n\\f4\\fs20  allows the same representation to be used in other contexts such as \n\\f3\\fs18 paste()\n\\f4\\fs20  and \n\\f3\\fs18 cat()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.2  Class DataFrame\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\b0\\fs18 \\cf2 (object<DataFrame>$)DataFrame(...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 DataFrame\n\\f4\\fs20  constructor can be called in the same ways as the constructor for \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (its superclass): with no parameters to make an empty \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , with key-value pairs, with a singleton \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , like \n\\f3\\fs18 DataFrame\n\\f4\\fs20 ) to make a copy, or with a string in JSON format.  See the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class for further documentation.  However, note that \n\\f3\\fs18 DataFrame\n\\f4\\fs20  can only use \n\\f3\\fs18 string\n\\f4\\fs20  keys; \n\\f3\\fs18 integer\n\\f4\\fs20  keys are not allowed.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.2.1  \n\\f2\\fs18 DataFrame\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 colNames => (string)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector containing all of the \n\\f3\\fs18 string\n\\f4\\fs20  column names in the \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , in order.  This property is currently an alias for the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  property \n\\f3\\fs18 allKeys\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 dim => (integer)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A two-element vector containing the dimensions of the \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The \n\\f3\\fs18 0\n\\f4\\fs20 th element is the number of rows (as provided by \n\\f3\\fs18 nrow\n\\f4\\fs20 ), and the \n\\f3\\fs18 1\n\\f4\\fs20 st element is the number of columns (as provided by \n\\f3\\fs18 ncol\n\\f4\\fs20 ).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 ncol => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The number of columns in the \n\\f3\\fs18 DataFrame\n\\f4\\fs20 ; this will be equal to the length of \n\\f3\\fs18 colNames\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 nrow => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The number of rows in the \n\\f3\\fs18 DataFrame\n\\f4\\fs20  (i.e., the number of elements in a column).  This will be the same for every column, by definition.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.2.2  \n\\f2\\fs18 DataFrame\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(*)asMatrix(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a matrix representation of the \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The matrix will have the same type as the elements of the \n\\f3\\fs18 DataFrame\n\\f4\\fs20 ; if the \n\\f3\\fs18 DataFrame\n\\f4\\fs20  contains more than one type of element, an error will be raised.  The order of the columns of the \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will be preserved.  This method is useful, for example, if you wish to read in a text file as a matrix; you can use \n\\f3\\fs18 readCSV()\n\\f4\\fs20  to read the file as a \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , and then convert it to a matrix with \n\\f3\\fs18 asMatrix()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)cbind(object<Dictionary>\\'a0source, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds all of the columns contained by \n\\f3\\fs18 source\n\\f4\\fs20  (which must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20  such as \n\\f3\\fs18 DataFrame\n\\f4\\fs20 ) to the receiver.  This method makes the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20  wider, by adding new columns.  If \n\\f3\\fs18 source\n\\f4\\fs20  contains a column name that is already defined in the target, an error will result.  As always for \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , the columns of the resulting \n\\f3\\fs18 DataFrame\n\\f4\\fs20  must all be the same length.\\\nThe \n\\f3\\fs18 source\n\\f4\\fs20  parameter may be a non-singleton vector containing multiple \n\\f3\\fs18 Dictionary\n\\f4\\fs20  objects, and additional \n\\f3\\fs18 Dictionary\n\\f4\\fs20  vectors may be supplied (thus the ellipsis in the signature).  Each \n\\f3\\fs18 Dictionary\n\\f4\\fs20  supplied will be added to the target, in the order supplied.\\\nThis method is similar to the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method \n\\f3\\fs18 addKeysAndValuesFrom()\n\\f4\\fs20 , which may be used instead if replacement of duplicate columns is desired.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)rbind(object<Dictionary>\\'a0source, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Appends all of the columns contained by \n\\f3\\fs18 source\n\\f4\\fs20  (which must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20  such as \n\\f3\\fs18 DataFrame\n\\f4\\fs20 ) to the receiver.  This method makes the \n\\f3\\fs18 DataFrame\n\\f4\\fs20  taller, by adding new rows.  If the source and target do not contain the same column names in the same order, an error will result.  As always for \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , the columns of the resulting \n\\f3\\fs18 DataFrame\n\\f4\\fs20  must all be the same length.\\\nThe \n\\f3\\fs18 source\n\\f4\\fs20  parameter may be a non-singleton vector containing multiple \n\\f3\\fs18 Dictionary\n\\f4\\fs20  objects, and additional \n\\f3\\fs18 Dictionary\n\\f4\\fs20  vectors may be supplied (thus the ellipsis in the signature).  Each \n\\f3\\fs18 Dictionary\n\\f4\\fs20  supplied will be appended to the target, in the order supplied.\\\nThis method is similar to the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method \n\\f3\\fs18 appendKeysAndValuesFrom()\n\\f4\\fs20 , which may be used instead if one wishes the append to work even when the columns are in different orders, or other such situations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(*)subset([Nli\\'a0rows\\'a0=\\'a0NULL], [Nlis\\'a0cols\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the elements in the selected rows and columns of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The selection logic is based upon that for \n\\f3\\fs18 subsetRows()\n\\f4\\fs20  and \n\\f3\\fs18 subsetColumns()\n\\f4\\fs20 , respectively; in short, rows may be selected by \n\\f3\\fs18 integer\n\\f4\\fs20  indices or by a \n\\f3\\fs18 logical\n\\f4\\fs20  vector, and columns may be selected by \n\\f3\\fs18 integer\n\\f4\\fs20  indices, by a \n\\f3\\fs18 logical\n\\f4\\fs20  vector, or by a \n\\f3\\fs18 string\n\\f4\\fs20  vector of column names.  In addition, however, \n\\f3\\fs18 NULL\n\\f4\\fs20  may be passed for either \n\\f3\\fs18 rows\n\\f4\\fs20  or \n\\f3\\fs18 cols\n\\f4\\fs20  to select all of the rows or all of the columns, respectively; this is the default for both parameters.  If you want entire rows (rather than selecting particular columns), pass \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 cols\n\\f4\\fs20 ; if you want entire columns (rather than selecting particular rows), pass \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 rows\n\\f4\\fs20 .\\\nThe first step performed by \n\\f3\\fs18 subset()\n\\f4\\fs20  is to produce a \n\\f3\\fs18 DataFrame\n\\f4\\fs20  that contains the selected rows and columns.  If that \n\\f3\\fs18 DataFrame\n\\f4\\fs20  contains more than one column, it is simply returned, and the behavior of \n\\f3\\fs18 subset()\n\\f4\\fs20  is identical to calling \n\\f3\\fs18 subsetRows()\n\\f4\\fs20  and \n\\f3\\fs18 subsetColumns()\n\\f4\\fs20  in sequence (in either order).  If, however, the resulting \n\\f3\\fs18 DataFrame\n\\f4\\fs20  contains only a single column, then \n\\f3\\fs18 subset()\n\\f4\\fs20  will return a vector containing the elements in that column \\'96 unlike the behavior of \n\\f3\\fs18 subsetRows()\n\\f4\\fs20  and \n\\f3\\fs18 subsetColumns()\n\\f4\\fs20 , which always return a \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  This method is therefore a convenient way to get a single value, or multiple values from the same column, from a \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  (Note that the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method \n\\f3\\fs18 getValue()\n\\f4\\fs20  can also be used to get all of the values from a given \n\\f3\\fs18 DataFrame\n\\f4\\fs20  column.)\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<DataFrame>$)subsetColumns(lis\\'a0index)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a new \n\\f3\\fs18 DataFrame\n\\f4\\fs20  containing values for the selected columns of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The selection logic described below is similar to how the subset operator \n\\f3\\fs18 []\n\\f4\\fs20  in Eidos works, selecting the columns of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .\\\nThe index parameter may be either \n\\f3\\fs18 integer\n\\f4\\fs20 , \n\\f3\\fs18 logical\n\\f4\\fs20 , or \n\\f3\\fs18 string\n\\f4\\fs20 ; we will discuss the \n\\f3\\fs18 integer\n\\f4\\fs20  case first.  If \n\\f3\\fs18 index\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20 , the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will contain the \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th column of the target (counting from the left, from \n\\f3\\fs18 0\n\\f4\\fs20 ).  If \n\\f3\\fs18 index\n\\f4\\fs20  is a non-singleton \n\\f3\\fs18 integer\n\\f4\\fs20  vector, the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will contains all of the selected columns, in the order that they are selected by \n\\f3\\fs18 index\n\\f4\\fs20 .  If any \n\\f3\\fs18 index\n\\f4\\fs20  value is out of range for the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20  (such that the \n\\f3\\fs18 DataFrame\n\\f4\\fs20  does not have an \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th column), an error will result.  If the same column is specified more than once, unique column names will be automatically generated for the additional copies of the column.\\\nIf \n\\f3\\fs18 index\n\\f4\\fs20  is a \n\\f3\\fs18 string\n\\f4\\fs20  vector, the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will contain copies of the columns in the target named by \n\\f3\\fs18 index\n\\f4\\fs20 .  As with an \n\\f3\\fs18 integer\n\\f4\\fs20  vector, it is an error if a given column does not exist in the target; and unique column names will be generated for additional copies of a column.\\\nFinally, if \n\\f3\\fs18 index\n\\f4\\fs20  is a \n\\f3\\fs18 logical\n\\f4\\fs20  vector, the length of \n\\f3\\fs18 index\n\\f4\\fs20  must be equal to the number of columns in the target.  In this case, the \n\\f3\\fs18 T\n\\f4\\fs20  values in \n\\f3\\fs18 index\n\\f4\\fs20  select the columns which will be included in the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The columns in the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will be in the same order as in the target.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<DataFrame>$)subsetRows(li\\'a0index, [logical$\\'a0drop\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a new \n\\f3\\fs18 DataFrame\n\\f4\\fs20  containing values for selected rows of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The selection logic described below works exactly as the subset operator \n\\f3\\fs18 []\n\\f4\\fs20  does in Eidos, selecting the rows of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 index\n\\f4\\fs20  parameter may be either \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 logical\n\\f4\\fs20 ; we will discuss the \n\\f3\\fs18 integer\n\\f4\\fs20  case first.  If \n\\f3\\fs18 index\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20 , the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will contain the \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th element of the value of each key of the target, under the same keys; this is a single row of the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  If \n\\f3\\fs18 index\n\\f4\\fs20  is a non-singleton \n\\f3\\fs18 integer\n\\f4\\fs20  vector, the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will contain the values for all of the selected rows, in the order that they are selected by \n\\f3\\fs18 index\n\\f4\\fs20 .  If any index value in \n\\f3\\fs18 index\n\\f4\\fs20  is out of range for the target \n\\f3\\fs18 DataFrame\n\\f4\\fs20  (such that that DataFrame does not have an \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th row), an error will result.\\\nIf \n\\f3\\fs18 index\n\\f4\\fs20  is \n\\f3\\fs18 logical\n\\f4\\fs20 , the length of \n\\f3\\fs18 index\n\\f4\\fs20  must be equal to the number of rows in the target.  In this case, the \n\\f3\\fs18 T\n\\f4\\fs20  values in \n\\f3\\fs18 index\n\\f4\\fs20  select the rows which will be included in the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  The values of each column in the returned \n\\f3\\fs18 DataFrame\n\\f4\\fs20  will be in the same order as in the target.\\\nIf the values of \n\\f3\\fs18 index\n\\f4\\fs20  are such that \n\\f1\\i no\n\\f4\\i0  value for a given key is selected, the \n\\f3\\fs18 drop\n\\f4\\fs20  parameter controls the resulting behavior.  If \n\\f3\\fs18 drop\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as \n\\f3\\fs18 integer(0)\n\\f4\\fs20  or \n\\f3\\fs18 string(0)\n\\f4\\fs20 .  If \n\\f3\\fs18 drop\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , the key will be omitted from the returned dictionary.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.3  Class Dictionary\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\b0\\fs18 \\cf2 (object<Dictionary>$)Dictionary(...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Creates a new \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object.  Called without arguments, as \n\\f3\\fs18 Dictionary()\n\\f4\\fs20 , this creates a new empty \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .\\\nAlternatively, key-value pairs can be passed to set up the initial state of the new \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .  These are set, sequentially, on the new \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , just as \n\\f3\\fs18 setValue()\n\\f4\\fs20  would do.  For example, calling \n\\f3\\fs18 Dictionary(\"a\", 0:3, \"b\", c(\"foo\", \"bar\"))\n\\f4\\fs20  is equivalent to calling \n\\f3\\fs18 Dictionary()\n\\f4\\fs20  and then calling \n\\f3\\fs18 setValue(\"a\", 0:3)\n\\f4\\fs20  and then \n\\f3\\fs18 setValue(\"b\", c(\"foo\", \"bar\"))\n\\f4\\fs20  on it; it is just a shorthand for convenience.  Keys may be of type \n\\f3\\fs18 string\n\\f4\\fs20  or \n\\f3\\fs18 integer\n\\f4\\fs20 , but must all be of the same type; \n\\f3\\fs18 Dictionary\n\\f4\\fs20  supports using either \n\\f3\\fs18 string\n\\f4\\fs20  or \n\\f3\\fs18 integer\n\\f4\\fs20  keys, but they cannot be mixed in a single \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object.\\\nAnother alternative is to call \n\\f3\\fs18 Dictionary()\n\\f4\\fs20  with a singleton \n\\f3\\fs18 Dictionary\n\\f4\\fs20  as its only argument; this creates a new \n\\f3\\fs18 Dictionary\n\\f4\\fs20  that is a copy of the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  passed, containing the same keys and values.  This is equivalent to creating a new empty \n\\f3\\fs18 Dictionary\n\\f4\\fs20  and then calling \n\\f3\\fs18 addKeysAndValuesFrom()\n\\f4\\fs20  to copy key-value pairs over; it is just a shorthand for convenience.\\\nA final alternative is to call \n\\f3\\fs18 Dictionary()\n\\f4\\fs20  with a \n\\f3\\fs18 string\n\\f4\\fs20  vector as its only argument; this creates a new \n\\f3\\fs18 Dictionary\n\\f4\\fs20  from the string, assuming that it is a data archive in JSON format.  If the \n\\f3\\fs18 string\n\\f4\\fs20  value is not a singleton, its elements will be joined together by newlines to make a singleton \n\\f3\\fs18 string\n\\f4\\fs20  value; this allows the result from \n\\f3\\fs18 readFile()\n\\f4\\fs20  to be passed directly to \n\\f3\\fs18 Dictionary()\n\\f4\\fs20  even for a multiline (prettyprinted) JSON file.  Note that a JSON string can be generated from the \n\\f3\\fs18 serialize()\n\\f4\\fs20  method of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ; together with this way of creating a \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , this provides the ability to persist arbitrary information to a string (perhaps a file on disk) and back again.  The recreated \n\\f3\\fs18 Dictionary\n\\f4\\fs20  should be identical to the original, except that zero length vectors such as \n\\f3\\fs18 integer(0)\n\\f4\\fs20 , \n\\f3\\fs18 float(0)\n\\f4\\fs20 , \n\\f3\\fs18 logical(0)\n\\f4\\fs20 , and \n\\f3\\fs18 string(0)\n\\f4\\fs20  will all be serialized as \n\\f3\\fs18 \"[]\"\n\\f4\\fs20  and recreated as \n\\f3\\fs18 integer(0)\n\\f4\\fs20  since JSON does not provide a way to specify the type of a zero-length array.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.3.1  \n\\f2\\fs18 Dictionary\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 allKeys => (is)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector containing all of the \n\\f3\\fs18 string\n\\f4\\fs20  or \n\\f3\\fs18 integer\n\\f4\\fs20  keys that have been assigned values using \n\\f3\\fs18 setValue()\n\\f4\\fs20 , in sorted (ascending alphabetic or numeric) order.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.3.2  \n\\f2\\fs18 Dictionary\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(void)addKeysAndValuesFrom(object<Dictionary>$\\'a0source)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds all of the key-value pairs contained by \n\\f3\\fs18 source\n\\f4\\fs20  (which must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ) to the receiver.  If the target already contains a key that is defined in \n\\f3\\fs18 source\n\\f4\\fs20 , the target\\'92s value for that key will be \n\\f1\\i replaced\n\\f4\\i0  by the value in \n\\f3\\fs18 source\n\\f4\\fs20  (contrast this with \n\\f3\\fs18 appendKeysAndValuesFrom()\n\\f4\\fs20 ).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)appendKeysAndValuesFrom(object<Dictionary>\\'a0source)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Appends all of the key-value pairs contained by \n\\f3\\fs18 source\n\\f4\\fs20  (which must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ) to the receiver.  If the target already contains a key that is defined in source, the value from source will be \n\\f1\\i appended\n\\f4\\i0  to the target\\'92s existing value, which must be of the same type (contrast this with \n\\f3\\fs18 addKeysAndValuesFrom()\n\\f4\\fs20 ); if the target does not already contain a key that is defined in source, that key-value pair will simply be added to the target.\\\nIn the current implementation, it is an error for either of the values involved in an append to be a matrix or array; values in these \n\\f3\\fs18 Dictionary\n\\f4\\fs20  objects should be simple vectors.  This limitation preserves the future option to expand this method\\'92s functionality to do smart things with matrices and arrays.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)clearKeysAndValues(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Removes all key-value pairs from the receiver.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(integer)compactIndices([logical$\\'a0preserveOrder\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Compacts the receiver, which must use \n\\f3\\fs18 integer\n\\f4\\fs20  keys.  After this operation, the receiver will contain only values that have a length greater than zero (discarding all key\\'96value pairs for which the value is a zero-length vector).  In addition, the keys used will be compacted down to begin at \n\\f3\\fs18 0\n\\f4\\fs20  and count upward sequentially.  If \n\\f3\\fs18 preserveOrder\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), the keys may end up in a different numerical order; this allows the compaction to be performed more efficiently.  If \n\\f3\\fs18 preserveOrder\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , on the other hand, the numerical order of the keys will be preserved.  The returned \n\\f3\\fs18 integer\n\\f4\\fs20  vector contains the original keys that were kept across the compaction operation, in the order in which they were used in the compaction; keys that were not kept (because their value was zero-length) are omitted from this result vector.\\\nFor example, with a dictionary that contains key\\'96value pairs \n\\f3\\fs18 -5=\"a\"\n\\f4\\fs20 , \n\\f3\\fs18 17=\"b\"\n\\f4\\fs20 , \n\\f3\\fs18 37=\"c\"\n\\f4\\fs20 , \n\\f3\\fs18 53=integer(0)\n\\f4\\fs20 , and \n\\f3\\fs18 82=\"d\"\n\\f4\\fs20 , \n\\f3\\fs18 compactIndices(preserveOrder=T)\n\\f4\\fs20  will transform the dictionary to contain \n\\f3\\fs18 0=\"a\"\n\\f4\\fs20 , \n\\f3\\fs18 1=\"b\"\n\\f4\\fs20 , \n\\f3\\fs18 2=\"c\"\n\\f4\\fs20 , and \n\\f3\\fs18 3=\"d\"\n\\f4\\fs20 , while key \n\\f3\\fs18 53\n\\f4\\fs20  (and its zero-length value) is dropped; the returned vector will be (\n\\f3\\fs18 5\n\\f4\\fs20 , \n\\f3\\fs18 17\n\\f4\\fs20 , \n\\f3\\fs18 37\n\\f4\\fs20 , \n\\f3\\fs18 82\n\\f4\\fs20 ).  The result from \n\\f3\\fs18 compactIndices(preserveOrder=F)\n\\f4\\fs20  has a non-deterministic order, but one possibility for the same example inout is that it would transform the dictionary to contain key\\'96value pairs \n\\f3\\fs18 0=\"c\"\n\\f4\\fs20 , \n\\f3\\fs18 1=\"d\"\n\\f4\\fs20 , \n\\f3\\fs18 2=\"a\"\n\\f4\\fs20 , and \n\\f3\\fs18 3=\"b\"\n\\f4\\fs20 , with a returned vector of (\n\\f3\\fs18 37\n\\f4\\fs20 , \n\\f3\\fs18 82\n\\f4\\fs20 , \n\\f3\\fs18 5\n\\f4\\fs20 , \n\\f3\\fs18 17\n\\f4\\fs20 ); the same key\\'96value pairs are kept, and they are again placed in sequential keys beginning with \n\\f3\\fs18 0\n\\f4\\fs20 , but their order is no longer preserved across the compaction.\\\nThis method is particularly useful when you have a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  \n\\f3\\fs18 d\n\\f4\\fs20  that contains results from some operation on a vector \n\\f3\\fs18 x\n\\f4\\fs20 , such that each key \n\\f3\\fs18 n\n\\f4\\fs20  in \n\\f3\\fs18 d\n\\f4\\fs20  has a value that is the result of processing the \n\\f3\\fs18 n\n\\f4\\fs20 \\'92th element of \n\\f3\\fs18 x\n\\f4\\fs20 .  In this case, \n\\f3\\fs18 order=d.compactIndices(preserveOrder=F)\n\\f4\\fs20  will transmogrify \n\\f3\\fs18 d\n\\f4\\fs20  to contain only the non-zero-length results, in sequential indices counting from \n\\f3\\fs18 0\n\\f4\\fs20 , and \n\\f3\\fs18 x[order]\n\\f4\\fs20  provides the elements of \n\\f3\\fs18 x\n\\f4\\fs20  that produced those results, in the same order as in \n\\f3\\fs18 d\n\\f4\\fs20  after compaction.  Using \n\\f3\\fs18 preserveOrder=T\n\\f4\\fs20  additionally keeps \n\\f3\\fs18 d\n\\f4\\fs20  in the same order as the original order of \n\\f3\\fs18 x\n\\f4\\fs20 , for cases in which that ordering is important.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Dictionary>$)getRowValues(li\\'a0index, [logical$\\'a0drop\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a new \n\\f3\\fs18 Dictionary\n\\f4\\fs20  containing values for selected \\'93rows\\'94 of the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , allowing \n\\f3\\fs18 Dictionary\n\\f4\\fs20  to act similarly to a \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  See the \n\\f3\\fs18 subsetRows()\n\\f4\\fs20  method of class \n\\f3\\fs18 DataFrame\n\\f4\\fs20  for comparison; the main utility of \n\\f3\\fs18 getRowValues()\n\\f4\\fs20  is that it can be used on a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  that has ragged \\'93rows\\'94.  The selection logic described below works similarly to the subset operator \n\\f3\\fs18 []\n\\f4\\fs20  in Eidos, selecting the \\'93rows\\'94 of the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 index\n\\f4\\fs20  parameter may be either \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 logical\n\\f4\\fs20 ; we will discuss the \n\\f3\\fs18 integer\n\\f4\\fs20  case first.  If \n\\f3\\fs18 index\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20 , the returned \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will contain the \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th element of the value of each key of the target, under the same keys; this is a single \\'93row\\'94 of the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .  If \n\\f3\\fs18 index\n\\f4\\fs20  is a non-singleton \n\\f3\\fs18 integer\n\\f4\\fs20  vector, the returned \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will contain the values for all of the selected rows, in the order that they are selected by \n\\f3\\fs18 index\n\\f4\\fs20 .  If any index value in \n\\f3\\fs18 index\n\\f4\\fs20  is out of range for any key of the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (such that that key does not have an \n\\f3\\fs18 index\n\\f4\\fs20 \\'92th value), the returned dictionary will simply not have a value for that \\'93row\\'94 of that key.\\\nIf \n\\f3\\fs18 index\n\\f4\\fs20  is \n\\f3\\fs18 logical\n\\f4\\fs20 , the \n\\f3\\fs18 T\n\\f4\\fs20  values in \n\\f3\\fs18 index\n\\f4\\fs20  select the \\'93rows\\'94 which will be included in the returned \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .  The values within each column in the returned \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will be in the same order as in the target.  The length of \n\\f3\\fs18 index\n\\f4\\fs20  need not match any column of the \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ; excess \\'93rows\\'94 beyond the length of \n\\f3\\fs18 index\n\\f4\\fs20  will not be selected, and excess values in \n\\f3\\fs18 index\n\\f4\\fs20  beyond the end of the longest \\'93column\\'94 will have no effect.\\\nIf the values of \n\\f3\\fs18 index\n\\f4\\fs20  are such that \n\\f1\\i no\n\\f4\\i0  value for a given key is selected, the \n\\f3\\fs18 drop\n\\f4\\fs20  parameter controls the resulting behavior.  If \n\\f3\\fs18 drop\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as \n\\f3\\fs18 integer(0)\n\\f4\\fs20  or \n\\f3\\fs18 string(0)\n\\f4\\fs20 .  If \n\\f3\\fs18 drop\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , the key will be omitted from the returned dictionary.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(*)getValue(is$\\'a0key)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the value previously set for the dictionary entry identifier \n\\f3\\fs18 key\n\\f4\\fs20  using \n\\f3\\fs18 setValue()\n\\f4\\fs20 , or \n\\f3\\fs18 NULL\n\\f4\\fs20  if no value has been set.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(logical$)identicalContents(object<Dictionary>$\\'a0x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns \n\\f3\\fs18 T\n\\f4\\fs20  if the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20  is equal to \n\\f3\\fs18 x\n\\f4\\fs20  in all respects \\'96 containing the same keys, with values that are identical in the sense defined by the \n\\f3\\fs18 identical()\n\\f4\\fs20  function in Eidos \\'96 or returns \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.\\\nNote that if \n\\f3\\fs18 Dictionary\n\\f4\\fs20  objects are contained, as values, by the dictionaries being tested for equality, they will be compared according to the standards of \n\\f3\\fs18 identical()\n\\f4\\fs20 , and must therefore actually be the \n\\f1\\i same\n\\f4\\i0  \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object, shared by both dictionaries, for \n\\f3\\fs18 isEqual()\n\\f4\\fs20  to return \n\\f3\\fs18 T\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(string)serialize([string$\\'a0format\\'a0=\\'a0\"slim\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a serialized form of the dictionary\\'92s contents as a \n\\f3\\fs18 string\n\\f4\\fs20  singleton or vector.  Five formats are supported at present, as chosen with the \n\\f3\\fs18 format\n\\f4\\fs20  parameter: \n\\f3\\fs18 \"slim\"\n\\f4\\fs20 , \n\\f3\\fs18 \"pretty\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"json\"\n\\f4\\fs20  produce a singleton string, whereas \n\\f3\\fs18 \"csv\"\n\\f4\\fs20  and \n\\f3\\fs18 \"tsv\"\n\\f4\\fs20  produce a \n\\f3\\fs18 string\n\\f4\\fs20  vector.  These serializations can be written to disk with \n\\f3\\fs18 writeFile()\n\\f4\\fs20  or \n\\f3\\fs18 writeTempFile()\n\\f4\\fs20 , written to the output stream with \n\\f3\\fs18 cat()\n\\f4\\fs20 , or used in any other way.\\\nThe default \n\\f3\\fs18 \"slim\"\n\\f4\\fs20  format is intended for simple, informal use where a very easily parseable string is desired.  For a simple dictionary containing only keys with singleton non-object values, this will be a semicolon-delimited string like \n\\f3\\fs18 '\"string1\"=value1;\"string2\"=value2;'\n\\f4\\fs20  or \n\\f3\\fs18 'int1=value1;int2=value2;'\n\\f4\\fs20 .  Values of type \n\\f3\\fs18 string\n\\f4\\fs20  will be quoted, and will be escaped with backslash escape sequences, including \n\\f3\\fs18 \\\\\\\\\n\\f4\\fs20 , \n\\f3\\fs18 \\\\\"\n\\f4\\fs20 , \n\\f3\\fs18 \\\\'\n\\f4\\fs20 , \n\\f3\\fs18 \\\\t\n\\f4\\fs20 , \n\\f3\\fs18 \\\\r\n\\f4\\fs20 , and \n\\f3\\fs18 \\\\n\n\\f4\\fs20 .  Values that are not singleton will be separated by spaces, such as \n\\f3\\fs18 '\"string1\"=1 2 3;'\n\\f4\\fs20 , while values that are themselves dictionaries will be delimited by braces, such as \n\\f3\\fs18 '\"string1\"=\\{int1=value1;int2=value2;\\};'\n\\f4\\fs20 .  Keys that are of type \n\\f3\\fs18 string\n\\f4\\fs20  will be quoted (always; note that this is a change in behavior starting in SLiM 4.1) and backslash-escaped (as needed, as for \n\\f3\\fs18 string\n\\f4\\fs20  values); keys that are of type \n\\f3\\fs18 integer\n\\f4\\fs20  are not quoted.  No facility for parsing \n\\f3\\fs18 \"slim\"\n\\f4\\fs20  serializations back into Eidos is presently provided.\\\nFor a more extended example, here is an input \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , assigned into a variable \n\\f3\\fs18 x\n\\f4\\fs20 :\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li907\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 x = Dictionary(\"a\", 17, \"b\", 1:5, \"c\", c(\"foo\", \"bar\"),\\uc0\\u8232                   \"d\", Dictionary(\"seq\", 1.5:5),\\u8232                   \"e\", Dictionary());\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 and here is the result of \n\\f3\\fs18 x.serialize(\"json\")\n\\f4\\fs20 , omitting the enclosing quotes that would indicate that this is a \n\\f3\\fs18 string\n\\f4\\fs20  value:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li907\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \"a\"=17;\"b\"=1 2 3 4 5;\"c\"=\"foo\" \"bar\";\"d\"=\\{\"seq\"=1.5 2.5 3.5 4.5;\\};\"e\"=\\{\\};\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 \"pretty\"\n\\f4\\fs20  format is intended for human-readable output, for purposes such as debugging output.  It is similar to the \n\\f3\\fs18 \"slim\"\n\\f4\\fs20  format, but (1)\\'a0it prints an enclosing set of braces at the top level, (2)\\'a0it adds newlines inside braces, (3)\\'a0it tracks an indentation level that increments for nested dictionaries, (4)\\'a0it adds whitespace it some positions for readability, such as around the equals signs that separate keys from values, and (5)\\'a0it omits the semicolon at the end of a value, adding a newline instead.  No facility for parsing \n\\f3\\fs18 \"pretty\"\n\\f4\\fs20  serializations back into Eidos is presently provided.\\\nFor the same extended example \n\\f3\\fs18 Dictionary\n\\f4\\fs20  as above, here is the result of \n\\f3\\fs18 x.serialize(\"pretty\")\n\\f4\\fs20 , again omitting the enclosing quotes that would indicate that this is a \n\\f3\\fs18 string\n\\f4\\fs20  value:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li907\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\{\\uc0\\u8232    \"a\" = 17\\u8232    \"b\" = 1 2 3 4 5\\u8232    \"c\" = \"foo\" \"bar\"\\u8232    \"d\" = \\{\\u8232       \"seq\" = 1.5 2.5 3.5 4.5\\u8232    \\}\\u8232    \"e\" = \\{\\}\\u8232 \\}\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 \"json\"\n\\f4\\fs20  format, introduced in Eidos 2.7 (SLiM 3.7), provides serialization of the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  into the standard JSON format, which may not be quite as brief or human-readable, but which can be used as a standard interchange format and read by the \n\\f3\\fs18 Dictionary()\n\\f4\\fs20  constructor in Eidos as well as by many other programs.  For example, a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  with a key \n\\f3\\fs18 \"key1\"\n\\f4\\fs20  with \n\\f3\\fs18 integer\n\\f4\\fs20  value \n\\f3\\fs18 1:3\n\\f4\\fs20  and key \n\\f3\\fs18 \"key2\"\n\\f4\\fs20  with \n\\f3\\fs18 string\n\\f4\\fs20  value \n\\f3\\fs18 \"value2\"\n\\f4\\fs20  would produce the JSON serialization \n\\f3\\fs18 '\\{\"key1\":[1,2,3],\"key2\":[\"value2\"]\\}'\n\\f4\\fs20 , where the outer single quotes are not part of the serialization itself, but are indicating that the serialization is a \n\\f3\\fs18 string\n\\f4\\fs20  value.  Note that since all Eidos values are vectors, even singleton values are serialized into JSON as arrays by Eidos; the hope is that this will make automated parsing of these JSON strings easier, since the singleton case will not have to be special-cased.  For example, \n\\f3\\fs18 Dictionary(\"a\", 1, \"b\", Dictionary(\"x\", 2))\n\\f4\\fs20  would be serialized into JSON as \n\\f3\\fs18 '\\{\"a\":[1],\"b\":[\\{\"x\":[2]\\}]\\}'\n\\f4\\fs20 .  Note that dictionaries that use \n\\f3\\fs18 integer\n\\f4\\fs20  keys cannot be serialized into JSON, because JSON does not support \n\\f3\\fs18 integer\n\\f4\\fs20  keys.  Documentation on the JSON format can be found online.\\\nThe \n\\f3\\fs18 \"csv\"\n\\f4\\fs20  and \n\\f3\\fs18 \"tsv\"\n\\f4\\fs20  formats produce standard comma-separated value (CSV) or tab-separated value (TSV) data.  These formats are primarily intended for output from \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , since that class is used to represent the sort of data tables that CSV/TSV are typically used for; but it may be used with \n\\f3\\fs18 Dictionary\n\\f4\\fs20  too, particularly if it is being used to represent a data table with ragged columns (missing values will just be skipped over, producing two commas or two tabs in sequence).  Values of type \n\\f3\\fs18 string\n\\f4\\fs20  will always be quoted, with double quotes (with a repeated double quote used to indicate the presence of a double quote inside a \n\\f3\\fs18 string\n\\f4\\fs20  value, as usual in CSV); values of other types never will.  Decimal points (not decimal commas, regardless of system localization) will always be used for \n\\f3\\fs18 float\n\\f4\\fs20  values, and will never be used for \n\\f3\\fs18 integer\n\\f4\\fs20  values.  Values of logical type will be serialized as \n\\f3\\fs18 TRUE\n\\f4\\fs20  or \n\\f3\\fs18 FALSE\n\\f4\\fs20 , without quotes.  A header line providing the names of the columns (i.e., the keys of the target \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ) will always be generated; those column names will also be quoted (if the keys of the dictionary are type \n\\f3\\fs18 string\n\\f4\\fs20 ; \n\\f3\\fs18 integer\n\\f4\\fs20  keys are not quoted).  One \n\\f3\\fs18 string\n\\f4\\fs20  element will be generated for each row of the target, plus one \n\\f3\\fs18 string\n\\f4\\fs20  element for the header line; newlines will not be present in the resulting \n\\f3\\fs18 string\n\\f4\\fs20  vector unless newlines were present within the \n\\f3\\fs18 string\n\\f4\\fs20  values in the \n\\f3\\fs18 Dictionary\n\\f4\\fs20 .  The resulting data, if written to a file, should be readable in Eidos using \n\\f3\\fs18 readCSV()\n\\f4\\fs20  (as long as there are no ragged columns or missing values), as well as in other software such as R and Excel.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setValue(is$\\'a0key, *\\'a0value)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Sets a value for the dictionary entry identifier \n\\f3\\fs18 key\n\\f4\\fs20 .  The key may be a \n\\f3\\fs18 string\n\\f4\\fs20  or an \n\\f3\\fs18 integer\n\\f4\\fs20 ; either is allowed, unless the target dictionary has already begun using keys of a given type, in which case it must continue using the same key type (a given dictionary cannot have both \n\\f3\\fs18 string\n\\f4\\fs20  and \n\\f3\\fs18 integer\n\\f4\\fs20  keys).  The value, which may be of any type, can be fetched later using \n\\f3\\fs18 getValue()\n\\f4\\fs20 .  Setting a key to a value of \n\\f3\\fs18 NULL\n\\f4\\fs20  removes that key from the dictionary.\\\nIf \n\\f3\\fs18 value\n\\f4\\fs20  is of type \n\\f3\\fs18 object\n\\f4\\fs20 , any \n\\f3\\fs18 object\n\\f4\\fs20  class is allowed; all objects may be added as values to a dictionary.  However, additional scoping restrictions may apply if the \n\\f3\\fs18 object\n\\f4\\fs20  class is not under an internal memory-management scheme called \\'93retain-release\\'94; in particular, it may not be legal to keep an object in a dictionary \\'93long term\\'94 if it is not under retain-release, where \\'93long term\\'94 is a scoping semantic defined by the Context.  All object classes defined by Eidos itself (\n\\f3\\fs18 Dictionary\n\\f4\\fs20 , \n\\f3\\fs18 DataFrame\n\\f4\\fs20 , \n\\f3\\fs18 Image\n\\f4\\fs20 ) are under retain-release, so this restriction does not affect pure Eidos code.  See the SLiM manual (section \\'93SLiM scoping rules\\'94) for further discussion of this topic.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(void)setValuesVectorized(is$\\'a0key, *\\'a0values)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This class method sets a singleton value from \n\\f3\\fs18 values\n\\f4\\fs20  into each target dictionary, using the same dictionary entry identifier \n\\f3\\fs18 key\n\\f4\\fs20  for each.  The number of elements in \n\\f3\\fs18 values\n\\f4\\fs20  must be equal to the number of target dictionaries, so that the 0th element of \n\\f3\\fs18 values\n\\f4\\fs20  is set as the value for the 0th target object, the 1st element of \n\\f3\\fs18 values\n\\f4\\fs20  is set as the value for the 1st target object, and so forth.\\\nThis is a vectorized version of \n\\f3\\fs18 setValue()\n\\f4\\fs20 ; \n\\f3\\fs18 dicts.setValuesVectorized(\"key\", values)\n\\f4\\fs20  is equivalent to \n\\f3\\fs18 for (dict in dicts, value in values) dict.setValue(\"key\", value)\n\\f4\\fs20 , but is faster since the \n\\f3\\fs18 for\n\\f4\\fs20  loop is vectorized internally.  The speedup is not enormous, however; the larger reason for the existence of this method is convenience.\\\nThe values are set into the target dictionaries in exactly the same way as the \n\\f3\\fs18 setValue()\n\\f4\\fs20  method would do; see that method for details about \n\\f3\\fs18 string\n\\f4\\fs20  versus \n\\f3\\fs18 integer\n\\f4\\fs20  keys, scoping restrictions for values of type \n\\f3\\fs18 object\n\\f4\\fs20 , and so forth.  Note that it is not possible to remove values from the target dictionaries, however, since it is not possible to pass \n\\f3\\fs18 NULL\n\\f4\\fs20  as a value here.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.4  Class Image\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\b0\\fs18 \\cf2 (object<Image>$)Image(...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Creates a new \n\\f3\\fs18 Image\n\\f4\\fs20  object.  This can be called in a few different ways.\\\nPassed a singleton \n\\f3\\fs18 string\n\\f4\\fs20 , as \n\\f3\\fs18 Image(string$ filePath)\n\\f4\\fs20 , it creates a new \n\\f3\\fs18 Image\n\\f4\\fs20  from the PNG file at \n\\f3\\fs18 filePath\n\\f4\\fs20 .  If the file represents a grayscale image, an 8-bit grayscale (K) \n\\f3\\fs18 Image\n\\f4\\fs20  will be created; all other PNG files will yield a 24-bit color (RGB) \n\\f3\\fs18 Image\n\\f4\\fs20 .\\\nPassed an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector, as \n\\f3\\fs18 Image(numeric matrix)\n\\f4\\fs20 , it creates a new grayscale \n\\f3\\fs18 Image\n\\f4\\fs20  from the values in \n\\f3\\fs18 matrix\n\\f4\\fs20 , which must be a matrix as its name suggests.  If \n\\f3\\fs18 matrix\n\\f4\\fs20  is \n\\f3\\fs18 integer\n\\f4\\fs20 , its values must be in [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 255\n\\f4\\fs20 ], and will be used directly as 8-bit pixel values without translation; if \n\\f3\\fs18 matrix\n\\f4\\fs20  is \n\\f3\\fs18 float\n\\f4\\fs20 , its values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], and will be translated into 8-bit pixel values.  The dimensions of the image, in pixels, will be equal to the dimensions of the matrix.  The orientation of the image will match that of the matrix, in the sense that the image will appear as the matrix does when printed in the Eidos console; internally this requires a transposition of values, as discussed further below.  For the \n\\f3\\fs18 integer\n\\f4\\fs20  case, the \n\\f3\\fs18 integerK\n\\f4\\fs20  property of the resulting image will recover the original matrix exactly; for the \n\\f3\\fs18 float\n\\f4\\fs20  case, the \n\\f3\\fs18 floatK\n\\f4\\fs20  property will only approximately recover the original matrix since the translation into 8-bit pixel values involves quantization, but values of \n\\f3\\fs18 0.0\n\\f4\\fs20  and \n\\f3\\fs18 1.0\n\\f4\\fs20  will be recovered exactly.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.4.1  \n\\f2\\fs18 Image\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 width => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The width of the image, in pixels.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 height => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The height of the image, in pixels.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 isGrayscale => (logical$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This flag is \n\\f3\\fs18 T\n\\f4\\fs20  if the image is grayscale, with only a K channel; it is \n\\f3\\fs18 F\n\\f4\\fs20  if the image is color, with R/G/B channels.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 bitsPerChannel => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The number of bits used to represent a single pixel, in one channel of the image.  At present this is always 8; grayscale (K) images are 8-bit, color (RGB) images are 24-bit.  It could be extended to support 16-bit channels in future.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 integerR => (integer)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The red (R) channel of the image, represented as a 2D \n\\f3\\fs18 integer\n\\f4\\fs20  matrix.  Values will be in [0,255].  See the \n\\f3\\fs18 floatR\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 integerG => (integer)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The green (G) channel of the image, represented as a 2D \n\\f3\\fs18 integer\n\\f4\\fs20  matrix.  Values will be in [0,255].  See the \n\\f3\\fs18 floatG\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 integerB => (integer)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The blue (R) channel of the image, represented as a 2D \n\\f3\\fs18 integer\n\\f4\\fs20  matrix.  Values will be in [0,255].  See the \n\\f3\\fs18 floatB\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 integerK => (integer)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The gray (K) channel of the image, represented as a 2D \n\\f3\\fs18 integer\n\\f4\\fs20  matrix.  Values will be in [0,255].  See the \n\\f3\\fs18 floatK\n\\f4\\fs20  property for an alternative representation.  If the image is color, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 floatR => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The red (R) channel of the image, represented as a 2D \n\\f3\\fs18 float\n\\f4\\fs20  matrix.  Values will be in [0,1], obtained by dividing the \n\\f3\\fs18 integerR\n\\f4\\fs20  layer by 255.  See the \n\\f3\\fs18 integerR\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 floatG => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The green (G) channel of the image, represented as a 2D \n\\f3\\fs18 float\n\\f4\\fs20  matrix.  Values will be in [0,1], obtained by dividing the \n\\f3\\fs18 integerG\n\\f4\\fs20  layer by 255.  See the \n\\f3\\fs18 integerG\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 floatB => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The blue (B) channel of the image, represented as a 2D \n\\f3\\fs18 float\n\\f4\\fs20  matrix.  Values will be in [0,1], obtained by dividing the \n\\f3\\fs18 integerB\n\\f4\\fs20  layer by 255.  See the \n\\f3\\fs18 integerB\n\\f4\\fs20  property for an alternative representation.  If the image is grayscale, this property is unavailable.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 floatK => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The gray (K) channel of the image, represented as a 2D \n\\f3\\fs18 float\n\\f4\\fs20  matrix.  Values will be in [0,1], obtained by dividing the \n\\f3\\fs18 integerK\n\\f4\\fs20  layer by 255.  See the \n\\f3\\fs18 integerK\n\\f4\\fs20  property for an alternative representation.  If the image is color, this property is unavailable.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.4.2  \n\\f2\\fs18 Image\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(void)write(string$\\'a0filePath)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Writes the image to the given filesystem path \n\\f3\\fs18 filePath\n\\f4\\fs20  as PNG data.  It is suggested, but not required, that \n\\f3\\fs18 filePath\n\\f4\\fs20  should end in a \n\\f3\\fs18 .png\n\\f4\\fs20  or \n\\f3\\fs18 .PNG\n\\f4\\fs20  filename extension.  If the file cannot be written, an error will result.  At present, since \n\\f3\\fs18 bitsPerChannel\n\\f4\\fs20  is always 8, grayscale data will be written as an 8-bit grayscale PNG while color (RGB) data will be written as a 24-bit color PNG without alpha.\\\n}"
  },
  {
    "path": "EidosScribe/EidosHelpController.h",
    "content": "//\n//  EidosHelpController.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/12/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include <string>\n#include <vector>\n\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n\n@interface EidosHelpController : NSObject\n{\n}\n\n+ (EidosHelpController *)sharedController;\n\n- (void)enterSearchForString:(NSString *)searchString titlesOnly:(BOOL)titlesOnly;\n\n- (NSWindow *)window;\n- (void)showWindow;\n\n// Add topics and items drawn from a specially formatted RTF file, under a designated top-level heading.\n// The signatures found for functions, methods, and prototypes will be checked against the supplied lists,\n// if they are not NULL, and if matches are found, colorized versions will be substituted.\n- (void)addTopicsFromRTFFile:(NSString *)rtfFile underHeading:(NSString *)topLevelHeading functions:(const std::vector<EidosFunctionSignature_CSP> *)functionList methods:(const std::vector<EidosMethodSignature_CSP> *)methodList properties:(const std::vector<EidosPropertySignature_CSP> *)propertyList;\n\n// Check for complete documentation\n- (void)checkDocumentationOfFunctions:(const std::vector<EidosFunctionSignature_CSP> *)functions;\n- (void)checkDocumentationOfClass:(EidosClass *)classObject;\n- (void)checkDocumentationForDuplicatePointers;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosHelpController.mm",
    "content": "//\n//  EidosHelpController.m\n//  SLiM\n//\n//  Created by Ben Haller on 9/12/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosHelpController.h\"\n#import \"EidosCocoaExtra.h\"\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#include <vector>\n#include <algorithm>\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n// EidosHelpOutlineView – this lets us colorize rows in the outline, and search for all rows matching an item\n@interface EidosHelpOutlineView : NSOutlineView\n- (NSIndexSet *)eidosRowIndicesForItem:(id)item;\n@end\n\n// EidosHelpTextStorage – a little subclass to make line wrapping in the help textview work the way it should, defined below\n@interface EidosHelpTextStorage : NSTextStorage\n- (id)init;\n- (id)initWithAttributedString:(NSAttributedString *)attrStr NS_DESIGNATED_INITIALIZER;\n@end\n\n// EidosDividerTextAttachmentCell – a little subclass to provide a divider between multiple help items, defined below\n@interface EidosDividerTextAttachmentCell : NSTextAttachmentCell\n@end\n\n// EidosLockingClipView – a little subclass to work around an AppKit bug, see setDescription: below\n@interface EidosLockingClipView : NSClipView\n@property (atomic, getter=isEidosScrollingLocked) BOOL eidosScrollingLocked;\n@end\n\n// EidosNSString – an NSString subclass to get around the non-uniqueness of NSTaggedPointerStrings; see guardAgainstNSTaggedPointerString\n@interface EidosNSString : NSString <NSCopying>\n{\n\tNSString *internal_string_;\n}\n+ (NSString *)stringWithString:(NSString *)aString;\n- (instancetype)init;\n- (instancetype)initWithString:(NSString *)aString;\n- (NSUInteger)length;\n- (unichar)characterAtIndex:(NSUInteger)index;\n- (void)getCharacters:(unichar *)buffer range:(NSRange)range;\n- (id)copyWithZone:(nullable NSZone *)zone;\n@end\n\n\n//\n//\tEidosHelpController\n//\n#pragma mark -\n#pragma mark EidosHelpController\n\n@interface EidosHelpController () <NSOutlineViewDataSource, NSOutlineViewDelegate>\n{\n\tNSMutableDictionary *topicRoot;\n\t\n\tint searchType;\t\t// 0 == Title, 1 == Content; equal to the tags on the search type menu items\n}\n\n@property (nonatomic, retain) IBOutlet NSWindow *helpWindow;\n\n@property (nonatomic, assign) IBOutlet NSSearchField *searchField;\n@property (nonatomic, assign) IBOutlet NSOutlineView *topicOutlineView;\n@property (nonatomic, assign) IBOutlet NSTextView *descriptionTextView;\n\n- (IBAction)searchTypeChanged:(id)sender;\n- (IBAction)searchFieldChanged:(id)sender;\n\n@end\n\n\n@implementation EidosHelpController\n\n+ (EidosHelpController *)sharedController\n{\n\tstatic EidosHelpController *sharedInstance = nil;\n\t\n\tif (!sharedInstance)\n\t\tsharedInstance = [[EidosHelpController alloc] init];\n\t\n\treturn sharedInstance;\n}\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\tstd::vector<EidosPropertySignature_CSP> builtin_properties = EidosClass::RegisteredClassProperties(true, false);\n\t\tstd::vector<EidosMethodSignature_CSP> builtin_methods = EidosClass::RegisteredClassMethods(true, false);\n\t\t\n\t\ttopicRoot = [NSMutableDictionary new];\n\t\t\n\t\t// Add Eidos topics; the only methods defined by Eidos come from EidosClass\n\t\t[self addTopicsFromRTFFile:@\"EidosHelpFunctions\" underHeading:@\"1. Eidos Functions\" functions:&EidosInterpreter::BuiltInFunctions() methods:nullptr properties:nullptr];\n\t\t[self addTopicsFromRTFFile:@\"EidosHelpClasses\" underHeading:@\"2. Eidos Classes\" functions:&EidosInterpreter::BuiltInFunctions() methods:&builtin_methods properties:&builtin_properties];    // constructors are in BuiltInFunctions()\n\t\t[self addTopicsFromRTFFile:@\"EidosHelpOperators\" underHeading:@\"3. Eidos Operators\" functions:nullptr methods:nullptr properties:nullptr];\n\t\t[self addTopicsFromRTFFile:@\"EidosHelpStatements\" underHeading:@\"4. Eidos Statements\" functions:nullptr methods:nullptr properties:nullptr];\n\t\t[self addTopicsFromRTFFile:@\"EidosHelpTypes\" underHeading:@\"5. Eidos Types\" functions:nullptr methods:nullptr properties:nullptr];\n\t\t\n\t\t//NSLog(@\"topicRoot == %@\", topicRoot);\n\t\t\n\t\t// Check for completeness of the help documentation, since it's easy to forget to add new functions/properties/methods to the doc\n\t\t[self checkDocumentationOfFunctions:&EidosInterpreter::BuiltInFunctions()];\n\t\t\n\t\tfor (EidosClass *class_object : EidosClass::RegisteredClasses(true, false))\n\t\t{\n\t\t\tconst std::string &element_type = class_object->ClassName();\n\t\t\t\n\t\t\tif (!Eidos_string_hasPrefix(element_type, \"_\") && (element_type != \"DictionaryRetained\"))\t\t// internal classes are undocumented\n\t\t\t\t[self checkDocumentationOfClass:class_object];\n\t\t}\n\t\t\n\t\t[self checkDocumentationForDuplicatePointers];\n\t}\n\t\n\treturn self;\n}\n\t\n- (void)dealloc\n{\n\t[self setHelpWindow:nil];\n\t\n\t[super dealloc];\n}\n\n// So, we have a little problem involving a private NSString subclass called NSTaggedPointerString:\n//\n// https://www.mikeash.com/pyblog/friday-qa-2015-07-31-tagged-pointer-strings.html\n//\n// The problem is that for short strings, NSTaggedPointerString effectively means that all copies of a given string are the\n// same exact object (the same pointer value), which means that using pointer equality to test whether two strings are\n// different objects, even though they contain the same characters, does not work – such tests are always true if the strings\n// are represented with NSTaggedPointerString.  We depend upon pointer equality to look up the right topics, due to the\n// crappy NSDictionary-based design of this class that I should probably rip out.  So we need to prevent NSTaggedPointerString\n// from getting into our topic tree.  As it turns out, at least for now +[NSString stringWithString:] will return a clean\n// string that is not an NSTaggedPointerString.  This is surprising, actually, since there is really no reason for it to make\n// a copy, but it does.  This could break at any point, but for now it works, and if it breaks I have a check elsewhere that\n// will detect the duplicate topic pointers and log (see -checkDocumentationForDuplicatePointers).  BCH 11/5/2017\n// Well, that stopped working in OS X 10.13; +[NSString stringWithString:] now makes an NSTaggedPointerString, foiling our\n// scheme.  So my new hack scheme is to use a custom NSString subclass, EidosNSString, for keys in our topic tree.  This method\n// now substitutes an EidosNSString for the original NSString.  That EidosNSString responds to copyWithZone: by making a copy\n// of itself, preventing NSTaggedPointerString from getting in.  This seems to work, and I think it ought to be fairly safe\n// and airtight.  We shall see.  BCH 2/26/2018\n// BCH 11/27/2019: Note that the Qt version of this class now has a much nicer design, in which a proper tree class is used\n// to represent the hierarchy instead of using NSDictionary.  There it is based on QTreeWidgetItem, but we could do the same\n// here with a custom NSObject subclass that just had a list of children, a display string, and an NSAttributedString for the doc.\n// This rearchitecture would let us get rid of this hack, and a bunch of other confusing cruft as well.\n- (NSString *)guardAgainstNSTaggedPointerString:(NSString *)oldString\n{\n\t//return oldString;\t\t// can be used to test the efficacy of checkDocumentationForDuplicatePointers; in OS X 10.12.6 we're good\n\treturn [EidosNSString stringWithString:oldString];\n}\n\n// The attributed strings straight out of the RTF file need a little reformatting, since they have paragraph indents and small font sizes appropriate for print/PDF.\n// This function corrects the strings by scanning over effective attribute ranges and patching in new paragraph styles and fonts.\n- (void)reformatTopicItemString:(NSMutableAttributedString *)topicItemAttrString\n{\n\tNSUInteger topicItemAttrStringLength = [topicItemAttrString length];\n\tNSRange topicItemAttrStringRange = NSMakeRange(0, topicItemAttrStringLength);\n\tNSRange effectiveRange;\n\t\n\t// Fix the paragraph styles to have no head indent\n\tfor (NSUInteger fixIndex = 0; fixIndex < topicItemAttrStringLength; fixIndex = effectiveRange.location + effectiveRange.length)\n\t{\n\t\tNSParagraphStyle *pStyle = [topicItemAttrString attribute:NSParagraphStyleAttributeName atIndex:fixIndex longestEffectiveRange:&effectiveRange inRange:topicItemAttrStringRange];\n\t\t\n\t\tif (pStyle)\n\t\t{\n\t\t\tCGFloat oldFirstLineHeadIndent = [pStyle firstLineHeadIndent];\n\t\t\t\n\t\t\tif (oldFirstLineHeadIndent > 0)\n\t\t\t{\n\t\t\t\tNSMutableParagraphStyle *newPStyle = [pStyle mutableCopy];\n\t\t\t\tCGFloat oldHeadIndent = [pStyle headIndent];\n\t\t\t\t\n\t\t\t\t[newPStyle setHeadIndent:oldHeadIndent - oldFirstLineHeadIndent];\n\t\t\t\t[newPStyle setFirstLineHeadIndent:0];\n\t\t\t\t[newPStyle setTailIndent:0];\n\t\t\t\t\n\t\t\t\t[topicItemAttrString addAttribute:NSParagraphStyleAttributeName value:newPStyle range:effectiveRange];\n\t\t\t\t[newPStyle release];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Fix the fonts to be a bit larger\n\tNSFontManager *fm = [NSFontManager sharedFontManager];\n\t\n\tfor (NSUInteger fixIndex = 0; fixIndex < topicItemAttrStringLength; fixIndex = effectiveRange.location + effectiveRange.length)\n\t{\n\t\tNSFont *font = [topicItemAttrString attribute:NSFontAttributeName atIndex:fixIndex longestEffectiveRange:&effectiveRange inRange:topicItemAttrStringRange];\n\t\t\n\t\tif (font)\n\t\t{\n\t\t\tNSFont *newFont = [fm convertFont:font toSize:[font pointSize] + 2];\n\t\t\t\n\t\t\t[topicItemAttrString addAttribute:NSFontAttributeName value:newFont range:effectiveRange];\n\t\t}\n\t}\n\t\n\t//NSLog(@\"attributed string for key %@ == %@\", topicItemKey, topicItemAttrString);\n}\n\n// This is a helper method for addTopicsFromRTFFile:... that finds the right parent dictionary to insert a given section index under.\n// This method makes a lot of assumptions about the layout of the RTF file, such as that section number proceeds in sorted order.\n- (NSMutableDictionary *)parentDictForSection:(NSString *)sectionString currentTopicDicts:(NSMutableDictionary *)topics topDict:(NSMutableDictionary *)topLevelDict\n{\n\tNSArray *sectionComponents = [sectionString componentsSeparatedByString:@\".\"];\n\tNSUInteger sectionCount = [sectionComponents count];\n\t\n\tif (sectionCount <= 1)\n\t{\n\t\t// With an empty section string, or a whole-number section like \"3\", the parent is always the top level dict\n\t\treturn topLevelDict;\n\t}\n\telse\n\t{\n\t\t// We have a section string like \"3.1\" or \"3.1.2\"; we want to look for a parent to add it to – like \"3\" or \"3.1\", respectively\n\t\tNSArray *parentSectionComponents = [sectionComponents subarrayWithRange:NSMakeRange(0, [sectionComponents count] - 1)];\n\t\tNSString *parentSectionString = [parentSectionComponents componentsJoinedByString:@\".\"];\n\t\tNSMutableDictionary *parentTopicDict = [topics objectForKey:parentSectionString];\n\t\t\n\t\tif (parentTopicDict)\n\t\t{\n\t\t\t// Found a parent to add to\n\t\t\treturn parentTopicDict;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Couldn't find a parent to add to, so the parent is the top level\n\t\t\treturn topLevelDict;\n\t\t}\n\t}\n}\n\n// This is a helper method for addTopicsFromRTFFile:... that creates a new \"topic dictionary\" under which items will be placed, and finds the right parent\n// dictionary to insert it under.  This method makes a lot of assumptions about the layout of the RTF file, such as that section number proceeds in sorted order.\n- (NSMutableDictionary *)topicDictForSection:(NSString *)sectionString title:(NSString *)title currentTopicDicts:(NSMutableDictionary *)topics topDict:(NSMutableDictionary *)topLevelDict\n{\n\tNSArray *sectionComponents = [sectionString componentsSeparatedByString:@\".\"];\n\tNSMutableDictionary *newTopicDict = [NSMutableDictionary dictionary];\n\t\n\tif ([title hasSuffix:@\" functions\"])\n\t\ttitle = [title substringToIndex:[title length] - [@\" functions\" length]];\n\t\n\tNSString *numberedTitle = [NSString stringWithFormat:@\"%@. %@\", [sectionComponents lastObject], title];\n\tNSMutableDictionary *parentTopicDict = [self parentDictForSection:sectionString currentTopicDicts:topics topDict:topLevelDict];\n\t\n\t[parentTopicDict setObject:newTopicDict forKey:[self guardAgainstNSTaggedPointerString:numberedTitle]];\n\t[topics setObject:newTopicDict forKey:[self guardAgainstNSTaggedPointerString:sectionString]];\n\t\n\treturn newTopicDict;\n}\n\n- (NSMutableDictionary *)effectiveTopicRoot\n{\n\tNSMutableDictionary *effectiveTopicRoot = topicRoot;\n\t\n\t// If the topic root contains only a single key, collapse that top level and consider the object for that key to be the searchDict\n\tif ([effectiveTopicRoot count] == 1)\n\t{\n\t\tid topValue = [[effectiveTopicRoot allValues] objectAtIndex:0];\n\t\t\n\t\tif ([topValue isKindOfClass:[NSDictionary class]])\n\t\t\teffectiveTopicRoot = topValue;\n\t}\n\t\n\treturn effectiveTopicRoot;\n}\n\n// This is the main RTF doc file reading method; it finds an RTF file of a given name in the main bundle, reads it into an attributed string, and then scans\n// that string for topic headings, function/method/property signature lines, etc., and creates a hierarchy of help topics from the results.  This process\n// assumes that the RTF doc file is laid out in a standard way that fits the regex patterns used here; it is designed to work directly with content copied\n// and pasted out of our Word documentation files into RTF in TextEdit.\n- (void)addTopicsFromRTFFile:(NSString *)rtfFile underHeading:(NSString *)topLevelHeading functions:(const std::vector<EidosFunctionSignature_CSP> *)functionList methods:(const std::vector<EidosMethodSignature_CSP> *)methodList properties:(const std::vector<EidosPropertySignature_CSP> *)propertyList\n{\n\tNSString *topicFilePath = [[NSBundle mainBundle] pathForResource:rtfFile ofType:@\"rtf\"];\n\tNSData *topicFileData = [NSData dataWithContentsOfFile:topicFilePath];\n\tNSAttributedString *topicFileAttrString = [[[NSAttributedString alloc] initWithRTF:topicFileData documentAttributes:NULL] autorelease];\n\t\n\t// Set up the top-level dictionary that we will place items under\n\tNSMutableDictionary *topLevelDict = [NSMutableDictionary dictionary];\n\tNSMutableDictionary *topics = [NSMutableDictionary dictionary];\t\t\t// keys are strings like 3.1 or 3.1.2 or whatever\n\tNSMutableDictionary *currentTopicDict = topLevelDict;\t\t\t\t\t// start out putting new topics in the top level dict\n\t\n\t[topicRoot setObject:topLevelDict forKey:[self guardAgainstNSTaggedPointerString:topLevelHeading]];\n\t\n\t// Set up the current topic item that we are appending content into\n\tNSString *topicItemKey = nil;\n\tNSMutableAttributedString *topicItemAttrString = nil;\n\t\n\t// Make regular expressions that we will use below\n\tNSRegularExpression *topicHeaderRegex = [NSRegularExpression regularExpressionWithPattern:@\"^((?:[0-9]+\\\\.)*[0-9]+)\\\\.?  (.+)$\" options:NSRegularExpressionCaseInsensitive error:NULL];\t\t\t\t\t\t\t\t\t// 2 captures\n\tNSRegularExpression *topicGenericItemRegex = [NSRegularExpression regularExpressionWithPattern:@\"^((?:[0-9]+\\\\.)*[0-9]+)\\\\.?  ITEM: ((?:[0-9]+\\\\.? )?)(.+)$\" options:NSRegularExpressionCaseInsensitive error:NULL];\t// 3 captures\n\tNSRegularExpression *topicFunctionRegex = [NSRegularExpression regularExpressionWithPattern:@\"^\\\\([a-zA-Z<>\\\\*+$]+\\\\)([a-zA-Z_0-9]+)\\\\(.+$\" options:NSRegularExpressionCaseInsensitive error:NULL];\t\t\t\t\t\t// 1 capture\n\tNSRegularExpression *topicMethodRegex = [NSRegularExpression regularExpressionWithPattern:@\"^([-–+])[ \\u00A0]\\\\([a-zA-Z<>\\\\*+$]+\\\\)([a-zA-Z_0-9]+)\\\\(.+$\" options:NSRegularExpressionCaseInsensitive error:NULL];\t\t\t// 2 captures\n\tNSRegularExpression *topicPropertyRegex = [NSRegularExpression regularExpressionWithPattern:@\"^([a-zA-Z_0-9]+)[ \\u00A0]((?:<[-–]>)|(?:=>)) \\\\([a-zA-Z<>\\\\*+$]+\\\\)$\" options:NSRegularExpressionCaseInsensitive error:NULL];\t// 2 captures\n\t\n\t// Scan through the file one line at a time, parsing out topic headers\n\tNSString *topicFileString = [topicFileAttrString string];\n\tNSArray *topicFileLineArray = [topicFileString componentsSeparatedByString:@\"\\n\"];\n\tNSUInteger lineCount = [topicFileLineArray count];\n\tNSUInteger lineStartIndex = 0;\t\t// the character index of the current line in topicFileAttrString\n\t\n\tfor (unsigned int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n\t{\n\t\tNSString *line = [topicFileLineArray objectAtIndex:lineIndex];\n\t\tNSUInteger lineLength = [line length];\n\t\tNSRange lineRange = NSMakeRange(0, lineLength);\n\t\tNSRange lineRangeInAttrString = NSMakeRange(lineStartIndex, lineLength);\n\t\tNSAttributedString *lineAttrString = [topicFileAttrString attributedSubstringFromRange:lineRangeInAttrString];\n\t\t\n\t\t// on the assumption (usually true) that we will need the corrected attributed string for this line, we reformat it now\n\t\t{\n\t\t\tNSMutableAttributedString *correctedLineAttrString = [[lineAttrString mutableCopy] autorelease];\n\t\t\t\n\t\t\t[self reformatTopicItemString:correctedLineAttrString];\n\t\t\tlineAttrString = correctedLineAttrString;\n\t\t}\n\t\t\n\t\t// figure out what kind of line we have and handle it\n\t\tlineStartIndex += (lineLength + 1);\t\t// +1 to jump over the newline\n\t\t\n\t\tNSUInteger isTopicHeaderLine = ([topicHeaderRegex numberOfMatchesInString:line options:(NSMatchingOptions)0 range:lineRange] > 0);\n\t\tNSUInteger isTopicGenericItemLine = ([topicGenericItemRegex numberOfMatchesInString:line options:(NSMatchingOptions)0 range:lineRange] > 0);\n\t\tNSUInteger isTopicFunctionLine = ([topicFunctionRegex numberOfMatchesInString:line options:(NSMatchingOptions)0 range:lineRange] > 0);\n\t\tNSUInteger isTopicMethodLine = ([topicMethodRegex numberOfMatchesInString:line options:(NSMatchingOptions)0 range:lineRange] > 0);\n\t\tNSUInteger isTopicPropertyLine = ([topicPropertyRegex numberOfMatchesInString:line options:(NSMatchingOptions)0 range:lineRange] > 0);\n\t\tNSUInteger matchCount = isTopicHeaderLine + isTopicFunctionLine + isTopicMethodLine + isTopicPropertyLine;\t// excludes isTopicGenericItemLine, which is a subtype of isTopicHeaderLine\n\t\t\n\t\tif (matchCount > 1)\n\t\t{\n\t\t\tNSLog(@\"*** line matched more than one regex type: %@\", line);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif (matchCount == 0)\n\t\t{\n\t\t\tif ([line length])\n\t\t\t{\n\t\t\t\tif (topicItemAttrString)\n\t\t\t\t{\n\t\t\t\t\t// We have a topic, so this is a content line, to be appended to the current topic item's content\n\t\t\t\t\t[topicItemAttrString replaceCharactersInRange:NSMakeRange([topicItemAttrString length], 0) withString:@\"\\n\"];\n\t\t\t\t\t[topicItemAttrString replaceCharactersInRange:NSMakeRange([topicItemAttrString length], 0) withAttributedString:lineAttrString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSLog(@\"orphan line while reading for top level heading %@\", topLevelHeading);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif ((matchCount == 1) || ((matchCount == 0) && (lineIndex == lineCount - 1)))\n\t\t{\n\t\t\t// This line starts a new header or item or ends the file, so we need to terminate the current item\n\t\t\tif (topicItemAttrString && topicItemKey)\n\t\t\t{\n\t\t\t\t[currentTopicDict setObject:topicItemAttrString forKey:[self guardAgainstNSTaggedPointerString:topicItemKey]];\n\t\t\t\t\n\t\t\t\ttopicItemAttrString= nil;\n\t\t\t\ttopicItemKey = nil;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (isTopicHeaderLine)\n\t\t{\n\t\t\t// We have hit a new topic header.  This might be a subtopic of the current topic, or a sibling, or a sibling of one of our ancestors\n\t\t\tNSTextCheckingResult *match = [topicHeaderRegex firstMatchInString:line options:(NSMatchingOptions)0 range:lineRange];\n\t\t\tNSRange sectionRange = [match rangeAtIndex:1];\n\t\t\tNSString *sectionString = [line substringWithRange:sectionRange];\n\t\t\tNSRange titleRange = [match rangeAtIndex:2];\n\t\t\tNSString *titleString = [line substringWithRange:titleRange];\n\t\t\t\n\t\t\t//NSLog(@\"topic header section %@, title %@, line: %@\", sectionString, titleString, line);\n\t\t\t\n\t\t\tif (isTopicGenericItemLine)\n\t\t\t{\n\t\t\t\t// This line plays two roles: it is both a header (with a period-separated section index at the beginning) and a\n\t\t\t\t// topic item starter like function/method/property lines, with item content following it immediately.  First we\n\t\t\t\t// use the header-line section string to find the right parent section to place it.\n\t\t\t\tcurrentTopicDict = [self parentDictForSection:sectionString currentTopicDicts:topics topDict:topLevelDict];\n\t\t\t\t\n\t\t\t\t// Then we extract the item name and create a new item under the parent dict.\n\t\t\t\tNSTextCheckingResult *itemMatch = [topicGenericItemRegex firstMatchInString:line options:(NSMatchingOptions)0 range:lineRange];\n\t\t\t\tNSRange itemOrderRange = [itemMatch rangeAtIndex:2];\n\t\t\t\tNSString *itemOrder = [line substringWithRange:itemOrderRange];\n\t\t\t\tNSRange itemNameRange = [itemMatch rangeAtIndex:3];\n\t\t\t\tNSString *itemName = [line substringWithRange:itemNameRange];\n\t\t\t\t\n\t\t\t\ttopicItemKey = [itemOrder stringByAppendingString:itemName];\n\t\t\t\ttopicItemAttrString = [[[lineAttrString attributedSubstringFromRange:itemNameRange] mutableCopy] autorelease];\n\t\t\t\t\n\t\t\t\t//NSLog(@\"   parsed topic header item with currentTopicDict %p, itemName %@, itemNameRange %@\", currentTopicDict, itemName, NSStringFromRange(itemNameRange));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This header line is not also an item line, so we want to create a new expandable category and await items\n\t\t\t\tcurrentTopicDict = [self topicDictForSection:sectionString title:titleString currentTopicDicts:topics topDict:topLevelDict];\n\t\t\t}\n\t\t}\n\t\telse if (isTopicFunctionLine)\n\t\t{\n\t\t\t// We have hit a new topic item line.  This will become a key in the current topic dictionary.\n\t\t\tNSTextCheckingResult *match = [topicFunctionRegex firstMatchInString:line options:(NSMatchingOptions)0 range:lineRange];\n\t\t\tNSRange callNameRange = [match rangeAtIndex:1];\n\t\t\tNSString *callName = [line substringWithRange:callNameRange];\n\t\t\t\n\t\t\t//NSLog(@\"topic function name: %@, line: %@\", callName, line);\n\t\t\t\n\t\t\t// Check for a built-in function signature that matches and substitute it in\n\t\t\tif (functionList)\n\t\t\t{\n\t\t\t\tstd::string function_name([callName UTF8String]);\n\t\t\t\tconst EidosFunctionSignature *function_signature = nullptr;\n\t\t\t\t\n\t\t\t\tfor (auto signature_iter = functionList->begin(); signature_iter != functionList->end(); signature_iter++)\n\t\t\t\t\tif ((*signature_iter)->call_name_.compare(function_name) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfunction_signature = signature_iter->get();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (function_signature)\n\t\t\t\t{\n\t\t\t\t\tNSAttributedString *attrSig = [NSAttributedString eidosAttributedStringForCallSignature:function_signature size:11.0];\n\t\t\t\t\tNSString *oldSignatureString = [lineAttrString string];\n\t\t\t\t\tNSString *newSignatureString = [attrSig string];\n\t\t\t\t\t\n\t\t\t\t\tif ([oldSignatureString isEqualToString:newSignatureString])\n\t\t\t\t\t{\n\t\t\t\t\t\t//NSLog(@\"signature match for function %@\", callName);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Replace the signature line from the RTF file with the syntax-colored version\n\t\t\t\t\t\tlineAttrString = attrSig;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tNSLog(@\"*** function signature mismatch:\\nold: %@\\nnew: %@\", oldSignatureString, newSignatureString);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSLog(@\"*** no function signature found for function name %@\", callName);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\ttopicItemKey = [callName stringByAppendingString:@\"()\"];\n\t\t\ttopicItemAttrString = [[[NSMutableAttributedString alloc] initWithAttributedString:lineAttrString] autorelease];\n\t\t}\n\t\telse if (isTopicMethodLine)\n\t\t{\n\t\t\t// We have hit a new topic item line.  This will become a key in the current topic dictionary.\n\t\t\tNSTextCheckingResult *match = [topicMethodRegex firstMatchInString:line options:(NSMatchingOptions)0 range:lineRange];\n\t\t\tNSRange classMethodRange = [match rangeAtIndex:1];\n\t\t\tNSString *classMethodString = [line substringWithRange:classMethodRange];\n\t\t\tNSRange callNameRange = [match rangeAtIndex:2];\n\t\t\tNSString *callName = [line substringWithRange:callNameRange];\n\t\t\t\n\t\t\t//NSLog(@\"topic method name: %@, line: %@\", callName, line);\n\t\t\t\n\t\t\t// Check for a built-in method signature that matches and substitute it in\n\t\t\tif (methodList)\n\t\t\t{\n\t\t\t\tstd::string method_name([callName UTF8String]);\n\t\t\t\tEidosMethodSignature_CSP method_signature = nullptr;\n\t\t\t\t\n\t\t\t\tfor (auto signature_iter = methodList->begin(); signature_iter != methodList->end(); signature_iter++)\n\t\t\t\t\tif ((*signature_iter)->call_name_.compare(method_name) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod_signature = *signature_iter;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (method_signature)\n\t\t\t\t{\n\t\t\t\t\tNSAttributedString *attrSig = [NSAttributedString eidosAttributedStringForCallSignature:method_signature.get() size:11.0];\n\t\t\t\t\tNSString *oldSignatureString = [lineAttrString string];\n\t\t\t\t\tNSString *newSignatureString = [attrSig string];\n\t\t\t\t\t\n\t\t\t\t\tif ([oldSignatureString isEqualToString:newSignatureString])\n\t\t\t\t\t{\n\t\t\t\t\t\t//NSLog(@\"signature match for method %@\", callName);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Replace the signature line from the RTF file with the syntax-colored version\n\t\t\t\t\t\tlineAttrString = attrSig;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// BCH 3 April 2022: I don't think there's any reason why we can't have more than one method with the same name,\n\t\t\t\t\t\t// but with different signatures, as long as they are not in the same class; we can't handle overloading, but\n\t\t\t\t\t\t// method lookup is within-class.  So this code could be generalized as the property lookup code below was; I just\n\t\t\t\t\t\t// haven't bothered to do so.\n\t\t\t\t\t\tNSLog(@\"*** method signature mismatch:\\ndocumentation: %@\\ndeclaration  : %@\", oldSignatureString, newSignatureString);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSLog(@\"*** no method signature found for method name %@\", callName);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\ttopicItemKey = [NSString stringWithFormat:@\"%@\\u00A0%@()\", classMethodString, callName];\n\t\t\ttopicItemAttrString = [[[NSMutableAttributedString alloc] initWithAttributedString:lineAttrString] autorelease];\n\t\t}\n\t\telse if (isTopicPropertyLine)\n\t\t{\n\t\t\t// We have hit a new topic item line.  This will become a key in the current topic dictionary.\n\t\t\tNSTextCheckingResult *match = [topicPropertyRegex firstMatchInString:line options:(NSMatchingOptions)0 range:lineRange];\n\t\t\tNSRange callNameRange = [match rangeAtIndex:1];\n\t\t\tNSString *callName = [line substringWithRange:callNameRange];\n\t\t\tNSRange readOnlyRange = [match rangeAtIndex:2];\n\t\t\tNSString *readOnlyName = [line substringWithRange:readOnlyRange];\n\t\t\t\n\t\t\t//NSLog(@\"topic property name: %@, line: %@\", callName, line);\n\t\t\t\n\t\t\t// Check for a built-in property signature that matches and substitute it in.  Note that we accept a match from any property in any class\n\t\t\t// API as long as the signature matches; we do not rigorously check that the API within a given class matches between signature and doc.\n\t\t\t// This is mostly not a problem because it is quite rare for the same property name to be used with more than one signature.\n\t\t\tif (propertyList)\n\t\t\t{\n\t\t\t\tstd::string property_name([callName UTF8String]);\n\t\t\t\tbool found_match = false, found_mismatch = false;\n\t\t\t\tNSString *oldSignatureString = nullptr;\n\t\t\t\tNSString *newSignatureString = nullptr;\n\t\t\t\t\n\t\t\t\tfor (auto signature_iter = propertyList->begin(); signature_iter != propertyList->end(); signature_iter++)\n\t\t\t\t\tif ((*signature_iter)->property_name_.compare(property_name) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosPropertySignature_CSP candidate_signature = *signature_iter;\n\t\t\t\t\t\tNSAttributedString *attrSig = [NSAttributedString eidosAttributedStringForPropertySignature:candidate_signature.get() size:11.0];\n\t\t\t\t\t\t\n\t\t\t\t\t\toldSignatureString = [lineAttrString string];\n\t\t\t\t\t\tnewSignatureString = [attrSig string];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ([oldSignatureString isEqualToString:newSignatureString])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//NSLog(@\"signature match for method %@\", callName);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Replace the signature line from the RTF file with the syntax-colored version\n\t\t\t\t\t\t\tlineAttrString = attrSig;\n\t\t\t\t\t\t\tfound_match = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If we find a mismatched signature but no matching signature, that's probably an error in either the doc or\n\t\t\t\t\t\t\t// the signature, unless we find a match later on with a different signature for the same property name.\n\t\t\t\t\t\t\tfound_mismatch = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (found_mismatch && !found_match)\n\t\t\t\t\tNSLog(@\"*** property signature mismatch:\\nold: %@\\nnew: %@\", oldSignatureString, newSignatureString);\n\t\t\t\telse if (!found_match)\n\t\t\t\t\tNSLog(@\"*** no property signature found for property name %@\", callName);\n\t\t\t}\n\t\t\t\n\t\t\ttopicItemKey = [NSString stringWithFormat:@\"%@ %@\", callName, readOnlyName];\n\t\t\ttopicItemAttrString = [[[NSMutableAttributedString alloc] initWithAttributedString:lineAttrString] autorelease];\n\t\t}\n\t}\n}\n\n- (void)checkDocumentationOfFunctions:(const std::vector<EidosFunctionSignature_CSP> *)functions\n{\n\tfor (const EidosFunctionSignature_CSP &functionSignature : *functions)\n\t{\n\t\tNSString *functionNameString = [NSString stringWithUTF8String:functionSignature->call_name_.c_str()];\n\t\t\n\t\tif (![functionNameString hasPrefix:@\"_\"])\n\t\t{\n\t\t\tNSString *functionString = [NSString stringWithFormat:@\"%@()\", functionNameString];\n\t\t\tid functionDocumentation = [self findObjectForKeyEqualTo:functionString withinDictionary:[self effectiveTopicRoot]];\n\t\t\t\n\t\t\tif (!functionDocumentation)\n\t\t\t{\n\t\t\t\tNSLog(@\"*** no documentation found for function %@\", functionString);\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)checkDocumentationOfClass:(EidosClass *)classObject\n{\n\tconst EidosClass *superclass = classObject->Superclass();\n\t\n\t// We're hiding DictionaryRetained, so DictionaryRetained subclasses pretend their superclass is Dictionary\n\tif (superclass == gEidosDictionaryRetained_Class)\n\t\tsuperclass = gEidosDictionaryUnretained_Class;\n\t\n\tconst std::string &className = classObject->ClassName();\n\tNSString *classString = [NSString stringWithUTF8String:className.c_str()];\n\tNSString *classKey = [NSString stringWithFormat:@\"Class %@\", classString];\n\tid classDocumentation = [self findObjectWithKeySuffix:classKey withinDictionary:[self effectiveTopicRoot]];\n\t\n\tif ([classDocumentation isKindOfClass:[NSDictionary class]])\n\t{\n\t\tNSDictionary *classDocDict = (NSDictionary *)classDocumentation;\n\t\tint classDocChildCount = (int)[classDocDict count];\n\t\tNSArray *keys = [classDocDict allKeys];\n\t\tNSString *propertiesKey = [NSString stringWithFormat:@\"1. %@ properties\", classString];\n\t\tNSString *methodsKey = [NSString stringWithFormat:@\"2. %@ methods\", classString];\n\t\t\n\t\tif (((classDocChildCount == 2) || (classDocChildCount == 3)) && [keys containsObject:propertiesKey] && [keys containsObject:methodsKey])    // 3 if there is a constructor function, which we don't presently check\n\t\t{\n\t\t\t// Check for complete documentation of all properties defined by the class\n\t\t\t{\n\t\t\t\tNSDictionary *propertyDict = [classDocDict objectForKey:propertiesKey];\n\t\t\t\tNSMutableArray *docProperties = [[propertyDict allKeys] mutableCopy];\n\t\t\t\tconst std::vector<EidosPropertySignature_CSP> *classProperties = classObject->Properties();\n\t\t\t\tconst std::vector<EidosPropertySignature_CSP> *superclassProperties = superclass ? superclass->Properties() : nullptr;\n\t\t\t\t\n\t\t\t\tfor (const EidosPropertySignature_CSP &propertySignature : *classProperties)\n\t\t\t\t{\n\t\t\t\t\tstd::string &&connector_string = propertySignature->PropertySymbol();\n\t\t\t\t\tNSString *connectorString = [NSString stringWithUTF8String:connector_string.c_str()];\t// \"<–>\" or \"=>\"\n\t\t\t\t\tNSString *propertyNameString = [NSString stringWithUTF8String:propertySignature->property_name_.c_str()];\n\t\t\t\t\tNSString *propertyString = [NSString stringWithFormat:@\"%@ %@\", propertyNameString, connectorString];\n\t\t\t\t\tNSUInteger docIndex = [docProperties indexOfObject:propertyString];\n\t\t\t\t\t\n\t\t\t\t\tif (docIndex != NSNotFound)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the property is defined in this class doc, consider it documented\n\t\t\t\t\t\t[docProperties removeObjectAtIndex:docIndex];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the property is not defined in this class doc, then that is an error unless it is a superclass property\n\t\t\t\t\t\tbool isSuperclassProperty = superclassProperties && (std::find(superclassProperties->begin(), superclassProperties->end(), propertySignature) != superclassProperties->end());\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!isSuperclassProperty)\n\t\t\t\t\t\t\tNSLog(@\"*** no documentation found for class %@ property %@\", classString, propertyString);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ([docProperties count])\n\t\t\t\t\tNSLog(@\"*** excess documentation found for class %@ properties %@\", classString, docProperties);\n\t\t\t\t\n\t\t\t\t[docProperties release];\n\t\t\t}\n\t\t\t\n\t\t\t// Check for complete documentation of all methods defined by the class\n\t\t\t{\n\t\t\t\tNSDictionary *methodDict = [classDocDict objectForKey:methodsKey];\n\t\t\t\tNSMutableArray *docMethods = [[methodDict allKeys] mutableCopy];\n\t\t\t\tconst std::vector<EidosMethodSignature_CSP> *classMethods = classObject->Methods();\n\t\t\t\tconst std::vector<EidosMethodSignature_CSP> *superclassMethods = superclass ? superclass->Methods() : nullptr;\n\t\t\t\t\n\t\t\t\tfor (const EidosMethodSignature_CSP &methodSignature : *classMethods)\n\t\t\t\t{\n\t\t\t\t\tNSString *methodNameString = [NSString stringWithUTF8String:methodSignature->call_name_.c_str()];\n\t\t\t\t\t\n\t\t\t\t\tif (![methodNameString hasPrefix:@\"_\"])\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string &&prefix_string = methodSignature->CallPrefix();\n\t\t\t\t\t\tNSString *prefixString = [NSString stringWithUTF8String:prefix_string.c_str()];\t// \"\", \"–\\u00A0\", or \"+\\u00A0\"\n\t\t\t\t\t\tNSString *methodString = [NSString stringWithFormat:@\"%@%@()\", prefixString, methodNameString];\n\t\t\t\t\t\tNSUInteger docIndex = [docMethods indexOfObject:methodString];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (docIndex != NSNotFound)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If the method is defined in this class doc, consider it documented\n\t\t\t\t\t\t\t[docMethods removeObjectAtIndex:docIndex];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If the method is not defined in this class doc, then that is an error unless it is a superclass method\n\t\t\t\t\t\t\tbool isSuperclassMethod = superclassMethods && (std::find(superclassMethods->begin(), superclassMethods->end(), methodSignature) != superclassMethods->end());\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!isSuperclassMethod)\n\t\t\t\t\t\t\t\tNSLog(@\"*** no documentation found for class %@ method %@\", classString, methodString);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ([docMethods count])\n\t\t\t\t\tNSLog(@\"*** excess documentation found for class %@ methods %@\", classString, docMethods);\n\t\t\t\t\n\t\t\t\t[docMethods release];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSLog(@\"*** documentation for class %@ in unexpected format\", classString);\n\t\t}\n\t}\n\telse\n\t{\n\t\tNSLog(@\"*** no documentation found for class %@\", classString);\n\t}\n}\n\n- (void)_gatherKeysWithinDictionary:(NSDictionary *)searchDict intoVector:(std::vector<pointer_t> &)vec\n{\n\t[searchDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {\n\t\tvec.emplace_back((pointer_t)key);\n\t\t\n\t\tif ([obj isKindOfClass:[NSDictionary class]])\n\t\t\t[self _gatherKeysWithinDictionary:obj intoVector:vec];\n\t}];\n}\n\n- (void)checkDocumentationForDuplicatePointers\n{\n\t// The goal here is to check that no two topics in the tree have the same pointer for their key.  This can happen if\n\t// NSStrings are uniqued behind out back, which it turns out Apple actually does now using NSTaggedPointerString; see\n\t// guardAgainstNSTaggedPointerString: above.  We have a workaround for that problem, for now, but need to be vigilant\n\t// in case our workaround breaks, as might happen if Apple makes +[NSString stringWithString:] smart enough to return\n\t// an NSTaggedPointerString back to us.\n\tstd::vector<pointer_t> topic_keys;\n\t\n\t[self _gatherKeysWithinDictionary:[self effectiveTopicRoot] intoVector:topic_keys];\n\t\n\t// Now that we've got all the keys, sort, and then find and print duplicates\n\tstd::sort(topic_keys.begin(), topic_keys.end());\n\t\n\tstd::vector<pointer_t>::iterator topic_iter = topic_keys.begin();\n\t\n\twhile (YES)\n\t{\n\t\ttopic_iter = std::adjacent_find(topic_iter, topic_keys.end());\n\t\t\n\t\tif (topic_iter == topic_keys.end())\n\t\t\tbreak;\n\t\t\n\t\tNSLog(@\"*** duplicate topic keys in help tree: %@ (%@)\", (NSString *)*topic_iter, [(id)(*topic_iter) class]);\n\t\t++topic_iter;\n\t}\n}\n\n- (NSWindow *)window\n{\n\tif (!_helpWindow)\n\t{\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"EidosHelpWindow\" owner:self topLevelObjects:NULL];\n\t\t\n\t\t// Replace the text storage of the description textview with our custom subclass\n\t\t[[_descriptionTextView layoutManager] replaceTextStorage:[[[EidosHelpTextStorage alloc] init] autorelease]];\n\t\t\n\t\t// Fix text container insets to look a bit nicer; {0,0} by default\n\t\t[_descriptionTextView setTextContainerInset:NSMakeSize(0.0, 5.0)];\n\t\t\n\t\t// Fix outline view to expand/collapse with a click anywhere in a topic row\n\t\t[_topicOutlineView setTarget:self];\n\t\t[_topicOutlineView setAction:@selector(outlineViewClicked:)];\n\t}\n\t\n\treturn _helpWindow;\n}\n\n- (void)showWindow\n{\n\t[[self window] makeKeyAndOrderFront:nil];\n}\n\n- (void)outlineViewClicked:(id)sender\n{\n\tNSOutlineView *senderOutlineView = (NSOutlineView *)sender;\n\t\n\tif (senderOutlineView == _topicOutlineView)\n\t{\n\t\tid clickItem = [_topicOutlineView itemAtRow:[_topicOutlineView clickedRow]];\n\t\t\n\t\tif (clickItem)\n\t\t{\n\t\t\tBOOL optionPressed = (([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagOption) == NSEventModifierFlagOption);\n\t\t\t\n\t\t\tif ([_topicOutlineView isItemExpanded:clickItem])\n\t\t\t\t[_topicOutlineView.animator collapseItem:clickItem collapseChildren:optionPressed];\n\t\t\telse\n\t\t\t\t[_topicOutlineView.animator expandItem:clickItem expandChildren:optionPressed];\n\t\t}\n\t}\n}\n\n- (IBAction)searchTypeChanged:(id)sender\n{\n\tNSMenuItem *senderMenuItem = (NSMenuItem *)sender;\n\tint newSearchType = (int)[senderMenuItem tag];\n\t\n\tif (newSearchType != searchType)\n\t{\n\t\tsearchType = newSearchType;\n\t\t\n\t\t[self searchFieldChanged:_searchField];\n\t}\n}\n\n- (BOOL)findItemsUnderRoot:(NSDictionary *)root withKey:(NSString *)rootKey matchingSearchString:(NSString *)searchString titlesOnly:(BOOL)titlesOnly addingToMatchKeys:(NSMutableArray *)matchKeys andItemsToExpand:(NSMutableArray *)expandItems\n{\n\t__block BOOL anyChildMatches = NO;\n\t\n\t[root enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {\n\t\tif ([obj isKindOfClass:[NSDictionary class]])\n\t\t{\n\t\t\t// If the object for the key is a dictionary, the child is an expandable item, so we need to recurse\n\t\t\tBOOL result = [self findItemsUnderRoot:obj withKey:key matchingSearchString:searchString titlesOnly:titlesOnly addingToMatchKeys:matchKeys andItemsToExpand:expandItems];\n\t\t\t\n\t\t\tif (result)\n\t\t\t\tanyChildMatches = YES;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the item is not a dictionary, then the child is a leaf, so we need to test for a match\n\t\t\tBOOL isMatch = NO;\n\t\t\t\n\t\t\tif ([key rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound)\n\t\t\t\tisMatch = YES;\n\t\t\t\n\t\t\tif (!titlesOnly)\n\t\t\t{\n\t\t\t\tif ([obj isKindOfClass:[NSString class]])\n\t\t\t\t{\n\t\t\t\t\tif ([obj rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound)\n\t\t\t\t\t\tisMatch = YES;\n\t\t\t\t}\n\t\t\t\telse if ([obj isKindOfClass:[NSAttributedString class]])\n\t\t\t\t{\n\t\t\t\t\tif ([[obj string] rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound)\n\t\t\t\t\t\tisMatch = YES;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (isMatch)\n\t\t\t{\n\t\t\t\t[matchKeys addObject:key];\n\t\t\t\tanyChildMatches = YES;\n\t\t\t}\n\t\t}\n\t}];\n\t\n\tif (anyChildMatches && rootKey)\n\t\t[expandItems addObject:rootKey];\n\t\n\treturn anyChildMatches;\n}\n\n- (IBAction)searchFieldChanged:(id)sender\n{\n\tNSString *searchString = [_searchField stringValue];\n\t\n\t// Do a depth-first search under the topic root that matches the search pattern, and gather tasks to perform\n\tNSMutableArray *matchKeys = [NSMutableArray array];\n\tNSMutableArray *expandItems = [NSMutableArray array];\n\t\n\t[self findItemsUnderRoot:[self effectiveTopicRoot] withKey:nil matchingSearchString:searchString titlesOnly:(searchType == 0) addingToMatchKeys:matchKeys andItemsToExpand:expandItems];\n\t\n\tif ([matchKeys count])\n\t{\n\t\t// First collapse everything, as an initial state\n\t\t[_topicOutlineView collapseItem:nil collapseChildren:YES];\n\t\t\n\t\t// Expand all nodes that have a search hit; reverse order so parents expand before their children\n\t\t[expandItems enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n\t\t\t[_topicOutlineView expandItem:obj];\n\t\t}];\n\t\t\n\t\t// Select all of the items that matched; rowForItem: only returns the first hit, so we have a custom method that gets all hits\n\t\t[matchKeys enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\n\t\t\t[_topicOutlineView selectRowIndexes:[(EidosHelpOutlineView *)_topicOutlineView eidosRowIndicesForItem:obj] byExtendingSelection:YES];\n\t\t}];\n\t\t\n\t\t// The outline view occasionally seems to mis-update; I think it is an AppKit bug but it's hard to be sure.\n\t\t// In any case, telling it to completely redraw here seems to fix the problem.\n\t\t[_topicOutlineView setNeedsDisplay:YES];\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (void)enterSearchForString:(NSString *)searchString titlesOnly:(BOOL)titlesOnly\n{\n\t// Load our nib if it is not already loaded\n\t[self window];\n\t\n\t// Set the search string per the request\n\t[_searchField setStringValue:searchString];\n\t\n\t// Set the search type per the request\n\tsearchType = titlesOnly ? 0 : 1;\n\t\n\t// Then execute the search by firing the search field's action\n\t[self searchFieldChanged:_searchField];\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL selector = [menuItem action];\n\t\n\tif (selector == @selector(searchTypeChanged:))\n\t{\n\t\tNSInteger tag = [menuItem tag];\n\t\t\n\t\t[menuItem setState:(searchType == tag) ? NSOnState : NSOffState];\n\t\treturn YES;\n\t}\n\t\n\treturn YES;\t// no super\n}\n\n- (id)findObjectWithKeySuffix:(NSString *)searchKeySuffix withinDictionary:(NSDictionary *)searchDict\n{\n\t__block id value = nullptr;\n\t\n\tif (value)\n\t\treturn value;\n\t\n\t[searchDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {\n\t\t// Search by substring matching; we have to be careful to use this method to search only for unique keys\n\t\tif ([key hasSuffix:searchKeySuffix])\n\t\t\tvalue = obj;\n\t\telse if ([obj isKindOfClass:[NSDictionary class]])\n\t\t\tvalue = [self findObjectWithKeySuffix:searchKeySuffix withinDictionary:obj];\n\t\t\n\t\tif (value)\n\t\t\t*stop = YES;\n\t}];\n\t\n\treturn value;\n}\n\n- (id)findObjectForKeyEqualTo:(NSString *)searchKey withinDictionary:(NSDictionary *)searchDict\n{\n\t__block id value = nullptr;\n\t\n\tif (value)\n\t\treturn value;\n\t\n\t[searchDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {\n\t\t// Search using isEqualToString:; we have to be careful to use this method to search only for unique keys\n\t\tif ([key isEqualToString:searchKey])\n\t\t\tvalue = obj;\n\t\telse if ([obj isKindOfClass:[NSDictionary class]])\n\t\t\tvalue = [self findObjectForKeyEqualTo:searchKey withinDictionary:obj];\n\t\t\n\t\tif (value)\n\t\t\t*stop = YES;\n\t}];\n\t\n\treturn value;\n}\n\n- (id)findObjectForKey:(NSString *)searchKey withinDictionary:(NSDictionary *)searchDict\n{\n\t__block id value = nullptr;\n\t\n\tif (value)\n\t\treturn value;\n\t\n\t[searchDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {\n\t\t// Search by pointer equality, not by hash/isEqual:, so that items with identical (but not pointer-equal) keys\n\t\t// can refer to different values in our topic tree; the \"subpopID\" property, for example, has the same name\n\t\t// in both Mutation and Substitution, but has different descriptions.\n\t\tif (key == searchKey)\n\t\t\tvalue = obj;\n\t\telse if ([obj isKindOfClass:[NSDictionary class]])\n\t\t\tvalue = [self findObjectForKey:searchKey withinDictionary:obj];\n\t\t\n\t\tif (value)\n\t\t\t*stop = YES;\n\t}];\n\t\n\treturn value;\n}\n\n- (id)findObjectForKey:(NSString *)searchKey\n{\n\t// The datasource methods below deal in keys; the child returned at a given index is an NSString key.  We often need\n\t// to find the corresponding value for a given key, but this is not simple since we don't have a reference to the\n\t// dictionary that it is a key within.  So we do a depth-first search through our topic tree to find it.  This is\n\t// going to be a bit slow, but the topic tree should be small so it shouldn't matter.  The alternative would be to\n\t// develop a better data structure for storing our topics, rather than using NSDictionary.\n\t\n\t// Start at the topic root\n\tNSDictionary *searchDict = [self effectiveTopicRoot];\n\t\n\t// If the search key is nil, return the searchDict; this makes the searchDict correspond to the root object of the outline view\n\t\tif (!searchKey)\n\t\t\treturn searchDict;\n\t\n\t// Otherwise, search within the searchDict\n\treturn [self findObjectForKey:searchKey withinDictionary:searchDict];\n}\n\n\n//\n//\tNSOutlineView datasource / delegate methods\n//\n#pragma mark NSOutlineView delegate\n\n- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item\n{\n\t// According to our design, outline items are always NSStrings, and we have to look up their values in our topic tree\n\tid itemValue = [self findObjectForKey:item];\n\t\n\tif ([itemValue isKindOfClass:[NSDictionary class]])\n\t\treturn [itemValue count];\n\t\n\treturn 0;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item\n{\n\t// According to our design, outline items are always NSStrings, and we have to look up their values in our topic tree\n\tid itemValue = [self findObjectForKey:item];\n\t\n\tif ([itemValue isKindOfClass:[NSDictionary class]])\n\t\treturn [[[itemValue allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)] objectAtIndex:index];\n\t\n\treturn (id _Nonnull)nil;\t// get rid of the static analyzer warning\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item\n{\n\t// According to our design, outline items are always NSStrings, and we have to look up their values in our topic tree\n\tid itemValue = [self findObjectForKey:item];\n\t\n\tif ([itemValue isKindOfClass:[NSDictionary class]])\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item\n{\n\tif (item)\n\t{\n\t\tstatic NSRegularExpression *sortOrderStripRegex = nullptr;\n\t\tBOOL isString = [item isKindOfClass:[NSString class]];\n\t\tNSString *itemString = isString ? item : [item string];\n\t\t\n\t\tif (!sortOrderStripRegex)\n\t\t\tsortOrderStripRegex = [[NSRegularExpression regularExpressionWithPattern:@\"^(?:[0-9]+\\\\. )(.+)$\" options:NSRegularExpressionCaseInsensitive error:NULL] retain];\n\t\t\n\t\tNSTextCheckingResult *match = [sortOrderStripRegex firstMatchInString:itemString options:(NSMatchingOptions)0 range:NSMakeRange(0, [itemString length])];\n\t\t\n\t\tif (match)\n\t\t{\n\t\t\t// If the item starts with a sort-order prefix, strip it off for display\n\t\t\tNSRange captureRange = [match rangeAtIndex:1];\n\t\t\t\n\t\t\tif (isString)\n\t\t\t\treturn [item substringWithRange:captureRange];\n\t\t\telse\n\t\t\t\treturn [item attributedSubstringFromRange:captureRange];\n\t\t}\n\t\t\n\t\treturn item;\n\t}\n\t\n\treturn @\"\";\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item\n{\n\t// We want items under the true topic root to look like groups; if we have collapsed the top level, we have no group items\n\tif ([topicRoot objectForKey:item])\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item\n{\n\treturn ![self outlineView:outlineView isItemExpandable:item];\n}\n\n- (void)lockClipView:(id)sender\n{\n\t// See comment in setDescription: below\n\tNSView *superview = [_descriptionTextView superview];\n\t\n\tif ([superview isKindOfClass:[EidosLockingClipView class]])\n\t\t[(EidosLockingClipView *)superview setEidosScrollingLocked:YES];\n}\n\n- (void)unlockClipView:(id)sender\n{\n\t// See comment in setDescription: below\n\tNSView *superview = [_descriptionTextView superview];\n\t\n\tif ([superview isKindOfClass:[EidosLockingClipView class]])\n\t\t[(EidosLockingClipView *)superview setEidosScrollingLocked:NO];\n}\n\n- (void)setDescription:(NSAttributedString *)newDescription\n{\n\tNSTextStorage *ts = [_descriptionTextView textStorage];\n\t\n\t[ts beginEditing];\n\t[ts setAttributedString:newDescription];\n\t[ts endEditing];\n\t\n\t// scroll to where we actually want to be and then lock it down\n\t[_descriptionTextView scrollPoint:NSZeroPoint];\n\t[self lockClipView:nil];\n\t\n\t// NSTextView will scroll the content down just slightly, annoyingly, if the content is too long to fit in the view;\n\t// to prevent this, we have to subclass NSClipView, as far as I can tell (forcing layout here does not work because\n\t// more work is still done by background layout later that moves the scroll point, and doing a delayed perform to\n\t// fix the scroll position is both unreliable and causes a visible jump).  Ugh.\n\t[self performSelector:@selector(unlockClipView:) withObject:nil afterDelay:0.1];\n}\n\n- (void)outlineViewSelectionDidChange:(NSNotification *)notification\n{\n\tNSOutlineView *outlineView = [notification object];\n\t\n\tif (outlineView == _topicOutlineView)\n\t{\n\t\tNSIndexSet *selectedIndices = [_topicOutlineView selectedRowIndexes];\n\t\tNSUInteger indexCount = [selectedIndices count];\n\t\t\n\t\tif (indexCount == 0)\n\t\t{\n\t\t\t// Empty selection, so clear the description textview\n\t\t\t[_descriptionTextView setString:@\"\"];\n\t\t}\n\t\telse if (indexCount == 1)\n\t\t{\n\t\t\t// Single-topic selection, so show the topic's description\n\t\t\tNSString *selectedKey = [_topicOutlineView itemAtRow:[selectedIndices firstIndex]];\n\t\t\tid selectedValue = [self findObjectForKey:selectedKey];\n\t\t\t\n\t\t\tif ([selectedValue isKindOfClass:[NSString class]])\n\t\t\t{\n\t\t\t\t[_descriptionTextView setString:selectedValue];\n\t\t\t}\n\t\t\telse if ([selectedValue isKindOfClass:[NSAttributedString class]])\n\t\t\t{\n\t\t\t\t[self setDescription:(NSAttributedString *)selectedValue];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Multiple items are selected, so we want to put together an attributed string that shows them all, with dividers\n\t\t\t__block NSMutableAttributedString *conglomerate = [[[NSMutableAttributedString alloc] initWithString:@\"\"] autorelease];\n\t\t\t__block BOOL firstIndex = YES;\n\t\t\t\n\t\t\t[selectedIndices enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {\n\t\t\t\tNSString *selectedKey = [_topicOutlineView itemAtRow:idx];\n\t\t\t\tid selectedValue = [self findObjectForKey:selectedKey];\n\t\t\t\t\n\t\t\t\tif ([selectedValue isKindOfClass:[NSAttributedString class]])\n\t\t\t\t{\n\t\t\t\t\tif (!firstIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\tNSTextAttachment *attachment = [[[NSTextAttachment alloc] init] autorelease];\n\t\t\t\t\t\tEidosDividerTextAttachmentCell *dividerCell = [[[EidosDividerTextAttachmentCell alloc] init] autorelease];\n\t\t\t\t\t\t\n\t\t\t\t\t\t[attachment setAttachmentCell:dividerCell];\n\t\t\t\t\t\t\n\t\t\t\t\t\tNSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];\n\t\t\t\t\t\t\n\t\t\t\t\t\t[conglomerate replaceCharactersInRange:NSMakeRange([conglomerate length], 0) withString:@\"\\n\"];\n\t\t\t\t\t\t[conglomerate replaceCharactersInRange:NSMakeRange([conglomerate length], 0) withAttributedString:attachmentString];\n\t\t\t\t\t\t[conglomerate replaceCharactersInRange:NSMakeRange([conglomerate length], 0) withString:@\"\\n\"];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfirstIndex = NO;\n\t\t\t\t\t\n\t\t\t\t\t[conglomerate replaceCharactersInRange:NSMakeRange([conglomerate length], 0) withAttributedString:selectedValue];\n\t\t\t\t}\n\t\t\t}];\n\t\t\t\n\t\t\t[self setDescription:conglomerate];\n\t\t}\n\t}\n}\n\n@end\n\n\n//\n//\tEidosHelpOutlineView\n//\n#pragma mark -\n#pragma mark EidosHelpOutlineView\n\n@implementation EidosHelpOutlineView\n\n- (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect\n{\n\t[super drawRow:rowIndex clipRect:clipRect];\n\t\n\tNSRect rowRect = [self rectOfRow:rowIndex];\n\tid item = [self itemAtRow:rowIndex];\n\tid delegate = [self delegate];\n\t\n\t// We want to colorize group rows green if they are from the Eidos doc, blue otherwise (Context doc)\n\tif ([delegate outlineView:self isGroupItem:item])\n\t{\n\t\tif (item && ([item rangeOfString:@\"Eidos\"].location != NSNotFound))\t// BCH 4/7/2016: containsString: added in 10.10\n\t\t{\n\t\t\t[[NSColor colorWithCalibratedRed:0 green:1.0 blue:0 alpha:0.04] set];\n\t\t\tNSRectFillUsingOperation(rowRect, NSCompositingOperationSourceOver);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[[NSColor colorWithCalibratedRed:0 green:0 blue:1.0 alpha:0.04] set];\n\t\t\tNSRectFillUsingOperation(rowRect, NSCompositingOperationSourceOver);\n\t\t}\n\t}\n\t\n\t// Add little colored boxes to the WF-only and nonWF-only API; this is pretty inefficient, but we\n\t// don't have very many strings to check so it should be fine, and is simpler than the alternatives...\n\tBOOL draw_WF_box = NO, draw_nonWF_box = NO, draw_nucmut_box = NO;\n\tstatic NSArray *stringsWF = nullptr;\n\tstatic NSArray *stringsNonWF = nullptr;\n\tstatic NSArray *stringsNucmut = nullptr;\n\t\n\tif (!stringsWF)\n\t\tstringsWF = [@[@\"–\\u00A0addSubpopSplit()\",\n\t\t\t\t\t   @\"–\\u00A0registerMateChoiceCallback()\",\n\t\t\t\t\t   @\"cloningRate =>\",\n\t\t\t\t\t   @\"immigrantSubpopFractions =>\",\n\t\t\t\t\t   @\"immigrantSubpopIDs =>\",\n\t\t\t\t\t   @\"selfingRate =>\",\n\t\t\t\t\t   @\"sexRatio =>\",\n\t\t\t\t\t   @\"–\\u00A0setCloningRate()\",\n\t\t\t\t\t   @\"–\\u00A0setMigrationRates()\",\n\t\t\t\t\t   @\"–\\u00A0setSelfingRate()\",\n\t\t\t\t\t   @\"–\\u00A0setSexRatio()\",\n\t\t\t\t\t   @\"–\\u00A0setSubpopulationSize()\",\n\t\t\t\t\t   @\"4. mateChoice() callbacks\"\n\t\t\t\t\t   ] retain];\n\t\n\tif (!stringsNonWF)\n\t\tstringsNonWF = [@[@\"initializeSLiMModelType()\",\n\t\t\t\t\t\t  @\"age =>\",\n\t\t\t\t\t\t  @\"modelType =>\",\n\t\t\t\t\t\t  @\"–\\u00A0registerReproductionCallback()\",\n\t\t\t\t\t\t  @\"–\\u00A0registerSurvivalCallback()\",\n\t\t\t\t\t\t  @\"–\\u00A0addCloned()\",\n\t\t\t\t\t\t  @\"–\\u00A0addCrossed()\",\n\t\t\t\t\t\t  @\"–\\u00A0addEmpty()\",\n\t\t\t\t\t\t  @\"–\\u00A0addMultiRecombinant()\",\n\t\t\t\t\t\t  @\"–\\u00A0addRecombinant()\",\n\t\t\t\t\t\t  @\"–\\u00A0addSelfed()\",\n\t\t\t\t\t\t  @\"–\\u00A0removeSubpopulation()\",\n\t\t\t\t\t\t  @\"–\\u00A0killIndividuals()\",\n\t\t\t\t\t\t  @\"–\\u00A0takeMigrants()\",\n\t\t\t\t\t\t  @\"8. reproduction() callbacks\",\n\t\t\t\t\t\t  @\"10. survival() callbacks\"\n\t\t\t\t\t\t  ] retain];\n\t\n\tif (!stringsNucmut)\n\t\tstringsNucmut = [@[@\"initializeAncestralNucleotides()\",\n\t\t\t\t\t\t   @\"initializeMutationTypeNuc()\",\n\t\t\t\t\t\t   @\"initializeHotspotMap()\",\n\t\t\t\t\t\t   @\"codonsToAminoAcids()\",\n\t\t\t\t\t\t   @\"randomNucleotides()\",\n\t\t\t\t\t\t   @\"mm16To256()\",\n\t\t\t\t\t\t   @\"mmJukesCantor()\",\n\t\t\t\t\t\t   @\"mmKimura()\",\n\t\t\t\t\t\t   @\"nucleotideCounts()\",\n\t\t\t\t\t\t   @\"nucleotideFrequencies()\",\n\t\t\t\t\t\t   @\"nucleotidesToCodons()\",\n\t\t\t\t\t\t   @\"codonsToNucleotides()\",\n\t\t\t\t\t\t   @\"nucleotideBased =>\",\n\t\t\t\t\t\t   @\"nucleotide <–>\",\n\t\t\t\t\t\t   @\"nucleotideValue <–>\",\n\t\t\t\t\t\t   @\"nucleotide =>\",\n\t\t\t\t\t\t   @\"nucleotideValue =>\",\n\t\t\t\t\t\t   @\"mutationMatrix =>\",\n\t\t\t\t\t\t   @\"–\\u00A0setMutationMatrix()\",\n\t\t\t\t\t\t   @\"–\\u00A0ancestralNucleotides()\",\n\t\t\t\t\t\t   @\"–\\u00A0setAncestralNucleotides()\",\n\t\t\t\t\t\t   @\"–\\u00A0nucleotides()\",\n\t\t\t\t\t\t   @\"hotspotEndPositions =>\",\n\t\t\t\t\t\t   @\"hotspotEndPositionsF =>\",\n\t\t\t\t\t\t   @\"hotspotEndPositionsM =>\",\n\t\t\t\t\t\t   @\"hotspotMultipliers =>\",\n\t\t\t\t\t\t   @\"hotspotMultipliersF =>\",\n\t\t\t\t\t\t   @\"hotspotMultipliersM =>\",\n\t\t\t\t\t\t   @\"–\\u00A0setHotspotMap()\"\n\t\t\t\t\t\t   ] retain];\n\t\n\tif ([stringsWF containsObject:item])\n\t\tdraw_WF_box = YES;\n\tif ([stringsNonWF containsObject:item])\n\t\tdraw_nonWF_box = YES;\n\tif ([stringsNucmut containsObject:item])\n\t\tdraw_nucmut_box = YES;\n\t\n\tif (draw_WF_box || draw_nonWF_box || draw_nucmut_box)\n\t{\n\t\tNSRect boxRect = NSMakeRect(NSMaxX(rowRect) - 13, rowRect.origin.y + 6, 8, 8);\n\t\t\n\t\tif (draw_WF_box)\n\t\t\t[[NSColor colorWithCalibratedRed:66/255.0 green:255/255.0 blue:53/255.0 alpha:1.0] set];\t// WF-only color (green)\n\t\telse if (draw_nonWF_box)\n\t\t\t[[NSColor colorWithCalibratedRed:88/255.0 green:148/255.0 blue:255/255.0 alpha:1.0] set];\t// nonWF-only color (blue)\n\t\telse //if (draw_nucmut_box)\n\t\t\t[[NSColor colorWithCalibratedRed:228/255.0 green:118/255.0 blue:255/255.0 alpha:1.0] set];\t// nucmut color (purple)\n\t\t\n\t\tNSRectFill(boxRect);\n\t\t[[NSColor blackColor] set];\n\t\tNSFrameRect(boxRect);\n\t}\n}\n\t\n- (NSIndexSet *)eidosRowIndicesForItem:(id)item\n{\n\tNSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];\n\tNSInteger rowCount = [self numberOfRows];\n\t\n\tfor (NSInteger rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n\t{\n\t\tid rowItem = [self itemAtRow:rowIndex];\n\t\t\n\t\tif ([item isEqual:rowItem])\n\t\t[indexSet addIndex:rowIndex];\n\t}\n\t\n\treturn indexSet;\n}\n\n@end\n\n\n//\n//\tEidosHelpTextStorage\n//\n#pragma mark -\n#pragma mark EidosHelpTextStorage\n\n@interface EidosHelpTextStorage ()\n{\n\tNSMutableAttributedString *contents;\n}\n@end\n\n@implementation EidosHelpTextStorage\n\n- (id)initWithAttributedString:(NSAttributedString *)attrStr\n{\n\tif (self = [super init])\n\t{\n\t\tcontents = attrStr ? [attrStr mutableCopy] : [[NSMutableAttributedString alloc] init];\n\t}\n\treturn self;\n}\n\n- init\n{\n\treturn [self initWithAttributedString:nil];\n}\n\n- (void)dealloc\n{\n\t[contents release];\n\t[super dealloc];\n}\n\n// The next set of methods are the primitives for attributed and mutable attributed string...\n\n- (NSString *)string\n{\n\treturn [contents string];\n}\n\n- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRange *)range\n{\n\treturn [contents attributesAtIndex:location effectiveRange:range];\n}\n\n- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str\n{\n\tNSUInteger origLen = [self length];\n\t[contents replaceCharactersInRange:range withString:str];\n\t[self edited:NSTextStorageEditedCharacters range:range changeInLength:[self length] - origLen];\n}\n\n- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range\n{\n\t[contents setAttributes:attrs range:range];\n\t[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];\n}\n\n// And now the actual reason for this subclass: to provide code-aware line break points\n\n- (NSUInteger)lineBreakBeforeIndex:(NSUInteger)index withinRange:(NSRange)aRange\n{\n\tNSUInteger breakpoint = [super lineBreakBeforeIndex:index withinRange:aRange];\n\tNSString *string = [self string];\n\t\n\t// until we hit the beginning of the string, demand earlier breakpoints if the breakpoint we're given splits in the middle of a type identifier\n\twhile ((breakpoint != NSNotFound) && (breakpoint > aRange.location) && (breakpoint < aRange.location + aRange.length))\n\t{\n\t\tunichar uch1 = [string characterAtIndex:breakpoint - 1];\n\t\tunichar uch2 = [string characterAtIndex:breakpoint];\n\t\t\n\t\tif (uch1 != ' ')\n\t\t{\n\t\t\tstatic BOOL beenHere = NO;\n\t\t\tstatic unichar nbs = 'x';\n\t\t\t\n\t\t\tif (!beenHere)\n\t\t\t{\n\t\t\t\tbeenHere = YES;\n\t\t\t\tnbs = [@\"\\u00A0\" characterAtIndex:0];\t\t// \"\\u00A0\" is a non-breaking space\n\t\t\t}\n\t\t\t\n\t\t\tif ((uch2 == '$') || (uch2 == nbs))\n\t\t\t{\n\t\t\t\tbreakpoint = [super lineBreakBeforeIndex:breakpoint withinRange:aRange];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\tbreak;\n\t}\n\t\n\t// if we failed to find a breakpoint, allow breaking after a non-breaking space; this is better than forcing a mid-word break\n\tif (((breakpoint == NSNotFound) || (breakpoint == aRange.location)) && (index > aRange.location))\n\t{\n\t\tNSRange nbsSearchRange;\n\t\t\n\t\tif (index - aRange.location < aRange.length)\n\t\t\tnbsSearchRange = NSMakeRange(aRange.location, index - aRange.location);\t// don't include index\n\t\telse\n\t\t\tnbsSearchRange = NSMakeRange(aRange.location, aRange.length - 1);\t\t// don't include last character\n\t\t\n\t\t// break after a non-breaking space if necessary, but not right at the start; avoid \"- (\"\n\t\tNSRange nbsRange = [string rangeOfString:@\"\\u00A0\" options:(NSStringCompareOptions)(NSLiteralSearch | NSBackwardsSearch) range:nbsSearchRange];\n\t\t\n\t\tif ((nbsRange.location != NSNotFound) && (nbsRange.location > aRange.location + 2))\n\t\t\tbreakpoint = nbsRange.location + 1;\n\t\telse\n\t\t{\n\t\t\t// If that didn't work, break after an opening parenthesis if necessary, but not right at the start; avoid \"- (\"\n\t\t\tnbsRange = [string rangeOfString:@\"(\" options:(NSStringCompareOptions)(NSLiteralSearch | NSBackwardsSearch) range:nbsSearchRange];\n\t\t\t\n\t\t\tif ((nbsRange.location != NSNotFound) && (nbsRange.location > aRange.location + 3))\n\t\t\t\tbreakpoint = nbsRange.location + 1;\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If that didn't work, break after a closing parenthesis if necessary\n\t\t\t\tnbsRange = [string rangeOfString:@\")\" options:(NSStringCompareOptions)(NSLiteralSearch | NSBackwardsSearch) range:nbsSearchRange];\n\t\t\t\t\n\t\t\t\tif ((nbsRange.location != NSNotFound) && (nbsRange.location != aRange.location))\n\t\t\t\t\tbreakpoint = nbsRange.location + 1;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn breakpoint;\n}\n\n@end\n\n\n//\n//\tEidosDividerTextAttachmentCell\n//\n#pragma mark -\n#pragma mark EidosDividerTextAttachmentCell\n\n@interface EidosDividerTextAttachmentCell ()\n@end\n\n@implementation EidosDividerTextAttachmentCell\n\n- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView\n{\n\tconst CGFloat widthFraction = 0.85;\n\tconst CGFloat spaceFraction = 1.0 - widthFraction;\n\tCGFloat cellLeft = cellFrame.origin.x;\n\tCGFloat cellRight = cellFrame.origin.x + cellFrame.size.width;\n\tCGFloat weightedLeft = round(cellLeft * widthFraction + cellRight * spaceFraction);\n\tCGFloat weightedRight = round(cellLeft * spaceFraction + cellRight * widthFraction);\n\tCGFloat middleHeight = round(cellFrame.origin.y + cellFrame.size.height * 0.5 + 1.0);\n\tNSRect dividerRect = NSMakeRect(weightedLeft, middleHeight, weightedRight - weightedLeft, 2);\n\t\n\t[[NSColor colorWithCalibratedWhite:0.4 alpha:1.0] set];\n\tNSRectFill(dividerRect);\n\t\n\t[[NSColor colorWithCalibratedWhite:0.7 alpha:1.0] set];\n\tNSRectFill(NSMakeRect(dividerRect.origin.x + 1, dividerRect.origin.y + 1, dividerRect.size.width - 1, 1));\n}\n\n- (void)highlight:(BOOL)flag withFrame:(NSRect)cellFrame inView:(NSView *)controlView\n{\n\t[self drawWithFrame:cellFrame inView:controlView];\n}\n\n- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(NSRect)lineFrag glyphPosition:(NSPoint)position characterIndex:(NSUInteger)charIndex\n{\n\t// the -10.0 appears to be necessary because the text container inset is not subtracted out of the lineFrag rect; is this an AppKit bug?\n\treturn NSMakeRect(0, 0, lineFrag.size.width - 10.0, lineFrag.size.height);\n}\n\n- (BOOL)wantsToTrackMouse\n{\n\treturn NO;\n}\n\n@end\n\n\n//\n//\tEidosLockingClipView\n//\n#pragma mark -\n#pragma mark EidosLockingClipView\n\n@implementation EidosLockingClipView\n\n- (NSRect)constrainBoundsRect:(NSRect)proposedBounds\n{\n\tNSRect modifiedBounds = [super constrainBoundsRect:proposedBounds];\n\t\n\tif (_eidosScrollingLocked)\n\t\tmodifiedBounds.origin.y = 0.0;\n\t\n\t//NSLog(@\"proposedBounds == %@, modifiedBounds == %@, locking is %@\", NSStringFromRect(proposedBounds), NSStringFromRect(modifiedBounds), _eidosScrollingLocked ? @\"ON\" : @\"OFF\");\n\t\n\treturn modifiedBounds;\n}\n\n@end\n\n\n//\n//\tEidosNSString\n//\n#pragma mark -\n#pragma mark EidosNSString\n\n@implementation EidosNSString\n+ (NSString *)stringWithString:(NSString *)aString\n{\n\treturn [[[EidosNSString alloc] initWithString:aString] autorelease];\n}\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\tinternal_string_ = [[NSString alloc] init];\n\t}\n\t\n\treturn self;\n}\n- (instancetype)initWithString:(NSString *)aString\n{\n\tif (self = [super init])\n\t{\n\t\tinternal_string_ = [[NSString alloc] initWithString:aString];\n\t}\n\t\n\treturn self;\n}\n- (void)dealloc\n{\n\tif (internal_string_)\n\t{\n\t\t[internal_string_ release];\n\t\tinternal_string_ = nil;\n\t}\n\t\n\t[super dealloc];\n}\n- (NSUInteger)length\n{\n\treturn [internal_string_ length];\n}\n- (unichar)characterAtIndex:(NSUInteger)index\n{\n\treturn [internal_string_ characterAtIndex:index];\n}\n- (void)getCharacters:(unichar *)buffer range:(NSRange)range\n{\n\t[internal_string_ getCharacters:buffer range:range];\n}\n- (id)copyWithZone:(nullable NSZone *)zone\n{\n\tNSString *copiedString = [internal_string_ copyWithZone:zone];\n\tEidosNSString *copy = [EidosNSString stringWithString:copiedString];\n\t[copiedString release];\n\treturn [copy retain];\n}\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosHelpFunctions.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Bold;\\f1\\fnil\\fcharset0 Menlo-Regular;\\f2\\froman\\fcharset0 TimesNewRomanPSMT;\n\\f3\\fswiss\\fcharset0 Optima-Regular;\\f4\\fswiss\\fcharset0 Optima-BoldItalic;\\f5\\fnil\\fcharset0 Menlo-Italic;\n\\f6\\fnil\\fcharset0 AppleSymbols;\\f7\\fswiss\\fcharset0 Optima-Italic;\\f8\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;\n\\f9\\fnil\\fcharset0 Menlo-Bold;\\f10\\fswiss\\fcharset0 Helvetica-Oblique;\\f11\\fswiss\\fcharset0 Helvetica;\n\\f12\\ftech\\fcharset77 Symbol;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;\\red0\\green0\\blue255;\\red213\\green0\\blue5;\n\\red150\\green150\\blue150;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;\\cssrgb\\c0\\c0\\c100000;\\cssrgb\\c87536\\c0\\c0;\n\\cssrgb\\c65500\\c65500\\c65500;}\n{\\*\\listtable{\\list\\listtemplateid1\\listhybrid{\\listlevel\\levelnfc23\\levelnfcn23\\leveljc0\\leveljcn0\\levelfollow0\\levelstartat1\\levelspace360\\levelindent0{\\*\\levelmarker \\{disc\\}}{\\leveltext\\leveltemplateid1\\'01\\uc0\\u8226 ;}{\\levelnumbers;}\\fi-360\\li720\\lin720 }{\\listname ;}\\listid1}\n{\\list\\listtemplateid2\\listhybrid{\\listlevel\\levelnfc23\\levelnfcn23\\leveljc0\\leveljcn0\\levelfollow0\\levelstartat1\\levelspace360\\levelindent0{\\*\\levelmarker \\{disc\\}}{\\leveltext\\leveltemplateid101\\'01\\uc0\\u8226 ;}{\\levelnumbers;}\\fi-360\\li720\\lin720 }{\\listname ;}\\listid2}\n{\\list\\listtemplateid3\\listhybrid{\\listlevel\\levelnfc23\\levelnfcn23\\leveljc0\\leveljcn0\\levelfollow0\\levelstartat1\\levelspace360\\levelindent0{\\*\\levelmarker \\{disc\\}}{\\leveltext\\leveltemplateid201\\'01\\uc0\\u8226 ;}{\\levelnumbers;}\\fi-360\\li720\\lin720 }{\\listname ;}\\listid3}}\n{\\*\\listoverridetable{\\listoverride\\listid1\\listoverridecount0\\ls1}{\\listoverride\\listid2\\listoverridecount0\\ls2}{\\listoverride\\listid3\\listoverridecount0\\ls3}}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab397\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.1.  Math functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (numeric)abs(numeric\n\\f2 \\'a0\n\\f1 x)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b absolute value\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 integer\n\\f3\\fs20 , the C++ function \n\\f1\\fs18 llabs()\n\\f3\\fs20  is used and an \n\\f1\\fs18 integer\n\\f3\\fs20  vector is returned; if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 float\n\\f3\\fs20 , the C++ function \n\\f1\\fs18 fabs()\n\\f3\\fs20  is used and a \n\\f1\\fs18 float\n\\f3\\fs20  vector is returned.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)acos(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b arc cosine\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 acos()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)asin(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b arc sine\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 asin()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)atan(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b arc tangent\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 atan()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)atan2(numeric\n\\f2 \\'a0\n\\f1 x, numeric\n\\f2 \\'a0\n\\f1 y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b arc tangent\n\\f3\\b0  of \n\\f1\\fs18 y/x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 atan2()\n\\f3\\fs20 , which uses the signs of both x and y to determine the correct quadrant for the result.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)ceil(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b ceiling\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the smallest integral value greater than or equal to \n\\f1\\fs18 x\n\\f3\\fs20 .  Note that the return value is \n\\f1\\fs18 float\n\\f3\\fs20  even though integral values are guaranteed, because values could be outside of the range representable by \n\\f1\\fs18 integer\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)cos(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b cosine\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 cos()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric)cumProduct(numeric\n\\f2 \\'a0\n\\f1 x)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b cumulative product\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a vector of equal length as \n\\f1\\fs18 x\n\\f3\\fs20 , in which the element at index \n\\f1\\fs18 i\n\\f3\\fs20  is equal to the product of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  across the range \n\\f1\\fs18 0:i\n\\f2\\fs20 .\n\\f3   The return type will match the type of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 integer\n\\f3\\fs20 , but all of the values of the cumulative product vector cannot be represented in that type, an error condition will result.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric)cumSum(numeric\n\\f2 \\'a0\n\\f1 x)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b cumulative sum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a vector of equal length as \n\\f1\\fs18 x\n\\f3\\fs20 , in which the element at index \n\\f1\\fs18 i\n\\f3\\fs20  is equal to the sum of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  across the range \n\\f1\\fs18 0:i\n\\f2\\fs20 .\n\\f3   The return type will match the type of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 integer\n\\f3\\fs20 , but all of the values of the cumulative sum vector cannot be represented in that type, an error condition will result.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)exp(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b base-\n\\f4\\i e\n\\f0\\i0  exponential\n\\f3\\b0  of \n\\f1\\fs18 x, \n\\f5\\i e\n\\f1\\i0 \\super x\n\\f3\\fs20 \\nosupersub ,  using the C++ function \n\\f1\\fs18 exp()\n\\f2\\fs20 .\n\\f3   This may be somewhat faster than \n\\f1\\fs18 E^x\n\\f3\\fs20  for large vectors.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)floor(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b floor\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the largest integral value less than or equal to \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   Note that the return value is \n\\f1\\fs18 float\n\\f3\\fs20  even though integral values are guaranteed, because values could be outside of the range representable by \n\\f1\\fs18 integer\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)integerDiv(integer\\'a0x, integer\\'a0y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the result of \n\\f0\\b integer division\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  by \n\\f1\\fs18 y\n\\f3\\fs20 .  The \n\\f1\\fs18 /\n\\f3\\fs20  operator in Eidos always produces a \n\\f1\\fs18 float\n\\f3\\fs20  result; if you want an \n\\f1\\fs18 integer\n\\f3\\fs20  result you may use this function instead.  If any value of \n\\f1\\fs18 y\n\\f3\\fs20  is \n\\f1\\fs18 0\n\\f3\\fs20 , an error will result.  The parameters \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must either be of equal length, or one of the two must be a singleton.  The precise behavior of \n\\f1\\fs18 integer\n\\f3\\fs20  division, in terms of how rounding and negative values are handled, may be platform dependent; it will be whatever the C++ behavior of \n\\f1\\fs18 integer\n\\f3\\fs20  division is on the given platform.  Eidos does not guarantee any particular behavior, so use this function with caution.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)integerMod(integer\\'a0x\n\\f2 ,\n\\f1  integer\\'a0y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the result of \n\\f0\\b integer modulo\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  by \n\\f1\\fs18 y\n\\f3\\fs20 .  The \n\\f1\\fs18 %\n\\f3\\fs20  operator in Eidos always produces a \n\\f1\\fs18 float\n\\f3\\fs20  result; if you want an \n\\f1\\fs18 integer\n\\f3\\fs20  result you may use this function instead.  If any value of \n\\f1\\fs18 y\n\\f3\\fs20  is \n\\f1\\fs18 0\n\\f3\\fs20 , an error will result.  The parameters \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must either be of equal length, or one of the two must be a singleton.  The precise behavior of \n\\f1\\fs18 integer\n\\f3\\fs20  modulo, in terms of how rounding and negative values are handled, may be platform dependent; it will be whatever the C++ behavior of \n\\f1\\fs18 integer\n\\f3\\fs20  modulo is on the given platform.  Eidos does not guarantee any particular behavior, so use this function with caution.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)isFinite(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b finiteness\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  is not \n\\f1\\fs18 INF\n\\f3\\fs20  or \n\\f1\\fs18 NAN\n\\f3\\fs20 , \n\\f1\\fs18 F\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 INF\n\\f3\\fs20  or \n\\f1\\fs18 NAN\n\\f2\\fs20 .\n\\f3   \n\\f1\\fs18 INF\n\\f3\\fs20  and \n\\f1\\fs18 NAN\n\\f3\\fs20  are defined only for type \n\\f1\\fs18 float\n\\f3\\fs20 , so x is required to be a \n\\f1\\fs18 float\n\\f2\\fs20 .\n\\f3   Note that \n\\f1\\fs18 isFinite()\n\\f3\\fs20  is not the opposite of \n\\f1\\fs18 isInfinite()\n\\f3\\fs20 , because \n\\f1\\fs18 NAN\n\\f3\\fs20  is considered to be neither finite nor infinite.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)isInfinite(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b infiniteness\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 INF\n\\f3\\fs20 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.  \n\\f1\\fs18 INF\n\\f3\\fs20  is defined only for type \n\\f1\\fs18 float\n\\f3\\fs20 , so x is required to be a \n\\f1\\fs18 float\n\\f3\\fs20 .  Note that \n\\f1\\fs18 isInfinite()\n\\f3\\fs20  is not the opposite of \n\\f1\\fs18 isFinite()\n\\f3\\fs20 , because \n\\f1\\fs18 NAN\n\\f3\\fs20  is considered to be neither finite nor infinite.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)isNAN(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b undefinedness\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  is not \n\\f1\\fs18 NAN\n\\f3\\fs20 , \n\\f1\\fs18 F\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 NAN\n\\f2\\fs20 .\n\\f3   \n\\f1\\fs18 NAN\n\\f3\\fs20  is defined only for type \n\\f1\\fs18 float\n\\f3\\fs20 , so x is required to be a \n\\f1\\fs18 float\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)log(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b base-\n\\f4\\i e\n\\f0\\i0  logarithm\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 log()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)log10(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b base-10 logarithm\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 log10()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)log2(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b base-2 logarithm\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 log2()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric$)product(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b product\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the result of multiplying all of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  together.  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 float\n\\f3\\fs20 , the result will be \n\\f1\\fs18 float\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 integer\n\\f3\\fs20 , things are a bit more complex; the result will be \n\\f1\\fs18 integer\n\\f3\\fs20  if it can fit into the \n\\f1\\fs18 integer\n\\f3\\fs20  type without overflow issues (including during intermediate stages of the computation), otherwise it will be \n\\f1\\fs18 float\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)round(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b round\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the integral value nearest to \n\\f1\\fs18 x\n\\f3\\fs20 , rounding half-way cases away from \n\\f1\\fs18 0\n\\f3\\fs20  (different from the rounding policy of R, which rounds halfway cases toward the nearest even number).  Note that the return value is \n\\f1\\fs18 float\n\\f3\\fs20  even though integral values are guaranteed, because values could be outside of the range representable by \n\\f1\\fs18 integer\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)setDifference(*\n\\f2 \\'a0\n\\f1 x, *\n\\f2 \\'a0\n\\f1 y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b set-theoretic (asymmetric) difference\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , denoted \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f6 \\uc0\\u8726 \n\\f3  \n\\f1\\fs18 y\n\\f3\\fs20 : a vector containing all elements that are in \n\\f1\\fs18 x\n\\f3\\fs20  but are not in \n\\f1\\fs18 y\n\\f3\\fs20 .  Duplicate elements will be stripped out, in the same manner as the \n\\f1\\fs18 unique()\n\\f3\\fs20  function.  The order of elements in the returned vector is arbitrary and should not be relied upon.  The returned vector will be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f2\\fs20 ,\n\\f3  and \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be of the same type.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)setIntersection(*\n\\f2 \\'a0\n\\f1 x, *\n\\f2 \\'a0\n\\f1 y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b set-theoretic intersection\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , denoted \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f6 \\uc0\\u8745 \n\\f3  \n\\f1\\fs18 y\n\\f3\\fs20 : a vector containing all elements that are in both \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  (but not in \n\\f7\\i only\n\\f3\\i0  \n\\f1\\fs18 x\n\\f3\\fs20  or \n\\f1\\fs18 y\n\\f3\\fs20 ).  Duplicate elements will be stripped out, in the same manner as the \n\\f1\\fs18 unique()\n\\f3\\fs20  function.  The order of elements in the returned vector is arbitrary and should not be relied upon.  The returned vector will be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f2\\fs20 ,\n\\f3  and \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be of the same type.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)setSymmetricDifference(*\n\\f2 \\'a0\n\\f1 x, *\n\\f2 \\'a0\n\\f1 y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b set-theoretic symmetric difference\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , denoted \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f6 \\uc0\\u8710 \n\\f3  \n\\f1\\fs18 y\n\\f3\\fs20 : a vector containing all elements that are in \n\\f1\\fs18 x\n\\f3\\fs20  or \n\\f1\\fs18 y\n\\f3\\fs20 , but not in both.  Duplicate elements will be stripped out, in the same manner as the \n\\f1\\fs18 unique()\n\\f3\\fs20  function.  The order of elements in the returned vector is arbitrary and should not be relied upon.  The returned vector will be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f2\\fs20 ,\n\\f3  and \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be of the same type.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)setUnion(*\n\\f2 \\'a0\n\\f1 x, *\n\\f2 \\'a0\n\\f1 y)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b set-theoretic union\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , denoted \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f6 \\uc0\\u8746 \n\\f3  \n\\f1\\fs18 y\n\\f3\\fs20 : a vector containing all elements that are in \n\\f1\\fs18 x\n\\f3\\fs20  and/or \n\\f1\\fs18 y\n\\f3\\fs20 .  Duplicate elements will be stripped out, in the same manner as the \n\\f1\\fs18 unique()\n\\f3\\fs20  function.  This function is therefore roughly equivalent to \n\\f1\\fs18 unique(c(x, y))\n\\f3\\fs20 , but this function will probably be faster.  The order of elements in the returned vector is arbitrary and should not be relied upon.  The returned vector will be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f2\\fs20 ,\n\\f3  and \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be of the same type.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (numeric)sign(numeric\\'a0x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b sign\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , meaning that for each element of x, a value of either \n\\f1\\fs18 -1\n\\f3\\fs20 , \n\\f1\\fs18 0\n\\f3\\fs20 , or \n\\f1\\fs18 1\n\\f3\\fs20  will be returned as the corresponding element in the returned vector depending upon whether the original element was (respectively) negative, zero, or positive.  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 integer\n\\f3\\fs20 , an \n\\f1\\fs18 integer\n\\f3\\fs20  vector is returned; if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 float\n\\f3\\fs20 , a \n\\f1\\fs18 float\n\\f3\\fs20  vector is returned.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)sin(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b sine\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 sin()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)sqrt(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b square root\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 sqrt()\n\\f2\\fs20 .\n\\f3   This may be somewhat faster than \n\\f1\\fs18 x^0.5\n\\f3\\fs20  for large vectors.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric$)sum(lif\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b sum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the result of adding all of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  together.  The unusual parameter type signature \n\\f1\\fs18 lif\n\\f3\\fs20  indicates that \n\\f1\\fs18 x\n\\f3\\fs20  can be \n\\f1\\fs18 logical\n\\f3\\fs20 , \n\\f1\\fs18 integer\n\\f3\\fs20 , or \n\\f1\\fs18 float\n\\f2\\fs20 .\n\\f3   If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 float\n\\f3\\fs20 , the result will be \n\\f1\\fs18 float\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 logical\n\\f3\\fs20 , the result will be \n\\f1\\fs18 integer\n\\f3\\fs20  (the number of \n\\f1\\fs18 T\n\\f3\\fs20  values in \n\\f1\\fs18 x\n\\f3\\fs20 , since the \n\\f1\\fs18 integer\n\\f3\\fs20  values of \n\\f1\\fs18 T\n\\f3\\fs20  and \n\\f1\\fs18 F\n\\f3\\fs20  are \n\\f1\\fs18 1\n\\f3\\fs20  and \n\\f1\\fs18 0\n\\f3\\fs20  respectively).  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 integer\n\\f3\\fs20 , things are a bit more complex; in this case, the result will be \n\\f1\\fs18 integer\n\\f3\\fs20  if it can fit into the \n\\f1\\fs18 integer\n\\f3\\fs20  type without overflow issues (including during intermediate stages of the computation), otherwise it will be \n\\f1\\fs18 float\n\\f2\\fs20 .\n\\f3   Note that floating-point roundoff issues can cause this function to return inexact results when \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 float\n\\f3\\fs20  type; this is rarely an issue, but see the \n\\f1\\fs18 sumExact()\n\\f3\\fs20  function for an alternative.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float$)sumExact(float\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b exact sum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the exact result of adding all of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  together.  Unlike the \n\\f1\\fs18 sum()\n\\f3\\fs20  function, \n\\f1\\fs18 sumExact()\n\\f3\\fs20  accepts only type \n\\f1\\fs18 float\n\\f3\\fs20 , since the \n\\f1\\fs18 sum()\n\\f3\\fs20  function is already exact for other types.  When summing floating-point values \\'96 particularly values that vary across many orders of magnitude \\'96 the precision limits of floating-point numbers can lead to roundoff errors that cause the \n\\f1\\fs18 sum()\n\\f3\\fs20  function to return an inexact result.  This function does additional work to ensure that the final result is exact within the possible limits of the \n\\f1\\fs18 float\n\\f3\\fs20  type; some roundoff may still inevitably occur, in other words, but a more exact result could not be represented with a value of type \n\\f1\\fs18 float\n\\f2\\fs20 .\n\\f3   The disadvantage of using this function instead of \n\\f1\\fs18 sum()\n\\f3\\fs20  is that it is much slower \\'96 about 35 times slower, according to one test on macOS, but that will vary across operating systems and hardware.  This function is rarely truly needed, but apart from the performance consequences there is no disadvantage to using it.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)tan(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b tangent\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  using the C++ function \n\\f1\\fs18 tan()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)trunc(float\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b truncation\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the integral value nearest to, but no larger in magnitude than, \n\\f1\\fs18 x\n\\f3\\fs20 .  Note that the return value is \n\\f1\\fs18 float\n\\f3\\fs20  even though integral values are guaranteed, because values could be outside of the range representable by \n\\f1\\fs18 integer\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.2.  Statistics functions\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)cor(numeric\\'a0x, \\kerning1\\expnd0\\expndtw0 [Nif\\'a0y\\'a0=\\'a0NULL]\\expnd0\\expndtw0\\kerning0\n)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns the \n\\f0\\b sample Pearson\\'92s correlation coefficient\n\\f3\\b0  between vectors \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , usually denoted \n\\f7\\i r\n\\f3\\i0 .  If \n\\f1\\fs18 y\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , it is considered to have the same value as \n\\f1\\fs18 x\n\\f3\\fs20 ; for vector \n\\f1\\fs18 x\n\\f3\\fs20  this is not very useful (since the correlation of \n\\f1\\fs18 x\n\\f3\\fs20  with itself is \n\\f1\\fs18 1.0\n\\f3\\fs20  by definition), but it is more useful for calculating a correlation matrix using the columns of \n\\f1\\fs18 x\n\\f3\\fs20  (see below).  The sizes of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be identical.  If \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  have a size of \n\\f1\\fs18 0\n\\f3\\fs20  or \n\\f1\\fs18 1\n\\f3\\fs20 , \n\\f1\\fs18 NAN\n\\f3\\fs20  will be returned (a change in behavior from Eidos 4.0; it used to return \n\\f1\\fs18 NULL\n\\f3\\fs20 ).  The return value will be a singleton \n\\f1\\fs18 float\n\\f3\\fs20 .\\\nIt is also legal to call \n\\f1\\fs18 cor()\n\\f3\\fs20  with matrix \n\\f1\\fs18 x\n\\f3\\fs20  and/or \n\\f1\\fs18 y\n\\f3\\fs20 .  In this case the return value will be a correlation matrix between x and y.  Each column of \n\\f1\\fs18 x\n\\f3\\fs20  will be represented by one row of the result (or if \n\\f1\\fs18 x\n\\f3\\fs20  is a vector, the result will simply have one row representing \n\\f1\\fs18 x\n\\f3\\fs20 ), and each column of \n\\f1\\fs18 y\n\\f3\\fs20  will be represented by one column of the result (or if \n\\f1\\fs18 y\n\\f3\\fs20  is a vector, the result will simply have one column representing \n\\f1\\fs18 y\n\\f3\\fs20 ).  Each element in the result matrix will therefore represent the correlation between a column of matrix \n\\f1\\fs18 x\n\\f3\\fs20  (or the entirety of vector \n\\f1\\fs18 x\n\\f3\\fs20 ) and a column of matrix \n\\f1\\fs18 y\n\\f3\\fs20  (or the entirety of vector y).  Calling \n\\f1\\fs18 cor(x, x)\n\\f3\\fs20 , or equivalently \n\\f1\\fs18 cor(x)\n\\f3\\fs20 , thus produces a symmetric correlation matrix among the columns of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)cov(numeric\\'a0x, \\kerning1\\expnd0\\expndtw0 [Nif\\'a0y\\'a0=\\'a0NULL]\\expnd0\\expndtw0\\kerning0\n)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns the \n\\f0\\b corrected sample covariance\n\\f3\\b0  between vectors \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 .  If \n\\f1\\fs18 y\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , it is considered to have the same value as \n\\f1\\fs18 x\n\\f3\\fs20 ; for vector \n\\f1\\fs18 x\n\\f3\\fs20  this is equivalent to calling \n\\f1\\fs18 var(x)\n\\f3\\fs20 , but it is more useful for calculating a variance-covariance matrix using the columns of \n\\f1\\fs18 x\n\\f3\\fs20  (see below).  The sizes of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be identical.  If \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  have a size of \n\\f1\\fs18 0\n\\f3\\fs20  or \n\\f1\\fs18 1\n\\f3\\fs20 , \n\\f1\\fs18 NAN\n\\f3\\fs20  will be returned (a change in behavior from Eidos 4.0; it used to return \n\\f1\\fs18 NULL\n\\f3\\fs20 ).  The return value will be a singleton \n\\f1\\fs18 float\n\\f3\\fs20 .\\\nIt is also legal to call \n\\f1\\fs18 cov()\n\\f3\\fs20  with matrix \n\\f1\\fs18 x\n\\f3\\fs20  and/or \n\\f1\\fs18 y\n\\f3\\fs20 .  In this case the return value will be a covariance matrix between x and y.  Each column of \n\\f1\\fs18 x\n\\f3\\fs20  will be represented by one row of the result (or if \n\\f1\\fs18 x\n\\f3\\fs20  is a vector, the result will simply have one row representing \n\\f1\\fs18 x\n\\f3\\fs20 ), and each column of \n\\f1\\fs18 y\n\\f3\\fs20  will be represented by one column of the result (or if \n\\f1\\fs18 y\n\\f3\\fs20  is a vector, the result will simply have one column representing \n\\f1\\fs18 y\n\\f3\\fs20 ).  Each element in the result matrix will therefore represent the covariance between a column of matrix \n\\f1\\fs18 x\n\\f3\\fs20  (or the entirety of vector \n\\f1\\fs18 x\n\\f3\\fs20 ) and a column of matrix \n\\f1\\fs18 y\n\\f3\\fs20  (or the entirety of vector y).  Calling \n\\f1\\fs18 cov(x, x)\n\\f3\\fs20 , or equivalently \n\\f1\\fs18 cov(x)\n\\f3\\fs20 , thus produces a symmetric variance-covariance matrix among the columns of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)filter(numeric\\'a0x, float\\'a0filter, [lif$\\'a0outside\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the result of convolving \n\\f1\\fs18 x\n\\f3\\fs20  with \n\\f1\\fs18 filter\n\\f3\\fs20 .  The returned vector will be the same length as \n\\f1\\fs18 x\n\\f3\\fs20 .  The convolution is performed by centering \n\\f1\\fs18 filter\n\\f3\\fs20  on each position of \n\\f1\\fs18 x\n\\f3\\fs20  to produce a corresponding result element that is the sum over the products of each \n\\f1\\fs18 filter\n\\f3\\fs20  value with each \n\\f1\\fs18 x\n\\f3\\fs20  value within the filter\\'92s range.  The length of \n\\f1\\fs18 filter\n\\f3\\fs20  is required to be odd, so that the filter has a central value (and can thus be centered over each value of \n\\f1\\fs18 x\n\\f3\\fs20 ).\\\nIf the filter, centered over a given value of \n\\f1\\fs18 x\n\\f3\\fs20 , extends beyond the end of \n\\f1\\fs18 x\n\\f3\\fs20  then the calculation of the corresponding element of the result is governed by the \n\\f1\\fs18 outside\n\\f3\\fs20  parameter.  When \n\\f1\\fs18 outside\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), the corresponding element in the result will be \n\\f1\\fs18 NAN\n\\f3\\fs20 ; this matches the behavior of the R \n\\f1\\fs18 filter()\n\\f3\\fs20  function (except that R uses \n\\f1\\fs18 NA\n\\f3\\fs20 ).  If \n\\f1\\fs18 outside\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , values outside \n\\f1\\fs18 x\n\\f3\\fs20  will be excluded from the calculation (the filter value covering that position will be considered to be \n\\f1\\fs18 0\n\\f3\\fs20 ), and the other values in the filter will be adjusted so that the sum of the absolute values of the filter weights used is unchanged, to compensate for the excluded values by giving the positions inside \n\\f1\\fs18 x\n\\f3\\fs20  more weight. Finally, if \n\\f1\\fs18 outside\n\\f3\\fs20  is \n\\f1\\fs18 integer\n\\f3\\fs20  or \n\\f1\\fs18 float\n\\f3\\fs20 , that value will be used as the value of \n\\f1\\fs18 x\n\\f3\\fs20  for all positions outside \n\\f1\\fs18 x\n\\f3\\fs20 ; one might pass an expected value or mean value in this way, to be used for all outside positions.\\\nThis function is useful for computing running means and similar transformations of an input vector.  For a simple running mean of width \n\\f1\\fs18 w\n\\f3\\fs20 , pass r\n\\f1\\fs18 ep(1/w, w)\n\\f3\\fs20  for \n\\f1\\fs18 filter\n\\f3\\fs20 .  That case is automatically detected and handled efficiently; otherwise, the runtime of this function is proportional to the length of \n\\f1\\fs18 x\n\\f3\\fs20  times the length of \n\\f1\\fs18 filter\n\\f3\\fs20 , and so will be slow for long filters.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (+$)max(+\\'a0x, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b maximum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and the other arguments supplied: the single greatest value contained by all of them.  All of the arguments must be the same type as \n\\f1\\fs18 x\n\\f3\\fs20 , and the return type will match that of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If all of the arguments have a size of \n\\f1\\fs18 0\n\\f3\\fs20 , the return value will be \n\\f1\\fs18 NULL\n\\f3\\fs20 ; note that this means that \n\\f1\\fs18 max(x,\\'a0max(y))\n\\f3\\fs20  may produce an error, if \n\\f1\\fs18 max(y)\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , in cases where \n\\f1\\fs18 max(x,\\'a0y)\n\\f3\\fs20  does not.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float$)mean(lif\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b arithmetic mean\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the sum of \n\\f1\\fs18 x\n\\f3\\fs20  divided by the number of values in \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If \n\\f1\\fs18 x\n\\f3\\fs20  has a size of \n\\f1\\fs18 0\n\\f3\\fs20 , the return value will be \n\\f1\\fs18 NULL\n\\f2\\fs20 .\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\n  The unusual parameter type signature \n\\f1\\fs18 lif\n\\f3\\fs20  indicates that \n\\f1\\fs18 x\n\\f3\\fs20  can be \n\\f1\\fs18 logical\n\\f3\\fs20 , \n\\f1\\fs18 integer\n\\f3\\fs20 , or \n\\f1\\fs18 float\n\\f3\\fs20 ; if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 logical\n\\f3\\fs20 , it is coerced to \n\\f1\\fs18 integer\n\\f3\\fs20  internally (with \n\\f1\\fs18 F\n\\f3\\fs20  being \n\\f1\\fs18 0\n\\f3\\fs20  and \n\\f1\\fs18 T\n\\f3\\fs20  being \n\\f1\\fs18 1\n\\f3\\fs20 , as always), allowing \n\\f1\\fs18 mean()\n\\f3\\fs20  to calculate the average truth value of a \n\\f1\\fs18 logical\n\\f3\\fs20  vector.\n\\f2 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (+$)min(+\\'a0x, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b minimum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and the other arguments supplied: the single smallest value contained by all of them.  All of the arguments must be the same type as \n\\f1\\fs18 x\n\\f3\\fs20 , and the return type will match that of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If all of the arguments have a size of \n\\f1\\fs18 0\n\\f3\\fs20 , the return value will be \n\\f1\\fs18 NULL\n\\f3\\fs20 ; note that this means that \n\\f1\\fs18 min(x,\\'a0min(y))\n\\f3\\fs20  may produce an error, if \n\\f1\\fs18 min(y)\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , in cases where \n\\f1\\fs18 min(x,\\'a0y)\n\\f3\\fs20  does not.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (+)pmax(+\\'a0x, +\\'a0y)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b parallel maximum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 : the element-wise maximum for each corresponding pair of elements in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 .  The type of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must match, and the returned value will have the same type.  In one usage pattern the size of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  match, in which case the returned value will have the same size.  In the other usage pattern either \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  is a singleton, in which case the returned value will match the size of the non-singleton argument, and pairs of elements for comparison will be formed between the singleton\\'92s element and each of the elements in the non-singleton.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (+)pmin(+\\'a0x, +\\'a0y)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b parallel minimum\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 : the element-wise minimum for each corresponding pair of elements in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 .  The type of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must match, and the returned value will have the same type.  In one usage pattern the size of \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  match, in which case the returned value will have the same size.  In the other usage pattern either \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  is a singleton, in which case the returned value will match the size of the non-singleton argument, and pairs of elements for comparison will be formed between the singleton\\'92s element and each of the elements in the non-singleton.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)quantile(numeric\\'a0x, [Nf\\'a0probs\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns \n\\f0\\b sample quantiles\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  for the given probabilities.  The smallest value in \n\\f1\\fs18 x\n\\f3\\fs20  corresponds to a probability of \n\\f1\\fs18 0\n\\f3\\fs20 , and the largest value in \n\\f1\\fs18 x\n\\f3\\fs20  to a probability of \n\\f1\\fs18 1\n\\f3\\fs20 .  The \n\\f1\\fs18 probs\n\\f3\\fs20  vector should be a vector of probabilities in \n\\f1\\fs18 [0, 1]\n\\f3\\fs20 , or \n\\f1\\fs18 NULL\n\\f3\\fs20 , which is equivalent to \n\\f1\\fs18 c(0.0, 0.25, 0.5, 0.75, 1.0)\n\\f3\\fs20 , requesting sample quartiles.\\\nThe quantile function linearly interpolates between the points of the empirical cumulative distribution function.  In other words, if \n\\f1\\fs18 x\n\\f3\\fs20  is a vector of length \n\\f7\\i n\n\\f3\\i0 +1, then the quantiles with \n\\f1\\fs18 probs\n\\f3\\fs20  equal to (0, 1/\n\\f7\\i n\n\\f3\\i0 , 2/\n\\f7\\i n\n\\f3\\i0 , ..., (\n\\f7\\i n\n\\f3\\i0 \\uc0\\u8722 1)/\n\\f7\\i n\n\\f3\\i0 , 1) are equal to the sorted values of \n\\f1\\fs18 x\n\\f3\\fs20 , and the quantile is a linear function of \n\\f1\\fs18 probs\n\\f3\\fs20  otherwise.  Note that there are many ways to compute quantiles; this algorithm corresponds to R\\'92s default \\'93type 7\\'94 algorithm.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric)range(numeric\n\\f2 \\'a0\n\\f1 x, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b range\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  and the other arguments supplied: a vector of length \n\\f1\\fs18 2\n\\f3\\fs20  composed of the minimum and maximum values contained by all of them, at indices \n\\f1\\fs18 0\n\\f3\\fs20  and \n\\f1\\fs18 1\n\\f3\\fs20  respectively.  All of the arguments must be the same type as \n\\f1\\fs18 x\n\\f3\\fs20 , and the return type will match that of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If all of the arguments have a size of \n\\f1\\fs18 0\n\\f3\\fs20 , the return value will be \n\\f1\\fs18 NULL\n\\f3\\fs20 ; note that this means that \n\\f1\\fs18 range(x,\\'a0range(y))\n\\f3\\fs20  may produce an error, if \n\\f1\\fs18 range(y)\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , in cases where \n\\f1\\fs18 range(x,\\'a0y)\n\\f3\\fs20  does not.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (numeric)rank(numeric\\'a0x, [string$\\'a0tiesMethod\\'a0=\\'a0\"average\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b ranks\n\\f3\\b0  of the elements of \n\\f1\\fs18 x\n\\f3\\fs20 : a vector of length \n\\f1\\fs18 L\n\\f3\\fs20  (the length of \n\\f1\\fs18 x\n\\f3\\fs20 ), composed of the relative ranks, from \n\\f1\\fs18 1\n\\f3\\fs20  to \n\\f1\\fs18 L\n\\f3\\fs20 , of each corresponding element of \n\\f1\\fs18 x\n\\f3\\fs20 .  The \n\\f1\\fs18 tiesMethod\n\\f3\\fs20  parameter may be any of \n\\f1\\fs18 \"average\"\n\\f3\\fs20  (the default), \n\\f1\\fs18 \"first\"\n\\f3\\fs20 , \n\\f1\\fs18 \"last\"\n\\f3\\fs20 , \n\\f1\\fs18 \"max\"\n\\f3\\fs20 , or \n\\f1\\fs18 \"min\"\n\\f3\\fs20  (\n\\f1\\fs18 \"random\"\n\\f3\\fs20 , supported by R, is not supported by Eidos at this time but could be added if needed).  For \n\\f1\\fs18 \"average\"\n\\f3\\fs20 , the return value is of type \n\\f1\\fs18 float\n\\f3\\fs20 ; for all others, it is of type \n\\f1\\fs18 integer\n\\f3\\fs20 .  (Note that the return type does \n\\f7\\i not\n\\f3\\i0  depend upon the type of \n\\f1\\fs18 x\n\\f3\\fs20 .)\\\nThe result for all of these \n\\f1\\fs18 tiesMethod\n\\f3\\fs20  values is identical (except for type) if the elements of \n\\f1\\fs18 x\n\\f3\\fs20  are unique; the difference between these methods is in how ties are resolved.  Suppose that \n\\f7\\i n\n\\f3\\i0  elements of \n\\f1\\fs18 x\n\\f3\\fs20  are tied (because they are equal), corresponding to ranks \n\\f7\\i k\n\\f3\\i0  through \n\\f7\\i k\n\\f3\\i0 +\n\\f7\\i n\\uc0\\u8722 \n\\f3\\i0 1.  For \n\\f1\\fs18 tiesMethod\n\\f3\\fs20  \n\\f1\\fs18 \"average\"\n\\f3\\fs20 , all \n\\f7\\i n\n\\f3\\i0  tied elements receive the same rank, (\n\\f7\\i k\n\\f3\\i0  + (\n\\f7\\i n\\uc0\\u8722 \n\\f3\\i0 1)/2), which is the average of the ranks.  For \n\\f1\\fs18 \"first\"\n\\f3\\fs20 , the first tied element receives rank \n\\f7\\i k\n\\f3\\i0 , upward to the last tied element receiving rank \n\\f7\\i k\n\\f3\\i0 +\n\\f7\\i n\\uc0\\u8722 \n\\f3\\i0 1.  For \n\\f1\\fs18 \"last\"\n\\f3\\fs20 , the last tied element receives rank \n\\f7\\i k\n\\f3\\i0 , downward to the first tied element receiving rank \n\\f7\\i k\n\\f3\\i0 +\n\\f7\\i n\\uc0\\u8722 \n\\f3\\i0 1.  For \n\\f1\\fs18 \"max\"\n\\f3\\fs20 , all \n\\f7\\i n\n\\f3\\i0  tied element receive the maximum rank, \n\\f7\\i k\n\\f3\\i0 +\n\\f7\\i n\\uc0\\u8722 \n\\f3\\i0 1.  For \n\\f1\\fs18 \"min\"\n\\f3\\fs20 , all \n\\f7\\i n\n\\f3\\i0  tied element receive the minimum rank, \n\\f7\\i k\n\\f3\\i0 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float$)sd(numeric\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b corrected sample standard deviation\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  has a size of \n\\f1\\fs18 0\n\\f3\\fs20  or \n\\f1\\fs18 1\n\\f3\\fs20 , \n\\f1\\fs18 NAN\n\\f3\\fs20  will be returned (a change in behavior from Eidos 4.0; it used to return \n\\f1\\fs18 NULL\n\\f3\\fs20 ).  Matrix/array dimensions are ignored by \n\\f1\\fs18 sd()\n\\f3\\fs20 ; it simply uses all of the elements of \n\\f1\\fs18 x\n\\f3\\fs20  for its calculation.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float$)ttest(float\n\\f2 \\'a0\n\\f1 x, [Nf\\'a0y\\'a0=\\'a0NULL], [Nf$\\'a0mu\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f7\\i p\n\\f3\\i0 -value resulting from running a \n\\f7\\i t\n\\f3\\i0 -test with the supplied data.  Two types of \n\\f7\\i t\n\\f2\\i0 -\n\\f3 tests can be performed.  If \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are supplied (i.e., \n\\f1\\fs18 y\n\\f3\\fs20  is non-\n\\f1\\fs18 NULL\n\\f3\\fs20 ), a two-sample unpaired two-sided Welch\\'92s \n\\f7\\i t\n\\f3\\i0 -test is conducted using the samples in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , each of which must contain at least two elements.  The null hypothesis for this test is that the two samples are drawn from populations with the same mean.  Other options, such as pooled-variance \n\\f7\\i t\n\\f3\\i0 -tests, paired \n\\f7\\i t\n\\f3\\i0 -tests, and one-sided \n\\f7\\i t\n\\f3\\i0 -tests, are not presently available.  If \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 mu\n\\f3\\fs20  are supplied (i.e., \n\\f1\\fs18 mu\n\\f3\\fs20  is non-\n\\f1\\fs18 NULL\n\\f3\\fs20 ), a one-sample \n\\f7\\i t\n\\f3\\i0 -test is conducted in which the null hypothesis is that the sample is drawn from a population with mean \n\\f1\\fs18 mu\n\\f2\\fs20 .\\\n\n\\f3 Note that the results from this function are substantially different from those produced by R.  The Eidos \n\\f1\\fs18 ttest() \n\\f3\\fs20 function uses uncorrected sample statistics, which means they will be biased for small sample sizes, whereas R probably uses corrected, unbiased sample statistics.  This is an Eidos bug, and might be fixed if anyone complains.  If large sample sizes are used, however, the bias is likely to be small, and uncorrected statistics are simpler and faster to compute.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float$)var(numeric\\'a0x)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns the \n\\f0\\b corrected sample variance\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  has a size of \n\\f1\\fs18 0\n\\f3\\fs20  or \n\\f1\\fs18 1\n\\f3\\fs20 , \n\\f1\\fs18 NAN\n\\f3\\fs20  will be returned (a change in behavior from Eidos 4.0; it used to return \n\\f1\\fs18 NULL\n\\f3\\fs20 ).  This is the square of the standard deviation calculated by \n\\f1\\fs18 sd()\n\\f3\\fs20 .  It is illegal to call \n\\f1\\fs18 var()\n\\f3\\fs20  with a matrix or array argument; use \n\\f1\\fs18 cov()\n\\f3\\fs20  to calculate a variance-covariance matrix.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.3.  Distribution drawing and density functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)dmvnorm(float\\'a0x, numeric\\'a0mu, numeric\\'a0sigma)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b probability densities for a \n\\f4\\i k\n\\f0\\i0 -dimensional multivariate normal distribution\n\\f3\\b0  with a length \n\\f7\\i k\n\\f3\\i0  mean vector \n\\f1\\fs18 mu\n\\f3\\fs20  and a \n\\f7\\i k\n\\f3\\i0  \\'d7 \n\\f7\\i k\n\\f3\\i0  variance-covariance matrix \n\\f1\\fs18 sigma\n\\f3\\fs20 .  The \n\\f1\\fs18 mu\n\\f3\\fs20  and \n\\f1\\fs18 sigma\n\\f3\\fs20  parameters are used for all densities.  The quantile values, \n\\f1\\fs18 x\n\\f3\\fs20 , should be supplied as a matrix with one row per vector of quantile values and \n\\f7\\i k\n\\f3\\i0  columns (one column per dimension); for convenience, a single quantile may be supplied as a vector rather than a matrix with just one row.  The number of dimensions \n\\f7\\i k\n\\f3\\i0  must be at least two; for \n\\f7\\i k\n\\f3\\i0 =1, use \n\\f1\\fs18 dnorm()\n\\f3\\fs20 .\\\nCholesky decomposition of the variance-covariance matrix \n\\f1\\fs18 sigma\n\\f3\\fs20  is involved as an internal step, and this requires that \n\\f1\\fs18 sigma\n\\f3\\fs20  be positive-definite; if it is not, an error will result.  When more than one density is needed, it is much more efficient to call \n\\f1\\fs18 dmvnorm()\n\\f3\\fs20  once to generate all of the densities, since the Cholesky decomposition of \n\\f1\\fs18 sigma\n\\f3\\fs20  can then be done just once.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)dbeta(float\\'a0x, numeric\\'a0alpha, numeric\\'a0beta)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b probability densities for a beta distribution\n\\f3\\b0  at quantiles \n\\f1\\fs18 x\n\\f3\\fs20  with parameters \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f1\\fs18 beta\n\\f3\\fs20 .  The \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f1\\fs18 beta\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , specifying a value for each density computation.  The probability density function is \n\\f8\\i P\n\\f2\\i0 (\n\\f8\\i s\n\\f2\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 ,\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )\\'a0= [\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 +\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )/\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 )\\uc0\\u915 (\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )]\n\\f8\\i s\n\\fs13\\fsmilli6667 \\super \\uc0\\u945 \n\\f2\\i0 \\uc0\\u8722 1\n\\fs20 \\nosupersub (1\\uc0\\u8722 \n\\f8\\i s\n\\f2\\i0 )\n\\f8\\i\\fs13\\fsmilli6667 \\super \\uc0\\u946 \n\\f2\\i0 \\uc0\\u8722 1\n\\f3\\fs20 \\nosupersub , where \n\\f8\\i \\uc0\\u945 \n\\f3\\i0  is \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f8\\i \\uc0\\u946 \n\\f3\\i0  is \n\\f1\\fs18 beta\n\\f3\\fs20 .  Both parameters must be greater than \n\\f1\\fs18 0\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)dexp(float\\'a0x, [numeric\\'a0mu\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b probability densities for an exponential distribution\n\\f3\\b0  at quantiles \n\\f1\\fs18 x\n\\f3\\fs20  with mean \n\\f1\\fs18 mu\n\\f3\\fs20  (i.e. rate \n\\f1\\fs18 1/mu\n\\f3\\fs20 ).  The \n\\f1\\fs18 mu\n\\f3\\fs20  parameter may either be a singleton, specifying a single value to be used for all of the draws, or they may be vectors of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , specifying a value for each density computation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)dgamma(float\\'a0x, numeric\\'a0mean, numeric\\'a0shape)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b probability densities for a gamma distribution\n\\f3\\b0  at quantiles \n\\f1\\fs18 x\n\\f3\\fs20  with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and shape parameter \n\\f1\\fs18 shape\n\\f3\\fs20 .  The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 shape\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , specifying a value for each density computation.  The probability density function is \n\\f8\\i P\n\\f2\\i0 (\n\\f8\\i s\n\\f2\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 ,\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )\\'a0= [\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 )\n\\f8\\i \\uc0\\u946 \n\\fs13\\fsmilli6667 \\super \\uc0\\u945 \n\\f2\\i0\\fs20 \\nosupersub ]\n\\fs13\\fsmilli6667 \\super \\uc0\\u8722 1\n\\f8\\i\\fs20 \\nosupersub s\n\\fs13\\fsmilli6667 \\super \\uc0\\u945 \n\\f2\\i0 \\uc0\\u8722 1\n\\fs20 \\nosupersub exp(\\uc0\\u8722 \n\\f8\\i s\n\\f2\\i0 /\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )\n\\f3 , where \n\\f8\\i \\uc0\\u945 \n\\f3\\i0  is the shape parameter \n\\f1\\fs18 shape\n\\f3\\fs20 , and the mean of the distribution given by \n\\f1\\fs18 mean\n\\f3\\fs20  is equal to \n\\f8\\i \\uc0\\u945 \\u946 \n\\f3\\i0 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (float)dnorm(float\\'a0x, [numeric\\'a0mean\\'a0=\\'a00], [numeric\\'a0sd\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f0\\b probability densities for a normal distribution\n\\f3\\b0  at quantiles \n\\f1\\fs18 x\n\\f3\\fs20  with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and standard deviation \n\\f1\\fs18 sd\n\\f3\\fs20 .  The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 sd\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the densities, or they may be vectors of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , specifying a value for each density computation.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)findInterval(numeric\\'a0x, numeric\\'a0vec, [logical$\\'a0rightmostClosed\\'a0=\\'a0F], [logical$\\'a0allInside\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b interval indices\n\\f3\\b0  for the values in \n\\f1\\fs18 x\n\\f3\\fs20  within a vector of non-decreasing breakpoints \n\\f1\\fs18 vec\n\\f3\\fs20 .  The returned \n\\f1\\fs18 integer\n\\f3\\fs20  vector contains, for each corresponding element of \n\\f1\\fs18 x\n\\f3\\fs20 , the index of the interval in \n\\f1\\fs18 vec\n\\f3\\fs20  within which that element of \n\\f1\\fs18 x\n\\f3\\fs20  is contained.\\\nMore precisely, if \n\\f1\\fs18 i\n\\f3\\fs20  is the returned \n\\f1\\fs18 integer\n\\f3\\fs20  vector from \n\\f1\\fs18 findInterval(x, v)\n\\f3\\fs20 , and \n\\f1\\fs18 N\n\\f3\\fs20  is \n\\f1\\fs18 length(v)\n\\f3\\fs20 , then for each index \n\\f1\\fs18 j\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20 , it will be true that \n\\f1\\fs18 v[i[j]]\n\\f3\\fs20  \\uc0\\u8804  \n\\f1\\fs18 x[j]\n\\f3\\fs20  < \n\\f1\\fs18 v[i[j]+1]\n\\f3\\fs20 , treating \n\\f1\\fs18 v[-1]\n\\f3\\fs20  as \n\\f1\\fs18 -INF\n\\f3\\fs20  and \n\\f1\\fs18 v[N]\n\\f3\\fs20  as \n\\f1\\fs18 INF\n\\f3\\fs20 , \n\\f7\\i assuming\n\\f3\\i0  that the two flags \n\\f1\\fs18 rightmostClosed\n\\f3\\fs20  and \n\\f1\\fs18 allInside\n\\f3\\fs20  have their default value of \n\\f1\\fs18 F\n\\f3\\fs20 .  The effects of the flags will be discussed below.  Note that \n\\f1\\fs18 vec\n\\f3\\fs20  must be non-decreasing; in other words, it must be sorted in ascending order, although it may have duplicate values.  The returned vector will thus be equal in length to \n\\f1\\fs18 x\n\\f3\\fs20 , and each of its elements will be in the interval [\n\\f1\\fs18 -1\n\\f3\\fs20 , \n\\f1\\fs18 N-1\n\\f3\\fs20 ].\\\nThe \n\\f1\\fs18 rightmostClosed\n\\f3\\fs20  flag, if \n\\f1\\fs18 T\n\\f3\\fs20 , alters the above behavior to treat the rightmost interval, \n\\f1\\fs18 vec[N-2]\n\\f3\\fs20  .. \n\\f1\\fs18 vec[N-1]\n\\f3\\fs20 , as closed.  This means that if \n\\f1\\fs18 x[j]==vec[N-1]\n\\f3\\fs20  (i.e., equals \n\\f1\\fs18 max(vec)\n\\f3\\fs20 ), the corresponding result \n\\f1\\fs18 i[j]\n\\f3\\fs20  will be \n\\f1\\fs18 N-2\n\\f3\\fs20  as for all other values in the last interval.\\\nThe \n\\f1\\fs18 allInside\n\\f3\\fs20  flag, if \n\\f1\\fs18 T\n\\f3\\fs20 , alters the above behavior to coerce returned indices into \n\\f1\\fs18 0\n\\f3\\fs20  .. \n\\f1\\fs18 N-2\n\\f3\\fs20 .  In other words, \n\\f1\\fs18 -1\n\\f3\\fs20  is mapped to \n\\f1\\fs18 0\n\\f3\\fs20 , and \n\\f1\\fs18 N-1\n\\f3\\fs20  is mapped to \n\\f1\\fs18 N-2\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)pnorm(float\\'a0q, [numeric\\'a0mean\\'a0=\\'a00], [numeric\\'a0sd\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b cumulative distribution function values for a normal distribution\n\\f3\\b0  at quantiles \n\\f1\\fs18 q\n\\f3\\fs20  with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and standard deviation \n\\f1\\fs18 sd\n\\f3\\fs20 .  The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 sd\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the quantiles, or they may be vectors of the same length as \n\\f1\\fs18 q\n\\f3\\fs20 , specifying a value for each quantile.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)qnorm(float\\'a0p, [numeric\\'a0mean\\'a0=\\'a00], [numeric\\'a0sd\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f0\\b quantiles for a normal distribution\n\\f3\\b0  with lower tail probabilities less than \n\\f1\\fs18 p\n\\f3\\fs20 , with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and standard deviation \n\\f1\\fs18 sd\n\\f3\\fs20 . The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 sd\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the quantiles, or they may be vectors of the same length as \n\\f1\\fs18 p\n\\f3\\fs20 , specifying a value for each quantile computation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)rbeta(integer$\\'a0n, numeric\\'a0alpha, numeric\\'a0beta)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a beta distribution\n\\f3\\b0  with parameters \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f1\\fs18 beta\n\\f3\\fs20 .  The \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f1\\fs18 beta\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  Draws are made from a beta distribution with probability density \n\\f8\\i P\n\\f2\\i0 (\n\\f8\\i s\n\\f2\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 ,\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )\\'a0= [\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 +\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )/\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f2\\i0 )\\uc0\\u915 (\n\\f8\\i \\uc0\\u946 \n\\f2\\i0 )]\n\\f8\\i s\n\\fs13\\fsmilli6667 \\super \\uc0\\u945 \n\\f2\\i0 \\uc0\\u8722 1\n\\fs20 \\nosupersub (1\\uc0\\u8722 \n\\f8\\i s\n\\f2\\i0 )\n\\f8\\i\\fs13\\fsmilli6667 \\super \\uc0\\u946 \n\\f2\\i0 \\uc0\\u8722 1\n\\f3\\fs20 \\nosupersub , where \n\\f8\\i \\uc0\\u945 \n\\f3\\i0  is \n\\f1\\fs18 alpha\n\\f3\\fs20  and \n\\f8\\i \\uc0\\u946 \n\\f3\\i0  is \n\\f1\\fs18 beta\n\\f3\\fs20 .  Both parameters must be greater than \n\\f1\\fs18 0\n\\f3\\fs20 .  The values drawn are in the interval [0, 1].\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (integer)rbinom(integer$\n\\f2 \\'a0\n\\f1 n, integer\\'a0size, float\\'a0prob)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a binomial distribution\n\\f3\\b0  with a number of trials specified by \n\\f1\\fs18 size\n\\f3\\fs20  and a probability of success specified by \n\\f1\\fs18 prob\n\\f3\\fs20 .  The \n\\f1\\fs18 size\n\\f3\\fs20  and \n\\f1\\fs18 prob\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)rcauchy(integer$\\'a0n, [numeric\\'a0location\\'a0=\\'a00], [numeric\\'a0scale\\'a0=\\'a01])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a Cauchy distribution\n\\f3\\b0  with location \n\\f1\\fs18 location\n\\f3\\fs20  and scale \n\\f1\\fs18 scale\n\\f3\\fs20 .  The \n\\f1\\fs18 location\n\\f3\\fs20  and \n\\f1\\fs18 scale\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (float)rdirichlet(integer$\\'a0n, numeric\\'a0alpha)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a matrix of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a Dirichlet distribution\n\\f3\\b0  with vector of shape parameters \n\\f1\\fs18 alpha\n\\f3\\fs20 .  The Dirichlet distribution is a multidimensional generalization of the beta distribution, sometimes called the multivariate beta distribution; see also \n\\f1\\fs18 rbeta()\n\\f3\\fs20 .  All values in \n\\f1\\fs18 alpha\n\\f3\\fs20  must be positive and finite, and \n\\f1\\fs18 alpha\n\\f3\\fs20  must be of length >= 2.  The return value is a matrix with \n\\f1\\fs18 n\n\\f3\\fs20  rows and \n\\f1\\fs18 size(alpha)\n\\f3\\fs20  columns, each row containing a single Dirichlet random deviate.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)rdunif(integer$\\'a0n, [integer\\'a0min\\'a0=\\'a00], [integer\\'a0max\n\\f2 \\'a0\n\\f1 =\\'a01])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a discrete uniform distribution\n\\f3\\b0  from \n\\f1\\fs18 min\n\\f3\\fs20  to \n\\f1\\fs18 max\n\\f3\\fs20 , inclusive.  The \n\\f1\\fs18 min\n\\f3\\fs20  and \n\\f1\\fs18 max\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  See \n\\f1\\fs18 runif()\n\\f3\\fs20  for draws from a continuous uniform distribution\\kerning1\\expnd0\\expndtw0 , and \n\\f1\\fs18 runif64()\n\\f3\\fs20  for uniform draws from the full 64-bit \n\\f1\\fs18 integer\n\\f3\\fs20  range\\expnd0\\expndtw0\\kerning0\n.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (integer)rdunif64(integer$\\'a0n)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a discrete uniform distribution spanning the full 64-bit \n\\f9\\fs18 integer\n\\f0\\fs20  range\n\\f3\\b0 .  See \n\\f1\\fs18 rdunif()\n\\f3\\fs20  for draws from a discrete uniform distribution with a specified range.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)rexp(integer$\n\\f2 \\'a0\n\\f1 n, [numeric\\'a0mu\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from an exponential distribution\n\\f3\\b0  with mean \n\\f1\\fs18 mu\n\\f3\\fs20  (i.e. rate \n\\f1\\fs18 1/mu\n\\f3\\fs20 ).  The \n\\f1\\fs18 mu\n\\f3\\fs20  parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)rf(integer$\\'a0n, numeric\\'a0d1, numeric\\'a0d2)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from an \n\\f4\\i F\n\\f0\\i0 -distribution\n\\f3\\b0  with degrees of freedom \n\\f1\\fs18 d1\n\\f3\\fs20  and \n\\f1\\fs18 d2\n\\f3\\fs20 .  The \n\\f1\\fs18 d1\n\\f3\\fs20  and \n\\f1\\fs18 d2\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)rgamma(integer$\n\\f2 \\'a0\n\\f1 n, numeric\\'a0mean, numeric\\'a0shape)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a gamma distribution\n\\f3\\b0  with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and shape parameter \n\\f1\\fs18 shape\n\\f3\\fs20 .  The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 shape\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  Draws are made from a gamma distribution with probability density \n\\f8\\i P\n\\f2\\i0 (\n\\f8\\i s\n\\f2\\i0 \\'a0|\\'a0\n\\f10\\i \\uc0\\u945 \n\\f2\\i0 ,\n\\f10\\i \\uc0\\u946 \n\\f2\\i0 )\\'a0= [\n\\f11 \\uc0\\u915 \n\\f2 (\n\\f10\\i \\uc0\\u945 \n\\f2\\i0 )\n\\f10\\i \\uc0\\u946 \\u945 \n\\f2\\i0 ]\\super \\uc0\\u8722 1\\nosupersub exp(\\uc0\\u8722 \n\\f8\\i s\n\\f2\\i0 /\n\\f10\\i \\uc0\\u946 \n\\f2\\i0 )\n\\f3 , where \n\\f10\\i \\uc0\\u945 \n\\f3\\i0  is the shape parameter \n\\f1\\fs18 shape\n\\f3\\fs20 , and the mean of the distribution given by \n\\f1\\fs18 mean\n\\f3\\fs20  is equal to \n\\f10\\i \\uc0\\u945 \\u946 \n\\f2\\i0 .\n\\f3   Values of \n\\f1\\fs18 mean\n\\f3\\fs20  less than zero are allowed, and are equivalent (in principle) to the negation of a draw from a gamma distribution with the same \n\\f1\\fs18 shape\n\\f3\\fs20  parameter and the negation of the \n\\f1\\fs18 mean\n\\f3\\fs20  parameter.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(integer)rgeom(integer$\\'a0n, float\\'a0p)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a geometric distribution\n\\f3\\b0  with parameter \n\\f1\\fs18 p\n\\f3\\fs20 .  The \n\\f1\\fs18 p\n\\f3\\fs20  parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  Eidos follows R in using the geometric distribution with support on the set \\{0, 1, 2, \\'85\\}, where the drawn value indicates the number of failures prior to success.  There is an alternative definition, based upon the number of trial required to get one success, so beware.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (float)rlaplace(integer$\\'a0n, [numeric\\'a0b\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a Laplace distribution\n\\f3\\b0  with shape parameter \n\\f1\\fs18 b\n\\f3\\fs20 .  The \n\\f1\\fs18 b\n\\f3\\fs20  parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)rlnorm(integer$\n\\f2 \\'a0\n\\f1 n, [numeric\\'a0meanlog\\'a0=\\'a00], [numeric\\'a0sdlog\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a lognormal distribution\n\\f3\\b0  with mean \n\\f1\\fs18 meanlog\n\\f3\\fs20  and standard deviation \n\\f1\\fs18 sdlog\n\\f3\\fs20 , specified on the log scale.  The \n\\f1\\fs18 meanlog\n\\f3\\fs20  and \n\\f1\\fs18 sdlog\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)rmultinom(integer$\\'a0n, integer$\\'a0size, numeric\\'a0prob)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a matrix of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random vectors from the specified multinomial distribution\n\\f3\\b0 .  For each random vector drawn from the multinomial distribution, \n\\f1\\fs18 size\n\\f3\\fs20  objects will be put into \n\\f7\\i k\n\\f3\\i0  boxes, where \n\\f1\\fs18 prob\n\\f3\\fs20  is a vector of probabilities of length \n\\f7\\i k\n\\f3\\i0  specifying the probability for each box.  If \n\\f1\\fs18 prob\n\\f3\\fs20  is not normalized to sum to \n\\f1\\fs18 1.0\n\\f3\\fs20 , its entries are treated as weights and normalized appropriately.  The draws are returned as a matrix with \n\\f7\\i k\n\\f3\\i0  rows (one row per box) and \n\\f1\\fs18 n\n\\f3\\fs20  columns (one column per drawn random vector).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float)rmvnorm(integer$\\'a0n, numeric\\'a0mu, numeric\\'a0sigma)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a matrix of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a \n\\f4\\i k\n\\f0\\i0 -dimensional multivariate normal distribution\n\\f3\\b0  with a length \n\\f7\\i k\n\\f3\\i0  mean vector \n\\f1\\fs18 mu\n\\f3\\fs20  and a \n\\f7\\i k\n\\f3\\i0  \\'d7 \n\\f7\\i k\n\\f3\\i0  variance-covariance matrix \n\\f1\\fs18 sigma\n\\f3\\fs20 .  The \n\\f1\\fs18 mu\n\\f3\\fs20  and \n\\f1\\fs18 sigma\n\\f3\\fs20  parameters are used for all \n\\f1\\fs18 n\n\\f3\\fs20  draws.  The draws are returned as a matrix with \n\\f1\\fs18 n\n\\f3\\fs20  rows (one row per draw) and \n\\f7\\i k\n\\f3\\i0  columns (one column per dimension).  The number of dimensions \n\\f7\\i k\n\\f3\\i0  must be at least two; for \n\\f7\\i k\n\\f3\\i0 =1, use \n\\f1\\fs18 rnorm()\n\\f3\\fs20 .\\\nCholesky decomposition of the variance-covariance matrix \n\\f1\\fs18 sigma\n\\f3\\fs20  is involved as an internal step, and this requires that \n\\f1\\fs18 sigma\n\\f3\\fs20  be positive-definite; if it is not, an error will result.  When more than one draw is needed, it is much more efficient to call \n\\f1\\fs18 rmvnorm()\n\\f3\\fs20  once to generate all of the draws, since the Cholesky decomposition of \n\\f1\\fs18 sigma\n\\f3\\fs20  can then be done just once.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (integer)rnbinom(integer$\\'a0n, numeric\\'a0size, float\\'a0prob)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a negative binomial distribution\n\\f3\\b0  representing the number of failures which occur in a sequence of Bernoulli trials before reaching a target number of successful trials specified by \n\\f1\\fs18 size\n\\f3\\fs20 , given a probability of success specified by \n\\f1\\fs18 prob\n\\f3\\fs20 .  The mean of this distribution for \n\\f1\\fs18 size\n\\f3\\fs20  \n\\f7\\i s\n\\f3\\i0  and \n\\f1\\fs18 prob\n\\f3\\fs20  \n\\f7\\i p\n\\f3\\i0  is \n\\f7\\i s\n\\f3\\i0 (1\\uc0\\u8722 \n\\f7\\i p\n\\f3\\i0 )/\n\\f7\\i p\n\\f3\\i0 , with variance \n\\f7\\i s\n\\f3\\i0 (1\\uc0\\u8722 \n\\f7\\i p\n\\f3\\i0 )/\n\\f7\\i p\n\\f3\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub .  The \n\\f1\\fs18 size\n\\f3\\fs20  and \n\\f1\\fs18 prob\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)rnorm(integer$\n\\f2 \\'a0\n\\f1 n, [numeric\\'a0mean\\'a0=\\'a00], [numeric\\'a0sd\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a normal distribution\n\\f3\\b0  with mean \n\\f1\\fs18 mean\n\\f3\\fs20  and standard deviation \n\\f1\\fs18 sd\n\\f3\\fs20 .  The \n\\f1\\fs18 mean\n\\f3\\fs20  and \n\\f1\\fs18 sd\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)rpois(integer$\n\\f2 \\'a0\n\\f1 n, numeric\\'a0lambda)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a Poisson distribution\n\\f3\\b0  with parameter \n\\f1\\fs18 lambda\n\\f3\\fs20  (not to be confused with the language concept of a \\'93lambda\\'94; \n\\f1\\fs18 lambda\n\\f3\\fs20  here is just the name of a parameter, because the symbol typically used for the parameter of a Poisson distribution is the Greek letter \n\\f11 \\uc0\\u955 \n\\f3 ).  The \n\\f1\\fs18 lambda\n\\f3\\fs20  parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)runif(integer$\\'a0n, [numeric\\'a0min\\'a0=\\'a00], [numeric\\'a0max\n\\f2 \\'a0\n\\f1 =\\'a01])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a continuous uniform distribution\n\\f3\\b0  from \n\\f1\\fs18 min\n\\f3\\fs20  to \n\\f1\\fs18 max\n\\f3\\fs20 , inclusive.  The \n\\f1\\fs18 min\n\\f3\\fs20  and \n\\f1\\fs18 max\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  See \n\\f1\\fs18 rdunif()\n\\f3\\fs20  for draws from a discrete uniform distribution.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (float)rweibull(integer$\n\\f2 \\'a0\n\\f1 n, numeric\\'a0lambda, numeric\\'a0k)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a Weibull distribution\n\\f3\\b0  with scale parameter \n\\f1\\fs18 lambda\n\\f3\\fs20  and shape parameter \n\\f1\\fs18 k\n\\f3\\fs20 , both greater than zero.  The \n\\f1\\fs18 lambda\n\\f3\\fs20  and \n\\f1\\fs18 k\n\\f3\\fs20  parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  Draws are made from a Weibull distribution with probability distribution \n\\f8\\i P\n\\f2\\i0 (\n\\f8\\i s\n\\f2\\i0 \\'a0|\\'a0\n\\f10\\i \\uc0\\u955 \n\\f2\\i0 ,\n\\f8\\i k\n\\f2\\i0 )\\'a0=\\'a0(\n\\f8\\i k\n\\f2\\i0  / \n\\f10\\i \\uc0\\u955 \n\\f8 \\super k\n\\f2\\i0 \\nosupersub )\\'a0\n\\f8\\i s\\super k\n\\f2\\i0 \\uc0\\u8722 1\\nosupersub \\'a0exp(-(\n\\f8\\i s\n\\f2\\i0 /\n\\f10\\i \\uc0\\u955 \n\\f2\\i0 )\n\\f8\\i \\super k\n\\f2\\i0 \\nosupersub ).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)rztpois(integer$\\'a0n, numeric\\'a0lambda)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of \n\\f1\\fs18 n\n\\f3\\fs20  \n\\f0\\b random draws from a zero-truncated Poisson distribution\n\\f3\\b0  with parameter \n\\f1\\fs18 lambda\n\\f3\\fs20  (not to be confused with the language concept of a \\'93lambda\\'94; \n\\f1\\fs18 lambda\n\\f3\\fs20  here is just the name of a parameter, because the symbol typically used for the parameter of a Poisson distribution is the Greek letter \n\\f8\\i \\uc0\\u955 \n\\f3\\i0 ).  The zero-truncated Poisson distribution is the conditional probability distribution of a Poisson-distributed random variable, given that the value of the random variable is not zero.  The values returned by \n\\f1\\fs18 rztpois()\n\\f3\\fs20  will therefore never be zero.\\\nThe \n\\f1\\fs18 lambda\n\\f3\\fs20  parameter, \n\\f8\\i \\uc0\\u955 \n\\f3\\i0 , may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length \n\\f1\\fs18 n\n\\f3\\fs20 , specifying a value for each draw.  It is important to note that for \n\\f1\\fs18 rpois()\n\\f3\\fs20  the expected mean of the distribution is \n\\f8\\i \\uc0\\u955 \n\\f3\\i0 , but for \n\\f1\\fs18 rztpois()\n\\f3\\fs20  the expected mean of the distribution is \n\\f8\\i \\uc0\\u955 \n\\f3\\i0 \\'a0/\\'a0(1\\'a0\\uc0\\u8722 \\'a0exp(\\u8722 \n\\f8\\i \\uc0\\u955 \n\\f3\\i0 )), precisely because the zero-truncated Poisson distribution is conditional upon being non-zero.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.4.  Vector construction functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (*)c(...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b concatenation\n\\f3\\b0  of all of its parameters into a single vector\\cf2 \\expnd0\\expndtw0\\kerning0\n, stripped of all matrix/array dimensions (see \n\\f1\\fs18 rbind()\n\\f3\\fs20  and \n\\f1\\fs18 cbind()\n\\f3\\fs20  for concatenation that does not strip this information)\\cf0 \\kerning1\\expnd0\\expndtw0 .  The parameters will be promoted to the highest type represented among them, and that type will be the return type.  \n\\f1\\fs18 NULL\n\\f3\\fs20  values are ignored; they have no effect on the result.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)float(integer$\n\\f2 \\'a0\n\\f1 length)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b new \n\\f9\\fs18 float\n\\f0\\fs20  vector\n\\f3\\b0  of the length specified by \n\\f1\\fs18 length\n\\f3\\fs20 , filled with \n\\f1\\fs18 0.0\n\\f3\\fs20  values.  This can be useful for pre-allocating a vector which you then fill with values by subscripting.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)integer(integer$\n\\f2 \\'a0\n\\f1 length, [integer$\\'a0fill1\\'a0=\\'a00], [integer$\\'a0fill2\\'a0=\\'a01], [Ni\\'a0fill2Indices\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b new \n\\f9\\fs18 integer\n\\f0\\fs20  vector\n\\f3\\b0  of the length specified by \n\\f1\\fs18 length\n\\f3\\fs20 , filled with \n\\f1\\fs18 0\n\\f3\\fs20  values by default.  This can be useful for pre-allocating a vector which you then fill with values by subscripting.\\\nIf a value is supplied for \n\\f1\\fs18 fill1\n\\f3\\fs20 , the new vector will be filled with that value instead of the default of \n\\f1\\fs18 0\n\\f2\\fs20 .\n\\f3   Additionally, if a non-\n\\f1\\fs18 NULL\n\\f3\\fs20  vector is supplied for \n\\f1\\fs18 fill2Indices\n\\f3\\fs20 , the indices specified by \n\\f1\\fs18 fill2Indices\n\\f3\\fs20  will be filled with the value provided by \n\\f1\\fs18 fill2\n\\f2\\fs20 .\n\\f3   For example, given the default values of \n\\f1\\fs18 0\n\\f3\\fs20  and \n\\f1\\fs18 1\n\\f3\\fs20  for \n\\f1\\fs18 fill1\n\\f3\\fs20  and \n\\f1\\fs18 fill2\n\\f3\\fs20 , the returned vector will contain \n\\f1\\fs18 1\n\\f3\\fs20  at all positions specified by \n\\f1\\fs18 fill2Indices\n\\f3\\fs20 , and will contain \n\\f1\\fs18 0\n\\f3\\fs20  at all other positions.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)logical(integer$\n\\f2 \\'a0\n\\f1 length)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b new \n\\f9\\fs18 logical\n\\f0\\fs20  vector\n\\f3\\b0  of the length specified by \n\\f1\\fs18 length\n\\f3\\fs20 , filled with \n\\f1\\fs18 F\n\\f3\\fs20  values.  This can be useful for pre-allocating a vector which you then fill with values by subscripting.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (object<Object>)object(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b new empty \n\\f9\\fs18 object\n\\f0\\fs20  vector\n\\f3\\b0 .  Unlike \n\\f1\\fs18 float()\n\\f3\\fs20 , \n\\f1\\fs18 integer()\n\\f3\\fs20 , \n\\f1\\fs18 logical()\n\\f3\\fs20 , and \n\\f1\\fs18 string()\n\\f3\\fs20 , a length cannot be specified and the new vector contains no elements.  This is because there is no default value for the object type.  Adding to such a vector is typically done with \n\\f1\\fs18 c()\n\\f2\\fs20 .\n\\f3   Note that the return value is of type \n\\f1\\fs18 object<Object>\n\\f3\\fs20 ; this method creates an \n\\f1\\fs18 object\n\\f3\\fs20  vector that does not know what element type it contains.  Such \n\\f1\\fs18 object\n\\f3\\fs20  vectors may be mixed freely with other \n\\f1\\fs18 object\n\\f3\\fs20  vectors in \n\\f1\\fs18 c()\n\\f3\\fs20  and similar contexts; the result of such mixing will take its \n\\f1\\fs18 object\n\\f3\\fs20 -element type from the \n\\f1\\fs18 object\n\\f3\\fs20  vector with a defined \n\\f1\\fs18 object\n\\f3\\fs20 -element type (if any).\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)rep(*\n\\f2 \\'a0\n\\f1 x, integer$\n\\f2 \\'a0\n\\f1 count)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b repetition\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the entirety of \n\\f1\\fs18 x\n\\f3\\fs20  is repeated \n\\f1\\fs18 count\n\\f3\\fs20  times.  The return type matches the type of \n\\f1\\fs18 x\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)repEach(*\n\\f2 \\'a0\n\\f1 x, integer\n\\f2 \\'a0\n\\f1 count)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b repetition of elements\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : each element of \n\\f1\\fs18 x\n\\f3\\fs20  is repeated.  If \n\\f1\\fs18 count\n\\f3\\fs20  is a singleton, it specifies the number of times that each element of \n\\f1\\fs18 x\n\\f3\\fs20  will be repeated.  Otherwise, the length of \n\\f1\\fs18 count\n\\f3\\fs20  must be equal to the length of \n\\f1\\fs18 x\n\\f3\\fs20 ; in this case, each element of \n\\f1\\fs18 x\n\\f3\\fs20  is repeated a number of times specified by the corresponding value of \n\\f1\\fs18 count\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)sample(*\\'a0x, integer$\\'a0size, [logical$\n\\f2 \\'a0\n\\f1 replace\\'a0=\\'a0F], [Nif\\'a0weights\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f1\\fs18 size\n\\f3\\fs20  containing a \n\\f0\\b sample from the elements of \n\\f9\\fs18 x\n\\f3\\b0\\fs20 .  If \n\\f1\\fs18 replace\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , sampling is conducted with replacement (the same element may be drawn more than once); if it is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), then sampling is done without replacement.  A vector of weights may be supplied in the optional parameter \n\\f1\\fs18 weights\n\\f3\\fs20 ; if not \n\\f1\\fs18 NULL\n\\f3\\fs20 , it must be equal in size to \n\\f1\\fs18 x\n\\f3\\fs20 , all weights must be non-negative, and the sum of the weights must be greater than \n\\f1\\fs18 0\n\\f3\\fs20 .  If \n\\f1\\fs18 weights\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default), then equal weights are used for all elements of \n\\f1\\fs18 x\n\\f3\\fs20 .  An error occurs if \n\\f1\\fs18 sample()\n\\f3\\fs20  runs out of viable elements from which to draw; most notably, if sampling is done without replacement then \n\\f1\\fs18 size\n\\f3\\fs20  must be at most equal to the size of \n\\f1\\fs18 x\n\\f3\\fs20 , but if weights of zero are supplied then the restriction on \n\\f1\\fs18 size\n\\f3\\fs20  will be even more stringent.  The draws are obtained from the standard Eidos random number generator, which might be shared with the Context.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (numeric)seq(numeric$\n\\f2 \\'a0\n\\f1 from, numeric$\n\\f2 \\'a0\n\\f1 to, [Nif$\n\\f2 \\'a0\n\\f1 by\n\\f2 \\'a0\n\\f1 =\\'a0NULL], [Ni$\n\\f2 \\'a0\n\\f1 length\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b sequence\n\\f3\\b0 , starting at \n\\f1\\fs18 from\n\\f3\\fs20  and proceeding in the direction of \n\\f1\\fs18 to\n\\f3\\fs20  until the next value in the sequence would fall beyond \n\\f1\\fs18 to\n\\f3\\fs20 .  If the optional parameters \n\\f1\\fs18 by\n\\f3\\fs20  and \n\\f1\\fs18 length\n\\f3\\fs20  are both \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default), the sequence steps by values of \n\\f1\\fs18 1\n\\f3\\fs20  or \n\\f1\\fs18 -1\n\\f3\\fs20  (as needed to proceed in the direction of \n\\f1\\fs18 to\n\\f3\\fs20 ).  A different step value may be supplied with \n\\f1\\fs18 by\n\\f3\\fs20 , but must have the necessary sign.  Alternatively, a sequence length may be supplied in \n\\f1\\fs18 length\n\\f3\\fs20 , in which case the step magnitude will be chosen to produce a sequence of the requested length (with the necessary sign, as before).  If \n\\f1\\fs18 from\n\\f3\\fs20  and \n\\f1\\fs18 to\n\\f3\\fs20  are both \n\\f1\\fs18 integer\n\\f3\\fs20  then the return type will be \n\\f1\\fs18 integer\n\\f3\\fs20  when possible (but this may not be possible, depending upon values supplied for \n\\f1\\fs18 by\n\\f3\\fs20  or \n\\f1\\fs18 length\n\\f3\\fs20 ), otherwise it will be \n\\f1\\fs18 float\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(integer)seqAlong(*\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns an \n\\f0\\b index sequence along \n\\f9\\fs18 x\n\\f3\\b0\\fs20 , from \n\\f1\\fs18 0\n\\f3\\fs20  to \n\\f1\\fs18 size(x) - 1\n\\f3\\fs20 , with a step of \n\\f1\\fs18 1\n\\f3\\fs20 .  This is a convenience function for easily obtaining a set of indices to address or iterate through a vector.  Any matrix/array dimension information is ignored; the index sequence is suitable for indexing into \n\\f1\\fs18 x\n\\f3\\fs20  as a vector.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)seqLen(integer$\\'a0length)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns an \n\\f0\\b index sequence of \n\\f9\\fs18 length\n\\f3\\b0\\fs20 , from \n\\f1\\fs18 0\n\\f3\\fs20  to \n\\f1\\fs18 length - 1\n\\f3\\fs20 , with a step of \n\\f1\\fs18 1\n\\f3\\fs20 ; if \n\\f1\\fs18 length\n\\f3\\fs20  is \n\\f1\\fs18 0\n\\f3\\fs20  the sequence will be zero-length.  This is a convenience function for easily obtaining a set of indices to address or iterate through a vector.  Note that when \n\\f1\\fs18 length\n\\f3\\fs20  is \n\\f1\\fs18 0\n\\f3\\fs20 , using the sequence operator with \n\\f1\\fs18 0:(length-1)\n\\f3\\fs20  will produce \n\\f1\\fs18 0\\'a0-1\n\\f3\\fs20 , and calling \n\\f1\\fs18 seq(a,\\'a0b,\\'a0length=length)\n\\f3\\fs20  will raise an error, but \n\\f1\\fs18 seqLen(length)\n\\f3\\fs20  will return \n\\f1\\fs18 integer(0)\n\\f3\\fs20 , making \n\\f1\\fs18 seqLen()\n\\f3\\fs20  particularly useful for generating a sequence of a given length that might be zero.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (string)string(integer$\n\\f2 \\'a0\n\\f1 length)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b new \n\\f9\\fs18 string\n\\f0\\fs20  vector\n\\f3\\b0  of the length specified by \n\\f1\\fs18 length\n\\f3\\fs20 , filled with \n\\f1\\fs18 \"\"\n\\f3\\fs20  values.  This can be useful for pre-allocating a vector which you then fill with values by subscripting.\n\\f2 \\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.5.  Value inspection & manipulation functions\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (logical$)all(logical\n\\f2 \\'a0\n\\f1 x, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f0\\b all values are \n\\f9\\fs18 T\n\\f3\\b0\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20  and in any other arguments supplied; if any value is \n\\f1\\fs18 F\n\\f3\\fs20 , returns \n\\f1\\fs18 F\n\\f2\\fs20 .\n\\f3   All arguments must be of \n\\f1\\fs18 logical\n\\f3\\fs20  type.  If all arguments are zero-length, \n\\f1\\fs18 T\n\\f3\\fs20  is returned.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical$)allClose(float\\'a0x, float\\'a0y, [float$\\'a0rtol\\'a0=\\'a01.0e-05], [float$\\'a0atol\\'a0=\\'a01.0e-08], [logical$\\'a0equalNAN\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f0\\b all pairs of values between \n\\f9\\fs18 x\n\\f0\\fs20  and y are \\'93close\\'94\n\\f3\\b0 ; if any pair of values is not close, returns \n\\f1\\fs18 F\n\\f3\\fs20 .  The definition of \\'93close\\'94 matches that used in the \n\\f1\\fs18 isClose()\n\\f3\\fs20  function; see that documentation for all further details, including the way that values in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are paired, as well as the meaning of the \n\\f1\\fs18 rtol\n\\f3\\fs20 , \n\\f1\\fs18 atol\n\\f3\\fs20 , and \n\\f1\\fs18 equalNAN\n\\f3\\fs20  parameters.  This function is essentially equivalent to \n\\f1\\fs18 all(isClose(x, y, rtol, atol, equalNAN))\n\\f3\\fs20 , but is more efficient.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)any(logical\n\\f2 \\'a0\n\\f1 x, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f0\\b any value is \n\\f9\\fs18 T\n\\f3\\b0\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20  or in any other arguments supplied; if all values are \n\\f1\\fs18 F\n\\f3\\fs20 , returns \n\\f1\\fs18 F\n\\f2\\fs20 .\n\\f3   All arguments must be of \n\\f1\\fs18 logical\n\\f3\\fs20  type.  If all arguments are zero-length, \n\\f1\\fs18 F\n\\f3\\fs20  is returned.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)cat(*\n\\f2 \\'a0\n\\f1 x, [string$\n\\f2 \\'a0\n\\f1 sep\n\\f2 \\'a0\n\\f1 =\\'a0\" \"]\\cf2 , [logical$\\'a0error\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Concatenates output\n\\f3\\b0  to Eidos\\'92s output stream, joined together by \n\\f1\\fs18 sep\n\\f3\\fs20 .  The value \n\\f1\\fs18 x\n\\f3\\fs20  that is output may be of any type.  A newline is not appended to the output, unlike the behavior of \n\\f1\\fs18 print()\n\\f3\\fs20 ; if a trailing newline is desired, you can use \n\\f1\\fs18 \"\\\\n\"\n\\f3\\fs20  (or use the \n\\f1\\fs18 catn()\n\\f3\\fs20  function).  Also unlike \n\\f1\\fs18 print()\n\\f3\\fs20 , \n\\f1\\fs18 cat()\n\\f3\\fs20  tends to emit very literal output; \n\\f1\\fs18 print(logical(0))\n\\f3\\fs20  will emit \\'93\n\\f1\\fs18 logical(0)\n\\f3\\fs20 \\'94, for example \\'96 showing a semantic interpretation of the value \\'96 whereas \n\\f1\\fs18 cat(logical(0))\n\\f3\\fs20  will emit nothing at all, since there are no elements in the value (it is zero-length).  Similarly, \n\\f1\\fs18 print(NULL)\n\\f3\\fs20  will emit \\'93\n\\f1\\fs18 NULL\n\\f3\\fs20 \\'94, but \n\\f1\\fs18 cat(NULL)\n\\f3\\fs20  will emit nothing.\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 By default (when \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 ), the output is sent to the standard Eidos output stream.  When running at the command line, this sends it to \n\\f1\\fs18 stdout\n\\f3\\fs20 ; when running in SLiMgui, this sends it to the simulation window\\'92s output textview.  If \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the output is instead sent to the Eidos error stream.  When running at the command line, this sends it to \n\\f1\\fs18 stderr\n\\f3\\fs20 ; when running in SLiMgui, the output is routed to the simulation\\'92s debugging output window.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)catn([*\n\\f2 \\'a0\n\\f1 x\n\\f2 \\'a0\n\\f1 =\\'a0\"\"], [string$\n\\f2 \\'a0\n\\f1 sep\n\\f2 \\'a0\n\\f1 =\\'a0\" \"]\\cf2 , [logical$\\'a0error\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Concatenates output (with a trailing newline)\n\\f3\\b0  to Eidos\\'92s output stream, joined together by \n\\f1\\fs18 sep\n\\f3\\fs20 .  The behavior of \n\\f1\\fs18 catn()\n\\f3\\fs20  is identical to that of \n\\f1\\fs18 cat()\n\\f3\\fs20 , except that a final newline character is appended to the output for convenience.  For \n\\f1\\fs18 catn()\n\\f3\\fs20  a default value of \n\\f1\\fs18 \"\"\n\\f3\\fs20  is supplied for \n\\f1\\fs18 x\n\\f3\\fs20 , to allow a simple \n\\f1\\fs18 catn()\n\\f3\\fs20  call with no parameters to emit a newline.\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 By default (when \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 ), the output is sent to the standard Eidos output stream.  When running at the command line, this sends it to \n\\f1\\fs18 stdout\n\\f3\\fs20 ; when running in SLiMgui, this sends it to the simulation window\\'92s output textview.  If \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the output is instead sent to the Eidos error stream.  When running at the command line, this sends it to \n\\f1\\fs18 stderr\n\\f3\\fs20 ; when running in SLiMgui, the output is routed to the simulation\\'92s debugging output window.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string)format(string$\n\\f2 \\'a0\n\\f1 format, numeric\\'a0x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of \n\\f0\\b formatted strings\n\\f3\\b0  generated from \n\\f1\\fs18 x\n\\f3\\fs20 , based upon the formatting string \n\\f1\\fs18 format\n\\f2\\fs20 .\n\\f3   The \n\\f1\\fs18 format\n\\f3\\fs20  parameter may be any \n\\f1\\fs18 string\n\\f3\\fs20  value, but must contain exactly one escape sequence beginning with the \n\\f1\\fs18 %\n\\f3\\fs20  character.  This escape sequence specifies how to format a single value from the vector \n\\f1\\fs18 x\n\\f3\\fs20 .  The returned vector contains one \n\\f1\\fs18 string\n\\f3\\fs20  value for each element of \n\\f1\\fs18 x\n\\f3\\fs20 ; each \n\\f1\\fs18 string\n\\f3\\fs20  value is identical to the string supplied in \n\\f1\\fs18 format\n\\f3\\fs20 , except with a formatted version of the corresponding value from \n\\f1\\fs18 x\n\\f3\\fs20  substituted in place of the escape sequence.\\\nThe syntax for \n\\f1\\fs18 format\n\\f3\\fs20  is a subset of the standard C/C++ \n\\f1\\fs18 printf()\n\\f3\\fs20 -style format strings (e.g., http://en.cppreference.com/w/c/io/fprintf).  The escape sequence used to format each value of x is composed of several elements:\\\n\\pard\\pardeftab397\\li907\\fi-187\\ri720\\sb60\\sa60\\partightenfactor0\n\\ls1\\ilvl0\\cf0 \\'96  A \n\\f1\\fs18 %\n\\f3\\fs20  character at the beginning, initiating the escape sequence (if an actual \n\\f1\\fs18 %\n\\f3\\fs20  character is desired, rather than an escape sequence, \n\\f1\\fs18 %%\n\\f3\\fs20  may be used)\\\n\\'96  Optional flags that modify the style of formatting:\\\n\\pard\\tx1170\\tx1890\\pardeftab397\\li1890\\fi-990\\ri720\\sb60\\sa60\\partightenfactor0\n\\ls2\\ilvl0\n\\f12\\fs18 \\cf0 \\'a5\t\n\\f1 -\n\\f3\\fs20  :\tThe value is left-justified with the field (as opposed to the default of right-justification).\\\n\\ls2\\ilvl0\n\\f12\\fs18 \\'a5\t\n\\f1 +\n\\f3\\fs20  :\tThe sign of the value is always prepended, even if the value is positive (as opposed to the default of appending the sign only if the value is negative).\\\n\\pard\\tx1170\\tx1890\\pardeftab397\\li1890\\fi-990\\ri720\\sb60\\sa60\\partightenfactor0\n\\ls2\\ilvl0\n\\f12 \\cf0 \\'a5\t\n\\f7\\i space\n\\f3\\i0  :\tThe value is prepended by a space when a sign is not prepended.  This is ignored if the \n\\f1\\fs18 +\n\\f3\\fs20  flag is present, since values are then always prepended by a sign.\\\n\\pard\\tx1170\\tx1890\\pardeftab397\\li1890\\fi-990\\ri720\\sb60\\sa60\\partightenfactor0\n\\ls2\\ilvl0\n\\f12\\fs18 \\cf0 \\'a5\t\n\\f1 #\n\\f3\\fs20  :\tAn alternative format is used.  For \n\\f1\\fs18 %o\n\\f3\\fs20 , at least one leading zero is always produced.  For \n\\f1\\fs18 %x\n\\f3\\fs20  and \n\\f1\\fs18 %X\n\\f3\\fs20 , \n\\f1\\fs18 0x\n\\f3\\fs20  or \n\\f1\\fs18 0X\n\\f3\\fs20  (respectively) is prepended if the value is nonzero.  For \n\\f1\\fs18 %f\n\\f3\\fs20 , \n\\f1\\fs18 %F\n\\f3\\fs20 , \n\\f1\\fs18 %e\n\\f3\\fs20 , \n\\f1\\fs18 %E\n\\f3\\fs20 , \n\\f1\\fs18 %g\n\\f3\\fs20 , and \n\\f1\\fs18 %G\n\\f3\\fs20 , a decimal point is forced even if no zeros follow.\\\n\\ls2\\ilvl0\n\\f12\\fs18 \\'a5\t\n\\f1 0\n\\f3\\fs20  :\tLeading zeros are used to pad the field instead of spaces.  This flag is ignored if the left-justification flag, \n\\f1\\fs18 -\n\\f3\\fs20 , is present.  It is also ignored for \n\\f1\\fs18 integer\n\\f3\\fs20  values, if a precision is specified.\\\n\\pard\\pardeftab397\\li907\\fi-187\\ri720\\sb60\\sa60\\partightenfactor0\n\\ls3\\ilvl0\\cf0 \\'96  An optional minimum field width, specified as an integer value.  Fields will be padded out to this minimum width.  Padding will be done with space characters by default (or with zeros, if the \n\\f1\\fs18 0\n\\f3\\fs20  flag is used), on the left by default (or on the right, if the \n\\f1\\fs18 -\n\\f3\\fs20  flag is used).\\\n\\'96  An optional precision, given as an integer value preceded by a \n\\f1\\fs18 .\n\\f3\\fs20  character.  If no integer value follows the \n\\f1\\fs18 .\n\\f3\\fs20  character, a precision of zero will be used.  For integer values of \n\\f1\\fs18 x\n\\f3\\fs20  (formatted with \n\\f1\\fs18 %d\n\\f3\\fs20 , \n\\f1\\fs18 %i\n\\f3\\fs20 , \n\\f1\\fs18 %o\n\\f3\\fs20 , \n\\f1\\fs18 %x\n\\f3\\fs20 , or \n\\f1\\fs18 %X\n\\f3\\fs20 ) the precision specifies the minimum number of digits that will appear (with extra zeros on the left if necessary), with a default precision of \n\\f1\\fs18 1\n\\f2\\fs20 .\n\\f3   For float values of \n\\f1\\fs18 x\n\\f3\\fs20  formatted with \n\\f1\\fs18 %f\n\\f3\\fs20 , \n\\f1\\fs18 %F\n\\f3\\fs20 , \n\\f1\\fs18 %e\n\\f3\\fs20 , \n\\f1\\fs18 %E\n\\f3\\fs20 , \n\\f1\\fs18 %g\n\\f3\\fs20 , or \n\\f1\\fs18 %G\n\\f3\\fs20 , the precision specifies the minimum number of digits that will appear to the right of the decimal point (with extra zeros on the right if necessary), with a default precision of \n\\f1\\fs18 6\n\\f2\\fs20 .\\\n\\ls3\\ilvl0\n\\f3 \\'96  A format specifier.  For \n\\f1\\fs18 integer\n\\f3\\fs20  values, this may be \n\\f1\\fs18 %d\n\\f3\\fs20  or \n\\f1\\fs18 %i\n\\f3\\fs20  (producing base-10 output; there is no difference between the two), \n\\f1\\fs18 %o\n\\f3\\fs20  (producing base-8 or octal output), \n\\f1\\fs18 %x\n\\f3\\fs20  (producing base-16 hexadecimal output using lowercase letters), or \n\\f1\\fs18 %X\n\\f3\\fs20  (producing base-16 hexadecimal output using uppercase letters).  For \n\\f1\\fs18 float\n\\f3\\fs20  values, this may be \n\\f1\\fs18 %f\n\\f3\\fs20  or \n\\f1\\fs18 %F\n\\f3\\fs20  to produce decimal notation (of the form \n\\f1\\fs18 [\\uc0\\u8722 ]ddd.ddd\n\\f3\\fs20 ; there is no difference between the two), \n\\f1\\fs18 %e\n\\f3\\fs20  or \n\\f1\\fs18 %E\n\\f3\\fs20  to produce scientific notation (of the form \n\\f1\\fs18 [\\uc0\\u8722 ]d.ddde\\'b1dd\n\\f3\\fs20  or \n\\f1\\fs18 [\\uc0\\u8722 ]d.dddE\\'b1dd\n\\f3\\fs20 , respectively), or \n\\f1\\fs18 %g\n\\f3\\fs20  or \n\\f1\\fs18 %G\n\\f3\\fs20  to produce either decimal notation or scientific notation (using the formatting of \n\\f1\\fs18 %f\n\\f3\\fs20  / \n\\f1\\fs18 %e\n\\f3\\fs20  or \n\\f1\\fs18 %F\n\\f3\\fs20  / \n\\f1\\fs18 %E\n\\f3\\fs20 , respectively) on a per-value basis, depending upon the range of the value.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Note that relative to the standard C/C++ \n\\f1\\fs18 printf()\n\\f3\\fs20 -style behavior, there are a few differences: (1) only a single escape sequence may be present in the format string, (2) the use of \n\\f1\\fs18 *\n\\f3\\fs20  to defer field width and precision values to a passed parameter is not supported, (3) only \n\\f1\\fs18 integer\n\\f3\\fs20  and \n\\f1\\fs18 float\n\\f3\\fs20  values of \n\\f1\\fs18 x\n\\f3\\fs20  are supported, (4) only the \n\\f1\\fs18 %d\n\\f3\\fs20 , \n\\f1\\fs18 %i\n\\f3\\fs20 , \n\\f1\\fs18 %o\n\\f3\\fs20 , \n\\f1\\fs18 %x\n\\f3\\fs20 , \n\\f1\\fs18 %X\n\\f3\\fs20 , \n\\f1\\fs18 %f\n\\f3\\fs20 , \n\\f1\\fs18 %F\n\\f3\\fs20 , \n\\f1\\fs18 %e\n\\f3\\fs20 , \n\\f1\\fs18 %E\n\\f3\\fs20 , \n\\f1\\fs18 %g\n\\f3\\fs20 , and \n\\f1\\fs18 %G\n\\f3\\fs20  format specifiers are supported, and (5) no length modifiers may be supplied, since Eidos does not support different sizes of the \n\\f1\\fs18 integer\n\\f3\\fs20  and \n\\f1\\fs18 float\n\\f3\\fs20  types.  Note also that the Eidos conventions of emitting \n\\f1\\fs18 INF\n\\f3\\fs20  and \n\\f1\\fs18 NAN\n\\f3\\fs20  for infinities and Not-A-Number values respectively is not honored by this function; the strings generated for such values are platform-dependent, following the implementation definition of the C++ compiler used to build Eidos, since \n\\f1\\fs18 format()\n\\f3\\fs20  calls through to \n\\f1\\fs18 snprintf()\n\\f3\\fs20  to assemble the final string values.\\\nFor example, \n\\f1\\fs18 format(\"A number: %+7.2f\", c(-4.1, 15.375, 8))\n\\f3\\fs20  will produce a vector with three elements: \n\\f1\\fs18 \"A number:   -4.10\" \"A number:  +15.38\" \"A number:   +8.00\"\n\\f2\\fs20 .\n\\f3   The precision of \n\\f1\\fs18 .2\n\\f3\\fs20  results in two digits after the decimal point, the minimum field width of \n\\f1\\fs18 7\n\\f3\\fs20  results in padding of the values on the left (with spaces) to a minimum of seven characters, the flag \n\\f1\\fs18 +\n\\f3\\fs20  causes a sign to be shown on positive values as well as negative values, and the format specifier \n\\f1\\fs18 f\n\\f3\\fs20  leads to the \n\\f1\\fs18 float\n\\f3\\fs20  values of \n\\f1\\fs18 x\n\\f3\\fs20  being formatted in base-10 decimal.  One \n\\f1\\fs18 string\n\\f3\\fs20  value is produced in the result vector for each value in the parameter \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   These values could then be merged into a single string with \n\\f1\\fs18 paste()\n\\f3\\fs20 , for example, or printed with \n\\f1\\fs18 print()\n\\f3\\fs20  or \n\\f1\\fs18 cat()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical$)identical(*\\'a0x, *\\'a0y, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a \n\\f1\\fs18 logical\n\\f3\\fs20  value indicating \n\\f0\\b whether two or more values are identical\n\\f3\\b0 .  For two values \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 , this will return \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  have exactly the same type and size, and all of their corresponding elements are exactly the same, and (for matrices and arrays) their dimensions are identical; otherwise it will return \n\\f1\\fs18 F\n\\f3\\fs20 .  Additional parameters beyond \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are compared to x in the same manner, and \n\\f1\\fs18 T\n\\f3\\fs20  is returned only if all of the parameters are identical.\\\nThe test here is for \n\\f7\\i exact\n\\f3\\i0  equality; an \n\\f1\\fs18 integer\n\\f3\\fs20  value of \n\\f1\\fs18 1\n\\f3\\fs20  is not considered identical to a \n\\f1\\fs18 float\n\\f3\\fs20  value of \n\\f1\\fs18 1.0\n\\f3\\fs20 , for example.  Elements in \n\\f1\\fs18 object\n\\f3\\fs20  values must be literally the same element, not simply identical in all of their properties.  Type promotion is never done.  For testing whether two values are the same, this is generally preferable to the use of operator\\'a0\n\\f1\\fs18 ==\n\\f3\\fs20  or operator\\'a0\n\\f1\\fs18 !=\n\\f3\\fs20 ; see the discussion at section 2.5.1.  Note that \n\\f1\\fs18 identical(NULL,NULL)\n\\f3\\fs20  and \n\\f1\\fs18 identical(NAN, NAN)\n\\f3\\fs20  are both \n\\f1\\fs18 T\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)ifelse(logical\\'a0test, *\\'a0trueValues, *\\'a0falseValues)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the result of a \n\\f0\\b vector conditional\n\\f3\\b0  operation: a vector composed of values from \n\\f1\\fs18 trueValues\n\\f3\\fs20 , for indices where \n\\f1\\fs18 test\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , and values from \n\\f1\\fs18 falseValues\n\\f3\\fs20 , for indices where \n\\f1\\fs18 test\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 .  The lengths of \n\\f1\\fs18 trueValues\n\\f3\\fs20  and \n\\f1\\fs18 falseValues\n\\f3\\fs20  must either be equal to \n\\f1\\fs18 1\n\\f3\\fs20  or to the length of \n\\f1\\fs18 test\n\\f3\\fs20 ; however, \n\\f1\\fs18 trueValues\n\\f3\\fs20  and \n\\f1\\fs18 falseValues\n\\f3\\fs20  don\\'92t need to be the same length as each other.  Furthermore, the type of \n\\f1\\fs18 trueValues\n\\f3\\fs20  and \n\\f1\\fs18 falseValues\n\\f3\\fs20  must be the same (including, if they are \n\\f1\\fs18 object\n\\f3\\fs20  type, their element type).  The return will be of the same length as \n\\f1\\fs18 test\n\\f3\\fs20 , and of the same type as \n\\f1\\fs18 trueValues\n\\f3\\fs20  and \n\\f1\\fs18 falseValues\n\\f3\\fs20 .  Each element of the return vector will be taken from the corresponding element of \n\\f1\\fs18 trueValues\n\\f3\\fs20  if the corresponding element of \n\\f1\\fs18 test\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , or from the corresponding element of \n\\f1\\fs18 falseValues\n\\f3\\fs20  if the corresponding element of \n\\f1\\fs18 test\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 ; if the vector from which the value is to be taken (i.e., \n\\f1\\fs18 trueValues\n\\f3\\fs20  or \n\\f1\\fs18 falseValues\n\\f3\\fs20 ) has a length of \n\\f1\\fs18 1\n\\f3\\fs20 , that single value is used repeatedly, recycling the vector.\\cf2 \\expnd0\\expndtw0\\kerning0\n  If \n\\f1\\fs18 test\n\\f3\\fs20 , \n\\f1\\fs18 trueValues\n\\f3\\fs20 , and/or \n\\f1\\fs18 falseValues\n\\f3\\fs20  are matrices or arrays, that will be ignored by \n\\f1\\fs18 ifelse()\n\\f3\\fs20  \n\\f7\\i except\n\\f3\\i0  that the result will be of the same dimensionality as \n\\f1\\fs18 test\n\\f3\\fs20 .\\cf0 \\kerning1\\expnd0\\expndtw0 \\\nThis is quite similar to a function in R of the same name; note, however, that Eidos evaluates all arguments to functions calls immediately, so \n\\f1\\fs18 trueValues\n\\f3\\fs20  and \n\\f1\\fs18 falseValues\n\\f3\\fs20  will be evaluated fully regardless of the values in \n\\f1\\fs18 test\n\\f3\\fs20 , unlike in R.  Value expressions without side effects are therefore recommended.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)isClose(float\\'a0x, float\\'a0y, [float$\\'a0rtol\\'a0=\\'a01.0e-05], [float$\\'a0atol\\'a0=\\'a01.0e-08], [logical$\\'a0equalNAN\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a logical vector indicating \n\\f0\\b whether each pair of values in \n\\f9\\fs18 x\n\\f0\\fs20  and \n\\f9\\fs18 y\n\\f0\\fs20  are \\'93close\\'94\n\\f3\\b0 ; if any pair of values is not close, returns \n\\f1\\fs18 F\n\\f3\\fs20 .  See the \n\\f1\\fs18 allClose()\n\\f3\\fs20  function for an efficient way to test whether \n\\f7\\i all\n\\f3\\i0  pairs of values in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are close.\\\nA pair of values \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  is considered \\'93close\\'94 according to the following criteria.  If both \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  are finite, they are close if \n\\f1\\fs18 abs(a \\uc0\\u8722  b) <= (atol + rtol * abs(b))\n\\f3\\fs20 .  If both \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  are infinite, they are close if they have the same sign.  If both \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  are \n\\f1\\fs18 NAN\n\\f3\\fs20 , they are close if \n\\f1\\fs18 equalNAN\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 .  In all other cases, \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  are not close.  For finite values, \n\\f1\\fs18 rtol\n\\f3\\fs20  thus defines a relative tolerance, and \n\\f1\\fs18 atol\n\\f3\\fs20  an absolute tolerance; the relative difference \n\\f1\\fs18 rtol * abs(b)\n\\f3\\fs20  and the absolute difference \n\\f1\\fs18 atol\n\\f3\\fs20  are added together and compared against the absolute difference between \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20  to determine closeness.\\\nNote that the default value for \n\\f1\\fs18 atol\n\\f3\\fs20  is not appropriate when comparing numbers with magnitudes much smaller than one; be sure to select \n\\f1\\fs18 atol\n\\f3\\fs20  for the use case at hand, especially for defining the threshold below which a non-zero value \n\\f1\\fs18 a\n\\f3\\fs20  will be considered \\'93close\\'94 to a very small or zero value \n\\f1\\fs18 b\n\\f3\\fs20 .  Note also that \n\\f1\\fs18 isClose()\n\\f3\\fs20  is not symmetric in \n\\f1\\fs18 a\n\\f3\\fs20  and \n\\f1\\fs18 b\n\\f3\\fs20 ; it assumes that b is the reference value for calculating the relative difference.\\\nRegarding how values in \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are paired, three cases are supported.  If \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are the same length, then \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  are paired element-wise; if \n\\f1\\fs18 x\n\\f3\\fs20  is singleton, the single \n\\f1\\fs18 x\n\\f3\\fs20  value is paired with each value in \n\\f1\\fs18 y\n\\f3\\fs20 ; or if \n\\f1\\fs18 y\n\\f3\\fs20  is singleton, each value in \n\\f1\\fs18 x\n\\f3\\fs20  is paired with the single \n\\f1\\fs18 y\n\\f3\\fs20  value.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(integer$)length(*\\'a0x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b size\n\\f3\\b0  (e.g., length) of \n\\f1\\fs18 x\n\\f3\\fs20 : the number of elements contained in \n\\f1\\fs18 x\n\\f3\\fs20 .  Note that \n\\f1\\fs18 length()\n\\f3\\fs20  is a synonym for \n\\f1\\fs18 size()\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (integer)match(*\\'a0x, *\\'a0table)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a vector of the \n\\f0\\b positions of (first) matches\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  in \n\\f1\\fs18 table\n\\f3\\fs20 .  Type promotion is not performed; x and \n\\f1\\fs18 table\n\\f3\\fs20  must be of the same type.  For each element of \n\\f1\\fs18 x\n\\f3\\fs20 , the corresponding element in the result will give the position of the first match for that element of \n\\f1\\fs18 x\n\\f3\\fs20  in \n\\f1\\fs18 table\n\\f3\\fs20 ; if the element has no match in \n\\f1\\fs18 table\n\\f3\\fs20 , the element in the result vector will be \n\\f1\\fs18 -1\n\\f3\\fs20 .  The result is therefore a vector of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 .  If a \n\\f1\\fs18 logical\n\\f3\\fs20  result is desired, with \n\\f1\\fs18 T\n\\f3\\fs20  indicating that a match was found for the corresponding element of \n\\f1\\fs18 x\n\\f3\\fs20 , use \n\\f1\\fs18 (match(x, table) >= 0)\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)order(+\\'a0x, [logical$\n\\f2 \\'a0\n\\f1 ascending\n\\f2 \\'a0\n\\f1 =\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b vector of sorting indices\n\\f3\\b0  for \n\\f1\\fs18 x\n\\f3\\fs20 : a new \n\\f1\\fs18 integer\n\\f3\\fs20  vector of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , containing the indices into \n\\f1\\fs18 x\n\\f3\\fs20  that would sort \n\\f1\\fs18 x\n\\f3\\fs20 .  In other words, \n\\f1\\fs18 x[order(x)]==sort(x)\n\\f3\\fs20 .  This can be useful for more complex sorting problems, such as sorting several vectors in parallel by a sort order determined by one of the vectors.  If the optional \n\\f1\\fs18 logical\n\\f3\\fs20  parameter \n\\f1\\fs18 ascending\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), then the sorted order will be ascending; if it is \n\\f1\\fs18 F\n\\f3\\fs20 , the sorted order will be descending.  The ordering is determined according to the same logic as the \n\\f1\\fs18 <\n\\f3\\fs20  and \n\\f1\\fs18 >\n\\f3\\fs20  operators in Eidos.  To easily sort vectors in a single step, use \n\\f1\\fs18 sort()\n\\f3\\fs20  or \n\\f1\\fs18 sortBy()\n\\f3\\fs20 , for non-\n\\f1\\fs18 object\n\\f3\\fs20  and \n\\f1\\fs18 object\n\\f3\\fs20  vectors respectively.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string$)paste(..., [string$\\'a0sep\\'a0=\\'a0\" \"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a \n\\f0\\b joined string\n\\f3\\b0  composed from the \n\\f1\\fs18 string\n\\f3\\fs20  representations of the elements of the parameters passed in, taken in order, joined together by \n\\f1\\fs18 sep\n\\f3\\fs20 .  Although this function is based upon the R \n\\f1\\fs18 paste()\n\\f3\\fs20  function of the same name, note that it is much simpler and less powerful; in particular, the result is always a singleton \n\\f1\\fs18 string\n\\f3\\fs20 , rather than returning a non-singleton \n\\f1\\fs18 string\n\\f3\\fs20  vector when one of the parameters is a non-singleton.  The string representation used by \n\\f1\\fs18 paste()\n\\f3\\fs20  is the same as that emitted by \n\\f1\\fs18 cat()\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string$)paste0(...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a \n\\f0\\b joined string\n\\f3\\b0  composed from the \n\\f1\\fs18 string\n\\f3\\fs20  representations of the elements of the parameters passed in, taken in order, joined together with no separator.  This function is identical to \n\\f1\\fs18 paste()\n\\f3\\fs20 , except that no separator is used.  Note that this differs from the semantics of \n\\f1\\fs18 paste0()\n\\f3\\fs20  in R.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)print(*\n\\f2 \\'a0\n\\f1 x\\cf2 , [logical$\\'a0error\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints output\n\\f3\\b0  to Eidos\\'92s output stream.  The value \n\\f1\\fs18 x\n\\f3\\fs20  that is output may be of any type.  A newline is appended to the output.  See \n\\f1\\fs18 cat()\n\\f3\\fs20  for a discussion of the differences between \n\\f1\\fs18 print()\n\\f3\\fs20  and \n\\f1\\fs18 cat()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 By default (when \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 ), the output is sent to the standard Eidos output stream.  When running at the command line, this sends it to \n\\f1\\fs18 stdout\n\\f3\\fs20 ; when running in SLiMgui, this sends it to the simulation window\\'92s output textview.  If \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the output is instead sent to the Eidos error stream.  When running at the command line, this sends it to \n\\f1\\fs18 stderr\n\\f3\\fs20 ; when running in SLiMgui, the output is routed to the simulation\\'92s debugging output window.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)rev(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b reverse\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a new vector with the same elements as \n\\f1\\fs18 x\n\\f3\\fs20 , but in the opposite order.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer$)size(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b size\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : the number of elements contained in \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\n  Note that \n\\f1\\fs18 length()\n\\f3\\fs20  is a synonym for \n\\f1\\fs18 size()\n\\f3\\fs20 .\n\\f2 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (+)sort(+\\'a0x, [logical$\n\\f2 \\'a0\n\\f1 ascending\n\\f2 \\'a0\n\\f1 =\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b sorted copy\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a new vector with the same elements as \n\\f1\\fs18 x\n\\f3\\fs20 , but in sorted order.  If the optional \n\\f1\\fs18 logical\n\\f3\\fs20  parameter \n\\f1\\fs18 ascending\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), then the sorted order will be ascending; if it is \n\\f1\\fs18 F\n\\f3\\fs20 , the sorted order will be descending.  The ordering is determined according to the same logic as the \n\\f1\\fs18 <\n\\f3\\fs20  and \n\\f1\\fs18 >\n\\f3\\fs20  operators in Eidos.  To sort an \n\\f1\\fs18 object\n\\f3\\fs20  vector, use \n\\f1\\fs18 sortBy()\n\\f2\\fs20 .\n\\f3   To obtain indices for sorting, use \n\\f1\\fs18 order()\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (object)sortBy(object\\'a0x, string$\n\\f2 \\'a0\n\\f1 property, [logical$\n\\f2 \\'a0\n\\f1 ascending\n\\f2 \\'a0\n\\f1 =\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b sorted copy\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a new vector with the same elements as \n\\f1\\fs18 x\n\\f3\\fs20 , but in sorted order.  If the optional \n\\f1\\fs18 logical\n\\f3\\fs20  parameter \n\\f1\\fs18 ascending\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), then the sorted order will be ascending; if it is \n\\f1\\fs18 F\n\\f3\\fs20 , the sorted order will be descending.  The ordering is determined according to the same logic as the \n\\f1\\fs18 <\n\\f3\\fs20  and \n\\f1\\fs18 >\n\\f3\\fs20  operators in Eidos.  The \n\\f1\\fs18 property\n\\f3\\fs20  argument gives the name of the property within the elements of \n\\f1\\fs18 x\n\\f3\\fs20  according to which sorting should be done.  This must be a simple property name; it cannot be a property path.  For example, to sort a \n\\f1\\fs18 Mutation\n\\f3\\fs20  vector by the selection coefficients of the mutations, you would simply pass \n\\f1\\fs18 \"selectionCoeff\"\n\\f3\\fs20 , including the quotes, for \n\\f1\\fs18 property\n\\f2\\fs20 .\n\\f3   To sort a non-\n\\f1\\fs18 object\n\\f3\\fs20  vector, use \n\\f1\\fs18 sort()\n\\f3\\fs20 .  To obtain indices for sorting, use \n\\f1\\fs18 order()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)str(*\n\\f2 \\'a0\n\\f1 x\\cf2 , [logical$\\'a0error\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints the structure\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 : a summary of its type and the values it contains.  If \n\\f1\\fs18 x\n\\f3\\fs20  is an \n\\f1\\fs18 object\n\\f2\\fs20 ,\n\\f3  note that \n\\f1\\fs18 str()\n\\f3\\fs20  produces different results from the \n\\f1\\fs18 str()\n\\f3\\fs20  method of \n\\f1\\fs18 x\n\\f3\\fs20 ; the \n\\f1\\fs18 str()\n\\f3\\fs20  function prints the external structure of \n\\f1\\fs18 x\n\\f3\\fs20  (the fact that it is an object, and the number and type of its elements), whereas the \n\\f1\\fs18 str()\n\\f3\\fs20  method prints the internal structure of \n\\f1\\fs18 x\n\\f3\\fs20  (the external structure of all the properties contained by \n\\f1\\fs18 x\n\\f3\\fs20 ).\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 By default (when \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 ), the output is sent to the standard Eidos output stream.  When running at the command line, this sends it to \n\\f1\\fs18 stdout\n\\f3\\fs20 ; when running in SLiMgui, this sends it to the simulation window\\'92s output textview.  If \n\\f1\\fs18 error\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the output is instead sent to the Eidos error stream.  When running at the command line, this sends it to \n\\f1\\fs18 stderr\n\\f3\\fs20 ; when running in SLiMgui, the output is routed to the simulation\\'92s debugging output window.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)tabulate(integer\\'a0bin, [Ni$\\'a0maxbin\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns \n\\f0\\b occurrence counts\n\\f3\\b0  for each non-negative integer in \n\\f1\\fs18 bin\n\\f3\\fs20 .  Occurrence counts are tabulated into bins for each value \n\\f1\\fs18 0:maxbin\n\\f3\\fs20  in \n\\f1\\fs18 bin\n\\f3\\fs20 ; values outside that range are ignored.  The default value of \n\\f1\\fs18 maxbin\n\\f3\\fs20 , \n\\f1\\fs18 NULL\n\\f3\\fs20 , is equivalent to passing \n\\f1\\fs18 maxbin=max(0, bin)\n\\f3\\fs20 ; in other words, by default the result vector will be exactly large enough to accommodate counts for every integer in \n\\f1\\fs18 bin\n\\f3\\fs20 .  In any case, the result vector will contain \n\\f1\\fs18 maxbin+1\n\\f3\\fs20  elements (some or all of which might be zero, if the occurrence count of that integer in \n\\f1\\fs18 bin\n\\f3\\fs20  is zero).\\\nNote that the semantics of this function differ slightly from the \n\\f1\\fs18 tabulate()\n\\f3\\fs20  function in R, because R is \n\\f1\\fs18 1\n\\f3\\fs20 -based and Eidos is \n\\f1\\fs18 0\n\\f3\\fs20 -based.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)unique(*\\'a0x, [logical$\\'a0preserveOrder\\'a0=\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b unique values\n\\f3\\b0  in \n\\f1\\fs18 x\n\\f3\\fs20 .  In other words, for each value \n\\f1\\fs18 k\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20  that occurs at least once, the vector returned will contain \n\\f1\\fs18 k\n\\f3\\fs20  exactly once.  If \n\\f1\\fs18 preserveOrder\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), the order of values in \n\\f1\\fs18 x\n\\f3\\fs20  is preserved, taking the first instance of each value; this is relatively slow, with O(\n\\f7\\i n\n\\f3\\i0 ^2) performance.  If \n\\f1\\fs18 preserveOrder\n\\f3\\fs20  if \n\\f1\\fs18 F\n\\f3\\fs20  instead, the order of values in \n\\f1\\fs18 x\n\\f3\\fs20  is not preserved, and no particular ordering should be relied upon; this is relatively fast, with O(\n\\f7\\i n\n\\f3\\i0  log \n\\f7\\i n\n\\f3\\i0 ) performance.  This performance difference will only matter for large vectors, however; for most applications the default behavior can be retained whether the order of the result matters or not.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)which(logical\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b indices of \n\\f9\\fs18 T\n\\f0\\fs20  values\n\\f3\\b0  in \n\\f1\\fs18 x\n\\f3\\fs20 .  In other words, if an index \n\\f1\\fs18 k\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , then the vector returned will contain \n\\f1\\fs18 k\n\\f3\\fs20 ; if index \n\\f1\\fs18 k\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 , the vector returned will omit \n\\f1\\fs18 k\n\\f3\\fs20 .  One way to look at this is that it converts from a \n\\f1\\fs18 logical\n\\f3\\fs20  subsetting vector to an \n\\f1\\fs18 integer\n\\f3\\fs20  (index-based) subsetting vector, without changing which subset positions would be selected.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer$)whichMax(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b index of the (first) maximum value\n\\f3\\b0  in \n\\f1\\fs18 x\n\\f3\\fs20 .  In other words, if \n\\f1\\fs18 k\n\\f3\\fs20  is equal to the maximum value in \n\\f1\\fs18 x\n\\f3\\fs20 , then the vector returned will contain the index of the first occurrence of \n\\f1\\fs18 k\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3   If the maximum value is unique, the result is the same as (but more efficient than) the expression \n\\f1\\fs18 which(x==max(x))\n\\f3\\fs20 , which returns the indices of \n\\f7\\i all\n\\f3\\i0  of the occurrences of the maximum value in \n\\f1\\fs18 x\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer$)whichMin(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b index of the (first) minimum value\n\\f3\\b0  in \n\\f1\\fs18 x\n\\f3\\fs20 .  In other words, if \n\\f1\\fs18 k\n\\f3\\fs20  is equal to the minimum value in \n\\f1\\fs18 x\n\\f3\\fs20 , then the vector returned will contain the index of the first occurrence of \n\\f1\\fs18 k\n\\f3\\fs20  in \n\\f1\\fs18 x\n\\f3\\fs20 .  If the minimum value is unique, the result is the same as (but more efficient than) the expression \n\\f1\\fs18 which(x==min(x))\n\\f3\\fs20 , which returns the indices of \n\\f7\\i all\n\\f3\\i0  of the occurrences of the minimum value in \n\\f1\\fs18 x\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.6.  Value type testing and coercion functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (float)asFloat(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b conversion to \n\\f9\\fs18 float\n\\f3\\b0\\fs20  of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 string\n\\f3\\fs20  and cannot be converted to \n\\f1\\fs18 float\n\\f3\\fs20 , Eidos will throw an error.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)asInteger(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b conversion to \n\\f9\\fs18 integer\n\\f3\\b0\\fs20  of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 string\n\\f3\\fs20  or \n\\f1\\fs18 float\n\\f3\\fs20  and cannot be converted to \n\\f1\\fs18 integer\n\\f3\\fs20 , Eidos will throw an error.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)asLogical(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b conversion to \n\\f9\\fs18 logical\n\\f3\\b0\\fs20  of \n\\f1\\fs18 x\n\\f3\\fs20 .  Recall that in Eidos the empty \n\\f1\\fs18 string\n\\f3\\fs20  \n\\f1\\fs18 \"\"\n\\f3\\fs20  is considered \n\\f1\\fs18 F\n\\f3\\fs20 , and all other \n\\f1\\fs18 string\n\\f3\\fs20  values are considered \n\\f1\\fs18 T\n\\f2\\fs20 .\n\\f3   Converting \n\\f1\\fs18 INF\n\\f3\\fs20  or \n\\f1\\fs18 -INF\n\\f3\\fs20  to \n\\f1\\fs18 logical\n\\f3\\fs20  yields \n\\f1\\fs18 T\n\\f3\\fs20  (since those values are not equal to zero); converting \n\\f1\\fs18 NAN\n\\f3\\fs20  to \n\\f1\\fs18 logical\n\\f3\\fs20  throws an error.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string)asString(+\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b conversion to \n\\f9\\fs18 string\n\\f3\\b0\\fs20  of \n\\f1\\fs18 x\n\\f2\\fs20 .\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\n  Note that \n\\f1\\fs18 asString(NULL)\n\\f3\\fs20  returns \n\\f1\\fs18 \"NULL\"\n\\f3\\fs20  even though \n\\f1\\fs18 NULL\n\\f3\\fs20  is zero-length.\n\\f2 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string$)elementType(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b element type\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , as a \n\\f1\\fs18 string\n\\f3\\fs20 .  For the non-\n\\f1\\fs18 object\n\\f3\\fs20  types, the element type is the same as the type: \n\\f1\\fs18 \"NULL\"\n\\f3\\fs20 , \n\\f1\\fs18 \"logical\"\n\\f3\\fs20 , \n\\f1\\fs18 \"integer\"\n\\f3\\fs20 , \n\\f1\\fs18 \"float\"\n\\f3\\fs20 , or \n\\f1\\fs18 \"string\"\n\\f3\\fs20 .  For \n\\f1\\fs18 object\n\\f3\\fs20  type, however, \n\\f1\\fs18 elementType()\n\\f3\\fs20  returns the name of the type of element contained by the object, such as \n\\f1\\fs18 \"Species\"\n\\f3\\fs20  or \n\\f1\\fs18 \"Mutation\"\n\\f3\\fs20  in the Context of SLiM.  Contrast this with \n\\f1\\fs18 type()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isFloat(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 float\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isInteger(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 integer\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isLogical(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 logical\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isNULL(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 NULL\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isObject(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 object\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)isString(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns \n\\f1\\fs18 T\n\\f3\\fs20  if \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f0\\b is \n\\f9\\fs18 string\n\\f0\\fs20  type\n\\f3\\b0 , \n\\f1\\fs18 F\n\\f3\\fs20  otherwise.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string$)type(*\n\\f2 \\'a0\n\\f1 x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b type\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , as a \n\\f1\\fs18 string\n\\f3\\fs20 : \n\\f1\\fs18 \"NULL\"\n\\f3\\fs20 , \n\\f1\\fs18 \"logical\"\n\\f3\\fs20 , \n\\f1\\fs18 \"integer\"\n\\f3\\fs20 , \n\\f1\\fs18 \"float\"\n\\f3\\fs20 , \n\\f1\\fs18 \"string\"\n\\f3\\fs20 , or \n\\f1\\fs18 \"object\"\n\\f3\\fs20 .  Contrast this with \n\\f1\\fs18 elementType()\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.7.  String manipulation functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 (lis)grep(string$\\'a0pattern, string\\'a0x, [logical$\\'a0ignoreCase\\'a0=\\'a0F], [string$\\'a0grammar\\'a0=\\'a0\"ECMAScript\"], [string$\\'a0value\\'a0=\\'a0\"indices\"], [logical$\\'a0fixed\\'a0=\\'a0F], [logical$\\'a0invert\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Searches for \n\\f0\\b regular expression matches\n\\f3\\b0  in the string-elements of \n\\f1\\fs18 x\n\\f3\\fs20 .  Regular expressions (regexes) express patterns that strings can either match or not match; they are very widely used in programming languages and terminal shells.  The topic of regexes is very complex, and a great deal of information about them can be found online, including examples and tutorials; this manual will not attempt to document the topic in detail.\\\nThe \n\\f1\\fs18 grep()\n\\f3\\fs20  function uses a regex supplied in \n\\f1\\fs18 pattern\n\\f3\\fs20 , looking for matches for the regex in each element of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 ignoreCase\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), the pattern matching will be case sensitive (i.e., uppercase versus lowercase will matter); if it is T, the pattern matching will be case-insensitive.\\\nThe \n\\f1\\fs18 grammar\n\\f3\\fs20  parameter determines the regex grammar used to find matches.  Several options are available.  The default, \n\\f1\\fs18 \"ECMAScript\"\n\\f3\\fs20 , is a straightforward regex grammar, the specification for which can be found at {\\field{\\*\\fldinst{HYPERLINK \"https://www.cplusplus.com/reference/regex/ECMAScript/\"}}{\\fldrslt \\cf3 \\ul \\ulc3 https://www.cplusplus.com/reference/regex/ECMAScript/}} among many other links.  The \n\\f1\\fs18 \"basic\"\n\\f3\\fs20  grammar uses POSIX basic regular expressions, often called BRE; this is documented at {\\field{\\*\\fldinst{HYPERLINK \"https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions\"}}{\\fldrslt \\cf3 \\ul \\ulc3 https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions}}.  The \n\\f1\\fs18 \"extended\"\n\\f3\\fs20  grammar uses POSIX extended regular expressions, often called ERE; this is documented at {\\field{\\*\\fldinst{HYPERLINK \"https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions\"}}{\\fldrslt \\cf3 \\ul \\ulc3 https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions}}.  The \n\\f1\\fs18 \"awk\"\n\\f3\\fs20  grammar is based upon the \n\\f1\\fs18 \"extended\"\n\\f3\\fs20  grammar, with more escapes for non-printing characters.  The \n\\f1\\fs18 \"grep\"\n\\f3\\fs20  and \n\\f1\\fs18 \"egrep\"\n\\f3\\fs20  grammars are based upon the \n\\f1\\fs18 \"basic\"\n\\f3\\fs20  and \n\\f1\\fs18 \"extended\"\n\\f3\\fs20  grammars, respectively, but also allow newline characters (\n\\f1\\fs18 \"\\\\n\"\n\\f3\\fs20 ) to separate alternations.  If you are not sure which grammar you want to use, \n\\f1\\fs18 \"ECMAScript\"\n\\f3\\fs20  is recommended.  All of these grammars are implemented internally in Eidos using the C++ \n\\f1\\fs18 <regex>\n\\f3\\fs20  library, so if you need clarification on the details of a grammar, you can search for related C++ materials online.\\\nInformation about the matches found is returned in one of four ways.  If \n\\f1\\fs18 value\n\\f3\\fs20  is \n\\f1\\fs18 \"indices\"\n\\f3\\fs20  (the default), an \n\\f1\\fs18 integer\n\\f3\\fs20  vector is returned containing the index in \n\\f1\\fs18 x\n\\f3\\fs20  for each match.  If \n\\f1\\fs18 value\n\\f3\\fs20  is \n\\f1\\fs18 \"elements\"\n\\f3\\fs20 , a \n\\f1\\fs18 string\n\\f3\\fs20  vector is returned containing the actual string-elements of \n\\f1\\fs18 x\n\\f3\\fs20  for each match.  If \n\\f1\\fs18 value\n\\f3\\fs20  is \n\\f1\\fs18 \"matches\"\n\\f3\\fs20 , a \n\\f1\\fs18 string\n\\f3\\fs20  vector is returned containing only the substring that matched, within each string-element in \n\\f1\\fs18 x\n\\f3\\fs20  that matched (if more than one substring in a given element matched, the \n\\f7\\i first\n\\f3\\i0  match is returned).  Finally, if \n\\f1\\fs18 value\n\\f3\\fs20  is \n\\f1\\fs18 \"logical\"\n\\f3\\fs20  a \n\\f1\\fs18 logical\n\\f3\\fs20  vector is returned, of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , containing \n\\f1\\fs18 T\n\\f3\\fs20  where the corresponding element of \n\\f1\\fs18 x\n\\f3\\fs20  matched, or \n\\f1\\fs18 F\n\\f3\\fs20  where it did not match.  This function therefore encapsulates the functionality of both the \n\\f1\\fs18 grep()\n\\f3\\fs20  and \n\\f1\\fs18 grepl()\n\\f3\\fs20  functions of R; use \n\\f1\\fs18 value=\"logical\"\n\\f3\\fs20  for functionality like that of R\\'92s \n\\f1\\fs18 grepl()\n\\f3\\fs20 .\\\nIf \n\\f1\\fs18 fixed\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), matching is determined using \n\\f1\\fs18 pattern\n\\f3\\fs20  following the specified regex grammar as described above.  If \n\\f1\\fs18 fixed\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , matching is instead determined using \n\\f1\\fs18 pattern\n\\f3\\fs20  as a \n\\f1\\fs18 string\n\\f3\\fs20  value to be matched \\'93as is\\'94, rather than as a regular expression; the \n\\f1\\fs18 grammar\n\\f3\\fs20  specified does not matter in this case, but \n\\f1\\fs18 ignoreCase\n\\f3\\fs20  still applies.  This could be thought of as another \n\\f1\\fs18 grammar\n\\f3\\fs20  value, really, meaning \\'93no grammar\\'94, but it is supplied as a separate flag following R.\\\nFinally, if \n\\f1\\fs18 invert\n\\f3\\fs20  if \n\\f1\\fs18 F\n\\f3\\fs20  (the default) matching proceeds as normal for the chosen regex grammar, whereas if \n\\f1\\fs18 invert\n\\f3\\fs20  if \n\\f1\\fs18 T\n\\f3\\fs20  matching is inverted: indices, elements, or \n\\f1\\fs18 logical\n\\f3\\fs20  values are returned for the elements of \n\\f1\\fs18 x\n\\f3\\fs20  that did \n\\f7\\i not\n\\f3\\i0  match.  If \n\\f1\\fs18 invert\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the \n\\f1\\fs18 value\n\\f3\\fs20  parameter may not be \n\\f1\\fs18 \"matches\"\n\\f3\\fs20 .\\\nNote that there is not presently any way to extract subpattern matches, nor is there any way to perform replacements of matches.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)nchar(string\\'a0x)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns a vector of the \n\\f0\\b number of characters\n\\f3\\b0  in the string-elements of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)strcontains(string\\'a0x, string$\\'a0s, [integer$\\'a0pos\\'a0=\\'a00])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b occurrence of a string\n\\f3\\b0  specified by \n\\f1\\fs18 s\n\\f3\\fs20  in each of the elements of \n\\f1\\fs18 x\n\\f3\\fs20 , starting at position \n\\f1\\fs18 pos\n\\f3\\fs20 .  Position \n\\f1\\fs18 0\n\\f3\\fs20 , the default, is the beginning of \n\\f1\\fs18 x\n\\f3\\fs20 ; a position of \n\\f1\\fs18 0\n\\f3\\fs20  means the entire string is searched.  A starting search position that is at or beyond the end of a given element of \n\\f1\\fs18 x\n\\f3\\fs20  is not an error; it just implies that a match will not be found in that element.  The existences of matches are returned as a \n\\f1\\fs18 logical\n\\f3\\fs20  vector; if a match was found in a given element, the corresponding value in the returned vector is \n\\f1\\fs18 T\n\\f3\\fs20 , otherwise it is \n\\f1\\fs18 F\n\\f3\\fs20 .  This function is a simplified version of \n\\f1\\fs18 strfind()\n\\f3\\fs20 , which returns the positions of matches.  The \n\\f1\\fs18 strprefix()\n\\f3\\fs20  and \n\\f1\\fs18 strsuffix()\n\\f3\\fs20  functions are also related.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)strfind(string\\'a0x, string$\\'a0s, [integer$\\'a0pos\\'a0=\\'a00])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b first occurrence of a string\n\\f3\\b0  specified by \n\\f1\\fs18 s\n\\f3\\fs20  in each of the elements of \n\\f1\\fs18 x\n\\f3\\fs20 , starting at position \n\\f1\\fs18 pos\n\\f3\\fs20 .  Position \n\\f1\\fs18 0\n\\f3\\fs20 , the default, is the beginning of \n\\f1\\fs18 x\n\\f3\\fs20 ; a position of \n\\f1\\fs18 0\n\\f3\\fs20  means the entire string is searched.  A starting search position that is at or beyond the end of a given element of \n\\f1\\fs18 x\n\\f3\\fs20  is not an error; it just implies that a match will not be found in that element.  The positions of matches are returned as an \n\\f1\\fs18 integer\n\\f3\\fs20  vector; if no match was found in a given element, the corresponding value in the returned vector is \n\\f1\\fs18 -1\n\\f3\\fs20 .  The \n\\f1\\fs18 strcontains()\n\\f3\\fs20  function may be used when a logical value (found / not found) is desired.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)strprefix(string\\'a0x, string$\\'a0s)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b occurrence of a prefix string\n\\f3\\b0  specified by \n\\f1\\fs18 s\n\\f3\\fs20  at the beginning of each of the elements of \n\\f1\\fs18 x\n\\f3\\fs20 .  The existences of prefixes are returned as a \n\\f1\\fs18 logical\n\\f3\\fs20  vector; if a given element begins with the prefix, the corresponding value in the returned vector is \n\\f1\\fs18 T\n\\f3\\fs20 , otherwise it is \n\\f1\\fs18 F\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)strsplit(string$\\'a0x, [string$\\'a0sep\\'a0=\\'a0\" \"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns \n\\f0\\b substrings\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  that were separated by the separator string \n\\f1\\fs18 sep\n\\f3\\fs20 .  Every substring defined by an occurrence of the separator is included, and thus zero-length substrings may be returned.  For example, \n\\f1\\fs18 strsplit(\".foo..bar.\", \".\")\n\\f3\\fs20  returns a string vector containing \n\\f1\\fs18 \"\"\n\\f3\\fs20 , \n\\f1\\fs18 \"foo\"\n\\f3\\fs20 , \n\\f1\\fs18 \"\"\n\\f3\\fs20 , \n\\f1\\fs18 \"bar\"\n\\f3\\fs20 , \n\\f1\\fs18 \"\"\n\\f3\\fs20 .  In that example, the empty string between \n\\f1\\fs18 \"foo\"\n\\f3\\fs20  and \n\\f1\\fs18 \"bar\"\n\\f3\\fs20  in the returned vector is present because there were two periods between \n\\f1\\fs18 foo\n\\f3\\fs20  and \n\\f1\\fs18 bar\n\\f3\\fs20  in the input string \\'96 the empty string is the substring between those two separators.  If \n\\f1\\fs18 sep\n\\f3\\fs20  is \n\\f1\\fs18 \"\"\n\\f3\\fs20 , a vector of single characters will be returned, resulting from splitting \n\\f1\\fs18 x\n\\f3\\fs20  at every position.  Note that \n\\f1\\fs18 paste()\n\\f3\\fs20  performs the inverse operation of \n\\f1\\fs18 strsplit()\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)strsuffix(string\\'a0x, string$\\'a0s)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b occurrence of a suffix string\n\\f3\\b0  specified by \n\\f1\\fs18 s\n\\f3\\fs20  at the end of each of the elements of \n\\f1\\fs18 x\n\\f3\\fs20 .  The existences of suffixes are returned as a \n\\f1\\fs18 logical\n\\f3\\fs20  vector; if a given element ends with the suffix, the corresponding value in the returned vector is \n\\f1\\fs18 T\n\\f3\\fs20 , otherwise it is \n\\f1\\fs18 F\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)substr(string\\'a0x, integer\\'a0first, [Ni\\'a0last\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns \n\\f0\\b substrings\n\\f3\\b0  extracted from the elements of \n\\f1\\fs18 x,\n\\f3\\fs20  spanning character position \n\\f1\\fs18 first\n\\f3\\fs20  to character position \n\\f1\\fs18 last\n\\f3\\fs20  (inclusive).  Character positions are numbered from \n\\f1\\fs18 0\n\\f3\\fs20  to \n\\f1\\fs18 nchar(x)-1\n\\f3\\fs20 .  Positions that fall outside of that range are legal; a substring range that encompasses no characters will produce an empty string.  If \n\\f1\\fs18 first\n\\f3\\fs20  is greater than \n\\f1\\fs18 last\n\\f3\\fs20 , an empty string will also result.  If \n\\f1\\fs18 last\n\\f3\\fs20  is NULL (the default), then the substring will extend to the end of the string.  The parameters \n\\f1\\fs18 first\n\\f3\\fs20  and \n\\f1\\fs18 last\n\\f3\\fs20  may either be singletons, specifying a single value to be used for all of the substrings, or they may be vectors of the same length as \n\\f1\\fs18 x\n\\f3\\fs20 , specifying a value for each substring.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.8.  Matrix and array functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (*)apply(*\\'a0x, integer\\'a0margin, string$\\'a0lambdaSource)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f7\\i\\fs20 \\cf4 \\expnd0\\expndtw0\\kerning0\nPrior to Eidos 1.6 / SLiM 2.6, \n\\f5\\fs18 sapply()\n\\f7\\fs20  was named \n\\f5\\fs18 apply()\n\\f7\\fs20 , and this function did not yet exist\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\i0\\b \\cf2 Applies a block of Eidos code to margins of x\n\\f3\\b0 .  This function is essentially an extension of \n\\f1\\fs18 sapply()\n\\f3\\fs20  for use with matrices and arrays; it is recommended that you fully understand \n\\f1\\fs18 sapply()\n\\f3\\fs20  before tackling this function.  As with \n\\f1\\fs18 sapply()\n\\f3\\fs20 , the lambda specified by \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  will be executed for subsets of \n\\f1\\fs18 x\n\\f3\\fs20 , and the results will be concatenated together with type-promotion in the style of \n\\f1\\fs18 c()\n\\f3\\fs20  to produce a result.  Unlike \n\\f1\\fs18 sapply()\n\\f3\\fs20 , however, the subsets of \n\\f1\\fs18 x\n\\f3\\fs20  used might be rows, columns, or higher-dimensional slices of \n\\f1\\fs18 x\n\\f3\\fs20 , rather than just single elements, depending upon the value of \n\\f1\\fs18 margin\n\\f3\\fs20 .  For \n\\f1\\fs18 apply()\n\\f3\\fs20 , \n\\f1\\fs18 x\n\\f3\\fs20  must be a matrix or array.  The \n\\f1\\fs18 apply()\n\\f3\\fs20  function in Eidos is patterned directly after the \n\\f1\\fs18 apply()\n\\f3\\fs20  function in R, and should behave identically, except that dimension indices in Eidos are zero-based whereas in R they are one-based.\\\nThe \n\\f1\\fs18 margin\n\\f3\\fs20  parameter gives the indices of dimensions of \n\\f1\\fs18 x\n\\f3\\fs20  that will be iterated over when assembling values to supply to lambdaSource.  If \n\\f1\\fs18 x\n\\f3\\fs20  is a matrix it has two dimensions: rows, of dimension index \n\\f1\\fs18 0\n\\f3\\fs20 , and columns, of dimension index \n\\f1\\fs18 1\n\\f3\\fs20 .  These are the indices of the dimension sizes returned by \n\\f1\\fs18 dim()\n\\f3\\fs20 ; \n\\f1\\fs18 dim(x)[0]\n\\f3\\fs20  gives the number of rows of \n\\f1\\fs18 x\n\\f3\\fs20 , and \n\\f1\\fs18 dim(x)[1]\n\\f3\\fs20  gives the number of columns.  These dimension indices are also apparent when subsetting \n\\f1\\fs18 x\n\\f3\\fs20 ; a subset index in position \n\\f1\\fs18 0\n\\f3\\fs20 , such as \n\\f1\\fs18 x[m,]\n\\f3\\fs20 , gives row \n\\f1\\fs18 m\n\\f3\\fs20  of \n\\f1\\fs18 x\n\\f3\\fs20 , whereas a subset index in position \n\\f1\\fs18 1\n\\f3\\fs20 , such as \n\\f1\\fs18 x[,n]\n\\f3\\fs20 , gives column \n\\f1\\fs18 n\n\\f3\\fs20  of \n\\f1\\fs18 x\n\\f3\\fs20 .  In the same manner, supplying \n\\f1\\fs18 0\n\\f3\\fs20  for \n\\f1\\fs18 margin\n\\f3\\fs20  specifies that subsets of \n\\f1\\fs18 x\n\\f3\\fs20  from \n\\f1\\fs18 x[0,]\n\\f3\\fs20  to \n\\f1\\fs18 x[m,]\n\\f3\\fs20  should be \\'93passed\\'94 to \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 , through the \n\\f1\\fs18 applyValue\n\\f3\\fs20  \\'93parameter\\'94; dimension \n\\f1\\fs18 0\n\\f3\\fs20  is iterated over, whereas dimension \n\\f1\\fs18 1\n\\f3\\fs20  is taken in aggregate since it is not included in \n\\f1\\fs18 margin\n\\f3\\fs20 .  The final effect of this is that whole rows of \n\\f1\\fs18 x\n\\f3\\fs20  are passed to \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  through \n\\f1\\fs18 applyValue\n\\f3\\fs20 .  Similarly, \n\\f1\\fs18 margin=1\n\\f3\\fs20  would specify that subsets of \n\\f1\\fs18 x\n\\f3\\fs20  from \n\\f1\\fs18 x[,0]\n\\f3\\fs20  to \n\\f1\\fs18 x[,n]\n\\f3\\fs20  should be passed to \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 , resulting in whole columns being passed.  Specifying \n\\f1\\fs18 margin=c(0,1)\n\\f3\\fs20  would indicate that dimensions \n\\f1\\fs18 0\n\\f3\\fs20  and \n\\f1\\fs18 1\n\\f3\\fs20  should both be iterated over (dimension \n\\f1\\fs18 0\n\\f3\\fs20  more rapidly), so for a matrix each each individual value of \n\\f1\\fs18 x\n\\f3\\fs20  would be passed to l\n\\f1\\fs18 ambdaSource\n\\f3\\fs20 .  Specifying \n\\f1\\fs18 margin=c(1,0)\n\\f3\\fs20  would similarly iterate over both dimensions, but dimension \n\\f1\\fs18 1\n\\f3\\fs20  more rapidly; the traversal order would therefore be different, and the dimensionality of the result would also differ (see below).  For higher-dimensional arrays dimension indices beyond \n\\f1\\fs18 1\n\\f3\\fs20  exist, and so \n\\f1\\fs18 margin=c(0,1)\n\\f3\\fs20  or \n\\f1\\fs18 margin=c(1,0)\n\\f3\\fs20  would provide slices of \n\\f1\\fs18 x\n\\f3\\fs20  to \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 , each slice having a specific row and column index.  Slices are generated by subsetting in the same way as operator \n\\f1\\fs18 []\n\\f3\\fs20 , but additionally, redundant dimensions are dropped as by \n\\f1\\fs18 drop()\n\\f3\\fs20 .\\\nThe return value from \n\\f1\\fs18 apply()\n\\f3\\fs20  is built up from the type-promoted concatenated results, as if by the \n\\f1\\fs18 c()\n\\f3\\fs20  function, from the iterated execution of \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 ; the only question is what dimensional structure is imposed upon that vector of values.  If the results from \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  are not of a consistent length, or are of length zero, then the concatenated results are returned as a plain vector.  If all results are of length \n\\f1\\fs18 n > 1\n\\f3\\fs20 , the return value is an array of dimensions \n\\f1\\fs18 c(n, dim(x)[margin]);\n\\f3\\fs20  in other words, each \n\\f1\\fs18 n\n\\f3\\fs20 -vector provides the lowest dimension of the result, and the sizes of the marginal dimensions are imposed upon the data above that.  If all results are of length \n\\f1\\fs18 n == 1\n\\f3\\fs20 , then if a single margin was specified the result is a vector (of length equal to the size of that marginal dimension), or if more than one margin was specified the result is an array of dimension \n\\f1\\fs18 dim(x)[margin]\n\\f3\\fs20 ; in other words, the sizes of the marginal dimensions are imposed upon the data.  Since \n\\f1\\fs18 apply()\n\\f3\\fs20  iterates over the marginal dimensions in the same manner, these structures follows the structure of the data.\\\nThe above explanation may not be entirely clear, so let\\'92s look at an example.  If \n\\f1\\fs18 x\n\\f3\\fs20  is a matrix with two rows and three columns, such as defined by \n\\f1\\fs18 x = matrix(1:6, nrow=2);\n\\f3\\fs20 , then executing \n\\f1\\fs18 apply(x,\\'a00,\\'a0\"sum(applyValue);\");\n\\f3\\fs20  would cause each row of \n\\f1\\fs18 x\n\\f3\\fs20  to be supplied to the lambda through \n\\f1\\fs18 applyValue\n\\f3\\fs20 , and the values in each row would thus be summed to produce \n\\f1\\fs18 9 12\n\\f3\\fs20  as a result.  The call \n\\f1\\fs18 apply(x,\\'a01,\\'a0\"sum(applyValue);\");\n\\f3\\fs20  would instead sum columns of \n\\f1\\fs18 x\n\\f3\\fs20 , producing \n\\f1\\fs18 3 7 11\n\\f3\\fs20  as a result.  Now consider using \n\\f1\\fs18 range()\n\\f3\\fs20  rather than \n\\f1\\fs18 sum()\n\\f3\\fs20  in the lambda, thus producing two values for each row or column.  The call \n\\f1\\fs18 apply(x,\\'a00,\\'a0\"range(applyValue);\");\n\\f3\\fs20  produces a result of \n\\f1\\fs18 matrix(c(1,5,2,6), nrow=2)\n\\f3\\fs20 , with the range of the first row of \n\\f1\\fs18 x\n\\f3\\fs20 , 1\\'965, in the first column of the result, and the range of the second row of \n\\f1\\fs18 x\n\\f3\\fs20 , 2\\'966, in the second column.  Although visualization becomes more difficult, these same patterns extend to higher dimensions and arbitrary margins of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 For efficiently obtaining the sums of the rows or columns of a matrix, see \n\\f1\\fs18 rowSums()\n\\f3\\fs20  and \n\\f1\\fs18 colSums()\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)array(*\\'a0data, integer\\'a0dim)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nCreates a new array\n\\f3\\b0  from the data specified by \n\\f1\\fs18 data\n\\f3\\fs20 , with the dimension sizes specified by \n\\f1\\fs18 dim\n\\f3\\fs20 .  The first dimension size in \n\\f1\\fs18 dim\n\\f3\\fs20  is the number of rows, and the second is the number of columns; further entries specify the sizes of higher-order dimensions.  As many dimensions may be specified as desired, but with a minimum of two dimensions.  An array with two dimensions is a matrix (by definition); note that \n\\f1\\fs18 matrix()\n\\f3\\fs20  may provide a more convenient way to make a new matrix.  Each dimension must be of size \n\\f1\\fs18 1\n\\f3\\fs20  or greater; \n\\f1\\fs18 0\n\\f3\\fs20 -size dimensions are not allowed.\\\nThe elements of \n\\f1\\fs18 data\n\\f3\\fs20  are used to populate the new array; the size of \n\\f1\\fs18 data\n\\f3\\fs20  must therefore be equal to the size of the new array, which is the product of all the values in \n\\f1\\fs18 dim\n\\f3\\fs20 .  The new array will be filled in dimension order: one element in each row until a column is filled, then on to the next column in the same manner until all columns are filled, and then onward into the higher-order dimensions in the same manner.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (*)asVector(*\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Creates a new vector\n\\f3\\b0  from the elements of \n\\f1\\fs18 x\n\\f3\\fs20 , stripping off any dimensional information associated with \n\\f1\\fs18 x\n\\f3\\fs20  being a vector or array.  The values of the resulting vector are read out from \n\\f1\\fs18 x\n\\f3\\fs20  in dimension order: one element from each row until a column is completed, then on to the next column in the same manner until all columns are completed, and then onward into the higher-order dimensions in the same manner.  If \n\\f1\\fs18 x\n\\f3\\fs20  is already a vector, it is returned unmodified.  See \n\\f1\\fs18 drop()\n\\f3\\fs20  for a similar method that drops only matrix/array dimensions that are redundant.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)cbind(...)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nCombines vectors or matrices by column\n\\f3\\b0  to produce a single matrix.  The parameters must be vectors (which are interpreted by \n\\f1\\fs18 cbind()\n\\f3\\fs20  as if they were one-column matrices) or matrices.  They must be of the same type, of the same class if they are of type \n\\f1\\fs18 object\n\\f3\\fs20 , and have the same number of rows.  If these conditions are met, the result is a single matrix with the parameters joined together, left to right.  Parameters may instead be \n\\f1\\fs18 NULL\n\\f3\\fs20 , in which case they are ignored; or if all parameters are \n\\f1\\fs18 NULL\n\\f3\\fs20 , the result is \n\\f1\\fs18 NULL\n\\f3\\fs20 .  A sequence of vectors, matrices, and \n\\f1\\fs18 NULL\n\\f3\\fs20 s may thus be concatenated with the \n\\f1\\fs18 NULL\n\\f3\\fs20  values removed, analogous to \n\\f1\\fs18 c()\n\\f3\\fs20 .  Calling \n\\f1\\fs18 cbind(x)\n\\f3\\fs20  is an easy way to create a one-column matrix from a vector.\\\nTo combine vectors or matrices by row instead, see \n\\f1\\fs18 rbind()\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (numeric)colSums(lif\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the sums of the columns\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a matrix.  The result is a vector of elements, each providing the sum of the corresponding column of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 logical\n\\f3\\fs20  or \n\\f1\\fs18 integer\n\\f3\\fs20  the result will be of type \n\\f1\\fs18 integer\n\\f3\\fs20 ; unlike the \n\\f1\\fs18 sum()\n\\f3\\fs20  function, \n\\f1\\fs18 colSums()\n\\f3\\fs20  does not promote the return type to \n\\f1\\fs18 float\n\\f3\\fs20  if \n\\f1\\fs18 integer\n\\f3\\fs20  overflow occurs, but instead throws an error.  If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 float\n\\f3\\fs20  the result will be of type \n\\f1\\fs18 float\n\\f3\\fs20 .  Except for the change in the treatment of \n\\f1\\fs18 integer\n\\f3\\fs20  overflow noted above, this is equivalent to using \n\\f1\\fs18 apply()\n\\f3\\fs20  with \n\\f1\\fs18 sum()\n\\f3\\fs20  to sum the columns of \n\\f1\\fs18 x\n\\f3\\fs20 , but is much faster.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (numeric$)det(numeric\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the determinant\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a square matrix (otherwise an error is raised).  The determinant is a scalar-valued function of the entries of the matrix, and characterizes some properties of the matrix.  In particular, the determinant is nonzero if and only if the matrix is invertible.  If the determinant is zero, the matrix does not have an inverse and is referred to as \\'93singular\\'94.  In Eidos the determinant is calculated from the \n\\f7\\i LU\n\\f3\\i0  decomposition of the matrix.  The return type will match the type of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (*)diag([*\\'a0x\\'a0=\\'a01], [Ni$\\'a0nrow\\'a0=\\'a0NULL], [Ni$\\'a0ncol\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the diagonal\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 .  This function has four distinct usage patterns (matching R).  First, if \n\\f1\\fs18 x\n\\f3\\fs20  is a matrix of any type, it returns the diagonal elements of \n\\f1\\fs18 x\n\\f3\\fs20  as a vector; in this case, \n\\f1\\fs18 nrow\n\\f3\\fs20  and \n\\f1\\fs18 ncol\n\\f3\\fs20  must be \n\\f1\\fs18 NULL\n\\f3\\fs20 .  Second, if \n\\f1\\fs18 x\n\\f3\\fs20  is \n\\f1\\fs18 1\n\\f3\\fs20  (the default) and \n\\f1\\fs18 nrow\n\\f3\\fs20  is non-\n\\f1\\fs18 NULL\n\\f3\\fs20 , it returns an identity matrix with the requested number of rows (and, if \n\\f1\\fs18 ncol\n\\f3\\fs20  is also non-\n\\f1\\fs18 NULL\n\\f3\\fs20 , the requested number of columns, otherwise the matrix will be square).  Third, if \n\\f1\\fs18 x\n\\f3\\fs20  is a singleton \n\\f1\\fs18 integer\n\\f3\\fs20  value and \n\\f1\\fs18 nrow\n\\f3\\fs20  and \n\\f1\\fs18 ncol\n\\f3\\fs20  are \n\\f1\\fs18 NULL\n\\f3\\fs20 , it returns a square identity matrix of size \n\\f1\\fs18 x\n\\f3\\fs20 .  Fourth, if x is a \n\\f1\\fs18 logical\n\\f3\\fs20 , \n\\f1\\fs18 integer\n\\f3\\fs20 , or \n\\f1\\fs18 float\n\\f3\\fs20  vector of length at least \n\\f1\\fs18 2\n\\f3\\fs20 , it returns a matrix that uses the values of \n\\f1\\fs18 x\n\\f3\\fs20  as its diagonal (without recycling or truncation, unlike R) and has \n\\f1\\fs18 F\n\\f3\\fs20 , \n\\f1\\fs18 0\n\\f3\\fs20 , or \n\\f1\\fs18 0.0\n\\f3\\fs20  off-diagonal entries as appropriate.\\\nNote that using \n\\f1\\fs18 diag(x)\n\\f3\\fs20 , without \n\\f1\\fs18 nrow\n\\f3\\fs20  or \n\\f1\\fs18 ncol\n\\f3\\fs20 , can have unexpected effects if \n\\f1\\fs18 x\n\\f3\\fs20  is a vector that could be of length one.  Use \n\\f1\\fs18 diag(x, nrow=length(x))\n\\f3\\fs20  for consistent behavior.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer)dim(*\\'a0x)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the dimensions\n\\f3\\b0  of matrix or array \n\\f1\\fs18 x\n\\f3\\fs20 .  The first dimension value is the number of rows, the second is the number of columns, and further values indicate the sizes of higher-order dimensions, identically to how dimensions are supplied to \n\\f1\\fs18 array()\n\\f3\\fs20 .  \n\\f1\\fs18 NULL\n\\f3\\fs20  is returned if \n\\f1\\fs18 x\n\\f3\\fs20  is not a matrix or array.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (*)drop(*\\'a0x)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the result of dropping redundant dimensions\n\\f3\\b0  from matrix or array \n\\f1\\fs18 x\n\\f3\\fs20 .  Redundant dimensions are those with a size of exactly 1.  Non-redundant dimensions are retained.  If only one non-redundant dimension is present, the result is a vector; if more than one non-redundant dimension is present, the result will be a matrix or array.  If \n\\f1\\fs18 x\n\\f3\\fs20  is not a matrix or array, it is returned unmodified.\\kerning1\\expnd0\\expndtw0   See \n\\f1\\fs18 asVector()\n\\f3\\fs20  for a way to drop all dimensions of a matrix or array, whether redundant or not.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (float)inverse(numeric\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the (multiplicative) inverse\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a square non-singular matrix (otherwise an error is raised).  If matrix \n\\f0\\b B\n\\f3\\b0  is the inverse of \n\\f7\\i n\n\\f3\\i0 -by-\n\\f7\\i n\n\\f3\\i0  matrix \n\\f0\\b A\n\\f3\\b0 , then \n\\f0\\b AB\n\\f3\\b0  = \n\\f0\\b BA\n\\f3\\b0  = \n\\f0\\b I\n\\f7\\i\\b0\\fs13\\fsmilli6667 \\sub n\n\\f3\\i0\\fs20 \\nosupersub , where \n\\f0\\b I\n\\f7\\i\\b0\\fs13\\fsmilli6667 \\sub n\n\\f3\\i0\\fs20 \\nosupersub  denotes the \n\\f7\\i n\n\\f3\\i0 -by-\n\\f7\\i n\n\\f3\\i0  identity matrix and the multiplication used is ordinary matrix multiplication as performed by \n\\f1\\fs18 matrixMult()\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  might be singular (and thus non-invertible), and you wish to avoid the possibility of an error, you can call \n\\f1\\fs18 det()\n\\f3\\fs20  first to find the determinant of the matrix; if the determinant is zero, the matrix is singular and does not have an inverse, and so \n\\f1\\fs18 inverse()\n\\f3\\fs20  should not be called.  In Eidos the inverse is calculated from the \n\\f7\\i LU\n\\f3\\i0  decomposition of the matrix.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)lowerTri(*\\'a0x, [logical$\\'a0diag\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the lower triangle\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a matrix.  The return value will be a \n\\f1\\fs18 logical\n\\f3\\fs20  matrix of the same dimensions as \n\\f1\\fs18 x\n\\f3\\fs20 , with elements \n\\f1\\fs18 T\n\\f3\\fs20  in the lower triangle, \n\\f1\\fs18 F\n\\f3\\fs20  elsewhere.  If \n\\f1\\fs18 diag\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), the diagonal is not included in the lower triangle; if \n\\f1\\fs18 diag\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the diagonal is included in the lower triangle (i.e., its elements will be \n\\f1\\fs18 T\n\\f3\\fs20 ).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)matrix(*\\'a0data, [Ni$\\'a0nrow\\'a0=\\'a0NULL], [Ni$\\'a0ncol\\'a0=\\'a0NULL], [logical$\\'a0byrow\\'a0=\\'a0F])\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nCreates a new matrix\n\\f3\\b0  from the data specified by \n\\f1\\fs18 data\n\\f3\\fs20 .  By default this creates a one-column matrix.  If non-\n\\f1\\fs18 NULL\n\\f3\\fs20  values are supplied for \n\\f1\\fs18 nrow\n\\f3\\fs20  and/or \n\\f1\\fs18 ncol\n\\f3\\fs20 , a matrix will be made with the requested number of rows and/or columns if possible; if the length of \n\\f1\\fs18 data\n\\f3\\fs20  is not compatible with the requested dimensions, an error will result.  By default, values from data will populate the matrix by columns, filling each column sequentially before moving on to the next column; if \n\\f1\\fs18 byrow\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  the matrix will be populated by rows instead.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (numeric)matrixMult(numeric\\'a0x, numeric\\'a0y)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the result of matrix multiplication\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20  with \n\\f1\\fs18 y\n\\f3\\fs20 .  In Eidos (as in R), with two matrices \n\\f1\\fs18 A\n\\f3\\fs20  and \n\\f1\\fs18 B\n\\f3\\fs20  the simple product \n\\f1\\fs18 A\\'a0*\\'a0B\n\\f3\\fs20  multiplies the corresponding elements of the matrices; in other words, if \n\\f1\\fs18 X\n\\f3\\fs20  is the result of \n\\f1\\fs18 A\\'a0*\\'a0B\n\\f3\\fs20 , then \n\\f1\\fs18 X\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub \\'a0=\\'a0\n\\f1\\fs18 A\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub \\'a0* \n\\f1\\fs18 B\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub .  This is parallel to the definition of other operators; A\\'a0+\\'a0B adds the corresponding elements of the matrices (\n\\f1\\fs18 X\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub \\'a0=\\'a0\n\\f1\\fs18 A\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub \\'a0+\\'a0\n\\f1\\fs18 B\n\\f7\\i\\fs13\\fsmilli6667 \\sub ij\n\\f3\\i0\\fs20 \\nosupersub ), etc.  In R, true matrix multiplication is achieved with a special operator, \n\\f1\\fs18 %*%\n\\f3\\fs20 ; in Eidos, the \n\\f1\\fs18 matrixMult()\n\\f3\\fs20  function is used instead.\\\nBoth \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  must be matrices, and must be conformable according to the standard definition of matrix multiplication (i.e., if \n\\f1\\fs18 x\n\\f3\\fs20  is an \n\\f7\\i n\n\\f3\\i0 \\'a0\\'d7\\'a0\n\\f7\\i m\n\\f3\\i0  matrix then \n\\f1\\fs18 y\n\\f3\\fs20  must be a \n\\f7\\i m\n\\f3\\i0 \\'a0\\'d7\\'a0\n\\f7\\i p\n\\f3\\i0  matrix, and the result will be a \n\\f7\\i n\n\\f3\\i0 \\'a0\\'d7\\'a0\n\\f7\\i p\n\\f3\\i0  matrix).  Vectors will not be promoted to matrices by this function, even if such promotion would lead to a conformable matrix.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (numeric)matrixPow(numeric\\'a0x, integer$\\'a0power)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the result of raising matrix \n\\f9\\fs18 x\n\\f0\\fs20  to an \n\\f9\\fs18 integer\n\\f0\\fs20  \n\\f9\\fs18 power\n\\f0\\fs20 .\n\\f3\\b0   The parameter x must be a square matrix (or an error will be raised).  This operation is performed by repeated matrix multiplication with \n\\f1\\fs18 matrixMult()\n\\f3\\fs20 , and uses \n\\f1\\fs18 inverse()\n\\f3\\fs20  to compute the inverse of the matrix if \n\\f1\\fs18 power\n\\f3\\fs20  is negative.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer$)nrow(*\\'a0x)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the number of rows\n\\f3\\b0  in matrix or array \n\\f1\\fs18 x\n\\f3\\fs20 .  For vector \n\\f1\\fs18 x\n\\f3\\fs20 , \n\\f1\\fs18 nrow()\n\\f3\\fs20  returns \n\\f1\\fs18 NULL\n\\f3\\fs20 ; \n\\f1\\fs18 size()\n\\f3\\fs20  should be used.  An equivalent of R\\'92s \n\\f1\\fs18 NROW()\n\\f3\\fs20  function, which treats vectors as \n\\f1\\fs18 1\n\\f3\\fs20 -column matrices, is not provided but would be trivial to implement as a user-defined function.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (integer$)ncol(*\\'a0x)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the number of columns\n\\f3\\b0  in matrix or array \n\\f1\\fs18 x\n\\f3\\fs20 .  For vector \n\\f1\\fs18 x\n\\f3\\fs20 , \n\\f1\\fs18 ncol()\n\\f3\\fs20  returns \n\\f1\\fs18 NULL\n\\f3\\fs20 ; \n\\f1\\fs18 size()\n\\f3\\fs20  should be used.  An equivalent of R\\'92s \n\\f1\\fs18 NCOL()\n\\f3\\fs20  function, which treats vectors as \n\\f1\\fs18 1\n\\f3\\fs20 -column matrices, is not provided but would be trivial to implement as a user-defined function.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (numeric)outerProduct(numeric\\'a0x, numeric\\'a0y)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the outer product\n\\f3\\b0  of vectors \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 .  The outer product, \n\\f1\\fs18 x\n\\f3\\fs20  \n\\f6 \\uc0\\u8855 \n\\f3  \n\\f1\\fs18 y\n\\f3\\fs20 , is the result of matrix multiplication of \n\\f1\\fs18 x\n\\f3\\fs20  with the transpose of \n\\f1\\fs18 y\n\\f3\\fs20 , or \n\\f1\\fs18 xy\n\\f3\\fs13\\fsmilli6667 \\super T\n\\fs20 \\nosupersub .  It will be a matrix with a number of rows equal to the length of \n\\f1\\fs18 x\n\\f3\\fs20 , and a number of columns equal to the length of \n\\f1\\fs18 y\n\\f3\\fs20 .  It is required that \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20  be vectors, not matrices or arrays, that they have non-zero lengths, and that they be the same type \\'96 both \n\\f1\\fs18 integer\n\\f3\\fs20  or both \n\\f1\\fs18 float\n\\f3\\fs20 .  The return value will be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20  and \n\\f1\\fs18 y\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)rbind(...)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nCombines vectors or matrices by row\n\\f3\\b0  to produce a single matrix.  The parameters must be vectors (which are interpreted by \n\\f1\\fs18 rbind()\n\\f3\\fs20  as if they were one-row matrices) or matrices.  They must be of the same type, of the same class if they are of type \n\\f1\\fs18 object\n\\f3\\fs20 , and have the same number of columns.  If these conditions are met, the result is a single matrix with the parameters joined together, top to bottom.  Parameters may instead be \n\\f1\\fs18 NULL\n\\f3\\fs20 , in which case they are ignored; or if all parameters are \n\\f1\\fs18 NULL\n\\f3\\fs20 , the result is \n\\f1\\fs18 NULL\n\\f3\\fs20 .  A sequence of vectors, matrices, and \n\\f1\\fs18 NULL\n\\f3\\fs20 s may thus be concatenated with the \n\\f1\\fs18 NULL\n\\f3\\fs20  values removed, analogous to \n\\f1\\fs18 c()\n\\f3\\fs20 .  Calling \n\\f1\\fs18 rbind(x)\n\\f3\\fs20  is an easy way to create a one-row matrix from a vector.\\\nTo combine vectors or matrices by column instead, see \n\\f1\\fs18 cbind()\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (numeric)rowSums(lif\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the sums of the rows\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a matrix.  The result is a vector of elements, each providing the sum of the corresponding row of \n\\f1\\fs18 x\n\\f3\\fs20 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 logical\n\\f3\\fs20  or \n\\f1\\fs18 integer\n\\f3\\fs20  the result will be of type \n\\f1\\fs18 integer\n\\f3\\fs20 ; unlike the \n\\f1\\fs18 sum()\n\\f3\\fs20  function, \n\\f1\\fs18 rowSums()\n\\f3\\fs20  does not promote the return type to \n\\f1\\fs18 float\n\\f3\\fs20  if \n\\f1\\fs18 integer\n\\f3\\fs20  overflow occurs, but instead throws an error.  If \n\\f1\\fs18 x\n\\f3\\fs20  is of type \n\\f1\\fs18 float\n\\f3\\fs20  the result will be of type \n\\f1\\fs18 float\n\\f3\\fs20 .  Except for the change in the treatment of \n\\f1\\fs18 integer\n\\f3\\fs20  overflow noted above, this is equivalent to using \n\\f1\\fs18 apply()\n\\f3\\fs20  with \n\\f1\\fs18 sum()\n\\f3\\fs20  to sum the rows of \n\\f1\\fs18 x\n\\f3\\fs20 , but is much faster.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)t(*\\'a0x)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns the transpose\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a matrix.  This is the matrix reflected across its diagonal; or alternatively, the matrix with its columns written out instead as rows in the same order.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (numeric$)tr(numeric\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the trace\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a square matrix (otherwise an error is raised).  The trace is the sum of the diagonal elements of the matrix.  The return type will match the type of \n\\f1\\fs18 x\n\\f3\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical)upperTri(*\\'a0x, [logical$\\'a0diag\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns the upper triangle\n\\f3\\b0  of \n\\f1\\fs18 x\n\\f3\\fs20 , which must be a matrix.  The return value will be a \n\\f1\\fs18 logical\n\\f3\\fs20  matrix of the same dimensions as \n\\f1\\fs18 x\n\\f3\\fs20 , with elements \n\\f1\\fs18 T\n\\f3\\fs20  in the upper triangle, \n\\f1\\fs18 F\n\\f3\\fs20  elsewhere.  If \n\\f1\\fs18 diag\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), the diagonal is not included in the upper triangle; if \n\\f1\\fs18 diag\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the diagonal is included in the upper triangle (i.e., its elements will be \n\\f1\\fs18 T\n\\f3\\fs20 ).\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.9.  Filesystem access functions\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (logical$)createDirectory(string$\\'a0path)\n\\f2 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Creates a new filesystem directory\n\\f3\\b0  at the path specified by \n\\f1\\fs18 path\n\\f3\\fs20  and returns a \n\\f1\\fs18 logical\n\\f3\\fs20  value indicating if the creation succeeded (\n\\f1\\fs18 T\n\\f3\\fs20 ) or failed (\n\\f1\\fs18 F\n\\f3\\fs20 ).  If the path already exists, \n\\f1\\fs18 createDirectory()\n\\f3\\fs20  will do nothing to the filesystem, will emit a warning, and will return \n\\f1\\fs18 T\n\\f3\\fs20  to indicate success if the existing path is a directory, or \n\\f1\\fs18 F\n\\f3\\fs20  to indicate failure if the existing path is not a directory.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)deleteFile(string$\\'a0filePath)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Deletes the file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20  and returns a \n\\f1\\fs18 logical\n\\f3\\fs20  value indicating if the deletion succeeded (\n\\f1\\fs18 T\n\\f3\\fs20 ) or failed (\n\\f1\\fs18 F\n\\f3\\fs20 ).\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 This function might also be able to delete a directory at \n\\f1\\fs18 filePath\n\\f3\\fs20 , but only if it is empty (apart from the \n\\f1\\fs18 .\n\\f3\\fs20  and \n\\f1\\fs18 ..\n\\f3\\fs20  directory entries that exist on Un*x filesystems).  If other files (including invisible files) exist in the directory, \n\\f1\\fs18 deleteFile()\n\\f3\\fs20  will probably fail as a safety measure, in which case the contained files must be deleted individually first.  This is vague because the actual policy regarding deletion of directories will depend upon the operating system, since Eidos achieves the deletion by calling an operating-system function.\n\\f2 \\cf0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(logical$)fileExists(string$\\'a0filePath)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Checks the existence of the file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20  and returns a \n\\f1\\fs18 logical\n\\f3\\fs20  value indicating if it exists (\n\\f1\\fs18 T\n\\f3\\fs20 ) or does not exist (\n\\f1\\fs18 F\n\\f3\\fs20 ).  This also works for directories.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (string)filesAtPath(string$\\'a0path, [logical$\\'a0fullPaths\\'a0=\\'a0F])\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f1\\fs18 string\n\\f3\\fs20  vector containing the \n\\f0\\b names of all files in a directory\n\\f3\\b0  specified by \n\\f1\\fs18 path\n\\f2\\fs20 .\n\\f3   If the optional parameter \n\\f1\\fs18 fullPaths\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , full filesystem paths are returned for each file; if \n\\f1\\fs18 fullPaths\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), then only the filenames relative to the specified directory are returned.  This list includes directories (i.e. subfolders), including the \n\\f1\\fs18 \".\"\n\\f3\\fs20  and \n\\f1\\fs18 \"..\"\n\\f3\\fs20  directories on Un*x systems.  The list also includes invisible files, such as those that begin with a \n\\f1\\fs18 \".\"\n\\f3\\fs20  on Un*x systems.  This function does not descend recursively into subdirectories.  If an error occurs during the read, \n\\f1\\fs18 NULL\n\\f3\\fs20  will be returned.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (logical$)flushFile(string$\\'a0filePath)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Flushes buffered content to a file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20 .  Normally, written data is buffered by \n\\f1\\fs18 writeFile()\n\\f3\\fs20  if the \n\\f1\\fs18 compress\n\\f3\\fs20  option of that function is \n\\f1\\fs18 T\n\\f3\\fs20 , holding the data in memory rather than writing it to disk immediately.  This buffering improves both performance and file size; however, sometimes it is desirable to flush the buffered data to disk with \n\\f1\\fs18 flush()\n\\f3\\fs20  so that the filesystem is up to date.  Note that flushing after every write is not recommended, since it will lose all of the benefits of buffering.  Calling \n\\f1\\fs18 flushFile()\n\\f3\\fs20  for a path that has not been written to, or is not being buffered, will do nothing.  If the flush is successful, \n\\f1\\fs18 T\n\\f3\\fs20  will be returned; if not, \n\\f1\\fs18 F\n\\f3\\fs20  will be returned (but at present, an error will result instead).\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(string$)getwd(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Gets the current filesystem working directory\n\\f3\\b0 .  The filesystem working directory is the directory which will be used as a base path for relative filesystem paths.  For example, if the working directory is \n\\f1\\fs18 \"~/Desktop\"\n\\f3\\fs20  (the \n\\f1\\fs18 Desktop\n\\f3\\fs20  subdirectory within the current user\\'92s home directory, as represented by \n\\f1\\fs18 ~\n\\f3\\fs20 ), then the filename \n\\f1\\fs18 \"foo.txt\"\n\\f3\\fs20  would correspond to the filesystem path \n\\f1\\fs18 \"~/Desktop/foo.txt\"\n\\f3\\fs20 , and the relative path \n\\f1\\fs18 \"bar/baz/\"\n\\f3\\fs20  would correspond to the filesystem path \n\\f1\\fs18 \\'93~/Desktop/bar/baz/\\'93\n\\f3\\fs20 .\\\nNote that the path returned may not be identical to the path previously set with \n\\f1\\fs18 setwd()\n\\f3\\fs20 , if for example symbolic links are involved; but it ought to refer to the same actual directory in the filesystem.\\\nThe initial working directory is \\'96 as is generally the case on Un*x \\'96 simply the directory given to the running Eidos process by its parent process (the operating system, a shell, a job scheduler, a debugger, or whatever the case may be).  If you launch Eidos (or SLiM) from the command line in a Un*x shell, it is typically the current directory in that shell.  Before relative filesystem paths are used, you may therefore wish check what the initial working directory is on your platform, with \n\\f1\\fs18 getwd()\n\\f3\\fs20 , if you are not sure.  Alternatively, you can simply use \n\\f1\\fs18 setwd()\n\\f3\\fs20  to set the working directory to a known path.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (object<DataFrame>$)readCSV(string$\\'a0filePath, [ls\\'a0colNames\\'a0=\\'a0T], [Ns$\\'a0colTypes\\'a0=\\'a0NULL], [string$\\'a0sep\\'a0=\\'a0\",\"], [string$\\'a0quote\\'a0=\\'a0'\"'], [string$\\'a0dec\\'a0=\\'a0\".\"], [string$\\'a0comment\\'a0=\\'a0\"\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Reads data from a CSV or other delimited file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20  and returns a \n\\f1\\fs18 DataFrame\n\\f3\\fs20  object containing the data in a tabular form.  CSV (comma-separated value) files use a somewhat standard file format in which a table of data is provided, with values within a row separated by commas, while rows in the table are separated by newlines.  Software from R to Excel (and Eidos; see the \n\\f1\\fs18 serialize()\n\\f3\\fs20  method of \n\\f1\\fs18 Dictionary\n\\f3\\fs20 ) can export data in CSV format.  This function can actually also read files that use a delimiter other than commas; TSV (tab-separated value) files are a popular alternative.  Since there is substantial variation in the exact file format for CSV files, this documentation will try to specify the precise format expected by this function.  Note that CSV files represent values differently that Eidos usually does, and some of the format options allowed by \n\\f1\\fs18 readCSV()\n\\f3\\fs20 , such as decimal commas, are not otherwise available in Eidos.\\\nIf \n\\f1\\fs18 colNames\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), the first row of data is taken to be a header, containing the string names of the columns in the data table; those names will be used by the resulting \n\\f1\\fs18 DataFrame\n\\f3\\fs20 .  If \n\\f1\\fs18 colNames\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 , a header row is not expected and column names are auto-generated as \n\\f1\\fs18 X1\n\\f3\\fs20 , \n\\f1\\fs18 X2\n\\f3\\fs20 , etc.  If \n\\f1\\fs18 colNames\n\\f3\\fs20  is a \n\\f1\\fs18 string\n\\f3\\fs20  vector, a header row is not expected and \n\\f1\\fs18 colNames\n\\f3\\fs20  will be used as the column names; if additional columns exist beyond the length of \n\\f1\\fs18 colNames\n\\f3\\fs20  their names will be auto-generated.  Duplicate column names will generate a warning and be made unique.\\\nIf \n\\f1\\fs18 colTypes\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default), the value type for each column will be guessed from the values it contains, as described below.  If \n\\f1\\fs18 colTypes\n\\f3\\fs20  is a singleton \n\\f1\\fs18 string\n\\f3\\fs20 , it should contain single-letter codes indicating the desired type for each column, from left to right.  The letters \n\\f1\\fs18 lifs\n\\f3\\fs20  have the same meaning as in Eidos signatures (\n\\f1\\fs18 logical\n\\f3\\fs20 , \n\\f1\\fs18 integer\n\\f3\\fs20 , \n\\f1\\fs18 float\n\\f3\\fs20 , and \n\\f1\\fs18 string\n\\f3\\fs20 ); in addition, \n\\f1\\fs18 ?\n\\f3\\fs20  may be used to indicate that the type for that column should be guessed as by default, and \n\\f1\\fs18 _\n\\f3\\fs20  or \n\\f1\\fs18 -\n\\f3\\fs20  may be used to indicate that that column should be skipped \\'96 omitted from the returned \n\\f1\\fs18 DataFrame\n\\f3\\fs20 .  Other characters in \n\\f1\\fs18 colTypes\n\\f3\\fs20  will result in an error.  If additional columns exist beyond the end of the \n\\f1\\fs18 colTypes\n\\f3\\fs20  string their types will be guessed as by default.\\\nThe separator between values is supplied by \n\\f1\\fs18 sep\n\\f3\\fs20 ; it is a comma by default, but a tab can be used instead by supplying tab (\n\\f1\\fs18 \"\\\\t\"\n\\f3\\fs20  in Eidos), or another character may also be used.  If \n\\f1\\fs18 sep\n\\f3\\fs20  is the empty string \n\\f1\\fs18 \"\"\n\\f3\\fs20 , the separator between values is \\'93whitespace\\'94, meaning one or more spaces or tabs.  When the separator is whitespace, whitespace at the beginning or the end of a line will be ignored.\\\nSimilarly, the character used to quote string values is a double quote (\n\\f1\\fs18 '\"'\n\\f3\\fs20  in Eidos), by default, but another character may be supplied in \n\\f1\\fs18 quote\n\\f3\\fs20 .  When the string delimiter is encountered, \n\\f7\\i all\n\\f3\\i0  following characters are considered to be part of the string until another string delimiter is encountered, terminating the string; this includes spaces, comment characters, newlines, and everything else.  Within a string value, the string delimiter itself is used twice in a row to indicate that the delimiter itself is present within the string; for example, if the string value (shown without the usual surrounding quotes to try to avoid confusion) is \n\\f1\\fs18 she said \"hello\"\n\\f3\\fs20 , and the string delimiter is the double quote as it is by default, then in the CSV file the value would be given as \n\\f1\\fs18 \"she said \"\"hello\"\"\"\n\\f3\\fs20 .  The usual Eidos style of escaping characters using a backslash is \n\\f7\\i not\n\\f3\\i0  part of the CSV standard followed here.  (When a string value is provided \n\\f7\\i without\n\\f3\\i0  using the string delimiter, all following characters are considered part of the string except a newline, the value separator \n\\f1\\fs18 sep\n\\f3\\fs20 , the quote separator \n\\f1\\fs18 quote\n\\f3\\fs20 , and the comment separator \n\\f1\\fs18 comment\n\\f3\\fs20 ; if none of those characters are present in the string value, the quote delimiter may be omitted.)\\\nThe character used to indicate a decimal delimiter in numbers may be supplied with \n\\f1\\fs18 dec\n\\f3\\fs20 ; by default this is \n\\f1\\fs18 \".\"\n\\f3\\fs20  (and so \n\\f1\\fs18 10.0\n\\f3\\fs20  would be ten, written with a decimal point), but \n\\f1\\fs18 \",\"\n\\f3\\fs20  is common in European data files (and so \n\\f1\\fs18 10,0\n\\f3\\fs20  would be ten, written with a decimal comma).  Note that \n\\f1\\fs18 dec\n\\f3\\fs20  and \n\\f1\\fs18 sep\n\\f3\\fs20  may not be the same, so that it is unambiguous whether \n\\f1\\fs18 10,0\n\\f3\\fs20  is two numbers (\n\\f1\\fs18 10\n\\f3\\fs20  and \n\\f1\\fs18 0\n\\f3\\fs20 ) or one number (\n\\f1\\fs18 10.0\n\\f3\\fs20 ).  For this reason, European CSV files that use a decimal comma typically use a semicolon as the value separator, which may be supplied with \n\\f1\\fs18 sep=\";\"\n\\f3\\fs20  to \n\\f1\\fs18 readCSV()\n\\f3\\fs20 .\\\nFinally, the remainder of a line following a comment character will be ignored when the file is read; by default \n\\f1\\fs18 comment\n\\f3\\fs20  is the empty string, \n\\f1\\fs18 \"\"\n\\f3\\fs20 , indicating that comments do not exist at all, but \n\\f1\\fs18 \"#\"\n\\f3\\fs20  is a popular comment prefix.\\\nTo translate the CSV data into a \n\\f1\\fs18 DataFrame\n\\f3\\fs20 , it is necessary for Eidos to guess what value type each column is unless a column type is specified by \n\\f1\\fs18 colTypes\n\\f3\\fs20 .  Quotes surrounding a value are irrelevant to this guess; for example, \n\\f1\\fs18 1997\n\\f3\\fs20  and \n\\f1\\fs18 \"1997\"\n\\f3\\fs20  are both candidates to be \n\\f1\\fs18 integer\n\\f3\\fs20  values (because some programs generate CSV output in which \n\\f7\\i every\n\\f3\\i0  value is quoted regardless of type).  If \n\\f7\\i every\n\\f3\\i0  value in a column is either \n\\f1\\fs18 true\n\\f3\\fs20 , \n\\f1\\fs18 false\n\\f3\\fs20 , \n\\f1\\fs18 TRUE\n\\f3\\fs20 , \n\\f1\\fs18 FALSE\n\\f3\\fs20 , \n\\f1\\fs18 T\n\\f3\\fs20 , or \n\\f1\\fs18 F\n\\f3\\fs20 , the column will be taken to be \n\\f1\\fs18 logical\n\\f3\\fs20 .  Otherwise, if \n\\f7\\i every\n\\f3\\i0  value in a column is an integer (here defined as an optional \n\\f1\\fs18 +\n\\f3\\fs20  or \n\\f1\\fs18 -\n\\f3\\fs20 , followed by nothing but decimal digits \n\\f1\\fs18 0123456789\n\\f3\\fs20 ), the column will be taken to be \n\\f1\\fs18 integer\n\\f3\\fs20 .  Otherwise, if \n\\f7\\i every\n\\f3\\i0  value in a column is a floating-point number (here defined as an optional \n\\f1\\fs18 +\n\\f3\\fs20  or \n\\f1\\fs18 -\n\\f3\\fs20 , followed by decimal digits \n\\f1\\fs18 0123456789\n\\f3\\fs20 , optionally a decimal separator and then optionally more decimal digits, and ending with an optional exponent like \n\\f1\\fs18 e7\n\\f3\\fs20 , \n\\f1\\fs18 E+05\n\\f3\\fs20 , or \n\\f1\\fs18 e-2\n\\f3\\fs20 ), the column will be taken to be \n\\f1\\fs18 float\n\\f3\\fs20 ; the special values \n\\f1\\fs18 NAN\n\\f3\\fs20 , \n\\f1\\fs18 INF\n\\f3\\fs20 , \n\\f1\\fs18 INFINITY\n\\f3\\fs20 , \n\\f1\\fs18 -INF\n\\f3\\fs20 , and \n\\f1\\fs18 -INFINITY\n\\f3\\fs20  (not case-sensitive) are also candidates to be \n\\f1\\fs18 float\n\\f3\\fs20  (if the rest of the column is also convertible to \n\\f1\\fs18 float\n\\f3\\fs20 ), representing the corresponding \n\\f1\\fs18 float\n\\f3\\fs20  constants.  Otherwise, the column will be taken to be \n\\f1\\fs18 string\n\\f3\\fs20 .  \n\\f1\\fs18 NULL\n\\f3\\fs20  and \n\\f1\\fs18 NA\n\\f3\\fs20  are not recognized by \n\\f1\\fs18 readCSV()\n\\f3\\fs20  in CSV files and will be read as strings.  Every line in a CSV file must contain the same number of values (forming a rectangular data table); missing values are not allowed by \n\\f1\\fs18 readCSV()\n\\f3\\fs20  since there is no way to represent them in \n\\f1\\fs18 DataFrame\n\\f3\\fs20  (since Eidos has no equivalent of R\\'92s \n\\f1\\fs18 NA\n\\f3\\fs20  value).  Spaces are considered part of a data field and are not trimmed, following the RFC 4180 standard.  These choices are an attempt to provide optimal behavior for most clients, but given the lack of any universal standard for CSV files, and the lack of any type information in the CSV format, they will not always work as desired; in such cases, it should be reasonably straightforward to preprocess input files using standard Unix text-processing tools like \n\\f1\\fs18 sed\n\\f3\\fs20  and \n\\f1\\fs18 awk\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string)readFile(string$\\'a0filePath)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Reads in the contents of a file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20  and returns a \n\\f1\\fs18 string\n\\f3\\fs20  vector containing the lines (separated by \n\\f1\\fs18 \\\\n\n\\f3\\fs20  and \n\\f1\\fs18 \\\\r\n\\f3\\fs20  characters) of the file.  Reading files other than text files is not presently supported.  If an error occurs during the read, \n\\f1\\fs18 NULL\n\\f3\\fs20  will be returned.\n\\f2 \\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(string$)setwd(string$\\'a0path)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Sets the current filesystem working directory\n\\f3\\b0 .  The filesystem working directory is the directory which will be used as a base path for relative filesystem paths (see \n\\f1\\fs18 getwd()\n\\f3\\fs20  for further discussion).  An error will result if the working directory cannot be set to the given path.\\\nThe current working directory prior to the change will be returned as an invisible \n\\f1\\fs18 string\n\\f3\\fs20  value; the value returned is identical to the value that would have been returned by \n\\f1\\fs18 getwd()\n\\f3\\fs20 , apart from its invisibility.\\\nSee \n\\f1\\fs18 getwd()\n\\f3\\fs20  for discussion regarding the initial working directory, before it is set with \n\\f1\\fs18 setwd()\n\\f3\\fs20 .\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (string$)tempdir(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns a path to a directory appropriate for saving temporary files\n\\f3\\b0 .  The path returned by \n\\f1\\fs18 tempdir()\n\\f3\\fs20  is platform-specific, and is not guaranteed to be the same from one run of SLiM to the next.  It is guaranteed to end in a slash, so further path components should be appended without a leading slash.  At present, on macOS and Linux systems, the path will be \n\\f1\\fs18 \"/tmp/\"\n\\f3\\fs20 ; this may change in future Eidos versions without warning.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical$)writeFile(string$\\'a0filePath, string\\'a0contents, [logical$\\'a0append\\'a0=\\'a0F], [logical$\\'a0compress\\'a0=\\'a0F])\n\\f2 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Writes or appends to a file\n\\f3\\b0  specified by \n\\f1\\fs18 filePath\n\\f3\\fs20  with contents specified by \n\\f1\\fs18 contents\n\\f3\\fs20 , a \n\\f1\\fs18 string\n\\f3\\fs20  vector of lines.  If \n\\f1\\fs18 append\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the write will be appended to the existing file (if any) at \n\\f1\\fs18 filePath\n\\f3\\fs20 ; if it is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), then the write will replace an existing file at that path.\\cf2   If the write is successful, \n\\f1\\fs18 T\n\\f3\\fs20  will be returned; if not, \n\\f1\\fs18 F\n\\f3\\fs20  will be returned (but at present, an error will result instead).\\cf0 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 If \n\\f1\\fs18 compress\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the contents will be compressed with \n\\f1\\fs18 zlib\n\\f3\\fs20  as they are written, and the standard \n\\f1\\fs18 .gz\n\\f3\\fs20  extension for \n\\f1\\fs18 gzip\n\\f3\\fs20 -compressed files will be appended to the filename in \n\\f1\\fs18 filePath\n\\f3\\fs20  if it is not already present.  If the \n\\f1\\fs18 compress\n\\f3\\fs20  option is used in conjunction with \n\\f1\\fs18 append==T\n\\f3\\fs20 , Eidos will buffer data to append and flush it to the file in a delayed fashion (for performance reasons), and so appended data may not be visible in the file until later \\'96 potentially not until the process ends (i.e., the end of the SLiM simulation, for example).  If that delay if undesirable, buffered data can be explicitly flushed to the filesystem with \n\\f1\\fs18 flushFile()\n\\f3\\fs20 .  The \n\\f1\\fs18 compress\n\\f3\\fs20  option was added in Eidos 2.4 (SLiM 3.4).  Note that \n\\f1\\fs18 readFile()\n\\f3\\fs20  does not currently support reading in compressed data.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Note that newline characters will be added at the ends of the lines in \n\\f1\\fs18 contents\n\\f3\\fs20 .  If you do not wish to have newlines added, you should use \n\\f1\\fs18 paste()\n\\f3\\fs20  to assemble the elements of \n\\f1\\fs18 contents\n\\f3\\fs20  together into a singleton \n\\f1\\fs18 string\n\\f2\\fs20 .\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string$)writeTempFile(string$\\'a0prefix, string$\\'a0suffix, string\\'a0contents, [logical$\\'a0compress\\'a0=\\'a0F])\n\\f2 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Writes to a unique temporary file\n\\f3\\b0  with contents specified by \n\\f1\\fs18 contents\n\\f3\\fs20 , a \n\\f1\\fs18 string\n\\f3\\fs20  vector of lines.  The filename used will begin with \n\\f1\\fs18 prefix\n\\f3\\fs20  and end with \n\\f1\\fs18 suffix\n\\f3\\fs20 , and will contain six random characters in between; for example, if \n\\f1\\fs18 prefix\n\\f3\\fs20  is \n\\f1\\fs18 \"plot1_\"\n\\f3\\fs20  and \n\\f1\\fs18 suffix\n\\f3\\fs20  is \n\\f1\\fs18 \".pdf\"\n\\f3\\fs20 , the generated filename might look like \n\\f1\\fs18 \"plot1_r5Mq0t.pdf\"\n\\f3\\fs20 .  It is legal for \n\\f1\\fs18 prefix\n\\f3\\fs20 , \n\\f1\\fs18 suffix\n\\f3\\fs20 , or both to be the empty string, \n\\f1\\fs18 \"\"\n\\f3\\fs20 , but supplying a file extension is usually advisable at minimum.  The file will be created inside the \n\\f1\\fs18 /tmp/\n\\f3\\fs20  directory of the system, which is provided by Un*x systems as a standard location for temporary files; the \n\\f1\\fs18 /tmp/\n\\f3\\fs20  directory should not be specified as part of prefix (nor should any other directory information).  The filename generated is guaranteed not to already exist in \n\\f1\\fs18 /tmp/\n\\f3\\fs20 .  The file is created with Un*x permissions \n\\f1\\fs18 0600\n\\f3\\fs20 , allowing reading and writing only by the user for security.  If the write is successful, the full path to the temporary file will be returned; if not, \n\\f1\\fs18 \"\"\n\\f3\\fs20  will be returned.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f1\\fs18 compress\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the contents will be compressed with \n\\f1\\fs18 zlib\n\\f3\\fs20  as they are written, and the standard \n\\f1\\fs18 .gz\n\\f3\\fs20  extension for \n\\f1\\fs18 gzip\n\\f3\\fs20 -compressed files will be appended to the filename suffix in \n\\f1\\fs18 suffix\n\\f3\\fs20  if it is not already present.  The \n\\f1\\fs18 compress\n\\f3\\fs20  option was added in Eidos 2.4 (SLiM 3.4).  Note that \n\\f1\\fs18 readFile()\n\\f3\\fs20  does not currently support reading in compressed data.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 Note that newline characters will be added at the ends of the lines in \n\\f1\\fs18 contents\n\\f3\\fs20 .  If you do not wish to have newlines added, you should use \n\\f1\\fs18 paste()\n\\f3\\fs20  to assemble the elements of \n\\f1\\fs18 contents\n\\f3\\fs20  together into a singleton \n\\f1\\fs18 string\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.10.  Color manipulation functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(string)cmColors(integer$\\'a0n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 This method has been deprecated, and may be removed in a future release of Eidos.\n\\f3\\b0   In SLiM 3.5 and later, use \n\\f1\\fs18 colors(n, \"cm\")\n\\f3\\fs20  instead.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf5 Generate colors in a \\'93cyan-magenta\\'94 color palette.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)colors(numeric\\'a0x, string$\\'a0name)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Generate colors in a standard color palette\n\\f3\\b0 .  If \n\\f1\\fs18 x\n\\f3\\fs20  is a singleton \n\\f1\\fs18 integer\n\\f3\\fs20 , the returned vector will contain \n\\f1\\fs18 x\n\\f3\\fs20  color strings representing \n\\f1\\fs18 x\n\\f3\\fs20  colors equidistant along the named palette, spanning its full extent.  Alternatively, if \n\\f1\\fs18 x\n\\f3\\fs20  is a \n\\f1\\fs18 float\n\\f3\\fs20  vector of values in [\n\\f1\\fs18 0\n\\f3\\fs20 ,\n\\f1\\fs18 1\n\\f3\\fs20 ], the returned vector will contain one color string for each value in \n\\f1\\fs18 x\n\\f3\\fs20 , representing the color at the corresponding fraction along the named palette (values outside [\n\\f1\\fs18 0\n\\f3\\fs20 ,\n\\f1\\fs18 1\n\\f3\\fs20 ] will be clamped to that range).  (Note that the function signature states the type of \n\\f1\\fs18 x\n\\f3\\fs20  as \n\\f1\\fs18 numeric\n\\f3\\fs20 , but in this function the \n\\f1\\fs18 integer\n\\f3\\fs20  and \n\\f1\\fs18 float\n\\f3\\fs20  cases have completely different semantic meanings.)\\\nThe color palette specified by \n\\f1\\fs18 name\n\\f3\\fs20  may be any of the following color palettes based upon color palettes in R: \n\\f1\\fs18 \"cm\"\n\\f3\\fs20 , \n\\f1\\fs18 \"heat\"\n\\f3\\fs20 , and \n\\f1\\fs18 \"terrain\"\n\\f3\\fs20 .\\\nIt may also be one of the following color palettes based on color palettes in MATLAB (and the Turbo palette from Anton Mikhailov of the Google AI group, based upon the Jet palette provided by MATLAB): \n\\f1\\fs18 \"parula\"\n\\f3\\fs20 , \n\\f1\\fs18 \"hot\"\n\\f3\\fs20 , \n\\f1\\fs18 \"jet\"\n\\f3\\fs20 , \n\\f1\\fs18 \"turbo\"\n\\f3\\fs20 , and \n\\f1\\fs18 \"gray\"\n\\f3\\fs20 .\\\nFinally, it may be one of the following color palettes based upon color palettes in Matplotlib, also available in the \n\\f1\\fs18 viridis\n\\f3\\fs20  R package: \n\\f1\\fs18 \"magma\"\n\\f3\\fs20 , \n\\f1\\fs18 \"inferno\"\n\\f3\\fs20 , \n\\f1\\fs18 \"plasma\"\n\\f3\\fs20 , \n\\f1\\fs18 \"viridis\"\n\\f3\\fs20 , and \n\\f1\\fs18 \"cividis\"\n\\f3\\fs20 .  These color palettes are designed to be perceptually uniform, changing continuously and linearly.  They are also designed to perform well even for users with red-green colorblindness; the \n\\f1\\fs18 \"cividis\"\n\\f3\\fs20  palette, in particular, is designed to look nearly identical to those with and without red-green colorblindness, to be perceptually uniform in both hue and brightness, and to increase linearly in brightness.\\\nThis function replaces the deprecated \n\\f1\\fs18 cmColors()\n\\f3\\fs20 , \n\\f1\\fs18 heatColors()\n\\f3\\fs20 , and \n\\f1\\fs18 terrainColors()\n\\f3\\fs20  functions, and adds several several additional color palettes to Eidos.  See \n\\f1\\fs18 rainbow()\n\\f3\\fs20  for another color palette function.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)color2rgb(string\\'a0color)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nConverts a color string to RGB\n\\f3\\b0 .  The color string specified in \n\\f1\\fs18 color\n\\f3\\fs20  may be either a named color or a color in hexadecimal format such as \n\\f1\\fs18 \"#007FC0\"\n\\f3\\fs20 .  The equivalent RGB color is returned as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (red, green, blue).  Returned RGB values will be in the interval [0, 1].\\\nThis function can also be called with a non-singleton vector of color strings in \n\\f1\\fs18 color\n\\f3\\fs20 .  In this case, the returned \n\\f1\\fs18 float\n\\f3\\fs20  value will be a matrix of RGB values, with three columns (red, green, blue) and one row per element of \n\\f1\\fs18 color\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)heatColors(integer$\\'a0n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 This method has been deprecated, and may be removed in a future release of Eidos.\n\\f3\\b0   In SLiM 3.5 and later, use \n\\f1\\fs18 colors(n, \"heat\")\n\\f3\\fs20  instead.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf5 Generate colors in a \\'93heat map\\'94 color palette.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (float)hsv2rgb(float\\'a0hsv)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Converts an HSV color to RGB\n\\f2\\b0 .\n\\f3   The HSV color is specified in \n\\f1\\fs18 hsv\n\\f3\\fs20  as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (hue, saturation, value), and the equivalent RGB color is returned as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (red, green, blue).  HSV values will be clamped to the interval [0, 1], and returned RGB values will also be in the interval [0, 1].\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\nThis function can also be called with a matrix of HSV values, with three columns (hue, saturation, value).  In this case, the returned \n\\f1\\fs18 float\n\\f3\\fs20  value will be a matrix of RGB values, with three columns (red, green, blue) and one row per row of \n\\f1\\fs18 hsv\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)rainbow(integer$\\'a0n, [float$\\'a0s\\'a0=\\'a01.0], [float$\\'a0v\\'a0=\\'a01.0], [float$\\'a0start\\'a0=\\'a00.0], [Nf$\\'a0end\\'a0=\\'a0NULL], [logical$\\'a0ccw\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Generate colors in a \\'93rainbow\\'94 color palette\n\\f3\\b0 .  The number of colors desired is passed in \n\\f1\\fs18 n\n\\f3\\fs20 , and the returned vector will contain \n\\f1\\fs18 n\n\\f3\\fs20  color strings.  Parameters \n\\f1\\fs18 s\n\\f3\\fs20  and \n\\f1\\fs18 v\n\\f3\\fs20  control the saturation and value of the rainbow colors generated.  The color sequence begins with the hue \n\\f1\\fs18 start\n\\f3\\fs20 , and ramps to the hue \n\\f1\\fs18 end\n\\f3\\fs20 , in a counter-clockwise direction around the standard HSV color wheel if \n\\f1\\fs18 ccw\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default, following R), otherwise in a clockwise direction.  If \n\\f1\\fs18 end\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default), a value of \n\\f1\\fs18 (n-1)/n\n\\f3\\fs20  is used, producing a complete rainbow around the color wheel when \n\\f1\\fs18 start\n\\f3\\fs20  is also the default value of \n\\f1\\fs18 0.0\n\\f3\\fs20 .  See \n\\f1\\fs18 colors()\n\\f3\\fs20  for other color palettes.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (string)rgb2color(float\\'a0rgb)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Converts an RGB color to a color string\n\\f2\\b0 .\n\\f3   The RGB color is specified in \n\\f1\\fs18 rgb\n\\f3\\fs20  as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (red, green, blue).  The equivalent color string is returned as singleton \n\\f1\\fs18 string\n\\f3\\fs20  specifying the color in the format \n\\f1\\fs18 \"#RRGGBB\"\n\\f3\\fs20 , such as \n\\f1\\fs18 \"#007FC0\"\n\\f2\\fs20 .\n\\f3   RGB values will be clamped to the interval [0, 1].\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\nThis function can also be called with a matrix of RGB values, with three columns (red, green, blue).  In this case, the returned \n\\f1\\fs18 string\n\\f3\\fs20  value will be a vector of color strings, with one element per row of \n\\f1\\fs18 rgb\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (float)rgb2hsv(float\\'a0rgb)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Converts an RGB color to HSV\n\\f2\\b0 .\n\\f3   The RGB color is specified in \n\\f1\\fs18 rgb\n\\f3\\fs20  as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (red, green, blue), and the equivalent HSV color is returned as a \n\\f1\\fs18 float\n\\f3\\fs20  vector of length three (hue, saturation, value).  RGB values will be clamped to the interval [0, 1], and returned HSV values will also be in the interval [0, 1].\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\nThis function can also be called with a matrix of RGB values, with three columns (red, green, blue).  In this case, the returned \n\\f1\\fs18 float\n\\f3\\fs20  value will be a matrix of HSV values, with three columns (hue, saturation, value) and one row per row of \n\\f1\\fs18 rgb\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string)terrainColors(integer$\\'a0n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 This method has been deprecated, and may be removed in a future release of Eidos.\n\\f3\\b0   In SLiM 3.5 and later, use \n\\f1\\fs18 colors(n, \"terrain\")\n\\f3\\fs20  instead.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf5 Generate colors in a \\'93terrain\\'94 color palette.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.11.  Miscellaneous functions\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 (void)assert(logical\\'a0assertions, [Ns$\\'a0message\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Assert that a condition or conditions are true\n\\f3\\b0 .  If any element of \n\\f1\\fs18 assertions\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 , execution will be stopped.  A message, \\'93assertion failed\\'94, will be printed before stopping; if \n\\f1\\fs18 message\n\\f3\\fs20  is not \n\\f1\\fs18 NULL\n\\f3\\fs20 ; its value will then be printed.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)beep([Ns$\\'a0soundName\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Plays a sound or beeps.\n\\f3\\b0   On macOS in a GUI environment (i.e., in EidosScribe or SLiMgui), the optional parameter \n\\f1\\fs18 soundName\n\\f3\\fs20  can be the name of a sound file to play; in other cases (if \n\\f1\\fs18 soundName\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , or at the command line, or on platforms other than OS X) \n\\f1\\fs18 soundName\n\\f3\\fs20  is ignored and a standard system beep is played.\\\nWhen \n\\f1\\fs18 soundName\n\\f3\\fs20  is not \n\\f1\\fs18 NULL\n\\f2\\fs20 ,\n\\f3  a sound file in a supported format (such as \n\\f1\\fs18 .aiff\n\\f3\\fs20  or \n\\f1\\fs18 .mp3\n\\f3\\fs20 ) is searched for sequentially in four standard locations, in this order: \n\\f1\\fs18 ~/Library/Sounds\n\\f3\\fs20 , \n\\f1\\fs18 /Library/Sounds\n\\f3\\fs20 , \n\\f1\\fs18 /Network/Library/Sounds\n\\f3\\fs20 , and finally \n\\f1\\fs18 /System/Library/Sounds\n\\f3\\fs20 .  Standard OS X sounds located in \n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n/System/Library/Sounds\n\\f3\\fs20 \\cf0 \\kerning1\\expnd0\\expndtw0  include \n\\f1\\fs18 \"Basso\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Blow\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Bottle\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Frog\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Funk\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Glass\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Hero\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Morse\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Ping\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Pop\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Purr\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Sosumi\"\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 \"Submarine\"\n\\f3\\fs20 , and \n\\f1\\fs18 \"Tink\"\n\\f3\\fs20 .  Do not include the file extension, such as \n\\f1\\fs18 .aiff\n\\f3\\fs20  or \n\\f1\\fs18 .mp3\n\\f3\\fs20 , in \n\\f1\\fs18 soundName\n\\f2\\fs20 .\\\n\n\\f0\\b CAUTION:\n\\f3\\b0  When not running in EidosScribe or SLiMgui, it is often the case that the only simple means available to play a beep is to send a \n\\f1\\fs18 BEL\n\\f3\\fs20  character (ASCII 7) to the standard output.  Unfortunately, when this is the case, it means that (1) no beep will be audible if output is being redirected into a file, and (2) a control character, \n\\f1\\fs18 ^G\n\\f3\\fs20 , will occur in the output at the point when the beep was requested.  It is therefore recommended that \n\\f1\\fs18 beep()\n\\f3\\fs20  be used only when doing interactive work in a terminal shell (or in a GUI), not when producing output files.  However, this issue is platform-specific; on some platforms \n\\f1\\fs18 beep()\n\\f3\\fs20  may result in a beep, and no emitted \n\\f1\\fs18 ^G\n\\f3\\fs20 , even when output is redirected.  When a \n\\f1\\fs18 ^G\n\\f3\\fs20  must be emitted to the standard output to generate the beep, a warning message will also be emitted to make any associated problems easier to diagnose.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)citation(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints citation information for Eidos\n\\f3\\b0  to Eidos\\'92s output stream.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float$)clock([string$\\'a0type\\'a0=\\'a0\"cpu\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the value of a \n\\f0\\b system clock\n\\f3\\b0 .  If \n\\f1\\fs18 type\n\\f3\\fs20  is \n\\f1\\fs18 \"cpu\"\n\\f3\\fs20 , this returns the current value of the CPU usage clock.  This is the amount of CPU time used by the current process, in seconds; it is unrelated to the current time of day (for that, see the \n\\f1\\fs18 time()\n\\f3\\fs20  function).  This is useful mainly for determining how much processor time a given section of code takes; \n\\f1\\fs18 clock()\n\\f3\\fs20  can be called before and after a block of code, and the end clock minus the start clock gives the elapsed CPU time consumed in the execution of the block of code.  See also the \n\\f1\\fs18 timed\n\\f3\\fs20  parameter of \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 , which automates this procedure.  Note that if multiple cores are utilized by the process, the CPU usage clock will be the sum of the CPU usage across all cores, and may therefore run faster than the wall clock.\\\nIf \n\\f1\\fs18 type\n\\f3\\fs20  is \n\\f1\\fs18 \"mono\"\n\\f3\\fs20 , this returns the value of the system\\'92s monotonic clock.  This represents user-perceived (\\'93wall clock\\'94) elapsed time from some arbitrary timebase (which will not change during the execution of the program), but it will not jump if the time zone or the wall clock time are changed for the system.  This clock is useful for measuring user-perceived elapsed time, as described above, and may provide a more useful metric for performance than CPU time if multiple cores are being utilized.\n\\f2 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string$)date(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b standard date string\n\\f3\\b0  for the current date in the local time of the executing machine.  The format is \n\\f1\\fs18 %d-%m-%Y\n\\f3\\fs20  (day in two digits, then month in two digits, then year in four digits, zero-padded and separated by dashes) regardless of the localization of the executing machine, for predictability and consistency.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string$)debugIndent(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Returns the \n\\f0\\b indentation string\n\\f3\\b0  currently being used to start lines in the debugging output stream.  In a pure Eidos context this will currently be the empty string, \n\\f1\\fs18 \"\"\n\\f3\\fs20 .  In specific Contexts, such as SLiM, the debugging output stream may be structured with nested indentation, in which case this string will typically be a series of spaces or tabs.  To make your debugging output (such as from \n\\f1\\fs18 cat()\n\\f3\\fs20 , \n\\f1\\fs18 catn()\n\\f3\\fs20 , or \n\\f1\\fs18 print()\n\\f3\\fs20  with the \n\\f1\\fs18 error=T\n\\f3\\fs20  optional argument set) line up with other output at the current level of execution nesting, you can start your new lines of output with this string if you wish.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)defineConstant(string$\\'a0symbol, *\\'a0value)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Defines a new constant\n\\f3\\b0  with the name \n\\f1\\fs18 symbol\n\\f3\\fs20  and the value specified by \n\\f1\\fs18 value\n\\f3\\fs20 .  The name cannot previously be defined in any way (i.e., as either a variable or a constant).  The defined constant acts identically to intrinsic Eidos constants such as \n\\f1\\fs18 T\n\\f3\\fs20 , \n\\f1\\fs18 NAN\n\\f3\\fs20 , and \n\\f1\\fs18 PI\n\\f3\\fs20 , and will remain defined for as long as the Eidos context lives even if it is defined inside a block being executed by \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 , \n\\f1\\fs18 apply()\n\\f3\\fs20 , \n\\f1\\fs18 sapply()\n\\f3\\fs20 , or a Context-defined script block.\\\nSyntactically, \n\\f1\\fs18 value\n\\f3\\fs20  may be any value at all; semantically, however, if \n\\f1\\fs18 value\n\\f3\\fs20  is of \n\\f1\\fs18 object\n\\f3\\fs20  type then \n\\f1\\fs18 value\n\\f3\\fs20 \\'92s class must be under an internal memory-management scheme called \\'93retain-release\\'94.  Objects that are not under retain-release can cease to exist whenever the Context is finished using them, and thus a defined constant referencing such an object could become invalid, which must be prevented.  Objects that are under retain-release will not cease to exist if they are referenced by a global constant; the reference to them from the global constant \\'93retains\\'94 them and keeps them in existence.  All object classes built into Eidos are under retain-release; see the SLiM manual (section \\'93SLiM scoping rules\\'94) for discussion of which SLiM object classes are under retain-release.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)defineGlobal(string$\\'a0symbol, *\\'a0value)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Defines a new global variable\n\\f3\\b0  with the name \n\\f1\\fs18 symbol\n\\f3\\fs20  and the value specified by \n\\f1\\fs18 value\n\\f3\\fs20 .  The name cannot previously be defined as a constant.  The result is similar to a standard variable assignment with operator \n\\f1\\fs18 =\n\\f3\\fs20 , except that the variable is always defined in the global scope (even if the \n\\f1\\fs18 defineGlobal()\n\\f3\\fs20  call is made inside a user-defined function or other locally-scoped block, such as a SLiM event or callback).  This means that the variable will remain defined even after the current scope is exited.  Note that global variables can be hidden by local variables with the same name; unlike defined constants, such scoped masking is allowed.\\\nSyntactically, \n\\f1\\fs18 value\n\\f3\\fs20  may be any value at all; semantically, however, if \n\\f1\\fs18 value\n\\f3\\fs20  is of \n\\f1\\fs18 object\n\\f3\\fs20  type then \n\\f1\\fs18 value\n\\f3\\fs20 \\'92s class must be under an internal memory-management scheme called \\'93retain-release\\'94.  Objects that are not under retain-release can cease to exist whenever the Context is finished using them, and thus a global variable referencing such an object could become invalid, which must be prevented.  Objects that are under retain-release will not cease to exist if they are referenced by a global variable; the reference to them from the global variable \\'93retains\\'94 them and keeps them in existence.  All object classes built into Eidos are under retain-release; see the SLiM manual (section \\'93SLiM scoping rules\\'94) for discussion of which SLiM object classes are under retain-release.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (\\cf2 \\expnd0\\expndtw0\\kerning0\nvNlifso\\cf0 \\kerning1\\expnd0\\expndtw0 )doCall(string$\\'a0functionName, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the results from a \n\\f0\\b call to a specified function\n\\f3\\b0 .  The function named by the parameter \n\\f1\\fs18 functionName\n\\f3\\fs20  is called, and the remaining parameters to \n\\f1\\fs18 doCall()\n\\f3\\fs20  are forwarded on to that function verbatim.  This can be useful for calling one of a set of similar functions, such as \n\\f1\\fs18 sin()\n\\f3\\fs20 , \n\\f1\\fs18 cos()\n\\f3\\fs20 , etc., to perform a math function determined at runtime, or one of the \n\\f1\\fs18 as...()\n\\f3\\fs20  family of functions to convert to a type determined at runtime.  Note that named arguments and default arguments, beyond the \n\\f1\\fs18 functionName\n\\f3\\fs20  argument, are not supported by \n\\f1\\fs18 doCall()\n\\f3\\fs20 ; all arguments to the target function must be specified explicitly, without names.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (\\cf2 \\expnd0\\expndtw0\\kerning0\nvNlifso\\cf0 \\kerning1\\expnd0\\expndtw0 )executeLambda(string$\\'a0lambdaSource, [ls$\\'a0timed\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nExecutes a block of Eidos code\n\\f3\\b0  defined by \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 .  Eidos allows you to execute \n\\f7\\i lambdas\n\\f3\\i0 : blocks of Eidos code which can be called directly within the same scope as the caller.  Eidos lambdas do not take arguments; for this reason, they are not first-class functions.  (Since they share the scope of the caller, however, you may effectively pass values in and out of a lambda using variables.)  The \n\\f1\\fs18 string\n\\f3\\fs20  argument \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  may contain one or many Eidos statements as a single \n\\f1\\fs18 string\n\\f3\\fs20  value.  Lambdas are represented, to the caller, only as the source code \n\\f1\\fs18 string\n\\f3\\fs20  \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 ; the executable code is not made available programmatically.  If an error occurs during the tokenization, parsing, or execution of the lambda, that error is raised as usual; executing code inside a lambda does not provide any additional protection against exceptions raised.  The return value produced by the code in the lambda is returned by \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 .  If the optional parameter \n\\f1\\fs18 timed\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the total (CPU clock) execution time for the lambda will be printed after the lambda has completed (see \n\\f1\\fs18 clock()\n\\f3\\fs20 ); if it is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), no timing information will be printed.  The \n\\f1\\fs18 timed\n\\f3\\fs20  parameter may also be \n\\f1\\fs18 \"cpu\"\n\\f3\\fs20  or \n\\f1\\fs18 \"mono\"\n\\f3\\fs20  to specifically request timing with the CPU clock (which will count the usage across all cores, and may thus run faster than wall clock time if multiple cores are being utilized) or the monotonic clock (which will correspond, more or less, to elapsed wall clock time regardless of multithreading); see the documentation for \n\\f1\\fs18 clock()\n\\f3\\fs20  for further discussion of these timing options.\\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 The current implementation of \n\\f1\\fs18 executeLambda()\n\\f3\\fs20  caches a tokenized and parsed version of \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 , so calling \n\\f1\\fs18 executeLambda()\n\\f3\\fs20  repeatedly on a single source \n\\f1\\fs18 string\n\\f3\\fs20  is much more efficient than calling \n\\f1\\fs18 executeLambda()\n\\f3\\fs20  with a newly constructed \n\\f1\\fs18 string\n\\f3\\fs20  each time.  If you can use a \n\\f1\\fs18 string\n\\f3\\fs20  literal for \n\\f1\\fs18 lambdaSource\n\\f3\\fs20 , or reuse a constructed source \n\\f1\\fs18 string\n\\f3\\fs20  stored in a variable, that will improve performance considerably.\n\\f2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (logical)exists(string\\'a0symbol)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns a \n\\f1\\fs18 logical\n\\f3\\fs20  vector indicating \n\\f0\\b whether symbols exist\n\\f3\\b0 .  If a symbol has been defined as an intrinsic Eidos constant like \n\\f1\\fs18 T\n\\f3\\fs20 , \n\\f1\\fs18 INF\n\\f3\\fs20 , and \n\\f1\\fs18 PI\n\\f3\\fs20 , or as a Context-defined constant like \n\\f1\\fs18 sim\n\\f3\\fs20  in SLiM, or as a user-defined constant using \n\\f1\\fs18 defineConstant()\n\\f3\\fs20 , or as a variable by assignment, this function returns \n\\f1\\fs18 T\n\\f3\\fs20 .  Otherwise, the symbol has not been defined, and \n\\f1\\fs18 exists()\n\\f3\\fs20  returns \n\\f1\\fs18 F\n\\f3\\fs20 .  This is commonly used to check whether a user-defined constant already exists, with the intention of defining the constant if it has not already been defined.  A vector of symbols may be passed, producing a vector of corresponding results.\n\\f2 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)functionSignature([Ns$\n\\f2 \\'a0\n\\f1 functionName\n\\f2 \\'a0\n\\f1 =\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints function signatures\n\\f3\\b0  for all functions (if \n\\f1\\fs18 functionName\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , the default), or for the function named by \n\\f1\\fs18 functionName\n\\f3\\fs20 , to Eidos\\'92s output stream.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)functionSource(string$\\'a0functionName)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Prints the Eidos source code\n\\f3\\b0  for the function specified by \n\\f1\\fs18 functionName\n\\f3\\fs20 , or prints a diagnostic message if the function is implemented in C++ rather than Eidos.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (integer$)getSeed(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns the \n\\f0\\b random number seed\n\\f3\\b0 .  This is the last seed value set using \n\\f1\\fs18 setSeed()\n\\f3\\fs20 ; if \n\\f1\\fs18 setSeed()\n\\f3\\fs20  has not been called, it will be a seed value chosen based on the process-id and the current time when Eidos was initialized, unless the Context has set a different seed value.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)license(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints Eidos\\'92s license terms\n\\f3\\b0  to Eidos\\'92s output stream.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)ls(\\cf2 [logical$\\'a0showSymbolTables\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Prints all currently defined variables\n\\f3\\b0  to Eidos\\'92s output stream.\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 Beginning in Eidos 2.5 (SLiM 3.5), the \n\\f1\\fs18 showSymbolTables\n\\f3\\fs20  optional argument can be set to \n\\f1\\fs18 T\n\\f3\\fs20  to request full information on the current symbol table chain.  This will show which symbol table a given symbol is defined in, as well as revealing whether there are other symbols with the same name that have been masked by a local definition.  This is mostly useful for debugging.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer$)parallelGetNumThreads(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Gets the number of threads\n\\f3\\b0  that is requested be used in subsequent parallel (i.e., multithreaded) regions, as set with \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20 .  If Eidos is not configured to run multithreaded, this function will return \n\\f1\\fs18 1\n\\f3\\fs20 .  See also \n\\f1\\fs18 parallelGetMaxThreads()\n\\f3\\fs20 , which returns the maximum number of threads that can be used.  Note that if this function returns the maximum number of threads, as returned by \n\\f1\\fs18 parallelGetMaxThreads()\n\\f3\\fs20 , then there are \n\\f7\\i two possible semantic meanings\n\\f3\\i0  of that return value, which cannot be distinguished using this function; see \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20  for discussion.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer$)parallelGetMaxThreads(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Gets the maximum number of threads\n\\f3\\b0  that can be used in parallel (i.e., multithreaded) regions.  This is configured externally; it may be OpenMP\\'92s default number of threads for the hardware platform being used, or may be set by an environment variable or command-line option.  If Eidos is not configured to run multithreaded, this function will return \n\\f1\\fs18 1\n\\f3\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (object<Dictionary>$)parallelGetTaskThreadCounts(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Gets the number of threads\n\\f3\\b0  that is requested to be used for specific tasks in Eidos and SLiM.  Returns a new \n\\f1\\fs18 Dictionary\n\\f3\\fs20  containing values for all of the tasks for which a number of threads can be specified; see \n\\f1\\fs18 parallelSetTaskThreadCounts()\n\\f3\\fs20  for a list of all such tasks.  Note that the specified number of threads will not necessarily be used in practice; in particular, a thread count set by \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20  will override these per-task counts.  Also, if the task size is below a certain task-specific threshold the task will not be executed in parallel regardless of these settings.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)parallelSetNumThreads([Ni$\\'a0numThreads\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Sets the number of threads\n\\f3\\b0  that is requested to be used in subsequent parallel (i.e., multithreaded) regions.  If Eidos is not configured to run multithreaded, this function will have no effect.  The requested number of threads will be clamped to the interval [\n\\f1\\fs18 1\n\\f3\\fs20 , \n\\f1\\fs18 maxThreads\n\\f3\\fs20 ], where \n\\f1\\fs18 maxThreads\n\\f3\\fs20  is the maximum number of threads configured externally (either by OpenMP\\'92s default, or by an environment variable or command-line option).  That maximum number of threads (the value of \n\\f1\\fs18 maxThreads\n\\f3\\fs20 ) can be obtained from \n\\f1\\fs18 parallelGetMaxThreads()\n\\f3\\fs20 .\\\nThere is an important wrinkle in the semantics of this method that must be explained.  Passing \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default) resets Eidos to the default number of threads for which it is configured to run.  In this configuration, \n\\f1\\fs18 parallelGetNumThreads()\n\\f3\\fs20  will return \n\\f1\\fs18 maxThreads\n\\f3\\fs20 , but the number of threads used for any given parallel operation might not, in fact, be equal to \n\\f1\\fs18 maxThreads\n\\f3\\fs20 ; Eidos might use fewer threads if it determines that that would improve performance.  Passing the value of \n\\f1\\fs18 maxThreads\n\\f3\\fs20  explicitly, on the other hand, sets Eidos to always use \n\\f1\\fs18 maxThreads\n\\f3\\fs20  threads, even if it may result in lower performance; but in this configuration, too, \n\\f1\\fs18 parallelGetNumThreads()\n\\f3\\fs20  will return \n\\f1\\fs18 maxThreads\n\\f3\\fs20 .  For example, suppose \n\\f1\\fs18 maxThreads\n\\f3\\fs20  is \n\\f1\\fs18 16\n\\f3\\fs20 .  Passing \n\\f1\\fs18 NULL\n\\f3\\fs20  requests that Eidos use \n\\f7\\i up to\n\\f3\\i0  \n\\f1\\fs18 16\n\\f3\\fs20  threads, as it sees fit; in contrast, explicitly passing \n\\f1\\fs18 16\n\\f3\\fs20  requests that Eidos use \n\\f7\\i exactly\n\\f3\\i0  16 threads.  In both cases, however, \n\\f1\\fs18 parallelGetNumThreads()\n\\f3\\fs20  will return \n\\f1\\fs18 16\n\\f3\\fs20 .\\\nIf you wish to temporarily change the number of threads used, the standard pattern is to call \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20  with the number of threads you want to use, do the operation you wish to control, and then call \n\\f1\\fs18 parallelSetNumThreads(NULL)\n\\f3\\fs20  to return to the default behavior of Eidos.\\\nNote that the number of threads requested here overrides any per-task request set with \n\\f1\\fs18 parallelSetTaskThreadCounts()\n\\f3\\fs20 .  Also, if the task size is below a certain task-specific threshold the task will not be executed in parallel regardless of these settings.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)parallelSetTaskThreadCounts(No<Dictionary>$\\'a0dict)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Sets the number of threads\n\\f3\\b0  that is requested to be used for specific tasks in Eidos and SLiM.  The dictionary \n\\f1\\fs18 dict\n\\f3\\fs20  should contain \n\\f1\\fs18 string\n\\f3\\fs20  keys that identify tasks, and \n\\f1\\fs18 integer\n\\f3\\fs20  values that provide the number of threads to be used when performing those tasks.  For example, a key of \n\\f1\\fs18 \"LOG10_FLOAT\"\n\\f3\\fs20  identifies the task of performing the \n\\f1\\fs18 log10()\n\\f3\\fs20  function on a \n\\f1\\fs18 float\n\\f3\\fs20  vector, and a value of \n\\f1\\fs18 8\n\\f3\\fs20  for that key would tell Eidos to use eight threads when performing that task.  The number of threads actually used will never be greater than the maximum thread count as returned by \n\\f1\\fs18 parallelGetMaxThreads()\n\\f3\\fs20 .  Furthermore, a thread count set with \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20  overrides the per-task setting, so if you wish to set specific per-task thread counts you should not set an overall thread count with \n\\f1\\fs18 parallelSetNumThreads()\n\\f3\\fs20 .  If \n\\f1\\fs18 dict\n\\f3\\fs20  is \n\\f1\\fs18 NULL\n\\f3\\fs20 , all task thread counts will be reset to their default values.\\\nThe currently requested thread counts for all tasks can be obtained with \n\\f1\\fs18 parallelGetTaskThreadCounts()\n\\f3\\fs20 .  Note that the counts returned by that function may not match the counts requested with \n\\f1\\fs18 parallelSetTaskThreadCounts()\n\\f3\\fs20 ; in particular, they may be clipped to the maximum number of threads as returned by \n\\f1\\fs18 parallelGetMaxThreads()\n\\f3\\fs20 .\\\nThe task keys recognized, and the tasks they govern, are:\\\n\\pard\\tx4320\\pardeftab720\\li1080\\sa180\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \"ABS_FLOAT\"\tabs(float x)\\uc0\\u8232 \"CEIL\"\tceil()\\u8232 \"EXP_FLOAT\"\texp(float x)\\u8232 \"FLOOR\"\tfloor()\\u8232 \"LOG_FLOAT\"\tlog(float x)\\u8232 \"LOG10_FLOAT\"\tlog10(float x)\\u8232 \"LOG2_FLOAT\"\tlog2(float x)\\u8232 \"ROUND\"\tround()\\u8232 \"SQRT_FLOAT\"\tsqrt(float x)\\u8232 \"SUM_INTEGER\"\tsum(integer x)\\u8232 \"SUM_FLOAT\"\tsum(float x)\\u8232 \"SUM_LOGICAL\"\tsum(logical x)\\u8232 \"TRUNC\"\ttrunc()\\\n\"MAX_INT\"\tmax(integer x)\\uc0\\u8232 \"MAX_FLOAT\"\tmax(float x)\\u8232 \"MIN_INT\"\tmin(integer x)\\u8232 \"MIN_FLOAT\"\tmin(float x)\\u8232 \"PMAX_INT_1\"\tpmax(i$ x, i y) / pmax(i x, i$ y)\\u8232 \"PMAX_INT_2\"\tpmax(integer x, integer y)\\u8232 \"PMAX_FLOAT_1\"\tpmax(f$ x, f y) / pmax(f x, f$ y)\\u8232 \"PMAX_FLOAT_2\"\tpmax(float x, float y)\\u8232 \"PMIN_INT_1\"\tpmin(i$ x, i y) / pmax(i x, i$ y)\\u8232 \"PMIN_INT_2\"\tpmin(integer x, integer y)\\u8232 \"PMIN_FLOAT_1\"\tpmin(f$ x, f y) / pmin(f x, f$ y)\\u8232 \"PMIN_FLOAT_2\"\tpmin(float x, float y)\\\n\"MATCH_INT\"\tmatch(integer x, integer table)\\uc0\\u8232 \"MATCH_FLOAT\"\tmatch(float x, float table)\\u8232 \"MATCH_STRING\"\tmatch(string x, string table)\\u8232 \"MATCH_OBJECT\"\tmatch(object x, object table)\\u8232 \"SAMPLE_INDEX\"\tsample()\n\\f3\\fs20  index buffer generation (internal)\n\\f1\\fs18 \\uc0\\u8232 \"SAMPLE_R_INT\"\tsample(integer x, weights=NULL)\\u8232 \"SAMPLE_R_FLOAT\"\tsample(float x, weights=NULL)\\u8232 \"SAMPLE_R_OBJECT\"\tsample(object x, weights=NULL)\\u8232 \"SAMPLE_WR_INT\"\tsample(integer x, if weights)\\u8232 \"SAMPLE_WR_FLOAT\"\tsample(float x, if weights)\\u8232 \"SAMPLE_WR_OBJECT\"\tsample(object x, if weights)\\u8232 \"TABULATE_MAXBIN\"\ttabulate()\n\\f3\\fs20  determination of \n\\f1\\fs18 maxbin\n\\f3\\fs20  (if not supplied)\n\\f1\\fs18 \\uc0\\u8232 \"TABULATE\"\ttabulate()\n\\f3\\fs20  main loop\n\\f1\\fs18 \\\n\"DNORM_1\"\tdnorm(numeric$ mean, numeric$ sd)\\uc0\\u8232 \"DNORM_2\"\tdnorm()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RBINOM_1\"\trbinom(i$ size = 1, f$ prob = 0.5)\\u8232 \"RBINOM_2\"\trbinom(i$ size, f$ prob)\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RBINOM_3\"\trbinom()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RDUNIF_1\"\trdunif(i$ min = 0, i$ max = 1)\n\\f3\\fs20  and similar\n\\f1\\fs18 \\uc0\\u8232 \"RDUNIF_2\"\trdunif(i$ min, i$ max)\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RDUNIF_3\"\trdunif()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"REXP_1\"\trexp(numeric$ mu)\\u8232 \"REXP_2\"\trexp()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RNORM_1\"\trnorm(numeric$ mean, numeric$ sd)\\u8232 \"RNORM_2\"\trnorm(numeric$ sigma)\\u8232 \"RNORM_3\"\trnorm()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RPOIS_1\"\trpois(numeric$ lambda)\\u8232 \"RPOIS_2\"\trpois()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RUNIF_1\"\trunif(numeric$ min = 0, numeric$ max = 1)\\u8232 \"RUNIF_2\"\trunif(numeric$ min, numeric$ max)\n\\f3\\fs20  other cases\n\\f1\\fs18 \\uc0\\u8232 \"RUNIF_3\"\trunif()\n\\f3\\fs20  other cases\n\\f1\\fs18 \\\n\"SORT_INT\"\tsort(integer x)\\uc0\\u8232 \"SORT_FLOAT\"\tsort(float x)\\u8232 \"SORT_STRING\"\tsort(string x)\\\n\"CLIPPEDINTEGRAL_1S\"\tclippedIntegral()\n\\f3\\fs20  for \n\\f1\\fs18 \"x\"\n\\f3\\fs20 , \n\\f1\\fs18 \"y\"\n\\f3\\fs20 , \n\\f1\\fs18 \"z\"\\uc0\\u8232 \"CLIPPEDINTEGRAL_2S\"\tclippedIntegral()\n\\f3\\fs20  for \n\\f1\\fs18 \"xy\"\n\\f3\\fs20 , \n\\f1\\fs18 \"xz\"\n\\f3\\fs20 , \n\\f1\\fs18 \"yz\"\\uc0\\u8232 \"DRAWBYSTRENGTH\"\tdrawByStrength(returnDict=T)\\u8232 \"INTNEIGHCOUNT\"\tinteractingNeighborSount()\\u8232 \"LOCALPOPDENSITY\"\tlocalPopulationDensity()\\u8232 \"NEARESTINTNEIGH\"\tnearestInteractingNeighbors(returnDict=T)\\u8232 \"NEARESTNEIGH\"\tnearestNeighbors(returnDict=T)\\u8232 \"NEIGHCOUNT\"\tneighborCount()\\u8232 \"TOTNEIGHSTRENGTH\"\ttotalOfNeighborsStrengths()\\\n\"POINT_IN_BOUNDS_1D\"\tpointInBounds()\n\\f3\\fs20 , 1D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_IN_BOUNDS_2D\"\tpointInBounds()\n\\f3\\fs20 , 2D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_IN_BOUNDS_3D\"\tpointInBounds()\n\\f3\\fs20 , 3D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_PERIODIC_1D\"\tpointPeriodic()\n\\f3\\fs20 , 1D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_PERIODIC_2D\"\tpointPeriodic()\n\\f3\\fs20 , 2D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_PERIODIC_3D\"\tpointPeriodic()\n\\f3\\fs20 , 3D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_REFLECTED_1D\"\tpointReflected()\n\\f3\\fs20 , 1D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_REFLECTED_2D\"\tpointReflected()\n\\f3\\fs20 , 2D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_REFLECTED_3D\"\tpointReflected()\n\\f3\\fs20 , 3D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_STOPPED_1D\"\tpointStopped()\n\\f3\\fs20 , 1D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_STOPPED_2D\"\tpointStopped()\n\\f3\\fs20 , 2D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_STOPPED_3D\"\tpointStopped()\n\\f3\\fs20 , 3D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_UNIFORM_1D\"\tpointUniform()\n\\f3\\fs20 , 1D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_UNIFORM_2D\"\tpointUniform()\n\\f3\\fs20 , 2D case\n\\f1\\fs18 \\uc0\\u8232 \"POINT_UNIFORM_3D\"\tpointUniform()\n\\f3\\fs20 , 3D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_1_1D\"\tsetSpatialPosition()\n\\f3\\fs20  with one point, 1D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_1_2D\"\tsetSpatialPosition()\n\\f3\\fs20  with one point, 2D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_1_3D\"\tsetSpatialPosition()\n\\f3\\fs20  with one point, 3D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_2_1D\"\tsetSpatialPosition()\n\\f3\\fs20  with \n\\f7\\i N\n\\f3\\i0  points, 1D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_2_2D\"\tsetSpatialPosition()\n\\f3\\fs20  with \n\\f7\\i N\n\\f3\\i0  points, 2D case\n\\f1\\fs18 \\uc0\\u8232 \"SET_SPATIAL_POS_2_3D\"\tsetSpatialPosition()\n\\f3\\fs20  with \n\\f7\\i N\n\\f3\\i0  points, 3D case\n\\f1\\fs18 \\uc0\\u8232 \"SPATIAL_MAP_VALUE\"\tspatialMapValue()\\\n\"CONTAINS_MARKER_MUT\"\tcontainsMarkerMutation(returnMutation = F)\\uc0\\u8232 \"I_COUNT_OF_MUTS_OF_TYPE\"\tcountOfMutationsOfType() (Individual)\\u8232 \"H_COUNT_OF_MUTS_OF_TYPE\"\tcountOfMutationsOfType() (Haplosome)\\u8232 \"INDS_W_PEDIGREE_IDS\"\tindividualsWithPedigreeIDs()\\u8232 \"RELATEDNESS\"\trelatedness()\\u8232 \"SAMPLE_INDIVIDUALS_1\"\tsampleIndividuals()\n\\f3\\fs20  simple case with replace=T\n\\f1\\fs18 \\uc0\\u8232 \"SAMPLE_INDIVIDUALS_2\"\tsampleIndividuals()\n\\f3\\fs20  base case with replace=T\n\\f1\\fs18 \\uc0\\u8232 \"SET_FITNESS_SCALE_1\"\tIndividual.fitness = \n\\f3\\fs20 one value\n\\f1\\fs18 \\uc0\\u8232 \"SET_FITNESS_SCALE_2\"\tIndividual.fitness = \n\\f7\\i\\fs20 N\n\\f3\\i0  values\n\\f1\\fs18 \\uc0\\u8232 \"SUM_OF_MUTS_OF_TYPE\"\tsumOfMutationsOfType()\\\n\"AGE_INCR\"\t\n\\f3\\fs20 incrementing \n\\f1\\fs18 Individual age\n\\f3\\fs20  values\n\\f1\\fs18 \\uc0\\u8232 \"DEFERRED_REPRO\"\t\n\\f3\\fs20 deferred nonWF reproduction\n\\f1\\fs18 \\uc0\\u8232 \"WF_REPRO\"\t\n\\f3\\fs20 WF reproduction (no callbacks)\n\\f1\\fs18 \\uc0\\u8232 \"FITNESS_ASEX_1\"\t\n\\f3\\fs20 fitness eval, asex, individual \n\\f1\\fs18 fitnessScaling\\uc0\\u8232 \"FITNESS_ASEX_2\"\t\n\\f3\\fs20 fitness eval, asex, no \n\\f1\\fs18 fitnessScaling\n\\f3\\fs20  or mutations\n\\f1\\fs18 \\uc0\\u8232 \"FITNESS_ASEX_3\"\t\n\\f3\\fs20 fitness eval, asex, \n\\f1\\fs18 fitnessScaling\n\\f3\\fs20  and mutations\n\\f1\\fs18 \\uc0\\u8232 \"FITNESS_SEX_1\"\t\n\\f3\\fs20 fitness eval, sexual, individual \n\\f1\\fs18 fitnessScaling\\uc0\\u8232 \"FITNESS_SEX_2\"\t\n\\f3\\fs20 fitness eval, sexual, no \n\\f1\\fs18 fitnessScaling\n\\f3\\fs20  or mutations\n\\f1\\fs18 \\uc0\\u8232 \"FITNESS_SEX_3\"\t\n\\f3\\fs20 fitness eval, sexual, \n\\f1\\fs18 fitnessScaling\n\\f3\\fs20  and mutations\n\\f1\\fs18 \\uc0\\u8232 \"MIGRANT_CLEAR\"\t\n\\f3\\fs20 clearing the \n\\f1\\fs18 migrant\n\\f3\\fs20  property at tick end\n\\f1\\fs18 \\uc0\\u8232 \"SIMPLIFY_SORT_PRE\"\t\n\\f3\\fs20 preparation for simplification sorting (internal)\n\\f1\\fs18 \\uc0\\u8232 \"SIMPLIFY_SORT\"\t\n\\f3\\fs20 simplification sorting\n\\f1\\fs18 \\uc0\\u8232 \"SIMPLIFY_SORT_POST\"\t\n\\f3\\fs20 cleanup after simplification sorting (internal)\n\\f1\\fs18 \\uc0\\u8232 \"PARENTS_CLEAR\"\t\n\\f3\\fs20 clearing parental haplosomes at tick end in WF models\n\\f1\\fs18 \\uc0\\u8232 \"UNIQUE_MUTRUNS\"\t\n\\f3\\fs20 uniquing mutation runs (internal bookkeeping)\n\\f1\\fs18 \\uc0\\u8232 \"SURVIVAL\"\t\n\\f3\\fs20 survival evaluation (no callbacks)\n\\f1\\fs18 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 Typically, a dictionary of task keys and thread counts is read from a file and set up with this function at initialization time, but it is also possible to change new task thread counts dynamically.  If Eidos is not configured to run multithreaded, this function has no effect.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (string$)readLine(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Reads a line of input from the \\'93standard input\\'94 file.\n\\f3\\b0   This function is intended to allow for communication between a running Eidos script (such as a SLiM simulation) and an external process that is sending input to it.  It reads one line from the standard input and returns it as a singleton \n\\f1\\fs18 string\n\\f3\\fs20 .  This is done with the C++ function \n\\f1\\fs18 std::getline()\n\\f3\\fs20 , using the \n\\f1\\fs18 std::cin\n\\f3\\fs20  file.  If that call returns false (typically because the end-of-file was reached or there was a read error of some kind), the empty string \n\\f1\\fs18 \"\"\n\\f3\\fs20  will be returned.  The \n\\f1\\fs18 system()\n\\f3\\fs20  function can also be helpful for related situations.\\\nThis function will raise an error if called in a GUI environment such as EidosScribe, SLiMgui, or SLiMguiLegacy, since there is no standard input set up for the running script in those environments.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)rm([Ns\\'a0variableNames\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Removes variables\n\\f3\\b0  from the Eidos namespace; in other words, it causes the variables to become undefined.  Variables are specified by their \n\\f1\\fs18 string\n\\f3\\fs20  name in the \n\\f1\\fs18 variableNames\n\\f3\\fs20  parameter.  If the optional \n\\f1\\fs18 variableNames\n\\f3\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f3\\fs20  (the default), \n\\f7\\i all\n\\f3\\i0  variables will be removed (be careful!).\\\nIn SLiM 3, there was an optional parameter \n\\f1\\fs18 removeConstants\n\\f3\\fs20  that, if \n\\f1\\fs18 T\n\\f3\\fs20 , allowed you to remove defined constants (and then potentially redefine them to have a different value).  The \n\\f1\\fs18 removeConstants\n\\f3\\fs20  parameter was removed in SLiM 4, since the \n\\f1\\fs18 defineGlobal()\n\\f3\\fs20  function now provides the ability to define (and redefine) global variables that are not constant.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (*)sapply(*\\'a0x, string$\\'a0lambdaSource, [string$\\'a0simplify\\'a0=\\'a0\"vector\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f7\\i\\fs20 \\cf4 \\expnd0\\expndtw0\\kerning0\nNamed \n\\f5\\fs18 apply()\n\\f7\\fs20  prior to Eidos 1.6 / SLiM 2.6\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\i0\\b \\cf2 Applies a block of Eidos code to the elements of x\n\\f3\\b0 .  This function is sort of a hybrid between \n\\f1\\fs18 c()\n\\f3\\fs20  and \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 ; it might be useful to consult the documentation for both of those functions to better understand what \n\\f1\\fs18 sapply()\n\\f3\\fs20  does.  For each element in \n\\f1\\fs18 x\n\\f3\\fs20 , the lambda defined by \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  will be called.  For the duration of that callout, a variable named \n\\f1\\fs18 applyValue\n\\f3\\fs20  will be defined to have as its value the element of \n\\f1\\fs18 x\n\\f3\\fs20  currently being processed.  The expectation is that the lambda will use \n\\f1\\fs18 applyValue\n\\f3\\fs20  in some way, and will return either \n\\f1\\fs18 NULL\n\\f3\\fs20  or a new value (which need not be a singleton, and need not be of the same type as \n\\f1\\fs18 x\n\\f3\\fs20 ).  The return value of \n\\f1\\fs18 sapply()\n\\f3\\fs20  is generated by concatenating together all of the individual vectors returned by the lambda, in exactly the same manner as the \n\\f1\\fs18 c()\n\\f3\\fs20  function (including the possibility of type promotion).\\\nSince this function can be hard to understand at first, here is an example:\\\n\n\\f1\\fs18 sapply(1:10, \"if (applyValue % 2) applyValue ^ 2; else NULL;\");\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 This produces the output \n\\f1\\fs18 1 9 25 49 81\n\\f3\\fs20 .  The \n\\f1\\fs18 sapply()\n\\f3\\fs20  operation begins with the vector \n\\f1\\fs18 1:10\n\\f3\\fs20 .  For each element of that vector, the lambda is called and \n\\f1\\fs18 applyValue\n\\f3\\fs20  is defined with the element value.  In this respect, \n\\f1\\fs18 sapply()\n\\f3\\fs20  is actually very much like a \n\\f1\\fs18 for\n\\f3\\fs20  loop.  If \n\\f1\\fs18 applyValue\n\\f3\\fs20  is even (as evaluated by the modulo operator, \n\\f1\\fs18 %\n\\f3\\fs20 ), the condition of the \n\\f1\\fs18 if\n\\f3\\fs20  statement is \n\\f1\\fs18 F\n\\f3\\fs20  and so \n\\f1\\fs18 NULL\n\\f3\\fs20  is returned by the lambda; this must be done explicitly, since a \n\\f1\\fs18 void\n\\f3\\fs20  return is not allowed by \n\\f1\\fs18 sapply()\n\\f3\\fs20 .  If \n\\f1\\fs18 applyValue\n\\f3\\fs20  is odd, on the other hand, the lambda returns its square (as calculated by the exponential operator, \n\\f1\\fs18 ^\n\\f3\\fs20 ).  Just as with the \n\\f1\\fs18 c()\n\\f3\\fs20  function, \n\\f1\\fs18 NULL\n\\f3\\fs20  values are dropped during concatenation, so the final result contains only the squares of the odd values.\\expnd0\\expndtw0\\kerning0\n\\\nThis example illustrates that the lambda can \\'93drop\\'94 values by returning \n\\f1\\fs18 NULL\n\\f3\\fs20 , so \n\\f1\\fs18 sapply()\n\\f3\\fs20  can be used to select particular elements of a vector that satisfy some condition, much like the subscript operator, \n\\f1\\fs18 []\n\\f3\\fs20 .  The example also illustrates that input and result types do not have to match; the vector passed in is \n\\f1\\fs18 integer\n\\f3\\fs20 , whereas the result vector is \n\\f1\\fs18 float\n\\f3\\fs20 .\\\nBeginning in Eidos 1.6, a new optional parameter named \n\\f1\\fs18 simplify\n\\f3\\fs20  allows the result of \n\\f1\\fs18 sapply()\n\\f3\\fs20  to be a matrix or array in certain cases, better organizing the elements of the result.  If the \n\\f1\\fs18 simplify\n\\f3\\fs20  parameter is \n\\f1\\fs18 \"vector\"\n\\f3\\fs20 , the concatenated result value is returned as a plain vector in all cases; this is the default behavior, for backward compatibility.  Two other possible values for \n\\f1\\fs18 simplify\n\\f3\\fs20  are presently supported.  If \n\\f1\\fs18 simplify\n\\f3\\fs20  is \n\\f1\\fs18 \"matrix\"\n\\f3\\fs20 , the concatenated result value will be turned into a matrix with one column for each non-\n\\f1\\fs18 NULL\n\\f3\\fs20  value returned by the lambda, as if the values were joined together with \n\\f1\\fs18 cbind()\n\\f3\\fs20 , as long as all of the lambda\\'92s return values are either (a) \n\\f1\\fs18 NULL\n\\f3\\fs20  or (b) the same length as the other non-\n\\f1\\fs18 NULL\n\\f3\\fs20  values returned.  If \n\\f1\\fs18 simplify\n\\f3\\fs20  is \n\\f1\\fs18 \"match\"\n\\f3\\fs20 , the concatenated result value will be turned into a vector, matrix, or array that exactly matches the dimensions as \n\\f1\\fs18 x\n\\f3\\fs20 , with a one-to-one correspondence between \n\\f1\\fs18 x\n\\f3\\fs20  and the elements of the return value just like a unary operator, as long as all of the lambda\\'92s return values are singletons (with no \n\\f1\\fs18 NULL\n\\f3\\fs20  values).  Both \n\\f1\\fs18 \"matrix\"\n\\f3\\fs20  and \n\\f1\\fs18 \"match\"\n\\f3\\fs20  will raise an error if their preconditions are not met, to avoid unexpected behavior, so care should be taken that the preconditions are always met when these options are used.\\\nAs with \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 , all defined variables are accessible within the lambda, and changes made to variables inside the lambda will persist beyond the end of the \n\\f1\\fs18 sapply()\n\\f3\\fs20  call; the lambda is executing in the same scope as the rest of your code.\\\nThe \n\\f1\\fs18 sapply()\n\\f3\\fs20  function can seem daunting at first, but it is an essential tool in the Eidos toolbox.  It combines the iteration of a \n\\f1\\fs18 for\n\\f3\\fs20  loop, the ability to select elements like operator \n\\f1\\fs18 []\n\\f3\\fs20 , and the ability to assemble results of mixed type together into a single vector like \n\\f1\\fs18 c()\n\\f3\\fs20 , all with the power of arbitrary Eidos code execution like \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 .  It is relatively fast, compared to other ways of achieving similar results such as a \n\\f1\\fs18 for\n\\f3\\fs20  loop that accumulates results with \n\\f1\\fs18 c()\n\\f3\\fs20 .  Like \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 , \n\\f1\\fs18 sapply()\n\\f3\\fs20  is most efficient if it is called multiple times with a single \n\\f1\\fs18 string\n\\f3\\fs20  script variable, rather than with a newly constructed \n\\f1\\fs18 string\n\\f3\\fs20  for \n\\f1\\fs18 lambdaSource\n\\f3\\fs20  each time.\\\nPrior to Eidos 1.6 (SLiM 2.6), \n\\f1\\fs18 sapply()\n\\f3\\fs20  was instead named \n\\f1\\fs18 apply()\n\\f3\\fs20 ; it was renamed to \n\\f1\\fs18 sapply()\n\\f3\\fs20  in order to more closely match the naming of functions in R.  This renaming allowed a new \n\\f1\\fs18 apply()\n\\f3\\fs20  function to be added to Eidos that operates on the margins of matrices and arrays, similar to the \n\\f1\\fs18 apply()\n\\f3\\fs20  function of R (see \n\\f1\\fs18 apply()\n\\f3\\fs20 , above).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (void)setSeed(integer$\\'a0seed)\n\\f2 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Set the random number seed\n\\f3\\b0 .  Future random numbers will be based upon the seed value set, and the random number sequence generated from a particular seed value is guaranteed to be reproducible.  The last seed set can be recovered with the \n\\f1\\fs18 getSeed()\n\\f3\\fs20  function.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)source(string$\n\\f2 \\'a0\n\\f1 filePath\\cf2 , [logical$\\'a0chdir\\'a0=\\'a0F]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Executes the contents of an Eidos source file\n\\f3\\b0  found at the filesystem path \n\\f1\\fs18 filePath\n\\f3\\fs20 .  This is essentially shorthand for calling \n\\f1\\fs18 readFile()\n\\f3\\fs20 , joining the read lines with newlines to form a single string using \n\\f1\\fs18 paste()\n\\f3\\fs20 , and then passing that string to \n\\f1\\fs18 executeLambda()\n\\f3\\fs20 .  The source file must consist of complete Eidos statements.  Regardless of what the last executed source line evaluates to, \n\\f1\\fs18 source()\n\\f3\\fs20  has no return value.  If no file exists at \n\\f1\\fs18 filePath\n\\f3\\fs20 , an error will be raised.\\\nThe \n\\f1\\fs18 chdir\n\\f3\\fs20  parameter controls the current working directory in effect while the source file is executed.  If \n\\f1\\fs18 chdir\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20  (the default), the current working directory will remain unchanged.  If \n\\f1\\fs18 chdir\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the current working directory will be temporarily changed to the filesystem path at which the source file is located, and restored after execution of the source file is complete.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)stop([Ns$\n\\f2 \\'a0\n\\f1 message\n\\f2 \\'a0\n\\f1 =\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Stops execution\n\\f3\\b0  of Eidos (and of the Context, such as the running SLiM simulation, if applicable), in the event of an error.  If the optional \n\\f1\\fs18 message\n\\f3\\fs20  parameter is not \n\\f1\\fs18 NULL\n\\f3\\fs20 , it will be printed to Eidos\\'92s output stream prior to stopping.\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(logical$)suppressWarnings(logical$\\'a0suppress)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Turns suppression of warning messages on or off\n\\f3\\b0 .  The \n\\f1\\fs18 suppress\n\\f3\\fs20  flag indicates whether suppression of warnings should be enabled (\n\\f1\\fs18 T\n\\f3\\fs20 ) or disabled (\n\\f1\\fs18 F\n\\f3\\fs20 ).  The previous warning-suppression value is returned by \n\\f1\\fs18 suppressWarnings()\n\\f3\\fs20 , making it easy to suppress warnings from a given call and then return to the previous suppression state afterwards.  It is recommended that warnings be suppressed only around short blocks of code (not all the time), so that unexpected but perhaps important warnings are not missed.  And of course warnings are generally emitted for good reasons; before deciding to disregard a given warning, make sure that you understand exactly why it is being issued, and are certain that it does not represent a serious problem.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (*)sysinfo(string$\\'a0key)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 Returns information about the system\n\\f3\\b0 .  The information returned by \n\\f1\\fs18 tempdir()\n\\f3\\fs20  depends upon the value of \n\\f1\\fs18 key\n\\f3\\fs20 , which selects one of the pieces of information listed:\\\n\\pard\\pardeftab2160\\li547\\fi360\\sa60\\partightenfactor0\n\n\\f0\\b \\cf2 \\ul \\ulc2 key\n\\f3\\b0 \\ulnone \t\n\\f0\\b \\ul value\n\\f3\\b0 \\ulnone \\\n\\pard\\pardeftab2160\\li547\\fi360\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 os\n\\f3\\fs20 \tthe name of the OS; \n\\f1\\fs18 \"macOS\"\n\\f3\\fs20  or \n\\f1\\fs18 \"Windows\"\n\\f3\\fs20 , or \n\\f1\\fs18 \"Unix\"\n\\f3\\fs20  for all others\\\n\n\\f1\\fs18 sysname\n\\f3\\fs20 \tthe name of the kernel\\\n\n\\f1\\fs18 release\n\\f3\\fs20 \tthe operating system (kernel) release\\\n\n\\f1\\fs18 version\n\\f3\\fs20 \tthe operating system (kernel) version\\\n\n\\f1\\fs18 nodename\n\\f3\\fs20 \tthe name by which the machine is known on the network\\\n\n\\f1\\fs18 machine\n\\f3\\fs20 \tthe hardware type; often the CPU type (e.g., \n\\f1\\fs18 \"x86_64\"\n\\f3\\fs20 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 The value \n\\f1\\fs18 \"unknown\"\n\\f3\\fs20  will be returned for a key if the correct value cannot be ascertained.  Note that the values of keys that refer to the kernel may not be what you expect; for example, on one particular macOS 10.15.7 system, \n\\f1\\fs18 sysname\n\\f3\\fs20  returns \n\\f1\\fs18 \"Darwin\"\n\\f3\\fs20 , \n\\f1\\fs18 release\n\\f3\\fs20  returns \n\\f1\\fs18 \"19.6.0\"\n\\f3\\fs20 , and \n\\f1\\fs18 version\n\\f3\\fs20  returns \n\\f1\\fs18 \"Darwin Kernel Version 19.6.0: Thu Sep 16 20:58:47 PDT 2021; root:xnu-6153.141.40.1~1/RELEASE_X86_64\"\n\\f3\\fs20 .\\\nFurther keys can be added if there is information that would be useful, particularly if a cross-platform way to obtain the information can be found.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (string)system(string$\\'a0command, [string\\'a0args\\'a0=\\'a0\"\"], [string\\'a0input\\'a0=\\'a0\"\"], [logical$\\'a0stderr\\'a0=\\'a0F], [logical$\\'a0wait\\'a0=\\'a0T])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf0 Runs a Un*x command in a \n\\f9\\fs18 /bin/sh\n\\f0\\fs20  shell\n\\f3\\b0  with optional arguments and input, and returns the result as a vector of output lines.  The \n\\f1\\fs18 args\n\\f3\\fs20  parameter may contain a vector of arguments to \n\\f1\\fs18 command\n\\f3\\fs20 ; they will be passed directly to the shell without any quoting, so applying the appropriate quoting as needed by \n\\f1\\fs18 /bin/sh\n\\f3\\fs20  is the caller\\'92s responsibility.  The arguments are appended to \n\\f1\\fs18 command\n\\f3\\fs20 , separated by spaces, and the result is passed to the shell as a single command string, so arguments may simply be given as part of \n\\f1\\fs18 command\n\\f3\\fs20  instead, if preferred.  By default no input is supplied to \n\\f1\\fs18 command\n\\f3\\fs20 ; if \n\\f1\\fs18 input\n\\f3\\fs20  is non-empty, however, it will be written to a temporary file (one line per \n\\f1\\fs18 string\n\\f3\\fs20  element) and the standard input of \n\\f1\\fs18 command\n\\f3\\fs20  will be redirected to that temporary file (using standard \n\\f1\\fs18 /bin/sh\n\\f3\\fs20  redirection with \n\\f1\\fs18 <\n\\f3\\fs20 , appended to the command string passed to the shell).  By default, output sent to standard error will not be captured (and thus may end up in the output of the SLiM process, or may be lost); if \n\\f1\\fs18 stderr\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , however, the standard error stream will be redirected into standard out (using standard \n\\f1\\fs18 /bin/sh\n\\f3\\fs20  redirection with \n\\f1\\fs18 2>&1\n\\f3\\fs20 , appended to the command string passed to the shell).\\\nArbitrary command strings involving multiple commands, pipes, redirection, etc., may be used with \n\\f1\\fs18 system()\n\\f3\\fs20 , but may be incompatible with the way that \n\\f1\\fs18 args\n\\f2\\fs20 ,\n\\f3  \n\\f1\\fs18 input\n\\f3\\fs20 , and \n\\f1\\fs18 stderr\n\\f3\\fs20  are handled by this function, so in this case supplying the whole command string in \n\\f1\\fs18 command\n\\f3\\fs20  may be the simplest course.  You may redirect standard error into standard output yourself in \n\\f1\\fs18 command\n\\f3\\fs20  with \n\\f1\\fs18 2>&1\n\\f2\\fs20 .\n\\f3   Supplying input to a complex command line can often be facilitated by the use of parentheses to create a subshell; for example,\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab543\\li900\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f1\\fs18 \\cf0 system(\"(wc -l | sed 's/ //g')\", input=c('foo', 'bar', 'baz'));\n\\f2 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 will supply the input lines to \n\\f1\\fs18 wc\n\\f3\\fs20  courtesy of the subshell started for the \n\\f1\\fs18 ()\n\\f3\\fs20  operator.  If this strategy doesn\\'92t work for the command line you want to execute, you can always write a temporary file yourself using \n\\f1\\fs18 writeFile()\n\\f3\\fs20  or \n\\f1\\fs18 writeTempFile()\n\\f3\\fs20  and redirect that file to standard input in \n\\f1\\fs18 command\n\\f3\\fs20  with \n\\f1\\fs18 <\n\\f2\\fs20 .\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3 \\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f1\\fs18 wait\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20  (the default), \n\\f1\\fs18 system()\n\\f3\\fs20  will wait for the command to finish, and return the output generated as a \n\\f1\\fs18 string\n\\f3\\fs20  vector, as described above.  If \n\\f1\\fs18 wait\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 , \n\\f1\\fs18 system()\n\\f3\\fs20  will instead append \n\\f1\\fs18 \" &\"\n\\f3\\fs20  to the end of the command line to request that it be run in the background, and it will not collect and return the output from the command; instead it will return \n\\f1\\fs18 string(0)\n\\f3\\fs20  immediately.  If the output from the command is needed, it could be redirected to a file, and that file could be checked periodically in Eidos for some indication that the command had completed; if output is not redirected to a file, it may appear in SLiM\\'92s output stream.  If the final command line executed by \n\\f1\\fs18 system()\n\\f3\\fs20  ends in \n\\f1\\fs18 \" &\"\n\\f3\\fs20 , the behavior of \n\\f1\\fs18 system()\n\\f3\\fs20  should be just as if \n\\f1\\fs18 wait=T\n\\f3\\fs20  had been supplied, but it is recommended to use \n\\f1\\fs18 wait=T\n\\f3\\fs20  instead to ensure that the command line is correctly assembled.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 There is an example at {\\field{\\*\\fldinst{HYPERLINK \"https://github.com/MesserLab/SLiM-Extras/blob/master/functions/rgnorm.slim\"}}{\\fldrslt \\cf3 \\ul \\ulc3 https://github.com/MesserLab/SLiM-Extras/blob/master/functions/rgnorm.slim}} that demonstrates the use of \n\\f1\\fs18 system()\n\\f3\\fs20 , calling out to Python, to obtain draws from a generalized normal distribution (which is not supported intrinsically by Eidos).  That example even includes internal buffering of a large number of draws, making it a reasonably efficient solution.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (string$)time(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf0 Returns a \n\\f0\\b standard time string\n\\f3\\b0  for the current time in the local time of the executing machine.  The format is \n\\f1\\fs18 %H:%M:%S\n\\f3\\fs20  (hour in two digits, then minute in two digits, then seconds in two digits, zero-padded and separated by dashes) regardless of the localization of the executing machine, for predictability and consistency.  The 24-hour clock time is used (i.e., no AM/PM).\n\\f2 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(float$)usage(\\kerning1\\expnd0\\expndtw0 [ls$\\'a0type\\'a0=\\'a0\"rss\"]\\expnd0\\expndtw0\\kerning0\n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns the \n\\f0\\b memory usage\n\\f3\\b0 .  This is the amount of memory used by the current process, in MB (megabytes); multiply by \n\\f1\\fs18 1024*1024\n\\f3\\fs20  to get the usage in bytes.\\\nMemory usage is a surprisingly complex topic.  One metric reported by \n\\f1\\fs18 usage()\n\\f3\\fs20  is the resident set size, or RSS, which includes memory usage from shared libraries, but does not include memory that is swapped out or has never been used.  For most purposes, RSS is a useful metric of memory usage from a practical perspective.  On some platforms (AIX, BSD, Solaris) the memory usage reported may be zero, but it should be correct on both macOS and Linux platforms.  On macOS, memory pages that have not been used for a while may get compressed by the kernel to reduce the RSS of the process; the RSS metric reported by \n\\f1\\fs18 usage()\n\\f3\\fs20  will reflect the compressed size of such pages, not their original size, so surprising decreases in memory usage may be observed when the kernel decides to compress some memory pages.  The RSS is requested with a \n\\f1\\fs18 type\n\\f3\\fs20  of \n\\f1\\fs18 \"rss\"\n\\f3\\fs20 , which is the default; for historical reasons, it can also be requested with a \n\\f1\\fs18 type\n\\f3\\fs20  of \n\\f1\\fs18 F\n\\f3\\fs20 .\\\nAnother metric reported by \n\\f1\\fs18 usage()\n\\f3\\fs20  is the peak RSS.  This is just the highest RSS value that has ever been recorded by the kernel.  It should generally mirror the behavior of RSS, except that it ratchets upward monotonically.  The peak RSS is requested with a \n\\f1\\fs18 type\n\\f3\\fs20  of \n\\f1\\fs18 \"rss_peak\"\n\\f3\\fs20 ; for historical reasons, it can also be requested with a \n\\f1\\fs18 type\n\\f3\\fs20  of \n\\f1\\fs18 T\n\\f3\\fs20 .\\\nThe third metric currently reported by \n\\f1\\fs18 usage()\n\\f3\\fs20  is the virtual memory usage.  This is essentially the amount of memory used by pages that have been assigned to the process, whether those pages are resident, compressed, or swapped.  It is typically much larger than the RSS, because it includes various types of memory that are not counted in the RSS; indeed, for some system configurations the virtual memory usage can be reported as being the entire memory space of the computer.  Whether it is a useful metric will be platform-dependent; \n\\f7\\i caveat emptor\n\\f3\\i0 .\\\nThis function can be useful for documenting the memory usage of long runs as they are in progress.  In SLiM, the RSS could also be used to trigger tree-sequence simplification with a call to \n\\f1\\fs18 treeSeqSimplify()\n\\f3\\fs20 , to reduce memory usage when it becomes too large, but keep in mind that the simplification process itself may cause a substantial spike in memory usage, and that page compression and swaps may reduce the RSS even though the memory actually used by tree-sequence recording continues to increase.\\\nWhen running under SLiM, other tools for monitoring memory usage include the \n\\f1\\fs18 slim\n\\f3\\fs20  command-line options \n\\f1\\fs18 -m[em]\n\\f3\\fs20  and \n\\f1\\fs18 -M[emhist]\n\\f3\\fs20 , and the \n\\f1\\fs18 usage()\n\\f3\\fs20  and \n\\f1\\fs18 outputUsage()\n\\f3\\fs20  methods of \n\\f1\\fs18 Community\n\\f3\\fs20 ; see the SLiM manual for more information.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (float)version(\\cf2 \\expnd0\\expndtw0\\kerning0\n[logical$\\'a0print\\'a0=\\'a0T]\\cf0 \\kerning1\\expnd0\\expndtw0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nGet Eidos\\'92s version.\n\\f3\\b0   There are two ways to use this function.  If \n\\f1\\fs18 print\n\\f3\\fs20  is \n\\f1\\fs18 T\n\\f3\\fs20 , the default, then the version number is printed to the Eidos output stream in a formatted manner, like \\'93\n\\f1\\fs18 Eidos version 2.1\n\\f3\\fs20 \\'94.  If Eidos is attached to a Context that provides a version number, that is also printed, like \\'93\n\\f1\\fs18 SLiM version 3.1\n\\f3\\fs20 \\'94.  In this case, the Eidos version number, and the Context version number if available, are returned as an invisible \n\\f1\\fs18 float\n\\f3\\fs20  vector.  This is most useful when using Eidos interactively.  If \n\\f1\\fs18 print\n\\f3\\fs20  is \n\\f1\\fs18 F\n\\f3\\fs20 , on the other hand, nothing is printed, but the returned \n\\f1\\fs18 float\n\\f3\\fs20  vector of version numbers is not invisible.  This is useful for scripts that need to test the Eidos or Context version they are running against.\\\nIn both cases, in the \n\\f1\\fs18 float\n\\f3\\fs20  version numbers returned, a version like 2.4.2 would be returned as \n\\f1\\fs18 2.42\n\\f3\\fs20 ; this would not scale well to subversions greater than nine, so that will be avoided in our versioning.}"
  },
  {
    "path": "EidosScribe/EidosHelpOperators.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2513\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Italic;\\f1\\fnil\\fcharset0 Menlo-Italic;\\f2\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;\n\\f3\\fswiss\\fcharset0 Optima-Regular;\\f4\\fnil\\fcharset0 Menlo-Regular;\\f5\\froman\\fcharset0 TimesNewRomanPSMT;\n}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i\\fs22 \\cf0 2.2.2  ITEM: 1. Sequences: operator \n\\f1\\fs18 :\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 The \n\\f4\\fs18 :\n\\f3\\fs22  operator is used to construct vectors with (usually) more than one value.  In particular, it is used to construct \n\\f0\\i sequences\n\\f3\\i0 , and so it is called the sequence operator.  Given operands \n\\f4\\fs18 x\n\\f3\\fs22  and \n\\f4\\fs18 y\n\\f3\\fs22  (standing for any two numbers), the sequence operator starts at \n\\f4\\fs18 x\n\\f3\\fs22  and counts, by \n\\f4\\fs18 1\n\\f3\\fs22  (or \n\\f4\\fs18 -1\n\\f3\\fs22 , as appropriate) toward \n\\f4\\fs18 y\n\\f3\\fs22  without passing it.  It yields a vector containing all of the numbers it encounters along the way.\\\nNote that the sequence operator can count down as well as up, that it can handle \n\\f4\\fs18 float\n\\f3\\fs22  as well as \n\\f4\\fs18 integer\n\\f3\\fs22  operands, and that negative numbers are allowed.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.2.4  ITEM: 2. Subsets: operator \n\\f1\\fs18 []\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 The \n\\f4\\fs18 []\n\\f3\\fs22  operator selects a subset of the vector upon which it operates; it is thus often called the subset operator.  It can work in one of two different ways, depending upon whether it is given an \n\\f4\\fs18 integer\n\\f3\\fs22  vector of indices, or is given a \n\\f4\\fs18 logical\n\\f3\\fs22  vector of selectors.\\\nFirst of all, a subset can be selected with an \n\\f4\\fs18 integer\n\\f3\\fs22  vector of indices.  These indices are zero-based, like C but unlike R; the first value in a vector is thus at index \n\\f4\\fs18 0\n\\f3\\fs22 , not index \n\\f4\\fs18 1\n\\f3\\fs22 .  Note that a given index can be used multiple times.\\\nSecond, a subset can be selected with a \n\\f4\\fs18 logical\n\\f3\\fs22  vector of selectors.  In this case, the \n\\f4\\fs18 logical\n\\f3\\fs22  vector must be the same length as the vector being selected; each \n\\f4\\fs18 logical\n\\f3\\fs22  value indicates whether the corresponding vector value should be selected (\n\\f4\\fs18 T\n\\f3\\fs22 ) or not (\n\\f4\\fs18 F\n\\f3\\fs22 ).\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.1  ITEM: 3. Arithmetic operators: \n\\f1\\fs18 +\n\\f0\\fs22 , \n\\f1\\fs18 -\n\\f0\\fs22 , \n\\f1\\fs18 *\n\\f0\\fs22 , \n\\f1\\fs18 /\n\\f0\\fs22 , \n\\f1\\fs18 %\n\\f0\\fs22 , \n\\f1\\fs18 ^\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 These are the standard operators of arithmetic; \n\\f4\\fs18 +\n\\f3\\fs22  performs addition, \n\\f4\\fs18 -\n\\f3\\fs22  performs subtraction, \n\\f4\\fs18 *\n\\f3\\fs22  performs multiplication, \n\\f4\\fs18 /\n\\f3\\fs22  performs division, \n\\f4\\fs18 %\n\\f3\\fs22  performs a modulo operation (more on that below), and \n\\f4\\fs18 ^\n\\f3\\fs22  performs exponentiation.  Not a great deal needs to be said about these operators, which behave according to the standard rules of mathematics.  They also follow the standard rules of \\'93precedence\\'94; exponentiation is the highest precedence, addition and subtraction are the lowest precedence, and the other three are in the middle, so \n\\f4\\fs18 4^2+5*6^7\n\\f3\\fs22  is grouped as (\n\\f4\\fs18 4^3)+(5*(6^7))\n\\f3\\fs22 , as expected if you remember your grade-school math.\\\nThere are only a few minor twists to be discussed.  One is the meaning of the \n\\f4\\fs18 %\n\\f3\\fs22  operator, which many people have not previously encountered.  This computes the \\'93modulo\\'94 from a division, which is the remainder left behind after division.  For example, \n\\f4\\fs18 13%6\n\\f3\\fs22  is \n\\f4\\fs18 1\n\\f3\\fs22 , because after \n\\f4\\fs18 13\n\\f3\\fs22  is divided evenly by \n\\f4\\fs18 6\n\\f3\\fs22  (taking care of \n\\f4\\fs18 12\n\\f3\\fs22  of the \n\\f4\\fs18 13\n\\f3\\fs22 ), \n\\f4\\fs18 1\n\\f3\\fs22  is left as a remainder.  Probably the most common use of \n\\f4\\fs18 %\n\\f3\\fs22  is in determining whether a number is even or odd by looking at the result of a \n\\f4\\fs18 %2\n\\f3\\fs22  operation; \n\\f4\\fs18 5%2\n\\f3\\fs22  is \n\\f4\\fs18 1\n\\f3\\fs22 , indicating that \n\\f4\\fs18 5\n\\f3\\fs22  is odd, whereas \n\\f4\\fs18 6%2\n\\f3\\fs22  is \n\\f4\\fs18 0\n\\f3\\fs22 , indicating that \n\\f4\\fs18 6\n\\f3\\fs22  is even.\\\nAnother twist is that both the division and modulo operators in Eidos operate on \n\\f4\\fs18 float\n\\f3\\fs22  values \\'96 even if \n\\f4\\fs18 integer\n\\f3\\fs22  values are passed \\'96 and return \n\\f4\\fs18 float\n\\f3\\fs22  results.  (For those who care, division is performed internally using the C++ division operator \n\\f4\\fs18 /\n\\f3\\fs22 , and modulo is performed using the C++ \n\\f4\\fs18 fmod()\n\\f3\\fs22  function).  This policy was chosen because the definitions of integer division and modulo vary widely among programming languages and are contested and unclear (see Bantchev 2006, http://www.math.bas.bg/bantchev/articles/divmod.pdf).  If you are sure that you want \n\\f4\\fs18 integer\n\\f3\\fs22  division or modulo, and understand the issues involved, Eidos provides the functions \n\\f4\\fs18 integerDiv()\n\\f3\\fs22  and \n\\f4\\fs18 integerMod()\n\\f3\\fs22  for this purpose.  Besides side-stepping the vague definitions of the \n\\f4\\fs18 integer\n\\f3\\fs22  operator, this policy also avoids rather common bugs involving the accidental use of \n\\f4\\fs18 integer\n\\f3\\fs22  division when \n\\f4\\fs18 float\n\\f3\\fs22  division was desired \\'96 a much more common occurrence than \n\\f0\\i vice versa\n\\f5\\i0 .\\\n\n\\f3 A third twist is that \n\\f4\\fs18 +\n\\f3\\fs22  and \n\\f4\\fs18 -\n\\f3\\fs22  can both act as \\'93unary\\'94 operators, meaning that they are happy to take just a single operand.  This is standard math notation, as in the expressions \n\\f4\\fs18 -6+3\n\\f3\\fs22  or \n\\f4\\fs18 7*-5\n\\f3\\fs22 ; but it can sometimes look a bit strange, as in the expression \n\\f4\\fs18 5--6\n\\f3\\fs22  (more easily read as \n\\f4\\fs18 5 - -6\n\\f3\\fs22 ).\\\nA fourth twist is that the \n\\f4\\fs18 ^\n\\f3\\fs22  operator is right-associative, whereas all other binary Eidos operators are left-associative.  For example, \n\\f4\\fs18 2-3-4\n\\f3\\fs22  is evaluated as \n\\f4\\fs18 (2-3)-4\n\\f3\\fs22 , not as \n\\f4\\fs18 2-(3-4)\n\\f3\\fs22 ; this is left-associativity.  However, \n\\f4\\fs18 2^3^4\n\\f3\\fs22  is evaluated as \n\\f4\\fs18 2^(3^4)\n\\f3\\fs22 , not \n\\f4\\fs18 (2^3)^4\n\\f3\\fs22 ; this is right-associativity.  Since this follows the standard associativity for these operators, in both mathematics and most other programming languages, the result should generally be intuitive, but if you have never explicitly thought about associativity before you might be taken by surprise.\\\nA fifth twist is that the arithmetic operators and functions in Eidos are guaranteed to handle overflows safely.  The \n\\f4\\fs18 float\n\\f3\\fs22  type is safe because it uses IEEE-standard arithmetic, including the use of \n\\f4\\fs18 INF\n\\f3\\fs22  to indicate infinities and the use of \n\\f4\\fs18 NAN\n\\f3\\fs22  to represent not-a-number results; this is the same as in most languages.  In Eidos, however, the \n\\f4\\fs18 integer\n\\f3\\fs22  type is also safe, unlike in C, C++, and many other languages.  All operations on \n\\f4\\fs18 integer\n\\f3\\fs22  values in Eidos either (1) will always produce \n\\f4\\fs18 float\n\\f3\\fs22  results, as the \n\\f4\\fs18 /\n\\f3\\fs22  and \n\\f4\\fs18 %\n\\f3\\fs22  operators do; (2) will produce \n\\f4\\fs18 float\n\\f3\\fs22  results when needed to avoid overflow, as the \n\\f4\\fs18 product()\n\\f3\\fs22  and \n\\f4\\fs18 sum()\n\\f3\\fs22  functions do; or (3) will raise an error condition on an overflow, as the Eidos operators \n\\f4\\fs18 +\n\\f3\\fs22 , \n\\f4\\fs18 -\n\\f3\\fs22 , and \n\\f4\\fs18 *\n\\f3\\fs22  do, as well as the \n\\f4\\fs18 abs()\n\\f3\\fs22  and \n\\f4\\fs18 asInteger()\n\\f3\\fs22  functions.  This means that the \n\\f4\\fs18 integer\n\\f3\\fs22  type in Eidos can be used without fear that overflows might cause results to be incorrect.\\\nThe final twist is really a reminder: \n\\f0\\i everything is a vector\n\\f3\\i0 .  These operators are designed to do something smart, when possible, with vectors of any length, not just with single-valued vectors as shown above.  In general, the operands of these arithmetic operators must either be the same length (in which case the elements in the operand vectors are paired off and the operation is performed between each pair), or one or the other vector must be of length \n\\f4\\fs18 1\n\\f3\\fs22  (in which case the operation is performed using that single value, paired with each value in the other operand vector).\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.2  ITEM: 4. Logical operators: \n\\f1\\fs18 |\n\\f0\\fs22 , \n\\f1\\fs18 &\n\\f0\\fs22 , \n\\f1\\fs18 !\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 The \n\\f4\\fs18 |\n\\f3\\fs22 , \n\\f4\\fs18 &\n\\f3\\fs22 , and \n\\f4\\fs18 !\n\\f3\\fs22  operators act upon \n\\f4\\fs18 logical\n\\f3\\fs22  values.  If they are given operands of other types, those operands will be \\'93coerced\\'94 to \n\\f4\\fs18 logical\n\\f3\\fs22  values following the rule mentioned above: zero is \n\\f4\\fs18 F\n\\f3\\fs22 , non-zero is \n\\f4\\fs18 T\n\\f3\\fs22  (and for \n\\f4\\fs18 string\n\\f3\\fs22  operands, a \n\\f4\\fs18 string\n\\f3\\fs22  that is zero characters long \\'96 the empty string, \n\\f4\\fs18 \"\"\n\\f3\\fs22  \\'96 is considered \n\\f4\\fs18 F\n\\f3\\fs22 , while all other \n\\f4\\fs18 string\n\\f3\\fs22  values are considered \n\\f4\\fs18 T\n\\f3\\fs22 ).\\\nAs to what they do: \n\\f4\\fs18 |\n\\f3\\fs22  is the \\'93or\\'94 operation, \n\\f4\\fs18 &\n\\f3\\fs22  is the \\'93and\\'94 operation, and \n\\f4\\fs18 !\n\\f3\\fs22  is the \\'93not\\'94 operation.  As in common parlance, \\'93or\\'94 is \n\\f4\\fs18 T\n\\f3\\fs22  if either of its operands is \n\\f4\\fs18 T\n\\f3\\fs22 , whereas \\'93and\\'94 is \n\\f4\\fs18 T\n\\f3\\fs22  only if both of its operands are \n\\f4\\fs18 T\n\\f3\\fs22 .  The \\'93not\\'94 operator is unary (it takes only one operand), and it negates its operand; \n\\f4\\fs18 T\n\\f3\\fs22  becomes \n\\f4\\fs18 F\n\\f3\\fs22 , \n\\f4\\fs18 F\n\\f3\\fs22  becomes \n\\f4\\fs18 T\n\\f3\\fs22 .  As with the arithmetic operators, these operators work with vector operands, too \\'96 either matching up values pairwise between the two operands, or applying a single value across a multivalued operand.\\\nThose familiar with programming might wish to know that the \n\\f4\\fs18 |\n\\f3\\fs22  and \n\\f4\\fs18 &\n\\f3\\fs22  operators do not \\'93short-circuit\\'94 \\'96 they can\\'92t, because they are vector operators. If the \n\\f4\\fs18 &\n\\f3\\fs22  operator first sees an operand that evaluates to \n\\f4\\fs18 F\n\\f3\\fs22 , for example, it knows that it will produce \n\\f4\\fs18 F\n\\f3\\fs22  value(s) as a result; but it does not know what size result vector to make. If a later operand is a multivalued vector, the \n\\f4\\fs18 &\n\\f3\\fs22  operator will produce a result vector of matching length; if all later operands are also length \n\\f4\\fs18 1\n\\f3\\fs22 , however, \n\\f4\\fs18 &\n\\f3\\fs22  will produce a result vector of length \n\\f4\\fs18 1\n\\f3\\fs22 .  To know this for sure (and to make sure that there are no illegal length mismatches between later operands), it must evaluate all of its operands; it cannot short-circuit.  Similarly for the \n\\f4\\fs18 |\n\\f3\\fs22  operator.\\\nThese semantics match those in R, for its \n\\f4\\fs18 |\n\\f3\\fs22  and \n\\f4\\fs18 &\n\\f3\\fs22  operators, but they might seem a little strange to those used to C and other scalar-based languages.  For those used to R, on the other hand, it should be noted here that Eidos does not support the \n\\f4\\fs18 &&\n\\f3\\fs22  and \n\\f4\\fs18 ||\n\\f3\\fs22  operators of R, for reasons of simplicity; it is safer to use the \n\\f4\\fs18 any()\n\\f3\\fs22  or \n\\f4\\fs18 all()\n\\f3\\fs22  functions to simplify multivalued \n\\f4\\fs18 logical\n\\f3\\fs22  vectors before using \n\\f4\\fs18 &\n\\f3\\fs22  or \n\\f4\\fs18 |\n\\f5\\fs22 .\n\\f3   If this is gibberish to you, it is not important; the point here is only to prevent confusion among users accustomed to R.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.3  ITEM: 5. Comparative operators: \n\\f1\\fs18 ==\n\\f0\\fs22 , \n\\f1\\fs18 !=\n\\f0\\fs22 , \n\\f1\\fs18 <\n\\f0\\fs22 , \n\\f1\\fs18 <=\n\\f0\\fs22 , \n\\f1\\fs18 >\n\\f0\\fs22 , \n\\f1\\fs18 >=\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 These operators compare their left and right operand.  The operators test for equality (\n\\f4\\fs18 ==\n\\f3\\fs22 ), inequality (\n\\f4\\fs18 !=\n\\f3\\fs22 ), less-than (\n\\f4\\fs18 <\n\\f3\\fs22 ), less-than-or-equality (\n\\f4\\fs18 <=\n\\f3\\fs22 ), greater-than (\n\\f4\\fs18 >\n\\f3\\fs22 ), and greater-than-or-equality (\n\\f4\\fs18 >=\n\\f3\\fs22 ) relationships.  As seen above with the arithmetic and logical operators, this can work in two different ways: if the operands are the same length, their elements are paired up and the comparison is done between each pair, whereas if the operands are not the same length then one operand must be of length one, and its value is compared against all of the values of the other operand.\\\nRegardless of the types of the operands, these operators all produce a \n\\f4\\fs18 logical\n\\f3\\fs22  result vector.  If the operands are of different types, promotion will be used to coerce them to be the same type (i.e. \n\\f4\\fs18 logical\n\\f3\\fs22  will be coerced to \n\\f4\\fs18 integer\n\\f3\\fs22 , \n\\f4\\fs18 integer\n\\f3\\fs22  to \n\\f4\\fs18 float\n\\f3\\fs22 , and \n\\f4\\fs18 float\n\\f3\\fs22  to \n\\f4\\fs18 string\n\\f3\\fs22 ).  Note that this is often not what you want!  You might not want the automatic type promotion that makes \n\\f4\\fs18 5==\"5\"\n\\f3\\fs22  evaluate as \n\\f4\\fs18 T\n\\f3\\fs22 , or the vectorized comparison that makes \n\\f4\\fs18 1:5==4\n\\f3\\fs22  evaluate as something other than simply \n\\f4\\fs18 F\n\\f3\\fs22 .  You might really want to ask: are two values \n\\f0\\i identical?\n\\f3\\i0   For such purposes, the \n\\f4\\fs18 identical()\n\\f3\\fs22  function is a better choice.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.4  ITEM: 6. String concatenation: operator \n\\f1\\fs18 +\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 The \n\\f4\\fs18 +\n\\f3\\fs22  operator is often used as an arithmetic operator, but it can also act as a concatenation operator for string operands. Concatenation is pasting together; the \n\\f4\\fs18 +\n\\f3\\fs22  operator simply pastes its string operands together, end to end.\\\nIn fact, this works with non-\n\\f4\\fs18 string\n\\f3\\fs22  operands too, as long as a \n\\f4\\fs18 string\n\\f3\\fs22  operand is nearby; the interpretation of \n\\f4\\fs18 +\n\\f3\\fs22  as a concatenation operator is preferred by Eidos, and wins out over its arithmetic interpretation, as long as a \n\\f4\\fs18 string\n\\f3\\fs22  operand is present to suggest doing so. The other non-\n\\f4\\fs18 string\n\\f3\\fs22  operands will be coerced to \n\\f4\\fs18 string\n\\f3\\fs22 .  However, this does not work retroactively; if Eidos has already done arithmetic addition on some operands, it will not go back and perform concatenation instead.  To force concatenation in such situations, you can simply begin the expression with an empty string, \n\\f4\\fs18 \"\"\n\\f3\\fs22 .\\\nThe concatenation operator also works with vectors, as usual.\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nBeginning with Eidos 2.2, string concatenation involving \n\\f4\\fs18 NULL\n\\f3\\fs22  concatenates the \n\\f4\\fs18 string\n\\f3\\fs22  value \n\\f4\\fs18 \"NULL\"\n\\f3\\fs22 , just as if \n\\f4\\fs18 NULL\n\\f3\\fs22  were a singleton \n\\f4\\fs18 string\n\\f3\\fs22  vector containing that value.\\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.4.1  ITEM: 7. Assignment: operator \n\\f1\\fs18 =\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0\\fs22 \\cf0 The results of expressions can be saved in variables.  As in many languages, this is done with the \n\\f4\\fs18 =\n\\f3\\fs22  operator, often called the assignment operator.\\\nThe assignment operator, \n\\f4\\fs18 =\n\\f3\\fs22 , is different from the equality comparison operator, \n\\f4\\fs18 ==\n\\f3\\fs22 .  In many languages, confusing the two can cause bugs that are hard to find; in C, for example, it is legal to write:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 if (x=y) ...\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 In C, this would assign the value of \n\\f4\\fs18 y\n\\f3\\fs22  to \n\\f4\\fs18 x\n\\f3\\fs22 , and then the expression \n\\f4\\fs18 x=y\n\\f3\\fs22  would evaluate to the value that was assigned, and that value would be tested by the \n\\f4\\fs18 if\n\\f3\\fs22  statement.  This can be useful as a way of writing extremely compact code; but it is also a very common source of bugs, especially for inexperienced programmers.  In Eidos using assignment in this way is simply illegal; assignment is allowed only in the context of a statement like \n\\f4\\fs18 x=y;\n\\f3\\fs22  to prevent these issues.  (This point is mostly of interest to experienced programmers, so if it is unclear, don\\'92t worry.)\\\nVariable names are fairly unrestricted.  They may begin with a letter (uppercase or lowercase) or an underscore, and subsequently may contain all of those characters, and numerical digits as well.  So \n\\f4\\fs18 x_23\n\\f3\\fs22 , \n\\f4\\fs18 fooBar\n\\f3\\fs22 , and \n\\f4\\fs18 MyVariable23\n\\f3\\fs22  are all legal variable names (although not good ones \\'96 good variable names explain what the variable represents, such as \n\\f4\\fs18 selection_coeff\n\\f3\\fs22 ).  However, \n\\f4\\fs18 4by4\n\\f3\\fs22  would not be a legal variable name, since it begins with a digit.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.5  ITEM: 8. The ternary conditional: operator \n\\f1\\fs18 ? else\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 Eidos, like many languages, has an \n\\f4\\fs18 if\n\\f3\\fs22  statement that can be used to specify conditional execution of statements, and an \n\\f4\\fs18 if-else\n\\f3\\fs22  construct can be used to provide an alternative code path.  Sometimes, however, one wishes to have conditional execution of an expression, rather than an entire statement.  The \n\\f4\\fs18 if-else\n\\f3\\fs22  construct is particularly inconvenient with assignments involving complex lvalues, such as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 if (condition)\\\n\tx[index].property = a;\\\nelse\\\n\tx[index].property = b;\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 It is desirable to provide a way for the user to specify that the choice of rvalue, \n\\f4\\fs18 a\n\\f3\\fs22  or \n\\f4\\fs18 b\n\\f3\\fs22 , should depend upon \n\\f4\\fs18 condition\n\\f3\\fs22  without having to duplicate the lvalue and the assignment.  The R language provides this functionality by making \n\\f4\\fs18 if-else\n\\f3\\fs22  statements result in an rvalue, like an expression.  The C language, on the other hand, provides a \n\\f0\\i ternary conditional\n\\f3\\i0  operator, \n\\f4\\fs18 ?:\n\\f5\\fs22 ,\n\\f3  that can be used in expressions to much the same effect.  Eidos straddles the gap with a ternary conditional operator, \n\\f4\\fs18 ? else\n\\f3\\fs22 , that uses the \n\\f4\\fs18 ?\n\\f3\\fs22  initiator of C, but the \n\\f4\\fs18 else\n\\f3\\fs22  token as a continuation as in R.  In the syntax of Eidos, the above conditional assignment can be rewritten as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 x[index].property = condition ? a else b;\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 This will evaluate \n\\f4\\fs18 condition\n\\f3\\fs22  and result in \n\\f4\\fs18 a\n\\f3\\fs22  if \n\\f4\\fs18 condition\n\\f3\\fs22  is \n\\f4\\fs18 T\n\\f3\\fs22 , or \n\\f4\\fs18 b\n\\f3\\fs22  if \n\\f4\\fs18 condition\n\\f3\\fs22  is \n\\f4\\fs18 F\n\\f3\\fs22 .  That result is then assigned into the lvalue.  Note that, as in C, the precedence of the ternary conditional operator is very low, but higher than operator \n\\f4\\fs18 =\n\\f3\\fs22 , so that parentheses are often not needed to group statements of this type.  The \n\\f4\\fs18 else\n\\f3\\fs22  clause of the ternary conditional is required; there is no equivalent of an \n\\f4\\fs18 if\n\\f3\\fs22  statement without an \n\\f4\\fs18 else\n\\f3\\fs22 , since an rvalue must be produced.\\\nJust as with \n\\f4\\fs18 if-else\n\\f3\\fs22  statements, only the selected subexpression, as determined by the condition, is evaluated; the other subexpression will not be evaluated, so any side effects it might have will not occur.  For example, with the statement:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 x = condition ? f1() else f2();\\\n\\pard\\pardeftab720\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 here \n\\f4\\fs18 f1()\n\\f3\\fs22  will be called if \n\\f4\\fs18 condition\n\\f3\\fs22  is \n\\f4\\fs18 T\n\\f3\\fs22 , \n\\f4\\fs18 f2()\n\\f3\\fs22  if \n\\f4\\fs18 condition\n\\f3\\fs22  is \n\\f4\\fs18 F\n\\f3\\fs22 ; only the subexpression selected by the condition is evaluated, and so it is never the case that both \n\\f4\\fs18 f1()\n\\f3\\fs22  and \n\\f4\\fs18 f2()\n\\f3\\fs22  are called.\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf0 Ternary conditionals may be nested.  Because the operator is right-associative, an expression such as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 z = (a == b ? a else b ? c else d);\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 is grouped as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 z = (a == b ? a else (b ? c else d));\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 rather than\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 z = ((a == b ? a else b) ? c else d);\n\\f5 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 This is generally desirable, since it provides a flow similar to chaining of \n\\f4\\fs18 if-else if-else\n\\f3\\fs22  statements.  In any case, parentheses may be used to change the order to evaluation as usual.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.3.6  ITEM: 9. Grouping: operator \n\\f1\\fs18 ()\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 All of the discussion above involved simple expressions that allowed the standard precedence rules of mathematics to determine the order of operations; \n\\f4\\fs18 1+2*3\n\\f3\\fs22  is evaluated as \n\\f4\\fs18 1+(2*3)\n\\f3\\fs22  rather than \n\\f4\\fs18 (1+2)*3\n\\f3\\fs22  because the \n\\f4\\fs18 *\n\\f3\\fs22  operator is higher precedence than the \n\\f4\\fs18 +\n\\f3\\fs22  operator.  For the record, here is the full precedence hierarchy for operators in Eidos, from highest to lowest precedence:\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\fi547\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs18 \\cf0 []\n\\f3\\fs22 , \n\\f4\\fs18 ()\n\\f3\\fs22 , \n\\f4\\fs18 .\n\\f5\\fs22 \t\n\\f3 subscript, function call, and member access\\\n\n\\f4\\fs18 ^\n\\f5\\fs22 \t\n\\f3 exponentiation \n\\f0\\i (right-associative)\n\\f5\\i0 \\\n\n\\f4\\fs18 +\n\\f3\\fs22 , \n\\f4\\fs18 -\n\\f3\\fs22 , \n\\f4\\fs18 !\n\\f5\\fs22 \t\n\\f3 unary plus, unary minus, logical (Boolean) negation \n\\f0\\i (right-associative)\n\\f5\\i0 \\\n\n\\f4\\fs18 :\n\\f5\\fs22 \t\n\\f3 sequence construction\\\n\n\\f4\\fs18 *\n\\f3\\fs22 , \n\\f4\\fs18 /\n\\f3\\fs22 , \n\\f4\\fs18 %\n\\f5\\fs22 \t\n\\f3 multiplication, division, and modulo\\\n\n\\f4\\fs18 +\n\\f3\\fs22 , \n\\f4\\fs18 -\n\\f5\\fs22 \t\n\\f3 addition and subtraction\\\n\n\\f4\\fs18 <\n\\f3\\fs22 , \n\\f4\\fs18 >\n\\f3\\fs22 , \n\\f4\\fs18 <=\n\\f3\\fs22 , \n\\f4\\fs18 >=\n\\f5\\fs22 \t\n\\f3 less-than, greater-than, less-than-or-equality, greater-than-or-equality\\\n\n\\f4\\fs18 ==\n\\f3\\fs22 , \n\\f4\\fs18 !=\n\\f5\\fs22 \t\n\\f3 equality and inequality\\\n\n\\f4\\fs18 &\n\\f5\\fs22 \t\n\\f3 logical (Boolean) and\\\n\n\\f4\\fs18 |\n\\f5\\fs22 \t\n\\f3 logical (Boolean) or\\\n\n\\f4\\fs18 =\n\\f5\\fs22 \t\n\\f3 assignment\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf0 Operators at the same precedence level are generally evaluated in the order in which they are encountered.  Put more technically, Eidos operators are generally left-associative; \n\\f4\\fs18 3*5%2\n\\f3\\fs22  evaluates as \n\\f4\\fs18 (3*5)%2\n\\f3\\fs22 , which is \n\\f4\\fs18 1\n\\f5\\fs22 ,\n\\f3  not as \n\\f4\\fs18 3*(5%2)\n\\f3\\fs22 , which is \n\\f4\\fs18 3\n\\f3\\fs22 .  The only binary operator in Eidos that is an exception to this rule is the \n\\f4\\fs18 ^\n\\f3\\fs22  operator, which (following standard mathematical convention) is right-associative; \n\\f4\\fs18 2^3^4\n\\f3\\fs22  is evaluated as \n\\f4\\fs18 2^(3^4)\n\\f3\\fs22 , not \n\\f4\\fs18 (2^3)^4\n\\f3\\fs22 .  The unary \n\\f4\\fs18 +\n\\f3\\fs22 , unary \n\\f4\\fs18 -\n\\f3\\fs22 , and \n\\f4\\fs18 !\n\\f3\\fs22  operators are also technically right-associative; for unary operators this is of little practical import, however (it basically just implies that the unary operators must occur to the left of their operand; you write \n\\f4\\fs18 -x\n\\f3\\fs22 , not \n\\f4\\fs18 x-\n\\f3\\fs22 , to express the negation of \n\\f4\\fs18 x\n\\f3\\fs22 ).\\\nIn any case, parentheses can be used to modify the order of operations, just as in math.  This works just as you would expect.\\\nNote that this use of parentheses is distinct from the \n\\f4\\fs18 ()\n\\f3\\fs22  operator as used in making function calls.\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 Finally, note that Eidos 2.4 and earlier (SLiM 3.4 and earlier) had an operator precedence bug: exponentiation was given a lower precedence than unary minus and its siblings, and so the expression \n\\f4\\fs18 -2^2\n\\f3\\fs22  would evaluate to \n\\f4\\fs18 4\n\\f3\\fs22 , as \n\\f4\\fs18 (-2)^2\n\\f3\\fs22 , rather than \n\\f4\\fs18 -4\n\\f3\\fs22 , as \n\\f4\\fs18 -(2^2)\n\\f3\\fs22 .  This violated standard mathematical precedence rules, and was fixed in Eidos 2.5 (SLiM 3.5).\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.7.1  ITEM: 10. Function calls: operator \n\\f1\\fs18 ()\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 A function is simply a block of code which has been given a name.  Using that name, you can then cause the execution of that block of code whenever you wish.  That is the first major purpose of functions: the \n\\f0\\i reuseability\n\\f3\\i0  of a useful chunk of code.  A function can be supplied with the particular variables upon which it should act, called the function\\'92s \\'93parameters\\'94 or \\'93arguments\\'94; you can execute a function with the sequence \n\\f4\\fs18 5:15\n\\f3\\fs22  as an argument in one place, and with the string \n\\f4\\fs18 \"foo\"\n\\f3\\fs22  as an argument in another.  That is the second major purpose of functions: the \n\\f0\\i generalization\n\\f3\\i0  of a useful chunk of code to easily act on different inputs.\\\nIn Eidos, you may define your own functions, or you may execute a \n\\f0\\i lambda\n\\f3\\i0  (i.e., a snippet of code represented as a \n\\f4\\fs18 string\n\\f3\\fs22  value) directly in the Eidos interpreter.  However, a fairly large set of built-in functions are supplied for your use, and the hope is that they will suffice for most purposes.\\\nFunctions are called using the \n\\f4\\fs18 ()\n\\f3\\fs22  operator.  Function arguments go between the parentheses of the \n\\f4\\fs18 ()\n\\f3\\fs22  operator, separated by commas.  Most functions expect an exact number of arguments; many functions, in fact, are even fussier than that, requiring each parameter to be of a particular type, a particular size, or both.  But some, such as \n\\f4\\fs18 c()\n\\f3\\fs22 , are more flexible.\\\nMany functions provide a return value.  In other words, a function call like \n\\f4\\fs18 c(5,6)\n\\f3\\fs22  can evaluate to a particular value, just as an expression like \n\\f4\\fs18 5+6\n\\f3\\fs22  evaluates to a particular value.  The result from a function call can be used in an expression or assigned to a variable, as you might expect.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.8.3  ITEM: 11. Properties: operator \n\\f1\\fs18 .\n\\f2\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 Objects encapsulate behaviors as well as elements.  One type of behavior is called a \n\\f0\\i property\n\\f3\\i0 .  A property is a simple attribute of each element in an \n\\f4\\fs18 object\n\\f3\\fs22 .  Properties can be read using the member-access operator, written as \n\\f4\\fs18 .\n\\f3\\fs22  (a period).  The name of a particular property can be used with \n\\f4\\fs18 .\n\\f3\\fs22  to get that property\\'92s value.  Operations on \n\\f4\\fs18 object\n\\f3\\fs22  are vectorized just as they are for all other types in Eidos; the result of the \n\\f4\\fs18 .\n\\f3\\fs22  operator is a vector containing the value of the property for all of the elements of the \n\\f4\\fs18 object\n\\f3\\fs22  operand.\\\nYou can also use the member-access operator to write new values to properties that are not read-only, using the \n\\f4\\fs18 =\n\\f3\\fs22  operator to do the assignment into the property selected by the \n\\f4\\fs18 .\n\\f3\\fs22  operator.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.8.6  ITEM: 12. Method calls: operator \n\\f1\\fs18 ()\n\\f0\\fs22  and operator \n\\f1\\fs18 .\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\i0 \\cf0 Objects encapsulate behaviors as well as elements.  In addition to properties, another type of behavior is called a \n\\f0\\i method\n\\f3\\i0 .  Methods are very much like functions; they are chunks of code that you can call to perform tasks.  However, each type of \n\\f4\\fs18 object\n\\f3\\fs22  has its own particular methods \\'96 unlike functions, which are defined globally.  Methods are more heavyweight than properties; they might involve quite a lot of computation, they might create a completely new \n\\f4\\fs18 object\n\\f3\\fs22  as their result, and they might even modify the \n\\f4\\fs18 object\n\\f3\\fs22  upon which they are called.  Not all methods are heavyweight in this sort of way, however; anything that one might want an \n\\f4\\fs18 object\n\\f3\\fs22  to do, but that does not feel like a simple property of the \n\\f4\\fs18 object\n\\f3\\fs22 , can be a method.  Methods can also take arguments, just like functions, and they can return whole vectors as their result, unlike (read-write) properties, which must refer to singleton values so that multiplexed assignment can work.  Methods are therefore much more powerful than properties.\\\nMethods are called using the member-access operator, \n\\f4\\fs18 .\n\\f3\\fs22 , with a syntax that looks a lot like accessing a property, but combined with the function call operator, \n\\f4\\fs18 ()\n\\f3\\fs22 .  That might look like:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f4\\fs18 \\cf0 object.method()\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs22 \\cf0 Naturally, method calls are also vector operations.  For a multi-element \n\\f4\\fs18 object\n\\f3\\fs22 , a single method call will result in the method call being multiplexed out to all of the elements of the \n\\f4\\fs18 object\n\\f3\\fs22 , and the results from all of those method calls will be concatenated together in the same way that the \n\\f4\\fs18 c()\n\\f3\\fs22  function performs concatenation (including dropping of \n\\f4\\fs18 NULL\n\\f3\\fs22 s and type promotion, potentially).\\\n}"
  },
  {
    "path": "EidosScribe/EidosHelpStatements.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2513\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Italic;\\f1\\fnil\\fcharset0 Menlo-Italic;\\f2\\fswiss\\fcharset0 Optima-Regular;\n\\f3\\fnil\\fcharset0 Menlo-Regular;\\f4\\froman\\fcharset0 TimesNewRomanPSMT;\\f5\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;\n}\n{\\colortbl;\\red255\\green255\\blue255;\\red170\\green13\\blue145;\\red28\\green10\\blue207;\\red255\\green0\\blue0;\n\\red28\\green0\\blue207;\\red0\\green116\\blue0;}\n{\\*\\expandedcolortbl;;\\csgenericrgb\\c66667\\c5098\\c56863;\\csgenericrgb\\c10980\\c3922\\c81176;\\csgenericrgb\\c100000\\c0\\c0;\n\\csgenericrgb\\c10980\\c0\\c81176;\\csgenericrgb\\c0\\c45490\\c0;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i\\fs22 \\cf0 2.5.1  ITEM: 1. \n\\f1\\fs18 if\n\\f0\\fs22  and \n\\f1\\fs18 if\\'96else\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 As in many languages, conditional execution is provided by the \n\\f3\\fs18 if\n\\f2\\fs22  statement.  This statement is supplied with a \n\\f3\\fs18 logical\n\\f2\\fs22  condition; if the condition is \n\\f3\\fs18 T\n\\f2\\fs22 , the rest of the \n\\f3\\fs18 if\n\\f2\\fs22  statement is executed, whereas if the condition is \n\\f3\\fs18 F\n\\f2\\fs22 , the rest of the \n\\f3\\fs18 if\n\\f2\\fs22  statement is ignored.  An example:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 if (2^2^2^2^2 > 10000) \"exponentiation is da bomb!\"\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 \"exponentiation is da bomb!\"\\\n\n\\f4\\fs4 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 The only twist here, really, is that the condition must evaluate to a single value, i.e. a vector of \n\\f3\\fs18 size() == 1\n\\f2\\fs22 .  The \n\\f3\\fs18 if\n\\f2\\fs22  statement, in other words, is essentially a scalar operator, not a vector operator.  If you have a multivalued \n\\f3\\fs18 logical\n\\f2\\fs22  vector, you can use the \n\\f3\\fs18 any()\n\\f2\\fs22  or \n\\f3\\fs18 all()\n\\f2\\fs22  functions to simplify it to a single \n\\f3\\fs18 logical\n\\f2\\fs22  value.  Alternatively, the \n\\f3\\fs18 ifelse()\n\\f2\\fs22  function provides a vector conditional operation, similar to that in R.\\\nIt is worth exploring this twist with an example.  Suppose you have a variable \n\\f3\\fs18 x\n\\f2\\fs22  which ought to be equal to \n\\f3\\fs18 3\n\\f2\\fs22 , and a variable \n\\f3\\fs18 y\n\\f2\\fs22  which ought to contain two values, \n\\f3\\fs18 7\n\\f2\\fs22  and \n\\f3\\fs18 8\n\\f2\\fs22 .  You might expect to be able to write:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 if (x == 3 & y == c(7,8)) \"yes!\"\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf4 ERROR (EidosInterpreter::Evaluate_If): condition has size() != 1\n\\f4 .\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\fs4 \\cf0 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 The error informs you that the size of condition is not equal to \n\\f3\\fs18 1\n\\f2\\fs22  (and that that is a problem).  The expression \n\\f3\\fs18 y\\'a0==\\'a0c(7,8)\n\\f2\\fs22  produces a \n\\f3\\fs18 logical\n\\f2\\fs22  vector with two values, the result of testing the first and second values respectively.  The \n\\f3\\fs18 &\n\\f4\\fs22 \\'a0\n\\f2 operator thus produces a two-valued \n\\f3\\fs18 logical\n\\f2\\fs22  vector as its result, and \n\\f3\\fs18 if\n\\f2\\fs22  is not happy about that.  To resolve this, you could use the \n\\f3\\fs18 all()\n\\f2\\fs22  function, or in many cases more appropriately, the \n\\f3\\fs18 identical()\n\\f2\\fs22  function.  See the Eidos manual for further discussion of this issue.\\\nIt is also worth noting that the condition for \n\\f3\\fs18 if\n\\f2\\fs22  does not need to be a \n\\f3\\fs18 logical\n\\f2\\fs22  value; a value of a different type will be converted to \n\\f3\\fs18 logical\n\\f2\\fs22  by coercion if possible.\\\nOften you want to perform an alternative action when the condition of an \n\\f3\\fs18 if\n\\f2\\fs22  statement is \n\\f3\\fs18 F\n\\f2\\fs22 ; the \n\\f3\\fs18 if\\'96else\n\\f2\\fs22  statement allows this.  It is simplest to just show this with an example:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 if (2/2/2/2/2 > 10000) \"division is da bomb!\"; else \"not so much.\"\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 \"not so much.\"\\\n\n\\f4\\fs4 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Super simple, right?\n\\f4 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.5.3  ITEM: 3. semicolons and \"null statements\", \n\\f1\\fs18 ;\n\\f5\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 Every statement in Eidos must end with a semicolon (except compound statements, which end with a closing brace).  However, when you\\'92re working interactively in EidosScribe, EidosScribe will add a trailing semicolon to your statements if necessary, just to make your life simpler.  So when you type:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 1+1==2\n\\f4 \\cf0 \\\n\\pard\\pardeftab720\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 what is really being evaluated behind the scenes is:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 1+1==2;\n\\f4 \\cf0 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 When you\\'92re not working interactively, semicolons are required, and if you forget, you will get an error, like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 1+1==2\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf4 ERROR (Parse): unexpected token 'EOF' in statement; expected ';'\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 EOF stands for End Of File; it\\'92s a standard way of referring to the end of an input buffer, in this case the line of input provided by the user for execution.\\\nThe simplest and shortest possible statement in Eidos is the \"null statement\", which consists of nothing but a semicolon:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf0 ;\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 This is not terribly useful, since it does nothing.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.5.4  ITEM: 4. compound statements with \n\\f1\\fs18 \\{ \\}\n\\f5\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The other thing you might wonder about, regarding \n\\f3\\fs18 if\n\\f2\\fs22  statements, is: what if I want to perform more than one action in response to the condition being \n\\f3\\fs18 T\n\\f2\\fs22  or \n\\f3\\fs18 F\n\\f2\\fs22 ?  This, then, is an opportune moment to introduce the concept of compound statements.  A compound statement is a series of statements (zero or more) enclosed by braces.  An example is worth a thousand words:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 if (1+1==2)\\\n\\{\\\n   x = 1;\\\n   x = x + 1;\\\n   x;\\\n\\}\\\nelse\\\n\\{\\\n   \"whoah, I'm confused\";\\\n\\}\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 2\\\n\n\\f4\\fs4 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Note that the input here is spread across multiple lines for clarity; all of this could be typed on a single line instead.  If entered as multiple lines, it cannot presently be entered in EidosScribe\\'92s interactive mode because the \n\\f3\\fs18 if\n\\f2\\fs22  statement would stand on its own and be evaluated as soon as it was completed; instead, the full text would need to be entered in the script area on the left, selected, and executed.  All of the blue lines are user input, whereas the final line in black, \n\\f3\\fs18 2\n\\f2\\fs22 , shows the output of the execution of the whole \n\\f3\\fs18 if\\'96else\n\\f2\\fs22  statement; the \n\\f3\\fs18 if\n\\f2\\fs22  clause is executed, the calculations involving \n\\f3\\fs18 x\n\\f2\\fs22  are performed, and the final statement \n\\f3\\fs18 x;\n\\f2\\fs22  produces a result which is printed to the console as usual.\\\nThe way that \n\\f3\\fs18 x;\n\\f2\\fs22  results in output here might seem a bit surprising at first, but it is a consequence of the fact that \n\\f0\\i the value of a compound statement is the value of the last statement executed within the compound statement\n\\f2\\i0 ; the values of the previous statements are discarded.\\\nYou can use a compound statement in any context in which a single statement would be allowed.  For example, compound statements are very commonly used with looping constructs.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.1  ITEM: 5. \n\\f1\\fs18 while\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 A \n\\f3\\fs18 while\n\\f2\\fs22  loop repeats a statement as long as a given condition is true.  The condition is tested before the first time that the statement is executed, so the statement will be executed zero or more times.  Here is a code snippet to compute the first twenty numbers of the Fibonacci sequence:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 fib = c(1, 1);\\\nwhile (size(fib) < 20)\\\n\\{\\\n   next_fib = fib[size(fib) - 1] + fib[size(fib) - 2];\\\n   fib = c(fib, next_fib);\\\n\\}\\\nfib;\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765\\\n\n\\f4\\fs4 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Its use of a \n\\f3\\fs18 while\n\\f2\\fs22  loop is optimal, because it ensures that if the \n\\f3\\fs18 fib\n\\f2\\fs22  vector is already long enough to satisfy the length condition \n\\f3\\fs18 size(fib) < 20\n\\f2\\fs22 , no further values of \n\\f3\\fs18 fib\n\\f2\\fs22  will be computed.  You could use this \n\\f3\\fs18 while\n\\f2\\fs22  loop to lengthen the \n\\f3\\fs18 fib\n\\f2\\fs22  vector on demand within a larger block of code that used the \n\\f3\\fs18 fib\n\\f2\\fs22  vector repeatedly.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.2  ITEM: 6. \n\\f1\\fs18 do\\'96while\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 A \n\\f3\\fs18 do\\'96while\n\\f2\\fs22  loop repeats a statement as long as a given condition is true.  Unlike \n\\f3\\fs18 while\n\\f2\\fs22  loops, in this case the condition is tested at the end of the loop, and thus the loop statement is always executed at least once.  Here is a code snippet to compute a factorial:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 counter = 5;\\\nfactorial = 1;\\\ndo\\\n\\{\\\n   factorial = factorial * counter;\\\n   counter = counter - 1;\\\n\\}\\\nwhile (counter > 0);\\\n\"The factorial of 5 is \" + factorial;\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 \"The factorial of 5 is 120\"\\\n\n\\f4\\fs4 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Note that this example could be rewritten using a \n\\f3\\fs18 while\n\\f2\\fs22  loop instead, but it might be a bit less intuitive in its operation since it would no longer embody the formal definition of the factorial as explicitly.  Note also that computing a factorial could be done much more trivially (and efficiently) using the sequence operator \n\\f3\\fs18 :\n\\f2\\fs22  and the \n\\f3\\fs18 product()\n\\f2\\fs22  function, but the code here is useful for the purpose of illustration.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.3  ITEM: 7. \n\\f1\\fs18 for\n\\f0\\fs22  statements (with \n\\f1\\fs18 in\n\\f0\\fs22 )\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 for\n\\f2\\fs22  loop is used to loop through all of the elements in a vector.  For each value in the given vector, a given variable is set to the value, and a given statement is then executed.  For example, the following code computes squares by setting \n\\f3\\fs18 element\n\\f2\\fs22  to each value of \n\\f3\\fs18 my_sequence\n\\f2\\fs22 , one by one, and then executing the \n\\f3\\fs18 print()\n\\f2\\fs22  function for each value:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f4\\fs4 \\cf0 \\\n\n\\f3\\fs18 \\cf2 >\\cf0  \\cf3 my_sequence = 1:4;\\\nfor (element in my_sequence)\\\n   print(\"The square of \" + element + \" is \" + element^2);\n\\f4 \\cf0 \\\n\n\\fs4 \\\n\n\\f3\\fs18 \"The square of 1 is 1\"\\\n\"The square of 2 is 4\"\\\n\"The square of 3 is 9\"\\\n\"The square of 4 is 16\"\\\n\n\\f4\\fs4 \\\n\\pard\\tx2340\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 This looping construct is called by various names in other languages, such as the \\'93for each\\'94 statement (PHP), the \\'93range-based for\\'94 (C++), \\'93fast enumeration\\'94 (Objective-C), and so forth.  It is different from the traditional \n\\f3\\fs18 for\n\\f2\\fs22  loop of C and related languages, which entails an initializer expression, a condition expression, and an increment/decrement expression.  That type of \n\\f3\\fs18 for\n\\f2\\fs22  loop does not exist in Eidos (following R); the iterator \n\\f3\\fs18 for\n\\f2\\fs22  of R and Eidos is a more natural and efficient choice for vector-based languages.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.4  ITEM: 8. \n\\f1\\fs18 next\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 Sometimes you might wish to cut short the execution of a given iteration of a loop, skipping the rest of the work that would normally be done and proceeding directly to the next iteration.  This is the function of the \n\\f3\\fs18 next\n\\f2\\fs22  statement.  The \n\\f3\\fs18 next\n\\f2\\fs22  statement can be used within \n\\f3\\fs18 for\n\\f2\\fs22 , \n\\f3\\fs18 while\n\\f2\\fs22 , and \n\\f3\\fs18 do\\'96while\n\\f2\\fs22  loops.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.5  ITEM: 9. \n\\f1\\fs18 break\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 Often it is necessary to stop the execution of a loop altogether, not just to cut short the current iteration of the loop as \n\\f3\\fs18 next\n\\f2\\fs22  does.  To achieve this \\'96 to break out of a loop completely \\'96 use the \n\\f3\\fs18 break\n\\f2\\fs22  statement.  The \n\\f3\\fs18 break\n\\f2\\fs22  statement can be used within \n\\f3\\fs18 for\n\\f2\\fs22 , \n\\f3\\fs18 while\n\\f2\\fs22 , and \n\\f3\\fs18 do\\'96while\n\\f2\\fs22  loops.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.6.6  ITEM: 10. \n\\f1\\fs18 return\n\\f0\\fs22  statements\\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 return\n\\f2\\fs22  statement returns a value from a block of code, as in other languages such as C and R.  In one common case, when defining a user-defined function, \n\\f3\\fs18 return\n\\f2\\fs22  is used to stop execution of the function and return a given value to the caller.  Otherwise, a \n\\f3\\fs18 return\n\\f2\\fs22  is useful mostly when the Context within which you\\'92re using Eidos uses the returned value.  When using Eidos in SLiM, for example, SLiM uses the value returned by Eidos scripts such as \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks and \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks, making \n\\f3\\fs18 return\n\\f2\\fs22  very useful in that Context.  Apart from such Context-dependent uses, \n\\f3\\fs18 return\n\\f2\\fs22  is mainly useful as a way to break out of nested loops regardless of the depth of nesting, as illustrated below.\\\nThe \n\\f3\\fs18 return\n\\f2\\fs22  statement is very simple: the keyword \n\\f3\\fs18 return\n\\f2\\fs22 , and then, optionally, an expression.  When the \n\\f3\\fs18 return\n\\f2\\fs22  statement is executed, the expression is evaluated and its value is immediately returned as the value of the largest enclosing statement.  The \n\\f3\\fs18 return\n\\f2\\fs22  statement therefore breaks out of all conditionals, loops, and compound statements, regardless of the depth of nesting.\\\nIn some circumstances a \n\\f3\\fs18 return\n\\f2\\fs22  statement is not necessary, because compound statements evaluate to the value of the last statement evaluated within them, and \n\\f3\\fs18 if\n\\f2\\fs22  statements behave similarly; as in R, therefore, a \n\\f3\\fs18 return\n\\f2\\fs22  statement can often be omitted.  However, using \n\\f3\\fs18 return\n\\f2\\fs22  makes the intentions of the programmer more explicit, and so its use is encouraged.\\\nIf the expression for the \n\\f3\\fs18 return\n\\f2\\fs22  statement is omitted, the return value used is \n\\f3\\fs18 NULL\n\\f2\\fs22 .  In situations where the return value will not be used, such as Eidos events in SLiM, the return value should be omitted to make the intent of the code clear.\\\n\\pard\\pardeftab397\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.9.1  ITEM: 11. single-line comments with \n\\f1\\fs18 //\n\\f5\\fs22 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 Technically, comments are actually a type of whitespace; comments in Eidos code are completely ignored and have no effect whatsoever on the results of the execution of code, just like other kinds of whitespace in most respects.  Single-line comments begin with \n\\f3\\fs18 //\n\\f2\\fs22  and then may consist of any text whatsoever, up to the end of the current line of code.  A comment may occur by itself on a line, or it may follow other Eidos code.  So for example, you could write:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab397\\li547\\ri1440\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf5 1\\cf0  + \\cf5 1\\cf0  == \\cf5 2\\cf0 ;    \\cf6 // this is true\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Comments are never required in Eidos, but using them to annotate your code is nevertheless a very good idea, both so that you remember what your intentions were when you come back to the code weeks or months later, and so that others who might need to understand or maintain your code have a helping hand.\n\\f4 \\\n\\pard\\pardeftab397\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.9.2  ITEM: 12. block comments with \n\\f1\\fs18 /* */\n\\f5\\fs22 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 It is possible to comment out whole blocks of script, instead of just single lines.  This can be useful for writing longer comments that describe a section of code in more detail.  In Eidos (as in C and C++), such block comments can be written with a beginning \n\\f3\\fs18 /*\n\\f2\\fs22  and a terminating \n\\f3\\fs18 */\n\\f2\\fs22 .  Here\\'92s an example of this style of comment:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf6 /*\\\n   This computes the factorial x!, which is\\\n   the product of all values from 1 to x, for\\\n   any positive integer x.\\\n*/\n\\f4 \\cf0 \\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3 \\cf0 x_factorial = product(\\cf5 1\\cf0 :x);\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 A nice feature of Eidos is that block comments nest properly, making it possible to use them to comment out stretches of code that already contain block comments.  For example, if the code above was no longer needed, but you didn\\'92t want to delete it entirely because you might need it again later, you could use a block comment to disable it:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf6 /*\t******* NOT NEEDED ************\\\n/*\\\n   This computes the factorial x!, which is\\\n   the product of all values from 1 to x, for\\\n   any positive integer x.\\\n*/\\\nx_factorial = product(1:x);\\\n*/\n\\f4 \\cf0 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 The outer block comment is not terminated by the first \n\\f3\\fs18 */\n\\f2\\fs22  because Eidos recognizes that that belongs to the inner block comment; the outer block comment continues until the second \n\\f3\\fs18 */\n\\f2\\fs22  is encountered.\\\n\\pard\\pardeftab397\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 4.1  ITEM: 13. user-defined functions\n\\f5 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 Suppose we wish to define a function that doubles whatever \n\\f3\\fs18 float\n\\f2\\fs22  value is passed to it.  This is very easy to do:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf2 function\\cf0  (float)double(float x)\\\n\\{\\\n\t\\cf2 return\\cf0  \\cf5 2\\cf0  * x;\\\n\\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 The \n\\f3\\fs18 function\n\\f2\\fs22  keyword initiates the declaration of a new function.  It is followed by the full signature for the new function; here the signature declares that the function is named \n\\f3\\fs18 double\n\\f2\\fs22 , takes a parameter named \n\\f3\\fs18 x\n\\f2\\fs22  that is of type \n\\f3\\fs18 float\n\\f2\\fs22 , and returns type \n\\f3\\fs18 float\n\\f2\\fs22 .  This signature is then followed by the definition of the new function, in the form of a compound statement; here, the \n\\f3\\fs18 double()\n\\f2\\fs22  function is defined as returning two times the value it was passed.  Note that a \n\\f3\\fs18 return\n\\f2\\fs22  statement is used here to return a specified value from the function; if no \n\\f3\\fs18 return\n\\f2\\fs22  statement is encountered, the value of the last statement evaluated is automatically returned to the caller (as in R), but generally it is clearer to explicitly use \n\\f3\\fs18 return\n\\f4\\fs22 .\\\n\n\\f2 Calling such functions works in exactly the same way as calling built-in functions:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf2 >\\cf5  double(5.35)\\\n\\cf0 10.7\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 Functions may be recursive; a simple \n\\f3\\fs18 factorial()\n\\f2\\fs22  function might be defined recursively as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf2 function\\cf0  (integer)factorial(integer x)\\\n\\{\\\n\t\\cf2 if\\cf0  (x <= \\cf5 1\\cf0 )\\\n\t\t\\cf2 return\\cf0  \\cf5 1\\cf0 ;\\\n\t\\cf2 else\n\\f4 \\cf0 \\\n\t\t\n\\f3 \\cf2 return\\cf0  x * factorial(x - \\cf5 1\\cf0 );\\\n\\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 This works well enough, as you can see:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\pardeftab720\\li547\\ri1440\\sb40\\sa40\\partightenfactor0\n\n\\f3\\fs18 \\cf2 >\\cf5  factorial(13)\\\n\\cf0 6227020800\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf0 As with the built-in Eidos functions, user-defined functions may take multiple parameters, each of which may be allowed to be one of several different possible types.  Parameters to user-defined functions may also be optional, with a default value if left unsupplied.  Finally, functions are \n\\f0\\i scoped\n\\f2\\i0 ; the code inside them executes in a private namespace in which only the parameters to the function are available, and variables defined inside a function will not persist beyond the end of the function\\'92s execution.\\\n\\\n}"
  },
  {
    "path": "EidosScribe/EidosHelpTypes.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2513\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Italic;\\f1\\fnil\\fcharset0 Menlo-Italic;\\f2\\fswiss\\fcharset0 Optima-Regular;\n\\f3\\fnil\\fcharset0 Menlo-Regular;\\f4\\froman\\fcharset0 TimesNewRomanPSMT;\\f5\\fnil\\fcharset0 LucidaGrande;\n\\f6\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;\\f7\\fswiss\\fcharset0 Optima-Bold;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i\\fs22 \\cf0 2.1.1  ITEM: 1. type \n\\f1\\fs18 integer\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 integer\n\\f2\\fs22  type is used in Eidos to represent integers \\'96 whole numbers, with no fractional component.  Unlike in many languages, exponential notation may be used to specify \n\\f3\\fs18 integer\n\\f2\\fs22  literals (\\'93literals\\'94 means values stated literally in the script, rather than derived through calculations).\\\nThe \n\\f3\\fs18 integer\n\\f2\\fs22  type is advantageous primarily because it is exact; it does not suffer from any sort of roundoff error. Exact comparison with integer constants is therefore safe; roundoff error will not lead to problems caused by \n\\f3\\fs18 0.999999999\n\\f2\\fs22  being deemed to be unequal to \n\\f3\\fs18 1\n\\f4\\fs22 .\n\\f2   However, \n\\f3\\fs18 integer\n\\f2\\fs22  is disadvantageous because it can only represent a limited range of values, and beyond that range, results will be unpredictable.  Eidos uses 64 bits to store \n\\f3\\fs18 integer\n\\f2\\fs22  values, so that range is quite wide; to \n\\f3\\fs18 \\uc0\\u8722 9223372036854775806\n\\f2\\fs22  to \n\\f3\\fs18 9223372036854775807\n\\f2\\fs22 , to be exact.  That is broad, but it is still enormously narrower than the range of numbers representable with \n\\f3\\fs18 float\n\\f4\\fs22 .\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.1.2  ITEM: 2. type \n\\f1\\fs18 float\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 float\n\\f2\\fs22  type is used in Eidos to represent all non-\n\\f3\\fs18 integer\n\\f2\\fs22  numbers \\'96 fractions and real numbers.  Exponential notation may be used to specify \n\\f3\\fs18 float\n\\f2\\fs22  literals; in particular; literals with a decimal point or a negative exponent are taken to be of type \n\\f3\\fs18 float\n\\f2\\fs22 .\\\nNote that this rule means that some literals are represented using \n\\f3\\fs18 float\n\\f2\\fs22  even though they could also be represented using \n\\f3\\fs18 integer\n\\f4\\fs22 .\\\n\n\\f2 The \n\\f3\\fs18 float\n\\f2\\fs22  type is advantageous primarily because it can represent an enormously wide range of values.  Eidos uses C++\\'92s \n\\f3\\fs18 double\n\\f2\\fs22  type to represent its \n\\f3\\fs18 float\n\\f2\\fs22  values; the range of values allowed will depend upon your computer\\'92s settings, but it will be vast.  If that range is exceeded, or if numerical problems occur, type \n\\f3\\fs18 float\n\\f2\\fs22  can also represent values as infinity or as \\'93Not A Number\\'94 (\n\\f3\\fs18 INF\n\\f2\\fs22  and \n\\f3\\fs18 NAN\n\\f2\\fs22 , respectively, in Eidos).  The \n\\f3\\fs18 float\n\\f2\\fs22  type is thus more robust for operations that might produce such values.  The disadvantage of \n\\f3\\fs18 float\n\\f2\\fs22  is that it is inexact; some values cannot be represented exactly (just as 1/3 in base 10 cannot be represented exactly, and must be written as 0.3333333...).  Roundoff can thus cause comparison errors, overflow and underflow errors, and the accumulation of numerical error.\\\nSeveral \n\\f3\\fs18 float\n\\f2\\fs22  constants are defined in Eidos; besides \n\\f3\\fs18 INF\n\\f2\\fs22  and \n\\f3\\fs18 NAN\n\\f2\\fs22 , \n\\f3\\fs18 PI\n\\f2\\fs22  is defined as \n\\f5 \\uc0\\u960 \n\\f2  (3.14159...), and \n\\f3\\fs18 E\n\\f2\\fs22  is defined as \n\\f6\\i e\n\\f2\\i0  (2.71828...).\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.1.3  ITEM: 3. type \n\\f1\\fs18 logical\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 logical\n\\f2\\fs22  type represents true and false values, such as those from comparisons.  In many languages this type is called something like \n\\f3\\fs18 boolean\n\\f2\\fs22  or \n\\f3\\fs18 BOOL\n\\f2\\fs22 ; Eidos follows R in using the name \n\\f3\\fs18 logical\n\\f2\\fs22  instead.\\\nThere are no \n\\f3\\fs18 logical\n\\f2\\fs22  literals in Eidos.  However, there are defined constants that behave in essentially the same way as literals.  In particular, \n\\f3\\fs18 T\n\\f2\\fs22  is defined as true, and \n\\f3\\fs18 F\n\\f2\\fs22  is defined as false.  These are the only two values that the \n\\f3\\fs18 logical\n\\f2\\fs22  type can take.  As in a great many other languages, these \n\\f3\\fs18 logical\n\\f2\\fs22  values have equivalent numerical values; \n\\f3\\fs18 F\n\\f2\\fs22  is \n\\f3\\fs18 0\n\\f2\\fs22 , and \n\\f3\\fs18 T\n\\f2\\fs22  is \n\\f3\\fs18 1\n\\f2\\fs22  (and in fact any non-zero value is considered to be true if converted to \n\\f3\\fs18 logical\n\\f2\\fs22  type).  Values of type \n\\f3\\fs18 integer\n\\f2\\fs22  or \n\\f3\\fs18 float\n\\f2\\fs22  may therefore be converted to \n\\f3\\fs18 logical\n\\f2\\fs22 , and vice-versa.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.1.4  ITEM: 4. type \n\\f1\\fs18 string\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 string\n\\f2\\fs22  type represents a string of characters \\'96 a word, a sentence, a paragraph, the complete works of Shakespeare.  There is no formatting on a \n\\f3\\fs18 string\n\\f2\\fs22  \\'96 no \n\\f4 font\n\\f2 , no \n\\fs16 point size\n\\fs22 , no \n\\f7\\b bold\n\\f2\\b0  or \n\\f0\\i italic\n\\f2\\i0 .  Instead, it is just a character stream.  A \n\\f3\\fs18 string\n\\f2\\fs22  literal must be enclosed by either single or double quotation marks, \n\\f3\\fs18 '\n\\f2\\fs22  or \n\\f3\\fs18 \"\n\\f2\\fs22 .  This choice simplifies writing Eidos strings that themselves contain quote characters, because you can delimit the string with the opposite kind of quote.  For example, \n\\f3\\fs18 'You say, \"Ere thrice the sun done salutation to the dawn\"'\n\\f2\\fs22  is a string that contains double quotes, whereas \n\\f3\\fs18 \"Quoth the Raven, 'nevermore'.\\'94\n\\f2\\fs22  is a string that contains single quotes.  Apart from this consideration, it does not matter whether you use single or double quotes; the internal representation is the same.  The suggested convention is to prefer double quotes, all else being equal, since they are more universally used in other programming languages.\\\nA complication arises if one wishes to include both single and double quotation marks within a \n\\f3\\fs18 string\n\\f2\\fs22 ; whichever delimiter you choose, one or the other quote character will terminate the \n\\f3\\fs18 string\n\\f2\\fs22  literal.  In this case, the quotation mark must be \\'93escaped\\'94 by preceding it with a backslash, \n\\f3\\fs18 \\\\\n\\f2\\fs22 .  The backslash can be used to \\'93escape\\'94 various other characters; to include a newline in a string, for example, use \n\\f3\\fs18 \\\\n\n\\f2\\fs22 , and to include a tab, use \n\\f3\\fs18 \\\\t\n\\f2\\fs22 .  Since the backslash has this special meaning, backslashes themselves must be escaped as \n\\f3\\fs18 \\\\\\\\\n\\f2\\fs22 .  An alternative to dealing with escape sequences is to use the \\'93here document\\'94 style of string literal; see the Eidos manual for details on this.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.7.2  ITEM: 5. type \n\\f1\\fs18 NULL\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf0 The \n\\f3\\fs18 NULL\n\\f2\\fs22  type two primary uses: as a return value, and as a parameter.\\\nAs a return value, \n\\f3\\fs18 NULL\n\\f2\\fs22  is used to indicate that a function had nothing useful to return.  Some functions always return \n\\f3\\fs18 NULL\n\\f2\\fs22 , such as \n\\f3\\fs18 print()\n\\f2\\fs22 ; \n\\f3\\fs18 print()\n\\f2\\fs22  sends its output directly to the Eidos console.  It has nothing useful to return, so it returns \n\\f3\\fs18 NULL\n\\f2\\fs22 .  (That \n\\f3\\fs18 NULL\n\\f2\\fs22  value does not normally get printed out by Eidos because it is marked as an \\'93invisible\\'94 return, a side topic not really worth getting into here; invisible returns work much as they do in R).\\\nSome functions will return a useful value if they can, but will return \n\\f3\\fs18 NULL\n\\f2\\fs22  if they can\\'92t. Often a \n\\f3\\fs18 NULL\n\\f2\\fs22  return is a result of passing \n\\f3\\fs18 NULL\n\\f2\\fs22  in as an argument; garbage in, garbage out, as they say.  For example, the \n\\f3\\fs18 readFile()\n\\f2\\fs22  function will return \n\\f3\\fs18 NULL\n\\f2\\fs22  if an error occurs that prevents the file read operation from completing.  The calling code could then detect that \n\\f3\\fs18 NULL\n\\f2\\fs22  return and act accordingly \\'96 it might try to read from a different path, print an error, or terminate execution with \n\\f3\\fs18 stop()\n\\f2\\fs22 , or it might just ignore the problem, if reading the file was optional anyway (such as an optional configuration file to modify the default behavior of a script).\\\nThe other use of \n\\f3\\fs18 NULL\n\\f2\\fs22 , as mentioned above, is as an argument to a function. Passing \n\\f3\\fs18 NULL\n\\f2\\fs22  is occasionally a way of signaling that you don\\'92t want to supply a value for an argument, or that you want a default behavior from the function rather than telling it more specifically what to do.\\\n\n\\f3\\fs18 NULL\n\\f2\\fs22  cannot be an element of a vector of some other type; it cannot be used to mark missing or unknown values, for example.  Instead, \n\\f3\\fs18 NULL\n\\f2\\fs22  is its own type of vector in Eidos, always of zero length.  (There is also no \n\\f3\\fs18 NA\n\\f2\\fs22  value in Eidos like the one in R, while we\\'92re on the topic of marking missing values.  Not having to worry about missing values makes Eidos substantially simpler and faster, and Eidos \\'96 unlike R \\'96 is not designed to be used for doing statistical analysis, so marking missing values is not expected to be important.  Eidos does support \n\\f3\\fs18 NAN\n\\f2\\fs22  \\'96 Not A Number \\'96 values in \n\\f3\\fs18 float\n\\f2\\fs22  vectors, however, which could conceivably be used to mark missing values if necessary.)\\\nThe basic philosophy of how Eidos handles \n\\f3\\fs18 NULL\n\\f2\\fs22  values in expressions and computations is that \n\\f3\\fs18 NULL\n\\f2\\fs22  in such situations represents a non-fatal error or an unknown value.  If using the \n\\f3\\fs18 NULL\n\\f2\\fs22  value in some meaningful way could lead to potentially misleading or incorrect results, Eidos will generate a fatal error.  The idea is to give Eidos code an opportunity to detect a \n\\f3\\fs18 NULL\n\\f2\\fs22 , and thus to catch and handle the non-fatal error; but if the code does not handle the \n\\f3\\fs18 NULL\n\\f2\\fs22 , using the \n\\f3\\fs18 NULL\n\\f2\\fs22  in further operations will result in a fatal error before the functioning of the code is seriously compromised.  \n\\f3\\fs18 NULL\n\\f2\\fs22  values are thus a sort of third rail; there\\'92s a good reason they exist, but you have to be very careful around them.  They are a bit like zero-valued pointers in C (\n\\f3\\fs18 NULL\n\\f2\\fs22 ), C++ (\n\\f3\\fs18 nullptr\n\\f2\\fs22 ), Objective-C (\n\\f3\\fs18 nil\n\\f2\\fs22 ), and similar languages; they are widely used, but if you ever use one the wrong way it is an immediate and fatal error.  For further details, please consult the Eidos manual.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 2.8.1  ITEM: 6. type \n\\f1\\fs18 object\n\\f0\\fs22 \\\n\\pard\\pardeftab720\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 In addition to \n\\f3\\fs18 logical\n\\f2\\fs22 , \n\\f3\\fs18 integer\n\\f2\\fs22 , \n\\f3\\fs18 float\n\\f2\\fs22 , \n\\f3\\fs18 string\n\\f2\\fs22 , and \n\\f3\\fs18 NULL\n\\f2\\fs22 , there is one more type in Eidos left to discuss: \n\\f3\\fs18 object\n\\f2\\fs22 .  A variable of type \n\\f3\\fs18 object\n\\f2\\fs22  is a vector that contains elements; it is a container, a bag of stuff.  In this way, it is similar to Eidos\\'92s other types; a \n\\f3\\fs18 float\n\\f2\\fs22  vector in Eidos contains floating-point elements, whereas an \n\\f3\\fs18 object\n\\f2\\fs22  vector contains \n\\f3\\fs18 object\n\\f2\\fs22 -elements (often just called \\'93objects\\'94; whether one is referring to a single \n\\f3\\fs18 object\n\\f2\\fs22 -element or a vector of type \n\\f3\\fs18 object\n\\f2\\fs22  is generally clear from context).  An \n\\f3\\fs18 object\n\\f2\\fs22  vector can also embody \n\\f0\\i behavior\n\\f2\\i0 : it has operations that it can perform using the elements it contains, which all belong to a \n\\f0\\i class\n\\f2\\i0  that defines the available behaviors.  The \n\\f3\\fs18 object\n\\f2\\fs22  type in Eidos is thus similar to objects in other languages such as Java, C++, or R \\'96 except much more limited.  In Eidos you cannot define your own \n\\f3\\fs18 object\n\\f2\\fs22  classes; you work only with the predefined \n\\f3\\fs18 object\n\\f2\\fs22  classes supplied by SLiM or whatever other Context you might be using Eidos within.  These predefined \n\\f3\\fs18 object\n\\f2\\fs22  classes generally define Context-dependent \n\\f3\\fs18 object\n\\f2\\fs22 -elements related to the task performed by the Context; in SLiM, the classes are things such as mutations, genomic elements, and mutation types (described in SLiM\\'92s documentation).  Eidos itself also supplies a few built-in \n\\f3\\fs18 object\n\\f2\\fs22  classes, notably \n\\f3\\fs18 Dictionary\n\\f2\\fs22  and \n\\f3\\fs18 Image\n\\f2\\fs22 .\\\nThe behaviors of objects in Eidos manifest in two ways: objects can have \n\\f0\\i properties\n\\f2\\i0  (also called instance variables or member variables, in other languages) that can be read from and written to, and they can have \n\\f0\\i methods\n\\f2\\i0  (also called member functions, in other languages).  The behavior of an \n\\f3\\fs18 object\n\\f2\\fs22  vector in Eidos is determined by the class of element the \n\\f3\\fs18 object\n\\f2\\fs22  contains; an Eidos \n\\f3\\fs18 object\n\\f2\\fs22  will always contain only one class of element (just as a \n\\f3\\fs18 float\n\\f2\\fs22  cannot contain \n\\f3\\fs18 string\n\\f2\\fs22 -elements, for example).\\\nInstances of particular \n\\f3\\fs18 object\n\\f2\\fs22  classes \\'96 particular kinds of objects \\'96 are obtained via built-in functions and/or global constants and variables.  For example, in SLiM there is a global constant called \n\\f3\\fs18 sim\n\\f2\\fs22  that represents the simulated species as an instance of the \n\\f3\\fs18 Species\n\\f2\\fs22  class.}"
  },
  {
    "path": "EidosScribe/EidosPrettyprinter.h",
    "content": "//\n//  EidosPrettyprinter.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Foundation/Foundation.h>\n\n#include <vector>\n\n#include \"eidos_script.h\"\n\n\n@interface EidosPrettyprinter : NSObject\n{\n}\n\n// Prettyprint the given token stream into an NSMutableString\n+ (BOOL)prettyprintTokens:(const std::vector<EidosToken> &)tokens fromScript:(EidosScript &)tokenScript intoString:(NSMutableString *)pretty;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosPrettyprinter.mm",
    "content": "//\n//  EidosPrettyprinter.m\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosPrettyprinter.h\"\n\n#include \"eidos_script.h\"\n\n\n@implementation EidosPrettyprinter\n\n+ (int)indentForStack:(std::vector<const EidosToken *> &)indentStack startingNewStatement:(BOOL)startingNewStatement nextTokenType:(EidosTokenType)nextTokenType\n{\n\t// Count the number of indents represented by the indent stack.  When a control-flow keyword is\n\t// followed by a left brace, the indent stack has two items on it, but we want to only indent\n\t// one level.\n\tint indent = 0;\n\tBOOL previousIndentStackItemWasControlFlow = NO;\n\t\n\tfor (int stackIndex = 0; stackIndex < (int)indentStack.size(); ++stackIndex)\n\t{\n\t\tEidosTokenType stackTokenType = indentStack[stackIndex]->token_type_;\n\t\t\n\t\t// skip over ternary conditionals; they do not generate indent, but are on the stack so we can match elses\n\t\tif (stackTokenType == EidosTokenType::kTokenConditional)\n\t\t\tcontinue;\n\t\t\n\t\tif (previousIndentStackItemWasControlFlow && (stackTokenType == EidosTokenType::kTokenLBrace))\n\t\t\t;\n\t\telse\n\t\t\t++indent;\n\t\t\n\t\tpreviousIndentStackItemWasControlFlow = !(stackTokenType == EidosTokenType::kTokenLBrace);\n\t}\n\t\n\tBOOL lastIndentIsControlFlow = previousIndentStackItemWasControlFlow;\n\t\n\t// Indent when continuing a statement, but not after a control-flow token.  The idea here is that\n\t// if you have a structure like:\n\t//\n\t//\tif (x)\n\t//\t\tif (y)\n\t//\t\t\t<statement>;\n\t//\n\t// the indent stack will already dictate that <statement> is indented twice; it does not need to\n\t// receive the !startingNewStatement extra indent level that we normally add to cause continuing\n\t// statements to be indented like:\n\t//\n\t//\tx = a + b + c +\n\t//\t\td + e + f;\n\t//\n\tif (!startingNewStatement && !lastIndentIsControlFlow)\n\t\tindent++;\n\t\n\t// If the next token is a left brace, outdent one level, conventionally.  This reflects usage like:\n\t//\n\t//\tif (x)\n\t//\t\ty;\n\t//\n\t//\tif (x)\n\t//\t{\n\t//\t\ty;\n\t//\t}\n\t//\n\t// This applies only if the last element on the indent stack is a control-flow indent, not a {.\n\t// This is the same rule we used when counting indentStack, but applied to nextTokenType.  We also\n\t// outdent when we see a left brace if we are mid-statement; this covers SLiM callback syntax.\n\t//\n\tif ((lastIndentIsControlFlow || !startingNewStatement) && (nextTokenType == EidosTokenType::kTokenLBrace))\n\t\tindent--;\n\t\n\t// For similar reasons, if the next token is a right brace, always outdent one level\n\tif (nextTokenType == EidosTokenType::kTokenRBrace)\n\t\tindent--;\n\t\n\treturn indent;\n}\n\n+ (BOOL)prettyprintTokens:(const std::vector<EidosToken> &)tokens fromScript:(EidosScript &)tokenScript intoString:(NSMutableString *)pretty\n{\n\t// We keep a stack of indent-generating tokens: { if else do while for.  The purpose of this is\n\t// to be able to tell what indent level we're at, and how it changes with a ; or a } token.\n\tstd::vector<const EidosToken *> indentStack;\n\tBOOL startingNewStatement = YES;\n\tint tokenCount = (int)tokens.size();\n\t\n\tfor (int tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex)\n\t{\n\t\tconst EidosToken &token = tokens[tokenIndex];\n\t\tNSString *tokenString = [NSString stringWithUTF8String:token.token_string_.c_str()];\n\t\tEidosTokenType nextTokenPeek = (tokenIndex + 1 < tokenCount ? tokens[tokenIndex+1].token_type_ : EidosTokenType::kTokenEOF);\n\t\t\n\t\t// Find the next non-whitespace, non-comment token for lookahead\n\t\tint nextSignificantTokenPeekIndex = tokenIndex + 1;\n\t\tEidosTokenType nextSignificantTokenPeek = EidosTokenType::kTokenEOF;\n\t\t\n\t\twhile (nextSignificantTokenPeekIndex < tokenCount)\n\t\t{\n\t\t\tEidosTokenType peek = tokens[nextSignificantTokenPeekIndex].token_type_;\n\t\t\t\n\t\t\tif ((peek != EidosTokenType::kTokenWhitespace) && (peek != EidosTokenType::kTokenComment) && (peek != EidosTokenType::kTokenCommentLong))\n\t\t\t{\n\t\t\t\tnextSignificantTokenPeek = peek;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tnextSignificantTokenPeekIndex++;\n\t\t}\n\t\t\n\t\tswitch (token.token_type_)\n\t\t{\n\t\t\t\t// These token types are not used in the AST and should not be present\n\t\t\tcase EidosTokenType::kTokenNone:\n\t\t\tcase EidosTokenType::kTokenBad:\n\t\t\t\treturn NO;\n\t\t\t\t\n\t\t\t\t// These are virtual tokens that can be ignored\n\t\t\tcase EidosTokenType::kTokenEOF:\n\t\t\tcase EidosTokenType::kTokenInterpreterBlock:\n\t\t\tcase EidosTokenType::kTokenContextFile:\n\t\t\tcase EidosTokenType::kTokenContextEidosBlock:\n\t\t\tcase EidosTokenType::kFirstIdentifierLikeToken:\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// This is where the rubber meets the road; prettyprinting is all about altering whitespace stretches.\n\t\t\t\t// We don't want to alter the user's newline decisions, so we count the number of newlines in this\n\t\t\t\t// whitespace stretch and always emit the same number.  If there are no newlines, we're in whitespace\n\t\t\t\t// inside a given line, with tokens on both sides; for the time being we do not alter those at all.\n\t\t\t\t// If there are newlines, though, then each newline is changed to be followed by the appropriate number\n\t\t\t\t// of tabs as indentation.  The indent depends upon the indent stack and some other state about the\n\t\t\t\t// context we are in.\n\t\t\tcase EidosTokenType::kTokenWhitespace:\n\t\t\t{\n\t\t\t\t__block int newlineCount = 0;\n\t\t\t\t\n\t\t\t\t[tokenString enumerateSubstringsInRange:NSMakeRange(0, [tokenString length])\n\t\t\t\t\t\t\t\t\t\t\t\toptions:NSStringEnumerationByParagraphs\n\t\t\t\t\t\t\t\t\t\t\t usingBlock:^(NSString * _Nullable paragraph, NSRange paragraphRange, NSRange enclosingRange, BOOL * _Nonnull stop)\n\t\t\t\t{\n\t\t\t\t\tif (enclosingRange.location + enclosingRange.length > paragraphRange.location + paragraphRange.length)\n\t\t\t\t\t\tnewlineCount++;\n\t\t\t\t}];\n\t\t\t\t\n\t\t\t\tif (newlineCount <= 0)\n\t\t\t\t{\n\t\t\t\t\t// Normally, whitespace tokens that do not contain a newline occur inside a line, and should be preserved.\n\t\t\t\t\t// A whitespace token that indents the start of a line normally started on the previous line and contains\n\t\t\t\t\t// a newline.  However, this is not the case at the very beginning of a script; the first token is special.\n\t\t\t\t\tif (tokenIndex > 0)\n\t\t\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tint indent = [EidosPrettyprinter indentForStack:indentStack startingNewStatement:startingNewStatement nextTokenType:nextTokenPeek];\n\t\t\t\t\t\n\t\t\t\t\tfor (int lineCounter = 0; lineCounter < newlineCount; ++lineCounter)\n\t\t\t\t\t{\n\t\t\t\t\t\t[pretty appendString:@\"\\n\"];\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int tabCounter = 0; tabCounter < indent; ++tabCounter)\n\t\t\t\t\t\t\t[pretty appendString:@\"\\t\"];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// We have ended a statement, so we reset our indent levels\n\t\t\tcase EidosTokenType::kTokenSemicolon:\n\t\t\t{\n\t\t\t\t// Pop indent-generating tokens that have expired with the end of this statement; a semicolon terminates\n\t\t\t\t// a whole nested series of if else do while for, but does not terminate an enclosing { block.  Also,\n\t\t\t\t// if there are nested if statements, a semicolon terminates only the first one if the next token is an else.\n\t\t\t\twhile (indentStack.size() > 0) {\n\t\t\t\t\tconst EidosToken *topIndentToken = indentStack.back();\n\t\t\t\t\t\n\t\t\t\t\tif (topIndentToken->token_type_ == EidosTokenType::kTokenLBrace)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif ((topIndentToken->token_type_ == EidosTokenType::kTokenIf) && (nextSignificantTokenPeek == EidosTokenType::kTokenElse))\n\t\t\t\t\t{\n\t\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Track braces\n\t\t\tcase EidosTokenType::kTokenLBrace:\n\t\t\t{\n\t\t\t\tindentStack.emplace_back(&token);\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosTokenType::kTokenRBrace:\n\t\t\t{\n\t\t\t\t// First pop the matching left brace\n\t\t\t\tif ((indentStack.size() == 0) || (indentStack.back()->token_type_ != EidosTokenType::kTokenLBrace))\n\t\t\t\t{\n\t\t\t\t\t// All other indent-producing tokens should already have been balanced; Eidos has no implicit termination of statements\n\t\t\t\t\tNSLog(@\"Unbalanced '}' token in prettyprinting!\");\n\t\t\t\t\treturn NO;\n\t\t\t\t}\n\t\t\t\tindentStack.pop_back();\n\t\t\t\t\n\t\t\t\t// Then pop indent-generating tokens above the left brace that have expired with the end of this statement\n\t\t\t\twhile (indentStack.size() > 0) {\n\t\t\t\t\tconst EidosToken *topIndentToken = indentStack.back();\n\t\t\t\t\t\n\t\t\t\t\tif (topIndentToken->token_type_ == EidosTokenType::kTokenLBrace)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Control-flow keywords influence our indent level; this might look like the normal statement inner indent,\n\t\t\t\t// but it is not, as can be seen when these control-flow keywords are nested like 'if (x) if (y) <statement>'.\n\t\t\t\t// When an if follows an else, the else is removed by the if, since we don't want two indents; else-if is one indent.\n\t\t\tcase EidosTokenType::kTokenIf:\n\t\t\t{\n\t\t\t\tif (indentStack.size())\n\t\t\t\t{\n\t\t\t\t\tEidosTokenType top_token_type = indentStack.back()->token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (top_token_type == EidosTokenType::kTokenElse)\n\t\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindentStack.emplace_back(&token);\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\tcase EidosTokenType::kTokenDo:\n\t\t\tcase EidosTokenType::kTokenWhile:\n\t\t\tcase EidosTokenType::kTokenFor:\n\t\t\tcase EidosTokenType::kTokenConditional:\t\t// note this does not generate indent, but is put on the stack\n\t\t\t{\n\t\t\t\tindentStack.emplace_back(&token);\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// else can be paired with if or ?.  In the former case, the if will be off the stack by the time the else\n\t\t\t\t// is encountered, and we put the else on to give us an equivalent indent.  In the latter case, we consider\n\t\t\t\t// the expressions within the ternary conditional to be statement-level; we don't indent, and we don't push\n\t\t\t\t// an else on the stack here, but we remove the conditional that we are completing.\n\t\t\tcase EidosTokenType::kTokenElse:\n\t\t\t{\n\t\t\t\tif (indentStack.size())\n\t\t\t\t{\n\t\t\t\t\tEidosTokenType top_token_type = indentStack.back()->token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (top_token_type == EidosTokenType::kTokenConditional)\n\t\t\t\t\t{\n\t\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindentStack.emplace_back(&token);\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Comments are preserved verbatim\n\t\t\tcase EidosTokenType::kTokenComment:\n\t\t\tcase EidosTokenType::kTokenCommentLong:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Tokens for operators are emitted verbatim\n\t\t\tcase EidosTokenType::kTokenColon:\n\t\t\tcase EidosTokenType::kTokenComma:\n\t\t\tcase EidosTokenType::kTokenDot:\n\t\t\tcase EidosTokenType::kTokenPlus:\n\t\t\tcase EidosTokenType::kTokenMinus:\n\t\t\tcase EidosTokenType::kTokenMod:\n\t\t\tcase EidosTokenType::kTokenMult:\n\t\t\tcase EidosTokenType::kTokenExp:\n\t\t\tcase EidosTokenType::kTokenAnd:\n\t\t\tcase EidosTokenType::kTokenOr:\n\t\t\tcase EidosTokenType::kTokenDiv:\n\t\t\tcase EidosTokenType::kTokenAssign:\n\t\t\tcase EidosTokenType::kTokenAssign_R:\n\t\t\tcase EidosTokenType::kTokenEq:\n\t\t\tcase EidosTokenType::kTokenLt:\n\t\t\tcase EidosTokenType::kTokenLtEq:\n\t\t\tcase EidosTokenType::kTokenGt:\n\t\t\tcase EidosTokenType::kTokenGtEq:\n\t\t\tcase EidosTokenType::kTokenNot:\n\t\t\tcase EidosTokenType::kTokenNotEq:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase EidosTokenType::kTokenSingleton:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Nesting levels of parens and brackets are not tracked at the moment\n\t\t\tcase EidosTokenType::kTokenLParen:\n\t\t\tcase EidosTokenType::kTokenRParen:\n\t\t\tcase EidosTokenType::kTokenLBracket:\n\t\t\tcase EidosTokenType::kTokenRBracket:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Numbers and identifiers are emitted verbatim\n\t\t\tcase EidosTokenType::kTokenNumber:\n\t\t\tcase EidosTokenType::kTokenIdentifier:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Strings are emitted verbatim, but their original string needs to be reconstructed;\n\t\t\t\t// token_string_ has the outer quotes removed and escape sequences resolved\n\t\t\tcase EidosTokenType::kTokenString:\n\t\t\t{\n\t\t\t\tstd::string string_original = tokenScript.String().substr(token.token_start_, token.token_end_ - token.token_start_ + 1);\n\t\t\t\t[pretty appendString:[NSString stringWithUTF8String:string_original.c_str()]];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// These keywords have no effect on indent level\n\t\t\tcase EidosTokenType::kTokenIn:\n\t\t\tcase EidosTokenType::kTokenNext:\n\t\t\tcase EidosTokenType::kTokenBreak:\n\t\t\tcase EidosTokenType::kTokenReturn:\n\t\t\tcase EidosTokenType::kTokenFunction:\n\t\t\t\t[pretty appendString:tokenString];\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Now that we're done processing that token, update startingNewStatement to reflect whether we are within\n\t\t// a statement, of which we have seen at least one token, or starting a new statement.  Nonsignificant\n\t\t// tokens (whitespace and comments) do not alter the state of startingNewStatement.\n\t\tif ((token.token_type_ != EidosTokenType::kTokenWhitespace) && (token.token_type_ != EidosTokenType::kTokenComment) && (token.token_type_ != EidosTokenType::kTokenCommentLong))\n\t\t\tstartingNewStatement = ((token.token_type_ == EidosTokenType::kTokenSemicolon) ||\n\t\t\t\t\t\t\t\t\t(token.token_type_ == EidosTokenType::kTokenLBrace) ||\n\t\t\t\t\t\t\t\t\t(token.token_type_ == EidosTokenType::kTokenRBrace));\n\t}\n\t\n\treturn YES;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosScribe-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>4.2</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016–2025 Benjamin C. Haller, http://messerlab.org/slim/. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "EidosScribe/EidosScribe.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "EidosScribe/EidosScribe_multi-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>4.2</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016–2025 Benjamin C. Haller, http://messerlab.org/slim/. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "EidosScribe/EidosScribe_multi.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "EidosScribe/EidosTextView.h",
    "content": "//\n//  EidosTextView.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/14/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n@protocol EidosTextViewDelegate;\n\n\n/*\n \n A subclass to provide various niceties for a syntax-colored, autoindenting, tab-stopped text view.\n This class uses the standard NSTextView delegate object, but will use the optional methods defined\n by the EidosTextViewDelegate protocol if implemented by that delegate.\n\n */\n\ntypedef enum EidosSyntaxColoringOption\n{\n\tkEidosSyntaxColoringNone = 0,\n\tkEidosSyntaxColoringEidos,\n\tkEidosSyntaxColoringOutput\n} EidosSyntaxColoringOption;\n\n\n@interface EidosTextView : NSTextView\n{\n}\n\n// A delegate for Eidos functionality; this is the same object as the NSText/NSTextView delegate, and is not declared explicitly\n// here because overriding properties with a different type doesn't really work.  So when you call setDelegate: on EidosTextView,\n// you will not get the proper type-checking, and you will get a runtime error if your delegate object does not in fact conform\n// to the EidosTextViewDelegate protocol.  But if you declare your conformance to the protocol, you should be fine.  This is a\n// little weird, but the only good alternative is to have a separate delegate object for Eidos, which would just be annoying and\n// confusing.\n//\n//@property (nonatomic, assign) id<EidosTextViewDelegate> delegate;\n\n// The syntax coloring option being used\n@property (nonatomic) EidosSyntaxColoringOption syntaxColoring;\n\n// The font size (of Menlo) being used\n@property (nonatomic) int displayFontSize;\n\n// A flag to temporarily disable syntax coloring, used to coalesce multiple changes into a single recolor\n@property (nonatomic) BOOL shouldRecolorAfterChanges;\n\n// Same designated initializers as NSTextView\n- (instancetype)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;\n\n// Actions associated with code editing\n- (IBAction)shiftSelectionLeft:(id)sender;\n- (IBAction)shiftSelectionRight:(id)sender;\n- (IBAction)commentUncommentSelection:(id)sender;\n\n// If an error occurs while tokenizing/parsing/executing Eidos code in this textview, call this to highlight the error\n- (void)selectErrorRange;\n\n// Called after disabling syntax coloring with shouldRecolorAfterChanges, to provide the coalesced recoloring\n- (void)recolorAfterChanges;\n\n// These are used by the Find Recipe panel in SLiM to highlight matches with search terms\n- (void)clearHighlightMatches;\n- (void)highlightMatchesForString:(NSString *)matchString;\n\n// This method is used to construct the function/method prototypes shown in the status bar; client code\n// probably will not call it, but possibly it could be used for context-sensitive help or something\n- (NSAttributedString *)attributedSignatureForScriptString:(NSString *)scriptString selection:(NSRange)selection;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosTextView.mm",
    "content": "//\n//  EidosTextView.mm\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/14/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosTextView.h\"\n#import \"EidosTextViewDelegate.h\"\n#import \"EidosConsoleTextView.h\"\n#import \"EidosCocoaExtra.h\"\n#import \"EidosHelpController.h\"\n\n#include \"eidos_script.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_type_table.h\"\n#include \"eidos_type_interpreter.h\"\n#include \"eidos_sorting.h\"\n\n#include <stdexcept>\n#include <memory>\n\n\n//\tEidosTextStorage – a little subclass to make word selection in EidosTextView work the way it should, defined below\n@interface EidosTextStorage : NSTextStorage\n- (id)init;\n- (id)initWithAttributedString:(NSAttributedString *)attrStr NS_DESIGNATED_INITIALIZER;\n@end\n\n\n@interface EidosTextView () <NSTextStorageDelegate>\n{\n\t// these are used in selectionRangeForProposedRange:granularity: to balance delimiters properly\n\tBOOL inEligibleDoubleClick;\n\tNSTimeInterval doubleDownTime;\n}\n@end\n\n@implementation EidosTextView\n\n- (instancetype)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)aTextContainer\n{\n\tif (self = [super initWithFrame:frameRect textContainer:aTextContainer])\n\t{\n\t\t_displayFontSize = 11;\n\t\t_shouldRecolorAfterChanges = YES;\n\t}\n\t\n\treturn self;\n}\n\n- (instancetype)initWithCoder:(NSCoder *)coder\n{\n\tif (self = [super initWithCoder:coder])\n\t{\n\t\t_displayFontSize = 11;\n\t\t_shouldRecolorAfterChanges = YES;\n\t}\n\t\n\treturn self;\n}\n\n- (void)awakeFromNib\n{\n\t// Replace the text storage of the description textview with our custom subclass\n\tNSLayoutManager *lm = [self layoutManager];\n\tNSTextStorage *ts = [self textStorage];\n\tEidosTextStorage *replacementTextStorage = [[EidosTextStorage alloc] initWithAttributedString:ts];\t// copy any existing text\n\t\n\t[lm replaceTextStorage:replacementTextStorage];\n\t[replacementTextStorage setDelegate:self];\n\t[replacementTextStorage release];\n\t\n\t// Turn off all of Cocoa's fancy text editing stuff\n\t[self setAutomaticDashSubstitutionEnabled:NO];\n\t[self setAutomaticDataDetectionEnabled:NO];\n\t[self setAutomaticLinkDetectionEnabled:NO];\n\t[self setAutomaticQuoteSubstitutionEnabled:NO];\n\t[self setAutomaticSpellingCorrectionEnabled:NO];\n\t[self setAutomaticTextReplacementEnabled:NO];\n\t[self setContinuousSpellCheckingEnabled:NO];\n\t[self setGrammarCheckingEnabled:NO];\n\t[self turnOffLigatures:nil];\n\t\n\t// Fix the font and typing attributes\n\t[self setFont:[NSFont fontWithName:@\"Menlo\" size:_displayFontSize]];\n\t[self setTypingAttributes:[NSDictionary eidosTextAttributesWithColor:nil size:_displayFontSize]];\n\t\n\t// Fix text container insets to look a bit nicer; {0,0} by default\n\t[self setTextContainerInset:NSMakeSize(0.0, 5.0)];\n}\n\n// The method signature is inherited from NSTextView, but we want to check that the delegate follows our delegate protocol\n- (void)setDelegate:(id<NSTextViewDelegate>)delegate\n{\n\tif (delegate && ![delegate conformsToProtocol:@protocol(EidosTextViewDelegate)])\n\t\tNSLog(@\"Delegate %@ assigned to EidosTextView %p does not conform to the EidosTextViewDelegate protocol!\", delegate, self);\n\t\n\t[super setDelegate:delegate];\n}\n\n// handle flashing of matching delimiters\n- (void)insertText:(id)insertString replacementRange:(NSRange)replacementRange\n{\n\t//bool replacingSelection = NSEqualRanges(replacementRange, [self selectedRange]);\n\t\n\t[super insertText:insertString replacementRange:replacementRange];\n\t\n\t// if we replaced something other than the selected range, something weird is going on and we shouldn't flash\n\t// this is commented out because it doesn't work; AppKit likes to call this method with {NSNotFound,0} for typing...\n\t//if (!replacingSelection)\n\t//\treturn;\n\t\n\t// if the insert string isn't one character in length, it cannot be a brace character\n\tif ([insertString length] != 1)\n\t\treturn;\n\t\n\tunichar uch = [insertString characterAtIndex:0];\n\t\n\tif ((uch == '}') || (uch == ']') || (uch == ')'))\n\t{\n\t\t// MAINTENANCE NOTE: This also exists, in slightly altered form, in selectionRangeForProposedRange:granularity:, so please maintain the two in parallel!\n\t\tNSString *scriptString = [[self textStorage] string];\n\t\tint stringLength = (int)[scriptString length];\n\t\tint proposedCharacterIndex = (int)[self selectedRange].location - 1;\t// just inserted a single character\n\t\tBOOL forward = false;\n\t\tunichar incrementChar = ' ';\n\t\tunichar decrementChar = ' ';\n\t\tEidosTokenType token1 = EidosTokenType::kTokenNone;\n\t\tEidosTokenType token2 = EidosTokenType::kTokenNone;\n\t\t\n\t\t// Check for any of the delimiter types we support, and set up to do a scan\n\t\tif (uch == '}')\t\t{ forward = false; incrementChar = '}'; decrementChar = '{'; token1 = EidosTokenType::kTokenLBrace; token2 = EidosTokenType::kTokenRBrace; }\n\t\tif (uch == ')')\t\t{ forward = false; incrementChar = ')'; decrementChar = '('; token1 = EidosTokenType::kTokenLParen; token2 = EidosTokenType::kTokenRParen; }\n\t\tif (uch == ']')\t\t{ forward = false; incrementChar = ']'; decrementChar = '['; token1 = EidosTokenType::kTokenLBracket; token2 = EidosTokenType::kTokenRBracket; }\n\t\t\n\t\tif (token1 != EidosTokenType::kTokenNone)\n\t\t{\n\t\t\t// We've got a double-click on a character that we want to balance-select.  This is complicated mostly\n\t\t\t// because of strings, which are a pain in the butt.  To simplify that issue, we tokenize and search\n\t\t\t// in the token stream parallel to searching in the text.\n\t\t\tstd::string script_string([scriptString UTF8String]);\n\t\t\tEidosScript script(script_string);\n\t\t\t\n\t\t\t// Tokenize\n\t\t\tscript.Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n\t\t\t\n\t\t\t// Find the token containing the double-click point\n\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\tint token_count = (int)tokens.size();\n\t\t\tconst EidosToken *click_token = nullptr;\n\t\t\tint click_token_index;\n\t\t\t\n\t\t\tfor (click_token_index = 0; click_token_index < token_count; ++click_token_index)\n\t\t\t{\n\t\t\t\tclick_token = &tokens[click_token_index];\n\t\t\t\t\n\t\t\t\tif ((click_token->token_UTF16_start_ <= proposedCharacterIndex) && (click_token->token_UTF16_end_ >= proposedCharacterIndex))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!click_token)\n\t\t\t\treturn;\n\t\t\t\n\t\t\t// OK, this token contains the character that was double-clicked.  We could have the actual token\n\t\t\t// (incrementToken), we could be in a string, or we could be in a comment.  We stay in the domain\n\t\t\t// that we start in; if in a string, for example, only delimiters within strings affect our scan.\n\t\t\tEidosTokenType click_token_type = click_token->token_type_;\n\t\t\tconst EidosToken *scan_token = click_token;\n\t\t\tint scan_token_index = click_token_index;\n\t\t\tNSInteger scanPosition = proposedCharacterIndex;\n\t\t\tint balanceCount = 0;\n\t\t\t\n\t\t\twhile (YES)\n\t\t\t{\n\t\t\t\tEidosTokenType scan_token_type = scan_token->token_type_;\n\t\t\t\tBOOL isCandidate;\n\t\t\t\t\n\t\t\t\tif (click_token_type == EidosTokenType::kTokenComment)\n\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenComment);\n\t\t\t\telse if (click_token_type == EidosTokenType::kTokenCommentLong)\n\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenCommentLong);\n\t\t\t\telse if (click_token_type == EidosTokenType::kTokenString)\n\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenString);\n\t\t\t\telse\n\t\t\t\t\tisCandidate = ((scan_token_type == token1) || (scan_token_type == token2));\n\t\t\t\t\n\t\t\t\tif (isCandidate)\n\t\t\t\t{\n\t\t\t\t\tuch = [scriptString characterAtIndex:scanPosition];\n\t\t\t\t\t\n\t\t\t\t\tif (uch == incrementChar)\n\t\t\t\t\t\tbalanceCount++;\n\t\t\t\t\telse if (uch == decrementChar)\n\t\t\t\t\t\tbalanceCount--;\n\t\t\t\t\t\n\t\t\t\t\t// If balanceCount is now zero, all opens have been balanced by closes, and we have found our matching delimiter\n\t\t\t\t\tif (balanceCount == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t[self showFindIndicatorForRange:NSMakeRange(scanPosition, 1)];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Advance, forward or backward, to the next character\n\t\t\t\tscanPosition += (forward ? 1 : -1);\n\t\t\t\tif ((scanPosition == stringLength) || (scanPosition == -1))\n\t\t\t\t{\n\t\t\t\t\t//NSBeep();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Make sure we're in the right token\n\t\t\t\twhile ((scan_token->token_UTF16_start_ > scanPosition) || (scan_token->token_UTF16_end_ < scanPosition))\n\t\t\t\t{\n\t\t\t\t\tscan_token_index += (forward ? 1 : -1);\n\t\t\t\t\t\n\t\t\t\t\tif ((scan_token_index < 0) || (scan_token_index == token_count))\n\t\t\t\t\t{\n\t\t\t\t\t\tNSLog(@\"ran out of tokens!\");\n\t\t\t\t\t\t//NSBeep();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tscan_token = &tokens[scan_token_index];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// handle autoindent by matching the whitespace beginning the current line\n- (void)insertNewline:(id)sender\n{\n\tNSString *textString = [self string];\n\tNSUInteger selectionStart = [self selectedRange].location;\n\tNSCharacterSet *newlineChars = [NSCharacterSet newlineCharacterSet];\n\tNSCharacterSet *whitespaceChars = [NSCharacterSet whitespaceCharacterSet];\n\t\n\t// start at the start of the selection and move backwards to the beginning of the line\n\tNSUInteger lineStart = selectionStart;\n\t\n\twhile (lineStart > 0)\n\t{\n\t\tunichar ch = [textString characterAtIndex:lineStart - 1];\n\t\t\n\t\tif ([newlineChars characterIsMember:ch])\n\t\t\tbreak;\n\t\t\n\t\t--lineStart;\n\t}\n\t\n\t// now we're either at the beginning of the content, or the beginning of the line; now find the end of the whitespace there, up to where we started\n\tNSUInteger whitespaceEnd = lineStart;\n\t\n\twhile (whitespaceEnd < selectionStart)\n\t{\n\t\tunichar ch = [textString characterAtIndex:whitespaceEnd];\n\t\t\n\t\tif (![whitespaceChars characterIsMember:ch])\n\t\t\tbreak;\n\t\t\n\t\t++whitespaceEnd;\n\t}\n\t\n\t// now we have the range of the leading whitespace; copy that, call super to insert the newline, and then paste in the whitespace\n\tNSRange whitespaceRange = NSMakeRange(lineStart, whitespaceEnd - lineStart);\n\tNSString *whitespaceString = [textString substringWithRange:whitespaceRange];\n\t\n\t// We use the insert... methods, which handle change notifications and undo correctly\n\t[super insertNewline:sender];\n\t[self insertText:whitespaceString replacementRange:NSMakeRange(NSNotFound, NSNotFound)];\n}\n\n// handle the home and end keys; rather bizarre that Apple doesn't implement these for us, but whatever...\n// OK, Apple *does* implement these, but apparently sometimes their implementation does nothing.  I haven't figured out a reproducible case to make that\n// happen, but it does happen, and when it does, this fixes it.  Overriding these methods seems quite harmless, so I'll leave this code in here.\n- (void)scrollToBeginningOfDocument:(id)sender\n{\n\t[self scrollRangeToVisible:NSMakeRange(0, 0)];\n}\n- (void)scrollToEndOfDocument:(id)sender\n{\n\t[self scrollRangeToVisible:NSMakeRange([[self string] length], 0)];\n}\n\n// NSTextView copies only plain text for us, because it is set to have rich text turned off.  That setting only means it is turned off for the user; the\n// user can't change the font, size, etc.  But we still can, and do, programatically do our syntax formatting.  We want that style information to get\n// copied to the pasteboard.  This has gotten even trickier now that our syntax coloring is done with temporary attributes; we need to translate those\n// into real attributes here.\n- (NSMutableAttributedString *)eidosAttrStringForSelectedRange\n{\n\tNSAttributedString *attrString = [self textStorage];\n\tNSRange selectedRange = [self selectedRange];\n\tNSMutableAttributedString *attrStringInRange = [[[attrString attributedSubstringFromRange:selectedRange] mutableCopy] autorelease];\n\t\n\t// Loop over the temporary color attributes and set them on the attributed string as real attributes\n\tNSLayoutManager *lm = [self layoutManager];\n\tNSRange effectiveRange = NSMakeRange(0, 0);\n\tNSUInteger charIndex = selectedRange.location;\n\t\n\twhile (charIndex < selectedRange.location + selectedRange.length)\n\t{\n\t\tNSColor *color = [lm temporaryAttribute:NSForegroundColorAttributeName atCharacterIndex:charIndex longestEffectiveRange:&effectiveRange inRange:selectedRange];\n\t\t\n\t\tif (color)\n\t\t\t[attrStringInRange addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(effectiveRange.location - selectedRange.location, effectiveRange.length)];\n\t\t\n\t\tcharIndex = effectiveRange.location + effectiveRange.length;\n\t}\n\t\n\treturn attrStringInRange;\n}\n\n- (IBAction)copy:(id)sender\n{\n\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\tNSAttributedString *attrStringInRange = [self eidosAttrStringForSelectedRange];\n\t\n\t// The documentation sucks, but as far as I can tell, this puts both a plain-text and a rich-text representation on the pasteboard\n\t[pasteboard clearContents];\n\t[pasteboard writeObjects:@[attrStringInRange]];\n}\n\n- (IBAction)copyAsParagraph:(id)sender\n{\n\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\tNSMutableAttributedString *attrStringInRange = [self eidosAttrStringForSelectedRange];\n\tNSString *originalString = [attrStringInRange string];\n\tunichar lineBreakChar = NSLineSeparatorCharacter;\n\tNSString *lineSeparator = [NSString stringWithCharacters:&lineBreakChar length:1];\n\t\n\t// Replace new paragraphs (\\n) with linebreaks (NSLineSeparatorCharacter) except at the very end (thus -2)\n\t// We do this by very dumb brute force, for now; doesn't matter\n\tfor (int i = (int)[attrStringInRange length] - 2; i >= 0; --i)\n\t{\n\t\tunichar ch = [originalString characterAtIndex:i];\n\t\t\n\t\tif (ch == '\\n')\n\t\t\t[attrStringInRange replaceCharactersInRange:NSMakeRange(i, 1) withString:lineSeparator];\n\t}\n\t\n\t// The documentation sucks, but as far as I can tell, this puts both a plain-text and a rich-text representation on the pasteboard\n\t[pasteboard clearContents];\n\t[pasteboard writeObjects:@[attrStringInRange]];\n}\n\n- (IBAction)paste:(id)sender\n{\n\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\tNSString *pbString = nil;\n\t\n\tif ([pasteboard canReadObjectForClasses:@[[NSString class]] options:nil])\n\t\tpbString = [[pasteboard readObjectsForClasses:@[[NSString class]] options:nil] objectAtIndex:0];\n\telse if ([pasteboard canReadObjectForClasses:@[[NSAttributedString class]] options:nil])\n\t\tpbString = [(NSAttributedString *)[[pasteboard readObjectsForClasses:@[[NSAttributedString class]] options:nil] objectAtIndex:0] string];\n\t\n\tif (pbString)\n\t{\n\t\t// This is the point of this override: to standardize the line endings present\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\n\\r\" withString:@\"\\n\"];\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\r\\n\" withString:@\"\\n\"];\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\r\" withString:@\"\\n\"];\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U00002028\" withString:@\"\\n\"];\t// NSLineSeparatorCharacter\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U00002029\" withString:@\"\\n\"];\t// NSParagraphSeparatorCharacter\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U000000A0\" withString:@\" \"];\t// Unicode \"no-break space\"\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U0000202F\" withString:@\" \"];\t// Unicode \"narrow no-break space\"\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U00002009\" withString:@\" \"];\t// Unicode \"thin space\"\n\t\tpbString = [pbString stringByReplacingOccurrencesOfString:@\"\\U00002007\" withString:@\" \"];\t// Unicode \"figure space\"\n\t\t\n\t\t[self insertText:pbString replacementRange:[self selectedRange]];\n\t}\n\telse\n\t\t[super paste:sender];\n}\n\n- (IBAction)pasteAsRichText:(id)sender\n{\n\t[self paste:sender];\n}\n\n- (IBAction)pasteAsPlainText:(id)sender\n{\n\t[self paste:sender];\n}\n\t\n- (void)undoRedoSelectionRange:(NSRange)range\n{\n\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:range];\n\t\n\t[self setSelectedRange: range];\n}\n\n- (IBAction)shiftSelectionLeft:(id)sender\n{\n\tif ([self isEditable])\n\t{\n\t\tNSTextStorage *ts = [self textStorage];\n\t\tNSMutableString *scriptString = [[self string] mutableCopy];\n\t\tNSUInteger scriptLength = [scriptString length];\n\t\tNSRange selectedRange = [self selectedRange];\n\t\tNSCharacterSet *newlineChars = [NSCharacterSet newlineCharacterSet];\n\t\tNSUInteger scanPosition;\n\t\t\n\t\t// start at the start of the selection and scan backwards over non-newline text until we hit a newline or the start of the file\n\t\tscanPosition = selectedRange.location;\n\t\t\n\t\twhile (scanPosition > 0)\n\t\t{\n\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition - 1]])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--scanPosition;\n\t\t}\n\t\t\n\t\t// we want to recolor only once, at the end of the whole operation\n\t\t[self setShouldRecolorAfterChanges:NO];\n\t\t\n\t\t// save the current selection so undo restores it\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t\n\t\t// ok, we're at the start of the line that the selection starts on; start removing tabs\n\t\t[ts beginEditing];\n\t\t\n\t\twhile ((scanPosition == selectedRange.location) || (scanPosition < selectedRange.location + selectedRange.length))\n\t\t{\n\t\t\t// if we are at the very end of the script string, then we have hit the end and we're done\n\t\t\tif (scanPosition == scriptLength)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// insert a tab at the start of this line and adjust our selection\n\t\t\tif ([scriptString characterAtIndex:scanPosition] == '\\t')\n\t\t\t{\n\t\t\t\tNSRange changeRange = NSMakeRange(scanPosition, 1);\n\t\t\t\t\n\t\t\t\tif ([self shouldChangeTextInRange:changeRange replacementString:@\"\"])\n\t\t\t\t{\n\t\t\t\t\t[ts replaceCharactersInRange:changeRange withString:@\"\"];\n\t\t\t\t\t[self didChangeText];\n\t\t\t\t\t\n\t\t\t\t\t[scriptString replaceCharactersInRange:changeRange withString:@\"\"];\n\t\t\t\t\tscriptLength--;\n\t\t\t\t\t\n\t\t\t\t\tif (scanPosition < selectedRange.location)\n\t\t\t\t\t\tselectedRange.location--;\n\t\t\t\t\telse\n\t\t\t\t\t\tif (selectedRange.length > 0)\n\t\t\t\t\t\t\tselectedRange.length--;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// now scan forward to the end of this line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// and then scan forward to the beginning of the next line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif (![newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t}\n\t\t\n\t\t[scriptString release];\n\t\t[ts endEditing];\n\t\t\n\t\t// set the new selection in a way that will work with redo\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t[self setSelectedRange:selectedRange];\n\t\t\n\t\t// recolor, coalesced\n\t\t[self setShouldRecolorAfterChanges:YES];\n\t\t[self recolorAfterChanges];\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (IBAction)shiftSelectionRight:(id)sender\n{\n\tif ([self isEditable])\n\t{\n\t\tNSTextStorage *ts = [self textStorage];\n\t\tNSMutableString *scriptString = [[self string] mutableCopy];\n\t\tNSUInteger scriptLength = [scriptString length];\n\t\tNSRange selectedRange = [self selectedRange];\n\t\tNSCharacterSet *newlineChars = [NSCharacterSet newlineCharacterSet];\n\t\tNSUInteger scanPosition;\n\t\t\n\t\t// start at the start of the selection and scan backwards over non-newline text until we hit a newline or the start of the file\n\t\tscanPosition = selectedRange.location;\n\t\t\n\t\twhile (scanPosition > 0)\n\t\t{\n\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition - 1]])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--scanPosition;\n\t\t}\n\t\t\n\t\t// we want to recolor only once, at the end of the whole operation\n\t\t[self setShouldRecolorAfterChanges:NO];\n\t\t\n\t\t// save the current selection so undo restores it\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t\n\t\t// ok, we're at the start of the line that the selection starts on; start inserting tabs\n\t\t[ts beginEditing];\n\t\t\n\t\twhile ((scanPosition == selectedRange.location) || (scanPosition < selectedRange.location + selectedRange.length))\n\t\t{\n\t\t\t// insert a tab at the start of this line and adjust our selection\n\t\t\tNSRange changeRange = NSMakeRange(scanPosition, 0);\n\t\t\t\n\t\t\tif ([self shouldChangeTextInRange:changeRange replacementString:@\"\\t\"])\n\t\t\t{\n\t\t\t\t[ts replaceCharactersInRange:changeRange withString:@\"\\t\"];\n\t\t\t\t[self didChangeText];\n\t\t\t\t\n\t\t\t\t[scriptString replaceCharactersInRange:changeRange withString:@\"\\t\"];\n\t\t\t\tscriptLength++;\n\t\t\t\t\n\t\t\t\tif ((scanPosition < selectedRange.location) || (selectedRange.length == 0))\n\t\t\t\t\tselectedRange.location++;\n\t\t\t\telse\n\t\t\t\t\tselectedRange.length++;\n\t\t\t}\n\t\t\t\n\t\t\t// now scan forward to the end of this line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// and then scan forward to the beginning of the next line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif (![newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// if we are at the very end of the script string, then we have hit the end and we're done\n\t\t\tif (scanPosition == scriptLength)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t[scriptString release];\n\t\t[ts endEditing];\n\t\t\n\t\t// set the new selection in a way that will work with redo\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t[self setSelectedRange:selectedRange];\n\t\t\n\t\t// recolor, coalesced\n\t\t[self setShouldRecolorAfterChanges:YES];\n\t\t[self recolorAfterChanges];\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (IBAction)commentUncommentSelection:(id)sender\n{\n\tif ([self isEditable])\n\t{\n\t\tNSTextStorage *ts = [self textStorage];\n\t\tNSMutableString *scriptString = [[self string] mutableCopy];\n\t\tNSUInteger scriptLength = [scriptString length];\n\t\tNSRange selectedRange = [self selectedRange];\n\t\tNSCharacterSet *newlineChars = [NSCharacterSet newlineCharacterSet];\n\t\tNSUInteger scanPosition;\n\t\t\n\t\t// start at the start of the selection and scan backwards over non-newline text until we hit a newline or the start of the file\n\t\tscanPosition = selectedRange.location;\n\t\t\n\t\twhile (scanPosition > 0)\n\t\t{\n\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition - 1]])\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--scanPosition;\n\t\t}\n\t\t\n\t\t// decide whether we are commenting or uncommenting; we are only uncommenting if every line spanned by the selection starts with \"//\"\n\t\tBOOL uncommenting = YES;\n\t\tNSUInteger scanPositionSave = scanPosition;\n\t\t\n\t\twhile ((scanPosition == selectedRange.location) || (scanPosition < selectedRange.location + selectedRange.length))\n\t\t{\n\t\t\t// comment/uncomment at the start of this line and adjust our selection\n\t\t\tif ((scanPosition + 1 >= scriptLength) || ([scriptString characterAtIndex:scanPosition] != '/') || ([scriptString characterAtIndex:scanPosition + 1] != '/'))\n\t\t\t{\n\t\t\t\tuncommenting = NO;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// now scan forward to the end of this line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// and then scan forward to the beginning of the next line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif (![newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// if we are at the very end of the script string, then we have hit the end and we're done\n\t\t\tif (scanPosition == scriptLength)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tscanPosition = scanPositionSave;\n\t\t\n\t\t// we want to recolor only once, at the end of the whole operation\n\t\t[self setShouldRecolorAfterChanges:NO];\n\t\t\n\t\t// save the current selection so undo restores it\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t\n\t\t// ok, we're at the start of the line that the selection starts on; start commenting / uncommenting\n\t\t[ts beginEditing];\n\t\t\n\t\twhile ((scanPosition == selectedRange.location) || (scanPosition < selectedRange.location + selectedRange.length))\n\t\t{\n\t\t\t// if we are at the very end of the script string, then we have hit the end and we're done\n\t\t\tif (uncommenting && (scanPosition == scriptLength))\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// comment/uncomment at the start of this line and adjust our selection\n\t\t\tif (uncommenting)\n\t\t\t{\n\t\t\t\tNSRange changeRange = NSMakeRange(scanPosition, 2);\n\t\t\t\t\n\t\t\t\tif ([self shouldChangeTextInRange:changeRange replacementString:@\"\"])\n\t\t\t\t{\n\t\t\t\t\t[ts replaceCharactersInRange:changeRange withString:@\"\"];\n\t\t\t\t\t[self didChangeText];\n\t\t\t\t\t\n\t\t\t\t\t[scriptString replaceCharactersInRange:changeRange withString:@\"\"];\n\t\t\t\t\tscriptLength -= 2;\n\t\t\t\t\t\n\t\t\t\t\tif (scanPosition < selectedRange.location)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (scanPosition == selectedRange.location - 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tselectedRange.location--;\n\t\t\t\t\t\t\tif (selectedRange.length > 0)\n\t\t\t\t\t\t\t\tselectedRange.length--;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tselectedRange.location -= 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (selectedRange.length > 2)\n\t\t\t\t\t\t\tselectedRange.length -= 2;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tselectedRange.length = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tNSRange changeRange = NSMakeRange(scanPosition, 0);\n\t\t\t\t\n\t\t\t\tif ([self shouldChangeTextInRange:changeRange replacementString:@\"//\"])\n\t\t\t\t{\n\t\t\t\t\t[ts replaceCharactersInRange:changeRange withString:@\"//\"];\n\t\t\t\t\t//[ts setAttributes:[NSDictionary eidosTextAttributesWithColor:[NSColor blackColor]] range:NSMakeRange(scanPosition, 2)];\n\t\t\t\t\t[self didChangeText];\n\t\t\t\t\t\n\t\t\t\t\t[scriptString replaceCharactersInRange:changeRange withString:@\"//\"];\n\t\t\t\t\tscriptLength += 2;\n\t\t\t\t\t\n\t\t\t\t\tif ((scanPosition < selectedRange.location) || (selectedRange.length == 0))\n\t\t\t\t\t\tselectedRange.location += 2;\n\t\t\t\t\telse\n\t\t\t\t\t\tselectedRange.length += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// now scan forward to the end of this line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif ([newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// and then scan forward to the beginning of the next line\n\t\t\twhile (scanPosition < scriptLength)\n\t\t\t{\n\t\t\t\tif (![newlineChars characterIsMember:[scriptString characterAtIndex:scanPosition]])\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++scanPosition;\n\t\t\t}\n\t\t\t\n\t\t\t// if we are at the very end of the script string, then we have hit the end and we're done\n\t\t\tif (!uncommenting && (scanPosition == scriptLength))\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t[scriptString release];\n\t\t[ts endEditing];\n\t\t\n\t\t// set the new selection in a way that will work with redo\n\t\t[[[self undoManager] prepareWithInvocationTarget:self] undoRedoSelectionRange:selectedRange];\n\t\t[self setSelectedRange:selectedRange];\n\t\t\n\t\t// recolor, coalesced\n\t\t[self setShouldRecolorAfterChanges:YES];\n\t\t[self recolorAfterChanges];\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\t// Mimic the way copy: enables, for consistency; enabled only when the selection is not zero-length\n\tif (sel == @selector(copyAsParagraph:))\n\t\treturn ([self selectedRange].length > 0);\n\t\n\treturn [super validateMenuItem:menuItem];\n}\n\n- (void)selectErrorRange\n{\n\t// If there is error-tracking information set, and the error is attributed to the user script,\n\t// then we can highlight the error range\n\tif ((!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == 0)) &&\n\t\t(gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 >= 0) &&\n\t\t(gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 >= gEidosErrorContext.errorPosition.characterStartOfErrorUTF16))\n\t{\n\t\tNSRange charRange = NSMakeRange(gEidosErrorContext.errorPosition.characterStartOfErrorUTF16, gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 - gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 + 1);\n\t\t\n\t\t[self setSelectedRange:charRange];\n\t\t[self scrollRangeToVisible:charRange];\n\t\t\n\t\t// Set the selection color to red for maximal visibility; this gets set back in setSelectedRanges:affinity:stillSelecting:\n\t\t[self setSelectedTextAttributes:@{NSBackgroundColorAttributeName:[NSColor redColor], NSForegroundColorAttributeName:[NSColor whiteColor]}];\n\t}\n\t\n\t// In any case, since we are the ultimate consumer of the error information, we should clear out\n\t// the error state to avoid misattribution of future errors\n\tClearErrorContext();\n}\n\n- (void)setSelectedRanges:(NSArray *)ranges affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag\n{\n\t// The text selection color may have been changed by -selectErrorRange; here we just make sure it is set back again\n\t[self setSelectedTextAttributes:@{NSBackgroundColorAttributeName:[NSColor selectedTextBackgroundColor]}];\n\t\n\t[super setSelectedRanges:ranges affinity:affinity stillSelecting:stillSelectingFlag];\n}\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\tNSUInteger modifiers = [theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;\t\t// BCH 4/7/2016: NSEventModifierFlags not defined in 10.9\n\t\n\t// If the control key is down, the click will be interpreted by super as a context-menu click even with option down, so we can let that through.\n\t// Otherwise, option-clicks produce discontiguous selections that we want to prevent since we are not prepared to deal with them.  Instead, we\n\t// use option-clicks to indicate that the word clicked on should be looked up in EidosHelpController.\n\tif ((modifiers & NSEventModifierFlagOption) && !(modifiers & NSEventModifierFlagControl))\n\t{\n\t\tNSPoint windowPoint = [theEvent locationInWindow];\n\t\tNSRect windowRect = NSMakeRect(windowPoint.x, windowPoint.y, 0, 0);\n\t\tNSRect screenRect = [[self window] convertRectToScreen:windowRect];\t// why is convertBaseToScreen: deprecated??\n\t\tNSPoint screenPoint = screenRect.origin;\n\t\tNSUInteger charIndex = [self characterIndexForPoint:screenPoint];\t// takes a point in screen coordinates, for some weird reason\n\t\t\n\t\tif (charIndex < [[self textStorage] length])\n\t\t{\n\t\t\tNSRange wordRange = [self selectionRangeForProposedRange:NSMakeRange(charIndex, 1) granularity:NSSelectByWord];\n\t\t\tNSString *word = [[self string] substringWithRange:wordRange];\n\t\t\tNSString *trimmedWord = [word stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n\t\t\t\n\t\t\t// A few substitutions to improve the search\n\t\t\tif ([trimmedWord isEqualToString:@\":\"])\t\t\ttrimmedWord = @\"operator :\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"(\"])\ttrimmedWord = @\"operator ()\";\n\t\t\telse if ([trimmedWord isEqualToString:@\")\"])\ttrimmedWord = @\"operator ()\";\n\t\t\telse if ([trimmedWord isEqualToString:@\",\"])\ttrimmedWord = @\"calls: operator ()\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"[\"])\ttrimmedWord = @\"operator []\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"]\"])\ttrimmedWord = @\"operator []\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"{\"])\ttrimmedWord = @\"compound statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"}\"])\ttrimmedWord = @\"compound statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\".\"])\ttrimmedWord = @\"operator .\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"=\"])\ttrimmedWord = @\"operator =\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"+\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"-\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"*\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"/\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"%\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"^\"])\ttrimmedWord = @\"Arithmetic operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"|\"])\ttrimmedWord = @\"Logical operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"&\"])\ttrimmedWord = @\"Logical operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"!\"])\ttrimmedWord = @\"Logical operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"==\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"!=\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"<=\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\">=\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"<\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\">\"])\ttrimmedWord = @\"Comparative operators\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"'\"])\ttrimmedWord = @\"type string\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"\\\"\"])\ttrimmedWord = @\"type string\";\n\t\t\telse if ([trimmedWord isEqualToString:@\";\"])\ttrimmedWord = @\"null statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"//\"])\ttrimmedWord = @\"comments\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"if\"])\ttrimmedWord = @\"if and if–else statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"else\"])\ttrimmedWord = @\"if and if–else statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"for\"])\ttrimmedWord = @\"for statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"in\"])\ttrimmedWord = @\"for statements\";\n\t\t\telse if ([trimmedWord isEqualToString:@\"function\"])\ttrimmedWord = @\"user-defined functions\";\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Give the delegate a chance to supply additional help-text substitutions\n\t\t\t\tid delegate = [self delegate];\n\t\t\t\t\n\t\t\t\tif ([delegate respondsToSelector:@selector(eidosTextView:helpTextForClickedText:)])\n\t\t\t\t{\n\t\t\t\t\tNSString *delegateResult = [delegate eidosTextView:self helpTextForClickedText:trimmedWord];\n\t\t\t\t\t\n\t\t\t\t\t// The delegate may return nil or @\"\" to indicate no substitution desired\n\t\t\t\t\tif ([delegateResult length])\n\t\t\t\t\t\ttrimmedWord = delegateResult;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// And then look up the hit using EidosHelpController\n\t\t\tif ([trimmedWord length] != 0)\n\t\t\t{\n\t\t\t\t[self setSelectedRange:wordRange];\n\t\t\t\t\n\t\t\t\tEidosHelpController *helpController = [EidosHelpController sharedController];\n\t\t\t\t\n\t\t\t\t[helpController enterSearchForString:trimmedWord titlesOnly:YES];\n\t\t\t\t[[helpController window] makeKeyAndOrderFront:self];\n\t\t\t}\n\t\t}\n\t\t\n\t\t// We need this to keep the help controller window in front after an option-click, otherwise AppKit forces us back on top again\n\t\t[NSApp preventWindowOrdering];\n\t\treturn;\n\t}\n\t\n\t// Start out willing to work with a double-click for purposes of delimiter-balancing;\n\t// see selectionRangeForProposedRange:proposedCharRange granularity: below\n\tinEligibleDoubleClick = YES;\n\t\n\t[super mouseDown:theEvent];\n}\n\n- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent\n{\n\tNSUInteger modifiers = [theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;\t\t// BCH 4/7/2016: NSEventModifierFlags not defined in 10.9\n\t\n\t// We need this to keep the help controller window in front after an option-click, otherwise AppKit forces us back on top again\n\tif ((modifiers & NSEventModifierFlagOption) && !(modifiers & NSEventModifierFlagControl))\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent\n{\n\tNSUInteger modifiers = [theEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;\t\t// BCH 4/7/2016: NSEventModifierFlags not defined in 10.9\n\t\n\t// We need this to keep the help controller window in front after an option-click, otherwise AppKit forces us back on top again\n\tif ((modifiers & NSEventModifierFlagOption) && !(modifiers & NSEventModifierFlagControl))\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (NSRange)selectionRangeForProposedRange:(NSRange)proposedCharRange granularity:(NSSelectionGranularity)granularity\n{\n\tif ((granularity == NSSelectByWord) && inEligibleDoubleClick)\n\t{\n\t\t// The proposed range has to be zero-length, otherwise this click sequence is ineligible\n\t\tif (proposedCharRange.length == 0)\n\t\t{\n\t\t\tNSEvent *event = [NSApp currentEvent];\n\t\t\tNSEventType eventType = [event type];\n\t\t\tNSTimeInterval eventTime = [event timestamp];\n\t\t\t\n\t\t\tif (eventType == NSEventTypeLeftMouseDown)\n\t\t\t{\n\t\t\t\t// This is the mouseDown of the double-click; we do not want to modify the selection here, just log the time\n\t\t\t\tdoubleDownTime = eventTime;\n\t\t\t}\n\t\t\telse if (eventType == NSEventTypeLeftMouseUp)\n\t\t\t{\n\t\t\t\t// After the double-click interval since the second mouseDown, the mouseUp is no longer eligible\n\t\t\t\tif (eventTime - doubleDownTime <= [NSEvent doubleClickInterval])\n\t\t\t\t{\n\t\t\t\t\t// MAINTENANCE NOTE: This also exists, in slightly altered form, in insertText:replacementRange:, so please maintain the two in parallel!\n\t\t\t\t\tNSString *scriptString = [[self textStorage] string];\n\t\t\t\t\tint stringLength = (int)[scriptString length];\n\t\t\t\t\tint proposedCharacterIndex = (int)proposedCharRange.location;\n\t\t\t\t\tunichar uch = [scriptString characterAtIndex:proposedCharacterIndex];\n\t\t\t\t\tBOOL forward = false;\n\t\t\t\t\tunichar incrementChar = ' ';\n\t\t\t\t\tunichar decrementChar = ' ';\n\t\t\t\t\tEidosTokenType token1 = EidosTokenType::kTokenNone;\n\t\t\t\t\tEidosTokenType token2 = EidosTokenType::kTokenNone;\n\t\t\t\t\t\n\t\t\t\t\t// Check for any of the delimiter types we support, and set up to do a scan\n\t\t\t\t\tif (uch == '{')\t\t{ forward = true; incrementChar = '{'; decrementChar = '}'; token1 = EidosTokenType::kTokenLBrace; token2 = EidosTokenType::kTokenRBrace; }\n\t\t\t\t\tif (uch == '}')\t\t{ forward = false; incrementChar = '}'; decrementChar = '{'; token1 = EidosTokenType::kTokenLBrace; token2 = EidosTokenType::kTokenRBrace; }\n\t\t\t\t\tif (uch == '(')\t\t{ forward = true; incrementChar = '('; decrementChar = ')'; token1 = EidosTokenType::kTokenLParen; token2 = EidosTokenType::kTokenRParen; }\n\t\t\t\t\tif (uch == ')')\t\t{ forward = false; incrementChar = ')'; decrementChar = '('; token1 = EidosTokenType::kTokenLParen; token2 = EidosTokenType::kTokenRParen; }\n\t\t\t\t\tif (uch == '[')\t\t{ forward = true; incrementChar = '['; decrementChar = ']'; token1 = EidosTokenType::kTokenLBracket; token2 = EidosTokenType::kTokenRBracket; }\n\t\t\t\t\tif (uch == ']')\t\t{ forward = false; incrementChar = ']'; decrementChar = '['; token1 = EidosTokenType::kTokenLBracket; token2 = EidosTokenType::kTokenRBracket; }\n\t\t\t\t\t\n\t\t\t\t\tif (token1 != EidosTokenType::kTokenNone)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We've got a double-click on a character that we want to balance-select.  This is complicated mostly\n\t\t\t\t\t\t// because of strings, which are a pain in the butt.  To simplify that issue, we tokenize and search\n\t\t\t\t\t\t// in the token stream parallel to searching in the text.\n\t\t\t\t\t\tstd::string script_string([scriptString UTF8String]);\n\t\t\t\t\t\tEidosScript script(script_string);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Tokenize\n\t\t\t\t\t\tscript.Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Find the token containing the double-click point\n\t\t\t\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\t\t\t\tint token_count = (int)tokens.size();\n\t\t\t\t\t\tconst EidosToken *click_token = nullptr;\n\t\t\t\t\t\tint click_token_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (click_token_index = 0; click_token_index < token_count; ++click_token_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tclick_token = &tokens[click_token_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((click_token->token_UTF16_start_ <= proposedCharacterIndex) && (click_token->token_UTF16_end_ >= proposedCharacterIndex))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (click_token)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// OK, this token contains the character that was double-clicked.  We could have the actual token\n\t\t\t\t\t\t\t// (incrementToken), we could be in a string, or we could be in a comment.  We stay in the domain\n\t\t\t\t\t\t\t// that we start in; if in a string, for example, only delimiters within strings affect our scan.\n\t\t\t\t\t\t\tEidosTokenType click_token_type = click_token->token_type_;\n\t\t\t\t\t\t\tconst EidosToken *scan_token = click_token;\n\t\t\t\t\t\t\tint scan_token_index = click_token_index;\n\t\t\t\t\t\t\tNSInteger scanPosition = proposedCharacterIndex;\n\t\t\t\t\t\t\tint balanceCount = 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\twhile (YES)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosTokenType scan_token_type = scan_token->token_type_;\n\t\t\t\t\t\t\t\tBOOL isCandidate;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (click_token_type == EidosTokenType::kTokenComment)\n\t\t\t\t\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenComment);\n\t\t\t\t\t\t\t\telse if (click_token_type == EidosTokenType::kTokenCommentLong)\n\t\t\t\t\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenCommentLong);\n\t\t\t\t\t\t\t\telse if (click_token_type == EidosTokenType::kTokenString)\n\t\t\t\t\t\t\t\t\tisCandidate = (scan_token_type == EidosTokenType::kTokenString);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tisCandidate = ((scan_token_type == token1) || (scan_token_type == token2));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (isCandidate)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuch = [scriptString characterAtIndex:scanPosition];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (uch == incrementChar)\n\t\t\t\t\t\t\t\t\t\tbalanceCount++;\n\t\t\t\t\t\t\t\t\telse if (uch == decrementChar)\n\t\t\t\t\t\t\t\t\t\tbalanceCount--;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// If balanceCount is now zero, all opens have been balanced by closes, and we have found our matching delimiter\n\t\t\t\t\t\t\t\t\tif (balanceCount == 0)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tinEligibleDoubleClick = false;\t// clear this to avoid potential confusion if we get called again later\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (forward)\n\t\t\t\t\t\t\t\t\t\t\treturn NSMakeRange(proposedCharacterIndex, scanPosition - proposedCharacterIndex + 1);\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\treturn NSMakeRange(scanPosition, proposedCharacterIndex - scanPosition + 1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Advance, forward or backward, to the next character; if we reached the end without balancing, beep\n\t\t\t\t\t\t\t\tscanPosition += (forward ? 1 : -1);\n\t\t\t\t\t\t\t\tif ((scanPosition == stringLength) || (scanPosition == -1))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tNSBeep();\n\t\t\t\t\t\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t\t\t\t\t\t\treturn NSMakeRange(proposedCharacterIndex, 1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Make sure we're in the right token\n\t\t\t\t\t\t\t\twhile ((scan_token->token_UTF16_start_ > scanPosition) || (scan_token->token_UTF16_end_ < scanPosition))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tscan_token_index += (forward ? 1 : -1);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif ((scan_token_index < 0) || (scan_token_index == token_count))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tNSLog(@\"ran out of tokens!\");\n\t\t\t\t\t\t\t\t\t\tNSBeep();\n\t\t\t\t\t\t\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t\t\t\t\t\t\t\treturn NSMakeRange(proposedCharacterIndex, 1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tscan_token = &tokens[scan_token_index];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tinEligibleDoubleClick = false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tinEligibleDoubleClick = false;\n\t\t}\n\t}\n\t\n\treturn [super selectionRangeForProposedRange:proposedCharRange granularity:granularity];\n}\n\n\n//\n//\tSyntax coloring\n//\n#pragma mark -\n#pragma mark Syntax coloring\n\n- (void)syntaxColorForEidos\n{\n\tid delegate = [self delegate];\n\t\n\t// Construct a Script object from the current script string\n\tNSString *scriptString = [self string];\n\tstd::string script_string([scriptString UTF8String]);\n\tEidosScript script(script_string);\n\t\n\t// Tokenize\n\tscript.Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n\t\n\t// Set up our shared colors\n\tstatic NSColor *numberLiteralColor = nil;\n\tstatic NSColor *stringLiteralColor = nil;\n\tstatic NSColor *commentColor = nil;\n\tstatic NSColor *identifierColor = nil;\n\tstatic NSColor *keywordColor = nil;\n\tstatic NSColor *contextKeywordColor = nil;\n\t\n\tif (!numberLiteralColor)\n\t{\n\t\tnumberLiteralColor = [[NSColor colorWithCalibratedRed:28/255.0 green:0/255.0 blue:207/255.0 alpha:1.0] retain];\n\t\tstringLiteralColor = [[NSColor colorWithCalibratedRed:196/255.0 green:26/255.0 blue:22/255.0 alpha:1.0] retain];\n\t\tcommentColor = [[NSColor colorWithCalibratedRed:0/255.0 green:116/255.0 blue:0/255.0 alpha:1.0] retain];\n\t\tidentifierColor = [[NSColor colorWithCalibratedRed:63/255.0 green:110/255.0 blue:116/255.0 alpha:1.0] retain];\n\t\tkeywordColor = [[NSColor colorWithCalibratedRed:170/255.0 green:13/255.0 blue:145/255.0 alpha:1.0] retain];\n\t\tcontextKeywordColor = [[NSColor colorWithCalibratedRed:80/255.0 green:13/255.0 blue:145/255.0 alpha:1.0] retain];\n\t}\n\t\n\t// Syntax color!\n\tNSRange fullRange = NSMakeRange(0, [[self textStorage] length]);\n\tNSLayoutManager *lm = [self layoutManager];\n\t\n\t[lm ensureGlyphsForCharacterRange:fullRange];\n\t[lm removeTemporaryAttribute:NSForegroundColorAttributeName forCharacterRange:fullRange];\n\t\n\tfor (const EidosToken &token : script.Tokens())\n\t{\n\t\tNSRange tokenRange = NSMakeRange(token.token_UTF16_start_, token.token_UTF16_end_ - token.token_UTF16_start_ + 1);\n\t\t\n\t\tif (token.token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:numberLiteralColor forCharacterRange:tokenRange];\n\t\tif (token.token_type_ == EidosTokenType::kTokenString)\n\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:stringLiteralColor forCharacterRange:tokenRange];\n\t\tif ((token.token_type_ == EidosTokenType::kTokenComment) || (token.token_type_ == EidosTokenType::kTokenCommentLong))\n\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:commentColor forCharacterRange:tokenRange];\n\t\tif (token.token_type_ > EidosTokenType::kFirstIdentifierLikeToken)\n\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:keywordColor forCharacterRange:tokenRange];\n\t\tif (token.token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\t// most identifiers are left as black; only special ones get colored\n\t\t\tconst std::string &token_string = token.token_string_;\n\t\t\t\n\t\t\tif ((token_string.compare(\"T\") == 0) ||\n\t\t\t\t(token_string.compare(\"F\") == 0) ||\n\t\t\t\t(token_string.compare(\"E\") == 0) ||\n\t\t\t\t(token_string.compare(\"PI\") == 0) ||\n\t\t\t\t(token_string.compare(\"INF\") == 0) ||\n\t\t\t\t(token_string.compare(\"NAN\") == 0) ||\n\t\t\t\t(token_string.compare(\"NULL\") == 0))\n\t\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:identifierColor forCharacterRange:tokenRange];\n\t\t\telse\n\t\t\t{\n\t\t\t\t// we also let the Context specify special identifiers that we will syntax color\n\t\t\t\tif ([delegate respondsToSelector:@selector(eidosTextView:tokenStringIsSpecialIdentifier:)])\n\t\t\t\t{\n\t\t\t\t\tEidosSyntaxHighlightType highlightType = [delegate eidosTextView:self tokenStringIsSpecialIdentifier:token_string];\n\t\t\t\t\t\n\t\t\t\t\tif (highlightType == EidosSyntaxHighlightType::kHighlightAsIdentifier)\n\t\t\t\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:identifierColor forCharacterRange:tokenRange];\n\t\t\t\t\telse if (highlightType == EidosSyntaxHighlightType::kHighlightAsKeyword)\n\t\t\t\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:keywordColor forCharacterRange:tokenRange];\n\t\t\t\t\telse if (highlightType == EidosSyntaxHighlightType::kHighlightAsContextKeyword)\n\t\t\t\t\t\t[lm addTemporaryAttribute:NSForegroundColorAttributeName value:contextKeywordColor forCharacterRange:tokenRange];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)syntaxColorForOutput\n{\n\tNSRange fullRange = NSMakeRange(0, [[self textStorage] length]);\n\tNSLayoutManager *lm = [self layoutManager];\n\tNSString *string = [self string];\n\tNSArray *lines = [string componentsSeparatedByString:@\"\\n\"];\n\tint lineCount = (int)[lines count];\n\tint stringPosition = 0;\n\t\n\t// Set up our shared attributes\n\tstatic NSDictionary *poundDirectiveAttrs = nil;\n\tstatic NSDictionary *commentAttrs = nil;\n\tstatic NSDictionary *subpopAttrs = nil;\n\tstatic NSDictionary *genomicElementAttrs = nil;\n\tstatic NSDictionary *mutationTypeAttrs = nil;\n\t\n\tif (!poundDirectiveAttrs)\n\t{\n\t\tpoundDirectiveAttrs = [@{NSForegroundColorAttributeName : [NSColor colorWithCalibratedRed:196/255.0 green:26/255.0 blue:22/255.0 alpha:1.0]} retain];\n\t\tcommentAttrs = [@{NSForegroundColorAttributeName : [NSColor colorWithCalibratedRed:0/255.0 green:116/255.0 blue:0/255.0 alpha:1.0]} retain];\n\t\tsubpopAttrs = [@{NSForegroundColorAttributeName : [NSColor colorWithCalibratedRed:28/255.0 green:0/255.0 blue:207/255.0 alpha:1.0]} retain];\n\t\tgenomicElementAttrs = [@{NSForegroundColorAttributeName : [NSColor colorWithCalibratedRed:63/255.0 green:110/255.0 blue:116/255.0 alpha:1.0]} retain];\n\t\tmutationTypeAttrs = [@{NSForegroundColorAttributeName : [NSColor colorWithCalibratedRed:170/255.0 green:13/255.0 blue:145/255.0 alpha:1.0]} retain];\n\t}\n\t\n\t// And then tokenize and color\n\t[lm removeTemporaryAttribute:NSForegroundColorAttributeName forCharacterRange:fullRange];\n\t\n\tfor (int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n\t{\n\t\tNSString *line = [lines objectAtIndex:lineIndex];\n\t\tNSRange lineRange = NSMakeRange(stringPosition, (int)[line length]);\n\t\tint nextStringPosition = (int)(stringPosition + lineRange.length + 1);\t\t\t// +1 for the newline\n\t\t\n\t\tif (lineRange.length)\n\t\t{\n\t\t\t//NSLog(@\"lineIndex %d, lineRange == %@\", lineIndex, NSStringFromRange(lineRange));\n\t\t\t\n\t\t\t// find comments and color and remove them\n\t\t\tNSRange commentRange = [line rangeOfString:@\"//\"];\n\t\t\t\n\t\t\tif ((commentRange.location != NSNotFound) && (commentRange.length == 2))\n\t\t\t{\n\t\t\t\tint commentLength = (int)(lineRange.length - commentRange.location);\n\t\t\t\t\n\t\t\t\t[lm addTemporaryAttributes:commentAttrs forCharacterRange:NSMakeRange(lineRange.location + commentRange.location, commentLength)];\n\t\t\t\t\n\t\t\t\tlineRange.length -= commentLength;\n\t\t\t\tline = [line substringToIndex:commentRange.location];\n\t\t\t}\n\t\t\t\n\t\t\t// if anything is left...\n\t\t\tif (lineRange.length)\n\t\t\t{\n\t\t\t\t// remove leading whitespace\n\t\t\t\tdo {\n\t\t\t\t\tNSRange leadingWhitespaceRange = [line rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet] options:NSAnchoredSearch];\n\t\t\t\t\t\n\t\t\t\t\tif (leadingWhitespaceRange.location == NSNotFound || leadingWhitespaceRange.length == 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tlineRange.location += leadingWhitespaceRange.length;\n\t\t\t\t\tlineRange.length -= leadingWhitespaceRange.length;\n\t\t\t\t\tline = [line substringFromIndex:leadingWhitespaceRange.length];\n\t\t\t\t} while (YES);\n\t\t\t\t\n\t\t\t\t// remove trailing whitespace\n\t\t\t\tdo {\n\t\t\t\t\tNSRange trailingWhitespaceRange = [line rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet] options:NSAnchoredSearch | NSBackwardsSearch];\n\t\t\t\t\t\n\t\t\t\t\tif (trailingWhitespaceRange.location == NSNotFound || trailingWhitespaceRange.length == 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tlineRange.length -= trailingWhitespaceRange.length;\n\t\t\t\t\tline = [line substringToIndex:trailingWhitespaceRange.location];\n\t\t\t\t} while (YES);\n\t\t\t\t\n\t\t\t\t// if anything is left...\n\t\t\t\tif (lineRange.length)\n\t\t\t\t{\n\t\t\t\t\t// find pound directives and color them\n\t\t\t\t\tif ([line characterAtIndex:0] == '#')\n\t\t\t\t\t\t[lm addTemporaryAttributes:poundDirectiveAttrs forCharacterRange:lineRange];\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tNSRange scanRange = NSMakeRange(0, lineRange.length);\n\t\t\t\t\t\t\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\tNSRange tokenRange = [line rangeOfString:@\"\\\\b[pgm][0-9]+\\\\b\" options:NSRegularExpressionSearch range:scanRange];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (tokenRange.location == NSNotFound || tokenRange.length == 0)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tNSString *substring = [line substringWithRange:tokenRange];\n\t\t\t\t\t\t\tNSDictionary *syntaxAttrs = nil;\n\t\t\t\t\t\t\tunichar firstChar = [substring characterAtIndex:0];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (firstChar == 'p')\n\t\t\t\t\t\t\t\tsyntaxAttrs = subpopAttrs;\n\t\t\t\t\t\t\telse if (firstChar == 'g')\n\t\t\t\t\t\t\t\tsyntaxAttrs = genomicElementAttrs;\n\t\t\t\t\t\t\telse if (firstChar == 'm')\n\t\t\t\t\t\t\t\tsyntaxAttrs = mutationTypeAttrs;\n\t\t\t\t\t\t\t// we don't presently color sX or iX in the output\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (syntaxAttrs)\n\t\t\t\t\t\t\t\t[lm addTemporaryAttributes:syntaxAttrs forCharacterRange:NSMakeRange(tokenRange.location + lineRange.location, tokenRange.length)];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tscanRange.length = (scanRange.location + scanRange.length) - (tokenRange.location + tokenRange.length);\n\t\t\t\t\t\t\tscanRange.location = (tokenRange.location + tokenRange.length);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (scanRange.length < 2)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} while (YES);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tstringPosition = nextStringPosition;\n\t}\n}\n\n- (void)clearSyntaxColoring\n{\n\tNSRange fullRange = NSMakeRange(0, [[self textStorage] length]);\n\tNSLayoutManager *lm = [self layoutManager];\n\t\n\t[lm ensureGlyphsForCharacterRange:fullRange];\n\t[lm removeTemporaryAttribute:NSForegroundColorAttributeName forCharacterRange:fullRange];\n}\n\n- (void)updateSyntaxColoring\n{\n\t// This method will clear all syntax coloring if EidosSyntaxColoringOption::NoSyntaxColoring is set, so\n\t// it should not be called on every text change, to allow the console textview to maintain its own coloring.\n\t// This does not trigger textDidChange (that is done manually), so there is no need for re-entrancy protection.\n\tswitch (_syntaxColoring)\n\t{\n\t\tcase kEidosSyntaxColoringNone:\n\t\t\t[self clearSyntaxColoring];\n\t\t\tbreak;\n\t\tcase kEidosSyntaxColoringEidos:\n\t\t\t[self syntaxColorForEidos];\n\t\t\tbreak;\n\t\tcase kEidosSyntaxColoringOutput:\n\t\t\t[self syntaxColorForOutput];\n\t\t\tbreak;\n\t}\n}\n\n- (void)setSyntaxColoring:(EidosSyntaxColoringOption)syntaxColoring\n{\n\tif (_syntaxColoring != syntaxColoring)\n\t{\n\t\t_syntaxColoring = syntaxColoring;\n\t\t\n\t\t[self updateSyntaxColoring];\n\t}\n}\n\n- (void)setDisplayFontSize:(int)fontSize\n{\n\t// This is used by SLiMgui; there is no UI exposing it in EidosScribe\n\tif (_displayFontSize != fontSize)\n\t{\n\t\t_displayFontSize = fontSize;\n\t\t\n\t\tNSFont *newFont = [NSFont fontWithName:@\"Menlo\" size:fontSize];\n\t\tNSTextStorage *ts = [self textStorage];\n\t\t\n\t\t// go through all attribute runs for NSFontAttribute and change them\n\t\t[ts beginEditing];\n\t\t\n\t\t[ts enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, ts.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {\n\t\t\tif (value) {\n\t\t\t\tNSFont *oldFont = (NSFont *)value;\n\t\t\t\tCGFloat pointSize = [oldFont pointSize];\n\t\t\t\t\n\t\t\t\tif ((pointSize >= 6.0) && (pointSize <= 100.0))\t\t// avoid resizing the padding lines in the console...\n\t\t\t\t{\n\t\t\t\t\t[ts removeAttribute:NSFontAttributeName range:range];\n\t\t\t\t\t[ts addAttribute:NSFontAttributeName value:newFont range:range];\n\t\t\t\t}\n\t\t\t}\n\t\t}];\n\t\t\n\t\t[ts endEditing];\n\t\t\n\t\t// set the typing attributes; this code just makes an assumption about the correct typing attributes\n\t\t// based on the class, probably I ought to add a new method on EidosTextView to get a typing attr dict...\n\t\tNSDictionary *textAttributes;\n\t\t\n\t\tif ([self isKindOfClass:[EidosConsoleTextView class]])\n\t\t\ttextAttributes = [NSDictionary eidosInputAttrsWithSize:[self displayFontSize]];\n\t\telse\n\t\t\ttextAttributes = [NSDictionary eidosTextAttributesWithColor:nil size:_displayFontSize];\n\t\t\n\t\t[self setTypingAttributes:textAttributes];\n\t\t\n\t\t// fix the tab stops\n\t\tNSParagraphStyle *pstyle = [textAttributes objectForKey:NSParagraphStyleAttributeName];\n\t\t\n\t\t[ts beginEditing];\n\t\t\n\t\t[ts enumerateAttribute:NSParagraphStyleAttributeName inRange:NSMakeRange(0, ts.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {\n\t\t\tif (value) {\n\t\t\t\t[ts removeAttribute:NSParagraphStyleAttributeName range:range];\n\t\t\t\t[ts addAttribute:NSParagraphStyleAttributeName value:pstyle range:range];\n\t\t\t}\n\t\t}];\n\t\t\n\t\t[ts endEditing];\n\t}\n}\n\n- (void)recolorAfterChanges\n{\n\t// We fold in syntax coloring as part of every change set.  If _syntaxColoring==NoSyntaxColoring, we don't do\n\t// anything on text changes; we only clear attributes when NoSyntaxColoring is initially set on the textview.\n\tif (_syntaxColoring != kEidosSyntaxColoringNone)\n\t\t[self updateSyntaxColoring];\n}\n\n- (void)didChangeText\n{\n\t// When we used regular attributes on the text storage for syntax coloring, this was done in\n\t// textStorageDidProcessEditing: since that is the right time to change attributes in response\n\t// to other changes.  Now that we use temporary attributes, though, we need to do it in this\n\t// method, so that the layout manager is completely synchronized with the new, changed text.\n\t[super didChangeText];\n\t\n\tif (_shouldRecolorAfterChanges)\n\t\t[self recolorAfterChanges];\n}\n\n- (void)clearHighlightMatches\n{\n\tNSRange fullRange = NSMakeRange(0, [[self textStorage] length]);\n\tNSLayoutManager *lm = [self layoutManager];\n\t\n\t[lm ensureGlyphsForCharacterRange:fullRange];\n\t[lm removeTemporaryAttribute:NSBackgroundColorAttributeName forCharacterRange:fullRange];\n}\n\n- (void)highlightMatchesForString:(NSString *)matchString\n{\n\tNSColor *highlightColor;\n\t\n\t// Get the find highlight color if available, otherwise the standard selected-text background color\n\tif (@available(macOS 10.13, *)) {\n\t\thighlightColor = [NSColor findHighlightColor];\n\t} else {\n\t\thighlightColor = [NSColor selectedControlColor];\n\t}\n\t\n\t// Highlight using the background color on all matches\n\tNSRange fullRange = NSMakeRange(0, [[self textStorage] length]);\n\tNSString *string = [[self textStorage] string];\n\tNSLayoutManager *lm = [self layoutManager];\n\t\n\t[lm ensureGlyphsForCharacterRange:fullRange];\n\t\n\t// thanks to https://stackoverflow.com/a/7033787/2752221\n\tNSRange searchRange = fullRange, foundRange;\n\t\n\twhile (searchRange.location < string.length)\n\t{\n\t\tsearchRange.length = string.length - searchRange.location;\n\t\tfoundRange = [string rangeOfString:matchString options:0 range:searchRange];\n\t\t\n\t\tif (foundRange.location != NSNotFound)\n\t\t{\n\t\t\t[lm addTemporaryAttribute:NSBackgroundColorAttributeName value:highlightColor forCharacterRange:foundRange];\n\t\t\t\n\t\t\tsearchRange.location = foundRange.location + 1;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n//\n//\tSignature display\n//\n#pragma mark -\n#pragma mark Signature display\n\n- (EidosFunctionMap *)functionMapForScriptString:(NSString *)scriptString includingOptionalFunctions:(BOOL)includingOptionalFunctions\n{\n\t// This returns a function map (owned by the caller) that reflects the best guess we can make, incorporating\n\t// any functions known to our delegate, as well as all functions we can scrape from the script string.\n\tstd::string script_string([scriptString UTF8String]);\n\tEidosScript script(script_string);\n\t\n\t// Tokenize\n\tscript.Tokenize(true, false);\t// make bad tokens as needed, don't keep nonsignificant tokens\n\t\n\treturn [self functionMapForTokenizedScript:script includingOptionalFunctions:includingOptionalFunctions];\n}\n\n- (EidosFunctionMap *)functionMapForTokenizedScript:(EidosScript &)script includingOptionalFunctions:(BOOL)includingOptionalFunctions\n{\n\t// This lower-level function takes a tokenized script object and works from there, allowing reuse of work\n\t// in the case of attributedSignatureForScriptString:...\n\tid delegate = [self delegate];\n\tEidosFunctionMap *functionMapPtr = nullptr;\n\t\n\tif ([delegate respondsToSelector:@selector(functionMapForEidosTextView:)])\n\t\tfunctionMapPtr = [delegate functionMapForEidosTextView:self];\n\t\n\tif (functionMapPtr)\n\t\tfunctionMapPtr = new EidosFunctionMap(*functionMapPtr);\n\telse\n\t\tfunctionMapPtr = new EidosFunctionMap(*EidosInterpreter::BuiltInFunctionMap());\n\t\n\t// functionMapForEidosTextView: returns the function map for the current interpreter state, and the type-interpreter\n\t// stuff we do below gives the delegate no chance to intervene (note that SLiMTypeInterpreter does not get in here,\n\t// unlike in the code completion machinery!).  But sometimes we want SLiM's zero-gen functions to be added to the map\n\t// in all cases; it would be even better to be smart the way code completion is, but that's more work than it's worth.\n\tif (includingOptionalFunctions)\n\t\tif ([delegate respondsToSelector:@selector(eidosTextView:addOptionalFunctionsToMap:)])\n\t\t\t[delegate eidosTextView:self addOptionalFunctionsToMap:functionMapPtr];\n\t\n\t// OK, now we have a starting point.  We now want to use the type-interpreter to add any functions that are declared\n\t// in the full script, so that such declarations are known to us even before they have actually been executed.\n\tEidosTypeTable typeTable;\n\tEidosCallTypeTable callTypeTable;\n\tEidosSymbolTable *symbols = gEidosConstantsSymbolTable;\n\t\n\tif ([delegate respondsToSelector:@selector(eidosTextView:symbolsFromBaseSymbols:)])\n\t\tsymbols = [delegate eidosTextView:self symbolsFromBaseSymbols:symbols];\n\t\n\tif (symbols)\n\t\tsymbols->AddSymbolsToTypeTable(&typeTable);\n\t\n\tscript.ParseInterpreterBlockToAST(true, true);\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n\t\n\tEidosTypeInterpreter typeInterpreter(script, typeTable, *functionMapPtr, callTypeTable);\n\t\n\ttypeInterpreter.TypeEvaluateInterpreterBlock();\t// result not used\n\t\n\treturn functionMapPtr;\n}\n\n- (NSAttributedString *)attributedSignatureForScriptString:(NSString *)scriptString selection:(NSRange)selection\n{\n\tif ([scriptString length])\n\t{\n\t\tstd::string script_string([scriptString UTF8String]);\n\t\tEidosScript script(script_string);\n\t\t\n\t\t// Tokenize\n\t\tscript.Tokenize(true, false);\t// make bad tokens as needed, don't keep nonsignificant tokens\n\t\t\n\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\tint tokenCount = (int)tokens.size();\n\t\t\n\t\t//NSLog(@\"script string \\\"%@\\\" contains %d tokens\", scriptString, tokenCount);\n\t\t\n\t\t// Search forward to find the token position of the start of the selection\n\t\tint selectionStart = (int)selection.location;\n\t\tint tokenIndex;\n\t\t\n\t\tfor (tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex)\n\t\t\tif (tokens[tokenIndex].token_UTF16_start_ >= selectionStart)\n\t\t\t\tbreak;\n\t\t\n\t\t//NSLog(@\"token %d follows the selection (selectionStart == %d)\", tokenIndex, selectionStart);\n\t\t//if (tokenIndex == tokenCount)\n\t\t//\tNSLog(@\"   (end of script)\");\n\t\t//else\n\t\t//\tNSLog(@\"   token string: %s\", tokens[tokenIndex]->token_string_.c_str());\n\t\t\n\t\t// tokenIndex now has the index of the first token *after* the selection start; it can be equal to tokenCount\n\t\t// Now we want to scan backward from there, balancing parentheses and looking for the pattern \"identifier(\"\n\t\tint backscanIndex = tokenIndex - 1;\n\t\tint parenCount = 0, lowestParenCountSeen = 0;\n\t\t\n\t\twhile (backscanIndex > 0)\t// last examined position is 1, since we can't look for an identifier at 0 - 1 == -1\n\t\t{\n\t\t\tconst EidosToken &token = tokens[backscanIndex];\n\t\t\tEidosTokenType tokenType = token.token_type_;\n\t\t\t\n\t\t\tif (tokenType == EidosTokenType::kTokenLParen)\n\t\t\t{\n\t\t\t\t--parenCount;\n\t\t\t\t\n\t\t\t\tif (parenCount < lowestParenCountSeen)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &previousToken = tokens[backscanIndex - 1];\n\t\t\t\t\tEidosTokenType previousTokenType = previousToken.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (previousTokenType == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// OK, we found the pattern \"identifier(\"; extract the name of the function/method\n\t\t\t\t\t\t// We also figure out here whether it is a method call (tokens like \".identifier(\") or not\n\t\t\t\t\t\tNSString *callName = [NSString stringWithUTF8String:previousToken.token_string_.c_str()];\n\t\t\t\t\t\tNSAttributedString *callAttrString = nil;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((backscanIndex > 1) && (tokens[backscanIndex - 2].token_type_ == EidosTokenType::kTokenDot))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This is a method call, so look up its signature that way\n\t\t\t\t\t\t\tcallAttrString = [self attributedSignatureForMethodName:callName];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If this is a function declaration like \"function(...)identifier(\" then show no signature; it's not a function call\n\t\t\t\t\t\t\t// Determining this requires a fairly complex backscan, because we also have things like \"if (...) identifier(\" which\n\t\t\t\t\t\t\t// are function calls.  This is the price we pay for working at the token level rather than the AST level for this;\n\t\t\t\t\t\t\t// so it goes.  Note that this backscan is separate from the one done outside this block.  BCH 1 March 2018.\n\t\t\t\t\t\t\tif ((backscanIndex > 1) && (tokens[backscanIndex - 2].token_type_ == EidosTokenType::kTokenRParen))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Start a new backscan starting at the right paren preceding the identifier; we need to scan back to the balancing\n\t\t\t\t\t\t\t\t// left paren, and then see if the next thing before that is \"function\" or not.\n\t\t\t\t\t\t\t\tint funcCheckIndex = backscanIndex - 2;\n\t\t\t\t\t\t\t\tint funcCheckParens = 0;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twhile (funcCheckIndex >= 0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst EidosToken &backscanToken = tokens[funcCheckIndex];\n\t\t\t\t\t\t\t\t\tEidosTokenType backscanTokenType = backscanToken.token_type_;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (backscanTokenType == EidosTokenType::kTokenRParen)\n\t\t\t\t\t\t\t\t\t\tfuncCheckParens++;\n\t\t\t\t\t\t\t\t\telse if (backscanTokenType == EidosTokenType::kTokenLParen)\n\t\t\t\t\t\t\t\t\t\tfuncCheckParens--;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t--funcCheckIndex;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (funcCheckParens == 0)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((funcCheckParens == 0) && (funcCheckIndex >= 0) && (tokens[funcCheckIndex].token_type_ == EidosTokenType::kTokenFunction))\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// This is a function call, so look up its signature that way, using our best-guess function map\n\t\t\t\t\t\t\tEidosFunctionMap *functionMapPtr = [self functionMapForTokenizedScript:script includingOptionalFunctions:YES];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcallAttrString = [self attributedSignatureForFunctionName:callName functionMap:functionMapPtr];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdelete functionMapPtr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!callAttrString)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Assemble an attributed string for our failed lookup message\n\t\t\t\t\t\t\tNSMutableAttributedString *attrStr = [[[NSMutableAttributedString alloc] init] autorelease];\n\t\t\t\t\t\t\tNSDictionary *plainAttrs = [NSDictionary eidosOutputAttrsWithSize:_displayFontSize];\n\t\t\t\t\t\t\tNSDictionary *functionAttrs = [NSDictionary eidosParseAttrsWithSize:_displayFontSize];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:callName attributes:functionAttrs] autorelease]];\n\t\t\t\t\t\t\t[attrStr appendAttributedString:[[[NSAttributedString alloc] initWithString:@\"() – unrecognized call\" attributes:plainAttrs] autorelease]];\n\t\t\t\t\t\t\t[attrStr addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [attrStr length])];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcallAttrString = attrStr;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn callAttrString;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlowestParenCountSeen = parenCount;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tokenType == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\t++parenCount;\n\t\t\t}\n\t\t\t\n\t\t\t--backscanIndex;\n\t\t}\n\t}\n\t\n\treturn [[[NSAttributedString alloc] init] autorelease];\n}\n\n- (NSAttributedString *)attributedSignatureForFunctionName:(NSString *)callName functionMap:(EidosFunctionMap *)functionMapPtr\n{\n\tstd::string call_name([callName UTF8String]);\n\t\n\t// Look for a matching function signature for the call name.\n\tfor (const auto& function_iter : *functionMapPtr)\n\t{\n\t\tconst EidosFunctionSignature *sig = function_iter.second.get();\n\t\tconst std::string &sig_call_name = sig->call_name_;\n\t\t\n\t\tif (sig_call_name.compare(call_name) == 0)\n\t\t\treturn [NSAttributedString eidosAttributedStringForCallSignature:sig size:[self displayFontSize]];\n\t}\n\t\n\treturn nil;\n}\n\n- (NSAttributedString *)attributedSignatureForMethodName:(NSString *)callName\n{\n\tstd::string call_name([callName UTF8String]);\n\t\n\t// Look for a matching method signature for the call name.\n\tfor (const EidosMethodSignature_CSP &sig : EidosClass::RegisteredClassMethods(true, true))\n\t{\n\t\tconst std::string &sig_call_name = sig->call_name_;\n\t\t\n\t\tif (sig_call_name.compare(call_name) == 0)\n\t\t\treturn [NSAttributedString eidosAttributedStringForCallSignature:sig.get() size:[self displayFontSize]];\n\t}\n\t\n\treturn nil;\n}\n\n\n//\n//\tAuto-completion\n//\n#pragma mark -\n#pragma mark Auto-completion\n\n- (void)keyDown:(NSEvent *)event\n{\n\t// Sometimes esc and command-. do not seem to be bound to complete:.  I'm not sure if that is a change on 10.12,\n\t// or a matter of individual key bindings.  In any case, we make sure, in this override, that they always work.\n\tNSString *chars = [event charactersIgnoringModifiers];\n\tNSUInteger flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;\t\t// BCH 4/7/2016: NSEventModifierFlags not defined in 10.9\n\t\n\tif ([chars length] == 1)\n\t{\n\t\tunichar keyChar = [chars characterAtIndex:0];\n\t\t\n\t\tif ((keyChar == 0x1B) && (flags == 0))\n\t\t{\n\t\t\t// escape key pressed\n\t\t\t[self doCommandBySelector:@selector(complete:)];\n\t\t\treturn;\n\t\t}\n\t\tif ((keyChar == '.') && (flags == NSEventModifierFlagCommand))\n\t\t{\n\t\t\t// command-. pressed\n\t\t\t[self doCommandBySelector:@selector(complete:)];\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t[super keyDown:event];\n}\n\n- (void)cancel:(id)sender\n{\n\t// Apple is now sending this for esc and/or command-. in some OS X versions; we want it to continue to trigger complete:\n\t[self complete:sender];\n}\n\n- (void)cancelOperation:(id)sender\n{\n\t// Apple is now sending this for esc and/or command-. in some OS X versions; we want it to continue to trigger complete:\n\t[self complete:sender];\n}\n\n- (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index\n{\n\tNSArray *completions = nil;\n\t\n#if EIDOS_DEBUG_COMPLETION\n\tstd::cout << \"<<<<<<<<<<<<<< completionsForPartialWordRange: START\" << std::endl;\n#endif\n\t\n\t[self _completionHandlerWithRangeForCompletion:NULL completions:&completions];\n\t\n#if EIDOS_DEBUG_COMPLETION\n\tstd::cout << \"<<<<<<<<<<<<<< completionsForPartialWordRange: END\" << std::endl;\n#endif\n\t\n\treturn completions;\n}\n\n- (NSRange)rangeForUserCompletion\n{\n\tNSRange baseRange = NSMakeRange(NSNotFound, 0);\n\t\n#if EIDOS_DEBUG_COMPLETION\n\tstd::cout << \"<<<<<<<<<<<<<< rangeForUserCompletion: START\" << std::endl;\n#endif\n\t\n\t[self _completionHandlerWithRangeForCompletion:&baseRange completions:NULL];\n\t\n#if EIDOS_DEBUG_COMPLETION\n\tstd::cout << \"<<<<<<<<<<<<<< rangeForUserCompletion: END\" << std::endl;\n#endif\n\t\n\treturn baseRange;\n}\n\n- (NSMutableArray *)globalCompletionsWithTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap keywords:(NSArray *)keywords argumentNames:(NSArray *)argumentNames\n{\n\tNSMutableArray *globals = [NSMutableArray array];\n\t\n\t// First add entries for symbols in our type table (from Eidos constants, defined symbols, or our delegate)\n\tif (typeTable)\n\t{\n\t\tstd::vector<std::string> typedSymbols = typeTable->AllSymbols();\n\t\t\n\t\tfor (std::string &symbol_name : typedSymbols)\n\t\t\t[globals addObject:[NSString stringWithUTF8String:symbol_name.c_str()]];\n\t}\n\t\n\t// Sort the symbols, who knows what order they come from EidosTypeTable in...\n\t[globals sortUsingSelector:@selector(compare:)];\n\t\n\t// Next, if we have argument names that are completion matches, we want them at the top\n\tif (argumentNames && [argumentNames count])\n\t{\n\t\tNSArray *oldGlobals = globals;\n\t\t\n\t\tglobals = [[argumentNames mutableCopy] autorelease];\n\t\t[globals addObjectsFromArray:oldGlobals];\n\t}\n\t\n\t// Next, a sorted list of functions, with () appended\n\tif (functionMap)\n\t{\n\t\tfor (const auto& function_iter : *functionMap)\n\t\t{\n\t\t\tconst EidosFunctionSignature *sig = function_iter.second.get();\n\t\t\tNSString *functionName = [NSString stringWithUTF8String:sig->call_name_.c_str()];\n\t\t\t\n\t\t\t// Exclude internal functions such as _Test()\n\t\t\tif (![functionName hasPrefix:@\"_\"])\n\t\t\t\t[globals addObject:[functionName stringByAppendingString:@\"()\"]];\n\t\t}\n\t}\n\t\n\t// Finally, provide language keywords as an option if requested\n\tif (keywords)\n\t\t[globals addObjectsFromArray:keywords];\n\t\n\treturn globals;\n}\n\n- (NSMutableArray *)completionsForKeyPathEndingInTokenIndex:(int)lastDotTokenIndex ofTokenStream:(const std::vector<EidosToken> &)tokens withTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap callTypes:(EidosCallTypeTable *)callTypeTable keywords:(NSArray *)keywords\n{\n\tconst EidosToken *token = &tokens[lastDotTokenIndex];\n\tEidosTokenType token_type = token->token_type_;\n\t\n\tif (token_type != EidosTokenType::kTokenDot)\n\t{\n\t\tNSLog(@\"***** completionsForKeyPathEndingInTokenIndex... called for non-kTokenDot token!\");\n\t\treturn nil;\n\t}\n\t\n\t// OK, we've got a key path ending in a dot, and we want to return a list of completions that would work for that key path.\n\t// We'll trace backward, adding identifiers to a vector to build up the chain of references.  If we hit a bracket, we'll\n\t// skip back over everything inside it, since subsetting does not change the type; we just need to balance brackets.  If we\n\t// hit a parenthesis, we do similarly.  If we hit other things – a semicolon, a comma, a brace – that terminates the key path chain.\n\tstd::vector<std::string> identifiers;\n\tstd::vector<bool> identifiers_are_calls;\n\tstd::vector<int32_t> identifier_positions;\n\tint bracketCount = 0, parenCount = 0;\n\tBOOL lastTokenWasDot = YES, justFinishedParenBlock = NO;\n\t\n\tfor (int tokenIndex = lastDotTokenIndex - 1; tokenIndex >= 0; --tokenIndex)\n\t{\n\t\ttoken = &tokens[tokenIndex];\n\t\ttoken_type = token->token_type_;\n\t\t\n\t\t// skip backward over whitespace and comments; they make no difference to us\n\t\tif ((token_type == EidosTokenType::kTokenWhitespace) || (token_type == EidosTokenType::kTokenComment) || (token_type == EidosTokenType::kTokenCommentLong))\n\t\t\tcontinue;\n\t\t\n\t\tif (bracketCount)\n\t\t{\n\t\t\t// If we're inside a bracketed stretch, all we do is balance brackets and run backward.  We don't even clear lastTokenWasDot,\n\t\t\t// because a []. sequence puts us in the same situation as having just seen a dot – we're still waiting for an identifier.\n\t\t\tif (token_type == EidosTokenType::kTokenRBracket)\n\t\t\t{\n\t\t\t\tbracketCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (token_type == EidosTokenType::kTokenLBracket)\n\t\t\t{\n\t\t\t\tbracketCount--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check for tokens that simply make no sense, and bail\n\t\t\tif ((token_type == EidosTokenType::kTokenLBrace) || (token_type == EidosTokenType::kTokenRBrace) || (token_type == EidosTokenType::kTokenSemicolon) || (token_type >= EidosTokenType::kFirstIdentifierLikeToken))\n\t\t\t\treturn nil;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\telse if (parenCount)\n\t\t{\n\t\t\t// If we're inside a paren stretch – which could be a parenthesized expression or a function call – we do similarly\n\t\t\t// to the brackets case, just balancing parens and running backward.  We don't clear lastTokenWasDot, because a\n\t\t\t// (). sequence puts us in the same situation (almost) as having just seen a dot – waiting for an identifier.\n\t\t\tif (token_type == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\tparenCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (token_type == EidosTokenType::kTokenLParen)\n\t\t\t{\n\t\t\t\tparenCount--;\n\t\t\t\t\n\t\t\t\tif (parenCount == 0)\n\t\t\t\t\tjustFinishedParenBlock = YES;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check for tokens that simply make no sense, and bail\n\t\t\tif ((token_type == EidosTokenType::kTokenLBrace) || (token_type == EidosTokenType::kTokenRBrace) || (token_type == EidosTokenType::kTokenSemicolon) || (token_type >= EidosTokenType::kFirstIdentifierLikeToken))\n\t\t\t\treturn nil;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (!lastTokenWasDot)\n\t\t{\n\t\t\t// We just saw an identifier, so the only thing that can continue the key path is a dot\n\t\t\tif (token_type == EidosTokenType::kTokenDot)\n\t\t\t{\n\t\t\t\tlastTokenWasDot = YES;\n\t\t\t\tjustFinishedParenBlock = NO;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// the key path has terminated at some non-key-path token, so we're done tracing it\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// OK, the last token was a dot (or a subset preceding a dot).  We're looking for an identifier, but we're willing\n\t\t// to get distracted by a subset sequence, since that does not change the type.  Anything else does not make sense.\n\t\tif (token_type == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\tidentifiers.emplace_back(token->token_string_);\n\t\t\tidentifiers_are_calls.push_back(justFinishedParenBlock);\n\t\t\tidentifier_positions.emplace_back(token->token_start_);\n\t\t\t\n\t\t\t// set up to continue searching the key path backwards\n\t\t\tlastTokenWasDot = NO;\n\t\t\tjustFinishedParenBlock = NO;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (token_type == EidosTokenType::kTokenRBracket)\n\t\t{\n\t\t\tbracketCount++;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (token_type == EidosTokenType::kTokenRParen)\n\t\t{\n\t\t\tparenCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// This makes no sense, so bail\n\t\treturn nil;\n\t}\n\t\n\t// If we were in the middle of tracing the key path when the loop ended, then something is wrong, bail.\n\tif (lastTokenWasDot || bracketCount || parenCount)\n\t\treturn nil;\n\t\n\t// OK, we've got an identifier chain in identifiers, in reverse order.  We want to start at\n\t// the beginning of the key path, and figure out what the class of the key path root is\n\tint key_path_index = (int)identifiers.size() - 1;\n\tstd::string &identifier_name = identifiers[key_path_index];\n\tEidosGlobalStringID identifier_ID = EidosStringRegistry::GlobalStringIDForString(identifier_name);\n\tbool identifier_is_call = identifiers_are_calls[key_path_index];\n\tconst EidosClass *key_path_class = nullptr;\n\t\n\tif (identifier_is_call)\n\t{\n\t\t// The root identifier is a call, so it should be a function call; try to look it up\n\t\tfor (const auto& function_iter : *functionMap)\n\t\t{\n\t\t\tconst EidosFunctionSignature *sig = function_iter.second.get();\n\t\t\t\n\t\t\tif (sig->call_name_.compare(identifier_name) == 0)\n\t\t\t{\n\t\t\t\tkey_path_class = sig->return_class_;\n\t\t\t\t\n\t\t\t\t// In some cases, the function signature does not have the information we need, because the class of the return value\n\t\t\t\t// of the function depends upon its parameters.  This is the case for functions like sample(), rep(), and so forth.\n\t\t\t\t// For this case, we have a special mechanism set up, whereby the EidosTypeInterpreter has logged the class of the\n\t\t\t\t// return value of function calls that it has evaluated.  We can look up the correct class in that log.  This is kind\n\t\t\t\t// of a gross solution, but short of rewriting all the completion code, it seems to be the easiest fix.  (Rewriting\n\t\t\t\t// to fix this more properly would involve doing code completion using a type-annotated tree, without any of the\n\t\t\t\t// token-stream handling that we have now; that would be a better design, but I'm going to save that rewrite for later.)\n\t\t\t\tif (!key_path_class)\n\t\t\t\t{\n\t\t\t\t\tauto callTypeIter = callTypeTable->find(identifier_positions[key_path_index]);\n\t\t\t\t\t\n\t\t\t\t\tif (callTypeIter != callTypeTable->end())\n\t\t\t\t\t\tkey_path_class = callTypeIter->second;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse if (typeTable)\n\t{\n\t\t// The root identifier is not a call, so it should be a global symbol; try to look it up\n\t\tEidosTypeSpecifier type_specifier = typeTable->GetTypeForSymbol(identifier_ID);\n\t\t\n\t\tif (!!(type_specifier.type_mask & kEidosValueMaskObject))\n\t\t\tkey_path_class = type_specifier.object_class;\n\t}\n\t\n\tif (!key_path_class)\n\t\treturn nil;\t\t\t\t// unknown symbol at the root\n\t\n\t// Now we've got a class for the root of the key path; follow forward through the key path to arrive at the final type.\n\twhile (--key_path_index >= 0)\n\t{\n\t\tidentifier_name = identifiers[key_path_index];\n\t\tidentifier_is_call = identifiers_are_calls[key_path_index];\n\t\t\n\t\tEidosGlobalStringID identifier_id = EidosStringRegistry::GlobalStringIDForString(identifier_name);\n\t\t\n\t\tif (identifier_id == gEidosID_none)\n\t\t\treturn nil;\t\t\t// unrecognized identifier in the key path, so there is probably a typo and we can't complete off of it\n\t\t\n\t\tif (identifier_is_call)\n\t\t{\n\t\t\t// We have a method call; look up its signature and get the class\n\t\t\tconst EidosCallSignature *call_signature = key_path_class->SignatureForMethod(identifier_id);\n\t\t\t\n\t\t\tif (!call_signature)\n\t\t\t\treturn nil;\t\t\t// no signature, so the class does not support the method given\n\t\t\t\n\t\t\tkey_path_class = call_signature->return_class_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have a property; look up its signature and get the class\n\t\t\tconst EidosPropertySignature *property_signature = key_path_class->SignatureForProperty(identifier_id);\n\t\t\t\n\t\t\tif (!property_signature)\n\t\t\t\treturn nil;\t\t\t// no signature, so the class does not support the property given\n\t\t\t\n\t\t\tkey_path_class = property_signature->value_class_;\n\t\t}\n\t\t\n\t\tif (!key_path_class)\n\t\t\treturn nil;\t\t\t// unknown symbol at the root; the property yields a non-object type\n\t}\n\t\n\t// OK, we've now got a EidosValue object that represents the end of the line; the final dot is off of this object.\n\t// So we want to extract all of its properties and methods, and return them all as candidates.\n\tNSMutableArray *candidates = [NSMutableArray array];\n\tconst EidosClass *terminus = key_path_class;\n\t\n\t// First, a sorted list of globals\n\tfor (auto symbol_sig : *terminus->Properties())\n\t{\n\t\tif (!symbol_sig->deprecated_)\n\t\t\t[candidates addObject:[NSString stringWithUTF8String:symbol_sig->property_name_.c_str()]];\n\t}\n\t\n\t[candidates sortUsingSelector:@selector(compare:)];\n\t\n\t// Next, a sorted list of methods, with () appended\n\tfor (auto method_sig : *terminus->Methods())\n\t{\n\t\tif (!method_sig->deprecated_)\n\t\t{\n\t\t\tNSString *methodName = [NSString stringWithUTF8String:method_sig->call_name_.c_str()];\n\t\t\t\n\t\t\t[candidates addObject:[methodName stringByAppendingString:@\"()\"]];\n\t\t}\n\t}\n\t\n\treturn candidates;\n}\n\n- (NSArray *)completionsFromArray:(NSArray *)candidates matchingBase:(NSString *)base\n{\n\tNSMutableArray *completions = [NSMutableArray array];\n\tNSInteger candidateCount = [candidates count];\n\t\n#if 0\n\t// This is simple prefix-based completion; if a candidates begins with base, then it is used\n\tfor (int candidateIndex = 0; candidateIndex < candidateCount; ++candidateIndex)\n\t{\n\t\tNSString *candidate = [candidates objectAtIndex:candidateIndex];\n\t\t\n\t\tif ([candidate hasPrefix:base])\n\t\t\t[completions addObject:candidate];\n\t}\n#else\n\t// This is part-based completion, where iTr will complete to initializeTreeSeq() and iGTy\n\t// will complete to initializeGenomicElementType().  To do this, we use a special comparator\n\t// that returns a score for the quality of the match, and then we sort all matches by score.\n\tstd::vector<int64_t> scores;\n\tNSMutableArray *unsortedCompletions = [NSMutableArray array];\n\t\n\tfor (int candidateIndex = 0; candidateIndex < candidateCount; ++candidateIndex)\n\t{\n\t\tNSString *candidate = [candidates objectAtIndex:candidateIndex];\n\t\tint64_t score = [candidate eidosScoreAsCompletionOfString:base];\n\t\t\n\t\tif (score != INT64_MIN)\n\t\t{\n\t\t\t[unsortedCompletions addObject:candidate];\n\t\t\tscores.emplace_back(score);\n\t\t}\n\t}\n\t\n\tif (scores.size())\n\t{\n\t\tstd::vector<int64_t> order = EidosSortIndexes(scores.data(), scores.size(), false);\n\t\t\n\t\tfor (int64_t index : order)\n\t\t\t[completions addObject:[unsortedCompletions objectAtIndex:index]];\n\t}\n#endif\n\t\n\treturn completions;\n}\n\n- (NSArray *)completionsForTokenStream:(const std::vector<EidosToken> &)tokens index:(int)lastTokenIndex canExtend:(BOOL)canExtend withTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap callTypes:(EidosCallTypeTable *)callTypeTable keywords:(NSArray *)keywords argumentNames:(NSArray *)argumentNames\n{\n\t// What completions we offer depends on the token stream\n\tconst EidosToken &token = tokens[lastTokenIndex];\n\tEidosTokenType token_type = token.token_type_;\n\t\n\tswitch (token_type)\n\t{\n\t\tcase EidosTokenType::kTokenNone:\n\t\tcase EidosTokenType::kTokenEOF:\n\t\tcase EidosTokenType::kTokenWhitespace:\n\t\tcase EidosTokenType::kTokenComment:\n\t\tcase EidosTokenType::kTokenCommentLong:\n\t\tcase EidosTokenType::kTokenInterpreterBlock:\n\t\tcase EidosTokenType::kTokenContextFile:\n\t\tcase EidosTokenType::kTokenContextEidosBlock:\n\t\tcase EidosTokenType::kFirstIdentifierLikeToken:\n\t\t\t// These should never be hit\n\t\t\treturn nil;\n\t\t\t\n\t\tcase EidosTokenType::kTokenIdentifier:\n\t\tcase EidosTokenType::kTokenIf:\n\t\tcase EidosTokenType::kTokenWhile:\n\t\tcase EidosTokenType::kTokenFor:\n\t\tcase EidosTokenType::kTokenNext:\n\t\tcase EidosTokenType::kTokenBreak:\n\t\tcase EidosTokenType::kTokenFunction:\n\t\tcase EidosTokenType::kTokenReturn:\n\t\tcase EidosTokenType::kTokenElse:\n\t\tcase EidosTokenType::kTokenDo:\n\t\tcase EidosTokenType::kTokenIn:\n\t\t\tif (canExtend)\n\t\t\t{\n\t\t\t\tNSMutableArray *completions = nil;\n\t\t\t\t\n\t\t\t\t// This is the tricky case, because the identifier we're extending could be the end of a key path like foo.bar[5:8].ba...\n\t\t\t\t// We need to move backwards from the current token until we find or fail to find a dot token; if we see a dot we're in\n\t\t\t\t// a key path, otherwise we're in the global context and should filter from those candidates\n\t\t\t\tfor (int previousTokenIndex = lastTokenIndex - 1; previousTokenIndex >= 0; --previousTokenIndex)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &previous_token = tokens[previousTokenIndex];\n\t\t\t\t\tEidosTokenType previous_token_type = previous_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\t// if the token we're on is skippable, continue backwards\n\t\t\t\t\tif ((previous_token_type == EidosTokenType::kTokenWhitespace) || (previous_token_type == EidosTokenType::kTokenComment) || (previous_token_type == EidosTokenType::kTokenCommentLong))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// if the token we're on is a dot, we are indeed at the end of a key path, and can fetch the completions for it\n\t\t\t\t\tif (previous_token_type == EidosTokenType::kTokenDot)\n\t\t\t\t\t{\n\t\t\t\t\t\tcompletions = [self completionsForKeyPathEndingInTokenIndex:previousTokenIndex ofTokenStream:tokens withTypes:typeTable functions:functionMap callTypes:callTypeTable keywords:keywords];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we see a semicolon or brace, we are in a completely global context\n\t\t\t\t\tif ((previous_token_type == EidosTokenType::kTokenSemicolon) || (previous_token_type == EidosTokenType::kTokenLBrace) || (previous_token_type == EidosTokenType::kTokenRBrace))\n\t\t\t\t\t{\n\t\t\t\t\t\tcompletions = [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:keywords argumentNames:nil];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we see any other token, we are not in a key path; let's assume we're following an operator\n\t\t\t\t\tcompletions = [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:nil argumentNames:argumentNames];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If we ran out of tokens, we're at the beginning of the file and so in the global context\n\t\t\t\tif (!completions)\n\t\t\t\t\tcompletions = [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:keywords argumentNames:nil];\n\t\t\t\t\n\t\t\t\t// Now we have an array of possible completions; we just need to remove those that don't complete the base string,\n\t\t\t\t// according to a heuristic algorithm, and sort those that do match by a score of their closeness of match.\n\t\t\t\treturn [self completionsFromArray:completions matchingBase:[NSString stringWithUTF8String:token.token_string_.c_str()]];\n\t\t\t}\n\t\t\telse if ((token_type == EidosTokenType::kTokenReturn) || (token_type == EidosTokenType::kTokenElse) || (token_type == EidosTokenType::kTokenDo) || (token_type == EidosTokenType::kTokenIn))\n\t\t\t{\n\t\t\t\t// If you can't extend and you're following an identifier, you presumably need an operator or a keyword or something;\n\t\t\t\t// you can't have two identifiers in a row.  The same is true of keywords that do not take an expression after them.\n\t\t\t\t// But return, else, do, and in can be followed immediately by an expression, so here we handle that case.  Identifiers\n\t\t\t\t// and other keywords will drop through to return nil below, expressing that we cannot complete in that case.\n\t\t\t\t// We used to put return, else, do, and in down the the operators at the bottom, but when canExtend is YES that\n\t\t\t\t// prevents them from completing to other things (\"in\" to \"inSLiMgui\", for example); moving them up to this case\n\t\t\t\t// allows that completion to work, but necessitates the addition of this block to get the correct functionality when\n\t\t\t\t// canExtend is NO.  BCH 1/22/2019\n\t\t\t\treturn [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:nil argumentNames:argumentNames];\n\t\t\t}\n\t\t\t\n\t\t\t// If the previous token was an identifier and we can't extend it, the next thing probably needs to be an operator or something\n\t\t\treturn nil;\n\t\t\t\n\t\tcase EidosTokenType::kTokenBad:\n\t\tcase EidosTokenType::kTokenNumber:\n\t\tcase EidosTokenType::kTokenString:\n\t\tcase EidosTokenType::kTokenRParen:\n\t\tcase EidosTokenType::kTokenRBracket:\n\t\tcase EidosTokenType::kTokenSingleton:\n\t\t\t// We don't have anything to suggest after such tokens; the next thing will need to be an operator, semicolon, etc.\n\t\t\treturn nil;\n\t\t\t\n\t\tcase EidosTokenType::kTokenDot:\n\t\t\t// This is the other tricky case, because we're being asked to extend a key path like foo.bar[5:8].\n\t\t\treturn [self completionsForKeyPathEndingInTokenIndex:lastTokenIndex ofTokenStream:tokens withTypes:typeTable functions:functionMap callTypes:callTypeTable keywords:keywords];\n\t\t\t\n\t\tcase EidosTokenType::kTokenSemicolon:\n\t\tcase EidosTokenType::kTokenLBrace:\n\t\tcase EidosTokenType::kTokenRBrace:\n\t\t\t// We are in the global context and anything goes, including a new statement\n\t\t\treturn [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:keywords argumentNames:nil];\n\t\t\t\n\t\tcase EidosTokenType::kTokenColon:\n\t\tcase EidosTokenType::kTokenComma:\n\t\tcase EidosTokenType::kTokenLParen:\n\t\tcase EidosTokenType::kTokenLBracket:\n\t\tcase EidosTokenType::kTokenPlus:\n\t\tcase EidosTokenType::kTokenMinus:\n\t\tcase EidosTokenType::kTokenMod:\n\t\tcase EidosTokenType::kTokenMult:\n\t\tcase EidosTokenType::kTokenExp:\n\t\tcase EidosTokenType::kTokenAnd:\n\t\tcase EidosTokenType::kTokenOr:\n\t\tcase EidosTokenType::kTokenDiv:\n\t\tcase EidosTokenType::kTokenConditional:\n\t\tcase EidosTokenType::kTokenAssign:\n\t\tcase EidosTokenType::kTokenAssign_R:\n\t\tcase EidosTokenType::kTokenEq:\n\t\tcase EidosTokenType::kTokenLt:\n\t\tcase EidosTokenType::kTokenLtEq:\n\t\tcase EidosTokenType::kTokenGt:\n\t\tcase EidosTokenType::kTokenGtEq:\n\t\tcase EidosTokenType::kTokenNot:\n\t\tcase EidosTokenType::kTokenNotEq:\n\t\t\t// We are following an operator or similar, so globals are OK but new statements are not\n\t\t\treturn [self globalCompletionsWithTypes:typeTable functions:functionMap keywords:nil argumentNames:argumentNames];\n\t}\n\t\n\treturn nil;\n}\n\n- (NSUInteger)rangeOffsetForCompletionRange\n{\n\t// This is for EidosConsoleTextView to be able to remove the prompt string from the string being completed\n\treturn 0;\n}\n\n- (NSArray *)uniquedArgumentNameCompletions:(std::vector<std::string> *)argumentCompletions\n{\n\t// put argument-name completions, if any, at the top of the list; we unique them (preserving order) and add \"=\"\n\tif (argumentCompletions && argumentCompletions->size())\n\t{\n\t\tNSMutableArray *completionsWithArgs = [NSMutableArray array];\n\t\t\n\t\tfor (std::string &arg_completion : *argumentCompletions)\n\t\t{\n\t\t\tNSString *argNameString = [NSString stringWithUTF8String:arg_completion.c_str()];\n\t\t\tNSString *argNameWithEquals = [argNameString stringByAppendingString:@\"=\"];\n\t\t\t\n\t\t\tif (![completionsWithArgs containsObject:argNameWithEquals])\n\t\t\t\t[completionsWithArgs addObject:argNameWithEquals];\n\t\t}\n\t\t\n\t\treturn completionsWithArgs;\n\t}\n\t\n\treturn nil;\n}\n\n// one funnel for all completion work, since we use the same pattern to answer both questions...\n- (void)_completionHandlerWithRangeForCompletion:(NSRange *)baseRange completions:(NSArray **)completions\n{\n\tNSString *scriptString = [self string];\n\tNSRange selection = [self selectedRange];\t// ignore charRange and work from the selection\n\tNSUInteger rangeOffset = [self rangeOffsetForCompletionRange];\n\t\n\t// correct the script string to have only what is entered after the prompt, if we are a EidosConsoleTextView\n\tif (rangeOffset)\n\t{\n\t\tscriptString = [scriptString substringFromIndex:rangeOffset];\n\t\tselection.location -= rangeOffset;\n\t\tselection.length -= rangeOffset;\n\t}\n\t\n\tNSUInteger selStart = selection.location;\n\t\n\tif (selStart != NSNotFound)\n\t{\n\t\t// Get the substring up to the start of the selection; that is the range relevant for completion\n\t\tNSString *scriptSubstring = [scriptString substringToIndex:selStart];\n\t\tstd::string script_string([scriptSubstring UTF8String]);\n\t\t\n\t\t// Do shared completion processing that can be intercepted by our delegate: getting a type table for defined variables,\n\t\t// as well as a function map and any added language keywords, all of which depend upon the point of completion\n\t\tid delegate = [self delegate];\n\t\tEidosTypeTable typeTable;\n\t\tEidosTypeTable *typeTablePtr = &typeTable;\n\t\tEidosFunctionMap functionMap(*EidosInterpreter::BuiltInFunctionMap());\n\t\tEidosFunctionMap *functionMapPtr = &functionMap;\n\t\tEidosCallTypeTable callTypeTable;\n\t\tEidosCallTypeTable *callTypeTablePtr = &callTypeTable;\n\t\tNSMutableArray *keywords = [NSMutableArray arrayWithObjects:@\"break\", @\"do\", @\"else\", @\"for\", @\"if\", @\"in\", @\"next\", @\"return\", @\"while\", @\"function\", nil];\n\t\tstd::vector<std::string> argumentCompletions;\n\t\tBOOL delegateHandled = NO;\n\t\t\n\t\tif ([delegate respondsToSelector:@selector(eidosTextView:completionContextWithScriptString:selection:typeTable:functionMap:callTypeTable:keywords:argumentNameCompletions:)])\n\t\t{\n\t\t\tdelegateHandled = [delegate eidosTextView:self completionContextWithScriptString:scriptSubstring selection:selection typeTable:&typeTablePtr functionMap:&functionMapPtr callTypeTable:&callTypeTablePtr keywords:keywords argumentNameCompletions:&argumentCompletions];\n\t\t}\n\t\t\n\t\t// set up automatic disposal of a substitute type table or function map provided by delegate\n\t\tstd::unique_ptr<EidosTypeTable> raii_typeTablePtr((typeTablePtr != &typeTable) ? typeTablePtr : nullptr);\n\t\tstd::unique_ptr<EidosFunctionMap> raii_functionMapPtr((functionMapPtr != &functionMap) ? functionMapPtr : nullptr);\n\t\tstd::unique_ptr<EidosCallTypeTable> raii_callTypeTablePtr((callTypeTablePtr != &callTypeTable) ? callTypeTablePtr : nullptr);\n\t\t\n\t\tif (!delegateHandled)\n\t\t{\n\t\t\t// First, set up a base type table using the symbol table\n\t\t\tEidosSymbolTable *symbols = gEidosConstantsSymbolTable;\n\t\t\t\n\t\t\tif ([delegate respondsToSelector:@selector(eidosTextView:symbolsFromBaseSymbols:)])\n\t\t\t\tsymbols = [delegate eidosTextView:self symbolsFromBaseSymbols:symbols];\n\t\t\t\n\t\t\tif (symbols)\n\t\t\t\tsymbols->AddSymbolsToTypeTable(typeTablePtr);\n\t\t\t\n\t\t\t// Next, a definitive function map that covers all functions defined in the entire script string (not just the script above\n\t\t\t// the completion point); this seems best, for mutually recursive functions etc..  Duplicate it back into functionMap and\n\t\t\t// delete the original, so we don't get confused.\n\t\t\tEidosFunctionMap *definitive_function_map = [self functionMapForScriptString:scriptString includingOptionalFunctions:NO];\n\t\t\t\n\t\t\tfunctionMap = *definitive_function_map;\n\t\t\tdelete definitive_function_map;\n\t\t\t\n\t\t\t// Next, add type table entries based on parsing and analysis of the user's code\n\t\t\tEidosScript script(script_string);\n\t\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\t\tstd::cout << \"Eidos script:\\n\" << script_string << std::endl << std::endl;\n#endif\n\t\t\t\n\t\t\tscript.Tokenize(true, false);\t\t\t\t\t// make bad tokens as needed, do not keep nonsignificant tokens\n\t\t\tscript.ParseInterpreterBlockToAST(true, true);\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n\t\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\t\tstd::ostringstream parse_stream;\n\t\t\tscript.PrintAST(parse_stream);\n\t\t\tstd::cout << \"Eidos AST:\\n\" << parse_stream.str() << std::endl << std::endl;\n#endif\n\t\t\t\n\t\t\tEidosTypeInterpreter typeInterpreter(script, *typeTablePtr, *functionMapPtr, *callTypeTablePtr);\n\t\t\t\n\t\t\ttypeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(&argumentCompletions, script_string.length());\t// result not used\n\t\t}\n\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\tstd::cout << \"Type table:\\n\" << *typeTablePtr << std::endl;\n#endif\n\t\t\n\t\t// Tokenize; we can't use the tokenization done above, as we want whitespace tokens here...\n\t\tEidosScript script(script_string);\n\t\tscript.Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\tstd::cout << \"Eidos token stream:\" << std::endl;\n\t\tscript.PrintTokens(std::cout);\n#endif\n\t\t\n\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\tint lastTokenIndex = (int)tokens.size() - 1;\n\t\tBOOL endedCleanly = NO, lastTokenInterrupted = NO;\n\t\t\n\t\t// if we ended with an EOF, that means we did not have a raise and there should be no untokenizable range at the end\n\t\tif ((lastTokenIndex >= 0) && (tokens[lastTokenIndex].token_type_ == EidosTokenType::kTokenEOF))\n\t\t{\n\t\t\t--lastTokenIndex;\n\t\t\tendedCleanly = YES;\n\t\t}\n\t\t\n\t\t// if we are at the end of a comment, without whitespace following it, then we are actually in the comment, and cannot complete\n\t\t// BCH 5 August 2017: Note that EidosTokenType::kTokenCommentLong is deliberately omitted here; this rule does not apply to it\n\t\tif ((lastTokenIndex >= 0) && (tokens[lastTokenIndex].token_type_ == EidosTokenType::kTokenComment))\n\t\t{\n\t\t\tif (baseRange) *baseRange = NSMakeRange(NSNotFound, 0);\n\t\t\tif (completions) *completions = nil;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// if we ended with whitespace or a comment, the previous token cannot be extended\n\t\twhile (lastTokenIndex >= 0) {\n\t\t\tconst EidosToken &token = tokens[lastTokenIndex];\n\t\t\t\n\t\t\tif ((token.token_type_ != EidosTokenType::kTokenWhitespace) && (token.token_type_ != EidosTokenType::kTokenComment) && (token.token_type_ != EidosTokenType::kTokenCommentLong))\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--lastTokenIndex;\n\t\t\tlastTokenInterrupted = YES;\n\t\t}\n\t\t\n\t\t// now diagnose what range we want to use as a basis for completion\n\t\tif (!endedCleanly)\n\t\t{\n\t\t\t// the selection is at the end of an untokenizable range; we might be in the middle of a string or a comment,\n\t\t\t// or there might be a tokenization error upstream of us.  let's not try to guess what the situation is.\n\t\t\tif (baseRange) *baseRange = NSMakeRange(NSNotFound, 0);\n\t\t\tif (completions) *completions = nil;\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (lastTokenIndex < 0)\n\t\t\t{\n\t\t\t\t// We're at the end of nothing but initial whitespace and comments; or if (!lastTokenInterrupted),\n\t\t\t\t// we're at the very beginning of the file.  Either way, offer insertion-point completions.\n\t\t\t\tif (baseRange) *baseRange = NSMakeRange(selection.location + rangeOffset, 0);\n\t\t\t\tif (completions) *completions = [self globalCompletionsWithTypes:typeTablePtr functions:functionMapPtr keywords:keywords argumentNames:nil];\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tconst EidosToken &token = tokens[lastTokenIndex];\n\t\t\tEidosTokenType token_type = token.token_type_;\n\t\t\t\n\t\t\t// BCH 31 May 2016: If the previous token is a right-paren, that is a tricky case because we could be following\n\t\t\t// for(), an if(), or while (), in which case we should allow an identifier to follow the right paren, or we could\n\t\t\t// be following parentheses for grouping, i.e. (a+b), or parentheses for a function call, foo(), in which case we\n\t\t\t// should not allow an identifier to follow the right paren.  This annoyance is basically because the right paren\n\t\t\t// serves a lot of different functions in the language and so just knowing that we are after one is not sufficient.\n\t\t\t// So we will walk backwards, balancing our parenthesis count, to try to figure out which case we are in.  Note\n\t\t\t// that even this code is not quite right; it mischaracterizes the do...while() case as allowing an identifier to\n\t\t\t// follow, because it sees the \"while\".  This is harder to fix, and do...while() is not a common construct, and\n\t\t\t// the mistake is pretty harmless, so whatever.\n\t\t\tif (token_type == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\tint parenCount = 1;\n\t\t\t\tint walkbackIndex = lastTokenIndex;\n\t\t\t\t\n\t\t\t\t// First walk back until our paren count balances\n\t\t\t\twhile (--walkbackIndex >= 0)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &walkback_token = tokens[walkbackIndex];\n\t\t\t\t\tEidosTokenType walkback_token_type = walkback_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (walkback_token_type == EidosTokenType::kTokenRParen)\t\t\tparenCount++;\n\t\t\t\t\telse if (walkback_token_type == EidosTokenType::kTokenLParen)\t\tparenCount--;\n\t\t\t\t\t\n\t\t\t\t\tif (parenCount == 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Then walk back over whitespace, and if the first non-white thing we see is right, allow completion\n\t\t\t\twhile (--walkbackIndex >= 0)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &walkback_token = tokens[walkbackIndex];\n\t\t\t\t\tEidosTokenType walkback_token_type = walkback_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif ((walkback_token_type != EidosTokenType::kTokenWhitespace) && (walkback_token_type != EidosTokenType::kTokenComment) && (walkback_token_type != EidosTokenType::kTokenCommentLong))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((walkback_token_type == EidosTokenType::kTokenFor) || (walkback_token_type == EidosTokenType::kTokenWhile) || (walkback_token_type == EidosTokenType::kTokenIf))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We are at the end of for(), if(), or while(), so we allow global completions as if we were after a semicolon\n\t\t\t\t\t\t\tif (baseRange) *baseRange = NSMakeRange(selection.location + rangeOffset, 0);\n\t\t\t\t\t\t\tif (completions) *completions = [self globalCompletionsWithTypes:typeTablePtr functions:functionMapPtr keywords:keywords argumentNames:nil];\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\t// we didn't hit one of the favored cases, so the code below will reject completion\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (lastTokenInterrupted)\n\t\t\t{\n\t\t\t\t// the last token cannot be extended, so if the last token is something an identifier can follow, like an\n\t\t\t\t// operator, then we can offer completions at the insertion point based on that, otherwise punt.\n\t\t\t\tif ((token_type == EidosTokenType::kTokenNumber) || (token_type == EidosTokenType::kTokenString) || (token_type == EidosTokenType::kTokenRParen) || (token_type == EidosTokenType::kTokenRBracket) || (token_type == EidosTokenType::kTokenIdentifier) || (token_type == EidosTokenType::kTokenIf) || (token_type == EidosTokenType::kTokenWhile) || (token_type == EidosTokenType::kTokenFor) || (token_type == EidosTokenType::kTokenNext) || (token_type == EidosTokenType::kTokenBreak) || (token_type == EidosTokenType::kTokenFunction))\n\t\t\t\t{\n\t\t\t\t\tif (baseRange) *baseRange = NSMakeRange(NSNotFound, 0);\n\t\t\t\t\tif (completions) *completions = nil;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (baseRange) *baseRange = NSMakeRange(selection.location + rangeOffset, 0);\n\t\t\t\tif (completions)\n\t\t\t\t{\n\t\t\t\t\tNSArray *argumentCompletionsArray = [self uniquedArgumentNameCompletions:&argumentCompletions];\n\t\t\t\t\t\n\t\t\t\t\t*completions = [self completionsForTokenStream:tokens index:lastTokenIndex canExtend:NO withTypes:typeTablePtr functions:functionMapPtr callTypes:callTypeTablePtr keywords:keywords argumentNames:argumentCompletionsArray];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the last token was not interrupted, so we can offer completions of it if we want to.\n\t\t\t\tNSRange tokenRange = NSMakeRange(token.token_UTF16_start_, token.token_UTF16_end_ - token.token_UTF16_start_ + 1);\n\t\t\t\t\n\t\t\t\tif (token_type >= EidosTokenType::kTokenIdentifier)\n\t\t\t\t{\n\t\t\t\t\tif (baseRange) *baseRange = NSMakeRange(tokenRange.location + rangeOffset, tokenRange.length);\n\t\t\t\t\tif (completions)\n\t\t\t\t\t{\n\t\t\t\t\t\tNSArray *argumentCompletionsArray = [self uniquedArgumentNameCompletions:&argumentCompletions];\n\t\t\t\t\t\t\n\t\t\t\t\t\t*completions = [self completionsForTokenStream:tokens index:lastTokenIndex canExtend:YES withTypes:typeTablePtr functions:functionMapPtr callTypes:callTypeTablePtr keywords:keywords argumentNames:argumentCompletionsArray];\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ((token_type == EidosTokenType::kTokenNumber) || (token_type == EidosTokenType::kTokenString) || (token_type == EidosTokenType::kTokenRParen) || (token_type == EidosTokenType::kTokenRBracket))\n\t\t\t\t{\n\t\t\t\t\tif (baseRange) *baseRange = NSMakeRange(NSNotFound, 0);\n\t\t\t\t\tif (completions) *completions = nil;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (baseRange) *baseRange = NSMakeRange(selection.location + rangeOffset, 0);\n\t\t\t\tif (completions)\n\t\t\t\t{\n\t\t\t\t\tNSArray *argumentCompletionsArray = [self uniquedArgumentNameCompletions:&argumentCompletions];\n\t\t\t\t\t\n\t\t\t\t\t*completions = [self completionsForTokenStream:tokens index:lastTokenIndex canExtend:NO withTypes:typeTablePtr functions:functionMapPtr callTypes:callTypeTablePtr keywords:keywords argumentNames:argumentCompletionsArray];\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n@end\n\n\n//\n//\tEidosTextStorage\n//\n#pragma mark -\n#pragma mark EidosTextStorage\n\n@interface EidosTextStorage ()\n{\n\tNSMutableAttributedString *contents;\n}\n@end\n\n@implementation EidosTextStorage\n\n- (id)initWithAttributedString:(NSAttributedString *)attrStr\n{\n\tif (self = [super init])\n\t{\n\t\tcontents = attrStr ? [attrStr mutableCopy] : [[NSMutableAttributedString alloc] init];\n\t}\n\treturn self;\n}\n\n- init\n{\n\treturn [self initWithAttributedString:nil];\n}\n\n- (void)dealloc\n{\n\t[contents release];\n\t[super dealloc];\n}\n\n// The next set of methods are the primitives for attributed and mutable attributed string...\n\n- (NSString *)string\n{\n\treturn [contents string];\n}\n\n- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRange *)range\n{\n\treturn [contents attributesAtIndex:location effectiveRange:range];\n}\n\n- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str\n{\n\tNSUInteger origLen = [self length];\n\t[contents replaceCharactersInRange:range withString:str];\n\t[self edited:NSTextStorageEditedCharacters range:range changeInLength:[self length] - origLen];\n}\n\n- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range\n{\n\t[contents setAttributes:attrs range:range];\n\t[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];\n}\n\n// And now the actual reason for this subclass: to provide code-aware word selection behavior\n\n- (NSRange)doubleClickAtIndex:(NSUInteger)location\n{\n\t// Start by calling super to get a proposed range.  This is documented to raise if location >= [self length]\n\t// or location < 0, so in the code below we can assume that location indicates a valid character position.\n\tNSRange superRange = [super doubleClickAtIndex:location];\n\tNSString *string = [self string];\n\tNSUInteger stringLength = [string length];\n\tunichar uch = [string characterAtIndex:location];\n\t\n\t// If the user has actually double-clicked a period, we want to just return the range of the period.\n\tif (uch == '.')\n\t\treturn NSMakeRange(location, 1);\n\t\n\t// Two-character tokens should be considered words, so look for those and fix as needed\n\tif (location < stringLength - 1)\n\t{\n\t\t// we have another character following us, so let's get it and check for cases\n\t\tunichar uch_after = [string characterAtIndex:location + 1];\n\t\t\n\t\tif (((uch == '/') && (uch_after == '/')) ||\n\t\t\t((uch == '=') && (uch_after == '=')) ||\n\t\t\t((uch == '<') && (uch_after == '=')) ||\n\t\t\t((uch == '>') && (uch_after == '=')) ||\n\t\t\t((uch == '!') && (uch_after == '=')))\n\t\t\treturn NSMakeRange(location, 2);\n\t}\n\t\n\tif (location > 0)\n\t{\n\t\t// we have another character preceding us, so let's get it and check for cases\n\t\tunichar uch_before = [string characterAtIndex:location - 1];\n\t\t\n\t\tif (((uch_before == '/') && (uch == '/')) ||\n\t\t\t((uch_before == '=') && (uch == '=')) ||\n\t\t\t((uch_before == '<') && (uch == '=')) ||\n\t\t\t((uch_before == '>') && (uch == '=')) ||\n\t\t\t((uch_before == '!') && (uch == '=')))\n\t\t\treturn NSMakeRange(location - 1, 2);\n\t}\n\t\n\t// Another case where super's behavior is wrong involves the dot operator; x.y should not be considered a word.\n\t// So we check for a period before or after the anchor position, and trim away the periods and everything\n\t// past them on both sides.  This will correctly handle longer sequences like foo.bar.baz.is.a.test.\n\tNSRange candidateRangeBeforeLocation = NSMakeRange(superRange.location, location - superRange.location);\n\tNSRange candidateRangeAfterLocation = NSMakeRange(location + 1, NSMaxRange(superRange) - (location + 1));\n\tNSRange periodBeforeRange = [string rangeOfString:@\".\" options:NSBackwardsSearch range:candidateRangeBeforeLocation];\n\tNSRange periodAfterRange = [string rangeOfString:@\".\" options:(NSStringCompareOptions)0 range:candidateRangeAfterLocation];\n\t\n\tif (periodBeforeRange.location != NSNotFound)\n\t{\n\t\t// Change superRange to start after the preceding period; fix its length so its end remains unchanged.\n\t\tsuperRange.length -= (periodBeforeRange.location + 1 - superRange.location);\n\t\tsuperRange.location = periodBeforeRange.location + 1;\n\t}\n\t\n\tif (periodAfterRange.location != NSNotFound)\n\t{\n\t\t// Change superRange to end before the following period\n\t\tsuperRange.length -= (NSMaxRange(superRange) - periodAfterRange.location);\n\t}\n\t\n\treturn superRange;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosTextViewDelegate.h",
    "content": "//\n//  EidosTextViewDelegate.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 9/10/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#import <Cocoa/Cocoa.h>\n\n#include <vector>\n#include <string>\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_type_table.h\"\n#include \"eidos_type_interpreter.h\"\n\n@class EidosTextView;\n\n\n/*\n \n This is an Objective-C++ header, and so can only be included by Objective-C++ compilations (.mm files instead of .m files).\n You should not need to include this header in your .h files, since you can declare protocol conformance in a class-continuation\n category in your .m file, so only classes that conform to this protocol should need to be Objective-C++.\n \n EidosTextViewDelegate is a protocol of optional methods that EidosTextView's delegate can implement, to allow the Context to\n customize code completion in an EidosTextView.  Note that if EidosConsoleWindowController is used, these methods get forwarded\n on by its delegate as well, so that EidosConsoleWindowController also gets Context-defined behavior.\n\n */\n\nenum class EidosSyntaxHighlightType\n{\n\tkNoSyntaxHighlight,\n\tkHighlightAsIdentifier,\n\tkHighlightAsKeyword,\n\tkHighlightAsContextKeyword\n};\n\n@interface EidosTextView(ObjCppExtensions)\n\n// Getting a \"definitive\" function map using type-interpreting to add to the delegate's function map\n- (EidosFunctionMap *)functionMapForScriptString:(NSString *)scriptString includingOptionalFunctions:(BOOL)includingOptionalFunctions;\n- (EidosFunctionMap *)functionMapForTokenizedScript:(EidosScript &)script includingOptionalFunctions:(BOOL)includingOptionalFunctions;\n\n@end\n\n@protocol EidosTextViewDelegate <NSTextViewDelegate>\n\n@optional\n\n// This allows the Context to define its own symbols beyond those in Eidos itself.\n// The returned symbol table is not freed by the caller, since it is assumed to be\n// an existing object with a lifetime managed by the callee.\n- (EidosSymbolTable *)eidosTextView:(EidosTextView *)eidosTextView symbolsFromBaseSymbols:(EidosSymbolTable *)baseSymbols;\n\n// This allows the Context to define its own functions beyond those in Eidos itself.\n// The returned symbol table is not freed by the caller, since it is assumed to be\n// an existing object with a lifetime managed by the callee.\n- (EidosFunctionMap *)functionMapForEidosTextView:(EidosTextView *)eidosTextView;\n\n// The functionMapForEidosTextView: delegate method returns the current function map from\n// the state of the delegate.  That may not include some optional functions, such as SLiM's\n// zero-generation functions, that EidosTextView wants to know about in some situations.\n// This delegate method requests those optional functions to be added.\n- (void)eidosTextView:(EidosTextView *)eidosTextView addOptionalFunctionsToMap:(EidosFunctionMap *)functionMap;\n\n// This allows the Context to define some special identifier tokens that should\n// receive different syntax coloring from standard identifiers because they are\n// in some way built in or provided by the Context automatically\n- (EidosSyntaxHighlightType)eidosTextView:(EidosTextView *)eidosTextView tokenStringIsSpecialIdentifier:(const std::string &)token_string;\n\n// This allows the Context to define substitutions for help searches when the user\n// option-clicks a token, to provide more targeted help results.  If no substitution\n// is desired, returning nil is recommended.\n- (NSString *)eidosTextView:(EidosTextView *)eidosTextView helpTextForClickedText:(NSString *)clickedText;\n\n// This allows the Context to customize the behavior of code completion, depending upon\n// the context in which the completion occurs (as determined by the script string, which\n// extends up to the end of the selection, and the selection range).  The delegate should\n// add types to the type table (which is empty), add functions to the function map (which\n// has the built-in Eidos functions already), and add applicable language keywords to the\n// keywords array.  If this delegate method is not implemented, EidosTextView will do its\n// standard behavior.  In particular, types will be found with ParseInterpreterBlockToAST()\n// and TypeEvaluateInterpreterBlock() in addition to symbolsFromBaseSymbols:, functions\n// will be found with functionMapForEidosTextView:, and no keywords will be added to the base\n// set.  This standard behavior is fine for Contexts that do not define context-dependent\n// language constructs in the way that SLiM does.\n//\n// Note that unlike symbolsFromBaseSymbols: and functionMapForEidosTextView:, here the delegate\n// is expected to modify the objects passed to it.  This difference is motivated by the idea\n// that the other delegate methods are providing a standard symbol table and function map\n// kept by the Context, whereas this delegate method is expected to create context-dependent\n// information that differs from the current state of the Context.  The delegate may even\n// replace the pointers passed to the type table and/or function map, in order to substitute\n// a new object (perhaps a subclass object) for those objects; in that case, the substituted\n// object will be freed by the caller (not the delegate), so don't give your private objects.\n//\n// Also note that the delegate does not need to worry about uniquing or sorting type entries.\n//\n// Return NO if you want Eidos to do its default behavior, YES if you have taken care of it.\n- (BOOL)eidosTextView:(EidosTextView *)eidosTextView completionContextWithScriptString:(NSString *)scriptString selection:(NSRange)selection typeTable:(EidosTypeTable **)typeTable functionMap:(EidosFunctionMap **)functionMap callTypeTable:(EidosCallTypeTable **)callTypeTable keywords:(NSMutableArray *)keywords argumentNameCompletions:(std::vector<std::string> *)argNameCompletions;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosValueWrapper.h",
    "content": "//\n//  EidosValueWrapper.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 5/31/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include \"eidos_value.h\"\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n/*\n \n This is an Objective-C++ header, and so can only be included by Objective-C++ compilations (.mm files instead of .m files).\n You should not need to include this header in your .h files, since you can declare protocol conformance in a class-continuation\n category in your .m file, so only classes that conform to this protocol should need to be Objective-C++.  However,\n EidosValueWrapper is used by EidosVariableBrowserController; it should never be used directly by client code.\n \n EidosValueWrapper is a rather tricky little beast.  The basic point is to provide the variable browser's NSOutlineView with\n Obj-C objects to represent the items that it displays.  Those items are \"really\" EidosValues of one sort or another – root\n EidosValues from the current symbol table, or sub-values that represent individual elements, properties, etc. from those\n root values.  Effectively, these values are related in a similar way to key paths, but with individual-element subscripting\n as well; foo.bar[5].baz.foobar[2] is a line that might be displayed in the variable browser, with a corresponding EidosValue.\n \n The first bit of complication comes from the fact that it isn't really kosher to keep EidosValues around unless you own them,\n so we participate in the smart pointer scheme used with EidosValue in eidos.  Whenever the state of the Eidos interpreter changes,\n we throw out all of our old wrappers, thereby getting rid of the EidosValue pointers they contain; we have a retain on them,\n but they are no longer part of the interpreter state and so should not be used.\n \n The second bit of complication, however, is that we want NSOutlineView to keep its expansion state identical across such\n reloads, even though it is displaying a whole new batch of EidosValueWrapper objects.  We therefore need EidosValueWrapper\n to implement -hash and -isEqual:, but those implementations cannot refer to the wrapped EidosValues at all, because they\n might already be invalid.  Hashing and equality therefor need to be based solely on the non-Eidos state of the wrappers.\n This means that a given wrapper needs to \"know\" its full \"key path\", not just its own name; hash and equality are determined\n by the full key path, in this scheme.  This is achieved by giving EidosValueWrapper a pointer to its parent, and making\n -hash and -isEqual: be recursive methods that follow the key path upward to the root and integrate information from the\n full path.\n \n */\n\n@interface EidosValueWrapper : NSObject\n{\n}\n\n+ (instancetype)wrapperForName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue;\n+ (instancetype)wrapperForName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue index:(int)anIndex of:(int)siblingCount;\n\n- (instancetype)init __attribute__((unavailable(\"This method is not available\")));\t// superclass designated initializer is not valid\n- (instancetype)initWithWrappedName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue index:(int)anIndex of:(int)siblingCount NS_DESIGNATED_INITIALIZER;\n\n- (void)invalidateWrappedValues;\n- (void)releaseChildWrappers;\n\n- (NSArray *)childWrappers;\n\n- (BOOL)isExpandable;\n\n- (id)displaySymbol;\n- (id)displayType;\n- (id)displaySize;\n- (id)displayValue;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosValueWrapper.mm",
    "content": "//\n//  EidosValueWrapper.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 5/31/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosValueWrapper.h\"\n\n#include \"eidos_value.h\"\n#include \"eidos_property_signature.h\"\n\n\n@interface EidosValueWrapper ()\n{\n@private\n\tEidosValueWrapper *parentWrapper;\n\t\n\tNSString *wrappedName;\t\t// the displayed name\n\tint wrappedIndex;\t\t\t// the index of wrappedValue upon which the row is based; -1 if the row represents the whole value\n\tint wrappedSiblingCount;\t// the number of siblings of this item; used for -hash and -isEqual:\n\t\n\tEidosValue_SP wrappedValue;\t// the value upon which the row is based\n\tBOOL isExpandable;\t\t\t// a cached value; YES if wrappedValue is of type object, NO otherwise\n\tBOOL isConstant;\t\t\t// is this value a built-in Eidos constant?\n\t\n\tNSMutableArray *childWrappers;\n}\n@end\n\n\n@implementation EidosValueWrapper\n\n+ (instancetype)wrapperForName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue\n{\n\treturn [[[self alloc] initWithWrappedName:aName parent:parent value:std::move(aValue) index:-1 of:0] autorelease];\n}\n\n+ (instancetype)wrapperForName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue index:(int)anIndex of:(int)siblingCount\n{\n\treturn [[[self alloc] initWithWrappedName:aName parent:parent value:std::move(aValue) index:anIndex of:siblingCount] autorelease];\n}\n\n- (instancetype)init\n{\n\t// The superclass designated initializer is not valid for us\n\tNSAssert(false, @\"-init is not defined for this class\");\n\t\n\treturn [self initWithWrappedName:nil parent:nil value:EidosValue_SP(nullptr) index:0 of:0];\n}\n\n- (instancetype)initWithWrappedName:(NSString *)aName parent:(EidosValueWrapper *)parent value:(EidosValue_SP)aValue index:(int)anIndex of:(int)siblingCount\n{\n\tif (self = [super init])\n\t{\n\t\tparentWrapper = [parent retain];\n\t\t\n\t\twrappedName = [aName retain];\n\t\twrappedIndex = anIndex;\n\t\twrappedSiblingCount = siblingCount;\n\t\t\n\t\twrappedValue = std::move(aValue);\n\t\t\n\t\t// We cache this so that we know whether we are expandable without needing to dereference wrappedValue;\n\t\t// we therefore know whether or not we are expandable even after wrappedValue is invalidated\n\t\tif (wrappedValue)\n\t\t\tisExpandable = (wrappedValue->Type() == EidosValueType::kValueObject);\n\t\telse\n\t\t\tisExpandable = false;\n\t\t\n\t\t// We want to display Eidos constants in gray text, to de-emphasize them.  For now, we just hard-code them\n\t\t// as a hack, because we *don't* want SLiM constants (sim, g1, p1, etc.) to display dimmed\n\t\tisConstant = NO;\n\t\t\n\t\tif (!parentWrapper && ([wrappedName isEqualToString:@\"T\"] || [wrappedName isEqualToString:@\"F\"] || [wrappedName isEqualToString:@\"E\"] || [wrappedName isEqualToString:@\"PI\"] || [wrappedName isEqualToString:@\"INF\"] || [wrappedName isEqualToString:@\"NAN\"] || [wrappedName isEqualToString:@\"NULL\"]))\n\t\t\tisConstant = YES;\n\t\t\n\t\tchildWrappers = nil;\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\twrappedValue.reset();\n\t\n\t[wrappedName release];\n\twrappedName = nil;\n\t\n\t[parentWrapper release];\n\tparentWrapper = nil;\n\t\n\t[childWrappers release];\n\tchildWrappers = nil;\n\t\n\t[super dealloc];\n}\n\n- (void)invalidateWrappedValues\n{\n\twrappedValue.reset();\n\t\n\t[childWrappers makeObjectsPerformSelector:@selector(invalidateWrappedValues)];\n}\n\n- (void)releaseChildWrappers\n{\n\t[childWrappers makeObjectsPerformSelector:@selector(releaseChildWrappers)];\n\t\n\t[childWrappers release];\n\tchildWrappers = nil;\n}\n\n- (NSArray *)childWrappers\n{\n\tif (!childWrappers)\n\t{\n\t\t// If we don't have our cache of child wrappers, set it up on demand\n\t\tchildWrappers = [NSMutableArray new];\n\t\t\n\t\t// If we have no wrapped value, we have no children\n\t\tif (!wrappedValue)\n\t\t\treturn childWrappers;\n\t\t\n\t\tint elementCount = wrappedValue->Count();\n\t\t\n\t\t// values which are of object type and contain more than one element get displayed as a list of elements\n\t\tif (elementCount > 1)\n\t\t{\n\t\t\tfor (int index = 0; index < elementCount;++ index)\n\t\t\t{\n\t\t\t\tNSString *childName = [NSString stringWithFormat:@\"%@[%ld]\", wrappedName, (long)index];\n\t\t\t\tEidosValue_SP childValue = wrappedValue->GetValueAtIndex(index, nullptr);\n\t\t\t\tEidosValueWrapper *childWrapper = [EidosValueWrapper wrapperForName:childName parent:self value:std::move(childValue) index:index of:elementCount];\n\t\t\t\t\n\t\t\t\t[childWrappers addObject:childWrapper];\n\t\t\t}\n\t\t}\n\t\telse if (wrappedValue->Type() == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosValue_Object *wrapped_object = ((EidosValue_Object *)wrappedValue.get());\n\t\t\tconst EidosClass *object_class = wrapped_object->Class();\n\t\t\tconst std::vector<EidosPropertySignature_CSP> *properties = object_class->Properties();\n\t\t\tint propertyCount = (int)properties->size();\n\t\t\tbool oldSuppressWarnings = gEidosSuppressWarnings, inaccessibleCaught = false;\n\t\t\t\n\t\t\tgEidosSuppressWarnings = true;\t\t// prevent warnings from questionable property accesses from producing warnings in the user's output pane\n\t\t\t\n\t\t\tfor (int index = 0; index < propertyCount; ++index)\n\t\t\t{\n\t\t\t\tconst EidosPropertySignature_CSP &propertySig = (*properties)[index];\n\t\t\t\tconst std::string &symbolName = propertySig->property_name_;\n\t\t\t\tEidosGlobalStringID symbolID = propertySig->property_id_;\n\t\t\t\tNSString *symbolObjcName = [NSString stringWithUTF8String:symbolName.c_str()];\n\t\t\t\tEidosValue_SP symbolValue;\n\t\t\t\t\n\t\t\t\t// protect against raises in property accesses due to inaccessible properties\n\t\t\t\ttry {\n\t\t\t\t\tsymbolValue = wrapped_object->GetPropertyOfElements(symbolID);\n\t\t\t\t} catch (...) {\n\t\t\t\t\t//std::cout << \"caught inaccessible property \" << symbolName << std::endl;\n\t\t\t\t\tinaccessibleCaught = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEidosValueWrapper *childWrapper = [EidosValueWrapper wrapperForName:symbolObjcName parent:self value:std::move(symbolValue)];\n\t\t\t\t\n\t\t\t\t[childWrappers addObject:childWrapper];\n\t\t\t}\n\t\t\t\n\t\t\tgEidosSuppressWarnings = oldSuppressWarnings;\n\t\t\t\n\t\t\tif (inaccessibleCaught)\n\t\t\t{\n\t\t\t\t// throw away the raise message(s) so they don't confuse us\n\t\t\t\tgEidosTermination.clear();\n\t\t\t\tgEidosTermination.str(gEidosStr_empty_string);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn childWrappers;\n}\n\n- (BOOL)isExpandable\n{\n\treturn isExpandable;\n}\n\n+ (NSDictionary *)italicAttrs\n{\n\tstatic NSDictionary *italicAttrs = nil;\n\t\n\tif (!italicAttrs)\n\t{\n\t\tNSFont *baseFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]];\n\t\tNSFont *italicFont = [[NSFontManager sharedFontManager] convertFont:baseFont toHaveTrait:NSItalicFontMask];\n\t\t\n\t\titalicAttrs = [@{NSFontAttributeName : italicFont} retain];\n\t}\n\t\n\treturn italicAttrs;\n}\n\n+ (NSDictionary *)dimmedAttrs\n{\n\tstatic NSDictionary *dimmedAttrs = nil;\n\t\n\tif (!dimmedAttrs)\n\t{\n\t\tNSFont *baseFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]];\n\t\t\n\t\tdimmedAttrs = [@{NSFontAttributeName : baseFont, NSForegroundColorAttributeName : [NSColor colorWithCalibratedWhite:0.5 alpha:1.0]} retain];\n\t}\n\t\n\treturn dimmedAttrs;\n}\n\n+ (NSDictionary *)centeredDimmedAttrs\n{\n\tstatic NSDictionary *centeredDimmedAttrs = nil;\n\t\n\tif (!centeredDimmedAttrs)\n\t{\n\t\tNSFont *baseFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeSmall]];\n\t\tNSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];\n\t\t\n\t\t[paragraphStyle setAlignment:NSTextAlignmentCenter];\n\t\t\n\t\tcenteredDimmedAttrs = [@{NSFontAttributeName : baseFont, NSForegroundColorAttributeName : [NSColor colorWithCalibratedWhite:0.5 alpha:1.0], NSParagraphStyleAttributeName : paragraphStyle} retain];\n\t\t\n\t\t[paragraphStyle release];\n\t}\n\t\n\treturn centeredDimmedAttrs;\n}\n\n- (id)displaySymbol\n{\n\t// If this row is a marker for an element within an object we treat it specially\n\tif (wrappedIndex != -1)\n\t\treturn [[[NSAttributedString alloc] initWithString:wrappedName attributes:[EidosValueWrapper italicAttrs]] autorelease];\n\t\n\tif (isConstant)\n\t\treturn [[[NSAttributedString alloc] initWithString:wrappedName attributes:[EidosValueWrapper dimmedAttrs]] autorelease];\n\t\n\treturn wrappedName;\n}\n\n- (id)displayType\n{\n\t// If this row is a marker for an element within an object we treat it specially\n\tif (wrappedIndex != -1)\n\t\treturn @\"\";\n\t\n\t// If the value is inaccessible display nothing\n\tif (!wrappedValue)\n\t\treturn @\"\";\n\t\n\tEidosValueType type = wrappedValue->Type();\n\tstd::string type_string = StringForEidosValueType(type);\n\tconst char *type_cstr = type_string.c_str();\n\tNSString *typeString = [NSString stringWithUTF8String:type_cstr];\n\t\n\tif (type == EidosValueType::kValueObject)\n\t{\n\t\tEidosValue_Object *object_value = (EidosValue_Object *)wrappedValue.get();\n\t\tconst std::string &element_string = object_value->ElementType();\n\t\tconst char *element_cstr = element_string.c_str();\n\t\tNSString *elementString = [NSString stringWithUTF8String:element_cstr];\n\t\t\n\t\ttypeString = [NSString stringWithFormat:@\"%@<%@>\", typeString, elementString];\n\t}\n\t\n\tif (isConstant)\n\t\treturn [[[NSAttributedString alloc] initWithString:typeString attributes:[EidosValueWrapper dimmedAttrs]] autorelease];\n\t\n\treturn typeString;\n}\n\n- (id)displaySize\n{\n\t// If this row is a marker for an element within an object we treat it specially\n\tif (wrappedIndex != -1)\n\t\treturn @\"\";\n\t\n\t// If the value is inaccessible display nothing\n\tif (!wrappedValue)\n\t\treturn @\"\";\n\t\n\tNSString *sizeString = [NSString stringWithFormat:@\"%d\", wrappedValue->Count()];\n\t\n\tif (isConstant)\n\t\treturn [[[NSAttributedString alloc] initWithString:sizeString attributes:[EidosValueWrapper centeredDimmedAttrs]] autorelease];\n\t\n\treturn sizeString;\n}\n\n- (id)displayValue\n{\n\t// If this row is a marker for an element within an object we treat it specially\n\tif (wrappedIndex != -1)\n\t\treturn @\"\";\n\t\n\t// If the value is inaccessible display \"<inaccessible>\"\n\tif (!wrappedValue)\n\t\treturn @\"<inaccessible>\";\n\t\n\tint value_count = wrappedValue->Count();\n\tstd::ostringstream outstream;\n\t\n\t// print values as a comma-separated list with strings quoted; halfway between print() and cat()\n\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t{\n\t\tEidosValue_SP element_value = wrappedValue->GetValueAtIndex(value_index, nullptr);\n\t\t\n\t\tif (value_index > 0)\n\t\t{\n\t\t\toutstream << \", \";\n\t\t\t\n\t\t\t// terminate the list at some reasonable point, otherwise we generate massively long strings for large vectors...\n\t\t\tif (value_index > 50)\n\t\t\t{\n\t\t\t\toutstream << \", ...\";\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\toutstream << *element_value;\n\t}\n\t\n\tstd::string &&out_string = outstream.str();\n\tNSString *outString = [NSString stringWithUTF8String:out_string.c_str()];\n\t\n\tif (isConstant)\n\t\treturn [[[NSAttributedString alloc] initWithString:outString attributes:[EidosValueWrapper dimmedAttrs]] autorelease];\n\t\n\treturn outString;\n}\n\n//\n//\tNSObject subclass overrides, to redefine equality\n//\n\n- (BOOL)isEqual:(id)anObject\n{\n\tif (self == anObject)\n\t\treturn YES;\n\tif (![anObject isMemberOfClass:[EidosValueWrapper class]])\n\t\treturn NO;\n\t\n\tEidosValueWrapper *otherWrapper = (EidosValueWrapper *)anObject;\n\t\n\tif (wrappedIndex != otherWrapper->wrappedIndex)\n\t\treturn NO;\n\tif (wrappedSiblingCount != otherWrapper->wrappedSiblingCount)\n\t\treturn NO;\n\tif (![wrappedName isEqualToString:otherWrapper->wrappedName])\n\t\treturn NO;\n\t\n\t// We call through to isEqualToWrapper: only if the parent wrapper is defined for both objects;\n\t// this is partly for speed, and partly because [nil isEqualToWrapper:nil] would give NO.\n\tEidosValueWrapper *otherWrapperParent = otherWrapper->parentWrapper;\n\t\n\tif (parentWrapper == otherWrapperParent)\n\t\treturn YES;\n\tif ((parentWrapper && !otherWrapperParent) || (!parentWrapper && otherWrapperParent))\n\t\treturn NO;\n\t\n\tif (![parentWrapper isEqualToWrapper:otherWrapperParent])\n\t\treturn NO;\n\t\n\treturn YES;\n}\n\n- (BOOL)isEqualToWrapper:(EidosValueWrapper *)otherWrapper\n{\n\t// Note that this method is missing the self==object test at the beginning!  This is because it\n\t// was already done by the caller; this method is not designed to be called externally!\n\t// Similarly, it does not check for object==nil, so it will crash if called with nil!\n\t\n\tif (wrappedIndex != otherWrapper->wrappedIndex)\n\t\treturn NO;\n\tif (wrappedSiblingCount != otherWrapper->wrappedSiblingCount)\n\t\treturn NO;\n\tif (![wrappedName isEqualToString:otherWrapper->wrappedName])\n\t\treturn NO;\n\t\n\t// We call through to isEqualToWrapper: only if the parent wrapper is defined for both objects;\n\t// this is partly for speed, and partly because [nil isEqualToWrapper:nil] would give NO.\n\tEidosValueWrapper *otherWrapperParent = otherWrapper->parentWrapper;\n\t\n\tif (parentWrapper == otherWrapperParent)\n\t\treturn YES;\n\tif ((parentWrapper && !otherWrapperParent) || (!parentWrapper && otherWrapperParent))\n\t\treturn NO;\n\t\n\tif (![parentWrapper isEqualToWrapper:otherWrapperParent])\n\t\treturn NO;\n\t\n\treturn YES;\n}\n\n- (NSUInteger)hash\n{\n\tNSUInteger hash = [wrappedName hash];\n\t\n\thash ^= wrappedIndex;\n\thash ^= (wrappedSiblingCount << 16);\n\t\n\tif (parentWrapper)\n\t\thash ^= ([parentWrapper hash] << 1);\n\t\n\t//NSLog(@\"hash for item named %@ == %lu\", wrappedName, (unsigned long)hash);\n\t\n\treturn hash;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosVariableBrowserController.h",
    "content": "//\n//  EidosVariableBrowserController.h\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/13/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n// BCH 4/7/2016: So we can build against the OS X 10.9 SDK\n#ifndef NS_DESIGNATED_INITIALIZER\n#define NS_DESIGNATED_INITIALIZER\n#endif\n\n\n@protocol EidosVariableBrowserControllerDelegate;\n\n\n/*\n \n EidosVariableBrowserController provides a prefab variable browser for Eidos.  It is integrated into\n EidosConsoleWindowController, so if you use that class, you get the variable browser for free.  If\n you build your own Eidos UI, you can use EidosVariableBrowserController directly.  In that case,\n you will need to extract it from EidosConsoleWindow.xib.\n \n */\n\n\n// Notifications sent to allow other objects that care about the visibility of the browser, such as toggle buttons, to update\nextern NSString *EidosVariableBrowserWillHideNotification;\nextern NSString *EidosVariableBrowserWillShowNotification;\n\n\n@interface EidosVariableBrowserController : NSObject\n{\n}\n\n// The delegate is often EidosConsoleWindowController, but can be your own delegate object\n@property (nonatomic, assign) IBOutlet NSObject<EidosVariableBrowserControllerDelegate> *delegate;\n\n// These properties are used by the nib, and are not likely to be used by clients\n@property (nonatomic, retain) IBOutlet NSWindow *browserWindow;\n@property (nonatomic, assign) IBOutlet NSOutlineView *browserOutline;\n@property (nonatomic, assign) IBOutlet NSTableColumn *symbolColumn;\n@property (nonatomic, assign) IBOutlet NSTableColumn *typeColumn;\n@property (nonatomic, assign) IBOutlet NSTableColumn *sizeColumn;\n@property (nonatomic, assign) IBOutlet NSTableColumn *valueColumn;\n\n// Normally EidosConsoleWindowController is instantiated in the EidosConsoleWindow.xib nib\n- (instancetype)init NS_DESIGNATED_INITIALIZER;\n\n// Show/hide the browser window\n- (void)showWindow;\n- (void)hideWindow;\n\n// Tell the controller that the browser window should be disposed of, not just closed; breaks retain loops\n- (void)cleanup;\n\n// Trigger a reload of the variable browser when symbols have changed\n- (void)reloadBrowser;\n\n// Make the browser show or hide; will send the appropriate notifications\n- (IBAction)toggleBrowserVisibility:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosVariableBrowserController.mm",
    "content": "//\n//  EidosVariableBrowserController.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 6/13/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"EidosVariableBrowserController.h\"\n#import \"EidosVariableBrowserControllerDelegate.h\"\n#import \"EidosValueWrapper.h\"\n\n#include \"eidos_property_signature.h\"\n#include \"eidos_symbol_table.h\"\n\n#include <sstream>\n\n\n// Notifications sent to allow other objects that care about the visibility of the browser, such as toggle buttons, to update\nNSString *EidosVariableBrowserWillHideNotification = @\"EidosVariableBrowserWillHide\";\nNSString *EidosVariableBrowserWillShowNotification = @\"EidosVariableBrowserWillShow\";\n\n\n@interface EidosVariableBrowserController () <NSWindowDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate>\n{\n@private\n\t// Wrappers for the currently displayed objects\n\tNSMutableArray *rootBrowserWrappers;\n\t\n\t// A set used to remember expanded items; see -reloadBrowser\n\tNSMutableSet *expandedSet;\n}\n@end\n\n\n@implementation EidosVariableBrowserController\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\t// We permanently keep a set of all elements that should be expanded; this persists across browser reloads, etc.\n\t\texpandedSet = [[NSMutableSet alloc] init];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t//NSLog(@\"EidosVariableBrowserController dealloc\");\n\t\n\t[self invalidateRootWrappers];\n\t\n\t[expandedSet release];\n\texpandedSet = nil;\n\t\n\t[self cleanup];\n\t\n\t[super dealloc];\n}\n\n- (void)setDelegate:(NSObject<EidosVariableBrowserControllerDelegate> *)newDelegate\n{\n\tif (newDelegate && ![newDelegate conformsToProtocol:@protocol(EidosVariableBrowserControllerDelegate)])\n\t\tNSLog(@\"Delegate %@ assigned to EidosVariableBrowserController %p does not conform to the EidosVariableBrowserControllerDelegate protocol!\", newDelegate, self);\n\t\n\t_delegate = newDelegate;\t// nonatomic, assign\n\t\n\t// Since our delegate defines what appears in our outline view, we need to reload when the delegate changes\n\t[self reloadBrowser];\n}\n\n- (void)showWindow\n{\n\tif (![_browserWindow isVisible])\n\t{\n\t\t[[NSNotificationCenter defaultCenter] postNotificationName:EidosVariableBrowserWillShowNotification object:self];\n\t\t[_browserWindow makeKeyAndOrderFront:nil];\n\t}\n}\n\n- (void)hideWindow\n{\n\tif ([_browserWindow isVisible])\n\t{\n\t\t[[NSNotificationCenter defaultCenter] postNotificationName:EidosVariableBrowserWillHideNotification object:self];\n\t\t[_browserWindow performClose:nil];\n\t}\n}\n\n- (void)cleanup\n{\n\t[[self browserWindow] setDelegate:nil];\n\t[self setBrowserWindow:nil];\n\t\n\t[self setDelegate:nil];\n}\n\n- (void)expandItemsInSet:(NSSet *)set belowItem:(id)parentItem\n{\n\t// BCH 4/7/2016: The -numberOfChildrenOfItem: and child:ofItem: methods of NSOutlineView do not exist in 10.9,\n\t// so we have to get the datasource of the outline view and get the information ourselves.\n\tBOOL respondsToNumberOfChildrenOfItem = [_browserOutline respondsToSelector:@selector(numberOfChildrenOfItem:)];\n\tBOOL respondsToChildOfItem = [_browserOutline respondsToSelector:@selector(child:ofItem:)];\n\tid <NSOutlineViewDataSource> datasource = ((respondsToNumberOfChildrenOfItem && respondsToChildOfItem) ? nil : [_browserOutline dataSource]);\n\t\n\tNSUInteger childCount = (respondsToNumberOfChildrenOfItem ? [_browserOutline numberOfChildrenOfItem:parentItem] : [datasource outlineView:_browserOutline numberOfChildrenOfItem:parentItem]);\n\t//NSLog(@\"after reload, outline has %lu children (%ld rows), expandedSet has %lu items\", (unsigned long)childCount, (long)[_browserOutline numberOfRows], (unsigned long)[expandedSet count]);\n\t\n\tfor (unsigned int i = 0; i < childCount; ++i)\n\t{\n\t\tid childItem = (respondsToChildOfItem ? [_browserOutline child:i ofItem:parentItem] : [datasource outlineView:_browserOutline child:i ofItem:parentItem]);\n\t\t\n\t\tif ([expandedSet containsObject:childItem])\t\t// uses -hash and -isEqual:, not pointer equality!\n\t\t{\n\t\t\tif ([_browserOutline isExpandable:childItem])\n\t\t\t{\n\t\t\t\t[_browserOutline expandItem:childItem];\n\t\t\t\t//NSLog(@\"      requested expansion for item with name %@ (%p, hash %lu)\", ((EidosValueWrapper *)childItem)->wrappedName, childItem, (unsigned long)[childItem hash]);\n\t\t\t\t\n\t\t\t\t// having expanded the item, we forget it from our set; this way if the user collapses it we won't re-expand it\n\t\t\t\t// note that if it stays expanded, it will be re-added to our set in reloadBrowser\n\t\t\t\t[expandedSet removeObject:childItem];\n\t\t\t\t\n\t\t\t\t[self expandItemsInSet:set belowItem:childItem];\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)reloadBrowser\n{\n\t// Reload symbols in our outline view.  This is complicated because we generally do a reload to a state that has zero items (while\n\t// script is executing) and then do another reload to a state that has items again (because the script is done executing), and we\n\t// want the expansion state to be preserved across that rather jumpy process.  The basic scheme is: (1) When we are about to\n\t// reload, we save all expanded items by going through all the rows of the outline view, getting the item for each row, finding\n\t// out if it is expanded, and if it is, keeping it in an NSSet – but we do this only if the outline view has items in it.  Then,\n\t// (2) After reloading, we go through each new item, see if it exists in our saved set (which uses -hash and -isEqual:, which\n\t// EidosValueWrapper implements for this purpose), and if so, we expand it and recurse down to check its children as well.\n\t\n\t// First, invalidate all of our old wrapped objects, to make sure that any invalid dereferences cause a clean crash\n\t[rootBrowserWrappers makeObjectsPerformSelector:@selector(invalidateWrappedValues)];\n\t\n\t// Then go through the outline view and save all items that are expanded\n\tNSUInteger rowCount = [_browserOutline numberOfRows];\n\t\n\t// BCH 26 Jan. 2020: On 10.15 NSOutlineView apparently caches the number of rows, so even though we would now return 0 from\n\t// outlineView:numberOfChildrenOfItem:, it gives us a non-zero count and then logs errors when we call itemAtRow:.  So now\n\t// we explicitly check that we actually have a symbol table, and if not, correct the number of rows to zero.\n\tif (![_delegate symbolTableForEidosVariableBrowserController:self])\n\t\trowCount = 0;\n\t\n\tif (rowCount > 0)\n\t{\n\t\t// The outline has items in it, so we will start a new set to save the expanded items\n\t\tfor (unsigned int i = 0; i < rowCount; ++i)\n\t\t{\n\t\t\tid rowItem = [_browserOutline itemAtRow:i];\n\t\t\t\n\t\t\t// Because we are in transition, it is possible for rowItem to be nil.  Specifically, the outline view may cache the\n\t\t\t// number of rows, and thus rowCount may be non-zero; and yet when a given row is asked for, the outline view may\n\t\t\t// then attempt to obtain it from the delegate (because NSOutlineView loads rows lazily), and the row may no longer\n\t\t\t// be there because the symbol table has changed (or been tossed entirely).  This is OK, actually.  Any row that\n\t\t\t// comes back as nil here is not expanded; a row doesn't get expanded if it hasn't even been loaded.  So rows that\n\t\t\t// come back as nil here can simply be ignored, since our only goal is to log a set of the expanded rows.  This\n\t\t\t// situation does, however, point out the trickiness inherent in asking NSOutlineView about its own state; it will\n\t\t\t// not necessarily answer in a self-consistent fashion!\n\t\t\t\n\t\t\tif (rowItem)\n\t\t\t{\n\t\t\t\tif ([_browserOutline isItemExpanded:rowItem])\n\t\t\t\t{\n\t\t\t\t\t[expandedSet addObject:rowItem];\n\t\t\t\t\t//NSLog(@\"remembering item with name %@ (%p, hash %lu) as expanded\", ((EidosValueWrapper *)rowItem)->wrappedName, rowItem, (unsigned long)[rowItem hash]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Clear out our wrapper arrays; the ones that are expanded are now retained by expandedSet\n\t[self invalidateRootWrappers];\n\t\n\t// Reload the outline view from scratch\n\t[_browserOutline reloadData];\n\t\n\t// Go through and expand items as needed\n\t[self expandItemsInSet:expandedSet belowItem:nil];\n}\n\n- (void)invalidateRootWrappers\n{\n\t[rootBrowserWrappers makeObjectsPerformSelector:@selector(releaseChildWrappers)];\n\t[rootBrowserWrappers release];\n\trootBrowserWrappers = nil;\t\t// set up to be recached\n}\n\n- (NSArray *)rootWrappers\n{\n\tif (!rootBrowserWrappers)\n\t{\n\t\t// If we don't have our root wrappers, set up the cache now\n\t\trootBrowserWrappers = [NSMutableArray new];\n\t\t\n\t\tEidosSymbolTable *symbols = [_delegate symbolTableForEidosVariableBrowserController:self];\n\t\t\n\t\t{\n\t\t\tstd::vector<std::string> readOnlySymbols = symbols->ReadOnlySymbols();\n\t\t\tint readOnlySymbolCount = (int)readOnlySymbols.size();\n\t\t\t\n\t\t\tfor (int index = 0; index < readOnlySymbolCount;++ index)\n\t\t\t{\n\t\t\t\tconst std::string &symbolName = readOnlySymbols[index];\n\t\t\t\tEidosValue_SP symbolValue = symbols->GetValueOrRaiseForSymbol(EidosStringRegistry::GlobalStringIDForString(symbolName));\n\t\t\t\tNSString *symbolObjcName = [NSString stringWithUTF8String:symbolName.c_str()];\n\t\t\t\tEidosValueWrapper *wrapper = [EidosValueWrapper wrapperForName:symbolObjcName parent:nil value:symbolValue];\n\t\t\t\t\n\t\t\t\t[rootBrowserWrappers addObject:wrapper];\n\t\t\t}\n\t\t}\n\t\t\n\t\t{\n\t\t\tstd::vector<std::string> readWriteSymbols = symbols->ReadWriteSymbols();\n\t\t\tint readWriteSymbolCount = (int)readWriteSymbols.size();\n\t\t\t\n\t\t\tfor (int index = 0; index < readWriteSymbolCount;++ index)\n\t\t\t{\n\t\t\t\tconst std::string &symbolName = readWriteSymbols[index];\n\t\t\t\tEidosValue_SP symbolValue = symbols->GetValueOrRaiseForSymbol(EidosStringRegistry::GlobalStringIDForString(symbolName));\n\t\t\t\tNSString *symbolObjcName = [NSString stringWithUTF8String:symbolName.c_str()];\n\t\t\t\tEidosValueWrapper *wrapper = [EidosValueWrapper wrapperForName:symbolObjcName parent:nil value:symbolValue];\n\t\t\t\t\n\t\t\t\t[rootBrowserWrappers addObject:wrapper];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn rootBrowserWrappers;\n}\n\n- (IBAction)toggleBrowserVisibility:(id)sender\n{\n\tif ([_browserWindow isVisible])\n\t\t[self hideWindow];\n\telse\n\t\t[self showWindow];\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\tif (sel == @selector(toggleBrowserVisibility:))\n\t\t[menuItem setTitle:([_browserWindow isVisible] ? @\"Hide Variable Browser\" : @\"Show Variable Browser\")];\n\t\n\treturn YES;\n}\n\n\n//\n//\tNSWindow delegate methods\n//\n#pragma mark -\n#pragma mark NSWindow delegate\n\n- (void)windowWillClose:(NSNotification *)notification\n{\n\tNSWindow *closingWindow = [notification object];\n\t\n\tif (closingWindow == _browserWindow)\n\t\t[[NSNotificationCenter defaultCenter] postNotificationName:EidosVariableBrowserWillHideNotification object:self];\n}\n\n\n//\n//\tNSOutlineView datasource / delegate methods\n//\n#pragma mark -\n#pragma mark NSOutlineView delegate\n\n- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item\n{\n\tif ([_delegate symbolTableForEidosVariableBrowserController:self])\n\t{\n\t\tNSArray *wrapperArray = (item ? [(EidosValueWrapper *)item childWrappers] : [self rootWrappers]);\n\t\tNSInteger count = [wrapperArray count];\n\t\t\n\t\t//NSLog(@\"count == %ld\", (long)count);\n\t\treturn count;\n\t}\n\t\n\t//NSLog(@\"count == 0\");\n\treturn 0;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item\n{\n\tif ([_delegate symbolTableForEidosVariableBrowserController:self])\n\t{\n\t\tNSArray *wrapperArray = (item ? [(EidosValueWrapper *)item childWrappers] : [self rootWrappers]);\n\t\tid child = [wrapperArray objectAtIndex:index];\n\t\t\n\t\t//NSLog(@\"child at index %ld == %@\", (long)index, child);\n\t\treturn child;\n\t}\n\t\n\t//NSLog(@\"child at index %ld == NULL\", (long)index);\n\treturn (id _Nonnull)nil;\t// get rid of the static analyzer warning\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item\n{\n\tif (item)\n\t\treturn [(EidosValueWrapper *)item isExpandable];\n\t\n\treturn NO;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item\n{\n\tif (item)\n\t{\n\t\tEidosValueWrapper *wrapper = (EidosValueWrapper *)item;\n\t\t\n\t\tif (tableColumn == _symbolColumn)\n\t\t\treturn [wrapper displaySymbol];\n\t\tif (tableColumn == _typeColumn)\n\t\t\treturn [wrapper displayType];\n\t\tif (tableColumn == _sizeColumn)\n\t\t\treturn [wrapper displaySize];\n\t\tif (tableColumn == _valueColumn)\n\t\t\treturn [wrapper displayValue];\n\t}\n\t\n\treturn @\"\";\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/EidosVariableBrowserControllerDelegate.h",
    "content": "//\n//  EidosVariableBrowserControllerDelegate.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n@class EidosVariableBrowserController;\nclass EidosSymbolTable;\n\n\n/*\n \n This is an Objective-C++ header, and so can only be included by Objective-C++ compilations (.mm files instead of .m files).\n You should not need to include this header in your .h files, since you can declare protocol conformance in a class-continuation\n category in your .m file, so only classes that conform to this protocol should need to be Objective-C++.\n \n EidosVariableBrowserControllerDelegate is a protocol for the delegate of an EidosVariableBrowserController.  The variable\n browser controller gets the symbols to display from its delegate; if you are using EidosConsoleWindowController it typically\n acts as the delegate for the variable browser, but if you are building your own Eidos user interface you will need to provide\n this delegate method.\n \n */\n\n\n@protocol EidosVariableBrowserControllerDelegate\n@required\n\n- (EidosSymbolTable *)symbolTableForEidosVariableBrowserController:(EidosVariableBrowserController *)browserController;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "EidosScribe/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_16x16.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_16x16@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_32x32.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_32x32@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_128x128.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_128x128@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_256x256.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_256x256@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_512x512.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"AppIcon_512x512@2x.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "EidosScribe/main.m",
    "content": "//\n//  main.m\n//  EidosScribe\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n\treturn NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n\n"
  },
  {
    "path": "PARALLEL",
    "content": "This file contains unreleased/unannounced changes for parallelization, in addition to those listed in VERSIONS.  It will be merged into VERSIONS once parallel SLiM is released publicly.\n\nPARALLEL changes (now in the master branch, but disabled):\n\tTO DO: the openmp branch had changes to travis.yml to test the openmp branch, which should be replicated somehow for GitHub Actions:\n\t\tusing macos xcode11.6/clang and linux bionic/gcc\n\t\ton osx, \"brew install libomp;\" \"ls -l /usr/local/opt/libomp/include/omp.h;\" \"ls -l /usr/local/include;\"\n\t\tnote the paths for the headers/lib are likely different, so that will require a bit of legwork\n\tupdated SLiM.xcodeproj for OpenMP configuration:\n\t\tduplicate the entire SLiM directory to SLiM_temp, open the SLiM.xcodeproj file in the copy, rename it in the Project Navigator to \"SLiM_OpenMP\", copy it back into the SLiM folder and delete the rest of the copy\n\t\tuse grep to find \"SLiM_temp\" inside files in the new SLiM_OpenMP.xcodeproj and fix them to refer to the correct directory (might be just one, or none)\n\t\tadd system header search path for targets eidos_multi and SLiM_multi, in Build Settings: /usr/local/include/ (non-recursive)\n\t\tadd library search path for targets eidos_multi and SLiM_multi, in Build Settings: /usr/local/lib/ (non-recursive)\n\t\tadd link to binary library, under \"Build Phases\" (Link Binary With Libraries) on targets eidos_multi and SLiM_multi, by dragging in /usr/local/lib/libomp.dylib\n\t\tadd to Other C Flags and Other C++ Flags for targets eidos_multi and SLiM_multi, in Build Settings: -Xclang and -fopenmp\n\t\tdisable library validation for targets eidos_multi and SLiM_multi, in Signing & Capabilities: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_disable-library-validation\n\t\tset Enable Index-While-Building Functionality to NO in Build Settings on targets eidos_multi and SLiM_multi\n\t\tdisable Link-Time Optimization, which appears to be incompatible with OpenMP\n\t\tswitched \"Build Active Architecture Only\" in Build Settings to YES for Release builds, for targets eidos_multi and SLiM_multi, because the older libomp.dylib builds do not have arm64 in them\n\t\tsee http://antonmenshov.com/2017/09/09/clang-openmp-setup-in-xcode/\n\t\tadded -Rpass=\"loop|vect\" -Rpass-missed=\"loop|vect\" -Rpass-analysis=\"loop|vect\" to Other C++ Flags for eidos_multi, to aid in optimization work\n\t\tadded \"-fno-math-errno\" to the project-level Other C++ Flags, to match the main project\n\t\tadded $(OTHER_CPLUSPLUSFLAGS) to that build setting for slim_multi and eidos_multi, to inherit from the project's settings\n\t\trequire 10.13 or later for eidos_multi and slim_multi, since that's the macOS version that the R libomp packages target\n\t\tadded SLiMguiLegacy_multi and EidosScribe_multi targets/schemes to the project for debugging/testing purposes; not intended for end users!\n\tmodify CMakeLists.txt to add a \"PARALLEL\" flag that can be set to \"ON\" to enable OpenMP with the -fopenmp flag\n\tmodify CMakeLists.txt to add /usr/local/include to all targets (through GSL_INCLUDES, which should maybe get cleaned up somehow)\n\tmodify CMakeLists.txt to build executables eidos_multi and slim_multi when PARALLEL is ON, and to link in libomp\n\tdisable parallel builds of EidosScribe, SLiMgui, and SLiMguiLegacy with #error directives; parallelization is for the command line only (active threads peg the CPU, passive threads are slower than single-threaded)\n\tadd a command-line option, -maxThreads <n>, to control the maximum number of threads used in OpenMP\n\tadd a header eidos_openmp.h that should be used instead of #include \"omp.h\", providing various useful definitions etc.\n\tadd an initialization function for OpenMP, Eidos_WarmUpOpenMP(), that must be called when warming up; sets various options, logs diagnostic info\n\tset default values for OMP_WAIT_POLICY (active) and OMP_PROC_BIND (false) and OMP_DYNAMIC (false) for slim and eidos\n\tadd THREAD_SAFETY_CHECK() convention for marking areas that are known not to be thread-safe, such as due to use of statics or globals\n\tadd gEidosMaxThreads global that has the max number of threads for the session (for pre-allocating per-thread data structures)\n\tcreate per-thread SparseVector pools to allow high-scalability parallelization of spatial interactions\n\tadd parallel sorting code - quicksort and mergesort, rather experimental at this point, just early work\n\tcreate per-thread random number generators to allow parallelization of code that involves RNG usage\n\tparallelize dnorm(), rbinom(), rdunif(), rexp(), rnorm(), rpois(), runif()\n\tparallelize tallying mutation refcounts, for the optimized fast case\n\tparallelize fitness evaluation for mutations, when there are no mutationEffect() or fitnessEffect() callbacks\n\tparallelize non-mutation-based fitness evaluation (i.e., only fitnessScaling values)\n\tparallelize some minor tick cycle bookkeeping: incrementing individual ages, clearing the migrant flag\n\tparallelize the viability/survival tick cycle stage's survival evaluation (without callbacks)\n\tparallelize localPopulationDensity(), clippedIntegral(), and neighborCount()\n\tadd gEidosNumThreads global that has the currently requested number of threads (usually equal to gEidosMaxThreads)\n\tadd functions to Eidos to support parallel execution: parallelGetNumThreads(), parallelGetMaxThreads(), and parallelSetNumThreads()\n\tadd unit tests for parallelized functions in Eidos, comparing against the same functions non-parallel\n\tadd nowait clause on parallel for loops that would otherwise have a double barrier\n\tshift to allocating per-thread RNGs in parallelized allocations, so \"first touch\" places each RNG in memory close to that thread's core\n\tswitch to dynamic scheduling for rbinom() and rdunif(), which seem to need it for unclear reasons\n\tuse a minimum chunk size of 16 for all dynamic schedules; problems that parallelize should always be at least that big, I imagine\n\t\tthe exception is countOfMutationsOfType() / sumOfMutationsOfType() and similar, because they do so much work per iteration that they can be worth going parallel even for two iterations\n\t\tnote that we never use schedule(guided) because its implementation in GCC is brain-dead; see https://stackoverflow.com/a/43047074/2752221\n\tswitch to OMP_PROC_BIND == true by default; keep threads with the data they're working on, recommended practice\n\tparallelize more Eidos math functions: abs(float), ceil(), exp(float), floor(), log(float), log10(float), log2(float), round(), sqrt(float), trunc()\n\tparallelize Eidos min/max functions: max(int), max(float), min(int), min(float), pmax(int), pmax(float), pmin(int), pmin(float)\n\tparallelize match(), tabulate(), sample (int/float/object, replace=T, weights=NULL), mean(l/i/f)\n\tparallelize Individual -relatedness(), -countOfMutationsOfType(), -setSpatialPosition(); Species -individualsWithPedigreeIDs()\n\tparallelize Subpopulation -pointInBounds(), -pointReflected(), -pointStopped(), pointPeriodic(), pointUniform()\n\tparallelize Haplosome -containsMarkerMutation()\n\tchange how RNG seeding works, for single-threaded and multi-threaded runs: use /dev/random to generate initial seeds, and for multi-threaded runs, use /dev/random for seeds for all threads beyond thread 0\n\tparallelize Haplosome -countOfMutationsOfType(), Subpopulation -spatialMapValue() and -sampleIndividuals()\n\tadd unit tests for various SLiM methods that have been parallelized\n\tparallelize InteractionType nearestNeighbors(), nearestInteractingNeighbors(), drawByStrength() by adding a returnDict parameter that lets the user get a Dictionary as a result, with one entry per receiver\n\t\ttheir \"receiver\" parameter is no longer required to be singleton (when returnDict == T), and their return value is now just \"object\" since it can be Individual or Dictionary\n\toverhaul the internal MutationRun design to allow it to be used multithreaded - get rid of refcounting, switch to usage tallying\n\tparallelize offspring generation in WF models, when no callbacks (mateChoice(), modifyChild(), recombination(), mutation()) are active; no tree-seq, no cloning\n\tparallelize offspring generation in WF model: add support for cloning\n\tparallelize tallying of mutation runs, clearing of parental haplosomes at the end of WF model ticks, and mutation run uniquing\n\tadd support for parallel reproduction when a non-default stacking policy is in use\n\tadd support for parallel reproduction with tree-sequence recording\n\tadd parallel reproduction in nonWF models, with no callbacks (recombination(), mutation()) active - modifyChild() callbacks are legal but cannot access child haplosomes since they are deferred\n\t\tthis is achieved by passing defer=T to addCrossed(), addCloned(), addSelfed(), addMultiRecombinant(), or addRecombinant()\n\tthread-safety work - break in backward reproducibility for scripts that use a type 's' DFE, because the code path for that shifted\n\talgorithm change for nearestNeighbors() and nearestNeighborsOfPoint(), when count is >1 and <N; the old algorithm was not thread-safe, and was inefficient; breaks backward reproducibility for the relevant case\n\t\tthe break in backward reproducibility is because the old algorithm returned the neighbors in a scrambled order, whereas the new algorithm returns them in sorted order; the order is not documented, so both are compliant\n\tadd max thread counts for each parallel loop, allowing flexible customization both by Eidos and by the user\n\ttweak the semantics of parallelSetNumThreads(): an integer requests that exact number of threads, whereas NULL requests \"up to\" the max number of threads (the default behavior)\n\t\tadd gEidosNumThreadsOverride flag indicating whether the number of threads has been overridden explicitly\n\tadd parallelSetTaskThreadCounts() function to set per-task thread counts, and parallelGetTaskThreadCounts() to get them\n\tadd recipe 22.7, Parallelizing nonWF reproduction and spatial interactions\n\tadd internal EidosBenchmark facility for timing of internal loops, for benchmarking of parallelization scaling\n\tadd a command-line option, -perTaskThreads, to let the user control how many threads to use for different tasks (if not overridden)\n\tparallelize sorting, where possible/efficient, add requisite per-task thread count keys\n\tparallelize edge table sorting during simplification, add requisite per-task thread count keys\n\n"
  },
  {
    "path": "QtSLiM/QtSLiM.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2019-07-10T21:56:47\n#\n#-------------------------------------------------\n\nQT       += core gui opengl\n\ngreaterThan(QT_MAJOR_VERSION, 4): QT += widgets\n\n# OpenGLWidget moved to openglwidgets in Qt6\ngreaterThan(QT_MAJOR_VERSION, 5): QT += openglwidgets\n\n# Note that the target is SLiMgui now, but the old QtSLiM name lives on throughout the project\nTARGET = SLiMgui\nTEMPLATE = app\n\n# qmake defines to set up a macOS bundle application build\nCONFIG += app_bundle\nQMAKE_INFO_PLIST = QtSLiM_Info.plist\nICON = QtSLiM_AppIcon.icns\nQMAKE_TARGET_BUNDLE_PREFIX = \"org.messerlab\"\nQMAKE_BUNDLE = \"SLiMgui\"\t\t# This governs the location of our prefs, which we keep under org.messerlab.SLiMgui\nVERSION = 5.2\n\ndocIconFiles.files = $$PWD/QtSLiM_DocIcon.icns\ndocIconFiles.path = Contents/Resources\nQMAKE_BUNDLE_DATA += docIconFiles\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\n# BCH 4/8/2026: I force AVX2 and FMA on for x86_64 builds (true since 2013), and NEON on for ARM64 builds\n# (true since forever), without the compiler capability testing done in CMakeFlags.txt.  This is a hack;\n# if it breaks things for an end user they can build with CMake instead or disable these defines.  Note\n# that building in Qt Creator is not the primary supported build method for SLiM, and is probably mostly\n# used only by me; I just want this on for development.  See https://github.com/MesserLab/SLiM/issues/598.\n# Note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro.\nmessage(\"Target architecture is: $${QMAKE_TARGET.arch}\")\n\nQMAKE_CFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\nQMAKE_CXXFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\n\nQMAKE_CFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\nQMAKE_CXXFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\n\nQMAKE_CFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\nQMAKE_CXXFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\n\n\n# Get the current Git SHA-1 and put it into a define; see https://stackoverflow.com/questions/27041573/print-git-hash-in-qt-as-macro-created-at-compile-time\n# Note that this only runs when qmake runs!  It would be nice to have a solution more like the one we use under CMake.\nGIT_HASH=\"\\\\\\\"$$system(git -C \\\"\"$$_PRO_FILE_PWD_\"\\\" rev-parse HEAD)\\\\\\\"\"\nDEFINES += GIT_SHA1=$$GIT_HASH\n#message(Git SHA-1 == $$GIT_HASH)\n\n\n# Warn and error on usage of deprecated Qt APIs; see also -Wno-deprecated-declarations below\n# These flags are for development; we don't want production builds warning or erroring due to deprecation\n# DEFINES += QT_DEPRECATED_WARNINGS\t\t\t\t\t# uncomment this to get warnings about deprecated APIs\n# DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x050F00    # disables all the APIs deprecated before Qt 5.15.0\n# DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060500    # disables all the APIs deprecated before Qt 6.5.0\n\n\n# Bring in flag settings from the environment; see https://stackoverflow.com/a/17578151/2752221\n# Right now I do this only in QtSLiM.pro, to bring a CXXFLAGS setting in from GitHub Actions, but\n# these lines could be added to the other .pro files too if that proves useful.\nQMAKE_CXXFLAGS += $$(CXXFLAGS)\nQMAKE_CFLAGS += $$(CFLAGS)\n\n\n# Set up to build QtSLiM; note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro\nDEFINES += EIDOS_GUI\nDEFINES += SLIMGUI=1\n\n\n# Uncomment this define to disable the use of OpenGL in SLiMgui completely.  This, plus removing the\n# link dependency on openglwidgets, should allow you to build SLiMgui without linking OpenGL at all.\n# I don't expect end users to need to do this; it is for testing purposes, to ensure than the code\n# path used when OpenGL is disabled in Preferences does not inadvertently make any OpenGL calls.\n#DEFINES += SLIM_NO_OPENGL\n\n\ngreaterThan(QT_MAJOR_VERSION, 5) {\n\t# For Qt6 we require C++17 (because Qt6 requires it), but don't use it ourselves\n\tCONFIG += c++17\n\tCONFIG += c17\n\tQMAKE_CFLAGS += -std=c17\n} else {\n\t# For Qt5 we require just C++11\n\tCONFIG += c++11\n\tCONFIG += c11\n\tQMAKE_CFLAGS += -std=c11\n}\n\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\nQMAKE_CXXFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CXXFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\n\n# get rid of warnings for deprecated declarations (not sure why commenting out QT_DEPRECATED_WARNINGS above is insufficient...)\nQMAKE_CXXFLAGS += -Wno-deprecated-declarations\n\n# other warnings we want\nQMAKE_CXXFLAGS += -Wshadow\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CXXFLAGS += -Wno-unknown-pragmas -Wno-attributes -Wno-unused-parameter\n}\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n# core library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -lcore\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -lcore\nelse:unix: LIBS += -L$$OUT_PWD/../core/ -lcore\nINCLUDEPATH += $$PWD/../core\nDEPENDPATH += $$PWD/../core\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/libcore.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/libcore.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/core.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/core.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../core/libcore.a\n\n# eidos library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../eidos/release/ -leidos\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../eidos/debug/ -leidos\nelse:unix: LIBS += -L$$OUT_PWD/../eidos/ -leidos\nINCLUDEPATH += $$PWD/../eidos\nDEPENDPATH += $$PWD/../eidos\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/release/libeidos.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/debug/libeidos.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/release/eidos.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/debug/eidos.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../eidos/libeidos.a\n\n# tskit library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../treerec/tskit/release/ -ltskit\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../treerec/tskit/debug/ -ltskit\nelse:unix: LIBS += -L$$OUT_PWD/../treerec/tskit/ -ltskit\nINCLUDEPATH += $$PWD/../treerec/tskit $$PWD/../treerec $$PWD/../treerec/tskit/kastore\nDEPENDPATH += $$PWD/../treerec/tskit\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/release/libtskit.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/debug/libtskit.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/release/tskit.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/debug/tskit.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/libtskit.a\n\n# gsl library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../gsl/release/ -lgsl\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../gsl/debug/ -lgsl\nelse:unix: LIBS += -L$$OUT_PWD/../gsl/ -lgsl\nINCLUDEPATH += $$PWD/../gsl $$PWD/../gsl/blas $$PWD/../gsl/block $$PWD/../gsl/cblas $$PWD/../gsl/cdf\nINCLUDEPATH += $$PWD/../gsl/complex $$PWD/../gsl/err $$PWD/../gsl/interpolation $$PWD/../gsl/linalg $$PWD/../gsl/matrix\nINCLUDEPATH += $$PWD/../gsl/randist $$PWD/../gsl/rng $$PWD/../gsl/specfunc $$PWD/../gsl/sys $$PWD/../gsl/vector\nDEPENDPATH += $$PWD/../gsl\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/libgsl.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/libgsl.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/gsl.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/gsl.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../gsl/libgsl.a\n\n# eidos_zlib library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../eidos_zlib/release/ -leidos_zlib\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../eidos_zlib/debug/ -leidos_zlib\nelse:unix: LIBS += -L$$OUT_PWD/../eidos_zlib/ -leidos_zlib\nINCLUDEPATH += $$PWD/../eidos_zlib $$PWD/../eidos_zlib/blas $$PWD/../eidos_zlib/block $$PWD/../eidos_zlib/cblas $$PWD/../eidos_zlib/cdf\nINCLUDEPATH += $$PWD/../eidos_zlib/complex $$PWD/../eidos_zlib/err $$PWD/../eidos_zlib/linalg $$PWD/../eidos_zlib/matrix\nINCLUDEPATH += $$PWD/../eidos_zlib/randist $$PWD/../eidos_zlib/rng $$PWD/../eidos_zlib/specfunc $$PWD/../eidos_zlib/sys $$PWD/../eidos_zlib/vector\nDEPENDPATH += $$PWD/../eidos_zlib\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/release/libeidos_zlib.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/debug/libeidos_zlib.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/release/eidos_zlib.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/debug/eidos_zlib.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/libeidos_zlib.a\n\n\nSOURCES += \\\n    ../cmake/GitSHA1_qmake.cpp \\\n    QtSLiMChromosomeWidget_GL.cpp \\\n    QtSLiMChromosomeWidget_QT.cpp \\\n    QtSLiMDebugOutputWindow.cpp \\\n    QtSLiMGraphView_1DPopulationSFS.cpp \\\n    QtSLiMGraphView_1DSampleSFS.cpp \\\n    QtSLiMGraphView_2DPopulationSFS.cpp \\\n    QtSLiMGraphView_2DSampleSFS.cpp \\\n    QtSLiMGraphView_AgeDistribution.cpp \\\n    QtSLiMGraphView_CustomPlot.cpp \\\n    QtSLiMGraphView_LifetimeReproduction.cpp \\\n    QtSLiMGraphView_MultispeciesPopSizeOverTime.cpp \\\n    QtSLiMGraphView_PopFitnessDist.cpp \\\n    QtSLiMGraphView_PopSizeOverTime.cpp \\\n    QtSLiMGraphView_SubpopFitnessDists.cpp \\\n    QtSLiMHaplotypeManager_GL.cpp \\\n    QtSLiMHaplotypeManager_QT.cpp \\\n    QtSLiMIndividualsWidget_GL.cpp \\\n    QtSLiMIndividualsWidget_QT.cpp \\\n    QtSLiMOpenGL.cpp \\\n    QtSLiM_Plot.cpp \\\n    main.cpp \\\n    QtSLiMWindow.cpp \\\n    QtSLiMAppDelegate.cpp \\\n    QtSLiMWindow_glue.cpp \\\n    QtSLiMChromosomeWidget.cpp \\\n    QtSLiMExtras.cpp \\\n    QtSLiMPopulationTable.cpp \\\n    QtSLiMIndividualsWidget.cpp \\\n    QtSLiMEidosPrettyprinter.cpp \\\n    QtSLiMAbout.cpp \\\n    QtSLiMPreferences.cpp \\\n    QtSLiMSyntaxHighlighting.cpp \\\n    QtSLiMFindRecipe.cpp \\\n    QtSLiMHelpWindow.cpp \\\n    QtSLiMScriptTextEdit.cpp \\\n    QtSLiMEidosConsole.cpp \\\n    QtSLiMEidosConsole_glue.cpp \\\n    QtSLiMConsoleTextEdit.cpp \\\n    QtSLiM_SLiMgui.cpp \\\n    QtSLiMTablesDrawer.cpp \\\n    QtSLiMFindPanel.cpp \\\n    QtSLiMGraphView.cpp \\\n    QtSLiMGraphView_FixationTimeHistogram.cpp \\\n    QtSLiMGraphView_LossTimeHistogram.cpp \\\n    QtSLiMGraphView_PopulationVisualization.cpp \\\n    QtSLiMGraphView_FitnessOverTime.cpp \\\n    QtSLiMGraphView_FrequencyTrajectory.cpp \\\n    QtSLiMHaplotypeManager.cpp \\\n    QtSLiMHaplotypeOptions.cpp \\\n    QtSLiMHaplotypeProgress.cpp \\\n    QtSLiMVariableBrowser.cpp\n\nHEADERS += \\\n    QtSLiMDebugOutputWindow.h \\\n    QtSLiMGraphView_1DPopulationSFS.h \\\n    QtSLiMGraphView_1DSampleSFS.h \\\n    QtSLiMGraphView_2DPopulationSFS.h \\\n    QtSLiMGraphView_2DSampleSFS.h \\\n    QtSLiMGraphView_AgeDistribution.h \\\n    QtSLiMGraphView_CustomPlot.h \\\n    QtSLiMGraphView_LifetimeReproduction.h \\\n    QtSLiMGraphView_MultispeciesPopSizeOverTime.h \\\n    QtSLiMGraphView_PopFitnessDist.h \\\n    QtSLiMGraphView_PopSizeOverTime.h \\\n    QtSLiMGraphView_SubpopFitnessDists.h \\\n    QtSLiMOpenGL.h \\\n    QtSLiMOpenGL_Emulation.h \\\n    QtSLiMWindow.h \\\n    QtSLiMAppDelegate.h \\\n    QtSLiMChromosomeWidget.h \\\n    QtSLiMExtras.h \\\n    QtSLiMPopulationTable.h \\\n    QtSLiMIndividualsWidget.h \\\n    QtSLiMEidosPrettyprinter.h \\\n    QtSLiMAbout.h \\\n    QtSLiMPreferences.h \\\n    QtSLiMSyntaxHighlighting.h \\\n    QtSLiMFindRecipe.h \\\n    QtSLiMHelpWindow.h \\\n    QtSLiMScriptTextEdit.h \\\n    QtSLiMEidosConsole.h \\\n    QtSLiMConsoleTextEdit.h \\\n    QtSLiM_Plot.h \\\n    QtSLiM_SLiMgui.h \\\n    QtSLiMTablesDrawer.h \\\n    QtSLiMFindPanel.h \\\n    QtSLiMGraphView.h \\\n    QtSLiMGraphView_FixationTimeHistogram.h \\\n    QtSLiMGraphView_LossTimeHistogram.h \\\n    QtSLiMGraphView_PopulationVisualization.h \\\n    QtSLiMGraphView_FitnessOverTime.h \\\n    QtSLiMGraphView_FrequencyTrajectory.h \\\n    QtSLiMHaplotypeManager.h \\\n    QtSLiMHaplotypeOptions.h \\\n    QtSLiMHaplotypeProgress.h \\\n    QtSLiMVariableBrowser.h\n\nFORMS += \\\n    QtSLiMDebugOutputWindow.ui \\\n    QtSLiMWindow.ui \\\n    QtSLiMAbout.ui \\\n    QtSLiMPreferences.ui \\\n    QtSLiMFindRecipe.ui \\\n    QtSLiMHelpWindow.ui \\\n    QtSLiMEidosConsole.ui \\\n    QtSLiMTablesDrawer.ui \\\n    QtSLiMFindPanel.ui \\\n    QtSLiMHaplotypeOptions.ui \\\n    QtSLiMHaplotypeProgress.ui \\\n    QtSLiMVariableBrowser.ui\n\n# Deploy to /Applications on macOS, /usr/local/bin on Linux/Un*x\nmacx: target.path = /Applications\nelse: unix:!android: target.path = /usr/local/bin\n!isEmpty(target.path): INSTALLS += target\n\nRESOURCES += \\\n    buttons.qrc \\\n    buttons_DARK.qrc \\\n    icons.qrc \\\n    recipes.qrc \\\n    help.qrc\n\nDISTFILES += \\\n\tQtSLiM_AppIcon.icns \\\n\tQtSLiM_DocIcon.icns\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMAbout.cpp",
    "content": "//\n//  QtSLiMAbout.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/2/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMAbout.h\"\n#include \"ui_QtSLiMAbout.h\"\n\n#include \"QtSLiMAppDelegate.h\"\n\n#include \"slim_globals.h\"\n\n// Get our Git commit SHA-1, as C string \"g_GIT_SHA1\"\n#include \"../cmake/GitSHA1.h\"\n\n\nQtSLiMAbout::QtSLiMAbout(QWidget *p_parent) : QDialog(p_parent), ui(new Ui::QtSLiMAbout)\n{\n    ui->setupUi(this);\n    \n    // change the app icon to our multi-size app icon for best results\n    ui->appIconButton->setIcon(qtSLiMAppDelegate->applicationIcon());\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // disable resizing\n    layout()->setSizeConstraint(QLayout::SetFixedSize);\n    setSizeGripEnabled(false);\n    \n    // fix version number; we incorporate the Git commit number here too, if we can\n    QString versionString(\"version \" + QString(SLIM_VERSION_STRING) + \" (Qt \" + QT_VERSION_STR + \", Git SHA-1 \");\n    QString gitSHA(g_GIT_SHA1);\n    \n    if (gitSHA.startsWith(\"unknown\"))\n        versionString.append(\"unknown\");\n    else if (gitSHA == \"GITDIR-NOTFOUND\")\n        versionString.append(\"not available\");\n    else\n        versionString.append(gitSHA.left(7));  // standard truncation is the last seven hex digits of the SHA-1\n    \n    versionString.append(\")\");\n    \n    ui->versionLabel->setText(versionString);\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nQtSLiMAbout::~QtSLiMAbout()\n{\n    delete ui;\n}\n"
  },
  {
    "path": "QtSLiM/QtSLiMAbout.h",
    "content": "//\n//  QtSLiMAbout.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/2/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMABOUT_H\n#define QTSLIMABOUT_H\n\n#include <QDialog>\n\nnamespace Ui {\nclass QtSLiMAbout;\n}\n\nclass QtSLiMAbout : public QDialog\n{\n    Q_OBJECT\n    \npublic:\n    explicit QtSLiMAbout(QWidget *p_parent = nullptr);\n    ~QtSLiMAbout();\n    \nprivate:\n    Ui::QtSLiMAbout *ui;\n};\n\n#endif // QTSLIMABOUT_H\n"
  },
  {
    "path": "QtSLiM/QtSLiMAbout.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMAbout</class>\n <widget class=\"QDialog\" name=\"QtSLiMAbout\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>620</width>\n    <height>554</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>20</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>20</number>\n     </property>\n     <item>\n      <widget class=\"QtSLiMIconView\" name=\"appIconButton\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>128</width>\n         <height>128</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>128</width>\n         <height>128</height>\n        </size>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"icons.qrc\">\n         <normaloff>:/icons/AppIcon128.png</normaloff>:/icons/AppIcon128.png</iconset>\n       </property>\n       <property name=\"iconSize\">\n        <size>\n         <width>128</width>\n         <height>128</height>\n        </size>\n       </property>\n       <property name=\"flat\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n       <item>\n        <spacer name=\"verticalSpacer_4\">\n         <property name=\"orientation\">\n          <enum>Qt::Vertical</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>20</width>\n           <height>10</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n       <item>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n         <property name=\"spacing\">\n          <number>3</number>\n         </property>\n         <item>\n          <widget class=\"QLabel\" name=\"label_5\">\n           <property name=\"enabled\">\n            <bool>true</bool>\n           </property>\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"font\">\n            <font>\n             <weight>75</weight>\n             <bold>true</bold>\n            </font>\n           </property>\n           <property name=\"text\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:15pt;&quot;&gt;SLiMgui : A graphical user interface for SLiM&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"verticalSpacer\">\n           <property name=\"orientation\">\n            <enum>Qt::Vertical</enum>\n           </property>\n           <property name=\"sizeType\">\n            <enum>QSizePolicy::Fixed</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>20</width>\n             <height>8</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"label_4\">\n           <property name=\"text\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Messer Lab, Cornell University, &lt;a href=&quot;http://messerlab.org/slim/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://messerlab.org/slim/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"openExternalLinks\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"label_3\">\n           <property name=\"text\">\n            <string>Copyright © 2016–2025 Benjamin C. Haller.  All rights reserved.</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"verticalSpacer_2\">\n           <property name=\"orientation\">\n            <enum>Qt::Vertical</enum>\n           </property>\n           <property name=\"sizeType\">\n            <enum>QSizePolicy::Fixed</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>20</width>\n             <height>8</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"label_2\">\n           <property name=\"text\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By Benjamin C. Haller and Philipp W. Messer.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"openExternalLinks\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <spacer name=\"verticalSpacer_3\">\n         <property name=\"orientation\">\n          <enum>Qt::Vertical</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>20</width>\n           <height>10</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"label_6\">\n       <property name=\"text\">\n        <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;\n&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;\np, li { white-space: pre-wrap; }\n&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.SF NS Text'; font-size:12pt; font-weight:400; font-style:normal;&quot;&gt;\n&lt;p style=&quot; margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;SLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.&lt;/p&gt;\n&lt;p style=&quot; margin-top:10px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;SLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.&lt;/p&gt;\n&lt;p style=&quot; margin-top:10px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;You should have received a copy of the GNU General Public License along with SLiM. If not, see &lt;a href=&quot;http://www.gnu.org/licenses/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.gnu.org/licenses/&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;\n&lt;p style=&quot; margin-top:10px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Please see the SLiM manual for credits and license information for code that has been incorporated into SLiM from other authors.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n       </property>\n       <property name=\"wordWrap\">\n        <bool>true</bool>\n       </property>\n       <property name=\"openExternalLinks\">\n        <bool>true</bool>\n       </property>\n       <property name=\"textInteractionFlags\">\n        <set>Qt::LinksAccessibleByMouse</set>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer_2\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n     <item>\n      <widget class=\"QLabel\" name=\"versionLabel\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"font\">\n        <font>\n         <pointsize>10</pointsize>\n        </font>\n       </property>\n       <property name=\"text\">\n        <string>3.3 (build 1)</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QDialogButtonBox\" name=\"buttonBox\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"standardButtons\">\n        <set>QDialogButtonBox::Close</set>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMIconView</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"icons.qrc\"/>\n </resources>\n <connections>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>accepted()</signal>\n   <receiver>QtSLiMAbout</receiver>\n   <slot>accept()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>248</x>\n     <y>254</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>157</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>rejected()</signal>\n   <receiver>QtSLiMAbout</receiver>\n   <slot>reject()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>316</x>\n     <y>260</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>286</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n </connections>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMAppDelegate.cpp",
    "content": "//\n//  QtSLiMAppDelegate.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/13/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMFindRecipe.h\"\n#include \"QtSLiM_SLiMgui.h\"\n#include \"QtSLiM_Plot.h\"\n#include \"QtSLiMScriptTextEdit.h\"\n#include \"QtSLiMAbout.h\"\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMHelpWindow.h\"\n#include \"QtSLiMFindPanel.h\"\n#include \"QtSLiMEidosConsole.h\"\n#include \"QtSLiMVariableBrowser.h\"\n#include \"QtSLiMTablesDrawer.h\"\n#include \"QtSLiMDebugOutputWindow.h\"\n#include \"QtSLiMConsoleTextEdit.h\"\n#include \"QtSLiMOpenGL.h\"\n#include \"QtSLiMExtras.h\"\n\n#include <QApplication>\n#include <QGuiApplication>\n#include <QScreen>\n#include <QOpenGLWidget>\n#include <QSurfaceFormat>\n#include <QMenu>\n#include <QAction>\n#include <QDir>\n#include <QKeyEvent>\n#include <QtGlobal>\n#include <QMenuBar>\n#include <QMenu>\n#include <QAction>\n#include <QDesktopServices>\n#include <QSettings>\n#include <QFileDialog>\n#include <QTextEdit>\n#include <QPlainTextEdit>\n#include <QLabel>\n#include <QDebug>\n#include <QStandardPaths>\n\n#include <stdio.h>\n#include <unistd.h>\n#include <time.h>\n#include <string>\n#include <algorithm>\n\n#include \"eidos_globals.h\"\n#include \"eidos_beep.h\"\n#include \"slim_globals.h\"\n#include \"slim_globals.h\"\n\n\n// Check the Qt version and display an error if it is unacceptable.  This can be turned off with\n// -D NO_QT_VERSION_ERROR; at present, that is used to allow GitHub Actions to test version\n// combinations that are not officially supported.  I do not recommend that end users use this flag.\n#ifdef NO_QT_VERSION_ERROR\n\n#warning \"Qt version check for SLiMgui disabled by -D NO_QT_VERSION_ERROR\"\n\n#else\n\n#ifdef __APPLE__\n// On macOS we enforce Qt 5.15.2 as a hard limit; macOS does not have Qt preinstalled, and there is\n// not much reason for anybody to use a version prior to 5.15.2 for a build.  5.15.2 is the only\n// Qt5 LTS version with support for macOS 11, dark mode, and various other things we want.  However,\n// if you need to build against an earlier Qt version (because you're using a macOS version earlier\n// than 10.13, perhaps), you can disable this check using the above flag and your build will probably\n// work; just note that that configuration is unsupported.\n#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 2))\n#error \"SLiMgui on macOS requires Qt version 5.15.2 or later.  Please uninstall Qt and then install a more recent version (5.15.2 or later recommended).\"\n#endif\n#else\n// On Linux we enforce Qt 5.9.5 as a hard limit, since it is what Ubuntu 18.04 LTS has preinstalled.\n// We don't rely on any specific post 5.9.5 features on Linux, and the best Qt version on Linux is\n// probably the version that a given distro has chosen to preinstall.\n#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 5))\n#error \"SLiMgui on Linux requires Qt version 5.9.5 or later.  Please uninstall Qt and then install a more recent version (5.15 LTS recommended).\"\n#endif\n#endif\n\n// We now support Qt 6, but do not require it.  Note that SLiM 4.2.2 was the last version that supported only Qt 5.\n#if (QT_VERSION >= QT_VERSION_CHECK(7, 0, 0))\n#error \"SLiMgui requires Qt 5 or Qt 6.  Qt 7 and later are not supported at this time.\"\n#endif\n#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))\n#error \"SLiMgui requires Qt 5 or Qt 6.  Qt 4 and earlier are not supported.\"\n#endif\n\n#endif\n\n\nstatic std::string Eidos_Beep_QT(const std::string &p_sound_name);\n\n\nQtSLiMAppDelegate *qtSLiMAppDelegate = nullptr;\n\n\n// A custom message handler that we can use, optionally, for debugging.  This is useful if Qt is emitting a warning and you don't know\n// where it's coming from; turn on the use of the message handler, and then set a breakpoint inside it, perhaps conditional on msg.\nvoid QtSLiM_MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)\n{\n#pragma unused (type, context)\n    \n    // Test for a specific message so you can break on it when it occurs\n    //if (msg.contains(\"Using QCharRef with an index\"))\n    //    qDebug() << \"HIT WATCH MESSAGE; SET A BREAKPOINT HERE!\";\n    \n    // Filter known benign Windows QPA spam when displays change\n#ifdef _WIN32\n    {\n        QByteArray category = context.category ? QByteArray(context.category) : QByteArray();\n        if (category == \"qwindows\")\n        {\n            if (msg.startsWith(\"Unable to get device information for\"))\n                return;\n        }\n    }\n#endif\n    \n    // useful behavior, from https://doc.qt.io/qt-5/qtglobal.html#qInstallMessageHandler\n    {\n        QByteArray localMsg = msg.toLocal8Bit();\n        \n#if 1\n        time_t rawtime;\n        struct tm *timeinfo;\n        \n        time(&rawtime);\n        timeinfo = localtime(&rawtime);\n        fprintf(stderr, \"%02d:%02d:%02d : \", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);\n#endif\n        \n#if 0\n        // Log file/line number and function/method name\n        const char *file = context.file ? context.file : \"\";\n        const char *function = context.function ? context.function : \"\";\n        \n        fprintf(stderr, \"%s (%s:%u, %s)\\n\", localMsg.constData(), file, context.line, function);\n#else\n        // Just log the message itself\n        fprintf(stderr, \"%s\\n\", localMsg.constData());\n#endif\n        \n#if 0\n        // Log a backtrace after each message\n        Eidos_PrintStacktrace(stderr, 20);\n#endif\n        \n        fflush(stderr);\n    }\n}\n\n\nQtSLiMAppDelegate::QtSLiMAppDelegate(QObject *p_parent) : QObject(p_parent)\n{\n    // Install a message handler; this seems useful for debugging\n    qInstallMessageHandler(QtSLiM_MessageHandler);\n    \n    // Determine whether we were launched from a shell or from something else (Finder, Xcode, etc.)\n\tlaunchedFromShell_ = (isatty(fileno(stdin)) == 1); // && !SLiM_AmIBeingDebugged();\n    \n    // Install our custom beep handler\n    Eidos_Beep = &Eidos_Beep_QT;\n    \n    // Let Qt know who we are, for QSettings configuration\n    QCoreApplication::setOrganizationName(\"MesserLab\");\n    QCoreApplication::setOrganizationDomain(\"messerlab.org\");   // Qt expects the domain in the standard order, and reverses it to form \"org.messerlab.SLiMgui.plist\" as per Apple's usage\n    QCoreApplication::setApplicationName(\"SLiMgui\");             // This governs the location of our prefs, which we keep under org.messerlab.SLiMgui\n    QCoreApplication::setApplicationVersion(SLIM_VERSION_STRING);\n    \n    // Warm up our back ends before anything else happens, including our own class objects\n    SLiM_ConfigureContext();\n    Eidos_WarmUp();\n    SLiM_WarmUp();\n    \n    gSLiM_Plot_Class = new Plot_Class(gStr_Plot, gEidosDictionaryUnretained_Class);\n    gSLiM_Plot_Class->CacheDispatchTables();\n    \n    gSLiM_SLiMgui_Class = new SLiMgui_Class(gStr_SLiMgui, gEidosDictionaryUnretained_Class);\n    gSLiM_SLiMgui_Class->CacheDispatchTables();\n\n    // Free the Eidos RNG; we want it to be uninitialized whenever we are not executing a\n    // simulation.  We keep our own RNG state, per-window.  Note that SLiMguiLegacy does\n    // not contain code corresponding to this in its delegate, because the order of its\n    // initialization is different; the Eidos RNG gets freed by -startNewSimulationFromScript\n    // before it causes any trouble.\n\tif (gEidos_RNG_Initialized)\n\t{\n\t\t_Eidos_FreeOneRNG(gEidos_RNG_SINGLE);\n\t\tgEidos_RNG_Initialized = false;\n\t}\n    \n    // Remember our current working directory, to return to whenever we are not inside SLiM/Eidos\n    app_cwd_ = Eidos_CurrentDirectory();\n    \n    // Initialize our OpenGL wrapper state\n    QtSLiM_AllocateGLBuffers();\n\n    // Set up the format for OpenGL buffers globally, so that it applies to all windows and contexts\n    // This defaults to OpenGL 2.0, which is what we want, so right now we don't customize\n    QSurfaceFormat format;\n    //format.setDepthBufferSize(24);\n    //format.setStencilBufferSize(8);\n    //format.setVersion(3, 2);\n    //format.setProfile(QSurfaceFormat::CompatibilityProfile);\n    QSurfaceFormat::setDefaultFormat(format);\n    \n    // Connect to the app to find out when we're terminating\n    QApplication *app = qApp;\n\n    connect(app, &QApplication::lastWindowClosed, this, &QtSLiMAppDelegate::lastWindowClosed);\n    connect(app, &QApplication::aboutToQuit, this, &QtSLiMAppDelegate::aboutToQuit);\n\n    // Install our event filter to detect modifier key changes\n    app->installEventFilter(this);\n    \n    // Track the last focused main window, for activeQtSLiMWindow()\n    connect(app, &QApplication::focusChanged, this, &QtSLiMAppDelegate::focusChanged);\n    \n    // We assume we are the global instance; FIXME singleton pattern would be good\n    qtSLiMAppDelegate = this;\n\n    // Ensure windows stay on-screen when displays change (added, removed, or modified)\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))\n\n    // This lambda (1) ensures that visible top-level windows remain on screen;\n    // (2) raises the active window to the front on the appropriate screen, if appropriate.\n    auto ensureOnScreen = [this]() {\n        const auto topLevels = QApplication::topLevelWidgets();\n        QWidget *active = qApp->activeWindow();\n        for (QWidget *w : topLevels)\n        {\n            if (!w || !w->isWindow())\n                continue;\n            // Do not affect hidden or minimized windows; only adjust currently visible ones\n            if (!w->isVisible())\n                continue;\n            if (w->windowState() & Qt::WindowMinimized)\n                continue;\n\n            // If the window is largely off-screen after a display change, move it without forcing it to the front\n            if (QtSLiMIsMostlyOnScreen(w))\n                continue;\n\n            if (w == active)\n            {\n                // For the active window, fully expose it (bring to front)\n                QtSLiMMakeWindowVisibleAndExposed(w);\n            }\n            else\n            {\n                // For other visible windows, adjust quietly without raising\n                QtSLiMRelocateQuietly(w);\n            }\n        }\n    };\n\n    // Connect to the screenAdded, screenRemoved, and geometryChanged signals\n    // to ensure that all top-level windows are visible and exposed\n    connect(app, &QGuiApplication::screenAdded,   this, [ensureOnScreen](QScreen *) { ensureOnScreen(); });\n    connect(app, &QGuiApplication::screenRemoved, this, [ensureOnScreen](QScreen *) { ensureOnScreen(); });\n    for (QScreen *screen : QGuiApplication::screens())\n        connect(screen, &QScreen::geometryChanged, this, [ensureOnScreen](const QRect &) { ensureOnScreen(); });\n#endif\n    \n    // Cache app-wide icons\n    slimDocumentIcon_.addFile(\":/icons/DocIcon16.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon32.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon48.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon64.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon128.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon256.png\");\n    slimDocumentIcon_.addFile(\":/icons/DocIcon512.png\");\n    \n    genericDocumentIcon_.addFile(\":/icons/GenericDocIcon16.png\");\n    genericDocumentIcon_.addFile(\":/icons/GenericDocIcon32.png\");\n    \n    appIcon_.addFile(\":/icons/AppIcon16.png\");\n    appIcon_.addFile(\":/icons/AppIcon32.png\");\n    appIcon_.addFile(\":/icons/AppIcon48.png\");\n    appIcon_.addFile(\":/icons/AppIcon64.png\");\n    appIcon_.addFile(\":/icons/AppIcon128.png\");\n    appIcon_.addFile(\":/icons/AppIcon256.png\");\n    appIcon_.addFile(\":/icons/AppIcon512.png\");\n    appIcon_.addFile(\":/icons/AppIcon1024.png\");\n    \n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(16, 16)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(32, 32)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(48, 48)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(64, 64)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(128, 128)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(256, 256)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(512, 512)));\n    appIconHighlighted_.addPixmap(QtSLiMDarkenPixmap(appIcon_.pixmap(1024, 1024)));\n    \n    // Set the application icon; this fixes the app icon in the dock/toolbar/whatever,\n    // even if the right icon is not attached for display in the desktop environment\n    app->setWindowIcon(appIcon_);\n}\n\nQtSLiMAppDelegate::~QtSLiMAppDelegate(void)\n{\n    //qDebug() << \"QtSLiMAppDelegate::~QtSLiMAppDelegate\";\n    \n#if SLIM_LEAK_CHECKING\n    QtSLiM_FreeGLBuffers();\n#endif\n    \n    qtSLiMAppDelegate = nullptr;    // kill the global shared instance, for safety\n}\n\n\n//\n//  Document opening\n//\n\nQtSLiMWindow *QtSLiMAppDelegate::findMainWindow(const QString &fileName) const\n{\n    QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();\n\n    const QList<QWidget *> topLevelWidgets = QApplication::topLevelWidgets();\n    for (QWidget *widget : topLevelWidgets) {\n        QtSLiMWindow *mainWin = qobject_cast<QtSLiMWindow *>(widget);\n        if (mainWin && (mainWin->isZombieWindow_ == false) && (mainWin->currentFile == canonicalFilePath))\n            return mainWin;\n    }\n\n    return nullptr;\n}\n\nvoid QtSLiMAppDelegate::newFile_WF(bool includeComments)\n{\n    QtSLiMWindow *currentActiveWindow = activeQtSLiMWindow();\n    QtSLiMWindow *window = new QtSLiMWindow(QtSLiMWindow::ModelType::WF, includeComments);\n    \n    window->tile(currentActiveWindow);\n    window->show();\n}\n\nvoid QtSLiMAppDelegate::newFile_nonWF(bool includeComments)\n{\n    QtSLiMWindow *currentActiveWindow = activeQtSLiMWindow();\n    QtSLiMWindow *window = new QtSLiMWindow(QtSLiMWindow::ModelType::nonWF, includeComments);\n    \n    window->tile(currentActiveWindow);\n    window->show();\n}\n\nQtSLiMWindow *QtSLiMAppDelegate::open(QtSLiMWindow *requester)\n{\n    QSettings settings;\n    QString directory = settings.value(\"QtSLiMDefaultOpenDirectory\", QVariant(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation))).toString();\n    QString fileName;\n    \n    if (!requester)\n        requester = activeQtSLiMWindow();\n    \n    if (requester)\n        fileName = QFileDialog::getOpenFileName(requester, QString(), directory, \"Files (*.slim *.txt *.png *.jpg *.jpeg *.bmp *.gif)\");\n    else\n        fileName = QFileDialog::getOpenFileName(nullptr, QString(), directory, \"Files (*.slim *.txt)\");\n    \n    if (!fileName.isEmpty())\n    {\n        settings.setValue(\"QtSLiMDefaultOpenDirectory\", QVariant(QFileInfo(fileName).path()));\n        return openFile(fileName, requester);\n    }\n    \n    return nullptr;\n}\n\nQtSLiMWindow *QtSLiMAppDelegate::openFile(const QString &fileName, QtSLiMWindow *requester)\n{\n    if (!requester)\n        requester = activeQtSLiMWindow();\n    \n    if (fileName.endsWith(\".png\", Qt::CaseInsensitive) ||\n            fileName.endsWith(\".jpg\", Qt::CaseInsensitive) ||\n            fileName.endsWith(\".jpeg\", Qt::CaseInsensitive) ||\n            fileName.endsWith(\".bmp\", Qt::CaseInsensitive) ||\n            fileName.endsWith(\".gif\", Qt::CaseInsensitive))\n    {\n        if (requester)\n        {\n            // An image; this opens as a child of the current SLiM window\n            QWidget *imageWindow = requester->imageWindowWithPath(fileName);\n            \n            if (imageWindow)\n                QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n            \n            return requester;\n        }\n        else\n        {\n            qApp->beep();\n            return nullptr;\n        }\n    }\n    else\n    {\n        // Should be a .slim or .txt file; look for an existing window for the file, otherwise open a new window (or reuse a reuseable window)\n        QtSLiMWindow *existing = findMainWindow(fileName);\n        if (existing) {\n            QtSLiMMakeWindowVisibleAndExposed(existing);\n            return existing;\n        }\n        \n        if (requester && requester->windowIsReuseable()) {\n            requester->loadFile(fileName);\n            return requester;\n        }\n        \n        QtSLiMWindow *window = new QtSLiMWindow(fileName);\n        if (window->isUntitled) {\n            delete window;\n            return nullptr;\n        }\n        window->tile(requester);\n        window->show();\n        return window;\n    }\n}\n\nvoid QtSLiMAppDelegate::openRecipeWithName(const QString &recipeName, const QString &recipeScript, QtSLiMWindow *requester)\n{\n    if (recipeName.endsWith(\".py\"))\n    {\n        // Python recipes live in GitHub and get opened in the user's browser.  This seems like the best solution;\n        // we don't want SLiMgui to become a Python IDE, so we don't want to open them in-app, but there is no\n        // good cross-platform solution for opening them in an app that makes sense, or even for revealing them\n        // on the desktop.  See https://github.com/MesserLab/SLiM/issues/137 for discussion.\n        QString urlString = \"https://raw.githubusercontent.com/MesserLab/SLiM/master/QtSLiM/recipes/\";\n        urlString.append(recipeName);\n        \n        QDesktopServices::openUrl(QUrl(urlString, QUrl::TolerantMode));\n    }\n    else\n    {\n        // SLiM recipes get opened in a new window (or reusing the current window, if applicable)\n        if (!requester)\n            requester = activeQtSLiMWindow();\n        \n        if (requester && requester->windowIsReuseable())\n        {\n            requester->loadRecipe(recipeName, recipeScript);\n            return;\n        }\n        \n        QtSLiMWindow *window = new QtSLiMWindow(recipeName, recipeScript);\n        if (!window->isRecipe) {\n            delete window;\n            return;\n        }\n        window->tile(requester);\n        window->show();\n    }\n}\n\n\n//\n//  Recipes menu handling\n//\n\nvoid QtSLiMAppDelegate::setUpRecipesMenu(QMenu *openRecipesMenu, QAction *findRecipeAction)\n{\n    // This is called by QtSLiMWindow::initializeUI().  We are to take control of the\n    // recipes submenu, filling it in and implementing the Find Recipe panel.\n    connect(findRecipeAction, &QAction::triggered, this, &QtSLiMAppDelegate::findRecipe);\n    \n    // Find recipes in our resources and sort by numeric order\n    QDir recipesDir(\":/recipes/\", \"Recipe *.*\", QDir::NoSort, QDir::Files | QDir::NoSymLinks);\n    QStringList entryList = recipesDir.entryList(QStringList(\"Recipe *.*\"));   // the previous name filter seems to be ignored\n    \n    std::sort(entryList.begin(), entryList.end(), EidosNaturalSort);\n    //qDebug() << entryList;\n    \n    // Append an action for each, organized into submenus\n    QString previousItemChapter;\n    QMenu *chapterSubmenu = nullptr;\n    \n    for (QString &entryName : entryList)\n    {\n        QString recipeName;\n        \n        // Determine the menu item text for the recipe, removing \"Recipe \" and \".txt\", and adding pythons\n        if (entryName.endsWith(\".txt\"))\n            recipeName = entryName.mid(7, entryName.length() - 11);\n        else if (entryName.endsWith(\".py\"))\n            recipeName = entryName.mid(7, entryName.length() - 7) + QString(\" 🐍\");\n        \n        int firstDotIndex = recipeName.indexOf('.');\n        \n        if (firstDotIndex != -1)\n        {\n            QString recipeChapter = recipeName.left(firstDotIndex);\n            \n            // Create a submenu for each chapter\n            if (recipeChapter != previousItemChapter)\n            {\n                int recipeChapterValue = recipeChapter.toInt();\n                QString chapterName;\n                \n                switch (recipeChapterValue)\n                {\n                    case 4: chapterName = \"Getting started: Neutral evolution in a panmictic population\";\t\tbreak;\n                    case 5: chapterName = \"Demography and population structure\";\t\t\t\t\t\t\t\tbreak;\n                    case 6: chapterName = \"Mutation types, genomic elements, and chromosome structure\";\t\t\tbreak;\n                    case 7: chapterName = \"SLiMgui visualizations for polymorphism patterns\";         \t\t\tbreak;\n                    case 8: chapterName = \"Reproduction, meiosis, and multiple chromosomes\";\t\t\t\t\tbreak;\n                    case 9:\tchapterName = \"Selective sweeps\";\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n                    case 10:chapterName = \"Context-dependent selection using mutationEffect() callbacks\";\t\tbreak;\n                    case 11:chapterName = \"Complex mating schemes using mateChoice() callbacks\";\t\t\t\tbreak;\n                    case 12:chapterName = \"Direct child modifications using modifyChild() callbacks\";\t\t\tbreak;\n                    case 13:chapterName = \"Phenotypes, fitness functions, quantitative traits, and QTLs\";\t\tbreak;\n                    case 14:chapterName = \"Advanced WF models\";\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n                    case 15:chapterName = \"Going beyond Wright-Fisher models: nonWF model recipes\";             break;\n                    case 16:chapterName = \"Advanced nonWF techniques for managing reproduction\";             \tbreak;\n                    case 17:chapterName = \"Continuous-space models, interactions, and spatial maps\";\t\t\tbreak;\n                    case 18:chapterName = \"Tree-sequence recording: tracking population history\";\t\t\t\tbreak;\n                    case 19:chapterName = \"Modeling explicit nucleotides\";\t\t\t\t\t\t\t\t\t\tbreak;\n                    case 20:chapterName = \"Multispecies modeling\";                                              break;\n                    case 23:chapterName = \"Parallel SLiM: Running SLiM multithreaded\";                          break;\n                    default: break;\n                }\n                \n                if (chapterName.length())\n                {\n                    QString fullChapterName = QString(\"%1 – %2\").arg(QString::number(recipeChapterValue), chapterName);\n                    QAction *mainItem = openRecipesMenu->addAction(fullChapterName);\n                    \n                    chapterSubmenu = new QMenu(fullChapterName, openRecipesMenu);\n                    mainItem->setMenu(chapterSubmenu);\n                }\n                else\n                {\n                    qDebug() << \"unrecognized chapter value \" << recipeChapterValue;\n                    qApp->beep();\n                    break;\n                }\n            }\n            \n            // Move on to the current chapter\n            previousItemChapter = recipeChapter;\n            \n            // And now add the menu item for the recipe\n            QAction *menuItem = chapterSubmenu->addAction(recipeName);\n            \n            connect(menuItem, &QAction::triggered, this, &QtSLiMAppDelegate::openRecipe);\n            menuItem->setData(QVariant(entryName));\n        }\n    }\n}\n\n\n//\n//  Recent document menu handling\n//\n\nstatic const int MaxRecentFiles = 10;\nstatic inline QString recentFilesKey() { return QStringLiteral(\"QtSLiMRecentFilesList\"); }\nstatic inline QString fileKey() { return QStringLiteral(\"file\"); }\n\nstatic QStringList readRecentFiles(QSettings &settings)\n{\n    QStringList result;\n    const int count = settings.beginReadArray(recentFilesKey());\n    for (int i = 0; i < count; ++i) {\n        settings.setArrayIndex(i);\n        result.append(settings.value(fileKey()).toString());\n    }\n    settings.endArray();\n    return result;\n}\n\nstatic void writeRecentFiles(const QStringList &files, QSettings &settings)\n{\n    const int count = files.size();\n    settings.beginWriteArray(recentFilesKey());\n    for (int i = 0; i < count; ++i) {\n        settings.setArrayIndex(i);\n        settings.setValue(fileKey(), files.at(i));\n    }\n    settings.endArray();\n}\n\nvoid QtSLiMAppDelegate::updateRecentFileActions()\n{\n    const QMenu *menu = qobject_cast<const QMenu *>(sender());\n    QSettings settings;\n\n    const QStringList recentFiles = readRecentFiles(settings);\n    const int count = qMin(int(MaxRecentFiles), recentFiles.size());\n    QList<QAction *> actions = menu->actions();\n    \n    for (int i = 0 ; i < MaxRecentFiles; ++i)\n    {\n        QAction *recentAction = actions[i];\n        \n        if (i < count)\n        {\n            const QString fileName = QFileInfo(recentFiles.at(i)).fileName();\n            recentAction->setText(fileName);\n            recentAction->setData(recentFiles.at(i));\n            recentAction->setVisible(true);\n        }\n        else\n        {\n            recentAction->setVisible(false);\n        }\n    }\n}\n\nvoid QtSLiMAppDelegate::openRecentFile()\n{\n    const QAction *action = qobject_cast<const QAction *>(sender());\n    \n    if (action)\n        openFile(action->data().toString(), nullptr);\n}\n\nvoid QtSLiMAppDelegate::clearRecentFiles()\n{\n    QSettings settings;\n    QStringList emptyRecentFiles;\n    writeRecentFiles(emptyRecentFiles, settings);\n}\n\nvoid QtSLiMAppDelegate::setUpRecentsMenu(QMenu *openRecentSubmenu)\n{\n    connect(openRecentSubmenu, &QMenu::aboutToShow, this, &QtSLiMAppDelegate::updateRecentFileActions);\n    \n    for (int i = 0; i < MaxRecentFiles; ++i)\n        openRecentSubmenu->addAction(QString(), this, &QtSLiMAppDelegate::openRecentFile)->setVisible(false);\n    \n    openRecentSubmenu->addSeparator();\n    openRecentSubmenu->addAction(\"Clear Menu\", this, &QtSLiMAppDelegate::clearRecentFiles);\n}\n\nvoid QtSLiMAppDelegate::prependToRecentFiles(const QString &fileName)\n{\n    QSettings settings;\n\n    const QStringList oldRecentFiles = readRecentFiles(settings);\n    QStringList recentFiles = oldRecentFiles;\n    recentFiles.removeAll(fileName);\n    recentFiles.prepend(fileName);\n    if (oldRecentFiles != recentFiles)\n        writeRecentFiles(recentFiles, settings);\n}\n\n\n//\n//  Event filtering\n//\n\nbool QtSLiMAppDelegate::eventFilter(QObject *p_obj, QEvent *p_event)\n{\n    QEvent::Type type = p_event->type();\n    \n    if ((type == QEvent::KeyPress) || (type == QEvent::KeyRelease))\n    {\n        // emit modifier changed signals for use by the app\n        QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(p_event);\n        \n        if (keyEvent)\n        {\n            Qt::Key key = static_cast<Qt::Key>(keyEvent->key());     // why does this return int?\n            \n            if ((key == Qt::Key_Shift) ||\n                    (key == Qt::Key_Control) ||\n                    (key == Qt::Key_Meta) ||\n                    (key == Qt::Key_Alt) ||\n                    (key == Qt::Key_AltGr) ||\n                    (key == Qt::Key_CapsLock) ||\n                    (key == Qt::Key_NumLock) ||\n                    (key == Qt::Key_ScrollLock))\n                emit modifiersChanged(keyEvent->modifiers());\n        }\n    }\n    else if ((type == QEvent::WindowActivate) || (type == QEvent::WindowDeactivate) || (type == QEvent::WindowStateChange) ||\n             (type == QEvent::WindowBlocked) || (type == QEvent::WindowUnblocked) || (type == QEvent::HideToParent) ||\n             (type == QEvent::ShowToParent) || (type == QEvent::Close))\n    {\n        // track the active window; we use a timer here because the active window is not yet accurate in all cases\n        // we also want to coalesce the work involved, so we use a flag to avoid scheduling more than one update\n        if (!queuedActiveWindowUpdate)\n        {\n            queuedActiveWindowUpdate = true;\n            //qDebug() << \"SCHEDULED... event type ==\" << type;\n            QTimer::singleShot(0, this, &QtSLiMAppDelegate::updateActiveWindowList);\n        }\n        else\n        {\n            //qDebug() << \"REDUNDANT... event type ==\" << type;\n        }\n    }\n    else if (type == QEvent::FileOpen)\n    {\n        // the user has requested that a file be opened\n        QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(p_event);\n        QString filePath = openEvent->file();\n        \n        openFile(filePath, nullptr);\n        \n        return true;    // filter this event, i.e., prevent any further Qt handling of it\n    }\n    else if (type == QEvent::ApplicationPaletteChange)\n    {\n        if (inDarkMode_ != QtSLiMInDarkMode())\n        {\n            inDarkMode_ = QtSLiMInDarkMode();\n            //qDebug() << \"inDarkMode_ == \" << inDarkMode_;\n            emit applicationPaletteChanged();\n        }\n    }\n    else if (type == QEvent::StatusTip)\n    {\n        // These are events that Qt sends to itself, to display \"status tips\" in the status bar for widgets the\n        // mouse is over, like buttons and menu bar items.  This is not a feature I presently want to use, and\n        // on Linux these events get sent even when the tip is empty, and cause the status bar to be cleared\n        // for no apparent reason.  So I'm going to just disable these events for now.\n\n        return true;    // filter this event, i.e., prevent any further Qt handling of it\n    }\n    \n    // standard event processing\n    return QObject::eventFilter(p_obj, p_event);\n}\n\n\n//\n//  public slots\n//\n\nvoid QtSLiMAppDelegate::appDidFinishLaunching(QtSLiMWindow *initialWindow)\n{\n    // Display a startup message in the initial window's status bar\n    if (initialWindow)\n        initialWindow->displayStartupMessage();\n    \n    // Cache our dark mode flag so we can respond to palette changes later\n    inDarkMode_ = QtSLiMInDarkMode();\n}\n\nvoid QtSLiMAppDelegate::lastWindowClosed(void)\n{\n}\n\nvoid QtSLiMAppDelegate::aboutToQuit(void)\n{\n    //qDebug() << \"QtSLiMAppDelegate::aboutToQuit\";\n}\n\nvoid QtSLiMAppDelegate::findRecipe(void)\n{\n    QtSLiMFindRecipe findRecipePanel(nullptr);\n    \n    int result = findRecipePanel.exec();\n    \n    if (result == QDialog::Accepted)\n    {\n        const QStringList resourceNames = findRecipePanel.selectedRecipeFilenames();\n        \n        for (const QString &resourceName : resourceNames)\n        {\n            //qDebug() << \"recipe name:\" << resourceName;\n            \n            QString resourcePath = \":/recipes/\" + resourceName;\n            QFile recipeFile(resourcePath);\n            \n            if (recipeFile.open(QFile::ReadOnly | QFile::Text))\n            {\n                QTextStream recipeTextStream(&recipeFile);\n                QString recipeScript = recipeTextStream.readAll();\n                QString trimmedName = resourceName;\n                \n                if (trimmedName.endsWith(\".txt\"))\n                    trimmedName.chop(4);\n                \n                openRecipeWithName(trimmedName, recipeScript, nullptr);\n            }\n        }\n    }\n}\n\nvoid QtSLiMAppDelegate::openRecipe(void)\n{\n    QAction *action = qobject_cast<QAction *>(sender());\n    \n    if (action)\n    {\n        const QVariant &data = action->data();\n        QString resourceName = data.toString();\n        \n        if (resourceName.length())\n        {\n            //qDebug() << \"recipe name:\" << resourceName;\n            \n            QString resourcePath = \":/recipes/\" + resourceName;\n            QFile recipeFile(resourcePath);\n            \n            if (recipeFile.open(QFile::ReadOnly | QFile::Text))\n            {\n                QTextStream recipeTextStream(&recipeFile);\n                QString recipeScript = recipeTextStream.readAll();\n                QString trimmedName = resourceName;\n                \n                if (trimmedName.endsWith(\".txt\"))\n                    trimmedName.chop(4);\n                \n                openRecipeWithName(trimmedName, recipeScript, nullptr);\n            }\n        }\n     }\n}\n\nvoid QtSLiMAppDelegate::playStateChanged(void)\n{\n    bool anyPlaying = false;\n    const QWidgetList topLevelWidgets = qApp->topLevelWidgets();\n    \n    for (QWidget *widget : topLevelWidgets)\n    {\n        QtSLiMWindow *mainWin = qobject_cast<QtSLiMWindow *>(widget);\n        \n        if (mainWin && mainWin->isPlaying())\n            anyPlaying = true;\n    }\n    \n    qApp->setWindowIcon(anyPlaying ? appIconHighlighted_ : appIcon_);\n}\n\n\n//\n//  \"First responder\" type dispatch for actions shared across the app\n//\n\n// Here is the problem driving this design.  We want various actions, like \"Close\" and \"New nonWF\" and so forth,\n// to work (with their shortcut) regardless of what window is frontmost; they should be global actions that\n// are, at least conceptually, handled by the app, not by any specific widget or window.  Originally I tried\n// defining these as \"application\" shortcuts, with Qt::ApplicationShortcut; that worked well on macOS, but on\n// Linux they were deemed \"ambiguous\" by Qt when more than one main window was open – Qt didn't know which\n// main window to dispatch to, for some reason.  Designating them as \"window\" shortcuts, with Qt::WindowShortcut,\n// therefore seems to be a forced move.  However, they then work only if a main window is the active window, on\n// Linux, unless we add them as window actions to every window in the app.  So that's what we do – add them to\n// every window.  This helper method takes a window and adds all the global actions to it.  I feel like I'm\n// maybe missing something with this design; there must be a more elegant way to do this in Qt.  But I've gone\n// around and around on the menu item dispatch mechanism, and this is the best solution I've found.\n\n// Note that it remains the case that the menu bar is owned by QtSLiMWindow, and that each QtSLiMWindow has its\n// own menu bar; on Linux that is visible to the user, on macOS it is not.  QtSLiMWindow is therefore responsible\n// for menu item enabling and validation, even for the global actions defined here.  The validation logic needs\n// to be parallel to the dispatch logic here.  Arguably, we could have QtSLiMWindow delegate the validation to\n// QtSLiMAppDelegate so that all the global action logic is together in this class, but since QtSLiMWindow owns\n// the menu items, and they are private, I left the validation code there.\n\n// Some actions added here have no shortcut.  Since they are not associated with any menu item or toolbar item,\n// they will never actually be called.  Conceptually, they are global actions, though, and if a shortcut is\n// added for them later, they will become callable here.  So they are declared here as placeholders.\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n// On Qt 5 we seem to need to combine flags with +, I have no idea why exactly\nstatic int flagsAndKey(int modifiers, int keys)\n{\n    return modifiers + keys;\n}\n#else\n// On Qt 6 we seem to need to combine flags with |, I have no idea why exactly\nstatic int flagsAndKey(int modifiers, int keys)\n{\n    return modifiers | keys;\n}\n#endif\n\nvoid QtSLiMAppDelegate::addActionsForGlobalMenuItems(QWidget *window)\n{\n    {\n        QAction *actionPreferences = new QAction(\"Preferences\", this);\n        actionPreferences->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionPreferences, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_preferences);\n        window->addAction(actionPreferences);\n    }\n    {\n        QAction *actionAbout = new QAction(\"About\", this);\n        //actionAbout->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionAbout, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_about);\n        window->addAction(actionAbout);\n    }\n    {\n        QAction *actionShowCycle_WF = new QAction(\"Show WF Tick Cycle\", this);\n        //actionShowCycle_WF->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowCycle_WF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_WF);\n        window->addAction(actionShowCycle_WF);\n    }\n    {\n        QAction *actionShowCycle_nonWF = new QAction(\"Show nonWF Tick Cycle\", this);\n        //actionShowCycle_nonWF->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowCycle_nonWF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_nonWF);\n        window->addAction(actionShowCycle_nonWF);\n    }\n    {\n        QAction *actionShowCycle_WF_MS = new QAction(\"Show WF Tick Cycle (Multispecies)\", this);\n        //actionShowCycle_WF_MS->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowCycle_WF_MS, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_WF_MS);\n        window->addAction(actionShowCycle_WF_MS);\n    }\n    {\n        QAction *actionShowCycle_nonWF_MS = new QAction(\"Show nonWF Tick Cycle (Multispecies)\", this);\n        //actionShowCycle_nonWF_MS->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowCycle_nonWF_MS, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_nonWF_MS);\n        window->addAction(actionShowCycle_nonWF_MS);\n    }\n    {\n        QAction *actionShowColorChart = new QAction(\"Show Color Chart\", this);\n        //actionShowColorChart->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowColorChart, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showColorChart);\n        window->addAction(actionShowColorChart);\n    }\n    {\n        QAction *actionShowPlotSymbols = new QAction(\"Show Plot Symbols\", this);\n        //actionShowPlotSymbols->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowPlotSymbols, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showPlotSymbols);\n        window->addAction(actionShowPlotSymbols);\n    }\n    {\n        QAction *actionShowColorScales = new QAction(\"Show SLiMgui Color Scales\", this);\n        //actionShowColorScales->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionShowColorScales, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showColorScales);\n        window->addAction(actionShowColorScales);\n    }\n    {\n        QAction *actionHelp = new QAction(\"Help\", this);\n        //actionHelp->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Comma));\n        connect(actionHelp, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n        window->addAction(actionHelp);\n    }\n    {\n        QAction *actionQuit = new QAction(\"Quit\", this);\n        actionQuit->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Q));\n        connect(actionQuit, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_quit);\n        window->addAction(actionQuit);\n    }\n    \n    {\n        QAction *actionNewWF = new QAction(\"New WF\", this);\n        actionNewWF->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_N));\n        connect(actionNewWF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newWF);\n        window->addAction(actionNewWF);\n    }\n    {\n        QAction *actionNewWF_commentless = new QAction(\"New WF (Commentless)\", this);\n        actionNewWF_commentless->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::AltModifier, Qt::Key_N));\n        connect(actionNewWF_commentless, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newWF_commentless);\n        window->addAction(actionNewWF_commentless);\n    }\n    {\n        QAction *actionNewNonWF = new QAction(\"New nonWF\", this);\n        actionNewNonWF->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_N));\n        connect(actionNewNonWF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newNonWF);\n        window->addAction(actionNewNonWF);\n    }\n    {\n        QAction *actionNewNonWF_commentless = new QAction(\"New nonWF (Commentless)\", this);\n        actionNewNonWF_commentless->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier, Qt::Key_N));\n        connect(actionNewNonWF_commentless, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newNonWF_commentless);\n        window->addAction(actionNewNonWF_commentless);\n    }\n    {\n        QAction *actionOpen = new QAction(\"Open\", this);\n        actionOpen->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_O));\n        connect(actionOpen, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_open);\n        window->addAction(actionOpen);\n    }\n    {\n        QAction *actionClose = new QAction(\"Close\", this);\n        actionClose->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_W));\n        connect(actionClose, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_close);\n        window->addAction(actionClose);\n    }\n    \n    {\n        QAction *actionFocusOnScript = new QAction(\"Focus on Script\", this);\n        actionFocusOnScript->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_1));\n        connect(actionFocusOnScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_focusOnScript);\n        window->addAction(actionFocusOnScript);\n    }\n    {\n        QAction *actionFocusOnConsole = new QAction(\"Focus on Console\", this);\n        actionFocusOnConsole->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_2));\n        connect(actionFocusOnConsole, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_focusOnConsole);\n        window->addAction(actionFocusOnConsole);\n    }\n    {\n        QAction *actionCheckScript = new QAction(\"Check Script\", this);\n        actionCheckScript->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Equal));\n        connect(actionCheckScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_checkScript);\n        window->addAction(actionCheckScript);\n    }\n    {\n        QAction *actionPrettyprintScript = new QAction(\"Prettyprint Script\", this);\n        //actionPrettyprintScript->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_Equal));       // this now goes to actionBiggerFont\n        connect(actionPrettyprintScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_prettyprintScript);\n        window->addAction(actionPrettyprintScript);\n    }\n    {\n        QAction *actionReformatScript = new QAction(\"Reformat Script\", this);               // removed since the shortcut for actionPrettyprintScript was removed\n        //actionReformatScript->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier, Qt::Key_Equal));\n        connect(actionReformatScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_reformatScript);\n        window->addAction(actionReformatScript);\n    }\n    {\n        QAction *actionShowScriptHelp = new QAction(\"Show Script Help\", this);\n        //actionShowScriptHelp->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_K));\n        connect(actionShowScriptHelp, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n        window->addAction(actionShowScriptHelp);\n    }\n    {\n        QAction *actionBiggerFont = new QAction(\"Bigger Font\", this);\n        actionBiggerFont->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Plus));\n        connect(actionBiggerFont, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_biggerFont);\n        window->addAction(actionBiggerFont);\n    }\n    {\n        QAction *actionSmallerFont = new QAction(\"Smaller Font\", this);\n        actionSmallerFont->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Minus));\n        connect(actionSmallerFont, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_smallerFont);\n        window->addAction(actionSmallerFont);\n    }\n    {\n        QAction *actionShowEidosConsole = new QAction(\"Show Eidos Console\", this);\n        actionShowEidosConsole->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_E));\n        connect(actionShowEidosConsole, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showEidosConsole);\n        window->addAction(actionShowEidosConsole);\n    }\n    {\n        QAction *actionShowVariableBrowser = new QAction(\"Show Variable Browser\", this);\n        actionShowVariableBrowser->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_B));\n        connect(actionShowVariableBrowser, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showVariableBrowser);\n        window->addAction(actionShowVariableBrowser);\n    }\n    {\n        QAction *actionClearOutput = new QAction(\"Clear Output\", this);\n        actionClearOutput->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_K));\n        connect(actionClearOutput, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_clearOutput);\n        window->addAction(actionClearOutput);\n    }\n    {\n        QAction *actionClearDebug = new QAction(\"Clear Debug Points\", this);\n        actionClearDebug->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::AltModifier, Qt::Key_K));\n        connect(actionClearDebug, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_clearDebugPoints);\n        window->addAction(actionClearDebug);\n    }\n    {\n        QAction *actionShowDebuggingOutput = new QAction(\"Show Debugging Output\", this);\n        actionShowDebuggingOutput->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_D));\n        connect(actionShowDebuggingOutput, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showDebuggingOutput);\n        window->addAction(actionShowDebuggingOutput);\n    }\n    {\n        QAction *actionExecuteSelection = new QAction(\"Execute Selection\", this);\n        actionExecuteSelection->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Return));\n        connect(actionExecuteSelection, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_executeSelection);\n        window->addAction(actionExecuteSelection);\n    }\n    {\n        QAction *actionExecuteAll = new QAction(\"Execute All\", this);\n        actionExecuteAll->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_Return));\n        connect(actionExecuteAll, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_executeAll);\n        window->addAction(actionExecuteAll);\n    }\n    \n    {\n        QAction *actionCopyAsHTML = new QAction(\"Copy as HTML\", this);\n        actionCopyAsHTML->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::AltModifier, Qt::Key_C));\n        connect(actionCopyAsHTML, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_copyAsHTML);\n        window->addAction(actionCopyAsHTML);\n    }\n    {\n        QAction *actionShiftLeft = new QAction(\"Shift Left\", this);\n        actionShiftLeft->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_BracketLeft));\n        connect(actionShiftLeft, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_shiftLeft);\n        window->addAction(actionShiftLeft);\n    }\n    {\n        QAction *actionShiftRight = new QAction(\"Shift Right\", this);\n        actionShiftRight->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_BracketRight));\n        connect(actionShiftRight, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_shiftRight);\n        window->addAction(actionShiftRight);\n    }\n    {\n        QAction *actionCommentUncomment = new QAction(\"CommentUncomment\", this);\n        actionCommentUncomment->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Slash));\n        connect(actionCommentUncomment, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_commentUncomment);\n        window->addAction(actionCommentUncomment);\n    }\n    \n    {\n        QAction *actionUndo = new QAction(\"Undo\", this);\n        actionUndo->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_Z));\n        connect(actionUndo, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_undo);\n        window->addAction(actionUndo);\n    }\n    {\n        QAction *actionRedo = new QAction(\"Redo\", this);\n        actionRedo->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_Z));\n        connect(actionRedo, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_redo);\n        window->addAction(actionRedo);\n    }\n    {\n        QAction *actionCut = new QAction(\"Cut\", this);\n        actionCut->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_X));\n        connect(actionCut, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_cut);\n        window->addAction(actionCut);\n    }\n    {\n        QAction *actionCopy = new QAction(\"Copy\", this);\n        actionCopy->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_C));\n        connect(actionCopy, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_copy);\n        window->addAction(actionCopy);\n    }\n    {\n        QAction *actionPaste = new QAction(\"Paste\", this);\n        actionPaste->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_V));\n        connect(actionPaste, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_paste);\n        window->addAction(actionPaste);\n    }\n    {\n        QAction *actionDuplicate = new QAction(\"Duplicate\", this);\n        actionDuplicate->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_D));\n        connect(actionDuplicate, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_duplicate);\n        window->addAction(actionDuplicate);\n    }\n    {\n        QAction *actionDelete = new QAction(\"Delete\", this);\n        //actionDelete->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_V));\n        connect(actionDelete, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_delete);\n        window->addAction(actionDelete);\n    }\n    {\n        QAction *actionSelectAll = new QAction(\"Select All\", this);\n        actionSelectAll->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_A));\n        connect(actionSelectAll, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_selectAll);\n        window->addAction(actionSelectAll);\n    }\n    \n    {\n        QAction *actionFindShow = new QAction(\"Find...\", this);\n        actionFindShow->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_F));\n        connect(actionFindShow, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findShow);\n        window->addAction(actionFindShow);\n    }\n    {\n        QAction *actionFindNext = new QAction(\"Find Next\", this);\n        actionFindNext->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_G));\n        connect(actionFindNext, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findNext);\n        window->addAction(actionFindNext);\n    }\n    {\n        QAction *actionFindPrevious = new QAction(\"Find Previous\", this);\n        actionFindPrevious->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_G));\n        connect(actionFindPrevious, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findPrevious);\n        window->addAction(actionFindPrevious);\n    }\n    {\n        QAction *actionReplaceAndFind = new QAction(\"Replace and Find\", this);\n        actionReplaceAndFind->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::AltModifier, Qt::Key_G));\n        connect(actionReplaceAndFind, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_replaceAndFind);\n        window->addAction(actionReplaceAndFind);\n    }\n    {\n        QAction *actionUseSelectionForFind = new QAction(\"Use Selection for Find\", this);\n        actionUseSelectionForFind->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_E));\n        connect(actionUseSelectionForFind, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_useSelectionForFind);\n        window->addAction(actionUseSelectionForFind);\n    }\n    {\n        QAction *actionUseSelectionForReplace = new QAction(\"Use Selection for Replace\", this);\n        actionUseSelectionForReplace->setShortcut(flagsAndKey(Qt::ControlModifier | Qt::AltModifier, Qt::Key_E));\n        connect(actionUseSelectionForReplace, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_useSelectionForReplace);\n        window->addAction(actionUseSelectionForReplace);\n    }\n    {\n        QAction *actionJumpToSelection = new QAction(\"Jump to Selection\", this);\n        actionJumpToSelection->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_J));\n        connect(actionJumpToSelection, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_jumpToSelection);\n        window->addAction(actionJumpToSelection);\n    }\n    {\n        QAction *actionJumpToLine = new QAction(\"Jump to Line\", this);\n        actionJumpToLine->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_L));\n        connect(actionJumpToLine, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_jumpToLine);\n        window->addAction(actionJumpToLine);\n    }\n    \n    {\n        QAction *actionMinimize = new QAction(\"Minimize\", this);\n        actionMinimize->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_M));\n        connect(actionMinimize, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_minimize);\n        window->addAction(actionMinimize);\n    }\n    {\n        QAction *actionZoom = new QAction(\"Zoom\", this);\n        //actionZoom->setShortcut(flagsAndKey(Qt::ControlModifier, Qt::Key_M));\n        connect(actionZoom, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_zoom);\n        window->addAction(actionZoom);\n    }\n}\n\nQtSLiMWindow *QtSLiMAppDelegate::dispatchQtSLiMWindowFromSecondaries(void)\n{\n    // The QtSLiMWindow associated with the focused widget; this should be used for\n    // dispatching actions that we want to work inside secondary windows that are\n    // associated with a particular QtSLiMWindow.\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : nullptr);\n    \n    // If we have no focused widget, just work from the active window\n    if (!focusWindow)\n        focusWindow = activeWindow();\n    \n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    QtSLiMVariableBrowser *varBrowser = dynamic_cast<QtSLiMVariableBrowser*>(focusWindow);\n    QtSLiMTablesDrawer *tablesDrawer = dynamic_cast<QtSLiMTablesDrawer*>(focusWindow);\n    QtSLiMDebugOutputWindow *debugOutputWindow = dynamic_cast<QtSLiMDebugOutputWindow*>(focusWindow);\n    \n    if (eidosConsole)\n        slimWindow = eidosConsole->parentSLiMWindow;\n    else if (varBrowser)\n        slimWindow = varBrowser->parentEidosConsole->parentSLiMWindow;\n    else if (tablesDrawer)\n        slimWindow = tablesDrawer->parentSLiMWindow;\n    else if (debugOutputWindow)\n        slimWindow = debugOutputWindow->parentSLiMWindow;\n    \n    // If we still can't find it, try using the parent of the active window\n    // This makes graph windows work for dispatch; they are just QWidgets but their parent is correct\n    if (focusWindow && !slimWindow)\n        slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow->parent());\n    \n    return slimWindow;\n}\n\nvoid QtSLiMAppDelegate::dispatch_preferences(void)\n{\n    QtSLiMPreferences &prefsWindow = QtSLiMPreferences::instance();\n    \n    QtSLiMMakeWindowVisibleAndExposed(&prefsWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_about(void)\n{\n    QtSLiMAbout *aboutWindow = new QtSLiMAbout(nullptr);\n    \n    aboutWindow->setAttribute(Qt::WA_DeleteOnClose);\n    \n    QtSLiMMakeWindowVisibleAndExposed(aboutWindow);\n}\n\nQWidget *QtSLiMAppDelegate::globalImageWindowWithPath(const QString &path, const QString &title, double scaleFactor)\n{\n    // This is based on QtSLiMWindow::imageWindowWithPath(), but makes a simple global window\n    // without context menus and other fluff, for simple display of help-related images\n    QImage image(path);\n    \n    if (image.isNull())\n    {\n        qApp->beep();\n        return nullptr;\n    }\n    \n    int window_width = round(image.width() * scaleFactor);\n    int window_height = round(image.height() * scaleFactor);\n    \n    QWidget *image_window = new QWidget(nullptr, Qt::Window | Qt::Tool);    // a parentless standalone window\n    \n    image_window->setWindowTitle(title);\n    image_window->setFixedSize(window_width, window_height);\n    \n    // Make the image view\n    QLabel *imageView = new QLabel();\n    \n    imageView->setStyleSheet(\"QLabel { background-color : white; }\");\n    imageView->setBackgroundRole(QPalette::Base);\n    imageView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);\n    imageView->setScaledContents(true);\n    imageView->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);\n    imageView->setPixmap(QPixmap::fromImage(image));\n    \n    // Install imageView in the window\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    image_window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    topLayout->addWidget(imageView);\n    \n    // Position the window nicely\n    //positionNewSubsidiaryWindow(image_window);\n    \n    // make window actions for all global menu items\n    // this does not seem to be necessary on macOS, but maybe it is on Linux; will need testing FIXME\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n    \n    image_window->setAttribute(Qt::WA_DeleteOnClose, true);\n    \n    return image_window;\n}\n\nvoid QtSLiMAppDelegate::dispatch_showCycle_WF(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/TickCycle_WF.png\", \"WF Cycle\", 0.32);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showCycle_nonWF(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/TickCycle_nonWF.png\", \"nonWF Cycle\", 0.32);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showCycle_WF_MS(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/TickCycle_WF_MS.png\", \"WF Cycle (Multispecies)\", 0.32);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showCycle_nonWF_MS(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/TickCycle_nonWF_MS.png\", \"nonWF Cycle (Multispecies)\", 0.32);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showColorChart(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/ColorChart.png\", \"Eidos Color Chart\", 0.5);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showPlotSymbols(void)\n{\n    QWidget *imageWindow = globalImageWindowWithPath(\":/help/PlotSymbols.png\", \"Plot Symbols\", 0.32);\n    \n    if (imageWindow)\n        QtSLiMMakeWindowVisibleAndExposed(imageWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_showColorScales(void)\n{\n    // This shows a global window that displays SLiMgui's color scales.  Unlike the above global image\n    // windows shown by globalImageWindowWithPath(), this window is drawn dynamically by a custom widget.\n    // This code is based on the code in globalImageWindowWithPath(), with that custom widget.\n    int window_width = round(301);\n    int window_height = round(197);\n    \n    QWidget *image_window = new QWidget(nullptr, Qt::Window | Qt::Tool);    // a parentless standalone window\n    \n    image_window->setWindowTitle(\"SLiMgui Color Scales\");\n    image_window->setFixedSize(window_width, window_height);\n    \n    // Make the custom widget\n    QtSLiMColorScaleWidget *colorScaleView = new QtSLiMColorScaleWidget(image_window);\n    \n    // Install imageView in the window\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    image_window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    topLayout->addWidget(colorScaleView);\n    \n    // Position the window nicely\n    //positionNewSubsidiaryWindow(image_window);\n    \n    // make window actions for all global menu items\n    // this does not seem to be necessary on macOS, but maybe it is on Linux; will need testing FIXME\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n    \n    image_window->setAttribute(Qt::WA_DeleteOnClose, true);\n    \n    if (image_window)\n        QtSLiMMakeWindowVisibleAndExposed(image_window);\n}\n\nvoid QtSLiMAppDelegate::dispatch_help(void)\n{\n    QtSLiMHelpWindow &helpWindow = QtSLiMHelpWindow::instance();\n    \n    QtSLiMMakeWindowVisibleAndExposed(&helpWindow);\n}\n\nvoid QtSLiMAppDelegate::dispatch_biggerFont(void)\n{\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    \n    prefs.displayFontBigger();\n}\n\nvoid QtSLiMAppDelegate::dispatch_smallerFont(void)\n{\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    \n    prefs.displayFontSmaller();\n}\n\nvoid QtSLiMAppDelegate::dispatch_quit(void)\n{\n    if (qApp)\n    {\n        closeRejected_ = false;\n        qApp->closeAllWindows();\n        \n        if (!closeRejected_)\n        {\n            // On macOS, explicitly quit since last window close doesn't auto-quit, for Qt 5.15.2.\n            // Builds against older Qt versions will just quit on the last window close, because\n            // QTBUG-86874 and QTBUG-86875 prevent this from working.\n#ifdef __APPLE__\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 2))\n            qApp->quit();\n#endif\n#endif\n        }\n    }\n}\n\nvoid QtSLiMAppDelegate::dispatch_newWF(void)\n{\n    newFile_WF(true);\n}\n\nvoid QtSLiMAppDelegate::dispatch_newWF_commentless(void)\n{\n    newFile_WF(false);\n}\n\nvoid QtSLiMAppDelegate::dispatch_newNonWF(void)\n{\n    newFile_nonWF(true);\n}\n\nvoid QtSLiMAppDelegate::dispatch_newNonWF_commentless(void)\n{\n    newFile_nonWF(false);\n}\n\nvoid QtSLiMAppDelegate::dispatch_open(void)\n{\n    open(nullptr);\n}\n\nvoid QtSLiMAppDelegate::dispatch_close(void)\n{\n    // We close the \"active\" window, which is a bit different from the front window\n    // It can be nullptr; in that case it's hard to know what to do\n    QWidget *currentActiveWindow = QApplication::activeWindow();\n    \n    if (currentActiveWindow)\n        currentActiveWindow->close();\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMAppDelegate::dispatch_copyAsHTML(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(focusWidget);\n    \n    if (scriptEdit && scriptEdit->isEnabled())\n        scriptEdit->copyAsHTML();\n}\n\nvoid QtSLiMAppDelegate::dispatch_shiftLeft(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(focusWidget);\n    \n    if (scriptEdit && scriptEdit->isEnabled() && !scriptEdit->isReadOnly())\n        scriptEdit->shiftSelectionLeft();\n}\n\nvoid QtSLiMAppDelegate::dispatch_shiftRight(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(focusWidget);\n    \n    if (scriptEdit && scriptEdit->isEnabled() && !scriptEdit->isReadOnly())\n        scriptEdit->shiftSelectionRight();\n}\n\nvoid QtSLiMAppDelegate::dispatch_commentUncomment(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(focusWidget);\n    \n    if (scriptEdit && scriptEdit->isEnabled() && !scriptEdit->isReadOnly())\n        scriptEdit->commentUncommentSelection();\n}\n\nvoid QtSLiMAppDelegate::dispatch_undo(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())\n        lineEdit->undo();\n    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())\n        textEdit->undo();\n    else if (plainTextEdit && plainTextEdit->isEnabled() && !plainTextEdit->isReadOnly())\n        plainTextEdit->undo();\n}\n\nvoid QtSLiMAppDelegate::dispatch_redo(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())\n        lineEdit->redo();\n    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())\n        textEdit->redo();\n    else if (plainTextEdit && plainTextEdit->isEnabled() && !plainTextEdit->isReadOnly())\n        plainTextEdit->redo();\n}\n\nvoid QtSLiMAppDelegate::dispatch_cut(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())\n        lineEdit->cut();\n    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())\n        textEdit->cut();\n    else if (plainTextEdit && plainTextEdit->isEnabled() && !plainTextEdit->isReadOnly())\n        plainTextEdit->cut();\n}\n\nvoid QtSLiMAppDelegate::dispatch_copy(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled())\n        lineEdit->copy();\n    else if (textEdit && textEdit->isEnabled())\n        textEdit->copy();\n    else if (plainTextEdit && plainTextEdit->isEnabled())\n        plainTextEdit->copy();\n}\n\nvoid QtSLiMAppDelegate::dispatch_paste(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())\n        lineEdit->paste();\n    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())\n        textEdit->paste();\n    else if (plainTextEdit && plainTextEdit->isEnabled() && !plainTextEdit->isReadOnly())\n        plainTextEdit->paste();\n}\n\nvoid QtSLiMAppDelegate::dispatch_duplicate(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(focusWidget);\n    \n    if (scriptEdit && scriptEdit->isEnabled() && !scriptEdit->isReadOnly())\n        scriptEdit->duplicateSelection();\n}\n\nvoid QtSLiMAppDelegate::dispatch_delete(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled() && !lineEdit->isReadOnly())\n        lineEdit->insert(\"\");\n    else if (textEdit && textEdit->isEnabled() && !textEdit->isReadOnly())\n        textEdit->insertPlainText(\"\");\n    else if (plainTextEdit && plainTextEdit->isEnabled() && !plainTextEdit->isReadOnly())\n        plainTextEdit->insertPlainText(\"\");\n}\n\nvoid QtSLiMAppDelegate::dispatch_selectAll(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(focusWidget);\n    QTextEdit *textEdit = dynamic_cast<QTextEdit*>(focusWidget);\n    QPlainTextEdit *plainTextEdit = dynamic_cast<QPlainTextEdit*>(focusWidget);\n    \n    if (lineEdit && lineEdit->isEnabled())\n        lineEdit->selectAll();\n    else if (textEdit && textEdit->isEnabled())\n        textEdit->selectAll();\n    else if (plainTextEdit && plainTextEdit->isEnabled())\n        plainTextEdit->selectAll();\n}\n\nvoid QtSLiMAppDelegate::dispatch_findShow(void)\n{\n    QtSLiMFindPanel::instance().showFindPanel();\n}\n\nvoid QtSLiMAppDelegate::dispatch_findNext(void)\n{\n    QtSLiMFindPanel::instance().findNext();\n}\n\nvoid QtSLiMAppDelegate::dispatch_findPrevious(void)\n{\n    QtSLiMFindPanel::instance().findPrevious();\n}\n\nvoid QtSLiMAppDelegate::dispatch_replaceAndFind(void)\n{\n    QtSLiMFindPanel::instance().replaceAndFind();\n}\n\nvoid QtSLiMAppDelegate::dispatch_useSelectionForFind(void)\n{\n    QtSLiMFindPanel::instance().useSelectionForFind();\n}\n\nvoid QtSLiMAppDelegate::dispatch_useSelectionForReplace(void)\n{\n    QtSLiMFindPanel::instance().useSelectionForReplace();\n}\n\nvoid QtSLiMAppDelegate::dispatch_jumpToSelection(void)\n{\n    QtSLiMFindPanel::instance().jumpToSelection();\n}\n\nvoid QtSLiMAppDelegate::dispatch_jumpToLine(void)\n{\n    QtSLiMFindPanel::instance().jumpToLine();\n}\n\nvoid QtSLiMAppDelegate::dispatch_focusOnScript(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->scriptTextEdit()->setFocus();\n    else if (eidosConsole)\n        eidosConsole->scriptTextEdit()->setFocus();\n}\n\nvoid QtSLiMAppDelegate::dispatch_focusOnConsole(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->outputTextEdit()->setFocus();\n    else if (eidosConsole)\n        eidosConsole->consoleTextEdit()->setFocus();\n}\n\nvoid QtSLiMAppDelegate::dispatch_checkScript(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->scriptTextEdit()->checkScript();\n    else if (eidosConsole)\n        eidosConsole->scriptTextEdit()->checkScript();\n}\n\nvoid QtSLiMAppDelegate::dispatch_prettyprintScript(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->scriptTextEdit()->prettyprint();\n    else if (eidosConsole)\n        eidosConsole->scriptTextEdit()->prettyprint();\n}\n\nvoid QtSLiMAppDelegate::dispatch_reformatScript(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->scriptTextEdit()->reformat();\n    else if (eidosConsole)\n        eidosConsole->scriptTextEdit()->reformat();\n}\n\nvoid QtSLiMAppDelegate::dispatch_showEidosConsole(void)\n{\n    QtSLiMWindow *slimWindow = dispatchQtSLiMWindowFromSecondaries();\n    \n    if (slimWindow)\n        slimWindow->showConsoleClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_showVariableBrowser(void)\n{\n    QtSLiMWindow *slimWindow = dispatchQtSLiMWindowFromSecondaries();\n    \n    if (slimWindow)\n        slimWindow->showBrowserClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_showDebuggingOutput(void)\n{\n    QtSLiMWindow *slimWindow = dispatchQtSLiMWindowFromSecondaries();\n    \n    if (slimWindow)\n        slimWindow->debugOutputClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_clearOutput(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->clearOutputClicked();\n    else if (eidosConsole)\n        eidosConsole->consoleTextEdit()->clearToPrompt();\n}\n\nvoid QtSLiMAppDelegate::dispatch_clearDebugPoints(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMWindow *slimWindow = dynamic_cast<QtSLiMWindow*>(focusWindow);\n    \n    if (slimWindow)\n        slimWindow->clearDebugPointsClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_executeSelection(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (eidosConsole)\n        eidosConsole->executeSelectionClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_executeAll(void)\n{\n    QWidget *focusWidget = QApplication::focusWidget();\n    QWidget *focusWindow = (focusWidget ? focusWidget->window() : activeWindow());\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    \n    if (eidosConsole)\n        eidosConsole->executeAllClicked();\n}\n\nvoid QtSLiMAppDelegate::dispatch_minimize(void)\n{\n    // We minimize the \"active\" window, which is a bit different from the front window\n    // It can be nullptr; in that case it's hard to know what to do\n    QWidget *currentActiveWindow = QApplication::activeWindow();\n    \n    if (currentActiveWindow)\n    {\n        bool isMinimized = currentActiveWindow->windowState() & Qt::WindowMinimized;\n        \n        if (isMinimized)\n            currentActiveWindow->setWindowState((currentActiveWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);\n        else\n            currentActiveWindow->setWindowState(currentActiveWindow->windowState() | Qt::WindowMinimized);    // Qt refuses to minimize Qt::Tool windows; see https://bugreports.qt.io/browse/QTBUG-86520\n    }\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMAppDelegate::dispatch_zoom(void)\n{\n    // We zoom the \"active\" window, which is a bit different from the front window\n    // It can be nullptr; in that case it's hard to know what to do\n    QWidget *currentActiveWindow = QApplication::activeWindow();\n    \n    if (currentActiveWindow)\n    {\n        bool isZoomed = currentActiveWindow->windowState() & Qt::WindowMaximized;\n        \n        if (isZoomed)\n            currentActiveWindow->setWindowState((currentActiveWindow->windowState() & ~Qt::WindowMaximized) | Qt::WindowActive);\n        else\n            currentActiveWindow->setWindowState((currentActiveWindow->windowState() | Qt::WindowMaximized) | Qt::WindowActive);\n    }\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpWorkshops(void)\n{\n    QDesktopServices::openUrl(QUrl(\"http://benhaller.com/workshops/workshops.html\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpFeedback(void)\n{\n    QDesktopServices::openUrl(QUrl(\"mailto:bhaller@mac.com?subject=SLiM%20Feedback\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpSLiMDiscuss(void)\n{\n    QDesktopServices::openUrl(QUrl(\"https://groups.google.com/d/forum/slim-discuss\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpSLiMAnnounce(void)\n{\n    QDesktopServices::openUrl(QUrl(\"https://groups.google.com/d/forum/slim-announce\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpSLiMHome(void)\n{\n    QDesktopServices::openUrl(QUrl(\"http://messerlab.org/slim/\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpSLiMExtras(void)\n{\n    QDesktopServices::openUrl(QUrl(\"https://github.com/MesserLab/SLiM-Extras\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpMesserLab(void)\n{\n    QDesktopServices::openUrl(QUrl(\"http://messerlab.org/\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpBenHaller(void)\n{\n    QDesktopServices::openUrl(QUrl(\"http://www.benhaller.com/\", QUrl::TolerantMode));\n}\n\nvoid QtSLiMAppDelegate::dispatch_helpStickSoftware(void)\n{\n    QDesktopServices::openUrl(QUrl(\"http://www.sticksoftware.com/\", QUrl::TolerantMode));\n}\n\n\n//\n//  Active QtSLiMWindow tracking\n//\n//  For the Find window and similar modeless interactions, we need to be able to find the active\n//  main window, which Qt does not provide (the \"active window\" is not necessarily a main window).\n//  To do this, we have to track focus changes, to maintain a list of windows that is sorted from\n//  front to back.\n//\n\nvoid QtSLiMAppDelegate::updateActiveWindowList(void)\n{\n    QWidget *window = qApp->activeWindow();\n    \n    if (window)\n    {\n        // window is now the front window, so move it to the front of focusedQtSLiMWindowList\n        focusedWindowList.removeOne(window);\n        focusedWindowList.push_front(window);\n    }\n    \n    // keep the window list trim and accurate\n    pruneWindowList();\n    \n    // emit our signal\n    emit activeWindowListChanged();\n    \n    // we're done updating, we can now update again if something new happens\n    queuedActiveWindowUpdate = false;\n    \n    // debug output\n//    qDebug() << \"New window list:\";\n//\n//    for (QPointer<QWidget> &window_ptr : focusedWindowList)\n//        if (window_ptr)\n//            qDebug() << \"   \" << window_ptr->windowTitle();\n}\n\nvoid QtSLiMAppDelegate::focusChanged(QWidget * /* old */, QWidget * /* now */)\n{\n    // track the active window; we use a timer here because the active window is not yet accurate in all cases\n    // we also want to coalesce the work involved, so we use a flag to avoid scheduling more than one update\n    if (!queuedActiveWindowUpdate)\n    {\n        queuedActiveWindowUpdate = true;\n        QTimer::singleShot(0, this, &QtSLiMAppDelegate::updateActiveWindowList);\n    }\n}\n\nvoid QtSLiMAppDelegate::pruneWindowList(void)\n{\n    int windowListCount = focusedWindowList.size();\n    \n    for (int listIndex = 0; listIndex < windowListCount; listIndex++)\n    {\n        QPointer<QWidget> &focused_window_ptr = focusedWindowList[listIndex];\n        \n        if (focused_window_ptr && focused_window_ptr->isVisible() && !focused_window_ptr->isHidden())\n        {\n            // prune zombie windows\n            bool isZombie = false;\n            QtSLiMWindow *qtSLiMWindow = qobject_cast<QtSLiMWindow *>(focused_window_ptr);\n            \n            if (qtSLiMWindow)\n                isZombie = qtSLiMWindow->isZombieWindow_;\n            \n            if (!isZombie)\n                continue;\n        }\n        \n        // prune\n        focusedWindowList.removeAt(listIndex);\n        windowListCount--;\n        listIndex--;\n    }\n}\n\nQtSLiMWindow *QtSLiMAppDelegate::activeQtSLiMWindow(void)\n{\n    // First try qApp's active window; if the SLiM window is key, this suffices\n    // This allows Qt to define the active main window in some platform-specific way,\n    // perhaps based upon which window the cursor is in, for example; for the\n    // activeWindowExcluding() method we want our window list to be the sole authority,\n    // but for this method I don't think we do...?\n    // We use this for dispatching commands that could go to any QtSLiMWindow, but that\n    // open a new document window that gets tiled; it's best to tile from the user's\n    // frontmost document window, I suppose.  We do not use it for other dispatch; see\n    // dispatchQtSLiMWindowFromSecondaries() for that.\n    QWidget *currentActiveWindow = qApp->activeWindow();\n    QtSLiMWindow *currentActiveQtSLiMWindow = qobject_cast<QtSLiMWindow *>(currentActiveWindow);\n    \n    if (currentActiveQtSLiMWindow && !currentActiveQtSLiMWindow->isZombieWindow_)\n        return currentActiveQtSLiMWindow;\n    \n    // If that fails, use the last focused main window, as tracked by focusChanged()\n    pruneWindowList();\n    \n    for (QPointer<QWidget> &focused_window_ptr : focusedWindowList)\n    {\n        if (focused_window_ptr)\n        {\n            QWidget *focused_window = focused_window_ptr.data();\n            QtSLiMWindow *focusedQtSLiMWindow = qobject_cast<QtSLiMWindow *>(focused_window);\n            \n            if (focusedQtSLiMWindow && !focusedQtSLiMWindow->isZombieWindow_)\n                return focusedQtSLiMWindow;\n        }\n    }\n    \n    return nullptr;\n}\n\nQWidget *QtSLiMAppDelegate::activeWindow(void)\n{\n    // QApplication can handle this one\n    return qApp->activeWindow();\n}\n\nQWidget *QtSLiMAppDelegate::activeWindowExcluding(QWidget *excluded)\n{\n    // Use the last focused window, as tracked by focusChanged()\n    pruneWindowList();\n    \n    for (QPointer<QWidget> &focused_window_ptr : focusedWindowList)\n    {\n        if (focused_window_ptr)\n        {\n            QWidget *focused_window = focused_window_ptr.data();\n            \n            if (focused_window != excluded)\n                return focused_window;\n        }\n    }\n    \n    return nullptr;\n}\n\n\n// This is declared in eidos_beep.h, but in QtSLiM it is actually defined here,\n// so that we can produce the beep sound with Qt\nstd::string Eidos_Beep_QT(const std::string &__attribute__((__unused__)) p_sound_name)\n{\n    std::string return_string;\n    \n    qApp->beep();\n    \n    return return_string;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMAppDelegate.h",
    "content": "//\n//  QtSLiMAppDelegate.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/13/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMAPPDELEGATE_H\n#define QTSLIMAPPDELEGATE_H\n\n#include <QObject>\n#include <QVector>\n#include <QIcon>\n#include <QPointer>\n#include <QMainWindow>\n#include <string>\n\nclass QMenuBar;\nclass QMenu;\nclass QAction;\nclass QtSLiMWindow;\nclass QtSLiMAppDelegate;\n \n\nextern QtSLiMAppDelegate *qtSLiMAppDelegate;    // global instance\n\nclass QtSLiMAppDelegate : public QObject\n{\n    Q_OBJECT\n\n    std::string app_cwd_;       // the app's current working directory\n    bool launchedFromShell_;\t// true if launched from shell, false if launched from Finder/other\n    \n    bool closeRejected_ = false;    // true if the user cancels the close of a window, to prevent quit\n    bool inDarkMode_ = false;\n    \n    QIcon appIcon_;\n    QIcon appIconHighlighted_;\n    QIcon slimDocumentIcon_;\n    QIcon genericDocumentIcon_;\n    \npublic:\n    explicit QtSLiMAppDelegate(QObject *parent);\n    virtual ~QtSLiMAppDelegate(void) override;\n\n    // Whether we were launched from a shell (true) or Finder/other (false)\n    bool launchedFromShell(void) { return launchedFromShell_; }\n    \n    // The current working directory for the app\n    std::string &QtSLiMCurrentWorkingDirectory(void) { return app_cwd_; }\n    \n    // Tracking the current active main window\n    QtSLiMWindow *activeQtSLiMWindow(void);             // the frontmost window that is a QtSLiMWindow\n    QWidget *activeWindow(void);                        // the frontmost window\n    QWidget *activeWindowExcluding(QWidget *excluded);  // the frontmost window that is not excluded\n    \n    // Finding targets for action dispatch\n    QtSLiMWindow *dispatchQtSLiMWindowFromSecondaries(void);    // the QtSLiMWindow associated with the focused widget or active window\n    \n    // Document opening\n    QtSLiMWindow *findMainWindow(const QString &fileName) const;\n    void newFile_WF(bool includeComments);\n    void newFile_nonWF(bool includeComments);\n    QtSLiMWindow *open(QtSLiMWindow *requester);\n    QtSLiMWindow *openFile(const QString &fileName, QtSLiMWindow *requester);\n    void openRecipeWithName(const QString &recipeName, const QString &recipeScript, QtSLiMWindow *requester);\n\n    // Recipes and Recents menus\n    void setUpRecipesMenu(QMenu *openRecipesSubmenu, QAction *findRecipeAction);\n    void setUpRecentsMenu(QMenu *openRecentSubmenu);\n    \n    void prependToRecentFiles(const QString &fileName);\n    \n    // App-wide shared icons\n    QIcon applicationIcon(void) { return appIcon_; }\n    QIcon slimDocumentIcon(void) { return slimDocumentIcon_; }\n    QIcon genericDocumentIcon(void) { return genericDocumentIcon_; }\n    \n    // Global actions: designated as \"window\" actions to avoid ambiguity, but defined on every window and handled by us\n    void addActionsForGlobalMenuItems(QWidget *window);\n    \npublic slots:\n    void appDidFinishLaunching(QtSLiMWindow *initialWindow);\n    \n    void closeRejected(void) { closeRejected_ = true; }\n    \n    void findRecipe(void);\n    void openRecipe(void);\n    \n    void playStateChanged(void);\n    \n    // These are slots for menu bar actions that get dispatched to the focal widget/window by us.\n    // Every window should use addActionsForGlobalMenuItems() to connect to these slots (except\n    // QtSLiMWindow, which connects the main menu bar actions to these slots instead).  This gives\n    // us a little bit of a \"first responder\" type functionality, where menu items work globally\n    // and get dispatched to the right target according to focus.\n    void dispatch_preferences(void);\n    void dispatch_about(void);\n    void dispatch_showCycle_WF(void);\n    void dispatch_showCycle_nonWF(void);\n    void dispatch_showCycle_WF_MS(void);\n    void dispatch_showCycle_nonWF_MS(void);\n    void dispatch_showColorChart(void);\n    void dispatch_showPlotSymbols(void);\n    void dispatch_showColorScales(void);\n    void dispatch_help(void);\n    void dispatch_quit(void);\n    \n    void dispatch_biggerFont(void);\n    void dispatch_smallerFont(void);\n    \n    void dispatch_newWF(void);\n    void dispatch_newWF_commentless(void);\n    void dispatch_newNonWF(void);\n    void dispatch_newNonWF_commentless(void);\n    void dispatch_open(void);\n    void dispatch_close(void);\n    \n    void dispatch_copyAsHTML(void);\n    void dispatch_shiftLeft(void);\n    void dispatch_shiftRight(void);\n    void dispatch_commentUncomment(void);\n    \n    void dispatch_undo(void);\n    void dispatch_redo(void);\n    void dispatch_cut(void);\n    void dispatch_copy(void);\n    void dispatch_paste(void);\n    void dispatch_duplicate(void);\n    void dispatch_delete(void);\n    void dispatch_selectAll(void);\n    \n    void dispatch_findShow(void);\n    void dispatch_findNext(void);\n    void dispatch_findPrevious(void);\n    void dispatch_replaceAndFind(void);\n    void dispatch_useSelectionForFind(void);\n    void dispatch_useSelectionForReplace(void);\n    void dispatch_jumpToSelection(void);\n    void dispatch_jumpToLine(void);\n    \n    void dispatch_focusOnScript(void);\n    void dispatch_focusOnConsole(void);\n    void dispatch_checkScript(void);\n    void dispatch_prettyprintScript(void);\n    void dispatch_reformatScript(void);\n    void dispatch_showEidosConsole(void);\n    void dispatch_showVariableBrowser(void);\n    void dispatch_clearOutput(void);\n    void dispatch_clearDebugPoints(void);\n    void dispatch_showDebuggingOutput(void);\n    void dispatch_executeSelection(void);\n    void dispatch_executeAll(void);\n\n    void dispatch_minimize(void);\n    void dispatch_zoom(void);\n    \n    void dispatch_helpWorkshops(void);\n    void dispatch_helpFeedback(void);\n    void dispatch_helpSLiMDiscuss(void);\n    void dispatch_helpSLiMAnnounce(void);\n    void dispatch_helpSLiMHome(void);\n    void dispatch_helpSLiMExtras(void);\n    void dispatch_helpMesserLab(void);\n    void dispatch_helpBenHaller(void);\n    void dispatch_helpStickSoftware(void);\n    \nsignals:\n    void modifiersChanged(Qt::KeyboardModifiers newModifiers);\n    void activeWindowListChanged(void);\n    void applicationPaletteChanged(void);\n    \nprivate:\n    virtual bool eventFilter(QObject *p_obj, QEvent *p_event) override;\n    \n    QVector<QPointer<QWidget>> focusedWindowList;       // a list of all windows, from front to back\n    void pruneWindowList(void);                         // remove all windows that are closed or hidden\n    bool queuedActiveWindowUpdate = false;\n    \n    QWidget *globalImageWindowWithPath(const QString &path, const QString &title, double scaleFactor);\n    \n    void updateRecentFileActions(void);\n    void openRecentFile(void);\n    void clearRecentFiles(void);\n    bool hasRecentFiles(void);\n    \nprivate slots:\n    void lastWindowClosed(void);\n    void aboutToQuit(void);\n    void focusChanged(QWidget *old, QWidget *now);\n    void updateActiveWindowList(void);\n};\n\n\n#endif // QTSLIMAPPDELEGATE_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMChromosomeWidget.cpp",
    "content": "//\n//  QtSLiMChromosomeWidget.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/28/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMChromosomeWidget.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMPreferences.h\"\n\n#include <QPainter>\n#include <QMenu>\n#include <QAction>\n#include <QActionGroup>\n#include <QMenu>\n#include <QMouseEvent>\n#include <QtDebug>\n\n#include <map>\n#include <algorithm>\n#include <vector>\n#include <string>\n\n\nstatic const int numberOfTicksPlusOne = 4;\nstatic const int tickLength = 5;\nstatic const int heightForTicks = 16;\nstatic const int selectionKnobSizeExtension = 2;\t// a 5-pixel-width knob is 2: 2 + 1 + 2, an extension on each side plus the one pixel of the bar in the middle\nstatic const int selectionKnobSize = selectionKnobSizeExtension + selectionKnobSizeExtension + 1;\nstatic const int spaceBetweenChromosomes = 5;\n\n\nQtSLiMChromosomeWidgetController::QtSLiMChromosomeWidgetController(QtSLiMWindow *slimWindow, QWidget *displayWindow, Species *focalSpecies, std::string chromosomeSymbol) :\n    QObject(displayWindow ? displayWindow : slimWindow),\n    slimWindow_(slimWindow),\n    displayWindow_(displayWindow),\n    chromosomeSymbol_(chromosomeSymbol)\n{\n    connect(slimWindow_, &QtSLiMWindow::controllerPartialUpdateAfterTick, this, &QtSLiMChromosomeWidgetController::updateFromController);\n    \n    // focalSpecies is used only in the displayWindow case, for showing the species badge in multispecies models\n    // otherwise, slimWindow will control the focal display species for our chromosome view as it requires\n    if (displayWindow)\n    {\n        if (!focalSpecies)\n        {\n            qDebug() << \"no focal species for creating a chromosome display!\";\n            return;\n        }\n        \n        focalSpeciesName_ = focalSpecies->name_;\n        // focalSpeciesAvatar_ is set up in buildChromosomeDisplay();\n    }\n}\n\nvoid QtSLiMChromosomeWidgetController::updateFromController(void)\n{\n    if (displayWindow_)\n    {\n        Species *displaySpecies = focalDisplaySpecies();\n        \n        if (displaySpecies)\n        {\n            Community *community = slimWindow_->community;\n            \n            if (needsRebuild_ && !invalidSimulation() && community->simulation_valid_ && (community->tick_ >= 1))\n            {\n                // It's hard to tell, in general, whether we need a rebuild: if the number of\n                // chromosomes has changed, or the length of any chromosome, or the symbol of\n                // any chromosome, etc.  There's no harm, so we just always rebuild at the\n                // first valid moment after recycling.\n                buildChromosomeDisplay(/* resetWindowSize */ false);\n                needsRebuild_ = false;\n            }\n        }\n        else\n        {\n            // we've just recycled or become invalid; our next update should rebuild the display\n            needsRebuild_ = true;\n        }\n    }\n    \n    emit needsRedisplay();\n}\n\nSpecies *QtSLiMChromosomeWidgetController::focalDisplaySpecies(void)\n{\n    if (displayWindow_)\n    {\n        // with a chromosome display, we are not based on the current focal species of slimWindow_, so we\n        // need to look up the focal display species dynamically based on its name (which could fail)\n        if (focalSpeciesName_.length() == 0)\n            return nullptr;\n        \n        if (slimWindow_ && slimWindow_->community && (slimWindow_->community->Tick() >= 1))\n            return slimWindow_->community->SpeciesWithName(focalSpeciesName_);\n        \n        return nullptr;\n    }\n    \n    // otherwise, our focal display species comes directly from slimWindow_\n    return slimWindow_->focalDisplaySpecies();\n}\n\nvoid QtSLiMChromosomeWidgetController::buildChromosomeDisplay(bool resetWindowSize)\n{\n    // Remove any existing content from our display window and build new content\n    if (!displayWindow_)\n        return;\n    \n    // Assess the chromosomes to be displayed\n    Species *focalSpecies = focalDisplaySpecies();\n    std::vector<Chromosome *> chromosomes;\n    bool singleChromosomeDisplay = (chromosomeSymbol_.length() != 0);   // a single-chromosome display has an associated symbol\n    \n    if (singleChromosomeDisplay)\n    {\n        // displaying a specific chromosome; check that it still exists\n        Chromosome *symbol_chrom = focalSpecies->ChromosomeFromSymbol(chromosomeSymbol_);\n        \n        if (symbol_chrom)\n            chromosomes.push_back(symbol_chrom);\n    }\n    else\n    {\n        // displaying all chromosomes\n        chromosomes = focalSpecies->Chromosomes();  // copies it, whatever\n    }\n    \n    int chromosomeCount = (int)chromosomes.size();\n    slim_position_t chromosomeMaxLength = 0;\n    \n    for (Chromosome *chromosome : chromosomes)\n    {\n        slim_position_t length = chromosome->last_position_ + 1;\n        \n        chromosomeMaxLength = std::max(chromosomeMaxLength, length);\n    }\n    \n    // Deal with window sizing; when displaying a single chromosome, the height is 16 more to make room for ticks\n    const int margin = 5;\n    const int spacing = 5;\n    const int buttonRowHeight = margin + margin + 20;\n    const int minChromosomeHeight = 20 + (singleChromosomeDisplay ? 35 : 0);\n    const int maxChromosomeHeight = 200 + (singleChromosomeDisplay ? 35 : 0);\n    const int defaultChromosomeHeight = 30 + (singleChromosomeDisplay ? 35 : 0);\n    const int rowCount = std::max(chromosomeCount, 1);      // space for a message row, if there are no chromosomes\n    \n    displayWindow_->setMinimumSize(500, margin + minChromosomeHeight * rowCount + spacing * (rowCount - 1) + buttonRowHeight);\n    displayWindow_->setMaximumSize(4096, margin + maxChromosomeHeight * rowCount + spacing * (rowCount - 1) + buttonRowHeight);\n    if (resetWindowSize)\n        displayWindow_->resize(800, margin + defaultChromosomeHeight * rowCount + spacing * (rowCount - 1) + buttonRowHeight);\n    \n    // Find the top-level layout and remove all of its current children\n    QVBoxLayout *topLayout = qobject_cast<QVBoxLayout *>(displayWindow_->layout());\n    \n    QtSLiMClearLayout(topLayout, /* deleteWidgets */ true);\n    \n    if (chromosomeCount > 0)\n    {\n        // Add a chromosome view for each chromosome in the model, with a spacer next to it to give it the right length\n        std::vector<QLabel *> labels;\n        bool firstRow = true;\n        \n        for (Chromosome *chromosome : chromosomes)\n        {\n            QHBoxLayout *rowLayout = new QHBoxLayout;\n            \n            rowLayout->setContentsMargins(margin, firstRow ? margin : spacing, margin, 0);\n            rowLayout->setSpacing(0);\n            topLayout->addLayout(rowLayout);\n            \n            QtSLiMChromosomeWidget *chromosomeWidget = new QtSLiMChromosomeWidget(nullptr);\n            \n            chromosomeWidget->setController(this);\n            chromosomeWidget->setFocalChromosome(chromosome);\n            chromosomeWidget->setDisplayedRange(QtSLiMRange(0, 0)); // display entirety\n            \n            // multi-chromosome displays do not show ticks, because it would be too crowded; single-chromosome displays do\n            if (!singleChromosomeDisplay)\n                chromosomeWidget->setShowsTicks(false);\n            \n            slim_position_t length = chromosome->last_position_ + 1;\n            double fractionOfMax = length / (double)chromosomeMaxLength;\n            int chromosomeStretch = (int)(round(fractionOfMax * 255));  // Qt requires a max value of 255\n            \n            QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);\n            sizePolicy1.setHorizontalStretch(useScaledWidths_ ? chromosomeStretch : 0);\n            sizePolicy1.setVerticalStretch(0);\n            chromosomeWidget->setSizePolicy(sizePolicy1);\n            \n            QLabel *chromosomeLabel = new QLabel();\n            chromosomeLabel->setText(QString::fromStdString(chromosome->symbol_));\n            chromosomeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);\n            \n            QSizePolicy sizePolicy2(QSizePolicy::Fixed, QSizePolicy::Expanding);\n            chromosomeLabel->setSizePolicy(sizePolicy2);\n            \n            rowLayout->addWidget(chromosomeLabel);\n            rowLayout->addSpacing(margin);\n            rowLayout->addWidget(chromosomeWidget);\n            \n            if (useScaledWidths_)\n                rowLayout->addStretch(255 - chromosomeStretch);     // the remaining width after chromosomeStretch\n            \n            labels.push_back(chromosomeLabel);\n            \n            firstRow = false;\n        }\n        \n        // adjust all the labels to have the same width\n        int maxWidth = 0;\n        \n        for (QLabel *label : labels)\n            maxWidth = std::max(maxWidth, label->sizeHint().width());\n        \n        for (QLabel *label : labels)\n            label->setMinimumWidth(maxWidth);\n    }\n    else\n    {\n        // no chromosomes; make a single row with a message label and nothing else\n        QHBoxLayout *rowLayout = new QHBoxLayout;\n        \n        rowLayout->setContentsMargins(margin, margin, margin, 0);\n        rowLayout->setSpacing(0);\n        topLayout->addLayout(rowLayout);\n        \n        QLabel *chromosomeLabel = new QLabel();\n        \n        if (singleChromosomeDisplay)\n            chromosomeLabel->setText(QString(\"no chromosome with symbol '%1' found\").arg(QString::fromStdString(chromosomeSymbol_)));\n        else\n            chromosomeLabel->setText(\"no chromosomes found for display\");\n            \n        chromosomeLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);\n        chromosomeLabel->setEnabled(false);\n        \n        QFont labelFont(chromosomeLabel->font());\n        labelFont.setBold(true);\n        chromosomeLabel->setFont(labelFont);\n        \n        QSizePolicy sizePolicy2(QSizePolicy::Expanding, QSizePolicy::Expanding);\n        chromosomeLabel->setSizePolicy(sizePolicy2);\n        \n        rowLayout->addWidget(chromosomeLabel);\n    }\n    \n    // Add a horizontal layout at the bottom, for the action button\n    QHBoxLayout *buttonLayout = nullptr;\n    \n    {\n        buttonLayout = new QHBoxLayout;\n        \n        buttonLayout->setContentsMargins(margin, margin, margin, margin);\n        buttonLayout->setSpacing(5);\n        topLayout->addLayout(buttonLayout);\n        \n        // set up the species badge; note that unlike QtSLiMGraphView, we set it up here immediately,\n        // since we are guaranteed to already have a valid species object, and then we don't update it\n        focalSpeciesAvatar_ = focalSpecies->avatar_;\n        \n        if (focalSpeciesAvatar_.length() && (focalSpecies->community_.all_species_.size() > 1))\n        {\n            QLabel *speciesLabel = new QLabel();\n            speciesLabel->setText(QString::fromStdString(focalSpeciesAvatar_));\n            buttonLayout->addWidget(speciesLabel);\n        }\n        \n        QSpacerItem *rightSpacer = new QSpacerItem(16, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);\n        buttonLayout->addItem(rightSpacer);\n        \n        // this code is based on the creation of executeScriptButton in ui_QtSLiMEidosConsole.h\n        QtSLiMPushButton *actionButton = new QtSLiMPushButton(displayWindow_);\n        actionButton->setObjectName(QString::fromUtf8(\"actionButton\"));\n        actionButton->setMinimumSize(QSize(20, 20));\n        actionButton->setMaximumSize(QSize(20, 20));\n        actionButton->setFocusPolicy(Qt::NoFocus);\n        QIcon icon4;\n        icon4.addFile(QtSLiMImagePath(\"action\", false), QSize(), QIcon::Normal, QIcon::Off);\n        icon4.addFile(QtSLiMImagePath(\"action\", true), QSize(), QIcon::Normal, QIcon::On);\n        actionButton->setIcon(icon4);\n        actionButton->setIconSize(QSize(20, 20));\n        actionButton->qtslimSetBaseName(\"action\");\n        actionButton->setCheckable(true);\n        actionButton->setFlat(true);\n#if QT_CONFIG(tooltip)\n        actionButton->setToolTip(\"<html><head/><body><p>configure chromosome display</p></body></html>\");\n#endif // QT_CONFIG(tooltip)\n        buttonLayout->addWidget(actionButton);\n        \n        connect(actionButton, &QPushButton::pressed, this, [actionButton, this]() { actionButton->qtslimSetHighlight(true); actionButtonRunMenu(actionButton); });\n        connect(actionButton, &QPushButton::released, this, [actionButton]() { actionButton->qtslimSetHighlight(false); });\n        \n        // note that this action button has no enable/disable code anywhere, since it is happy to respond at all times\n    }\n}\n\nvoid QtSLiMChromosomeWidgetController::runChromosomeContextMenuAtPoint(QPoint p_globalPoint)\n{\n    if (!slimWindow_)\n        return;\n    \n    Community *community = slimWindow_->community;\n    \n    if (!invalidSimulation() && community && community->simulation_valid_)\n    {\n        QMenu contextMenu(\"chromosome_menu\", slimWindow_);  // slimWindow_ is the parent in the sense that the menu is freed if slimWindow_ is freed\n        QAction *scaledWidths = nullptr;\n        QAction *unscaledWidths = nullptr;\n        Species *focalSpecies = focalDisplaySpecies();\n        \n        if (displayWindow_ && focalSpecies && (focalSpecies->Chromosomes().size() > 1))\n        {\n            // only in multichromosome models, offer to scale the widths of the displayed chromosomes\n            // according to their length or not, as the user prefers\n            scaledWidths = contextMenu.addAction(\"Use Scaled Widths\");\n            scaledWidths->setCheckable(true);\n            scaledWidths->setChecked(useScaledWidths_);\n            \n            unscaledWidths = contextMenu.addAction(\"Use Full Widths\");\n            unscaledWidths->setCheckable(true);\n            unscaledWidths->setChecked(!useScaledWidths_);\n            \n            contextMenu.addSeparator();\n        }\n        \n        QAction *displayMutations = contextMenu.addAction(\"Display Mutations\");\n        displayMutations->setCheckable(true);\n        displayMutations->setChecked(shouldDrawMutations_);\n        \n        QAction *displaySubstitutions = contextMenu.addAction(\"Display Substitutions\");\n        displaySubstitutions->setCheckable(true);\n        displaySubstitutions->setChecked(shouldDrawFixedSubstitutions_);\n        \n        QAction *displayGenomicElements = contextMenu.addAction(\"Display Genomic Elements\");\n        displayGenomicElements->setCheckable(true);\n        displayGenomicElements->setChecked(shouldDrawGenomicElements_);\n        \n        QAction *displayRateMaps = contextMenu.addAction(\"Display Rate Maps\");\n        displayRateMaps->setCheckable(true);\n        displayRateMaps->setChecked(shouldDrawRateMaps_);\n        \n        contextMenu.addSeparator();\n        \n        QAction *displayFrequencies = contextMenu.addAction(\"Display Frequencies\");\n        displayFrequencies->setCheckable(true);\n        displayFrequencies->setChecked(!displayHaplotypes_);\n        \n        QAction *displayHaplotypes = contextMenu.addAction(\"Display Haplotypes\");\n        displayHaplotypes->setCheckable(true);\n        displayHaplotypes->setChecked(displayHaplotypes_);\n        \n        QActionGroup *displayGroup = new QActionGroup(this);    // On Linux this provides a radio-button-group appearance\n        displayGroup->addAction(displayFrequencies);\n        displayGroup->addAction(displayHaplotypes);\n        \n        QAction *displayAllMutations = nullptr;\n        QAction *selectNonneutralMutations = nullptr;\n        \n        // mutation type checkmark items\n        {\n            const std::map<slim_objectid_t,MutationType*> &muttypes = community->AllMutationTypes();\n            \n            if (muttypes.size() > 0)\n            {\n                contextMenu.addSeparator();\n                \n                displayAllMutations = contextMenu.addAction(\"Display All Mutations\");\n                displayAllMutations->setCheckable(true);\n                displayAllMutations->setChecked(displayMuttypes_.size() == 0);\n                \n                // Make a sorted list of all mutation types we know – those that exist, and those that used to exist that we are displaying\n                std::vector<slim_objectid_t> all_muttypes;\n                \n                for (auto muttype_iter : muttypes)\n                {\n                    MutationType *muttype = muttype_iter.second;\n                    slim_objectid_t muttype_id = muttype->mutation_type_id_;\n                    \n                    all_muttypes.emplace_back(muttype_id);\n                }\n                \n                all_muttypes.insert(all_muttypes.end(), displayMuttypes_.begin(), displayMuttypes_.end());\n                \n                // Avoid building a huge menu, which will hang the app\n                if (all_muttypes.size() <= 500)\n                {\n                    std::sort(all_muttypes.begin(), all_muttypes.end());\n                    all_muttypes.resize(static_cast<size_t>(std::distance(all_muttypes.begin(), std::unique(all_muttypes.begin(), all_muttypes.end()))));\n                    \n                    // Then add menu items for each of those muttypes\n                    for (slim_objectid_t muttype_id : all_muttypes)\n                    {\n                        QString menuItemTitle = QString(\"Display m%1\").arg(muttype_id);\n                        MutationType *muttype = community->MutationTypeWithID(muttype_id);  // try to look up the mutation type; can fail if it doesn't exists now\n                        \n                        if (muttype && (community->all_species_.size() > 1))\n                            menuItemTitle.append(\" \").append(QString::fromStdString(muttype->species_.avatar_));\n                        \n                        QAction *mutationAction = contextMenu.addAction(menuItemTitle);\n                        \n                        mutationAction->setData(muttype_id);\n                        mutationAction->setCheckable(true);\n                        \n                        if (std::find(displayMuttypes_.begin(), displayMuttypes_.end(), muttype_id) != displayMuttypes_.end())\n                            mutationAction->setChecked(true);\n                    }\n                }\n                \n                contextMenu.addSeparator();\n                \n                selectNonneutralMutations = contextMenu.addAction(\"Select Non-Neutral MutationTypes\");\n            }\n        }\n        \n        // Run the context menu synchronously\n        QAction *action = contextMenu.exec(p_globalPoint);\n        \n        // Act upon the chosen action; we just do it right here instead of dealing with slots\n        if (action)\n        {\n            if (action == scaledWidths)\n            {\n                if (!useScaledWidths_)\n                {\n                    useScaledWidths_ = true;\n                    buildChromosomeDisplay(/* resetWindowSize */ false);\n                }\n            }\n            else if (action == unscaledWidths)\n            {\n                if (useScaledWidths_)\n                {\n                    useScaledWidths_ = false;\n                    buildChromosomeDisplay(/* resetWindowSize */ false);\n                }\n            }\n            else if (action == displayMutations)\n                shouldDrawMutations_ = !shouldDrawMutations_;\n            else if (action == displaySubstitutions)\n                shouldDrawFixedSubstitutions_ = !shouldDrawFixedSubstitutions_;\n            else if (action == displayGenomicElements)\n                shouldDrawGenomicElements_ = !shouldDrawGenomicElements_;\n            else if (action == displayRateMaps)\n                shouldDrawRateMaps_ = !shouldDrawRateMaps_;\n            else if (action == displayFrequencies)\n                displayHaplotypes_ = false;\n            else if (action == displayHaplotypes)\n                displayHaplotypes_ = true;\n            else\n            {\n                const std::map<slim_objectid_t,MutationType*> &muttypes = community->AllMutationTypes();\n                \n                if (action == displayAllMutations)\n                    displayMuttypes_.clear();\n                else if (action == selectNonneutralMutations)\n                {\n                    // - (IBAction)filterNonNeutral:(id)sender\n                    displayMuttypes_.clear();\n                    \n                    for (auto muttype_iter : muttypes)\n                    {\n                        MutationType *muttype = muttype_iter.second;\n                        slim_objectid_t muttype_id = muttype->mutation_type_id_;\n                        \n                        if ((muttype->dfe_type_ != DFEType::kFixed) || (muttype->dfe_parameters_[0] != 0.0))\n                            displayMuttypes_.emplace_back(muttype_id);\n                    }\n                }\n                else\n                {\n                    // - (IBAction)filterMutations:(id)sender\n                    slim_objectid_t muttype_id = action->data().toInt();\n                    auto present_iter = std::find(displayMuttypes_.begin(), displayMuttypes_.end(), muttype_id);\n                    \n                    if (present_iter == displayMuttypes_.end())\n                    {\n                        // this mut-type is not being displayed, so add it to our display list\n                        displayMuttypes_.emplace_back(muttype_id);\n                    }\n                    else\n                    {\n                        // this mut-type is being displayed, so remove it from our display list\n                        displayMuttypes_.erase(present_iter);\n                    }\n                }\n            }\n            \n            emit needsRedisplay();\n        }\n    }\n}\n\nvoid QtSLiMChromosomeWidgetController::actionButtonRunMenu(QtSLiMPushButton *p_actionButton)\n{\n    QPoint mousePos = QCursor::pos();\n    \n    runChromosomeContextMenuAtPoint(mousePos);\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    p_actionButton->qtslimSetHighlight(false);\n}\n\n\nQtSLiMChromosomeWidget::QtSLiMChromosomeWidget(QWidget *p_parent, QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, Qt::WindowFlags f)\n#ifndef SLIM_NO_OPENGL\n    : QOpenGLWidget(p_parent, f)\n#else\n    : QWidget(p_parent, f)\n#endif\n{\n    controller_ = controller;\n    setFocalDisplaySpecies(displaySpecies);\n    \n    // We support both OpenGL and non-OpenGL display, because some platforms seem\n    // to have problems with OpenGL (https://github.com/MesserLab/SLiM/issues/462)\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::useOpenGLPrefChanged, this, [this]() { update(); });\n}\n\nQtSLiMChromosomeWidget::~QtSLiMChromosomeWidget()\n{\n    setDependentChromosomeView(nullptr);\n\t\n    controller_ = nullptr;\n}\n\nvoid QtSLiMChromosomeWidget::setController(QtSLiMChromosomeWidgetController *controller)\n{\n    if (controller != controller_)\n    {\n        if (controller_)\n            disconnect(controller_, &QtSLiMChromosomeWidgetController::needsRedisplay, this, nullptr);\n        \n        controller_ = controller;\n        connect(controller, &QtSLiMChromosomeWidgetController::needsRedisplay, this, &QtSLiMChromosomeWidget::updateAfterTick);\n    }\n}\n\nvoid QtSLiMChromosomeWidget::setFocalDisplaySpecies(Species *displaySpecies)\n{\n    // We can have no focal species (when coming out of the nib, in particular); in that case we display empty state\n    if (displaySpecies && (displaySpecies->name_ != focalSpeciesName_))\n    {\n        // we've switched species, so we should remember the new one\n        focalSpeciesName_ = displaySpecies->name_;\n        \n        // ... and reset to showing an overview of all the chromosomes\n        focalChromosomeSymbol_ = \"\";\n        \n        update();\n        updateDependentView();\n    }\n    else\n    {\n        // if displaySpecies is nullptr or unchanged, we just stick with our last remembered species\n    }\n}\n\nSpecies *QtSLiMChromosomeWidget::focalDisplaySpecies(void)\n{\n    // We look up our focal species object by name every time, since keeping a pointer to it would be unsafe\n    // Before initialize() is done species have not been created, so we return nullptr in that case\n    if (focalSpeciesName_.length() == 0)\n        return nullptr;\n    \n    if (controller_ && controller_->community() && (controller_->community()->Tick() >= 1))\n        return controller_->community()->SpeciesWithName(focalSpeciesName_);\n    \n    return nullptr;\n}\n\nvoid QtSLiMChromosomeWidget::setFocalChromosome(Chromosome *chromosome)\n{\n    if (chromosome)\n    {\n        if (chromosome->Symbol() != focalChromosomeSymbol_)\n        {\n            // we've switched chromosomes, so remember the new one\n            focalChromosomeSymbol_ = chromosome->Symbol();\n            \n            // ... and reset to the default selection\n            setSelectedRange(QtSLiMRange(0, 0));\n            \n            // ... and if our new chromosome belongs to a different species, remember that\n            if (chromosome->species_.name_ != focalSpeciesName_)\n                focalSpeciesName_ = chromosome->species_.name_;\n            \n            update();\n            updateDependentView();\n        }\n    }\n    else\n    {\n        if (focalChromosomeSymbol_.length())\n        {\n            // we had a focal chromosome symbol, so reset to the overall view\n            focalChromosomeSymbol_ = \"\";\n            \n            update();\n            updateDependentView();\n        }\n    }\n}\n\nChromosome *QtSLiMChromosomeWidget::focalChromosome(void)\n{\n    Species *focalSpecies = focalDisplaySpecies();\n    \n    if (focalSpecies)\n    {\n        if (focalChromosomeSymbol_.length())\n        {\n            Chromosome *chromosome = focalSpecies->ChromosomeFromSymbol(focalChromosomeSymbol_);\n            \n            if (isOverview_ && !chromosome)\n            {\n                // The focal chromosome apparently no longer exists, but we want to keep\n                // trying to focus on it if it comes back (e.g., after a recycle), so we\n                // do not reset or forget the focal chromosome symbol here; we only reset\n                // the symbol to \"\" in setFocalDisplaySpecies() and setFocalChromosome().\n                // However, if the focal species has chromosomes (and they don't match),\n                // then apparently we're waiting for something that won't happen; give up\n                // and switch.\n                if (focalSpecies->Chromosomes().size() > 1)\n                {\n                    focalChromosomeSymbol_ = \"\";\n                    return nullptr;\n                }\n                else if (focalSpecies->Chromosomes().size() == 1)\n                {\n                    chromosome = focalSpecies->Chromosomes()[0];\n                    focalChromosomeSymbol_ = chromosome->Symbol();\n                }\n            }\n            \n            return chromosome;\n        }\n        else if (focalSpecies->Chromosomes().size() == 1)\n        {\n            // The species has just one chromosome, so there is no visual difference\n            // between that chromosome being selected vs. not selected.  However, we\n            // want to return that chromosome to the caller, so if it is not selected,\n            // we fix that here and return it.\n            Chromosome *chromosome = focalSpecies->Chromosomes()[0];\n            \n            focalChromosomeSymbol_ = chromosome->Symbol();\n            return chromosome;\n        }\n    }\n    \n    return nullptr;\n}\n\nvoid QtSLiMChromosomeWidget::setDependentChromosomeView(QtSLiMChromosomeWidget *p_dependent_widget)\n{\n    if (dependentChromosomeView_ != p_dependent_widget)\n    {\n        dependentChromosomeView_ = p_dependent_widget;\n        isOverview_ = (dependentChromosomeView_ ? true : false);\n        showsTicks_ = !isOverview_;\n        \n        updateDependentView();\n    }\n}\n\nvoid QtSLiMChromosomeWidget::updateDependentView(void)\n{\n    if (dependentChromosomeView_)\n    {\n        Chromosome *chromosome = focalChromosome();\n        \n        dependentChromosomeView_->setFocalChromosome(chromosome);\n        \n        if (chromosome)\n            dependentChromosomeView_->setDisplayedRange(getSelectedRange(chromosome));\n        else\n            dependentChromosomeView_->setDisplayedRange(QtSLiMRange(0, 0)); // display entirely\n        \n        dependentChromosomeView_->stateChanged();\n    }\n}\n\nvoid QtSLiMChromosomeWidget::stateChanged(void)\n{\n    update();\n}\n\nvoid QtSLiMChromosomeWidget::updateAfterTick(void)\n{\n    // overview chromosomes don't need to update all the time, since their display doesn't change\n    if (!isOverview_)\n        stateChanged();\n}\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMChromosomeWidget::initializeGL()\n{\n    initializeOpenGLFunctions();\n    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);\n}\n\nvoid QtSLiMChromosomeWidget::resizeGL(int w, int h)\n{\n    glViewport(0, 0, w, h);\n    \n\t// Update the projection\n\tglMatrixMode(GL_PROJECTION);\n    glLoadIdentity();\n\tglMatrixMode(GL_MODELVIEW);\n}\n#endif\n\nQRect QtSLiMChromosomeWidget::rectEncompassingBaseToBase(slim_position_t startBase, slim_position_t endBase, QRect interiorRect, QtSLiMRange displayedRange)\n{\n\tdouble startFraction = (startBase - static_cast<slim_position_t>(displayedRange.location)) / static_cast<double>(displayedRange.length);\n\tdouble leftEdgeDouble = interiorRect.left() + startFraction * interiorRect.width();\n\tdouble endFraction = (endBase + 1 - static_cast<slim_position_t>(displayedRange.location)) / static_cast<double>(displayedRange.length);\n\tdouble rightEdgeDouble = interiorRect.left() + endFraction * interiorRect.width();\n\tint leftEdge, rightEdge;\n\t\n\tif (rightEdgeDouble - leftEdgeDouble > 1.0)\n\t{\n\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\tleftEdge = static_cast<int>(floor(leftEdgeDouble));\n\t\trightEdge = static_cast<int>(ceil(rightEdgeDouble));\n\t}\n\telse\n\t{\n\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the left-right positions span a pixel boundary\n\t\tleftEdge = static_cast<int>(floor(leftEdgeDouble));\n\t\trightEdge = leftEdge + 1;\n\t}\n\t\n\treturn QRect(leftEdge, interiorRect.top(), rightEdge - leftEdge, interiorRect.height());\n}\n\nslim_position_t QtSLiMChromosomeWidget::baseForPosition(double position, QRect interiorRect, QtSLiMRange displayedRange)\n{\n\tdouble fraction = (position - interiorRect.left()) / interiorRect.width();\n\tslim_position_t base = static_cast<slim_position_t>(floor(fraction * (displayedRange.length + 1) + displayedRange.location));\n\t\n\treturn base;\n}\n\nQRect QtSLiMChromosomeWidget::getContentRect(void)\n{\n    QRect bounds = rect();\n\t\n\t// The height gets adjusted because our \"content rect\" does not include the space for selection knobs below\n    // (for the overview) or for tick marks and labels (for the zoomed view).  Note that SLiMguiLegacy has a two-\n    // pixel margin on the left and right of the chromosome view, to avoid clipping the selection knobs, but that\n    // is a bit harder to do in Qt since the UI layout is trickier, so we just let the knobs clip; it's fine.\n    int bottomMargin = (isOverview_ ? (selectionKnobSize+1) : heightForTicks);\n    \n    if (!isOverview_ && !showsTicks_)\n        bottomMargin = 0;\n    \n    return QRect(bounds.left(), bounds.top(), bounds.width(), bounds.height() - bottomMargin);\n}\n\nQtSLiMRange QtSLiMChromosomeWidget::getSelectedRange(Chromosome *chromosome)\n{\n    if (hasSelection_ && chromosome && (chromosome == focalChromosome()))\n\t{\n\t\treturn QtSLiMRange(selectionFirstBase_, selectionLastBase_ - selectionFirstBase_ + 1);\t// number of bases encompassed; a selection from x to x encompasses 1 base\n\t}\n    else if (chromosome)\n\t{\n\t\tslim_position_t chromosomeLastPosition = chromosome->last_position_;\n\t\t\n\t\treturn QtSLiMRange(0, chromosomeLastPosition + 1);\t// chromosomeLastPosition + 1 bases are encompassed\n\t}\n    else\n    {\n        return QtSLiMRange(0, 0);\n    }\n}\n\nvoid QtSLiMChromosomeWidget::setSelectedRange(QtSLiMRange p_selectionRange)\n{\n    if (isOverview_ && (p_selectionRange.length >= 1))\n\t{\n\t\tselectionFirstBase_ = static_cast<slim_position_t>(p_selectionRange.location);\n\t\tselectionLastBase_ = static_cast<slim_position_t>(p_selectionRange.location + p_selectionRange.length) - 1;\n\t\thasSelection_ = true;\n\t\t\n\t\t// Save the selection for restoring across recycles, etc.\n\t\tsavedSelectionFirstBase_ = selectionFirstBase_;\n\t\tsavedSelectionLastBase_ = selectionLastBase_;\n\t\tsavedHasSelection_ = hasSelection_;\n\t}\n\telse if (hasSelection_)\n\t{\n\t\thasSelection_ = false;\n\t\t\n\t\t// Save the selection for restoring across recycles, etc.\n\t\tsavedHasSelection_ = hasSelection_;\n\t}\n\telse\n\t{\n\t\t// Save the selection for restoring across recycles, etc.\n\t\tsavedHasSelection_ = false;\n\t\t\n\t\treturn;\n\t}\n\t\n\t// Our selection changed, so update and post a change notification\n    update();\n    \n    if (isOverview_ && dependentChromosomeView_)\n        updateDependentView();\n}\n\nvoid QtSLiMChromosomeWidget::restoreLastSelection(void)\n{\n    if (isOverview_ && savedHasSelection_)\n\t{\n\t\tselectionFirstBase_ = savedSelectionFirstBase_;\n\t\tselectionLastBase_ = savedSelectionLastBase_;\n\t\thasSelection_ = savedHasSelection_;\n\t}\n\telse if (hasSelection_)\n\t{\n\t\thasSelection_ = false;\n\t}\n\t\n\t// Our selection changed, so update and post a change notification\n\tupdate();\n    \n    // We want to always post the notification, to make sure updating happens correctly;\n    // this ensures that correct ticks marks get drawn after a recycle, etc.\n    if (isOverview_ && dependentChromosomeView_)\n        updateDependentView();\n}\n\nQtSLiMRange QtSLiMChromosomeWidget::getDisplayedRange(Chromosome *chromosome)\n{\n    if (isOverview_)\n    {\n        // the overview always displays the whole length\n        slim_position_t chromosomeLastPosition = chromosome->last_position_;\n        \n        return QtSLiMRange(0, chromosomeLastPosition + 1);\t// chromosomeLastPosition + 1 bases are encompassed\n    }\n    else if (!chromosome || (displayedRange_.length == 0))\n    {\n        // the detail view displays the entire length unless a specific displayed range is set\n        slim_position_t chromosomeLastPosition = chromosome->last_position_;\n        \n        return QtSLiMRange(0, chromosomeLastPosition + 1);\t// chromosomeLastPosition + 1 bases are encompassed\n    }\n    else\n    {\n\t\treturn displayedRange_;\n    }\n}\n\nvoid QtSLiMChromosomeWidget::setDisplayedRange(QtSLiMRange p_displayedRange)\n{\n    displayedRange_ = p_displayedRange;\n    update();\n}\n\nvoid QtSLiMChromosomeWidget::setShowsTicks(bool p_showTicks)\n{\n    if (p_showTicks != showsTicks_)\n    {\n        showsTicks_ = p_showTicks;\n        update();\n    }\n}\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMChromosomeWidget::paintGL()\n#else\nvoid QtSLiMChromosomeWidget::paintEvent(QPaintEvent * /* p_paint_event */)\n#endif\n{\n    QPainter painter(this);\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    painter.eraseRect(rect());      // erase to background color, which is not guaranteed\n    //painter.fillRect(rect(), Qt::red);\n    \n    painter.setPen(Qt::black);      // make sure we have our default color of black, since Qt apparently does not guarantee that\n    \n    Species *displaySpecies = focalDisplaySpecies();\n    bool ready = (isEnabled() && controller_ && !controller_->invalidSimulation() && (displaySpecies != nullptr));\n    QRect contentRect = getContentRect();\n\tQRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n    \n    // if the simulation is at tick 0, it is not ready\n\tif (ready)\n        if (controller_->community()->Tick() == 0)\n\t\t\tready = false;\n\t\n    if (ready)\n    {\n        if (isOverview_)\n        {\n            drawOverview(displaySpecies, painter);\n        }\n        else\n        {\n            Chromosome *chromosome = focalChromosome();\n            \n            if (!chromosome)\n            {\n                // display all chromosomes simultaneously\n                drawFullGenome(displaySpecies, painter);\n            }\n            else\n            {\n                // display one chromosome in the regular way\n                QtSLiMRange displayedRange = getDisplayedRange(chromosome);\n                \n                // draw ticks at bottom of content rect\n                if (showsTicks_)\n                    drawTicksInContentRect(contentRect, displaySpecies, displayedRange, painter);\n                    \n                    // do the core drawing, with or without OpenGL according to user preference\n#ifndef SLIM_NO_OPENGL\n                if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n                {\n                    painter.beginNativePainting();\n                    glDrawRect(contentRect, displaySpecies, chromosome);\n                    painter.endNativePainting();\n                }\n                else\n#endif\n                {\n                    qtDrawRect(contentRect, displaySpecies, chromosome, painter);\n                }\n                \n                // frame near the end, so that any roundoff errors that caused overdrawing by a pixel get cleaned up\n                QtSLiMFrameRect(contentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.6, 1.0), painter);\n            }\n        }\n    }\n    else\n    {\n        // erase the content area itself\n        painter.fillRect(interiorRect, QtSLiMColorWithWhite(inDarkMode ? 0.118 : 0.9, 1.0));\n        \n        // frame\n        QtSLiMFrameRect(contentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.77, 1.0), painter);\n    }\n}\n\nvoid QtSLiMChromosomeWidget::drawOverview(Species *displaySpecies, QPainter &painter)\n{\n    // the overview draws all of the chromosomes showing genomic elements; always with Qt, not GL\n    Chromosome *focalChrom = focalChromosome();\n    QRect contentRect = getContentRect();\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (!displaySpecies->HasGenetics())\n    {\n        QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n        \n        painter.fillRect(interiorRect, QtSLiMColorWithWhite(inDarkMode ? 0.118 : 0.9, 1.0));\n        QtSLiMFrameRect(contentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.77, 1.0), painter);\n        return;\n    }\n    \n    const std::vector<Chromosome *> &chromosomes = displaySpecies->Chromosomes();\n    int chromosomeCount = (int)chromosomes.size();\n    int64_t availableWidth = contentRect.width() - (chromosomeCount * 2) - ((chromosomeCount - 1) * spaceBetweenChromosomes);\n    int64_t totalLength = 0;\n    \n    // after a delay, we show chromosome numbers unless we're tracking or have a single-chromosome model\n    bool showChromosomeNumbers = (showChromosomeNumbers_ && !isTracking_ && (chromosomeCount > 1));\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        \n        totalLength += chromLength;\n    }\n    \n    if (showChromosomeNumbers)\n    {\n        painter.save();\n        \n        static QFont *tickFont = nullptr;\n        \n        if (!tickFont)\n        {\n            tickFont = new QFont();\n#ifdef __linux__\n            tickFont->setPointSize(8);\n#else\n            tickFont->setPointSize(10);\n#endif\n        }\n        painter.setFont(*tickFont);\n    }\n    \n    int64_t remainingLength = totalLength;\n    int leftPosition = contentRect.left();\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        double scale = (double)availableWidth / remainingLength;\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        int width = (int)round(chromLength * scale);\n        int paddedWidth = 2 + width;\n        QRect chromContentRect(leftPosition, contentRect.top(), paddedWidth, contentRect.height());\n        QRect chromInteriorRect = chromContentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n        QtSLiMRange displayedRange = getDisplayedRange(chrom);\n        \n        if (showChromosomeNumbers)\n        {\n            painter.fillRect(chromInteriorRect, Qt::white);\n            \n            const std::string &symbol = chrom->Symbol();\n            QString symbolLabel = QString::fromStdString(symbol);\n            QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, symbolLabel);\n            double labelWidth = labelBoundingRect.width();\n            \n            // display the chromosome symbol only if there is space for it\n            if (labelWidth < chromInteriorRect.width())\n            {\n                int symbolLabelX = static_cast<int>(round(chromContentRect.center().x())) + 1;\n                int symbolLabelY = static_cast<int>(round(chromContentRect.center().y())) + 7;\n                int textFlags = (Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignBottom | Qt::AlignHCenter);\n                \n                painter.drawText(QRect(symbolLabelX, symbolLabelY, 0, 0), textFlags, symbolLabel);\n            }\n        }\n        else\n        {\n            painter.fillRect(chromInteriorRect, Qt::black);\n            \n            qtDrawGenomicElements(chromInteriorRect, chrom, displayedRange, painter);                    \n        }\n        \n        if (chrom == focalChrom)\n        {\n            if (hasSelection_)\n            {\n                // overlay the selection last, since it bridges over the frame; when showing chromosome numbers\n                // in light mode, drawing the interior shadow looks better because of the white background\n                QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.6, 1.0), painter);\n                overlaySelection(chromInteriorRect, displayedRange, /* drawInteriorShadow */ showChromosomeNumbers && !inDarkMode, painter);\n            }\n            else if (chromosomes.size() > 1)\n            {\n                // the selected chromosome gets a heavier frame, if we have more than one chromosome\n                QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.0 : 0.4, 1.0), painter);\n            }\n            else\n            {\n                QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.6, 1.0), painter);\n            }\n        }\n        else\n        {\n            if ((chromosomes.size() > 1) && focalChrom)\n            {\n                // with more than one chromosome, chromosomes other than the focal chromosome get washed out\n                painter.fillRect(chromInteriorRect, QtSLiMColorWithWhite(inDarkMode ? 0.0 : 1.0, inDarkMode ? 0.50 : 0.60));\n                QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.1 : 0.8, 1.0), painter);\n            }\n            else\n            {\n                QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.6, 1.0), painter);\n            }\n        }\n        \n        leftPosition += (paddedWidth + spaceBetweenChromosomes);\n        availableWidth -= width;\n        remainingLength -= chromLength;\n    }\n    \n    if (showChromosomeNumbers)\n    {\n        painter.restore();\n    }\n}\n\nvoid QtSLiMChromosomeWidget::drawFullGenome(Species *displaySpecies, QPainter &painter)\n{\n    // this is similar to drawOverview(), but shows the detail view and can use GL\n    // we end up here in no-genetics models, because there is no selected chromosome (no chromosomes at all)\n    QRect contentRect = getContentRect();\n    bool inDarkMode = QtSLiMInDarkMode();\n    const std::vector<Chromosome *> &chromosomes = displaySpecies->Chromosomes();\n    int chromosomeCount = (int)chromosomes.size();\n    int64_t availableWidth = contentRect.width() - (chromosomeCount * 2) - ((chromosomeCount - 1) * spaceBetweenChromosomes);\n    int64_t totalLength = 0;\n    \n    if (!displaySpecies->HasGenetics())\n    {\n        QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n        \n        painter.fillRect(interiorRect, QtSLiMColorWithWhite(inDarkMode ? 0.118 : 0.9, 1.0));\n        QtSLiMFrameRect(contentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.77, 1.0), painter);\n        \n        // draw the \"no genetics\" label at the bottom; we now do this instead of drawTicksInContentRect()\n        static QFont *tickFont = nullptr;\n        \n        if (!tickFont)\n        {\n            tickFont = new QFont();\n#ifdef __linux__\n            tickFont->setPointSize(7);\n#else\n            tickFont->setPointSize(9);\n#endif\n        }\n        painter.setFont(*tickFont);\n        \n        QString tickLabel(\"no genetics\");\n        int tickLabelX = static_cast<int>(floor(contentRect.left() + contentRect.width() / 2.0));\n        int tickLabelY = contentRect.bottom() + (2 + 13);\n        int textFlags = (Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignBottom | Qt::AlignHCenter);\n        \n        painter.drawText(QRect(tickLabelX, tickLabelY, 0, 0), textFlags, tickLabel);\n        return;\n    }\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        \n        totalLength += chromLength;\n    }\n    \n    int64_t remainingLength = totalLength;\n    int leftPosition = contentRect.left();\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        // display one chromosome in the regular way\n        double scale = (double)availableWidth / remainingLength;\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        int width = (int)round(chromLength * scale);\n        int paddedWidth = 2 + width;\n        QRect chromContentRect(leftPosition, contentRect.top(), paddedWidth, contentRect.height());\n        QRect chromInteriorRect = chromContentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n        slim_position_t chromosomeLastPosition = chrom->last_position_;\n        QtSLiMRange displayedRange = QtSLiMRange(0, chromosomeLastPosition + 1);    // chromosomeLastPosition + 1 bases are encompassed\n        \n        painter.fillRect(chromInteriorRect, Qt::black);\n        \n        // draw ticks at bottom of content rect\n        if (showsTicks_)\n            drawTicksInContentRect(chromContentRect, displaySpecies, displayedRange, painter);\n        \n        // do the core drawing, with or without OpenGL according to user preference\n#ifndef SLIM_NO_OPENGL\n        if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n        {\n            painter.beginNativePainting();\n            glDrawRect(chromContentRect, displaySpecies, chrom);\n            painter.endNativePainting();\n        }\n        else\n#endif\n        {\n            qtDrawRect(chromContentRect, displaySpecies, chrom, painter);\n        }\n        \n        // frame near the end, so that any roundoff errors that caused overdrawing by a pixel get cleaned up\n        QtSLiMFrameRect(chromContentRect, QtSLiMColorWithWhite(inDarkMode ? 0.067 : 0.6, 1.0), painter);\n        \n        leftPosition += (paddedWidth + spaceBetweenChromosomes);\n        availableWidth -= width;\n        remainingLength -= chromLength;\n    }\n}\n\nvoid QtSLiMChromosomeWidget::drawTicksInContentRect(QRect contentRect, __attribute__((__unused__)) Species *displaySpecies, QtSLiMRange displayedRange, QPainter &painter)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n\tQRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n\tint64_t lastTickIndex = numberOfTicksPlusOne;\n\t\n    painter.save();\n    painter.setPen(inDarkMode ? Qt::white : Qt::black);\n    \n\t// Display fewer ticks when we are displaying a very small number of positions\n\tlastTickIndex = std::min(lastTickIndex, (displayedRange.length + 1) / 3);\n\t\n\tdouble tickIndexDivisor = ((lastTickIndex == 0) ? 1.0 : static_cast<double>(lastTickIndex));\t\t// avoid a divide by zero when we are displaying a single site\n    static QFont *tickFont = nullptr;\n    \n    if (!tickFont)\n    {\n        tickFont = new QFont();\n#ifdef __linux__\n        tickFont->setPointSize(7);\n#else\n        tickFont->setPointSize(9);\n#endif\n    }\n    painter.setFont(*tickFont);\n    \n    QFontMetricsF fontMetrics(*tickFont);\n    \n    if (displayedRange.length == 0)\n\t{\n\t\t// The \"no genetics\" case is now handled in drawFullGenome()\n        painter.restore();\n\t\treturn;\n\t}\n    \n    // We use scientific notation in two situations: (1) for numbers larger than 1e8, for readability, with four digits\n    // after the decimal point, and (2) when the largest tick label and 0 won't fit together, for space-efficiency,\n    // with two digits after the decimal point\n    bool useScientificNotation = false;             // the rightmost tick determines this since it has the largest tickBase\n    int scientificNotationDigits = 4;\n    slim_position_t largestTickBase = static_cast<slim_position_t>(displayedRange.location) + static_cast<slim_position_t>(ceil((displayedRange.length - 1) * (lastTickIndex / tickIndexDivisor)));\n    \n    if (largestTickBase >= 1e7)\n    {\n        useScientificNotation = true;\n    }\n    \n    {\n        QString largestTickLabel;\n        \n        if (useScientificNotation)   // assume X.XXXXeX and check whether space forces us down to X.XXeX format\n        {\n            largestTickLabel = QString::asprintf(\"0  %.4e\", static_cast<double>(largestTickBase));   // is there enough room for a zero and the max tick label?\n            \n            largestTickLabel.replace(\".0000e\", \".0e\");\n            largestTickLabel.replace(\".000e\", \".0e\");\n            largestTickLabel.replace(\"000e\", \"e\");     // didn't get replaced by the previous line, so it must follow a non-zero digit\n            largestTickLabel.replace(\".00e\", \".0e\");\n            largestTickLabel.replace(\"00e\", \"e\");      // didn't get replaced by the previous line, so it must follow a non-zero digit\n            largestTickLabel.replace(\"e+0\", \"e\");\n            largestTickLabel.replace(\"e+\", \"e\");\n        }\n        else\n            QTextStream(&largestTickLabel) << \"0  \" << static_cast<int64_t>(largestTickBase);   // is there enough room for a zero and the max tick label?\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        double tickLabelWidth = fontMetrics.width(largestTickLabel);               // deprecated in 5.11\n#else\n        double tickLabelWidth = fontMetrics.horizontalAdvance(largestTickLabel);   // added in Qt 5.11\n#endif\n        \n        if (tickLabelWidth > interiorRect.width())\n        {\n            useScientificNotation = true;\n            scientificNotationDigits = 2;   // space is tight, so just assume we need to display fewer digits; trying to decide how many we can fit gets very complex\n        }\n    }\n    \n    // Draw tick marks and tick labels; we go from the right backwards because we want to at least fit the rightmost tick label if we can\n    int leftmostNotDrawn = interiorRect.left();     // used to avoid overlapping labels\n    int rightmostNotDrawn = interiorRect.right();   // used to avoid overlapping labels\n    \n\tfor (int simpleTickIndex = 0; simpleTickIndex <= lastTickIndex; ++simpleTickIndex)\n\t{\n        // first figure out the tick position\n        int tickIndex = ((simpleTickIndex == 0) ? lastTickIndex : (((simpleTickIndex == 1) ? 0 : (lastTickIndex - simpleTickIndex + 1))));  // lastTickIndex first, 0 second, then the rest in backwards order\n        slim_position_t tickBase = static_cast<slim_position_t>(displayedRange.location) + static_cast<slim_position_t>(ceil((displayedRange.length - 1) * (tickIndex / tickIndexDivisor)));\t// -1 because we are choosing an in-between-base position that falls, at most, to the left of the last base\n        QRect tickRect = rectEncompassingBaseToBase(tickBase, tickBase, interiorRect, displayedRange);\n        \n        tickRect.setHeight(tickLength);\n        tickRect.moveBottom(contentRect.bottom() + tickLength);\n        \n        // figure out the label's alignment relative to the tick\n        bool forceCenteredLabel = (tickRect.width() > 50);      // with wide ticks, just center all labels; there's room for lots of digits here\n        Qt::AlignmentFlag labelAlignment;\n        int tickLabelX;\n        \n        if ((tickIndex == lastTickIndex) && !forceCenteredLabel)\n        {\n            labelAlignment = Qt::AlignRight;\n            tickLabelX = tickRect.right() + 2;\n        }\n        else if ((tickIndex == 0) && !forceCenteredLabel)\n        {\n            labelAlignment = Qt::AlignLeft;\n            tickLabelX = tickRect.left() - 1;\n        }\n        else\n        {\n            labelAlignment = Qt::AlignHCenter;\n            tickLabelX = static_cast<int>(floor(tickRect.left() + tickRect.width() / 2.0)) + 1;\n        }\n        \n        // make the label\n        QString tickLabel;\n        \n        if (useScientificNotation && (tickBase != 0))\n        {\n            // we remove cruft around the exponential; we want \"1.5000e+09\" -> \"1.5e9\", \"1.0000e+09\" -> \"1.0e9\", etc.\n            if (scientificNotationDigits == 4)\n            {\n                tickLabel = QString::asprintf(\"%.4e\", static_cast<double>(tickBase));\n                \n                tickLabel.replace(\".0000e\", \".0e\");\n                tickLabel.replace(\".000e\", \".0e\");\n                tickLabel.replace(\"000e\", \"e\");     // didn't get replaced by the previous line, so it must follow a non-zero digit\n                tickLabel.replace(\".00e\", \".0e\");\n                tickLabel.replace(\"00e\", \"e\");      // didn't get replaced by the previous line, so it must follow a non-zero digit\n            }\n            else\n            {\n                tickLabel = QString::asprintf(\"%.2e\", static_cast<double>(tickBase));\n                \n                tickLabel.replace(\".00e\", \".0e\");\n                tickLabel.replace(\"00e\", \"e\");      // didn't get replaced by the previous line, so it must follow a non-zero digit\n            }\n            \n            tickLabel.replace(\"e+0\", \"e\");\n            tickLabel.replace(\"e+\", \"e\");\n        }\n        else\n            QTextStream(&tickLabel) << static_cast<int64_t>(tickBase);\n        \n        // measure it\n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        double tickLabelWidth = fontMetrics.width(tickLabel);               // deprecated in 5.11\n#else\n        double tickLabelWidth = fontMetrics.horizontalAdvance(tickLabel);   // added in Qt 5.11\n#endif\n        \n        int labelLeftEdge, labelRightEdge;\n        \n        if (labelAlignment == Qt::AlignRight)\n        {\n            labelLeftEdge = tickLabelX - tickLabelWidth;\n            labelRightEdge = tickLabelX;\n        }\n        else if (labelAlignment == Qt::AlignLeft)\n        {\n            labelLeftEdge = tickLabelX;\n            labelRightEdge = tickLabelX + tickLabelWidth;\n        }\n        else    // Qt::AlignHCenter\n        {\n            labelLeftEdge = tickLabelX - (int)std::ceil(tickLabelWidth / 2.0);\n            labelRightEdge = tickLabelX + (int)std::ceil(tickLabelWidth / 2.0);\n        }\n        \n        // decide whether the label fits\n        bool drawLabel = true;\n        \n        if ((tickIndex == lastTickIndex) && (labelLeftEdge < leftmostNotDrawn))\n            drawLabel = false;\n        else if ((tickIndex > 0) && (tickIndex != lastTickIndex) && (labelLeftEdge - 5 < leftmostNotDrawn))\n            drawLabel = false;\n        else if ((tickIndex < lastTickIndex) && (labelRightEdge + 5 > rightmostNotDrawn))\n            drawLabel = false;\n        \n        if (!drawLabel && (tickIndex == lastTickIndex))                         // if the rightmost label doesn't fit, skip all ticks and labels\n            break;\n        if (!drawLabel && (tickIndex != 0) && (tickIndex != lastTickIndex))     // skip interior tick marks if we skip their label\n            continue;\n        \n        // draw a tick for it; if we are displaying a single site or two sites, make a tick mark one pixel wide; a very wide one looks weird\n        if (displayedRange.length <= 2)\n        {\n            tickRect.setLeft(static_cast<int>(floor(tickRect.left() + tickRect.width() / 2.0 - 0.5)));\n            tickRect.setWidth(1);\n        }\n        \n        painter.fillRect(tickRect, inDarkMode ? QColor(10, 10, 10, 255) : QColor(127, 127, 127, 255));  // in dark mode, 17 matches the frame, but is too light\n        \n        // if we decided to draw the tick even though the label doesn't fit, now skip the label\n        if (!drawLabel)\n            continue;\n        \n        // and then draw the tick label\n        int tickLabelY = contentRect.bottom() + (tickLength + 13);\n        int textFlags = (Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignBottom | labelAlignment);\n        \n        painter.drawText(QRect(tickLabelX, tickLabelY, 0, 0), textFlags, tickLabel);\n        \n        // keep track of where we have drawn text, to avoid overlap; this is a bit tricky because we draw the ticks out of order\n        if (simpleTickIndex == 1)\n            leftmostNotDrawn = std::max(leftmostNotDrawn, labelRightEdge);      // changes only when we draw the left-edge tick\n        if (simpleTickIndex != 1)\n            rightmostNotDrawn = std::min(rightmostNotDrawn, labelLeftEdge);     // does not change when we draw the left-edge tick\n\t}\n    \n    painter.restore();\n}\n\nvoid QtSLiMChromosomeWidget::updateDisplayedMutationTypes(Species *displaySpecies)\n{\n    // We use a flag in MutationType to indicate whether we're drawing that type or not; we update those flags here,\n    // before every drawing of mutations, from the vector of mutation type IDs that we keep internally\n    if (controller_)\n    {\n        if (displaySpecies)\n        {\n            std::map<slim_objectid_t,MutationType*> &muttypes = displaySpecies->mutation_types_;\n            std::vector<slim_objectid_t> &displayTypes = displayMuttypes();\n            \n            for (auto muttype_iter : muttypes)\n            {\n                MutationType *muttype = muttype_iter.second;\n                \n                if (displayTypes.size())\n                {\n                    slim_objectid_t muttype_id = muttype->mutation_type_id_;\n                    \n                    muttype->mutation_type_displayed_ = (std::find(displayTypes.begin(), displayTypes.end(), muttype_id) != displayTypes.end());\n                }\n                else\n                {\n                    muttype->mutation_type_displayed_ = true;\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMChromosomeWidget::overlaySelection(QRect interiorRect, QtSLiMRange displayedRange, bool drawInteriorShadow, QPainter &painter)\n{\n\tif (hasSelection_)\n\t{\n        // wash out the exterior of the selection\n        bool inDarkMode = QtSLiMInDarkMode();\n        \n        if (selectionFirstBase_ > 0)\n        {\n            QRect leftOfSelectionRect = rectEncompassingBaseToBase(0, selectionFirstBase_ - 1, interiorRect, displayedRange);\n            \n            painter.fillRect(leftOfSelectionRect, QtSLiMColorWithWhite(inDarkMode ? 0.0 : 1.0, inDarkMode ? 0.50 : 0.60));\n        }\n        if (selectionLastBase_ < displayedRange.length - 1)\n        {\n            QRect rightOfSelectionRect = rectEncompassingBaseToBase(selectionLastBase_ + 1, displayedRange.length - 1, interiorRect, displayedRange);\n            \n            painter.fillRect(rightOfSelectionRect, QtSLiMColorWithWhite(inDarkMode ? 0.0 : 1.0, inDarkMode ? 0.50 : 0.60));\n        }\n        \n\t\t// draw a bar at the start and end of the selection\n        QRect selectionRect = rectEncompassingBaseToBase(selectionFirstBase_, selectionLastBase_, interiorRect, displayedRange);\n\t\tQRect selectionStartBar1 = QRect(selectionRect.left() - 1, interiorRect.top(), 1, interiorRect.height());\n\t\tQRect selectionStartBar2 = QRect(selectionRect.left(), interiorRect.top(), 1, interiorRect.height() + 5);\n\t\tQRect selectionStartBar3 = QRect(selectionRect.left() + 1, interiorRect.top(), 1, interiorRect.height());\n\t\tQRect selectionEndBar1 = QRect(selectionRect.left() + selectionRect.width() - 2, interiorRect.top(), 1, interiorRect.height());\n\t\tQRect selectionEndBar2 = QRect(selectionRect.left() + selectionRect.width() - 1, interiorRect.top(), 1, interiorRect.height() + 5);\n\t\tQRect selectionEndBar3 = QRect(selectionRect.left() + selectionRect.width(), interiorRect.top(), 1, interiorRect.height());\n\t\t\n        painter.fillRect(selectionStartBar1, QtSLiMColorWithWhite(1.0, 0.15));\n        if (drawInteriorShadow)\n            painter.fillRect(selectionEndBar1, QtSLiMColorWithWhite(1.0, 0.15));\n        \n        painter.fillRect(selectionStartBar2, inDarkMode ? QtSLiMColorWithWhite(0.8, 1.0) : Qt::black);\n        painter.fillRect(selectionEndBar2, inDarkMode ? QtSLiMColorWithWhite(0.8, 1.0) : Qt::black);\n\t\t\n        if (drawInteriorShadow)\n            painter.fillRect(selectionStartBar3, QtSLiMColorWithWhite(0.0, 0.30));\n        painter.fillRect(selectionEndBar3, QtSLiMColorWithWhite(0.0, 0.30));\n        \n\t\t// draw a ball at the end of each bar\n        // FIXME this doesn't look quite as nice as SLiMgui, because QPainter doesn't antialias\n        // also we can get clipped by one pixel at the edge of the view; subtle but imperfect\n\t\tQRect selectionStartBall = QRect(selectionRect.left() - selectionKnobSizeExtension, interiorRect.bottom() + (selectionKnobSize - 2), selectionKnobSize, selectionKnobSize);\n\t\tQRect selectionEndBall = QRect(selectionRect.left() + selectionRect.width() - (selectionKnobSizeExtension + 1), interiorRect.bottom() + (selectionKnobSize - 2), selectionKnobSize, selectionKnobSize);\n\t\t\n        painter.save();\n        painter.setPen(Qt::NoPen);\n        \n        painter.setBrush(inDarkMode ? QtSLiMColorWithWhite(0.65, 1.0) : Qt::black);\t// outline\n\t\tpainter.drawEllipse(selectionStartBall);\n\t\tpainter.drawEllipse(selectionEndBall);\n\t\t\n        painter.setBrush(QtSLiMColorWithWhite(0.3, 1.0));\t// interior\n\t\tpainter.drawEllipse(selectionStartBall.adjusted(1, 1, -1, -1));\n\t\tpainter.drawEllipse(selectionEndBall.adjusted(1, 1, -1, -1));\n\t\t\n\t\tpainter.setBrush(QtSLiMColorWithWhite(1.0, 0.5));\t// highlight\n\t\tpainter.drawEllipse(selectionStartBall.adjusted(1, 1, -2, -2));\n\t\tpainter.drawEllipse(selectionEndBall.adjusted(1, 1, -2, -2));\n        \n        painter.restore();\n    }\n}\n\nChromosome *QtSLiMChromosomeWidget::_findFocalChromosomeForTracking(QMouseEvent *p_event)\n{\n    // this hit-tracks the same layout that drawOverview() displays\n    QPoint curPoint = p_event->pos();\n    QRect overallRect = rect();\n    QRect contentRect = getContentRect();\n    Species *displaySpecies = focalDisplaySpecies();\n    const std::vector<Chromosome *> &chromosomes = displaySpecies->Chromosomes();\n    int chromosomeCount = (int)chromosomes.size();\n    int64_t availableWidth = contentRect.width() - (chromosomeCount * 2) - ((chromosomeCount - 1) * spaceBetweenChromosomes);\n    int64_t totalLength = 0;\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        \n        totalLength += chromLength;\n    }\n    \n    int64_t remainingLength = totalLength;\n    int leftPosition = contentRect.left();\n    \n    // note that we hit-test against the overall frames of the chromosomes (including the margin\n    // at the bottom for selection knobs), but set contentRectForTrackedChromosome_ based on the\n    // content rect for the chromosome (excluding that margin); see mousePressEvent() for why.\n    for (Chromosome *chrom : chromosomes)\n    {\n        double scale = (double)availableWidth / remainingLength;\n        slim_position_t chromLength = (chrom->last_position_ + 1);\n        int width = (int)round(chromLength * scale);\n        int paddedWidth = 2 + width;\n        QRect chromOverallFrame(leftPosition, overallRect.top(), paddedWidth, overallRect.height());\n        \n        if (chromOverallFrame.contains(curPoint))\n        {\n            QRect chromContentRect(leftPosition, contentRect.top(), paddedWidth, contentRect.height());\n            \n            contentRectForTrackedChromosome_ = chromContentRect;\n            return chrom;\n        }\n        \n        leftPosition += (paddedWidth + spaceBetweenChromosomes);\n        availableWidth -= width;\n        remainingLength -= chromLength;\n    }\n    \n    return nullptr;\n}\n\nvoid QtSLiMChromosomeWidget::mousePressEvent(QMouseEvent *p_event)\n{\n    Species *displaySpecies = focalDisplaySpecies();\n\tbool ready = (isOverview_ && isEnabled() && !controller_->invalidSimulation() && (displaySpecies != nullptr));\n\t\n\t// if the simulation is at tick 0, it is not ready\n\tif (ready)\n        if (controller_->community()->Tick() == 0)\n\t\t\tready = false;\n\t\n\tif (ready)\n\t{\n        // find which chromosome was clicked in; this sets contentRectForTrackedChromosome_ to the content rect of that chromosome\n        // note that it hit-tests aginst the overall chromosome view, including the selection knob margin, though\n        Chromosome *hitChromosome = _findFocalChromosomeForTracking(p_event);\n        \n        simpleClickInFocalChromosome_ = false;     // only true in the one case set below\n        \n        // if the click was not in a chromosome (like in the gap between them), just return with no effect\n        if (!hitChromosome)\n            return;\n        \n        QRect contentRect = contentRectForTrackedChromosome_;\n        QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n        QtSLiMRange displayedRange = getDisplayedRange(hitChromosome);\n        QPoint curPoint = p_event->pos();\n        \n        // check for a hit in one of our selection handles\n        if (hasSelection_ && (hitChromosome == focalChromosome()))\n\t\t{\n\t\t\tQRect selectionRect = rectEncompassingBaseToBase(selectionFirstBase_, selectionLastBase_, interiorRect, displayedRange);\n\t\t\tint leftEdge = selectionRect.left();\n\t\t\tint rightEdge = selectionRect.left() + selectionRect.width() - 1;\t// -1 to be on the left edge of the right-edge pixel strip\n\t\t\tQRect leftSelectionBar = QRect(leftEdge - 2, selectionRect.top() - 1, 5, selectionRect.height() + 2);\n\t\t\tQRect leftSelectionKnob = QRect(leftEdge - (selectionKnobSizeExtension + 1), selectionRect.bottom() + (selectionKnobSize - 3), (selectionKnobSizeExtension + 1) * 2 + 1, selectionKnobSize + 2);\n\t\t\tQRect rightSelectionBar = QRect(rightEdge - 2, selectionRect.top() - 1, 5, selectionRect.height() + 2);\n\t\t\tQRect rightSelectionKnob = QRect(rightEdge - (selectionKnobSizeExtension + 1), selectionRect.bottom() + (selectionKnobSize - 3), (selectionKnobSizeExtension + 1) * 2 + 1, selectionKnobSize + 2);\n\t\t\t\n\t\t\tif (leftSelectionBar.contains(curPoint) || leftSelectionKnob.contains(curPoint))\n\t\t\t{\n\t\t\t\tisTracking_ = true;\n                movedSufficiently_ = true;  // a hit in a selection bar is unambiguously a drag\n\t\t\t\ttrackingXAdjust_ = (curPoint.x() - leftEdge) - 1;\t\t// I'm not sure why the -1 is needed, but it is...\n\t\t\t\ttrackingStartBase_ = selectionLastBase_;\t// we're dragging the left knob, so the right knob is the tracking anchor\n\t\t\t\ttrackingLastBase_ = baseForPosition(curPoint.x() - trackingXAdjust_, interiorRect, displayedRange);\t// instead of selectionFirstBase, so the selection does not change at all if the mouse does not move\n\t\t\t\t\n\t\t\t\tmouseMoveEvent(p_event);\t// the click may not be aligned exactly on the center of the bar, so clicking might shift it a bit; do that now\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (rightSelectionBar.contains(curPoint) || rightSelectionKnob.contains(curPoint))\n\t\t\t{\n\t\t\t\tisTracking_ = true;\n                movedSufficiently_ = true;  // a hit in a selection bar is unambiguously a drag\n\t\t\t\ttrackingXAdjust_ = (curPoint.x() - rightEdge);\n\t\t\t\ttrackingStartBase_ = selectionFirstBase_;\t// we're dragging the right knob, so the left knob is the tracking anchor\n\t\t\t\ttrackingLastBase_ = baseForPosition(curPoint.x() - trackingXAdjust_, interiorRect, displayedRange);\t// instead of selectionLastBase, so the selection does not change at all if the mouse does not move\n\t\t\t\t\n\t\t\t\tmouseMoveEvent(p_event);\t// the click may not be aligned exactly on the center of the bar, so clicking might shift it a bit; do that now\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n        \n        // _findFocalChromosomeForTracking() will return a hit anywhere in the overall chromosome view, so that we can test for hits\n        // in the selection knobs above; but from this point forward, we only want to handle hits that are actually in the content area\n        if (!contentRect.contains(curPoint))\n            return;\n        \n        // our behavior depends on whether the hit chromosome was already the focal chromosome\n        if ((hitChromosome == focalChromosome()) && !hasSelection_)\n        {\n            // if the click was in the currently selected chromosome, and there is presently no selection, remember\n            // that fact; if we get a mouse-up without a selection being dragged out, we will deselect completely\n            // (if we presently have a selection, the click removes the selection, but does not deselect completely)\n            simpleClickInFocalChromosome_ = true;\n            update();\n        }\n        else if (hitChromosome != focalChromosome())\n        {\n            // given that it wasn't a hit in a selection handle, we now switch to the chromosome that was clicked in;\n            // other kinds of clicks change the focal chromosome to the one hit by the click\n            setFocalChromosome(hitChromosome);\n            update();\n        }\n        \n\t\t// option-clicks just set the selection to the clicked genomic element, no questions asked\n        // tracking does not continue beyond this step, since we don't set isTracking_ = true\n        if (p_event->modifiers() & Qt::AltModifier)\n\t\t{\n            slim_position_t clickedBase = baseForPosition(curPoint.x(), interiorRect, displayedRange);\n            QtSLiMRange selectionRange = QtSLiMRange(0, 0);\n            GenomicElement *genomicElement = hitChromosome->ElementForPosition(clickedBase);\n            \n            if (genomicElement)\n            {\n                slim_position_t startPosition = genomicElement->start_position_;\n                slim_position_t endPosition = genomicElement->end_position_;\n                selectionRange = QtSLiMRange(startPosition, endPosition - startPosition + 1);\n            }\n            \n            mouseInsideCounter_++;  // prevent a flip to displaying chromosome numbers\n            simpleClickInFocalChromosome_ = false;\n            \n            setSelectedRange(selectionRange);\n            return;\n        }\n        \n        // otherwise we have an ordinary click, selecting a chromosome and perhaps dragging out a selection\n        {\n            isTracking_ = true;\n            movedSufficiently_ = false;     // require a movement threshold before beginning to drag\n            initialMouseX = curPoint.x();\n            trackingStartBase_ = baseForPosition(curPoint.x(), interiorRect, displayedRange);\n            trackingLastBase_ = trackingStartBase_;\n            trackingXAdjust_ = 0;\n            \n            // We start off with no selection, and wait for the user to drag out a selection\n\t\t\tif (hasSelection_)\n\t\t\t{\n\t\t\t\thasSelection_ = false;\n\t\t\t\t\n\t\t\t\t// Save the selection for restoring across recycles, etc.\n\t\t\t\tsavedHasSelection_ = hasSelection_;\n\t\t\t\t\n\t\t\t\tupdate();\n                updateDependentView();\n\t\t\t}\n        }\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::_mouseTrackEvent(QMouseEvent *p_event)\n{\n    QRect contentRect = contentRectForTrackedChromosome_;\n    QRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n    QtSLiMRange displayedRange = getDisplayedRange(focalChromosome());\n    QPoint curPoint = p_event->pos();\n\t\n\tQPoint correctedPoint = QPoint(curPoint.x() - trackingXAdjust_, curPoint.y());\n\tslim_position_t trackingNewBase = baseForPosition(correctedPoint.x(), interiorRect, displayedRange);\n\tbool selectionChanged = false;\n\t\n\tif (trackingNewBase != trackingLastBase_)\n\t{\n\t\ttrackingLastBase_ = trackingNewBase;\n\t\t\n\t\tslim_position_t trackingLeftBase = trackingStartBase_, trackingRightBase = trackingLastBase_;\n\t\t\n\t\tif (trackingLeftBase > trackingRightBase)\n\t\t{\n\t\t\ttrackingLeftBase = trackingLastBase_;\n\t\t\ttrackingRightBase = trackingStartBase_;\n\t\t}\n\t\t\n\t\tif (trackingLeftBase <= static_cast<slim_position_t>(displayedRange.location))\n\t\t\ttrackingLeftBase = static_cast<slim_position_t>(displayedRange.location);\n\t\tif (trackingRightBase > static_cast<slim_position_t>((displayedRange.location + displayedRange.length) - 1))\n\t\t\ttrackingRightBase = static_cast<slim_position_t>((displayedRange.location + displayedRange.length) - 1);\n\t\t\n\t\tif (trackingRightBase <= trackingLeftBase + 3)      // minimum selection length is 5; below that, reset to no selection\n\t\t{\n\t\t\tif (hasSelection_)\n\t\t\t\tselectionChanged = true;\n\t\t\t\n\t\t\thasSelection_ = false;\n\t\t\t\n\t\t\t// Save the selection for restoring across recycles, etc.\n\t\t\tsavedHasSelection_ = hasSelection_;\n\t\t}\n        else if (movedSufficiently_ || (abs(initialMouseX - curPoint.x()) > 2))  // movement threshold before drag-selection begins\n\t\t{\n\t\t\tselectionChanged = true;\n\t\t\thasSelection_ = true;\n            movedSufficiently_ = true;\n\t\t\tselectionFirstBase_ = trackingLeftBase;\n\t\t\tselectionLastBase_ = trackingRightBase;\n            simpleClickInFocalChromosome_ = false;  // no resetting to overview\n\t\t\t\n\t\t\t// Save the selection for restoring across recycles, etc.\n\t\t\tsavedSelectionFirstBase_ = selectionFirstBase_;\n\t\t\tsavedSelectionLastBase_ = selectionLastBase_;\n\t\t\tsavedHasSelection_ = hasSelection_;\n\t\t}\n\t\t\n\t\tif (selectionChanged)\n\t\t{\n\t\t\tupdate();\n            updateDependentView();\n\t\t}\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::mouseMoveEvent(QMouseEvent *p_event)\n{\n    if (isOverview_ && isTracking_)\n\t\t_mouseTrackEvent(p_event);\n}\n\nvoid QtSLiMChromosomeWidget::mouseReleaseEvent(QMouseEvent *p_event)\n{\n    if (isOverview_ && isTracking_)\n\t{\n        _mouseTrackEvent(p_event);\n        \n        // prevent a flip to showing chromosome numbers after user tracking\n        mouseInsideCounter_++;\n        showChromosomeNumbers_ = false;\n        \n        // if we had a simple click and mouse-up in the focal chromosome, and there\n        // was no existing selection, then reset to showing all chromosomes\n        if (simpleClickInFocalChromosome_)\n        {\n            setFocalChromosome(nullptr);\n            update();\n            updateDependentView();\n        }\n\t}\n\t\n\tisTracking_ = false;\n}\n\nvoid QtSLiMChromosomeWidget::contextMenuEvent(QContextMenuEvent * /* p_event */)\n{\n    // BCH 5/9/2022: I think now that we can have multiple chromosome views it might be best to make\n    // people use the action button; a context menu running on a particular view looks view-specific,\n    // but the multiple chromosome views share all their configuration state, so that would be odd.\n    \n    //if (!isOverview_)\n    //    controller_->runChromosomeContextMenuAtPoint(p_event->globalPos());\n}\n\nvoid QtSLiMChromosomeWidget::enterEvent(QTSLIM_ENTER_EVENT * /* event */)\n{\n    if (isOverview_)\n    {\n        // When the mouse enters, we want to switch to showing chromosome numbers, but we want it to\n        // happen with a bit of a delay so it doesn't flip visually when the user is just moving the\n        // mouse around.  We want the display change not to happen again if the mouse exits before\n        // the delay is up, *even* if it re-enters again within the delay period.  To achieve that,\n        // we use a unique identifier for each entry, in the form of a counter, mouseInsideCounter_.\n        // We use a one-second delay to give the user time to start dragging a selection if they\n        // want to; that would often depend upon the genomic elements, so we don't want to hide them.\n        mouseInside_ = true;\n        mouseInsideCounter_++;\n        \n        int thisMouseInsideCounter = mouseInsideCounter_;\n        \n        QTimer::singleShot(1000, this,\n            [this, thisMouseInsideCounter]() {\n                if (mouseInside_ && (mouseInsideCounter_ == thisMouseInsideCounter))\n                {\n                    showChromosomeNumbers_ = true;\n                    update();\n                }\n            });\n    }\n}\n\nvoid QtSLiMChromosomeWidget::leaveEvent(QEvent * /* event */)\n{\n    if (isOverview_)\n    {\n        mouseInside_ = false;\n        mouseInsideCounter_++;\n        \n        if (showChromosomeNumbers_)\n        {\n            // When the mouse exists, we want to switch away from showing chromosome numbers, but we\n            // again want it to happen with a bit of delay, so that the user can mouse over to the\n            // chromosome number they want without having it flip back due to a mouse track that\n            // passes outside the overview strip.  So we want the display change not to happen if\n            // the mouse enters again within that delay.  We can use the same mechanism as above.\n            int thisMouseInsideCounter = mouseInsideCounter_;\n            \n            QTimer::singleShot(500, this,\n                [this, thisMouseInsideCounter]() {\n                    if (!mouseInside_ && (mouseInsideCounter_ == thisMouseInsideCounter))\n                    {\n                        showChromosomeNumbers_ = false;\n                        update();\n                    }\n                });\n        }\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMChromosomeWidget.h",
    "content": "//\n//  QtSLiMChromosomeWidget.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/28/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMCHROMOSOMEWIDGET_H\n#define QTSLIMCHROMOSOMEWIDGET_H\n\n// Silence deprecated OpenGL warnings on macOS\n#define GL_SILENCE_DEPRECATION\n\n#include <QWidget>\n#include <QPointer>\n\n#ifndef SLIM_NO_OPENGL\n#include <QOpenGLWidget>\n#include <QOpenGLFunctions>\n#endif\n\n#include \"slim_globals.h\"\n\n#include \"QtSLiMWindow.h\"\n\n\nclass QtSLiMWindow;\nclass QtSLiMHaplotypeManager;\nclass QPainter;\nclass QContextMenuEvent;\nclass QButton;\n\n\nstruct QtSLiMRange\n{\n    int64_t location, length;\n    \n    explicit QtSLiMRange() : location(0), length(0) {}\n    explicit QtSLiMRange(int64_t p_location, int64_t p_length) : location(p_location), length(p_length) {}\n};\n\n\n// This is a little controller class that governs a chromosome view or views, and an associated action button\n// It is used by QtSLiMWindow for the main chromosome views (overview and zoomed), and by the chromosome display\nclass QtSLiMChromosomeWidgetController : public QObject\n{\n    Q_OBJECT\n    \n    QtSLiMWindow *slimWindow_ = nullptr;\n    \n    // state used only in the chromosome display case\n    QPointer<QWidget> displayWindow_ = nullptr;\n    std::string focalSpeciesName_;                  // we keep the name of our focal species, since a pointer would be unsafe\n    std::string focalSpeciesAvatar_;                // cached so we can display it even when the simulation is invalid\n    std::string chromosomeSymbol_;                  // a chromosome symbol, or \"\" for \"all chromosomes\"\n    bool needsRebuild_ = false;                     // true immediately after recycling\n    \npublic:\n    bool useScaledWidths_ = true;                   // used only by the chromosome display\n    bool shouldDrawMutations_ = true;\n    bool shouldDrawFixedSubstitutions_ = false;\n    bool shouldDrawGenomicElements_ = false;\n    bool shouldDrawRateMaps_ = false;\n    \n    bool displayHaplotypes_ = false;                // if false, displaying frequencies; if true, displaying haplotypes\n    std::vector<slim_objectid_t> displayMuttypes_;  // if empty, display all mutation types; otherwise, display only the muttypes chosen\n    \n    QtSLiMChromosomeWidgetController(QtSLiMWindow *slimWindow, QWidget *displayWindow, Species *focalSpecies, std::string chromosomeSymbol);\n    \n    void buildChromosomeDisplay(bool resetWindowSize);\n    void updateFromController(void);\n    \n    void runChromosomeContextMenuAtPoint(QPoint p_globalPoint);\n    void actionButtonRunMenu(QtSLiMPushButton *p_actionButton);\n    \n    // forwards from slimWindow_; this is everything QtSLiMChromosomeWidget needs from the outside world\n    bool invalidSimulation(void) { return slimWindow_->invalidSimulation(); }\n    Community *community(void) { return slimWindow_->community; }\n    Species *focalDisplaySpecies(void);\n    void colorForGenomicElementType(GenomicElementType *elementType, slim_objectid_t elementTypeID, float *p_red, float *p_green, float *p_blue, float *p_alpha)\n        { slimWindow_->colorForGenomicElementType(elementType, elementTypeID, p_red, p_green, p_blue, p_alpha); }\n    QtSLiMWindow *slimWindow(void) { return slimWindow_; }\n        \nsignals:\n    void needsRedisplay(void);\n};\n\n\n// This is a fast macro for when all we need is the offset of a base from the left edge of interiorRect; interiorRect.origin.x is not added here!\n// This is based on the same math as rectEncompassingBase:toBase:interiorRect:displayedRange:, and must be kept in synch with that method.\n#define LEFT_OFFSET_OF_BASE(startBase, interiorRect, displayedRange) (static_cast<int>(floor(((startBase - static_cast<slim_position_t>(displayedRange.location)) / static_cast<double>(displayedRange.length)) * interiorRect.width())))\n\n\n#ifndef SLIM_NO_OPENGL\nclass QtSLiMChromosomeWidget : public QOpenGLWidget, protected QOpenGLFunctions\n#else\nclass QtSLiMChromosomeWidget : public QWidget\n#endif\n{\n    Q_OBJECT\n    \n    QtSLiMChromosomeWidgetController *controller_ = nullptr;\n    std::string focalSpeciesName_;                                  // we keep the name of our focal species, since a pointer would be unsafe\n    std::string focalChromosomeSymbol_;                             // we keep the symbol of our focal chromosome, since a pointer would be unsafe\n    \n    bool isOverview_ = false;\n    QtSLiMChromosomeWidget *dependentChromosomeView_ = nullptr;\n    \n    bool showsTicks_ = true;\n    \n    // Displayed range (only in a regular chromosome view)\n    QtSLiMRange displayedRange_;\n    \n    // Selection (only in the overview)\n\tbool hasSelection_ = false;\n\tslim_position_t selectionFirstBase_ = 0, selectionLastBase_ = 0;\n\t\n\t// Selection memory – saved and restored across events like recycles\n\tbool savedHasSelection_ = false;\n\tslim_position_t savedSelectionFirstBase_ = 0, savedSelectionLastBase_ = 0;\n    \n    // Mouse-over display change (only in the overview)\n    bool mouseInside_ = false;\n    int mouseInsideCounter_ = 0;\n    bool showChromosomeNumbers_ = false;            // set true after a delay when the mouse is inside\n    \n    // Tracking (only in the overview)\n    bool isTracking_ = false;\n    bool movedSufficiently_ = false;                // a movement threshold is required before dragging begins\n    int initialMouseX = 0;                          // the initial x for the movement threshold\n    \n    QRect contentRectForTrackedChromosome_;\n    slim_position_t trackingStartBase_ = 0, trackingLastBase_ = 0;\n\tint trackingXAdjust_ = 0;                       // to keep the cursor stuck on a knob that is click-dragged\n    bool simpleClickInFocalChromosome_ = false;     // used to keep track of whether we could deselect on mouse-up\n\t//SLiMSelectionMarker *startMarker, *endMarker;\n    \npublic:\n    explicit QtSLiMChromosomeWidget(QWidget *p_parent = nullptr, QtSLiMChromosomeWidgetController *controller = nullptr, Species *displaySpecies = nullptr, Qt::WindowFlags f = Qt::WindowFlags());\n    virtual ~QtSLiMChromosomeWidget() override;\n    \n    void setController(QtSLiMChromosomeWidgetController *controller);\n    void setFocalDisplaySpecies(Species *displaySpecies);\n    Species *focalDisplaySpecies(void);\n    void setFocalChromosome(Chromosome *chromosome);\n    Chromosome *focalChromosome(void);\n    \n    void setDependentChromosomeView(QtSLiMChromosomeWidget *p_dependent_widget);\n    \n    bool hasSelection(void) { return hasSelection_; }\n    QtSLiMRange getSelectedRange(Chromosome *chromosome);\n    void setSelectedRange(QtSLiMRange p_selectionRange);\n    void restoreLastSelection(void);\n    void updateDependentView(void);\n    \n    QtSLiMRange getDisplayedRange(Chromosome *chromosome);\n    void setDisplayedRange(QtSLiMRange p_displayedRange);\n    \n    bool showsTicks(void) { return showsTicks_; }\n    void setShowsTicks(bool p_showTicks);\n    \n    void stateChanged(void);    // update when the SLiM model state changes; tosses any cached display info\n    void updateAfterTick(void);\n    \nprotected:\n#ifndef SLIM_NO_OPENGL\n    virtual void initializeGL() override;\n    virtual void resizeGL(int w, int h) override;\n    virtual void paintGL() override;\n#else\n    virtual void paintEvent(QPaintEvent *event) override;\n#endif\n    \n    QRect rectEncompassingBaseToBase(slim_position_t startBase, slim_position_t endBase, QRect interiorRect, QtSLiMRange displayedRange);\n    slim_position_t baseForPosition(double position, QRect interiorRect, QtSLiMRange displayedRange);\n    QRect getContentRect(void);\n    \n    void drawOverview(Species *displaySpecies, QPainter &painter);\n    void drawFullGenome(Species *displaySpecies, QPainter &painter);\n    \n    void drawTicksInContentRect(QRect contentRect, Species *displaySpecies, QtSLiMRange displayedRange, QPainter &painter);\n    void overlaySelection(QRect interiorRect, QtSLiMRange displayedRange, bool drawInteriorShadow, QPainter &painter);\n    void updateDisplayedMutationTypes(Species *displaySpecies);\n    \n    // OpenGL drawing; this is the primary drawing code\n#ifndef SLIM_NO_OPENGL\n    void glDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome);\n    void glDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n    void glDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n    void glDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n    void _glDrawRateMapIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, std::vector<slim_position_t> &ends, std::vector<double> &rates, double hue);\n    void glDrawRecombinationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n    void glDrawMutationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n    void glDrawRateMaps(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange);\n#endif\n    \n    // Qt-based drawing, provided as a backup if OpenGL has problems on a given platform\n    void qtDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome, QPainter &painter);\n    void qtDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    void qtDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    void qtDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    void _qtDrawRateMapIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, std::vector<slim_position_t> &ends, std::vector<double> &rates, double hue, QPainter &painter);\n    void qtDrawRecombinationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    void qtDrawMutationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    void qtDrawRateMaps(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter);\n    \n    Chromosome *_findFocalChromosomeForTracking(QMouseEvent *p_event);\n    virtual void mousePressEvent(QMouseEvent *p_event) override;\n    void _mouseTrackEvent(QMouseEvent *p_event);\n    virtual void mouseMoveEvent(QMouseEvent *p_event) override;\n    virtual void mouseReleaseEvent(QMouseEvent *p_event) override;\n    virtual void contextMenuEvent(QContextMenuEvent *p_event) override;\n    \n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n#define QTSLIM_ENTER_EVENT  QEvent\n#else\n#define QTSLIM_ENTER_EVENT  QEnterEvent\n#endif\n    virtual void enterEvent(QTSLIM_ENTER_EVENT *event) override;\n    virtual void leaveEvent(QEvent *event) override;\n    \n    // Our configuration is kept by the controller, since it is shared by all chromosome views for multispecies models\n    // However, \"overview\" chromosome views are always configured the same, hard-coded here\n    inline bool shouldDrawMutations(void) const { return isOverview_ ? false : controller_->shouldDrawMutations_; }\n    inline bool shouldDrawFixedSubstitutions(void) const { return isOverview_ ? false : controller_->shouldDrawFixedSubstitutions_; }\n    inline bool shouldDrawGenomicElements(void) const { return isOverview_ ? true : controller_->shouldDrawGenomicElements_; }\n    inline bool shouldDrawRateMaps(void) const { return isOverview_ ? false : controller_->shouldDrawRateMaps_; }\n    inline bool displayHaplotypes(void) const { return isOverview_ ? false : controller_->displayHaplotypes_; }\n    inline std::vector<slim_objectid_t> &displayMuttypes(void) const { return controller_->displayMuttypes_; }\n};\n\n#endif // QTSLIMCHROMOSOMEWIDGET_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMChromosomeWidget_GL.cpp",
    "content": "//\n//  QtSLiMChromosomeWidget_GL.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef SLIM_NO_OPENGL\n\n#include \"QtSLiMChromosomeWidget.h\"\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMOpenGL.h\"\n\n#include <QtDebug>\n\n#include <map>\n#include <algorithm>\n#include <vector>\n\n\n//\n//  OpenGL-based drawing; maintain this in parallel with the Qt-based drawing!\n//\n\nvoid QtSLiMChromosomeWidget::glDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome)\n{\n    bool ready = isEnabled() && !controller_->invalidSimulation();\n\tQRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n    \n    // if the simulation is at tick 0, it is not ready\n\tif (ready)\n        if (controller_->community()->Tick() == 0)\n\t\t\tready = false;\n\t\n    if (ready)\n    {\n        // erase the content area itself\n        glColor3f(0.0f, 0.0f, 0.0f);\n\t\tglRecti(interiorRect.left(), interiorRect.top(), interiorRect.left() + interiorRect.width(), interiorRect.top() + interiorRect.height());\n        \n\t\tQtSLiMRange displayedRange = getDisplayedRange(chromosome);\n\t\t\n\t\tbool splitHeight = (shouldDrawRateMaps() && shouldDrawGenomicElements());\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n        \n        // draw recombination intervals in interior\n\t\tif (shouldDrawRateMaps())\n\t\t\tglDrawRateMaps(splitHeight ? topInteriorRect : interiorRect, chromosome, displayedRange);\n\t\t\n\t\t// draw genomic elements in interior\n\t\tif (shouldDrawGenomicElements())\n\t\t\tglDrawGenomicElements(splitHeight ? bottomInteriorRect : interiorRect, chromosome, displayedRange);\n\t\t\n\t\t// figure out which mutation types we're displaying\n\t\tif (shouldDrawFixedSubstitutions() || shouldDrawMutations())\n\t\t\tupdateDisplayedMutationTypes(displaySpecies);\n\t\t\n\t\t// draw fixed substitutions in interior\n\t\tif (shouldDrawFixedSubstitutions())\n\t\t\tglDrawFixedSubstitutions(interiorRect, chromosome, displayedRange);\n\t\t\n\t\t// draw mutations in interior\n\t\tif (shouldDrawMutations())\n\t\t{\n\t\t\tif (displayHaplotypes())\n\t\t\t{\n\t\t\t\t// display mutations as a haplotype plot, courtesy of QtSLiMHaplotypeManager; we use ClusterNearestNeighbor and\n\t\t\t\t// ClusterNoOptimization because they're fast, and NN might also provide a bit more run-to-run continuity\n                size_t interiorHeight = static_cast<size_t>(interiorRect.height());\t// one sample per available pixel line, for simplicity and speed; 47, in the current UI layout\n                QtSLiMHaplotypeManager *haplotype_mgr = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, chromosome, displayedRange, interiorHeight, false, 0, 0);\n                \n                if (haplotype_mgr)\n                    haplotype_mgr->glDrawHaplotypes(interiorRect, false, false, false);\n                \n                delete haplotype_mgr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// display mutations as a frequency plot; this is the standard display mode\n                glDrawMutations(interiorRect, chromosome, displayedRange);\n\t\t\t}\n\t\t}\n    }\n    else\n    {\n        // erase the content area itself\n\t\tglColor3f(0.88f, 0.88f, 0.88f);\n        glRecti(0, 0, interiorRect.width(), interiorRect.height());\n    }\n}\n\nvoid QtSLiMChromosomeWidget::glDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n\tint previousIntervalLeftEdge = -10000;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tfor (GenomicElement *genomicElement : chromosome->GenomicElements())\n\t{\n\t\tslim_position_t startPosition = genomicElement->start_position_;\n\t\tslim_position_t endPosition = genomicElement->end_position_;\n\t\tQRect elementRect = rectEncompassingBaseToBase(startPosition, endPosition, interiorRect, displayedRange);\n\t\tbool widthOne = (elementRect.width() == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (elementRect.left() == previousIntervalLeftEdge))\n            elementRect.adjust(1, 0, 0, 0);\n\t\t\n\t\t// draw only the visible part, if any\n        elementRect = elementRect.intersected(interiorRect);\n\t\t\n\t\tif (!elementRect.isEmpty())\n\t\t{\n\t\t\tGenomicElementType *geType = genomicElement->genomic_element_type_ptr_;\n\t\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha;\n\t\t\t\n\t\t\tif (!geType->color_.empty())\n\t\t\t{\n\t\t\t\tcolorRed = geType->color_red_;\n\t\t\t\tcolorGreen = geType->color_green_;\n\t\t\t\tcolorBlue = geType->color_blue_;\n\t\t\t\tcolorAlpha = 1.0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tslim_objectid_t elementTypeID = geType->genomic_element_type_id_;\n                \n\t\t\t\tcontroller_->colorForGenomicElementType(geType, elementTypeID, &colorRed, &colorGreen, &colorBlue, &colorAlpha);\n\t\t\t}\n\t\t\t\n\t\t\tSLIM_GL_DEFCOORDS(elementRect);\n\t\t\tSLIM_GL_PUSHRECT();\n\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = elementRect.left();\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::glDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n\tdouble scalingFactor = 0.8; // used to be controller->selectionColorScale;\n    Species *displaySpecies = &chromosome->species_;\n\tPopulation &pop = displaySpecies->population_;\n\tdouble totalHaplosomeCount = chromosome->gui_total_haplosome_count_;\t\t\t\t// this includes only haplosomes in the selected subpopulations\n    \n    // Prefetch the mutations we actually want to display\n    static std::vector<const Mutation *> mutations;\n    mutations.resize(0);\n    \n    {\n        int registry_size;\n        const MutationIndex *registry = pop.MutationRegistry(&registry_size);\n        Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n        slim_chromosome_index_t chromosome_index = chromosome->Index();\n        \n        for (int registry_index = 0; registry_index < registry_size; ++registry_index)\n        {\n            const Mutation *mutation = mut_block_ptr + registry[registry_index];\n            \n            if (mutation->chromosome_index_ == chromosome_index)\n            {\n                const MutationType *mutType = mutation->mutation_type_ptr_;\n                \n                if (mutType->mutation_type_displayed_)\n                    mutations.emplace_back(mutation);\n            }\n        }\n    }\n    \n\t// Set up to draw rects\n\tfloat colorRed = 0.0f, colorGreen = 0.0f, colorBlue = 0.0f, colorAlpha = 1.0;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tif ((mutations.size() < 1000) || (displayedRange.length < interiorRect.width()))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n        for (const Mutation *mutation : mutations)\n\t\t{\n\t\t\tconst MutationType *mutType = mutation->mutation_type_ptr_;\n            slim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n            slim_position_t mutationPosition = mutation->position_;\n            QRect mutationTickRect = rectEncompassingBaseToBase(mutationPosition, mutationPosition, interiorRect, displayedRange);\n            \n            if (!mutType->color_.empty())\n            {\n                colorRed = mutType->color_red_;\n                colorGreen = mutType->color_green_;\n                colorBlue = mutType->color_blue_;\n            }\n            else\n            {\n                RGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n            }\n            \n            int height_adjust = mutationTickRect.height() - static_cast<int>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n            mutationTickRect.setTop(mutationTickRect.top() + height_adjust);\n            \n            SLIM_GL_DEFCOORDS(mutationTickRect);\n            SLIM_GL_PUSHRECT();\n            SLIM_GL_PUSHRECT_COLORS();\n            SLIM_GL_CHECKBUFFERS();\n        }\n\t}\n\telse\n\t{\n\t\t// We have a lot of mutations, so let's try to be smarter.  It's hard to be smarter.  The overhead from allocating the NSColors and such\n\t\t// is pretty negligible; practially all the time is spent in NSRectFill().  Unfortunately, NSRectFillListWithColors() provides basically\n\t\t// no speedup; Apple doesn't appear to have optimized it.  So, here's what I came up with.  For each mutation type that uses a fixed DFE,\n\t\t// and thus a fixed color, we can do a radix sort of mutations into bins corresponding to each pixel in our displayed image.  Then we\n\t\t// can draw each bin just once, making one bar for the highest bar in that bin.  Mutations from non-fixed DFEs, and mutations which have\n\t\t// had their selection coefficient changed, will be drawn at the end in the usual (slow) way.\n\t\tint displayPixelWidth = interiorRect.width();\n\t\tint16_t *heightBuffer = static_cast<int16_t *>(malloc(static_cast<size_t>(displayPixelWidth) * sizeof(int16_t)));\n\t\tbool *mutationsPlotted = static_cast<bool *>(calloc(mutations.size(), sizeof(bool)));\t// faster than using gui_scratch_reference_count_ because of cache locality\n\t\tint64_t remainingMutations = mutations.size();\n\t\t\n\t\t// First zero out the scratch refcount, which we use to track which mutations we have drawn already\n\t\t//for (int mutIndex = 0; mutIndex < mutationCount; ++mutIndex)\n\t\t//\tmutations[mutIndex]->gui_scratch_reference_count_ = 0;\n\t\t\n\t\t// Then loop through the declared mutation types\n\t\tstd::map<slim_objectid_t,MutationType*> &mut_types = displaySpecies->mutation_types_;\n\t\tbool draw_muttypes_sequentially = (mut_types.size() <= 20);\t// with a lot of mutation types, the algorithm below becomes very inefficient\n\t\t\n\t\tfor (auto mutationTypeIter : mut_types)\n\t\t{\n\t\t\tMutationType *mut_type = mutationTypeIter.second;\n\t\t\t\n\t\t\tif (mut_type->mutation_type_displayed_)\n\t\t\t{\n\t\t\t\tif (draw_muttypes_sequentially)\n\t\t\t\t{\n\t\t\t\t\tbool mut_type_fixed_color = !mut_type->color_.empty();\n\t\t\t\t\t\n\t\t\t\t\t// We optimize fixed-DFE mutation types only, and those using a fixed color set by the user\n\t\t\t\t\tif ((mut_type->dfe_type_ == DFEType::kFixed) || mut_type_fixed_color)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_selcoeff_t mut_type_selcoeff = (mut_type_fixed_color ? 0.0 : static_cast<slim_selcoeff_t>(mut_type->dfe_parameters_[0]));\n\t\t\t\t\t\t\n\t\t\t\t\t\tEIDOS_BZERO(heightBuffer, static_cast<size_t>(displayPixelWidth) * sizeof(int16_t));\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Scan through the mutation list for mutations of this type with the right selcoeff\n                        for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t\t\t{\n                            const Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\t\t\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n                            // We do want to do an exact floating-point equality compare here; we want to see whether the mutation's selcoeff is unmodified from the fixed DFE\n\t\t\t\t\t\t\tif ((mutation->mutation_type_ptr_ == mut_type) && (mut_type_fixed_color || (mutation->selection_coeff_ == mut_type_selcoeff)))\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// includes only refs from the selected subpopulations\n\t\t\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\t\t\tint16_t barHeight = static_cast<int16_t>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t\t\t\tif (barHeight > heightBuffer[xPos])\n\t\t\t\t\t\t\t\t\t\theightBuffer[xPos] = barHeight;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\t\t\tmutationsPlotted[mutation_index] = true;\n\t\t\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Now draw all of the mutations we found, by looping through our radix bins\n\t\t\t\t\t\tif (mut_type_fixed_color)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolorRed = mut_type->color_red_;\n\t\t\t\t\t\t\tcolorGreen = mut_type->color_green_;\n\t\t\t\t\t\t\tcolorBlue = mut_type->color_blue_;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mut_type_selcoeff), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint barHeight = heightBuffer[binIndex];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (barHeight)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tQRect mutationTickRect(interiorRect.x() + binIndex, interiorRect.y(), 1, interiorRect.height());\n                                mutationTickRect.setTop(mutationTickRect.top() + interiorRect.height() - barHeight);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We're not displaying this mutation type, so we need to mark off all the mutations belonging to it as handled\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\n\t\t\t\t\tif (mutation->mutation_type_ptr_ == mut_type)\n\t\t\t\t\t{\n\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\tmutationsPlotted[mutation_index] = true;\n\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Draw any undrawn mutations on top; these are guaranteed not to use a fixed color set by the user, since those are all handled above\n\t\tif (remainingMutations)\n\t\t{\n\t\t\tif (remainingMutations < 1000)\n\t\t\t{\n\t\t\t\t// Plot the remainder by brute force, since there are not that many\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[mutation_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n                        QRect mutationTickRect = rectEncompassingBaseToBase(mutationPosition, mutationPosition, interiorRect, displayedRange);\n                        int height_adjust = mutationTickRect.height() - static_cast<int>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\n                        mutationTickRect.setTop(mutationTickRect.top() + height_adjust);\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// OK, we have a lot of mutations left to draw.  Here we will again use the radix sort trick, to keep track of only the tallest bar in each column\n\t\t\t\tconst Mutation **mutationBuffer = static_cast<const Mutation **>(calloc(static_cast<size_t>(displayPixelWidth),  sizeof(Mutation *)));\n\t\t\t\t\n\t\t\t\tEIDOS_BZERO(heightBuffer, static_cast<size_t>(displayPixelWidth) * sizeof(int16_t));\n\t\t\t\t\n\t\t\t\t// Find the tallest bar in each column\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[mutation_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\tint16_t barHeight = static_cast<int16_t>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (barHeight > heightBuffer[xPos])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theightBuffer[xPos] = barHeight;\n\t\t\t\t\t\t\t\tmutationBuffer[xPos] = mutation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now plot the bars\n\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t{\n\t\t\t\t\tint barHeight = heightBuffer[binIndex];\n\t\t\t\t\t\n\t\t\t\t\tif (barHeight)\n\t\t\t\t\t{\n                        QRect mutationTickRect(interiorRect.x() + binIndex, interiorRect.y(), 1, interiorRect.height());\n                        mutationTickRect.setTop(mutationTickRect.top() + interiorRect.height() - barHeight);\n                        \n\t\t\t\t\t\tconst Mutation *mutation = mutationBuffer[binIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfree(mutationBuffer);\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(heightBuffer);\n\t\tfree(mutationsPlotted);\n\t}\n\t\n\tSLIM_GL_FINISH();\n    \n    mutations.resize(0);\n}\n\nvoid QtSLiMChromosomeWidget::glDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n    double scalingFactor = 0.8; // used to be controller->selectionColorScale;\n    Species *displaySpecies = &chromosome->species_;\n\tPopulation &pop = displaySpecies->population_;\n\tbool chromosomeHasDefaultColor = !chromosome->color_sub_.empty();\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n    slim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\n\t// Set up to draw rects\n\tfloat colorRed = 0.2f, colorGreen = 0.2f, colorBlue = 1.0f, colorAlpha = 1.0;\n\t\n\tif (chromosomeHasDefaultColor)\n\t{\n\t\tcolorRed = chromosome->color_sub_red_;\n\t\tcolorGreen = chromosome->color_sub_green_;\n\t\tcolorBlue = chromosome->color_sub_blue_;\n\t}\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tif ((substitutions.size() < 1000) || (displayedRange.length < interiorRect.width()))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n            if ((substitution->chromosome_index_ == chromosome_index) && (substitution->mutation_type_ptr_->mutation_type_displayed_))\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tQRect substitutionTickRect = rectEncompassingBaseToBase(substitutionPosition, substitutionPosition, interiorRect, displayedRange);\n\t\t\t\t\n\t\t\t\tif (!shouldDrawMutations() || !chromosomeHasDefaultColor)\n\t\t\t\t{\n\t\t\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue (set above), to contrast\n\t\t\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tcolorRed = mutType->color_sub_red_;\n\t\t\t\t\t\tcolorGreen = mutType->color_sub_green_;\n\t\t\t\t\t\tcolorBlue = mutType->color_sub_blue_;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(substitution->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSLIM_GL_DEFCOORDS(substitutionTickRect);\n\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We have a lot of substitutions, so do a radix sort, as we do in drawMutationsInInteriorRect: below.\n\t\tint displayPixelWidth = interiorRect.width();\n\t\tconst Substitution **subBuffer = static_cast<const Substitution **>(calloc(static_cast<size_t>(displayPixelWidth), sizeof(Substitution *)));\n\t\t\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n            if ((substitution->chromosome_index_ == chromosome_index) && (substitution->mutation_type_ptr_->mutation_type_displayed_))\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tdouble startFraction = (substitutionPosition - static_cast<slim_position_t>(displayedRange.location)) / static_cast<double>(displayedRange.length);\n\t\t\t\tint xPos = static_cast<int>(floor(startFraction * interiorRect.width()));\n\t\t\t\t\n\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\tsubBuffer[xPos] = substitution;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (shouldDrawMutations() && chromosomeHasDefaultColor)\n\t\t{\n\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue, to contrast\n\t\t\tQRect mutationTickRect = interiorRect;\n            \n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n                    mutationTickRect.setX(interiorRect.x() + binIndex);\n                    mutationTickRect.setWidth(1);\n                    \n\t\t\t\t\t// consolidate adjacent lines together, since they are all the same color\n\t\t\t\t\twhile ((binIndex + 1 < displayPixelWidth) && subBuffer[binIndex + 1])\n\t\t\t\t\t{\n                        mutationTickRect.setWidth(mutationTickRect.width() + 1);\n\t\t\t\t\t\tbinIndex++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n            QRect mutationTickRect = interiorRect;\n\t\t\t\n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tcolorRed = mutType->color_sub_red_;\n\t\t\t\t\t\tcolorGreen = mutType->color_sub_green_;\n\t\t\t\t\t\tcolorBlue = mutType->color_sub_blue_;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(substitution->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t}\n\t\t\t\t\t\n                    mutationTickRect.setX(interiorRect.x() + binIndex);\n                    mutationTickRect.setWidth(1);\n\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(subBuffer);\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::_glDrawRateMapIntervals(QRect &interiorRect, __attribute__((__unused__)) Chromosome *chromosome, QtSLiMRange displayedRange, std::vector<slim_position_t> &ends, std::vector<double> &rates, double hue)\n{\n\tsize_t recombinationIntervalCount = ends.size();\n\tslim_position_t intervalStartPosition = 0;\n\tint previousIntervalLeftEdge = -10000;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tfor (size_t interval = 0; interval < recombinationIntervalCount; ++interval)\n\t{\n\t\tslim_position_t intervalEndPosition = ends[interval];\n\t\tdouble intervalRate = rates[interval];\n\t\tQRect intervalRect = rectEncompassingBaseToBase(intervalStartPosition, intervalEndPosition, interiorRect, displayedRange);\n\t\tbool widthOne = (intervalRect.width() == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (intervalRect.left() == previousIntervalLeftEdge))\n            intervalRect.adjust(1, 0, 0, 0);\n\t\t\n\t\t// draw only the visible part, if any\n        intervalRect = intervalRect.intersected(interiorRect);\n\t\t\n        if (!intervalRect.isEmpty())\n\t\t{\n\t\t\t// color according to how \"hot\" the region is\n            float colorRed, colorGreen, colorBlue, colorAlpha;\n\t\t\t\n\t\t\tif (intervalRate == 0.0)\n\t\t\t{\n\t\t\t\t// a recombination or mutation rate of 0.0 comes out as black, whereas the lowest brightness below is 0.5; we want to distinguish this\n\t\t\t\tcolorRed = colorGreen = colorBlue = 0.0;\n\t\t\t\tcolorAlpha = 1.0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the formula below scales 1e-6 to 1.0 and 1e-9 to 0.0; values outside that range clip, but we want there to be\n\t\t\t\t// reasonable contrast within the range of values commonly used, so we don't want to make the range too wide\n\t\t\t\tdouble lightness, brightness = 1.0, saturation = 1.0;\n\t\t\t\t\n\t\t\t\tlightness = (log10(intervalRate) + 9.0) / 3.0;\n\t\t\t\tlightness = std::max(lightness, 0.0);\n\t\t\t\tlightness = std::min(lightness, 1.0);\n\t\t\t\t\n\t\t\t\tif (lightness >= 0.5)\tsaturation = 1.0 - ((lightness - 0.5) * 2.0);\t// goes from 1.0 at lightness 0.5 to 0.0 at lightness 1.0\n\t\t\t\telse\t\t\t\t\tbrightness = 0.5 + lightness;\t\t\t\t\t// goes from 1.0 at lightness 0.5 to 0.5 at lightness 0.0\n\t\t\t\t\n                QColor intervalColor = QtSLiMColorWithHSV(hue, saturation, brightness, 1.0);\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n                // In Qt5, getRgbF() expects pointers to qreal, which is double\n                double r, g, b, a;\n\t\t\t\tintervalColor.getRgbF(&r, &g, &b, &a);\n                \n                colorRed = static_cast<float>(r);\n                colorGreen = static_cast<float>(g);\n                colorBlue = static_cast<float>(b);\n                colorAlpha = static_cast<float>(a);\n#else\n                // In Qt6, getRgbF() expects pointers to float\n                intervalColor.getRgbF(&colorRed, &colorGreen, &colorBlue, &colorAlpha);\n#endif\n\t\t\t}\n\t\t\t\n\t\t\tSLIM_GL_DEFCOORDS(intervalRect);\n\t\t\tSLIM_GL_PUSHRECT();\n\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = intervalRect.left();\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t\t\n\t\t// the next interval starts at the next base after this one ended\n\t\tintervalStartPosition = intervalEndPosition + 1;\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::glDrawRecombinationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n\tif (chromosome->single_recombination_map_)\n\t{\n\t\t_glDrawRateMapIntervals(interiorRect, chromosome, displayedRange, chromosome->recombination_end_positions_H_, chromosome->recombination_rates_H_, 0.65);\n\t}\n\telse\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n\t\t\n\t\t_glDrawRateMapIntervals(topInteriorRect, chromosome, displayedRange, chromosome->recombination_end_positions_M_, chromosome->recombination_rates_M_, 0.65);\n\t\t_glDrawRateMapIntervals(bottomInteriorRect, chromosome, displayedRange, chromosome->recombination_end_positions_F_, chromosome->recombination_rates_F_, 0.65);\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::glDrawMutationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n\tif (chromosome->single_mutation_map_)\n\t{\n\t\t_glDrawRateMapIntervals(interiorRect, chromosome, displayedRange, chromosome->mutation_end_positions_H_, chromosome->mutation_rates_H_, 0.75);\n\t}\n\telse\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n\t\t\n\t\t_glDrawRateMapIntervals(topInteriorRect, chromosome, displayedRange, chromosome->mutation_end_positions_M_, chromosome->mutation_rates_M_, 0.75);\n\t\t_glDrawRateMapIntervals(bottomInteriorRect, chromosome, displayedRange, chromosome->mutation_end_positions_F_, chromosome->mutation_rates_F_, 0.75);\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::glDrawRateMaps(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange)\n{\n\tbool recombinationWorthShowing = false;\n\tbool mutationWorthShowing = false;\n\t\n\tif (chromosome->single_mutation_map_)\n\t\tmutationWorthShowing = (chromosome->mutation_end_positions_H_.size() > 1);\n\telse\n\t\tmutationWorthShowing = ((chromosome->mutation_end_positions_M_.size() > 1) || (chromosome->mutation_end_positions_F_.size() > 1));\n\t\n\tif (chromosome->single_recombination_map_)\n\t\trecombinationWorthShowing = (chromosome->recombination_end_positions_H_.size() > 1);\n\telse\n\t\trecombinationWorthShowing = ((chromosome->recombination_end_positions_M_.size() > 1) || (chromosome->recombination_end_positions_F_.size() > 1));\n\t\n\t// If neither map is worth showing, we show just the recombination map, to mirror the behavior of 2.4 and earlier\n\tif ((!mutationWorthShowing && !recombinationWorthShowing) || (!mutationWorthShowing && recombinationWorthShowing))\n\t{\n\t\tglDrawRecombinationIntervals(interiorRect, chromosome, displayedRange);\n\t}\n\telse if (mutationWorthShowing && !recombinationWorthShowing)\n\t{\n\t\tglDrawMutationIntervals(interiorRect, chromosome, displayedRange);\n\t}\n\telse\t// mutationWorthShowing && recombinationWorthShowing\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n        \n\t\tglDrawRecombinationIntervals(topInteriorRect, chromosome, displayedRange);\n\t\tglDrawMutationIntervals(bottomInteriorRect, chromosome, displayedRange);\n\t}\n}\n\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMChromosomeWidget_QT.cpp",
    "content": "//\n//  QtSLiMChromosomeWidget_QT.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMChromosomeWidget.h\"\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMOpenGL_Emulation.h\"\n\n#include <QtDebug>\n\n#include <map>\n#include <algorithm>\n#include <vector>\n\n\n//\n//  OpenGL-based drawing; maintain this in parallel with the Qt-based drawing!\n//\n\nvoid QtSLiMChromosomeWidget::qtDrawRect(QRect contentRect, Species *displaySpecies, Chromosome *chromosome, QPainter &painter)\n{\n    bool ready = isEnabled() && !controller_->invalidSimulation();\n\tQRect interiorRect = contentRect.marginsRemoved(QMargins(1, 1, 1, 1));\n    \n    // if the simulation is at tick 0, it is not ready\n\tif (ready)\n        if (controller_->community()->Tick() == 0)\n\t\t\tready = false;\n\t\n    if (ready)\n    {\n        // erase the content area itself\n        painter.fillRect(interiorRect, Qt::black);\n        \n\t\tQtSLiMRange displayedRange = getDisplayedRange(chromosome);\n\t\t\n\t\tbool splitHeight = (shouldDrawRateMaps() && shouldDrawGenomicElements());\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n        \n        // draw recombination intervals in interior\n\t\tif (shouldDrawRateMaps())\n\t\t\tqtDrawRateMaps(splitHeight ? topInteriorRect : interiorRect, chromosome, displayedRange, painter);\n\t\t\n\t\t// draw genomic elements in interior\n\t\tif (shouldDrawGenomicElements())\n\t\t\tqtDrawGenomicElements(splitHeight ? bottomInteriorRect : interiorRect, chromosome, displayedRange, painter);\n\t\t\n\t\t// figure out which mutation types we're displaying\n\t\tif (shouldDrawFixedSubstitutions() || shouldDrawMutations())\n\t\t\tupdateDisplayedMutationTypes(displaySpecies);\n\t\t\n\t\t// draw fixed substitutions in interior\n\t\tif (shouldDrawFixedSubstitutions())\n\t\t\tqtDrawFixedSubstitutions(interiorRect, chromosome, displayedRange, painter);\n\t\t\n\t\t// draw mutations in interior\n\t\tif (shouldDrawMutations())\n\t\t{\n\t\t\tif (displayHaplotypes())\n\t\t\t{\n\t\t\t\t// display mutations as a haplotype plot, courtesy of QtSLiMHaplotypeManager; we use ClusterNearestNeighbor and\n\t\t\t\t// ClusterNoOptimization because they're fast, and NN might also provide a bit more run-to-run continuity\n                size_t interiorHeight = static_cast<size_t>(interiorRect.height());\t// one sample per available pixel line, for simplicity and speed; 47, in the current UI layout\n                QtSLiMHaplotypeManager *haplotype_mgr = new QtSLiMHaplotypeManager(nullptr, QtSLiMHaplotypeManager::ClusterNearestNeighbor, QtSLiMHaplotypeManager::ClusterNoOptimization, controller_, displaySpecies, chromosome, displayedRange, interiorHeight, false, 0, 0);\n                \n                if (haplotype_mgr)\n                    haplotype_mgr->qtDrawHaplotypes(interiorRect, false, false, false, painter);\n                \n                delete haplotype_mgr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// display mutations as a frequency plot; this is the standard display mode\n                qtDrawMutations(interiorRect, chromosome, displayedRange, painter);\n\t\t\t}\n\t\t}\n    }\n    else\n    {\n        // erase the content area itself\n        painter.fillRect(QRect(0, 0, interiorRect.width(), interiorRect.height()), QtSLiMColorWithWhite(0.88, 1.0));\n    }\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawGenomicElements(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n\tint previousIntervalLeftEdge = -10000;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tfor (GenomicElement *genomicElement : chromosome->GenomicElements())\n\t{\n\t\tslim_position_t startPosition = genomicElement->start_position_;\n\t\tslim_position_t endPosition = genomicElement->end_position_;\n\t\tQRect elementRect = rectEncompassingBaseToBase(startPosition, endPosition, interiorRect, displayedRange);\n\t\tbool widthOne = (elementRect.width() == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (elementRect.left() == previousIntervalLeftEdge))\n            elementRect.adjust(1, 0, 0, 0);\n\t\t\n\t\t// draw only the visible part, if any\n        elementRect = elementRect.intersected(interiorRect);\n\t\t\n\t\tif (!elementRect.isEmpty())\n\t\t{\n\t\t\tGenomicElementType *geType = genomicElement->genomic_element_type_ptr_;\n\t\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha;\n\t\t\t\n\t\t\tif (!geType->color_.empty())\n\t\t\t{\n\t\t\t\tcolorRed = geType->color_red_;\n\t\t\t\tcolorGreen = geType->color_green_;\n\t\t\t\tcolorBlue = geType->color_blue_;\n\t\t\t\tcolorAlpha = 1.0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tslim_objectid_t elementTypeID = geType->genomic_element_type_id_;\n                \n\t\t\t\tcontroller_->colorForGenomicElementType(geType, elementTypeID, &colorRed, &colorGreen, &colorBlue, &colorAlpha);\n\t\t\t}\n\t\t\t\n\t\t\tSLIM_GL_DEFCOORDS(elementRect);\n\t\t\tSLIM_GL_PUSHRECT();\n\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = elementRect.left();\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawMutations(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n\tdouble scalingFactor = 0.8; // used to be controller->selectionColorScale;\n    Species *displaySpecies = &chromosome->species_;\n\tPopulation &pop = displaySpecies->population_;\n    double totalHaplosomeCount = chromosome->gui_total_haplosome_count_;\t\t\t\t// this includes only haplosomes in the selected subpopulations\n    \n    // Prefetch the mutations we actually want to display\n    static std::vector<const Mutation *> mutations;\n    mutations.resize(0);\n    \n    {\n        int registry_size;\n        const MutationIndex *registry = pop.MutationRegistry(&registry_size);\n        Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n        slim_chromosome_index_t chromosome_index = chromosome->Index();\n        \n        for (int registry_index = 0; registry_index < registry_size; ++registry_index)\n        {\n            const Mutation *mutation = mut_block_ptr + registry[registry_index];\n            \n            if (mutation->chromosome_index_ == chromosome_index)\n            {\n                const MutationType *mutType = mutation->mutation_type_ptr_;\n                \n                if (mutType->mutation_type_displayed_)\n                    mutations.emplace_back(mutation);\n            }\n        }\n    }\n    \n\t// Set up to draw rects\n\tfloat colorRed = 0.0f, colorGreen = 0.0f, colorBlue = 0.0f, colorAlpha = 1.0;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tif ((mutations.size() < 1000) || (displayedRange.length < interiorRect.width()))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n\t\tfor (const Mutation *mutation : mutations)\n\t\t{\n            const MutationType *mutType = mutation->mutation_type_ptr_;\n            slim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n            slim_position_t mutationPosition = mutation->position_;\n            QRect mutationTickRect = rectEncompassingBaseToBase(mutationPosition, mutationPosition, interiorRect, displayedRange);\n            \n            if (!mutType->color_.empty())\n            {\n                colorRed = mutType->color_red_;\n                colorGreen = mutType->color_green_;\n                colorBlue = mutType->color_blue_;\n            }\n            else\n            {\n                RGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n            }\n            \n            int height_adjust = mutationTickRect.height() - static_cast<int>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n            mutationTickRect.setTop(mutationTickRect.top() + height_adjust);\n            \n            SLIM_GL_DEFCOORDS(mutationTickRect);\n            SLIM_GL_PUSHRECT();\n            SLIM_GL_PUSHRECT_COLORS();\n            SLIM_GL_CHECKBUFFERS();\n        }\n\t}\n\telse\n\t{\n\t\t// We have a lot of mutations, so let's try to be smarter.  It's hard to be smarter.  The overhead from allocating the NSColors and such\n\t\t// is pretty negligible; practially all the time is spent in NSRectFill().  Unfortunately, NSRectFillListWithColors() provides basically\n\t\t// no speedup; Apple doesn't appear to have optimized it.  So, here's what I came up with.  For each mutation type that uses a fixed DFE,\n\t\t// and thus a fixed color, we can do a radix sort of mutations into bins corresponding to each pixel in our displayed image.  Then we\n\t\t// can draw each bin just once, making one bar for the highest bar in that bin.  Mutations from non-fixed DFEs, and mutations which have\n\t\t// had their selection coefficient changed, will be drawn at the end in the usual (slow) way.\n\t\tint displayPixelWidth = interiorRect.width();\n\t\tint16_t *heightBuffer = static_cast<int16_t *>(malloc(static_cast<size_t>(displayPixelWidth) * sizeof(int16_t)));\n\t\tbool *mutationsPlotted = static_cast<bool *>(calloc(mutations.size(), sizeof(bool)));\t// faster than using gui_scratch_reference_count_ because of cache locality\n\t\tint64_t remainingMutations = mutations.size();\n\t\t\n\t\t// First zero out the scratch refcount, which we use to track which mutations we have drawn already\n\t\t//for (int mutIndex = 0; mutIndex < mutationCount; ++mutIndex)\n\t\t//\tmutations[mutIndex]->gui_scratch_reference_count_ = 0;\n\t\t\n\t\t// Then loop through the declared mutation types\n\t\tstd::map<slim_objectid_t,MutationType*> &mut_types = displaySpecies->mutation_types_;\n\t\tbool draw_muttypes_sequentially = (mut_types.size() <= 20);\t// with a lot of mutation types, the algorithm below becomes very inefficient\n\t\t\n\t\tfor (auto mutationTypeIter : mut_types)\n\t\t{\n\t\t\tMutationType *mut_type = mutationTypeIter.second;\n\t\t\t\n\t\t\tif (mut_type->mutation_type_displayed_)\n\t\t\t{\n\t\t\t\tif (draw_muttypes_sequentially)\n\t\t\t\t{\n\t\t\t\t\tbool mut_type_fixed_color = !mut_type->color_.empty();\n\t\t\t\t\t\n\t\t\t\t\t// We optimize fixed-DFE mutation types only, and those using a fixed color set by the user\n\t\t\t\t\tif ((mut_type->dfe_type_ == DFEType::kFixed) || mut_type_fixed_color)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_selcoeff_t mut_type_selcoeff = (mut_type_fixed_color ? 0.0 : static_cast<slim_selcoeff_t>(mut_type->dfe_parameters_[0]));\n\t\t\t\t\t\t\n\t\t\t\t\t\tEIDOS_BZERO(heightBuffer, static_cast<size_t>(displayPixelWidth) * sizeof(int16_t));\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Scan through the mutation list for mutations of this type with the right selcoeff\n\t\t\t\t\t\tfor (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\t\t\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n                            // We do want to do an exact floating-point equality compare here; we want to see whether the mutation's selcoeff is unmodified from the fixed DFE\n\t\t\t\t\t\t\tif ((mutation->mutation_type_ptr_ == mut_type) && (mut_type_fixed_color || (mutation->selection_coeff_ == mut_type_selcoeff)))\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// includes only refs from the selected subpopulations\n\t\t\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\t\t\tint16_t barHeight = static_cast<int16_t>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t\t\t\tif (barHeight > heightBuffer[xPos])\n\t\t\t\t\t\t\t\t\t\theightBuffer[xPos] = barHeight;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\t\t\tmutationsPlotted[mutation_index] = true;\n\t\t\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Now draw all of the mutations we found, by looping through our radix bins\n\t\t\t\t\t\tif (mut_type_fixed_color)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcolorRed = mut_type->color_red_;\n\t\t\t\t\t\t\tcolorGreen = mut_type->color_green_;\n\t\t\t\t\t\t\tcolorBlue = mut_type->color_blue_;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mut_type_selcoeff), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint barHeight = heightBuffer[binIndex];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (barHeight)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tQRect mutationTickRect(interiorRect.x() + binIndex, interiorRect.y(), 1, interiorRect.height());\n                                mutationTickRect.setTop(mutationTickRect.top() + interiorRect.height() - barHeight);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We're not displaying this mutation type, so we need to mark off all the mutations belonging to it as handled\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n                    const Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\n\t\t\t\t\tif (mutation->mutation_type_ptr_ == mut_type)\n\t\t\t\t\t{\n\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\tmutationsPlotted[mutation_index] = true;\n\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Draw any undrawn mutations on top; these are guaranteed not to use a fixed color set by the user, since those are all handled above\n\t\tif (remainingMutations)\n\t\t{\n\t\t\tif (remainingMutations < 1000)\n\t\t\t{\n\t\t\t\t// Plot the remainder by brute force, since there are not that many\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[mutation_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n                        QRect mutationTickRect = rectEncompassingBaseToBase(mutationPosition, mutationPosition, interiorRect, displayedRange);\n                        int height_adjust = mutationTickRect.height() - static_cast<int>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\n                        mutationTickRect.setTop(mutationTickRect.top() + height_adjust);\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// OK, we have a lot of mutations left to draw.  Here we will again use the radix sort trick, to keep track of only the tallest bar in each column\n\t\t\t\tconst Mutation **mutationBuffer = static_cast<const Mutation **>(calloc(static_cast<size_t>(displayPixelWidth),  sizeof(Mutation *)));\n\t\t\t\t\n\t\t\t\tEIDOS_BZERO(heightBuffer, static_cast<size_t>(displayPixelWidth) * sizeof(int16_t));\n\t\t\t\t\n\t\t\t\t// Find the tallest bar in each column\n                for (int mutation_index = 0; mutation_index < (int)mutations.size(); ++mutation_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[mutation_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mutations[mutation_index];\n\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\tint16_t barHeight = static_cast<int16_t>(ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.height()));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (barHeight > heightBuffer[xPos])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\theightBuffer[xPos] = barHeight;\n\t\t\t\t\t\t\t\tmutationBuffer[xPos] = mutation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now plot the bars\n\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t{\n\t\t\t\t\tint barHeight = heightBuffer[binIndex];\n\t\t\t\t\t\n\t\t\t\t\tif (barHeight)\n\t\t\t\t\t{\n                        QRect mutationTickRect(interiorRect.x() + binIndex, interiorRect.y(), 1, interiorRect.height());\n                        mutationTickRect.setTop(mutationTickRect.top() + interiorRect.height() - barHeight);\n                        \n\t\t\t\t\t\tconst Mutation *mutation = mutationBuffer[binIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(mutation->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfree(mutationBuffer);\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(heightBuffer);\n\t\tfree(mutationsPlotted);\n\t}\n\t\n\tSLIM_GL_FINISH();\n    \n    mutations.resize(0);\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawFixedSubstitutions(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n    double scalingFactor = 0.8; // used to be controller->selectionColorScale;\n    Species *displaySpecies = &chromosome->species_;\n\tPopulation &pop = displaySpecies->population_;\n\tbool chromosomeHasDefaultColor = !chromosome->color_sub_.empty();\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n    slim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\n\t// Set up to draw rects\n\tfloat colorRed = 0.2f, colorGreen = 0.2f, colorBlue = 1.0f, colorAlpha = 1.0;\n\t\n\tif (chromosomeHasDefaultColor)\n\t{\n\t\tcolorRed = chromosome->color_sub_red_;\n\t\tcolorGreen = chromosome->color_sub_green_;\n\t\tcolorBlue = chromosome->color_sub_blue_;\n\t}\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tif ((substitutions.size() < 1000) || (displayedRange.length < interiorRect.width()))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n            if ((substitution->chromosome_index_ == chromosome_index) && (substitution->mutation_type_ptr_->mutation_type_displayed_))\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tQRect substitutionTickRect = rectEncompassingBaseToBase(substitutionPosition, substitutionPosition, interiorRect, displayedRange);\n\t\t\t\t\n\t\t\t\tif (!shouldDrawMutations() || !chromosomeHasDefaultColor)\n\t\t\t\t{\n\t\t\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue (set above), to contrast\n\t\t\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tcolorRed = mutType->color_sub_red_;\n\t\t\t\t\t\tcolorGreen = mutType->color_sub_green_;\n\t\t\t\t\t\tcolorBlue = mutType->color_sub_blue_;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(substitution->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSLIM_GL_DEFCOORDS(substitutionTickRect);\n\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We have a lot of substitutions, so do a radix sort, as we do in drawMutationsInInteriorRect: below.\n\t\tint displayPixelWidth = interiorRect.width();\n\t\tconst Substitution **subBuffer = static_cast<const Substitution **>(calloc(static_cast<size_t>(displayPixelWidth), sizeof(Substitution *)));\n\t\t\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n            if ((substitution->chromosome_index_ == chromosome_index) && (substitution->mutation_type_ptr_->mutation_type_displayed_))\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tdouble startFraction = (substitutionPosition - static_cast<slim_position_t>(displayedRange.location)) / static_cast<double>(displayedRange.length);\n\t\t\t\tint xPos = static_cast<int>(floor(startFraction * interiorRect.width()));\n\t\t\t\t\n\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\tsubBuffer[xPos] = substitution;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (shouldDrawMutations() && chromosomeHasDefaultColor)\n\t\t{\n\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue, to contrast\n\t\t\tQRect mutationTickRect = interiorRect;\n            \n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n                    mutationTickRect.setX(interiorRect.x() + binIndex);\n                    mutationTickRect.setWidth(1);\n                    \n\t\t\t\t\t// consolidate adjacent lines together, since they are all the same color\n\t\t\t\t\twhile ((binIndex + 1 < displayPixelWidth) && subBuffer[binIndex + 1])\n\t\t\t\t\t{\n                        mutationTickRect.setWidth(mutationTickRect.width() + 1);\n\t\t\t\t\t\tbinIndex++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n            QRect mutationTickRect = interiorRect;\n\t\t\t\n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tcolorRed = mutType->color_sub_red_;\n\t\t\t\t\t\tcolorGreen = mutType->color_sub_green_;\n\t\t\t\t\t\tcolorBlue = mutType->color_sub_blue_;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(static_cast<double>(substitution->selection_coeff_), &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t}\n\t\t\t\t\t\n                    mutationTickRect.setX(interiorRect.x() + binIndex);\n                    mutationTickRect.setWidth(1);\n\t\t\t\t\tSLIM_GL_DEFCOORDS(mutationTickRect);\n\t\t\t\t\tSLIM_GL_PUSHRECT();\n\t\t\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(subBuffer);\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::_qtDrawRateMapIntervals(QRect &interiorRect, __attribute__((__unused__)) Chromosome *chromosome, QtSLiMRange displayedRange, std::vector<slim_position_t> &ends, std::vector<double> &rates, double hue, QPainter &painter)\n{\n\tsize_t recombinationIntervalCount = ends.size();\n\tslim_position_t intervalStartPosition = 0;\n\tint previousIntervalLeftEdge = -10000;\n\t\n\tSLIM_GL_PREPARE();\n\t\n\tfor (size_t interval = 0; interval < recombinationIntervalCount; ++interval)\n\t{\n\t\tslim_position_t intervalEndPosition = ends[interval];\n\t\tdouble intervalRate = rates[interval];\n\t\tQRect intervalRect = rectEncompassingBaseToBase(intervalStartPosition, intervalEndPosition, interiorRect, displayedRange);\n\t\tbool widthOne = (intervalRect.width() == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (intervalRect.left() == previousIntervalLeftEdge))\n            intervalRect.adjust(1, 0, 0, 0);\n\t\t\n\t\t// draw only the visible part, if any\n        intervalRect = intervalRect.intersected(interiorRect);\n\t\t\n        if (!intervalRect.isEmpty())\n\t\t{\n\t\t\t// color according to how \"hot\" the region is\n            float colorRed, colorGreen, colorBlue, colorAlpha;\n\t\t\t\n\t\t\tif (intervalRate == 0.0)\n\t\t\t{\n\t\t\t\t// a recombination or mutation rate of 0.0 comes out as black, whereas the lowest brightness below is 0.5; we want to distinguish this\n\t\t\t\tcolorRed = colorGreen = colorBlue = 0.0;\n\t\t\t\tcolorAlpha = 1.0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the formula below scales 1e-6 to 1.0 and 1e-9 to 0.0; values outside that range clip, but we want there to be\n\t\t\t\t// reasonable contrast within the range of values commonly used, so we don't want to make the range too wide\n\t\t\t\tdouble lightness, brightness = 1.0, saturation = 1.0;\n\t\t\t\t\n\t\t\t\tlightness = (log10(intervalRate) + 9.0) / 3.0;\n\t\t\t\tlightness = std::max(lightness, 0.0);\n\t\t\t\tlightness = std::min(lightness, 1.0);\n\t\t\t\t\n\t\t\t\tif (lightness >= 0.5)\tsaturation = 1.0 - ((lightness - 0.5) * 2.0);\t// goes from 1.0 at lightness 0.5 to 0.0 at lightness 1.0\n\t\t\t\telse\t\t\t\t\tbrightness = 0.5 + lightness;\t\t\t\t\t// goes from 1.0 at lightness 0.5 to 0.5 at lightness 0.0\n\t\t\t\t\n                QColor intervalColor = QtSLiMColorWithHSV(hue, saturation, brightness, 1.0);\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n                // In Qt5, getRgbF() expects pointers to qreal, which is double\n                double r, g, b, a;\n\t\t\t\tintervalColor.getRgbF(&r, &g, &b, &a);\n                \n                colorRed = static_cast<float>(r);\n                colorGreen = static_cast<float>(g);\n                colorBlue = static_cast<float>(b);\n                colorAlpha = static_cast<float>(a);\n#else\n                // In Qt6, getRgbF() expects pointers to float\n                intervalColor.getRgbF(&colorRed, &colorGreen, &colorBlue, &colorAlpha);\n#endif\n\t\t\t}\n\t\t\t\n\t\t\tSLIM_GL_DEFCOORDS(intervalRect);\n\t\t\tSLIM_GL_PUSHRECT();\n\t\t\tSLIM_GL_PUSHRECT_COLORS();\n\t\t\tSLIM_GL_CHECKBUFFERS();\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = intervalRect.left();\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t\t\n\t\t// the next interval starts at the next base after this one ended\n\t\tintervalStartPosition = intervalEndPosition + 1;\n\t}\n\t\n\tSLIM_GL_FINISH();\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawRecombinationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n\tif (chromosome->single_recombination_map_)\n\t{\n\t\t_qtDrawRateMapIntervals(interiorRect, chromosome, displayedRange, chromosome->recombination_end_positions_H_, chromosome->recombination_rates_H_, 0.65, painter);\n\t}\n\telse\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n\t\t\n\t\t_qtDrawRateMapIntervals(topInteriorRect, chromosome, displayedRange, chromosome->recombination_end_positions_M_, chromosome->recombination_rates_M_, 0.65, painter);\n\t\t_qtDrawRateMapIntervals(bottomInteriorRect, chromosome, displayedRange, chromosome->recombination_end_positions_F_, chromosome->recombination_rates_F_, 0.65, painter);\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawMutationIntervals(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n\tif (chromosome->single_mutation_map_)\n\t{\n\t\t_qtDrawRateMapIntervals(interiorRect, chromosome, displayedRange, chromosome->mutation_end_positions_H_, chromosome->mutation_rates_H_, 0.75, painter);\n\t}\n\telse\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n\t\t\n\t\t_qtDrawRateMapIntervals(topInteriorRect, chromosome, displayedRange, chromosome->mutation_end_positions_M_, chromosome->mutation_rates_M_, 0.75, painter);\n\t\t_qtDrawRateMapIntervals(bottomInteriorRect, chromosome, displayedRange, chromosome->mutation_end_positions_F_, chromosome->mutation_rates_F_, 0.75, painter);\n\t}\n}\n\nvoid QtSLiMChromosomeWidget::qtDrawRateMaps(QRect &interiorRect, Chromosome *chromosome, QtSLiMRange displayedRange, QPainter &painter)\n{\n\tbool recombinationWorthShowing = false;\n\tbool mutationWorthShowing = false;\n\t\n\tif (chromosome->single_mutation_map_)\n\t\tmutationWorthShowing = (chromosome->mutation_end_positions_H_.size() > 1);\n\telse\n\t\tmutationWorthShowing = ((chromosome->mutation_end_positions_M_.size() > 1) || (chromosome->mutation_end_positions_F_.size() > 1));\n\t\n\tif (chromosome->single_recombination_map_)\n\t\trecombinationWorthShowing = (chromosome->recombination_end_positions_H_.size() > 1);\n\telse\n\t\trecombinationWorthShowing = ((chromosome->recombination_end_positions_M_.size() > 1) || (chromosome->recombination_end_positions_F_.size() > 1));\n\t\n\t// If neither map is worth showing, we show just the recombination map, to mirror the behavior of 2.4 and earlier\n\tif ((!mutationWorthShowing && !recombinationWorthShowing) || (!mutationWorthShowing && recombinationWorthShowing))\n\t{\n\t\tqtDrawRecombinationIntervals(interiorRect, chromosome, displayedRange, painter);\n\t}\n\telse if (mutationWorthShowing && !recombinationWorthShowing)\n\t{\n\t\tqtDrawMutationIntervals(interiorRect, chromosome, displayedRange, painter);\n\t}\n\telse\t// mutationWorthShowing && recombinationWorthShowing\n\t{\n\t\tQRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tint halfHeight = static_cast<int>(ceil(interiorRect.height() / 2.0));\n\t\tint remainingHeight = interiorRect.height() - halfHeight;\n\t\t\n        topInteriorRect.setHeight(halfHeight);\n        bottomInteriorRect.setHeight(remainingHeight);\n        bottomInteriorRect.translate(0, halfHeight);\n        \n\t\tqtDrawRecombinationIntervals(topInteriorRect, chromosome, displayedRange, painter);\n\t\tqtDrawMutationIntervals(bottomInteriorRect, chromosome, displayedRange, painter);\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMConsoleTextEdit.cpp",
    "content": "//\n//  QtSLiMConsoleTextEdit.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMConsoleTextEdit.h\"\n\n#include <QTextCursor>\n#include <QMouseEvent>\n#include <QKeyEvent>\n#include <QScrollBar>\n#include <QCompleter>\n#include <QAbstractItemView>\n#include <QDebug>\n\n#include <algorithm>\n\n#include \"QtSLiMExtras.h\"\n#include \"eidos_globals.h\"\n#include \"slim_globals.h\"\n\n\n// It's tempting to use QChar::LineSeparator here instead of \\n, and in some ways it\n// produces better behavior (copy/paste to TextEdit produces better results, for example),\n// but it might cause the user problems because it's Unicode-specific; and we want command\n// lines to be a separate block with margins above and below, also.\nstatic const QString NEWLINE(\"\\n\");\n\n// This is margin in pixels above and below command lines, to set them off nicely\nstatic const double BLOCK_MARGIN = 3.0;\n\n\nQtSLiMConsoleTextEdit::QtSLiMConsoleTextEdit(const QString &text, QWidget *p_parent) : QtSLiMTextEdit(text, p_parent)\n{\n    selfInit();\n}\n\nQtSLiMConsoleTextEdit::QtSLiMConsoleTextEdit(QWidget *p_parent) : QtSLiMTextEdit(p_parent)\n{\n    selfInit();\n}\n\nvoid QtSLiMConsoleTextEdit::selfInit(void)\n{\n    // set up to react to selection changes; see these methods for comments\n    connect(this, &QPlainTextEdit::selectionChanged, this, &QtSLiMConsoleTextEdit::handleSelectionChanged);\n    connect(this, &QPlainTextEdit::cursorPositionChanged, this, &QtSLiMConsoleTextEdit::handleSelectionChanged);\n    connect(this, &QtSLiMConsoleTextEdit::selectionWasChangedDuringLastEvent, this, &QtSLiMConsoleTextEdit::adjustSelectionAndReadOnly, Qt::QueuedConnection);\n}\n\nQtSLiMConsoleTextEdit::~QtSLiMConsoleTextEdit()\n{\n}\n\nQTextCharFormat QtSLiMConsoleTextEdit::textFormatForColor(QColor color)\n{\n    QTextCharFormat attrs;\n    attrs.setForeground(QBrush(color));\n    return attrs;\n}\n\nvoid QtSLiMConsoleTextEdit::scriptStringAndSelection(QString &scriptString, int &position, int &length, int &offset)\n{\n    // here we provide a subclass definition of what we consider \"script\": just what follows the prompt\n    QTextCursor commandCursor(lastPromptCursor);\n    commandCursor.setPosition(commandCursor.position(), QTextCursor::MoveAnchor);\n    commandCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n    \n    scriptString = commandCursor.selectedText();\n    \n    QTextCursor selection = textCursor();\n    position = selection.anchor();\n    length = selection.position() - position;\n    \n    position -= commandCursor.anchor();      // compensate for snipping off everything from the prompt back\n    offset = commandCursor.anchor();    // tell the caller how much we snipped off\n}\n\nvoid QtSLiMConsoleTextEdit::showWelcome(void)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    setCurrentCharFormat(textFormatForColor(inDarkMode ? Qt::white : Qt::black));\n    \n    QString welcomeMessage;\n    welcomeMessage = welcomeMessage + \"Eidos version \" + EIDOS_VERSION_STRING + NEWLINE + NEWLINE;\t\t// EIDOS VERSION\n    welcomeMessage += \"By Benjamin C. Haller and Philipp W. Messer.\" + NEWLINE;\n    welcomeMessage += \"Copyright (c) 2016–2026 Benjamin C. Haller.\" + NEWLINE;\n    welcomeMessage += \"All rights reserved.\" + NEWLINE + NEWLINE;\n    welcomeMessage += \"Eidos is free software with ABSOLUTELY NO WARRANTY.\" + NEWLINE;\n    welcomeMessage += \"Type license() for license and distribution details.\" + NEWLINE + NEWLINE;\n    welcomeMessage += \"Go to https://github.com/MesserLab/SLiM for source\" + NEWLINE;\n    welcomeMessage += \"code, documentation, examples, and other information.\" + NEWLINE + NEWLINE;\n    welcomeMessage += \"Welcome to Eidos!\" + NEWLINE + NEWLINE;\n    welcomeMessage += \"-----------------------------------------------------\" + NEWLINE + NEWLINE;\n    welcomeMessage += \"Connected to SLiMgui simulation.\" + NEWLINE;\n    welcomeMessage = welcomeMessage + \"SLiM version \" + SLIM_VERSION_STRING + \".\" + NEWLINE + NEWLINE;      // SLIM VERSION\n    welcomeMessage += \"-----------------------------------------------------\" + NEWLINE + NEWLINE;\n    \n    insertPlainText(welcomeMessage);\n}\n\nvoid QtSLiMConsoleTextEdit::showPrompt(QChar promptChar)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    QTextCharFormat promptAttrs = textFormatForColor(inDarkMode ? QColor(220, 83, 185) : QColor(170, 13, 145));\n    QTextCharFormat inputAttrs = textFormatForColor(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207));\n    \n    moveCursor(QTextCursor::End);\n    setCurrentCharFormat(promptAttrs);\n    insertPlainText(promptChar);\n    moveCursor(QTextCursor::End);\n    setCurrentCharFormat(inputAttrs);\n    insertPlainText(\" \");\n    moveCursor(QTextCursor::End);\n    \n    QTextCursor promptCursor(document());\n    promptCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);\n    promptCursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2);\n    promptCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);\n    \n    QTextBlockFormat marginBlockFormat;\n    marginBlockFormat.setTopMargin(BLOCK_MARGIN);\n    marginBlockFormat.setBottomMargin(BLOCK_MARGIN);\n    promptCursor.setBlockFormat(marginBlockFormat);\n    \n    // We remember the prompt range for various purposes such as uneditability of old content\n    lastPromptCursor = promptCursor;\n    lastPromptCursor.setKeepPositionOnInsert(true);\n    \n    // When a new prompt appears, one can no longer undo/redo previous changes\n    document()->clearUndoRedoStacks();\n}\n\nvoid QtSLiMConsoleTextEdit::showPrompt(void)\n{\n    showPrompt('>');\n}\n\nvoid QtSLiMConsoleTextEdit::showContinuationPrompt(void)\n{\n    // The user has entered an incomplete script line, so we need to append a newline...\n    moveCursor(QTextCursor::End);\n    insertPlainText(NEWLINE);\n    \n    // ...and issue a continuation prompt to await further input\n    int promptEnd = lastPromptCursor.position();\n    \n    showPrompt('+');\n    originalPromptEnd = promptEnd;\n    isContinuationPrompt = true;\n}\n\nvoid QtSLiMConsoleTextEdit::appendExecution(QString result, QString errorString, QString tokenString, QString parseString, QString executionString)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    moveCursor(QTextCursor::End);\n    insertPlainText(NEWLINE);\n    \n    if (tokenString.length())\n    {\n        moveCursor(QTextCursor::End);\n        setCurrentCharFormat(textFormatForColor(inDarkMode ? QColor(100, 56, 32) : QColor(100, 56, 32)));\n        insertPlainText(tokenString);\n    }\n    if (parseString.length())\n    {\n        moveCursor(QTextCursor::End);\n        setCurrentCharFormat(textFormatForColor(inDarkMode ? QColor(90, 210, 90) : QColor(0, 116, 0)));\n        insertPlainText(parseString);\n    }\n    if (executionString.length())\n    {\n        moveCursor(QTextCursor::End);\n        setCurrentCharFormat(textFormatForColor(inDarkMode ? QColor(70, 205, 216) : QColor(63, 110, 116)));\n        insertPlainText(executionString);\n    }\n    if (result.length())\n    {\n        QTextBlockFormat plainBlockFormat;\n        \n        moveCursor(QTextCursor::End);\n        setCurrentCharFormat(textFormatForColor(inDarkMode ? QColor(255, 255, 255) : QColor(0, 0, 0)));\n        textCursor().setBlockFormat(plainBlockFormat);\n        insertPlainText(result);\n    }\n    if (errorString.length())\n    {\n        QTextBlockFormat marginBlockFormat;\n        marginBlockFormat.setTopMargin(BLOCK_MARGIN);\n        marginBlockFormat.setBottomMargin(BLOCK_MARGIN);\n        \n        moveCursor(QTextCursor::End);\n        setCurrentCharFormat(textFormatForColor(inDarkMode ? QColor(220, 98, 90) : QColor(196, 26, 22)));\n        textCursor().setBlockFormat(marginBlockFormat);\n        insertPlainText(errorString);\n        \n\t\t// If we have an error, it is in the user script, and it has a valid position,\n\t\t// then we can try to highlight it in the input\n        if ((!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == 0)) &&\n            (gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 >= 0) &&\n            (gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 >= gEidosErrorContext.errorPosition.characterStartOfErrorUTF16))\n\t\t{\n            int promptEnd = lastPromptCursor.position();\n\t\t\tint errorTokenStart = gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 + promptEnd;\n\t\t\tint errorTokenEnd = gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 + promptEnd;\n\t\t\t\n            QTextCursor highlightCursor(lastPromptCursor);\n            highlightCursor.setPosition(errorTokenStart, QTextCursor::MoveAnchor);\n            highlightCursor.setPosition(errorTokenEnd + 1, QTextCursor::KeepAnchor);\n            \n            QTextCharFormat highlightFormat;\n            highlightFormat.setForeground(QBrush(Qt::black));\n            highlightFormat.setBackground(QBrush(inDarkMode ? QColor(220, 98, 90) : QColor(QColor(Qt::red).lighter(120))));\n            \n            highlightCursor.setCharFormat(highlightFormat);\n            \n            // note that unlike the error highlighting in the scripting views, this error\n            // highlighting is permanent, and will not be removed by later cursor changes\n\t\t}\n    }\n    \n    // scroll to bottom\n    verticalScrollBar()->setValue(verticalScrollBar()->maximum());\n}\n\nvoid QtSLiMConsoleTextEdit::clearToPrompt(void)\n{\n    if (isContinuationPrompt)\n    {\n        QTextCursor deleteCursor(lastPromptCursor);\n        deleteCursor.setPosition(originalPromptEnd - 2, QTextCursor::MoveAnchor);\n        deleteCursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);\n        deleteCursor.insertText(\"\");\n        originalPromptEnd = 2;\n    }\n    else\n    {\n        QTextCursor deleteCursor(lastPromptCursor);\n        deleteCursor.setPosition(deleteCursor.anchor(), QTextCursor::MoveAnchor);\n        deleteCursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);\n        deleteCursor.insertText(\"\");\n    }\n    \n    // Clearing the console is not undoable, and it clears the undo/redo history\n    document()->clearUndoRedoStacks();\n}\n\nQString QtSLiMConsoleTextEdit::currentCommandAtPrompt(void)\n{\n    QTextCursor commandCursor(lastPromptCursor);\n    commandCursor.setPosition(commandCursor.position(), QTextCursor::MoveAnchor);\n    commandCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n    return commandCursor.selectedText();\n}\n\nvoid QtSLiMConsoleTextEdit::setCommandAtPrompt(QString newCommand)\n{\n    newCommand = newCommand.trimmed();  // trim off whitespace around the command line\n    \n    QTextCursor commandCursor(lastPromptCursor);\n    commandCursor.setPosition(commandCursor.position(), QTextCursor::MoveAnchor);\n    commandCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n    commandCursor.setKeepPositionOnInsert(false);    \n    commandCursor.insertText(newCommand);\n    moveCursor(QTextCursor::End);\n}\n\nvoid QtSLiMConsoleTextEdit::registerNewHistoryItem(QString newItem)\n{\n    // If there is a provisional item on the top of the stack, get rid of it and replace it\n\tif (lastHistoryItemIsProvisional)\n\t{\n        history.pop_back();\n\t\tlastHistoryItemIsProvisional = false;\n\t}\n\t\n    history.push_back(newItem);\n\thistoryIndex = history.count();\t// a new prompt, one beyond the last history item\n}\n\nvoid QtSLiMConsoleTextEdit::elideContinuationPrompt(void)\n{\n    // This replaces the continuation prompt, if there is one, with a space, and switches the active prompt back to the original prompt;\n\t// the net effect is as if the user entered a newline and two spaces at the original prompt, with no continuation.  Note that the\n\t// two spaces at the beginning of continuation lines is mirrored in fullInputString, below.\n\tif (isContinuationPrompt)\n\t{\n        bool inDarkMode = QtSLiMInDarkMode();\n        QTextCharFormat inputAttrs = textFormatForColor(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207));\n        QTextCursor fixCursor(lastPromptCursor);\n        fixCursor.setPosition(lastPromptCursor.anchor(), QTextCursor::MoveAnchor);\n        fixCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);\n        fixCursor.insertText(\" \", inputAttrs);\n        \n        lastPromptCursor.setPosition(originalPromptEnd - 2, QTextCursor::MoveAnchor);\n        lastPromptCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);\n        isContinuationPrompt = false;\n\t}\n}\n\nQString QtSLiMConsoleTextEdit::fullInputString(void)\n{\n\telideContinuationPrompt();\n\t\n    QTextCursor commandCursor(lastPromptCursor);\n    \n    commandCursor.setPosition(commandCursor.position(), QTextCursor::MoveAnchor);\n    commandCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n    return commandCursor.selectedText();\n}\n\nvoid QtSLiMConsoleTextEdit::previousHistory(void)\n{\n    if (historyIndex > 0)\n\t{\n\t\t// If the user has typed at the current prompt and it is unsaved, save it in the history before going up\n\t\tif (historyIndex == history.count())\n\t\t{\n\t\t\tQString commandString = currentCommandAtPrompt();\n\t\t\t\n\t\t\tif (commandString.length() > 0)\n\t\t\t{\n\t\t\t\t// If there is a provisional item on the top of the stack, get rid of it and replace it\n\t\t\t\tif (lastHistoryItemIsProvisional)\n\t\t\t\t{\n                    history.pop_back();\n\t\t\t\t\tlastHistoryItemIsProvisional = false;\n\t\t\t\t\t--historyIndex;\n\t\t\t\t}\n\t\t\t\t\n                history.push_back(commandString);\n\t\t\t\tlastHistoryItemIsProvisional = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if the only item on the stack was provisional, and we just replaced it, we may have nowhere up to go\n\t\tif (historyIndex > 0)\n\t\t{\n\t\t\t--historyIndex;\n\t\t\n\t\t\tsetCommandAtPrompt(history[historyIndex]);\n\t\t}\n\t\t\n\t\t//NSLog(@\"moveUp: end:\\nhistory = %@\\nhistoryIndex = %d\\nlastHistoryItemIsProvisional = %@\", history, historyIndex, lastHistoryItemIsProvisional ? @\"YES\" : @\"NO\");\n\t}\n}\n\nvoid QtSLiMConsoleTextEdit::nextHistory(void)\n{\n    if (historyIndex <= history.count())\n\t{\n\t\t// If the user has typed at the current prompt and it is unsaved, save it in the history before going down\n\t\tif (historyIndex == history.count())\n\t\t{\n\t\t\tQString commandString = currentCommandAtPrompt();\n\t\t\t\n\t\t\tif (commandString.length() > 0)\n\t\t\t{\n\t\t\t\t// If there is a provisional item on the top of the stack, get rid of it and replace it\n\t\t\t\tif (lastHistoryItemIsProvisional)\n\t\t\t\t{\n                    history.pop_back();\n\t\t\t\t\tlastHistoryItemIsProvisional = false;\n\t\t\t\t\t--historyIndex;\n\t\t\t\t}\n\t\t\t\t\n                history.push_back(commandString);\n\t\t\t\tlastHistoryItemIsProvisional = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn;\n\t\t}\n\t\t\n\t\t++historyIndex;\n\t\t\n\t\tif (historyIndex == history.count())\n\t\t\tsetCommandAtPrompt(\"\");\n\t\telse\n\t\t\tsetCommandAtPrompt(history[historyIndex]);\n\t\t\n\t\t//NSLog(@\"moveDown: end:\\nhistory = %@\\nhistoryIndex = %d\\nlastHistoryItemIsProvisional = %@\", history, historyIndex, lastHistoryItemIsProvisional ? @\"YES\" : @\"NO\");\n\t}\n}\n\nvoid QtSLiMConsoleTextEdit::executeCurrentPrompt(void)\n{\n    QTextCursor endCursor(document());\n    endCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);\n    \n    if (isContinuationPrompt && (lastPromptCursor.position() == endCursor.position()))\n    {\n        // If the user has hit return at an empty continuation prompt, we take that as a sign that they want to get out of it\n        QString executionString = fullInputString();\n        \n        registerNewHistoryItem(executionString);\n        \n        moveCursor(QTextCursor::End);\n        insertPlainText(NEWLINE);\n        \n        // show a new prompt\n        showPrompt();\n    }\n    else\n    {\n        // The current prompt might be a non-empty continuation prompt, so now we get the full input string from the original prompt\n        QString command = fullInputString();\n        \n        //qDebug() << \"execute \" << command;\n        registerNewHistoryItem(command);\n        emit executeScript(command);\n    }\n}\n\nvoid QtSLiMConsoleTextEdit::keyPressEvent(QKeyEvent *p_event)\n{\n    // With a completer, we have to call super in some cases to let it handle the completer logic\n    // This code is parallel to the code in QtSLiMTextEdit::keyPressEvent()\n    if (completer)\n    {\n        if (completer->popup()->isVisible()) {\n            // The following keys are forwarded by the completer to the widget\n           switch (p_event->key()) {\n           case Qt::Key_Enter:\n           case Qt::Key_Return:\n           case Qt::Key_Escape:\n           case Qt::Key_Tab:\n           case Qt::Key_Backtab:\n                QtSLiMTextEdit::keyPressEvent(p_event);\n                return; // let super pass these keys on to the completer\n           default:\n               break;\n           }\n        }\n        \n        // if we have a visible completer popup, the key pressed is not one of the special keys above (including escape)\n        // our completion key shortcut is the escape key, so check for that now\n        bool isShortcut = ((p_event->modifiers() == Qt::NoModifier) && p_event->key() == Qt::Key_Escape); // escape\n        \n        if (!isShortcut)\n        {\n            // any key other than escape and the special keys above causes the completion popup to hide\n            // then we drop through to our normal key handling below\n            completer->popup()->hide();\n        }\n        else\n        {\n            // the completer shortcut has been pressed; let super run the completer\n            QtSLiMTextEdit::keyPressEvent(p_event);\n            return;\n        }\n    }\n    \n    if (p_event->matches(QKeySequence::MoveToPreviousLine))\n    {\n        // up-arrow pressed; cycle through the command history\n        previousHistory();\n        p_event->accept();\n    }\n    else if (p_event->matches(QKeySequence::MoveToNextLine))\n    {\n        // down-arrow pressed; cycle through the command history\n        nextHistory();\n        p_event->accept();\n    }\n    else if (p_event->matches(QKeySequence::InsertLineSeparator) || p_event->matches(QKeySequence::InsertParagraphSeparator))\n    {\n        // return/enter pressed; execute the statement(s) entered\n        executeCurrentPrompt();\n        p_event->accept();\n    }\n    else if (p_event->key() == Qt::Key_Escape)\n    {\n        // escape pressed; this should be handled by the code above, but if we get here just ignore it\n        //qDebug() << \"escape!\";\n        p_event->accept();\n    }\n    else if (p_event->matches(QKeySequence::MoveToEndOfBlock) ||\n             p_event->matches(QKeySequence::MoveToEndOfDocument) ||\n             p_event->matches(QKeySequence::MoveToEndOfLine) ||\n             p_event->matches(QKeySequence::MoveToNextChar) ||\n             p_event->matches(QKeySequence::MoveToNextLine) ||\n             p_event->matches(QKeySequence::MoveToNextPage) ||\n             p_event->matches(QKeySequence::MoveToNextWord) ||\n             p_event->matches(QKeySequence::MoveToPreviousChar) ||\n             p_event->matches(QKeySequence::MoveToPreviousLine) ||\n             p_event->matches(QKeySequence::MoveToPreviousPage) ||\n             p_event->matches(QKeySequence::MoveToPreviousWord) ||\n             p_event->matches(QKeySequence::MoveToStartOfBlock) ||\n             p_event->matches(QKeySequence::MoveToStartOfDocument) ||\n             p_event->matches(QKeySequence::MoveToStartOfLine) ||\n             p_event->matches(QKeySequence::SelectAll) ||\n             p_event->matches(QKeySequence::SelectEndOfBlock) ||\n             p_event->matches(QKeySequence::SelectEndOfDocument) ||\n             p_event->matches(QKeySequence::SelectEndOfLine) ||\n             p_event->matches(QKeySequence::SelectNextChar) ||\n             p_event->matches(QKeySequence::SelectNextLine) ||\n             p_event->matches(QKeySequence::SelectNextPage) ||\n             p_event->matches(QKeySequence::SelectNextWord) ||\n             p_event->matches(QKeySequence::SelectPreviousChar) ||\n             p_event->matches(QKeySequence::SelectPreviousLine) ||\n             p_event->matches(QKeySequence::SelectPreviousPage) ||\n             p_event->matches(QKeySequence::SelectPreviousWord) ||\n             p_event->matches(QKeySequence::SelectStartOfBlock) ||\n             p_event->matches(QKeySequence::SelectStartOfDocument) ||\n             p_event->matches(QKeySequence::SelectStartOfLine))\n    {\n        if (isReadOnly())\n        {\n            // being read-only interferes with keyboard selection changes, for some odd reason,\n            // so we change ourselves to editable around the call to super\n            setReadOnly(false);\n            QtSLiMTextEdit::keyPressEvent(p_event);\n            updateReadOnly();   // maybe roDTS has changed, so maybe we no longer want to be read-only\n        }\n        else if (p_event->matches(QKeySequence::SelectAll))\n        {\n            // in the non-read-only case, we want Select All to select everything in the console, rather\n            // than follow the selection-clipping convention below, I think...\n            QtSLiMTextEdit::keyPressEvent(p_event);\n        }\n        else\n        {\n            // in the non-read-only case, the cursor is inside the command area, and we want to clip movement and\n            // selection to stay within the command area; the user can select other content if they want to, but\n            // by default we assume their intention is to work within the command line (except select all, above)\n            QtSLiMTextEdit::keyPressEvent(p_event);\n            \n            QTextCursor selection(textCursor());\n            int anchor = std::max(selection.anchor(), lastPromptCursor.position());\n            int position = std::max(selection.position(), lastPromptCursor.position());\n            \n            selection.setPosition(anchor, QTextCursor::MoveAnchor);\n            selection.setPosition(position, QTextCursor::KeepAnchor);\n            setTextCursor(selection);\n        }\n    }\n    else if (p_event->matches(QKeySequence::Backspace) || p_event->matches(QKeySequence::DeleteStartOfWord) || (p_event->key() == Qt::Key_Backspace))\n    {\n        // suppress backspace if it would backspace into the prompt; note QKeySequence::Backspace doesn't seem to work!\n        QTextCursor currentCursor(textCursor());\n        \n        if ((currentCursor.position() == currentCursor.anchor()) && (currentCursor.position() == lastPromptCursor.position()))\n        {\n            p_event->accept();\n            return;\n        }\n        \n        QtSLiMTextEdit::keyPressEvent(p_event);\n    }\n    else if (p_event->matches(QKeySequence::DeleteCompleteLine))\n    {\n        // I'm not sure how to produce this on a keyboard, but let's make sure it doesn't delete the prompt\n        setCommandAtPrompt(\"\");\n        p_event->accept();\n    }\n    else\n    {\n        // if the key was not handled above, pass the event to super\n        QtSLiMTextEdit::keyPressEvent(p_event);\n    }\n}\n\nvoid QtSLiMConsoleTextEdit::mousePressEvent(QMouseEvent *p_event)\n{\n    // keep track of when we are inside a mouse tracking loop\n    insideMouseTracking = true;\n    sawSelectionChange = false;\n    \n    QtSLiMTextEdit::mousePressEvent(p_event);\n}\n\nvoid QtSLiMConsoleTextEdit::mouseReleaseEvent(QMouseEvent *p_event)\n{\n    QtSLiMTextEdit::mouseReleaseEvent(p_event);\n    \n    // we're done with the mouse tracking loop; if it changed the selection, we now adjust\n    insideMouseTracking = false;\n    if (sawSelectionChange)\n        adjustSelectionAndReadOnly();\n}\n\nvoid QtSLiMConsoleTextEdit::handleSelectionChanged(void)\n{\n    // This is a handler for both selectionChanged and cursorPositionChanged signals,\n    // because neither one is emitted consistently enough to be usable in general,\n    // unfortunately.  So for a given change, we may be called just once (through one\n    // of those signals) or twice.  We want to defer our reaction until the end of\n    // the event being handled, because sometimes Qt will change one aspect of the\n    // selection (the anchor, say), send one signal, then change another aspect of\n    // the selection (the position, say), and send another signal; if we react to\n    // the first change before the second change has also been made we will misjudge\n    // what needs to be done.\n    \n    //qDebug() << \"handleSelectionChanged\";\n    \n    if (insideMouseTracking)\n    {\n        // when mouse-tracking, selection changes get deferred until tracking is complete\n        // adjustSelectionAndReadOnly() will be called by QtSLiMConsoleTextEdit::mouseReleaseEvent()\n        sawSelectionChange = true;\n    }\n    else\n    {\n        // when not mouse-tracking, selection changes get adjusted at the end of\n        // this event loop callout so we are sure all changes have been made\n        // adjustSelectionAndReadOnly() will be called by a queued connection set up in selfInit()\n        emit selectionWasChangedDuringLastEvent();\n    }\n}\n\nvoid QtSLiMConsoleTextEdit::adjustSelectionAndReadOnly(void)\n{\n    //qDebug() << \"adjustSelectionAndReadOnly\";\n    \n    QTextCursor selection(textCursor());\n    \n    if (selection.position() == selection.anchor())\n    {\n        // a zero-length selection has been requested; if it falls before the end of the prompt, we adjust it\n        // to fall at the end of the console instead; note we will get a re-entrant call back from this\n        // a special case: if the new position is just to the left of the prompt end, move to the prompt end\n        if (selection.position() == lastPromptCursor.position() - 1)\n            moveCursor(QTextCursor::Right);\n        else if (selection.position() < lastPromptCursor.position())\n            moveCursor(QTextCursor::End);\n        \n        setReadOnlyDueToSelection(false);\n    }\n    else\n    {\n        // a non-zero-length selection has been requested; we allow any such selection, but if it encompasses\n        // characters before the end of the current prompt, we make ourselves non-editable to prevent changes\n        int start = selection.selectionStart();\n        \n        if (start < lastPromptCursor.position())\n            setReadOnlyDueToSelection(true);\n        else\n            setReadOnlyDueToSelection(false);\n    }\n}\n\n// prevent drops outside of the prompt area\n// thanks to https://github.com/uglide/QtConsole/blob/master/src/qconsole.cpp\nvoid QtSLiMConsoleTextEdit::dragMoveEvent(QDragMoveEvent *p_event)\n{\n    // Figure out where the drop would go\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    QTextCursor dropCursor = cursorForPosition(p_event->pos());\n#else\n    QTextCursor dropCursor = cursorForPosition(p_event->position().toPoint());\n#endif\n    \n    //qDebug() << \"dragMoveEvent: \" << dropCursor.position();\n    \n    if (dropCursor.position() < lastPromptCursor.position())\n    {\n        // Ignore the event if the drop would be outside the command area\n        p_event->ignore(cursorRect(dropCursor));\n    }\n    else\n    {\n        // Accept the event if the drop is inside the command area\n        p_event->accept(cursorRect(dropCursor));\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMConsoleTextEdit.h",
    "content": "//\n//  QtSLiMConsoleTextEdit.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMCONSOLETEXTEDIT_H\n#define QTSLIMCONSOLETEXTEDIT_H\n\n#include <QPlainTextEdit>\n#include <QTextCharFormat>\n#include <QColor>\n#include <QStringList>\n\n#include \"QtSLiMScriptTextEdit.h\"   // defines our superclass, QtSLiMTextEdit\n\n\nclass QtSLiMConsoleTextEdit : public QtSLiMTextEdit\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMConsoleTextEdit(const QString &text, QWidget *p_parent = nullptr);\n    QtSLiMConsoleTextEdit(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMConsoleTextEdit() override;\n    \n    static QTextCharFormat textFormatForColor(QColor color);\n    \n    // Show the initial welcome message\n    void showWelcome(void);\n    \n    // Prompts and spacers\n    void showPrompt(QChar promptChar);\n    void showPrompt(void);\n    void showContinuationPrompt(void);\n    void clearToPrompt(void);\n    \n    // Commands and history\n    void appendExecution(QString result, QString errorString, QString tokenString, QString parseString, QString executionString);\n    QString currentCommandAtPrompt(void);\n    void setCommandAtPrompt(QString newCommand);\n    void registerNewHistoryItem(QString newItem);\n    \n    // Fix the selection to be legal, and adjust the read-only setting accordingly\n    void adjustSelectionAndReadOnly(void);\n    \n    // Read-only state handling; this is a consequence of two independent flags, for us\n    void setReadOnlyDueToSelection(bool flag) { roDTS = flag; updateReadOnly(); }\n    void setReadOnlyDueToActivation(bool flag) { roDTA = flag; updateReadOnly(); }\n    void updateReadOnly(void) { setReadOnly(roDTS | roDTA); }\n    \npublic slots:\n    void previousHistory(void);\n    void nextHistory(void);\n    void executeCurrentPrompt(void);\n    \nsignals:\n    void executeScript(QString script);\n    \nprotected:\n    void selfInit(void);\n    virtual void keyPressEvent(QKeyEvent *p_event) override;\n    \n    // handling input prompts and continuation\n    QTextCursor lastPromptCursor;\n    bool isContinuationPrompt = false;\n    int originalPromptEnd = 0;\n    \n    void elideContinuationPrompt(void);\n    QString fullInputString(void);\n    \n    virtual void scriptStringAndSelection(QString &scriptString, int &position, int &length, int &offset) override;\n    \n    // handling the command history\n    QStringList history;\n    int historyIndex = 0;\n    bool lastHistoryItemIsProvisional = false;\t// got added to the history by a moveUp: event but is not an executed command\n    \n    // handling read-only status\n    bool roDTS = false;\n    bool roDTA = false;\n    \n    // handling the selection and editability\n    bool insideMouseTracking = false, sawSelectionChange = false;\n    \n    virtual void mousePressEvent(QMouseEvent *p_event) override;\n    virtual void mouseReleaseEvent(QMouseEvent *p_event) override;\n    void handleSelectionChanged(void);\n    virtual void dragMoveEvent(QDragMoveEvent *p_event) override;\n    \nsignals:\n    void selectionWasChangedDuringLastEvent(void);\n};\n\n\n#endif // QTSLIMCONSOLETEXTEDIT_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMDebugOutputWindow.cpp",
    "content": "//\n//  QtSLiMDebugOutputWindow.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 02/06/2021.\n//  Copyright (c) 2021-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMDebugOutputWindow.h\"\n#include \"ui_QtSLiMDebugOutputWindow.h\"\n\n#include <QSettings>\n#include <QMenu>\n#include <QAction>\n#include <QTableWidget>\n#include <QTableWidgetItem>\n#include <QClipboard>\n#include <QGuiApplication>\n#include <QDebug>\n\n#include <utility>\n#include <string>\n#include <vector>\n#include <limits>\n\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMExtras.h\"\n\n#include \"log_file.h\"\n\n\n//\n//  QtSLiMDebugOutputWindow\n//\n\nQtSLiMDebugOutputWindow::QtSLiMDebugOutputWindow(QtSLiMWindow *p_parent) :\n    QWidget(p_parent, Qt::Window),    // the console window has us as a parent, but is still a standalone window\n    parentSLiMWindow(p_parent),\n    ui(new Ui::QtSLiMDebugOutputWindow)\n{\n    ui->setupUi(this);\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMDebugOutputWindow\");\n    resize(settings.value(\"size\", QSize(400, 300)).toSize());\n    move(settings.value(\"pos\", QPoint(25, 445)).toPoint());\n    settings.endGroup();\n    \n    // set up the tab bar; annoyingly, this cannot be configured in Designer at all!\n    ui->tabBar->setAcceptDrops(false);\n    ui->tabBar->setDocumentMode(false);\n    ui->tabBar->setDrawBase(false);\n    ui->tabBar->setExpanding(false);\n    ui->tabBar->setMovable(false);\n    ui->tabBar->setShape(QTabBar::RoundedNorth);\n    ui->tabBar->setTabsClosable(false);\n    ui->tabBar->setUsesScrollButtons(false);\n    ui->tabBar->setIconSize(QSize(15, 15));\n    \n    ui->tabBar->addTab(\"Debug Output\");\n    ui->tabBar->setTabToolTip(0, \"Debug Output\");\n    ui->tabBar->addTab(\"Run Output\");\n    ui->tabBar->setTabToolTip(1, \"Run Output\");\n    ui->tabBar->addTab(\"Scheduling\");\n    ui->tabBar->setTabToolTip(2, \"Scheduling\");\n    resetTabIcons();\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, [this]() { resetTabIcons(); }); // adjust to dark mode change\n    \n    connect(ui->tabBar, &QTabBar::currentChanged, this, &QtSLiMDebugOutputWindow::selectedTabChanged);\n    \n    // glue UI; no separate file since this is very simple\n    connect(ui->clearOutputButton, &QPushButton::clicked, this, &QtSLiMDebugOutputWindow::clearOutputClicked);\n    ui->clearOutputButton->qtslimSetBaseName(\"delete\");\n    connect(ui->clearOutputButton, &QPushButton::pressed, this, &QtSLiMDebugOutputWindow::clearOutputPressed);\n    connect(ui->clearOutputButton, &QPushButton::released, this, &QtSLiMDebugOutputWindow::clearOutputReleased);\n    \n    // fix the layout of the window\n    ui->outputHeaderLayout->setSpacing(4);\n    ui->outputHeaderLayout->setContentsMargins(0, 0, 0, 0);\n    \n    // QtSLiMTextEdit attributes\n    ui->debugOutputTextEdit->setOptionClickEnabled(false);\n    ui->debugOutputTextEdit->setCodeCompletionEnabled(false);\n    ui->debugOutputTextEdit->setScriptType(QtSLiMTextEdit::NoScriptType);\n    ui->debugOutputTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::OutputHighlighting);\n    ui->debugOutputTextEdit->setReadOnly(true);\n    \n    ui->runOutputTextEdit->setOptionClickEnabled(false);\n    ui->runOutputTextEdit->setCodeCompletionEnabled(false);\n    ui->runOutputTextEdit->setScriptType(QtSLiMTextEdit::NoScriptType);\n    ui->runOutputTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::OutputHighlighting);\n    ui->runOutputTextEdit->setReadOnly(true);\n    \n    ui->schedulingOutputTextEdit->setOptionClickEnabled(false);\n    ui->schedulingOutputTextEdit->setCodeCompletionEnabled(false);\n    ui->schedulingOutputTextEdit->setScriptType(QtSLiMTextEdit::NoScriptType);\n    ui->schedulingOutputTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::OutputHighlighting);\n    ui->schedulingOutputTextEdit->setReadOnly(true);\n    \n    showDebugOutput();\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nQtSLiMDebugOutputWindow::~QtSLiMDebugOutputWindow()\n{\n    delete ui;\n}\n\nvoid QtSLiMDebugOutputWindow::resetTabIcons(void)\n{\n    // No icons for now, see how it goes\n    /*\n    QIcon debugTabIcon(QtSLiMImagePath(\"debug\", false));\n    \n    ui->tabBar->setTabIcon(0, debugTabIcon);\n    ui->tabBar->setTabIcon(1, qtSLiMAppDelegate->applicationIcon());\n    */\n}\n\nvoid QtSLiMDebugOutputWindow::hideAllViews(void)\n{\n    ui->debugOutputTextEdit->setVisible(false);\n    ui->runOutputTextEdit->setVisible(false);\n    ui->schedulingOutputTextEdit->setVisible(false);\n    \n    for (QTableWidget *logtable : logfileViews)\n        logtable->setVisible(false);\n    \n    for (QtSLiMTextEdit *fileview : fileViews)\n        fileview->setVisible(false);\n}\n\nvoid QtSLiMDebugOutputWindow::showDebugOutput()\n{\n    hideAllViews();\n    ui->debugOutputTextEdit->setVisible(true);\n}\n\nvoid QtSLiMDebugOutputWindow::showRunOutput()\n{\n    hideAllViews();\n    ui->runOutputTextEdit->setVisible(true);\n}\n\nvoid QtSLiMDebugOutputWindow::showSchedulingOutput()\n{\n    hideAllViews();\n    ui->schedulingOutputTextEdit->setVisible(true);\n}\n\nvoid QtSLiMDebugOutputWindow::showLogFile(int logFileIndex)\n{\n    QTableWidget *table = logfileViews[logFileIndex];\n    \n    hideAllViews();\n    table->setVisible(true);\n}\n\nvoid QtSLiMDebugOutputWindow::showFile(int fileIndex)\n{\n    QtSLiMTextEdit *fileview = fileViews[fileIndex];\n    \n    hideAllViews();\n    fileview->setVisible(true);\n}\n\nvoid QtSLiMDebugOutputWindow::tabReceivedInput(int tabIndex)\n{\n    // set the tab's text color to red when new input is received, if it is not the current tab\n    // the color depends on dark mode; FIXME we should fix it on dark mode change but we don't\n    if (tabIndex != ui->tabBar->currentIndex())\n    {\n        QColor color = (QtSLiMInDarkMode() ? QColor(255, 128, 128, 255) : QColor(192, 0, 0, 255));\n        \n        ui->tabBar->setTabTextColor(tabIndex, color);\n    }\n}\n\nvoid QtSLiMDebugOutputWindow::takeDebugOutput(QString str)\n{\n    ui->debugOutputTextEdit->moveCursor(QTextCursor::End);\n    ui->debugOutputTextEdit->insertPlainText(str);\n    ui->debugOutputTextEdit->moveCursor(QTextCursor::End);\n    \n    tabReceivedInput(0);\n}\n\nvoid QtSLiMDebugOutputWindow::takeRunOutput(QString str)\n{\n    ui->runOutputTextEdit->moveCursor(QTextCursor::End);\n    ui->runOutputTextEdit->insertPlainText(str);\n    ui->runOutputTextEdit->moveCursor(QTextCursor::End);\n    \n    tabReceivedInput(1);\n}\n\nvoid QtSLiMDebugOutputWindow::takeSchedulingOutput(QString str)\n{\n    ui->schedulingOutputTextEdit->moveCursor(QTextCursor::End);\n    ui->schedulingOutputTextEdit->insertPlainText(str);\n    ui->schedulingOutputTextEdit->moveCursor(QTextCursor::End);\n    \n    tabReceivedInput(2);\n}\n\nQTableWidget *QtSLiMDebugOutputWindow::logFileTableForPath(const std::string &path)\n{\n    auto pathIter = std::find(logfilePaths.begin(), logfilePaths.end(), path);\n    QTableWidget *table = nullptr;\n    \n    if (pathIter != logfilePaths.end())\n    {\n        size_t tableIndex = std::distance(logfilePaths.begin(), pathIter);\n        \n        table = logfileViews[tableIndex];\n    }\n    \n    return table;\n}\n\nvoid QtSLiMDebugOutputWindow::takeLogFileOutput(std::vector<std::string> &lineElements, const std::string &path)\n{\n    // First, find the index of the log file view we're taking input into\n    // If we didn't find one, make a new one\n    auto pathIter = std::find(logfilePaths.begin(), logfilePaths.end(), path);\n    QTableWidget *table;\n    size_t tableIndex;\n    \n    if (pathIter != logfilePaths.end())\n    {\n        tableIndex = std::distance(logfilePaths.begin(), pathIter);\n        table = logfileViews[tableIndex];\n    }\n    else\n    {\n        QLayout *windowLayout = this->layout();\n        \n        table = new QTableWidget();\n        table->setSortingEnabled(false);\n        table->setAlternatingRowColors(true);\n        table->setDragEnabled(false);\n        table->setAcceptDrops(false);\n        table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);\n        table->setSelectionMode(QAbstractItemView::NoSelection);\n        table->horizontalHeader()->setResizeContentsPrecision(100);     // look at the first 100 rows to determine sizing\n        table->horizontalHeader()->setMinimumSectionSize(100);          // wide enough to fit most floating-point output\n        table->horizontalHeader()->setMaximumSectionSize(400);          // don't let super-wide output push the table width too far\n        table->horizontalHeader()->setSectionsClickable(false);\n        table->setVisible(false);\n        windowLayout->addWidget(table);\n        \n        // Get right-clicks on table widget headers and items, to run our context menu\n        table->setContextMenuPolicy(Qt::CustomContextMenu);\n        connect(table, &QTableWidget::customContextMenuRequested, this, &QtSLiMDebugOutputWindow::logFileRightClick);\n        table->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);\n        connect(table->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &QtSLiMDebugOutputWindow::logFileRightClick);\n        \n        // Make a new tab and insert it at the correct position in the tab bar\n        QString filename = QString::fromStdString(Eidos_LastPathComponent(path));\n        \n        tableIndex = logfilePaths.size();\n        ui->tabBar->insertTab(tableIndex + 3, filename);\n        ui->tabBar->setTabToolTip(tableIndex + 3, filename);\n        \n        // Add the new view's info\n        logfilePaths.emplace_back(path);\n        logfileViews.emplace_back(table);\n        logfileLineNumbers.emplace_back(-1);\n    }\n    \n    // Then create a new QTableWidgetItem for each item in the row\n    // If this is the first row we have taken, then it's the header row\n    bool firstTime = !table->horizontalHeaderItem(0);\n    \n    if (firstTime)\n    {\n        int col = 0;\n        \n        table->setColumnCount(lineElements.size());\n        \n        for (const std::string &str : lineElements)\n        {\n            QString qstr = QString::fromStdString(str);\n            QTableWidgetItem *colItem = new QTableWidgetItem(qstr);\n            colItem->setFlags(Qt::ItemIsEnabled);\n            \n            QFont itemFont = colItem->font();\n            itemFont.setBold(true);\n            colItem->setFont(itemFont);\n            \n            table->setHorizontalHeaderItem(col, colItem);\n            col++;\n        }\n    }\n    else\n    {\n        int rowIndex = table->rowCount();\n        int lineNumber = logfileLineNumbers[tableIndex] + 1;\n        int col = 0;\n        \n        table->setRowCount(rowIndex + 1);\n        \n        QTableWidgetItem *rowItem = new QTableWidgetItem(QString(\"%1\").arg(lineNumber));\n        rowItem->setFlags(Qt::NoItemFlags);\n        rowItem->setTextAlignment(Qt::AlignRight);\n        rowItem->setForeground(Qt::darkGray);\n        table->setVerticalHeaderItem(rowIndex, rowItem);\n        \n        logfileLineNumbers[tableIndex] = lineNumber;\n        \n        for (const std::string &str : lineElements)\n        {\n            QString qstr = QString::fromStdString(str);\n            QTableWidgetItem *item = new QTableWidgetItem(qstr);\n            item->setFlags(Qt::ItemIsEnabled);\n            item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);\n            table->setItem(rowIndex, col, item);\n            col++;\n        }\n        \n        table->scrollToBottom();\n    }\n    \n    // adjust to fit the headers and the initial rows; this is probably rather expensive,\n    // but LogFile usually only fires once per tick or less, so hopefully not a big deal\n    table->resizeColumnsToContents();\n    \n    tabReceivedInput(tableIndex + 3);\n}\n\nvoid QtSLiMDebugOutputWindow::logFileRightClick(const QPoint &pos)\n{\n    for (QTableWidget *table : logfileViews)\n    {\n        if (table->isVisible())\n        {\n            // found the visible/active table\n            int clickedColumnIndex = table->horizontalHeader()->logicalIndexAt(pos);\n            \n            if (clickedColumnIndex != -1)\n            {\n                int rowCount = table->rowCount();\n                int columnCount = table->columnCount();\n                \n                if ((rowCount > 0) && (columnCount > 0))\n                {\n                    std::vector<uint8_t> columnIsNumeric;        // were any conversion errors to double detected?\n                    \n                    for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex)\n                    {\n                        columnIsNumeric.push_back(true);\n                        \n                        for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                        {\n                            QTableWidgetItem *item = table->item(rowIndex, columnIndex);\n                            \n                            if (item)\n                            {\n                                QString itemText = item->text();\n                                \n                                if ((itemText == \"NAN\") || (itemText == \"INF\") || (itemText == \"-INF\"))\n                                {\n                                    // NAN / INF / -INF are acceptable as double values, although\n                                    // whatever parser the data ends up in might not like it...\n                                }\n                                else\n                                {\n                                    bool ok;\n                                    \n                                    itemText.toDouble(&ok);\n                                    if (!ok)\n                                    {\n                                        columnIsNumeric.back() = false;\n                                        break;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    \n                    // make a context menu\n                    QMenu contextMenu(\"logfile_menu\", this);\n                    QString columnName = table->horizontalHeaderItem(clickedColumnIndex)->text();\n                    \n                    QString copyDataTitle(\"Copy Data for \");\n                    copyDataTitle.append(columnName);\n                    QAction *copyDataAction = contextMenu.addAction(copyDataTitle);\n                    copyDataAction->setEnabled(true);\n                    \n                    QString graphData1DTitle(\"Graph \");\n                    graphData1DTitle.append(columnName);\n                    QAction *graphData1DAction = contextMenu.addAction(graphData1DTitle);\n                    graphData1DAction->setEnabled(columnIsNumeric[clickedColumnIndex]);\n                    \n                    if (columnIsNumeric[clickedColumnIndex])\n                    {\n                        // if the clicked column is numeric, we can potentially plot it as the\n                        // dependent variable with a different column as the independent variable\n                        bool has2DGraphActions = false;\n                        \n                        for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex)\n                        {\n                            if ((columnIndex != clickedColumnIndex) && (columnIsNumeric[columnIndex]))\n                            {\n                                if (!has2DGraphActions)\n                                {\n                                    contextMenu.addSeparator();\n                                    \n                                    {\n                                        QString graphData2DTitle(\"Graph \");\n                                        graphData2DTitle.append(columnName);\n                                        graphData2DTitle.append(\" ~ \");\n                                        graphData2DTitle.append(table->horizontalHeaderItem(columnIndex)->text());\n                                        graphData2DTitle.append(\" (line plot)\");\n                                        QAction *graphData2DAction = contextMenu.addAction(graphData2DTitle);\n                                        graphData2DAction->setEnabled(true);\n                                        graphData2DAction->setData(columnIndex);\n                                    }\n                                    {\n                                        QString graphData2DTitle(\"Graph \");\n                                        graphData2DTitle.append(columnName);\n                                        graphData2DTitle.append(\" ~ \");\n                                        graphData2DTitle.append(table->horizontalHeaderItem(columnIndex)->text());\n                                        graphData2DTitle.append(\" (scatter plot)\");\n                                        QAction *graphData2DAction = contextMenu.addAction(graphData2DTitle);\n                                        graphData2DAction->setEnabled(true);\n                                        graphData2DAction->setData(columnIndex + 10000);    // 10000 is \"scatter plot\"\n                                    }\n                                    \n                                    has2DGraphActions = true;\n                                }\n                            }\n                        }\n                    }\n                    \n                    // could also add items for, e.g., Graph Data for FST ~ cycle\n                    // just need to vet all columns to determine which are double/integer\n                    \n                    // run the context menu synchronously\n                    QPoint globalPoint = table->mapToGlobal(pos);\n                    QAction *action = contextMenu.exec(globalPoint);\n                    \n                    if (action == copyDataAction)\n                    {\n                        QString string(\"# LogFile data: \");\n                        \n                        string.append(columnName);\n                        string.append(\"\\n\");\n                        string.append(slimDateline());\n                        string.append(\"\\n\\n\");\n                        \n                        if (columnIsNumeric[clickedColumnIndex])\n                        {\n                            // if the values are all double, we can just dump\n                            // the value strings unquoted, as numeric data\n                            for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                            {\n                                QTableWidgetItem *item = table->item(rowIndex, clickedColumnIndex);\n                                \n                                if (rowIndex > 0)\n                                    string.append(QString(\", \"));\n                                string.append(item->text());\n                            }\n                        }\n                        else\n                        {\n                            // otherwise, we dump the value strings quoted\n                            // FIXME should worry about quoting issues here\n                            for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                            {\n                                QTableWidgetItem *item = table->item(rowIndex, clickedColumnIndex);\n                                \n                                if (rowIndex > 0)\n                                    string.append(QString(\", \\\"\"));\n                                else\n                                    string.append(\"\\\"\");\n                                \n                                string.append(item->text());\n                                string.append(\"\\\"\");\n                            }\n                        }\n                        \n                        QClipboard *clipboard = QGuiApplication::clipboard();\n                        clipboard->setText(string);\n                    }\n                    else if (action == graphData1DAction)\n                    {\n                        // all values are convertible to double; guaranteed above\n                        double *y_values = (double *)malloc(rowCount * sizeof(double));\n                        \n                        for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                        {\n                            QTableWidgetItem *item = table->item(rowIndex, clickedColumnIndex);\n                            QString text = item->text();\n                            double value;\n                            \n                            if (text == \"NAN\")\n                                value = std::numeric_limits<double>::quiet_NaN();\n                            else if (text == \"INF\")\n                                value = std::numeric_limits<double>::infinity();\n                            else if (text == \"-INF\")\n                                value = -std::numeric_limits<double>::infinity();\n                            else\n                                value = text.toDouble();\n                            \n                            y_values[rowIndex] = value;\n                        }\n                        \n                        parentSLiMWindow->plotLogFileData_1D(columnName, columnName, y_values, rowCount);\n                    }\n                    else if (action)    // graphData2DAction\n                    {\n                        // all values are convertible to double; guaranteed above\n                        QVariant actiondata = action->data();\n                        int xColumnIndex = actiondata.toInt();\n                        bool makeScatterPlot = false;\n                        \n                        if (xColumnIndex >= 10000)\n                        {\n                            xColumnIndex -= 10000;\n                            makeScatterPlot = true;\n                        }\n                        \n                        QString xColumnName = table->horizontalHeaderItem(xColumnIndex)->text();\n                        \n                        double *x_values = (double *)malloc(rowCount * sizeof(double));\n                        double *y_values = (double *)malloc(rowCount * sizeof(double));\n                        \n                        for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                        {\n                            QTableWidgetItem *x_item = table->item(rowIndex, xColumnIndex);\n                            QTableWidgetItem *y_item = table->item(rowIndex, clickedColumnIndex);\n                            QString x_text = x_item->text();\n                            QString y_text = y_item->text();\n                            double x_value, y_value;\n                            \n                            if (x_text == \"NAN\")\n                                x_value = std::numeric_limits<double>::quiet_NaN();\n                            else if (x_text == \"INF\")\n                                x_value = std::numeric_limits<double>::infinity();\n                            else if (x_text == \"-INF\")\n                                x_value = -std::numeric_limits<double>::infinity();\n                            else\n                                x_value = x_text.toDouble();\n                            \n                            if (y_text == \"NAN\")\n                                y_value = std::numeric_limits<double>::quiet_NaN();\n                            else if (y_text == \"INF\")\n                                y_value = std::numeric_limits<double>::infinity();\n                            else if (y_text == \"-INF\")\n                                y_value = -std::numeric_limits<double>::infinity();\n                            else\n                                y_value = y_text.toDouble();\n                            \n                            x_values[rowIndex] = x_value;\n                            y_values[rowIndex] = y_value;\n                        }\n                        \n                        QString title = QString(\"%1 ~ %2\").arg(columnName).arg(xColumnName);\n                        \n                        parentSLiMWindow->plotLogFileData_2D(title, xColumnName, columnName, x_values, y_values, rowCount, makeScatterPlot);\n                    }\n                }\n            }\n        }\n    }\n}\n\nEidosValue_SP QtSLiMDebugOutputWindow::dataForColumn(LogFile *logFile, int64_t columnIndex)\n{\n    const std::string &logfile_path = logFile->UserFilePath();\n    QTableWidget *table = logFileTableForPath(logfile_path);\n    \n    if (table)\n    {\n        int rowCount = table->rowCount();\n        int columnCount = table->columnCount();\n        \n        if ((rowCount > 0) && (columnCount > 0) && (columnIndex < columnCount))\n        {\n            bool columnIsNumeric = true;        // were any conversion errors to double detected?\n            \n            for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n            {\n                QTableWidgetItem *item = table->item(rowIndex, columnIndex);\n                \n                if (item)\n                {\n                    QString itemText = item->text();\n                    \n                    if ((itemText == \"NAN\") || (itemText == \"INF\") || (itemText == \"-INF\"))\n                    {\n                        // NAN / INF / -INF are acceptable as double values, although\n                        // whatever parser the data ends up in might not like it...\n                    }\n                    else\n                    {\n                        bool ok;\n                        \n                        itemText.toDouble(&ok);\n                        if (!ok)\n                        {\n                            columnIsNumeric = false;\n                            break;\n                        }\n                    }\n                }\n            }\n            \n            if (columnIsNumeric)\n            {\n                EidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(rowCount);\n                \n                for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                {\n                    QTableWidgetItem *item = table->item(rowIndex, columnIndex);\n                    QString text = item->text();\n                    double value;\n                    \n                    if (text == \"NAN\")\n                        value = std::numeric_limits<double>::quiet_NaN();\n                    else if (text == \"INF\")\n                        value = std::numeric_limits<double>::infinity();\n                    else if (text == \"-INF\")\n                        value = -std::numeric_limits<double>::infinity();\n                    else\n                        value = text.toDouble();\n                    \n                    float_result->set_float_no_check(value, rowIndex);\n                }\n                \n                return EidosValue_SP(float_result);\n            }\n            else\n            {\n                EidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(rowCount);\n                \n                for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n                {\n                    QTableWidgetItem *item = table->item(rowIndex, columnIndex);\n                    QString text = item->text();\n                    \n                    string_result->PushString(text.toStdString());\n                }\n                \n                return EidosValue_SP(string_result);\n            }\n        }\n    }\n    \n    return gStaticEidosValueNULL;\n}\n\nEidosValue_SP QtSLiMDebugOutputWindow::dataForColumn(LogFile *logFile, const std::string &columnName)\n{\n    std::vector<std::string> columnNames = logFile->SortedKeys_StringKeys();\n    auto columnIter = std::find(columnNames.begin(), columnNames.end(), columnName);\n    \n    if (columnIter != columnNames.end())\n        return dataForColumn(logFile, std::distance(columnNames.begin(), columnIter));\n    \n    return gStaticEidosValueNULL;\n}\n\nvoid QtSLiMDebugOutputWindow::takeFileOutput(std::vector<std::string> &lines, bool append, const std::string &path)\n{\n    // First, find the index of the file view we're taking input into\n    // If we didn't find one, make a new one\n    auto pathIter = std::find(filePaths.begin(), filePaths.end(), path);\n    QtSLiMTextEdit *fileview;\n    size_t fileIndex;\n    \n    if (pathIter != filePaths.end())\n    {\n        fileIndex = std::distance(filePaths.begin(), pathIter);\n        fileview = fileViews[fileIndex];\n    }\n    else\n    {\n        QLayout *windowLayout = this->layout();\n        \n        fileview = new QtSLiMTextEdit();\n        fileview->setUndoRedoEnabled(false);\n        fileview->setOptionClickEnabled(false);\n        fileview->setCodeCompletionEnabled(false);\n        fileview->setScriptType(QtSLiMTextEdit::NoScriptType);\n        fileview->setSyntaxHighlightType(QtSLiMTextEdit::NoHighlighting);\n        fileview->setReadOnly(true);\n        fileview->setVisible(false);\n        windowLayout->addWidget(fileview);\n        \n        // Make a new tab and add it at the end of the tab bar\n        QString filename = QString::fromStdString(Eidos_LastPathComponent(path));\n        \n        fileIndex = filePaths.size();\n        ui->tabBar->insertTab(ui->tabBar->count(), filename);\n        ui->tabBar->setTabToolTip(ui->tabBar->count() - 1, filename);\n        \n        // Add the new view's info\n        filePaths.emplace_back(path);\n        fileViews.emplace_back(fileview);\n    }\n    \n    // Then append the new text to the view, as with the built in textviews\n    if (!append)\n        fileview->setPlainText(\"\");\n    \n    fileview->moveCursor(QTextCursor::End);\n    \n    bool hasPrecedingLines = (fileview->textCursor().position() != 0);\n    \n    for (const std::string &str : lines)\n    {\n        if (hasPrecedingLines)\n            fileview->insertPlainText(\"\\n\");\n        fileview->insertPlainText(QString::fromStdString(str));\n        hasPrecedingLines = true;\n    }\n    \n    fileview->moveCursor(QTextCursor::End);\n    \n    tabReceivedInput(fileIndex + 3 + logfilePaths.size());\n}\n\nvoid QtSLiMDebugOutputWindow::clearAllOutput(void)\n{\n    ui->debugOutputTextEdit->setPlainText(\"\");\n    ui->runOutputTextEdit->setPlainText(\"\");\n    ui->schedulingOutputTextEdit->setPlainText(\"\");\n    \n    // Remove all tabs but the base three completely; they may not exist again after recycling\n    while (ui->tabBar->count() > 3)\n        ui->tabBar->removeTab(3);\n    \n    // Reset the base three tabs to the default text color\n    ui->tabBar->setTabTextColor(0, ui->tabBar->tabTextColor(-1));\n    ui->tabBar->setTabTextColor(1, ui->tabBar->tabTextColor(-1));\n    ui->tabBar->setTabTextColor(2, ui->tabBar->tabTextColor(-1));\n    \n    logfilePaths.clear();\n    logfileViews.clear();\n    logfileLineNumbers.clear();\n    filePaths.clear();\n    fileViews.clear();\n}\n\nvoid QtSLiMDebugOutputWindow::clearOutputClicked(void)\n{\n    if (ui->debugOutputTextEdit->isVisible())\n        ui->debugOutputTextEdit->setPlainText(\"\");\n    \n    if (ui->runOutputTextEdit->isVisible())\n        ui->runOutputTextEdit->setPlainText(\"\");\n    \n    if (ui->schedulingOutputTextEdit->isVisible())\n        ui->schedulingOutputTextEdit->setPlainText(\"\");\n    \n    for (QTableWidget *table : logfileViews)\n        if (table->isVisible())\n            table->setRowCount(0);\n    \n    for (QtSLiMTextEdit *file : fileViews)\n        if (file->isVisible())\n            file->setPlainText(\"\");\n}\n\nvoid QtSLiMDebugOutputWindow::selectedTabChanged(void)\n{\n    int tabIndex = ui->tabBar->currentIndex();\n    \n    ui->tabBar->setTabTextColor(tabIndex, ui->tabBar->tabTextColor(-1));  // set to an invalid color to clear to the default color\n    \n    if (tabIndex == 0)\n    {\n        showDebugOutput();\n        return;\n    }\n    else if (tabIndex == 1)\n    {\n        showRunOutput();\n        return;\n    }\n    else if (tabIndex == 2)\n    {\n        showSchedulingOutput();\n        return;\n    }\n    else\n    {\n        tabIndex -= 3;                      // zero-base the index for logfilePaths\n        \n        if ((tabIndex >= 0) && (tabIndex < (int)logfilePaths.size()))\n        {\n            showLogFile(tabIndex);\n            return;\n        }\n        \n        tabIndex -= logfilePaths.size();    // zero-base the index for filePaths\n        \n        if ((tabIndex >= 0) && (tabIndex < (int)fileViews.size()))\n        {\n            showFile(tabIndex);\n            return;\n        }\n        \n        qDebug() << \"unexpected current tab index\" << ui->tabBar->currentIndex() << \"in selectedTabChanged()\";\n    }\n}\n\nvoid QtSLiMDebugOutputWindow::clearOutputPressed(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(true);\n}\n\nvoid QtSLiMDebugOutputWindow::clearOutputReleased(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(false);\n}\n\nvoid QtSLiMDebugOutputWindow::closeEvent(QCloseEvent *p_event)\n{\n    // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMDebugOutputWindow\");\n    settings.setValue(\"size\", size());\n    settings.setValue(\"pos\", pos());\n    settings.endGroup();\n    \n    // send our close signal\n    emit willClose();\n    \n    // use super's default behavior\n    QWidget::closeEvent(p_event);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMDebugOutputWindow.h",
    "content": "//\n//  QtSLiMDebugOutputWindow.h\n//  SLiM\n//\n//  Created by Ben Haller on 02/06/2021.\n//  Copyright (c) 2021-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMDEBUGOUTPUTWINDOW_H\n#define QTSLIMDEBUGOUTPUTWINDOW_H\n\n#include <QWidget>\n\n#include <vector>\n#include <string>\n\n#include \"eidos_globals.h\"\n\n\nclass QCloseEvent;\nclass QtSLiMWindow;\nclass QtSLiMTextEdit;\nclass QTableWidget;\nclass QTableWidgetItem;\nclass LogFile;\n\n\nnamespace Ui {\nclass QtSLiMDebugOutputWindow;\n}\n\nclass QtSLiMDebugOutputWindow : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMWindow *parentSLiMWindow = nullptr;     // a copy of parent with the correct class, for convenience\n    \n    explicit QtSLiMDebugOutputWindow(QtSLiMWindow *p_parent = nullptr);\n    virtual ~QtSLiMDebugOutputWindow() override;\n    \n    // Our various output views, which each collect output independently\n    void takeDebugOutput(QString str);\n    void takeRunOutput(QString str);\n    void takeSchedulingOutput(QString str);\n    void takeLogFileOutput(std::vector<std::string> &lineElements, const std::string &path);\n    void takeFileOutput(std::vector<std::string> &lines, bool append, const std::string &path);\n    \n    EidosValue_SP dataForColumn(LogFile *logFile, int64_t columnIndex);\n    EidosValue_SP dataForColumn(LogFile *logFile, const std::string &columnName);\n    \npublic slots:\n    void clearAllOutput(void);\n    void clearOutputClicked(void);\n    \n    void showDebugOutput(void);\n    void showRunOutput(void);\n    void showSchedulingOutput(void);\n    void showLogFile(int logFileIndex);\n    void showFile(int fileIndex);\n    \nsignals:\n    void willClose(void);\n    \nprivate slots:\n    void tabReceivedInput(int tabIndex);\n    void selectedTabChanged(void);\n    virtual void closeEvent(QCloseEvent *p_event) override;\n    void clearOutputPressed(void);\n    void clearOutputReleased(void);\n    void logFileRightClick(const QPoint &pos);\n    \nprivate:\n    Ui::QtSLiMDebugOutputWindow *ui;\n    \n    // all the LogFile paths we have seen, views containing their output, and the last line number emitted\n    std::vector<std::string> logfilePaths;\n    std::vector<QTableWidget *> logfileViews;\n    std::vector<size_t> logfileLineNumbers;\n    \n    QTableWidget *logFileTableForPath(const std::string &path);\n    \n    // all the ordinary file paths we have seen, from writeFile() and similar, and output views\n    std::vector<std::string> filePaths;\n    std::vector<QtSLiMTextEdit *> fileViews;\n    \n    void resetTabIcons(void);\n    void hideAllViews(void);\n};\n\n\n#endif // QTSLIMDEBUGOUTPUTWINDOW_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMDebugOutputWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMDebugOutputWindow</class>\n <widget class=\"QWidget\" name=\"QtSLiMDebugOutputWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>700</width>\n    <height>500</height>\n   </rect>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>700</width>\n    <height>250</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Output Viewer</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>3</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>3</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>3</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>3</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>3</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"outputHeaderLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QtSLiMPushButton\" name=\"clearOutputButton\">\n       <property name=\"minimumSize\">\n        <size>\n         <width>20</width>\n         <height>20</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>20</width>\n         <height>20</height>\n        </size>\n       </property>\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"toolTip\">\n        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;clear the selected output log&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"buttons.qrc\">\n         <normaloff>:/buttons/delete.png</normaloff>\n         <normalon>:/buttons/delete_H.png</normalon>:/buttons/delete.png</iconset>\n       </property>\n       <property name=\"iconSize\">\n        <size>\n         <width>20</width>\n         <height>20</height>\n        </size>\n       </property>\n       <property name=\"flat\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QTabBar\" name=\"tabBar\" native=\"true\"/>\n     </item>\n     <item>\n      <spacer name=\"horizontalSpacer_3\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>10</width>\n         <height>10</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <widget class=\"QtSLiMTextEdit\" name=\"debugOutputTextEdit\">\n     <property name=\"undoRedoEnabled\">\n      <bool>false</bool>\n     </property>\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QtSLiMTextEdit\" name=\"runOutputTextEdit\">\n     <property name=\"undoRedoEnabled\">\n      <bool>false</bool>\n     </property>\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QtSLiMTextEdit\" name=\"schedulingOutputTextEdit\">\n     <property name=\"undoRedoEnabled\">\n      <bool>false</bool>\n     </property>\n     <property name=\"readOnly\">\n      <bool>true</bool>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMPushButton</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMTextEdit</class>\n   <extends>QPlainTextEdit</extends>\n   <header>QtSLiMScriptTextEdit.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QTabBar</class>\n   <extends>QWidget</extends>\n   <header>QTabBar.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"buttons.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosConsole.cpp",
    "content": "//\n//  QtSLiMEidosConsole.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMEidosConsole.h\"\n#include \"ui_QtSLiMEidosConsole.h\"\n\n#include <QStatusBar>\n#include <QSettings>\n#include <QSplitter>\n#include <QDebug>\n\n#include <utility>\n#include <string>\n\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMVariableBrowser.h\"\n#include \"QtSLiMExtras.h\"\n\n\nQtSLiMEidosConsole::QtSLiMEidosConsole(QtSLiMWindow *p_parent) :\n    QWidget(p_parent, Qt::Window),    // the console window has us as a parent, but is still a standalone window\n    parentSLiMWindow(p_parent),\n    ui(new Ui::QtSLiMEidosConsole)\n{\n    ui->setupUi(this);\n    interpolateSplitters();\n    glueUI();\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // add a status bar at the bottom; there is a layout in Designer for it already\n    // thanks to https://stackoverflow.com/a/6143818/2752221\n    statusBar_ = new QtSLiMStatusBar(this);\n    ui->statusBarLayout->addWidget(statusBar_);\n    statusBar_->setMaximumHeight(statusBar_->sizeHint().height());\n    \n    // set up the script view to syntax highlight\n    ui->scriptTextEdit->setScriptType(QtSLiMTextEdit::EidosScriptType);\n    ui->scriptTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::ScriptHighlighting);\n    \n    // set up the console view to be Eidos script, but without highlighting\n    ui->consoleTextEdit->setScriptType(QtSLiMTextEdit::EidosScriptType);\n    ui->consoleTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::NoHighlighting);\n    \n    // enable option-click in both textedits\n    ui->scriptTextEdit->setOptionClickEnabled(true);\n    ui->consoleTextEdit->setOptionClickEnabled(true);\n    \n    // enable code completion in both textedits\n    ui->scriptTextEdit->setCodeCompletionEnabled(true);\n    ui->consoleTextEdit->setCodeCompletionEnabled(true);\n    \n    // set initial text in console and show the initial prompt\n    QtSLiMConsoleTextEdit *console = ui->consoleTextEdit;\n    console->showWelcome();\n    console->showPrompt();\n    console->setFocus();\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMEidosConsole\");\n    resize(settings.value(\"size\", QSize(550, 400)).toSize());\n    move(settings.value(\"pos\", QPoint(25, 45)).toPoint());\n    settings.endGroup();\n    \n    // Enable our UI initially\n    setInterfaceEnabled(true);\n    \n    // Execute a null statement to get our symbols set up, for code completion etc.\n\t// Note this has the side effect of creating a random number generator gEidos_RNG for our use.\n\tvalidateSymbolTableAndFunctionMap();\n}\n\nQtSLiMEidosConsole::~QtSLiMEidosConsole()\n{\n    delete ui;\n    \n    delete global_symbols;\n    global_symbols = nullptr;\n    \n    if (global_function_map_owned)\n        delete global_function_map;\n    global_function_map = nullptr;\n}\n\nvoid QtSLiMEidosConsole::interpolateSplitters(void)\n{\n#if 1\n    // add a top-level horizontal splitter\n    \n    const int splitterMargin = 0;\n    QLayout *parentLayout = ui->overallLayout;\n    QVBoxLayout *firstSubLayout = ui->scriptLayout;\n    QVBoxLayout *secondSubLayout = ui->outputLayout;\n    \n    // force geometry calculation, which is lazy\n    setAttribute(Qt::WA_DontShowOnScreen, true);\n    show();\n    hide();\n    setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // get the geometry we need\n    QMargins marginsP = parentLayout->contentsMargins();\n    QMargins marginsS1 = firstSubLayout->contentsMargins();\n    QMargins marginsS2 = secondSubLayout->contentsMargins();\n    \n    // change fixed-size views to be flexible, so they cooperate with the splitter\n    ui->scriptTextEdit->setMinimumWidth(250);\n    ui->consoleTextEdit->setMinimumWidth(250);\n    \n    // empty out parentLayout\n    QLayoutItem *child;\n    while ((child = parentLayout->takeAt(0)) != nullptr);\n    \n    // make the new top-level widgets and transfer in their contents\n    scriptWidget = new QWidget(nullptr);\n    scriptWidget->setLayout(firstSubLayout);\n    firstSubLayout->setContentsMargins(QMargins(marginsS1.left() + marginsP.left(), marginsS1.top() + marginsP.top(), marginsS1.right() + splitterMargin, marginsS1.bottom() + marginsP.bottom()));\n    \n    outputWidget = new QWidget(nullptr);\n    outputWidget->setLayout(secondSubLayout);\n    secondSubLayout->setContentsMargins(QMargins(marginsS2.left() + splitterMargin, marginsS2.top() + marginsP.top(), marginsS2.right() + marginsP.right(), marginsS2.bottom() + marginsP.bottom()));\n    \n    // make the QSplitter between the left and right and add the subsidiary widgets to it\n    splitter = new QSplitter(Qt::Horizontal, this);\n    \n    splitter->setChildrenCollapsible(true);\n    splitter->addWidget(scriptWidget);\n    splitter->addWidget(outputWidget);\n    splitter->setHandleWidth(splitter->handleWidth() + 3);\n    splitter->setStretchFactor(0, 1);\n    splitter->setStretchFactor(1, 2);    // initially, give 2/3 of the width to the output widget\n    \n    // and finally, add the splitter to the parent layout\n    parentLayout->addWidget(splitter);\n    parentLayout->setContentsMargins(0, 0, 0, 0);\n#endif\n}\n\nvoid QtSLiMEidosConsole::closeEvent(QCloseEvent *p_event)\n{\n    // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMEidosConsole\");\n    settings.setValue(\"size\", size());\n    settings.setValue(\"pos\", pos());\n    settings.endGroup();\n    \n    // send our close signal\n    emit willClose();\n    \n    // use super's default behavior\n    QWidget::closeEvent(p_event);\n}\n\nvoid QtSLiMEidosConsole::showBrowserClicked(void)\n{\n    if (!variableBrowser_)\n    {\n        variableBrowser_ = new QtSLiMVariableBrowser(this);\n        \n        if (variableBrowser_)\n        {\n            variableBrowser_->setAttribute(Qt::WA_DeleteOnClose);\n            \n            // wire ourselves up to monitor the console for closing, to free\n            connect(variableBrowser_, &QtSLiMVariableBrowser::willClose, this, [this]() {\n                variableBrowser_ = nullptr;     // deleted on close\n            });\n        }\n        else\n        {\n            qDebug() << \"Could not create variable browser\";\n        }\n    }\n    \n    QtSLiMMakeWindowVisibleAndExposed(variableBrowser_);\n}\n\nQStatusBar *QtSLiMEidosConsole::statusBar(void)\n{\n    return statusBar_;\n}\n\nQtSLiMScriptTextEdit *QtSLiMEidosConsole::scriptTextEdit(void)\n{\n    return ui->scriptTextEdit;\n}\n\nQtSLiMConsoleTextEdit *QtSLiMEidosConsole::consoleTextEdit(void)\n{\n    return ui->consoleTextEdit;\n}\n\nQtSLiMVariableBrowser *QtSLiMEidosConsole::variableBrowser(void)\n{\n    return variableBrowser_;\n}\n\n// enable/disable the user interface as the simulation's state changes\nvoid QtSLiMEidosConsole::setInterfaceEnabled(bool enabled)\n{\n    ui->checkScriptButton->setEnabled(enabled);\n    ui->prettyprintButton->setEnabled(enabled);\n    ui->executeAllButton->setEnabled(enabled);\n    ui->executeSelectionButton->setEnabled(enabled);\n    ui->consoleTextEdit->setReadOnlyDueToActivation(!enabled);\n}\n\n// Throw away the current symbol table\nvoid QtSLiMEidosConsole::invalidateSymbolTableAndFunctionMap(void)\n{\n    if (global_symbols)\n\t{\n\t\tdelete global_symbols;\n\t\tglobal_symbols = nullptr;\n\t}\n\t\n\tif (global_function_map)\n\t{\n        if (global_function_map_owned)\n            delete global_function_map;\n\t\tglobal_function_map = nullptr;\n\t}\n\t\n    if (variableBrowser_)\n        variableBrowser_->reloadBrowser(false);     // false tells the browser we're now invalid\n}\n\n// Make a new symbol table from our delegate's current state; this actually executes a minimal script, \";\",\n// to produce the symbol table as a side effect of setting up for the script's execution\nvoid QtSLiMEidosConsole::validateSymbolTableAndFunctionMap(void)\n{\n    if (!global_symbols || !global_function_map)\n\t{\n\t\tQString errorString;\n\t\t\n\t\t_executeScriptString(\";\", nullptr, nullptr, nullptr, &errorString, false);\n\t\t\n\t\tif (errorString.length())\n\t\t\tqDebug() << \"Error in validateSymbolTableAndFunctionMap: \" << errorString;\n\t}\n\t\n    if (variableBrowser_)\n        variableBrowser_->reloadBrowser(true);\n}\n\n// Low-level script execution\nQString QtSLiMEidosConsole::_executeScriptString(QString scriptString, QString *tokenString, QString *parseString,\n                             QString *executionString, QString *errorString, bool semicolonOptional)\n{\n    // the back end can't handle Unicode well at present, being based on std::string...\n    scriptString.replace(QChar::ParagraphSeparator, \"\\n\");\n    scriptString.replace(QChar::LineSeparator, \"\\n\");\n    \n    std::string script_string(scriptString.toStdString());\n\tEidosScript script(script_string);\n\tstd::string output;\n\t\n\t// Unfortunately, running readFromPopulationFile() is too much of a shock for SLiMgui.  It invalidates variables that are being displayed in\n\t// the variable browser, in such an abrupt way that it causes a crash.  Basically, the code in readFromPopulationFile() that \"cleans\" all\n\t// references to mutations and such does not have any way to clean SLiMgui's references, and so those stale references cause a crash.\n\t// There is probably a better solution, but for now, we look for code containing readFromPopulationFile() and special-case it.  The user\n\t// could circumvent this and trigger a crash, so this is just a band-aid; a proper solution is needed.  Another problem with this band-aid\n\t// is that SLiMgui's display does not refresh to show the new population state.  Indeed, that is an issue with anything that changes the\n\t// visible state, such as adding new mutations.  There needs to be some way for Eidos code to tell SLiMgui that UI refreshing is needed,\n\t// and to clean references to variables that are about to invalidated.  FIXME\n\tbool safeguardReferences = false;\n\t\n    if (scriptString.contains(\"readFromPopulationFile\"))\n\t\tsafeguardReferences = true;\n\t\n\tif (safeguardReferences)\n\t\tinvalidateSymbolTableAndFunctionMap();\n\t\n\t// Make the final semicolon optional if requested; this allows input like \"6+7\" in the console\n\tif (semicolonOptional)\n\t\tscript.SetFinalSemicolonOptional(true);\n\t\n\t// Tokenize\n\ttry\n\t{\n\t\tscript.Tokenize();\n\t\t\n\t\tif (tokenString)\n\t\t{\n\t\t\tstd::ostringstream token_stream;\n\t\t\t\n\t\t\tscript.PrintTokens(token_stream);\n\t\t\t\n\t\t\tstd::string &&token_string = token_stream.str();\n            *tokenString = QString::fromStdString(token_string);\n\t\t}\n\t}\n\tcatch (...)\n    {\n        std::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n        *errorString = QString::fromStdString(error_string);\n        \n        // move the error outside of the currentScript context if possible; the ranges\n        // should have already been moved by TranslateErrorContextToUserScript()\n        if (gEidosErrorContext.currentScript == &script)\n        {\n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in tokenization.\" << std::endl;\n#endif\n            gEidosErrorContext.currentScript = nullptr;\n        }\n        else if (gEidosErrorContext.currentScript)\n        {\n            // The error got translated to a script we don't recognize; clear the error info,\n            // all we can do is show the error string to the user, with no position\n            errorString->insert(0, \"A tokenization error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\");\n            \n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in tokenization traced to a different script; clearing all error info.\" << std::endl;\n#endif\n            ClearErrorContext();\n        }\n        \n        return nullptr;\n    }\n    \n\t// Parse, an \"interpreter block\" bounded by an EOF rather than a \"script block\" that requires braces\n\ttry\n\t{\n\t\tscript.ParseInterpreterBlockToAST(true);\n\t\t\n\t\tif (parseString)\n\t\t{\n\t\t\tstd::ostringstream parse_stream;\n\t\t\t\n\t\t\tscript.PrintAST(parse_stream);\n\t\t\t\n\t\t\tstd::string &&parse_string = parse_stream.str();\n\t\t\t*parseString = QString::fromStdString(parse_string);\n\t\t}\n\t}\n\tcatch (...)\n    {\n        std::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n        *errorString = QString::fromStdString(error_string);\n        \n        // move the error outside of the currentScript context if possible; the ranges\n        // should have already been moved by TranslateErrorContextToUserScript()\n        if (gEidosErrorContext.currentScript == &script)\n        {\n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in parsing.\" << std::endl;\n#endif\n            gEidosErrorContext.currentScript = nullptr;\n        }\n        else if (gEidosErrorContext.currentScript)\n        {\n            // The error got translated to a script we don't recognize; clear the error info,\n            // all we can do is show the error string to the user, with no position\n            errorString->insert(0, \"A parsing error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\");\n            \n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in parsing traced to a different script; clearing all error info.\" << std::endl;\n#endif\n            ClearErrorContext();\n        }\n        \n        return nullptr;\n    }\n    \n\t// Get a symbol table and let SLiM add symbols to it\n\tif (!global_symbols)\n\t{\n\t\tglobal_symbols = gEidosConstantsSymbolTable;\n\t\t\n        // in SLiMgui this comes from the delegate method eidosConsoleWindowController:symbolsFromBaseSymbols:\n        if (parentSLiMWindow->community && !parentSLiMWindow->invalidSimulation())\n            global_symbols = parentSLiMWindow->community->SymbolsFromBaseSymbols(global_symbols);\n\t\t\n        // With the advant of global versus local symbol tables, the semantics here have gotten a little tricky.  In EidosScribe\n\t\t// we want the console to work in the global variables table directly, which we need to create; that will be our symbol\n\t\t// table.  In SLiM, we want the console to work in a local variables table; SLiM has its own global variables table,\n\t\t// which we don't want to clutter up, just as if were were in a callback.  So here, we now check whether a global variables\n\t\t// table is already in the chain, and if so, we create a local variables table; otherwise we create a global variables table.\n\t\tbool global_variables_table_exists = false;\n\t\tEidosSymbolTable *scan_table = global_symbols;\n\t\t\n\t\twhile (scan_table)\n\t\t{\n\t\t\tif (scan_table->TableType() == EidosSymbolTableType::kGlobalVariablesTable)\n\t\t\t{\n\t\t\t\tglobal_variables_table_exists = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tscan_table = scan_table->ChainSymbolTable();\n\t\t}\n\t\t\n\t\tEidosSymbolTableType console_table_type = global_variables_table_exists ? EidosSymbolTableType::kLocalVariablesTable : EidosSymbolTableType::kGlobalVariablesTable;\n\t\t\n\t\tglobal_symbols = new EidosSymbolTable(console_table_type, global_symbols);\t// add a table for script-defined variables on top\n\t}\n\t\n\t// Get a function map from SLiM, or make one ourselves\n\tif (!global_function_map)\n\t{\n        global_function_map_owned = false;\n\t\t\n        if (parentSLiMWindow->community && !parentSLiMWindow->invalidSimulation())\n\t\t\tglobal_function_map = &parentSLiMWindow->community->FunctionMap();\n\t\t\n\t\tif (!global_function_map)\n\t\t{\n\t\t\tglobal_function_map = new EidosFunctionMap(*EidosInterpreter::BuiltInFunctionMap());\n\t\t\tglobal_function_map_owned = true;\n\t\t}\n\t}\n\t\n\t// Get the EidosContext, if any, from SLiM\n\tEidosContext *eidos_context = parentSLiMWindow->community;\n\t\n\t// Interpret the parsed block\n    parentSLiMWindow->willExecuteScript();\n\t\n    std::ostringstream outstream;\t// in the Eidos console, one output stream for both types of output\n\tEidosInterpreter interpreter(script, *global_symbols, *global_function_map, eidos_context, outstream, outstream\n#ifdef SLIMGUI\n            , true\n#endif\n            );\n\t\n\ttry\n\t{\n\t\tif (executionString)\n\t\t\tinterpreter.SetShouldLogExecution(true);\n\t\t\n\t\tEidosValue_SP result = interpreter.EvaluateInterpreterBlock(true, true);\t// print output, return the last statement value (result not used)\n\t\toutput = outstream.str();\n\t\t\n        if (variableBrowser_)\n            variableBrowser_->reloadBrowser(true);\n\t\t\n\t\tif (executionString)\n\t\t{\n\t\t\tstd::string &&execution_string = interpreter.ExecutionLog();\n\t\t\t*executionString = QString::fromStdString(execution_string);\n\t\t}\n\t}\n\tcatch (...)\n    {\n        parentSLiMWindow->didExecuteScript();\n        \n        output = outstream.str();\n        \n        std::string &&error_string = Eidos_GetUntrimmedRaiseMessage();\n        *errorString = QString::fromStdString(error_string);\n        \n        // move the error outside of the currentScript context if possible; the ranges\n        // should have already been moved by TranslateErrorContextToUserScript()\n        if (gEidosErrorContext.currentScript == &script)\n        {\n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: clearing gEidosErrorContext.currentScript after error in execution.\" << std::endl;\n#endif\n            gEidosErrorContext.currentScript = nullptr;\n        }\n        else if (gEidosErrorContext.currentScript)\n        {\n            // The error got translated to a script we don't recognize; clear the error info,\n            // all we can do is show the error string to the user, with no position\n            errorString->insert(0, \"An execution error occurred in a different script context, so the error position cannot be highlighted in the console:\\n\");\n            \n#if EIDOS_DEBUG_ERROR_POSITIONS\n            std::cout << \"-[EidosConsoleWindowController _executeScriptString:...]: error in execution traced to a different script; clearing all error info.\" << std::endl;\n#endif\n            ClearErrorContext();\n        }\n        \n        return QString::fromStdString(output);\n    }\n    \n\tparentSLiMWindow->didExecuteScript();\n\t\n\t// See comment on safeguardReferences above\n\tif (safeguardReferences)\n\t\tvalidateSymbolTableAndFunctionMap();\n    \n    // Flush buffered output to files after every script execution, so the user sees the results\n    // NOTE THAT THE WORKING DIRECTORY HAS BEEN CHANGED BACK AT THIS POINT!\n    bool flush_success = Eidos_FlushFiles();\n    \n    if (!flush_success)\n        *errorString = \"ERROR (Eidos_FlushFiles): A compressed file buffer failed to write out to disk.  Please check file paths, filesystem writeability and permissions, available disk space, and other possible causes of file I/O problems.\\n\";\n    \n    return QString::fromStdString(output);\n}\n\n// Execute the given script string, with the terminating semicolon being optional if requested\nvoid QtSLiMEidosConsole::executeScriptString(QString scriptString, bool semicolonOptional)\n{\n    QString tokenString, parseString, executionString, errorString;\n    bool showTokens = false; //[defaults boolForKey:EidosDefaultsShowTokensKey];\n\tbool showParse = false; //[defaults boolForKey:EidosDefaultsShowParseKey];\n\tbool showExecution = false; //[defaults boolForKey:EidosDefaultsShowExecutionKey];\n    QtSLiMConsoleTextEdit *console = ui->consoleTextEdit;\n    \n    QString result = _executeScriptString(scriptString,\n                                          showTokens ? &tokenString : nullptr,\n                                          showParse ? &parseString : nullptr,\n                                          showExecution ? &executionString : nullptr,\n                                          &errorString,\n                                          semicolonOptional);\n    \n    if (errorString.contains(\"unexpected token 'EOF'\"))\n    {\n        // The user has entered an incomplete script line, so we use a continuation prompt\n        console->showContinuationPrompt();\n    }\n    else\n    {\n        console->appendExecution(result, errorString, tokenString, parseString, executionString);\n        console->showPrompt();\n    }\n}\n\n\n//\n//  public slots\n//\n\nvoid QtSLiMEidosConsole::executeAllClicked(void)\n{\n    QString all = ui->scriptTextEdit->toPlainText();\n    \n    ui->consoleTextEdit->setCommandAtPrompt(all);\n    ui->consoleTextEdit->executeCurrentPrompt();\n}\n\nvoid QtSLiMEidosConsole::executeSelectionClicked(void)\n{\n    QTextCursor selectionCursor(ui->scriptTextEdit->textCursor());\n    \n    if (selectionCursor.selectionStart() == selectionCursor.selectionEnd())\n    {\n        // zero-length selections get extended to encompass the full line\n        selectionCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);\n        selectionCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);\n    }\n    \n    QString selection = selectionCursor.selectedText();\n    \n    ui->consoleTextEdit->setCommandAtPrompt(selection);\n    ui->consoleTextEdit->executeCurrentPrompt();\n}\n\nvoid QtSLiMEidosConsole::executePromptScript(QString executionString)\n{\n    executeScriptString(executionString, true);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosConsole.h",
    "content": "//\n//  QtSLiMEidosConsole.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMEIDOSCONSOLE_H\n#define QTSLIMEIDOSCONSOLE_H\n\n#include <QWidget>\n#include <QString>\n#include <QTextCursor>\n\nclass QCloseEvent;\nclass QtSLiMWindow;\nclass QStatusBar;\nclass QSplitter;\nclass QtSLiMScriptTextEdit;\nclass QtSLiMConsoleTextEdit;\nclass QtSLiMVariableBrowser;\n\n#include \"eidos_script.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n\n\nnamespace Ui {\nclass QtSLiMEidosConsole;\n}\n\nclass QtSLiMEidosConsole : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMWindow *parentSLiMWindow = nullptr;     // a copy of parent with the correct class, for convenience\n    \n    explicit QtSLiMEidosConsole(QtSLiMWindow *p_parent = nullptr);\n    virtual ~QtSLiMEidosConsole() override;\n    \n    // Enable/disable the user interface as the simulation's state changes\n    void setInterfaceEnabled(bool enabled);\n    \n    // Throw away the current symbol table\n    void invalidateSymbolTableAndFunctionMap(void);\n    \n    // Make a new symbol table from our delegate's current state; this actually executes a minimal script, \";\",\n    // to produce the symbol table as a side effect of setting up for the script's execution\n    void validateSymbolTableAndFunctionMap(void);\n    \n    EidosSymbolTable *symbolTable(void) { return global_symbols; }\n    \n    // Execute the given script string, with the terminating semicolon being optional if requested\n    void executeScriptString(QString scriptString, bool semicolonOptional);\n    \n    // Access to key UI items\n    QStatusBar *statusBar(void);\n    QtSLiMScriptTextEdit *scriptTextEdit(void);\n    QtSLiMConsoleTextEdit *consoleTextEdit(void);\n    QtSLiMVariableBrowser *variableBrowser(void);\n    \npublic slots:\n    void executeAllClicked(void);\n    void executeSelectionClicked(void);\n    void showBrowserClicked(void);\n    \nsignals:\n    void willClose(void);\n    \n    //\n    //  UI glue, defined in QtSLiMEidosConsole_glue.cpp\n    //\n    \nprivate slots:\n    void checkScriptPressed(void);\n    void checkScriptReleased(void);\n    void prettyprintPressed(void);\n    void prettyprintReleased(void);\n    void scriptHelpPressed(void);\n    void scriptHelpReleased(void);\n    void showBrowserPressed(void);\n    void showBrowserReleased(void);\n    \n    void executeSelectionPressed(void);\n    void executeSelectionReleased(void);\n    void executeAllPressed(void);\n    void executeAllReleased(void);\n    void executePromptScript(QString executionString);\n\n    void clearOutputPressed(void);\n    void clearOutputReleased(void);\n    \n    virtual void closeEvent(QCloseEvent *p_event) override;\n    \nprivate:\n    Ui::QtSLiMEidosConsole *ui;\n    QStatusBar *statusBar_ = nullptr;\n    void glueUI(void);\n    \n    bool interfaceEnabled = false;              // set to false when the simulation is running or invalid\n    \n    // Variable browser support\n    QtSLiMVariableBrowser *variableBrowser_ = nullptr;\n    \n    // The symbol table for the console interpreter; needs to be wiped whenever the symbol table changes\n\tEidosSymbolTable *global_symbols = nullptr;\n\t\n\t// The function map for the console interpreter; carries over from invocation to invocation\n\tEidosFunctionMap *global_function_map = nullptr;\n    bool global_function_map_owned = false;\n\n    // Execution internals\n    QString _executeScriptString(QString scriptString, QString *tokenString, QString *parseString,\n                                 QString *executionString, QString *errorString, bool semicolonOptional);\n    \n    \n    // splitter support\n    void interpolateSplitters(void);\n    QWidget *scriptWidget = nullptr;\n    QWidget *outputWidget = nullptr;\n    QSplitter *splitter = nullptr;\n};\n\n\n#endif // QTSLIMEIDOSCONSOLE_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosConsole.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMEidosConsole</class>\n <widget class=\"QWidget\" name=\"QtSLiMEidosConsole\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>700</width>\n    <height>500</height>\n   </rect>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>700</width>\n    <height>250</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Eidos Console</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"overallLayout\" stretch=\"2,3\">\n     <property name=\"spacing\">\n      <number>6</number>\n     </property>\n     <property name=\"leftMargin\">\n      <number>3</number>\n     </property>\n     <property name=\"topMargin\">\n      <number>3</number>\n     </property>\n     <property name=\"rightMargin\">\n      <number>3</number>\n     </property>\n     <property name=\"bottomMargin\">\n      <number>3</number>\n     </property>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"scriptLayout\">\n       <property name=\"spacing\">\n        <number>3</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"scriptHeaderLayout\">\n         <property name=\"spacing\">\n          <number>3</number>\n         </property>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"checkScriptButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;check script syntax&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/check.png</normaloff>\n             <normalon>:/buttons/check_H.png</normalon>:/buttons/check.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"prettyprintButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prettyprint script&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/prettyprint.png</normaloff>\n             <normalon>:/buttons/prettyprint_H.png</normalon>:/buttons/prettyprint.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"scriptHelpButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;scripting help&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/syntax_help.png</normaloff>\n             <normalon>:/buttons/syntax_help_H.png</normalon>:/buttons/syntax_help.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"browserButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;show Eidos variable browser&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/show_browser.png</normaloff>\n             <normalon>:/buttons/show_browser_H.png</normalon>:/buttons/show_browser.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"checkable\">\n            <bool>true</bool>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"scriptHeaderLabel\">\n           <property name=\"text\">\n            <string> Eidos:</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"executeSelectionButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;execute selection&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/execute_selection.png</normaloff>\n             <normalon>:/buttons/execute_selection_H.png</normalon>:/buttons/execute_selection.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"checkable\">\n            <bool>true</bool>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"executeAllButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;execute full script&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/execute_script.png</normaloff>\n             <normalon>:/buttons/execute_script_H.png</normalon>:/buttons/execute_script.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QtSLiMScriptTextEdit\" name=\"scriptTextEdit\"/>\n       </item>\n      </layout>\n     </item>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"outputLayout\">\n       <property name=\"spacing\">\n        <number>3</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"outputHeaderLayout\">\n         <property name=\"spacing\">\n          <number>3</number>\n         </property>\n         <item>\n          <widget class=\"QtSLiMPushButton\" name=\"clearOutputButton\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"maximumSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"focusPolicy\">\n            <enum>Qt::NoFocus</enum>\n           </property>\n           <property name=\"toolTip\">\n            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;clear output log&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n           </property>\n           <property name=\"icon\">\n            <iconset resource=\"buttons.qrc\">\n             <normaloff>:/buttons/delete.png</normaloff>\n             <normalon>:/buttons/delete_H.png</normalon>:/buttons/delete.png</iconset>\n           </property>\n           <property name=\"iconSize\">\n            <size>\n             <width>20</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"outputHeaderLabel\">\n           <property name=\"text\">\n            <string> Console:</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_3\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QtSLiMConsoleTextEdit\" name=\"consoleTextEdit\"/>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"statusBarLayout\"/>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMPushButton</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMScriptTextEdit</class>\n   <extends>QPlainTextEdit</extends>\n   <header>QtSLiMScriptTextEdit.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMConsoleTextEdit</class>\n   <extends>QPlainTextEdit</extends>\n   <header>QtSLiMConsoleTextEdit.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"buttons.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosConsole_glue.cpp",
    "content": "//\n//  QtSLiMEidosConsole_glue.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMEidosConsole.h\"\n#include \"ui_QtSLiMEidosConsole.h\"\n\n#include <QCoreApplication>\n#include <QKeyEvent>\n#include <QDesktopServices>\n\n#include \"QtSLiMAppDelegate.h\"\n\n\nvoid QtSLiMEidosConsole::glueUI(void)\n{\n    connect(ui->consoleTextEdit, &QtSLiMConsoleTextEdit::executeScript, this, &QtSLiMEidosConsole::executePromptScript);\n    \n    // connect all QtSLiMEidosConsole slots\n    connect(ui->checkScriptButton, &QPushButton::clicked, ui->scriptTextEdit, &QtSLiMTextEdit::checkScript);\n    connect(ui->prettyprintButton, &QPushButton::clicked, ui->scriptTextEdit, &QtSLiMTextEdit::prettyprintClicked);\n    connect(ui->scriptHelpButton, &QPushButton::clicked, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n    connect(ui->browserButton, &QPushButton::clicked, this, &QtSLiMEidosConsole::showBrowserClicked);\n    \n    connect(ui->executeSelectionButton, &QPushButton::clicked, this, &QtSLiMEidosConsole::executeSelectionClicked);\n    connect(ui->executeAllButton, &QPushButton::clicked, this, &QtSLiMEidosConsole::executeAllClicked);\n\n    connect(ui->clearOutputButton, &QPushButton::clicked, ui->consoleTextEdit, &QtSLiMConsoleTextEdit::clearToPrompt);\n    \n    // set up QtSLiMPushButton \"base names\" for all buttons\n    ui->checkScriptButton->qtslimSetBaseName(\"check\");\n    ui->prettyprintButton->qtslimSetBaseName(\"prettyprint\");\n    ui->scriptHelpButton->qtslimSetBaseName(\"syntax_help\");\n    ui->browserButton->qtslimSetBaseName(\"show_browser\");\n    ui->executeSelectionButton->qtslimSetBaseName(\"execute_selection\");\n    ui->executeAllButton->qtslimSetBaseName(\"execute_script\");\n    ui->clearOutputButton->qtslimSetBaseName(\"delete\");\n    \n    // set up all icon-based QPushButtons to change their icon as they track\n    connect(ui->checkScriptButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::checkScriptPressed);\n    connect(ui->checkScriptButton, &QPushButton::released, this, &QtSLiMEidosConsole::checkScriptReleased);\n    connect(ui->prettyprintButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::prettyprintPressed);\n    connect(ui->prettyprintButton, &QPushButton::released, this, &QtSLiMEidosConsole::prettyprintReleased);\n    connect(ui->scriptHelpButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::scriptHelpPressed);\n    connect(ui->scriptHelpButton, &QPushButton::released, this, &QtSLiMEidosConsole::scriptHelpReleased);\n    connect(ui->browserButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::showBrowserPressed);\n    connect(ui->browserButton, &QPushButton::released, this, &QtSLiMEidosConsole::showBrowserReleased);\n    \n    connect(ui->executeSelectionButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::executeSelectionPressed);\n    connect(ui->executeSelectionButton, &QPushButton::released, this, &QtSLiMEidosConsole::executeSelectionReleased);\n    connect(ui->executeAllButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::executeAllPressed);\n    connect(ui->executeAllButton, &QPushButton::released, this, &QtSLiMEidosConsole::executeAllReleased);\n    \n    connect(ui->clearOutputButton, &QPushButton::pressed, this, &QtSLiMEidosConsole::clearOutputPressed);\n    connect(ui->clearOutputButton, &QPushButton::released, this, &QtSLiMEidosConsole::clearOutputReleased);\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\n\n//\n//  private slots\n//\n\nvoid QtSLiMEidosConsole::checkScriptPressed(void)\n{\n    ui->checkScriptButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::checkScriptReleased(void)\n{\n    ui->checkScriptButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::prettyprintPressed(void)\n{\n    ui->prettyprintButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::prettyprintReleased(void)\n{\n    ui->prettyprintButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::scriptHelpPressed(void)\n{\n    ui->scriptHelpButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::scriptHelpReleased(void)\n{\n    ui->scriptHelpButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::showBrowserPressed(void)\n{\n    ui->browserButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::showBrowserReleased(void)\n{\n    ui->browserButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::executeSelectionPressed(void)\n{\n    ui->executeSelectionButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::executeSelectionReleased(void)\n{\n    ui->executeSelectionButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::executeAllPressed(void)\n{\n    ui->executeAllButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::executeAllReleased(void)\n{\n    ui->executeAllButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMEidosConsole::clearOutputPressed(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMEidosConsole::clearOutputReleased(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(false);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosPrettyprinter.cpp",
    "content": "//\n//  QtSLiMEidosPrettyprinter.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/1/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMEidosPrettyprinter.h\"\n#include <eidos_script.h>\n\n#include <QString>\n#include <QChar>\n#include <QDebug>\n\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\nstatic int Eidos_indentForStack(std::vector<const EidosToken *> &indentStack, bool startingNewStatement, EidosTokenType nextTokenType)\n{\n    // Count the number of indents represented by the indent stack.  When a control-flow keyword is\n\t// followed by a left brace, the indent stack has two items on it, but we want to only indent\n\t// one level.\n\tint indent = 0;\n\tbool previousIndentStackItemWasControlFlow = false;\n\t\n\tfor (size_t stackIndex = 0; stackIndex < indentStack.size(); ++stackIndex)\n\t{\n\t\tEidosTokenType stackTokenType = indentStack[stackIndex]->token_type_;\n\t\t\n\t\t// skip over ternary conditionals; they do not generate indent, but are on the stack so we can match elses\n\t\tif (stackTokenType == EidosTokenType::kTokenConditional)\n\t\t\tcontinue;\n\t\t\n\t\tif (previousIndentStackItemWasControlFlow && (stackTokenType == EidosTokenType::kTokenLBrace))\n\t\t\t;\n\t\telse\n\t\t\t++indent;\n\t\t\n\t\tpreviousIndentStackItemWasControlFlow = !(stackTokenType == EidosTokenType::kTokenLBrace);\n\t}\n\t\n\tbool lastIndentIsControlFlow = previousIndentStackItemWasControlFlow;\n\t\n\t// Indent when continuing a statement, but not after a control-flow token.  The idea here is that\n\t// if you have a structure like:\n\t//\n\t//\tif (x)\n\t//\t\tif (y)\n\t//\t\t\t<statement>;\n\t//\n\t// the indent stack will already dictate that <statement> is indented twice; it does not need to\n\t// receive the !startingNewStatement extra indent level that we normally add to cause continuing\n\t// statements to be indented like:\n\t//\n\t//\tx = a + b + c +\n\t//\t\td + e + f;\n\t//\n\tif (!startingNewStatement && !lastIndentIsControlFlow)\n\t\tindent++;\n\t\n\t// If the next token is a left brace, outdent one level, conventionally.  This reflects usage like:\n\t//\n\t//\tif (x)\n\t//\t\ty;\n\t//\n\t//\tif (x)\n\t//\t{\n\t//\t\ty;\n\t//\t}\n\t//\n\t// This applies only if the last element on the indent stack is a control-flow indent, not a {.\n\t// This is the same rule we used when counting indentStack, but applied to nextTokenType.  We also\n\t// outdent when we see a left brace if we are mid-statement; this covers SLiM callback syntax.\n\t//\n\tif ((lastIndentIsControlFlow || !startingNewStatement) && (nextTokenType == EidosTokenType::kTokenLBrace))\n\t\tindent--;\n\t\n\t// For similar reasons, if the next token is a right brace, always outdent one level\n\tif (nextTokenType == EidosTokenType::kTokenRBrace)\n\t\tindent--;\n\t\n\treturn indent;\n}\n\nbool Eidos_prettyprintTokensFromScript(const std::vector<EidosToken> &tokens, EidosScript &tokenScript, std::string &pretty)\n{\n    // We keep a stack of indent-generating tokens: { if else do while for.  The purpose of this is\n\t// to be able to tell what indent level we're at, and how it changes with a ; or a } token.\n\tstd::vector<const EidosToken *> indentStack;\n\tbool startingNewStatement = true;\n\tsize_t tokenCount = tokens.size();\n\t\n\tfor (size_t tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex)\n\t{\n\t\tconst EidosToken &token = tokens[tokenIndex];\n        std::string tokenString(token.token_string_);\n\t\tEidosTokenType nextTokenPeek = (tokenIndex + 1 < tokenCount ? tokens[tokenIndex+1].token_type_ : EidosTokenType::kTokenEOF);\n\t\t\n\t\t// Find the next non-whitespace, non-comment token for lookahead\n\t\tsize_t nextSignificantTokenPeekIndex = tokenIndex + 1;\n\t\tEidosTokenType nextSignificantTokenPeek = EidosTokenType::kTokenEOF;\n\t\t\n\t\twhile (nextSignificantTokenPeekIndex < tokenCount)\n\t\t{\n\t\t\tEidosTokenType peek = tokens[nextSignificantTokenPeekIndex].token_type_;\n\t\t\t\n\t\t\tif ((peek != EidosTokenType::kTokenWhitespace) && (peek != EidosTokenType::kTokenComment) && (peek != EidosTokenType::kTokenCommentLong))\n\t\t\t{\n\t\t\t\tnextSignificantTokenPeek = peek;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tnextSignificantTokenPeekIndex++;\n\t\t}\n\t\t\n\t\tswitch (token.token_type_)\n\t\t{\n\t\t\t\t// These token types are not used in the AST and should not be present\n\t\t\tcase EidosTokenType::kTokenNone:\n\t\t\tcase EidosTokenType::kTokenBad:\n\t\t\t\treturn false;\n\t\t\t\t\n\t\t\t\t// These are virtual tokens that can be ignored\n\t\t\tcase EidosTokenType::kTokenEOF:\n\t\t\tcase EidosTokenType::kTokenInterpreterBlock:\n\t\t\tcase EidosTokenType::kTokenContextFile:\n\t\t\tcase EidosTokenType::kTokenContextEidosBlock:\n\t\t\tcase EidosTokenType::kFirstIdentifierLikeToken:\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// This is where the rubber meets the road; prettyprinting is all about altering whitespace stretches.\n\t\t\t\t// We don't want to alter the user's newline decisions, so we count the number of newlines in this\n\t\t\t\t// whitespace stretch and always emit the same number.  If there are no newlines, we're in whitespace\n\t\t\t\t// inside a given line, with tokens on both sides; for the time being we do not alter those at all.\n\t\t\t\t// If there are newlines, though, then each newline is changed to be followed by the appropriate number\n\t\t\t\t// of tabs as indentation.  The indent depends upon the indent stack and some other state about the\n\t\t\t\t// context we are in.\n\t\t\tcase EidosTokenType::kTokenWhitespace:\n\t\t\t{\n                // We use QString to get intelligent treatment of Unicode and UTF-8; std::string is just too dumb.\n                // In SLiMGui this is done with NSString.  We want to count newlines in a mac/unix/windows agnostic way.\n                const QString q_tokenString = QString::fromStdString(tokenString);\n                int newlineCount = 0;\n                bool prevWasCR = false, prevWasLF = false;\n                \n                for (QChar qch : q_tokenString)\n                {\n                    if (qch == QChar::LineFeed)\n                    {\n                        if (prevWasCR) { prevWasCR = false; continue; }     // CR-LF counts for one\n                        newlineCount++;\n                        prevWasLF = true;\n                    }\n                    else if (qch == QChar::CarriageReturn)\n                    {\n                        if (prevWasLF) { prevWasLF = false; continue; }     // LF-CR counts for one\n                        newlineCount++;\n                        prevWasCR = true;\n                    }\n                    else if (qch == QChar::ParagraphSeparator)\n                    {\n                        newlineCount++;\n                        prevWasCR = prevWasLF = false;\n                    }\n                }\n                \n\t\t\t\tif (newlineCount <= 0)\n\t\t\t\t{\n\t\t\t\t\t// Normally, whitespace tokens that do not contain a newline occur inside a line, and should be preserved.\n\t\t\t\t\t// A whitespace token that indents the start of a line normally started on the previous line and contains\n\t\t\t\t\t// a newline.  However, this is not the case at the very beginning of a script; the first token is special.\n\t\t\t\t\tif (tokenIndex > 0)\n                        pretty.append(tokenString);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n                    int indent = Eidos_indentForStack(indentStack, startingNewStatement, nextTokenPeek);\n\t\t\t\t\t\n\t\t\t\t\tfor (int lineCounter = 0; lineCounter < newlineCount; ++lineCounter)\n\t\t\t\t\t{\n                        pretty.append(\"\\n\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int tabCounter = 0; tabCounter < indent; ++tabCounter)\n                            pretty.append(\"\\t\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// We have ended a statement, so we reset our indent levels\n\t\t\tcase EidosTokenType::kTokenSemicolon:\n\t\t\t{\n\t\t\t\t// Pop indent-generating tokens that have expired with the end of this statement; a semicolon terminates\n\t\t\t\t// a whole nested series of if else do while for, but does not terminate an enclosing { block.  Also,\n\t\t\t\t// if there are nested if statements, a semicolon terminates only the first one if the next token is an else.\n\t\t\t\twhile (indentStack.size() > 0) {\n\t\t\t\t\tconst EidosToken *topIndentToken = indentStack.back();\n\t\t\t\t\t\n\t\t\t\t\tif (topIndentToken->token_type_ == EidosTokenType::kTokenLBrace)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif ((topIndentToken->token_type_ == EidosTokenType::kTokenIf) && (nextSignificantTokenPeek == EidosTokenType::kTokenElse))\n\t\t\t\t\t{\n\t\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Track braces\n\t\t\tcase EidosTokenType::kTokenLBrace:\n\t\t\t{\n\t\t\t\tindentStack.emplace_back(&token);\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosTokenType::kTokenRBrace:\n\t\t\t{\n\t\t\t\t// First pop the matching left brace\n\t\t\t\tif ((indentStack.size() == 0) || (indentStack.back()->token_type_ != EidosTokenType::kTokenLBrace))\n\t\t\t\t{\n\t\t\t\t\t// All other indent-producing tokens should already have been balanced; Eidos has no implicit termination of statements\n\t\t\t\t\t//NSLog(@\"Unbalanced '}' token in prettyprinting!\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tindentStack.pop_back();\n\t\t\t\t\n\t\t\t\t// Then pop indent-generating tokens above the left brace that have expired with the end of this statement\n\t\t\t\twhile (indentStack.size() > 0) {\n\t\t\t\t\tconst EidosToken *topIndentToken = indentStack.back();\n\t\t\t\t\t\n\t\t\t\t\tif (topIndentToken->token_type_ == EidosTokenType::kTokenLBrace)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Control-flow keywords influence our indent level; this might look like the normal statement inner indent,\n\t\t\t\t// but it is not, as can be seen when these control-flow keywords are nested like 'if (x) if (y) <statement>'.\n\t\t\t\t// When an if follows an else, the else is removed by the if, since we don't want two indents; else-if is one indent.\n\t\t\tcase EidosTokenType::kTokenIf:\n\t\t\t{\n\t\t\t\tif (indentStack.size())\n\t\t\t\t{\n\t\t\t\t\tEidosTokenType top_token_type = indentStack.back()->token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (top_token_type == EidosTokenType::kTokenElse)\n\t\t\t\t\t\tindentStack.pop_back();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindentStack.emplace_back(&token);\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\tcase EidosTokenType::kTokenDo:\n\t\t\tcase EidosTokenType::kTokenWhile:\n\t\t\tcase EidosTokenType::kTokenFor:\n\t\t\tcase EidosTokenType::kTokenConditional:\t\t// note this does not generate indent, but is put on the stack\n\t\t\t{\n\t\t\t\tindentStack.emplace_back(&token);\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// else can be paired with if or ?.  In the former case, the if will be off the stack by the time the else\n\t\t\t\t// is encountered, and we put the else on to give us an equivalent indent.  In the latter case, we consider\n\t\t\t\t// the expressions within the ternary conditional to be statement-level; we don't indent, and we don't push\n\t\t\t\t// an else on the stack here, but we remove the conditional that we are completing.\n\t\t\tcase EidosTokenType::kTokenElse:\n\t\t\t{\n\t\t\t\tif (indentStack.size())\n\t\t\t\t{\n\t\t\t\t\tEidosTokenType top_token_type = indentStack.back()->token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (top_token_type == EidosTokenType::kTokenConditional)\n\t\t\t\t\t{\n\t\t\t\t\t\tindentStack.pop_back();\n                        pretty.append(tokenString);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindentStack.emplace_back(&token);\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// Comments are preserved verbatim\n\t\t\tcase EidosTokenType::kTokenComment:\n\t\t\tcase EidosTokenType::kTokenCommentLong:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Tokens for operators are emitted verbatim\n\t\t\tcase EidosTokenType::kTokenColon:\n\t\t\tcase EidosTokenType::kTokenComma:\n\t\t\tcase EidosTokenType::kTokenDot:\n\t\t\tcase EidosTokenType::kTokenPlus:\n\t\t\tcase EidosTokenType::kTokenMinus:\n\t\t\tcase EidosTokenType::kTokenMod:\n\t\t\tcase EidosTokenType::kTokenMult:\n\t\t\tcase EidosTokenType::kTokenExp:\n\t\t\tcase EidosTokenType::kTokenAnd:\n\t\t\tcase EidosTokenType::kTokenOr:\n\t\t\tcase EidosTokenType::kTokenDiv:\n\t\t\tcase EidosTokenType::kTokenAssign:\n            case EidosTokenType::kTokenAssign_R:\n\t\t\tcase EidosTokenType::kTokenEq:\n\t\t\tcase EidosTokenType::kTokenLt:\n\t\t\tcase EidosTokenType::kTokenLtEq:\n\t\t\tcase EidosTokenType::kTokenGt:\n\t\t\tcase EidosTokenType::kTokenGtEq:\n\t\t\tcase EidosTokenType::kTokenNot:\n\t\t\tcase EidosTokenType::kTokenNotEq:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase EidosTokenType::kTokenSingleton:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Nesting levels of parens and brackets are not tracked at the moment\n\t\t\tcase EidosTokenType::kTokenLParen:\n\t\t\tcase EidosTokenType::kTokenRParen:\n\t\t\tcase EidosTokenType::kTokenLBracket:\n\t\t\tcase EidosTokenType::kTokenRBracket:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Numbers and identifiers are emitted verbatim\n\t\t\tcase EidosTokenType::kTokenNumber:\n\t\t\tcase EidosTokenType::kTokenIdentifier:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// Strings are emitted verbatim, but their original string needs to be reconstructed;\n\t\t\t\t// token_string_ has the outer quotes removed and escape sequences resolved\n\t\t\tcase EidosTokenType::kTokenString:\n                pretty.append(tokenScript.String().substr(static_cast<size_t>(token.token_start_), static_cast<size_t>(token.token_end_ - token.token_start_ + 1)));\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// These keywords have no effect on indent level\n\t\t\tcase EidosTokenType::kTokenIn:\n\t\t\tcase EidosTokenType::kTokenNext:\n\t\t\tcase EidosTokenType::kTokenBreak:\n\t\t\tcase EidosTokenType::kTokenReturn:\n\t\t\tcase EidosTokenType::kTokenFunction:\n                pretty.append(tokenString);\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Now that we're done processing that token, update startingNewStatement to reflect whether we are within\n\t\t// a statement, of which we have seen at least one token, or starting a new statement.  Nonsignificant\n\t\t// tokens (whitespace and comments) do not alter the state of startingNewStatement.\n\t\tif ((token.token_type_ != EidosTokenType::kTokenWhitespace) && (token.token_type_ != EidosTokenType::kTokenComment) && (token.token_type_ != EidosTokenType::kTokenCommentLong))\n\t\t\tstartingNewStatement = ((token.token_type_ == EidosTokenType::kTokenSemicolon) ||\n\t\t\t\t\t\t\t\t\t(token.token_type_ == EidosTokenType::kTokenLBrace) ||\n\t\t\t\t\t\t\t\t\t(token.token_type_ == EidosTokenType::kTokenRBrace));\n\t}\n\t\n\treturn true;\n}\n\nstatic inline const EidosToken &NextSignificantToken(const std::vector<EidosToken> &tokens, size_t tokenIndex)\n{\n    // This scans forward from tokenIndex (not including tokenIndex itself) and returns the\n    // next token that is not a whitespace, comment, or other non-significant token.\n    do {\n        if (tokenIndex == tokens.size() - 1)\n            return tokens[tokenIndex];\n        \n        tokenIndex++;\n        \n        EidosTokenType tokenType = tokens[tokenIndex].token_type_;\n        \n        if ((tokenType != EidosTokenType::kTokenWhitespace) &&\n                (tokenType != EidosTokenType::kTokenComment) &&\n                (tokenType != EidosTokenType::kTokenCommentLong))\n            return tokens[tokenIndex];\n    } while (true);\n}\n\nstatic inline const EidosToken &PreviousSignificantToken(const std::vector<EidosToken> &tokens, size_t tokenIndex)\n{\n    // This scans backward from tokenIndex (not including tokenIndex itself) and returns the\n    // previous token that is not a whitespace, comment, or other non-significant token.\n    do {\n        if (tokenIndex == 0)\n            return tokens[tokenIndex];\n        \n        tokenIndex--;\n        \n        EidosTokenType tokenType = tokens[tokenIndex].token_type_;\n        \n        if ((tokenType != EidosTokenType::kTokenWhitespace) &&\n                (tokenType != EidosTokenType::kTokenComment) &&\n                (tokenType != EidosTokenType::kTokenCommentLong))\n            return tokens[tokenIndex];\n    } while (true);\n}\n\nstatic inline void EmitWhitespace(bool &forceSpace, int &forceNewlineCount, std::string &pretty)\n{\n    // This emits space before the next token.  It should be called immediately before the next token is emitted, so that\n    // other considerations can influence the nature of the whitespace before it is actually appended to the string.\n    if (pretty.length() > 0)\n    {\n        if (forceNewlineCount > 0)\n        {\n            for (int i = 0; i < forceNewlineCount; ++i)\n                pretty.append(\"\\n\");\n        }\n        else if (forceSpace)\n            pretty.append(\" \");\n    }\n    \n    forceSpace = false;\n    forceNewlineCount = 0;\n}\n\nbool Eidos_reformatTokensFromScript(const std::vector<EidosToken> &tokens, EidosScript &tokenScript, std::string &pretty)\n{\n    // Completely reformat the script string, changing newlines and spaces as well as line indents.  This is different enough\n    // in its logic that it doesn't seem to make sense for it to share code with Eidos_prettyprintTokensFromScript(); it would\n    // just be a mess.  However, there is certainly a lot of shared logic, too.  Note that we do not deal with indentation at\n    // all here.  Instead, we just call Eidos_prettyprintTokensFromScript() at the end to prettyprint the reformatted code.\n    size_t tokenCount = tokens.size();\n    int parenNestCount = 0;\n    int braceNestCount = 0;\n    bool forceNewlineAfterParenBalance = false;\n    bool resolveWhileSemanticsAfterParenBalance = false;\n    int insideTernaryConditionalCount = 0;\n    bool lastTokenContainedNewline = true;\n    bool lastTokenSuppressesCommentSpacing = true;\n    int functionDeclarationCountdown = 0;\n    bool forceSpace = false;\n    int forceNewlineCount = 0;\n\t\n\tfor (size_t tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex)\n\t{\n\t\tconst EidosToken &token = tokens[tokenIndex];\n        const std::string &tokenString = token.token_string_;\n        EidosTokenType tokenType = token.token_type_;\n        bool nextLastTokenSuppressesCommentSpacing = false;\n        \n        switch (tokenType)\n        {\n            // These token types are not used in the AST and should not be present\n        case EidosTokenType::kTokenNone:\n        case EidosTokenType::kTokenBad:\n            return false;\n            \n            // These are virtual tokens that can be ignored\n        case EidosTokenType::kTokenEOF:\n        case EidosTokenType::kTokenInterpreterBlock:\n        case EidosTokenType::kTokenContextFile:\n        case EidosTokenType::kTokenContextEidosBlock:\n        case EidosTokenType::kFirstIdentifierLikeToken:\n            break;\n            \n            // Whitespace is completely ignored; we do our own whitespace.  We do look to see whether a newline is\n            // present, though, so that we can keep comments on the same line as code when that situation exists\n        case EidosTokenType::kTokenWhitespace:\n            lastTokenContainedNewline = (tokenString.find_first_of(\"\\n\\r\\x0C\") != std::string::npos);\n            break;\n            \n            // Comments are copied verbatim, and always get a newline after them; whether they get a newline before depends\n        case EidosTokenType::kTokenComment:\n        case EidosTokenType::kTokenCommentLong:\n        {\n            int postCommentNewlineCount = 1;\n            \n            if (lastTokenContainedNewline)\n            {\n                // we like to have a blank line before standalone comments, unless they follow a brace or a standalone comment\n                forceNewlineCount = std::max(forceNewlineCount, lastTokenSuppressesCommentSpacing ? 1 : 2);\n                nextLastTokenSuppressesCommentSpacing = true;\n            }\n            else\n            {\n                // same-line comments don't get a preceding newline, but if that means we're suppressing newlines,\n                // make up for it after ourselves; we're just a tack-on on top of whatever was already happening\n                forceSpace = true;\n                postCommentNewlineCount = forceNewlineCount;\n                forceNewlineCount = 0;\n            }\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            if ((tokenType == EidosTokenType::kTokenComment) || lastTokenContainedNewline)\n                forceNewlineCount = postCommentNewlineCount;\n            else\n                forceSpace = true;\n            break;\n        }\n            \n            // These tokens get no space before them, even if requested by the previous token; and they are followed by a newline\n        case EidosTokenType::kTokenSemicolon:\n            forceSpace = false;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceNewlineCount = 1;\n            break;\n            \n            // This post-increments the indent level, and is always followed by a newline\n        case EidosTokenType::kTokenLBrace:\n            forceNewlineCount = 1;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceNewlineCount = 1;\n            braceNestCount++;\n            nextLastTokenSuppressesCommentSpacing = true;\n            break;\n            \n            // This pre-decrements the indent level, and is always followed by a newline – two newlines at the topmost level\n        case EidosTokenType::kTokenRBrace:\n            forceNewlineCount = 1;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            braceNestCount--;\n            forceNewlineCount = 1;\n            if ((braceNestCount == 0) && (parenNestCount == 0))\n                forceNewlineCount = 2;            \n            break;\n            \n            // Plus and minus can be binary or unary; emit like kTokenMult if binary, like kTokenNot if unary\n        case EidosTokenType::kTokenPlus:\n        case EidosTokenType::kTokenMinus:\n        {\n            bool isBinary = false;\n            const EidosToken &previous_token = PreviousSignificantToken(tokens, tokenIndex);\n            EidosTokenType prev_type = previous_token.token_type_;\n            \n            if ((prev_type == EidosTokenType::kTokenNumber) ||\n                    (prev_type == EidosTokenType::kTokenString) ||\n                    (prev_type == EidosTokenType::kTokenIdentifier) ||\n                    (prev_type == EidosTokenType::kTokenRParen) ||\n                    (prev_type == EidosTokenType::kTokenRBracket))\n                isBinary = true;\n            \n            if (isBinary)\n                forceSpace = true;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            if (isBinary)\n                forceSpace = true;\n            break;\n        }\n            \n            // These tokens should be emitted verbatim, surrounded by single spaces\n        case EidosTokenType::kTokenMod:\n        case EidosTokenType::kTokenMult:\n        case EidosTokenType::kTokenAnd:\n        case EidosTokenType::kTokenOr:\n        case EidosTokenType::kTokenDiv:\n        case EidosTokenType::kTokenConditional:\n        case EidosTokenType::kTokenEq:\n        case EidosTokenType::kTokenLt:\n        case EidosTokenType::kTokenLtEq:\n        case EidosTokenType::kTokenGt:\n        case EidosTokenType::kTokenGtEq:\n        case EidosTokenType::kTokenNotEq:\n        case EidosTokenType::kTokenIn:\n            if ((functionDeclarationCountdown > 0) &&\n                    ((tokenType == EidosTokenType::kTokenLt) || (tokenType == EidosTokenType::kTokenGt)))\n            {\n                // special treatment for \"o<object-type>\" syntax in function declarations\n                forceSpace = false;\n                EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n                pretty.append(tokenString);\n                if (tokenType == EidosTokenType::kTokenGt)\n                    forceSpace = true;\n            }\n            else\n            {\n                forceSpace = true;\n                EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n                pretty.append(tokenString);\n                forceSpace = true;\n                if (tokenType == EidosTokenType::kTokenConditional)\n                    insideTernaryConditionalCount++;\n            }\n            break;\n            \n            // This token gets spaces around it if it's not inside parentheses, like x = y;, but no spaces inside parens, like foo(x=y);\n        case EidosTokenType::kTokenAssign:\n        case EidosTokenType::kTokenAssign_R:\n            if (parenNestCount == 0)\n                forceSpace = true;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            if (parenNestCount == 0)\n                forceSpace = true;\n            break;\n            \n            // These tokens should get a space before them, but none after them\n            pretty.append(tokenString);\n            break;\n            \n            // These tokens should get a space after them, but should force there to be none before them\n        case EidosTokenType::kTokenComma:\n        case EidosTokenType::kTokenSingleton:\n        case EidosTokenType::kTokenReturn:\n            forceSpace = false;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceSpace = true;\n            break;\n            \n            // These tokens should not get spaces on either side of them (unless the adjecent token demands it)\n        case EidosTokenType::kTokenColon:\n        case EidosTokenType::kTokenLBracket:\n        case EidosTokenType::kTokenRBracket:\n        case EidosTokenType::kTokenDot:\n        case EidosTokenType::kTokenExp:\n        case EidosTokenType::kTokenNot:\n        case EidosTokenType::kTokenNext:\n        case EidosTokenType::kTokenBreak:\n        case EidosTokenType::kTokenNumber:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            break;\n            \n            // Identifiers have special spacing at the top level, because constructs like \"s1 1000 early()\" don't follow normal rules\n        case EidosTokenType::kTokenIdentifier:\n            if ((parenNestCount == 0) && (braceNestCount == 0) && (functionDeclarationCountdown == 0))\n                forceSpace = true;\n            if (PreviousSignificantToken(tokens, tokenIndex).token_type_ == EidosTokenType::kTokenIdentifier)\n                forceSpace = true;  // always force a space between two adjacent identifiers, like [lif foo=T]\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            if ((parenNestCount == 0) && (braceNestCount == 0) && (NextSignificantToken(tokens, tokenIndex).token_type_ == EidosTokenType::kTokenNumber))\n                forceSpace = true;\n            break;\n            \n            // Same as the above category, but string tokens have to be emitted in a special way\n        case EidosTokenType::kTokenString:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenScript.String().substr(static_cast<size_t>(token.token_start_), static_cast<size_t>(token.token_end_ - token.token_start_ + 1)));\n            break;\n            \n            // Left parentheses keep track of their nesting state\n        case EidosTokenType::kTokenLParen:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            parenNestCount++;\n            break;\n            \n            // Right parentheses keep track of their nesting state, and can do some special actions if they balance out\n        case EidosTokenType::kTokenRParen:\n            forceSpace = false;     // never a space before a right paren\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            if (--parenNestCount == 0)\n            {\n                if (forceNewlineAfterParenBalance)\n                {\n                    forceNewlineAfterParenBalance = false;\n                    forceNewlineCount = 1;\n                }\n                if (resolveWhileSemanticsAfterParenBalance)\n                {\n                    resolveWhileSemanticsAfterParenBalance = false;\n                    \n                    // We rely here on the fact that the script parses without errors\n                    const EidosToken &nextSigToken = NextSignificantToken(tokens, tokenIndex);\n                    \n                    if (nextSigToken.token_type_ != EidosTokenType::kTokenSemicolon)\n                    {\n                        // If the next token is a semicolon, we are terminating a do-while loop\n                        // (or we're a while loop with a null statement as its body, which we treat incorrectly)\n                        // If the next token is not a semicolon, we are starting a while loop, so we need a newline\n                        forceNewlineCount = 1;\n                    }\n                }\n                if (functionDeclarationCountdown > 0)\n                    functionDeclarationCountdown--;\n            }\n            break;\n            \n            // These tokens are followed by a space, a parenthesized expression, and then a newline\n        case EidosTokenType::kTokenIf:\n        case EidosTokenType::kTokenFor:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceSpace = true;\n            forceNewlineAfterParenBalance = true;\n            break;\n            \n            // The \"do\" token starts a do-while loop\n        case EidosTokenType::kTokenDo:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceNewlineCount = 1;\n            break;\n            \n            // The \"while\" token either ends a do-while loop, or starts a while loop\n        case EidosTokenType::kTokenWhile:\n            forceSpace = true;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceSpace = true;\n            resolveWhileSemanticsAfterParenBalance = true;\n            break;\n            \n            // The \"else\" token is handled differently depending on whether it is in a ?else expression or an if-else construct\n        case EidosTokenType::kTokenElse:\n            forceSpace = true;\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceSpace = true;\n            if (insideTernaryConditionalCount)\n                --insideTernaryConditionalCount;\n            else if (NextSignificantToken(tokens, tokenIndex).token_type_ != EidosTokenType::kTokenIf)\n                forceNewlineCount = 1;\n            break;\n            \n            // The function token, for user-defined functions, is particularly tricky since it initiates a signature\n            // We handle this by going into a special mode that chews through the signature declaration\n        case EidosTokenType::kTokenFunction:\n            EmitWhitespace(forceSpace, forceNewlineCount, pretty);\n            pretty.append(tokenString);\n            forceSpace = true;\n            functionDeclarationCountdown = 2;   // we will require two close-out right parens to finish the declaration\n            break;\n        }\n        \n        if (tokenType != EidosTokenType::kTokenWhitespace)\n        {\n            lastTokenContainedNewline = false;\n            lastTokenSuppressesCommentSpacing = nextLastTokenSuppressesCommentSpacing;\n        }\n    }\n    \n    // We're done reformatting; now we need to generate a new script and a new token stream, and fix the indentation of our\n    // reformatted string by calling Eidos_prettyprintTokensFromScript(); this avoids duplicating a bunch of logic\n    try {\n        EidosScript indentScript(pretty);\n        \n        indentScript.Tokenize(false, true);\t// get whitespace and comment tokens\n        \n        const std::vector<EidosToken> &indentTokens = indentScript.Tokens();\n        std::string pretty_indented;\n        bool success = false;\n        \n        success = Eidos_prettyprintTokensFromScript(indentTokens, indentScript, pretty_indented);\n        \n        if (success)\n            pretty = pretty_indented;\n        else\n            return false;\n    }\n    catch (...)\n    {\n        qDebug() << \"Reformatted code no longer parsed!\";\n        return false;\n    }\n    \n    return true;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMEidosPrettyprinter.h",
    "content": "//\n//  QtSLiMEidosPrettyprinter.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/1/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMEIDOSPRETTYPRINTER_H\n#define QTSLIMEIDOSPRETTYPRINTER_H\n\n\n#include <string>\n#include <eidos_token.h>\n\nclass EidosScript;\n\n\n// Generate a prettyprinted script string into parameter pretty, from the tokens and script supplied\nbool Eidos_prettyprintTokensFromScript(const std::vector<EidosToken> &tokens, EidosScript &tokenScript, std::string &pretty);\n\nbool Eidos_reformatTokensFromScript(const std::vector<EidosToken> &tokens, EidosScript &tokenScript, std::string &pretty);\n\n\n#endif // QTSLIMEIDOSPRETTYPRINTER_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMExtras.cpp",
    "content": "//\n//  QtSLiMExtras.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/28/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMExtras.h\"\n\n#include <QTimer>\n#include <QTextCharFormat>\n#include <QAction>\n#include <QButtonGroup>\n#include <QDialog>\n#include <QDialogButtonBox>\n#include <QSizePolicy>\n#include <QGridLayout>\n#include <QLabel>\n#include <QPointer>\n#include <QLineEdit>\n#include <QSpacerItem>\n#include <QVBoxLayout>\n#include <QPaintEvent>\n#include <QStyleOption>\n#include <QStyle>\n#include <QTextDocument>\n#include <QAbstractTextDocumentLayout>\n#include <QPalette>\n#include <QApplication>\n#include <QDateTime>\n#include <QGuiApplication>\n#include <QScreen>\n#include <QWindow>\n#include <QDebug>\n#include <cmath>\n\n#include <string>\n#include <algorithm>\n\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMAppDelegate.h\"\n\n#include \"eidos_value.h\"\n\n\nbool QtSLiMIsMostlyOnScreen(QWidget *window)\n{\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))\n    QRect f = window->frameGeometry();\n    QScreen *screen1 = QGuiApplication::screenAt(f.topLeft());\n    QScreen *screen2 = QGuiApplication::screenAt(f.topRight());\n    QScreen *screen3 = QGuiApplication::screenAt(f.bottomLeft());\n    QScreen *screen4 = QGuiApplication::screenAt(f.bottomRight());\n    QScreen *screen5 = QGuiApplication::screenAt(f.center());\n    int cornerCount = (!!screen1) + (!!screen2) + (!!screen3) + (!!screen4);\n    if (!screen5) cornerCount = 0;\n    return (cornerCount >= 2);\n#else\n    Q_UNUSED(window);\n    return true;\n#endif\n}\n\nvoid QtSLiMRelocateQuietly(QWidget *window)\n{\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))\n    QScreen *primary = QGuiApplication::primaryScreen();\n    QRect avail = primary ? primary->availableGeometry() : QRect(0,0,1024,768);\n    window->resize(window->size().boundedTo(avail.size()));\n    window->move(avail.topLeft() + QPoint(50, 50));\n#else\n    Q_UNUSED(window);\n#endif\n}\n\nvoid QtSLiMMakeWindowVisibleAndExposed(QWidget *window)\n{\n    // we've had lots of problems in SLiMgui with windows not showing when the user expects them to show; this function\n    // is intended to mitigate those issues by doing EVERYTHING we can to make the window visible and exposed.\n    if (!window->isWindow())\n    {\n        qDebug() << \"The widget\" << window << \"is not a window!\";\n        return;\n    }\n    \n    // if there is a window other than us that is full-screen, we might have trouble getting in front of it\n    // I'm not sure how this is normally dealt with by operating systems, since I never use full-screen mode\n    // on macOS it seems to work OK; the new window goes full-screen also, in front of the other, which\n    // I assume is the standard behavior...?  I'll wait for reported bugs on this one, I don't know.  FIXME\n\n    // Fullscreen note: on Windows, \"fullscreen\" often means a borderless maximized window that can be\n    // overlaid by another normal window that calls show/raise/activate. We intentionally do that here so\n    // SLiMgui presents visibly on the current screen if possible, without minimizing/altering other apps.\n    // If the window still isn't exposed (e.g., truly exclusive fullscreen), we will attempt relocation to\n    // another monitor after a short delay; if that also fails, we flash the app icon to notify the user. -Chris\n\n    // Still unclear how this will behave on Linux systems, hopefuly the same as macOS?\n    \n    // un-miniaturize the window if it is miniaturized\n    if (window->windowState() & Qt::WindowMinimized)\n        window->setWindowState((window->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);\n    \n    // the standard Qt litany for making a window rise to front: show, raise, activate\n    window->show();\n    window->raise();\n    window->activateWindow();\n    \n    // If not sufficiently visible, relocate to a safe point on the primary screen\n    if (!QtSLiMIsMostlyOnScreen(window))\n        QtSLiMRelocateQuietly(window);\n\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))\n    // If still not actually exposed (e.g., exclusive fullscreen), re-check shortly and then try other screens\n    if (QWindow *w = window->windowHandle())\n    {\n        if (!w->isExposed())\n        {\n            QPointer<QWidget> safeWindow(window);\n            QTimer::singleShot(200, qApp, [safeWindow]() {\n                if (!safeWindow)\n                    return;\n                QWidget *win = safeWindow.data();\n                QWindow *wh = win->windowHandle();\n                if (!wh)\n                    return;\n                if (wh->isExposed())\n                    return;    // became exposed in the meantime; do nothing\n\n                QScreen *currentScreen = QGuiApplication::screenAt(win->frameGeometry().center());\n                const QList<QScreen*> screens = QGuiApplication::screens();\n                for (QScreen *screen : screens)\n                {\n                    if (screen == currentScreen)\n                        continue;\n                    QRect avail = screen->availableGeometry();\n                    win->move(avail.topLeft() + QPoint(50, 50));\n                    win->raise();\n                    win->activateWindow();\n                    if (wh->isExposed())\n                        return;\n                }\n                // If we still are not exposed anywhere, alert the user via taskbar/dock\n                qApp->alert(win);\n            });\n        }\n    }\n#endif\n}\n\nvoid QtSLiMClearLayout(QLayout *layout, bool deleteWidgets)\n{\n    // this code from https://stackoverflow.com/a/7077340/2752221\n    // thanks to stackoverflow user Darko Maksimovic\n    while (QLayoutItem *item = layout->takeAt(0))\n    {\n        if (deleteWidgets)\n        {\n            if (QWidget *widget = item->widget())\n                widget->deleteLater();\n        }\n        if (QLayout *childLayout = item->layout())\n            QtSLiMClearLayout(childLayout, deleteWidgets);\n        delete item;\n    }\n}\n\nvoid QtSLiMFrameRect(const QRect &p_rect, const QColor &p_color, QPainter &p_painter)\n{\n    p_painter.fillRect(QRect(p_rect.left(), p_rect.top(), p_rect.width(), 1), p_color);                                 // top edge\n    p_painter.fillRect(QRect(p_rect.left(), p_rect.top() + 1, 1, p_rect.height() - 2), p_color);                        // left edge (without corner pixels)\n    p_painter.fillRect(QRect(p_rect.left() + p_rect.width() - 1, p_rect.top() + 1, 1, p_rect.height() - 2), p_color);   // right edge (without corner pixels)\n    p_painter.fillRect(QRect(p_rect.left(), p_rect.top() + p_rect.height() - 1, p_rect.width(), 1), p_color);           // bottom edge\n}\n\nvoid QtSLiMFrameRect(const QRectF &p_rect, const QColor &p_color, QPainter &p_painter, double w)\n{\n    p_painter.fillRect(QRectF(p_rect.left(), p_rect.top(), p_rect.width(), w), p_color);\n    p_painter.fillRect(QRectF(p_rect.left(), p_rect.top() + w, w, p_rect.height() - 2*w), p_color);\n    p_painter.fillRect(QRectF(p_rect.left() + p_rect.width() - w, p_rect.top() + w, w, p_rect.height() - 2*w), p_color);\n    p_painter.fillRect(QRectF(p_rect.left(), p_rect.top() + p_rect.height() - w, p_rect.width(), w), p_color);\n}\n\nQColor QtSLiMColorWithWhite(double p_white, double p_alpha)\n{\n    QColor color;\n    color.setRgbF(p_white, p_white, p_white, p_alpha);\n    return color;\n}\n\nQColor QtSLiMColorWithRGB(double p_red, double p_green, double p_blue, double p_alpha)\n{\n    QColor color;\n    color.setRgbF(p_red, p_green, p_blue, p_alpha);\n    return color;\n}\n\nQColor QtSLiMColorWithHSV(double p_hue, double p_saturation, double p_value, double p_alpha)\n{\n    QColor color;\n    color.setHsvF(p_hue, p_saturation, p_value, p_alpha);\n    return color;\n}\n\n\nbool QtSLiMInDarkMode(void)\n{\n    // We determine whether we're in dark mode heuristically: if the window background color is darker than 50% gray\n    // We don't attempt to cache this value, since it sounds like the change notification for this is buggy\n    QColor windowColor = QPalette().color(QPalette::Window);\n    double windowBrightness = 0.21 * windowColor.redF() + 0.72 * windowColor.greenF() + 0.07 * windowColor.blueF();\n    \n    return (windowBrightness < 0.5);\n}\n\nQString QtSLiMImagePath(QString baseName, bool highlighted)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    baseName = (inDarkMode ? \":/buttons_DARK/\" : \":/buttons/\") + baseName;\n    \n    if (highlighted)\n        baseName += \"_H\";\n    if (inDarkMode)\n        baseName += \"_DARK\";\n    baseName += \".png\";\n    \n    return baseName;\n}\n\n\nconst double greenBrightness = 0.8;\n\nvoid RGBForFitness(double value, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor)\n{\n\t// apply the scaling factor\n\tvalue = (value - 1.0) * scalingFactor + 1.0;\n\t\n\tif (value <= 0.5)\n\t{\n\t\t// value <= 0.5 is a shade of red, going down to black\n\t\t*colorRed = static_cast<float>(value * 2.0);\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value >= 2.0)\n\t{\n\t\t// value >= 2.0 is a shade of green, going up to white\n\t\t*colorRed = static_cast<float>((value - 2.0) * greenBrightness / value);\n\t\t*colorGreen = static_cast<float>(greenBrightness);\n\t\t*colorBlue = static_cast<float>((value - 2.0) * greenBrightness / value);\n\t}\n\telse if (value <= 1.0)\n\t{\n\t\t// value <= 1.0 (but > 0.5) goes from red (unfit) to yellow (neutral)\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = static_cast<float>((value - 0.5) * 2.0);\n\t\t*colorBlue = 0.0;\n\t}\n\telse\t// 1.0 < value < 2.0\n\t{\n\t\t// value > 1.0 (but < 2.0) goes from yellow (neutral) to green (fit)\n\t\t*colorRed = static_cast<float>(2.0 - value);\n\t\t*colorGreen = static_cast<float>(greenBrightness + (1.0 - greenBrightness) * (2.0 - value));\n\t\t*colorBlue = 0.0;\n\t}\n}\n\nvoid RGBForSelectionCoeff(double value, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor)\n{\n\t// apply a scaling factor; this could be user-adjustible since different models have different relevant fitness ranges\n\tvalue *= scalingFactor;\n\t\n\t// and add 1, just so we can re-use the same code as in RGBForFitness()\n\tvalue += 1.0;\n\t\n\tif (value <= 0.0)\n\t{\n\t\t// value <= 0.0 is the darkest shade of red we use\n\t\t*colorRed = 0.5;\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value <= 0.5)\n\t{\n\t\t// value <= 0.5 is a shade of red, going down toward black\n\t\t*colorRed = static_cast<float>(value + 0.5);\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value < 1.0)\n\t{\n\t\t// value <= 1.0 (but > 0.5) goes from red (very unfit) to orange (nearly neutral)\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = static_cast<float>((value - 0.5) * 1.0);\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value == 1.0)\n\t{\n\t\t// exactly neutral mutations are yellow\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = 1.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value <= 1.5)\n\t{\n\t\t// value > 1.0 (but < 1.5) goes from green (nearly neutral) to cyan (fit)\n\t\t*colorRed = 0.0;\n\t\t*colorGreen = static_cast<float>(greenBrightness);\n\t\t*colorBlue = static_cast<float>((value - 1.0) * 2.0);\n\t}\n\telse if (value <= 2.0)\n\t{\n\t\t// value > 1.5 (but < 2.0) goes from cyan (fit) to blue (very fit)\n\t\t*colorRed = 0.0;\n\t\t*colorGreen = static_cast<float>(greenBrightness * ((2.0 - value) * 2.0));\n\t\t*colorBlue = 1.0;\n\t}\n\telse // (value > 2.0)\n\t{\n\t\t// value > 2.0 is a shade of blue, going up toward white\n\t\t*colorRed = static_cast<float>((value - 2.0) * 0.75 / value);\n\t\t*colorGreen = static_cast<float>((value - 2.0) * 0.75 / value);\n\t\t*colorBlue = 1.0;\n\t}\n}\n\nQtSLiMColorScaleWidget::QtSLiMColorScaleWidget(QWidget *p_parent) : QWidget(p_parent),\n    fitnessTicks({\"0.0\", \"0.5\", \"1.0\", \"1.5\", \"2.0\"}),\n    effectTicks({\"-1.0\", \"-0.5\", \"0.0\", \"0.5\", \"1.0\"})\n{\n    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);\n}\n\nvoid QtSLiMColorScaleWidget::paintEvent(QPaintEvent * /*p_paintEvent*/)\n{\n    // we're designed to fit in a fixed size of 301 x 197; see dispatch_showColorScales()\n    //QRect overallRect = contentsRect();\n    QPainter painter(this);\n    QRect stripe1 = QRect(15, 33, 271, 20);     // odd width so we have a central pixel of exactly yellow\n    QRect stripe2 = QRect(15, 105, 271, 20);    // odd width so we have a central pixel of exactly yellow\n    \n    static QFont *labelFont = nullptr;\n    \n    if (!labelFont)\n    {\n        labelFont = new QFont();\n#ifdef __linux__\n        labelFont->setPointSize(10);\n#else\n        labelFont->setPointSize(12);\n#endif\n        labelFont->setBold(true);\n    }\n    painter.setFont(*labelFont);\n    \n    const double labelYOffset = -8;\n    \n    // Fitness color scale\n    painter.drawText(stripe1.x(), stripe1.y() + labelYOffset, \"Individual fitness scale:\");\n    \n    for (int x = stripe1.left() + 1; x <= (stripe1.left() + 1) + (stripe1.width() - 3); ++x)\n    {\n        const double scalingFactor = 0.8;   // this is constant in QtSLiM; there used to be a slider\n        QRect sliver(x, stripe1.top() + 1, 1, stripe1.height() - 2);\n        double sliverFraction = (x - (stripe1.left() + 1)) / (stripe1.width() - 3.0);\n        double fitness = sliverFraction * 2.0;     // cover fitness values of 0.0 to 2.0\n        float r, g, b;\n        RGBForFitness(fitness, &r, &g, &b, scalingFactor);\n        painter.fillRect(sliver, QColor(round(r * 255), round(g * 255), round(b * 255)));\n    }\n    \n    QtSLiMFrameRect(stripe1, Qt::black, painter);\n    \n    // Mutation effect color scale\n    painter.drawText(stripe2.x(), stripe2.y() + labelYOffset, \"Mutation effect scale:\");\n    \n    for (int x = stripe2.left() + 1; x <= (stripe2.left() + 1) + (stripe2.width() - 3); ++x)\n    {\n        const double scalingFactor = 0.8;   // this is constant in QtSLiM; there used to be a slider\n        QRect sliver(x, stripe2.top() + 1, 1, stripe2.height() - 2);\n        double sliverFraction = (x - (stripe2.left() + 1)) / (stripe2.width() - 3.0);\n        double fitness = sliverFraction * 2.0 - 1;     // cover mutation effect values of -1.0 to 1.0\n        float r, g, b;\n        RGBForSelectionCoeff(fitness, &r, &g, &b, scalingFactor);\n        painter.fillRect(sliver, QColor(round(r * 255), round(g * 255), round(b * 255)));\n        \n        //qDebug() << \"x =\" << x << \" << sliverFraction =\" << sliverFraction << \" fitness =\" << fitness;\n    }\n    \n    QtSLiMFrameRect(stripe2, Qt::black, painter);\n    \n    // Draw axis scales\n    static QFont *tickFont = nullptr;\n    \n    if (!tickFont)\n    {\n        tickFont = new QFont();\n#ifdef __linux__\n        tickFont->setPointSize(8);\n#else\n        tickFont->setPointSize(10);\n#endif\n    }\n    painter.setFont(*tickFont);\n    \n    QFontMetricsF fontMetrics(*tickFont);\n    \n    for (int tickIndex = 0; tickIndex < 5; tickIndex++)\n    {\n        bool longTick = (tickIndex % 2 == 0);\n        int tickX = round(stripe1.left() + 1 + (tickIndex / 4.0) * (stripe1.width() - 3.0));\n        QString tickLabel;\n        double tickLabelWidth;\n        \n        // label stripe 1\n        tickLabel = fitnessTicks[tickIndex];\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        tickLabelWidth = fontMetrics.width(tickLabel);               // deprecated in 5.11\n#else\n        tickLabelWidth = fontMetrics.horizontalAdvance(tickLabel);   // added in Qt 5.11\n#endif\n        \n        painter.fillRect(tickX, stripe1.bottom() + 1, 1, longTick ? 4 : 2, Qt::black);\n        painter.drawText(QPointF(tickX - tickLabelWidth / 2.0 + 1, stripe1.bottom() + 16), tickLabel);\n        \n        // label stripe 2\n        tickLabel = effectTicks[tickIndex];\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        tickLabelWidth = fontMetrics.width(tickLabel);               // deprecated in 5.11\n#else\n        tickLabelWidth = fontMetrics.horizontalAdvance(tickLabel);   // added in Qt 5.11\n#endif\n        \n        painter.fillRect(tickX, stripe2.bottom() + 1, 1, longTick ? 4 : 2, Qt::black);\n        painter.drawText(QPointF(tickX - tickLabelWidth / 2.0 + 1, stripe2.bottom() + 16), tickLabel);\n    }\n    \n    // add final notes in italic\n    static QFont *noteFont = nullptr;\n    \n    if (!noteFont)\n    {\n        noteFont = new QFont();\n#ifdef __linux__\n        noteFont->setPointSize(9);\n#else\n        noteFont->setPointSize(11);\n#endif\n        noteFont->setItalic(true);\n    }\n    painter.setFont(*noteFont);\n    \n    painter.drawText(stripe1.x(), stripe2.bottom() + 44, \"Yellow indicates neutrality on both color scales.\");\n    painter.drawText(stripe1.x(), stripe2.bottom() + 58, \"Both scales fade out to white for large values.\");\n}\n\n// A subclass of QLineEdit that selects all its text when it receives keyboard focus\n// thanks to https://stackoverflow.com/a/51807268/2752221\nQtSLiMGenerationLineEdit::QtSLiMGenerationLineEdit(const QString &contents, QWidget *p_parent) : QLineEdit(contents, p_parent)\n{\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, [this]() { _ReconfigureAppearance(); });\n    _ReconfigureAppearance();\n}\n\nQtSLiMGenerationLineEdit::QtSLiMGenerationLineEdit(QWidget *p_parent) : QLineEdit(p_parent)\n{\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, [this]() { _ReconfigureAppearance(); });\n    _ReconfigureAppearance();\n}\n\nQtSLiMGenerationLineEdit::~QtSLiMGenerationLineEdit() {}\n\nvoid QtSLiMGenerationLineEdit::focusInEvent(QFocusEvent *p_event)\n{\n    // First let the base class process the event\n    QLineEdit::focusInEvent(p_event);\n    \n    // Then select the text by a single shot timer, so that everything will\n    // be processed before (calling selectAll() directly won't work)\n    QTimer::singleShot(0, this, &QLineEdit::selectAll);\n}\n\nvoid QtSLiMGenerationLineEdit::setProgress(double p_progress)\n{\n    double newProgress = std::min(std::max(p_progress, 0.0), 1.0);\n    \n    if (newProgress != progress)\n    {\n        progress = newProgress;\n        update();\n    }\n}\n\nvoid QtSLiMGenerationLineEdit::_ReconfigureAppearance()\n{\n    // Eight states, based on three binary flags; but two states never happen in practice\n    bool darkMode = QtSLiMInDarkMode();\n    bool enabled = isEnabled();\n    \n    if (darkMode)\n    {\n        if (enabled)\n        {\n            if (dimmed)\n                setStyleSheet(\"color: red;  background-color: black\");                  // doesn't happen\n            else\n                setStyleSheet(\"color: rgb(255, 255, 255);  background-color: black\");   // not playing\n        }\n        else\n        {\n            if (dimmed)\n                setStyleSheet(\"color: rgb(40, 40, 40);  background-color: black\");      // error state (not normally visible)\n            else\n                setStyleSheet(\"color: rgb(170, 170, 170);  background-color: black\");   // playing\n        }\n    }\n    else\n    {\n        if (enabled)\n        {\n            if (dimmed)\n                setStyleSheet(\"color: red;  background-color: white\");                  // doesn't happen\n            else\n                setStyleSheet(\"color: rgb(0, 0, 0);  background-color: white\");         // not playing\n        }\n        else\n        {\n            if (dimmed)\n                setStyleSheet(\"color: rgb(192, 192, 192);  background-color: white\");   // error state (not normally visible)\n            else\n                setStyleSheet(\"color: rgb(120, 120, 120);  background-color: white\");   // playing\n        }\n    }\n    \n    update();\n}\n\nvoid QtSLiMGenerationLineEdit::setAppearance(bool p_enabled, bool p_dimmed)\n{\n    if ((isEnabled() != p_enabled) || (dimmed != p_dimmed))\n    {\n        setEnabled(p_enabled);\n        dimmed = p_dimmed;\n        \n        _ReconfigureAppearance();\n    }\n}\n\nvoid QtSLiMGenerationLineEdit::paintEvent(QPaintEvent *p_paintEvent)\n{\n    // first let super draw\n    QLineEdit::paintEvent(p_paintEvent);\n    \n    // then overlay a progress bar on top, if requested, and if we are not disabled & dimmed (error state)\n    bool enabled = isEnabled();\n    \n    if (!enabled && dimmed)\n        return;\n    \n    if (progress > 0.0)\n    {\n        bool darkMode = QtSLiMInDarkMode();\n        QPainter painter(this);\n        QRect bounds = rect().adjusted(2, 2, -2, -2);\n        \n        bounds.setWidth(round(bounds.width() * progress));\n        \n        if (darkMode) {\n            // lighten the black background to a dark green; text is unaffected since it's light\n            painter.setCompositionMode(QPainter::CompositionMode_Lighten);\n            painter.fillRect(bounds, QColor(0, 120, 0));\n        } else {\n            // darken the white background to a light green; text is unaffected since it's dark\n            painter.setCompositionMode(QPainter::CompositionMode_Darken);\n            painter.fillRect(bounds, QColor(180, 255, 180));\n        }\n    }\n}\n\nvoid ColorizePropertySignature(const EidosPropertySignature *property_signature, double pointSize, QTextCursor lineCursor)\n{\n    //\n    //\tNote this logic is paralleled in the function operator<<(ostream &, const EidosPropertySignature &).\n    //\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n    //\n    QString docSigString = lineCursor.selectedText();\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    QTextCharFormat ttFormat;\n    QFont displayFont(prefs.displayFontPref());\n    displayFont.setPointSizeF(pointSize);\n    ttFormat.setFont(displayFont);\n    lineCursor.setCharFormat(ttFormat);\n    \n    bool inDarkMode = QtSLiMInDarkMode();\n    QTextCharFormat functionAttrs(ttFormat), typeAttrs(ttFormat);\n    functionAttrs.setForeground(QBrush(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207)));\n    typeAttrs.setForeground(QBrush(inDarkMode ? QColor(90, 210, 90) : QColor(0, 116, 0)));\n    \n    QTextCursor propertyNameCursor(lineCursor);\n    propertyNameCursor.setPosition(lineCursor.anchor(), QTextCursor::MoveAnchor);\n    propertyNameCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, static_cast<int>(property_signature->property_name_.length()));\n    propertyNameCursor.setCharFormat(functionAttrs);\n    \n    int nameLength = QString::fromStdString(property_signature->property_name_).length();\n    int connectorLength = QString::fromStdString(property_signature->PropertySymbol()).length();\n    int typeLength = docSigString.length() - (nameLength + 4 + connectorLength);\n    QTextCursor typeCursor(lineCursor);\n    typeCursor.setPosition(lineCursor.position(), QTextCursor::MoveAnchor);\n    typeCursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1);\n    typeCursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, typeLength);\n    typeCursor.setCharFormat(typeAttrs);\n}\n\nvoid ColorizeCallSignature(const EidosCallSignature *call_signature, double pointSize, QTextCursor lineCursor)\n{\n    //\n    //\tNote this logic is paralleled in the function operator<<(ostream &, const EidosCallSignature &).\n    //\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n    //\n    QString docSigString = lineCursor.selectedText();\n    std::ostringstream ss;\n    ss << *call_signature;\n    QString callSigString = QString::fromStdString(ss.str());\n    \n    if (callSigString.endsWith(\" <SLiM>\") && !docSigString.endsWith(\" <SLiM>\"))\n        callSigString.chop(7);\n    \n    if (docSigString != callSigString)\n    {\n        qDebug() << \"*** \" << ((call_signature->CallPrefix().length() > 0) ? \"method\" : \"function\") << \"signature mismatch:\\nold:\" << docSigString << \"\\nnew:\" << callSigString;\n        return;\n    }\n    \n    // the signature conforms to expectations, so we can colorize it\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    QTextCharFormat ttFormat;\n    QFont displayFont(prefs.displayFontPref());\n    displayFont.setPointSizeF(pointSize);\n    ttFormat.setFont(displayFont);\n    lineCursor.setCharFormat(ttFormat);\n    \n    bool inDarkMode = QtSLiMInDarkMode();\n    QTextCharFormat typeAttrs(ttFormat), functionAttrs(ttFormat), paramAttrs(ttFormat);\n    typeAttrs.setForeground(QBrush(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207)));\n    functionAttrs.setForeground(QBrush(inDarkMode ? QColor(90, 210, 90) : QColor(0, 116, 0)));\n    paramAttrs.setForeground(QBrush(inDarkMode ? QColor(220, 83, 185) : QColor(170, 13, 145)));\n    \n    int prefix_string_len = QString::fromStdString(call_signature->CallPrefix()).length();\n    int return_type_string_len = QString::fromStdString(StringForEidosValueMask(call_signature->return_mask_, call_signature->return_class_, \"\", nullptr)).length();\n    int function_name_string_len = QString::fromStdString(call_signature->call_name_).length();\n    \n    // colorize return type\n    QTextCursor scanCursor(lineCursor);\n    scanCursor.setPosition(lineCursor.anchor() + prefix_string_len + 1, QTextCursor::MoveAnchor);\n    scanCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, return_type_string_len);\n    scanCursor.setCharFormat(typeAttrs);\n    \n    // colorize call name\n    scanCursor.setPosition(scanCursor.position() + 1, QTextCursor::MoveAnchor);\n    scanCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, function_name_string_len);\n    scanCursor.setCharFormat(functionAttrs);\n    \n    scanCursor.setPosition(scanCursor.position() + 1, QTextCursor::MoveAnchor);\n    \n    // colorize arguments\n    size_t arg_mask_count = call_signature->arg_masks_.size();\n    \n    if (arg_mask_count == 0)\n    {\n        // colorize \"void\"\n        scanCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 4);\n        scanCursor.setCharFormat(typeAttrs);\n    }\n    else\n    {\n        for (size_t arg_index = 0; arg_index < arg_mask_count; ++arg_index)\n        {\n            EidosValueMask type_mask = call_signature->arg_masks_[arg_index];\n            const std::string &arg_name = call_signature->arg_names_[arg_index];\n            const EidosClass *arg_obj_class = call_signature->arg_classes_[arg_index];\n            EidosValue_SP arg_default = call_signature->arg_defaults_[arg_index];\n            \n            // skip private arguments\n            if ((arg_name.length() >= 1) && (arg_name[0] == '_'))\n                continue;\n            \n            scanCursor.setPosition(scanCursor.position() + ((arg_index > 0) ? 2 : 0), QTextCursor::MoveAnchor);     // \", \"\n            \n            //\n            //\tNote this logic is paralleled in the function StringForEidosValueMask().\n            //\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n            //\n            if (arg_name == gEidosStr_ELLIPSIS)\n            {\n                scanCursor.setPosition(scanCursor.position() + 3, QTextCursor::MoveAnchor);     // \"...\"\n                continue;\n            }\n            \n            bool is_optional = !!(type_mask & kEidosValueMaskOptional);\n            bool requires_singleton = !!(type_mask & kEidosValueMaskSingleton);\n            EidosValueMask stripped_mask = type_mask & kEidosValueMaskFlagStrip;\n            int typeLength = 0;\n            \n            if (is_optional)\n                scanCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);     // \"[\"\n            \n            if (stripped_mask == kEidosValueMaskNone)               typeLength = 1;     // \"?\"\n            else if (stripped_mask == kEidosValueMaskAny)           typeLength = 1;     // \"*\"\n            else if (stripped_mask == kEidosValueMaskAnyBase)       typeLength = 1;     // \"+\"\n            else if (stripped_mask == kEidosValueMaskVOID)          typeLength = 4;     // \"void\"\n            else if (stripped_mask == kEidosValueMaskNULL)          typeLength = 4;     // \"NULL\"\n            else if (stripped_mask == kEidosValueMaskLogical)       typeLength = 7;     // \"logical\"\n            else if (stripped_mask == kEidosValueMaskString)        typeLength = 6;     // \"string\"\n            else if (stripped_mask == kEidosValueMaskInt)           typeLength = 7;     // \"integer\"\n            else if (stripped_mask == kEidosValueMaskFloat)         typeLength = 5;     // \"float\"\n            else if (stripped_mask == kEidosValueMaskObject)        typeLength = 6;     // \"object\"\n            else if (stripped_mask == kEidosValueMaskNumeric)       typeLength = 7;     // \"numeric\"\n            else\n            {\n                if (stripped_mask & kEidosValueMaskVOID)            typeLength++;     // \"v\"\n                if (stripped_mask & kEidosValueMaskNULL)            typeLength++;     // \"N\"\n                if (stripped_mask & kEidosValueMaskLogical)         typeLength++;     // \"l\"\n                if (stripped_mask & kEidosValueMaskInt)             typeLength++;     // \"i\"\n                if (stripped_mask & kEidosValueMaskFloat)           typeLength++;     // \"f\"\n                if (stripped_mask & kEidosValueMaskString)          typeLength++;     // \"s\"\n                if (stripped_mask & kEidosValueMaskObject)          typeLength++;     // \"o\"\n            }\n            \n            if (arg_obj_class && (stripped_mask & kEidosValueMaskObject))\n            {\n                int obj_type_name_len = QString::fromStdString(arg_obj_class->ClassNameForDisplay()).length();\n                \n                typeLength += (obj_type_name_len + 2);  // \"<\" obj_type_name \">\"\n            }\n            \n            if (requires_singleton)\n                typeLength++;     // \"$\"\n            \n            scanCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, typeLength);\n            scanCursor.setCharFormat(typeAttrs);\n            scanCursor.setPosition(scanCursor.position(), QTextCursor::MoveAnchor);\n            \n            if (arg_name.length() > 0)\n            {\n                scanCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);    // \" \"\n                scanCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, QString::fromStdString(arg_name).length());\n                scanCursor.setCharFormat(paramAttrs);\n                scanCursor.setPosition(scanCursor.position(), QTextCursor::MoveAnchor);\n            }\n            \n            if (is_optional)\n            {\n                if (arg_default && (arg_default != gStaticEidosValueNULLInvisible.get()))\n                {\n                    scanCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 3);    // \" = \"\n                    \n                    std::ostringstream default_string_stream;\n                    \n                    arg_default->Print(default_string_stream);\n                    \n                    int default_string_len = QString::fromStdString(default_string_stream.str()).length();\n                    \n                    scanCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, default_string_len);\n                }\n                \n                scanCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1);    // \"]\"\n            }\n        }\n    }\n}\n\n\n// A subclass of QHBoxLayout specifically designed to lay out the play controls in the main window\n\nQtSLiMPlayControlsLayout::~QtSLiMPlayControlsLayout()\n{\n}\n\nQSize QtSLiMPlayControlsLayout::sizeHint() const\n{\n    QSize size(0,0);\n    int n = count();\n    \n    for (int i = 0; i < n; ++i)\n    {\n        if (i == 2)\n            continue;     // the profile button takes no space\n        \n        QLayoutItem *layoutItem = itemAt(i);\n        QSize itemSizeHint = layoutItem->sizeHint();\n        \n        size.rwidth() += itemSizeHint.width();\n        size.rheight() = std::max(size.height(), itemSizeHint.height());\n    }\n    \n    size.rwidth() += (n - 2) * spacing();   // -2 because we exclude spacing for the profile button\n    \n    return size;\n}\n\nQSize QtSLiMPlayControlsLayout::minimumSize() const\n{\n    QSize size(0,0);\n    int n = count();\n    \n    for (int i = 0; i < n; ++i)\n    {\n        if (i == 2)\n            continue;     // the profile button takes no space\n        \n        QLayoutItem *layoutItem = itemAt(i);\n        QSize itemMinimumSize = layoutItem->minimumSize();\n        \n        size.rwidth() += itemMinimumSize.width();\n        size.rheight() = std::max(size.height(), itemMinimumSize.height());\n    }\n    \n    size.rwidth() += (n - 2) * spacing();   // -2 because we exclude spacing for the profile button\n    \n    return size;\n}\n\nvoid QtSLiMPlayControlsLayout::setGeometry(const QRect &rect)\n{\n    QHBoxLayout::setGeometry(rect);\n    \n    int n = count();\n    int position = rect.x();\n    QRect playButtonRect;\n    \n    for (int i = 0; i < n; ++i)\n    {\n        if (i == 2)\n            continue;     // the profile button takes no space\n        \n        QLayoutItem *layoutItem = itemAt(i);\n        QSize itemSizeHint = layoutItem->sizeHint();\n        QRect geom(position, rect.y(), itemSizeHint.width(), itemSizeHint.height());\n        \n        layoutItem->setGeometry(geom);\n        position += itemSizeHint.width() + spacing();\n        \n        if (i == 1)\n            playButtonRect = geom;\n    }\n    \n    // position the profile button; the button must lie inside the bounds of the parent widget due to clipping\n    QLayoutItem *profileButton = itemAt(2);\n    QSize itemSizeHint = profileButton->sizeHint();\n    QRect geom(playButtonRect.left() + playButtonRect.width() - 22, rect.y() - 6, itemSizeHint.width(), itemSizeHint.height());\n    \n    profileButton->setGeometry(geom);\n}\n\n// Heat colors for profiling display\n#define SLIM_YELLOW_FRACTION 0.10\n#define SLIM_SATURATION 0.75\n\nQColor slimColorForFraction(double fraction)\n{\n    if (fraction < SLIM_YELLOW_FRACTION)\n\t{\n\t\t// small fractions fall on a ramp from white (0.0) to yellow (SLIM_YELLOW_FRACTION)\n        return QtSLiMColorWithHSV(1.0 / 6.0, (fraction / SLIM_YELLOW_FRACTION) * SLIM_SATURATION, 1.0, 1.0);\n\t}\n\telse\n\t{\n\t\t// larger fractions ramp from yellow (SLIM_YELLOW_FRACTION) to red (1.0)\n        return QtSLiMColorWithHSV((1.0 / 6.0) * (1.0 - (fraction - SLIM_YELLOW_FRACTION) / (1.0 - SLIM_YELLOW_FRACTION)), SLIM_SATURATION, 1.0, 1.0);\n\t}\n}\n\n// Nicely formatted memory usage strings\n\nQString stringForByteCount(uint64_t bytes)\n{\n    if (bytes > 512.0 * 1024.0 * 1024.0 * 1024.0)\n\t\treturn QString(\"%1 TB\").arg(bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0), 0, 'f', 2);\n\telse if (bytes > 512.0 * 1024.0 * 1024.0)\n\t\treturn QString(\"%1 GB\").arg(bytes / (1024.0 * 1024.0 * 1024.0), 0, 'f', 2);\n\telse if (bytes > 512.0 * 1024.0)\n\t\treturn QString(\"%1 MB\").arg(bytes / (1024.0 * 1024.0), 0, 'f', 2);\n\telse if (bytes > 512.0)\n\t\treturn QString(\"%1 KB\").arg(bytes / 1024.0, 0, 'f', 2);\n\telse\n\t\treturn QString(\"%1 bytes\").arg(bytes);\n}\n\nQString attributedStringForByteCount(uint64_t bytes, double total, QTextCharFormat &format)\n{\n    QString byteString = stringForByteCount(bytes);\n\tdouble fraction = bytes / total;\n\tQColor fractionColor = slimColorForFraction(fraction);\n\t\n    // We modify format for the caller, which they can use to colorize the returned string\n    format.setBackground(fractionColor);\n    \n\treturn byteString;\n}\n\nQString slimDateline(void)\n{\n    QDateTime dateTime = QDateTime::currentDateTime();\n    QString dateTimeString = dateTime.toString(\"M/d/yy, h:mm:ss AP\");        // format: 3/28/20, 8:03:09 PM\n    \n    return QString(\"# %1\").arg(dateTimeString);\n}\n\n// Running a panel to obtain numbers from the user\n// The goal here is to avoid a proliferation of dumb forms, by programmatically generating the UI\n\nQStringList QtSLiMRunLineEditArrayDialog(QWidget *p_parent, QString title, QStringList captions, QStringList values)\n{\n    if (captions.size() < 1)\n        return QStringList();\n    if (captions.size() != values.size())\n    {\n        qDebug(\"QtSLiMRunLineEditArrayDialog: captions and values are not the same length!\");\n        return QStringList();\n    }\n    \n    // make the dialog with an overall vertical layout\n    QDialog *dialog = new QDialog(p_parent);\n    QVBoxLayout *verticalLayout = new QVBoxLayout(dialog);\n    \n    // title label\n    {\n        QLabel *titleLabel = new QLabel(dialog);\n        QFont font;\n        font.setBold(true);\n        font.setWeight(QFont::Bold);    // used to be 75, which made little sense; fixed for Qt6\n        titleLabel->setText(title);\n        titleLabel->setFont(font);\n        verticalLayout->addWidget(titleLabel);\n    }\n    \n    // below-title spacer\n    {\n        QSpacerItem *belowTitleSpacer = new QSpacerItem(20, 8, QSizePolicy::Minimum, QSizePolicy::Fixed);\n        verticalLayout->addItem(belowTitleSpacer);\n    }\n    \n    // grid layout\n    QVector<QLineEdit *> lineEdits;\n    \n    {\n        QGridLayout *gridLayout = new QGridLayout();\n        int rowCount = captions.size();\n        \n        for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)\n        {\n            QString caption = captions[rowIndex];\n            QString value = values[rowIndex];\n            \n            QLabel *paramLabel = new QLabel(dialog);\n            paramLabel->setText(caption);\n            gridLayout->addWidget(paramLabel, rowIndex, 1);\n            \n            QLineEdit *paramLineEdit = new QLineEdit(dialog);\n            paramLineEdit->setText(value);\n            paramLineEdit->setFixedWidth(60);\n            paramLineEdit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);\n            gridLayout->addWidget(paramLineEdit, rowIndex, 3);\n            \n            lineEdits.push_back(paramLineEdit);\n        }\n        \n        // spacers, which only need to exist in the first row of the grid\n        {\n            QSpacerItem *leftMarginSpacer = new QSpacerItem(16, 5, QSizePolicy::Fixed, QSizePolicy::Minimum);\n            gridLayout->addItem(leftMarginSpacer, 0, 0);\n        }\n        {\n            QSpacerItem *internalSpacer = new QSpacerItem(20, 5, QSizePolicy::Fixed, QSizePolicy::Minimum);\n            gridLayout->addItem(internalSpacer, 0, 2);\n        }\n        \n        verticalLayout->addLayout(gridLayout);\n    }\n    \n    // button box\n    {\n        QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);\n        buttonBox->setOrientation(Qt::Horizontal);\n        buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);\n        verticalLayout->addWidget(buttonBox);\n        \n        QObject::connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);\n        QObject::connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);\n    }\n    \n    // fix sizing\n    dialog->setFixedSize(dialog->sizeHint());\n    dialog->setSizeGripEnabled(false);\n    \n    // select the first lineEdit and run the dialog\n    lineEdits[0]->selectAll();\n    \n    int result = dialog->exec();\n    \n    if (result == QDialog::Accepted)\n    {\n        QStringList returnList;\n        \n        for (QLineEdit *lineEdit : static_cast<const QVector<QLineEdit *> &>(lineEdits))\n            returnList.append(lineEdit->text());\n        \n        delete dialog;\n        return returnList;\n    }\n    else\n    {\n        delete dialog;\n        return QStringList();\n    }\n}\n\n\n// A subclass of QPushButton that draws its image with antialiasing, for a better appearance; used for the About panel\n// See QtSLiMPushButton below for further comments; it uses the same approach, with additional bells and whistles\nvoid QtSLiMIconView::paintEvent(QPaintEvent * /* p_paintEvent */)\n{\n    QPainter painter(this);\n    QRect bounds = rect();\n    \n    // This uses the icon to draw, which works because of Qt::AA_UseHighDpiPixmaps\n    painter.save();\n    painter.setRenderHint(QPainter::SmoothPixmapTransform);\n    icon().paint(&painter, bounds, Qt::AlignCenter, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);\n    painter.restore();\n}\n\n\n// A subclass of QPushButton that draws its image at screen resolution, for a better appearance on Retina etc.\n// Turns out setting Qt::AA_UseHighDpiPixmaps fixes that issue; but this subclass also makes the buttons draw\n// correctly in Qt 5.14.2, where button icons are shifted right one pixel and then clipped in an ugly way.\n// BCH 1/18/2021: This class now has additional smarts to handle dark mode.  First of all, the base name for\n// the icon used should be set up at creation time with a call to qtslimSetIcon(), with a highlight of false,\n// presumably; for an icon of :/buttons/foo.png, that would be qtslimSetIcon(\"foo\", false).  When the icon\n// should be changed, either in its base name or highlight state, this can be changed with another such call.\n// This will lead to the use of one of four image files depending on highlight state and dark mode state:\n// :/buttons/foo.png, :/buttons/foo_H.png, :/buttons_DARK/foo_DARK.png, or :/buttons_DARK/foo_H_DARK.png.\n// If the corresponding image file does not exist, an error message will be logged to the console, and the\n// button will probably not draw properly.  All button images should be exactly the same size.\n\nQtSLiMPushButton::QtSLiMPushButton(const QIcon &p_icon, const QString &p_text, QWidget *p_parent) : QPushButton(p_icon, p_text, p_parent)\n{\n    sharedInit();\n}\n\nQtSLiMPushButton::QtSLiMPushButton(const QString &p_text, QWidget *p_parent) : QPushButton(p_text, p_parent)\n{\n    sharedInit();\n}\n\nQtSLiMPushButton::QtSLiMPushButton(QWidget *p_parent) : QPushButton(p_parent)\n{\n    sharedInit();\n}\n\nvoid QtSLiMPushButton::sharedInit(void)\n{\n    // This button class is designed to work with icon images that include a border and background,\n    // and typically include a transparent background, so we use a style sheet to enforce that\n    setStyleSheet(QString::fromUtf8(\"QPushButton:pressed {\\n\"\n                                    \"\tbackground-color: #00000000;\\n\"\n                                    \"\tborder: 0px;\\n\"\n                                    \"}\\n\"\n                                    \"QPushButton:checked {\\n\"\n                                    \"\tbackground-color: #00000000;\\n\"\n                                    \"\tborder: 0px;\\n\"\n                                    \"}\"));\n}\n\nQtSLiMPushButton::~QtSLiMPushButton(void)\n{\n    qtslimFreeCachedIcons();\n}\n\nvoid QtSLiMPushButton::qtslimFreeCachedIcons(void)\n{\n    if (qtslimIcon) { delete qtslimIcon; qtslimIcon = nullptr; }\n    if (qtslimIcon_H) { delete qtslimIcon_H; qtslimIcon_H = nullptr; }\n    if (qtslimIcon_DARK) { delete qtslimIcon_DARK; qtslimIcon_DARK = nullptr; }\n    if (qtslimIcon_H_DARK) { delete qtslimIcon_H_DARK; qtslimIcon_H_DARK = nullptr; }\n}\n\nbool QtSLiMPushButton::hitButton(const QPoint &mousePosition) const\n{\n    // I noticed that mouse tracking in QtSLiMPushButton was off; it seemed like the bounds were\n    // kind of inset, and Qt doesn't know the buttons are circular, and so forth.  Therefore this.\n    \n    // mousePosition is in the same coordinate system as rect(); we want to consider mousePosition\n    // to be a hit if it is inside the circle or oval bounded by rect(), so let's bust out Pythagoras\n    QRect bounds = rect();\n    double xd = (mousePosition.x() - bounds.left()) / (double)bounds.width() - 0.5;\n    double yd = (mousePosition.y() - bounds.top()) / (double)bounds.height() - 0.5;\n    double distance = std::sqrt(xd * xd + yd * yd);\n    \n    //qDebug() << \"x ==\" << x << \", y ==\" << y << \"; d ==\" << d;\n    \n    return (distance <= 0.51);  // a little more than 0.5 to provide a little slop\n}\n\nvoid QtSLiMPushButton::paintEvent(QPaintEvent *p_paintEvent)\n{\n    // We need a base name to operate; without one, we punt to super and it draws whatever it draws\n    if (qtslimBaseName.length() == 0)\n    {\n        qDebug() << \"QtSLiMPushButton::paintEvent: base name not set for object\" << objectName();\n        QPushButton::paintEvent(p_paintEvent);\n        return;\n    }\n    \n    // We have a base name; get the cached icon corresponding to our state\n    QIcon *cachedIcon = qtslimIconForState(qtslimHighlighted, QtSLiMInDarkMode());\n    \n    if (!cachedIcon)\n    {\n        qDebug() << \"QtSLiMPushButton::paintEvent: icon not found for base name\" << qtslimBaseName;\n        QPushButton::paintEvent(p_paintEvent);\n        return;\n    }\n    \n    // We got a valid icon; draw with it\n    QPainter painter(this);\n    QRect bounds = rect();\n    \n    // This uses the icon to draw, which works because of Qt::AA_UseHighDpiPixmaps\n    painter.save();\n    painter.setRenderHint(QPainter::SmoothPixmapTransform);\n    \n    if (temporaryIcon.isNull())\n    {\n        cachedIcon->paint(&painter, bounds, Qt::AlignCenter, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);\n    }\n    else\n    {\n        // assume that the temporary icon completely covers the base icon when opacity is 1.0; this avoids artifacts\n        // in the appearance of the button with opacity 1.0 due to double-drawing pixels with partial alpha\n        if (temporaryIconOpacity < 1.0)\n            cachedIcon->paint(&painter, bounds, Qt::AlignCenter, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);\n        \n        if (temporaryIconOpacity > 0.0)\n        {\n            painter.setOpacity(temporaryIconOpacity);\n            temporaryIcon.paint(&painter, bounds, Qt::AlignCenter, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);\n        }\n    }\n    \n    painter.restore();\n    \n    /*\n    // This code would construct and draw a high-DPI image, but using Qt::AA_UseHighDpiPixmaps is better\n    QTransform transform = painter.combinedTransform();\n    QRect mappedBounds = transform.mapRect(bounds);\n    QSize size = mappedBounds.size();\n    QIcon ico = icon();\n    QPixmap pix = ico.pixmap(size, isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::Off);\n    QImage image = pix.toImage();\n    \n    painter.drawImage(rect(), image);\n    */\n}\n\nvoid QtSLiMPushButton::qtslimSetHighlight(bool highlighted)\n{\n    if (qtslimBaseName.length() == 0)\n        qDebug() << \"QtSLiMPushButton::qtslimSetHighlight: base name not set for object\" << objectName();\n    \n    // We're not changing our base name, so we don't need to throw out cached icons\n    qtslimHighlighted = highlighted;\n    update();\n}\n\nvoid QtSLiMPushButton::qtslimSetIcon(QString baseName, bool highlighted)\n{\n    if (baseName == qtslimBaseName)\n    {\n        // We're not changing our base name, so we don't need to throw out cached icons\n        qtslimHighlighted = highlighted;\n    }\n    else\n    {\n        // We're changing base name, so throw out cached icons\n        qtslimBaseName = baseName;\n        qtslimHighlighted = highlighted;\n        qtslimFreeCachedIcons();\n    }\n    \n    update();\n}\n\nQIcon *QtSLiMPushButton::qtslimIconForState(bool highlighted, bool darkMode)\n{\n    if (!highlighted)\n    {\n        if (!darkMode)\n        {\n            if (!qtslimIcon)\n            {\n                QString path = \":/buttons/\";\n                path += qtslimBaseName;\n                path += \".png\";\n                qtslimIcon = new QIcon(path);\n            }\n            return qtslimIcon;\n        }\n        else\n        {\n            if (!qtslimIcon_DARK)\n            {\n                QString path = \":/buttons_DARK/\";\n                path += qtslimBaseName;\n                path += \"_DARK.png\";\n                qtslimIcon_DARK = new QIcon(path);\n            }\n            return qtslimIcon_DARK;\n        }\n    }\n    else\n    {\n        if (!darkMode)\n        {\n            if (!qtslimIcon_H)\n            {\n                QString path = \":/buttons/\";\n                path += qtslimBaseName;\n                path += \"_H.png\";\n                qtslimIcon_H = new QIcon(path);\n            }\n            return qtslimIcon_H;\n        }\n        else\n        {\n            if (!qtslimIcon_H_DARK)\n            {\n                QString path = \":/buttons_DARK/\";\n                path += qtslimBaseName;\n                path += \"_H_DARK.png\";\n                qtslimIcon_H_DARK = new QIcon(path);\n            }\n            return qtslimIcon_H_DARK;\n        }\n    }\n}\n\n\n// A subclass of QSplitterHandle that does some custom drawing\nvoid QtSLiMSplitterHandle::paintEvent(QPaintEvent *p_paintEvent)\n{\n    QPainter painter(this);\n    QRect bounds = rect();\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    // provide a darkened and beveled appearance\n    QRect begin1Strip, begin2Strip, centerStrip, end2Strip, end1Strip;\n    \n    if (orientation() == Qt::Vertical)\n    {\n        begin1Strip = bounds.adjusted(0, 0, 0, -(bounds.height() - 1));\n        begin2Strip = bounds.adjusted(0, 1, 0, -(bounds.height() - 2));\n        centerStrip = bounds.adjusted(0, 2, 0, -2);\n        end2Strip = bounds.adjusted(0, bounds.height() - 2, 0, -1);\n        end1Strip = bounds.adjusted(0, bounds.height() - 1, 0, 0);\n    }\n    else    // Qt::Horizontal\n    {\n        begin1Strip = bounds.adjusted(0, 0, -(bounds.width() - 1), 0);\n        begin2Strip = bounds.adjusted(1, 0, -(bounds.width() - 2), 0);\n        centerStrip = bounds.adjusted(2, 0, -2, 0);\n        end2Strip = bounds.adjusted(bounds.width() - 2, 0, -1, 0);\n        end1Strip = bounds.adjusted(bounds.width() - 1, 0, 0, 0);\n    }\n    \n    painter.fillRect(begin1Strip, QtSLiMColorWithWhite(inDarkMode ? 0.227 : 0.773, 1.0));\n    painter.fillRect(begin2Strip, QtSLiMColorWithWhite(inDarkMode ? 0.000 : 1.000, 1.0));\n    painter.fillRect(centerStrip, QtSLiMColorWithWhite(inDarkMode ? 0.035 : 0.965, 1.0));\n    painter.fillRect(end2Strip, QtSLiMColorWithWhite(inDarkMode ? 0.082 : 0.918, 1.0));\n    painter.fillRect(end1Strip, QtSLiMColorWithWhite(inDarkMode ? 0.278 : 0.722, 1.0));\n    \n    \n    // On Linux, super draws the knob one pixel to the right of where it ought to be, so we draw it ourselves\n    // This code is modified from QtSplitterHandle in the Qt 5.14.2 sources (it's identical in Qt 5.9.8)\n    // This may turn out to be undesirable, as it assumes that the Linux widget kit is the one I use on Ubuntu\n#if defined(__linux__)\n    if (orientation() == Qt::Horizontal)\n    {\n        QStyleOption opt(0);\n        opt.rect = contentsRect().adjusted(0, 0, -1, 0);    // make the rect one pixel narrower, which shifts the knob\n        opt.palette = palette();\n        opt.state = QStyle::State_Horizontal;\n        \n        /*\n        // We don't have access to the hover/pressed state as far as I know, but it seems to be unused anyway\n        if (d->hover)\n            opt.state |= QStyle::State_MouseOver;\n        if (d->pressed)\n            opt.state |= QStyle::State_Sunken;\n        */\n        \n        if (isEnabled())\n            opt.state |= QStyle::State_Enabled;\n        \n        parentWidget()->style()->drawControl(QStyle::CE_Splitter, &opt, &painter, splitter());\n        return;\n    }\n#endif\n    \n    // call super to overlay the splitter knob\n    QSplitterHandle::paintEvent(p_paintEvent);\n}\n\n\n// A subclass of QStatusBar that draws a top separator, so our splitters abut nicely\n// BCH 9/20/2020: this now draws the message as HTML text too, allowing colorized signatures\nQtSLiMStatusBar::QtSLiMStatusBar(QWidget *p_parent) : QStatusBar(p_parent)\n{\n    // whenever our message changes, we resize vertically to accommodate it\n    connect(this, &QStatusBar::messageChanged, this, [this]() { setHeightFromContent(); });\n}\n\nvoid QtSLiMStatusBar::paintEvent(QPaintEvent * /*p_paintEvent*/)\n{\n    QPainter p(this);\n    QRect bounds = rect();\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    // fill the interior; we no longer try to inherit this from QStatusBar, that was a headache\n    p.fillRect(bounds, QtSLiMColorWithWhite(inDarkMode ? 0.118 : 0.965, 1.0));\n    \n    // draw the top separator and bevel lines\n    QRect bevelLine = bounds.adjusted(0, 0, 0, -(bounds.height() - 1));\n    \n    p.fillRect(bevelLine, QtSLiMColorWithWhite(inDarkMode ? 0.278 : 0.722, 1.0));\n    p.fillRect(bevelLine.adjusted(0, 1, 0, 1), QtSLiMColorWithWhite(inDarkMode ? 0.000 : 1.000, 1.0));\n    p.fillRect(bevelLine.adjusted(0, (bounds.height() - 1), 0, (bounds.height() - 1)), QtSLiMColorWithWhite(inDarkMode ? 0.082 : 0.918, 1.0));\n    \n    // draw the message\n    if (!currentMessage().isEmpty())\n    {\n        // would be nice for these coordinates not to be magic\n#ifdef __APPLE__\n        p.translate(QPointF(6, 3));\n#else\n        p.translate(QPointF(5, 1));\n#endif\n\n        p.setPen(inDarkMode ? Qt::white : Qt::black);\n        QSizeF pageSize(bounds.width() - 10, 200);           // wrap to our width, with a maximum height of 200 (which should never happen)\n        QTextDocument td;\n        td.setPageSize(pageSize);\n        td.setHtml(currentMessage());\n        td.drawContents(&p, bounds);\n    }\n}\n\nvoid QtSLiMStatusBar::resizeEvent(QResizeEvent *p_resizeEvent)\n{\n    // first call super to realize all consequences of the resize\n    QStatusBar::resizeEvent(p_resizeEvent);\n    \n    // Then calculate our new minimum height, as a result of wrapping, and set it in a deferred manner to avoid recursion issues\n    QTimer::singleShot(0, this, &QtSLiMStatusBar::setHeightFromContent);\n}\n\nvoid QtSLiMStatusBar::setHeightFromContent(void)\n{\n    // this mirrors the code in QtSLiMStatusBar::paintEvent()\n    QRect bounds = rect();\n    QSizeF pageSize(bounds.width() - 10, 200);           // wrap to our width, with a maximum height of 200 (which should never happen)\n    QTextDocument td;\n    td.setPageSize(pageSize);\n    td.setHtml(currentMessage());\n    \n    // now get the drawn text height and calculate our minimum height\n    QSizeF textSize = td.documentLayout()->documentSize();\n    QSize minSizeHint = minimumSizeHint();\n    QSize oldMinSize = minimumSize();\n    QSize newMinSize;\n    int newMaxHeight;\n    \n    if (textSize.height() < minSizeHint.height())\n    {\n        newMinSize = QSize(0, 0);\n        newMaxHeight = minSizeHint.height();\n    }\n    else\n    {\n#ifdef __linux__\n        newMinSize = QSize(minSizeHint.width(), textSize.height() + 0);\n#else\n        newMinSize = QSize(minSizeHint.width(), textSize.height() + 6);\n#endif\n        newMaxHeight = newMinSize.height();\n    }\n    \n    // set the new size only if it is different from the old height, to minimize thrash\n    if (newMinSize != oldMinSize)\n    {\n        setMinimumSize(newMinSize);\n        setMaximumHeight(newMaxHeight);  // we have to set the max height also, to make the Eidos console's status bar work properly\n        \n        //qDebug() << \"setHeightFromContent():\";\n        //qDebug() << \"   minSizeHint == \" << minSizeHint;\n        //qDebug() << \"   textSize == \" << textSize;\n        //qDebug() << \"   newMinSize == \" << newMinSize;\n    }\n}\n\nQPixmap QtSLiMDarkenPixmap(QPixmap p_pixmap)\n{\n    QPixmap pixmap(p_pixmap);\n    \n    {\n        QPainter painter(&pixmap);\n        \n        painter.fillRect(pixmap.rect(), QtSLiMColorWithWhite(0.0, 0.35));\n    }\n    \n    return pixmap;\n}\n\n\n// find flashing; see https://bugreports.qt.io/browse/QTBUG-83147\n\nstatic QPalette QtSLiMFlashPalette(QPlainTextEdit *te)\n{\n    // Returns a palette for QtSLiMTextEdit for highlighting errors, which could depend on platform and dark mode\n    // Note that this is based on the current palette, and derives only the highlight colors\n    QPalette p = te->palette();\n    p.setColor(QPalette::Highlight, QColor(QColor(Qt::yellow)));\n    p.setColor(QPalette::HighlightedText, QColor(Qt::black));\n    return p;\n}\n\nvoid QtSLiMFlashHighlightInTextEdit(QPlainTextEdit *te)\n{\n    const int delayMillisec = 80;   // seems good?  12.5 times per second\n    \n    // set to the flash color\n    te->setPalette(QtSLiMFlashPalette(te));\n    \n    // set up timers to flash the color again; we don't worry about being called multiple times,\n    // cancelling old timers, etc., because this is so quick that it really doesn't matter;\n    // it sorts itself out more quickly than the user can really notice any discrepancy\n    QTimer::singleShot(delayMillisec, te, [te]() { te->setPalette(qApp->palette(te)); });\n    QTimer::singleShot(delayMillisec * 2, te, [te]() { te->setPalette(QtSLiMFlashPalette(te)); });\n    QTimer::singleShot(delayMillisec * 3, te, [te]() { te->setPalette(qApp->palette(te)); });\n}\n\n// A QLabel that shows shortened text with an ellipsis; see https://stackoverflow.com/a/73316405/2752221\nQtSLiMEllipsisLabel::QtSLiMEllipsisLabel(QWidget *parent)\n    : QtSLiMEllipsisLabel(\"\", parent)\n{\n}\n\nQtSLiMEllipsisLabel::QtSLiMEllipsisLabel(QString text, QWidget *parent)\n    : QLabel(parent)\n{\n    setText(text);\n}\n\nvoid QtSLiMEllipsisLabel::setText(QString text)\n{\n    m_text = text;\n    updateText();\n}\n\nQSize QtSLiMEllipsisLabel::minimumSizeHint() const\n{\n    return QSize(0, QLabel::minimumSizeHint().height());\n}\n\nvoid QtSLiMEllipsisLabel::resizeEvent(QResizeEvent *p_event)\n{\n    QLabel::resizeEvent(p_event);\n    updateText();\n}\n\nvoid QtSLiMEllipsisLabel::updateText()\n{\n    QFontMetrics metrics(font());\n    QString elided = metrics.elidedText(m_text, Qt::ElideRight, width());\n    QLabel::setText(elided);\n}\n\nvoid QtSLiMEllipsisLabel::mousePressEvent(QMouseEvent *p_event)\n{\n    // check the mouse position and only take the click if it is within the displayed label's extent\n    QPoint curPoint = p_event->pos();\n    int clickX = curPoint.x();\n    \n    QFontMetrics metrics(font());\n    int labelLength = metrics.size(0, text()).width();\n    \n    if ((clickX >= 0) && (clickX <= labelLength + 1))\n        emit pressed();     // triggers QtSLiMWindow::jumpToPopupButtonPressed()\n}\n\n// Natural sorting (sorting numerically when the first difference is a numeric substring)\nbool EidosNaturalSort(QString &a, QString &b)\n{\n    QChar *aptr = a.data();\n    int alen = a.length();\n    \n    QChar *bptr = b.data();\n    int blen = b.length();\n    \n    do {\n        // look for a shared non-numeric prefix and remove it\n        while ((alen >= 1) && (blen >= 1))\n        {\n            QChar ach = *aptr;\n            QChar bch = *bptr;\n            \n            if ((ach == bch) && !ach.isDigit())\n            {\n                aptr++;\n                alen--;\n                \n                bptr++;\n                blen--;\n            }\n            else break;\n        }\n        \n        // parse a leading integer from both strings\n        bool anum = false;\n        int aval = 0;\n        \n        while ((alen >= 1) && aptr->isDigit())\n        {\n            char ach = aptr->toLatin1();    // we assume that if isDigit() is true, the digit is ASCII\n            \n            if ((ach >= '0') && (ach <= '9'))\n            {\n                aval = aval * 10 + (ach - '0');\n                aptr++;\n                alen--;\n                anum = true;\n            }\n        }\n        \n        bool bnum = false;\n        int bval = 0;\n        \n        while ((blen >= 1) && bptr->isDigit())\n        {\n            char bch = bptr->toLatin1();    // we assume that if isDigit() is true, the digit is ASCII\n            \n            if ((bch >= '0') && (bch <= '9'))\n            {\n                bval = bval * 10 + (bch - '0');\n                bptr++;\n                blen--;\n                bnum = true;\n            }\n        }\n        \n        // look for a shared numeric (integer) prefix\n        if (anum && bnum)\n        {\n            // if a numeric prefix is present in both, compare numerically\n            if (aval != bval)\n            {\n                return aval < bval;\n            }\n            // else if the numeric prefixes are identical, drop through and repeat the process\n        }\n        else\n        {\n            // if one or both strings do not have a numeric prefix, compare alphabetically\n            return a < b;\n        }\n    } while (true);\n    \n    return a < b;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMExtras.h",
    "content": "//\n//  QtSLiMExtras.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/28/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMEXTRAS_H\n#define QTSLIMEXTRAS_H\n\n#include <QObject>\n#include <QString>\n#include <QWidget>\n#include <QColor>\n#include <QRect>\n#include <QPainter>\n#include <QLineEdit>\n#include <QTextCursor>\n#include <QHBoxLayout>\n#include <QPushButton>\n#include <QList>\n#include <QSplitter>\n#include <QSplitterHandle>\n#include <QStatusBar>\n#include <QPlainTextEdit>\n#include <QLabel>\n#include <QStaticText>\n\n#include <cmath>\n#include <algorithm>\n\n#include \"eidos_property_signature.h\"\n#include \"eidos_call_signature.h\"\n\nclass QPaintEvent;\n\n// legend positions for QtSLiMGraphView\ntypedef enum {\n    kUnconfigured = -1,\n    kTopLeft = 0,\n    kTopRight,\n    kBottomLeft,\n    kBottomRight\n} QtSLiM_LegendPosition;\n\n// Utility helpers for window visibility/relocation\nbool QtSLiMIsMostlyOnScreen(QWidget *window);\nvoid QtSLiMRelocateQuietly(QWidget *window);\n\nvoid QtSLiMMakeWindowVisibleAndExposed(QWidget *window);\n\nvoid QtSLiMClearLayout(QLayout *layout, bool deleteWidgets = true);\n\nvoid QtSLiMFrameRect(const QRect &p_rect, const QColor &p_color, QPainter &p_painter);\nvoid QtSLiMFrameRect(const QRectF &p_rect, const QColor &p_color, QPainter &p_painter, double p_lineWidth);\n\nQColor QtSLiMColorWithWhite(double p_white, double p_alpha);\nQColor QtSLiMColorWithRGB(double p_red, double p_green, double p_blue, double p_alpha);\nQColor QtSLiMColorWithHSV(double p_hue, double p_saturation, double p_value, double p_alpha);\n\nvoid RGBForFitness(double fitness, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor);\nvoid RGBForSelectionCoeff(double selectionCoeff, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor);\n\n// A color scale widget that shows the color scales for fitness and selection coefficients\nclass QtSLiMColorScaleWidget : public QWidget\n{\npublic:\n    QtSLiMColorScaleWidget(QWidget *p_parent);\nprotected:\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\nprivate:\n    std::vector<QString> fitnessTicks, effectTicks;\n};\n\n// Whether we're in \"dark mode\" for user interface rendering\nbool QtSLiMInDarkMode(void);    \n\n// Standard paths for our images, ending in _H for highlighted, and then in _DARK for dark mode icons, and then in .png\nQString QtSLiMImagePath(QString baseName, bool highlighted);\n\n\n// A subclass of QLineEdit that selects all its text when it receives keyboard focus\n// It also supports showing a \"progress bar\" under its text, and it has a modified\n// appearance that can be disabled but still show fairly dark text for readability\nclass QtSLiMGenerationLineEdit : public QLineEdit\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGenerationLineEdit(const QString &contents, QWidget *p_parent = nullptr);\n    QtSLiMGenerationLineEdit(QWidget *p_parent = nullptr);\n    virtual\t~QtSLiMGenerationLineEdit() override;\n    \n    // can optionally display \"progress\" in the background of the lineedit\n    void setProgress(double p_progress);\n    \n    // set its appearance/behavior; do not use setEnabled(), use this!\n    void setAppearance(bool p_enabled, bool p_dimmed);\n    \nprotected:\n    virtual void focusInEvent(QFocusEvent *p_event) override;\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n    \nprivate:\n    QtSLiMGenerationLineEdit() = delete;\n    QtSLiMGenerationLineEdit(const QtSLiMGenerationLineEdit&) = delete;\n    QtSLiMGenerationLineEdit& operator=(const QtSLiMGenerationLineEdit&) = delete;\n    \n    void _ReconfigureAppearance(void);\n    \n    double progress = 0.0;\n    bool dimmed = false;\n};\n\nvoid ColorizePropertySignature(const EidosPropertySignature *property_signature, double pointSize, QTextCursor lineCursor);\nvoid ColorizeCallSignature(const EidosCallSignature *call_signature, double pointSize, QTextCursor lineCursor);\n\n// A subclass of QHBoxLayout specifically designed to lay out the play controls in the main window\nclass QtSLiMPlayControlsLayout : public QHBoxLayout\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMPlayControlsLayout(QWidget *p_parent): QHBoxLayout(p_parent) {}\n    QtSLiMPlayControlsLayout(): QHBoxLayout() {}\n    virtual ~QtSLiMPlayControlsLayout() override;\n\n    virtual QSize sizeHint() const override;\n    virtual QSize minimumSize() const override;\n    virtual void setGeometry(const QRect &rect) override;\n};\n\n// Heat colors for profiling display\nQColor slimColorForFraction(double fraction);\n\n// Nicely formatted memory usage strings\nQString stringForByteCount(uint64_t bytes);\nQString attributedStringForByteCount(uint64_t bytes, double total, QTextCharFormat &format);\n\n// Nicely formatted dateline for output\nQString slimDateline(void);\n\n// Running a panel to obtain numbers from the user\nQStringList QtSLiMRunLineEditArrayDialog(QWidget *p_parent, QString title, QStringList captions, QStringList values);\n\n// A subclass of QPushButton that draws its image with antialiasing, for a better appearance; used for the About panel\nclass QtSLiMIconView : public QPushButton\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMIconView(const QIcon &p_icon, const QString &p_text, QWidget *p_parent = nullptr) : QPushButton(p_icon, p_text, p_parent) {}\n    QtSLiMIconView(const QString &p_text, QWidget *p_parent = nullptr) : QPushButton(p_text, p_parent) {}\n    QtSLiMIconView(QWidget *p_parent = nullptr) : QPushButton(p_parent) {}\n    virtual ~QtSLiMIconView(void) override {}\n    \nprotected:\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n};\n\n// A subclass of QPushButton that draws its image with antialiasing, for a better appearance, and handles dark mode appearance\nclass QtSLiMPushButton : public QPushButton\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMPushButton(const QIcon &p_icon, const QString &p_text, QWidget *p_parent = nullptr);\n    QtSLiMPushButton(const QString &p_text, QWidget *p_parent = nullptr);\n    QtSLiMPushButton(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMPushButton(void) override;\n    \n    void qtslimSetBaseName(QString baseName) { qtslimSetIcon(baseName, false); }\n    void qtslimSetHighlight(bool highlighted);\n    void qtslimSetIcon(QString baseName, bool highlighted);\n    \n    // An added feature beyond QPushButton: support for a \"temporary icon\" drawn on top of the\n    // normal cached icon, with variable opacity.  This supports the pulsing debug output button.\n    void setTemporaryIcon(QIcon tempIcon) { temporaryIcon = tempIcon; update(); }\n    void setTemporaryIconOpacity(double opacity) { temporaryIconOpacity = opacity; update(); }\n    void clearTemporaryIcon(void) { temporaryIcon = QIcon(); update(); }\n    \nprotected:\n    void sharedInit(void);\n    virtual bool hitButton(const QPoint &pos) const override;\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n    \n    QString qtslimBaseName;                 // base name, such as \"foo\"\n    bool qtslimHighlighted = false;         // highlighted state (appends _H to the base name)\n    \n    QIcon *qtslimIcon = nullptr;\n    QIcon *qtslimIcon_H = nullptr;\n    QIcon *qtslimIcon_DARK = nullptr;\n    QIcon *qtslimIcon_H_DARK = nullptr;\n    \n    QIcon temporaryIcon;\n    double temporaryIconOpacity = 0.0;\n    \n    void qtslimFreeCachedIcons(void);\n    QIcon *qtslimIconForState(bool highlighted, bool darkMode);\n};\n\n// A subclass of QSplitterHandle that does some custom drawing\nclass QtSLiMSplitterHandle : public QSplitterHandle\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMSplitterHandle(Qt::Orientation p_orientation, QSplitter *p_parent) : QSplitterHandle(p_orientation, p_parent) {}\n    virtual ~QtSLiMSplitterHandle(void) override {}\n    \nprotected:\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n};\n\n// A subclass of QSplitter that supplies a custom QSplitterHandle subclass\nclass QtSLiMSplitter : public QSplitter\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMSplitter(Qt::Orientation p_orientation, QWidget *p_parent = nullptr) : QSplitter(p_orientation, p_parent) {}\n    QtSLiMSplitter(QWidget *p_parent = nullptr) : QSplitter(p_parent) {}\n    virtual ~QtSLiMSplitter(void) override {}\n    \nprotected:\n    virtual QSplitterHandle *createHandle(void) override { return new QtSLiMSplitterHandle(orientation(), this); }\n};\n\n// A subclass of QStatusBar that draws a top separator on Linux, so our splitters abut nicely\nclass QtSLiMStatusBar : public QStatusBar\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMStatusBar(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMStatusBar(void) override {}\n    \nprotected:\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n    virtual void resizeEvent(QResizeEvent *p_resizeEvent) override;\n    void setHeightFromContent(void);\n};\n\n// Used to create the dark app icon displayed when running a model\nQPixmap QtSLiMDarkenPixmap(QPixmap p_pixmap);\n\nvoid QtSLiMFlashHighlightInTextEdit(QPlainTextEdit *te);\n\n// A QLabel subclass that shows shortened text with an ellipsis; see https://stackoverflow.com/a/73316405/2752221\nclass QtSLiMEllipsisLabel : public QLabel\n{\n    Q_OBJECT\n    \npublic:\n    explicit QtSLiMEllipsisLabel(QWidget *parent = nullptr);\n    explicit QtSLiMEllipsisLabel(QString text, QWidget *parent = nullptr);\n    void setText(QString);\n    virtual QSize minimumSizeHint() const;\n    \nsignals:\n    void pressed(void);\n    \nprotected:\n    void resizeEvent(QResizeEvent *p_event);\n    void mousePressEvent(QMouseEvent *p_event);\n    \nprivate:\n    void updateText();\n    QString m_text;\n};\n\n// Natural sorting (sorting numerically when the first difference is a numeric substring)\nbool EidosNaturalSort(QString &a, QString &b);\n\n\n// Incremental sorting\n//\n// This is from https://github.com/KukyNekoi/magicode by Erik Regla, released under the GPL 3.\n// The algorithms involved are described in Paredes & Navarro (2006) \"Optimal Incremental\n// Sorting\" and Regla & Paredes (2015) \"Worst-case Optimal Incremental Sorting\".  Thanks very\n// much to Erik Regla for making this code available for use.\n\n#define FIXED_PIVOT_SELECTION 1 // remove to allow random initial pivot selection\n#define USE_FAT_PARTITION 1    // use three-way-partitioning\n#define USE_ALPHA_LESS_THAN_P30 1    // use three-way-partitioning\n\ntemplate<class T>\nclass BareBoneIQS {\npublic:\n    BareBoneIQS(T *target_ptr, std::size_t target_size);\n    ~BareBoneIQS();\n    inline void swap(std::size_t lhs, std::size_t rhs);\n    inline std::size_t partition(T pivot_value, std::size_t lhs, std::size_t rhs);\n    std::size_t partition_redundant(T pivot_value, std::size_t lhs, std::size_t rhs);\n    inline std::size_t stack_pop();\n    inline std::size_t stack_peek();\n    inline void stack_push(std::size_t value);\n    virtual T next();\n\nprotected:\n    /**\n     * In this example we used a stack which is the same length of the array. This is only for\n     * testing purposes and can be changed into a proper stack later on if desired\n     *\n     */\n    std::size_t *stack;\n    std::size_t stack_length;\n\n    std::size_t target_size;\n    std::size_t extracted_count;\n    T *target_ptr;\n\n};\n\ntemplate <class T>\nclass BareBoneIIQS : public BareBoneIQS<T> {\npublic:\n    BareBoneIIQS(T *p_target_ptr, std::size_t p_target_size);\n    ~BareBoneIIQS();\n    T next();\n    std::size_t bfprt(std::size_t lhs, std::size_t rhs, std::size_t median_length);\n    std::size_t median(std::size_t lhs, std::size_t rhs);\n};\n\n/* This constructor allows in-place ordering */\ntemplate <class T>\nBareBoneIQS<T>::BareBoneIQS(T *p_target_ptr, std::size_t p_target_size){\n    this->target_ptr = p_target_ptr;\n    this->target_size = p_target_size;\n\n    this->stack = (std::size_t *) std::malloc(p_target_size * sizeof(std::size_t)) ;\n    this->stack[0] = p_target_size - 1; // index of the last element\n    this->stack_length = 1; //starts with a single element, the top\n\n    this->extracted_count = 0; // this way, after adding +1, we can partition as whole\n}\n\ntemplate <class T>\nBareBoneIQS<T>::~BareBoneIQS() {\n    std::free(this->stack);\n}\n\n/**\n * @brief Swaps two elements in the referenced array\n *\n * @param lhs left index to be swapped\n * @param rhs right index to be swapped\n */\ntemplate <class T>\ninline void BareBoneIQS<T>::swap(std::size_t lhs, std::size_t rhs){\n    T _temp_val = this->target_ptr[lhs];\n    this->target_ptr[lhs] = this->target_ptr[rhs];\n    this->target_ptr[rhs] = _temp_val;\n}\n\n/**\n * @brief Implementation of Hoare's partition algorithm. Can be found on\n * Cormen's \"Introduction to algorithms - 2nd edition\" p146\n * This implementation is not resistant to the case on which the elements are repeated.\n *\n * @param pivot_value the pivot value to use\n * @param lhs the left boundary for partition algorithm (inclusive)\n * @param rhs the right boundary for partition algorithm (inclusive)\n * @return std::size_t the index on which the partition value belongs\n */\ntemplate <class T>\ninline std::size_t BareBoneIQS<T>::partition(T pivot_value, std::size_t lhs, std::size_t rhs){\n    if(lhs == rhs) return lhs;\n    lhs--;\n    rhs++;\n\n    while(1){\n        do{\n            lhs++;\n        } while(this->target_ptr[lhs] < pivot_value);\n        do{\n            rhs--;\n        } while(pivot_value < this->target_ptr[rhs]);\n        if (lhs >= rhs) return rhs;\n        this->swap(lhs, rhs);\n    }\n}\n\n/**\n * Modified version of hoare's algorithm intended to be resistant to redundant elements along the\n * partition. This scheme is also known as three-way partitioning. Make sure to select the forcing pivot\n * scheme that matches your problem accordingly\n * @param pivot_value the pivot value to use\n * @param lhs the left boundary for partition algorithm (inclusive)\n * @param rhs the right boundary for partition algorithm (inclusive)\n * @return std::size_t the index on which the partition value belongs\n */\ntemplate<class T>\ninline std::size_t BareBoneIQS<T>::partition_redundant(T pivot_value, std::size_t lhs, std::size_t rhs) {\n    std::size_t i = lhs - 1;\n    std::size_t k = rhs + 1;\n    while (1) {\n        while (this->target_ptr[++i] < pivot_value);\n        while (this->target_ptr[--k] > pivot_value);\n        if (i >= k) break;\n        this->swap(i, k);\n    }\n    i = k++;\n    while(i > lhs && this->target_ptr[i] == pivot_value) i--;\n    while(k < rhs && this->target_ptr[k] == pivot_value) k++;\n\n    #ifdef FORCE_PIVOT_SELECTION_LEFT\n        return i; // return left pivot\n    #elif FORCE_PIVOT_SELECTION_RIGHT\n        return k; // return left pivot\n    #else\n        return (i + k) / 2; // if there is a group, then return the middle element to guarantee a position\n    #endif\n}\n\n/**\n * @brief Pops the last element on the stack\n * @return std::size_t element at the top of the stack\n */\ntemplate<class T>\ninline std::size_t BareBoneIQS<T>::stack_pop(){\n    return this->stack[--this->stack_length];\n}\n\n/**\n * @brief Peeks the last element on the stack\n * @return std::size_t element at the top of the stack\n */\ntemplate<class T>\ninline std::size_t BareBoneIQS<T>::stack_peek(){\n    return this->stack[this->stack_length-1];\n}\n\n/**\n * @brief Inserts an element on the top of the stack\n * @param value the element to insert\n */\ntemplate<class T>\ninline void BareBoneIQS<T>::stack_push(std::size_t value){\n    this->stack[this->stack_length] = value;\n    this->stack_length++;\n}\n\n/**\n * @brief Retrieves the next sorted element. The basic idea is to\n * use quick select to find the smallest element, but store the pivots along the\n * way in order to shorten future calculations.\n *\n * @return T the next sorted element\n */\ntemplate<class T>\nT BareBoneIQS<T>::next() {\n    // This for allows the tail recursion\n    while(1){\n        // Base condition. If the element referenced by the top of the stack\n        // is the element that we're actually searching, then retrieve it and\n        // resize the search window\n        if (this->extracted_count == this->stack_peek()){\n            this->extracted_count++;\n            return this->target_ptr[this->stack_pop()];\n        }\n\n        // Selects a random pivot from the remaining array\n\n        #ifdef FIXED_PIVOT_SELECTION\n            std::size_t pivot_idx = this->extracted_count;\n        #else\n            std::size_t rand_range = this->stack_peek() - this->extracted_count;\n            std::size_t pivot_idx = this->extracted_count + (rand() % rand_range);\n        #endif\n        T pivot_value = this->target_ptr[pivot_idx];\n\n        // pivot partition and indexing\n        #ifdef USE_FAT_PARTITION\n                pivot_idx = this->partition_redundant(pivot_value, this->extracted_count, this->stack_peek());\n        #else\n                pivot_idx = this->partition(pivot_value, this->extracted_count, this->stack_peek());\n        #endif\n\n        // Push and recurse the loop\n        this->stack_push(pivot_idx);\n    }\n}\n\n/* This constructor allows in-place ordering */\ntemplate <class T>\nBareBoneIIQS<T>::BareBoneIIQS(T *p_target_ptr, std::size_t p_target_size): BareBoneIQS<T>(p_target_ptr, p_target_size){\n}\ntemplate <class T>\nBareBoneIIQS<T>::~BareBoneIIQS() {\n}\n\n/**\n *\n * @brief Retrieves the next sorted element. The basic idea is to\n * use quick select to find the smallest element, but store the pivots along the\n * way in order to shortent future calculations.\n *\n * @tparam T The template class/type to use\n * @return T the next sorted element\n */\ntemplate<class T>\nT BareBoneIIQS<T>::next() {\n    while(1){\n        // Base condition. If the element referenced by the top of the stack\n        // is the element that we're actually searching, then retrieve it and\n        // resize the search window\n        std::size_t top_element = this->stack_peek();\n        std::size_t range = top_element - this->extracted_count;\n        std::size_t p70_idx = (std::size_t)std::ceil(range * 0.7);\n\n\n        if (this->extracted_count == top_element ){\n            this->extracted_count++;\n            return this->target_ptr[this->stack_pop()];\n        }\n\n        #ifdef FIXED_PIVOT_SELECTION\n            std::size_t pivot_idx = this->extracted_count;\n        #else\n            std::size_t rand_range = this->stack_peek() - this->extracted_count;\n            std::size_t pivot_idx = this->extracted_count + (rand() % rand_range);\n        #endif\n\n        T pivot_value = this->target_ptr[pivot_idx];\n\n        // pivot partition and indexing\n        #ifdef USE_FAT_PARTITION\n            pivot_idx = this->partition_redundant(pivot_value, this->extracted_count, top_element);\n        #else\n            pivot_idx = this->partition(pivot_value, this->extracted_count, top_element);\n        #endif\n\n        #ifdef REUSE_PIVOTS\n            std::size_t previous_pivot_idx = pivot_idx;\n        #endif\n\n        // IIQS changes start! only check if range is less than the square root of the total size\n        // First, we need to check if this pointer belongs P70 \\union P30\n        #ifdef USE_ALPHA_LESS_THAN_P30\n            std::size_t p30_idx = (std::size_t)std::ceil(range * 0.3); // actually, if we don't care about balancing the stack, you can ignore the p30 condition\n            if (p30_idx > pivot_idx || pivot_idx > p70_idx){\n        #else\n            if (pivot_idx > p70_idx){\n        #endif\n            // if we enter here, then it's because the index needs to be recomputed.\n            // So, we ditch the index and get a nice approximate median median and reuse previous computation\n            pivot_idx = this->bfprt(this->extracted_count, top_element, 5);\n            pivot_value = this->target_ptr[pivot_idx];\n            // then we re-partition, assuming that this median is better\n            #ifdef USE_FAT_PARTITION\n                pivot_idx = this->partition_redundant(pivot_value, this->extracted_count, top_element);\n            #else\n                pivot_idx = this->partition(pivot_value, this->extracted_count, top_element);\n            #endif\n        }\n\n        // I need to see later how it does affect the stack this segment.\n        #ifdef REUSE_PIVOTS\n            if(previous_pivot_idx < pivot_idx){\n                this->stack_push(pivot_idx);\n                this->stack_push(previous_pivot_idx);\n                continue;\n            }\n            else if(previous_pivot_idx > pivot_idx){\n                this->stack_push(previous_pivot_idx);\n                this->stack_push(pivot_idx);\n                continue;\n            }\n        #endif\n        // Push and recurse the loop\n        this->stack_push(pivot_idx);\n    }\n}\n\n\n/**\n * In-place implementation of bfprt. Instead of the classical implementation when auxiliary structures are used\n * this implementation forces two phenomena on the array which both are beneficial to IQS. First, given that we force\n * the selection of the first index, elements near the beginning have a high chance of being good pivots. Second, we\n * don't use extra memory to allocate those median results.\n * @tparam T The template class/type to use\n * @param lhs the left index to sort (inclusive)\n * @param rhs the right index to sort (inclusive)\n * @param median_length size of the median to use on bfprt, 5 is commonly used\n * @return the median value\n */\ntemplate<class T>\ninline std::size_t BareBoneIIQS<T>::bfprt(std::size_t lhs, std::size_t rhs, std::size_t median_length) {\n    std::size_t base_lhs = lhs;\n    std::size_t medians_extracted = 0;\n\n    while(1){\n        // reset base conditions\n        lhs = base_lhs;\n\n        // check base case\n        if( rhs <= base_lhs + median_length) {\n            return this->median(base_lhs, rhs);\n        }\n\n        // tail recursion step for bfprt\n        while(lhs + median_length <= rhs){\n            std::size_t median_index = this->median(lhs, lhs + median_length);\n            //move median to the start of the array\n            this->swap(median_index, base_lhs + medians_extracted);\n            // search for next stride\n            lhs += median_length;\n            medians_extracted++;\n        }\n        rhs = medians_extracted + base_lhs;\n        medians_extracted = 0;\n    }\n}\n\n/**\n * Median selection via quickselect. We can assume that this process is constant, as it is being always executed\n * with 5 elements (by default, you can change this later)\n *\n * @tparam T  T The template class/type to use\n * @param lhs the left boundary for median algorithm (inclusive)\n * @param rhs the right boundary for median algorithm (inclusive)\n * @return the median index\n */\ntemplate<class T>\ninline std::size_t BareBoneIIQS<T>::median(std::size_t lhs, std::size_t rhs) {\n    std::sort(this->target_ptr + lhs, this->target_ptr + rhs);\n    return (lhs + rhs) / 2;\n    /* implement heapsort later as it is more cache-friendly for small arrays, I'm too drunk now */\n    /* explanation: due to how heapsort is implemented, it scatters in-memory operations, that's\n     * on how the tree is represented on the array (the 2k +1 thing), so if you \"recurse\" long\n     * enough (namely, you're searching for an element on which you need to trash the cache or even\n     * worse, you lose the dram-bursting) then it gets its performance degraded.\n     *\n     * But since on median finding of a fixed set of elements it's small enough to fit on the cache\n     * and to get dram-bursting benefits, it works better than other sorting algorithms in practice.\n     */\n}\n\n//\n// Incremental sorting ENDS\n//\n\n\n#endif // QTSLIMEXTRAS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindPanel.cpp",
    "content": "//\n//  QtSLiMFindPanel.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/24/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMFindPanel.h\"\n#include \"ui_QtSLiMFindPanel.h\"\n\n#include <QPlainTextEdit>\n#include <QApplication>\n#include <QSettings>\n#include <QClipboard>\n#include <QTextBlock>\n#include <QDebug>\n\n#include <utility>\n\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMExtras.h\"\n\n\nQtSLiMFindPanel &QtSLiMFindPanel::instance(void)\n{\n    static QtSLiMFindPanel *inst = nullptr;\n    \n    if (!inst)\n        inst = new QtSLiMFindPanel(nullptr);\n    \n    return *inst;\n}\n\nQtSLiMFindPanel::QtSLiMFindPanel(QWidget *p_parent) : QDialog(p_parent), ui(new Ui::QtSLiMFindPanel)\n{\n    ui->setupUi(this);\n    \n    QSettings settings;\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // Connect the panel UI\n    connect(ui->findNextButton, &QPushButton::clicked, this, &QtSLiMFindPanel::findNext);\n    connect(ui->findPreviousButton, &QPushButton::clicked, this, &QtSLiMFindPanel::findPrevious);\n    connect(ui->replaceAndFindButton, &QPushButton::clicked, this, &QtSLiMFindPanel::replaceAndFind);\n    connect(ui->replaceButton, &QPushButton::clicked, this, &QtSLiMFindPanel::replace);\n    connect(ui->replaceAllButton, &QPushButton::clicked, this, &QtSLiMFindPanel::replaceAll);\n    \n    connect(ui->matchCaseCheckBox, &QPushButton::clicked, this, &QtSLiMFindPanel::optionsChanged);\n    connect(ui->wholeWordCheckBox, &QPushButton::clicked, this, &QtSLiMFindPanel::optionsChanged);\n    connect(ui->wrapAroundCheckBox, &QPushButton::clicked, this, &QtSLiMFindPanel::optionsChanged);\n    \n    connect(ui->findTextLineEdit, &QLineEdit::textChanged, this, &QtSLiMFindPanel::findTextChanged);\n    connect(ui->replaceTextLineEdit, &QLineEdit::textChanged, this, &QtSLiMFindPanel::replaceTextChanged);\n    \n    // Set up the find and replace fields\n    ui->findTextLineEdit->setClearButtonEnabled(true);\n    ui->replaceTextLineEdit->setClearButtonEnabled(true);\n    \n    changingFindText = true;\n    ui->findTextLineEdit->clear();\n    ui->replaceTextLineEdit->clear();\n    changingFindText = false;\n    \n    // If Qt's clipboard supports a find buffer (currently macOS only), talk to it\n    QClipboard *clipboard = QGuiApplication::clipboard();\n    \n    if (clipboard && clipboard->supportsFindBuffer())\n    {\n        // Note that this logs \"QMime::convertToMime: unhandled mimetype: text/plain\" in Qt 5.9.8 if the\n        // find buffer is empty; there seems to be no way to avoid that log, so whatever\n        QString findText = clipboard->text(QClipboard::FindBuffer);\n        \n        changingFindText = true;\n        ui->findTextLineEdit->setText(findText);\n        changingFindText = false;\n        \n        connect(clipboard, &QClipboard::findBufferChanged, this, &QtSLiMFindPanel::findBufferChanged);\n    }\n    else\n    {\n        ui->findTextLineEdit->setText(settings.value(\"QtSLiMFindPanel/findText\", \"\").toString());\n    }\n    \n    ui->replaceTextLineEdit->setText(settings.value(\"QtSLiMFindPanel/replaceText\", \"\").toString());\n    \n    fixEnableState();\n    \n    // Restore saved options\n    settings.beginGroup(\"QtSLiMFindPanel\");\n    ui->matchCaseCheckBox->setChecked(settings.value(\"matchCase\", false).toBool());\n    ui->wholeWordCheckBox->setChecked(settings.value(\"wholeWord\", false).toBool());\n    ui->wrapAroundCheckBox->setChecked(settings.value(\"wrapAround\", true).toBool());\n    settings.endGroup();\n    \n    // Clear the status text\n    ui->statusText->clear();\n    \n    // The initial height should be enforced as the minimum and maximum height\n    setMinimumHeight(height());\n    setMaximumHeight(height());\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    settings.beginGroup(\"QtSLiMFindPanel\");\n    resize(settings.value(\"size\", QSize(width(), height())).toSize());\n    move(settings.value(\"pos\", QPoint(25, 45)).toPoint());\n    settings.endGroup();\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nQtSLiMFindPanel::~QtSLiMFindPanel(void)\n{\n    qDebug() << \"QtSLiMFindPanel::~QtSLiMFindPanel()\";\n    \n    delete ui;\n}\n\nQPlainTextEdit *QtSLiMFindPanel::targetTextEditRequireModifiable(bool requireModifiable)\n{\n    // We rely on QtSLiMAppDelegate to track the active window list for us;\n    // our target is the frontmost window that is not our own window\n    // It can be deallocated before us during quit, so we need to check\n    if (!qtSLiMAppDelegate)\n        return nullptr;\n    \n    QWidget *currentFocusWindow = qtSLiMAppDelegate->activeWindowExcluding(this);\n    \n    if (currentFocusWindow)\n    {\n        //qDebug() << \"targetTextEditRequireModifiable() found active window\" << currentFocusWindow->windowTitle();\n        \n        // Given a target window, we target the focusWidget *if* it is a textedit\n        QWidget *windowFocusWidget = currentFocusWindow->focusWidget();\n        QPlainTextEdit *textEdit = dynamic_cast<QPlainTextEdit*>(windowFocusWidget);\n        \n//        if (windowFocusWidget)\n//            qDebug() << \"   windowFocusWidget\" << windowFocusWidget << \" \" << windowFocusWidget->objectName() << \", textEdit\" << textEdit;\n//        else\n//            qDebug() << \"   NO FOCUSWIDGET\";\n        \n        // If we've found a textedit, return it if it satisfies requirements\n        // There is no fallback, nor should there be; the focused textedit is our target\n        if (textEdit)\n        {\n            if (!textEdit->isEnabled())\n                return nullptr;\n            if (requireModifiable && textEdit->isReadOnly())\n                return nullptr;\n            \n            return textEdit;\n        }\n    }\n    else\n    {\n        //qDebug() << \"targetTextEditRequireModifiable() : NO ACTIVE WINDOW\";\n    }\n    \n    return nullptr;\n}\n\nvoid QtSLiMFindPanel::showFindPanel(void)\n{\n    QtSLiMMakeWindowVisibleAndExposed(this);\n    \n    // When the find panel is raised, it is conventional to select the find text so the user can immediately type to replace it\n    ui->findTextLineEdit->selectAll();\n    ui->findTextLineEdit->setFocus();\n}\n\nvoid QtSLiMFindPanel::closeEvent(QCloseEvent *p_event)\n{\n    // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMFindPanel\");\n    settings.setValue(\"size\", size());\n    settings.setValue(\"pos\", pos());\n    settings.endGroup();\n    \n    // use super's default behavior\n    QDialog::closeEvent(p_event);\n}\n\nbool QtSLiMFindPanel::findForwardWrapBeep(QPlainTextEdit *target, bool forward, bool wrap, bool beepIfNotFound)\n{\n    // This method is the only place where I looked at its source code, but for this method at least,\n    // thanks to Lorenzo Bettini for his QtFindReplaceDialog project, http://qtfindreplace.sourceforge.net\n    // It is under the LGPL, so to the extent that I did lean on his code here, it is GPL-compatible.\n    \n    if (!target)\n    {\n        qDebug() << \"QtSLiMFindPanel::find() called with no target textEdit!\";\n        return false;\n    }\n    \n    QString findString = ui->findTextLineEdit->text();\n    QTextDocument::FindFlags findFlags;\n    \n    if (!forward)\n        findFlags |= QTextDocument::FindBackward;\n    if (ui->matchCaseCheckBox->isChecked())\n        findFlags |= QTextDocument::FindCaseSensitively;\n    if (ui->wholeWordCheckBox->isChecked())\n        findFlags |= QTextDocument::FindWholeWords;\n    \n    // There is a bug, fixed in Qt 5.12.5, where finding backwards fails to find the first occurrence\n    // that it ought to find, in specific circumstances: the selection must start at the start of a\n    // line, and the first previous occurrence must be in the preceding line.  The find() method gets\n    // confused by the preceding block's end.  See https://bugreports.qt.io/browse/QTBUG-48035.  I do\n    // not attempt to work around this bug here; the workaround would be a bit complex, and the bug\n    // has been fixed, and it's unlikely to bite anyone – it's an edge case, and Find Previous is\n    // relatively unusual.  But I've put this as a reminder, in case the bug gets reported to me.\n    \n    bool findResult = target->find(findString, findFlags);\n    \n    if (findResult)\n    {\n        target->centerCursor();\n        QtSLiMFlashHighlightInTextEdit(target);\n    }\n    else if (wrap)\n    {\n        // If we're wrapping around, do the wrap and try again\n        QTextCursor originalCursor(target->textCursor());\n        \n        if (forward)\n            target->moveCursor(QTextCursor::Start);\n        else\n            target->moveCursor(QTextCursor::End);\n        \n        findResult = target->find(findString, findFlags);\n        \n        if (findResult)\n        {\n            target->centerCursor();\n            QtSLiMFlashHighlightInTextEdit(target);\n        }\n        else\n            target->setTextCursor(originalCursor);\n    }\n    \n    if (!findResult)\n    {\n        ui->statusText->setText(\"no match found \");\n        if (beepIfNotFound)\n            qApp->beep();\n    }\n    \n    return findResult;\n}\n\nvoid QtSLiMFindPanel::findNext(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    QString findString = ui->findTextLineEdit->text();\n    \n    if (!target || !findString.length()) { qApp->beep(); return; }\n    \n    findForwardWrapBeep(target, true, ui->wrapAroundCheckBox->isChecked(), true);\n}\n\nvoid QtSLiMFindPanel::findPrevious(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    QString findString = ui->findTextLineEdit->text();\n    \n    if (!target || !findString.length()) { qApp->beep(); return; }\n    \n    findForwardWrapBeep(target, false, ui->wrapAroundCheckBox->isChecked(), true);\n}\n\nvoid QtSLiMFindPanel::replaceAndFind(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(true);\n    QString findString = ui->findTextLineEdit->text();\n    \n    if (!target || !findString.length()) { qApp->beep(); return; }\n    \n    // if the selection is non-empty and equals the find string, replace; then find\n    if (target->textCursor().hasSelection())\n    {\n        QString selectedText = target->textCursor().selectedText();\n        \n        if (0 == QString::compare(selectedText, ui->findTextLineEdit->text(), ui->matchCaseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive))\n            target->textCursor().insertText(ui->replaceTextLineEdit->text());\n    }\n    \n    findForwardWrapBeep(target, true, ui->wrapAroundCheckBox->isChecked(), true);\n    jumpToSelection();\n}\n\nvoid QtSLiMFindPanel::replace(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(true);\n    QString findString = ui->findTextLineEdit->text();\n    \n    if (!target || !findString.length()) { qApp->beep(); return; }\n    \n    // beep if the selection is empty\n    if (!target->textCursor().hasSelection()) { qApp->beep(); return; }\n    \n    target->textCursor().insertText(ui->replaceTextLineEdit->text());\n}\n\nvoid QtSLiMFindPanel::replaceAll(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(true);\n    QString findString = ui->findTextLineEdit->text();\n    \n    if (!target || !findString.length()) { qApp->beep(); return; }\n    \n    // Search from the document start\n    QTextCursor originalCursor(target->textCursor());\n    bool hasOccurrence = false;\n    int replaceCount = 0;\n    \n    target->moveCursor(QTextCursor::Start);\n    hasOccurrence = findForwardWrapBeep(target, true, false, true);   // beeps if none found\n    \n    // Then, assuming we found at least one occurrence, loop replacing and finding\n    if (hasOccurrence)\n    {\n        target->textCursor().beginEditBlock();      // make this a single undoable action\n        \n        while (hasOccurrence)\n        {\n            target->textCursor().insertText(ui->replaceTextLineEdit->text());\n            replaceCount++;\n            hasOccurrence = findForwardWrapBeep(target, true, false, false);\n        }\n        \n        target->textCursor().endEditBlock();        // undoable action ends\n    }\n    \n    // Restore the original cursor as closely as we can\n    target->setTextCursor(originalCursor);\n    jumpToSelection();\n    \n    // show the replacement count\n    ui->statusText->setText(QString(\"replaced %1 occurrence%2 \").arg(replaceCount).arg(replaceCount == 1 ? \"\" : \"s\"));\n}\n\nvoid QtSLiMFindPanel::useSelectionForFind(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    QString selectionString = target->textCursor().selectedText();\n    \n    if (selectionString.length())\n        ui->findTextLineEdit->setText(selectionString);     // this will trigger QtSLiMFindPanel::findTextChanged()\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMFindPanel::useSelectionForReplace(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    QString selectionString = target->textCursor().selectedText();\n    \n    if (selectionString.length())\n        ui->replaceTextLineEdit->setText(selectionString);     // this will trigger QtSLiMFindPanel::replaceTextChanged()\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMFindPanel::jumpToSelection(void)\n{\n    ui->statusText->clear();\n    \n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    target->centerCursor();\n    QtSLiMFlashHighlightInTextEdit(target);\n}\n\nvoid QtSLiMFindPanel::jumpToLine(void)\n{\n    QPlainTextEdit *target = targetTextEditRequireModifiable(false);\n    \n    int lineIndex = target->textCursor().block().blockNumber();\n    \n    QStringList choices = QtSLiMRunLineEditArrayDialog(target->window(), \"Jump to Line:\",\n                                                       QStringList{\"Line number:\"},\n                                                       QStringList{QString::number(lineIndex)});\n    \n    if (choices.length() == 1)\n    {\n        lineIndex = choices[0].toInt();\n        \n        if (lineIndex < 1) { lineIndex = 1; qApp->beep(); }\n        if (lineIndex > target->document()->blockCount()) { lineIndex = target->document()->blockCount(); qApp->beep(); }\n        \n        QTextCursor lineCursor(target->document());\n        \n        lineCursor.setPosition(0);\n        lineCursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, lineIndex - 1);\n        \n        target->setTextCursor(lineCursor);\n        target->centerCursor();\n    }\n}\n\nvoid QtSLiMFindPanel::findBufferChanged(void)\n{\n    // If the clipboard's find buffer changes, we need to (1) update the find lineEdit, and (2) update our status text\n    \n    // We use changingFindText to avoid responding to find text changes we cause ourselves\n    if (!changingFindText)\n    {\n        QClipboard *clipboard = QGuiApplication::clipboard();\n        \n        if (clipboard && clipboard->supportsFindBuffer())\n        {\n            QString findText = clipboard->text(QClipboard::FindBuffer);\n            \n            changingFindText = true;\n            ui->findTextLineEdit->setText(findText);\n            changingFindText = false;\n            \n            ui->statusText->clear();\n            fixEnableState();\n        }\n    }\n}\n\nvoid QtSLiMFindPanel::findTextChanged(void)\n{\n    // If the find text lineEdit changes, we need to (1) update the clipboard, and (2) update our status text\n    \n    // We use changingFindText to avoid responding to find text changes we cause ourselves\n    if (!changingFindText)\n    {\n        QString findText = ui->findTextLineEdit->text();\n        \n        if (findText.length())  // don't change the find buffer if we have no find text\n        {\n            QClipboard *clipboard = QGuiApplication::clipboard();\n            \n            if (clipboard && clipboard->supportsFindBuffer())\n            {\n                changingFindText = true;\n                clipboard->setText(findText, QClipboard::FindBuffer);\n                changingFindText = false;\n            }\n            else\n            {\n                QSettings settings;\n                \n                settings.setValue(\"QtSLiMFindPanel/findText\", findText);\n            }\n        }\n        \n        ui->statusText->clear();\n        fixEnableState();\n    }\n}\n\nvoid QtSLiMFindPanel::replaceTextChanged(void)\n{\n    ui->statusText->clear();\n    \n    // Save the replace string to prefs; unlike findTextChanged() we do this even when the replace string is zero-length\n    QSettings settings;\n    \n    settings.setValue(\"QtSLiMFindPanel/replaceText\", ui->replaceTextLineEdit->text());\n}\n\nvoid QtSLiMFindPanel::optionsChanged(void)\n{\n    ui->statusText->clear();\n    \n    // When the search options change, we need to write options to prefs\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMFindPanel\");\n    settings.setValue(\"matchCase\", ui->matchCaseCheckBox->isChecked());\n    settings.setValue(\"wholeWord\", ui->wholeWordCheckBox->isChecked());\n    settings.setValue(\"wrapAround\", ui->wrapAroundCheckBox->isChecked());\n    settings.endGroup();\n}\n\nvoid QtSLiMFindPanel::fixEnableState(void)\n{\n    bool hasFindText = (ui->findTextLineEdit->text().length() > 0);\n    bool hasTarget = (QtSLiMFindPanel::targetTextEditRequireModifiable(false) != nullptr);\n    bool hasModifiableTarget = (QtSLiMFindPanel::targetTextEditRequireModifiable(true) != nullptr);\n    \n    ui->findNextButton->setEnabled(hasFindText && hasTarget);\n    ui->findPreviousButton->setEnabled(hasFindText && hasTarget);\n    ui->replaceAndFindButton->setEnabled(hasFindText && hasModifiableTarget);    \n    ui->replaceButton->setEnabled(hasFindText && hasModifiableTarget);    \n    ui->replaceAllButton->setEnabled(hasFindText && hasModifiableTarget);    \n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindPanel.h",
    "content": "//\n//  QtSLiMFindPanel.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/24/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMFINDPANEL_H\n#define QTSLIMFINDPANEL_H\n\n#include <QDialog>\n\nclass QCloseEvent;\nclass QPlainTextEdit;\n\n\nnamespace Ui {\nclass QtSLiMFindPanel;\n}\n\nclass QtSLiMFindPanel : public QDialog\n{\n    Q_OBJECT\n    \npublic:\n    static QtSLiMFindPanel &instance(void);\n    \n    // BCH 2/10/2021: Switched from QTextEdit to QPlainTextEdit for the target of the Find panel,\n    // since we are switching over to QPlainTextEdit for the script/console/output views.\n    // Unfortunate that the design kind of requires it to be one or the other; C++ for the lose.\n    // Once again we need Obj-C protocols.\n    QPlainTextEdit *targetTextEditRequireModifiable(bool requireModifiable); // public for menu enabling\n    \npublic slots:\n    void showFindPanel(void);\n    void findNext(void);\n    void findPrevious(void);\n    void replaceAndFind(void);\n    void replace(void);\n    void replaceAll(void);\n    void useSelectionForFind(void);\n    void useSelectionForReplace(void);\n    void jumpToSelection(void);\n    void jumpToLine(void);\n    void fixEnableState(void);\n    \nprivate:\n    // singleton pattern\n    explicit QtSLiMFindPanel(QWidget *p_parent = nullptr);\n    QtSLiMFindPanel(void) = delete;\n    virtual ~QtSLiMFindPanel(void) override;\n    QtSLiMFindPanel(const QtSLiMFindPanel&) = delete;\n    QtSLiMFindPanel& operator=(const QtSLiMFindPanel&) = delete;\n    \n    virtual void closeEvent(QCloseEvent *e) override;\n    \n    bool findForwardWrapBeep(QPlainTextEdit *target, bool forward, bool wrap, bool beepIfNotFound);\n    \n    bool changingFindText = false;\n    \nprivate slots:\n    void findBufferChanged(void);\n    void findTextChanged(void);\n    void replaceTextChanged(void);\n    void optionsChanged(void);\n    \nprivate:\n    Ui::QtSLiMFindPanel *ui;\n};\n\n\n#endif // QTSLIMFINDPANEL_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindPanel.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMFindPanel</class>\n <widget class=\"QDialog\" name=\"QtSLiMFindPanel\">\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>450</width>\n    <height>190</height>\n   </size>\n  </property>\n  <property name=\"maximumSize\">\n   <size>\n    <width>16777215</width>\n    <height>190</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Find &amp; Replace</string>\n  </property>\n  <property name=\"sizeGripEnabled\">\n   <bool>true</bool>\n  </property>\n  <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n   <property name=\"leftMargin\">\n    <number>8</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>8</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>8</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>8</number>\n   </property>\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <layout class=\"QGridLayout\" name=\"gridLayout\">\n       <item row=\"1\" column=\"0\">\n        <widget class=\"QLabel\" name=\"replaceLabel\">\n         <property name=\"text\">\n          <string>Replace:</string>\n         </property>\n        </widget>\n       </item>\n       <item row=\"0\" column=\"0\">\n        <widget class=\"QLabel\" name=\"findLabel\">\n         <property name=\"text\">\n          <string>Find:</string>\n         </property>\n        </widget>\n       </item>\n       <item row=\"0\" column=\"1\">\n        <widget class=\"QLineEdit\" name=\"findTextLineEdit\"/>\n       </item>\n       <item row=\"1\" column=\"1\">\n        <widget class=\"QLineEdit\" name=\"replaceTextLineEdit\"/>\n       </item>\n      </layout>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"statusText\">\n       <property name=\"font\">\n        <font>\n         <pointsize>11</pointsize>\n         <italic>true</italic>\n        </font>\n       </property>\n       <property name=\"text\">\n        <string>status text lineedit </string>\n       </property>\n       <property name=\"alignment\">\n        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"optionsLabel\">\n       <property name=\"text\">\n        <string>Options:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n       <property name=\"spacing\">\n        <number>8</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>12</number>\n       </property>\n       <item>\n        <widget class=\"QCheckBox\" name=\"matchCaseCheckBox\">\n         <property name=\"focusPolicy\">\n          <enum>Qt::NoFocus</enum>\n         </property>\n         <property name=\"text\">\n          <string>Match case</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"wholeWordCheckBox\">\n         <property name=\"focusPolicy\">\n          <enum>Qt::NoFocus</enum>\n         </property>\n         <property name=\"text\">\n          <string>Whole word</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QCheckBox\" name=\"wrapAroundCheckBox\">\n         <property name=\"focusPolicy\">\n          <enum>Qt::NoFocus</enum>\n         </property>\n         <property name=\"text\">\n          <string>Wrap around</string>\n         </property>\n        </widget>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n     <property name=\"spacing\">\n      <number>9</number>\n     </property>\n     <item>\n      <widget class=\"QPushButton\" name=\"findNextButton\">\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"text\">\n        <string>Find Next</string>\n       </property>\n       <property name=\"default\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"findPreviousButton\">\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"text\">\n        <string>Find Previous</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>10</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"replaceAndFindButton\">\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"text\">\n        <string>Replace &amp;&amp; Find</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"replaceButton\">\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"text\">\n        <string>Replace</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPushButton\" name=\"replaceAllButton\">\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"text\">\n        <string>Replace All</string>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindRecipe.cpp",
    "content": "//\n//  QtSLiMFindRecipe.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMFindRecipe.h\"\n#include \"ui_QtSLiMFindRecipe.h\"\n\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMSyntaxHighlighting.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMExtras.h\"\n\n#include <QDir>\n#include <QTextStream>\n#include <QDebug>\n\n#include <algorithm>\n#include <vector>\n\n\nQtSLiMFindRecipe::QtSLiMFindRecipe(QWidget *p_parent) : QDialog(p_parent), ui(new Ui::QtSLiMFindRecipe)\n{\n    ui->setupUi(this);\n    \n    // change the app icon to our multi-size app icon for best results\n    ui->iconSLiM->setIcon(qtSLiMAppDelegate->applicationIcon());\n    \n    // load recipes and get ready to search\n    loadRecipes();\n\tconstructMatchList();\n    updateMatchListWidget();\n\t\n\tvalidateOK();\n    updatePreview();\n\t\n    // set up the script preview with syntax coloring and tab stops\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    double tabWidth = 0;\n    \n    ui->scriptPreviewTextEdit->setFont(prefs.displayFontPref(&tabWidth));\n#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))\n    ui->scriptPreviewTextEdit->setTabStopWidth((int)floor(tabWidth));      // deprecated in 5.10\n#else\n    ui->scriptPreviewTextEdit->setTabStopDistance(tabWidth);               // added in 5.10\n#endif\n    \n    if (prefs.scriptSyntaxHighlightPref())\n        new QtSLiMScriptHighlighter(ui->scriptPreviewTextEdit->document());\n    \n    // wire things up\n    connect(ui->keyword1LineEdit, &QLineEdit::textChanged, this, &QtSLiMFindRecipe::keywordChanged);\n    connect(ui->keyword2LineEdit, &QLineEdit::textChanged, this, &QtSLiMFindRecipe::keywordChanged);\n    connect(ui->keyword3LineEdit, &QLineEdit::textChanged, this, &QtSLiMFindRecipe::keywordChanged);\n    \n    connect(ui->matchListWidget, &QListWidget::itemSelectionChanged, this, &QtSLiMFindRecipe::matchListSelectionChanged);\n    connect(ui->matchListWidget, &QListWidget::itemDoubleClicked, this, &QtSLiMFindRecipe::matchListDoubleClicked);\n}\n\nQtSLiMFindRecipe::~QtSLiMFindRecipe()\n{\n    delete ui;\n}\n\nQStringList QtSLiMFindRecipe::selectedRecipeFilenames(void)\n{\n    const QList<QListWidgetItem *> selectedItems = ui->matchListWidget->selectedItems();\n    QStringList selectedFilenames;\n    \n    for (QListWidgetItem *selectedItem : selectedItems)\n    {\n        int selectedRow = ui->matchListWidget->row(selectedItem);\n        \n        selectedFilenames.append(matchRecipeFilenames[selectedRow]);\n    }\n    \n    return selectedFilenames;\n}\n\nvoid QtSLiMFindRecipe::loadRecipes(void)\n{\n    QDir recipesDir(\":/recipes/\", \"Recipe *.*\", QDir::NoSort, QDir::Files | QDir::NoSymLinks);\n    QStringList entryList = recipesDir.entryList(QStringList(\"Recipe *.*\"));   // the previous name filter seems to be ignored\n    \n    std::sort(entryList.begin(), entryList.end(), EidosNaturalSort);\n    \n    recipeFilenames = entryList;\n    matchRecipeFilenames = entryList;\n    \n    for (QString &filename : recipeFilenames)\n    {\n        QString filePath = \":/recipes/\" + filename;\n        QFile recipeFile(filePath);\n        \n        if (recipeFile.open(QFile::ReadOnly | QFile::Text))\n        {\n            QTextStream fileTextStream(&recipeFile);\n            QString fileContents = fileTextStream.readAll();\n            \n            recipeContents.push_back(fileContents);\n        }\n        else\n        {\n            recipeContents.push_back(\"### An error occurred reading the contents of this recipe\");\n        }\n    }\n}\n\nQString QtSLiMFindRecipe::displayStringForRecipeFilename(const QString &name)\n{\n    if (name.endsWith(\".txt\"))\n    {\n        // Remove the .txt extension for SLiM models\n        return name.mid(7, name.length() - 11);\n    }\n    else if (name.endsWith(\".py\"))\n    {\n        // Leave the .py extension for Python models, and add a python\n        // FIXME it would be nice to force these lines to have the same line height, but I can't find a way to do so\n        return name.mid(7, name.length() - 7) + QString(\" 🐍\");\n    }\n    \n    return \"\";\n}\n\nbool QtSLiMFindRecipe::recipeIndexMatchesKeyword(int recipeIndex, QString &keyword)\n{\n\t// an empty keyword matches all recipes\n    if (keyword.length() == 0)\n        return true;\n\t\n\t// look for a match in the filename\n    const QString &filename = recipeFilenames[recipeIndex];\n\t\n    if (filename.contains(keyword, Qt::CaseInsensitive))\n\t\treturn true;\n\t\n\t// look for a match in the file contents\n    const QString &contents = recipeContents[recipeIndex];\n\t\n    if (contents.contains(keyword, Qt::CaseInsensitive))\n\t\treturn true;\n\t\n\treturn false;\n}\n\nvoid QtSLiMFindRecipe::constructMatchList(void)\n{\n    matchRecipeFilenames.clear();\n    \n    QString keyword1 = ui->keyword1LineEdit->text();\n    QString keyword2 = ui->keyword2LineEdit->text();\n    QString keyword3 = ui->keyword3LineEdit->text();\n    \n    for (int i = 0; i < recipeFilenames.size(); ++i)\n    {\n        if (recipeIndexMatchesKeyword(i, keyword1) && recipeIndexMatchesKeyword(i, keyword2) && recipeIndexMatchesKeyword(i, keyword3))\n            matchRecipeFilenames.append(recipeFilenames[i]);\n    }\n}\n\nvoid QtSLiMFindRecipe::updateMatchListWidget(void)\n{\n    QListWidget *matchList = ui->matchListWidget;\n    \n    matchList->clear();\n    \n    for (const QString &match : static_cast<const QStringList &>(matchRecipeFilenames))\n        matchList->addItem(displayStringForRecipeFilename(match));\n}\n\nvoid QtSLiMFindRecipe::validateOK(void)\n{\n    QPushButton *okButton = ui->buttonBox->button(QDialogButtonBox::Ok);\n    \n    okButton->setEnabled(ui->matchListWidget->selectedItems().size() > 0);\n}\n\nvoid QtSLiMFindRecipe::updatePreview(void)\n{\n    if (ui->matchListWidget->selectedItems().size() == 0)\n\t{\n        ui->scriptPreviewTextEdit->clear();\n\t}\n    else if (ui->matchListWidget->selectedItems().size() > 1)\n\t{\n        ui->scriptPreviewTextEdit->setPlainText(\"// Multiple recipes selected\");\n\t}\n\telse\n\t{\n        int selectedRowIndex = ui->matchListWidget->currentRow();\n        QString &filename = matchRecipeFilenames[selectedRowIndex];\n        \n        QString filePath = \":/recipes/\" + filename;\n        QFile recipeFile(filePath);\n        \n        if (recipeFile.open(QFile::ReadOnly | QFile::Text))\n        {\n            QTextStream fileTextStream(&recipeFile);\n            QString fileContents = fileTextStream.readAll();\n            \n            ui->scriptPreviewTextEdit->setPlainText(fileContents);\n        }\n        else\n        {\n            ui->scriptPreviewTextEdit->setPlainText(\"### An error occurred reading the contents of this recipe\");\n        }\n        \n\t\thighlightPreview();\n\t}\n}\n\nvoid QtSLiMFindRecipe::highlightPreview(void)\n{\n    // thanks to https://stackoverflow.com/a/16149381/2752221\n    QPlainTextEdit *script = ui->scriptPreviewTextEdit;\n    const QString &scriptString = script->toPlainText();\n    QTextCursor tc = script->textCursor();\n    tc.select(QTextCursor::Document);\n    \n    QString keyword1 = ui->keyword1LineEdit->text();\n    QString keyword2 = ui->keyword2LineEdit->text();\n    QString keyword3 = ui->keyword3LineEdit->text();\n    const std::vector<QString> keywords{keyword1, keyword2, keyword3};\n    \n    QList<QTextEdit::ExtraSelection> extraSelections;\n    QTextCharFormat format;\n    \n    format.setBackground(Qt::yellow);\n    \n    for (const QString &keyword : keywords)\n    {\n        if (keyword.length() == 0)\n            continue;\n        \n        int from = 0;\n        \n        while (true)\n        {\n            int matchPos = scriptString.indexOf(keyword, from, Qt::CaseInsensitive);\n            \n            if (matchPos == -1)\n                break;\n            \n            QTextEdit::ExtraSelection sel;\n            sel.format = format;\n            sel.cursor = tc;                    // this makes the cursor refer to the document, I think\n            sel.cursor.clearSelection();        // this seems unnecessary to me, but I'm not certain\n            sel.cursor.setPosition(matchPos);\n            sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, keyword.length());\n            extraSelections.append(sel);\n            \n            from = matchPos + 1;\n        }\n    }\n    \n    script->setExtraSelections(extraSelections);\n}\n\nvoid QtSLiMFindRecipe::keywordChanged()\n{\n    // FIXME would be nice to preserve the selection across this; see -[FindRecipeController keywordChanged:]\n    constructMatchList();\n    updateMatchListWidget();\n\tvalidateOK();\n    highlightPreview();\n}\n\nvoid QtSLiMFindRecipe::matchListSelectionChanged()\n{\n    validateOK();\n    updatePreview();\n}\n\nvoid QtSLiMFindRecipe::matchListDoubleClicked()\n{\n    if (ui->matchListWidget->selectedItems().size() > 0)\n        done(QDialog::Accepted);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindRecipe.h",
    "content": "//\n//  QtSLiMFindRecipe.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/6/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMFINDRECIPE_H\n#define QTSLIMFINDRECIPE_H\n\n#include <QString>\n#include <QStringList>\n#include <QDialog>\n\n\nnamespace Ui {\nclass QtSLiMFindRecipe;\n}\n\nclass QtSLiMFindRecipe : public QDialog\n{\n    Q_OBJECT\n    \n    QStringList recipeFilenames;\n    QStringList recipeContents;\n    \n    QStringList matchRecipeFilenames;\n    \npublic:\n    explicit QtSLiMFindRecipe(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMFindRecipe() override;\n    \n    QStringList selectedRecipeFilenames(void);\n    \nprotected:\n    void loadRecipes(void);\n    QString displayStringForRecipeFilename(const QString &name);\n    bool recipeIndexMatchesKeyword(int recipeIndex, QString &keyword);\n    void constructMatchList(void);\n    void updateMatchListWidget(void);\n    void validateOK(void);\n    void updatePreview(void);\n    void highlightPreview(void);\n    \nprotected slots:\n    void keywordChanged();\n    void matchListSelectionChanged();\n    void matchListDoubleClicked();\n    \nprivate:\n    Ui::QtSLiMFindRecipe *ui;\n};\n\n\n#endif // QTSLIMFINDRECIPE_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMFindRecipe.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMFindRecipe</class>\n <widget class=\"QDialog\" name=\"QtSLiMFindRecipe\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>824</width>\n    <height>736</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"modal\">\n   <bool>true</bool>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n   <property name=\"spacing\">\n    <number>20</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>20</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>20</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>20</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>20</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"sizeConstraint\">\n      <enum>QLayout::SetMinimumSize</enum>\n     </property>\n     <item>\n      <widget class=\"QtSLiMIconView\" name=\"iconSLiM\">\n       <property name=\"enabled\">\n        <bool>true</bool>\n       </property>\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"icons.qrc\">\n         <normaloff>:/icons/AppIcon128.png</normaloff>:/icons/AppIcon128.png</iconset>\n       </property>\n       <property name=\"iconSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"autoDefault\">\n        <bool>false</bool>\n       </property>\n       <property name=\"flat\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n       <property name=\"spacing\">\n        <number>3</number>\n       </property>\n       <item>\n        <widget class=\"QLabel\" name=\"label\">\n         <property name=\"text\">\n          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Find Recipe&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QLabel\" name=\"label_2\">\n         <property name=\"text\">\n          <string>Enter the search keywords and select a match from the list.</string>\n         </property>\n        </widget>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n     <item>\n      <spacer name=\"horizontalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>70</width>\n         <height>20</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n       <property name=\"spacing\">\n        <number>12</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n         <property name=\"sizeConstraint\">\n          <enum>QLayout::SetMinimumSize</enum>\n         </property>\n         <item alignment=\"Qt::AlignTop\">\n          <widget class=\"QLabel\" name=\"label_3\">\n           <property name=\"text\">\n            <string>Keywords:</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n           <property name=\"spacing\">\n            <number>2</number>\n           </property>\n           <item>\n            <widget class=\"QLineEdit\" name=\"keyword1LineEdit\"/>\n           </item>\n           <item>\n            <widget class=\"QLabel\" name=\"label_4\">\n             <property name=\"text\">\n              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;AND&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QLineEdit\" name=\"keyword2LineEdit\"/>\n           </item>\n           <item>\n            <widget class=\"QLabel\" name=\"label_5\">\n             <property name=\"text\">\n              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;AND&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QLineEdit\" name=\"keyword3LineEdit\"/>\n           </item>\n          </layout>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <spacer name=\"verticalSpacer\">\n         <property name=\"orientation\">\n          <enum>Qt::Vertical</enum>\n         </property>\n         <property name=\"sizeType\">\n          <enum>QSizePolicy::Fixed</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>20</width>\n           <height>5</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n       <item>\n        <widget class=\"QLabel\" name=\"label_6\">\n         <property name=\"text\">\n          <string>Matches:</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QListWidget\" name=\"matchListWidget\">\n         <property name=\"sizePolicy\">\n          <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n           <horstretch>0</horstretch>\n           <verstretch>1</verstretch>\n          </sizepolicy>\n         </property>\n         <property name=\"minimumSize\">\n          <size>\n           <width>700</width>\n           <height>110</height>\n          </size>\n         </property>\n         <property name=\"verticalScrollBarPolicy\">\n          <enum>Qt::ScrollBarAlwaysOn</enum>\n         </property>\n         <property name=\"selectionMode\">\n          <enum>QAbstractItemView::ExtendedSelection</enum>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QPlainTextEdit\" name=\"scriptPreviewTextEdit\">\n         <property name=\"sizePolicy\">\n          <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n           <horstretch>0</horstretch>\n           <verstretch>2</verstretch>\n          </sizepolicy>\n         </property>\n         <property name=\"minimumSize\">\n          <size>\n           <width>0</width>\n           <height>220</height>\n          </size>\n         </property>\n         <property name=\"verticalScrollBarPolicy\">\n          <enum>Qt::ScrollBarAlwaysOn</enum>\n         </property>\n         <property name=\"readOnly\">\n          <bool>true</bool>\n         </property>\n        </widget>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <widget class=\"QDialogButtonBox\" name=\"buttonBox\">\n     <property name=\"orientation\">\n      <enum>Qt::Horizontal</enum>\n     </property>\n     <property name=\"standardButtons\">\n      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMIconView</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"icons.qrc\"/>\n </resources>\n <connections>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>accepted()</signal>\n   <receiver>QtSLiMFindRecipe</receiver>\n   <slot>accept()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>248</x>\n     <y>254</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>157</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>rejected()</signal>\n   <receiver>QtSLiMFindRecipe</receiver>\n   <slot>reject()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>316</x>\n     <y>260</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>286</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n </connections>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView.cpp",
    "content": "//\n//  QtSLiMGraphView.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/27/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView.h\"\n\n#include <QDateTime>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QApplication>\n#include <QGuiApplication>\n#include <QClipboard>\n#include <QMimeData>\n#include <QFileDialog>\n#include <QStandardPaths>\n#include <QPdfWriter>\n#include <QBuffer>\n#include <QComboBox>\n#include <QtGlobal>\n#include <QMessageBox>\n#include <QLabel>\n#include <QPainterPath>\n#include <QDebug>\n\n#include <map>\n#include <string>\n#include <algorithm>\n#include <vector>\n#include <cmath>\n\n#include \"species.h\"\n#include \"subpopulation.h\"\n#include \"haplosome.h\"\n#include \"mutation_run.h\"\n\n\nQFont QtSLiMGraphView::labelFontOfPointSize(double size)\n{\n    static QFont timesNewRoman(\"Times New Roman\", 10);\n    \n    // Derive a font of the proper size, while leaving the original untouched\n    QFont font(timesNewRoman);\n#ifdef __linux__\n    font.setPointSizeF(size * 0.75);\n#else\n    // font sizes are calibrated for macOS; on Linux they need to be a little smaller\n    font.setPointSizeF(size);\n#endif\n    \n    return font;\n}\n\nQtSLiMGraphView::QtSLiMGraphView(QWidget *p_parent, QtSLiMWindow *controller) : QWidget(p_parent)\n{\n    controller_ = controller;\n    setFocalDisplaySpecies(controller_->focalDisplaySpecies());\n    \n    connect(controller, &QtSLiMWindow::controllerFullUpdateAfterTick, this, &QtSLiMGraphView::updateAfterTick);\n    connect(controller, &QtSLiMWindow::controllerTickFinished, this, &QtSLiMGraphView::controllerTickFinished);\n    connect(controller, &QtSLiMWindow::controllerRecycled, this, &QtSLiMGraphView::controllerRecycled);\n    \n    original_x0_ = 0.0;\n    original_x1_ = 1.0;\n    original_y0_ = 0.0;\n    original_y1_ = 1.0;\n    \n    x0_ = original_x0_;\n    x1_ = original_x1_;\n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    showXAxis_ = true;\n    allowXAxisUserRescale_ = true;\n    showXAxisTicks_ = true;\n    \n    showYAxis_ = true;\n    allowYAxisUserRescale_ = true;\n    showYAxisTicks_ = true;\n    \n    xAxisMin_ = x0_;\n    xAxisMax_ = x1_;\n    xAxisMajorTickInterval_ = 0.5;\n    xAxisMinorTickInterval_ = 0.25;\n    xAxisMajorTickModulus_ = 2;\n    xAxisHistogramStyle_ = false;\n    xAxisTickValuePrecision_ = 1;\n    xAxisLabelsType_ = 1;           // default numeric labels\n\n    yAxisMin_ = y0_;\n    yAxisMax_ = y1_;\n    yAxisMajorTickInterval_ = 0.5;\n    yAxisMinorTickInterval_ = 0.25;\n    yAxisMajorTickModulus_ = 2;\n    yAxisTickValuePrecision_ = 1;\n    yAxisHistogramStyle_ = false;\n    yAxisLog_ = false;\n    yAxisLabelsType_ = 1;           // default numeric labels\n    \n    xAxisLabel_ = \"This is the x-axis, yo\";\n    yAxisLabel_ = \"This is the y-axis, yo\";\n    \n    legendVisible_ = true;\n    showHorizontalGridLines_ = false;\n    showVerticalGridLines_ = false;\n    showGridLinesMajorOnly_ = false;\n    showFullBox_ = false;\n    allowHorizontalGridChange_ = true;\n    allowVerticalGridChange_ = true;\n    allowFullBoxChange_ = true;\n}\n\nvoid QtSLiMGraphView::addedToWindow(void)\n{\n}\n\nQtSLiMGraphView::~QtSLiMGraphView()\n{\n    // It would be nice if we could call these methods automatically for subclasses, but we cannot.  By the time\n    // this destructor has been called, the subclass has already been destructed, and a virtual function call\n    // here calls the QtSLiMGraphView implementation, not the subclass implementation.  Subclasses that use these\n    // methods must call them themselves in their destructors.\n    QtSLiMGraphView::invalidateDrawingCache();\n    QtSLiMGraphView::invalidateCachedData();\n    \n    if (xAxisAt_)\n    {\n        delete xAxisAt_;\n        xAxisAt_ = nullptr;\n    }\n    if (xAxisLabels_)\n    {\n        delete xAxisLabels_;\n        xAxisLabels_ = nullptr;\n    }\n    if (yAxisAt_)\n    {\n        delete yAxisAt_;\n        yAxisAt_ = nullptr;\n    }\n    if (yAxisLabels_)\n    {\n        delete yAxisLabels_;\n        yAxisLabels_ = nullptr;\n    }\n    xAxisLabelsType_ = 1;\n    yAxisLabelsType_ = 1;\n    \n    controller_ = nullptr;\n}\n\nvoid QtSLiMGraphView::setFocalDisplaySpecies(Species *species)\n{\n    if (species)\n    {\n        focalSpeciesName_ = species->name_;\n        // focalSpeciesAvatar_ is set by updateSpeciesBadge()\n    }\n    else\n    {\n        focalSpeciesName_ = \"\";\n        focalSpeciesAvatar_ = \"\";\n    }\n}\n\nSpecies *QtSLiMGraphView::focalDisplaySpecies(void)\n{\n    // We look up our focal species object by name every time, since keeping a pointer to it would be unsafe\n    // Before initialize() is done species have not been created, so we return nullptr in that case\n    // Some graph types will have no focal species; in that case we always return nullptr\n    if (focalSpeciesName_.length() == 0)\n        return nullptr;\n    \n    if (controller_ && controller_->community && (controller_->community->Tick() >= 1))\n        return controller_->community->SpeciesWithName(focalSpeciesName_);\n    \n    return nullptr;\n}\n\nbool QtSLiMGraphView::missingFocalDisplaySpecies(void)\n{\n    if (focalSpeciesName_.length() == 0)\n        return false;\n    return (focalDisplaySpecies() == nullptr);\n}\n\nvoid QtSLiMGraphView::updateSpeciesBadge(void)\n{\n    // graphs that do not have a focal species, such as QtSLiMGraphView_MultispeciesPopSizeOverTime, have no species badge\n    if (focalSpeciesName_.length() == 0)\n        return;\n    \n    // if we do not have a button layout, punt; in some cases we get called by updateAfterTick() before we have been placed in our window\n    QHBoxLayout *enclosingLayout = buttonLayout();\n    \n    if (!enclosingLayout)\n        return;\n    \n    int layoutCount = enclosingLayout->count();\n    QLayoutItem *labelItem = (layoutCount > 0) ? enclosingLayout->itemAt(0) : nullptr;\n    QWidget *labelWidget = labelItem ? labelItem->widget() : nullptr;\n    QLabel *speciesLabel = qobject_cast<QLabel *>(labelWidget);\n    \n    if (!speciesLabel)\n    {\n        qDebug() << \"No species label!  enclosingLayout ==\" << enclosingLayout << \", layoutCount ==\" << layoutCount << \", labelItem ==\" << labelItem << \", labelWidget ==\" << labelWidget;\n        return;\n    }\n    \n    Species *graphSpecies = focalDisplaySpecies();\n    \n    // Cache our graphSpecies avatar whenever we're in a valid state, because it could change,\n    // and because we want to be able to display it even when the sim is in an invalid state\n    if (graphSpecies)\n    {\n        if (graphSpecies->community_.all_species_.size() > 1)\n            focalSpeciesAvatar_ = graphSpecies->avatar_;\n        else\n            focalSpeciesAvatar_ = \"\";\n    }\n    \n    // Display our current avatar cache; if we have no avatar, hide the label\n    if (focalSpeciesAvatar_.length())\n    {\n        speciesLabel->setText(QString::fromStdString(focalSpeciesAvatar_));\n        speciesLabel->setHidden(false);\n    }\n    else\n    {\n        speciesLabel->setText(\"\");\n        speciesLabel->setHidden(true);\n    }\n}\n\nQHBoxLayout *QtSLiMGraphView::buttonLayout(void)\n{\n    // Note this method makes assumptions about the layouts in the parent window\n    // It needs to be kept parallel to QtSLiMWindow::graphWindowWithView()\n    QVBoxLayout *topLayout = dynamic_cast<QVBoxLayout *>(window()->layout());\n    \n    if (topLayout && (topLayout->count() >= 2))\n    {\n        QLayoutItem *layoutItem = topLayout->itemAt(1);\n        \n        return dynamic_cast<QHBoxLayout *>(layoutItem);\n    }\n    \n    return nullptr;\n}\n\nQPushButton *QtSLiMGraphView::actionButton(void)\n{\n    // Note this method makes assumptions about the layouts in the parent window\n    // It needs to be kept parallel to QtSLiMWindow::graphWindowWithView()\n    QHBoxLayout *enclosingLayout = buttonLayout();\n    int layoutCount = enclosingLayout ? enclosingLayout->count() : 0;\n    QLayoutItem *buttonItem = (layoutCount > 0) ? enclosingLayout->itemAt(layoutCount - 1) : nullptr;\n    QWidget *buttonWidget = buttonItem ? buttonItem->widget() : nullptr;\n    \n    return qobject_cast<QPushButton *>(buttonWidget);\n}\n\nQComboBox *QtSLiMGraphView::newButtonInLayout(QHBoxLayout *p_layout)\n{\n    QComboBox *button = new QComboBox(this);\n    button->setEditable(false);\n    button->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);\n    button->setMinimumContentsLength(2);\n    p_layout->insertWidget(p_layout->count() - 2, button);  // left of the spacer and action button\n    \n    return button;\n}\n\nQRect QtSLiMGraphView::interiorRectForBounds(QRect bounds)\n{\n    // The interiorRect is the area which QtSLiMGraphView clips the plotting within.  So it is the live plot\n    // area, within the axes of the plot.  In a borderless plot, it is the full interior area of the window,\n    // but afer setting up clipping drawContents() will inset the interiorRect by the margins given to\n    // setBorderless(); the data area will be inset by the margins, but not clipped to the margins.  This is\n    // conceptually similar to the 4% expansion of the axis ranges done in bordered plots.\n    QRect interiorRect = bounds;\n    \n    // If the plot is borderless, there is no inset for the interior rect at all\n    if (is_borderless_)\n        return interiorRect;\n    \n    // For now, 10 pixels margin on a side if there is no axis, 40 pixels margin if there is an axis\n    \n    if (showXAxis_)\n        interiorRect.adjust(50, 0, -10, 0);\n    else\n        interiorRect.adjust(10, 0, -10, 0);\n    \n    if (showYAxis_)\n        interiorRect.adjust(0, 50, 0, -10);\n    else\n        interiorRect.adjust(0, 10, 0, -10);\n    \n    return interiorRect;\n}\n\ndouble QtSLiMGraphView::plotToDeviceX(double plotx, QRect interiorRect)\n{\n\tdouble fractionAlongSide = (plotx - x0_) / (x1_ - x0_);\n\t\n    if (generatingPDF_)\n    {\n        // We go from the left edge of the first pixel to the right edge of the last pixel\n        return (fractionAlongSide * interiorRect.width() + interiorRect.x());\n    }\n    else\n    {\n        // We go from the center of the first pixel to the center of the last pixel\n        return (fractionAlongSide * (interiorRect.width() - 1.0) + interiorRect.x()) + 0.5;\n    }\n}\n\ndouble QtSLiMGraphView::plotToDeviceY(double ploty, QRect interiorRect)\n{\n\tdouble fractionAlongSide = (ploty - y0_) / (y1_ - y0_);\n\t\n    if (generatingPDF_)\n    {\n        // We go from the bottom edge of the first pixel to the top edge of the last pixel\n        return (fractionAlongSide * interiorRect.height() + interiorRect.y());\n    }\n    else\n    {\n        // We go from the center of the first pixel to the center of the last pixel\n        return (fractionAlongSide * (interiorRect.height() - 1.0) + interiorRect.y()) + 0.5;\n    }\n}\n\ndouble QtSLiMGraphView::roundPlotToDeviceX(double plotx, QRect interiorRect)\n{\n\tdouble fractionAlongSide = (plotx - x0_) / (x1_ - x0_);\n\t\n    if (generatingPDF_)\n    {\n        // We go from the left edge of the first pixel to the right edge of the last pixel\n        return (fractionAlongSide * interiorRect.width() + interiorRect.x());\n    }\n    else\n    {\n        // We go from the center of the first pixel to the center of the last pixel, rounded off to pixel midpoints\n        return SLIM_SCREEN_ROUND(fractionAlongSide * (interiorRect.width() - 1.0) + interiorRect.x()) + 0.5;\n    }\n}\n\ndouble QtSLiMGraphView::roundPlotToDeviceY(double ploty, QRect interiorRect)\n{\n\tdouble fractionAlongSide = (ploty - y0_) / (y1_ - y0_);\n\t\n    if (generatingPDF_)\n    {\n        // We go from the bottom edge of the first pixel to the top edge of the last pixel\n        return (fractionAlongSide * interiorRect.height() + interiorRect.y());\n    }\n    else\n    {\n        // We go from the center of the first pixel to the center of the last pixel, rounded off to pixel midpoints\n        return SLIM_SCREEN_ROUND(fractionAlongSide * (interiorRect.height() - 1.0) + interiorRect.y()) + 0.5;\n    }\n}\n\nvoid QtSLiMGraphView::willDraw(QPainter & /* painter */, QRect /* interiorRect */)\n{\n}\n\nQString QtSLiMGraphView::labelTextForTick(double tickValue, int tickValuePrecision, double minorTickInterval)\n{\n    // This utility method handles negative tickValuePrecision values, which request\n    // output mode 'g' instead of 'f', and also make sure that values extremely close\n    // to zero are output as zero.  (The need for the latter correction is because\n    // we use a double value as a for loop index in the plotting code, which is not\n    // really a good idea.)\n    if (std::fabs(tickValue) < std::fabs(minorTickInterval) / 1e6)\n        tickValue = 0.0;\n    \n    if (tickValuePrecision < 0)\n        return QString(\"%1\").arg(tickValue, 0, 'g', -tickValuePrecision);\n    else\n        return QString(\"%1\").arg(tickValue, 0, 'f', tickValuePrecision);\n}\n\nvoid QtSLiMGraphView::drawAxisTickLabel(QPainter &painter, QString labelText, double xValueForTick, double axisLength,\n                                        bool isFirstTick, bool isLastTick)\n{\n    // Draws a tick label.  This method thinks of the axis as being the x axis, and assumes that the coordinate system\n    // of the painter has been rotated as needed for that assumption to make sense.  The coordinate system should be\n    // shifted so that the axis starts at x==0, and drawing the text with a baseline at y==0 is correct.\n    QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, labelText);\n    double labelWidth = labelBoundingRect.width();\n    double labelX = xValueForTick - SLIM_SCREEN_ROUND(labelWidth / 2.0);\n    \n    if (tweakXAxisTickLabelAlignment_)\n    {\n        if (isFirstTick && (labelX < 0))\n            labelX = xValueForTick - 2.0;\n        else if (isLastTick && (labelX + labelWidth > axisLength))\n            labelX = xValueForTick - SLIM_SCREEN_ROUND(labelWidth) + 2.0;\n    }\n    \n    // draw a debugging line that is positioned where we intend the baseline of the tick label to go\n    //painter.fillRect(QRectF(0, 0, axisLength, 1), Qt::red);\n    \n    painter.drawText(QPointF(labelX, 0), labelText);\n}\n\nvoid QtSLiMGraphView::drawXAxisTicks(QPainter &painter, QRect interiorRect)\n{\n    QFont font = QtSLiMGraphView::fontForTickLabels();\n    QFontMetricsF fontMetrics(font);\n    double capHeight = std::ceil(fontMetrics.capHeight());\n    \n    painter.setFont(font);\n    painter.setBrush(Qt::black);\n    \n    if (xAxisAt_)\n    {\n        // user-specified tick positions, which may or may not have corresponding label strings\n        int tickCount = (int)xAxisAt_->size();\n        \n        for (int tickIndex = 0; tickIndex < tickCount; ++tickIndex)\n        {\n            double tickValue = (*xAxisAt_)[tickIndex];\n            bool isFirstTick = (tickIndex == 0);\n            bool isLastTick = (tickIndex == tickCount - 1);\n            QString labelText;\n            \n            if (xAxisLabelsType_ == 1)\n                labelText = labelTextForTick(tickValue, -8, 1e-100);\n            else if (xAxisLabelsType_ == 2)\n                labelText = (*xAxisLabels_)[tickIndex];\n            else\n                labelText = \" \";    // force a major tick mark when labels are turned off\n            \n            bool isMajorTick = labelText.length();\n            double tickLength = (isMajorTick ? 6 : 3);\n            double xValueForTick;\n            \n            if (generatingPDF_)\n                xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + interiorRect.width() * ((tickValue - x0_) / (x1_ - x0_)) - 0.5);    // left edge of pixel\n            else\n                xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + (interiorRect.width() - 1) * ((tickValue - x0_) / (x1_ - x0_)));    // left edge of pixel\n            \n            //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", xValueForTick == \" << xValueForTick;\n            \n            painter.fillRect(QRectF(xValueForTick, interiorRect.y() - tickLength, 1, tickLength - (generatingPDF_ ? 0.5 : 0.0)), Qt::black);\n            \n            if (isMajorTick && (xAxisLabelsType_ != 0))\n            {\n                painter.save();\n                painter.translate(interiorRect.x(), 41 - capHeight);\n                painter.scale(1.0, -1.0);\n                drawAxisTickLabel(painter, labelText, xValueForTick - interiorRect.x(), interiorRect.width(), isFirstTick, isLastTick);\n                painter.restore();\n            }\n        }\n    }\n    else\n    {\n        double axisMin = xAxisMin_;\n        double axisMax = xAxisMax_;\n        int tickValuePrecision = xAxisTickValuePrecision_;\n        double tickValue;\n        \n        if (!xAxisHistogramStyle_)\n        {\n            double minorTickInterval = xAxisMinorTickInterval_;\n            int majorTickModulus = xAxisMajorTickModulus_;\n            int tickIndex;\n            \n            for (tickValue = axisMin, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n            {\n                bool isFirstTick = (tickIndex == 0);\n                bool isLastTick = (tickValue + minorTickInterval > (axisMax + minorTickInterval / 10.0));\n                bool isMajorTick = ((tickIndex % majorTickModulus) == 0);\n                double tickLength = (isMajorTick ? 6 : 3);\n                double xValueForTick;\n                \n                if (generatingPDF_)\n                    xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + interiorRect.width() * ((tickValue - x0_) / (x1_ - x0_)) - 0.5);    // left edge of pixel\n                else\n                    xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + (interiorRect.width() - 1) * ((tickValue - x0_) / (x1_ - x0_)));    // left edge of pixel\n                \n                //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", xValueForTick == \" << xValueForTick;\n                \n                painter.fillRect(QRectF(xValueForTick, interiorRect.y() - tickLength, 1, tickLength - (generatingPDF_ ? 0.5 : 0.0)), Qt::black);\n                \n                if (isMajorTick && (xAxisLabelsType_ != 0))\n                {\n                    QString labelText = labelTextForTick(tickValue, tickValuePrecision, minorTickInterval);\n                    \n                    painter.save();\n                    painter.translate(interiorRect.x(), 41 - capHeight);\n                    painter.scale(1.0, -1.0);\n                    drawAxisTickLabel(painter, labelText, xValueForTick - interiorRect.x(), interiorRect.width(), isFirstTick, isLastTick);\n                    painter.restore();\n                }\n            }\n        }\n        else\n        {\n            // Histogram-style ticks are centered under each bar position, at the 0.5 positions on the axis\n            // So a histogram-style axis declared with min/max of 0/10 actually spans 1..10, with ticks at 0.5..9.5 labeled 1..10\n            double axisStart = axisMin + 1;\n            \n            for (tickValue = axisStart; tickValue <= axisMax; tickValue++)\n            {\n                bool isFirstTick = (tickValue == axisStart);\n                bool isLastTick = (tickValue == axisMax);\n                bool isMajorTick = isFirstTick || isLastTick;\n                double tickLength = (isMajorTick ? 6 : 3);\n                double xValueForTick;\n                \n                if (generatingPDF_)\n                    xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + interiorRect.width() * ((tickValue - 0.5 - x0_) / (x1_ - x0_)) - 0.5);    // left edge of pixel\n                else\n                    xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + (interiorRect.width() - 1) * ((tickValue - 0.5 - x0_) / (x1_ - x0_)));    // left edge of pixel\n                \n                //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", xValueForTick == \" << xValueForTick;\n                \n                painter.fillRect(QRectF(xValueForTick, interiorRect.y() - tickLength, 1, tickLength - (generatingPDF_ ? 0.5 : 0.0)), Qt::black);\n                \n                if (isMajorTick && (xAxisLabelsType_ != 0))\n                {\n                    QString labelText = labelTextForTick(tickValue, tickValuePrecision, 1.0);\n                    \n                    painter.save();\n                    painter.translate(interiorRect.x(), 41 - capHeight);\n                    painter.scale(1.0, -1.0);\n                    drawAxisTickLabel(painter, labelText, xValueForTick - interiorRect.x(), interiorRect.width(), isFirstTick, isLastTick);\n                    painter.restore();\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView::drawXAxis(QPainter &painter, QRect interiorRect)\n{\n    double yAxisFudge = showYAxis_ ? 1 : (generatingPDF_ ? 0.5 : 0);\n\tQRectF axisRect(interiorRect.x() - yAxisFudge, interiorRect.y() - 1, interiorRect.width() + yAxisFudge + (generatingPDF_ ? 0.5 : 0), 1);\n\t\n    painter.fillRect(axisRect, Qt::black);\n\t\n\t// show label\n    QFont font = QtSLiMGraphView::fontForAxisLabels();\n    QFontMetricsF fontMetrics(font);\n    double capHeight = fontMetrics.capHeight();\n    \n    painter.setFont(font);\n    painter.setBrush(Qt::black);\n    \n    QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, xAxisLabel_);\n    QPoint drawPoint(interiorRect.x() + (interiorRect.width() - labelBoundingRect.width()) / 2, 0);\n    \n    painter.save();\n    painter.translate(0, 14 - std::ceil(capHeight / 2.0));\n    painter.scale(1.0, -1.0);\n    \n    // draw debugging lines that are positioned where we intend the axis label to go\n    //painter.fillRect(QRectF(interiorRect.x(), 0, interiorRect.width(), 1), Qt::blue);\n    //painter.fillRect(QRectF(drawPoint.x(), -capHeight * 0.5, labelBoundingRect.width(), 1), Qt::red);\n    \n    painter.drawText(drawPoint, xAxisLabel_);\n    \n    painter.restore();\n}\n\nvoid QtSLiMGraphView::drawYAxisTicks(QPainter &painter, QRect interiorRect)\n{\n    painter.setFont(QtSLiMGraphView::fontForTickLabels());\n    painter.setBrush(Qt::black);\n    \n    if (yAxisAt_)\n    {\n        // user-specified tick positions, which may or may not have corresponding label strings\n        int tickCount = (int)yAxisAt_->size();\n        \n        for (int tickIndex = 0; tickIndex < tickCount; ++tickIndex)\n        {\n            double tickValue = (*yAxisAt_)[tickIndex];\n            bool isFirstTick = (tickIndex == 0);\n            bool isLastTick = (tickIndex == tickCount - 1);\n            QString labelText;\n            \n            if (yAxisLabelsType_ == 1)\n                labelText = labelTextForTick(tickValue, -8, 1e-100);\n            else if (yAxisLabelsType_ == 2)\n                labelText = (*yAxisLabels_)[tickIndex];\n            else\n                labelText = \" \";    // force a major tick mark when labels are turned off\n            \n            bool isMajorTick = labelText.length();\n            double tickLength = (isMajorTick ? 6 : 3);\n            double yValueForTick;\n            \n            if (generatingPDF_)\n                yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + interiorRect.height() * ((tickValue - y0_) / (y1_ - y0_)) - 0.5);   // bottom edge of pixel\n            else\n                yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + (interiorRect.height() - 1) * ((tickValue - y0_) / (y1_ - y0_)));   // bottom edge of pixel\n            \n            //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", yValueForTick == \" << yValueForTick;\n            \n            painter.fillRect(QRectF(interiorRect.x() - tickLength, yValueForTick, tickLength - (generatingPDF_ ? 0.5 : 0.0), 1), Qt::black);\n            \n            if (isMajorTick)\n            {\n                painter.save();\n                painter.translate(41, interiorRect.y());\n                painter.rotate(90);\n                painter.scale(1.0, -1.0);\n                drawAxisTickLabel(painter, labelText, yValueForTick - interiorRect.y(), interiorRect.height(), isFirstTick, isLastTick);\n                painter.restore();\n            }\n        }\n    }\n    else\n    {\n        double axisMin = yAxisMin_;\n        double axisMax = yAxisMax_;\n        int tickValuePrecision = yAxisTickValuePrecision_;\n        double tickValue;\n        \n        if (!yAxisHistogramStyle_)\n        {\n            double axisStart = (yAxisLog_ ? round(yAxisMin_) : yAxisMin_);  // with a log scale, we leave a little room at the bottom\n            double minorTickInterval = yAxisMinorTickInterval_;\n            int majorTickModulus = yAxisMajorTickModulus_;\n            int tickIndex;\n            \n            for (tickValue = axisStart, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n            {\n                bool isFirstTick = (tickIndex == 0);\n                bool isLastTick = (tickValue + minorTickInterval > (axisMax + minorTickInterval / 10.0));\n                bool isMajorTick = ((tickIndex % majorTickModulus) == 0);\n                double tickLength = (isMajorTick ? 6 : 3);\n                double transformedTickValue = tickValue;\n                \n                if (yAxisLog_ && !isMajorTick)\n                {\n                    // with a log scale, adjust the tick positions so they are non-linear; this is hackish\n                    double intPart = std::floor(tickValue);\n                    double fractPart = tickValue - intPart;\n                    double minorTickIndex = fractPart * 9.0;\n                    double minorTickOffset = std::log10(minorTickIndex + 1.0);\n                    transformedTickValue = intPart + minorTickOffset;\n                    //std::cout << intPart << \" , \" << fractPart << \"\\n\";\n                }\n                \n                double yValueForTick;\n                \n                if (generatingPDF_)\n                    yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + interiorRect.height() * ((transformedTickValue - y0_) / (y1_ - y0_)) - 0.5);   // bottom edge of pixel\n                else\n                    yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + (interiorRect.height() - 1) * ((transformedTickValue - y0_) / (y1_ - y0_)));   // bottom edge of pixel\n                \n                //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", yValueForTick == \" << yValueForTick;\n                \n                painter.fillRect(QRectF(interiorRect.x() - tickLength, yValueForTick, tickLength - (generatingPDF_ ? 0.5 : 0.0), 1), Qt::black);\n                \n                if (isMajorTick)\n                {\n                    QString labelText = labelTextForTick(tickValue, tickValuePrecision, minorTickInterval);\n                    \n                    if (yAxisLog_)\n                    {\n                        if (std::abs(tickValue - 0.0) < 0.0000001)          labelText = \"1\";\n                        else if (std::abs(tickValue - 1.0) < 0.0000001)     labelText = \"10\";\n                        else if (std::abs(tickValue - 2.0) < 0.0000001)     labelText = \"100\";\n                        else                                                labelText = QString(\"10^%1\").arg((int)round(tickValue));\n                    }\n                    \n                    painter.save();\n                    painter.translate(41, interiorRect.y());\n                    painter.rotate(90);\n                    painter.scale(1.0, -1.0);\n                    drawAxisTickLabel(painter, labelText, yValueForTick - interiorRect.y(), interiorRect.height(), isFirstTick, isLastTick);\n                    painter.restore();\n                }\n            }\n        }\n        else\n        {\n            // Histogram-style ticks are centered to the left of each bar position, at the 0.5 positions on the axis\n            // So a histogram-style axis declared with min/max of 0/10 actually spans 1..10, with ticks at 0.5..9.5 labeled 1..10\n            double axisStart = axisMin + 1;\n            \n            for (tickValue = axisStart; tickValue <= axisMax; tickValue++)\n            {\n                bool isFirstTick = (tickValue == axisStart);\n                bool isLastTick = (tickValue == axisMax);\n                bool isMajorTick = isFirstTick || isLastTick;\n                double tickLength = (isMajorTick ? 6 : 3);\n                double yValueForTick;\n                \n                if (generatingPDF_)\n                    yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + interiorRect.height() * ((tickValue - 0.5 - y0_) / (y1_ - y0_)) - 0.5);   // bottom edge of pixel\n                else\n                    yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + (interiorRect.height() - 1) * ((tickValue - 0.5 - y0_) / (y1_ - y0_)));   // bottom edge of pixel\n                \n                //qDebug() << \"tickValue == \" << tickValue << \", isMajorTick == \" << (isMajorTick ? \"YES\" : \"NO\") << \", yValueForTick == \" << yValueForTick;\n                \n                painter.fillRect(QRectF(interiorRect.x() - tickLength, yValueForTick, tickLength - (generatingPDF_ ? 0.5 : 0.0), 1), Qt::black);\n                \n                if (isMajorTick)\n                {\n                    QString labelText = labelTextForTick(tickValue, tickValuePrecision, 1.0);\n                    \n                    painter.save();\n                    painter.translate(41, interiorRect.y());\n                    painter.rotate(90);\n                    painter.scale(1.0, -1.0);\n                    drawAxisTickLabel(painter, labelText, yValueForTick - interiorRect.y(), interiorRect.height(), isFirstTick, isLastTick);\n                    painter.restore();\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView::drawYAxis(QPainter &painter, QRect interiorRect)\n{\n    double xAxisFudge = showXAxis_ ? 1 : (generatingPDF_ ? 0.5 : 0);\n\tQRectF axisRect(interiorRect.x() - 1, interiorRect.y() - xAxisFudge, 1, interiorRect.height() + xAxisFudge + (generatingPDF_ ? 0.5 : 0));\n    \n    painter.fillRect(axisRect, Qt::black);\n    \n    // show label, rotated\n    QFont font = QtSLiMGraphView::fontForAxisLabels();\n    QFontMetricsF fontMetrics(font);\n    double capHeight = fontMetrics.capHeight();\n    \n    painter.setFont(font);\n    painter.setBrush(Qt::black);\n    \n    QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, yAxisLabel_);\n    QPoint drawPoint(interiorRect.y() + (interiorRect.height() - labelBoundingRect.width()) / 2, 0);\n    \n    painter.save();\n    painter.translate(11 + std::ceil(capHeight / 2.0), 0.0);\n    painter.rotate(90);\n    painter.scale(1.0, -1.0);\n    \n    // draw debugging lines that are positioned where we intend the axis label to go\n    //painter.fillRect(QRectF(interiorRect.y(), 0, interiorRect.height(), 1), Qt::blue);\n    //painter.fillRect(QRectF(drawPoint.x(), -capHeight * 0.5, labelBoundingRect.width(), 1), Qt::red);\n    \n    painter.drawText(drawPoint, yAxisLabel_);\n    \n    painter.restore();\n}\n\nvoid QtSLiMGraphView::drawFullBox(QPainter &painter, QRect interiorRect)\n{\n\tQRect axisRect;\n\t\n\t// upper x axis\n\tint yAxisFudge = showYAxis_ ? 1 : 0;\n\t\n\taxisRect = QRect(interiorRect.x() - yAxisFudge, interiorRect.y() + interiorRect.height(), interiorRect.width() + yAxisFudge + 1, 1);\n\t\n    painter.fillRect(axisRect, Qt::black);\n\t\n\t// right-hand y axis\n\tint xAxisFudge = showXAxis_ ? 1 : 0;\n\t\n\taxisRect = QRect(interiorRect.x() + interiorRect.width(), interiorRect.y() - xAxisFudge, 1, interiorRect.height() + xAxisFudge + 1);\n\t\n    painter.fillRect(axisRect, Qt::black);\n}\n\nvoid QtSLiMGraphView::drawVerticalGridLines(QPainter &painter, QRect interiorRect)\n{\n    // we assume that no grid lines fall outside of the axis range\n    QColor gridColor = QtSLiMGraphView::gridLineColor();\n\tdouble axisMin = xAxisMin_;\n\tdouble axisMax = xAxisMax_;\n\tdouble minorTickInterval = xAxisMinorTickInterval_;\n\tdouble tickValue;\n\t\n\tfor (tickValue = axisMin; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval)\n\t{\n\t\tdouble xValueForTick;\n        \n        if (generatingPDF_)\n            xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + interiorRect.width() * ((tickValue - x0_) / (x1_ - x0_)) - 0.5);    // left edge of pixel\n        else\n            xValueForTick = SLIM_SCREEN_ROUND(interiorRect.x() + (interiorRect.width() - 1) * ((tickValue - x0_) / (x1_ - x0_)));    // left edge of pixel\n\t\t\n\t\tif (std::abs(xValueForTick - interiorRect.x()) < 1.25)\n\t\t\tcontinue;\n\t\tif ((std::abs(xValueForTick - (interiorRect.x() + interiorRect.width() - 1)) < 1.25) && showFullBox_)\n\t\t\tcontinue;\n\t\t\n        painter.fillRect(QRectF(xValueForTick, interiorRect.y(), 1, interiorRect.height()), gridColor);\n\t}\n}\n\nvoid QtSLiMGraphView::drawHorizontalGridLines(QPainter &painter, QRect interiorRect)\n{\n    // we assume that no grid lines fall outside of the axis range\n    QColor gridColor = QtSLiMGraphView::gridLineColor();\n\tdouble axisMin = yAxisMin_;\n\tdouble axisMax = yAxisMax_;\n\tdouble minorTickInterval = yAxisMinorTickInterval_;\n\tdouble tickValue;\n    double axisStart = (yAxisLog_ ? round(axisMin) : axisMin);  // with a log scale, we leave a little room at the bottom\n    double tickValueIncrement = (showGridLinesMajorOnly_ ? yAxisMajorTickInterval_ : minorTickInterval);\n\t\n\tfor (tickValue = axisStart; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += tickValueIncrement)\n\t{\n\t\tdouble yValueForTick;\n        \n        if (generatingPDF_)\n            yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + interiorRect.height() * ((tickValue - y0_) / (y1_ - y0_)) - 0.5);   // bottom edge of pixel\n        else\n            yValueForTick = SLIM_SCREEN_ROUND(interiorRect.y() + (interiorRect.height() - 1) * ((tickValue - y0_) / (y1_ - y0_)));   // bottom edge of pixel\n\t\t\n\t\tif (std::abs(yValueForTick - interiorRect.y()) < 1.25)\n\t\t\tcontinue;\n\t\tif ((std::abs(yValueForTick - (interiorRect.y() + interiorRect.height() - 1)) < 1.25) && showFullBox_)\n\t\t\tcontinue;\n\t\t\n        painter.fillRect(QRectF(interiorRect.x(), yValueForTick, interiorRect.width(), 1), gridColor);\n\t}\n}\n\nvoid QtSLiMGraphView::drawMessage(QPainter &painter, QString messageString, QRect p_rect)\n{\n    painter.setFont(QtSLiMGraphView::labelFontOfPointSize(16));\n    painter.setBrush(QtSLiMColorWithWhite(0.4, 1.0));\n    \n    painter.drawText(p_rect, Qt::AlignHCenter | Qt::AlignVCenter, messageString);\n}\n\nvoid QtSLiMGraphView::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    painter.fillRect(interiorRect, QtSLiMColorWithHSV(0.15, 0.15, 1.0, 1.0));\n}\n\nQtSLiMLegendSpec QtSLiMGraphView::legendKey(void)\n{\n    return QtSLiMLegendSpec();\n}\n\nint QtSLiMGraphView::lineCountForLegend(QtSLiMLegendSpec &legend)\n{\n    // check for duplicate labels, which get uniqued into a single line\n    // displayedLabels maps from label to index, but we don't use the index here; parallel with drawLegend()\n    QMap<QString, int> displayedLabels;\n    int lineCount = 0;\n    \n    for (const QtSLiMLegendEntry &legendEntry : legend)\n    {\n        if (legendEntry.entry_type == QtSLiM_LegendEntryType::kTitle)\n        {\n            // title items do not participate in the duplicate process; they always stand alone\n            lineCount++;\n        }\n        else\n        {\n            QString labelString = legendEntry.label;\n            auto existingEntry = displayedLabels.find(labelString);\n            \n            if (existingEntry == displayedLabels.end())\n            {\n                // not a duplicate\n                displayedLabels.insert(labelString, 0);\n                lineCount++;\n            }\n        }\n    }\n    \n    return lineCount;\n}\n\ndouble QtSLiMGraphView::graphicsWidthForLegend(QtSLiMLegendSpec &legend, double legendLineHeight)\n{\n    // with a specified width, use that width\n    if (legend_graphicsWidth != -1)\n        return legend_graphicsWidth;\n    \n    // otherwise, the default graphics width depends upon whether there are any duplicate\n    // entries and lines; we want to make the area a bit wider if we have points on top of lines\n    const double legendGraphicsWidth_default = legendLineHeight;\n    \n    int entryCount = static_cast<int>(legend.size());\n    int lineCount = lineCountForLegend(legend);    // remove duplicate lines from the count\n    \n    if (entryCount != lineCount)\n    {\n        for (const QtSLiMLegendEntry &legendEntry : legend)\n        {\n            if (legendEntry.entry_type == QtSLiM_LegendEntryType::kLine)\n            {\n                // duplicates entries, and some entries are lines; expand\n                return legendGraphicsWidth_default * 2.0;\n            }\n        }\n    }\n    \n    return legendGraphicsWidth_default;\n}\n\nQSizeF QtSLiMGraphView::legendSize(QPainter &painter)\n{\n    // This method must be synchronized with QtSLiMGraphView::drawLegend()\n    QtSLiMLegendSpec legend = legendKey();\n    int entryCount = static_cast<int>(legend.size());\n    \n\tif (entryCount == 0)\n\t\treturn QSize();\n    \n    const double legendLabelPointSize = ((legend_labelSize == -1) ? 10 : legend_labelSize);\n    const double legendLineHeight = ((legend_lineHeight == -1) ? legendLabelPointSize : legend_lineHeight);\n    const double legendInteriorMargin = ((legend_interiorMargin == -1) ?  5 : legend_interiorMargin);\n    const double legendGraphicsWidth = graphicsWidthForLegend(legend, legendLineHeight);\n    \n    int lineCount = lineCountForLegend(legend);    // remove duplicate lines from the count\n    QSizeF legend_size = QSize(0, legendLineHeight * lineCount + legendInteriorMargin * (lineCount - 1));\n\t\n    for (const QtSLiMLegendEntry &legendEntry : legend)\n    {\n        // we don't bother removing duplicate lines here, we just measure them twice; no harm\n        QString labelString = legendEntry.label;\n        \n        // incorporate the width of the label into the width of the legend\n        QRectF labelBoundingBox = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, labelString);\n        double labelWidth = labelBoundingBox.width();\n        \n        // items other than title entries have a graphics box and an interior margin as well\n        if (legendEntry.entry_type != QtSLiM_LegendEntryType::kTitle)\n            labelWidth += legendGraphicsWidth + legendInteriorMargin;\n        \n        labelWidth = SLIM_SCREEN_ROUND(labelWidth);\n        \n        legend_size.setWidth(std::max(legend_size.width(), labelWidth));\n    }\n    \n\treturn legend_size;\n}\n\nvoid QtSLiMGraphView::drawLegend(QPainter &painter, QRectF legendRect)\n{\n    // This method must be synchronized with QtSLiMGraphView::legendSize()\n    // drawLegendInInteriorRect() has already done the frame/fill, including margins, for us\n    QtSLiMLegendSpec legend = legendKey();\n    int entryCount = static_cast<int>(legend.size());\n    \n    if (entryCount == 0)\n        return;\n    \n    const double legendLabelPointSize = ((legend_labelSize == -1) ? 10 : legend_labelSize);\n    const double legendLineHeight = ((legend_lineHeight == -1) ? legendLabelPointSize : legend_lineHeight);\n    const double legendInteriorMargin = ((legend_interiorMargin == -1) ?  5 : legend_interiorMargin);\n    const double legendGraphicsWidth = graphicsWidthForLegend(legend, legendLineHeight);\n    \n    QFont legendFont = labelFontOfPointSize(legendLabelPointSize);\n    QFontMetricsF legendFontMetrics(legendFont);\n    double capHeight = legendFontMetrics.capHeight();\n    const double labelVerticalAdjust = (legendLineHeight - capHeight) / 2.0;\n    double swatchSize = capHeight * 1.5;\n    int lineCount = lineCountForLegend(legend);             // remove duplicate lines from the count\n    QMap<QString, int> displayedLabels;       // maps from label to index\n    \n#if 0\n    // show the legend layout, for debugging\n    for (int index = 0; index < lineCount; ++index)\n    {\n        int positionIndex = (lineCount - 1) - index;                   // top to bottom\n        QRectF entryBox(legendRect.x(), legendRect.y() + positionIndex * (legendLineHeight + legendInteriorMargin), legendRect.width(), legendLineHeight);\n        QRectF graphicsBox(entryBox);\n        QRectF labelBox(entryBox);\n        \n        graphicsBox.setWidth(legendGraphicsWidth);\n        labelBox.adjust(legendGraphicsWidth + legendInteriorMargin, 0, 0, 0);\n        \n        painter.fillRect(entryBox, Qt::white);\n        painter.fillRect(graphicsBox, QtSLiMColorWithWhite(0.85, 1.0));\n        painter.fillRect(labelBox, QtSLiMColorWithWhite(0.85, 1.0));\n        QtSLiMFrameRect(entryBox, Qt::black, painter, 1.0);\n    }\n#endif\n    \n    int nextLinePosition = lineCount - 1;      // top to bottom\n    \n    for (int index = 0; index < entryCount; ++index)\n    {\n        const QtSLiMLegendEntry &legendEntry = legend[index];\n        QString labelString = legendEntry.label;\n        \n        // check for duplicate labels, which get uniqued into a single line\n        int positionIndex;\n        bool isDuplicate = false;\n        \n        if (legendEntry.entry_type == QtSLiM_LegendEntryType::kTitle)\n        {\n            // title items do not participate in the duplicate process; they always stand alone\n            positionIndex = (nextLinePosition--);\n        }\n        else\n        {\n            auto existingEntry = displayedLabels.find(labelString);\n            \n            if (existingEntry == displayedLabels.end())\n            {\n                // not a duplicate\n                positionIndex = (nextLinePosition--);\n                displayedLabels.insert(labelString, positionIndex);\n            }\n            else\n            {\n                // duplicate; use the previously determined position\n                positionIndex = existingEntry.value();\n                isDuplicate = true;\n            }\n        }\n        \n        QRectF entryBox(legendRect.x(), legendRect.y() + positionIndex * (legendLineHeight + legendInteriorMargin), legendRect.width(), legendLineHeight);\n        QRectF graphicsBox(entryBox);\n        QRectF labelBox(entryBox);\n        \n        graphicsBox.setWidth(legendGraphicsWidth);\n        labelBox.adjust(legendGraphicsWidth + legendInteriorMargin, 0, 0, 0);\n        \n        // draw the graphics in graphicsBox\n        switch (legendEntry.entry_type)\n        {\n        case QtSLiM_LegendEntryType::kTitle:\n        {\n            // use the full entry box for title items\n            labelBox = entryBox;\n            break;\n        }\n        case QtSLiM_LegendEntryType::kSwatch:\n        {\n            QRectF swatchBox = graphicsBox;\n            \n            // make the width and height be, at most, swatchSize (a scaled factor of the capHeight)\n            {\n                double widthAdj = (swatchBox.width() > swatchSize) ? (swatchBox.width() - swatchSize) / 2 : 0;\n                double heightAdj = (swatchBox.height() > swatchSize) ? (swatchBox.height() - swatchSize) / 2 : 0;\n                swatchBox.adjust(widthAdj, heightAdj, -widthAdj, -heightAdj);\n            }\n            \n            // make sure the swatch is square, by shrinking it\n            if (swatchBox.width() != swatchBox.height())\n            {\n                double widthAdj = (swatchBox.width() > swatchBox.height()) ? (swatchBox.width() - swatchBox.height()) / 2 : 0;\n                double heightAdj = (swatchBox.height() > swatchBox.width()) ? (swatchBox.height() - swatchBox.width()) / 2 : 0;\n                swatchBox.adjust(widthAdj, heightAdj, -widthAdj, -heightAdj);\n            }\n            \n            QColor swatchColor = legendEntry.swatch_color;\n            \n            painter.fillRect(swatchBox, swatchColor);\n            QtSLiMFrameRect(swatchBox, Qt::black, painter, 1.0);\n            break;\n        }\n        case QtSLiM_LegendEntryType::kLine:\n        {\n            double lineWidth = legendEntry.line_lwd;\n            QColor lineColor = legendEntry.line_color;\n            QPainterPath linePath;\n            QPen linePen(lineColor, lineWidth);\n            double y = SLIM_SCREEN_ROUND(graphicsBox.center().y()) + 0.5;\n            \n            linePen.setCapStyle(Qt::FlatCap);\n            \n            linePath.moveTo(graphicsBox.left(), y);\n            linePath.lineTo(graphicsBox.right(), y);\n            painter.strokePath(linePath, linePen);\n            break;\n        }\n        case QtSLiM_LegendEntryType::kPoint:\n        {\n            drawPointSymbol(painter, graphicsBox.center().x(), graphicsBox.center().y(),\n                            legendEntry.point_symbol, legendEntry.point_color, legendEntry.point_border,\n                            /* alpha */ 1.0, legendEntry.point_lwd, legendEntry.point_size);\n            break;\n        }\n        default: break;\n        }\n        \n        // if the entry is not a duplicate, draw the text label\n        if (!isDuplicate)\n        {\n            double labelX = labelBox.x();\n            double labelY = labelBox.y() + labelVerticalAdjust;\n            \n            labelY = painter.transform().map(QPointF(labelX, labelY)).y();\n            \n            painter.setWorldMatrixEnabled(false);\n            painter.drawText(QPointF(labelX, labelY), labelString);\n            painter.setWorldMatrixEnabled(true);\n        }\n    }\n}\n\nvoid QtSLiMGraphView::drawLegendInInteriorRect(QPainter &painter, QRect interiorRect)\n{\n    // set the legend label font for the methods we call, which will rely on it\n    const double legendLabelPointSize = ((legend_labelSize == -1) ? 10 : legend_labelSize);\n    QFont legendFont = labelFontOfPointSize(legendLabelPointSize);\n    \n    painter.setFont(legendFont);\n    \n    // assess the size of the legend, given all configuration preferences\n    QSizeF legend_size = legendSize(painter);\n\tint legendWidth = static_cast<int>(ceil(legend_size.width()));\n\tint legendHeight = static_cast<int>(ceil(legend_size.height()));\n\t\n\tif ((legendWidth > 0) && (legendHeight > 0))\n\t{\n        // legend_entryMargin provides the margin between and around each entry, within the legend's box; +1 for the width of the legend's frame\n        const double legendExteriorMargin = ((legend_exteriorMargin == -1) ?  9 : legend_exteriorMargin) + 1;\n        \n\t\tQRect legendRect(0, 0, legendWidth + legendExteriorMargin + legendExteriorMargin, legendHeight + legendExteriorMargin + legendExteriorMargin);\n        \n        // positional inset from the edge, outside the legend's box; -1 so an inset of zero matches the \"full box\"\n        int legendInset = ((legend_inset == -1) ?  3 : legend_inset) - 1;\n        \n\t\t// position the legend in the chosen corner with the chosen inset\n        QtSLiM_LegendPosition position = legend_position_;\n        \n        if (position == QtSLiM_LegendPosition::kUnconfigured)\n            position = QtSLiM_LegendPosition::kTopRight;\n        \n        if ((position == QtSLiM_LegendPosition::kTopLeft) || (position == QtSLiM_LegendPosition::kTopRight))\n            legendRect.moveTop(interiorRect.y() + interiorRect.height() - (legendRect.height() + legendInset));\n        else if ((position == QtSLiM_LegendPosition::kBottomLeft) || (position == QtSLiM_LegendPosition::kBottomRight))\n            legendRect.moveTop(interiorRect.y() + legendInset);\n        \n        if ((position == QtSLiM_LegendPosition::kTopRight) || (position == QtSLiM_LegendPosition::kBottomRight))\n            legendRect.moveLeft(interiorRect.x() + interiorRect.width() - (legendRect.width() + legendInset));\n        else if ((position == QtSLiM_LegendPosition::kTopLeft) || (position == QtSLiM_LegendPosition::kBottomLeft))\n            legendRect.moveLeft(interiorRect.x() + legendInset);\n        \n\t\t// frame the legend and erase it with a slightly gray wash\n        painter.fillRect(legendRect, QtSLiMColorWithWhite(0.95, 1.0));\n        QtSLiMFrameRect(legendRect, QtSLiMColorWithWhite(0.3, 1.0), painter);\n        \n\t\t// inset and draw the legend content\n\t\tlegendRect.adjust(legendExteriorMargin, legendExteriorMargin, -legendExteriorMargin, -legendExteriorMargin);\n\t\tdrawLegend(painter, legendRect);\n\t}\n}\n\nvoid QtSLiMGraphView::setBorderless(bool isBorderless, double marginLeft, double marginTop, double marginRight, double marginBottom)\n{\n    // Convert to/from a borderless plot; this is used only by custom plots\n    is_borderless_ = isBorderless;\n    \n    borderless_margin_left_ = marginLeft;\n    borderless_margin_top_ = marginTop;\n    borderless_margin_right_ = marginRight;\n    borderless_margin_bottom_ = marginBottom;\n    \n    // x0/y0/x1/y1 do not change, but changing our borderless value reconfigures the axis ranges; unless they have been\n    // explicitly set by the user in the QtSLiM UI, they get re-evaluated based upon the original axis range\n    if (!xAxisIsUIRescaled_)\n    {\n\t\t// we generally try to maintain original_x0_ and original_x1_ in sync with x0_ and x1_, but this is the\n\t\t// only place where original_x0_ and original_x1_ actually matter outside of where they are locally set\n\t\t// up -- the only place where we re-set x0_ and x1_ back to their original values, because we want to\n\t\t// re-generate a new axis range based upon a changed is_borderless_ value\n        x0_ = original_x0_;\n        x1_ = original_x1_;\n        \n        //std::cout << \"is_borderless_ == \" << (is_borderless_ ? \"T\" : \"F\") << std::endl;\n        //std::cout << \"   BEFORE: x0_ == \" << x0_ << \", x1_ == \" << x1_ << \", xAxisMin_ == \" << xAxisMin_ << \", xAxisMax_ == \" << xAxisMax_ << std::endl;\n        \n        configureAxisForRange(x0_, x1_, xAxisMin_, xAxisMax_, xAxisMajorTickInterval_, xAxisMinorTickInterval_,\n                              xAxisMajorTickModulus_, xAxisTickValuePrecision_);\n        \n        //std::cout << \"   AFTER: x0_ == \" << x0_ << \", x1_ == \" << x1_ << \", xAxisMin_ == \" << xAxisMin_ << \", xAxisMax_ == \" << xAxisMax_ << std::endl;\n    }\n    \n    if (!yAxisIsUIRescaled_)\n    {\n\t\t// we generally try to maintain original_y0_ and original_y1_ in sync with y0_ and y1_, but this is the\n\t\t// only place where original_y0_ and original_y1_ actually matter outside of where they are locally set\n\t\t// up -- the only place where we re-set y0_ and y1_ back to their original values, because we want to\n\t\t// re-generate a new axis range based upon a changed is_borderless_ value\n        y0_ = original_y0_;\n        y1_ = original_y1_;\n        \n        configureAxisForRange(y0_, y1_, yAxisMin_, yAxisMax_, yAxisMajorTickInterval_, yAxisMinorTickInterval_,\n                              yAxisMajorTickModulus_, yAxisTickValuePrecision_);\n    }\n}\n\nvoid QtSLiMGraphView::drawContents(QPainter &painter)\n{\n    // Set to a default color of black; I thought Qt did this for me, but apparently not\n    painter.setPen(Qt::black);\n    \n    // Erase background\n    QRect bounds = rect();\n    \n\tif (!generatingPDF_)\n\t\tpainter.fillRect(bounds, Qt::white);\n\t\n\t// Get our controller and test for validity, so subclasses don't have to worry about this\n    if (!controller_ || controller_->invalidSimulation())\n    {\n        drawMessage(painter, \"invalid\\nsimulation\", bounds);\n    }\n    else if (controller_->community->Tick() == 0)\n    {\n        drawMessage(painter, \"no\\ndata\", bounds);\n    }\n    else if (missingFocalDisplaySpecies())\n    {\n        // The species name no longer refers to a species in the community\n        drawMessage(painter, \"missing\\nspecies\", bounds);\n    }\n    else if (disableMessage().length() > 0)\n    {\n        drawMessage(painter, disableMessage(), bounds);\n    }\n    else\n\t{\n\t\tQRect interiorRect = interiorRectForBounds(bounds);\n        \n        // flip the coordinate system so (0, 0) is at lower left\n        // see https://stackoverflow.com/questions/4413570/use-window-viewport-to-flip-qpainter-y-axis\n        painter.save();\n        painter.translate(0, height());\n        painter.scale(1.0, -1.0);\n\t\t\n\t\twillDraw(painter, interiorRect);\n\t\t\n\t\t// Draw grid lines, if requested, and if tick marks are turned on for the corresponding axis\n\t\tif (showHorizontalGridLines_ && showYAxis_ && showYAxisTicks_)\n\t\t\tdrawHorizontalGridLines(painter, interiorRect);\n\t\t\n\t\tif (showVerticalGridLines_ && showXAxis_ && showXAxisTicks_)\n\t\t\tdrawVerticalGridLines(painter, interiorRect);\n\t\t\n\t\t// Draw the interior of the graph; this will be overridden by the subclass\n\t\t// We clip the interior drawing to the interior rect, so outliers get clipped out\n        painter.save();\n        painter.setClipRect(interiorRect, Qt::IntersectClip);\n        \n        // When drawing borderless, we have margins by which we inset interiorRect, but we clip to bounds\n        if (is_borderless_)\n            interiorRect.adjust(borderless_margin_left_, borderless_margin_bottom_, -borderless_margin_right_, -borderless_margin_top_);\n        \n\t\tdrawGraph(painter, interiorRect);\n\t\t\n        painter.restore();\n\t\t\n\t\t// If we're caching, skip all overdrawing, since it cannot be cached (it would then appear under new drawing that supplements the cache)\n\t\tif (!cachingNow_)\n\t\t{\n\t\t\t// Overdraw axes, ticks, and axis labels, if requested\n            if (!is_borderless_)\n            {\n                if (showXAxis_)\n                    drawXAxis(painter, interiorRect);\n                \n                if (showYAxis_)\n                    drawYAxis(painter, interiorRect);\n                \n                if (showFullBox_)\n                    drawFullBox(painter, interiorRect);\n                \n                if (showXAxis_ && showXAxisTicks_)\n                    drawXAxisTicks(painter, interiorRect);\n                \n                if (showYAxis_ && showYAxisTicks_)\n                    drawYAxisTicks(painter, interiorRect);\n            }\n            else\n            {\n                // when borderless, the \"full box\", if requested, frames the full bounds\n                if (showFullBox_)\n                    QtSLiMFrameRect(bounds, Qt::black, painter);\n            }\n            \n\t\t\t// Overdraw the legend\n\t\t\tif (legendVisible_)\n\t\t\t\tdrawLegendInInteriorRect(painter, interiorRect);\n\t\t}\n        \n        // unflip\n        painter.restore();\n\t}\n}\n\nvoid QtSLiMGraphView::paintEvent(QPaintEvent * /* p_paintEvent */)\n{\n\tQPainter painter(this);\n    \n    painter.setRenderHint(QPainter::Antialiasing);\n    \n    drawContents(painter);\n}\n\nvoid QtSLiMGraphView::invalidateCachedData()\n{\n    // GraphView has no cached data, but it supports the idea of it\n    // If anything ever gets added here, calls to super will need to be added in subclasses\n}\n\nvoid QtSLiMGraphView::invalidateDrawingCache(void)\n{\n    // GraphView has no drawing cache, but it supports the idea of one\n    // If anything ever gets added here, calls to super will need to be added in subclasses\n}\n\nvoid QtSLiMGraphView::graphWindowResized(void)\n{\n\tinvalidateDrawingCache();\n}\n\nvoid QtSLiMGraphView::resizeEvent(QResizeEvent *p_event)\n{\n    // this override is private; subclassers should override graphWindowResized()\n    graphWindowResized();\n    QWidget::resizeEvent(p_event);\n}\n\nvoid QtSLiMGraphView::controllerRecycled(void)\n{\n    updateSpeciesBadge();\n    \n\tinvalidateDrawingCache();\n    invalidateCachedData();\n    \n    // recycling reverts custom axis settings from axis() back to the default\n    // the design of what reverts on a recycle and what doesn't is kind of ad hoc...\n    if (xAxisAt_)\n    {\n        delete xAxisAt_;\n        xAxisAt_ = nullptr;\n    }\n    if (xAxisLabels_)\n    {\n        delete xAxisLabels_;\n        xAxisLabels_ = nullptr;\n    }\n    if (yAxisAt_)\n    {\n        delete yAxisAt_;\n        yAxisAt_ = nullptr;\n    }\n    if (yAxisLabels_)\n    {\n        delete yAxisLabels_;\n        yAxisLabels_ = nullptr;\n    }\n    xAxisLabelsType_ = 1;\n    yAxisLabelsType_ = 1;\n    \n    update();\n    \n    QPushButton *action = actionButton();\n    if (action) action->setEnabled(!controller_->invalidSimulation() && !missingFocalDisplaySpecies());\n}\n\nvoid QtSLiMGraphView::controllerTickFinished(void)\n{\n}\n\nvoid QtSLiMGraphView::updateAfterTick(void)\n{\n    updateSpeciesBadge();\n    \n    update();\n    \n    QPushButton *action = actionButton();\n    if (action) action->setEnabled(!controller_->invalidSimulation() && !missingFocalDisplaySpecies());\n}\n\nbool QtSLiMGraphView::providesStringForData(void)\n{\n    // subclassers that override stringForData() should also override this to return true\n    // this is an annoying substitute for Obj-C's respondsToSelector:\n    return false;\n}\n\nQString QtSLiMGraphView::stringForData(void)\n{\n    QString string(\"# Graph data: \");\n\t\n    string.append(graphTitle());\n    string.append(\"\\n\");\n    string.append(slimDateline());\n    string.append(\"\\n\\n\");\n    \n    appendStringForData(string);\n    \n    // Get rid of extra commas, as a service to subclasses\n    string.replace(\", \\n\", \"\\n\");\n    \n    return string;\n}\n\nvoid QtSLiMGraphView::actionButtonRunMenu(QtSLiMPushButton *p_actionButton)\n{\n    contextMenuEvent(nullptr);\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    p_actionButton->qtslimSetHighlight(false);\n}\n\nvoid QtSLiMGraphView::subclassAddItemsToMenu(QMenu & /* contextMenu */, QContextMenuEvent * /* event */)\n{\n}\n\nQString QtSLiMGraphView::disableMessage(void)\n{\n    return \"\";\n}\n\nbool QtSLiMGraphView::writeToFile(QString fileName)\n{\n    QSize graphSize = size();\n    QPdfWriter pdfwriter(fileName);\n    QPageSize pageSize = QPageSize(graphSize, QString(), QPageSize::ExactMatch);\n    QMarginsF margins(0, 0, 0, 0);\n    \n    pdfwriter.setCreator(\"SLiMgui\");\n    pdfwriter.setResolution(72);    // match the screen?\n    pdfwriter.setPageSize(pageSize);\n    pdfwriter.setPageMargins(margins);\n    \n    QPainter painter;\n    \n    if (painter.begin(&pdfwriter))\n    {\n        generatingPDF_ = true;\n        drawContents(painter);\n        generatingPDF_ = false;\n        painter.end();\n        \n        return true;\n    }\n    else\n    {\n        return false;\n    }\n}\n\nvoid QtSLiMGraphView::contextMenuEvent(QContextMenuEvent *p_event)\n{\n    if (!controller_->invalidSimulation() && !missingFocalDisplaySpecies()) // && ![[controller window] attachedSheet])\n\t{\n\t\tbool addedItems = false;\n        QMenu contextMenu(\"graph_menu\", this);\n        \n        QAction *aboutGraph = nullptr;\n        QAction *legendToggle = nullptr;\n        QAction *gridHToggle = nullptr;\n        QAction *gridVToggle = nullptr;\n        QAction *boxToggle = nullptr;\n        QAction *changeBinCount = nullptr;\n        QAction *changeHeatmapMargins = nullptr;\n        QAction *changeXAxisScale = nullptr;\n        QAction *changeYAxisScale = nullptr;\n        QAction *copyGraph = nullptr;\n        QAction *exportGraph = nullptr;\n        QAction *copyData = nullptr;\n        QAction *exportData = nullptr;\n        \n        // Show a description of the graph\n        aboutGraph = contextMenu.addAction(\"About This Graph...\");\n        contextMenu.addSeparator();\n        \n\t\t// Toggle legend visibility\n\t\tif (legendKey().size() > 0)\n\t\t{\n            legendToggle = contextMenu.addAction(legendVisible_ ? \"Hide Legend\" : \"Show Legend\");\n\t\t\taddedItems = true;\n\t\t}\n\t\t\n\t\t// Toggle horizontal grid line visibility\n\t\tif (allowHorizontalGridChange_ && showYAxis_ && showYAxisTicks_)\n\t\t{\n\t\t\tgridHToggle = contextMenu.addAction(showHorizontalGridLines_ ? \"Hide Horizontal Grid\" : \"Show Horizontal Grid\");\n\t\t\taddedItems = true;\n\t\t}\n\t\t\n\t\t// Toggle vertical grid line visibility\n\t\tif (allowVerticalGridChange_ && showXAxis_ && showXAxisTicks_)\n\t\t{\n\t\t\tgridVToggle = contextMenu.addAction(showVerticalGridLines_ ? \"Hide Vertical Grid\" : \"Show Vertical Grid\");\n\t\t\taddedItems = true;\n\t\t}\n\t\t\n\t\t// Toggle box visibility\n\t\tif (allowFullBoxChange_ && showXAxis_ && showYAxis_)\n\t\t{\n\t\t\tboxToggle = contextMenu.addAction(showFullBox_ ? \"Hide Full Box\" : \"Show Full Box\");\n\t\t\taddedItems = true;\n\t\t}\n\t\t\n\t\t// Add a separator if we had any visibility-toggle menu items above\n        if (addedItems)\n            contextMenu.addSeparator();\n\t\taddedItems = false;\n\t\t\n\t\t// Rescale axes\n        if (histogramBinCount_ && allowBinCountRescale_)\n\t\t{\n            changeBinCount = contextMenu.addAction(\"Change Bin Count...\");\n\t\t\taddedItems = true;\n\t\t}\n        if (allowHeatmapMarginsChange_)\n        {\n            changeHeatmapMargins = contextMenu.addAction(heatmapMargins_ ? \"Remove Patch Margins\" : \"Add Patch Margins\");\n            addedItems = true;\n        }\n\t\tif (showXAxis_ && showXAxisTicks_ && allowXAxisUserRescale_)\n\t\t{\n            changeXAxisScale = contextMenu.addAction(\"Change X Axis Scale...\");\n\t\t\taddedItems = true;\n\t\t}\n\t\tif (showYAxis_ && showYAxisTicks_ && allowYAxisUserRescale_)\n\t\t{\n            changeYAxisScale = contextMenu.addAction(\"Change Y Axis Scale...\");\n\t\t\taddedItems = true;\n\t\t}\n        \n\t\t// Add a separator if we had any visibility-toggle menu items above\n\t\tif (addedItems)\n            contextMenu.addSeparator();\n\t\taddedItems = false;\n\t\t(void)addedItems;\t// dead store above is deliberate\n\t\t\n\t\t// Allow a subclass to introduce menu items here, above the copy/export menu items, which belong at the bottom;\n        // we are responsible for adding a separator afterwards if needed\n\t\tint preSubclassItemCount = contextMenu.actions().count();\n\t\t\n\t\tsubclassAddItemsToMenu(contextMenu, p_event);\n\t\t\n\t\tif (preSubclassItemCount != contextMenu.actions().count())\n            contextMenu.addSeparator();\n        \n\t\t// Copy/export the graph image\n\t\t{\n            // BCH 4/21/2020: FIXME the \"as ...\" names here are temporary, until the bug below is fixed and we can copy PDF...\n            copyGraph = contextMenu.addAction(\"Copy Graph as Bitmap\");\n            exportGraph = contextMenu.addAction(\"Export Graph as PDF...\");\n\t\t}\n        \n\t\t// Copy/export the data to the clipboard\n\t\tif (providesStringForData())\n\t\t{\n            contextMenu.addSeparator();\n            copyData = contextMenu.addAction(\"Copy Data\");\n            exportData = contextMenu.addAction(\"Export Data...\");\n\t\t}\n        \n        // Run the context menu synchronously\n        QPoint menuPos = (p_event ? p_event->globalPos() : QCursor::pos());\n        QAction *action = contextMenu.exec(menuPos);\n        \n        // Act upon the chosen action; we just do it right here instead of dealing with slots\n        if (action)\n        {\n            if (action == aboutGraph)\n            {\n                QString title = graphTitle();\n                QString about = aboutString();\n                \n                QMessageBox messageBox(this);\n                messageBox.setText(title);\n                messageBox.setInformativeText(about);\n                messageBox.setIcon(QMessageBox::Information);\n                \n                // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n                // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::WindowModal seems\n                // to be safe, I can't find a way to make this message box block the UI without doing it deliberately\n                messageBox.setWindowModality(Qt::WindowModal);\n                messageBox.exec();\n            }\n            if (action == legendToggle)\n            {\n                legendVisible_ = !legendVisible_;\n                update();\n            }\n            if (action == gridHToggle)\n            {\n                showHorizontalGridLines_ = !showHorizontalGridLines_;\n                update();\n            }\n            if (action == gridVToggle)\n            {\n                showVerticalGridLines_ = !showVerticalGridLines_;\n                update();\n            }\n            if (action == boxToggle)\n            {\n                showFullBox_ = !showFullBox_;\n                update();\n            }\n            if (action == changeBinCount)\n            {\n                QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a bin count:\", QStringList(\"Bin count:\"), QStringList(QString::number(histogramBinCount_)));\n                \n                if (choices.length() == 1)\n                {\n                    int newBinCount = choices[0].toInt();\n                    \n                    if ((newBinCount > 1) && (newBinCount <= 500))\n                    {\n                        histogramBinCount_ = newBinCount;\n                        invalidateDrawingCache();\n                        invalidateCachedData();\n                        update();\n                    }\n                    else qApp->beep();\n                }\n            }\n            if (action == changeHeatmapMargins)\n            {\n                heatmapMargins_ = 1- heatmapMargins_;   // toggle\n                update();\n            }\n            if (action == changeXAxisScale)\n            {\n                QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a configuration for the axis:\",\n                                                                   QStringList{\"Minimum value:\", \"Maximum value:\", \"Interval between major ticks:\", \"Minor tick divisions per major tick interval:\", \"Tick label precision:\"},\n                                                                   QStringList{QString::number(xAxisMin_), QString::number(xAxisMax_), QString::number(xAxisMajorTickInterval_), QString::number(xAxisMajorTickModulus_),QString::number(xAxisTickValuePrecision_)});\n                \n                if (choices.length() == 5)\n                {\n                    xAxisMin_ = choices[0].toDouble();\n                    xAxisMax_ = choices[1].toDouble();\n                    xAxisMajorTickInterval_ = choices[2].toDouble();\n                    xAxisMajorTickModulus_ = std::max(choices[3].toInt(), 1);       // zero causes a crash; better would be to validate that it is an integer value, etc.\n                    xAxisTickValuePrecision_ = choices[4].toInt();\n                    xAxisMinorTickInterval_ = xAxisMajorTickInterval_ / xAxisMajorTickModulus_;\n                    xAxisIsUserRescaled_ = true;\n                    xAxisIsUIRescaled_ = true;\n                    \n                    // for now, these are the same, except in custom plots\n                    original_x0_ = xAxisMin_;\n                    original_x1_ = xAxisMax_;\n                    \n                    x0_ = original_x0_;\n                    x1_ = original_x1_;\n                    \n                    invalidateDrawingCache();\n                    update();\n                }\n            }\n            if (action == changeYAxisScale)\n            {\n                if (!yAxisLog_)\n                {\n                    QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a configuration for the axis:\",\n                                                                       QStringList{\"Minimum value:\", \"Maximum value:\", \"Interval between major ticks:\", \"Minor tick divisions per major tick interval:\", \"Tick label precision:\"},\n                                                                       QStringList{QString::number(yAxisMin_), QString::number(yAxisMax_), QString::number(yAxisMajorTickInterval_), QString::number(yAxisMajorTickModulus_),QString::number(yAxisTickValuePrecision_)});\n                    \n                    if (choices.length() == 5)\n                    {\n                        yAxisMin_ = choices[0].toDouble();\n                        yAxisMax_ = choices[1].toDouble();\n                        yAxisMajorTickInterval_ = choices[2].toDouble();\n                        yAxisMajorTickModulus_ = std::max(choices[3].toInt(), 1);       // zero causes a crash; better would be to validate that it is an integer value, etc.\n                        yAxisTickValuePrecision_ = choices[4].toInt();\n                        yAxisMinorTickInterval_ = yAxisMajorTickInterval_ / yAxisMajorTickModulus_;\n                        yAxisIsUserRescaled_ = true;\n                        yAxisIsUIRescaled_ = true;\n                        \n                        // for now, these are the same, except in custom plots\n                        original_y0_ = yAxisMin_;\n                        original_y1_ = yAxisMax_;\n                        \n                        y0_ = original_y0_;\n                        y1_ = original_y1_;\n                        \n                        invalidateDrawingCache();\n                        update();\n                    }\n                }\n                else\n                {\n                    QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a maximum log-scale power:\",\n                                                                       QStringList{\"Maximum value (10^x):\"},\n                                                                       QStringList{QString::number(yAxisMax_)});\n                    \n                    if (choices.length() == 1)\n                    {\n                        int newPower = choices[0].toInt();\n                        \n                        if ((newPower >= 1) && (newPower <= 10))\n                        {\n                            yAxisMax_ = (double)newPower;\n                            \n                            // for now, these are the same, except in custom plots\n                            original_y1_ = yAxisMax_;\n                            y1_ = original_y1_;\n                            \n                            invalidateDrawingCache();\n                            update();\n                        }\n                        else qApp->beep();\n                    }\n                }\n            }\n            if (action == copyGraph)\n            {\n#if 0\n                // FIXME this clipboard data is not usable on macOS, apparently because the MIME tag doesn't\n                // come through properly; see https://bugreports.qt.io/browse/QTBUG-83164\n                // I can't find a workaround so I'll wait for them to respond\n                QBuffer buffer;\n                \n                buffer.open(QIODevice::WriteOnly);\n                {\n                    QSize graphSize = size();\n                    QPdfWriter pdfwriter(&buffer);\n                    QPageSize pageSize = QPageSize(graphSize, QString(), QPageSize::ExactMatch);\n                    QMarginsF margins(0, 0, 0, 0);\n                    \n                    pdfwriter.setCreator(\"SLiMgui\");\n                    pdfwriter.setResolution(72);    // match the screen?\n                    pdfwriter.setPageSize(pageSize);\n                    pdfwriter.setPageMargins(margins);\n                    \n                    QPainter painter(&pdfwriter);\n                    generatingPDF_ = true;\n                    drawContents(painter);\n                    generatingPDF_ = false;\n                }\n                buffer.close();\n                \n                QClipboard *clipboard = QGuiApplication::clipboard();\n                QMimeData mimeData;\n                mimeData.setData(\"application/pdf\", buffer.data());\n                clipboard->setMimeData(&mimeData);\n#else\n                // Until the above bug gets fixed, we'll copy raster data to the clipboard instead\n                QPixmap pixmap(size());\n                render(&pixmap);\n                QImage image = pixmap.toImage();\n                QClipboard *clipboard = QGuiApplication::clipboard();\n                clipboard->setImage(image);\n#endif\n            }\n            if (action == exportGraph)\n            {\n                // FIXME maybe this should use QtSLiMDefaultSaveDirectory?  see QtSLiMWindow::saveAs()\n                QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);\n                QFileInfo fileInfo(QDir(desktopPath), \"graph.pdf\");\n                QString path = fileInfo.absoluteFilePath();\n                QString fileName = QFileDialog::getSaveFileName(this, \"Export Graph\", path);\n                \n                if (!fileName.isEmpty())\n                {\n                    bool success = writeToFile(fileName);\n                    \n                    if (!success)\n                        qApp->beep();\n                }\n            }\n            if (action == copyData)\n            {\n                QClipboard *clipboard = QGuiApplication::clipboard();\n                clipboard->setText(stringForData());\n            }\n            if (action == exportData)\n            {\n                // FIXME maybe this should use QtSLiMDefaultSaveDirectory?  see QtSLiMWindow::saveAs()\n                QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);\n                QFileInfo fileInfo(QDir(desktopPath), \"data.txt\");\n                QString path = fileInfo.absoluteFilePath();\n                QString fileName = QFileDialog::getSaveFileName(this, \"Export Data\", path);\n                \n                if (!fileName.isEmpty())\n                {\n                    QFile file(fileName);\n                    \n                    if (file.open(QFile::WriteOnly | QFile::Text))\n                        file.write(stringForData().toUtf8());\n                    else\n                        qApp->beep();\n                }\n            }\n        }\n\t}\n}\n\nvoid QtSLiMGraphView::setXAxisRangeFromTick(void)\n{\n    Community *community = controller_->community;\n    \n    // We can't get the estimated last tick until tick ranges are known\n    if (!community || (community->Tick() < 1))\n        return;\n    \n    slim_tick_t lastTick = community->EstimatedLastTick();\n    \n    // The last tick could be just about anything, so we need some smart axis setup code here – a problem we neglect elsewhere\n\t// since we use hard-coded axis setups in other places.  The goal is to (1) have the axis max be >= lastTick, (2) have the axis\n\t// max be == lastTick if lastTick is a reasonably round number (a single-digit multiple of a power of 10, say), (3) have just a few\n\t// other major tick intervals drawn, so labels don't collide or look crowded, and (4) have a few minor tick intervals in between\n\t// the majors.  Labels that are single-digit multiples of powers of 10 are to be strongly preferred.\n\tdouble lower10power = pow(10.0, floor(log10(lastTick)));    // 8000 gives 1000, 1000 gives 1000, 10000 gives 10000\n\tdouble lower5mult = lower10power / 2.0;\t\t\t\t\t\t// 8000 gives 500, 1000 gives 500, 10000 gives 5000\n\tdouble axisMax = ceil(lastTick / lower5mult) * lower5mult;\t// 8000 gives 8000, 7500 gives 7500, 1100 gives 1500\n\tdouble contained5mults = axisMax / lower5mult;\t\t\t\t// 8000 gives 16, 7500 gives 15, 1100 gives 3, 1000 gives 2\n\t\n\tif (contained5mults <= 3)\n\t{\n\t\t// We have a max like 1500 that divides into 5mults well, so do that\n\t\txAxisMax_ = axisMax;\n\t\txAxisMajorTickInterval_ = lower5mult;\n\t\txAxisMinorTickInterval_ = lower5mult / 5;\n\t\txAxisMajorTickModulus_ = 5;\n\t\txAxisTickValuePrecision_ = 0;\n        \n        // for now, these are the same, except in custom plots\n        original_x1_ = xAxisMax_;\n        x1_ = original_x1_;\n\t}\n\telse\n\t{\n\t\t// We have a max like 7000 that does not divide into 5mults well; for simplicity, we just always divide these in two\n\t\txAxisMax_ = axisMax;\n\t\txAxisMajorTickInterval_ = axisMax / 2;\n\t\txAxisMinorTickInterval_ = axisMax / 4;\n\t\txAxisMajorTickModulus_ = 2;\n\t\txAxisTickValuePrecision_ = 0;\n        \n        // for now, these are the same, except in custom plots\n        original_x1_ = xAxisMax_;\n        x1_ = original_x1_;\n\t}\n}\n\nvoid QtSLiMGraphView::configureAxisForRange(double &dim0, double &dim1, double &axisMin, double &axisMax,\n                                            double &majorTickInterval, double &minorTickInterval,\n                                            int &majorTickModulus, int &tickValuePrecision)\n{\n    if (is_borderless_)\n    {\n        // For borderless plots, we leave the axis range untouched; the axis range does not get outset.\n        // However, drawContents() will inset the interiorRect by the margins given to setBorderless();\n        // that provides a similar way of framing the data with margins around them.\n        axisMin = dim0;\n        axisMax = dim1;\n    }\n    else\n    {\n        // We call down to our R-inspired axis calculation methods to figure out a good axis layout.\n        // The call here, to _GScale(), is parallel to the point in R's plot.window() function where\n        // it calls down to GScale() for each of the two axes.  Note that this branch modifies dim0\n        // and dim1; we keep the \"original_\" versions of the axis ranges so that we can back that out\n        // in setBorderless().\n        int nDivisions;\n        \n        //qDebug() << \"configureAxisForRange() : original dim0 ==\" << dim0 << \", dim1 ==\" << dim1;\n        \n        _GScale(dim0, dim1, axisMin, axisMax, nDivisions);\n        \n        //qDebug() << \"    after axisGScale() : dim0 ==\" << dim0 << \", dim1 ==\" << dim1;\n        //qDebug() << \"    after axisGScale() : axisMin ==\" << axisMin << \", axisMax ==\" << axisMax << \", nDivisions ==\" << nDivisions;\n        \n        // We go beyond R a little, designating some ticks as \"major\" (getting a label, and a longer tick\n        // mark) and others \"minor\" (just a short tick mark with no label).  We do that after the R-based\n        // tick calculations are done, just assigned roles based on the number of divisions; this could\n        // probably be improved.  It's a good idea primarily because we tend to display plots at a much\n        // smaller default size than R, and so there just isn't room for every tick mark to get a label.\n        switch (nDivisions)\n        {\n        case 2:\n        case 4:\n        case 6:\n        case 8:\n        case 10:\n            majorTickInterval = (axisMax - axisMin) / 2.0;\n            minorTickInterval = (axisMax - axisMin) / nDivisions;\n            majorTickModulus = nDivisions / 2;\n            break;\n        case 3:\n        case 9:\n            majorTickInterval = (axisMax - axisMin) / 3.0;\n            minorTickInterval = (axisMax - axisMin) / nDivisions;\n            majorTickModulus = nDivisions / 3;\n            break;\n        default:\n            majorTickInterval = axisMax - axisMin;\n            minorTickInterval = majorTickInterval;\n            majorTickModulus = 1;\n            break;\n        }\n        \n        //qDebug() << \"    majorTickInterval ==\" << majorTickInterval << \", minorTickInterval ==\" << minorTickInterval << \", majorTickModulus ==\" << majorTickModulus;\n        \n        // We now use a negative tick precision to ask the tick-plotting code to use output mode 'g'\n        // instead of 'f', with the tick precision meaning the number of significant digits, not\n        // the number of digits after the decimal point.  This is used only by this method; old-\n        // style QtSLiM plots still use mode 'f'.  The precision value chosen here is arbitrary,\n        // but note that trailing zeros are removed by mode 'g', so this precision will only be\n        // used if it is needed; and mode 'g' also switches to scientific notation if it is more\n        // concise.\n        tickValuePrecision = -8;\n        \n        //qDebug() << \"    tickValuePrecision ==\" << tickValuePrecision;\n    }\n}\n\nQtSLiMLegendSpec QtSLiMGraphView::subpopulationLegendKey(std::vector<slim_objectid_t> &subpopsToDisplay, bool drawSubpopsGray)\n{\n    QtSLiMLegendSpec legend_key;\n    \n    // put \"All\" first, if it occurs in subpopsToDisplay\n    if (std::find(subpopsToDisplay.begin(), subpopsToDisplay.end(), -1) != subpopsToDisplay.end())\n        legend_key.emplace_back(\"All\", Qt::black);\n\n    if (drawSubpopsGray)\n    {\n        legend_key.emplace_back(\"pX\", QtSLiMColorWithWhite(0.5, 1.0));\n    }\n    else\n    {\n        for (auto subpop_id : subpopsToDisplay)\n        {\n            if (subpop_id != -1)\n            {\n                QString labelString = QString(\"p%1\").arg(subpop_id);\n\n                legend_key.emplace_back(labelString, controller_->whiteContrastingColorForIndex(subpop_id));\n            }\n        }\n    }\n\n    return legend_key;\n}\n\nQtSLiMLegendSpec QtSLiMGraphView::mutationTypeLegendKey(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!graphSpecies)\n        return QtSLiMLegendSpec();\n    \n    int mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n    \n    // if we only have one mutation type, do not show a legend\n    if (mutationTypeCount < 2)\n        return QtSLiMLegendSpec();\n    \n    QtSLiMLegendSpec legend_key;\n    \n    // first we put in placeholders, of swatch type\n    std::map<slim_objectid_t,MutationType*> &mutTypes = graphSpecies->mutation_types_;\n    \n    for (size_t index = 0; index < mutTypes.size(); ++index)\n        legend_key.emplace_back(\"placeholder\", QColor());\n    \n    // then we replace the placeholders with lines, but we do it out of order, according to mutation_type_index_ values\n    for (auto mutationTypeIter : mutTypes)\n    {\n        MutationType *mutationType = mutationTypeIter.second;\n        int mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n        QString labelString = QString(\"m%1\").arg(mutationType->mutation_type_id_);\n        QtSLiMLegendEntry &entry = legend_key[static_cast<size_t>(mutationTypeIndex)];\n        \n        entry.label = labelString;\n        entry.swatch_color = controller_->blackContrastingColorForIndex(mutationTypeIndex);\n    }\n    \n    return legend_key;\n}\n\nvoid QtSLiMGraphView::drawPointSymbol(QPainter &painter, double x, double y, int symbol, QColor symbolColor, QColor borderColor, double alpha, double lineWidth, double size)\n{\n    size = size * 3.5;       // this scales what size=1 looks like\n    \n    if (alpha != 1.0)\n    {\n        symbolColor.setAlphaF(alpha);\n        borderColor.setAlphaF(alpha);\n    }\n    \n    switch (symbol)\n    {\n    case 0:     // square outline\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addRect(x - size, y - size, size * 2, size * 2);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 1:     // circle outline\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addEllipse(x - size * 1.13, y - size * 1.13, size * 2 * 1.13, size * 2 * 1.13);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 2:     // triangle outline pointing up\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x, y + size * 1.4);\n        symbolStrokePath.lineTo(x + 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolStrokePath.lineTo(x - 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolStrokePath.closeSubpath();\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 3:     // orthogonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x, y + size);\n        symbolStrokePath.lineTo(x, y - size);\n        symbolStrokePath.moveTo(x + size, y);\n        symbolStrokePath.lineTo(x - size, y);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 4:     // diagonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x + size * 0.7071, y + size * 0.7071);\n        symbolStrokePath.lineTo(x - size * 0.7071, y - size * 0.7071);\n        symbolStrokePath.moveTo(x + size * 0.7071, y - size * 0.7071);\n        symbolStrokePath.lineTo(x - size * 0.7071, y + size * 0.7071);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 5:     // diamond outline\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x + size * 1.3, y);\n        symbolStrokePath.lineTo(x, y - size * 1.3);\n        symbolStrokePath.lineTo(x - size * 1.3, y);\n        symbolStrokePath.lineTo(x, y + size * 1.3);\n        symbolStrokePath.closeSubpath();\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 6:     // triangle outline pointing down\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x, y - size * 1.4);\n        symbolStrokePath.lineTo(x + 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolStrokePath.lineTo(x - 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolStrokePath.closeSubpath();\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 7:     // square outline with diagonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addRect(x - size, y - size, size * 2, size * 2);\n        symbolStrokePath.moveTo(x + size * 0.93, y + size * 0.93);\n        symbolStrokePath.lineTo(x - size * 0.93, y - size * 0.93);\n        symbolStrokePath.moveTo(x + size * 0.93, y - size * 0.93);\n        symbolStrokePath.lineTo(x - size * 0.93, y + size * 0.93);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 8:     // 8-pointed asterisk\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x, y + size);\n        symbolStrokePath.lineTo(x, y - size);\n        symbolStrokePath.moveTo(x + size, y);\n        symbolStrokePath.lineTo(x - size, y);\n        symbolStrokePath.moveTo(x + size * 0.7071, y + size * 0.7071);\n        symbolStrokePath.lineTo(x - size * 0.7071, y - size * 0.7071);\n        symbolStrokePath.moveTo(x + size * 0.7071, y - size * 0.7071);\n        symbolStrokePath.lineTo(x - size * 0.7071, y + size * 0.7071);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 9:     // diamond with orthogonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x + size * 1.3, y);\n        symbolStrokePath.lineTo(x, y - size * 1.3);\n        symbolStrokePath.lineTo(x - size * 1.3, y);\n        symbolStrokePath.lineTo(x, y + size * 1.3);\n        symbolStrokePath.closeSubpath();\n        symbolStrokePath.moveTo(x, y + size * 1.2);\n        symbolStrokePath.lineTo(x, y - size * 1.2);\n        symbolStrokePath.moveTo(x + size * 1.2, y);\n        symbolStrokePath.lineTo(x - size * 1.2, y);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 10:     // circle outline with orthogonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addEllipse(x - size * 1.13, y - size * 1.13, size * 2 * 1.13, size * 2 * 1.13);\n        symbolStrokePath.moveTo(x, y + size * 1.05);\n        symbolStrokePath.lineTo(x, y - size * 1.05);\n        symbolStrokePath.moveTo(x + size * 1.05, y);\n        symbolStrokePath.lineTo(x - size * 1.05, y);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 11:     // six-pointed star outline (overlapping triangles)\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.moveTo(x, y + size * 1.4);\n        symbolStrokePath.lineTo(x + 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolStrokePath.lineTo(x - 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolStrokePath.closeSubpath();\n        symbolStrokePath.moveTo(x, y - size * 1.4);\n        symbolStrokePath.lineTo(x + 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolStrokePath.lineTo(x - 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolStrokePath.closeSubpath();\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 12:     // square outline with orthogonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addRect(x - size, y - size, size * 2, size * 2);\n        symbolStrokePath.moveTo(x, y + size * 0.9);\n        symbolStrokePath.lineTo(x, y - size * 0.9);\n        symbolStrokePath.moveTo(x + size * 0.9, y);\n        symbolStrokePath.lineTo(x - size * 0.9, y);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 13:     // circle outline with diagonal cross\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addEllipse(x - size * 1.13, y - size * 1.13, size * 2 * 1.13, size * 2 * 1.13);\n        symbolStrokePath.moveTo(x + size * 0.75, y + size * 0.75);\n        symbolStrokePath.lineTo(x - size * 0.75, y - size * 0.75);\n        symbolStrokePath.moveTo(x + size * 0.75, y - size * 0.75);\n        symbolStrokePath.lineTo(x - size * 0.75, y + size * 0.75);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 14:     // square with embedded triangle\n    {\n        QPainterPath symbolStrokePath;\n        symbolStrokePath.addRect(x - size, y - size, size * 2, size * 2);\n        symbolStrokePath.moveTo(x - size, y - size);\n        symbolStrokePath.lineTo(x, y + size);\n        symbolStrokePath.lineTo(x + size, y - size);\n        painter.strokePath(symbolStrokePath, QPen(symbolColor, lineWidth));\n        break;\n    }\n    case 15:     // square filled\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.addRect(x - size, y - size, size * 2, size * 2);\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 16:     // circle filled\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.addEllipse(x - size * 1.13, y - size * 1.13, size * 2 * 1.13, size * 2 * 1.13);\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 17:     // triangle filled pointing up\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x, y + size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 18:     // diamond filled\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x + size * 1.3, y);\n        symbolFillPath.lineTo(x, y - size * 1.3);\n        symbolFillPath.lineTo(x - size * 1.3, y);\n        symbolFillPath.lineTo(x, y + size * 1.3);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 19:     // triangle filled pointing down\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x, y - size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 20:     // six-pointed star filled (overlapping triangles)\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x, y + size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        symbolFillPath.moveTo(x, y - size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        symbolFillPath.setFillRule(Qt::WindingFill);\n        painter.fillPath(symbolFillPath, symbolColor);\n        break;\n    }\n    case 21:     // circle filled and stroked\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.addEllipse(x - size * 1.13, y - size * 1.13, size * 2 * 1.13, size * 2 * 1.13);\n        painter.fillPath(symbolFillPath, symbolColor);\n        painter.strokePath(symbolFillPath, QPen(borderColor, lineWidth));\n        break;\n    }\n    case 22:     // square filled and stroked\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.addRect(x - size, y - size, size * 2, size * 2);\n        painter.fillPath(symbolFillPath, symbolColor);\n        painter.strokePath(symbolFillPath, QPen(borderColor, lineWidth));\n        break;\n    }\n    case 23:     // diamond filled and stroked\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x + size * 1.3, y);\n        symbolFillPath.lineTo(x, y - size * 1.3);\n        symbolFillPath.lineTo(x - size * 1.3, y);\n        symbolFillPath.lineTo(x, y + size * 1.3);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        painter.strokePath(symbolFillPath, QPen(borderColor, lineWidth));\n        break;\n    }\n    case 24:     // triangle filled and stroked pointing up\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x, y + size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y - 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        painter.strokePath(symbolFillPath, QPen(borderColor, lineWidth));\n        break;\n    }\n    case 25:     // triangle filled and stroked pointing down\n    {\n        QPainterPath symbolFillPath;\n        symbolFillPath.moveTo(x, y - size * 1.4);\n        symbolFillPath.lineTo(x + 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.lineTo(x - 0.8660 * size * 1.4, y + 0.5 * size * 1.4);\n        symbolFillPath.closeSubpath();\n        painter.fillPath(symbolFillPath, symbolColor);\n        painter.strokePath(symbolFillPath, QPen(borderColor, lineWidth));\n        break;\n    }\n    default:        // other symbols draw nothing\n        break;\n    }\n}\n\nvoid QtSLiMGraphView::drawGroupedBarplot(QPainter &painter, QRect interiorRect, double *buffer, int subBinCount, int mainBinCount, double firstBinValue, double mainBinWidth)\n{\n    // Decide on a display style; if we have lots of width, then we draw bars with a fill color, spaced out nicely,\n\t// but if we are cramped for space then we draw solid black bars.  Note the latter style does not really\n\t// work with sub-bins; not much we can do about that, since we don't have the room to draw...\n\tint interiorWidth = interiorRect.width();\n\tint totalBarCount = subBinCount * mainBinCount;\n\tint drawStyle = 0;\n\t\n\tif (totalBarCount * 7 + 1 <= interiorWidth)\t\t\t\t// room for space, space, space, frame, fill, fill, frame...\n\t\tdrawStyle = 0;\n\telse if (totalBarCount * 5 + 1 <= interiorWidth)\t\t// room for space, frame, fill, fill, frame...\n\t\tdrawStyle = 1;\n\telse if (totalBarCount * 2 + 1 <= interiorWidth)\t\t// room for frame, fill, [frame]...\n\t\tdrawStyle = 2;\n\telse\n\t\tdrawStyle = 3;\n\t\n    if (generatingPDF_ && (drawStyle == 3))\n        drawStyle = 2;\n    \n    for (int mainBinIndex = 0; mainBinIndex < mainBinCount; ++mainBinIndex)\n    {\n\t\tdouble binMinValue = mainBinIndex * mainBinWidth + firstBinValue;\n\t\tdouble binMaxValue = (mainBinIndex + 1) * mainBinWidth + firstBinValue;\n\t\tdouble barLeft = roundPlotToDeviceX(binMinValue, interiorRect);\n\t\tdouble barRight = roundPlotToDeviceX(binMaxValue, interiorRect);\n        double lineWidth = generatingPDF_ ? 0.3 : 1.0;\n        double halfLineWidth = lineWidth / 2.0;\n\t\t\n\t\tswitch (drawStyle)\n\t\t{\n\t\t\tcase 0: barLeft += (1.0 + halfLineWidth); barRight -= (1.0 + halfLineWidth); break;\n\t\t\tcase 1: barLeft += halfLineWidth; barRight -= halfLineWidth; break;\n\t\t\tcase 2: barLeft -= halfLineWidth; barRight += halfLineWidth; break;\n\t\t\tcase 3: barLeft -= halfLineWidth; barRight += halfLineWidth; break;\n\t\t}\n\t\t\n\t\tfor (int subBinIndex = 0; subBinIndex < subBinCount; ++subBinIndex)\n\t\t{\n\t\t\tint actualBinIndex = subBinIndex + mainBinIndex * subBinCount;\n\t\t\tdouble binValue = buffer[actualBinIndex];\n\t\t\tdouble barBottom = interiorRect.y() - (generatingPDF_ ? 0.5 : 1.0);\n\t\t\tdouble barTop;\n\t\t\tQRectF barRect;\n            \n            if (fabs(binValue - 0) < 0.00000001)\n                continue;\n            \n            if (generatingPDF_)\n            {\n                barTop =  plotToDeviceY(binValue, interiorRect);\n                barRect = QRectF(barLeft, barBottom, barRight - barLeft, barTop - barBottom);\n            }\n            else\n            {\n                barTop = roundPlotToDeviceY(binValue, interiorRect) + 0.5;\n                barRect = QRectF(qRound(barLeft), qRound(barBottom), qRound(barRight - barLeft), qRound(barTop - barBottom));\n\t\t\t}\n            \n\t\t\tif (barRect.height() > 0.0)\n\t\t\t{\n\t\t\t\t// subdivide into sub-bars for each mutation type, if there is more than one\n\t\t\t\tif (subBinCount > 1)\n\t\t\t\t{\n\t\t\t\t\tdouble barWidth = barRect.width();\n\t\t\t\t\tdouble subBarWidth = (barWidth - lineWidth) / subBinCount;\n\t\t\t\t\tdouble subbarLeft = SLIM_SCREEN_ROUND(barRect.x() + subBinIndex * subBarWidth);\n\t\t\t\t\tdouble subbarRight = SLIM_SCREEN_ROUND(barRect.x() + (subBinIndex + 1) * subBarWidth) + lineWidth;\n\t\t\t\t\t\n                    if (generatingPDF_)\n                    {\n                        barRect.setX(subbarLeft);\n                        barRect.setWidth(subbarRight - subbarLeft);\n                    }\n                    else\n                    {\n                        barRect.setX(qRound(subbarLeft));\n                        barRect.setWidth(qRound(subbarRight - subbarLeft));\n                    }\n\t\t\t\t}\n                \n\t\t\t\t// fill and frame\n\t\t\t\tif (drawStyle == 3)\n\t\t\t\t{\n                    painter.fillRect(barRect, Qt::black);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n                    painter.fillRect(barRect, controller_->blackContrastingColorForIndex(subBinIndex));\n                    QtSLiMFrameRect(barRect, Qt::black, painter, lineWidth);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid QtSLiMGraphView::drawBarplot(QPainter &painter, QRect interiorRect, double *buffer, int binCount, double firstBinValue, double binWidth)\n{\n\tdrawGroupedBarplot(painter, interiorRect, buffer, 1, binCount, firstBinValue, binWidth);\n}\n\nvoid QtSLiMGraphView::drawHeatmap(QPainter &painter, QRect interiorRect, double *buffer, int xBinCount, int yBinCount)\n{\n    int intHeatMapMargins = (generatingPDF_ ? 0 : heatmapMargins_);     // when generating a PDF we use an inset for accuracy\n    double patchWidth = (interiorRect.width() - intHeatMapMargins) / (double)xBinCount;\n    double patchHeight = (interiorRect.height() - intHeatMapMargins) / (double)yBinCount;\n    \n    for (int xc = 0; xc < xBinCount; ++xc)\n    {\n        for (int yc = 0; yc < yBinCount; ++yc)\n        {\n            double value = buffer[xc + yc * xBinCount];\n            double patchX1 = SLIM_SCREEN_ROUND(interiorRect.left() + patchWidth * xc) + intHeatMapMargins;\n            double patchX2 = SLIM_SCREEN_ROUND(interiorRect.left() + patchWidth * (xc + 1));\n            double patchY1 = SLIM_SCREEN_ROUND(interiorRect.top() + patchHeight * yc) + intHeatMapMargins;\n            double patchY2 = SLIM_SCREEN_ROUND(interiorRect.top() + patchHeight * (yc + 1));\n            QRectF patchRect(patchX1, patchY1, patchX2 - patchX1, patchY2 - patchY1);\n            \n            if (generatingPDF_)\n                patchRect.adjust(0.5 * heatmapMargins_, 0.5 * heatmapMargins_, -0.5 * heatmapMargins_, -0.5 * heatmapMargins_);\n            \n            double r, g, b;\n            \n            if (value == -10000)\n            {\n                r = 0.25; g = 0.25; b = 1.0;  // a special \"no value\" color for the 2D SFS plot\n            }\n            else\n                Eidos_ColorPaletteLookup(1.0 - value, EidosColorPalette::kPalette_hot, r, g, b);\n            \n            painter.fillRect(patchRect, QtSLiMColorWithRGB(r, g, b, 1.0));\n        }\n    }\n}\n\nbool QtSLiMGraphView::addSubpopulationsToMenu(QComboBox *subpopButton, slim_objectid_t selectedSubpopID, slim_objectid_t avoidSubpopID)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tslim_objectid_t firstTag = -1;\n    \n    // QComboBox::currentIndexChanged signals will be sent during rebuilding; this flag\n    // allows client code to avoid (over-)reacting to those signals.\n    rebuildingMenu_ = true;\n\t\n\t// Depopulate and populate the menu\n\tsubpopButton->clear();\n\n\tif (graphSpecies)\n\t{\n\t\tPopulation &population = graphSpecies->population_;\n\t\t\n\t\tfor (auto popIter : population.subpops_)\n\t\t{\n\t\t\tslim_objectid_t subpopID = popIter.first;\n\t\t\tQString subpopString = QString(\"p%1\").arg(subpopID);\n\t\t\t\n\t\t\tsubpopButton->addItem(subpopString, subpopID);\n\t\t\t\n\t\t\t// Remember the first item we add; we will use this item's tag to make a selection if needed\n            // If we have a tag to avoid, avoid it, preferring the second item if necessary\n\t\t\tif (firstTag == -1)\n\t\t\t\tfirstTag = subpopID;\n            if (firstTag == avoidSubpopID)\n                firstTag = subpopID;\n\t\t}\n\t}\n\t\n\t//[subpopulationButton slimSortMenuItemsByTag];\n\t\n\t// If it is empty, disable it\n\tbool hasItems = (subpopButton->count() >= 1);\n\t\n    subpopButton->setEnabled(hasItems);\n\t\n    // Done rebuilding the menu, resume change messages\n    rebuildingMenu_ = false;\n    \n\t// Fix the selection and then select the chosen subpopulation\n\tif (hasItems)\n\t{\n\t\tint indexOfTag = subpopButton->findData(selectedSubpopID);\n\t\t\n\t\tif (indexOfTag == -1)\n            selectedSubpopID = -1;\n\t\tif (selectedSubpopID == -1)\n            selectedSubpopID = firstTag;\n        if (selectedSubpopID == avoidSubpopID)\n            selectedSubpopID = firstTag;\n\t\t\n        subpopButton->setCurrentIndex(subpopButton->findData(selectedSubpopID));\n        \n        // this signal, emitted after rebuildingMenu_ is set to false, is the one that sticks\n        emit subpopButton->QComboBox::currentIndexChanged(subpopButton->currentIndex());\n\t}\n\t\n\treturn hasItems;\t// true if we found at least one subpop to add to the menu, false otherwise\n}\n\nbool QtSLiMGraphView::addMutationTypesToMenu(QComboBox *mutTypeButton, int selectedMutIDIndex)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tint firstTag = -1;\n\t\n    // QComboBox::currentIndexChanged signals will be sent during rebuilding; this flag\n    // allows client code to avoid (over-)reacting to those signals.\n    rebuildingMenu_ = true;\n\t\n\t// Depopulate and populate the menu\n\tmutTypeButton->clear();\n\t\n\tif (graphSpecies)\n\t{\n\t\tstd::map<slim_objectid_t,MutationType*> &mutationTypes = graphSpecies->mutation_types_;\n\t\t\n\t\tfor (auto mutTypeIter : mutationTypes)\n\t\t{\n\t\t\tMutationType *mutationType = mutTypeIter.second;\n\t\t\tslim_objectid_t mutationTypeID = mutationType->mutation_type_id_;\n\t\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\n\t\t\tQString mutationTypeString = QString(\"m%1\").arg(mutationTypeID);\n\t\t\t\n\t\t\tmutTypeButton->addItem(mutationTypeString, mutationTypeIndex);\n\t\t\t\n\t\t\t// Remember the first item we add; we will use this item's tag to make a selection if needed\n\t\t\tif (firstTag == -1)\n\t\t\t\tfirstTag = mutationTypeIndex;\n\t\t}\n\t}\n\t\n\t//[mutationTypeButton slimSortMenuItemsByTag];\n\t\n\t// If it is empty, disable it\n\tbool hasItems = (mutTypeButton->count() >= 1);\n\t\n\tmutTypeButton->setEnabled(hasItems);\n\t\n    // Done rebuilding the menu, resume change messages\n    rebuildingMenu_ = false;\n    \n\t// Fix the selection and then select the chosen mutation type\n\tif (hasItems)\n\t{\n\t\tint indexOfTag = mutTypeButton->findData(selectedMutIDIndex);\n\t\t\n\t\tif (indexOfTag == -1)\n            selectedMutIDIndex = -1;\n\t\tif (selectedMutIDIndex == -1)\n            selectedMutIDIndex = firstTag;\n\t\t\n\t\tmutTypeButton->setCurrentIndex(mutTypeButton->findData(selectedMutIDIndex));\n        \n        // this signal, emitted after rebuildingMenu_ is set to false, is the one that sticks\n        emit mutTypeButton->QComboBox::currentIndexChanged(mutTypeButton->currentIndex());\n\t}\n\t\n\treturn hasItems;\t// true if we found at least one muttype to add to the menu, false otherwise\n}\n\nsize_t QtSLiMGraphView::tallyGUIMutationReferences(slim_objectid_t subpop_id, int muttype_index)\n{\n    //\n\t// this code is a slightly modified clone of the code in Population::TallyMutationReferences; here we scan only the\n\t// subpopulation that is being displayed in this graph, and tally into gui_scratch_reference_count only\n\t// BCH 4/21/2023: This could use mutrun use counts to run faster...\n\t//\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!graphSpecies)\n        return 0;\n    \n    Population &population = graphSpecies->population_;\n    size_t subpop_total_haplosome_count = 0;\n    \n    Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n    \n    {\n        int registry_size;\n        const MutationIndex *registry = population.MutationRegistry(&registry_size);\n        const MutationIndex *registry_iter_end = registry + registry_size;\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n            (mut_block_ptr + *registry_iter)->gui_scratch_reference_count_ = 0;\n    }\n    \n    Subpopulation *subpop = graphSpecies->SubpopulationWithID(subpop_id);\n    \n    if (subpop)\t// tally only within our chosen subpop\n    {\n        int haplosome_count_per_individual = subpop->HaplosomeCountPerIndividual();\n        \n        for (Individual *ind : subpop->parent_individuals_)\n        {\n            Haplosome **haplosomes = ind->haplosomes_;\n            \n            for (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n            {\n                Haplosome *haplosome = haplosomes[haplosome_index];\n                \n                if (!haplosome->IsNull())\n                {\n                    int mutrun_count = haplosome->mutrun_count_;\n                    \n                    for (int run_index = 0; run_index < mutrun_count; ++run_index)\n                    {\n                        const MutationRun *mutrun = haplosome->mutruns_[run_index];\n                        const MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n                        const MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n                        \n                        for (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n                        {\n                            const Mutation *mutation = mut_block_ptr + *haplosome_iter;\n                            \n                            if (mutation->mutation_type_ptr_->mutation_type_index_ == muttype_index)\n                                (mutation->gui_scratch_reference_count_)++;\n                        }\n                    }\n                    \n                    subpop_total_haplosome_count++;\n                }\n            }\n        }\n    }\n    \n    return subpop_total_haplosome_count;\n}\n\nsize_t QtSLiMGraphView::tallyGUIMutationReferences(const std::vector<Haplosome *> &haplosomes, int muttype_index)\n{\n    //\n\t// this code is a slightly modified clone of the code in Population::TallyMutationReferences; here we scan only the\n\t// subpopulation that is being displayed in this graph, and tally into gui_scratch_reference_count only\n\t// BCH 4/21/2023: This could use mutrun use counts to run faster...\n\t//\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!graphSpecies)\n        return 0;\n    \n    Population &population = graphSpecies->population_;\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n    \n    {\n        int registry_size;\n        const MutationIndex *registry = population.MutationRegistry(&registry_size);\n        const MutationIndex *registry_iter_end = registry + registry_size;\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n            (mut_block_ptr + *registry_iter)->gui_scratch_reference_count_ = 0;\n    }\n    \n\tfor (const Haplosome *haplosome : haplosomes)\n\t{\n        if (!haplosome->IsNull())\n        {\n            int mutrun_count = haplosome->mutrun_count_;\n            \n            for (int run_index = 0; run_index < mutrun_count; ++run_index)\n            {\n                const MutationRun *mutrun = haplosome->mutruns_[run_index];\n                const MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n                const MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n                \n                for (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n                {\n                    const Mutation *mutation = mut_block_ptr + *haplosome_iter;\n                    \n                    if (mutation->mutation_type_ptr_->mutation_type_index_ == muttype_index)\n                        (mutation->gui_scratch_reference_count_)++;\n                }\n            }\n        }\n    }\n    \n    return haplosomes.size();\n}\n\n\n//\n//  Axis tick calculations\n//\n//  This code is based upon the code in R 4.3.2.  R is open source under the GPL, so\n//  we are free to use it in Eidos/SLiM which is also GPL.  The GPL license is already\n//  incorporated in this distribution.  Thanks to all the contributors to this code in\n//  R, which provides a nice algorithm.\n//\n//  In QtSLiM's adapted code, I have removed a bunch of debugging code, removed the\n//  log-axis case, removed support for axis min > max, removed all the par()-based\n//  graphics-parameter stuff, removed various errors and warnings, etc.  These changes\n//  simplified the code, at the cost of making it less general and robust.  QtSLiM\n//  doesn't really want to be reporting random internal warnings and errors to the\n//  user, though; if we hit one of the edge cases that R used to handle, then que sera,\n//  sera.\n//\n\n// modified from R-4.3.2/src/library/graphics/src/graphics.c : void GScale(double min, double max, int axis, pGEDevDesc dd)\nvoid QtSLiMGraphView::_GScale(double &minValue, double &maxValue, double &axisMin, double &axisMax, int &nDivisions)\n{\n#define EPS_FAC_1  16\n    \n    // number of divisions; this comes from lab[0] in R, but for us we just always use the default of 5\n    nDivisions = 5;\n    \n    double temp = std::max(std::fabs(maxValue), std::fabs(minValue));\n    \n    if (temp == 0)      /* min = max = 0 */\n    {\n        minValue = -1;\n        maxValue = 1;\n    }\n    else\n    {\n        // careful to avoid overflow (and underflow) here:\n        double tf = (temp > 1) ? (temp * DBL_EPSILON) * EPS_FAC_1 : (temp * EPS_FAC_1  ) * DBL_EPSILON;\n        \n        if (tf == 0)\n            tf = DBL_MIN;\n        \n        if (std::fabs(maxValue - minValue) < tf)\n        {\n            temp *= 1e-2;\n            minValue -= temp;\n            maxValue += temp;\n        }\n    }\n    \n    if (true)\n    {\n        // R axis style 'r': (regular) first extends the data range by 4 percent at each end\n        // and then finds an axis with pretty labels that fits within the extended range.\n        temp = (temp > 100\n                    ? 0.04 * maxValue - 0.04 * minValue   // not to overflow\n                    : 0.04 * (maxValue - minValue));      // is negative iff max < min\n        \n        // careful now to not get to +/- Inf :\n        double d;\n        \n        d = minValue - temp;\n        if (std::isfinite(d))\n            minValue = d;\n        else\n            minValue = (d < 0) ? -DBL_MAX : DBL_MAX;\n        \n        d = maxValue + temp;\n        if (std::isfinite(d))\n            maxValue = d;\n        else\n            maxValue = (d < 0) ? -DBL_MAX : DBL_MAX;\n    }\n    else\n    {\n        // R axis style 'i': (internal) just finds an axis with pretty labels that fits\n        // within the original data range.  Presently inaccessible in QtSLiM.\n    }\n    \n    // Computation of [xy]axp[0:2] == (min,max,n) :\n    axisMin = minValue;\n    axisMax = maxValue;\n    \n    _GAxisPars(&axisMin, &axisMax, &nDivisions);\n\n#undef EPS_FAC_1\n}\n\n// modified from R-4.3.2/src/main/graphics.c : void GAxisPars(double *min, double *max, int *n, Rboolean log, int axis)\nvoid QtSLiMGraphView::_GAxisPars(double *minValue, double *maxValue, int *nDivisions)\n{\n#define EPS_FAC_2 16\n    \n    /* save only for the extreme case (EPS_FAC_2): */\n    double min_o = *minValue, max_o = *maxValue;\n    \n    _GEPretty(minValue, maxValue, nDivisions);\n    \n    double t_ = std::max(fabs(*maxValue), fabs(*minValue)),\n        tf = // careful to avoid overflow (and underflow) here:\n        (t_ > 1)\n            ? (t_ * DBL_EPSILON) * EPS_FAC_2\n            : (t_ * EPS_FAC_2  ) * DBL_EPSILON;\n    if (tf == 0) tf = DBL_MIN;\n    \n    if (fabs(*maxValue - *minValue) <= tf) {\n        /* Treat this case somewhat similar to the (min ~= max) case above */\n        /* Too much accuracy here just shows machine differences */\n        \n        /* No pretty()ing anymore */\n        *minValue = min_o;\n        *maxValue = max_o;\n        double eps = .005 * (*maxValue - *minValue);/* .005: not to go to DBL_MIN/MAX */\n        *minValue += eps;\n        *maxValue -= eps;\n        *nDivisions = 1;\n    }\n\n#undef EPS_FAC_2\n}\n\n// modified R-4.3.2/src/main/graphics.c : static void GLPretty(double *ul, double *uh, int *n)\nvoid QtSLiMGraphView::_GEPretty(double *lo, double *up, int *nDivisions)\n{\n    /*\tSet scale and ticks for linear scales.\n *\n *\tPre:\t    x1 == lo < up == x2      ;  nDivisions >= 1\n *\tPost: x1 <= y1 := lo < up =: y2 <= x2;\tnDivisions >= 1\n */\n    if (*nDivisions <= 0)\n        return;\n    \n    if (!std::isfinite(*lo) || !std::isfinite(*up)) // also catch NA etc\n        return;\n    \n    // For *finite* boundaries, now allow (*up - *lo) = +/- inf  as R_pretty() now does\n    double ns = *lo, nu = *up;\n    double unit, high_u_fact[3] = { .8, 1.7, 1.125 };\n        // =   (h, h5 , f_min) = (high.u.bias, u5.bias, f_min)\n    \n    unit = _R_pretty(&ns, &nu, nDivisions, /* min_n = */ 1,\n                    /* shrink_sml = */ 0.25,\n                    high_u_fact,\n                    2 /* do eps_correction in any case */);\n    \n    // The following is ugly since it kind of happens already in R_pretty(..):\n#define rounding_eps 1e-10 /* <- compatible to seq*(); was 1e-7 till 2017-08-14 */\n    \n    if (nu >= ns + 1) {\n        int mod = 0;\n        if (               ns * unit < *lo - rounding_eps * unit) { ns++; mod++; }\n        if (nu > ns + 1 && nu * unit > *up + rounding_eps * unit) { nu--; mod++; }\n        if (mod) *nDivisions = (int)(nu - ns);\n    }\n    \n    *lo = ns * unit;\n    *up = nu * unit;\n}\n\n// modified from R-4.3.2/src/appl/pretty.c : double R_pretty(double *lo, double *up, int *ndiv, int min_n, double shrink_sml, const double high_u_fact[], int eps_correction, int return_bounds)\ndouble QtSLiMGraphView::_R_pretty(double *lo, double *up, int *nDivisions, int min_n,\n                double shrink_sml,\n                const double high_u_fact[], // = (h, h5, f_min) below \n                int eps_correction)\n{\n/* From version 0.65 on, we had rounding_eps := 1e-5, before, r..eps = 0\n * then, 1e-7 was consistent with seq.default() and seq.int() till 2010-02-03,\n * where it was changed to 1e-10 for seq*(), and in 2017-08-14 for pretty(): */\n#define rounding_eps 1e-10\n\n// (h, h5, f_min) = c(high.u.bias, u5.bias, f.min) in base::pretty.default():\n#define h     high_u_fact[0]\n#define h5    high_u_fact[1]\n#define f_min high_u_fact[2]\n    \n    double // save input boundaries\n        lo_ = *lo,\n        up_ = *up,\n        dx = up_ - lo_,\n        cell, U;\n    bool i_small;\n    /* cell := \"scale\"\there */\n    if (dx == 0 && up_ == 0) { /*  up == lo == 0\t */\n        cell = 1;\n        i_small = true;\n    } else {\n        cell = std::max(fabs(lo_),fabs(up_));\n        /* U = upper bound on cell/unit */\n        U = 1 + ((h5 >= 1.5*h+.5) ? 1/(1+h) : 1.5/(1+h5));\n        U *= std::max(1,*nDivisions) * DBL_EPSILON; // avoid overflow for large nDivisions\n        /* added times 3, as several calculations here */\n        i_small = dx < cell * U * 3;\n    }\n\n    /*OLD: cell = FLT_EPSILON+ dx / *nDivisions; FLT_EPSILON = 1.192e-07 */\n    if (i_small) {\n        if(cell > 10)\n            cell = 9 + cell/10;\n        cell *= shrink_sml;\n        if(min_n > 1) cell /= min_n;\n    } else {\n        cell = dx;\n        if (std::isfinite(dx)) {\n            if (*nDivisions > 1) cell /= *nDivisions;\n        } else { // up - lo = +Inf (overflow; both are finite)\n            if (*nDivisions >= 2) {\n                cell = up_ / (*nDivisions) - lo_ / (*nDivisions);\n            }\n        }\n    }\n\n// f_min: arg, default = 2^-20, was 20.  till R 4.1.0 (2021-05)\n#define MAX_F 1.25 //\t\twas 10.   \"   \"   \"\n    \n    double subsmall = f_min*DBL_MIN;\n    if (subsmall == 0.) // subnormals underflowing to zero (not yet seen!)\n        subsmall = DBL_MIN;\n    if (cell < subsmall) { // possibly subnormal\n        cell = subsmall;\n    } else if (cell > DBL_MAX/MAX_F) {\n        cell = DBL_MAX/MAX_F;\n    }\n\n#undef MAX_F\n    \n    /* NB: the power can be negative and this relies on exact\n       calculation, which glibc's exp10 does not achieve */\n    double base = pow(10.0, floor(log10(cell))); /* base <= cell < 10*base */\n    \n    /* unit : from { 1,2,5,10 } * base\n     *\t such that |u - cell| is small,\n     * favoring larger (if h > 1, else smaller)  u  values;\n     * favor '5' more than '2'  if h5 > h  (default h5 = .5 + 1.5 h) */\n    double unit = base;\n    if ((U = 2*base)-cell <  h*(cell-unit)) { unit = U;\n        if ((U = 5*base)-cell < h5*(cell-unit)) { unit = U;\n            if ((U =10*base)-cell <  h*(cell-unit))   unit = U; }}\n    /* Result (c := cell,  b := base,  u := unit):\n     *\tc in [\t1,\t       (2+ h)/ (1+h) ] b ==> u=  b\n     *\tc in ( (2+ h) /(1+h),  (5+2h5)/(1+h5)] b ==> u= 2b\n     *\tc in ( (5+2h5)/(1+h5), (10+5h)/(1+h) ] b ==> u= 5b\n     *\tc in ((10+5h) /(1+h),\t     10      ) b ==> u=10b\n     *\n     *\t===>\t2/5 *(2+h)/(1+h)  <=  c/u  <=  (2+h)/(1+h)\t*/\n    \n    double ns = floor(lo_/unit+rounding_eps);\n    double nu = ceil (up_/unit-rounding_eps);\n    \n    if (eps_correction && (eps_correction > 1 || !i_small)) {\n        // FIXME?: assumes 0 <= lo <= up  (what if lo <= up < 0 ?)\n        if (lo_ != 0.) *lo *= (1- DBL_EPSILON); else *lo = -DBL_MIN;\n        if (up_ != 0.) *up *= (1+ DBL_EPSILON); else *up = +DBL_MIN;\n    }\n\n    while (ns*unit > *lo + rounding_eps*unit) ns--;\n    while (!std::isfinite(ns*unit)) ns++;\n\n    while (nu*unit < *up - rounding_eps*unit) nu++;\n    while (!std::isfinite(nu*unit)) nu--;\n    \n    int k = (int)(0.5 + nu - ns);\n    if (k < min_n) {\n        /* ensure that\tnu - ns\t == min_n */\n        k = min_n - k;\n        if (lo_ == 0. && ns == 0. && up_ != 0.) {\n            nu += k;\n        } else if (up_ == 0. && nu == 0. && lo_ != 0.) {\n            ns -= k;\n        } else if (ns >= 0.) {\n            nu += k/2;\n            ns -= k/2 + k%2;/* ==> nu-ns = old(nu-ns) + min_n -k = min_n */\n        } else {\n            ns -= k/2;\n            nu += k/2 + k%2;\n        }\n        *nDivisions = min_n;\n    }\n    else {\n        *nDivisions = k;\n    }\n    \n    *lo = ns;\n    *up = nu;\n\n    return unit;\n#undef h\n#undef h5\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView.h",
    "content": "//\n//  QtSLiMGraphView.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/27/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_H\n#define QTSLIMGRAPHVIEW_H\n\n#include <QWidget>\n#include <QFont>\n#include <QColor>\n\n#include <utility>\n#include <vector>\n\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMWindow.h\"\n\nclass QHBoxLayout;\nclass QComboBox;\nclass QPushButton;\n\n\n// A quick and dirty macro to enable rounding of coordinates to the nearest pixel only when we are not generating PDF\n// FIXME this ought to be revisited in the light of Retina displays, printing, etc.\n#define SLIM_SCREEN_ROUND(x)\t\t(generatingPDF_ ? (x) : round(x))\n\n\n// Legend support\nenum class QtSLiM_LegendEntryType : int {\n    kUninitialized = -1,\n    kTitle = 0,\n    kSwatch,\n    kLine,\n    kPoint\n};\n\nclass QtSLiMLegendEntry {\npublic: \n    // the text label for the legend entry\n    QString label;\n    \n    // the type of legend entry\n    QtSLiM_LegendEntryType entry_type = QtSLiM_LegendEntryType::kUninitialized;\n    \n    // attributes for a swatch component (QtSLiM_LegendEntryType::kSwatch)\n    QColor swatch_color;\n    \n    // attributes for a line component (QtSLiM_LegendEntryType::kLine); same as for plotLines()\n    double line_lwd;\n    QColor line_color;\n    \n    // attributes for a point component (QtSLiM_LegendEntryType::kPoint); same as for plotPoints()\n    int point_symbol;\n    QColor point_color;\n    QColor point_border;\n    double point_lwd;\n    double point_size;\n    \n    // constructor for an entry that shows a color swatch\n    QtSLiMLegendEntry(QString p_label, QColor p_swatch_color) :\n        label(p_label), entry_type(QtSLiM_LegendEntryType::kSwatch), swatch_color(p_swatch_color) {};\n    \n    // constructor for an entry that shows a line segment\n    QtSLiMLegendEntry(QString p_label, double p_line_lwd, QColor p_line_color) :\n        label(p_label), entry_type(QtSLiM_LegendEntryType::kLine), line_lwd(p_line_lwd), line_color(p_line_color) {};\n    \n    // constructor for an entry that shows a point symbol\n    QtSLiMLegendEntry(QString p_label, int p_point_symbol, QColor p_point_color, QColor p_point_border, double p_point_lwd, double p_point_size) :\n        label(p_label), entry_type(QtSLiM_LegendEntryType::kPoint), point_symbol(p_point_symbol), point_color(p_point_color), point_border(p_point_border), point_lwd(p_point_lwd), point_size(p_point_size) {};\n    \n    // constructor for an entry that shows a title\n    QtSLiMLegendEntry(QString p_label) :\n        label(p_label), entry_type(QtSLiM_LegendEntryType::kTitle) {};\n};\n\ntypedef std::vector<QtSLiMLegendEntry> QtSLiMLegendSpec;\n\n\nclass QtSLiMGraphView : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    static QFont labelFontOfPointSize(double size);\n    static inline QColor gridLineColor(void) { return QtSLiMColorWithWhite(0.85, 1.0); }\n    \n    QtSLiMGraphView(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView() override;\n    \n    virtual QString graphTitle(void) = 0;\n    virtual QString aboutString(void) = 0;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect);\n    \n    void setBorderless(bool isBorderless, double marginLeft, double marginTop, double marginRight, double marginBottom);\n    \n    bool writeToFile(QString fileName);\n    \npublic slots:\n    virtual void addedToWindow(void);\n    virtual void invalidateCachedData(void);        // subclasses must call this themselves in their destructor - super cannot do it!\n    virtual void invalidateDrawingCache(void);      // subclasses must call this themselves in their destructor - super cannot do it!\n    virtual void graphWindowResized(void);\n    virtual void controllerRecycled(void);          // subclasses must call super: QtSLiMGraphView::controllerRecycled()\n    virtual void controllerTickFinished(void);\n    virtual void updateAfterTick(void);             // subclasses must call super: QtSLiMGraphView::updateAfterTick()\n    virtual void updateSpeciesBadge(void);\n    void actionButtonRunMenu(QtSLiMPushButton *actionButton);\n    \nprotected:\n    QtSLiMWindow *controller_ = nullptr;\n    std::string focalSpeciesName_;                                  // we keep the name of our focal species, since a pointer would be unsafe\n    std::string focalSpeciesAvatar_;                                // cached so we can display it even when the simulation is invalid\n    \n    void setFocalDisplaySpecies(Species *species);\n    Species *focalDisplaySpecies(void);\n    bool missingFocalDisplaySpecies(void);                          // true if the graph has a focal display species but can't find it\n    \n    // Base graphing functionality\n    QRect interiorRectForBounds(QRect bounds);\n    \n    double plotToDeviceX(double plotx, QRect interiorRect);\n    double plotToDeviceY(double ploty, QRect interiorRect);\n    double roundPlotToDeviceX(double plotx, QRect interiorRect);\t// rounded off to the nearest midpixel\n    double roundPlotToDeviceY(double ploty, QRect interiorRect);\t// rounded off to the nearest midpixel\n    \n    inline QFont fontForAxisLabels(void) { return labelFontOfPointSize(axisLabelSize_); }\n    inline QFont fontForTickLabels(void) { return labelFontOfPointSize(tickLabelSize_); }\n    \n    QString labelTextForTick(double tickValue, int tickValuePrecision, double minorTickInterval);\n    void drawAxisTickLabel(QPainter &painter, QString labelText, double xValueForTick, double axisLength,\n                           bool isFirstTick, bool isLastTick);\n    \n    void drawXAxisTicks(QPainter &painter, QRect interiorRect);\n    void drawXAxis(QPainter &painter, QRect interiorRect);\n    void drawYAxisTicks(QPainter &painter, QRect interiorRect);\n    void drawYAxis(QPainter &painter, QRect interiorRect);\n    void drawFullBox(QPainter &painter, QRect interiorRect);\n    void drawVerticalGridLines(QPainter &painter, QRect interiorRect);\n    void drawHorizontalGridLines(QPainter &painter, QRect interiorRect);\n    void drawMessage(QPainter &painter, QString messageString, QRect rect);\n    void drawLegendInInteriorRect(QPainter &painter, QRect interiorRect);\n    \n    // Mandatory subclass overrides\n    virtual void appendStringForData(QString &string) = 0;\n    \n    // Optional subclass overrides\n    virtual void willDraw(QPainter &painter, QRect interiorRect);\n    virtual bool providesStringForData(void);\n    virtual QtSLiMLegendSpec legendKey(void);\n    virtual QSizeF legendSize(QPainter &painter);\n    virtual void drawLegend(QPainter &painter, QRectF legendRect);\n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event);\n    virtual QString disableMessage(void);\n    \n    // Adding new widgets at the bottom of the window\n    QHBoxLayout *buttonLayout(void);\n    QPushButton *actionButton(void);\n    QComboBox *newButtonInLayout(QHBoxLayout *layout);\n    \n    // Prefab additions\n    void setXAxisRangeFromTick(void);\n    void configureAxisForRange(double &dim0, double &dim1, double &axisMin, double &axisMax,\n                               double &majorTickInterval, double &minorTickInterval,\n                               int &majorTickModulus, int &tickValuePrecision);\n    QtSLiMLegendSpec subpopulationLegendKey(std::vector<slim_objectid_t> &subpopsToDisplay, bool drawSubpopsGray);\n    QtSLiMLegendSpec mutationTypeLegendKey(void);\n    void drawGroupedBarplot(QPainter &painter, QRect interiorRect, double *buffer, int subBinCount, int mainBinCount, double firstBinValue, double mainBinWidth);\n    void drawBarplot(QPainter &painter, QRect interiorRect, double *buffer, int binCount, double firstBinValue, double binWidth);\n    void drawHeatmap(QPainter &painter, QRect interiorRect, double *buffer, int xBinCount, int yBinCount);\n    bool addSubpopulationsToMenu(QComboBox *subpopButton, slim_objectid_t selectedSubpopID, slim_objectid_t avoidSubpopID = -1);\n    bool addMutationTypesToMenu(QComboBox *mutTypeButton, int selectedMutIDIndex);\n    size_t tallyGUIMutationReferences(slim_objectid_t subpop_id, int muttype_index);\n    size_t tallyGUIMutationReferences(const std::vector<Haplosome *> &haplosomes, int muttype_index);\n    \n    // Properties; initialized in the constructor, these defaults are just zero-fill\n    // The bounds in user coordinates (x0_/x1_/y0_/y1_) are the actual extents of the\n    // axes; this is somewhat unrelated to the positions at which tick and labels are\n    // drawn, which are prettified.  The axis limits (xAxisMin_, xAxisMax_, ...) express\n    // the limits of tick marks; they are the conceptual limits of the axes, but\n    // typically there are margins of 4% or so outside of that range so the data isn't\n    // right up against the edges of the plot.  The original axis limits provided\n    // by the user are kept in original_x0_ etc., since x0_ and xAxisMin_ do not\n    // necessarily reflect the original values; they can get changed for aesthetics.\n    // See QtSLiMGraphView::setBorderless() for the reason we need the original values.\n    double original_x0_ = 0.0, original_x1_ = 0.0, original_y0_ = 0.0, original_y1_ = 0.0;\n    double x0_ = 0.0, x1_ = 0.0, y0_ = 0.0, y1_ = 0.0;  // coordinate space bounds\n    \n    double axisLabelSize_ = 15;\n    double tickLabelSize_ = 10;\n    \n    bool showXAxis_ = false;\n    bool allowXAxisUserRescale_ = false;\n    bool xAxisIsUserRescaled_ = false;      // the user gave a custom axis scale in any way (such as in createPlot())\n    bool xAxisIsUIRescaled_ = false;        // the user gave a custom axis scale in the QtSLiM UI, which has precedence\n    bool showXAxisTicks_ = false;\n    double xAxisMin_ = 0.0, xAxisMax_ = 0.0;\n    double xAxisMajorTickInterval_ = 0.0, xAxisMinorTickInterval_ = 0.0;\n    int xAxisMajorTickModulus_ = 0;\n    int xAxisTickValuePrecision_ = 0;   // negative values request output mode 'g' instead of 'f'\n    bool xAxisHistogramStyle_ = false;\n    QString xAxisLabel_;\n    std::vector<double> *xAxisAt_ = nullptr;\n    int xAxisLabelsType_ = 0;           // 0 == F (don't show labels), 1 == T (numeric position labels), 2 == use xAxisLabels_\n    std::vector<QString> *xAxisLabels_ = nullptr;\n    \n    bool showYAxis_ = false;\n    bool allowYAxisUserRescale_ = false;\n    bool yAxisIsUserRescaled_ = false;      // the user gave a custom axis scale in any way (such as in createPlot())\n    bool yAxisIsUIRescaled_ = false;        // the user gave a custom axis scale in the QtSLiM UI, which has precedence\n    bool showYAxisTicks_ = false;\n    double yAxisMin_ = 0.0, yAxisMax_ = 0.0;\n    double yAxisMajorTickInterval_ = 0.0, yAxisMinorTickInterval_ = 0.0;\n    int yAxisMajorTickModulus_ = 0;\n    int yAxisTickValuePrecision_ = 0;   // negative values request output mode 'g' instead of 'f'\n    bool yAxisHistogramStyle_ = false;\n    bool yAxisLog_ = false;\n    QString yAxisLabel_;\n    std::vector<double> *yAxisAt_ = nullptr;\n    int yAxisLabelsType_ = 0;           // 0 == F (don't show labels), 1 == T (numeric position labels), 2 == use yAxisLabels_\n    std::vector<QString> *yAxisLabels_ = nullptr;\n    \n    bool legendVisible_ = false;\n    QtSLiM_LegendPosition legend_position_ = QtSLiM_LegendPosition::kUnconfigured;\n    int legend_inset = -1;\n    double legend_labelSize = -1;\n    double legend_lineHeight = -1;\n    double legend_graphicsWidth = -1;\n    double legend_exteriorMargin = -1;\n    double legend_interiorMargin = -1;\n    \n    bool showHorizontalGridLines_ = false;\n    bool showVerticalGridLines_ = false;\n    bool showGridLinesMajorOnly_ = false;\n    bool showFullBox_ = false;\n    bool allowHorizontalGridChange_ = false;\n    bool allowVerticalGridChange_ = false;\n    bool allowFullBoxChange_ = false;\n    \n    bool tweakXAxisTickLabelAlignment_ = false;\n    \n    // borderless plots show no axes, no ticks, no labels; this feature is used only for custom plots\n    // for borderless plots, the plot region is the whole window area, and the data range fills the plot\n    // that is inset by the margins given here, measured in pixels, to allow a bit of overflow\n    bool is_borderless_ = false;\n    double borderless_margin_left_ = 0.0;\n    double borderless_margin_right_ = 0.0;\n    double borderless_margin_top_ = 0.0;\n    double borderless_margin_bottom_ = 0.0;\n    \n    // Prefab additions properties\n    int histogramBinCount_ = 0;\n    bool allowBinCountRescale_ = false;\n    int heatmapMargins_ = 0;\n    bool allowHeatmapMarginsChange_ = false;\n    bool rebuildingMenu_ = false;           // set to true during addSubpopulationsToMenu() / addMutationTypesToMenu()\n    \n    // set to YES during a copy: operation, to allow customization\n\tbool generatingPDF_ = false;\n\t\n\t// caching for drawing speed is up to subclasses, if they want to do it, but we provide minimal support\n    // in GraphView to make it work smoothly; this flag is to prevent recursion in the drawing code, and to\n    // disable drawing of things that don't belong in a cache, such as the legend\n\tbool cachingNow_ = false;\n    \nprotected:\n    int lineCountForLegend(QtSLiMLegendSpec &legend);\n    double graphicsWidthForLegend(QtSLiMLegendSpec &legend, double legendLineHeight);\n    void drawPointSymbol(QPainter &painter, double x, double y, int symbol, QColor symbolColor, QColor borderColor, double alpha, double lineWidth, double size);\n    \nprivate:\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override;\n    void drawContents(QPainter &painter);\n    \n    virtual void resizeEvent(QResizeEvent *p_event) override;\n    virtual void contextMenuEvent(QContextMenuEvent *p_event) override;\n    \n    QString stringForData(void);\n    \n    // Internal axis layout code, based on R; presently used only by custom graphs\n    void _GScale(double &minValue, double &maxValue, double &axisMin, double &axisMax, int &nDivisions);\n    void _GAxisPars(double *minValue, double *maxValue, int *nDivisions);\n    void _GEPretty(double *lo, double *up, int *nDivisions);\n    double _R_pretty(double *lo, double *up, int *nDivisions, int min_n, double shrink_sml,\n                        const double high_u_fact[], int eps_correction);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_1DPopulationSFS.cpp",
    "content": "//\n//  QtSLiMGraphView_1DPopulationSFS.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/27/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_1DPopulationSFS.h\"\n\n#include \"QtSLiMWindow.h\"\n\n#include <string>\n\n\nQtSLiMGraphView_1DPopulationSFS::QtSLiMGraphView_1DPopulationSFS(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 10;\n    allowBinCountRescale_ = true;\n    \n    xAxisMajorTickInterval_ = 0.2;\n    xAxisMinorTickInterval_ = 0.1;\n    xAxisMajorTickModulus_ = 2;\n    xAxisTickValuePrecision_ = 1;\n    \n    xAxisLabel_ = \"Mutation frequency\";\n    yAxisLabel_ = \"Proportion of mutations\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = false;\n    \n    showHorizontalGridLines_ = true;\n}\n\nQtSLiMGraphView_1DPopulationSFS::~QtSLiMGraphView_1DPopulationSFS()\n{\n}\n\nQString QtSLiMGraphView_1DPopulationSFS::graphTitle(void)\n{\n    return \"1D Population SFS\";\n}\n\nQString QtSLiMGraphView_1DPopulationSFS::aboutString(void)\n{\n    return \"The 1D Population SFS graph shows a Site Frequency Spectrum (SFS) for the entire population.  Since \"\n           \"mutation occurrence counts across the whole population might be very large, the x axis here is the \"\n           \"frequency of a given mutation, from 0.0 to 1.0, rather than an occurrence count.  The y axis is the \"\n           \"proportion of all mutations that fall within a given binned frequency range.  The number of frequency \"\n           \"bins can be customized from the action menu.  The 1D Sample SFS graph provides an alternative that \"\n           \"might also be useful.\";\n}\n\ndouble *QtSLiMGraphView_1DPopulationSFS::populationSFS(int mutationTypeCount)\n{\n    static uint32_t *spectrum = nullptr;\t\t\t// used for tallying\n\tstatic double *doubleSpectrum = nullptr;\t// not used for tallying, to avoid precision issues\n\tstatic size_t spectrumBins = 0;\n\tint binCount = histogramBinCount_;\n\tsize_t usedSpectrumBins = static_cast<size_t>(binCount * mutationTypeCount);\n\t\n\t// allocate our bins\n\tif (!spectrum || (spectrumBins < usedSpectrumBins))\n\t{\n\t\tspectrumBins = usedSpectrumBins;\n\t\tspectrum = static_cast<uint32_t *>(realloc(spectrum, spectrumBins * sizeof(uint32_t)));\n\t\tdoubleSpectrum = static_cast<double *>(realloc(doubleSpectrum, spectrumBins * sizeof(double)));\n\t}\n\t\n\t// clear our bins\n\tfor (size_t i = 0; i < usedSpectrumBins; ++i)\n\t\tspectrum[i] = 0;\n\t\n\t// get the selected chromosome range\n    Species *graphSpecies = focalDisplaySpecies();\n\t\n\t// tally into our bins\n\tPopulation &pop = graphSpecies->population_;\n\t\n\tpop.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\t// update tallies; usually this will just use the cache set up by Population::MaintainRegistry()\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n    int registry_size;\n    const MutationIndex *registry = pop.MutationRegistry(&registry_size);\n\t\n\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t{\n\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n        Chromosome *mut_chromosome = graphSpecies->Chromosomes()[mutation->chromosome_index_];\n        double totalHaplosomeCount = ((mut_chromosome->total_haplosome_count_ == 0) ? 1 : mut_chromosome->total_haplosome_count_);   // prevent a zero count from producing NAN frequencies below\n\t\t\n\t\tslim_refcount_t mutationRefCount = *(refcount_block_ptr + mutation->BlockIndex());\n\t\tdouble mutationFrequency = mutationRefCount / totalHaplosomeCount;\n\t\tint mutationBin = static_cast<int>(floor(mutationFrequency * binCount));\n\t\tint mutationTypeIndex = mutation->mutation_type_ptr_->mutation_type_index_;\n\t\t\n\t\tif (mutationBin == binCount)\n\t\t\tmutationBin = binCount - 1;\n\t\t\n\t\t(spectrum[mutationTypeIndex + mutationBin * mutationTypeCount])++;\t// bins in sequence for each mutation type within one frequency bin, then again for the next frequency bin, etc.\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tuint32_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += spectrum[binIndex];\n\t\t}\n\t\t\n        for (int bin = 0; bin < binCount; ++bin)\n        {\n            int binIndex = mutationTypeIndex + bin * mutationTypeCount;\n            \n            doubleSpectrum[binIndex] = (total > 0) ? (spectrum[binIndex] / static_cast<double>(total)) : 0.0;\n        }\n    }\n\t\n\t// return the final tally; note this is a pointer in to our static ivar, and must not be freed!\n\treturn doubleSpectrum;\n}\n\nvoid QtSLiMGraphView_1DPopulationSFS::drawGraph(QPainter &painter, QRect interiorRect)\n{\n\tint binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n\tint mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\tdouble *spectrum = populationSFS(mutationTypeCount);\n\t\n\t// plot our histogram bars\n\tdrawGroupedBarplot(painter, interiorRect, spectrum, mutationTypeCount, binCount, 0.0, (1.0 / binCount));\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_1DPopulationSFS::legendKey(void)\n{\n\treturn mutationTypeLegendKey();     // we use the prefab mutation type legend\n}\n\nbool QtSLiMGraphView_1DPopulationSFS::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_1DPopulationSFS::appendStringForData(QString &string)\n{\n    // get the selected chromosome range\n    Species *graphSpecies = focalDisplaySpecies();\n\tint binCount = histogramBinCount_;\n\tint mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\tdouble *plotData = populationSFS(mutationTypeCount);\n\t\n\tfor (auto mutationTypeIter : graphSpecies->mutation_types_)\n\t{\n\t\tMutationType *mutationType = mutationTypeIter.second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n        string.append(QString(\"\\\"m%1\\\", \").arg(mutationType->mutation_type_id_));\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n            string.append(QString(\"%1, \").arg(plotData[histIndex], 0, 'f', 4));\n\t\t}\n\t\t\n        string.append(\"\\n\");\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_1DPopulationSFS.h",
    "content": "//\n//  QtSLiMGraphView_1DPopulationSFS.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/27/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_1DPOPULATIONSFS_H\n#define QTSLIMGRAPHVIEW_1DPOPULATIONSFS_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_1DPopulationSFS : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_1DPopulationSFS(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_1DPopulationSFS() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    \nprivate:\n    double *populationSFS(int mutationTypeCount);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_1DPOPULATIONSFS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_1DSampleSFS.cpp",
    "content": "//\n//  QtSLiMGraphView_1DSampleSFS.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/20/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_1DSampleSFS.h\"\n\n#include <QComboBox>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QApplication>\n#include <QGuiApplication>\n#include <QDebug>\n\n#include <string>\n#include <vector>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n#include \"mutation_type.h\"\n\n\nQtSLiMGraphView_1DSampleSFS::QtSLiMGraphView_1DSampleSFS(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 20;        // this is also the haplosome sample size\n    allowBinCountRescale_ = false;\n    \n    original_x0_ = 0;\n    original_x1_ = histogramBinCount_;\n    \n    x0_ = original_x0_;\n    x1_ = original_x1_;\n    \n    xAxisMin_ = x0_;\n    xAxisMax_ = x1_;\n    xAxisHistogramStyle_ = true;\n    xAxisTickValuePrecision_ = 0;\n    \n    original_y0_ = -0.05;      // on log scale; we want a frequency of 1 to show slightly above baseline\n    original_y1_ = 3.0;        // on log scale; maximum power of 10\n    \n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    yAxisMin_ = y0_;\n    yAxisMax_ = y1_;\n    yAxisMajorTickInterval_ = 1;\n    yAxisMinorTickInterval_ = 1/9.0;\n    yAxisMajorTickModulus_ = 9;         // 9 ticks per major; ticks at 1:10 are represented by values 0:9, and 0 and 9 both need to be modulo 0\n    yAxisLog_ = true;       // changes positioning of ticks, grid lines, etc.\n    \n    xAxisLabel_ = \"Count in sample\";\n    yAxisLabel_ = \"Number of mutations\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    showGridLinesMajorOnly_ = true;\n    allowHorizontalGridChange_ = true;\n    allowVerticalGridChange_ = false;\n    allowFullBoxChange_ = true;\n    \n    selectedSubpopulation1ID_ = 1;\n    selectedMutationTypeIndex_ = -1;\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulation1Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation1Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_1DSampleSFS::subpopulation1PopupChanged);\n        \n        mutationTypeButton_ = newButtonInLayout(button_layout);\n        connect(mutationTypeButton_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_1DSampleSFS::mutationTypePopupChanged);\n        \n        addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n        addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    }\n}\n\nQtSLiMGraphView_1DSampleSFS::~QtSLiMGraphView_1DSampleSFS()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_1DSampleSFS::invalidateCachedData();\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::subpopulation1PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation1Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation1ID_ != newSubpopID))\n    {\n        selectedSubpopulation1ID_ = newSubpopID;\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::mutationTypePopupChanged(int /* index */)\n{\n    int newMutTypeIndex = mutationTypeButton_->currentData().toInt();\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedMutationTypeIndex_ != newMutTypeIndex))\n    {\n        selectedMutationTypeIndex_ = newMutTypeIndex;\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t\tupdate();\n\t\n    // Remake our popups, whether or not the controller is valid\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_1DSampleSFS::graphTitle(void)\n{\n    return \"1D Sample SFS\";\n}\n\nQString QtSLiMGraphView_1DSampleSFS::aboutString(void)\n{\n    return \"The 1D Sample SFS graph shows a Site Frequency Spectrum (SFS) for a sample of haplosomes taken \"\n           \"(with replacement) from a given subpopulation, for mutations of a given mutation type.  The x axis \"\n           \"here is the occurrence count of a given mutation within the sample, from 1 to the sample size.  The \"\n           \"y axis is the number of mutations in the sample with that specific occurrence count, on a log \"\n           \"scale.  The y axis range and the sample size can be customized from the action menu.  The 1D \"\n           \"Population SFS graph provides an alternative that might also be useful.\";\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::invalidateCachedData(void)\n{\n    if (sfs1dbuf_)\n    {\n        free(sfs1dbuf_);\n        sfs1dbuf_ = nullptr;\n    }\n    \n    QtSLiMGraphView::invalidateCachedData();\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::updateAfterTick(void)\n{\n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n\t\n    invalidateCachedData();\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_1DSampleSFS::disableMessage(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (graphSpecies)\n    {\n        Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n        MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n        \n        //qDebug() << \"muttype \" << muttype << \" for id \" << selectedMutationTypeIndex_;\n        \n        //if (!subpop1 || !muttype)\n        //    return \"no\\ndata\";\n        if (!subpop1)\n            return \"no\\nsubpop\";\n        if (!muttype)\n            return \"no\\nmuttype\";\n    }\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::drawGraph(QPainter &painter, QRect interiorRect)\n{\n\tuint64_t *sfs1dbuf = mutation1DSFS();\n\t\n    if (sfs1dbuf)\n    {\n        // plot our histogram bars\n        double *sfsTransformed = (double *)calloc(histogramBinCount_, sizeof(double));\n        \n        for (int i = 0; i < histogramBinCount_; ++i)\n        {\n            uint64_t value = sfs1dbuf[i];\n            \n            sfsTransformed[i] = (value == 0) ? -1000 : log10(value);\n        }\n        \n        drawBarplot(painter, interiorRect, sfsTransformed, histogramBinCount_, 0.0, 1.0);\n        \n        free(sfsTransformed);\n    }\n}\n\nbool QtSLiMGraphView_1DSampleSFS::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::appendStringForData(QString &string)\n{\n\tuint64_t *plotData = mutation1DSFS();\n\t\n    for (int i = 0; i < histogramBinCount_; ++i)\n        string.append(QString(\"%1, \").arg(plotData[i]));\n    \n    string.append(\"\\n\");\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::changeSampleSize(void)\n{\n    // Similar to \"Change Bin Count...\", just different branding\n    QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a sample size:\", QStringList(\"Sample size:\"), QStringList(QString::number(histogramBinCount_)));\n    \n    if (choices.length() == 1)\n    {\n        int newSampleSize = choices[0].toInt();\n        \n        if ((newSampleSize > 1) && (newSampleSize <= 500))\n        {\n            histogramBinCount_ = newSampleSize;\n            xAxisMax_ = histogramBinCount_;\n            original_x1_ = histogramBinCount_;               // the same as xAxisMax_, for base plots\n            x1_ = original_x1_;\n            invalidateCachedData();\n            update();\n        }\n        else qApp->beep();\n    }\n}\n\nvoid QtSLiMGraphView_1DSampleSFS::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(\"Change Sample Size...\", this, &QtSLiMGraphView_1DSampleSFS::changeSampleSize);\n}\n\nuint64_t *QtSLiMGraphView_1DSampleSFS::mutation1DSFS(void)\n{\n    if (!sfs1dbuf_)\n    {\n        Species *graphSpecies = focalDisplaySpecies();\n        Population &population = graphSpecies->population_;\n        \n        // Find our subpops and mutation type\n        Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n        MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n        \n        if (!subpop1 || !muttype)\n            return nullptr;\n        \n        // Get frequencies for a sample taken (with replacement) from subpop1\n        {\n            std::vector<Haplosome *> sampleHaplosomes;\n            std::vector<Individual *> &subpopIndividuals = subpop1->parent_individuals_;\n            size_t subpopHaplosomeCount = subpopIndividuals.size() * 2;\n            \n            if (subpopHaplosomeCount)\n                for (int i = 0; i < histogramBinCount_ - 1; ++i)\n                {\n                    slim_popsize_t haplosome_index = random() % subpopHaplosomeCount;\n                    slim_popsize_t individual_index = haplosome_index >> 1;\n                    Haplosome *haplosome = subpopIndividuals[individual_index]->haplosomes_[haplosome_index & 0x01];\n                    \n                    sampleHaplosomes.emplace_back(haplosome);\n                }\n            \n            tallyGUIMutationReferences(sampleHaplosomes, selectedMutationTypeIndex_);\n        }\n        \n        // Tally into our bins\n        sfs1dbuf_ = static_cast<uint64_t *>(calloc(histogramBinCount_, sizeof(uint64_t)));\n        Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n        int registry_size;\n        const MutationIndex *registry = population.MutationRegistry(&registry_size);\n        \n        for (int registry_index = 0; registry_index < registry_size; ++registry_index)\n        {\n            const Mutation *mutation = mut_block_ptr + registry[registry_index];\n            slim_refcount_t mutationRefCount = mutation->gui_scratch_reference_count_;\n            int mutationBin = mutationRefCount - 1;\n            \n            if (mutationBin >= 0)           // mutationBin is -1 if the mutation is not present in the sample at all\n                (sfs1dbuf_[mutationBin])++;\n        }\n    }\n    \n    // Return the final tally; note that we retain ownership of this buffer and only free it when we want to force a recache\n\treturn sfs1dbuf_;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_1DSampleSFS.h",
    "content": "//\n//  QtSLiMGraphView_1DSampleSFS.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/20/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_1DSAMPLESFS_H\n#define QTSLIMGRAPHVIEW_1DSAMPLESFS_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_1DSampleSFS : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_1DSampleSFS(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_1DSampleSFS() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void invalidateCachedData(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void subpopulation1PopupChanged(int index);\n    void mutationTypePopupChanged(int index);\n    void changeSampleSize(void);\n    \nprivate:\n    // pop-up menu buttons\n    QComboBox *subpopulation1Button_ = nullptr;\n\tQComboBox *mutationTypeButton_ = nullptr;\n    \n    // The subpop and mutation type selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulation1ID_;\n    int selectedMutationTypeIndex_;\n    \n    uint64_t *sfs1dbuf_ = nullptr;\n    uint64_t *mutation1DSFS(void);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_1DSAMPLESFS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_2DPopulationSFS.cpp",
    "content": "//\n//  QtSLiMGraphView_2DPopulationSFS.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/22/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_2DPopulationSFS.h\"\n\n#include <QComboBox>\n#include <QDebug>\n\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"mutation_type.h\"\n\n\nQtSLiMGraphView_2DPopulationSFS::QtSLiMGraphView_2DPopulationSFS(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 20;\n    allowBinCountRescale_ = true;\n    \n    heatmapMargins_ = 0;\n    allowHeatmapMarginsChange_ = true;\n    \n    xAxisLabel_ = \"Frequency in p1\";\n    yAxisLabel_ = \"Frequency in p2\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = false;\n    \n    showHorizontalGridLines_ = false;\n    showVerticalGridLines_ = false;\n    showFullBox_ = true;\n    allowHorizontalGridChange_ = false;\n    allowVerticalGridChange_ = false;\n    allowFullBoxChange_ = false;\n    \n    // Default to plotting p1 against p2, with no default mutation type\n    selectedSubpopulation1ID_ = 1;\n    selectedSubpopulation2ID_ = 2;\n    selectedMutationTypeIndex_ = -1;\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulation1Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation1Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DPopulationSFS::subpopulation1PopupChanged);\n        \n        subpopulation2Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation2Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DPopulationSFS::subpopulation2PopupChanged);\n        \n        mutationTypeButton_ = newButtonInLayout(button_layout);\n        connect(mutationTypeButton_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DPopulationSFS::mutationTypePopupChanged);\n        \n        addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n        addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_);\n        addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    }\n}\n\nQtSLiMGraphView_2DPopulationSFS::~QtSLiMGraphView_2DPopulationSFS()\n{\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::subpopulation1PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation1Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation1ID_ != newSubpopID))\n    {\n        selectedSubpopulation1ID_ = newSubpopID;\n        xAxisLabel_ = QString(\"Frequency in p%1\").arg(selectedSubpopulation1ID_);\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::subpopulation2PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation2Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation2ID_ != newSubpopID))\n    {\n        selectedSubpopulation2ID_ = newSubpopID;\n        yAxisLabel_ = QString(\"Frequency in p%1\").arg(selectedSubpopulation2ID_);\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::mutationTypePopupChanged(int /* index */)\n{\n    int newMutTypeIndex = mutationTypeButton_->currentData().toInt();\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedMutationTypeIndex_ != newMutTypeIndex))\n    {\n        selectedMutationTypeIndex_ = newMutTypeIndex;\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t\tupdate();\n\t\n    // Remake our popups, whether or not the controller is valid\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_2DPopulationSFS::graphTitle(void)\n{\n    return \"2D Population SFS\";\n}\n\nQString QtSLiMGraphView_2DPopulationSFS::aboutString(void)\n{\n    return \"The 2D Population SFS graph shows a Site Frequency Spectrum (SFS) for two entire subpopulations in \"\n           \"the population, for mutations of a given mutation type.  Since mutation occurrence counts across \"\n           \"whole subpopulations might be very large, the x and y axes here are the frequencies of a given mutation \"\n           \"in the two subpopulations, from 0.0 to 1.0 on each axis, rather than occurrence counts.  The z axis, \"\n           \"represented with color, is the proportion of mutations (among those present in either of the two \"\n           \"subpopulations) that fall within a binned range of frequencies in the two subpopulations; a proportion \"\n           \"of zero is represented by white, and the maximum observed proportion is represented by black (rescaled each \"\n           \"time the graph redisplays), with heat colors from yellow (low) through red and up to black (high).  The \"\n           \"number of frequency bins can be customized from the action menu.  The 2D Sample SFS graph provides an \"\n           \"alternative that might also be useful.\";\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::updateAfterTick(void)\n{\n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_, selectedSubpopulation1ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n\t\n    invalidateCachedData();\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_2DPopulationSFS::disableMessage(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (graphSpecies)\n    {\n        Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n        Subpopulation *subpop2 = graphSpecies->SubpopulationWithID(selectedSubpopulation2ID_);\n        MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n        \n        if (!subpop1 || !subpop2 || !muttype)\n            return \"no\\ndata\";\n    }\n    \n    return \"\";\n}\n\n\nvoid QtSLiMGraphView_2DPopulationSFS::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    double *sfs2dbuf = mutation2DSFS();\n    \n    if (sfs2dbuf)\n    {\n        drawHeatmap(painter, interiorRect, sfs2dbuf, histogramBinCount_, histogramBinCount_);\n        free(sfs2dbuf);\n    }\n}\n\nbool QtSLiMGraphView_2DPopulationSFS::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_2DPopulationSFS::appendStringForData(QString &string)\n{\n    double *plotData = mutation2DSFS();\n\t\n    for (int yc = 0; yc < histogramBinCount_; ++yc)\n    {\n        for (int xc = 0; xc < histogramBinCount_; ++xc)\n            string.append(QString(\"%1, \").arg(plotData[xc + yc * histogramBinCount_], 0, 'f', 4));\n        string.append(\"\\n\");\n    }\n    \n    free(plotData);\n}\n\ndouble *QtSLiMGraphView_2DPopulationSFS::mutation2DSFS(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &population = graphSpecies->population_;\n    int registry_size;\n    const MutationIndex *registry = population.MutationRegistry(&registry_size);\n    const MutationIndex *registry_iter_end = registry + registry_size;\n    \n    // Find our subpops and mutation type\n    Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n    Subpopulation *subpop2 = graphSpecies->SubpopulationWithID(selectedSubpopulation2ID_);\n    MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n    \n    if (!subpop1 || !subpop2 || !muttype)\n\t\treturn nullptr;\n    \n    // Get frequencies in subpop1 and subpop2\n    Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n    std::vector<slim_refcount_t> refcounts1, refcounts2;\n    size_t subpop1_total_haplosome_count, subpop2_total_haplosome_count;\n    \n    {\n        subpop1_total_haplosome_count = tallyGUIMutationReferences(selectedSubpopulation1ID_, selectedMutationTypeIndex_);\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n        {\n            const Mutation *mutation = mut_block_ptr + *registry_iter;\n            if (mutation->mutation_type_ptr_->mutation_type_index_ == selectedMutationTypeIndex_)\n                refcounts1.emplace_back(mutation->gui_scratch_reference_count_);\n        }\n        \n        if (subpop1_total_haplosome_count == 0)\n            subpop1_total_haplosome_count = 1;     // counts will all be zero; prevent NAN frequency, make it zero instead\n    }\n    {\n        subpop2_total_haplosome_count = tallyGUIMutationReferences(selectedSubpopulation2ID_, selectedMutationTypeIndex_);\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n        {\n            const Mutation *mutation = mut_block_ptr + *registry_iter;\n            if (mutation->mutation_type_ptr_->mutation_type_index_ == selectedMutationTypeIndex_)\n                refcounts2.emplace_back(mutation->gui_scratch_reference_count_);\n        }\n        \n        if (subpop2_total_haplosome_count == 0)\n            subpop2_total_haplosome_count = 1;     // counts will all be zero; prevent NAN frequency, make it zero instead\n    }\n    \n    // Tally up the binned 2D SFS from the 1D data\n    double *sfs2dbuf = (double *)calloc(histogramBinCount_ * histogramBinCount_, sizeof(double));\n    size_t refcounts_size = refcounts1.size();\n    \n    for (size_t refcount_index = 0; refcount_index < refcounts_size; ++refcount_index)\n    {\n        slim_refcount_t count1 = refcounts1[refcount_index];\n        slim_refcount_t count2 = refcounts2[refcount_index];\n        \n        // exclude mutations that are not present in either subpopulation\n        if ((count1 > 0) || (count2 > 0))\n        {\n            double freq1 = count1 / (double)subpop1_total_haplosome_count;\n            double freq2 = count2 / (double)subpop2_total_haplosome_count;\n            int bin1 = static_cast<int>(round(freq1 * (histogramBinCount_ - 1)));\n            int bin2 = static_cast<int>(round(freq2 * (histogramBinCount_ - 1)));\n            sfs2dbuf[bin1 + bin2 * histogramBinCount_]++;\n        }\n    }\n    \n    // Normalize the bin counts to [0,1]; 0 is reserved for actual zero counts, the rest are on a log scale\n    double maxCount = 0;\n    \n    for (int i = 0; i < histogramBinCount_ * histogramBinCount_; ++i)\n        maxCount = std::max(maxCount, sfs2dbuf[i]);\n    \n    if (maxCount > 0.0)\n    {\n        double logMaxCount = std::log10(maxCount + 1);\n        \n        for (int i = 0; i < histogramBinCount_ * histogramBinCount_; ++i)\n        {\n            double value = sfs2dbuf[i];\n            \n            if (value != 0.0)\n                sfs2dbuf[i] = std::log10(value + 1) / logMaxCount;\n        }\n    }\n    \n    // return the final tally; note the caller takes responsibility for freeing this buffer!\n    return sfs2dbuf;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_2DPopulationSFS.h",
    "content": "//\n//  QtSLiMGraphView_2DPopulationSFS.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/18/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_2DPOPULATIONSFS_H\n#define QTSLIMGRAPHVIEW_2DPOPULATIONSFS_H\n\n#include \"QtSLiMGraphView.h\"\n\nclass MutationType;\n\n\nclass QtSLiMGraphView_2DPopulationSFS : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_2DPopulationSFS(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_2DPopulationSFS() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void subpopulation1PopupChanged(int index);\n    void subpopulation2PopupChanged(int index);\n    void mutationTypePopupChanged(int index);\n    \nprivate:\n    // pop-up menu buttons\n    QComboBox *subpopulation1Button_ = nullptr;\n    QComboBox *subpopulation2Button_ = nullptr;\n\tQComboBox *mutationTypeButton_ = nullptr;\n    \n    // The subpop and mutation type selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulation1ID_;\n    slim_objectid_t selectedSubpopulation2ID_;\n    int selectedMutationTypeIndex_;\n    \n    double *mutation2DSFS(void);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_2DPOPULATIONSFS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_2DSampleSFS.cpp",
    "content": "//\n//  QtSLiMGraphView_2DSampleSFS.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/18/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_2DSampleSFS.h\"\n\n#include <QComboBox>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QApplication>\n#include <QGuiApplication>\n#include <QDebug>\n\n#include <string>\n#include <vector>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n#include \"mutation_type.h\"\n\n\nQtSLiMGraphView_2DSampleSFS::QtSLiMGraphView_2DSampleSFS(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 21;        // this is the haplosome sample size + 1\n    allowBinCountRescale_ = false;\n    \n    original_x0_ = -1;                 // zero is included, unlike the 1D plot\n    original_x1_ = histogramBinCount_ - 1;\n    \n    x0_ = original_x0_;\n    x1_ = original_x1_;\n    \n    xAxisMin_ = x0_;\n    xAxisMax_ = x1_;\n    xAxisHistogramStyle_ = true;\n    xAxisTickValuePrecision_ = 0;\n    \n    original_y0_ = -1;                 // zero is included, unlike the 1D plot\n    original_y1_ = histogramBinCount_ - 1;\n    \n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    yAxisMin_ = y0_;\n    yAxisMax_ = y1_;\n    yAxisHistogramStyle_ = true;\n    yAxisTickValuePrecision_ = 0;\n    \n    zAxisMax_ = 1000;   // 10^3\n    \n    heatmapMargins_ = 0;\n    allowHeatmapMarginsChange_ = true;\n    \n    xAxisLabel_ = \"Count in p1 sample\";\n    yAxisLabel_ = \"Count in p2 sample\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = false;\n    \n    showHorizontalGridLines_ = false;\n    showVerticalGridLines_ = false;\n    showFullBox_ = true;\n    allowHorizontalGridChange_ = false;\n    allowVerticalGridChange_ = false;\n    allowFullBoxChange_ = false;\n    \n    // Default to plotting p1 against p2, with no default mutation type\n    selectedSubpopulation1ID_ = 1;\n    selectedSubpopulation2ID_ = 2;\n    selectedMutationTypeIndex_ = -1;\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulation1Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation1Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DSampleSFS::subpopulation1PopupChanged);\n        \n        subpopulation2Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation2Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DSampleSFS::subpopulation2PopupChanged);\n        \n        mutationTypeButton_ = newButtonInLayout(button_layout);\n        connect(mutationTypeButton_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_2DSampleSFS::mutationTypePopupChanged);\n        \n        addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n        addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_);\n        addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    }\n}\n\nQtSLiMGraphView_2DSampleSFS::~QtSLiMGraphView_2DSampleSFS()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_2DSampleSFS::invalidateCachedData();\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::subpopulation1PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation1Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation1ID_ != newSubpopID))\n    {\n        selectedSubpopulation1ID_ = newSubpopID;\n        xAxisLabel_ = QString(\"Count in p%1 sample\").arg(selectedSubpopulation1ID_);\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::subpopulation2PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation2Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation2ID_ != newSubpopID))\n    {\n        selectedSubpopulation2ID_ = newSubpopID;\n        yAxisLabel_ = QString(\"Count in p%1 sample\").arg(selectedSubpopulation2ID_);\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::mutationTypePopupChanged(int /* index */)\n{\n    int newMutTypeIndex = mutationTypeButton_->currentData().toInt();\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedMutationTypeIndex_ != newMutTypeIndex))\n    {\n        selectedMutationTypeIndex_ = newMutTypeIndex;\n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t\tupdate();\n\t\n    // Remake our popups, whether or not the controller is valid\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_2DSampleSFS::graphTitle(void)\n{\n    return \"2D Sample SFS\";\n}\n\nQString QtSLiMGraphView_2DSampleSFS::aboutString(void)\n{\n    return \"The 2D Sample SFS graph shows a Site Frequency Spectrum (SFS) for a sample of haplosomes taken \"\n           \"(with replacement) from two given subpopulations, for mutations of a given mutation type.  The x and y axes \"\n           \"here are the occurrence counts of a given mutation within the two samples, from 0 to the sample size.  The \"\n           \"z axis, represented with color, is the number of mutations in the samples with those specific occurrence \"\n           \"counts; a count of zero is represented by white, and the chosen maximum count is represented by black, \"\n           \"with heat colors from yellow (low) through red and up to black (high).  The lower left bin is always blue, \"\n           \"representing the fact that mutations not present in either sample are not included in the graph, and thus \"\n           \"there is no count to depict for that bin.  The z axis maximum and the sample size can be customized from \"\n           \"the action menu.  The 2D Population SFS graph provides an alternative that might also be useful.\";\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::invalidateCachedData(void)\n{\n    if (sfs2dbuf_)\n    {\n        free(sfs2dbuf_);\n        sfs2dbuf_ = nullptr;\n    }\n    \n    QtSLiMGraphView::invalidateCachedData();\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::updateAfterTick(void)\n{\n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    addSubpopulationsToMenu(subpopulation2Button_, selectedSubpopulation2ID_, selectedSubpopulation1ID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n\t\n    invalidateCachedData();\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_2DSampleSFS::disableMessage(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (graphSpecies)\n    {\n        Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n        Subpopulation *subpop2 = graphSpecies->SubpopulationWithID(selectedSubpopulation2ID_);\n        MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n        \n        if (!subpop1 || !subpop2 || !muttype)\n            return \"no\\ndata\";\n    }\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::willDraw(QPainter &painter, QRect /* interiorRect */)\n{\n    QRect bounds = rect();\n    \n    if (!cachingNow_)\n    {\n        painter.setFont(QtSLiMGraphView::fontForTickLabels());\n        painter.setBrush(Qt::black);\n        \n        QString rangeString = QString(\"z ∈ [0, %1]\").arg((long)zAxisMax_);\n        QPoint drawPoint(bounds.x() + 10, bounds.y() + 10);\n        \n        drawPoint = painter.transform().map(drawPoint);\n        painter.setWorldMatrixEnabled(false);\n        painter.drawText(drawPoint, rangeString);\n        painter.setWorldMatrixEnabled(true);\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    uint64_t *sfs2dbuf = mutation2DSFS();\n    \n    if (sfs2dbuf)\n    {\n        // plot our histogram bars\n        double *sfsTransformed = (double *)calloc(histogramBinCount_ * histogramBinCount_, sizeof(double));\n        double logZMax = log10(zAxisMax_);\n        \n        for (int i = 1; i < histogramBinCount_ * histogramBinCount_; ++i)\n        {\n            uint64_t value = sfs2dbuf[i];\n            \n            sfsTransformed[i] = (value == 0) ? -1000 : (log10(value) / logZMax);\n        }\n        sfsTransformed[0] = -10000; // a special value that assigns a \"no value\" color to this square\n        \n        drawHeatmap(painter, interiorRect, sfsTransformed, histogramBinCount_, histogramBinCount_);\n        \n        free(sfsTransformed);\n    }\n}\n\nbool QtSLiMGraphView_2DSampleSFS::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::appendStringForData(QString &string)\n{\n\tuint64_t *plotData = mutation2DSFS();\n\t\n    for (int yc = 0; yc < histogramBinCount_; ++yc)\n    {\n        for (int xc = 0; xc < histogramBinCount_; ++xc)\n            string.append(QString(\"%1, \").arg(plotData[xc + yc * histogramBinCount_]));\n        string.append(\"\\n\");\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::changeZAxisScale(void)\n{\n    QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a z-axis maximum:\",\n                                                       QStringList{\"Maximum value:\"},\n                                                       QStringList{QString::number(zAxisMax_)});\n    \n    if (choices.length() == 1)\n    {\n        int newZMax = choices[0].toInt();\n        \n        if ((newZMax >= 10) && (newZMax <= 1000000))\n        {\n            zAxisMax_ = (double)newZMax;\n            \n            invalidateCachedData();\n            update();\n        }\n        else qApp->beep();\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::changeSampleSize(void)\n{\n    // Similar to \"Change Bin Count...\", just different branding\n    QStringList choices = QtSLiMRunLineEditArrayDialog(window(), \"Choose a sample size:\", QStringList(\"Sample size:\"), QStringList(QString::number(histogramBinCount_ - 1)));\n    \n    if (choices.length() == 1)\n    {\n        int newSampleSize = choices[0].toInt();\n        \n        if ((newSampleSize > 1) && (newSampleSize <= 500))\n        {\n            histogramBinCount_ = newSampleSize + 1;\n            xAxisMax_ = histogramBinCount_ - 1;\n            yAxisMax_ = histogramBinCount_ - 1;\n            original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n            original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n            x1_ = original_x1_;\n            y1_ = original_y1_;\n            invalidateCachedData();\n            update();\n        }\n        else qApp->beep();\n    }\n}\n\nvoid QtSLiMGraphView_2DSampleSFS::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(\"Change Z Axis Scale...\", this, &QtSLiMGraphView_2DSampleSFS::changeZAxisScale);\n    contextMenu.addAction(\"Change Sample Size...\", this, &QtSLiMGraphView_2DSampleSFS::changeSampleSize);\n}\n\nuint64_t *QtSLiMGraphView_2DSampleSFS::mutation2DSFS(void)\n{\n    if (!sfs2dbuf_)\n    {\n        Species *graphSpecies = focalDisplaySpecies();\n        Population &population = graphSpecies->population_;\n        int registry_size;\n        const MutationIndex *registry = population.MutationRegistry(&registry_size);\n        const MutationIndex *registry_iter_end = registry + registry_size;\n        Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n        \n        // Find our subpops and mutation type\n        Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n        Subpopulation *subpop2 = graphSpecies->SubpopulationWithID(selectedSubpopulation2ID_);\n        MutationType *muttype = graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_);\n        \n        if (!subpop1 || !subpop2 || !muttype)\n            return nullptr;\n        \n        // Get frequencies for a sample taken from subpop1\n        {\n            std::vector<Haplosome *> sample1Haplosomes;\n            std::vector<Individual *> &subpopIndividuals = subpop1->parent_individuals_;\n            size_t subpopHaplosomeCount = subpopIndividuals.size() * 2;\n            \n            if (subpopHaplosomeCount)\n                for (int i = 0; i < histogramBinCount_ - 1; ++i)\n                {\n                    slim_popsize_t haplosome_index = random() % subpopHaplosomeCount;\n                    slim_popsize_t individual_index = haplosome_index >> 1;\n                    Haplosome *haplosome = subpopIndividuals[individual_index]->haplosomes_[haplosome_index & 0x01];\n                    \n                    sample1Haplosomes.emplace_back(haplosome);\n                }\n            \n            tallyGUIMutationReferences(sample1Haplosomes, selectedMutationTypeIndex_);\n        }\n        \n        std::vector<slim_refcount_t> refcounts1;\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n        {\n            const Mutation *mutation = mut_block_ptr + *registry_iter;\n            if (mutation->mutation_type_ptr_->mutation_type_index_ == selectedMutationTypeIndex_)\n                refcounts1.emplace_back(mutation->gui_scratch_reference_count_);\n        }\n        \n        // Get frequencies for a sample taken from subpop2\n        {\n            std::vector<Haplosome *> sample2Haplosomes;\n            std::vector<Individual *> &subpopIndividuals = subpop2->parent_individuals_;\n            size_t subpopHaplosomeCount = subpopIndividuals.size() * 2;\n            \n            if (subpopHaplosomeCount)\n                for (int i = 0; i < histogramBinCount_ - 1; ++i)\n                {\n                    slim_popsize_t haplosome_index = random() % subpopHaplosomeCount;\n                    slim_popsize_t individual_index = haplosome_index >> 1;\n                    Haplosome *haplosome = subpopIndividuals[individual_index]->haplosomes_[haplosome_index & 0x01];\n                    \n                    sample2Haplosomes.emplace_back(haplosome);\n                }\n            \n            tallyGUIMutationReferences(sample2Haplosomes, selectedMutationTypeIndex_);\n        }\n        \n        std::vector<slim_refcount_t> refcounts2;\n        \n        for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n        {\n            const Mutation *mutation = mut_block_ptr + *registry_iter;\n            if (mutation->mutation_type_ptr_->mutation_type_index_ == selectedMutationTypeIndex_)\n                refcounts2.emplace_back(mutation->gui_scratch_reference_count_);\n        }\n        \n        // Tally up the binned 2D SFS from the 1D data\n        sfs2dbuf_ = (uint64_t *)calloc(histogramBinCount_ * histogramBinCount_, sizeof(uint64_t));\n        size_t refcounts_size = refcounts1.size();\n        \n        for (size_t refcount_index = 0; refcount_index < refcounts_size; ++refcount_index)\n        {\n            slim_refcount_t mutationRefCount1 = refcounts1[refcount_index];\n            slim_refcount_t mutationRefCount2 = refcounts2[refcount_index];\n            \n            if ((mutationRefCount1 > 0) || (mutationRefCount2 > 0))   // exclude mutations not present in either sample\n                sfs2dbuf_[mutationRefCount1 + mutationRefCount2 * histogramBinCount_]++;\n        }\n    }\n    \n    // Return the final tally; note that we retain ownership of this buffer and only free it when we want to force a recache\n    return sfs2dbuf_;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_2DSampleSFS.h",
    "content": "//\n//  QtSLiMGraphView_2DSampleSFS.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/18/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_2DSAMPLESFS_H\n#define QTSLIMGRAPHVIEW_2DSAMPLESFS_H\n\n#include \"QtSLiMGraphView.h\"\n\nclass MutationType;\n\n\nclass QtSLiMGraphView_2DSampleSFS : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_2DSampleSFS(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_2DSampleSFS() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void willDraw(QPainter &painter, QRect interiorRect) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void invalidateCachedData(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void subpopulation1PopupChanged(int index);\n    void subpopulation2PopupChanged(int index);\n    void mutationTypePopupChanged(int index);\n    void changeZAxisScale(void);\n    void changeSampleSize(void);\n    \nprivate:\n    // pop-up menu buttons\n    QComboBox *subpopulation1Button_ = nullptr;\n    QComboBox *subpopulation2Button_ = nullptr;\n\tQComboBox *mutationTypeButton_ = nullptr;\n    \n    // The subpop and mutation type selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulation1ID_;\n    slim_objectid_t selectedSubpopulation2ID_;\n    int selectedMutationTypeIndex_;\n    \n    double zAxisMax_ = 0.0;\n    \n    uint64_t *sfs2dbuf_ = nullptr;\n    uint64_t *mutation2DSFS(void);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_2DSAMPLESFS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_AgeDistribution.cpp",
    "content": "//\n//  QtSLiMGraphView_AgeDistribution.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_AgeDistribution.h\"\n\n#include <QComboBox>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QApplication>\n#include <QGuiApplication>\n#include <QDebug>\n\n#include <string>\n#include <algorithm>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n\n\nQtSLiMGraphView_AgeDistribution::QtSLiMGraphView_AgeDistribution(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 10;        // max age (no age 0 since we display after tick increment); this rescales automatically\n    allowBinCountRescale_ = false;\n    \n    original_x0_ = 0;\n    original_x1_ = histogramBinCount_;\n    \n    x0_ = original_x0_;\n    x1_ = original_x1_;\n    \n    xAxisMin_ = x0_;\n    xAxisMax_ = x1_;\n    xAxisHistogramStyle_ = true;\n    xAxisTickValuePrecision_ = 0;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    xAxisLabel_ = \"Age\";\n    yAxisLabel_ = \"Frequency\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = false;\n    \n    showHorizontalGridLines_ = true;\n    allowHorizontalGridChange_ = true;\n    allowVerticalGridChange_ = false;\n    allowFullBoxChange_ = true;\n    \n    selectedSubpopulation1ID_ = 1;\n}\n\nvoid QtSLiMGraphView_AgeDistribution::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulation1Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation1Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_AgeDistribution::subpopulation1PopupChanged);\n        \n        addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    }\n}\n\nQtSLiMGraphView_AgeDistribution::~QtSLiMGraphView_AgeDistribution()\n{\n}\n\nvoid QtSLiMGraphView_AgeDistribution::subpopulation1PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation1Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation1ID_ != newSubpopID))\n    {\n        selectedSubpopulation1ID_ = newSubpopID;\n        \n        // Reset our autoscaling x axis\n        histogramBinCount_ = 10;\n        xAxisMax_ = histogramBinCount_;\n        original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n        x1_ = original_x1_;\n        \n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_AgeDistribution::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t\tupdate();\n    \n    // Remake our popups, whether or not the controller is valid\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    \n    // Reset our autoscaling x axis\n    histogramBinCount_ = 10;\n    xAxisMax_ = histogramBinCount_;\n    original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n    x1_ = original_x1_;\n    \n    // Reset our autoscaling y axis\n    yAxisMax_ = 1.0;\n    original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n    y1_ = original_y1_;\n    yAxisMajorTickInterval_ = 0.5;\n    yAxisMinorTickInterval_ = 0.25;\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_AgeDistribution::graphTitle(void)\n{\n    return \"Age Distribution\";\n}\n\nQString QtSLiMGraphView_AgeDistribution::aboutString(void)\n{\n    return \"The Age Distribution graph shows the distribution of age values within a chosen subpopulation.  The \"\n           \"x axis is individual age (in cycles, in the SLiM sense of the term); the y axis is the frequency \"\n           \"of a given age in the population, normalized to a total of 1.0.  This graph is only meaningful \"\n           \"for nonWF models; WF models have non-overlapping generations without age structure.  Note that \"\n           \"display occurs <i>after</i> the cycle counter increments, so new offspring will have age 1.\";\n}\n\nvoid QtSLiMGraphView_AgeDistribution::updateAfterTick(void)\n{\n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n\t\n    invalidateCachedData();\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_AgeDistribution::disableMessage(void)\n{\n    if (controller_ && !controller_->invalidSimulation())\n    {\n        if (controller_->community->ModelType() == SLiMModelType::kModelTypeWF)\n            return \"requires a\\nnonWF model\";\n        \n        Species *graphSpecies = focalDisplaySpecies();\n        \n        if (graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_) == nullptr)\n            return \"no\\ndata\";\n    }\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_AgeDistribution::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n\tdouble *ageDist = ageDistribution(&binCount, tallySexesSeparately);\n    int totalBinCount = tallySexesSeparately ? (binCount * 2) : binCount;\n\t\n    if (ageDist)\n    {\n        // rescale the x axis if needed\n        if (binCount != histogramBinCount_)\n        {\n            histogramBinCount_ = binCount;\n            xAxisMax_ = histogramBinCount_;\n            original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n            x1_ = original_x1_;\n            invalidateCachedData();\n        }\n        \n        // rescale the y axis if needed\n        double maxFreq = 0.000000001;   // guarantee a non-zero axis range\n        \n        for (int binIndex = 0; binIndex < totalBinCount; ++binIndex)\n            maxFreq = std::max(maxFreq, ageDist[binIndex]);\n        \n        double ceilingFreq = std::ceil(maxFreq * 5.0) / 5.0;    // 0.2 / 0.4 / 0.6 / 0.8 / 1.0\n        \n        if ((ceilingFreq > yAxisMax_) ||\n                ((ceilingFreq < yAxisMax_) && (maxFreq + 0.05 < ceilingFreq)))    // require a margin of error to jump down\n        {\n            yAxisMax_ = ceilingFreq;\n            original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n            y1_ = original_y1_;\n            yAxisMajorTickInterval_ = ceilingFreq / 2.0;\n            yAxisMinorTickInterval_ = ceilingFreq / 4.0;\n        }\n        \n        // plot our histogram bars\n        if (tallySexesSeparately)\n            drawGroupedBarplot(painter, interiorRect, ageDist, 2, histogramBinCount_, 0.0, 1.0);\n        else\n            drawBarplot(painter, interiorRect, ageDist, histogramBinCount_, 0.0, 1.0);\n        \n        free(ageDist);\n    }\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_AgeDistribution::legendKey(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n    \n\tif (tallySexesSeparately)\n    {\n        QtSLiMLegendSpec legend_key;\n        \n        legend_key.emplace_back(\"M\", controller_->blackContrastingColorForIndex(0));\n        legend_key.emplace_back(\"F\", controller_->blackContrastingColorForIndex(1));\n        \n        return legend_key;\n    }\n    else\n    {\n        return QtSLiMLegendSpec();\n    }\n}\n\nbool QtSLiMGraphView_AgeDistribution::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_AgeDistribution::appendStringForData(QString &string)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n\tdouble *ageDist = ageDistribution(&binCount, tallySexesSeparately);\n\t\n    if (ageDist)\n    {\n        if (tallySexesSeparately)\n        {\n            string.append(\"M : \");\n            \n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(ageDist[i * 2], 0, 'f', 4));\n            \n            string.append(\"\\n\\nF : \");\n            \n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(ageDist[i * 2 + 1], 0, 'f', 4));\n        }\n        else\n        {\n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(ageDist[i], 0, 'f', 4));\n        }\n        \n        free(ageDist);\n    }\n    \n    string.append(\"\\n\");\n}\n\ndouble *QtSLiMGraphView_AgeDistribution::ageDistribution(int *binCount, bool tallySexesSeparately)\n{\n    // Find our subpop\n    Species *graphSpecies = focalDisplaySpecies();\n    Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n    \n    if (!subpop1)\n        return nullptr;\n    \n    // Find the maximum age and choose the new bin count\n    slim_age_t maxAge = 1;\n    \n    for (const Individual *individual : subpop1->parent_individuals_)\n        maxAge = std::max(maxAge, individual->age_);\n    \n    // compare to the logic in QtSLiMGraphView_LifetimeReproduction::reproductionDistribution();\n    // it is different here because we subtract 1 from every age in the tallying code below,\n    // there is no bin for age==0, and age==1 goes into bin #0; confusing!\n    if (maxAge > *binCount)\n        *binCount = (slim_age_t)(std::ceil(maxAge / 10.0) * 10.0);\n    \n    int newBinCount = *binCount;\n    \n    // Tally into our bins\n    int totalBinCount = (tallySexesSeparately ? newBinCount * 2 : newBinCount);\n    double *ageTallies = static_cast<double *>(calloc(totalBinCount, sizeof(double)));\n    \n    for (const Individual *individual : subpop1->parent_individuals_)\n    {\n        slim_age_t age = individual->age_ - 1;  // age 1 is bin 0, age binCount is bin binCount-1\n        \n        if (age < 0) age = 0;\n        if (age >= newBinCount) age = newBinCount - 1;\n        \n        if (tallySexesSeparately)\n        {\n            if (individual->sex_ == IndividualSex::kFemale)\n                ageTallies[age * 2 + 1]++;\n            else\n                ageTallies[age * 2]++;\n        }\n        else\n        {\n            ageTallies[age]++;\n        }\n    }\n    \n    // Normalize to 1\n    \n    if (tallySexesSeparately)\n    {\n        // males\n        double totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += ageTallies[i * 2];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                ageTallies[i * 2] /= totalTallies;\n        \n        // females\n        totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += ageTallies[i * 2 + 1];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                ageTallies[i * 2 + 1] /= totalTallies;\n    }\n    else\n    {\n        double totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += ageTallies[i];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                ageTallies[i] /= totalTallies;\n    }\n    \n    // Return the final tally; note that the caller takes ownership of the buffer\n\treturn ageTallies;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_AgeDistribution.h",
    "content": "//\n//  QtSLiMGraphView_AgeDistribution.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_AGEDISTRIBUTION_H\n#define QTSLIMGRAPHVIEW_AGEDISTRIBUTION_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_AgeDistribution : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_AgeDistribution(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_AgeDistribution() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void subpopulation1PopupChanged(int index);\n    \nprivate:\n    // pop-up menu buttons\n    QComboBox *subpopulation1Button_ = nullptr;\n    \n    // The subpop selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulation1ID_;\n    \n    double *ageDistribution(int *binCount, bool tallySexesSeparately);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_AGEDISTRIBUTION_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_CustomPlot.cpp",
    "content": "//\n//  QtSLiMGraphView_CustomPlot.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 1/19/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_CustomPlot.h\"\n\n#include <QPainterPath>\n#include <QPainter>\n#include <QFont>\n#include <QFontMetrics>\n#include <QDebug>\n\n#include \"QtSLiM_Plot.h\"\n\n#include <limits>\n#include <algorithm>\n#include <vector>\n\n\nQtSLiMGraphView_CustomPlot::QtSLiMGraphView_CustomPlot(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    title_ = \"Custom Plot\";     // will be replaced\n    xAxisLabel_ = \"x\";\n    yAxisLabel_ = \"y\";\n    \n    // user-rescaling of the axes should work fine, but will switch to the \"base plot\" way of handling\n    // the data range and the axis ticks, so some functionality will be disabled, such as auto-resizing\n    // the data range and axes to fit newly added data; so it goes\n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    setFocalDisplaySpecies(nullptr);\n    \n    QtSLiMGraphView_CustomPlot::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_CustomPlot::freeData(void)\n{\n    // discard all plot data\n    for (double *x1buffer : x1data_)\n        free(x1buffer);\n    \n    for (double *y1buffer : y1data_)\n        free(y1buffer);\n    \n    for (double *x2buffer : x2data_)\n        free(x2buffer);\n    \n    for (double *y2buffer : y2data_)\n        free(y2buffer);\n    \n    for (std::vector<QString> *labelsbuffer : labels_)\n        delete labelsbuffer;\n    \n    for (std::vector<int> *symbolbuffer : symbol_)\n        delete symbolbuffer;\n    \n    for (std::vector<QColor> *colorbuffer : color_)\n        delete colorbuffer;\n    \n    for (std::vector<QColor> *borderbuffer : border_)\n        delete borderbuffer;\n    \n    for (std::vector<double> *alphabuffer : alpha_)\n        delete alphabuffer;\n    \n    for (std::vector<double> *lwdbuffer : line_width_)\n        delete lwdbuffer;\n    \n    for (std::vector<double> *sizebuffer : size_)\n        delete sizebuffer;\n    \n    for (std::vector<double> *anglebuffer : angle_)\n        delete anglebuffer;\n    \n    plot_type_.clear();\n    x1data_.clear();\n    y1data_.clear();\n    x2data_.clear();\n    y2data_.clear();\n    data_count_.clear();\n    labels_.clear();\n    symbol_.clear();\n    color_.clear();\n    border_.clear();\n    alpha_.clear();\n    line_width_.clear();\n    size_.clear();\n    angle_.clear();\n    xadj_.clear();\n    yadj_.clear();\n    image_.clear();\n    \n    // reset the legend state\n    legend_added_ = false;\n    \n    legend_position_ = QtSLiM_LegendPosition::kUnconfigured;\n    legend_inset = -1;\n    legend_labelSize = -1;\n    legend_lineHeight = -1;\n    legend_graphicsWidth = -1;\n    legend_exteriorMargin = -1;\n    legend_interiorMargin = -1;\n    \n    legend_entries_.clear();\n}\n\nQtSLiMGraphView_CustomPlot::~QtSLiMGraphView_CustomPlot()\n{\n    // We are responsible for our own destruction\n    \n    // We own our corresponding Eidos object of class Plot, and free it here.  It is not under retain/release,\n    // and this should occur only at a \"long-term boundary\" since it is triggered by the plot window closing\n    // in SLiMgui.  Note that sometimes eidos_plot_object_ is nullptr, such as when the custom plot was created\n    // in SLiMgui's UI from LogFile data; this is fine, it just means the window is not controllable from script.\n    if (eidos_plot_object_)\n    {\n        delete eidos_plot_object_;\n        eidos_plot_object_ = nullptr;\n    }\n    \n    freeData();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setTitle(QString title)\n{\n    title_ = title;\n    \n    QWidget *graphWindow = window();\n    \n    if (graphWindow)\n        graphWindow->setWindowTitle(title);\n}\n\nvoid QtSLiMGraphView_CustomPlot::setXLabel(QString x_label)\n{\n    xAxisLabel_ = x_label;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setYLabel(QString y_label)\n{\n    yAxisLabel_ = y_label;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setShowHorizontalGrid(bool showHorizontalGrid)\n{\n    showHorizontalGridLines_ = showHorizontalGrid;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setShowVerticalGrid(bool showVerticalGrid)\n{\n    showVerticalGridLines_ = showVerticalGrid;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setShowFullBox(bool showFullBox)\n{\n    showFullBox_ = showFullBox;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setAxisLabelSize(double axisLabelSize)\n{\n    axisLabelSize_ = axisLabelSize;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setTickLabelSize(double tickLabelSize)\n{\n    tickLabelSize_ = tickLabelSize;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setLegendPosition(QtSLiM_LegendPosition position)\n{\n    legend_position_ = position;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::setDataRanges(double *x_range, double *y_range)\n{\n    // this is called by QtSLiMWindow::eidos_createPlot(), to set up for the user's specified ranges\n    // nullptr for an axis indicates that we want that axis to be controlled by the range of the data\n    // otherwise, we set up the min and max values for the axis from the given (two-valued) range buffer\n    if (x_range)\n    {\n        original_x0_ = x_range[0];\n        original_x1_ = x_range[1];\n        \n        x0_ = original_x0_;\n        x1_ = original_x1_;\n        \n        configureAxisForRange(x0_, x1_, xAxisMin_, xAxisMax_,\n                              xAxisMajorTickInterval_, xAxisMinorTickInterval_,\n                              xAxisMajorTickModulus_, xAxisTickValuePrecision_);\n        xAxisIsUserRescaled_ = true;\n        xAxisIsUIRescaled_ = false;\n    }\n    else\n    {\n        // allow any user configuration in the UI to persist through a recycle\n        // if a range was set by createPlot(), though, we want to reset that\n        if (!xAxisIsUIRescaled_)\n            xAxisIsUserRescaled_ = false;\n    }\n    \n    if (y_range)\n    {\n        original_y0_ = y_range[0];\n        original_y1_ = y_range[1];\n        \n        y0_ = original_y0_;\n        y1_ = original_y1_;\n        \n        configureAxisForRange(y0_, y1_, yAxisMin_, yAxisMax_,\n                              yAxisMajorTickInterval_, yAxisMinorTickInterval_,\n                              yAxisMajorTickModulus_, yAxisTickValuePrecision_);\n        yAxisIsUserRescaled_ = true;\n        yAxisIsUIRescaled_ = false;\n    }\n    else\n    {\n        // allow any user configuration in the UI to persist through a recycle\n        // if a range was set by createPlot(), though, we want to reset that\n        if (!yAxisIsUIRescaled_)\n            yAxisIsUserRescaled_ = false;\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::setAxisConfiguration(int side, std::vector<double> *at, int labels_type, std::vector<QString> *labels)\n{\n    // This method is called by the Eidos method Plot::axis() to customize axis display.\n    // Note that Plot::ExecuteMethod_axis() does a bunch of bounds-checking and such for us.\n    if (side == 1)\n    {\n        // x-axis configuration\n        if (xAxisAt_)\n        {\n            delete xAxisAt_;\n            xAxisAt_ = nullptr;\n        }\n        if (xAxisLabels_)\n        {\n            delete xAxisLabels_;\n            xAxisLabels_ = nullptr;\n        }\n        \n        if (at)\n        {\n            xAxisAt_ = at;\n            allowXAxisUserRescale_ = false;\n        }\n        else\n        {\n            allowXAxisUserRescale_ = true;\n        }\n        \n        xAxisLabelsType_ = labels_type;\n        xAxisLabels_ = labels;\n    }\n    else if (side == 2)\n    {\n        // y-axis configuration\n        if (yAxisAt_)\n        {\n            delete yAxisAt_;\n            yAxisAt_ = nullptr;\n        }\n        if (yAxisLabels_)\n        {\n            delete yAxisLabels_;\n            yAxisLabels_ = nullptr;\n        }\n        \n        if (at)\n        {\n            yAxisAt_ = at;\n            allowYAxisUserRescale_ = false;\n        }\n        else\n        {\n            allowYAxisUserRescale_ = true;\n        }\n        \n        yAxisLabelsType_ = labels_type;\n        yAxisLabels_ = labels;\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::dataRange(std::vector<double *> &data_vector, double *p_min, double *p_max)\n{\n    // This method accumulates the min/max for the range of our data, in either x or y\n    // It excludes NAN and INF values from the range; such values are not plotted\n    double min = std::numeric_limits<double>::infinity();\n    double max = -std::numeric_limits<double>::infinity();\n    \n    for (int data_index = 0; data_index < (int)data_vector.size(); ++data_index)\n    {\n        // lines from abline() are not included in the data range; they are decoration\n        if ((plot_type_[data_index] == QtSLiM_CustomPlotType::kABLines) ||\n            (plot_type_[data_index] == QtSLiM_CustomPlotType::kHLines) ||\n            (plot_type_[data_index] == QtSLiM_CustomPlotType::kVLines))\n            continue;\n        \n        double *point_data = data_vector[data_index];\n        \n        if (point_data)\n        {\n            int point_count = data_count_[data_index];\n            \n            for (int point_index = 0; point_index < point_count; ++point_index)\n            {\n                double point_value = point_data[point_index];\n                \n                if (std::isfinite(point_value))\n                {\n                    min = std::min(min, point_value);\n                    max = std::max(max, point_value);\n                }\n            }\n        }\n    }\n    \n    *p_min = min;\n    *p_max = max;\n}\n\nvoid QtSLiMGraphView_CustomPlot::rescaleAxesForDataRange(void)\n{\n    // this is called when new data is added to a plot, to rescale the axes as needed\n    // set up axes based on the data range; we try to apply a little intelligence, but if the user\n    // wants really intelligent axis ranges, they can set them up themselves...\n    double x1min, x1max, y1min, y1max, x2min, x2max, y2min, y2max;\n    \n    dataRange(x1data_, &x1min, &x1max);\n    dataRange(y1data_, &y1min, &y1max);\n    dataRange(x2data_, &x2min, &x2max);\n    dataRange(y2data_, &y2min, &y2max);\n    \n    double xmin = std::min(x1min, x2min);\n    double xmax = std::max(x1max, x2max);\n    double ymin = std::min(y1min, y2min);\n    double ymax = std::max(y1max, y2max);\n    \n    //std::cout << \"-----\" << std::endl;\n    //std::cout << \"   xmin == \" << xmin << \", x1min == \" << x1min << \", x2min << \" << x2min << std::endl;\n    //std::cout << \"   xmax == \" << xmax << \", x1max == \" << x1max << \", x2max << \" << x2max << std::endl;\n    //std::cout << \"   ymin == \" << ymin << \", y1min == \" << y1min << \", y2min << \" << y2min << std::endl;\n    //std::cout << \"   ymax == \" << ymax << \", y1max == \" << y1max << \", y2max << \" << y2max << std::endl;\n    \n    has_finite_data_ = false;\n    \n    if (std::isfinite(xmin) && std::isfinite(xmax) && std::isfinite(ymin) && std::isfinite(ymax))\n    {\n        if (!xAxisIsUserRescaled_)\n        {\n            original_x0_ = xmin;\n            original_x1_ = xmax;\n            \n            x0_ = original_x0_;\n            x1_ = original_x1_;\n            \n            configureAxisForRange(x0_, x1_, xAxisMin_, xAxisMax_, xAxisMajorTickInterval_, xAxisMinorTickInterval_,\n                                  xAxisMajorTickModulus_, xAxisTickValuePrecision_);\n        }\n        \n        if (!yAxisIsUserRescaled_)\n        {\n            original_y0_ = ymin;\n            original_y1_ = ymax;\n            \n            y0_ = original_y0_;\n            y1_ = original_y1_;\n            \n            configureAxisForRange(y0_, y1_, yAxisMin_, yAxisMax_, yAxisMajorTickInterval_, yAxisMinorTickInterval_,\n                                  yAxisMajorTickModulus_, yAxisTickValuePrecision_);\n        }\n        \n        has_finite_data_ = true;\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::addABLineData(double *a_values, double *b_values,\n                                               double *h_values, double *v_values, int data_count,\n                                               std::vector<QColor> *color, std::vector<double> *alpha,\n                                               std::vector<double> *lwd)\n{\n    if (a_values)\n    {\n        plot_type_.push_back(QtSLiM_CustomPlotType::kABLines);\n        x1data_.push_back(a_values);\n        y1data_.push_back(b_values);\n    }\n    else if (h_values)\n    {\n        plot_type_.push_back(QtSLiM_CustomPlotType::kHLines);\n        x1data_.push_back(h_values);\n        y1data_.push_back(nullptr);\n    }\n    else if (v_values)\n    {\n        plot_type_.push_back(QtSLiM_CustomPlotType::kVLines);\n        x1data_.push_back(v_values);\n        y1data_.push_back(nullptr);\n    }\n    \n    x2data_.push_back(nullptr);             // unused for abline\n    y2data_.push_back(nullptr);             // unused for abline\n    labels_.push_back(nullptr);             // unused for abline\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for abline\n    color_.push_back(color);\n    border_.push_back(nullptr);             // unused for abline\n    alpha_.push_back(alpha);\n    line_width_.push_back(lwd);\n    size_.push_back(nullptr);               // unused for abline\n    angle_.push_back(nullptr);              // unused for abline\n    xadj_.push_back(-1);                    // unused for abline\n    yadj_.push_back(-1);                    // unused for abline\n    image_.push_back(QImage());             // unused for abline\n    \n    //rescaleAxesForDataRange();            // not needed for abline\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLineData(double *x_values, double *y_values, int data_count,\n                                             std::vector<QColor> *color, std::vector<double> *alpha,\n                                             std::vector<double> *lwd)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kLines);\n    x1data_.push_back(x_values);\n    y1data_.push_back(y_values);\n    x2data_.push_back(nullptr);             // unused for lines\n    y2data_.push_back(nullptr);             // unused for lines\n    labels_.push_back(nullptr);             // unused for lines\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for lines\n    color_.push_back(color);\n    border_.push_back(nullptr);             // unused for lines\n    alpha_.push_back(alpha);\n    line_width_.push_back(lwd);\n    size_.push_back(nullptr);               // unused for lines\n    angle_.push_back(nullptr);              // unused for lines\n    xadj_.push_back(-1);                    // unused for lines\n    yadj_.push_back(-1);                    // unused for lines\n    image_.push_back(QImage());             // unused for lines\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addRectData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,\n                                             int data_count, std::vector<QColor> *color, std::vector<QColor> *border,\n                                             std::vector<double> *alpha, std::vector<double> *lwd)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kRects);\n    x1data_.push_back(x1_values);\n    y1data_.push_back(y1_values);\n    x2data_.push_back(x2_values);\n    y2data_.push_back(y2_values);\n    labels_.push_back(nullptr);             // unused for rects\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for rects\n    color_.push_back(color);\n    border_.push_back(border);\n    alpha_.push_back(alpha);\n    line_width_.push_back(lwd);\n    size_.push_back(nullptr);               // unused for rects\n    angle_.push_back(nullptr);              // unused for rects\n    xadj_.push_back(-1);                    // unused for rects\n    yadj_.push_back(-1);                    // unused for rects\n    image_.push_back(QImage());             // unused for rects\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addSegmentData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,\n                                                int data_count, std::vector<QColor> *color,\n                                                std::vector<double> *alpha, std::vector<double> *lwd)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kSegments);\n    x1data_.push_back(x1_values);\n    y1data_.push_back(y1_values);\n    x2data_.push_back(x2_values);\n    y2data_.push_back(y2_values);\n    labels_.push_back(nullptr);             // unused for segments\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for segments\n    color_.push_back(color);\n    border_.push_back(nullptr);             // unused for segments\n    alpha_.push_back(alpha);\n    line_width_.push_back(lwd);\n    size_.push_back(nullptr);               // unused for segments\n    angle_.push_back(nullptr);              // unused for segments\n    xadj_.push_back(-1);                    // unused for segments\n    yadj_.push_back(-1);                    // unused for segments\n    image_.push_back(QImage());             // unused for segments\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addMarginTextData(double *x_values, double *y_values, std::vector<QString> *labels, int data_count,\n                                                   std::vector<QColor> *color, std::vector<double> *alpha,\n                                                   std::vector<double> *size, double *adj, std::vector<double> *angle)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kMarginText);\n    x1data_.push_back(x_values);\n    y1data_.push_back(y_values);\n    x2data_.push_back(nullptr);             // unused for text\n    y2data_.push_back(nullptr);             // unused for text\n    labels_.push_back(labels);\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for text\n    color_.push_back(color);\n    border_.push_back(nullptr);             // unused for text\n    alpha_.push_back(alpha);\n    line_width_.push_back(nullptr);         // unused for text\n    size_.push_back(size);\n    angle_.push_back(angle);                // unused for text\n    xadj_.push_back(adj[0]);\n    yadj_.push_back(adj[1]);\n    image_.push_back(QImage());             // unused for text\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addPointData(double *x_values, double *y_values, int data_count,\n                                              std::vector<int> *symbol, std::vector<QColor> *color, std::vector<QColor> *border,\n                                              std::vector<double> *alpha, std::vector<double> *lwd, std::vector<double> *size)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kPoints);\n    x1data_.push_back(x_values);\n    y1data_.push_back(y_values);\n    x2data_.push_back(nullptr);             // unused for points\n    y2data_.push_back(nullptr);             // unused for points\n    labels_.push_back(nullptr);             // unused for points\n    data_count_.push_back(data_count);\n    symbol_.push_back(symbol);\n    color_.push_back(color);\n    border_.push_back(border);\n    alpha_.push_back(alpha);\n    line_width_.push_back(lwd);\n    size_.push_back(size);\n    angle_.push_back(nullptr);              // unused for points\n    xadj_.push_back(-1);                    // unused for points\n    yadj_.push_back(-1);                    // unused for points\n    image_.push_back(QImage());             // unused for points\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addTextData(double *x_values, double *y_values, std::vector<QString> *labels, int data_count,\n                                             std::vector<QColor> *color, std::vector<double> *alpha,\n                                             std::vector<double> *size, double *adj, std::vector<double> *angle)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kText);\n    x1data_.push_back(x_values);\n    y1data_.push_back(y_values);\n    x2data_.push_back(nullptr);             // unused for text\n    y2data_.push_back(nullptr);             // unused for text\n    labels_.push_back(labels);\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for text\n    color_.push_back(color);\n    border_.push_back(nullptr);             // unused for text\n    alpha_.push_back(alpha);\n    line_width_.push_back(nullptr);         // unused for text\n    size_.push_back(size);\n    angle_.push_back(angle);                // unused for text\n    xadj_.push_back(adj[0]);\n    yadj_.push_back(adj[1]);\n    image_.push_back(QImage());             // unused for text\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addImageData(double *x_values, double *y_values, int data_count,\n                  QImage image, std::vector<double> *alpha)\n{\n    plot_type_.push_back(QtSLiM_CustomPlotType::kImage);\n    x1data_.push_back(x_values);\n    y1data_.push_back(y_values);\n    x2data_.push_back(nullptr);             // unused for image\n    y2data_.push_back(nullptr);             // unused for image\n    labels_.push_back(nullptr);             // unused for image\n    data_count_.push_back(data_count);\n    symbol_.push_back(nullptr);             // unused for image\n    color_.push_back(nullptr);              // unused for image\n    border_.push_back(nullptr);             // unused for image\n    alpha_.push_back(alpha);\n    line_width_.push_back(nullptr);         // unused for image\n    size_.push_back(nullptr);               // unused for image\n    angle_.push_back(nullptr);              // unused for image\n    xadj_.push_back(-1);                    // unused for image\n    yadj_.push_back(-1);                    // unused for image\n    image_.push_back(image);\n    \n    rescaleAxesForDataRange();\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLegend(QtSLiM_LegendPosition position, int inset, double labelSize, double lineHeight,\n                                           double graphicsWidth, double exteriorMargin, double interiorMargin)\n{\n    legend_added_ = true;\n    \n    legend_position_ = position;\n    legend_inset = inset;\n    legend_labelSize = labelSize;\n    legend_lineHeight = lineHeight;\n    legend_graphicsWidth = graphicsWidth;\n    legend_exteriorMargin = exteriorMargin;\n    legend_interiorMargin = interiorMargin;\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLegendLineEntry(QString label, QColor color, double lwd)\n{\n    legend_entries_.emplace_back(label, lwd, color);\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLegendPointEntry(QString label, int symbol, QColor color, QColor border, double lwd, double size)\n{\n    legend_entries_.emplace_back(label, symbol, color, border, lwd, size);\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLegendSwatchEntry(QString label, QColor color)\n{\n    legend_entries_.emplace_back(label, color);\n    update();\n}\n\nvoid QtSLiMGraphView_CustomPlot::addLegendTitleEntry(QString label)\n{\n    legend_entries_.emplace_back(label);\n    update();\n}\n\nQString QtSLiMGraphView_CustomPlot::graphTitle(void)\n{\n    return title_;\n}\n\nQString QtSLiMGraphView_CustomPlot::aboutString(void)\n{\n    return \"The Custom Plot graph type displays user-provided data that is supplied \"\n           \"in script with createPlot() and subsequent calls.\";\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    for (int i = 0; i < (int)plot_type_.size(); ++i)\n    {\n        QtSLiM_CustomPlotType plot_type = plot_type_[i];\n        \n        switch (plot_type)\n        {\n        case QtSLiM_CustomPlotType::kLines:\n            drawLines(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kSegments:\n            drawSegments(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kRects:\n            drawRects(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kMarginText:\n            drawMarginText(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kPoints:\n            drawPoints(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kText:\n            drawText(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kABLines:\n            drawABLines(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kHLines:\n            drawHLines(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kVLines:\n            drawVLines(painter, interiorRect, i);\n            break;\n        case QtSLiM_CustomPlotType::kImage:\n            drawImage(painter, interiorRect, i);\n            break;\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::appendStringForData(QString & /* string */)\n{\n    // No data string\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_CustomPlot::legendKey(void)\n{\n    return legend_entries_;\n}\n\nvoid QtSLiMGraphView_CustomPlot::controllerRecycled(void)\n{\n    freeData();\n    update();\n    \n    QtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_CustomPlot::disableMessage(void)\n{\n    if ((plot_type_.size() == 0) || !has_finite_data_)\n        return \"no\\ndata\";\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawABLines(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *adata = x1data_[dataIndex];\n    double *bdata = y1data_[dataIndex];\n    int lineCount = data_count_[dataIndex];\n    std::vector<QColor> &lineColors = *color_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineAlphas = *alpha_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineWidths = *line_width_[dataIndex];      // might be one value or N values\n    \n    for (int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n    {\n        QPainterPath linePath;\n        double user_a = adata[lineIndex];\n        double user_b = bdata[lineIndex];\n        \n        if (std::isfinite(user_a) && std::isfinite(user_b))\n        {\n            // slope-intercept: y = a + bx\n            double user_x1 = x0_ - 100000.0;\n            double user_x2 = x1_ + 100000.0;\n            double user_y1 = user_a + user_b * user_x1;\n            double user_y2 = user_a + user_b * user_x2;\n            QPointF devicePoint1(plotToDeviceX(user_x1, interiorRect), plotToDeviceY(user_y1, interiorRect));\n            QPointF devicePoint2(plotToDeviceX(user_x2, interiorRect), plotToDeviceY(user_y2, interiorRect));\n            QColor lineColor = lineColors[lineIndex % lineColors.size()];\n            double lineAlpha = lineAlphas[lineIndex % lineAlphas.size()];\n            double lineWidth = lineWidths[lineIndex % lineWidths.size()];\n            \n            linePath.moveTo(devicePoint1);\n            linePath.lineTo(devicePoint2);\n            \n            if (lineAlpha != 1.0)\n                lineColor.setAlphaF(lineAlpha);\n            \n            painter.strokePath(linePath, QPen(lineColor, lineWidth));\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawHLines(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *hdata = x1data_[dataIndex];\n    int lineCount = data_count_[dataIndex];\n    std::vector<QColor> &lineColors = *color_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineAlphas = *alpha_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineWidths = *line_width_[dataIndex];      // might be one value or N values\n    \n    for (int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n    {\n        QPainterPath linePath;\n        double user_h = hdata[lineIndex];\n        \n        if (std::isfinite(user_h))\n        {\n            // round the y-coordinate for display to make the line look nicer, especially for lwd 1.0\n            QPointF devicePoint1(plotToDeviceX(x0_ - 100000.0, interiorRect), roundPlotToDeviceY(user_h, interiorRect));\n            QPointF devicePoint2(plotToDeviceX(x1_ + 100000.0, interiorRect), roundPlotToDeviceY(user_h, interiorRect));\n            QColor lineColor = lineColors[lineIndex % lineColors.size()];\n            double lineAlpha = lineAlphas[lineIndex % lineAlphas.size()];\n            double lineWidth = lineWidths[lineIndex % lineWidths.size()];\n            \n            linePath.moveTo(devicePoint1);\n            linePath.lineTo(devicePoint2);\n            \n            if (lineAlpha != 1.0)\n                lineColor.setAlphaF(lineAlpha);\n            \n            painter.strokePath(linePath, QPen(lineColor, lineWidth));\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawVLines(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *vdata = x1data_[dataIndex];\n    int lineCount = data_count_[dataIndex];\n    std::vector<QColor> &lineColors = *color_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineAlphas = *alpha_[dataIndex];           // might be one value or N values\n    std::vector<double> &lineWidths = *line_width_[dataIndex];      // might be one value or N values\n    \n    for (int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n    {\n        QPainterPath linePath;\n        double user_v = vdata[lineIndex];\n        \n        if (std::isfinite(user_v))\n        {\n            // round the x-coordinate for display to make the line look nicer, especially for lwd 1.0\n            QPointF devicePoint1(roundPlotToDeviceX(user_v, interiorRect), plotToDeviceY(y0_ - 100000.0, interiorRect));\n            QPointF devicePoint2(roundPlotToDeviceX(user_v, interiorRect), plotToDeviceY(y1_ + 100000.0, interiorRect));\n            QColor lineColor = lineColors[lineIndex % lineColors.size()];\n            double lineAlpha = lineAlphas[lineIndex % lineAlphas.size()];\n            double lineWidth = lineWidths[lineIndex % lineWidths.size()];\n            \n            linePath.moveTo(devicePoint1);\n            linePath.lineTo(devicePoint2);\n            \n            if (lineAlpha != 1.0)\n                lineColor.setAlphaF(lineAlpha);\n            \n            painter.strokePath(linePath, QPen(lineColor, lineWidth));\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawLines(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *xdata = x1data_[dataIndex];\n    double *ydata = y1data_[dataIndex];\n    int vertexCount = data_count_[dataIndex];\n    QColor lineColor = (*color_[dataIndex])[0];                 // guaranteed to be only one value, for lines()\n    double lineAlpha = (*alpha_[dataIndex])[0];                 // guaranteed to be only one value, for lines()\n    double lineWidth = (*line_width_[dataIndex])[0];            // guaranteed to be only one value, for lines()\n    \n    if (lineAlpha != 1.0)\n    {\n        // This strokes each line segment as a separate path, so that when successive line segments cross, the alpha\n        // value affects their area of overlap.  This is arguably more likely to be what the user expects.  However,\n        // it doesn't draw the line joins nicely, with bevels and such, so the line path as a whole might less pretty.\n        // We therefore use this drawing method only when alpha is not 1.0.\n        lineColor.setAlphaF(lineAlpha);\n        \n        for (int vertexIndex = 0; vertexIndex < vertexCount - 1; ++vertexIndex)\n        {\n            QPainterPath linePath;\n            double user_x1 = xdata[vertexIndex];\n            double user_y1 = ydata[vertexIndex];\n            double user_x2 = xdata[vertexIndex + 1];\n            double user_y2 = ydata[vertexIndex + 1];\n            \n            if (!std::isnan(user_x1) && !std::isnan(user_y1) && !std::isnan(user_x2) && !std::isnan(user_y2))\n            {\n                QPointF devicePoint1(plotToDeviceX(user_x1, interiorRect), plotToDeviceY(user_y1, interiorRect));\n                QPointF devicePoint2(plotToDeviceX(user_x2, interiorRect), plotToDeviceY(user_y2, interiorRect));\n                \n                linePath.moveTo(devicePoint1);\n                linePath.lineTo(devicePoint2);\n                painter.strokePath(linePath, QPen(lineColor, lineWidth));\n            }\n        }\n    }\n    else\n    {\n        QPainterPath linePath;\n        bool startedLine = false;\n        \n        for (int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)\n        {\n            double user_x = xdata[vertexIndex];\n            double user_y = ydata[vertexIndex];\n            \n            if (!std::isnan(user_x) && !std::isnan(user_y))\n            {\n                QPointF devicePoint(plotToDeviceX(user_x, interiorRect), plotToDeviceY(user_y, interiorRect));\n                \n                if (startedLine)    linePath.lineTo(devicePoint);\n                else                linePath.moveTo(devicePoint);\n                \n                startedLine = true;\n            }\n            else\n            {\n                // a NAN value for x or y interrupts the line being plotted; INF values are plotted, but don't affect axis ranges\n                startedLine = false;\n            }\n        }\n        \n        if (lineAlpha != 1.0)\n            lineColor.setAlphaF(lineAlpha);\n        \n        painter.strokePath(linePath, QPen(lineColor, lineWidth));\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawMarginText(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *xdata = x1data_[dataIndex];\n    double *ydata = y1data_[dataIndex];\n    std::vector<QString> &labels = *labels_[dataIndex];\n    int pointCount = data_count_[dataIndex];\n    std::vector<QColor> &textColors = *color_[dataIndex];\n    std::vector<double> &textAlphas = *alpha_[dataIndex];\n    std::vector<double> &textAngles = *angle_[dataIndex];\n    std::vector<double> &pointSizes = *size_[dataIndex];\n    double xadj = xadj_[dataIndex];\n    double yadj = yadj_[dataIndex];\n    \n    // move clipping area outward to encompass our entire parent widget\n    QRect bounds = rect();\n    \n    painter.save();\n    painter.setClipRect(bounds, Qt::ReplaceClip);\n    \n    //QtSLiMFrameRect(interiorRect, Qt::green, painter);\n    \n    // set up to get the font and font info\n    double lastPointSize = -1;\n    QFont labelFont;\n    double capHeight = 0;\n    \n    for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex)\n    {\n        double user_x = xdata[pointIndex];\n        double user_y = ydata[pointIndex];\n        \n        if (std::isfinite(user_x) && std::isfinite(user_y))\n        {\n            // for mtext(), coordinates inside the plot area are in [0,1]\n            QString &labelText = labels[pointIndex];\n            double x = user_x * interiorRect.width() + interiorRect.x();\n            double y = user_y * interiorRect.height() + interiorRect.y();\n            \n            //qDebug() << \"labelText ==\" << labelText << \", user_x ==\" << user_x << \", user_y ==\" << user_y << \", x ==\" << x << \", y ==\" << y;\n            \n            // translate the painter so (x, y) is at (0, 0)\n            painter.save();\n            painter.translate(x, y);\n            x = 0;\n            y = 0;\n            \n            double pointSize = pointSizes[pointIndex % pointSizes.size()];\n            \n            if (pointSize != lastPointSize)\n            {\n                labelFont = QtSLiMGraphView::labelFontOfPointSize(pointSize);\n                capHeight = QFontMetricsF(labelFont).capHeight();\n                painter.setFont(labelFont);\n                \n                lastPointSize = pointSize;\n            }\n            \n            QColor textColor = textColors[pointIndex % textColors.size()];\n            double alpha = textAlphas[pointIndex % textAlphas.size()];\n            \n            if (alpha != 1.0)\n                textColor.setAlphaF(alpha);\n            \n            painter.setPen(textColor);\n            \n            QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, labelText);\n            \n            // labelBoundingRect is useful for its width, which seems to be calculated correctly; its height, however, is oddly large, and\n            // is not useful, so we use the capHeight from the font metrics instead.  This means that vertically centered (yadj == 0.5) is\n            // the midpoint between the baseline and the capHeight, which I think is probably the best behavior.\n            double labelWidth = labelBoundingRect.width();\n            double labelHeight = capHeight;\n            double labelX = x - SLIM_SCREEN_ROUND(labelWidth * xadj);\n            double labelY = y - SLIM_SCREEN_ROUND(labelHeight * yadj);\n            \n            //qDebug() << \"   labelBoundingRect ==\" << labelBoundingRect << \", labelWidth ==\" << labelWidth << \", labelHeight ==\" << labelHeight << \", capHeight ==\" << capHeight;\n            //qDebug() << \"   labelX ==\" << labelX << \", labelY ==\" << labelY;\n            \n            // rotate the coordinate system around (x, y); for example, -10.0 is 10 degrees clockwise\n            double textAngle = textAngles[pointIndex];\n            \n            if (textAngle != 0.0)\n                painter.rotate(-textAngles[pointIndex]);\n            \n#if 0\n            // draw the axes for the text around the pivot point\n            QPainterPath linePath;\n            \n            linePath.moveTo(-50, 0);\n            linePath.lineTo(50, 0);\n            linePath.moveTo(0, -50);\n            linePath.lineTo(0, 50);\n            painter.strokePath(linePath, QPen(Qt::green, 1.0));\n#endif\n            \n            // flip vertically so the text is upright, and then use -labelY since we're flipped\n            painter.scale(1.0, -1.0);\n            \n            painter.drawText(QPointF(labelX, -labelY), labelText);\n            \n            painter.restore();\n        }\n        else\n        {\n            // a NAN or INF value for x or y is not plotted\n        }\n    }\n    \n    painter.restore();\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawRects(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *x1data = x1data_[dataIndex];\n    double *y1data = y1data_[dataIndex];\n    double *x2data = x2data_[dataIndex];\n    double *y2data = y2data_[dataIndex];\n    int segmentCount = data_count_[dataIndex];\n    std::vector<QColor> &colors = *color_[dataIndex];\n    std::vector<QColor> &borderColors = *border_[dataIndex];\n    std::vector<double> &alphas = *alpha_[dataIndex];\n    std::vector<double> &lineWidths = *line_width_[dataIndex];\n    \n    for (int segmentIndex = 0; segmentIndex < segmentCount; ++segmentIndex)\n    {\n        double user_x1 = x1data[segmentIndex];\n        double user_y1 = y1data[segmentIndex];\n        double user_x2 = x2data[segmentIndex];\n        double user_y2 = y2data[segmentIndex];\n        \n        if (!std::isnan(user_x1) && !std::isnan(user_y1) && !std::isnan(user_x2) && !std::isnan(user_y2))\n        {\n            double device_x1 = plotToDeviceX(user_x1, interiorRect);\n            double device_y1 = plotToDeviceY(user_y1, interiorRect);\n            double device_x2 = plotToDeviceX(user_x2, interiorRect);\n            double device_y2 = plotToDeviceY(user_y2, interiorRect);\n            QColor color = colors[segmentIndex % colors.size()];\n            QColor borderColor = borderColors[segmentIndex % borderColors.size()];\n            double alpha = alphas[segmentIndex % alphas.size()];\n            double lineWidth = lineWidths[segmentIndex % lineWidths.size()];\n            \n            if (color.alphaF() != 0.0f)\n            {\n                // fill the rect\n                if (alpha != 1.0)\n                    color.setAlphaF(alpha);\n                \n                QRectF rect(device_x1, device_y1, device_x2 - device_x1, device_y2 - device_y1);\n                \n                painter.fillRect(rect, color);\n            }\n            \n            if (borderColor.alphaF() != 0.0f)\n            {\n                // frame the rect\n                if (alpha != 1.0)\n                    borderColor.setAlphaF(alpha);\n                \n                QPainterPath linePath;\n                linePath.moveTo(device_x1, device_y1);\n                linePath.lineTo(device_x2, device_y1);\n                linePath.lineTo(device_x2, device_y2);\n                linePath.lineTo(device_x1, device_y2);\n                linePath.closeSubpath();\n\t\t\t\tpainter.strokePath(linePath, QPen(borderColor, lineWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawSegments(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *x1data = x1data_[dataIndex];\n    double *y1data = y1data_[dataIndex];\n    double *x2data = x2data_[dataIndex];\n    double *y2data = y2data_[dataIndex];\n    int segmentCount = data_count_[dataIndex];\n    std::vector<QColor> &colors = *color_[dataIndex];\n    std::vector<double> &alphas = *alpha_[dataIndex];\n    std::vector<double> &lineWidths = *line_width_[dataIndex];\n    \n    for (int segmentIndex = 0; segmentIndex < segmentCount; ++segmentIndex)\n    {\n        QPainterPath linePath;\n        double user_x1 = x1data[segmentIndex];\n        double user_y1 = y1data[segmentIndex];\n        double user_x2 = x2data[segmentIndex];\n        double user_y2 = y2data[segmentIndex];\n        \n        if (!std::isnan(user_x1) && !std::isnan(user_y1) && !std::isnan(user_x2) && !std::isnan(user_y2))\n        {\n            QPointF devicePoint1(plotToDeviceX(user_x1, interiorRect), plotToDeviceY(user_y1, interiorRect));\n            QPointF devicePoint2(plotToDeviceX(user_x2, interiorRect), plotToDeviceY(user_y2, interiorRect));\n            QColor color = colors[segmentIndex % colors.size()];\n            double alpha = alphas[segmentIndex % alphas.size()];\n            double lineWidth = lineWidths[segmentIndex % lineWidths.size()];\n            \n            if (alpha != 1.0)\n                color.setAlphaF(alpha);\n            \n            linePath.moveTo(devicePoint1);\n            linePath.lineTo(devicePoint2);\n            painter.strokePath(linePath, QPen(color, lineWidth));\n        }\n    }\n}\n\n\nvoid QtSLiMGraphView_CustomPlot::drawPoints(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *xdata = x1data_[dataIndex];\n    double *ydata = y1data_[dataIndex];\n    int pointCount = data_count_[dataIndex];\n    std::vector<int> &symbols = *symbol_[dataIndex];\n    std::vector<QColor> &symbolColors = *color_[dataIndex];\n    std::vector<QColor> &borderColors = *border_[dataIndex];\n    std::vector<double> &alphas = *alpha_[dataIndex];\n    std::vector<double> &lineWidths = *line_width_[dataIndex];\n    std::vector<double> &sizes = *size_[dataIndex];\n    \n    for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex)\n    {\n        double user_x = xdata[pointIndex];\n        double user_y = ydata[pointIndex];\n        \n        // given that the line width, color, etc. can change with each symbol, we just plot each symbol individually\n        if (std::isfinite(user_x) && std::isfinite(user_y))\n        {\n            double x = plotToDeviceX(user_x, interiorRect);\n            double y = plotToDeviceY(user_y, interiorRect);\n            int symbol = symbols[pointIndex % symbols.size()];\n            QColor symbolColor = symbolColors[pointIndex % symbolColors.size()];\n            QColor borderColor = borderColors[pointIndex % borderColors.size()];\n            double alpha = alphas[pointIndex % alphas.size()];\n            double lineWidth = lineWidths[pointIndex % lineWidths.size()];\n            double size = sizes[pointIndex % sizes.size()];\n            \n            drawPointSymbol(painter, x, y, symbol, symbolColor, borderColor, alpha, lineWidth, size);\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawText(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *xdata = x1data_[dataIndex];\n    double *ydata = y1data_[dataIndex];\n    std::vector<QString> &labels = *labels_[dataIndex];\n    int pointCount = data_count_[dataIndex];\n    std::vector<QColor> &textColors = *color_[dataIndex];\n    std::vector<double> &textAlphas = *alpha_[dataIndex];\n    std::vector<double> &textAngles = *angle_[dataIndex];\n    std::vector<double> &pointSizes = *size_[dataIndex];\n    double xadj = xadj_[dataIndex];\n    double yadj = yadj_[dataIndex];\n    \n    // set up to get the font and font info\n    double lastPointSize = -1;\n    QFont labelFont;\n    double capHeight = 0;\n    \n    for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex)\n    {\n        double user_x = xdata[pointIndex];\n        double user_y = ydata[pointIndex];\n        \n        if (std::isfinite(user_x) && std::isfinite(user_y))\n        {\n            QString &labelText = labels[pointIndex];\n            double x = plotToDeviceX(user_x, interiorRect);\n            double y = plotToDeviceY(user_y, interiorRect);\n            \n            //qDebug() << \"labelText ==\" << labelText << \", user_x ==\" << user_x << \", user_y ==\" << user_y << \", x ==\" << x << \", y ==\" << y;\n            \n            // translate the painter so (x, y) is at (0, 0)\n            painter.save();\n            painter.translate(x, y);\n            x = 0;\n            y = 0;\n            \n            double pointSize = pointSizes[pointIndex % pointSizes.size()];\n            \n            if (pointSize != lastPointSize)\n            {\n                labelFont = QtSLiMGraphView::labelFontOfPointSize(pointSize);\n                capHeight = QFontMetricsF(labelFont).capHeight();\n                painter.setFont(labelFont);\n                \n                lastPointSize = pointSize;\n            }\n            \n            QColor textColor = textColors[pointIndex % textColors.size()];\n            double alpha = textAlphas[pointIndex % textAlphas.size()];\n            \n            if (alpha != 1.0)\n                textColor.setAlphaF(alpha);\n            \n            painter.setPen(textColor);\n            \n            QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, labelText);\n            \n            // labelBoundingRect is useful for its width, which seems to be calculated correctly; its height, however, is oddly large, and\n            // is not useful, so we use the capHeight from the font metrics instead.  This means that vertically centered (yadj == 0.5) is\n            // the midpoint between the baseline and the capHeight, which I think is probably the best behavior.\n            double labelWidth = labelBoundingRect.width();\n            double labelHeight = capHeight;\n            double labelX = x - SLIM_SCREEN_ROUND(labelWidth * xadj);\n            double labelY = y - SLIM_SCREEN_ROUND(labelHeight * yadj);\n            \n            //qDebug() << \"   labelBoundingRect ==\" << labelBoundingRect << \", labelWidth ==\" << labelWidth << \", labelHeight ==\" << labelHeight << \", capHeight ==\" << capHeight;\n            //qDebug() << \"   labelX ==\" << labelX << \", labelY ==\" << labelY;\n            \n            // rotate the coordinate system around (x, y); for example, -10.0 is 10 degrees clockwise\n            double textAngle = textAngles[pointIndex];\n            \n            if (textAngle != 0.0)\n                painter.rotate(-textAngles[pointIndex]);\n                \n#if 0\n            // draw the axes for the text around the pivot point\n            QPainterPath linePath;\n            \n            linePath.moveTo(-50, 0);\n            linePath.lineTo(50, 0);\n            linePath.moveTo(0, -50);\n            linePath.lineTo(0, 50);\n            painter.strokePath(linePath, QPen(Qt::green, 1.0));\n#endif\n            \n            // flip vertically so the text is upright, and then use -labelY since we're flipped\n            painter.scale(1.0, -1.0);\n            \n            painter.drawText(QPointF(labelX, -labelY), labelText);\n            \n            painter.restore();\n        }\n        else\n        {\n            // a NAN or INF value for x or y is not plotted\n        }\n    }\n}\n\nvoid QtSLiMGraphView_CustomPlot::drawImage(QPainter &painter, QRect interiorRect, int dataIndex)\n{\n    double *xdata = x1data_[dataIndex];\n    double *ydata = y1data_[dataIndex];\n    double alpha = (*alpha_[dataIndex])[0];\n    \n    double user_x1 = xdata[0], user_y1 = ydata[0];\n    double user_x2 = xdata[1], user_y2 = ydata[1];\n    \n    // for image() we always want to use pixel edges, as in PDF, not pixel centers, so that the plotted image\n    // uses up the full pixels at the edges of the plot area if the image fills the whole plot area\n    bool old_generatingPDF_ = generatingPDF_;\n    generatingPDF_ = true;\n    \n    double x1 = plotToDeviceX(user_x1, interiorRect);\n    double y1 = plotToDeviceY(user_y1, interiorRect);\n    double x2 = plotToDeviceX(user_x2, interiorRect);\n    double y2 = plotToDeviceY(user_y2, interiorRect);\n    \n    generatingPDF_ = old_generatingPDF_;\n    \n    // the coordinates are absolute, but Qt wants them as width/height\n    double target_width = x2 - x1;\n    double target_height = y2 - y1;\n    \n    // get the image data\n    const QImage &image = image_[dataIndex];\n    \n    QRectF target(x1, y1, target_width, target_height);\n    \n    if (alpha != 1.0)\n        painter.setOpacity(alpha);\n    \n    // we do not want antialiasing of images drawn here; unfortunately that is difficult, because Qt ignores its render hints\n    // in some cases and still gives us an interpolated image, so we also have to scale the image itself sometimes\n    bool old_antialiasing = painter.testRenderHint(QPainter::Antialiasing);\n    bool old_smoothpixmap = painter.testRenderHint(QPainter::SmoothPixmapTransform);\n    painter.setRenderHint(QPainter::Antialiasing, false);\n    painter.setRenderHint(QPainter::SmoothPixmapTransform, false);\n    \n    if (generatingPDF_)\n    {\n        const QImage scaledImage = image.scaled(target_width, target_height, Qt::IgnoreAspectRatio, Qt::FastTransformation);\n        \n        painter.drawImage(target, scaledImage);\n    }\n    else\n    {\n        // for on-screen display I have not seen it smooth the rescale, and I don't want the overhead of making a new image every time...\n        painter.drawImage(target, image);\n    }\n    \n    painter.setRenderHint(QPainter::Antialiasing, old_antialiasing);\n    painter.setRenderHint(QPainter::SmoothPixmapTransform, old_smoothpixmap);\n    \n    if (alpha != 1.0)\n        painter.setOpacity(1.0);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_CustomPlot.h",
    "content": "//\n//  QtSLiMGraphView_CustomPlot.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/19/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_CUSTOMPLOT_H\n#define QTSLIMGRAPHVIEW_CUSTOMPLOT_H\n\n#include <QWidget>\n\n#include <vector>\n\n#include \"QtSLiMGraphView.h\"\n\nclass Plot;\n\n\nenum class QtSLiM_CustomPlotType : int {\n    kLines,\n    kSegments,\n    kRects,\n    kPoints,\n    kMarginText,\n    kText,\n    kABLines,   // from abline()\n    kHLines,    // from abline()\n    kVLines,    // from abline()\n    kImage,\n};\n\nclass QtSLiMGraphView_CustomPlot : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_CustomPlot(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_CustomPlot() override;\n    \n    Plot *eidosPlotObject(void) { return eidos_plot_object_; }\n    void setEidosPlotObject(Plot *plot_object) { eidos_plot_object_ = plot_object; }    // takes ownership\n    \n    void freeData(void);\n    \n    void setTitle(QString title);\n    void setXLabel(QString x_label);\n    void setYLabel(QString y_label);\n    void setShowHorizontalGrid(bool showHorizontalGrid);\n    void setShowVerticalGrid(bool showVerticalGrid);\n    void setShowFullBox(bool showFullBox);\n    void setAxisLabelSize(double axisLabelSize);\n    void setTickLabelSize(double tickLabelSize);\n    void setLegendPosition(QtSLiM_LegendPosition position);\n    void setDataRanges(double *x_range, double *y_range);\n    void setAxisConfiguration(int side, std::vector<double> *at, int labels_type, std::vector<QString> *labels);\n    \n    void addABLineData(double *a_values, double *b_values,\n                       double *h_values, double *v_values, int data_count,\n                       std::vector<QColor> *color, std::vector<double> *alpha,\n                       std::vector<double> *lwd);\n    void addImageData(double *x_values, double *y_values, int data_count,\n                      QImage image, std::vector<double> *alpha);\n    void addLineData(double *x_values, double *y_values, int data_count,\n                     std::vector<QColor> *color, std::vector<double> *alpha,\n                     std::vector<double> *lwd);\n    void addMarginTextData(double *x_values, double *y_values, std::vector<QString> *labels, int data_count,\n                           std::vector<QColor> *color, std::vector<double> *alpha, std::vector<double> *size,\n                           double *adj, std::vector<double> *angle);\n    void addPointData(double *x_values, double *y_values, int data_count,\n                      std::vector<int> *symbol, std::vector<QColor> *color, std::vector<QColor> *border,\n                      std::vector<double> *alpha, std::vector<double> *lwd, std::vector<double> *size);\n    void addRectData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,\n                     int data_count, std::vector<QColor> *color, std::vector<QColor> *border,\n                     std::vector<double> *alpha, std::vector<double> *lwd);\n    void addSegmentData(double *x1_values, double *y1_values, double *x2_values, double *y2_values,\n                        int data_count, std::vector<QColor> *color,\n                        std::vector<double> *alpha, std::vector<double> *lwd);\n    void addTextData(double *x_values, double *y_values, std::vector<QString> *labels, int data_count,\n                     std::vector<QColor> *color, std::vector<double> *alpha, std::vector<double> *size,\n                     double *adj, std::vector<double> *angle);\n    \n    void addLegend(QtSLiM_LegendPosition position, int inset, double labelSize, double lineHeight,\n                   double graphicsWidth, double exteriorMargin, double interiorMargin);\n    void addLegendLineEntry(QString label, QColor color, double lwd);\n    void addLegendPointEntry(QString label, int symbol, QColor color, QColor border, double lwd, double size);\n    void addLegendSwatchEntry(QString label, QColor color);\n    void addLegendTitleEntry(QString label);\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual QString disableMessage(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual void appendStringForData(QString &string) override;\n    \n    bool legendAdded(void) { return legend_added_; }\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    \npublic slots:\n    virtual void controllerRecycled(void) override;\n    \nprivate:\n    Plot *eidos_plot_object_ = nullptr;                 // OWNED POINTER\n    \n    QString title_;\n    \n    // we can keep any number of sets of lines and points; they get plotted in the order supplied to us\n    // some parameters don't apply to a given plot type; placeholder values are inserted for those\n    bool has_finite_data_;\n    \n    std::vector<QtSLiM_CustomPlotType> plot_type_;\n    std::vector<double *> x1data_;\n    std::vector<double *> y1data_;\n    std::vector<double *> x2data_;\n    std::vector<double *> y2data_;\n    std::vector<int> data_count_;                       // the count for the xdata / ydata buffers\n    std::vector<std::vector<QString> *> labels_;        // one label per point\n    std::vector<std::vector<int> *> symbol_;            // one symbol per point, OR one symbol for all points\n    std::vector<std::vector<QColor> *> color_;          // one color per point, OR one color for all points\n    std::vector<std::vector<QColor> *> border_;         // one border color per point, OR one for all points\n    std::vector<std::vector<double> *> alpha_;          // one alpha per point, OR one alpha for all points\n    std::vector<std::vector<double> *> line_width_;     // one lwd per point, OR one lwd for all points\n    std::vector<std::vector<double> *> size_;           // one size per point, OR one size for all points\n    std::vector<std::vector<double> *> angle_;          // one angle per point, OR one angle for all points\n    std::vector<double> xadj_;                          // one xadj for all points\n    std::vector<double> yadj_;                          // one yadj for all points\n    std::vector<QImage> image_;                         // one QImage per image data; QImage() if unused\n    \n    void dataRange(std::vector<double *> &data, double *p_min, double *p_max);\n    void rescaleAxesForDataRange(void);\n    void drawABLines(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawHLines(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawVLines(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawLines(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawMarginText(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawSegments(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawRects(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawPoints(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawText(QPainter &painter, QRect interiorRect, int dataIndex);\n    void drawImage(QPainter &painter, QRect interiorRect, int dataIndex);\n    \n    bool legend_added_ = false;                         // set to true by addLegend()\n    QtSLiMLegendSpec legend_entries_;                   // unlike most graph types, we keep our legend around\n};\n\n\n#endif // QTSLIMGRAPHVIEW_CUSTOMPLOT_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FitnessOverTime.cpp",
    "content": "//\n//  QtSLiMGraphView_FitnessOverTime.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_FitnessOverTime.h\"\n\n#include <QAction>\n#include <QMenu>\n#include <QPixmap>\n#include <QPainterPath>\n#include <QDebug>\n\n#include <limits>\n#include <string>\n#include <vector>\n\n#include \"QtSLiMWindow.h\"\n\n\nQtSLiMGraphView_FitnessOverTime::QtSLiMGraphView_FitnessOverTime(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    //setXAxisRangeFromTick();\t// the end tick is not yet known\n    setDefaultYAxisRange();\n    \n    xAxisLabel_ = \"Tick\";\n    yAxisLabel_ = \"Fitness (rescaled)\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    showSubpopulations_ = true;\n    drawLines_ = true;\n    \n    QtSLiMGraphView_FitnessOverTime::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::setDefaultYAxisRange(void)\n{\n    original_y0_ = 0.9;\n    original_y1_ = 1.1;\t\t// dynamic\n    \n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    yAxisMin_ = y0_;\n    yAxisMax_ = y1_;\n\tyAxisMajorTickInterval_ = 0.1;\n\tyAxisMinorTickInterval_ = 0.02;\n\tyAxisMajorTickModulus_ = 5;\n\tyAxisTickValuePrecision_ = 1;\n}\n\nQtSLiMGraphView_FitnessOverTime::~QtSLiMGraphView_FitnessOverTime()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_FitnessOverTime::invalidateDrawingCache();\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::invalidateDrawingCache(void)\n{\n    delete drawingCache_;\n\tdrawingCache_ = nullptr;\n\tdrawingCacheTick_ = 0;\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t{\n\t\tif (!yAxisIsUserRescaled_)\n\t\t\tsetDefaultYAxisRange();\n\t\t//if (!xAxisIsUserRescaled_)\n\t\t//\tsetXAxisRangeFromTick();\t// the end tick is not yet known\n\t\t\n\t\tupdate();\n\t}\n\t\n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_FitnessOverTime::graphTitle(void)\n{\n    return \"Fitness ~ Time\";\n}\n\nQString QtSLiMGraphView_FitnessOverTime::aboutString(void)\n{\n    return \"The Fitness ~ Time graph shows mean fitness as a function of time.  The mean fitness \"\n           \"of the population is shown with a thick black line, while those of subpopulations \"\n           \"are shown with thinner colored lines.  Fixation events during the model run are \"\n           \"shown with light blue vertical lines at the tick in which they occurred.  The \"\n           \"fitness shown is 'rescaled', meaning that when non-neutral mutations fix and are 'substituted' by \"\n           \"SLiM they are no longer included in fitness calculations, so the y axis is 'rescaled'; \"\n           \"this is mainly relevant to WF models.  It is also 'rescaled' in the sense that it \"\n           \"excludes subpopulation fitnessScaling values (to emphasize individual fitness effects \"\n           \"over density-dependence); this is mainly relevant to nonWF models.\";\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::updateAfterTick(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!controller_->invalidSimulation() && graphSpecies && !yAxisIsUserRescaled_)\n    {\n        // BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n        if (!xAxisIsUserRescaled_)\n            setXAxisRangeFromTick();\n        \n        Population &pop = graphSpecies->population_;\n        double minHistory = std::numeric_limits<double>::infinity();\n        double maxHistory = -std::numeric_limits<double>::infinity();\n        bool showSubpops = showSubpopulations_ && (pop.fitness_histories_.size() > 2);\n        \n        for (auto history_record_iter : pop.fitness_histories_)\n        {\n            if (showSubpops || (history_record_iter.first == -1))\n            {\n                FitnessHistory &history_record = history_record_iter.second;\n                double *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                \n                // find the min and max history value\n                for (int i = 0; i < historyLength; ++i)\n                {\n                    double historyEntry = history[i];\n                    \n                    if (!std::isnan(historyEntry))\n                    {\n                        if (historyEntry > maxHistory)\n                            maxHistory = historyEntry;\n                        if (historyEntry < minHistory)\n                            minHistory = historyEntry;\n                    }\n                }\n            }\n        }\n        \n        // set axis range to encompass the data\n        if (!std::isinf(minHistory) && !std::isinf(maxHistory))\n        {\n            if ((minHistory < 0.9) || (maxHistory > 1.1))\t// if we're outside our original axis range...\n            {\n                double axisMin = (minHistory < 0.5 ? 0.0 : 0.5);\t// either 0.0 or 0.5\n                double axisMax = ceil(maxHistory * 2.0) / 2.0;\t\t// 1.5, 2.0, 2.5, ...\n                \n                if (axisMax < 1.5)\n                    axisMax = 1.5;\n                \n                if ((fabs(axisMin - yAxisMin_) > 0.0000001) || (fabs(axisMax - yAxisMax_) > 0.0000001))\n                {\n                    yAxisMin_ = axisMin;\n                    original_y0_ = yAxisMin_;               // the same as yAxisMin_, for base plots\n                    y0_ = original_y0_;\n                    yAxisMax_ = axisMax;\n                    original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                    y1_ = original_y1_;\n                    yAxisMajorTickInterval_ = 0.5;\n                    yAxisMinorTickInterval_ = 0.25;\n                    yAxisMajorTickModulus_ = 2;\n                    yAxisTickValuePrecision_ = 1;\n                    \n                    QtSLiMGraphView_FitnessOverTime::invalidateDrawingCache();\n                }\n            }\n        }\n    }\n    \n    QtSLiMGraphView::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::drawPointGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// The tick counter can get set backwards, in which case our drawing cache is invalid – it contains drawing of things in the\n\t// future that may no longer happen.  So we need to detect that case and invalidate our cache.\n\tif (!cachingNow_ && drawingCache_ && (drawingCacheTick_ > completedTicks))\n\t{\n\t\t//qDebug() << \"backward tick change detected, invalidating drawing cache\";\n\t\tinvalidateDrawingCache();\n\t}\n\t\n\t// If we're not caching, then: if our cache is invalid OR we have crossed a 1000-tick boundary since we last cached, cache an image\n\tif (!cachingNow_ && (!drawingCache_ || ((completedTicks / 1000) > (drawingCacheTick_ / 1000))))\n\t{\n        invalidateDrawingCache();\n\t\t\n        //qDebug() << \"making new cache at tick \" << community->Tick();\n\t\tcachingNow_ = true;\n        \n\t\tQPixmap *cache = new QPixmap(interiorRect.size());\n        cache->fill(Qt::transparent);   // transparent so grid lines don't get overwritten by drawPixmap()\n        \n        QPainter cachePainter(cache);\n        drawGraph(cachePainter, cache->rect());\n        \n        drawingCache_ = cache;\n\t\tdrawingCacheTick_ = completedTicks;\n\t\tcachingNow_ = false;\n\t}\n\t\n\t// Now draw our cache, if we have one\n\tif (drawingCache_)\n    {\n        //qDebug() << \"drawing cache:\" << drawingCache_->rect() << \", drawingCacheTick_ == \" << drawingCacheTick_;\n        painter.drawPixmap(interiorRect, *drawingCache_, drawingCache_->rect());\n    }\n    \n\t// Draw fixation events\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n\t\t\n\t\t// If we are caching, draw all events; if we are not, draw only those that are not already in the cache\n\t\tif (!cachingNow_ && (fixation_tick < drawingCacheTick_))\n\t\t\tcontinue;\n\t\t\n        double substitutionX = plotToDeviceX(fixation_tick, interiorRect);\n\t\tQRectF substitutionRect(substitutionX - 0.5, interiorRect.x(), 1.0, interiorRect.height());\n\t\t\n        painter.fillRect(substitutionRect, QtSLiMColorWithRGB(0.2, 0.2, 1.0, 0.2));\n\t}\n\t\n\t// Draw the fitness history as a scatter plot; better suited to caching of the image\n    bool showSubpops = showSubpopulations_ && (pop.fitness_histories_.size() > 2);\n\tbool drawSubpopsGray = (showSubpops && (pop.fitness_histories_.size() > 8));\t// 7 subpops + pop\n\t\n\t// First draw subpops, then draw the mean population fitness\n    for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n    {\n        QColor pointColor = ((iter == 0) ? QtSLiMColorWithWhite(0.5, 1.0) : Qt::black);\n        \n        for (auto history_record_iter : pop.fitness_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n            {\n                FitnessHistory &history_record = history_record_iter.second;\n                double *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                \n                // If we're caching now, draw all points; otherwise, if we have a cache, draw only additional points\n                slim_tick_t firstHistoryEntryToDraw = (cachingNow_ ? 0 : (drawingCache_ ? drawingCacheTick_ : 0));\n                \n                for (slim_tick_t i = firstHistoryEntryToDraw; (i < historyLength) && (i < completedTicks); ++i)\n                {\n                    double historyEntry = history[i];\n                    \n                    if (!std::isnan(historyEntry))\n                    {\n                        QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                        \n                        if ((iter == 0) && !drawSubpopsGray)\n                            pointColor = controller_->whiteContrastingColorForIndex(history_record_iter.first);\n                        \n                        painter.fillRect(QRectF(historyPoint.x() - 0.5, historyPoint.y() - 0.5, 1.0, 1.0), pointColor);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::drawLineGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// Draw fixation events\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n        double substitutionX = plotToDeviceX(fixation_tick, interiorRect);\n\t\tQRectF substitutionRect(substitutionX - 0.5, interiorRect.x(), 1.0, interiorRect.height());\n\t\t\n        painter.fillRect(substitutionRect, QtSLiMColorWithRGB(0.2, 0.2, 1.0, 0.2));\n\t}\n\t\n\t// Draw the fitness history as a line plot\n\tbool showSubpops = showSubpopulations_ && (pop.fitness_histories_.size() > 2);\n\tbool drawSubpopsGray = (showSubpops && (pop.fitness_histories_.size() > 8));\t// 7 subpops + pop\n\t\n    // First draw subpops, then draw the mean population fitness\n    for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n    {\n        QColor lineColor = (iter == 0) ? QtSLiMColorWithWhite(0.5, 1.0) : Qt::black;\n        double lineWidth = (iter == 0) ? 1.0 : 1.5;\n        \n        for (auto history_record_iter : pop.fitness_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n            {\n                FitnessHistory &history_record = history_record_iter.second;\n                double *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                QPainterPath linePath;\n                bool startedLine = false;\n                \n                for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                {\n                    double historyEntry = history[i];\n                    \n                    if (std::isnan(historyEntry))\n                    {\n                        startedLine = false;\n                    }\n                    else\n                    {\n                        QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                        \n                        if (startedLine)    linePath.lineTo(historyPoint);\n                        else                linePath.moveTo(historyPoint);\n                        \n                        startedLine = true;\n                    }\n                }\n                \n                if ((iter == 0) && !drawSubpopsGray)\n                    lineColor = controller_->whiteContrastingColorForIndex(history_record_iter.first);\n                \n                painter.strokePath(linePath, QPen(lineColor, lineWidth));\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    if (drawLines_)\n\t\tdrawLineGraph(painter, interiorRect);\n\telse\n\t\tdrawPointGraph(painter, interiorRect);\n}\n\nbool QtSLiMGraphView_FitnessOverTime::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::appendStringForData(QString &string)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// Fixation events\n\tstring.append(\"# Fixation ticks:\\n\");\n\t\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n\t\t\n\t\tstring.append(QString(\"%1, \").arg(fixation_tick));\n\t}\n\t\n\t// Fitness history\n    bool showSubpops = showSubpopulations_ && (pop.fitness_histories_.size() > 2);\n    \n\tstring.append(\"\\n\\n# Fitness history:\\n\");\n\t\n    for (int iter = 0; iter <= (showSubpops ? 1 : 0); ++iter)\n    {\n        for (auto history_record_iter : pop.fitness_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first == -1)) || ((iter == 1) && (history_record_iter.first != -1)))\n            {\n                FitnessHistory &history_record = history_record_iter.second;\n                double *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                \n                if (iter == 1)\n                    string.append(QString(\"\\n\\n# Fitness history (subpopulation p%1):\\n\").arg(history_record_iter.first));\n                \n                for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                    string.append(QString(\"%1, \").arg(history[i], 0, 'f', 4));\n                \n                string.append(\"\\n\");\n\t\t\t}\n\t\t}\n\t}\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_FitnessOverTime::legendKey(void)\n{\n    if (!showSubpopulations_)\n        return QtSLiMLegendSpec();\n    \n    Species *graphSpecies = focalDisplaySpecies();\n    std::vector<slim_objectid_t> subpopsToDisplay;\n    \n    for (auto history_record_iter : graphSpecies->population_.fitness_histories_)\n        subpopsToDisplay.emplace_back(history_record_iter.first);\n\n    return subpopulationLegendKey(subpopsToDisplay, subpopsToDisplay.size() > 8);\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::toggleShowSubpopulations(void)\n{\n    showSubpopulations_ = !showSubpopulations_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::toggleDrawLines(void)\n{\n    drawLines_ = !drawLines_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_FitnessOverTime::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(showSubpopulations_ ? \"Hide Subpopulations\" : \"Show Subpopulations\", this, &QtSLiMGraphView_FitnessOverTime::toggleShowSubpopulations);\n    contextMenu.addAction(drawLines_ ? \"Draw Points (Faster)\" : \"Draw Lines (Slower)\", this, &QtSLiMGraphView_FitnessOverTime::toggleDrawLines);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FitnessOverTime.h",
    "content": "//\n//  QtSLiMGraphView_FitnessOverTime.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/31/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_FITNESSOVERTIME_H\n#define QTSLIMGRAPHVIEW_FITNESSOVERTIME_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\nclass QPixmap;\n\n\nclass QtSLiMGraphView_FitnessOverTime : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_FitnessOverTime(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_FitnessOverTime() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    \npublic slots:\n    virtual void invalidateDrawingCache(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void toggleShowSubpopulations(void);\n    void toggleDrawLines(void);\n    \nprotected:\n    virtual QtSLiMLegendSpec legendKey(void) override;    \n    \nprivate:\n    bool showSubpopulations_ = false;\n    bool drawLines_ = false;\n    \n    QPixmap *drawingCache_ = nullptr;\n\tslim_tick_t drawingCacheTick_ = 0;\n    \n    void setDefaultYAxisRange(void);\n    \n    void drawPointGraph(QPainter &painter, QRect interiorRect);\n    void drawLineGraph(QPainter &painter, QRect interiorRect);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_FITNESSOVERTIME_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FixationTimeHistogram.cpp",
    "content": "//\n//  QtSLiMGraphView_FixationTimeHistogram.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_FixationTimeHistogram.h\"\n\n#include <string>\n\n#include \"QtSLiMWindow.h\"\n\n\nQtSLiMGraphView_FixationTimeHistogram::QtSLiMGraphView_FixationTimeHistogram(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 10;\n    //allowBinCountRescale_ = true;     // not supported yet\n    \n    original_x1_ = 1000;\n    x1_ = original_x1_;\n    \n    xAxisMax_ = x1_;\n    xAxisMajorTickInterval_ = 200;\n    xAxisMinorTickInterval_ = 100;\n    xAxisMajorTickModulus_ = 2;\n    xAxisTickValuePrecision_ = 0;\n    \n    xAxisLabel_ = \"Mutation fixation time\";\n    yAxisLabel_ = \"Proportion of fixed mutations\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n}\n\nQtSLiMGraphView_FixationTimeHistogram::~QtSLiMGraphView_FixationTimeHistogram()\n{\n}\n\nQString QtSLiMGraphView_FixationTimeHistogram::graphTitle(void)\n{\n    return \"Mutation Fixation Time\";\n}\n\nQString QtSLiMGraphView_FixationTimeHistogram::aboutString(void)\n{\n    return \"The Mutation Fixation Time graph shows a histogram of mutation fixation times, \"\n           \"for those mutations that have fixed.  The proportions are calculated and plotted \"\n           \"separately for each mutation type, for comparison.\";\n}\n\ndouble *QtSLiMGraphView_FixationTimeHistogram::fixationTimeData(void)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n\tint mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\tslim_tick_t *histogram = graphSpecies->population_.mutation_fixation_times_;\n\tint64_t histogramBins = static_cast<int64_t>(graphSpecies->population_.mutation_fixation_tick_slots_);\t// fewer than binCount * mutationTypeCount may exist\n\tstatic double *rebin = nullptr;\n\tstatic size_t rebinBins = 0;\n\tsize_t usedRebinBins = static_cast<size_t>(binCount * mutationTypeCount);\n\t\n    // re-bin for display; SLiM bins every 10 ticks, but right now we want to plot every 100 ticks as a bin\n\tif (!rebin || (rebinBins < usedRebinBins))\n\t{\n\t\trebinBins = usedRebinBins;\n\t\trebin = static_cast<double *>(realloc(rebin, rebinBins * sizeof(double)));\n\t}\n\t\n\tfor (size_t i = 0; i < usedRebinBins; ++i)\n\t\trebin[i] = 0.0;\n\t\n\tfor (int i = 0; i < binCount * 10; ++i)\n\t{\n\t\tfor (int j = 0; j < mutationTypeCount; ++j)\n\t\t{\n\t\t\tint histIndex = j + i * mutationTypeCount;\n\t\t\t\n\t\t\tif (histIndex < histogramBins)\n                rebin[j + (i / 10) * mutationTypeCount] += histogram[histIndex];\n\t\t}\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tint64_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += static_cast<int64_t>(rebin[binIndex]);\n\t\t}\n        \n        if (total == 0)\n            total = 1;  // if counts are all zero, avoid a divide by zero below and just end up with 0 instead\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\trebin[binIndex] /= static_cast<double>(total);\n\t\t}\n\t}\n\t\n\treturn rebin;\n}\n\nvoid QtSLiMGraphView_FixationTimeHistogram::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    double *plotData = fixationTimeData();\n\tint binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    int mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\t\n\t// plot our histogram bars\n\tdrawGroupedBarplot(painter, interiorRect, plotData, mutationTypeCount, binCount, 0.0, 100.0);\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_FixationTimeHistogram::legendKey(void)\n{\n\treturn mutationTypeLegendKey();     // we use the prefab mutation type legend\n}\n\nbool QtSLiMGraphView_FixationTimeHistogram::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_FixationTimeHistogram::appendStringForData(QString &string)\n{\n\tdouble *plotData = fixationTimeData();\n\tint binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    int mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\t\n\tfor (auto mutationTypeIter : graphSpecies->mutation_types_)\n\t{\n\t\tMutationType *mutationType = mutationTypeIter.second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n        string.append(QString(\"\\\"m%1\\\", \").arg(mutationType->mutation_type_id_));\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n            string.append(QString(\"%1, \").arg(plotData[histIndex], 0, 'f', 4));\n\t\t}\n\t\t\n        string.append(\"\\n\");\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FixationTimeHistogram.h",
    "content": "//\n//  QtSLiMGraphView_FixationTimeHistogram.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_FIXATIONTIMEHISTOGRAM_H\n#define QTSLIMGRAPHVIEW_FIXATIONTIMEHISTOGRAM_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_FixationTimeHistogram : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_FixationTimeHistogram(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_FixationTimeHistogram() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    \nprivate:\n    double *fixationTimeData(void);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_FIXATIONTIMEHISTOGRAM_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FrequencyTrajectory.cpp",
    "content": "//\n//  QtSLiMGraphView_FrequencyTrajectory.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/1/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_FrequencyTrajectory.h\"\n\n#include <QAction>\n#include <QMenu>\n#include <QPainterPath>\n#include <QComboBox>\n#include <QDebug>\n\n#include <string>\n#include <vector>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n\n\nQtSLiMGraphView_FrequencyTrajectory::QtSLiMGraphView_FrequencyTrajectory(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    //setXAxisRangeFromTick();\t// the end tick is not yet known\n    \n    xAxisLabel_ = \"Tick\";\n    yAxisLabel_ = \"Frequency\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    // Start with no selected subpop or mutation-type; these will be set to the first menu item added when menus are constructed\n    selectedSubpopulationID_ = -1;\n    selectedMutationTypeIndex_ = -1;\n    \n    // Start plotting lost mutations, by default\n    plotLostMutations_ = true;\n    plotFixedMutations_ = true;\n    plotActiveMutations_ = true;\n    useColorsForPlotting_ = true;\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulationButton_ = newButtonInLayout(button_layout);\n        connect(subpopulationButton_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_FrequencyTrajectory::subpopulationPopupChanged);\n        \n        mutationTypeButton_ = newButtonInLayout(button_layout);\n        connect(mutationTypeButton_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_FrequencyTrajectory::mutationTypePopupChanged);\n        \n        addSubpopulationsToMenu(subpopulationButton_, selectedSubpopulationID_);\n        addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    }\n    \n    // We want to display a \"recycle to start gathering data at the start of the run\" message\n    justAddedToWindow_ = true;\n}\n\nQtSLiMGraphView_FrequencyTrajectory::~QtSLiMGraphView_FrequencyTrajectory()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_FrequencyTrajectory::invalidateCachedData();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::invalidateCachedData(void)\n{\n    // first free all the MutationFrequencyHistory objects we've stored\n    for (auto &item : frequencyHistoryDict_)\n        delete item.second;\n    \n    for (auto &item : frequencyHistoryColdStorageLost_)\n        delete item;\n    \n    for (auto &item : frequencyHistoryColdStorageFixed_)\n        delete item;\n    \n    // then clear out the storage\n    frequencyHistoryDict_.clear();\n    frequencyHistoryColdStorageLost_.clear();\n    frequencyHistoryColdStorageFixed_.clear();\n    \n    justAddedToWindow_ = true;\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::fetchDataForFinishedTick(void)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!graphSpecies)\n        return;\n    \n    Population &population = graphSpecies->population_;\n    int registry_size;\n    const MutationIndex *registry = population.MutationRegistry(&registry_size);\n    const MutationIndex *registry_iter_end = registry + registry_size;\n    \n    // Check that the subpop and muttype we're supposed to be surveying exists; if not, bail.\n    bool hasSubpop = true, hasMuttype = true;\n    \n    if (!graphSpecies->SubpopulationWithID(selectedSubpopulationID_))\n        hasSubpop = addSubpopulationsToMenu(subpopulationButton_, selectedSubpopulationID_);\n    if (!graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_))\n        hasMuttype = addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    if (!hasSubpop || !hasMuttype)\n        return;\n    \n    // Start by zeroing out the \"updated\" flags; this is how we find dead mutations\n    for (auto &pair_ref : frequencyHistoryDict_)\n        pair_ref.second->updated = false;\n    \n    // Tally reference counts within selectedSubpopulationID_\n    size_t subpop_total_haplosome_count = tallyGUIMutationReferences(selectedSubpopulationID_, selectedMutationTypeIndex_);\n    \n    if (subpop_total_haplosome_count == 0)\n        subpop_total_haplosome_count = 1;  // refcounts will all be zero; prevent NAN values below, make them 0 instead\n    \n    // Now we can run through the mutations and use the tallies in gui_scratch_reference_count to update our histories\n    Mutation *mut_block_ptr = gSLiM_Mutation_Block;\n    \n    for (const MutationIndex *registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n    {\n        const Mutation *mutation = mut_block_ptr + *registry_iter;\n        slim_refcount_t refcount = mutation->gui_scratch_reference_count_;\n        \n        if (refcount)\n        {\n            uint16_t value = static_cast<uint16_t>((static_cast<size_t>(refcount) * static_cast<size_t>(UINT16_MAX)) / subpop_total_haplosome_count);\n            slim_mutationid_t mutationID = mutation->mutation_id_;\n            auto history_iter = frequencyHistoryDict_.find(mutationID);\n            \n            //NSLog(@\"mutation refcount %d has uint16_t value %d, found history %p for id %lld\", refcount, value, history, (long long int)mutation->mutation_id_);\n            \n            if (history_iter != frequencyHistoryDict_.end())\n            {\n                // We have a history for this mutation, so we just need to add an entry; this sets the updated flag\n                MutationFrequencyHistory *history = history_iter->second;\n                \n                history->addEntry(value);\n            }\n            else\n            {\n                // No history, so we make one starting at this tick; this also sets the updated flag\n                // Note we use community->Tick() - 1, because the tick counter has already been advanced to the next tick\n                MutationFrequencyHistory *history = new MutationFrequencyHistory(value, mutation, community->Tick() - 1);\n                \n                frequencyHistoryDict_.emplace(mutationID, history);\n            }\n        }\n    }\n    \n    // OK, now every mutation that has frequency >0 in our subpop has got a current entry.  But what about mutations that used to circulate,\n    // but don't any more?  These could still be active in a different subpop, or they might be gone – lost or fixed.  For the former case,\n    // we need to add an entry with frequency zero.  For the latter case, we need to put their history into \"cold storage\" for efficiency.\n    std::vector<MutationFrequencyHistory *> historiesToAddToColdStorage;\n    \n    for (auto entry_iter : frequencyHistoryDict_)\n    {\n        MutationFrequencyHistory *history = entry_iter.second;\n        \n        if (!history->updated)\n        {\n            slim_mutationid_t historyID = history->mutationID;\n            bool mutationStillExists = false;\n            \n            for (const MutationIndex *mutation_iter = registry; mutation_iter != registry_iter_end; ++mutation_iter)\n            {\n                const Mutation *mutation = mut_block_ptr + *mutation_iter;\n                slim_mutationid_t mutationID = mutation->mutation_id_;\n                \n                if (historyID == mutationID)\n                {\n                    mutationStillExists = true;\n                    break;\n                }\n            }\n            \n            if (mutationStillExists)\n            {\n                // The mutation is still around, so just add a zero entry for it\n                history->addEntry(0);\n            }\n            else\n            {\n                // The mutation is gone, so we need to put its history into cold storage, but we can't modify\n                // our dictionary since we are enumerating it, so we just make a record and do it below\n                historiesToAddToColdStorage.emplace_back(history);\n            }\n        }\n    }\n    \n    // Now, if historiesToAddToColdStorage is non-nil, we have histories to put into cold storage; do it now\n    for (MutationFrequencyHistory *history : historiesToAddToColdStorage)\n    {\n        // The remaining tricky bit is that we have to figure out whether the vanished mutation was fixed or lost; we do this by\n        // scanning through all our Substitution objects, which use the same unique IDs as Mutations use.  We need to know this\n        // for two reasons: to add the final entry for the mutation, and to put it into the correct cold storage array.\n        slim_mutationid_t mutationID = history->mutationID;\n        bool wasFixed = false;\n        \n        std::vector<Substitution*> &substitutions = population.substitutions_;\n        \n        for (const Substitution *substitution : substitutions)\n        {\n            if (substitution->mutation_id_ == mutationID)\n            {\n                wasFixed = true;\n                break;\n            }\n        }\n        \n        if (wasFixed)\n        {\n            history->addEntry(UINT16_MAX);\n            frequencyHistoryColdStorageFixed_.emplace_back(history);\n        }\n        else\n        {\n            history->addEntry(0);\n            frequencyHistoryColdStorageLost_.emplace_back(history);\n        }\n        \n        auto history_iter = frequencyHistoryDict_.find(mutationID);\n        frequencyHistoryDict_.erase(history_iter);\n    }\n    \n    //NSLog(@\"frequencyHistoryDict has %lld entries, frequencyHistoryColdStorageLost has %lld entries, frequencyHistoryColdStorageFixed has %lld entries\", (long long int)[frequencyHistoryDict count], (long long int)[frequencyHistoryColdStorageLost count], (long long int)[frequencyHistoryColdStorageFixed count]);\n    \n    lastTick_ = community->Tick();\n    justAddedToWindow_ = false;\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::subpopulationPopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulationButton_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulationID_ != newSubpopID))\n    {\n        selectedSubpopulationID_ = newSubpopID;\n        invalidateCachedData();\n        fetchDataForFinishedTick();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::mutationTypePopupChanged(int /* index */)\n{\n    int newMutTypeIndex = mutationTypeButton_->currentData().toInt();\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedMutationTypeIndex_ != newMutTypeIndex))\n    {\n        selectedMutationTypeIndex_ = newMutTypeIndex;\n        invalidateCachedData();\n        fetchDataForFinishedTick();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t{\n\t\t//if (!xAxisIsUserRescaled_)\n\t\t//\tsetXAxisRangeFromTick();\t// the end tick is not yet known\n\t\t\n\t\tupdate();\n\t}\n\t\n    // Remake our popups, whether or not the controller is valid\n\tinvalidateCachedData();\n\taddSubpopulationsToMenu(subpopulationButton_, selectedSubpopulationID_);\n\taddMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    \n    // We do not want to display our \"recycle to start gathering at the start\" message after a recycle\n    justAddedToWindow_ = false;\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::controllerTickFinished(void)\n{\n    QtSLiMGraphView::controllerTickFinished();\n    \n    // Check for an unexpected change in Tick(), in which case we invalidate all our histories and start over\n    Community *community = controller_->community;\n\t\n\tif (lastTick_ != community->Tick() - 1)\n\t{\n        invalidateCachedData();\n        update();\n    }\n\t\n\t// Fetch and store the frequencies for all mutations of the selected mutation type(s), within the subpopulation selected\n    fetchDataForFinishedTick();\n}\n\nQString QtSLiMGraphView_FrequencyTrajectory::graphTitle(void)\n{\n    return \"Mutation Frequency Trajectories\";\n}\n\nQString QtSLiMGraphView_FrequencyTrajectory::aboutString(void)\n{\n    return \"The Mutation Frequency Trajectories graph shows historical trajectories of mutation \"\n           \"frequencies over time, within a given subpopulation and for a given \"\n           \"mutation type.  Color represents whether a given mutation was \"\n           \"lost (red), fixed population-wide and substituted by SLiM (blue), or is \"\n           \"still segregating (black).  These categories can be separately enabled \"\n           \"or disabled in the action menu.  Because of the large amount of data \"\n           \"recorded for this graph, recording is only enabled when the graph is \"\n           \"open, and only for the selected subpopulation and mutation type; to \"\n           \"fill in missing data, it is necessary to recycle and run when the graph \"\n           \"window is already open and configured as desired.\";\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::updateAfterTick(void)\n{\n    // BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n    if (!xAxisIsUserRescaled_)\n        setXAxisRangeFromTick();\n    \n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n    // in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulationButton_, selectedSubpopulationID_);\n    addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n    \n    QtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_FrequencyTrajectory::disableMessage(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (graphSpecies)\n    {\n        // check that we have a valid subpop and muttype\n        bool hasSubpop = true, hasMuttype = true;\n        \n        if (!graphSpecies->SubpopulationWithID(selectedSubpopulationID_))\n            hasSubpop = addSubpopulationsToMenu(subpopulationButton_, selectedSubpopulationID_);\n        if (!graphSpecies->MutationTypeWithIndex(selectedMutationTypeIndex_))\n            hasMuttype = addMutationTypesToMenu(mutationTypeButton_, selectedMutationTypeIndex_);\n        if (!hasSubpop || !hasMuttype)\n            return \"no\\ndata\";\n        \n        // check that we have some history recorded\n        qDebug() << \"justAddedToWindow_ ==\" << justAddedToWindow_;\n        \n        if (justAddedToWindow_)\n            return \"initiating data collection;\\nrecycle and run to\\ncollect data from the\\nstart of the simulation\";\n    }\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::drawHistory(QPainter &painter, MutationFrequencyHistory *history, QRect interiorRect)\n{\n    size_t entryCount = history->entryCount;\n\t\n\tif (entryCount > 1)\t\t// one entry just generates a moveto\n\t{\n\t\tuint16_t *entries = history->entries;\n        QPainterPath linePath;\n\t\tuint16_t firstValue = *entries;\n\t\tdouble firstFrequency = static_cast<double>(firstValue) / UINT16_MAX;\n\t\tslim_tick_t tick = history->baseTick;\n\t\tQPointF firstPoint(plotToDeviceX(tick, interiorRect), plotToDeviceY(firstFrequency, interiorRect));\n\t\t\n        linePath.moveTo(firstPoint);\n\t\t\n\t\tfor (size_t entryIndex = 1; entryIndex < entryCount; ++entryIndex)\n\t\t{\n\t\t\tuint16_t value = entries[entryIndex];\n\t\t\tdouble frequency = static_cast<double>(value) / UINT16_MAX;\n\t\t\tQPointF nextPoint(plotToDeviceX(++tick, interiorRect), plotToDeviceY(frequency, interiorRect));\n\t\t\t\n            linePath.lineTo(nextPoint);\n\t\t}\n\t\t\n        painter.drawPath(linePath);\n\t}\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    painter.setBrush(Qt::NoBrush);\n    painter.setPen(QPen(Qt::black, 1.0));\n    \n\t// Go through all our history entries and draw a line for each.  First we draw the ones in cold storage, then the active ones.\n\tif (plotLostMutations_)\n\t{\n\t\tif (useColorsForPlotting_)\n            painter.setPen(QPen(Qt::red, 1.0));\n\t\t\n        for (MutationFrequencyHistory *history : frequencyHistoryColdStorageLost_)\n            drawHistory(painter, history, interiorRect);\n\t}\n\t\n\tif (plotFixedMutations_)\n\t{\n\t\tif (useColorsForPlotting_)\n            painter.setPen(QPen(QtSLiMColorWithRGB(0.4, 0.4, 1.0, 1.0), 1.0));\n\t\t\n        for (MutationFrequencyHistory *history : frequencyHistoryColdStorageFixed_)\n            drawHistory(painter, history, interiorRect);\n\t}\n\t\n\tif (plotActiveMutations_)\n\t{\n\t\tif (useColorsForPlotting_)\n            painter.setPen(QPen(Qt::black, 1.0));\n\t\t\n        for (auto history_pair : frequencyHistoryDict_)\n            drawHistory(painter, history_pair.second, interiorRect);\n\t}\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::toggleShowLostMutations(void)\n{\n    plotLostMutations_ = !plotLostMutations_;\n    update();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::toggleShowFixedMutations(void)\n{\n    plotFixedMutations_ = !plotFixedMutations_;\n    update();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::toggleShowActiveMutations(void)\n{\n    plotActiveMutations_ = !plotActiveMutations_;\n    update();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::toggleUseColorsForPlotting(void)\n{\n    useColorsForPlotting_ = !useColorsForPlotting_;\n    update();\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(plotLostMutations_ ? \"Hide Lost Mutations\" : \"Show Lost Mutations\", this, &QtSLiMGraphView_FrequencyTrajectory::toggleShowLostMutations);\n    contextMenu.addAction(plotFixedMutations_ ? \"Hide Fixed Mutations\" : \"Show Fixed Mutations\", this, &QtSLiMGraphView_FrequencyTrajectory::toggleShowFixedMutations);\n    contextMenu.addAction(plotActiveMutations_ ? \"Hide Active Mutations\" : \"Show Active Mutations\", this, &QtSLiMGraphView_FrequencyTrajectory::toggleShowActiveMutations);\n    contextMenu.addSeparator();\n    contextMenu.addAction(useColorsForPlotting_ ? \"Black Plot Lines\" : \"Colored Plot Lines\", this, &QtSLiMGraphView_FrequencyTrajectory::toggleUseColorsForPlotting);\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_FrequencyTrajectory::legendKey(void)\n{\n\tif (!useColorsForPlotting_)\n\t\treturn QtSLiMLegendSpec();\n\t\n\tQtSLiMLegendSpec legend_key;\n\t\n\tif (plotLostMutations_)\n\t\tlegend_key.emplace_back(\"lost\", Qt::red);\n\t\n\tif (plotFixedMutations_)\n\t\tlegend_key.emplace_back(\"fixed\", QtSLiMColorWithRGB(0.4, 0.4, 1.0, 1.0));\n\t\n\tif (plotActiveMutations_)\n\t\tlegend_key.emplace_back(\"active\", Qt::black);\n\t\n\treturn legend_key;\n}\n\nbool QtSLiMGraphView_FrequencyTrajectory::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::appendEntriesToString(std::vector<MutationFrequencyHistory *> &array, QString &string, slim_tick_t completedTicks)\n{\n    for (MutationFrequencyHistory *history : array)\n    {\n        int entryCount = static_cast<int>(history->entryCount);\n\t\tslim_tick_t baseTick = history->baseTick;\n\t\t\n\t\tfor (slim_tick_t tick = 1; tick <= completedTicks; ++tick)\n\t\t{\n\t\t\tif (tick < baseTick)\n                string.append(\"NA, \");\n\t\t\telse if (tick - baseTick < entryCount)\n                string.append(QString(\"%1, \").arg(static_cast<double>(history->entries[tick - baseTick]) / UINT16_MAX, 0, 'f', 4));\n\t\t\telse\n                string.append(\"NA, \");\n\t\t}\n\t\t\n        string.append(\"\\n\");\n    }\n}\n\nvoid QtSLiMGraphView_FrequencyTrajectory::appendStringForData(QString &string)\n{\n    Community *community = controller_->community;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n    if (plotLostMutations_)\n\t{\n\t\tstring.append(\"# Lost mutations:\\n\");\n\t\tappendEntriesToString(frequencyHistoryColdStorageLost_, string, completedTicks);\n        string.append(\"\\n\\n\");\n\t}\n\t\n\tif (plotFixedMutations_)\n\t{\n\t\tstring.append(\"# Fixed mutations:\\n\");\n\t\tappendEntriesToString(frequencyHistoryColdStorageFixed_, string, completedTicks);\n        string.append(\"\\n\\n\");\n\t}\n\t\n\tif (plotActiveMutations_)\n\t{\n\t\tstring.append(\"# Active mutations:\\n\");\n        \n        std::vector<MutationFrequencyHistory *> allActive;\n        \n        for (auto &pair_ref : frequencyHistoryDict_)\n            allActive.emplace_back(pair_ref.second);\n        \n\t\tappendEntriesToString(allActive, string, completedTicks);\n        string.append(\"\\n\\n\");\n\t}\n}\n\n\n//\n//  MutationFrequencyHistory\n//\n\nMutationFrequencyHistory::MutationFrequencyHistory(uint16_t value, const Mutation *mutation, slim_tick_t tick)\n{\n    mutationID = mutation->mutation_id_;\n    mutationType = mutation->mutation_type_ptr_;\n    baseTick = tick;\n    \n    bufferSize = 0;\n    entryCount = 0;\n    entries = nullptr;\n    \n    addEntry(value);\n}\n\nMutationFrequencyHistory::~MutationFrequencyHistory()\n{\n\tif (entries)\n\t{\n\t\tfree(entries);\n\t\tentries = nullptr;\n\t\t\n\t\tbufferSize = 0;\n\t\tentryCount = 0;\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_FrequencyTrajectory.h",
    "content": "//\n//  QtSLiMGraphView_FrequencyTrajectory.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/1/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_FREQUENCYTRAJECTORY_H\n#define QTSLIMGRAPHVIEW_FREQUENCYTRAJECTORY_H\n\n#include <QWidget>\n#include <unordered_map>\n#include <vector>\n\n#include \"QtSLiMGraphView.h\"\n#include \"mutation.h\"\n#include \"mutation_type.h\"\n\nclass MutationFrequencyHistory;\n\n\nclass QtSLiMGraphView_FrequencyTrajectory : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_FrequencyTrajectory(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_FrequencyTrajectory() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void invalidateCachedData(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void controllerTickFinished(void) override;\n    virtual void updateAfterTick(void) override;\n    void toggleShowLostMutations(void);\n    void toggleShowFixedMutations(void);\n    void toggleShowActiveMutations(void);\n    void toggleUseColorsForPlotting(void);\n    void subpopulationPopupChanged(int index);\n    void mutationTypePopupChanged(int index);\n    \nprotected:\n    virtual QtSLiMLegendSpec legendKey(void) override;    \n    \nprivate:\n    // Mutation history storage\n    std::unordered_map<slim_mutationid_t, MutationFrequencyHistory *> frequencyHistoryDict_;    // unordered_map of active MutationFrequencyHistory objects, with slim_mutationid_t keys\n    std::vector<MutationFrequencyHistory *> frequencyHistoryColdStorageLost_;                   // vector of MutationFrequencyHistory objects that have been lost\n    std::vector<MutationFrequencyHistory *> frequencyHistoryColdStorageFixed_;                  // vector of MutationFrequencyHistory objects that have been fixed\n    slim_tick_t lastTick_ = 0;                                                                  // the last tick data was gathered for; used to detect a backward move in time\n    bool justAddedToWindow_ = true;                                                             // true when the plot window has just been created\n    \n    // pop-up menu buttons\n    QComboBox *subpopulationButton_ = nullptr;\n\tQComboBox *mutationTypeButton_ = nullptr;\n    \n    // The subpop and mutation type selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulationID_;\n    int selectedMutationTypeIndex_;\n    \n    // User-selected display prefs\n    bool plotLostMutations_ = false;\n    bool plotFixedMutations_ = false;\n    bool plotActiveMutations_ = false;\n    bool useColorsForPlotting_ = false;\n    \n    void fetchDataForFinishedTick(void);\n    void drawHistory(QPainter &painter, MutationFrequencyHistory *history, QRect interiorRect);\n    void appendEntriesToString(std::vector<MutationFrequencyHistory *> &array, QString &string, slim_tick_t completedTicks);\n};\n\n\n// We want to keep a history of frequency values for each mutation of the chosen mutation type in the\n// chosen subpopulation.  The history of a mutation should persist after it has vanished, and if a\n// new mutation object gets allocated at the same memory location, it should be treated as a distinct\n// mutation; so we can't use pointers to identify mutations.  Instead, we keep data on them using a\n// unique 64-bit ID generated only when SLiM is running under SLiMgui.  At the end of a tick,\n// we loop through all mutations in the registry, and add an entry for that mutation in our data store.\n// This is probably O(n^2), but so it goes.  It should only be used for mutation types that generate\n// few mutations; if somebody tries to plot every mutation in a common mutation-type, they will suffer.\n\nclass MutationFrequencyHistory\n{\npublic:\n\t// The 64-bit mutation ID is how we keep track of the mutation we reference; its pointer might go stale and be reused.\n\tslim_mutationid_t mutationID;\n\t\n    // We keep a flag that we use to figure out if our mutation is dead; if it is, we can be moved into cold storage.\n\tbool updated;\n    \n\t// Mostly we are just a malloced array of uint16s.  The data we're storing is doubles, conceptually, but to minimize our memory footprint\n\t// (which might be very large!) we convert the doubles, which are guaranteed to be in the range [0.0, 1.0], to uint16s in the range\n\t// [0, UINT16_MAX] (65535).  The buffer size is the number of entries allocated, the entry count is the number used so far, and the\n\t// base tick is the first tick recorded; the assumption is that entries are then sequential without gaps.\n\tuint32_t bufferSize, entryCount;\n\tslim_tick_t baseTick;\n\tuint16_t *entries;\n\t\n\t// Remember our mutation type so we can set our line color, etc., if we wish\n\tconst MutationType *mutationType;\n\t\npublic:\n    MutationFrequencyHistory(uint16_t value, const Mutation *mutation, slim_tick_t tick);\n    ~MutationFrequencyHistory();\n    \n    inline void addEntry(uint16_t value)\n    {\n        if (entryCount == bufferSize)\n        {\n            // We need to expand\n            bufferSize += 1024;\n            entries = static_cast<uint16_t *>(realloc(entries, bufferSize * sizeof(uint16_t)));\n        }\n        \n        entries[entryCount++] = value;\n        updated = true;\n    }\n};\n\n\n#endif // QTSLIMGRAPHVIEW_FREQUENCYTRAJECTORY_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_LifetimeReproduction.cpp",
    "content": "//\n//  QtSLiMGraphView_LifetimeReproduction.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 11/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_LifetimeReproduction.h\"\n\n#include <QComboBox>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QApplication>\n#include <QGuiApplication>\n#include <QDebug>\n\n#include <string>\n#include <algorithm>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n\n\nQtSLiMGraphView_LifetimeReproduction::QtSLiMGraphView_LifetimeReproduction(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 11;        // max reproductive output (from 0 to 10); this rescales automatically\n    allowBinCountRescale_ = false;\n    \n    original_x0_ = -1;                 // zero is included\n    original_x1_ = histogramBinCount_ - 1;\n    \n    x0_ = original_x0_;\n    x1_ = original_x1_;\n    \n    xAxisMin_ = x0_;\n    xAxisMax_ = x1_;\n    xAxisHistogramStyle_ = true;\n    xAxisTickValuePrecision_ = 0;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    xAxisLabel_ = \"Lifetime reproduction\";\n    yAxisLabel_ = \"Frequency\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = false;\n    \n    showHorizontalGridLines_ = true;\n    allowHorizontalGridChange_ = true;\n    allowVerticalGridChange_ = false;\n    allowFullBoxChange_ = true;\n    \n    selectedSubpopulation1ID_ = 1;\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::addedToWindow(void)\n{\n    // Make our pop-up menu buttons\n    QHBoxLayout *button_layout = buttonLayout();\n    \n    if (button_layout)\n    {\n        subpopulation1Button_ = newButtonInLayout(button_layout);\n        connect(subpopulation1Button_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &QtSLiMGraphView_LifetimeReproduction::subpopulation1PopupChanged);\n        \n        addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    }\n}\n\nQtSLiMGraphView_LifetimeReproduction::~QtSLiMGraphView_LifetimeReproduction()\n{\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::subpopulation1PopupChanged(int /* index */)\n{\n    slim_objectid_t newSubpopID = SLiMClampToObjectidType(subpopulation1Button_->currentData().toInt());\n    \n    // don't react to non-changes and changes during rebuilds\n    if (!rebuildingMenu_ && (selectedSubpopulation1ID_ != newSubpopID))\n    {\n        selectedSubpopulation1ID_ = newSubpopID;\n        \n        // Reset our autoscaling x axis\n        histogramBinCount_ = 11;\n        xAxisMax_ = histogramBinCount_ - 1;\n        original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n        x1_ = original_x1_;\n        \n        invalidateCachedData();\n        update();\n    }\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t\tupdate();\n    \n    // Remake our popups, whether or not the controller is valid\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n    \n    // Reset our autoscaling x axis\n    histogramBinCount_ = 11;\n    xAxisMax_ = histogramBinCount_ - 1;\n    original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n    x1_ = original_x1_;\n    \n    // Reset our autoscaling y axis\n    yAxisMax_ = 1.0;\n    original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n    y1_ = original_y1_;\n    yAxisMajorTickInterval_ = 0.5;\n    yAxisMinorTickInterval_ = 0.25;\n    \n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_LifetimeReproduction::graphTitle(void)\n{\n    return \"Lifetime Reproductive Output\";\n}\n\nQString QtSLiMGraphView_LifetimeReproduction::aboutString(void)\n{\n    return \"The Lifetime Reproductive Output graph shows the distribution of lifetime reproductive output within \"\n           \"a chosen subpopulation, for individuals that died in the last tick.  The x axis is individual \"\n           \"lifetime reproductive output; the y axis is the frequency of a given lifetime reproductive output \"\n           \"in the population, normalized to a total of 1.0.\";\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::updateAfterTick(void)\n{\n    // Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n    addSubpopulationsToMenu(subpopulation1Button_, selectedSubpopulation1ID_);\n\t\n    invalidateCachedData();\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nQString QtSLiMGraphView_LifetimeReproduction::disableMessage(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (graphSpecies)\n    {\n        if (graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_) == nullptr)\n            return \"no\\ndata\";\n    }\n    \n    return \"\";\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n\tdouble *reproductionDist = reproductionDistribution(&binCount, tallySexesSeparately);\n    int totalBinCount = tallySexesSeparately ? (binCount * 2) : binCount;\n\t\n    if (reproductionDist)\n    {\n        // rescale the x axis if needed\n        if (binCount != histogramBinCount_)\n        {\n            histogramBinCount_ = binCount;\n            xAxisMax_ = histogramBinCount_ - 1;\n            original_x1_ = xAxisMax_;               // the same as xAxisMax_, for base plots\n            x1_ = original_x1_;\n            invalidateCachedData();\n        }\n        \n        // rescale the y axis if needed\n        double maxFreq = 0.000000001;   // guarantee a non-zero axis range\n        \n        for (int binIndex = 0; binIndex < totalBinCount; ++binIndex)\n            maxFreq = std::max(maxFreq, reproductionDist[binIndex]);\n        \n        double ceilingFreq = std::ceil(maxFreq * 5.0) / 5.0;    // 0.2 / 0.4 / 0.6 / 0.8 / 1.0\n        \n        if ((ceilingFreq > yAxisMax_) ||\n                ((ceilingFreq < yAxisMax_) && (maxFreq + 0.05 < ceilingFreq)))    // require a margin of error to jump down\n        {\n            yAxisMax_ = ceilingFreq;\n            original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n            y1_ = original_y1_;\n            yAxisMajorTickInterval_ = ceilingFreq / 2.0;\n            yAxisMinorTickInterval_ = ceilingFreq / 4.0;\n        }\n        \n        // plot our histogram bars; note that xAxisMin_ is -1 so we use that as a minimum\n        if (tallySexesSeparately)\n            drawGroupedBarplot(painter, interiorRect, reproductionDist, 2, histogramBinCount_, -1.0, 1.0);\n        else\n            drawBarplot(painter, interiorRect, reproductionDist, histogramBinCount_, -1.0, 1.0);\n        \n        free(reproductionDist);\n    }\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_LifetimeReproduction::legendKey(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n    \n\tif (tallySexesSeparately)\n    {\n        QtSLiMLegendSpec legend_key;\n        \n        legend_key.emplace_back(\"M\", controller_->blackContrastingColorForIndex(0));\n        legend_key.emplace_back(\"F\", controller_->blackContrastingColorForIndex(1));\n        \n        return legend_key;\n    }\n    else\n    {\n        return QtSLiMLegendSpec();\n    }\n}\n\nbool QtSLiMGraphView_LifetimeReproduction::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_LifetimeReproduction::appendStringForData(QString &string)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    bool tallySexesSeparately = graphSpecies->sex_enabled_;\n\tdouble *reproductionDist = reproductionDistribution(&binCount, tallySexesSeparately);\n\t\n    if (reproductionDist)\n    {\n        if (tallySexesSeparately)\n        {\n            string.append(\"M : \");\n            \n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(reproductionDist[i * 2], 0, 'f', 4));\n            \n            string.append(\"\\n\\nF : \");\n            \n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(reproductionDist[i * 2 + 1], 0, 'f', 4));\n        }\n        else\n        {\n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(reproductionDist[i], 0, 'f', 4));\n        }\n        \n        free(reproductionDist);\n    }\n    \n    string.append(\"\\n\");\n}\n\ndouble *QtSLiMGraphView_LifetimeReproduction::reproductionDistribution(int *binCount, bool tallySexesSeparately)\n{\n    // Find our subpop\n    Species *graphSpecies = focalDisplaySpecies();\n    Subpopulation *subpop1 = graphSpecies->SubpopulationWithID(selectedSubpopulation1ID_);\n    \n    if (!subpop1)\n        return nullptr;\n    \n    // Find the maximum reproductive output and choose the new bin count\n    int32_t maxReproduction = 0;\n    \n    for (int32_t reproduction : subpop1->lifetime_reproductive_output_F_)\n        maxReproduction = std::max(maxReproduction, reproduction);\n    for (int32_t reproduction : subpop1->lifetime_reproductive_output_MH_)\n        maxReproduction = std::max(maxReproduction, reproduction);\n    \n    // compare to the logic in QtSLiMGraphView_AgeDistribution::ageDistribution();\n    // it is different here because reproduction count 0 gets a bin, so if the\n    // max reproduction is 12, we need 13 bins; confusing!\n    if (maxReproduction >= *binCount)\n        *binCount = (int)(std::ceil(maxReproduction / 10.0) * 10.0 + 1);    // +1 because zero gets an entry\n    \n    int newBinCount = *binCount;\n    \n    // Tally into our bins\n    int totalBinCount = (tallySexesSeparately ? newBinCount * 2 : newBinCount);\n    double *reproductionTallies = static_cast<double *>(calloc(totalBinCount, sizeof(double)));\n    \n    for (int reproduction : subpop1->lifetime_reproductive_output_F_)\n    {\n        if (tallySexesSeparately)\n            reproductionTallies[reproduction * 2 + 1]++;\n        else\n            reproductionTallies[reproduction]++;\n    }\n    for (int reproduction : subpop1->lifetime_reproductive_output_MH_)\n    {\n        if (tallySexesSeparately)\n            reproductionTallies[reproduction * 2]++;\n        else\n            reproductionTallies[reproduction]++;\n    }\n    \n    // Normalize to 1\n    \n    if (tallySexesSeparately)\n    {\n        // males\n        double totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += reproductionTallies[i * 2];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                reproductionTallies[i * 2] /= totalTallies;\n        \n        // females\n        totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += reproductionTallies[i * 2 + 1];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                reproductionTallies[i * 2 + 1] /= totalTallies;\n    }\n    else\n    {\n        double totalTallies = 0.0;\n        \n        for (int i = 0; i < newBinCount; ++i)\n            totalTallies += reproductionTallies[i];\n        \n        if (totalTallies > 0.0)\n            for (int i = 0; i < newBinCount; ++i)\n                reproductionTallies[i] /= totalTallies;\n    }\n    \n    // Return the final tally; note that the caller takes ownership of the buffer\n\treturn reproductionTallies;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_LifetimeReproduction.h",
    "content": "//\n//  QtSLiMGraphView_LifetimeReproduction.h\n//  SLiM\n//\n//  Created by Ben Haller on 11/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_LIFETIMEREPRODUCTION_H\n#define QTSLIMGRAPHVIEW_LIFETIMEREPRODUCTION_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_LifetimeReproduction : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_LifetimeReproduction(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_LifetimeReproduction() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual QString disableMessage(void) override;\n    \npublic slots:\n    virtual void addedToWindow(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void subpopulation1PopupChanged(int index);\n    \nprivate:\n    // pop-up menu buttons\n    QComboBox *subpopulation1Button_ = nullptr;\n    \n    // The subpop selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n    slim_objectid_t selectedSubpopulation1ID_;\n    \n    double *reproductionDistribution(int *binCount, bool tallySexesSeparately);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_LIFETIMEREPRODUCTION_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_LossTimeHistogram.cpp",
    "content": "//\n//  QtSLiMGraphView_LossTimeHistogram.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_LossTimeHistogram.h\"\n\n#include <string>\n\n#include \"QtSLiMWindow.h\"\n\n\nQtSLiMGraphView_LossTimeHistogram::QtSLiMGraphView_LossTimeHistogram(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 10;\n    //allowBinCountRescale_ = true;     // not supported yet\n    \n    original_x1_ = 100;\n    x1_ = original_x1_;\n    \n    xAxisMax_ = x1_;\n    xAxisMajorTickInterval_ = 20;\n    xAxisMinorTickInterval_ = 10;\n    xAxisMajorTickModulus_ = 2;\n    xAxisTickValuePrecision_ = 0;\n    \n    xAxisLabel_ = \"Mutation loss time\";\n    yAxisLabel_ = \"Proportion of lost mutations\";\n    \n    allowXAxisUserRescale_ = false;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n}\n\nQtSLiMGraphView_LossTimeHistogram::~QtSLiMGraphView_LossTimeHistogram()\n{\n}\n\nQString QtSLiMGraphView_LossTimeHistogram::graphTitle(void)\n{\n    return \"Mutation Loss Time\";\n}\n\nQString QtSLiMGraphView_LossTimeHistogram::aboutString(void)\n{\n    return \"The Mutation Loss Time graph shows a histogram of mutation loss times, for \"\n           \"those mutations that have been lost.  The proportions are calculated and plotted \"\n           \"separately for each mutation type, for comparison.\";\n}\n\ndouble *QtSLiMGraphView_LossTimeHistogram::lossTimeData(void)\n{\n    int binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n\tint mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\tslim_tick_t *histogram = graphSpecies->population_.mutation_loss_times_;\n\tint64_t histogramBins = static_cast<int64_t>(graphSpecies->population_.mutation_loss_tick_slots_);\t// fewer than binCount * mutationTypeCount may exist\n\tstatic double *rebin = nullptr;\n\tstatic size_t rebinBins = 0;\n\tsize_t usedRebinBins = static_cast<size_t>(binCount * mutationTypeCount);\n\t\n\t// re-bin for display; use double, normalize, etc.\n\tif (!rebin || (rebinBins < usedRebinBins))\n\t{\n\t\trebinBins = usedRebinBins;\n\t\trebin = static_cast<double *>(realloc(rebin, rebinBins * sizeof(double)));\n\t}\n\t\n\tfor (size_t i = 0; i < usedRebinBins; ++i)\n\t\trebin[i] = 0.0;\n\t\n\tfor (int i = 0; i < binCount; ++i)\n\t{\n\t\tfor (int j = 0; j < mutationTypeCount; ++j)\n\t\t{\n\t\t\tint histIndex = j + i * mutationTypeCount;\n\t\t\t\n\t\t\tif (histIndex < histogramBins)\n\t\t\t\trebin[histIndex] += histogram[histIndex];\n\t\t}\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tint64_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += static_cast<int64_t>(rebin[binIndex]);\n\t\t}\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\trebin[binIndex] /= static_cast<double>(total);\n\t\t}\n\t}\n\t\n\treturn rebin;\n}\n\nvoid QtSLiMGraphView_LossTimeHistogram::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    double *plotData = lossTimeData();\n\tint binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    int mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\t\n\t// plot our histogram bars\n\tdrawGroupedBarplot(painter, interiorRect, plotData, mutationTypeCount, binCount, 0.0, 10.0);\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_LossTimeHistogram::legendKey(void)\n{\n\treturn mutationTypeLegendKey();     // we use the prefab mutation type legend\n}\n\nbool QtSLiMGraphView_LossTimeHistogram::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_LossTimeHistogram::appendStringForData(QString &string)\n{\n\tdouble *plotData = lossTimeData();\n\tint binCount = histogramBinCount_;\n    Species *graphSpecies = focalDisplaySpecies();\n    int mutationTypeCount = static_cast<int>(graphSpecies->mutation_types_.size());\n\t\n\tfor (auto mutationTypeIter : graphSpecies->mutation_types_)\n\t{\n\t\tMutationType *mutationType = mutationTypeIter.second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n        string.append(QString(\"\\\"m%1\\\", \").arg(mutationType->mutation_type_id_));\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n            string.append(QString(\"%1, \").arg(plotData[histIndex], 0, 'f', 4));\n\t\t}\n\t\t\n        string.append(\"\\n\");\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_LossTimeHistogram.h",
    "content": "//\n//  QtSLiMGraphView_LossTimeHistogram.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_LOSSTIMEHISTOGRAM_H\n#define QTSLIMGRAPHVIEW_LOSSTIMEHISTOGRAM_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_LossTimeHistogram : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_LossTimeHistogram(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_LossTimeHistogram() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual QtSLiMLegendSpec legendKey(void) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    \nprivate:\n    double *lossTimeData(void);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_LOSSTIMEHISTOGRAM_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_MultispeciesPopSizeOverTime.cpp",
    "content": "//\n//  QtSLiMGraphView_MultispeciesPopSizeOverTime.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/25/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_MultispeciesPopSizeOverTime.h\"\n\n#include <QAction>\n#include <QMenu>\n#include <QPixmap>\n#include <QPainterPath>\n#include <QDebug>\n\n#include <string>\n#include <vector>\n#include <algorithm>\n\n#include \"QtSLiMWindow.h\"\n\n\nQtSLiMGraphView_MultispeciesPopSizeOverTime::QtSLiMGraphView_MultispeciesPopSizeOverTime(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    // super assumes that we are species-specific; we tell it we are not\n    setFocalDisplaySpecies(nullptr);\n    \n    //setXAxisRangeFromTick();\t// the end tick is not yet known\n    setDefaultYAxisRange();\n    \n    xAxisLabel_ = \"Tick\";\n    yAxisLabel_ = \"Number of individuals\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    showSubpopulations_ = true;\n    drawLines_ = true;\n    \n    QtSLiMGraphView_MultispeciesPopSizeOverTime::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::setDefaultYAxisRange(void)\n{\n    original_y0_ = 0.0;\n    original_y1_ = 100.0;\t\t// dynamic\n    \n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    yAxisMin_ = y0_;\n\tyAxisMax_ = y1_;\n\tyAxisMajorTickInterval_ = 50;\n\tyAxisMinorTickInterval_ = 10;\n\tyAxisMajorTickModulus_ = 5;\n\tyAxisTickValuePrecision_ = 0;\n}\n\nQtSLiMGraphView_MultispeciesPopSizeOverTime::~QtSLiMGraphView_MultispeciesPopSizeOverTime()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_MultispeciesPopSizeOverTime::invalidateDrawingCache();\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::invalidateDrawingCache(void)\n{\n    delete drawingCache_;\n\tdrawingCache_ = nullptr;\n\tdrawingCacheTick_ = 0;\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t{\n\t\tif (!yAxisIsUserRescaled_)\n\t\t\tsetDefaultYAxisRange();\n\t\t//if (!xAxisIsUserRescaled_)\n\t\t//\tsetXAxisRangeFromTick();\t// the end tick is not yet known\n\t\t\n\t\tupdate();\n\t}\n\t\n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_MultispeciesPopSizeOverTime::graphTitle(void)\n{\n    return \"Multispecies Population Size ~ Time\";\n}\n\nQString QtSLiMGraphView_MultispeciesPopSizeOverTime::aboutString(void)\n{\n    return \"The Multispecies Population Size ~ Time graph shows species (and subpopulation) \"\n           \"size as a function of time.  The size of each species is shown with a thick \"\n           \"bright line, while those of subpopulations are shown with thinner pastel lines.\";\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::updateAfterTick(void)\n{\n    // BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n    if (!controller_->invalidSimulation() && !xAxisIsUserRescaled_)\n        setXAxisRangeFromTick();\n    \n    if (!controller_->invalidSimulation() && !yAxisIsUserRescaled_)\n    {\n        Community *community = controller_->community;\n        slim_popsize_t maxHistory = 0;\n        \n        for (Species *species : community->all_species_)\n        {\n            Population &pop = species->population_;\n            bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n            \n            for (auto history_record_iter : pop.subpop_size_histories_)\n            {\n                if (showSubpops || (history_record_iter.first == -1))\n                {\n                    SubpopSizeHistory &history_record = history_record_iter.second;\n                    slim_popsize_t *history = history_record.history_;\n                    slim_tick_t historyLength = history_record.history_length_;\n                    \n                    // find the min and max history value\n                    for (int i = 0; i < historyLength; ++i)\n                        maxHistory = std::max(maxHistory, history[i]);\n                }\n            }\n        }\n\t\t\n\t\t// set axis range to encompass the data\n        if (maxHistory > yAxisMax_)\n        {\n            if (maxHistory <= 1000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 100.0) * 100.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 200;\n                yAxisMinorTickInterval_ = 100;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else if (maxHistory <= 10000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 1000.0) * 1000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 2000;\n                yAxisMinorTickInterval_ = 1000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else if (maxHistory <= 100000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 10000.0) * 10000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 20000;\n                yAxisMinorTickInterval_ = 10000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 100000.0) * 100000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 200000;\n                yAxisMinorTickInterval_ = 100000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            \n            QtSLiMGraphView_MultispeciesPopSizeOverTime::invalidateDrawingCache();\n        }\n    }\n\t\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::drawPointGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// The tick counter can get set backwards, in which case our drawing cache is invalid – it contains drawing of things in the\n\t// future that may no longer happen.  So we need to detect that case and invalidate our cache.\n\tif (!cachingNow_ && drawingCache_ && (drawingCacheTick_ > completedTicks))\n\t{\n\t\t//qDebug() << \"backward tick change detected, invalidating drawing cache\";\n\t\tinvalidateDrawingCache();\n\t}\n\t\n\t// If we're not caching, then: if our cache is invalid OR we have crossed a 1000-tick boundary since we last cached, cache an image\n\tif (!cachingNow_ && (!drawingCache_ || ((completedTicks / 1000) > (drawingCacheTick_ / 1000))))\n\t{\n        invalidateDrawingCache();\n\t\t\n        //qDebug() << \"making new cache at tick \" << community->Tick();\n\t\tcachingNow_ = true;\n        \n\t\tQPixmap *cache = new QPixmap(interiorRect.size());\n        cache->fill(Qt::transparent);   // transparent so grid lines don't get overwritten by drawPixmap()\n        \n        QPainter cachePainter(cache);\n        drawGraph(cachePainter, cache->rect());\n        \n        drawingCache_ = cache;\n\t\tdrawingCacheTick_ = completedTicks;\n\t\tcachingNow_ = false;\n\t}\n\t\n\t// Now draw our cache, if we have one\n\tif (drawingCache_)\n    {\n        //qDebug() << \"drawing cache:\" << drawingCache_->rect() << \", drawingCacheTick_ == \" << drawingCacheTick_;\n        painter.drawPixmap(interiorRect, *drawingCache_, drawingCache_->rect());\n    }\n    \n\t// Draw the size history as a scatter plot; better suited to caching of the image\n    for (Species *species : community->all_species_)\n    {\n        Population &pop = species->population_;\n        bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n        \n        // First draw subpops, then draw the population size\n        for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n        {\n            QColor speciesColor = controller_->qcolorForSpecies(species);\n            QColor pointColor = (iter == 0) ? speciesColor.lighter(150) : speciesColor;\n            \n            for (auto history_record_iter : pop.subpop_size_histories_)\n            {\n                if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n                {\n                    SubpopSizeHistory &history_record = history_record_iter.second;\n                    slim_popsize_t *history = history_record.history_;\n                    slim_tick_t historyLength = history_record.history_length_;\n                    \n                    // If we're caching now, draw all points; otherwise, if we have a cache, draw only additional points\n                    slim_tick_t firstHistoryEntryToDraw = (cachingNow_ ? 0 : (drawingCache_ ? drawingCacheTick_ : 0));\n                    \n                    for (slim_tick_t i = firstHistoryEntryToDraw; (i < historyLength) && (i < completedTicks); ++i)\n                    {\n                        slim_popsize_t historyEntry = history[i];\n                        \n                        if (historyEntry != 0)\n                        {\n                            QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                            \n                            painter.fillRect(QRectF(historyPoint.x() - 0.5, historyPoint.y() - 0.5, 1.0, 1.0), pointColor);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::drawLineGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n    \n    for (Species *species : community->all_species_)\n    {\n        Population &pop = species->population_;\n        slim_tick_t completedTicks = community->Tick() - 1;\n        \n        // Draw the size history as a line plot\n        bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n        \n        // First draw subpops, then draw the population size\n        for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n        {\n            QColor speciesColor = controller_->qcolorForSpecies(species);\n            QColor lineColor = (iter == 0) ? speciesColor.lighter(150) : speciesColor;\n            double lineWidth = (iter == 0) ? 1.0 : 1.5;\n            \n            for (auto history_record_iter : pop.subpop_size_histories_)\n            {\n                if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n                {\n                    SubpopSizeHistory &history_record = history_record_iter.second;\n                    slim_popsize_t *history = history_record.history_;\n                    slim_tick_t historyLength = history_record.history_length_;\n                    QPainterPath linePath;\n                    bool startedLine = false;\n                    \n                    for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                    {\n                        slim_popsize_t historyEntry = history[i];\n                        \n                        if (historyEntry == 0)\n                        {\n                            startedLine = false;\n                        }\n                        else\n                        {\n                            QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                            \n                            if (startedLine)    linePath.lineTo(historyPoint);\n                            else                linePath.moveTo(historyPoint);\n                            \n                            startedLine = true;\n                        }\n                    }\n                    \n                    painter.strokePath(linePath, QPen(lineColor, lineWidth));\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    if (drawLines_)\n\t\tdrawLineGraph(painter, interiorRect);\n\telse\n\t\tdrawPointGraph(painter, interiorRect);\n}\n\nbool QtSLiMGraphView_MultispeciesPopSizeOverTime::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::appendStringForData(QString &string)\n{\n    Community *community = controller_->community;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n    // Size history\n    for (Species *species : community->all_species_)\n    {\n        QString speciesName = QString::fromStdString(species->name_);\n        Population &pop = species->population_;\n        bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n        \n        string.append(QString(\"\\n\\n# Size history (species %1):\\n\").arg(speciesName));\n        \n        for (int iter = 0; iter <= (showSubpops ? 1 : 0); ++iter)\n        {\n            for (auto history_record_iter : pop.subpop_size_histories_)\n            {\n                if (((iter == 0) && (history_record_iter.first == -1)) || ((iter == 1) && (history_record_iter.first != -1)))\n                {\n                    SubpopSizeHistory &history_record = history_record_iter.second;\n                    slim_popsize_t *history = history_record.history_;\n                    slim_tick_t historyLength = history_record.history_length_;\n                    \n                    if (iter == 1)\n                        string.append(QString(\"\\n\\n# Size history (subpopulation p%1):\\n\").arg(history_record_iter.first));\n                    \n                    for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                        string.append(QString(\"%1, \").arg(history[i]));\n                    \n                    string.append(\"\\n\");\n                }\n            }\n        }\n    }\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_MultispeciesPopSizeOverTime::legendKey(void)\n{\n    Community *community = controller_->community;\n    QtSLiMLegendSpec legend_key;\n    \n    for (Species *species : community->all_species_)\n    {\n        QString speciesName = QString::fromStdString(species->name_);\n        QColor speciesColor = controller_->qcolorForSpecies(species);\n        \n        legend_key.emplace_back(speciesName, speciesColor);\n    }\n    \n    return legend_key;\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::toggleShowSubpopulations(void)\n{\n    showSubpopulations_ = !showSubpopulations_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::toggleDrawLines(void)\n{\n    drawLines_ = !drawLines_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_MultispeciesPopSizeOverTime::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(showSubpopulations_ ? \"Hide Subpopulations\" : \"Show Subpopulations\", this, &QtSLiMGraphView_MultispeciesPopSizeOverTime::toggleShowSubpopulations);\n    contextMenu.addAction(drawLines_ ? \"Draw Points (Faster)\" : \"Draw Lines (Slower)\", this, &QtSLiMGraphView_MultispeciesPopSizeOverTime::toggleDrawLines);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_MultispeciesPopSizeOverTime.h",
    "content": "//\n//  QtSLiMGraphView_MultispeciesPopSizeOverTime.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/25/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_MULTISPECIESPOPSIZEOVERTIME_H\n#define QTSLIMGRAPHVIEW_MULTISPECIESPOPSIZEOVERTIME_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\nclass QPixmap;\n\n\nclass QtSLiMGraphView_MultispeciesPopSizeOverTime : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_MultispeciesPopSizeOverTime(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_MultispeciesPopSizeOverTime() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    \npublic slots:\n    virtual void invalidateDrawingCache(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void toggleShowSubpopulations(void);\n    void toggleDrawLines(void);\n    \nprotected:\n    virtual QtSLiMLegendSpec legendKey(void) override;    \n    \nprivate:\n    bool showSubpopulations_ = false;\n    bool drawLines_ = false;\n    \n    QPixmap *drawingCache_ = nullptr;\n\tslim_tick_t drawingCacheTick_ = 0;\n    \n    void setDefaultYAxisRange(void);\n    \n    void drawPointGraph(QPainter &painter, QRect interiorRect);\n    void drawLineGraph(QPainter &painter, QRect interiorRect);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_MULTISPECIESPOPSIZEOVERTIME_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopFitnessDist.cpp",
    "content": "//\n//  QtSLiMGraphView_PopFitnessDist.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/3/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_PopFitnessDist.h\"\n\n#include \"QtSLiMWindow.h\"\n#include \"species.h\"\n#include \"population.h\"\n#include \"subpopulation.h\"\n#include \"individual.h\"\n\n#include <utility>\n#include <string>\n\n\nQtSLiMGraphView_PopFitnessDist::QtSLiMGraphView_PopFitnessDist(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 50;\n    allowBinCountRescale_ = true;\n    \n    original_x1_ = 2.0;\n    x1_ = original_x1_;\n    \n    xAxisMax_ = x1_;\n    xAxisMajorTickInterval_ = 1.0;\n    xAxisMinorTickInterval_ = 0.2;\n    xAxisMajorTickModulus_ = 5;\n    xAxisTickValuePrecision_ = 1;\n    \n    xAxisLabel_ = \"Fitness (rescaled)\";\n    yAxisLabel_ = \"Frequency\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n}\n\nQtSLiMGraphView_PopFitnessDist::~QtSLiMGraphView_PopFitnessDist()\n{\n}\n\nQString QtSLiMGraphView_PopFitnessDist::graphTitle(void)\n{\n    return \"Population Fitness Distribution\";\n}\n\nQString QtSLiMGraphView_PopFitnessDist::aboutString(void)\n{\n    return \"The Population Fitness Distribution graph shows the distribution of fitness \"\n           \"values across all individuals in the population, as a histogram.  Fitness \"\n           \"is 'rescaled' as explained in the Fitness ~ Time graph's about \"\n           \"info.  The number of histogram bins can be changed in the action menu.  The \"\n           \"Subpopulation Fitness Distributions graph provides an alternative that \"\n           \"might also be useful.\";\n}\n\ndouble *QtSLiMGraphView_PopFitnessDist::populationFitnessData(void)\n{\n    int binCount = histogramBinCount_;\n\tstatic double *bins = nullptr;\n\tstatic size_t allocedBins = 0;\n\t\n\tif (!bins || (allocedBins < (size_t)binCount))\n\t{\n\t\tallocedBins = binCount;\n\t\tbins = static_cast<double *>(realloc(bins, allocedBins * sizeof(double)));\n\t}\n\t\n\tfor (int i = 0; i < binCount; ++i)\n\t\tbins[i] = 0.0;\n\t\n    // bin fitness values from across the population\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &pop = graphSpecies->population_;\n    \n    for (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : pop.subpops_)\n    {\n        const Subpopulation *subpop = subpop_pair.second;\n        \n        for (const Individual *individual : subpop->parent_individuals_)\n        {\n            double fitness = individual->cached_unscaled_fitness_;\n            int bin = (int)(((fitness - xAxisMin_) / (xAxisMax_ - xAxisMin_)) * binCount);\n            if (bin < 0) bin = 0;\n            if (bin >= binCount) bin = binCount - 1;\n            \n            bins[bin]++;\n        }\n    }\n    \n    // normalize the frequencies to a total of 1.0\n    double totalCount = 0.0;\n    \n    for (int i = 0; i < binCount; ++i)\n        totalCount += bins[i];\n    \n    if (totalCount == 0.0)\n        totalCount = 1.0;   // counts are all zero; prevent divide by zero below, get 0 instead\n    \n    for (int i = 0; i < binCount; ++i)\n        bins[i] = bins[i] / totalCount;\n    \n    return bins;\n}\n\nvoid QtSLiMGraphView_PopFitnessDist::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    double *plotData = populationFitnessData();\n\tint binCount = histogramBinCount_;\n\t\n\t// plot our histogram bars\n\tdrawBarplot(painter, interiorRect, plotData, binCount, xAxisMin_, (xAxisMax_ - xAxisMin_) / binCount);\n}\n\nbool QtSLiMGraphView_PopFitnessDist::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_PopFitnessDist::appendStringForData(QString &string)\n{\n\tdouble *plotData = populationFitnessData();\n\tint binCount = histogramBinCount_;\n\t\n    for (int i = 0; i < binCount; ++i)\n        string.append(QString(\"%1, \").arg(plotData[i], 0, 'f', 4));\n    \n    string.append(\"\\n\");\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopFitnessDist.h",
    "content": "//\n//  QtSLiMGraphView_PopFitnessDist.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/3/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_POPFITNESSDIST_H\n#define QTSLIMGRAPHVIEW_POPFITNESSDIST_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_PopFitnessDist : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_PopFitnessDist(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_PopFitnessDist() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    \nprivate:\n    double *populationFitnessData(void);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_POPFITNESSDIST_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopSizeOverTime.cpp",
    "content": "//\n//  QtSLiMGraphView_PopSizeOverTime.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_PopSizeOverTime.h\"\n\n#include <QAction>\n#include <QMenu>\n#include <QPixmap>\n#include <QPainterPath>\n#include <QDebug>\n\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"QtSLiMWindow.h\"\n\n\nQtSLiMGraphView_PopSizeOverTime::QtSLiMGraphView_PopSizeOverTime(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    //setXAxisRangeFromTick();\t// the end tick is not yet known\n    setDefaultYAxisRange();\n    \n    xAxisLabel_ = \"Tick\";\n    yAxisLabel_ = \"Number of individuals\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n    tweakXAxisTickLabelAlignment_ = true;\n    \n    showSubpopulations_ = true;\n    drawLines_ = true;\n    \n    QtSLiMGraphView_PopSizeOverTime::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::setDefaultYAxisRange(void)\n{\n    original_y0_ = 0.0;\n    original_y1_ = 100.0;\t\t// dynamic\n    \n    y0_ = original_y0_;\n    y1_ = original_y1_;\n    \n    yAxisMin_ = y0_;\n    yAxisMax_ = y1_;\n\tyAxisMajorTickInterval_ = 50;\n\tyAxisMinorTickInterval_ = 10;\n\tyAxisMajorTickModulus_ = 5;\n\tyAxisTickValuePrecision_ = 0;\n}\n\nQtSLiMGraphView_PopSizeOverTime::~QtSLiMGraphView_PopSizeOverTime()\n{\n    // We are responsible for our own destruction\n    QtSLiMGraphView_PopSizeOverTime::invalidateDrawingCache();\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::invalidateDrawingCache(void)\n{\n    delete drawingCache_;\n\tdrawingCache_ = nullptr;\n\tdrawingCacheTick_ = 0;\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::controllerRecycled(void)\n{\n\tif (!controller_->invalidSimulation())\n\t{\n\t\tif (!yAxisIsUserRescaled_)\n\t\t\tsetDefaultYAxisRange();\n\t\t//if (!xAxisIsUserRescaled_)\n\t\t//\tsetXAxisRangeFromTick();\t// the end tick is not yet known\n\t\t\n\t\tupdate();\n\t}\n\t\n\tQtSLiMGraphView::controllerRecycled();\n}\n\nQString QtSLiMGraphView_PopSizeOverTime::graphTitle(void)\n{\n    return \"Population Size ~ Time\";\n}\n\nQString QtSLiMGraphView_PopSizeOverTime::aboutString(void)\n{\n    return \"The Population Size ~ Time graph shows population (and subpopulation) size as a \"\n           \"function of time.  The size of the population is shown with a thick black line, \"\n           \"while those of subpopulations are shown with thinner colored lines.\";\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::updateAfterTick(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    // BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n    if (!controller_->invalidSimulation() && graphSpecies && !xAxisIsUserRescaled_)\n        setXAxisRangeFromTick();\n    \n    if (!controller_->invalidSimulation() && graphSpecies && !yAxisIsUserRescaled_)\n    {\n\t\tPopulation &pop = graphSpecies->population_;\n\t\tslim_popsize_t maxHistory = 0;\n\t\tbool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n\t\t\n\t\tfor (auto history_record_iter : pop.subpop_size_histories_)\n\t\t{\n\t\t\tif (showSubpops || (history_record_iter.first == -1))\n\t\t\t{\n\t\t\t\tSubpopSizeHistory &history_record = history_record_iter.second;\n\t\t\t\tslim_popsize_t *history = history_record.history_;\n\t\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\t\n\t\t\t\t// find the min and max history value\n\t\t\t\tfor (int i = 0; i < historyLength; ++i)\n                    maxHistory = std::max(maxHistory, history[i]);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// set axis range to encompass the data\n        if (maxHistory > yAxisMax_)\n        {\n            if (maxHistory <= 1000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 100.0) * 100.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 200;\n                yAxisMinorTickInterval_ = 100;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else if (maxHistory <= 10000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 1000.0) * 1000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 2000;\n                yAxisMinorTickInterval_ = 1000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else if (maxHistory <= 100000)\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 10000.0) * 10000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 20000;\n                yAxisMinorTickInterval_ = 10000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            else\n            {\n                maxHistory = (slim_popsize_t)(std::ceil(maxHistory / 100000.0) * 100000.0);\n                yAxisMax_ = maxHistory;\n                original_y1_ = yAxisMax_;               // the same as yAxisMax_, for base plots\n                y1_ = original_y1_;\n                yAxisMajorTickInterval_ = 200000;\n                yAxisMinorTickInterval_ = 100000;\n                yAxisMajorTickModulus_ = 2;\n            }\n            \n            QtSLiMGraphView_PopSizeOverTime::invalidateDrawingCache();\n        }\n    }\n\t\n\tQtSLiMGraphView::updateAfterTick();\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::drawPointGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// The tick counter can get set backwards, in which case our drawing cache is invalid – it contains drawing of things in the\n\t// future that may no longer happen.  So we need to detect that case and invalidate our cache.\n\tif (!cachingNow_ && drawingCache_ && (drawingCacheTick_ > completedTicks))\n\t{\n\t\t//qDebug() << \"backward tick change detected, invalidating drawing cache\";\n\t\tinvalidateDrawingCache();\n\t}\n\t\n\t// If we're not caching, then: if our cache is invalid OR we have crossed a 1000-tick boundary since we last cached, cache an image\n\tif (!cachingNow_ && (!drawingCache_ || ((completedTicks / 1000) > (drawingCacheTick_ / 1000))))\n\t{\n        invalidateDrawingCache();\n\t\t\n        //qDebug() << \"making new cache at tick \" << community->Tick();\n\t\tcachingNow_ = true;\n        \n\t\tQPixmap *cache = new QPixmap(interiorRect.size());\n        cache->fill(Qt::transparent);   // transparent so grid lines don't get overwritten by drawPixmap()\n        \n        QPainter cachePainter(cache);\n        drawGraph(cachePainter, cache->rect());\n        \n        drawingCache_ = cache;\n\t\tdrawingCacheTick_ = completedTicks;\n\t\tcachingNow_ = false;\n\t}\n\t\n\t// Now draw our cache, if we have one\n\tif (drawingCache_)\n    {\n        //qDebug() << \"drawing cache:\" << drawingCache_->rect() << \", drawingCacheTick_ == \" << drawingCacheTick_;\n        painter.drawPixmap(interiorRect, *drawingCache_, drawingCache_->rect());\n    }\n    \n\t// Draw the size history as a scatter plot; better suited to caching of the image\n    bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n\tbool drawSubpopsGray = (showSubpops && (pop.subpop_size_histories_.size() > 8));\t// 7 subpops + pop\n\t\n\t// First draw subpops, then draw the population size\n    for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n    {\n        QColor pointColor = ((iter == 0) ? QtSLiMColorWithWhite(0.5, 1.0) : Qt::black);\n        \n        for (auto history_record_iter : pop.subpop_size_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n            {\n                SubpopSizeHistory &history_record = history_record_iter.second;\n                slim_popsize_t *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                \n                if ((iter == 0) && !drawSubpopsGray)\n                    pointColor = controller_->whiteContrastingColorForIndex(history_record_iter.first);\n                \n                // If we're caching now, draw all points; otherwise, if we have a cache, draw only additional points\n                slim_tick_t firstHistoryEntryToDraw = (cachingNow_ ? 0 : (drawingCache_ ? drawingCacheTick_ : 0));\n                \n                for (slim_tick_t i = firstHistoryEntryToDraw; (i < historyLength) && (i < completedTicks); ++i)\n                {\n                    slim_popsize_t historyEntry = history[i];\n                    \n                    if (historyEntry != 0)\n                    {\n                        QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                        \n                        painter.fillRect(QRectF(historyPoint.x() - 0.5, historyPoint.y() - 0.5, 1.0, 1.0), pointColor);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::drawLineGraph(QPainter &painter, QRect interiorRect)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n\t// Draw the size history as a line plot\n\tbool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n\tbool drawSubpopsGray = (showSubpops && (pop.subpop_size_histories_.size() > 8));\t// 7 subpops + pop\n\t\n    // First draw subpops, then draw the population size\n    for (int iter = (showSubpops ? 0 : 1); iter <= 1; ++iter)\n    {\n        QColor lineColor = (iter == 0) ? QtSLiMColorWithWhite(0.5, 1.0) : Qt::black;\n        double lineWidth = (iter == 0) ? 1.0 : 1.5;\n        \n        for (auto history_record_iter : pop.subpop_size_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first != -1)) || ((iter == 1) && (history_record_iter.first == -1)))\n            {\n                SubpopSizeHistory &history_record = history_record_iter.second;\n                slim_popsize_t *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                QPainterPath linePath;\n                bool startedLine = false;\n                \n                for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                {\n                    slim_popsize_t historyEntry = history[i];\n                    \n                    if (historyEntry == 0)\n                    {\n                        startedLine = false;\n                    }\n                    else\n                    {\n                        QPointF historyPoint(plotToDeviceX(i, interiorRect), plotToDeviceY(historyEntry, interiorRect));\n                        \n                        if (startedLine)    linePath.lineTo(historyPoint);\n                        else                linePath.moveTo(historyPoint);\n                        \n                        startedLine = true;\n                    }\n                }\n                \n                if ((iter == 0) && !drawSubpopsGray)\n                    lineColor = controller_->whiteContrastingColorForIndex(history_record_iter.first);\n                \n                painter.strokePath(linePath, QPen(lineColor, lineWidth));\n            }\n        }\n    }\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    if (drawLines_)\n\t\tdrawLineGraph(painter, interiorRect);\n\telse\n\t\tdrawPointGraph(painter, interiorRect);\n}\n\nbool QtSLiMGraphView_PopSizeOverTime::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::appendStringForData(QString &string)\n{\n    Community *community = controller_->community;\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tslim_tick_t completedTicks = community->Tick() - 1;\n\t\n    // Size history\n    bool showSubpops = showSubpopulations_ && (pop.subpop_size_histories_.size() > 2);\n    \n\tstring.append(\"\\n\\n# Size history:\\n\");\n\t\n    for (int iter = 0; iter <= (showSubpops ? 1 : 0); ++iter)\n    {\n        for (auto history_record_iter : pop.subpop_size_histories_)\n        {\n            if (((iter == 0) && (history_record_iter.first == -1)) || ((iter == 1) && (history_record_iter.first != -1)))\n            {\n                SubpopSizeHistory &history_record = history_record_iter.second;\n                slim_popsize_t *history = history_record.history_;\n                slim_tick_t historyLength = history_record.history_length_;\n                \n                if (iter == 1)\n                    string.append(QString(\"\\n\\n# Size history (subpopulation p%1):\\n\").arg(history_record_iter.first));\n                \n                for (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n                    string.append(QString(\"%1, \").arg(history[i]));\n                \n                string.append(\"\\n\");\n            }\n        }\n    }\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_PopSizeOverTime::legendKey(void)\n{\n    if (!showSubpopulations_)\n        return QtSLiMLegendSpec();\n    \n    Species *graphSpecies = focalDisplaySpecies();\n    std::vector<slim_objectid_t> subpopsToDisplay;\n    \n    for (auto history_record_iter : graphSpecies->population_.subpop_size_histories_)\n        subpopsToDisplay.emplace_back(history_record_iter.first);\n\n    return subpopulationLegendKey(subpopsToDisplay, subpopsToDisplay.size() > 8);\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::toggleShowSubpopulations(void)\n{\n    showSubpopulations_ = !showSubpopulations_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::toggleDrawLines(void)\n{\n    drawLines_ = !drawLines_;\n    invalidateDrawingCache();\n    update();\n}\n\nvoid QtSLiMGraphView_PopSizeOverTime::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    contextMenu.addAction(showSubpopulations_ ? \"Hide Subpopulations\" : \"Show Subpopulations\", this, &QtSLiMGraphView_PopSizeOverTime::toggleShowSubpopulations);\n    contextMenu.addAction(drawLines_ ? \"Draw Points (Faster)\" : \"Draw Lines (Slower)\", this, &QtSLiMGraphView_PopSizeOverTime::toggleDrawLines);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopSizeOverTime.h",
    "content": "//\n//  QtSLiMGraphView_PopSizeOverTime.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_POPSIZEOVERTIME_H\n#define QTSLIMGRAPHVIEW_POPSIZEOVERTIME_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\nclass QPixmap;\n\n\nclass QtSLiMGraphView_PopSizeOverTime : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_PopSizeOverTime(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_PopSizeOverTime() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    \npublic slots:\n    virtual void invalidateDrawingCache(void) override;\n    virtual void controllerRecycled(void) override;\n    virtual void updateAfterTick(void) override;\n    void toggleShowSubpopulations(void);\n    void toggleDrawLines(void);\n    \nprotected:\n    virtual QtSLiMLegendSpec legendKey(void) override;    \n    \nprivate:\n    bool showSubpopulations_ = false;\n    bool drawLines_ = false;\n    \n    QPixmap *drawingCache_ = nullptr;\n\tslim_tick_t drawingCacheTick_ = 0;\n    \n    void setDefaultYAxisRange(void);\n    \n    void drawPointGraph(QPainter &painter, QRect interiorRect);\n    void drawLineGraph(QPainter &painter, QRect interiorRect);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_POPSIZEOVERTIME_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopulationVisualization.cpp",
    "content": "//\n//  QtSLiMGraphView_PopulationVisualization.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_PopulationVisualization.h\"\n\n#include <QAction>\n#include <QMenu>\n#include <QPainterPath>\n#include <QDebug>\n\n#include <map>\n#include <limits>\n#include <utility>\n#include <algorithm>\n\n#include \"QtSLiMWindow.h\"\n#include \"subpopulation.h\"\n\n// This define changes the visualization a little for use making Perry's icon; should be 0 otherwise\n#define PERRY_ICON 0\n\n#if PERRY_ICON\n#warning PERRY_ICON should be 0!\n#endif\n\nQtSLiMGraphView_PopulationVisualization::QtSLiMGraphView_PopulationVisualization(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    showXAxis_ = false;\n    showYAxis_ = false;\n}\n\nQtSLiMGraphView_PopulationVisualization::~QtSLiMGraphView_PopulationVisualization()\n{\n}\n\nQString QtSLiMGraphView_PopulationVisualization::graphTitle(void)\n{\n    return \"Population Visualization\";\n}\n\nQString QtSLiMGraphView_PopulationVisualization::aboutString(void)\n{\n    return \"The Population Visualization graph shows a visual depiction of the population structure of \"\n           \"the model, at the current tick.  Each subpopulation is shown as a circle, with size \"\n           \"proportional to the number of individuals in the subpopulation, and color representing the \"\n           \"mean fitness of the subpopulation.  Arrows show migration between subpopulations, with \"\n           \"the thickness of arrows representing the magnitude of migration.\";\n}\n\nQRectF QtSLiMGraphView_PopulationVisualization::rectForSubpop(Subpopulation *subpop, QPointF center)\n{\n\t// figure out the right radius, clamped to reasonable limits\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tslim_popsize_t clampedSubpopSize = subpopSize;\n\t\n\tif (clampedSubpopSize < 200)\n\t\tclampedSubpopSize = 200;\n\tif (clampedSubpopSize > 10000)\n\t\tclampedSubpopSize = 10000;\n\t\n\tdouble subpopRadius = sqrt(clampedSubpopSize) / 500;\t// size 10,000 has radius 0.2\n\t\n\tif (subpop->gui_radius_scaling_from_user_)\n\t\tsubpopRadius *= subpop->gui_radius_scaling_;\n\t\n\treturn QRectF(center.x() - subpopRadius, center.y() - subpopRadius, 2 * subpopRadius, 2 * subpopRadius);\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::drawSubpop(QPainter &painter, Subpopulation *subpop, slim_objectid_t subpopID, QPointF center)\n{\n\t// figure out the right radius, clamped to reasonable limits\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tslim_popsize_t clampedSubpopSize = subpopSize;\n\t\n\tif (clampedSubpopSize < 200)\n\t\tclampedSubpopSize = 200;\n\tif (clampedSubpopSize > 10000)\n\t\tclampedSubpopSize = 10000;\n\t\n    double subpopRadius = sqrt(clampedSubpopSize) / 500;\t// size 10,000 has radius 0.2\n\t\n\tif (subpop->gui_radius_scaling_from_user_)\n\t\tsubpopRadius *= subpop->gui_radius_scaling_;\n\t\n\tsubpop->gui_radius_ = subpopRadius;\n\t\n\t// determine the color\n\tfloat colorRed = 0.0, colorGreen = 0.0, colorBlue = 0.0;\n\t\n\tif (subpop->gui_color_from_user_)\n\t{\n\t\tcolorRed = subpop->gui_color_red_;\n\t\tcolorGreen = subpop->gui_color_green_;\n\t\tcolorBlue = subpop->gui_color_blue_;\n\t}\n\telse\n\t{\n\t\t// calculate the color from the mean fitness of the population\n        // we normalize fitness values with subpopFitnessScaling so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\tconst double fitnessScalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\t\tdouble fitness = ((subpopSize == 0) ? -10000.0 : subpop->parental_mean_unscaled_fitness_);\n\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, fitnessScalingFactor);\n\t}\n\t\n    QColor color = QtSLiMColorWithRGB(static_cast<double>(colorRed), static_cast<double>(colorGreen), static_cast<double>(colorBlue), 1.0);\n\t\n\t// draw the circle\n    painter.setBrush(color);\n    painter.setPen(QPen(Qt::black, 0.002));\n    painter.drawEllipse(center, subpopRadius, subpopRadius);\n    \n\t// label it with the subpopulation ID\n#if !PERRY_ICON\n    painter.setWorldMatrixEnabled(false);\n    \n\tQString popString = QString(\"p%1\").arg(subpopID);\n\tdouble brightness = static_cast<double>(0.299f * colorRed + 0.587f * colorGreen + 0.114f * colorBlue);\n\tdouble scalingFromUser = (subpop->gui_radius_scaling_from_user_ ? subpop->gui_radius_scaling_ : 1.0);\n\t\n    painter.setFont(labelFontOfPointSize(0.04 * scalingFactor_ * scalingFromUser));\n    painter.setPen((brightness > 0.5) ? Qt::black : Qt::white);\n    painter.setBrush(Qt::NoBrush);\n\t\n    QRect labelBoundingRect = painter.boundingRect(QRect(), Qt::TextDontClip | Qt::TextSingleLine, popString);\n    QPointF drawPoint = painter.transform().map(center);\n    drawPoint.setX(drawPoint.x() - labelBoundingRect.width() / 2.0 + 1.0);\n    drawPoint.setY(drawPoint.y() + 0.008 * scalingFactor_ * scalingFromUser);\n    \n    painter.drawText(drawPoint, popString);\n    painter.setWorldMatrixEnabled(true);\n#endif\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::drawArrowFromSubpopToSubpop(QPainter &painter, Subpopulation *sourceSubpop, Subpopulation *destSubpop, double migrantFraction)\n{\n    double destCenterX = destSubpop->gui_center_x_;\n\tdouble destCenterY = destSubpop->gui_center_y_;\n\tdouble sourceCenterX = sourceSubpop->gui_center_x_;\n\tdouble sourceCenterY = sourceSubpop->gui_center_y_;\n\t\n\t// we want to draw an arrow connecting these two subpops; first, we need to figure out the endpoints\n\t// they start and end a small fixed distance outside of the source/dest subpop circles\n\tdouble vectorDX = (destCenterX - sourceCenterX);\n\tdouble vectorDY = (destCenterY - sourceCenterY);\n\tdouble vectorLength = sqrt(vectorDX * vectorDX + vectorDY * vectorDY);\n\tdouble sourceEndWeight = (0.01 + sourceSubpop->gui_radius_) / vectorLength;\n\tdouble sourceEndX = sourceCenterX + (destCenterX - sourceCenterX) * sourceEndWeight;\n\tdouble sourceEndY = sourceCenterY + (destCenterY - sourceCenterY) * sourceEndWeight;\n\tdouble destEndWeight = (0.01 + destSubpop->gui_radius_) / vectorLength;\n\tdouble destEndX = destCenterX + (sourceCenterX - destCenterX) * destEndWeight;\n\tdouble destEndY = destCenterY + (sourceCenterY - destCenterY) * destEndWeight;\n\t\n\t// now, using those endpoints, we have a \"partial vector\" that goes from just outside the source subpop circle to\n\t// just outside the dest subpop circle; this partial vector will be the basis for the bezier that we draw, but we\n\t// need to calculate control points to make the bezier curve outward, using a perpendicular vector\n\tdouble partVecDX = destEndX - sourceEndX;\t// dx/dy for the partial vector from source to dest that we have just calculated\n\tdouble partVecDY = destEndY - sourceEndY;\n\tdouble partVecLength = sqrt(partVecDX * partVecDX + partVecDY * partVecDY);\t\t// the length of that partial vector\n\tdouble perpendicularFromSourceDX = partVecDY;\t\t// a vector perpendicular to that partial vector, by clockwise rotation\n\tdouble perpendicularFromSourceDY = -partVecDX;\n\tdouble controlPoint1X = sourceEndX + partVecDX * 0.3 + perpendicularFromSourceDX * 0.1;\n\tdouble controlPoint1Y = sourceEndY + partVecDY * 0.3 + perpendicularFromSourceDY * 0.1;\n\tdouble controlPoint2X = destEndX - partVecDX * 0.3 + perpendicularFromSourceDX * 0.1;\n\tdouble controlPoint2Y = destEndY - partVecDY * 0.3 + perpendicularFromSourceDY * 0.1;\n\t\n\t// now we figure out our line width, and we calculate a spatial translation of the bezier to shift in slightly off of\n\t// the midline, based on the line width, so that incoming and outgoing vectors do not overlap at the start/end points\n\tdouble lineWidth = 0.001 * (sqrt(migrantFraction) / 0.03);\t// non-linear line width scale\n#if PERRY_ICON\n    double finalShiftMagnitude = 0.0;\n#else    \n\tdouble finalShiftMagnitude = std::max(lineWidth * 0.75, 0.010);\n#endif\n\tdouble finalShiftX = perpendicularFromSourceDX * finalShiftMagnitude / partVecLength;\n\tdouble finalShiftY = perpendicularFromSourceDY * finalShiftMagnitude / partVecLength;\n\tdouble arrowheadSize = std::max(lineWidth * 1.5, 0.008);\n\t\n\t// we have to use a clipping path to cut back the destination end of the vector, to make room for the arrowhead\n    painter.save();\n\t\n\tdouble clipRadius = vectorLength - (destSubpop->gui_radius_ + arrowheadSize + 0.01);\n\tQRectF clipCircle = QRectF(sourceCenterX - clipRadius, sourceCenterY - clipRadius, clipRadius * 2, clipRadius * 2);\n    QPainterPath clipBezier;\n    \n    clipBezier.addEllipse(clipCircle);\n    painter.setClipPath(clipBezier, Qt::IntersectClip);\n    \n\t// now draw the curved line connecting the subpops\n    QPainterPath bezierLines;\n\tdouble shiftedSourceEndX = sourceEndX + finalShiftX, shiftedSourceEndY = sourceEndY + finalShiftY;\n\tdouble shiftedDestEndX = destEndX + finalShiftX, shiftedDestEndY = destEndY + finalShiftY;\n\tdouble shiftedControl1X = controlPoint1X + finalShiftX, shiftedControl1Y = controlPoint1Y + finalShiftY;\n\tdouble shiftedControl2X = controlPoint2X + finalShiftX, shiftedControl2Y = controlPoint2Y + finalShiftY;\n    \n#if PERRY_ICON\n    bezierLines.moveTo(QPointF(shiftedSourceEndX, shiftedSourceEndY));\n    bezierLines.lineTo(QPointF(shiftedDestEndX, shiftedDestEndY));\n#else    \n    bezierLines.moveTo(QPointF(shiftedSourceEndX, shiftedSourceEndY));\n    bezierLines.cubicTo(QPointF(shiftedControl1X, shiftedControl1Y), QPointF(shiftedControl2X, shiftedControl2Y), QPointF(shiftedDestEndX, shiftedDestEndY));\n#endif\n    \n    painter.strokePath(bezierLines, QPen(Qt::black, lineWidth));\n\t\n\t// restore the clipping path\n    painter.restore();\n    \n#if !PERRY_ICON    \n\t// draw the arrowhead; this is oriented along the line from (shiftedDestEndX, shiftedDestEndY) to (shiftedControl2X, shiftedControl2Y),\n\t// of length partVecLength, and is calculated using a perpendicular off of that vector\n    QPainterPath bezierArrowheads;\n\tdouble angleCorrectionFactor = (arrowheadSize / partVecLength) * 0.5;\t// large arrowheads need to be tilted closer to the source-dest pop line\n\tdouble headInsideX = shiftedControl2X * (1 - angleCorrectionFactor) + shiftedSourceEndX * angleCorrectionFactor;\n\tdouble headInsideY = shiftedControl2Y * (1 - angleCorrectionFactor) + shiftedSourceEndY * angleCorrectionFactor;\n\tdouble headMidlineDX = headInsideX - shiftedDestEndX, headMidlineDY = headInsideY - shiftedDestEndY;\n\tdouble headMidlineLength = sqrt(headMidlineDX * headMidlineDX + headMidlineDY * headMidlineDY);\n\tdouble headMidlineNormDX = (headMidlineDX / headMidlineLength) * arrowheadSize;\t\t\t\t\t// normalized to have length arrowheadSize\n\tdouble headMidlineNormDY = (headMidlineDY / headMidlineLength) * arrowheadSize;\n\tdouble headPerpendicular1DX = headMidlineNormDY, headPerpendicular1DY = -headMidlineNormDX;\t\t// perpendicular to the normalized midline\n\tdouble headPerpendicular2DX = -headMidlineNormDY, headPerpendicular2DY = headMidlineNormDX;\t\t// just the negation of perpendicular 1\n\t\n    bezierArrowheads.moveTo(shiftedDestEndX, shiftedDestEndY);\n    bezierArrowheads.lineTo(shiftedDestEndX + headMidlineNormDX * 1.75 + headPerpendicular1DX * 0.9, shiftedDestEndY + headMidlineNormDY * 1.75 + headPerpendicular1DY * 0.9);\n    bezierArrowheads.lineTo(shiftedDestEndX + headMidlineNormDX * 1.2, shiftedDestEndY + headMidlineNormDY * 1.2);\n    bezierArrowheads.lineTo(shiftedDestEndX + headMidlineNormDX * 1.75 + headPerpendicular2DX * 0.9, shiftedDestEndY + headMidlineNormDY * 1.75 + headPerpendicular2DY * 0.9);\n    bezierArrowheads.closeSubpath();\n    \n    painter.fillPath(bezierArrowheads, Qt::black);\n#endif\n}\n\nstatic bool is_line_intersection(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y)\n{\n\tdouble s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom;\n\ts10_x = p1_x - p0_x;\n\ts10_y = p1_y - p0_y;\n\ts32_x = p3_x - p2_x;\n\ts32_y = p3_y - p2_y;\n\t\n\tdenom = s10_x * s32_y - s32_x * s10_y;\n\tif (fabs(denom - 0) < 0.00001)\n\t\treturn false; // Collinear\n\tbool denomPositive = denom > 0;\n\t\n\ts02_x = p0_x - p2_x;\n\ts02_y = p0_y - p2_y;\n\ts_numer = s10_x * s02_y - s10_y * s02_x;\n\tif ((s_numer < 0) == denomPositive)\n\t\treturn false; // No collision\n\t\n\tt_numer = s32_x * s02_y - s32_y * s02_x;\n\tif ((t_numer < 0) == denomPositive)\n\t\treturn false; // No collision\n\t\n\tif (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))\n\t\treturn false; // No collision\n\t\n\treturn true;\n}\n\ndouble QtSLiMGraphView_PopulationVisualization::scorePositions(double *center_x, double *center_y, bool *connected, size_t subpopCount)\n{\n\tdouble score = 0.0;\n\tdouble meanEdge = 0.0;\n\tint edgeCount = 0;\n\tdouble minx = std::numeric_limits<double>::infinity(), maxy = -std::numeric_limits<double>::infinity();\n\t\n\t// First we calculate the mean edge length; we will consider this the optimum length\n\tfor (size_t subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tdouble xc = center_x[subpopIndex];\n\t\tdouble yc = center_y[subpopIndex];\n\t\t\n\t\t// If any node has a NaN value, that is an immediate disqualifier; I'm not sure how it happens, but it occasionally does\n\t\tif (std::isnan(xc) || std::isnan(yc))\n\t\t\treturn -100000000;\n\t\t\n\t\tif (xc < minx) minx = xc;\n\t\tif (yc > maxy) maxy = yc;\n\t\t\n\t\tfor (size_t sourceIndex = subpopIndex + 1; sourceIndex < subpopCount; ++sourceIndex)\n\t\t{\n\t\t\tif (connected[subpopIndex * subpopCount + sourceIndex])\n\t\t\t{\n\t\t\t\tdouble dx = xc - center_x[sourceIndex];\n\t\t\t\tdouble dy = yc - center_y[sourceIndex];\n\t\t\t\tdouble distanceSquared = dx * dx + dy * dy;\n\t\t\t\tdouble distance = sqrt(distanceSquared);\n\t\t\t\t\n\t\t\t\tmeanEdge += distance;\n\t\t\t\tedgeCount++;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tmeanEdge /= edgeCount;\n\t\n\t// Add a little score if the first subpop is near the upper left\n\tif ((fabs(center_x[0] - minx) < 0.05) && (fabs(center_y[0] - maxy) < 0.05))\n\t{\n\t\tscore += 0.01;\n\t\t\n\t\t// Add a little more score if the second subpop is to its right in roughly the same row\n\t\tif ((center_x[1] - center_x[0] > meanEdge/2) && (fabs(center_y[0] - center_y[1]) < 0.05))\n\t\t\tscore += 0.01;\n\t}\n\t\n\t// Score distances and crossings\n\tfor (size_t subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tdouble xc = center_x[subpopIndex];\n\t\tdouble yc = center_y[subpopIndex];\n\t\t\n\t\tfor (size_t sourceIndex = subpopIndex + 1; sourceIndex < subpopCount; ++sourceIndex)\n\t\t{\n\t\t\tdouble dx = xc - center_x[sourceIndex];\n\t\t\tdouble dy = yc - center_y[sourceIndex];\n\t\t\tdouble distanceSquared = dx * dx + dy * dy;\n\t\t\tdouble distance = sqrt(distanceSquared);\n\t\t\t\n\t\t\t// being closer than k invokes a penalty\n\t\t\tif (distance < meanEdge)\n\t\t\t\tscore -= (meanEdge - distance);\n\t\t\t\n\t\t\t// on the other hand, distance between connected subpops is very bad; this is above all what we want to optimize\n\t\t\tif (connected[subpopIndex * subpopCount + sourceIndex])\n\t\t\t{\n\t\t\t\tif (distance > meanEdge)\n\t\t\t\t\tscore -= (distance - meanEdge);\n\t\t\t\t\n\t\t\t\t// Detect crossings\n\t\t\t\tfor (size_t secondSubpop = subpopIndex + 1; secondSubpop < subpopCount; ++secondSubpop)\n\t\t\t\t\tfor (size_t secondSource = secondSubpop + 1; secondSource < subpopCount; ++secondSource)\n\t\t\t\t\t\tif (connected[secondSubpop * subpopCount + secondSource])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble x0 = xc, x1 = center_x[sourceIndex], x2 = center_x[secondSubpop], x3 = center_x[secondSource];\n\t\t\t\t\t\t\tdouble y0 = yc, y1 = center_y[sourceIndex], y2 = center_y[secondSubpop], y3 = center_y[secondSource];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// I test intersection with slightly shortened line segments, because I don't want endpoints that touch to be marked as intersections\n\t\t\t\t\t\t\tif (is_line_intersection(x0*0.99 + x1*0.01, y0*0.99 + y1*0.01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x0*0.01 + x1*0.99, y0*0.01 + y1*0.99,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x2*0.99 + x3*0.01, y2*0.99 + y3*0.01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x2*0.01 + x3*0.99, y2*0.01 + y3*0.99))\n\t\t\t\t\t\t\t\tscore -= 100;\n\t\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn score;\n}\n\n// This is a simple implementation of the algorithm of Fruchterman and Reingold 1991;\n// there are better algorithms out there, but this one is simple...\nvoid QtSLiMGraphView_PopulationVisualization::optimizePositions(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tsize_t subpopCount = pop.subpops_.size();\n\t\n\tif (subpopCount == 0)\n\t\treturn;\n\t\n\tdouble layout_width = 0.58, layout_length = 0.58;\t\t// allows for the radii of the vertices at max subpop size\n\tdouble area = layout_width * layout_length;\n\tdouble k = sqrt(area / subpopCount);\n\tdouble kSquared = k * k;\n\tbool *connected;\n\t\n\tconnected = static_cast<bool *>(calloc(subpopCount * subpopCount, sizeof(bool)));\n\t\n\t// We start by figuring out connectivity\n\tauto subpopIter = pop.subpops_.begin();\n\t\n\tfor (size_t subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,double> &fractions_pair : subpop->migrant_fractions_)\n\t\t{\n\t\t\tslim_objectid_t migrant_source_id = fractions_pair.first;\n\t\t\t\n\t\t\t// We need to get from the source ID to the index of the source subpop in the pop array\n\t\t\tauto sourceIter = pop.subpops_.begin();\n\t\t\tsize_t sourceIndex;\n\t\t\t\n\t\t\tfor (sourceIndex = 0; sourceIndex < subpopCount; ++sourceIndex)\n\t\t\t{\n\t\t\t\tif ((*sourceIter).first == migrant_source_id)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++sourceIter;\n\t\t\t}\n\t\t\t\n\t\t\tif (sourceIndex == subpopCount)\n\t\t\t{\n\t\t\t\tfree(connected);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t// Mark the connection bidirectionally\n\t\t\tconnected[subpopIndex * subpopCount + sourceIndex] = true;\n\t\t\tconnected[sourceIndex * subpopCount + subpopIndex] = true;\n\t\t}\n\t\t\n\t\t++subpopIter;\n\t}\n\t\n\tdouble *pos_x, *pos_y;\t\t// vertex positions\n\tdouble *disp_x, *disp_y;\t// vertex forces/displacements\n\tdouble *best_x, *best_y;\t// best vertex positions from multiple runs\n\tdouble best_score = -std::numeric_limits<double>::infinity();\n\t\n\tpos_x = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\tpos_y = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\tdisp_x = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\tdisp_y = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\tbest_x = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\tbest_y = static_cast<double *>(malloc(sizeof(double) * subpopCount));\n\t\n\t// We do multiple separate runs from different starting configurations, to try to find the optimal solution\n\tfor (int trialIteration = 0; trialIteration < 50; ++trialIteration)\n\t{\n\t\tdouble temperature = layout_width / 5.0;\n\t\t\n\t\t// initialize positions; this is basically the G := (V,E) step of the Fruchterman & Reingold algorithm\n\t\tfor (size_t subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t{\n\t\t\tpos_x[subpopIndex] = (random() / static_cast<double>(INT32_MAX)) * layout_width - layout_width/2;\n\t\t\tpos_y[subpopIndex] = (random() / static_cast<double>(INT32_MAX)) * layout_length - layout_length/2;\n\t\t}\n\t\t\n\t\t// Then we do the core loop of the Fruchterman & Reingold algorithm, which calculates forces and displacements\n\t\tfor (int optimizeIteration = 1; optimizeIteration < 1000; ++optimizeIteration)\n\t\t{\n\t\t\t// Calculate repulsive forces\n\t\t\tfor (size_t v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tdisp_x[v] = 0.0;\n\t\t\t\tdisp_y[v] = 0.0;\n\t\t\t\t\n\t\t\t\tfor (size_t u = 0; u < subpopCount; ++u)\n\t\t\t\t{\n\t\t\t\t\tif (u != v)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble delta_x = pos_x[v] - pos_x[u];\n\t\t\t\t\t\tdouble delta_y = pos_y[v] - pos_y[u];\n\t\t\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\t\t\tdouble multiplier = kSquared / delta_magnitude_squared;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// This is a speed-optimized version of the pseudocode version commented out below\n\t\t\t\t\t\tdisp_x[v] += delta_x * multiplier;\n\t\t\t\t\t\tdisp_y[v] += delta_y * multiplier;\n\t\t\t\t\t\t\n\t\t\t\t\t\t//double delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\t\t\n\t\t\t\t\t\t//disp_x[v] += (delta_x / delta_magnitude) * (kSquared / delta_magnitude);\n\t\t\t\t\t\t//disp_y[v] += (delta_y / delta_magnitude) * (kSquared / delta_magnitude);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Calculate attractive forces\n\t\t\tfor (size_t v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tfor (size_t u = v + 1; u < subpopCount; ++u)\n\t\t\t\t{\n\t\t\t\t\tif (connected[v * subpopCount + u])\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is an edge between u and v\n\t\t\t\t\t\tdouble delta_x = pos_x[v] - pos_x[u];\n\t\t\t\t\t\tdouble delta_y = pos_y[v] - pos_y[u];\n\t\t\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\t\t\tdouble delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\t\tdouble multiplier = (delta_magnitude_squared / k) / delta_magnitude;\n\t\t\t\t\t\tdouble delta_multiplier_x = delta_x * multiplier;\n\t\t\t\t\t\tdouble delta_multiplier_y = delta_y * multiplier;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdisp_x[v] -= delta_multiplier_x;\n\t\t\t\t\t\tdisp_y[v] -= delta_multiplier_y;\n\t\t\t\t\t\tdisp_x[u] += delta_multiplier_x;\n\t\t\t\t\t\tdisp_y[u] += delta_multiplier_y;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Limit max displacement to temperature t and prevent displacement outside frame\n\t\t\tfor (size_t v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tdouble delta_x = disp_x[v];\n\t\t\t\tdouble delta_y = disp_y[v];\n\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\tdouble delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\n\t\t\t\tif (delta_magnitude < temperature)\n\t\t\t\t{\n\t\t\t\t\tpos_x[v] += disp_x[v];\n\t\t\t\t\tpos_y[v] += disp_y[v];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tpos_x[v] += (disp_x[v] / delta_magnitude) * temperature;\n\t\t\t\t\tpos_y[v] += (disp_y[v] / delta_magnitude) * temperature;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (pos_x[v] < -layout_width/2) pos_x[v] = -layout_width/2;\n\t\t\t\tif (pos_y[v] < -layout_length/2) pos_y[v] = -layout_length/2;\n\t\t\t\tif (pos_x[v] > layout_width/2) pos_x[v] = layout_width/2;\n\t\t\t\tif (pos_y[v] > layout_length/2) pos_y[v] = layout_length/2;\n\t\t\t}\n\t\t\t\n\t\t\t// reduce the temperature as the layout approaches a better configuration\n\t\t\t// Fruchterman & Reingold are vague about exactly what they did here, but there is a rapid cooling phase (quenching)\n\t\t\t// and then a constant low-temperature phase (simmering); I've taken a guess at what that might look like\n\t\t\ttemperature = temperature * 0.95;\n\t\t\t\n\t\t\tif (temperature < 0.002)\n\t\t\t\ttemperature = 0.002;\n\t\t}\n\t\t\n\t\t// Test the final candidate and keep the best candidate\n\t\tdouble candidate_score = scorePositions(pos_x, pos_y, connected, subpopCount);\n\t\t\n\t\tif (candidate_score > best_score)\n\t\t{\n\t\t\tfor (size_t v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tbest_x[v] = pos_x[v];\n\t\t\t\tbest_y[v] = pos_y[v];\n\t\t\t}\n\t\t\tbest_score = candidate_score;\n\t\t\t//NSLog(@\"better candidate, new score == %f\", best_score);\n\t\t}\n\t}\n\t\n\t// Finally, we set the positions we have arrived at back into the subpops\n\tsubpopIter = pop.subpops_.begin();\n\t\n\tfor (size_t subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\n\t\tsubpop->gui_center_x_ = best_x[subpopIndex] + 0.5;\n\t\tsubpop->gui_center_y_ = best_y[subpopIndex] + 0.5;\n\t\tsubpop->gui_center_from_user_ = false;\t\t// optimization overrides previously set display settings\n\t\t++subpopIter;\n\t}\n\t\n\tfree(pos_x);\n\tfree(pos_y);\n\tfree(disp_x);\n\tfree(disp_y);\n\tfree(connected);\n\tfree(best_x);\n\tfree(best_y);\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n\tint subpopCount = static_cast<int>(pop.subpops_.size());\n    Community &community = graphSpecies->community_;\n\t\n\tif (subpopCount == 0)\n\t{\n        // this is an ugly hack that assumes things about QtSLiMGraphView's implementation\n        // we restore() twice to get back to the original coordinate system for drawMessage()\n        // then we save() twice so that the expected number of pops are still available\n        painter.restore();\n        painter.restore();\n\t\tdrawMessage(painter, \"no subpopulations\", rect());\n        painter.save();\n        painter.save();\n\t\treturn;\n\t}\n\t\n\t// First, we transform our coordinate system so that a square of size (1,1) fits maximally and centered\n\tpainter.save();\n    \n    QTransform transform;\n    if (interiorRect.width() > interiorRect.height())\n    {\n        transform.translate(interiorRect.x(), interiorRect.y());\n        transform.translate(SLIM_SCREEN_ROUND((interiorRect.width() - interiorRect.height()) / 2.0), 0);\n        scalingFactor_ = interiorRect.height();\n    }\n    else\n    {\n        transform.translate(interiorRect.x(), interiorRect.y());\n        transform.translate(0, SLIM_SCREEN_ROUND((interiorRect.height() - interiorRect.width()) / 2.0));\n        scalingFactor_ = interiorRect.width();\n    }\n    transform.scale(scalingFactor_, scalingFactor_);\n    painter.setWorldTransform(transform, true);\n    \n\t// test frame\n    //painter.setBrush(Qt::NoBrush);\n    //painter.setPen(QPen(Qt::black, 0.002));\n    //painter.drawRect(QRect(0, 0, 1, 1));\n\t\n\tif (subpopCount == 1)\n\t{\n\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\n\t\t// a single subpop is shown as a circle at the center\n\t\tdrawSubpop(painter, (*subpopIter).second, (*subpopIter).first, QPointF(0.5, 0.5));\n\t}\n\telse if (subpopCount > 1)\n\t{\n\t\t// first we distribute our subpops in a ring\n\t\tbool allUserConfigured = true;\n\t\t\n\t\t{\n\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\tdouble theta = (M_PI * 2.0 / subpopCount) * subpopIndex + M_PI_2;\n\t\t\t\t\n\t\t\t\tif (!subpop->gui_center_from_user_)\n\t\t\t\t{\n\t\t\t\t\tsubpop->gui_center_x_ = 0.5 - cos(theta) * 0.29;\n\t\t\t\t\tsubpop->gui_center_y_ = 0.5 + sin(theta) * 0.29;\n\t\t\t\t\tallUserConfigured = false;\n\t\t\t\t}\n\t\t\t\t++subpopIter;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if position optimization is on, we do that to optimize the positions of the subpops\n\t\tif ((community.ModelType() == SLiMModelType::kModelTypeWF) && optimizePositions_ && (subpopCount > 2))\n\t\t\toptimizePositions();\n\t\t\n\t\tif (!allUserConfigured)\n\t\t{\n\t\t\t// then do some sizing, to figure out the maximum extent of our subpops\n\t\t\tQRectF boundingBox = QRectF();\n\t\t\t\n\t\t\t{\n\t\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\t\n\t\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\t\t\n\t\t\t\t\tQPointF center(subpop->gui_center_x_, subpop->gui_center_y_);\n\t\t\t\t\tQRectF subpopRect = rectForSubpop(subpop, center);\n\t\t\t\t\t\n\t\t\t\t\tboundingBox = ((subpopIndex == 0) ? subpopRect : boundingBox.united(subpopRect));\n\t\t\t\t\t\n\t\t\t\t\t++subpopIter;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// then we translate our coordinate system so that the subpops are centered within our (0, 0, 1, 1) box\n\t\t\tdouble offsetX = ((1.0 - boundingBox.width()) / 2.0) - boundingBox.x();\n\t\t\tdouble offsetY = ((1.0 - boundingBox.height()) / 2.0) - boundingBox.y();\n\t\t\t\n            QTransform offsetTransform;\n            offsetTransform.translate(offsetX, offsetY);\n            painter.setWorldTransform(offsetTransform, true);\n\t\t}\n\t\t\n\t\t// then we draw the subpops\n\t\t{\n\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\tslim_objectid_t subpopID = (*subpopIter).first;\n\t\t\t\tQPointF center(subpop->gui_center_x_, subpop->gui_center_y_);\n\t\t\t\t\n\t\t\t\tdrawSubpop(painter, subpop, subpopID, center);\n\t\t\t\t++subpopIter;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// in the multipop case, we need to draw migration arrows, too\n\t\t{\n\t\t\tfor (auto destSubpopIter : pop.subpops_)\n\t\t\t{\n\t\t\t\tSubpopulation *destSubpop = destSubpopIter.second;\n\t\t\t\tstd::map<slim_objectid_t,double> &destMigrants = (community.ModelType() == SLiMModelType::kModelTypeWF) ? destSubpop->migrant_fractions_ : destSubpop->gui_migrants_;\n\t\t\t\t\n\t\t\t\tfor (auto sourceSubpopIter : destMigrants)\n\t\t\t\t{\n\t\t\t\t\tslim_objectid_t sourceSubpopID = sourceSubpopIter.first;\n                    Subpopulation *sourceSubpop = graphSpecies->SubpopulationWithID(sourceSubpopID);\n\t\t\t\t\t\n\t\t\t\t\tif (sourceSubpop)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble migrantFraction = sourceSubpopIter.second;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// The gui_migrants_ map is raw migration counts, which need to be converted to a fraction of the sourceSubpop pre-migration size\n\t\t\t\t\t\tif (community.ModelType() == SLiMModelType::kModelTypeNonWF)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (sourceSubpop->gui_premigration_size_ <= 0)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmigrantFraction /= sourceSubpop->gui_premigration_size_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (migrantFraction < 0.0)\n\t\t\t\t\t\t\t\tmigrantFraction = 0.0;\n\t\t\t\t\t\t\tif (migrantFraction > 1.0)\n\t\t\t\t\t\t\t\tmigrantFraction = 1.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n                        if (migrationArrows_ == 1)\n                            drawArrowFromSubpopToSubpop(painter, sourceSubpop, destSubpop, 0.002);              // thin arrows; 0.002 is arbitrary but seems reasonable\n                        else if (migrationArrows_ == 2)\n                            drawArrowFromSubpopToSubpop(painter, sourceSubpop, destSubpop, migrantFraction);    // migration-scaled arrow thickness\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// We're done with our transformed coordinate system\n    painter.restore();\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::toggleOptimizedPositions(void)\n{\n    optimizePositions_ = !optimizePositions_;\n    update();\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent * /* event */)\n{\n    QAction *menuItem = contextMenu.addAction(optimizePositions_ ? \"Standard Positions\" : \"Optimized Positions\", this, &QtSLiMGraphView_PopulationVisualization::toggleOptimizedPositions);\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &pop = graphSpecies->population_;\n    \n    // If any subpop has a user-defined center, disable position optimization; it doesn't know how to\n    // handle those, and there's no way to revert back after it messes things up, and so forth\n    bool userDefinedCenter = false;\n    \n    for (auto subpopIter : pop.subpops_)\n        if (subpopIter.second->gui_center_from_user_)\n        {\n            userDefinedCenter = true;\n            break;\n        }\n    \n    menuItem->setEnabled(!userDefinedCenter);\n    \n    // Offer a choice regarding the migration arrow style, since they can clutter things up a lot\n    contextMenu.addSeparator();\n    \n    QAction *noMigAction = contextMenu.addAction(\"No Migration Arrows\", this, [this]() { migrationArrows_ = 0; update(); });\n    QAction *thinMigAction = contextMenu.addAction(\"Thin Migration Arrows\", this, [this]() { migrationArrows_ = 1; update(); });\n    QAction *fullMigAction = contextMenu.addAction(\"Full Migration Arrows\", this, [this]() { migrationArrows_ = 2; update(); });\n    \n    noMigAction->setCheckable(true);\n    thinMigAction->setCheckable(true);\n    fullMigAction->setCheckable(true);\n    \n    noMigAction->setChecked(migrationArrows_ == 0);\n    thinMigAction->setChecked(migrationArrows_ == 1);\n    fullMigAction->setChecked(migrationArrows_ == 2);\n}\n\nvoid QtSLiMGraphView_PopulationVisualization::appendStringForData(QString & /* string */)\n{\n    // No data string\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_PopulationVisualization.h",
    "content": "//\n//  QtSLiMGraphView_PopulationVisualization.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/30/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_POPULATIONVISUALIZATION_H\n#define QTSLIMGRAPHVIEW_POPULATIONVISUALIZATION_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\n\nclass QtSLiMGraphView_PopulationVisualization : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_PopulationVisualization(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_PopulationVisualization() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual void subclassAddItemsToMenu(QMenu &contextMenu, QContextMenuEvent *p_event) override;\n    virtual void appendStringForData(QString &string) override;\n    \npublic slots:\n    void toggleOptimizedPositions(void);\n    \nprivate:\n    double scalingFactor_;\n    \n    bool optimizePositions_ = false;\n    double scorePositions(double *center_x, double *center_y, bool *connected, size_t subpopCount);\n    void optimizePositions(void); \n    \n    int migrationArrows_ = 2;   // 0 == none, 1 == thin, 2 == full\n    \n    QRectF rectForSubpop(Subpopulation *subpop, QPointF center);\n    void drawSubpop(QPainter &painter, Subpopulation *subpop, slim_objectid_t subpopID, QPointF center);\n    void drawArrowFromSubpopToSubpop(QPainter &painter, Subpopulation *sourceSubpop, Subpopulation *destSubpop, double migrantFraction);\n};\n\n\n#endif // QTSLIMGRAPHVIEW_POPULATIONVISUALIZATION_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_SubpopFitnessDists.cpp",
    "content": "//\n//  QtSLiMGraphView_SubpopFitnessDists.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/8/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMGraphView_SubpopFitnessDists.h\"\n\n#include \"QtSLiMWindow.h\"\n#include \"species.h\"\n#include \"population.h\"\n#include \"subpopulation.h\"\n#include \"individual.h\"\n\n#include <utility>\n#include <string>\n\n#include <QPainterPath>\n\nQtSLiMGraphView_SubpopFitnessDists::QtSLiMGraphView_SubpopFitnessDists(QWidget *p_parent, QtSLiMWindow *controller) : QtSLiMGraphView(p_parent, controller)\n{\n    histogramBinCount_ = 50;\n    allowBinCountRescale_ = true;\n    \n    original_x1_ = 2.0;\n    x1_ = original_x1_;\n    \n    xAxisMax_ = x1_;\n    xAxisMajorTickInterval_ = 1.0;\n    xAxisMinorTickInterval_ = 0.2;\n    xAxisMajorTickModulus_ = 5;\n    xAxisTickValuePrecision_ = 1;\n    \n    xAxisLabel_ = \"Fitness (rescaled)\";\n    yAxisLabel_ = \"Frequency\";\n    \n    allowXAxisUserRescale_ = true;\n    allowYAxisUserRescale_ = true;\n    \n    showHorizontalGridLines_ = true;\n}\n\nQtSLiMGraphView_SubpopFitnessDists::~QtSLiMGraphView_SubpopFitnessDists()\n{\n}\n\nQString QtSLiMGraphView_SubpopFitnessDists::graphTitle(void)\n{\n    return \"Subpopulation Fitness Distributions\";\n}\n\nQString QtSLiMGraphView_SubpopFitnessDists::aboutString(void)\n{\n    return \"The Subpopulation Fitness Distributions graph shows the distribution of fitness \"\n           \"values for each subpopulation as a separate line.  The primary purpose of this \"\n           \"visualization is to allow the fitness distributions of many subpopulations \"\n           \"to be compared visually.  Fitness is 'rescaled' as explained in the \"\n           \"Fitness ~ Time graph's about info.  The number of histogram bins can be changed \"\n           \"in the action menu.  The Population Fitness Distribution graph provides an \"\n           \"alternative that might also be useful.\";\n}\n\ndouble *QtSLiMGraphView_SubpopFitnessDists::subpopulationFitnessData(const Subpopulation *requestedSubpop)\n{\n    int binCount = histogramBinCount_;\n\tstatic double *bins = nullptr;\n\tstatic size_t allocedBins = 0;\n\t\n\tif (!bins || (allocedBins < (size_t)binCount))\n\t{\n\t\tallocedBins = binCount;\n\t\tbins = static_cast<double *>(realloc(bins, allocedBins * sizeof(double)));\n\t}\n\t\n\tfor (int i = 0; i < binCount; ++i)\n\t\tbins[i] = 0.0;\n\t\n    // bin fitness values from one subpop or from across the population\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &pop = graphSpecies->population_;\n    \n    for (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : pop.subpops_)\n    {\n        const Subpopulation *subpop = subpop_pair.second;\n        \n        if (requestedSubpop && (subpop != requestedSubpop))\n            continue;\n        \n        for (const Individual *individual : subpop->parent_individuals_)\n        {\n            double fitness = individual->cached_unscaled_fitness_;\n            int bin = (int)(((fitness - xAxisMin_) / (xAxisMax_ - xAxisMin_)) * binCount);\n            if (bin < 0) bin = 0;\n            if (bin >= binCount) bin = binCount - 1;\n            \n            bins[bin]++;\n        }\n    }\n    \n    // normalize the frequencies to a total of 1.0\n    double totalCount = 0.0;\n    \n    for (int i = 0; i < binCount; ++i)\n        totalCount += bins[i];\n    \n    if (totalCount == 0)\n        totalCount = 1;  // if counts are all zero, avoid a divide by zero below and just end up with 0 instead\n    \n    for (int i = 0; i < binCount; ++i)\n        bins[i] = bins[i] / totalCount;\n    \n    return bins;\n}\n\nvoid QtSLiMGraphView_SubpopFitnessDists::drawGraph(QPainter &painter, QRect interiorRect)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n    bool showSubpops = true;\n\tbool drawSubpopsGray = (showSubpops && (pop.subpops_.size() > 8));\t// 7 subpops + pop\n    int binCount = histogramBinCount_;\n    \n    // First draw subpop fitness distributions\n\tif (showSubpops)\n\t{\n        for (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : pop.subpops_)\n        {\n            const Subpopulation *subpop = subpop_pair.second;\n            double *plotData = subpopulationFitnessData(subpop);\n            QPainterPath linePath;\n            bool startedLine = false;\n            \n            for (int i = 0; i < binCount; ++i)\n            {\n                QPointF historyPoint(plotToDeviceX(xAxisMin_ + (xAxisMax_ - xAxisMin_) * (i + 0.5) / binCount, interiorRect), plotToDeviceY(plotData[i], interiorRect));\n                \n                if (startedLine)    linePath.lineTo(historyPoint);\n                else                linePath.moveTo(historyPoint);\n                \n                startedLine = true;\n            }\n            \n            if (drawSubpopsGray)\n                painter.strokePath(linePath, QPen(QtSLiMColorWithWhite(0.5, 1.0), 1.0));\n            else\n                painter.strokePath(linePath, QPen(controller_->whiteContrastingColorForIndex(subpop->subpopulation_id_), 1.0));\n        }\n\t}\n\t\n\t// Then draw the population fitness distribution\n    double *plotData = subpopulationFitnessData(nullptr);\n    QPainterPath linePath;\n    bool startedLine = false;\n    \n    for (int i = 0; i < binCount; ++i)\n    {\n        QPointF historyPoint(plotToDeviceX(xAxisMin_ + (xAxisMax_ - xAxisMin_) * (i + 0.5) / binCount, interiorRect), plotToDeviceY(plotData[i], interiorRect));\n        \n        if (startedLine)    linePath.lineTo(historyPoint);\n        else                linePath.moveTo(historyPoint);\n        \n        startedLine = true;\n    }\n    \n    painter.strokePath(linePath, QPen(Qt::black, 1.5));\n}\n\nbool QtSLiMGraphView_SubpopFitnessDists::providesStringForData(void)\n{\n    return true;\n}\n\nvoid QtSLiMGraphView_SubpopFitnessDists::appendStringForData(QString &string)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n\tPopulation &pop = graphSpecies->population_;\n    bool showSubpops = true;\n    int binCount = histogramBinCount_;\n\t\n    // First add subpop fitness distributions\n\tif (showSubpops)\n\t{\n        for (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : pop.subpops_)\n        {\n            const Subpopulation *subpop = subpop_pair.second;\n            double *plotData = subpopulationFitnessData(subpop);\n            \n            string.append(QString(\"# Fitness distribution (subpopulation p%1):\\n\").arg(subpop->subpopulation_id_));\n            \n            for (int i = 0; i < binCount; ++i)\n                string.append(QString(\"%1, \").arg(plotData[i], 0, 'f', 4));\n                \n            string.append(\"\\n\\n\");\n        }\n\t}\n\t\n\t// Then add the population fitness distribution\n    double *plotData = subpopulationFitnessData(nullptr);\n    \n    string.append(\"# Fitness distribution (population):\\n\");\n    \n    for (int i = 0; i < binCount; ++i)\n        string.append(QString(\"%1, \").arg(plotData[i], 0, 'f', 4));\n        \n    string.append(\"\\n\");\n}\n\nQtSLiMLegendSpec QtSLiMGraphView_SubpopFitnessDists::legendKey(void)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &pop = graphSpecies->population_;\n\tbool showSubpops = true;\n\tbool drawSubpopsGray = (showSubpops && (pop.subpops_.size() > 8));\t// 7 subpops + pop\n\t\n\tif (!showSubpops)\n\t\treturn QtSLiMLegendSpec();\n\t\n    QtSLiMLegendSpec legend_key;\n\n    legend_key.emplace_back(\"All\", Qt::black);\n\t\n\tif (drawSubpopsGray)\n\t{\n        legend_key.emplace_back(\"pX\", QtSLiMColorWithWhite(0.5, 1.0));\n\t}\n\telse\n\t{\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : pop.subpops_)\n\t\t{\n            slim_objectid_t subpop_id = subpop_pair.second->subpopulation_id_;\n            QString labelString = QString(\"p%1\").arg(subpop_id);\n            \n            legend_key.emplace_back(labelString, controller_->whiteContrastingColorForIndex(subpop_id));\n        }\n\t}\n\t\n\treturn legend_key;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMGraphView_SubpopFitnessDists.h",
    "content": "//\n//  QtSLiMGraphView_SubpopFitnessDists.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/3/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMGRAPHVIEW_SUBPOPFITNESSDISTS_H\n#define QTSLIMGRAPHVIEW_SUBPOPFITNESSDISTS_H\n\n#include <QWidget>\n\n#include \"QtSLiMGraphView.h\"\n\nclass Subpopulation;\n\n\nclass QtSLiMGraphView_SubpopFitnessDists : public QtSLiMGraphView\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGraphView_SubpopFitnessDists(QWidget *p_parent, QtSLiMWindow *controller);\n    virtual ~QtSLiMGraphView_SubpopFitnessDists() override;\n    \n    virtual QString graphTitle(void) override;\n    virtual QString aboutString(void) override;\n    virtual void drawGraph(QPainter &painter, QRect interiorRect) override;\n    virtual bool providesStringForData(void) override;\n    virtual void appendStringForData(QString &string) override;    \n    \nprotected:\n    virtual QtSLiMLegendSpec legendKey(void) override;    \n    \nprivate:\n    double *subpopulationFitnessData(const Subpopulation *requestedSubpop);    \n};\n\n\n#endif // QTSLIMGRAPHVIEW_SUBPOPFITNESSDISTS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeManager.cpp",
    "content": "//\n//  QtSLiMHaplotypeManager.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/3/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMChromosomeWidget.h\"\n#include \"QtSLiMHaplotypeOptions.h\"\n#include \"QtSLiMHaplotypeProgress.h\"\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMExtras.h\"\n\n#include <QOpenGLFunctions>\n#include <QDialog>\n#include <QMenu>\n#include <QAction>\n#include <QContextMenuEvent>\n#include <QGuiApplication>\n#include <QClipboard>\n#include <QMimeData>\n#include <QFileDialog>\n#include <QStandardPaths>\n#include <QLabel>\n#include <QMessageBox>\n#include <QPalette>\n#include <QDebug>\n\n#include <vector>\n#include <algorithm>\n#include <utility>\n\n#include \"eidos_globals.h\"\n#include \"subpopulation.h\"\n#include \"species.h\"\n\n\nconst int QtSLiM_SubpopulationStripWidth = 5;\n\n\n// This class method runs a plot options dialog, and then produces a haplotype plot with a progress panel as it is being constructed\nvoid QtSLiMHaplotypeManager::CreateHaplotypePlot(QtSLiMChromosomeWidgetController *controller, Chromosome *focalChromosome)\n{\n    QtSLiMWindow *slimWindow = controller->slimWindow();\n    \n    if (!slimWindow)\n        return;\n    \n    Species *displaySpecies = controller->focalDisplaySpecies();\n    \n    if (!displaySpecies)\n    {\n        QMessageBox messageBox(slimWindow);\n        messageBox.setText(\"Haplotype Plot\");\n        messageBox.setInformativeText(\"A single species must be chosen to create a haplotype plot; the plot will be based upon the selected species.\");\n        messageBox.setIcon(QMessageBox::Warning);\n        \n        // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n        // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n        // seems necessary so floating windows can't be on top of the message box\n        messageBox.setWindowModality(Qt::ApplicationModal);\n        messageBox.exec();\n        return;\n    }\n    \n    // This method can create a haplotype plot for one chromosome or many.  Many is the\n    // base case, of which one is a special case.  Chromosomes assort independently, so\n    // each per-chromosome plot is independent, but it is useful to see them together.\n    std::vector<Chromosome *> chromosomes;\n    \n    if (focalChromosome)\n        chromosomes.push_back(focalChromosome);\n    else\n        chromosomes = displaySpecies->Chromosomes();\n    \n    if (chromosomes.size() == 0)\n        return;         // should never happen; menu items etc. should be disabled in this case\n    \n    slim_position_t longestLength = 0;\n    \n    for (Chromosome *chromosome : chromosomes)\n        longestLength = std::max(longestLength, chromosome->last_position_ + 1);\n    \n    // Run the options panel\n    QtSLiMHaplotypeOptions optionsPanel(controller->slimWindow());\n    \n    int result = optionsPanel.exec();\n    \n    if (result != QDialog::Accepted)\n        return;\n    \n    QtSLiMHaplotypeManager::ClusteringMethod clusteringMethod = optionsPanel.clusteringMethod();\n    QtSLiMHaplotypeManager::ClusteringOptimization clusteringOptimization = optionsPanel.clusteringOptimization();\n    size_t haplosomeSampleSize = optionsPanel.haplosomeSampleSize();\n    \n    // Make a new window to show the graph\n    QWidget *window = new QWidget(controller->slimWindow(), Qt::Window | Qt::Tool);    // the graph window has us as a parent, but is still a standalone window\n    \n    window->setMinimumSize(400, 200);\n    window->resize(500, 400);\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    window->setWindowIcon(QIcon());\n#endif\n    \n    // Set up a top-level view, topViewWidget, that contains all of the haplotype views (empty for now)\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    \n    QtSLiMHaplotypeTopView *topViewWidget = new QtSLiMHaplotypeTopView(nullptr);\n    QHBoxLayout *allViewsLayout = new QHBoxLayout;\n    \n    allViewsLayout->setContentsMargins(5, 5, 5, 5);\n    allViewsLayout->setSpacing(5);\n    \n    topViewWidget->setLayout(allViewsLayout);\n    topLayout->addWidget(topViewWidget);\n    \n    if (chromosomes.size() > 1)\n    {\n        topViewWidget->setShowChromosomeSymbols(true);\n        allViewsLayout->setContentsMargins(5, 20, 5, 5);\n    }\n    \n    std::vector<QtSLiMHaplotypeView *> haplotypeViews;\n    \n    for (Chromosome *chromosome : chromosomes)\n    {\n        QtSLiMHaplotypeView *haplotypeView = new QtSLiMHaplotypeView(nullptr);\n        QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);\n        sizePolicy1.setHorizontalStretch(std::max(3, (int)std::round(255 * ((chromosome->last_position_ + 1) / (double)longestLength))));\n        sizePolicy1.setVerticalStretch(0);\n        haplotypeView->setSizePolicy(sizePolicy1);\n        haplotypeView->chromosomeSymbol_ = chromosome->Symbol();\n        \n        allViewsLayout->addWidget(haplotypeView);\n        haplotypeViews.push_back(haplotypeView);\n    }\n    \n    // Add a horizontal layout at the bottom, for the action button, and maybe other cruft, over time\n    // The first haplotype view runs the action buttion, and forwards all state changes along the chain\n    QHBoxLayout *buttonLayout = nullptr;\n    \n    {\n        buttonLayout = new QHBoxLayout;\n        \n        buttonLayout->setContentsMargins(5, 5, 5, 5);\n        buttonLayout->setSpacing(5);\n        topLayout->addLayout(buttonLayout);\n        \n        if (controller->community()->all_species_.size() > 1)\n        {\n            // make our species avatar badge\n            QLabel *speciesLabel = new QLabel();\n            speciesLabel->setText(QString::fromStdString(displaySpecies->avatar_));\n            buttonLayout->addWidget(speciesLabel);\n        }\n        \n        QSpacerItem *leftSpacer = new QSpacerItem(16, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);\n        buttonLayout->addItem(leftSpacer);\n        \n        if (chromosomes.size() > 1)\n        {\n            // draw a little warning, in gray italic small, since users might think the chromosome plots are somehow correlated\n            QLabel *warningLabel = new QLabel();\n            \n            warningLabel->setText(\"note: each chromosome is sampled independently\");\n            warningLabel->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);\n            \n            QFont labelFont(warningLabel->font());\n            labelFont.setItalic(true);\n            labelFont.setPointSize(labelFont.pointSize() - 2);\n            warningLabel->setFont(labelFont);\n            \n            QPalette labelPalette(warningLabel->palette());\n            labelPalette.setColor(QPalette::WindowText, QtSLiMColorWithWhite(0.5, 1.0));\n            warningLabel->setPalette(labelPalette);\n            \n            buttonLayout->addWidget(warningLabel);\n        }\n        \n        QSpacerItem *rightSpacer = new QSpacerItem(16, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);\n        buttonLayout->addItem(rightSpacer);\n        \n        // this code is based on the creation of executeScriptButton in ui_QtSLiMEidosConsole.h\n        QtSLiMPushButton *actionButton = new QtSLiMPushButton(window);\n        actionButton->setObjectName(QString::fromUtf8(\"actionButton\"));\n        actionButton->setMinimumSize(QSize(20, 20));\n        actionButton->setMaximumSize(QSize(20, 20));\n        actionButton->setFocusPolicy(Qt::NoFocus);\n        QIcon icon4;\n        icon4.addFile(QtSLiMImagePath(\"action\", false), QSize(), QIcon::Normal, QIcon::Off);\n        icon4.addFile(QtSLiMImagePath(\"action\", true), QSize(), QIcon::Normal, QIcon::On);\n        actionButton->setIcon(icon4);\n        actionButton->setIconSize(QSize(20, 20));\n        actionButton->qtslimSetBaseName(\"action\");\n        actionButton->setCheckable(true);\n        actionButton->setFlat(true);\n#if QT_CONFIG(tooltip)\n        actionButton->setToolTip(\"<html><head/><body><p>configure plot</p></body></html>\");\n#endif // QT_CONFIG(tooltip)\n        buttonLayout->addWidget(actionButton);\n        \n        connect(actionButton, &QPushButton::pressed, topViewWidget, [actionButton, topViewWidget]() { actionButton->qtslimSetHighlight(true); topViewWidget->actionButtonRunMenu(actionButton); });\n        connect(actionButton, &QPushButton::released, topViewWidget, [actionButton]() { actionButton->qtslimSetHighlight(false); });\n        \n        actionButton->setEnabled(true);\n    }\n    \n    // make window actions for all global menu items\n    // we do NOT need to do this, because we use Qt::Tool; Qt will use our parent winodw's shortcuts\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(window);\n    \n    // If we have more than one chromosome to do, show the window so the user can see partial results there\n    if (chromosomes.size() > 1)\n        QtSLiMMakeWindowVisibleAndExposed(window);\n    \n    // then create and install the haplotype managers, one by one; each will display once it is completed\n    for (int index = 0; index < (int)chromosomes.size(); ++index)\n    {\n        Chromosome *chromosome = chromosomes[index];\n        QtSLiMHaplotypeView *haplotypeView = haplotypeViews[index];\n        \n        // First generate the haplotype plot data, with a progress panel\n        QtSLiMHaplotypeManager *haplotypeManager = new QtSLiMHaplotypeManager(nullptr, clusteringMethod, clusteringOptimization, controller,\n                                                                              displaySpecies, chromosome, QtSLiMRange(0,0), haplosomeSampleSize,\n                                                                              true, index + 1, chromosomes.size());\n        \n        if (haplotypeManager->valid_)\n        {\n            // this will be called for each chromosome, but the titles should all be the same, so it's fine\n            window->setWindowTitle(QString(\"Haplotype snapshot (%1)\").arg(haplotypeManager->titleStringWithoutChromosome));\n            \n            // The haplotype manager is owned by the graph view, as a delegate object\n            haplotypeView->setDelegate(haplotypeManager);\n        }\n    }\n    \n    // If we have just one chromosome to do, show the window now that it's done\n    if (chromosomes.size() <= 1)\n        QtSLiMMakeWindowVisibleAndExposed(window);\n}\n\nQtSLiMHaplotypeManager::QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMethod clusteringMethod, ClusteringOptimization optimizationMethod,\n                                               QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, Chromosome *chromosome,\n                                               QtSLiMRange displayedRange, size_t sampleSize, bool showProgress, int progressChromIndex,\n                                               int progressChromTotal) :\n    QObject(p_parent)\n{\n    controller_ = controller;\n    focalSpeciesName_ = displaySpecies->name_;\n    \n    Community *community = controller_->community();\n    Species *graphSpecies = focalDisplaySpecies();\n    Population &population = graphSpecies->population_;\n    \n    clusterMethod = clusteringMethod;\n    clusterOptimization = optimizationMethod;\n    \n    // Figure out which subpops are selected (or if none are, consider all to be); we will display only the selected subpops\n    std::vector<Subpopulation *> selected_subpops;\n    \n    for (auto subpop_pair : population.subpops_)\n        if (subpop_pair.second->gui_selected_)\n            selected_subpops.emplace_back(subpop_pair.second);\n    \n    if (selected_subpops.size() == 0)\n        for (auto subpop_pair : population.subpops_)\n            selected_subpops.emplace_back(subpop_pair.second);\n    \n    // Figure out whether we're analyzing / displaying a subrange\n    usingSubrange = (displayedRange.length == 0) ? false : true;\n    subrangeFirstBase = displayedRange.location;\n    subrangeLastBase = displayedRange.location + displayedRange.length - 1;\n    \n    // Also dig to find out whether we're displaying all mutation types or just a subset; if a subset, each MutationType has a display flag\n    displayingMuttypeSubset = (controller_->displayMuttypes_.size() != 0);\n    \n    // Set our window title from the controller's state\n    QString title;\n    \n    if (selected_subpops.size() == 0)\n    {\n        // If there are no subpops (which can happen at the very start of running a model, for example), use a dash\n        title = \"–\";\n    }\n    else\n    {\n        bool first_subpop = true;\n        \n        for (Subpopulation *subpop : selected_subpops)\n        {\n            if (!first_subpop)\n                title.append(\" \");\n            \n            title.append(QString(\"p%1\").arg(subpop->subpopulation_id_));\n            \n            first_subpop = false;\n        }\n    }\n    \n    if (usingSubrange)\n        title.append(QString(\", positions %1:%2\").arg(subrangeFirstBase).arg(subrangeLastBase));\n    \n    title.append(QString(\", tick %1\").arg(community->Tick()));\n    \n    titleStringWithoutChromosome = title;\n    \n    if (displaySpecies->Chromosomes().size() > 1)\n        title.append(QString(\", chromosome '%2'\").arg(QString::fromStdString(chromosome->Symbol())));\n    \n    titleString = title;\n    subpopCount = static_cast<int>(selected_subpops.size());\n    \n    // Fetch haplosomes and figure out what we're going to plot; note that we plot only non-null haplosomes\n    slim_chromosome_index_t chromosome_index = chromosome->Index();\n    int first_haplosome_index = graphSpecies->FirstHaplosomeIndices()[chromosome_index];\n    int last_haplosome_index = graphSpecies->LastHaplosomeIndices()[chromosome_index];\n    \n    for (Subpopulation *subpop : selected_subpops)\n    {\n        for (Individual *ind : subpop->parent_individuals_)\n        {\n            Haplosome **ind_haplosomes = ind->haplosomes_;\n            \n            for (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n            {\n                Haplosome *haplosome = ind_haplosomes[haplosome_index];\n                \n                if (!haplosome->IsNull())\n                    haplosomes.emplace_back(haplosome);\n            }\n        }\n    }\n    \n    // If a sample is requested, select that now; sampleSize <= 0 means no sampling\n    if ((sampleSize > 0) && (haplosomes.size() > sampleSize))\n    {\n        Eidos_random_unique(haplosomes.begin(), haplosomes.end(), sampleSize);\n\t\thaplosomes.resize(sampleSize);\n    }\n    \n    // Cache all the information about the mutations that we're going to need\n    configureMutationInfoBuffer(chromosome);\n    \n    // Keep track of the range of subpop IDs we reference, even if not represented by any haplosomes here\n    maxSubpopID = 0;\n    minSubpopID = SLIM_MAX_ID_VALUE;\n    \n    for (Subpopulation *subpop : selected_subpops)\n    {\n        slim_objectid_t subpop_id = subpop->subpopulation_id_;\n        \n        minSubpopID = std::min(minSubpopID, subpop_id);\n        maxSubpopID = std::max(maxSubpopID, subpop_id);\n    }\n    \n    // Show a progress panel if requested\n    if (showProgress)\n    {\n        int progressSteps = (clusterOptimization == QtSLiMHaplotypeManager::ClusterOptimizeWith2opt) ? 3 : 2;\n        \n        progressPanel_ = new QtSLiMHaplotypeProgress(controller_->slimWindow());\n        progressPanel_->runProgressWithHaplosomeCount(haplosomes.size(), progressSteps, progressChromIndex, progressChromTotal);\n    }\n    \n    // Do the clustering analysis synchronously, updating the progress panel as we go\n    finishClusteringAnalysis();\n    \n    // Hide the progress panel\n    if (progressPanel_)\n    {\n        progressPanel_->hide();\n        delete progressPanel_;\n        progressPanel_ = nullptr;\n    }\n}\n\nQtSLiMHaplotypeManager::~QtSLiMHaplotypeManager(void)\n{\n    if (mutationInfo)\n\t{\n\t\tfree(mutationInfo);\n\t\tmutationInfo = nullptr;\n\t}\n\t\n\tif (mutationPositions)\n\t{\n\t\tfree(mutationPositions);\n\t\tmutationPositions = nullptr;\n\t}\n\t\n\tif (displayList)\n\t{\n\t\tdelete displayList;\n\t\tdisplayList = nullptr;\n\t}\n}\n\nSpecies *QtSLiMHaplotypeManager::focalDisplaySpecies(void)\n{\n    // We look up our focal species object by name every time, since keeping a pointer to it would be unsafe\n    // Before initialize() is done species have not been created, so we return nullptr in that case\n    if (controller_ && controller_->community() && (controller_->community()->Tick() >= 1))\n\t\treturn controller_->community()->SpeciesWithName(focalSpeciesName_);\n\t\n\treturn nullptr;\n}\n\nvoid QtSLiMHaplotypeManager::finishClusteringAnalysis(void)\n{\n\t// Work out an approximate best sort order\n\tsortHaplosomes();\n\t\n    if (valid_ && progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n        valid_ = false;\n    \n    if (valid_)\n\t{\n\t\t// Remember the subpop ID for each haplosome\n\t\tfor (Haplosome *haplosome : haplosomes)\n\t\t\thaplosomeSubpopIDs.emplace_back(haplosome->individual_->subpopulation_->subpopulation_id_);\n\t\t\n\t\t// Build our plotting data vectors.  Because we are a snapshot, we can't rely on our controller's data\n\t\t// at all after this method returns; we have to remember everything we need to create our display list.\n\t\tconfigureDisplayBuffers();\n\t}\n\t\n\t// Now we are done with the haplosomes vector; clear it\n\thaplosomes.clear();\n\thaplosomes.resize(0);\n}\n\nvoid QtSLiMHaplotypeManager::configureMutationInfoBuffer(Chromosome *chromosome)\n{\n    Species *graphSpecies = focalDisplaySpecies();\n    \n    if (!graphSpecies)\n        return;\n    \n    Population &population = graphSpecies->population_;\n\tdouble scalingFactor = 0.8; // used to be controller->selectionColorScale;\n    int registry_size;\n    const MutationIndex *registry = population.MutationRegistry(&registry_size);\n\tconst MutationIndex *reg_end_ptr = registry + registry_size;\n\tMutationIndex biggest_index = 0;\n\t\n\t// First, find the biggest index presently in use; that's how many entries we need\n    // BCH 12/25/2024: With multiple chromosomes, this is rather wasteful; I think this class\n    // could be redesigned to capture just the subset of mutations that are live for a given\n    // chromosome, essentially re-indexing the mutations, but it's not clear this matters\n    // to performance; we just waste a bit of memory here, but it's not a big deal.\n\tfor (const MutationIndex *reg_ptr = registry; reg_ptr != reg_end_ptr; ++reg_ptr)\n\t{\n\t\tMutationIndex mut_index = *reg_ptr;\n\t\t\n\t\tif (mut_index > biggest_index)\n\t\t\tbiggest_index = mut_index;\n\t}\n\t\n\t// Allocate our mutationInfo buffer with entries for every MutationIndex in use\n\tmutationIndexCount = static_cast<size_t>(biggest_index + 1);\n\tmutationInfo = static_cast<HaploMutation *>(malloc(sizeof(HaploMutation) * mutationIndexCount));\n\tmutationPositions = static_cast<slim_position_t *>(malloc(sizeof(slim_position_t) * mutationIndexCount));\n\t\n\t// Copy the information we need on each mutation in use\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tfor (const MutationIndex *reg_ptr = registry; reg_ptr != reg_end_ptr; ++reg_ptr)\n\t{\n\t\tMutationIndex mut_index = *reg_ptr;\n\t\tconst Mutation *mut = mut_block_ptr + mut_index;\n\t\tslim_position_t mut_position = mut->position_;\n\t\tconst MutationType *mut_type = mut->mutation_type_ptr_;\n\t\tHaploMutation *haplo_mut = mutationInfo + mut_index;\n\t\t\n\t\thaplo_mut->position_ = mut_position;\n\t\t*(mutationPositions + mut_index) = mut_position;\n\t\t\n\t\tif (!mut_type->color_.empty())\n\t\t{\n\t\t\thaplo_mut->red_ = mut_type->color_red_;\n\t\t\thaplo_mut->green_ = mut_type->color_green_;\n\t\t\thaplo_mut->blue_ = mut_type->color_blue_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRGBForSelectionCoeff(static_cast<double>(mut->selection_coeff_), &haplo_mut->red_, &haplo_mut->green_, &haplo_mut->blue_, scalingFactor);\n\t\t}\n\t\t\n\t\thaplo_mut->neutral_ = (mut->selection_coeff_ == 0.0f);\n\t\t\n\t\thaplo_mut->display_ = mut_type->mutation_type_displayed_;\n\t}\n\t\n\t// Remember the chromosome length\n\tmutationLastPosition = chromosome->last_position_;\n}\n\nvoid QtSLiMHaplotypeManager::sortHaplosomes(void)\n{\n    size_t haplosome_count = haplosomes.size();\n\t\n\tif (haplosome_count == 0)\n\t\treturn;\n\t\n\tstd::vector<Haplosome *> original_haplosomes = haplosomes;\t// copy the vector because we will need to reorder it below\n\tstd::vector<int> final_path;\n\t\n\t// first get our distance matrix; these are inter-city distances\n\tint64_t *distances;\n\t\n\tif (displayingMuttypeSubset)\n\t{\n\t\tif (usingSubrange)\n\t\t\tdistances = buildDistanceArrayForSubrangeAndSubtypes();\n\t\telse\n\t\t\tdistances = buildDistanceArrayForSubtypes();\n\t}\n\telse\n\t{\n\t\tif (usingSubrange)\n\t\t\tdistances = buildDistanceArrayForSubrange();\n\t\telse\n\t\t\tdistances = buildDistanceArray();\n\t}\n\t\n    if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\tgoto cancelledExit;\n\t\n\tswitch (clusterMethod)\n\t{\n\t\tcase ClusterNearestNeighbor:\n\t\t\tnearestNeighborSolve(distances, haplosome_count, final_path);\n\t\t\tbreak;\n\t\t\t\n\t\tcase ClusterGreedy:\n\t\t\tgreedySolve(distances, haplosome_count, final_path);\n\t\t\tbreak;\n\t}\n\t\n    if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\tgoto cancelledExit;\n\t\n\tcheckPath(final_path, haplosome_count);\n\t\n    if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\tgoto cancelledExit;\n\t\n\tif (clusterOptimization != ClusterNoOptimization)\n\t{\n\t\tswitch (clusterOptimization)\n\t\t{\n\t\t\tcase ClusterNoOptimization:\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tcase ClusterOptimizeWith2opt:\n\t\t\t\tdo2optOptimizationOfSolution(final_path, distances, haplosome_count);\n\t\t\t\tbreak;\n\t\t}\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            goto cancelledExit;\n\t\t\n\t\tcheckPath(final_path, haplosome_count);\n\t}\n\t\n    if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\tgoto cancelledExit;\n\t\n\t// reorder the haplosomes vector according to the path we found\n\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; ++haplosome_index)\n\t\thaplosomes[haplosome_index] = original_haplosomes[static_cast<size_t>(final_path[haplosome_index])];\n\t\ncancelledExit:\n\tfree(distances);\n}\n\nvoid QtSLiMHaplotypeManager::configureDisplayBuffers(void)\n{\n    size_t haplosome_count = haplosomes.size();\n\t\n\t// Allocate our display list and size it so it has one std::vector<MutationIndex> per haplosome\n\tdisplayList = new std::vector<std::vector<MutationIndex>>;\n\t\n\tdisplayList->resize(haplosome_count);\n\t\n\t// Then save off the information for each haplosome into the display list\n\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; ++haplosome_index)\n\t{\n\t\tHaplosome &haplosome = *haplosomes[haplosome_index];\n\t\tstd::vector<MutationIndex> &haplosome_display = (*displayList)[haplosome_index];\n\t\t\n\t\tif (!usingSubrange)\n\t\t{\n\t\t\t// Size our display list to fit the number of mutations in the haplosome\n\t\t\tsize_t mut_count = static_cast<size_t>(haplosome.mutation_count());\n\t\t\t\n\t\t\thaplosome_display.reserve(mut_count);\n\t\t\t\n\t\t\t// Loop through mutations to get the mutation indices\n\t\t\tint mutrun_count = haplosome.mutrun_count_;\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\t\tconst MutationIndex *mut_start_ptr = mutrun->begin_pointer_const();\n\t\t\t\tconst MutationIndex *mut_end_ptr = mutrun->end_pointer_const();\n\t\t\t\t\n\t\t\t\tif (displayingMuttypeSubset)\n\t\t\t\t{\n\t\t\t\t\t// displaying a subset of mutation types, need to check\n\t\t\t\t\tfor (const MutationIndex *mut_ptr = mut_start_ptr; mut_ptr < mut_end_ptr; ++mut_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut_index = *mut_ptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mutationInfo + mut_index)->display_)\n\t\t\t\t\t\t\thaplosome_display.emplace_back(*mut_ptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// displaying all mutation types, no need to check\n\t\t\t\t\tfor (const MutationIndex *mut_ptr = mut_start_ptr; mut_ptr < mut_end_ptr; ++mut_ptr)\n\t\t\t\t\t\thaplosome_display.emplace_back(*mut_ptr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We are using a subrange, so we need to check the position of each mutation before adding it\n\t\t\tint mutrun_count = haplosome.mutrun_count_;\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\t\tconst MutationIndex *mut_start_ptr = mutrun->begin_pointer_const();\n\t\t\t\tconst MutationIndex *mut_end_ptr = mutrun->end_pointer_const();\n\t\t\t\t\n\t\t\t\tif (displayingMuttypeSubset)\n\t\t\t\t{\n\t\t\t\t\t// displaying a subset of mutation types, need to check\n\t\t\t\t\tfor (const MutationIndex *mut_ptr = mut_start_ptr; mut_ptr < mut_end_ptr; ++mut_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut_index = *mut_ptr;\n\t\t\t\t\t\tslim_position_t mut_position = *(mutationPositions + mut_index);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut_position >= subrangeFirstBase) && (mut_position <= subrangeLastBase))\n\t\t\t\t\t\t\tif ((mutationInfo + mut_index)->display_)\n\t\t\t\t\t\t\t\thaplosome_display.emplace_back(mut_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// displaying all mutation types, no need to check\n\t\t\t\t\tfor (const MutationIndex *mut_ptr = mut_start_ptr; mut_ptr < mut_end_ptr; ++mut_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut_index = *mut_ptr;\n\t\t\t\t\t\tslim_position_t mut_position = *(mutationPositions + mut_index);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut_position >= subrangeFirstBase) && (mut_position <= subrangeLastBase))\n\t\t\t\t\t\t\thaplosome_display.emplace_back(mut_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid QtSLiMHaplotypeManager::tallyBincounts(int64_t *bincounts, std::vector<MutationIndex> &haplosomeList)\n{\n    EIDOS_BZERO(bincounts, 1024 * sizeof(int64_t));\n\t\n\tfor (MutationIndex mut_index : haplosomeList)\n\t\tbincounts[mutationInfo[mut_index].position_ % 1024]++;\n}\n\nint64_t QtSLiMHaplotypeManager::distanceForBincounts(int64_t *bincounts1, int64_t *bincounts2)\n{\n    int64_t distance = 0;\n\t\n\tfor (int i = 0; i < 1024; ++i)\n\t\tdistance += abs(bincounts1[i] - bincounts2[i]);\n\t\n\treturn distance;\n}\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMHaplotypeManager::glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground)\n{\n    // Erase the background to either black or white, depending on displayBW\n\tif (eraseBackground)\n\t{\n\t\tif (displayBW)\n\t\t\tglColor3f(1.0f, 1.0f, 1.0f);\n\t\telse\n\t\t\tglColor3f(0.0f, 0.0f, 0.0f);\n\t\tglRecti(interior.x(), interior.y(), interior.x() + interior.width(), interior.y() + interior.height());\n\t}\n\t\n\t// Draw subpopulation strips if requested\n\tif (showSubpopStrips)\n\t{\n\t\tQRect subpopStripRect = interior;\n\t\t\n        subpopStripRect.setWidth(QtSLiM_SubpopulationStripWidth);\n\t\tglDrawSubpopStripsInRect(subpopStripRect);\n        \n        interior.adjust(QtSLiM_SubpopulationStripWidth, 0, 0, 0);\n\t}\n\t\n\t// Draw the haplotypes in the remaining portion of the interior\n\tglDrawDisplayListInRect(interior, displayBW);\n}\n#endif\n\nvoid QtSLiMHaplotypeManager::qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, QPainter &painter)\n{\n    // Erase the background to either black or white, depending on displayBW\n    if (eraseBackground)\n    {\n        painter.fillRect(interior, displayBW ? Qt::white : Qt::black);\n    }\n    \n    // Draw subpopulation strips if requested\n    if (showSubpopStrips)\n    {\n        QRect subpopStripRect = interior;\n        \n        subpopStripRect.setWidth(QtSLiM_SubpopulationStripWidth);\n        qtDrawSubpopStripsInRect(subpopStripRect, painter);\n        \n        interior.adjust(QtSLiM_SubpopulationStripWidth, 0, 0, 0);\n    }\n    \n    // Draw the haplotypes in the remaining portion of the interior\n    qtDrawDisplayListInRect(interior, displayBW, painter);\n}\n\n// Traveling Salesman Problem code\n//\n// We have a set of haplosomes, each of which may be defined as being a particular distance from each other haplosome (defined here\n// as the number of differences in the mutations contained).  We want to sort the haplosomes into an order that groups similar\n// haplosomes together, minimizing the overall distance through \"haplosome space\" traveled from top to bottom of our display.  This\n// is exactly the Traveling Salesman Problem, without returning to the starting \"city\".  This is a very intensively studied\n// problem, is NP-hard, and would take an enormously long time to solve exactly for even a relatively small number of haplosomes,\n// whereas we will routinely have thousands of haplosomes.  We will find an approximate solution using a fast heuristic algorithm,\n// because we are not greatly concerned with the quality of the solution and we are extremely concerned with runtime.  The\n// nearest-neighbor method is the fastest heuristic, and is O(N^2) in the number of cities; the Greedy algorithm is slower but\n// produces significantly better results.  We can refine our initial solution using the 2-opt method.\n\n#pragma mark Traveling salesman problem\n\n// This allocates and builds an array of distances between haplosomes.  The returned array is owned by the caller.  This is where\n// we spend the large majority of our time, at present; this algorithm is O(N^2), but has a large constant (because really also\n// it depends on the length of the chromosome, the configuration of mutation runs, etc.).  This method runs prior to the actual\n// Traveling Salesman Problem; here we're just figuring out the distances between our \"cities\".  We have four versions of this\n// method, for speed; this is the base version, and separate versions are below that handle a chromosome subrange and/or a\n// subset of all of the mutation types.\nint64_t *QtSLiMHaplotypeManager::buildDistanceArray(void)\n{\n    size_t haplosome_count = haplosomes.size();\n\tint64_t *distances = static_cast<int64_t *>(malloc(haplosome_count * haplosome_count * sizeof(int64_t)));\n\tuint8_t *mutation_seen = static_cast<uint8_t *>(calloc(mutationIndexCount, sizeof(uint8_t)));\n\tuint8_t seen_marker = 1;\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tHaplosome *haplosome1 = haplosomes[i];\n\t\tint64_t *distance_column = distances + i;\n\t\tint64_t *distance_row = distances + i * haplosome_count;\n\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\tconst MutationRun **haplosome1_mutruns = haplosome1->mutruns_;\n\t\t\n\t\tdistance_row[i] = 0;\n\t\t\n\t\tfor (size_t j = i + 1; j < haplosome_count; ++j)\n\t\t{\n\t\t\tHaplosome *haplosome2 = haplosomes[j];\n\t\t\tconst MutationRun **haplosome2_mutruns = haplosome2->mutruns_;\n\t\t\tint64_t distance = 0;\n\t\t\t\n\t\t\tfor (int mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *haplosome1_mutrun = haplosome1_mutruns[mutrun_index];\n\t\t\t\tconst MutationRun *haplosome2_mutrun = haplosome2_mutruns[mutrun_index];\n\t\t\t\tint haplosome1_mutcount = haplosome1_mutrun->size();\n\t\t\t\tint haplosome2_mutcount = haplosome2_mutrun->size();\n\t\t\t\t\n\t\t\t\tif (haplosome1_mutrun == haplosome2_mutrun)\n\t\t\t\t\t;\t\t\t\t\t\t\t\t\t\t// identical runs have no differences\n\t\t\t\telse if (haplosome1_mutcount == 0)\n\t\t\t\t\tdistance += haplosome2_mutcount;\n\t\t\t\telse if (haplosome2_mutcount == 0)\n\t\t\t\t\tdistance += haplosome1_mutcount;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We use a radix strategy to count the number of mismatches; assume up front that all mutations are mismatched,\n\t\t\t\t\t// and then subtract two for each mutation that turns out to be shared, using a uint8_t buffer to track usage.\n\t\t\t\t\tdistance += haplosome1_mutcount + haplosome2_mutcount;\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *mutrun1_end = haplosome1_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun1_ptr = haplosome1_mutrun->begin_pointer_const(); mutrun1_ptr != mutrun1_end; ++mutrun1_ptr)\n\t\t\t\t\t\tmutation_seen[*mutrun1_ptr] = seen_marker;\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *mutrun2_end = haplosome2_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun2_ptr = haplosome2_mutrun->begin_pointer_const(); mutrun2_ptr != mutrun2_end; ++mutrun2_ptr)\n\t\t\t\t\t\tif (mutation_seen[*mutrun2_ptr] == seen_marker)\n\t\t\t\t\t\t\tdistance -= 2;\n\t\t\t\t\t\n\t\t\t\t\t// To avoid having to clear the usage buffer every time, we play an additional trick: we use an incrementing\n\t\t\t\t\t// marker value to indicate usage, and clear the buffer only when it reaches 255.  Makes about a 10% difference!\n\t\t\t\t\tseen_marker++;\n\t\t\t\t\t\n\t\t\t\t\tif (seen_marker == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_BZERO(mutation_seen, mutationIndexCount);\n\t\t\t\t\t\t\n\t\t\t\t\t\tseen_marker = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// set the distance at both mirrored locations in the distance buffer\n\t\t\t*(distance_column + j * haplosome_count) = distance;\n\t\t\t*(distance_row + j) = distance;\n\t\t}\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(i + 1, 0);\n\t}\n\t\n\tfree(mutation_seen);\n\t\n\treturn distances;\n}\n\n// This does the same thing as buildDistanceArrayForHaplosomes:, but uses the chosen subrange of each haplosome\nint64_t *QtSLiMHaplotypeManager::buildDistanceArrayForSubrange(void)\n{\n    slim_position_t firstBase = subrangeFirstBase, lastBase = subrangeLastBase;\n\t\n\tsize_t haplosome_count = haplosomes.size();\n\tint64_t *distances = static_cast<int64_t *>(malloc(haplosome_count * haplosome_count * sizeof(int64_t)));\n\tuint8_t *mutation_seen = static_cast<uint8_t *>(calloc(mutationIndexCount, sizeof(uint8_t)));\n\tuint8_t seen_marker = 1;\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tHaplosome *haplosome1 = haplosomes[i];\n\t\tint64_t *distance_column = distances + i;\n\t\tint64_t *distance_row = distances + i * haplosome_count;\n\t\tslim_position_t mutrun_length = haplosome1->mutrun_length_;\n\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\tconst MutationRun **haplosome1_mutruns = haplosome1->mutruns_;\n\t\t\n\t\tdistance_row[i] = 0;\n\t\t\n\t\tfor (size_t j = i + 1; j < haplosome_count; ++j)\n\t\t{\n\t\t\tHaplosome *haplosome2 = haplosomes[j];\n\t\t\tconst MutationRun **haplosome2_mutruns = haplosome2->mutruns_;\n\t\t\tint64_t distance = 0;\n\t\t\t\n\t\t\tfor (int mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t\t{\n\t\t\t\t// Skip mutation runs outside of the subrange we're focused on\n\t\t\t\tif ((mutrun_length * mutrun_index > lastBase) || (mutrun_length * mutrun_index + mutrun_length - 1 < firstBase))\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// OK, this mutrun intersects with our chosen subrange; proceed\n\t\t\t\tconst MutationRun *haplosome1_mutrun = haplosome1_mutruns[mutrun_index];\n\t\t\t\tconst MutationRun *haplosome2_mutrun = haplosome2_mutruns[mutrun_index];\n\t\t\t\t\n\t\t\t\tif (haplosome1_mutrun == haplosome2_mutrun)\n\t\t\t\t\t;\t\t\t\t\t\t\t\t\t\t// identical runs have no differences\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We use a radix strategy to count the number of mismatches.  Note this is done a bit differently than in\n\t\t\t\t\t// buildDistanceArrayForHaplosomes:; here we do not add the total and then subtract matches.\n\t\t\t\t\tconst MutationIndex *mutrun1_end = haplosome1_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun1_ptr = haplosome1_mutrun->begin_pointer_const(); mutrun1_ptr != mutrun1_end; ++mutrun1_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut1_index = *mutrun1_ptr;\n\t\t\t\t\t\tslim_position_t mut1_position = mutationPositions[mut1_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut1_position >= firstBase) && (mut1_position <= lastBase))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmutation_seen[mut1_index] = seen_marker;\n\t\t\t\t\t\t\tdistance++;\t\t// assume unmatched\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *mutrun2_end = haplosome2_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun2_ptr = haplosome2_mutrun->begin_pointer_const(); mutrun2_ptr != mutrun2_end; ++mutrun2_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut2_index = *mutrun2_ptr;\n\t\t\t\t\t\tslim_position_t mut2_position = mutationPositions[mut2_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut2_position >= firstBase) && (mut2_position <= lastBase))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutation_seen[mut2_index] == seen_marker)\n\t\t\t\t\t\t\t\tdistance -= 1;\t// matched, so decrement to compensate for the assumption of non-match above\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tdistance++;\t\t// not matched, so increment\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// To avoid having to clear the usage buffer every time, we play an additional trick: we use an incrementing\n\t\t\t\t\t// marker value to indicate usage, and clear the buffer only when it reaches 255.  Makes about a 10% difference!\n\t\t\t\t\tseen_marker++;\n\t\t\t\t\t\n\t\t\t\t\tif (seen_marker == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_BZERO(mutation_seen, mutationIndexCount);\n\t\t\t\t\t\t\n\t\t\t\t\t\tseen_marker = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// set the distance at both mirrored locations in the distance buffer\n\t\t\t*(distance_column + j * haplosome_count) = distance;\n\t\t\t*(distance_row + j) = distance;\n\t\t}\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(i + 1, 0);\n\t}\n\t\n\tfree(mutation_seen);\n\t\n\treturn distances;\n}\n\n// This does the same thing as buildDistanceArrayForHaplosomes:, but uses only mutations of a mutation type that is chosen for display\nint64_t *QtSLiMHaplotypeManager::buildDistanceArrayForSubtypes(void)\n{\n    size_t haplosome_count = haplosomes.size();\n\tint64_t *distances = static_cast<int64_t *>(malloc(haplosome_count * haplosome_count * sizeof(int64_t)));\n\tuint8_t *mutation_seen = static_cast<uint8_t *>(calloc(mutationIndexCount, sizeof(uint8_t)));\n\tuint8_t seen_marker = 1;\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tHaplosome *haplosome1 = haplosomes[i];\n\t\tint64_t *distance_column = distances + i;\n\t\tint64_t *distance_row = distances + i * haplosome_count;\n\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\tconst MutationRun **haplosome1_mutruns = haplosome1->mutruns_;\n\t\t\n\t\tdistance_row[i] = 0;\n\t\t\n\t\tfor (size_t j = i + 1; j < haplosome_count; ++j)\n\t\t{\n\t\t\tHaplosome *haplosome2 = haplosomes[j];\n\t\t\tconst MutationRun **haplosome2_mutruns = haplosome2->mutruns_;\n\t\t\tint64_t distance = 0;\n\t\t\t\n\t\t\tfor (int mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *haplosome1_mutrun = haplosome1_mutruns[mutrun_index];\n\t\t\t\tconst MutationRun *haplosome2_mutrun = haplosome2_mutruns[mutrun_index];\n\t\t\t\t\n\t\t\t\tif (haplosome1_mutrun == haplosome2_mutrun)\n\t\t\t\t\t;\t\t\t\t\t\t\t\t\t\t// identical runs have no differences\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We use a radix strategy to count the number of mismatches.  Note this is done a bit differently than in\n\t\t\t\t\t// buildDistanceArrayForHaplosomes:; here we do not add the total and then subtract matches.\n\t\t\t\t\tconst MutationIndex *mutrun1_end = haplosome1_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun1_ptr = haplosome1_mutrun->begin_pointer_const(); mutrun1_ptr != mutrun1_end; ++mutrun1_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut1_index = *mutrun1_ptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutationInfo[mut1_index].display_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmutation_seen[mut1_index] = seen_marker;\n\t\t\t\t\t\t\tdistance++;\t\t// assume unmatched\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *mutrun2_end = haplosome2_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun2_ptr = haplosome2_mutrun->begin_pointer_const(); mutrun2_ptr != mutrun2_end; ++mutrun2_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut2_index = *mutrun2_ptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutationInfo[mut2_index].display_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutation_seen[mut2_index] == seen_marker)\n\t\t\t\t\t\t\t\tdistance -= 1;\t// matched, so decrement to compensate for the assumption of non-match above\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tdistance++;\t\t// not matched, so increment\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// To avoid having to clear the usage buffer every time, we play an additional trick: we use an incrementing\n\t\t\t\t\t// marker value to indicate usage, and clear the buffer only when it reaches 255.  Makes about a 10% difference!\n\t\t\t\t\tseen_marker++;\n\t\t\t\t\t\n\t\t\t\t\tif (seen_marker == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_BZERO(mutation_seen, mutationIndexCount);\n\t\t\t\t\t\t\n\t\t\t\t\t\tseen_marker = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// set the distance at both mirrored locations in the distance buffer\n\t\t\t*(distance_column + j * haplosome_count) = distance;\n\t\t\t*(distance_row + j) = distance;\n\t\t}\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(i + 1, 0);\n\t}\n\t\n\tfree(mutation_seen);\n\t\n\treturn distances;\n}\n\n// This does the same thing as buildDistanceArrayForHaplosomes:, but uses the chosen subrange of each haplosome, and only mutations of mutation types being displayed\nint64_t *QtSLiMHaplotypeManager::buildDistanceArrayForSubrangeAndSubtypes(void)\n{\n    slim_position_t firstBase = subrangeFirstBase, lastBase = subrangeLastBase;\n\t\n\tsize_t haplosome_count = haplosomes.size();\n\tint64_t *distances = static_cast<int64_t *>(malloc(haplosome_count * haplosome_count * sizeof(int64_t)));\n\tuint8_t *mutation_seen = static_cast<uint8_t *>(calloc(mutationIndexCount, sizeof(uint8_t)));\n\tuint8_t seen_marker = 1;\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tHaplosome *haplosome1 = haplosomes[i];\n\t\tint64_t *distance_column = distances + i;\n\t\tint64_t *distance_row = distances + i * haplosome_count;\n\t\tslim_position_t mutrun_length = haplosome1->mutrun_length_;\n\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\tconst MutationRun **haplosome1_mutruns = haplosome1->mutruns_;\n\t\t\n\t\tdistance_row[i] = 0;\n\t\t\n\t\tfor (size_t j = i + 1; j < haplosome_count; ++j)\n\t\t{\n\t\t\tHaplosome *haplosome2 = haplosomes[j];\n\t\t\tconst MutationRun **haplosome2_mutruns = haplosome2->mutruns_;\n\t\t\tint64_t distance = 0;\n\t\t\t\n\t\t\tfor (int mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t\t{\n\t\t\t\t// Skip mutation runs outside of the subrange we're focused on\n\t\t\t\tif ((mutrun_length * mutrun_index > lastBase) || (mutrun_length * mutrun_index + mutrun_length - 1 < firstBase))\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// OK, this mutrun intersects with our chosen subrange; proceed\n\t\t\t\tconst MutationRun *haplosome1_mutrun = haplosome1_mutruns[mutrun_index];\n\t\t\t\tconst MutationRun *haplosome2_mutrun = haplosome2_mutruns[mutrun_index];\n\t\t\t\t\n\t\t\t\tif (haplosome1_mutrun == haplosome2_mutrun)\n\t\t\t\t\t;\t\t\t\t\t\t\t\t\t\t// identical runs have no differences\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We use a radix strategy to count the number of mismatches.  Note this is done a bit differently than in\n\t\t\t\t\t// buildDistanceArrayForHaplosomes:; here we do not add the total and then subtract matches.\n\t\t\t\t\tconst MutationIndex *mutrun1_end = haplosome1_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun1_ptr = haplosome1_mutrun->begin_pointer_const(); mutrun1_ptr != mutrun1_end; ++mutrun1_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut1_index = *mutrun1_ptr;\n\t\t\t\t\t\tslim_position_t mut1_position = mutationPositions[mut1_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut1_position >= firstBase) && (mut1_position <= lastBase))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutationInfo[mut1_index].display_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmutation_seen[mut1_index] = seen_marker;\n\t\t\t\t\t\t\t\tdistance++;\t\t// assume unmatched\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *mutrun2_end = haplosome2_mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationIndex *mutrun2_ptr = haplosome2_mutrun->begin_pointer_const(); mutrun2_ptr != mutrun2_end; ++mutrun2_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut2_index = *mutrun2_ptr;\n\t\t\t\t\t\tslim_position_t mut2_position = mutationPositions[mut2_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut2_position >= firstBase) && (mut2_position <= lastBase))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutationInfo[mut2_index].display_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (mutation_seen[mut2_index] == seen_marker)\n\t\t\t\t\t\t\t\t\tdistance -= 1;\t// matched, so decrement to compensate for the assumption of non-match above\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tdistance++;\t\t// not matched, so increment\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// To avoid having to clear the usage buffer every time, we play an additional trick: we use an incrementing\n\t\t\t\t\t// marker value to indicate usage, and clear the buffer only when it reaches 255.  Makes about a 10% difference!\n\t\t\t\t\tseen_marker++;\n\t\t\t\t\t\n\t\t\t\t\tif (seen_marker == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_BZERO(mutation_seen, mutationIndexCount);\n\t\t\t\t\t\t\n\t\t\t\t\t\tseen_marker = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// set the distance at both mirrored locations in the distance buffer\n\t\t\t*(distance_column + j * haplosome_count) = distance;\n\t\t\t*(distance_row + j) = distance;\n\t\t}\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(i + 1, 0);\n\t}\n\t\n\tfree(mutation_seen);\n\t\n\treturn distances;\n}\n\n// Since we want to solve the Traveling Salesman Problem without returning to the original city, the choice of the initial city\n// may be quite important to the solution we get.  It seems reasonable to start at the city that is the most isolated, i.e. has\n// the largest distance from itself to any other city.  By starting with this city, we avoid having to have two edges connecting\n// to it, both of which would be relatively long.  However, this is just a guess, and might be modified by refinement later.\nint QtSLiMHaplotypeManager::indexOfMostIsolatedHaplosomeWithDistances(int64_t *distances, size_t haplosome_count)\n{\n\tint64_t greatest_isolation = -1;\n\tint greatest_isolation_index = -1;\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tint64_t isolation = INT64_MAX;\n\t\tint64_t *row_ptr = distances + i * haplosome_count;\n\t\t\n\t\tfor (size_t j = 0; j < haplosome_count; ++j)\n\t\t{\n\t\t\tint64_t distance = row_ptr[j];\n\t\t\t\n\t\t\t// distances of 0 don't count for isolation estimation; we really want the most isolated identical cluster of haplosomes\n\t\t\t// this also serves to take care of the j == i case for us without special-casing, which is nice...\n\t\t\tif (distance == 0)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tif (distance < isolation)\n\t\t\t\tisolation = distance;\n\t\t}\n\t\t\n\t\tif (isolation > greatest_isolation)\n\t\t{\n\t\t\tgreatest_isolation = isolation;\n\t\t\tgreatest_isolation_index = static_cast<int>(i);\n\t\t}\n\t}\n\t\n\treturn greatest_isolation_index;\n}\n\n// The nearest-neighbor method provides an initial solution for the Traveling Salesman Problem by beginning with a chosen city\n// (see indexOfMostIsolatedHaplosomeWithDistances:size: above) and adding successive cities according to which is closest to the\n// city we have reached thus far.  This is quite simple to implement, and runs in O(N^2) time.  However, the greedy algorithm\n// below runs only a little more slowly, and produces significantly better results, so unless speed is essential it is better.\nvoid QtSLiMHaplotypeManager::nearestNeighborSolve(int64_t *distances, size_t haplosome_count, std::vector<int> &solution)\n{\n    size_t haplosomes_left = haplosome_count;\n\t\n\tsolution.reserve(haplosome_count);\n\t\n\t// we have to make a copy of the distances matrix, as we modify it internally\n\tint64_t *distances_copy = static_cast<int64_t *>(malloc(haplosome_count * haplosome_count * sizeof(int64_t)));\n\t\n\tmemcpy(distances_copy, distances, haplosome_count * haplosome_count * sizeof(int64_t));\n\t\n\t// find the haplosome that is farthest from any other haplosome; this will be our starting point, for now\n\tint last_path_index = indexOfMostIsolatedHaplosomeWithDistances(distances_copy, haplosome_count);\n\t\n\tdo\n\t{\n\t\t// add the chosen haplosome to our path\n\t\tsolution.emplace_back(last_path_index);\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(haplosome_count - haplosomes_left + 1, 1);\n\t\t\n\t\t// if we just added the last haplosome, we're done\n\t\tif (--haplosomes_left == 0)\n\t\t\tbreak;\n\t\t\n\t\t// otherwise, mark the chosen haplosome as unavailable by setting distances to it to INT64_MAX\n\t\tint64_t *column_ptr = distances_copy + last_path_index;\n\t\t\n\t\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t\t{\n\t\t\t*column_ptr = INT64_MAX;\n\t\t\tcolumn_ptr += haplosome_count;\n\t\t}\n\t\t\n\t\t// now we need to find the next city, which will be the nearest neighbor of the last city\n\t\tint64_t *row_ptr = distances_copy + last_path_index * static_cast<int>(haplosome_count);\n\t\tint64_t nearest_neighbor_distance = INT64_MAX;\n\t\tint nearest_neighbor_index = -1;\n\t\t\n\t\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t\t{\n\t\t\tint64_t distance = row_ptr[i];\n\t\t\t\n\t\t\tif (distance < nearest_neighbor_distance)\n\t\t\t{\n\t\t\t\tnearest_neighbor_distance = distance;\n\t\t\t\tnearest_neighbor_index = static_cast<int>(i);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// found the next city; add it to the path by looping back to the top\n\t\tlast_path_index = nearest_neighbor_index;\n\t}\n\twhile (true);\n\t\n\tfree(distances_copy);\n}\n\n// The greedy method provides an initial solution for the Traveling Salesman Problem by sorting all possible edges,\n// and then iteratively adding the shortest legal edge to the path until the full path has been constructed.  This\n// is a little more complex than nearest neighbor, and runs a bit more slowly, but gives a somewhat better result.\ntypedef struct {\n\tint i, k;\n\tint64_t d;\n} greedy_edge;\n\nstatic bool operator<(const greedy_edge &i, const greedy_edge &j) __attribute__((unused));\nstatic bool operator>(const greedy_edge &i, const greedy_edge &j) __attribute__((unused));\nstatic bool operator==(const greedy_edge &i, const greedy_edge &j) __attribute__((unused));\nstatic bool operator!=(const greedy_edge &i, const greedy_edge &j) __attribute__((unused));\n\nstatic bool operator<(const greedy_edge &i, const greedy_edge &j) { return (i.d < j.d); }\nstatic bool operator>(const greedy_edge &i, const greedy_edge &j) { return (i.d > j.d); }\nstatic bool operator==(const greedy_edge &i, const greedy_edge &j) { return (i.d == j.d); }\nstatic bool operator!=(const greedy_edge &i, const greedy_edge &j) { return (i.d != j.d); }\n\nvoid QtSLiMHaplotypeManager::greedySolve(int64_t *distances, size_t haplosome_count, std::vector<int> &solution)\n{\n    // The first thing we need to do is sort all possible edges in ascending order by length;\n\t// we don't need to differentiate a->b versus b->a since our distances are symmetric\n\tstd::vector<greedy_edge> edge_buf;\n\tsize_t edge_count = (haplosome_count * (haplosome_count - 1)) / 2;\n\t\n\tedge_buf.reserve(edge_count);\t// one of the two factors is even so /2 is safe\n\t\n\tfor (size_t i = 0; i < haplosome_count - 1; ++i)\n\t{\n\t\tfor (size_t k = i + 1; k < haplosome_count; ++k)\n\t\t\tedge_buf.emplace_back(greedy_edge{static_cast<int>(i), static_cast<int>(k), *(distances + i + k * haplosome_count)});\n\t}\n    \n\tif (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\treturn;\n\t\n\tif (progressPanel_)\n\t{\n        // We have a progress panel, so we do an incremental sort\n        BareBoneIIQS<greedy_edge> sorter(edge_buf.data(), edge_count);\n        \n        for (size_t i = 0; i < haplosome_count - 1; ++i)\n        {\n            for (size_t k = i + 1; k < haplosome_count; ++k)\n                sorter.next();\n            \n            if (progressPanel_->haplotypeProgressIsCancelled())\n                return;\n            \n            progressPanel_->setHaplotypeProgress(i, 1);\n        }\n\t}\n\telse\n\t{\n\t\t// If we're not running with a progress panel, we have no progress indicator so we can just use std::sort()\n\t\tstd::sort(edge_buf.begin(), edge_buf.end());\n\t}\n\t\n\tif (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\treturn;\n\t\n\t// Now we take take the first legal edge from the top of edge_buf and add it to our path. \"Legal\" means it\n\t// doesn't increase the degree of either participating node above 2, and doesn't create a cycle.  We check\n\t// the first condition by keeping a vector of the degrees of all nodes, so that's easy.  We check the second\n\t// condition by keeping a vector of \"group\" tags for each participating node; an edge that joins two nodes\n\t// in the same group creates a cycle and is thus illegal (maybe there's a better way to detect cycles but I\n\t// haven't thought of it yet :->).\n\tstd::vector<greedy_edge> path_components;\n\tuint8_t *node_degrees = static_cast<uint8_t *>(calloc(sizeof(uint8_t), haplosome_count));\n\tint *node_groups = static_cast<int *>(calloc(sizeof(int), haplosome_count));\n\tint next_node_group = 1;\n\t\n\tpath_components.reserve(haplosome_count);\n\t\n\tfor (size_t edge_index = 0; edge_index < edge_count; ++edge_index)\n\t{\n\t\tgreedy_edge &candidate_edge = edge_buf[edge_index];\n\t\t\n\t\t// Get the participating nodes and check that they still have a free end\n\t\tint i = candidate_edge.i;\n\t\t\n\t\tif (node_degrees[i] == 2)\n\t\t\tcontinue;\n\t\t\n\t\tint k = candidate_edge.k;\n\t\t\n\t\tif (node_degrees[k] == 2)\n\t\t\tcontinue;\n\t\t\n\t\t// Check whether they are in the same group (and not 0), in which case this edge would create a cycle\n\t\tint group_i = node_groups[i];\n\t\tint group_k = node_groups[k];\n\t\t\n\t\tif ((group_i != 0) && (group_i == group_k))\n\t\t\tcontinue;\n\t\t\n\t\t// OK, the edge is legal.  Add it to our path, and maintain the group tags\n\t\tpath_components.emplace_back(candidate_edge);\n\t\tnode_degrees[i]++;\n\t\tnode_degrees[k]++;\n\t\t\n\t\tif ((group_i == 0) && (group_k == 0))\n\t\t{\n\t\t\t// making a new group\n\t\t\tnode_groups[i] = next_node_group;\n\t\t\tnode_groups[k] = next_node_group;\n\t\t\tnext_node_group++;\n\t\t}\n\t\telse if (group_i == 0)\n\t\t{\n\t\t\t// adding node i to an existing group\n\t\t\tnode_groups[i] = group_k;\n\t\t}\n\t\telse if (group_k == 0)\n\t\t{\n\t\t\t// adding node k to an existing group\n\t\t\tnode_groups[k] = group_i;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// joining two groups; one gets assimilated\n\t\t\t// the assimilation could probably be done more efficiently but this overhead won't matter\n\t\t\tfor (size_t node_index = 0; node_index < haplosome_count; ++node_index)\n\t\t\t\tif (node_groups[node_index] == group_k)\n\t\t\t\t\tnode_groups[node_index] = group_i;\n\t\t}\n\t\t\n\t\tif (path_components.size() == haplosome_count - 1)\t\t// no return edge\n\t\t\tbreak;\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            goto cancelExit;\n\t}\n\t\n\t// Check our work\n\t{\n\t\tint degree1_count = 0, degree2_count = 0, universal_group = node_groups[0];\n\t\t\n\t\tfor (size_t node_index = 0; node_index < haplosome_count; ++node_index)\n\t\t{\n\t\t\tif (node_degrees[node_index] == 1) ++degree1_count;\n\t\t\telse if (node_degrees[node_index] == 2) ++degree2_count;\n\t\t\telse qDebug() << \"node of degree other than 1 or 2 seen (degree\" << node_degrees[node_index] << \")\";\n\t\t\t\n\t\t\tif (node_groups[node_index] != universal_group)\n\t\t\t\tqDebug() << \"node of non-matching group seen (group\" << node_groups[node_index] << \")\";\n\t\t}\n        \n        // suppress \"variable set but not used\" warnings, since we may want these bookkeeping variables at some point...\n        (void)degree1_count;\n        (void)degree2_count;\n\t}\n\t\n\tif (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n\t\tgoto cancelExit;\n\t\n\t// Finally, we have a jumble of edges that are in no order, and we need to make a coherent path from them.\n\t// We start at the first degree-1 node we find, which is one of the two ends; doesn't matter which.\n\t{\n\t\tsize_t remaining_edge_count = haplosome_count - 1;\n\t\tsize_t last_index;\n\t\t\n\t\tfor (last_index = 0; last_index < haplosome_count; ++last_index)\n\t\t\tif (node_degrees[last_index] == 1)\n\t\t\t\tbreak;\n\t\t\n\t\tsolution.emplace_back(static_cast<int>(last_index));\n\t\t\n\t\tdo\n\t\t{\n\t\t\t// look for an edge involving last_index that we haven't used yet (there should be only one)\n\t\t\tsize_t next_edge_index;\n\t\t\tint next_index = INT_MAX;\t// get rid of the unitialized var warning, and cause a crash if we have a bug\n\t\t\t\n\t\t\tfor (next_edge_index = 0; next_edge_index < remaining_edge_count; ++next_edge_index)\n\t\t\t{\n\t\t\t\tgreedy_edge &candidate_edge = path_components[next_edge_index];\n\t\t\t\t\n\t\t\t\tif (candidate_edge.i == static_cast<int>(last_index))\n\t\t\t\t{\n\t\t\t\t\tnext_index = candidate_edge.k;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (candidate_edge.k == static_cast<int>(last_index))\n\t\t\t\t{\n\t\t\t\t\tnext_index = candidate_edge.i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n            if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n                break;\n\t\t\t\n\t\t\t// found it; assimilate it into the path and remove it from path_components\n\t\t\tsolution.emplace_back(next_index);\n\t\t\tlast_index = static_cast<size_t>(next_index);\n\t\t\t\n\t\t\tpath_components[next_edge_index] = path_components[--remaining_edge_count];\n\t\t}\n\t\twhile (remaining_edge_count > 0);\n\t}\n\t\ncancelExit:\n\tfree(node_degrees);\n\tfree(node_groups);\n}\n\n// check that a given path visits every city exactly once\nbool QtSLiMHaplotypeManager::checkPath(std::vector<int> &path, size_t haplosome_count)\n{\n    uint8_t *visits = static_cast<uint8_t *>(calloc(sizeof(uint8_t), haplosome_count));\n\t\n\tif (path.size() != haplosome_count)\n\t{\n\t\tqDebug() << \"checkPath:size: path is wrong length\";\n\t\tfree(visits);\n\t\treturn false;\n\t}\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t{\n\t\tint city_index = path[i];\n\t\t\n\t\tvisits[city_index]++;\n\t}\n\t\n\tfor (size_t i = 0; i < haplosome_count; ++i)\n\t\tif (visits[i] != 1)\n\t\t{\n\t\t\tqDebug() << \"checkPath:size: city visited wrong count (\" << visits[i] << \")\";\n\t\t\tfree(visits);\n\t\t\treturn false;\n\t\t}\n\t\n\tfree(visits);\n\treturn true;\n}\n\n// calculate the length of a given path\nint64_t QtSLiMHaplotypeManager::lengthOfPath(std::vector<int> &path, int64_t *distances, size_t haplosome_count)\n{\n\tint64_t length = 0;\n\tint current_city = path[0];\n\t\n\tfor (size_t city_index = 1; city_index < haplosome_count; city_index++)\n\t{\n\t\tint next_city = path[city_index];\n\t\t\n\t\tlength += *(distances + static_cast<size_t>(current_city) * haplosome_count + next_city);\n\t\tcurrent_city = next_city;\n\t}\n\t\n\treturn length;\n}\n\n// Do \"2-opt\" optimization of a given path, which involves inverting ranges of the path that lead to a better solution.\n// This is quite time-consuming and improves the result only marginally, so we do not want it to be the default, but it\n// might be useful to provide as an option.  This method always takes the first optimization it sees that moves in a\n// positive direction; I tried taking the best optimization available at each step, instead, and it ran half as fast\n// and achieved results that were no better on average, so I didn't even keep that code.\nvoid QtSLiMHaplotypeManager::do2optOptimizationOfSolution(std::vector<int> &path, int64_t *distances, size_t haplosome_count)\n{\n    // Figure out the length of the current path\n\tint64_t original_distance = lengthOfPath(path, distances, haplosome_count);\n\tint64_t best_distance = original_distance;\n\t\n\t//NSLog(@\"2-opt initial length: %lld\", (long long int)best_distance);\n\t\n\t// Iterate until we can find no 2-opt improvement; this algorithm courtesy of https://en.wikipedia.org/wiki/2-opt\n\tsize_t farthest_i = 0;\t// for our progress bar\n\t\nstartAgain:\n\tfor (size_t i = 0; i < haplosome_count - 1; i++)\n\t{\n\t\tfor (size_t k = i + 1; k < haplosome_count; ++k)\n\t\t{\n\t\t\t// First, try the proposed path without actually constructing it; we just need to subtract the lengths of the\n\t\t\t// edges being removed and add the lengths of the edges being added, rather than constructing the whole new\n\t\t\t// path and measuring its length.  If we have a path 1:9 and are inverting i=3 to k=5, it looks like:\n\t\t\t//\n\t\t\t//\t\t1\t2\t3\t4\t5\t6\t7\t8\t9\n\t\t\t//\t\t\t   (i\t\tk)\n\t\t\t//\n\t\t\t//\t\t1\t2  (5\t4\t3)\t6\t7\t8\t9\n\t\t\t//\n\t\t\t// So the 2-3 edge and the 5-6 edge were subtracted, and the 2-5 edge and the 3-6 edge were added.  Note that\n\t\t\t// we can only get away with juggling the distances this way because our problem is symmetric; the length of\n\t\t\t// 3-4-5 is guaranteed the same as the length of the reversed segment 5-4-3.  If the reversed segment is at\n\t\t\t// one or the other end of the path, we only need to patch up one edge; we don't return to the start city.\n\t\t\t// Note also that i and k are not haplosome indexes; they are indexes into our current path, which provides us\n\t\t\t// with the relevant haplosomes indexes.\n\t\t\tint64_t new_distance = best_distance;\n\t\t\tsize_t index_i = static_cast<size_t>(path[i]);\n\t\t\tsize_t index_k = static_cast<size_t>(path[k]);\n\t\t\t\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\tsize_t index_i_minus_1 = static_cast<size_t>(path[i - 1]);\n\t\t\t\t\n\t\t\t\tnew_distance -= *(distances + index_i_minus_1 + index_i * haplosome_count);\t// remove edge (i-1)-(i)\n\t\t\t\tnew_distance += *(distances + index_i_minus_1 + index_k * haplosome_count);\t// add edge (i-1)-(k)\n\t\t\t}\n\t\t\tif (k < haplosome_count - 1)\n\t\t\t{\n\t\t\t\tsize_t index_k_plus_1 = static_cast<size_t>(path[k + 1]);\n\t\t\t\t\n\t\t\t\tnew_distance -= *(distances + index_k + index_k_plus_1 * haplosome_count);\t\t// remove edge (k)-(k+1)\n\t\t\t\tnew_distance += *(distances + index_i + index_k_plus_1 * haplosome_count);\t\t// add edge (i)-(k+1)\n\t\t\t}\n\t\t\t\n\t\t\tif (new_distance < best_distance)\n\t\t\t{\n\t\t\t\t// OK, the new path is an improvement, so let's take it.  We construct it by inverting the sequence\n\t\t\t\t// from i to k in our path vector, by swapping elements until we reach the center.\n\t\t\t\tfor (size_t inversion_length = 0; ; inversion_length++)\n\t\t\t\t{\n\t\t\t\t\tsize_t swap1 = i + inversion_length;\n\t\t\t\t\tsize_t swap2 = k - inversion_length;\n\t\t\t\t\t\n\t\t\t\t\tif (swap1 >= swap2)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tstd::swap(path[swap1], path[swap2]);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbest_distance = new_distance;\n\t\t\t\t\n\t\t\t\t//NSLog(@\"Improved path length: %lld (inverted from %d to %d)\", (long long int)best_distance, i, k);\n\t\t\t\t//NSLog(@\"   checkback: new path length is %lld\", (long long int)[self lengthOfPath:path withDistances:distances size:haplosome_count]);\n\t\t\t\tgoto startAgain;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// We update our progress bar according to the furthest we have ever gotten in the outer loop; we keep having to start\n\t\t// over again, and there's no way to know how many times we're going to do that, so this seems like the best estimator.\n\t\tfarthest_i = std::max(farthest_i, i + 1);\n\t\t\n        if (progressPanel_)\n            progressPanel_->setHaplotypeProgress(farthest_i, 2);\n\t\t\n        if (progressPanel_ && progressPanel_->haplotypeProgressIsCancelled())\n            break;\n\t}\n\t\n\t//NSLog(@\"Distance changed from %lld to %lld (%.3f%% improvement)\", (long long int)original_distance, (long long int)best_distance, ((original_distance - best_distance) / (double)original_distance) * 100.0);\n}\n\n\n//\n// QtSLiMHaplotypeView\n//\n// This class is private to QtSLiMHaplotypeManager, but is declared here so MOC gets it automatically\n// It displays a haplotype view for one chromosome; QtSLiMHaplotypeTopView may contain one or more\n//\n\n#pragma mark QtSLiMHaplotypeView\n\nQtSLiMHaplotypeView::QtSLiMHaplotypeView(QWidget *p_parent, Qt::WindowFlags f)\n#ifndef SLIM_NO_OPENGL\n    : QOpenGLWidget(p_parent, f)\n#else\n    : QWidget(p_parent, f)\n#endif\n{\n    // We support both OpenGL and non-OpenGL display, because some platforms seem\n    // to have problems with OpenGL (https://github.com/MesserLab/SLiM/issues/462)\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::useOpenGLPrefChanged, this, [this]() { update(); });\n}\n\nQtSLiMHaplotypeView::~QtSLiMHaplotypeView(void)\n{\n    delegate_ = nullptr;\n}\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMHaplotypeView::initializeGL()\n{\n    initializeOpenGLFunctions();\n    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);\n}\n\nvoid QtSLiMHaplotypeView::resizeGL(int w, int h)\n{\n    glViewport(0, 0, w, h);\n    \n\t// Update the projection\n\tglMatrixMode(GL_PROJECTION);\n    glLoadIdentity();\n\tglMatrixMode(GL_MODELVIEW);\n}\n#endif\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMHaplotypeView::paintGL()\n#else\nvoid QtSLiMHaplotypeView::paintEvent(QPaintEvent * /* p_paint_event */)\n#endif\n{\n    QPainter painter(this);\n    QRect interior = rect();\n    \n    // frame with gray\n#ifndef SLIM_NO_OPENGL\n    if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n    {\n        painter.beginNativePainting();\n        glColor3f(0.5f, 0.5f, 0.5f);\n        glRecti(interior.x(), interior.y(), interior.x() + interior.width(), interior.y() + interior.height());\n    }\n    else\n#endif\n    {\n        painter.fillRect(interior, QtSLiMColorWithWhite(0.5, 1.0));\n    }\n        \n    interior.adjust(1, 1, -1, -1);\n    \n    if (delegate_)\n    {\n#ifndef SLIM_NO_OPENGL\n        if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n            delegate_->glDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true);\n        else\n#endif\n            delegate_->qtDrawHaplotypes(interior, displayBlackAndWhite_, showSubpopulationStrips_, true, painter);\n    }\n    else\n    {\n#ifndef SLIM_NO_OPENGL\n        if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n        {\n            painter.beginNativePainting();\n            glColor3f(0.95f, 0.95f, 0.95f);\n            glRecti(interior.x(), interior.y(), interior.x() + interior.width(), interior.y() + interior.height());\n        }\n        else\n#endif\n        {\n            painter.fillRect(interior, QtSLiMColorWithWhite(0.9, 1.0));\n        }\n    }\n\n#ifndef SLIM_NO_OPENGL\n    if (QtSLiMPreferencesNotifier::instance().useOpenGLPref())\n        painter.endNativePainting();\n#endif\n}\n\nvoid QtSLiMHaplotypeView::setDisplayBlackAndWhite(bool flag)\n{\n    displayBlackAndWhite_ = flag;\n    update();\n}\n\nvoid QtSLiMHaplotypeView::setDisplaySubpopulationStrips(bool flag)\n{\n    showSubpopulationStrips_ = flag;\n    update();\n}\n\n\n//\n// QtSLiMHaplotypeTopView\n//\n// This class is private to QtSLiMHaplotypeManager, but is declared here so MOC gets it automatically\n// This contains a set of QtSLiMHaplotypeViews to display a set of haplotype plots for chromosomes\n//\n\n#pragma mark QtSLiMHaplotypeTopView\n\nQtSLiMHaplotypeTopView::QtSLiMHaplotypeTopView(QWidget *p_parent, Qt::WindowFlags f)\n    : QWidget(p_parent, f)\n{\n}\n\nQtSLiMHaplotypeTopView::~QtSLiMHaplotypeTopView(void)\n{\n}\n\nvoid QtSLiMHaplotypeTopView::paintEvent(QPaintEvent * /* p_paint_event */)\n{\n    QPainter painter(this);\n    QRect interior = rect();\n    \n    painter.fillRect(interior, Qt::white);\n    \n    if (showChromosomeSymbols_)\n    {\n        // We draw the text labels for our child views, since we are a regular QWidget and they might be QOpenGLWidgets\n        // This is the main motivation for the existence of this class at all; taking a snapshot of a mixed-drawing\n        // widget with render() does not work well for some reason, so we need the QPainter drawing done in the parent\n        static QFont *tickFont = nullptr;\n        \n        if (!tickFont)\n        {\n            tickFont = new QFont();\n#ifdef __linux__\n            tickFont->setPointSize(8);\n#else\n            tickFont->setPointSize(11);\n#endif\n        }\n        painter.setFont(*tickFont);\n        painter.setPen(Qt::black);\n        \n        QFontMetricsF fontMetrics(*tickFont);\n        \n        const QObjectList &child_objects = children();\n        \n        for (QObject *child_object : child_objects)\n        {\n            QtSLiMHaplotypeView *child_widget = qobject_cast<QtSLiMHaplotypeView *>(child_object);\n            \n            if (child_widget && child_widget->isVisible())\n            {\n                QString chromosomeSymbol = QString::fromStdString(child_widget->chromosomeSymbol_);\n                \n                if (chromosomeSymbol.length())\n                {\n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n                    double symbolLabelWidth = fontMetrics.width(chromosomeSymbol);               // deprecated in 5.11\n#else\n                    double symbolLabelWidth = fontMetrics.horizontalAdvance(chromosomeSymbol);   // added in Qt 5.11\n#endif\n                    \n                    QRect viewFrame = child_widget->geometry();\n                    QRect labelFrame = QRect(viewFrame.left(), 0, viewFrame.width(), viewFrame.top());\n                    \n                    if (symbolLabelWidth <= viewFrame.width())\n                        painter.drawText(labelFrame,\n                                         Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignVCenter | Qt::AlignHCenter,\n                                         chromosomeSymbol);\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMHaplotypeTopView::actionButtonRunMenu(QtSLiMPushButton *p_actionButton)\n{\n    QMenu contextMenu(\"graph_menu\", this);\n    \n    QAction *bwColorToggle = contextMenu.addAction(displayBlackAndWhite_ ? \"Display Colors\" : \"Display Black && White\");\n    QAction *subpopStripsToggle = contextMenu.addAction(showSubpopulationStrips_ ? \"Hide Subpopulation Strips\" : \"Show Subpopulation Strips\");\n    \n    contextMenu.addSeparator();\n    \n    QAction *copyPlot = contextMenu.addAction(\"Copy Plot\");\n    QAction *exportPlot = contextMenu.addAction(\"Export Plot...\");\n    \n    // Run the context menu synchronously\n    QPoint menuPos = QCursor::pos();\n    QAction *action = contextMenu.exec(menuPos);\n    \n    // Act upon the chosen action; we just do it right here instead of dealing with slots\n    if (action)\n    {\n        if (action == bwColorToggle)\n        {\n            displayBlackAndWhite_ = !displayBlackAndWhite_;\n            \n            // We tell all of our child QtSLiMHaplotypeViews about this configuration change\n            const QObjectList &child_objects = children();\n            \n            for (QObject *child_object : child_objects)\n            {\n                QtSLiMHaplotypeView *child_widget = qobject_cast<QtSLiMHaplotypeView *>(child_object);\n                \n                if (child_widget && child_widget->isVisible())\n                    child_widget->setDisplayBlackAndWhite(displayBlackAndWhite_);\n            }\n        }\n        if (action == subpopStripsToggle)\n        {\n            showSubpopulationStrips_ = !showSubpopulationStrips_;\n            \n            // We tell all of our child QtSLiMHaplotypeViews about this configuration change\n            const QObjectList &child_objects = children();\n            \n            for (QObject *child_object : child_objects)\n            {\n                QtSLiMHaplotypeView *child_widget = qobject_cast<QtSLiMHaplotypeView *>(child_object);\n                \n                if (child_widget && child_widget->isVisible())\n                    child_widget->setDisplaySubpopulationStrips(showSubpopulationStrips_);\n            }\n        }\n        else if (action == copyPlot)\n        {\n            QPixmap pixmap(size());\n            render(&pixmap);\n            QImage snap = pixmap.toImage();\n            QClipboard *clipboard = QGuiApplication::clipboard();\n            clipboard->setImage(snap);\n        }\n        else if (action == exportPlot)\n        {\n            // FIXME maybe this should use QtSLiMDefaultSaveDirectory?  see QtSLiMWindow::saveAs()\n            QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);\n            QFileInfo fileInfo(QDir(desktopPath), \"haplotypes.png\");\n            QString path = fileInfo.absoluteFilePath();\n            QString fileName = QFileDialog::getSaveFileName(this, \"Export Graph\", path);\n            \n            if (!fileName.isEmpty())\n            {\n                QPixmap pixmap(size());\n                render(&pixmap);\n                QImage snap = pixmap.toImage();\n                \n                snap.save(fileName, \"PNG\", 100);    // JPG does not come out well; colors washed out\n            }\n        }\n    }\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    p_actionButton->qtslimSetHighlight(false);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeManager.h",
    "content": "//\n//  QtSLiMHaplotypeManager.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/3/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMHAPLOTYPEMANAGER_H\n#define QTSLIMHAPLOTYPEMANAGER_H\n\n// Silence deprecated OpenGL warnings on macOS\n#define GL_SILENCE_DEPRECATION\n\n#include <QObject>\n#include <QRect>\n#include <QString>\n#include <QWidget>\n\n#ifndef SLIM_NO_OPENGL\n#include <QOpenGLWidget>\n#include <QOpenGLFunctions>\n#endif\n\n#include <string>\n\n#include \"slim_globals.h\"\n#include \"mutation.h\"\n\n#include \"QtSLiMChromosomeWidget.h\"\n\n\nclass QtSLiMChromosomeWidgetController;\nclass Species;\nclass Haplosome;\nclass QtSLiMHaplotypeProgress;\nclass QtSLiMPushButton;\n\n\nclass QtSLiMHaplotypeManager : public QObject\n{\n    Q_OBJECT\n    \npublic:\n    enum ClusteringMethod {\n        ClusterNearestNeighbor,\n        ClusterGreedy\n    };\n    enum ClusteringOptimization {\n        ClusterNoOptimization,\n        ClusterOptimizeWith2opt\n    };\n    \n    // This class method runs a plot options dialog, and then produces a haplotype plot with a progress panel as it is being constructed\n    static void CreateHaplotypePlot(QtSLiMChromosomeWidgetController *controller, Chromosome *focalChromosome);\n    \n    // Constructing a QtSLiMHaplotypeManager directly is also allowing, if you don't want options or progress\n    QtSLiMHaplotypeManager(QObject *p_parent, ClusteringMethod clusteringMethod, ClusteringOptimization optimizationMethod,\n                           QtSLiMChromosomeWidgetController *controller, Species *displaySpecies, Chromosome *chromosome,\n                           QtSLiMRange displayedRange, size_t sampleSize, bool showProgress, int progressChromIndex,\n                           int progressChromTotal);\n    ~QtSLiMHaplotypeManager(void);\n    \n#ifndef SLIM_NO_OPENGL\n    void glDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground);\n#endif\n    void qtDrawHaplotypes(QRect interior, bool displayBW, bool showSubpopStrips, bool eraseBackground, QPainter &painter);\n    \n    // Public properties\n    QString titleString;\n    QString titleStringWithoutChromosome;\n    int subpopCount = 0;\n    bool valid_ = true;     // set to false if the user cancels the progress panel\n\nprivate:\n    QtSLiMChromosomeWidgetController *controller_ = nullptr;\n    std::string focalSpeciesName_;                          // we keep the name of our focal species, since a pointer would be unsafe\n    \n    Species *focalDisplaySpecies(void);\n    \n    QtSLiMHaplotypeProgress *progressPanel_ = nullptr;\n    \n    ClusteringMethod clusterMethod;\n\tClusteringOptimization clusterOptimization;\n    \n    // Display list data structures.  We map every Mutation in the registry to a struct we define that keeps the necessary information\n    // to display that mutation: position and color.  We use MutationIndex to index into a vector of those structs, using the same\n    // index values used by the registry for simplicity.  Each haplosome is then turned into a vector of MutationIndex that lets\n    // us plot the mutations for that haplosome.\n    struct HaploMutation {\n        slim_position_t position_;\n        float red_, green_, blue_;\n        bool neutral_;\t\t\t\t\t// selection_coeff_ == 0.0, used to display neutral mutations under selected mutations\n        bool display_;\t\t\t\t\t// from the mutation type's mutation_type_displayed_ flag\n    };\n    \n    // Haplosomes: note that this vector points back into SLiM's data structures, so using it is not safe in general.  It is used\n\t// by this class only while building the display list below; after that stage, we clear this vector.  The work to build the\n\t// display list gets done on a background thread, but the SLiMgui window is blocked by the progress panel during that time.\n\tstd::vector<Haplosome *> haplosomes;\n\t\n\t// Display list\n\tHaploMutation *mutationInfo = nullptr;                  // a buffer of SLiMHaploMutation providing display information per mutation\n\tslim_position_t *mutationPositions = nullptr;           // the same info as in mutationInfo, but in a single buffer for access efficiency\n\tslim_position_t mutationLastPosition = 0;               // from the chromosome\n\tsize_t mutationIndexCount = 0;                          // the number of MutationIndex values in use\n\tstd::vector<std::vector<MutationIndex>> *displayList = nullptr;\t// a vector of haplosome information, where each haplosome is a vector of MutationIndex\n\t\n\t// Subpopulation information\n\tstd::vector<slim_objectid_t> haplosomeSubpopIDs;\t\t\t// the subpop ID for each haplosome, corresponding to the display list order\n\tslim_objectid_t maxSubpopID = 0;\n\tslim_objectid_t minSubpopID = 0;\n\t\n\t// Chromosome subrange information\n\tbool usingSubrange = false;\n\tslim_position_t subrangeFirstBase = 0, subrangeLastBase = 0;\n\t\n\t// Mutation type display information\n\tbool displayingMuttypeSubset = false;\n    \n    void finishClusteringAnalysis(void);\n    void configureMutationInfoBuffer(Chromosome *chromosome);\n    void sortHaplosomes(void);\n    void configureDisplayBuffers(void);\n    void allocateGLBuffers(void);\n    void tallyBincounts(int64_t *bincounts, std::vector<MutationIndex> &haplosomeList);\n    int64_t distanceForBincounts(int64_t *bincounts1, int64_t *bincounts2);\n    \n    // OpenGL drawing; this is the primary drawing code\n#ifndef SLIM_NO_OPENGL\n    void glDrawSubpopStripsInRect(QRect interior);\n    void glDrawDisplayListInRect(QRect interior, bool displayBW);\n#endif\n    \n    // Qt-based drawing, provided as a backup if OpenGL has problems on a given platform\n    void qtDrawSubpopStripsInRect(QRect interior, QPainter &painter);\n    void qtDrawDisplayListInRect(QRect interior, bool displayBW, QPainter &painter);\n    \n    int64_t *buildDistanceArray(void);\n    int64_t *buildDistanceArrayForSubrange(void);\n    int64_t *buildDistanceArrayForSubtypes(void);\n    int64_t *buildDistanceArrayForSubrangeAndSubtypes(void);\n    int indexOfMostIsolatedHaplosomeWithDistances(int64_t *distances, size_t haplosome_count);\n    void nearestNeighborSolve(int64_t *distances, size_t haplosome_count, std::vector<int> &solution);\n    void greedySolve(int64_t *distances, size_t haplosome_count, std::vector<int> &solution);\n    bool checkPath(std::vector<int> &path, size_t haplosome_count);\n    int64_t lengthOfPath(std::vector<int> &path, int64_t *distances, size_t haplosome_count);\n    void do2optOptimizationOfSolution(std::vector<int> &path, int64_t *distances, size_t haplosome_count);\n};\n\n\n//\n// QtSLiMHaplotypeView\n//\n// This class is private to QtSLiMHaplotypeManager, but is declared here so MOC gets it automatically\n// It displays a haplotype view for one chromosome; QtSLiMHaplotypeTopView may contain one or more\n//\n\n#ifndef SLIM_NO_OPENGL\nclass QtSLiMHaplotypeView : public QOpenGLWidget, protected QOpenGLFunctions\n#else\nclass QtSLiMHaplotypeView : public QWidget\n#endif\n{\n    Q_OBJECT\n    \npublic:\n    std::string chromosomeSymbol_;\n    \n    explicit QtSLiMHaplotypeView(QWidget *p_parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());\n    virtual ~QtSLiMHaplotypeView(void) override;\n    \n    void setDelegate(QtSLiMHaplotypeManager *delegate) { delegate_ = delegate; delegate_->setParent(this); update(); }\n    \n    // state changes from the action button; called by QtSLiMHaplotypeTopView\n    void setDisplayBlackAndWhite(bool flag);\n    void setDisplaySubpopulationStrips(bool flag);\n    \nprivate:\n    QtSLiMHaplotypeManager *delegate_ = nullptr;\n    \n    bool displayBlackAndWhite_ = false;\n    bool showSubpopulationStrips_ = false;\n    \n#ifndef SLIM_NO_OPENGL\n    virtual void initializeGL() override;\n    virtual void resizeGL(int w, int h) override;\n    virtual void paintGL() override;\n#else\n    virtual void paintEvent(QPaintEvent *event) override;\n#endif\n};\n\n\n//\n// QtSLiMHaplotypeTopView\n//\n// This class is private to QtSLiMHaplotypeManager, but is declared here so MOC gets it automatically\n// This contains a set of QtSLiMHaplotypeViews to display a set of haplotype plots for chromosomes\n//\n\nclass QtSLiMHaplotypeTopView : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    explicit QtSLiMHaplotypeTopView(QWidget *p_parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());\n    virtual ~QtSLiMHaplotypeTopView(void) override;\n    \npublic slots:\n    void actionButtonRunMenu(QtSLiMPushButton *actionButton);\n    \n    void setShowChromosomeSymbols(bool flag) { showChromosomeSymbols_ = flag; }\n    \nprivate:\n    bool displayBlackAndWhite_ = false;\n    bool showSubpopulationStrips_ = false;\n    \n    bool showChromosomeSymbols_ = false;\n    \n    virtual void paintEvent(QPaintEvent *event) override;\n};\n\n\n#endif // QTSLIMHAPLOTYPEMANAGER_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeManager_GL.cpp",
    "content": "//\n//  QtSLiMHaplotypeManager_GL.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/26/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef SLIM_NO_OPENGL\n\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMOpenGL.h\"\n\n#include <QDebug>\n\n#include <vector>\n#include <algorithm>\n#include <utility>\n\n\nvoid QtSLiMHaplotypeManager::glDrawSubpopStripsInRect(QRect interior)\n{\n    // Set up to draw rects\n    SLIM_GL_PREPARE();\n\t\n\t// Loop through the haplosomes and draw them; we do this in two passes, neutral mutations underneath selected mutations\n\tsize_t haplosome_index = 0, haplosome_count = haplosomeSubpopIDs.size();\n\tfloat height_divisor = haplosome_count;\n\tfloat left = static_cast<float>(interior.x());\n\tfloat right = static_cast<float>(interior.x() + interior.width());\n\t\n\tfor (slim_objectid_t haplosome_subpop_id : haplosomeSubpopIDs)\n\t{\n\t\tfloat top = interior.y() + (haplosome_index / height_divisor) * interior.height();\n\t\tfloat bottom = interior.y() + ((haplosome_index + 1) / height_divisor) * interior.height();\n\t\t\n\t\tif (bottom - top > 1.0f)\n\t\t{\n\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\ttop = floorf(top);\n\t\t\tbottom = ceilf(bottom);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\ttop = floorf(top);\n\t\t\tbottom = top + 1;\n\t\t}\n        \n        SLIM_GL_PUSHRECT();\n\t\t\n\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha;\n\t\tdouble hue = (haplosome_subpop_id - minSubpopID) / static_cast<double>(maxSubpopID - minSubpopID + 1);\n        QColor hsbColor = QtSLiMColorWithHSV(hue, 1.0, 1.0, 1.0);\n\t\tQColor rgbColor = hsbColor.toRgb();\n        \n\t\tcolorRed = static_cast<float>(rgbColor.redF());\n\t\tcolorGreen = static_cast<float>(rgbColor.greenF());\n\t\tcolorBlue = static_cast<float>(rgbColor.blueF());\n        colorAlpha = 1.0;\n        \n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS();\n\t\t\n\t\thaplosome_index++;\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\nvoid QtSLiMHaplotypeManager::glDrawDisplayListInRect(QRect interior, bool displayBW)\n{\n\t// Set up to draw rects\n    SLIM_GL_PREPARE();\n    \n    // decide whether to plot in ascending order or descending order; we do this based on\n    // which end has higher mutational density, to try to maximize visual continuity\n\tsize_t haplosome_count = displayList->size();\n\tbool ascending = true;\n\t\n\tif (haplosome_count > 1)\n\t{\n\t\tstd::vector<MutationIndex> &first_haplosome_list = (*displayList)[0];\n\t\tstd::vector<MutationIndex> &last_haplosome_list = (*displayList)[haplosome_count - 1];\n        \n        ascending = (first_haplosome_list.size() < last_haplosome_list.size());\n\t}\n\t\n\t// Loop through the haplosomes and draw them; we do this in two passes, neutral mutations underneath selected mutations\n\tfor (int pass_count = 0; pass_count <= 1; ++pass_count)\n\t{\n\t\tbool plotting_neutral = (pass_count == 0);\n\t\tfloat height_divisor = haplosome_count;\n\t\tfloat width_subtractor = (usingSubrange ? subrangeFirstBase : 0);\n\t\tfloat width_divisor = (usingSubrange ? (subrangeLastBase - subrangeFirstBase + 1) : (mutationLastPosition + 1));\n\t\t\n\t\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; ++haplosome_index)\n\t\t{\n\t\t\tstd::vector<MutationIndex> &haplosome_list = (ascending ? (*displayList)[haplosome_index] : (*displayList)[(haplosome_count - 1) - haplosome_index]);\n\t\t\tfloat top = interior.y() + (haplosome_index / height_divisor) * interior.height();\n\t\t\tfloat bottom = interior.y() + ((haplosome_index + 1) / height_divisor) * interior.height();\n\t\t\t\n\t\t\tif (bottom - top > 1.0f)\n\t\t\t{\n\t\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\t\ttop = floorf(top);\n\t\t\t\tbottom = ceilf(bottom);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\t\ttop = floorf(top);\n\t\t\t\tbottom = top + 1;\n\t\t\t}\n\t\t\t\n\t\t\tfor (MutationIndex mut_index : haplosome_list)\n\t\t\t{\n\t\t\t\tHaploMutation &mut_info = mutationInfo[mut_index];\n\t\t\t\t\n\t\t\t\tif (mut_info.neutral_ == plotting_neutral)\n\t\t\t\t{\n\t\t\t\t\tslim_position_t mut_position = mut_info.position_;\n\t\t\t\t\tfloat left = interior.x() + ((mut_position - width_subtractor) / width_divisor) * interior.width();\n\t\t\t\t\tfloat right = interior.x() + ((mut_position - width_subtractor + 1) / width_divisor) * interior.width();\n\t\t\t\t\t\n\t\t\t\t\tif (right - left > 1.0f)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\t\t\t\tleft = floorf(left);\n\t\t\t\t\t\tright = ceilf(right);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\t\t\t\tleft = floorf(left);\n\t\t\t\t\t\tright = left + 1;\n\t\t\t\t\t}\n                    \n                    SLIM_GL_PUSHRECT();\n\t\t\t\t\t\n\t\t\t\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha = 1.0;\n\t\t\t\t\t\n\t\t\t\t\tif (displayBW) {\n\t\t\t\t\t\tcolorRed = 0;\t\t\t\t\tcolorGreen = 0;\t\t\t\t\t\tcolorBlue = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolorRed = mut_info.red_;\t\tcolorGreen = mut_info.green_;\t\tcolorBlue = mut_info.blue_;\n\t\t\t\t\t}\n                    \n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeManager_QT.cpp",
    "content": "//\n//  QtSLiMHaplotypeManager_QT.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/26/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMOpenGL_Emulation.h\"\n\n#include <QDebug>\n\n#include <vector>\n#include <algorithm>\n#include <utility>\n\n\nvoid QtSLiMHaplotypeManager::qtDrawSubpopStripsInRect(QRect interior, QPainter &painter)\n{\n    // Set up to draw rects\n    SLIM_GL_PREPARE();\n\t\n\t// Loop through the haplosomes and draw them; we do this in two passes, neutral mutations underneath selected mutations\n\tsize_t haplosome_index = 0, haplosome_count = haplosomeSubpopIDs.size();\n\tfloat height_divisor = haplosome_count;\n\tfloat left = static_cast<float>(interior.x());\n\tfloat right = static_cast<float>(interior.x() + interior.width());\n\t\n\tfor (slim_objectid_t haplosome_subpop_id : haplosomeSubpopIDs)\n\t{\n\t\tfloat top = interior.y() + (haplosome_index / height_divisor) * interior.height();\n\t\tfloat bottom = interior.y() + ((haplosome_index + 1) / height_divisor) * interior.height();\n\t\t\n\t\tif (bottom - top > 1.0f)\n\t\t{\n\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\ttop = floorf(top);\n\t\t\tbottom = ceilf(bottom);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\ttop = floorf(top);\n\t\t\tbottom = top + 1;\n\t\t}\n        \n        SLIM_GL_PUSHRECT();\n\t\t\n\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha;\n\t\tdouble hue = (haplosome_subpop_id - minSubpopID) / static_cast<double>(maxSubpopID - minSubpopID + 1);\n        QColor hsbColor = QtSLiMColorWithHSV(hue, 1.0, 1.0, 1.0);\n\t\tQColor rgbColor = hsbColor.toRgb();\n        \n\t\tcolorRed = static_cast<float>(rgbColor.redF());\n\t\tcolorGreen = static_cast<float>(rgbColor.greenF());\n\t\tcolorBlue = static_cast<float>(rgbColor.blueF());\n        colorAlpha = 1.0;\n        \n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS_NORECT();\n\t\t\n\t\thaplosome_index++;\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\nvoid QtSLiMHaplotypeManager::qtDrawDisplayListInRect(QRect interior, bool displayBW, QPainter &painter)\n{\n\t// Set up to draw rects\n    SLIM_GL_PREPARE();\n\t\n\t// decide whether to plot in ascending order or descending order; we do this based on\n    // which end has higher mutational density, to try to maximize visual continuity\n\tsize_t haplosome_count = displayList->size();\n\tbool ascending = true;\n\t\n\tif (haplosome_count > 1)\n\t{\n\t\tstd::vector<MutationIndex> &first_haplosome_list = (*displayList)[0];\n\t\tstd::vector<MutationIndex> &last_haplosome_list = (*displayList)[haplosome_count - 1];\n        \n        ascending = (first_haplosome_list.size() < last_haplosome_list.size());\n\t}\n\t\n\t// Loop through the haplosomes and draw them; we do this in two passes, neutral mutations underneath selected mutations\n\tfor (int pass_count = 0; pass_count <= 1; ++pass_count)\n\t{\n\t\tbool plotting_neutral = (pass_count == 0);\n\t\tfloat height_divisor = haplosome_count;\n\t\tfloat width_subtractor = (usingSubrange ? subrangeFirstBase : 0);\n\t\tfloat width_divisor = (usingSubrange ? (subrangeLastBase - subrangeFirstBase + 1) : (mutationLastPosition + 1));\n\t\t\n\t\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; ++haplosome_index)\n\t\t{\n\t\t\tstd::vector<MutationIndex> &haplosome_list = (ascending ? (*displayList)[haplosome_index] : (*displayList)[(haplosome_count - 1) - haplosome_index]);\n\t\t\tfloat top = interior.y() + (haplosome_index / height_divisor) * interior.height();\n\t\t\tfloat bottom = interior.y() + ((haplosome_index + 1) / height_divisor) * interior.height();\n\t\t\t\n\t\t\tif (bottom - top > 1.0f)\n\t\t\t{\n\t\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\t\ttop = floorf(top);\n\t\t\t\tbottom = ceilf(bottom);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\t\ttop = floorf(top);\n\t\t\t\tbottom = top + 1;\n\t\t\t}\n\t\t\t\n\t\t\tfor (MutationIndex mut_index : haplosome_list)\n\t\t\t{\n\t\t\t\tHaploMutation &mut_info = mutationInfo[mut_index];\n\t\t\t\t\n\t\t\t\tif (mut_info.neutral_ == plotting_neutral)\n\t\t\t\t{\n\t\t\t\t\tslim_position_t mut_position = mut_info.position_;\n\t\t\t\t\tfloat left = interior.x() + ((mut_position - width_subtractor) / width_divisor) * interior.width();\n\t\t\t\t\tfloat right = interior.x() + ((mut_position - width_subtractor + 1) / width_divisor) * interior.width();\n\t\t\t\t\t\n\t\t\t\t\tif (right - left > 1.0f)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\t\t\t\t\tleft = floorf(left);\n\t\t\t\t\t\tright = ceilf(right);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the positions span a pixel boundary\n\t\t\t\t\t\tleft = floorf(left);\n\t\t\t\t\t\tright = left + 1;\n\t\t\t\t\t}\n                    \n                    SLIM_GL_PUSHRECT();\n\t\t\t\t\t\n\t\t\t\t\tfloat colorRed, colorGreen, colorBlue, colorAlpha = 1.0;\n\t\t\t\t\t\n\t\t\t\t\tif (displayBW) {\n\t\t\t\t\t\tcolorRed = 0;\t\t\t\t\tcolorGreen = 0;\t\t\t\t\t\tcolorBlue = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolorRed = mut_info.red_;\t\tcolorGreen = mut_info.green_;\t\tcolorBlue = mut_info.blue_;\n\t\t\t\t\t}\n                    \n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS_NORECT();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeOptions.cpp",
    "content": "//\n//  QtSLiMHaplotypeOptions.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/4/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMHaplotypeOptions.h\"\n#include \"ui_QtSLiMHaplotypeOptions.h\"\n\n#include <QApplication>\n\n#include \"QtSLiMAppDelegate.h\"\n\n\nQtSLiMHaplotypeOptions::QtSLiMHaplotypeOptions(QWidget *p_parent) :\n    QDialog(p_parent),\n    ui(new Ui::QtSLiMHaplotypeOptions)\n{\n    ui->setupUi(this);\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // change the app icon to our multi-size app icon for best results\n    ui->appIconButton->setIcon(qtSLiMAppDelegate->applicationIcon());\n    \n    // fix sizing\n    setFixedSize(sizeHint());\n    setSizeGripEnabled(false);\n    \n    // enabled/disable the sample size lineEdit\n    connect(ui->haplosomesSampleRadio, &QAbstractButton::toggled, this, [this]() { ui->sampleSizeLineEdit->setEnabled(ui->haplosomesSampleRadio->isChecked()); });\n}\n\nQtSLiMHaplotypeOptions::~QtSLiMHaplotypeOptions()\n{\n    delete ui;\n}\n\nvoid QtSLiMHaplotypeOptions::done(int r)\n{\n    // do validation; see https://www.qtcentre.org/threads/8048-Validate-Data-in-QDialog\n    bool usingSampleSize = ui->haplosomesSampleRadio->isChecked();\n    \n    if ((QDialog::Accepted == r) && usingSampleSize)  // ok was pressed and the sample size field is being used\n    {\n        QString sampleSizeText = ui->sampleSizeLineEdit->text();\n        size_t sampleSizeInt = sampleSizeText.toULong();\n        QString validatedText = QString(\"%1\").arg(sampleSizeInt);\n        \n        if ((sampleSizeText == validatedText) && (sampleSizeInt > 1))\n        {\n            QDialog::done(r);\n            return;\n        }\n        else\n        {\n            qApp->beep();\n            return;\n        }\n    }\n    else    // cancel, close or exc was pressed\n    {\n        QDialog::done(r);\n        return;\n    }\n}\n\nsize_t QtSLiMHaplotypeOptions::haplosomeSampleSize(void)\n{\n    bool usingSampleSize = ui->haplosomesSampleRadio->isChecked();\n    \n    if (!usingSampleSize)\n        return 0;\n    \n    return ui->sampleSizeLineEdit->text().toULong();\n}\n\nQtSLiMHaplotypeManager::ClusteringMethod QtSLiMHaplotypeOptions::clusteringMethod(void)\n{\n    if (ui->clusterNearestRadio->isChecked())       return QtSLiMHaplotypeManager::ClusterNearestNeighbor;\n    if (ui->clusterGreedyRadio->isChecked())        return QtSLiMHaplotypeManager::ClusterGreedy;\n    if (ui->clusterGreedyOpt2Radio->isChecked())    return QtSLiMHaplotypeManager::ClusterGreedy;\n    return QtSLiMHaplotypeManager::ClusterNearestNeighbor;\n}\n\nQtSLiMHaplotypeManager::ClusteringOptimization QtSLiMHaplotypeOptions::clusteringOptimization(void)\n{\n    if (ui->clusterNearestRadio->isChecked())       return QtSLiMHaplotypeManager::ClusterNoOptimization;\n    if (ui->clusterGreedyRadio->isChecked())        return QtSLiMHaplotypeManager::ClusterNoOptimization;\n    if (ui->clusterGreedyOpt2Radio->isChecked())    return QtSLiMHaplotypeManager::ClusterOptimizeWith2opt;\n    return QtSLiMHaplotypeManager::ClusterNoOptimization;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeOptions.h",
    "content": "//\n//  QtSLiMHaplotypeOptions.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/4/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMHAPLOTYPEOPTIONS_H\n#define QTSLIMHAPLOTYPEOPTIONS_H\n\n#include <QDialog>\n\n#include \"QtSLiMHaplotypeManager.h\"\n\n\nnamespace Ui {\nclass QtSLiMHaplotypeOptions;\n}\n\nclass QtSLiMHaplotypeOptions : public QDialog\n{\n    Q_OBJECT\n    \npublic:\n    explicit QtSLiMHaplotypeOptions(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMHaplotypeOptions() override;\n    \n    size_t haplosomeSampleSize(void);    // 0 indicates \"all haplosomes\"\n    QtSLiMHaplotypeManager::ClusteringMethod clusteringMethod(void);\n    QtSLiMHaplotypeManager::ClusteringOptimization clusteringOptimization(void);\n    \nprivate:\n    Ui::QtSLiMHaplotypeOptions *ui;\n    \n    virtual void done(int r) override;\n};\n\n\n#endif // QTSLIMHAPLOTYPEOPTIONS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeOptions.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMHaplotypeOptions</class>\n <widget class=\"QDialog\" name=\"QtSLiMHaplotypeOptions\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>479</width>\n    <height>437</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Haplotype Plot Options</string>\n  </property>\n  <property name=\"modal\">\n   <bool>true</bool>\n  </property>\n  <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n     <item>\n      <widget class=\"QtSLiMIconView\" name=\"appIconButton\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"icons.qrc\">\n         <normaloff>:/icons/AppIcon128.png</normaloff>:/icons/AppIcon128.png</iconset>\n       </property>\n       <property name=\"iconSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"flat\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>40</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n     <property name=\"spacing\">\n      <number>0</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"label\">\n       <property name=\"font\">\n        <font>\n         <weight>75</weight>\n         <bold>true</bold>\n        </font>\n       </property>\n       <property name=\"text\">\n        <string>Haplotype Plot Options</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer_4\">\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>5</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"label_2\">\n       <property name=\"text\">\n        <string>Choose options to be used in generating the haplotype plot.  Note that some choices may cause plot generation to take a very long time!</string>\n       </property>\n       <property name=\"wordWrap\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer_2\">\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>12</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n       <item>\n        <spacer name=\"horizontalSpacer_3\">\n         <property name=\"orientation\">\n          <enum>Qt::Horizontal</enum>\n         </property>\n         <property name=\"sizeType\">\n          <enum>QSizePolicy::Fixed</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>12</width>\n           <height>20</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n       <item>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\">\n         <item>\n          <widget class=\"QGroupBox\" name=\"groupBox\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"title\">\n            <string>Haplosomes to display:</string>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n            <property name=\"spacing\">\n             <number>8</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>10</number>\n            </property>\n            <item>\n             <widget class=\"QRadioButton\" name=\"haplosomesAllRadio\">\n              <property name=\"text\">\n               <string>All haplosomes in the selected subpopulation</string>\n              </property>\n              <property name=\"checked\">\n               <bool>false</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QRadioButton\" name=\"haplosomesSampleRadio\">\n              <property name=\"text\">\n               <string>A sample from those haplosomes of size:</string>\n              </property>\n              <property name=\"checked\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n              <item>\n               <spacer name=\"horizontalSpacer\">\n                <property name=\"orientation\">\n                 <enum>Qt::Horizontal</enum>\n                </property>\n                <property name=\"sizeType\">\n                 <enum>QSizePolicy::Fixed</enum>\n                </property>\n                <property name=\"sizeHint\" stdset=\"0\">\n                 <size>\n                  <width>8</width>\n                  <height>5</height>\n                 </size>\n                </property>\n               </spacer>\n              </item>\n              <item>\n               <widget class=\"QLineEdit\" name=\"sampleSizeLineEdit\">\n                <property name=\"minimumSize\">\n                 <size>\n                  <width>65</width>\n                  <height>0</height>\n                 </size>\n                </property>\n                <property name=\"maximumSize\">\n                 <size>\n                  <width>65</width>\n                  <height>16777215</height>\n                 </size>\n                </property>\n                <property name=\"text\">\n                 <string>1000</string>\n                </property>\n                <property name=\"alignment\">\n                 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n                </property>\n               </widget>\n              </item>\n              <item>\n               <spacer name=\"horizontalSpacer_2\">\n                <property name=\"orientation\">\n                 <enum>Qt::Horizontal</enum>\n                </property>\n                <property name=\"sizeHint\" stdset=\"0\">\n                 <size>\n                  <width>40</width>\n                  <height>5</height>\n                 </size>\n                </property>\n               </spacer>\n              </item>\n             </layout>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QGroupBox\" name=\"groupBox_2\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"title\">\n            <string>Clustering algorithm:</string>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n            <property name=\"spacing\">\n             <number>8</number>\n            </property>\n            <property name=\"sizeConstraint\">\n             <enum>QLayout::SetDefaultConstraint</enum>\n            </property>\n            <property name=\"topMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>24</number>\n            </property>\n            <item>\n             <widget class=\"QRadioButton\" name=\"clusterNearestRadio\">\n              <property name=\"text\">\n               <string>Nearest neighbor (faster for large samples)</string>\n              </property>\n              <property name=\"checked\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QRadioButton\" name=\"clusterGreedyRadio\">\n              <property name=\"text\">\n               <string>Greedy (a little slower, but higher quality)</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QRadioButton\" name=\"clusterGreedyOpt2Radio\">\n              <property name=\"text\">\n               <string>Greedy + 2-opt (very slow, highest quality)</string>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </item>\n      </layout>\n     </item>\n     <item>\n      <widget class=\"QDialogButtonBox\" name=\"buttonBox\">\n       <property name=\"orientation\">\n        <enum>Qt::Horizontal</enum>\n       </property>\n       <property name=\"standardButtons\">\n        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMIconView</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"icons.qrc\"/>\n </resources>\n <connections>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>accepted()</signal>\n   <receiver>QtSLiMHaplotypeOptions</receiver>\n   <slot>accept()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>248</x>\n     <y>254</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>157</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n  <connection>\n   <sender>buttonBox</sender>\n   <signal>rejected()</signal>\n   <receiver>QtSLiMHaplotypeOptions</receiver>\n   <slot>reject()</slot>\n   <hints>\n    <hint type=\"sourcelabel\">\n     <x>316</x>\n     <y>260</y>\n    </hint>\n    <hint type=\"destinationlabel\">\n     <x>286</x>\n     <y>274</y>\n    </hint>\n   </hints>\n  </connection>\n </connections>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeProgress.cpp",
    "content": "//\n//  QtSLiMHaplotypeProgress.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/4/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMHaplotypeProgress.h\"\n#include \"ui_QtSLiMHaplotypeProgress.h\"\n\n#include \"QtSLiMAppDelegate.h\"\n\n\nQtSLiMHaplotypeProgress::QtSLiMHaplotypeProgress(QWidget *p_parent) :\n    QDialog(p_parent),\n    ui(new Ui::QtSLiMHaplotypeProgress)\n{\n    ui->setupUi(this);\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // change the app icon to our multi-size app icon for best results\n    ui->appIconButton->setIcon(qtSLiMAppDelegate->applicationIcon());\n    \n    // wire up cancel button\n    connect(ui->cancelButton, &QPushButton::clicked, this, [this]() { cancelled_ = true; });\n}\n\nQtSLiMHaplotypeProgress::~QtSLiMHaplotypeProgress()\n{\n    delete ui;\n}\n\nvoid QtSLiMHaplotypeProgress::runProgressWithHaplosomeCount(size_t haplosome_count, int stepCount, int progressChromIndex, int progressChromTotal)\n{\n    // set up initial state\n    taskDistances_Value_ = 0;\n\ttaskClustering_Value_ = 0;\n\ttaskOptimization_Value_ = 0;\n    \n    ui->chromosomeIndexLabel->setText(QString(\"Chromosome %1 of %2:\").arg(progressChromIndex).arg(progressChromTotal));\n    \n    ui->step1ProgressBar->setRange(0, static_cast<int>(haplosome_count));\n    ui->step2ProgressBar->setRange(0, static_cast<int>(haplosome_count));\n    ui->step3ProgressBar->setRange(0, static_cast<int>(haplosome_count));\n    \n    ui->step1ProgressBar->setValue(0);\n    ui->step2ProgressBar->setValue(0);\n    ui->step3ProgressBar->setValue(0);\n    \n    // if we're not doing an optimization step, remove those controls\n    if (stepCount == 2)\n    {\n        ui->barBoxLayout->removeWidget(ui->step3Box);   // remove from layout\n        ui->step3Box->setParent(nullptr);               // remove from parent widget\n        delete ui->step3Box;                            // also deletes ui->step3ProgressBar\n        ui->step3Box = nullptr;\n        ui->step3ProgressBar = nullptr;\n    }\n    \n    // fix sizing\n    setFixedSize(sizeHint());\n    setSizeGripEnabled(false);\n    \n    // make the progress window visible/active\n    setModal(true);\n    show();\n}\n\nbool QtSLiMHaplotypeProgress::haplotypeProgressIsCancelled(void)\n{\n    // spin the event loop for the panel, so the user can click \"Cancel\"\n    if (!cancelled_)\n        QCoreApplication::processEvents();\n    \n    // return the cancelled state\n    return cancelled_;\n}\n\nvoid QtSLiMHaplotypeProgress::setHaplotypeProgress(size_t progress, int stage)\n{\n    switch (stage)\n    {\n        case 0: taskDistances_Value_ = static_cast<int>(progress); break;\n        case 1: taskClustering_Value_ = static_cast<int>(progress); break;\n        case 2: taskOptimization_Value_ = static_cast<int>(progress); break;\n    }\n    \n    ui->step1ProgressBar->setValue(taskDistances_Value_);\n    ui->step2ProgressBar->setValue(taskClustering_Value_);\n    if (ui->step3ProgressBar)\n        ui->step3ProgressBar->setValue(taskOptimization_Value_);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeProgress.h",
    "content": "//\n//  QtSLiMHaplotypeProgress.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/4/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMHAPLOTYPEPROGRESS_H\n#define QTSLIMHAPLOTYPEPROGRESS_H\n\n#include <QDialog>\n\n\nnamespace Ui {\nclass QtSLiMHaplotypeProgress;\n}\n\nclass QtSLiMHaplotypeProgress : public QDialog\n{\n    Q_OBJECT\n    \npublic:\n    explicit QtSLiMHaplotypeProgress(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMHaplotypeProgress() override;\n    \n    void runProgressWithHaplosomeCount(size_t haplosome_count, int stepCount, int progressChromIndex, int progressChromTotal);\n    bool haplotypeProgressIsCancelled(void);\n    \n    void setHaplotypeProgress(size_t progress, int stage);\n    \nprivate:\n    Ui::QtSLiMHaplotypeProgress *ui;\n    \n    int taskDistances_Value_;\n\tint taskClustering_Value_;\n\tint taskOptimization_Value_;\n    \n    bool cancelled_ = false;\n};\n\n\n#endif // QTSLIMHAPLOTYPEPROGRESS_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHaplotypeProgress.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMHaplotypeProgress</class>\n <widget class=\"QDialog\" name=\"QtSLiMHaplotypeProgress\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>327</width>\n    <height>330</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Haplotype Plot Progress</string>\n  </property>\n  <property name=\"modal\">\n   <bool>true</bool>\n  </property>\n  <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n     <item>\n      <widget class=\"QtSLiMIconView\" name=\"appIconButton\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"icon\">\n        <iconset resource=\"icons.qrc\">\n         <normaloff>:/icons/AppIcon128.png</normaloff>:/icons/AppIcon128.png</iconset>\n       </property>\n       <property name=\"iconSize\">\n        <size>\n         <width>48</width>\n         <height>48</height>\n        </size>\n       </property>\n       <property name=\"flat\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer\">\n       <property name=\"orientation\">\n        <enum>Qt::Orientation::Vertical</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>40</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n     <property name=\"spacing\">\n      <number>0</number>\n     </property>\n     <item>\n      <widget class=\"QLabel\" name=\"label\">\n       <property name=\"font\">\n        <font>\n         <bold>true</bold>\n        </font>\n       </property>\n       <property name=\"text\">\n        <string>Haplotype Plot Progress</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer_4\">\n       <property name=\"orientation\">\n        <enum>Qt::Orientation::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Policy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>5</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"label_2\">\n       <property name=\"text\">\n        <string>Please wait for the haplotype analysis to complete...</string>\n       </property>\n       <property name=\"wordWrap\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer_2\">\n       <property name=\"orientation\">\n        <enum>Qt::Orientation::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Policy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>16</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <widget class=\"QLabel\" name=\"chromosomeIndexLabel\">\n       <property name=\"text\">\n        <string>Chromosome X of Y:</string>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <spacer name=\"verticalSpacer_3\">\n       <property name=\"orientation\">\n        <enum>Qt::Orientation::Vertical</enum>\n       </property>\n       <property name=\"sizeType\">\n        <enum>QSizePolicy::Policy::Fixed</enum>\n       </property>\n       <property name=\"sizeHint\" stdset=\"0\">\n        <size>\n         <width>20</width>\n         <height>12</height>\n        </size>\n       </property>\n      </spacer>\n     </item>\n     <item>\n      <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n       <item>\n        <spacer name=\"horizontalSpacer_3\">\n         <property name=\"orientation\">\n          <enum>Qt::Orientation::Horizontal</enum>\n         </property>\n         <property name=\"sizeType\">\n          <enum>QSizePolicy::Policy::Fixed</enum>\n         </property>\n         <property name=\"sizeHint\" stdset=\"0\">\n          <size>\n           <width>12</width>\n           <height>20</height>\n          </size>\n         </property>\n        </spacer>\n       </item>\n       <item>\n        <layout class=\"QVBoxLayout\" name=\"barBoxLayout\">\n         <item>\n          <widget class=\"QGroupBox\" name=\"step1Box\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"title\">\n            <string>Calculating genetic distances:</string>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n            <property name=\"spacing\">\n             <number>8</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>10</number>\n            </property>\n            <item>\n             <widget class=\"QProgressBar\" name=\"step1ProgressBar\">\n              <property name=\"value\">\n               <number>24</number>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QGroupBox\" name=\"step2Box\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"title\">\n            <string>Clustering haplosomes:</string>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n            <property name=\"spacing\">\n             <number>8</number>\n            </property>\n            <property name=\"sizeConstraint\">\n             <enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>\n            </property>\n            <property name=\"topMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>10</number>\n            </property>\n            <item>\n             <widget class=\"QProgressBar\" name=\"step2ProgressBar\">\n              <property name=\"value\">\n               <number>24</number>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QGroupBox\" name=\"step3Box\">\n           <property name=\"title\">\n            <string>Optimizing clustering:</string>\n           </property>\n           <property name=\"flat\">\n            <bool>true</bool>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_6\">\n            <property name=\"spacing\">\n             <number>8</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>16</number>\n            </property>\n            <item>\n             <widget class=\"QProgressBar\" name=\"step3ProgressBar\">\n              <property name=\"value\">\n               <number>24</number>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </item>\n      </layout>\n     </item>\n     <item>\n      <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n       <property name=\"spacing\">\n        <number>0</number>\n       </property>\n       <item>\n        <widget class=\"QPushButton\" name=\"cancelButton\">\n         <property name=\"sizePolicy\">\n          <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n           <horstretch>0</horstretch>\n           <verstretch>0</verstretch>\n          </sizepolicy>\n         </property>\n         <property name=\"text\">\n          <string>Cancel</string>\n         </property>\n        </widget>\n       </item>\n      </layout>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMIconView</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"icons.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMHelpWindow.cpp",
    "content": "//\n//  QtSLiMHelpWindow.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 11/19/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"QtSLiMHelpWindow.h\"\n#include \"ui_QtSLiMHelpWindow.h\"\n\n#include <QLineEdit>\n#include <QIcon>\n#include <QDebug>\n#include <QSettings>\n#include <QCloseEvent>\n#include <QTreeWidget>\n#include <QTreeWidgetItem>\n#include <QTextDocument>\n#include <QTextDocumentFragment>\n#include <QRegularExpression>\n#include <QTextCursor>\n#include <QFile>\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"community.h\"\n\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMAppDelegate.h\"\n\n#include <vector>\n#include <algorithm>\n#include <utility>\n#include <string>\n\n\n//\n// This is our custom outline item class, which can hold a QTextDocumentFragment\n//\nQtSLiMHelpItem::~QtSLiMHelpItem()\n{\n}\n\nQVariant QtSLiMHelpItem::data(int column, int role) const\n{\n    if (is_top_level && (role == Qt::ForegroundRole))\n    {\n        bool inDarkMode = QtSLiMInDarkMode();\n        \n        if (inDarkMode)\n            return QBrush(QtSLiMColorWithWhite(0.8, 1.0));\n        else\n            return QBrush(QtSLiMColorWithWhite(0.4, 1.0));\n    }\n    \n    return QTreeWidgetItem::data(column, role);\n}\n\n\n//\n// This subclass of QStyledItemDelegate provides custom drawing for the outline view.\n//\nQtSLiMHelpOutlineDelegate::~QtSLiMHelpOutlineDelegate(void)\n{\n}\n\nvoid QtSLiMHelpOutlineDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const\n{\n    QString itemString = index.data().toString();\n    \n    itemString = itemString.replace(QChar::Nbsp, ' ');  // standardize down to regular spaces\n    \n    bool topLevel = !index.parent().isValid();\n    QRect fullRect = option.rect;\n    fullRect.setLeft(0);             // we are not clipped; we will draw outside our rect to occupy the full width of the view\n    \n    // if we're a top-level item, wash a background color over our row; we use alpha so the disclosure triangle remains visible\n    if (topLevel)\n    {\n        bool inDarkMode = QtSLiMInDarkMode();\n        bool isEidos = index.data().toString().startsWith(\"Eidos \");\n        \n        if (isEidos)\n            painter->fillRect(fullRect, QBrush(inDarkMode ? QtSLiMColorWithRGB(0.0, 1.0, 0.0, 0.10) : QtSLiMColorWithRGB(0.0, 1.0, 0.0, 0.04)));       // pale green background for Eidos docs\n        else\n            painter->fillRect(fullRect, QBrush(inDarkMode ? QtSLiMColorWithRGB(0.0, 0.0, 1.0, 0.15) : QtSLiMColorWithRGB(0.0, 0.0, 1.0, 0.04)));       // pale blue background for SLiM docs\n    }\n    \n    // On Ubuntu, items get shown as having \"focus\" even when they're not selectable, which I dislike; this disables that appearance\n    // See https://stackoverflow.com/a/2061871/2752221\n    QStyleOptionViewItem modifiedOption(option);\n    if (modifiedOption.state & QStyle::State_HasFocus)\n        modifiedOption.state = modifiedOption.state ^ QStyle::State_HasFocus;\n    \n    // then let super draw\n    QStyledItemDelegate::paint(painter, modifiedOption, index);\n    \n    // custom overdraw\n    if (topLevel)\n    {\n        // if an item is top-level, we want to frame it to look heavier, like a \"group item\" on macOS\n        bool inDarkMode = QtSLiMInDarkMode();\n        \n        painter->fillRect(QRect(fullRect.left(), fullRect.top(), fullRect.width(), 1), QtSLiMColorWithWhite(inDarkMode ? 0.15 : 0.85, 1.0));        // top edge in light gray\n        painter->fillRect(QRect(fullRect.left(), fullRect.top() + fullRect.height() - 1, fullRect.width(), 1), QtSLiMColorWithWhite(inDarkMode ? 0.05 : 0.65, 1.0));     // bottom edge in medium gray\n    }\n    else\n    {\n        // otherwise, add a color box on the right for the items that need them\n        static QStringList *stringsWF = nullptr;\n        static QStringList *stringsNonWF = nullptr;\n        static QStringList *stringsNucmut = nullptr;\n        \n        if (!stringsWF)\n            stringsWF = new QStringList({\"– addSubpopSplit()\",\n                                         \"– registerMateChoiceCallback()\",\n                                         \"cloningRate =>\",\n                                         \"immigrantSubpopFractions =>\",\n                                         \"immigrantSubpopIDs =>\",\n                                         \"selfingRate =>\",\n                                         \"sexRatio =>\",\n                                         \"– setCloningRate()\",\n                                         \"– setMigrationRates()\",\n                                         \"– setSelfingRate()\",\n                                         \"– setSexRatio()\",\n                                         \"– setSubpopulationSize()\",\n                                         \"mateChoice() callbacks\"\n                                        });\n        \n        if (!stringsNonWF)\n            stringsNonWF = new QStringList({\"initializeSLiMModelType()\",\n                              \"age =>\",\n                              \"modelType =>\",\n                              \"– registerReproductionCallback()\",\n                              \"– registerSurvivalCallback()\",\n                              \"– addCloned()\",\n                              \"– addCrossed()\",\n                              \"– addEmpty()\",\n                              \"– addMultiRecombinant()\",\n                              \"– addRecombinant()\",\n                              \"– addSelfed()\",\n                              \"– removeSubpopulation()\",\n                              \"– killIndividuals()\",\n                              \"– takeMigrants()\",\n                              \"reproduction() callbacks\",\n                              \"survival() callbacks\"\n                              });\n        \n        if (!stringsNucmut)\n            stringsNucmut = new QStringList({\"initializeAncestralNucleotides()\",\n                               \"initializeMutationTypeNuc()\",\n                               \"initializeHotspotMap()\",\n                               \"codonsToAminoAcids()\",\n                               \"randomNucleotides()\",\n                               \"mm16To256()\",\n                               \"mmJukesCantor()\",\n                               \"mmKimura()\",\n                               \"nucleotideCounts()\",\n                               \"nucleotideFrequencies()\",\n                               \"nucleotidesToCodons()\",\n                               \"codonsToNucleotides()\",\n                               \"nucleotideBased =>\",\n                               \"nucleotide <–>\",\n                               \"nucleotideValue <–>\",\n                               \"nucleotide =>\",\n                               \"nucleotideValue =>\",\n                               \"mutationMatrix =>\",\n                               \"– setMutationMatrix()\",\n                               \"– ancestralNucleotides()\",\n                               \"– setAncestralNucleotides()\",\n                               \"– nucleotides()\",\n                               \"hotspotEndPositions =>\",\n                               \"hotspotEndPositionsF =>\",\n                               \"hotspotEndPositionsM =>\",\n                               \"hotspotMultipliers =>\",\n                               \"hotspotMultipliersF =>\",\n                               \"hotspotMultipliersM =>\",\n                               \"– setHotspotMap()\"\n                               });\n        \n        bool draw_WF_box = stringsWF->contains(itemString);\n        bool draw_nonWF_box = stringsNonWF->contains(itemString);\n        bool draw_nucmut_box = stringsNucmut->contains(itemString);\n        \n        if (draw_WF_box || draw_nonWF_box || draw_nucmut_box)\n        {\n            QRect boxRect = QRect(fullRect.left() + fullRect.width() - 14, fullRect.top() + 4, 8, 8);\n            QColor boxColor;\n            \n            if (draw_WF_box)\n                boxColor = QColor(66, 255, 53);         // WF-only color (green)\n            else if (draw_nonWF_box)\n                boxColor = QColor(88, 148, 255);        // nonWF-only color (blue)\n            else //if (draw_nucmut_box)\n                boxColor = QColor(228, 118, 255);       // nucmut color (purple)\n            \n            painter->fillRect(boxRect, boxColor);\n            QtSLiMFrameRect(boxRect, Qt::black, *painter);\n        }\n    }\n}\n\n\n//\n// This is the QWidget subclass for the help window, which does the heavy lifting of building the doc outline from HTML files\n//\nQtSLiMHelpWindow &QtSLiMHelpWindow::instance(void)\n{\n    static QtSLiMHelpWindow *inst = nullptr;\n    \n    if (!inst)\n        inst = new QtSLiMHelpWindow(nullptr);\n    \n    return *inst;\n}\n\nQtSLiMHelpWindow::QtSLiMHelpWindow(QWidget *p_parent) : QWidget(p_parent, Qt::Window), ui(new Ui::QtSLiMHelpWindow)\n{\n    ui->setupUi(this);\n    interpolateSplitters();\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // Configure the search field to look like a search field\n    ui->searchField->setClearButtonEnabled(true);\n    ui->searchField->setPlaceholderText(\"Search...\");\n    \n    connect(ui->searchField, &QLineEdit::returnPressed, this, &QtSLiMHelpWindow::searchFieldChanged);\n    connect(ui->searchScopeButton, &QPushButton::clicked, this, &QtSLiMHelpWindow::searchScopeToggled);\n    \n    // Change the search scope button's appearance based on the app palette\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, &QtSLiMHelpWindow::applicationPaletteChanged);\n    applicationPaletteChanged();\n    \n    // Configure the outline view to behave as we wish\n    connect(ui->topicOutlineView, &QTreeWidget::itemSelectionChanged, this, &QtSLiMHelpWindow::outlineSelectionChanged);\n    connect(ui->topicOutlineView, &QTreeWidget::itemClicked, this, &QtSLiMHelpWindow::itemClicked);\n    connect(ui->topicOutlineView, &QTreeWidget::itemCollapsed, this, &QtSLiMHelpWindow::itemCollapsed);\n    connect(ui->topicOutlineView, &QTreeWidget::itemExpanded, this, &QtSLiMHelpWindow::itemExpanded);\n    \n    QAbstractItemDelegate *outlineDelegate = new QtSLiMHelpOutlineDelegate(ui->topicOutlineView);\n    ui->topicOutlineView->setItemDelegate(outlineDelegate);\n    \n    // tweak appearance on Linux; the form is adjusted for macOS\n#if defined(__linux__)\n    {\n        // use a smaller font for the outline\n        QFont outlineFont(ui->topicOutlineView->font());\n        outlineFont.setPointSizeF(outlineFont.pointSizeF() - 1);\n        ui->topicOutlineView->setFont(outlineFont);\n        \n        // the headers/content button needs somewhat different metrics\n        ui->searchScopeButton->setMinimumWidth(75);\n        ui->searchScopeButton->setMaximumWidth(75);\n    }\n#endif\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMHelpWindow\");\n    resize(settings.value(\"size\", QSize(550, 400)).toSize());\n    move(settings.value(\"pos\", QPoint(25, 45)).toPoint());\n    settings.endGroup();\n    \n    // Add Eidos topics\n    std::vector<EidosPropertySignature_CSP> builtin_properties = EidosClass::RegisteredClassProperties(true, false);\n    std::vector<EidosMethodSignature_CSP> builtin_methods = EidosClass::RegisteredClassMethods(true, false);\n    \n    addTopicsFromRTFFile(\"EidosHelpFunctions\", \"Eidos Functions\", &EidosInterpreter::BuiltInFunctions(), nullptr, nullptr);\n    addTopicsFromRTFFile(\"EidosHelpClasses\", \"Eidos Classes\", &EidosInterpreter::BuiltInFunctions(), &builtin_methods, &builtin_properties);    // constructors are in BuiltInFunctions()\n    addTopicsFromRTFFile(\"EidosHelpOperators\", \"Eidos Operators\", nullptr, nullptr, nullptr);\n    addTopicsFromRTFFile(\"EidosHelpStatements\", \"Eidos Statements\", nullptr, nullptr, nullptr);\n    addTopicsFromRTFFile(\"EidosHelpTypes\", \"Eidos Types\", nullptr, nullptr, nullptr);\n    \n    // Check for completeness of the Eidos documentation\n    checkDocumentationOfFunctions(&EidosInterpreter::BuiltInFunctions());\n    \n    for (EidosClass *class_object : EidosClass::RegisteredClasses(true, false))\n    {\n        const std::string &element_type = class_object->ClassName();\n        \n        if (!Eidos_string_hasPrefix(element_type, \"_\") && (element_type != \"DictionaryRetained\"))\t\t// internal classes are undocumented\n        {\n            checkDocumentationOfClass(class_object);\n            addSuperclassItemForClass(class_object);\n        }\n    }\n    \n    // Add SLiM topics\n    std::vector<EidosPropertySignature_CSP> context_properties = EidosClass::RegisteredClassProperties(false, true);\n    std::vector<EidosMethodSignature_CSP> context_methods = EidosClass::RegisteredClassMethods(false, true);\n    const std::vector<EidosFunctionSignature_CSP> *zg_functions = Community::ZeroTickFunctionSignatures();\n    const std::vector<EidosFunctionSignature_CSP> *slim_functions = Community::SLiMFunctionSignatures();\n    std::vector<EidosFunctionSignature_CSP> all_slim_functions;\n    \n    all_slim_functions.insert(all_slim_functions.end(), zg_functions->begin(), zg_functions->end());\n    all_slim_functions.insert(all_slim_functions.end(), slim_functions->begin(), slim_functions->end());\n    \n    addTopicsFromRTFFile(\"SLiMHelpFunctions\", \"SLiM Functions\", &all_slim_functions, nullptr, nullptr);\n    addTopicsFromRTFFile(\"SLiMHelpClasses\", \"SLiM Classes\", nullptr, &context_methods, &context_properties);\n    addTopicsFromRTFFile(\"SLiMHelpCallbacks\", \"SLiM Events and Callbacks\", nullptr, nullptr, nullptr);\n    \n    // Check for completeness of the SLiM documentation\n    checkDocumentationOfFunctions(&all_slim_functions);\n    \n    for (EidosClass *class_object : EidosClass::RegisteredClasses(false, true))\n    {\n        const std::string &element_type = class_object->ClassName();\n        \n        if (!Eidos_string_hasPrefix(element_type, \"_\"))\t\t// internal classes are undocumented\n        {\n            checkDocumentationOfClass(class_object);\n            addSuperclassItemForClass(class_object);\n        }\n    }\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nvoid QtSLiMHelpWindow::applicationPaletteChanged(void)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    // Custom colors for the search mode button for dark mode vs. light mode; note that this completely overrides the style sheet in the .ui file!\n    if (inDarkMode)\n        ui->searchScopeButton->setStyleSheet(\"QPushButton { border: 1px solid #888; border-radius: 20px; border-style: outset; margin: 0px; padding: 2px; background: rgb(125, 125, 125); } QPushButton:pressed { background: rgb(105, 105, 105); }\");\n    else\n        ui->searchScopeButton->setStyleSheet(\"QPushButton { border: 1px solid #888; border-radius: 20px; border-style: outset; margin: 0px; padding: 2px; background: rgb(245, 245, 245); } QPushButton:pressed { background: rgb(195, 195, 195); }\");\n}\n\nQtSLiMHelpWindow::~QtSLiMHelpWindow()\n{\n    delete ui;\n}\n\nvoid QtSLiMHelpWindow::interpolateSplitters(void)\n{\n#if 1\n    // add a top-level horizontal splitter\n    \n    QLayout *parentLayout = ui->horizontalLayout;\n    QWidget *firstWidget = ui->topicOutlineView;\n    QWidget *secondWidget = ui->descriptionTextEdit;\n    \n    // force geometry calculation, which is lazy\n    setAttribute(Qt::WA_DontShowOnScreen, true);\n    show();\n    hide();\n    setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // change fixed-size views to be flexible, so they cooperate with the splitter\n    firstWidget->setMinimumWidth(200);\n    firstWidget->setMaximumWidth(400);\n    \n    // empty out parentLayout\n    QLayoutItem *child;\n    while ((child = parentLayout->takeAt(0)) != nullptr);\n    \n    // make the QSplitter between the left and right and add the subsidiary widgets to it\n    splitter = new QSplitter(Qt::Horizontal, this);\n    \n    splitter->addWidget(firstWidget);\n    splitter->addWidget(secondWidget);\n    splitter->setHandleWidth(splitter->handleWidth() + 3);\n    splitter->setStretchFactor(0, 1);\n    splitter->setStretchFactor(1, 2);    // initially, give 2/3 of the width to the description textedit\n    splitter->setCollapsible(0, true);\n    splitter->setCollapsible(1, false);\n    \n    // and finally, add the splitter to the parent layout\n    parentLayout->addWidget(splitter);\n    parentLayout->setContentsMargins(0, 0, 0, 0);\n#endif\n}\n\nbool QtSLiMHelpWindow::findItemsMatchingSearchString(QTreeWidgetItem *root, const QString searchString, bool titlesOnly, std::vector<QTreeWidgetItem *> &matchKeys, std::vector<QTreeWidgetItem *> &expandItems)\n{\n\tbool anyChildMatches = false;\n\t\n    for (int child_index = 0; child_index < root->childCount(); ++child_index)\n\t{\n        QTreeWidgetItem *childItem = root->child(child_index);\n        \n\t\tif (childItem->childCount() > 0)\n\t\t{\n\t\t\t// Recurse through the child's children\n\t\t\tbool result = findItemsMatchingSearchString(childItem, searchString, titlesOnly, matchKeys, expandItems);\n\t\t\t\n\t\t\tif (result)\n\t\t\t\tanyChildMatches = true;\n\t\t}\n\t\telse if (childItem->childIndicatorPolicy() == QTreeWidgetItem::DontShowIndicatorWhenChildless)\n\t\t{\n\t\t\t// If the item has no children, and is not showing an indicator, it is a leaf and should be searched\n\t\t\tbool isMatch = false;\n            const QString itemText = childItem->text(0);\n            \n            if (itemText.contains(searchString, Qt::CaseInsensitive))\n\t\t\t\tisMatch = true;\n\t\t\t\n\t\t\tif (!titlesOnly)\n\t\t\t{\n                QtSLiMHelpItem *helpItem = dynamic_cast<QtSLiMHelpItem *>(childItem);\n                \n                if (helpItem)\n                {\n                    QTextDocumentFragment *helpFragment = helpItem->doc_fragment;\n                    \n                    if (helpFragment)\n                    {\n                        const QString helpText = helpFragment->toPlainText();\n                        \n                        if (helpText.contains(searchString, Qt::CaseInsensitive))\n                            isMatch = true;\n                    }\n                }\n\t\t\t}\n\t\t\t\n\t\t\tif (isMatch)\n\t\t\t{\n\t\t\t\tmatchKeys.emplace_back(childItem);\n\t\t\t\tanyChildMatches = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (anyChildMatches)\n\t\texpandItems.emplace_back(root);\n\t\n\treturn anyChildMatches;\n}\n\nvoid QtSLiMHelpWindow::expandToShowItems(const std::vector<QTreeWidgetItem *> &expandItems, const std::vector<QTreeWidgetItem *> &matchKeys)\n{\n    // Coalesce the selection change to avoid obsessively re-generating the documentation textedit\n    doingProgrammaticSelection = true;\n    doingProgrammaticCollapseExpand = true;\n    \n    // Deselect and collapse everything, as an initial state\n    ui->topicOutlineView->setCurrentItem(nullptr, 0, QItemSelectionModel::Clear);\n    recursiveCollapse(ui->topicOutlineView->invisibleRootItem());   // collapseAll() only collapses items that are visible!\n    \n    // Expand all nodes that have a search hit; reverse order so parents expand before their children\n    for (auto iter = expandItems.rbegin(); iter != expandItems.rend(); ++iter)\n        ui->topicOutlineView->expandItem(*iter);\n    \n    // Select all of the items that matched\n    for (auto item : matchKeys)\n        ui->topicOutlineView->setCurrentItem(item, 0, QItemSelectionModel::Select);\n    \n    // Finish coalescing selection changes\n    doingProgrammaticCollapseExpand = false;\n    doingProgrammaticSelection = false;\n    outlineSelectionChanged();\n}\n\nvoid QtSLiMHelpWindow::searchFieldChanged(void)\n{\n    QString searchString = ui->searchField->text();\n    \n    ui->searchField->selectAll();\n    \n    if (searchString.length())\n    {\n        // Do a depth-first search under the topic root that matches the search pattern, and gather tasks to perform\n        std::vector<QTreeWidgetItem *> matchKeys;\n        std::vector<QTreeWidgetItem *> expandItems;\n        \n        findItemsMatchingSearchString(ui->topicOutlineView->invisibleRootItem(), searchString, (searchType == 0), matchKeys, expandItems);\n        \n        if (matchKeys.size())\n            expandToShowItems(expandItems, matchKeys);\n        else\n            qApp->beep();\n    }\n}\n\nvoid QtSLiMHelpWindow::searchScopeToggled(void)\n{\n    searchType = 1 - searchType;\n    \n    if (searchType == 0)\n        ui->searchScopeButton->setText(\"🔍  headers\");\n    else if (searchType == 1)\n        ui->searchScopeButton->setText(\"🔍  content\");\n    \n    searchFieldChanged();\n}\n\nvoid QtSLiMHelpWindow::enterSearchForString(QString searchString, bool titlesOnly)\n{\n\t// Show our window and bring it front\n    QtSLiMMakeWindowVisibleAndExposed(this);\n\t\n\t// Set the search string per the request\n    ui->searchField->setText(searchString);\n\t\n\t// Set the search type per the request\n    int desiredSearchType = titlesOnly ? 0 : 1;\n\t\n    if (searchType != desiredSearchType)\n        searchScopeToggled();   // re-runs the search as a side effect\n\telse\n        searchFieldChanged();   // re-run explicitly\n}\n\nvoid QtSLiMHelpWindow::closeEvent(QCloseEvent *p_event)\n{\n    // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMHelpWindow\");\n    settings.setValue(\"size\", size());\n    settings.setValue(\"pos\", pos());\n    settings.endGroup();\n    \n    // use super's default behavior\n    QWidget::closeEvent(p_event);\n}\n\n// This is a helper method for addTopicsFromRTFFile:... that finds the right parent item to insert a given section index under.\n// This method makes a lot of assumptions about the layout of the RTF file, such as that section number proceeds in sorted order.\nQTreeWidgetItem *QtSLiMHelpWindow::parentItemForSection(const QString &sectionString, QtSLiMTopicMap &topics, QtSLiMHelpItem *topItem)\n{\n    QStringList sectionComponents = sectionString.split('.');\n\tint sectionCount = sectionComponents.size();\n\t\n\tif (sectionCount <= 1)\n\t{\n        // With an empty section string, or a whole-number section like \"3\", the parent is the top item\n\t\treturn topItem;\n\t}\n\telse\n\t{\n\t\t// We have a section string like \"3.1\" or \"3.1.2\"; we want to look for a parent to add it to – like \"3\" or \"3.1\", respectively\n\t\tsectionComponents.pop_back();\n\t\t\n\t\tQString parentSectionString = sectionComponents.join('.');\n\t\tauto parentTopicDictIter = topics.find(parentSectionString);\n\t\t\n\t\tif (parentTopicDictIter != topics.end())\n\t\t\treturn parentTopicDictIter.value();     // Found a parent to add to\n\t\telse\n\t\t\treturn topItem;                         // Couldn't find a parent to add to, so the parent is the top item\n\t}\n}\n\n// This is a helper method for addTopicsFromRTFFile:... that creates a new QTreeWidgetItem under which items will be placed, and finds the right parent\n// item to insert it under.  This method makes a lot of assumptions about the layout of the RTF file, such as that section number proceeds in sorted order.\nQtSLiMHelpItem *QtSLiMHelpWindow::createItemForSection(const QString &sectionString, QString title, QtSLiMTopicMap &topics, QtSLiMHelpItem *topItem)\n{\n\tstatic const QString functions(\" functions\");\n\t\n    if (title.endsWith(functions))\n        title.chop(functions.length());\n\t\n    QStringList sectionComponents = sectionString.split('.');\n\tQTreeWidgetItem *parentItem = parentItemForSection(sectionString, topics, topItem);\n    QtSLiMHelpItem *newItem = new QtSLiMHelpItem(parentItem);\n\t\n    newItem->setText(0, title);\n    newItem->setFlags(Qt::ItemIsEnabled);\n    newItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);\n    \n    topics.insert(sectionString, newItem);\n\t\n\treturn newItem;\n}\n\n// This is the main RTF doc file reading method; it finds an RTF file of a given name in the main bundle, reads it into an attributed string, and then scans\n// that string for topic headings, function/method/property signature lines, etc., and creates a hierarchy of help topics from the results.  This process\n// assumes that the RTF doc file is laid out in a standard way that fits the regex patterns used here; it is designed to work directly with content copied\n// and pasted out of our Word documentation files into RTF in TextEdit.\nvoid QtSLiMHelpWindow::addTopicsFromRTFFile(const QString &htmlFile,\n                                            const QString &topLevelHeading,\n                                            const std::vector<EidosFunctionSignature_CSP> *functionList,\n                                            const std::vector<EidosMethodSignature_CSP> *methodList,\n                                            const std::vector<EidosPropertySignature_CSP> *propertyList)\n{\n    QString topicFilePath = QString(\":/help/\") + htmlFile + QString(\".html\");\n    QTextDocument topicFileTextDocument;\n    \n    // Read the HTML resource in and create a QTextDocument\n    {\n        QFile topicFile(topicFilePath);\n        QString topicFileData;\n        \n        if (!topicFile.open(QIODevice::ReadOnly | QIODevice::Text)) {   // QIODevice::Text converts line endings to \\n, making Windows happy; harmless\n            qDebug() << \"QtSLiMHelpWindow::addTopicsFromRTFFile(): could not find HTML file \" << htmlFile;\n            return;\n        }\n        \n        topicFileData = topicFile.readAll();\n        topicFile.close();\n        \n        // OK, so this is gross and probably fragile.  Our HTML content has colors set on the text in some places: sometimes for syntax coloring\n        // of code snippets, but also just setting text explicitly to black for no apparent reason.  This doesn't translate well to dark mode;\n        // the syntax coloring uses colors that are fairly illegible against black, and the black text of course ends up black-on-black.  We thus\n        // need to strip off all color information.  Ideally, we'd do this on the QTextDocument, but I don't know how to do that (see question at\n        // https://stackoverflow.com/questions/65779196/how-to-remove-all-text-color-attributes-from-a-qtextdocument).  So instead, here we scan\n        // the HTML source code for color attributes and remove them, with a regex.  (What could possibly go wrong???)\n        // BCH 5/7/2021: This regex worked well, but a better solution appears to be the code below.  We'll see whether it causes any problems.\n        // BCH 12/12/2021: Well, that code below did cause problems: it caused the formatting to be lost from \"SLiM Events and Callbacks\" and\n        // \"Eidos Statements\" for no apparent reason.  So, reverting to this regex, which has had no observed problems thus far.\n        static const QRegularExpression htmlColorRegex(\"(;? ?color: ?#[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])\");\n        \n        topicFileData.replace(htmlColorRegex, \"\");\n        \n        // FIXME while on the topic of dark mode, there is a subtle bug in the help window's handling of it.  We call ColorizeCallSignature() and\n        // ColorizePropertySignature() below to colorize property/function/method signatures.  Those produce colorized strings tailored to the\n        // mode we're currently in: light mode or dark mode.  If the user then switches modes, those strings are incorrectly colored.  This is\n        // not a disaster - the color schemes are not that different - but it's a bug.  Ideally, we'd either do the colorizing dynamically at\n        // display time, or we'd reload the whole help document when the display mode switches.  Both are rather difficult to do, however.\n        \n        // Create the QTextDocument from the HTML\n        topicFileTextDocument.setHtml(topicFileData);\n        \n        // Get rid of foreground and background colors set on the text; the original solution was the regex commented out above, but this seems\n        // to work just as well, and is less icky/scary.  This solution is from https://stackoverflow.com/a/67384128/2752221.\n        // BCH 12/12/2021: This solution caused loss of text formatting in some cases; reverting to the regex solution above.  Oh well.\n        /*QTextCharFormat defaultFormat = QTextCharFormat();\n        QTextCursor tc(&topicFileTextDocument);\n        tc.select(QTextCursor::Document);\n        QTextCharFormat docFormat = tc.charFormat();\n        docFormat.setBackground(defaultFormat.background());\n        docFormat.setForeground(defaultFormat.foreground());\n        tc.mergeCharFormat(docFormat);*/\n    }\n    \n    // Create the topic map for the section being parsed; this keeps track of numbered sections so we can find where children go\n    QtSLiMTopicMap topics;\t\t\t\t// keys are strings like 3.1 or 3.1.2 or whatever\n    \n    // Create the top-level item for the section we're parsing; note that QtSLiMHelpOutlineDelegate does additional display customization\n    QtSLiMHelpItem *topItem = new QtSLiMHelpItem(ui->topicOutlineView);\n    topItem->setText(0, topLevelHeading);\n    topItem->setFlags(Qt::ItemIsEnabled);\n    topItem->setForeground(0, QBrush(QtSLiMColorWithWhite(0.4, 1.0)));\n    topItem->setSizeHint(0, QSize(20.0, 20.0));\n    topItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);\n    QFont itemFont(topItem->font(0));\n    itemFont.setBold(true);\n    topItem->setFont(0, itemFont);\n    topItem->is_top_level = true;\n    \n    // Set up the current topic item that we are appending content into\n    QtSLiMHelpItem *currentTopicItem = topItem;\n\tQString topicItemKey;\n\tQTextCursor *topicItemCursor = nullptr;\n    \n    // Make regular expressions that we will use below\n    static const QRegularExpression topicHeaderRegex(\"^((?:[0-9]+\\\\.)*[0-9]+)\\\\.?[\\u00A0 ] (.+)$\", QRegularExpression::CaseInsensitiveOption);\n    static const QRegularExpression topicGenericItemRegex(\"^((?:[0-9]+\\\\.)*[0-9]+)\\\\.?[\\u00A0 ] ITEM: ((?:[0-9]+\\\\.? )?)(.+)$\", QRegularExpression::CaseInsensitiveOption);\n    static const QRegularExpression topicFunctionRegex(\"^\\\\([a-zA-Z<>\\\\*+$]+\\\\)([a-zA-Z_0-9]+)\\\\(.+$\", QRegularExpression::CaseInsensitiveOption);\n    static const QRegularExpression topicMethodRegex(\"^([-–+])[\\u00A0 ]\\\\([a-zA-Z<>\\\\*+$]+\\\\)([a-zA-Z_0-9]+)\\\\(.+$\", QRegularExpression::CaseInsensitiveOption);\n    static const QRegularExpression topicPropertyRegex(\"^([a-zA-Z_0-9]+)[\\u00A0 ]((?:<[-–]>)|(?:=>)) \\\\([a-zA-Z<>\\\\*+$]+\\\\)$\", QRegularExpression::CaseInsensitiveOption);\n\t\n    if (!topicHeaderRegex.isValid() || !topicGenericItemRegex.isValid() || !topicFunctionRegex.isValid() || !topicMethodRegex.isValid() || !topicPropertyRegex.isValid())\n        qDebug() << \"QtSLiMHelpWindow::addTopicsFromRTFFile(): invalid regex\";\n    \n    // Scan through the file one line at a time, parsing out topic headers\n\tQString topicFileString = topicFileTextDocument.toRawText();\n\tQStringList topicFileLineArray = topicFileString.split(QChar::ParagraphSeparator);  // this is what Qt's HTML rendering uses between blocks\n\tint lineCount = topicFileLineArray.size();\n\tint lineStartIndex = 0;\t\t// the character index of the current line in topicFileAttrString\n\t\n\tfor (int lineIndex = 0; lineIndex < lineCount; ++lineIndex)\n\t{\n\t\tconst QString &line = topicFileLineArray.at(lineIndex);\n\t\tint lineLength = line.length();\n        QTextCursor lineCursor(&topicFileTextDocument);\n        \n        lineCursor.setPosition(lineStartIndex);\n        lineCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, lineLength);\n        \n        // figure out what kind of line we have and handle it\n        QRegularExpressionMatch match_topicHeaderRegex = topicHeaderRegex.match(line);\n        QRegularExpressionMatch match_topicGenericItemRegex = topicGenericItemRegex.match(line);\n        QRegularExpressionMatch match_topicFunctionRegex = topicFunctionRegex.match(line);\n        QRegularExpressionMatch match_topicMethodRegex = topicMethodRegex.match(line);\n        QRegularExpressionMatch match_topicPropertyRegex = topicPropertyRegex.match(line);\n\t\tint isTopicHeaderLine = match_topicHeaderRegex.hasMatch();\n\t\tint isTopicGenericItemLine = match_topicGenericItemRegex.hasMatch();\n\t\tint isTopicFunctionLine = match_topicFunctionRegex.hasMatch();\n\t\tint isTopicMethodLine = match_topicMethodRegex.hasMatch();\n\t\tint isTopicPropertyLine = match_topicPropertyRegex.hasMatch();\n\t\tint matchCount = isTopicHeaderLine + isTopicFunctionLine + isTopicMethodLine + isTopicPropertyLine;\t// excludes isTopicGenericItemLine, which is a subtype of isTopicHeaderLine\n\t\t\n\t\tif (matchCount > 1)\n\t\t{\n\t\t\tqDebug() << \"*** line matched more than one regex type: %@\" << line;\n\t\t\treturn;\n\t\t}\n        \n        if (matchCount == 0)\n        {\n            if (lineLength)\n            {\n                // If we have a topic, this is a content line, to be appended to the current topic item's content\n                if (topicItemCursor)\n                    topicItemCursor->movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, lineLength + 1);     // 1 for the QChar::ParagraphSeparator\n                else if (line.trimmed().length())\n                    qDebug() << \"orphan line while reading for top level heading \" << topLevelHeading << \": \" << line;\n            }\n        }\n        \n        if ((matchCount == 1) || ((matchCount == 0) && (lineIndex == lineCount - 1)))\n\t\t{\n\t\t\t// This line starts a new header or item or ends the file, so we need to terminate the current item\n\t\t\tif (topicItemCursor && topicItemKey.length())\n\t\t\t{\n                if (!currentTopicItem)\n                {\n                    qDebug() << \"no current topic item for text to be placed into\";\n                    return;\n                }\n                \n                QtSLiMHelpItem *childItem = new QtSLiMHelpItem(currentTopicItem);\n                QTextDocumentFragment *topicFragment = new QTextDocumentFragment(topicItemCursor->selection());\n                \n                childItem->setText(0, topicItemKey);\n                childItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);\n                childItem->doc_fragment = topicFragment;\n                \n                delete topicItemCursor;\n                topicItemCursor = nullptr;\n                topicItemKey.clear();\n\t\t\t}\n\t\t}\n        \n        if (isTopicHeaderLine)\n\t\t{\n\t\t\t// We have hit a new topic header.  This might be a subtopic of the current topic, or a sibling, or a sibling of one of our ancestors\n            QString sectionString = match_topicHeaderRegex.captured(1);\n            QString titleString = match_topicHeaderRegex.captured(2);\n\t\t\t\n\t\t\t//qDebug() << \"topic header section \" << sectionString << \", title \" << titleString << \", line: \" << line;\n\t\t\t\n\t\t\tif (isTopicGenericItemLine)\n\t\t\t{\n\t\t\t\t// This line plays two roles: it is both a header (with a period-separated section index at the beginning) and a\n\t\t\t\t// topic item starter like function/method/property lines, with item content following it immediately.  First we\n\t\t\t\t// use the header-line section string to find the right parent section to place it.\n\t\t\t\tcurrentTopicItem = dynamic_cast<QtSLiMHelpItem *>(parentItemForSection(sectionString, topics, topItem));\n\t\t\t\t\n\t\t\t\t// Then we extract the item name and create a new item under the parent dict.\n                //QString itemOrder = match_topicGenericItemRegex.captured(2);\n                QString itemName = match_topicGenericItemRegex.captured(3);\n                int itemName_pos = match_topicGenericItemRegex.capturedStart(3);\n                int itemName_len = match_topicGenericItemRegex.capturedLength(3);\n                \n                topicItemCursor = new QTextCursor(&topicFileTextDocument);\n                \n                topicItemCursor->setPosition(lineStartIndex + itemName_pos);\n                topicItemCursor->movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, itemName_len);\n                \n\t\t\t\ttopicItemKey = itemName;\n\t\t\t}\n            else\n            {\n                // This header line is not also an item line, so we want to create a new expandable category and await items\n                currentTopicItem = createItemForSection(sectionString, titleString, topics, topItem);\n            }\n        }\n        else if (isTopicFunctionLine)\n\t\t{\n            // This topic item is a function declaration\n            QString callName = match_topicFunctionRegex.captured(1);\n\t\t\t\n\t\t\t//qDebug() << \"topic function name: \" << callName << \", line: \" << line;\n\t\t\t\n\t\t\t// Check for a built-in function signature that matches and substitute it in\n\t\t\tif (functionList)\n\t\t\t{\n\t\t\t\tstd::string function_name = callName.toStdString();\n\t\t\t\tconst EidosFunctionSignature *function_signature = nullptr;\n\t\t\t\t\n\t\t\t\tfor (const auto &signature_iter : *functionList)\n\t\t\t\t\tif (signature_iter->call_name_.compare(function_name) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfunction_signature = signature_iter.get();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (function_signature)\n                    ColorizeCallSignature(function_signature, 11.0, lineCursor);\n\t\t\t\telse\n\t\t\t\t\tqDebug() << \"*** no function signature found for function name \" << callName;\n\t\t\t}\n\t\t\t\n\t\t\ttopicItemKey = callName + \"()\";\n            topicItemCursor = new QTextCursor(lineCursor);\n        }\n        else if (isTopicMethodLine)\n\t\t{\n            // This topic item is a method declaration\n            QString classMethodString = match_topicMethodRegex.captured(1);\n            QString callName = match_topicMethodRegex.captured(2);\n\t\t\t\n\t\t\t//qDebug() << \"topic method name: \" << callName << \", line: \" << line;\n\t\t\t\n\t\t\t// Check for a built-in method signature that matches and substitute it in\n            // BCH 3 April 2022: I don't think there's any reason why we can't have more than one method with the same name,\n            // but with different signatures, as long as they are not in the same class; we can't handle overloading, but\n            // method lookup is within-class.  So this code could be generalized as the property lookup code below was; I just\n            // haven't bothered to do so.\n\t\t\tif (methodList)\n\t\t\t{\n\t\t\t\tstd::string method_name(callName.toStdString());\n\t\t\t\tconst EidosMethodSignature *method_signature = nullptr;\n\t\t\t\t\n\t\t\t\tfor (const auto &signature_iter : *methodList)\n\t\t\t\t\tif (signature_iter->call_name_.compare(method_name) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod_signature = signature_iter.get();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (method_signature)\n                    ColorizeCallSignature(method_signature, 11.0, lineCursor);\n\t\t\t\telse\n\t\t\t\t\tqDebug() << \"*** no method signature found for method name \" << callName;\n\t\t\t}\n\t\t\t\n            topicItemKey = classMethodString + \"\\u00A0\" + callName + \"()\";\n            topicItemCursor = new QTextCursor(lineCursor);\n        }\n        else if (isTopicPropertyLine)\n\t\t{\n            // This topic item is a method declaration\n            QString callName = match_topicPropertyRegex.captured(1);\n            QString readOnlyName = match_topicPropertyRegex.captured(2);\n\t\t\t\n            //qDebug() << \"topic property name: \" << callName << \", line: \" << line;\n            \n            // Check for a built-in property signature that matches and substitute it in.  Note that we accept a match from any property in any class\n\t\t\t// API as long as the signature matches; we do not rigorously check that the API within a given class matches between signature and doc.\n\t\t\t// This is mostly not a problem because it is quite rare for the same property name to be used with more than one signature.\n            if (propertyList)\n            {\n                std::string property_name(callName.toStdString());\n                bool found_match = false, found_mismatch = false;\n                QString oldSignatureString, newSignatureString;\n                \n                for (const auto &signature_iter : *propertyList)\n                    if (signature_iter->property_name_.compare(property_name) == 0)\n                    {\n                        const EidosPropertySignature *property_signature = signature_iter.get();\n                        \n                        oldSignatureString = lineCursor.selectedText();\n                        std::ostringstream ss;\n                        ss << *property_signature;\n                        newSignatureString = QString::fromStdString(ss.str());\n                        \n                        if (newSignatureString == oldSignatureString)\n                        {\n                            //qDebug() << \"signature match for method\" << callName;\n                            \n                            // Replace the signature line with the syntax-colored version\n                            ColorizePropertySignature(property_signature, 11.0, lineCursor);\n                            found_match = true;\n                            break;\n                        }\n                        else\n                        {\n                            // If we find a mismatched signature but no matching signature, that's probably an error in either the doc or\n                            // the signature, unless we find a match later on with a different signature for the same property name.\n                            found_mismatch = true;\n                        }\n                    }\n                \n                if (found_mismatch && !found_match)\n                    qDebug() << \"*** property signature mismatch:\\nold: \" << oldSignatureString << \"\\nnew: \" << newSignatureString;\n\t\t\t\telse if (!found_match)\n\t\t\t\t\tqDebug() << \"*** no property signature found for property name\" << callName;\n\t\t\t}\n\t\t\t\n\t\t\ttopicItemKey = callName + \"\\u00A0\" + readOnlyName;\n            topicItemCursor = new QTextCursor(lineCursor);\n        }\n        \n        lineStartIndex += (lineLength + 1);\t\t// +1 to jump over the newline\n    }\n}\n\nvoid QtSLiMHelpWindow::checkDocumentationOfFunctions(const std::vector<EidosFunctionSignature_CSP> *functions)\n{\n    for (const EidosFunctionSignature_CSP &functionSignature : *functions)\n\t{\n\t\tQString functionNameString = QString::fromStdString(functionSignature->call_name_);\n\t\t\n\t\tif (!functionNameString.startsWith(\"_\"))\n\t\t\tif (!findObjectForKeyEqualTo(functionNameString + \"()\", ui->topicOutlineView->invisibleRootItem()))\n\t\t\t\tqDebug() << \"*** no documentation found for function \" << functionNameString << \"()\";\n\t}\n}\n\nvoid QtSLiMHelpWindow::checkDocumentationOfClass(EidosClass *classObject)\n{\n    const EidosClass *superclassObject = classObject->Superclass();\n\t\n\t// We're hiding DictionaryRetained, so DictionaryRetained subclasses pretend their superclass is Dictionary\n\tif (superclassObject == gEidosDictionaryRetained_Class)\n\t\tsuperclassObject = gEidosDictionaryUnretained_Class;\n\t\n    const QString className = QString::fromStdString(classObject->ClassName());\n\tconst QString classKey = \"Class \" + className;\n\tQtSLiMHelpItem *classDocumentation = findObjectWithKeySuffix(classKey, ui->topicOutlineView->invisibleRootItem());\n    int classDocChildCount = classDocumentation ? classDocumentation->childCount() : 0;\n\t\n\tif (classDocumentation && (classDocumentation->doc_fragment == nullptr) && (classDocChildCount > 0))\n\t{\n\t\tQString propertiesKey = /*QString(\"1. \") +*/ className + QString(\" properties\");\n\t\tQString methodsKey = /*QString(\"2. \") +*/ className + QString(\" methods\");\n        QtSLiMHelpItem *classPropertyItem = findObjectForKeyEqualTo(propertiesKey, classDocumentation);\n        QtSLiMHelpItem *classMethodsItem = findObjectForKeyEqualTo(methodsKey, classDocumentation);\n        \n\t\tif ((classDocChildCount == 2) || (classDocChildCount == 3))    // 3 if there is a constructor function, which we don't presently check\n\t\t{\n\t\t\t// Check for complete documentation of all properties defined by the class\n\t\t\t{\n\t\t\t\tconst std::vector<EidosPropertySignature_CSP> *classProperties = classObject->Properties();\n                const std::vector<EidosPropertySignature_CSP> *superclassProperties = superclassObject ? superclassObject->Properties() : nullptr;\n\t\t\t\tQStringList docProperties;\n\t\t\t\t\n                if (classPropertyItem)\n                    for (int child_index = 0; child_index < classPropertyItem->childCount(); ++child_index)\n                        docProperties.push_back(classPropertyItem->child(child_index)->text(0));\n                \n\t\t\t\tfor (const EidosPropertySignature_CSP &propertySignature : *classProperties)\n\t\t\t\t{\n                    const std::string &&connector_string = propertySignature->PropertySymbol();\n                    const std::string &property_name_string = propertySignature->property_name_;\n                    QString property_string = QString::fromStdString(property_name_string) + QString(\"\\u00A0\") + QString::fromStdString(connector_string);\n                    int docIndex = docProperties.indexOf(property_string);\n                    \n                    if (docIndex != -1)\n                    {\n                        // If the property is defined in this class doc, consider it documented\n                        docProperties.removeAt(docIndex);\n                    }\n                    else\n                    {\n                        // If the property is not defined in this class doc, then that is an error unless it is a superclass property\n                        bool isSuperclassProperty = superclassProperties && (std::find(superclassProperties->begin(), superclassProperties->end(), propertySignature) != superclassProperties->end());\n\t\t\t\t\t\n                        if (!isSuperclassProperty)\n                            qDebug() << \"*** no documentation found for class \" << className << \" property \" << property_string;\n                    }\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (docProperties.size())\n\t\t\t\t\tqDebug() << \"*** excess documentation found for class \" << className << \" properties \" << docProperties;\n\t\t\t}\n\t\t\t\n\t\t\t// Check for complete documentation of all methods defined by the class\n\t\t\t{\n\t\t\t\tconst std::vector<EidosMethodSignature_CSP> *classMethods = classObject->Methods();\n\t\t\t\tconst std::vector<EidosMethodSignature_CSP> *superclassMethods = superclassObject ? superclassObject->Methods() : nullptr;\n\t\t\t\tQStringList docMethods;\n\t\t\t\t\n                if (classMethodsItem)\n                    for (int child_index = 0; child_index < classMethodsItem->childCount(); ++child_index)\n                        docMethods.push_back(classMethodsItem->child(child_index)->text(0));\n                \n\t\t\t\tfor (const EidosMethodSignature_CSP &methodSignature : *classMethods)\n\t\t\t\t{\n\t\t\t\t\tconst std::string &method_name_string = methodSignature->call_name_;\n\t\t\t\t\t\n\t\t\t\t\tif ((method_name_string.length() == 0) || (method_name_string[0] != '_'))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string &&prefix_string = methodSignature->CallPrefix();\n\t\t\t\t\t\tQString method_string = QString::fromStdString(prefix_string) + QString::fromStdString(method_name_string) + QString(\"()\");\n\t\t\t\t\t\tint docIndex = docMethods.indexOf(method_string);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (docIndex != -1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If the method is defined in this class doc, consider it documented\n\t\t\t\t\t\t\tdocMethods.removeAt(docIndex);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If the method is not defined in this class doc, then that is an error unless it is a superclass method\n\t\t\t\t\t\t\tbool isSuperclassMethod = superclassMethods && (std::find(superclassMethods->begin(), superclassMethods->end(), methodSignature) != superclassMethods->end());\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!isSuperclassMethod)\n\t\t\t\t\t\t\t\tqDebug() << \"*** no documentation found for class \" << className << \" method \" << method_string;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (docMethods.size())\n\t\t\t\t\tqDebug() << \"*** excess documentation found for class \" << className << \" methods \" << docMethods;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tqDebug() << \"*** documentation for class \" << className << \" in unexpected format\";\n\t\t}\n\t}\n\telse\n\t{\n\t\tqDebug() << \"*** no documentation found for class \" << className;\n\t}\n}\n\nvoid QtSLiMHelpWindow::addSuperclassItemForClass(EidosClass *classObject)\n{\n    const EidosClass *superclassObject = classObject->Superclass();\n\t\n\t// We're hiding DictionaryRetained, so DictionaryRetained subclasses pretend their superclass is Dictionary\n\tif (superclassObject == gEidosDictionaryRetained_Class)\n\t\tsuperclassObject = gEidosDictionaryUnretained_Class;\n\t\n    const QString className = QString::fromStdString(classObject->ClassName());\n\tconst QString classKey = \"Class \" + className;\n\tQtSLiMHelpItem *classDocumentation = findObjectWithKeySuffix(classKey, ui->topicOutlineView->invisibleRootItem());\n    int classDocChildCount = classDocumentation ? classDocumentation->childCount() : 0;\n\t\n\tif (classDocumentation && (classDocumentation->doc_fragment == nullptr) && (classDocChildCount > 0))\n\t{\n        QString superclassName = superclassObject ? QString::fromStdString(superclassObject->ClassName()) : QString(\"none\");\n        \n        bool inDarkMode = QtSLiMInDarkMode();\n        QtSLiMHelpItem *superclassItem = new QtSLiMHelpItem((QTreeWidgetItem *)nullptr);\n        \n        superclassItem->setText(0, QString(\"Superclass: \" + superclassName));\n        superclassItem->setFlags(Qt::ItemIsEnabled);\n        \n        if (superclassObject)\n        {\n            // Hyperlink appearance, with blue underlined text\n            superclassItem->setForeground(0, QBrush(inDarkMode ? QtSLiMColorWithHSV(0.65, 0.6, 1.0, 1.0) : QtSLiMColorWithHSV(0.65, 1.0, 0.8, 1.0)));\n            \n            QFont itemFont(superclassItem->font(0));\n            itemFont.setUnderline(true);\n            superclassItem->setFont(0, itemFont);\n        }\n        else\n        {\n            // Dimmed appearance\n            superclassItem->setForeground(0, QBrush(inDarkMode ? QtSLiMColorWithWhite(0.5, 1.0) : QtSLiMColorWithWhite(0.3, 1.0)));\n        }\n        \n        classDocumentation->insertChild(0, superclassItem);     // takes ownership\n\t}\n}\n\nvoid QtSLiMHelpWindow::outlineSelectionChanged(void)\n{\n    if (!doingProgrammaticSelection)\n    {\n        QList<QTreeWidgetItem *> &&selection = ui->topicOutlineView->selectedItems();\n        QPlainTextEdit *textedit = ui->descriptionTextEdit;\n        QTextDocument *textdoc = textedit->document();\n        bool firstItem = true;\n        \n        textedit->clear();\n        \n        QTextCursor insertion(textdoc);\n        insertion.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);\n        \n        QTextBlockFormat defaultBlockFormat;\n        QTextBlockFormat hrBlockFormat;\n        hrBlockFormat.setTopMargin(10.0);\n        hrBlockFormat.setBottomMargin(10.0);\n        hrBlockFormat.setAlignment(Qt::AlignHCenter);\n        \n        for (QTreeWidgetItem *selwidget : selection)\n        {\n            if (!firstItem)\n            {\n                insertion.insertBlock(hrBlockFormat);\n                // inserting an HR doesn't work properly, but the bug I filed got a useful response if I ever want to revisit this: https://bugreports.qt.io/browse/QTBUG-80473\n                //            insertion.insertHtml(\"<HR>\");\n                insertion.insertText(\"––––––––––––––––––––\");\n                insertion.insertBlock(defaultBlockFormat);\n            }\n            firstItem = false;\n            \n            QtSLiMHelpItem *helpItem = dynamic_cast<QtSLiMHelpItem *>(selwidget);\n            \n            if (helpItem && helpItem->doc_fragment)\n                insertion.insertFragment(*helpItem->doc_fragment);\n        }\n        \n        //qDebug() << textdoc->toHtml();\n    }\n}\n\nvoid QtSLiMHelpWindow::recursiveExpand(QTreeWidgetItem *item)\n{\n    // Expand pre-order; I don't think this matters, but it seems safer\n    if (!item->isExpanded())\n        ui->topicOutlineView->expandItem(item);\n    \n    for (int child_index = 0; child_index < item->childCount(); child_index++)\n        recursiveExpand(item->child(child_index));\n}\n\nvoid QtSLiMHelpWindow::recursiveCollapse(QTreeWidgetItem *item)\n{\n    // Collapse post-order; I don't think this matters, but it seems safer\n    for (int child_index = 0; child_index < item->childCount(); child_index++)\n        recursiveCollapse(item->child(child_index));\n    \n    if (item->isExpanded())\n        ui->topicOutlineView->collapseItem(item);\n}\n\nvoid QtSLiMHelpWindow::itemClicked(QTreeWidgetItem *item, int __attribute__((__unused__)) column)\n{\n    if ((item->childCount() == 0) && (item->childIndicatorPolicy() == QTreeWidgetItem::DontShowIndicatorWhenChildless))\n    {\n        // If the item has no children, and is not showing an indicator, it is a leaf and might be a hyperlink item\n        QString itemText = item->text(0);\n        \n        if (itemText.startsWith(\"Superclass: \"))\n        {\n            QString superclassName = itemText.right(itemText.length() - QString(\"Superclass: \").length());\n            \n            if (superclassName != \"none\")\n            {\n                QString sectionTitle = \"Class \" + superclassName;\n                \n                // Open disclosure triangles to show the section\n                std::vector<QTreeWidgetItem *> matchKeys;\n                std::vector<QTreeWidgetItem *> expandItems;\n                \n                QTreeWidgetItem *classDocumentation = findObjectWithKeySuffix(sectionTitle, ui->topicOutlineView->invisibleRootItem());\n                \n                while (classDocumentation)\n                {\n                    expandItems.emplace_back(classDocumentation);\n                    classDocumentation = classDocumentation->parent();\n                }\n                \n                if (expandItems.size())\n                    expandToShowItems(expandItems, matchKeys);\n                else\n                    qApp->beep();\n            }\n        }\n    }\n    else\n    {\n        // Otherwise, it has a disclosure triangle and needs to expand/collapse\n        bool optionPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier);\n        \n        doingProgrammaticCollapseExpand = true;\n        \n        if (optionPressed)\n        {\n            // recursively expand/collapse items below this item\n            if (item->isExpanded())\n                recursiveCollapse(item);\n            else\n                recursiveExpand(item);\n        }\n        else\n        {\n            // expand/collapse just this item\n            if (item->isExpanded())\n                ui->topicOutlineView->collapseItem(item);\n            else\n                ui->topicOutlineView->expandItem(item);\n        }\n        \n        doingProgrammaticCollapseExpand = false;\n    }\n}\n\nvoid QtSLiMHelpWindow::itemCollapsed(QTreeWidgetItem *item)\n{\n    // If the user has collapsed an item by clicking, we want to implement option-clicking on top of that\n    if (!doingProgrammaticCollapseExpand)\n    {\n        bool optionPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier);\n        \n        if (optionPressed)\n        {\n            doingProgrammaticCollapseExpand = true;\n            recursiveCollapse(item);\n            doingProgrammaticCollapseExpand = false;\n        }\n    }\n}\n\nvoid QtSLiMHelpWindow::itemExpanded(QTreeWidgetItem *item)\n{\n    // If the user has expanded an item by clicking, we want to implement option-clicking on top of that\n    if (!doingProgrammaticCollapseExpand)\n    {\n        bool optionPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier);\n        \n        if (optionPressed)\n        {\n            doingProgrammaticCollapseExpand = true;\n            recursiveExpand(item);\n            doingProgrammaticCollapseExpand = false;\n        }\n    }\n}\n\nQtSLiMHelpItem *QtSLiMHelpWindow::findObjectWithKeySuffix(const QString searchKeySuffix, QTreeWidgetItem *searchItem)\n{\n\tQtSLiMHelpItem *value = nullptr;\n    int childCount = searchItem->childCount();\n\t\n    for (int childIndex = 0; childIndex < childCount; ++childIndex)\n\t{\n        QTreeWidgetItem *child = searchItem->child(childIndex);\n        QtSLiMHelpItem *our_child = dynamic_cast<QtSLiMHelpItem *>(child);\n        \n        if (our_child)\n        {\n            QString childTitle = child->text(0);\n            \n            // Search by substring matching; we have to be careful to use this method to search only for unique keys\n            if (childTitle.endsWith(searchKeySuffix))\n                value = our_child;\n            else if (our_child->childCount())\n                value = findObjectWithKeySuffix(searchKeySuffix, our_child);\n            \n            if (value)\n                break;\n        }\n\t}\n\t\n\treturn value;\n}\n\nQtSLiMHelpItem *QtSLiMHelpWindow::findObjectForKeyEqualTo(const QString searchKey, QTreeWidgetItem *searchItem)\n{\n\tQtSLiMHelpItem *value = nullptr;\n\tint childCount = searchItem->childCount();\n    \n\tfor (int childIndex = 0; childIndex < childCount; ++childIndex)\n\t{\n        QTreeWidgetItem *child = searchItem->child(childIndex);\n        QtSLiMHelpItem *our_child = dynamic_cast<QtSLiMHelpItem *>(child);\n        \n        if (our_child)\n        {\n            QString childTitle = child->text(0);\n            \n            // Search using string equality; we have to be careful to use this method to search only for unique keys\n            if (childTitle == searchKey)\n                value = our_child;\n            else if (our_child->childCount())\n                value = findObjectForKeyEqualTo(searchKey, our_child);\n            \n            if (value)\n                break;\n        }\n\t}\n\t\n\treturn value;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHelpWindow.h",
    "content": "//\n//  QtSLiMHelpWindow.h\n//  SLiM\n//\n//  Created by Ben Haller on 11/19/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMHELPWINDOW_H\n#define QTSLIMHELPWINDOW_H\n\n#include <QWidget>\n#include <QTreeWidget>\n#include <QTreeWidgetItem>\n#include <QTextDocumentFragment>\n#include <QMap>\n#include <QStyledItemDelegate>\n\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\nclass QCloseEvent;\nclass QSplitter;\nclass EidosClass;\n\n\n// SLiMgui uses an NSDictionary-based design to hold the documentation tree data structure.  Here we\n// instead leverage the fact that QTreeWidgetItem already represents a tree structure, and simply\n// use it directly to represent the documentation tree.  We use a custom subclass so we can keep\n// associated doc, which is held as a QTextDocumentFragment; this is used only by leaves\n\nclass QtSLiMHelpItem : public QTreeWidgetItem\n{\n    // no Q_OBJECT; QTreeWidgetItem is not a QObject subclass!\n    \npublic:\n    QTextDocumentFragment *doc_fragment = nullptr;\n    bool is_top_level = false;\n    \n    explicit QtSLiMHelpItem(QTreeWidget *p_parent) : QTreeWidgetItem(p_parent) {}\n    explicit QtSLiMHelpItem(QTreeWidgetItem *p_parent) : QTreeWidgetItem(p_parent) {}\n    virtual ~QtSLiMHelpItem() override;\n    \n    virtual QVariant data(int column, int role) const override;\n};\n\n\n// This subclass of QStyledItemDelegate provides custom drawing for the outline view.\n\nclass QtSLiMHelpOutlineDelegate : public QStyledItemDelegate\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMHelpOutlineDelegate(QObject *p_parent = nullptr) : QStyledItemDelegate(p_parent) {}\n    virtual ~QtSLiMHelpOutlineDelegate(void) override;\n    \n    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;\n};\n\n\n// We keep a QMap of topics in the currently building hierarchy so we can find the right parent\n// for each new item.  This is a temporary data structure used only during the build of each section.\ntypedef QMap<QString, QtSLiMHelpItem *> QtSLiMTopicMap;\n\n\n// This class provides a singleton help window\n\nnamespace Ui {\nclass QtSLiMHelpWindow;\n}\n\nclass QtSLiMHelpWindow : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    static QtSLiMHelpWindow &instance(void);\n    \n    void enterSearchForString(QString searchString, bool titlesOnly = true);\n    \nprotected slots:\n    void applicationPaletteChanged(void);\n    \nprivate:\n    // singleton pattern\n    explicit QtSLiMHelpWindow(QWidget *p_parent = nullptr);\n    QtSLiMHelpWindow(void) = delete;\n    virtual ~QtSLiMHelpWindow(void) override;\n    QtSLiMHelpWindow(const QtSLiMHelpWindow&) = delete;\n    QtSLiMHelpWindow& operator=(const QtSLiMHelpWindow&) = delete;\n    \n    // Add topics and items drawn from a specially formatted HTML file, under a designated top-level heading.\n    // The signatures found for functions, methods, and prototypes will be checked against the supplied lists,\n    // if they are not NULL, and if matches are found, colorized versions will be substituted.\n    void addTopicsFromRTFFile(const QString &htmlFile,\n                              const QString &topLevelHeading,\n                              const std::vector<EidosFunctionSignature_CSP> *functionList,\n                              const std::vector<EidosMethodSignature_CSP> *methodList,\n                              const std::vector<EidosPropertySignature_CSP> *propertyList);\n    \n    // Searching\n    bool findItemsMatchingSearchString(QTreeWidgetItem *root, const QString searchString, bool titlesOnly, std::vector<QTreeWidgetItem *> &matchKeys, std::vector<QTreeWidgetItem *> &expandItems);\n    void expandToShowItems(const std::vector<QTreeWidgetItem *> &expandItems, const std::vector<QTreeWidgetItem *> &matchKeys);\n    void searchFieldChanged(void);\n    void searchScopeToggled(void);\n    \n    // Smart expand/contract, with the option key making it apply to all children as well\n    void recursiveExpand(QTreeWidgetItem *item);\n    void recursiveCollapse(QTreeWidgetItem *item);\n    void itemClicked(QTreeWidgetItem *item, int column);\n    void itemCollapsed(QTreeWidgetItem *item);\n    void itemExpanded(QTreeWidgetItem *item);\n    \n    // Check for complete documentation\n    QtSLiMHelpItem *findObjectWithKeySuffix(const QString searchKeySuffix, QTreeWidgetItem *searchItem);\n    QtSLiMHelpItem *findObjectForKeyEqualTo(const QString searchKey, QTreeWidgetItem *searchItem);\n    void checkDocumentationOfFunctions(const std::vector<EidosFunctionSignature_CSP> *functions);\n    void checkDocumentationOfClass(EidosClass *classObject);\n    void addSuperclassItemForClass(EidosClass *classObject);\n    \n    // responding to events\n    virtual void closeEvent(QCloseEvent *e) override;\n    void outlineSelectionChanged(void);\n    \n    // Internals\n    QTreeWidgetItem *parentItemForSection(const QString &sectionString, QtSLiMTopicMap &topics, QtSLiMHelpItem *topItem);\n    QtSLiMHelpItem *createItemForSection(const QString &sectionString, QString title, QtSLiMTopicMap &topics, QtSLiMHelpItem *topItem);\n    \nprivate:\n    int searchType = 0;\t\t// 0 == Title, 1 == Content; equal to the tags on the search type menu items\n    bool doingProgrammaticCollapseExpand = false;   // used to distinguish user actions from programmatic ones\n    bool doingProgrammaticSelection = false;        // used to distinguish user actions from programmatic ones\n    \n    void interpolateSplitters(void);\n    QSplitter *splitter = nullptr;\n    \n    Ui::QtSLiMHelpWindow *ui;\n};\n\n\n#endif // QTSLIMHELPWINDOW_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMHelpWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMHelpWindow</class>\n <widget class=\"QWidget\" name=\"QtSLiMHelpWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>700</width>\n    <height>400</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Scripting Help</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>4</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>4</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>4</number>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QPushButton\" name=\"searchScopeButton\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>60</width>\n         <height>0</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>60</width>\n         <height>16777215</height>\n        </size>\n       </property>\n       <property name=\"font\">\n        <font>\n         <pointsize>9</pointsize>\n        </font>\n       </property>\n       <property name=\"focusPolicy\">\n        <enum>Qt::NoFocus</enum>\n       </property>\n       <property name=\"styleSheet\">\n        <string notr=\"true\">QPushButton {\nborder: 1px solid #888;\nborder-radius: 20px;\nborder-style: outset;\nmargin: 0px;\npadding: 2px;\nbackground: rgb(245, 245, 245);\n}\nQPushButton:pressed {\nbackground: rgb(195, 195, 195);\n}</string>\n       </property>\n       <property name=\"text\">\n        <string>🔍  headers</string>\n       </property>\n       <property name=\"autoDefault\">\n        <bool>false</bool>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QLineEdit\" name=\"searchField\"/>\n     </item>\n    </layout>\n   </item>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n     <property name=\"spacing\">\n      <number>4</number>\n     </property>\n     <item>\n      <widget class=\"QTreeWidget\" name=\"topicOutlineView\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Expanding\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>280</width>\n         <height>200</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>280</width>\n         <height>16777215</height>\n        </size>\n       </property>\n       <property name=\"font\">\n        <font>\n         <pointsize>11</pointsize>\n        </font>\n       </property>\n       <property name=\"focusPolicy\">\n        <enum>Qt::ClickFocus</enum>\n       </property>\n       <property name=\"editTriggers\">\n        <set>QAbstractItemView::NoEditTriggers</set>\n       </property>\n       <property name=\"selectionMode\">\n        <enum>QAbstractItemView::ExtendedSelection</enum>\n       </property>\n       <property name=\"indentation\">\n        <number>13</number>\n       </property>\n       <property name=\"headerHidden\">\n        <bool>true</bool>\n       </property>\n       <property name=\"expandsOnDoubleClick\">\n        <bool>false</bool>\n       </property>\n       <column>\n        <property name=\"text\">\n         <string notr=\"true\">1</string>\n        </property>\n       </column>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QPlainTextEdit\" name=\"descriptionTextEdit\">\n       <property name=\"minimumSize\">\n        <size>\n         <width>250</width>\n         <height>0</height>\n        </size>\n       </property>\n       <property name=\"focusPolicy\">\n        <enum>Qt::ClickFocus</enum>\n       </property>\n       <property name=\"undoRedoEnabled\">\n        <bool>false</bool>\n       </property>\n       <property name=\"readOnly\">\n        <bool>true</bool>\n       </property>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMIndividualsWidget.cpp",
    "content": "//\n//  QtSLiMIndividualsWidget.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMIndividualsWidget.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMPreferences.h\"\n\n#include <QMenu>\n#include <QAction>\n#include <QActionGroup>\n#include <QContextMenuEvent>\n#include <QtGlobal>\n#include <QDebug>\n\n#include <map>\n#include <utility>\n#include <string>\n#include <vector>\n\n\nQtSLiMIndividualsWidget::QtSLiMIndividualsWidget(QWidget *p_parent, Qt::WindowFlags f)\n#ifndef SLIM_NO_OPENGL\n    : QOpenGLWidget(p_parent, f)\n#else\n    : QWidget(p_parent, f)\n#endif\n{\n    preferredDisplayMode = PopulationViewDisplayMode::kDisplaySpatialSeparate;\t// prefer spatial display when possible, fall back to individuals\n    \n    // We support both OpenGL and non-OpenGL display, because some platforms seem\n    // to have problems with OpenGL (https://github.com/MesserLab/SLiM/issues/462)\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::useOpenGLPrefChanged, this, [this]() { update(); });\n}\n\nQtSLiMIndividualsWidget::~QtSLiMIndividualsWidget()\n{\n}\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMIndividualsWidget::initializeGL()\n{\n    initializeOpenGLFunctions();\n    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);\n}\n\nvoid QtSLiMIndividualsWidget::resizeGL(int w, int h)\n{\n    glViewport(0, 0, w, h);\n    \n\t// Update the projection\n\tglMatrixMode(GL_PROJECTION);\n    glLoadIdentity();\n\tglMatrixMode(GL_MODELVIEW);\n}\n#endif\n\n#ifndef SLIM_NO_OPENGL\nvoid QtSLiMIndividualsWidget::paintGL()\n#else\nvoid QtSLiMIndividualsWidget::paintEvent(QPaintEvent * /* p_paint_event */)\n#endif\n{\n    QPainter painter(this);\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    //painter.eraseRect(rect());      // erase to background color, which is not guaranteed\n    painter.fillRect(rect(), Qt::red);\n    \n    //\n\t//\tNOTE this code is parallel to code in tileSubpopulations() and both should be maintained!\n\t//\n\t\n\tQRect bounds = rect();\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n\tstd::vector<Subpopulation*> selectedSubpopulations = controller->selectedSubpopulations();\n\tint selectedSubpopCount = static_cast<int>(selectedSubpopulations.size());\n    bool displayingUnified = ((preferredDisplayMode == PopulationViewDisplayMode::kDisplaySpatialUnified) && canDisplayUnified(selectedSubpopulations));\n\t\n    // In SLiMgui this has to be called in advance, to swap in/out the error view, but here we\n    // can simply call it before each update to pre-plan, making for a simpler design\n    tileSubpopulations(selectedSubpopulations);\n    \n\tif ((selectedSubpopCount == 0) || !canDisplayAllIndividuals)\n\t{\n\t\t// clear to a shade of gray\n        if (inDarkMode)\n            painter.fillRect(QRect(0, 0, bounds.width(), bounds.height()), QtSLiMColorWithWhite(0.118, 1.0));\n        else\n            painter.fillRect(QRect(0, 0, bounds.width(), bounds.height()), QtSLiMColorWithWhite(0.9, 1.0));\n\t\t\n        // display a message if we have too many subpops to show\n        if (!canDisplayAllIndividuals)\n        {\n            painter.setPen(Qt::darkGray);\n            painter.drawText(bounds, Qt::AlignCenter, \"too many subpops\\nor individuals\\nto display – try\\nresizing to make\\nmore space\");\n        }\n        \n\t\t// Frame our view\n\t\tqtDrawViewFrameInBounds(bounds, painter);\n\t}\n\telse\n\t{\n        // Clear to background gray; we always do this now, because the tile title bars are on the window background\n\t\tpainter.fillRect(rect(), palette().color(QPalette::Window));\n\t\t\n        // Show title bars above each subpop tile\n        static QFont *titleFont = nullptr;\n        static QIcon actionIcon_LIGHT, actionIcon_DARK;\n        \n        if (!titleFont)\n        {\n            titleFont = new QFont();\n            \n#ifdef __linux__\n            // font sizes are calibrated for macOS; on Linux they need to be a little smaller\n            titleFont->setPointSize(titleFont->pointSize() * 0.75);\n#endif\n            \n            actionIcon_LIGHT.addFile(\":/buttons/action.png\", QSize(), QIcon::Normal, QIcon::Off);\n            actionIcon_LIGHT.addFile(\":/buttons/action_H.png\", QSize(), QIcon::Normal, QIcon::On);\n            actionIcon_DARK.addFile(\":/buttons_DARK/action_DARK.png\", QSize(), QIcon::Normal, QIcon::Off);\n            actionIcon_DARK.addFile(\":/buttons_DARK/action_H_DARK.png\", QSize(), QIcon::Normal, QIcon::On);\n        }\n        \n        QIcon *actionIcon = (inDarkMode ? &actionIcon_DARK : &actionIcon_LIGHT);\n        \n        painter.save();\n        painter.setRenderHint(QPainter::SmoothPixmapTransform);\n        painter.setPen(inDarkMode ? Qt::white : Qt::black);\n        painter.setFont(*titleFont);\n        \n        for (Subpopulation *subpop : selectedSubpopulations)\n\t\t{\n\t\t\tauto tileIter = subpopTiles.find(subpop->subpopulation_id_);\n\t\t\t\n\t\t\tif (tileIter != subpopTiles.end())\n\t\t\t{\n\t\t\t\tQRect tileBounds = tileIter->second;\n\t\t\t\tQRect buttonBounds(tileBounds.left(), tileBounds.top(), 20, 20);\n                \n                if (subpop->subpopulation_id_ == actionButtonHighlightSubpopID_)\n                    actionIcon->paint(&painter, buttonBounds, Qt::AlignCenter, QIcon::Normal, QIcon::On);\n                else\n                    actionIcon->paint(&painter, buttonBounds, Qt::AlignCenter, QIcon::Normal, QIcon::Off);\n                \n                int titleX = tileBounds.left() + 23;\n                int titleY = tileBounds.top() + 17;\n                int textFlags = (Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignBottom | Qt::AlignLeft);\n                QString title;\n                \n                if (displayingUnified)\n                {\n                    title = \"Unified (all subpopulations)\";\n                }\n                else\n                {\n                    title = QString(\"p%1\").arg(subpop->subpopulation_id_);\n                    \n                    if (controller->community->all_species_.size() > 1)\n                        title.append(\" \").append(QString::fromStdString(subpop->species_.avatar_));\n                }\n                \n                painter.drawText(QRect(titleX, titleY, 0, 0), textFlags, title);\n            }\n            \n            if (displayingUnified)\n                break;\n        }\n        \n        painter.restore();\n        \n        // find a consensus square size for non-spatial display, for consistency\n        int squareSize = 20;\n        \n        for (Subpopulation *subpop : selectedSubpopulations)\n        {\n            PopulationViewDisplayMode displayMode = (displayingUnified ? PopulationViewDisplayMode::kDisplaySpatialUnified : displayModeForSubpopulation(subpop));\n            \n            if (displayMode == PopulationViewDisplayMode::kDisplayIndividuals)\n            {\n                auto tileIter = subpopTiles.find(subpop->subpopulation_id_);\n                \n                if (tileIter != subpopTiles.end())\n                {\n                    QRect tileBounds = tileIter->second;\n                    \n                    // remove a margin at the top for the title bar\n                    tileBounds.setTop(tileBounds.top() + 22);\n                    \n                    int thisSquareSize = squareSizeForSubpopulationInArea(subpop, tileBounds);\n                    \n                    if ((thisSquareSize < squareSize) && (thisSquareSize >= 1))\n                        squareSize = thisSquareSize;\n                }\n            }\n        }\n        \n        // And now draw the tiles themselves\n        bool useGL = QtSLiMPreferencesNotifier::instance().useOpenGLPref();\n        \n        if (useGL)\n            painter.beginNativePainting();\n        \n        bool clearBackground = true;    // used for display mode 2 to prevent repeated clearing\n        \n\t\tfor (Subpopulation *subpop : selectedSubpopulations)\n\t\t{\n            Species *displaySpecies = &subpop->species_;\n            PopulationViewDisplayMode displayMode = (displayingUnified ? PopulationViewDisplayMode::kDisplaySpatialUnified : displayModeForSubpopulation(subpop));\n            \n\t\t\tauto tileIter = subpopTiles.find(subpop->subpopulation_id_);\n\t\t\t\n\t\t\tif (tileIter != subpopTiles.end())\n\t\t\t{\n\t\t\t\tQRect tileBounds = tileIter->second;\n                \n                // remove a margin at the top for the title bar\n                tileBounds.setTop(tileBounds.top() + 22);\n\t\t\t\t\n                if ((displayMode == PopulationViewDisplayMode::kDisplaySpatialSeparate) || (displayMode == PopulationViewDisplayMode::kDisplaySpatialUnified))\n\t\t\t\t{\n                    QRect spatialDisplayBounds = spatialDisplayBoundsForSubpopulation(subpop, tileBounds);\n                    QRect frameBounds = spatialDisplayBounds.adjusted(-1, -1, 1, 1);\n                    \n                    if (clearBackground)\n                    {\n                        if (frameBounds != tileBounds)\n                        {\n                            // If we have inset the tileBounds because of aspect ratio considerations\n                            // in spatialDisplayBoundsForSubpopulation() (which only happens in 2D),\n                            // clear to a shade of gray and frame the overall tileBounds\n#ifndef SLIM_NO_OPENGL\n                            if (useGL)\n                            {\n                                glColor3f(0.9f, 0.9f, 0.9f);\n                                glRecti(tileBounds.left(), tileBounds.top(), (tileBounds.left() + tileBounds.width()), (tileBounds.top() + tileBounds.height()));\n                                glDrawViewFrameInBounds(tileBounds);\n                            }\n                            else\n#endif\n                            {\n                                painter.fillRect(tileBounds, QtSLiMColorWithWhite(0.9, 1.0));\n                                qtDrawViewFrameInBounds(tileBounds, painter);\n                            }\n                        }\n                        \n#ifndef SLIM_NO_OPENGL\n                        if (useGL)\n                            glDrawSpatialBackgroundInBoundsForSubpopulation(spatialDisplayBounds, subpop, displaySpecies->spatial_dimensionality_);\n                        else\n#endif\n                            qtDrawSpatialBackgroundInBoundsForSubpopulation(spatialDisplayBounds, subpop, displaySpecies->spatial_dimensionality_, painter);\n                    }\n                    \n                    float forceRGB[4];\n                    float *forceColor = nullptr;\n                    \n                    if ((displayMode == PopulationViewDisplayMode::kDisplaySpatialUnified) && (controller->focalSpeciesName.compare(\"all\") == 0))\n                    {\n                        controller->colorForSpecies(displaySpecies, forceRGB + 0, forceRGB + 1, forceRGB + 2,forceRGB + 3);\n                        forceColor = forceRGB;\n                    }\n                    \n#ifndef SLIM_NO_OPENGL\n                    if (useGL)\n                    {\n                        glDrawSpatialIndividualsFromSubpopulationInArea(subpop, spatialDisplayBounds, displaySpecies->spatial_dimensionality_, forceColor);\n                        glDrawViewFrameInBounds(frameBounds); // framed more than once in displayMode 2, which is OK\n                    }\n                    else\n#endif\n                    {\n                        qtDrawSpatialIndividualsFromSubpopulationInArea(subpop, spatialDisplayBounds, displaySpecies->spatial_dimensionality_, forceColor, painter);\n                        qtDrawViewFrameInBounds(frameBounds, painter); // framed more than once in displayMode 2, which is OK\n                    }\n                    \n                    if (displayMode == 2)\n                        clearBackground = false;\n\t\t\t\t}\n\t\t\t\telse\t// displayMode == PopulationViewDisplayMode::kDisplayIndividuals\n\t\t\t\t{\n                    auto backgroundIter = subviewSettings.find(subpop->subpopulation_id_);\n                    PopulationViewSettings background;\n                    \n                    chooseDefaultBackgroundSettingsForSubpopulation(&background, nullptr, subpop);\n                    \n                    if ((backgroundIter != subviewSettings.end()) && (backgroundIter->second.backgroundType <= 2))\n                        background = backgroundIter->second;\n                    \n                    int backgroundColor = background.backgroundType;\n                    float bgGray = 0.0;\n                    \n                    if (backgroundColor == 0)\n                        bgGray = 0.0;\n                    else if (backgroundColor == 1)\n                        bgGray = 0.3f;\n                    else if (backgroundColor == 2)\n                        bgGray = 1.0;\n                        \n#ifndef SLIM_NO_OPENGL\n                    if (useGL)\n                    {\n                        glColor3f(bgGray, bgGray, bgGray);\n                        glRecti(tileBounds.left(), tileBounds.top(), (tileBounds.left() + tileBounds.width()), (tileBounds.top() + tileBounds.height()));\n                        \n                        glDrawViewFrameInBounds(tileBounds);\n                        glDrawIndividualsFromSubpopulationInArea(subpop, tileBounds, squareSize);\n                    }\n                    else\n#endif\n                    {\n                        painter.fillRect(tileBounds, QtSLiMColorWithWhite(bgGray, 1.0));\n                        \n                        qtDrawViewFrameInBounds(tileBounds, painter);\n                        qtDrawIndividualsFromSubpopulationInArea(subpop, tileBounds, squareSize, painter);\n                    }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n        \n        if (useGL)\n            painter.endNativePainting();\n\t}\n}\n\nbool QtSLiMIndividualsWidget::canDisplayUnified(std::vector<Subpopulation*> &selectedSubpopulations)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    Community *community = controller->community;\n    int selectedSubpopCount = static_cast<int>(selectedSubpopulations.size());\n    \n    if (community->simulation_valid_ && (community->Tick() >= 1))\n\t{\n        if (selectedSubpopCount <= 1)\n            return false;                // unified display requires more than one subpop\n        \n        // we need all the subpops to have the same spatial bounds and dimensionality, so their coordinate systems match up\n        // we presently allow periodicity to not match; not sure about that one way or the other\n        double x0 = 0, x1 = 0, y0 = 0, y1 = 0, z0 = 0, z1 = 0;  // suppress unused warnings\n        int dimensionality = 0;\n        bool first = true;\n        \n        for (Subpopulation *subpop : selectedSubpopulations)\n        {\n            Species *subpop_species = &subpop->species_;\n            \n            if (subpop_species->spatial_dimensionality_ == 0)\n                return false;\n            \n            if (first)\n            {\n                x0 = subpop->bounds_x0_;    x1 = subpop->bounds_x1_;\n                y0 = subpop->bounds_y0_;    y1 = subpop->bounds_y1_;\n                z0 = subpop->bounds_z0_;    z1 = subpop->bounds_z1_;\n                dimensionality = subpop_species->spatial_dimensionality_;\n                first = false;\n            }\n            else\n            {\n                if ((x0 != subpop->bounds_x0_) || (x1 != subpop->bounds_x1_) ||\n                        (y0 != subpop->bounds_y0_) || (y1 != subpop->bounds_y1_) ||\n                        (z0 != subpop->bounds_z0_) || (z1 != subpop->bounds_z1_) ||\n                        (dimensionality != subpop_species->spatial_dimensionality_))\n                    return false;\n            }\n        }\n        \n        return true;\n    }\n    \n    return true;    // allow unified to be chosen as long as we have no information to the contrary\n}\n\nPopulationViewDisplayMode QtSLiMIndividualsWidget::displayModeForSubpopulation(Subpopulation *subpopulation)\n{\n    // the decision regarding unified display is made external to this method, so we don't worry about it here\n    // We just need to choose between individual versus spatial display\n    if (preferredDisplayMode == PopulationViewDisplayMode::kDisplayIndividuals)\n        return PopulationViewDisplayMode::kDisplayIndividuals;\n    \n    if (subpopulation->species_.spatial_dimensionality_ == 0)\n        return PopulationViewDisplayMode::kDisplayIndividuals;\n    \n    return PopulationViewDisplayMode::kDisplaySpatialSeparate;\n}\n\nvoid QtSLiMIndividualsWidget::tileSubpopulations(std::vector<Subpopulation*> &selectedSubpopulations)\n{\n\t//\n\t//\tNOTE this code is parallel to code in paintGL() and both should be maintained!\n\t//\n\t\n\t// We will decide upon new tiles for our subpopulations here, so start out empty\n\tsubpopTiles.clear();\n\t\n    QRect bounds = rect();\n    int selectedSubpopCount = static_cast<int>(selectedSubpopulations.size());\n    bool displayingUnified = ((preferredDisplayMode == PopulationViewDisplayMode::kDisplaySpatialUnified) && canDisplayUnified(selectedSubpopulations));\n    \n\tif (selectedSubpopCount == 0)\n\t{\n\t\tcanDisplayAllIndividuals = true;\n\t}\n    else if (displayingUnified)\n\t{\n        // set all tiles to be the full bounds for overlay mode\n        for (int subpopIndex = 0; subpopIndex < selectedSubpopCount; subpopIndex++)\n        {\n            Subpopulation *subpop = selectedSubpopulations[static_cast<size_t>(subpopIndex)];\n            \n            subpopTiles.emplace(subpop->subpopulation_id_, bounds);\n        }\n        canDisplayAllIndividuals = true;\n\t}\n    else if (selectedSubpopCount == 1)\n\t{\n        Subpopulation *selectedSubpop = selectedSubpopulations[0];\n        PopulationViewDisplayMode displayMode = displayModeForSubpopulation(selectedSubpop);\n        \n        subpopTiles.emplace(selectedSubpop->subpopulation_id_, bounds);\n        \n        if (displayMode == PopulationViewDisplayMode::kDisplaySpatialSeparate)\n        {\n            canDisplayAllIndividuals = true;\n        }\n        else\n        {\n            bounds.setTop(bounds.top() + 22);     // take out title bar space\n            \n            canDisplayAllIndividuals = canDisplayIndividualsFromSubpopulationInArea(selectedSubpop, bounds);\n        }\n    }\n    else // not unified, more than one subpop\n\t{\n\t\t// adaptively finds the layout that maximizes the pixel area covered; fails if no layout is satisfactory\n        QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n        int minBoxWidth = ((controller->community->all_species_.size() > 1) ? 70 : 50);     // room for avatars\n\t\tint64_t bestTotalExtent = 0;\n\t\t\n        canDisplayAllIndividuals = false;\n        \n\t\tfor (int rowCount = 1; rowCount <= selectedSubpopCount; ++rowCount)\n\t\t{\n\t\t\tint columnCount = static_cast<int>(ceil(selectedSubpopCount / static_cast<double>(rowCount)));\n\t\t\tint interBoxSpace = 5;\n\t\t\tint totalInterboxHeight = interBoxSpace * (rowCount - 1);\n\t\t\tint totalInterboxWidth = interBoxSpace * (columnCount - 1);\n\t\t\tdouble boxWidth = (bounds.width() - totalInterboxWidth) / static_cast<double>(columnCount);\n\t\t\tdouble boxHeight = (bounds.height() - totalInterboxHeight) / static_cast<double>(rowCount);\n\t\t\tstd::map<slim_objectid_t, QRect> candidateTiles;\n\t\t\tint64_t totalExtent = 0;\n            \n            // Round the box width down, for consistency, and calculate an offset to center the tiles\n            // So the visual width of the individuals view is quantized in such a way as to evenly subdivide\n            // We don't do this with the height since the effect of height variation is less visible, and\n            // having the visual height of the view not match the neighboring views would look weird\n            boxWidth = floor(boxWidth);\n            \n            int leftOffset = floor(bounds.width() - (boxWidth * columnCount + totalInterboxWidth)) / 2;\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < selectedSubpopCount; subpopIndex++)\n\t\t\t{\n\t\t\t\tint columnIndex = subpopIndex % columnCount;\n\t\t\t\tint rowIndex = subpopIndex / columnCount;\n\t\t\t\tint boxLeft = qRound(bounds.x() + leftOffset + columnIndex * (interBoxSpace + boxWidth));\n\t\t\t\tint boxRight = qRound(bounds.x() + leftOffset + columnIndex * (interBoxSpace + boxWidth) + boxWidth);\n\t\t\t\tint boxTop = qRound(bounds.y() + rowIndex * (interBoxSpace + boxHeight));\n\t\t\t\tint boxBottom = qRound(bounds.y() + rowIndex * (interBoxSpace + boxHeight) + boxHeight);\n\t\t\t\tQRect boxBounds(boxLeft, boxTop, boxRight - boxLeft, boxBottom - boxTop);\n\t\t\t\tSubpopulation *subpop = selectedSubpopulations[static_cast<size_t>(subpopIndex)];\n                PopulationViewDisplayMode displayMode = displayModeForSubpopulation(subpop);\n                \n                // Too narrow or short a box size (figuring in 22 pixels for the title bar) is not allowed\n                if ((boxWidth < minBoxWidth) || (boxHeight < ((displayMode == PopulationViewDisplayMode::kDisplaySpatialSeparate) ? 72 : 42)))\n                    goto layoutRejected;\n\t\t\t\t\n                //qDebug() << \"boxWidth ==\" << boxWidth << \"for rowCount ==\" << rowCount;\n                \n\t\t\t\tcandidateTiles.emplace(subpop->subpopulation_id_, boxBounds);\n\t\t\t\t\n\t\t\t\t// find out what pixel area actually gets used by this box, and use that to choose the optimal layout\n                boxBounds.setTop(boxBounds.top() + 22);     // take out title bar space\n                \n                if (displayMode == PopulationViewDisplayMode::kDisplaySpatialSeparate)\n                {\n                    // for spatial display, squeeze to the spatial aspect ratio\n                    boxBounds = spatialDisplayBoundsForSubpopulation(subpop, boxBounds);\n                }\n                else\n                {\n                    // for non-spatial display, check that the individuals will fit in the allotted area\n                    if (!canDisplayIndividualsFromSubpopulationInArea(subpop, boxBounds))\n                    {\n                        totalExtent = 0;\n                        break;\n                    }\n                }\n                \n\t\t\t\tint64_t extent = static_cast<int64_t>(boxBounds.width()) * static_cast<int64_t>(boxBounds.height());\n\t\t\t\t\n\t\t\t\ttotalExtent += extent;\n\t\t\t}\n\t\t\t\n\t\t\tif (totalExtent > bestTotalExtent)\n\t\t\t{\n\t\t\t\tbestTotalExtent = totalExtent;\n\t\t\t\tstd::swap(subpopTiles, candidateTiles);\n                canDisplayAllIndividuals = true;\n\t\t\t}\nlayoutRejected:\n            ;\n\t\t}\n\t}\n}\n\nbool QtSLiMIndividualsWidget::canDisplayIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds)\n{\n    //\n\t//\tNOTE this code is parallel to the code in drawIndividualsFromSubpopulation:inArea: and should be maintained in parallel\n\t//\n\t\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tint squareSize, viewColumns = 0, viewRows = 0;\n\t\n\t// first figure out the biggest square size that will allow us to display the whole subpopulation\n\tfor (squareSize = 20; squareSize > 1; --squareSize)\n\t{\n\t\tviewColumns = static_cast<int>(floor((bounds.width() - 3) / squareSize));\n\t\tviewRows = static_cast<int>(floor((bounds.height() - 3) / squareSize));\n\t\t\n\t\tif (viewColumns * viewRows > subpopSize)\n\t\t{\n\t\t\t// If we have an empty row at the bottom, then break for sure; this allows us to look nice and symmetrical\n\t\t\tif ((subpopSize - 1) / viewColumns < viewRows - 1)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Otherwise, break only if we are getting uncomfortably small; otherwise, let's drop down one square size to allow symmetry\n\t\t\tif (squareSize <= 5)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn (squareSize > 1);\n}\n\nQRect QtSLiMIndividualsWidget::spatialDisplayBoundsForSubpopulation(Subpopulation *subpop, QRect tileBounds)\n{\n\t// Determine a subframe for drawing spatial information inside.  The subframe we use is the maximal subframe\n\t// with integer boundaries that preserves, as closely as possible, the aspect ratio of the subpop's bounds.\n    // If sim->spatial_dimensionality_ is 1, there are no aspect ratio considerations so we just inset.\n\tQRect spatialDisplayBounds = tileBounds.adjusted(1, 1, -1, -1);\n    \n    if (subpop->species_.spatial_dimensionality_ > 1)\n    {\n        double displayAspect = spatialDisplayBounds.width() / static_cast<double>(spatialDisplayBounds.height());\n        double bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n        double bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n        double bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n        double subpopAspect = bounds_x_size / bounds_y_size;\n        \n        if (subpopAspect > displayAspect)\n        {\n            // The display bounds will need to shrink vertically to match the subpop\n            int idealSize = qRound(spatialDisplayBounds.width() / subpopAspect);\n            int roundedOffset = qRound((spatialDisplayBounds.height() - idealSize) / 2.0);\n            \n            spatialDisplayBounds.setY(spatialDisplayBounds.y() + roundedOffset);\n            spatialDisplayBounds.setHeight(idealSize);\n        }\n        else if (subpopAspect < displayAspect)\n        {\n            // The display bounds will need to shrink horizontally to match the subpop\n            int idealSize = qRound(spatialDisplayBounds.height() * subpopAspect);\n            int roundedOffset = qRound((spatialDisplayBounds.width() - idealSize) / 2.0);\n            \n            spatialDisplayBounds.setX(spatialDisplayBounds.x() + roundedOffset);\n            spatialDisplayBounds.setWidth(idealSize);\n        }\n    }\n    \n\treturn spatialDisplayBounds;\n}\n\nint QtSLiMIndividualsWidget::squareSizeForSubpopulationInArea(Subpopulation *subpop, QRect bounds)\n{\n    slim_popsize_t subpopSize = subpop->parent_subpop_size_;\n    int squareSize, viewColumns = 0, viewRows = 0;\n    \n    // first figure out the biggest square size that will allow us to display the whole subpopulation\n    for (squareSize = 20; squareSize > 1; --squareSize)\n    {\n        viewColumns = static_cast<int>(floor((bounds.width() - 3) / squareSize));\n        viewRows = static_cast<int>(floor((bounds.height() - 3) / squareSize));\n        \n        if (viewColumns * viewRows > subpopSize)\n        {\n            // If we have an empty row at the bottom, then break for sure; this allows us to look nice and symmetrical\n            if ((subpopSize - 1) / viewColumns < viewRows - 1)\n                break;\n            \n            // Otherwise, break only if we are getting uncomfortably small; otherwise, let's drop down one square size to allow symmetry\n            if (squareSize <= 5)\n                break;\n        }\n    }\n    \n    return squareSize;\n}\n\nvoid QtSLiMIndividualsWidget::cacheDisplayBufferForMapForSubpopulation(SpatialMap *background_map, Subpopulation *subpop, bool flipped)\n{\n\t// Cache a display buffer for the given background map.  This method should be called only in the 2D \"xy\"\n\t// case; in the 1D case we can't know the maximum width ahead of time, so we just draw rects without caching,\n\t// and in the 3D \"xyz\" case we don't know which z-slice to use so we can't display the spatial map.\n\t// The window might be too narrow to display a full-size map right now, but we want to premake a full-size map.\n\t// The sizing logic here is taken from drawRect:, assuming that we are not constrained in width.\n\t\n\t// By the way, it may occur to the reader to wonder why we keep the buffer as uint8_t values, given that we\n\t// convert to and from uint_8 for the display code that uses float RGB components.  My rationale is that\n\t// this drastically cuts the amount of memory that has to be accessed, and that the display code, in particular,\n\t// is probably memory-bound since most of the work is done in the GPU.  I haven't done any speed tests to\n\t// confirm that hunch, though.  In any case, it's plenty fast and I don't see significant display artifacts.\n\t\n\tQRect full_bounds = rect().adjusted(1, 1, -1, -1);\n\tint max_height = full_bounds.height();\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\tdouble subpopAspect = bounds_x_size / bounds_y_size;\n\tint max_width = qRound(max_height * subpopAspect);\n\t\n\t// If we have a display buffer of the wrong size, free it.  This should only happen when the user changes\n\t// the Subpopulation's spatialBounds after it has displayed; it should not happen with a window resize.\n\t// The user has no way to change the map or the colormap except to set a whole new map, which will also\n\t// result in the old one being freed, so we're already safe in those circumstances.\n    if (background_map->display_buffer_ && ((background_map->buffer_width_ != max_width) || (background_map->buffer_height_ != max_height) || (background_map->buffer_flipped_ != flipped)))\n\t{\n\t\tfree(background_map->display_buffer_);\n\t\tbackground_map->display_buffer_ = nullptr;\n\t}\n\t\n\t// Now allocate and validate the display buffer if we haven't already done so.\n\tif (!background_map->display_buffer_)\n\t{\n\t\tuint8_t *display_buf = static_cast<uint8_t *>(malloc(static_cast<size_t>(max_width * max_height * 3) * sizeof(uint8_t)));\n\t\tbackground_map->display_buffer_ = display_buf;\n\t\tbackground_map->buffer_width_ = max_width;\n        background_map->buffer_height_ = max_height;\n        background_map->buffer_flipped_ = flipped;\n        \n        background_map->FillRGBBuffer(display_buf, max_width, max_height, flipped, /* no_interpolation */ false);\n\t}\n}\n\nvoid QtSLiMIndividualsWidget::chooseDefaultBackgroundSettingsForSubpopulation(PopulationViewSettings *background, SpatialMap **returnMap, Subpopulation *subpop)\n{\n    PopulationViewDisplayMode displayMode = displayModeForSubpopulation(subpop);\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (displayMode == PopulationViewDisplayMode::kDisplayIndividuals)\n    {\n        // black or white following the dark mode setting, by default\n        if (inDarkMode)\n            background->backgroundType = 0;\n        else\n            background->backgroundType = 2;\n    }\n    else\n    {\n        // black by default\n        background->backgroundType = 0;\n        \n        // if there are spatial maps defined, we try to choose one, requiring \"x\" or \"y\" or \"xy\", and requiring\n        // a color map to be defined, and preferring 2D over 1D, providing the same default behavior as SLiM 2.x\n        SpatialMapMap &spatial_maps = subpop->spatial_maps_;\n        SpatialMap *background_map = nullptr;\n        std::string background_map_name;\n        \n        for (const auto &map_pair : spatial_maps)\n        {\n            SpatialMap *map = map_pair.second;\n            \n            // a map must be \"x\", \"y\", or \"xy\", and must have a defined color map, for us to choose it as a default at all\n            if (((map->spatiality_string_ == \"x\") || (map->spatiality_string_ == \"y\") || (map->spatiality_string_ == \"xy\")) && (map->n_colors_ > 0))\n            {\n                // the map is usable, so now we check whether it's better than the map we previously found, if any\n                if ((!background_map) || (map->spatiality_ > background_map->spatiality_))\n                {\n                    background_map = map;\n                    background_map_name = map_pair.first;\n                }\n            }\n        }\n        \n        if (background_map)\n        {\n            background->backgroundType = 3;\n            background->spatialMapName = background_map_name;\n            background->showGridPoints = false;\n            *returnMap = background_map;\n        }\n    }\n}\n\nvoid QtSLiMIndividualsWidget::runContextMenuAtPoint(QPoint globalPoint, Subpopulation *subpopForEvent)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    Community *community = controller->community;\n\tbool disableAll = false;\n\t\n\t// When the simulation is not valid and initialized, the context menu is disabled\n\tif (!community || !community->simulation_valid_ || (community->Tick() < 1))\n\t\tdisableAll = true;\n\t\n    QMenu contextMenu(\"population_menu\", this);\n    \n    QAction *titleAction1 = contextMenu.addAction(\"Global preferred display mode:\");\n    QFont titleFont = titleAction1->font();\n    titleFont.setBold(true);\n    titleFont.setItalic(true);\n    titleAction1->setFont(titleFont);\n    titleAction1->setEnabled(false);\n    \n    QAction *displayNonSpatial = contextMenu.addAction(\"Display Non-spatial\");\n    displayNonSpatial->setData(0);\n    displayNonSpatial->setCheckable(true);\n    displayNonSpatial->setEnabled(!disableAll);\n    \n    QAction *displaySpatial = contextMenu.addAction(\"Display Spatial (separate)\");\n    displaySpatial->setData(1);\n    displaySpatial->setCheckable(true);\n    displaySpatial->setEnabled(!disableAll);\n    \n    QAction *displayUnified = contextMenu.addAction(\"Display Spatial (unified)\");\n    displayUnified->setData(2);\n    displayUnified->setCheckable(true);\n    displayUnified->setEnabled(!disableAll);\n    \n    // Check the item corresponding to our current display preference, if any\n    if (!disableAll)\n    {\n        if (preferredDisplayMode == PopulationViewDisplayMode::kDisplayIndividuals)         displayNonSpatial->setChecked(true);\n        if (preferredDisplayMode == PopulationViewDisplayMode::kDisplaySpatialSeparate)     displaySpatial->setChecked(true);\n        if (preferredDisplayMode == PopulationViewDisplayMode::kDisplaySpatialUnified)      displayUnified->setChecked(true);\n    }\n    \n    QActionGroup *displayGroup = new QActionGroup(this);    // On Linux this provides a radio-button-group appearance\n    displayGroup->addAction(displayNonSpatial);\n    displayGroup->addAction(displaySpatial);\n    displayGroup->addAction(displayUnified);\n    \n    // Provide background options (colors, spatial maps for spatial subpops)\n    if (subpopForEvent && !disableAll)\n    {\n        contextMenu.addSeparator();\n        \n        QAction *titleAction2 = contextMenu.addAction(\"For this subview:\");\n        titleAction2->setFont(titleFont);\n        titleAction2->setEnabled(false);\n        \n        QAction *headerAction = contextMenu.addAction(QString(\"Background for p%1:\").arg(subpopForEvent->subpopulation_id_));\n        headerAction->setData(-1);\n        headerAction->setEnabled(false);\n        \n        // check the menu item for the preferred display option; if we're in auto mode, don't check anything (could put a dash by the currently chosen style?)\n        auto backgroundIter = subviewSettings.find(subpopForEvent->subpopulation_id_);\n        PopulationViewSettings *background = ((backgroundIter == subviewSettings.end()) ? nullptr : &backgroundIter->second);\n        int backgroundType = (background ? background->backgroundType : -1);\n        bool showGrid = (background ? background->showGridPoints : false);\n        \n        QAction *blackAction = contextMenu.addAction(\"Black Background\");\n        blackAction->setData(10);\n        blackAction->setCheckable(true);\n        blackAction->setChecked(backgroundType == 0);\n        blackAction->setEnabled(!disableAll);\n        \n        QAction *grayAction = contextMenu.addAction(\"Gray Background\");\n        grayAction->setData(11);\n        grayAction->setCheckable(true);\n        grayAction->setChecked(backgroundType == 1);\n        grayAction->setEnabled(!disableAll);\n        \n        QAction *whiteAction = contextMenu.addAction(\"White Background\");\n        whiteAction->setData(12);\n        whiteAction->setCheckable(true);\n        whiteAction->setChecked(backgroundType == 2);\n        whiteAction->setEnabled(!disableAll);\n        \n        QActionGroup *backgroundGroup = new QActionGroup(this);    // On Linux this provides a radio-button-group appearance\n        backgroundGroup->addAction(blackAction);\n        backgroundGroup->addAction(grayAction);\n        backgroundGroup->addAction(whiteAction);\n        \n        if (preferredDisplayMode > 0)\n        {\n            // look for spatial maps to offer as choices; need to scan the defined maps for the ones we can use\n            SpatialMapMap &spatial_maps = subpopForEvent->spatial_maps_;\n            \n            for (const auto &map_pair : spatial_maps)\n            {\n                SpatialMap *map = map_pair.second;\n                \n                // We used to display only maps with a color scale; now we just make up a color scale if none is given.  Only\n                // \"x\", \"y\", and \"xy\" maps are considered displayable; we can't display a z coordinate, and we can't display\n                // even the x or y portion of \"xz\", \"yz\", and \"xyz\" maps.\n                bool displayable = ((map->spatiality_string_ == \"x\") || (map->spatiality_string_ == \"y\") || (map->spatiality_string_ == \"xy\"));\n                QString mapName = QString::fromStdString(map_pair.first);\n                QString spatialityName = QString::fromStdString(map->spatiality_string_);\n                QString menuItemTitle;\n                \n                if (map->spatiality_ == 1)\n                    menuItemTitle = QString(\"Spatial Map \\\"%1\\\" (\\\"%2\\\", %3)\").arg(mapName).arg(spatialityName).arg(map->grid_size_[0]);\n                else if (map->spatiality_ == 2)\n                    menuItemTitle = QString(\"Spatial Map \\\"%1\\\" (\\\"%2\\\", %3×%4)\").arg(mapName).arg(spatialityName).arg(map->grid_size_[0]).arg(map->grid_size_[1]);\n                else // (map->spatiality_ == 3)\n                    menuItemTitle = QString(\"Spatial Map \\\"%1\\\" (\\\"%2\\\", %3×%4×%5)\").arg(mapName).arg(spatialityName).arg(map->grid_size_[0]).arg(map->grid_size_[1]).arg(map->grid_size_[2]);\n                \n                QAction *mapAction1 = contextMenu.addAction(menuItemTitle);\n                mapAction1->setData(mapName);\n                mapAction1->setCheckable(true);\n                mapAction1->setChecked((backgroundType == 3) && (mapName == QString::fromStdString(background->spatialMapName) && !showGrid));\n                mapAction1->setEnabled(!disableAll && displayable);\n                \n                backgroundGroup->addAction(mapAction1);\n                \n                // 9/29/2023: now we support displaying spatial maps with a display of the underlying grid, too\n                // There is a second menu item for each map, with \"with grid\" added to the title and \"__WITH_GRID\" added to the data\n                menuItemTitle.append(\" with grid\");\n                QString mapDataName = mapName;\n                mapDataName.append(\"__WITH_GRID\");\n                QAction *mapAction2 = contextMenu.addAction(menuItemTitle);\n                mapAction2->setData(mapDataName);\n                mapAction2->setCheckable(true);\n                mapAction2->setChecked((backgroundType == 3) && (mapName == QString::fromStdString(background->spatialMapName) && showGrid));\n                mapAction2->setEnabled(!disableAll && displayable);\n                \n                backgroundGroup->addAction(mapAction2);\n            }\n        }\n    }\n\t\n    // Run the context menu synchronously\n    QAction *action = contextMenu.exec(globalPoint);\n    \n    // Act upon the chosen action; we just do it right here instead of dealing with slots\n    if (action)\n    {\n        if ((action == displayNonSpatial) || (action == displaySpatial) || (action == displayUnified))\n        {\n            // - (IBAction)setDisplayStyle:(id)sender\n            PopulationViewDisplayMode newDisplayMode = (PopulationViewDisplayMode)action->data().toInt();\n            \n            if (newDisplayMode != preferredDisplayMode)\n            {\n                preferredDisplayMode = newDisplayMode;\n                update();\n            }\n        }\n        else if (subpopForEvent)\n        {\n            // - (IBAction)setDisplayBackground:(id)sender\n            int newDisplayBackground;\n            bool newShowGrid = false;\n            auto backgroundIter = subviewSettings.find(subpopForEvent->subpopulation_id_);\n            PopulationViewSettings *background = ((backgroundIter == subviewSettings.end()) ? nullptr : &backgroundIter->second);\n            std::string mapName;\n            \n            // If the user has selected a spatial map, extract its name\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n            if (static_cast<QMetaType::Type>(action->data().type()) == QMetaType::QString)  // for some reason this method's return type is apparently misdeclared; see the doc\n#else\n            if (action->data().typeId() == QMetaType::QString)\n#endif\n            {\n                QString qMapName = action->data().toString();\n                \n                // detect the \"with grid\" ending if present\n                if (qMapName.endsWith(\"__WITH_GRID\"))\n                {\n                    qMapName.chop(11);\n                    newShowGrid = true;\n                }\n                \n                mapName = qMapName.toStdString();\n                \n                if (mapName.length() == 0)\n                    return;\n                \n                newDisplayBackground = 3;\n            }\n            else\n            {\n                newDisplayBackground = action->data().toInt() - 10;\n                newShowGrid = false;\n            }\n            \n            // Update the existing background entry, or make a new entry\n            if (background)\n            {\n                background->backgroundType = newDisplayBackground;\n                background->spatialMapName = mapName;\n                background->showGridPoints = newShowGrid;\n                update();\n            }\n            else\n            {\n                subviewSettings.emplace(subpopForEvent->subpopulation_id_, PopulationViewSettings{newDisplayBackground, mapName, newShowGrid});\n                update();\n            }\n        }\n    }\n}\n\nvoid QtSLiMIndividualsWidget::contextMenuEvent(QContextMenuEvent *p_event)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    Community *community = controller->community;\n    bool disableAll = false;\n\t\n\t// When the simulation is not valid and initialized, the context menu is disabled\n    if (!community || !community->simulation_valid_ || (community->Tick() < 1))\n\t\tdisableAll = true;\n    \n    // Find the subpop that was clicked in; in \"unified\" display mode, this is the first selected subpop\n    Subpopulation *subpopForEvent = nullptr;\n    \n\tif (!disableAll)\n\t{\n\t\tstd::vector<Subpopulation*> selectedSubpopulations = controller->selectedSubpopulations();\n        QPoint viewPoint = p_event->pos();\n\t\t\n\t\t// our tile coordinates are in the OpenGL coordinate system, which has the origin at top left\n\t\t//viewPoint.y = [self bounds].size.height - viewPoint.y;\n\t\t\n\t\tfor (Subpopulation *subpop : selectedSubpopulations)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop->subpopulation_id_;\n\t\t\tauto tileIter = subpopTiles.find(subpop_id);\n\t\t\t\n\t\t\tif (tileIter != subpopTiles.end())\n\t\t\t{\n\t\t\t\tQRect tileRect = tileIter->second;\n\t\t\t\t\n                if (tileRect.contains(viewPoint))\n\t\t\t\t{\n\t\t\t\t\tsubpopForEvent = subpop;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    }\n    \n    runContextMenuAtPoint(p_event->globalPos(), subpopForEvent);\n}\n\nvoid QtSLiMIndividualsWidget::mousePressEvent(QMouseEvent *p_event)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    Community *community = controller->community;\n\t\n\t// When the simulation is not valid and initialized, the context menu is disabled\n    if (!community || !community->simulation_valid_ || (community->Tick() < 1))\n\t\treturn;\n    \n    std::vector<Subpopulation*> selectedSubpopulations = controller->selectedSubpopulations();\n\tint selectedSubpopCount = static_cast<int>(selectedSubpopulations.size());\n\t\n    if ((selectedSubpopCount == 0) || !canDisplayAllIndividuals)\n        return;\n    \n    QPoint mousePos = p_event->pos();\n    Subpopulation *subpopForEvent = nullptr;\n    \n    for (Subpopulation *subpop : selectedSubpopulations)\n    {\n        auto tileIter = subpopTiles.find(subpop->subpopulation_id_);\n        \n        if (tileIter != subpopTiles.end())\n        {\n            QRect tileBounds = tileIter->second;\n            QRect buttonBounds(tileBounds.left(), tileBounds.top(), 20, 20);\n            double xd = (mousePos.x() - buttonBounds.left()) / (double)buttonBounds.width() - 0.5;\n            double yd = (mousePos.y() - buttonBounds.top()) / (double)buttonBounds.height() - 0.5;\n            double distance = std::sqrt(xd * xd + yd * yd);\n            \n            if (buttonBounds.contains(mousePos) && (distance <= 0.51))\n            {\n                actionButtonHighlightSubpopID_ = subpop->subpopulation_id_;\n                update();\n                \n                subpopForEvent = subpop;\n                break;\n            }\n        }\n    }\n    \n    if (subpopForEvent)\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n        runContextMenuAtPoint(p_event->globalPos(), subpopForEvent);\n#else\n        runContextMenuAtPoint(p_event->globalPosition().toPoint(), subpopForEvent);\n#endif\n    \n    // redraw to get rid of action button highlight\n    actionButtonHighlightSubpopID_ = -1;\n    update();\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMIndividualsWidget.h",
    "content": "//\n//  QtSLiMIndividualsWidget.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMINDIVIDUALSWIDGET_H\n#define QTSLIMINDIVIDUALSWIDGET_H\n\n// Silence deprecated OpenGL warnings on macOS\n#define GL_SILENCE_DEPRECATION\n\n#include <QWidget>\n\n#ifndef SLIM_NO_OPENGL\n#include <QOpenGLWidget>\n#include <QOpenGLFunctions>\n#endif\n\n#include \"slim_globals.h\"\n#include \"subpopulation.h\"\n#include <map>\n\nclass QContextMenuEvent;\n\n\ntypedef struct {\n\tint backgroundType;\t\t\t\t// 0 == black, 1 == gray, 2 == white, 3 == named spatial map; if no preference has been set, no entry will exist\n\tstd::string spatialMapName;\t\t// the name of the spatial map chosen, for backgroundType == 3\n\tbool showGridPoints;            // if true show spatial grid points, for backgroundType == 3\n} PopulationViewSettings;\n\ntypedef enum {\n    kDisplayIndividuals = 0,\n    kDisplaySpatialSeparate,\n    kDisplaySpatialUnified\n} PopulationViewDisplayMode;\n\n#ifndef SLIM_NO_OPENGL\nclass QtSLiMIndividualsWidget : public QOpenGLWidget, protected QOpenGLFunctions\n#else\nclass QtSLiMIndividualsWidget : public QWidget\n#endif\n{\n    Q_OBJECT\n    \n    // display mode: this is now just a suggestion; each subpop will fall back to what it is able to do\n\tPopulationViewDisplayMode preferredDisplayMode = kDisplaySpatialSeparate;\n\t\n\t// per-subview display preferences, kept indexed by subpopulation id\n\tstd::map<slim_objectid_t, PopulationViewSettings> subviewSettings;\n\t\n\t// subview tiling, kept indexed by subpopulation id\n\tstd::map<slim_objectid_t, QRect> subpopTiles;\n    bool canDisplayAllIndividuals = false;\n    \n    // action button tracking support\n    slim_objectid_t actionButtonHighlightSubpopID_ = -1;\n    \npublic:\n    explicit QtSLiMIndividualsWidget(QWidget *p_parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());\n    virtual ~QtSLiMIndividualsWidget() override;\n    \n    void tileSubpopulations(std::vector<Subpopulation*> &selectedSubpopulations);\n    void runContextMenuAtPoint(QPoint globalPoint, Subpopulation *subpopForEvent);\n    \nprotected:\n#ifndef SLIM_NO_OPENGL\n    virtual void initializeGL() override;\n    virtual void resizeGL(int w, int h) override;\n    virtual void paintGL() override;\n#else\n    virtual void paintEvent(QPaintEvent *event) override;\n#endif\n\n    bool canDisplayUnified(std::vector<Subpopulation*> &selectedSubpopulations);\n    PopulationViewDisplayMode displayModeForSubpopulation(Subpopulation *subpopulation);\n    bool canDisplayIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds);\n    QRect spatialDisplayBoundsForSubpopulation(Subpopulation *subpop, QRect tileBounds);\n    \n    int squareSizeForSubpopulationInArea(Subpopulation *subpop, QRect bounds);\n    void cacheDisplayBufferForMapForSubpopulation(SpatialMap *background_map, Subpopulation *subpop, bool flipped);\n    void chooseDefaultBackgroundSettingsForSubpopulation(PopulationViewSettings *settings, SpatialMap **returnMap, Subpopulation *subpop);\n    \n    // OpenGL drawing; this is the primary drawing code\n#ifndef SLIM_NO_OPENGL\n    void glDrawViewFrameInBounds(QRect bounds);\n    void glDrawIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int squareSize);\n    void _glDrawBackgroundSpatialMap(SpatialMap *background_map, QRect bounds, Subpopulation *subpop, bool showGridPoints);\n    void glDrawSpatialBackgroundInBoundsForSubpopulation(QRect bounds, Subpopulation * subpop, int dimensionality);\n    void glDrawSpatialIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int dimensionality, float *forceColor);\n#endif\n    \n    // Qt-based drawing, provided as a backup if OpenGL has problems on a given platform\n    void qtDrawViewFrameInBounds(QRect bounds, QPainter &painter);\n    void qtDrawIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int squareSize, QPainter &painter);\n    void _qtDrawBackgroundSpatialMap(SpatialMap *background_map, QRect bounds, Subpopulation *subpop, bool showGridPoints, QPainter &painter);\n    void qtDrawSpatialBackgroundInBoundsForSubpopulation(QRect bounds, Subpopulation * subpop, int dimensionality, QPainter &painter);\n    void qtDrawSpatialIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int dimensionality, float *forceColor, QPainter &painter);\n    \n    virtual void contextMenuEvent(QContextMenuEvent *p_event) override;\n    virtual void mousePressEvent(QMouseEvent *p_event) override;\n};\n\n#endif // QTSLIMINDIVIDUALSWIDGET_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMIndividualsWidget_GL.cpp",
    "content": "//\n//  QtSLiMIndividualsWidget_GL.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef SLIM_NO_OPENGL\n\n#include \"QtSLiMIndividualsWidget.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMOpenGL.h\"\n\n#include <QDebug>\n\n#include <map>\n#include <utility>\n#include <string>\n#include <vector>\n\n\n//\n//  OpenGL-based drawing; maintain this in parallel with the Qt-based drawing!\n//\n\nvoid QtSLiMIndividualsWidget::glDrawViewFrameInBounds(QRect bounds)\n{\n    int ox = bounds.left(), oy = bounds.top();\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (inDarkMode)\n        glColor3f(0.067f, 0.067f, 0.067f);\n    else\n        glColor3f(0.77f, 0.77f, 0.77f);\n    \n    glRecti(ox, oy, ox + 1, oy + bounds.height());\n    glRecti(ox + 1, oy, ox + bounds.width() - 1, oy + 1);\n    glRecti(ox + bounds.width() - 1, oy, ox + bounds.width(), oy + bounds.height());\n    glRecti(ox + 1, oy + bounds.height() - 1, ox + bounds.width() - 1, oy + bounds.height());\n}\n\nvoid QtSLiMIndividualsWidget::glDrawIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int squareSize)\n{\n    //\n    //\tNOTE this code is parallel to the code in canDisplayIndividualsFromSubpopulation:inArea: and should be maintained in parallel\n    //\n    \n    //QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    double scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n    slim_popsize_t subpopSize = subpop->parent_subpop_size_;\n    int viewColumns = 0, viewRows = 0;\n    \n    // our square size is given from above (a consensus based on squareSizeForSubpopulationInArea(); calculate metrics from it\n    viewColumns = static_cast<int>(floor((bounds.width() - 3) / squareSize));\n    viewRows = static_cast<int>(floor((bounds.height() - 3) / squareSize));\n    \n    if (viewColumns * viewRows < subpopSize)\n        squareSize = 1;\n    \n    if (squareSize > 1)\n    {\n        int squareSpacing = 0;\n        \n        // Convert square area to space between squares if possible\n        if (squareSize > 2)\n        {\n            --squareSize;\n            ++squareSpacing;\n        }\n        if (squareSize > 5)\n        {\n            --squareSize;\n            ++squareSpacing;\n        }\n        \n        double excessSpaceX = bounds.width() - ((squareSize + squareSpacing) * viewColumns - squareSpacing);\n        double excessSpaceY = bounds.height() - ((squareSize + squareSpacing) * viewRows - squareSpacing);\n        int offsetX = static_cast<int>(floor(excessSpaceX / 2.0));\n        int offsetY = static_cast<int>(floor(excessSpaceY / 2.0));\n        \n        // If we have an empty row at the bottom, then we can use the same value for offsetY as for offsetX, for symmetry\n        if ((subpopSize - 1) / viewColumns < viewRows - 1)\n            offsetY = offsetX;\n        \n        QRect individualArea(bounds.left() + offsetX, bounds.top() + offsetY, bounds.width() - offsetX, bounds.height() - offsetY);\n        \n        int individualArrayIndex;\n        \n        // Set up to draw rects\n        SLIM_GL_PREPARE();\n        \n        for (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n        {\n            // Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n            float left = static_cast<float>(individualArea.left() + (individualArrayIndex % viewColumns) * (squareSize + squareSpacing));\n            float top = static_cast<float>(individualArea.top() + (individualArrayIndex / viewColumns) * (squareSize + squareSpacing));\n            float right = left + squareSize;\n            float bottom = top + squareSize;\n            \n            SLIM_GL_PUSHRECT();\n            \n            // dark gray default, for a fitness of NaN; should never happen\n            float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n            Individual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n            \n            if (Individual::s_any_individual_color_set_ && individual.color_set_)\n            {\n                colorRed = individual.colorR_ / 255.0F;\n                colorGreen = individual.colorG_ / 255.0F;\n                colorBlue = individual.colorB_ / 255.0F;\n            }\n            else\n            {\n                // use individual trait values to determine color; we use fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n                // we use cached_unscaled_fitness_ so individual fitness, unscaled by subpopulation fitness, is used for coloring\n                double fitness = individual.cached_unscaled_fitness_;\n                \n                if (!std::isnan(fitness))\n                    RGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n            }\n            \n            SLIM_GL_PUSHRECT_COLORS();\n            SLIM_GL_CHECKBUFFERS();\n        }\n        \n        // Draw any leftovers\n        SLIM_GL_FINISH();\n    }\n    else\n    {\n        // This is what we do if we cannot display a subpopulation because there are too many individuals in it to display\n        glColor3f(0.9f, 0.9f, 1.0f);\n        \n        int ox = bounds.left(), oy = bounds.top();\n        \n        glRecti(ox + 1, oy + 1, ox + bounds.width() - 1, oy + bounds.height() - 1);\n    }\n}\n\nvoid QtSLiMIndividualsWidget::_glDrawBackgroundSpatialMap(SpatialMap *background_map, QRect bounds, Subpopulation *subpop, bool showGridPoints)\n{\n    // We have a spatial map with a color map, so use it to draw the background\n\tint bounds_x1 = bounds.x();\n\tint bounds_y1 = bounds.y();\n\tint bounds_x2 = bounds.x() + bounds.width();\n\tint bounds_y2 = bounds.y() + bounds.height();\n\t\n\t//glColor3f(0.0, 0.0, 0.0);\n\t//glRecti(bounds_x1, bounds_y1, bounds_x2, bounds_y2);\n    \n    {\n        // Set up to draw rects\n        SLIM_GL_PREPARE();\n        \n        if (background_map->spatiality_ == 1)\n        {\n            // This is the spatiality \"x\" and \"y\" cases; they are the only 1D spatiality values for which SLiMgui will draw\n            // In the 1D case we can't cache a display buffer, since we don't know what aspect ratio to use, so we just\n            // draw rects.  Whether those rects are horizontal or vertical will depend on the spatiality of the map.  Most\n            // of the code is identical, though, because of the way we handle dimensions, so we share the two cases here.\n            bool spatiality_is_x = (background_map->spatiality_string_ == \"x\");\n            int64_t xsize = background_map->grid_size_[0];\n            double *values = background_map->values_;\n            \n            if (background_map->interpolate_)\n            {\n                // Interpolation, so we need to draw every line individually\n                int min_coord = (spatiality_is_x ? bounds_x1 : bounds_y1);\n                int max_coord = (spatiality_is_x ? bounds_x2 : bounds_y2);\n                \n                for (int xc = min_coord; xc < max_coord; ++xc)\n                {\n                    double x_fraction = (xc + 0.5 - min_coord) / (max_coord - min_coord);\t// values evaluated at pixel centers\n                    double x_map = x_fraction * (xsize - 1);\n                    int x1_map = static_cast<int>(floor(x_map));\n                    int x2_map = static_cast<int>(ceil(x_map));\n                    double fraction_x2 = x_map - x1_map;\n                    double fraction_x1 = 1.0 - fraction_x2;\n                    double value_x1 = values[x1_map] * fraction_x1;\n                    double value_x2 = values[x2_map] * fraction_x2;\n                    double value = value_x1 + value_x2;\n                    \n                    float left, right, top, bottom;\n                    \n                    if (spatiality_is_x)\n                    {\n                        left = xc;\n                        right = xc + 1;\n                        top = bounds_y1;\n                        bottom = bounds_y2;\n                    }\n                    else\n                    {\n                        top = (max_coord - 1) - xc + min_coord;\t// flip for y, to use Cartesian coordinates\n                        bottom = top + 1;\n                        left = bounds_x1;\n                        right = bounds_x2;\n                    }\n                    \n                    float rgb[3];\n                    background_map->ColorForValue(value, rgb);\n                    \n                    float colorRed = rgb[0];\n                    float colorGreen = rgb[1];\n                    float colorBlue = rgb[2];\n                    float colorAlpha = 1.0;\n                    \n                    //glColor3f(colorRed, colorGreen, colorBlue);\n                    //glRecti(x1, y1, x2, y2);\n                    \n                    SLIM_GL_PUSHRECT();\n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS();\n                }\n            }\n            else\n            {\n                // No interpolation, so we can draw whole grid blocks\n                for (int xc = 0; xc < xsize; xc++)\n                {\n                    double value = (spatiality_is_x ? values[xc] : values[(xsize - 1) - xc]);\t// flip for y, to use Cartesian coordinates\n                    float left, right, top, bottom;\n                    \n                    if (spatiality_is_x)\n                    {\n                        left = qRound(((xc - 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        right = qRound(((xc + 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        \n                        if (left < bounds_x1) left = bounds_x1;\n                        if (right > bounds_x2) right = bounds_x2;\n                        \n                        top = bounds_y1;\n                        bottom = bounds_y2;\n                    }\n                    else\n                    {\n                        top = qRound(((xc - 0.5) / (xsize - 1)) * bounds.height() + bounds.y());\n                        bottom = qRound(((xc + 0.5) / (xsize - 1)) * bounds.height() + bounds.y());\n                        \n                        if (top < bounds_y1) top = bounds_y1;\n                        if (bottom > bounds_y2) bottom = bounds_y2;\n                        \n                        left = bounds_x1;\n                        right = bounds_x2;\n                    }\n                    \n                    float rgb[3];\n                    \n                    background_map->ColorForValue(value, rgb);\n                    \n                    float colorRed = rgb[0];\n                    float colorGreen = rgb[1];\n                    float colorBlue = rgb[2];\n                    float colorAlpha = 1.0;\n                    \n                    //glColor3f(colorRed, colorGreen, colorBlue);\n                    //glRecti(x1, y1, x2, y2);\n                    \n                    SLIM_GL_PUSHRECT();\n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS();\n                }\n            }\n        }\n        else // if (background_map->spatiality_ == 2)\n        {\n            // This is the spatiality \"xy\" case; it is the only 2D spatiality for which SLiMgui will draw\n            \n            // First, cache the display buffer if needed.  If this succeeds, we'll use it.\n            // It should always succeed, so the tile-drawing code below is dead code, kept for parallelism with the 1D case.\n            cacheDisplayBufferForMapForSubpopulation(background_map, subpop, /* flipped */ false);\n            \n            uint8_t *display_buf = background_map->display_buffer_;\n            \n            if (display_buf)\n            {\n                // Use a cached display buffer to draw.\n                // FIXME I think there is a bug here somewhere, the boundaries of the pixels fluctuate oddly when the\n                // individuals pane is resized, even if the actual area the map is displaying in doesn't change size.\n                // Maybe try using GL_POINTS?\n                int buf_width = background_map->buffer_width_;\n                int buf_height = background_map->buffer_height_;\n                bool display_full_size = ((bounds.width() == buf_width) && (bounds.height() == buf_height));\n                float scale_x = bounds.width() / static_cast<float>(buf_width);\n                float scale_y = bounds.height() / static_cast<float>(buf_height);\n                \n                // Then run through the pixels in the display buffer and draw them; this could be done\n                // with some sort of OpenGL image-drawing method instead, but it's actually already\n                // remarkably fast, at least on my machine, and drawing an image with OpenGL seems very\n                // gross, and I tried it once before and couldn't get it to work well...\n                for (int yc = 0; yc < buf_height; yc++)\n                {\n                    // We flip the buffer vertically; it's the simplest way to get it into the right coordinate space\n                    uint8_t *buf_ptr = display_buf + ((buf_height - 1) - yc) * buf_width * 3;\n                    \n                    for (int xc = 0; xc < buf_width; xc++)\n                    {\n                        float colorRed = *(buf_ptr++) / 255.0f;\n                        float colorGreen = *(buf_ptr++) / 255.0f;\n                        float colorBlue = *(buf_ptr++) / 255.0f;\n                        float colorAlpha = 1.0;\n                        float left, right, top, bottom;\n                        \n                        if (display_full_size)\n                        {\n                            left = bounds_x1 + xc;\n                            right = left + 1.0f;\n                            top = bounds_y1 + yc;\n                            bottom = top + 1.0f;\n                        }\n                        else\n                        {\n                            left = bounds_x1 + xc * scale_x;\n                            right = bounds_x1 + (xc + 1) * scale_x;\n                            top = bounds_y1 + yc * scale_y;\n                            bottom = bounds_y1 + (yc + 1) * scale_y;\n                        }\n                        \n                        SLIM_GL_PUSHRECT();\n                        SLIM_GL_PUSHRECT_COLORS();\n                        SLIM_GL_CHECKBUFFERS();\n                    }\n                }\n            }\n            else\n            {\n                // Draw rects for each map tile, without caching.  Not as slow as you might expect,\n                // but for really big maps it does get cumbersome.  This is dead code now, overridden\n                // by the buffer-drawing code above, which also handles interpolation correctly.\n                int64_t xsize = background_map->grid_size_[0];\n                int64_t ysize = background_map->grid_size_[1];\n                double *values = background_map->values_;\n                int n_colors = background_map->n_colors_;\n                \n                for (int yc = 0; yc < ysize; yc++)\n                {\n                    float top = qRound(((yc - 0.5) / (ysize - 1)) * bounds.height() + bounds.y());\n                    float bottom = qRound(((yc + 0.5) / (ysize - 1)) * bounds.height() + bounds.y());\n                    \n                    if (top < bounds_y1) top = bounds_y1;\n                    if (bottom > bounds_y2) bottom = bounds_y2;\n                    \n                    // Flip our display, since our coordinate system is flipped relative to our buffer\n                    double *values_row = values + ((ysize - 1) - yc) * xsize;\n                    \n                    for (int xc = 0; xc < xsize; xc++)\n                    {\n                        double value = *(values_row + xc);\n                        float left = qRound(((xc - 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        float right = qRound(((xc + 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        \n                        if (left < bounds_x1) left = bounds_x1;\n                        if (right > bounds_x2) right = bounds_x2;\n                        \n                        float value_fraction = (background_map->colors_min_ < background_map->colors_max_) ? static_cast<float>((value - background_map->colors_min_) / (background_map->colors_max_ - background_map->colors_min_)) : 0.0f;\n                        float color_index = value_fraction * (n_colors - 1);\n                        int color_index_1 = static_cast<int>(floorf(color_index));\n                        int color_index_2 = static_cast<int>(ceilf(color_index));\n                        \n                        if (color_index_1 < 0) color_index_1 = 0;\n                        if (color_index_1 >= n_colors) color_index_1 = n_colors - 1;\n                        if (color_index_2 < 0) color_index_2 = 0;\n                        if (color_index_2 >= n_colors) color_index_2 = n_colors - 1;\n                        \n                        float color_2_weight = color_index - color_index_1;\n                        float color_1_weight = 1.0f - color_2_weight;\n                        \n                        float red1 = background_map->red_components_[color_index_1];\n                        float green1 = background_map->green_components_[color_index_1];\n                        float blue1 = background_map->blue_components_[color_index_1];\n                        float red2 = background_map->red_components_[color_index_2];\n                        float green2 = background_map->green_components_[color_index_2];\n                        float blue2 = background_map->blue_components_[color_index_2];\n                        float colorRed = red1 * color_1_weight + red2 * color_2_weight;\n                        float colorGreen = green1 * color_1_weight + green2 * color_2_weight;\n                        float colorBlue = blue1 * color_1_weight + blue2 * color_2_weight;\n                        float colorAlpha = 1.0;\n                        \n                        //glColor3f(red, green, blue);\n                        //glRecti(x1, y1, x2, y2);\n                        \n                        SLIM_GL_PUSHRECT();\n                        SLIM_GL_PUSHRECT_COLORS();\n                        SLIM_GL_CHECKBUFFERS();\n                        \n                        //std::cout << \"x = \" << x << \", y = \" << y << \", value = \" << value << \": color_index = \" << color_index << \", color_index_1 = \" << color_index_1 << \", color_index_2 = \" << color_index_2 << \", color_1_weight = \" << color_1_weight << \", color_2_weight = \" << color_2_weight << \", red = \" << red << std::endl;\n                    }\n                }\n            }\n        }\n        \n        // Draw any leftovers\n        SLIM_GL_FINISH();\n    }\n    \n    if (showGridPoints)\n    {\n        // BCH 9/29/2023 new feature: draw boxes showing where the grid nodes are, since that is rather confusing!\n        float margin_outer = 5.5f;\n        float margin_inner = 3.5f;\n        float spacing = 10.0f;\n        int64_t xsize = background_map->grid_size_[0];\n        int64_t ysize = background_map->grid_size_[1];\n        double *values = background_map->values_;\n        \n        // require that there is sufficient space that we're not just showing a packed grid of squares\n        // downsize to small and smaller depictions as needed\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 4.5f;\n            margin_inner = 2.5f;\n            spacing = 8.0;\n        }\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 3.5f;\n            margin_inner = 1.5f;\n            spacing = 6.0;\n        }\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 1.0f;\n            margin_inner = 0.0f;\n            spacing = 2.0;\n        }\n        \n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) <= bounds_x2) && ((ysize - 1) * (margin_outer * 2.0 + spacing) <= bounds_y2))\n        {\n            // Set up to draw rects\n            SLIM_GL_PREPARE();\n            \n            // first pass we draw squares to make outlines, second pass we draw the interiors in color\n            for (int pass = 0; pass <= 1; ++pass)\n            {\n                const float margin = ((pass == 0) ? margin_outer : margin_inner);\n                \n                if (margin == 0.0)\n                    continue;\n                \n                for (int x = 0; x < xsize; ++x)\n                {\n                    for (int y = 0; y < ysize; ++y)\n                    {\n                        float position_x = x / (float)(xsize - 1);\t// 0 to 1\n                        float position_y = y / (float)(ysize - 1);\t// 0 to 1\n                        \n                        float centerX = (float)(bounds_x1 + round(position_x * bounds.width()));\n                        float centerY = (float)(bounds_y1 + bounds.height() - round(position_y * bounds.height()));\n                        float left = centerX - margin;\n                        float top = centerY - margin;\n                        float right = centerX + margin;\n                        float bottom = centerY + margin;\n                        \n                        if (left < bounds_x1)\n                            left = bounds_x1;\n                        if (top < bounds_y1)\n                            top = bounds_y1;\n                        if (right > bounds_x2)\n                            right = bounds_x2;\n                        if (bottom > bounds_y2)\n                            bottom = bounds_y2;\n                        \n                        SLIM_GL_PUSHRECT();\n                        \n                        float colorRed;\n                        float colorGreen;\n                        float colorBlue;\n                        float colorAlpha;\n                        \n                        if (pass == 0)\n                        {\n                            colorRed = 1.0;\n                            colorGreen = 0.25;\n                            colorBlue = 0.25;\n                            colorAlpha = 1.0;\n                        }\n                        else\n                        {\n                            // look up the map's color at this grid point\n                            float rgb[3];\n                            double value = values[x + y * xsize];\n                            \n                            background_map->ColorForValue(value, rgb);\n                            \n                            colorRed = rgb[0];\n                            colorGreen = rgb[1];\n                            colorBlue = rgb[2];\n                            colorAlpha = 1.0;\n                        }\n                        \n                        SLIM_GL_PUSHRECT_COLORS();\n                        SLIM_GL_CHECKBUFFERS();\n                    }\n                }\n            }\n            \n            // Draw any leftovers\n            SLIM_GL_FINISH();\n        }\n    }\n}\n\nvoid QtSLiMIndividualsWidget::glDrawSpatialBackgroundInBoundsForSubpopulation(QRect bounds, Subpopulation * subpop, int /* dimensionality */)\n{\n    auto backgroundIter = subviewSettings.find(subpop->subpopulation_id_);\n\tPopulationViewSettings background;\n\tSpatialMap *background_map = nullptr;\n\t\n\tif (backgroundIter == subviewSettings.end())\n\t{\n\t\t// The user has not made a choice, so choose a temporary default.  We don't want this choice to \"stick\",\n\t\t// so that we can, e.g., begin as black and then change to a spatial map if one is defined.\n\t\tchooseDefaultBackgroundSettingsForSubpopulation(&background, &background_map, subpop);\n\t}\n\telse\n\t{\n\t\t// The user has made a choice; verify that it is acceptable, and then use it.\n\t\tbackground = backgroundIter->second;\n\t\t\n\t\tif (background.backgroundType == 3)\n\t\t{\n\t\t\tSpatialMapMap &spatial_maps = subpop->spatial_maps_;\n\t\t\tauto map_iter = spatial_maps.find(background.spatialMapName);\n\t\t\t\n\t\t\tif (map_iter != spatial_maps.end())\n\t\t\t{\n\t\t\t\tbackground_map = map_iter->second;\n\t\t\t\t\n\t\t\t\t// if the user somehow managed to choose a map that is not of an acceptable dimensionality, reject it here\n\t\t\t\tif ((background_map->spatiality_string_ != \"x\") && (background_map->spatiality_string_ != \"y\") && (background_map->spatiality_string_ != \"xy\"))\n\t\t\t\t\tbackground_map = nullptr;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if we're supposed to use a background map but we couldn't find it, or it's unacceptable, revert to black\n\t\tif ((background.backgroundType == 3) && !background_map)\n\t\t\tbackground.backgroundType = 0;\n\t}\n\t\n\tif ((background.backgroundType == 3) && background_map)\n\t{\n\t\t_glDrawBackgroundSpatialMap(background_map, bounds, subpop, background.showGridPoints);\n\t}\n\telse\n\t{\n\t\t// No background map, so just clear to the preferred background color\n\t\tint backgroundColor = background.backgroundType;\n\t\t\n\t\tif (backgroundColor == 0)\n\t\t\tglColor3f(0.0, 0.0, 0.0);\n\t\telse if (backgroundColor == 1)\n\t\t\tglColor3f(0.3f, 0.3f, 0.3f);\n\t\telse if (backgroundColor == 2)\n\t\t\tglColor3f(1.0, 1.0, 1.0);\n\t\telse\n\t\t\tglColor3f(0.0, 0.0, 0.0);\n\t\t\n\t\tglRecti(bounds.x(), bounds.y(), bounds.x() + bounds.width(), bounds.y() + bounds.height());\n\t}\n}\n\nvoid QtSLiMIndividualsWidget::glDrawSpatialIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int dimensionality, float *forceColor)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n\tdouble scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\t\n\tQRect individualArea(bounds.x(), bounds.y(), bounds.width() - 1, bounds.height() - 1);\n\t\n\tint individualArrayIndex;\n\t\n\t// Set up to draw rects\n    SLIM_GL_PREPARE();\n\t\n\t// First we outline all individuals\n\tif (dimensionality == 1)\n\t\tsrandom(static_cast<unsigned int>(controller->community->Tick()));\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n\t\tIndividual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n\t\t\tposition_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>(random() / static_cast<double>(INT32_MAX));\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tposition_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f) || (position_y < 0.0f) || (position_y > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tfloat centerX = static_cast<float>(individualArea.x() + round(position_x * individualArea.width()) + 0.5f);\n\t\tfloat centerY = static_cast<float>(individualArea.y() + individualArea.height() - round(position_y * individualArea.height()) + 0.5f);\n\t\t\n\t\tfloat left = centerX - 2.5f;\n\t\tfloat top = centerY - 2.5f;\n\t\tfloat right = centerX + 2.5f;\n\t\tfloat bottom = centerY + 2.5f;\n\t\t\n\t\tif (left < individualArea.x()) left = static_cast<float>(individualArea.x());\n\t\tif (top < individualArea.y()) top = static_cast<float>(individualArea.y());\n\t\tif (right > individualArea.x() + individualArea.width() + 1) right = static_cast<float>(individualArea.x() + individualArea.width() + 1);\n\t\tif (bottom > individualArea.y() + individualArea.height() + 1) bottom = static_cast<float>(individualArea.y() + individualArea.height() + 1);\n        \n        float colorRed = 0.25;\n        float colorGreen = 0.25;\n        float colorBlue = 0.25;\n        float colorAlpha = 1.0;\n        \n        SLIM_GL_PUSHRECT();\n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS();\n\t}\n\t\n\t// Then we draw all individuals\n\tif (dimensionality == 1)\n        srandom(static_cast<unsigned int>(controller->community->Tick()));\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n        Individual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n            position_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>(random() / static_cast<double>(INT32_MAX));\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n            position_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f) || (position_y < 0.0f) || (position_y > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n        float centerX = static_cast<float>(individualArea.x() + round(position_x * individualArea.width()) + 0.5f);\n\t\tfloat centerY = static_cast<float>(individualArea.y() + individualArea.height() - round(position_y * individualArea.height()) + 0.5f);\n\t\tfloat left = centerX - 1.5f;\n\t\tfloat top = centerY - 1.5f;\n\t\tfloat right = centerX + 1.5f;\n\t\tfloat bottom = centerY + 1.5f;\n\t\t\n\t\t// clipping deliberately not done here; because individual rects are 3x3, they will fall at most one pixel\n\t\t// outside our drawing area, and thus the flaw will be covered by the view frame when it overdraws\n        \n        SLIM_GL_PUSHRECT();\n\t\t\n\t\t// dark gray default, for a fitness of NaN; should never happen\n\t\tfloat colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n\t\t\n\t\tif (Individual::s_any_individual_color_set_ && individual.color_set_)\n\t\t{\n\t\t\tcolorRed = individual.colorR_ / 255.0F;\n\t\t\tcolorGreen = individual.colorG_ / 255.0F;\n\t\t\tcolorBlue = individual.colorB_ / 255.0F;\n\t\t}\n        else if (forceColor)\n        {\n            // forceColor is used to make each species draw with a distinctive color in multispecies models in unified display mode\n            colorRed = forceColor[0];\n\t\t\tcolorGreen = forceColor[1];\n\t\t\tcolorBlue = forceColor[2];\n        }\n\t\telse\n\t\t{\n\t\t\t// use individual trait values to determine color; we used fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n\t\t\t// we use cached_unscaled_fitness_ so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\t\tdouble fitness = individual.cached_unscaled_fitness_;\n\t\t\t\n\t\t\tif (!std::isnan(fitness))\n\t\t\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t}\n        \n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS();\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMIndividualsWidget_QT.cpp",
    "content": "//\n//  QtSLiMIndividualsWidget_QT.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMIndividualsWidget.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMOpenGL_Emulation.h\"\n\n#include <QDebug>\n\n#include <map>\n#include <utility>\n#include <string>\n#include <vector>\n\n\n//\n//  Qt-based drawing; maintain this in parallel with the OpenGL-based drawing!\n//\n\nvoid QtSLiMIndividualsWidget::qtDrawViewFrameInBounds(QRect bounds, QPainter &painter)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (inDarkMode)\n        QtSLiMFrameRect(bounds, QtSLiMColorWithWhite(0.067, 1.0), painter);\n    else\n        QtSLiMFrameRect(bounds, QtSLiMColorWithWhite(0.77, 1.0), painter);\n}\n\nvoid QtSLiMIndividualsWidget::qtDrawIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int squareSize, QPainter &painter)\n{\n    //\n    //\tNOTE this code is parallel to the code in canDisplayIndividualsFromSubpopulation:inArea: and should be maintained in parallel\n    //\n    \n    //QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n    double scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n    slim_popsize_t subpopSize = subpop->parent_subpop_size_;\n    int viewColumns = 0, viewRows = 0;\n    \n    // our square size is given from above (a consensus based on squareSizeForSubpopulationInArea(); calculate metrics from it\n    viewColumns = static_cast<int>(floor((bounds.width() - 3) / squareSize));\n    viewRows = static_cast<int>(floor((bounds.height() - 3) / squareSize));\n    \n    if (viewColumns * viewRows < subpopSize)\n        squareSize = 1;\n    \n    if (squareSize > 1)\n    {\n        int squareSpacing = 0;\n        \n        // Convert square area to space between squares if possible\n        if (squareSize > 2)\n        {\n            --squareSize;\n            ++squareSpacing;\n        }\n        if (squareSize > 5)\n        {\n            --squareSize;\n            ++squareSpacing;\n        }\n        \n        double excessSpaceX = bounds.width() - ((squareSize + squareSpacing) * viewColumns - squareSpacing);\n        double excessSpaceY = bounds.height() - ((squareSize + squareSpacing) * viewRows - squareSpacing);\n        int offsetX = static_cast<int>(floor(excessSpaceX / 2.0));\n        int offsetY = static_cast<int>(floor(excessSpaceY / 2.0));\n        \n        // If we have an empty row at the bottom, then we can use the same value for offsetY as for offsetX, for symmetry\n        if ((subpopSize - 1) / viewColumns < viewRows - 1)\n            offsetY = offsetX;\n        \n        QRect individualArea(bounds.left() + offsetX, bounds.top() + offsetY, bounds.width() - offsetX, bounds.height() - offsetY);\n        \n        int individualArrayIndex;\n        \n        // Set up to draw rects\n        SLIM_GL_PREPARE();\n        \n        for (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n        {\n            // Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n            float left = static_cast<float>(individualArea.left() + (individualArrayIndex % viewColumns) * (squareSize + squareSpacing));\n            float top = static_cast<float>(individualArea.top() + (individualArrayIndex / viewColumns) * (squareSize + squareSpacing));\n            float right = left + squareSize;\n            float bottom = top + squareSize;\n            \n            SLIM_GL_PUSHRECT();\n            \n            // dark gray default, for a fitness of NaN; should never happen\n            float colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n            Individual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n            \n            if (Individual::s_any_individual_color_set_ && individual.color_set_)\n            {\n                colorRed = individual.colorR_ / 255.0F;\n                colorGreen = individual.colorG_ / 255.0F;\n                colorBlue = individual.colorB_ / 255.0F;\n            }\n            else\n            {\n                // use individual trait values to determine color; we use fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n                // we use cached_unscaled_fitness_ so individual fitness, unscaled by subpopulation fitness, is used for coloring\n                double fitness = individual.cached_unscaled_fitness_;\n                \n                if (!std::isnan(fitness))\n                    RGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n            }\n            \n            SLIM_GL_PUSHRECT_COLORS();\n            SLIM_GL_CHECKBUFFERS_NORECT();\n        }\n        \n        // Draw any leftovers\n        SLIM_GL_FINISH();\n    }\n    else\n    {\n        // This is what we do if we cannot display a subpopulation because there are too many individuals in it to display\n        QRect insetBounds = bounds.adjusted(1, 1, -1, -1);\n        \n        painter.fillRect(insetBounds, QtSLiMColorWithRGB(0.9, 0.9, 1.0, 1.0));\n    }\n}\n\nvoid QtSLiMIndividualsWidget::_qtDrawBackgroundSpatialMap(SpatialMap *background_map, QRect bounds, Subpopulation *subpop, bool showGridPoints, QPainter &painter)\n{\n    // We have a spatial map with a color map, so use it to draw the background\n\tint bounds_x1 = bounds.x();\n\tint bounds_y1 = bounds.y();\n\tint bounds_x2 = bounds.x() + bounds.width();\n\tint bounds_y2 = bounds.y() + bounds.height();\n\t\n    {\n        // Set up to draw rects\n        SLIM_GL_PREPARE();\n        \n        if (background_map->spatiality_ == 1)\n        {\n            // This is the spatiality \"x\" and \"y\" cases; they are the only 1D spatiality values for which SLiMgui will draw\n            // In the 1D case we can't cache a display buffer, since we don't know what aspect ratio to use, so we just\n            // draw rects.  Whether those rects are horizontal or vertical will depend on the spatiality of the map.  Most\n            // of the code is identical, though, because of the way we handle dimensions, so we share the two cases here.\n            bool spatiality_is_x = (background_map->spatiality_string_ == \"x\");\n            int64_t xsize = background_map->grid_size_[0];\n            double *values = background_map->values_;\n            \n            if (background_map->interpolate_)\n            {\n                // Interpolation, so we need to draw every line individually\n                int min_coord = (spatiality_is_x ? bounds_x1 : bounds_y1);\n                int max_coord = (spatiality_is_x ? bounds_x2 : bounds_y2);\n                \n                for (int xc = min_coord; xc < max_coord; ++xc)\n                {\n                    double x_fraction = (xc + 0.5 - min_coord) / (max_coord - min_coord);\t// values evaluated at pixel centers\n                    double x_map = x_fraction * (xsize - 1);\n                    int x1_map = static_cast<int>(floor(x_map));\n                    int x2_map = static_cast<int>(ceil(x_map));\n                    double fraction_x2 = x_map - x1_map;\n                    double fraction_x1 = 1.0 - fraction_x2;\n                    double value_x1 = values[x1_map] * fraction_x1;\n                    double value_x2 = values[x2_map] * fraction_x2;\n                    double value = value_x1 + value_x2;\n                    \n                    float left, right, top, bottom;\n                    \n                    if (spatiality_is_x)\n                    {\n                        left = xc;\n                        right = xc + 1;\n                        top = bounds_y1;\n                        bottom = bounds_y2;\n                    }\n                    else\n                    {\n                        top = (max_coord - 1) - xc + min_coord;\t// flip for y, to use Cartesian coordinates\n                        bottom = top + 1;\n                        left = bounds_x1;\n                        right = bounds_x2;\n                    }\n                    \n                    float rgb[3];\n                    background_map->ColorForValue(value, rgb);\n                    \n                    float colorRed = rgb[0];\n                    float colorGreen = rgb[1];\n                    float colorBlue = rgb[2];\n                    float colorAlpha = 1.0;\n                    \n                    SLIM_GL_PUSHRECT();\n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS_NORECT();\n                }\n            }\n            else\n            {\n                // No interpolation, so we can draw whole grid blocks\n                for (int xc = 0; xc < xsize; xc++)\n                {\n                    double value = (spatiality_is_x ? values[xc] : values[(xsize - 1) - xc]);\t// flip for y, to use Cartesian coordinates\n                    float left, right, top, bottom;\n                    \n                    if (spatiality_is_x)\n                    {\n                        left = qRound(((xc - 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        right = qRound(((xc + 0.5) / (xsize - 1)) * bounds.width() + bounds.x());\n                        \n                        if (left < bounds_x1) left = bounds_x1;\n                        if (right > bounds_x2) right = bounds_x2;\n                        \n                        top = bounds_y1;\n                        bottom = bounds_y2;\n                    }\n                    else\n                    {\n                        top = qRound(((xc - 0.5) / (xsize - 1)) * bounds.height() + bounds.y());\n                        bottom = qRound(((xc + 0.5) / (xsize - 1)) * bounds.height() + bounds.y());\n                        \n                        if (top < bounds_y1) top = bounds_y1;\n                        if (bottom > bounds_y2) bottom = bounds_y2;\n                        \n                        left = bounds_x1;\n                        right = bounds_x2;\n                    }\n                    \n                    float rgb[3];\n                    \n                    background_map->ColorForValue(value, rgb);\n                    \n                    float colorRed = rgb[0];\n                    float colorGreen = rgb[1];\n                    float colorBlue = rgb[2];\n                    float colorAlpha = 1.0;\n                    \n                    SLIM_GL_PUSHRECT();\n                    SLIM_GL_PUSHRECT_COLORS();\n                    SLIM_GL_CHECKBUFFERS_NORECT();\n                }\n            }\n        }\n        else // if (background_map->spatiality_ == 2)\n        {\n            // This is the spatiality \"xy\" case; it is the only 2D spatiality for which SLiMgui will draw\n            \n            // First, cache the display buffer if needed.  If this succeeds, we'll use it.\n            // It should always succeed, so the tile-drawing code below is dead code, kept for parallelism with the 1D case.\n            cacheDisplayBufferForMapForSubpopulation(background_map, subpop, /* flipped */ true);\n            \n            const uint8_t *display_buf = background_map->display_buffer_;\n            \n            if (display_buf)\n            {\n                // Use a cached display buffer to draw.\n                int buf_width = background_map->buffer_width_;\n                int buf_height = background_map->buffer_height_;\n                QImage bufferImage(display_buf, buf_width, buf_height, buf_width * 3, QImage::Format_RGB888);\n                \n                painter.drawImage(bounds, bufferImage);\n            }\n        }\n        \n        // Draw any leftovers\n        SLIM_GL_FINISH();\n    }\n    \n    if (showGridPoints)\n    {\n        // BCH 9/29/2023 new feature: draw boxes showing where the grid nodes are, since that is rather confusing!\n        float margin_outer = 5.5f;\n        float margin_inner = 3.5f;\n        float spacing = 10.0f;\n        int64_t xsize = background_map->grid_size_[0];\n        int64_t ysize = background_map->grid_size_[1];\n        double *values = background_map->values_;\n        \n        // require that there is sufficient space that we're not just showing a packed grid of squares\n        // downsize to small and smaller depictions as needed\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 4.5f;\n            margin_inner = 2.5f;\n            spacing = 8.0;\n        }\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 3.5f;\n            margin_inner = 1.5f;\n            spacing = 6.0;\n        }\n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) > bounds_x2) || ((ysize - 1) * (margin_outer * 2.0 + spacing) > bounds_y2))\n        {\n            margin_outer = 1.0f;\n            margin_inner = 0.0f;\n            spacing = 2.0;\n        }\n        \n        if (((xsize - 1) * (margin_outer * 2.0 + spacing) <= bounds_x2) && ((ysize - 1) * (margin_outer * 2.0 + spacing) <= bounds_y2))\n        {\n            // Set up to draw rects\n            SLIM_GL_PREPARE();\n            \n            // first pass we draw squares to make outlines, second pass we draw the interiors in color\n            for (int pass = 0; pass <= 1; ++pass)\n            {\n                const float margin = ((pass == 0) ? margin_outer : margin_inner);\n                \n                if (margin == 0.0)\n                    continue;\n                \n                for (int x = 0; x < xsize; ++x)\n                {\n                    for (int y = 0; y < ysize; ++y)\n                    {\n                        float position_x = x / (float)(xsize - 1);\t// 0 to 1\n                        float position_y = y / (float)(ysize - 1);\t// 0 to 1\n                        \n                        float centerX = (float)(bounds_x1 + round(position_x * bounds.width()));\n                        float centerY = (float)(bounds_y1 + bounds.height() - round(position_y * bounds.height()));\n                        float left = centerX - margin;\n                        float top = centerY - margin;\n                        float right = centerX + margin;\n                        float bottom = centerY + margin;\n                        \n                        if (left < bounds_x1)\n                            left = bounds_x1;\n                        if (top < bounds_y1)\n                            top = bounds_y1;\n                        if (right > bounds_x2)\n                            right = bounds_x2;\n                        if (bottom > bounds_y2)\n                            bottom = bounds_y2;\n                        \n                        SLIM_GL_PUSHRECT();\n                        \n                        float colorRed;\n                        float colorGreen;\n                        float colorBlue;\n                        float colorAlpha;\n                        \n                        if (pass == 0)\n                        {\n                            colorRed = 1.0;\n                            colorGreen = 0.25;\n                            colorBlue = 0.25;\n                            colorAlpha = 1.0;\n                        }\n                        else\n                        {\n                            // look up the map's color at this grid point\n                            float rgb[3];\n                            double value = values[x + y * xsize];\n                            \n                            background_map->ColorForValue(value, rgb);\n                            \n                            colorRed = rgb[0];\n                            colorGreen = rgb[1];\n                            colorBlue = rgb[2];\n                            colorAlpha = 1.0;\n                        }\n                        \n                        SLIM_GL_PUSHRECT_COLORS();\n                        SLIM_GL_CHECKBUFFERS_NORECT();\n                    }\n                }\n            }\n            \n            // Draw any leftovers\n            SLIM_GL_FINISH();\n        }\n    }\n}\n\nvoid QtSLiMIndividualsWidget::qtDrawSpatialBackgroundInBoundsForSubpopulation(QRect bounds, Subpopulation * subpop, int /* dimensionality */, QPainter &painter)\n{\n    auto backgroundIter = subviewSettings.find(subpop->subpopulation_id_);\n\tPopulationViewSettings background;\n\tSpatialMap *background_map = nullptr;\n\t\n\tif (backgroundIter == subviewSettings.end())\n\t{\n\t\t// The user has not made a choice, so choose a temporary default.  We don't want this choice to \"stick\",\n\t\t// so that we can, e.g., begin as black and then change to a spatial map if one is defined.\n\t\tchooseDefaultBackgroundSettingsForSubpopulation(&background, &background_map, subpop);\n\t}\n\telse\n\t{\n\t\t// The user has made a choice; verify that it is acceptable, and then use it.\n\t\tbackground = backgroundIter->second;\n\t\t\n\t\tif (background.backgroundType == 3)\n\t\t{\n\t\t\tSpatialMapMap &spatial_maps = subpop->spatial_maps_;\n\t\t\tauto map_iter = spatial_maps.find(background.spatialMapName);\n\t\t\t\n\t\t\tif (map_iter != spatial_maps.end())\n\t\t\t{\n\t\t\t\tbackground_map = map_iter->second;\n\t\t\t\t\n\t\t\t\t// if the user somehow managed to choose a map that is not of an acceptable dimensionality, reject it here\n\t\t\t\tif ((background_map->spatiality_string_ != \"x\") && (background_map->spatiality_string_ != \"y\") && (background_map->spatiality_string_ != \"xy\"))\n\t\t\t\t\tbackground_map = nullptr;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if we're supposed to use a background map but we couldn't find it, or it's unacceptable, revert to black\n\t\tif ((background.backgroundType == 3) && !background_map)\n\t\t\tbackground.backgroundType = 0;\n\t}\n\t\n\tif ((background.backgroundType == 3) && background_map)\n\t{\n\t\t_qtDrawBackgroundSpatialMap(background_map, bounds, subpop, background.showGridPoints, painter);\n\t}\n\telse\n\t{\n\t\t// No background map, so just clear to the preferred background color\n\t\tint backgroundColor = background.backgroundType;\n\t\t\n\t\tif (backgroundColor == 0)\n            painter.fillRect(bounds, Qt::black);\n\t\telse if (backgroundColor == 1)\n            painter.fillRect(bounds, QtSLiMColorWithWhite(0.3, 1.0));\n\t\telse if (backgroundColor == 2)\n            painter.fillRect(bounds, Qt::white);\n\t\telse\n            painter.fillRect(bounds, Qt::black);\n\t}\n}\n\nvoid QtSLiMIndividualsWidget::qtDrawSpatialIndividualsFromSubpopulationInArea(Subpopulation *subpop, QRect bounds, int dimensionality, float *forceColor, QPainter &painter)\n{\n    QtSLiMWindow *controller = dynamic_cast<QtSLiMWindow *>(window());\n\tdouble scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\t\n\tQRect individualArea(bounds.x(), bounds.y(), bounds.width() - 1, bounds.height() - 1);\n\t\n\tint individualArrayIndex;\n\t\n\t// Set up to draw rects\n    SLIM_GL_PREPARE();\n\t\n\t// First we outline all individuals\n\tif (dimensionality == 1)\n\t\tsrandom(static_cast<unsigned int>(controller->community->Tick()));\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n\t\tIndividual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n\t\t\tposition_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>(random() / static_cast<double>(INT32_MAX));\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tposition_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f) || (position_y < 0.0f) || (position_y > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tfloat centerX = static_cast<float>(individualArea.x() + round(position_x * individualArea.width()) + 0.5f);\n\t\tfloat centerY = static_cast<float>(individualArea.y() + individualArea.height() - round(position_y * individualArea.height()) + 0.5f);\n\t\t\n\t\tfloat left = centerX - 2.5f;\n\t\tfloat top = centerY - 2.5f;\n\t\tfloat right = centerX + 2.5f;\n\t\tfloat bottom = centerY + 2.5f;\n\t\t\n\t\tif (left < individualArea.x()) left = static_cast<float>(individualArea.x());\n\t\tif (top < individualArea.y()) top = static_cast<float>(individualArea.y());\n\t\tif (right > individualArea.x() + individualArea.width() + 1) right = static_cast<float>(individualArea.x() + individualArea.width() + 1);\n\t\tif (bottom > individualArea.y() + individualArea.height() + 1) bottom = static_cast<float>(individualArea.y() + individualArea.height() + 1);\n        \n        float colorRed = 0.25;\n        float colorGreen = 0.25;\n        float colorBlue = 0.25;\n        float colorAlpha = 1.0;\n        \n        SLIM_GL_PUSHRECT();\n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS_NORECT();\n\t}\n\t\n\t// Then we draw all individuals\n\tif (dimensionality == 1)\n        srandom(static_cast<unsigned int>(controller->community->Tick()));\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n        Individual &individual = *subpop->parent_individuals_[static_cast<size_t>(individualArrayIndex)];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n            position_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>(random() / static_cast<double>(INT32_MAX));\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n            position_x = static_cast<float>((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = static_cast<float>((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0f) || (position_x > 1.0f) || (position_y < 0.0f) || (position_y > 1.0f))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n        float centerX = static_cast<float>(individualArea.x() + round(position_x * individualArea.width()) + 0.5f);\n\t\tfloat centerY = static_cast<float>(individualArea.y() + individualArea.height() - round(position_y * individualArea.height()) + 0.5f);\n\t\tfloat left = centerX - 1.5f;\n\t\tfloat top = centerY - 1.5f;\n\t\tfloat right = centerX + 1.5f;\n\t\tfloat bottom = centerY + 1.5f;\n\t\t\n\t\t// clipping deliberately not done here; because individual rects are 3x3, they will fall at most one pixel\n\t\t// outside our drawing area, and thus the flaw will be covered by the view frame when it overdraws\n        \n        SLIM_GL_PUSHRECT();\n\t\t\n\t\t// dark gray default, for a fitness of NaN; should never happen\n\t\tfloat colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n\t\t\n\t\tif (Individual::s_any_individual_color_set_ && individual.color_set_)\n\t\t{\n\t\t\tcolorRed = individual.colorR_ / 255.0F;\n\t\t\tcolorGreen = individual.colorG_ / 255.0F;\n\t\t\tcolorBlue = individual.colorB_ / 255.0F;\n\t\t}\n        else if (forceColor)\n        {\n            // forceColor is used to make each species draw with a distinctive color in multispecies models in unified display mode\n            colorRed = forceColor[0];\n\t\t\tcolorGreen = forceColor[1];\n\t\t\tcolorBlue = forceColor[2];\n        }\n\t\telse\n\t\t{\n\t\t\t// use individual trait values to determine color; we used fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n\t\t\t// we use cached_unscaled_fitness_ so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\t\tdouble fitness = individual.cached_unscaled_fitness_;\n\t\t\t\n\t\t\tif (!std::isnan(fitness))\n\t\t\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t}\n        \n        SLIM_GL_PUSHRECT_COLORS();\n        SLIM_GL_CHECKBUFFERS_NORECT();\n\t}\n\t\n\t// Draw any leftovers\n    SLIM_GL_FINISH();\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMOpenGL.cpp",
    "content": "//\n//  QtSLiMOpenGL.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMOpenGL.h\"\n\n#include <cstdlib>\n\n\nfloat *glArrayVertices = nullptr;\nfloat *glArrayColors = nullptr;\n\nvoid QtSLiM_AllocateGLBuffers(void)\n{\n    if (!glArrayVertices)\n        glArrayVertices = static_cast<float *>(malloc(kMaxVertices * 2 * sizeof(float)));\t\t// 2 floats per vertex, kMaxVertices vertices\n    \n    if (!glArrayColors)\n        glArrayColors = static_cast<float *>(malloc(kMaxVertices * 4 * sizeof(float)));\t\t// 4 floats per color, kMaxVertices colors\n}\n\nvoid QtSLiM_FreeGLBuffers(void)\n{\n    if (glArrayVertices)\n    {\n        free(glArrayVertices);\n        glArrayVertices = nullptr;\n    }\n    \n    if (glArrayColors)\n    {\n        free(glArrayColors);\n        glArrayColors = nullptr;\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMOpenGL.h",
    "content": "//\n//  QtSLiMOpenGL.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMOPENGL_H\n#define QTSLIMOPENGL_H\n\n\n/*\n * This header defines utility macros and functions for drawing with OpenGL.\n * This should be included only locally within OpenGL-specific rendering code.\n */\n\n\n// OpenGL buffers for rendering; shared across all rendering code\n// These buffers are allocated by QtSLiMAppDelegate at launch\n#define kMaxGLRects 4000\t\t\t\t// 4000 rects\n#define kMaxVertices (kMaxGLRects * 4)\t// 4 vertices each\n\nextern float *glArrayVertices;\nextern float *glArrayColors;\n\nextern void QtSLiM_AllocateGLBuffers(void);\nextern void QtSLiM_FreeGLBuffers(void);\n\n\n#define SLIM_GL_PREPARE()\t\t\t\t\t\t\t\t\t\t\\\n\tint displayListIndex = 0;\t\t\t\t\t\t\t\t\t\\\n\tfloat *vertices = glArrayVertices, *colors = glArrayColors;\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tglEnableClientState(GL_VERTEX_ARRAY);\t\t\t\t\t\t\\\n\tglVertexPointer(2, GL_FLOAT, 0, glArrayVertices);\t\t\t\\\n\tglEnableClientState(GL_COLOR_ARRAY);\t\t\t\t\t\t\\\n\tglColorPointer(4, GL_FLOAT, 0, glArrayColors);\n\n#define SLIM_GL_DEFCOORDS(rect)                                 \\\n\tfloat left = static_cast<float>(rect.left());               \\\n\tfloat top = static_cast<float>(rect.top());                 \\\n\tfloat right = left + static_cast<float>(rect.width());      \\\n\tfloat bottom = top + static_cast<float>(rect.height());\n\n#define SLIM_GL_PUSHRECT()\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = left;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = top;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = left;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = bottom;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = right;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = bottom;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = right;\t\t\t\t\t\t\t\t\t\t\\\n\t*(vertices++) = top;\n\n#define SLIM_GL_PUSHRECT_COLORS()\t\t\t\t\t\t\t\t\\\n\tfor (int j = 0; j < 4; ++j)\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t*(colors++) = colorRed;\t\t\t\t\t\t\t\t\t\\\n\t\t*(colors++) = colorGreen;\t\t\t\t\t\t\t\t\\\n\t\t*(colors++) = colorBlue;\t\t\t\t\t\t\t\t\\\n\t\t*(colors++) = colorAlpha;\t\t\t\t\t\t\t\t\\\n\t}\n\n#define SLIM_GL_CHECKBUFFERS()\t\t\t\t\t\t\t\t\t\\\n\tdisplayListIndex++;\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tif (displayListIndex == kMaxGLRects)\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tvertices = glArrayVertices;\t\t\t\t\t\t\t\t\\\n\t\tcolors = glArrayColors;\t\t\t\t\t\t\t\t\t\\\n\t\tdisplayListIndex = 0;\t\t\t\t\t\t\t\t\t\\\n\t}\n\n#define SLIM_GL_FINISH()\t\t\t\t\t\t\t\t\t\t\\\n\tif (displayListIndex)\t\t\t\t\t\t\t\t\t\t\\\n\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tglDisableClientState(GL_VERTEX_ARRAY);\t\t\t\t\t\t\\\n\tglDisableClientState(GL_COLOR_ARRAY);\n\n\n#endif // QTSLIMOPENGL_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMOpenGL_Emulation.h",
    "content": "//\n//  QtSLiMOpenGL_Emulation.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/25/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMOPENGL_EMULATION_H\n#define QTSLIMOPENGL_EMULATION_H\n\n\n/*\n * This header defines utility macros and functions for drawing with OpenGL, but they are emulated with Qt.\n * This should be included only locally within Qt-specific rendering code.  See also QtSLiMOpenGL.h.\n */\n\n\n#define SLIM_GL_PREPARE()\n\n#define SLIM_GL_DEFCOORDS(rect)                                 \\\n    QRect &RECT_TO_DRAW = rect;\n\n#define SLIM_GL_PUSHRECT()\n\n#define SLIM_GL_PUSHRECT_COLORS()\n\n#define SLIM_GL_CHECKBUFFERS()                                                  \\\n    {                                                                           \\\n        QColor COLOR_TO_DRAW;                                                   \\\n        COLOR_TO_DRAW.setRgbF(colorRed, colorGreen, colorBlue, colorAlpha);     \\\n        painter.fillRect(RECT_TO_DRAW, COLOR_TO_DRAW);                          \\\n    }\n\n#define SLIM_GL_CHECKBUFFERS_NORECT()                                           \\\n{                                                                               \\\n        QColor COLOR_TO_DRAW;                                                   \\\n        COLOR_TO_DRAW.setRgbF(colorRed, colorGreen, colorBlue, colorAlpha);     \\\n        QRect RECT_TO_DRAW(left, top, right-left, bottom-top);                  \\\n        painter.fillRect(RECT_TO_DRAW, COLOR_TO_DRAW);                          \\\n}\n\n#define SLIM_GL_FINISH()\n\n\n#endif // QTSLIMOPENGL_EMULATION_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMPopulationTable.cpp",
    "content": "//\n//  QtSLiMPopulationTable.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMPopulationTable.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"subpopulation.h\"\n\n#include <QDebug>\n\n#include <utility>\n#include <vector>\n\n\nQtSLiMPopulationTableModel::QtSLiMPopulationTableModel(QObject *p_parent) : QAbstractTableModel(p_parent)\n{\n    // p_parent must be a pointer to QtSLiMWindow, which holds our model information\n    if (dynamic_cast<QtSLiMWindow *>(p_parent) == nullptr)\n        throw p_parent;\n}\n\nQtSLiMPopulationTableModel::~QtSLiMPopulationTableModel() \n{\n}\n\nint QtSLiMPopulationTableModel::rowCount(const QModelIndex & /* parent */) const\n{\n    return static_cast<int>(displaySubpops.size());\n}\n\nint QtSLiMPopulationTableModel::columnCount(const QModelIndex & /* parent */) const\n{\n    return 6;\n}\n\nQVariant QtSLiMPopulationTableModel::data(const QModelIndex &p_index, int role) const\n{\n    if (!p_index.isValid())\n        return QVariant();\n    \n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    int subpopCount = static_cast<int>(displaySubpops.size());\n    \n    if (subpopCount == 0)\n        return QVariant();\n    \n    if (role == Qt::DisplayRole)\n    {\n        if (p_index.row() < subpopCount)\n        {\n            auto popIter = displaySubpops.begin();\n            \n            std::advance(popIter, p_index.row());\n            Subpopulation *subpop = *popIter;\n            Species *species = &(subpop->species_);\n            \n            // BCH 3/21/2024: This check is a debugging leftover that should stay permanently.  The display list\n            // for the population table was out of date and contained subpopulations that had been deallocated,\n            // leading to a crash.  This was a very hard bug to find, so it's worth keeping this code here.  The\n            // bug was fixed with needsUpdateForDisplaySubpops() in QtSLiMPopulationTableModel.  \n            if (species == nullptr)\n            {\n                qDebug() << \"INVALID SUBPOPULATION in QtSLiMPopulationTableModel::data()!\";\n                qApp->beep();\n            }\n            \n            if (p_index.column() == 0)\n            {\n                QString idString = QString(\"p%1\").arg(subpop->subpopulation_id_);\n                \n                if (community->all_species_.size() > 1)\n                    idString.append(\" \").append(QString::fromStdString(species->avatar_));\n                \n                return QVariant(idString);\n            }\n            else if (p_index.column() == 1)\n            {\n                return QVariant(QString(\"%1\").arg(subpop->parent_subpop_size_));\n            }\n            else if (community->ModelType() == SLiMModelType::kModelTypeNonWF)\n            {\n                // in nonWF models selfing/cloning/sex rates/ratios are emergent, calculated from collected metrics\n                double total_offspring = subpop->gui_offspring_cloned_M_ + subpop->gui_offspring_crossed_ + subpop->gui_offspring_empty_ + subpop->gui_offspring_selfed_;\n                \n                if (subpop->sex_enabled_)\n                    total_offspring += subpop->gui_offspring_cloned_F_;\t\t// avoid double-counting clones when we are modeling hermaphrodites\n                \n                if (p_index.column() == 2)\n                {\n                    if (!subpop->sex_enabled_ && (total_offspring > 0))\n                        return QVariant(QString(\"%1\").arg(subpop->gui_offspring_selfed_ / total_offspring, 0, 'f', 2));\n                }\n                else if (p_index.column() == 3)\n                {\n                    if (total_offspring > 0)\n                        return QVariant(QString(\"%1\").arg(subpop->gui_offspring_cloned_F_ / total_offspring, 0, 'f', 2));\n                }\n                else if (p_index.column() == 4)\n                {\n                    if (total_offspring > 0)\n                        return QVariant(QString(\"%1\").arg(subpop->gui_offspring_cloned_M_ / total_offspring, 0, 'f', 2));\n                }\n                else if (p_index.column() == 5)\n                {\n                    if (subpop->sex_enabled_ && (subpop->parent_subpop_size_ > 0))\n                        return QVariant(QString(\"%1\").arg(1.0 - subpop->parent_first_male_index_ / static_cast<double>(subpop->parent_subpop_size_), 0, 'f', 2));\n                }\n                \n                return QVariant(\"—\");\n            }\n            else\t// sim->ModelType() == SLiMModelType::kModelTypeWF\n            {\n                if (p_index.column() == 2)\n                {\n                    if (subpop->sex_enabled_)\n                        return QVariant(\"—\");\n                    else\n                        return QVariant(QString(\"%1\").arg(subpop->selfing_fraction_, 0, 'f', 2));\n                }\n                else if (p_index.column() == 3)\n                {\n                    return QVariant(QString(\"%1\").arg(subpop->female_clone_fraction_, 0, 'f', 2));\n                }\n                else if (p_index.column() == 4)\n                {\n                    return QVariant(QString(\"%1\").arg(subpop->male_clone_fraction_, 0, 'f', 2));\n                }\n                else if (p_index.column() == 5)\n                {\n                    if (subpop->sex_enabled_)\n                        return QVariant(QString(\"%1\").arg(subpop->parent_sex_ratio_, 0, 'f', 2));\n                    else\n                        return QVariant(\"—\");\n                }\n            }\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (p_index.column())\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 4: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 5: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n\nQVariant QtSLiMPopulationTableModel::headerData(int section,\n                                Qt::Orientation /* p_orientation */,\n                                int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"ID\");\n        case 1: return QVariant(\"N\");\n        //case 2: return QVariant(\"self\");\n        //case 3: return QVariant(\"clF\");\n        //case 4: return QVariant(\"clM\");\n        //case 5: return QVariant(\"SR\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"the Eidos identifier for the subpopulation\");\n        case 1: return QVariant(\"the subpopulation size\");\n        case 2: return QVariant(\"the selfing rate of the subpopulation\");\n        case 3: return QVariant(\"the cloning rate of the subpopulation, for females\");\n        case 4: return QVariant(\"the cloning rate of the subpopulation, for males\");\n        case 5: return QVariant(\"the sex ratio of the subpopulation, M:(M+F)\");\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 4: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 5: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        }\n    }\n//    else if (role == Qt::DecorationRole)\n//    {\n//        switch (section)\n//        {\n//        case 2: return QVariant::fromValue(QIcon(QtSLiMImagePath(\"Qt_selfing_rate\", false)));\n//        case 3: return QVariant::fromValue(QIcon(QtSLiMImagePath(\"Qt_female_symbol\", false)));\n//        case 4: return QVariant::fromValue(QIcon(QtSLiMImagePath(\"Qt_male_symbol\", false)));\n//        case 5: return QVariant::fromValue(QIcon(QtSLiMImagePath(\"Qt_sex_ratio\", false)));\n//        }\n//    }\n    return QVariant();\n}\n\nbool QtSLiMPopulationTableModel::needsUpdateForDisplaySubpops(std::vector<Subpopulation *> &newDisplayList)\n{\n    // Checks whether our cached display list is out of date; if it is, a reload needs to be forced.\n    return (displaySubpops != newDisplayList);\n}\n\nvoid QtSLiMPopulationTableModel::reloadTable(std::vector<Subpopulation *> &newDisplayList)\n{\n    beginResetModel();\n    \n    // recache the list of subpopulations we display\n    std::swap(displaySubpops, newDisplayList);\n    newDisplayList.clear();\n    \n    endResetModel();\n}\n\nQtSLiMPopulationTableHeaderView::QtSLiMPopulationTableHeaderView(Qt::Orientation p_orientation, QWidget *p_parent) : QHeaderView(p_orientation, p_parent)\n{\n    cacheIcons();\n    \n    // Recache our icons if the light mode  / dark mode setting changes\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, [this]() { freeCachedIcons(); cacheIcons(); });\n}\n\nvoid QtSLiMPopulationTableHeaderView::freeCachedIcons(void)\n{\n    if (icon_cloning_rate)\n    {\n        delete icon_cloning_rate;\n        icon_cloning_rate = nullptr;\n    }\n    if (icon_selfing_rate)\n    {\n        delete icon_selfing_rate;\n        icon_selfing_rate = nullptr;\n    }\n    if (icon_sex_ratio)\n    {\n        delete icon_sex_ratio;\n        icon_sex_ratio = nullptr;\n    }\n    if (icon_female_symbol)\n    {\n        delete icon_female_symbol;\n        icon_female_symbol = nullptr;\n    }\n    if (icon_male_symbol)\n    {\n        delete icon_male_symbol;\n        icon_male_symbol = nullptr;\n    }\n}\n\nvoid QtSLiMPopulationTableHeaderView::cacheIcons(void)\n{\n    // Note that this caches the icons for the current light mode / dark mode setting; they will be recached if the mode changes\n    icon_cloning_rate = new QIcon(QtSLiMImagePath(\"Qt_cloning_rate\", false));\n    icon_selfing_rate = new QIcon(QtSLiMImagePath(\"Qt_selfing_rate\", false));\n    icon_sex_ratio = new QIcon(QtSLiMImagePath(\"Qt_sex_ratio\", false));\n    icon_female_symbol = new QIcon(QtSLiMImagePath(\"Qt_female_symbol\", false));\n    icon_male_symbol = new QIcon(QtSLiMImagePath(\"Qt_male_symbol\", false));    \n}\n\nQtSLiMPopulationTableHeaderView::~QtSLiMPopulationTableHeaderView()\n{\n    freeCachedIcons();\n}\n\nvoid QtSLiMPopulationTableHeaderView::paintSection(QPainter *painter, const QRect &p_rect, int p_logicalIndex) const\n{\n    painter->save();\n    QHeaderView::paintSection(painter, p_rect, p_logicalIndex);\n    painter->restore();\n    \n    painter->save();\n    painter->setRenderHint(QPainter::SmoothPixmapTransform);\n    \n    switch (p_logicalIndex)\n    {\n    case 2:\n    case 5:\n    {\n        QIcon *icon = (p_logicalIndex == 2 ? icon_selfing_rate : icon_sex_ratio);\n        QPoint center = p_rect.center();\n        \n        icon->paint(painter, center.x() - 5, center.y() - 6, 12, 12);\n        break;\n    }\n    case 3:\n    {\n        QIcon *icon1 = icon_cloning_rate;\n        QIcon *icon2 = icon_female_symbol;\n        QPoint center = p_rect.center();\n        \n        icon1->paint(painter, center.x() - 11, center.y() - 6, 12, 12);\n        icon2->paint(painter, center.x() + 1, center.y() - 6, 12, 12);\n        break;\n    }\n    case 4:\n    {\n        QIcon *icon1 = icon_cloning_rate;\n        QIcon *icon2 = icon_male_symbol;\n        QPoint center = p_rect.center();\n        \n        icon1->paint(painter, center.x() - 13, center.y() - 6, 12, 12);\n        icon2->paint(painter, center.x() + 1, center.y() - 6, 12, 12);\n        break;\n    }\n    default: break;\n    }\n    \n    painter->restore();\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMPopulationTable.h",
    "content": "//\n//  QtSLiMPopulationTable.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/30/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMPOPULATIONTABLE_H\n#define QTSLIMPOPULATIONTABLE_H\n\n#include <QObject>\n#include <QAbstractTableModel>\n#include <QHeaderView>\n\nclass QPainter;\nclass Subpopulation;\n\n\nclass QtSLiMPopulationTableModel : public QAbstractTableModel\n{\n    Q_OBJECT    \n    \npublic:\n    QtSLiMPopulationTableModel(QObject *p_parent = nullptr);\n    virtual ~QtSLiMPopulationTableModel() override;\n\n    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;\n    virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;\n\n    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;\n    virtual QVariant headerData(int section, Qt::Orientation p_orientation, int role = Qt::DisplayRole) const override;\n    \n    bool needsUpdateForDisplaySubpops(std::vector<Subpopulation *> &newDisplayList);\n    void reloadTable(std::vector<Subpopulation *> &newDisplayList);\n    \n    Subpopulation *subpopAtIndex(int i) const { return displaySubpops[i]; }\n    \nprotected:\n    // We cache a list of the subpopulations we are displaying, for more efficient display\n    std::vector<Subpopulation *> displaySubpops;\n};\n\nclass QtSLiMPopulationTableHeaderView : public QHeaderView\n{\n    Q_OBJECT\n    \n    QIcon *icon_cloning_rate = nullptr;\n    QIcon *icon_selfing_rate = nullptr;\n    QIcon *icon_sex_ratio = nullptr;\n    QIcon *icon_female_symbol = nullptr;\n    QIcon *icon_male_symbol = nullptr;\n    \npublic:\n    QtSLiMPopulationTableHeaderView(Qt::Orientation p_orientation, QWidget *p_parent = nullptr);\n    virtual ~QtSLiMPopulationTableHeaderView() override;\n    \n    virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override;\n    \nprotected:\n    void freeCachedIcons(void);\n    void cacheIcons(void);\n};\n\n\n#endif // QTSLIMPOPULATIONTABLE_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMPreferences.cpp",
    "content": "//\n//  QtSLiMPreferences.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/3/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMPreferences.h\"\n#include \"ui_QtSLiMPreferences.h\"\n\n#include <QSettings>\n#include <QFontMetricsF>\n#include <QDebug>\n\n#include \"QtSLiMAppDelegate.h\"\n\n\n//\n//  QSettings keys for the prefs we control; these are private\n//\n\nstatic const char *QtSLiMAppStartupAction = \"QtSLiMAppStartupAction\";\nstatic const char *QtSLiMForceDarkMode = \"QtSLiMForceDarkMode\";\nstatic const char *QtSLiMForceFusionStyle = \"QtSLiMForceFusionStyle\";\nstatic const char *QtSLiMUseOpenGL = \"QtSLiMUseOpenGL\";\nstatic const char *QtSLiMDisplayFontFamily = \"QtSLiMDisplayFontFamily\";\nstatic const char *QtSLiMDisplayFontSize = \"QtSLiMDisplayFontSize\";\nstatic const char *QtSLiMSyntaxHighlightScript = \"QtSLiMSyntaxHighlightScript\";\nstatic const char *QtSLiMSyntaxHighlightOutput = \"QtSLiMSyntaxHighlightOutput\";\nstatic const char *QtSLiMShowLineNumbers = \"QtSLiMShowLineNumbers\";\nstatic const char *QtSLiMShowPageGuide = \"QtSLiMShowPageGuide\";\nstatic const char *QtSLiMPageGuideColumn = \"QtSLiMPageGuideColumn\";\nstatic const char *QtSLiMHighlightCurrentLine = \"QtSLiMHighlightCurrentLine\";\nstatic const char *QtSLiMAutosaveOnRecycle = \"QtSLiMAutosaveOnRecycle\";\nstatic const char *QtSLiMShowSaveInUntitled = \"QtSLiMShowSaveInUntitled\";\nstatic const char *QtSLiMReloadOnSafeExternalEdits = \"QtSLiMReloadOnSafeExternalEdits\";\n\n\nstatic QFont &defaultDisplayFont(void)\n{\n    // This function determines the default font chosen when the user has expressed no preference.\n    // It depends upon font availability, so it can't be hard-coded.\n    static QFont *defaultFont = nullptr;\n    \n    if (!defaultFont)\n    {\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n        QFontDatabase fontdb;\n        QStringList families = fontdb.families();\n#else\n        QStringList families = QFontDatabase::families();\n#endif\n        \n        // Use filter() to look for matches, since the foundry can be appended after the name (why isn't this easier??)\n        if (families.filter(\"Consola\").size() > 0)                 // good on Windows\n            defaultFont = new QFont(\"Consola\", 13);\n        else if (families.filter(\"Courier New\").size() > 0)         // good on Mac\n            defaultFont = new QFont(\"Courier New\", 13);\n        else if (families.filter(\"Menlo\").size() > 0)               // good on Mac\n            defaultFont = new QFont(\"Menlo\", 12);\n        else if (families.filter(\"Ubuntu Mono\").size() > 0)         // good on Ubuntu\n            defaultFont = new QFont(\"Ubuntu Mono\", 11);\n        else if (families.filter(\"DejaVu Sans Mono\").size() > 0)    // good on Ubuntu\n            defaultFont = new QFont(\"DejaVu Sans Mono\", 9);\n        else\n            defaultFont = new QFont(\"Courier\", 10);                 // a reasonable default that should be omnipresent\n    }\n    \n    return *defaultFont;\n}\n\n\n//\n//  QtSLiMPreferencesNotifier: the pref supplier and notifier\n//\n\nQtSLiMPreferencesNotifier &QtSLiMPreferencesNotifier::instance(void)\n{\n    static QtSLiMPreferencesNotifier *inst = nullptr;\n    \n    if (!inst)\n        inst = new QtSLiMPreferencesNotifier();\n    \n    return *inst;\n}\n\n// pref value fetching\n\nint QtSLiMPreferencesNotifier::appStartupPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMAppStartupAction, QVariant(1)).toInt();\n}\n\nbool QtSLiMPreferencesNotifier::forceDarkModePref(void)\n{\n#ifdef __APPLE__\n    // On macOS this pref is always considered to be false\n    return false;\n#endif\n    \n    QSettings settings;\n    \n    return settings.value(QtSLiMForceDarkMode, QVariant(false)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::forceFusionStylePref(void)\n{\n#ifdef __APPLE__\n    // On macOS this pref is always considered to be false\n    return false;\n#endif\n    \n    QSettings settings;\n    \n    return settings.value(QtSLiMForceFusionStyle, QVariant(false)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::useOpenGLPref(void)\n{\n#ifndef SLIM_NO_OPENGL\n    QSettings settings;\n\n#ifdef _WIN32\n    // BCH 3/23/2025: Too many people are getting bitten by OpenGL not working properly on\n    // Windows, for reasons that have not been diagnosed.  Turning this off on Windows.\n    // It runs a little slower, but there will be a lot less confusion.\n    return settings.value(QtSLiMUseOpenGL, QVariant(false)).toBool();\n#else\n    return settings.value(QtSLiMUseOpenGL, QVariant(true)).toBool();\n#endif\n#else\n    return false;\n#endif\n}\n\nQFont QtSLiMPreferencesNotifier::displayFontPref(double *tabWidth) const\n{\n    QFont &defaultFont = defaultDisplayFont();\n    QString defaultFamily = defaultFont.family();\n    int defaultSize = defaultFont.pointSize();\n    \n    QSettings settings;\n    QString fontFamily = settings.value(QtSLiMDisplayFontFamily, QVariant(defaultFamily)).toString();\n    int fontSize = settings.value(QtSLiMDisplayFontSize, QVariant(defaultSize)).toInt();\n    QFont font(fontFamily, fontSize);\n    \n    font.setFixedPitch(true);    // I think this is a hint to help QFont match to similar fonts?\n    \n    if (tabWidth)\n    {\n        QFontMetricsF fm(font);\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        *tabWidth = fm.width(\"   \");                // deprecated in 5.11\n#else\n        *tabWidth = fm.horizontalAdvance(\"   \");    // added in Qt 5.11\n#endif\n    }\n    \n    return font;\n}\n\nbool QtSLiMPreferencesNotifier::scriptSyntaxHighlightPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMSyntaxHighlightScript, QVariant(true)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::outputSyntaxHighlightPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMSyntaxHighlightOutput, QVariant(true)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::showLineNumbersPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMShowLineNumbers, QVariant(true)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::highlightCurrentLinePref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMHighlightCurrentLine, QVariant(true)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::showPageGuidePref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMShowPageGuide, QVariant(false)).toBool();\n}\n\nint QtSLiMPreferencesNotifier::pageGuideColumnPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMPageGuideColumn, QVariant(80)).toInt();\n}\n\nbool QtSLiMPreferencesNotifier::autosaveOnRecyclePref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMAutosaveOnRecycle, QVariant(false)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::showSaveIfUntitledPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMShowSaveInUntitled, QVariant(false)).toBool();\n}\n\nbool QtSLiMPreferencesNotifier::reloadOnSafeExternalEditsPref(void) const\n{\n    QSettings settings;\n    \n    return settings.value(QtSLiMReloadOnSafeExternalEdits, QVariant(false)).toBool();\n}\n\nvoid QtSLiMPreferencesNotifier::displayFontBigger(void)\n{\n    QFont &defaultFont = defaultDisplayFont();\n    int defaultSize = defaultFont.pointSize();\n    \n    QSettings settings;\n    int fontSize = settings.value(QtSLiMDisplayFontSize, QVariant(defaultSize)).toInt();\n    \n    if (fontSize < 50)  // matches value in QtSLiMPreferences.ui\n    {\n        // if the prefs window exists, we need to tell it to adjust itself\n        // if not, we send ourselves the message it would have sent us\n        QtSLiMPreferences *prefsWindow = QtSLiMPreferences::instanceForcingAllocation(false);\n        \n        if (prefsWindow)\n            prefsWindow->ui->fontSizeSpinBox->setValue(fontSize + 1);\n        else\n            fontSizeChanged(fontSize + 1);            \n    }\n    else\n        qApp->beep();\n}\n\nvoid QtSLiMPreferencesNotifier::displayFontSmaller(void)\n{\n    QFont &defaultFont = defaultDisplayFont();\n    int defaultSize = defaultFont.pointSize();\n    \n    QSettings settings;\n    int fontSize = settings.value(QtSLiMDisplayFontSize, QVariant(defaultSize)).toInt();\n    \n    if (fontSize > 6)  // matches value in QtSLiMPreferences.ui\n    {\n        // if the prefs window exists, we need to tell it to adjust itself\n        // if not, we send ourselves the message it would have sent us\n        QtSLiMPreferences *prefsWindow = QtSLiMPreferences::instanceForcingAllocation(false);\n        \n        if (prefsWindow)\n            prefsWindow->ui->fontSizeSpinBox->setValue(fontSize - 1);\n        else\n            fontSizeChanged(fontSize - 1);            \n    }\n    else\n        qApp->beep();\n}\n\n\n// slots; these update the settings and then emit new signals\n\nvoid QtSLiMPreferencesNotifier::startupRadioChanged()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    if (prefsUI.ui->startupRadioCreateNew->isChecked())\n        settings.setValue(QtSLiMAppStartupAction, QVariant(1));\n    else if (prefsUI.ui->startupRadioOpenFile->isChecked())\n        settings.setValue(QtSLiMAppStartupAction, QVariant(2));\n    \n    emit appStartupPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::forceDarkModeToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMForceDarkMode, QVariant(prefsUI.ui->forceDarkMode->isChecked()));\n    \n    // no signal is emitted for this pref; it takes effect on the next restart of the app\n    //emit forceDarkModePrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::forceFusionStyleToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMForceFusionStyle, QVariant(prefsUI.ui->forceFusionStyle->isChecked()));\n    \n    // no signal is emitted for this pref; it takes effect on the next restart of the app\n    //emit forceFusionStylePrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::useOpenGLToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMUseOpenGL, QVariant(prefsUI.ui->useOpenGL->isChecked()));\n    \n    emit useOpenGLPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::fontChanged(const QFont &newFont)\n{\n    QString fontFamily = newFont.family();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMDisplayFontFamily, QVariant(fontFamily));\n    \n    emit displayFontPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::fontSizeChanged(int newSize)\n{\n    QSettings settings;\n    \n    settings.setValue(QtSLiMDisplayFontSize, QVariant(newSize));\n    \n    emit displayFontPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::syntaxHighlightScriptToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMSyntaxHighlightScript, QVariant(prefsUI.ui->syntaxHighlightScript->isChecked()));\n    \n    emit scriptSyntaxHighlightPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::syntaxHighlightOutputToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMSyntaxHighlightOutput, QVariant(prefsUI.ui->syntaxHighlightOutput->isChecked()));\n    \n    emit outputSyntaxHighlightPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::showLineNumbersToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMShowLineNumbers, QVariant(prefsUI.ui->showLineNumbers->isChecked()));\n    \n    emit showLineNumbersPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::highlightCurrentLineToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMHighlightCurrentLine, QVariant(prefsUI.ui->highlightCurrentLine->isChecked()));\n    \n    emit highlightCurrentLinePrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::showPageGuideToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMShowPageGuide, QVariant(prefsUI.ui->showPageGuide->isChecked()));\n    \n    emit pageGuidePrefsChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::pageGuideColumnChanged(int newColumn)\n{\n    QSettings settings;\n    \n    settings.setValue(QtSLiMPageGuideColumn, QVariant(newColumn));\n    \n    emit pageGuidePrefsChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::autosaveOnRecycleToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMAutosaveOnRecycle, QVariant(prefsUI.ui->autosaveOnRecycle->isChecked()));\n    \n    emit autosaveOnRecyclePrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::showSaveIfUntitledToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMShowSaveInUntitled, QVariant(prefsUI.ui->showSaveIfUntitled->isChecked()));\n    \n    emit showSaveIfUntitledPrefChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::reloadOnSafeExternalEditsToggled()\n{\n    QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance();\n    QSettings settings;\n    \n    settings.setValue(QtSLiMReloadOnSafeExternalEdits, QVariant(prefsUI.ui->reloadOnSafeExternalEdits->isChecked()));\n    \n    emit reloadOnSafeExternalEditsChanged();\n}\n\nvoid QtSLiMPreferencesNotifier::resetSuppressedClicked()\n{\n    // All \"do not show this again\" settings should be removed here\n    // There is no signal rebroadcast for this; nobody should cache these flags\n    QSettings settings;\n    settings.remove(\"QtSLiMSuppressScriptCheckSuccessPanel\");\n}\n\n\n//\n//  QtSLiMPreferences: the actual UI class\n//\n\nQtSLiMPreferences *QtSLiMPreferences::instanceForcingAllocation(bool force_allocation)\n{\n    static QtSLiMPreferences *inst = nullptr;\n    \n    if (!inst && force_allocation)\n        inst = new QtSLiMPreferences(nullptr);\n    \n    return inst;\n}\n\nQtSLiMPreferences &QtSLiMPreferences::instance(void)\n{\n    return *QtSLiMPreferences::instanceForcingAllocation(true);\n}\n\nQtSLiMPreferences::QtSLiMPreferences(QWidget *p_parent) : QDialog(p_parent), ui(new Ui::QtSLiMPreferences)\n{\n    ui->setupUi(this);\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // set the initial state of the UI elements from QtSLiMPreferencesNotifier\n    QtSLiMPreferencesNotifier *notifier = &QtSLiMPreferencesNotifier::instance();\n    \n    ui->startupRadioCreateNew->setChecked(notifier->appStartupPref() == 1);\n    ui->startupRadioOpenFile->setChecked(notifier->appStartupPref() == 2);\n    \n    ui->fontComboBox->setCurrentFont(notifier->displayFontPref());\n    ui->fontSizeSpinBox->setValue(notifier->displayFontPref().pointSize());\n    \n    ui->syntaxHighlightScript->setChecked(notifier->scriptSyntaxHighlightPref());\n    ui->syntaxHighlightOutput->setChecked(notifier->outputSyntaxHighlightPref());\n    \n    ui->showLineNumbers->setChecked(notifier->showLineNumbersPref());\n    ui->highlightCurrentLine->setChecked(notifier->highlightCurrentLinePref());\n    \n    // the presence of this hidden widget fixes a padding bug; see https://forum.qt.io/topic/10757/unwanted-padding-around-qhboxlayout\n    ui->pageGuideNoPadWidget->hide();\n    ui->showPageGuide->setChecked(notifier->showPageGuidePref());\n    ui->pageGuideSpinBox->setValue(notifier->pageGuideColumnPref());\n    \n    ui->autosaveOnRecycle->setChecked(notifier->autosaveOnRecyclePref());\n    ui->showSaveIfUntitled->setChecked(notifier->showSaveIfUntitledPref());\n    ui->showSaveIfUntitled->setEnabled(notifier->autosaveOnRecyclePref());\n    \n    ui->reloadOnSafeExternalEdits->setChecked(notifier->reloadOnSafeExternalEditsPref());\n    \n    // connect the UI elements to QtSLiMPreferencesNotifier\n    connect(ui->startupRadioOpenFile, &QRadioButton::toggled, notifier, &QtSLiMPreferencesNotifier::startupRadioChanged);\n    connect(ui->startupRadioCreateNew, &QRadioButton::toggled, notifier, &QtSLiMPreferencesNotifier::startupRadioChanged);\n    \n    connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, notifier, &QtSLiMPreferencesNotifier::fontChanged);\n    connect(ui->fontSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), notifier, &QtSLiMPreferencesNotifier::fontSizeChanged);\n\n    connect(ui->syntaxHighlightScript, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::syntaxHighlightScriptToggled);\n    connect(ui->syntaxHighlightOutput, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::syntaxHighlightOutputToggled);\n    \n    connect(ui->showLineNumbers, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showLineNumbersToggled);\n    connect(ui->highlightCurrentLine, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::highlightCurrentLineToggled);\n    connect(ui->showPageGuide, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showPageGuideToggled);\n    connect(ui->pageGuideSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), notifier, &QtSLiMPreferencesNotifier::pageGuideColumnChanged);\n    \n    connect(ui->autosaveOnRecycle, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::autosaveOnRecycleToggled);\n    connect(ui->showSaveIfUntitled, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showSaveIfUntitledToggled);\n    connect(notifier, &QtSLiMPreferencesNotifier::autosaveOnRecyclePrefChanged, this, [this, notifier]() { ui->showSaveIfUntitled->setEnabled(notifier->autosaveOnRecyclePref()); });\n    \n    connect(ui->reloadOnSafeExternalEdits, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::reloadOnSafeExternalEditsToggled);\n    \n    connect(ui->resetSuppressedButton, &QPushButton::clicked, notifier, &QtSLiMPreferencesNotifier::resetSuppressedClicked);\n    \n    // handle the user interface display prefs, which are hidden and disconnected on macOS\n    ui->useOpenGL->setChecked(notifier->useOpenGLPref());\n    \n    connect(ui->useOpenGL, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::useOpenGLToggled);\n\n#ifdef __APPLE__\n    // This old code hid the UI prefs entirely on macOS\n//    ui->uiAppearanceGroup->setHidden(true);\n//    ui->verticalSpacer_uiAppearance->changeSize(0, 0);\n//    ui->verticalSpacer_uiAppearance->invalidate();\n//    ui->verticalLayout->invalidate();\n    \n    // This new code leaves the \"Use OpenGL for speed\" checkbox visible and hides the rest\n    ui->requireRelaunchLabel->setHidden(true);\n    ui->forceDarkMode->setHidden(true);\n    ui->forceFusionStyle->setHidden(true);\n    ui->verticalSpacer_requireRelaunch->changeSize(0, 0);\n    ui->verticalSpacer_requireRelaunch->invalidate();\n    ui->verticalLayout->invalidate();\n#else\n    ui->forceDarkMode->setChecked(notifier->forceDarkModePref());\n    ui->forceFusionStyle->setChecked(notifier->forceFusionStylePref());\n    \n    connect(ui->forceDarkMode, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::forceDarkModeToggled);\n    connect(ui->forceFusionStyle, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::forceFusionStyleToggled);\n#endif\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nQtSLiMPreferences::~QtSLiMPreferences()\n{\n    delete ui;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMPreferences.h",
    "content": "//\n//  QtSLiMPreferences.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/3/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMPREFERENCES_H\n#define QTSLIMPREFERENCES_H\n\n#include <QDialog>\n\n\n// This class provides a singleton object that interested parties can connect to\n// This separated design allows clients to connect before the prefs panel exists\n\nclass QtSLiMPreferencesNotifier : public QObject\n{\n    Q_OBJECT\n    \npublic:\n    static QtSLiMPreferencesNotifier &instance(void);\n    \n    // Get the current pref values, falling back on defaults\n    int appStartupPref(void) const;               // 0 == do nothing, 1 == create a new window, 2 == run an open panel\n    bool forceDarkModePref(void);\n    bool forceFusionStylePref(void);\n    bool useOpenGLPref(void);\n    QFont displayFontPref(double *tabWidth = nullptr) const;\n    bool scriptSyntaxHighlightPref(void) const;\n    bool outputSyntaxHighlightPref(void) const;\n    bool showLineNumbersPref(void) const;\n    bool showPageGuidePref(void) const;\n    int pageGuideColumnPref(void) const;\n    bool highlightCurrentLinePref(void) const;\n    bool autosaveOnRecyclePref(void) const;\n    bool reloadOnSafeExternalEditsPref(void) const;\n    bool showSaveIfUntitledPref(void) const;\n    \n    // Change preferences values in ways other than the Preferences panel itself\n    void displayFontBigger(void);\n    void displayFontSmaller(void);\n    \nsignals:\n    // Get notified when a pref value changes\n    void appStartupPrefChanged(void);\n    void useOpenGLPrefChanged(void);\n    void displayFontPrefChanged(void);\n    void scriptSyntaxHighlightPrefChanged(void);\n    void outputSyntaxHighlightPrefChanged(void);\n    void showLineNumbersPrefChanged(void);\n    void pageGuidePrefsChanged(void);\n    void highlightCurrentLinePrefChanged(void);\n    void autosaveOnRecyclePrefChanged(void);\n    void reloadOnSafeExternalEditsChanged(void);\n    void showSaveIfUntitledPrefChanged(void);\n    \nprivate:\n    // singleton pattern\n    QtSLiMPreferencesNotifier() = default;\n    ~QtSLiMPreferencesNotifier() = default;\n    QtSLiMPreferencesNotifier(const QtSLiMPreferencesNotifier&) = delete;\n    QtSLiMPreferencesNotifier& operator=(const QtSLiMPreferencesNotifier&) = delete;\n    \nprivate slots:\n    void startupRadioChanged();\n    void forceDarkModeToggled();\n    void forceFusionStyleToggled();\n    void useOpenGLToggled();\n    void fontChanged(const QFont &font);\n    void fontSizeChanged(int newSize);\n    void syntaxHighlightScriptToggled();\n    void syntaxHighlightOutputToggled();\n    void showLineNumbersToggled();\n    void showPageGuideToggled();\n    void pageGuideColumnChanged(int newColumn);\n    void highlightCurrentLineToggled();\n    void autosaveOnRecycleToggled();\n    void reloadOnSafeExternalEditsToggled();\n    void showSaveIfUntitledToggled();\n    void resetSuppressedClicked();\n    \n    friend class QtSLiMPreferences;\n};\n\n\n// This is the actual UI stuff\n\nnamespace Ui {\nclass QtSLiMPreferences;\n}\n\nclass QtSLiMPreferences : public QDialog\n{\n    Q_OBJECT\n    \npublic:\n    static QtSLiMPreferences *instanceForcingAllocation(bool force_allocation);\n    static QtSLiMPreferences &instance(void);\n    \nprivate:\n    // singleton pattern\n    explicit QtSLiMPreferences(QWidget *p_parent = nullptr);\n    QtSLiMPreferences() = default;\n    ~QtSLiMPreferences();\n    QtSLiMPreferences(const QtSLiMPreferencesNotifier&) = delete;\n    QtSLiMPreferences& operator=(const QtSLiMPreferencesNotifier&) = delete;\n    \nprivate:\n    Ui::QtSLiMPreferences *ui;\n    \n    friend class QtSLiMPreferencesNotifier;\n};\n\n\n#endif // QTSLIMPREFERENCES_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMPreferences.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMPreferences</class>\n <widget class=\"QDialog\" name=\"QtSLiMPreferences\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>303</width>\n    <height>780</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>SLiMgui Preferences</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>6</number>\n   </property>\n   <property name=\"sizeConstraint\">\n    <enum>QLayout::SetFixedSize</enum>\n   </property>\n   <property name=\"topMargin\">\n    <number>12</number>\n   </property>\n   <item>\n    <spacer name=\"verticalSpacer_7\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"startupGroup\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>When SLiMgui starts:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QRadioButton\" name=\"startupRadioCreateNew\">\n        <property name=\"toolTip\">\n         <string>a new untitled window with a default WF model will be created on startup</string>\n        </property>\n        <property name=\"text\">\n         <string>Create a new simulation window</string>\n        </property>\n        <property name=\"checked\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QRadioButton\" name=\"startupRadioOpenFile\">\n        <property name=\"toolTip\">\n         <string>the &quot;open file&quot; panel will be run at startup</string>\n        </property>\n        <property name=\"text\">\n         <string>Ask for a script file to open</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"uiAppearanceGroup\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>User interface appearance:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_7\" stretch=\"0,0,0,0,0\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QCheckBox\" name=\"useOpenGL\">\n        <property name=\"toolTip\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;use OpenGL for fast display; uncheck this if you experience display problems with the Individuals and Chromosome views&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n        <property name=\"text\">\n         <string>Use OpenGL for fast display</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <spacer name=\"verticalSpacer_requireRelaunch\">\n        <property name=\"orientation\">\n         <enum>Qt::Vertical</enum>\n        </property>\n        <property name=\"sizeType\">\n         <enum>QSizePolicy::Fixed</enum>\n        </property>\n        <property name=\"sizeHint\" stdset=\"0\">\n         <size>\n          <width>20</width>\n          <height>8</height>\n         </size>\n        </property>\n       </spacer>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"requireRelaunchLabel\">\n        <property name=\"text\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;Changes below require a relaunch to take effect.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QCheckBox\" name=\"forceDarkMode\">\n        <property name=\"toolTip\">\n         <string>force a &quot;dark mode&quot; color palette for the user interface appearance</string>\n        </property>\n        <property name=\"text\">\n         <string>Force a &quot;dark mode&quot; palette</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QCheckBox\" name=\"forceFusionStyle\">\n        <property name=\"toolTip\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;force the use of Qt's Fusion user interface style, which can make the &amp;quot;dark mode&amp;quot; appearance more consistent&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n        <property name=\"text\">\n         <string>Force the Fusion UI style</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_uiAppearance\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"displayFontGroup\">\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>Display font:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QFontComboBox\" name=\"fontComboBox\">\n        <property name=\"focusPolicy\">\n         <enum>Qt::NoFocus</enum>\n        </property>\n        <property name=\"toolTip\">\n         <string>the font to use for script and output views</string>\n        </property>\n        <property name=\"editable\">\n         <bool>false</bool>\n        </property>\n        <property name=\"writingSystem\">\n         <enum>QFontDatabase::Latin</enum>\n        </property>\n        <property name=\"fontFilters\">\n         <set>QFontComboBox::MonospacedFonts|QFontComboBox::ScalableFonts</set>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n        <item>\n         <widget class=\"QSpinBox\" name=\"fontSizeSpinBox\">\n          <property name=\"sizePolicy\">\n           <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n            <horstretch>0</horstretch>\n            <verstretch>0</verstretch>\n           </sizepolicy>\n          </property>\n          <property name=\"minimumSize\">\n           <size>\n            <width>50</width>\n            <height>0</height>\n           </size>\n          </property>\n          <property name=\"maximumSize\">\n           <size>\n            <width>50</width>\n            <height>16777215</height>\n           </size>\n          </property>\n          <property name=\"focusPolicy\">\n           <enum>Qt::StrongFocus</enum>\n          </property>\n          <property name=\"toolTip\">\n           <string>the font size to use for script and output views</string>\n          </property>\n          <property name=\"alignment\">\n           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n          </property>\n          <property name=\"minimum\">\n           <number>6</number>\n          </property>\n          <property name=\"maximum\">\n           <number>50</number>\n          </property>\n          <property name=\"value\">\n           <number>12</number>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QLabel\" name=\"label_4\">\n          <property name=\"sizePolicy\">\n           <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Preferred\">\n            <horstretch>0</horstretch>\n            <verstretch>0</verstretch>\n           </sizepolicy>\n          </property>\n          <property name=\"text\">\n           <string>points</string>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_2\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"syntaxHighlightingGroup\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>Enable syntax highlighting:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QCheckBox\" name=\"syntaxHighlightScript\">\n        <property name=\"toolTip\">\n         <string>enabled syntax highlighting in script views; this may cause poor performance with long scripts</string>\n        </property>\n        <property name=\"text\">\n         <string>In the script area</string>\n        </property>\n        <property name=\"checked\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QCheckBox\" name=\"syntaxHighlightOutput\">\n        <property name=\"toolTip\">\n         <string>enabled syntax highlighting in output views; this may cause poor performance with large amounts of output</string>\n        </property>\n        <property name=\"text\">\n         <string>In the output area</string>\n        </property>\n        <property name=\"checked\">\n         <bool>true</bool>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_5\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"lineNumberingGroup\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>Script view appearance:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\" stretch=\"0,0,0\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QCheckBox\" name=\"showLineNumbers\">\n        <property name=\"toolTip\">\n         <string>show line numbers in a gutter on the left of script views</string>\n        </property>\n        <property name=\"text\">\n         <string>Show line numbers</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QCheckBox\" name=\"highlightCurrentLine\">\n        <property name=\"toolTip\">\n         <string>highlight the current editing line in script views</string>\n        </property>\n        <property name=\"text\">\n         <string>Highlight current line</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"pageGuideLayout\" stretch=\"0,0,0,1\">\n        <item>\n         <widget class=\"QWidget\" name=\"pageGuideNoPadWidget\" native=\"true\"/>\n        </item>\n        <item>\n         <widget class=\"QCheckBox\" name=\"showPageGuide\">\n          <property name=\"text\">\n           <string>Page guide at column: </string>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"QSpinBox\" name=\"pageGuideSpinBox\">\n          <property name=\"minimumSize\">\n           <size>\n            <width>55</width>\n            <height>0</height>\n           </size>\n          </property>\n          <property name=\"focusPolicy\">\n           <enum>Qt::StrongFocus</enum>\n          </property>\n          <property name=\"alignment\">\n           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>\n          </property>\n          <property name=\"minimum\">\n           <number>1</number>\n          </property>\n          <property name=\"maximum\">\n           <number>999</number>\n          </property>\n          <property name=\"value\">\n           <number>80</number>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <spacer name=\"horizontalSpacer\">\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n          <property name=\"sizeHint\" stdset=\"0\">\n           <size>\n            <width>5</width>\n            <height>5</height>\n           </size>\n          </property>\n         </spacer>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_3\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"autosaveGroup\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>Autosave:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_6\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QCheckBox\" name=\"autosaveOnRecycle\">\n        <property name=\"toolTip\">\n         <string>save to disk automatically whenever the model is recycled</string>\n        </property>\n        <property name=\"text\">\n         <string>Autosave on every recycle</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QCheckBox\" name=\"showSaveIfUntitled\">\n        <property name=\"toolTip\">\n         <string>if autosave is enabled, run a &quot;save file&quot; panel if the model has not yet been saved</string>\n        </property>\n        <property name=\"text\">\n         <string>Show save panel if untitled</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_6\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QGroupBox\" name=\"uiAppearanceGroup_2\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"styleSheet\">\n      <string notr=\"true\">QGroupBox { font-weight: bold; }</string>\n     </property>\n     <property name=\"title\">\n      <string>External editing:</string>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_8\" stretch=\"0,0\">\n      <property name=\"spacing\">\n       <number>6</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>6</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>6</number>\n      </property>\n      <item>\n       <widget class=\"QCheckBox\" name=\"reloadOnSafeExternalEdits\">\n        <property name=\"toolTip\">\n         <string>reload externally edited files without user confirmation, if no unsaved changes in SLiMgui would be overwritten</string>\n        </property>\n        <property name=\"text\">\n         <string>Reload changes automatically</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QLabel\" name=\"label_2\">\n        <property name=\"text\">\n         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;(only if there are no unsaved changes)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"Line\" name=\"line\">\n     <property name=\"orientation\">\n      <enum>Qt::Horizontal</enum>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_4\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>8</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QPushButton\" name=\"resetSuppressedButton\">\n     <property name=\"text\">\n      <string>Reset suppressed alert panels</string>\n     </property>\n     <property name=\"autoDefault\">\n      <bool>false</bool>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"label_5\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"text\">\n      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;This resets all of the &amp;quot;do not show this&lt;br/&gt;message again&amp;quot; flags across SLiMgui.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMScriptTextEdit.cpp",
    "content": "//\n//  QtSLiMScriptTextEdit.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 11/24/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMScriptTextEdit.h\"\n\n#include <QApplication>\n#include <QGuiApplication>\n#include <QTextCursor>\n#include <QPaintEvent>\n#include <QMouseEvent>\n#include <QRegularExpression>\n#include <QStyle>\n#include <QAbstractTextDocumentLayout>\n#include <QMessageBox>\n#include <QSettings>\n#include <QCheckBox>\n#include <QMainWindow>\n#include <QStatusBar>\n#include <QCompleter>\n#include <QStringListModel>\n#include <QScrollBar>\n#include <QTextDocument>\n#include <QMenu>\n#include <QToolTip>\n#include <QClipboard>\n#include <QMimeData>\n#include <QDebug>\n\n#include <utility>\n#include <memory>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMEidosPrettyprinter.h\"\n#include \"QtSLiMSyntaxHighlighting.h\"\n#include \"QtSLiMEidosConsole.h\"\n#include \"QtSLiMHelpWindow.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiM_SLiMgui.h\"\n\n#include \"eidos_script.h\"\n#include \"eidos_token.h\"\n#include \"slim_eidos_block.h\"\n#include \"subpopulation.h\"\n#include \"eidos_interpreter.h\"\n#include \"interaction_type.h\"\n#include \"eidos_sorting.h\"\n\n\n//\n//  QtSLiMTextEdit\n//\n\nQtSLiMTextEdit::QtSLiMTextEdit(const QString &text, QWidget *p_parent) : QPlainTextEdit(text, p_parent)\n{\n    selfInit();\n}\n\nQtSLiMTextEdit::QtSLiMTextEdit(QWidget *p_parent) : QPlainTextEdit(p_parent)\n{\n    selfInit();\n}\n\nvoid QtSLiMTextEdit::selfInit(void)\n{\n    // track changes to undo/redo availability\n    connect(this, &QPlainTextEdit::undoAvailable, this, [this](bool b) { undoAvailable_ = b; });\n    connect(this, &QPlainTextEdit::redoAvailable, this, [this](bool b) { redoAvailable_ = b; });\n    connect(this, &QPlainTextEdit::copyAvailable, this, [this](bool b) { copyAvailable_ = b; });\n    \n    // clear the custom error background color whenever the selection changes\n    connect(this, &QPlainTextEdit::selectionChanged, this, [this]() { setPalette(qtslimStandardPalette()); });\n    connect(this, &QPlainTextEdit::cursorPositionChanged, this, [this]() { setPalette(qtslimStandardPalette()); });\n    \n    // because we mess with the palette, we have to reset it on dark mode changes; this resets the error\n    // highlighting if it is set up, which is a bug, but not one worth worrying about I suppose...\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, [this]() { setPalette(qtslimStandardPalette()); });\n    \n    // clear the status bar on a selection change\n    connect(this, &QPlainTextEdit::selectionChanged, this, &QtSLiMTextEdit::updateStatusFieldFromSelection);\n    connect(this, &QPlainTextEdit::cursorPositionChanged, this, &QtSLiMTextEdit::updateStatusFieldFromSelection);\n    \n    // BCH 28 August 2025: get rid of the annoying insertion point remnant shown briefly when the selection changes\n    // this is a dangerous change since it could, if there is a bug somewhere, make the insertion point disappear!\n    connect(this, &QPlainTextEdit::selectionChanged, this, [this]() { if (textCursor().hasSelection()) setCursorWidth(0); else setCursorWidth(1); });\n    connect(this, &QPlainTextEdit::cursorPositionChanged, this, [this]() { if (textCursor().hasSelection()) setCursorWidth(0); else setCursorWidth(1); });\n    \n    // Wire up to change the font when the display font pref changes\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::displayFontPrefChanged, this, &QtSLiMTextEdit::displayFontPrefChanged);\n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::scriptSyntaxHighlightPrefChanged, this, &QtSLiMTextEdit::scriptSyntaxHighlightPrefChanged);\n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::outputSyntaxHighlightPrefChanged, this, &QtSLiMTextEdit::outputSyntaxHighlightPrefChanged);\n    \n    // Get notified of modifier key changes, so we can change our cursor\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::modifiersChanged, this, &QtSLiMTextEdit::modifiersChanged);\n    \n    // set up tab stops based on the display font\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    double tabWidth = 0;\n    QFont scriptFont = prefs.displayFontPref(&tabWidth);\n    \n    setFont(scriptFont);\n#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))\n    setTabStopWidth((int)floor(tabWidth));      // deprecated in 5.10\n#else\n    setTabStopDistance(tabWidth);               // added in 5.10\n#endif\n}\n\nQtSLiMTextEdit::~QtSLiMTextEdit()\n{\n}\n\nvoid QtSLiMTextEdit::setScriptType(ScriptType type)\n{\n    // Configure our script type; this should be called once, early\n    scriptType = type;\n}\n\nvoid QtSLiMTextEdit::setSyntaxHighlightType(ScriptHighlightingType type)\n{\n    // Configure our syntax highlighting; this should be called once, early\n    syntaxHighlightingType = type;\n    \n    scriptSyntaxHighlightPrefChanged();     // create a highlighter if needed\n    outputSyntaxHighlightPrefChanged();     // create a highlighter if needed\n}\n\nvoid QtSLiMTextEdit::setOptionClickEnabled(bool enabled)\n{\n    optionClickEnabled = enabled;\n    optionClickIntercepted = false;\n}\n\nvoid QtSLiMTextEdit::displayFontPrefChanged()\n{\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    double tabWidth = 0;\n    QFont displayFont = prefs.displayFontPref(&tabWidth);\n    \n    setFont(displayFont);\n#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))\n    setTabStopWidth((int)floor(tabWidth));      // deprecated in 5.10\n#else\n    setTabStopDistance(tabWidth);               // added in 5.10\n#endif\n}\n\nvoid QtSLiMTextEdit::scriptSyntaxHighlightPrefChanged()\n{\n    if (syntaxHighlightingType == QtSLiMTextEdit::ScriptHighlighting)\n    {\n        QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n        bool highlightPref = prefs.scriptSyntaxHighlightPref();\n        \n        if (highlightPref && !scriptHighlighter)\n        {\n            scriptHighlighter = new QtSLiMScriptHighlighter(document());\n        }\n        else if (!highlightPref && scriptHighlighter)\n        {\n            scriptHighlighter->setDocument(nullptr);\n            scriptHighlighter->setParent(nullptr);\n            delete scriptHighlighter;\n            scriptHighlighter = nullptr;\n        }\n    }\n}\n\nvoid QtSLiMTextEdit::outputSyntaxHighlightPrefChanged()\n{\n    if (syntaxHighlightingType == QtSLiMTextEdit::OutputHighlighting)\n    {\n        QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n        bool highlightPref = prefs.outputSyntaxHighlightPref();\n        \n        if (highlightPref && !outputHighlighter)\n        {\n            outputHighlighter = new QtSLiMOutputHighlighter(document());\n        }\n        else if (!highlightPref && outputHighlighter)\n        {\n            outputHighlighter->setDocument(nullptr);\n            outputHighlighter->setParent(nullptr);\n            delete outputHighlighter;\n            outputHighlighter = nullptr;\n        }\n    }\n}\n\nvoid QtSLiMTextEdit::highlightError(int startPosition, int endPosition)\n{\n    QTextCursor highlight_cursor(document());\n    \n    highlight_cursor.setPosition(startPosition);\n    highlight_cursor.setPosition(endPosition, QTextCursor::KeepAnchor);\n    setTextCursor(highlight_cursor);\n    centerCursor();\n    \n    setPalette(qtslimErrorPalette());\n    \n    // note that this custom selection color is cleared by a connection to QPlainTextEdit::selectionChanged()\n}\n\nvoid QtSLiMTextEdit::selectErrorRange(EidosErrorContext &errorContext)\n{\n    // If there is error-tracking information set, and the error is attributed to the user script,\n    // then we can highlight the error range\n    if ((!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == 0)) &&\n        (errorContext.errorPosition.characterStartOfErrorUTF16 >= 0) &&\n        (errorContext.errorPosition.characterEndOfErrorUTF16 >= errorContext.errorPosition.characterStartOfErrorUTF16))\n    {\n\t\thighlightError(errorContext.errorPosition.characterStartOfErrorUTF16, errorContext.errorPosition.characterEndOfErrorUTF16 + 1);\n    }\n}\n\nQPalette QtSLiMTextEdit::qtslimStandardPalette(void)\n{\n    // Returns the standard palette for QtSLiMTextEdit, which could depend on platform and dark mode\n    return qApp->palette(this);\n}\n\nQPalette QtSLiMTextEdit::qtslimErrorPalette(void)\n{\n    // Returns a palette for QtSLiMTextEdit for highlighting errors, which could depend on platform and dark mode\n    // Note that this is based on the current palette, and derives only the highlight colors\n    QPalette p = palette();\n    p.setColor(QPalette::Highlight, QColor(QColor(Qt::red).lighter(120)));\n    p.setColor(QPalette::HighlightedText, QColor(Qt::black));\n    return p;\n}\n\nQStatusBar *QtSLiMTextEdit::statusBarForWindow(void)\n{\n    // This is a bit of a hack because the console window is not a MainWindow subclass, and makes its own status bar\n    QWidget *ourWindow = window();\n    QMainWindow *mainWindow = dynamic_cast<QMainWindow *>(ourWindow);\n    QtSLiMEidosConsole *consoleWindow = dynamic_cast<QtSLiMEidosConsole *>(ourWindow);\n    QStatusBar *statusBar = nullptr;\n    \n    if (mainWindow)\n        statusBar = mainWindow->statusBar();\n    else if (consoleWindow)\n        statusBar = consoleWindow->statusBar();\n    \n    return statusBar;\n}\n\nQtSLiMWindow *QtSLiMTextEdit::slimControllerForWindow(void)\n{\n    QtSLiMWindow *windowSLiMController = dynamic_cast<QtSLiMWindow *>(window());\n    \n    if (windowSLiMController)\n        return windowSLiMController;\n    \n    QtSLiMEidosConsole *windowEidosConsole = dynamic_cast<QtSLiMEidosConsole *>(window());\n    \n    if (windowEidosConsole)\n        return windowEidosConsole->parentSLiMWindow;\n    \n    return nullptr;\n}\n\nQtSLiMEidosConsole *QtSLiMTextEdit::slimEidosConsoleForWindow(void)\n{\n    QtSLiMEidosConsole *windowEidosConsole = dynamic_cast<QtSLiMEidosConsole *>(window());\n    \n    if (windowEidosConsole)\n        return windowEidosConsole;\n    \n    return nullptr;\n}\n\nbool QtSLiMTextEdit::checkScriptSuppressSuccessResponse(bool suppressSuccessResponse)\n{\n\t// Note this does *not* check out scriptString, which represents the state of the script when the Community object was created\n\t// Instead, it checks the current script in the script TextView – which is not used for anything until the recycle button is clicked.\n    QByteArray utf8bytes = toPlainText().toUtf8();\n\tconst char *cstr = utf8bytes.constData();\n\tstd::string errorDiagnostic;\n\t\n\tif (!cstr)\n\t{\n\t\terrorDiagnostic = \"The script string could not be read, possibly due to an encoding problem.\";\n\t}\n\telse\n\t{\n        if (scriptType == EidosScriptType)\n        {\n            EidosScript script(cstr);\n            \n            try {\n                script.Tokenize();\n                script.ParseInterpreterBlockToAST(true);\n            }\n            catch (...)\n            {\n                errorDiagnostic = Eidos_GetTrimmedRaiseMessage();\n            }\n        }\n        else if (scriptType == SLiMScriptType)\n        {\n            SLiMEidosScript script(cstr);\n            \n            try {\n                script.Tokenize();\n                script.ParseSLiMFileToAST();\n            }\n            catch (...)\n            {\n                errorDiagnostic = Eidos_GetTrimmedRaiseMessage();\n            }\n        }\n        else\n        {\n            qDebug() << \"checkScriptSuppressSuccessResponse() called with no script type set\";\n        }\n\t}\n\t\n\tbool checkDidSucceed = !(errorDiagnostic.length());\n\t\n\tif (!checkDidSucceed || !suppressSuccessResponse)\n\t{\n\t\tif (!checkDidSucceed)\n\t\t{\n\t\t\t// On failure, we show an alert describing the error, and highlight the relevant script line\n            qApp->beep();\n            \n            EidosErrorContext errorContext = gEidosErrorContext;\n            \n            ClearErrorContext();\n            \n            selectErrorRange(errorContext);\n            \n            QString q_errorDiagnostic = QString::fromStdString(errorDiagnostic);\n            QMessageBox messageBox(this);\n            messageBox.setText(\"Script error\");\n            messageBox.setInformativeText(q_errorDiagnostic);\n            messageBox.setIcon(QMessageBox::Warning);\n            \n            // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n            // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n            // seems necessary so floating windows can't be on top of the message box\n            messageBox.setWindowModality(Qt::ApplicationModal);\n            messageBox.setFixedWidth(700);      // seems to be ignored\n            messageBox.exec();\n            \n\t\t\t// Show the error in the status bar also\n            QStatusBar *statusBar = statusBarForWindow();\n            \n            if (statusBar)\n                statusBar->showMessage(\"<font color='#cc0000' style='font-size: 11px;'>\" + q_errorDiagnostic.trimmed().toHtmlEscaped() + \"</font>\");\n\t\t}\n\t\telse\n\t\t{\n            QSettings settings;\n            \n            if (!settings.value(\"QtSLiMSuppressScriptCheckSuccessPanel\", false).toBool())\n\t\t\t{\n                // In SLiMgui we play a \"success\" sound too, but doing anything besides beeping is apparently difficult with Qt...\n                \n                QMessageBox messageBox(this);\n                messageBox.setText(\"No script errors\");\n                messageBox.setInformativeText(\"No errors found.\");\n                messageBox.setIcon(QMessageBox::Information);\n                \n                // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n                // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n                // seems necessary so floating windows can't be on top of the message box\n                messageBox.setWindowModality(Qt::ApplicationModal);\n                messageBox.setCheckBox(new QCheckBox(\"Do not show this message again\", nullptr));\n                messageBox.exec();\n                \n                if (messageBox.checkBox()->isChecked())\n                    settings.setValue(\"QtSLiMSuppressScriptCheckSuccessPanel\", true);\n            }\n\t\t}\n\t}\n\t\n\treturn checkDidSucceed;\n}\n\nvoid QtSLiMTextEdit::checkScript(void)\n{\n    checkScriptSuppressSuccessResponse(false);\n}\n\nvoid QtSLiMTextEdit::_prettyprint_reformat(bool p_reformat)\n{\n    if (isEnabled())\n\t{\n\t\tif (checkScriptSuppressSuccessResponse(true))\n\t\t{\n\t\t\t// We know the script is syntactically correct, so we can tokenize and parse it without worries\n            QByteArray utf8bytes = toPlainText().toUtf8();\n            const char *cstr = utf8bytes.constData();\n\t\t\tEidosScript script(cstr);\n            \n\t\t\tscript.Tokenize(false, true);\t// get whitespace and comment tokens\n\t\t\t\n\t\t\t// Then generate a new script string that is prettyprinted\n\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\tstd::string pretty;\n\t\t\tbool success = false;\n            \n            if (p_reformat)\n                success = Eidos_reformatTokensFromScript(tokens, script, pretty);\n            else\n                success = Eidos_prettyprintTokensFromScript(tokens, script, pretty);\n            \n            if (success)\n            {\n                // We want to replace our text in a way that is undoable; to do this, we use the text cursor\n                QString replacementString = QString::fromStdString(pretty);\n                \n                QTextCursor &&replacement_cursor = textCursor();\n                \n                replacement_cursor.beginEditBlock();\n                replacement_cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);\n                replacement_cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n                replacement_cursor.insertText(replacementString);\n                replacement_cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);\n                replacement_cursor.endEditBlock();\n                setTextCursor(replacement_cursor);\n            }\n            else\n                qApp->beep();\n\t\t}\n\t}\n\telse\n\t{\n        qApp->beep();\n\t}\n}\n\nvoid QtSLiMTextEdit::prettyprint(void)\n{\n    _prettyprint_reformat(false);\n}\n\nvoid QtSLiMTextEdit::reformat(void)\n{\n    _prettyprint_reformat(true);\n}\n\nvoid QtSLiMTextEdit::prettyprintClicked(void)\n{\n    // Get the option-key state; if it is pressed, we do a full reformat\n    bool optionPressed = QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier);\n    \n    if (optionPressed)\n        reformat();\n    else\n        prettyprint();\n}\n\nvoid QtSLiMTextEdit::scriptHelpOptionClick(QString searchString)\n{\n    QtSLiMHelpWindow &helpWindow = QtSLiMHelpWindow::instance();\n    \n    // A few Eidos substitutions to improve the search\n    if (searchString == \":\")                    searchString = \"operator :\";\n    else if (searchString == \"(\")               searchString = \"operator ()\";\n    else if (searchString == \")\")               searchString = \"operator ()\";\n    else if (searchString == \",\")               searchString = \"calls: operator ()\";\n    else if (searchString == \"[\")               searchString = \"operator []\";\n    else if (searchString == \"]\")               searchString = \"operator []\";\n    else if (searchString == \"{\")               searchString = \"compound statements\";\n    else if (searchString == \"}\")               searchString = \"compound statements\";\n    else if (searchString == \".\")               searchString = \"operator .\";\n    else if (searchString == \"=\")               searchString = \"operator =\";\n    else if (searchString == \"+\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"-\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"*\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"/\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"%\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"^\")               searchString = \"Arithmetic operators\";\n    else if (searchString == \"|\")               searchString = \"Logical operators\";\n    else if (searchString == \"&\")               searchString = \"Logical operators\";\n    else if (searchString == \"!\")               searchString = \"Logical operators\";\n    else if (searchString == \"==\")              searchString = \"Comparative operators\";\n    else if (searchString == \"!=\")              searchString = \"Comparative operators\";\n    else if (searchString == \"<=\")              searchString = \"Comparative operators\";\n    else if (searchString == \">=\")              searchString = \"Comparative operators\";\n    else if (searchString == \"<\")               searchString = \"Comparative operators\";\n    else if (searchString == \">\")               searchString = \"Comparative operators\";\n    else if (searchString == \"'\")               searchString = \"type string\";\n    else if (searchString == \"\\\"\")              searchString = \"type string\";\n    else if (searchString == \";\")               searchString = \"null statements\";\n    else if (searchString == \"//\")              searchString = \"comments\";\n    else if (searchString == \"if\")              searchString = \"if and if–else statements\";\n    else if (searchString == \"else\")            searchString = \"if and if–else statements\";\n    else if (searchString == \"do\")              searchString = \"do–while statements\";\n    else if (searchString == \"while\")           searchString = \"while statements\";    // this brings up both while and do-while statements, correctly\n    else if (searchString == \"for\")             searchString = \"for statements\";\n    else if (searchString == \"in\")              searchString = \"for statements\";\n    else if (searchString == \"next\")            searchString = \"next statements\";\n    else if (searchString == \"break\")           searchString = \"break statements\";\n    else if (searchString == \"return\")          searchString = \"return statements\";\n    else if (searchString == \"function\")        searchString = \"user-defined functions\";\n    // and SLiM substitutions; \"initialize\" is deliberately omitted here so that the initialize...() methods also come up\n    else if (searchString == \"first\")\t\t\tsearchString = \"Eidos events\";\n    else if (searchString == \"early\")\t\t\tsearchString = \"Eidos events\";\n\telse if (searchString == \"late\")\t\t\tsearchString = \"Eidos events\";\n\telse if (searchString == \"mutationEffect\")  searchString = \"mutationEffect() callbacks\";\n\telse if (searchString == \"fitnessEffect\")   searchString = \"fitnessEffect() callbacks\";\n\telse if (searchString == \"interaction\")     searchString = \"interaction() callbacks\";\n\telse if (searchString == \"mateChoice\")      searchString = \"mateChoice() callbacks\";\n\telse if (searchString == \"modifyChild\")     searchString = \"modifyChild() callbacks\";\n\telse if (searchString == \"recombination\")\tsearchString = \"recombination() callbacks\";\n\telse if (searchString == \"mutation\")\t\tsearchString = \"mutation() callbacks\";\n\telse if (searchString == \"survival\")\t\tsearchString = \"survival() callbacks\";\n\telse if (searchString == \"reproduction\")\tsearchString = \"reproduction() callbacks\";\n    \n    // now send the search string on to the help window\n    helpWindow.enterSearchForString(searchString, true);\n}\n\nvoid QtSLiMTextEdit::mousePressEvent(QMouseEvent *p_event)\n{\n    bool optionPressed = (optionClickEnabled && QGuiApplication::keyboardModifiers().testFlag(Qt::AltModifier));\n    \n    if (optionPressed)\n    {\n        // option-click gets intercepted to bring up help\n        optionClickIntercepted = true;\n        \n        // get the position of the character clicked on; note that cursorForPosition()\n        // returns the closest cursor position *between* characters, not which character\n        // was actually clicked on, so we try to compensate here by fudging the position\n        // leftward by half a character width; we used to use hitTest() for this purpose,\n        // but for QPlainTextEdit hitTest() always returns -1 for some reason.\n        const QFont &displayFont = QtSLiMPreferencesNotifier::instance().displayFontPref(nullptr);\n        QFontMetricsF fm(displayFont);\n        int fudgeFactor;\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        fudgeFactor = std::round(fm.width(\" \") / 2.0) + 1;                // deprecated in 5.11\n#else\n        fudgeFactor = std::round(fm.horizontalAdvance(\" \") / 2.0) + 1;    // added in Qt 5.11\n#endif\n        \n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n        QPoint localPos = p_event->localPos().toPoint();\n#else\n        QPoint localPos = p_event->position().toPoint();\n#endif\n        QPoint fudgedPoint(std::max(0, localPos.x() - fudgeFactor), localPos.y());\n        int characterPositionClicked = cursorForPosition(fudgedPoint).position();\n        \n        //qDebug() << \"localPos ==\" << localPos << \", characterPositionClicked ==\" << characterPositionClicked;\n        \n        if (characterPositionClicked == -1)     // occurs if you click between lines of text\n            return;\n        \n        QTextCursor charCursor(document());\n        charCursor.setPosition(characterPositionClicked, QTextCursor::MoveAnchor);\n        charCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);\n        \n        QString characterString = charCursor.selectedText();\n        \n        if (characterString.length() != 1)      // not sure if this ever happens, being safe\n            return;\n        \n        QChar character = characterString.at(0);\n        \n        if (character.isSpace())                // no help on whitespace\n            return;\n        \n        //qDebug() << characterPositionClicked << \": \" << charCursor.anchor() << \",\" << charCursor.position() << \",\" << charCursor.selectedText();\n        \n        // if the character is a letter or number, we want to select the word it\n        // is contained by and use that as the symbol for lookup; otherwise, \n        // it is symbolic, and we want to try to match the right symbol in the code\n        QTextCursor symbolCursor(charCursor);\n        \n        if (character.isLetterOrNumber())\n        {\n            // start at the anchor and find the encompassing word\n            symbolCursor.setPosition(symbolCursor.anchor(), QTextCursor::MoveAnchor);\n            symbolCursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);\n            symbolCursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);\n        }\n        else if ((character == '/') || (character == '=') || (character == '<') || (character == '>') || (character == '!'))\n        {\n            // the character clicked might be part of a multicharacter symbol: // == <= >= !=\n            // we will look at two-character groups anchored in the clicked character to test this\n            QTextCursor leftPairCursor(document()), rightPairCursor(document());\n            leftPairCursor.setPosition(characterPositionClicked - 1, QTextCursor::MoveAnchor);\n            leftPairCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);\n            rightPairCursor.setPosition(characterPositionClicked, QTextCursor::MoveAnchor);\n            rightPairCursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2);\n            \n            QString leftPairString = leftPairCursor.selectedText(), rightPairString = rightPairCursor.selectedText();\n            \n            if ((leftPairString == \"//\") || (leftPairString == \"==\") || (leftPairString == \"<=\") || (leftPairString == \">=\") || (leftPairString == \"!=\"))\n                symbolCursor = leftPairCursor;\n            else if ((rightPairString == \"//\") || (rightPairString == \"==\") || (rightPairString == \"<=\") || (rightPairString == \">=\") || (rightPairString == \"!=\"))\n                symbolCursor = rightPairCursor;\n            // else we drop through and search for the one-character symbol\n        }\n        else\n        {\n            // the character clicked is a one-character symbol; we just drop through\n        }\n        \n        // select the symbol and trigger a lookup\n        QString symbol = symbolCursor.selectedText();\n        \n        if (symbol.length())\n        {\n            setTextCursor(symbolCursor);\n            scriptHelpOptionClick(symbol);\n        }\n    }\n    else\n    {\n        // all other cases go to super\n        optionClickIntercepted = false;\n        \n        QPlainTextEdit::mousePressEvent(p_event);\n    }\n}\n\nvoid QtSLiMTextEdit::mouseMoveEvent(QMouseEvent *p_event)\n{\n    // forward to super, as long as we did not intercept this mouse event\n    if (!optionClickIntercepted)\n        QPlainTextEdit::mouseMoveEvent(p_event);\n}\n\nvoid QtSLiMTextEdit::mouseReleaseEvent(QMouseEvent *p_event)\n{\n    // forward to super, as long as we did not intercept this mouse event\n    if (!optionClickIntercepted)\n        QPlainTextEdit::mouseReleaseEvent(p_event);\n    \n    optionClickIntercepted = false;\n}\n\nvoid QtSLiMTextEdit::fixMouseCursor(void)\n{\n    if (optionClickEnabled)\n    {\n        // we want a pointing hand cursor when option is pressed; if the cursor is wrong, fix it\n        // note the cursor for QPlainTextEdit is apparently controlled by its viewport\n        bool optionPressed = QGuiApplication::queryKeyboardModifiers().testFlag(Qt::AltModifier);\n        QWidget *vp = viewport();\n        \n        if (optionPressed && (vp->cursor().shape() != Qt::PointingHandCursor))\n            vp->setCursor(Qt::PointingHandCursor);\n        else if (!optionPressed && (vp->cursor().shape() != Qt::IBeamCursor))\n            vp->setCursor(Qt::IBeamCursor);\n    }\n}\n\n#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\nvoid QtSLiMTextEdit::enterEvent(QEnterEvent *p_event)\n{\n    // forward to super\n    QPlainTextEdit::enterEvent(p_event);\n    \n    // modifiersChanged() generally keeps our cursor correct, but we do it on enterEvent\n    // as well just as a fallback; for example, if the mouse is inside us on launch and\n    // the modifier is already down, enterEvent() will fix out initial cursor\n    fixMouseCursor();\n}\n#else\nvoid QtSLiMTextEdit::enterEvent(QEvent *p_event)\n{\n    // forward to super\n    QPlainTextEdit::enterEvent(p_event);\n    \n    // modifiersChanged() generally keeps our cursor correct, but we do it on enterEvent\n    // as well just as a fallback; for example, if the mouse is inside us on launch and\n    // the modifier is already down, enterEvent() will fix out initial cursor\n    fixMouseCursor();\n}\n#endif\n\nvoid QtSLiMTextEdit::modifiersChanged(Qt::KeyboardModifiers __attribute__((unused)) newModifiers)\n{\n    // keyPressEvent() and keyReleaseEvent() are sent to us only when we have the focus, but\n    // we want to change our cursor even when we don't have focus, so we use an event filter\n    fixMouseCursor();\n}\n\nEidosFunctionSignature_CSP QtSLiMTextEdit::signatureForFunctionName(QString callName, EidosFunctionMap *functionMapPtr)\n{\n\tstd::string call_name = callName.toStdString();\n\t\n\t// Look for a matching function signature for the call name.\n\tfor (const auto& function_iter : *functionMapPtr)\n\t{\n\t\tconst EidosFunctionSignature_CSP &sig = function_iter.second;\n\t\tconst std::string &sig_call_name = sig->call_name_;\n\t\t\n\t\tif (sig_call_name.compare(call_name) == 0)\n\t\t\treturn sig;\n\t}\n\t\n\treturn nullptr;\n}\n\nEidosMethodSignature_CSP QtSLiMTextEdit::signatureForMethodName(QString callName)\n{\n\tstd::string call_name = callName.toStdString();\n\t\n    // Look for a matching method signature for the call name.\n\tconst std::vector<EidosMethodSignature_CSP> methodSignatures = EidosClass::RegisteredClassMethods(true, true);\n\t\n\tfor (const EidosMethodSignature_CSP &sig : methodSignatures)\n\t{\n\t\tconst std::string &sig_call_name = sig->call_name_;\n\t\t\n\t\tif (sig_call_name.compare(call_name) == 0)\n\t\t\treturn sig;\n\t}\n\t\n\treturn nullptr;\n}\n\n//- (EidosFunctionMap *)functionMapForScriptString:(NSString *)scriptString includingOptionalFunctions:(BOOL)includingOptionalFunctions\nEidosFunctionMap *QtSLiMTextEdit::functionMapForScriptString(QString scriptString, bool includingOptionalFunctions)\n{\n\t// This returns a function map (owned by the caller) that reflects the best guess we can make, incorporating\n\t// any functions known to our delegate, as well as all functions we can scrape from the script string.\n\tstd::string script_string = scriptString.toStdString();\n\tEidosScript script(script_string);\n\t\n\t// Tokenize\n\tscript.Tokenize(true, false);\t// make bad tokens as needed, don't keep nonsignificant tokens\n\t\n\treturn functionMapForTokenizedScript(script, includingOptionalFunctions);\n}\n\nEidosFunctionMap *QtSLiMTextEdit::functionMapForTokenizedScript(EidosScript &script, bool includingOptionalFunctions)\n{\n    // This lower-level function takes a tokenized script object and works from there, allowing reuse of work\n    // in the case of attributedSignatureForScriptString:...\n    QtSLiMWindow *windowSLiMController = slimControllerForWindow();\n    Community *community = (windowSLiMController ? windowSLiMController->community : nullptr);\n    bool invalidSimulation = (windowSLiMController ? windowSLiMController->invalidSimulation() : true);\n    \n    // start with all the functions that are available in the current simulation context\n    EidosFunctionMap *functionMapPtr = nullptr;\n    \n    if (community && !invalidSimulation)\n        functionMapPtr = new EidosFunctionMap(community->FunctionMap());\n    else\n        functionMapPtr = new EidosFunctionMap(*EidosInterpreter::BuiltInFunctionMap());\n    \n    // functionMapForEidosTextView: returns the function map for the current interpreter state, and the type-interpreter\n    // stuff we do below gives the delegate no chance to intervene (note that SLiMTypeInterpreter does not get in here,\n    // unlike in the code completion machinery!).  But sometimes we want SLiM's zero-gen functions to be added to the map\n    // in all cases; it would be even better to be smart the way code completion is, but that's more work than it's worth.\n    if (includingOptionalFunctions)\n    {\n        // add SLiM functions that are context-dependent\n        Community::AddZeroTickFunctionsToMap(*functionMapPtr);\n        Community::AddSLiMFunctionsToMap(*functionMapPtr);\n    }\n    \n    // OK, now we have a starting point.  We now want to use the type-interpreter to add any functions that are declared\n    // in the full script, so that such declarations are known to us even before they have actually been executed.\n    EidosTypeTable typeTable;\n    EidosCallTypeTable callTypeTable;\n    EidosSymbolTable *symbols = gEidosConstantsSymbolTable;\n    \n    symbols = symbolsFromBaseSymbols(symbols);\n    \n    if (symbols)\n        symbols->AddSymbolsToTypeTable(&typeTable);\n    \n    script.ParseInterpreterBlockToAST(true, true);\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n    \n    EidosTypeInterpreter typeInterpreter(script, typeTable, *functionMapPtr, callTypeTable);\n    \n    typeInterpreter.TypeEvaluateInterpreterBlock();\t// result not used\n    \n    return functionMapPtr;\n}\n\nEidosSymbolTable *QtSLiMTextEdit::symbolsFromBaseSymbols(EidosSymbolTable *baseSymbols)\n{\n    // in SLiMgui this is a delegate method, eidosTextView:symbolsFromBaseSymbols:\n    // the point is simply to substitute in a console symbol table when one is available\n    QtSLiMEidosConsole *consoleWindow = slimEidosConsoleForWindow();\n    \n    if (consoleWindow)\n        return consoleWindow->symbolTable();\n    \n    return baseSymbols;\n}\n\nvoid QtSLiMTextEdit::scriptStringAndSelection(QString &scriptString, int &position, int &length, int &offset)\n{\n    // by default, the entire contents of the textedit are considered \"script\"\n    scriptString = toPlainText();\n    \n    QTextCursor selection_cursor(textCursor());\n    position = selection_cursor.selectionStart();\n    length = selection_cursor.selectionEnd() - position;\n    offset = 0;\n}\n\nEidosCallSignature_CSP QtSLiMTextEdit::signatureForScriptSelection(QString &callName)\n{\n    // Note we return a copy of the signature, owned by the caller\n    QString scriptString;\n    int selectionStart, selectionLength, rangeOffset;\n    \n    scriptStringAndSelection(scriptString, selectionStart, selectionLength, rangeOffset);\n    \n    if (scriptString.length())\n\t{\n\t\tstd::string script_string = scriptString.toStdString();\n\t\tEidosScript script(script_string);\n\t\t\n\t\t// Tokenize\n\t\tscript.Tokenize(true, false);\t// make bad tokens as needed, don't keep nonsignificant tokens\n\t\t\n\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\tsize_t tokenCount = tokens.size();\n\t\t\n\t\t// Search forward to find the token position of the start of the selection\n\t\tsize_t tokenIndex;\n\t\t\n\t\tfor (tokenIndex = 0; tokenIndex < tokenCount; ++tokenIndex)\n\t\t\tif (tokens[tokenIndex].token_UTF16_start_ >= selectionStart)\n\t\t\t\tbreak;\n\t\t\n\t\t// tokenIndex now has the index of the first token *after* the selection start; it can be equal to tokenCount\n\t\t// Now we want to scan backward from there, balancing parentheses and looking for the pattern \"identifier(\"\n\t\tint backscanIndex = static_cast<int>(tokenIndex) - 1;\n\t\tint parenCount = 0, lowestParenCountSeen = 0;\n\t\t\n\t\twhile (backscanIndex > 0)\t// last examined position is 1, since we can't look for an identifier at 0 - 1 == -1\n\t\t{\n\t\t\tconst EidosToken &token = tokens[static_cast<size_t>(backscanIndex)];\n\t\t\tEidosTokenType tokenType = token.token_type_;\n\t\t\t\n\t\t\tif (tokenType == EidosTokenType::kTokenLParen)\n\t\t\t{\n\t\t\t\t--parenCount;\n\t\t\t\t\n\t\t\t\tif (parenCount < lowestParenCountSeen)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &previousToken = tokens[static_cast<size_t>(backscanIndex) - 1];\n\t\t\t\t\tEidosTokenType previousTokenType = previousToken.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (previousTokenType == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// OK, we found the pattern \"identifier(\"; extract the name of the function/method\n\t\t\t\t\t\t// We also figure out here whether it is a method call (tokens like \".identifier(\") or not\n                        callName = QString::fromStdString(previousToken.token_string_);\n                        \n\t\t\t\t\t\tif ((backscanIndex > 1) && (tokens[static_cast<size_t>(backscanIndex) - 2].token_type_ == EidosTokenType::kTokenDot))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This is a method call, so look up its signature that way\n\t\t\t\t\t\t\tEidosMethodSignature_CSP callSignature = signatureForMethodName(callName);\n                            \n                            return std::move(callSignature);    // std::move() here avoids a bug in old compilers, according to a compiler warning...\n                        }\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If this is a function declaration like \"function(...)identifier(\" then show no signature; it's not a function call\n\t\t\t\t\t\t\t// Determining this requires a fairly complex backscan, because we also have things like \"if (...) identifier(\" which\n\t\t\t\t\t\t\t// are function calls.  This is the price we pay for working at the token level rather than the AST level for this;\n\t\t\t\t\t\t\t// so it goes.  Note that this backscan is separate from the one done outside this block.  BCH 1 March 2018.\n\t\t\t\t\t\t\tif ((backscanIndex > 1) && (tokens[static_cast<size_t>(backscanIndex) - 2].token_type_ == EidosTokenType::kTokenRParen))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Start a new backscan starting at the right paren preceding the identifier; we need to scan back to the balancing\n\t\t\t\t\t\t\t\t// left paren, and then see if the next thing before that is \"function\" or not.\n\t\t\t\t\t\t\t\tint funcCheckIndex = backscanIndex - 2;\n\t\t\t\t\t\t\t\tint funcCheckParens = 0;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twhile (funcCheckIndex >= 0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst EidosToken &backscanToken = tokens[static_cast<size_t>(funcCheckIndex)];\n\t\t\t\t\t\t\t\t\tEidosTokenType backscanTokenType = backscanToken.token_type_;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (backscanTokenType == EidosTokenType::kTokenRParen)\n\t\t\t\t\t\t\t\t\t\tfuncCheckParens++;\n\t\t\t\t\t\t\t\t\telse if (backscanTokenType == EidosTokenType::kTokenLParen)\n\t\t\t\t\t\t\t\t\t\tfuncCheckParens--;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t--funcCheckIndex;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (funcCheckParens == 0)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((funcCheckParens == 0) && (funcCheckIndex >= 0) && (tokens[static_cast<size_t>(funcCheckIndex)].token_type_ == EidosTokenType::kTokenFunction))\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// This is a function call, so look up its signature that way, using our best-guess function map\n\t\t\t\t\t\t\tEidosFunctionMap *functionMapPtr = functionMapForTokenizedScript(script, true);\n                            EidosFunctionSignature_CSP callSignature = signatureForFunctionName(callName, functionMapPtr);\n                            \n\t\t\t\t\t\t\tdelete functionMapPtr;              // note that callSignature survives this deletion because of shared_ptr\n                            \n                            return std::move(callSignature);    // std::move() here avoids a bug in old compilers, according to a compiler warning...\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlowestParenCountSeen = parenCount;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (tokenType == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\t++parenCount;\n\t\t\t}\n\t\t\t\n\t\t\t--backscanIndex;\n\t\t}\n\t}\n\t\n\treturn nullptr;\n}\n\nvoid QtSLiMTextEdit::updateStatusFieldFromSelection(void)\n{\n    if (scriptType != NoScriptType)\n    {\n        QString callName;\n        EidosCallSignature_CSP signature = signatureForScriptSelection(callName);\n        \n        if (!signature && (scriptType == SLiMScriptType))\n        {\n            // Handle SLiM callback signatures\n            if (callName == \"initialize\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"initialize\", nullptr, kEidosValueMaskVOID)));\n                signature = callbackSig;\n            }\n            else if (callName == \"first\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"first\", nullptr, kEidosValueMaskVOID)));\n                signature = callbackSig;\n            }\n            else if (callName == \"early\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"early\", nullptr, kEidosValueMaskVOID)));\n                signature = callbackSig;\n            }\n            else if (callName == \"late\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"late\", nullptr, kEidosValueMaskVOID)));\n                signature = callbackSig;\n            }\n            else if (callName == \"mutationEffect\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mutationEffect\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_S(\"mutationType\", gSLiM_MutationType_Class)->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"fitnessEffect\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"fitnessEffect\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"interaction\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"interaction\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_S(\"interactionType\", gSLiM_InteractionType_Class)->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"mateChoice\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mateChoice\", nullptr, kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"modifyChild\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"modifyChild\", nullptr, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"recombination\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"recombination\", nullptr, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible)->AddIntString_OSN(\"chromosome\", gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"survival\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"survival\", nullptr, kEidosValueMaskNULL | kEidosValueMaskLogical | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Subpopulation_Class))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"mutation\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mutation\", nullptr, kEidosValueMaskLogical | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Mutation_Class))->AddObject_OSN(\"mutationType\", gSLiM_MutationType_Class, gStaticEidosValueNULLInvisible)->AddObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n            else if (callName == \"reproduction\")\n            {\n                static EidosCallSignature_CSP callbackSig = nullptr;\n                if (!callbackSig) callbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"reproduction\", nullptr, kEidosValueMaskVOID))->AddObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible)->AddString_OSN(\"sex\", gStaticEidosValueNULLInvisible));\n                signature = callbackSig;\n            }\n        }\n        \n        QString displayString;\n        \n        if (signature)\n            displayString = QString::fromStdString(signature->SignatureString());\n        else if (!signature && callName.length())\n            displayString = callName + \"() – unrecognized call\";\n        \n        QStatusBar *statusBar = statusBarForWindow();\n        \n        if (displayString.length())\n        {\n            // The status bar now supports display of an HTML string, so we use QTextDocument and ColorizeCallSignature() to make one\n            QTextDocument td;\n            \n            td.setPlainText(displayString);\n            \n            if (signature)\n            {\n                QTextCursor tc(&td);\n                tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);\n                tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n                \n#ifdef __linux__\n                ColorizeCallSignature(signature.get(), 9, tc);\n#else\n                ColorizeCallSignature(signature.get(), 11, tc);\n#endif\n            }\n            \n            // hanging indent for multiline wrapping aesthetics\n            {\n                QTextCursor tc(&td);\n                tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);\n                tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n                \n                QTextBlockFormat blockFormat;\n                blockFormat.setLeftMargin(30);\n                blockFormat.setTextIndent(-30);\n                \n                tc.setBlockFormat(blockFormat);\n            }\n            \n            QString htmlString = td.toHtml();\n            //qDebug() << \"setting HTML:\" << htmlString;\n            \n            statusBar->showMessage(htmlString);\n        }\n        else\n        {\n            statusBar->clearMessage();\n        }\n        \n        // show the script block's declaration to the right of the Jump button\n        QtSLiMWindow *windowSLiMController = dynamic_cast<QtSLiMWindow *>(window());\n        \n        if (windowSLiMController)\n            windowSLiMController->setScriptBlockLabelTextFromSelection();\n    }\n}\n\n// Completion support\n\nvoid QtSLiMTextEdit::setCodeCompletionEnabled(bool enabled)\n{\n    codeCompletionEnabled = enabled;\n    \n    if (codeCompletionEnabled && !completer)\n    {\n        if (completer)\n            QObject::disconnect(completer, nullptr, this, nullptr);\n        \n        completer = new QCompleter(this);\n        \n        // Make a dummy model for construction\n        QStringList words;\n        words << \"foo\";\n        words << \"bar\";\n        words << \"baz\";\n        \n        completer->setModel(new QStringListModel(words, completer));\n        completer->setModelSorting(QCompleter::UnsortedModel);\n        completer->setCaseSensitivity(Qt::CaseInsensitive);\n        completer->setWrapAround(false);\n        completer->setWidget(this);\n        \n        connect(completer, QOverload<const QString &>::of(&QCompleter::activated), this, &QtSLiMTextEdit::insertCompletion);    // note this activated() signal was deprecated in 5.15, use QComboBox::textActivated() which was added in 5.14\n    }\n}\n\nvoid QtSLiMTextEdit::insertCompletion(const QString& completionOriginal)\n{\n    if (completer->widget() != this)\n        return;\n    \n    // If the completion string ends in \") {}\" we add newlines to it here; we don't want to show multi-line completions\n    // in the popup, but we want to produce them for the user when the completion is accepted; see slimSpecificCompletion()\n    QString completion = completionOriginal;\n    bool multilineCompletion = false;\n    \n    if (completion.endsWith(\") { }\"))\n    {\n        completion.replace(\") { }\", \") {\\n\\t\\n}\\n\");\n        multilineCompletion = true;\n    }\n    \n    // The cursor that we used as a completion root gets replaced completely by the completion string\n    NSRange completionRange = rangeForUserCompletion();\n    \n    if (completionRange.location != NSNotFound)\n    {\n        QTextCursor tc = textCursor();\n        int endPosition = std::max(tc.selectionEnd(), completionRange.location + completionRange.length);   // the completion is off the selection start, but we want to replace any selected text also\n        \n        tc.setPosition(completionRange.location, QTextCursor::MoveAnchor);\n        tc.setPosition(endPosition, QTextCursor::KeepAnchor);\n        \n        // If the character after the completion range is '(', suppress trailing parentheses on the completion\n        QTextCursor afterCompletion(tc);\n        afterCompletion.setPosition(afterCompletion.position(), QTextCursor::MoveAnchor);\n        afterCompletion.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 1);\n        \n        if (afterCompletion.selectedText() == '(')\n        {\n            if (completion.endsWith(\"()\"))\n                completion.chop(2);\n        }\n        \n        // Replace the completion range with the completion string\n        tc.insertText(completion);\n        \n        // If the completion is multiline, put the insertion point inside the braces of the completion\n        if (multilineCompletion)\n            tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 3);\n        \n        setTextCursor(tc);\n    }\n    else\n    {\n        qApp->beep();\n    }\n}\n\nvoid QtSLiMTextEdit::autoindentAfterNewline(void)\n{\n    // We are called by QtSLiMTextEdit::keyPressEvent() immediately after it calls\n    // super to insert a newline in response to Key_Enter or Key_Return\n    if (scriptType != NoScriptType)\n    {\n        QTextCursor tc = textCursor();\n        int selStart = tc.selectionStart(), selEnd = tc.selectionEnd();\n        const QString scriptString = toPlainText();\n        \n        // verify that we have an insertion point immediately following a newline\n        if ((selStart == selEnd) && (selStart > 0) && (scriptString[selStart - 1] == '\\n'))\n        {\n            QTextCursor previousLine = tc;\n            previousLine.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor);\n            previousLine.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);\n            \n            QString lineString = previousLine.selectedText();\n            QString whitespace;\n            \n            for (int position = 0; position < lineString.length(); ++position)\n            {\n                QChar qch = lineString[position];\n                \n                if (qch.isSpace())\n                    whitespace.append(qch);\n                else\n                    break;\n            }\n            \n            // insert the same whitespace as the previous line had, joining the undo block for the newline insertion\n            if (whitespace.length())\n            {\n                tc.joinPreviousEditBlock();\n                tc.insertText(whitespace);\n                tc.endEditBlock();\n                \n                // BCH 5/24/2025: Fix an autoindent bug that I'm surprised I didn't notice before; if\n                // you're at the end of an indented line, and press return and then press up-arrow,\n                // you move to the wrong position in the previous line, as if the auto-indent had not\n                // occurred.  It's weird, because the cursor shows visibly at the correct position,\n                // but then up-arrow reveals that in some way it was actually not in that position.\n                // Anyhow, explicitly setting the text cursor here seems to fix it.  Maybe I didn't\n                // notice it before because this is a new bug in Qt 6?  If so, this workaround should\n                // be safe on Qt 5.\n                setTextCursor(tc);\n            }\n        }\n    }\n}\n\nvoid QtSLiMTextEdit::keyPressEvent(QKeyEvent *p_event)\n{\n    // Without a completer, we just call super\n    if (!completer)\n    {\n        QPlainTextEdit::keyPressEvent(p_event);\n        return;\n    }\n    \n    if (completer->popup()->isVisible()) {\n        // The following keys are forwarded by the completer to the widget\n       switch (p_event->key()) {\n       case Qt::Key_Enter:\n       case Qt::Key_Return:\n       case Qt::Key_Escape:\n       case Qt::Key_Tab:\n       case Qt::Key_Backtab:\n            p_event->ignore();\n            return; // let the completer do default behavior\n       default:\n           break;\n       }\n    }\n    \n    // if we have a visible completer popup, the key pressed is not one of the special keys above (including escape)\n    // our completion key shortcut is the escape key, so check for that now\n    bool isShortcut = ((p_event->modifiers() == Qt::NoModifier) && p_event->key() == Qt::Key_Escape); // escape\n    \n    if (!isShortcut)\n    {\n        // any key other than escape and the special keys above causes the completion popup to hide\n        completer->popup()->hide();\n        QPlainTextEdit::keyPressEvent(p_event);\n        \n        // implement autoindent\n        if ((p_event->modifiers() == Qt::NoModifier) && ((p_event->key() == Qt::Key_Enter) || (p_event->key() == Qt::Key_Return)))\n            autoindentAfterNewline();\n        \n        return;\n    }\n    \n    // we have a completer and the shortcut has been pressed; initiate completion\n    \n    // first, figure out the range of text we are completing (the \"root\")\n    NSRange completionRange = rangeForUserCompletion();\n    \n    if (completionRange.location != NSNotFound)\n    {\n        QTextCursor completionRootCursor = textCursor();\n        completionRootCursor.setPosition(completionRange.location, QTextCursor::MoveAnchor);\n        //completionRootCursor.setPosition(completionRange.location + completionRange.length, QTextCursor::KeepAnchor); // this aligns the popup with the right edge of the selection, but we want the left edge, I think...\n        \n        // get the correct context-sensitive word list for the completer\n        QStringList completions = completionsForPartialWordRange(completionRange, nullptr);\n        \n        completer->setModel(new QStringListModel(completions, completer));\n        \n        // place the completer appropriately for the cursor; the doc is a bit vague, but this seems to work\n        QRect cr = cursorRect(completionRootCursor);\n        \n        cr.setWidth(completer->popup()->sizeHintForColumn(0)\n                    + completer->popup()->verticalScrollBar()->sizeHint().width());\n        \n        // zero out the completer's completion root; we do not use it, because we implement our own matching algorithm\n        completer->setCompletionPrefix(\"\");\n        completer->popup()->setCurrentIndex(completer->completionModel()->index(0, 0));\n        \n        completer->complete(cr); // pop up below the current cursor rect in the textview\n    }\n    else\n    {\n        qApp->beep();\n    }\n    \n}\n\n// the rest here is completion code adapted from EidosScribe and SLiMgui\n// we mirror the NSTextView APIs completionsForPartialWordRange:indexOfSelectedItem: and\n// rangeForUserCompletion to allow our ported code to function identically to SLiMgui\n\n// - (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index\nQStringList QtSLiMTextEdit::completionsForPartialWordRange(NSRange __attribute__((__unused__)) charRange, int * __attribute__((__unused__)) indexOfSelectedItem)\n{\n\tQStringList completions;        //NSArray *completions = nil;\n\t\n\t_completionHandlerWithRangeForCompletion(nullptr, &completions);\n    \n\treturn completions;\n}\n\n// - (NSRange)rangeForUserCompletion\nNSRange QtSLiMTextEdit::rangeForUserCompletion(void)\n{\n    NSRange baseRange = {NSNotFound, 0};\n    \n\t_completionHandlerWithRangeForCompletion(&baseRange, nullptr);\n    \n\treturn baseRange;\n}\n\n//- (NSMutableArray *)globalCompletionsWithTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap keywords:(NSArray *)keywords argumentNames:(NSArray *)argumentNames\nQStringList QtSLiMTextEdit::globalCompletionsWithTypesFunctionsKeywordsArguments(EidosTypeTable *typeTable, EidosFunctionMap *functionMap, QStringList keywords, QStringList argumentNames)\n{\n\tQStringList globals;\n\t\n\t// First add entries for symbols in our type table (from Eidos constants, defined symbols, or our delegate)\n\tif (typeTable)\n\t{\n\t\tstd::vector<std::string> typedSymbols = typeTable->AllSymbols();\n\t\t\n\t\tfor (std::string &symbol_name : typedSymbols)\n            globals << QString::fromStdString(symbol_name);\n\t}\n\t\n\t// Sort the symbols, who knows what order they come from EidosTypeTable in...\n    globals.sort();\n\t\n\t// Next, if we have argument names that are completion matches, we want them at the top\n\tif (argumentNames.size())\n\t{\n        QStringList oldGlobals = globals;\n        \n        globals = argumentNames;\n        globals.append(oldGlobals);\n\t}\n\t\n\t// Next, a sorted list of functions, with () appended\n\tif (functionMap)\n\t{\n\t\tfor (const auto& function_iter : *functionMap)\n\t\t{\n\t\t\tconst EidosFunctionSignature *sig = function_iter.second.get();\n\t\t\tQString functionName = QString::fromStdString(sig->call_name_);\n\t\t\t\n\t\t\t// Exclude internal functions such as _Test()\n            if (!functionName.startsWith(\"_\"))\n            {\n                functionName.append(\"()\");\n                globals.append(functionName);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Finally, provide language keywords as an option if requested\n\tif (keywords.size())\n\t\tglobals.append(keywords);\n\t\n\treturn globals;\n}\n\n//- (NSMutableArray *)completionsForKeyPathEndingInTokenIndex:(int)lastDotTokenIndex ofTokenStream:(const std::vector<EidosToken> &)tokens withTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap callTypes:(EidosCallTypeTable *)callTypeTable keywords:(NSArray *)keywords\nQStringList QtSLiMTextEdit::completionsForKeyPathEndingInTokenIndexOfTokenStream(int lastDotTokenIndex, const std::vector<EidosToken> &tokens, EidosTypeTable *typeTable, EidosFunctionMap *functionMap, EidosCallTypeTable *callTypeTable, QStringList __attribute__((__unused__)) keywords)\n{\n\tconst EidosToken *token = &tokens[static_cast<size_t>(lastDotTokenIndex)];\n\tEidosTokenType token_type = token->token_type_;\n\t\n\tif (token_type != EidosTokenType::kTokenDot)\n\t{\n\t\tqDebug() << \"***** completionsForKeyPathEndingInTokenIndex... called for non-kTokenDot token!\";\n\t\treturn QStringList();\n\t}\n\t\n\t// OK, we've got a key path ending in a dot, and we want to return a list of completions that would work for that key path.\n\t// We'll trace backward, adding identifiers to a vector to build up the chain of references.  If we hit a bracket, we'll\n\t// skip back over everything inside it, since subsetting does not change the type; we just need to balance brackets.  If we\n\t// hit a parenthesis, we do similarly.  If we hit other things – a semicolon, a comma, a brace – that terminates the key path chain.\n\tstd::vector<std::string> identifiers;\n\tstd::vector<bool> identifiers_are_calls;\n\tstd::vector<int32_t> identifier_positions;\n\tint bracketCount = 0, parenCount = 0;\n\tbool lastTokenWasDot = true, justFinishedParenBlock = false;\n\t\n\tfor (int tokenIndex = lastDotTokenIndex - 1; tokenIndex >= 0; --tokenIndex)\n\t{\n\t\ttoken = &tokens[static_cast<size_t>(tokenIndex)];\n\t\ttoken_type = token->token_type_;\n\t\t\n\t\t// skip backward over whitespace and comments; they make no difference to us\n\t\tif ((token_type == EidosTokenType::kTokenWhitespace) || (token_type == EidosTokenType::kTokenComment) || (token_type == EidosTokenType::kTokenCommentLong))\n\t\t\tcontinue;\n\t\t\n\t\tif (bracketCount)\n\t\t{\n\t\t\t// If we're inside a bracketed stretch, all we do is balance brackets and run backward.  We don't even clear lastTokenWasDot,\n\t\t\t// because a []. sequence puts us in the same situation as having just seen a dot – we're still waiting for an identifier.\n\t\t\tif (token_type == EidosTokenType::kTokenRBracket)\n\t\t\t{\n\t\t\t\tbracketCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (token_type == EidosTokenType::kTokenLBracket)\n\t\t\t{\n\t\t\t\tbracketCount--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check for tokens that simply make no sense, and bail\n\t\t\tif ((token_type == EidosTokenType::kTokenLBrace) || (token_type == EidosTokenType::kTokenRBrace) || (token_type == EidosTokenType::kTokenSemicolon) || (token_type >= EidosTokenType::kFirstIdentifierLikeToken))\n\t\t\t\treturn QStringList();\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\telse if (parenCount)\n\t\t{\n\t\t\t// If we're inside a paren stretch – which could be a parenthesized expression or a function call – we do similarly\n\t\t\t// to the brackets case, just balancing parens and running backward.  We don't clear lastTokenWasDot, because a\n\t\t\t// (). sequence puts us in the same situation (almost) as having just seen a dot – waiting for an identifier.\n\t\t\tif (token_type == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\tparenCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (token_type == EidosTokenType::kTokenLParen)\n\t\t\t{\n\t\t\t\tparenCount--;\n\t\t\t\t\n\t\t\t\tif (parenCount == 0)\n\t\t\t\t\tjustFinishedParenBlock = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check for tokens that simply make no sense, and bail\n\t\t\tif ((token_type == EidosTokenType::kTokenLBrace) || (token_type == EidosTokenType::kTokenRBrace) || (token_type == EidosTokenType::kTokenSemicolon) || (token_type >= EidosTokenType::kFirstIdentifierLikeToken))\n\t\t\t\treturn QStringList();\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (!lastTokenWasDot)\n\t\t{\n\t\t\t// We just saw an identifier, so the only thing that can continue the key path is a dot\n\t\t\tif (token_type == EidosTokenType::kTokenDot)\n\t\t\t{\n\t\t\t\tlastTokenWasDot = true;\n\t\t\t\tjustFinishedParenBlock = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// the key path has terminated at some non-key-path token, so we're done tracing it\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// OK, the last token was a dot (or a subset preceding a dot).  We're looking for an identifier, but we're willing\n\t\t// to get distracted by a subset sequence, since that does not change the type.  Anything else does not make sense.\n\t\tif (token_type == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\tidentifiers.emplace_back(token->token_string_);\n\t\t\tidentifiers_are_calls.push_back(justFinishedParenBlock);\n\t\t\tidentifier_positions.emplace_back(token->token_start_);\n\t\t\t\n\t\t\t// set up to continue searching the key path backwards\n\t\t\tlastTokenWasDot = false;\n\t\t\tjustFinishedParenBlock = false;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (token_type == EidosTokenType::kTokenRBracket)\n\t\t{\n\t\t\tbracketCount++;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (token_type == EidosTokenType::kTokenRParen)\n\t\t{\n\t\t\tparenCount++;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// This makes no sense, so bail\n\t\treturn QStringList();\n\t}\n\t\n\t// If we were in the middle of tracing the key path when the loop ended, then something is wrong, bail.\n\tif (lastTokenWasDot || bracketCount || parenCount)\n\t\treturn QStringList();\n\t\n\t// OK, we've got an identifier chain in identifiers, in reverse order.  We want to start at\n\t// the beginning of the key path, and figure out what the class of the key path root is\n\tint key_path_index = static_cast<int>(identifiers.size()) - 1;\n\tstd::string &identifier_name = identifiers[static_cast<size_t>(key_path_index)];\n\tEidosGlobalStringID identifier_ID = EidosStringRegistry::GlobalStringIDForString(identifier_name);\n\tbool identifier_is_call = identifiers_are_calls[static_cast<size_t>(key_path_index)];\n\tconst EidosClass *key_path_class = nullptr;\n\t\n\tif (identifier_is_call)\n\t{\n\t\t// The root identifier is a call, so it should be a function call; try to look it up\n\t\tfor (const auto& function_iter : *functionMap)\n\t\t{\n\t\t\tconst EidosFunctionSignature *sig = function_iter.second.get();\n\t\t\t\n\t\t\tif (sig->call_name_.compare(identifier_name) == 0)\n\t\t\t{\n\t\t\t\tkey_path_class = sig->return_class_;\n\t\t\t\t\n\t\t\t\t// In some cases, the function signature does not have the information we need, because the class of the return value\n\t\t\t\t// of the function depends upon its parameters.  This is the case for functions like sample(), rep(), and so forth.\n\t\t\t\t// For this case, we have a special mechanism set up, whereby the EidosTypeInterpreter has logged the class of the\n\t\t\t\t// return value of function calls that it has evaluated.  We can look up the correct class in that log.  This is kind\n\t\t\t\t// of a gross solution, but short of rewriting all the completion code, it seems to be the easiest fix.  (Rewriting\n\t\t\t\t// to fix this more properly would involve doing code completion using a type-annotated tree, without any of the\n\t\t\t\t// token-stream handling that we have now; that would be a better design, but I'm going to save that rewrite for later.)\n\t\t\t\tif (!key_path_class)\n\t\t\t\t{\n\t\t\t\t\tauto callTypeIter = callTypeTable->find(identifier_positions[static_cast<size_t>(key_path_index)]);\n\t\t\t\t\t\n\t\t\t\t\tif (callTypeIter != callTypeTable->end())\n\t\t\t\t\t\tkey_path_class = callTypeIter->second;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse if (typeTable)\n\t{\n\t\t// The root identifier is not a call, so it should be a global symbol; try to look it up\n\t\tEidosTypeSpecifier type_specifier = typeTable->GetTypeForSymbol(identifier_ID);\n\t\t\n\t\tif (!!(type_specifier.type_mask & kEidosValueMaskObject))\n\t\t\tkey_path_class = type_specifier.object_class;\n\t}\n\t\n\tif (!key_path_class)\n\t\treturn QStringList();\t\t\t\t// unknown symbol at the root\n\t\n\t// Now we've got a class for the root of the key path; follow forward through the key path to arrive at the final type.\n\twhile (--key_path_index >= 0)\n\t{\n\t\tidentifier_name = identifiers[static_cast<size_t>(key_path_index)];\n\t\tidentifier_is_call = identifiers_are_calls[static_cast<size_t>(key_path_index)];\n\t\t\n\t\tEidosGlobalStringID identifier_id = EidosStringRegistry::GlobalStringIDForString(identifier_name);\n\t\t\n\t\tif (identifier_id == gEidosID_none)\n\t\t\treturn QStringList();\t\t\t// unrecognized identifier in the key path, so there is probably a typo and we can't complete off of it\n\t\t\n\t\tif (identifier_is_call)\n\t\t{\n\t\t\t// We have a method call; look up its signature and get the class\n\t\t\tconst EidosCallSignature *call_signature = key_path_class->SignatureForMethod(identifier_id);\n\t\t\t\n\t\t\tif (!call_signature)\n\t\t\t\treturn QStringList();\t\t\t// no signature, so the class does not support the method given\n\t\t\t\n\t\t\tkey_path_class = call_signature->return_class_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have a property; look up its signature and get the class\n\t\t\tconst EidosPropertySignature *property_signature = key_path_class->SignatureForProperty(identifier_id);\n\t\t\t\n\t\t\tif (!property_signature)\n\t\t\t\treturn QStringList();\t\t\t// no signature, so the class does not support the property given\n\t\t\t\n\t\t\tkey_path_class = property_signature->value_class_;\n\t\t}\n\t\t\n\t\tif (!key_path_class)\n\t\t\treturn QStringList();\t\t\t// unknown symbol at the root; the property yields a non-object type\n\t}\n\t\n\t// OK, we've now got a EidosValue object that represents the end of the line; the final dot is off of this object.\n\t// So we want to extract all of its properties and methods, and return them all as candidates.\n\tQStringList candidates;\n\tconst EidosClass *terminus = key_path_class;\n\t\n\t// First, a sorted list of globals\n\tfor (const auto &symbol_sig : *terminus->Properties())\n    {\n        if (!symbol_sig->deprecated_)\n            candidates << QString::fromStdString(symbol_sig->property_name_);\n\t}\n    \n\tcandidates.sort();\n\t\n\t// Next, a sorted list of methods, with () appended\n\tfor (const auto &method_sig : *terminus->Methods())\n\t{\n        if (!method_sig->deprecated_)\n        {\n            QString methodName = QString::fromStdString(method_sig->call_name_);\n            \n            methodName.append(\"()\");\n            candidates << methodName;\n        }\n\t}\n\t\n\treturn candidates;\n}\n\n//- (int64_t)eidosScoreAsCompletionOfString:(NSString *)base\nint64_t QtSLiMTextEdit::scoreForCandidateAsCompletionOfString(QString candidate, QString base)\n{\n    // Evaluate the quality of the target as a completion for completionBase and return a score.\n\t// We look for each character of completionBase in candidate, in order, case-insensitive; all\n\t// characters must be present in order for the target to be a completion at all.  Beyond that,\n\t// a higher score is garnered if the matches in candidate are (1) either uppercase or the 0th character,\n\t// and (2) if they are relatively near the beginning, and (3) if they occur contiguously.\n\tint64_t score = 0;\n\tint baseLength = base.length();\n\t\n\t// Do the comparison scan; find a match for each composed character sequence in base.  I *think*\n    // QString contains QChars that represent composed character sequences already, so I think in this\n    // port of the Objective-C code maybe I can ignore that issue...?  We work use rangeOfString: to do\n    // searches, to avoid issues with diacritical marks, alternative composition sequences, casing, etc.\n\tint firstUnusedIndex = 0, firstUnmatchedIndex = 0;\n\t\n\tdo\n\t{\n\t\t//NSRange baseRangeToMatch = [base rangeOfComposedCharacterSequenceAtIndex:firstUnmatchedIndex];\n\t\t//NSString *stringToMatch = [base substringWithRange:baseRangeToMatch];\n        int baseIndexToMatch = firstUnmatchedIndex;\n        QString stringToMatch = base.mid(baseIndexToMatch, 1);\n        QString uppercaseStringToMatch = stringToMatch.toUpper();\n\t\tint candidateMatchIndex;\n\t\t\n\t\tif ((stringToMatch == uppercaseStringToMatch) && (firstUnmatchedIndex != 0))\n\t\t{\n\t\t\t// If the character in base is uppercase, we only want to match an uppercase character in candidate.\n\t\t\t// The exception is the first character of base; WTF should match writeTempFile() well.\n            candidateMatchIndex = candidate.indexOf(stringToMatch, firstUnusedIndex);\n\t\t\tscore += 1000;\t// uppercase match\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the character in base is not uppercase, we will match any case in candidate, but we prefer a\n\t\t\t// lowercase character if it matches the very next part of candidate, otherwise we prefer uppercase.\n            candidateMatchIndex = candidate.indexOf(stringToMatch, firstUnusedIndex);\n\t\t\t\n\t\t\tif (candidateMatchIndex == firstUnusedIndex)\n\t\t\t{\n\t\t\t\tscore += 2000;\t// next-character match is even better than upper-case; continuity trumps camelcase\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tint uppercaseMatchIndex = candidate.indexOf(uppercaseStringToMatch, firstUnusedIndex);\n\t\t\t\t\n\t\t\t\tif (uppercaseMatchIndex != -1)\n\t\t\t\t{\n\t\t\t\t\tcandidateMatchIndex = uppercaseMatchIndex;\n\t\t\t\t\tscore += 1000;\t// uppercase match\n\t\t\t\t}\n\t\t\t\telse if (firstUnusedIndex > 0)\n\t\t\t\t{\n\t\t\t\t\t// This match is crap; we're jumping forward to a lowercase letter, so it's unlikely to be what\n\t\t\t\t\t// the user wants.  So we bail.  This can be commented out to return lower-quality matches.\n\t\t\t\t\treturn INT64_MIN;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// no match in candidate for the composed character sequence in base; candidate is not a good completion of base\n\t\tif (candidateMatchIndex == -1)\n\t\t\treturn INT64_MIN;\n\t\t\n\t\t// matching the very beginning of candidate is very good; we really want to match the start of a candidate\n\t\t// otherwise, earlier matches are better; a match at position 0 gets the largest score increment\n\t\tif (candidateMatchIndex == 0)\n\t\t\tscore += 100000;\n\t\telse\n            score -= (candidateMatchIndex * 10);\n        \n        // penalize skipping over a capital letter in candidate to get to the match position; iS is not a great match for initializeTreeSequence() compared to initializeSex()\n        for (int skippedIndex = firstUnusedIndex; skippedIndex < candidateMatchIndex; ++skippedIndex)\n        {\n            QString skippedChar = base.mid(skippedIndex, 1);\n            \n            if (skippedChar == skippedChar.toUpper())\n                score -= 50;\n        }\n\t\t\n\t\t// move firstUnusedIndex to follow the matched range in candidate\n\t\tfirstUnusedIndex = candidateMatchIndex + 1;\n\t\t\n\t\t// move to the next composed character sequence in base\n\t\tfirstUnmatchedIndex = baseIndexToMatch + 1;\n\t\tif (firstUnmatchedIndex >= baseLength)\n\t\t\tbreak;\n\t}\n\twhile (true);\n    \n    // penalize the unused length of the completed string, all else being equal\n    score -= (candidate.length() - firstUnmatchedIndex);\n\t\n\t// we want argument-name matches to be at the top, always, when they are available, so bump their score\n\tif (candidate.endsWith(\"=\"))\n\t\tscore += 1000000;\n    \n    //qDebug() << \"Score for\" << candidate << \"given base\" << base << \"==\" << score;\n\t\n\treturn score;\n}\n\n//- (NSArray *)completionsFromArray:(NSArray *)candidates matchingBase:(NSString *)base\nQStringList QtSLiMTextEdit::completionsFromArrayMatchingBase(QStringList candidates, QString base)\n{\n\tQStringList completions;\n\tint candidateCount = candidates.size();\n\t\n#if 0\n\t// This is simple prefix-based completion; if a candidates begins with base, then it is used\n\tfor (int candidateIndex = 0; candidateIndex < candidateCount; ++candidateIndex)\n\t{\n\t\tQString candidate = candidates[candidateIndex];\n\t\t\n\t\tif (candidate.startsWith(base))\n\t\t\tcompletions << candidate;\n\t}\n#else\n\t// This is part-based completion, where iTr will complete to initializeTreeSeq() and iGTy\n\t// will complete to initializeGenomicElementType().  To do this, we use a special comparator\n\t// that returns a score for the quality of the match, and then we sort all matches by score.\n\tstd::vector<int64_t> scores;\n\tQStringList unsortedCompletions;\n\t\n\tfor (int candidateIndex = 0; candidateIndex < candidateCount; ++candidateIndex)\n\t{\n\t\tQString candidate = candidates[candidateIndex];\n\t\tint64_t score = scoreForCandidateAsCompletionOfString(candidate, base);\n\t\t\n\t\tif (score != INT64_MIN)\n\t\t{\n\t\t\tunsortedCompletions << candidate;\n\t\t\tscores.emplace_back(score);\n\t\t}\n\t}\n\t\n\tif (scores.size())\n\t{\n\t\tstd::vector<int64_t> order = EidosSortIndexes(scores.data(), scores.size(), false);\n\t\t\n\t\tfor (int64_t index : order)\n\t\t\tcompletions << unsortedCompletions[static_cast<int>(index)];\n\t}\n#endif\n\t\n\treturn completions;\n}\n\n//- (NSArray *)completionsForTokenStream:(const std::vector<EidosToken> &)tokens index:(int)lastTokenIndex canExtend:(BOOL)canExtend withTypes:(EidosTypeTable *)typeTable functions:(EidosFunctionMap *)functionMap callTypes:(EidosCallTypeTable *)callTypeTable keywords:(NSArray *)keywords argumentNames:(NSArray *)argumentNames\nQStringList QtSLiMTextEdit::completionsForTokenStream(const std::vector<EidosToken> &tokens, int lastTokenIndex, bool canExtend, EidosTypeTable *typeTable, EidosFunctionMap *functionMap, EidosCallTypeTable *callTypeTable, QStringList keywords, QStringList argumentNames)\n{\n\t// What completions we offer depends on the token stream\n\tconst EidosToken &token = tokens[static_cast<size_t>(lastTokenIndex)];\n\tEidosTokenType token_type = token.token_type_;\n\t\n\tswitch (token_type)\n\t{\n\t\tcase EidosTokenType::kTokenNone:\n\t\tcase EidosTokenType::kTokenEOF:\n\t\tcase EidosTokenType::kTokenWhitespace:\n\t\tcase EidosTokenType::kTokenComment:\n\t\tcase EidosTokenType::kTokenCommentLong:\n\t\tcase EidosTokenType::kTokenInterpreterBlock:\n\t\tcase EidosTokenType::kTokenContextFile:\n\t\tcase EidosTokenType::kTokenContextEidosBlock:\n\t\tcase EidosTokenType::kFirstIdentifierLikeToken:\n\t\t\t// These should never be hit\n\t\t\treturn QStringList();\n\t\t\t\n\t\tcase EidosTokenType::kTokenIdentifier:\n\t\tcase EidosTokenType::kTokenIf:\n\t\tcase EidosTokenType::kTokenWhile:\n\t\tcase EidosTokenType::kTokenFor:\n\t\tcase EidosTokenType::kTokenNext:\n\t\tcase EidosTokenType::kTokenBreak:\n\t\tcase EidosTokenType::kTokenFunction:\n\t\tcase EidosTokenType::kTokenReturn:\n\t\tcase EidosTokenType::kTokenElse:\n\t\tcase EidosTokenType::kTokenDo:\n\t\tcase EidosTokenType::kTokenIn:\n\t\t\tif (canExtend)\n\t\t\t{\n\t\t\t\tQStringList completions;\n\t\t\t\t\n\t\t\t\t// This is the tricky case, because the identifier we're extending could be the end of a key path like foo.bar[5:8].ba...\n\t\t\t\t// We need to move backwards from the current token until we find or fail to find a dot token; if we see a dot we're in\n\t\t\t\t// a key path, otherwise we're in the global context and should filter from those candidates\n\t\t\t\tfor (int previousTokenIndex = lastTokenIndex - 1; previousTokenIndex >= 0; --previousTokenIndex)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &previous_token = tokens[static_cast<size_t>(previousTokenIndex)];\n\t\t\t\t\tEidosTokenType previous_token_type = previous_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\t// if the token we're on is skippable, continue backwards\n\t\t\t\t\tif ((previous_token_type == EidosTokenType::kTokenWhitespace) || (previous_token_type == EidosTokenType::kTokenComment) || (previous_token_type == EidosTokenType::kTokenCommentLong))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// if the token we're on is a dot, we are indeed at the end of a key path, and can fetch the completions for it\n\t\t\t\t\tif (previous_token_type == EidosTokenType::kTokenDot)\n\t\t\t\t\t{\n                        completions = completionsForKeyPathEndingInTokenIndexOfTokenStream(previousTokenIndex, tokens, typeTable, functionMap, callTypeTable, keywords);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we see a semicolon or brace, we are in a completely global context\n\t\t\t\t\tif ((previous_token_type == EidosTokenType::kTokenSemicolon) || (previous_token_type == EidosTokenType::kTokenLBrace) || (previous_token_type == EidosTokenType::kTokenRBrace))\n\t\t\t\t\t{\n                        completions = globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, keywords, QStringList());\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we see any other token, we are not in a key path; let's assume we're following an operator\n                    completions = globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, QStringList(), argumentNames);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If we ran out of tokens, we're at the beginning of the file and so in the global context\n\t\t\t\tif (completions.size() == 0)\n                    completions = globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, keywords, QStringList());\n\t\t\t\t\n\t\t\t\t// Now we have an array of possible completions; we just need to remove those that don't complete the base string,\n\t\t\t\t// according to a heuristic algorithm, and sort those that do match by a score of their closeness of match.\n                return completionsFromArrayMatchingBase(completions, QString::fromStdString(token.token_string_));\n\t\t\t}\n\t\t\telse if ((token_type == EidosTokenType::kTokenReturn) || (token_type == EidosTokenType::kTokenElse) || (token_type == EidosTokenType::kTokenDo) || (token_type == EidosTokenType::kTokenIn))\n\t\t\t{\n\t\t\t\t// If you can't extend and you're following an identifier, you presumably need an operator or a keyword or something;\n\t\t\t\t// you can't have two identifiers in a row.  The same is true of keywords that do not take an expression after them.\n\t\t\t\t// But return, else, do, and in can be followed immediately by an expression, so here we handle that case.  Identifiers\n\t\t\t\t// and other keywords will drop through to return nil below, expressing that we cannot complete in that case.\n\t\t\t\t// We used to put return, else, do, and in down the the operators at the bottom, but when canExtend is YES that\n\t\t\t\t// prevents them from completing to other things (\"in\" to \"inSLiMgui\", for example); moving them up to this case\n\t\t\t\t// allows that completion to work, but necessitates the addition of this block to get the correct functionality when\n\t\t\t\t// canExtend is NO.  BCH 1/22/2019\n                return globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, QStringList(), argumentNames);\n\t\t\t}\n\t\t\t\n\t\t\t// If the previous token was an identifier and we can't extend it, the next thing probably needs to be an operator or something\n\t\t\treturn QStringList();\n\t\t\t\n\t\tcase EidosTokenType::kTokenBad:\n\t\tcase EidosTokenType::kTokenNumber:\n\t\tcase EidosTokenType::kTokenString:\n\t\tcase EidosTokenType::kTokenRParen:\n\t\tcase EidosTokenType::kTokenRBracket:\n\t\tcase EidosTokenType::kTokenSingleton:\n\t\t\t// We don't have anything to suggest after such tokens; the next thing will need to be an operator, semicolon, etc.\n\t\t\treturn QStringList();\n\t\t\t\n\t\tcase EidosTokenType::kTokenDot:\n\t\t\t// This is the other tricky case, because we're being asked to extend a key path like foo.bar[5:8].\n            return completionsForKeyPathEndingInTokenIndexOfTokenStream(lastTokenIndex, tokens, typeTable, functionMap, callTypeTable, keywords);\n\t\t\t\n\t\tcase EidosTokenType::kTokenSemicolon:\n\t\tcase EidosTokenType::kTokenLBrace:\n\t\tcase EidosTokenType::kTokenRBrace:\n\t\t\t// We are in the global context and anything goes, including a new statement\n            return globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, keywords, QStringList());\n\t\t\t\n\t\tcase EidosTokenType::kTokenColon:\n\t\tcase EidosTokenType::kTokenComma:\n\t\tcase EidosTokenType::kTokenLParen:\n\t\tcase EidosTokenType::kTokenLBracket:\n\t\tcase EidosTokenType::kTokenPlus:\n\t\tcase EidosTokenType::kTokenMinus:\n\t\tcase EidosTokenType::kTokenMod:\n\t\tcase EidosTokenType::kTokenMult:\n\t\tcase EidosTokenType::kTokenExp:\n\t\tcase EidosTokenType::kTokenAnd:\n\t\tcase EidosTokenType::kTokenOr:\n\t\tcase EidosTokenType::kTokenDiv:\n\t\tcase EidosTokenType::kTokenConditional:\n        case EidosTokenType::kTokenAssign:\n        case EidosTokenType::kTokenAssign_R:\n\t\tcase EidosTokenType::kTokenEq:\n\t\tcase EidosTokenType::kTokenLt:\n\t\tcase EidosTokenType::kTokenLtEq:\n\t\tcase EidosTokenType::kTokenGt:\n\t\tcase EidosTokenType::kTokenGtEq:\n\t\tcase EidosTokenType::kTokenNot:\n\t\tcase EidosTokenType::kTokenNotEq:\n\t\t\t// We are following an operator or similar, so globals are OK but new statements are not\n            return globalCompletionsWithTypesFunctionsKeywordsArguments(typeTable, functionMap, QStringList(), argumentNames);\n\t}\n\t\n\treturn QStringList();\n}\n\n//- (NSArray *)uniquedArgumentNameCompletions:(std::vector<std::string> *)argumentCompletions\nQStringList QtSLiMTextEdit::uniquedArgumentNameCompletions(std::vector<std::string> *argumentCompletions)\n{\n\t// put argument-name completions, if any, at the top of the list; we unique them (preserving order) and add \"=\"\n\tif (argumentCompletions && argumentCompletions->size())\n\t{\n\t\tQStringList completionsWithArgs;\n\t\t\n\t\tfor (std::string &arg_completion : *argumentCompletions)\n            completionsWithArgs << QString::fromStdString(arg_completion).append(\"=\");\n\t\t\n        completionsWithArgs.removeDuplicates();\n\t\treturn completionsWithArgs;\n\t}\n\t\n\treturn QStringList();\n}\n\n//- (BOOL)eidosTextView:(EidosTextView *)eidosTextView completionContextWithScriptString:(NSString *)completionScriptString selection:(NSRange)selection typeTable:(EidosTypeTable **)typeTable functionMap:(EidosFunctionMap **)functionMap callTypeTable:(EidosCallTypeTable **)callTypeTable keywords:(NSMutableArray *)keywords argumentNameCompletions:(std::vector<std::string> *)argNameCompletions\nvoid QtSLiMTextEdit::slimSpecificCompletion(QString completionScriptString, NSRange selection, EidosTypeTable **typeTable, EidosFunctionMap **functionMap, EidosCallTypeTable **callTypeTable, QStringList *keywords, std::vector<std::string> *argNameCompletions)\n{\n    // Code completion in the console window and other ancillary EidosTextViews should use the standard code completion\n    // machinery in EidosTextView.  In the script view, however, we want things to behave somewhat differently.  In\n    // other contexts, we want the variables and functions available to depend solely upon the current state of the\n    // simulation; whatever is actually available is what code completion provides.  In the script view, however, we\n    // want to be smarter than that.  Initialization functions should be available when the user is completing\n    // inside an initialize() callback, and not available otherwise, regardless of the current simulation state.\n    // Similarly, variables associated with particular types of callbacks should always be available within those\n    // callbacks; variables defined in script blocks other than the focal block should not be visible in code\n    // completion; defined constants should be available everywhere; and it should be assumed that variables with\n    // names like pX, mX, gX, and sX have their usual types even if they are not presently defined.  This delegate\n    // method accomplishes all of those things, by replacing the standard EidosTextView completion handling.\n    std::string script_string(completionScriptString.toStdString());\n    SLiMEidosScript script(script_string);\n    \n    // Parse an \"interpreter block\" bounded by an EOF rather than a \"script block\" that requires braces\n    script.Tokenize(true, false);\t\t\t\t// make bad tokens as needed, do not keep nonsignificant tokens\n    script.ParseSLiMFileToAST(true);\t\t\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n    \n    // Substitute a type table of class SLiMTypeTable and add any defined symbols to it.  We use SLiMTypeTable so that\n    // variables like pX, gX, mX, and sX have a known object type even if they are not presently defined in the simulation.\n    *typeTable = new SLiMTypeTable();\n    \n    QtSLiMWindow *windowSLiMController = slimControllerForWindow();\n    QtSLiMEidosConsole *consoleController = (windowSLiMController ? windowSLiMController->ConsoleController() : nullptr);\n    EidosSymbolTable *symbols = (consoleController ? consoleController->symbolTable() : nullptr);\n    \n    if (symbols)\n        symbols->AddSymbolsToTypeTable(*typeTable);\n    \n    // Use the script text view's facility for using type-interpreting to get a \"definitive\" function map.  This way\n    // all functions that are defined, even if below the completion point, end up in the function map.\n    *functionMap = functionMapForScriptString(toPlainText(), false);\n    \n    Community::AddSLiMFunctionsToMap(**functionMap);\n    \n    // Now we scan through the children of the root node, each of which is the root of a SLiM script block.  The last\n    // script block is the one we are actually completing inside, but we also want to do a quick scan of any other\n    // blocks we find, solely to add entries for any defineConstant() calls we can decode.\n    const EidosASTNode *script_root = script.AST();\n    \n    if (script_root && (script_root->children_.size() > 0))\n    {\n        EidosASTNode *completion_block = script_root->children_.back();\n        \n        // If the last script block has a range that ends before the start of the selection, then we are completing after the end\n        // of that block, at the outer level of the script.  Detect that case and fall through to the handler for it at the end.\n        int32_t completion_block_end = completion_block->token_->token_end_;\n        \n        if (static_cast<int>(selection.location) > completion_block_end)\n        {\n            // Selection is after end of completion_block\n            completion_block = nullptr;\n        }\n        \n        if (completion_block)\n        {\n            for (EidosASTNode *script_block_node : script_root->children_)\n            {\n                // skip species/ticks specifiers, which are identifier token nodes at the top level of the AST with one child\n                if ((script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (script_block_node->children_.size() == 1))\n                    continue;\n                \n                // script_block_node can have various children, such as an sX identifier, start and end ticks, a block type\n                // identifier like late(), and then the root node of the compound statement for the script block.  We want to\n                // decode the parts that are important to us, without the complication of making SLiMEidosBlock objects.\n                EidosASTNode *block_statement_root = nullptr;\n                SLiMEidosBlockType block_type = SLiMEidosBlockType::SLiMEidosNoBlockType;\n                \n                for (EidosASTNode *block_child : script_block_node->children_)\n                {\n                    EidosToken *child_token = block_child->token_;\n                    \n                    if (child_token->token_type_ == EidosTokenType::kTokenIdentifier)\n                    {\n                        const std::string &child_string = child_token->token_string_;\n                        \n                        if (child_string.compare(gStr_first) == 0)\t\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosEventFirst;\n                        else if (child_string.compare(gStr_early) == 0)         \tblock_type = SLiMEidosBlockType::SLiMEidosEventEarly;\n                        else if (child_string.compare(gStr_late) == 0)\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosEventLate;\n                        else if (child_string.compare(gStr_initialize) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosInitializeCallback;\n                        else if (child_string.compare(gStr_fitnessEffect) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosFitnessEffectCallback;\n                        else if (child_string.compare(gStr_mutationEffect) == 0)\tblock_type = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\n                        else if (child_string.compare(gStr_interaction) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosInteractionCallback;\n                        else if (child_string.compare(gStr_mateChoice) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n                        else if (child_string.compare(gStr_modifyChild) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n                        else if (child_string.compare(gStr_recombination) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n                        else if (child_string.compare(gStr_mutation) == 0)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosMutationCallback;\n                        else if (child_string.compare(gStr_survival) == 0)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosSurvivalCallback;\n                        else if (child_string.compare(gStr_reproduction) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosReproductionCallback;\n                        \n                        // Check for an sX designation on a script block and, if found, add a symbol for it\n                        else if ((block_child == script_block_node->children_[0]) && (child_string.length() >= 2))\n                        {\n                            if (child_string[0] == 's')\n                            {\n                                bool all_numeric = true;\n                                \n                                for (size_t idx = 1; idx < child_string.length(); ++idx)\n                                    if (!isdigit(child_string[idx]))\n                                        all_numeric = false;\n                                \n                                if (all_numeric)\n                                {\n                                    EidosGlobalStringID constant_id = EidosStringRegistry::GlobalStringIDForString(child_string);\n                                    \n                                    (*typeTable)->SetTypeForSymbol(constant_id, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class});\n                                }\n                            }\n                        }\n                    }\n                    else if (child_token->token_type_ == EidosTokenType::kTokenLBrace)\n                    {\n                        block_statement_root = block_child;\n                    }\n                    else if (child_token->token_type_ == EidosTokenType::kTokenFunction)\n                    {\n                        // We handle function blocks a bit differently; see below\n                        block_type = SLiMEidosBlockType::SLiMEidosUserDefinedFunction;\n                        \n                        if (block_child->children_.size() >= 4)\n                            block_statement_root = block_child->children_[3];\n                    }\n                }\n                \n                // Now we know the type of the node, and the root node of its compound statement; extract what we want\n                if (block_statement_root)\n                {\n                    // The species/community symbols are  defined in all blocks except initialize() blocks; we need to add\n                    // and remove them dynamically so that each block has it defined or not defined as necessary.  Since\n                    // the completion block is last, the symbols will be correctly defined at the end of this process.\n                    if (block_type == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n                    {\n                        std::vector<EidosGlobalStringID> symbol_ids = (*typeTable)->AllSymbolIDs();\n                        \n                        for (EidosGlobalStringID symbol_id : symbol_ids)\n                        {\n                            EidosTypeSpecifier typeSpec = (*typeTable)->GetTypeForSymbol(symbol_id);\n                            \n                            if ((typeSpec.type_mask == kEidosValueMaskObject) && ((typeSpec.object_class == gSLiM_Community_Class) || (typeSpec.object_class == gSLiM_Species_Class)))\n                                (*typeTable)->RemoveTypeForSymbol(symbol_id);\n                        }\n                    }\n                    else\n                    {\n                        Community *community = (windowSLiMController ? windowSLiMController->community : nullptr);\n                        \n                        (*typeTable)->SetTypeForSymbol(gID_community, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Community_Class});\n                        \n                        if (community)\n                        {\n                            for (Species *species : community->AllSpecies())\n                            {\n                                EidosGlobalStringID species_symbol = species->self_symbol_.first;\n                                \n                                (*typeTable)->SetTypeForSymbol(species_symbol, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Species_Class});\n                            }\n                        }\n                        else\n                        {\n                            // We don't have a community object, so we don't have a vector of species; this is usually because of a failed parse\n                            // In this case, we try to keep things functional by just assuming the single-species case and defining \"sim\"\n                            (*typeTable)->SetTypeForSymbol(gID_sim, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Species_Class});\n                        }\n                    }\n                    \n                    // The slimgui symbol is always available within a block, but not at the top level\n                    (*typeTable)->SetTypeForSymbol(gID_slimgui, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMgui_Class});\n                    \n                    // Do the same for the zero-tick functions, which should be defined in initialization() blocks and\n                    // not in other blocks; we add and remove them dynamically so they are defined as appropriate.  We ought\n                    // to do this for other block-specific stuff as well (like the stuff below), but it is unlikely to matter.\n                    // Note that we consider the zero-gen functions to always be defined inside function blocks, since the\n                    // function might be called from the zero gen (we have no way of knowing definitively).\n                    if ((block_type == SLiMEidosBlockType::SLiMEidosInitializeCallback) || (block_type == SLiMEidosBlockType::SLiMEidosUserDefinedFunction))\n                        Community::AddZeroTickFunctionsToMap(**functionMap);\n                    else\n                        Community::RemoveZeroTickFunctionsFromMap(**functionMap);\n                    \n                    if (script_block_node == completion_block)\n                    {\n                        // This is the block we're actually completing in the context of; it is also the last block in the script\n                        // snippet that we're working with.  We want to first define any callback-associated variables for the block.\n                        // Note that self is not defined inside functions, even though they are SLiMEidosBlocks; we pretend we are Eidos.\n                        if (block_type == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n                            (*typeTable)->RemoveTypeForSymbol(gID_self);\n                        else\n                            (*typeTable)->SetTypeForSymbol(gID_self, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class});\n                        \n                        switch (block_type)\n                        {\n                        case SLiMEidosBlockType::SLiMEidosEventFirst:\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosEventEarly:\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosEventLate:\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosInitializeCallback:\n                            (*typeTable)->RemoveSymbolsOfClass(gSLiM_Subpopulation_Class);\t// subpops defined upstream from us still do not exist for us\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_mut,\t\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Mutation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_homozygous,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_effect,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosInteractionCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_distance,\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_strength,\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_receiver,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_exerter,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_sourceSubpop,\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gEidosID_weights,\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosModifyChildCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_child,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_parent1,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_isCloning,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_isSelfing,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_parent2,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_sourceSubpop,\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosRecombinationCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_haplosome1,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_haplosome2,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_breakpoints,\t\tEidosTypeSpecifier{kEidosValueMaskInt, nullptr});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosMutationCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_mut,\t\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Mutation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_parent,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_element,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_GenomicElement_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_haplosome,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_originalNuc,\t\tEidosTypeSpecifier{kEidosValueMaskInt, nullptr});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosSurvivalCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_surviving,       EidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_fitness,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            (*typeTable)->SetTypeForSymbol(gID_draw,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosReproductionCallback:\n                            (*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n                            (*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n                            break;\n                        case SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n                        {\n                            // Similar to the local variables that are defined for callbacks above, here we need to define the parameters to the\n                            // function, by parsing the relevant AST nodes; this is parallel to EidosTypeInterpreter::TypeEvaluate_FunctionDecl()\n                            EidosASTNode *function_declaration_node = script_block_node->children_[0];\n                            const EidosASTNode *param_list_node = function_declaration_node->children_[2];\n                            const std::vector<EidosASTNode *> &param_nodes = param_list_node->children_;\n                            std::vector<std::string> used_param_names;\n                            \n                            for (EidosASTNode *param_node : param_nodes)\n                            {\n                                const std::vector<EidosASTNode *> &param_children = param_node->children_;\n                                int param_children_count = static_cast<int>(param_children.size());\n                                \n                                if ((param_children_count == 2) || (param_children_count == 3))\n                                {\n                                    EidosTypeSpecifier &param_type = param_children[0]->typespec_;\n                                    const std::string &param_name = param_children[1]->token_->token_string_;\n                                    \n                                    // Check param_name; it needs to not be used by another parameter\n                                    if (std::find(used_param_names.begin(), used_param_names.end(), param_name) != used_param_names.end())\n                                        continue;\n                                    \n                                    if (param_children_count >= 2)\n                                    {\n                                        // param_node has 2 or 3 children (type, identifier, [default]); we don't care about default values\n                                        (*typeTable)->SetTypeForSymbol(EidosStringRegistry::GlobalStringIDForString(param_name), param_type);\n                                    }\n                                }\n                            }\n                            break;\n                        }\n                        case SLiMEidosBlockType::SLiMEidosNoBlockType: break;\t// never hit\n                        }\n                    }\n                    \n                    if (script_block_node == completion_block)\n                    {\n                        // Make a type interpreter and add symbols to our type table using it\n                        // We use SLiMTypeInterpreter because we want to pick up definitions of SLiM constants\n                        SLiMTypeInterpreter typeInterpreter(block_statement_root, **typeTable, **functionMap, **callTypeTable);\n                        \n                        typeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(argNameCompletions, script_string.length());\t// result not used\n                        \n                        return;\n                    }\n                    else\n                    {\n                        // This is not the block we're completing in.  We want to add symbols for any constant-defining calls\n                        // in this block; apart from that, this block cannot affect the completion block, due to scoping.\n                        // However, constant-defining calls might use the types of variables, like defineConstant(\"foo\", bar)\n                        // where the type of foo comes from the type of bar; so we need to keep track of all symbols even\n                        // though they will fall out of scope.  We therefore use a separate local type table with a reference\n                        // upward to our main type table.\n                        EidosTypeTable scopedTypeTable(**typeTable);\n                        \n                        // Make a type interpreter and add symbols to our type table using it\n                        // We use SLiMTypeInterpreter because we want to pick up definitions of SLiM constants\n                        SLiMTypeInterpreter typeInterpreter(block_statement_root, scopedTypeTable, **functionMap, **callTypeTable);\n                        \n                        typeInterpreter.SetExternalTypeTable(*typeTable);\t\t// defined constants/variables should also go into the global scope\n                        typeInterpreter.TypeEvaluateInterpreterBlock();         // result not used\n                    }\n                }\n            }\n        }\n    }\n    \n    // We drop through to here if we have a bad or empty script root, or if the final script block (completion_block) didn't\n    // have a compound statement (meaning its starting brace has not yet been typed), or if we're completing outside of any\n    // existing script block.  In these sorts of cases, we want to return completions for the outer level of a SLiM script.\n    // This means that standard Eidos language keywords like \"while\", \"next\", etc. are not legal, but SLiM script block\n    // keywords like \"first\", \"early\", \"late\", \"mutationEffect\", \"fitnessEffect\", \"interaction\", \"mateChoice\", \"modifyChild\",\n    // \"recombination\", \"mutation\", \"survival\", and \"reproduction\" are.  We also add \"species\" and \"ticks\" here for\n    // multispecies models.\n    // Note that the strings here are display strings; they are fixed to contain newlines in insertCompletion()\n    keywords->clear();\n    (*keywords) << \"initialize() { }\";\n    (*keywords) << \"first() { }\";\n    (*keywords) << \"early() { }\";\n    (*keywords) << \"late() { }\";\n    (*keywords) << \"mutationEffect() { }\";\n    (*keywords) << \"fitnessEffect() { }\";\n    (*keywords) << \"interaction() { }\";\n    (*keywords) << \"mateChoice() { }\";\n    (*keywords) << \"modifyChild() { }\";\n    (*keywords) << \"recombination() { }\";\n    (*keywords) << \"mutation() { }\";\n    (*keywords) << \"survival() { }\";\n    (*keywords) << \"reproduction() { }\";\n    (*keywords) << \"function (void)name(void) { }\";\n    (*keywords) << \"species\";\n    (*keywords) << \"ticks\";\n    \n    // At the outer level, functions are also not legal\n    (*functionMap)->clear();\n    \n    // And no variables exist except SLiM objects like pX, gX, mX, sX and species symbols\n    std::vector<EidosGlobalStringID> symbol_ids = (*typeTable)->AllSymbolIDs();\n    \n    for (EidosGlobalStringID symbol_id : symbol_ids)\n    {\n        EidosTypeSpecifier typeSpec = (*typeTable)->GetTypeForSymbol(symbol_id);\n        \n        if ((typeSpec.type_mask != kEidosValueMaskObject) || (typeSpec.object_class == gSLiM_Community_Class) || (typeSpec.object_class == gSLiM_SLiMgui_Class))\n            (*typeTable)->RemoveTypeForSymbol(symbol_id);\n    }\n}\n\n//- (void)_completionHandlerWithRangeForCompletion:(NSRange *)baseRange completions:(NSArray **)completions\nvoid QtSLiMTextEdit::_completionHandlerWithRangeForCompletion(NSRange *baseRange, QStringList *completions)\n{\n    QString scriptString;\n    int selectionStart, selectionLength, rangeOffset;\n    \n    scriptStringAndSelection(scriptString, selectionStart, selectionLength, rangeOffset);\n\n    NSRange selection = {selectionStart, selectionLength};\t// ignore charRange and work from the selection\n\tint selStart = selection.location;\n\t\n\t//if (selStart != NSNotFound)       // I don't think this can happen in Qt; you always have a text cursor...\n\t{\n\t\t// Get the substring up to the start of the selection; that is the range relevant for completion\n\t\tQString scriptSubstring = scriptString.left(selStart);\n\t\tstd::string script_string(scriptSubstring.toStdString());\n\t\t\n\t\t// Do shared completion processing that can be intercepted by our delegate: getting a type table for defined variables,\n\t\t// as well as a function map and any added language keywords, all of which depend upon the point of completion\n\t\tEidosTypeTable typeTable;\n\t\tEidosTypeTable *typeTablePtr = &typeTable;\n\t\tEidosFunctionMap functionMap(*EidosInterpreter::BuiltInFunctionMap());\n\t\tEidosFunctionMap *functionMapPtr = &functionMap;\n\t\tEidosCallTypeTable callTypeTable;\n\t\tEidosCallTypeTable *callTypeTablePtr = &callTypeTable;\n        QStringList keywords = {\"break\", \"do\", \"else\", \"for\", \"if\", \"in\", \"next\", \"return\", \"while\", \"function\"};\n\t\tstd::vector<std::string> argumentCompletions;\n\t\t\n\t\tif (scriptType == ScriptType::SLiMScriptType)\n            slimSpecificCompletion(scriptSubstring, selection, &typeTablePtr, &functionMapPtr, &callTypeTablePtr, &keywords, &argumentCompletions);\n\t\t\n\t\t// set up automatic disposal of a substitute type table or function map provided by delegate\n\t\tstd::unique_ptr<EidosTypeTable> raii_typeTablePtr((typeTablePtr != &typeTable) ? typeTablePtr : nullptr);\n\t\tstd::unique_ptr<EidosFunctionMap> raii_functionMapPtr((functionMapPtr != &functionMap) ? functionMapPtr : nullptr);\n\t\tstd::unique_ptr<EidosCallTypeTable> raii_callTypeTablePtr((callTypeTablePtr != &callTypeTable) ? callTypeTablePtr : nullptr);\n\t\t\n\t\tif (scriptType != ScriptType::SLiMScriptType)\n\t\t{\n\t\t\t// First, set up a base type table using the symbol table\n\t\t\tEidosSymbolTable *symbols = gEidosConstantsSymbolTable;\n\t\t\t\n            symbols = symbolsFromBaseSymbols(symbols);\n\t\t\t\n\t\t\tif (symbols)\n\t\t\t\tsymbols->AddSymbolsToTypeTable(typeTablePtr);\n\t\t\t\n\t\t\t// Next, a definitive function map that covers all functions defined in the entire script string (not just the script above\n\t\t\t// the completion point); this seems best, for mutually recursive functions etc..  Duplicate it back into functionMap and\n\t\t\t// delete the original, so we don't get confused.\n\t\t\tEidosFunctionMap *definitive_function_map = functionMapForScriptString(scriptString, false);\n\t\t\t\n\t\t\tfunctionMap = *definitive_function_map;\n\t\t\tdelete definitive_function_map;\n\t\t\t\n\t\t\t// Next, add type table entries based on parsing and analysis of the user's code\n\t\t\tEidosScript script(script_string);\n\t\t\t\n\t\t\tscript.Tokenize(true, false);\t\t\t\t\t// make bad tokens as needed, do not keep nonsignificant tokens\n\t\t\tscript.ParseInterpreterBlockToAST(true, true);\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n\t\t\t\n\t\t\tEidosTypeInterpreter typeInterpreter(script, *typeTablePtr, *functionMapPtr, *callTypeTablePtr);\n\t\t\t\n\t\t\ttypeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(&argumentCompletions, script_string.length());\t// result not used\n\t\t}\n\t\t\n\t\t// Tokenize; we can't use the tokenization done above, as we want whitespace tokens here...\n\t\tEidosScript script(script_string);\n\t\tscript.Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n\t\t\n\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\tint lastTokenIndex = static_cast<int>(tokens.size()) - 1;\n\t\tbool endedCleanly = false, lastTokenInterrupted = false;\n\t\t\n\t\t// if we ended with an EOF, that means we did not have a raise and there should be no untokenizable range at the end\n\t\tif ((lastTokenIndex >= 0) && (tokens[static_cast<size_t>(lastTokenIndex)].token_type_ == EidosTokenType::kTokenEOF))\n\t\t{\n\t\t\t--lastTokenIndex;\n\t\t\tendedCleanly = true;\n\t\t}\n\t\t\n\t\t// if we are at the end of a comment, without whitespace following it, then we are actually in the comment, and cannot complete\n\t\t// BCH 5 August 2017: Note that EidosTokenType::kTokenCommentLong is deliberately omitted here; this rule does not apply to it\n\t\tif ((lastTokenIndex >= 0) && (tokens[static_cast<size_t>(lastTokenIndex)].token_type_ == EidosTokenType::kTokenComment))\n\t\t{\n            if (baseRange) *baseRange = {NSNotFound, 0};\n\t\t\tif (completions) *completions = QStringList();\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// if we ended with whitespace or a comment, the previous token cannot be extended\n\t\twhile (lastTokenIndex >= 0) {\n\t\t\tconst EidosToken &token = tokens[static_cast<size_t>(lastTokenIndex)];\n\t\t\t\n\t\t\tif ((token.token_type_ != EidosTokenType::kTokenWhitespace) && (token.token_type_ != EidosTokenType::kTokenComment) && (token.token_type_ != EidosTokenType::kTokenCommentLong))\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t--lastTokenIndex;\n\t\t\tlastTokenInterrupted = true;\n\t\t}\n\t\t\n\t\t// now diagnose what range we want to use as a basis for completion\n\t\tif (!endedCleanly)\n\t\t{\n\t\t\t// the selection is at the end of an untokenizable range; we might be in the middle of a string or a comment,\n\t\t\t// or there might be a tokenization error upstream of us.  let's not try to guess what the situation is.\n            if (baseRange) *baseRange = {NSNotFound, 0};\n\t\t\tif (completions) *completions = QStringList();\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (lastTokenIndex < 0)\n\t\t\t{\n\t\t\t\t// We're at the end of nothing but initial whitespace and comments; or if (!lastTokenInterrupted),\n\t\t\t\t// we're at the very beginning of the file.  Either way, offer insertion-point completions.\n                if (baseRange) *baseRange = {selection.location + rangeOffset, 0};\n\t\t\t\tif (completions) *completions = globalCompletionsWithTypesFunctionsKeywordsArguments(typeTablePtr, functionMapPtr, keywords, QStringList());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tconst EidosToken &token = tokens[static_cast<size_t>(lastTokenIndex)];\n\t\t\tEidosTokenType token_type = token.token_type_;\n\t\t\t\n\t\t\t// BCH 31 May 2016: If the previous token is a right-paren, that is a tricky case because we could be following\n\t\t\t// for(), an if(), or while (), in which case we should allow an identifier to follow the right paren, or we could\n\t\t\t// be following parentheses for grouping, i.e. (a+b), or parentheses for a function call, foo(), in which case we\n\t\t\t// should not allow an identifier to follow the right paren.  This annoyance is basically because the right paren\n\t\t\t// serves a lot of different functions in the language and so just knowing that we are after one is not sufficient.\n\t\t\t// So we will walk backwards, balancing our parenthesis count, to try to figure out which case we are in.  Note\n\t\t\t// that even this code is not quite right; it mischaracterizes the do...while() case as allowing an identifier to\n\t\t\t// follow, because it sees the \"while\".  This is harder to fix, and do...while() is not a common construct, and\n\t\t\t// the mistake is pretty harmless, so whatever.\n\t\t\tif (token_type == EidosTokenType::kTokenRParen)\n\t\t\t{\n\t\t\t\tint parenCount = 1;\n\t\t\t\tint walkbackIndex = lastTokenIndex;\n\t\t\t\t\n\t\t\t\t// First walk back until our paren count balances\n\t\t\t\twhile (--walkbackIndex >= 0)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &walkback_token = tokens[static_cast<size_t>(walkbackIndex)];\n\t\t\t\t\tEidosTokenType walkback_token_type = walkback_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (walkback_token_type == EidosTokenType::kTokenRParen)\t\t\tparenCount++;\n\t\t\t\t\telse if (walkback_token_type == EidosTokenType::kTokenLParen)\t\tparenCount--;\n\t\t\t\t\t\n\t\t\t\t\tif (parenCount == 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Then walk back over whitespace, and if the first non-white thing we see is right, allow completion\n\t\t\t\twhile (--walkbackIndex >= 0)\n\t\t\t\t{\n\t\t\t\t\tconst EidosToken &walkback_token = tokens[static_cast<size_t>(walkbackIndex)];\n\t\t\t\t\tEidosTokenType walkback_token_type = walkback_token.token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif ((walkback_token_type != EidosTokenType::kTokenWhitespace) && (walkback_token_type != EidosTokenType::kTokenComment) && (walkback_token_type != EidosTokenType::kTokenCommentLong))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((walkback_token_type == EidosTokenType::kTokenFor) || (walkback_token_type == EidosTokenType::kTokenWhile) || (walkback_token_type == EidosTokenType::kTokenIf))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We are at the end of for(), if(), or while(), so we allow global completions as if we were after a semicolon\n                            if (baseRange) *baseRange = {selection.location + rangeOffset, 0};\n\t\t\t\t\t\t\tif (completions) *completions = globalCompletionsWithTypesFunctionsKeywordsArguments(typeTablePtr, functionMapPtr, keywords, QStringList());\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\t// we didn't hit one of the favored cases, so the code below will reject completion\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (lastTokenInterrupted)\n\t\t\t{\n\t\t\t\t// the last token cannot be extended, so if the last token is something an identifier can follow, like an\n\t\t\t\t// operator, then we can offer completions at the insertion point based on that, otherwise punt.\n\t\t\t\tif ((token_type == EidosTokenType::kTokenNumber) || (token_type == EidosTokenType::kTokenString) || (token_type == EidosTokenType::kTokenRParen) || (token_type == EidosTokenType::kTokenRBracket) || (token_type == EidosTokenType::kTokenIdentifier) || (token_type == EidosTokenType::kTokenIf) || (token_type == EidosTokenType::kTokenWhile) || (token_type == EidosTokenType::kTokenFor) || (token_type == EidosTokenType::kTokenNext) || (token_type == EidosTokenType::kTokenBreak) || (token_type == EidosTokenType::kTokenFunction))\n\t\t\t\t{\n                    if (baseRange) *baseRange = {NSNotFound, 0};\n\t\t\t\t\tif (completions) *completions = QStringList();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n                if (baseRange) *baseRange = {selection.location + rangeOffset, 0};\n\t\t\t\tif (completions)\n\t\t\t\t{\n                    QStringList argumentCompletionsArray = uniquedArgumentNameCompletions(&argumentCompletions);\n                    \n                    *completions = completionsForTokenStream(tokens, lastTokenIndex, false, typeTablePtr, functionMapPtr, callTypeTablePtr, keywords, argumentCompletionsArray);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the last token was not interrupted, so we can offer completions of it if we want to.\n                NSRange tokenRange = {token.token_UTF16_start_, token.token_UTF16_end_ - token.token_UTF16_start_ + 1};\n\t\t\t\t\n\t\t\t\tif (token_type >= EidosTokenType::kTokenIdentifier)\n\t\t\t\t{\n                    if (baseRange) *baseRange = {tokenRange.location + rangeOffset, tokenRange.length};\n\t\t\t\t\tif (completions)\n\t\t\t\t\t{\n                        QStringList argumentCompletionsArray = uniquedArgumentNameCompletions(&argumentCompletions);\n\t\t\t\t\t\t\n                        *completions = completionsForTokenStream(tokens, lastTokenIndex, true, typeTablePtr, functionMapPtr, callTypeTablePtr, keywords, argumentCompletionsArray);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ((token_type == EidosTokenType::kTokenNumber) || (token_type == EidosTokenType::kTokenString) || (token_type == EidosTokenType::kTokenRParen) || (token_type == EidosTokenType::kTokenRBracket))\n\t\t\t\t{\n                    if (baseRange) *baseRange = {NSNotFound, 0};\n\t\t\t\t\tif (completions) *completions = QStringList();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n                if (baseRange) *baseRange = {selection.location + rangeOffset, 0};\n\t\t\t\tif (completions)\n\t\t\t\t{\n                    QStringList argumentCompletionsArray = uniquedArgumentNameCompletions(&argumentCompletions);\n\t\t\t\t\t\n                    *completions = completionsForTokenStream(tokens, lastTokenIndex, false, typeTablePtr, functionMapPtr, callTypeTablePtr, keywords, argumentCompletionsArray);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n//\n//  LineNumberArea\n//\n\n// This provides line numbers in QtSLiMScriptTextEdit\n// This code is adapted from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html\nclass LineNumberArea : public QWidget\n{\npublic:\n    LineNumberArea(QtSLiMScriptTextEdit *editor);\n\n    virtual QSize sizeHint() const override { return QSize(codeEditor->lineNumberAreaWidth(), 0); }\n\nprotected:\n    virtual bool event(QEvent *p_event) override;\n    virtual void paintEvent(QPaintEvent *p_paintEvent) override { codeEditor->lineNumberAreaPaintEvent(p_paintEvent); }\n    virtual void mousePressEvent(QMouseEvent *p_mouseEvent) override { codeEditor->lineNumberAreaMousePressEvent(p_mouseEvent); }\n    virtual void mouseMoveEvent(QMouseEvent *p_mouseEvent) override { codeEditor->lineNumberAreaMouseMoveEvent(p_mouseEvent); }\n    virtual void mouseReleaseEvent(QMouseEvent *p_mouseEvent) override { codeEditor->lineNumberAreaMouseReleaseEvent(p_mouseEvent); }\n    virtual void contextMenuEvent(QContextMenuEvent *p_event) override { codeEditor->lineNumberAreaContextMenuEvent(p_event); }\n    virtual void wheelEvent(QWheelEvent *p_wheelEvent) override { codeEditor->lineNumberAreaWheelEvent(p_wheelEvent); }\n\nprivate:\n    QtSLiMScriptTextEdit *codeEditor;\n};\n\nLineNumberArea::LineNumberArea(QtSLiMScriptTextEdit *editor) : QWidget(editor), codeEditor(editor)\n{\n    setMouseTracking(true);     // for live tooltip updating (debug point gutter vs. line numbers)\n}\n\nbool LineNumberArea::event(QEvent *p_event)\n{\n    if (p_event->type() == QEvent::ToolTip) {\n        QHelpEvent *helpEvent = static_cast<QHelpEvent *>(p_event);\n        codeEditor->lineNumberAreaToolTipEvent(helpEvent); \n        return true;\n    }\n    return QWidget::event(p_event);\n}\n\n\n//\n//  QtSLiMScriptTextEdit\n//\n\nQtSLiMScriptTextEdit::QtSLiMScriptTextEdit(const QString &text, QWidget *p_parent) : QtSLiMTextEdit(text, p_parent)\n{\n    sharedInit();\n}\n\nQtSLiMScriptTextEdit::QtSLiMScriptTextEdit(QWidget *p_parent) : QtSLiMTextEdit(p_parent)\n{\n    sharedInit();\n}\n\nvoid QtSLiMScriptTextEdit::sharedInit(void)\n{\n    setCenterOnScroll(true);\n    \n    initializeLineNumbers();\n    \n    // set up to listen to changes to page guide prefs\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::pageGuidePrefsChanged, this, [this]() { viewport()->update(); });\n}\n\nvoid QtSLiMScriptTextEdit::initializeLineNumbers(void)\n{\n    // This code is adapted from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html\n    lineNumberArea = new LineNumberArea(this);\n    \n    connect(this->document(), SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));\n    connect(this->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateLineNumberArea(int)));\n    connect(this, SIGNAL(textChanged()), this, SLOT(updateLineNumberArea()));\n    connect(this, SIGNAL(selectionChanged()), this, SLOT(updateLineNumberArea()));\n    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateLineNumberArea()));\n    \n    connect(this, &QtSLiMScriptTextEdit::selectionChanged, this, &QtSLiMScriptTextEdit::highlightCurrentLine);\n    connect(this, &QtSLiMScriptTextEdit::cursorPositionChanged, this, &QtSLiMScriptTextEdit::highlightCurrentLine);\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, &QtSLiMScriptTextEdit::highlightCurrentLine);\n    \n    // Watch prefs for line numbering and highlighting\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::showLineNumbersPrefChanged, this, [this]() { updateLineNumberArea(); });\n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::highlightCurrentLinePrefChanged, this, [this]() { highlightCurrentLine(); });\n    \n    updateLineNumberAreaWidth(0);\n    highlightCurrentLine();\n    \n    // We now set up to maintain our debugging icons here too\n    connect(this, SIGNAL(textChanged()), this, SLOT(updateDebugPoints()));\n    \n    // Watch for changes to the controller's change count, so we can disable debug points when the document needs recycling\n    // Also watch for the end of model initialization; species colors may have changed, necessitating an update\n    QtSLiMWindow *controller = slimControllerForWindow();\n    \n    if (controller)\n    {\n        connect(controller, &QtSLiMWindow::controllerChangeCountChanged, this, &QtSLiMScriptTextEdit::controllerChangeCountChanged);\n        connect(controller, &QtSLiMWindow::controllerTickFinished, this, &QtSLiMScriptTextEdit::controllerTickFinished);\n    }\n}\n\nQtSLiMScriptTextEdit::~QtSLiMScriptTextEdit()\n{\n}\n\nQStringList QtSLiMScriptTextEdit::linesForRoundedSelection(QTextCursor &p_cursor, bool &movedBack)\n{\n    // find the start and end of the blocks we're operating on\n    int anchor = p_cursor.anchor(), position = p_cursor.position();\n    if (anchor > position)\n        std::swap(anchor, position);\n    movedBack = false;\n    \n    QTextCursor startBlockCursor(p_cursor);\n    startBlockCursor.setPosition(anchor, QTextCursor::MoveAnchor);\n    startBlockCursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);\n    QTextCursor endBlockCursor(p_cursor);\n    endBlockCursor.setPosition(position, QTextCursor::MoveAnchor);\n    if (endBlockCursor.atBlockStart() && (position > anchor))\n    {\n        // the selection includes the newline at the end of the last line; we need to move backward to avoid swallowing the following line\n        endBlockCursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor);\n        movedBack = true;\n    }\n    endBlockCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::MoveAnchor);\n    \n    // select the whole lines we're operating on\n    p_cursor.beginEditBlock();\n    p_cursor.setPosition(startBlockCursor.position(), QTextCursor::MoveAnchor);\n    p_cursor.setPosition(endBlockCursor.position(), QTextCursor::KeepAnchor);\n    \n    // separate the lines, remove a tab at the start of each, and rejoin them\n    QString selectedString = p_cursor.selectedText();\n    static const QRegularExpression lineEndMatch(\"\\\\R\", QRegularExpression::UseUnicodePropertiesOption);\n    \n#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))\n    return selectedString.split(lineEndMatch, QString::KeepEmptyParts);     // deprecated in 5.14\n#else\n    return selectedString.split(lineEndMatch, Qt::KeepEmptyParts);          // added in 5.14\n#endif\n}\n\nvoid QtSLiMScriptTextEdit::copyAsHTML(void)\n{\n    if (isEnabled())\n    {\n        QString html = exportAsHtml();\n        QClipboard *clipboard = QGuiApplication::clipboard();\n        QMimeData *mimeData = new QMimeData;\n        \n        mimeData->setHtml(html);\n        mimeData->setText(html);\n        clipboard->setMimeData(mimeData);\n    }\n}\n\nvoid QtSLiMScriptTextEdit::duplicateSelection(void)\n{\n    if (isEnabled() && !isReadOnly())\n    {\n        QTextCursor &&edit_cursor = textCursor();\n        QString selectedString = edit_cursor.selectedText();\n        int pasteStart = edit_cursor.selectionEnd();\n        \n        edit_cursor.beginEditBlock();\n        \n        edit_cursor.setPosition(pasteStart, QTextCursor::MoveAnchor);\n        edit_cursor.insertText(selectedString);\n        \n        int pasteEnd = edit_cursor.position();\n        \n        edit_cursor.setPosition(pasteStart, QTextCursor::MoveAnchor);\n        edit_cursor.setPosition(pasteEnd, QTextCursor::KeepAnchor);\n        \n        // end the editing block, producing one undo-able operation\n        edit_cursor.endEditBlock();\n        setTextCursor(edit_cursor);\n    }\n    else\n    {\n        qApp->beep();\n    }\n}\n\nvoid QtSLiMScriptTextEdit::shiftSelectionLeft(void)\n{\n    if (isEnabled() && !isReadOnly())\n\t{\n        QTextCursor &&edit_cursor = textCursor();\n        bool movedBack;\n        QStringList lines = linesForRoundedSelection(edit_cursor, movedBack);\n        \n        for (QString &line : lines)\n            if (line.length() && (line[0] == '\\t'))\n                line.remove(0, 1);\n        \n        QString replacementString = lines.join(QChar::ParagraphSeparator);\n\t\t\n        // end the editing block, producing one undo-able operation\n        edit_cursor.insertText(replacementString);\n        edit_cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, replacementString.length());\n        edit_cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, replacementString.length());\n        if (movedBack)\n            edit_cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);\n\t\tedit_cursor.endEditBlock();\n        setTextCursor(edit_cursor);\n\t}\n\telse\n\t{\n\t\tqApp->beep();\n\t}\n}\n\nvoid QtSLiMScriptTextEdit::shiftSelectionRight(void)\n{\n    if (isEnabled() && !isReadOnly())\n\t{\n        QTextCursor &&edit_cursor = textCursor();\n        bool movedBack;\n        QStringList lines = linesForRoundedSelection(edit_cursor, movedBack);\n        \n        for (QString &line : lines)\n            line.insert(0, '\\t');\n        \n        QString replacementString = lines.join(QChar::ParagraphSeparator);\n\t\t\n        // end the editing block, producing one undo-able operation\n        edit_cursor.insertText(replacementString);\n        edit_cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, replacementString.length());\n        edit_cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, replacementString.length());\n        if (movedBack)\n            edit_cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);\n\t\tedit_cursor.endEditBlock();\n        setTextCursor(edit_cursor);\n\t}\n\telse\n\t{\n\t\tqApp->beep();\n\t}\n}\n\nvoid QtSLiMScriptTextEdit::commentUncommentSelection(void)\n{\n    if (isEnabled() && !isReadOnly())\n\t{\n        QTextCursor &&edit_cursor = textCursor();\n        bool movedBack;\n        QStringList lines = linesForRoundedSelection(edit_cursor, movedBack);\n        \n        // decide whether we are commenting or uncommenting; we are only uncommenting if every line spanned by the selection starts with \"//\"\n\t\tbool uncommenting = true;\n        \n        for (QString &line : lines)\n        {\n            if (!line.startsWith(\"//\"))\n            {\n                uncommenting = false;\n                break;\n            }\n        }\n        \n        // now do the comment / uncomment\n        if (uncommenting)\n        {\n            for (QString &line : lines)\n                line.remove(0, 2);\n        }\n        else\n        {\n            for (QString &line : lines)\n                line.insert(0, \"//\");\n        }\n        \n        QString replacementString = lines.join(QChar::ParagraphSeparator);\n\t\t\n        // end the editing block, producing one undo-able operation\n        edit_cursor.insertText(replacementString);\n        edit_cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, replacementString.length());\n        edit_cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, replacementString.length());\n        if (movedBack)\n            edit_cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);\n\t\tedit_cursor.endEditBlock();\n        setTextCursor(edit_cursor);\n\t}\n\telse\n\t{\n\t\tqApp->beep();\n\t}\n}\n\nvoid QtSLiMScriptTextEdit::insertFromMimeData(const QMimeData *source)\n{\n    // if the data pasted is text, we want to convert weird line breaks into newlines\n    // note that the substitution done here strips off any other mime types in source,\n    // but that seems fine; if there's text, we're going to paste text, so whatever.\n    if (source && source->hasText())\n    {\n        QString text = source->text();\n        \n        // Unknown characters can be identified with https://www.babelstone.co.uk/Unicode/whatisit.html\n        //qDebug() << \"pasted:\" << text;\n        \n        // Unicode \"U+2028 : LINE SEPARATOR\" is the one presently causing me problems,\n        // but U+2029 should be replaced as well; we want vanilla non-unicode line ends.\n        text.replace(QChar::LineSeparator, '\\n');\n        text.replace(QChar::ParagraphSeparator, '\\n');\n        \n        //qDebug() << \"substituted:\" << text;\n        \n        QMimeData substitute;\n        substitute.setText(text);\n        \n        QPlainTextEdit::insertFromMimeData(&substitute);\n        return;\n    }\n    \n    // call to super to do the work\n    QPlainTextEdit::insertFromMimeData(source);\n}\n\n// From here down is the machinery for providing line numbers with LineNumberArea\n// This code is adapted from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html\n\nint QtSLiMScriptTextEdit::lineNumberAreaWidth()\n{\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    // We now show debugging icons in the line number area too, since they are kept by line number\n    // The line number area therefore no longer goes down to width 0 when the pref is disabled\n    if (scriptType == SLiMScriptType)\n    {\n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        lineNumberAreaBugWidth = 3 + fontMetrics().width(\"9\") * 2;                 // deprecated in 5.11\n#else\n        lineNumberAreaBugWidth = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * 2;   // added in Qt 5.11\n#endif\n    }\n    else\n    {\n        lineNumberAreaBugWidth = 0;\n    }\n    \n    if (!prefsNotifier.showLineNumbersPref())\n        return lineNumberAreaBugWidth;\n    \n    int digits = 1;\n    int max = qMax(1, document()->blockCount());\n    while (max >= 10) {\n        max /= 10;\n        ++digits;\n    }\n\n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n    int space = 13 + fontMetrics().width(\"9\") * digits;                 // deprecated in 5.11\n#else\n    int space = 13 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;   // added in Qt 5.11\n#endif\n    \n    return lineNumberAreaBugWidth + space;\n}\n\nvoid QtSLiMScriptTextEdit::displayFontPrefChanged()\n{\n    QtSLiMTextEdit::displayFontPrefChanged();\n    updateLineNumberArea();\n}\n\nvoid QtSLiMScriptTextEdit::updateLineNumberAreaWidth(int /* newBlockCount */)\n{\n    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);\n}\n\nvoid QtSLiMScriptTextEdit::updateLineNumberArea(void)\n{\n    QRect contents_rect = contentsRect();\n    lineNumberArea->update(0, contents_rect.y(), lineNumberArea->width(), contents_rect.height());\n    updateLineNumberAreaWidth(0);\n    \n    int dy = verticalScrollBar()->sliderPosition();\n    if (dy > -1)\n        lineNumberArea->scroll(0, dy);\n}\n\nvoid QtSLiMScriptTextEdit::resizeEvent(QResizeEvent *e)\n{\n    QPlainTextEdit::resizeEvent(e);\n\n    QRect cr = contentsRect();\n    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));\n}\n\nvoid QtSLiMScriptTextEdit::toggleDebuggingForLine(int lineNumber)\n{\n    if (scriptType != SLiMScriptType)\n        return;\n    \n    // First figure out whether we have a debugging point at the line in question\n    bool hasExistingCursor = false;\n    \n    //qDebug() << \"toggleDebuggingForLine():\" << lineNumber;\n    //qDebug() << \"block contents:\" << document()->findBlockByNumber(lineNumber).text();\n    \n    for (int cursorIndex = 0; cursorIndex < (int)bugCursors.size(); cursorIndex++)\n    {\n        QTextCursor &existingCursor = bugCursors[cursorIndex];\n        QTextBlock cursorBlock = existingCursor.block();\n        int blockNumber = cursorBlock.blockNumber();\n        \n        if (blockNumber == lineNumber)\n        {\n            hasExistingCursor = true;\n            bugCursors.erase(bugCursors.begin() + cursorIndex);\n            --cursorIndex;\n        }\n    }\n    \n    if (hasExistingCursor)\n    {\n        // This line number had a debugging point; we cleared it above\n    }\n    else\n    {\n        // This line number does not currently have a debugging point; add one\n        QTextDocument *doc = document();\n        QTextBlock block = doc->findBlockByNumber(lineNumber);\n        QString blockText = block.text();\n        \n        // Find the first non-whitespace character in the block; the debug point starts at that character\n        int firstNonWhitespace = 0;\n        \n        for (firstNonWhitespace = 0; firstNonWhitespace < blockText.length(); ++firstNonWhitespace)\n        {\n            QChar qch = blockText[firstNonWhitespace];\n            \n            if ((qch != ' ') && (qch != '\\t'))\n                break;\n        }\n        \n        // If the block contains nothing but whitespace, decline to set a debugging point\n        // This kind of makes sense semantically, and in any case if it's an empty line there's no text to put our cursor on\n        if (firstNonWhitespace == blockText.length())\n            return;\n        \n        // Make a text cursor encompassing the remainder of the block, from the first non-whitespace character\n        QTextCursor tc(block);\n        tc.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, firstNonWhitespace);\n        tc.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor, 1);\n        \n        // Remember the cursor as a debug point\n        bugCursors.emplace_back(tc);\n    }\n    \n    // Since the cursors changed, we need to recache our line numbers\n    updateDebugPoints();\n}\n\nvoid QtSLiMScriptTextEdit::trackLineSelection(int lineNumber, int anchorLineNumber)\n{\n    QTextDocument *doc = document();\n    QTextBlock block = doc->findBlockByNumber(lineNumber);\n    QTextCursor block_tc(block);\n    QTextBlock anchor_block = doc->findBlockByNumber(anchorLineNumber);\n    QTextCursor anchor_tc(anchor_block);\n    \n    block_tc.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor, 1);\n    block_tc.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 1);\n    \n    int block_start = block_tc.selectionStart();\n    int block_end = block_tc.selectionEnd();\n    \n    anchor_tc.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor, 1);\n    anchor_tc.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 1);\n    \n    int anchor_start = anchor_tc.selectionStart();\n    int anchor_end = anchor_tc.selectionEnd();\n    \n    QTextCursor selection_tc(anchor_tc);\n    \n    if (anchor_start <= block_start)\n    {\n        // the anchor is above the final line, so select from the anchor start to the final end\n        selection_tc.setPosition(block_end, QTextCursor::KeepAnchor);\n    }\n    else\n    {\n        // the anchor is below the final line, so select from the anchor end to the final start\n        selection_tc.setPosition(anchor_end, QTextCursor::MoveAnchor);\n        selection_tc.setPosition(block_start, QTextCursor::KeepAnchor);\n    }\n    \n    setTextCursor(selection_tc);\n}\n\nvoid QtSLiMScriptTextEdit::updateDebugPoints(void)\n{\n    // prevent re-entrancy\n    if (coloringDebugPointCursors)\n        return;\n    \n    //qDebug() << \"updateDebugPoints():\" << bugCursors.size() << \"debug cursors exist\";\n    \n    // Generate a new bugLines vector from our text cursors; we vet the cursors at the same time,\n    // and remove any cursors that are zero-length, or that are now duplicates\n    EidosInterpreterDebugPointsSet newBugLines;\n    int bugCursorCount = (int)bugCursors.size();\n    \n    for (int bugCursorIndex = 0; bugCursorIndex < bugCursorCount; ++bugCursorIndex)\n    {\n        QTextCursor &bugCursor = bugCursors[bugCursorIndex];\n        bool zeroLength = !bugCursor.hasSelection();\n        \n        // Fix cursors to encompass their block; they can get out of whack due to typing\n        // This is probably usually unnecessary, but it's a trivial amount of work\n        if (!zeroLength)\n        {\n            bugCursor.setPosition(bugCursor.selectionStart(), QTextCursor::MoveAnchor);\n            bugCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor, 1);\n        }\n        \n        QTextBlock cursorBlock = bugCursor.block();\n        int blockNumber = cursorBlock.blockNumber();\n        \n        if (!zeroLength && (newBugLines.set.find(blockNumber) == newBugLines.set.end()))\n        {\n            // this line is not already marked as debug; mark it now\n            newBugLines.set.emplace(blockNumber);\n            continue;\n        }\n        \n        // discard a redundant or zero-length cursor; this generally results from lines being\n        // merged together in the editor (redundant), or being deleted (zero-length)\n        bugCursors.erase(bugCursors.begin() + bugCursorIndex);\n        bugCursorIndex--;\n        bugCursorCount--;\n    }\n    \n    // Set a temporary color on our cursors for debugging\n#if 0\n    {\n        coloringDebugPointCursors = true;\n        \n        QTextCharFormat clearFormat;\n        QTextCharFormat highlightFormat;\n        \n        clearFormat.setBackground(QBrush(QColor(255, 255, 255)));\n        highlightFormat.setBackground(QBrush(QColor(220, 255, 220)));\n        \n        QTextCursor tc(document());\n        tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);\n        tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);\n        \n        tc.setCharFormat(clearFormat);\n        \n        for (QTextCursor &bugCursor : bugCursors)\n            bugCursor.setCharFormat(highlightFormat);\n        \n        coloringDebugPointCursors = false;\n    }\n#endif\n    \n    // If bugLines changed, we need to recache/redraw\n    if (newBugLines.set != bugLines.set)\n    {\n        std::swap(newBugLines.set, bugLines.set);\n        \n        if (debugPointsEnabled)\n            enabledBugLines.set = bugLines.set;\n        else\n            enabledBugLines.set.clear();\n        \n        lineNumberArea->update();\n    }\n    \n    //qDebug() << \"   updateDebugPoints():\" << bugLines.size() << \"debug points set\";\n}\n\nvoid QtSLiMScriptTextEdit::controllerChangeCountChanged(int changeCount)\n{\n    if (changeCount == 0)\n    {\n        // recycled and unedited; debug points enabled\n        debugPointsEnabled = true;\n        enabledBugLines.set = bugLines.set;\n        lineNumberArea->update();\n    }\n    else\n    {\n        // edited without a recycle; debug points disabled\n        debugPointsEnabled = false;\n        enabledBugLines.set.clear();\n        lineNumberArea->update();\n    }\n}\n\nvoid QtSLiMScriptTextEdit::controllerTickFinished(void)\n{\n    // If we just finished initialize() callbacks, species colors may have changed\n    QtSLiMWindow *controller = slimControllerForWindow();\n    \n    if (controller && controller->community && (controller->community->Tick() == 1))\n        lineNumberArea->update();\n}\n\n// light appearance: standard blue highlight\nstatic QColor lineHighlightColor = QtSLiMColorWithHSV(3.6/6.0, 0.1, 1.0, 1.0);\n\n// dark appearance: dark blue highlight\nstatic QColor lineHighlightColor_DARK = QtSLiMColorWithHSV(4.0/6.0, 0.5, 0.30, 1.0);\n\nvoid QtSLiMScriptTextEdit::highlightCurrentLine()\n{\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    QList<QTextEdit::ExtraSelection> extra_selections;\n    \n    if (!isReadOnly() && prefsNotifier.highlightCurrentLinePref()) {\n        bool inDarkMode = QtSLiMInDarkMode();\n        QTextEdit::ExtraSelection selection;\n        \n        selection.format.setBackground(inDarkMode ? lineHighlightColor_DARK : lineHighlightColor);\n        selection.format.setProperty(QTextFormat::FullWidthSelection, true);\n        selection.cursor = textCursor();\n        \n        if (selection.cursor.hasSelection())\n        {\n            // with a selection, we want to try to highlight the appropriate range\n            // if the selection ends at a newline, we don't want to highlight the\n            // next line; want want to highlight the lines that contain visible text\n            int start = selection.cursor.selectionStart();\n            \n            selection.cursor.setPosition(start, QTextCursor::MoveAnchor);\n            \n            // still have a movement bug when the selection changes, the highlight doesn't update correctly in some cases\n            // check when/how the message is sent\n        }\n        \n        //qDebug() << \"highlightCurrentLine() with position\" << selection.cursor.selectionStart();\n        \n        extra_selections.append(selection);\n    }\n    \n    setExtraSelections(extra_selections);\n}\n\n// light appearance\nstatic QColor bugAreaBackground = QtSLiMColorWithWhite(0.95, 1.0);\nstatic QColor lineAreaBackground = QtSLiMColorWithWhite(0.92, 1.0);\nstatic QColor lineAreaNumber = QtSLiMColorWithWhite(0.75, 1.0);\nstatic QColor lineAreaNumberCurrent = QtSLiMColorWithWhite(0.4, 1.0);\n\n// dark appearance\nstatic QColor bugAreaBackground_DARK = QtSLiMColorWithWhite(0.05, 1.0);\nstatic QColor lineAreaBackground_DARK = QtSLiMColorWithWhite(0.08, 1.0);\nstatic QColor lineAreaNumber_DARK = QtSLiMColorWithWhite(0.25, 1.0);\nstatic QColor lineAreaNumberCurrent_DARK = QtSLiMColorWithWhite(0.6, 1.0);\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaToolTipEvent(QHelpEvent *p_helpEvent)\n{\n    // provide different tooltips for the debug point gutter versus the line number area\n    QPointF localPos = p_helpEvent->pos();\n    \n    if ((lineNumberAreaBugWidth == 0) || ((localPos.x() < 0) || (localPos.x() >= lineNumberAreaBugWidth + 2)))     // +2 for a little slop\n        QToolTip::showText(p_helpEvent->globalPos(), \"<html><head/><body><p>script line numbers</p></body></html>\");\n    else\n        QToolTip::showText(p_helpEvent->globalPos(), \"<html><head/><body><p>debug point gutter (click to set/clear a debug point)</p></body></html>\");\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaPaintEvent(QPaintEvent *p_paintEvent)\n{\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    bool showBlockColors = true;\n    bool showLineNumbers = prefsNotifier.showLineNumbersPref();\n    int bugCount = (int)bugLines.set.size();\n    \n    // Fill the background with the appropriate colors\n    QRect overallRect = contentsRect();\n    \n    if (overallRect.width() <= 0)\n        return;\n    \n    overallRect.setWidth(lineNumberArea->width());\n    \n    QRect bugRect = overallRect;\n    QRect lineNumberRect = overallRect;\n    bugRect.setWidth(lineNumberAreaBugWidth);\n    lineNumberRect.adjust(lineNumberAreaBugWidth, 0, 0, 0);\n    \n    bool inDarkMode = QtSLiMInDarkMode();\n    QPainter painter(lineNumberArea);\n    \n    // We now show slightly different background colors for the debug point gutter vs. the line number area\n    //painter.fillRect(overallRect, inDarkMode ? lineAreaBackground_DARK : lineAreaBackground);\n    painter.fillRect(bugRect, inDarkMode ? bugAreaBackground_DARK : bugAreaBackground);\n    painter.fillRect(lineNumberRect, inDarkMode ? lineAreaBackground_DARK : lineAreaBackground);\n    \n    if ((bugCount == 0) && !showLineNumbers)\n        return;\n    \n    static QIcon *bugIcon_LIGHT = nullptr;\n    static QIcon *bugIcon_DARK = nullptr;\n    \n    if (!inDarkMode && !bugIcon_LIGHT && (bugCount > 0))\n        bugIcon_LIGHT = new QIcon(\":/icons/bug.png\");\n    if (inDarkMode && !bugIcon_DARK && (bugCount > 0))\n        bugIcon_DARK = new QIcon(\":/icons/bug_DARK.png\");\n    \n    QIcon *bugIcon = (inDarkMode ? bugIcon_DARK : bugIcon_LIGHT);\n    \n    // Prepare to show block colors in multispecies mode; we translate into line numbers and colors on demand\n    // We postpone this display until after initialize() so we don't show the default colors, which is weird\n    std::vector<int> blockColorStarts, blockColorEnds;\n    std::vector<QColor> blockColors;\n    QtSLiMWindow *controller = slimControllerForWindow();\n    int blockColorCount = 0;\n    \n    if (showBlockColors && controller && controller->community && (controller->community->Tick() >= 1) && blockCursors.size())\n    {\n        for (int index = 0; index < (int)blockCursors.size(); ++index)\n        {\n            QTextCursor &tc = blockCursors[index];\n            \n            if (tc.hasSelection())\n            {\n                QTextCursor start_tc(tc);\n                QTextCursor end_tc(tc);\n                start_tc.setPosition(start_tc.selectionStart(), QTextCursor::MoveAnchor);\n                end_tc.setPosition(end_tc.selectionEnd(), QTextCursor::MoveAnchor);\n                \n                blockColorStarts.emplace_back(start_tc.block().blockNumber());\n                blockColorEnds.emplace_back(end_tc.block().blockNumber());\n                blockColors.emplace_back(controller->qcolorForSpecies(blockSpecies[index]));\n            }\n        }\n        \n        blockColorCount = blockColors.size();\n    }\n    else\n    {\n        showBlockColors = false;\n    }\n    \n    // Draw the numbers and bug symbols (displaying the current line number in col_1)\n    QTextBlock block = firstVisibleBlock();\n    int blockNumber = block.blockNumber();\n    int cursorBlockNumber = textCursor().blockNumber();\n    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());\n    int bottom = top + qRound(blockBoundingRect(block).height());\n    \n    painter.setPen(inDarkMode ? lineAreaNumber_DARK : lineAreaNumber);\n    painter.save();\n    painter.setRenderHint(QPainter::SmoothPixmapTransform);\n    \n    while (block.isValid() && (top <= p_paintEvent->rect().bottom()))\n    {\n        if (block.isVisible() && (bottom >= p_paintEvent->rect().top()))\n        {\n            if (showBlockColors)\n            {\n                for (int index = 0; index < blockColorCount; ++index)\n                {\n                    int startBlockNumber = blockColorStarts[index];\n                    int endBlockNumber = blockColorEnds[index];\n                    \n                    if ((blockNumber >= startBlockNumber) && (blockNumber <= endBlockNumber))\n                    {\n                        QRect speciesHighlightBounds(lineNumberRect.left() + lineNumberRect.width() - 4, top, 2, bottom - top);\n                        \n                        if (blockNumber == startBlockNumber)\n                            speciesHighlightBounds.adjust(0, 1, 0, 0);\n                        if (blockNumber == endBlockNumber)\n                            speciesHighlightBounds.adjust(0, 0, 0, -1);\n                        \n                        speciesHighlightBounds = speciesHighlightBounds.intersected(overallRect);\n                        \n                        painter.fillRect(speciesHighlightBounds, blockColors[index]);\n                        break;\n                    }\n                }\n            }\n            if (showLineNumbers)\n            {\n                if (cursorBlockNumber == blockNumber) painter.setPen(inDarkMode ? lineAreaNumberCurrent_DARK : lineAreaNumberCurrent);\n                \n                QString number = QString::number(blockNumber + 1);\n                painter.drawText(-7, top, lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number);\n                \n                if (cursorBlockNumber == blockNumber) painter.setPen(inDarkMode ? lineAreaNumber_DARK : lineAreaNumber);\n            }\n            if (bugCount)\n            {\n                if (bugLines.set.find(blockNumber) != bugLines.set.end())\n                {\n                    QRect bugIconBounds(bugRect.left(), top, bugRect.width(), bottom - top);\n                    \n                    //painter.fillRect(bugIconBounds, Qt::green);\n                    \n                    // enforce square bounds for drawing\n                    if (bugIconBounds.width() != bugIconBounds.height())\n                    {\n                        int iconWidth = bugIconBounds.width();\n                        int iconHeight = bugIconBounds.height();\n                        int adjust = std::abs(iconWidth - iconHeight);\n                        int halfAdjust = adjust / 2;\n                        int remainder = adjust - halfAdjust;\n                        \n                        if (iconWidth > iconHeight)\n                            bugIconBounds.adjust(halfAdjust, 0, -remainder, 0);\n                        else\n                            bugIconBounds.adjust(0, halfAdjust, 0, -remainder);\n                    }\n                    \n                    // shrink the bug at large sizes\n                    if (bugIconBounds.width() > 24)\n                        bugIconBounds.adjust(3, 3, -3, -3);\n                    else if (bugIconBounds.width() > 20)\n                        bugIconBounds.adjust(2, 2, -2, -2);\n                    else if (bugIconBounds.width() > 16)\n                        bugIconBounds.adjust(1, 1, -1, -1);\n                    \n                    // shift left slightly if we can\n                    if (bugIconBounds.left() > bugRect.left())\n                        bugIconBounds.adjust(-1, 0, -1, 0);\n                    \n                    //qDebug() << \"bugIconBounds ==\" << bugIconBounds;\n                    //painter.fillRect(bugIconBounds, Qt::red);\n                    \n                    if (debugPointsEnabled)\n                        bugIcon->paint(&painter, bugIconBounds, Qt::AlignCenter, QIcon::Normal, QIcon::Off);\n                    else\n                        bugIcon->paint(&painter, bugIconBounds, Qt::AlignCenter, QIcon::Disabled, QIcon::Off);\n                }\n            }\n        }\n\n        block = block.next();\n        top = bottom;\n        bottom = top + qRound(blockBoundingRect(block).height());\n        ++blockNumber;\n    }\n    \n    painter.restore();\n}\n\nint QtSLiMScriptTextEdit::_blockNumberForLocalY(QPointF localPos)\n{\n    qreal localY = localPos.y();\n    \n    //qDebug() << \"localY ==\" << localY;\n    \n    // Find the position of the click in the document.  We loop through the blocks manually.\n    QTextBlock block = firstVisibleBlock();\n    int blockNumber = block.blockNumber();\n    int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());\n    int bottom = top + qRound(blockBoundingRect(block).height());\n    \n    while (block.isValid())\n    {\n        if (block.isVisible())\n        {\n            if ((localY >= top) && (localY <= bottom))\n            {\n                return blockNumber;\n            }\n            else if (localY < top)\n            {\n                return -1;\n            }\n        }\n        \n        block = block.next();\n        top = bottom;\n        bottom = top + qRound(blockBoundingRect(block).height());\n        ++blockNumber;\n    }\n    \n    return -1;\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaMousePressEvent(QMouseEvent *p_mouseEvent)\n{\n    if (lineNumberAreaBugWidth == 0)\n        return;\n    \n    // For some reason, Qt calls mousePressEvent() first for control-clicks and right-clicks,\n    // and *then* calls contextMenuEvent(), so we need to detect the context menu situation\n    // and return without doing anything.  Note that Qt::RightButton is set for control-clicks!\n    if (p_mouseEvent->button() == Qt::RightButton)\n        return;\n    \n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    QPointF localPos = p_mouseEvent->localPos();\n#else\n    QPointF localPos = p_mouseEvent->position();\n#endif\n    \n    if (localPos.x() < 0)\n        return;\n    \n    int blockNumber = _blockNumberForLocalY(localPos);\n    \n    if (blockNumber != -1)\n    {\n        if (localPos.x() >= lineNumberAreaBugWidth)\n        {\n            // This is a click in the line number area, so select the line\n            trackingLineSelection = true;\n            trackingLineAnchor = blockNumber;\n            \n            trackLineSelection(blockNumber, trackingLineAnchor);\n        }\n        else\n        {\n            // This is a click in the debug point column, so toggle debugging\n            toggleDebuggingForLine(blockNumber);\n        }\n    }\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaMouseMoveEvent(QMouseEvent *p_mouseEvent)\n{\n    if (!trackingLineSelection)\n        return;\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    QPointF localPos = p_mouseEvent->localPos();\n#else\n    QPointF localPos = p_mouseEvent->position();\n#endif\n    \n    int blockNumber = _blockNumberForLocalY(localPos);\n    \n    if (blockNumber != -1)\n    {\n        trackLineSelection(blockNumber, trackingLineAnchor);\n    }\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaMouseReleaseEvent(QMouseEvent *p_mouseEvent)\n{\n    if (!trackingLineSelection)\n        return;\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    QPointF localPos = p_mouseEvent->localPos();\n#else\n    QPointF localPos = p_mouseEvent->position();\n#endif\n    \n    int blockNumber = _blockNumberForLocalY(localPos);\n    \n    if (blockNumber != -1)\n    {\n        trackLineSelection(blockNumber, trackingLineAnchor);\n    }\n    \n    trackingLineSelection = false;\n    trackingLineAnchor = -1;\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaContextMenuEvent(QContextMenuEvent *p_event)\n{\n    if (lineNumberAreaBugWidth == 0)\n        return;\n    \n    p_event->accept();\n    \n    QMenu contextMenu(\"line_area_menu\", this);\n    \n    QAction *clearDebugPointsAction = contextMenu.addAction(\"Clear Debug Points\");\n    \n    // Run the context menu synchronously\n    QAction *action = contextMenu.exec(p_event->globalPos());\n    \n    // Act upon the chosen action; we just do it right here instead of dealing with slots\n    if (action)\n    {\n        if (action == clearDebugPointsAction)\n            clearDebugPoints();\n    }\n}\n\nvoid QtSLiMScriptTextEdit::lineNumberAreaWheelEvent(QWheelEvent *p_wheelEvent)\n{\n    // We want wheel events in the debug/line number area to scroll the script textview, so it forwards them to us here\n    // I'm not sure of the legality of this, since the event is tailored for a different widget, but it seems to work...\n    wheelEvent(p_wheelEvent);\n}\n\nvoid QtSLiMScriptTextEdit::clearDebugPoints(void)\n{\n    bugCursors.clear();\n    updateDebugPoints();\n}\n\nvoid QtSLiMScriptTextEdit::clearScriptBlockColoring(void)\n{\n    blockCursors.clear();\n    blockSpecies.clear();\n}\n\nvoid QtSLiMScriptTextEdit::addScriptBlockColoring(int startPos, int endPos, Species *species)\n{\n    QTextCursor tc(document());\n    tc.setPosition(startPos, QTextCursor::MoveAnchor);\n    tc.setPosition(endPos, QTextCursor::KeepAnchor);\n    \n    blockCursors.emplace_back(tc);\n    blockSpecies.emplace_back(species);\n}\n\n// this method courtesy of SO user Larswad, https://stackoverflow.com/a/15808889/2752221\nQString QtSLiMScriptTextEdit::exportAsHtml(void)\n{\n    // Create a new document from the entire document\n    QTextCursor cursor(document());\n    cursor.select(QTextCursor::Document);\n    QTextDocument *tempDocument = new QTextDocument;\n    QTextCursor tempCursor(tempDocument);\n    \n    tempCursor.insertFragment(cursor.selection());\n    tempCursor.select(QTextCursor::Document);\n    \n    // Set the default foreground for the inserted characters\n    QTextCharFormat textfmt = tempCursor.charFormat();\n    textfmt.setForeground(Qt::black);\n    tempCursor.setCharFormat(textfmt);\n    \n    // Apply the additional formats set by the syntax highlighter\n    QTextBlock start = document()->findBlock(cursor.selectionStart());\n    QTextBlock end = document()->findBlock(cursor.selectionEnd());\n    end = end.next();\n    const int selectionStart = cursor.selectionStart();\n    const int endOfDocument = tempDocument->characterCount() - 1;\n    for (QTextBlock current = start; current.isValid() and current not_eq end; current = current.next()) {\n        const QTextLayout* layout(current.layout());\n        \n        foreach (const QTextLayout::FormatRange &range, layout->formats()) {\n            const int formatStart = current.position() + range.start - selectionStart;\n            const int formatEnd = formatStart + range.length;\n            if(formatEnd <= 0 or formatStart >= endOfDocument)\n                continue;\n            tempCursor.setPosition(qMax(formatStart, 0));\n            tempCursor.setPosition(qMin(formatEnd, endOfDocument), QTextCursor::KeepAnchor);\n            tempCursor.setCharFormat(range.format);\n        }\n    }\n    \n    // Reset the user states since they are not interesting\n    for (QTextBlock block = tempDocument->begin(); block.isValid(); block = block.next())\n        block.setUserState(-1);\n    \n    // Make sure the text appears pre-formatted, and set the background we want\n    tempCursor.select(QTextCursor::Document);\n    QTextBlockFormat blockFormat = tempCursor.blockFormat();\n    blockFormat.setNonBreakableLines(true);\n    //blockFormat.setBackground(Qt::black);\n    tempCursor.setBlockFormat(blockFormat);\n    \n    // Select the same range with tempCursor as is selected in the original document\n    QTextCursor selectedRange = textCursor();\n    tempCursor.setPosition(selectedRange.anchor(), QTextCursor::MoveAnchor);\n    tempCursor.setPosition(selectedRange.position(), QTextCursor::KeepAnchor);\n    \n    // Retrieve the syntax highlighted and formatted html\n    QString html = tempCursor.selection().toHtml();\n    delete tempDocument;\n    \n    // There is a bug where the first line uses <p> instead of <pre>, because\n    // it is a fragment, I guess.  We can fix that with a regex.\n    QRegularExpression pToPreRegex(\"<p style=(.*)</p>\");\n    pToPreRegex.setPatternOptions(QRegularExpression::CaseInsensitiveOption);\n    html.replace(pToPreRegex, \"<pre style=\\\\1</pre>\");\n    \n    // Change new paragraphs to new lines, so we get one paragraph of text\n    // This doesn't work, you always get a new paragraph for each line; <BR> doesn't work either.\n    //QRegularExpression preRegex(\"</pre>.?.?<pre style=\\\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\\\">\");\n    //preRegex.setPatternOptions(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption);\n    //html.replace(preRegex, \"\\n\");\n    \n    return html;\n}\n\nvoid QtSLiMScriptTextEdit::paintEvent(QPaintEvent *event)\n{\n    // If the user wants a \"page guide\", show a slightly dimmed margin beyond a threshold column\n    // Note that Qt has already cleared to the white background of the QTextEdit\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    bool showPageGuide = prefs.showPageGuidePref();\n    \n    if (showPageGuide)\n    {\n        QFont displayFont = prefs.displayFontPref();\n        QFontMetricsF fm(displayFont);\n        double marginStart;\n        QString marginString(prefs.pageGuideColumnPref(), ' ');\n        \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n        marginStart = fm.width(marginString);                // deprecated in 5.11\n#else\n        marginStart = fm.horizontalAdvance(marginString);    // added in Qt 5.11\n#endif\n        \n        // adjust by the document margin, which is built into QTextDocument; this took a while to find!\n        // this is an inset of the QTextEdit's contents, on all four sides; it defaults to 4, which we do not change\n        QTextDocument *doc = document();\n        double docMargin = doc->documentMargin();\n        \n        marginStart += docMargin;\n        marginStart = round(marginStart);\n        \n        QRect bounds = rect();\n        \n        if (bounds.width() >= marginStart)\n        {\n            // Because QTextEdit's display lives inside a scrollable area, we use viewport()\n            QPainter painter(this->viewport());\n            \n            QRect margin = bounds.adjusted(marginStart, 0, 0, 0);\n            QRect marginEdge = margin;\n            \n            // draw a one-pixel darker line at the border\n            marginEdge.setWidth(1);\n            margin.adjust(1, 0, 0, 0);\n            \n            painter.fillRect(marginEdge, QtSLiMColorWithWhite(0.918, 1.0));\n            painter.fillRect(margin, QtSLiMColorWithWhite(0.980, 1.0));\n        }\n    }\n    \n    // call super to have it paint; this draws all the text and everything\n    QtSLiMTextEdit::paintEvent(event);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMScriptTextEdit.h",
    "content": "//\n//  QtSLiMScriptTextEdit.h\n//  SLiM\n//\n//  Created by Ben Haller on 11/24/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMSCRIPTTEXTEDIT_H\n#define QTSLIMSCRIPTTEXTEDIT_H\n\n#include <QPlainTextEdit>\n#include <QPalette>\n#include <QtGlobal>     // for QT_VERSION\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_type_interpreter.h\"\n\nclass QtSLiMOutputHighlighter;\nclass QtSLiMScriptHighlighter;\nclass QStatusBar;\nclass EidosCallSignature;\nclass QtSLiMWindow;\nclass QtSLiMEidosConsole;\nclass QCompleter;\nclass QHelpEvent;\nclass QPaintEvent;\nclass QMouseEvent;\n\nclass Species;\n\n\n// We define NSRange and NSNotFound because we want to be able to represent \"no range\",\n// which QTextCursor cannot do; there is no equivalent of NSNotFound for it.  We should\n// never be linked with Objective-C code, so there should be no conflict.  Note these\n// definitions are not the same as Apple's; I kept the names just for convenience.\n\ntypedef struct _NSRange {\n    int location;\n    int length;\n} NSRange;\n\nstatic const int NSNotFound = INT_MAX;\n\n\n// A QPlainTextEdit subclass that provides a signal for an option-click on a script\n// symbol.  This also provides some basic smarts for syntax coloring and so forth.\n// QtSLiMScriptTextEdit and QtSLiMConsoleTextEdit are both subclasses of this class.\nclass QtSLiMTextEdit : public QPlainTextEdit\n{\n    Q_OBJECT\n    \npublic:\n    enum ScriptType {\n        NoScriptType = 0,\n        EidosScriptType,\n        SLiMScriptType\n    };\n    enum ScriptHighlightingType {\n        NoHighlighting = 0,\n        ScriptHighlighting,\n        OutputHighlighting\n    };\n    \n    QtSLiMTextEdit(const QString &text, QWidget *p_parent = nullptr);\n    QtSLiMTextEdit(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMTextEdit() override;\n    \n    // configuration\n    void setScriptType(ScriptType type);\n    void setSyntaxHighlightType(ScriptHighlightingType type);\n    void setOptionClickEnabled(bool enabled);\n    void setCodeCompletionEnabled(bool enabled);\n    \n    // highlight errors\n    void highlightError(int startPosition, int endPosition);   \n    void selectErrorRange(EidosErrorContext &errorContext);\n    QPalette qtslimStandardPalette(void);\n    QPalette qtslimErrorPalette(void);\n    \n    // undo/redo availability; named to avoid future collision with QPlainTextEdit for this obvious feature\n    bool qtslimIsUndoAvailable(void) { return undoAvailable_; }\n    bool qtslimIsRedoAvailable(void) { return redoAvailable_; }\n    bool qtslimIsCopyAvailable(void) { return copyAvailable_; }\n    \npublic slots:\n    void checkScript(void);\n    void prettyprint(void);\n    void reformat(void);\n    void prettyprintClicked(void);      // decides whether to reformat or prettyprint based on the option key state\n    \nsignals:\n    \nprotected:\n    ScriptType scriptType = ScriptType::NoScriptType;\n    ScriptHighlightingType syntaxHighlightingType = QtSLiMTextEdit::NoHighlighting;\n    QtSLiMOutputHighlighter *outputHighlighter = nullptr;\n    QtSLiMScriptHighlighter *scriptHighlighter = nullptr;\n    \n    void selfInit(void);\n    QStatusBar *statusBarForWindow(void);\n    QtSLiMWindow *slimControllerForWindow(void);\n    QtSLiMEidosConsole *slimEidosConsoleForWindow(void);\n    \n    // used to track that we are intercepting a mouse event\n    bool optionClickEnabled = false;\n    bool optionClickIntercepted = false;\n    virtual void mousePressEvent(QMouseEvent *p_event) override;\n    virtual void mouseMoveEvent(QMouseEvent *p_event) override;\n    virtual void mouseReleaseEvent(QMouseEvent *p_event) override;\n    void scriptHelpOptionClick(QString searchString);\n    \n    // used to maintain the correct cursor (pointing hand when option is pressed)\n    void fixMouseCursor(void);\n#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)\n    virtual void enterEvent(QEnterEvent *p_event) override;\n#else\n    virtual void enterEvent(QEvent *p_event) override;\n#endif\n    \n    // keeping track of undo/redo availability\n    bool undoAvailable_ = false;\n    bool redoAvailable_ = false;\n    bool copyAvailable_ = false;\n    \n    // used for code completion in script textviews\n    bool codeCompletionEnabled = false;\n    QCompleter *completer = nullptr;\n    \n    void autoindentAfterNewline(void);\n    virtual void keyPressEvent(QKeyEvent *e) override;\n    QStringList completionsForPartialWordRange(NSRange charRange, int *indexOfSelectedItem);\n    NSRange rangeForUserCompletion(void);\n    \n    QStringList globalCompletionsWithTypesFunctionsKeywordsArguments(EidosTypeTable *typeTable, EidosFunctionMap *functionMap, QStringList keywords, QStringList argumentNames);\n    QStringList completionsForKeyPathEndingInTokenIndexOfTokenStream(int lastDotTokenIndex, const std::vector<EidosToken> &tokens, EidosTypeTable *typeTable, EidosFunctionMap *functionMap, EidosCallTypeTable *callTypeTable, QStringList keywords);\n    QStringList completionsFromArrayMatchingBase(QStringList candidates, QString base);\n    QStringList completionsForTokenStream(const std::vector<EidosToken> &tokens, int lastTokenIndex, bool canExtend, EidosTypeTable *typeTable, EidosFunctionMap *functionMap, EidosCallTypeTable *callTypeTable, QStringList keywords, QStringList argumentNames);\n    QStringList uniquedArgumentNameCompletions(std::vector<std::string> *argumentCompletions);\n    void _completionHandlerWithRangeForCompletion(NSRange *baseRange, QStringList *completions);\n    int64_t scoreForCandidateAsCompletionOfString(QString candidate, QString base);\n    void slimSpecificCompletion(QString completionScriptString, NSRange selection, EidosTypeTable **typeTable, EidosFunctionMap **functionMap, EidosCallTypeTable **callTypeTable, QStringList *keywords, std::vector<std::string> *argNameCompletions);\n\n    EidosFunctionMap *functionMapForScriptString(QString scriptString, bool includingOptionalFunctions);\n    EidosFunctionMap *functionMapForTokenizedScript(EidosScript &script, bool includingOptionalFunctions);\n    EidosSymbolTable *symbolsFromBaseSymbols(EidosSymbolTable *baseSymbols);\n    \n    // status bar signatures\n    EidosFunctionSignature_CSP signatureForFunctionName(QString callName, EidosFunctionMap *functionMapPtr);\n    const std::vector<EidosMethodSignature_CSP> *slimguiAllMethodSignatures(void);\n    EidosMethodSignature_CSP signatureForMethodName(QString callName);\n    EidosCallSignature_CSP signatureForScriptSelection(QString &callName);\n    \n    // virtual function for accessing the script portion of the contents; for normal\n    // script textedits this is the whole content and the text cursor, but for the\n    // console view it is just the snippet of script following the prompt\n    virtual void scriptStringAndSelection(QString &scriptString, int &pos, int &len, int &offset);\n    \nprotected slots:\n    virtual void displayFontPrefChanged();\n    void scriptSyntaxHighlightPrefChanged();\n    void outputSyntaxHighlightPrefChanged();\n    bool checkScriptSuppressSuccessResponse(bool suppressSuccessResponse);\n    void modifiersChanged(Qt::KeyboardModifiers newModifiers);\n    \n    void updateStatusFieldFromSelection(void);\n    \n    void insertCompletion(const QString &completion);\n    void _prettyprint_reformat(bool reformat);\n};\n\n// A QtSLiMTextEdit subclass that provides various smarts for editing Eidos script\nclass QtSLiMScriptTextEdit : public QtSLiMTextEdit\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMScriptTextEdit(const QString &text, QWidget *p_parent = nullptr);\n    QtSLiMScriptTextEdit(QWidget *p_parent = nullptr);\n    virtual ~QtSLiMScriptTextEdit() override;\n    \n    EidosInterpreterDebugPointsSet &debuggingPoints(void) { return enabledBugLines; }\n    \n    void clearScriptBlockColoring(void);\n    void addScriptBlockColoring(int startPos, int endPos, Species *species);\n    \n    QString exportAsHtml(void);\n    \n    virtual void insertFromMimeData(const QMimeData *source) override;\n    \npublic slots:\n    void copyAsHTML(void);\n    void duplicateSelection(void);\n    void shiftSelectionLeft(void);\n    void shiftSelectionRight(void);\n    void commentUncommentSelection(void);\n    void clearDebugPoints(void);\n    \nprotected:\n    QStringList linesForRoundedSelection(QTextCursor &cursor, bool &movedBack);\n    int _blockNumberForLocalY(QPointF localPos);\n    \n    // From here down is the machinery for providing line numbers\n    // This code is adapted from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html\npublic:\n    void lineNumberAreaToolTipEvent(QHelpEvent *p_helpEvent);\n    void lineNumberAreaPaintEvent(QPaintEvent *p_paintEvent);\n    void lineNumberAreaMousePressEvent(QMouseEvent *p_mouseEvent);\n    void lineNumberAreaMouseMoveEvent(QMouseEvent *p_mouseEvent);\n    void lineNumberAreaMouseReleaseEvent(QMouseEvent *p_mouseEvent);\n    void lineNumberAreaContextMenuEvent(QContextMenuEvent *p_event);\n    void lineNumberAreaWheelEvent(QWheelEvent *p_wheelEvent);\n    int lineNumberAreaWidth(void);\n\nprotected:\n    void sharedInit(void);\n    void initializeLineNumbers(void);\n    virtual void resizeEvent(QResizeEvent *p_event) override;\n    virtual void paintEvent(QPaintEvent *event) override;\n\nprotected slots:\n    virtual void displayFontPrefChanged() override;\n    \nprivate slots:\n    void updateLineNumberAreaWidth(int newBlockCount);\n    void highlightCurrentLine(void);\n    void updateLineNumberArea(QRectF /*rect_f*/) { updateLineNumberArea(); }\n    void updateLineNumberArea(int /*slider_pos*/) { updateLineNumberArea(); }\n    void updateLineNumberArea(void);\n    void updateDebugPoints(void);\n    void controllerChangeCountChanged(int changeCount);\n    void controllerTickFinished(void);\n\nprivate:\n    QWidget *lineNumberArea;\n    \n    // Debug points\n    int lineNumberAreaBugWidth = 0;\n    std::vector<QTextCursor> bugCursors;                // we use QTextCursor to maintain the positions of debugging points across edits\n    EidosInterpreterDebugPointsSet bugLines;            // line numbers for debug points; std::unordered_set<int> or equivalent\n    EidosInterpreterDebugPointsSet enabledBugLines;     // for public consumption; empty when debug points are disabled\n    bool debugPointsEnabled = true;                     // disabled when edited without a recycle (recycle button is green)\n    bool coloringDebugPointCursors = false;             // a flag to prevent re-entrancy\n    \n    void toggleDebuggingForLine(int lineNumber);\n    \n    // Line selection by clicking in the line area\n    void trackLineSelection(int lineNumber, int anchorLineNumber);\n    \n    bool trackingLineSelection = false;\n    int trackingLineAnchor = 0;\n    \n    // Species coloring\n    std::vector<QTextCursor> blockCursors;              // we use QTextCursor to maintain the positions of script blocks across edits\n    std::vector<Species *> blockSpecies;                // the corresponding Species object for each block\n};\n\n\n#endif // QTSLIMSCRIPTTEXTEDIT_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMSyntaxHighlighting.cpp",
    "content": "//\n//  QtSLiMSyntaxHighlighting.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/4/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMSyntaxHighlighting.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMAppDelegate.h\"\n\n#include <QTextDocument>\n#include <QString>\n#include <QTextCharFormat>\n#include <QDebug>\n\n#include <string>\n#include <vector>\n\n#include \"eidos_script.h\"\n#include \"slim_globals.h\"\n\n\n//\n//  QtSLiMOutputHighlighter\n//\n\nQtSLiMOutputHighlighter::QtSLiMOutputHighlighter(QTextDocument *p_parent) :\n    QSyntaxHighlighter(p_parent),\n    poundRegex(QString(\"^\\\\s*#[^\\\\n]*\")),\n    commentRegex(QString(\"//[^\\\\n]*\")),\n    globalRegex(QString(\"\\\\b[pgm][0-9]+\\\\b\"))\n{\n    // listen for changes to the application color palette (i.e., dark mode vs. light mode)\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, &QtSLiMOutputHighlighter::paletteChanged);\n    paletteChanged();\n}\n\nvoid QtSLiMOutputHighlighter::paletteChanged(void)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (!cachedTextFormats || (cachedForDarkMode != inDarkMode))\n    {\n        poundDirectiveFormat.setForeground(inDarkMode ? QColor(220, 98, 90) : QColor(196, 26, 22));\n        commentFormat.setForeground(inDarkMode ? QColor(90, 210, 90) : QColor(0, 116, 0));\n        subpopFormat.setForeground(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207));\n        genomicElementFormat.setForeground(inDarkMode ? QColor(70, 205, 216) : QColor(63, 110, 116));\n        mutationTypeFormat.setForeground(inDarkMode ? QColor(220, 83, 185) : QColor(170, 13, 145));\n        \n        cachedTextFormats = true;\n        \n        if (cachedForDarkMode != inDarkMode)\n        {\n            cachedForDarkMode = inDarkMode;\n            rehighlight();\n        }\n    }\n}\n\nvoid QtSLiMOutputHighlighter::highlightBlock(const QString &text)\n{\n    if (text.length())\n    {\n        // highlight globals first; if they occur inside pound or comment regions, their format will be overwritten\n        {\n            QRegularExpressionMatchIterator matchIterator = globalRegex.globalMatch(text);\n            while (matchIterator.hasNext()) {\n                QRegularExpressionMatch match = matchIterator.next();\n                QString matchString = match.captured();\n                \n                if (matchString.length() > 0)\n                {\n                    if (matchString[0] == 'p')\n                        setFormat(match.capturedStart(), match.capturedLength(), subpopFormat);\n                    else if (matchString[0] == 'g')\n                        setFormat(match.capturedStart(), match.capturedLength(), genomicElementFormat);\n                    else if (matchString[0] == 'm')\n                        setFormat(match.capturedStart(), match.capturedLength(), mutationTypeFormat);\n\t\t\t\t\t// we don't presently color sX or iX in the output\n                }\n            }\n        }\n        \n        // highlight pound lines next, since that overrides the previous coloring rules\n        {\n            QRegularExpressionMatchIterator matchIterator = poundRegex.globalMatch(text);\n            while (matchIterator.hasNext()) {\n                QRegularExpressionMatch match = matchIterator.next();\n                setFormat(match.capturedStart(), match.capturedLength(), poundDirectiveFormat);\n            }\n        }\n        \n        // highlight comments last, since there is no syntax coloring inside them\n        {\n            QRegularExpressionMatchIterator matchIterator = commentRegex.globalMatch(text);\n            while (matchIterator.hasNext()) {\n                QRegularExpressionMatch match = matchIterator.next();\n                setFormat(match.capturedStart(), match.capturedLength(), commentFormat);\n            }\n        }\n    }\n}\n\n\n//\n//  QtSLiMScriptHighlighter\n//\n\nQtSLiMScriptHighlighter::QtSLiMScriptHighlighter(QTextDocument *p_parent) : QSyntaxHighlighter(p_parent)\n{\n    // listen for changes to our document's contents\n    // FIXME technically we need to recache and stuff if setDocument() is called, but we never do that in QtSLiM\n    connect(p_parent, &QTextDocument::contentsChanged, this, &QtSLiMScriptHighlighter::documentContentsChanged);\n    \n    // listen for changes to the application color palette (i.e., dark mode vs. light mode)\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, &QtSLiMScriptHighlighter::paletteChanged);\n    paletteChanged();\n}\n\nvoid QtSLiMScriptHighlighter::paletteChanged(void)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    if (!cachedTextFormats || (cachedForDarkMode != inDarkMode))\n    {\n        numberLiteralFormat.setForeground(inDarkMode ? QColor(115, 145, 255) : QColor(28, 0, 207));\n        stringLiteralFormat.setForeground(inDarkMode ? QColor(220, 98, 90) : QColor(196, 26, 22));\n        commentFormat.setForeground(inDarkMode ? QColor(90, 210, 90) : QColor(0, 116, 0));\n        identifierFormat.setForeground(inDarkMode ? QColor(70, 205, 216) : QColor(63, 110, 116));\n        keywordFormat.setForeground(inDarkMode ? QColor(220, 83, 185) : QColor(170, 13, 145));\n        contextKeywordFormat.setForeground(QColor(80, 13, 145));    // not used at present\n        \n        cachedTextFormats = true;\n        \n        if (cachedForDarkMode != inDarkMode)\n        {\n            cachedForDarkMode = inDarkMode;\n            rehighlight();\n        }\n    }\n}\n\nQtSLiMScriptHighlighter::~QtSLiMScriptHighlighter()\n{\n    // throw out our cached information about the document\n    documentContentsChanged();\n}\n\nvoid QtSLiMScriptHighlighter::documentContentsChanged(void)\n{\n    // Note that this is called by highlightBlock() below, as well as by the QTextDocument::contentsChanged signal\n    if (script)\n    {\n        delete script;\n        script = nullptr;\n        \n        lastProcessedTokenIndex = -1;\n    }\n}\n\nvoid QtSLiMScriptHighlighter::highlightBlock(__attribute__((__unused__)) const QString &text)\n{\n    //qDebug() << \"highlightBlock : \" << text;\n    \n    const QTextBlock &block = currentBlock();\n    int pos = block.position(), len = block.length();\n    \n    // Unfortunately, when setPlainText() gets called on the document's textedit, it does not send us\n    // a contentsChanged signal until *after* it has asked us to do all of the syntax highlighting\n    // for the new script.  So that signal is useless to us, and we have to look for a change ourselves\n    // instead, by comparing the script string we have cached to the current script string.  This is\n    // not great, since it requires a comparison of the entire script string, which will usually be\n    // unchanged.  We optimize by doing this check only when we've been asked to highlight the very\n    // first block; when setPlainText() is called, highlighting will proceed from the beginning.\n    if (script && (pos == 0))\n    {\n        const std::string &cached_script_string = script->String();\n        const std::string real_script_string = document()->toPlainText().toUtf8().constData();\n        \n        if (cached_script_string.compare(real_script_string) != 0)\n        {\n            //qDebug() << \"cached script is wrong!\";\n            documentContentsChanged();\n        }\n    }\n    \n    // set up a new cached script if we don't have one\n    if (!script)\n    {\n        script = new EidosScript(document()->toPlainText().toUtf8().constData());\n        \n        script->Tokenize(true, true);\t// make bad tokens as needed, keep nonsignificant tokens\n        \n        //qDebug() << \"   tokenized...\";\n    }\n    \n    const std::vector<EidosToken> &tokens = script->Tokens();\n    int64_t token_count = static_cast<int64_t>(tokens.size());\n    int64_t token_index = 0;\n    \n    if ((lastProcessedTokenIndex != -1) && (lastProcessedTokenIndex < token_count))\n    {\n        // check whether we can skip tokens processed by earlier calls to highlightBlock,\n        // avoiding having to do an O(N) scan for each block, which would be O(N^2) overall\n        const EidosToken &lastProcessedToken = tokens[static_cast<size_t>(lastProcessedTokenIndex)];\n        \n        if (lastProcessedToken.token_UTF16_end_ < pos)\n            token_index = lastProcessedTokenIndex;\n    }\n    \n    //qDebug() << \"   token_count == \" << token_count << \", initial token_index == \" << token_index;\n    \n    for (; token_index < token_count; ++token_index)\n    {\n        const EidosToken &token = tokens[static_cast<size_t>(token_index)];\n        \n        // a token that starts after the end of the current block means we're done\n        int token_start = token.token_UTF16_start_;\n        \n        if (token_start >= pos + len)\n            break;\n        \n        // a token that ends before the start of the current block means we haven't reached our work yet\n        int token_end = token.token_UTF16_end_;\n        \n        if (token_end < pos)\n        {\n            lastProcessedTokenIndex = token_index;\n            continue;\n        }\n        \n        // remember that we processed this token, unless it extends beyond the end of this block (as whitespace and comments can, among others)\n        if (token_end < pos + len)\n            lastProcessedTokenIndex = token_index;\n        \n        // otherwise, the token is in this block and should be colored; from here on, token_start and token_end are within-block positions\n        // note that a token might start before this block and extend into it, or extend past the end of this block, so we clip\n        token_start -= pos;\n        token_end -= pos;\n        \n        if (token_start < 0)\n            token_start = 0;\n        if (token_end >= len)\n            token_end = len - 1;\n        \n        if (token.token_type_ >= EidosTokenType::kFirstIdentifierLikeToken)\n        {\n            setFormat(token_start, token_end - token_start + 1, keywordFormat);\n            continue;\n        }\n        \n        switch (token.token_type_)\n        {\n        case EidosTokenType::kTokenNumber:\n            setFormat(token_start, token_end - token_start + 1, numberLiteralFormat);\n            break;\n        case EidosTokenType::kTokenString:\n            setFormat(token_start, token_end - token_start + 1, stringLiteralFormat);\n            break;\n        case EidosTokenType::kTokenComment:\n        case EidosTokenType::kTokenCommentLong:\n            setFormat(token_start, token_end - token_start + 1, commentFormat);\n            break;\n        case EidosTokenType::kTokenIdentifier:\n        {\n            // most identifiers are left as black; only special ones get colored\n            const std::string &token_string = token.token_string_;\n            \n            if ((token_string.compare(\"T\") == 0) ||\n                    (token_string.compare(\"F\") == 0) ||\n                    (token_string.compare(\"E\") == 0) ||\n                    (token_string.compare(\"PI\") == 0) ||\n                    (token_string.compare(\"INF\") == 0) ||\n                    (token_string.compare(\"NAN\") == 0) ||\n                    (token_string.compare(\"NULL\") == 0))\n            {\n                setFormat(token_start, token_end - token_start + 1, identifierFormat);\n            }\n            else\n            {\n                // Here we handle SLiM-specific syntax coloring, beyond the Eidos coloring done above\n                // This is from -[SLiMWindowController eidosConsoleWindowController:tokenStringIsSpecialIdentifier:]\n                if (token_string.compare(gStr_community) == 0)\n                    setFormat(token_start, token_end - token_start + 1, identifierFormat);\n                else if (token_string.compare(gStr_sim) == 0)\n                    setFormat(token_start, token_end - token_start + 1, identifierFormat);\n                else if (token_string.compare(gStr_slimgui) == 0)\n                    setFormat(token_start, token_end - token_start + 1, identifierFormat);\n                // -[SLiMWindowController eidosConsoleWindowController:tokenStringIsSpecialIdentifier:] has code\n                // here to give a special color (contextKeywordFormat) to the various keywords for callbacks, like\n                // \"mutationEffect\", \"initialize\", etc.; it is commented out and I don't think we want it\n                else\n                {\n                    int token_length = static_cast<int>(token_string.length());\n                    \n                    if (token_length >= 2)\n                    {\n                        char first_ch = token_string[0];\n                        \n                        if ((first_ch == 'p') || (first_ch == 'g') || (first_ch == 'm') || (first_ch == 's') || (first_ch == 'i'))\n                        {\n                            bool is_slim_identifier = true;\n                            \n                            for (int ch_index = 1; ch_index < token_length; ++ch_index)\n                            {\n                                char idx_ch = token_string[static_cast<size_t>(ch_index)];\n                                \n                                if ((idx_ch < '0') || (idx_ch > '9'))\n                                {\n                                    is_slim_identifier = false;\n                                    break;\n                                }\n                            }\n                            \n                            if (is_slim_identifier)\n                                setFormat(token_start, token_end - token_start + 1, identifierFormat);\n                        }\n                    }\n                    \n                }\n            }\n            break;\n        }\n        default:\n            break;\n        }\n    }\n    \n    // Here we deliberately break an optimization in QSyntaxHighlighter.  It uses these block states to\n    // determine whether a rehighlight of one block needs to cascade to the next block; for example, a\n    // new '/*' inserted in one block might cause the next block to become a comment.  We are not set\n    // up to represent such states explicitly for QSyntaxHighlighter's benefit, so we just always poke\n    // the block state so that QSyntaxHighlighter always recolors the following blocks, all the way to\n    // the end of the script.  This is a bit unfortunate, but in practice it doesn't seem to produce\n    // noticeable performance issues, and if it does the user can always turn off syntax coloring.\n    setCurrentBlockState(currentBlockState() + 1);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMSyntaxHighlighting.h",
    "content": "//\n//  QtSLiMSyntaxHighlighting.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/4/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMSYNTAXHIGHLIGHTING_H\n#define QTSLIMSYNTAXHIGHLIGHTING_H\n\n#include <QSyntaxHighlighter>\n#include <QTextCharFormat>\n#include <QRegularExpression>\n\nclass QString;\nclass QTextDocument;\nclass EidosScript;\n\n\n// This one is for the output pane, and is regex-driven\nclass QtSLiMOutputHighlighter : public QSyntaxHighlighter\n{\n    Q_OBJECT\n\npublic:\n    QtSLiMOutputHighlighter(QTextDocument *p_parent = nullptr);\n\nprotected:\n    virtual void highlightBlock(const QString &text) override;\n\nprotected slots:\n    void paletteChanged(void);\n    \nprivate:\n    bool cachedTextFormats = false;\n    bool cachedForDarkMode = false;\n    \n    QRegularExpression poundRegex;\n    QTextCharFormat poundDirectiveFormat;\n    \n    QRegularExpression commentRegex;\n    QTextCharFormat commentFormat;\n    \n    QRegularExpression globalRegex;\n    QTextCharFormat subpopFormat;\n    QTextCharFormat genomicElementFormat;\n    QTextCharFormat mutationTypeFormat;\n};\n\n// This one is for the scripting pane, and is AST-driven\nclass QtSLiMScriptHighlighter : public QSyntaxHighlighter\n{\n    Q_OBJECT\n\npublic:\n    QtSLiMScriptHighlighter(QTextDocument *p_parent = nullptr);\n    virtual ~QtSLiMScriptHighlighter() override;\n\nprotected:\n    virtual void highlightBlock(const QString &text) override;\n    \nprotected slots:\n    void documentContentsChanged(void);\n    void paletteChanged(void);\n    \nprivate:\n    bool cachedTextFormats = false;\n    bool cachedForDarkMode = false;\n    QTextCharFormat numberLiteralFormat;\n    QTextCharFormat stringLiteralFormat;\n    QTextCharFormat commentFormat;\n    QTextCharFormat identifierFormat;\n    QTextCharFormat keywordFormat;\n    QTextCharFormat contextKeywordFormat;\n    \n    EidosScript *script = nullptr;\n    int64_t lastProcessedTokenIndex = -1;\n};\n\n\n#endif // QTSLIMSYNTAXHIGHLIGHTING_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMTablesDrawer.cpp",
    "content": "//\n//  QtSLiMTablesDrawer.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 2/22/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMTablesDrawer.h\"\n#include \"ui_QtSLiMTablesDrawer.h\"\n\n#include <QPainter>\n#include <QKeyEvent>\n#include <QImage>\n#include <QBuffer>\n#include <QByteArray>\n#include <QString>\n#include <QtGlobal>\n#include <QWindow>\n#include <QDebug>\n\n#include <algorithm>\n#include <utility>\n#include <string>\n#include <vector>\n#include <map>\n\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMAppDelegate.h\"\n\n#include \"mutation_type.h\"\n#include \"interaction_type.h\"\n#include \"eidos_rng.h\"\n\n#include <ctime>\n\n\n// a helper function for making the tooltip images in the mutation and interaction type tables\n// this corresponds to SLiMgui's -[SLiMFunctionGraphToolTipView drawRect:]\nstatic QImage imageForMutationOrInteractionType(MutationType *mut_type, InteractionType *interaction_type)\n{\n    QImage image = QImage(154, 100, QImage::Format_ARGB32);     // double resolution, for high-resolution displays\n    QPainter painter(&image);\n    \n    painter.scale(2.0, 2.0);    // compensate for high resolution\n    painter.setRenderHint(QPainter::Antialiasing);\n    \n    QRect bounds(0, 0, 77, 50);\n    \n    // Flip coordinate system to match that in SLiMgui, for easy porting\n    painter.translate(0, 50);\n    painter.scale(1.0, -1.0);\n    \n    // Frame and fill our tooltip rect\n    painter.fillRect(bounds, QtSLiMColorWithWhite(0.95, 1.0));\n    //QtSLiMFrameRect(bounds, QtSLiMColorWithWhite(0.75, 1.0), painter);  // not used, since Qt gives our tooltip a frame\n    \n    // Plan our plotting\n\tif ((!mut_type && !interaction_type) || (mut_type && interaction_type))\n\t\treturn image;\n\t\n\tsize_t sample_size;\n\tstd::vector<double> draws;\n\tbool draw_positive = false, draw_negative = false;\n\tbool heights_negative = false;\n\tdouble axis_min, axis_max;\n\tbool draw_axis_midpoint = true, custom_axis_max = false;\n\t\n\tif (mut_type)\n\t{\n\t\t// Generate draws for a mutation type; this case is stochastic, based upon a large number of DFE samples.\n\t\t// Draw all the values we will plot; we need our own private RNG so we don't screw up the simulation's.\n\t\t// Drawing selection coefficients could raise, if they are type \"s\" and there is an error in the script,\n\t\t// so we run the sampling inside a try/catch block; if we get a raise, we just show a \"?\" in the plot.\n\t\tstatic bool rng_initialized = false;\n\t\tstatic Eidos_RNG_State local_rng;\n\t\t\n\t\tsample_size = (mut_type->dfe_type_ == DFEType::kScript) ? 100000 : 1000000;\t// large enough to make curves pretty smooth, small enough to be reasonably fast\n\t\tdraws.reserve(sample_size);\n\t\t\n\t\tif (!rng_initialized)\n\t\t{\n\t\t\t_Eidos_InitializeOneRNG(local_rng);\n\t\t\trng_initialized = true;\n\t\t}\n\t\t\n\t\t_Eidos_SetOneRNGSeed(local_rng, 10);\t\t// arbitrary seed, but the same seed every time\n\t\t\n\t\tstd::swap(local_rng, gEidos_RNG_SINGLE);\t// swap in our local RNG for DrawSelectionCoefficient()\n\t\t\n\t\t//std::clock_t start = std::clock();\n\t\t\n\t\ttry\n\t\t{\n\t\t\tfor (size_t sample_count = 0; sample_count < sample_size; ++sample_count)\n\t\t\t{\n\t\t\t\tdouble draw = mut_type->DrawSelectionCoefficient();\n\t\t\t\t\n\t\t\t\tdraws.emplace_back(draw);\n\t\t\t\t\n\t\t\t\tif (draw < 0.0)\t\t\tdraw_negative = true;\n\t\t\t\telse if (draw > 0.0)\tdraw_positive = true;\n\t\t\t}\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tdraws.clear();\n\t\t\tdraw_negative = true;\n\t\t\tdraw_positive = true;\n\t\t}\n\t\t\n\t\t//NSLog(@\"Draws took %f seconds\", (std::clock() - start) / (double)CLOCKS_PER_SEC);\n\t\t\n\t\tstd::swap(local_rng, gEidos_RNG_SINGLE);\t// swap out our local RNG; restore the standard RNG\n\t\t\n\t\t// figure out axis limits\n\t\tif (draw_negative && !draw_positive)\n\t\t{\n\t\t\taxis_min = -1.0;\n\t\t\taxis_max = 0.0;\n\t\t}\n\t\telse if (draw_positive && !draw_negative)\n\t\t{\n\t\t\taxis_min = 0.0;\n\t\t\taxis_max = 1.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\taxis_min = -1.0;\n\t\t\taxis_max = 1.0;\n\t\t}\n\t}\n\telse // if (interaction_type)\n\t{\n\t\t// Since interaction types are deterministic, we don't need draws; we will just calculate our\n\t\t// bin heights directly below.\n\t\tsample_size = 0;\n\t\tdraw_negative = false;\n\t\tdraw_positive = true;\n\t\taxis_min = 0.0;\n\t\tif ((interaction_type->max_distance_ < 1.0) || std::isinf(interaction_type->max_distance_))\n\t\t{\n\t\t\taxis_max = 1.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\taxis_max = interaction_type->max_distance_;\n\t\t\tdraw_axis_midpoint = false;\n\t\t\tcustom_axis_max = true;\n\t\t}\n\t\theights_negative = (interaction_type->if_param1_ < 0.0);\t// this is a negative-strength interaction, if T\n\t}\n\t\n\t// Draw the graph axes and ticks\n    QRect graphRect(bounds.x() + 6, bounds.y() + (heights_negative ? 5 : 14), bounds.width() - 12, bounds.height() - 20);\n\tint axis_y = (heights_negative ? graphRect.y() + graphRect.height() - 1 : graphRect.y());\n\tint tickoff3 = (heights_negative ? 1 : -3);\n\tint tickoff1 = (heights_negative ? 1 : -1);\n\tQColor axisColor = QtSLiMColorWithWhite(0.2, 1.0);\n    \n    painter.fillRect(QRect(graphRect.x(), axis_y, graphRect.width(), 1), axisColor);\n\t\n\tpainter.fillRect(QRect(graphRect.x(), axis_y + tickoff3, 1, 3), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.125), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.25), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.375), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.5), axis_y + tickoff3, 1, 3), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.625), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.75), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + qRound((graphRect.width() - 1) * 0.875), axis_y + tickoff1, 1, 1), axisColor);\n\tpainter.fillRect(QRect(graphRect.x() + graphRect.width() - 1, axis_y + tickoff3, 1, 3), axisColor);\n    \n    // Draw the axis labels\n#ifdef __linux__\n    painter.setFont(QFont(\"Times New Roman\", 14));  // 7, but double scale\n#else\n    painter.setFont(QFont(\"Times New Roman\", 18));  // 9, but double scale\n#endif\n    \n    std::ostringstream ss;\n\tss << axis_max;\n\tstd::string ss_str = ss.str();\n\tQString axis_max_pretty_string = QString::fromStdString(ss_str);\n\tQString axis_min_label = (axis_min == 0.0 ? \"0\" : \"−1\");\n\tQString axis_half_label = (axis_min == 0.0 ? \"0.5\" : (axis_max == 0.0 ? \"−0.5\" : \"0\"));\n\tQString axis_max_label = (custom_axis_max ? axis_max_pretty_string : (axis_max == 0.0 ? \"0\" : \"1\"));\n    double min_label_width = painter.boundingRect(QRectF(), 0, axis_min_label).width() / 2.0;       // /2.0 to compensate for scaled font size\n    double half_label_width = painter.boundingRect(QRectF(), 0, axis_half_label).width() / 2.0;\n    double max_label_width = painter.boundingRect(QRectF(), 0, axis_max_label).width() / 2.0;\n    double min_label_halfwidth = min_label_width / 2.0;\n    double half_label_halfwidth = half_label_width / 2.0;\n    double max_label_halfwidth = max_label_width / 2.0;\n    double label_y = (heights_negative ? bounds.y() + bounds.height() - 11 : bounds.y() + 2);\n    QPointF min_label_point = painter.transform().map(QPointF(bounds.x() + 7 - min_label_halfwidth, label_y));\n    QPointF half_label_point = painter.transform().map(QPointF(bounds.x() + 39 - half_label_halfwidth, label_y));\n    QPointF max_label_point = painter.transform().map(QPointF(custom_axis_max ? bounds.x() + 72 - max_label_width : bounds.x() + 71 - max_label_halfwidth, label_y));\n    \n    painter.setWorldMatrixEnabled(false);\n    painter.drawText(min_label_point, axis_min_label);\n    if (draw_axis_midpoint)\n        painter.drawText(half_label_point, axis_half_label);\n    painter.drawText(max_label_point, axis_max_label);\n    painter.setWorldMatrixEnabled(true);\n    \n    // If we had an exception while drawing values, just show a question mark and return\n\tif (mut_type && !draws.size())\n\t{\n#ifdef __linux__\n        painter.setFont(QFont(\"Times New Roman\", 28));  // 14, but double scale\n#else\n        painter.setFont(QFont(\"Times New Roman\", 36));  // 18, but double scale\n#endif\n        \n        QString labelText(\"?\");\n        int labelWidth = painter.boundingRect(QRect(), 0, labelText).width();\n        double labelX = bounds.x() + qRound((bounds.width() - labelWidth / 2.0) / 2.0); // inner /2.0 compensates for the double-scaled font size, which QPainter does not do, oddly\n        double labelY = bounds.y() + 22;\n        QPointF labelPoint = painter.transform().map(QPointF(labelX, labelY));\n        \n        painter.setWorldMatrixEnabled(false);\n        painter.drawText(labelPoint, labelText);\n        painter.setWorldMatrixEnabled(true);\n\t}\n    \n    QRect interiorRect(graphRect.x(), graphRect.y() + (heights_negative ? 0 : 2), graphRect.width(), graphRect.height() - 2);\n\t\n\t// Tabulate the distribution from the samples we took; the math here is a bit subtle, because when we are doing a -1 to +1 axis\n\t// we want those values to fall at bin centers, but when we're doing 0 to +1 or -1 to 0 we want 0 to fall at the bin edge.\n\tint half_bin_count = interiorRect.width();\n\tint bin_count = half_bin_count * 2;\t\t\t\t\t\t\t\t// 2x bins to look nice on Retina displays\n\tdouble *bins = static_cast<double *>(calloc(static_cast<size_t>(bin_count), sizeof(double)));\n\t\n\tif (sample_size)\n\t{\n\t\t// sample-based tabulation into a histogram; mutation types only, right now\n\t\tfor (size_t sample_count = 0; sample_count < sample_size; ++sample_count)\n\t\t{\n\t\t\tdouble sel_coeff = draws[sample_count];\n\t\t\tint bin_index;\n\t\t\t\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wfloat-equal\"\n\t\t\tif ((axis_min == -1.0) && (axis_max == 1.0))\n\t\t\t\tbin_index = static_cast<int>(floor(((sel_coeff + 1.0) / 2.0) * (bin_count - 1) + 0.5));\n\t\t\telse if ((axis_min == -1.0) && (axis_max == 0.0))\n\t\t\t\tbin_index = static_cast<int>(ceil((sel_coeff + 1.0) * (bin_count - 1 - 0.5) + 0.5));\t\t// 0.0 maps to bin_count - 1, -1.0 maps to the center of bin 0\n\t\t\telse // if ((axis_min == 0.0) && (axis_max == 1.0))\n\t\t\t\tbin_index = static_cast<int>(floor(sel_coeff * (bin_count - 1 + 0.5)));\t\t\t\t\t// 0.0 maps to 0, 1.0 maps to the center of bin_count - 1\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\t\t\t\n\t\t\tif ((bin_index >= 0) && (bin_index < bin_count))\n\t\t\t\tbins[bin_index]++;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// non-sample-based construction of a function by evaluation; interaction types only, right now\n\t\tdouble max_x = interaction_type->max_distance_;\n\t\t\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tdouble bin_left = (bin_index / static_cast<double>(bin_count)) * axis_max;\n\t\t\tdouble bin_right = ((bin_index + 1) / static_cast<double>(bin_count)) * axis_max;\n\t\t\tdouble total_value = 0.0;\n\t\t\t\n\t\t\tfor (int evaluate_index = 0; evaluate_index <= 999; ++evaluate_index)\n\t\t\t{\n\t\t\t\tdouble evaluate_x = bin_left + (bin_right - bin_left) / 999;\n\t\t\t\t\n\t\t\t\tif (evaluate_x < max_x)\n\t\t\t\t\ttotal_value += interaction_type->CalculateStrengthNoCallbacks(evaluate_x);\n\t\t\t}\n\t\t\t\n\t\t\tbins[bin_index] = total_value / 1000.0;\n\t\t}\n\t}\n\t\n    // If we only have samples equal to zero, replicate the center column for symmetry\n\tif (!draw_positive && !draw_negative)\n\t{\n\t\tdouble zero_count = std::max(bins[half_bin_count - 1], bins[half_bin_count]);\t// whichever way it rounds...\n\t\t\n\t\tbins[half_bin_count - 1] = zero_count;\n\t\tbins[half_bin_count] = zero_count;\n\t}\n\t\n\t// Find the maximum-magnitude bin count\n\tdouble max_bin = 0;\n\t\n\tif (heights_negative)\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t\tmax_bin = std::min(max_bin, bins[bin_index]);\n\t}\n\telse\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t\tmax_bin = std::max(max_bin, bins[bin_index]);\n\t}\n\t\n    // Plot the bins\n    QColor plotColor = Qt::black;\n\t\n\tif (heights_negative)\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tif (bins[bin_index] < 0)\n\t\t\t{\n\t\t\t\tdouble height = interiorRect.height() * (bins[bin_index] / max_bin);\n\t\t\t\t\n                painter.fillRect(QRectF(interiorRect.x() + bin_index * 0.5, interiorRect.y() + interiorRect.height() - height, 0.5, height), plotColor);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tif (bins[bin_index] > 0)\n                painter.fillRect(QRectF(interiorRect.x() + bin_index * 0.5, interiorRect.y(), 0.5, interiorRect.height() * (bins[bin_index] / max_bin)), plotColor);\n\t\t}\n\t}\n\t\n\tfree(bins);\n    return image;\n}\n    \n\n//\n//  QtSLiMTablesDrawer\n//\n\nQtSLiMTablesDrawer::QtSLiMTablesDrawer(QtSLiMWindow *p_parent) :\n    QWidget(p_parent, Qt::Window),\n    parentSLiMWindow(p_parent),\n    ui(new Ui::QtSLiMTablesDrawer)\n{\n    ui->setupUi(this);\n    initializeUI();\n}\n\nQtSLiMTablesDrawer::~QtSLiMTablesDrawer()\n{\n    delete ui;\n}\n\nQHeaderView *QtSLiMTablesDrawer::configureTableView(QTableView *tableView)\n{\n    QHeaderView *tableHHeader = tableView->horizontalHeader();\n    QHeaderView *tableVHeader = tableView->verticalHeader();\n    \n    tableHHeader->setMinimumSectionSize(1);\n    tableVHeader->setMinimumSectionSize(1);\n    \n    tableHHeader->setSectionsClickable(false);\n    tableHHeader->setSectionsMovable(false);\n    \n    QFont headerFont = tableHHeader->font();\n    QFont cellFont = tableView->font();\n#ifdef __linux__\n    headerFont.setPointSize(8);\n    cellFont.setPointSize(8);\n#else\n    headerFont.setPointSize(11);\n    cellFont.setPointSize(11);\n#endif\n    tableHHeader->setFont(headerFont);\n    tableView->setFont(cellFont);\n    \n    tableVHeader->setSectionResizeMode(QHeaderView::Fixed);\n    tableVHeader->setDefaultSectionSize(18);\n    \n    return tableHHeader;\n}\n\nvoid QtSLiMTablesDrawer::initializeUI(void)\n{\n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // Make the models for the tables; this is a sort of datasource concept, except\n    // that because C++ is not sufficiently dynamic it has to be a separate object\n    mutTypeTableModel_ = new QtSLiMMutTypeTableModel(parentSLiMWindow);\n    ui->mutationTypeTable->setModel(mutTypeTableModel_);\n    \n    geTypeTableModel_ = new QtSLiMGETypeTypeTableModel(parentSLiMWindow);\n    ui->genomicElementTypeTable->setModel(geTypeTableModel_);\n\n    interactionTypeTableModel_ = new QtSLiMInteractionTypeTableModel(parentSLiMWindow);\n    ui->interactionTypeTable->setModel(interactionTypeTableModel_);\n\n    eidosBlockTableModel_ = new QtSLiMEidosBlockTableModel(parentSLiMWindow);\n    ui->eidosBlockTable->setModel(eidosBlockTableModel_);\n    \n    // Configure the table views, then set column widths and sizing behavior\n    {\n        QHeaderView *mutTypeTableHHeader = configureTableView(ui->mutationTypeTable);\n        \n        mutTypeTableHHeader->resizeSection(0, 53);\n        mutTypeTableHHeader->resizeSection(1, 43);\n        mutTypeTableHHeader->resizeSection(2, 53);\n        //mutTypeTableHHeader->resizeSection(3, ?);\n        mutTypeTableHHeader->setSectionResizeMode(0, QHeaderView::Fixed);\n        mutTypeTableHHeader->setSectionResizeMode(1, QHeaderView::Fixed);\n        mutTypeTableHHeader->setSectionResizeMode(2, QHeaderView::Fixed);\n        mutTypeTableHHeader->setSectionResizeMode(3, QHeaderView::Stretch);\n        \n        // pre-configure for our image tooltips with an off-white background\n        ui->mutationTypeTable->setStyleSheet(\"QToolTip{border: 0px; padding: 0px; margin-top: 1px; background-color: '#F2F2F2'; opacity: 255;}\");\n    }\n    {\n        QHeaderView *geTypeTableHHeader = configureTableView(ui->genomicElementTypeTable);\n        \n        geTypeTableHHeader->resizeSection(0, 53);\n        geTypeTableHHeader->resizeSection(1, 43);\n        //geTypeTableHHeader->resizeSection(2, ?);\n        geTypeTableHHeader->setSectionResizeMode(0, QHeaderView::Fixed);\n        geTypeTableHHeader->setSectionResizeMode(1, QHeaderView::Fixed);\n        geTypeTableHHeader->setSectionResizeMode(2, QHeaderView::Stretch);\n        \n        QAbstractItemDelegate *tableDelegate = new QtSLiMGETypeTypeTableDelegate(ui->genomicElementTypeTable);\n        ui->genomicElementTypeTable->setItemDelegate(tableDelegate);\n    }\n    {\n        QHeaderView *interactionTypeTableHHeader = configureTableView(ui->interactionTypeTable);\n        \n        interactionTypeTableHHeader->resizeSection(0, 53);\n        interactionTypeTableHHeader->resizeSection(1, 43);\n        interactionTypeTableHHeader->resizeSection(2, 53);\n        //interactionTypeTableHHeader->resizeSection(3, ?);\n        interactionTypeTableHHeader->setSectionResizeMode(0, QHeaderView::Fixed);\n        interactionTypeTableHHeader->setSectionResizeMode(1, QHeaderView::Fixed);\n        interactionTypeTableHHeader->setSectionResizeMode(2, QHeaderView::Fixed);\n        interactionTypeTableHHeader->setSectionResizeMode(3, QHeaderView::Stretch);\n        \n        // pre-configure for our image tooltips with an off-white background\n        ui->interactionTypeTable->setStyleSheet(\"QToolTip{border: 0px; padding: 0px; margin-top: 1px; background-color: '#F2F2F2'; opacity: 255;}\");\n    }\n    {\n        QHeaderView *eidosBlockTableHHeader = configureTableView(ui->eidosBlockTable);\n        \n        eidosBlockTableHHeader->resizeSection(0, 53);\n        eidosBlockTableHHeader->resizeSection(1, 63);\n        eidosBlockTableHHeader->resizeSection(2, 63);\n        //eidosBlockTableHHeader->resizeSection(3, ?);\n        eidosBlockTableHHeader->setSectionResizeMode(0, QHeaderView::Fixed);\n        eidosBlockTableHHeader->setSectionResizeMode(1, QHeaderView::Fixed);\n        eidosBlockTableHHeader->setSectionResizeMode(2, QHeaderView::Fixed);\n        eidosBlockTableHHeader->setSectionResizeMode(3, QHeaderView::Stretch);\n    }\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nvoid QtSLiMTablesDrawer::closeEvent(QCloseEvent *p_event)\n{\n    // send our close signal\n    emit willClose();\n    \n    // use super's default behavior\n    QWidget::closeEvent(p_event);\n}\n\n\n//\n//  Define models for the four table views\n//\n\nQtSLiMMutTypeTableModel::QtSLiMMutTypeTableModel(QObject *p_parent) : QAbstractTableModel(p_parent)\n{\n    // p_parent must be a pointer to QtSLiMWindow, which holds our model information\n    if (dynamic_cast<QtSLiMWindow *>(p_parent) == nullptr)\n        throw p_parent;\n}\n\nQtSLiMMutTypeTableModel::~QtSLiMMutTypeTableModel()\n{\n}\n\nint QtSLiMMutTypeTableModel::rowCount(const QModelIndex & /* p_parent */) const\n{\n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (community)\n        return static_cast<int>(community->AllMutationTypes().size());\n    \n    return 0;\n}\n\nint QtSLiMMutTypeTableModel::columnCount(const QModelIndex & /* p_parent */) const\n{\n    return 4;\n}\n\nQVariant QtSLiMMutTypeTableModel::data(const QModelIndex &p_index, int role) const\n{\n    if (!p_index.isValid())\n        return QVariant();\n    \n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (!community)\n        return QVariant();\n    \n    if (role == Qt::DisplayRole)\n    {\n        const std::map<slim_objectid_t,MutationType*> &mutationTypes = community->AllMutationTypes();\n        int mutationTypeCount = static_cast<int>(mutationTypes.size());\n        \n        if (p_index.row() < mutationTypeCount)\n        {\n            auto mutTypeIter = mutationTypes.begin();\n            \n            std::advance(mutTypeIter, p_index.row());\n            slim_objectid_t mutTypeID = mutTypeIter->first;\n            MutationType *mutationType = mutTypeIter->second;\n            \n            if (p_index.column() == 0)\n            {\n                QString idString = QString(\"m%1\").arg(mutTypeID);\n                \n                if (community->all_species_.size() > 1)\n                    idString.append(\" \").append(QString::fromStdString(mutationType->species_.avatar_));\n                \n                return QVariant(idString);\n            }\n            else if (p_index.column() == 1)\n            {\n                return QVariant(QString(\"%1\").arg(static_cast<double>(mutationType->dominance_coeff_), 0, 'f', 3));\n            }\n            else if (p_index.column() == 2)\n            {\n                switch (mutationType->dfe_type_)\n                {\n                    case DFEType::kFixed:\t\t\treturn QVariant(QString(\"fixed\"));\n                    case DFEType::kGamma:\t\t\treturn QVariant(QString(\"gamma\"));\n                    case DFEType::kExponential:\t\treturn QVariant(QString(\"exp\"));\n                    case DFEType::kNormal:\t\t\treturn QVariant(QString(\"normal\"));\n                    case DFEType::kWeibull:\t\t\treturn QVariant(QString(\"Weibull\"));\n                    case DFEType::kLaplace:\t\t\treturn QVariant(QString(\"Laplace\"));\n                    case DFEType::kScript:\t\t\treturn QVariant(QString(\"script\"));\n                }\n            }\n            else if (p_index.column() == 3)\n            {\n                QString paramString;\n                \n                if (mutationType->dfe_type_ == DFEType::kScript)\n                {\n                    // DFE type 's' has parameters of type string\n                    for (unsigned int paramIndex = 0; paramIndex < mutationType->dfe_strings_.size(); ++paramIndex)\n                    {\n                        QString dfe_string = QString::fromStdString(mutationType->dfe_strings_[paramIndex]);\n                        \n                        paramString += (\"\\\"\" + dfe_string + \"\\\"\");\n                        \n                        if (paramIndex < mutationType->dfe_strings_.size() - 1)\n                            paramString += \", \";\n                    }\n                }\n                else\n                {\n                    // All other DFEs have parameters of type double\n                    for (unsigned int paramIndex = 0; paramIndex < mutationType->dfe_parameters_.size(); ++paramIndex)\n                    {\n                        QString paramSymbol;\n                        \n                        switch (mutationType->dfe_type_)\n                        {\n                            case DFEType::kFixed:\t\t\tparamSymbol = \"s\"; break;\n                            case DFEType::kGamma:\t\t\tparamSymbol = (paramIndex == 0 ? \"s̄\" : \"α\"); break;\n                            case DFEType::kExponential:\t\tparamSymbol = \"s̄\"; break;\n                            case DFEType::kNormal:\t\t\tparamSymbol = (paramIndex == 0 ? \"s̄\" : \"σ\"); break;\n                            case DFEType::kWeibull:\t\t\tparamSymbol = (paramIndex == 0 ? \"λ\" : \"k\"); break;\n                            case DFEType::kLaplace:\t\t\tparamSymbol = (paramIndex == 0 ? \"s̄\" : \"b\"); break;\n                            case DFEType::kScript:\t\t\tbreak;\n                        }\n                        \n                        paramString += QString(\"%1=%2\").arg(paramSymbol).arg(mutationType->dfe_parameters_[paramIndex], 0, 'f', 3);\n                        \n                        if (paramIndex < mutationType->dfe_parameters_.size() - 1)\n                            paramString += \", \";\n                    }\n                }\n                \n                return QVariant(paramString);\n            }\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        const std::map<slim_objectid_t,MutationType*> &mutationTypes = community->AllMutationTypes();\n        int mutationTypeCount = static_cast<int>(mutationTypes.size());\n        \n        if (p_index.row() < mutationTypeCount)\n        {\n            auto mutTypeIter = mutationTypes.begin();\n            std::advance(mutTypeIter, p_index.row());\n            \n            // Display an image in the tooltip; thanks to https://stackoverflow.com/a/34300771/2752221\n            QImage image = imageForMutationOrInteractionType(mutTypeIter->second, nullptr);\n            \n            // the image is high-dpi; smoothly downscale the image to standard DPI if we're not on a high-DPI screen\n            QWidget *tablesWindow = controller->TablesDrawerController();\n            QWindow *tablesWindowHandle = tablesWindow ? tablesWindow->windowHandle() : nullptr;\n            double dpi = tablesWindowHandle ? tablesWindowHandle->devicePixelRatio() : 1.0;\n            \n            if (dpi < 1.5)\n                image = image.scaled(QSize(77, 50), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\n            \n            QByteArray image_data;\n            QBuffer buffer(&image_data);\n            image.save(&buffer, \"PNG\", 100);\n            return QString(\"<img width=77 height=50 src='data:image/png;base64, %0'>\").arg(QString(image_data.toBase64()));\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (p_index.column())\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n\nQVariant QtSLiMMutTypeTableModel::headerData(int section,\n                                             Qt::Orientation /* orientation */,\n                                             int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"ID\");\n        case 1: return QVariant(\"h\");\n        case 2: return QVariant(\"DFE\");\n        case 3: return QVariant(\"Params\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"the ID for the mutation type\");\n        case 1: return QVariant(\"the dominance coefficient\");\n        case 2: return QVariant(\"the distribution of fitness effects\");\n        case 3: return QVariant(\"the DFE parameters\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n    \nvoid QtSLiMMutTypeTableModel::reloadTable(void)\n{\n    beginResetModel();\n    endResetModel();\n}\n\n\nQtSLiMGETypeTypeTableModel::QtSLiMGETypeTypeTableModel(QObject *p_parent) : QAbstractTableModel(p_parent)\n{\n    // p_parent must be a pointer to QtSLiMWindow, which holds our model information\n    if (dynamic_cast<QtSLiMWindow *>(p_parent) == nullptr)\n        throw p_parent;\n}\n\nQtSLiMGETypeTypeTableModel::~QtSLiMGETypeTypeTableModel()\n{\n}\n\nint QtSLiMGETypeTypeTableModel::rowCount(const QModelIndex & /* p_parent */) const\n{\n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (community)\n        return static_cast<int>(community->AllGenomicElementTypes().size());\n    \n    return 0;\n}\n\nint QtSLiMGETypeTypeTableModel::columnCount(const QModelIndex & /* p_parent */) const\n{\n    return 3;\n}\n\nQVariant QtSLiMGETypeTypeTableModel::data(const QModelIndex &p_index, int role) const\n{\n    if (!p_index.isValid())\n        return QVariant();\n    \n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (!community)\n        return QVariant();\n    \n    if (role == Qt::DisplayRole)\n    {\n        const std::map<slim_objectid_t,GenomicElementType*> &genomicElementTypes = community->AllGenomicElementTypes();\n        int genomicElementTypeCount = static_cast<int>(genomicElementTypes.size());\n        \n        if (p_index.row() < genomicElementTypeCount)\n        {\n            auto genomicElementTypeIter = genomicElementTypes.begin();\n            \n            std::advance(genomicElementTypeIter, p_index.row());\n            slim_objectid_t genomicElementTypeID = genomicElementTypeIter->first;\n            GenomicElementType *genomicElementType = genomicElementTypeIter->second;\n            \n            if (p_index.column() == 0)\n            {\n                QString idString = QString(\"g%1\").arg(genomicElementTypeID);\n                \n                if (community->all_species_.size() > 1)\n                    idString.append(\" \").append(QString::fromStdString(genomicElementType->species_.avatar_));\n                \n                return QVariant(idString);\n            }\n            else if (p_index.column() == 1)\n            {\n                float red, green, blue, alpha;\n                \n                controller->colorForGenomicElementType(genomicElementType, genomicElementTypeID, &red, &green, &blue, &alpha);\n                \n                QColor geTypeColor = QColor::fromRgbF(static_cast<qreal>(red), static_cast<qreal>(green), static_cast<qreal>(blue), static_cast<qreal>(alpha));\n                QRgb geTypeRGB = geTypeColor.rgb();\n                \n                return QVariant(geTypeRGB); // return the color as an unsigned int\n            }\n            else if (p_index.column() == 2)\n            {\n                QString paramString;\n                \n                for (unsigned int mutTypeIndex = 0; mutTypeIndex < genomicElementType->mutation_fractions_.size(); ++mutTypeIndex)\n                {\n                    MutationType *mutType = genomicElementType->mutation_type_ptrs_[mutTypeIndex];\n                    double mutTypeFraction = genomicElementType->mutation_fractions_[mutTypeIndex];\n                    \n                    paramString += QString(\"m%1=%2\").arg(mutType->mutation_type_id_).arg(mutTypeFraction, 0, 'f', 3);\n                    \n                    if (mutTypeIndex < genomicElementType->mutation_fractions_.size() - 1)\n                        paramString += \", \";\n                }\n                \n                return QVariant(paramString);\n            }\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (p_index.column())\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n\nQVariant QtSLiMGETypeTypeTableModel::headerData(int section,\n                                                Qt::Orientation /* orientation */,\n                                                int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"ID\");\n        case 1: return QVariant(\"Color\");\n        case 2: return QVariant(\"Mutation types\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"the ID for the genomic element type\");\n        case 1: return QVariant(\"the color used in SLiMgui\");\n        case 2: return QVariant(\"the mutation types drawn from\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    return QVariant();\n}\n    \nvoid QtSLiMGETypeTypeTableModel::reloadTable(void)\n{\n    beginResetModel();\n    endResetModel();\n}\n\n\nQtSLiMInteractionTypeTableModel::QtSLiMInteractionTypeTableModel(QObject *p_parent) : QAbstractTableModel(p_parent)\n{\n    // p_parent must be a pointer to QtSLiMWindow, which holds our model information\n    if (dynamic_cast<QtSLiMWindow *>(p_parent) == nullptr)\n        throw p_parent;\n}\n\nQtSLiMInteractionTypeTableModel::~QtSLiMInteractionTypeTableModel()\n{\n}\n\nint QtSLiMInteractionTypeTableModel::rowCount(const QModelIndex & /* p_parent */) const\n{\n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (community)\n        return static_cast<int>(community->AllInteractionTypes().size());\n    \n    return 0;\n}\n\nint QtSLiMInteractionTypeTableModel::columnCount(const QModelIndex & /* p_parent */) const\n{\n    return 4;\n}\n\nQVariant QtSLiMInteractionTypeTableModel::data(const QModelIndex &p_index, int role) const\n{\n    if (!p_index.isValid())\n        return QVariant();\n    \n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    Community *community = controller->community;\n    \n    if (!community)\n        return QVariant();\n    \n    if (role == Qt::DisplayRole)\n    {\n        const std::map<slim_objectid_t,InteractionType*> &interactionTypes = community->AllInteractionTypes();\n        int interactionTypeCount = static_cast<int>(interactionTypes.size());\n        \n        if (p_index.row() < interactionTypeCount)\n        {\n            auto interactionTypeIter = interactionTypes.begin();\n            \n            std::advance(interactionTypeIter, p_index.row());\n            slim_objectid_t interactionTypeID = interactionTypeIter->first;\n            InteractionType *interactionType = interactionTypeIter->second;\n            \n            if (p_index.column() == 0)\n            {\n                QString idString = QString(\"i%1\").arg(interactionTypeID);\n                \n                return QVariant(idString);\n            }\n            else if (p_index.column() == 1)\n            {\n                return QVariant(QString(\"%1\").arg(interactionType->max_distance_, 0, 'f', 3));\n            }\n            else if (p_index.column() == 2)\n            {\n                switch (interactionType->if_type_)\n                {\n                    case SpatialKernelType::kFixed:\t\t\t\treturn QVariant(QString(\"fixed\"));\n                    case SpatialKernelType::kLinear:\t\t\treturn QVariant(QString(\"linear\"));\n                    case SpatialKernelType::kExponential:\t\treturn QVariant(QString(\"exp\"));\n                    case SpatialKernelType::kNormal:\t\t\treturn QVariant(QString(\"normal\"));\n                    case SpatialKernelType::kCauchy:\t\t\treturn QVariant(QString(\"Cauchy\"));\n                    case SpatialKernelType::kStudentsT:\t\t\treturn QVariant(QString(\"Student's t\"));\n                }\n            }\n            else if (p_index.column() == 3)\n            {\n                QString paramString;\n                \n                // the first parameter is always the maximum interaction strength\n                paramString += QString(\"f=%1\").arg(interactionType->if_param1_, 0, 'f', 3);\n                \n                // append second parameters where applicable\n                switch (interactionType->if_type_)\n                {\n                    case SpatialKernelType::kFixed:\n                    case SpatialKernelType::kLinear:\n                        break;\n                    case SpatialKernelType::kExponential:\n                        paramString += QString(\", β=%1\").arg(interactionType->if_param2_, 0, 'f', 3);\n                        break;\n                    case SpatialKernelType::kNormal:\n                        paramString += QString(\", σ=%1\").arg(interactionType->if_param2_, 0, 'f', 3);\n                        break;\n                    case SpatialKernelType::kCauchy:\n                        paramString += QString(\", γ=%1\").arg(interactionType->if_param2_, 0, 'f', 3);\n                        break;\n                    case SpatialKernelType::kStudentsT:\n                        paramString += QString(\", ν=%1, σ=%2\").arg(interactionType->if_param2_, 0, 'f', 3).arg(interactionType->if_param3_, 0, 'f', 3);\n                        break;\n                }\n                \n                return QVariant(paramString);\n            }\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        const std::map<slim_objectid_t,InteractionType*> &interactionTypes = community->AllInteractionTypes();\n        int interactionTypeCount = static_cast<int>(interactionTypes.size());\n        \n        if (p_index.row() < interactionTypeCount)\n        {\n            auto interactionTypeIter = interactionTypes.begin();\n            std::advance(interactionTypeIter, p_index.row());\n            \n            // Display an image in the tooltip; thanks to https://stackoverflow.com/a/34300771/2752221\n            QImage image = imageForMutationOrInteractionType(nullptr, interactionTypeIter->second);\n            \n            // the image is high-dpi; smoothly downscale the image to standard DPI if we're not on a high-DPI screen\n            QWidget *tablesWindow = controller->TablesDrawerController();\n            QWindow *tablesWindowHandle = tablesWindow ? tablesWindow->windowHandle() : nullptr;\n            double dpi = tablesWindowHandle ? tablesWindowHandle->devicePixelRatio() : 1.0;\n            \n            if (dpi < 1.5)\n                image = image.scaled(QSize(77, 50), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\n            \n            QByteArray image_data;\n            QBuffer buffer(&image_data);\n            image.save(&buffer, \"PNG\", 100);\n            return QString(\"<img width=77 height=50 src='data:image/png;base64, %0'>\").arg(QString(image_data.toBase64()));\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (p_index.column())\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n\nQVariant QtSLiMInteractionTypeTableModel::headerData(int section,\n                                                     Qt::Orientation /* orientation */,\n                                                     int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"ID\");\n        case 1: return QVariant(\"max\");\n        case 2: return QVariant(\"IF\");\n        case 3: return QVariant(\"Params\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"the ID for the interaction type\");\n        case 1: return QVariant(\"the maximum interaction distance\");\n        case 2: return QVariant(\"the interaction function\");\n        case 3: return QVariant(\"the interaction function parameters\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    return QVariant();\n}\n    \nvoid QtSLiMInteractionTypeTableModel::reloadTable(void)\n{\n    beginResetModel();\n    endResetModel();\n}\n\n\nQtSLiMEidosBlockTableModel::QtSLiMEidosBlockTableModel(QObject *p_parent) : QAbstractTableModel(p_parent)\n{\n    // p_parent must be a pointer to QtSLiMWindow, which holds our model information\n    if (dynamic_cast<QtSLiMWindow *>(p_parent) == nullptr)\n        throw p_parent;\n}\n\nQtSLiMEidosBlockTableModel::~QtSLiMEidosBlockTableModel()\n{\n}\n\nint QtSLiMEidosBlockTableModel::rowCount(const QModelIndex & /* p_parent */) const\n{\n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    \n    if (controller && !controller->invalidSimulation())\n        return static_cast<int>(controller->community->AllScriptBlocks().size());\n    \n    return 0;\n}\n\nint QtSLiMEidosBlockTableModel::columnCount(const QModelIndex & /* p_parent */) const\n{\n    return 4;\n}\n\nQVariant QtSLiMEidosBlockTableModel::data(const QModelIndex &p_index, int role) const\n{\n    if (!p_index.isValid())\n        return QVariant();\n    \n    QtSLiMWindow *controller = static_cast<QtSLiMWindow *>(parent());\n    \n    if (!controller || controller->invalidSimulation())\n        return QVariant();\n    \n    if (role == Qt::DisplayRole)\n    {\n        Community *community = controller->community;\n        std::vector<SLiMEidosBlock*> &scriptBlocks = community->AllScriptBlocks();\n        int scriptBlockCount = static_cast<int>(scriptBlocks.size());\n        \n        if (p_index.row() < scriptBlockCount)\n        {\n            SLiMEidosBlock *scriptBlock = scriptBlocks[static_cast<size_t>(p_index.row())];\n            \n            if (p_index.column() == 0)\n            {\n                slim_objectid_t block_id = scriptBlock->block_id_;\n                QString idString;\n                \n                if (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n                    idString = \"—\";\n                else if (block_id == -1)\n                    idString = \"—\";\n                else\n                    idString = QString(\"s%1\").arg(block_id);\n                \n                if ((community->all_species_.size() > 1) && scriptBlock->species_spec_)\n                    idString.append(\" \").append(QString::fromStdString(scriptBlock->species_spec_->avatar_));\n                else if ((community->all_species_.size() > 1) && scriptBlock->ticks_spec_)\n                    idString.append(\" \").append(QString::fromStdString(scriptBlock->ticks_spec_->avatar_));\n                \n                return QVariant(idString);\n            }\n            else if (p_index.column() == 1)\n            {\n                if (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n                    return QVariant(\"—\");\n                else if (!scriptBlock->tick_range_evaluated_)\n                    return QVariant(\"?\");\n                else if (scriptBlock->tick_range_is_sequence_ == false)\n                    return QVariant(\"...\");\n                else if (scriptBlock->tick_start_ == -1)\n                    return QVariant(\"MIN\");\n                else\n                    return QVariant(QString(\"%1\").arg(scriptBlock->tick_start_));\n            }\n            else if (p_index.column() == 2)\n            {\n                if (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n                    return QVariant(\"—\");\n                else if (!scriptBlock->tick_range_evaluated_)\n                    return QVariant(\"?\");\n                else if (scriptBlock->tick_range_is_sequence_ == false)\n                    return QVariant(\"...\");\n                else if (scriptBlock->tick_end_ == SLIM_MAX_TICK + 1)\n                    return QVariant(\"MAX\");\n                else\n                    return QVariant(QString(\"%1\").arg(scriptBlock->tick_end_));\n            }\n            else if (p_index.column() == 3)\n            {\n                switch (scriptBlock->type_)\n                {\n                    case SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\treturn QVariant(\"first()\");\n                    case SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\treturn QVariant(\"early()\");\n                    case SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\treturn QVariant(\"late()\");\n                    case SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\treturn QVariant(\"initialize()\");\n                    case SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\treturn QVariant(\"mutationEffect()\");\n                    case SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\treturn QVariant(\"fitnessEffect()\");\n                    case SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\treturn QVariant(\"interaction()\");\n                    case SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\treturn QVariant(\"mateChoice()\");\n                    case SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\treturn QVariant(\"modifyChild()\");\n                    case SLiMEidosBlockType::SLiMEidosRecombinationCallback:\treturn QVariant(\"recombination()\");\n                    case SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\treturn QVariant(\"mutation()\");\n                    case SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\treturn QVariant(\"survival()\");\n                    case SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\treturn QVariant(\"reproduction()\");\n                    case SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n                    {\n                        EidosASTNode *function_decl_node = scriptBlock->root_node_->children_[0];\n                        EidosASTNode *function_name_node = function_decl_node->children_[1];\n                        QString function_name = QString::fromStdString(function_name_node->token_->token_string_);\n                        \n                        return function_name + \"()\";\n                    }\n                    case SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\treturn QVariant(\"\");\t// never hit\n                }\n            }\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        Community *community = controller->community;\n        std::vector<SLiMEidosBlock*> &scriptBlocks = community->AllScriptBlocks();\n        int scriptBlockCount = static_cast<int>(scriptBlocks.size());\n        \n        if (p_index.row() < scriptBlockCount)\n        {\n            SLiMEidosBlock *scriptBlock = scriptBlocks[static_cast<size_t>(p_index.row())];\n            const char *script_string = scriptBlock->compound_statement_node_->token_->token_string_.c_str();\n            QString q_script_string = QString::fromStdString(script_string);\n            \n            q_script_string.replace('\\t', \"   \");\n            \n            return q_script_string;\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (p_index.column())\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    \n    return QVariant();\n}\n\nQVariant QtSLiMEidosBlockTableModel::headerData(int section,\n                                                Qt::Orientation /* orientation */,\n                                                int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"ID\");\n        case 1: return QVariant(\"Start\");\n        case 2: return QVariant(\"End\");\n        case 3: return QVariant(\"Type\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::ToolTipRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(\"the ID for the script block\");\n        case 1: return QVariant(\"the start tick\");\n        case 2: return QVariant(\"the end tick\");\n        case 3: return QVariant(\"the script block type\");\n        default: return QVariant(\"\");\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        switch (section)\n        {\n        case 0: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 1: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 2: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        case 3: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);\n        }\n    }\n    return QVariant();\n}\n    \nvoid QtSLiMEidosBlockTableModel::reloadTable(void)\n{\n    beginResetModel();\n    endResetModel();\n}\n\n\n//\n//  Drawing delegates for custom drawing in the table views\n//\n\nQtSLiMGETypeTypeTableDelegate::~QtSLiMGETypeTypeTableDelegate(void)\n{\n}\n\nvoid QtSLiMGETypeTypeTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const\n{\n    if (index.column() == 1)\n    {\n        // Get the color for the genomic element type, which has been encoded as an unsigned int in a QVariant\n        QVariant data = index.data();\n        QRgb rgbData = static_cast<QRgb>(data.toUInt());\n        QColor boxColor(rgbData);\n        \n        // Calculate a rect for the color swatch in the center of the item's field\n        QRect itemRect = option.rect;\n        int centerX = static_cast<int>(itemRect.center().x());\n        int halfSide = static_cast<int>((itemRect.height() - 8) / 2);\n        QRect boxRect = QRect(centerX - halfSide, itemRect.top() + 5, halfSide * 2, halfSide * 2);\n        \n        // Fill and frame\n        painter->fillRect(boxRect, boxColor);\n        QtSLiMFrameRect(boxRect, Qt::black, *painter);\n    }\n    else\n    {\n        // Let super draw\n        QStyledItemDelegate::paint(painter, option, index);\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMTablesDrawer.h",
    "content": "//\n//  QtSLiMTablesDrawer.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/22/2020.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMTABLESDRAWER_H\n#define QTSLIMTABLESDRAWER_H\n\n#include <QAbstractTableModel>\n#include <QStyledItemDelegate>\n#include <QWidget>\n\nclass QCloseEvent;\nclass QtSLiMWindow;\nclass QTableView;\nclass QHeaderView;\n\nclass QtSLiMMutTypeTableModel;\nclass QtSLiMGETypeTypeTableModel;\nclass QtSLiMInteractionTypeTableModel;\nclass QtSLiMEidosBlockTableModel;\n\n\nnamespace Ui {\nclass QtSLiMTablesDrawer;\n}\n\nclass QtSLiMTablesDrawer : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMWindow *parentSLiMWindow = nullptr;     // a copy of parent with the correct class, for convenience\n    \n    explicit QtSLiMTablesDrawer(QtSLiMWindow *p_parent = nullptr);\n    virtual ~QtSLiMTablesDrawer() override;\n    \nsignals:\n    void willClose(void);\n    \nprivate slots:\n    virtual void closeEvent(QCloseEvent *p_event) override;\n    \nprivate:\n    Ui::QtSLiMTablesDrawer *ui;\n    \n    QtSLiMMutTypeTableModel *mutTypeTableModel_ = nullptr;\n    QtSLiMGETypeTypeTableModel *geTypeTableModel_ = nullptr;\n    QtSLiMInteractionTypeTableModel *interactionTypeTableModel_ = nullptr;\n    QtSLiMEidosBlockTableModel *eidosBlockTableModel_ = nullptr;\n    \n    QHeaderView *configureTableView(QTableView *tableView);\n    void initializeUI(void);\n    \n    friend QtSLiMWindow;\n};\n\n\n//\n//  Declare models for the four table views; has to be in header file for MOC\n//\n\nclass QtSLiMMutTypeTableModel : public QAbstractTableModel\n{\n    Q_OBJECT    \n    \npublic:\n    QtSLiMMutTypeTableModel(QObject *p_parent = nullptr);\n    virtual ~QtSLiMMutTypeTableModel() override;\n\n    virtual int rowCount(const QModelIndex &p_parent = QModelIndex()) const override;\n    virtual int columnCount(const QModelIndex &p_parent = QModelIndex()) const override;\n\n    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;\n    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;\n    \n    void reloadTable(void);\n};\n\nclass QtSLiMGETypeTypeTableModel : public QAbstractTableModel\n{\n    Q_OBJECT    \n    \npublic:\n    QtSLiMGETypeTypeTableModel(QObject *p_parent = nullptr);\n    virtual ~QtSLiMGETypeTypeTableModel() override;\n\n    virtual int rowCount(const QModelIndex &p_parent = QModelIndex()) const override;\n    virtual int columnCount(const QModelIndex &p_parent = QModelIndex()) const override;\n\n    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;\n    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;\n    \n    void reloadTable(void);\n};\n\nclass QtSLiMInteractionTypeTableModel : public QAbstractTableModel\n{\n    Q_OBJECT    \n    \npublic:\n    QtSLiMInteractionTypeTableModel(QObject *p_parent = nullptr);\n    virtual ~QtSLiMInteractionTypeTableModel() override;\n\n    virtual int rowCount(const QModelIndex &p_parent = QModelIndex()) const override;\n    virtual int columnCount(const QModelIndex &p_parent = QModelIndex()) const override;\n\n    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;\n    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;\n    \n    void reloadTable(void);\n};\n\nclass QtSLiMEidosBlockTableModel : public QAbstractTableModel\n{\n    Q_OBJECT    \n    \npublic:\n    QtSLiMEidosBlockTableModel(QObject *p_parent = nullptr);\n    virtual ~QtSLiMEidosBlockTableModel() override;\n\n    virtual int rowCount(const QModelIndex &p_parent = QModelIndex()) const override;\n    virtual int columnCount(const QModelIndex &p_parent = QModelIndex()) const override;\n\n    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;\n    virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;\n    \n    void reloadTable(void);\n};\n\n\n//\n//  Drawing delegates for custom drawing in the table views\n//\n\nclass QtSLiMGETypeTypeTableDelegate : public QStyledItemDelegate\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMGETypeTypeTableDelegate(QObject *p_parent = nullptr) : QStyledItemDelegate(p_parent) {}\n    virtual ~QtSLiMGETypeTypeTableDelegate(void) override;\n    \n    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;\n};\n\n\n#endif // QTSLIMTABLESDRAWER_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMTablesDrawer.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMTablesDrawer</class>\n <widget class=\"QWidget\" name=\"QtSLiMTablesDrawer\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>810</height>\n   </rect>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>280</width>\n    <height>500</height>\n   </size>\n  </property>\n  <property name=\"maximumSize\">\n   <size>\n    <width>510</width>\n    <height>16777215</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Object Tables</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"leftMargin\">\n    <number>10</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>10</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>10</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>10</number>\n   </property>\n   <item>\n    <widget class=\"QLabel\" name=\"mutationTypeLabel\">\n     <property name=\"text\">\n      <string>Mutation Types:</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QTableView\" name=\"mutationTypeTable\">\n     <property name=\"focusPolicy\">\n      <enum>Qt::NoFocus</enum>\n     </property>\n     <property name=\"verticalScrollBarPolicy\">\n      <enum>Qt::ScrollBarAlwaysOn</enum>\n     </property>\n     <property name=\"editTriggers\">\n      <set>QAbstractItemView::NoEditTriggers</set>\n     </property>\n     <property name=\"tabKeyNavigation\">\n      <bool>false</bool>\n     </property>\n     <property name=\"showDropIndicator\" stdset=\"0\">\n      <bool>false</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::NoSelection</enum>\n     </property>\n     <property name=\"showGrid\">\n      <bool>false</bool>\n     </property>\n     <property name=\"wordWrap\">\n      <bool>false</bool>\n     </property>\n     <property name=\"cornerButtonEnabled\">\n      <bool>false</bool>\n     </property>\n     <attribute name=\"verticalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>4</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"genomicElementTypeLabel\">\n     <property name=\"text\">\n      <string>Genomic Element Types:</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QTableView\" name=\"genomicElementTypeTable\">\n     <property name=\"focusPolicy\">\n      <enum>Qt::NoFocus</enum>\n     </property>\n     <property name=\"verticalScrollBarPolicy\">\n      <enum>Qt::ScrollBarAlwaysOn</enum>\n     </property>\n     <property name=\"editTriggers\">\n      <set>QAbstractItemView::NoEditTriggers</set>\n     </property>\n     <property name=\"tabKeyNavigation\">\n      <bool>false</bool>\n     </property>\n     <property name=\"showDropIndicator\" stdset=\"0\">\n      <bool>false</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::NoSelection</enum>\n     </property>\n     <property name=\"showGrid\">\n      <bool>false</bool>\n     </property>\n     <property name=\"wordWrap\">\n      <bool>false</bool>\n     </property>\n     <property name=\"cornerButtonEnabled\">\n      <bool>false</bool>\n     </property>\n     <attribute name=\"verticalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_2\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>4</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"interactionTypeLabel\">\n     <property name=\"text\">\n      <string>Interaction Types:</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QTableView\" name=\"interactionTypeTable\">\n     <property name=\"focusPolicy\">\n      <enum>Qt::NoFocus</enum>\n     </property>\n     <property name=\"verticalScrollBarPolicy\">\n      <enum>Qt::ScrollBarAlwaysOn</enum>\n     </property>\n     <property name=\"editTriggers\">\n      <set>QAbstractItemView::NoEditTriggers</set>\n     </property>\n     <property name=\"tabKeyNavigation\">\n      <bool>false</bool>\n     </property>\n     <property name=\"showDropIndicator\" stdset=\"0\">\n      <bool>false</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::NoSelection</enum>\n     </property>\n     <property name=\"showGrid\">\n      <bool>false</bool>\n     </property>\n     <property name=\"wordWrap\">\n      <bool>false</bool>\n     </property>\n     <property name=\"cornerButtonEnabled\">\n      <bool>false</bool>\n     </property>\n     <attribute name=\"verticalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"verticalSpacer_3\">\n     <property name=\"orientation\">\n      <enum>Qt::Vertical</enum>\n     </property>\n     <property name=\"sizeType\">\n      <enum>QSizePolicy::Fixed</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>20</width>\n       <height>4</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"eidosBlockLabel\">\n     <property name=\"text\">\n      <string>Eidos Blocks:</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QTableView\" name=\"eidosBlockTable\">\n     <property name=\"focusPolicy\">\n      <enum>Qt::NoFocus</enum>\n     </property>\n     <property name=\"verticalScrollBarPolicy\">\n      <enum>Qt::ScrollBarAlwaysOn</enum>\n     </property>\n     <property name=\"editTriggers\">\n      <set>QAbstractItemView::NoEditTriggers</set>\n     </property>\n     <property name=\"tabKeyNavigation\">\n      <bool>false</bool>\n     </property>\n     <property name=\"showDropIndicator\" stdset=\"0\">\n      <bool>false</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::NoSelection</enum>\n     </property>\n     <property name=\"showGrid\">\n      <bool>false</bool>\n     </property>\n     <property name=\"wordWrap\">\n      <bool>false</bool>\n     </property>\n     <property name=\"cornerButtonEnabled\">\n      <bool>false</bool>\n     </property>\n     <attribute name=\"verticalHeaderVisible\">\n      <bool>false</bool>\n     </attribute>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMVariableBrowser.cpp",
    "content": "//\n//  QtSLiMVariableBrowser.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/17/2019.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMVariableBrowser.h\"\n#include \"ui_QtSLiMVariableBrowser.h\"\n\n#include <QSettings>\n#include <QStringList>\n#include <QVariant>\n#include <QTreeWidgetItem>\n#include <QScrollBar>\n#include <QDebug>\n\n#include <utility>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"QtSLiMEidosConsole.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMExtras.h\"\n\n#include \"eidos_symbol_table.h\"\n\n\nstatic int QtSLiMVarBrowserRowHeight = 0;  // a global, for simplicity; 0 is uninitialized, -1 is failed to init\n\n\n//\n// This subclass of QStyledItemDelegate provides custom drawing for the outline view.\n//\n\nQtSLiMVariableBrowserDelegate::~QtSLiMVariableBrowserDelegate(void)\n{\n}\n\nvoid QtSLiMVariableBrowserDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const\n{\n    // On Ubuntu, items get shown as having \"focus\" even when they're not selectable, which I dislike; this disables that appearance\n    // See https://stackoverflow.com/a/2061871/2752221\n    QStyleOptionViewItem modifiedOption(option);\n    if (modifiedOption.state & QStyle::State_HasFocus)\n        modifiedOption.state = modifiedOption.state ^ QStyle::State_HasFocus;\n    \n    // then let super draw\n    QStyledItemDelegate::paint(painter, modifiedOption, index);\n}\n\n\n//\n//  QtSLiMBrowserItem\n//\n\nQtSLiMBrowserItem::QtSLiMBrowserItem(QString name, EidosValue_SP value, int elementIndex, bool isEllipsis) :\n    QTreeWidgetItem(), symbol_name(name), eidos_value(value), element_index(elementIndex), is_ellipsis(isEllipsis)\n{\n    // We want to display Eidos constants in gray text, to de-emphasize them.  For now, we just hard-code them\n    // as a hack, because we *don't* want SLiM constants (sim, g1, p1, etc.) to display dimmed\n    is_eidos_constant = false;\n    if ((name == \"T\") || (name == \"F\") || (name == \"E\") || (name == \"PI\") || (name == \"INF\") || (name == \"NAN\") || (name == \"NULL\"))\n        is_eidos_constant = true;\n    \n    // If we contain children, they won't be added under us until we get expanded, so force the indicator on\n    // Note this applies both to the row for the vector (count > 0) and rows for elements (count > 0)\n    if (eidos_value && (eidos_value->Type() == EidosValueType::kValueObject) && (eidos_value->Count() > 0))\n    {\n        setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);\n        has_children = true;\n    }\n    else\n    {\n        has_children = false;\n    }\n    \n    // Precompute the hash value for this item.  This is done up front and cached, so that it is available\n    // even if our eidos_value object element gets deallocated.  We use it to confirm that two browser items\n    // truly refer to the same Eidos object.  The hash encapsulates the symbol name, the element index, and\n    // the object-element type.  It does not encapsulate the number of elements; we want matches to carry\n    // over across changes in vector length.  Note that of course hash collisions can occur.  That will\n    // result in the expansion of the wrong item during a browser reload; it is not fatal, so as long as it\n    // is very rare, it's OK.  Since the same symbol might provide a different EidosValue object every time\n    // it is accessed (as properties often would), and we can't look inside the elements, this is the best\n    // we can do.  It should be quite reliable.\n    item_hash = qHash(symbol_name) ^ static_cast<unsigned int>(element_index);\n    \n    if (eidos_value && (eidos_value->Type() == EidosValueType::kValueObject))\n        item_hash ^= (std::hash<std::string>{}(eidos_value->ElementType()) << 16);\n}\n\nQtSLiMBrowserItem::~QtSLiMBrowserItem(void)\n{\n    //qDebug() << \"QtSLiMBrowserItem::~QtSLiMBrowserItem\";\n    eidos_value.reset();\n}\n\nQVariant QtSLiMBrowserItem::data(int column, int role) const\n{\n    if (role == Qt::DisplayRole)\n    {\n        if (column == 0)            return symbol_name;\n        if (is_ellipsis)            return QVariant();\n        if (!eidos_value)           return (column == 3) ? \"<inaccessible>\" : QVariant();\n        if (element_index != -1)    return QVariant();\n        \n        // the remainder of this assumes the above conditions: the column is not 0, the item is not an ellipsis item,\n        // there is an associated eidos_value, and the element_index is -1 (we're representing a whole vector)\n        if (column == 1)\n        {\n            EidosValueType value_type = eidos_value->Type();\n            std::string type_string = StringForEidosValueType(value_type);\n            QString typeString = QString::fromStdString(type_string);\n            \n            if (value_type == EidosValueType::kValueObject)\n            {\n                EidosValue_Object *object_value = static_cast<EidosValue_Object *>(eidos_value.get());\n                const std::string &element_string = object_value->ElementType();\n                QString elementString = QString::fromStdString(element_string);\n                \n                typeString.append('<');\n                typeString.append(elementString);\n                typeString.append('>');\n            }\n            \n            return typeString;\n        }\n        else if (column == 2)\n        {\n            return eidos_value->Count();\n        }\n        else if (column == 3)\n        {\n            int value_count = eidos_value->Count();\n            std::ostringstream outstream;\n            \n            // print values as a comma-separated list with strings quoted; halfway between print() and cat()\n            for (int value_index = 0; value_index < value_count; ++value_index)\n            {\n                EidosValue_SP element_value = eidos_value->GetValueAtIndex(value_index, nullptr);\n                \n                if (value_index > 0)\n                {\n                    outstream << \", \";\n                    \n                    // terminate the list at some reasonable point, otherwise we generate massively long strings for large vectors...\n                    if (value_index > 50)\n                    {\n                        outstream << \", ...\";\n                        break;\n                    }\n                }\n                outstream << *element_value;\n            }\n            \n            return QString::fromStdString(outstream.str()).simplified();\n        }\n    }\n    else if (role == Qt::TextAlignmentRole)\n    {\n        if (column == 2)\n            return static_cast<Qt::Alignment::Int>(Qt::AlignHCenter | Qt::AlignVCenter);\n        else\n            return static_cast<Qt::Alignment::Int>(Qt::AlignLeft | Qt::AlignVCenter);\n    }\n    else if (role == Qt::ForegroundRole)\n    {\n        bool inDarkMode = QtSLiMInDarkMode();\n        \n        if (inDarkMode)\n            return QBrush(is_eidos_constant ? Qt::gray : Qt::white);\n        else\n            return QBrush(is_eidos_constant ? Qt::darkGray : Qt::black);\n    }\n    else if (role == Qt::FontRole)\n    {\n        static QFont *defaultFont = nullptr;\n        static QFont *italicFont = nullptr;\n        \n        if (!defaultFont)\n        {\n            defaultFont = new QFont(QTreeWidgetItem::data(column, Qt::FontRole).value<QFont>());\n            italicFont = new QFont(*defaultFont);\n            italicFont->setItalic(true);\n        }\n        \n        return (element_index == -1) ? *defaultFont : *italicFont;\n    }\n    else if (role == Qt::SizeHintRole)\n    {\n        if (QtSLiMVarBrowserRowHeight > 0)\n            return QSize(0, QtSLiMVarBrowserRowHeight);\n        else\n            return QTreeWidgetItem::data(column, Qt::SizeHintRole);\n    }\n    \n    return QVariant();\n}\n\n\n//\n//  QtSLiMVariableBrowser\n//\n\nQtSLiMVariableBrowser::QtSLiMVariableBrowser(QtSLiMEidosConsole *p_parent) :\n    QWidget(p_parent, Qt::Window),    // the console window has us as a parent, but is still a standalone window\n    parentEidosConsole(p_parent),\n    ui(new Ui::QtSLiMVariableBrowser)\n{\n    ui->setupUi(this);\n    \n    // no window icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(QIcon());\n#endif\n    \n    // prevent this window from keeping the app running when all main windows are closed\n    setAttribute(Qt::WA_QuitOnClose, false);\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMVariableBrowser\");\n    resize(settings.value(\"size\", QSize(400, 300)).toSize());\n    move(settings.value(\"pos\", QPoint(25, 445)).toPoint());\n    settings.endGroup();\n    \n    // tree widget settings\n    QTreeWidget *browserTree = ui->browserTreeWidget;\n    \n    QAbstractItemDelegate *outlineDelegate = new QtSLiMVariableBrowserDelegate(browserTree);\n    browserTree->setItemDelegate(outlineDelegate);\n    \n#if defined(__linux__)\n    {\n        // use a smaller font for the outline on Linux\n        QFont browserFont(browserTree->font());\n        browserFont.setPointSizeF(browserFont.pointSizeF() - 1);\n        browserTree->setFont(browserFont);\n    }\n#endif\n    \n    browserTree->setHeaderLabels(QStringList{\"Symbol\", \"Type\", \"Size\", \"Values\"});\n#if defined(__APPLE__)\n    browserTree->headerItem()->setTextAlignment(0, Qt::AlignVCenter);\n    browserTree->headerItem()->setTextAlignment(1, Qt::AlignVCenter);\n    browserTree->headerItem()->setTextAlignment(2, Qt::AlignCenter);\n    browserTree->headerItem()->setTextAlignment(3, Qt::AlignVCenter);\n#else\n    browserTree->headerItem()->setTextAlignment(0, Qt::AlignTop);\n    browserTree->headerItem()->setTextAlignment(1, Qt::AlignTop);\n    browserTree->headerItem()->setTextAlignment(2, Qt::AlignHCenter | Qt::AlignTop);\n    browserTree->headerItem()->setTextAlignment(3, Qt::AlignTop);\n#endif\n    browserTree->setColumnWidth(0, 180);\n    browserTree->setColumnWidth(1, 180);\n    browserTree->setColumnWidth(2, 75);\n    browserTree->header()->setMinimumHeight(21);\n    browserTree->header()->setSectionResizeMode(QHeaderView::Fixed);\n    browserTree->header()->setSectionsMovable(false);\n    browserTree->setMinimumWidth(500);\n    browserTree->setUniformRowHeights(true);\n    \n    // handle expand/collapse events\n    connect(browserTree, &QTreeWidget::itemExpanded, this, &QtSLiMVariableBrowser::itemExpanded);\n    connect(browserTree, &QTreeWidget::itemCollapsed, this, &QtSLiMVariableBrowser::itemCollapsed);\n    connect(browserTree, &QTreeWidget::itemClicked, this, &QtSLiMVariableBrowser::itemClicked);\n    \n    // watch the tree widget's vertical scroller, to restore the scroll position\n    connect(ui->browserTreeWidget->verticalScrollBar(), &QScrollBar::valueChanged, this, &QtSLiMVariableBrowser::scrollerChanged);\n    \n    // initial state\n    reloadBrowser(true);\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n}\n\nQtSLiMVariableBrowser::~QtSLiMVariableBrowser()\n{\n    clearSavedExpansionState();\n    \n    delete ui;\n}\n\nvoid QtSLiMVariableBrowser::closeEvent(QCloseEvent *p_event)\n{\n    // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMVariableBrowser\");\n    settings.setValue(\"size\", size());\n    settings.setValue(\"pos\", pos());\n    settings.endGroup();\n    \n    // send our close signal\n    emit willClose();\n    \n    // use super's default behavior\n    QWidget::closeEvent(p_event);\n}\n\nvoid QtSLiMVariableBrowser::reloadBrowser(bool nowValidState)\n{\n    QTreeWidget *browserTree = ui->browserTreeWidget;\n    \n    // Take over the old browser tree so we can consult it for things to expand\n    QTreeWidgetItem *root = browserTree->invisibleRootItem();\n    \n    //qDebug() << \"   RELOAD: root ==\" << root << \"and has\" << root->childCount() << \"children\";\n    \n    if (root->childCount() > 0)\n    {\n        if (old_children.count() == 0)\n        {\n            // The root currently has items under it; if we have no valid saved state already,\n            // the current state of the tree represents a state we want to save\n            old_children = root->takeChildren();\n            old_scroll_position = browserTree->verticalScrollBar()->value();\n            //qDebug() << \"   SAVED OLD TREE ITEMS FOR MATCHING\";\n            \n            // We don't use the EidosValues in the saved tree at all, since they will potentially be stale;\n            // to free up the memory involved, we go through the saved tree and wipe the values to nullptr\n            for (QTreeWidgetItem *old_root_child : static_cast<const QList<QTreeWidgetItem *> &>(old_children))\n                wipeEidosValuesFromSubtree(old_root_child);\n        }\n        else\n        {\n            // We didn't want to save the current state, since we already have a saved state that\n            // has not been invalidated by a more recent user action; so just clear the root\n            browserTree->clear();\n        }\n    }\n    \n    // Make the new root items; we do not attempt to reuse the old items, not worth the complication\n    if (parentEidosConsole)\n    {\n        EidosSymbolTable *symbols = parentEidosConsole->symbolTable();\n        \n        if (symbols)\n        {\n            // Add constants first, then non-constants\n            for (int isConstant = 1; isConstant >= 0; --isConstant)\n            {\n                std::vector<std::string> symbolNamesVec = isConstant ? symbols->ReadOnlySymbols() : symbols->ReadWriteSymbols();\n                size_t symbolNamesCount = symbolNamesVec.size();\n                \n                for (size_t index = 0; index < symbolNamesCount;++ index)\n                {\n                    const std::string &symbolName = symbolNamesVec[index];\n                    EidosValue_SP symbolValue = symbols->GetValueOrRaiseForSymbol(EidosStringRegistry::GlobalStringIDForString(symbolName));\n                    QtSLiMBrowserItem *item = new QtSLiMBrowserItem(QString::fromStdString(symbolName), std::move(symbolValue));\n                    browserTree->addTopLevelItem(item);\n                    \n                    // figure out the correct row height, which we have to do after making a row item\n                    if (QtSLiMVarBrowserRowHeight == 0)\n                    {\n                        QRect item_rect = browserTree->visualItemRect(item);\n                        int defaultHeight = item_rect.height();\n                        QtSLiMVarBrowserRowHeight = (defaultHeight > 0) ? defaultHeight + 2 : -1;\n                    }\n                }\n            }\n        }\n    }\n    \n    // If we're now in a valid state, we'll try to match our old expanded state; otherwise, we have\n    // just emptied out the tree, but are in an invalid state where we cannot repopulate it\n    if (nowValidState)\n    {\n        // Analyze the old children and try to expand items to match the previous state\n        doingMatching = true;\n        \n        for (QTreeWidgetItem *old_root_child : static_cast<const QList<QTreeWidgetItem *> &>(old_children))\n            matchExpansionOfOldItem(old_root_child, root);\n        \n        // Try to restore the scroll position to where it was when we saved the tree\n        // We use visualItemRect() for its side effect of forcing relayout, giving the\n        // vertical scroller the right value range; I don't see an API for that\n        if (browserTree->invisibleRootItem()->childCount() > 0)\n        {\n            browserTree->visualItemRect(browserTree->invisibleRootItem()->child(0));\n            browserTree->verticalScrollBar()->setValue(old_scroll_position);\n        }\n        \n        doingMatching = false;\n        \n        // Note that we hang on to the old expanded state; we will continue to use it until it is invalidated\n    }\n}\n\nvoid QtSLiMVariableBrowser::matchExpansionOfOldItem(QTreeWidgetItem *itemToMatch, QTreeWidgetItem *parentToSearch)\n{\n    // The old tree item itemToMatch was expanded; we have been asked to find a matching item in parentToSearch and expand it\n    QtSLiMBrowserItem *browserItemToMatch = dynamic_cast<QtSLiMBrowserItem *>(itemToMatch);\n    \n    if (browserItemToMatch && browserItemToMatch->childCount() > 0)\n    {\n        //qDebug() << \"Old symbol\" << browserItemToMatch->symbol_name << \"was expanded, looking for match...\";\n        //qDebug() << \"   parentToSearch ==\" << parentToSearch << \"and has\" << parentToSearch->childCount() << \"children\";\n        \n        // Old state we're trying to match; note that the EidosValue here may contain freed objects!\n        // We thus can't look inside the EidosValue to establish a match, nor do we want to use pointer\n        // equality (the underlying object might have been dealloced and a new object alloced at the\n        // same address; and in any case the same symbol might have changed address, as properties\n        // would unless their value is cached).  Instead, to establish a match we use a precomputed\n        // hash value that includes symbol name, element index, and object-element type.\n        uint item_hash_to_match = browserItemToMatch->item_hash;\n        \n        // We consider a \"match\" to have an identical hash; it must also have children to expand\n        for (int parentToSearchIndex = 0; parentToSearchIndex < parentToSearch->childCount(); parentToSearchIndex++)\n        {\n            QTreeWidgetItem *childItemToCheck = parentToSearch->child(parentToSearchIndex);\n            QtSLiMBrowserItem *childBrowserItemToCheck = dynamic_cast<QtSLiMBrowserItem *>(childItemToCheck);\n            \n            if (childBrowserItemToCheck && childBrowserItemToCheck->has_children)\n            {\n                //qDebug() << \"   checking child item with symbol\" << childBrowserItemToCheck->symbol_name << \"...\";\n                \n                if (childBrowserItemToCheck->item_hash == item_hash_to_match)\n                {\n                    // We have a match, so we expand it\n                    //qDebug() << \"      MATCH: expanding...\";\n                    ui->browserTreeWidget->expandItem(childBrowserItemToCheck);\n                    \n                    // If the items involved are vectors with >1 child, expand to the right number of children\n                    int targetChildCount = browserItemToMatch->childCount();\n                    int currentChildCount = childBrowserItemToCheck->childCount();\n                    \n                    while (currentChildCount < targetChildCount)\n                    {\n                        QTreeWidgetItem *lastExpanded = childBrowserItemToCheck->child(currentChildCount - 1);\n                        QtSLiMBrowserItem *lastBrowserItem = dynamic_cast<QtSLiMBrowserItem *>(lastExpanded);\n                        \n                        if (!lastBrowserItem || !lastBrowserItem->is_ellipsis)\n                            break;\n                        \n                        expandEllipsisItem(lastBrowserItem);\n                        currentChildCount = childBrowserItemToCheck->childCount();\n                    }\n                    \n                    // Since this item was expanded, we might have further matches in need of expansion under it\n                    for (int old_child_index = 0; old_child_index < browserItemToMatch->childCount(); old_child_index++)\n                    {\n                        QTreeWidgetItem *old_item_child = browserItemToMatch->child(old_child_index);\n                        matchExpansionOfOldItem(old_item_child, childBrowserItemToCheck);\n                    }\n                }\n                else\n                {\n                    //qDebug() << \"      no match :  hashes are\" << item_hash_to_match << \"and\" << childBrowserItemToCheck->item_hash;\n                }\n            }\n        }\n    }\n}\n\nvoid QtSLiMVariableBrowser::wipeEidosValuesFromSubtree(QTreeWidgetItem *item)\n{\n    QtSLiMBrowserItem *browserItem = dynamic_cast<QtSLiMBrowserItem *>(item);\n    \n    if (browserItem)\n    {\n        browserItem->eidos_value.reset();\n        \n        for (int child_index = 0; child_index < browserItem->childCount(); child_index++)\n            wipeEidosValuesFromSubtree(browserItem->child(child_index));\n    }\n}\n\nvoid QtSLiMVariableBrowser::appendIndexedItemsToItem(QtSLiMBrowserItem *browserItem, int startIndex)\n{\n    EidosValue *eidos_value = browserItem->eidos_value.get();\n    \n    if (eidos_value && (eidos_value->Type() == EidosValueType::kValueObject))\n    {\n        int elementCount = eidos_value->Count();\n        int appendCount = std::max(10, startIndex);           // reveal twice as many items with each expansion\n        int lastIndex = ((startIndex + appendCount - 1) > (elementCount - 1)) ? (elementCount - 1) : (startIndex + appendCount - 1);\n        int index;\n        \n        for (index = startIndex; index <= lastIndex; ++index)\n        {\n            QString childName = QString(\"%1[%2]\").arg(browserItem->symbol_name).arg(index);\n            QtSLiMBrowserItem *childItem = new QtSLiMBrowserItem(childName, browserItem->eidos_value, index);   // elements refer to the main vector\n            \n            browserItem->addChild(childItem);\n        }\n        \n        if (index < elementCount - 1)\n        {\n            QtSLiMBrowserItem *ellipsisItem = new QtSLiMBrowserItem(\"...\", EidosValue_SP(nullptr), index, true);\n            \n            browserItem->addChild(ellipsisItem);\n        }\n    }\n}\n\nvoid QtSLiMVariableBrowser::itemExpanded(QTreeWidgetItem *item)\n{\n    clearSavedExpansionState();     // invalidate our saved expansion state\n    \n    QtSLiMBrowserItem *browserItem = dynamic_cast<QtSLiMBrowserItem *>(item);\n    EidosValue *eidos_value = browserItem->eidos_value.get();\n    int element_index = browserItem->element_index;\n    \n    if (eidos_value && (eidos_value->Type() == EidosValueType::kValueObject))\n    {\n        int elementCount = eidos_value->Count();\n\t\t\n\t\t// values which are of object type and contain more than one element get displayed as a list of elements\n\t\tif ((elementCount > 1) && (element_index == -1))\n\t\t{\n            appendIndexedItemsToItem(browserItem, 0);\n\t\t}\n        else if ((elementCount == 1) || (element_index != -1))\n        {\n            // display property values for either (a) a object vector of length 1, or (b) an element of an object vector\n            // we used to display zero-length property values for zero-length object vectors, but don't any more\n            int display_index = (element_index != -1) ? element_index : 0;\n            EidosValue_Object *eidos_object_vector = static_cast<EidosValue_Object *>(eidos_value);\n            EidosObject *eidos_object = eidos_object_vector->ObjectElementAtIndex_NOCAST(display_index, nullptr);\n\t\t\tconst EidosClass *object_class = eidos_object->Class();\n\t\t\tconst std::vector<EidosPropertySignature_CSP> *properties = object_class->Properties();\n\t\t\tsize_t propertyCount = properties->size();\n\t\t\tbool oldSuppressWarnings = gEidosSuppressWarnings, inaccessibleCaught = false;\n\t\t\t\n\t\t\tgEidosSuppressWarnings = true;\t\t// prevent warnings from questionable property accesses from producing warnings in the user's output pane\n\t\t\t\n\t\t\tfor (size_t index = 0; index < propertyCount; ++index)\n\t\t\t{\n\t\t\t\tconst EidosPropertySignature_CSP &propertySig = (*properties)[index];\n\t\t\t\tconst std::string &symbolName = propertySig->property_name_;\n\t\t\t\tEidosGlobalStringID symbolID = propertySig->property_id_;\n                QString symbolString = QString::fromStdString(symbolName);\n\t\t\t\tEidosValue_SP symbolValue;\n\t\t\t\t\n\t\t\t\t// protect against raises in property accesses due to inaccessible properties\n\t\t\t\ttry {\n\t\t\t\t\tsymbolValue = eidos_object->GetProperty(symbolID);\n\t\t\t\t} catch (...) {\n\t\t\t\t\t//std::cout << \"caught inaccessible property \" << symbolName << std::endl;\n\t\t\t\t\tinaccessibleCaught = true;\n\t\t\t\t}\n\t\t\t\t\n                QtSLiMBrowserItem *childItem = new QtSLiMBrowserItem(symbolString, std::move(symbolValue));\n\t\t\t\t\n                item->addChild(childItem);\n\t\t\t}\n\t\t\t\n\t\t\tgEidosSuppressWarnings = oldSuppressWarnings;\n\t\t\t\n\t\t\tif (inaccessibleCaught)\n\t\t\t{\n\t\t\t\t// throw away the raise message(s) so they don't confuse us\n\t\t\t\tgEidosTermination.clear();\n\t\t\t\tgEidosTermination.str(gEidosStr_empty_string);\n\t\t\t}\n        }\n    }\n}\n\nvoid QtSLiMVariableBrowser::itemCollapsed(QTreeWidgetItem *item)\n{\n    clearSavedExpansionState();     // invalidate our saved expansion state\n    \n    // Take the children from item and free them\n    QList<QTreeWidgetItem *> item_children = item->takeChildren();\n    \n    while (!item_children.isEmpty())\n        delete item_children.takeFirst();\n}\n\nvoid QtSLiMVariableBrowser::expandEllipsisItem(QtSLiMBrowserItem *browserItem)\n{\n    clearSavedExpansionState();     // invalidate our saved expansion state\n    \n    QTreeWidgetItem *parentItem = browserItem->parent();\n    QtSLiMBrowserItem *parentBrowserItem = dynamic_cast<QtSLiMBrowserItem *>(parentItem);\n    \n    if (parentBrowserItem)\n    {\n        appendIndexedItemsToItem(parentBrowserItem, browserItem->element_index);\n        parentBrowserItem->removeChild(browserItem);\n        delete browserItem;\n    }\n}\n\nvoid QtSLiMVariableBrowser::itemClicked(QTreeWidgetItem *item, int /* column */)\n{\n    // If the item is an ellipsis item, expand it to show more items\n    QtSLiMBrowserItem *browserItem = dynamic_cast<QtSLiMBrowserItem *>(item);\n    \n    if (browserItem)\n    {\n        if (browserItem->is_ellipsis)\n        {\n            expandEllipsisItem(browserItem);\n        }\n        else if (browserItem->isExpanded())\n        {\n            ui->browserTreeWidget->collapseItem(browserItem);\n        }\n        else    // collapsed\n        {\n            ui->browserTreeWidget->expandItem(browserItem);\n        }\n    }\n}\n\nvoid QtSLiMVariableBrowser::clearSavedExpansionState(void)\n{\n    // We want to save the expansion state only when the user changes it.  That way,\n    // we will re-expand correctly even after a recycle and several steps; we'll\n    // remember what used to be open until the user changes it.\n    \n    // Matching involves doing various expansions; that should not trigger a discard\n    // of the saved state, because it doesn't come from a user action\n    if (doingMatching)\n        return;\n    \n    while (!old_children.isEmpty())\n        delete old_children.takeFirst();\n}\n\nvoid QtSLiMVariableBrowser::scrollerChanged(void)\n{\n    if (doingMatching)\n        return;\n    \n    // If the user drags the scroller to a new position, we want to remember and restore\n    // that new position even if we're restoring a tree that was saved earlier\n    old_scroll_position = ui->browserTreeWidget->verticalScrollBar()->value();\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMVariableBrowser.h",
    "content": "//\n//  QtSLiMVariableBrowser.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/17/2019.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMVARIABLEBROWSER_H\n#define QTSLIMVARIABLEBROWSER_H\n\n#include <QWidget>\n#include <QTreeWidgetItem>\n#include <QStyledItemDelegate>\n\n#include \"eidos_value.h\"\n\nclass QCloseEvent;\nclass QtSLiMEidosConsole;\n\n\n// A QTreeWidgetItem subclass that keeps associated information\n\nclass QtSLiMBrowserItem : public QTreeWidgetItem\n{\n    // no Q_OBJECT; QTreeWidgetItem is not a QObject subclass!\n    \npublic:\n    QtSLiMBrowserItem(QString name, EidosValue_SP value) : QtSLiMBrowserItem(name, value, -1) {}\n    QtSLiMBrowserItem(QString name, EidosValue_SP value, int index) : QtSLiMBrowserItem(name, value, index, false) {}\n    QtSLiMBrowserItem(QString name, EidosValue_SP value, int index, bool isEllipsis);\n    virtual ~QtSLiMBrowserItem(void) override;\n    \n    virtual QVariant data(int column, int role) const override;\n    \n    QString symbol_name;            // the name as displayed in the browser\n    EidosValue_SP eidos_value;      // the EidosValue referred to by this item (perhaps just one element of it)\n    int element_index;              // -1 if this item refers to the whole value; otherwise, an element index\n    uint item_hash;                 // a precomputed hash value that can be used to confirm that items match\n    bool is_eidos_constant;         // true if this is one of the built-in Eidos constants; cached for speed\n    bool is_ellipsis;               // true if this item is a \"...\" representing more undisplayed elements\n    bool has_children;              // true if this item has children (which might not be created yet)\n};\n\n\n// This subclass of QStyledItemDelegate provides custom drawing for the outline view.\n\nclass QtSLiMVariableBrowserDelegate : public QStyledItemDelegate\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMVariableBrowserDelegate(QObject *p_parent = nullptr) : QStyledItemDelegate(p_parent) {}\n    virtual ~QtSLiMVariableBrowserDelegate(void) override;\n    \n    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;\n};\n\n\nnamespace Ui {\nclass QtSLiMVariableBrowser;\n}\n\nclass QtSLiMVariableBrowser : public QWidget\n{\n    Q_OBJECT\n    \npublic:\n    QtSLiMEidosConsole *parentEidosConsole = nullptr;     // a copy of parent with the correct class, for convenience\n    \n    explicit QtSLiMVariableBrowser(QtSLiMEidosConsole *p_parent = nullptr);\n    virtual ~QtSLiMVariableBrowser() override;\n    \n    void reloadBrowser(bool nowValidState);\n    \npublic slots:\n    void itemExpanded(QTreeWidgetItem *item);\n    void itemCollapsed(QTreeWidgetItem *item);\n    void itemClicked(QTreeWidgetItem *item, int column);\n    \nsignals:\n    void willClose(void);\n    \nprivate slots:\n    virtual void closeEvent(QCloseEvent *p_event) override;\n    \nprivate:\n    Ui::QtSLiMVariableBrowser *ui;\n    \n    void appendIndexedItemsToItem(QtSLiMBrowserItem *browserItem, int startIndex);\n    void matchExpansionOfOldItem(QTreeWidgetItem *itemToMatch, QTreeWidgetItem *parentToSearch);\n    void expandEllipsisItem(QtSLiMBrowserItem *browserItem);\n    void clearSavedExpansionState(void);\n    void wipeEidosValuesFromSubtree(QTreeWidgetItem *item);\n    void scrollerChanged(void);\n    \n    QList<QTreeWidgetItem *> old_children;  // a saved tree that we will try to match next reload\n    int old_scroll_position = 0;            // a saved scroll position, parallel to old_children\n    bool doingMatching = false;\n};\n\n\n#endif // QTSLIMVARIABLEBROWSER_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMVariableBrowser.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMVariableBrowser</class>\n <widget class=\"QWidget\" name=\"QtSLiMVariableBrowser\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Variable Browser</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QTreeWidget\" name=\"browserTreeWidget\">\n     <property name=\"minimumSize\">\n      <size>\n       <width>300</width>\n       <height>200</height>\n      </size>\n     </property>\n     <property name=\"font\">\n      <font>\n       <pointsize>11</pointsize>\n      </font>\n     </property>\n     <property name=\"focusPolicy\">\n      <enum>Qt::StrongFocus</enum>\n     </property>\n     <property name=\"frameShape\">\n      <enum>QFrame::NoFrame</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Plain</enum>\n     </property>\n     <property name=\"lineWidth\">\n      <number>0</number>\n     </property>\n     <property name=\"horizontalScrollBarPolicy\">\n      <enum>Qt::ScrollBarAlwaysOff</enum>\n     </property>\n     <property name=\"editTriggers\">\n      <set>QAbstractItemView::NoEditTriggers</set>\n     </property>\n     <property name=\"showDropIndicator\" stdset=\"0\">\n      <bool>false</bool>\n     </property>\n     <property name=\"selectionMode\">\n      <enum>QAbstractItemView::NoSelection</enum>\n     </property>\n     <property name=\"indentation\">\n      <number>13</number>\n     </property>\n     <property name=\"expandsOnDoubleClick\">\n      <bool>false</bool>\n     </property>\n     <column>\n      <property name=\"text\">\n       <string notr=\"true\">1</string>\n      </property>\n     </column>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMWindow.cpp",
    "content": "//\n//  QtSLiMWindow.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMWindow.h\"\n#include \"ui_QtSLiMWindow.h\"\n#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMFindPanel.h\"\n#include \"QtSLiMHelpWindow.h\"\n#include \"QtSLiMEidosConsole.h\"\n#include \"QtSLiMVariableBrowser.h\"\n#include \"QtSLiMDebugOutputWindow.h\"\n#include \"QtSLiMTablesDrawer.h\"\n#include \"QtSLiMScriptTextEdit.h\"\n#include \"QtSLiM_SLiMgui.h\"\n\n#include \"QtSLiMGraphView.h\"\n#include \"QtSLiMGraphView_1DPopulationSFS.h\"\n#include \"QtSLiMGraphView_1DSampleSFS.h\"\n#include \"QtSLiMGraphView_2DPopulationSFS.h\"\n#include \"QtSLiMGraphView_2DSampleSFS.h\"\n#include \"QtSLiMGraphView_LossTimeHistogram.h\"\n#include \"QtSLiMGraphView_FixationTimeHistogram.h\"\n#include \"QtSLiMGraphView_AgeDistribution.h\"\n#include \"QtSLiMGraphView_LifetimeReproduction.h\"\n#include \"QtSLiMGraphView_PopulationVisualization.h\"\n#include \"QtSLiMGraphView_FitnessOverTime.h\"\n#include \"QtSLiMGraphView_PopSizeOverTime.h\"\n#include \"QtSLiMGraphView_FrequencyTrajectory.h\"\n#include \"QtSLiMGraphView_PopFitnessDist.h\"\n#include \"QtSLiMGraphView_SubpopFitnessDists.h\"\n#include \"QtSLiMGraphView_MultispeciesPopSizeOverTime.h\"\n#include \"QtSLiMHaplotypeManager.h\"\n#include \"QtSLiMGraphView_CustomPlot.h\"\n\n#include <QCoreApplication>\n#include <QFontDatabase>\n#include <QFontMetricsF>\n#include <QtDebug>\n#include <QMessageBox>\n#include <QPlainTextEdit>\n#include <QCursor>\n#include <QPalette>\n#include <QFileDialog>\n#include <QSettings>\n#include <QCheckBox>\n#include <QCloseEvent>\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n#include <QDesktopWidget>\n#endif\n#include <QStandardPaths>\n#include <QToolTip>\n#include <QHBoxLayout>\n#include <QVBoxLayout>\n#include <QSplitter>\n#include <QFileSystemWatcher>\n#include <QClipboard>\n#include <QProcess>\n#include <QDesktopServices>\n#include <QScreen>\n#include <QMetaMethod>\n#include <QLabel>\n#include <QActionGroup>\n\n#include <unistd.h>\n#include <sys/stat.h>\n\n#include <utility>\n#include <map>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"individual.h\"\n#include \"eidos_test.h\"\n#include \"slim_test.h\"\n#include \"log_file.h\"\n\n#ifdef _OPENMP\n#error Building SLiMgui to run in parallel is not currently supported.\n#endif\n\n\n// This allows us to use Qt::QueuedConnection with EidosErrorContext\nQ_DECLARE_METATYPE(EidosErrorContext)\nstatic int EidosErrorContext_metatype_id = qRegisterMetaType<EidosErrorContext>();\n\n\nstatic std::string defaultWFScriptString(void)\n{\n    return std::string(\n                \"// set up a simple neutral simulation\\n\"\n                \"initialize() {\\n\"\n                \"\tinitializeMutationRate(1e-7);\\n\"\n                \"\t\\n\"\n                \"\t// m1 mutation type: neutral\\n\"\n                \"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n                \"\t\\n\"\n                \"\t// g1 genomic element type: uses m1 for all mutations\\n\"\n                \"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n                \"\t\\n\"\n                \"\t// uniform chromosome of length 100 kb with uniform recombination\\n\"\n                \"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n                \"\tinitializeRecombinationRate(1e-8);\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// create a population of 500 individuals\\n\"\n                \"1 early() {\\n\"\n                \"\tsim.addSubpop(\\\"p1\\\", 500);\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// output samples of 10 haplosomes periodically, all fixed mutations at end\\n\"\n                \"1000 late() { p1.outputSample(10); }\\n\"\n                \"2000 late() { p1.outputSample(10); }\\n\"\n                \"2000 late() { sim.outputFixedMutations(); }\\n\");\n}\n\nstatic std::string defaultWFScriptString_NC(void)\n{\n    return std::string(\n        \"initialize() {\\n\"\n        \"\tinitializeMutationRate(1e-7);\\n\"\n        \"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n        \"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n        \"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n        \"\tinitializeRecombinationRate(1e-8);\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"1 early() {\\n\"\n        \"\tsim.addSubpop(\\\"p1\\\", 500);\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"2000 late() { sim.outputFixedMutations(); }\\n\");\n}\n\nstatic std::string defaultNonWFScriptString(void)\n{\n    return std::string(\n                \"// set up a simple neutral nonWF simulation\\n\"\n                \"initialize() {\\n\"\n                \"\tinitializeSLiMModelType(\\\"nonWF\\\");\\n\"\n                \"\tdefineConstant(\\\"K\\\", 500);\t// carrying capacity\\n\"\n                \"\t\\n\"\n                \"\t// neutral mutations, which are allowed to fix\\n\"\n                \"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n                \"\tm1.convertToSubstitution = T;\\n\"\n                \"\t\\n\"\n                \"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n                \"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n                \"\tinitializeMutationRate(1e-7);\\n\"\n                \"\tinitializeRecombinationRate(1e-8);\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// each individual reproduces itself once\\n\"\n                \"reproduction() {\\n\"\n                \"\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// create an initial population of 10 individuals\\n\"\n                \"1 early() {\\n\"\n                \"\tsim.addSubpop(\\\"p1\\\", 10);\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// provide density-dependent selection\\n\"\n                \"early() {\\n\"\n                \"\tp1.fitnessScaling = K / p1.individualCount;\\n\"\n                \"}\\n\"\n                \"\\n\"\n                \"// output all fixed mutations at end\\n\"\n                \"2000 late() { sim.outputFixedMutations(); }\\n\");\n}\n\nstatic std::string defaultNonWFScriptString_NC(void)\n{\n    return std::string(\n        \"initialize() {\\n\"\n        \"\tinitializeSLiMModelType(\\\"nonWF\\\");\\n\"\n        \"\tdefineConstant(\\\"K\\\", 500);\\n\"\n        \"\t\\n\"\n        \"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n        \"\tm1.convertToSubstitution = T;\\n\"\n        \"\t\\n\"\n        \"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n        \"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n        \"\tinitializeMutationRate(1e-7);\\n\"\n        \"\tinitializeRecombinationRate(1e-8);\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"reproduction() {\\n\"\n        \"\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"1 early() {\\n\"\n        \"\tsim.addSubpop(\\\"p1\\\", 10);\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"early() {\\n\"\n        \"\tp1.fitnessScaling = K / p1.individualCount;\\n\"\n        \"}\\n\"\n        \"\\n\"\n        \"2000 late() { sim.outputFixedMutations(); }\\n\");\n}\n\n\nQtSLiMWindow::QtSLiMWindow(QtSLiMWindow::ModelType modelType, bool includeComments) : QMainWindow(nullptr), ui(new Ui::QtSLiMWindow)\n{\n    init();\n    setCurrentFile(QString());\n    \n    // set up the initial script\n    std::string untitledScriptString;\n    if (includeComments)\n        untitledScriptString = (modelType == QtSLiMWindow::ModelType::WF) ? defaultWFScriptString() : defaultNonWFScriptString();\n    else\n        untitledScriptString = (modelType == QtSLiMWindow::ModelType::WF) ? defaultWFScriptString_NC() : defaultNonWFScriptString_NC();\n    \n    lastSavedString = QString::fromStdString(untitledScriptString);\n    lastSavedDate = QDateTime::currentDateTime();\n    scriptChangeObserved = false;\n    \n    ui->scriptTextEdit->setPlainText(lastSavedString);\n    \n    if (consoleController)\n        consoleController->invalidateSymbolTableAndFunctionMap();\n    \n    setScriptStringAndInitializeSimulation(untitledScriptString);\n    \n    if (consoleController)\n        consoleController->validateSymbolTableAndFunctionMap();\n    \n    // Update all our UI to reflect the current state of the simulation\n    updateAfterTickFull(true);\n    resetSLiMChangeCount();     // no recycle change count; the current model is correct\n    setWindowModified(false);    // untitled windows consider themselves unmodified\n}\n\nQtSLiMWindow::QtSLiMWindow(const QString &fileName) : QMainWindow(nullptr), ui(new Ui::QtSLiMWindow)\n{\n    init();\n    loadFile(fileName);\n}\n\nQtSLiMWindow::QtSLiMWindow(const QString &recipeName, const QString &recipeScript) : QMainWindow(nullptr), ui(new Ui::QtSLiMWindow)\n{\n    init();\n    setCurrentFile(QString());\n    setWindowFilePath(recipeName);\n    isRecipe = true;\n    isTransient = false;\n    \n    // set up the initial script\n    lastSavedString = recipeScript;\n    lastSavedDate = QDateTime::currentDateTime();\n    scriptChangeObserved = false;\n    \n    ui->scriptTextEdit->setPlainText(recipeScript);\n    setScriptStringAndInitializeSimulation(recipeScript.toUtf8().constData());\n    \n    // Update all our UI to reflect the current state of the simulation\n    updateAfterTickFull(true);\n    resetSLiMChangeCount();     // no recycle change count; the current model is correct\n    setWindowModified(false);    // untitled windows consider themselves unmodified\n}\n\nvoid QtSLiMWindow::init(void)\n{\n    // On macOS, we turn off the automatic quit on last window close, for Qt 5.15.2.\n    // However, Qt's treatment of the menu bar seems to be a bit buggy unless a main window exists.\n    // That main window can be hidden; it just needs to exist.  So here we just allow our main\n    // window(s) to leak,so that Qt is happy.  This sucks, obviously, but really it seems unlikely\n    // to matter.  The window will notice its zombified state when it is closed, and will free\n    // resources and mark itself as a zombie so it doesn't get included in the Window menu, etc.\n    // Builds against older Qt versions will just quit on the last window close, because\n    // QTBUG-86874 and QTBUG-86875 prevent this from working.\n#ifdef __APPLE__\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 2))\n    // no set of the attribute on Qt 5.15.2; we will *not* delete on close\n#else\n    setAttribute(Qt::WA_DeleteOnClose);\n#endif\n#else\n    setAttribute(Qt::WA_DeleteOnClose);\n#endif\n    isUntitled = true;\n    isRecipe = false;\n    \n    // create the window UI\n    ui->setupUi(this);\n    \n    // hide the species bar initially so it doesn't interfere with the sizing done by interpolateSplitters()\n    ui->speciesBarWidget->setHidden(true);\n    \n    ui->speciesBar->setAcceptDrops(false);\n    ui->speciesBar->setDocumentMode(false);\n    ui->speciesBar->setDrawBase(false);\n    ui->speciesBar->setExpanding(false);\n    ui->speciesBar->setMovable(false);\n    ui->speciesBar->setShape(QTabBar::RoundedNorth);\n    ui->speciesBar->setTabsClosable(false);\n    ui->speciesBar->setUsesScrollButtons(false);\n    \n    connect(ui->speciesBar, &QTabBar::currentChanged, this, &QtSLiMWindow::selectedSpeciesChanged);\n    \n    // add splitters with the species bar hidden; this sets correct heights on things\n    interpolateSplitters();\n    initializeUI();\n    \n    // with everything built, mark ourselves as transient (recipes and files will mark this false after us)\n    isTransient = true;\n    \n    // wire up our continuous play and tick play timers\n    connect(&continuousPlayInvocationTimer_, &QTimer::timeout, this, &QtSLiMWindow::_continuousPlay);\n    connect(&continuousProfileInvocationTimer_, &QTimer::timeout, this, &QtSLiMWindow::_continuousProfile);\n    connect(&playOneStepInvocationTimer_, &QTimer::timeout, this, &QtSLiMWindow::_playOneStep);\n    \n    // wire up deferred display of script errors and termination messages\n    connect(this, &QtSLiMWindow::terminationWithMessage, this, &QtSLiMWindow::showTerminationMessage, Qt::QueuedConnection);\n    \n    // forward option-clicks in our views to the help window\n    ui->scriptTextEdit->setOptionClickEnabled(true);\n    ui->outputTextEdit->setOptionClickEnabled(false);\n    \n    // the script textview completes, the output textview does not\n    ui->scriptTextEdit->setCodeCompletionEnabled(true);\n    ui->outputTextEdit->setCodeCompletionEnabled(false);\n    \n    // We set the working directory for new windows to ~/Desktop/, since it makes no sense for them to use the location of the app.\n    // Each running simulation will track its own working directory, and the user can set it with a button in the SLiMgui window.\n    // BCH 4/2/2020: Per request from PLR, we will now use the Desktop as the default directory only if we were launched by Finder\n    // or equivalent; if we were launched by a shell, we will use the working directory given us by that shell.  See issue #76\n    if (qtSLiMAppDelegate->launchedFromShell())\n        sim_working_dir = qtSLiMAppDelegate->QtSLiMCurrentWorkingDirectory();\n    else\n#ifdef _WIN32\n        sim_working_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();\n#else\n        sim_working_dir = Eidos_ResolvedPath(\"~/Desktop\");\n#endif\n    \n    // Check that our chosen working directory actually exists; if not, use ~\n    struct stat buffer;\n    \n    if (stat(sim_working_dir.c_str(), &buffer) != 0)\n#ifdef _WIN32\n        sim_working_dir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString();\n#else\n        sim_working_dir = Eidos_ResolvedPath(\"~\");\n#endif\n    \n    sim_requested_working_dir = sim_working_dir;\t// return to the working dir on recycle unless the user overrides it\n    \n    // Wire up things that set the window to be modified.\n    connect(ui->scriptTextEdit, &QPlainTextEdit::textChanged, this, &QtSLiMWindow::documentWasModified);\n    connect(ui->scriptTextEdit, &QPlainTextEdit::textChanged, this, &QtSLiMWindow::scriptTexteditChanged);\n    \n    // Watch for app activation to check for external modification of our file\n    connect(qApp, &QApplication::applicationStateChanged, this, &QtSLiMWindow::appStateChanged);\n    \n    // Watch for changes to the selection in the population tableview\n    connect(ui->subpopTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QtSLiMWindow::subpopSelectionDidChange);\n    \n    // Watch for changes to our change count, for the recycle button color\n    connect(this, &QtSLiMWindow::controllerChangeCountChanged, this, [this]() { updateRecycleButtonIcon(false); });\n    \n    // Ensure that the tick lineedit does not have the initial keyboard focus and has no selection; hard to do!\n    // BCH 5 August 2022: this code is no longer working, the tick lineedit still has initial focus, sigh; I added\n    // the call to ui->scriptTextEdit->setFocus() and that seems to do it, not sure why I didn't do that before;\n    // but since this seems to be fragile, I'm going to leave *both* approaches in the code here, maybe which\n    // approach works depends on the Qt version or the platform or something.  Forward in all directions!\n    ui->tickLineEdit->setFocusPolicy(Qt::FocusPolicy::NoFocus);\n    QTimer::singleShot(0, this, [this]() { ui->tickLineEdit->setFocusPolicy(Qt::FocusPolicy::StrongFocus); });\n    ui->scriptTextEdit->setFocus();\n    \n    // watch for a change to light mode / dark mode, to customize display of the play speed slider for example\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::applicationPaletteChanged, this, &QtSLiMWindow::applicationPaletteChanged);\n    applicationPaletteChanged();\n    \n    // Instantiate the help panel up front so that it responds instantly; slows down our launch, but it seems better to me...\n    QtSLiMHelpWindow::instance();\n    \n\t// Allocate a RNG temporarily, so it exists when we create the console controller and run self-tests\n    // This is just for the duration of this init() method; we will tear it down again below\n    if (!sim_RNG_initialized)\n    {\n        _Eidos_InitializeOneRNG(sim_RNG);\n        sim_RNG_initialized = true;\n    }\n    \n    // Create our console window; we want one all the time, so that it keeps live symbols for code completion for us\n    if (!consoleController)\n    {\n        consoleController = new QtSLiMEidosConsole(this);\n        if (consoleController)\n        {\n            // wire ourselves up to monitor the console for closing, to fix our button state\n            connect(consoleController, &QtSLiMEidosConsole::willClose, this, [this]() {\n                ui->consoleButton->setChecked(false);\n                showConsoleReleased();\n            });\n        }\n        else\n        {\n            qDebug() << \"Could not create console controller\";\n        }\n    }\n    \n    // Create our debug output window; we want one all the time, so we can log to it\n    debugOutputWindow_ = new QtSLiMDebugOutputWindow(this);\n    \n    connect(&debugButtonFlashTimer_, &QTimer::timeout, this, &QtSLiMWindow::handleDebugButtonFlash);\n    \n    // We need to update our button/menu enable state whenever the focus or the active window changes\n    connect(qApp, &QApplication::focusChanged, this, &QtSLiMWindow::updateUIEnabling);\n    connect(qtSLiMAppDelegate, &QtSLiMAppDelegate::activeWindowListChanged, this, &QtSLiMWindow::updateUIEnabling);\n    \n    // We also do it specifically when the Edit menu is about to show, to correctly validate undo/redo in all cases\n    // Note that it is not simple to do this revalidation when a keyboard shortcut is pressed, but happily (?), Qt\n    // ignores the action validation state in that case anyway; undo/redo is delivered even if the action is disabled\n    connect(ui->menuEdit, &QMenu::aboutToShow, this, &QtSLiMWindow::updateUIEnabling);\n    \n    // And also when about to show the Graph menu, because the Create Haplotype Plot items might need tweaking\n    connect(ui->menuGraph, &QMenu::aboutToShow, this, &QtSLiMWindow::updateUIEnabling);\n    \n    // And also when about to show the Script menu, because the Show/Hide menu items might not be accurately named\n    connect(ui->menuScript, &QMenu::aboutToShow, this, &QtSLiMWindow::updateUIEnabling);\n    \n    // The app delegate wants to know our play state so it can change the app icon\n    connect(this, &QtSLiMWindow::playStateChanged, qtSLiMAppDelegate, &QtSLiMAppDelegate::playStateChanged);\n    \n    // Set the window icon, overriding the app icon\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    setWindowIcon(qtSLiMAppDelegate->slimDocumentIcon());\n#endif\n    \n    // Run self-tests if modifiers are down, if we are the first window opened\n    // Note that this alters the state of the app: mutation ids have been used, the RNG has been used,\n    // lots of objects have been leaked due to raises, etc.  So this should be hidden/optional/undocumented.\n    static bool beenHere = false;\n    \n    if (!beenHere)\n    {\n        bool optionPressed = QGuiApplication::queryKeyboardModifiers().testFlag(Qt::AltModifier);\n        bool shiftPressed = QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier);\n        \n        if (optionPressed && shiftPressed)\n        {\n            willExecuteScript();\n            \n            std::cerr << \"Running Eidos self-test...\" << std::endl;\n            RunEidosTests();\n            std::cerr << std::endl << std::endl;\n            std::cerr << \"Running SLiM self-test...\" << std::endl;\n            RunSLiMTests();\n            \n            didExecuteScript();\n        }\n        \n        beenHere = true;\n    }\n    \n    // Tear down the temporary RNG that we created above\n    if (sim_RNG_initialized)\n\t{\n\t\t_Eidos_FreeOneRNG(sim_RNG);\n\t\tsim_RNG_initialized = false;\n\t}\n}\n\nvoid QtSLiMWindow::interpolateVerticalSplitter(void)\n{\n    const int splitterMargin = 8;\n    QLayout *parentLayout = ui->centralWidget->layout();\n    QVBoxLayout *firstSubLayout = ui->overallTopLayout;\n    QHBoxLayout *secondSubLayout = ui->overallBottomLayout;\n    \n    // force geometry calculation, which is lazy\n    setAttribute(Qt::WA_DontShowOnScreen, true);\n    show();\n    hide();\n    setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // get the geometry we need\n    QSize firstSubSize = firstSubLayout->sizeHint();\n    QMargins marginsP = QMargins(8, 8, 8, 8); //parentLayout->contentsMargins();\n    QMargins marginsS1 = firstSubLayout->contentsMargins();\n    QMargins marginsS2 = secondSubLayout->contentsMargins();\n    \n    // change fixed-size views to be flexible, so they cooperate with the splitters\n    firstSubLayout->setStretch(0, 1);\n    ui->subpopTableView->setMaximumHeight(QWIDGETSIZE_MAX);\n    ui->individualsWidget->setMaximumHeight(QWIDGETSIZE_MAX);\n    ui->topRightLayout->setStretch(4, 1);\n#if !defined(__APPLE__)\n    ui->topRightLayout->setSpacing(3);  // a platform-dependent value that prevents a couple of pixels of \"play\" above the play speed slider, for reasons I don't understand\n#else\n    ui->topRightLayout->setSpacing(4);\n#endif\n    ui->playSpeedSlider->setFixedHeight(ui->playSpeedSlider->sizeHint().height());\n    \n    // empty out parentLayout\n    QLayoutItem *child;\n    while ((child = parentLayout->takeAt(0)) != nullptr);\n    \n    ui->topBottomDividerLine->setParent(nullptr);\n    ui->topBottomDividerLine = nullptr;\n    \n    // make the new top-level widgets and transfer in their contents\n    overallTopWidget = new QWidget(nullptr);\n    overallTopWidget->setLayout(firstSubLayout);\n    overallTopWidget->setMinimumHeight(firstSubSize.height() + (splitterMargin - 5));   // there is already 5 pixels of margin at the bottom of overallTopWidget due to layout details\n    firstSubLayout->setContentsMargins(QMargins(marginsS1.left() + marginsP.left(), marginsS1.top() + marginsP.top(), marginsS1.right() + marginsP.right(), marginsS1.bottom() + (splitterMargin - 5)));\n    \n    overallBottomWidget = new QWidget(nullptr);\n    overallBottomWidget->setLayout(secondSubLayout);\n    secondSubLayout->setContentsMargins(QMargins(marginsS2.left() + marginsP.left(), marginsS2.top() + splitterMargin, marginsS2.right() + marginsP.right(), marginsS2.bottom() + marginsP.bottom()));\n    \n    // make the QSplitter between the top and bottom and add the top-level widgets to it\n    overallSplitter = new QtSLiMSplitter(Qt::Vertical, this);\n    \n    overallSplitter->setChildrenCollapsible(true);\n    overallSplitter->addWidget(overallTopWidget);\n    overallSplitter->addWidget(overallBottomWidget);\n    overallSplitter->setHandleWidth(std::max(9, overallSplitter->handleWidth() + 3));   // ends up 9 on Ubuntu, 10 on macOS\n    overallSplitter->setStretchFactor(0, 1);\n    overallSplitter->setStretchFactor(1, 100);    // initially, give all height to the bottom widget\n    \n    // and finally, add the splitter to the parent layout\n    parentLayout->addWidget(overallSplitter);\n    parentLayout->setContentsMargins(0, 0, 0, 0);\n}\n\nvoid QtSLiMWindow::interpolateHorizontalSplitter(void)\n{\n    const int splitterMargin = 8;\n    QLayout *parentLayout = overallBottomWidget->layout();\n    QVBoxLayout *firstSubLayout = ui->scriptLayout;\n    QVBoxLayout *secondSubLayout = ui->outputLayout;\n    \n    // force geometry calculation, which is lazy\n    setAttribute(Qt::WA_DontShowOnScreen, true);\n    show();\n    hide();\n    setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // get the geometry we need\n    QMargins marginsP = parentLayout->contentsMargins();\n    QMargins marginsS1 = firstSubLayout->contentsMargins();\n    QMargins marginsS2 = secondSubLayout->contentsMargins();\n    \n    // empty out parentLayout\n    QLayoutItem *child;\n    while ((child = parentLayout->takeAt(0)) != nullptr);\n    \n    // make the new top-level widgets and transfer in their contents\n    scriptWidget = new QWidget(nullptr);\n    scriptWidget->setLayout(firstSubLayout);\n    firstSubLayout->setContentsMargins(QMargins(marginsS1.left() + marginsP.left(), marginsS1.top() + marginsP.top(), marginsS1.right() + splitterMargin, marginsS1.bottom() + marginsP.bottom()));\n    \n    outputWidget = new QWidget(nullptr);\n    outputWidget->setLayout(secondSubLayout);\n    secondSubLayout->setContentsMargins(QMargins(marginsS2.left() + splitterMargin, marginsS2.top() + marginsP.top(), marginsS2.right() + marginsP.right(), marginsS2.bottom() + marginsP.bottom()));\n    \n    // make the QSplitter between the left and right and add the subsidiary widgets to it\n    bottomSplitter = new QtSLiMSplitter(Qt::Horizontal, this);\n    \n    bottomSplitter->setChildrenCollapsible(true);\n    bottomSplitter->addWidget(scriptWidget);\n    bottomSplitter->addWidget(outputWidget);\n    bottomSplitter->setHandleWidth(std::max(9, bottomSplitter->handleWidth() + 3));   // ends up 9 on Ubuntu, 10 on macOS\n    bottomSplitter->setStretchFactor(0, 2);\n    bottomSplitter->setStretchFactor(1, 1);    // initially, give 2/3 of the width to the script widget\n    \n    // and finally, add the splitter to the parent layout\n    parentLayout->addWidget(bottomSplitter);\n    parentLayout->setContentsMargins(0, 0, 0, 0);\n}\n\nvoid QtSLiMWindow::interpolateSplitters(void)\n{\n#if 1\n    // This case is hit if splitters are enabled; it adds a top-level vertical splitter and a subsidiary horizontal splitter\n    // We do this at runtime, rather than in QtSLiMWindow.ui, to preserve the non-splitter option, and because the required\n    // alterations are complex and depend upon the (platform-dependent) initial calculated sizes of the various elements\n    interpolateVerticalSplitter();\n    interpolateHorizontalSplitter();\n#else\n    // This case is hit if splitters are disabled; it does a little cleanup of elements that exist to support the splitters\n    ui->topRightLayout->removeItem(ui->playControlsSpacerExpanding);\n    delete ui->playControlsSpacerExpanding;\n    ui->playControlsSpacerExpanding = nullptr;\n#endif\n}\n\nvoid QtSLiMWindow::addChromosomeWidgets(QVBoxLayout *chromosomeLayout, QtSLiMChromosomeWidget *overviewWidget, QtSLiMChromosomeWidget *zoomedWidget)\n{\n    if (!chromosomeConfig)\n        chromosomeConfig = new QtSLiMChromosomeWidgetController(this, nullptr, nullptr, \"\");\n    \n    overviewWidget->setController(chromosomeConfig);\n\toverviewWidget->setDependentChromosomeView(zoomedWidget);\n\t\n    zoomedWidget->setController(chromosomeConfig);\n\tzoomedWidget->setDependentChromosomeView(nullptr);\n    \n    // Add these widgets to our vectors of chromosome widgets\n    chromosomeWidgetLayouts.push_back(chromosomeLayout);\n    chromosomeOverviewWidgets.push_back(overviewWidget);\n    chromosomeZoomedWidgets.push_back(zoomedWidget);\n}\n\nvoid QtSLiMWindow::initializeUI(void)\n{\n    glueUI();\n    \n    // fix the layout of the window\n    ui->scriptHeaderLayout->setSpacing(4);\n    ui->scriptHeaderLayout->setContentsMargins(0, 0, 0, 0);\n    ui->scriptHeaderLabel->setContentsMargins(8, 0, 15, 0);\n\n    ui->outputHeaderLayout->setSpacing(4);\n    ui->outputHeaderLayout->setContentsMargins(0, 0, 0, 0);\n    ui->outputHeaderLabel->setContentsMargins(8, 0, 15, 0);\n\n    ui->playControlsLayout->setSpacing(8);\n    ui->playControlsLayout->setContentsMargins(0, 0, 0, 0);\n    \n    // substitute a custom layout subclass for playControlsLayout to lay out the profile button specially\n    {\n        int indexOfPlayControlsLayout = -1;\n        \n        // QLayout::indexOf(QLayoutItem *layoutItem) wasn't added until 5.12, oddly\n        for (int i = 0; i < ui->topRightLayout->count(); ++i)\n            if (ui->topRightLayout->itemAt(i) == ui->playControlsLayout)\n                indexOfPlayControlsLayout = i;\n        \n        if (indexOfPlayControlsLayout >= 0)\n        {\n            QtSLiMPlayControlsLayout *newPlayControlsLayout = new QtSLiMPlayControlsLayout();\n            ui->topRightLayout->insertItem(indexOfPlayControlsLayout, newPlayControlsLayout);\n            newPlayControlsLayout->setParent(ui->topRightLayout);   // surprising that insertItem() doesn't do this...; but this sets our parentWidget also, correctly\n            \n            // Transfer over the contents of the old layout\n            while (ui->playControlsLayout->count())\n            {\n                QLayoutItem *layoutItem = ui->playControlsLayout->takeAt(0);\n                newPlayControlsLayout->addItem(layoutItem);\n            }\n            \n            // Transfer properties of the old layout\n            newPlayControlsLayout->setSpacing(ui->playControlsLayout->spacing());\n            newPlayControlsLayout->setContentsMargins(ui->playControlsLayout->contentsMargins());\n            \n            // Get rid of the old layout\n            ui->topRightLayout->removeItem(ui->playControlsLayout);\n            ui->playControlsLayout = nullptr;\n            \n            // Remember the new layout\n            ui->playControlsLayout = newPlayControlsLayout;\n        }\n        else\n        {\n            qDebug() << \"Couldn't find playControlsLayout!\";\n        }\n    }\n    \n    // set the script types and syntax highlighting appropriately\n    ui->scriptTextEdit->setScriptType(QtSLiMTextEdit::SLiMScriptType);\n    ui->scriptTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::ScriptHighlighting);\n    \n    ui->outputTextEdit->setScriptType(QtSLiMTextEdit::NoScriptType);\n    ui->outputTextEdit->setSyntaxHighlightType(QtSLiMTextEdit::OutputHighlighting);\n    \n    // set up the script block label, to the right of the Jump menu\n    QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n    \n    connect(&prefsNotifier, &QtSLiMPreferencesNotifier::displayFontPrefChanged, this, &QtSLiMWindow::displayFontPrefChanged);\n    displayFontPrefChanged();\n    \n    // set button states\n    ui->toggleDrawerButton->setChecked(false);\n    \n    // Set up the population table view\n    populationTableModel_ = new QtSLiMPopulationTableModel(this);\n    ui->subpopTableView->setModel(populationTableModel_);\n    ui->subpopTableView->setHorizontalHeader(new QtSLiMPopulationTableHeaderView(Qt::Orientation::Horizontal, this));\n    \n    QHeaderView *popTableHHeader = ui->subpopTableView->horizontalHeader();\n    QHeaderView *popTableVHeader = ui->subpopTableView->verticalHeader();\n    \n    popTableHHeader->setMinimumSectionSize(1);\n    popTableVHeader->setMinimumSectionSize(1);\n    \n    popTableHHeader->resizeSection(0, 65);\n    //popTableHHeader->resizeSection(1, 60);\n    popTableHHeader->resizeSection(2, 40);\n    popTableHHeader->resizeSection(3, 40);\n    popTableHHeader->resizeSection(4, 40);\n    popTableHHeader->resizeSection(5, 40);\n    popTableHHeader->setSectionsClickable(false);\n    popTableHHeader->setSectionsMovable(false);\n    popTableHHeader->setSectionResizeMode(0, QHeaderView::Fixed);\n    popTableHHeader->setSectionResizeMode(1, QHeaderView::Stretch);\n    popTableHHeader->setSectionResizeMode(2, QHeaderView::Fixed);\n    popTableHHeader->setSectionResizeMode(3, QHeaderView::Fixed);\n    popTableHHeader->setSectionResizeMode(4, QHeaderView::Fixed);\n    popTableHHeader->setSectionResizeMode(5, QHeaderView::Fixed);\n    \n    QFont headerFont = popTableHHeader->font();\n    QFont cellFont = ui->subpopTableView->font();\n#ifdef __linux__\n    headerFont.setPointSize(8);\n    cellFont.setPointSize(8);\n#else\n    headerFont.setPointSize(11);\n    cellFont.setPointSize(11);\n#endif\n    popTableHHeader->setFont(headerFont);\n    ui->subpopTableView->setFont(cellFont);\n    \n    popTableVHeader->setSectionResizeMode(QHeaderView::Fixed);\n    popTableVHeader->setDefaultSectionSize(18);\n    \n    // Set up our built-in chromosome widgets; this should be the only place these ui outlets are used!\n    addChromosomeWidgets(ui->chromosomeWidgetLayout, ui->chromosomeOverview, ui->chromosomeZoomed);\n    \n    // Restore the saved window position; see https://doc.qt.io/qt-5/qsettings.html#details\n    QSettings settings;\n    \n    settings.beginGroup(\"QtSLiMMainWindow\");\n    resize(settings.value(\"size\", QSize(950, 700)).toSize());\n    move(settings.value(\"pos\", QPoint(100, 100)).toPoint());\n    settings.endGroup();\n    \n    // Ask the app delegate to handle the recipes menu for us\n    qtSLiMAppDelegate->setUpRecipesMenu(ui->menuOpenRecipe, ui->actionFindRecipe);\n    \n    // Likewise for the recent documents menu\n    QMenu *recentMenu = new QMenu(\"Open Recent\", this);\n    ui->actionOpenRecent->setMenu(recentMenu);\n    \n    qtSLiMAppDelegate->setUpRecentsMenu(recentMenu);\n    \n    // Set up the Window menu, which updates on demand\n    connect(ui->menuWindow, &QMenu::aboutToShow, this, &QtSLiMWindow::updateWindowMenu);\n}\n\nvoid QtSLiMWindow::displayFontPrefChanged(void)\n{\n    // Xcode doesn't use its monospace for this, and it does look a bit out of place in the UI\n    // So let's try it allowing the font to remain the default system font...?\n//    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n//    QFont displayFont = prefs.displayFontPref(nullptr);\n    \n//    displayFont.setPointSize(13);\n//    ui->scriptBlockLabel->setFont(displayFont);\n}\n\nvoid QtSLiMWindow::applicationPaletteChanged(void)\n{\n    bool inDarkMode = QtSLiMInDarkMode();\n    \n    // Custom colors for the play slider; note that this completely overrides the style sheet in the .ui file!\n    if (inDarkMode)\n    {\n        ui->playSpeedSlider->setStyleSheet(\n                    R\"V0G0N(\n                    QSlider::groove:horizontal {\n                        border: 1px solid #606060;\n                        border-radius: 1px;\n                        height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n                        background: #808080;\n                        margin: 2px 0;\n                    }\n                    QSlider::groove:horizontal:disabled {\n                        border: 1px solid #505050;\n                        border-radius: 1px;\n                        height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n                        background: #606060;\n                        margin: 2px 0;\n                    }\n                    \n                    QSlider::handle:horizontal {\n                        background: #f0f0f0;\n                        border: 1px solid #b0b0b0;\n                        width: 8px;\n                        margin: -4px 0;\n                        border-radius: 4px;\n                    }\n                    QSlider::handle:horizontal:disabled {\n                        background: #606060;\n                        border: 1px solid #505050;\n                        width: 8px;\n                        margin: -4px 0;\n                        border-radius: 4px;\n                    })V0G0N\");\n    }\n    else\n    {\n        ui->playSpeedSlider->setStyleSheet(\n                    R\"V0G0N(\n                    QSlider::groove:horizontal {\n                        border: 1px solid #888888;\n                        border-radius: 1px;\n                        height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n                        background: #a0a0a0;\n                        margin: 2px 0;\n                    }\n                    QSlider::groove:horizontal:disabled {\n                        border: 1px solid #cccccc;\n                        border-radius: 1px;\n                        height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n                        background: #e0e0e0;\n                        margin: 2px 0;\n                    }\n                    \n                    QSlider::handle:horizontal {\n                        background: #ffffff;\n                        border: 1px solid #909090;\n                        width: 8px;\n                        margin: -4px 0;\n                        border-radius: 4px;\n                    }\n                    QSlider::handle:horizontal:disabled {\n                        background: #ffffff;\n                        border: 1px solid #d0d0d0;\n                        width: 8px;\n                        margin: -4px 0;\n                        border-radius: 4px;\n                    })V0G0N\");\n    }\n}\n\nvoid QtSLiMWindow::displayStartupMessage(void)\n{\n    // Set the initial status bar message; called by QtSLiMAppDelegate::appDidFinishLaunching()\n    bool inDarkMode = QtSLiMInDarkMode();\n    QString message(inDarkMode ? \"<font color='#AAAAAA' style='font-size: 11px;'>SLiM %1, %2 build.</font>\"\n                               : \"<font color='#555555' style='font-size: 11px;'>SLiM %1, %2 build.</font>\");\n    \n    ui->statusBar->showMessage(message.arg(QString(SLIM_VERSION_STRING)).arg(\n#if DEBUG\n                                   \"debug\"\n#else\n                                   \"release\"\n#endif\n                                   ));    \n}\n\nQtSLiMScriptTextEdit *QtSLiMWindow::scriptTextEdit(void)\n{\n    return ui->scriptTextEdit;\n}\n\nQtSLiMTextEdit *QtSLiMWindow::outputTextEdit(void)\n{\n    return ui->outputTextEdit;\n}\n\nQtSLiMWindow::~QtSLiMWindow()\n{\n    // Do this first, in case it uses any ivars that will be freed\n    setInvalidSimulation(true);\n    \n    // Disconnect our connections having to do with focus changes, since they can fire\n    // during our destruction while we are in an invalid state\n    disconnect(qApp, QMetaMethod(), this, QMetaMethod());\n    disconnect(qtSLiMAppDelegate, QMetaMethod(), this, QMetaMethod());\n    \n    // Then tear down the UI\n    delete ui;\n\n    // Disconnect delegate relationships\n    if (consoleController)\n        consoleController->parentSLiMWindow = nullptr;\n    \n    // Free resources\n    if (community)\n    {\n        delete community;\n        community = nullptr;\n        focalSpecies = nullptr;\n    }\n    if (slimgui)\n\t{\n\t\tdelete slimgui;\n\t\tslimgui = nullptr;\n\t}\n\t\n\tif (sim_RNG_initialized)\n\t{\n    \t_Eidos_FreeOneRNG(sim_RNG);\n    \tsim_RNG_initialized = false;\n\t}\n\t\n    // The console is owned by us, and it owns the variable browser.  Since the parent\n    // relationships are set up, they should be released by Qt automatically.\n    if (consoleController)\n    {\n        //if (consoleController->browserController)\n        //  consoleController->browserController->hide();\n        consoleController->hide();\n    }\n}\n\nvoid QtSLiMWindow::invalidateUI(void)\n{\n    // This is called only on macOS, when a window closes.  We can't be deleted, because\n    // that screws up the global menu bar.  Instead, we need to go into a zombie state,\n    // by freeing up our graph windows, console, etc., but remain allocated (but hidden).\n    // The main goal is erasing all traces of us in the user interface; freeing the\n    // maximal amount of memory is less of a concern, since we're not talking about\n    // that much memory anyway.\n    \n    // First set a flag indicating that we're going into zombie mode\n    isZombieWindow_ = true;\n    \n    // Set some other state to prevent ourselves from being reused in any way\n    isUntitled = false;\n    isTransient = false;\n    currentFile = \"ZOMBIE ZOMBIE ZOMBIE ZOMBIE ZOMBIE\";\n    \n    // Stop all timers, so we don't try to play in the background\n    continuousPlayElapsedTimer_.invalidate();\n    continuousPlayInvocationTimer_.stop();\n    continuousProfileInvocationTimer_.stop();\n    playOneStepInvocationTimer_.stop();\n    \n    continuousPlayOn_ = false;\n    profilePlayOn_ = false;\n    nonProfilePlayOn_ = false;\n    tickPlayOn_ = false;\n    \n    // Recycle to throw away any bulky simulation state; set the default script first to avoid errors\n    // Note that this creates a species named \"sim\" even if the window being closed was multispecies!\n    ui->scriptTextEdit->setPlainText(QString::fromStdString(defaultWFScriptString()));\n    recycleClicked();\n    \n    // Close the variable browser and Eidos console\n    if (consoleController)\n    {\n        QtSLiMVariableBrowser *browser = consoleController->variableBrowser();\n        \n        if (browser)\n            browser->close();\n        \n        consoleController->close();\n    }\n    \n    // Close the tables drawer\n    if (tablesDrawerController)\n        tablesDrawerController->close();\n    \n    // Close all other subsidiary windows\n    const QObjectList &child_objects = children();\n    \n    for (QObject *child_object : child_objects)\n    {\n        QWidget *child_widget = qobject_cast<QWidget *>(child_object);\n        \n        if (child_widget && child_widget->isVisible() && (child_widget->windowFlags() & Qt::Window))\n            child_widget->close();\n    }\n}\n\nQtSLiMGraphView *QtSLiMWindow::graphViewWithTitle(QString title)\n{\n    // This searches through our child views for a graph window with the requested title\n    const QObjectList &child_objects = children();\n    \n    for (QObject *child_object : child_objects)\n    {\n        QWidget *child_widget = qobject_cast<QWidget *>(child_object);\n        \n        if (child_widget && child_widget->isVisible() && (child_widget->windowFlags() & Qt::Window))\n        {\n            QtSLiMGraphView *graphView = graphViewForGraphWindow(child_widget);\n            \n            if (graphView && (graphView->graphTitle() == title))\n                return graphView;\n        }\n    }\n    \n    return nullptr;\n}\n\nint QtSLiMWindow::graphViewCount(void)\n{\n    // This searches through our child views for graph windows and returns a count\n    int count = 0;\n    \n    const QObjectList &child_objects = children();\n    \n    for (QObject *child_object : child_objects)\n    {\n        QWidget *child_widget = qobject_cast<QWidget *>(child_object);\n        \n        if (child_widget && child_widget->isVisible() && (child_widget->windowFlags() & Qt::Window))\n        {\n            QtSLiMGraphView *graphView = graphViewForGraphWindow(child_widget);\n            \n            if (graphView)\n                count++;\n        }\n    }\n    \n    return count;\n}\n\nconst QColor &QtSLiMWindow::blackContrastingColorForIndex(int index)\n{\n    static std::vector<QColor> colorArray;\n\t\n\tif (colorArray.size() == 0)\n\t{\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.65, 0.65, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.55, 1.00, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.40, 1.00, 0.90, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.16, 1.00, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.08, 0.65, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.00, 0.65, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.80, 0.65, 1.00, 1.0));\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.00, 0.00, 0.80, 1.0));\n\t}\n\t\n    return ((index >= 0) && (index <= 6)) ? colorArray[static_cast<size_t>(index)] : colorArray[7];\n}\n\nconst QColor &QtSLiMWindow::whiteContrastingColorForIndex(int index)\n{\n    static std::vector<QColor> colorArray;\n    \n    if (colorArray.size() == 0)\n    {\n        colorArray.emplace_back(QtSLiMColorWithHSV(0.65, 0.75, 1.00, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.55, 1.00, 1.00, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.40, 1.00, 0.80, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.08, 0.75, 1.00, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.00, 0.85, 1.00, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.80, 0.85, 1.00, 1.0));\n\t\tcolorArray.emplace_back(QtSLiMColorWithHSV(0.00, 0.00, 0.50, 1.0));\n    }\n    \n    return ((index >= 0) && (index <= 5)) ? colorArray[static_cast<size_t>(index)] : colorArray[6];\n}\n\nvoid QtSLiMWindow::colorForGenomicElementType(GenomicElementType *elementType, slim_objectid_t elementTypeID, float *p_red, float *p_green, float *p_blue, float *p_alpha)\n{\n\tif (elementType && !elementType->color_.empty())\n\t{\n        *p_red = elementType->color_red_;\n        *p_green = elementType->color_green_;\n        *p_blue = elementType->color_blue_;\n        *p_alpha = 1.0f;\n\t}\n\telse\n\t{\n        auto elementColorIter = genomicElementColorRegistry.find(elementTypeID);\n\t\tconst QColor *elementColor = nullptr;\n        \n\t\tif (elementColorIter == genomicElementColorRegistry.end())\n\t\t{\n\t\t\telementColor = &QtSLiMWindow::blackContrastingColorForIndex(static_cast<int>(genomicElementColorRegistry.size()));\n            \n            genomicElementColorRegistry.emplace(elementTypeID, *elementColor);\n\t\t}\n        else\n        {\n            elementColor = &elementColorIter->second;\n        }\n\t\t\n        *p_red = static_cast<float>(elementColor->redF());\n        *p_green = static_cast<float>(elementColor->greenF());\n        *p_blue = static_cast<float>(elementColor->blueF());\n        *p_alpha = static_cast<float>(elementColor->alphaF());\n\t}\n}\n\nQColor QtSLiMWindow::qcolorForSpecies(Species *species)\n{\n    if (species->color_.length() > 0)\n        return QtSLiMColorWithRGB(species->color_red_, species->color_green_, species->color_blue_, 1.0);\n    \n    return whiteContrastingColorForIndex(species->species_id_);\n}\n\nvoid QtSLiMWindow::colorForSpecies(Species *species, float *p_red, float *p_green, float *p_blue, float *p_alpha)\n{\n    if (species->color_.length() > 0)\n    {\n        *p_red = species->color_red_;\n        *p_green = species->color_green_;\n        *p_blue = species->color_blue_;\n        *p_alpha = 1.0;\n        return;\n    }\n    \n    const QColor &speciesColor = whiteContrastingColorForIndex(species->species_id_);\n    \n    *p_red = static_cast<float>(speciesColor.redF());\n    *p_green = static_cast<float>(speciesColor.greenF());\n    *p_blue = static_cast<float>(speciesColor.blueF());\n    *p_alpha = static_cast<float>(speciesColor.alphaF());\n}\n\n\n//\n//  Document support\n//\n\nvoid QtSLiMWindow::closeEvent(QCloseEvent *p_event)\n{\n    if (maybeSave())\n    {\n        // We used to save the window size/position here, but now that is done in moveEvent() / resizeEvent()\n        p_event->accept();\n        \n        // In case we are playing when we get closed, emit a signal to un-highlight the app icon\n        if (continuousPlayOn_)\n        {\n            continuousPlayOn_ = false;\n            //updateUIEnabling();           // not needed, the window is going away anyway\n            emit playStateChanged();\n        }\n        \n        // On macOS, we turn off the automatic quit on last window close, for Qt 5.15.2.\n        // In that case, we no longer get freed when we close, because we need to stick around\n        // to make the global menubar work; see QtSLiMWindow::init().  So when we're closing,\n        // we now free up the resources we hold and mark ourselves as a zombie window.\n        // Builds against older Qt versions will just quit on the last window close, because\n        // QTBUG-86874 and QTBUG-86875 prevent this from working.\n#ifdef __APPLE__\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 2))\n        invalidateUI();\n#endif\n#endif\n    }\n    else\n    {\n        p_event->ignore();\n        qtSLiMAppDelegate->closeRejected();\n    }\n}\n\nvoid QtSLiMWindow::moveEvent(QMoveEvent *p_event)\n{\n    if (donePositioning_)\n    {\n        // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n        QSettings settings;\n        \n        settings.beginGroup(\"QtSLiMMainWindow\");\n        settings.setValue(\"size\", size());\n        settings.setValue(\"pos\", pos());\n        settings.endGroup();\n        \n        //qDebug() << \"moveEvent() after done positioning\";\n    }\n    \n    QWidget::moveEvent(p_event);\n}\n\nvoid QtSLiMWindow::resizeEvent(QResizeEvent *p_event)\n{\n    if (donePositioning_)\n    {\n        // Save the window position; see https://doc.qt.io/qt-5/qsettings.html#details\n        QSettings settings;\n        \n        settings.beginGroup(\"QtSLiMMainWindow\");\n        settings.setValue(\"size\", size());\n        settings.setValue(\"pos\", pos());\n        settings.endGroup();\n        \n        //qDebug() << \"resizeEvent() after done positioning\";\n    }\n    \n    QWidget::resizeEvent(p_event);\n}\n\nvoid QtSLiMWindow::showEvent(QShowEvent *p_event)\n{\n    QWidget::showEvent(p_event);\n    \n    if (!testAttribute(Qt::WA_DontShowOnScreen))\n    {\n        //qDebug() << \"showEvent() : done positioning\";\n        donePositioning_ = true;\n    }\n}\n\nbool QtSLiMWindow::isScriptModified(void)\n{\n    // We used to use Qt's isWindowModified() change-tracking system.  Unfortunately, apparently that is broken on Debian;\n    // see https://github.com/MesserLab/SLiM/issues/370.  It looks like Qt internally calls textChanged() and modifies the\n    // document when it shouldn't, resulting in untitled documents being marked dirty.  So now we check whether the\n    // script string has been changed from when it was last saved to disk, or from its initial state if it is not\n    // based on a disk file.  Once a change has been observed, the document stays dirty; it doesn't revert to clean if\n    // the script string goes back to its original state (although smart, that would be non-standard).  BCH 10/24/2023\n    if (scriptChangeObserved)\n        return true;\n    \n    QString curScriptString = ui->scriptTextEdit->toPlainText();\n    \n    if (lastSavedString != curScriptString)\n    {\n        scriptChangeObserved = true;    // sticky until saved\n        return true;\n    }\n    \n    return false;\n}\n\nbool QtSLiMWindow::windowIsReuseable(void)\n{\n    return (isUntitled && !isRecipe && isTransient && (slimChangeCount == 0) && !isScriptModified());\n}\n\nbool QtSLiMWindow::save()\n{\n    return isUntitled ? saveAs() : saveFile(currentFile);\n}\n\nbool QtSLiMWindow::saveAs()\n{\n    QString fileName;\n    \n    if (isUntitled)\n    {\n        QSettings settings;\n        QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);\n        QString directory = settings.value(\"QtSLiMDefaultSaveDirectory\", QVariant(desktopPath)).toString();\n        QFileInfo fileInfo(QDir(directory), \"Untitled.slim\");\n        QString path = fileInfo.absoluteFilePath();\n        \n        fileName = QFileDialog::getSaveFileName(this, \"Save As\", path);\n        \n        if (!fileName.isEmpty())\n            settings.setValue(\"QtSLiMDefaultSaveDirectory\", QVariant(QFileInfo(fileName).path()));\n    }\n    else\n    {\n        // propose saving to the existing filename in the existing directory\n        fileName = QFileDialog::getSaveFileName(this, \"Save As\", currentFile);\n    }\n    \n    if (fileName.isEmpty())\n        return false;\n\n    return saveFile(fileName);\n}\n\nvoid QtSLiMWindow::revert()\n{\n    if (isUntitled)\n    {\n        qApp->beep();\n    }\n    else\n    {\n        const QMessageBox::StandardButton ret = QMessageBox::warning(this, \"SLiMgui\", \"Are you sure you want to revert?  All changes will be lost.\", QMessageBox::Yes | QMessageBox::Cancel);\n        \n        switch (ret) {\n        case QMessageBox::Yes:\n            loadFile(currentFile);\n            break;\n        case QMessageBox::Cancel:\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nbool QtSLiMWindow::maybeSave()\n{\n    // the recycle button change state is irrelevant; the document change state is what matters\n    if (!isScriptModified())\n        return true;\n    \n    const QMessageBox::StandardButton ret = QMessageBox::warning(this, \"SLiMgui\", \"The document has been modified.\\nDo you want to save your changes?\", QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);\n    \n    switch (ret) {\n    case QMessageBox::Save:\n        return save();\n    case QMessageBox::Cancel:\n        return false;\n    default:\n        break;\n    }\n    return true;\n}\n\nvoid QtSLiMWindow::loadFile(const QString &fileName)\n{\n    QFile file(fileName);\n    \n    if (!file.open(QFile::ReadOnly | QFile::Text)) {\n        QMessageBox::warning(this, \"SLiMgui\", QString(\"Cannot read file %1:\\n%2.\").arg(QDir::toNativeSeparators(fileName), file.errorString()));\n        return;\n    }\n    \n    QTextStream in(&file);\n    QString contents = in.readAll();\n    \n    lastSavedString = contents;\n    lastSavedDate = QDateTime::currentDateTime();\n    scriptChangeObserved = false;\n    \n    ui->scriptTextEdit->setPlainText(contents);\n    \n    if (consoleController)\n        consoleController->invalidateSymbolTableAndFunctionMap();\n    \n    clearOutputClicked();\n    setScriptStringAndInitializeSimulation(contents.toUtf8().constData());\n    \n    if (consoleController)\n        consoleController->validateSymbolTableAndFunctionMap();\n    \n    setCurrentFile(fileName);\n    \n    // Update all our UI to reflect the current state of the simulation\n    updateAfterTickFull(true);\n    resetSLiMChangeCount();     // no recycle change count; the current model is correct\n    setWindowModified(false);   // loaded windows start unmodified\n}\n\nvoid QtSLiMWindow::loadRecipe(const QString &recipeName, const QString &recipeScript)\n{\n    if (consoleController)\n        consoleController->invalidateSymbolTableAndFunctionMap();\n    \n    clearOutputClicked();\n    \n    lastSavedString = recipeScript;\n    lastSavedDate = QDateTime::currentDateTime();\n    scriptChangeObserved = false;\n    \n    ui->scriptTextEdit->setPlainText(recipeScript);\n    setScriptStringAndInitializeSimulation(recipeScript.toUtf8().constData());\n    \n    if (consoleController)\n        consoleController->validateSymbolTableAndFunctionMap();\n    \n    setWindowFilePath(recipeName);\n    isRecipe = true;\n    isTransient = false;\n    \n    // Update all our UI to reflect the current state of the simulation\n    updateAfterTickFull(true);\n    resetSLiMChangeCount();     // no recycle change count; the current model is correct\n    setWindowModified(false);   // loaded windows start unmodified\n}\n\nbool QtSLiMWindow::saveFile(const QString &fileName)\n{\n    QFile file(fileName);\n    if (!file.open(QFile::WriteOnly | QFile::Text)) {\n        QMessageBox::warning(this, \"SLiMgui\", QString(\"Cannot write file %1:\\n%2.\").arg(QDir::toNativeSeparators(fileName), file.errorString()));\n        return false;\n    }\n    \n    lastSavedString = ui->scriptTextEdit->toPlainText();\n    lastSavedDate = QDateTime::currentDateTime();\n    scriptChangeObserved = false;\n\n    QTextStream out(&file);\n    out << lastSavedString;\n\n    setCurrentFile(fileName);\n    return true;\n}\n\nvoid QtSLiMWindow::setCurrentFile(const QString &fileName)\n{\n    static int sequenceNumber = 1;\n\n    isUntitled = fileName.isEmpty();\n    \n    if (isUntitled) {\n        if (sequenceNumber == 1)\n            currentFile = QString(\"Untitled\");\n        else\n            currentFile = QString(\"Untitled %1\").arg(sequenceNumber);\n        sequenceNumber++;\n    } else {\n        currentFile = QFileInfo(fileName).canonicalFilePath();\n    }\n\n    ui->scriptTextEdit->document()->setModified(false);\n    setWindowModified(false);\n    if (!isUntitled)\n        isTransient = false;\n    \n    if (!isUntitled)\n        qtSLiMAppDelegate->prependToRecentFiles(currentFile);\n    \n    setWindowFilePath(currentFile);\n}\n\nvoid QtSLiMWindow::documentWasModified()\n{\n    // This method should be called whenever anything happens that makes us want to mark a window as \"dirty\" – confirm before closing.\n    // This is not quite the same as scriptTexteditChanged(), which is called whenever anything happens that makes the recycle\n    // button go green; recycling resets the recycle button to gray, whereas saving resets the document state to unmodified.\n    // We could be called for things that are saveable but do not trigger a need for recycling.\n    \n    // Things are a little more complicated now, because of a Qt bug on Debian that calls us even though the document has not,\n    // in fact, been modified.  So we now determine the window modified state by comparing the script string to the last\n    // saved / original script string.  See isScriptModified().  BCH 10/24/2023\n    \n    //setWindowModified(true);              // the old way that produces buggy behavior\n    setWindowModified(isScriptModified());  // the new way that checks whether the script has actually changed\n}\n\nvoid QtSLiMWindow::tile(const QMainWindow *previous)\n{\n    if (!previous)\n        return;\n    int topFrameWidth = previous->geometry().top() - previous->pos().y();\n    if (!topFrameWidth)\n        topFrameWidth = 40;\n    const QPoint position = previous->pos() + 2 * QPoint(topFrameWidth, topFrameWidth);\n    \n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    // In some versions of Qt5, such as 5.9.5, QScreen did not yet exist\n    if (QApplication::desktop()->availableGeometry(this).contains(rect().bottomRight() + position))\n#else\n    if (this->screen()->availableGeometry().contains(rect().bottomRight() + position))\n#endif\n        move(position);\n}\n\nvoid QtSLiMWindow::appStateChanged(Qt::ApplicationState state)\n{\n    if (state == Qt::ApplicationState::ApplicationActive)\n    {\n        // Apparently we have a re-entrancy problem on Linux (see https://github.com/MesserLab/SLiM/issues/476),\n        // so now we use this flag to prevent that from happening.  It should be set true around all QMessageBox\n        // displays below.\n        if (currentlyWarningAboutDiskFile)\n            return;\n        \n        // the motivation for listening to these state changes is to check for externally-edited\n        // documents; that can only happen for files that have been saved to disk\n        if (!isUntitled && !isRecipe && !isTransient && !isZombieWindow_ && currentFile.length() && lastSavedDate.isValid())\n        {\n            if (QFile::exists(currentFile))\n            {\n                // apparently the file now exists; reset that warning flag\n                warnedAboutNotExistingOnDisk = false;\n                \n                QFileInfo fileInfo(currentFile);\n                QString filename = fileInfo.fileName();         // last path component, for showing to the user\n                QDateTime modDate = fileInfo.lastModified();\n                \n                if (modDate > lastSavedDate)\n                {\n                    // check for readability different file contents\n                    QFile file(currentFile);\n                    \n                    if (!file.open(QFile::ReadOnly | QFile::Text)) {\n                        // avoid showing the same warning twice, unless we see that the problem is fixed\n                        if (warnedAboutUnreadabilityOnDisk)\n                            return;\n                        warnedAboutUnreadabilityOnDisk = true;\n                        \n                        // if the file is not readable at all, we want to warn if it comes back with unexpected contents\n                        warnedAboutExternalEditing = false;\n                        lastExternalChangeString.clear();\n                        \n                        currentlyWarningAboutDiskFile = true;\n                        QMessageBox::warning(this, \"SLiMgui\", QString(\"File %1 appears to have been modified externally (on disk), but cannot be read; you may wish to check permissions.\").arg(filename));\n                        currentlyWarningAboutDiskFile = false;\n                        return;\n                    }\n                    \n                    // apparently the file is now readable; reset that warning flag\n                    warnedAboutUnreadabilityOnDisk = false;\n                    \n                    QTextStream in(&file);\n                    QString contents = in.readAll();\n                    \n                    if (contents == lastSavedString)\n                    {\n                        // the mod date was tweaked, but the file contents are the same; silently update our mod date\n                        //qDebug() << \"no mod: date changed but identical contents\";\n                        lastSavedDate = modDate;\n                        \n                        // we might have warned before, and now returned to our previous state;\n                        // in that case, we should forget that we warned about it before\n                        warnedAboutExternalEditing = false;\n                        lastExternalChangeString.clear();\n                        \n                        return;\n                    }\n                    \n                    // If we already warned the user about these file contents, return without\n                    // warning again; we don't want to warn again unless the contents change again\n                    if (warnedAboutExternalEditing && (contents == lastExternalChangeString))\n                        return;\n                    \n                    //qDebug() << \"EXTERNAL MOD!\";\n                    \n                    // We are going to warn about the external change below; set our state accordingly\n                    warnedAboutExternalEditing = true;\n                    lastExternalChangeString = contents;\n                    \n                    // The file has changed externally; we need to ask the user what to do\n                    QMessageBox::StandardButton ret = QMessageBox::No;\n                    \n                    if (isScriptModified())\n                    {\n                        // If the script in SLiMgui has been changed (i.e., there are unsaved changes), reloading\n                        // is quite dangerous so we require user confirmation with a default of No.\n                        QString prompt = QString(\"File %1 has been modified externally (on disk); do you wish to reload it?\\n\\nThere are unsaved changes in SLiMgui; if you reload, those changes will be lost!\").arg(filename);\n                        \n                        currentlyWarningAboutDiskFile = true;\n                        ret = QMessageBox::critical(this, \"SLiMgui\", prompt, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);\n                        currentlyWarningAboutDiskFile = false;\n                    }\n                    else\n                    {\n                        // If that is not the case, we can suggest the reload as a safer operation with a default\n                        // of Yes.  In this case, we also allow the user to auto-confirm in Preferences.\n                        QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n                        \n                        if (prefsNotifier.reloadOnSafeExternalEditsPref())\n                        {\n                            ret = QMessageBox::Yes;\n                        }\n                        else\n                        {\n                            QString prompt = QString(\"File %1 has been modified externally (on disk); do you wish to reload it?\\n\\n(There are no unsaved changes in SLiMgui that would be lost.  In the Preferences panel you can choose to automatically reload, in this case.)\").arg(filename);\n                            \n                            currentlyWarningAboutDiskFile = true;\n                            ret = QMessageBox::question(this, \"SLiMgui\", prompt, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);\n                            currentlyWarningAboutDiskFile = false;\n                        }\n                    }\n                    \n                    if (ret == QMessageBox::Yes)\n                    {\n                        loadFile(currentFile);\n                        \n                        // since we reloaded our file, we want to warn again if it happens again\n                        warnedAboutExternalEditing = false;\n                        lastExternalChangeString.clear();\n                    }\n                }\n                else\n                {\n                    //qDebug() << \"no mod: mod date equal\";\n                }\n            }\n            else\n            {\n                // avoid showing the same warning twice, unless we see that the problem is fixed\n                if (warnedAboutNotExistingOnDisk)\n                    return;\n                warnedAboutNotExistingOnDisk = true;\n                \n                // if the file doesn't exist on disk at all, we want to warn if it comes back with unexpected contents\n                warnedAboutExternalEditing = false;\n                lastExternalChangeString.clear();\n                \n                currentlyWarningAboutDiskFile = true;\n                QMessageBox::warning(this, \"SLiMgui\", QString(\"File %1 no longer exists on disk; you may wish to re-save or close.\").arg(QDir::toNativeSeparators(currentFile)));\n                currentlyWarningAboutDiskFile = false;\n                return;\n            }\n        }\n        else\n        {\n            //qDebug() << \"no mod: unsaved file\";\n        }\n    }\n}\n\n\n//\n//  Simulation state\n//\n\nstd::vector<Subpopulation *> QtSLiMWindow::listedSubpopulations(void)\n{\n    // This funnel method provides the vector of subpopulations that we are displaying in the population table\n    // It handles the multispecies case and the \"all\" species tab for us\n    std::vector<Subpopulation *> listedSubpops;\n    Species *displaySpecies = focalDisplaySpecies();\n    \n    if (displaySpecies)\n    {\n        // If we have a displaySpecies, we just show all of the subpopulations in the species\n        for (auto &iter : displaySpecies->population_.subpops_)\n            listedSubpops.push_back(iter.second);\n    }\n    else if (!invalidSimulation() && community && community->simulation_valid_)\n    {\n        // If we don't, then we show all subpopulations of all species; this is the \"all\" tab\n        for (Species *species : community->AllSpecies())\n            for (auto &iter : species->population_.subpops_)\n                listedSubpops.push_back(iter.second);\n        \n        // Sort by id, not by species\n        std::sort(listedSubpops.begin(), listedSubpops.end(), [](Subpopulation *l, Subpopulation *r) { return l->subpopulation_id_ < r->subpopulation_id_; });\n    }\n    \n    return listedSubpops;     // note these are sorted by id, not by species, unlike selectedSubpopulations()\n}\n\nstd::vector<Subpopulation*> QtSLiMWindow::selectedSubpopulations(void)\n{\n    Species *displaySpecies = focalDisplaySpecies();\n    std::vector<Subpopulation*> selectedSubpops;\n\t\n    if (community && community->simulation_valid_)\n    {\n        for (Species *species : community->all_species_)\n        {\n            if (!displaySpecies || (displaySpecies == species))\n            {\n                Population &population = species->population_;\n                \n                for (auto popIter : population.subpops_)\n                {\n                    Subpopulation *subpop = popIter.second;\n                    \n                    if (subpop->gui_selected_)\n                        selectedSubpops.emplace_back(subpop);\n                }\n            }\n        }\n    }\n    \n\treturn selectedSubpops;     // note these are sorted by species, not by id, unlike listedSubpopulations()\n}\n\nvoid QtSLiMWindow::setInvalidSimulation(bool p_invalid)\n{\n    if (invalidSimulation_ != p_invalid)\n    {\n        invalidSimulation_ = p_invalid;\n        updateUIEnabling();\n    }\n}\n\nvoid QtSLiMWindow::setReachedSimulationEnd(bool p_reachedEnd)\n{\n    if (reachedSimulationEnd_ != p_reachedEnd)\n    {\n        reachedSimulationEnd_ = p_reachedEnd;\n        updateUIEnabling();\n    }\n}\n\nvoid QtSLiMWindow::setContinuousPlayOn(bool p_flag)\n{\n    if (continuousPlayOn_ != p_flag)\n    {\n        continuousPlayOn_ = p_flag;\n        updateUIEnabling();\n        emit playStateChanged();\n    }\n}\n\nvoid QtSLiMWindow::setTickPlayOn(bool p_flag)\n{\n    if (tickPlayOn_ != p_flag)\n    {\n        tickPlayOn_ = p_flag;\n        updateUIEnabling();\n    }\n}\n\nvoid QtSLiMWindow::setProfilePlayOn(bool p_flag)\n{\n    if (profilePlayOn_ != p_flag)\n    {\n        profilePlayOn_ = p_flag;\n        updateUIEnabling();\n    }\n}\n\nvoid QtSLiMWindow::setNonProfilePlayOn(bool p_flag)\n{\n    if (nonProfilePlayOn_ != p_flag)\n    {\n        nonProfilePlayOn_ = p_flag;\n        updateUIEnabling();\n    }\n}\n\nbool QtSLiMWindow::offerAndExecuteAutofix(QTextCursor target, QString replacement, QString explanation, QString terminationMessage)\n{\n    QString informativeText = \"SLiMgui has found an issue with your script that it knows how to fix:\\n\\n\";\n    informativeText.append(explanation);\n    informativeText.append(\"\\n\\nWould you like SLiMgui to automatically fix it, and then recycle?\\n\");\n    \n    QMessageBox messageBox(this);\n    messageBox.setText(\"Autofixable Error\");\n    messageBox.setInformativeText(informativeText);\n    messageBox.setDetailedText(terminationMessage.trimmed());\n    messageBox.setIcon(QMessageBox::Warning);\n    \n    // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n    // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n    // seems necessary so floating windows can't be on top of the message box\n    messageBox.setWindowModality(Qt::ApplicationModal);\n    messageBox.setFixedWidth(700);      // seems to be ignored\n    messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n    \n    int button = messageBox.exec();\n    \n    if (button == QMessageBox::Yes)\n    {\n        target.insertText(replacement);\n        recycleClicked();\n        return true;\n    }\n    \n    return false;\n}\n\nbool QtSLiMWindow::checkTerminationForAutofix(QString terminationMessage)\n{\n    QTextCursor selection = ui->scriptTextEdit->textCursor();\n    QString selectionString = selection.selectedText();\n    \n    // Note that is important to test the selection string to make sure it makes sense, because the error position might not be correct!\n    \n    // get the four characters prior to the selected error range, to recognize if the error is preceded by \"sim.\"; note this is a heuristic, not precise\n    QTextCursor beforeSelection4 = selection;\n    beforeSelection4.setPosition(beforeSelection4.selectionStart(), QTextCursor::MoveAnchor);\n    beforeSelection4.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 4);\n    beforeSelection4.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 4);\n    QString beforeSelection4String = beforeSelection4.selectedText();\n    \n    //\n    //  Changes for SLiM 4.0: multispecies SLiM, mostly, plus fitness() -> mutationEffect() and fitness(NULL) -> fitnessEffect()\n    //\n    \n    // early() events are no longer default\n    if (terminationMessage.contains(\"unexpected token {\") &&\n            terminationMessage.contains(\"expected an event declaration\") &&\n            terminationMessage.contains(\"early() is no longer a default script block type\") &&\n            (selectionString == \"{\"))\n        return offerAndExecuteAutofix(selection, \"early() {\", \"Script blocks no longer default to `early()`; `early()` must be explicitly specified.\", terminationMessage);\n    \n    // sim to community changes\n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"createLogFile\") &&\n            terminationMessage.contains(\"method createLogFile() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `createLogFile()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"deregisterScriptBlock\") &&\n            terminationMessage.contains(\"method deregisterScriptBlock() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `deregisterScriptBlock()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"registerFirstEvent\") &&\n            terminationMessage.contains(\"method registerFirstEvent() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `registerFirstEvent()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"registerEarlyEvent\") &&\n            terminationMessage.contains(\"method registerEarlyEvent() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `registerEarlyEvent()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"registerLateEvent\") &&\n            terminationMessage.contains(\"method registerLateEvent() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `registerLateEvent()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"rescheduleScriptBlock\") &&\n            terminationMessage.contains(\"method rescheduleScriptBlock() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `rescheduleScriptBlock()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"simulationFinished\") &&\n            terminationMessage.contains(\"method simulationFinished() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `simulationFinished()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"outputUsage\") &&\n            terminationMessage.contains(\"method outputUsage() is not defined on object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `outputUsage()` method has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"logFiles\") &&\n            terminationMessage.contains(\"property logFiles is not defined for object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `logFiles` property has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"generationStage\") &&\n            terminationMessage.contains(\"property generationStage is not defined for object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `generationStage` property has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"modelType\") &&\n            terminationMessage.contains(\"property modelType is not defined for object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `modelType` property has been moved to the Community class.\", terminationMessage);\n    \n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"verbosity\") &&\n            terminationMessage.contains(\"property verbosity is not defined for object element type Species\"))\n        return offerAndExecuteAutofix(beforeSelection4, \"community.\", \"The `verbosity` property has been moved to the Community class.\", terminationMessage);\n    \n    // generation to tick changes\n    if (terminationMessage.contains(\"property originGeneration is not defined for object element type Mutation\") &&\n            (selectionString == \"originGeneration\"))\n        return offerAndExecuteAutofix(selection, \"originTick\", \"The `originGeneration` property has been removed from Mutation; in its place is `originTick` (which measures in ticks, not generations).\", terminationMessage);\n\n    if (terminationMessage.contains(\"property originGeneration is not defined for object element type Substitution\") &&\n            (selectionString == \"originGeneration\"))\n        return offerAndExecuteAutofix(selection, \"originTick\", \"The `originGeneration` property has been removed from Substitution; in its place is `originTick` (which measures in ticks, not generations).\", terminationMessage);\n\n    if (terminationMessage.contains(\"property fixationGeneration is not defined for object element type Substitution\") &&\n            (selectionString == \"fixationGeneration\"))\n        return offerAndExecuteAutofix(selection, \"fixationTick\", \"The `fixationGeneration` property has been removed from Substitution; in its place is `fixationTick` (which measures in ticks, not generations).\", terminationMessage);\n    \n    // generation to cycle changes\n    if (terminationMessage.contains(\"property generation is not defined for object element type Species\") &&\n            (selectionString == \"generation\"))\n        return offerAndExecuteAutofix(selection, \"cycle\", \"The `generation` property of Species has been renamed to `cycle`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property generationStage is not defined for object element type Community\") &&\n            (selectionString == \"generationStage\"))\n        return offerAndExecuteAutofix(selection, \"cycleStage\", \"The `generationStage` property of Community has been renamed to `cycleStage`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method addGeneration() is not defined on object element type LogFile\") &&\n            (selectionString == \"addGeneration\"))\n        return offerAndExecuteAutofix(selection, \"addCycle\", \"The `addGeneration()` method of Community has been renamed to `addCycle()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method addGenerationStage() is not defined on object element type LogFile\") &&\n            (selectionString == \"addGenerationStage\"))\n        return offerAndExecuteAutofix(selection, \"addCycleStage\", \"The `addGenerationStage()` method of Community has been renamed to `addCycleStage()`.\", terminationMessage);\n    \n    // removal of various callback pseudo-parameters\n    // genome1 and genome2 are now handled below, since there are two possible fixes now\n    if (terminationMessage.contains(\"undefined identifier childGenome1\") &&\n            (selectionString == \"childGenome1\"))\n        return offerAndExecuteAutofix(selection, \"child.genome1\", \"The `childGenome1` pseudo-parameter has been removed; it is now accessed as `child.genome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier childGenome2\") &&\n            (selectionString == \"childGenome2\"))\n        return offerAndExecuteAutofix(selection, \"child.genome2\", \"The `childGenome2` pseudo-parameter has been removed; it is now accessed as `child.genome2`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier parent1Genome1\") &&\n            (selectionString == \"parent1Genome1\"))\n        return offerAndExecuteAutofix(selection, \"parent1.genome1\", \"The `parent1Genome1` pseudo-parameter has been removed; it is now accessed as `parent1.genome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier parent1Genome2\") &&\n            (selectionString == \"parent1Genome2\"))\n        return offerAndExecuteAutofix(selection, \"parent1.genome2\", \"The `parent1Genome2` pseudo-parameter has been removed; it is now accessed as `parent1.genome2`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier parent2Genome1\") &&\n            (selectionString == \"parent2Genome1\"))\n        return offerAndExecuteAutofix(selection, \"parent2.genome1\", \"The `parent2Genome1` pseudo-parameter has been removed; it is now accessed as `parent2.genome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier parent2Genome2\") &&\n            (selectionString == \"parent2Genome2\"))\n        return offerAndExecuteAutofix(selection, \"parent2.genome2\", \"The `parent2Genome2` pseudo-parameter has been removed; it is now accessed as `parent2.genome2`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier childIsFemale\") &&\n            (selectionString == \"childIsFemale\"))\n        return offerAndExecuteAutofix(selection, \"(child.sex == \\\"F\\\")\", \"The `childIsFemale` pseudo-parameter has been removed; it is now accessed as `child.sex == \\\"F\\\"`.\", terminationMessage);\n    \n    // changes to InteractionType -evaluate()\n    if (terminationMessage.contains(\"missing required argument subpops\") && (selectionString == \"evaluate\"))\n    {\n        QTextCursor entireCall = selection;\n        entireCall.setPosition(entireCall.selectionStart(), QTextCursor::MoveAnchor);\n        entireCall.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 11);\n        QString entireCallString = entireCall.selectedText();\n        \n        if (entireCallString == \"evaluate();\")\n            return offerAndExecuteAutofix(entireCall, \"evaluate(sim.subpopulations);\", \"The evaluate() method now requires a vector of subpopulations to evaluate.\", terminationMessage);\n    }\n    \n    if (terminationMessage.contains(\"named argument immediate skipped over required argument subpops\") && (selectionString == \"evaluate\"))\n    {\n        QTextCursor entireCall = selection;\n        entireCall.setPosition(entireCall.selectionStart(), QTextCursor::MoveAnchor);\n        entireCall.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 22);\n        QString entireCallString = entireCall.selectedText();\n        \n        if ((entireCallString == \"evaluate(immediate=T);\") || (entireCallString == \"evaluate(immediate=F);\"))\n            return offerAndExecuteAutofix(entireCall, \"evaluate(sim.subpopulations);\", \"The evaluate() method no longer supports immediate evaluation, and the `immediate` parameter has been removed.\", terminationMessage);\n    }\n    \n    if (terminationMessage.contains(\"unrecognized named argument immediate\") && (selectionString == \"evaluate\"))\n    {\n        {\n            QTextCursor callEnd = selection;\n            callEnd.setPosition(callEnd.selectionStart(), QTextCursor::MoveAnchor);\n            callEnd.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);\n            callEnd.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 15);\n            QString callEndString = callEnd.selectedText();\n            \n            if ((callEndString == \", immediate=T);\") || (callEndString == \", immediate=F);\"))\n                return offerAndExecuteAutofix(callEnd, \");\", \"The evaluate() method no longer supports immediate evaluation, and the `immediate` parameter has been removed.\", terminationMessage);\n        }\n        \n        {\n            QTextCursor callEnd = selection;\n            callEnd.setPosition(callEnd.selectionStart(), QTextCursor::MoveAnchor);\n            callEnd.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);\n            callEnd.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 14);\n            QString callEndString = callEnd.selectedText();\n            \n            if ((callEndString == \",immediate=T);\") || (callEndString == \",immediate=F);\"))\n                return offerAndExecuteAutofix(callEnd, \");\", \"The evaluate() method no longer supports immediate evaluation, and the `immediate` parameter has been removed.\", terminationMessage);\n        }\n        \n        {\n            QTextCursor callEnd = selection;\n            callEnd.setPosition(callEnd.selectionStart(), QTextCursor::MoveAnchor);\n            callEnd.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);\n            callEnd.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 17);\n            QString callEndString = callEnd.selectedText();\n            \n            if ((callEndString == \", immediate = T);\") || (callEndString == \", immediate = F);\"))\n                return offerAndExecuteAutofix(callEnd, \");\", \"The evaluate() method no longer supports immediate evaluation, and the `immediate` parameter has been removed.\", terminationMessage);\n        }\n        \n        {\n            QTextCursor callEnd = selection;\n            callEnd.setPosition(callEnd.selectionStart(), QTextCursor::MoveAnchor);\n            callEnd.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor, 1);\n            callEnd.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 16);\n            QString callEndString = callEnd.selectedText();\n            \n            if ((callEndString == \",immediate = T);\") || (callEndString == \",immediate = F);\"))\n                return offerAndExecuteAutofix(callEnd, \");\", \"The evaluate() method no longer supports immediate evaluation, and the `immediate` parameter has been removed.\", terminationMessage);\n        }\n    }\n    \n    // API changes in anticipation of multi-phenotype\n    if (terminationMessage.contains(\"unexpected identifier @fitness; expected an event declaration\"))\n    {\n        {\n            QTextCursor callbackDecl = selection;\n            callbackDecl.setPosition(callbackDecl.selectionStart(), QTextCursor::MoveAnchor);\n            callbackDecl.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 14);\n            QString callbackDeclString = callbackDecl.selectedText();\n            \n            if (callbackDeclString == \"fitness(NULL, \")\n                return offerAndExecuteAutofix(callbackDecl, \"fitnessEffect(\", \"The fitness(NULL) callback type is now called a fitnessEffect() callback.\", terminationMessage);\n        }\n        \n        {\n            QTextCursor callbackDecl = selection;\n            callbackDecl.setPosition(callbackDecl.selectionStart(), QTextCursor::MoveAnchor);\n            callbackDecl.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 13);\n            QString callbackDeclString = callbackDecl.selectedText();\n            \n            if (callbackDeclString == \"fitness(NULL,\")\n                return offerAndExecuteAutofix(callbackDecl, \"fitnessEffect(\", \"The fitness(NULL) callback type is now called a fitnessEffect() callback.\", terminationMessage);\n            if (callbackDeclString == \"fitness(NULL)\")\n                return offerAndExecuteAutofix(callbackDecl, \"fitnessEffect()\", \"The fitness(NULL) callback type is now called a fitnessEffect() callback.\", terminationMessage);\n        }\n        \n        {\n            QTextCursor callbackDecl = selection;\n            callbackDecl.setPosition(callbackDecl.selectionStart(), QTextCursor::MoveAnchor);\n            callbackDecl.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 9);\n            QString callbackDeclString = callbackDecl.selectedText();\n            \n            if (callbackDeclString == \"fitness(m\")\n                return offerAndExecuteAutofix(callbackDecl, \"mutationEffect(m\", \"The fitness() callback type is now called a mutationEffect() callback.\", terminationMessage);\n        }\n    }\n    \n    if (terminationMessage.contains(\"undefined identifier relFitness\"))\n        return offerAndExecuteAutofix(selection, \"effect\", \"The `relFitness` pseudo-parameter has been renamed to `effect`.\", terminationMessage);\n    \n    // other deprecated APIs, unrelated to multispecies and multi-phenotype\n    if ((beforeSelection4String == \"sim.\") &&\n            (selectionString == \"inSLiMgui\") &&\n            terminationMessage.contains(\"property inSLiMgui is not defined for object element type Species\"))\n    {\n        QTextCursor simAndSelection = beforeSelection4;\n        simAndSelection.setPosition(selection.selectionEnd(), QTextCursor::KeepAnchor);\n        \n        return offerAndExecuteAutofix(simAndSelection, \"exists(\\\"slimgui\\\")\", \"The `inSLiMgui` property has been removed; now use `exists(\\\"slimgui\\\")`.\", terminationMessage);\n    }\n    \n    //\n    //  Shift from genome to haplosome for SLiM 5.0\n    //\n    \n    if (terminationMessage.contains(\"could not find an Eidos class named 'Genome'\") &&\n            (selectionString == \"Genome\"))\n        return offerAndExecuteAutofix(selection, \"Haplosome\", \"The `Genome` class has been renamed to `Haplosome`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genomeType is not defined for object element type Haplosome\") &&\n            (selectionString == \"genomeType\"))\n        return offerAndExecuteAutofix(selection, \"chromosome.type\", \"The `genomeType` property of Haplosome has been removed; it is now accessed as `chromosome.type`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property isNullGenome is not defined for object element type Haplosome\") &&\n            (selectionString == \"isNullGenome\"))\n        return offerAndExecuteAutofix(selection, \"isNullHaplosome\", \"The `isNullGenome` property of Haplosome has been renamed to `isNullHaplosome`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genomePedigreeID is not defined for object element type Haplosome\") &&\n            (selectionString == \"genomePedigreeID\"))\n        return offerAndExecuteAutofix(selection, \"haplosomePedigreeID\", \"The `genomePedigreeID` property of Haplosome has been renamed to `haplosomePedigreeID`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method mutationCountsInGenomes() is not defined on object element type Haplosome\") &&\n            (selectionString == \"mutationCountsInGenomes\"))\n        return offerAndExecuteAutofix(selection, \"mutationCountsInHaplosomes\", \"The `mutationCountsInGenomes()` method of Haplosome has been renamed to `mutationCountsInHaplosomes()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method mutationFrequenciesInGenomes() is not defined on object element type Haplosome\") &&\n            (selectionString == \"mutationFrequenciesInGenomes\"))\n        return offerAndExecuteAutofix(selection, \"mutationFrequenciesInHaplosomes\", \"The `mutationFrequenciesInGenomes` property of Haplosome has been renamed to `mutationFrequenciesInHaplosomes`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genomes is not defined for object element type Individual\") &&\n            (selectionString == \"genomes\"))\n        return offerAndExecuteAutofix(selection, \"haplosomes\", \"The `genomes` property of Individual has been renamed to `haplosomes`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genomesNonNull is not defined for object element type Individual\") &&\n            (selectionString == \"genomesNonNull\"))\n        return offerAndExecuteAutofix(selection, \"haplosomesNonNull\", \"The `genomesNonNull` property of Individual has been renamed to `haplosomesNonNull`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genome1 is not defined for object element type Individual\") &&\n            (selectionString == \"genome1\"))\n        return offerAndExecuteAutofix(selection, \"haploidGenome1\", \"The `genome1` property of Individual has been renamed to `haploidGenome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"property genome2 is not defined for object element type Individual\") &&\n            (selectionString == \"genome2\"))\n        return offerAndExecuteAutofix(selection, \"haploidGenome2\", \"The `genome2` property of Individual has been renamed to `haploidGenome2`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property genomes is not defined for object element type Subpopulation\") &&\n            (selectionString == \"genomes\"))\n        return offerAndExecuteAutofix(selection, \"haplosomes\", \"The `genomes` property of Subpopulation has been renamed to `haplosomes`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"property genomesNonNull is not defined for object element type Subpopulation\") &&\n            (selectionString == \"genomesNonNull\"))\n        return offerAndExecuteAutofix(selection, \"haplosomesNonNull\", \"The `genomesNonNull` property of Subpopulation has been renamed to `haplosomesNonNull`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"property chromosome is not defined for object element type Species\") &&\n            (selectionString == \"chromosome\"))\n        return offerAndExecuteAutofix(selection, \"chromosomes\", \"The `chromosome` property of Species has been renamed to `chromosomes`.\", terminationMessage);     // actually, this property was left in, for now\n\n    if (terminationMessage.contains(\"property chromosomeType is not defined for object element type Species\") &&\n            (selectionString == \"chromosomeType\"))\n        return offerAndExecuteAutofix(selection, \"chromosome.type\", \"The `chromosomeType` property of Species has been removed; it is now accessed as `chromosome.type`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier genome\") &&\n            (selectionString == \"genome\"))\n        return offerAndExecuteAutofix(selection, \"haplosome\", \"The `genome` pseudo-parameter has been renamed to `haplosome`.\", terminationMessage);\n\n    // genome1 and genome2 for some callback types were removed in favor of individual.genome1 and individual.genome2 for SLiM 4.0,\n    // and used to be autofixed above; however, in recombination() callbacks genome1 has become haplosome1 and genome2 has\n    // become haplosome2, which conflicted with the previous autofix.  This sequence of fixes works for all cases.\n    if (terminationMessage.contains(\"undefined identifier genome1\") &&\n            (selectionString == \"genome1\"))\n        return offerAndExecuteAutofix(selection, \"haplosome1\", \"The `genome1` pseudo-parameter has been renamed to `haplosome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier haplosome1\") &&\n            (selectionString == \"haplosome1\"))\n        return offerAndExecuteAutofix(selection, \"individual.haploidGenome1\", \"The `haplosome1` pseudo-parameter has been removed; it is now accessed as `individual.haploidGenome1`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier genome2\") &&\n            (selectionString == \"genome2\"))\n        return offerAndExecuteAutofix(selection, \"haplosome2\", \"The `genome2` pseudo-parameter has been renamed to `haplosome2`.\", terminationMessage);\n\n    if (terminationMessage.contains(\"undefined identifier haplosome2\") &&\n            (selectionString == \"haplosome2\"))\n        return offerAndExecuteAutofix(selection, \"individual.haploidGenome2\", \"The `haplosome2` pseudo-parameter has been removed; it is now accessed as `individual.haploidGenome2`.\", terminationMessage);\n    \n    // Other SLiM 5.0 autofixes\n    if (terminationMessage.contains(\"method readFromVCF() is not defined on object element type Haplosome\") &&\n            (selectionString == \"readFromVCF\"))\n        return offerAndExecuteAutofix(selection, \"readHaplosomesFromVCF\", \"The `readFromVCF()` method of Haplosome has been renamed to `readHaplosomesFromVCF()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method readFromMS() is not defined on object element type Haplosome\") &&\n            (selectionString == \"readFromMS\"))\n        return offerAndExecuteAutofix(selection, \"readHaplosomesFromMS\", \"The `readFromMS()` method of Haplosome has been renamed to `readHaplosomesFromMS()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"property haploidDominanceCoeff is not defined for object element type MutationType\") &&\n            (selectionString == \"haploidDominanceCoeff\"))\n        return offerAndExecuteAutofix(selection, \"hemizygousDominanceCoeff\", \"The `haploidDominanceCoeff` property of MutationType has been renamed to `hemizygousDominanceCoeff`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method output() is not defined on object element type Haplosome\") &&\n            (selectionString == \"output\"))\n        return offerAndExecuteAutofix(selection, \"outputHaplosomes\", \"The `output()` method of Haplosome has been renamed to `outputHaplosomes()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method outputMS() is not defined on object element type Haplosome\") &&\n            (selectionString == \"outputMS\"))\n        return offerAndExecuteAutofix(selection, \"outputHaplosomesToMS\", \"The `outputMS()` method of Haplosome has been renamed to `outputHaplosomesToMS()`.\", terminationMessage);\n    \n    if (terminationMessage.contains(\"method outputVCF() is not defined on object element type Haplosome\") &&\n            (selectionString == \"outputVCF\"))\n        return offerAndExecuteAutofix(selection, \"outputHaplosomesToVCF\", \"The `outputVCF()` method of Haplosome has been renamed to `outputHaplosomesToVCF()`.\", terminationMessage);\n    \n    return false;\n}\n\nvoid QtSLiMWindow::showTerminationMessage(QString terminationMessage, EidosErrorContext errorContext)\n{\n    //qDebug() << terminationMessage;\n    \n    // Depending on the circumstances of the error, we might be able to select a range in our input file to show what caused the error\n\tif (!changedSinceRecycle())\n    {\n\t\tui->scriptTextEdit->selectErrorRange(errorContext);\n        \n        // check to see if this is an error we can assist the user in fixing; if they choose to autofix, we are done\n        if (checkTerminationForAutofix(terminationMessage))\n            return;\n    }\n    \n    // Show an error sheet/panel\n    QString fullMessage(terminationMessage);\n    \n    fullMessage.append(\"\\nThis error has invalidated the simulation; it cannot be run further.  Once the script is fixed, you can recycle the simulation and try again.\");\n    \n    QMessageBox messageBox(this);\n    messageBox.setText(\"Simulation Runtime Error\");\n    messageBox.setInformativeText(fullMessage);\n    messageBox.setIcon(QMessageBox::Warning);\n    \n    // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n    // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n    // seems necessary so floating windows can't be on top of the message box\n    messageBox.setWindowModality(Qt::ApplicationModal);\n    messageBox.setFixedWidth(700);      // seems to be ignored\n    messageBox.exec();\n    \n    // Show the error in the status bar also\n    statusBar()->showMessage(\"<font color='#cc0000' style='font-size: 11px;'>\" + terminationMessage.trimmed().toHtmlEscaped() + \"</font>\");\n}\n\nvoid QtSLiMWindow::checkForSimulationTermination(void)\n{\n    std::string &&terminationMessage = gEidosTermination.str();\n\n    if (!terminationMessage.empty())\n    {\n        // Get the termination message and clear the global\n        QString message = QString::fromStdString(terminationMessage);\n\n        gEidosTermination.clear();\n        gEidosTermination.str(\"\");\n\n        // Get the error position and clear the global\n        EidosErrorContext errorContext = gEidosErrorContext;\n        \n        ClearErrorContext();\n        \n        // Send the signal, which connects up to QtSLiMWindow::showTerminationMessage() through a Qt::QueuedConnection\n        emit terminationWithMessage(message, errorContext);\n        \n        // Now we need to clean up so we are in a displayable state.  Note that we don't even attempt to dispose\n        // of the old simulation object; who knows what state it is in, touching it might crash.\n        community = nullptr;\n        focalSpecies = nullptr;\n        slimgui = nullptr;\n\n\t\tif (sim_RNG_initialized)\n\t\t{\n        \t_Eidos_FreeOneRNG(sim_RNG);\n        \tsim_RNG_initialized = false;\n\t\t}\n\t\t\n        setReachedSimulationEnd(true);\n        setInvalidSimulation(true);\n    }\n}\n\nvoid QtSLiMWindow::startNewSimulationFromScript(void)\n{\n    if (community)\n    {\n        delete community;\n        community = nullptr;\n        focalSpecies = nullptr;\n    }\n    if (slimgui)\n    {\n        delete slimgui;\n        slimgui = nullptr;\n    }\n    \n    // forget any script block coloring\n    ui->scriptTextEdit->clearScriptBlockColoring();\n\n\t// Free the old simulation RNG and make a new one, to have clean state\n\tif (sim_RNG_initialized)\n\t{\n\t\t_Eidos_FreeOneRNG(sim_RNG);\n\t\tsim_RNG_initialized = false;\n\t}\n\t\n\t_Eidos_InitializeOneRNG(sim_RNG);\n\tsim_RNG_initialized = true;\n\t\n\t// The Eidos RNG may be set up already; if so, get rid of it.  When we are not running, we keep the\n\t// Eidos RNG in an initialized state, to catch errors with the swapping of RNG state.  Nobody should\n\t// use it when we have not swapped in our own RNG.\n\tif (gEidos_RNG_Initialized)\n\t{\n\t\t_Eidos_FreeOneRNG(gEidos_RNG_SINGLE);\n\t\tgEidos_RNG_Initialized = false;\n\t}\n\t\n\t// Swap in our RNG\n\tstd::swap(sim_RNG, gEidos_RNG_SINGLE);\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\n    std::istringstream infile(scriptString);\n\n    try\n    {\n        community = new Community();\n        community->InitializeFromFile(infile);\n        community->InitializeRNGFromSeed(nullptr);\n        community->FinishInitialization();\n        \n        community->SetDebugPoints(&ui->scriptTextEdit->debuggingPoints());\n\n\t\t// Swap out our RNG\n\t\tstd::swap(sim_RNG, gEidos_RNG_SINGLE);\n\t\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\n        // We also reset various Eidos/SLiM instance state; each SLiMgui window is independent\n        sim_next_pedigree_id = 0;\n        sim_next_mutation_id = 0;\n        sim_suppress_warnings = false;\n\n        // The current working directory was set up in -init to be ~/Desktop, and should not be reset here; if the\n        // user has changed it, that change ought to stick across recycles.  So this bounces us back to the last dir chosen.\n        sim_working_dir = sim_requested_working_dir;\n\n        setReachedSimulationEnd(false);\n        setInvalidSimulation(false);\n        hasImported_ = false;\n    }\n    catch (...)\n    {\n        // BCH 12/25/2022: adding this to swap out our RNG after a raise, seems better...\n\t\tstd::swap(sim_RNG, gEidos_RNG_SINGLE);\n\t\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n        \n        if (community)\n            community->simulation_valid_ = false;\n        setReachedSimulationEnd(true);\n        checkForSimulationTermination();\n    }\n\n    if (community)\n    {\n        // make a new SLiMgui instance to represent SLiMgui in Eidos\n        slimgui = new SLiMgui(*community, this);\n\n        // set up the \"slimgui\" symbol for it immediately\n        // BCH 11/7/2025: note this symbol is now protected in SLiM_ConfigureContext()\n        community->simulation_constants_->InitializeConstantSymbolEntry(slimgui->SymbolTableEntry());\n    }\n    \n    if (community && community->simulation_valid_ && (community->all_species_.size() > 1))\n    {\n        // set up script block coloring\n        std::vector<SLiMEidosBlock*> &blocks = community->AllScriptBlocks();\n        \n        for (SLiMEidosBlock *block : blocks)\n        {\n            Species *species = (block->species_spec_ ? block->species_spec_ : (block->ticks_spec_ ? block->ticks_spec_ : nullptr));\n            \n            if (species && !block->script_ && block->root_node_ && block->root_node_->token_)\n            {\n                EidosToken *block_root_token = block->root_node_->token_;\n                int startPos = block_root_token->token_UTF16_start_;\n                int endPos = block_root_token->token_UTF16_end_;\n                \n                ui->scriptTextEdit->addScriptBlockColoring(startPos, endPos, species);\n            }\n        }\n    }\n}\n\nvoid QtSLiMWindow::setScriptStringAndInitializeSimulation(std::string string)\n{\n    scriptString = string;\n    startNewSimulationFromScript();\n}\n\nSpecies *QtSLiMWindow::focalDisplaySpecies(void)\n{\n    // SLiMgui focuses on one species at a time in its main window display; this method should be called to obtain that species.\n\t// This funnel method checks for various invalid states and returns nil; callers should check for a nil return as needed.\n\tif (!invalidSimulation_ && community && community->simulation_valid_)\n\t{\n        // If we have a focal species set already, it must be valid (the community still exists), so return it\n        if (focalSpecies)\n            return focalSpecies;\n        \n        // If \"all\" is chosen, we return nullptr, which represents that state\n        if (focalSpeciesName.compare(\"all\") == 0)\n            return nullptr;\n        \n        // If not, we'll choose a species from the species list if there are any\n\t\tconst std::vector<Species *> &all_species = community->AllSpecies();\n\t\t\n\t\tif (all_species.size() >= 1)\n        {\n            // If we have a species name remembered, try to choose that species again\n            if (focalSpeciesName.length())\n            {\n                for (Species *species : all_species)\n                {\n                    if (species->name_.compare(focalSpeciesName) == 0)\n                    {\n                        focalSpecies = species;\n                        return focalSpecies;\n                    }\n                }\n            }\n            \n            // Failing that, choose the first declared species and remember its name\n            focalSpecies = all_species[0];\n            focalSpeciesName = focalSpecies->name_;\n        }\n\t}\n\t\n\treturn nullptr;\n}\n\nChromosome *QtSLiMWindow::focalChromosome(void)\n{\n    // There needs to be a focal display species to answer this question; if\n    // we are on the \"all\" tab in a multispecies model, there are multiple\n    // focal chromosomes, so we return nullptr.\n    Species *species = focalDisplaySpecies();\n    \n    if (!species)\n        return nullptr;\n    \n    // If there is one focal display species, then the first overview widget\n    // if the one being displayed (see updateChromosomeViewSetup()).\n    QtSLiMChromosomeWidget *overviewWidget = chromosomeOverviewWidgets[0];\n    \n    Chromosome *chromosome = overviewWidget->focalChromosome();\n    \n    return chromosome;\n}\n\nvoid QtSLiMWindow::selectedSpeciesChanged(void)\n{\n    // We don't want to react to automatic tab changes as we are adding or removing tabs from the species bar\n    if (reloadingSpeciesBar)\n        return;\n    \n    int speciesIndex = ui->speciesBar->currentIndex();\n    const std::vector<Species *> &allSpecies = community->AllSpecies();\n    \n    if (speciesIndex == (int)allSpecies.size())\n    {\n        // this is the \"all\" tab\n        focalSpecies = nullptr;\n        focalSpeciesName = \"all\";\n    }\n    else\n    {\n        if ((speciesIndex < 0) || (speciesIndex >= (int)allSpecies.size()))\n        {\n            qDebug() << \"selectedSpeciesChanged() index\" << speciesIndex << \"out of range\";\n            return;\n        }\n        \n        focalSpecies = allSpecies[speciesIndex];\n        focalSpeciesName = focalSpecies->name_;\n    }\n    \n    //qDebug() << \"selectedSpeciesChanged(): changed to species name\" << QString::fromStdString(focalSpeciesName);\n    \n    // do a full update to show the state for the new species\n    updateAfterTickFull(true);\n    updateUIEnabling();\n}\n\nQtSLiMGraphView *QtSLiMWindow::graphViewForGraphWindow(QWidget *p_window)\n{\n    if (p_window)\n    {\n        QLayout *window_layout = p_window->layout();\n        \n        if (window_layout && (window_layout->count() > 0))\n        {\n            QLayoutItem *item = window_layout->itemAt(0);\n            \n            if (item)\n                return qobject_cast<QtSLiMGraphView *>(item->widget());\n        }\n    }\n    return nullptr;\n}\n\nvoid QtSLiMWindow::updateOutputViews(void)\n{\n    QtSLiMDebugOutputWindow *debugWindow = debugOutputWindow();\n    std::string &&newOutput = gSLiMOut.str();\n\t\n\tif (!newOutput.empty())\n\t{\n        QString str = QString::fromStdString(newOutput);\n\t\t\n\t\t// So, ideally we would stay pinned at the bottom if the user had scrolled to the bottom, but would stay\n\t\t// at the user's chosen scroll position above the bottom if they chose such a position.  Unfortunately,\n\t\t// this doesn't seem to work.  I'm not quite sure why.  Particularly when large amounts of output get\n\t\t// added quickly, the scroller doesn't seem to catch up, and then it reads here as not being at the\n\t\t// bottom, and so we become unpinned even though we used to be pinned.  I'm going to just give up, for\n\t\t// now, and always scroll to the bottom when new output comes out.  That's what many other such apps\n\t\t// do anyway; it's a little annoying if you're trying to read old output, but so it goes.\n\t\t\n\t\t//NSScrollView *enclosingScrollView = [outputTextView enclosingScrollView];\n\t\t//BOOL scrolledToBottom = YES; //(![enclosingScrollView hasVerticalScroller] || [[enclosingScrollView verticalScroller] doubleValue] == 1.0);\n\t\t\n        // ui->outputTextEdit->append(str) would seem the obvious thing to do, but that adds an extra newline (!),\n        // so it can't be used.  WTF.  The solution here does not preserve the user's scroll position; see discussion at\n        // https://stackoverflow.com/questions/13559990/how-to-append-text-to-qplaintextedit-without-adding-newline-and-keep-scroll-at\n        // which has a complex solution involving subclassing QPlainTextEdit... sigh...\n        ui->outputTextEdit->moveCursor(QTextCursor::End);\n        ui->outputTextEdit->insertPlainText(str);\n        ui->outputTextEdit->moveCursor(QTextCursor::End);\n        \n\t\t//if ([[NSUserDefaults standardUserDefaults] boolForKey:defaultsSyntaxHighlightOutputKey])\n\t\t//\t[outputTextView recolorAfterChanges];\n\t\t\n\t\t// if the user was scrolled to the bottom, we keep them there; otherwise, we let them stay where they were\n\t\t//if (scrolledToBottom)\n\t\t//\t[outputTextView scrollRangeToVisible:NSMakeRange([[outputTextView string] length], 0)];\n\t\t\n        // We add run output to the appropriate subview of the output viewer, too; it shows up in both places\n        if (debugWindow)\n            debugWindow->takeRunOutput(str);\n        \n\t\t// clear any error flags set on the stream and empty out its string so it is ready to receive new output\n\t\tgSLiMOut.clear();\n\t\tgSLiMOut.str(\"\");\n\t}\n    \n    // BCH 2/9/2021: We now handle the error output here too, since we want to be in charge of how the\n    // debug window shows itself, etc.  We follow the same strategy as above; comments have been removed.\n    std::string &&newErrors = gSLiMError.str();\n    \n    if (!newErrors.empty())\n    {\n        QString str = QString::fromStdString(newErrors);\n        \n        // BCH 7/17/2024: Decided to send debug output to the main window also, not just the debug output tab\n        // of the debug window; otherwise important messages get lost.  So the main window shows both.\n        ui->outputTextEdit->moveCursor(QTextCursor::End);\n        ui->outputTextEdit->insertPlainText(str);\n        ui->outputTextEdit->moveCursor(QTextCursor::End);\n        \n        if (debugWindow)\n        {\n            debugWindow->takeDebugOutput(str);\n            \n            // Flash the debugging output button to alert the user to new output\n            flashDebugButton();\n        }\n        \n        gSLiMError.clear();\n        gSLiMError.str(\"\");\n    }\n    \n    // BCH 5/15/2022: And now scheduling stream output happens here too, following the pattern above.\n    std::string &&newSchedulingOutput = gSLiMScheduling.str();\n    \n    if (!newSchedulingOutput.empty())\n    {\n        QString str = QString::fromStdString(newSchedulingOutput);\n        \n        if (debugWindow)\n            debugWindow->takeSchedulingOutput(str);\n        \n        gSLiMScheduling.clear();\n        gSLiMScheduling.str(\"\");\n    }\n    \n    // Scan through LogFile instances kept by the sim and flush them to the debug window\n    if (debugWindow && !invalidSimulation_ && community)\n    {\n        for (LogFile *logfile : community->log_file_registry_)\n        {\n            for (auto &lineElements : logfile->emitted_lines_)\n            {\n                // This call takes a vector of string elements comprising one logfile output line\n                debugWindow->takeLogFileOutput(lineElements, logfile->user_file_path_);\n            }\n            \n            logfile->emitted_lines_.clear();\n        }\n    }\n    \n    // Scan through file output kept by the sim and flush it to the debug window\n    if (debugWindow && !invalidSimulation_ && community)\n    {\n        for (size_t index = 0; index < community->file_write_paths_.size(); ++index)\n        {\n            // This call takes a vector of lines comprising all the output for one file\n            debugWindow->takeFileOutput(community->file_write_buffers_[index], community->file_write_appends_[index], community->file_write_paths_[index]);\n        }\n        \n        community->file_write_paths_.clear();\n        community->file_write_buffers_.clear();\n        community->file_write_appends_.clear();\n    }\n}\n\nvoid QtSLiMWindow::flashDebugButton(void)\n{\n    // every 40 is one cycle up and down, to red and back; so 200 gives five cycles,\n    // which seems good for catching the user's attention effectively; maybe excessive,\n    // but that's better than being missed...\n    if (debugButtonFlashCount_ == 0)\n        debugButtonFlashCount_ = 200;\n    else if (debugButtonFlashCount_ < 200)\n        debugButtonFlashCount_ += 40;       // new output adds one cycle, up to the max of five\n    \n    debugButtonFlashTimer_.start(0);\n}\n\nvoid QtSLiMWindow::stopDebugButtonFlash(void)\n{\n    // called when the button gets clicked, pressed, etc.\n    debugButtonFlashCount_ = 0;\n    ui->debugOutputButton->setTemporaryIconOpacity(0.0);\n    debugButtonFlashTimer_.stop();\n}\n\nvoid QtSLiMWindow::handleDebugButtonFlash(void)\n{\n    // decrement with each tick\n    --debugButtonFlashCount_;\n    if (debugButtonFlashCount_ < 0)\n        debugButtonFlashCount_ = 0;\n    \n    // set opacity of the red overlay based on the counter, and reschedule ourselves as needed\n    if (debugButtonFlashCount_ == 0)\n    {\n        stopDebugButtonFlash();\n    }\n    else\n    {\n        int opacity_int = debugButtonFlashCount_ % 40;\n        const double PI = 3.141592653589793;    // not in the C++ standard until C++20!\n        //double opacity_float = std::max(0.0, std::sin(PI * opacity_int / 40.0));                              // dwell on red; not as nice, I decided\n        double opacity_float = std::max(0.0, 1.0 - (std::cos(2 * PI * opacity_int / 40.0) * 0.5 + 0.5));        // equal time red and non-red\n        \n        //qDebug() << \"debugButtonFlashCount_\" << debugButtonFlashCount_ << \", opacity_int\" << opacity_int << \", opacity_float\" << opacity_float;\n        \n        ui->debugOutputButton->setTemporaryIconOpacity(opacity_float);\n        \n        if (debugButtonFlashTimer_.interval() != 17)   // about 60 Hz\n            debugButtonFlashTimer_.start(17);\n    }\n}\n\nvoid QtSLiMWindow::updateTickCounter(void)\n{\n    Species *displaySpecies = focalDisplaySpecies();\n    \n    if (!displaySpecies)\n        ui->cycleLineEdit->setText(\"\");\n    else if (community->Tick() == 0)\n        ui->cycleLineEdit->setText(\"initialize()\");\n    else\n         ui->cycleLineEdit->setText(QString::number(displaySpecies->Cycle()));\n    \n    if (!community)\n    {\n        ui->tickLineEdit->setText(\"\");\n        ui->tickLineEdit->setProgress(0.0);\n    }\n    else if (community->Tick() == 0)\n    {\n        ui->tickLineEdit->setText(\"initialize()\");\n        ui->tickLineEdit->setProgress(0.0);\n    }\n    else\n    {\n        slim_tick_t tick = community->Tick();\n        slim_tick_t lastTick = community->EstimatedLastTick();\n        \n        double progress = (lastTick > 0) ? (tick / (double)lastTick) : 0.0;\n        \n        ui->tickLineEdit->setText(QString::number(tick));\n        ui->tickLineEdit->setProgress(progress);\n    }\n}\n\nvoid QtSLiMWindow::updateSpeciesBar(void)\n{\n    // Update the species bar as needed; we do this only after initialization, to avoid a hide/show on recycle of multispecies models\n    if (!invalidSimulation_ && community && community->simulation_valid_ && (community->Tick() >= 1))\n    {\n        bool speciesBarVisibleNow = !ui->speciesBarWidget->isHidden();\n        bool speciesBarShouldBeVisible = (community->all_species_.size() > 1);\n        \n        if (speciesBarVisibleNow && !speciesBarShouldBeVisible)\n        {\n            ui->speciesBar->setEnabled(false);\n            ui->speciesBarWidget->setHidden(true);\n            \n            reloadingSpeciesBar = true;\n            \n            while (ui->speciesBar->count())\n                ui->speciesBar->removeTab(0);\n            \n            reloadingSpeciesBar = false;\n        }\n        else if (!speciesBarVisibleNow && speciesBarShouldBeVisible)\n        {\n            ui->speciesBar->setEnabled(true);\n            ui->speciesBarWidget->setHidden(false);\n            \n            if ((ui->speciesBar->count() == 0) && (community->all_species_.size() > 0))\n            {\n                // add tabs for species when shown\n                int selectedSpeciesIndex = 0;\n                bool avatarsOnly = (community->all_species_.size() > 2);\n                \n                reloadingSpeciesBar = true;\n                \n                for (Species *species : community->all_species_)\n                {\n                    QString tabLabel = QString::fromStdString(species->avatar_);\n                    \n                    if (!avatarsOnly)\n                    {\n                        tabLabel.append(\" \");\n                        tabLabel.append(QString::fromStdString(species->name_));\n                    }\n                    \n                    int newTabIndex = ui->speciesBar->addTab(tabLabel);\n                    \n                    ui->speciesBar->setTabToolTip(newTabIndex, QString::fromStdString(species->name_).prepend(\"Species \"));\n                    \n                    if (focalSpeciesName.length() && (species->name_.compare(focalSpeciesName) == 0))\n                        selectedSpeciesIndex = newTabIndex;\n                }\n                \n                {\n                    // add the \"all\" tab\n                    QString allLabel = QString::fromUtf8(\"\\xF0\\x9F\\x94\\x85\");   // \"low brightness symbol\", https://www.compart.com/en/unicode/U+1F505\n                \n                    if (!avatarsOnly)\n                        allLabel.append(\" all\");\n                    \n                    int newTabIndex = ui->speciesBar->addTab(allLabel);\n                    \n                    ui->speciesBar->setTabToolTip(newTabIndex, \"Show all species together\");\n                    \n                    if (focalSpeciesName.length() && (focalSpeciesName.compare(\"all\") == 0))\n                        selectedSpeciesIndex = newTabIndex;\n                }\n                \n                reloadingSpeciesBar = false;\n                \n                //qDebug() << \"selecting index\" << selectedSpeciesIndex << \"for name\" << QString::fromStdString(focalSpeciesName);\n                ui->speciesBar->setCurrentIndex(selectedSpeciesIndex);\n            }\n        }\n    }\n    else\n    {\n        // Whenever we're invalid or uninitialized, we hide the species bar and disable and remove all the tabs\n        ui->speciesBar->setEnabled(false);\n        ui->speciesBarWidget->setHidden(true);\n        \n        reloadingSpeciesBar = true;\n        \n        while (ui->speciesBar->count())\n            ui->speciesBar->removeTab(0);\n        \n        reloadingSpeciesBar = false;\n    }\n}\n\nvoid QtSLiMWindow::removeExtraChromosomeViews(void)\n{\n    while (chromosomeOverviewWidgets.size() > 1)\n    {\n        QVBoxLayout *widgetLayout = chromosomeWidgetLayouts.back();\n        \n        ui->chromosomeLayout->removeItem(widgetLayout);\n        \n        QtSLiMClearLayout(widgetLayout, /* deleteWidgets */ true);\n        delete widgetLayout;\n        \n        ui->chromosomeLayout->update();\n        \n        chromosomeWidgetLayouts.pop_back();\n        chromosomeOverviewWidgets.pop_back();\n        chromosomeZoomedWidgets.pop_back();\n    }\n    \n    // Sometimes the call above to QtSLiMClearLayout hangs for up to a second.  This appears to be due to\n    // disposing of the OpenGL context used for the widget, and might be an AMD Radeon issue.  Here's a backtrace\n    // I managed to get from sample.  The only thing I can think of to do about this would be to keep the view\n    // around and reuse it, to avoid having to dispose of its context.  But this may be specific to my hardware;\n    // probably not worth jumping through hoops to address.  BCH 5/9/2022\n    //\n    // 845 QtSLiMChromosomeWidget::~QtSLiMChromosomeWidget()  (in SLiMgui) + 188  [0x1033354ac]  QtSLiMChromosomeWidget.cpp:140\n    //   845 QOpenGLWidget::~QOpenGLWidget()  (in QtWidgets) + 39  [0x104811887]  qopenglwidget.cpp:1020\n    //     844 QOpenGLWidgetPrivate::reset()  (in QtWidgets) + 226  [0x104810582]  qopenglwidget.cpp:719\n    //       844 QOpenGLContext::~QOpenGLContext()  (in QtGui) + 24  [0x104e58f68]  qopenglcontext.cpp:690\n    //         844 QOpenGLContext::destroy()  (in QtGui) + 200  [0x104e58818]  qopenglcontext.cpp:653\n    //           844 QCocoaGLContext::~QCocoaGLContext()  (in libqcocoa.dylib) + 14  [0x105c648ce]  qcocoaglcontext.mm:354\n    //             844 QCocoaGLContext::~QCocoaGLContext()  (in libqcocoa.dylib) + 51  [0x105c64753]  qcocoaglcontext.mm:355\n    //               844 -[NSOpenGLContext dealloc]  (in AppKit) + 62  [0x7fff34349987]\n    //                 844 CGLReleaseContext  (in OpenGL) + 178  [0x7fff4166942a]\n    //                   843 gliDestroyContext  (in GLEngine) + 127  [0x7fff4168f9d1]\n    //                     843 gldDestroyContext  (in libGPUSupportMercury.dylib) + 114  [0x7fff57fe6745]\n    //                       842 glrTerminateContext  (in AMDRadeonX6000GLDriver) + 42  [0x11f390257]\n}\n\nvoid QtSLiMWindow::updateChromosomeViewSetup(void)\n{\n    Species *displaySpecies = focalDisplaySpecies();\n    \n    QtSLiMChromosomeWidget *overviewWidget = chromosomeOverviewWidgets[0];\n    QtSLiMChromosomeWidget *zoomedWidget = chromosomeZoomedWidgets[0];\n    \n    if (invalidSimulation_ || !community || !community->simulation_valid_ || (community->Tick() == 0))\n    {\n        // We are in an invalid state of some kind, so we want one chromosome view that is displaying the empty state\n        overviewWidget->setFocalDisplaySpecies(nullptr);\n        zoomedWidget->setFocalDisplaySpecies(nullptr);\n        \n        removeExtraChromosomeViews();\n    }\n    else if (displaySpecies)\n    {\n        // We have a focal display species, so we want just one chromosome view, displaying that species\n        overviewWidget->setFocalDisplaySpecies(displaySpecies);\n        zoomedWidget->setFocalDisplaySpecies(displaySpecies);\n        \n        removeExtraChromosomeViews();\n    }\n    else if (chromosomeOverviewWidgets.size() != community->all_species_.size())\n    {\n        // We are on the \"all\" species tab in a multispecies model; create a chromosome view for each species\n        // We should always arrive at this state through the \"invalid state\" case above as an intermediate\n        removeExtraChromosomeViews();\n        \n        for (int index = 0; index < (int)community->all_species_.size(); ++index)\n        {\n            displaySpecies = community->all_species_[index];\n            \n            if (index == 0)\n            {\n                // overviewWidget and zoomedWidget were set above and are used for index == 0\n            }\n            else\n            {\n                // Beyond the built-in chromosome view, we create the rest dynamically\n                // This code is based directly on the MOC code for the built-in views\n                QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);\n                sizePolicy1.setHorizontalStretch(0);\n                sizePolicy1.setVerticalStretch(0);\n                \n                QVBoxLayout *chromosomeWidgetLayout = new QVBoxLayout();\n                chromosomeWidgetLayout->setSpacing(4);\n                \n                overviewWidget = new QtSLiMChromosomeWidget(ui->centralWidget);\n                sizePolicy1.setHeightForWidth(overviewWidget->sizePolicy().hasHeightForWidth());\n                overviewWidget->setSizePolicy(sizePolicy1);\n                overviewWidget->setMinimumSize(QSize(0, 20));\n                overviewWidget->setMaximumSize(QSize(16777215, 20));\n                chromosomeWidgetLayout->addWidget(overviewWidget);\n                \n                zoomedWidget = new QtSLiMChromosomeWidget(ui->centralWidget);\n                sizePolicy1.setHeightForWidth(zoomedWidget->sizePolicy().hasHeightForWidth());\n                zoomedWidget->setSizePolicy(sizePolicy1);\n                zoomedWidget->setMinimumSize(QSize(0, 65));\n                zoomedWidget->setMaximumSize(QSize(16777215, 65));\n                chromosomeWidgetLayout->addWidget(zoomedWidget);\n                \n                ui->chromosomeLayout->insertLayout(1, chromosomeWidgetLayout);\n                \n                addChromosomeWidgets(chromosomeWidgetLayout, overviewWidget, zoomedWidget);\n            }\n            \n            overviewWidget->setFocalDisplaySpecies(displaySpecies);\n            zoomedWidget->setFocalDisplaySpecies(displaySpecies);\n        }\n    }\n}\n\nvoid QtSLiMWindow::updateAfterTickFull(bool fullUpdate)\n{\n    // fullUpdate is used to suppress some expensive updating to every third update\n\tif (!fullUpdate)\n\t{\n\t\tif (++partialUpdateCount_ >= 3)\n\t\t{\n\t\t\tpartialUpdateCount_ = 0;\n\t\t\tfullUpdate = true;\n\t\t}\n\t}\n    \n    // Update the species bar and then fetch the focal species after that update, which might change it\n    updateSpeciesBar();\n\t\n    // Create or destroy chromosome views for each species, and set the species for each chromosome view\n    updateChromosomeViewSetup();\n    \n    // Flush any buffered output to files every full update, so that the user sees changes to the files without too much delay\n    // NOTE THAT THE WORKING DIRECTORY HAS BEEN CHANGED BACK AT THIS POINT!\n\tif (fullUpdate)\n    {\n\t\tbool flush_success = Eidos_FlushFiles();\n        \n        if (!flush_success)\n        {\n            // Showing a message right here is a bit disruptive to the flow of the code; for example, if the step button is pressed,\n            // it will stick down and bad things will happen.  So we need to actually halt the simulation with the error.  We might\n            // as well do that with the standard error termination mechanism.  Hopefully this will never be hit anyway.  BCH 3/18/2024\n            gEidosTermination.clear();\n            gEidosTermination.str(\"\");\n            gEidosTermination << \"ERROR (Eidos_FlushFiles): A compressed file buffer failed to write out to disk.  Please check file paths, filesystem writeability and permissions, available disk space, and other possible causes of file I/O problems.\\n\";\n            ClearErrorContext();\n        }\n    }\n\t\n\t// Check whether the simulation has terminated due to an error; if so, show an error message with a delayed perform\n\tcheckForSimulationTermination();\n\t\n\t// The rest of the code here needs to be careful about the invalid state; we do want to update our controls when invalid, but sim is nil.\n    bool inInvalidState = (!community || !community->simulation_valid_ || invalidSimulation());\n    \n    if (fullUpdate)\n        updateOutputViews();\n    \n    // Minimal population table updating.  When the list of subpops changes, we always need to redisplay, otherwise the display\n    // list is outdated and might contain deallocated Subpopulations.  Other than that, though, we only want to redisplay\n    // on full updates, because reloading and redisplaying the tableview can be quite expensive.  The QtSLiMPopulationTableModel\n    // keeps a cache of its display list, and we can use that to see whether a redisplay is needed or not.\n    std::vector<Subpopulation *> newDisplaySubpops = listedSubpopulations();\n    \n    if (fullUpdate || populationTableModel_->needsUpdateForDisplaySubpops(newDisplaySubpops))\n\t{\n        //qDebug() << \"UPDATING TABLE\";\n        \n\t\t// Reloading the subpop tableview is tricky, because we need to preserve the selection across the reload, while also noting that the selection is forced\n\t\t// to change when a subpop goes extinct.  The current selection is noted in the gui_selected_ ivar of each subpop.  So what we do here is reload the tableview\n\t\t// while suppressing our usual update of our selection state, and then we try to re-impose our selection state on the new tableview content.  If a subpop\n\t\t// went extinct, we will fail to notice the selection change; but that is OK, since we force an update of populationView and chromosomeZoomed below anyway.\n\t\treloadingSubpopTableview = true;                        // suppresses QtSLiMWindow::subpopSelectionDidChange()\n        populationTableModel_->reloadTable(newDisplaySubpops);  // invalidates newDisplaySubpops with std::swap()\n\t\t\n        int subpopCount = populationTableModel_->rowCount();\n        \n\t\tif (subpopCount > 0)\n\t\t{\n            ui->subpopTableView->selectionModel()->reset();\n            \n\t\t\tfor (int i = 0; i < subpopCount; ++i)\n\t\t\t{\n                Subpopulation *subpop = populationTableModel_->subpopAtIndex(i);\n                \n\t\t\t\tif (subpop->gui_selected_)\n                {\n                    QModelIndex modelIndex = ui->subpopTableView->model()->index(i, 0);\n                    \n                    ui->subpopTableView->selectionModel()->select(modelIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);\n                }\n\t\t\t}\n\t\t}\n        else\n        {\n            ui->subpopTableView->selectionModel()->clear();\n        }\n\t\t\n\t\treloadingSubpopTableview = false;\n        \n        // We don't want to allow an empty selection, maybe; if we are now in that state, and there are subpops to select, select them all\n        // See also subpopSelectionDidChange() which also needs to do this\n        if ((ui->subpopTableView->selectionModel()->selectedRows().size() == 0) && subpopCount)\n            ui->subpopTableView->selectAll();\n\t}\n    else\n    {\n        //qDebug() << \"skipping unnecessary table update\";\n    }\n\t\n\t// Now update our other UI, some of which depends upon the state of subpopTableView\n    ui->individualsWidget->update();\n    \n    if (fullUpdate)\n        updateTickCounter();\n    \n    if (fullUpdate)\n    {\n        double elapsedTimeInSLiM = elapsedCPUClock_ / static_cast<double>(CLOCKS_PER_SEC);\n        \n        if (elapsedTimeInSLiM == 0.0)\n            ui->statusBar->clearMessage();\n        else\n        {\n            bool inDarkMode = QtSLiMInDarkMode();\n            QString message(inDarkMode ? \"<font color='#AAAAAA' style='font-size: 11px;'><tt>%1</tt> CPU seconds elapsed inside SLiM; <tt>%2</tt> MB memory usage in SLiM; <tt>%3</tt> mutations segregating, <tt>%4</tt> substitutions.</font>\"\n                                       : \"<font color='#555555' style='font-size: 11px;'><tt>%1</tt> CPU seconds elapsed inside SLiM; <tt>%2</tt> MB memory usage in SLiM; <tt>%3</tt> mutations segregating, <tt>%4</tt> substitutions.</font>\");\n            \n            if (!inInvalidState)\n            {\n                int totalRegistrySize = 0;\n                \n                for (Species *species : community->AllSpecies())\n                {\n                    int registry_size;\n                    \n                    species->population_.MutationRegistry(&registry_size);\n                    totalRegistrySize += registry_size;\n                }\n                \n                // Tally up usage across the simulation\n                SLiMMemoryUsage_Community usage_community;\n                SLiMMemoryUsage_Species usage_all_species;\n                \n                EIDOS_BZERO(&usage_all_species, sizeof(SLiMMemoryUsage_Species));\n                \n                community->TabulateSLiMMemoryUsage_Community(&usage_community, nullptr);\n                \n                for (Species *species : community->AllSpecies())\n                {\n                    SLiMMemoryUsage_Species usage_one_species;\n                    \n                    species->TabulateSLiMMemoryUsage_Species(&usage_one_species);\n                    AccumulateMemoryUsageIntoTotal_Species(usage_one_species, usage_all_species);\n                }\n                \n                double current_memory_MB = (usage_community.totalMemoryUsage + usage_all_species.totalMemoryUsage) / (1024.0 * 1024.0);\n                \n                // Tally up substitutions across the simulation\n                int totalSubstitutions = 0;\n                \n                for (Species *species : community->AllSpecies())\n                    totalSubstitutions += species->population_.substitutions_.size();\n                \n                ui->statusBar->showMessage(message.arg(elapsedTimeInSLiM, 0, 'f', 6)\n                                           .arg(current_memory_MB, 0, 'f', 1)\n                                           .arg(totalRegistrySize)\n                                           .arg(totalSubstitutions));\n            }\n            else\n                ui->statusBar->showMessage(message.arg(elapsedTimeInSLiM, 0, 'f', 6));\n        }\n\t}\n    \n\t// Update stuff that only needs updating when the script is re-parsed, not after every tick\n\tif (inInvalidState || community->mutation_types_changed_)\n\t{\n        if (tablesDrawerController && tablesDrawerController->mutTypeTableModel_)\n            tablesDrawerController->mutTypeTableModel_->reloadTable();\n\t\t\n\t\tif (community)\n\t\t\tcommunity->mutation_types_changed_ = false;\n\t}\n\t\n\tif (inInvalidState || community->genomic_element_types_changed_)\n\t{\n        if (tablesDrawerController && tablesDrawerController->geTypeTableModel_)\n            tablesDrawerController->geTypeTableModel_->reloadTable();\n\t\t\n\t\tif (community)\n\t\t\tcommunity->genomic_element_types_changed_ = false;\n\t}\n\t\n\tif (inInvalidState || community->interaction_types_changed_)\n\t{\n        if (tablesDrawerController && tablesDrawerController->interactionTypeTableModel_)\n            tablesDrawerController->interactionTypeTableModel_->reloadTable();\n\t\t\n\t\tif (community)\n\t\t\tcommunity->interaction_types_changed_ = false;\n\t}\n\t\n\tif (inInvalidState || community->scripts_changed_)\n\t{\n        if (tablesDrawerController && tablesDrawerController->eidosBlockTableModel_)\n            tablesDrawerController->eidosBlockTableModel_->reloadTable();\n\t\t\n\t\tif (community)\n\t\t\tcommunity->scripts_changed_ = false;\n\t}\n\t\n\tif (inInvalidState || community->chromosome_changed_)\n\t{\n        for (QtSLiMChromosomeWidget *overviewWidget : chromosomeOverviewWidgets)\n        {\n            overviewWidget->restoreLastSelection();\n            overviewWidget->update();\n        }\n        \n\t\tif (community)\n\t\t\tcommunity->chromosome_changed_ = false;\n\t}\n\t\n\t// Update graph windows as well; this will usually trigger an update() but may do other updating work as well\n    // BCH 9/26/2024: This mechanism is now used to update chromosome views as well.  We now have two signals,\n    // one for partial updates and one for full updates; a given receiver should connect to just one of these signals.\n    // The partial update signal is always emitted; the full update signal is emitted only for full updates,\n    // which are less frequent.\n    if (fullUpdate)\n        emit controllerFullUpdateAfterTick();\n    \n    emit controllerPartialUpdateAfterTick();\n}\n\nvoid QtSLiMWindow::updatePlayButtonIcon(bool pressed)\n{\n    bool highlighted = ui->playButton->isChecked() ^ pressed;\n    \n    ui->playButton->qtslimSetHighlight(highlighted);\n}\n\nvoid QtSLiMWindow::updateProfileButtonIcon(bool pressed)\n{\n    bool highlighted = ui->profileButton->isChecked() ^ pressed;\n    \n    if (profilePlayOn_)\n        ui->profileButton->qtslimSetIcon(\"profile_R\", !highlighted);    // flipped intentionally\n    else\n        ui->profileButton->qtslimSetIcon(\"profile\", highlighted);\n}\n\nvoid QtSLiMWindow::updateRecycleButtonIcon(bool pressed)\n{\n    if (slimChangeCount)\n        ui->recycleButton->qtslimSetIcon(\"recycle_G\", pressed);\n    else\n        ui->recycleButton->qtslimSetIcon(\"recycle\", pressed);\n}\n\nvoid QtSLiMWindow::updateUIEnabling(void)\n{\n    // First we update all the UI that belongs exclusively to ourselves: buttons, labels, etc.\n    ui->playOneStepButton->setEnabled(!reachedSimulationEnd_ && !continuousPlayOn_);\n    ui->playButton->setEnabled(!reachedSimulationEnd_ && !profilePlayOn_);\n    ui->profileButton->setEnabled(!reachedSimulationEnd_ && !nonProfilePlayOn_ && !tickPlayOn_);\n    ui->recycleButton->setEnabled(!continuousPlayOn_);\n    \n    ui->playSpeedSlider->setEnabled(!invalidSimulation_);\n    \n    if (invalidSimulation_)\n    {\n        // when an error occurs, we want these textfields to have a dimmed/disabled appearance\n        ui->tickLineEdit->setAppearance(/* enabled */ false, /* dimmed */ true);\n        ui->cycleLineEdit->setAppearance(/* enabled */ false, /* dimmed */ true);\n    }\n    else\n    {\n        // otherwise, we want an enabled _appearance_ at all times, but we have to disable them\n        // to prevent editing during play; so we set the text color to prevent it from dimming\n        // note that the cycle lineedit is always disabled, but follows the appearance of the tick lineedit;\n        // the \"editable but dimmed\" visual appearance is actually a little different so hopefully this is clear\n        bool editingAllowed = (!reachedSimulationEnd_ && !continuousPlayOn_);\n        \n        ui->tickLineEdit->setAppearance(/* enabled */ editingAllowed, /* dimmed */ false);\n        ui->cycleLineEdit->setAppearance(/* enabled */ false, /* dimmed */ false);\n    }\n    \n    ui->toggleDrawerButton->setEnabled(true);\n    \n    ui->clearDebugButton->setEnabled(true);\n    ui->checkScriptButton->setEnabled(!continuousPlayOn_);\n    ui->prettyprintButton->setEnabled(!continuousPlayOn_);\n    ui->scriptHelpButton->setEnabled(true);\n    ui->consoleButton->setEnabled(true);\n    ui->browserButton->setEnabled(true);\n    ui->jumpToPopupButton->setEnabled(true);\n    \n    ui->chromosomeActionButton->setEnabled(!invalidSimulation_);\n    ui->chromosomeDisplayButton->setEnabled(!invalidSimulation_);\n    ui->clearOutputButton->setEnabled(!invalidSimulation_);\n    ui->dumpPopulationButton->setEnabled(!invalidSimulation_);\n    ui->debugOutputButton->setEnabled(true);\n    ui->graphPopupButton->setEnabled(!invalidSimulation_);\n    ui->changeDirectoryButton->setEnabled(!continuousPlayOn_);\n    \n    ui->scriptTextEdit->setReadOnly(continuousPlayOn_);\n    ui->outputTextEdit->setReadOnly(true);\n    \n    ui->tickLabel->setEnabled(!invalidSimulation_);\n    ui->cycleLabel->setEnabled(!invalidSimulation_);\n    ui->outputHeaderLabel->setEnabled(!invalidSimulation_);\n    \n    // Tell the console controller to enable/disable its buttons\n    if (consoleController)\n        consoleController->setInterfaceEnabled(!continuousPlayOn_);\n    \n    // Then, if we are the focused or active window, we update the menus to reflect our state\n    // If there's a focused/active window but it isn't us, we reflect that situation with a different method\n    // Keep in mind that in Qt each QMainWindow has its own menu bar, its own actions, etc.; this is not global state!\n    // This means we spend a little time updating menu enable states that are not visible anyway, but it's fast\n    QWidget *currentFocusWidget = qApp->focusWidget();\n    QWidget *focusWindow = (currentFocusWidget ? currentFocusWidget->window() : qtSLiMAppDelegate->activeWindow());\n    \n    if (focusWindow == this) {\n        //qDebug() << \"updateMenuEnablingACTIVE()\";\n        updateMenuEnablingACTIVE(currentFocusWidget);\n    } else {\n        //qDebug() << \"updateMenuEnablingINACTIVE()\";\n        updateMenuEnablingINACTIVE(currentFocusWidget, focusWindow);\n    }\n}\n\nvoid QtSLiMWindow::updateMenuEnablingACTIVE(QWidget *p_focusWidget)\n{\n    // Enable/disable actions (i.e., menu items) when our window is active.  Note that this\n    // does not enable/disable buttons; that is done in QtSLiMWindow::updateUIEnabling().\n    \n    ui->actionClose->setEnabled(true);\n    ui->actionSave->setEnabled(true);\n    ui->actionSaveAs->setEnabled(true);\n    ui->actionRevertToSaved->setEnabled(!isUntitled);\n    \n    //ui->menuSimulation->setEnabled(true);     // commented out these menu-level enable/disables; they flash weirdly and are distracting\n    ui->actionStep->setEnabled(!reachedSimulationEnd_ && !continuousPlayOn_);\n    ui->actionPlay->setEnabled(!reachedSimulationEnd_ && !profilePlayOn_);\n    ui->actionPlay->setText(nonProfilePlayOn_ ? \"Stop\" : \"Play\");\n    ui->actionProfile->setEnabled(!reachedSimulationEnd_ && !nonProfilePlayOn_ && !tickPlayOn_);\n    ui->actionProfile->setText(profilePlayOn_ ? \"Stop\" : \"Profile\");\n    ui->actionRecycle->setEnabled(!continuousPlayOn_);\n    \n    //ui->menuScript->setEnabled(true);\n    ui->actionClearDebug->setEnabled(true);\n    ui->actionCheckScript->setEnabled(!continuousPlayOn_);\n    ui->actionPrettyprintScript->setEnabled(!continuousPlayOn_);\n    ui->actionReformatScript->setEnabled(!continuousPlayOn_);\n    ui->actionShowScriptHelp->setEnabled(true);\n    ui->actionBiggerFont->setEnabled(true);\n    ui->actionSmallerFont->setEnabled(true);\n    ui->actionShowEidosConsole->setEnabled(true);\n    ui->actionShowVariableBrowser->setEnabled(true);\n    ui->actionShowDebuggingOutput->setEnabled(true);\n    \n    ui->actionClearOutput->setEnabled(!invalidSimulation_);\n    ui->actionExecuteAll->setEnabled(false);\n    ui->actionExecuteSelection->setEnabled(false);\n    ui->actionDumpPopulationState->setEnabled(!invalidSimulation_);\n    ui->actionChangeWorkingDirectory->setEnabled(!continuousPlayOn_);\n    \n    // see QtSLiMWindow::graphPopupButtonRunMenu() for parallel code involving the graph popup button\n    Species *displaySpecies = focalDisplaySpecies();\n    bool graphItemsEnabled = displaySpecies && !invalidSimulation_;\n    \n    //ui->menuGraph->setEnabled(graphItemsEnabled);\n    ui->actionGraph_1D_Population_SFS->setEnabled(graphItemsEnabled);\n\tui->actionGraph_1D_Sample_SFS->setEnabled(graphItemsEnabled);\n\tui->actionGraph_2D_Population_SFS->setEnabled(graphItemsEnabled);\n\tui->actionGraph_2D_Sample_SFS->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Mutation_Frequency_Trajectories->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Mutation_Loss_Time_Histogram->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Mutation_Fixation_Time_Histogram->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Population_Fitness_Distribution->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Subpopulation_Fitness_Distributions->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Fitness_Time->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Age_Distribution->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Lifetime_Reproduce_Output->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Population_Size_Time->setEnabled(graphItemsEnabled);\n\tui->actionGraph_Population_Visualization->setEnabled(graphItemsEnabled);\n    ui->actionGraph_Multispecies_Population_Size_Time->setEnabled(!invalidSimulation_);     // displaySpecies not required\n    \n    // the haplotype plot menu items are a bit complicated\n    bool haplotypePlotEnabled = displaySpecies && !continuousPlayOn_ && displaySpecies->population_.subpops_.size();\n    ui->actionCreate_Haplotype_Plot_All->setEnabled(haplotypePlotEnabled);\n    ui->actionCreate_Haplotype_Plot_Selected->setEnabled(haplotypePlotEnabled && (focalChromosome() != nullptr));\n    \n    if (haplotypePlotEnabled && (displaySpecies->Chromosomes().size() > 1))\n    {\n        // enabled with 2+ chromosomes, we show both menu items\n        ui->actionCreate_Haplotype_Plot_All->setText(\"Create Haplotype Plot (all chromosomes)\");\n        ui->actionCreate_Haplotype_Plot_Selected->setVisible(true);\n    }\n    else\n    {\n        // disabled or with 0 or 1 chromosomes, we show only actionCreate_Haplotype_Plot_All\n        ui->actionCreate_Haplotype_Plot_All->setText(\"Create Haplotype Plot\");\n        ui->actionCreate_Haplotype_Plot_Selected->setVisible(false);\n    }\n    \n    updateMenuEnablingSHARED(p_focusWidget);\n}\n\nvoid QtSLiMWindow::updateMenuEnablingINACTIVE(QWidget *p_focusWidget, QWidget *focusWindow)\n{\n    // Enable/disable actions (i.e., menu items) when our window is inactive.  Note that this\n    // does not enable/disable buttons; that is done in QtSLiMWindow::updateUIEnabling().\n    \n    QWidget *currentActiveWindow = QApplication::activeWindow();\n    ui->actionClose->setEnabled(currentActiveWindow ? true : false);\n    \n    ui->actionSave->setEnabled(false);\n    ui->actionSaveAs->setEnabled(false);\n    ui->actionRevertToSaved->setEnabled(false);\n    \n    //ui->menuSimulation->setEnabled(false);\n    ui->actionStep->setEnabled(false);\n    ui->actionPlay->setEnabled(false);\n    ui->actionPlay->setText(\"Play\");\n    ui->actionProfile->setEnabled(false);\n    ui->actionProfile->setText(\"Profile\");\n    ui->actionRecycle->setEnabled(false);\n    \n    // The script menu state, if we are inactive, is mostly either (a) governed by the front console\n    // controller, or (b) is disabled, if a console controller is not active\n    QtSLiMEidosConsole *eidosConsole = dynamic_cast<QtSLiMEidosConsole*>(focusWindow);\n    bool consoleFocused = (eidosConsole != nullptr);\n    bool consoleFocusedAndEditable = ((eidosConsole != nullptr) && !continuousPlayOn_);\n    \n    //ui->menuScript->setEnabled(consoleFocused);\n    ui->actionCheckScript->setEnabled(consoleFocusedAndEditable);\n    ui->actionPrettyprintScript->setEnabled(consoleFocusedAndEditable);\n    ui->actionReformatScript->setEnabled(consoleFocusedAndEditable);\n    ui->actionClearOutput->setEnabled(consoleFocused);\n    ui->actionExecuteAll->setEnabled(consoleFocusedAndEditable);\n    ui->actionExecuteSelection->setEnabled(consoleFocusedAndEditable);\n    \n    // but these menu items apply only to QtSLiMWindow, not to the Eidos console\n    ui->actionClearDebug->setEnabled(false);\n    ui->actionDumpPopulationState->setEnabled(false);\n    ui->actionChangeWorkingDirectory->setEnabled(false);\n    \n    //ui->menuGraph->setEnabled(false);\n    ui->actionGraph_1D_Population_SFS->setEnabled(false);\n\tui->actionGraph_1D_Sample_SFS->setEnabled(false);\n\tui->actionGraph_2D_Population_SFS->setEnabled(false);\n\tui->actionGraph_2D_Sample_SFS->setEnabled(false);\n\tui->actionGraph_Mutation_Frequency_Trajectories->setEnabled(false);\n\tui->actionGraph_Mutation_Loss_Time_Histogram->setEnabled(false);\n\tui->actionGraph_Mutation_Fixation_Time_Histogram->setEnabled(false);\n\tui->actionGraph_Population_Fitness_Distribution->setEnabled(false);\n\tui->actionGraph_Subpopulation_Fitness_Distributions->setEnabled(false);\n\tui->actionGraph_Fitness_Time->setEnabled(false);\n\tui->actionGraph_Age_Distribution->setEnabled(false);\n\tui->actionGraph_Lifetime_Reproduce_Output->setEnabled(false);\n\tui->actionGraph_Population_Size_Time->setEnabled(false);\n\tui->actionGraph_Population_Visualization->setEnabled(false);\n    \n    // the haplotype plot menu items take on a generic appearance when disabled\n    ui->actionCreate_Haplotype_Plot_All->setEnabled(false);\n    ui->actionCreate_Haplotype_Plot_All->setText(\"Create Haplotype Plot\");\n    ui->actionCreate_Haplotype_Plot_Selected->setEnabled(false);\n    ui->actionCreate_Haplotype_Plot_Selected->setVisible(false);\n    \n    // we can show our various windows as long as we can reach the controller window\n    QtSLiMWindow *slimWindow = qtSLiMAppDelegate->dispatchQtSLiMWindowFromSecondaries();\n    bool canReachSLiMWindow = !!slimWindow;\n    \n    ui->actionShowScriptHelp->setEnabled(canReachSLiMWindow);\n    ui->actionShowEidosConsole->setEnabled(canReachSLiMWindow);\n    ui->actionShowVariableBrowser->setEnabled(canReachSLiMWindow);\n    ui->actionShowDebuggingOutput->setEnabled(canReachSLiMWindow);\n    \n    updateMenuEnablingSHARED(p_focusWidget);\n}\n\nvoid QtSLiMWindow::updateMenuEnablingSHARED(QWidget *p_focusWidget)\n{\n    // Here we update the enable state for menu items, such as cut/copy/paste, that go to\n    // the p_focusWidget whatever window it might be in; \"first responder\" in Cocoa parlance\n    QLineEdit *lE = dynamic_cast<QLineEdit*>(p_focusWidget);\n    QTextEdit *tE = dynamic_cast<QTextEdit*>(p_focusWidget);\n    QPlainTextEdit *ptE = dynamic_cast<QPlainTextEdit*>(p_focusWidget);\n    QtSLiMTextEdit *stE = dynamic_cast<QtSLiMTextEdit *>(tE);\n    bool hasEnabledDestination = (lE && lE->isEnabled()) || (tE && tE->isEnabled()) || (ptE && ptE->isEnabled());\n    bool hasEnabledModifiableDestination = (lE && lE->isEnabled() && !lE->isReadOnly()) ||\n            (tE && tE->isEnabled() && !tE->isReadOnly()) || (ptE && ptE->isEnabled() && !ptE->isReadOnly());\n    bool hasUndoableDestination = (lE && lE->isEnabled() && !lE->isReadOnly() && lE->isUndoAvailable()) ||\n            (tE && tE->isEnabled() && !tE->isReadOnly() && tE->isUndoRedoEnabled()) ||\n            (ptE && ptE->isEnabled() && !ptE->isReadOnly() && ptE->isUndoRedoEnabled());\n    bool hasRedoableDestination = (lE && lE->isEnabled() && !lE->isReadOnly() && lE->isRedoAvailable()) ||\n            (tE && tE->isEnabled() && !tE->isReadOnly() && tE->isUndoRedoEnabled()) ||\n            (ptE && ptE->isEnabled() && !ptE->isReadOnly() && ptE->isUndoRedoEnabled());\n    bool hasCopyableDestination = (lE && lE->isEnabled() && lE->selectedText().length()) ||\n            (tE && tE->isEnabled()) || (ptE && ptE->isEnabled());\n    \n    if (stE)\n    {\n        // refine our assessment of undo/redo/copy capability if possible\n        hasUndoableDestination = hasUndoableDestination && stE->qtslimIsUndoAvailable();\n        hasRedoableDestination = hasRedoableDestination && stE->qtslimIsRedoAvailable();\n        hasCopyableDestination = hasCopyableDestination && stE->qtslimIsCopyAvailable();\n    }\n    \n    ui->actionUndo->setEnabled(hasUndoableDestination);\n    ui->actionRedo->setEnabled(hasRedoableDestination);\n    ui->actionCut->setEnabled(hasEnabledModifiableDestination);\n    ui->actionCopy->setEnabled(hasCopyableDestination);\n    ui->actionPaste->setEnabled(hasEnabledModifiableDestination);\n    ui->actionDelete->setEnabled(hasEnabledModifiableDestination);\n    ui->actionSelectAll->setEnabled(hasEnabledDestination);\n    \n    ui->actionBiggerFont->setEnabled(true);\n    ui->actionSmallerFont->setEnabled(true);\n    \n    // actions handled by QtSLiMScriptTextEdit only\n    QtSLiMScriptTextEdit *scriptEdit = dynamic_cast<QtSLiMScriptTextEdit*>(p_focusWidget);\n    bool isScriptTextEdit = (!!scriptEdit);\n    bool isModifiableScriptTextEdit = (isScriptTextEdit && !scriptEdit->isReadOnly());\n    \n    ui->actionDuplicate->setEnabled(isModifiableScriptTextEdit);\n    ui->actionCopyAsHTML->setEnabled(isScriptTextEdit);\n    ui->actionShiftLeft->setEnabled(isModifiableScriptTextEdit);\n    ui->actionShiftRight->setEnabled(isModifiableScriptTextEdit);\n    ui->actionCommentUncomment->setEnabled(isModifiableScriptTextEdit);\n    \n    // actions handled by the Find panel only\n    QtSLiMFindPanel &findPanelInstance = QtSLiMFindPanel::instance();\n    bool hasFindTarget = (findPanelInstance.targetTextEditRequireModifiable(false) != nullptr);\n    bool hasModifiableFindTarget = (findPanelInstance.targetTextEditRequireModifiable(true) != nullptr);\n    \n    ui->actionFindShow->setEnabled(true);\n    ui->actionFindNext->setEnabled(hasFindTarget);\n    ui->actionFindPrevious->setEnabled(hasFindTarget);\n    ui->actionReplaceAndFind->setEnabled(hasModifiableFindTarget);\n    ui->actionUseSelectionForFind->setEnabled(hasFindTarget);\n    ui->actionUseSelectionForReplace->setEnabled(hasFindTarget);\n    ui->actionJumpToSelection->setEnabled(hasFindTarget);\n    ui->actionJumpToLine->setEnabled(hasFindTarget);\n    \n    findPanelInstance.fixEnableState();   // give it a chance to update its buttons whenever we update\n}\n\nvoid QtSLiMWindow::updateWindowMenu(void)\n{\n    // Clear out old actions, up to the separator\n    do\n    {\n        const QList<QAction *> actions = ui->menuWindow->actions();\n        QAction *lastAction = actions.last();\n        \n        if (!lastAction)\n            break;\n        if ((lastAction->objectName().length() == 0) || (lastAction->objectName() == \"action\"))\n            break;\n        \n        // I have seen this loop fail to terminate, because apparently asking for an action\n        // to be removed sometimes fails.  So now we watch the number of actions and make\n        // sure it goes down, otherwise we bail.  BCH 1/29/2024\n        int actionCount = actions.count();\n        \n        ui->menuWindow->removeAction(lastAction);\n        \n        if (ui->menuWindow->actions().count() >= actionCount)\n        {\n            qDebug() << \"QtSLiMWindow::updateWindowMenu() menu clearing terminating due to malfunction\";\n            break;\n        }\n    }\n    while (true);\n    \n    // Get the main windows, in sorted order\n    const QList<QWidget *> allWidgets = QApplication::allWidgets();\n    std::vector<std::pair<std::string, QtSLiMWindow *>> windows;\n    \n    for (QWidget *widget : allWidgets)\n    {\n        QtSLiMWindow *mainWin = qobject_cast<QtSLiMWindow *>(widget);\n        \n        if (mainWin && !mainWin->isZombieWindow_)\n        {\n            QString title = mainWin->windowTitle();\n            \n            if (title.endsWith(\"[*]\"))\n                title.chop(3);\n            \n            windows.emplace_back(title.toStdString(), mainWin);\n        }\n    }\n    \n    std::sort(windows.begin(), windows.end(), [](const std::pair<std::string, QtSLiMWindow *> &l, const std::pair<std::string, QtSLiMWindow *> &r) { return l.first < r.first; });\n    \n    // Make new actions\n    QWidget *activeWindow = qtSLiMAppDelegate->activeWindow();\n    \n    for (const auto &pair : windows)\n    {\n        QString title = QString::fromStdString(pair.first);\n        QtSLiMWindow *mainWin = pair.second;\n        \n        if (mainWin)\n        {\n            QAction *action = ui->menuWindow->addAction(title, mainWin, [mainWin]() { QtSLiMMakeWindowVisibleAndExposed(mainWin); });\n            action->setCheckable(mainWin == activeWindow);  // only set checkable if checked, to avoid the empty checkbox on Ubuntu\n            action->setChecked(mainWin == activeWindow);\n            action->setObjectName(\"__QtSLiM_window__\");\n            \n            // Get the subwindows, in sorted order\n            std::vector<std::pair<std::string, QWidget *>> subwindows;\n            \n            for (QWidget *widget : allWidgets)\n            {\n                QWidget *finalParent = widget->parentWidget();\n                \n                while (finalParent && (finalParent != mainWin))\n                    finalParent = finalParent->parentWidget();\n                \n                if ((qobject_cast<QtSLiMWindow *>(widget) == nullptr) &&\n                        (finalParent == mainWin) &&\n                        (widget->isVisible()) &&\n                        (((widget->windowFlags() & Qt::Window) == Qt::Window) || ((widget->windowFlags() & Qt::Tool) == Qt::Tool)))\n                {\n                    QString subwindowTitle = widget->windowTitle();\n                    \n                    if (subwindowTitle.length())\n                    {\n                        if (graphViewForGraphWindow(widget))\n                            subwindowTitle.prepend(\"Graph: \");\n                        subwindows.emplace_back(subwindowTitle.toStdString(), widget);\n                    }\n                }\n            }\n            \n            std::sort(subwindows.begin(), subwindows.end(), [](const std::pair<std::string, QWidget *> &l, const std::pair<std::string, QWidget *> &r) { return l.first < r.first; });\n            \n            // Add indented subitems for windows owned by this main window\n            for (const auto &subpair : subwindows)\n            {\n                QString subwindowTitle = QString::fromStdString(subpair.first);\n                QWidget *subwindow = subpair.second;\n                \n                QAction *subwindowAction = ui->menuWindow->addAction(subwindowTitle.prepend(\"    \"), subwindow, [subwindow]() { QtSLiMMakeWindowVisibleAndExposed(subwindow); });\n                subwindowAction->setCheckable(subwindow == activeWindow);  // only set checkable if checked, to avoid the empty checkbox on Ubuntu\n                subwindowAction->setChecked(subwindow == activeWindow);\n                subwindowAction->setObjectName(\"__QtSLiM_subwindow__\");\n            }\n        }\n    }\n}\n\n\n//\n//  profiling\n//\n\n#if (SLIMPROFILING == 1)\n\nvoid QtSLiMWindow::colorScriptWithProfileCountsFromNode(const EidosASTNode *node, double elapsedTime, int32_t baseIndex, QTextDocument *doc, QTextCharFormat &baseFormat)\n{\n    // First color the range for this node\n\teidos_profile_t count = node->profile_total_;\n\t\n\tif (count > 0)\n\t{\n\t\tint32_t start = 0, end = 0;\n\t\t\n\t\tnode->FullUTF16Range(&start, &end);\n\t\t\n\t\tstart -= baseIndex;\n\t\tend -= baseIndex;\n\t\t\n\t\tQTextCursor colorCursor(doc);\n        colorCursor.setPosition(start);\n        colorCursor.setPosition(end + 1, QTextCursor::KeepAnchor);\n        \n        QColor backgroundColor = slimColorForFraction(Eidos_ElapsedProfileTime(count) / elapsedTime);\n\t\tQTextCharFormat colorFormat = baseFormat;\n        \n        colorFormat.setBackground(backgroundColor);\n        colorCursor.setCharFormat(colorFormat);\n\t}\n\t\n\t// Then let child nodes color\n\tfor (const EidosASTNode *child : node->children_)\n        colorScriptWithProfileCountsFromNode(child, elapsedTime, baseIndex, doc, baseFormat);\n}\n\nvoid QtSLiMWindow::displayProfileResults(void)\n{\n    // Make a new window to show the profile results\n    QWidget *profile_window = new QWidget(this, Qt::Window);    // the profile window has us as a parent, but is still a standalone window\n    QString title = profile_window->windowTitle();\n    \n    if (title.length() == 0)\n        title = \"Untitled\";\n    \n    profile_window->setWindowTitle(\"Profile Report for \" + title);\n    profile_window->setMinimumSize(500, 200);\n    profile_window->resize(500, 600);\n    profile_window->move(50, 50);\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    profile_window->setWindowIcon(QIcon());\n#endif\n    \n    // make window actions for all global menu items\n    qtSLiMAppDelegate->addActionsForGlobalMenuItems(profile_window);\n    \n    // Make a QPlainTextEdit to hold the results\n    QHBoxLayout *window_layout = new QHBoxLayout;\n    QPlainTextEdit *textEdit = new QPlainTextEdit();\n    \n    profile_window->setLayout(window_layout);\n    \n    window_layout->setContentsMargins(0, 0, 0, 0);\n    window_layout->setSpacing(0);\n    window_layout->addWidget(textEdit);\n    \n    textEdit->setFrameStyle(QFrame::NoFrame);\n    textEdit->setReadOnly(true);\n    \n    // Change the background color for the palette to white (rather than letting it be black when in dark mode)\n    QPalette p = textEdit->palette();\n    p.setColor(QPalette::Active, QPalette::Base, Qt::white);\n    textEdit->setPalette(p);\n    textEdit->setBackgroundVisible(false);\n    \n    // Make the text document that will hold the profile results\n    QTextDocument *doc = textEdit->document();\n    QTextCursor tc = textEdit->textCursor();\n    \n    doc->setDocumentMargin(10);\n    \n    // Choose our fonts; the variable names here are historical, they are not necessarily menlo/optima...\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    QFont menlo11(prefs.displayFontPref());\n    qreal displayFontSize = menlo11.pointSizeF();\n    qreal scaleFactor = displayFontSize / 11.0;     // The unscaled sizes are geared toward Optima on the Mac\n    \n#if defined(__linux__)\n    // On Linux font sizes seem to run large, who knows why, so reduce the scale factor somewhat to compensate\n    scaleFactor *= 0.75;\n#endif\n\n    QFont optimaFont;\n    {\n        // We want a body font of Optima on the Mac; on non-Mac platforms we'll just use the default system font for now\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n        QFontDatabase fontdb;\n        QStringList families = fontdb.families();\n#else\n        QStringList families = QFontDatabase::families();\n#endif\n        \n        // Use filter() to look for matches, since the foundry can be appended after the name (why isn't this easier??)\n        if (families.filter(\"Optima\").size() > 0)              // good on Mac\n            optimaFont = QFont(\"Optima\", 13);\n    }\n    \n    QFont optima18b(optimaFont);\n    QFont optima14b(optimaFont);\n    QFont optima13(optimaFont);\n    QFont optima13i(optimaFont);\n    QFont optima8(optimaFont);\n    QFont optima3(optimaFont);\n    \n    optima18b.setPointSizeF(scaleFactor * 18);\n    optima18b.setWeight(QFont::Bold);\n    optima14b.setPointSizeF(scaleFactor * 14);\n    optima14b.setWeight(QFont::Bold);\n    optima13.setPointSizeF(scaleFactor * 13);\n    optima13i.setPointSizeF(scaleFactor * 13);\n    optima13i.setItalic(true);\n    optima8.setPointSizeF(scaleFactor * 8);\n    optima3.setPointSizeF(scaleFactor * 3);\n    \n    // Make the QTextCharFormat objects we will use.  Note that we override the usual foreground/background colors\n    // that come from light/dark mode; because we change the background color of text, we want to use a balck-on-white\n    // base palette whether we are in light or dark mode, otherwise things get complicated, especially since the user\n    // might switch between light/dark after the profile is displayed\n    QTextCharFormat optima18b_d, optima14b_d, optima13_d, optima13i_d, optima8_d, optima3_d, menlo11_d;\n    \n    optima18b_d.setFont(optima18b);\n    optima14b_d.setFont(optima14b);\n    optima13_d.setFont(optima13);\n    optima13i_d.setFont(optima13i);\n    optima8_d.setFont(optima8);\n    optima3_d.setFont(optima3);\n    menlo11_d.setFont(menlo11);\n    \n    optima18b_d.setBackground(Qt::white);\n    optima14b_d.setBackground(Qt::white);\n    optima13_d.setBackground(Qt::white);\n    optima13i_d.setBackground(Qt::white);\n    optima8_d.setBackground(Qt::white);\n    optima3_d.setBackground(Qt::white);\n    menlo11_d.setBackground(Qt::white);\n    \n    optima18b_d.setForeground(Qt::black);\n    optima14b_d.setForeground(Qt::black);\n    optima13_d.setForeground(Qt::black);\n    optima13i_d.setForeground(Qt::black);\n    optima8_d.setForeground(Qt::black);\n    optima3_d.setForeground(Qt::black);\n    menlo11_d.setForeground(Qt::black);\n    \n    // Adjust the tab width to the monospace font we have chosen\n    double tabWidth = 0;\n    QFontMetricsF fm(menlo11);\n    \n#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))\n    tabWidth = fm.width(\"   \");                // deprecated in 5.11\n#else\n    tabWidth = fm.horizontalAdvance(\"   \");    // added in Qt 5.11\n#endif\n    \n#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))\n    textEdit->setTabStopWidth((int)floor(tabWidth));      // deprecated in 5.10\n#else\n    textEdit->setTabStopDistance(tabWidth);               // added in 5.10\n#endif\n    \n    // Build the report attributed string\n    QDateTime profileStartDate = QDateTime::fromSecsSinceEpoch(community->profile_start_date);\n\tQDateTime profileEndDate = QDateTime::fromSecsSinceEpoch(community->profile_end_date);\n\t\n    QString startDateString = profileStartDate.toString(\"M/d/yy, h:mm:ss AP\");\n    QString endDateString = profileEndDate.toString(\"M/d/yy, h:mm:ss AP\");\n\tdouble elapsedWallClockTime = (std::chrono::duration_cast<std::chrono::microseconds>(community->profile_end_clock - community->profile_start_clock).count()) / (double)1000000L;\n    double elapsedCPUTimeInSLiM = community->profile_elapsed_CPU_clock / static_cast<double>(CLOCKS_PER_SEC);\n\tdouble elapsedWallClockTimeInSLiM = Eidos_ElapsedProfileTime(community->profile_elapsed_wall_clock);\n\tslim_tick_t elapsedSLiMTicks = community->profile_end_tick - community->profile_start_tick;\n    \n    tc.insertText(\"Profile Report\\n\", optima18b_d);\n    tc.insertText(\" \\n\", optima3_d);\n    \n    tc.insertText(\"Model: \" + title + \"\\n\", optima13_d);\n    tc.insertText(\" \\n\", optima8_d);\n    \n    tc.insertText(\"Run start: \" + startDateString + \"\\n\", optima13_d);\n    tc.insertText(\"Run end: \" + endDateString + \"\\n\", optima13_d);\n    tc.insertText(\" \\n\", optima8_d);\n    \n#ifdef _OPENMP\n    tc.insertText(QString(\"Maximum parallel threads: %1\\n\").arg(gEidosMaxThreads), optima13_d);\n    tc.insertText(\" \\n\", optima8_d);\n#endif\n    \n    tc.insertText(QString(\"Elapsed wall clock time: %1 s\\n\").arg(elapsedWallClockTime, 0, 'f', 2), optima13_d);\n    tc.insertText(QString(\"Elapsed wall clock time inside SLiM core (corrected): %1 s\\n\").arg(elapsedWallClockTimeInSLiM, 0, 'f', 2), optima13_d);\n    tc.insertText(QString(\"Elapsed CPU time inside SLiM core (uncorrected): %1 s\\n\").arg(elapsedCPUTimeInSLiM, 0, 'f', 2), optima13_d);\n    tc.insertText(QString(\"Elapsed ticks: %1%2\\n\").arg(elapsedSLiMTicks).arg((community->profile_start_tick == 0) ? \" (including initialize)\" : \"\"), optima13_d);\n    tc.insertText(\" \\n\", optima8_d);\n    \n    tc.insertText(QString(\"Profile block external overhead: %1 ticks (%2 s)\\n\").arg(gEidos_ProfileOverheadTicks, 0, 'f', 2).arg(gEidos_ProfileOverheadSeconds, 0, 'g', 4), optima13_d);\n    tc.insertText(QString(\"Profile block internal lag: %1 ticks (%2 s)\\n\").arg(gEidos_ProfileLagTicks, 0, 'f', 2).arg(gEidos_ProfileLagSeconds, 0, 'g', 4), optima13_d);\n    tc.insertText(\" \\n\", optima8_d);\n    \n    size_t total_usage = community->profile_total_memory_usage_Community.totalMemoryUsage + community->profile_total_memory_usage_AllSpecies.totalMemoryUsage;\n\tsize_t average_usage = total_usage / community->total_memory_tallies_;\n\tsize_t last_usage = community->profile_last_memory_usage_Community.totalMemoryUsage + community->profile_last_memory_usage_AllSpecies.totalMemoryUsage;\n\t\n    tc.insertText(QString(\"Average tick SLiM memory use: %1\\n\").arg(stringForByteCount(average_usage)), optima13_d);\n    tc.insertText(QString(\"Final tick SLiM memory use: %1\\n\").arg(stringForByteCount(last_usage)), optima13_d);\n    \n\t//\n\t//\tCycle stage breakdown\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tbool isWF = (community->ModelType() == SLiMModelType::kModelTypeWF);\n\t\tdouble elapsedStage0Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[0]);\n\t\tdouble elapsedStage1Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[1]);\n\t\tdouble elapsedStage2Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[2]);\n\t\tdouble elapsedStage3Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[3]);\n\t\tdouble elapsedStage4Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[4]);\n\t\tdouble elapsedStage5Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[5]);\n\t\tdouble elapsedStage6Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[6]);\n        double elapsedStage7Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[7]);\n        double elapsedStage8Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[8]);\n\t\tdouble percentStage0 = (elapsedStage0Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage1 = (elapsedStage1Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage2 = (elapsedStage2Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage3 = (elapsedStage3Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage4 = (elapsedStage4Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage5 = (elapsedStage5Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage6 = (elapsedStage6Time / elapsedWallClockTimeInSLiM) * 100.0;\n        double percentStage7 = (elapsedStage7Time / elapsedWallClockTimeInSLiM) * 100.0;\n        double percentStage8 = (elapsedStage8Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage0Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage1Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage2Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage3Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage4Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage5Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage6Time));\n        fw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage7Time));\n        fw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage8Time));\n\t\t\n\t\ttc.insertText(\" \\n\", optima13_d);\n\t\ttc.insertText(\"Cycle stage breakdown\\n\", optima14b_d);\n\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage0Time, fw, 'f', 2).arg(percentStage0, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText(\" : initialize() callback execution\\n\", optima13_d);\n\t\t\n        tc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage1Time, fw, 'f', 2).arg(percentStage1, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 0 – first() event execution\\n\" : \" : stage 0 – first() event execution\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage2Time, fw, 'f', 2).arg(percentStage2, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 1 – early() event execution\\n\" : \" : stage 1 – offspring generation\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage3Time, fw, 'f', 2).arg(percentStage3, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 2 – offspring generation\\n\" : \" : stage 2 – early() event execution\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage4Time, fw, 'f', 2).arg(percentStage4, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 3 – generation swap\\n\" : \" : stage 3 – fitness calculation\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage5Time, fw, 'f', 2).arg(percentStage5, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 4 – bookkeeping (fixed mutation removal, etc.)\\n\" : \" : stage 4 – viability/survival selection\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage6Time, fw, 'f', 2).arg(percentStage6, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 5 – late() event execution\\n\" : \" : stage 5 – bookkeeping (fixed mutation removal, etc.)\\n\"), optima13_d);\n\t\t\n\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage7Time, fw, 'f', 2).arg(percentStage7, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 6 – fitness calculation\\n\" : \" : stage 6 – late() event execution\\n\"), optima13_d);\n        \n        tc.insertText(QString(\"%1 s (%2%)\").arg(elapsedStage8Time, fw, 'f', 2).arg(percentStage8, 5, 'f', 2), menlo11_d);\n\t\ttc.insertText((isWF ? \" : stage 7 – tree sequence auto-simplification\\n\" : \" : stage 7 – tree sequence auto-simplification\\n\"), optima13_d);\n\t}\n\t\n\t//\n\t//\tCallback type breakdown\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n        double elapsedTime_first = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventFirst]);\n\t\tdouble elapsedTime_early = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventEarly]);\n\t\tdouble elapsedTime_late = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventLate]);\n\t\tdouble elapsedTime_initialize = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInitializeCallback]);\n\t\tdouble elapsedTime_mutationEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationEffectCallback]);\n\t\tdouble elapsedTime_fitnessEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosFitnessEffectCallback]);\n\t\tdouble elapsedTime_interaction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInteractionCallback]);\n\t\tdouble elapsedTime_matechoice = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMateChoiceCallback]);\n\t\tdouble elapsedTime_modifychild = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosModifyChildCallback]);\n\t\tdouble elapsedTime_recombination = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosRecombinationCallback]);\n\t\tdouble elapsedTime_mutation = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationCallback]);\n\t\tdouble elapsedTime_reproduction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosReproductionCallback]);\n        double elapsedTime_survival = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosSurvivalCallback]);\n\t\tdouble percent_first = (elapsedTime_first / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_early = (elapsedTime_early / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_late = (elapsedTime_late / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_initialize = (elapsedTime_initialize / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitness = (elapsedTime_mutationEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitnessglobal = (elapsedTime_fitnessEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_interaction = (elapsedTime_interaction / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_matechoice = (elapsedTime_matechoice / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_modifychild = (elapsedTime_modifychild / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_recombination = (elapsedTime_recombination / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_mutation = (elapsedTime_mutation / elapsedWallClockTimeInSLiM) * 100.0;\n        double percent_reproduction = (elapsedTime_reproduction / elapsedWallClockTimeInSLiM) * 100.0;\n        double percent_survival = (elapsedTime_survival / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4, fw2 = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_first));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_early));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_late));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_initialize));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutationEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_fitnessEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_interaction));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_matechoice));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_modifychild));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_recombination));\n        fw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutation));\n        fw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_reproduction));\n        fw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_survival));\n\t\t\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_first));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_early));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_late));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_initialize));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitness));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitnessglobal));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_interaction));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_matechoice));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_modifychild));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_recombination));\n        fw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_mutation));\n        fw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_reproduction));\n        fw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_survival));\n\t\t\n\t\ttc.insertText(\" \\n\", optima13_d);\n\t\ttc.insertText(\"Callback type breakdown\\n\", optima14b_d);\n\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\n\t\t// Note these are out of numeric order, but in cycle stage order\n\t\tif (community->ModelType() == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_initialize, fw, 'f', 2).arg(percent_initialize, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : initialize() callbacks\\n\", optima13_d);\n\t\t\t\n            tc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_first, fw, 'f', 2).arg(percent_first, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : first() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_early, fw, 'f', 2).arg(percent_early, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : early() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_matechoice, fw, 'f', 2).arg(percent_matechoice, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : mateChoice() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_recombination, fw, 'f', 2).arg(percent_recombination, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : recombination() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_mutation, fw, 'f', 2).arg(percent_mutation, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : mutation() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_modifychild, fw, 'f', 2).arg(percent_modifychild, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : modifyChild() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_late, fw, 'f', 2).arg(percent_late, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : late() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_mutationEffect, fw, 'f', 2).arg(percent_fitness, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : mutationEffect() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_fitnessEffect, fw, 'f', 2).arg(percent_fitnessglobal, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : fitnessEffect() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_interaction, fw, 'f', 2).arg(percent_interaction, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : interaction() callbacks\\n\", optima13_d);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_initialize, fw, 'f', 2).arg(percent_initialize, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : initialize() callbacks\\n\", optima13_d);\n\t\t\t\n            tc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_first, fw, 'f', 2).arg(percent_first, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : first() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_reproduction, fw, 'f', 2).arg(percent_reproduction, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : reproduction() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_recombination, fw, 'f', 2).arg(percent_recombination, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : recombination() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_mutation, fw, 'f', 2).arg(percent_mutation, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : mutation() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_modifychild, fw, 'f', 2).arg(percent_modifychild, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : modifyChild() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_early, fw, 'f', 2).arg(percent_early, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : early() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_mutationEffect, fw, 'f', 2).arg(percent_fitness, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : mutationEffect() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_fitnessEffect, fw, 'f', 2).arg(percent_fitnessglobal, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : fitnessEffect() callbacks\\n\", optima13_d);\n\t\t\t\n            tc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_survival, fw, 'f', 2).arg(percent_survival, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : survival() callbacks\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_late, fw, 'f', 2).arg(percent_late, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : late() events\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(QString(\"%1 s (%2%)\").arg(elapsedTime_interaction, fw, 'f', 2).arg(percent_interaction, fw2, 'f', 2), menlo11_d);\n\t\t\ttc.insertText(\" : interaction() callbacks\\n\", optima13_d);\n\t\t}\n\t}\n\t\n\t//\n\t//\tScript block profiles\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\t{\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\t\n\t\t\t// Convert the profile counts in all script blocks into self counts (excluding the counts of nodes below them)\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t\tif (script_block->type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\t\t// exclude function blocks; not user-visible\n\t\t\t\t\tscript_block->root_node_->ConvertProfileTotalsToSelfCounts();\n\t\t}\n\t\t{\n\t\t\ttc.insertText(\" \\n\", optima13_d);\n\t\t\ttc.insertText(\"Script block profiles (as a fraction of corrected wall clock time)\\n\", optima14b_d);\n\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\ttc.insertText(\" \\n \\n\", menlo11_d);\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tQString script_string = QString::fromStdString(script_std_string);\n\t\t\t\t\t\n\t\t\t\t\ttc.insertText(QString(\"%1 s (%2%):\\n\").arg(total_block_time, 0, 'f', 2).arg(percent_block_time, 0, 'f', 2), menlo11_d);\n\t\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\t\t\n                    int colorBase = tc.position();\n                    tc.insertText(script_string, menlo11_d);\n                    colorScriptWithProfileCountsFromNode(profile_root, elapsedWallClockTimeInSLiM, profile_root->token_->token_UTF16_start_ - colorBase, doc, menlo11_d);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\ttc.insertText(\"(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\", optima13i_d);\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\ttc.insertText(\" \\n\", optima13_d);\n\t\t\ttc.insertText(\"Script block profiles (as a fraction of within-block wall clock time)\\n\", optima14b_d);\n\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\ttc.insertText(\" \\n \\n\", menlo11_d);\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n                    QString script_string = QString::fromStdString(script_std_string);\n\t\t\t\t\t\n\t\t\t\t\ttc.insertText(QString(\"%1 s (%2%):\\n\").arg(total_block_time, 0, 'f', 2).arg(percent_block_time, 0, 'f', 2), menlo11_d);\n\t\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\t\t\n                    int colorBase = tc.position();\n                    tc.insertText(script_string, menlo11_d);\n                    if (total_block_time > 0.0)\n                        colorScriptWithProfileCountsFromNode(profile_root, total_block_time, profile_root->token_->token_UTF16_start_ - colorBase, doc, menlo11_d);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\ttc.insertText(\"(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\", optima13i_d);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//\n\t//\tUser-defined functions (if any)\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tEidosFunctionMap &function_map = community->FunctionMap();\n\t\tstd::vector<const EidosFunctionSignature *> userDefinedFunctions;\n\t\t\n\t\tfor (const auto &functionPairIter : function_map)\n\t\t{\n\t\t\tconst EidosFunctionSignature *signature = functionPairIter.second.get();\n\t\t\t\n\t\t\tif (signature->body_script_ && signature->user_defined_)\n\t\t\t{\n\t\t\t\tsignature->body_script_->AST()->ConvertProfileTotalsToSelfCounts();\n\t\t\t\tuserDefinedFunctions.emplace_back(signature);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\ttc.insertText(\" \\n\", optima13_d);\n\t\t\ttc.insertText(\"User-defined functions (as a fraction of corrected wall clock time)\\n\", optima14b_d);\n\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\ttc.insertText(\" \\n \\n\", menlo11_d);\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tQString script_string = QString::fromStdString(script_std_string);\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\tQString signatureString = QString::fromStdString(signature_string);\n\t\t\t\t\t\n\t\t\t\t\ttc.insertText(QString(\"%1 s (%2%):\\n\").arg(total_block_time, 0, 'f', 2).arg(percent_block_time, 0, 'f', 2), menlo11_d);\n\t\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\t\ttc.insertText(signatureString + \"\\n\", menlo11_d);\n\t\t\t\t\t\n                    int colorBase = tc.position();\n                    tc.insertText(script_string, menlo11_d);\n                    colorScriptWithProfileCountsFromNode(profile_root, elapsedWallClockTimeInSLiM, profile_root->token_->token_UTF16_start_ - colorBase, doc, menlo11_d);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\ttc.insertText(\"(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\", optima13i_d);\n\t\t\t}\n\t\t}\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\ttc.insertText(\" \\n\", optima13_d);\n\t\t\ttc.insertText(\"User-defined functions (as a fraction of within-block wall clock time)\\n\", optima14b_d);\n\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\ttc.insertText(\" \\n \\n\", menlo11_d);\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tQString script_string = QString::fromStdString(script_std_string);\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\tQString signatureString = QString::fromStdString(signature_string);\n\t\t\t\t\t\n\t\t\t\t\ttc.insertText(QString(\"%1 s (%2%):\\n\").arg(total_block_time, 0, 'f', 2).arg(percent_block_time, 0, 'f', 2), menlo11_d);\n\t\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\t\ttc.insertText(signatureString + \"\\n\", menlo11_d);\n\t\t\t\t\t\n                    int colorBase = tc.position();\n                    tc.insertText(script_string, menlo11_d);\n                    if (total_block_time > 0.0)\n                        colorScriptWithProfileCountsFromNode(profile_root, total_block_time, profile_root->token_->token_UTF16_start_ - colorBase, doc, menlo11_d);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\ttc.insertText(\" \\n\", menlo11_d);\n\t\t\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\t\ttc.insertText(\"(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\", optima13i_d);\n\t\t\t}\n\t\t}\n\t}\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t//\n\t//\tMutationRun metrics, presented per Species\n\t//\n    for (Species *focal_species : community->all_species_)\n\t{\n        tc.insertText(\" \\n\", menlo11_d);\n\t\ttc.insertText(\" \\n\", optima13_d);\n\t\ttc.insertText(\"MutationRun usage\", optima14b_d);\n        if (community->all_species_.size() > 1)\n        {\n            tc.insertText(\" (\", optima14b_d);\n            tc.insertText(QString::fromStdString(focal_species->avatar_), optima14b_d);\n            tc.insertText(\" \", optima14b_d);\n            tc.insertText(QString::fromStdString(focal_species->name_), optima14b_d);\n            tc.insertText(\")\", optima14b_d);\n        }\n        tc.insertText(\"\\n\", optima14b_d);\n\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\n        if (!focal_species->HasGenetics())\n        {\n            tc.insertText(\"(omitted for no-genetics species)\", optima13i_d);\n            continue;\n        }\n        \n        {\n            int64_t regime_tallies[3];\n            int64_t regime_tallies_total = static_cast<int>(focal_species->profile_nonneutral_regime_history_.size());\n            \n            for (int regime = 0; regime < 3; ++regime)\n                regime_tallies[regime] = 0;\n            \n            for (int32_t regime : focal_species->profile_nonneutral_regime_history_)\n                if ((regime >= 1) && (regime <= 3))\n                    regime_tallies[regime - 1]++;\n                else\n                    regime_tallies_total--;\n            \n            for (int regime = 0; regime < 3; ++regime)\n            {\n                tc.insertText(QString(\"%1%\").arg((regime_tallies[regime] / static_cast<double>(regime_tallies_total)) * 100.0, 6, 'f', 2), menlo11_d);\n                tc.insertText(QString(\" of ticks : regime %1 (%2)\\n\").arg(regime + 1).arg(regime == 0 ? \"no mutationEffect() callbacks\" : (regime == 1 ? \"constant neutral mutationEffect() callbacks only\" : \"unpredictable mutationEffect() callbacks present\")), optima13_d);\n            }\n            \n            tc.insertText(\" \\n\", optima8_d);\n        }\n\t\t\n        tc.insertText(QString(\"%1\").arg(focal_species->profile_max_mutation_index_), menlo11_d);\n\t\ttc.insertText(\" maximum simultaneous mutations\\n\", optima13_d);\n        \n        \n        const std::vector<Chromosome *> &chromosomes = focal_species->Chromosomes();\n\t\t\n\t\tfor (Chromosome *focal_chromosome : chromosomes)\n\t\t{\n            tc.insertText(\" \\n\", optima13_d);\n            tc.insertText(\"Chromosome \", optima13i_d);\n            tc.insertText(QString::fromStdString(focal_chromosome->Symbol()), optima13i_d);\n            tc.insertText(\":\\n\", optima13i_d);\n            tc.insertText(\" \\n\", optima3_d);\n            \n            {\n                int64_t power_tallies[20];\t// we only go up to 1024 mutruns right now, but this gives us some headroom\n                int64_t power_tallies_total = static_cast<int>(focal_chromosome->profile_mutcount_history_.size());\n                \n                for (int power = 0; power < 20; ++power)\n                    power_tallies[power] = 0;\n                \n                for (int32_t count : focal_chromosome->profile_mutcount_history_)\n                {\n                    int power = static_cast<int>(round(log2(count)));\n                    \n                    power_tallies[power]++;\n                }\n                \n                for (int power = 0; power < 20; ++power)\n                {\n                    if (power_tallies[power] > 0)\n                    {\n                        tc.insertText(QString(\"%1%\").arg((power_tallies[power] / static_cast<double>(power_tallies_total)) * 100.0, 6, 'f', 2), menlo11_d);\n                        tc.insertText(QString(\" of ticks : %1 mutation runs per haplosome\\n\").arg(static_cast<int>(round(pow(2.0, power)))), optima13_d);\n                    }\n                }\n            }\n            \n            tc.insertText(\" \\n\", optima8_d);\n            \n            tc.insertText(QString(\"%1\").arg(focal_chromosome->profile_mutation_total_usage_), menlo11_d);\n            tc.insertText(\" mutations referenced, summed across all ticks\\n\", optima13_d);\n            \n            tc.insertText(QString(\"%1\").arg(focal_chromosome->profile_nonneutral_mutation_total_), menlo11_d);\n            tc.insertText(\" mutations considered potentially nonneutral\\n\", optima13_d);\n            \n            tc.insertText(QString(\"%1%\").arg(((focal_chromosome->profile_mutation_total_usage_ - focal_chromosome->profile_nonneutral_mutation_total_) / static_cast<double>(focal_chromosome->profile_mutation_total_usage_)) * 100.0, 0, 'f', 2), menlo11_d);\n            tc.insertText(\" of mutations excluded from fitness calculations\\n\", optima13_d);\n            \n            \n            tc.insertText(\" \\n\", optima8_d);\n            \n            tc.insertText(QString(\"%1\").arg(focal_chromosome->profile_mutrun_total_usage_), menlo11_d);\n            tc.insertText(\" mutation runs referenced, summed across all ticks\\n\", optima13_d);\n            \n            tc.insertText(QString(\"%1\").arg(focal_chromosome->profile_unique_mutrun_total_), menlo11_d);\n            tc.insertText(\" unique mutation runs maintained among those\\n\", optima13_d);\n            \n            tc.insertText(QString(\"%1%\").arg((focal_chromosome->profile_mutrun_nonneutral_recache_total_ / static_cast<double>(focal_chromosome->profile_unique_mutrun_total_)) * 100.0, 6, 'f', 2), menlo11_d);\n            tc.insertText(\" of mutation run nonneutral caches rebuilt per tick\\n\", optima13_d);\n            \n            tc.insertText(QString(\"%1%\").arg(((focal_chromosome->profile_mutrun_total_usage_ - focal_chromosome->profile_unique_mutrun_total_) / static_cast<double>(focal_chromosome->profile_mutrun_total_usage_)) * 100.0, 6, 'f', 2), menlo11_d);\n            tc.insertText(\" of mutation runs shared among haplosomes\\n\", optima13_d);\n        }\n\t}\n#endif\n\t\n\t{\n\t\t//\n\t\t//\tMemory usage metrics\n\t\t//\n        SLiMMemoryUsage_Community &mem_tot_C = community->profile_total_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_tot_S = community->profile_total_memory_usage_AllSpecies;\n\t\tSLiMMemoryUsage_Community &mem_last_C = community->profile_last_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_last_S = community->profile_last_memory_usage_AllSpecies;\n\t\tuint64_t div = static_cast<uint64_t>(community->total_memory_tallies_);\n\t\tdouble ddiv = community->total_memory_tallies_;\n        double average_total = (mem_tot_C.totalMemoryUsage + mem_tot_S.totalMemoryUsage) / ddiv;\n\t\tdouble final_total = mem_last_C.totalMemoryUsage + mem_last_S.totalMemoryUsage;\n\t\t\n\t\ttc.insertText(\" \\n\", optima13_d);\n\t\ttc.insertText(\"SLiM memory usage (average / final tick)\\n\", optima14b_d);\n\t\ttc.insertText(\" \\n\", optima3_d);\n\t\t\n        QTextCharFormat colored_menlo = menlo11_d;\n        \n\t\t// Chromosome\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.chromosomeObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.chromosomeObjects, final_total, colored_menlo), colored_menlo);\n        tc.insertText(QString(\" : Chromosome objects (%1 / %2)\\n\").arg(mem_tot_S.chromosomeObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.chromosomeObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.chromosomeMutationRateMaps / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.chromosomeMutationRateMaps, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : mutation rate maps\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.chromosomeRecombinationRateMaps / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.chromosomeRecombinationRateMaps, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : recombination rate maps\\n\", optima13_d);\n\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.chromosomeAncestralSequence / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.chromosomeAncestralSequence, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : ancestral nucleotides\\n\", optima13_d);\n\t\t\n        // Community\n        tc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.communityObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.communityObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : Community object\\n\", optima13_d);\n\t\t\n\t\t// Haplosome\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.haplosomeObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.haplosomeObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : Haplosome objects (%1 / %2)\\n\").arg(mem_tot_S.haplosomeObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.haplosomeObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.haplosomeExternalBuffers / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.haplosomeExternalBuffers, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : external MutationRun* buffers\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.haplosomeUnusedPoolSpace / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.haplosomeUnusedPoolSpace, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool space\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.haplosomeUnusedPoolBuffers / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.haplosomeUnusedPoolBuffers, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool buffers\\n\", optima13_d);\n\t\t\n\t\t// GenomicElement\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.genomicElementObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.genomicElementObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : GenomicElement objects (%1 / %2)\\n\").arg(mem_tot_S.genomicElementObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.genomicElementObjects_count), optima13_d);\n\t\t\n\t\t// GenomicElementType\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.genomicElementTypeObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.genomicElementTypeObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : GenomicElementType objects (%1 / %2)\\n\").arg(mem_tot_S.genomicElementTypeObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.genomicElementTypeObjects_count), optima13_d);\n\t\t\n\t\t// Individual\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.individualObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.individualObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : Individual objects (%1 / %2)\\n\").arg(mem_tot_S.individualObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.individualObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.individualHaplosomeVectors / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.individualHaplosomeVectors, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : external Haplosome* buffers\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.individualJunkyardAndHaplosomes / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.individualJunkyardAndHaplosomes, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : individuals awaiting reuse\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.individualUnusedPoolSpace / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.individualUnusedPoolSpace, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool space\\n\", optima13_d);\n\t\t\n\t\t// InteractionType\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.interactionTypeObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.interactionTypeObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : InteractionType objects (%1 / %2)\\n\").arg(mem_tot_C.interactionTypeObjects_count / ddiv, 0, 'f', 2).arg(mem_last_C.interactionTypeObjects_count), optima13_d);\n\t\t\n\t\tif (mem_tot_C.interactionTypeObjects_count || mem_last_C.interactionTypeObjects_count)\n\t\t{\n\t\t\ttc.insertText(\"   \", menlo11_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.interactionTypeKDTrees / div, average_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" / \", optima13_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_last_C.interactionTypeKDTrees, final_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" : k-d trees\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(\"   \", menlo11_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.interactionTypePositionCaches / div, average_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" / \", optima13_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_last_C.interactionTypePositionCaches, final_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" : position caches\\n\", optima13_d);\n\t\t\t\n\t\t\ttc.insertText(\"   \", menlo11_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.interactionTypeSparseVectorPool / div, average_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" / \", optima13_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_last_C.interactionTypeSparseVectorPool, final_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" : sparse arrays\\n\", optima13_d);\n\t\t}\n\t\t\n\t\t// Mutation\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : Mutation objects (%1 / %2)\\n\").arg(mem_tot_S.mutationObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.mutationObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.mutationRefcountBuffer / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.mutationRefcountBuffer, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : refcount buffer\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.mutationUnusedPoolSpace / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.mutationUnusedPoolSpace, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool space\\n\", optima13_d);\n\t\t\n\t\t// MutationRun\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationRunObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationRunObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : MutationRun objects (%1 / %2)\\n\").arg(mem_tot_S.mutationRunObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.mutationRunObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationRunExternalBuffers / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationRunExternalBuffers, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : external MutationIndex buffers\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationRunNonneutralCaches / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationRunNonneutralCaches, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : nonneutral mutation caches\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationRunUnusedPoolSpace / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationRunUnusedPoolSpace, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool space\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationRunUnusedPoolBuffers / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationRunUnusedPoolBuffers, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : unused pool buffers\\n\", optima13_d);\n\t\t\n\t\t// MutationType\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.mutationTypeObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.mutationTypeObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : MutationType objects (%1 / %2)\\n\").arg(mem_tot_S.mutationTypeObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.mutationTypeObjects_count), optima13_d);\n\t\t\n\t\t// Species\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.speciesObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.speciesObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : Species objects\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.speciesTreeSeqTables / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.speciesTreeSeqTables, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : tree-sequence tables\\n\", optima13_d);\n\t\t\n\t\t// Subpopulation\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.subpopulationObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.subpopulationObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : Subpopulation objects (%1 / %2)\\n\").arg(mem_tot_S.subpopulationObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.subpopulationObjects_count), optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.subpopulationFitnessCaches / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.subpopulationFitnessCaches, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : fitness caches\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.subpopulationParentTables / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.subpopulationParentTables, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : parent tables\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.subpopulationSpatialMaps / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.subpopulationSpatialMaps, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : spatial maps\\n\", optima13_d);\n\t\t\n\t\tif (mem_tot_S.subpopulationSpatialMapsDisplay || mem_last_S.subpopulationSpatialMapsDisplay)\n\t\t{\n\t\t\ttc.insertText(\"   \", menlo11_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.subpopulationSpatialMapsDisplay / div, average_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" / \", optima13_d);\n\t\t\ttc.insertText(attributedStringForByteCount(mem_last_S.subpopulationSpatialMapsDisplay, final_total, colored_menlo), colored_menlo);\n\t\t\ttc.insertText(\" : spatial map display (SLiMgui only)\\n\", optima13_d);\n\t\t}\n\t\t\n\t\t// Substitution\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_S.substitutionObjects / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_S.substitutionObjects, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(QString(\" : Substitution objects (%1 / %2)\\n\").arg(mem_tot_S.substitutionObjects_count / ddiv, 0, 'f', 2).arg(mem_last_S.substitutionObjects_count), optima13_d);\n\t\t\n\t\t// Eidos\n\t\ttc.insertText(\" \\n\", optima8_d);\n\t\ttc.insertText(\"Eidos:\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.eidosASTNodePool / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.eidosASTNodePool, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : EidosASTNode pool\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.eidosSymbolTablePool / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.eidosSymbolTablePool, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : EidosSymbolTable pool\\n\", optima13_d);\n\t\t\n\t\ttc.insertText(\"   \", menlo11_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_tot_C.eidosValuePool / div, average_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" / \", optima13_d);\n\t\ttc.insertText(attributedStringForByteCount(mem_last_C.eidosValuePool, final_total, colored_menlo), colored_menlo);\n\t\ttc.insertText(\" : EidosValue pool\\n\", optima13_d);\n        \n        tc.insertText(\"   \", menlo11_d);\n        tc.insertText(attributedStringForByteCount(mem_tot_C.fileBuffers / div, average_total, colored_menlo), colored_menlo);\n        tc.insertText(\" / \", optima13_d);\n        tc.insertText(attributedStringForByteCount(mem_last_C.fileBuffers, final_total, colored_menlo), colored_menlo);\n        tc.insertText(\" : File buffers\", optima13_d);\n    }\n    \n    // Done, show the window\n    tc.setPosition(0);\n    textEdit->setTextCursor(tc);\n    profile_window->show();    \n}\n\n#endif\t// (SLIMPROFILING == 1)\n\n\n//\n//  simulation play mechanics\n//\n\nvoid QtSLiMWindow::willExecuteScript(void)\n{\n    // Whenever we are about to execute script, we swap in our random number generator; at other times, gEidos_rng is NULL.\n    // The goal here is to keep each SLiM window independent in its random number sequence.\n    if (gEidos_RNG_Initialized)\n        qDebug() << \"eidosConsoleWindowControllerWillExecuteScript: gEidos_rng already set up!\";\n\n    if (!sim_RNG_initialized)\n        qDebug() << \"sim_RNG is not yet set up!\";\n    \n\tstd::swap(sim_RNG, gEidos_RNG_SINGLE);\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\n    // We also swap in the pedigree id and mutation id counters; each SLiMgui window is independent\n    gSLiM_next_pedigree_id = sim_next_pedigree_id;\n    gSLiM_next_mutation_id = sim_next_mutation_id;\n    gEidosSuppressWarnings = sim_suppress_warnings;\n\n    // Set the current directory to its value for this window\n    errno = 0;\n    int retval = chdir(sim_working_dir.c_str());\n\n    if (retval == -1)\n        qDebug() << \"willExecuteScript: Unable to set the working directory to \" << sim_working_dir.c_str() << \" (error \" << errno << \")\";\n}\n\nvoid QtSLiMWindow::didExecuteScript(void)\n{\n    // Swap our random number generator back out again; see -eidosConsoleWindowControllerWillExecuteScript\n\tstd::swap(sim_RNG, gEidos_RNG_SINGLE);\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\n    // Swap out our pedigree id and mutation id counters; see -eidosConsoleWindowControllerWillExecuteScript\n    // Setting to -100000 here is not necessary, but will maybe help find bugs...\n    sim_next_pedigree_id = gSLiM_next_pedigree_id;\n    gSLiM_next_pedigree_id = -100000;\n\n    sim_next_mutation_id = gSLiM_next_mutation_id;\n    gSLiM_next_mutation_id = -100000;\n\n    sim_suppress_warnings = gEidosSuppressWarnings;\n    gEidosSuppressWarnings = false;\n\n    // Get the current working directory; each SLiM window has its own cwd, which may have been changed in script since ...WillExecuteScript:\n    sim_working_dir = Eidos_CurrentDirectory();\n\n    // Return to the app's working directory when not running SLiM/Eidos code\n    std::string &app_cwd = qtSLiMAppDelegate->QtSLiMCurrentWorkingDirectory();\n    errno = 0;\n    int retval = chdir(app_cwd.c_str());\n\n    if (retval == -1)\n        qDebug() << \"didExecuteScript: Unable to set the working directory to \" << app_cwd.c_str() << \" (error \" << errno << \")\";\n}\n\nbool QtSLiMWindow::runSimOneTick(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    // This method should always be used when calling out to run the simulation, because it swaps the correct random number\n    // generator stuff in and out bracketing the call to RunOneTick().  This bracketing would need to be done around\n    // any other call out to the simulation that caused it to use random numbers, too, such as subsample output.\n    bool stillRunning = true;\n\n    willExecuteScript();\n\n    // We always take a start clock measurement, to tally elapsed time spent running the model\n    clock_t startCPUClock = clock();\n    \n#if (SLIMPROFILING == 1)\n\tif (profilePlayOn_)\n\t{\n\t\t// We put the wall clock measurements on the inside since we want those to be maximally accurate,\n\t\t// as profile report percentages are fractions of the total elapsed wall clock time.\n\t\tSLIM_PROFILE_BLOCK_START();\n\n\t\tstillRunning = community->RunOneTick();\n\n\t\tSLIM_PROFILE_BLOCK_END(community->profile_elapsed_wall_clock);\n\t}\n    else\n#endif\n    {\n        stillRunning = community->RunOneTick();\n    }\n    \n    // Take an end clock time to tally elapsed time spent running the model\n    clock_t endCPUClock = clock();\n    \n    elapsedCPUClock_ += (endCPUClock - startCPUClock);\n    \n#if (SLIMPROFILING == 1)\n\tif (profilePlayOn_)\n        community->profile_elapsed_CPU_clock += (endCPUClock - startCPUClock);\n#endif\n    \n    didExecuteScript();\n\n    // We also want to let graphViews know when each tick has finished, in case they need to pull data from the sim.  Note this\n    // happens after every tick, not just when we are updating the UI, so drawing and setNeedsDisplay: should not happen here.\n    emit controllerTickFinished();\n\n    return stillRunning;\n}\n\nvoid QtSLiMWindow::_continuousPlay(void)\n{\n    // NOTE this code is parallel to the code in _continuousProfile()\n\tif (!invalidSimulation_)\n\t{\n        QElapsedTimer playStartTimer;\n        playStartTimer.start();\n        \n\t\tdouble speedSliderValue = ui->playSpeedSlider->value() / 100.0;     // scale is 0 to 100, since only integer values are allowed by QSlider\n\t\tdouble intervalSinceStarting = continuousPlayElapsedTimer_.nsecsElapsed() / 1000000000.0;\n\t\t\n\t\t// Calculate frames per second; this equation must match the equation in playSpeedChanged:\n\t\tdouble maxTicksPerSecond = 1000000000.0;\t// bounded, to allow -eidos_pauseExecution to interrupt us\n\t\t\n\t\tif (speedSliderValue < 0.99999)\n\t\t\tmaxTicksPerSecond = (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * 839;\n\t\t\n\t\t//qDebug() << \"speedSliderValue == \" << speedSliderValue << \", maxTicksPerSecond == \" << maxTicksPerSecond;\n\t\t\n\t\t// We keep a local version of reachedSimulationEnd, because calling setReachedSimulationEnd: every tick\n\t\t// can actually be a large drag for simulations that run extremely quickly – it can actually exceed the time\n\t\t// spent running the simulation itself!  Moral of the story, KVO is wicked slow.\n\t\tbool reachedEnd = reachedSimulationEnd_;\n\t\t\n\t\tdo\n\t\t{\n\t\t\tif (continuousPlayTicksCompleted_ / intervalSinceStarting >= maxTicksPerSecond)\n\t\t\t\tbreak;\n\t\t\t\n            if (tickPlayOn_ && (community->Tick() >= targetTick_))\n                break;\n            \n            reachedEnd = !runSimOneTick();\n\t\t\t\n\t\t\tcontinuousPlayTicksCompleted_++;\n\t\t}\n\t\twhile (!reachedEnd && (playStartTimer.nsecsElapsed() / 1000000000.0) < 0.02);\n\t\t\n\t\tsetReachedSimulationEnd(reachedEnd);\n\t\t\n\t\tif (!reachedSimulationEnd_ && (!tickPlayOn_ || !(community->Tick() >= targetTick_)))\n\t\t{\n            updateAfterTickFull((playStartTimer.nsecsElapsed() / 1000000000.0) > 0.04);\n\t\t\tcontinuousPlayInvocationTimer_.start(0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// stop playing\n\t\t\tupdateAfterTickFull(true);\n            \n            if (nonProfilePlayOn_)\n                playOrProfile(PlayType::kNormalPlay);       // click the Play button\n            else if (tickPlayOn_)\n                playOrProfile(PlayType::kTickPlay);   // click the Play button\n\t\t\t\n\t\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t\t//[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n}\n\nvoid QtSLiMWindow::_continuousProfile(void)\n{\n\t// NOTE this code is parallel to the code in _continuousPlay()\n\tif (!invalidSimulation_)\n\t{\n        QElapsedTimer playStartTimer;\n        playStartTimer.start();\n\t\t\n\t\t// We keep a local version of reachedSimulationEnd, because calling setReachedSimulationEnd: every tick\n\t\t// can actually be a large drag for simulations that run extremely quickly – it can actually exceed the time\n\t\t// spent running the simulation itself!  Moral of the story, KVO is wicked slow.\n\t\tbool reachedEnd = reachedSimulationEnd_;\n\t\t\n\t\tif (!reachedEnd)\n\t\t{\n\t\t\tdo\n\t\t\t{\n                reachedEnd = !runSimOneTick();\n\t\t\t\t\n\t\t\t\tcontinuousPlayTicksCompleted_++;\n\t\t\t}\n            while (!reachedEnd && (playStartTimer.nsecsElapsed() / 1000000000.0) < 0.02);\n\t\t\t\n            setReachedSimulationEnd(reachedEnd);\n\t\t}\n\t\t\n\t\tif (!reachedSimulationEnd_)\n\t\t{\n            updateAfterTickFull((playStartTimer.nsecsElapsed() / 1000000000.0) > 0.04);\n            continuousProfileInvocationTimer_.start(0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// stop profiling\n            updateAfterTickFull(true);\n\t\t\tplayOrProfile(PlayType::kProfilePlay);   // click the Profile button\n\t\t\t\n\t\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t\t//[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n}\n\nvoid QtSLiMWindow::playOrProfile(PlayType playType)\n{\n#if DEBUG\n\tif (playType == PlayType::kProfilePlay)\n\t{\n        ui->profileButton->setChecked(false);\n        updateProfileButtonIcon(false);\n\t\t\n        QMessageBox messageBox(this);\n        messageBox.setText(\"Release build required\");\n        messageBox.setInformativeText(\"In order to obtain accurate timing information that is relevant to the actual runtime of a model, profiling requires that you are running a Release build of SLiMgui.\");\n        messageBox.setIcon(QMessageBox::Warning);\n        \n        // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n        // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n        // seems necessary so floating windows can't be on top of the message box\n        messageBox.setWindowModality(Qt::ApplicationModal);\n        messageBox.exec();\n\t\t\n\t\treturn;\n\t}\n#endif\n    \n#if (SLIMPROFILING != 1)\n\tif (playType == PlayType::kProfilePlay)\n\t{\n        ui->profileButton->setChecked(false);\n        updateProfileButtonIcon(false);\n\t\t\n        QMessageBox messageBox(this);\n        messageBox.setText(\"Profiling disabled\");\n        messageBox.setInformativeText(\"Profiling has been disabled in this build of SLiMgui.  Please change the definition of SLIMPROFILING to 1 in the project's .pro files.\");\n        messageBox.setIcon(QMessageBox::Warning);\n        \n        // see https://forum.qt.io/topic/160751/error-panel-goes-underneath-floating-window-causing-confusion\n        // regarding the choice between Qt::WindowModal and Qt::ApplicationModal; here Qt::ApplicationModal\n        // seems necessary so floating windows can't be on top of the message box\n        messageBox.setWindowModality(Qt::ApplicationModal);\n        messageBox.exec();\n\t\t\n\t\treturn;\n\t}\n#endif\n    \n    if (!continuousPlayOn_)\n\t{\n        // log information needed to track our play speed\n        continuousPlayElapsedTimer_.restart();\n\t\tcontinuousPlayTicksCompleted_ = 0;\n        \n\t\tsetContinuousPlayOn(true);\n\t\tif (playType == PlayType::kProfilePlay)\n            setProfilePlayOn(true);\n        else if (playType == PlayType::kNormalPlay)\n            setNonProfilePlayOn(true);\n        else if (playType == PlayType::kTickPlay)\n            setTickPlayOn(true);\n\t\t\n\t\t// keep the button on; this works for the button itself automatically, but when the menu item is chosen this is needed\n\t\tif (playType == PlayType::kProfilePlay)\n\t\t{\n            ui->profileButton->setChecked(true);\n            updateProfileButtonIcon(false);\n\t\t}\n\t\telse    // kNormalPlay and kTickPlay\n\t\t{\n            ui->playButton->setChecked(true);\n            updatePlayButtonIcon(false);\n\t\t\t//[self placeSubview:playButton aboveSubview:profileButton];\n\t\t}\n\t\t\n\t\t// invalidate the console symbols, and don't validate them until we are done\n\t\tif (consoleController)\n            consoleController->invalidateSymbolTableAndFunctionMap();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// prepare profiling information if necessary\n\t\tif (playType == PlayType::kProfilePlay)\n\t\t\tcommunity->StartProfiling();\n#endif\n\t\t\n\t\t// start playing/profiling\n\t\tif (playType == PlayType::kProfilePlay)\n            continuousProfileInvocationTimer_.start(0);\n        else    // kNormalPlay and kTickPlay\n            continuousPlayInvocationTimer_.start(0);\n\t}\n\telse\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// close out profiling information if necessary\n\t\tif ((playType == PlayType::kProfilePlay) && community && !invalidSimulation_)\n\t\t\tcommunity->StopProfiling();\n#endif\n\t\t\n        // stop our recurring perform request\n\t\tif (playType == PlayType::kProfilePlay)\n            continuousProfileInvocationTimer_.stop();\n        else\n            continuousPlayInvocationTimer_.stop();\n\t\t\n        setContinuousPlayOn(false);\n        if (playType == PlayType::kProfilePlay)\n            setProfilePlayOn(false);\n        else if (playType == PlayType::kNormalPlay)\n            setNonProfilePlayOn(false);\n        else if (playType == PlayType::kTickPlay)\n            setTickPlayOn(false);\n\t\t\n\t\t// keep the button off; this works for the button itself automatically, but when the menu item is chosen this is needed\n\t\tif (playType == PlayType::kProfilePlay)\n\t\t{\n            ui->profileButton->setChecked(false);\n            updateProfileButtonIcon(false);\n\t\t}\n\t\telse    // kNormalPlay and kTickPlay\n\t\t{\n            ui->playButton->setChecked(false);\n            updatePlayButtonIcon(false);\n\t\t\t//[self placeSubview:profileButton aboveSubview:playButton];\n\t\t}\n\t\t\n        // clean up and update UI\n\t\tif (consoleController)\n            consoleController->validateSymbolTableAndFunctionMap();\n        \n\t\tupdateAfterTickFull(true);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// If we just finished profiling, display a report\n\t\tif ((playType == PlayType::kProfilePlay) && community && !invalidSimulation_)\n\t\t\tdisplayProfileResults();\n#endif\n\t}\n}\n\n//\n//\tEidos SLiMgui method forwards\n//\n\nvoid QtSLiMWindow::finish_eidos_pauseExecution(void)\n{\n\t// this gets called by performSelectorOnMainThread: after _continuousPlay: has broken out of its loop\n\t// if the simulation has already ended, or is invalid, or is not in continuous play, it does nothing\n\tif (!invalidSimulation_ && !reachedSimulationEnd_ && continuousPlayOn_ && nonProfilePlayOn_ && !profilePlayOn_ && !tickPlayOn_)\n\t{\n\t\tplayOrProfile(PlayType::kNormalPlay);\t// this will simulate a press of the play button to stop continuous play\n\t\t\n\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t//[NSApp requestUserAttention:NSInformationalRequest];\n\t}\n}\n\nEidosValue_SP QtSLiMWindow::eidos_logFileData(LogFile *logFile, EidosValue *column_value)\n{\n    // start by flushing any pending output to the debug output window\n    updateOutputViews();\n    \n    // then fetch the data from the debug output window\n    QtSLiMDebugOutputWindow *debugOutput = debugOutputWindow();\n    \n    if (column_value->Type() == EidosValueType::kValueInt)\n        return debugOutput->dataForColumn(logFile, column_value->IntAtIndex_NOCAST(0, nullptr));\n    else\n        return debugOutput->dataForColumn(logFile, column_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    return gStaticEidosValueNULL;\n}\n\nvoid QtSLiMWindow::eidos_openDocument(QString path)\n{\n    if (path.endsWith(\".pdf\", Qt::CaseInsensitive))\n    {\n        // Block opening PDFs; SLiMgui supported PDF but QtSLiM doesn't, so we should explicitly intercept and error out, otherwise we'll try to open the PDF as a SLiM model\n\t\t// FIXME: This shouldn't be using EIDOS_TERMINATION!\n        EIDOS_TERMINATION << \"ERROR (QtSLiMWindow::eidos_openDocument): opening PDF files is not supported in SLiMgui; using PNG instead is suggested.\" << EidosTerminate(nullptr);\n    }\n    \n    qtSLiMAppDelegate->openFile(path, this);\n}\n\nvoid QtSLiMWindow::eidos_pauseExecution(void)\n{\n    if (!invalidSimulation_ && !reachedSimulationEnd_ && continuousPlayOn_ && nonProfilePlayOn_ && !profilePlayOn_ && !tickPlayOn_)\n\t{\n\t\tcontinuousPlayTicksCompleted_ = UINT64_MAX - 1;\t\t\t// this will break us out of the loop in _continuousPlay: at the end of this tick\n        \n        QMetaObject::invokeMethod(this, \"finish_eidos_pauseExecution\", Qt::QueuedConnection);   // this will actually stop continuous play\n\t}\n}\n\nQtSLiMGraphView_CustomPlot *QtSLiMWindow::eidos_createPlot(QString title, double *x_range, double *y_range, QString x_label, QString y_label, double width, double height, bool horizontalGrid, bool verticalGrid, bool fullBox, double axisLabelSize, double tickLabelSize)\n{\n    QtSLiMGraphView *graphView = graphViewWithTitle(title);\n    QtSLiMGraphView_CustomPlot *customPlot = nullptr;\n    QWidget *graphWindow = nullptr;\n    bool createdWindow = false;\n    \n    if (graphView)\n    {\n        customPlot = dynamic_cast<QtSLiMGraphView_CustomPlot *>(graphView);\n        \n        if (!customPlot)\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): a plot window exists with the given title, but it is not a custom plot window.\" << EidosTerminate(nullptr);\n        \n        graphWindow = graphView->window();\n    }\n    else\n    {\n        customPlot = new QtSLiMGraphView_CustomPlot(this, this);\n        \n        // width/height are 0 if they were NULL in the Eidos call; supply the default size here\n        if (width == 0)\n            width = 300;\n        \n        if (height == 0)\n            height = 300;\n        \n        if ((width < 250) || (height < 250))\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires the window width and height to be at least 250 pixels.\" << EidosTerminate(nullptr);\n        \n        graphWindow = graphWindowWithView(customPlot, width, height);\n        createdWindow = true;\n    }\n    \n    if (customPlot && graphWindow)\n    {\n        // calling createPlot() resets the plot's state, creating it afresh even if it already exists\n        customPlot->controllerRecycled();\n        customPlot->setBorderless(false, 0, 0, 0, 0);\n        customPlot->setTitle(title);\n        customPlot->setXLabel(x_label);\n        customPlot->setYLabel(y_label);\n        customPlot->setDataRanges(x_range, y_range);\n        customPlot->setShowHorizontalGrid(horizontalGrid);\n        customPlot->setShowVerticalGrid(verticalGrid);\n        customPlot->setShowFullBox(fullBox);\n        \n        if (axisLabelSize > 0)\n            customPlot->setAxisLabelSize(axisLabelSize);\n        \n        if (tickLabelSize > 0)\n            customPlot->setTickLabelSize(tickLabelSize);\n        \n        if (createdWindow)\n            QtSLiMMakeWindowVisibleAndExposed(graphWindow);\n\t\t\n\t\t// BCH 11/16/2025: There is one tricky thing here, which is that in practice the plot window might not be allowed\n\t\t// to be the requested size, due to screen constraints.  We don't know that until we try.  Before the call to\n\t\t// the QtSLiMMakeWindowVisibleAndExposed() the window is still at the original size we requested (on macOS, at\n\t\t// least).  After that call, it has been constrained by whatever factors (screen size, dock/menubar, etc.) exist.\n\t\t// We can't do anything about those constraints; but we do want to try to preserve the original aspect ratio\n\t\t// requested by the user, and we emit a warning to the console.  See https://github.com/MesserLab/SLiM/issues/567\n\t\tdouble realized_width = customPlot->width(), realized_height = customPlot->height();\n\t\tdouble trim_width = graphWindow->width() - realized_width, trim_height = graphWindow->height() - realized_height;\n\t\t\n\t\tif ((realized_width != width) || (realized_height != height))\n\t\t{\n\t\t\tstd::cout << \"SLiMgui: the requested graph window size (\" << width << \", \" << height << \") was not attainable; the realized size was (\" <<\n\t\t\t\t\t\t realized_width << \", \" << realized_height << \").  Resizing to try to preserve the requested aspect ratio.\" << std::endl;\n\t\t\t\n\t\t\tdouble requested_aspect_ratio = width / height;\n\t\t\tdouble realized_aspect_ratio = realized_width / realized_height;\n\t\t\t\n\t\t\tif (realized_aspect_ratio > requested_aspect_ratio)\n\t\t\t{\n\t\t\t\t// the width is, proportionally, larger than requested and needs to be reduced\n\t\t\t\tdouble corrected_width = std::round(requested_aspect_ratio * realized_height + trim_width);\n\t\t\t\tgraphWindow->resize(corrected_width, graphWindow->height());\n\t\t\t}\n\t\t\telse if (realized_aspect_ratio < requested_aspect_ratio)\n\t\t\t{\n\t\t\t\t// the height is, proportionally, larger than requested and needs to be reduced\n\t\t\t\tdouble corrected_height = std::round(realized_width / requested_aspect_ratio + trim_height);\n\t\t\t\tgraphWindow->resize(graphWindow->width(), corrected_height);\n\t\t\t}\n\t\t\t\n\t\t\t//std::cout << \"   requested aspect ratio \" << requested_aspect_ratio << \"; final aspect ratio after correction \" <<\n\t\t\t//          (customPlot->width() / (double)customPlot->height()) << std::endl;\n\t\t}\n    }\n    else\n    {\n        qApp->beep();\n    }\n    \n    return customPlot;\n}\n\nQtSLiMGraphView_CustomPlot *QtSLiMWindow::eidos_plotWithTitle(QString title)\n{\n    QtSLiMGraphView *graphView = graphViewWithTitle(title);\n    QtSLiMGraphView_CustomPlot *customPlot = nullptr;\n    \n    if (graphView)\n    {\n        customPlot = dynamic_cast<QtSLiMGraphView_CustomPlot *>(graphView);\n        \n        if (customPlot)\n        {\n            Plot *plotobj = customPlot->eidosPlotObject();\n            \n            if (plotobj)\n                return customPlot;\n        }\n        \n        EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_plotWithTitle): a plot window exists with the given title, but it is not a custom plot window created with createPlot().\" << EidosTerminate(nullptr);\n    }\n    else\n    {\n        // when there is no plot window with the given title, it is not an error\n        return nullptr;\n    }\n}\n\nvoid QtSLiMWindow::plotLogFileData_1D(QString title, QString y_title, double *y_values, int data_count)\n{\n    // To plot logfile data, we call through to the same APIs as for Eidos-based plotting\n    QtSLiMGraphView_CustomPlot *plot = eidos_createPlot(title, nullptr, nullptr, \"time\", y_title, 0, 0, -1, -1, -1, -1, -1);\n    \n    double *x_values = (double *)malloc(data_count * sizeof(double));\n    for (int i = 0; i < data_count; ++i)\n        x_values[i] = i;\n    \n    std::vector<QColor> *color = new std::vector<QColor>;\n    color->emplace_back(255, 0, 0, 255);\n    \n    std::vector<double> *alpha = new std::vector<double>;\n    alpha->push_back(1.0);\n    \n    std::vector<double> *lwd = new std::vector<double>;\n    lwd->push_back(1.5);\n    \n    plot->addLineData(x_values, y_values, data_count, color, alpha, lwd);     // takes buffers from us\n}\n\nvoid QtSLiMWindow::plotLogFileData_2D(QString title, QString x_title, QString y_title, double *x_values, double *y_values, int data_count, bool makeScatterPlot)\n{\n    // To plot logfile data, we call through to the same APIs as for Eidos-based plotting\n    QtSLiMGraphView_CustomPlot *plot = eidos_createPlot(title, nullptr, nullptr, x_title, y_title, 0, 0, -1, -1, -1, -1, -1);\n    \n    std::vector<QColor> *color = new std::vector<QColor>;\n    color->emplace_back(0, 0, 0, 255);\n    \n    std::vector<double> *alpha = new std::vector<double>;\n    alpha->push_back(1.0);\n    \n    std::vector<double> *lwd = new std::vector<double>;\n    lwd->push_back(1.0);\n    \n    if (makeScatterPlot)\n    {\n        std::vector<int> *symbol = new std::vector<int>;\n        symbol->push_back(16);\n        \n        std::vector<QColor> *border = new std::vector<QColor>;\n        border->emplace_back(0, 0, 0, 255);\n        \n        std::vector<double> *size = new std::vector<double>;\n        size->push_back(0.5);\n        \n        plot->addPointData(x_values, y_values, data_count, symbol, color, border, alpha, lwd, size);      // takes buffers from us\n    }\n    else\n    {\n        plot->addLineData(x_values, y_values, data_count, color, alpha, lwd);                             // takes buffers from us\n    }\n}\n\n\n//\n//  change tracking and the recycle button\n//\n\n// Do our own tracking of the change count.  We do this so that we know whether the script is in\n// the same state it was in when we last recycled, or has been changed.  If it has been changed,\n// we add a highlight under the recycle button to suggest to the user that they might want to\n// recycle to bring their changes into force.\nvoid QtSLiMWindow::updateChangeCount(void) //:(NSDocumentChangeType)change\n{\n\t//[super updateChangeCount:change];\n\t\n\t// Mask off flags in the high bits.  Apple is not explicit about this, but NSChangeDiscardable\n\t// is 256, and acts as a flag bit, so it seems reasonable to assume this for future compatibility.\n//\tNSDocumentChangeType maskedChange = (NSDocumentChangeType)(change & 0x00FF);\n\t\n//\tif ((maskedChange == NSChangeDone) || (maskedChange == NSChangeRedone))\n\t\tslimChangeCount++;\n//\telse if (maskedChange == NSChangeUndone)\n//\t\tslimChangeCount--;\n\t\n    emit controllerChangeCountChanged(slimChangeCount);\n}\n\nbool QtSLiMWindow::changedSinceRecycle(void)\n{\n\treturn !(slimChangeCount == 0);\n}\n\nvoid QtSLiMWindow::resetSLiMChangeCount(void)\n{\n    slimChangeCount = 0;\n    emit controllerChangeCountChanged(slimChangeCount);\n}\n\n// slot receiving the signal QPlainTextEdit::textChanged() from the script textedit\nvoid QtSLiMWindow::scriptTexteditChanged(void)\n{\n    // Poke the change count.  In SLiMgui we get separate notification types for changes vs. undo/redo,\n    // allowing us to know when the document has returned to a checkpoint state due to undo/redo, but\n    // there seems to be no way to do that with Qt, so once we register a change, only recycling will\n    // bring us back to the unchanged state.\n    updateChangeCount();\n}\n\n\n//\n//  public slots\n//\n\nvoid QtSLiMWindow::playOneStepClicked(void)\n{\n    if (!invalidSimulation_)\n    {\n        if (consoleController)\n            consoleController->invalidateSymbolTableAndFunctionMap();\n        \n        setReachedSimulationEnd(!runSimOneTick());\n        \n        // BCH 5/7/2021: moved these two lines up here, above validateSymbolTableAndFunctionMap(), so that\n        // updateAfterTickFull() calls checkForSimulationTermination() for us before we re-validate the\n        // symbol table; this way if the simulation has hit an error the symbol table no longer contains\n        // SLiM stuff in it.  I *think* this mirrors what happens when play, rather than step, is used.\n        // Nevertheless, it might be a fragile change, so I'm leaving this comment to document the change.\n        ui->tickLineEdit->clearFocus();\n        updateAfterTickFull(true);\n        \n        if (consoleController)\n            consoleController->validateSymbolTableAndFunctionMap();\n    }\n}\n\nvoid QtSLiMWindow::_playOneStep(void)\n{\n    playOneStepClicked();\n    \n    if (!reachedSimulationEnd_)\n    {\n        playOneStepInvocationTimer_.start(350); // milliseconds\n    }\n    else\n    {\n        // stop playing\n        playOneStepReleased();\n    }\n}\n\nvoid QtSLiMWindow::playOneStepPressed(void)\n{\n    ui->playOneStepButton->qtslimSetHighlight(true);\n    _playOneStep();\n}\n\nvoid QtSLiMWindow::playOneStepReleased(void)\n{\n    ui->playOneStepButton->qtslimSetHighlight(false);\n    playOneStepInvocationTimer_.stop();\n}\n\nvoid QtSLiMWindow::tickChanged(void)\n{\n\tif (!tickPlayOn_)\n\t{\n\t\tQString tickString = ui->tickLineEdit->text();\n\t\t\n\t\t// Special-case initialize(); we can never advance to it, since it is first, so we just validate it\n\t\tif (tickString == \"initialize()\")\n\t\t{\n\t\t\tif (community->Tick() != 0)\n\t\t\t{\n\t\t\t\tqApp->beep();\n\t\t\t\tupdateTickCounter();\n                ui->tickLineEdit->selectAll();\n\t\t\t}\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Get the integer value from the textfield, since it is not \"initialize()\"\n\t\ttargetTick_ = SLiMClampToTickType(static_cast<int64_t>(tickString.toLongLong()));\n\t\t\n\t\t// make sure the requested tick is in range\n\t\tif (community->Tick() >= targetTick_)\n\t\t{\n\t\t\tif (community->Tick() > targetTick_)\n            {\n                qApp->beep();\n                updateTickCounter();\n                ui->tickLineEdit->selectAll();\n\t\t\t}\n            \n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// get the first responder out of the tick textfield\n        ui->tickLineEdit->clearFocus();\n\t\t\n\t\t// start playing\n        playOrProfile(PlayType::kTickPlay);\n\t}\n\telse\n\t{\n\t\t// stop our recurring perform request; I don't think this is hit any more\n        playOrProfile(PlayType::kTickPlay);\n\t}\n}\n\nvoid QtSLiMWindow::recycleClicked(void)\n{\n    // If the user has requested autosaves, act on that; these calls run modal, blocking panels\n    if (!isZombieWindow_)\n    {\n        QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance();\n        \n        if (prefsNotifier.autosaveOnRecyclePref())\n        {\n            if (!isUntitled)\n                saveFile(currentFile);\n            else if (prefsNotifier.showSaveIfUntitledPref())\n                saveAs();\n            //else\n            //    qApp->beep();\n        }\n    }\n    \n    // Now do the recycle\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    // Converting a QString to a std::string is surprisingly tricky: https://stackoverflow.com/a/4644922/2752221\n    std::string utf8_script_string = ui->scriptTextEdit->toPlainText().toUtf8().constData();\n    \n    if (consoleController)\n        consoleController->invalidateSymbolTableAndFunctionMap();\n    \n    clearOutputClicked();\n    if (debugOutputWindow_)\n        debugOutputWindow_->clearAllOutput();\n    \n    setScriptStringAndInitializeSimulation(utf8_script_string);\n    \n    if (consoleController)\n        consoleController->validateSymbolTableAndFunctionMap();\n    \n    ui->tickLineEdit->clearFocus();\n    elapsedCPUClock_ = 0;\n    \n    updateAfterTickFull(true);\n    \n    ui->scriptTextEdit->setPalette(ui->scriptTextEdit->qtslimStandardPalette());     // clear any error highlighting\n    \n    // A bit of playing with undo.  We want to break undo coalescing at the point of recycling, so that undo and redo stop\n    // at the moment that we recycled.  Then we reset a change counter that we use to know if we have changed relative to\n    // the recycle point, so we can highlight the recycle button to show that the executing script is out of date.\n    //[scriptTextView breakUndoCoalescing];\n    resetSLiMChangeCount();\n    \n    emit controllerRecycled();\n}\n\nvoid QtSLiMWindow::playSpeedChanged(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n\t// We want our speed to be from the point when the slider changed, not from when play started\n    continuousPlayElapsedTimer_.restart();\n\tcontinuousPlayTicksCompleted_ = 1;\t\t// this prevents a new tick from executing every time the slider moves a pixel\n\t\n\t// This method is called whenever playSpeedSlider changes, continuously; we want to show the chosen speed in a tooltip-ish window\n    double speedSliderValue = ui->playSpeedSlider->value() / 100.0;     // scale is 0 to 100, since only integer values are allowed by QSlider\n\t\n\t// Calculate frames per second; this equation must match the equation in _continuousPlay:\n\tdouble maxTicksPerSecond = static_cast<double>(INFINITY);\n\t\n\tif (speedSliderValue < 0.99999)\n\t\tmaxTicksPerSecond = (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * 839;\n\t\n\t// Make a tooltip label string\n\tQString fpsString(\"∞ fps\");\n\t\n\tif (!std::isinf(maxTicksPerSecond))\n\t{\n\t\tif (maxTicksPerSecond < 1.0)\n\t\t\tfpsString = QString::asprintf(\"%.2f fps\", maxTicksPerSecond);\n\t\telse if (maxTicksPerSecond < 10.0)\n\t\t\tfpsString = QString::asprintf(\"%.1f fps\", maxTicksPerSecond);\n\t\telse\n\t\t\tfpsString = QString::asprintf(\"%.0f fps\", maxTicksPerSecond);\n\t\t\n\t\t//qDebug() << \"fps string: \" << fpsString;\n\t}\n    \n    // Show the tooltip; wow, that was easy...\n    QPoint widgetOrigin = ui->playSpeedSlider->mapToGlobal(QPoint());\n    QPoint cursorPosition = QCursor::pos();\n    QPoint tooltipPosition = QPoint(cursorPosition.x() - 2, widgetOrigin.y() - ui->playSpeedSlider->rect().height() - 8);\n    QToolTip::showText(tooltipPosition, fpsString, ui->playSpeedSlider, QRect(), 1000000);  // 1000 seconds; taken down on mouseup automatically\n}\n\nvoid QtSLiMWindow::showDrawerClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    if (!tablesDrawerController)\n        tablesDrawerController = new QtSLiMTablesDrawer(this);\n    \n    // position it to the right of the main window, with the same height\n    QRect windowRect = geometry();\n    windowRect.setLeft(windowRect.left() + windowRect.width() + 9);\n    windowRect.setRight(windowRect.left() + 200);   // the minimum in the nib is larger\n    \n    tablesDrawerController->setGeometry(windowRect);\n    \n    QtSLiMMakeWindowVisibleAndExposed(tablesDrawerController);\n}\n\nvoid QtSLiMWindow::chromosomeDisplayPopupButtonRunMenu(void)\n{\n    Species *displaySpecies = focalDisplaySpecies();\n    \n    // When the simulation is not valid and initialized, the context menu is disabled\n\tif (invalidSimulation_)\n        return;\n    \n    QMenu contextMenu(\"chromdisplay_menu\", this);\n    \n    if (!displaySpecies || !displaySpecies->HasGenetics() || (displaySpecies->Chromosomes().size() == 0))\n\t{\n        // Just run a dummy menu explaining why the menu is not available\n        QString reasonString;\n        \n        if (!displaySpecies)\n            reasonString = \"No focal species is selected\";\n        else if (!displaySpecies->HasGenetics())\n            reasonString = \"The focal species has no genetics\";\n        else if (displaySpecies->community_.tick_ == 0)\n            reasonString = \"The focal species has not initialized\";\n        else\n            reasonString = \"No chromosomes to display\";     // not sure whether/when this occurs\n        \n        QAction *no_chroms = contextMenu.addAction(reasonString);\n        no_chroms->setEnabled(false);\n        \n        QPoint mousePos = QCursor::pos();\n        contextMenu.exec(mousePos);\n        chromosomeDisplayReleased();\n        return;\n    }\n    \n    bool disableAll = false;\n    QAction *chromDisplayAll = contextMenu.addAction(\"New Chromosome Display (all)\");\n    chromDisplayAll->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    const std::vector<Chromosome *> &chromosomes = displaySpecies->Chromosomes();\n    \n    for (Chromosome *chrom : chromosomes)\n    {\n        QString menuItemTitle = QString(\"New Chromosome Display (symbol '%1')\").arg(QString::fromStdString(chrom->Symbol()));\n        \n        QAction *chromAction = contextMenu.addAction(menuItemTitle);\n        \n        chromAction->setData(QVariant::fromValue(chrom->ID()));      // we use the ID temporarily, to run the menu, but the symbol will be the actual key\n        chromAction->setEnabled(!disableAll);\n    }\n    \n    // Run the context menu synchronously\n    QPoint mousePos = QCursor::pos();\n    QAction *action = contextMenu.exec(mousePos);\n    \n    if (action && !invalidSimulation_)\n    {\n        isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n        displaySpecies = focalDisplaySpecies();     // might change while the menu is running...\n        \n        int chrom_id;               // not slim_chromosome_index_t since it can also be -1\n        std::string chrom_symbol;\n        QString windowTitle;\n        \n        if (action == chromDisplayAll)\n        {\n            chrom_id = -1;                      // -1 means \"all\"\n            chrom_symbol = \"\";                  // ditto\n            windowTitle = \"Chromosome Display\";\n        }\n        else\n        {\n            chrom_id = action->data().toInt();\n            \n            Chromosome *chrom = displaySpecies->ChromosomeFromID(chrom_id);\n            chrom_symbol = chrom->Symbol();\n            \n            windowTitle = QString(\"Chromosome Display ('%1')\").arg(QString::fromStdString(chrom_symbol));\n        }\n        \n        QWidget *chromosomeDisplay = newChromosomeDisplay(chrom_symbol, windowTitle);\n        \n        if (chromosomeDisplay)\n            QtSLiMMakeWindowVisibleAndExposed(chromosomeDisplay);\n    }\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    chromosomeDisplayReleased();\n}\n\nvoid QtSLiMWindow::showConsoleClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    if (!consoleController)\n    {\n        qApp->beep();\n        return;\n    }\n    \n    QtSLiMMakeWindowVisibleAndExposed(consoleController);\n}\n\nvoid QtSLiMWindow::showBrowserClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    if (!consoleController)\n    {\n        qApp->beep();\n        return;\n    }\n    \n    consoleController->showBrowserClicked();\n}\n\nvoid QtSLiMWindow::debugOutputClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    if (!debugOutputWindow_)\n    {\n        qApp->beep();\n        return;\n    }\n    \n    stopDebugButtonFlash();\n    \n    QtSLiMMakeWindowVisibleAndExposed(debugOutputWindow_);\n}\n\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n// In some versions of Qt5, such as 5.9.5, QChar::FormFeed did not yet exist\n#define Eidos_FormFeed 0x0C\n#else\n// In Qt6, QChar::FormFeed is the preferred symbol for this\n#define Eidos_FormFeed QChar::FormFeed\n#endif\n\nvoid QtSLiMWindow::jumpToPopupButtonRunMenu(void)\n{\n    QPlainTextEdit *scriptTE = ui->scriptTextEdit;\n    QString jumpScriptString = scriptTE->toPlainText();\n    QByteArray utf8bytes = jumpScriptString.toUtf8();\n\tconst char *cstr = utf8bytes.constData();\n    bool failedParse = true;\n    \n    // Collect actions, with associated script positions\n    std::vector<std::pair<int32_t, QAction *>> jumpActions;\n    \n    // First we scan for comments of the form /** comment */ or /// comment, which are taken to be section headers\n    // BCH 10/13/2020: Now we exclude comments of the form /*** or ////, since they are not of the expected form, but are instead just somebody's fancy comment block\n    // BCH 11/15/2021: Whoops, the previous change broke /***/ as a separator item; added back in as a special case\n    if (cstr)\n    {\n        SLiMEidosScript script(cstr);\n        \n        script.Tokenize(true, true);            // make bad tokens as needed, keep nonsignificant tokens\n        \n        const std::vector<EidosToken> &tokens = script.Tokens();\n        size_t token_count = tokens.size();\n        QString comment;\n        \n        for (size_t token_index = 0; token_index < token_count; ++token_index)\n        {\n            const EidosToken &token = tokens[token_index];\n            \n            if ((token.token_type_ == EidosTokenType::kTokenCommentLong) && (token.token_string_ == \"/***/\"))\n            {\n                comment = QString();\n            }\n            else if ((token.token_type_ == EidosTokenType::kTokenComment) && (token.token_string_.rfind(\"///\", 0) == 0) && (token.token_string_.rfind(\"////\", 0) != 0))\n            {\n                comment = QString::fromStdString(token.token_string_);\n                comment = comment.mid(3);\n            }\n            else if (token.token_type_ == EidosTokenType::kTokenCommentLong && (token.token_string_.rfind(\"/**\", 0) == 0) && (token.token_string_.rfind(\"/***\", 0) != 0))\n            {\n                comment = QString::fromStdString(token.token_string_);\n                comment = comment.mid(3, comment.length() - 5);\n            }\n            else\n                continue;\n            \n            // Exclude comments that contain newlines and similar characters\n            if ((comment.indexOf(QChar::LineFeed) != -1) ||\n                    (comment.indexOf(Eidos_FormFeed) != -1) ||\n                    (comment.indexOf(QChar::CarriageReturn) != -1) ||\n                    (comment.indexOf(QChar::ParagraphSeparator) != -1) ||\n                    (comment.indexOf(QChar::LineSeparator) != -1))\n                continue;\n            \n            comment = comment.trimmed();\n            comment = comment.replace(\"&\", \"&&\");   // quote ampersands since Qt uses them as keyboard shortcut escapes\n            \n            int32_t comment_start = token.token_UTF16_start_;\n            int32_t comment_end = token.token_UTF16_end_ + 1;\n            QAction *jumpAction;\n            \n            if (comment.length() == 0)\n            {\n                jumpAction = new QAction(\"\", scriptTE);\n                jumpAction->setSeparator(true);\n            }\n            else\n            {\n                // we cannot handle within-text formatting, since Qt doesn't support it; just an overall style\n                // this is supported only on these section header items; we can't do the formatting on script block items\n                \n                // handle # H1 to ###### H6 headers, used to set the font size; these cannot be nested\n                int headerLevel = 3;    // 1/2 are bigger; 3 is \"default\" and has no effect; 4/5/6 are progressively smaller\n                \n                if (comment.startsWith(\"# \"))\n                {\n                    headerLevel = 1;\n                    comment = comment.mid(2);\n                }\n                else if (comment.startsWith(\"## \"))\n                {\n                    headerLevel = 2;\n                    comment = comment.mid(3);\n                }\n                else if (comment.startsWith(\"### \"))\n                {\n                    headerLevel = 3;\n                    comment = comment.mid(4);\n                }\n                else if (comment.startsWith(\"#### \"))\n                {\n                    headerLevel = 4;\n                    comment = comment.mid(5);\n                }\n                else if (comment.startsWith(\"##### \"))\n                {\n                    headerLevel = 5;\n                    comment = comment.mid(6);\n                }\n                else if (comment.startsWith(\"###### \"))\n                {\n                    headerLevel = 6;\n                    comment = comment.mid(7);\n                }\n                \n                // handle **bold** and _italic_ markdown; these can be nested and all get eaten\n                bool isBold = false, isItalic = false;\n                bool sawStyleChange = false;\n                \n                do\n                {\n                    // loop until this stays false, so we handle nested styles\n                    sawStyleChange = false;\n                    \n                    if (comment.startsWith(\"__\") && comment.endsWith(\"__\"))\n                    {\n                        isBold = true;\n                        sawStyleChange = true;\n                        comment = comment.mid(2, comment.length() - 4);\n                    }\n                    if (comment.startsWith(\"**\") && comment.endsWith(\"**\"))\n                    {\n                        isBold = true;\n                        sawStyleChange = true;\n                        comment = comment.mid(2, comment.length() - 4);\n                    }\n                    if (comment.startsWith(\"_\") && comment.endsWith(\"_\"))\n                    {\n                        isItalic = true;\n                        sawStyleChange = true;\n                        comment = comment.mid(1, comment.length() - 2);\n                    }\n                    if (comment.startsWith(\"*\") && comment.endsWith(\"*\"))\n                    {\n                        isItalic = true;\n                        sawStyleChange = true;\n                        comment = comment.mid(1, comment.length() - 2);\n                    }\n                }\n                while (sawStyleChange);\n                \n                jumpAction = new QAction(comment);\n                connect(jumpAction, &QAction::triggered, scriptTE, [scriptTE, comment_start, comment_end]() {\n                    QTextCursor cursor = scriptTE->textCursor();\n                    cursor.setPosition(comment_start, QTextCursor::MoveAnchor);\n                    cursor.setPosition(comment_end, QTextCursor::KeepAnchor);\n                    scriptTE->setTextCursor(cursor);\n                    scriptTE->centerCursor();\n                    QtSLiMFlashHighlightInTextEdit(scriptTE);\n                });\n                \n                QFont action_font = jumpAction->font();\n                if (isBold)\n                    action_font.setBold(true);\n                if (isItalic)\n                    action_font.setItalic(true);\n                if (headerLevel == 1)\n                    action_font.setPointSizeF(action_font.pointSizeF() * 1.50);\n                if (headerLevel == 2)\n                    action_font.setPointSizeF(action_font.pointSizeF() * 1.25);\n                //if (headerLevel == 3)\n                //    action_font.setPointSizeF(action_font.pointSizeF() * 1.00);\n                if (headerLevel == 4)\n                    action_font.setPointSizeF(action_font.pointSizeF() * 0.96);\n                if (headerLevel == 5)\n                    action_font.setPointSizeF(action_font.pointSizeF() * 0.85);\n                if (headerLevel == 6)\n                    action_font.setPointSizeF(action_font.pointSizeF() * 0.75);\n                jumpAction->setFont(action_font);\n            }\n            \n            jumpActions.emplace_back(comment_start, jumpAction);\n        }\n    }\n    \n    // Figure out whether we have multispecies avatars, and thus want to use the \"low brightness symbol\" emoji for \"ticks all\" blocks.\n    // This emoji provides nicely lined up spacing in the menu, and indicates \"ticks all\" clearly; seems better than nothing.  It would\n    // be even better, perhaps, to have a spacer of emoji width, to make things line up without having a symbol displayed; unfortunately\n    // such a spacer does not seem to exist.  https://stackoverflow.com/questions/66496671/is-there-a-blank-unicode-character-matching-emoji-width\n    QString ticksAllAvatar;\n    \n    if (community && community->is_explicit_species_ && (community->all_species_.size() > 0))\n    {\n        bool hasAvatars = false;\n        \n        for (Species *species : community->all_species_)\n            if (species->avatar_.length() > 0)\n                hasAvatars = true;\n        \n        if (hasAvatars)\n            ticksAllAvatar = QString::fromUtf8(\"\\xF0\\x9F\\x94\\x85\");     // \"low brightness symbol\", https://www.compart.com/en/unicode/U+1F505\n    }\n    \n    // Next we parse and get script blocks\n    if (cstr)\n    {\n        SLiMEidosScript script(cstr);\n        \n        try {\n            script.Tokenize(true, false);            // make bad tokens as needed, do not keep nonsignificant tokens\n            script.ParseSLiMFileToAST(true);        // make bad nodes as needed (i.e. never raise, and produce a correct tree)\n            \n            // Extract SLiMEidosBlocks from the parse tree\n            const EidosASTNode *root_node = script.AST();\n            QString specifierAvatar;\n            \n            for (EidosASTNode *script_block_node : root_node->children_)\n            {\n                // handle species/ticks specifiers, which are identifier token nodes at the top level of the AST with one child\n                if ((script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (script_block_node->children_.size() == 1))\n                {\n                    EidosASTNode *specifierChild = script_block_node->children_[0];\n                    std::string specifierSpeciesName = specifierChild->token_->token_string_;\n                    Species *specifierSpecies = (community ? community->SpeciesWithName(specifierSpeciesName) : nullptr);\n                    \n                    if (specifierSpecies && specifierSpecies->avatar_.length())\n                        specifierAvatar = QString::fromStdString(specifierSpecies->avatar_);\n                    else if (!specifierSpecies && (specifierSpeciesName == \"all\"))\n                        specifierAvatar = ticksAllAvatar;\n                    \n                    continue;\n                }\n                \n                // Create the block and use it to find the string from the start of its declaration to the start of its code\n                SLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_block_node);\n                int32_t decl_start = new_script_block->root_node_->token_->token_UTF16_start_;\n                int32_t code_start = new_script_block->compound_statement_node_->token_->token_UTF16_start_;\n                QString decl = jumpScriptString.mid(decl_start, code_start - decl_start);\n                \n                // Remove everything including and after the first newline\n                if (decl.indexOf(QChar::LineFeed) != -1)\n                    decl.truncate(decl.indexOf(QChar::LineFeed));\n                if (decl.indexOf(Eidos_FormFeed) != -1)\n                    decl.truncate(decl.indexOf(Eidos_FormFeed));\n                if (decl.indexOf(QChar::CarriageReturn) != -1)\n                    decl.truncate(decl.indexOf(QChar::CarriageReturn));\n                if (decl.indexOf(QChar::ParagraphSeparator) != -1)\n                    decl.truncate(decl.indexOf(QChar::ParagraphSeparator));\n                if (decl.indexOf(QChar::LineSeparator) != -1)\n                    decl.truncate(decl.indexOf(QChar::LineSeparator));\n                \n                // Extract a comment at the end and put it after a em-dash in the string\n                int simpleCommentStart = decl.indexOf(\"//\");\n                int blockCommentStart = decl.indexOf(\"/*\");\n                QString comment;\n                \n                if ((simpleCommentStart != -1) && ((blockCommentStart == -1) || (simpleCommentStart < blockCommentStart)))\n                {\n                    // extract a simple comment\n                    comment = decl.right(decl.length() - simpleCommentStart - 2);\n                    decl.truncate(simpleCommentStart);\n                }\n                else if ((blockCommentStart != -1) && ((simpleCommentStart == -1) || (blockCommentStart < simpleCommentStart)))\n                {\n                    // extract a block comment\n                    comment = decl.right(decl.length() - blockCommentStart - 2);\n                    decl.truncate(blockCommentStart);\n                    \n                    int blockCommentEnd = comment.indexOf(\"*/\");\n                    \n                    if (blockCommentEnd != -1)\n                        comment.truncate(blockCommentEnd);\n                }\n                \n                // Calculate the end of the declaration string; trim off whitespace at the end\n                decl = decl.trimmed();\n                \n                int32_t decl_end = decl_start + decl.length();\n                \n                // Remove trailing whitespace, replace tabs with spaces, etc.\n                decl = decl.simplified();\n                comment = comment.trimmed();\n                comment = comment.replace(\"&\", \"&&\");   // quote ampersands since Qt uses them as keyboard shortcut escapes\n                \n                if (comment.length() > 0)\n                    decl = decl + \"  —  \" + comment;\n                \n                // If a species/ticks specifier was previously seen that provides us with an avatar, prepend that\n                if (specifierAvatar.length())\n                {\n                    decl = specifierAvatar + \" \" + decl;\n                    specifierAvatar.clear();\n                }\n                \n                // Make a menu item with the final string, and annotate it with the range to select\n                QAction *jumpAction = new QAction(decl);\n                \n                connect(jumpAction, &QAction::triggered, scriptTE, [scriptTE, decl_start, decl_end]() {\n                    QTextCursor cursor = scriptTE->textCursor();\n                    cursor.setPosition(decl_start, QTextCursor::MoveAnchor);\n                    cursor.setPosition(decl_end, QTextCursor::KeepAnchor);\n                    scriptTE->setTextCursor(cursor);\n                    scriptTE->centerCursor();\n                    QtSLiMFlashHighlightInTextEdit(scriptTE);\n                });\n                \n                jumpActions.emplace_back(decl_start, jumpAction);\n                \n                failedParse = false;\n                \n                delete new_script_block;\n            }\n        }\n        catch (...)\n        {\n            // If a raise occurred during parsing, error message junk has been generated\n            // that we need to clear out; we don't want it to be shown to the user\n            gEidosTermination.clear();\n            gEidosTermination.str(\"\");\n        }\n    }\n    \n    QMenu contextMenu(\"jump_to_menu\", this);\n    \n    if (failedParse || (jumpActions.size() == 0))\n    {\n        QAction *parseErrorItem = contextMenu.addAction(\"No symbols\");\n        parseErrorItem->setEnabled(false);\n        \n        // contextMenu never took ownership, so we need to dispose of allocated actions\n        for (auto &jump_pair : jumpActions)\n            delete jump_pair.second;\n    }\n    else\n    {\n        // sort the actions by position\n        std::sort(jumpActions.begin(),\n                  jumpActions.end(),\n                  [](const std::pair<int32_t, QAction *> &a1, const std::pair<int32_t, QAction *> &a2) { return a1.first < a2.first; });\n        \n        // add them all to contextMenu, and give it ownership\n        for (auto &jump_pair : jumpActions)\n        {\n            contextMenu.addAction(jump_pair.second);\n            jump_pair.second->setParent(&contextMenu);\n        }\n    }\n    \n    // Run the context menu synchronously\n    QPoint mousePos = QCursor::pos();\n    contextMenu.exec(mousePos);\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    jumpToPopupButtonReleased();\n}\n\nvoid QtSLiMWindow::setScriptBlockLabelTextFromSelection(void)\n{\n    // this does a subset of the parsing logic of QtSLiMWindow::jumpToPopupButtonRunMenu()\n    // it is used to get the label text for the script block label, to the right of the Jump button\n    QPlainTextEdit *scriptTE = ui->scriptTextEdit;\n    QString curScriptString = scriptTE->toPlainText();\n    QByteArray utf8bytes = curScriptString.toUtf8();\n    const char *cstr = utf8bytes.constData();\n    \n    QTextCursor selection_cursor(scriptTE->textCursor());\n    int selStart = selection_cursor.selectionStart();\n    int selEnd = selection_cursor.selectionEnd();\n    \n    if (cstr)\n    {\n        // Figure out whether we have multispecies avatars, and thus want to use the \"low brightness symbol\" emoji for \"ticks all\" blocks.\n        // This emoji provides nicely lined up spacing in the menu, and indicates \"ticks all\" clearly; seems better than nothing.  It would\n        // be even better, perhaps, to have a spacer of emoji width, to make things line up without having a symbol displayed; unfortunately\n        // such a spacer does not seem to exist.  https://stackoverflow.com/questions/66496671/is-there-a-blank-unicode-character-matching-emoji-width\n        QString ticksAllAvatar;\n        \n        if (community && community->is_explicit_species_ && (community->all_species_.size() > 0))\n        {\n            bool hasAvatars = false;\n            \n            for (Species *species : community->all_species_)\n                if (species->avatar_.length() > 0)\n                    hasAvatars = true;\n            \n            if (hasAvatars)\n                ticksAllAvatar = QString::fromUtf8(\"\\xF0\\x9F\\x94\\x85\");     // \"low brightness symbol\", https://www.compart.com/en/unicode/U+1F505\n        }\n        \n        SLiMEidosScript script(cstr);\n        \n        try {\n            script.Tokenize(true, false);            // make bad tokens as needed, do not keep nonsignificant tokens\n            script.ParseSLiMFileToAST(true);        // make bad nodes as needed (i.e. never raise, and produce a correct tree)\n            \n            // Extract SLiMEidosBlocks from the parse tree\n            const EidosASTNode *root_node = script.AST();\n            QString specifierAvatar;\n            \n            for (EidosASTNode *script_block_node : root_node->children_)\n            {\n                // handle species/ticks specifiers, which are identifier token nodes at the top level of the AST with one child\n                if ((script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (script_block_node->children_.size() == 1))\n                {\n                    EidosASTNode *specifierChild = script_block_node->children_[0];\n                    std::string specifierSpeciesName = specifierChild->token_->token_string_;\n                    Species *specifierSpecies = (community ? community->SpeciesWithName(specifierSpeciesName) : nullptr);\n                    \n                    if (specifierSpecies && specifierSpecies->avatar_.length())\n                        specifierAvatar = QString::fromStdString(specifierSpecies->avatar_);\n                    else if (!specifierSpecies && (specifierSpeciesName == \"all\"))\n                        specifierAvatar = ticksAllAvatar;\n                    \n                    continue;\n                }\n                \n                // Create the block and use it to find the string from the start of its declaration to the start of its code\n                SLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_block_node);\n                int32_t decl_start = new_script_block->root_node_->token_->token_UTF16_start_;\n                int32_t code_end = new_script_block->compound_statement_node_->token_->token_UTF16_end_;\n                \n                if ((selStart >= decl_start) && (selStart <= code_end) && (selEnd <= code_end + 2))     // +2 allows a selection through the end brace and one more character (typically a newline)\n                {\n                    int32_t code_start = new_script_block->compound_statement_node_->token_->token_UTF16_start_;\n                    QString decl = curScriptString.mid(decl_start, code_start - decl_start);\n                    \n                    // Remove everything including and after the first newline\n                    if (decl.indexOf(QChar::LineFeed) != -1)\n                        decl.truncate(decl.indexOf(QChar::LineFeed));\n                    if (decl.indexOf(Eidos_FormFeed) != -1)\n                        decl.truncate(decl.indexOf(Eidos_FormFeed));\n                    if (decl.indexOf(QChar::CarriageReturn) != -1)\n                        decl.truncate(decl.indexOf(QChar::CarriageReturn));\n                    if (decl.indexOf(QChar::ParagraphSeparator) != -1)\n                        decl.truncate(decl.indexOf(QChar::ParagraphSeparator));\n                    if (decl.indexOf(QChar::LineSeparator) != -1)\n                        decl.truncate(decl.indexOf(QChar::LineSeparator));\n                    \n                    // Extract a comment at the end and put it after a em-dash in the string\n                    int simpleCommentStart = decl.indexOf(\"//\");\n                    int blockCommentStart = decl.indexOf(\"/*\");\n                    QString comment;\n                    \n                    if ((simpleCommentStart != -1) && ((blockCommentStart == -1) || (simpleCommentStart < blockCommentStart)))\n                    {\n                        // extract a simple comment\n                        comment = decl.right(decl.length() - simpleCommentStart - 2);\n                        decl.truncate(simpleCommentStart);\n                    }\n                    else if ((blockCommentStart != -1) && ((simpleCommentStart == -1) || (blockCommentStart < simpleCommentStart)))\n                    {\n                        // extract a block comment\n                        comment = decl.right(decl.length() - blockCommentStart - 2);\n                        decl.truncate(blockCommentStart);\n                        \n                        int blockCommentEnd = comment.indexOf(\"*/\");\n                        \n                        if (blockCommentEnd != -1)\n                            comment.truncate(blockCommentEnd);\n                    }\n                    \n                    // Calculate the end of the declaration string; trim off whitespace at the end\n                    decl = decl.trimmed();\n                    \n                    // Remove trailing whitespace, replace tabs with spaces, etc.\n                    decl = decl.simplified();\n                    comment = comment.trimmed();\n                    \n                    if (comment.length() > 0)\n                        decl = decl + \"  —  \" + comment;\n                               \n                               // If a species/ticks specifier was previously seen that provides us with an avatar, prepend that\n                               if (specifierAvatar.length())\n                        {\n                            decl = specifierAvatar + \" \" + decl;\n                            specifierAvatar.clear();\n                        }\n                    \n                    delete new_script_block;\n                        \n                    ui->scriptBlockLabel->setText(decl);\n                    return;\n                }\n                \n                delete new_script_block;\n            }\n        }\n        catch (...)\n        {\n            // If a raise occurred during parsing, error message junk has been generated\n            // that we need to clear out; we don't want it to be shown to the user\n            gEidosTermination.clear();\n            gEidosTermination.str(\"\");\n        }\n    }\n    \n    ui->scriptBlockLabel->setText(QString(\"\"));\n}\n\nvoid QtSLiMWindow::clearOutputClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    ui->outputTextEdit->setPlainText(\"\");\n}\n\nvoid QtSLiMWindow::clearDebugPointsClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    ui->scriptTextEdit->clearDebugPoints();\n}\n\nvoid QtSLiMWindow::dumpPopulationClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    try\n\t{\n        // BCH 3/6/2022: Note that the species cycle has been added here for SLiM 4, in keeping with SLiM's native output formats.\n        Species *displaySpecies = focalDisplaySpecies();\n        \n        if (displaySpecies)\n        {\n            slim_tick_t species_cycle = displaySpecies->Cycle();\n            \n            // dump the population: output spatial positions and ages and tags if available, but not ancestral sequence or substitutions\n\t\t\tIndividual::PrintIndividuals_SLiM(SLIM_OUTSTREAM, nullptr, 0, *displaySpecies, true, true, false, false, true, false, /* p_focal_chromosome */ nullptr);\n            \n            // dump fixed substitutions also; so the dump in SLiMgui is like outputFull() + outputFixedMutations()\n            SLIM_OUTSTREAM << std::endl;\n            SLIM_OUTSTREAM << \"#OUT: \" << community->tick_ << \" \" << species_cycle << \" F \" << std::endl;\n            SLIM_OUTSTREAM << \"Mutations:\" << std::endl;\n            \n            for (unsigned int i = 0; i < displaySpecies->population_.substitutions_.size(); i++)\n            {\n                SLIM_OUTSTREAM << i << \" \";\n                displaySpecies->population_.substitutions_[i]->PrintForSLiMOutput_Tag(SLIM_OUTSTREAM);\n            }\n            \n            // now send SLIM_OUTSTREAM to the output textview\n            updateOutputViews();\n        }\n        else\n        {\n            // With no display species, including when on the \"all\" species tab, we just beep\n            qApp->beep();\n        }\n\t}\n\tcatch (...)\n\t{\n\t}\n}\n\nvoid QtSLiMWindow::displayGraphClicked(void)\n{\n    // see QtSLiMWindow::graphPopupButtonRunMenu() for parallel code for the graph pop-up button\n    QObject *object = sender();\n    QAction *action = qobject_cast<QAction *>(object);\n    \n    if (action)\n    {\n        Species *displaySpecies = focalDisplaySpecies();\n        \n        if (action == ui->actionCreate_Haplotype_Plot_All)\n        {\n            if (!continuousPlayOn_ && displaySpecies && displaySpecies->population_.subpops_.size())\n            {\n                isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n                \n                QtSLiMHaplotypeManager::CreateHaplotypePlot(chromosomeConfig, nullptr);\n            }\n            else\n            {\n                qApp->beep();\n            }\n        }\n        else if (action == ui->actionCreate_Haplotype_Plot_Selected)\n        {\n            if (!continuousPlayOn_ && displaySpecies && displaySpecies->population_.subpops_.size() && (focalChromosome() != nullptr))\n            {\n                isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n                \n                QtSLiMHaplotypeManager::CreateHaplotypePlot(chromosomeConfig, focalChromosome());\n            }\n            else\n            {\n                qApp->beep();\n            }\n        }\n        else\n        {\n            QtSLiMGraphView *graphView = nullptr;\n            \n            if (displaySpecies)\n            {\n                if (action == ui->actionGraph_1D_Population_SFS)\n                    graphView = new QtSLiMGraphView_1DPopulationSFS(this, this);\n                else if (action == ui->actionGraph_1D_Sample_SFS)\n                    graphView = new QtSLiMGraphView_1DSampleSFS(this, this);\n                else if (action == ui->actionGraph_2D_Population_SFS)\n                    graphView = new QtSLiMGraphView_2DPopulationSFS(this, this);\n                else if (action == ui->actionGraph_2D_Sample_SFS)\n                    graphView = new QtSLiMGraphView_2DSampleSFS(this, this);\n                else if (action == ui->actionGraph_Mutation_Frequency_Trajectories)\n                    graphView = new QtSLiMGraphView_FrequencyTrajectory(this, this);\n                else if (action == ui->actionGraph_Mutation_Loss_Time_Histogram)\n                    graphView = new QtSLiMGraphView_LossTimeHistogram(this, this);\n                else if (action == ui->actionGraph_Mutation_Fixation_Time_Histogram)\n                    graphView = new QtSLiMGraphView_FixationTimeHistogram(this, this);\n                else if (action == ui->actionGraph_Population_Fitness_Distribution)\n                    graphView = new QtSLiMGraphView_PopFitnessDist(this, this);\n                else if (action == ui->actionGraph_Subpopulation_Fitness_Distributions)\n                    graphView = new QtSLiMGraphView_SubpopFitnessDists(this, this);\n                else if (action == ui->actionGraph_Fitness_Time)\n                    graphView = new QtSLiMGraphView_FitnessOverTime(this, this);\n                else if (action == ui->actionGraph_Age_Distribution)\n                    graphView = new QtSLiMGraphView_AgeDistribution(this, this);\n                else if (action == ui->actionGraph_Lifetime_Reproduce_Output)\n                    graphView = new QtSLiMGraphView_LifetimeReproduction(this, this);\n                else if (action == ui->actionGraph_Population_Size_Time)\n                    graphView = new QtSLiMGraphView_PopSizeOverTime(this, this);\n                else if (action == ui->actionGraph_Population_Visualization)\n                    graphView = new QtSLiMGraphView_PopulationVisualization(this, this);\n            }\n            else if (action == ui->actionGraph_Multispecies_Population_Size_Time)\n                graphView = new QtSLiMGraphView_MultispeciesPopSizeOverTime(this, this);\n            \n            if (graphView)\n            {\n                QWidget *graphWindow = graphWindowWithView(graphView);\n                \n                if (graphWindow)\n                    QtSLiMMakeWindowVisibleAndExposed(graphWindow);\n            }\n            else\n            {\n                qApp->beep();\n            }\n        }\n    }\n}\n\nstatic bool rectIsOnscreen(QRect windowRect)\n{\n    const QList<QScreen *> screens = QGuiApplication::screens();\n    \n    for (QScreen *screen : screens)\n    {\n        QRect screenRect = screen->availableGeometry();\n        \n        if (screenRect.contains(windowRect, true))\n            return true;\n    }\n    \n    return false;\n}\n\nvoid QtSLiMWindow::positionNewSubsidiaryWindow(QWidget *p_window)\n{\n    // If all previous graph windows have been closed, reset our positioning.  This scheme could be much smarter;\n    // we could actually try to avoid the specific rectangles covered by existing subsidiary windows.\n    if (graphViewCount() == 0)\n    {\n        openedGraphCount_left = 0;\n        openedGraphCount_right = 0;\n        openedGraphCount_top = 0;\n        openedGraphCount_bottom = 0;\n    }\n    \n    // Force geometry calculation, which is lazy\n    p_window->setAttribute(Qt::WA_DontShowOnScreen, true);\n    p_window->show();\n    p_window->hide();\n    p_window->setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // Now get the frame geometry; note that on X11 systems the window frame is often not included in frameGeometry(), even\n    // though it's supposed to be, because it is simply not available from X.  We attempt to compensate by adding in the\n    // height of the window title bar, although that entails making assumptions about the windowing system appearance.\n    QRect windowFrame = p_window->frameGeometry();\n    QRect mainWindowFrame = this->frameGeometry();\n    bool drawerIsOpen = (!!tablesDrawerController);\n    const int titleBarHeight = 30;\n    QPoint unadjust;\n    \n    if (windowFrame == p_window->geometry())\n    {\n        windowFrame.adjust(0, -titleBarHeight, 0, 0);\n        unadjust = QPoint(0, 30);\n    }\n    if (mainWindowFrame == this->geometry())\n    {\n        mainWindowFrame.adjust(0, -titleBarHeight, 0, 0);\n    }\n    \n    // try along the bottom first\n    {\n        QRect candidateFrame = windowFrame;\n        \n        candidateFrame.moveLeft(mainWindowFrame.left() + openedGraphCount_bottom * (windowFrame.width() + 5));\n        candidateFrame.moveTop(mainWindowFrame.bottom() + 5);\n        \n        if (rectIsOnscreen(candidateFrame) && (candidateFrame.right() <= mainWindowFrame.right()))          // avoid going over to the right, to leave room for the tables drawer window\n        {\n            p_window->move(candidateFrame.topLeft() + unadjust);\n            openedGraphCount_bottom++;\n            return;\n        }\n    }\n    \n    // try on the left side\n    {\n        QRect candidateFrame = windowFrame;\n        \n        candidateFrame.moveRight(mainWindowFrame.left() - 5);\n        candidateFrame.moveTop(mainWindowFrame.top() + openedGraphCount_left * (windowFrame.height() + 5));\n        \n        if (rectIsOnscreen(candidateFrame)) // && (candidateFrame.bottom() <= mainWindowFrame.bottom()))    // doesn't overlap anybody else\n        {\n            p_window->move(candidateFrame.topLeft() + unadjust);\n            openedGraphCount_left++;\n            return;\n        }\n    }\n    \n    // try along the top\n\t{\n\t\tQRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.moveLeft(mainWindowFrame.left() + openedGraphCount_top * (windowFrame.width() + 5));\n\t\tcandidateFrame.moveBottom(mainWindowFrame.top() - 5);\n\t\t\n        if (rectIsOnscreen(candidateFrame)) // && (candidateFrame.right() <= mainWindowFrame.right()))    // doesn't overlap anybody else\n        {\n            p_window->move(candidateFrame.topLeft() + unadjust);\n            openedGraphCount_top++;\n            return;\n        }\n\t}\n    \n    // unless the drawer is open, let's try on the right side\n\tif (!drawerIsOpen)\n\t{\n\t\tQRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.moveLeft(mainWindowFrame.right() + 5);\n        candidateFrame.moveTop(mainWindowFrame.top() + openedGraphCount_right * (windowFrame.height() + 5));\n\t\t\n        if (rectIsOnscreen(candidateFrame)) // && (candidateFrame.bottom() <= mainWindowFrame.bottom()))   // doesn't overlap anybody else\n        {\n            p_window->move(candidateFrame.topLeft() + unadjust);\n            openedGraphCount_right++;\n            return;\n        }\n\t}\n\t\n    // if the drawer is open, try to the right of it\n    if (drawerIsOpen)\n    {\n        QRect drawerFrame = tablesDrawerController->frameGeometry();\n        QRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.moveLeft(drawerFrame.right() + 5);\n        candidateFrame.moveTop(drawerFrame.top() + openedGraphCount_right * (windowFrame.height() + 5));\n\t\t\n        if (rectIsOnscreen(candidateFrame)) // && (candidateFrame.bottom() <= drawerFrame.bottom()))    // doesn't overlap anybody else\n        {\n            p_window->move(candidateFrame.topLeft() + unadjust);\n            openedGraphCount_right++;\n            return;\n        }\n    }\n\t\n\t// if none of those worked, we just leave the window where it got placed out of the nib\n}\n\nQWidget *QtSLiMWindow::imageWindowWithPath(const QString &path)\n{\n    QImage image(path);\n    QFileInfo fileInfo(path);\n    \n    // We have an image; note that it might be a \"null image\", however\n    bool null = image.isNull();\n    int window_width = (null ? 288 : image.width());\n    int window_height = (null ? 288 : image.height());\n    \n    QWidget *image_window = new QWidget(this, Qt::Window | Qt::Tool);    // the image window has us as a parent, but is still a standalone window\n    \n    image_window->setWindowTitle(fileInfo.fileName());\n    image_window->setFixedSize(window_width, window_height);\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    image_window->setWindowIcon(qtSLiMAppDelegate->genericDocumentIcon());    // doesn't seem to quite work; we get the SLiM document icon, inherited from parent presumably\n#endif\n    image_window->setWindowFilePath(path);\n    \n    // Make the image view\n    QLabel *imageView = new QLabel();\n    \n    imageView->setStyleSheet(\"QLabel { background-color : white; }\");\n    imageView->setBackgroundRole(QPalette::Base);\n    imageView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);\n    imageView->setScaledContents(true);\n    imageView->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);\n    \n    if (null)\n        imageView->setText(\"No image data\");\n    else\n        imageView->setPixmap(QPixmap::fromImage(image));\n    \n    // Install imageView in the window\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    image_window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    topLayout->addWidget(imageView);\n    \n    // Make a file system watcher to update us when the image changes\n    QFileSystemWatcher *watcher = new QFileSystemWatcher(QStringList(path), image_window);\n    \n    connect(watcher, &QFileSystemWatcher::fileChanged, imageView, [imageView](const QString &watched_path) {\n        QImage watched_image(watched_path);\n        \n        if (watched_image.isNull()) {\n            imageView->setText(\"No image data\");\n        } else {\n            imageView->setPixmap(QPixmap::fromImage(watched_image));\n            imageView->window()->setFixedSize(watched_image.width(), watched_image.height());\n        }\n    });\n    \n    // Set up a context menu for copy/open\n    QMenu *contextMenu = new QMenu(\"image_menu\", imageView);\n    contextMenu->addAction(\"Copy Image\", this, [path]() {\n        QImage watched_image(path);     // get the current image from the filesystem\n        QClipboard *clipboard = QGuiApplication::clipboard();\n        clipboard->setImage(watched_image);\n    });\n    contextMenu->addAction(\"Copy File Path\", this, [path]() {\n        QClipboard *clipboard = QGuiApplication::clipboard();\n        clipboard->setText(path);\n    });\n    \n    // Reveal in Finder / Show in Explorer: see https://stackoverflow.com/questions/3490336\n    // Note there is no good solution on Linux, so we do \"Open File\" instead\n    #if defined(Q_OS_MACOS)\n    contextMenu->addAction(\"Reveal in Finder\", this, [path]() {\n        const QFileInfo fileInfo(path);\n        QStringList scriptArgs;\n        scriptArgs << QLatin1String(\"-e\") << QString::fromLatin1(\"tell application \\\"Finder\\\" to reveal POSIX file \\\"%1\\\"\").arg(fileInfo.canonicalFilePath());\n        QProcess::execute(QLatin1String(\"/usr/bin/osascript\"), scriptArgs);\n        scriptArgs.clear();\n        scriptArgs << QLatin1String(\"-e\") << QLatin1String(\"tell application \\\"Finder\\\" to activate\");\n        QProcess::execute(QLatin1String(\"/usr/bin/osascript\"), scriptArgs);\n    });\n    #elif defined(Q_WS_WIN)\n    contextMenu->addAction(\"Show in Explorer\", [path]() {\n        const QFileInfo fileInfo(path);\n        const FileName explorer = Environment::systemEnvironment().searchInPath(QLatin1String(\"explorer.exe\"));\n        if (explorer.isEmpty())\n            qApp->beep();\n        QStringList param;\n        if (!fileInfo.isDir())\n            param += QLatin1String(\"/select,\");\n        param += QDir::toNativeSeparators(fileInfo.canonicalFilePath());\n        QProcess::startDetached(explorer.toString() + \" \" + param);\n    });\n    #else\n    contextMenu->addAction(\"Open File\", [path]() {\n        QDesktopServices::openUrl(QUrl::fromLocalFile(path));\n    });\n    #endif\n    \n    imageView->setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(imageView, &QLabel::customContextMenuRequested, imageView, [imageView, contextMenu](const QPoint &pos) {\n        // Run the context menu if we have an image (in which case the text length is zero)\n        if (imageView->text().length() == 0)\n            contextMenu->exec(imageView->mapToGlobal(pos));\n    });\n    \n    // Position the window nicely\n    positionNewSubsidiaryWindow(image_window);\n    \n    // make window actions for all global menu items\n    // we do NOT need to do this, because we use Qt::Tool; Qt will use our parent window's shortcuts\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(this);\n    \n    image_window->setAttribute(Qt::WA_DeleteOnClose, true);\n    \n    return image_window;\n}\n\nQWidget *QtSLiMWindow::graphWindowWithView(QtSLiMGraphView *graphView, double windowWidth, double windowHeight)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    // Make a new window to show the graph\n    QWidget *graph_window = new QWidget(this, Qt::Window | Qt::Tool);    // the graph window has us as a parent, but is still a standalone window\n    QString title = graphView->graphTitle();\n    \n    graph_window->setWindowTitle(title);\n    graph_window->setMinimumSize(250, 250);\n    graph_window->resize(windowWidth, windowHeight);\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    graph_window->setWindowIcon(QIcon());\n#endif\n    \n    // Install graphView in the window\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    graph_window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    topLayout->addWidget(graphView);\n    \n    // Add a horizontal layout at the bottom, for popup buttons and such added by the graph\n    QHBoxLayout *buttonLayout = nullptr;\n    \n    {\n        buttonLayout = new QHBoxLayout;\n        \n        buttonLayout->setContentsMargins(5, 5, 5, 5);\n        buttonLayout->setSpacing(5);\n        topLayout->addLayout(buttonLayout);\n        \n        QLabel *speciesLabel = new QLabel();\n        speciesLabel->setText(\"\");\n        buttonLayout->addWidget(speciesLabel);\n        speciesLabel->setHidden(true);\n        \n        QSpacerItem *rightSpacer = new QSpacerItem(16, 5, QSizePolicy::Expanding, QSizePolicy::Minimum);\n        buttonLayout->addItem(rightSpacer);\n        \n        // this code is based on the creation of executeScriptButton in ui_QtSLiMEidosConsole.h\n        QtSLiMPushButton *actionButton = new QtSLiMPushButton(graph_window);\n        actionButton->setObjectName(QString::fromUtf8(\"actionButton\"));\n        actionButton->setMinimumSize(QSize(20, 20));\n        actionButton->setMaximumSize(QSize(20, 20));\n        actionButton->setFocusPolicy(Qt::NoFocus);\n        QIcon icon4;\n        icon4.addFile(QtSLiMImagePath(\"action\", false), QSize(), QIcon::Normal, QIcon::Off);\n        icon4.addFile(QtSLiMImagePath(\"action\", true), QSize(), QIcon::Normal, QIcon::On);\n        actionButton->setIcon(icon4);\n        actionButton->setIconSize(QSize(20, 20));\n        actionButton->qtslimSetBaseName(\"action\");\n        actionButton->setCheckable(true);\n        actionButton->setFlat(true);\n#if QT_CONFIG(tooltip)\n        actionButton->setToolTip(\"<html><head/><body><p>configure graph</p></body></html>\");\n#endif // QT_CONFIG(tooltip)\n        buttonLayout->addWidget(actionButton);\n        \n        connect(actionButton, &QPushButton::pressed, graphView, [actionButton, graphView]() { actionButton->qtslimSetHighlight(true); graphView->actionButtonRunMenu(actionButton); });\n        connect(actionButton, &QPushButton::released, graphView, [actionButton]() { actionButton->qtslimSetHighlight(false); });\n        \n        actionButton->setEnabled(!invalidSimulation() && (community->Tick() > 0));\n    }\n    \n    // Give the graph view a chance to do something with the window it's now in\n    graphView->addedToWindow();\n    \n    // force geometry calculation, which is lazy\n    graph_window->setAttribute(Qt::WA_DontShowOnScreen, true);\n    graph_window->show();\n    graph_window->hide();\n    graph_window->setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // If we added a button layout, give it room so the graph area is still square\n    // Note this has to happen after forcing layout calculations\n    if (buttonLayout)\n    {\n        QSize contentSize = graph_window->size();\n        QSize minSize = graph_window->minimumSize();\n        int buttonLayoutHeight = buttonLayout->geometry().height();\n        \n        contentSize.setHeight(contentSize.height() + buttonLayoutHeight);\n        graph_window->resize(contentSize);\n        \n        minSize.setHeight(minSize.height() + buttonLayoutHeight);\n        graph_window->setMinimumSize(minSize);\n    }\n    \n    // Position the window nicely\n    positionNewSubsidiaryWindow(graph_window);\n    \n    // make window actions for all global menu items\n    // we do NOT need to do this, because we use Qt::Tool; Qt will use our parent window's shortcuts\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(graph_window);\n    \n    graph_window->setAttribute(Qt::WA_DeleteOnClose, true);\n    \n    graphView->updateSpeciesBadge();\n    \n    return graph_window;\n}\n\nvoid QtSLiMWindow::graphPopupButtonRunMenu(void)\n{\n\tbool disableAll = false;\n    Species *displaySpecies = focalDisplaySpecies();\n\t\n\t// When the simulation is not valid and initialized, the context menu is disabled\n\tif (invalidSimulation_ || !displaySpecies)\n\t\tdisableAll = true;\n    \n    QMenu contextMenu(\"graph_menu\", this);\n    \n    QAction *graph1DFreqSpectrum = contextMenu.addAction(\"Graph 1D Population SFS\");\n    graph1DFreqSpectrum->setEnabled(!disableAll);\n    \n    QAction *graph1DSampleSFS = contextMenu.addAction(\"Graph 1D Sample SFS\");\n    graph1DSampleSFS->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    QAction *graph2DFreqSpectrum = contextMenu.addAction(\"Graph 2D Population SFS\");\n    graph2DFreqSpectrum->setEnabled(!disableAll);\n    \n    QAction *graph2DSampleSFS = contextMenu.addAction(\"Graph 2D Sample SFS\");\n    graph2DSampleSFS->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    QAction *graphMutFreqTrajectories = contextMenu.addAction(\"Graph Mutation Frequency Trajectories\");\n    graphMutFreqTrajectories->setEnabled(!disableAll);\n    \n    QAction *graphMutLossTimeHist = contextMenu.addAction(\"Graph Mutation Loss Time Histogram\");\n    graphMutLossTimeHist->setEnabled(!disableAll);\n    \n    QAction *graphMutFixTimeHist = contextMenu.addAction(\"Graph Mutation Fixation Time Histogram\");\n    graphMutFixTimeHist->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    QAction *graphPopFitnessDist = contextMenu.addAction(\"Graph Population Fitness Distribution\");\n    graphPopFitnessDist->setEnabled(!disableAll);\n    \n    QAction *graphSubpopFitnessDists = contextMenu.addAction(\"Graph Subpopulation Fitness Distributions\");\n    graphSubpopFitnessDists->setEnabled(!disableAll);\n    \n    QAction *graphFitnessVsTime = contextMenu.addAction(\"Graph Fitness ~ Time\");\n    graphFitnessVsTime->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    QAction *graphAgeDistribution = contextMenu.addAction(\"Graph Age Distribution\");\n    graphAgeDistribution->setEnabled(!disableAll);\n    \n    QAction *graphLifetimeReproduction = contextMenu.addAction(\"Graph Lifetime Reproductive Output\");\n    graphLifetimeReproduction->setEnabled(!disableAll);\n    \n    QAction *graphPopSizeVsTime = contextMenu.addAction(\"Graph Population Size ~ Time\");\n    graphPopSizeVsTime->setEnabled(!disableAll);\n    \n    QAction *graphPopVisualization = contextMenu.addAction(\"Graph Population Visualization\");\n    graphPopVisualization->setEnabled(!disableAll);\n    \n    contextMenu.addSeparator();\n    \n    QAction *graphMultispeciesPopSizeVsTime = contextMenu.addAction(\"Multispecies Population Size ~ Time\");\n    graphMultispeciesPopSizeVsTime->setEnabled(!invalidSimulation_);\n    \n    contextMenu.addSeparator();\n    \n    // the haplotype plot menu items are a bit complicated\n    bool haplotypePlotEnabled = !disableAll && displaySpecies && !continuousPlayOn_ && displaySpecies->population_.subpops_.size();\n    \n    QAction *createHaplotypePlotAll = contextMenu.addAction(\"Create Haplotype Plot (all chromosomes)\");\n    createHaplotypePlotAll->setEnabled(haplotypePlotEnabled);\n    \n    QAction *createHaplotypePlotOne = contextMenu.addAction(\"Create Haplotype Plot (selected chromosome)\");\n    createHaplotypePlotOne->setEnabled(haplotypePlotEnabled && (focalChromosome() != nullptr));\n    \n    if (haplotypePlotEnabled && (displaySpecies->Chromosomes().size() > 1))\n    {\n        // enabled with 2+ chromosomes, we show both menu items\n        createHaplotypePlotAll->setText(\"Create Haplotype Plot (all chromosomes)\");\n        createHaplotypePlotOne->setVisible(true);\n    }\n    else\n    {\n        // disabled or with 0 or 1 chromosomes, we show only createHaplotypePlotAll\n        createHaplotypePlotAll->setText(\"Create Haplotype Plot\");\n        createHaplotypePlotOne->setVisible(false);\n    }\n    \n    // Run the context menu synchronously\n    QPoint mousePos = QCursor::pos();\n    QAction *action = contextMenu.exec(mousePos);\n    \n    if (action && !invalidSimulation_)\n    {\n        displaySpecies = focalDisplaySpecies();     // might change while the menu is running...\n        \n        if (action == createHaplotypePlotAll)\n        {\n            if (!continuousPlayOn_ && displaySpecies && displaySpecies->population_.subpops_.size())\n            {\n                isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n                \n                QtSLiMHaplotypeManager::CreateHaplotypePlot(chromosomeConfig, nullptr);\n            }\n            else\n            {\n                qApp->beep();\n            }\n        }\n        else if (action == createHaplotypePlotOne)\n        {\n            if (!continuousPlayOn_ && displaySpecies && displaySpecies->population_.subpops_.size() && (focalChromosome() != nullptr))\n            {\n                isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n                \n                QtSLiMHaplotypeManager::CreateHaplotypePlot(chromosomeConfig, focalChromosome());\n            }\n            else\n            {\n                qApp->beep();\n            }\n        }\n        else\n        {\n            QtSLiMGraphView *graphView = nullptr;\n            \n            if (displaySpecies)\n            {\n                if (action == graph1DFreqSpectrum)\n                    graphView = new QtSLiMGraphView_1DPopulationSFS(this, this);\n                if (action == graph1DSampleSFS)\n                    graphView = new QtSLiMGraphView_1DSampleSFS(this, this);\n                if (action == graph2DFreqSpectrum)\n                    graphView = new QtSLiMGraphView_2DPopulationSFS(this, this);\n                if (action == graph2DSampleSFS)\n                    graphView = new QtSLiMGraphView_2DSampleSFS(this, this);\n                if (action == graphMutFreqTrajectories)\n                    graphView = new QtSLiMGraphView_FrequencyTrajectory(this, this);\n                if (action == graphMutLossTimeHist)\n                    graphView = new QtSLiMGraphView_LossTimeHistogram(this, this);\n                if (action == graphMutFixTimeHist)\n                    graphView = new QtSLiMGraphView_FixationTimeHistogram(this, this);\n                if (action == graphPopFitnessDist)\n                    graphView = new QtSLiMGraphView_PopFitnessDist(this, this);\n                if (action == graphSubpopFitnessDists)\n                    graphView = new QtSLiMGraphView_SubpopFitnessDists(this, this);\n                if (action == graphFitnessVsTime)\n                    graphView = new QtSLiMGraphView_FitnessOverTime(this, this);\n                if (action == graphAgeDistribution)\n                    graphView = new QtSLiMGraphView_AgeDistribution(this, this);\n                if (action == graphLifetimeReproduction)\n                    graphView = new QtSLiMGraphView_LifetimeReproduction(this, this);\n                if (action == graphPopSizeVsTime)\n                    graphView = new QtSLiMGraphView_PopSizeOverTime(this, this);\n                if (action == graphPopVisualization)\n                    graphView = new QtSLiMGraphView_PopulationVisualization(this, this);\n            }\n            \n            if (action == graphMultispeciesPopSizeVsTime)\n                graphView = new QtSLiMGraphView_MultispeciesPopSizeOverTime(this, this);\n            \n            if (graphView)\n            {\n                QWidget *graphWindow = graphWindowWithView(graphView);\n                \n                if (graphWindow)\n                    QtSLiMMakeWindowVisibleAndExposed(graphWindow);\n            }\n            else\n            {\n                qApp->beep();\n            }                \n        }\n    }\n    \n    // This is not called by Qt, for some reason (nested tracking loops?), so we call it explicitly\n    graphPopupButtonReleased();\n}\n\nQWidget *QtSLiMWindow::newChromosomeDisplay(std::string chromosome_symbol, QString windowTitle)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    // Create a chromosome display window for the focal species; if the window is on the \"all\" tab\n    // in a multispecies model, just return (we shouldn't be called in that case anyway).\n    // FIXME there is a flaw in the whole design here -- none of this updates dynamically if the\n    // user changes the number of chromosomes, the chromosome symbols, etc.  The user will need\n    // to close the display window and open a new one, if that happens; not the end of the world.\n    // Fixing this would require a smarter controller object that rebuilds the whole content of\n    // the display after a recycle-and-step to reflect whatever the initialize() process built.\n    Species *species = focalDisplaySpecies();\n    \n    if (!species)\n        return nullptr;\n    \n    // Make a new window to show the chromosome display\n    QWidget *display_window = new QWidget(this, Qt::Window | Qt::Tool);    // the display window has us as a parent, but is still a standalone window\n    \n    display_window->setWindowTitle(windowTitle);\n#ifdef __APPLE__\n    // set the window icon only on macOS; on Linux it changes the app icon as a side effect\n    display_window->setWindowIcon(QIcon());\n#endif\n    \n    // Make a new layout for chromosome views and build the display inside it\n    QVBoxLayout *topLayout = new QVBoxLayout;\n    \n    display_window->setLayout(topLayout);\n    topLayout->setContentsMargins(0, 0, 0, 0);\n    topLayout->setSpacing(0);\n    \n    QtSLiMChromosomeWidgetController *displayController = new QtSLiMChromosomeWidgetController(this, display_window, species, chromosome_symbol);\n    \n    displayController->buildChromosomeDisplay(/* resetWindowSize */ true);\n    \n    // force geometry calculation, which is lazy\n    display_window->setAttribute(Qt::WA_DontShowOnScreen, true);\n    display_window->show();\n    display_window->hide();\n    display_window->setAttribute(Qt::WA_DontShowOnScreen, false);\n    \n    // Position the window nicely\n    display_window->move(this->frameGeometry().topLeft() + QPoint(50, 50));\n    \n    // make window actions for all global menu items\n    // we do NOT need to do this, because we use Qt::Tool; Qt will use our parent window's shortcuts\n    //qtSLiMAppDelegate->addActionsForGlobalMenuItems(display_window);\n    \n    display_window->setAttribute(Qt::WA_DeleteOnClose, true);\n    \n    return display_window;\n}\n\nvoid QtSLiMWindow::changeDirectoryClicked(void)\n{\n    isTransient = false;    // Since the user has taken an interest in the window, clear the document's transient status\n    \n    QFileDialog dialog(this);\n    dialog.setAcceptMode(QFileDialog::AcceptOpen);\n    dialog.setFileMode(QFileDialog::Directory);\n    dialog.setViewMode(QFileDialog::List);\n    dialog.setDirectory(QString::fromUtf8(sim_working_dir.c_str()));\n    \n    // FIXME could use QFileDialog::open() to get a sheet instead of an app-model panel...\n    if (dialog.exec())\n    {\n        QStringList fileNames = dialog.selectedFiles();\n        \n        if (fileNames.size() == 1)\n        {\n            sim_working_dir = fileNames[0].toUtf8().constData();\n            sim_requested_working_dir = sim_working_dir;\n        }\n    }\n}\n\nvoid QtSLiMWindow::subpopSelectionDidChange(const QItemSelection & /* selected */, const QItemSelection & /* deselected */)\n{\n    if (!invalidSimulation_ && !reloadingSubpopTableview)\n    {\n        QItemSelectionModel *selectionModel = ui->subpopTableView->selectionModel();\n        QModelIndexList selectedRows = selectionModel->selectedRows();\n        std::vector<Subpopulation *> subpops = listedSubpopulations();\n        size_t subpopCount = subpops.size();\n        \n        // first get the state of each row, for algorithmic convenience\n        std::vector<bool> rowSelectedState(subpopCount, false);\n        \n        for (QModelIndex &modelIndex : selectedRows)\n            rowSelectedState[static_cast<size_t>(modelIndex.row())] = true;\n        \n        // then loop through subpops and update their selected state\n        auto subpopIter = subpops.begin();\n        //bool all_selected = true;\n        bool none_selected = true;\n        \n        for (size_t i = 0; i < subpopCount; ++i)\n        {\n            (*subpopIter)->gui_selected_ = rowSelectedState[i];\n            \n            if ((*subpopIter)->gui_selected_)\n                none_selected = false;\n            //else\n            //    all_selected = false;\n            \n            subpopIter++;\n        }\n        \n        // If the selection has changed, that means that our private mutation tallies need to be recomputed\n        for (Species *species : community->AllSpecies())\n\t\t{\n\t\t\tspecies->population_.InvalidateMutationReferencesCache();\t// force a retally\n\t\t\tspecies->population_.TallyMutationReferencesAcrossPopulation_SLiMgui();\n\t\t}\n\t\t\n        // It's a bit hard to tell for sure whether we need to update or not, since a selected subpop might have been removed from the tableview;\n        // selection changes should not happen often, so we can just always update, I think.\n        ui->individualsWidget->update();\n        \n        for (QtSLiMChromosomeWidget *zoomedWidget : chromosomeZoomedWidgets)\n            zoomedWidget->update();     // was setNeedsDisplayInInterior, which would be more minimal\n        \n        // We don't want to allow an empty selection, maybe; if we are now in that state, and there are subpops to select, select them all\n        // See also updateAfterTickFull() which also needs to do this\n        if (none_selected && subpops.size())\n            ui->subpopTableView->selectAll();\n    }\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMWindow.h",
    "content": "//\n//  QtSLiMWindow.h\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIMWINDOW_H\n#define QTSLIMWINDOW_H\n\n#include <QMainWindow>\n#include <QTimer>\n#include <QElapsedTimer>\n#include <QColor>\n#include <QDateTime>\n#include <QApplication>\n\n#include <string>\n#include <vector>\n#include <unordered_map>\n#include <ctime>\n\n#include \"eidos_globals.h\"\n#include \"slim_globals.h\"\n#include \"eidos_rng.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"QtSLiMExtras.h\"\n#include \"QtSLiMPopulationTable.h\"\n\nclass Subpopulation;\nclass QCloseEvent;\nclass QTextCursor;\nclass QtSLiMEidosConsole;\nclass QtSLiMTablesDrawer;\nclass QItemSelection;\nclass SLiMgui;\nclass QtSLiMGraphView;\nclass QtSLiMGraphView_CustomPlot;\nclass Plot;\nclass QtSLiMScriptTextEdit;\nclass QtSLiMTextEdit;\nclass QtSLiMDebugOutputWindow;\nclass QtSLiMChromosomeWidget;\nclass QtSLiMChromosomeWidgetController;\nclass LogFile;\n\n\nnamespace Ui {\nclass QtSLiMWindow;\n}\n\nclass QtSLiMWindow : public QMainWindow\n{\n    Q_OBJECT    \n\nprivate:\n    // basic file i/o and change count management\n    void init(void);\n    void initializeUI(void);\n    bool maybeSave(void);\n    bool saveFile(const QString &fileName);\n    void setCurrentFile(const QString &fileName);\n    \n    int slimChangeCount = 0;                    // private change count governing the recycle button's highlight\n    \n    QString lastSavedString;                    // the last string saved to disk, or initial script string\n    QDateTime lastSavedDate;                    // the date when we last saved, to detect external changes\n    bool scriptChangeObserved = false;          // has a change to the script been observed since last saved?\n    bool isScriptModified(void);                // uses scriptChangeObserved / lastSavedString to determine modified status\n    \n    // tracking our interaction with the user about the file on disk, mod dates, external editing, etc.\n    // the goal here is to avoid warning more than once; see https://github.com/MesserLab/SLiM/issues/476\n    bool warnedAboutUnreadabilityOnDisk = false;    // avoid repeating this unless it gets fixed\n    bool warnedAboutNotExistingOnDisk = false;      // avoid repeating this unless it gets fixed\n    bool warnedAboutExternalEditing = false;        // avoid repeating this unless it gets fixed or changes\n    QString lastExternalChangeString;               // the string we last observed on disk and warned about\n    bool currentlyWarningAboutDiskFile = false;     // a flag to avoid re-entrancy for this window\n    \n    // state variables that are globals in Eidos and SLiM; we swap these in and out as needed, to provide each sim with its own context\n\tbool sim_RNG_initialized = false;\n    Eidos_RNG_State sim_RNG;                // QtSLiM never runs multithreaded, so we do not need the _PERTHREAD variant here\n    slim_pedigreeid_t sim_next_pedigree_id = 0;\n    slim_mutationid_t sim_next_mutation_id = 0;\n    bool sim_suppress_warnings = false;\n    std::string sim_working_dir;\t\t\t// the current working dir that we will return to when executing SLiM/Eidos code\n    std::string sim_requested_working_dir;\t// the last working dir set by the user with the SLiMgui button/menu; we return to it on recycle\n\n    // play-related variables; note that continuousPlayOn covers profiling play, tick play, and normal play, whereas profilePlayOn,\n    // tickPlayOn_, and nonProfilePlayOn_ cover those cases individually; this is for simplicity in enable bindings in the nib\n    bool invalidSimulation_ = true, continuousPlayOn_ = false, profilePlayOn_ = false, nonProfilePlayOn_ = false;\n    bool tickPlayOn_ = false, reachedSimulationEnd_ = false, hasImported_ = false;\n    slim_tick_t targetTick_ = 0;\n    QElapsedTimer continuousPlayElapsedTimer_;\n    QTimer continuousPlayInvocationTimer_;\n    uint64_t continuousPlayTicksCompleted_ = 0;\n    QTimer continuousProfileInvocationTimer_;\n    QTimer playOneStepInvocationTimer_;\n    int partialUpdateCount_ = 0;\n    std::clock_t elapsedCPUClock_ = 0;      // kept even when not profiling, for status bar updates\n\n    QtSLiMPopulationTableModel *populationTableModel_ = nullptr;\n    QtSLiMEidosConsole *consoleController = nullptr;\n    QtSLiMTablesDrawer *tablesDrawerController = nullptr;\n    \n    QtSLiMDebugOutputWindow *debugOutputWindow_ = nullptr;\n    QTimer debugButtonFlashTimer_;\n    int debugButtonFlashCount_ = 0;\n    \n    int openedGraphCount_left = 0;      // used for new graph window positioning\n    int openedGraphCount_right = 0;\n    int openedGraphCount_top = 0;\n    int openedGraphCount_bottom = 0;\n    \npublic:\n    bool isZombieWindow_ = false;   // set when the UI is invalidated, to avoid various issues\n    bool isUntitled = false, isRecipe = false, isTransient = false;\n    QString currentFile;\n    \n    std::string scriptString;\t// the script string that we are running on right now; not the same as the script textview!\n    Community *community = nullptr;\t\t// the simulation instance for this window\n    Species *focalSpecies = nullptr;    // NOT OWNED: a pointer to the focal species in community; do not use, call focalDisplaySpecies()\n    std::string focalSpeciesName;       // the name of the focal species (or \"all\"), for persistence across recycles\n    SLiMgui *slimgui = nullptr;\t\t\t// the SLiMgui Eidos class instance for this window\n\n    // display-related variables\n    std::unordered_map<slim_objectid_t, QColor> genomicElementColorRegistry;\n    bool reloadingSubpopTableview = false;\n    bool reloadingSpeciesBar = false;\n    \n    // chromosome view configuration, applied to all chromosome views in multispecies models\n    QtSLiMChromosomeWidgetController *chromosomeConfig = nullptr;\n    \npublic:\n    typedef enum {\n        WF = 0,\n        nonWF\n    } ModelType;\n    \n    QtSLiMWindow(QtSLiMWindow::ModelType modelType, bool includeComments);  // untitled window\n    explicit QtSLiMWindow(const QString &fileName);                         // window from a file\n    QtSLiMWindow(const QString &recipeName, const QString &recipeScript);   // window from a recipe\n    virtual ~QtSLiMWindow() override;\n    \n    void tile(const QMainWindow *previous);\n    void displayStartupMessage(void);\n    void loadFile(const QString &fileName);                                     // loads a file into an existing window\n    void loadRecipe(const QString &recipeName, const QString &recipeScript);    // loads a recipe into an existing window\n    QWidget *imageWindowWithPath(const QString &path);                          // creates an image window subsidiary to the receiver\n    \n    static const QColor &blackContrastingColorForIndex(int index);\n    static const QColor &whiteContrastingColorForIndex(int index);\n    void colorForGenomicElementType(GenomicElementType *elementType, slim_objectid_t elementTypeID, float *p_red, float *p_green, float *p_blue, float *p_alpha);\n    void colorForSpecies(Species *species, float *p_red, float *p_green, float *p_blue, float *p_alpha);\n    QColor qcolorForSpecies(Species *species);\n    \n    std::vector<Subpopulation *> listedSubpopulations(void);\n    std::vector<Subpopulation*> selectedSubpopulations(void);\n    \n    inline bool invalidSimulation(void) { return invalidSimulation_; }\n    void setInvalidSimulation(bool p_invalid);\n    inline bool reachedSimulationEnd(void) { return reachedSimulationEnd_; }\n    void setReachedSimulationEnd(bool p_reachedEnd);\n    inline bool isPlaying(void) { return continuousPlayOn_; }\n    void setContinuousPlayOn(bool p_flag);\n    void setTickPlayOn(bool p_flag);\n    void setProfilePlayOn(bool p_flag);\n    void setNonProfilePlayOn(bool p_flag);\n    QtSLiMScriptTextEdit *scriptTextEdit(void);\n    QtSLiMTextEdit *outputTextEdit(void);\n    QtSLiMEidosConsole *ConsoleController(void) { return consoleController; }\n    QtSLiMTablesDrawer *TablesDrawerController(void) { return tablesDrawerController; }\n    \n    QtSLiMDebugOutputWindow *debugOutputWindow(void) { return debugOutputWindow_; }\n    void flashDebugButton(void);\n    void stopDebugButtonFlash(void);\n    \n    void checkForSimulationTermination(void);\n    void startNewSimulationFromScript(void);\n    void setScriptStringAndInitializeSimulation(std::string string);\n    \n    Species *focalDisplaySpecies(void);\n    Chromosome *focalChromosome(void);\n    \n    void updateOutputViews(void);\n    void updateTickCounter(void);\n    void updateSpeciesBar(void);\n    void updateChromosomeViewSetup(void);\n    void updateAfterTickFull(bool p_fullUpdate);\n    void updatePlayButtonIcon(bool pressed);\n    void updateProfileButtonIcon(bool pressed);\n    void updateRecycleButtonIcon(bool pressed);\n    void updateUIEnabling(void);\n    void updateMenuEnablingACTIVE(QWidget *focusWidget);\n    void updateMenuEnablingINACTIVE(QWidget *focusWidget, QWidget *focusWindow);\n    void updateMenuEnablingSHARED(QWidget *focusWidget);\n    void updateWindowMenu(void);\n\n    void colorScriptWithProfileCountsFromNode(const EidosASTNode *node, double elapsedTime, int32_t baseIndex, QTextDocument *doc, QTextCharFormat &baseFormat);\n    void displayProfileResults(void);\n    \n    void willExecuteScript(void);\n    void didExecuteScript(void);\n    bool runSimOneTick(void);\n    void _continuousPlay(void);\n    void _continuousProfile(void);\n    void _playOneStep(void);\n    \n    enum PlayType {\n        kNormalPlay = 0,\n        kProfilePlay,\n        kTickPlay,\n    };\n    void playOrProfile(PlayType playType);\n    \n    bool windowIsReuseable(void);   // requires isUntitled, !isRecipe, isTransient, and other conditions\n    void updateChangeCount(void);\n    bool changedSinceRecycle(void);\n    void resetSLiMChangeCount(void);\n    void scriptTexteditChanged(void);\n    void setScriptBlockLabelTextFromSelection(void);\n    \n    bool checkScriptSuppressSuccessResponse(bool suppressSuccessResponse);   \n    \n    bool offerAndExecuteAutofix(QTextCursor target, QString replacement, QString explanation, QString terminationMessage);\n    bool checkTerminationForAutofix(QString terminationMessage);\n    \n    //\tEidos SLiMgui method forwards\n    EidosValue_SP eidos_logFileData(LogFile *logFile, EidosValue *column_value);\n    void eidos_openDocument(QString path);\n    void eidos_pauseExecution(void);\n    QtSLiMGraphView_CustomPlot *eidos_createPlot(QString title, double *x_range, double *y_range, QString x_label, QString y_label, double width, double height, bool horizontalGrid, bool verticalGrid, bool fullBox, double axisLabelSize, double tickLabelSize);\n    QtSLiMGraphView_CustomPlot *eidos_plotWithTitle(QString title);\n    \n    void plotLogFileData_1D(QString title, QString y_title, double *y_values, int data_count);\n    void plotLogFileData_2D(QString title, QString x_title, QString y_title, double *x_values, double *y_values, int data_count, bool makeScatterPlot);\n    \nsignals:\n    void terminationWithMessage(QString message, EidosErrorContext errorContext);\n    void playStateChanged(void);\n    void controllerChangeCountChanged(int changeCount);\n    \n    void controllerPartialUpdateAfterTick(void);\n    void controllerFullUpdateAfterTick(void);\n    void controllerTickFinished(void);\n    void controllerRecycled(void);\n    \npublic slots:\n    void showTerminationMessage(QString terminationMessage, EidosErrorContext errorContext);\n    \n    void playOneStepClicked(void);\n    void tickChanged(void);\n    void recycleClicked(void);\n    void playSpeedChanged(void);\n\n    void showDrawerClicked(void);\n    void chromosomeDisplayPopupButtonRunMenu(void);\n    void showConsoleClicked(void);\n    void showBrowserClicked(void);\n    void jumpToPopupButtonRunMenu(void);\n\n    void clearOutputClicked(void);\n    void clearDebugPointsClicked(void);\n    void dumpPopulationClicked(void);\n    void debugOutputClicked(void);\n    void graphPopupButtonRunMenu(void);\n    void changeDirectoryClicked(void);\n    void displayGraphClicked(void);\n\n    void selectedSpeciesChanged(void);\n    void subpopSelectionDidChange(const QItemSelection &selected, const QItemSelection &deselected);\n    \n    //\n    //  UI glue, defined in QtSLiMWindow_glue.cpp\n    //\n    \nprivate slots:\n    void displayFontPrefChanged(void);\n    void applicationPaletteChanged(void);\n    \n    bool save(void);\n    bool saveAs(void);\n    void revert(void);\n    void documentWasModified(void);\n    void appStateChanged(Qt::ApplicationState state);\n    \n    void playOneStepPressed(void);\n    void playOneStepReleased(void);\n    void playPressed(void);\n    void playReleased(void);\n    void profilePressed(void);\n    void profileReleased(void);\n    void recyclePressed(void);\n    void recycleReleased(void);\n\n    void toggleDrawerPressed(void);\n    void toggleDrawerReleased(void);\n    void chromosomeActionPressed(void);\n    void chromosomeActionReleased(void);\n    void chromosomeDisplayPressed(void);\n    void chromosomeDisplayReleased(void);\n\n    void clearDebugPressed(void);\n    void clearDebugReleased(void);\n    void checkScriptPressed(void);\n    void checkScriptReleased(void);\n    void prettyprintPressed(void);\n    void prettyprintReleased(void);\n    void scriptHelpPressed(void);\n    void scriptHelpReleased(void);\n    void showConsolePressed(void);\n    void showConsoleReleased(void);\n    void showBrowserPressed(void);\n    void showBrowserReleased(void);\n    void jumpToPopupButtonPressed(void);\n    void jumpToPopupButtonReleased(void);\n\n    void clearOutputPressed(void);\n    void clearOutputReleased(void);\n    void dumpPopulationPressed(void);\n    void dumpPopulationReleased(void);\n    void debugOutputPressed(void);\n    void debugOutputReleased(void);\n    void graphPopupButtonPressed(void);\n    void graphPopupButtonReleased(void);\n    void changeDirectoryPressed(void);\n    void changeDirectoryReleased(void);\n    \n    void handleDebugButtonFlash(void);\n    \n    void finish_eidos_pauseExecution(void);\n    \nprotected:\n    virtual void closeEvent(QCloseEvent *p_event) override;\n    virtual void moveEvent(QMoveEvent *p_event) override;\n    virtual void resizeEvent(QResizeEvent *p_event) override;\n    virtual void showEvent(QShowEvent *p_event) override;\n    void positionNewSubsidiaryWindow(QWidget *window);\n    QWidget *graphWindowWithView(QtSLiMGraphView *graphView, double windowWidth=300, double windowHeight=300);\n    QtSLiMGraphView *graphViewForGraphWindow(QWidget *window);\n    QWidget *newChromosomeDisplay(std::string chromosome_symbol, QString windowTitle);  // pass \"\" for all chromosomes, or a symbol for one chromosome\n    \n    // used to suppress saving of resize/position info until we are fully constructed\n    bool donePositioning_ = false;\n    \n    // splitter support\n    void interpolateVerticalSplitter(void);\n    QWidget *overallTopWidget = nullptr;\n    QWidget *overallBottomWidget = nullptr;\n    QSplitter *overallSplitter = nullptr;\n    \n    void interpolateHorizontalSplitter(void);\n    QWidget *scriptWidget = nullptr;\n    QWidget *outputWidget = nullptr;\n    QSplitter *bottomSplitter = nullptr;\n    \n    void interpolateSplitters(void);\n    \n    // multispecies chromosome view support\n    std::vector<QVBoxLayout *> chromosomeWidgetLayouts;\n    std::vector<QtSLiMChromosomeWidget *> chromosomeOverviewWidgets;\n    std::vector<QtSLiMChromosomeWidget *> chromosomeZoomedWidgets;\n    \n    void removeExtraChromosomeViews(void);\n    void addChromosomeWidgets(QVBoxLayout *chromosomeLayout, QtSLiMChromosomeWidget *overviewWidget, QtSLiMChromosomeWidget *zoomedWidget);\n    void runChromosomeContextMenuAtPoint(QPoint p_globalPoint);\n    \nprivate:\n    void glueUI(void);\n    void invalidateUI(void);\n    QtSLiMGraphView *graphViewWithTitle(QString title);\n    int graphViewCount(void);\n    \n    Ui::QtSLiMWindow *ui;\n};\n\n#endif // QTSLIMWINDOW_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiMWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QtSLiMWindow</class>\n <widget class=\"QMainWindow\" name=\"QtSLiMWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>914</width>\n    <height>691</height>\n   </rect>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>850</width>\n    <height>500</height>\n   </size>\n  </property>\n  <widget class=\"QWidget\" name=\"centralWidget\">\n   <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n    <property name=\"leftMargin\">\n     <number>10</number>\n    </property>\n    <property name=\"topMargin\">\n     <number>10</number>\n    </property>\n    <property name=\"rightMargin\">\n     <number>10</number>\n    </property>\n    <property name=\"bottomMargin\">\n     <number>10</number>\n    </property>\n    <item>\n     <layout class=\"QVBoxLayout\" name=\"overallTopLayout\" stretch=\"1,0\">\n      <property name=\"spacing\">\n       <number>5</number>\n      </property>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"topLayout\">\n        <property name=\"spacing\">\n         <number>10</number>\n        </property>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"speciesSubpopTableLayout\">\n          <item>\n           <widget class=\"QWidget\" name=\"speciesBarWidget\" native=\"true\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>270</width>\n              <height>21</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>270</width>\n              <height>21</height>\n             </size>\n            </property>\n            <layout class=\"QHBoxLayout\" name=\"speciesBarLayout\">\n             <property name=\"leftMargin\">\n              <number>0</number>\n             </property>\n             <property name=\"topMargin\">\n              <number>0</number>\n             </property>\n             <property name=\"rightMargin\">\n              <number>0</number>\n             </property>\n             <property name=\"bottomMargin\">\n              <number>0</number>\n             </property>\n             <item>\n              <widget class=\"QTabBar\" name=\"speciesBar\" native=\"true\"/>\n             </item>\n             <item>\n              <spacer name=\"speciesBarSpacer\">\n               <property name=\"orientation\">\n                <enum>Qt::Orientation::Horizontal</enum>\n               </property>\n               <property name=\"sizeHint\" stdset=\"0\">\n                <size>\n                 <width>40</width>\n                 <height>10</height>\n                </size>\n               </property>\n              </spacer>\n             </item>\n            </layout>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QTableView\" name=\"subpopTableView\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Expanding\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>300</width>\n              <height>0</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>300</width>\n              <height>130</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"verticalScrollBarPolicy\">\n             <enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOn</enum>\n            </property>\n            <property name=\"editTriggers\">\n             <set>QAbstractItemView::EditTrigger::NoEditTriggers</set>\n            </property>\n            <property name=\"tabKeyNavigation\">\n             <bool>false</bool>\n            </property>\n            <property name=\"showDropIndicator\" stdset=\"0\">\n             <bool>false</bool>\n            </property>\n            <property name=\"selectionMode\">\n             <enum>QAbstractItemView::SelectionMode::ExtendedSelection</enum>\n            </property>\n            <property name=\"selectionBehavior\">\n             <enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>\n            </property>\n            <property name=\"showGrid\">\n             <bool>false</bool>\n            </property>\n            <property name=\"wordWrap\">\n             <bool>false</bool>\n            </property>\n            <property name=\"cornerButtonEnabled\">\n             <bool>false</bool>\n            </property>\n            <attribute name=\"verticalHeaderVisible\">\n             <bool>false</bool>\n            </attribute>\n           </widget>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <widget class=\"QtSLiMIndividualsWidget\" name=\"individualsWidget\">\n          <property name=\"sizePolicy\">\n           <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n            <horstretch>0</horstretch>\n            <verstretch>0</verstretch>\n           </sizepolicy>\n          </property>\n          <property name=\"maximumSize\">\n           <size>\n            <width>16777215</width>\n            <height>130</height>\n           </size>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"topRightLayout\">\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"playControlsLayout\">\n            <property name=\"sizeConstraint\">\n             <enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>\n            </property>\n            <item>\n             <widget class=\"QtSLiMPushButton\" name=\"playOneStepButton\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"focusPolicy\">\n               <enum>Qt::FocusPolicy::NoFocus</enum>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;step one tick&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"icon\">\n               <iconset resource=\"buttons.qrc\">\n                <normaloff>:/buttons/play_step.png</normaloff>\n                <normalon>:/buttons/play_step_H.png</normalon>:/buttons/play_step.png</iconset>\n              </property>\n              <property name=\"iconSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"flat\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QtSLiMPushButton\" name=\"playButton\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"focusPolicy\">\n               <enum>Qt::FocusPolicy::NoFocus</enum>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;play simulation continuously&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"icon\">\n               <iconset resource=\"buttons.qrc\">\n                <normaloff>:/buttons/play.png</normaloff>\n                <normalon>:/buttons/play_H.png</normalon>:/buttons/play.png</iconset>\n              </property>\n              <property name=\"iconSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"checkable\">\n               <bool>true</bool>\n              </property>\n              <property name=\"flat\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QtSLiMPushButton\" name=\"profileButton\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>30</width>\n                <height>30</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>30</width>\n                <height>30</height>\n               </size>\n              </property>\n              <property name=\"focusPolicy\">\n               <enum>Qt::FocusPolicy::NoFocus</enum>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;profile simulation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"icon\">\n               <iconset resource=\"buttons.qrc\">\n                <normaloff>:/buttons/profile.png</normaloff>\n                <normalon>:/buttons/profile_H.png</normalon>:/buttons/profile.png</iconset>\n              </property>\n              <property name=\"iconSize\">\n               <size>\n                <width>30</width>\n                <height>30</height>\n               </size>\n              </property>\n              <property name=\"checkable\">\n               <bool>true</bool>\n              </property>\n              <property name=\"flat\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QtSLiMPushButton\" name=\"recycleButton\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"focusPolicy\">\n               <enum>Qt::FocusPolicy::NoFocus</enum>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;recycle simulation&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"icon\">\n               <iconset resource=\"buttons.qrc\">\n                <normaloff>:/buttons/recycle.png</normaloff>\n                <normalon>:/buttons/recycle_H.png</normalon>:/buttons/recycle.png</iconset>\n              </property>\n              <property name=\"iconSize\">\n               <size>\n                <width>60</width>\n                <height>60</height>\n               </size>\n              </property>\n              <property name=\"flat\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </item>\n          <item alignment=\"Qt::AlignmentFlag::AlignHCenter\">\n           <widget class=\"QSlider\" name=\"playSpeedSlider\">\n            <property name=\"maximumSize\">\n             <size>\n              <width>60</width>\n              <height>16777215</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;simulation playing speed&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"styleSheet\">\n             <string notr=\"true\">QSlider::groove:horizontal {\n    border: 1px solid #888888;\n    border-radius: 1px;\n    height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n    background: #a0a0a0;\n    margin: 2px 0;\n}\nQSlider::groove:horizontal:disabled {\n    border: 1px solid #cccccc;\n    border-radius: 1px;\n    height: 2px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */\n    background: #e0e0e0;\n    margin: 2px 0;\n}\n\nQSlider::handle:horizontal {\n    background: #ffffff;\n    border: 1px solid #909090;\n    width: 8px;\n    margin: -4px 0;\n    border-radius: 4px;\n}\nQSlider::handle:horizontal:disabled {\n    background: #ffffff;\n    border: 1px solid #d0d0d0;\n    width: 8px;\n    margin: -4px 0;\n    border-radius: 4px;\n}\n</string>\n            </property>\n            <property name=\"maximum\">\n             <number>100</number>\n            </property>\n            <property name=\"sliderPosition\">\n             <number>100</number>\n            </property>\n            <property name=\"orientation\">\n             <enum>Qt::Orientation::Horizontal</enum>\n            </property>\n            <property name=\"invertedAppearance\">\n             <bool>false</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"playControlsSpacerFixed\">\n            <property name=\"orientation\">\n             <enum>Qt::Orientation::Vertical</enum>\n            </property>\n            <property name=\"sizeType\">\n             <enum>QSizePolicy::Policy::Fixed</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>20</width>\n              <height>15</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"tickLayout\">\n            <property name=\"sizeConstraint\">\n             <enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>\n            </property>\n            <item>\n             <spacer name=\"horizontalSpacer\">\n              <property name=\"orientation\">\n               <enum>Qt::Orientation::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Policy::Fixed</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>2</width>\n                <height>10</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"tickLabel\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Preferred\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"minimumSize\">\n               <size>\n                <width>80</width>\n                <height>0</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>80</width>\n                <height>16777215</height>\n               </size>\n              </property>\n              <property name=\"text\">\n               <string>Tick:</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QtSLiMGenerationLineEdit\" name=\"tickLineEdit\">\n              <property name=\"maximumSize\">\n               <size>\n                <width>100</width>\n                <height>16777215</height>\n               </size>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;the tick that is about to execute&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"text\">\n               <string>initialize()</string>\n              </property>\n              <property name=\"alignment\">\n               <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"horizontalSpacer_2\">\n              <property name=\"orientation\">\n               <enum>Qt::Orientation::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Policy::Fixed</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>2</width>\n                <height>10</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n           </layout>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"cycleLayout\">\n            <item>\n             <spacer name=\"horizontalSpacer_5\">\n              <property name=\"orientation\">\n               <enum>Qt::Orientation::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Policy::Fixed</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>2</width>\n                <height>10</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"cycleLabel\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>80</width>\n                <height>0</height>\n               </size>\n              </property>\n              <property name=\"maximumSize\">\n               <size>\n                <width>80</width>\n                <height>16777215</height>\n               </size>\n              </property>\n              <property name=\"text\">\n               <string>Cycle:</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QtSLiMGenerationLineEdit\" name=\"cycleLineEdit\">\n              <property name=\"maximumSize\">\n               <size>\n                <width>100</width>\n                <height>16777215</height>\n               </size>\n              </property>\n              <property name=\"toolTip\">\n               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;the cycle that will execute next&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n              </property>\n              <property name=\"text\">\n               <string>initialize()</string>\n              </property>\n              <property name=\"alignment\">\n               <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>\n              </property>\n              <property name=\"readOnly\">\n               <bool>true</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"horizontalSpacer_6\">\n              <property name=\"orientation\">\n               <enum>Qt::Orientation::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Policy::Fixed</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>2</width>\n                <height>10</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n           </layout>\n          </item>\n          <item>\n           <spacer name=\"playControlsSpacerExpanding\">\n            <property name=\"orientation\">\n             <enum>Qt::Orientation::Vertical</enum>\n            </property>\n            <property name=\"sizeType\">\n             <enum>QSizePolicy::Policy::MinimumExpanding</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>20</width>\n              <height>0</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n         </layout>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <layout class=\"QHBoxLayout\" name=\"chromosomeLayout\">\n        <property name=\"spacing\">\n         <number>8</number>\n        </property>\n        <property name=\"topMargin\">\n         <number>5</number>\n        </property>\n        <property name=\"bottomMargin\">\n         <number>5</number>\n        </property>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"chromosomeWidgetLayout\">\n          <property name=\"spacing\">\n           <number>4</number>\n          </property>\n          <item>\n           <widget class=\"QtSLiMChromosomeWidget\" name=\"chromosomeOverview\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>0</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>16777215</width>\n              <height>20</height>\n             </size>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMChromosomeWidget\" name=\"chromosomeZoomed\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Expanding\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>0</width>\n              <height>65</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>16777215</width>\n              <height>65</height>\n             </size>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"chromosomeRightLayout\">\n          <property name=\"spacing\">\n           <number>5</number>\n          </property>\n          <item alignment=\"Qt::AlignmentFlag::AlignRight\">\n           <widget class=\"QtSLiMPushButton\" name=\"toggleDrawerButton\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;open object tables window&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/open_type_drawer.png</normaloff>\n              <normalon>:/buttons/open_type_drawer_H.png</normalon>:/buttons/open_type_drawer.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"chromosomeActionButton\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;chromosome view actions&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/action.png</normaloff>\n              <normalon>:/buttons/action_H.png</normalon>:/buttons/action.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"chromosomeDisplayButton\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;make a new chromosome display window&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/chrom_display.png</normaloff>\n              <normalon>:/buttons/chrom_display_H.png</normalon>:/buttons/chrom_display.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"verticalSpacer_2\">\n            <property name=\"orientation\">\n             <enum>Qt::Orientation::Vertical</enum>\n            </property>\n            <property name=\"sizeType\">\n             <enum>QSizePolicy::Policy::Fixed</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>20</width>\n              <height>14</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n         </layout>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </item>\n    <item>\n     <widget class=\"Line\" name=\"topBottomDividerLine\">\n      <property name=\"orientation\">\n       <enum>Qt::Orientation::Horizontal</enum>\n      </property>\n     </widget>\n    </item>\n    <item>\n     <layout class=\"QHBoxLayout\" name=\"overallBottomLayout\" stretch=\"2,1\">\n      <item>\n       <layout class=\"QVBoxLayout\" name=\"scriptLayout\">\n        <item>\n         <layout class=\"QHBoxLayout\" name=\"scriptHeaderLayout\">\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"clearDebugButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;clear debug points (set a debug point by clicking below)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/clear_debug.png</normaloff>\n              <normalon>:/buttons/clear_debug_H.png</normalon>:/buttons/clear_debug.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"checkScriptButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;check script syntax&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/check.png</normaloff>\n              <normalon>:/buttons/check_H.png</normalon>:/buttons/check.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"prettyprintButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prettyprint script; option-click/alt-click to do a full reformat&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/prettyprint.png</normaloff>\n              <normalon>:/buttons/prettyprint_H.png</normalon>:/buttons/prettyprint.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"scriptHelpButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;scripting help&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/syntax_help.png</normaloff>\n              <normalon>:/buttons/syntax_help_H.png</normalon>:/buttons/syntax_help.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"consoleButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;show Eidos console&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/show_console.png</normaloff>\n              <normalon>:/buttons/show_console_H.png</normalon>:/buttons/show_console.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"browserButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;show Eidos variable browser&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/show_browser.png</normaloff>\n              <normalon>:/buttons/show_browser_H.png</normalon>:/buttons/show_browser.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QLabel\" name=\"scriptHeaderLabel\">\n            <property name=\"text\">\n             <string>Input Script:</string>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"jumpToPopupButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;jump to an event or callback&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/jump_to.png</normaloff>\n              <normalon>:/buttons/jump_to_H.png</normalon>:/buttons/jump_to.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMEllipsisLabel\" name=\"scriptBlockLabel\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Expanding\" vsizetype=\"Preferred\">\n              <horstretch>0</horstretch>\n              <verstretch>0</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"text\">\n             <string>1 early()</string>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <widget class=\"QtSLiMScriptTextEdit\" name=\"scriptTextEdit\"/>\n        </item>\n       </layout>\n      </item>\n      <item>\n       <layout class=\"QVBoxLayout\" name=\"outputLayout\">\n        <item>\n         <layout class=\"QHBoxLayout\" name=\"outputHeaderLayout\">\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"clearOutputButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;clear output log&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/delete.png</normaloff>\n              <normalon>:/buttons/delete_H.png</normalon>:/buttons/delete.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"dumpPopulationButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;dump population state&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/dump_output.png</normaloff>\n              <normalon>:/buttons/dump_output_H.png</normalon>:/buttons/dump_output.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QLabel\" name=\"outputHeaderLabel\">\n            <property name=\"text\">\n             <string>Run Output:</string>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"debugOutputButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;show the debugging output viewer&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"text\">\n             <string/>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/debug.png</normaloff>\n              <normalon>:/buttons/debug_H.png</normalon>:/buttons/debug.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"checkable\">\n             <bool>true</bool>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"graphPopupButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;show a graph&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/graph_submenu.png</normaloff>\n              <normalon>:/buttons/graph_submenu_H.png</normalon>:/buttons/graph_submenu.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"horizontalSpacer_3\">\n            <property name=\"orientation\">\n             <enum>Qt::Orientation::Horizontal</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>40</width>\n              <height>10</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <widget class=\"QtSLiMPushButton\" name=\"changeDirectoryButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"maximumSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"focusPolicy\">\n             <enum>Qt::FocusPolicy::NoFocus</enum>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;change working directory&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"icon\">\n             <iconset resource=\"buttons.qrc\">\n              <normaloff>:/buttons/change_folder.png</normaloff>\n              <normalon>:/buttons/change_folder_H.png</normalon>:/buttons/change_folder.png</iconset>\n            </property>\n            <property name=\"iconSize\">\n             <size>\n              <width>20</width>\n              <height>20</height>\n             </size>\n            </property>\n            <property name=\"flat\">\n             <bool>true</bool>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <widget class=\"QtSLiMTextEdit\" name=\"outputTextEdit\">\n          <property name=\"readOnly\">\n           <bool>true</bool>\n          </property>\n         </widget>\n        </item>\n       </layout>\n      </item>\n     </layout>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menuBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>914</width>\n     <height>37</height>\n    </rect>\n   </property>\n   <widget class=\"QMenu\" name=\"menuFile\">\n    <property name=\"title\">\n     <string>File</string>\n    </property>\n    <widget class=\"QMenu\" name=\"menuOpenRecipe\">\n     <property name=\"title\">\n      <string>Open Recipe</string>\n     </property>\n     <addaction name=\"actionFindRecipe\"/>\n     <addaction name=\"separator\"/>\n    </widget>\n    <addaction name=\"actionAboutQtSLiM\"/>\n    <addaction name=\"actionPreferences\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionNew\"/>\n    <addaction name=\"actionNew_nonWF\"/>\n    <addaction name=\"actionOpen\"/>\n    <addaction name=\"actionOpenRecent\"/>\n    <addaction name=\"menuOpenRecipe\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionClose\"/>\n    <addaction name=\"actionSave\"/>\n    <addaction name=\"actionSaveAs\"/>\n    <addaction name=\"actionRevertToSaved\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionQuitQtSLiM\"/>\n   </widget>\n   <widget class=\"QMenu\" name=\"menuEdit\">\n    <property name=\"title\">\n     <string>Edit</string>\n    </property>\n    <widget class=\"QMenu\" name=\"menuFind\">\n     <property name=\"title\">\n      <string>Find</string>\n     </property>\n     <addaction name=\"actionFindShow\"/>\n     <addaction name=\"actionFindNext\"/>\n     <addaction name=\"actionFindPrevious\"/>\n     <addaction name=\"actionReplaceAndFind\"/>\n     <addaction name=\"actionUseSelectionForFind\"/>\n     <addaction name=\"actionUseSelectionForReplace\"/>\n     <addaction name=\"actionJumpToSelection\"/>\n     <addaction name=\"actionJumpToLine\"/>\n    </widget>\n    <addaction name=\"actionUndo\"/>\n    <addaction name=\"actionRedo\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionCut\"/>\n    <addaction name=\"actionCopy\"/>\n    <addaction name=\"actionCopyAsHTML\"/>\n    <addaction name=\"actionPaste\"/>\n    <addaction name=\"actionDuplicate\"/>\n    <addaction name=\"actionDelete\"/>\n    <addaction name=\"actionSelectAll\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"menuFind\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionShiftLeft\"/>\n    <addaction name=\"actionShiftRight\"/>\n    <addaction name=\"actionCommentUncomment\"/>\n   </widget>\n   <widget class=\"QMenu\" name=\"menuSimulation\">\n    <property name=\"title\">\n     <string>Simulation</string>\n    </property>\n    <widget class=\"QMenu\" name=\"menuGraph\">\n     <property name=\"title\">\n      <string>Show Graph</string>\n     </property>\n     <addaction name=\"actionGraph_1D_Population_SFS\"/>\n     <addaction name=\"actionGraph_1D_Sample_SFS\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionGraph_2D_Population_SFS\"/>\n     <addaction name=\"actionGraph_2D_Sample_SFS\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionGraph_Mutation_Frequency_Trajectories\"/>\n     <addaction name=\"actionGraph_Mutation_Loss_Time_Histogram\"/>\n     <addaction name=\"actionGraph_Mutation_Fixation_Time_Histogram\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionGraph_Population_Fitness_Distribution\"/>\n     <addaction name=\"actionGraph_Subpopulation_Fitness_Distributions\"/>\n     <addaction name=\"actionGraph_Fitness_Time\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionGraph_Age_Distribution\"/>\n     <addaction name=\"actionGraph_Lifetime_Reproduce_Output\"/>\n     <addaction name=\"actionGraph_Population_Size_Time\"/>\n     <addaction name=\"actionGraph_Population_Visualization\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionGraph_Multispecies_Population_Size_Time\"/>\n     <addaction name=\"separator\"/>\n     <addaction name=\"actionCreate_Haplotype_Plot_All\"/>\n     <addaction name=\"actionCreate_Haplotype_Plot_Selected\"/>\n    </widget>\n    <addaction name=\"actionStep\"/>\n    <addaction name=\"actionPlay\"/>\n    <addaction name=\"actionProfile\"/>\n    <addaction name=\"actionRecycle\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionChangeWorkingDirectory\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"menuGraph\"/>\n    <addaction name=\"actionDumpPopulationState\"/>\n   </widget>\n   <widget class=\"QMenu\" name=\"menuScript\">\n    <property name=\"title\">\n     <string>Script</string>\n    </property>\n    <addaction name=\"actionCheckScript\"/>\n    <addaction name=\"actionPrettyprintScript\"/>\n    <addaction name=\"actionReformatScript\"/>\n    <addaction name=\"actionShowScriptHelp\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionBiggerFont\"/>\n    <addaction name=\"actionSmallerFont\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionShowVariableBrowser\"/>\n    <addaction name=\"actionShowEidosConsole\"/>\n    <addaction name=\"actionShowDebuggingOutput\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionClearOutput\"/>\n    <addaction name=\"actionClearDebug\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionExecuteSelection\"/>\n    <addaction name=\"actionExecuteAll\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionFocusOnScript\"/>\n    <addaction name=\"actionFocusOnConsole\"/>\n   </widget>\n   <widget class=\"QMenu\" name=\"menuHelp\">\n    <property name=\"title\">\n     <string>Help</string>\n    </property>\n    <addaction name=\"actionShowCycle_WF\"/>\n    <addaction name=\"actionShowCycle_nonWF\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionShowCycle_WF_MS\"/>\n    <addaction name=\"actionShowCycle_nonWF_MS\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionShowColorChart\"/>\n    <addaction name=\"actionShowPlotSymbols\"/>\n    <addaction name=\"actionShowColorScales\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionQtSLiMHelp\"/>\n    <addaction name=\"actionSLiMWorkshops\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionSendFeedback\"/>\n    <addaction name=\"actionMailingList_slimannounce\"/>\n    <addaction name=\"actionMailingList_slimdiscuss\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionSLiMHomePage\"/>\n    <addaction name=\"actionSLiMExtras\"/>\n    <addaction name=\"separator\"/>\n    <addaction name=\"actionAboutMesserLab\"/>\n    <addaction name=\"actionAboutBenHaller\"/>\n    <addaction name=\"actionAboutStickSoftware\"/>\n   </widget>\n   <widget class=\"QMenu\" name=\"menuWindow\">\n    <property name=\"title\">\n     <string>Window</string>\n    </property>\n    <addaction name=\"actionMinimize\"/>\n    <addaction name=\"actionZoom\"/>\n    <addaction name=\"separator\"/>\n   </widget>\n   <addaction name=\"menuFile\"/>\n   <addaction name=\"menuEdit\"/>\n   <addaction name=\"menuSimulation\"/>\n   <addaction name=\"menuScript\"/>\n   <addaction name=\"menuWindow\"/>\n   <addaction name=\"menuHelp\"/>\n  </widget>\n  <widget class=\"QtSLiMStatusBar\" name=\"statusBar\"/>\n  <action name=\"actionNew\">\n   <property name=\"text\">\n    <string>New</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+N</string>\n   </property>\n  </action>\n  <action name=\"actionNew_nonWF\">\n   <property name=\"text\">\n    <string>New (nonWF)</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+N</string>\n   </property>\n  </action>\n  <action name=\"actionOpen\">\n   <property name=\"text\">\n    <string>Open...</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+O</string>\n   </property>\n  </action>\n  <action name=\"actionClose\">\n   <property name=\"text\">\n    <string>Close</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+W</string>\n   </property>\n  </action>\n  <action name=\"actionSave\">\n   <property name=\"text\">\n    <string>Save</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+S</string>\n   </property>\n  </action>\n  <action name=\"actionSaveAs\">\n   <property name=\"text\">\n    <string>Save As...</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+S</string>\n   </property>\n  </action>\n  <action name=\"actionCut\">\n   <property name=\"text\">\n    <string>Cut</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+X</string>\n   </property>\n  </action>\n  <action name=\"actionCopy\">\n   <property name=\"text\">\n    <string>Copy</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+C</string>\n   </property>\n  </action>\n  <action name=\"actionPaste\">\n   <property name=\"text\">\n    <string>Paste</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+V</string>\n   </property>\n  </action>\n  <action name=\"actionUndo\">\n   <property name=\"text\">\n    <string>Undo</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Z</string>\n   </property>\n  </action>\n  <action name=\"actionRedo\">\n   <property name=\"text\">\n    <string>Redo</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+Z</string>\n   </property>\n  </action>\n  <action name=\"actionDelete\">\n   <property name=\"text\">\n    <string>Delete</string>\n   </property>\n  </action>\n  <action name=\"actionSelectAll\">\n   <property name=\"text\">\n    <string>Select All</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+A</string>\n   </property>\n  </action>\n  <action name=\"actionShiftLeft\">\n   <property name=\"text\">\n    <string>Shift Left</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+[</string>\n   </property>\n  </action>\n  <action name=\"actionShiftRight\">\n   <property name=\"text\">\n    <string>Shift Right</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+]</string>\n   </property>\n  </action>\n  <action name=\"actionCommentUncomment\">\n   <property name=\"text\">\n    <string>Comment / Uncomment</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+/</string>\n   </property>\n  </action>\n  <action name=\"actionStep\">\n   <property name=\"text\">\n    <string>Step</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+P</string>\n   </property>\n  </action>\n  <action name=\"actionPlay\">\n   <property name=\"text\">\n    <string>Play</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+P</string>\n   </property>\n  </action>\n  <action name=\"actionProfile\">\n   <property name=\"text\">\n    <string>Profile</string>\n   </property>\n  </action>\n  <action name=\"actionRecycle\">\n   <property name=\"text\">\n    <string>Recycle</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+R</string>\n   </property>\n  </action>\n  <action name=\"actionChangeWorkingDirectory\">\n   <property name=\"text\">\n    <string>Change Working Directory...</string>\n   </property>\n  </action>\n  <action name=\"actionDumpPopulationState\">\n   <property name=\"text\">\n    <string>Dump Population State</string>\n   </property>\n  </action>\n  <action name=\"actionCheckScript\">\n   <property name=\"text\">\n    <string>Check Script</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+=</string>\n   </property>\n  </action>\n  <action name=\"actionPrettyprintScript\">\n   <property name=\"text\">\n    <string>Prettyprint Script</string>\n   </property>\n  </action>\n  <action name=\"actionShowScriptHelp\">\n   <property name=\"text\">\n    <string>Show Script Help</string>\n   </property>\n  </action>\n  <action name=\"actionShowVariableBrowser\">\n   <property name=\"text\">\n    <string>Show Variable Browser</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+B</string>\n   </property>\n  </action>\n  <action name=\"actionShowEidosConsole\">\n   <property name=\"text\">\n    <string>Show Eidos Console</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+E</string>\n   </property>\n  </action>\n  <action name=\"actionClearOutput\">\n   <property name=\"text\">\n    <string>Clear Output</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+K</string>\n   </property>\n  </action>\n  <action name=\"actionExecuteSelection\">\n   <property name=\"text\">\n    <string>Execute Selection</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Return</string>\n   </property>\n  </action>\n  <action name=\"actionExecuteAll\">\n   <property name=\"text\">\n    <string>Execute All</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+Return</string>\n   </property>\n  </action>\n  <action name=\"actionQtSLiMHelp\">\n   <property name=\"text\">\n    <string>SLiMgui Help</string>\n   </property>\n  </action>\n  <action name=\"actionSendFeedback\">\n   <property name=\"text\">\n    <string>Send Feedback on SLiM</string>\n   </property>\n  </action>\n  <action name=\"actionMailingList_slimannounce\">\n   <property name=\"text\">\n    <string>Mailing List: slim-announce</string>\n   </property>\n  </action>\n  <action name=\"actionMailingList_slimdiscuss\">\n   <property name=\"text\">\n    <string>Mailing List: slim-discuss</string>\n   </property>\n  </action>\n  <action name=\"actionSLiMHomePage\">\n   <property name=\"text\">\n    <string>SLiM Home Page</string>\n   </property>\n  </action>\n  <action name=\"actionSLiMExtras\">\n   <property name=\"text\">\n    <string>SLiM-Extras on GitHub</string>\n   </property>\n  </action>\n  <action name=\"actionAboutMesserLab\">\n   <property name=\"text\">\n    <string>About the Messer Lab</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::NoRole</enum>\n   </property>\n  </action>\n  <action name=\"actionAboutBenHaller\">\n   <property name=\"text\">\n    <string>About Ben Haller</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::NoRole</enum>\n   </property>\n  </action>\n  <action name=\"actionAboutStickSoftware\">\n   <property name=\"text\">\n    <string>About Stick Software</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::NoRole</enum>\n   </property>\n  </action>\n  <action name=\"actionAboutQtSLiM\">\n   <property name=\"text\">\n    <string>About SLiMgui</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::AboutRole</enum>\n   </property>\n  </action>\n  <action name=\"actionQuitQtSLiM\">\n   <property name=\"text\">\n    <string>Quit SLiMgui</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Q</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::QuitRole</enum>\n   </property>\n  </action>\n  <action name=\"actionFindRecipe\">\n   <property name=\"text\">\n    <string>Find Recipe...</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+O</string>\n   </property>\n  </action>\n  <action name=\"actionPreferences\">\n   <property name=\"text\">\n    <string>Preferences...</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+,</string>\n   </property>\n   <property name=\"menuRole\">\n    <enum>QAction::MenuRole::PreferencesRole</enum>\n   </property>\n  </action>\n  <action name=\"actionFindShow\">\n   <property name=\"text\">\n    <string>Find...</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+F</string>\n   </property>\n  </action>\n  <action name=\"actionReplaceAndFind\">\n   <property name=\"text\">\n    <string>Replace &amp;&amp; Find</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Alt+G</string>\n   </property>\n  </action>\n  <action name=\"actionFindNext\">\n   <property name=\"text\">\n    <string>Find Next</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+G</string>\n   </property>\n  </action>\n  <action name=\"actionFindPrevious\">\n   <property name=\"text\">\n    <string>Find Previous</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+G</string>\n   </property>\n  </action>\n  <action name=\"actionUseSelectionForFind\">\n   <property name=\"text\">\n    <string>Use Selection for Find</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+E</string>\n   </property>\n  </action>\n  <action name=\"actionJumpToSelection\">\n   <property name=\"text\">\n    <string>Jump to Selection</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+J</string>\n   </property>\n  </action>\n  <action name=\"actionRevertToSaved\">\n   <property name=\"text\">\n    <string>Revert to Saved</string>\n   </property>\n  </action>\n  <action name=\"actionOpenRecent\">\n   <property name=\"text\">\n    <string>Open Recent</string>\n   </property>\n  </action>\n  <action name=\"actionSLiMWorkshops\">\n   <property name=\"text\">\n    <string>SLiM Workshops</string>\n   </property>\n  </action>\n  <action name=\"actionUseSelectionForReplace\">\n   <property name=\"text\">\n    <string>Use Selection for Replace</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Alt+E</string>\n   </property>\n  </action>\n  <action name=\"actionJumpToLine\">\n   <property name=\"text\">\n    <string>Jump to Line</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+L</string>\n   </property>\n  </action>\n  <action name=\"actionMinimize\">\n   <property name=\"text\">\n    <string>Minimize</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+M</string>\n   </property>\n  </action>\n  <action name=\"actionZoom\">\n   <property name=\"text\">\n    <string>Zoom</string>\n   </property>\n  </action>\n  <action name=\"actionReformatScript\">\n   <property name=\"text\">\n    <string>Reformat Script</string>\n   </property>\n  </action>\n  <action name=\"actionShowDebuggingOutput\">\n   <property name=\"text\">\n    <string>Show Debugging Output</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Shift+D</string>\n   </property>\n  </action>\n  <action name=\"actionClearDebug\">\n   <property name=\"text\">\n    <string>Clear Debug Points</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Alt+K</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_1D_Population_SFS\">\n   <property name=\"text\">\n    <string>Graph 1D Population SFS</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_1D_Sample_SFS\">\n   <property name=\"text\">\n    <string>Graph 1D Sample SFS</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_2D_Population_SFS\">\n   <property name=\"text\">\n    <string>Graph 2D Population SFS</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_2D_Sample_SFS\">\n   <property name=\"text\">\n    <string>Graph 2D Sample SFS</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Mutation_Frequency_Trajectories\">\n   <property name=\"text\">\n    <string>Graph Mutation Frequency Trajectories</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Mutation_Loss_Time_Histogram\">\n   <property name=\"text\">\n    <string>Graph Mutation Loss Time Histogram</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Mutation_Fixation_Time_Histogram\">\n   <property name=\"text\">\n    <string>Graph Mutation Fixation Time Histogram</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Population_Fitness_Distribution\">\n   <property name=\"text\">\n    <string>Graph Population Fitness Distribution</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Subpopulation_Fitness_Distributions\">\n   <property name=\"text\">\n    <string>Graph Subpopulation Fitness Distributions</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Fitness_Time\">\n   <property name=\"text\">\n    <string>Graph Fitness ~ Time</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Age_Distribution\">\n   <property name=\"text\">\n    <string>Graph Age Distribution</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Lifetime_Reproduce_Output\">\n   <property name=\"text\">\n    <string>Graph Lifetime Reproduce Output</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Population_Size_Time\">\n   <property name=\"text\">\n    <string>Graph Population Size ~ Time</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Population_Visualization\">\n   <property name=\"text\">\n    <string>Graph Population Visualization</string>\n   </property>\n  </action>\n  <action name=\"actionCreate_Haplotype_Plot_All\">\n   <property name=\"text\">\n    <string>Create Haplotype Plot (all chromosomes)</string>\n   </property>\n  </action>\n  <action name=\"actionShowCycle_WF\">\n   <property name=\"text\">\n    <string>Show WF Tick Cycle</string>\n   </property>\n  </action>\n  <action name=\"actionShowCycle_nonWF\">\n   <property name=\"text\">\n    <string>Show nonWF Tick Cycle</string>\n   </property>\n  </action>\n  <action name=\"actionGraph_Multispecies_Population_Size_Time\">\n   <property name=\"text\">\n    <string>Multispecies Population Size ~ Time</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Graph Multispecies Population Size ~ Time</string>\n   </property>\n  </action>\n  <action name=\"actionFocusOnScript\">\n   <property name=\"text\">\n    <string>Focus on Script</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+1</string>\n   </property>\n  </action>\n  <action name=\"actionFocusOnConsole\">\n   <property name=\"text\">\n    <string>Focus on Console</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+2</string>\n   </property>\n  </action>\n  <action name=\"actionBiggerFont\">\n   <property name=\"text\">\n    <string>Bigger Font</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl++</string>\n   </property>\n  </action>\n  <action name=\"actionSmallerFont\">\n   <property name=\"text\">\n    <string>Smaller Font</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+-</string>\n   </property>\n  </action>\n  <action name=\"actionShowCycle_WF_MS\">\n   <property name=\"text\">\n    <string>Show WF Tick Cycle (Multispecies)</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Show WF Tick Cycle (Multispecies)</string>\n   </property>\n  </action>\n  <action name=\"actionShowCycle_nonWF_MS\">\n   <property name=\"text\">\n    <string>Show nonWF Tick Cycle (Multispecies)</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Show nonWF Tick Cycle (Multispecies)</string>\n   </property>\n  </action>\n  <action name=\"actionCopyAsHTML\">\n   <property name=\"text\">\n    <string>Copy as HTML</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Copy as HTML</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+Alt+C</string>\n   </property>\n  </action>\n  <action name=\"actionCreate_Haplotype_Plot_Selected\">\n   <property name=\"text\">\n    <string>Create Haplotype Plot (selected chromosome)</string>\n   </property>\n  </action>\n  <action name=\"actionShowColorChart\">\n   <property name=\"text\">\n    <string>Show Color Chart</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Show a chart of the named colors provided by Eidos</string>\n   </property>\n  </action>\n  <action name=\"actionShowPlotSymbols\">\n   <property name=\"text\">\n    <string>Show Plot Symbols</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Show a chart depicting the plot symbols used by Plot's points() method</string>\n   </property>\n  </action>\n  <action name=\"actionDuplicate\">\n   <property name=\"text\">\n    <string>Duplicate</string>\n   </property>\n   <property name=\"shortcut\">\n    <string>Ctrl+D</string>\n   </property>\n  </action>\n  <action name=\"actionShowColorScales\">\n   <property name=\"text\">\n    <string>Show SLiMgui Color Scales</string>\n   </property>\n   <property name=\"toolTip\">\n    <string>Show a chart depicting the color scales used by SLiMgui for mutation effects and individual fitness</string>\n   </property>\n  </action>\n </widget>\n <layoutdefault spacing=\"6\" margin=\"11\"/>\n <customwidgets>\n  <customwidget>\n   <class>QtSLiMPushButton</class>\n   <extends>QPushButton</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMTextEdit</class>\n   <extends>QPlainTextEdit</extends>\n   <header>QtSLiMScriptTextEdit.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMChromosomeWidget</class>\n   <extends>QOpenGLWidget</extends>\n   <header>QtSLiMChromosomeWidget.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMIndividualsWidget</class>\n   <extends>QOpenGLWidget</extends>\n   <header>QtSLiMIndividualsWidget.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMGenerationLineEdit</class>\n   <extends>QLineEdit</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMStatusBar</class>\n   <extends>QStatusBar</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMScriptTextEdit</class>\n   <extends>QPlainTextEdit</extends>\n   <header>QtSLiMScriptTextEdit.h</header>\n  </customwidget>\n  <customwidget>\n   <class>QTabBar</class>\n   <extends>QWidget</extends>\n   <header>QTabBar.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>QtSLiMEllipsisLabel</class>\n   <extends>QLabel</extends>\n   <header>QtSLiMExtras.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"buttons.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtSLiM/QtSLiMWindow_glue.cpp",
    "content": "//\n//  QtSLiMWindow_glue.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiMWindow.h\"\n#include \"ui_QtSLiMWindow.h\"\n\n#include <QCoreApplication>\n#include <QKeyEvent>\n#include <QDebug>\n\n#include \"QtSLiMScriptTextEdit.h\"\n#include \"QtSLiMAppDelegate.h\"\n\n\nvoid QtSLiMWindow::glueUI(void)\n{\n    // connect all QtSLiMWindow slots\n    //connect(ui->playOneStepButton, &QPushButton::clicked, this, &QtSLiMWindow::playOneStepClicked);   // done in playOneStepPressed() now!\n    connect(ui->playButton, &QPushButton::clicked, this, [this]() { playOrProfile(tickPlayOn_ ? PlayType::kTickPlay : PlayType::kNormalPlay); });\n    connect(ui->profileButton, &QPushButton::clicked, this, [this]() { playOrProfile(PlayType::kProfilePlay); });\n    connect(ui->tickLineEdit, &QLineEdit::returnPressed, this, &QtSLiMWindow::tickChanged);\n    //connect(ui->cycleLineEdit, &QLineEdit::returnPressed, this, &QtSLiMWindow::cycleChanged);   // not editable at the moment\n    connect(ui->recycleButton, &QPushButton::clicked, this, &QtSLiMWindow::recycleClicked);\n    connect(ui->playSpeedSlider, &QSlider::valueChanged, this, &QtSLiMWindow::playSpeedChanged);\n\n    connect(ui->toggleDrawerButton, &QPushButton::clicked, this, &QtSLiMWindow::showDrawerClicked);\n    //connect(ui->chromosomeActionButton, &QPushButton::clicked, this, &QtSLiMWindow::chromosomeActionClicked); // this button runs when it is pressed\n    //connect(ui->chromosomeDisplayButton, &QPushButton::clicked, this, &QtSLiMWindow::chromosomeDisplayClicked); // this button runs when it is pressed\n\n    connect(ui->clearDebugButton, &QPushButton::clicked, ui->scriptTextEdit, &QtSLiMScriptTextEdit::clearDebugPoints);\n    connect(ui->checkScriptButton, &QPushButton::clicked, ui->scriptTextEdit, &QtSLiMTextEdit::checkScript);\n    connect(ui->prettyprintButton, &QPushButton::clicked, ui->scriptTextEdit, &QtSLiMTextEdit::prettyprintClicked);\n    connect(ui->scriptHelpButton, &QPushButton::clicked, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n    connect(ui->consoleButton, &QPushButton::clicked, this, &QtSLiMWindow::showConsoleClicked);\n    connect(ui->browserButton, &QPushButton::clicked, this, &QtSLiMWindow::showBrowserClicked);\n    //connect(ui->jumpToPopupButton, &QPushButton::clicked, this, &QtSLiMWindow::jumpToPopupButtonClicked); // this button runs when it is pressed\n\n    connect(ui->clearOutputButton, &QPushButton::clicked, this, &QtSLiMWindow::clearOutputClicked);\n    connect(ui->dumpPopulationButton, &QPushButton::clicked, this, &QtSLiMWindow::dumpPopulationClicked);\n    connect(ui->debugOutputButton, &QPushButton::clicked, this, &QtSLiMWindow::debugOutputClicked);\n    //connect(ui->graphPopupButton, &QPushButton::clicked, this, &QtSLiMWindow::graphPopupButtonClicked); // this button runs when it is pressed\n    connect(ui->changeDirectoryButton, &QPushButton::clicked, this, &QtSLiMWindow::changeDirectoryClicked);\n\n    // set up QtSLiMPushButton \"base names\" for all buttons\n    ui->playOneStepButton->qtslimSetBaseName(\"play_step\");\n    ui->playButton->qtslimSetBaseName(\"play\");\n    ui->profileButton->qtslimSetBaseName(\"profile\");\n    ui->recycleButton->qtslimSetBaseName(\"recycle\");\n    ui->toggleDrawerButton->qtslimSetBaseName(\"open_type_drawer\");\n    ui->chromosomeActionButton->qtslimSetBaseName(\"action\");\n    ui->chromosomeDisplayButton->qtslimSetBaseName(\"chrom_display\");\n    ui->clearDebugButton->qtslimSetBaseName(\"clear_debug\");\n    ui->checkScriptButton->qtslimSetBaseName(\"check\");\n    ui->prettyprintButton->qtslimSetBaseName(\"prettyprint\");\n    ui->scriptHelpButton->qtslimSetBaseName(\"syntax_help\");\n    ui->consoleButton->qtslimSetBaseName(\"show_console\");\n    ui->browserButton->qtslimSetBaseName(\"show_browser\");\n    ui->jumpToPopupButton->qtslimSetBaseName(\"jump_to\");\n    ui->clearOutputButton->qtslimSetBaseName(\"delete\");\n    ui->dumpPopulationButton->qtslimSetBaseName(\"dump_output\");\n    ui->debugOutputButton->qtslimSetBaseName(\"debug\");\n    ui->graphPopupButton->qtslimSetBaseName(\"graph_submenu\");\n    ui->changeDirectoryButton->qtslimSetBaseName(\"change_folder\");\n    \n    // set up the \"temporary icon\" on the debugging button, to support pulsing\n    static QIcon *debug_RED = nullptr;\n    if (!debug_RED)\n        debug_RED = new QIcon(\":buttons/debug_RED.png\");\n    ui->debugOutputButton->setTemporaryIcon(*debug_RED);\n    \n    // set up all icon-based QPushButtons to change their icon as they track\n    connect(ui->playOneStepButton, &QPushButton::pressed, this, &QtSLiMWindow::playOneStepPressed);\n    connect(ui->playOneStepButton, &QPushButton::released, this, &QtSLiMWindow::playOneStepReleased);\n    connect(ui->playButton, &QPushButton::pressed, this, &QtSLiMWindow::playPressed);\n    connect(ui->playButton, &QPushButton::released, this, &QtSLiMWindow::playReleased);\n    connect(ui->profileButton, &QPushButton::pressed, this, &QtSLiMWindow::profilePressed);\n    connect(ui->profileButton, &QPushButton::released, this, &QtSLiMWindow::profileReleased);\n    connect(ui->recycleButton, &QPushButton::pressed, this, &QtSLiMWindow::recyclePressed);\n    connect(ui->recycleButton, &QPushButton::released, this, &QtSLiMWindow::recycleReleased);\n    connect(ui->toggleDrawerButton, &QPushButton::pressed, this, &QtSLiMWindow::toggleDrawerPressed);\n    connect(ui->toggleDrawerButton, &QPushButton::released, this, &QtSLiMWindow::toggleDrawerReleased);\n    connect(ui->chromosomeActionButton, &QPushButton::pressed, this, &QtSLiMWindow::chromosomeActionPressed);\n    connect(ui->chromosomeActionButton, &QPushButton::released, this, &QtSLiMWindow::chromosomeActionReleased);\n    connect(ui->chromosomeDisplayButton, &QPushButton::pressed, this, &QtSLiMWindow::chromosomeDisplayPressed);\n    connect(ui->chromosomeDisplayButton, &QPushButton::released, this, &QtSLiMWindow::chromosomeDisplayReleased);\n    connect(ui->clearDebugButton, &QPushButton::pressed, this, &QtSLiMWindow::clearDebugPressed);\n    connect(ui->clearDebugButton, &QPushButton::released, this, &QtSLiMWindow::clearDebugReleased);\n    connect(ui->checkScriptButton, &QPushButton::pressed, this, &QtSLiMWindow::checkScriptPressed);\n    connect(ui->checkScriptButton, &QPushButton::released, this, &QtSLiMWindow::checkScriptReleased);\n    connect(ui->prettyprintButton, &QPushButton::pressed, this, &QtSLiMWindow::prettyprintPressed);\n    connect(ui->prettyprintButton, &QPushButton::released, this, &QtSLiMWindow::prettyprintReleased);\n    connect(ui->scriptHelpButton, &QPushButton::pressed, this, &QtSLiMWindow::scriptHelpPressed);\n    connect(ui->scriptHelpButton, &QPushButton::released, this, &QtSLiMWindow::scriptHelpReleased);\n    connect(ui->consoleButton, &QPushButton::pressed, this, &QtSLiMWindow::showConsolePressed);\n    connect(ui->consoleButton, &QPushButton::released, this, &QtSLiMWindow::showConsoleReleased);\n    connect(ui->browserButton, &QPushButton::pressed, this, &QtSLiMWindow::showBrowserPressed);\n    connect(ui->browserButton, &QPushButton::released, this, &QtSLiMWindow::showBrowserReleased);\n    connect(ui->jumpToPopupButton, &QPushButton::pressed, this, &QtSLiMWindow::jumpToPopupButtonPressed);\n    connect(ui->jumpToPopupButton, &QPushButton::released, this, &QtSLiMWindow::jumpToPopupButtonReleased);\n    connect(ui->scriptBlockLabel, &QtSLiMEllipsisLabel::pressed, this, &QtSLiMWindow::jumpToPopupButtonPressed);\n    //connect(ui->scriptBlockLabel, &QtSLiMEllipsisLabel::released, this, &QtSLiMWindow::jumpToPopupButtonReleased);    // seems to be unnecessary\n    connect(ui->clearOutputButton, &QPushButton::pressed, this, &QtSLiMWindow::clearOutputPressed);\n    connect(ui->clearOutputButton, &QPushButton::released, this, &QtSLiMWindow::clearOutputReleased);\n    connect(ui->dumpPopulationButton, &QPushButton::pressed, this, &QtSLiMWindow::dumpPopulationPressed);\n    connect(ui->dumpPopulationButton, &QPushButton::released, this, &QtSLiMWindow::dumpPopulationReleased);\n    connect(ui->debugOutputButton, &QPushButton::pressed, this, &QtSLiMWindow::debugOutputPressed);\n    connect(ui->debugOutputButton, &QPushButton::released, this, &QtSLiMWindow::debugOutputReleased);\n    connect(ui->graphPopupButton, &QPushButton::pressed, this, &QtSLiMWindow::graphPopupButtonPressed);\n    connect(ui->graphPopupButton, &QPushButton::released, this, &QtSLiMWindow::graphPopupButtonReleased);\n    connect(ui->changeDirectoryButton, &QPushButton::pressed, this, &QtSLiMWindow::changeDirectoryPressed);\n    connect(ui->changeDirectoryButton, &QPushButton::released, this, &QtSLiMWindow::changeDirectoryReleased);\n    \n    // this action seems to need to be added to the main window in order to function reliably;\n    // I'm not sure why, maybe it is because it is connected to an object that is not a widget?\n    // adding it as an action here seems to have no visible effect except that the shortcut now works\n    addAction(ui->actionFindRecipe);\n    \n    // menu items that are not visible, for hidden shortcuts\n    QAction *actionNewWF_commentless = new QAction(\"New WF (Commentless)\", this);\n    actionNewWF_commentless->setShortcut(Qt::ControlModifier | Qt::AltModifier | Qt::Key_N);\n    connect(actionNewWF_commentless, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newWF_commentless);\n    addAction(actionNewWF_commentless);\n    \n    QAction *actionNewNonWF_commentless = new QAction(\"New nonWF (Commentless)\", this);\n    actionNewNonWF_commentless->setShortcut(Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier | Qt::Key_N);\n    connect(actionNewNonWF_commentless, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newNonWF_commentless);\n    addAction(actionNewNonWF_commentless);\n    \n    // connect all menu items with existing slots\n    connect(ui->actionPreferences, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_preferences);\n    connect(ui->actionAboutQtSLiM, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_about);\n    connect(ui->actionShowCycle_WF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_WF);\n    connect(ui->actionShowCycle_nonWF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_nonWF);\n    connect(ui->actionShowCycle_WF_MS, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_WF_MS);\n    connect(ui->actionShowCycle_nonWF_MS, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showCycle_nonWF_MS);\n    connect(ui->actionShowColorChart, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showColorChart);\n    connect(ui->actionShowPlotSymbols, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showPlotSymbols);\n    connect(ui->actionShowColorScales, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showColorScales);\n    connect(ui->actionQtSLiMHelp, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n    connect(ui->actionQuitQtSLiM, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_quit);\n    connect(ui->actionNew, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newWF);\n    connect(ui->actionNew_nonWF, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_newNonWF);\n    connect(ui->actionOpen, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_open);\n    connect(ui->actionClose, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_close);\n    connect(ui->actionSave, &QAction::triggered, this, &QtSLiMWindow::save);\n    connect(ui->actionSaveAs, &QAction::triggered, this, &QtSLiMWindow::saveAs);\n    connect(ui->actionRevertToSaved, &QAction::triggered, this, &QtSLiMWindow::revert);\n    connect(ui->actionStep, &QAction::triggered, this, &QtSLiMWindow::playOneStepClicked);\n    connect(ui->actionPlay, &QAction::triggered, this, [this]() { playOrProfile(tickPlayOn_ ? PlayType::kTickPlay : PlayType::kNormalPlay); });\n    connect(ui->actionProfile, &QAction::triggered, this, [this]() { playOrProfile(PlayType::kProfilePlay); });\n    connect(ui->actionRecycle, &QAction::triggered, this, &QtSLiMWindow::recycleClicked);\n    connect(ui->actionChangeWorkingDirectory, &QAction::triggered, this, &QtSLiMWindow::changeDirectoryClicked);\n    connect(ui->actionDumpPopulationState, &QAction::triggered, this, &QtSLiMWindow::dumpPopulationClicked);\n    connect(ui->actionMinimize, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_minimize);\n    connect(ui->actionZoom, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_zoom);\n    \n    connect(ui->actionGraph_1D_Population_SFS, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_1D_Sample_SFS, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_2D_Population_SFS, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_2D_Sample_SFS, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Mutation_Frequency_Trajectories, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Mutation_Loss_Time_Histogram, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Mutation_Fixation_Time_Histogram, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Population_Fitness_Distribution, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Subpopulation_Fitness_Distributions, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Fitness_Time, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Age_Distribution, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Lifetime_Reproduce_Output, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n\tconnect(ui->actionGraph_Population_Size_Time, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n    connect(ui->actionGraph_Population_Visualization, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n    connect(ui->actionGraph_Multispecies_Population_Size_Time, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n    connect(ui->actionCreate_Haplotype_Plot_All, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n    connect(ui->actionCreate_Haplotype_Plot_Selected, &QAction::triggered, this, &QtSLiMWindow::displayGraphClicked);\n    \n    // connect menu items that can go to either a QtSLiMWindow or a QtSLiMEidosConsole\n    connect(ui->actionFocusOnScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_focusOnScript);\n    connect(ui->actionFocusOnConsole, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_focusOnConsole);\n    connect(ui->actionCheckScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_checkScript);\n    connect(ui->actionPrettyprintScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_prettyprintScript);\n    connect(ui->actionReformatScript, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_reformatScript);\n    connect(ui->actionShowScriptHelp, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_help);\n    connect(ui->actionBiggerFont, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_biggerFont);\n    connect(ui->actionSmallerFont, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_smallerFont);\n    connect(ui->actionShowEidosConsole, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showEidosConsole);\n    connect(ui->actionShowVariableBrowser, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showVariableBrowser);\n    connect(ui->actionClearOutput, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_clearOutput);\n    connect(ui->actionClearDebug, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_clearDebugPoints);\n    connect(ui->actionShowDebuggingOutput, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_showDebuggingOutput);\n    \n    // connect menu items that open a URL\n    connect(ui->actionSLiMWorkshops, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpWorkshops);\n    connect(ui->actionSendFeedback, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpFeedback);\n    connect(ui->actionMailingList_slimdiscuss, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpSLiMDiscuss);\n    connect(ui->actionMailingList_slimannounce, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpSLiMAnnounce);\n    connect(ui->actionSLiMHomePage, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpSLiMHome);\n    connect(ui->actionSLiMExtras, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpSLiMExtras);\n    connect(ui->actionAboutMesserLab, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpMesserLab);\n    connect(ui->actionAboutBenHaller, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpBenHaller);\n    connect(ui->actionAboutStickSoftware, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_helpStickSoftware);\n    \n    // connect custom menu items\n    connect(ui->actionCopyAsHTML, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_copyAsHTML);\n    connect(ui->actionShiftLeft, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_shiftLeft);\n    connect(ui->actionShiftRight, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_shiftRight);\n    connect(ui->actionCommentUncomment, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_commentUncomment);\n    connect(ui->actionExecuteSelection, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_executeSelection);\n    connect(ui->actionExecuteAll, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_executeAll);\n    \n    // standard actions that need to be dispatched (I haven't found a better way to do this;\n    // this is basically implementing the first responder / event dispatch mechanism)\n    connect(ui->actionUndo, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_undo);\n    connect(ui->actionRedo, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_redo);\n    connect(ui->actionCut, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_cut);\n    connect(ui->actionCopy, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_copy);\n    connect(ui->actionPaste, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_paste);\n    connect(ui->actionDuplicate, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_duplicate);\n    connect(ui->actionDelete, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_delete);\n    connect(ui->actionSelectAll, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_selectAll);\n    \n    // Find panel actions; these just get forwarded to QtSLiMFindPanel\n    connect(ui->actionFindShow, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findShow);\n    connect(ui->actionFindNext, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findNext);\n    connect(ui->actionFindPrevious, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_findPrevious);\n    connect(ui->actionReplaceAndFind, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_replaceAndFind);\n    connect(ui->actionUseSelectionForFind, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_useSelectionForFind);\n    connect(ui->actionUseSelectionForReplace, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_useSelectionForReplace);\n    connect(ui->actionJumpToSelection, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_jumpToSelection);\n    connect(ui->actionJumpToLine, &QAction::triggered, qtSLiMAppDelegate, &QtSLiMAppDelegate::dispatch_jumpToLine);\n}\n\n\n//\n//  private slots\n//\n\nvoid QtSLiMWindow::playPressed(void)\n{\n    updatePlayButtonIcon(true);\n}\nvoid QtSLiMWindow::playReleased(void)\n{\n    updatePlayButtonIcon(false);\n}\nvoid QtSLiMWindow::profilePressed(void)\n{\n    updateProfileButtonIcon(true);\n}\nvoid QtSLiMWindow::profileReleased(void)\n{\n    updateProfileButtonIcon(false);\n}\nvoid QtSLiMWindow::recyclePressed(void)\n{\n    updateRecycleButtonIcon(true);\n}\nvoid QtSLiMWindow::recycleReleased(void)\n{\n    updateRecycleButtonIcon(false);\n}\nvoid QtSLiMWindow::toggleDrawerPressed(void)\n{\n    ui->toggleDrawerButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::toggleDrawerReleased(void)\n{\n    ui->toggleDrawerButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::chromosomeActionPressed(void)\n{\n    ui->chromosomeActionButton->qtslimSetHighlight(true);\n    chromosomeConfig->actionButtonRunMenu(ui->chromosomeActionButton);\n}\nvoid QtSLiMWindow::chromosomeActionReleased(void)\n{\n    ui->chromosomeActionButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::chromosomeDisplayPressed(void)\n{\n    ui->chromosomeDisplayButton->qtslimSetHighlight(true);\n    chromosomeDisplayPopupButtonRunMenu();  // this button runs its menu when it is pressed, so make that call here\n}\nvoid QtSLiMWindow::chromosomeDisplayReleased(void)\n{\n    ui->chromosomeDisplayButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::clearDebugPressed(void)\n{\n    ui->clearDebugButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::clearDebugReleased(void)\n{\n    ui->clearDebugButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::checkScriptPressed(void)\n{\n    ui->checkScriptButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::checkScriptReleased(void)\n{\n    ui->checkScriptButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::prettyprintPressed(void)\n{\n    ui->prettyprintButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::prettyprintReleased(void)\n{\n    ui->prettyprintButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::scriptHelpPressed(void)\n{\n    ui->scriptHelpButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::scriptHelpReleased(void)\n{\n    ui->scriptHelpButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::showConsolePressed(void)\n{\n    ui->consoleButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::showConsoleReleased(void)\n{\n    ui->consoleButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::showBrowserPressed(void)\n{\n    ui->browserButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::showBrowserReleased(void)\n{\n    ui->browserButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::jumpToPopupButtonPressed(void)\n{\n    ui->jumpToPopupButton->qtslimSetHighlight(true);\n    jumpToPopupButtonRunMenu();  // this button runs its menu when it is pressed, so make that call here\n}\nvoid QtSLiMWindow::jumpToPopupButtonReleased(void)\n{\n    ui->jumpToPopupButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::clearOutputPressed(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::clearOutputReleased(void)\n{\n    ui->clearOutputButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::dumpPopulationPressed(void)\n{\n    ui->dumpPopulationButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::dumpPopulationReleased(void)\n{\n    ui->dumpPopulationButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::debugOutputPressed(void)\n{\n    ui->debugOutputButton->qtslimSetHighlight(true);\n    stopDebugButtonFlash();\n}\nvoid QtSLiMWindow::debugOutputReleased(void)\n{\n    ui->debugOutputButton->qtslimSetHighlight(false);\n    stopDebugButtonFlash();\n}\nvoid QtSLiMWindow::graphPopupButtonPressed(void)\n{\n    ui->graphPopupButton->qtslimSetHighlight(true);\n    graphPopupButtonRunMenu();  // this button runs its menu when it is pressed, so make that call here\n}\nvoid QtSLiMWindow::graphPopupButtonReleased(void)\n{\n    ui->graphPopupButton->qtslimSetHighlight(false);\n}\nvoid QtSLiMWindow::changeDirectoryPressed(void)\n{\n    ui->changeDirectoryButton->qtslimSetHighlight(true);\n}\nvoid QtSLiMWindow::changeDirectoryReleased(void)\n{\n    ui->changeDirectoryButton->qtslimSetHighlight(false);\n}\n"
  },
  {
    "path": "QtSLiM/QtSLiM_Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>SLiMgui</string>\n\t<key>CFBundleName</key>\n\t<string>SLiMgui</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleVersion</key>\n\t<string>${QMAKE_FULL_VERSION}</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>${QMAKE_FULL_VERSION}</string>\n\t<key>CFBundleGetInfoString</key>\n\t<string>The SLiM modeling environment.</string>\n\t<key>CFBundleIconFile</key>\n\t<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleSignature</key>\n\t<string>${QMAKE_PKGINFO_TYPEINFO}</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>${MACOSX_DEPLOYMENT_TARGET}</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016–2025 Benjamin C. Haller, http://messerlab.org/slim/. All rights reserved.</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>NSSupportsAutomaticGraphicsSwitching</key>\n\t<true/>\n\t<key>NSRequiresAquaSystemAppearance</key>\n\t<false/>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>slim</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeIconFile</key>\n\t\t\t<string>QtSLiM_DocIcon.icns</string>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Owner</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>txt</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>NSStringPboardType</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>public.plain-text</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>jpg</string>\n\t\t\t\t<string>jpeg</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>image/jpeg</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>JPEG image</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>public.jpeg</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>png</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>image/png</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>PNG image</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>public.png</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>gif</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>image/gif</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>GIF image</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>com.compuserve.gif</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>UTExportedTypeDeclarations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>UTTypeConformsTo</key>\n\t\t\t<array>\n\t\t\t\t<string>public.text</string>\n\t\t\t</array>\n\t\t\t<key>UTTypeDescription</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>UTTypeIconFile</key>\n\t\t\t<string>QtSLiM_DocIcon.icns</string>\n\t\t\t<key>UTTypeIdentifier</key>\n\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t<key>UTTypeReferenceURL</key>\n\t\t\t<string>https://messerlab.org/slim/</string>\n\t\t\t<key>UTTypeTagSpecification</key>\n\t\t\t<dict>\n\t\t\t\t<key>com.apple.nspboard-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>NSStringPboardType</string>\n\t\t\t\t</array>\n\t\t\t\t<key>com.apple.ostype</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>SLiM</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.filename-extension</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>slim</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.mime-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>text/plain</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "QtSLiM/QtSLiM_Plot.cpp",
    "content": "//\n//  QtSLiM_Plot.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 1/30/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiM_Plot.h\"\n#include \"QtSLiMGraphView_CustomPlot.h\"\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_class_Image.h\"\n\n#include \"spatial_map.h\"\n\n#include <unistd.h>\n\n#include <string>\n#include <algorithm>\n#include <vector>\n#include <limits>\n\n\n#pragma mark -\n#pragma mark Plot\n#pragma mark -\n\nPlot::Plot(const std::string &title, QtSLiMGraphView_CustomPlot *p_plotview) :\n    title_(title), plotview_(p_plotview)\n{\n}\n\nPlot::~Plot(void)\n{\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *Plot::Class(void) const\n{\n\treturn gSLiM_Plot_Class;\n}\n\nvoid Plot::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP Plot::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t// constants\n        case gID_title:\n        {\n            return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(title_));\n        }\n        \n        // variables\n\t\t\n\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid Plot::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP Plot::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n        case gID_abline:                return ExecuteMethod_abline(p_method_id, p_arguments, p_interpreter);\n        case gID_addLegend:             return ExecuteMethod_addLegend(p_method_id, p_arguments, p_interpreter);\n        case gID_axis:                  return ExecuteMethod_axis(p_method_id, p_arguments, p_interpreter);\n        case gID_image:                 return ExecuteMethod_image(p_method_id, p_arguments, p_interpreter);\n        case gID_legendLineEntry:       return ExecuteMethod_legendLineEntry(p_method_id, p_arguments, p_interpreter);\n        case gID_legendPointEntry:      return ExecuteMethod_legendPointEntry(p_method_id, p_arguments, p_interpreter);\n        case gID_legendSwatchEntry:     return ExecuteMethod_legendSwatchEntry(p_method_id, p_arguments, p_interpreter);\n        case gID_legendTitleEntry:      return ExecuteMethod_legendTitleEntry(p_method_id, p_arguments, p_interpreter);\n        case gID_lines:\t\t\t\t\treturn ExecuteMethod_lines(p_method_id, p_arguments, p_interpreter);\n        case gID_matrix:                return ExecuteMethod_matrix(p_method_id, p_arguments, p_interpreter);\n        case gID_mtext:                 return ExecuteMethod_mtext(p_method_id, p_arguments, p_interpreter);\n        case gID_points:\t\t\t\treturn ExecuteMethod_points(p_method_id, p_arguments, p_interpreter);\n        case gID_rects:\t\t\t\t\treturn ExecuteMethod_rects(p_method_id, p_arguments, p_interpreter);\n        case gID_segments:\t\t\t\treturn ExecuteMethod_segments(p_method_id, p_arguments, p_interpreter);\n        case gID_setBorderless:\t\t\treturn ExecuteMethod_setBorderless(p_method_id, p_arguments, p_interpreter);\n        case gID_text:\t\t\t\t\treturn ExecuteMethod_text(p_method_id, p_arguments, p_interpreter);\n        case gEidosID_write:\t\t\treturn ExecuteMethod_write(p_method_id, p_arguments, p_interpreter);\n        default:                        return super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (void)abline([Nif a = NULL], [Nif b = NULL], [Nif h = NULL], [Nif v = NULL], [string color = \"red\"], [numeric lwd = 1.0], [float alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_abline(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *a_value = p_arguments[0].get();\n    EidosValue *b_value = p_arguments[1].get();\n    EidosValue *h_value = p_arguments[2].get();\n    EidosValue *v_value = p_arguments[3].get();\n    EidosValue *color_value = p_arguments[4].get();\n    EidosValue *lwd_value = p_arguments[5].get();\n    EidosValue *alpha_value = p_arguments[6].get();\n    double *a = nullptr, *b = nullptr, *h = nullptr, *v = nullptr;\n    int line_count;\n    \n    if ((a_value->Type() != EidosValueType::kValueNULL) && (b_value->Type() != EidosValueType::kValueNULL) && (h_value->Type() == EidosValueType::kValueNULL) && (v_value->Type() == EidosValueType::kValueNULL))\n    {\n        // a and b\n        int acount = a_value->Count();\n        int bcount = b_value->Count();\n        \n        if (acount == bcount)   line_count = acount;\n        else if (acount == 1)   line_count = bcount;\n        else if (bcount == 1)   line_count = acount;\n        else\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires a and b to be the same length, or one of them to be singleton.\" << EidosTerminate();\n        \n        if (line_count == 0)\n            return gStaticEidosValueVOID;\n        \n        a = (double *)malloc(line_count * sizeof(double));\n        b = (double *)malloc(line_count * sizeof(double));\n        \n        if (!a || !b)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n        \n        for (int index = 0; index < line_count; ++index)\n        {\n            a[index] = a_value->NumericAtIndex_NOCAST(index % acount, nullptr);\n            b[index] = b_value->NumericAtIndex_NOCAST(index % bcount, nullptr);\n        }\n    }\n    else if ((a_value->Type() == EidosValueType::kValueNULL) && (b_value->Type() == EidosValueType::kValueNULL) && (h_value->Type() != EidosValueType::kValueNULL) && (v_value->Type() == EidosValueType::kValueNULL))\n    {\n        // h\n        line_count = h_value->Count();\n        \n        if (line_count == 0)\n            return gStaticEidosValueVOID;\n        \n        h = (double *)malloc(line_count * sizeof(double));\n        \n        if (!h)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n        \n        for (int index = 0; index < line_count; ++index)\n            h[index] = h_value->NumericAtIndex_NOCAST(index, nullptr);\n    }\n    else if ((a_value->Type() == EidosValueType::kValueNULL) && (b_value->Type() == EidosValueType::kValueNULL) && (h_value->Type() == EidosValueType::kValueNULL) && (v_value->Type() != EidosValueType::kValueNULL))\n    {\n        // v\n        line_count = v_value->Count();\n        \n        if (line_count == 0)\n            return gStaticEidosValueVOID;\n        \n        v = (double *)malloc(line_count * sizeof(double));\n        \n        if (!v)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n        \n        for (int index = 0; index < line_count; ++index)\n            v[index] = v_value->NumericAtIndex_NOCAST(index, nullptr);\n    }\n    else\n    {\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires one of three usage modes: (1) a and b are non-NULL while h and v are NULL; (2) a, b, and v are NULL while h is non-NULL; or (3) a, b, and h are NULL while v is non-NULL.\" << EidosTerminate(nullptr);\n    }\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != line_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires color to match the number of lines, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t colorR, colorG, colorB;\n        \n        Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n        \n        colors->emplace_back(colorR, colorG, colorB, 255);\n    }\n    \n    // lwd\n    std::vector<double> *lwds = new std::vector<double>;\n    int lwd_count = lwd_value->Count();\n    \n    if ((lwd_count != 1) && (lwd_count != line_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires lwd to match the number of lines, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < lwd_count; ++index)\n    {\n        double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((lwd < 0.0) || (lwd > 100.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires the elements of lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n        \n        lwds->push_back(lwd);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != line_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires alpha to match the number of lines, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_abline): abline() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    plotview_->addABLineData(a, b, h, v, line_count, colors, alphas, lwds);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)addLegend([Ns$ position = NULL], [Ni$ inset = NULL], [Nif$ labelSize = NULL], [Nif$ lineHeight = NULL], [Nif$ graphicsWidth = NULL], [Nif$ exteriorMargin = NULL], [Nif$ interiorMargin = NULL])\n//\nEidosValue_SP Plot::ExecuteMethod_addLegend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *position_value = p_arguments[0].get();\n    EidosValue *inset_value = p_arguments[1].get();\n    EidosValue *labelSize_value = p_arguments[2].get();\n    EidosValue *lineHeight_value = p_arguments[3].get();\n    EidosValue *graphicsWidth_value = p_arguments[4].get();\n    EidosValue *exteriorMargin_value = p_arguments[5].get();\n    EidosValue *interiorMargin_value = p_arguments[6].get();\n    \n    // position\n    QtSLiM_LegendPosition position;\n    \n    if (position_value->Type() == EidosValueType::kValueNULL)\n    {\n        position = QtSLiM_LegendPosition::kUnconfigured;\n    }\n    else\n    {\n        QString positionString  = QString::fromStdString(position_value->StringAtIndex_NOCAST(0, nullptr));\n        \n        if (positionString == \"topLeft\")\n            position = QtSLiM_LegendPosition::kTopLeft;\n        else if (positionString == \"topRight\")\n            position = QtSLiM_LegendPosition::kTopRight;\n        else if (positionString == \"bottomLeft\")\n            position = QtSLiM_LegendPosition::kBottomLeft;\n        else if (positionString == \"bottomRight\")\n            position = QtSLiM_LegendPosition::kBottomRight;\n        else\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires position to be 'topLeft', 'topRight', 'bottomLeft', or 'bottomRight' (or NULL).\" << EidosTerminate(nullptr);\n    }\n    \n    // inset\n    int inset;\n    \n    if (inset_value->Type() == EidosValueType::kValueNULL)\n        inset = -1;\n    else\n    {\n        inset = inset_value->IntAtIndex_NOCAST(0, nullptr);\n        \n        if ((inset < 0) || (inset > 50))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires inset to be in [0, 50].\" << EidosTerminate(nullptr);\n    }\n    \n    // labelSize\n    double labelSize;\n    \n    if (labelSize_value->Type() == EidosValueType::kValueNULL)\n        labelSize = -1;\n    else\n    {\n        labelSize = labelSize_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(labelSize) || (labelSize < 5) || (labelSize > 50))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires labelSize to be in [5, 50].\" << EidosTerminate(nullptr);\n    }\n    \n    // lineHeight\n    double lineHeight;\n    \n    if (lineHeight_value->Type() == EidosValueType::kValueNULL)\n        lineHeight = -1;\n    else\n    {\n        lineHeight = lineHeight_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(lineHeight) || (lineHeight < 5) || (lineHeight > 100))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires lineHeight to be in [5, 100].\" << EidosTerminate(nullptr);\n    }\n    \n    // graphicsWidth\n    double graphicsWidth;\n    \n    if (graphicsWidth_value->Type() == EidosValueType::kValueNULL)\n        graphicsWidth = -1;\n    else\n    {\n        graphicsWidth = graphicsWidth_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(graphicsWidth) || (graphicsWidth < 5) || (graphicsWidth > 100))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires graphicsWidth to be in [5, 100].\" << EidosTerminate(nullptr);\n    }\n    \n    // exteriorMargin\n    double exteriorMargin;\n    \n    if (exteriorMargin_value->Type() == EidosValueType::kValueNULL)\n        exteriorMargin = -1;\n    else\n    {\n        exteriorMargin = exteriorMargin_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(exteriorMargin) || (exteriorMargin < 0) || (exteriorMargin > 50))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires exteriorMargin to be in [0, 50].\" << EidosTerminate(nullptr);\n    }\n    \n    // interiorMargin\n    double interiorMargin;\n    \n    if (interiorMargin_value->Type() == EidosValueType::kValueNULL)\n        interiorMargin = -1;\n    else\n    {\n        interiorMargin = interiorMargin_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(interiorMargin) || (interiorMargin < 0) || (interiorMargin > 50))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() requires interiorMargin to be in [0, 50].\" << EidosTerminate(nullptr);\n    }\n    \n    if (plotview_->legendAdded())\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_addLegend): addLegend() has already been called for this plot, and should only be called once.\" << EidosTerminate(nullptr);\n    \n    plotview_->addLegend(position, inset, labelSize, lineHeight, graphicsWidth, exteriorMargin, interiorMargin);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)axis(integer$ side, [Nif at = NULL], [ls labels = T])\n//\nEidosValue_SP Plot::ExecuteMethod_axis(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *side_value = p_arguments[0].get();\n    EidosValue *at_value = p_arguments[1].get();\n    EidosValue *labels_value = p_arguments[2].get();\n    \n    // side\n    int side = (int)side_value->IntAtIndex_NOCAST(0, nullptr);\n    \n    if ((side != 1) && (side != 2))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_axis): axis() requires side to be 1 (for the x axis) or 2 (for the y axis).\" << EidosTerminate(nullptr);\n    \n    // at\n    std::vector<double> *at = nullptr;\n    int at_length = 0;\n    double last_at = -std::numeric_limits<double>::infinity();\n    \n    if (at_value->Type() != EidosValueType::kValueNULL)\n    {\n        at_length = at_value->Count();\n        at = new std::vector<double>;\n        \n        for (int index = 0; index < at_length; ++index)\n        {\n            double pos = at_value->NumericAtIndex_NOCAST(index, nullptr);\n            \n            if (!std::isfinite(pos))\n                EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_axis): axis() requires the elements of at to be finite.\" << EidosTerminate(nullptr);\n            \n            if (pos <= last_at)\n                EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_axis): axis() requires the elements of at to be in sorted (increasing) order.\" << EidosTerminate(nullptr);\n            last_at = pos;\n            \n            at->push_back(pos);\n        }\n    }\n    \n    // labels\n    std::vector<QString> *labels;\n    int labels_type;\n    \n    if (labels_value->Type() == EidosValueType::kValueLogical)\n    {\n        // labels can be T, F, or a vector of type string; we need a separate flag to differentiate those cases\n        // T is 1, F is 0, and the string vector case is 2\n        labels = nullptr;\n        labels_type = (int)labels_value->LogicalAtIndex_NOCAST(0, nullptr);\n    }\n    else\n    {\n        if (at_value->Type() == EidosValueType::kValueNULL)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_axis): axis() requires that when at is NULL, labels be T or F; a vector of labels cannot be supplied without corresponding positions.\" << EidosTerminate(nullptr);\n        \n        const std::string *string_data = labels_value->StringData();\n        int labels_length = labels_value->Count();\n        \n        if (labels_length != at_length)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_axis): axis() requires that labels be the same length as at (if labels is not T or F), to supply a label for each corresponding position.\" << EidosTerminate(nullptr);\n        \n        labels = new std::vector<QString>;\n        labels_type = 2;\n        \n        for (int index = 0; index < labels_length; ++index)\n            labels->emplace_back(QString::fromStdString(string_data[index]));\n    }\n    \n    plotview_->setAxisConfiguration(side, at, labels_type, labels);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)image(object$ image, numeric$ x1, numeric$ y1, numeric$ x2, numeric$ y2, [logical$ flipped = F], [float$ alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_image(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *image_value = p_arguments[0].get();\n    EidosValue *x1_value = p_arguments[1].get();\n    EidosValue *y1_value = p_arguments[2].get();\n    EidosValue *x2_value = p_arguments[3].get();\n    EidosValue *y2_value = p_arguments[4].get();\n    EidosValue *flipped_value = p_arguments[5].get();\n    EidosValue *alpha_value = p_arguments[6].get();\n    \n    // flipped -- handled out of order because we need this to process image\n    bool flipped = flipped_value->LogicalAtIndex_NOCAST(0, nullptr);\n    \n    // image\n    EidosObject *image_object = image_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n    QImage image;\n    \n    if (image_object->Class() == gSLiM_SpatialMap_Class)\n    {\n        // if image is a SpatialImage, plot the map's values; it must be a singleton and have 2D spatiality\n        if (image_value->Count() != 1)\n            EIDOS_TERMINATION << \"ERROR (Plot::image): a SpatialMap value passed to image() must be a singleton.\" << EidosTerminate(nullptr);\n        \n        SpatialMap *spatial_map = (SpatialMap *)image_object;\n        \n        if (spatial_map->image_ && (spatial_map->image_flipped_ == flipped))\n        {\n            // we have a cached QImage for this SpatialMap, and it matches our flipped flag\n            image = *(QImage *)spatial_map->image_;  // make a copy with implicit sharing\n        }\n        else\n        {\n            // cache the spatial map's image if it doesn't already have a matching cache; first delete any existing (unmatching) cache\n            if (spatial_map->image_)\n            {\n                if (spatial_map->image_deleter_)\n                    spatial_map->image_deleter_(spatial_map->image_);\n                else\n                    std::cout << \"Missing SpatialMap image_deleter_; leaking memory\" << std::endl;\n                \n                spatial_map->image_ = nullptr;\n                spatial_map->image_deleter_ = nullptr;\n            }\n            \n            if (spatial_map->spatiality_ != 2)\n                EIDOS_TERMINATION << \"ERROR (Plot::image): image() only supports plotting of spatial maps of spatiality 2 ('xy', 'xz', or 'yz' maps).\" << EidosTerminate(nullptr);\n            \n            int64_t image_width = spatial_map->grid_size_[0];\n            int64_t image_height = spatial_map->grid_size_[1];\n            \n            if ((image_width <= 1) || (image_height <= 1))\n                EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires the plotted spatial map to be 2x2 or larger in its grid dimensions.\" << EidosTerminate(nullptr);\n            \n            // the edge rows/columns get one pixel; interior rows/edges get two pixels\n            // this gives us an image that correctly matches the spatial map in SLiM\n            image_width = image_width * 2 - 2;\n            image_height = image_height * 2 - 2;\n            \n            // make the image buffer to be used by QtSLiMGraphView_CustomPlot; note that it takes ownership of image_data and frees it for us\n            const int bytes_per_pixel = 3;  // RGB888 format\n            uint8_t *image_data = (uint8_t *)malloc(image_width * image_height * bytes_per_pixel * sizeof(uint8_t));\n            \n            // we never interpolate map values, since the correct resolution is ambiguous; we're generating vector graphics here\n            // FIXME: maybe the spatial map display in the individuals view should turn off interpolation too; let the user interpolate the map if they want interpolated display\n            spatial_map->FillRGBBuffer(image_data, image_width, image_height, flipped, /* no_interpolation */ false);\n            \n            QImage *cached_image = new QImage(image_data, image_width, image_height, image_width * bytes_per_pixel, QImage::Format_RGB888, free, image_data);\n            \n            // We give the cached image to the SpatialMap object.  Since it doesn't build against Qt, we give it a deletor function.\n            spatial_map->image_ = cached_image;\n            spatial_map->image_flipped_ = flipped;\n            spatial_map->image_deleter_ = Eidos_Deleter<QImage>;\n            \n            image = *cached_image;  // make a copy with implicit sharing\n        }\n    }\n    else if (image_object->Class() == gEidosImage_Class)\n    {\n        // if image is an Image, plot the image's values; it must be a singleton\n        if (image_value->Count() != 1)\n            EIDOS_TERMINATION << \"ERROR (Plot::image): an Image value passed to image() must be a singleton.\" << EidosTerminate(nullptr);\n        \n        EidosImage *eidos_image = (EidosImage *)image_object;\n        \n        if (eidos_image->image_ && (eidos_image->image_flipped_ == flipped))\n        {\n            // we have a cached QImage for this Image, and it matches our flipped flag\n            image = *(QImage *)eidos_image->image_;  // make a copy with implicit sharing\n        }\n        else\n        {\n            // cache the Image's image if it doesn't already have a matching cache; first delete any existing (unmatching) cache\n            if (eidos_image->image_)\n            {\n                if (eidos_image->image_deleter_)\n                    eidos_image->image_deleter_(eidos_image->image_);\n                else\n                    std::cout << \"Missing Image image_deleter_; leaking memory\" << std::endl;\n                \n                eidos_image->image_ = nullptr;\n                eidos_image->image_deleter_ = nullptr;\n            }\n            \n            int64_t image_width = eidos_image->width_;\n            int64_t image_height = eidos_image->height_;\n            \n            // make the image buffer to be used by QtSLiMGraphView_CustomPlot; note that it takes ownership of image_data and frees it for us\n            const int bytes_per_pixel = (eidos_image->is_grayscale_ ? 1 : 3);  // Grayscale8 or RGB888 format\n            uint8_t *image_data = (uint8_t *)malloc(image_width * image_height * bytes_per_pixel * sizeof(uint8_t));\n            \n            // optionally flip the rows of the image buffer so it displays in the orientation we want; this could be an option\n            // note that here flipping is done by default, so flipped=true turns off this flip!\n            if (!flipped)\n            {\n                for (int y = 0; y < image_height; ++y)\n                    memcpy(image_data + y * (image_width * bytes_per_pixel * sizeof(uint8_t)),\n                           eidos_image->pixels_.data() + (image_height - y - 1) * (image_width * bytes_per_pixel * sizeof(uint8_t)),\n                           image_width * bytes_per_pixel * sizeof(uint8_t));\n            }\n            else\n            {\n                memcpy(image_data, eidos_image->pixels_.data(), image_width * image_height * bytes_per_pixel * sizeof(uint8_t));\n            }\n            \n            QImage *cached_image = new QImage(image_data, image_width, image_height, image_width * bytes_per_pixel,\n                                              (eidos_image->is_grayscale_ ? QImage::Format_Grayscale8 : QImage::Format_RGB888), free, image_data);\n            \n            // We give the cached image to the EidosImage object.  Since it doesn't build against Qt, we give it a deletor function.\n            eidos_image->image_ = cached_image;\n            eidos_image->image_flipped_ = flipped;\n            eidos_image->image_deleter_ = Eidos_Deleter<QImage>;\n            \n            image = *cached_image;  // make a copy with implicit sharing\n        }\n    }\n    else\n    {\n        EIDOS_TERMINATION << \"ERROR (Plot::image): unsupported object class in image(); image must be of class SpatialMap or class Image.\" << EidosTerminate(nullptr);\n    }\n    \n    // x and y\n    double *x = (double *)malloc(2 * sizeof(double));\n    double *y = (double *)malloc(2 * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::image): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    x[0] = x1_value->NumericAtIndex_NOCAST(0, nullptr);\n    y[0] = y1_value->NumericAtIndex_NOCAST(0, nullptr);\n    x[1] = x2_value->NumericAtIndex_NOCAST(0, nullptr);\n    y[1] = y2_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if (x[0] > x[1])\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires x1 <= x2.\" << EidosTerminate(nullptr);\n    if (y[0] > y[1])\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires y1 <= y2.\" << EidosTerminate(nullptr);\n    \n    // alpha\n    double alpha = alpha_value->FloatAtIndex_NOCAST(0, nullptr);\n    \n    if ((alpha < 0.0) || (alpha > 1.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires the image alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n    \n    std::vector<double> *imageAlphas = new std::vector<double>;  // we only take a singleton alpha, but the API expects a buffer\n    \n    imageAlphas->push_back(alpha);\n    \n    plotview_->addImageData(x, y, 2, image, imageAlphas);       // implicitly shares image; takes the x, y, and imageAlphas buffers from us\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendLineEntry(string$ label, [string$ color = \"red\"], [numeric$ lwd = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *label_value = p_arguments[0].get();\n    EidosValue *color_value = p_arguments[1].get();\n    EidosValue *lwd_value = p_arguments[2].get();\n    \n    // label\n    QString label = QString::fromStdString(label_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (label.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendLineEntry): legendLineEntry() requires a non-empty legend label.\" << EidosTerminate();\n    \n    // color\n    std::string color_string = color_value->StringAtIndex_NOCAST(0, nullptr);\n    uint8_t colorR, colorG, colorB;\n    \n    Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n    \n    QColor color(colorR, colorG, colorB, 255);\n    \n    // lwd\n    double lwd = lwd_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if ((lwd < 0.0) || (lwd > 100.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendLineEntry): legendLineEntry() requires the line width lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n    \n    if (!plotview_->legendAdded())\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendLineEntry): addLegend() must be called before adding legend entries.\" << EidosTerminate(nullptr);\n    \n    plotview_->addLegendLineEntry(label, color, lwd);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendPointEntry(string$ label, [integer$ symbol = 0], [string$ color = \"red\"], [string$ border = \"black\"], [numeric$ lwd = 1.0], [numeric$ size = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *label_value = p_arguments[0].get();\n    EidosValue *symbol_value = p_arguments[1].get();\n    EidosValue *color_value = p_arguments[2].get();\n    EidosValue *border_value = p_arguments[3].get();\n    EidosValue *lwd_value = p_arguments[4].get();\n    EidosValue *size_value = p_arguments[5].get();\n    \n    // label\n    QString label = QString::fromStdString(label_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (label.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendPointEntry): legendPointEntry() requires a non-empty legend label.\" << EidosTerminate();\n    \n    // symbol\n    int symbol = symbol_value->IntAtIndex_NOCAST(0, nullptr);\n    \n    if (symbol < 0)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendPointEntry): legendPointEntry() requires the elements of symbol to be >= 0.\" << EidosTerminate();\n    \n    // color\n    std::string color_string = color_value->StringAtIndex_NOCAST(0, nullptr);\n    uint8_t colorR, colorG, colorB;\n    \n    Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n    \n    QColor color(colorR, colorG, colorB, 255);\n    \n    // border\n    std::string border_string = border_value->StringAtIndex_NOCAST(0, nullptr);\n    uint8_t borderR, borderG, borderB;\n    \n    Eidos_GetColorComponents(border_string, &borderR, &borderG, &borderB);\n    \n    QColor border(borderR, borderG, borderB, 255);\n    \n    // lwd\n    double lwd = lwd_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if ((lwd < 0.0) || (lwd > 100.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendPointEntry): legendPointEntry() requires the elements of lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n    \n    // size\n    double size = size_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if ((size <= 0.0) || (size > 1000.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendPointEntry): legendPointEntry() requires the elements of size to be in (0, 1000].\" << EidosTerminate(nullptr);\n    \n    if (!plotview_->legendAdded())\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendPointEntry): addLegend() must be called before adding legend entries.\" << EidosTerminate(nullptr);\n    \n    plotview_->addLegendPointEntry(label, symbol, color, border, lwd, size);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendSwatchEntry(string$ label, [string$ color = \"red\"])\n//\nEidosValue_SP Plot::ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *label_value = p_arguments[0].get();\n    EidosValue *color_value = p_arguments[1].get();\n    \n    // label\n    QString label = QString::fromStdString(label_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (label.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendSwatchEntry): legendSwatchEntry() requires a non-empty legend label.\" << EidosTerminate();\n    \n    // color\n    std::string color_string = color_value->StringAtIndex_NOCAST(0, nullptr);\n    uint8_t colorR, colorG, colorB;\n    \n    Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n    \n    QColor color(colorR, colorG, colorB, 255);\n    \n    if (!plotview_->legendAdded())\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendSwatchEntry): addLegend() must be called before adding legend entries.\" << EidosTerminate(nullptr);\n    \n    plotview_->addLegendSwatchEntry(label, color);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendTitleEntry(string$ label)\n//\nEidosValue_SP Plot::ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *label_value = p_arguments[0].get();\n    \n    // label\n    QString label = QString::fromStdString(label_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (!plotview_->legendAdded())\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_legendTitleEntry): addLegend() must be called before adding legend entries.\" << EidosTerminate(nullptr);\n    \n    plotview_->addLegendTitleEntry(label);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)lines(numeric x, numeric y, [string$ color = \"red\"], [numeric$ lwd = 1.0], [float$ alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *x_value = p_arguments[0].get();\n    EidosValue *y_value = p_arguments[1].get();\n    EidosValue *color_value = p_arguments[2].get();\n    EidosValue *lwd_value = p_arguments[3].get();\n    EidosValue *alpha_value = p_arguments[4].get();\n    \n    // x and y\n    int xcount = x_value->Count();\n    int ycount = y_value->Count();\n    \n    if (xcount != ycount)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_lines): lines() requires x and y to be the same length.\" << EidosTerminate();\n    \n    double *x = (double *)malloc(xcount * sizeof(double));\n    double *y = (double *)malloc(ycount * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_lines): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x, x_value->FloatData(), xcount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x_value->IntData();\n        \n        for (int index = 0; index < xcount; ++index)\n            x[index] = int_data[index];\n    }\n    \n    if (y_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y, y_value->FloatData(), ycount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y_value->IntData();\n        \n        for (int index = 0; index < ycount; ++index)\n            y[index] = int_data[index];\n    }\n    \n    // color\n    std::string color_string = color_value->StringAtIndex_NOCAST(0, nullptr);\n    uint8_t colorR, colorG, colorB;\n    \n    Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n    \n    std::vector<QColor> *colors = new std::vector<QColor>;\n    \n    colors->emplace_back(colorR, colorG, colorB, 255);\n    \n    // lwd\n    double lwd = lwd_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if ((lwd < 0.0) || (lwd > 100.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_lines): lines() requires the line width lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n    \n    std::vector<double> *lineWidths = new std::vector<double>;  // we only take a singleton width, but the API expects a buffer\n    \n    lineWidths->push_back(lwd);\n    \n    // alpha\n    double alpha = alpha_value->FloatAtIndex_NOCAST(0, nullptr);\n    \n    if ((alpha < 0.0) || (alpha > 1.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_lines): lines() requires the line width alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n    \n    std::vector<double> *lineAlphas = new std::vector<double>;  // we only take a singleton alpha, but the API expects a buffer\n    \n    lineAlphas->push_back(alpha);\n    \n    plotview_->addLineData(x, y, xcount, colors, lineAlphas, lineWidths);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)matrix(object$ image, numeric$ x1, numeric$ y1, numeric$ x2, numeric$ y2, [logical$ flipped = F],\n//                                          [Nif valueRange = NULL], [Ns$ colors = NULL], [float$ alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_matrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *matrix_value = p_arguments[0].get();\n    EidosValue *x1_value = p_arguments[1].get();\n    EidosValue *y1_value = p_arguments[2].get();\n    EidosValue *x2_value = p_arguments[3].get();\n    EidosValue *y2_value = p_arguments[4].get();\n    EidosValue *flipped_value = p_arguments[5].get();\n    EidosValue *valueRange_value = p_arguments[6].get();\n    EidosValue *colors_value = p_arguments[7].get();\n    EidosValue *alpha_value = p_arguments[8].get();\n    \n    // flipped\n    bool flipped = flipped_value->LogicalAtIndex_NOCAST(0, nullptr);\n    \n    // valueRange\n    double range_min = 0.0, range_max = 0.0;\n    \n    if (valueRange_value->Type() == EidosValueType::kValueNULL)\n    {\n        range_min = 0.0;\n        range_max = 1.0;\n    }\n    else\n    {\n        if (valueRange_value->Count() != 2)\n            EIDOS_TERMINATION << \"ERROR (Plot::matrix): matrix() requires valueRange to be a vector of length 2 providing a data range, or NULL to use the default data range of [0, 1].\" << EidosTerminate(nullptr);\n        \n        range_min = valueRange_value->NumericAtIndex_NOCAST(0, nullptr);\n        range_max = valueRange_value->NumericAtIndex_NOCAST(1, nullptr);\n        \n        if (!std::isfinite(range_min) || !std::isfinite(range_max) || (range_min == range_max))\n            EIDOS_TERMINATION << \"ERROR (Plot::matrix): matrix() requires valueRange to contain finite, unequal values that define a data range.\" << EidosTerminate(nullptr);\n    }\n    \n    // colors\n    std::string colors_name;\n    \n    if (colors_value->Type() == EidosValueType::kValueNULL)\n    {\n        colors_name = \"gray\";\n        std::swap(range_min, range_max);\n    }\n    else\n    {\n        colors_name = colors_value->StringAtIndex_NOCAST(0, nullptr);\n    }\n    \n    EidosColorPalette palette = Eidos_PaletteForName(colors_name);\n    \n    if (palette == EidosColorPalette::kPalette_INVALID)\n        EIDOS_TERMINATION << \"ERROR (Plot::matrix): unrecognized color palette name in matrix().\" << EidosTerminate(nullptr);\n    \n    // figure out the rescaling factors in effect; note that colors=NULL might have reversed the rescaling range\n    bool rescaling = false;\n    double rescale_offset = 0.0;\n    double rescale_scaling = 1.0;\n    \n    if ((range_min != 0.0) || (range_max != 1.0))\n    {\n        rescaling = true;\n        rescale_offset = -range_min;\n        rescale_scaling = 1.0 / (range_max - range_min);\n    }\n    \n    // matrix\n    if ((matrix_value->DimensionCount() != 2))\n        EIDOS_TERMINATION << \"ERROR (Plot::matrix): matrix() requires that parameter matrix is actually a matrix (not a vector or array).\" << EidosTerminate(nullptr);\n    \n    const int64_t *dims = matrix_value->Dimensions();\n    int64_t matrix_rows = dims[0];\n    int64_t matrix_columns = dims[1];\n    \n    if ((matrix_value->DimensionCount() != 2) || (matrix_rows < 1) || (matrix_columns < 1))\n        EIDOS_TERMINATION << \"ERROR (Plot::matrix): matrix() requires a matrix that is at least 1x1 in its dimensions.\" << EidosTerminate(nullptr);\n    \n    // make the image buffer to be used by QtSLiMGraphView_CustomPlot; note that it takes ownership of image_data and frees it for us\n    int64_t image_width = matrix_columns;\n    int64_t image_height = matrix_rows;\n    const int bytes_per_pixel = 3;  // RGB888 format\n    uint8_t *image_data = (uint8_t *)malloc(matrix_rows * matrix_columns * bytes_per_pixel * sizeof(uint8_t));\n    uint8_t *image_data_ptr = image_data;\n    \n    // optionally flip the rows of the image buffer so it displays in the orientation we want; this could be an option\n    // note that here flipping is done by default, so flipped=true turns off this flip!\n    if (matrix_value->Type() == EidosValueType::kValueInt)\n    {\n        const int64_t *matrix_data = matrix_value->IntData();\n        \n        for (int64_t matrix_row = 0; matrix_row < matrix_rows; ++matrix_row)\n        {\n            int64_t matrix_row_to_read = (flipped ? matrix_row : (matrix_rows - 1) - matrix_row);\n            \n            for (int64_t matrix_column = 0; matrix_column < matrix_columns; ++matrix_column)\n            {\n                double original_value = matrix_data[matrix_row_to_read + matrix_column * matrix_rows];\n                double value = original_value;\n                \n                if (rescaling)\n                    value = (value + rescale_offset) * rescale_scaling;\n                \n                if (value < 0.0)\n                    value = 0.0;\n                if (value > 1.0)\n                    value = 1.0;\n                \n                double red, green, blue;\n                \n                Eidos_ColorPaletteLookup(value, palette, red, green, blue);\n                \n                uint8_t r_i = round(red * 255.0);\n                uint8_t g_i = round(green * 255.0);\n                uint8_t b_i = round(blue * 255.0);\n                \n                *(image_data_ptr++) = r_i;\n                *(image_data_ptr++) = g_i;\n                *(image_data_ptr++) = b_i;\n                \n                //std::cout << \"original_value \" << original_value << \" rescaled to value \" << value << \", r \" << (uint32_t)r_i << \", g \" << (uint32_t)g_i << \", b \" << (uint32_t)b_i << std::endl;\n            }\n        }\n    }\n    else\n    {\n        const double *matrix_data = matrix_value->FloatData();\n        \n        for (int64_t matrix_row = 0; matrix_row < matrix_rows; ++matrix_row)\n        {\n            int64_t matrix_row_to_read = (flipped ? matrix_row : (matrix_rows - 1) - matrix_row);\n            \n            for (int64_t matrix_column = 0; matrix_column < matrix_columns; ++matrix_column)\n            {\n                double original_value = matrix_data[matrix_row_to_read + matrix_column * matrix_rows];\n                double value = original_value;\n                \n                if (rescaling)\n                    value = (value + rescale_offset) * rescale_scaling;\n                \n                if (value < 0.0)\n                    value = 0.0;\n                if (value > 1.0)\n                    value = 1.0;\n                \n                double red, green, blue;\n                \n                Eidos_ColorPaletteLookup(value, palette, red, green, blue);\n                \n                uint8_t r_i = round(red * 255.0);\n                uint8_t g_i = round(green * 255.0);\n                uint8_t b_i = round(blue * 255.0);\n                \n                *(image_data_ptr++) = r_i;\n                *(image_data_ptr++) = g_i;\n                *(image_data_ptr++) = b_i;\n                \n                //std::cout << \"original_value \" << original_value << \" rescaled to value \" << value << \", r \" << (uint32_t)r_i << \", g \" << (uint32_t)g_i << \", b \" << (uint32_t)b_i << std::endl;\n            }\n        }\n    }\n    \n    QImage image(image_data, image_width, image_height, image_width * bytes_per_pixel, QImage::Format_RGB888, free, image_data);\n    \n    // x and y\n    double *x = (double *)malloc(2 * sizeof(double));\n    double *y = (double *)malloc(2 * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::image): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    x[0] = x1_value->NumericAtIndex_NOCAST(0, nullptr);\n    y[0] = y1_value->NumericAtIndex_NOCAST(0, nullptr);\n    x[1] = x2_value->NumericAtIndex_NOCAST(0, nullptr);\n    y[1] = y2_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if (x[0] > x[1])\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires x1 <= x2.\" << EidosTerminate(nullptr);\n    if (y[0] > y[1])\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires y1 <= y2.\" << EidosTerminate(nullptr);\n    \n    // alpha\n    double alpha = alpha_value->FloatAtIndex_NOCAST(0, nullptr);\n    \n    if ((alpha < 0.0) || (alpha > 1.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::image): image() requires the image alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n    \n    std::vector<double> *imageAlphas = new std::vector<double>;  // we only take a singleton alpha, but the API expects a buffer\n    \n    imageAlphas->push_back(alpha);\n    \n    plotview_->addImageData(x, y, 2, image, imageAlphas);       // implicitly shares image; takes the x, y, and imageAlphas buffers from us\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)mtext(numeric x, numeric y, string labels, [string color = \"black\"], [numeric size = 10.0], [Nif adj = NULL], [float alpha = 1.0], [numeric angle = 0.0])\n//\nEidosValue_SP Plot::ExecuteMethod_mtext(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *x_value = p_arguments[0].get();\n    EidosValue *y_value = p_arguments[1].get();\n    EidosValue *labels_value = p_arguments[2].get();\n    EidosValue *color_value = p_arguments[3].get();\n    EidosValue *size_value = p_arguments[4].get();\n    EidosValue *adj_value = p_arguments[5].get();\n    EidosValue *alpha_value = p_arguments[6].get();\n    EidosValue *angle_value = p_arguments[7].get();\n    \n    // x and y\n    int xcount = x_value->Count();\n    int ycount = y_value->Count();\n    int labelscount = labels_value->Count();\n    \n    if ((xcount != ycount) || (xcount != labelscount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires x, y, and labels to be the same length.\" << EidosTerminate();\n    \n    double *x = (double *)malloc(xcount * sizeof(double));\n    double *y = (double *)malloc(ycount * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x, x_value->FloatData(), xcount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x_value->IntData();\n        \n        for (int index = 0; index < xcount; ++index)\n            x[index] = int_data[index];\n    }\n    \n    if (y_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y, y_value->FloatData(), ycount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y_value->IntData();\n        \n        for (int index = 0; index < ycount; ++index)\n            y[index] = int_data[index];\n    }\n    \n    // labels\n    std::vector<QString> *labels = new std::vector<QString>;\n    const std::string *string_data = labels_value->StringData();\n    \n    for (int index = 0; index < labelscount; ++index)\n        labels->emplace_back(QString::fromStdString(string_data[index]));\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires color to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t colorR, colorG, colorB;\n        \n        Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n        \n        colors->emplace_back(colorR, colorG, colorB, 255);\n    }\n    \n    // size\n    std::vector<double> *sizes = new std::vector<double>;\n    int size_count = size_value->Count();\n    \n    if ((size_count != 1) && (size_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires size to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < size_count; ++index)\n    {\n        double size = size_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((size <= 0.0) || (size > 1000.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires the elements of size to be in (0, 1000].\" << EidosTerminate(nullptr);\n        \n        sizes->push_back(size);\n    }\n    \n    // adj\n    double adj[2] = {0.5, 0.5};\n    \n    if (adj_value->Type() != EidosValueType::kValueNULL)\n    {\n        if (adj_value->Count() != 2)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires adj to be a numeric vector of length 2, or NULL.\" << EidosTerminate();\n        \n        adj[0] = adj_value->NumericAtIndex_NOCAST(0, nullptr);\n        adj[1] = adj_value->NumericAtIndex_NOCAST(1, nullptr);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires alpha to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    // angle\n    std::vector<double> *angles = new std::vector<double>;\n    int angle_count = angle_value->Count();\n    \n    if ((angle_count != 1) && (angle_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires angle to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < angle_count; ++index)\n    {\n        double angle = angle_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if (!std::isfinite(angle))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): mtext() requires the elements of angle to be finite.\" << EidosTerminate(nullptr);\n        \n        angles->push_back(angle);\n    }\n    \n    plotview_->addMarginTextData(x, y, labels, xcount, colors, alphas, sizes, adj, angles);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)points(numeric x, numeric y, [integer symbol = 0], [string color = \"red\"], [string border = \"black\"], [numeric lwd = 1.0], [numeric size = 1.0], [float alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *x_value = p_arguments[0].get();\n    EidosValue *y_value = p_arguments[1].get();\n    EidosValue *symbol_value = p_arguments[2].get();\n    EidosValue *color_value = p_arguments[3].get();\n    EidosValue *border_value = p_arguments[4].get();\n    EidosValue *lwd_value = p_arguments[5].get();\n    EidosValue *size_value = p_arguments[6].get();\n    EidosValue *alpha_value = p_arguments[7].get();\n    \n    // x and y\n    int xcount = x_value->Count();\n    int ycount = y_value->Count();\n    \n    if (xcount != ycount)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires x and y to be the same length.\" << EidosTerminate();\n    \n    double *x = (double *)malloc(xcount * sizeof(double));\n    double *y = (double *)malloc(ycount * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x, x_value->FloatData(), xcount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x_value->IntData();\n        \n        for (int index = 0; index < xcount; ++index)\n            x[index] = int_data[index];\n    }\n    \n    if (y_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y, y_value->FloatData(), ycount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y_value->IntData();\n        \n        for (int index = 0; index < ycount; ++index)\n            y[index] = int_data[index];\n    }\n    \n    // symbol\n    std::vector<int> *symbols = new std::vector<int>;\n    int symbol_count = symbol_value->Count();\n    \n    if ((symbol_count != 1) && (symbol_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires symbol to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < symbol_count; ++index)\n    {\n        int symbol = symbol_value->IntAtIndex_NOCAST(index, nullptr);\n        \n        if (symbol < 0)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires the elements of symbol to be >= 0.\" << EidosTerminate();\n        \n        symbols->push_back(symbol);\n    }\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires color to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t colorR, colorG, colorB;\n        \n        Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n        \n        colors->emplace_back(colorR, colorG, colorB, 255);\n    }\n    \n    // border\n    std::vector<QColor> *borders = new std::vector<QColor>;\n    int border_count = border_value->Count();\n    \n    if ((border_count != 1) && (border_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires border to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < border_count; ++index)\n    {\n        std::string border_string = border_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t borderR, borderG, borderB;\n        \n        Eidos_GetColorComponents(border_string, &borderR, &borderG, &borderB);\n        \n        borders->emplace_back(borderR, borderG, borderB, 255);\n    }\n    \n    // lwd\n    std::vector<double> *lwds = new std::vector<double>;\n    int lwd_count = lwd_value->Count();\n    \n    if ((lwd_count != 1) && (lwd_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires lwd to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < lwd_count; ++index)\n    {\n        double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((lwd < 0.0) || (lwd > 100.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires the elements of lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n        \n        lwds->push_back(lwd);\n    }\n    \n    // size\n    std::vector<double> *sizes = new std::vector<double>;\n    int size_count = size_value->Count();\n    \n    if ((size_count != 1) && (size_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires size to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < size_count; ++index)\n    {\n        double size = size_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((size <= 0.0) || (size > 1000.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires the elements of size to be in (0, 1000].\" << EidosTerminate(nullptr);\n        \n        sizes->push_back(size);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires alpha to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_points): points() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    plotview_->addPointData(x, y, xcount, symbols, colors, borders, alphas, lwds, sizes);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)rects(numeric x1, numeric y1, numeric x2, numeric y2, [string color = \"red\"], [string border = \"black\"], [numeric lwd = 1.0], [float alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n    EidosValue *x1_value = p_arguments[0].get();\n    EidosValue *y1_value = p_arguments[1].get();\n    EidosValue *x2_value = p_arguments[2].get();\n    EidosValue *y2_value = p_arguments[3].get();\n    EidosValue *color_value = p_arguments[4].get();\n    EidosValue *border_value = p_arguments[5].get();\n    EidosValue *lwd_value = p_arguments[6].get();\n    EidosValue *alpha_value = p_arguments[7].get();\n    \n    // x1, y1, x2, y2\n    int segment_count = x1_value->Count();\n    int y1count = y1_value->Count();\n    int x2count = x2_value->Count();\n    int y2count = y2_value->Count();\n    \n    if ((segment_count != y1count) || (segment_count != x2count) || (segment_count != y2count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires x1, y1, x2, and y2 to be the same length.\" << EidosTerminate();\n    \n    double *x1 = (double *)malloc(segment_count * sizeof(double));\n    double *y1 = (double *)malloc(segment_count * sizeof(double));\n    double *x2 = (double *)malloc(segment_count * sizeof(double));\n    double *y2 = (double *)malloc(segment_count * sizeof(double));\n    \n    if (!x1 || !y1 || !x2 || !y2)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x1_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x1, x1_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x1_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            x1[index] = int_data[index];\n    }\n    \n    if (y1_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y1, y1_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y1_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            y1[index] = int_data[index];\n    }\n    \n    if (x2_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x2, x2_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x2_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            x2[index] = int_data[index];\n    }\n    \n    if (y2_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y2, y2_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y2_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            y2[index] = int_data[index];\n    }\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires color to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        \n        if (color_string == \"none\")\n        {\n            // \"none\" is a special named color provided by rects() to say you don't want a frame or fill\n            colors->emplace_back(Qt::transparent);\n        }\n        else\n        {\n            uint8_t colorR, colorG, colorB;\n            \n            Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n            \n            colors->emplace_back(colorR, colorG, colorB, 255);\n        }\n    }\n    \n    // border\n    std::vector<QColor> *borders = new std::vector<QColor>;\n    int border_count = border_value->Count();\n    \n    if ((border_count != 1) && (border_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires border to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < border_count; ++index)\n    {\n        std::string border_string = border_value->StringAtIndex_NOCAST(index, nullptr);\n        \n        if (border_string == \"none\")\n        {\n            // \"none\" is a special named color provided by rects() to say you don't want a frame or fill\n            borders->emplace_back(Qt::transparent);\n        }\n        else\n        {\n            uint8_t borderR, borderG, borderB;\n            \n            Eidos_GetColorComponents(border_string, &borderR, &borderG, &borderB);\n            \n            borders->emplace_back(borderR, borderG, borderB, 255);\n        }\n    }\n    \n    // lwd\n    std::vector<double> *lwds = new std::vector<double>;\n    int lwd_count = lwd_value->Count();\n    \n    if ((lwd_count != 1) && (lwd_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires lwd to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < lwd_count; ++index)\n    {\n        double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((lwd < 0.0) || (lwd > 100.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires the elements of lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n        \n        lwds->push_back(lwd);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires alpha to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_rects): rects() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    plotview_->addRectData(x1, y1, x2, y2, segment_count, colors, borders, alphas, lwds);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)segments(numeric x1, numeric y1, numeric x2, numeric y2, [string color = \"red\"], [numeric lwd = 1.0], [float alpha = 1.0])\n//\nEidosValue_SP Plot::ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n    EidosValue *x1_value = p_arguments[0].get();\n    EidosValue *y1_value = p_arguments[1].get();\n    EidosValue *x2_value = p_arguments[2].get();\n    EidosValue *y2_value = p_arguments[3].get();\n    EidosValue *color_value = p_arguments[4].get();\n    EidosValue *lwd_value = p_arguments[5].get();\n    EidosValue *alpha_value = p_arguments[6].get();\n    \n    // x1, y1, x2, y2\n    int segment_count = x1_value->Count();\n    int y1count = y1_value->Count();\n    int x2count = x2_value->Count();\n    int y2count = y2_value->Count();\n    \n    if ((segment_count != y1count) || (segment_count != x2count) || (segment_count != y2count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires x1, y1, x2, and y2 to be the same length.\" << EidosTerminate();\n    \n    double *x1 = (double *)malloc(segment_count * sizeof(double));\n    double *y1 = (double *)malloc(segment_count * sizeof(double));\n    double *x2 = (double *)malloc(segment_count * sizeof(double));\n    double *y2 = (double *)malloc(segment_count * sizeof(double));\n    \n    if (!x1 || !y1 || !x2 || !y2)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x1_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x1, x1_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x1_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            x1[index] = int_data[index];\n    }\n    \n    if (y1_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y1, y1_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y1_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            y1[index] = int_data[index];\n    }\n    \n    if (x2_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x2, x2_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x2_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            x2[index] = int_data[index];\n    }\n    \n    if (y2_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y2, y2_value->FloatData(), segment_count * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y2_value->IntData();\n        \n        for (int index = 0; index < segment_count; ++index)\n            y2[index] = int_data[index];\n    }\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires color to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t colorR, colorG, colorB;\n        \n        Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n        \n        colors->emplace_back(colorR, colorG, colorB, 255);\n    }\n    \n    // lwd\n    std::vector<double> *lwds = new std::vector<double>;\n    int lwd_count = lwd_value->Count();\n    \n    if ((lwd_count != 1) && (lwd_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires lwd to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < lwd_count; ++index)\n    {\n        double lwd = lwd_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((lwd < 0.0) || (lwd > 100.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of lwd to be in [0, 100].\" << EidosTerminate(nullptr);\n        \n        lwds->push_back(lwd);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != segment_count))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires alpha to match the length of x1/y1/x2/y2, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_segments): segments() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    plotview_->addSegmentData(x1, y1, x2, y2, segment_count, colors, alphas, lwds);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setBorderless([numeric marginLeft = 0.0], [numeric marginTop = 0.0], [numeric marginRight = 0.0], [numeric marginBottom = 0.0])\n//\nEidosValue_SP Plot::ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n    EidosValue *marginLeft_value = p_arguments[0].get();\n    EidosValue *marginTop_value = p_arguments[1].get();\n    EidosValue *marginRight_value = p_arguments[2].get();\n    EidosValue *marginBottom_value = p_arguments[3].get();\n    \n    double marginLeft = marginLeft_value->NumericAtIndex_NOCAST(0, nullptr);\n    double marginTop = marginTop_value->NumericAtIndex_NOCAST(0, nullptr);\n    double marginRight = marginRight_value->NumericAtIndex_NOCAST(0, nullptr);\n    double marginBottom = marginBottom_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if ((marginLeft < 0.0) || (marginTop < 0.0) || (marginRight < 0.0) || (marginBottom < 0.0))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_setBorderless): setBorderless() requires all margins to be >= 0.\" << EidosTerminate(nullptr);\n    \n    plotview_->setBorderless(true, marginLeft, marginTop, marginRight, marginBottom);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)text(numeric x, numeric y, string labels, [string color = \"black\"], [numeric size = 10.0], [Nif adj = NULL], [float alpha = 1.0], [numeric angle = 0.0])\n//\nEidosValue_SP Plot::ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *x_value = p_arguments[0].get();\n    EidosValue *y_value = p_arguments[1].get();\n    EidosValue *labels_value = p_arguments[2].get();\n    EidosValue *color_value = p_arguments[3].get();\n    EidosValue *size_value = p_arguments[4].get();\n    EidosValue *adj_value = p_arguments[5].get();\n    EidosValue *alpha_value = p_arguments[6].get();\n    EidosValue *angle_value = p_arguments[7].get();\n    \n    // x and y\n    int xcount = x_value->Count();\n    int ycount = y_value->Count();\n    int labelscount = labels_value->Count();\n    \n    if ((xcount != ycount) || (xcount != labelscount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires x, y, and labels to be the same length.\" << EidosTerminate();\n    \n    double *x = (double *)malloc(xcount * sizeof(double));\n    double *y = (double *)malloc(ycount * sizeof(double));\n    \n    if (!x || !y)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n    \n    if (x_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(x, x_value->FloatData(), xcount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = x_value->IntData();\n        \n        for (int index = 0; index < xcount; ++index)\n            x[index] = int_data[index];\n    }\n    \n    if (y_value->Type() == EidosValueType::kValueFloat)\n    {\n        memcpy(y, y_value->FloatData(), ycount * sizeof(double));\n    }\n    else\n    {\n        const int64_t *int_data = y_value->IntData();\n        \n        for (int index = 0; index < ycount; ++index)\n            y[index] = int_data[index];\n    }\n    \n    // labels\n    std::vector<QString> *labels = new std::vector<QString>;\n    const std::string *string_data = labels_value->StringData();\n    \n    for (int index = 0; index < labelscount; ++index)\n        labels->emplace_back(QString::fromStdString(string_data[index]));\n    \n    // color\n    std::vector<QColor> *colors = new std::vector<QColor>;\n    int color_count = color_value->Count();\n    \n    if ((color_count != 1) && (color_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires color to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < color_count; ++index)\n    {\n        std::string color_string = color_value->StringAtIndex_NOCAST(index, nullptr);\n        uint8_t colorR, colorG, colorB;\n        \n        Eidos_GetColorComponents(color_string, &colorR, &colorG, &colorB);\n        \n        colors->emplace_back(colorR, colorG, colorB, 255);\n    }\n    \n    // size\n    std::vector<double> *sizes = new std::vector<double>;\n    int size_count = size_value->Count();\n    \n    if ((size_count != 1) && (size_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires size to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < size_count; ++index)\n    {\n        double size = size_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if ((size <= 0.0) || (size > 1000.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires the elements of size to be in (0, 1000].\" << EidosTerminate(nullptr);\n        \n        sizes->push_back(size);\n    }\n    \n    // adj\n    double adj[2] = {0.5, 0.5};\n    \n    if (adj_value->Type() != EidosValueType::kValueNULL)\n    {\n        if (adj_value->Count() != 2)\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires adj to be a numeric vector of length 2, or NULL.\" << EidosTerminate();\n        \n        adj[0] = adj_value->NumericAtIndex_NOCAST(0, nullptr);\n        adj[1] = adj_value->NumericAtIndex_NOCAST(1, nullptr);\n    }\n    \n    // alpha\n    std::vector<double> *alphas = new std::vector<double>;\n    int alpha_count = alpha_value->Count();\n    \n    if ((alpha_count != 1) && (alpha_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires alpha to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < alpha_count; ++index)\n    {\n        double alpha = alpha_value->FloatAtIndex_NOCAST(index, nullptr);\n        \n        if ((alpha < 0.0) || (alpha > 1.0))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_text): text() requires the elements of alpha to be in [0, 1].\" << EidosTerminate(nullptr);\n        \n        alphas->push_back(alpha);\n    }\n    \n    // angle\n    std::vector<double> *angles = new std::vector<double>;\n    int angle_count = angle_value->Count();\n    \n    if ((angle_count != 1) && (angle_count != xcount))\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): text() requires angle to match the length of x and y, or be singleton.\" << EidosTerminate();\n    \n    for (int index = 0; index < angle_count; ++index)\n    {\n        double angle = angle_value->NumericAtIndex_NOCAST(index, nullptr);\n        \n        if (!std::isfinite(angle))\n            EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_mtext): text() requires the elements of angle to be finite.\" << EidosTerminate(nullptr);\n        \n        angles->push_back(angle);\n    }\n    \n    plotview_->addTextData(x, y, labels, xcount, colors, alphas, sizes, adj, angles);       // takes ownership of buffers\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)write(string$ filePath)\n//\nEidosValue_SP Plot::ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *filePath_value = p_arguments[0].get();\n    \n    std::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (outfile_path.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_write): write() requires a non-empty path.\" << EidosTerminate();\n    \n    QString qpath = QString::fromStdString(outfile_path);\n    bool success = plotview_->writeToFile(qpath);\n    \n    if (!success)\n        EIDOS_TERMINATION << \"ERROR (Plot::ExecuteMethod_write): write() could not write to \" << outfile_path << \"; check the permissions of the enclosing directory.\" << EidosTerminate();\n    \n    return gStaticEidosValueVOID;\n}\n\n\n//\n//\tPlot_Class\n//\n#pragma mark -\n#pragma mark Plot_Class\n#pragma mark -\n\nEidosClass *gSLiM_Plot_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Plot_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n        \n        properties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_title, true,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n        \n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Plot_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n        \n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_abline, kEidosValueMaskVOID))\n                                  ->AddNumeric_ON(\"a\", gStaticEidosValueNULL)->AddNumeric_ON(\"b\", gStaticEidosValueNULL)\n                                  ->AddNumeric_ON(\"h\", gStaticEidosValueNULL)->AddNumeric_ON(\"v\", gStaticEidosValueNULL)\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_addLegend, kEidosValueMaskVOID))\n                                  ->AddString_OSN(\"position\", gStaticEidosValueNULL)->AddInt_OSN(\"inset\", gStaticEidosValueNULL)\n                                  ->AddNumeric_OSN(\"labelSize\", gStaticEidosValueNULL)->AddNumeric_OSN(\"lineHeight\", gStaticEidosValueNULL)\n                                  ->AddNumeric_OSN(\"graphicsWidth\", gStaticEidosValueNULL)->AddNumeric_OSN(\"exteriorMargin\", gStaticEidosValueNULL)\n                                  ->AddNumeric_OSN(\"interiorMargin\", gStaticEidosValueNULL)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_axis, kEidosValueMaskVOID))\n                                  ->AddInt_S(\"side\")->AddNumeric_ON(\"at\", gStaticEidosValueNULL)\n                                  ->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional, \"labels\", nullptr, gStaticEidosValue_LogicalT)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_image, kEidosValueMaskVOID))\n                                  ->AddObject_S(gStr_image, nullptr)->AddNumeric_S(\"x1\")->AddNumeric_S(\"y1\")->AddNumeric_S(\"x2\")->AddNumeric_S(\"y2\")\n                                  ->AddLogical_OS(\"flipped\", gStaticEidosValue_LogicalF)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendLineEntry, kEidosValueMaskVOID))\n                                  ->AddString_S(\"label\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendPointEntry, kEidosValueMaskVOID))\n                                  ->AddString_S(\"label\")->AddInt_OS(\"symbol\", gStaticEidosValue_Integer0)\n                                  ->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddString_OS(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n                                  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1)->AddNumeric_OS(\"size\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendSwatchEntry, kEidosValueMaskVOID))\n                                  ->AddString_S(\"label\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_legendTitleEntry, kEidosValueMaskVOID))\n                                  ->AddString_S(\"label\")));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_lines, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_matrix, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"matrix\")->AddNumeric_S(\"x1\")->AddNumeric_S(\"y1\")->AddNumeric_S(\"x2\")->AddNumeric_S(\"y2\")\n                                  ->AddLogical_OS(\"flipped\", gStaticEidosValue_LogicalF)->AddNumeric_ON(\"valueRange\", gStaticEidosValueNULL)\n                                  ->AddString_OSN(\"colors\", gStaticEidosValueNULL)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_mtext, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString(\"labels\")\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n                                  ->AddNumeric_O(\"size\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(10)))\n                                  ->AddNumeric_ON(\"adj\", gStaticEidosValueNULL)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)\n                                  ->AddNumeric_O(\"angle\", gStaticEidosValue_Float0)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_points, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddInt_O(\"symbol\", gStaticEidosValue_Integer0)\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddString_O(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n                                  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddNumeric_O(\"size\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_rects, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x1\")->AddNumeric(\"y1\")->AddNumeric(\"x2\")->AddNumeric(\"y2\")\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddString_O(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n                                  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_segments, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x1\")->AddNumeric(\"y1\")->AddNumeric(\"x2\")->AddNumeric(\"y2\")\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n                                  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_setBorderless, kEidosValueMaskVOID))\n                                  ->AddNumeric_OS(\"marginLeft\", gStaticEidosValue_Float0)->AddNumeric_OS(\"marginTop\", gStaticEidosValue_Float0)\n                                  ->AddNumeric_OS(\"marginRight\", gStaticEidosValue_Float0)->AddNumeric_OS(\"marginBottom\", gStaticEidosValue_Float0)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_text, kEidosValueMaskVOID))\n                                  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString(\"labels\")\n                                  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n                                  ->AddNumeric_O(\"size\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(10)))\n                                  ->AddNumeric_ON(\"adj\", gStaticEidosValueNULL)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)\n                                  ->AddNumeric_O(\"angle\", gStaticEidosValue_Float0)));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gEidosStr_write, kEidosValueMaskVOID))\n                                  ->AddString_S(gEidosStr_filePath)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiM_Plot.h",
    "content": "//\n//  QtSLiM_Plot.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/30/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIM_PLOT_H\n#define QTSLIM_PLOT_H\n\n\n#include <vector>\n#include <string>\n\n#include \"eidos_value.h\"\n#include \"slim_globals.h\"\n\nclass QtSLiMGraphView_CustomPlot;\n\n\nextern EidosClass *gSLiM_Plot_Class;\n\n\nclass Plot : public EidosDictionaryUnretained\n{\n    //\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n    \nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\npublic:\n    \n    std::string title_;                                     // the title as given to createPlot()\n\tQtSLiMGraphView_CustomPlot *plotview_;                  // We have a reference to the QtSLiMGraphView_CustomPlot that displays us\n\t\n\tPlot(const Plot&) = delete;                             // no copying\n\tPlot& operator=(const Plot&) = delete;                  // no copying\n\tPlot(void) = delete;                                    // no null construction\n    Plot(const std::string &title, QtSLiMGraphView_CustomPlot *p_plotview);\n\tvirtual ~Plot(void) override;\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n    virtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n    EidosValue_SP ExecuteMethod_abline(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_addLegend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_axis(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_image(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_matrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_mtext(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass Plot_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tPlot_Class(const Plot_Class &p_original) = delete;\t// no copy-construct\n\tPlot_Class& operator=(const Plot_Class&) = delete;\t// no copying\n\tinline Plot_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif // QTSLIM_PLOT_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiM_SLiMgui.cpp",
    "content": "//\n//  QtSLiM_SLiMgui.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/7/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"QtSLiM_SLiMgui.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMGraphView_CustomPlot.h\"\n#include \"QtSLiM_Plot.h\"\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"log_file.h\"\n\n#include <unistd.h>\n\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\n#pragma mark -\n#pragma mark SLiMGUI\n#pragma mark -\n\nSLiMgui::SLiMgui(Community &p_community, QtSLiMWindow *p_controller) :\n\tcommunity_(p_community),\n\tcontroller_(p_controller),\n\tself_symbol_(gID_slimgui, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMgui_Class)))\n{\n}\n\nSLiMgui::~SLiMgui(void)\n{\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *SLiMgui::Class(void) const\n{\n\treturn gSLiM_SLiMgui_Class;\n}\n\nvoid SLiMgui::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP SLiMgui::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t// constants\n\t\tcase gID_pid:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(getpid()));\n\t\t}\n\t\t\n\t\t// variables\n\t\t\n\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid SLiMgui::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP SLiMgui::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n        case gID_createPlot:\t\t\t\treturn ExecuteMethod_createPlot(p_method_id, p_arguments, p_interpreter);\n        case gID_logFileData:\t\t\t\treturn ExecuteMethod_logFileData(p_method_id, p_arguments, p_interpreter);\n        case gID_openDocument:\t\t\t\treturn ExecuteMethod_openDocument(p_method_id, p_arguments, p_interpreter);\n        case gID_pauseExecution:\t\t\treturn ExecuteMethod_pauseExecution(p_method_id, p_arguments, p_interpreter);\n        case gID_plotWithTitle:\t\t\t\treturn ExecuteMethod_plotWithTitle(p_method_id, p_arguments, p_interpreter);\n        default:\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (No<Plot>$)createPlot(string$ title, [Nif xrange = NULL], [Nif yrange = NULL], [string$ xlab = \"x\"], [string$ ylab = \"y\"], [Nif$ width = NULL], [Nif$ height = NULL]\n//                                                  [logical$ horizontalGrid = F], [logical$ verticalGrid = F], [logical$ fullBox = T])\n//\nEidosValue_SP SLiMgui::ExecuteMethod_createPlot(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *title_value = p_arguments[0].get();\n    EidosValue *xrange_value = p_arguments[1].get();\n    EidosValue *yrange_value = p_arguments[2].get();\n    EidosValue *xlab_value = p_arguments[3].get();\n    EidosValue *ylab_value = p_arguments[4].get();\n    EidosValue *width_value = p_arguments[5].get();\n    EidosValue *height_value = p_arguments[6].get();\n    EidosValue *horizontalGrid_value = p_arguments[7].get();\n    EidosValue *verticalGrid_value = p_arguments[8].get();\n    EidosValue *fullBox_value = p_arguments[9].get();\n    EidosValue *axisLabelSize_value = p_arguments[10].get();\n    EidosValue *tickLabelSize_value = p_arguments[11].get();\n    \n    std::string std_title = title_value->StringAtIndex_NOCAST(0, nullptr);\n    QString title = QString::fromStdString(std_title);\n    \n    if (title.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires a non-empty plot title.\" << EidosTerminate();\n    \n    double *x_range = nullptr;\n    double x_range_array[2];\n    \n    if (xrange_value->Type() != EidosValueType::kValueNULL)\n    {\n        if (xrange_value->Count() != 2)\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires xrange to be a numeric vector of length 2, or NULL.\" << EidosTerminate();\n        \n        x_range_array[0] = xrange_value->NumericAtIndex_NOCAST(0, nullptr);\n        x_range_array[1] = xrange_value->NumericAtIndex_NOCAST(1, nullptr);\n        x_range = x_range_array;\n        \n        if (x_range[0] >= x_range[1])\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires xrange[0] < xrange[1], when a range is specified (non-NULL).\" << EidosTerminate();\n    }\n    \n    double *y_range = nullptr;\n    double y_range_array[2];\n    \n    if (yrange_value->Type() != EidosValueType::kValueNULL)\n    {\n        if (yrange_value->Count() != 2)\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires yrange to be a numeric vector of length 2, or NULL.\" << EidosTerminate();\n        \n        y_range_array[0] = yrange_value->NumericAtIndex_NOCAST(0, nullptr);\n        y_range_array[1] = yrange_value->NumericAtIndex_NOCAST(1, nullptr);\n        y_range = y_range_array;\n        \n        if (y_range[0] >= y_range[1])\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires yrange[0] < yrange[1], when a range is specified (non-NULL).\" << EidosTerminate();\n    }\n    \n    QString xlab = QString::fromStdString(xlab_value->StringAtIndex_NOCAST(0, nullptr));\n    QString ylab = QString::fromStdString(ylab_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    double width = 0.0;\n    \n    if (width_value->Type() != EidosValueType::kValueNULL)\n    {\n        width = width_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(width) || (width <= 0.0))\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires width to be > 0.0, or NULL.\" << EidosTerminate();\n    }\n    \n    double height = 0.0;\n    \n    if (height_value->Type() != EidosValueType::kValueNULL)\n    {\n        height = height_value->NumericAtIndex_NOCAST(0, nullptr);\n        \n        if (!std::isfinite(height) || (height <= 0.0))\n            EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires height to be > 0.0, or NULL.\" << EidosTerminate();\n    }\n    \n    bool horizontalGrid = horizontalGrid_value->LogicalAtIndex_NOCAST(0, nullptr);\n    bool verticalGrid = verticalGrid_value->LogicalAtIndex_NOCAST(0, nullptr);\n    bool fullBox = fullBox_value->LogicalAtIndex_NOCAST(0, nullptr);\n    \n    double axisLabelSize = axisLabelSize_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if (!std::isfinite(axisLabelSize) || (axisLabelSize < 2.0) || (axisLabelSize > 30.0))\n        EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires axisLabelSize to be in [2, 30].\" << EidosTerminate();\n    \n    double tickLabelSize = tickLabelSize_value->NumericAtIndex_NOCAST(0, nullptr);\n    \n    if (!std::isfinite(tickLabelSize) || (tickLabelSize < 2.0) || (tickLabelSize > 30.0))\n        EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_createPlot): createPlot() requires tickLabelSize to be in [2, 30].\" << EidosTerminate();\n    \n    // make the plot view; note this might return an existing object\n    QtSLiMGraphView_CustomPlot *plotview = controller_->eidos_createPlot(title, x_range, y_range, xlab, ylab, width, height, horizontalGrid, verticalGrid, fullBox, axisLabelSize, tickLabelSize);\n    \n    // plotview owns its Eidos instance of class Plot, and keeps it across recycles\n    Plot *plot = plotview->eidosPlotObject();\n    \n    if (!plot)\n    {\n        plot = new Plot(std_title, plotview);\n        plotview->setEidosPlotObject(plot);\n    }\n    \n    EidosValue_SP result_SP(EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(plot, gSLiM_Plot_Class)));\n    \n    return result_SP;\n}\n\n//\t*********************\t– (Nfs)logFileData(o<LogFile>$ logFile, is$ column)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_logFileData(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    \n    EidosValue_Object *logFile_value = (EidosValue_Object *)p_arguments[0].get();\n    EidosValue *column_value = p_arguments[1].get();\n    \n    LogFile *logFile = (LogFile *)logFile_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n    \n    return controller_->eidos_logFileData(logFile, column_value);\n}\n\n//\t*********************\t– (void)openDocument(string$ path)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_openDocument(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    \n    EidosValue *filePath_value = p_arguments[0].get();\n    std::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n    QString filePath = QString::fromStdString(file_path);\n    \n    controller_->eidos_openDocument(filePath);\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)pauseExecution(void)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_pauseExecution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    \n    controller_->eidos_pauseExecution();\n    \n    return gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (No<Plot>$)plotWithTitle(string$ title)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_plotWithTitle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n    EidosValue *title_value = p_arguments[0].get();\n    \n    QString title = QString::fromStdString(title_value->StringAtIndex_NOCAST(0, nullptr));\n    \n    if (title.length() == 0)\n        EIDOS_TERMINATION << \"ERROR (SLiMgui::ExecuteMethod_plotWithTitle): plotWithTitle() requires a non-empty plot title.\" << EidosTerminate();\n    \n    QtSLiMGraphView_CustomPlot *plotview = controller_->eidos_plotWithTitle(title);\n    \n    if (plotview)\n    {\n        Plot *plot = plotview->eidosPlotObject();\n        EidosValue_SP result_SP(EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(plot, gSLiM_Plot_Class)));\n        \n        return result_SP;\n    }\n    \n    return gStaticEidosValueNULL;\n}\n\n\n//\n//\tSLiMgui_Class\n//\n#pragma mark -\n#pragma mark SLiMgui_Class\n#pragma mark -\n\nEidosClass *gSLiM_SLiMgui_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *SLiMgui_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back(static_cast<EidosPropertySignature *>((new EidosPropertySignature(gStr_pid, true,\tkEidosValueMaskInt | kEidosValueMaskSingleton))));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *SLiMgui_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n        \n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_createPlot, kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Plot_Class))->AddString_S(\"title\")\n                                  ->AddNumeric_ON(\"xrange\", gStaticEidosValueNULL)->AddNumeric_ON(\"yrange\", gStaticEidosValueNULL)\n                                  ->AddString_OS(\"xlab\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"x\")))\n                                  ->AddString_OS(\"ylab\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"y\")))\n                                  ->AddNumeric_OSN(\"width\", gStaticEidosValueNULL)->AddNumeric_OSN(\"height\", gStaticEidosValueNULL)\n                                  ->AddLogical_OS(\"horizontalGrid\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"verticalGrid\", gStaticEidosValue_LogicalF)\n                                  ->AddLogical_OS(\"fullBox\", gStaticEidosValue_LogicalT)\n                                  ->AddNumeric_OS(\"axisLabelSize\", EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(15)))\n                                  ->AddNumeric_OS(\"tickLabelSize\", EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(10)))));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_logFileData, kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString))\n                                  ->AddObject_S(\"logFile\", gSLiM_LogFile_Class)->AddIntString_S(\"column\")));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_openDocument, kEidosValueMaskVOID))->AddString_S(\"filePath\")));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_pauseExecution, kEidosValueMaskVOID))));\n        methods->emplace_back(static_cast<EidosInstanceMethodSignature *>((new EidosInstanceMethodSignature(gStr_plotWithTitle,\n                                  kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Plot_Class))->AddString_S(\"title\")));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/QtSLiM_SLiMgui.h",
    "content": "//\n//  QtSLiM_SLiMgui.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/7/2019.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef QTSLIM_SLIMGUI_H\n#define QTSLIM_SLIMGUI_H\n\n\n#include <vector>\n#include <string>\n#include <map>\n\n#include \"eidos_value.h\"\n#include \"eidos_symbol_table.h\"\n#include \"slim_globals.h\"\n\nclass QtSLiMWindow;\n\n\nextern EidosClass *gSLiM_SLiMgui_Class;\n\n\nclass SLiMgui : public EidosDictionaryUnretained\n{\n    //\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n    \nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\npublic:\n\t\n\tCommunity &community_;                      // We have a reference to our community object\n\tQtSLiMWindow *controller_;                  // We have a reference to the SLiMgui window controller for our simulation\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t// for fast setup of the symbol table\n\t\n\tSLiMgui(const SLiMgui&) = delete;\t\t\t\t\t// no copying\n\tSLiMgui& operator=(const SLiMgui&) = delete;\t\t// no copying\n\tSLiMgui(void) = delete;\t\t\t\t\t\t\t\t// no null construction\n\tSLiMgui(Community &p_community, QtSLiMWindow *p_controller);\n\tvirtual ~SLiMgui(void) override;\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; }\n\t\n\tvirtual const EidosClass *Class(void) const override;\n    virtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n    EidosValue_SP ExecuteMethod_createPlot(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_logFileData(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_openDocument(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_pauseExecution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n    EidosValue_SP ExecuteMethod_plotWithTitle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass SLiMgui_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tSLiMgui_Class(const SLiMgui_Class &p_original) = delete;\t// no copy-construct\n\tSLiMgui_Class& operator=(const SLiMgui_Class&) = delete;\t// no copying\n\tinline SLiMgui_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif // QTSLIM_SLIMGUI_H\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/buttons.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/buttons\"/>\n    <qresource prefix=\"/\">\n        <file>buttons/play_H.png</file>\n        <file>buttons/play.png</file>\n        <file>buttons/play_step_H.png</file>\n        <file>buttons/play_step.png</file>\n        <file>buttons/recycle_H.png</file>\n        <file>buttons/recycle.png</file>\n        <file>buttons/change_folder_H.png</file>\n        <file>buttons/change_folder.png</file>\n        <file>buttons/check_H.png</file>\n        <file>buttons/check.png</file>\n        <file>buttons/chrom_display_H.png</file>\n        <file>buttons/chrom_display.png</file>\n        <file>buttons/delete_H.png</file>\n        <file>buttons/delete.png</file>\n        <file>buttons/dump_output_H.png</file>\n        <file>buttons/dump_output.png</file>\n        <file>buttons/edit_submenu_H.png</file>\n        <file>buttons/edit_submenu.png</file>\n        <file>buttons/execute_script_H.png</file>\n        <file>buttons/execute_script.png</file>\n        <file>buttons/execute_selection_H.png</file>\n        <file>buttons/execute_selection.png</file>\n        <file>buttons/graph_submenu_H.png</file>\n        <file>buttons/graph_submenu.png</file>\n        <file>buttons/prettyprint_H.png</file>\n        <file>buttons/prettyprint.png</file>\n        <file>buttons/profile_H.png</file>\n        <file>buttons/profile.png</file>\n        <file>buttons/show_browser_H.png</file>\n        <file>buttons/show_browser.png</file>\n        <file>buttons/show_console_H.png</file>\n        <file>buttons/show_console.png</file>\n        <file>buttons/show_execution_H.png</file>\n        <file>buttons/show_execution.png</file>\n        <file>buttons/show_fixed_H.png</file>\n        <file>buttons/show_fixed.png</file>\n        <file>buttons/show_genomicelements_H.png</file>\n        <file>buttons/show_genomicelements.png</file>\n        <file>buttons/show_mutations_H.png</file>\n        <file>buttons/show_mutations.png</file>\n        <file>buttons/show_parse_H.png</file>\n        <file>buttons/show_parse.png</file>\n        <file>buttons/show_recombination_H.png</file>\n        <file>buttons/show_recombination.png</file>\n        <file>buttons/show_tokens_H.png</file>\n        <file>buttons/show_tokens.png</file>\n        <file>buttons/syntax_help_H.png</file>\n        <file>buttons/syntax_help.png</file>\n        <file>buttons/open_type_drawer_H.png</file>\n        <file>buttons/open_type_drawer.png</file>\n        <file>buttons/recycle_G.png</file>\n        <file>buttons/recycle_G_H.png</file>\n        <file>buttons/Qt_sex_ratio.png</file>\n        <file>buttons/Qt_cloning_rate.png</file>\n        <file>buttons/Qt_female_symbol.png</file>\n        <file>buttons/Qt_male_symbol.png</file>\n        <file>buttons/Qt_selfing_rate.png</file>\n        <file>buttons/profile_R.png</file>\n        <file>buttons/profile_R_H.png</file>\n        <file>buttons/action_H.png</file>\n        <file>buttons/action.png</file>\n        <file>buttons/jump_to_H.png</file>\n        <file>buttons/jump_to.png</file>\n        <file>buttons/debug_H.png</file>\n        <file>buttons/debug.png</file>\n        <file>buttons/debug_RED.png</file>\n        <file>buttons/clear_debug_H.png</file>\n        <file>buttons/clear_debug.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "QtSLiM/buttons_DARK.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/buttons_DARK\"/>\n    <qresource prefix=\"/\">\n        <file>buttons_DARK/play_H_DARK.png</file>\n        <file>buttons_DARK/play_DARK.png</file>\n        <file>buttons_DARK/play_step_H_DARK.png</file>\n        <file>buttons_DARK/play_step_DARK.png</file>\n        <file>buttons_DARK/recycle_H_DARK.png</file>\n        <file>buttons_DARK/recycle_DARK.png</file>\n        <file>buttons_DARK/change_folder_H_DARK.png</file>\n        <file>buttons_DARK/change_folder_DARK.png</file>\n        <file>buttons_DARK/check_H_DARK.png</file>\n        <file>buttons_DARK/check_DARK.png</file>\n        <file>buttons_DARK/chrom_display_H_DARK.png</file>\n        <file>buttons_DARK/chrom_display_DARK.png</file>\n        <file>buttons_DARK/delete_H_DARK.png</file>\n        <file>buttons_DARK/delete_DARK.png</file>\n        <file>buttons_DARK/dump_output_H_DARK.png</file>\n        <file>buttons_DARK/dump_output_DARK.png</file>\n        <file>buttons_DARK/edit_submenu_H_DARK.png</file>\n        <file>buttons_DARK/edit_submenu_DARK.png</file>\n        <file>buttons_DARK/execute_script_H_DARK.png</file>\n        <file>buttons_DARK/execute_script_DARK.png</file>\n        <file>buttons_DARK/execute_selection_H_DARK.png</file>\n        <file>buttons_DARK/execute_selection_DARK.png</file>\n        <file>buttons_DARK/graph_submenu_H_DARK.png</file>\n        <file>buttons_DARK/graph_submenu_DARK.png</file>\n        <file>buttons_DARK/prettyprint_H_DARK.png</file>\n        <file>buttons_DARK/prettyprint_DARK.png</file>\n        <file>buttons_DARK/profile_H_DARK.png</file>\n        <file>buttons_DARK/profile_DARK.png</file>\n        <file>buttons_DARK/show_browser_H_DARK.png</file>\n        <file>buttons_DARK/show_browser_DARK.png</file>\n        <file>buttons_DARK/show_console_H_DARK.png</file>\n        <file>buttons_DARK/show_console_DARK.png</file>\n        <file>buttons_DARK/show_execution_H_DARK.png</file>\n        <file>buttons_DARK/show_execution_DARK.png</file>\n        <file>buttons_DARK/show_fixed_H_DARK.png</file>\n        <file>buttons_DARK/show_fixed_DARK.png</file>\n        <file>buttons_DARK/show_genomicelements_H_DARK.png</file>\n        <file>buttons_DARK/show_genomicelements_DARK.png</file>\n        <file>buttons_DARK/show_mutations_H_DARK.png</file>\n        <file>buttons_DARK/show_mutations_DARK.png</file>\n        <file>buttons_DARK/show_parse_H_DARK.png</file>\n        <file>buttons_DARK/show_parse_DARK.png</file>\n        <file>buttons_DARK/show_recombination_H_DARK.png</file>\n        <file>buttons_DARK/show_recombination_DARK.png</file>\n        <file>buttons_DARK/show_tokens_H_DARK.png</file>\n        <file>buttons_DARK/show_tokens_DARK.png</file>\n        <file>buttons_DARK/syntax_help_H_DARK.png</file>\n        <file>buttons_DARK/syntax_help_DARK.png</file>\n        <file>buttons_DARK/open_type_drawer_H_DARK.png</file>\n        <file>buttons_DARK/open_type_drawer_DARK.png</file>\n        <file>buttons_DARK/recycle_G_DARK.png</file>\n        <file>buttons_DARK/recycle_G_H_DARK.png</file>\n        <file>buttons_DARK/Qt_sex_ratio_DARK.png</file>\n        <file>buttons_DARK/Qt_cloning_rate_DARK.png</file>\n        <file>buttons_DARK/Qt_female_symbol_DARK.png</file>\n        <file>buttons_DARK/Qt_male_symbol_DARK.png</file>\n        <file>buttons_DARK/Qt_selfing_rate_DARK.png</file>\n        <file>buttons_DARK/profile_R_DARK.png</file>\n        <file>buttons_DARK/profile_R_H_DARK.png</file>\n        <file>buttons_DARK/action_H_DARK.png</file>\n        <file>buttons_DARK/action_DARK.png</file>\n        <file>buttons_DARK/jump_to_H_DARK.png</file>\n        <file>buttons_DARK/jump_to_DARK.png</file>\n        <file>buttons_DARK/debug_DARK.png</file>\n        <file>buttons_DARK/debug_H_DARK.png</file>\n        <file>buttons_DARK/clear_debug_DARK.png</file>\n        <file>buttons_DARK/clear_debug_H_DARK.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "QtSLiM/help/EidosHelpClasses.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"2299.77\">\n  <style type=\"text/css\">\n    p.p1 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima; color: #000000}\n    p.p2 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima; color: #000000}\n    p.p3 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo; color: #000000}\n    p.p4 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #000000}\n    p.p5 {margin: 9.0px 0.0px 9.0px 45.4px; font: 9.0px Menlo; color: #000000}\n    span.s1 {font: 9.0px Menlo}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><b>5.1<span class=\"Apple-converted-space\">  </span>Class Object</b></p>\n<p class=\"p2\"><i>5.1.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Object</i></span><i> properties</i></p>\n<p class=\"p2\"><i>5.1.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Object</i></span><i> methods</i></p>\n<p class=\"p3\">+ (integer$)length(void)</p>\n<p class=\"p4\">Returns the size (e.g., length) of the receiving object.<span class=\"Apple-converted-space\">  </span>This is equivalent to the <span class=\"s1\">length()</span> (or <span class=\"s1\">size()</span>) function; in other words, for any <span class=\"s1\">object</span> <span class=\"s1\">x</span>, the return value of the function call <span class=\"s1\">length(x)</span> equals the return value of the class method call <span class=\"s1\">x.length()</span>.<span class=\"Apple-converted-space\">  </span>This method is provided solely for syntactic convenience.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s1\">+length()</span> is a synonym for <span class=\"s1\">+size()</span>.</p>\n<p class=\"p3\">+ (void)methodSignature([Ns$ methodName = NULL])</p>\n<p class=\"p4\">Prints the method signature for the method specified by <span class=\"s1\">methodName</span>, or for all methods supported by the receiving object if <span class=\"s1\">methodName</span> is <span class=\"s1\">NULL</span> (the default).</p>\n<p class=\"p3\">+ (void)propertySignature([Ns$ propertyName = NULL])</p>\n<p class=\"p4\">Prints the property signature for the property specified by <span class=\"s1\">propertyName</span>, or for all properties supported by the receiving object if <span class=\"s1\">propertyName</span> is <span class=\"s1\">NULL</span> (the default).</p>\n<p class=\"p3\">+ (integer$)size(void)</p>\n<p class=\"p4\">Returns the size of the receiving object.<span class=\"Apple-converted-space\">  </span>This is equivalent to the <span class=\"s1\">size()</span> (or <span class=\"s1\">length()</span>) function; in other words, for any <span class=\"s1\">object</span> <span class=\"s1\">x</span>, the return value of the function call <span class=\"s1\">size(x)</span> equals the return value of the class method call <span class=\"s1\">x.size()</span>.<span class=\"Apple-converted-space\">  </span>This method is provided solely for syntactic convenience.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s1\">+length()</span> is a synonym for <span class=\"s1\">+size()</span>.</p>\n<p class=\"p3\">– (void)str(void)</p>\n<p class=\"p4\">Prints the internal property structure of the receiving object; in particular, the element type of the object is printed, followed, on successive lines, by all of the properties supported by the object, their types, and a sample of their values.</p>\n<p class=\"p3\">– (string$)stringRepresentation(void)</p>\n<p class=\"p4\">Returns a singleton <span class=\"s1\">string</span> value that represents the receiving object.<span class=\"Apple-converted-space\">  </span>By default, this is simply the name of the class of the receiving object; however, many subclasses of <span class=\"s1\">Object</span> provide a different string representation.<span class=\"Apple-converted-space\">  </span>The value returned by <span class=\"s1\">stringRepresentation()</span> is the same string that would be printed by <span class=\"s1\">print()</span> for the object, so <span class=\"s1\">stringRepresentation()</span> allows the same representation to be used in other contexts such as <span class=\"s1\">paste()</span> and <span class=\"s1\">cat()</span>.</p>\n<p class=\"p1\"><b>5.2<span class=\"Apple-converted-space\">  </span>Class DataFrame</b></p>\n<p class=\"p3\">(object&lt;DataFrame&gt;$)DataFrame(...)</p>\n<p class=\"p4\">The <span class=\"s1\">DataFrame</span> constructor can be called in the same ways as the constructor for <span class=\"s1\">Dictionary</span> (its superclass): with no parameters to make an empty <span class=\"s1\">DataFrame</span>, with key-value pairs, with a singleton <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>, like <span class=\"s1\">DataFrame</span>) to make a copy, or with a string in JSON format.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">Dictionary</span> class for further documentation.<span class=\"Apple-converted-space\">  </span>However, note that <span class=\"s1\">DataFrame</span> can only use <span class=\"s1\">string</span> keys; <span class=\"s1\">integer</span> keys are not allowed.</p>\n<p class=\"p2\"><i>5.2.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>DataFrame</i></span><i> properties</i></p>\n<p class=\"p3\">colNames =&gt; (string)</p>\n<p class=\"p4\">A vector containing all of the <span class=\"s1\">string</span> column names in the <span class=\"s1\">DataFrame</span>, in order.<span class=\"Apple-converted-space\">  </span>This property is currently an alias for the <span class=\"s1\">Dictionary</span> property <span class=\"s1\">allKeys</span>.</p>\n<p class=\"p3\">dim =&gt; (integer)</p>\n<p class=\"p4\">A two-element vector containing the dimensions of the <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">0</span>th element is the number of rows (as provided by <span class=\"s1\">nrow</span>), and the <span class=\"s1\">1</span>st element is the number of columns (as provided by <span class=\"s1\">ncol</span>).</p>\n<p class=\"p3\">ncol =&gt; (integer$)</p>\n<p class=\"p4\">The number of columns in the <span class=\"s1\">DataFrame</span>; this will be equal to the length of <span class=\"s1\">colNames</span>.</p>\n<p class=\"p3\">nrow =&gt; (integer$)</p>\n<p class=\"p4\">The number of rows in the <span class=\"s1\">DataFrame</span> (i.e., the number of elements in a column).<span class=\"Apple-converted-space\">  </span>This will be the same for every column, by definition.</p>\n<p class=\"p2\"><i>5.2.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>DataFrame</i></span><i> methods</i></p>\n<p class=\"p3\">– (*)asMatrix(void)</p>\n<p class=\"p4\">Returns a matrix representation of the <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The matrix will have the same type as the elements of the <span class=\"s1\">DataFrame</span>; if the <span class=\"s1\">DataFrame</span> contains more than one type of element, an error will be raised.<span class=\"Apple-converted-space\">  </span>The order of the columns of the <span class=\"s1\">DataFrame</span> will be preserved.<span class=\"Apple-converted-space\">  </span>This method is useful, for example, if you wish to read in a text file as a matrix; you can use <span class=\"s1\">readCSV()</span> to read the file as a <span class=\"s1\">DataFrame</span>, and then convert it to a matrix with <span class=\"s1\">asMatrix()</span>.</p>\n<p class=\"p3\">– (void)cbind(object&lt;Dictionary&gt; source, ...)</p>\n<p class=\"p4\">Adds all of the columns contained by <span class=\"s1\">source</span> (which must be a <span class=\"s1\">Dictionary</span> or a subclass of <span class=\"s1\">Dictionary</span> such as <span class=\"s1\">DataFrame</span>) to the receiver.<span class=\"Apple-converted-space\">  </span>This method makes the target <span class=\"s1\">DataFrame</span> wider, by adding new columns.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">source</span> contains a column name that is already defined in the target, an error will result.<span class=\"Apple-converted-space\">  </span>As always for <span class=\"s1\">DataFrame</span>, the columns of the resulting <span class=\"s1\">DataFrame</span> must all be the same length.</p>\n<p class=\"p4\">The <span class=\"s1\">source</span> parameter may be a non-singleton vector containing multiple <span class=\"s1\">Dictionary</span> objects, and additional <span class=\"s1\">Dictionary</span> vectors may be supplied (thus the ellipsis in the signature).<span class=\"Apple-converted-space\">  </span>Each <span class=\"s1\">Dictionary</span> supplied will be added to the target, in the order supplied.</p>\n<p class=\"p4\">This method is similar to the <span class=\"s1\">Dictionary</span> method <span class=\"s1\">addKeysAndValuesFrom()</span>, which may be used instead if replacement of duplicate columns is desired.</p>\n<p class=\"p3\">– (void)rbind(object&lt;Dictionary&gt; source, ...)</p>\n<p class=\"p4\">Appends all of the columns contained by <span class=\"s1\">source</span> (which must be a <span class=\"s1\">Dictionary</span> or a subclass of <span class=\"s1\">Dictionary</span> such as <span class=\"s1\">DataFrame</span>) to the receiver.<span class=\"Apple-converted-space\">  </span>This method makes the <span class=\"s1\">DataFrame</span> taller, by adding new rows.<span class=\"Apple-converted-space\">  </span>If the source and target do not contain the same column names in the same order, an error will result.<span class=\"Apple-converted-space\">  </span>As always for <span class=\"s1\">DataFrame</span>, the columns of the resulting <span class=\"s1\">DataFrame</span> must all be the same length.</p>\n<p class=\"p4\">The <span class=\"s1\">source</span> parameter may be a non-singleton vector containing multiple <span class=\"s1\">Dictionary</span> objects, and additional <span class=\"s1\">Dictionary</span> vectors may be supplied (thus the ellipsis in the signature).<span class=\"Apple-converted-space\">  </span>Each <span class=\"s1\">Dictionary</span> supplied will be appended to the target, in the order supplied.</p>\n<p class=\"p4\">This method is similar to the <span class=\"s1\">Dictionary</span> method <span class=\"s1\">appendKeysAndValuesFrom()</span>, which may be used instead if one wishes the append to work even when the columns are in different orders, or other such situations.</p>\n<p class=\"p3\">– (*)subset([Nli rows = NULL], [Nlis cols = NULL])</p>\n<p class=\"p4\">Returns the elements in the selected rows and columns of the target <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The selection logic is based upon that for <span class=\"s1\">subsetRows()</span> and <span class=\"s1\">subsetColumns()</span>, respectively; in short, rows may be selected by <span class=\"s1\">integer</span> indices or by a <span class=\"s1\">logical</span> vector, and columns may be selected by <span class=\"s1\">integer</span> indices, by a <span class=\"s1\">logical</span> vector, or by a <span class=\"s1\">string</span> vector of column names.<span class=\"Apple-converted-space\">  </span>In addition, however, <span class=\"s1\">NULL</span> may be passed for either <span class=\"s1\">rows</span> or <span class=\"s1\">cols</span> to select all of the rows or all of the columns, respectively; this is the default for both parameters.<span class=\"Apple-converted-space\">  </span>If you want entire rows (rather than selecting particular columns), pass <span class=\"s1\">NULL</span> for <span class=\"s1\">cols</span>; if you want entire columns (rather than selecting particular rows), pass <span class=\"s1\">NULL</span> for <span class=\"s1\">rows</span>.</p>\n<p class=\"p4\">The first step performed by <span class=\"s1\">subset()</span> is to produce a <span class=\"s1\">DataFrame</span> that contains the selected rows and columns.<span class=\"Apple-converted-space\">  </span>If that <span class=\"s1\">DataFrame</span> contains more than one column, it is simply returned, and the behavior of <span class=\"s1\">subset()</span> is identical to calling <span class=\"s1\">subsetRows()</span> and <span class=\"s1\">subsetColumns()</span> in sequence (in either order).<span class=\"Apple-converted-space\">  </span>If, however, the resulting <span class=\"s1\">DataFrame</span> contains only a single column, then <span class=\"s1\">subset()</span> will return a vector containing the elements in that column – unlike the behavior of <span class=\"s1\">subsetRows()</span> and <span class=\"s1\">subsetColumns()</span>, which always return a <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>This method is therefore a convenient way to get a single value, or multiple values from the same column, from a <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>(Note that the <span class=\"s1\">Dictionary</span> method <span class=\"s1\">getValue()</span> can also be used to get all of the values from a given <span class=\"s1\">DataFrame</span> column.)</p>\n<p class=\"p3\">– (object&lt;DataFrame&gt;$)subsetColumns(lis index)</p>\n<p class=\"p4\">Returns a new <span class=\"s1\">DataFrame</span> containing values for the selected columns of the target <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The selection logic described below is similar to how the subset operator <span class=\"s1\">[]</span> in Eidos works, selecting the columns of the target <span class=\"s1\">DataFrame</span>.</p>\n<p class=\"p4\">The index parameter may be either <span class=\"s1\">integer</span>, <span class=\"s1\">logical</span>, or <span class=\"s1\">string</span>; we will discuss the <span class=\"s1\">integer</span> case first.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a singleton <span class=\"s1\">integer</span>, the returned <span class=\"s1\">DataFrame</span> will contain the <span class=\"s1\">index</span>’th column of the target (counting from the left, from <span class=\"s1\">0</span>).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a non-singleton <span class=\"s1\">integer</span> vector, the returned <span class=\"s1\">DataFrame</span> will contains all of the selected columns, in the order that they are selected by <span class=\"s1\">index</span>.<span class=\"Apple-converted-space\">  </span>If any <span class=\"s1\">index</span> value is out of range for the target <span class=\"s1\">DataFrame</span> (such that the <span class=\"s1\">DataFrame</span> does not have an <span class=\"s1\">index</span>’th column), an error will result.<span class=\"Apple-converted-space\">  </span>If the same column is specified more than once, unique column names will be automatically generated for the additional copies of the column.</p>\n<p class=\"p4\">If <span class=\"s1\">index</span> is a <span class=\"s1\">string</span> vector, the returned <span class=\"s1\">DataFrame</span> will contain copies of the columns in the target named by <span class=\"s1\">index</span>.<span class=\"Apple-converted-space\">  </span>As with an <span class=\"s1\">integer</span> vector, it is an error if a given column does not exist in the target; and unique column names will be generated for additional copies of a column.</p>\n<p class=\"p4\">Finally, if <span class=\"s1\">index</span> is a <span class=\"s1\">logical</span> vector, the length of <span class=\"s1\">index</span> must be equal to the number of columns in the target.<span class=\"Apple-converted-space\">  </span>In this case, the <span class=\"s1\">T</span> values in <span class=\"s1\">index</span> select the columns which will be included in the returned <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The columns in the returned <span class=\"s1\">DataFrame</span> will be in the same order as in the target.</p>\n<p class=\"p3\">– (object&lt;DataFrame&gt;$)subsetRows(li index, [logical$ drop = F])</p>\n<p class=\"p4\">Returns a new <span class=\"s1\">DataFrame</span> containing values for selected rows of the target <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The selection logic described below works exactly as the subset operator <span class=\"s1\">[]</span> does in Eidos, selecting the rows of the target <span class=\"s1\">DataFrame</span>.</p>\n<p class=\"p4\">The <span class=\"s1\">index</span> parameter may be either <span class=\"s1\">integer</span> or <span class=\"s1\">logical</span>; we will discuss the <span class=\"s1\">integer</span> case first.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a singleton <span class=\"s1\">integer</span>, the returned <span class=\"s1\">DataFrame</span> will contain the <span class=\"s1\">index</span>’th element of the value of each key of the target, under the same keys; this is a single row of the target <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a non-singleton <span class=\"s1\">integer</span> vector, the returned <span class=\"s1\">DataFrame</span> will contain the values for all of the selected rows, in the order that they are selected by <span class=\"s1\">index</span>.<span class=\"Apple-converted-space\">  </span>If any index value in <span class=\"s1\">index</span> is out of range for the target <span class=\"s1\">DataFrame</span> (such that that DataFrame does not have an <span class=\"s1\">index</span>’th row), an error will result.</p>\n<p class=\"p4\">If <span class=\"s1\">index</span> is <span class=\"s1\">logical</span>, the length of <span class=\"s1\">index</span> must be equal to the number of rows in the target.<span class=\"Apple-converted-space\">  </span>In this case, the <span class=\"s1\">T</span> values in <span class=\"s1\">index</span> select the rows which will be included in the returned <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>The values of each column in the returned <span class=\"s1\">DataFrame</span> will be in the same order as in the target.</p>\n<p class=\"p4\">If the values of <span class=\"s1\">index</span> are such that <i>no</i> value for a given key is selected, the <span class=\"s1\">drop</span> parameter controls the resulting behavior.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">drop</span> is <span class=\"s1\">F</span> (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as <span class=\"s1\">integer(0)</span> or <span class=\"s1\">string(0)</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">drop</span> is <span class=\"s1\">T</span>, the key will be omitted from the returned dictionary.</p>\n<p class=\"p1\"><b>5.3<span class=\"Apple-converted-space\">  </span>Class Dictionary</b></p>\n<p class=\"p3\">(object&lt;Dictionary&gt;$)Dictionary(...)</p>\n<p class=\"p4\">Creates a new <span class=\"s1\">Dictionary</span> object.<span class=\"Apple-converted-space\">  </span>Called without arguments, as <span class=\"s1\">Dictionary()</span>, this creates a new empty <span class=\"s1\">Dictionary</span>.</p>\n<p class=\"p4\">Alternatively, key-value pairs can be passed to set up the initial state of the new <span class=\"s1\">Dictionary</span>.<span class=\"Apple-converted-space\">  </span>These are set, sequentially, on the new <span class=\"s1\">Dictionary</span>, just as <span class=\"s1\">setValue()</span> would do.<span class=\"Apple-converted-space\">  </span>For example, calling <span class=\"s1\">Dictionary(\"a\", 0:3, \"b\", c(\"foo\", \"bar\"))</span> is equivalent to calling <span class=\"s1\">Dictionary()</span> and then calling <span class=\"s1\">setValue(\"a\", 0:3)</span> and then <span class=\"s1\">setValue(\"b\", c(\"foo\", \"bar\"))</span> on it; it is just a shorthand for convenience.<span class=\"Apple-converted-space\">  </span>Keys may be of type <span class=\"s1\">string</span> or <span class=\"s1\">integer</span>, but must all be of the same type; <span class=\"s1\">Dictionary</span> supports using either <span class=\"s1\">string</span> or <span class=\"s1\">integer</span> keys, but they cannot be mixed in a single <span class=\"s1\">Dictionary</span> object.</p>\n<p class=\"p4\">Another alternative is to call <span class=\"s1\">Dictionary()</span> with a singleton <span class=\"s1\">Dictionary</span> as its only argument; this creates a new <span class=\"s1\">Dictionary</span> that is a copy of the <span class=\"s1\">Dictionary</span> passed, containing the same keys and values.<span class=\"Apple-converted-space\">  </span>This is equivalent to creating a new empty <span class=\"s1\">Dictionary</span> and then calling <span class=\"s1\">addKeysAndValuesFrom()</span> to copy key-value pairs over; it is just a shorthand for convenience.</p>\n<p class=\"p4\">A final alternative is to call <span class=\"s1\">Dictionary()</span> with a <span class=\"s1\">string</span> vector as its only argument; this creates a new <span class=\"s1\">Dictionary</span> from the string, assuming that it is a data archive in JSON format.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">string</span> value is not a singleton, its elements will be joined together by newlines to make a singleton <span class=\"s1\">string</span> value; this allows the result from <span class=\"s1\">readFile()</span> to be passed directly to <span class=\"s1\">Dictionary()</span> even for a multiline (prettyprinted) JSON file.<span class=\"Apple-converted-space\">  </span>Note that a JSON string can be generated from the <span class=\"s1\">serialize()</span> method of <span class=\"s1\">Dictionary</span>; together with this way of creating a <span class=\"s1\">Dictionary</span>, this provides the ability to persist arbitrary information to a string (perhaps a file on disk) and back again.<span class=\"Apple-converted-space\">  </span>The recreated <span class=\"s1\">Dictionary</span> should be identical to the original, except that zero length vectors such as <span class=\"s1\">integer(0)</span>, <span class=\"s1\">float(0)</span>, <span class=\"s1\">logical(0)</span>, and <span class=\"s1\">string(0)</span> will all be serialized as <span class=\"s1\">\"[]\"</span> and recreated as <span class=\"s1\">integer(0)</span> since JSON does not provide a way to specify the type of a zero-length array.</p>\n<p class=\"p2\"><i>5.3.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Dictionary</i></span><i> properties</i></p>\n<p class=\"p3\">allKeys =&gt; (is)</p>\n<p class=\"p4\">A vector containing all of the <span class=\"s1\">string</span> or <span class=\"s1\">integer</span> keys that have been assigned values using <span class=\"s1\">setValue()</span>, in sorted (ascending alphabetic or numeric) order.</p>\n<p class=\"p2\"><i>5.3.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Dictionary</i></span><i> methods</i></p>\n<p class=\"p3\">– (void)addKeysAndValuesFrom(object&lt;Dictionary&gt;$ source)</p>\n<p class=\"p4\">Adds all of the key-value pairs contained by <span class=\"s1\">source</span> (which must be a <span class=\"s1\">Dictionary</span> or a subclass of <span class=\"s1\">Dictionary</span>) to the receiver.<span class=\"Apple-converted-space\">  </span>If the target already contains a key that is defined in <span class=\"s1\">source</span>, the target’s value for that key will be <i>replaced</i> by the value in <span class=\"s1\">source</span> (contrast this with <span class=\"s1\">appendKeysAndValuesFrom()</span>).</p>\n<p class=\"p3\">– (void)appendKeysAndValuesFrom(object&lt;Dictionary&gt; source)</p>\n<p class=\"p4\">Appends all of the key-value pairs contained by <span class=\"s1\">source</span> (which must be a <span class=\"s1\">Dictionary</span> or a subclass of <span class=\"s1\">Dictionary</span>) to the receiver.<span class=\"Apple-converted-space\">  </span>If the target already contains a key that is defined in source, the value from source will be <i>appended</i> to the target’s existing value, which must be of the same type (contrast this with <span class=\"s1\">addKeysAndValuesFrom()</span>); if the target does not already contain a key that is defined in source, that key-value pair will simply be added to the target.</p>\n<p class=\"p4\">In the current implementation, it is an error for either of the values involved in an append to be a matrix or array; values in these <span class=\"s1\">Dictionary</span> objects should be simple vectors.<span class=\"Apple-converted-space\">  </span>This limitation preserves the future option to expand this method’s functionality to do smart things with matrices and arrays.</p>\n<p class=\"p3\">– (void)clearKeysAndValues(void)</p>\n<p class=\"p4\">Removes all key-value pairs from the receiver.</p>\n<p class=\"p3\">– (integer)compactIndices([logical$ preserveOrder = F])</p>\n<p class=\"p4\">Compacts the receiver, which must use <span class=\"s1\">integer</span> keys.<span class=\"Apple-converted-space\">  </span>After this operation, the receiver will contain only values that have a length greater than zero (discarding all key–value pairs for which the value is a zero-length vector).<span class=\"Apple-converted-space\">  </span>In addition, the keys used will be compacted down to begin at <span class=\"s1\">0</span> and count upward sequentially.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">preserveOrder</span> is <span class=\"s1\">F</span> (the default), the keys may end up in a different numerical order; this allows the compaction to be performed more efficiently.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">preserveOrder</span> is <span class=\"s1\">T</span>, on the other hand, the numerical order of the keys will be preserved.<span class=\"Apple-converted-space\">  </span>The returned <span class=\"s1\">integer</span> vector contains the original keys that were kept across the compaction operation, in the order in which they were used in the compaction; keys that were not kept (because their value was zero-length) are omitted from this result vector.</p>\n<p class=\"p4\">For example, with a dictionary that contains key–value pairs <span class=\"s1\">-5=\"a\"</span>, <span class=\"s1\">17=\"b\"</span>, <span class=\"s1\">37=\"c\"</span>, <span class=\"s1\">53=integer(0)</span>, and <span class=\"s1\">82=\"d\"</span>, <span class=\"s1\">compactIndices(preserveOrder=T)</span> will transform the dictionary to contain <span class=\"s1\">0=\"a\"</span>, <span class=\"s1\">1=\"b\"</span>, <span class=\"s1\">2=\"c\"</span>, and <span class=\"s1\">3=\"d\"</span>, while key <span class=\"s1\">53</span> (and its zero-length value) is dropped; the returned vector will be (<span class=\"s1\">5</span>, <span class=\"s1\">17</span>, <span class=\"s1\">37</span>, <span class=\"s1\">82</span>).<span class=\"Apple-converted-space\">  </span>The result from <span class=\"s1\">compactIndices(preserveOrder=F)</span> has a non-deterministic order, but one possibility for the same example inout is that it would transform the dictionary to contain key–value pairs <span class=\"s1\">0=\"c\"</span>, <span class=\"s1\">1=\"d\"</span>, <span class=\"s1\">2=\"a\"</span>, and <span class=\"s1\">3=\"b\"</span>, with a returned vector of (<span class=\"s1\">37</span>, <span class=\"s1\">82</span>, <span class=\"s1\">5</span>, <span class=\"s1\">17</span>); the same key–value pairs are kept, and they are again placed in sequential keys beginning with <span class=\"s1\">0</span>, but their order is no longer preserved across the compaction.</p>\n<p class=\"p4\">This method is particularly useful when you have a <span class=\"s1\">Dictionary</span> <span class=\"s1\">d</span> that contains results from some operation on a vector <span class=\"s1\">x</span>, such that each key <span class=\"s1\">n</span> in <span class=\"s1\">d</span> has a value that is the result of processing the <span class=\"s1\">n</span>’th element of <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>In this case, <span class=\"s1\">order=d.compactIndices(preserveOrder=F)</span> will transmogrify <span class=\"s1\">d</span> to contain only the non-zero-length results, in sequential indices counting from <span class=\"s1\">0</span>, and <span class=\"s1\">x[order]</span> provides the elements of <span class=\"s1\">x</span> that produced those results, in the same order as in <span class=\"s1\">d</span> after compaction.<span class=\"Apple-converted-space\">  </span>Using <span class=\"s1\">preserveOrder=T</span> additionally keeps <span class=\"s1\">d</span> in the same order as the original order of <span class=\"s1\">x</span>, for cases in which that ordering is important.</p>\n<p class=\"p3\">– (object&lt;Dictionary&gt;$)getRowValues(li index, [logical$ drop = F])</p>\n<p class=\"p4\">Returns a new <span class=\"s1\">Dictionary</span> containing values for selected “rows” of the target <span class=\"s1\">Dictionary</span>, allowing <span class=\"s1\">Dictionary</span> to act similarly to a <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">subsetRows()</span> method of class <span class=\"s1\">DataFrame</span> for comparison; the main utility of <span class=\"s1\">getRowValues()</span> is that it can be used on a <span class=\"s1\">Dictionary</span> that has ragged “rows”.<span class=\"Apple-converted-space\">  </span>The selection logic described below works similarly to the subset operator <span class=\"s1\">[]</span> in Eidos, selecting the “rows” of the target <span class=\"s1\">Dictionary</span>.</p>\n<p class=\"p4\">The <span class=\"s1\">index</span> parameter may be either <span class=\"s1\">integer</span> or <span class=\"s1\">logical</span>; we will discuss the <span class=\"s1\">integer</span> case first.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a singleton <span class=\"s1\">integer</span>, the returned <span class=\"s1\">Dictionary</span> will contain the <span class=\"s1\">index</span>’th element of the value of each key of the target, under the same keys; this is a single “row” of the target <span class=\"s1\">Dictionary</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">index</span> is a non-singleton <span class=\"s1\">integer</span> vector, the returned <span class=\"s1\">Dictionary</span> will contain the values for all of the selected rows, in the order that they are selected by <span class=\"s1\">index</span>.<span class=\"Apple-converted-space\">  </span>If any index value in <span class=\"s1\">index</span> is out of range for any key of the target <span class=\"s1\">Dictionary</span> (such that that key does not have an <span class=\"s1\">index</span>’th value), the returned dictionary will simply not have a value for that “row” of that key.</p>\n<p class=\"p4\">If <span class=\"s1\">index</span> is <span class=\"s1\">logical</span>, the <span class=\"s1\">T</span> values in <span class=\"s1\">index</span> select the “rows” which will be included in the returned <span class=\"s1\">Dictionary</span>.<span class=\"Apple-converted-space\">  </span>The values within each column in the returned <span class=\"s1\">Dictionary</span> will be in the same order as in the target.<span class=\"Apple-converted-space\">  </span>The length of <span class=\"s1\">index</span> need not match any column of the <span class=\"s1\">Dictionary</span>; excess “rows” beyond the length of <span class=\"s1\">index</span> will not be selected, and excess values in <span class=\"s1\">index</span> beyond the end of the longest “column” will have no effect.</p>\n<p class=\"p4\">If the values of <span class=\"s1\">index</span> are such that <i>no</i> value for a given key is selected, the <span class=\"s1\">drop</span> parameter controls the resulting behavior.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">drop</span> is <span class=\"s1\">F</span> (the default), the key will be included in the returned dictionary with a zero-length value of matching type, such as <span class=\"s1\">integer(0)</span> or <span class=\"s1\">string(0)</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">drop</span> is <span class=\"s1\">T</span>, the key will be omitted from the returned dictionary.</p>\n<p class=\"p3\">– (*)getValue(is$ key)</p>\n<p class=\"p4\">Returns the value previously set for the dictionary entry identifier <span class=\"s1\">key</span> using <span class=\"s1\">setValue()</span>, or <span class=\"s1\">NULL</span> if no value has been set.</p>\n<p class=\"p3\">– (logical$)identicalContents(object&lt;Dictionary&gt;$ x)</p>\n<p class=\"p4\">Returns <span class=\"s1\">T</span> if the target <span class=\"s1\">Dictionary</span> is equal to <span class=\"s1\">x</span> in all respects – containing the same keys, with values that are identical in the sense defined by the <span class=\"s1\">identical()</span> function in Eidos – or returns <span class=\"s1\">F</span> otherwise.</p>\n<p class=\"p4\">Note that if <span class=\"s1\">Dictionary</span> objects are contained, as values, by the dictionaries being tested for equality, they will be compared according to the standards of <span class=\"s1\">identical()</span>, and must therefore actually be the <i>same</i> <span class=\"s1\">Dictionary</span> object, shared by both dictionaries, for <span class=\"s1\">isEqual()</span> to return <span class=\"s1\">T</span>.</p>\n<p class=\"p3\">– (string)serialize([string$ format = \"slim\"])</p>\n<p class=\"p4\">Returns a serialized form of the dictionary’s contents as a <span class=\"s1\">string</span> singleton or vector.<span class=\"Apple-converted-space\">  </span>Five formats are supported at present, as chosen with the <span class=\"s1\">format</span> parameter: <span class=\"s1\">\"slim\"</span>, <span class=\"s1\">\"pretty\"</span>, and <span class=\"s1\">\"json\"</span> produce a singleton string, whereas <span class=\"s1\">\"csv\"</span> and <span class=\"s1\">\"tsv\"</span> produce a <span class=\"s1\">string</span> vector.<span class=\"Apple-converted-space\">  </span>These serializations can be written to disk with <span class=\"s1\">writeFile()</span> or <span class=\"s1\">writeTempFile()</span>, written to the output stream with <span class=\"s1\">cat()</span>, or used in any other way.</p>\n<p class=\"p4\">The default <span class=\"s1\">\"slim\"</span> format is intended for simple, informal use where a very easily parseable string is desired.<span class=\"Apple-converted-space\">  </span>For a simple dictionary containing only keys with singleton non-object values, this will be a semicolon-delimited string like <span class=\"s1\">'\"string1\"=value1;\"string2\"=value2;'</span> or <span class=\"s1\">'int1=value1;int2=value2;'</span>.<span class=\"Apple-converted-space\">  </span>Values of type <span class=\"s1\">string</span> will be quoted, and will be escaped with backslash escape sequences, including <span class=\"s1\">\\\\</span>, <span class=\"s1\">\\\"</span>, <span class=\"s1\">\\'</span>, <span class=\"s1\">\\t</span>, <span class=\"s1\">\\r</span>, and <span class=\"s1\">\\n</span>.<span class=\"Apple-converted-space\">  </span>Values that are not singleton will be separated by spaces, such as <span class=\"s1\">'\"string1\"=1 2 3;'</span>, while values that are themselves dictionaries will be delimited by braces, such as <span class=\"s1\">'\"string1\"={int1=value1;int2=value2;};'</span>.<span class=\"Apple-converted-space\">  </span>Keys that are of type <span class=\"s1\">string</span> will be quoted (always; note that this is a change in behavior starting in SLiM 4.1) and backslash-escaped (as needed, as for <span class=\"s1\">string</span> values); keys that are of type <span class=\"s1\">integer</span> are not quoted.<span class=\"Apple-converted-space\">  </span>No facility for parsing <span class=\"s1\">\"slim\"</span> serializations back into Eidos is presently provided.</p>\n<p class=\"p4\">For a more extended example, here is an input <span class=\"s1\">Dictionary</span>, assigned into a variable <span class=\"s1\">x</span>:</p>\n<p class=\"p5\">x = Dictionary(\"a\", 17, \"b\", 1:5, \"c\", c(\"foo\", \"bar\"),<br>\n<span class=\"Apple-converted-space\">                  </span>\"d\", Dictionary(\"seq\", 1.5:5),<br>\n<span class=\"Apple-converted-space\">                  </span>\"e\", Dictionary());</p>\n<p class=\"p4\">and here is the result of <span class=\"s1\">x.serialize(\"json\")</span>, omitting the enclosing quotes that would indicate that this is a <span class=\"s1\">string</span> value:</p>\n<p class=\"p5\">\"a\"=17;\"b\"=1 2 3 4 5;\"c\"=\"foo\" \"bar\";\"d\"={\"seq\"=1.5 2.5 3.5 4.5;};\"e\"={};</p>\n<p class=\"p4\">The <span class=\"s1\">\"pretty\"</span> format is intended for human-readable output, for purposes such as debugging output.<span class=\"Apple-converted-space\">  </span>It is similar to the <span class=\"s1\">\"slim\"</span> format, but (1) it prints an enclosing set of braces at the top level, (2) it adds newlines inside braces, (3) it tracks an indentation level that increments for nested dictionaries, (4) it adds whitespace it some positions for readability, such as around the equals signs that separate keys from values, and (5) it omits the semicolon at the end of a value, adding a newline instead.<span class=\"Apple-converted-space\">  </span>No facility for parsing <span class=\"s1\">\"pretty\"</span> serializations back into Eidos is presently provided.</p>\n<p class=\"p4\">For the same extended example <span class=\"s1\">Dictionary</span> as above, here is the result of <span class=\"s1\">x.serialize(\"pretty\")</span>, again omitting the enclosing quotes that would indicate that this is a <span class=\"s1\">string</span> value:</p>\n<p class=\"p5\">{<br>\n<span class=\"Apple-converted-space\">   </span>\"a\" = 17<br>\n<span class=\"Apple-converted-space\">   </span>\"b\" = 1 2 3 4 5<br>\n<span class=\"Apple-converted-space\">   </span>\"c\" = \"foo\" \"bar\"<br>\n<span class=\"Apple-converted-space\">   </span>\"d\" = {<br>\n<span class=\"Apple-converted-space\">      </span>\"seq\" = 1.5 2.5 3.5 4.5<br>\n<span class=\"Apple-converted-space\">   </span>}<br>\n<span class=\"Apple-converted-space\">   </span>\"e\" = {}<br>\n}</p>\n<p class=\"p4\">The <span class=\"s1\">\"json\"</span> format, introduced in Eidos 2.7 (SLiM 3.7), provides serialization of the <span class=\"s1\">Dictionary</span> into the standard JSON format, which may not be quite as brief or human-readable, but which can be used as a standard interchange format and read by the <span class=\"s1\">Dictionary()</span> constructor in Eidos as well as by many other programs.<span class=\"Apple-converted-space\">  </span>For example, a <span class=\"s1\">Dictionary</span> with a key <span class=\"s1\">\"key1\"</span> with <span class=\"s1\">integer</span> value <span class=\"s1\">1:3</span> and key <span class=\"s1\">\"key2\"</span> with <span class=\"s1\">string</span> value <span class=\"s1\">\"value2\"</span> would produce the JSON serialization <span class=\"s1\">'{\"key1\":[1,2,3],\"key2\":[\"value2\"]}'</span>, where the outer single quotes are not part of the serialization itself, but are indicating that the serialization is a <span class=\"s1\">string</span> value.<span class=\"Apple-converted-space\">  </span>Note that since all Eidos values are vectors, even singleton values are serialized into JSON as arrays by Eidos; the hope is that this will make automated parsing of these JSON strings easier, since the singleton case will not have to be special-cased.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s1\">Dictionary(\"a\", 1, \"b\", Dictionary(\"x\", 2))</span> would be serialized into JSON as <span class=\"s1\">'{\"a\":[1],\"b\":[{\"x\":[2]}]}'</span>.<span class=\"Apple-converted-space\">  </span>Note that dictionaries that use <span class=\"s1\">integer</span> keys cannot be serialized into JSON, because JSON does not support <span class=\"s1\">integer</span> keys.<span class=\"Apple-converted-space\">  </span>Documentation on the JSON format can be found online.</p>\n<p class=\"p4\">The <span class=\"s1\">\"csv\"</span> and <span class=\"s1\">\"tsv\"</span> formats produce standard comma-separated value (CSV) or tab-separated value (TSV) data.<span class=\"Apple-converted-space\">  </span>These formats are primarily intended for output from <span class=\"s1\">DataFrame</span>, since that class is used to represent the sort of data tables that CSV/TSV are typically used for; but it may be used with <span class=\"s1\">Dictionary</span> too, particularly if it is being used to represent a data table with ragged columns (missing values will just be skipped over, producing two commas or two tabs in sequence).<span class=\"Apple-converted-space\">  </span>Values of type <span class=\"s1\">string</span> will always be quoted, with double quotes (with a repeated double quote used to indicate the presence of a double quote inside a <span class=\"s1\">string</span> value, as usual in CSV); values of other types never will.<span class=\"Apple-converted-space\">  </span>Decimal points (not decimal commas, regardless of system localization) will always be used for <span class=\"s1\">float</span> values, and will never be used for <span class=\"s1\">integer</span> values.<span class=\"Apple-converted-space\">  </span>Values of logical type will be serialized as <span class=\"s1\">TRUE</span> or <span class=\"s1\">FALSE</span>, without quotes.<span class=\"Apple-converted-space\">  </span>A header line providing the names of the columns (i.e., the keys of the target <span class=\"s1\">Dictionary</span>) will always be generated; those column names will also be quoted (if the keys of the dictionary are type <span class=\"s1\">string</span>; <span class=\"s1\">integer</span> keys are not quoted).<span class=\"Apple-converted-space\">  </span>One <span class=\"s1\">string</span> element will be generated for each row of the target, plus one <span class=\"s1\">string</span> element for the header line; newlines will not be present in the resulting <span class=\"s1\">string</span> vector unless newlines were present within the <span class=\"s1\">string</span> values in the <span class=\"s1\">Dictionary</span>.<span class=\"Apple-converted-space\">  </span>The resulting data, if written to a file, should be readable in Eidos using <span class=\"s1\">readCSV()</span> (as long as there are no ragged columns or missing values), as well as in other software such as R and Excel.</p>\n<p class=\"p3\">– (void)setValue(is$ key, * value)</p>\n<p class=\"p4\">Sets a value for the dictionary entry identifier <span class=\"s1\">key</span>.<span class=\"Apple-converted-space\">  </span>The key may be a <span class=\"s1\">string</span> or an <span class=\"s1\">integer</span>; either is allowed, unless the target dictionary has already begun using keys of a given type, in which case it must continue using the same key type (a given dictionary cannot have both <span class=\"s1\">string</span> and <span class=\"s1\">integer</span> keys).<span class=\"Apple-converted-space\">  </span>The value, which may be of any type, can be fetched later using <span class=\"s1\">getValue()</span>.<span class=\"Apple-converted-space\">  </span>Setting a key to a value of <span class=\"s1\">NULL</span> removes that key from the dictionary.</p>\n<p class=\"p4\">If <span class=\"s1\">value</span> is of type <span class=\"s1\">object</span>, any <span class=\"s1\">object</span> class is allowed; all objects may be added as values to a dictionary.<span class=\"Apple-converted-space\">  </span>However, additional scoping restrictions may apply if the <span class=\"s1\">object</span> class is not under an internal memory-management scheme called “retain-release”; in particular, it may not be legal to keep an object in a dictionary “long term” if it is not under retain-release, where “long term” is a scoping semantic defined by the Context.<span class=\"Apple-converted-space\">  </span>All object classes defined by Eidos itself (<span class=\"s1\">Dictionary</span>, <span class=\"s1\">DataFrame</span>, <span class=\"s1\">Image</span>) are under retain-release, so this restriction does not affect pure Eidos code.<span class=\"Apple-converted-space\">  </span>See the SLiM manual (section “SLiM scoping rules”) for further discussion of this topic.</p>\n<p class=\"p3\">+ (void)setValuesVectorized(is$ key, * values)</p>\n<p class=\"p4\">This class method sets a singleton value from <span class=\"s1\">values</span> into each target dictionary, using the same dictionary entry identifier <span class=\"s1\">key</span> for each.<span class=\"Apple-converted-space\">  </span>The number of elements in <span class=\"s1\">values</span> must be equal to the number of target dictionaries, so that the 0th element of <span class=\"s1\">values</span> is set as the value for the 0th target object, the 1st element of <span class=\"s1\">values</span> is set as the value for the 1st target object, and so forth.</p>\n<p class=\"p4\">This is a vectorized version of <span class=\"s1\">setValue()</span>; <span class=\"s1\">dicts.setValuesVectorized(\"key\", values)</span> is equivalent to <span class=\"s1\">for (dict in dicts, value in values) dict.setValue(\"key\", value)</span>, but is faster since the <span class=\"s1\">for</span> loop is vectorized internally.<span class=\"Apple-converted-space\">  </span>The speedup is not enormous, however; the larger reason for the existence of this method is convenience.</p>\n<p class=\"p4\">The values are set into the target dictionaries in exactly the same way as the <span class=\"s1\">setValue()</span> method would do; see that method for details about <span class=\"s1\">string</span> versus <span class=\"s1\">integer</span> keys, scoping restrictions for values of type <span class=\"s1\">object</span>, and so forth.<span class=\"Apple-converted-space\">  </span>Note that it is not possible to remove values from the target dictionaries, however, since it is not possible to pass <span class=\"s1\">NULL</span> as a value here.</p>\n<p class=\"p1\"><b>5.4<span class=\"Apple-converted-space\">  </span>Class Image</b></p>\n<p class=\"p3\">(object&lt;Image&gt;$)Image(...)</p>\n<p class=\"p4\">Creates a new <span class=\"s1\">Image</span> object.<span class=\"Apple-converted-space\">  </span>This can be called in a few different ways.</p>\n<p class=\"p4\">Passed a singleton <span class=\"s1\">string</span>, as <span class=\"s1\">Image(string$ filePath)</span>, it creates a new <span class=\"s1\">Image</span> from the PNG file at <span class=\"s1\">filePath</span>.<span class=\"Apple-converted-space\">  </span>If the file represents a grayscale image, an 8-bit grayscale (K) <span class=\"s1\">Image</span> will be created; all other PNG files will yield a 24-bit color (RGB) <span class=\"s1\">Image</span>.</p>\n<p class=\"p4\">Passed an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector, as <span class=\"s1\">Image(numeric matrix)</span>, it creates a new grayscale <span class=\"s1\">Image</span> from the values in <span class=\"s1\">matrix</span>, which must be a matrix as its name suggests.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">matrix</span> is <span class=\"s1\">integer</span>, its values must be in [<span class=\"s1\">0</span>, <span class=\"s1\">255</span>], and will be used directly as 8-bit pixel values without translation; if <span class=\"s1\">matrix</span> is <span class=\"s1\">float</span>, its values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], and will be translated into 8-bit pixel values.<span class=\"Apple-converted-space\">  </span>The dimensions of the image, in pixels, will be equal to the dimensions of the matrix.<span class=\"Apple-converted-space\">  </span>The orientation of the image will match that of the matrix, in the sense that the image will appear as the matrix does when printed in the Eidos console; internally this requires a transposition of values, as discussed further below.<span class=\"Apple-converted-space\">  </span>For the <span class=\"s1\">integer</span> case, the <span class=\"s1\">integerK</span> property of the resulting image will recover the original matrix exactly; for the <span class=\"s1\">float</span> case, the <span class=\"s1\">floatK</span> property will only approximately recover the original matrix since the translation into 8-bit pixel values involves quantization, but values of <span class=\"s1\">0.0</span> and <span class=\"s1\">1.0</span> will be recovered exactly.</p>\n<p class=\"p2\"><i>5.4.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Image</i></span><i> properties</i></p>\n<p class=\"p3\">width =&gt; (integer$)</p>\n<p class=\"p4\">The width of the image, in pixels.</p>\n<p class=\"p3\">height =&gt; (integer$)</p>\n<p class=\"p4\">The height of the image, in pixels.</p>\n<p class=\"p3\">isGrayscale =&gt; (logical$)</p>\n<p class=\"p4\">This flag is <span class=\"s1\">T</span> if the image is grayscale, with only a K channel; it is <span class=\"s1\">F</span> if the image is color, with R/G/B channels.</p>\n<p class=\"p3\">bitsPerChannel =&gt; (integer$)</p>\n<p class=\"p4\">The number of bits used to represent a single pixel, in one channel of the image.<span class=\"Apple-converted-space\">  </span>At present this is always 8; grayscale (K) images are 8-bit, color (RGB) images are 24-bit.<span class=\"Apple-converted-space\">  </span>It could be extended to support 16-bit channels in future.</p>\n<p class=\"p3\">integerR =&gt; (integer)</p>\n<p class=\"p4\">The red (R) channel of the image, represented as a 2D <span class=\"s1\">integer</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,255].<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">floatR</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">integerG =&gt; (integer)</p>\n<p class=\"p4\">The green (G) channel of the image, represented as a 2D <span class=\"s1\">integer</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,255].<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">floatG</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">integerB =&gt; (integer)</p>\n<p class=\"p4\">The blue (R) channel of the image, represented as a 2D <span class=\"s1\">integer</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,255].<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">floatB</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">integerK =&gt; (integer)</p>\n<p class=\"p4\">The gray (K) channel of the image, represented as a 2D <span class=\"s1\">integer</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,255].<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">floatK</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is color, this property is unavailable.</p>\n<p class=\"p3\">floatR =&gt; (float)</p>\n<p class=\"p4\">The red (R) channel of the image, represented as a 2D <span class=\"s1\">float</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,1], obtained by dividing the <span class=\"s1\">integerR</span> layer by 255.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">integerR</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">floatG =&gt; (float)</p>\n<p class=\"p4\">The green (G) channel of the image, represented as a 2D <span class=\"s1\">float</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,1], obtained by dividing the <span class=\"s1\">integerG</span> layer by 255.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">integerG</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">floatB =&gt; (float)</p>\n<p class=\"p4\">The blue (B) channel of the image, represented as a 2D <span class=\"s1\">float</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,1], obtained by dividing the <span class=\"s1\">integerB</span> layer by 255.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">integerB</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is grayscale, this property is unavailable.</p>\n<p class=\"p3\">floatK =&gt; (float)</p>\n<p class=\"p4\">The gray (K) channel of the image, represented as a 2D <span class=\"s1\">float</span> matrix.<span class=\"Apple-converted-space\">  </span>Values will be in [0,1], obtained by dividing the <span class=\"s1\">integerK</span> layer by 255.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">integerK</span> property for an alternative representation.<span class=\"Apple-converted-space\">  </span>If the image is color, this property is unavailable.</p>\n<p class=\"p2\"><i>5.4.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Image</i></span><i> methods</i></p>\n<p class=\"p3\">– (void)write(string$ filePath)</p>\n<p class=\"p4\">Writes the image to the given filesystem path <span class=\"s1\">filePath</span> as PNG data.<span class=\"Apple-converted-space\">  </span>It is suggested, but not required, that <span class=\"s1\">filePath</span> should end in a <span class=\"s1\">.png</span> or <span class=\"s1\">.PNG</span> filename extension.<span class=\"Apple-converted-space\">  </span>If the file cannot be written, an error will result.<span class=\"Apple-converted-space\">  </span>At present, since <span class=\"s1\">bitsPerChannel</span> is always 8, grayscale data will be written as an 8-bit grayscale PNG while color (RGB) data will be written as a 24-bit color PNG without alpha.</p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/EidosHelpFunctions.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"2487.7\">\n  <style type=\"text/css\">\n    p.p1 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo}\n    p.p3 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima}\n    p.p4 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo; color: #000000}\n    p.p5 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #000000}\n    p.p7 {margin: 3.0px 0.0px 3.0px 27.4px; font: 9.0px Menlo}\n    p.p8 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #d50005}\n    p.p9 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #969696}\n    p.p10 {margin: 0.0px 0.0px 9.0px 54.0px; font: 9.0px Menlo; color: #000000}\n    p.p11 {margin: 0.0px 0.0px 9.0px 54.0px; font: 10.0px Optima; color: #000000}\n    p.p12 {margin: 3.0px 0.0px 3.0px 27.4px; font: 9.0px Menlo; color: #000000}\n    p.p13 {margin: 0.0px 0.0px 3.0px 27.4px; text-indent: 18.0px; font: 10.0px Optima; color: #000000}\n    p.p14 {margin: 9.0px 0.0px 9.0px 45.0px; font: 9.0px Menlo}\n    li.li6 {margin: 3.0px 0.0px 3.0px 0.0px; font: 10.0px Optima}\n    span.s1 {font: 9.0px 'Times New Roman'}\n    span.s2 {font: 9.0px Menlo}\n    span.s3 {font: 10.0px 'Times New Roman'}\n    span.s4 {font: 10.0px 'Apple Symbols'}\n    span.s5 {font-kerning: none}\n    span.s6 {color: #000000}\n    span.s7 {font: 9.0px Menlo; color: #000000}\n    span.s8 {font: 10.0px 'Times New Roman'; color: #000000}\n    span.s9 {font: 9.0px Menlo; font-kerning: none}\n    span.s10 {font: 10.0px 'Times New Roman'; font-kerning: none}\n    span.s11 {font: 6.7px 'Times New Roman'; font-kerning: none}\n    span.s12 {font: 10.0px Helvetica}\n    span.s13 {font: 6.7px Optima}\n    span.s14 {font-kerning: none; color: #000000}\n    span.s15 {font: 9.0px Menlo; font-kerning: none; color: #000000}\n    span.s16 {font: 9.0px Symbol}\n    span.s17 {font: 10.0px Symbol}\n    span.s18 {font: 9.0px 'Times New Roman'; color: #000000}\n    span.s19 {font: 10.0px Optima}\n    span.s20 {text-decoration: underline ; color: #0000ff}\n    span.s21 {font: 6.7px Optima; font-kerning: none}\n    span.s22 {text-decoration: underline}\n    span.Apple-tab-span {white-space:pre}\n    ul.ul1 {list-style-type: disc}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><b>3.1.<span class=\"Apple-converted-space\">  </span>Math functions</b></p>\n<p class=\"p2\">(numeric)abs(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>absolute value</b> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">integer</span>, the C++ function <span class=\"s2\">llabs()</span> is used and an <span class=\"s2\">integer</span> vector is returned; if <span class=\"s2\">x</span> is <span class=\"s2\">float</span>, the C++ function <span class=\"s2\">fabs()</span> is used and a <span class=\"s2\">float</span> vector is returned.</p>\n<p class=\"p2\">(float)acos(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>arc cosine</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">acos()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)asin(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>arc sine</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">asin()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)atan(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>arc tangent</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">atan()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)atan2(numeric<span class=\"s1\"> </span>x, numeric<span class=\"s1\"> </span>y)</p>\n<p class=\"p3\">Returns the <b>arc tangent</b> of <span class=\"s2\">y/x</span> using the C++ function <span class=\"s2\">atan2()</span>, which uses the signs of both x and y to determine the correct quadrant for the result.</p>\n<p class=\"p2\">(float)ceil(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>ceiling</b> of <span class=\"s2\">x</span>: the smallest integral value greater than or equal to <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>Note that the return value is <span class=\"s2\">float</span> even though integral values are guaranteed, because values could be outside of the range representable by <span class=\"s2\">integer</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)cos(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>cosine</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">cos()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(numeric)cumProduct(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>cumulative product</b> of <span class=\"s2\">x</span>: a vector of equal length as <span class=\"s2\">x</span>, in which the element at index <span class=\"s2\">i</span> is equal to the product of the elements of <span class=\"s2\">x</span> across the range <span class=\"s2\">0:i</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The return type will match the type of <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">integer</span>, but all of the values of the cumulative product vector cannot be represented in that type, an error condition will result.</p>\n<p class=\"p2\">(numeric)cumSum(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>cumulative sum</b> of <span class=\"s2\">x</span>: a vector of equal length as <span class=\"s2\">x</span>, in which the element at index <span class=\"s2\">i</span> is equal to the sum of the elements of <span class=\"s2\">x</span> across the range <span class=\"s2\">0:i</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The return type will match the type of <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">integer</span>, but all of the values of the cumulative sum vector cannot be represented in that type, an error condition will result.</p>\n<p class=\"p2\">(float)exp(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>base-<i>e</i> exponential</b> of <span class=\"s2\">x, <i>e</i><sup>x</sup></span>,<span class=\"Apple-converted-space\">  </span>using the C++ function <span class=\"s2\">exp()</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>This may be somewhat faster than <span class=\"s2\">E^x</span> for large vectors.</p>\n<p class=\"p2\">(float)floor(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>floor</b> of <span class=\"s2\">x</span>: the largest integral value less than or equal to <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Note that the return value is <span class=\"s2\">float</span> even though integral values are guaranteed, because values could be outside of the range representable by <span class=\"s2\">integer</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(integer)integerDiv(integer x, integer y)</p>\n<p class=\"p3\">Returns the result of <b>integer division</b> of <span class=\"s2\">x</span> by <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">/</span> operator in Eidos always produces a <span class=\"s2\">float</span> result; if you want an <span class=\"s2\">integer</span> result you may use this function instead.<span class=\"Apple-converted-space\">  </span>If any value of <span class=\"s2\">y</span> is <span class=\"s2\">0</span>, an error will result.<span class=\"Apple-converted-space\">  </span>The parameters <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must either be of equal length, or one of the two must be a singleton.<span class=\"Apple-converted-space\">  </span>The precise behavior of <span class=\"s2\">integer</span> division, in terms of how rounding and negative values are handled, may be platform dependent; it will be whatever the C++ behavior of <span class=\"s2\">integer</span> division is on the given platform.<span class=\"Apple-converted-space\">  </span>Eidos does not guarantee any particular behavior, so use this function with caution.</p>\n<p class=\"p2\">(integer)integerMod(integer x<span class=\"s1\">,</span> integer y)</p>\n<p class=\"p3\">Returns the result of <b>integer modulo</b> of <span class=\"s2\">x</span> by <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">%</span> operator in Eidos always produces a <span class=\"s2\">float</span> result; if you want an <span class=\"s2\">integer</span> result you may use this function instead.<span class=\"Apple-converted-space\">  </span>If any value of <span class=\"s2\">y</span> is <span class=\"s2\">0</span>, an error will result.<span class=\"Apple-converted-space\">  </span>The parameters <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must either be of equal length, or one of the two must be a singleton.<span class=\"Apple-converted-space\">  </span>The precise behavior of <span class=\"s2\">integer</span> modulo, in terms of how rounding and negative values are handled, may be platform dependent; it will be whatever the C++ behavior of <span class=\"s2\">integer</span> modulo is on the given platform.<span class=\"Apple-converted-space\">  </span>Eidos does not guarantee any particular behavior, so use this function with caution.</p>\n<p class=\"p2\">(logical)isFinite(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>finiteness</b> of <span class=\"s2\">x</span>: <span class=\"s2\">T</span> if <span class=\"s2\">x</span> is not <span class=\"s2\">INF</span> or <span class=\"s2\">NAN</span>, <span class=\"s2\">F</span> if <span class=\"s2\">x</span> is <span class=\"s2\">INF</span> or <span class=\"s2\">NAN</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span><span class=\"s2\">INF</span> and <span class=\"s2\">NAN</span> are defined only for type <span class=\"s2\">float</span>, so x is required to be a <span class=\"s2\">float</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">isFinite()</span> is not the opposite of <span class=\"s2\">isInfinite()</span>, because <span class=\"s2\">NAN</span> is considered to be neither finite nor infinite.</p>\n<p class=\"p2\">(logical)isInfinite(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>infiniteness</b> of <span class=\"s2\">x</span>: <span class=\"s2\">T</span> if <span class=\"s2\">x</span> is <span class=\"s2\">INF</span>, <span class=\"s2\">F</span> otherwise.<span class=\"Apple-converted-space\">  </span><span class=\"s2\">INF</span> is defined only for type <span class=\"s2\">float</span>, so x is required to be a <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">isInfinite()</span> is not the opposite of <span class=\"s2\">isFinite()</span>, because <span class=\"s2\">NAN</span> is considered to be neither finite nor infinite.</p>\n<p class=\"p2\">(logical)isNAN(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>undefinedness</b> of <span class=\"s2\">x</span>: <span class=\"s2\">T</span> if <span class=\"s2\">x</span> is not <span class=\"s2\">NAN</span>, <span class=\"s2\">F</span> if <span class=\"s2\">x</span> is <span class=\"s2\">NAN</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span><span class=\"s2\">NAN</span> is defined only for type <span class=\"s2\">float</span>, so x is required to be a <span class=\"s2\">float</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)log(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>base-<i>e</i> logarithm</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">log()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)log10(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>base-10 logarithm</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">log10()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)log2(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>base-2 logarithm</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">log2()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(numeric$)product(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>product</b> of <span class=\"s2\">x</span>: the result of multiplying all of the elements of <span class=\"s2\">x</span> together.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">float</span>, the result will be <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">integer</span>, things are a bit more complex; the result will be <span class=\"s2\">integer</span> if it can fit into the <span class=\"s2\">integer</span> type without overflow issues (including during intermediate stages of the computation), otherwise it will be <span class=\"s2\">float</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)round(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>round</b> of <span class=\"s2\">x</span>: the integral value nearest to <span class=\"s2\">x</span>, rounding half-way cases away from <span class=\"s2\">0</span> (different from the rounding policy of R, which rounds halfway cases toward the nearest even number).<span class=\"Apple-converted-space\">  </span>Note that the return value is <span class=\"s2\">float</span> even though integral values are guaranteed, because values could be outside of the range representable by <span class=\"s2\">integer</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(*)setDifference(*<span class=\"s1\"> </span>x, *<span class=\"s1\"> </span>y)</p>\n<p class=\"p3\">Returns the <b>set-theoretic (asymmetric) difference</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, denoted <span class=\"s2\">x</span> <span class=\"s4\">∖</span> <span class=\"s2\">y</span>: a vector containing all elements that are in <span class=\"s2\">x</span> but are not in <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>Duplicate elements will be stripped out, in the same manner as the <span class=\"s2\">unique()</span> function.<span class=\"Apple-converted-space\">  </span>The order of elements in the returned vector is arbitrary and should not be relied upon.<span class=\"Apple-converted-space\">  </span>The returned vector will be of the same type as <span class=\"s2\">x</span> and <span class=\"s2\">y</span><span class=\"s3\">,</span> and <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be of the same type.</p>\n<p class=\"p2\">(*)setIntersection(*<span class=\"s1\"> </span>x, *<span class=\"s1\"> </span>y)</p>\n<p class=\"p3\">Returns the <b>set-theoretic intersection</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, denoted <span class=\"s2\">x</span> <span class=\"s4\">∩</span> <span class=\"s2\">y</span>: a vector containing all elements that are in both <span class=\"s2\">x</span> and <span class=\"s2\">y</span> (but not in <i>only</i> <span class=\"s2\">x</span> or <span class=\"s2\">y</span>).<span class=\"Apple-converted-space\">  </span>Duplicate elements will be stripped out, in the same manner as the <span class=\"s2\">unique()</span> function.<span class=\"Apple-converted-space\">  </span>The order of elements in the returned vector is arbitrary and should not be relied upon.<span class=\"Apple-converted-space\">  </span>The returned vector will be of the same type as <span class=\"s2\">x</span> and <span class=\"s2\">y</span><span class=\"s3\">,</span> and <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be of the same type.</p>\n<p class=\"p2\">(*)setSymmetricDifference(*<span class=\"s1\"> </span>x, *<span class=\"s1\"> </span>y)</p>\n<p class=\"p3\">Returns the <b>set-theoretic symmetric difference</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, denoted <span class=\"s2\">x</span> <span class=\"s4\">∆</span> <span class=\"s2\">y</span>: a vector containing all elements that are in <span class=\"s2\">x</span> or <span class=\"s2\">y</span>, but not in both.<span class=\"Apple-converted-space\">  </span>Duplicate elements will be stripped out, in the same manner as the <span class=\"s2\">unique()</span> function.<span class=\"Apple-converted-space\">  </span>The order of elements in the returned vector is arbitrary and should not be relied upon.<span class=\"Apple-converted-space\">  </span>The returned vector will be of the same type as <span class=\"s2\">x</span> and <span class=\"s2\">y</span><span class=\"s3\">,</span> and <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be of the same type.</p>\n<p class=\"p2\">(*)setUnion(*<span class=\"s1\"> </span>x, *<span class=\"s1\"> </span>y)</p>\n<p class=\"p3\">Returns the <b>set-theoretic union</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, denoted <span class=\"s2\">x</span> <span class=\"s4\">∪</span> <span class=\"s2\">y</span>: a vector containing all elements that are in <span class=\"s2\">x</span> and/or <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>Duplicate elements will be stripped out, in the same manner as the <span class=\"s2\">unique()</span> function.<span class=\"Apple-converted-space\">  </span>This function is therefore roughly equivalent to <span class=\"s2\">unique(c(x, y))</span>, but this function will probably be faster.<span class=\"Apple-converted-space\">  </span>The order of elements in the returned vector is arbitrary and should not be relied upon.<span class=\"Apple-converted-space\">  </span>The returned vector will be of the same type as <span class=\"s2\">x</span> and <span class=\"s2\">y</span><span class=\"s3\">,</span> and <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be of the same type.</p>\n<p class=\"p4\">(numeric)sign(numeric x)</p>\n<p class=\"p5\">Returns the <b>sign</b> of <span class=\"s2\">x</span>, meaning that for each element of x, a value of either <span class=\"s2\">-1</span>, <span class=\"s2\">0</span>, or <span class=\"s2\">1</span> will be returned as the corresponding element in the returned vector depending upon whether the original element was (respectively) negative, zero, or positive.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">integer</span>, an <span class=\"s2\">integer</span> vector is returned; if <span class=\"s2\">x</span> is <span class=\"s2\">float</span>, a <span class=\"s2\">float</span> vector is returned.</p>\n<p class=\"p2\">(float)sin(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>sine</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">sin()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)sqrt(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>square root</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">sqrt()</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>This may be somewhat faster than <span class=\"s2\">x^0.5</span> for large vectors.</p>\n<p class=\"p2\">(numeric$)sum(lif x)</p>\n<p class=\"p3\">Returns the <b>sum</b> of <span class=\"s2\">x</span>: the result of adding all of the elements of <span class=\"s2\">x</span> together.<span class=\"Apple-converted-space\">  </span>The unusual parameter type signature <span class=\"s2\">lif</span> indicates that <span class=\"s2\">x</span> can be <span class=\"s2\">logical</span>, <span class=\"s2\">integer</span>, or <span class=\"s2\">float</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">float</span>, the result will be <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">logical</span>, the result will be <span class=\"s2\">integer</span> (the number of <span class=\"s2\">T</span> values in <span class=\"s2\">x</span>, since the <span class=\"s2\">integer</span> values of <span class=\"s2\">T</span> and <span class=\"s2\">F</span> are <span class=\"s2\">1</span> and <span class=\"s2\">0</span> respectively).<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">integer</span>, things are a bit more complex; in this case, the result will be <span class=\"s2\">integer</span> if it can fit into the <span class=\"s2\">integer</span> type without overflow issues (including during intermediate stages of the computation), otherwise it will be <span class=\"s2\">float</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Note that floating-point roundoff issues can cause this function to return inexact results when <span class=\"s2\">x</span> is <span class=\"s2\">float</span> type; this is rarely an issue, but see the <span class=\"s2\">sumExact()</span> function for an alternative.</p>\n<p class=\"p2\">(float$)sumExact(float x)</p>\n<p class=\"p3\">Returns the <b>exact sum</b> of <span class=\"s2\">x</span>: the exact result of adding all of the elements of <span class=\"s2\">x</span> together.<span class=\"Apple-converted-space\">  </span>Unlike the <span class=\"s2\">sum()</span> function, <span class=\"s2\">sumExact()</span> accepts only type <span class=\"s2\">float</span>, since the <span class=\"s2\">sum()</span> function is already exact for other types.<span class=\"Apple-converted-space\">  </span>When summing floating-point values – particularly values that vary across many orders of magnitude – the precision limits of floating-point numbers can lead to roundoff errors that cause the <span class=\"s2\">sum()</span> function to return an inexact result.<span class=\"Apple-converted-space\">  </span>This function does additional work to ensure that the final result is exact within the possible limits of the <span class=\"s2\">float</span> type; some roundoff may still inevitably occur, in other words, but a more exact result could not be represented with a value of type <span class=\"s2\">float</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The disadvantage of using this function instead of <span class=\"s2\">sum()</span> is that it is much slower – about 35 times slower, according to one test on macOS, but that will vary across operating systems and hardware.<span class=\"Apple-converted-space\">  </span>This function is rarely truly needed, but apart from the performance consequences there is no disadvantage to using it.</p>\n<p class=\"p2\">(float)tan(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>tangent</b> of <span class=\"s2\">x</span> using the C++ function <span class=\"s2\">tan()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(float)trunc(float<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>truncation</b> of <span class=\"s2\">x</span>: the integral value nearest to, but no larger in magnitude than, <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>Note that the return value is <span class=\"s2\">float</span> even though integral values are guaranteed, because values could be outside of the range representable by <span class=\"s2\">integer</span><span class=\"s3\">.</span></p>\n<p class=\"p1\"><b>3.2.<span class=\"Apple-converted-space\">  </span>Statistics functions</b></p>\n<p class=\"p4\"><span class=\"s5\">(float)cor(numeric x, </span>[Nif y = NULL]<span class=\"s5\">)</span></p>\n<p class=\"p5\">Returns the <b>sample Pearson’s correlation coefficient</b> between vectors <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, usually denoted <i>r</i>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">y</span> is <span class=\"s2\">NULL</span>, it is considered to have the same value as <span class=\"s2\">x</span>; for vector <span class=\"s2\">x</span> this is not very useful (since the correlation of <span class=\"s2\">x</span> with itself is <span class=\"s2\">1.0</span> by definition), but it is more useful for calculating a correlation matrix using the columns of <span class=\"s2\">x</span> (see below).<span class=\"Apple-converted-space\">  </span>The sizes of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be identical.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> and <span class=\"s2\">y</span> have a size of <span class=\"s2\">0</span> or <span class=\"s2\">1</span>, <span class=\"s2\">NAN</span> will be returned (a change in behavior from Eidos 4.0; it used to return <span class=\"s2\">NULL</span>).<span class=\"Apple-converted-space\">  </span>The return value will be a singleton <span class=\"s2\">float</span>.</p>\n<p class=\"p5\">It is also legal to call <span class=\"s2\">cor()</span> with matrix <span class=\"s2\">x</span> and/or <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>In this case the return value will be a correlation matrix between x and y.<span class=\"Apple-converted-space\">  </span>Each column of <span class=\"s2\">x</span> will be represented by one row of the result (or if <span class=\"s2\">x</span> is a vector, the result will simply have one row representing <span class=\"s2\">x</span>), and each column of <span class=\"s2\">y</span> will be represented by one column of the result (or if <span class=\"s2\">y</span> is a vector, the result will simply have one column representing <span class=\"s2\">y</span>).<span class=\"Apple-converted-space\">  </span>Each element in the result matrix will therefore represent the correlation between a column of matrix <span class=\"s2\">x</span> (or the entirety of vector <span class=\"s2\">x</span>) and a column of matrix <span class=\"s2\">y</span> (or the entirety of vector y).<span class=\"Apple-converted-space\">  </span>Calling <span class=\"s2\">cor(x, x)</span>, or equivalently <span class=\"s2\">cor(x)</span>, thus produces a symmetric correlation matrix among the columns of <span class=\"s2\">x</span>.</p>\n<p class=\"p4\"><span class=\"s5\">(float)cov(numeric x, </span>[Nif y = NULL]<span class=\"s5\">)</span></p>\n<p class=\"p5\">Returns the <b>corrected sample covariance</b> between vectors <span class=\"s2\">x</span> and <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">y</span> is <span class=\"s2\">NULL</span>, it is considered to have the same value as <span class=\"s2\">x</span>; for vector <span class=\"s2\">x</span> this is equivalent to calling <span class=\"s2\">var(x)</span>, but it is more useful for calculating a variance-covariance matrix using the columns of <span class=\"s2\">x</span> (see below).<span class=\"Apple-converted-space\">  </span>The sizes of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must be identical.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> and <span class=\"s2\">y</span> have a size of <span class=\"s2\">0</span> or <span class=\"s2\">1</span>, <span class=\"s2\">NAN</span> will be returned (a change in behavior from Eidos 4.0; it used to return <span class=\"s2\">NULL</span>).<span class=\"Apple-converted-space\">  </span>The return value will be a singleton <span class=\"s2\">float</span>.</p>\n<p class=\"p5\">It is also legal to call <span class=\"s2\">cov()</span> with matrix <span class=\"s2\">x</span> and/or <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>In this case the return value will be a covariance matrix between x and y.<span class=\"Apple-converted-space\">  </span>Each column of <span class=\"s2\">x</span> will be represented by one row of the result (or if <span class=\"s2\">x</span> is a vector, the result will simply have one row representing <span class=\"s2\">x</span>), and each column of <span class=\"s2\">y</span> will be represented by one column of the result (or if <span class=\"s2\">y</span> is a vector, the result will simply have one column representing <span class=\"s2\">y</span>).<span class=\"Apple-converted-space\">  </span>Each element in the result matrix will therefore represent the covariance between a column of matrix <span class=\"s2\">x</span> (or the entirety of vector <span class=\"s2\">x</span>) and a column of matrix <span class=\"s2\">y</span> (or the entirety of vector y).<span class=\"Apple-converted-space\">  </span>Calling <span class=\"s2\">cov(x, x)</span>, or equivalently <span class=\"s2\">cov(x)</span>, thus produces a symmetric variance-covariance matrix among the columns of <span class=\"s2\">x</span>.</p>\n<p class=\"p4\">(float)filter(numeric x, float filter, [lif$ outside = F])</p>\n<p class=\"p5\">Returns the result of convolving <span class=\"s2\">x</span> with <span class=\"s2\">filter</span>.<span class=\"Apple-converted-space\">  </span>The returned vector will be the same length as <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>The convolution is performed by centering <span class=\"s2\">filter</span> on each position of <span class=\"s2\">x</span> to produce a corresponding result element that is the sum over the products of each <span class=\"s2\">filter</span> value with each <span class=\"s2\">x</span> value within the filter’s range.<span class=\"Apple-converted-space\">  </span>The length of <span class=\"s2\">filter</span> is required to be odd, so that the filter has a central value (and can thus be centered over each value of <span class=\"s2\">x</span>).</p>\n<p class=\"p5\">If the filter, centered over a given value of <span class=\"s2\">x</span>, extends beyond the end of <span class=\"s2\">x</span> then the calculation of the corresponding element of the result is governed by the <span class=\"s2\">outside</span> parameter.<span class=\"Apple-converted-space\">  </span>When <span class=\"s2\">outside</span> is <span class=\"s2\">F</span> (the default), the corresponding element in the result will be <span class=\"s2\">NAN</span>; this matches the behavior of the R <span class=\"s2\">filter()</span> function (except that R uses <span class=\"s2\">NA</span>).<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">outside</span> is <span class=\"s2\">T</span>, values outside <span class=\"s2\">x</span> will be excluded from the calculation (the filter value covering that position will be considered to be <span class=\"s2\">0</span>), and the other values in the filter will be adjusted so that the sum of the absolute values of the filter weights used is unchanged, to compensate for the excluded values by giving the positions inside <span class=\"s2\">x</span> more weight. Finally, if <span class=\"s2\">outside</span> is <span class=\"s2\">integer</span> or <span class=\"s2\">float</span>, that value will be used as the value of <span class=\"s2\">x</span> for all positions outside <span class=\"s2\">x</span>; one might pass an expected value or mean value in this way, to be used for all outside positions.</p>\n<p class=\"p5\">This function is useful for computing running means and similar transformations of an input vector.<span class=\"Apple-converted-space\">  </span>For a simple running mean of width <span class=\"s2\">w</span>, pass r<span class=\"s2\">ep(1/w, w)</span> for <span class=\"s2\">filter</span>.<span class=\"Apple-converted-space\">  </span>That case is automatically detected and handled efficiently; otherwise, the runtime of this function is proportional to the length of <span class=\"s2\">x</span> times the length of <span class=\"s2\">filter</span>, and so will be slow for long filters.</p>\n<p class=\"p2\">(+$)max(+ x, ...)</p>\n<p class=\"p3\">Returns the <b>maximum</b> of <span class=\"s2\">x</span> and the other arguments supplied: the single greatest value contained by all of them.<span class=\"Apple-converted-space\">  </span>All of the arguments must be the same type as <span class=\"s2\">x</span>, and the return type will match that of <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If all of the arguments have a size of <span class=\"s2\">0</span>, the return value will be <span class=\"s2\">NULL</span>; note that this means that <span class=\"s2\">max(x, max(y))</span> may produce an error, if <span class=\"s2\">max(y)</span> is <span class=\"s2\">NULL</span>, in cases where <span class=\"s2\">max(x, y)</span> does not.</p>\n<p class=\"p2\">(float$)mean(lif<span class=\"s1\"> </span>x)</p>\n<p class=\"p5\"><span class=\"s6\">Returns the <b>arithmetic mean</b> of </span><span class=\"s7\">x</span><span class=\"s6\">: the sum of </span><span class=\"s7\">x</span><span class=\"s6\"> divided by the number of values in </span><span class=\"s7\">x</span><span class=\"s8\">.</span><span class=\"s6\"><span class=\"Apple-converted-space\">  </span>If </span><span class=\"s7\">x</span><span class=\"s6\"> has a size of </span><span class=\"s7\">0</span><span class=\"s6\">, the return value will be </span><span class=\"s7\">NULL</span><span class=\"s8\">.</span><span class=\"s5\"><span class=\"Apple-converted-space\">  </span>The unusual parameter type signature </span><span class=\"s9\">lif</span><span class=\"s5\"> indicates that </span><span class=\"s9\">x</span><span class=\"s5\"> can be </span><span class=\"s9\">logical</span><span class=\"s5\">, </span><span class=\"s9\">integer</span><span class=\"s5\">, or </span><span class=\"s9\">float</span><span class=\"s5\">; if </span><span class=\"s9\">x</span><span class=\"s5\"> is </span><span class=\"s9\">logical</span><span class=\"s5\">, it is coerced to </span><span class=\"s9\">integer</span><span class=\"s5\"> internally (with </span><span class=\"s9\">F</span><span class=\"s5\"> being </span><span class=\"s9\">0</span><span class=\"s5\"> and </span><span class=\"s9\">T</span><span class=\"s5\"> being </span><span class=\"s9\">1</span><span class=\"s5\">, as always), allowing </span><span class=\"s9\">mean()</span><span class=\"s5\"> to calculate the average truth value of a </span><span class=\"s9\">logical</span><span class=\"s5\"> vector.</span></p>\n<p class=\"p2\">(+$)min(+ x, ...)</p>\n<p class=\"p3\">Returns the <b>minimum</b> of <span class=\"s2\">x</span> and the other arguments supplied: the single smallest value contained by all of them.<span class=\"Apple-converted-space\">  </span>All of the arguments must be the same type as <span class=\"s2\">x</span>, and the return type will match that of <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If all of the arguments have a size of <span class=\"s2\">0</span>, the return value will be <span class=\"s2\">NULL</span>; note that this means that <span class=\"s2\">min(x, min(y))</span> may produce an error, if <span class=\"s2\">min(y)</span> is <span class=\"s2\">NULL</span>, in cases where <span class=\"s2\">min(x, y)</span> does not.</p>\n<p class=\"p2\">(+)pmax(+ x, + y)</p>\n<p class=\"p3\">Returns the <b>parallel maximum</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>: the element-wise maximum for each corresponding pair of elements in <span class=\"s2\">x</span> and <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>The type of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must match, and the returned value will have the same type.<span class=\"Apple-converted-space\">  </span>In one usage pattern the size of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> match, in which case the returned value will have the same size.<span class=\"Apple-converted-space\">  </span>In the other usage pattern either <span class=\"s2\">x</span> and <span class=\"s2\">y</span> is a singleton, in which case the returned value will match the size of the non-singleton argument, and pairs of elements for comparison will be formed between the singleton’s element and each of the elements in the non-singleton.</p>\n<p class=\"p2\">(+)pmin(+ x, + y)</p>\n<p class=\"p3\">Returns the <b>parallel minimum</b> of <span class=\"s2\">x</span> and <span class=\"s2\">y</span>: the element-wise minimum for each corresponding pair of elements in <span class=\"s2\">x</span> and <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>The type of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> must match, and the returned value will have the same type.<span class=\"Apple-converted-space\">  </span>In one usage pattern the size of <span class=\"s2\">x</span> and <span class=\"s2\">y</span> match, in which case the returned value will have the same size.<span class=\"Apple-converted-space\">  </span>In the other usage pattern either <span class=\"s2\">x</span> and <span class=\"s2\">y</span> is a singleton, in which case the returned value will match the size of the non-singleton argument, and pairs of elements for comparison will be formed between the singleton’s element and each of the elements in the non-singleton.</p>\n<p class=\"p4\">(float)quantile(numeric x, [Nf probs = NULL])</p>\n<p class=\"p5\">Returns <b>sample quantiles</b> of <span class=\"s2\">x</span> for the given probabilities.<span class=\"Apple-converted-space\">  </span>The smallest value in <span class=\"s2\">x</span> corresponds to a probability of <span class=\"s2\">0</span>, and the largest value in <span class=\"s2\">x</span> to a probability of <span class=\"s2\">1</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">probs</span> vector should be a vector of probabilities in <span class=\"s2\">[0, 1]</span>, or <span class=\"s2\">NULL</span>, which is equivalent to <span class=\"s2\">c(0.0, 0.25, 0.5, 0.75, 1.0)</span>, requesting sample quartiles.</p>\n<p class=\"p5\">The quantile function linearly interpolates between the points of the empirical cumulative distribution function.<span class=\"Apple-converted-space\">  </span>In other words, if <span class=\"s2\">x</span> is a vector of length <i>n</i>+1, then the quantiles with <span class=\"s2\">probs</span> equal to (0, 1/<i>n</i>, 2/<i>n</i>, ..., (<i>n</i>−1)/<i>n</i>, 1) are equal to the sorted values of <span class=\"s2\">x</span>, and the quantile is a linear function of <span class=\"s2\">probs</span> otherwise.<span class=\"Apple-converted-space\">  </span>Note that there are many ways to compute quantiles; this algorithm corresponds to R’s default “type 7” algorithm.</p>\n<p class=\"p2\">(numeric)range(numeric<span class=\"s1\"> </span>x, ...)</p>\n<p class=\"p3\">Returns the <b>range</b> of <span class=\"s2\">x</span> and the other arguments supplied: a vector of length <span class=\"s2\">2</span> composed of the minimum and maximum values contained by all of them, at indices <span class=\"s2\">0</span> and <span class=\"s2\">1</span> respectively.<span class=\"Apple-converted-space\">  </span>All of the arguments must be the same type as <span class=\"s2\">x</span>, and the return type will match that of <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If all of the arguments have a size of <span class=\"s2\">0</span>, the return value will be <span class=\"s2\">NULL</span>; note that this means that <span class=\"s2\">range(x, range(y))</span> may produce an error, if <span class=\"s2\">range(y)</span> is <span class=\"s2\">NULL</span>, in cases where <span class=\"s2\">range(x, y)</span> does not.</p>\n<p class=\"p4\">(numeric)rank(numeric x, [string$ tiesMethod = \"average\"])</p>\n<p class=\"p5\">Returns the <b>ranks</b> of the elements of <span class=\"s2\">x</span>: a vector of length <span class=\"s2\">L</span> (the length of <span class=\"s2\">x</span>), composed of the relative ranks, from <span class=\"s2\">1</span> to <span class=\"s2\">L</span>, of each corresponding element of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">tiesMethod</span> parameter may be any of <span class=\"s2\">\"average\"</span> (the default), <span class=\"s2\">\"first\"</span>, <span class=\"s2\">\"last\"</span>, <span class=\"s2\">\"max\"</span>, or <span class=\"s2\">\"min\"</span> (<span class=\"s2\">\"random\"</span>, supported by R, is not supported by Eidos at this time but could be added if needed).<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">\"average\"</span>, the return value is of type <span class=\"s2\">float</span>; for all others, it is of type <span class=\"s2\">integer</span>.<span class=\"Apple-converted-space\">  </span>(Note that the return type does <i>not</i> depend upon the type of <span class=\"s2\">x</span>.)</p>\n<p class=\"p5\">The result for all of these <span class=\"s2\">tiesMethod</span> values is identical (except for type) if the elements of <span class=\"s2\">x</span> are unique; the difference between these methods is in how ties are resolved.<span class=\"Apple-converted-space\">  </span>Suppose that <i>n</i> elements of <span class=\"s2\">x</span> are tied (because they are equal), corresponding to ranks <i>k</i> through <i>k</i>+<i>n−</i>1.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">tiesMethod</span> <span class=\"s2\">\"average\"</span>, all <i>n</i> tied elements receive the same rank, (<i>k</i> + (<i>n−</i>1)/2), which is the average of the ranks.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">\"first\"</span>, the first tied element receives rank <i>k</i>, upward to the last tied element receiving rank <i>k</i>+<i>n−</i>1.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">\"last\"</span>, the last tied element receives rank <i>k</i>, downward to the first tied element receiving rank <i>k</i>+<i>n−</i>1.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">\"max\"</span>, all <i>n</i> tied element receive the maximum rank, <i>k</i>+<i>n−</i>1.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">\"min\"</span>, all <i>n</i> tied element receive the minimum rank, <i>k</i>.</p>\n<p class=\"p2\">(float$)sd(numeric<span class=\"s1\"> </span>x)</p>\n<p class=\"p5\">Returns the <b>corrected sample standard deviation</b> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> has a size of <span class=\"s2\">0</span> or <span class=\"s2\">1</span>, <span class=\"s2\">NAN</span> will be returned (a change in behavior from Eidos 4.0; it used to return <span class=\"s2\">NULL</span>).<span class=\"Apple-converted-space\">  </span>Matrix/array dimensions are ignored by <span class=\"s2\">sd()</span>; it simply uses all of the elements of <span class=\"s2\">x</span> for its calculation.</p>\n<p class=\"p2\">(float$)ttest(float<span class=\"s1\"> </span>x, [Nf y = NULL], [Nf$ mu = NULL])</p>\n<p class=\"p3\">Returns the <i>p</i>-value resulting from running a <i>t</i>-test with the supplied data.<span class=\"Apple-converted-space\">  </span>Two types of <i>t</i><span class=\"s3\">-</span>tests can be performed.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are supplied (i.e., <span class=\"s2\">y</span> is non-<span class=\"s2\">NULL</span>), a two-sample unpaired two-sided Welch’s <i>t</i>-test is conducted using the samples in <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, each of which must contain at least two elements.<span class=\"Apple-converted-space\">  </span>The null hypothesis for this test is that the two samples are drawn from populations with the same mean.<span class=\"Apple-converted-space\">  </span>Other options, such as pooled-variance <i>t</i>-tests, paired <i>t</i>-tests, and one-sided <i>t</i>-tests, are not presently available.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> and <span class=\"s2\">mu</span> are supplied (i.e., <span class=\"s2\">mu</span> is non-<span class=\"s2\">NULL</span>), a one-sample <i>t</i>-test is conducted in which the null hypothesis is that the sample is drawn from a population with mean <span class=\"s2\">mu</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">Note that the results from this function are substantially different from those produced by R.<span class=\"Apple-converted-space\">  </span>The Eidos <span class=\"s2\">ttest() </span>function uses uncorrected sample statistics, which means they will be biased for small sample sizes, whereas R probably uses corrected, unbiased sample statistics.<span class=\"Apple-converted-space\">  </span>This is an Eidos bug, and might be fixed if anyone complains.<span class=\"Apple-converted-space\">  </span>If large sample sizes are used, however, the bias is likely to be small, and uncorrected statistics are simpler and faster to compute.</p>\n<p class=\"p4\"><span class=\"s5\">(float$)var(numeric x)</span></p>\n<p class=\"p5\">Returns the <b>corrected sample variance</b> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> has a size of <span class=\"s2\">0</span> or <span class=\"s2\">1</span>, <span class=\"s2\">NAN</span> will be returned (a change in behavior from Eidos 4.0; it used to return <span class=\"s2\">NULL</span>).<span class=\"Apple-converted-space\">  </span>This is the square of the standard deviation calculated by <span class=\"s2\">sd()</span>.<span class=\"Apple-converted-space\">  </span>It is illegal to call <span class=\"s2\">var()</span> with a matrix or array argument; use <span class=\"s2\">cov()</span> to calculate a variance-covariance matrix.</p>\n<p class=\"p1\"><b>3.3.<span class=\"Apple-converted-space\">  </span>Distribution drawing and density functions</b></p>\n<p class=\"p4\"><span class=\"s5\">(float)dmvnorm(float x, numeric mu, numeric sigma)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>probability densities for a <i>k</i>-dimensional multivariate normal distribution</b> with a length <i>k</i> mean vector </span><span class=\"s9\">mu</span><span class=\"s5\"> and a <i>k</i> × <i>k</i> variance-covariance matrix </span><span class=\"s9\">sigma</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">mu</span><span class=\"s5\"> and </span><span class=\"s9\">sigma</span><span class=\"s5\"> parameters are used for all densities.<span class=\"Apple-converted-space\">  </span>The quantile values, </span><span class=\"s9\">x</span><span class=\"s5\">, should be supplied as a matrix with one row per vector of quantile values and <i>k</i> columns (one column per dimension); for convenience, a single quantile may be supplied as a vector rather than a matrix with just one row.<span class=\"Apple-converted-space\">  </span>The number of dimensions <i>k</i> must be at least two; for <i>k</i>=1, use </span><span class=\"s9\">dnorm()</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">Cholesky decomposition of the variance-covariance matrix </span><span class=\"s9\">sigma</span><span class=\"s5\"> is involved as an internal step, and this requires that </span><span class=\"s9\">sigma</span><span class=\"s5\"> be positive-definite; if it is not, an error will result.<span class=\"Apple-converted-space\">  </span>When more than one density is needed, it is much more efficient to call </span><span class=\"s9\">dmvnorm()</span><span class=\"s5\"> once to generate all of the densities, since the Cholesky decomposition of </span><span class=\"s9\">sigma</span><span class=\"s5\"> can then be done just once.</span></p>\n<p class=\"p4\"><span class=\"s5\">(float)dbeta(float x, numeric alpha, numeric beta)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>probability densities for a beta distribution</b> at quantiles </span><span class=\"s9\">x</span><span class=\"s5\"> with parameters </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s9\">beta</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s9\">beta</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of the same length as </span><span class=\"s9\">x</span><span class=\"s5\">, specifying a value for each density computation.<span class=\"Apple-converted-space\">  </span>The probability density function is </span><span class=\"s10\"><i>P</i>(<i>s</i> | <i>α</i>,<i>β</i>) = [Γ(<i>α</i>+<i>β</i>)/Γ(<i>α</i>)Γ(<i>β</i>)]<i>s</i></span><span class=\"s11\"><i><sup>α</sup></i><sup>−1</sup></span><span class=\"s10\">(1−<i>s</i>)</span><span class=\"s11\"><i><sup>β</sup></i><sup>−1</sup></span><span class=\"s5\">, where </span><span class=\"s10\"><i>α</i></span><span class=\"s5\"> is </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s10\"><i>β</i></span><span class=\"s5\"> is </span><span class=\"s9\">beta</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Both parameters must be greater than </span><span class=\"s9\">0</span><span class=\"s5\">.</span></p>\n<p class=\"p4\"><span class=\"s5\">(float)dexp(float x, [numeric mu = 1])</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>probability densities for an exponential distribution</b> at quantiles </span><span class=\"s9\">x</span><span class=\"s5\"> with mean </span><span class=\"s9\">mu</span><span class=\"s5\"> (i.e. rate </span><span class=\"s9\">1/mu</span><span class=\"s5\">).<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">mu</span><span class=\"s5\"> parameter may either be a singleton, specifying a single value to be used for all of the draws, or they may be vectors of the same length as </span><span class=\"s9\">x</span><span class=\"s5\">, specifying a value for each density computation.</span></p>\n<p class=\"p4\"><span class=\"s5\">(float)dgamma(float x, numeric mean, numeric shape)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>probability densities for a gamma distribution</b> at quantiles </span><span class=\"s9\">x</span><span class=\"s5\"> with mean </span><span class=\"s9\">mean</span><span class=\"s5\"> and shape parameter </span><span class=\"s9\">shape</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">mean</span><span class=\"s5\"> and </span><span class=\"s9\">shape</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of the same length as </span><span class=\"s9\">x</span><span class=\"s5\">, specifying a value for each density computation.<span class=\"Apple-converted-space\">  </span>The probability density function is </span><span class=\"s10\"><i>P</i>(<i>s</i> | <i>α</i>,<i>β</i>) = [Γ(<i>α</i>)<i>β</i></span><span class=\"s11\"><i><sup>α</sup></i></span><span class=\"s10\">]</span><span class=\"s11\"><sup>−1</sup></span><span class=\"s10\"><i>s</i></span><span class=\"s11\"><i><sup>α</sup></i><sup>−1</sup></span><span class=\"s10\">exp(−<i>s</i>/<i>β</i>)</span><span class=\"s5\">, where </span><span class=\"s10\"><i>α</i></span><span class=\"s5\"> is the shape parameter </span><span class=\"s9\">shape</span><span class=\"s5\">, and the mean of the distribution given by </span><span class=\"s9\">mean</span><span class=\"s5\"> is equal to </span><span class=\"s10\"><i>αβ</i></span><span class=\"s5\">.</span></p>\n<p class=\"p2\">(float)dnorm(float x, [numeric mean = 0], [numeric sd = 1])</p>\n<p class=\"p3\">Returns a vector of <b>probability densities for a normal distribution</b> at quantiles <span class=\"s2\">x</span> with mean <span class=\"s2\">mean</span> and standard deviation <span class=\"s2\">sd</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">mean</span> and <span class=\"s2\">sd</span> parameters may either be singletons, specifying a single value to be used for all of the densities, or they may be vectors of the same length as <span class=\"s2\">x</span>, specifying a value for each density computation.</p>\n<p class=\"p4\">(integer)findInterval(numeric x, numeric vec, [logical$ rightmostClosed = F], [logical$ allInside = F])</p>\n<p class=\"p5\">Returns a vector of <b>interval indices</b> for the values in <span class=\"s2\">x</span> within a vector of non-decreasing breakpoints <span class=\"s2\">vec</span>.<span class=\"Apple-converted-space\">  </span>The returned <span class=\"s2\">integer</span> vector contains, for each corresponding element of <span class=\"s2\">x</span>, the index of the interval in <span class=\"s2\">vec</span> within which that element of <span class=\"s2\">x</span> is contained.</p>\n<p class=\"p5\">More precisely, if <span class=\"s2\">i</span> is the returned <span class=\"s2\">integer</span> vector from <span class=\"s2\">findInterval(x, v)</span>, and <span class=\"s2\">N</span> is <span class=\"s2\">length(v)</span>, then for each index <span class=\"s2\">j</span> in <span class=\"s2\">x</span>, it will be true that <span class=\"s2\">v[i[j]]</span> ≤ <span class=\"s2\">x[j]</span> &lt; <span class=\"s2\">v[i[j]+1]</span>, treating <span class=\"s2\">v[-1]</span> as <span class=\"s2\">-INF</span> and <span class=\"s2\">v[N]</span> as <span class=\"s2\">INF</span>, <i>assuming</i> that the two flags <span class=\"s2\">rightmostClosed</span> and <span class=\"s2\">allInside</span> have their default value of <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>The effects of the flags will be discussed below.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">vec</span> must be non-decreasing; in other words, it must be sorted in ascending order, although it may have duplicate values.<span class=\"Apple-converted-space\">  </span>The returned vector will thus be equal in length to <span class=\"s2\">x</span>, and each of its elements will be in the interval [<span class=\"s2\">-1</span>, <span class=\"s2\">N-1</span>].</p>\n<p class=\"p5\">The <span class=\"s2\">rightmostClosed</span> flag, if <span class=\"s2\">T</span>, alters the above behavior to treat the rightmost interval, <span class=\"s2\">vec[N-2]</span> .. <span class=\"s2\">vec[N-1]</span>, as closed.<span class=\"Apple-converted-space\">  </span>This means that if <span class=\"s2\">x[j]==vec[N-1]</span> (i.e., equals <span class=\"s2\">max(vec)</span>), the corresponding result <span class=\"s2\">i[j]</span> will be <span class=\"s2\">N-2</span> as for all other values in the last interval.</p>\n<p class=\"p5\">The <span class=\"s2\">allInside</span> flag, if <span class=\"s2\">T</span>, alters the above behavior to coerce returned indices into <span class=\"s2\">0</span> .. <span class=\"s2\">N-2</span>.<span class=\"Apple-converted-space\">  </span>In other words, <span class=\"s2\">-1</span> is mapped to <span class=\"s2\">0</span>, and <span class=\"s2\">N-1</span> is mapped to <span class=\"s2\">N-2</span>.</p>\n<p class=\"p4\"><span class=\"s5\">(float)pnorm(float q, [numeric mean = 0], [numeric sd = 1])</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>cumulative distribution function values for a normal distribution</b> at quantiles </span><span class=\"s9\">q</span><span class=\"s5\"> with mean </span><span class=\"s9\">mean</span><span class=\"s5\"> and standard deviation </span><span class=\"s9\">sd</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">mean</span><span class=\"s5\"> and </span><span class=\"s9\">sd</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the quantiles, or they may be vectors of the same length as </span><span class=\"s9\">q</span><span class=\"s5\">, specifying a value for each quantile.</span></p>\n<p class=\"p4\"><span class=\"s5\">(float)qnorm(float p, [numeric mean = 0], [numeric sd = 1])</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of <b>quantiles for a normal distribution</b> with lower tail probabilities less than </span><span class=\"s9\">p</span><span class=\"s5\">, with mean </span><span class=\"s9\">mean</span><span class=\"s5\"> and standard deviation </span><span class=\"s9\">sd</span><span class=\"s5\">. The </span><span class=\"s9\">mean</span><span class=\"s5\"> and </span><span class=\"s9\">sd</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the quantiles, or they may be vectors of the same length as </span><span class=\"s9\">p</span><span class=\"s5\">, specifying a value for each quantile computation.</span></p>\n<p class=\"p4\"><span class=\"s5\">(float)rbeta(integer$ n, numeric alpha, numeric beta)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a beta distribution</b> with parameters </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s9\">beta</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s9\">beta</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length </span><span class=\"s9\">n</span><span class=\"s5\">, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>Draws are made from a beta distribution with probability density </span><span class=\"s10\"><i>P</i>(<i>s</i> | <i>α</i>,<i>β</i>) = [Γ(<i>α</i>+<i>β</i>)/Γ(<i>α</i>)Γ(<i>β</i>)]<i>s</i></span><span class=\"s11\"><i><sup>α</sup></i><sup>−1</sup></span><span class=\"s10\">(1−<i>s</i>)</span><span class=\"s11\"><i><sup>β</sup></i><sup>−1</sup></span><span class=\"s5\">, where </span><span class=\"s10\"><i>α</i></span><span class=\"s5\"> is </span><span class=\"s9\">alpha</span><span class=\"s5\"> and </span><span class=\"s10\"><i>β</i></span><span class=\"s5\"> is </span><span class=\"s9\">beta</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Both parameters must be greater than </span><span class=\"s9\">0</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The values drawn are in the interval [0, 1].</span></p>\n<p class=\"p2\">(integer)rbinom(integer$<span class=\"s1\"> </span>n, integer size, float prob)</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a binomial distribution</b> with a number of trials specified by <span class=\"s2\">size</span> and a probability of success specified by <span class=\"s2\">prob</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">size</span> and <span class=\"s2\">prob</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p4\"><span class=\"s5\">(float)rcauchy(integer$ n, [numeric location = 0], [numeric scale = 1])</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a Cauchy distribution</b> with location </span><span class=\"s9\">location</span><span class=\"s5\"> and scale </span><span class=\"s9\">scale</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">location</span><span class=\"s5\"> and </span><span class=\"s9\">scale</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length </span><span class=\"s9\">n</span><span class=\"s5\">, specifying a value for each draw.</span></p>\n<p class=\"p4\">(float)rdirichlet(integer$ n, numeric alpha)</p>\n<p class=\"p5\">Returns a matrix of <span class=\"s2\">n</span> <b>random draws from a Dirichlet distribution</b> with vector of shape parameters <span class=\"s2\">alpha</span>.<span class=\"Apple-converted-space\">  </span>The Dirichlet distribution is a multidimensional generalization of the beta distribution, sometimes called the multivariate beta distribution; see also <span class=\"s2\">rbeta()</span>.<span class=\"Apple-converted-space\">  </span>All values in <span class=\"s2\">alpha</span> must be positive and finite, and <span class=\"s2\">alpha</span> must be of length &gt;= 2.<span class=\"Apple-converted-space\">  </span>The return value is a matrix with <span class=\"s2\">n</span> rows and <span class=\"s2\">size(alpha)</span> columns, each row containing a single Dirichlet random deviate.</p>\n<p class=\"p2\">(integer)rdunif(integer$ n, [integer min = 0], [integer max<span class=\"s1\"> </span>= 1])</p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a discrete uniform distribution</b> from </span><span class=\"s9\">min</span><span class=\"s5\"> to </span><span class=\"s9\">max</span><span class=\"s5\">, inclusive.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">min</span><span class=\"s5\"> and </span><span class=\"s9\">max</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length </span><span class=\"s9\">n</span><span class=\"s5\">, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s9\">runif()</span><span class=\"s5\"> for draws from a continuous uniform distribution</span>, and <span class=\"s2\">runif64()</span> for uniform draws from the full 64-bit <span class=\"s2\">integer</span> range<span class=\"s5\">.</span></p>\n<p class=\"p4\">(integer)rdunif64(integer$ n)</p>\n<p class=\"p5\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a discrete uniform distribution spanning the full 64-bit </b><span class=\"s2\"><b>integer</b></span><b> range</b>.<span class=\"Apple-converted-space\">  </span>See <span class=\"s2\">rdunif()</span> for draws from a discrete uniform distribution with a specified range.</p>\n<p class=\"p2\">(float)rexp(integer$<span class=\"s1\"> </span>n, [numeric mu = 1])</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from an exponential distribution</b> with mean <span class=\"s2\">mu</span> (i.e. rate <span class=\"s2\">1/mu</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">mu</span> parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p4\">(float)rf(integer$ n, numeric d1, numeric d2)</p>\n<p class=\"p5\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from an <i>F</i>-distribution</b> with degrees of freedom <span class=\"s2\">d1</span> and <span class=\"s2\">d2</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">d1</span> and <span class=\"s2\">d2</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p2\">(float)rgamma(integer$<span class=\"s1\"> </span>n, numeric mean, numeric shape)</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a gamma distribution</b> with mean <span class=\"s2\">mean</span> and shape parameter <span class=\"s2\">shape</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">mean</span> and <span class=\"s2\">shape</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>Draws are made from a gamma distribution with probability density <span class=\"s3\"><i>P</i>(<i>s</i> | </span><span class=\"s12\"><i>α</i></span><span class=\"s3\">,</span><span class=\"s12\"><i>β</i></span><span class=\"s3\">) = [</span><span class=\"s12\">Γ</span><span class=\"s3\">(</span><span class=\"s12\"><i>α</i></span><span class=\"s3\">)</span><span class=\"s12\"><i>βα</i></span><span class=\"s3\">]<sup>−1</sup>exp(−<i>s</i>/</span><span class=\"s12\"><i>β</i></span><span class=\"s3\">)</span>, where <span class=\"s12\"><i>α</i></span> is the shape parameter <span class=\"s2\">shape</span>, and the mean of the distribution given by <span class=\"s2\">mean</span> is equal to <span class=\"s12\"><i>αβ</i></span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Values of <span class=\"s2\">mean</span> less than zero are allowed, and are equivalent (in principle) to the negation of a draw from a gamma distribution with the same <span class=\"s2\">shape</span> parameter and the negation of the <span class=\"s2\">mean</span> parameter.</p>\n<p class=\"p4\"><span class=\"s5\">(integer)rgeom(integer$ n, float p)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a geometric distribution</b> with parameter </span><span class=\"s9\">p</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">p</span><span class=\"s5\"> parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length </span><span class=\"s9\">n</span><span class=\"s5\">, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>Eidos follows R in using the geometric distribution with support on the set {0, 1, 2, …}, where the drawn value indicates the number of failures prior to success.<span class=\"Apple-converted-space\">  </span>There is an alternative definition, based upon the number of trial required to get one success, so beware.</span></p>\n<p class=\"p4\">(float)rlaplace(integer$ n, [numeric b = 1])</p>\n<p class=\"p5\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a Laplace distribution</b> with shape parameter <span class=\"s2\">b</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">b</span> parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p2\">(float)rlnorm(integer$<span class=\"s1\"> </span>n, [numeric meanlog = 0], [numeric sdlog = 1])</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a lognormal distribution</b> with mean <span class=\"s2\">meanlog</span> and standard deviation <span class=\"s2\">sdlog</span>, specified on the log scale.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">meanlog</span> and <span class=\"s2\">sdlog</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p4\">(integer)rmultinom(integer$ n, integer$ size, numeric prob)</p>\n<p class=\"p5\">Returns a matrix of <span class=\"s2\">n</span> <b>random vectors from the specified multinomial distribution</b>.<span class=\"Apple-converted-space\">  </span>For each random vector drawn from the multinomial distribution, <span class=\"s2\">size</span> objects will be put into <i>k</i> boxes, where <span class=\"s2\">prob</span> is a vector of probabilities of length <i>k</i> specifying the probability for each box.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">prob</span> is not normalized to sum to <span class=\"s2\">1.0</span>, its entries are treated as weights and normalized appropriately.<span class=\"Apple-converted-space\">  </span>The draws are returned as a matrix with <i>k</i> rows (one row per box) and <span class=\"s2\">n</span> columns (one column per drawn random vector).</p>\n<p class=\"p4\"><span class=\"s5\">(float)rmvnorm(integer$ n, numeric mu, numeric sigma)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns a matrix of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a <i>k</i>-dimensional multivariate normal distribution</b> with a length <i>k</i> mean vector </span><span class=\"s9\">mu</span><span class=\"s5\"> and a <i>k</i> × <i>k</i> variance-covariance matrix </span><span class=\"s9\">sigma</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">mu</span><span class=\"s5\"> and </span><span class=\"s9\">sigma</span><span class=\"s5\"> parameters are used for all </span><span class=\"s9\">n</span><span class=\"s5\"> draws.<span class=\"Apple-converted-space\">  </span>The draws are returned as a matrix with </span><span class=\"s9\">n</span><span class=\"s5\"> rows (one row per draw) and <i>k</i> columns (one column per dimension).<span class=\"Apple-converted-space\">  </span>The number of dimensions <i>k</i> must be at least two; for <i>k</i>=1, use </span><span class=\"s9\">rnorm()</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">Cholesky decomposition of the variance-covariance matrix </span><span class=\"s9\">sigma</span><span class=\"s5\"> is involved as an internal step, and this requires that </span><span class=\"s9\">sigma</span><span class=\"s5\"> be positive-definite; if it is not, an error will result.<span class=\"Apple-converted-space\">  </span>When more than one draw is needed, it is much more efficient to call </span><span class=\"s9\">rmvnorm()</span><span class=\"s5\"> once to generate all of the draws, since the Cholesky decomposition of </span><span class=\"s9\">sigma</span><span class=\"s5\"> can then be done just once.</span></p>\n<p class=\"p4\">(integer)rnbinom(integer$ n, numeric size, float prob)</p>\n<p class=\"p5\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a negative binomial distribution</b> representing the number of failures which occur in a sequence of Bernoulli trials before reaching a target number of successful trials specified by <span class=\"s2\">size</span>, given a probability of success specified by <span class=\"s2\">prob</span>.<span class=\"Apple-converted-space\">  </span>The mean of this distribution for <span class=\"s2\">size</span> <i>s</i> and <span class=\"s2\">prob</span> <i>p</i> is <i>s</i>(1−<i>p</i>)/<i>p</i>, with variance <i>s</i>(1−<i>p</i>)/<i>p</i><span class=\"s13\"><sup>2</sup></span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">size</span> and <span class=\"s2\">prob</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p2\">(float)rnorm(integer$<span class=\"s1\"> </span>n, [numeric mean = 0], [numeric sd = 1])</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a normal distribution</b> with mean <span class=\"s2\">mean</span> and standard deviation <span class=\"s2\">sd</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">mean</span> and <span class=\"s2\">sd</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p2\">(integer)rpois(integer$<span class=\"s1\"> </span>n, numeric lambda)</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a Poisson distribution</b> with parameter <span class=\"s2\">lambda</span> (not to be confused with the language concept of a “lambda”; <span class=\"s2\">lambda</span> here is just the name of a parameter, because the symbol typically used for the parameter of a Poisson distribution is the Greek letter <span class=\"s12\">λ</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">lambda</span> parameter may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length <span class=\"s2\">n</span>, specifying a value for each draw.</p>\n<p class=\"p2\">(float)runif(integer$ n, [numeric min = 0], [numeric max<span class=\"s1\"> </span>= 1])</p>\n<p class=\"p5\"><span class=\"s5\">Returns a vector of </span><span class=\"s9\">n</span><span class=\"s5\"> <b>random draws from a continuous uniform distribution</b> from </span><span class=\"s9\">min</span><span class=\"s5\"> to </span><span class=\"s9\">max</span><span class=\"s5\">, inclusive.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">min</span><span class=\"s5\"> and </span><span class=\"s9\">max</span><span class=\"s5\"> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length </span><span class=\"s9\">n</span><span class=\"s5\">, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s9\">rdunif()</span><span class=\"s5\"> for draws from a discrete uniform distribution.</span></p>\n<p class=\"p2\">(float)rweibull(integer$<span class=\"s1\"> </span>n, numeric lambda, numeric k)</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a Weibull distribution</b> with scale parameter <span class=\"s2\">lambda</span> and shape parameter <span class=\"s2\">k</span>, both greater than zero.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">lambda</span> and <span class=\"s2\">k</span> parameters may either be singletons, specifying a single value to be used for all of the draws, or they may be vectors of length <span class=\"s2\">n</span>, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>Draws are made from a Weibull distribution with probability distribution <span class=\"s3\"><i>P</i>(<i>s</i> | </span><span class=\"s12\"><i>λ</i></span><span class=\"s3\">,<i>k</i>) = (<i>k</i> / </span><span class=\"s12\"><i>λ</i></span><span class=\"s3\"><i><sup>k</sup></i>) <i>s<sup>k</sup></i><sup>−1</sup> exp(-(<i>s</i>/</span><span class=\"s12\"><i>λ</i></span><span class=\"s3\">)<i><sup>k</sup></i>).</span></p>\n<p class=\"p4\">(integer)rztpois(integer$ n, numeric lambda)</p>\n<p class=\"p5\">Returns a vector of <span class=\"s2\">n</span> <b>random draws from a zero-truncated Poisson distribution</b> with parameter <span class=\"s2\">lambda</span> (not to be confused with the language concept of a “lambda”; <span class=\"s2\">lambda</span> here is just the name of a parameter, because the symbol typically used for the parameter of a Poisson distribution is the Greek letter <span class=\"s3\"><i>λ</i></span>).<span class=\"Apple-converted-space\">  </span>The zero-truncated Poisson distribution is the conditional probability distribution of a Poisson-distributed random variable, given that the value of the random variable is not zero.<span class=\"Apple-converted-space\">  </span>The values returned by <span class=\"s2\">rztpois()</span> will therefore never be zero.</p>\n<p class=\"p5\">The <span class=\"s2\">lambda</span> parameter, <span class=\"s3\"><i>λ</i></span>, may either be a singleton, specifying a single value to be used for all of the draws, or it may be a vector of length <span class=\"s2\">n</span>, specifying a value for each draw.<span class=\"Apple-converted-space\">  </span>It is important to note that for <span class=\"s2\">rpois()</span> the expected mean of the distribution is <span class=\"s3\"><i>λ</i></span>, but for <span class=\"s2\">rztpois()</span> the expected mean of the distribution is <span class=\"s3\"><i>λ</i></span> / (1 − exp(−<span class=\"s3\"><i>λ</i></span>)), precisely because the zero-truncated Poisson distribution is conditional upon being non-zero.</p>\n<p class=\"p1\"><b>3.4.<span class=\"Apple-converted-space\">  </span>Vector construction functions</b></p>\n<p class=\"p2\">(*)c(...)</p>\n<p class=\"p3\">Returns the <b>concatenation</b> of all of its parameters into a single vector<span class=\"s14\">, stripped of all matrix/array dimensions (see </span><span class=\"s15\">rbind()</span><span class=\"s14\"> and </span><span class=\"s15\">cbind()</span><span class=\"s14\"> for concatenation that does not strip this information)</span>.<span class=\"Apple-converted-space\">  </span>The parameters will be promoted to the highest type represented among them, and that type will be the return type.<span class=\"Apple-converted-space\">  </span><span class=\"s2\">NULL</span> values are ignored; they have no effect on the result.</p>\n<p class=\"p2\">(float)float(integer$<span class=\"s1\"> </span>length)</p>\n<p class=\"p3\">Returns a <b>new </b><span class=\"s2\"><b>float</b></span><b> vector</b> of the length specified by <span class=\"s2\">length</span>, filled with <span class=\"s2\">0.0</span> values.<span class=\"Apple-converted-space\">  </span>This can be useful for pre-allocating a vector which you then fill with values by subscripting.</p>\n<p class=\"p2\">(integer)integer(integer$<span class=\"s1\"> </span>length, [integer$ fill1 = 0], [integer$ fill2 = 1], [Ni fill2Indices = NULL])</p>\n<p class=\"p3\">Returns a <b>new </b><span class=\"s2\"><b>integer</b></span><b> vector</b> of the length specified by <span class=\"s2\">length</span>, filled with <span class=\"s2\">0</span> values by default.<span class=\"Apple-converted-space\">  </span>This can be useful for pre-allocating a vector which you then fill with values by subscripting.</p>\n<p class=\"p3\">If a value is supplied for <span class=\"s2\">fill1</span>, the new vector will be filled with that value instead of the default of <span class=\"s2\">0</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Additionally, if a non-<span class=\"s2\">NULL</span> vector is supplied for <span class=\"s2\">fill2Indices</span>, the indices specified by <span class=\"s2\">fill2Indices</span> will be filled with the value provided by <span class=\"s2\">fill2</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>For example, given the default values of <span class=\"s2\">0</span> and <span class=\"s2\">1</span> for <span class=\"s2\">fill1</span> and <span class=\"s2\">fill2</span>, the returned vector will contain <span class=\"s2\">1</span> at all positions specified by <span class=\"s2\">fill2Indices</span>, and will contain <span class=\"s2\">0</span> at all other positions.</p>\n<p class=\"p2\">(logical)logical(integer$<span class=\"s1\"> </span>length)</p>\n<p class=\"p3\">Returns a <b>new </b><span class=\"s2\"><b>logical</b></span><b> vector</b> of the length specified by <span class=\"s2\">length</span>, filled with <span class=\"s2\">F</span> values.<span class=\"Apple-converted-space\">  </span>This can be useful for pre-allocating a vector which you then fill with values by subscripting.</p>\n<p class=\"p2\">(object&lt;Object&gt;)object(void)</p>\n<p class=\"p3\">Returns a <b>new empty </b><span class=\"s2\"><b>object</b></span><b> vector</b>.<span class=\"Apple-converted-space\">  </span>Unlike <span class=\"s2\">float()</span>, <span class=\"s2\">integer()</span>, <span class=\"s2\">logical()</span>, and <span class=\"s2\">string()</span>, a length cannot be specified and the new vector contains no elements.<span class=\"Apple-converted-space\">  </span>This is because there is no default value for the object type.<span class=\"Apple-converted-space\">  </span>Adding to such a vector is typically done with <span class=\"s2\">c()</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Note that the return value is of type <span class=\"s2\">object&lt;Object&gt;</span>; this method creates an <span class=\"s2\">object</span> vector that does not know what element type it contains.<span class=\"Apple-converted-space\">  </span>Such <span class=\"s2\">object</span> vectors may be mixed freely with other <span class=\"s2\">object</span> vectors in <span class=\"s2\">c()</span> and similar contexts; the result of such mixing will take its <span class=\"s2\">object</span>-element type from the <span class=\"s2\">object</span> vector with a defined <span class=\"s2\">object</span>-element type (if any).</p>\n<p class=\"p2\">(*)rep(*<span class=\"s1\"> </span>x, integer$<span class=\"s1\"> </span>count)</p>\n<p class=\"p3\">Returns the <b>repetition</b> of <span class=\"s2\">x</span>: the entirety of <span class=\"s2\">x</span> is repeated <span class=\"s2\">count</span> times.<span class=\"Apple-converted-space\">  </span>The return type matches the type of <span class=\"s2\">x</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(*)repEach(*<span class=\"s1\"> </span>x, integer<span class=\"s1\"> </span>count)</p>\n<p class=\"p3\">Returns the <b>repetition of elements</b> of <span class=\"s2\">x</span>: each element of <span class=\"s2\">x</span> is repeated.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">count</span> is a singleton, it specifies the number of times that each element of <span class=\"s2\">x</span> will be repeated.<span class=\"Apple-converted-space\">  </span>Otherwise, the length of <span class=\"s2\">count</span> must be equal to the length of <span class=\"s2\">x</span>; in this case, each element of <span class=\"s2\">x</span> is repeated a number of times specified by the corresponding value of <span class=\"s2\">count</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(*)sample(* x, integer$ size, [logical$<span class=\"s1\"> </span>replace = F], [Nif weights = NULL])</p>\n<p class=\"p3\">Returns a vector of <span class=\"s2\">size</span> containing a <b>sample from the elements of </b><span class=\"s2\"><b>x</b></span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">replace</span> is <span class=\"s2\">T</span>, sampling is conducted with replacement (the same element may be drawn more than once); if it is <span class=\"s2\">F</span> (the default), then sampling is done without replacement.<span class=\"Apple-converted-space\">  </span>A vector of weights may be supplied in the optional parameter <span class=\"s2\">weights</span>; if not <span class=\"s2\">NULL</span>, it must be equal in size to <span class=\"s2\">x</span>, all weights must be non-negative, and the sum of the weights must be greater than <span class=\"s2\">0</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">weights</span> is <span class=\"s2\">NULL</span> (the default), then equal weights are used for all elements of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>An error occurs if <span class=\"s2\">sample()</span> runs out of viable elements from which to draw; most notably, if sampling is done without replacement then <span class=\"s2\">size</span> must be at most equal to the size of <span class=\"s2\">x</span>, but if weights of zero are supplied then the restriction on <span class=\"s2\">size</span> will be even more stringent.<span class=\"Apple-converted-space\">  </span>The draws are obtained from the standard Eidos random number generator, which might be shared with the Context.</p>\n<p class=\"p2\">(numeric)seq(numeric$<span class=\"s1\"> </span>from, numeric$<span class=\"s1\"> </span>to, [Nif$<span class=\"s1\"> </span>by<span class=\"s1\"> </span>= NULL], [Ni$<span class=\"s1\"> </span>length = NULL])</p>\n<p class=\"p3\">Returns a <b>sequence</b>, starting at <span class=\"s2\">from</span> and proceeding in the direction of <span class=\"s2\">to</span> until the next value in the sequence would fall beyond <span class=\"s2\">to</span>.<span class=\"Apple-converted-space\">  </span>If the optional parameters <span class=\"s2\">by</span> and <span class=\"s2\">length</span> are both <span class=\"s2\">NULL</span> (the default), the sequence steps by values of <span class=\"s2\">1</span> or <span class=\"s2\">-1</span> (as needed to proceed in the direction of <span class=\"s2\">to</span>).<span class=\"Apple-converted-space\">  </span>A different step value may be supplied with <span class=\"s2\">by</span>, but must have the necessary sign.<span class=\"Apple-converted-space\">  </span>Alternatively, a sequence length may be supplied in <span class=\"s2\">length</span>, in which case the step magnitude will be chosen to produce a sequence of the requested length (with the necessary sign, as before).<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">from</span> and <span class=\"s2\">to</span> are both <span class=\"s2\">integer</span> then the return type will be <span class=\"s2\">integer</span> when possible (but this may not be possible, depending upon values supplied for <span class=\"s2\">by</span> or <span class=\"s2\">length</span>), otherwise it will be <span class=\"s2\">float</span><span class=\"s3\">.</span></p>\n<p class=\"p4\"><span class=\"s5\">(integer)seqAlong(* x)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns an <b>index sequence along </b></span><span class=\"s9\"><b>x</b></span><span class=\"s5\">, from </span><span class=\"s9\">0</span><span class=\"s5\"> to </span><span class=\"s9\">size(x) - 1</span><span class=\"s5\">, with a step of </span><span class=\"s9\">1</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>This is a convenience function for easily obtaining a set of indices to address or iterate through a vector.<span class=\"Apple-converted-space\">  </span>Any matrix/array dimension information is ignored; the index sequence is suitable for indexing into </span><span class=\"s9\">x</span><span class=\"s5\"> as a vector.</span></p>\n<p class=\"p4\"><span class=\"s5\">(integer)seqLen(integer$ length)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns an <b>index sequence of </b></span><span class=\"s9\"><b>length</b></span><span class=\"s5\">, from </span><span class=\"s9\">0</span><span class=\"s5\"> to </span><span class=\"s9\">length - 1</span><span class=\"s5\">, with a step of </span><span class=\"s9\">1</span><span class=\"s5\">; if </span><span class=\"s9\">length</span><span class=\"s5\"> is </span><span class=\"s9\">0</span><span class=\"s5\"> the sequence will be zero-length.<span class=\"Apple-converted-space\">  </span>This is a convenience function for easily obtaining a set of indices to address or iterate through a vector.<span class=\"Apple-converted-space\">  </span>Note that when </span><span class=\"s9\">length</span><span class=\"s5\"> is </span><span class=\"s9\">0</span><span class=\"s5\">, using the sequence operator with </span><span class=\"s9\">0:(length-1)</span><span class=\"s5\"> will produce </span><span class=\"s9\">0 -1</span><span class=\"s5\">, and calling </span><span class=\"s9\">seq(a, b, length=length)</span><span class=\"s5\"> will raise an error, but </span><span class=\"s9\">seqLen(length)</span><span class=\"s5\"> will return </span><span class=\"s9\">integer(0)</span><span class=\"s5\">, making </span><span class=\"s9\">seqLen()</span><span class=\"s5\"> particularly useful for generating a sequence of a given length that might be zero.</span></p>\n<p class=\"p2\">(string)string(integer$<span class=\"s1\"> </span>length)</p>\n<p class=\"p3\">Returns a <b>new </b><span class=\"s2\"><b>string</b></span><b> vector</b> of the length specified by <span class=\"s2\">length</span>, filled with <span class=\"s2\">\"\"</span> values.<span class=\"Apple-converted-space\">  </span>This can be useful for pre-allocating a vector which you then fill with values by subscripting.</p>\n<p class=\"p1\"><b>3.5.<span class=\"Apple-converted-space\">  </span>Value inspection &amp; manipulation functions</b></p>\n<p class=\"p2\">(logical$)all(logical<span class=\"s1\"> </span>x, ...)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <b>all values are </b><span class=\"s2\"><b>T</b></span> in <span class=\"s2\">x</span> and in any other arguments supplied; if any value is <span class=\"s2\">F</span>, returns <span class=\"s2\">F</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>All arguments must be of <span class=\"s2\">logical</span> type.<span class=\"Apple-converted-space\">  </span>If all arguments are zero-length, <span class=\"s2\">T</span> is returned.</p>\n<p class=\"p4\">(logical$)allClose(float x, float y, [float$ rtol = 1.0e-05], [float$ atol = 1.0e-08], [logical$ equalNAN = F])</p>\n<p class=\"p5\">Returns <span class=\"s2\">T</span> if <b>all pairs of values between </b><span class=\"s2\"><b>x</b></span><b> and y are “close”</b>; if any pair of values is not close, returns <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>The definition of “close” matches that used in the <span class=\"s2\">isClose()</span> function; see that documentation for all further details, including the way that values in <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are paired, as well as the meaning of the <span class=\"s2\">rtol</span>, <span class=\"s2\">atol</span>, and <span class=\"s2\">equalNAN</span> parameters.<span class=\"Apple-converted-space\">  </span>This function is essentially equivalent to <span class=\"s2\">all(isClose(x, y, rtol, atol, equalNAN))</span>, but is more efficient.</p>\n<p class=\"p2\">(logical$)any(logical<span class=\"s1\"> </span>x, ...)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <b>any value is </b><span class=\"s2\"><b>T</b></span> in <span class=\"s2\">x</span> or in any other arguments supplied; if all values are <span class=\"s2\">F</span>, returns <span class=\"s2\">F</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>All arguments must be of <span class=\"s2\">logical</span> type.<span class=\"Apple-converted-space\">  </span>If all arguments are zero-length, <span class=\"s2\">F</span> is returned.</p>\n<p class=\"p2\">(void)cat(*<span class=\"s1\"> </span>x, [string$<span class=\"s1\"> </span>sep<span class=\"s1\"> </span>= \" \"]<span class=\"s6\">, [logical$ error = F]</span>)</p>\n<p class=\"p3\"><b>Concatenates output</b> to Eidos’s output stream, joined together by <span class=\"s2\">sep</span>.<span class=\"Apple-converted-space\">  </span>The value <span class=\"s2\">x</span> that is output may be of any type.<span class=\"Apple-converted-space\">  </span>A newline is not appended to the output, unlike the behavior of <span class=\"s2\">print()</span>; if a trailing newline is desired, you can use <span class=\"s2\">\"\\n\"</span> (or use the <span class=\"s2\">catn()</span> function).<span class=\"Apple-converted-space\">  </span>Also unlike <span class=\"s2\">print()</span>, <span class=\"s2\">cat()</span> tends to emit very literal output; <span class=\"s2\">print(logical(0))</span> will emit “<span class=\"s2\">logical(0)</span>”, for example – showing a semantic interpretation of the value – whereas <span class=\"s2\">cat(logical(0))</span> will emit nothing at all, since there are no elements in the value (it is zero-length).<span class=\"Apple-converted-space\">  </span>Similarly, <span class=\"s2\">print(NULL)</span> will emit “<span class=\"s2\">NULL</span>”, but <span class=\"s2\">cat(NULL)</span> will emit nothing.</p>\n<p class=\"p5\">By default (when <span class=\"s2\">error</span> is <span class=\"s2\">F</span>), the output is sent to the standard Eidos output stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stdout</span>; when running in SLiMgui, this sends it to the simulation window’s output textview.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">error</span> is <span class=\"s2\">T</span>, the output is instead sent to the Eidos error stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stderr</span>; when running in SLiMgui, the output is routed to the simulation’s debugging output window.</p>\n<p class=\"p2\">(void)catn([*<span class=\"s1\"> </span>x<span class=\"s1\"> </span>= \"\"], [string$<span class=\"s1\"> </span>sep<span class=\"s1\"> </span>= \" \"]<span class=\"s6\">, [logical$ error = F]</span>)</p>\n<p class=\"p3\"><b>Concatenates output (with a trailing newline)</b> to Eidos’s output stream, joined together by <span class=\"s2\">sep</span>.<span class=\"Apple-converted-space\">  </span>The behavior of <span class=\"s2\">catn()</span> is identical to that of <span class=\"s2\">cat()</span>, except that a final newline character is appended to the output for convenience.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">catn()</span> a default value of <span class=\"s2\">\"\"</span> is supplied for <span class=\"s2\">x</span>, to allow a simple <span class=\"s2\">catn()</span> call with no parameters to emit a newline.</p>\n<p class=\"p5\">By default (when <span class=\"s2\">error</span> is <span class=\"s2\">F</span>), the output is sent to the standard Eidos output stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stdout</span>; when running in SLiMgui, this sends it to the simulation window’s output textview.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">error</span> is <span class=\"s2\">T</span>, the output is instead sent to the Eidos error stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stderr</span>; when running in SLiMgui, the output is routed to the simulation’s debugging output window.</p>\n<p class=\"p2\">(string)format(string$<span class=\"s1\"> </span>format, numeric x)</p>\n<p class=\"p3\">Returns a vector of <b>formatted strings</b> generated from <span class=\"s2\">x</span>, based upon the formatting string <span class=\"s2\">format</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">format</span> parameter may be any <span class=\"s2\">string</span> value, but must contain exactly one escape sequence beginning with the <span class=\"s2\">%</span> character.<span class=\"Apple-converted-space\">  </span>This escape sequence specifies how to format a single value from the vector <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>The returned vector contains one <span class=\"s2\">string</span> value for each element of <span class=\"s2\">x</span>; each <span class=\"s2\">string</span> value is identical to the string supplied in <span class=\"s2\">format</span>, except with a formatted version of the corresponding value from <span class=\"s2\">x</span> substituted in place of the escape sequence.</p>\n<p class=\"p3\">The syntax for <span class=\"s2\">format</span> is a subset of the standard C/C++ <span class=\"s2\">printf()</span>-style format strings (e.g., http://en.cppreference.com/w/c/io/fprintf).<span class=\"Apple-converted-space\">  </span>The escape sequence used to format each value of x is composed of several elements:</p>\n<ul class=\"ul1\">\n  <li class=\"li6\">–<span class=\"Apple-converted-space\">  </span>A <span class=\"s2\">%</span> character at the beginning, initiating the escape sequence (if an actual <span class=\"s2\">%</span> character is desired, rather than an escape sequence, <span class=\"s2\">%%</span> may be used)</li>\n  <li class=\"li6\">–<span class=\"Apple-converted-space\">  </span>Optional flags that modify the style of formatting:</li>\n</ul>\n<ul class=\"ul1\">\n  <li class=\"li6\"><span class=\"s16\">•<span class=\"Apple-tab-span\">\t</span></span><span class=\"s2\">-</span> :<span class=\"Apple-tab-span\">\t</span>The value is left-justified with the field (as opposed to the default of right-justification).</li>\n  <li class=\"li6\"><span class=\"s16\">•<span class=\"Apple-tab-span\">\t</span></span><span class=\"s2\">+</span> :<span class=\"Apple-tab-span\">\t</span>The sign of the value is always prepended, even if the value is positive (as opposed to the default of appending the sign only if the value is negative).</li>\n  <li class=\"li6\"><span class=\"s17\">•<span class=\"Apple-tab-span\">\t</span></span><i>space</i> :<span class=\"Apple-tab-span\">\t</span>The value is prepended by a space when a sign is not prepended.<span class=\"Apple-converted-space\">  </span>This is ignored if the <span class=\"s2\">+</span> flag is present, since values are then always prepended by a sign.</li>\n  <li class=\"li6\"><span class=\"s16\">•<span class=\"Apple-tab-span\">\t</span></span><span class=\"s2\">#</span> :<span class=\"Apple-tab-span\">\t</span>An alternative format is used.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">%o</span>, at least one leading zero is always produced.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">%x</span> and <span class=\"s2\">%X</span>, <span class=\"s2\">0x</span> or <span class=\"s2\">0X</span> (respectively) is prepended if the value is nonzero.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">%f</span>, <span class=\"s2\">%F</span>, <span class=\"s2\">%e</span>, <span class=\"s2\">%E</span>, <span class=\"s2\">%g</span>, and <span class=\"s2\">%G</span>, a decimal point is forced even if no zeros follow.</li>\n  <li class=\"li6\"><span class=\"s16\">•<span class=\"Apple-tab-span\">\t</span></span><span class=\"s2\">0</span> :<span class=\"Apple-tab-span\">\t</span>Leading zeros are used to pad the field instead of spaces.<span class=\"Apple-converted-space\">  </span>This flag is ignored if the left-justification flag, <span class=\"s2\">-</span>, is present.<span class=\"Apple-converted-space\">  </span>It is also ignored for <span class=\"s2\">integer</span> values, if a precision is specified.</li>\n</ul>\n<ul class=\"ul1\">\n  <li class=\"li6\">–<span class=\"Apple-converted-space\">  </span>An optional minimum field width, specified as an integer value.<span class=\"Apple-converted-space\">  </span>Fields will be padded out to this minimum width.<span class=\"Apple-converted-space\">  </span>Padding will be done with space characters by default (or with zeros, if the <span class=\"s2\">0</span> flag is used), on the left by default (or on the right, if the <span class=\"s2\">-</span> flag is used).</li>\n  <li class=\"li6\">–<span class=\"Apple-converted-space\">  </span>An optional precision, given as an integer value preceded by a <span class=\"s2\">.</span> character.<span class=\"Apple-converted-space\">  </span>If no integer value follows the <span class=\"s2\">.</span> character, a precision of zero will be used.<span class=\"Apple-converted-space\">  </span>For integer values of <span class=\"s2\">x</span> (formatted with <span class=\"s2\">%d</span>, <span class=\"s2\">%i</span>, <span class=\"s2\">%o</span>, <span class=\"s2\">%x</span>, or <span class=\"s2\">%X</span>) the precision specifies the minimum number of digits that will appear (with extra zeros on the left if necessary), with a default precision of <span class=\"s2\">1</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>For float values of <span class=\"s2\">x</span> formatted with <span class=\"s2\">%f</span>, <span class=\"s2\">%F</span>, <span class=\"s2\">%e</span>, <span class=\"s2\">%E</span>, <span class=\"s2\">%g</span>, or <span class=\"s2\">%G</span>, the precision specifies the minimum number of digits that will appear to the right of the decimal point (with extra zeros on the right if necessary), with a default precision of <span class=\"s2\">6</span><span class=\"s3\">.</span></li>\n  <li class=\"li6\">–<span class=\"Apple-converted-space\">  </span>A format specifier.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">integer</span> values, this may be <span class=\"s2\">%d</span> or <span class=\"s2\">%i</span> (producing base-10 output; there is no difference between the two), <span class=\"s2\">%o</span> (producing base-8 or octal output), <span class=\"s2\">%x</span> (producing base-16 hexadecimal output using lowercase letters), or <span class=\"s2\">%X</span> (producing base-16 hexadecimal output using uppercase letters).<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">float</span> values, this may be <span class=\"s2\">%f</span> or <span class=\"s2\">%F</span> to produce decimal notation (of the form <span class=\"s2\">[−]ddd.ddd</span>; there is no difference between the two), <span class=\"s2\">%e</span> or <span class=\"s2\">%E</span> to produce scientific notation (of the form <span class=\"s2\">[−]d.ddde±dd</span> or <span class=\"s2\">[−]d.dddE±dd</span>, respectively), or <span class=\"s2\">%g</span> or <span class=\"s2\">%G</span> to produce either decimal notation or scientific notation (using the formatting of <span class=\"s2\">%f</span> / <span class=\"s2\">%e</span> or <span class=\"s2\">%F</span> / <span class=\"s2\">%E</span>, respectively) on a per-value basis, depending upon the range of the value.</li>\n</ul>\n<p class=\"p3\">Note that relative to the standard C/C++ <span class=\"s2\">printf()</span>-style behavior, there are a few differences: (1) only a single escape sequence may be present in the format string, (2) the use of <span class=\"s2\">*</span> to defer field width and precision values to a passed parameter is not supported, (3) only <span class=\"s2\">integer</span> and <span class=\"s2\">float</span> values of <span class=\"s2\">x</span> are supported, (4) only the <span class=\"s2\">%d</span>, <span class=\"s2\">%i</span>, <span class=\"s2\">%o</span>, <span class=\"s2\">%x</span>, <span class=\"s2\">%X</span>, <span class=\"s2\">%f</span>, <span class=\"s2\">%F</span>, <span class=\"s2\">%e</span>, <span class=\"s2\">%E</span>, <span class=\"s2\">%g</span>, and <span class=\"s2\">%G</span> format specifiers are supported, and (5) no length modifiers may be supplied, since Eidos does not support different sizes of the <span class=\"s2\">integer</span> and <span class=\"s2\">float</span> types.<span class=\"Apple-converted-space\">  </span>Note also that the Eidos conventions of emitting <span class=\"s2\">INF</span> and <span class=\"s2\">NAN</span> for infinities and Not-A-Number values respectively is not honored by this function; the strings generated for such values are platform-dependent, following the implementation definition of the C++ compiler used to build Eidos, since <span class=\"s2\">format()</span> calls through to <span class=\"s2\">snprintf()</span> to assemble the final string values.</p>\n<p class=\"p3\">For example, <span class=\"s2\">format(\"A number: %+7.2f\", c(-4.1, 15.375, 8))</span> will produce a vector with three elements: <span class=\"s2\">\"A number: <span class=\"Apple-converted-space\">  </span>-4.10\" \"A number:<span class=\"Apple-converted-space\">  </span>+15.38\" \"A number: <span class=\"Apple-converted-space\">  </span>+8.00\"</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The precision of <span class=\"s2\">.2</span> results in two digits after the decimal point, the minimum field width of <span class=\"s2\">7</span> results in padding of the values on the left (with spaces) to a minimum of seven characters, the flag <span class=\"s2\">+</span> causes a sign to be shown on positive values as well as negative values, and the format specifier <span class=\"s2\">f</span> leads to the <span class=\"s2\">float</span> values of <span class=\"s2\">x</span> being formatted in base-10 decimal.<span class=\"Apple-converted-space\">  </span>One <span class=\"s2\">string</span> value is produced in the result vector for each value in the parameter <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>These values could then be merged into a single string with <span class=\"s2\">paste()</span>, for example, or printed with <span class=\"s2\">print()</span> or <span class=\"s2\">cat()</span><span class=\"s3\">.</span></p>\n<p class=\"p4\">(logical$)identical(* x, * y, ...)</p>\n<p class=\"p5\">Returns a <span class=\"s2\">logical</span> value indicating <b>whether two or more values are identical</b>.<span class=\"Apple-converted-space\">  </span>For two values <span class=\"s2\">x</span> and <span class=\"s2\">y</span>, this will return <span class=\"s2\">T</span> if <span class=\"s2\">x</span> and <span class=\"s2\">y</span> have exactly the same type and size, and all of their corresponding elements are exactly the same, and (for matrices and arrays) their dimensions are identical; otherwise it will return <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>Additional parameters beyond <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are compared to x in the same manner, and <span class=\"s2\">T</span> is returned only if all of the parameters are identical.</p>\n<p class=\"p5\">The test here is for <i>exact</i> equality; an <span class=\"s2\">integer</span> value of <span class=\"s2\">1</span> is not considered identical to a <span class=\"s2\">float</span> value of <span class=\"s2\">1.0</span>, for example.<span class=\"Apple-converted-space\">  </span>Elements in <span class=\"s2\">object</span> values must be literally the same element, not simply identical in all of their properties.<span class=\"Apple-converted-space\">  </span>Type promotion is never done.<span class=\"Apple-converted-space\">  </span>For testing whether two values are the same, this is generally preferable to the use of operator <span class=\"s2\">==</span> or operator <span class=\"s2\">!=</span>; see the discussion at section 2.5.1.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">identical(NULL,NULL)</span> and <span class=\"s2\">identical(NAN, NAN)</span> are both <span class=\"s2\">T</span>.</p>\n<p class=\"p2\">(*)ifelse(logical test, * trueValues, * falseValues)</p>\n<p class=\"p3\">Returns the result of a <b>vector conditional</b> operation: a vector composed of values from <span class=\"s2\">trueValues</span>, for indices where <span class=\"s2\">test</span> is <span class=\"s2\">T</span>, and values from <span class=\"s2\">falseValues</span>, for indices where <span class=\"s2\">test</span> is <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>The lengths of <span class=\"s2\">trueValues</span> and <span class=\"s2\">falseValues</span> must either be equal to <span class=\"s2\">1</span> or to the length of <span class=\"s2\">test</span>; however, <span class=\"s2\">trueValues</span> and <span class=\"s2\">falseValues</span> don’t need to be the same length as each other.<span class=\"Apple-converted-space\">  </span>Furthermore, the type of <span class=\"s2\">trueValues</span> and <span class=\"s2\">falseValues</span> must be the same (including, if they are <span class=\"s2\">object</span> type, their element type).<span class=\"Apple-converted-space\">  </span>The return will be of the same length as <span class=\"s2\">test</span>, and of the same type as <span class=\"s2\">trueValues</span> and <span class=\"s2\">falseValues</span>.<span class=\"Apple-converted-space\">  </span>Each element of the return vector will be taken from the corresponding element of <span class=\"s2\">trueValues</span> if the corresponding element of <span class=\"s2\">test</span> is <span class=\"s2\">T</span>, or from the corresponding element of <span class=\"s2\">falseValues</span> if the corresponding element of <span class=\"s2\">test</span> is <span class=\"s2\">F</span>; if the vector from which the value is to be taken (i.e., <span class=\"s2\">trueValues</span> or <span class=\"s2\">falseValues</span>) has a length of <span class=\"s2\">1</span>, that single value is used repeatedly, recycling the vector.<span class=\"s14\"><span class=\"Apple-converted-space\">  </span>If </span><span class=\"s15\">test</span><span class=\"s14\">, </span><span class=\"s15\">trueValues</span><span class=\"s14\">, and/or </span><span class=\"s15\">falseValues</span><span class=\"s14\"> are matrices or arrays, that will be ignored by </span><span class=\"s15\">ifelse()</span><span class=\"s14\"> <i>except</i> that the result will be of the same dimensionality as </span><span class=\"s15\">test</span><span class=\"s14\">.</span></p>\n<p class=\"p3\">This is quite similar to a function in R of the same name; note, however, that Eidos evaluates all arguments to functions calls immediately, so <span class=\"s2\">trueValues</span> and <span class=\"s2\">falseValues</span> will be evaluated fully regardless of the values in <span class=\"s2\">test</span>, unlike in R.<span class=\"Apple-converted-space\">  </span>Value expressions without side effects are therefore recommended.</p>\n<p class=\"p4\">(logical)isClose(float x, float y, [float$ rtol = 1.0e-05], [float$ atol = 1.0e-08], [logical$ equalNAN = F])</p>\n<p class=\"p5\">Returns a logical vector indicating <b>whether each pair of values in </b><span class=\"s2\"><b>x</b></span><b> and </b><span class=\"s2\"><b>y</b></span><b> are “close”</b>; if any pair of values is not close, returns <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s2\">allClose()</span> function for an efficient way to test whether <i>all</i> pairs of values in <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are close.</p>\n<p class=\"p5\">A pair of values <span class=\"s2\">a</span> and <span class=\"s2\">b</span> is considered “close” according to the following criteria.<span class=\"Apple-converted-space\">  </span>If both <span class=\"s2\">a</span> and <span class=\"s2\">b</span> are finite, they are close if <span class=\"s2\">abs(a − b) &lt;= (atol + rtol * abs(b))</span>.<span class=\"Apple-converted-space\">  </span>If both <span class=\"s2\">a</span> and <span class=\"s2\">b</span> are infinite, they are close if they have the same sign.<span class=\"Apple-converted-space\">  </span>If both <span class=\"s2\">a</span> and <span class=\"s2\">b</span> are <span class=\"s2\">NAN</span>, they are close if <span class=\"s2\">equalNAN</span> is <span class=\"s2\">T</span>.<span class=\"Apple-converted-space\">  </span>In all other cases, <span class=\"s2\">a</span> and <span class=\"s2\">b</span> are not close.<span class=\"Apple-converted-space\">  </span>For finite values, <span class=\"s2\">rtol</span> thus defines a relative tolerance, and <span class=\"s2\">atol</span> an absolute tolerance; the relative difference <span class=\"s2\">rtol * abs(b)</span> and the absolute difference <span class=\"s2\">atol</span> are added together and compared against the absolute difference between <span class=\"s2\">a</span> and <span class=\"s2\">b</span> to determine closeness.</p>\n<p class=\"p5\">Note that the default value for <span class=\"s2\">atol</span> is not appropriate when comparing numbers with magnitudes much smaller than one; be sure to select <span class=\"s2\">atol</span> for the use case at hand, especially for defining the threshold below which a non-zero value <span class=\"s2\">a</span> will be considered “close” to a very small or zero value <span class=\"s2\">b</span>.<span class=\"Apple-converted-space\">  </span>Note also that <span class=\"s2\">isClose()</span> is not symmetric in <span class=\"s2\">a</span> and <span class=\"s2\">b</span>; it assumes that b is the reference value for calculating the relative difference.</p>\n<p class=\"p5\">Regarding how values in <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are paired, three cases are supported.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are the same length, then <span class=\"s2\">x</span> and <span class=\"s2\">y</span> are paired element-wise; if <span class=\"s2\">x</span> is singleton, the single <span class=\"s2\">x</span> value is paired with each value in <span class=\"s2\">y</span>; or if <span class=\"s2\">y</span> is singleton, each value in <span class=\"s2\">x</span> is paired with the single <span class=\"s2\">y</span> value.</p>\n<p class=\"p4\"><span class=\"s5\">(integer$)length(* x)</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns the <b>size</b> (e.g., length) of </span><span class=\"s9\">x</span><span class=\"s5\">: the number of elements contained in </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Note that </span><span class=\"s9\">length()</span><span class=\"s5\"> is a synonym for </span><span class=\"s9\">size()</span><span class=\"s5\">.</span></p>\n<p class=\"p2\">(integer)match(* x, * table)</p>\n<p class=\"p3\">Returns a vector of the <b>positions of (first) matches</b> of <span class=\"s2\">x</span> in <span class=\"s2\">table</span>.<span class=\"Apple-converted-space\">  </span>Type promotion is not performed; x and <span class=\"s2\">table</span> must be of the same type.<span class=\"Apple-converted-space\">  </span>For each element of <span class=\"s2\">x</span>, the corresponding element in the result will give the position of the first match for that element of <span class=\"s2\">x</span> in <span class=\"s2\">table</span>; if the element has no match in <span class=\"s2\">table</span>, the element in the result vector will be <span class=\"s2\">-1</span>.<span class=\"Apple-converted-space\">  </span>The result is therefore a vector of the same length as <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If a <span class=\"s2\">logical</span> result is desired, with <span class=\"s2\">T</span> indicating that a match was found for the corresponding element of <span class=\"s2\">x</span>, use <span class=\"s2\">(match(x, table) &gt;= 0)</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(integer)order(+ x, [logical$<span class=\"s1\"> </span>ascending<span class=\"s1\"> </span>= T])</p>\n<p class=\"p3\">Returns a <b>vector of sorting indices</b> for <span class=\"s2\">x</span>: a new <span class=\"s2\">integer</span> vector of the same length as <span class=\"s2\">x</span>, containing the indices into <span class=\"s2\">x</span> that would sort <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>In other words, <span class=\"s2\">x[order(x)]==sort(x)</span>.<span class=\"Apple-converted-space\">  </span>This can be useful for more complex sorting problems, such as sorting several vectors in parallel by a sort order determined by one of the vectors.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s2\">logical</span> parameter <span class=\"s2\">ascending</span> is <span class=\"s2\">T</span> (the default), then the sorted order will be ascending; if it is <span class=\"s2\">F</span>, the sorted order will be descending.<span class=\"Apple-converted-space\">  </span>The ordering is determined according to the same logic as the <span class=\"s2\">&lt;</span> and <span class=\"s2\">&gt;</span> operators in Eidos.<span class=\"Apple-converted-space\">  </span>To easily sort vectors in a single step, use <span class=\"s2\">sort()</span> or <span class=\"s2\">sortBy()</span>, for non-<span class=\"s2\">object</span> and <span class=\"s2\">object</span> vectors respectively.</p>\n<p class=\"p4\">(string$)paste(..., [string$ sep = \" \"])</p>\n<p class=\"p5\">Returns a <b>joined string</b> composed from the <span class=\"s2\">string</span> representations of the elements of the parameters passed in, taken in order, joined together by <span class=\"s2\">sep</span>.<span class=\"Apple-converted-space\">  </span>Although this function is based upon the R <span class=\"s2\">paste()</span> function of the same name, note that it is much simpler and less powerful; in particular, the result is always a singleton <span class=\"s2\">string</span>, rather than returning a non-singleton <span class=\"s2\">string</span> vector when one of the parameters is a non-singleton.<span class=\"Apple-converted-space\">  </span>The string representation used by <span class=\"s2\">paste()</span> is the same as that emitted by <span class=\"s2\">cat()</span>.</p>\n<p class=\"p4\">(string$)paste0(...)</p>\n<p class=\"p5\">Returns a <b>joined string</b> composed from the <span class=\"s2\">string</span> representations of the elements of the parameters passed in, taken in order, joined together with no separator.<span class=\"Apple-converted-space\">  </span>This function is identical to <span class=\"s2\">paste()</span>, except that no separator is used.<span class=\"Apple-converted-space\">  </span>Note that this differs from the semantics of <span class=\"s2\">paste0()</span> in R.</p>\n<p class=\"p4\"><span class=\"s6\">(void)print(*</span><span class=\"s18\"> </span><span class=\"s6\">x</span>, [logical$ error = F]<span class=\"s6\">)</span></p>\n<p class=\"p3\"><b>Prints output</b> to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>The value <span class=\"s2\">x</span> that is output may be of any type.<span class=\"Apple-converted-space\">  </span>A newline is appended to the output.<span class=\"Apple-converted-space\">  </span>See <span class=\"s2\">cat()</span> for a discussion of the differences between <span class=\"s2\">print()</span> and <span class=\"s2\">cat()</span><span class=\"s3\">.</span></p>\n<p class=\"p5\">By default (when <span class=\"s2\">error</span> is <span class=\"s2\">F</span>), the output is sent to the standard Eidos output stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stdout</span>; when running in SLiMgui, this sends it to the simulation window’s output textview.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">error</span> is <span class=\"s2\">T</span>, the output is instead sent to the Eidos error stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stderr</span>; when running in SLiMgui, the output is routed to the simulation’s debugging output window.</p>\n<p class=\"p2\">(*)rev(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>reverse</b> of <span class=\"s2\">x</span>: a new vector with the same elements as <span class=\"s2\">x</span>, but in the opposite order.</p>\n<p class=\"p2\">(integer$)size(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>size</b> of <span class=\"s2\">x</span>: the number of elements contained in <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"s14\"><span class=\"Apple-converted-space\">  </span>Note that </span><span class=\"s15\">length()</span><span class=\"s14\"> is a synonym for </span><span class=\"s15\">size()</span><span class=\"s14\">.</span></p>\n<p class=\"p2\">(+)sort(+ x, [logical$<span class=\"s1\"> </span>ascending<span class=\"s1\"> </span>= T])</p>\n<p class=\"p3\">Returns a <b>sorted copy</b> of <span class=\"s2\">x</span>: a new vector with the same elements as <span class=\"s2\">x</span>, but in sorted order.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s2\">logical</span> parameter <span class=\"s2\">ascending</span> is <span class=\"s2\">T</span> (the default), then the sorted order will be ascending; if it is <span class=\"s2\">F</span>, the sorted order will be descending.<span class=\"Apple-converted-space\">  </span>The ordering is determined according to the same logic as the <span class=\"s2\">&lt;</span> and <span class=\"s2\">&gt;</span> operators in Eidos.<span class=\"Apple-converted-space\">  </span>To sort an <span class=\"s2\">object</span> vector, use <span class=\"s2\">sortBy()</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>To obtain indices for sorting, use <span class=\"s2\">order()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(object)sortBy(object x, string$<span class=\"s1\"> </span>property, [logical$<span class=\"s1\"> </span>ascending<span class=\"s1\"> </span>= T])</p>\n<p class=\"p3\">Returns a <b>sorted copy</b> of <span class=\"s2\">x</span>: a new vector with the same elements as <span class=\"s2\">x</span>, but in sorted order.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s2\">logical</span> parameter <span class=\"s2\">ascending</span> is <span class=\"s2\">T</span> (the default), then the sorted order will be ascending; if it is <span class=\"s2\">F</span>, the sorted order will be descending.<span class=\"Apple-converted-space\">  </span>The ordering is determined according to the same logic as the <span class=\"s2\">&lt;</span> and <span class=\"s2\">&gt;</span> operators in Eidos.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">property</span> argument gives the name of the property within the elements of <span class=\"s2\">x</span> according to which sorting should be done.<span class=\"Apple-converted-space\">  </span>This must be a simple property name; it cannot be a property path.<span class=\"Apple-converted-space\">  </span>For example, to sort a <span class=\"s2\">Mutation</span> vector by the selection coefficients of the mutations, you would simply pass <span class=\"s2\">\"selectionCoeff\"</span>, including the quotes, for <span class=\"s2\">property</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>To sort a non-<span class=\"s2\">object</span> vector, use <span class=\"s2\">sort()</span>.<span class=\"Apple-converted-space\">  </span>To obtain indices for sorting, use <span class=\"s2\">order()</span><span class=\"s3\">.</span></p>\n<p class=\"p4\"><span class=\"s6\">(void)str(*</span><span class=\"s18\"> </span><span class=\"s6\">x</span>, [logical$ error = F]<span class=\"s6\">)</span></p>\n<p class=\"p3\"><b>Prints the structure</b> of <span class=\"s2\">x</span>: a summary of its type and the values it contains.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is an <span class=\"s2\">object</span><span class=\"s3\">,</span> note that <span class=\"s2\">str()</span> produces different results from the <span class=\"s2\">str()</span> method of <span class=\"s2\">x</span>; the <span class=\"s2\">str()</span> function prints the external structure of <span class=\"s2\">x</span> (the fact that it is an object, and the number and type of its elements), whereas the <span class=\"s2\">str()</span> method prints the internal structure of <span class=\"s2\">x</span> (the external structure of all the properties contained by <span class=\"s2\">x</span>).</p>\n<p class=\"p5\">By default (when <span class=\"s2\">error</span> is <span class=\"s2\">F</span>), the output is sent to the standard Eidos output stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stdout</span>; when running in SLiMgui, this sends it to the simulation window’s output textview.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">error</span> is <span class=\"s2\">T</span>, the output is instead sent to the Eidos error stream.<span class=\"Apple-converted-space\">  </span>When running at the command line, this sends it to <span class=\"s2\">stderr</span>; when running in SLiMgui, the output is routed to the simulation’s debugging output window.</p>\n<p class=\"p4\">(integer)tabulate(integer bin, [Ni$ maxbin = NULL])</p>\n<p class=\"p5\">Returns <b>occurrence counts</b> for each non-negative integer in <span class=\"s2\">bin</span>.<span class=\"Apple-converted-space\">  </span>Occurrence counts are tabulated into bins for each value <span class=\"s2\">0:maxbin</span> in <span class=\"s2\">bin</span>; values outside that range are ignored.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s2\">maxbin</span>, <span class=\"s2\">NULL</span>, is equivalent to passing <span class=\"s2\">maxbin=max(0, bin)</span>; in other words, by default the result vector will be exactly large enough to accommodate counts for every integer in <span class=\"s2\">bin</span>.<span class=\"Apple-converted-space\">  </span>In any case, the result vector will contain <span class=\"s2\">maxbin+1</span> elements (some or all of which might be zero, if the occurrence count of that integer in <span class=\"s2\">bin</span> is zero).</p>\n<p class=\"p5\">Note that the semantics of this function differ slightly from the <span class=\"s2\">tabulate()</span> function in R, because R is <span class=\"s2\">1</span>-based and Eidos is <span class=\"s2\">0</span>-based.</p>\n<p class=\"p2\">(*)unique(* x, [logical$ preserveOrder = T])</p>\n<p class=\"p3\">Returns the <b>unique values</b> in <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>In other words, for each value <span class=\"s2\">k</span> in <span class=\"s2\">x</span> that occurs at least once, the vector returned will contain <span class=\"s2\">k</span> exactly once.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">preserveOrder</span> is <span class=\"s2\">T</span> (the default), the order of values in <span class=\"s2\">x</span> is preserved, taking the first instance of each value; this is relatively slow, with O(<i>n</i>^2) performance.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">preserveOrder</span> if <span class=\"s2\">F</span> instead, the order of values in <span class=\"s2\">x</span> is not preserved, and no particular ordering should be relied upon; this is relatively fast, with O(<i>n</i> log <i>n</i>) performance.<span class=\"Apple-converted-space\">  </span>This performance difference will only matter for large vectors, however; for most applications the default behavior can be retained whether the order of the result matters or not.</p>\n<p class=\"p2\">(integer)which(logical<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>indices of </b><span class=\"s2\"><b>T</b></span><b> values</b> in <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>In other words, if an index <span class=\"s2\">k</span> in <span class=\"s2\">x</span> is <span class=\"s2\">T</span>, then the vector returned will contain <span class=\"s2\">k</span>; if index <span class=\"s2\">k</span> in <span class=\"s2\">x</span> is <span class=\"s2\">F</span>, the vector returned will omit <span class=\"s2\">k</span>.<span class=\"Apple-converted-space\">  </span>One way to look at this is that it converts from a <span class=\"s2\">logical</span> subsetting vector to an <span class=\"s2\">integer</span> (index-based) subsetting vector, without changing which subset positions would be selected.</p>\n<p class=\"p2\">(integer$)whichMax(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>index of the (first) maximum value</b> in <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>In other words, if <span class=\"s2\">k</span> is equal to the maximum value in <span class=\"s2\">x</span>, then the vector returned will contain the index of the first occurrence of <span class=\"s2\">k</span> in <span class=\"s2\">x</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If the maximum value is unique, the result is the same as (but more efficient than) the expression <span class=\"s2\">which(x==max(x))</span>, which returns the indices of <i>all</i> of the occurrences of the maximum value in <span class=\"s2\">x</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(integer$)whichMin(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>index of the (first) minimum value</b> in <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>In other words, if <span class=\"s2\">k</span> is equal to the minimum value in <span class=\"s2\">x</span>, then the vector returned will contain the index of the first occurrence of <span class=\"s2\">k</span> in <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If the minimum value is unique, the result is the same as (but more efficient than) the expression <span class=\"s2\">which(x==min(x))</span>, which returns the indices of <i>all</i> of the occurrences of the minimum value in <span class=\"s2\">x</span><span class=\"s3\">.</span></p>\n<p class=\"p1\"><b>3.6.<span class=\"Apple-converted-space\">  </span>Value type testing and coercion functions</b></p>\n<p class=\"p2\">(float)asFloat(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>conversion to </b><span class=\"s2\"><b>float</b></span> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is <span class=\"s2\">string</span> and cannot be converted to <span class=\"s2\">float</span>, Eidos will throw an error.</p>\n<p class=\"p2\">(integer)asInteger(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>conversion to </b><span class=\"s2\"><b>integer</b></span> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">string</span> or <span class=\"s2\">float</span> and cannot be converted to <span class=\"s2\">integer</span>, Eidos will throw an error.</p>\n<p class=\"p2\">(logical)asLogical(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>conversion to </b><span class=\"s2\"><b>logical</b></span> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>Recall that in Eidos the empty <span class=\"s2\">string</span> <span class=\"s2\">\"\"</span> is considered <span class=\"s2\">F</span>, and all other <span class=\"s2\">string</span> values are considered <span class=\"s2\">T</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Converting <span class=\"s2\">INF</span> or <span class=\"s2\">-INF</span> to <span class=\"s2\">logical</span> yields <span class=\"s2\">T</span> (since those values are not equal to zero); converting <span class=\"s2\">NAN</span> to <span class=\"s2\">logical</span> throws an error.</p>\n<p class=\"p2\">(string)asString(+<span class=\"s1\"> </span>x)</p>\n<p class=\"p5\"><span class=\"s6\">Returns the <b>conversion to </b></span><span class=\"s7\"><b>string</b></span><span class=\"s6\"> of </span><span class=\"s7\">x</span><span class=\"s8\">.</span><span class=\"s5\"><span class=\"Apple-converted-space\">  </span>Note that </span><span class=\"s9\">asString(NULL)</span><span class=\"s5\"> returns </span><span class=\"s9\">\"NULL\"</span><span class=\"s5\"> even though </span><span class=\"s9\">NULL</span><span class=\"s5\"> is zero-length.</span></p>\n<p class=\"p2\">(string$)elementType(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns the <b>element type</b> of <span class=\"s2\">x</span>, as a <span class=\"s2\">string</span>.<span class=\"Apple-converted-space\">  </span>For the non-<span class=\"s2\">object</span> types, the element type is the same as the type: <span class=\"s2\">\"NULL\"</span>, <span class=\"s2\">\"logical\"</span>, <span class=\"s2\">\"integer\"</span>, <span class=\"s2\">\"float\"</span>, or <span class=\"s2\">\"string\"</span>.<span class=\"Apple-converted-space\">  </span>For <span class=\"s2\">object</span> type, however, <span class=\"s2\">elementType()</span> returns the name of the type of element contained by the object, such as <span class=\"s2\">\"Species\"</span> or <span class=\"s2\">\"Mutation\"</span> in the Context of SLiM.<span class=\"Apple-converted-space\">  </span>Contrast this with <span class=\"s2\">type()</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(logical$)isFloat(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>float</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(logical$)isInteger(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>integer</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(logical$)isLogical(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>logical</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(logical$)isNULL(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>NULL</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(logical$)isObject(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>object</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(logical$)isString(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p3\">Returns <span class=\"s2\">T</span> if <span class=\"s2\">x</span> <b>is </b><span class=\"s2\"><b>string</b></span><b> type</b>, <span class=\"s2\">F</span> otherwise.</p>\n<p class=\"p2\">(string$)type(*<span class=\"s1\"> </span>x)</p>\n<p class=\"p7\"><span class=\"s19\">Returns the <b>type</b> of </span>x<span class=\"s19\">, as a </span>string<span class=\"s19\">: </span>\"NULL\"<span class=\"s19\">, </span>\"logical\"<span class=\"s19\">, </span>\"integer\"<span class=\"s19\">, </span>\"float\"<span class=\"s19\">, </span>\"string\"<span class=\"s19\">, or </span>\"object\"<span class=\"s19\">.<span class=\"Apple-converted-space\">  </span>Contrast this with </span>elementType()<span class=\"s3\">.</span></p>\n<p class=\"p1\"><b>3.7.<span class=\"Apple-converted-space\">  </span>String manipulation functions</b></p>\n<p class=\"p4\">(lis)grep(string$ pattern, string x, [logical$ ignoreCase = F], [string$ grammar = \"ECMAScript\"], [string$ value = \"indices\"], [logical$ fixed = F], [logical$ invert = F])</p>\n<p class=\"p5\">Searches for <b>regular expression matches</b> in the string-elements of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>Regular expressions (regexes) express patterns that strings can either match or not match; they are very widely used in programming languages and terminal shells.<span class=\"Apple-converted-space\">  </span>The topic of regexes is very complex, and a great deal of information about them can be found online, including examples and tutorials; this manual will not attempt to document the topic in detail.</p>\n<p class=\"p5\">The <span class=\"s2\">grep()</span> function uses a regex supplied in <span class=\"s2\">pattern</span>, looking for matches for the regex in each element of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">ignoreCase</span> is <span class=\"s2\">F</span> (the default), the pattern matching will be case sensitive (i.e., uppercase versus lowercase will matter); if it is T, the pattern matching will be case-insensitive.</p>\n<p class=\"p5\">The <span class=\"s2\">grammar</span> parameter determines the regex grammar used to find matches.<span class=\"Apple-converted-space\">  </span>Several options are available.<span class=\"Apple-converted-space\">  </span>The default, <span class=\"s2\">\"ECMAScript\"</span>, is a straightforward regex grammar, the specification for which can be found at <a href=\"https://www.cplusplus.com/reference/regex/ECMAScript/\"><span class=\"s20\">https://www.cplusplus.com/reference/regex/ECMAScript/</span></a> among many other links.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">\"basic\"</span> grammar uses POSIX basic regular expressions, often called BRE; this is documented at <a href=\"https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions\"><span class=\"s20\">https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions</span></a>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">\"extended\"</span> grammar uses POSIX extended regular expressions, often called ERE; this is documented at <a href=\"https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions\"><span class=\"s20\">https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions</span></a>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">\"awk\"</span> grammar is based upon the <span class=\"s2\">\"extended\"</span> grammar, with more escapes for non-printing characters.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">\"grep\"</span> and <span class=\"s2\">\"egrep\"</span> grammars are based upon the <span class=\"s2\">\"basic\"</span> and <span class=\"s2\">\"extended\"</span> grammars, respectively, but also allow newline characters (<span class=\"s2\">\"\\n\"</span>) to separate alternations.<span class=\"Apple-converted-space\">  </span>If you are not sure which grammar you want to use, <span class=\"s2\">\"ECMAScript\"</span> is recommended.<span class=\"Apple-converted-space\">  </span>All of these grammars are implemented internally in Eidos using the C++ <span class=\"s2\">&lt;regex&gt;</span> library, so if you need clarification on the details of a grammar, you can search for related C++ materials online.</p>\n<p class=\"p5\">Information about the matches found is returned in one of four ways.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">value</span> is <span class=\"s2\">\"indices\"</span> (the default), an <span class=\"s2\">integer</span> vector is returned containing the index in <span class=\"s2\">x</span> for each match.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">value</span> is <span class=\"s2\">\"elements\"</span>, a <span class=\"s2\">string</span> vector is returned containing the actual string-elements of <span class=\"s2\">x</span> for each match.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">value</span> is <span class=\"s2\">\"matches\"</span>, a <span class=\"s2\">string</span> vector is returned containing only the substring that matched, within each string-element in <span class=\"s2\">x</span> that matched (if more than one substring in a given element matched, the <i>first</i> match is returned).<span class=\"Apple-converted-space\">  </span>Finally, if <span class=\"s2\">value</span> is <span class=\"s2\">\"logical\"</span> a <span class=\"s2\">logical</span> vector is returned, of the same length as <span class=\"s2\">x</span>, containing <span class=\"s2\">T</span> where the corresponding element of <span class=\"s2\">x</span> matched, or <span class=\"s2\">F</span> where it did not match.<span class=\"Apple-converted-space\">  </span>This function therefore encapsulates the functionality of both the <span class=\"s2\">grep()</span> and <span class=\"s2\">grepl()</span> functions of R; use <span class=\"s2\">value=\"logical\"</span> for functionality like that of R’s <span class=\"s2\">grepl()</span>.</p>\n<p class=\"p5\">If <span class=\"s2\">fixed</span> is <span class=\"s2\">F</span> (the default), matching is determined using <span class=\"s2\">pattern</span> following the specified regex grammar as described above.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">fixed</span> is <span class=\"s2\">T</span>, matching is instead determined using <span class=\"s2\">pattern</span> as a <span class=\"s2\">string</span> value to be matched “as is”, rather than as a regular expression; the <span class=\"s2\">grammar</span> specified does not matter in this case, but <span class=\"s2\">ignoreCase</span> still applies.<span class=\"Apple-converted-space\">  </span>This could be thought of as another <span class=\"s2\">grammar</span> value, really, meaning “no grammar”, but it is supplied as a separate flag following R.</p>\n<p class=\"p5\">Finally, if <span class=\"s2\">invert</span> if <span class=\"s2\">F</span> (the default) matching proceeds as normal for the chosen regex grammar, whereas if <span class=\"s2\">invert</span> if <span class=\"s2\">T</span> matching is inverted: indices, elements, or <span class=\"s2\">logical</span> values are returned for the elements of <span class=\"s2\">x</span> that did <i>not</i> match.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">invert</span> is <span class=\"s2\">T</span>, the <span class=\"s2\">value</span> parameter may not be <span class=\"s2\">\"matches\"</span>.</p>\n<p class=\"p5\">Note that there is not presently any way to extract subpattern matches, nor is there any way to perform replacements of matches.</p>\n<p class=\"p4\">(integer)nchar(string x)</p>\n<p class=\"p5\">Returns a vector of the <b>number of characters</b> in the string-elements of <span class=\"s2\">x</span>.</p>\n<p class=\"p4\">(logical)strcontains(string x, string$ s, [integer$ pos = 0])</p>\n<p class=\"p5\">Returns the <b>occurrence of a string</b> specified by <span class=\"s2\">s</span> in each of the elements of <span class=\"s2\">x</span>, starting at position <span class=\"s2\">pos</span>.<span class=\"Apple-converted-space\">  </span>Position <span class=\"s2\">0</span>, the default, is the beginning of <span class=\"s2\">x</span>; a position of <span class=\"s2\">0</span> means the entire string is searched.<span class=\"Apple-converted-space\">  </span>A starting search position that is at or beyond the end of a given element of <span class=\"s2\">x</span> is not an error; it just implies that a match will not be found in that element.<span class=\"Apple-converted-space\">  </span>The existences of matches are returned as a <span class=\"s2\">logical</span> vector; if a match was found in a given element, the corresponding value in the returned vector is <span class=\"s2\">T</span>, otherwise it is <span class=\"s2\">F</span>.<span class=\"Apple-converted-space\">  </span>This function is a simplified version of <span class=\"s2\">strfind()</span>, which returns the positions of matches.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">strprefix()</span> and <span class=\"s2\">strsuffix()</span> functions are also related.</p>\n<p class=\"p4\">(integer)strfind(string x, string$ s, [integer$ pos = 0])</p>\n<p class=\"p5\">Returns the <b>first occurrence of a string</b> specified by <span class=\"s2\">s</span> in each of the elements of <span class=\"s2\">x</span>, starting at position <span class=\"s2\">pos</span>.<span class=\"Apple-converted-space\">  </span>Position <span class=\"s2\">0</span>, the default, is the beginning of <span class=\"s2\">x</span>; a position of <span class=\"s2\">0</span> means the entire string is searched.<span class=\"Apple-converted-space\">  </span>A starting search position that is at or beyond the end of a given element of <span class=\"s2\">x</span> is not an error; it just implies that a match will not be found in that element.<span class=\"Apple-converted-space\">  </span>The positions of matches are returned as an <span class=\"s2\">integer</span> vector; if no match was found in a given element, the corresponding value in the returned vector is <span class=\"s2\">-1</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">strcontains()</span> function may be used when a logical value (found / not found) is desired.</p>\n<p class=\"p4\">(logical)strprefix(string x, string$ s)</p>\n<p class=\"p5\">Returns the <b>occurrence of a prefix string</b> specified by <span class=\"s2\">s</span> at the beginning of each of the elements of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>The existences of prefixes are returned as a <span class=\"s2\">logical</span> vector; if a given element begins with the prefix, the corresponding value in the returned vector is <span class=\"s2\">T</span>, otherwise it is <span class=\"s2\">F</span>.</p>\n<p class=\"p4\">(string)strsplit(string$ x, [string$ sep = \" \"])</p>\n<p class=\"p5\">Returns <b>substrings</b> of <span class=\"s2\">x</span> that were separated by the separator string <span class=\"s2\">sep</span>.<span class=\"Apple-converted-space\">  </span>Every substring defined by an occurrence of the separator is included, and thus zero-length substrings may be returned.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s2\">strsplit(\".foo..bar.\", \".\")</span> returns a string vector containing <span class=\"s2\">\"\"</span>, <span class=\"s2\">\"foo\"</span>, <span class=\"s2\">\"\"</span>, <span class=\"s2\">\"bar\"</span>, <span class=\"s2\">\"\"</span>.<span class=\"Apple-converted-space\">  </span>In that example, the empty string between <span class=\"s2\">\"foo\"</span> and <span class=\"s2\">\"bar\"</span> in the returned vector is present because there were two periods between <span class=\"s2\">foo</span> and <span class=\"s2\">bar</span> in the input string – the empty string is the substring between those two separators.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">sep</span> is <span class=\"s2\">\"\"</span>, a vector of single characters will be returned, resulting from splitting <span class=\"s2\">x</span> at every position.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">paste()</span> performs the inverse operation of <span class=\"s2\">strsplit()</span>.</p>\n<p class=\"p4\">(logical)strsuffix(string x, string$ s)</p>\n<p class=\"p5\">Returns the <b>occurrence of a suffix string</b> specified by <span class=\"s2\">s</span> at the end of each of the elements of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>The existences of suffixes are returned as a <span class=\"s2\">logical</span> vector; if a given element ends with the suffix, the corresponding value in the returned vector is <span class=\"s2\">T</span>, otherwise it is <span class=\"s2\">F</span>.</p>\n<p class=\"p4\">(string)substr(string x, integer first, [Ni last = NULL])</p>\n<p class=\"p5\">Returns <b>substrings</b> extracted from the elements of <span class=\"s2\">x,</span> spanning character position <span class=\"s2\">first</span> to character position <span class=\"s2\">last</span> (inclusive).<span class=\"Apple-converted-space\">  </span>Character positions are numbered from <span class=\"s2\">0</span> to <span class=\"s2\">nchar(x)-1</span>.<span class=\"Apple-converted-space\">  </span>Positions that fall outside of that range are legal; a substring range that encompasses no characters will produce an empty string.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">first</span> is greater than <span class=\"s2\">last</span>, an empty string will also result.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">last</span> is NULL (the default), then the substring will extend to the end of the string.<span class=\"Apple-converted-space\">  </span>The parameters <span class=\"s2\">first</span> and <span class=\"s2\">last</span> may either be singletons, specifying a single value to be used for all of the substrings, or they may be vectors of the same length as <span class=\"s2\">x</span>, specifying a value for each substring.</p>\n<p class=\"p1\"><b>3.8.<span class=\"Apple-converted-space\">  </span>Matrix and array functions</b></p>\n<p class=\"p2\">(*)apply(* x, integer margin, string$ lambdaSource)</p>\n<p class=\"p8\"><span class=\"s5\"><i>Prior to Eidos 1.6 / SLiM 2.6, </i></span><span class=\"s9\"><i>sapply()</i></span><span class=\"s5\"><i> was named </i></span><span class=\"s9\"><i>apply()</i></span><span class=\"s5\"><i>, and this function did not yet exist</i></span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Applies a block of Eidos code to margins of x</b>.<span class=\"Apple-converted-space\">  </span>This function is essentially an extension of </span><span class=\"s9\">sapply()</span><span class=\"s5\"> for use with matrices and arrays; it is recommended that you fully understand </span><span class=\"s9\">sapply()</span><span class=\"s5\"> before tackling this function.<span class=\"Apple-converted-space\">  </span>As with </span><span class=\"s9\">sapply()</span><span class=\"s5\">, the lambda specified by </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> will be executed for subsets of </span><span class=\"s9\">x</span><span class=\"s5\">, and the results will be concatenated together with type-promotion in the style of </span><span class=\"s9\">c()</span><span class=\"s5\"> to produce a result.<span class=\"Apple-converted-space\">  </span>Unlike </span><span class=\"s9\">sapply()</span><span class=\"s5\">, however, the subsets of </span><span class=\"s9\">x</span><span class=\"s5\"> used might be rows, columns, or higher-dimensional slices of </span><span class=\"s9\">x</span><span class=\"s5\">, rather than just single elements, depending upon the value of </span><span class=\"s9\">margin</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>For </span><span class=\"s9\">apply()</span><span class=\"s5\">, </span><span class=\"s9\">x</span><span class=\"s5\"> must be a matrix or array.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">apply()</span><span class=\"s5\"> function in Eidos is patterned directly after the </span><span class=\"s9\">apply()</span><span class=\"s5\"> function in R, and should behave identically, except that dimension indices in Eidos are zero-based whereas in R they are one-based.</span></p>\n<p class=\"p5\"><span class=\"s5\">The </span><span class=\"s9\">margin</span><span class=\"s5\"> parameter gives the indices of dimensions of </span><span class=\"s9\">x</span><span class=\"s5\"> that will be iterated over when assembling values to supply to lambdaSource.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">x</span><span class=\"s5\"> is a matrix it has two dimensions: rows, of dimension index </span><span class=\"s9\">0</span><span class=\"s5\">, and columns, of dimension index </span><span class=\"s9\">1</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>These are the indices of the dimension sizes returned by </span><span class=\"s9\">dim()</span><span class=\"s5\">; </span><span class=\"s9\">dim(x)[0]</span><span class=\"s5\"> gives the number of rows of </span><span class=\"s9\">x</span><span class=\"s5\">, and </span><span class=\"s9\">dim(x)[1]</span><span class=\"s5\"> gives the number of columns.<span class=\"Apple-converted-space\">  </span>These dimension indices are also apparent when subsetting </span><span class=\"s9\">x</span><span class=\"s5\">; a subset index in position </span><span class=\"s9\">0</span><span class=\"s5\">, such as </span><span class=\"s9\">x[m,]</span><span class=\"s5\">, gives row </span><span class=\"s9\">m</span><span class=\"s5\"> of </span><span class=\"s9\">x</span><span class=\"s5\">, whereas a subset index in position </span><span class=\"s9\">1</span><span class=\"s5\">, such as </span><span class=\"s9\">x[,n]</span><span class=\"s5\">, gives column </span><span class=\"s9\">n</span><span class=\"s5\"> of </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>In the same manner, supplying </span><span class=\"s9\">0</span><span class=\"s5\"> for </span><span class=\"s9\">margin</span><span class=\"s5\"> specifies that subsets of </span><span class=\"s9\">x</span><span class=\"s5\"> from </span><span class=\"s9\">x[0,]</span><span class=\"s5\"> to </span><span class=\"s9\">x[m,]</span><span class=\"s5\"> should be “passed” to </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">, through the </span><span class=\"s9\">applyValue</span><span class=\"s5\"> “parameter”; dimension </span><span class=\"s9\">0</span><span class=\"s5\"> is iterated over, whereas dimension </span><span class=\"s9\">1</span><span class=\"s5\"> is taken in aggregate since it is not included in </span><span class=\"s9\">margin</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The final effect of this is that whole rows of </span><span class=\"s9\">x</span><span class=\"s5\"> are passed to </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> through </span><span class=\"s9\">applyValue</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Similarly, </span><span class=\"s9\">margin=1</span><span class=\"s5\"> would specify that subsets of </span><span class=\"s9\">x</span><span class=\"s5\"> from </span><span class=\"s9\">x[,0]</span><span class=\"s5\"> to </span><span class=\"s9\">x[,n]</span><span class=\"s5\"> should be passed to </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">, resulting in whole columns being passed.<span class=\"Apple-converted-space\">  </span>Specifying </span><span class=\"s9\">margin=c(0,1)</span><span class=\"s5\"> would indicate that dimensions </span><span class=\"s9\">0</span><span class=\"s5\"> and </span><span class=\"s9\">1</span><span class=\"s5\"> should both be iterated over (dimension </span><span class=\"s9\">0</span><span class=\"s5\"> more rapidly), so for a matrix each each individual value of </span><span class=\"s9\">x</span><span class=\"s5\"> would be passed to l</span><span class=\"s9\">ambdaSource</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Specifying </span><span class=\"s9\">margin=c(1,0)</span><span class=\"s5\"> would similarly iterate over both dimensions, but dimension </span><span class=\"s9\">1</span><span class=\"s5\"> more rapidly; the traversal order would therefore be different, and the dimensionality of the result would also differ (see below).<span class=\"Apple-converted-space\">  </span>For higher-dimensional arrays dimension indices beyond </span><span class=\"s9\">1</span><span class=\"s5\"> exist, and so </span><span class=\"s9\">margin=c(0,1)</span><span class=\"s5\"> or </span><span class=\"s9\">margin=c(1,0)</span><span class=\"s5\"> would provide slices of </span><span class=\"s9\">x</span><span class=\"s5\"> to </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">, each slice having a specific row and column index.<span class=\"Apple-converted-space\">  </span>Slices are generated by subsetting in the same way as operator </span><span class=\"s9\">[]</span><span class=\"s5\">, but additionally, redundant dimensions are dropped as by </span><span class=\"s9\">drop()</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">The return value from </span><span class=\"s9\">apply()</span><span class=\"s5\"> is built up from the type-promoted concatenated results, as if by the </span><span class=\"s9\">c()</span><span class=\"s5\"> function, from the iterated execution of </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">; the only question is what dimensional structure is imposed upon that vector of values.<span class=\"Apple-converted-space\">  </span>If the results from </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> are not of a consistent length, or are of length zero, then the concatenated results are returned as a plain vector.<span class=\"Apple-converted-space\">  </span>If all results are of length </span><span class=\"s9\">n &gt; 1</span><span class=\"s5\">, the return value is an array of dimensions </span><span class=\"s9\">c(n, dim(x)[margin]);</span><span class=\"s5\"> in other words, each </span><span class=\"s9\">n</span><span class=\"s5\">-vector provides the lowest dimension of the result, and the sizes of the marginal dimensions are imposed upon the data above that.<span class=\"Apple-converted-space\">  </span>If all results are of length </span><span class=\"s9\">n == 1</span><span class=\"s5\">, then if a single margin was specified the result is a vector (of length equal to the size of that marginal dimension), or if more than one margin was specified the result is an array of dimension </span><span class=\"s9\">dim(x)[margin]</span><span class=\"s5\">; in other words, the sizes of the marginal dimensions are imposed upon the data.<span class=\"Apple-converted-space\">  </span>Since </span><span class=\"s9\">apply()</span><span class=\"s5\"> iterates over the marginal dimensions in the same manner, these structures follows the structure of the data.</span></p>\n<p class=\"p5\"><span class=\"s5\">The above explanation may not be entirely clear, so let’s look at an example.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">x</span><span class=\"s5\"> is a matrix with two rows and three columns, such as defined by </span><span class=\"s9\">x = matrix(1:6, nrow=2);</span><span class=\"s5\">, then executing </span><span class=\"s9\">apply(x, 0, \"sum(applyValue);\");</span><span class=\"s5\"> would cause each row of </span><span class=\"s9\">x</span><span class=\"s5\"> to be supplied to the lambda through </span><span class=\"s9\">applyValue</span><span class=\"s5\">, and the values in each row would thus be summed to produce </span><span class=\"s9\">9 12</span><span class=\"s5\"> as a result.<span class=\"Apple-converted-space\">  </span>The call </span><span class=\"s9\">apply(x, 1, \"sum(applyValue);\");</span><span class=\"s5\"> would instead sum columns of </span><span class=\"s9\">x</span><span class=\"s5\">, producing </span><span class=\"s9\">3 7 11</span><span class=\"s5\"> as a result.<span class=\"Apple-converted-space\">  </span>Now consider using </span><span class=\"s9\">range()</span><span class=\"s5\"> rather than </span><span class=\"s9\">sum()</span><span class=\"s5\"> in the lambda, thus producing two values for each row or column.<span class=\"Apple-converted-space\">  </span>The call </span><span class=\"s9\">apply(x, 0, \"range(applyValue);\");</span><span class=\"s5\"> produces a result of </span><span class=\"s9\">matrix(c(1,5,2,6), nrow=2)</span><span class=\"s5\">, with the range of the first row of </span><span class=\"s9\">x</span><span class=\"s5\">, 1–5, in the first column of the result, and the range of the second row of </span><span class=\"s9\">x</span><span class=\"s5\">, 2–6, in the second column.<span class=\"Apple-converted-space\">  </span>Although visualization becomes more difficult, these same patterns extend to higher dimensions and arbitrary margins of </span><span class=\"s9\">x</span><span class=\"s5\">.</span></p>\n<p class=\"p5\">For efficiently obtaining the sums of the rows or columns of a matrix, see <span class=\"s2\">rowSums()</span> and <span class=\"s2\">colSums()</span>.</p>\n<p class=\"p2\">(*)array(* data, integer dim)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Creates a new array</b> from the data specified by </span><span class=\"s9\">data</span><span class=\"s5\">, with the dimension sizes specified by </span><span class=\"s9\">dim</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The first dimension size in </span><span class=\"s9\">dim</span><span class=\"s5\"> is the number of rows, and the second is the number of columns; further entries specify the sizes of higher-order dimensions.<span class=\"Apple-converted-space\">  </span>As many dimensions may be specified as desired, but with a minimum of two dimensions.<span class=\"Apple-converted-space\">  </span>An array with two dimensions is a matrix (by definition); note that </span><span class=\"s9\">matrix()</span><span class=\"s5\"> may provide a more convenient way to make a new matrix.<span class=\"Apple-converted-space\">  </span>Each dimension must be of size </span><span class=\"s9\">1</span><span class=\"s5\"> or greater; </span><span class=\"s9\">0</span><span class=\"s5\">-size dimensions are not allowed.</span></p>\n<p class=\"p5\"><span class=\"s5\">The elements of </span><span class=\"s9\">data</span><span class=\"s5\"> are used to populate the new array; the size of </span><span class=\"s9\">data</span><span class=\"s5\"> must therefore be equal to the size of the new array, which is the product of all the values in </span><span class=\"s9\">dim</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The new array will be filled in dimension order: one element in each row until a column is filled, then on to the next column in the same manner until all columns are filled, and then onward into the higher-order dimensions in the same manner.</span></p>\n<p class=\"p4\">(*)asVector(* x)</p>\n<p class=\"p5\"><b>Creates a new vector</b> from the elements of <span class=\"s2\">x</span>, stripping off any dimensional information associated with <span class=\"s2\">x</span> being a vector or array.<span class=\"Apple-converted-space\">  </span>The values of the resulting vector are read out from <span class=\"s2\">x</span> in dimension order: one element from each row until a column is completed, then on to the next column in the same manner until all columns are completed, and then onward into the higher-order dimensions in the same manner.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is already a vector, it is returned unmodified.<span class=\"Apple-converted-space\">  </span>See <span class=\"s2\">drop()</span> for a similar method that drops only matrix/array dimensions that are redundant.</p>\n<p class=\"p2\">(*)cbind(...)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Combines vectors or matrices by column</b> to produce a single matrix.<span class=\"Apple-converted-space\">  </span>The parameters must be vectors (which are interpreted by </span><span class=\"s9\">cbind()</span><span class=\"s5\"> as if they were one-column matrices) or matrices.<span class=\"Apple-converted-space\">  </span>They must be of the same type, of the same class if they are of type </span><span class=\"s9\">object</span><span class=\"s5\">, and have the same number of rows.<span class=\"Apple-converted-space\">  </span>If these conditions are met, the result is a single matrix with the parameters joined together, left to right.<span class=\"Apple-converted-space\">  </span>Parameters may instead be </span><span class=\"s9\">NULL</span><span class=\"s5\">, in which case they are ignored; or if all parameters are </span><span class=\"s9\">NULL</span><span class=\"s5\">, the result is </span><span class=\"s9\">NULL</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>A sequence of vectors, matrices, and </span><span class=\"s9\">NULL</span><span class=\"s5\">s may thus be concatenated with the </span><span class=\"s9\">NULL</span><span class=\"s5\"> values removed, analogous to </span><span class=\"s9\">c()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Calling </span><span class=\"s9\">cbind(x)</span><span class=\"s5\"> is an easy way to create a one-column matrix from a vector.</span></p>\n<p class=\"p5\"><span class=\"s5\">To combine vectors or matrices by row instead, see </span><span class=\"s9\">rbind()</span><span class=\"s5\">.</span></p>\n<p class=\"p4\">(numeric)colSums(lif x)</p>\n<p class=\"p5\"><b>Returns the sums of the columns</b> of <span class=\"s2\">x</span>, which must be a matrix.<span class=\"Apple-converted-space\">  </span>The result is a vector of elements, each providing the sum of the corresponding column of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">logical</span> or <span class=\"s2\">integer</span> the result will be of type <span class=\"s2\">integer</span>; unlike the <span class=\"s2\">sum()</span> function, <span class=\"s2\">colSums()</span> does not promote the return type to <span class=\"s2\">float</span> if <span class=\"s2\">integer</span> overflow occurs, but instead throws an error.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">float</span> the result will be of type <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>Except for the change in the treatment of <span class=\"s2\">integer</span> overflow noted above, this is equivalent to using <span class=\"s2\">apply()</span> with <span class=\"s2\">sum()</span> to sum the columns of <span class=\"s2\">x</span>, but is much faster.</p>\n<p class=\"p4\">(numeric$)det(numeric x)</p>\n<p class=\"p5\"><b>Returns the determinant</b> of <span class=\"s2\">x</span>, which must be a square matrix (otherwise an error is raised).<span class=\"Apple-converted-space\">  </span>The determinant is a scalar-valued function of the entries of the matrix, and characterizes some properties of the matrix.<span class=\"Apple-converted-space\">  </span>In particular, the determinant is nonzero if and only if the matrix is invertible.<span class=\"Apple-converted-space\">  </span>If the determinant is zero, the matrix does not have an inverse and is referred to as “singular”.<span class=\"Apple-converted-space\">  </span>In Eidos the determinant is calculated from the <i>LU</i> decomposition of the matrix.<span class=\"Apple-converted-space\">  </span>The return type will match the type of <span class=\"s2\">x</span>.</p>\n<p class=\"p4\">(*)diag([* x = 1], [Ni$ nrow = NULL], [Ni$ ncol = NULL])</p>\n<p class=\"p5\"><b>Returns the diagonal</b> of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>This function has four distinct usage patterns (matching R).<span class=\"Apple-converted-space\">  </span>First, if <span class=\"s2\">x</span> is a matrix of any type, it returns the diagonal elements of <span class=\"s2\">x</span> as a vector; in this case, <span class=\"s2\">nrow</span> and <span class=\"s2\">ncol</span> must be <span class=\"s2\">NULL</span>.<span class=\"Apple-converted-space\">  </span>Second, if <span class=\"s2\">x</span> is <span class=\"s2\">1</span> (the default) and <span class=\"s2\">nrow</span> is non-<span class=\"s2\">NULL</span>, it returns an identity matrix with the requested number of rows (and, if <span class=\"s2\">ncol</span> is also non-<span class=\"s2\">NULL</span>, the requested number of columns, otherwise the matrix will be square).<span class=\"Apple-converted-space\">  </span>Third, if <span class=\"s2\">x</span> is a singleton <span class=\"s2\">integer</span> value and <span class=\"s2\">nrow</span> and <span class=\"s2\">ncol</span> are <span class=\"s2\">NULL</span>, it returns a square identity matrix of size <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>Fourth, if x is a <span class=\"s2\">logical</span>, <span class=\"s2\">integer</span>, or <span class=\"s2\">float</span> vector of length at least <span class=\"s2\">2</span>, it returns a matrix that uses the values of <span class=\"s2\">x</span> as its diagonal (without recycling or truncation, unlike R) and has <span class=\"s2\">F</span>, <span class=\"s2\">0</span>, or <span class=\"s2\">0.0</span> off-diagonal entries as appropriate.</p>\n<p class=\"p5\">Note that using <span class=\"s2\">diag(x)</span>, without <span class=\"s2\">nrow</span> or <span class=\"s2\">ncol</span>, can have unexpected effects if <span class=\"s2\">x</span> is a vector that could be of length one.<span class=\"Apple-converted-space\">  </span>Use <span class=\"s2\">diag(x, nrow=length(x))</span> for consistent behavior.</p>\n<p class=\"p2\">(integer)dim(* x)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the dimensions</b> of matrix or array </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The first dimension value is the number of rows, the second is the number of columns, and further values indicate the sizes of higher-order dimensions, identically to how dimensions are supplied to </span><span class=\"s9\">array()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span></span><span class=\"s9\">NULL</span><span class=\"s5\"> is returned if </span><span class=\"s9\">x</span><span class=\"s5\"> is not a matrix or array.</span></p>\n<p class=\"p2\">(*)drop(* x)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the result of dropping redundant dimensions</b> from matrix or array </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Redundant dimensions are those with a size of exactly 1.<span class=\"Apple-converted-space\">  </span>Non-redundant dimensions are retained.<span class=\"Apple-converted-space\">  </span>If only one non-redundant dimension is present, the result is a vector; if more than one non-redundant dimension is present, the result will be a matrix or array.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">x</span><span class=\"s5\"> is not a matrix or array, it is returned unmodified.</span><span class=\"Apple-converted-space\">  </span>See <span class=\"s2\">asVector()</span> for a way to drop all dimensions of a matrix or array, whether redundant or not.</p>\n<p class=\"p4\">(float)inverse(numeric x)</p>\n<p class=\"p5\"><b>Returns the (multiplicative) inverse</b> of <span class=\"s2\">x</span>, which must be a square non-singular matrix (otherwise an error is raised).<span class=\"Apple-converted-space\">  </span>If matrix <b>B</b> is the inverse of <i>n</i>-by-<i>n</i> matrix <b>A</b>, then <b>AB</b> = <b>BA</b> = <b>I</b><span class=\"s13\"><i><sub>n</sub></i></span>, where <b>I</b><span class=\"s13\"><i><sub>n</sub></i></span> denotes the <i>n</i>-by-<i>n</i> identity matrix and the multiplication used is ordinary matrix multiplication as performed by <span class=\"s2\">matrixMult()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> might be singular (and thus non-invertible), and you wish to avoid the possibility of an error, you can call <span class=\"s2\">det()</span> first to find the determinant of the matrix; if the determinant is zero, the matrix is singular and does not have an inverse, and so <span class=\"s2\">inverse()</span> should not be called.<span class=\"Apple-converted-space\">  </span>In Eidos the inverse is calculated from the <i>LU</i> decomposition of the matrix.</p>\n<p class=\"p4\">(logical)lowerTri(* x, [logical$ diag = F])</p>\n<p class=\"p5\"><b>Returns the lower triangle</b> of <span class=\"s2\">x</span>, which must be a matrix.<span class=\"Apple-converted-space\">  </span>The return value will be a <span class=\"s2\">logical</span> matrix of the same dimensions as <span class=\"s2\">x</span>, with elements <span class=\"s2\">T</span> in the lower triangle, <span class=\"s2\">F</span> elsewhere.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">diag</span> is <span class=\"s2\">F</span> (the default), the diagonal is not included in the lower triangle; if <span class=\"s2\">diag</span> is <span class=\"s2\">T</span>, the diagonal is included in the lower triangle (i.e., its elements will be <span class=\"s2\">T</span>).</p>\n<p class=\"p2\">(*)matrix(* data, [Ni$ nrow = NULL], [Ni$ ncol = NULL], [logical$ byrow = F])</p>\n<p class=\"p5\"><span class=\"s5\"><b>Creates a new matrix</b> from the data specified by </span><span class=\"s9\">data</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>By default this creates a one-column matrix.<span class=\"Apple-converted-space\">  </span>If non-</span><span class=\"s9\">NULL</span><span class=\"s5\"> values are supplied for </span><span class=\"s9\">nrow</span><span class=\"s5\"> and/or </span><span class=\"s9\">ncol</span><span class=\"s5\">, a matrix will be made with the requested number of rows and/or columns if possible; if the length of </span><span class=\"s9\">data</span><span class=\"s5\"> is not compatible with the requested dimensions, an error will result.<span class=\"Apple-converted-space\">  </span>By default, values from data will populate the matrix by columns, filling each column sequentially before moving on to the next column; if </span><span class=\"s9\">byrow</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\"> the matrix will be populated by rows instead.</span></p>\n<p class=\"p2\">(numeric)matrixMult(numeric x, numeric y)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the result of matrix multiplication</b> of </span><span class=\"s9\">x</span><span class=\"s5\"> with </span><span class=\"s9\">y</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>In Eidos (as in R), with two matrices </span><span class=\"s9\">A</span><span class=\"s5\"> and </span><span class=\"s9\">B</span><span class=\"s5\"> the simple product </span><span class=\"s9\">A * B</span><span class=\"s5\"> multiplies the corresponding elements of the matrices; in other words, if </span><span class=\"s9\">X</span><span class=\"s5\"> is the result of </span><span class=\"s9\">A * B</span><span class=\"s5\">, then </span><span class=\"s9\">X</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\"> = </span><span class=\"s9\">A</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\"> * </span><span class=\"s9\">B</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>This is parallel to the definition of other operators; A + B adds the corresponding elements of the matrices (</span><span class=\"s9\">X</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\"> = </span><span class=\"s9\">A</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\"> + </span><span class=\"s9\">B</span><span class=\"s21\"><i><sub>ij</sub></i></span><span class=\"s5\">), etc.<span class=\"Apple-converted-space\">  </span>In R, true matrix multiplication is achieved with a special operator, </span><span class=\"s9\">%*%</span><span class=\"s5\">; in Eidos, the </span><span class=\"s9\">matrixMult()</span><span class=\"s5\"> function is used instead.</span></p>\n<p class=\"p5\"><span class=\"s5\">Both </span><span class=\"s9\">x</span><span class=\"s5\"> and </span><span class=\"s9\">y</span><span class=\"s5\"> must be matrices, and must be conformable according to the standard definition of matrix multiplication (i.e., if </span><span class=\"s9\">x</span><span class=\"s5\"> is an <i>n</i> × <i>m</i> matrix then </span><span class=\"s9\">y</span><span class=\"s5\"> must be a <i>m</i> × <i>p</i> matrix, and the result will be a <i>n</i> × <i>p</i> matrix).<span class=\"Apple-converted-space\">  </span>Vectors will not be promoted to matrices by this function, even if such promotion would lead to a conformable matrix.</span></p>\n<p class=\"p4\">(numeric)matrixPow(numeric x, integer$ power)</p>\n<p class=\"p5\"><b>Returns the result of raising matrix </b><span class=\"s2\"><b>x</b></span><b> to an </b><span class=\"s2\"><b>integer</b></span><b> </b><span class=\"s2\"><b>power</b></span><b>.</b><span class=\"Apple-converted-space\">  </span>The parameter x must be a square matrix (or an error will be raised).<span class=\"Apple-converted-space\">  </span>This operation is performed by repeated matrix multiplication with <span class=\"s2\">matrixMult()</span>, and uses <span class=\"s2\">inverse()</span> to compute the inverse of the matrix if <span class=\"s2\">power</span> is negative.</p>\n<p class=\"p2\">(integer$)nrow(* x)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the number of rows</b> in matrix or array </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>For vector </span><span class=\"s9\">x</span><span class=\"s5\">, </span><span class=\"s9\">nrow()</span><span class=\"s5\"> returns </span><span class=\"s9\">NULL</span><span class=\"s5\">; </span><span class=\"s9\">size()</span><span class=\"s5\"> should be used.<span class=\"Apple-converted-space\">  </span>An equivalent of R’s </span><span class=\"s9\">NROW()</span><span class=\"s5\"> function, which treats vectors as </span><span class=\"s9\">1</span><span class=\"s5\">-column matrices, is not provided but would be trivial to implement as a user-defined function.</span></p>\n<p class=\"p2\">(integer$)ncol(* x)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the number of columns</b> in matrix or array </span><span class=\"s9\">x</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>For vector </span><span class=\"s9\">x</span><span class=\"s5\">, </span><span class=\"s9\">ncol()</span><span class=\"s5\"> returns </span><span class=\"s9\">NULL</span><span class=\"s5\">; </span><span class=\"s9\">size()</span><span class=\"s5\"> should be used.<span class=\"Apple-converted-space\">  </span>An equivalent of R’s </span><span class=\"s9\">NCOL()</span><span class=\"s5\"> function, which treats vectors as </span><span class=\"s9\">1</span><span class=\"s5\">-column matrices, is not provided but would be trivial to implement as a user-defined function.</span></p>\n<p class=\"p4\">(numeric)outerProduct(numeric x, numeric y)</p>\n<p class=\"p5\"><b>Returns the outer product</b> of vectors <span class=\"s2\">x</span> and <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>The outer product, <span class=\"s2\">x</span> <span class=\"s4\">⊗</span> <span class=\"s2\">y</span>, is the result of matrix multiplication of <span class=\"s2\">x</span> with the transpose of <span class=\"s2\">y</span>, or <span class=\"s2\">xy</span><span class=\"s13\"><sup>T</sup></span>.<span class=\"Apple-converted-space\">  </span>It will be a matrix with a number of rows equal to the length of <span class=\"s2\">x</span>, and a number of columns equal to the length of <span class=\"s2\">y</span>.<span class=\"Apple-converted-space\">  </span>It is required that <span class=\"s2\">x</span> and <span class=\"s2\">y</span> be vectors, not matrices or arrays, that they have non-zero lengths, and that they be the same type – both <span class=\"s2\">integer</span> or both <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>The return value will be of the same type as <span class=\"s2\">x</span> and <span class=\"s2\">y</span>.</p>\n<p class=\"p2\">(*)rbind(...)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Combines vectors or matrices by row</b> to produce a single matrix.<span class=\"Apple-converted-space\">  </span>The parameters must be vectors (which are interpreted by </span><span class=\"s9\">rbind()</span><span class=\"s5\"> as if they were one-row matrices) or matrices.<span class=\"Apple-converted-space\">  </span>They must be of the same type, of the same class if they are of type </span><span class=\"s9\">object</span><span class=\"s5\">, and have the same number of columns.<span class=\"Apple-converted-space\">  </span>If these conditions are met, the result is a single matrix with the parameters joined together, top to bottom.<span class=\"Apple-converted-space\">  </span>Parameters may instead be </span><span class=\"s9\">NULL</span><span class=\"s5\">, in which case they are ignored; or if all parameters are </span><span class=\"s9\">NULL</span><span class=\"s5\">, the result is </span><span class=\"s9\">NULL</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>A sequence of vectors, matrices, and </span><span class=\"s9\">NULL</span><span class=\"s5\">s may thus be concatenated with the </span><span class=\"s9\">NULL</span><span class=\"s5\"> values removed, analogous to </span><span class=\"s9\">c()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Calling </span><span class=\"s9\">rbind(x)</span><span class=\"s5\"> is an easy way to create a one-row matrix from a vector.</span></p>\n<p class=\"p5\"><span class=\"s5\">To combine vectors or matrices by column instead, see </span><span class=\"s9\">cbind()</span><span class=\"s5\">.</span></p>\n<p class=\"p4\">(numeric)rowSums(lif x)</p>\n<p class=\"p5\"><b>Returns the sums of the rows</b> of <span class=\"s2\">x</span>, which must be a matrix.<span class=\"Apple-converted-space\">  </span>The result is a vector of elements, each providing the sum of the corresponding row of <span class=\"s2\">x</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">logical</span> or <span class=\"s2\">integer</span> the result will be of type <span class=\"s2\">integer</span>; unlike the <span class=\"s2\">sum()</span> function, <span class=\"s2\">rowSums()</span> does not promote the return type to <span class=\"s2\">float</span> if <span class=\"s2\">integer</span> overflow occurs, but instead throws an error.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is of type <span class=\"s2\">float</span> the result will be of type <span class=\"s2\">float</span>.<span class=\"Apple-converted-space\">  </span>Except for the change in the treatment of <span class=\"s2\">integer</span> overflow noted above, this is equivalent to using <span class=\"s2\">apply()</span> with <span class=\"s2\">sum()</span> to sum the rows of <span class=\"s2\">x</span>, but is much faster.</p>\n<p class=\"p2\">(*)t(* x)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Returns the transpose</b> of </span><span class=\"s9\">x</span><span class=\"s5\">, which must be a matrix.<span class=\"Apple-converted-space\">  </span>This is the matrix reflected across its diagonal; or alternatively, the matrix with its columns written out instead as rows in the same order.</span></p>\n<p class=\"p4\">(numeric$)tr(numeric x)</p>\n<p class=\"p5\"><b>Returns the trace</b> of <span class=\"s2\">x</span>, which must be a square matrix (otherwise an error is raised).<span class=\"Apple-converted-space\">  </span>The trace is the sum of the diagonal elements of the matrix.<span class=\"Apple-converted-space\">  </span>The return type will match the type of <span class=\"s2\">x</span>.</p>\n<p class=\"p4\">(logical)upperTri(* x, [logical$ diag = F])</p>\n<p class=\"p5\"><b>Returns the upper triangle</b> of <span class=\"s2\">x</span>, which must be a matrix.<span class=\"Apple-converted-space\">  </span>The return value will be a <span class=\"s2\">logical</span> matrix of the same dimensions as <span class=\"s2\">x</span>, with elements <span class=\"s2\">T</span> in the upper triangle, <span class=\"s2\">F</span> elsewhere.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">diag</span> is <span class=\"s2\">F</span> (the default), the diagonal is not included in the upper triangle; if <span class=\"s2\">diag</span> is <span class=\"s2\">T</span>, the diagonal is included in the upper triangle (i.e., its elements will be <span class=\"s2\">T</span>).</p>\n<p class=\"p1\"><b>3.9.<span class=\"Apple-converted-space\">  </span>Filesystem access functions</b></p>\n<p class=\"p2\">(logical$)createDirectory(string$ path)</p>\n<p class=\"p3\"><b>Creates a new filesystem directory</b> at the path specified by <span class=\"s2\">path</span> and returns a <span class=\"s2\">logical</span> value indicating if the creation succeeded (<span class=\"s2\">T</span>) or failed (<span class=\"s2\">F</span>).<span class=\"Apple-converted-space\">  </span>If the path already exists, <span class=\"s2\">createDirectory()</span> will do nothing to the filesystem, will emit a warning, and will return <span class=\"s2\">T</span> to indicate success if the existing path is a directory, or <span class=\"s2\">F</span> to indicate failure if the existing path is not a directory.</p>\n<p class=\"p2\">(logical$)deleteFile(string$ filePath)</p>\n<p class=\"p3\"><b>Deletes the file</b> specified by <span class=\"s2\">filePath</span> and returns a <span class=\"s2\">logical</span> value indicating if the deletion succeeded (<span class=\"s2\">T</span>) or failed (<span class=\"s2\">F</span>).</p>\n<p class=\"p5\">This function might also be able to delete a directory at <span class=\"s2\">filePath</span>, but only if it is empty (apart from the <span class=\"s2\">.</span> and <span class=\"s2\">..</span> directory entries that exist on Un*x filesystems).<span class=\"Apple-converted-space\">  </span>If other files (including invisible files) exist in the directory, <span class=\"s2\">deleteFile()</span> will probably fail as a safety measure, in which case the contained files must be deleted individually first.<span class=\"Apple-converted-space\">  </span>This is vague because the actual policy regarding deletion of directories will depend upon the operating system, since Eidos achieves the deletion by calling an operating-system function.</p>\n<p class=\"p4\"><span class=\"s5\">(logical$)fileExists(string$ filePath)</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Checks the existence of the file</b> specified by </span><span class=\"s9\">filePath</span><span class=\"s5\"> and returns a </span><span class=\"s9\">logical</span><span class=\"s5\"> value indicating if it exists (</span><span class=\"s9\">T</span><span class=\"s5\">) or does not exist (</span><span class=\"s9\">F</span><span class=\"s5\">).<span class=\"Apple-converted-space\">  </span>This also works for directories.</span></p>\n<p class=\"p2\">(string)filesAtPath(string$ path, [logical$ fullPaths = F])</p>\n<p class=\"p3\">Returns a <span class=\"s2\">string</span> vector containing the <b>names of all files in a directory</b> specified by <span class=\"s2\">path</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s2\">fullPaths</span> is <span class=\"s2\">T</span>, full filesystem paths are returned for each file; if <span class=\"s2\">fullPaths</span> is <span class=\"s2\">F</span> (the default), then only the filenames relative to the specified directory are returned.<span class=\"Apple-converted-space\">  </span>This list includes directories (i.e. subfolders), including the <span class=\"s2\">\".\"</span> and <span class=\"s2\">\"..\"</span> directories on Un*x systems.<span class=\"Apple-converted-space\">  </span>The list also includes invisible files, such as those that begin with a <span class=\"s2\">\".\"</span> on Un*x systems.<span class=\"Apple-converted-space\">  </span>This function does not descend recursively into subdirectories.<span class=\"Apple-converted-space\">  </span>If an error occurs during the read, <span class=\"s2\">NULL</span> will be returned.</p>\n<p class=\"p4\">(logical$)flushFile(string$ filePath)</p>\n<p class=\"p5\"><b>Flushes buffered content to a file</b> specified by <span class=\"s2\">filePath</span>.<span class=\"Apple-converted-space\">  </span>Normally, written data is buffered by <span class=\"s2\">writeFile()</span> if the <span class=\"s2\">compress</span> option of that function is <span class=\"s2\">T</span>, holding the data in memory rather than writing it to disk immediately.<span class=\"Apple-converted-space\">  </span>This buffering improves both performance and file size; however, sometimes it is desirable to flush the buffered data to disk with <span class=\"s2\">flush()</span> so that the filesystem is up to date.<span class=\"Apple-converted-space\">  </span>Note that flushing after every write is not recommended, since it will lose all of the benefits of buffering.<span class=\"Apple-converted-space\">  </span>Calling <span class=\"s2\">flushFile()</span> for a path that has not been written to, or is not being buffered, will do nothing.<span class=\"Apple-converted-space\">  </span>If the flush is successful, <span class=\"s2\">T</span> will be returned; if not, <span class=\"s2\">F</span> will be returned (but at present, an error will result instead).</p>\n<p class=\"p4\"><span class=\"s5\">(string$)getwd(void)</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Gets the current filesystem working directory</b>.<span class=\"Apple-converted-space\">  </span>The filesystem working directory is the directory which will be used as a base path for relative filesystem paths.<span class=\"Apple-converted-space\">  </span>For example, if the working directory is </span><span class=\"s9\">\"~/Desktop\"</span><span class=\"s5\"> (the </span><span class=\"s9\">Desktop</span><span class=\"s5\"> subdirectory within the current user’s home directory, as represented by </span><span class=\"s9\">~</span><span class=\"s5\">), then the filename </span><span class=\"s9\">\"foo.txt\"</span><span class=\"s5\"> would correspond to the filesystem path </span><span class=\"s9\">\"~/Desktop/foo.txt\"</span><span class=\"s5\">, and the relative path </span><span class=\"s9\">\"bar/baz/\"</span><span class=\"s5\"> would correspond to the filesystem path </span><span class=\"s9\">“~/Desktop/bar/baz/“</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">Note that the path returned may not be identical to the path previously set with </span><span class=\"s9\">setwd()</span><span class=\"s5\">, if for example symbolic links are involved; but it ought to refer to the same actual directory in the filesystem.</span></p>\n<p class=\"p5\"><span class=\"s5\">The initial working directory is – as is generally the case on Un*x – simply the directory given to the running Eidos process by its parent process (the operating system, a shell, a job scheduler, a debugger, or whatever the case may be).<span class=\"Apple-converted-space\">  </span>If you launch Eidos (or SLiM) from the command line in a Un*x shell, it is typically the current directory in that shell.<span class=\"Apple-converted-space\">  </span>Before relative filesystem paths are used, you may therefore wish check what the initial working directory is on your platform, with </span><span class=\"s9\">getwd()</span><span class=\"s5\">, if you are not sure.<span class=\"Apple-converted-space\">  </span>Alternatively, you can simply use </span><span class=\"s9\">setwd()</span><span class=\"s5\"> to set the working directory to a known path.</span></p>\n<p class=\"p4\">(object&lt;DataFrame&gt;$)readCSV(string$ filePath, [ls colNames = T], [Ns$ colTypes = NULL], [string$ sep = \",\"], [string$ quote = '\"'], [string$ dec = \".\"], [string$ comment = \"\"])</p>\n<p class=\"p5\"><b>Reads data from a CSV or other delimited file</b> specified by <span class=\"s2\">filePath</span> and returns a <span class=\"s2\">DataFrame</span> object containing the data in a tabular form.<span class=\"Apple-converted-space\">  </span>CSV (comma-separated value) files use a somewhat standard file format in which a table of data is provided, with values within a row separated by commas, while rows in the table are separated by newlines.<span class=\"Apple-converted-space\">  </span>Software from R to Excel (and Eidos; see the <span class=\"s2\">serialize()</span> method of <span class=\"s2\">Dictionary</span>) can export data in CSV format.<span class=\"Apple-converted-space\">  </span>This function can actually also read files that use a delimiter other than commas; TSV (tab-separated value) files are a popular alternative.<span class=\"Apple-converted-space\">  </span>Since there is substantial variation in the exact file format for CSV files, this documentation will try to specify the precise format expected by this function.<span class=\"Apple-converted-space\">  </span>Note that CSV files represent values differently that Eidos usually does, and some of the format options allowed by <span class=\"s2\">readCSV()</span>, such as decimal commas, are not otherwise available in Eidos.</p>\n<p class=\"p5\">If <span class=\"s2\">colNames</span> is <span class=\"s2\">T</span> (the default), the first row of data is taken to be a header, containing the string names of the columns in the data table; those names will be used by the resulting <span class=\"s2\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">colNames</span> is <span class=\"s2\">F</span>, a header row is not expected and column names are auto-generated as <span class=\"s2\">X1</span>, <span class=\"s2\">X2</span>, etc.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">colNames</span> is a <span class=\"s2\">string</span> vector, a header row is not expected and <span class=\"s2\">colNames</span> will be used as the column names; if additional columns exist beyond the length of <span class=\"s2\">colNames</span> their names will be auto-generated.<span class=\"Apple-converted-space\">  </span>Duplicate column names will generate a warning and be made unique.</p>\n<p class=\"p5\">If <span class=\"s2\">colTypes</span> is <span class=\"s2\">NULL</span> (the default), the value type for each column will be guessed from the values it contains, as described below.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">colTypes</span> is a singleton <span class=\"s2\">string</span>, it should contain single-letter codes indicating the desired type for each column, from left to right.<span class=\"Apple-converted-space\">  </span>The letters <span class=\"s2\">lifs</span> have the same meaning as in Eidos signatures (<span class=\"s2\">logical</span>, <span class=\"s2\">integer</span>, <span class=\"s2\">float</span>, and <span class=\"s2\">string</span>); in addition, <span class=\"s2\">?</span> may be used to indicate that the type for that column should be guessed as by default, and <span class=\"s2\">_</span> or <span class=\"s2\">-</span> may be used to indicate that that column should be skipped – omitted from the returned <span class=\"s2\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>Other characters in <span class=\"s2\">colTypes</span> will result in an error.<span class=\"Apple-converted-space\">  </span>If additional columns exist beyond the end of the <span class=\"s2\">colTypes</span> string their types will be guessed as by default.</p>\n<p class=\"p5\">The separator between values is supplied by <span class=\"s2\">sep</span>; it is a comma by default, but a tab can be used instead by supplying tab (<span class=\"s2\">\"\\t\"</span> in Eidos), or another character may also be used.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">sep</span> is the empty string <span class=\"s2\">\"\"</span>, the separator between values is “whitespace”, meaning one or more spaces or tabs.<span class=\"Apple-converted-space\">  </span>When the separator is whitespace, whitespace at the beginning or the end of a line will be ignored.</p>\n<p class=\"p5\">Similarly, the character used to quote string values is a double quote (<span class=\"s2\">'\"'</span> in Eidos), by default, but another character may be supplied in <span class=\"s2\">quote</span>.<span class=\"Apple-converted-space\">  </span>When the string delimiter is encountered, <i>all</i> following characters are considered to be part of the string until another string delimiter is encountered, terminating the string; this includes spaces, comment characters, newlines, and everything else.<span class=\"Apple-converted-space\">  </span>Within a string value, the string delimiter itself is used twice in a row to indicate that the delimiter itself is present within the string; for example, if the string value (shown without the usual surrounding quotes to try to avoid confusion) is <span class=\"s2\">she said \"hello\"</span>, and the string delimiter is the double quote as it is by default, then in the CSV file the value would be given as <span class=\"s2\">\"she said \"\"hello\"\"\"</span>.<span class=\"Apple-converted-space\">  </span>The usual Eidos style of escaping characters using a backslash is <i>not</i> part of the CSV standard followed here.<span class=\"Apple-converted-space\">  </span>(When a string value is provided <i>without</i> using the string delimiter, all following characters are considered part of the string except a newline, the value separator <span class=\"s2\">sep</span>, the quote separator <span class=\"s2\">quote</span>, and the comment separator <span class=\"s2\">comment</span>; if none of those characters are present in the string value, the quote delimiter may be omitted.)</p>\n<p class=\"p5\">The character used to indicate a decimal delimiter in numbers may be supplied with <span class=\"s2\">dec</span>; by default this is <span class=\"s2\">\".\"</span> (and so <span class=\"s2\">10.0</span> would be ten, written with a decimal point), but <span class=\"s2\">\",\"</span> is common in European data files (and so <span class=\"s2\">10,0</span> would be ten, written with a decimal comma).<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">dec</span> and <span class=\"s2\">sep</span> may not be the same, so that it is unambiguous whether <span class=\"s2\">10,0</span> is two numbers (<span class=\"s2\">10</span> and <span class=\"s2\">0</span>) or one number (<span class=\"s2\">10.0</span>).<span class=\"Apple-converted-space\">  </span>For this reason, European CSV files that use a decimal comma typically use a semicolon as the value separator, which may be supplied with <span class=\"s2\">sep=\";\"</span> to <span class=\"s2\">readCSV()</span>.</p>\n<p class=\"p5\">Finally, the remainder of a line following a comment character will be ignored when the file is read; by default <span class=\"s2\">comment</span> is the empty string, <span class=\"s2\">\"\"</span>, indicating that comments do not exist at all, but <span class=\"s2\">\"#\"</span> is a popular comment prefix.</p>\n<p class=\"p5\">To translate the CSV data into a <span class=\"s2\">DataFrame</span>, it is necessary for Eidos to guess what value type each column is unless a column type is specified by <span class=\"s2\">colTypes</span>.<span class=\"Apple-converted-space\">  </span>Quotes surrounding a value are irrelevant to this guess; for example, <span class=\"s2\">1997</span> and <span class=\"s2\">\"1997\"</span> are both candidates to be <span class=\"s2\">integer</span> values (because some programs generate CSV output in which <i>every</i> value is quoted regardless of type).<span class=\"Apple-converted-space\">  </span>If <i>every</i> value in a column is either <span class=\"s2\">true</span>, <span class=\"s2\">false</span>, <span class=\"s2\">TRUE</span>, <span class=\"s2\">FALSE</span>, <span class=\"s2\">T</span>, or <span class=\"s2\">F</span>, the column will be taken to be <span class=\"s2\">logical</span>.<span class=\"Apple-converted-space\">  </span>Otherwise, if <i>every</i> value in a column is an integer (here defined as an optional <span class=\"s2\">+</span> or <span class=\"s2\">-</span>, followed by nothing but decimal digits <span class=\"s2\">0123456789</span>), the column will be taken to be <span class=\"s2\">integer</span>.<span class=\"Apple-converted-space\">  </span>Otherwise, if <i>every</i> value in a column is a floating-point number (here defined as an optional <span class=\"s2\">+</span> or <span class=\"s2\">-</span>, followed by decimal digits <span class=\"s2\">0123456789</span>, optionally a decimal separator and then optionally more decimal digits, and ending with an optional exponent like <span class=\"s2\">e7</span>, <span class=\"s2\">E+05</span>, or <span class=\"s2\">e-2</span>), the column will be taken to be <span class=\"s2\">float</span>; the special values <span class=\"s2\">NAN</span>, <span class=\"s2\">INF</span>, <span class=\"s2\">INFINITY</span>, <span class=\"s2\">-INF</span>, and <span class=\"s2\">-INFINITY</span> (not case-sensitive) are also candidates to be <span class=\"s2\">float</span> (if the rest of the column is also convertible to <span class=\"s2\">float</span>), representing the corresponding <span class=\"s2\">float</span> constants.<span class=\"Apple-converted-space\">  </span>Otherwise, the column will be taken to be <span class=\"s2\">string</span>.<span class=\"Apple-converted-space\">  </span><span class=\"s2\">NULL</span> and <span class=\"s2\">NA</span> are not recognized by <span class=\"s2\">readCSV()</span> in CSV files and will be read as strings.<span class=\"Apple-converted-space\">  </span>Every line in a CSV file must contain the same number of values (forming a rectangular data table); missing values are not allowed by <span class=\"s2\">readCSV()</span> since there is no way to represent them in <span class=\"s2\">DataFrame</span> (since Eidos has no equivalent of R’s <span class=\"s2\">NA</span> value).<span class=\"Apple-converted-space\">  </span>Spaces are considered part of a data field and are not trimmed, following the RFC 4180 standard.<span class=\"Apple-converted-space\">  </span>These choices are an attempt to provide optimal behavior for most clients, but given the lack of any universal standard for CSV files, and the lack of any type information in the CSV format, they will not always work as desired; in such cases, it should be reasonably straightforward to preprocess input files using standard Unix text-processing tools like <span class=\"s2\">sed</span> and <span class=\"s2\">awk</span>.</p>\n<p class=\"p2\">(string)readFile(string$ filePath)</p>\n<p class=\"p3\"><b>Reads in the contents of a file</b> specified by <span class=\"s2\">filePath</span> and returns a <span class=\"s2\">string</span> vector containing the lines (separated by <span class=\"s2\">\\n</span> and <span class=\"s2\">\\r</span> characters) of the file.<span class=\"Apple-converted-space\">  </span>Reading files other than text files is not presently supported.<span class=\"Apple-converted-space\">  </span>If an error occurs during the read, <span class=\"s2\">NULL</span> will be returned.</p>\n<p class=\"p4\"><span class=\"s5\">(string$)setwd(string$ path)</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Sets the current filesystem working directory</b>.<span class=\"Apple-converted-space\">  </span>The filesystem working directory is the directory which will be used as a base path for relative filesystem paths (see </span><span class=\"s9\">getwd()</span><span class=\"s5\"> for further discussion).<span class=\"Apple-converted-space\">  </span>An error will result if the working directory cannot be set to the given path.</span></p>\n<p class=\"p5\"><span class=\"s5\">The current working directory prior to the change will be returned as an invisible </span><span class=\"s9\">string</span><span class=\"s5\"> value; the value returned is identical to the value that would have been returned by </span><span class=\"s9\">getwd()</span><span class=\"s5\">, apart from its invisibility.</span></p>\n<p class=\"p5\"><span class=\"s5\">See </span><span class=\"s9\">getwd()</span><span class=\"s5\"> for discussion regarding the initial working directory, before it is set with </span><span class=\"s9\">setwd()</span><span class=\"s5\">.</span></p>\n<p class=\"p4\">(string$)tempdir(void)</p>\n<p class=\"p5\"><b>Returns a path to a directory appropriate for saving temporary files</b>.<span class=\"Apple-converted-space\">  </span>The path returned by <span class=\"s2\">tempdir()</span> is platform-specific, and is not guaranteed to be the same from one run of SLiM to the next.<span class=\"Apple-converted-space\">  </span>It is guaranteed to end in a slash, so further path components should be appended without a leading slash.<span class=\"Apple-converted-space\">  </span>At present, on macOS and Linux systems, the path will be <span class=\"s2\">\"/tmp/\"</span>; this may change in future Eidos versions without warning.</p>\n<p class=\"p2\">(logical$)writeFile(string$ filePath, string contents, [logical$ append = F], [logical$ compress = F])</p>\n<p class=\"p3\"><b>Writes or appends to a file</b> specified by <span class=\"s2\">filePath</span> with contents specified by <span class=\"s2\">contents</span>, a <span class=\"s2\">string</span> vector of lines.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">append</span> is <span class=\"s2\">T</span>, the write will be appended to the existing file (if any) at <span class=\"s2\">filePath</span>; if it is <span class=\"s2\">F</span> (the default), then the write will replace an existing file at that path.<span class=\"s6\"><span class=\"Apple-converted-space\">  </span>If the write is successful, </span><span class=\"s7\">T</span><span class=\"s6\"> will be returned; if not, </span><span class=\"s7\">F</span><span class=\"s6\"> will be returned (but at present, an error will result instead).</span></p>\n<p class=\"p5\">If <span class=\"s2\">compress</span> is <span class=\"s2\">T</span>, the contents will be compressed with <span class=\"s2\">zlib</span> as they are written, and the standard <span class=\"s2\">.gz</span> extension for <span class=\"s2\">gzip</span>-compressed files will be appended to the filename in <span class=\"s2\">filePath</span> if it is not already present.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s2\">compress</span> option is used in conjunction with <span class=\"s2\">append==T</span>, Eidos will buffer data to append and flush it to the file in a delayed fashion (for performance reasons), and so appended data may not be visible in the file until later – potentially not until the process ends (i.e., the end of the SLiM simulation, for example).<span class=\"Apple-converted-space\">  </span>If that delay if undesirable, buffered data can be explicitly flushed to the filesystem with <span class=\"s2\">flushFile()</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">compress</span> option was added in Eidos 2.4 (SLiM 3.4).<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s2\">readFile()</span> does not currently support reading in compressed data.</p>\n<p class=\"p3\">Note that newline characters will be added at the ends of the lines in <span class=\"s2\">contents</span>.<span class=\"Apple-converted-space\">  </span>If you do not wish to have newlines added, you should use <span class=\"s2\">paste()</span> to assemble the elements of <span class=\"s2\">contents</span> together into a singleton <span class=\"s2\">string</span><span class=\"s3\">.</span></p>\n<p class=\"p2\">(string$)writeTempFile(string$ prefix, string$ suffix, string contents, [logical$ compress = F])</p>\n<p class=\"p3\"><b>Writes to a unique temporary file</b> with contents specified by <span class=\"s2\">contents</span>, a <span class=\"s2\">string</span> vector of lines.<span class=\"Apple-converted-space\">  </span>The filename used will begin with <span class=\"s2\">prefix</span> and end with <span class=\"s2\">suffix</span>, and will contain six random characters in between; for example, if <span class=\"s2\">prefix</span> is <span class=\"s2\">\"plot1_\"</span> and <span class=\"s2\">suffix</span> is <span class=\"s2\">\".pdf\"</span>, the generated filename might look like <span class=\"s2\">\"plot1_r5Mq0t.pdf\"</span>.<span class=\"Apple-converted-space\">  </span>It is legal for <span class=\"s2\">prefix</span>, <span class=\"s2\">suffix</span>, or both to be the empty string, <span class=\"s2\">\"\"</span>, but supplying a file extension is usually advisable at minimum.<span class=\"Apple-converted-space\">  </span>The file will be created inside the <span class=\"s2\">/tmp/</span> directory of the system, which is provided by Un*x systems as a standard location for temporary files; the <span class=\"s2\">/tmp/</span> directory should not be specified as part of prefix (nor should any other directory information).<span class=\"Apple-converted-space\">  </span>The filename generated is guaranteed not to already exist in <span class=\"s2\">/tmp/</span>.<span class=\"Apple-converted-space\">  </span>The file is created with Un*x permissions <span class=\"s2\">0600</span>, allowing reading and writing only by the user for security.<span class=\"Apple-converted-space\">  </span>If the write is successful, the full path to the temporary file will be returned; if not, <span class=\"s2\">\"\"</span> will be returned.</p>\n<p class=\"p5\"><span class=\"s5\">If </span><span class=\"s9\">compress</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\">, the contents will be compressed with </span><span class=\"s9\">zlib</span><span class=\"s5\"> as they are written, and the standard </span><span class=\"s9\">.gz</span><span class=\"s5\"> extension for </span><span class=\"s9\">gzip</span><span class=\"s5\">-compressed files will be appended to the filename suffix in </span><span class=\"s9\">suffix</span><span class=\"s5\"> if it is not already present.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">compress</span><span class=\"s5\"> option was added in Eidos 2.4 (SLiM 3.4).<span class=\"Apple-converted-space\">  </span>Note that </span><span class=\"s9\">readFile()</span><span class=\"s5\"> does not currently support reading in compressed data.</span></p>\n<p class=\"p3\">Note that newline characters will be added at the ends of the lines in <span class=\"s2\">contents</span>.<span class=\"Apple-converted-space\">  </span>If you do not wish to have newlines added, you should use <span class=\"s2\">paste()</span> to assemble the elements of <span class=\"s2\">contents</span> together into a singleton <span class=\"s2\">string</span><span class=\"s3\">.</span></p>\n<p class=\"p1\"><b>3.10.<span class=\"Apple-converted-space\">  </span>Color manipulation functions</b></p>\n<p class=\"p4\"><span class=\"s5\">(string)cmColors(integer$ n)</span></p>\n<p class=\"p5\"><b>This method has been deprecated, and may be removed in a future release of Eidos.</b><span class=\"Apple-converted-space\">  </span>In SLiM 3.5 and later, use <span class=\"s2\">colors(n, \"cm\")</span> instead.</p>\n<p class=\"p9\">Generate colors in a “cyan-magenta” color palette.</p>\n<p class=\"p4\">(string)colors(numeric x, string$ name)</p>\n<p class=\"p5\"><b>Generate colors in a standard color palette</b>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">x</span> is a singleton <span class=\"s2\">integer</span>, the returned vector will contain <span class=\"s2\">x</span> color strings representing <span class=\"s2\">x</span> colors equidistant along the named palette, spanning its full extent.<span class=\"Apple-converted-space\">  </span>Alternatively, if <span class=\"s2\">x</span> is a <span class=\"s2\">float</span> vector of values in [<span class=\"s2\">0</span>,<span class=\"s2\">1</span>], the returned vector will contain one color string for each value in <span class=\"s2\">x</span>, representing the color at the corresponding fraction along the named palette (values outside [<span class=\"s2\">0</span>,<span class=\"s2\">1</span>] will be clamped to that range).<span class=\"Apple-converted-space\">  </span>(Note that the function signature states the type of <span class=\"s2\">x</span> as <span class=\"s2\">numeric</span>, but in this function the <span class=\"s2\">integer</span> and <span class=\"s2\">float</span> cases have completely different semantic meanings.)</p>\n<p class=\"p5\">The color palette specified by <span class=\"s2\">name</span> may be any of the following color palettes based upon color palettes in R: <span class=\"s2\">\"cm\"</span>, <span class=\"s2\">\"heat\"</span>, and <span class=\"s2\">\"terrain\"</span>.</p>\n<p class=\"p5\">It may also be one of the following color palettes based on color palettes in MATLAB (and the Turbo palette from Anton Mikhailov of the Google AI group, based upon the Jet palette provided by MATLAB): <span class=\"s2\">\"parula\"</span>, <span class=\"s2\">\"hot\"</span>, <span class=\"s2\">\"jet\"</span>, <span class=\"s2\">\"turbo\"</span>, and <span class=\"s2\">\"gray\"</span>.</p>\n<p class=\"p5\">Finally, it may be one of the following color palettes based upon color palettes in Matplotlib, also available in the <span class=\"s2\">viridis</span> R package: <span class=\"s2\">\"magma\"</span>, <span class=\"s2\">\"inferno\"</span>, <span class=\"s2\">\"plasma\"</span>, <span class=\"s2\">\"viridis\"</span>, and <span class=\"s2\">\"cividis\"</span>.<span class=\"Apple-converted-space\">  </span>These color palettes are designed to be perceptually uniform, changing continuously and linearly.<span class=\"Apple-converted-space\">  </span>They are also designed to perform well even for users with red-green colorblindness; the <span class=\"s2\">\"cividis\"</span> palette, in particular, is designed to look nearly identical to those with and without red-green colorblindness, to be perceptually uniform in both hue and brightness, and to increase linearly in brightness.</p>\n<p class=\"p5\">This function replaces the deprecated <span class=\"s2\">cmColors()</span>, <span class=\"s2\">heatColors()</span>, and <span class=\"s2\">terrainColors()</span> functions, and adds several several additional color palettes to Eidos.<span class=\"Apple-converted-space\">  </span>See <span class=\"s2\">rainbow()</span> for another color palette function.</p>\n<p class=\"p2\">(float)color2rgb(string color)</p>\n<p class=\"p5\"><span class=\"s5\"><b>Converts a color string to RGB</b>.<span class=\"Apple-converted-space\">  </span>The color string specified in </span><span class=\"s9\">color</span><span class=\"s5\"> may be either a named color or a color in hexadecimal format such as </span><span class=\"s9\">\"#007FC0\"</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The equivalent RGB color is returned as a </span><span class=\"s9\">float</span><span class=\"s5\"> vector of length three (red, green, blue).<span class=\"Apple-converted-space\">  </span>Returned RGB values will be in the interval [0, 1].</span></p>\n<p class=\"p5\"><span class=\"s5\">This function can also be called with a non-singleton vector of color strings in </span><span class=\"s9\">color</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>In this case, the returned </span><span class=\"s9\">float</span><span class=\"s5\"> value will be a matrix of RGB values, with three columns (red, green, blue) and one row per element of </span><span class=\"s9\">color</span><span class=\"s5\">.</span></p>\n<p class=\"p4\"><span class=\"s5\">(string)heatColors(integer$ n)</span></p>\n<p class=\"p5\"><b>This method has been deprecated, and may be removed in a future release of Eidos.</b><span class=\"Apple-converted-space\">  </span>In SLiM 3.5 and later, use <span class=\"s2\">colors(n, \"heat\")</span> instead.</p>\n<p class=\"p9\">Generate colors in a “heat map” color palette.</p>\n<p class=\"p2\">(float)hsv2rgb(float hsv)</p>\n<p class=\"p3\"><b>Converts an HSV color to RGB</b><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The HSV color is specified in <span class=\"s2\">hsv</span> as a <span class=\"s2\">float</span> vector of length three (hue, saturation, value), and the equivalent RGB color is returned as a <span class=\"s2\">float</span> vector of length three (red, green, blue).<span class=\"Apple-converted-space\">  </span>HSV values will be clamped to the interval [0, 1], and returned RGB values will also be in the interval [0, 1].</p>\n<p class=\"p5\"><span class=\"s5\">This function can also be called with a matrix of HSV values, with three columns (hue, saturation, value).<span class=\"Apple-converted-space\">  </span>In this case, the returned </span><span class=\"s9\">float</span><span class=\"s5\"> value will be a matrix of RGB values, with three columns (red, green, blue) and one row per row of </span><span class=\"s9\">hsv</span><span class=\"s5\">.</span></p>\n<p class=\"p4\"><span class=\"s5\">(string)rainbow(integer$ n, [float$ s = 1.0], [float$ v = 1.0], [float$ start = 0.0], [Nf$ end = NULL], [logical$ ccw = T])</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Generate colors in a “rainbow” color palette</b>.<span class=\"Apple-converted-space\">  </span>The number of colors desired is passed in </span><span class=\"s9\">n</span><span class=\"s5\">, and the returned vector will contain </span><span class=\"s9\">n</span><span class=\"s5\"> color strings.<span class=\"Apple-converted-space\">  </span>Parameters </span><span class=\"s9\">s</span><span class=\"s5\"> and </span><span class=\"s9\">v</span><span class=\"s5\"> control the saturation and value of the rainbow colors generated.<span class=\"Apple-converted-space\">  </span>The color sequence begins with the hue </span><span class=\"s9\">start</span><span class=\"s5\">, and ramps to the hue </span><span class=\"s9\">end</span><span class=\"s5\">, in a counter-clockwise direction around the standard HSV color wheel if </span><span class=\"s9\">ccw</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\"> (the default, following R), otherwise in a clockwise direction.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">end</span><span class=\"s5\"> is </span><span class=\"s9\">NULL</span><span class=\"s5\"> (the default), a value of </span><span class=\"s9\">(n-1)/n</span><span class=\"s5\"> is used, producing a complete rainbow around the color wheel when </span><span class=\"s9\">start</span><span class=\"s5\"> is also the default value of </span><span class=\"s9\">0.0</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s9\">colors()</span><span class=\"s5\"> for other color palettes.</span></p>\n<p class=\"p2\">(string)rgb2color(float rgb)</p>\n<p class=\"p3\"><b>Converts an RGB color to a color string</b><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The RGB color is specified in <span class=\"s2\">rgb</span> as a <span class=\"s2\">float</span> vector of length three (red, green, blue).<span class=\"Apple-converted-space\">  </span>The equivalent color string is returned as singleton <span class=\"s2\">string</span> specifying the color in the format <span class=\"s2\">\"#RRGGBB\"</span>, such as <span class=\"s2\">\"#007FC0\"</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>RGB values will be clamped to the interval [0, 1].</p>\n<p class=\"p5\"><span class=\"s5\">This function can also be called with a matrix of RGB values, with three columns (red, green, blue).<span class=\"Apple-converted-space\">  </span>In this case, the returned </span><span class=\"s9\">string</span><span class=\"s5\"> value will be a vector of color strings, with one element per row of </span><span class=\"s9\">rgb</span><span class=\"s5\">.</span></p>\n<p class=\"p2\">(float)rgb2hsv(float rgb)</p>\n<p class=\"p3\"><b>Converts an RGB color to HSV</b><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>The RGB color is specified in <span class=\"s2\">rgb</span> as a <span class=\"s2\">float</span> vector of length three (red, green, blue), and the equivalent HSV color is returned as a <span class=\"s2\">float</span> vector of length three (hue, saturation, value).<span class=\"Apple-converted-space\">  </span>RGB values will be clamped to the interval [0, 1], and returned HSV values will also be in the interval [0, 1].</p>\n<p class=\"p5\"><span class=\"s5\">This function can also be called with a matrix of RGB values, with three columns (red, green, blue).<span class=\"Apple-converted-space\">  </span>In this case, the returned </span><span class=\"s9\">float</span><span class=\"s5\"> value will be a matrix of HSV values, with three columns (hue, saturation, value) and one row per row of </span><span class=\"s9\">rgb</span><span class=\"s5\">.</span></p>\n<p class=\"p4\"><span class=\"s5\">(string)terrainColors(integer$ n)</span></p>\n<p class=\"p5\"><b>This method has been deprecated, and may be removed in a future release of Eidos.</b><span class=\"Apple-converted-space\">  </span>In SLiM 3.5 and later, use <span class=\"s2\">colors(n, \"terrain\")</span> instead.</p>\n<p class=\"p9\">Generate colors in a “terrain” color palette.</p>\n<p class=\"p1\"><b>3.11.<span class=\"Apple-converted-space\">  </span>Miscellaneous functions</b></p>\n<p class=\"p4\">(void)assert(logical assertions, [Ns$ message = NULL])</p>\n<p class=\"p5\"><b>Assert that a condition or conditions are true</b>.<span class=\"Apple-converted-space\">  </span>If any element of <span class=\"s2\">assertions</span> is <span class=\"s2\">F</span>, execution will be stopped.<span class=\"Apple-converted-space\">  </span>A message, “assertion failed”, will be printed before stopping; if <span class=\"s2\">message</span> is not <span class=\"s2\">NULL</span>; its value will then be printed.</p>\n<p class=\"p2\">(void)beep([Ns$ soundName = NULL])</p>\n<p class=\"p3\"><b>Plays a sound or beeps.</b><span class=\"Apple-converted-space\">  </span>On macOS in a GUI environment (i.e., in EidosScribe or SLiMgui), the optional parameter <span class=\"s2\">soundName</span> can be the name of a sound file to play; in other cases (if <span class=\"s2\">soundName</span> is <span class=\"s2\">NULL</span>, or at the command line, or on platforms other than OS X) <span class=\"s2\">soundName</span> is ignored and a standard system beep is played.</p>\n<p class=\"p3\">When <span class=\"s2\">soundName</span> is not <span class=\"s2\">NULL</span><span class=\"s3\">,</span> a sound file in a supported format (such as <span class=\"s2\">.aiff</span> or <span class=\"s2\">.mp3</span>) is searched for sequentially in four standard locations, in this order: <span class=\"s2\">~/Library/Sounds</span>, <span class=\"s2\">/Library/Sounds</span>, <span class=\"s2\">/Network/Library/Sounds</span>, and finally <span class=\"s2\">/System/Library/Sounds</span>.<span class=\"Apple-converted-space\">  </span>Standard OS X sounds located in <span class=\"s15\">/System/Library/Sounds</span> include <span class=\"s2\">\"Basso\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Blow\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Bottle\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Frog\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Funk\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Glass\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Hero\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Morse\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Ping\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Pop\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Purr\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Sosumi\"</span><span class=\"s3\">,</span> <span class=\"s2\">\"Submarine\"</span>, and <span class=\"s2\">\"Tink\"</span>.<span class=\"Apple-converted-space\">  </span>Do not include the file extension, such as <span class=\"s2\">.aiff</span> or <span class=\"s2\">.mp3</span>, in <span class=\"s2\">soundName</span><span class=\"s3\">.</span></p>\n<p class=\"p3\"><b>CAUTION:</b> When not running in EidosScribe or SLiMgui, it is often the case that the only simple means available to play a beep is to send a <span class=\"s2\">BEL</span> character (ASCII 7) to the standard output.<span class=\"Apple-converted-space\">  </span>Unfortunately, when this is the case, it means that (1) no beep will be audible if output is being redirected into a file, and (2) a control character, <span class=\"s2\">^G</span>, will occur in the output at the point when the beep was requested.<span class=\"Apple-converted-space\">  </span>It is therefore recommended that <span class=\"s2\">beep()</span> be used only when doing interactive work in a terminal shell (or in a GUI), not when producing output files.<span class=\"Apple-converted-space\">  </span>However, this issue is platform-specific; on some platforms <span class=\"s2\">beep()</span> may result in a beep, and no emitted <span class=\"s2\">^G</span>, even when output is redirected.<span class=\"Apple-converted-space\">  </span>When a <span class=\"s2\">^G</span> must be emitted to the standard output to generate the beep, a warning message will also be emitted to make any associated problems easier to diagnose.</p>\n<p class=\"p2\">(void)citation(void)</p>\n<p class=\"p3\"><b>Prints citation information for Eidos</b> to Eidos’s output stream.</p>\n<p class=\"p4\"><span class=\"s5\">(float$)clock([string$ type = \"cpu\"])</span></p>\n<p class=\"p5\"><span class=\"s5\">Returns the value of a <b>system clock</b>.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">type</span><span class=\"s5\"> is </span><span class=\"s9\">\"cpu\"</span><span class=\"s5\">, this returns the current value of the CPU usage clock.<span class=\"Apple-converted-space\">  </span>This is the amount of CPU time used by the current process, in seconds; it is unrelated to the current time of day (for that, see the </span><span class=\"s9\">time()</span><span class=\"s5\"> function).<span class=\"Apple-converted-space\">  </span>This is useful mainly for determining how much processor time a given section of code takes; </span><span class=\"s9\">clock()</span><span class=\"s5\"> can be called before and after a block of code, and the end clock minus the start clock gives the elapsed CPU time consumed in the execution of the block of code.<span class=\"Apple-converted-space\">  </span>See also the </span><span class=\"s9\">timed</span><span class=\"s5\"> parameter of </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">, which automates this procedure.<span class=\"Apple-converted-space\">  </span>Note that if multiple cores are utilized by the process, the CPU usage clock will be the sum of the CPU usage across all cores, and may therefore run faster than the wall clock.</span></p>\n<p class=\"p5\"><span class=\"s5\">If </span><span class=\"s9\">type</span><span class=\"s5\"> is </span><span class=\"s9\">\"mono\"</span><span class=\"s5\">, this returns the value of the system’s monotonic clock.<span class=\"Apple-converted-space\">  </span>This represents user-perceived (“wall clock”) elapsed time from some arbitrary timebase (which will not change during the execution of the program), but it will not jump if the time zone or the wall clock time are changed for the system.<span class=\"Apple-converted-space\">  </span>This clock is useful for measuring user-perceived elapsed time, as described above, and may provide a more useful metric for performance than CPU time if multiple cores are being utilized.</span></p>\n<p class=\"p2\">(string$)date(void)</p>\n<p class=\"p3\">Returns a <b>standard date string</b> for the current date in the local time of the executing machine.<span class=\"Apple-converted-space\">  </span>The format is <span class=\"s2\">%d-%m-%Y</span> (day in two digits, then month in two digits, then year in four digits, zero-padded and separated by dashes) regardless of the localization of the executing machine, for predictability and consistency.</p>\n<p class=\"p4\">(string$)debugIndent(void)</p>\n<p class=\"p5\">Returns the <b>indentation string</b> currently being used to start lines in the debugging output stream.<span class=\"Apple-converted-space\">  </span>In a pure Eidos context this will currently be the empty string, <span class=\"s2\">\"\"</span>.<span class=\"Apple-converted-space\">  </span>In specific Contexts, such as SLiM, the debugging output stream may be structured with nested indentation, in which case this string will typically be a series of spaces or tabs.<span class=\"Apple-converted-space\">  </span>To make your debugging output (such as from <span class=\"s2\">cat()</span>, <span class=\"s2\">catn()</span>, or <span class=\"s2\">print()</span> with the <span class=\"s2\">error=T</span> optional argument set) line up with other output at the current level of execution nesting, you can start your new lines of output with this string if you wish.</p>\n<p class=\"p4\">(void)defineConstant(string$ symbol, * value)</p>\n<p class=\"p5\"><b>Defines a new constant</b> with the name <span class=\"s2\">symbol</span> and the value specified by <span class=\"s2\">value</span>.<span class=\"Apple-converted-space\">  </span>The name cannot previously be defined in any way (i.e., as either a variable or a constant).<span class=\"Apple-converted-space\">  </span>The defined constant acts identically to intrinsic Eidos constants such as <span class=\"s2\">T</span>, <span class=\"s2\">NAN</span>, and <span class=\"s2\">PI</span>, and will remain defined for as long as the Eidos context lives even if it is defined inside a block being executed by <span class=\"s2\">executeLambda()</span>, <span class=\"s2\">apply()</span>, <span class=\"s2\">sapply()</span>, or a Context-defined script block.</p>\n<p class=\"p5\">Syntactically, <span class=\"s2\">value</span> may be any value at all; semantically, however, if <span class=\"s2\">value</span> is of <span class=\"s2\">object</span> type then <span class=\"s2\">value</span>’s class must be under an internal memory-management scheme called “retain-release”.<span class=\"Apple-converted-space\">  </span>Objects that are not under retain-release can cease to exist whenever the Context is finished using them, and thus a defined constant referencing such an object could become invalid, which must be prevented.<span class=\"Apple-converted-space\">  </span>Objects that are under retain-release will not cease to exist if they are referenced by a global constant; the reference to them from the global constant “retains” them and keeps them in existence.<span class=\"Apple-converted-space\">  </span>All object classes built into Eidos are under retain-release; see the SLiM manual (section “SLiM scoping rules”) for discussion of which SLiM object classes are under retain-release.</p>\n<p class=\"p4\">(void)defineGlobal(string$ symbol, * value)</p>\n<p class=\"p5\"><b>Defines a new global variable</b> with the name <span class=\"s2\">symbol</span> and the value specified by <span class=\"s2\">value</span>.<span class=\"Apple-converted-space\">  </span>The name cannot previously be defined as a constant.<span class=\"Apple-converted-space\">  </span>The result is similar to a standard variable assignment with operator <span class=\"s2\">=</span>, except that the variable is always defined in the global scope (even if the <span class=\"s2\">defineGlobal()</span> call is made inside a user-defined function or other locally-scoped block, such as a SLiM event or callback).<span class=\"Apple-converted-space\">  </span>This means that the variable will remain defined even after the current scope is exited.<span class=\"Apple-converted-space\">  </span>Note that global variables can be hidden by local variables with the same name; unlike defined constants, such scoped masking is allowed.</p>\n<p class=\"p5\">Syntactically, <span class=\"s2\">value</span> may be any value at all; semantically, however, if <span class=\"s2\">value</span> is of <span class=\"s2\">object</span> type then <span class=\"s2\">value</span>’s class must be under an internal memory-management scheme called “retain-release”.<span class=\"Apple-converted-space\">  </span>Objects that are not under retain-release can cease to exist whenever the Context is finished using them, and thus a global variable referencing such an object could become invalid, which must be prevented.<span class=\"Apple-converted-space\">  </span>Objects that are under retain-release will not cease to exist if they are referenced by a global variable; the reference to them from the global variable “retains” them and keeps them in existence.<span class=\"Apple-converted-space\">  </span>All object classes built into Eidos are under retain-release; see the SLiM manual (section “SLiM scoping rules”) for discussion of which SLiM object classes are under retain-release.</p>\n<p class=\"p2\">(<span class=\"s14\">vNlifso</span>)doCall(string$ functionName, ...)</p>\n<p class=\"p3\">Returns the results from a <b>call to a specified function</b>.<span class=\"Apple-converted-space\">  </span>The function named by the parameter <span class=\"s2\">functionName</span> is called, and the remaining parameters to <span class=\"s2\">doCall()</span> are forwarded on to that function verbatim.<span class=\"Apple-converted-space\">  </span>This can be useful for calling one of a set of similar functions, such as <span class=\"s2\">sin()</span>, <span class=\"s2\">cos()</span>, etc., to perform a math function determined at runtime, or one of the <span class=\"s2\">as...()</span> family of functions to convert to a type determined at runtime.<span class=\"Apple-converted-space\">  </span>Note that named arguments and default arguments, beyond the <span class=\"s2\">functionName</span> argument, are not supported by <span class=\"s2\">doCall()</span>; all arguments to the target function must be specified explicitly, without names.</p>\n<p class=\"p2\">(<span class=\"s14\">vNlifso</span>)executeLambda(string$ lambdaSource, [ls$ timed = F])</p>\n<p class=\"p5\"><span class=\"s5\"><b>Executes a block of Eidos code</b> defined by </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Eidos allows you to execute <i>lambdas</i>: blocks of Eidos code which can be called directly within the same scope as the caller.<span class=\"Apple-converted-space\">  </span>Eidos lambdas do not take arguments; for this reason, they are not first-class functions.<span class=\"Apple-converted-space\">  </span>(Since they share the scope of the caller, however, you may effectively pass values in and out of a lambda using variables.)<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">string</span><span class=\"s5\"> argument </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> may contain one or many Eidos statements as a single </span><span class=\"s9\">string</span><span class=\"s5\"> value.<span class=\"Apple-converted-space\">  </span>Lambdas are represented, to the caller, only as the source code </span><span class=\"s9\">string</span><span class=\"s5\"> </span><span class=\"s9\">lambdaSource</span><span class=\"s5\">; the executable code is not made available programmatically.<span class=\"Apple-converted-space\">  </span>If an error occurs during the tokenization, parsing, or execution of the lambda, that error is raised as usual; executing code inside a lambda does not provide any additional protection against exceptions raised.<span class=\"Apple-converted-space\">  </span>The return value produced by the code in the lambda is returned by </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>If the optional parameter </span><span class=\"s9\">timed</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\">, the total (CPU clock) execution time for the lambda will be printed after the lambda has completed (see </span><span class=\"s9\">clock()</span><span class=\"s5\">); if it is </span><span class=\"s9\">F</span><span class=\"s5\"> (the default), no timing information will be printed.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">timed</span><span class=\"s5\"> parameter may also be </span><span class=\"s9\">\"cpu\"</span><span class=\"s5\"> or </span><span class=\"s9\">\"mono\"</span><span class=\"s5\"> to specifically request timing with the CPU clock (which will count the usage across all cores, and may thus run faster than wall clock time if multiple cores are being utilized) or the monotonic clock (which will correspond, more or less, to elapsed wall clock time regardless of multithreading); see the documentation for </span><span class=\"s9\">clock()</span><span class=\"s5\"> for further discussion of these timing options.</span></p>\n<p class=\"p3\">The current implementation of <span class=\"s2\">executeLambda()</span> caches a tokenized and parsed version of <span class=\"s2\">lambdaSource</span>, so calling <span class=\"s2\">executeLambda()</span> repeatedly on a single source <span class=\"s2\">string</span> is much more efficient than calling <span class=\"s2\">executeLambda()</span> with a newly constructed <span class=\"s2\">string</span> each time.<span class=\"Apple-converted-space\">  </span>If you can use a <span class=\"s2\">string</span> literal for <span class=\"s2\">lambdaSource</span>, or reuse a constructed source <span class=\"s2\">string</span> stored in a variable, that will improve performance considerably.</p>\n<p class=\"p2\">(logical)exists(string symbol)</p>\n<p class=\"p5\"><span class=\"s5\">Returns a </span><span class=\"s9\">logical</span><span class=\"s5\"> vector indicating <b>whether symbols exist</b>.<span class=\"Apple-converted-space\">  </span>If a symbol has been defined as an intrinsic Eidos constant like </span><span class=\"s9\">T</span><span class=\"s5\">, </span><span class=\"s9\">INF</span><span class=\"s5\">, and </span><span class=\"s9\">PI</span><span class=\"s5\">, or as a Context-defined constant like </span><span class=\"s9\">sim</span><span class=\"s5\"> in SLiM, or as a user-defined constant using </span><span class=\"s9\">defineConstant()</span><span class=\"s5\">, or as a variable by assignment, this function returns </span><span class=\"s9\">T</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Otherwise, the symbol has not been defined, and </span><span class=\"s9\">exists()</span><span class=\"s5\"> returns </span><span class=\"s9\">F</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>This is commonly used to check whether a user-defined constant already exists, with the intention of defining the constant if it has not already been defined.<span class=\"Apple-converted-space\">  </span>A vector of symbols may be passed, producing a vector of corresponding results.</span></p>\n<p class=\"p2\">(void)functionSignature([Ns$<span class=\"s1\"> </span>functionName<span class=\"s1\"> </span>= NULL])</p>\n<p class=\"p3\"><b>Prints function signatures</b> for all functions (if <span class=\"s2\">functionName</span> is <span class=\"s2\">NULL</span>, the default), or for the function named by <span class=\"s2\">functionName</span>, to Eidos’s output stream.</p>\n<p class=\"p4\">(void)functionSource(string$ functionName)</p>\n<p class=\"p5\"><b>Prints the Eidos source code</b> for the function specified by <span class=\"s2\">functionName</span>, or prints a diagnostic message if the function is implemented in C++ rather than Eidos.</p>\n<p class=\"p2\">(integer$)getSeed(void)</p>\n<p class=\"p3\">Returns the <b>random number seed</b>.<span class=\"Apple-converted-space\">  </span>This is the last seed value set using <span class=\"s2\">setSeed()</span>; if <span class=\"s2\">setSeed()</span> has not been called, it will be a seed value chosen based on the process-id and the current time when Eidos was initialized, unless the Context has set a different seed value.</p>\n<p class=\"p2\">(void)license(void)</p>\n<p class=\"p3\"><b>Prints Eidos’s license terms</b> to Eidos’s output stream.</p>\n<p class=\"p4\"><span class=\"s6\">(void)ls(</span>[logical$ showSymbolTables = F]<span class=\"s6\">)</span></p>\n<p class=\"p3\"><b>Prints all currently defined variables</b> to Eidos’s output stream.</p>\n<p class=\"p5\">Beginning in Eidos 2.5 (SLiM 3.5), the <span class=\"s2\">showSymbolTables</span> optional argument can be set to <span class=\"s2\">T</span> to request full information on the current symbol table chain.<span class=\"Apple-converted-space\">  </span>This will show which symbol table a given symbol is defined in, as well as revealing whether there are other symbols with the same name that have been masked by a local definition.<span class=\"Apple-converted-space\">  </span>This is mostly useful for debugging.</p>\n<p class=\"p4\">(integer$)parallelGetNumThreads(void)</p>\n<p class=\"p5\"><b>Gets the number of threads</b> that is requested be used in subsequent parallel (i.e., multithreaded) regions, as set with <span class=\"s2\">parallelSetNumThreads()</span>.<span class=\"Apple-converted-space\">  </span>If Eidos is not configured to run multithreaded, this function will return <span class=\"s2\">1</span>.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s2\">parallelGetMaxThreads()</span>, which returns the maximum number of threads that can be used.<span class=\"Apple-converted-space\">  </span>Note that if this function returns the maximum number of threads, as returned by <span class=\"s2\">parallelGetMaxThreads()</span>, then there are <i>two possible semantic meanings</i> of that return value, which cannot be distinguished using this function; see <span class=\"s2\">parallelSetNumThreads()</span> for discussion.</p>\n<p class=\"p4\">(integer$)parallelGetMaxThreads(void)</p>\n<p class=\"p5\"><b>Gets the maximum number of threads</b> that can be used in parallel (i.e., multithreaded) regions.<span class=\"Apple-converted-space\">  </span>This is configured externally; it may be OpenMP’s default number of threads for the hardware platform being used, or may be set by an environment variable or command-line option.<span class=\"Apple-converted-space\">  </span>If Eidos is not configured to run multithreaded, this function will return <span class=\"s2\">1</span>.</p>\n<p class=\"p4\">(object&lt;Dictionary&gt;$)parallelGetTaskThreadCounts(void)</p>\n<p class=\"p5\"><b>Gets the number of threads</b> that is requested to be used for specific tasks in Eidos and SLiM.<span class=\"Apple-converted-space\">  </span>Returns a new <span class=\"s2\">Dictionary</span> containing values for all of the tasks for which a number of threads can be specified; see <span class=\"s2\">parallelSetTaskThreadCounts()</span> for a list of all such tasks.<span class=\"Apple-converted-space\">  </span>Note that the specified number of threads will not necessarily be used in practice; in particular, a thread count set by <span class=\"s2\">parallelSetNumThreads()</span> will override these per-task counts.<span class=\"Apple-converted-space\">  </span>Also, if the task size is below a certain task-specific threshold the task will not be executed in parallel regardless of these settings.</p>\n<p class=\"p4\">(void)parallelSetNumThreads([Ni$ numThreads = NULL])</p>\n<p class=\"p5\"><b>Sets the number of threads</b> that is requested to be used in subsequent parallel (i.e., multithreaded) regions.<span class=\"Apple-converted-space\">  </span>If Eidos is not configured to run multithreaded, this function will have no effect.<span class=\"Apple-converted-space\">  </span>The requested number of threads will be clamped to the interval [<span class=\"s2\">1</span>, <span class=\"s2\">maxThreads</span>], where <span class=\"s2\">maxThreads</span> is the maximum number of threads configured externally (either by OpenMP’s default, or by an environment variable or command-line option).<span class=\"Apple-converted-space\">  </span>That maximum number of threads (the value of <span class=\"s2\">maxThreads</span>) can be obtained from <span class=\"s2\">parallelGetMaxThreads()</span>.</p>\n<p class=\"p5\">There is an important wrinkle in the semantics of this method that must be explained.<span class=\"Apple-converted-space\">  </span>Passing <span class=\"s2\">NULL</span> (the default) resets Eidos to the default number of threads for which it is configured to run.<span class=\"Apple-converted-space\">  </span>In this configuration, <span class=\"s2\">parallelGetNumThreads()</span> will return <span class=\"s2\">maxThreads</span>, but the number of threads used for any given parallel operation might not, in fact, be equal to <span class=\"s2\">maxThreads</span>; Eidos might use fewer threads if it determines that that would improve performance.<span class=\"Apple-converted-space\">  </span>Passing the value of <span class=\"s2\">maxThreads</span> explicitly, on the other hand, sets Eidos to always use <span class=\"s2\">maxThreads</span> threads, even if it may result in lower performance; but in this configuration, too, <span class=\"s2\">parallelGetNumThreads()</span> will return <span class=\"s2\">maxThreads</span>.<span class=\"Apple-converted-space\">  </span>For example, suppose <span class=\"s2\">maxThreads</span> is <span class=\"s2\">16</span>.<span class=\"Apple-converted-space\">  </span>Passing <span class=\"s2\">NULL</span> requests that Eidos use <i>up to</i> <span class=\"s2\">16</span> threads, as it sees fit; in contrast, explicitly passing <span class=\"s2\">16</span> requests that Eidos use <i>exactly</i> 16 threads.<span class=\"Apple-converted-space\">  </span>In both cases, however, <span class=\"s2\">parallelGetNumThreads()</span> will return <span class=\"s2\">16</span>.</p>\n<p class=\"p5\">If you wish to temporarily change the number of threads used, the standard pattern is to call <span class=\"s2\">parallelSetNumThreads()</span> with the number of threads you want to use, do the operation you wish to control, and then call <span class=\"s2\">parallelSetNumThreads(NULL)</span> to return to the default behavior of Eidos.</p>\n<p class=\"p5\">Note that the number of threads requested here overrides any per-task request set with <span class=\"s2\">parallelSetTaskThreadCounts()</span>.<span class=\"Apple-converted-space\">  </span>Also, if the task size is below a certain task-specific threshold the task will not be executed in parallel regardless of these settings.</p>\n<p class=\"p4\">(void)parallelSetTaskThreadCounts(No&lt;Dictionary&gt;$ dict)</p>\n<p class=\"p5\"><b>Sets the number of threads</b> that is requested to be used for specific tasks in Eidos and SLiM.<span class=\"Apple-converted-space\">  </span>The dictionary <span class=\"s2\">dict</span> should contain <span class=\"s2\">string</span> keys that identify tasks, and <span class=\"s2\">integer</span> values that provide the number of threads to be used when performing those tasks.<span class=\"Apple-converted-space\">  </span>For example, a key of <span class=\"s2\">\"LOG10_FLOAT\"</span> identifies the task of performing the <span class=\"s2\">log10()</span> function on a <span class=\"s2\">float</span> vector, and a value of <span class=\"s2\">8</span> for that key would tell Eidos to use eight threads when performing that task.<span class=\"Apple-converted-space\">  </span>The number of threads actually used will never be greater than the maximum thread count as returned by <span class=\"s2\">parallelGetMaxThreads()</span>.<span class=\"Apple-converted-space\">  </span>Furthermore, a thread count set with <span class=\"s2\">parallelSetNumThreads()</span> overrides the per-task setting, so if you wish to set specific per-task thread counts you should not set an overall thread count with <span class=\"s2\">parallelSetNumThreads()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">dict</span> is <span class=\"s2\">NULL</span>, all task thread counts will be reset to their default values.</p>\n<p class=\"p5\">The currently requested thread counts for all tasks can be obtained with <span class=\"s2\">parallelGetTaskThreadCounts()</span>.<span class=\"Apple-converted-space\">  </span>Note that the counts returned by that function may not match the counts requested with <span class=\"s2\">parallelSetTaskThreadCounts()</span>; in particular, they may be clipped to the maximum number of threads as returned by <span class=\"s2\">parallelGetMaxThreads()</span>.</p>\n<p class=\"p5\">The task keys recognized, and the tasks they govern, are:</p>\n<p class=\"p10\">\"ABS_FLOAT\"<span class=\"Apple-tab-span\">\t</span>abs(float x)<br>\n\"CEIL\"<span class=\"Apple-tab-span\">\t</span>ceil()<br>\n\"EXP_FLOAT\"<span class=\"Apple-tab-span\">\t</span>exp(float x)<br>\n\"FLOOR\"<span class=\"Apple-tab-span\">\t</span>floor()<br>\n\"LOG_FLOAT\"<span class=\"Apple-tab-span\">\t</span>log(float x)<br>\n\"LOG10_FLOAT\"<span class=\"Apple-tab-span\">\t</span>log10(float x)<br>\n\"LOG2_FLOAT\"<span class=\"Apple-tab-span\">\t</span>log2(float x)<br>\n\"ROUND\"<span class=\"Apple-tab-span\">\t</span>round()<br>\n\"SQRT_FLOAT\"<span class=\"Apple-tab-span\">\t</span>sqrt(float x)<br>\n\"SUM_INTEGER\"<span class=\"Apple-tab-span\">\t</span>sum(integer x)<br>\n\"SUM_FLOAT\"<span class=\"Apple-tab-span\">\t</span>sum(float x)<br>\n\"SUM_LOGICAL\"<span class=\"Apple-tab-span\">\t</span>sum(logical x)<br>\n\"TRUNC\"<span class=\"Apple-tab-span\">\t</span>trunc()</p>\n<p class=\"p10\">\"MAX_INT\"<span class=\"Apple-tab-span\">\t</span>max(integer x)<br>\n\"MAX_FLOAT\"<span class=\"Apple-tab-span\">\t</span>max(float x)<br>\n\"MIN_INT\"<span class=\"Apple-tab-span\">\t</span>min(integer x)<br>\n\"MIN_FLOAT\"<span class=\"Apple-tab-span\">\t</span>min(float x)<br>\n\"PMAX_INT_1\"<span class=\"Apple-tab-span\">\t</span>pmax(i$ x, i y) / pmax(i x, i$ y)<br>\n\"PMAX_INT_2\"<span class=\"Apple-tab-span\">\t</span>pmax(integer x, integer y)<br>\n\"PMAX_FLOAT_1\"<span class=\"Apple-tab-span\">\t</span>pmax(f$ x, f y) / pmax(f x, f$ y)<br>\n\"PMAX_FLOAT_2\"<span class=\"Apple-tab-span\">\t</span>pmax(float x, float y)<br>\n\"PMIN_INT_1\"<span class=\"Apple-tab-span\">\t</span>pmin(i$ x, i y) / pmax(i x, i$ y)<br>\n\"PMIN_INT_2\"<span class=\"Apple-tab-span\">\t</span>pmin(integer x, integer y)<br>\n\"PMIN_FLOAT_1\"<span class=\"Apple-tab-span\">\t</span>pmin(f$ x, f y) / pmin(f x, f$ y)<br>\n\"PMIN_FLOAT_2\"<span class=\"Apple-tab-span\">\t</span>pmin(float x, float y)</p>\n<p class=\"p10\">\"MATCH_INT\"<span class=\"Apple-tab-span\">\t</span>match(integer x, integer table)<br>\n\"MATCH_FLOAT\"<span class=\"Apple-tab-span\">\t</span>match(float x, float table)<br>\n\"MATCH_STRING\"<span class=\"Apple-tab-span\">\t</span>match(string x, string table)<br>\n\"MATCH_OBJECT\"<span class=\"Apple-tab-span\">\t</span>match(object x, object table)<br>\n\"SAMPLE_INDEX\"<span class=\"Apple-tab-span\">\t</span>sample()<span class=\"s19\"> index buffer generation (internal)</span><br>\n\"SAMPLE_R_INT\"<span class=\"Apple-tab-span\">\t</span>sample(integer x, weights=NULL)<br>\n\"SAMPLE_R_FLOAT\"<span class=\"Apple-tab-span\">\t</span>sample(float x, weights=NULL)<br>\n\"SAMPLE_R_OBJECT\"<span class=\"Apple-tab-span\">\t</span>sample(object x, weights=NULL)<br>\n\"SAMPLE_WR_INT\"<span class=\"Apple-tab-span\">\t</span>sample(integer x, if weights)<br>\n\"SAMPLE_WR_FLOAT\"<span class=\"Apple-tab-span\">\t</span>sample(float x, if weights)<br>\n\"SAMPLE_WR_OBJECT\"<span class=\"Apple-tab-span\">\t</span>sample(object x, if weights)<br>\n\"TABULATE_MAXBIN\"<span class=\"Apple-tab-span\">\t</span>tabulate()<span class=\"s19\"> determination of </span>maxbin<span class=\"s19\"> (if not supplied)</span><br>\n\"TABULATE\"<span class=\"Apple-tab-span\">\t</span>tabulate()<span class=\"s19\"> main loop</span></p>\n<p class=\"p10\">\"DNORM_1\"<span class=\"Apple-tab-span\">\t</span>dnorm(numeric$ mean, numeric$ sd)<br>\n\"DNORM_2\"<span class=\"Apple-tab-span\">\t</span>dnorm()<span class=\"s19\"> other cases</span><br>\n\"RBINOM_1\"<span class=\"Apple-tab-span\">\t</span>rbinom(i$ size = 1, f$ prob = 0.5)<br>\n\"RBINOM_2\"<span class=\"Apple-tab-span\">\t</span>rbinom(i$ size, f$ prob)<span class=\"s19\"> other cases</span><br>\n\"RBINOM_3\"<span class=\"Apple-tab-span\">\t</span>rbinom()<span class=\"s19\"> other cases</span><br>\n\"RDUNIF_1\"<span class=\"Apple-tab-span\">\t</span>rdunif(i$ min = 0, i$ max = 1)<span class=\"s19\"> and similar</span><br>\n\"RDUNIF_2\"<span class=\"Apple-tab-span\">\t</span>rdunif(i$ min, i$ max)<span class=\"s19\"> other cases</span><br>\n\"RDUNIF_3\"<span class=\"Apple-tab-span\">\t</span>rdunif()<span class=\"s19\"> other cases</span><br>\n\"REXP_1\"<span class=\"Apple-tab-span\">\t</span>rexp(numeric$ mu)<br>\n\"REXP_2\"<span class=\"Apple-tab-span\">\t</span>rexp()<span class=\"s19\"> other cases</span><br>\n\"RNORM_1\"<span class=\"Apple-tab-span\">\t</span>rnorm(numeric$ mean, numeric$ sd)<br>\n\"RNORM_2\"<span class=\"Apple-tab-span\">\t</span>rnorm(numeric$ sigma)<br>\n\"RNORM_3\"<span class=\"Apple-tab-span\">\t</span>rnorm()<span class=\"s19\"> other cases</span><br>\n\"RPOIS_1\"<span class=\"Apple-tab-span\">\t</span>rpois(numeric$ lambda)<br>\n\"RPOIS_2\"<span class=\"Apple-tab-span\">\t</span>rpois()<span class=\"s19\"> other cases</span><br>\n\"RUNIF_1\"<span class=\"Apple-tab-span\">\t</span>runif(numeric$ min = 0, numeric$ max = 1)<br>\n\"RUNIF_2\"<span class=\"Apple-tab-span\">\t</span>runif(numeric$ min, numeric$ max)<span class=\"s19\"> other cases</span><br>\n\"RUNIF_3\"<span class=\"Apple-tab-span\">\t</span>runif()<span class=\"s19\"> other cases</span></p>\n<p class=\"p10\">\"SORT_INT\"<span class=\"Apple-tab-span\">\t</span>sort(integer x)<br>\n\"SORT_FLOAT\"<span class=\"Apple-tab-span\">\t</span>sort(float x)<br>\n\"SORT_STRING\"<span class=\"Apple-tab-span\">\t</span>sort(string x)</p>\n<p class=\"p10\">\"CLIPPEDINTEGRAL_1S\"<span class=\"Apple-tab-span\">\t</span>clippedIntegral()<span class=\"s19\"> for </span>\"x\"<span class=\"s19\">, </span>\"y\"<span class=\"s19\">, </span>\"z\"<br>\n\"CLIPPEDINTEGRAL_2S\"<span class=\"Apple-tab-span\">\t</span>clippedIntegral()<span class=\"s19\"> for </span>\"xy\"<span class=\"s19\">, </span>\"xz\"<span class=\"s19\">, </span>\"yz\"<br>\n\"DRAWBYSTRENGTH\"<span class=\"Apple-tab-span\">\t</span>drawByStrength(returnDict=T)<br>\n\"INTNEIGHCOUNT\"<span class=\"Apple-tab-span\">\t</span>interactingNeighborSount()<br>\n\"LOCALPOPDENSITY\"<span class=\"Apple-tab-span\">\t</span>localPopulationDensity()<br>\n\"NEARESTINTNEIGH\"<span class=\"Apple-tab-span\">\t</span>nearestInteractingNeighbors(returnDict=T)<br>\n\"NEARESTNEIGH\"<span class=\"Apple-tab-span\">\t</span>nearestNeighbors(returnDict=T)<br>\n\"NEIGHCOUNT\"<span class=\"Apple-tab-span\">\t</span>neighborCount()<br>\n\"TOTNEIGHSTRENGTH\"<span class=\"Apple-tab-span\">\t</span>totalOfNeighborsStrengths()</p>\n<p class=\"p10\">\"POINT_IN_BOUNDS_1D\"<span class=\"Apple-tab-span\">\t</span>pointInBounds()<span class=\"s19\">, 1D case</span><br>\n\"POINT_IN_BOUNDS_2D\"<span class=\"Apple-tab-span\">\t</span>pointInBounds()<span class=\"s19\">, 2D case</span><br>\n\"POINT_IN_BOUNDS_3D\"<span class=\"Apple-tab-span\">\t</span>pointInBounds()<span class=\"s19\">, 3D case</span><br>\n\"POINT_PERIODIC_1D\"<span class=\"Apple-tab-span\">\t</span>pointPeriodic()<span class=\"s19\">, 1D case</span><br>\n\"POINT_PERIODIC_2D\"<span class=\"Apple-tab-span\">\t</span>pointPeriodic()<span class=\"s19\">, 2D case</span><br>\n\"POINT_PERIODIC_3D\"<span class=\"Apple-tab-span\">\t</span>pointPeriodic()<span class=\"s19\">, 3D case</span><br>\n\"POINT_REFLECTED_1D\"<span class=\"Apple-tab-span\">\t</span>pointReflected()<span class=\"s19\">, 1D case</span><br>\n\"POINT_REFLECTED_2D\"<span class=\"Apple-tab-span\">\t</span>pointReflected()<span class=\"s19\">, 2D case</span><br>\n\"POINT_REFLECTED_3D\"<span class=\"Apple-tab-span\">\t</span>pointReflected()<span class=\"s19\">, 3D case</span><br>\n\"POINT_STOPPED_1D\"<span class=\"Apple-tab-span\">\t</span>pointStopped()<span class=\"s19\">, 1D case</span><br>\n\"POINT_STOPPED_2D\"<span class=\"Apple-tab-span\">\t</span>pointStopped()<span class=\"s19\">, 2D case</span><br>\n\"POINT_STOPPED_3D\"<span class=\"Apple-tab-span\">\t</span>pointStopped()<span class=\"s19\">, 3D case</span><br>\n\"POINT_UNIFORM_1D\"<span class=\"Apple-tab-span\">\t</span>pointUniform()<span class=\"s19\">, 1D case</span><br>\n\"POINT_UNIFORM_2D\"<span class=\"Apple-tab-span\">\t</span>pointUniform()<span class=\"s19\">, 2D case</span><br>\n\"POINT_UNIFORM_3D\"<span class=\"Apple-tab-span\">\t</span>pointUniform()<span class=\"s19\">, 3D case</span><br>\n\"SET_SPATIAL_POS_1_1D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with one point, 1D case</span><br>\n\"SET_SPATIAL_POS_1_2D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with one point, 2D case</span><br>\n\"SET_SPATIAL_POS_1_3D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with one point, 3D case</span><br>\n\"SET_SPATIAL_POS_2_1D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with <i>N</i> points, 1D case</span><br>\n\"SET_SPATIAL_POS_2_2D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with <i>N</i> points, 2D case</span><br>\n\"SET_SPATIAL_POS_2_3D\"<span class=\"Apple-tab-span\">\t</span>setSpatialPosition()<span class=\"s19\"> with <i>N</i> points, 3D case</span><br>\n\"SPATIAL_MAP_VALUE\"<span class=\"Apple-tab-span\">\t</span>spatialMapValue()</p>\n<p class=\"p10\">\"CONTAINS_MARKER_MUT\"<span class=\"Apple-tab-span\">\t</span>containsMarkerMutation(returnMutation = F)<br>\n\"I_COUNT_OF_MUTS_OF_TYPE\"<span class=\"Apple-tab-span\">\t</span>countOfMutationsOfType() (Individual)<br>\n\"H_COUNT_OF_MUTS_OF_TYPE\"<span class=\"Apple-tab-span\">\t</span>countOfMutationsOfType() (Haplosome)<br>\n\"INDS_W_PEDIGREE_IDS\"<span class=\"Apple-tab-span\">\t</span>individualsWithPedigreeIDs()<br>\n\"RELATEDNESS\"<span class=\"Apple-tab-span\">\t</span>relatedness()<br>\n\"SAMPLE_INDIVIDUALS_1\"<span class=\"Apple-tab-span\">\t</span>sampleIndividuals()<span class=\"s19\"> simple case with replace=T</span><br>\n\"SAMPLE_INDIVIDUALS_2\"<span class=\"Apple-tab-span\">\t</span>sampleIndividuals()<span class=\"s19\"> base case with replace=T</span><br>\n\"SET_FITNESS_SCALE_1\"<span class=\"Apple-tab-span\">\t</span>Individual.fitness = <span class=\"s19\">one value</span><br>\n\"SET_FITNESS_SCALE_2\"<span class=\"Apple-tab-span\">\t</span>Individual.fitness = <span class=\"s19\"><i>N</i> values</span><br>\n\"SUM_OF_MUTS_OF_TYPE\"<span class=\"Apple-tab-span\">\t</span>sumOfMutationsOfType()</p>\n<p class=\"p11\"><span class=\"s2\">\"AGE_INCR\"<span class=\"Apple-tab-span\">\t</span></span>incrementing <span class=\"s2\">Individual age</span> values<span class=\"s2\"><br>\n\"DEFERRED_REPRO\"<span class=\"Apple-tab-span\">\t</span></span>deferred nonWF reproduction<span class=\"s2\"><br>\n\"WF_REPRO\"<span class=\"Apple-tab-span\">\t</span></span>WF reproduction (no callbacks)<span class=\"s2\"><br>\n\"FITNESS_ASEX_1\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, asex, individual <span class=\"s2\">fitnessScaling<br>\n\"FITNESS_ASEX_2\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, asex, no <span class=\"s2\">fitnessScaling</span> or mutations<span class=\"s2\"><br>\n\"FITNESS_ASEX_3\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, asex, <span class=\"s2\">fitnessScaling</span> and mutations<span class=\"s2\"><br>\n\"FITNESS_SEX_1\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, sexual, individual <span class=\"s2\">fitnessScaling<br>\n\"FITNESS_SEX_2\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, sexual, no <span class=\"s2\">fitnessScaling</span> or mutations<span class=\"s2\"><br>\n\"FITNESS_SEX_3\"<span class=\"Apple-tab-span\">\t</span></span>fitness eval, sexual, <span class=\"s2\">fitnessScaling</span> and mutations<span class=\"s2\"><br>\n\"MIGRANT_CLEAR\"<span class=\"Apple-tab-span\">\t</span></span>clearing the <span class=\"s2\">migrant</span> property at tick end<span class=\"s2\"><br>\n\"SIMPLIFY_SORT_PRE\"<span class=\"Apple-tab-span\">\t</span></span>preparation for simplification sorting (internal)<span class=\"s2\"><br>\n\"SIMPLIFY_SORT\"<span class=\"Apple-tab-span\">\t</span></span>simplification sorting<span class=\"s2\"><br>\n\"SIMPLIFY_SORT_POST\"<span class=\"Apple-tab-span\">\t</span></span>cleanup after simplification sorting (internal)<span class=\"s2\"><br>\n\"PARENTS_CLEAR\"<span class=\"Apple-tab-span\">\t</span></span>clearing parental haplosomes at tick end in WF models<span class=\"s2\"><br>\n\"UNIQUE_MUTRUNS\"<span class=\"Apple-tab-span\">\t</span></span>uniquing mutation runs (internal bookkeeping)<span class=\"s2\"><br>\n\"SURVIVAL\"<span class=\"Apple-tab-span\">\t</span></span>survival evaluation (no callbacks)</p>\n<p class=\"p5\">Typically, a dictionary of task keys and thread counts is read from a file and set up with this function at initialization time, but it is also possible to change new task thread counts dynamically.<span class=\"Apple-converted-space\">  </span>If Eidos is not configured to run multithreaded, this function has no effect.</p>\n<p class=\"p4\">(string$)readLine(void)</p>\n<p class=\"p5\"><b>Reads a line of input from the “standard input” file.</b><span class=\"Apple-converted-space\">  </span>This function is intended to allow for communication between a running Eidos script (such as a SLiM simulation) and an external process that is sending input to it.<span class=\"Apple-converted-space\">  </span>It reads one line from the standard input and returns it as a singleton <span class=\"s2\">string</span>.<span class=\"Apple-converted-space\">  </span>This is done with the C++ function <span class=\"s2\">std::getline()</span>, using the <span class=\"s2\">std::cin</span> file.<span class=\"Apple-converted-space\">  </span>If that call returns false (typically because the end-of-file was reached or there was a read error of some kind), the empty string <span class=\"s2\">\"\"</span> will be returned.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">system()</span> function can also be helpful for related situations.</p>\n<p class=\"p5\">This function will raise an error if called in a GUI environment such as EidosScribe, SLiMgui, or SLiMguiLegacy, since there is no standard input set up for the running script in those environments.</p>\n<p class=\"p4\">(void)rm([Ns variableNames = NULL])</p>\n<p class=\"p5\"><b>Removes variables</b> from the Eidos namespace; in other words, it causes the variables to become undefined.<span class=\"Apple-converted-space\">  </span>Variables are specified by their <span class=\"s2\">string</span> name in the <span class=\"s2\">variableNames</span> parameter.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s2\">variableNames</span> parameter is <span class=\"s2\">NULL</span> (the default), <i>all</i> variables will be removed (be careful!).</p>\n<p class=\"p5\">In SLiM 3, there was an optional parameter <span class=\"s2\">removeConstants</span> that, if <span class=\"s2\">T</span>, allowed you to remove defined constants (and then potentially redefine them to have a different value).<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">removeConstants</span> parameter was removed in SLiM 4, since the <span class=\"s2\">defineGlobal()</span> function now provides the ability to define (and redefine) global variables that are not constant.</p>\n<p class=\"p2\">(*)sapply(* x, string$ lambdaSource, [string$ simplify = \"vector\"])</p>\n<p class=\"p8\"><span class=\"s5\"><i>Named </i></span><span class=\"s9\"><i>apply()</i></span><span class=\"s5\"><i> prior to Eidos 1.6 / SLiM 2.6</i></span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Applies a block of Eidos code to the elements of x</b>.<span class=\"Apple-converted-space\">  </span>This function is sort of a hybrid between </span><span class=\"s9\">c()</span><span class=\"s5\"> and </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">; it might be useful to consult the documentation for both of those functions to better understand what </span><span class=\"s9\">sapply()</span><span class=\"s5\"> does.<span class=\"Apple-converted-space\">  </span>For each element in </span><span class=\"s9\">x</span><span class=\"s5\">, the lambda defined by </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> will be called.<span class=\"Apple-converted-space\">  </span>For the duration of that callout, a variable named </span><span class=\"s9\">applyValue</span><span class=\"s5\"> will be defined to have as its value the element of </span><span class=\"s9\">x</span><span class=\"s5\"> currently being processed.<span class=\"Apple-converted-space\">  </span>The expectation is that the lambda will use </span><span class=\"s9\">applyValue</span><span class=\"s5\"> in some way, and will return either </span><span class=\"s9\">NULL</span><span class=\"s5\"> or a new value (which need not be a singleton, and need not be of the same type as </span><span class=\"s9\">x</span><span class=\"s5\">).<span class=\"Apple-converted-space\">  </span>The return value of </span><span class=\"s9\">sapply()</span><span class=\"s5\"> is generated by concatenating together all of the individual vectors returned by the lambda, in exactly the same manner as the </span><span class=\"s9\">c()</span><span class=\"s5\"> function (including the possibility of type promotion).</span></p>\n<p class=\"p5\"><span class=\"s5\">Since this function can be hard to understand at first, here is an example:</span></p>\n<p class=\"p12\"><span class=\"s5\">sapply(1:10, \"if (applyValue % 2) applyValue ^ 2; else NULL;\");</span></p>\n<p class=\"p5\">This produces the output <span class=\"s2\">1 9 25 49 81</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">sapply()</span> operation begins with the vector <span class=\"s2\">1:10</span>.<span class=\"Apple-converted-space\">  </span>For each element of that vector, the lambda is called and <span class=\"s2\">applyValue</span> is defined with the element value.<span class=\"Apple-converted-space\">  </span>In this respect, <span class=\"s2\">sapply()</span> is actually very much like a <span class=\"s2\">for</span> loop.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">applyValue</span> is even (as evaluated by the modulo operator, <span class=\"s2\">%</span>), the condition of the <span class=\"s2\">if</span> statement is <span class=\"s2\">F</span> and so <span class=\"s2\">NULL</span> is returned by the lambda; this must be done explicitly, since a <span class=\"s2\">void</span> return is not allowed by <span class=\"s2\">sapply()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">applyValue</span> is odd, on the other hand, the lambda returns its square (as calculated by the exponential operator, <span class=\"s2\">^</span>).<span class=\"Apple-converted-space\">  </span>Just as with the <span class=\"s2\">c()</span> function, <span class=\"s2\">NULL</span> values are dropped during concatenation, so the final result contains only the squares of the odd values.</p>\n<p class=\"p5\"><span class=\"s5\">This example illustrates that the lambda can “drop” values by returning </span><span class=\"s9\">NULL</span><span class=\"s5\">, so </span><span class=\"s9\">sapply()</span><span class=\"s5\"> can be used to select particular elements of a vector that satisfy some condition, much like the subscript operator, </span><span class=\"s9\">[]</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>The example also illustrates that input and result types do not have to match; the vector passed in is </span><span class=\"s9\">integer</span><span class=\"s5\">, whereas the result vector is </span><span class=\"s9\">float</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">Beginning in Eidos 1.6, a new optional parameter named </span><span class=\"s9\">simplify</span><span class=\"s5\"> allows the result of </span><span class=\"s9\">sapply()</span><span class=\"s5\"> to be a matrix or array in certain cases, better organizing the elements of the result.<span class=\"Apple-converted-space\">  </span>If the </span><span class=\"s9\">simplify</span><span class=\"s5\"> parameter is </span><span class=\"s9\">\"vector\"</span><span class=\"s5\">, the concatenated result value is returned as a plain vector in all cases; this is the default behavior, for backward compatibility.<span class=\"Apple-converted-space\">  </span>Two other possible values for </span><span class=\"s9\">simplify</span><span class=\"s5\"> are presently supported.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">simplify</span><span class=\"s5\"> is </span><span class=\"s9\">\"matrix\"</span><span class=\"s5\">, the concatenated result value will be turned into a matrix with one column for each non-</span><span class=\"s9\">NULL</span><span class=\"s5\"> value returned by the lambda, as if the values were joined together with </span><span class=\"s9\">cbind()</span><span class=\"s5\">, as long as all of the lambda’s return values are either (a) </span><span class=\"s9\">NULL</span><span class=\"s5\"> or (b) the same length as the other non-</span><span class=\"s9\">NULL</span><span class=\"s5\"> values returned.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">simplify</span><span class=\"s5\"> is </span><span class=\"s9\">\"match\"</span><span class=\"s5\">, the concatenated result value will be turned into a vector, matrix, or array that exactly matches the dimensions as </span><span class=\"s9\">x</span><span class=\"s5\">, with a one-to-one correspondence between </span><span class=\"s9\">x</span><span class=\"s5\"> and the elements of the return value just like a unary operator, as long as all of the lambda’s return values are singletons (with no </span><span class=\"s9\">NULL</span><span class=\"s5\"> values).<span class=\"Apple-converted-space\">  </span>Both </span><span class=\"s9\">\"matrix\"</span><span class=\"s5\"> and </span><span class=\"s9\">\"match\"</span><span class=\"s5\"> will raise an error if their preconditions are not met, to avoid unexpected behavior, so care should be taken that the preconditions are always met when these options are used.</span></p>\n<p class=\"p5\"><span class=\"s5\">As with </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">, all defined variables are accessible within the lambda, and changes made to variables inside the lambda will persist beyond the end of the </span><span class=\"s9\">sapply()</span><span class=\"s5\"> call; the lambda is executing in the same scope as the rest of your code.</span></p>\n<p class=\"p5\"><span class=\"s5\">The </span><span class=\"s9\">sapply()</span><span class=\"s5\"> function can seem daunting at first, but it is an essential tool in the Eidos toolbox.<span class=\"Apple-converted-space\">  </span>It combines the iteration of a </span><span class=\"s9\">for</span><span class=\"s5\"> loop, the ability to select elements like operator </span><span class=\"s9\">[]</span><span class=\"s5\">, and the ability to assemble results of mixed type together into a single vector like </span><span class=\"s9\">c()</span><span class=\"s5\">, all with the power of arbitrary Eidos code execution like </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>It is relatively fast, compared to other ways of achieving similar results such as a </span><span class=\"s9\">for</span><span class=\"s5\"> loop that accumulates results with </span><span class=\"s9\">c()</span><span class=\"s5\">.<span class=\"Apple-converted-space\">  </span>Like </span><span class=\"s9\">executeLambda()</span><span class=\"s5\">, </span><span class=\"s9\">sapply()</span><span class=\"s5\"> is most efficient if it is called multiple times with a single </span><span class=\"s9\">string</span><span class=\"s5\"> script variable, rather than with a newly constructed </span><span class=\"s9\">string</span><span class=\"s5\"> for </span><span class=\"s9\">lambdaSource</span><span class=\"s5\"> each time.</span></p>\n<p class=\"p5\"><span class=\"s5\">Prior to Eidos 1.6 (SLiM 2.6), </span><span class=\"s9\">sapply()</span><span class=\"s5\"> was instead named </span><span class=\"s9\">apply()</span><span class=\"s5\">; it was renamed to </span><span class=\"s9\">sapply()</span><span class=\"s5\"> in order to more closely match the naming of functions in R.<span class=\"Apple-converted-space\">  </span>This renaming allowed a new </span><span class=\"s9\">apply()</span><span class=\"s5\"> function to be added to Eidos that operates on the margins of matrices and arrays, similar to the </span><span class=\"s9\">apply()</span><span class=\"s5\"> function of R (see </span><span class=\"s9\">apply()</span><span class=\"s5\">, above).</span></p>\n<p class=\"p2\">(void)setSeed(integer$ seed)</p>\n<p class=\"p3\"><b>Set the random number seed</b>.<span class=\"Apple-converted-space\">  </span>Future random numbers will be based upon the seed value set, and the random number sequence generated from a particular seed value is guaranteed to be reproducible.<span class=\"Apple-converted-space\">  </span>The last seed set can be recovered with the <span class=\"s2\">getSeed()</span> function.</p>\n<p class=\"p2\">(void)source(string$<span class=\"s1\"> </span>filePath<span class=\"s6\">, [logical$ chdir = F]</span>)</p>\n<p class=\"p5\"><b>Executes the contents of an Eidos source file</b> found at the filesystem path <span class=\"s2\">filePath</span>.<span class=\"Apple-converted-space\">  </span>This is essentially shorthand for calling <span class=\"s2\">readFile()</span>, joining the read lines with newlines to form a single string using <span class=\"s2\">paste()</span>, and then passing that string to <span class=\"s2\">executeLambda()</span>.<span class=\"Apple-converted-space\">  </span>The source file must consist of complete Eidos statements.<span class=\"Apple-converted-space\">  </span>Regardless of what the last executed source line evaluates to, <span class=\"s2\">source()</span> has no return value.<span class=\"Apple-converted-space\">  </span>If no file exists at <span class=\"s2\">filePath</span>, an error will be raised.</p>\n<p class=\"p5\">The <span class=\"s2\">chdir</span> parameter controls the current working directory in effect while the source file is executed.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">chdir</span> is <span class=\"s2\">F</span> (the default), the current working directory will remain unchanged.<span class=\"Apple-converted-space\">  </span>If <span class=\"s2\">chdir</span> is <span class=\"s2\">T</span>, the current working directory will be temporarily changed to the filesystem path at which the source file is located, and restored after execution of the source file is complete.</p>\n<p class=\"p2\">(void)stop([Ns$<span class=\"s1\"> </span>message<span class=\"s1\"> </span>= NULL])</p>\n<p class=\"p3\"><b>Stops execution</b> of Eidos (and of the Context, such as the running SLiM simulation, if applicable), in the event of an error.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s2\">message</span> parameter is not <span class=\"s2\">NULL</span>, it will be printed to Eidos’s output stream prior to stopping.</p>\n<p class=\"p4\"><span class=\"s5\">(logical$)suppressWarnings(logical$ suppress)</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Turns suppression of warning messages on or off</b>.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s9\">suppress</span><span class=\"s5\"> flag indicates whether suppression of warnings should be enabled (</span><span class=\"s9\">T</span><span class=\"s5\">) or disabled (</span><span class=\"s9\">F</span><span class=\"s5\">).<span class=\"Apple-converted-space\">  </span>The previous warning-suppression value is returned by </span><span class=\"s9\">suppressWarnings()</span><span class=\"s5\">, making it easy to suppress warnings from a given call and then return to the previous suppression state afterwards.<span class=\"Apple-converted-space\">  </span>It is recommended that warnings be suppressed only around short blocks of code (not all the time), so that unexpected but perhaps important warnings are not missed.<span class=\"Apple-converted-space\">  </span>And of course warnings are generally emitted for good reasons; before deciding to disregard a given warning, make sure that you understand exactly why it is being issued, and are certain that it does not represent a serious problem.</span></p>\n<p class=\"p4\">(*)sysinfo(string$ key)</p>\n<p class=\"p5\"><b>Returns information about the system</b>.<span class=\"Apple-converted-space\">  </span>The information returned by <span class=\"s2\">tempdir()</span> depends upon the value of <span class=\"s2\">key</span>, which selects one of the pieces of information listed:</p>\n<p class=\"p13\"><span class=\"s22\"><b>key</b></span><span class=\"Apple-tab-span\">\t</span><span class=\"s22\"><b>value</b></span></p>\n<p class=\"p13\"><span class=\"s2\">os</span><span class=\"Apple-tab-span\">\t</span>the name of the OS; <span class=\"s2\">\"macOS\"</span> or <span class=\"s2\">\"Windows\"</span>, or <span class=\"s2\">\"Unix\"</span> for all others</p>\n<p class=\"p13\"><span class=\"s2\">sysname</span><span class=\"Apple-tab-span\">\t</span>the name of the kernel</p>\n<p class=\"p13\"><span class=\"s2\">release</span><span class=\"Apple-tab-span\">\t</span>the operating system (kernel) release</p>\n<p class=\"p13\"><span class=\"s2\">version</span><span class=\"Apple-tab-span\">\t</span>the operating system (kernel) version</p>\n<p class=\"p13\"><span class=\"s2\">nodename</span><span class=\"Apple-tab-span\">\t</span>the name by which the machine is known on the network</p>\n<p class=\"p13\"><span class=\"s2\">machine</span><span class=\"Apple-tab-span\">\t</span>the hardware type; often the CPU type (e.g., <span class=\"s2\">\"x86_64\"</span>)</p>\n<p class=\"p5\">The value <span class=\"s2\">\"unknown\"</span> will be returned for a key if the correct value cannot be ascertained.<span class=\"Apple-converted-space\">  </span>Note that the values of keys that refer to the kernel may not be what you expect; for example, on one particular macOS 10.15.7 system, <span class=\"s2\">sysname</span> returns <span class=\"s2\">\"Darwin\"</span>, <span class=\"s2\">release</span> returns <span class=\"s2\">\"19.6.0\"</span>, and <span class=\"s2\">version</span> returns <span class=\"s2\">\"Darwin Kernel Version 19.6.0: Thu Sep 16 20:58:47 PDT 2021; root:xnu-6153.141.40.1~1/RELEASE_X86_64\"</span>.</p>\n<p class=\"p5\">Further keys can be added if there is information that would be useful, particularly if a cross-platform way to obtain the information can be found.</p>\n<p class=\"p2\">(string)system(string$ command, [string args = \"\"], [string input = \"\"], [logical$ stderr = F], [logical$ wait = T])</p>\n<p class=\"p3\"><b>Runs a Un*x command in a </b><span class=\"s2\"><b>/bin/sh</b></span><b> shell</b> with optional arguments and input, and returns the result as a vector of output lines.<span class=\"Apple-converted-space\">  </span>The <span class=\"s2\">args</span> parameter may contain a vector of arguments to <span class=\"s2\">command</span>; they will be passed directly to the shell without any quoting, so applying the appropriate quoting as needed by <span class=\"s2\">/bin/sh</span> is the caller’s responsibility.<span class=\"Apple-converted-space\">  </span>The arguments are appended to <span class=\"s2\">command</span>, separated by spaces, and the result is passed to the shell as a single command string, so arguments may simply be given as part of <span class=\"s2\">command</span> instead, if preferred.<span class=\"Apple-converted-space\">  </span>By default no input is supplied to <span class=\"s2\">command</span>; if <span class=\"s2\">input</span> is non-empty, however, it will be written to a temporary file (one line per <span class=\"s2\">string</span> element) and the standard input of <span class=\"s2\">command</span> will be redirected to that temporary file (using standard <span class=\"s2\">/bin/sh</span> redirection with <span class=\"s2\">&lt;</span>, appended to the command string passed to the shell).<span class=\"Apple-converted-space\">  </span>By default, output sent to standard error will not be captured (and thus may end up in the output of the SLiM process, or may be lost); if <span class=\"s2\">stderr</span> is <span class=\"s2\">T</span>, however, the standard error stream will be redirected into standard out (using standard <span class=\"s2\">/bin/sh</span> redirection with <span class=\"s2\">2&gt;&amp;1</span>, appended to the command string passed to the shell).</p>\n<p class=\"p3\">Arbitrary command strings involving multiple commands, pipes, redirection, etc., may be used with <span class=\"s2\">system()</span>, but may be incompatible with the way that <span class=\"s2\">args</span><span class=\"s3\">,</span> <span class=\"s2\">input</span>, and <span class=\"s2\">stderr</span> are handled by this function, so in this case supplying the whole command string in <span class=\"s2\">command</span> may be the simplest course.<span class=\"Apple-converted-space\">  </span>You may redirect standard error into standard output yourself in <span class=\"s2\">command</span> with <span class=\"s2\">2&gt;&amp;1</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>Supplying input to a complex command line can often be facilitated by the use of parentheses to create a subshell; for example,</p>\n<p class=\"p14\">system(\"(wc -l | sed 's/ //g')\", input=c('foo', 'bar', 'baz'));</p>\n<p class=\"p3\">will supply the input lines to <span class=\"s2\">wc</span> courtesy of the subshell started for the <span class=\"s2\">()</span> operator.<span class=\"Apple-converted-space\">  </span>If this strategy doesn’t work for the command line you want to execute, you can always write a temporary file yourself using <span class=\"s2\">writeFile()</span> or <span class=\"s2\">writeTempFile()</span> and redirect that file to standard input in <span class=\"s2\">command</span> with <span class=\"s2\">&lt;</span><span class=\"s3\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">If </span><span class=\"s9\">wait</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\"> (the default), </span><span class=\"s9\">system()</span><span class=\"s5\"> will wait for the command to finish, and return the output generated as a </span><span class=\"s9\">string</span><span class=\"s5\"> vector, as described above.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">wait</span><span class=\"s5\"> is </span><span class=\"s9\">F</span><span class=\"s5\">, </span><span class=\"s9\">system()</span><span class=\"s5\"> will instead append </span><span class=\"s9\">\" &amp;\"</span><span class=\"s5\"> to the end of the command line to request that it be run in the background, and it will not collect and return the output from the command; instead it will return </span><span class=\"s9\">string(0)</span><span class=\"s5\"> immediately.<span class=\"Apple-converted-space\">  </span>If the output from the command is needed, it could be redirected to a file, and that file could be checked periodically in Eidos for some indication that the command had completed; if output is not redirected to a file, it may appear in SLiM’s output stream.<span class=\"Apple-converted-space\">  </span>If the final command line executed by </span><span class=\"s9\">system()</span><span class=\"s5\"> ends in </span><span class=\"s9\">\" &amp;\"</span><span class=\"s5\">, the behavior of </span><span class=\"s9\">system()</span><span class=\"s5\"> should be just as if </span><span class=\"s9\">wait=T</span><span class=\"s5\"> had been supplied, but it is recommended to use </span><span class=\"s9\">wait=T</span><span class=\"s5\"> instead to ensure that the command line is correctly assembled.</span></p>\n<p class=\"p5\">There is an example at <a href=\"https://github.com/MesserLab/SLiM-Extras/blob/master/functions/rgnorm.slim\"><span class=\"s20\">https://github.com/MesserLab/SLiM-Extras/blob/master/functions/rgnorm.slim</span></a> that demonstrates the use of <span class=\"s2\">system()</span>, calling out to Python, to obtain draws from a generalized normal distribution (which is not supported intrinsically by Eidos).<span class=\"Apple-converted-space\">  </span>That example even includes internal buffering of a large number of draws, making it a reasonably efficient solution.</p>\n<p class=\"p2\">(string$)time(void)</p>\n<p class=\"p3\">Returns a <b>standard time string</b> for the current time in the local time of the executing machine.<span class=\"Apple-converted-space\">  </span>The format is <span class=\"s2\">%H:%M:%S</span> (hour in two digits, then minute in two digits, then seconds in two digits, zero-padded and separated by dashes) regardless of the localization of the executing machine, for predictability and consistency.<span class=\"Apple-converted-space\">  </span>The 24-hour clock time is used (i.e., no AM/PM).</p>\n<p class=\"p4\"><span class=\"s5\">(float$)usage(</span>[ls$ type = \"rss\"]<span class=\"s5\">)</span></p>\n<p class=\"p5\">Returns the <b>memory usage</b>.<span class=\"Apple-converted-space\">  </span>This is the amount of memory used by the current process, in MB (megabytes); multiply by <span class=\"s2\">1024*1024</span> to get the usage in bytes.</p>\n<p class=\"p5\">Memory usage is a surprisingly complex topic.<span class=\"Apple-converted-space\">  </span>One metric reported by <span class=\"s2\">usage()</span> is the resident set size, or RSS, which includes memory usage from shared libraries, but does not include memory that is swapped out or has never been used.<span class=\"Apple-converted-space\">  </span>For most purposes, RSS is a useful metric of memory usage from a practical perspective.<span class=\"Apple-converted-space\">  </span>On some platforms (AIX, BSD, Solaris) the memory usage reported may be zero, but it should be correct on both macOS and Linux platforms.<span class=\"Apple-converted-space\">  </span>On macOS, memory pages that have not been used for a while may get compressed by the kernel to reduce the RSS of the process; the RSS metric reported by <span class=\"s2\">usage()</span> will reflect the compressed size of such pages, not their original size, so surprising decreases in memory usage may be observed when the kernel decides to compress some memory pages.<span class=\"Apple-converted-space\">  </span>The RSS is requested with a <span class=\"s2\">type</span> of <span class=\"s2\">\"rss\"</span>, which is the default; for historical reasons, it can also be requested with a <span class=\"s2\">type</span> of <span class=\"s2\">F</span>.</p>\n<p class=\"p5\">Another metric reported by <span class=\"s2\">usage()</span> is the peak RSS.<span class=\"Apple-converted-space\">  </span>This is just the highest RSS value that has ever been recorded by the kernel.<span class=\"Apple-converted-space\">  </span>It should generally mirror the behavior of RSS, except that it ratchets upward monotonically.<span class=\"Apple-converted-space\">  </span>The peak RSS is requested with a <span class=\"s2\">type</span> of <span class=\"s2\">\"rss_peak\"</span>; for historical reasons, it can also be requested with a <span class=\"s2\">type</span> of <span class=\"s2\">T</span>.</p>\n<p class=\"p5\">The third metric currently reported by <span class=\"s2\">usage()</span> is the virtual memory usage.<span class=\"Apple-converted-space\">  </span>This is essentially the amount of memory used by pages that have been assigned to the process, whether those pages are resident, compressed, or swapped.<span class=\"Apple-converted-space\">  </span>It is typically much larger than the RSS, because it includes various types of memory that are not counted in the RSS; indeed, for some system configurations the virtual memory usage can be reported as being the entire memory space of the computer.<span class=\"Apple-converted-space\">  </span>Whether it is a useful metric will be platform-dependent; <i>caveat emptor</i>.</p>\n<p class=\"p5\">This function can be useful for documenting the memory usage of long runs as they are in progress.<span class=\"Apple-converted-space\">  </span>In SLiM, the RSS could also be used to trigger tree-sequence simplification with a call to <span class=\"s2\">treeSeqSimplify()</span>, to reduce memory usage when it becomes too large, but keep in mind that the simplification process itself may cause a substantial spike in memory usage, and that page compression and swaps may reduce the RSS even though the memory actually used by tree-sequence recording continues to increase.</p>\n<p class=\"p5\">When running under SLiM, other tools for monitoring memory usage include the <span class=\"s2\">slim</span> command-line options <span class=\"s2\">-m[em]</span> and <span class=\"s2\">-M[emhist]</span>, and the <span class=\"s2\">usage()</span> and <span class=\"s2\">outputUsage()</span> methods of <span class=\"s2\">Community</span>; see the SLiM manual for more information.</p>\n<p class=\"p4\"><span class=\"s6\">(float)version(</span><span class=\"s5\">[logical$ print = T]</span><span class=\"s6\">)</span></p>\n<p class=\"p5\"><span class=\"s5\"><b>Get Eidos’s version.</b><span class=\"Apple-converted-space\">  </span>There are two ways to use this function.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">print</span><span class=\"s5\"> is </span><span class=\"s9\">T</span><span class=\"s5\">, the default, then the version number is printed to the Eidos output stream in a formatted manner, like “</span><span class=\"s9\">Eidos version 2.1</span><span class=\"s5\">”.<span class=\"Apple-converted-space\">  </span>If Eidos is attached to a Context that provides a version number, that is also printed, like “</span><span class=\"s9\">SLiM version 3.1</span><span class=\"s5\">”.<span class=\"Apple-converted-space\">  </span>In this case, the Eidos version number, and the Context version number if available, are returned as an invisible </span><span class=\"s9\">float</span><span class=\"s5\"> vector.<span class=\"Apple-converted-space\">  </span>This is most useful when using Eidos interactively.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s9\">print</span><span class=\"s5\"> is </span><span class=\"s9\">F</span><span class=\"s5\">, on the other hand, nothing is printed, but the returned </span><span class=\"s9\">float</span><span class=\"s5\"> vector of version numbers is not invisible.<span class=\"Apple-converted-space\">  </span>This is useful for scripts that need to test the Eidos or Context version they are running against.</span></p>\n<p class=\"p5\"><span class=\"s5\">In both cases, in the </span><span class=\"s9\">float</span><span class=\"s5\"> version numbers returned, a version like 2.4.2 would be returned as </span><span class=\"s9\">2.42</span><span class=\"s5\">; this would not scale well to subversions greater than nine, so that will be avoided in our versioning.</span></p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/EidosHelpOperators.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"1894.6\">\n  <style type=\"text/css\">\n    p.p1 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima}\n    p.p3 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima; color: #000000}\n    p.p4 {margin: 9.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo}\n    p.p5 {margin: 2.0px 0.0px 2.0px 0.0px; font: 11.0px Optima}\n    p.p6 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 27.4px; font: 11.0px Optima}\n    span.s1 {font: 9.0px Menlo}\n    span.s2 {font: 11.0px 'Times New Roman'}\n    span.s3 {font-kerning: none}\n    span.s4 {font: 9.0px Menlo; font-kerning: none}\n    span.Apple-tab-span {white-space:pre}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><i>2.2.2<span class=\"Apple-converted-space\">  </span>ITEM: 1. Sequences: operator </i><span class=\"s1\"><i>:</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">:</span> operator is used to construct vectors with (usually) more than one value.<span class=\"Apple-converted-space\">  </span>In particular, it is used to construct <i>sequences</i>, and so it is called the sequence operator.<span class=\"Apple-converted-space\">  </span>Given operands <span class=\"s1\">x</span> and <span class=\"s1\">y</span> (standing for any two numbers), the sequence operator starts at <span class=\"s1\">x</span> and counts, by <span class=\"s1\">1</span> (or <span class=\"s1\">-1</span>, as appropriate) toward <span class=\"s1\">y</span> without passing it.<span class=\"Apple-converted-space\">  </span>It yields a vector containing all of the numbers it encounters along the way.</p>\n<p class=\"p2\">Note that the sequence operator can count down as well as up, that it can handle <span class=\"s1\">float</span> as well as <span class=\"s1\">integer</span> operands, and that negative numbers are allowed.</p>\n<p class=\"p1\"><i>2.2.4<span class=\"Apple-converted-space\">  </span>ITEM: 2. Subsets: operator </i><span class=\"s1\"><i>[]</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">[]</span> operator selects a subset of the vector upon which it operates; it is thus often called the subset operator.<span class=\"Apple-converted-space\">  </span>It can work in one of two different ways, depending upon whether it is given an <span class=\"s1\">integer</span> vector of indices, or is given a <span class=\"s1\">logical</span> vector of selectors.</p>\n<p class=\"p2\">First of all, a subset can be selected with an <span class=\"s1\">integer</span> vector of indices.<span class=\"Apple-converted-space\">  </span>These indices are zero-based, like C but unlike R; the first value in a vector is thus at index <span class=\"s1\">0</span>, not index <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>Note that a given index can be used multiple times.</p>\n<p class=\"p2\">Second, a subset can be selected with a <span class=\"s1\">logical</span> vector of selectors.<span class=\"Apple-converted-space\">  </span>In this case, the <span class=\"s1\">logical</span> vector must be the same length as the vector being selected; each <span class=\"s1\">logical</span> value indicates whether the corresponding vector value should be selected (<span class=\"s1\">T</span>) or not (<span class=\"s1\">F</span>).</p>\n<p class=\"p1\"><i>2.3.1<span class=\"Apple-converted-space\">  </span>ITEM: 3. Arithmetic operators: </i><span class=\"s1\"><i>+</i></span><i>, </i><span class=\"s1\"><i>-</i></span><i>, </i><span class=\"s1\"><i>*</i></span><i>, </i><span class=\"s1\"><i>/</i></span><i>, </i><span class=\"s1\"><i>%</i></span><i>, </i><span class=\"s1\"><i>^</i></span></p>\n<p class=\"p2\">These are the standard operators of arithmetic; <span class=\"s1\">+</span> performs addition, <span class=\"s1\">-</span> performs subtraction, <span class=\"s1\">*</span> performs multiplication, <span class=\"s1\">/</span> performs division, <span class=\"s1\">%</span> performs a modulo operation (more on that below), and <span class=\"s1\">^</span> performs exponentiation.<span class=\"Apple-converted-space\">  </span>Not a great deal needs to be said about these operators, which behave according to the standard rules of mathematics.<span class=\"Apple-converted-space\">  </span>They also follow the standard rules of “precedence”; exponentiation is the highest precedence, addition and subtraction are the lowest precedence, and the other three are in the middle, so <span class=\"s1\">4^2+5*6^7</span> is grouped as (<span class=\"s1\">4^3)+(5*(6^7))</span>, as expected if you remember your grade-school math.</p>\n<p class=\"p2\">There are only a few minor twists to be discussed.<span class=\"Apple-converted-space\">  </span>One is the meaning of the <span class=\"s1\">%</span> operator, which many people have not previously encountered.<span class=\"Apple-converted-space\">  </span>This computes the “modulo” from a division, which is the remainder left behind after division.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s1\">13%6</span> is <span class=\"s1\">1</span>, because after <span class=\"s1\">13</span> is divided evenly by <span class=\"s1\">6</span> (taking care of <span class=\"s1\">12</span> of the <span class=\"s1\">13</span>), <span class=\"s1\">1</span> is left as a remainder.<span class=\"Apple-converted-space\">  </span>Probably the most common use of <span class=\"s1\">%</span> is in determining whether a number is even or odd by looking at the result of a <span class=\"s1\">%2</span> operation; <span class=\"s1\">5%2</span> is <span class=\"s1\">1</span>, indicating that <span class=\"s1\">5</span> is odd, whereas <span class=\"s1\">6%2</span> is <span class=\"s1\">0</span>, indicating that <span class=\"s1\">6</span> is even.</p>\n<p class=\"p2\">Another twist is that both the division and modulo operators in Eidos operate on <span class=\"s1\">float</span> values – even if <span class=\"s1\">integer</span> values are passed – and return <span class=\"s1\">float</span> results.<span class=\"Apple-converted-space\">  </span>(For those who care, division is performed internally using the C++ division operator <span class=\"s1\">/</span>, and modulo is performed using the C++ <span class=\"s1\">fmod()</span> function).<span class=\"Apple-converted-space\">  </span>This policy was chosen because the definitions of integer division and modulo vary widely among programming languages and are contested and unclear (see Bantchev 2006, http://www.math.bas.bg/bantchev/articles/divmod.pdf).<span class=\"Apple-converted-space\">  </span>If you are sure that you want <span class=\"s1\">integer</span> division or modulo, and understand the issues involved, Eidos provides the functions <span class=\"s1\">integerDiv()</span> and <span class=\"s1\">integerMod()</span> for this purpose.<span class=\"Apple-converted-space\">  </span>Besides side-stepping the vague definitions of the <span class=\"s1\">integer</span> operator, this policy also avoids rather common bugs involving the accidental use of <span class=\"s1\">integer</span> division when <span class=\"s1\">float</span> division was desired – a much more common occurrence than <i>vice versa</i><span class=\"s2\">.</span></p>\n<p class=\"p2\">A third twist is that <span class=\"s1\">+</span> and <span class=\"s1\">-</span> can both act as “unary” operators, meaning that they are happy to take just a single operand.<span class=\"Apple-converted-space\">  </span>This is standard math notation, as in the expressions <span class=\"s1\">-6+3</span> or <span class=\"s1\">7*-5</span>; but it can sometimes look a bit strange, as in the expression <span class=\"s1\">5--6</span> (more easily read as <span class=\"s1\">5 - -6</span>).</p>\n<p class=\"p2\">A fourth twist is that the <span class=\"s1\">^</span> operator is right-associative, whereas all other binary Eidos operators are left-associative.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s1\">2-3-4</span> is evaluated as <span class=\"s1\">(2-3)-4</span>, not as <span class=\"s1\">2-(3-4)</span>; this is left-associativity.<span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">2^3^4</span> is evaluated as <span class=\"s1\">2^(3^4)</span>, not <span class=\"s1\">(2^3)^4</span>; this is right-associativity.<span class=\"Apple-converted-space\">  </span>Since this follows the standard associativity for these operators, in both mathematics and most other programming languages, the result should generally be intuitive, but if you have never explicitly thought about associativity before you might be taken by surprise.</p>\n<p class=\"p2\">A fifth twist is that the arithmetic operators and functions in Eidos are guaranteed to handle overflows safely.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">float</span> type is safe because it uses IEEE-standard arithmetic, including the use of <span class=\"s1\">INF</span> to indicate infinities and the use of <span class=\"s1\">NAN</span> to represent not-a-number results; this is the same as in most languages.<span class=\"Apple-converted-space\">  </span>In Eidos, however, the <span class=\"s1\">integer</span> type is also safe, unlike in C, C++, and many other languages.<span class=\"Apple-converted-space\">  </span>All operations on <span class=\"s1\">integer</span> values in Eidos either (1) will always produce <span class=\"s1\">float</span> results, as the <span class=\"s1\">/</span> and <span class=\"s1\">%</span> operators do; (2) will produce <span class=\"s1\">float</span> results when needed to avoid overflow, as the <span class=\"s1\">product()</span> and <span class=\"s1\">sum()</span> functions do; or (3) will raise an error condition on an overflow, as the Eidos operators <span class=\"s1\">+</span>, <span class=\"s1\">-</span>, and <span class=\"s1\">*</span> do, as well as the <span class=\"s1\">abs()</span> and <span class=\"s1\">asInteger()</span> functions.<span class=\"Apple-converted-space\">  </span>This means that the <span class=\"s1\">integer</span> type in Eidos can be used without fear that overflows might cause results to be incorrect.</p>\n<p class=\"p2\">The final twist is really a reminder: <i>everything is a vector</i>.<span class=\"Apple-converted-space\">  </span>These operators are designed to do something smart, when possible, with vectors of any length, not just with single-valued vectors as shown above.<span class=\"Apple-converted-space\">  </span>In general, the operands of these arithmetic operators must either be the same length (in which case the elements in the operand vectors are paired off and the operation is performed between each pair), or one or the other vector must be of length <span class=\"s1\">1</span> (in which case the operation is performed using that single value, paired with each value in the other operand vector).</p>\n<p class=\"p1\"><i>2.3.2<span class=\"Apple-converted-space\">  </span>ITEM: 4. Logical operators: </i><span class=\"s1\"><i>|</i></span><i>, </i><span class=\"s1\"><i>&amp;</i></span><i>, </i><span class=\"s1\"><i>!</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">|</span>, <span class=\"s1\">&amp;</span>, and <span class=\"s1\">!</span> operators act upon <span class=\"s1\">logical</span> values.<span class=\"Apple-converted-space\">  </span>If they are given operands of other types, those operands will be “coerced” to <span class=\"s1\">logical</span> values following the rule mentioned above: zero is <span class=\"s1\">F</span>, non-zero is <span class=\"s1\">T</span> (and for <span class=\"s1\">string</span> operands, a <span class=\"s1\">string</span> that is zero characters long – the empty string, <span class=\"s1\">\"\"</span> – is considered <span class=\"s1\">F</span>, while all other <span class=\"s1\">string</span> values are considered <span class=\"s1\">T</span>).</p>\n<p class=\"p2\">As to what they do: <span class=\"s1\">|</span> is the “or” operation, <span class=\"s1\">&amp;</span> is the “and” operation, and <span class=\"s1\">!</span> is the “not” operation.<span class=\"Apple-converted-space\">  </span>As in common parlance, “or” is <span class=\"s1\">T</span> if either of its operands is <span class=\"s1\">T</span>, whereas “and” is <span class=\"s1\">T</span> only if both of its operands are <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>The “not” operator is unary (it takes only one operand), and it negates its operand; <span class=\"s1\">T</span> becomes <span class=\"s1\">F</span>, <span class=\"s1\">F</span> becomes <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>As with the arithmetic operators, these operators work with vector operands, too – either matching up values pairwise between the two operands, or applying a single value across a multivalued operand.</p>\n<p class=\"p2\">Those familiar with programming might wish to know that the <span class=\"s1\">|</span> and <span class=\"s1\">&amp;</span> operators do not “short-circuit” – they can’t, because they are vector operators. If the <span class=\"s1\">&amp;</span> operator first sees an operand that evaluates to <span class=\"s1\">F</span>, for example, it knows that it will produce <span class=\"s1\">F</span> value(s) as a result; but it does not know what size result vector to make. If a later operand is a multivalued vector, the <span class=\"s1\">&amp;</span> operator will produce a result vector of matching length; if all later operands are also length <span class=\"s1\">1</span>, however, <span class=\"s1\">&amp;</span> will produce a result vector of length <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>To know this for sure (and to make sure that there are no illegal length mismatches between later operands), it must evaluate all of its operands; it cannot short-circuit.<span class=\"Apple-converted-space\">  </span>Similarly for the <span class=\"s1\">|</span> operator.</p>\n<p class=\"p2\">These semantics match those in R, for its <span class=\"s1\">|</span> and <span class=\"s1\">&amp;</span> operators, but they might seem a little strange to those used to C and other scalar-based languages.<span class=\"Apple-converted-space\">  </span>For those used to R, on the other hand, it should be noted here that Eidos does not support the <span class=\"s1\">&amp;&amp;</span> and <span class=\"s1\">||</span> operators of R, for reasons of simplicity; it is safer to use the <span class=\"s1\">any()</span> or <span class=\"s1\">all()</span> functions to simplify multivalued <span class=\"s1\">logical</span> vectors before using <span class=\"s1\">&amp;</span> or <span class=\"s1\">|</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>If this is gibberish to you, it is not important; the point here is only to prevent confusion among users accustomed to R.</p>\n<p class=\"p1\"><i>2.3.3<span class=\"Apple-converted-space\">  </span>ITEM: 5. Comparative operators: </i><span class=\"s1\"><i>==</i></span><i>, </i><span class=\"s1\"><i>!=</i></span><i>, </i><span class=\"s1\"><i>&lt;</i></span><i>, </i><span class=\"s1\"><i>&lt;=</i></span><i>, </i><span class=\"s1\"><i>&gt;</i></span><i>, </i><span class=\"s1\"><i>&gt;=</i></span></p>\n<p class=\"p2\">These operators compare their left and right operand.<span class=\"Apple-converted-space\">  </span>The operators test for equality (<span class=\"s1\">==</span>), inequality (<span class=\"s1\">!=</span>), less-than (<span class=\"s1\">&lt;</span>), less-than-or-equality (<span class=\"s1\">&lt;=</span>), greater-than (<span class=\"s1\">&gt;</span>), and greater-than-or-equality (<span class=\"s1\">&gt;=</span>) relationships.<span class=\"Apple-converted-space\">  </span>As seen above with the arithmetic and logical operators, this can work in two different ways: if the operands are the same length, their elements are paired up and the comparison is done between each pair, whereas if the operands are not the same length then one operand must be of length one, and its value is compared against all of the values of the other operand.</p>\n<p class=\"p2\">Regardless of the types of the operands, these operators all produce a <span class=\"s1\">logical</span> result vector.<span class=\"Apple-converted-space\">  </span>If the operands are of different types, promotion will be used to coerce them to be the same type (i.e. <span class=\"s1\">logical</span> will be coerced to <span class=\"s1\">integer</span>, <span class=\"s1\">integer</span> to <span class=\"s1\">float</span>, and <span class=\"s1\">float</span> to <span class=\"s1\">string</span>).<span class=\"Apple-converted-space\">  </span>Note that this is often not what you want!<span class=\"Apple-converted-space\">  </span>You might not want the automatic type promotion that makes <span class=\"s1\">5==\"5\"</span> evaluate as <span class=\"s1\">T</span>, or the vectorized comparison that makes <span class=\"s1\">1:5==4</span> evaluate as something other than simply <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>You might really want to ask: are two values <i>identical?</i><span class=\"Apple-converted-space\">  </span>For such purposes, the <span class=\"s1\">identical()</span> function is a better choice.</p>\n<p class=\"p1\"><i>2.3.4<span class=\"Apple-converted-space\">  </span>ITEM: 6. String concatenation: operator </i><span class=\"s1\"><i>+</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">+</span> operator is often used as an arithmetic operator, but it can also act as a concatenation operator for string operands. Concatenation is pasting together; the <span class=\"s1\">+</span> operator simply pastes its string operands together, end to end.</p>\n<p class=\"p2\">In fact, this works with non-<span class=\"s1\">string</span> operands too, as long as a <span class=\"s1\">string</span> operand is nearby; the interpretation of <span class=\"s1\">+</span> as a concatenation operator is preferred by Eidos, and wins out over its arithmetic interpretation, as long as a <span class=\"s1\">string</span> operand is present to suggest doing so. The other non-<span class=\"s1\">string</span> operands will be coerced to <span class=\"s1\">string</span>.<span class=\"Apple-converted-space\">  </span>However, this does not work retroactively; if Eidos has already done arithmetic addition on some operands, it will not go back and perform concatenation instead.<span class=\"Apple-converted-space\">  </span>To force concatenation in such situations, you can simply begin the expression with an empty string, <span class=\"s1\">\"\"</span>.</p>\n<p class=\"p2\">The concatenation operator also works with vectors, as usual.</p>\n<p class=\"p3\"><span class=\"s3\">Beginning with Eidos 2.2, string concatenation involving </span><span class=\"s4\">NULL</span><span class=\"s3\"> concatenates the </span><span class=\"s4\">string</span><span class=\"s3\"> value </span><span class=\"s4\">\"NULL\"</span><span class=\"s3\">, just as if </span><span class=\"s4\">NULL</span><span class=\"s3\"> were a singleton </span><span class=\"s4\">string</span><span class=\"s3\"> vector containing that value.</span></p>\n<p class=\"p1\"><i>2.4.1<span class=\"Apple-converted-space\">  </span>ITEM: 7. Assignment: operator </i><span class=\"s1\"><i>=</i></span></p>\n<p class=\"p2\">The results of expressions can be saved in variables.<span class=\"Apple-converted-space\">  </span>As in many languages, this is done with the <span class=\"s1\">=</span> operator, often called the assignment operator.</p>\n<p class=\"p2\">The assignment operator, <span class=\"s1\">=</span>, is different from the equality comparison operator, <span class=\"s1\">==</span>.<span class=\"Apple-converted-space\">  </span>In many languages, confusing the two can cause bugs that are hard to find; in C, for example, it is legal to write:</p>\n<p class=\"p4\">if (x=y) ...</p>\n<p class=\"p2\">In C, this would assign the value of <span class=\"s1\">y</span> to <span class=\"s1\">x</span>, and then the expression <span class=\"s1\">x=y</span> would evaluate to the value that was assigned, and that value would be tested by the <span class=\"s1\">if</span> statement.<span class=\"Apple-converted-space\">  </span>This can be useful as a way of writing extremely compact code; but it is also a very common source of bugs, especially for inexperienced programmers.<span class=\"Apple-converted-space\">  </span>In Eidos using assignment in this way is simply illegal; assignment is allowed only in the context of a statement like <span class=\"s1\">x=y;</span> to prevent these issues.<span class=\"Apple-converted-space\">  </span>(This point is mostly of interest to experienced programmers, so if it is unclear, don’t worry.)</p>\n<p class=\"p2\">Variable names are fairly unrestricted.<span class=\"Apple-converted-space\">  </span>They may begin with a letter (uppercase or lowercase) or an underscore, and subsequently may contain all of those characters, and numerical digits as well.<span class=\"Apple-converted-space\">  </span>So <span class=\"s1\">x_23</span>, <span class=\"s1\">fooBar</span>, and <span class=\"s1\">MyVariable23</span> are all legal variable names (although not good ones – good variable names explain what the variable represents, such as <span class=\"s1\">selection_coeff</span>).<span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">4by4</span> would not be a legal variable name, since it begins with a digit.</p>\n<p class=\"p1\"><i>2.3.5<span class=\"Apple-converted-space\">  </span>ITEM: 8. The ternary conditional: operator </i><span class=\"s1\"><i>? else</i></span></p>\n<p class=\"p2\">Eidos, like many languages, has an <span class=\"s1\">if</span> statement that can be used to specify conditional execution of statements, and an <span class=\"s1\">if-else</span> construct can be used to provide an alternative code path.<span class=\"Apple-converted-space\">  </span>Sometimes, however, one wishes to have conditional execution of an expression, rather than an entire statement.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">if-else</span> construct is particularly inconvenient with assignments involving complex lvalues, such as:</p>\n<p class=\"p4\">if (condition)</p>\n<p class=\"p4\"><span class=\"Apple-tab-span\">\t</span>x[index].property = a;</p>\n<p class=\"p4\">else</p>\n<p class=\"p4\"><span class=\"Apple-tab-span\">\t</span>x[index].property = b;</p>\n<p class=\"p2\">It is desirable to provide a way for the user to specify that the choice of rvalue, <span class=\"s1\">a</span> or <span class=\"s1\">b</span>, should depend upon <span class=\"s1\">condition</span> without having to duplicate the lvalue and the assignment.<span class=\"Apple-converted-space\">  </span>The R language provides this functionality by making <span class=\"s1\">if-else</span> statements result in an rvalue, like an expression.<span class=\"Apple-converted-space\">  </span>The C language, on the other hand, provides a <i>ternary conditional</i> operator, <span class=\"s1\">?:</span><span class=\"s2\">,</span> that can be used in expressions to much the same effect.<span class=\"Apple-converted-space\">  </span>Eidos straddles the gap with a ternary conditional operator, <span class=\"s1\">? else</span>, that uses the <span class=\"s1\">?</span> initiator of C, but the <span class=\"s1\">else</span> token as a continuation as in R.<span class=\"Apple-converted-space\">  </span>In the syntax of Eidos, the above conditional assignment can be rewritten as:</p>\n<p class=\"p4\">x[index].property = condition ? a else b;</p>\n<p class=\"p2\">This will evaluate <span class=\"s1\">condition</span> and result in <span class=\"s1\">a</span> if <span class=\"s1\">condition</span> is <span class=\"s1\">T</span>, or <span class=\"s1\">b</span> if <span class=\"s1\">condition</span> is <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>That result is then assigned into the lvalue.<span class=\"Apple-converted-space\">  </span>Note that, as in C, the precedence of the ternary conditional operator is very low, but higher than operator <span class=\"s1\">=</span>, so that parentheses are often not needed to group statements of this type.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">else</span> clause of the ternary conditional is required; there is no equivalent of an <span class=\"s1\">if</span> statement without an <span class=\"s1\">else</span>, since an rvalue must be produced.</p>\n<p class=\"p2\">Just as with <span class=\"s1\">if-else</span> statements, only the selected subexpression, as determined by the condition, is evaluated; the other subexpression will not be evaluated, so any side effects it might have will not occur.<span class=\"Apple-converted-space\">  </span>For example, with the statement:</p>\n<p class=\"p4\">x = condition ? f1() else f2();</p>\n<p class=\"p5\">here <span class=\"s1\">f1()</span> will be called if <span class=\"s1\">condition</span> is <span class=\"s1\">T</span>, <span class=\"s1\">f2()</span> if <span class=\"s1\">condition</span> is <span class=\"s1\">F</span>; only the subexpression selected by the condition is evaluated, and so it is never the case that both <span class=\"s1\">f1()</span> and <span class=\"s1\">f2()</span> are called.</p>\n<p class=\"p2\">Ternary conditionals may be nested.<span class=\"Apple-converted-space\">  </span>Because the operator is right-associative, an expression such as:</p>\n<p class=\"p4\">z = (a == b ? a else b ? c else d);</p>\n<p class=\"p5\">is grouped as:</p>\n<p class=\"p4\">z = (a == b ? a else (b ? c else d));</p>\n<p class=\"p5\">rather than</p>\n<p class=\"p4\">z = ((a == b ? a else b) ? c else d);</p>\n<p class=\"p2\">This is generally desirable, since it provides a flow similar to chaining of <span class=\"s1\">if-else if-else</span> statements.<span class=\"Apple-converted-space\">  </span>In any case, parentheses may be used to change the order to evaluation as usual.</p>\n<p class=\"p1\"><i>2.3.6<span class=\"Apple-converted-space\">  </span>ITEM: 9. Grouping: operator </i><span class=\"s1\"><i>()</i></span></p>\n<p class=\"p2\">All of the discussion above involved simple expressions that allowed the standard precedence rules of mathematics to determine the order of operations; <span class=\"s1\">1+2*3</span> is evaluated as <span class=\"s1\">1+(2*3)</span> rather than <span class=\"s1\">(1+2)*3</span> because the <span class=\"s1\">*</span> operator is higher precedence than the <span class=\"s1\">+</span> operator.<span class=\"Apple-converted-space\">  </span>For the record, here is the full precedence hierarchy for operators in Eidos, from highest to lowest precedence:</p>\n<p class=\"p6\"><span class=\"s1\">[]</span>, <span class=\"s1\">()</span>, <span class=\"s1\">.</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>subscript, function call, and member access</p>\n<p class=\"p6\"><span class=\"s1\">^</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>exponentiation <i>(right-associative)</i></p>\n<p class=\"p6\"><span class=\"s1\">+</span>, <span class=\"s1\">-</span>, <span class=\"s1\">!</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>unary plus, unary minus, logical (Boolean) negation <i>(right-associative)</i></p>\n<p class=\"p6\"><span class=\"s1\">:</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>sequence construction</p>\n<p class=\"p6\"><span class=\"s1\">*</span>, <span class=\"s1\">/</span>, <span class=\"s1\">%</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>multiplication, division, and modulo</p>\n<p class=\"p6\"><span class=\"s1\">+</span>, <span class=\"s1\">-</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>addition and subtraction</p>\n<p class=\"p6\"><span class=\"s1\">&lt;</span>, <span class=\"s1\">&gt;</span>, <span class=\"s1\">&lt;=</span>, <span class=\"s1\">&gt;=</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>less-than, greater-than, less-than-or-equality, greater-than-or-equality</p>\n<p class=\"p6\"><span class=\"s1\">==</span>, <span class=\"s1\">!=</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>equality and inequality</p>\n<p class=\"p6\"><span class=\"s1\">&amp;</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>logical (Boolean) and</p>\n<p class=\"p6\"><span class=\"s1\">|</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>logical (Boolean) or</p>\n<p class=\"p6\"><span class=\"s1\">=</span><span class=\"s2\"><span class=\"Apple-tab-span\">\t</span></span>assignment</p>\n<p class=\"p2\">Operators at the same precedence level are generally evaluated in the order in which they are encountered.<span class=\"Apple-converted-space\">  </span>Put more technically, Eidos operators are generally left-associative; <span class=\"s1\">3*5%2</span> evaluates as <span class=\"s1\">(3*5)%2</span>, which is <span class=\"s1\">1</span><span class=\"s2\">,</span> not as <span class=\"s1\">3*(5%2)</span>, which is <span class=\"s1\">3</span>.<span class=\"Apple-converted-space\">  </span>The only binary operator in Eidos that is an exception to this rule is the <span class=\"s1\">^</span> operator, which (following standard mathematical convention) is right-associative; <span class=\"s1\">2^3^4</span> is evaluated as <span class=\"s1\">2^(3^4)</span>, not <span class=\"s1\">(2^3)^4</span>.<span class=\"Apple-converted-space\">  </span>The unary <span class=\"s1\">+</span>, unary <span class=\"s1\">-</span>, and <span class=\"s1\">!</span> operators are also technically right-associative; for unary operators this is of little practical import, however (it basically just implies that the unary operators must occur to the left of their operand; you write <span class=\"s1\">-x</span>, not <span class=\"s1\">x-</span>, to express the negation of <span class=\"s1\">x</span>).</p>\n<p class=\"p2\">In any case, parentheses can be used to modify the order of operations, just as in math.<span class=\"Apple-converted-space\">  </span>This works just as you would expect.</p>\n<p class=\"p2\">Note that this use of parentheses is distinct from the <span class=\"s1\">()</span> operator as used in making function calls.</p>\n<p class=\"p3\">Finally, note that Eidos 2.4 and earlier (SLiM 3.4 and earlier) had an operator precedence bug: exponentiation was given a lower precedence than unary minus and its siblings, and so the expression <span class=\"s1\">-2^2</span> would evaluate to <span class=\"s1\">4</span>, as <span class=\"s1\">(-2)^2</span>, rather than <span class=\"s1\">-4</span>, as <span class=\"s1\">-(2^2)</span>.<span class=\"Apple-converted-space\">  </span>This violated standard mathematical precedence rules, and was fixed in Eidos 2.5 (SLiM 3.5).</p>\n<p class=\"p1\"><i>2.7.1<span class=\"Apple-converted-space\">  </span>ITEM: 10. Function calls: operator </i><span class=\"s1\"><i>()</i></span></p>\n<p class=\"p2\">A function is simply a block of code which has been given a name.<span class=\"Apple-converted-space\">  </span>Using that name, you can then cause the execution of that block of code whenever you wish.<span class=\"Apple-converted-space\">  </span>That is the first major purpose of functions: the <i>reuseability</i> of a useful chunk of code.<span class=\"Apple-converted-space\">  </span>A function can be supplied with the particular variables upon which it should act, called the function’s “parameters” or “arguments”; you can execute a function with the sequence <span class=\"s1\">5:15</span> as an argument in one place, and with the string <span class=\"s1\">\"foo\"</span> as an argument in another.<span class=\"Apple-converted-space\">  </span>That is the second major purpose of functions: the <i>generalization</i> of a useful chunk of code to easily act on different inputs.</p>\n<p class=\"p2\">In Eidos, you may define your own functions, or you may execute a <i>lambda</i> (i.e., a snippet of code represented as a <span class=\"s1\">string</span> value) directly in the Eidos interpreter.<span class=\"Apple-converted-space\">  </span>However, a fairly large set of built-in functions are supplied for your use, and the hope is that they will suffice for most purposes.</p>\n<p class=\"p2\">Functions are called using the <span class=\"s1\">()</span> operator.<span class=\"Apple-converted-space\">  </span>Function arguments go between the parentheses of the <span class=\"s1\">()</span> operator, separated by commas.<span class=\"Apple-converted-space\">  </span>Most functions expect an exact number of arguments; many functions, in fact, are even fussier than that, requiring each parameter to be of a particular type, a particular size, or both.<span class=\"Apple-converted-space\">  </span>But some, such as <span class=\"s1\">c()</span>, are more flexible.</p>\n<p class=\"p2\">Many functions provide a return value.<span class=\"Apple-converted-space\">  </span>In other words, a function call like <span class=\"s1\">c(5,6)</span> can evaluate to a particular value, just as an expression like <span class=\"s1\">5+6</span> evaluates to a particular value.<span class=\"Apple-converted-space\">  </span>The result from a function call can be used in an expression or assigned to a variable, as you might expect.</p>\n<p class=\"p1\"><i>2.8.3<span class=\"Apple-converted-space\">  </span>ITEM: 11. Properties: operator </i><span class=\"s1\"><i>.</i></span></p>\n<p class=\"p2\">Objects encapsulate behaviors as well as elements.<span class=\"Apple-converted-space\">  </span>One type of behavior is called a <i>property</i>.<span class=\"Apple-converted-space\">  </span>A property is a simple attribute of each element in an <span class=\"s1\">object</span>.<span class=\"Apple-converted-space\">  </span>Properties can be read using the member-access operator, written as <span class=\"s1\">.</span> (a period).<span class=\"Apple-converted-space\">  </span>The name of a particular property can be used with <span class=\"s1\">.</span> to get that property’s value.<span class=\"Apple-converted-space\">  </span>Operations on <span class=\"s1\">object</span> are vectorized just as they are for all other types in Eidos; the result of the <span class=\"s1\">.</span> operator is a vector containing the value of the property for all of the elements of the <span class=\"s1\">object</span> operand.</p>\n<p class=\"p2\">You can also use the member-access operator to write new values to properties that are not read-only, using the <span class=\"s1\">=</span> operator to do the assignment into the property selected by the <span class=\"s1\">.</span> operator.</p>\n<p class=\"p1\"><i>2.8.6<span class=\"Apple-converted-space\">  </span>ITEM: 12. Method calls: operator </i><span class=\"s1\"><i>()</i></span><i> and operator </i><span class=\"s1\"><i>.</i></span></p>\n<p class=\"p2\">Objects encapsulate behaviors as well as elements.<span class=\"Apple-converted-space\">  </span>In addition to properties, another type of behavior is called a <i>method</i>.<span class=\"Apple-converted-space\">  </span>Methods are very much like functions; they are chunks of code that you can call to perform tasks.<span class=\"Apple-converted-space\">  </span>However, each type of <span class=\"s1\">object</span> has its own particular methods – unlike functions, which are defined globally.<span class=\"Apple-converted-space\">  </span>Methods are more heavyweight than properties; they might involve quite a lot of computation, they might create a completely new <span class=\"s1\">object</span> as their result, and they might even modify the <span class=\"s1\">object</span> upon which they are called.<span class=\"Apple-converted-space\">  </span>Not all methods are heavyweight in this sort of way, however; anything that one might want an <span class=\"s1\">object</span> to do, but that does not feel like a simple property of the <span class=\"s1\">object</span>, can be a method.<span class=\"Apple-converted-space\">  </span>Methods can also take arguments, just like functions, and they can return whole vectors as their result, unlike (read-write) properties, which must refer to singleton values so that multiplexed assignment can work.<span class=\"Apple-converted-space\">  </span>Methods are therefore much more powerful than properties.</p>\n<p class=\"p2\">Methods are called using the member-access operator, <span class=\"s1\">.</span>, with a syntax that looks a lot like accessing a property, but combined with the function call operator, <span class=\"s1\">()</span>.<span class=\"Apple-converted-space\">  </span>That might look like:</p>\n<p class=\"p4\">object.method()</p>\n<p class=\"p2\">Naturally, method calls are also vector operations.<span class=\"Apple-converted-space\">  </span>For a multi-element <span class=\"s1\">object</span>, a single method call will result in the method call being multiplexed out to all of the elements of the <span class=\"s1\">object</span>, and the results from all of those method calls will be concatenated together in the same way that the <span class=\"s1\">c()</span> function performs concatenation (including dropping of <span class=\"s1\">NULL</span>s and type promotion, potentially).</p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/EidosHelpStatements.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"1894.6\">\n  <style type=\"text/css\">\n    p.p1 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima}\n    p.p3 {margin: 2.0px 0.0px 2.0px 27.4px; font: 2.0px 'Times New Roman'; min-height: 2.0px}\n    p.p4 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo; color: #1c0acf}\n    p.p5 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo}\n    p.p6 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo; color: #ff0000}\n    p.p7 {margin: 9.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo; color: #1c0acf}\n    p.p8 {margin: 2.0px 0.0px 2.0px 0.0px; font: 11.0px Optima}\n    p.p9 {margin: 9.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo}\n    p.p10 {margin: 9.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo; color: #007400}\n    p.p11 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo; color: #007400}\n    p.p12 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo; color: #1c00cf}\n    p.p13 {margin: 2.0px 0.0px 2.0px 27.4px; font: 9.0px Menlo; color: #aa0d91}\n    p.p14 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima; min-height: 13.0px}\n    span.s1 {font: 9.0px Menlo}\n    span.s2 {color: #aa0d91}\n    span.s3 {color: #000000}\n    span.s4 {font: 9.0px 'Times New Roman'}\n    span.s5 {font: 11.0px 'Times New Roman'}\n    span.s6 {color: #1c00cf}\n    span.Apple-tab-span {white-space:pre}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><i>2.5.1<span class=\"Apple-converted-space\">  </span>ITEM: 1. </i><span class=\"s1\"><i>if</i></span><i> and </i><span class=\"s1\"><i>if–else</i></span><i> statements</i></p>\n<p class=\"p2\">As in many languages, conditional execution is provided by the <span class=\"s1\">if</span> statement.<span class=\"Apple-converted-space\">  </span>This statement is supplied with a <span class=\"s1\">logical</span> condition; if the condition is <span class=\"s1\">T</span>, the rest of the <span class=\"s1\">if</span> statement is executed, whereas if the condition is <span class=\"s1\">F</span>, the rest of the <span class=\"s1\">if</span> statement is ignored.<span class=\"Apple-converted-space\">  </span>An example:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>if (2^2^2^2^2 &gt; 10000) \"exponentiation is da bomb!\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">\"exponentiation is da bomb!\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">The only twist here, really, is that the condition must evaluate to a single value, i.e. a vector of <span class=\"s1\">size() == 1</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">if</span> statement, in other words, is essentially a scalar operator, not a vector operator.<span class=\"Apple-converted-space\">  </span>If you have a multivalued <span class=\"s1\">logical</span> vector, you can use the <span class=\"s1\">any()</span> or <span class=\"s1\">all()</span> functions to simplify it to a single <span class=\"s1\">logical</span> value.<span class=\"Apple-converted-space\">  </span>Alternatively, the <span class=\"s1\">ifelse()</span> function provides a vector conditional operation, similar to that in R.</p>\n<p class=\"p2\">It is worth exploring this twist with an example.<span class=\"Apple-converted-space\">  </span>Suppose you have a variable <span class=\"s1\">x</span> which ought to be equal to <span class=\"s1\">3</span>, and a variable <span class=\"s1\">y</span> which ought to contain two values, <span class=\"s1\">7</span> and <span class=\"s1\">8</span>.<span class=\"Apple-converted-space\">  </span>You might expect to be able to write:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>if (x == 3 &amp; y == c(7,8)) \"yes!\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p6\">ERROR (EidosInterpreter::Evaluate_If): condition has size() != 1<span class=\"s4\">.</span></p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">The error informs you that the size of condition is not equal to <span class=\"s1\">1</span> (and that that is a problem).<span class=\"Apple-converted-space\">  </span>The expression <span class=\"s1\">y == c(7,8)</span> produces a <span class=\"s1\">logical</span> vector with two values, the result of testing the first and second values respectively.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">&amp;</span><span class=\"s5\"> </span>operator thus produces a two-valued <span class=\"s1\">logical</span> vector as its result, and <span class=\"s1\">if</span> is not happy about that.<span class=\"Apple-converted-space\">  </span>To resolve this, you could use the <span class=\"s1\">all()</span> function, or in many cases more appropriately, the <span class=\"s1\">identical()</span> function.<span class=\"Apple-converted-space\">  </span>See the Eidos manual for further discussion of this issue.</p>\n<p class=\"p2\">It is also worth noting that the condition for <span class=\"s1\">if</span> does not need to be a <span class=\"s1\">logical</span> value; a value of a different type will be converted to <span class=\"s1\">logical</span> by coercion if possible.</p>\n<p class=\"p2\">Often you want to perform an alternative action when the condition of an <span class=\"s1\">if</span> statement is <span class=\"s1\">F</span>; the <span class=\"s1\">if–else</span> statement allows this.<span class=\"Apple-converted-space\">  </span>It is simplest to just show this with an example:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>if (2/2/2/2/2 &gt; 10000) \"division is da bomb!\"; else \"not so much.\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">\"not so much.\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">Super simple, right?</p>\n<p class=\"p1\"><i>2.5.3<span class=\"Apple-converted-space\">  </span>ITEM: 3. semicolons and \"null statements\", </i><span class=\"s1\"><i>;</i></span></p>\n<p class=\"p2\">Every statement in Eidos must end with a semicolon (except compound statements, which end with a closing brace).<span class=\"Apple-converted-space\">  </span>However, when you’re working interactively in EidosScribe, EidosScribe will add a trailing semicolon to your statements if necessary, just to make your life simpler.<span class=\"Apple-converted-space\">  </span>So when you type:</p>\n<p class=\"p7\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>1+1==2</p>\n<p class=\"p8\">what is really being evaluated behind the scenes is:</p>\n<p class=\"p7\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>1+1==2;</p>\n<p class=\"p2\">When you’re not working interactively, semicolons are required, and if you forget, you will get an error, like this:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>1+1==2</p>\n<p class=\"p3\"><br></p>\n<p class=\"p6\">ERROR (Parse): unexpected token 'EOF' in statement; expected ';'</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">EOF stands for End Of File; it’s a standard way of referring to the end of an input buffer, in this case the line of input provided by the user for execution.</p>\n<p class=\"p2\">The simplest and shortest possible statement in Eidos is the \"null statement\", which consists of nothing but a semicolon:</p>\n<p class=\"p9\">;</p>\n<p class=\"p2\">This is not terribly useful, since it does nothing.</p>\n<p class=\"p1\"><i>2.5.4<span class=\"Apple-converted-space\">  </span>ITEM: 4. compound statements with </i><span class=\"s1\"><i>{ }</i></span></p>\n<p class=\"p2\">The other thing you might wonder about, regarding <span class=\"s1\">if</span> statements, is: what if I want to perform more than one action in response to the condition being <span class=\"s1\">T</span> or <span class=\"s1\">F</span>?<span class=\"Apple-converted-space\">  </span>This, then, is an opportune moment to introduce the concept of compound statements.<span class=\"Apple-converted-space\">  </span>A compound statement is a series of statements (zero or more) enclosed by braces.<span class=\"Apple-converted-space\">  </span>An example is worth a thousand words:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>if (1+1==2)</p>\n<p class=\"p4\">{</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>x = 1;</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>x = x + 1;</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>x;</p>\n<p class=\"p4\">}</p>\n<p class=\"p4\">else</p>\n<p class=\"p4\">{</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>\"whoah, I'm confused\";</p>\n<p class=\"p4\">}</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">2</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">Note that the input here is spread across multiple lines for clarity; all of this could be typed on a single line instead.<span class=\"Apple-converted-space\">  </span>If entered as multiple lines, it cannot presently be entered in EidosScribe’s interactive mode because the <span class=\"s1\">if</span> statement would stand on its own and be evaluated as soon as it was completed; instead, the full text would need to be entered in the script area on the left, selected, and executed.<span class=\"Apple-converted-space\">  </span>All of the blue lines are user input, whereas the final line in black, <span class=\"s1\">2</span>, shows the output of the execution of the whole <span class=\"s1\">if–else</span> statement; the <span class=\"s1\">if</span> clause is executed, the calculations involving <span class=\"s1\">x</span> are performed, and the final statement <span class=\"s1\">x;</span> produces a result which is printed to the console as usual.</p>\n<p class=\"p2\">The way that <span class=\"s1\">x;</span> results in output here might seem a bit surprising at first, but it is a consequence of the fact that <i>the value of a compound statement is the value of the last statement executed within the compound statement</i>; the values of the previous statements are discarded.</p>\n<p class=\"p2\">You can use a compound statement in any context in which a single statement would be allowed.<span class=\"Apple-converted-space\">  </span>For example, compound statements are very commonly used with looping constructs.</p>\n<p class=\"p1\"><i>2.6.1<span class=\"Apple-converted-space\">  </span>ITEM: 5. </i><span class=\"s1\"><i>while</i></span><i> statements</i></p>\n<p class=\"p2\">A <span class=\"s1\">while</span> loop repeats a statement as long as a given condition is true.<span class=\"Apple-converted-space\">  </span>The condition is tested before the first time that the statement is executed, so the statement will be executed zero or more times.<span class=\"Apple-converted-space\">  </span>Here is a code snippet to compute the first twenty numbers of the Fibonacci sequence:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>fib = c(1, 1);</p>\n<p class=\"p4\">while (size(fib) &lt; 20)</p>\n<p class=\"p4\">{</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>next_fib = fib[size(fib) - 1] + fib[size(fib) - 2];</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>fib = c(fib, next_fib);</p>\n<p class=\"p4\">}</p>\n<p class=\"p4\">fib;</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">Its use of a <span class=\"s1\">while</span> loop is optimal, because it ensures that if the <span class=\"s1\">fib</span> vector is already long enough to satisfy the length condition <span class=\"s1\">size(fib) &lt; 20</span>, no further values of <span class=\"s1\">fib</span> will be computed.<span class=\"Apple-converted-space\">  </span>You could use this <span class=\"s1\">while</span> loop to lengthen the <span class=\"s1\">fib</span> vector on demand within a larger block of code that used the <span class=\"s1\">fib</span> vector repeatedly.</p>\n<p class=\"p1\"><i>2.6.2<span class=\"Apple-converted-space\">  </span>ITEM: 6. </i><span class=\"s1\"><i>do–while</i></span><i> statements</i></p>\n<p class=\"p2\">A <span class=\"s1\">do–while</span> loop repeats a statement as long as a given condition is true.<span class=\"Apple-converted-space\">  </span>Unlike <span class=\"s1\">while</span> loops, in this case the condition is tested at the end of the loop, and thus the loop statement is always executed at least once.<span class=\"Apple-converted-space\">  </span>Here is a code snippet to compute a factorial:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>counter = 5;</p>\n<p class=\"p4\">factorial = 1;</p>\n<p class=\"p4\">do</p>\n<p class=\"p4\">{</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>factorial = factorial * counter;</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>counter = counter - 1;</p>\n<p class=\"p4\">}</p>\n<p class=\"p4\">while (counter &gt; 0);</p>\n<p class=\"p4\">\"The factorial of 5 is \" + factorial;</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">\"The factorial of 5 is 120\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">Note that this example could be rewritten using a <span class=\"s1\">while</span> loop instead, but it might be a bit less intuitive in its operation since it would no longer embody the formal definition of the factorial as explicitly.<span class=\"Apple-converted-space\">  </span>Note also that computing a factorial could be done much more trivially (and efficiently) using the sequence operator <span class=\"s1\">:</span> and the <span class=\"s1\">product()</span> function, but the code here is useful for the purpose of illustration.</p>\n<p class=\"p1\"><i>2.6.3<span class=\"Apple-converted-space\">  </span>ITEM: 7. </i><span class=\"s1\"><i>for</i></span><i> statements (with </i><span class=\"s1\"><i>in</i></span><i>)</i></p>\n<p class=\"p2\">The <span class=\"s1\">for</span> loop is used to loop through all of the elements in a vector.<span class=\"Apple-converted-space\">  </span>For each value in the given vector, a given variable is set to the value, and a given statement is then executed.<span class=\"Apple-converted-space\">  </span>For example, the following code computes squares by setting <span class=\"s1\">element</span> to each value of <span class=\"s1\">my_sequence</span>, one by one, and then executing the <span class=\"s1\">print()</span> function for each value:</p>\n<p class=\"p3\"><br></p>\n<p class=\"p4\"><span class=\"s2\">&gt;</span><span class=\"s3\"> </span>my_sequence = 1:4;</p>\n<p class=\"p4\">for (element in my_sequence)</p>\n<p class=\"p4\"><span class=\"Apple-converted-space\">   </span>print(\"The square of \" + element + \" is \" + element^2);</p>\n<p class=\"p3\"><br></p>\n<p class=\"p5\">\"The square of 1 is 1\"</p>\n<p class=\"p5\">\"The square of 2 is 4\"</p>\n<p class=\"p5\">\"The square of 3 is 9\"</p>\n<p class=\"p5\">\"The square of 4 is 16\"</p>\n<p class=\"p3\"><br></p>\n<p class=\"p2\">This looping construct is called by various names in other languages, such as the “for each” statement (PHP), the “range-based for” (C++), “fast enumeration” (Objective-C), and so forth.<span class=\"Apple-converted-space\">  </span>It is different from the traditional <span class=\"s1\">for</span> loop of C and related languages, which entails an initializer expression, a condition expression, and an increment/decrement expression.<span class=\"Apple-converted-space\">  </span>That type of <span class=\"s1\">for</span> loop does not exist in Eidos (following R); the iterator <span class=\"s1\">for</span> of R and Eidos is a more natural and efficient choice for vector-based languages.</p>\n<p class=\"p1\"><i>2.6.4<span class=\"Apple-converted-space\">  </span>ITEM: 8. </i><span class=\"s1\"><i>next</i></span><i> statements</i></p>\n<p class=\"p2\">Sometimes you might wish to cut short the execution of a given iteration of a loop, skipping the rest of the work that would normally be done and proceeding directly to the next iteration.<span class=\"Apple-converted-space\">  </span>This is the function of the <span class=\"s1\">next</span> statement.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">next</span> statement can be used within <span class=\"s1\">for</span>, <span class=\"s1\">while</span>, and <span class=\"s1\">do–while</span> loops.</p>\n<p class=\"p1\"><i>2.6.5<span class=\"Apple-converted-space\">  </span>ITEM: 9. </i><span class=\"s1\"><i>break</i></span><i> statements</i></p>\n<p class=\"p2\">Often it is necessary to stop the execution of a loop altogether, not just to cut short the current iteration of the loop as <span class=\"s1\">next</span> does.<span class=\"Apple-converted-space\">  </span>To achieve this – to break out of a loop completely – use the <span class=\"s1\">break</span> statement.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">break</span> statement can be used within <span class=\"s1\">for</span>, <span class=\"s1\">while</span>, and <span class=\"s1\">do–while</span> loops.</p>\n<p class=\"p1\"><i>2.6.6<span class=\"Apple-converted-space\">  </span>ITEM: 10. </i><span class=\"s1\"><i>return</i></span><i> statements</i></p>\n<p class=\"p2\">The <span class=\"s1\">return</span> statement returns a value from a block of code, as in other languages such as C and R.<span class=\"Apple-converted-space\">  </span>In one common case, when defining a user-defined function, <span class=\"s1\">return</span> is used to stop execution of the function and return a given value to the caller.<span class=\"Apple-converted-space\">  </span>Otherwise, a <span class=\"s1\">return</span> is useful mostly when the Context within which you’re using Eidos uses the returned value.<span class=\"Apple-converted-space\">  </span>When using Eidos in SLiM, for example, SLiM uses the value returned by Eidos scripts such as <span class=\"s1\">mutationEffect()</span> callbacks and <span class=\"s1\">mateChoice()</span> callbacks, making <span class=\"s1\">return</span> very useful in that Context.<span class=\"Apple-converted-space\">  </span>Apart from such Context-dependent uses, <span class=\"s1\">return</span> is mainly useful as a way to break out of nested loops regardless of the depth of nesting, as illustrated below.</p>\n<p class=\"p2\">The <span class=\"s1\">return</span> statement is very simple: the keyword <span class=\"s1\">return</span>, and then, optionally, an expression.<span class=\"Apple-converted-space\">  </span>When the <span class=\"s1\">return</span> statement is executed, the expression is evaluated and its value is immediately returned as the value of the largest enclosing statement.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">return</span> statement therefore breaks out of all conditionals, loops, and compound statements, regardless of the depth of nesting.</p>\n<p class=\"p2\">In some circumstances a <span class=\"s1\">return</span> statement is not necessary, because compound statements evaluate to the value of the last statement evaluated within them, and <span class=\"s1\">if</span> statements behave similarly; as in R, therefore, a <span class=\"s1\">return</span> statement can often be omitted.<span class=\"Apple-converted-space\">  </span>However, using <span class=\"s1\">return</span> makes the intentions of the programmer more explicit, and so its use is encouraged.</p>\n<p class=\"p2\">If the expression for the <span class=\"s1\">return</span> statement is omitted, the return value used is <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>In situations where the return value will not be used, such as Eidos events in SLiM, the return value should be omitted to make the intent of the code clear.</p>\n<p class=\"p1\"><i>2.9.1<span class=\"Apple-converted-space\">  </span>ITEM: 11. single-line comments with </i><span class=\"s1\"><i>//</i></span></p>\n<p class=\"p2\">Technically, comments are actually a type of whitespace; comments in Eidos code are completely ignored and have no effect whatsoever on the results of the execution of code, just like other kinds of whitespace in most respects.<span class=\"Apple-converted-space\">  </span>Single-line comments begin with <span class=\"s1\">//</span> and then may consist of any text whatsoever, up to the end of the current line of code.<span class=\"Apple-converted-space\">  </span>A comment may occur by itself on a line, or it may follow other Eidos code.<span class=\"Apple-converted-space\">  </span>So for example, you could write:</p>\n<p class=\"p10\"><span class=\"s6\">1</span><span class=\"s3\"> + </span><span class=\"s6\">1</span><span class=\"s3\"> == </span><span class=\"s6\">2</span><span class=\"s3\">;<span class=\"Apple-converted-space\">    </span></span>// this is true</p>\n<p class=\"p2\">Comments are never required in Eidos, but using them to annotate your code is nevertheless a very good idea, both so that you remember what your intentions were when you come back to the code weeks or months later, and so that others who might need to understand or maintain your code have a helping hand.</p>\n<p class=\"p1\"><i>2.9.2<span class=\"Apple-converted-space\">  </span>ITEM: 12. block comments with </i><span class=\"s1\"><i>/* */</i></span></p>\n<p class=\"p2\">It is possible to comment out whole blocks of script, instead of just single lines.<span class=\"Apple-converted-space\">  </span>This can be useful for writing longer comments that describe a section of code in more detail.<span class=\"Apple-converted-space\">  </span>In Eidos (as in C and C++), such block comments can be written with a beginning <span class=\"s1\">/*</span> and a terminating <span class=\"s1\">*/</span>.<span class=\"Apple-converted-space\">  </span>Here’s an example of this style of comment:</p>\n<p class=\"p11\">/*</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>This computes the factorial x!, which is</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>the product of all values from 1 to x, for</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>any positive integer x.</p>\n<p class=\"p11\">*/</p>\n<p class=\"p5\">x_factorial = product(<span class=\"s6\">1</span>:x);</p>\n<p class=\"p2\">A nice feature of Eidos is that block comments nest properly, making it possible to use them to comment out stretches of code that already contain block comments.<span class=\"Apple-converted-space\">  </span>For example, if the code above was no longer needed, but you didn’t want to delete it entirely because you might need it again later, you could use a block comment to disable it:</p>\n<p class=\"p11\">/*<span class=\"Apple-tab-span\">\t</span>******* NOT NEEDED ************</p>\n<p class=\"p11\">/*</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>This computes the factorial x!, which is</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>the product of all values from 1 to x, for</p>\n<p class=\"p11\"><span class=\"Apple-converted-space\">   </span>any positive integer x.</p>\n<p class=\"p11\">*/</p>\n<p class=\"p11\">x_factorial = product(1:x);</p>\n<p class=\"p11\">*/</p>\n<p class=\"p2\">The outer block comment is not terminated by the first <span class=\"s1\">*/</span> because Eidos recognizes that that belongs to the inner block comment; the outer block comment continues until the second <span class=\"s1\">*/</span> is encountered.</p>\n<p class=\"p1\"><i>4.1<span class=\"Apple-converted-space\">  </span>ITEM: 13. user-defined functions</i></p>\n<p class=\"p2\">Suppose we wish to define a function that doubles whatever <span class=\"s1\">float</span> value is passed to it.<span class=\"Apple-converted-space\">  </span>This is very easy to do:</p>\n<p class=\"p5\"><span class=\"s2\">function</span> (float)double(float x)</p>\n<p class=\"p5\">{</p>\n<p class=\"p5\"><span class=\"Apple-tab-span\">\t</span><span class=\"s2\">return</span> <span class=\"s6\">2</span> * x;</p>\n<p class=\"p5\">}</p>\n<p class=\"p2\">The <span class=\"s1\">function</span> keyword initiates the declaration of a new function.<span class=\"Apple-converted-space\">  </span>It is followed by the full signature for the new function; here the signature declares that the function is named <span class=\"s1\">double</span>, takes a parameter named <span class=\"s1\">x</span> that is of type <span class=\"s1\">float</span>, and returns type <span class=\"s1\">float</span>.<span class=\"Apple-converted-space\">  </span>This signature is then followed by the definition of the new function, in the form of a compound statement; here, the <span class=\"s1\">double()</span> function is defined as returning two times the value it was passed.<span class=\"Apple-converted-space\">  </span>Note that a <span class=\"s1\">return</span> statement is used here to return a specified value from the function; if no <span class=\"s1\">return</span> statement is encountered, the value of the last statement evaluated is automatically returned to the caller (as in R), but generally it is clearer to explicitly use <span class=\"s1\">return</span><span class=\"s5\">.</span></p>\n<p class=\"p2\">Calling such functions works in exactly the same way as calling built-in functions:</p>\n<p class=\"p12\"><span class=\"s2\">&gt;</span> double(5.35)</p>\n<p class=\"p5\">10.7</p>\n<p class=\"p2\">Functions may be recursive; a simple <span class=\"s1\">factorial()</span> function might be defined recursively as:</p>\n<p class=\"p5\"><span class=\"s2\">function</span> (integer)factorial(integer x)</p>\n<p class=\"p5\">{</p>\n<p class=\"p5\"><span class=\"Apple-tab-span\">\t</span><span class=\"s2\">if</span> (x &lt;= <span class=\"s6\">1</span>)</p>\n<p class=\"p13\"><span class=\"s3\"><span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span></span>return<span class=\"s3\"> </span><span class=\"s6\">1</span><span class=\"s3\">;</span></p>\n<p class=\"p13\"><span class=\"s3\"><span class=\"Apple-tab-span\">\t</span></span>else</p>\n<p class=\"p5\"><span class=\"s4\"><span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span></span><span class=\"s2\">return</span> x * factorial(x - <span class=\"s6\">1</span>);</p>\n<p class=\"p5\">}</p>\n<p class=\"p2\">This works well enough, as you can see:</p>\n<p class=\"p12\"><span class=\"s2\">&gt;</span> factorial(13)</p>\n<p class=\"p5\">6227020800</p>\n<p class=\"p2\">As with the built-in Eidos functions, user-defined functions may take multiple parameters, each of which may be allowed to be one of several different possible types.<span class=\"Apple-converted-space\">  </span>Parameters to user-defined functions may also be optional, with a default value if left unsupplied.<span class=\"Apple-converted-space\">  </span>Finally, functions are <i>scoped</i>; the code inside them executes in a private namespace in which only the parameters to the function are available, and variables defined inside a function will not persist beyond the end of the function’s execution.</p>\n<p class=\"p14\"><br></p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/EidosHelpTypes.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"1894.6\">\n  <style type=\"text/css\">\n    p.p1 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima}\n    p.p3 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima; color: #000000}\n    span.s1 {font: 9.0px Menlo}\n    span.s2 {font: 11.0px 'Times New Roman'}\n    span.s3 {font: 11.0px 'Lucida Grande'}\n    span.s4 {font: 8.0px Optima}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><i>2.1.1<span class=\"Apple-converted-space\">  </span>ITEM: 1. type </i><span class=\"s1\"><i>integer</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">integer</span> type is used in Eidos to represent integers – whole numbers, with no fractional component.<span class=\"Apple-converted-space\">  </span>Unlike in many languages, exponential notation may be used to specify <span class=\"s1\">integer</span> literals (“literals” means values stated literally in the script, rather than derived through calculations).</p>\n<p class=\"p2\">The <span class=\"s1\">integer</span> type is advantageous primarily because it is exact; it does not suffer from any sort of roundoff error. Exact comparison with integer constants is therefore safe; roundoff error will not lead to problems caused by <span class=\"s1\">0.999999999</span> being deemed to be unequal to <span class=\"s1\">1</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">integer</span> is disadvantageous because it can only represent a limited range of values, and beyond that range, results will be unpredictable.<span class=\"Apple-converted-space\">  </span>Eidos uses 64 bits to store <span class=\"s1\">integer</span> values, so that range is quite wide; to <span class=\"s1\">−9223372036854775806</span> to <span class=\"s1\">9223372036854775807</span>, to be exact.<span class=\"Apple-converted-space\">  </span>That is broad, but it is still enormously narrower than the range of numbers representable with <span class=\"s1\">float</span><span class=\"s2\">.</span></p>\n<p class=\"p1\"><i>2.1.2<span class=\"Apple-converted-space\">  </span>ITEM: 2. type </i><span class=\"s1\"><i>float</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">float</span> type is used in Eidos to represent all non-<span class=\"s1\">integer</span> numbers – fractions and real numbers.<span class=\"Apple-converted-space\">  </span>Exponential notation may be used to specify <span class=\"s1\">float</span> literals; in particular; literals with a decimal point or a negative exponent are taken to be of type <span class=\"s1\">float</span>.</p>\n<p class=\"p2\">Note that this rule means that some literals are represented using <span class=\"s1\">float</span> even though they could also be represented using <span class=\"s1\">integer</span><span class=\"s2\">.</span></p>\n<p class=\"p2\">The <span class=\"s1\">float</span> type is advantageous primarily because it can represent an enormously wide range of values.<span class=\"Apple-converted-space\">  </span>Eidos uses C++’s <span class=\"s1\">double</span> type to represent its <span class=\"s1\">float</span> values; the range of values allowed will depend upon your computer’s settings, but it will be vast.<span class=\"Apple-converted-space\">  </span>If that range is exceeded, or if numerical problems occur, type <span class=\"s1\">float</span> can also represent values as infinity or as “Not A Number” (<span class=\"s1\">INF</span> and <span class=\"s1\">NAN</span>, respectively, in Eidos).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">float</span> type is thus more robust for operations that might produce such values.<span class=\"Apple-converted-space\">  </span>The disadvantage of <span class=\"s1\">float</span> is that it is inexact; some values cannot be represented exactly (just as 1/3 in base 10 cannot be represented exactly, and must be written as 0.3333333...).<span class=\"Apple-converted-space\">  </span>Roundoff can thus cause comparison errors, overflow and underflow errors, and the accumulation of numerical error.</p>\n<p class=\"p2\">Several <span class=\"s1\">float</span> constants are defined in Eidos; besides <span class=\"s1\">INF</span> and <span class=\"s1\">NAN</span>, <span class=\"s1\">PI</span> is defined as <span class=\"s3\">π</span> (3.14159...), and <span class=\"s1\">E</span> is defined as <span class=\"s2\"><i>e</i></span> (2.71828...).</p>\n<p class=\"p1\"><i>2.1.3<span class=\"Apple-converted-space\">  </span>ITEM: 3. type </i><span class=\"s1\"><i>logical</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">logical</span> type represents true and false values, such as those from comparisons.<span class=\"Apple-converted-space\">  </span>In many languages this type is called something like <span class=\"s1\">boolean</span> or <span class=\"s1\">BOOL</span>; Eidos follows R in using the name <span class=\"s1\">logical</span> instead.</p>\n<p class=\"p2\">There are no <span class=\"s1\">logical</span> literals in Eidos.<span class=\"Apple-converted-space\">  </span>However, there are defined constants that behave in essentially the same way as literals.<span class=\"Apple-converted-space\">  </span>In particular, <span class=\"s1\">T</span> is defined as true, and <span class=\"s1\">F</span> is defined as false.<span class=\"Apple-converted-space\">  </span>These are the only two values that the <span class=\"s1\">logical</span> type can take.<span class=\"Apple-converted-space\">  </span>As in a great many other languages, these <span class=\"s1\">logical</span> values have equivalent numerical values; <span class=\"s1\">F</span> is <span class=\"s1\">0</span>, and <span class=\"s1\">T</span> is <span class=\"s1\">1</span> (and in fact any non-zero value is considered to be true if converted to <span class=\"s1\">logical</span> type).<span class=\"Apple-converted-space\">  </span>Values of type <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> may therefore be converted to <span class=\"s1\">logical</span>, and vice-versa.</p>\n<p class=\"p1\"><i>2.1.4<span class=\"Apple-converted-space\">  </span>ITEM: 4. type </i><span class=\"s1\"><i>string</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">string</span> type represents a string of characters – a word, a sentence, a paragraph, the complete works of Shakespeare.<span class=\"Apple-converted-space\">  </span>There is no formatting on a <span class=\"s1\">string</span> – no <span class=\"s2\">font</span>, no <span class=\"s4\">point size</span>, no <b>bold</b> or <i>italic</i>.<span class=\"Apple-converted-space\">  </span>Instead, it is just a character stream.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">string</span> literal must be enclosed by either single or double quotation marks, <span class=\"s1\">'</span> or <span class=\"s1\">\"</span>.<span class=\"Apple-converted-space\">  </span>This choice simplifies writing Eidos strings that themselves contain quote characters, because you can delimit the string with the opposite kind of quote.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s1\">'You say, \"Ere thrice the sun done salutation to the dawn\"'</span> is a string that contains double quotes, whereas <span class=\"s1\">\"Quoth the Raven, 'nevermore'.”</span> is a string that contains single quotes.<span class=\"Apple-converted-space\">  </span>Apart from this consideration, it does not matter whether you use single or double quotes; the internal representation is the same.<span class=\"Apple-converted-space\">  </span>The suggested convention is to prefer double quotes, all else being equal, since they are more universally used in other programming languages.</p>\n<p class=\"p2\">A complication arises if one wishes to include both single and double quotation marks within a <span class=\"s1\">string</span>; whichever delimiter you choose, one or the other quote character will terminate the <span class=\"s1\">string</span> literal.<span class=\"Apple-converted-space\">  </span>In this case, the quotation mark must be “escaped” by preceding it with a backslash, <span class=\"s1\">\\</span>.<span class=\"Apple-converted-space\">  </span>The backslash can be used to “escape” various other characters; to include a newline in a string, for example, use <span class=\"s1\">\\n</span>, and to include a tab, use <span class=\"s1\">\\t</span>.<span class=\"Apple-converted-space\">  </span>Since the backslash has this special meaning, backslashes themselves must be escaped as <span class=\"s1\">\\\\</span>.<span class=\"Apple-converted-space\">  </span>An alternative to dealing with escape sequences is to use the “here document” style of string literal; see the Eidos manual for details on this.</p>\n<p class=\"p1\"><i>2.7.2<span class=\"Apple-converted-space\">  </span>ITEM: 5. type </i><span class=\"s1\"><i>NULL</i></span></p>\n<p class=\"p2\">The <span class=\"s1\">NULL</span> type two primary uses: as a return value, and as a parameter.</p>\n<p class=\"p2\">As a return value, <span class=\"s1\">NULL</span> is used to indicate that a function had nothing useful to return.<span class=\"Apple-converted-space\">  </span>Some functions always return <span class=\"s1\">NULL</span>, such as <span class=\"s1\">print()</span>; <span class=\"s1\">print()</span> sends its output directly to the Eidos console.<span class=\"Apple-converted-space\">  </span>It has nothing useful to return, so it returns <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>(That <span class=\"s1\">NULL</span> value does not normally get printed out by Eidos because it is marked as an “invisible” return, a side topic not really worth getting into here; invisible returns work much as they do in R).</p>\n<p class=\"p2\">Some functions will return a useful value if they can, but will return <span class=\"s1\">NULL</span> if they can’t. Often a <span class=\"s1\">NULL</span> return is a result of passing <span class=\"s1\">NULL</span> in as an argument; garbage in, garbage out, as they say.<span class=\"Apple-converted-space\">  </span>For example, the <span class=\"s1\">readFile()</span> function will return <span class=\"s1\">NULL</span> if an error occurs that prevents the file read operation from completing.<span class=\"Apple-converted-space\">  </span>The calling code could then detect that <span class=\"s1\">NULL</span> return and act accordingly – it might try to read from a different path, print an error, or terminate execution with <span class=\"s1\">stop()</span>, or it might just ignore the problem, if reading the file was optional anyway (such as an optional configuration file to modify the default behavior of a script).</p>\n<p class=\"p2\">The other use of <span class=\"s1\">NULL</span>, as mentioned above, is as an argument to a function. Passing <span class=\"s1\">NULL</span> is occasionally a way of signaling that you don’t want to supply a value for an argument, or that you want a default behavior from the function rather than telling it more specifically what to do.</p>\n<p class=\"p2\"><span class=\"s1\">NULL</span> cannot be an element of a vector of some other type; it cannot be used to mark missing or unknown values, for example.<span class=\"Apple-converted-space\">  </span>Instead, <span class=\"s1\">NULL</span> is its own type of vector in Eidos, always of zero length.<span class=\"Apple-converted-space\">  </span>(There is also no <span class=\"s1\">NA</span> value in Eidos like the one in R, while we’re on the topic of marking missing values.<span class=\"Apple-converted-space\">  </span>Not having to worry about missing values makes Eidos substantially simpler and faster, and Eidos – unlike R – is not designed to be used for doing statistical analysis, so marking missing values is not expected to be important.<span class=\"Apple-converted-space\">  </span>Eidos does support <span class=\"s1\">NAN</span> – Not A Number – values in <span class=\"s1\">float</span> vectors, however, which could conceivably be used to mark missing values if necessary.)</p>\n<p class=\"p2\">The basic philosophy of how Eidos handles <span class=\"s1\">NULL</span> values in expressions and computations is that <span class=\"s1\">NULL</span> in such situations represents a non-fatal error or an unknown value.<span class=\"Apple-converted-space\">  </span>If using the <span class=\"s1\">NULL</span> value in some meaningful way could lead to potentially misleading or incorrect results, Eidos will generate a fatal error.<span class=\"Apple-converted-space\">  </span>The idea is to give Eidos code an opportunity to detect a <span class=\"s1\">NULL</span>, and thus to catch and handle the non-fatal error; but if the code does not handle the <span class=\"s1\">NULL</span>, using the <span class=\"s1\">NULL</span> in further operations will result in a fatal error before the functioning of the code is seriously compromised.<span class=\"Apple-converted-space\">  </span><span class=\"s1\">NULL</span> values are thus a sort of third rail; there’s a good reason they exist, but you have to be very careful around them.<span class=\"Apple-converted-space\">  </span>They are a bit like zero-valued pointers in C (<span class=\"s1\">NULL</span>), C++ (<span class=\"s1\">nullptr</span>), Objective-C (<span class=\"s1\">nil</span>), and similar languages; they are widely used, but if you ever use one the wrong way it is an immediate and fatal error.<span class=\"Apple-converted-space\">  </span>For further details, please consult the Eidos manual.</p>\n<p class=\"p1\"><i>2.8.1<span class=\"Apple-converted-space\">  </span>ITEM: 6. type </i><span class=\"s1\"><i>object</i></span></p>\n<p class=\"p3\">In addition to <span class=\"s1\">logical</span>, <span class=\"s1\">integer</span>, <span class=\"s1\">float</span>, <span class=\"s1\">string</span>, and <span class=\"s1\">NULL</span>, there is one more type in Eidos left to discuss: <span class=\"s1\">object</span>.<span class=\"Apple-converted-space\">  </span>A variable of type <span class=\"s1\">object</span> is a vector that contains elements; it is a container, a bag of stuff.<span class=\"Apple-converted-space\">  </span>In this way, it is similar to Eidos’s other types; a <span class=\"s1\">float</span> vector in Eidos contains floating-point elements, whereas an <span class=\"s1\">object</span> vector contains <span class=\"s1\">object</span>-elements (often just called “objects”; whether one is referring to a single <span class=\"s1\">object</span>-element or a vector of type <span class=\"s1\">object</span> is generally clear from context).<span class=\"Apple-converted-space\">  </span>An <span class=\"s1\">object</span> vector can also embody <i>behavior</i>: it has operations that it can perform using the elements it contains, which all belong to a <i>class</i> that defines the available behaviors.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">object</span> type in Eidos is thus similar to objects in other languages such as Java, C++, or R – except much more limited.<span class=\"Apple-converted-space\">  </span>In Eidos you cannot define your own <span class=\"s1\">object</span> classes; you work only with the predefined <span class=\"s1\">object</span> classes supplied by SLiM or whatever other Context you might be using Eidos within.<span class=\"Apple-converted-space\">  </span>These predefined <span class=\"s1\">object</span> classes generally define Context-dependent <span class=\"s1\">object</span>-elements related to the task performed by the Context; in SLiM, the classes are things such as mutations, genomic elements, and mutation types (described in SLiM’s documentation).<span class=\"Apple-converted-space\">  </span>Eidos itself also supplies a few built-in <span class=\"s1\">object</span> classes, notably <span class=\"s1\">Dictionary</span> and <span class=\"s1\">Image</span>.</p>\n<p class=\"p3\">The behaviors of objects in Eidos manifest in two ways: objects can have <i>properties</i> (also called instance variables or member variables, in other languages) that can be read from and written to, and they can have <i>methods</i> (also called member functions, in other languages).<span class=\"Apple-converted-space\">  </span>The behavior of an <span class=\"s1\">object</span> vector in Eidos is determined by the class of element the <span class=\"s1\">object</span> contains; an Eidos <span class=\"s1\">object</span> will always contain only one class of element (just as a <span class=\"s1\">float</span> cannot contain <span class=\"s1\">string</span>-elements, for example).</p>\n<p class=\"p3\">Instances of particular <span class=\"s1\">object</span> classes – particular kinds of objects – are obtained via built-in functions and/or global constants and variables.<span class=\"Apple-converted-space\">  </span>For example, in SLiM there is a global constant called <span class=\"s1\">sim</span> that represents the simulated species as an instance of the <span class=\"s1\">Species</span> class.</p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/SLiMHelpCallbacks.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"2299.77\">\n  <style type=\"text/css\">\n    p.p1 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima; color: #000000}\n    p.p3 {margin: 9.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo; color: #000000}\n    p.p4 {margin: 0.0px 0.0px 3.0px 94.5px; text-indent: -67.2px; font: 11.0px Optima; color: #000000}\n    p.p5 {margin: 0.0px 0.0px 9.0px 94.5px; text-indent: -67.2px; font: 11.0px Optima; color: #000000}\n    p.p6 {margin: 9.0px 0.0px 9.0px 27.4px; font: 11.0px Optima; color: #000000}\n    p.p7 {margin: 2.0px 0.0px 2.0px 0.0px; font: 11.0px Optima; color: #000000}\n    p.p8 {margin: 0.0px 0.0px 0.0px 94.3px; text-indent: -67.0px; font: 11.0px Optima; color: #000000}\n    p.p9 {margin: 0.0px 0.0px 0.0px 103.7px; text-indent: -76.3px; font: 11.0px Optima; color: #000000}\n    p.p10 {margin: 0.0px 0.0px 9.0px 103.5px; text-indent: -76.2px; font: 11.0px Optima; color: #000000}\n    p.p11 {margin: 0.0px 0.0px 0.0px 54.0px; text-indent: -26.6px; font: 11.0px Optima; color: #000000}\n    p.p12 {margin: 0.0px 0.0px 9.0px 54.0px; text-indent: -26.6px; font: 11.0px Optima; color: #000000}\n    p.p13 {margin: 0.0px 0.0px 9.0px 103.7px; text-indent: -76.3px; font: 11.0px Optima; color: #000000}\n    p.p14 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px Optima; color: #000000; min-height: 13.0px}\n    span.s1 {font: 9.0px Menlo}\n    span.s2 {color: #1c00cf}\n    span.s3 {color: #3f6e74}\n    span.s4 {color: #1400c4}\n    span.s5 {color: #b50013}\n    span.s6 {font: 11.0px Optima}\n    span.s7 {font: 7.3px Optima}\n    span.s8 {font-kerning: none}\n    span.Apple-tab-span {white-space:pre}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><i>5.13.0<span class=\"Apple-converted-space\">  </span>ITEM: 1. </i><span class=\"s1\"><i>initialize()</i></span><i> callbacks</i></p>\n<p class=\"p2\">Before a SLiM simulation can be run, the various classes underlying the simulation need to be set up with an initial configuration.<span class=\"Apple-converted-space\">  </span>Simulation configuration in SLiM is done in <span class=\"s1\"><i>initialize()</i></span><i> callbacks</i> that run prior to the beginning of simulation execution.<span class=\"Apple-converted-space\">  </span>For our present purposes, the idea is very simple; in your input file, you can write something like this:</p>\n<p class=\"p3\">initialize()<br>\n{<br>\n<span class=\"Apple-tab-span\">\t</span>...<br>\n}</p>\n<p class=\"p2\">The <span class=\"s1\">initialize()</span> declaration specifies that the script block is to be executed as an <span class=\"s1\">initialize()</span> callback before the simulation starts.<span class=\"Apple-converted-space\">  </span>The script between the braces <span class=\"s1\">{}</span> would set up various aspects of the simulation by calling <i>initialization functions</i>.<span class=\"Apple-converted-space\">  </span>These are SLiM functions that may be called only in an <span class=\"s1\">initialize()</span> callback, and their names begin with <span class=\"s1\">initialize</span> to mark them clearly as such.<span class=\"Apple-converted-space\">  </span>You may also use other Eidos functionality in these callbacks; for example, you might automate generating a complex genetic structure containing many genes by using a <span class=\"s1\">for</span> loop.</p>\n<p class=\"p2\">In general, it is required for a species to set up its genetic structure in an <span class=\"s1\">initialize()</span> callback with calls to <span class=\"s1\">initializeMutationRate()</span>, <span class=\"s1\">initializeRecombinationRate()</span>, <span class=\"s1\">initializeMutationType()</span>, <span class=\"s1\">initializeGenomicElementType()</span>, and <span class=\"s1\">initializeGenomicElement()</span>; species must call all of these, setting up at least one mutation type, at least one genomic element type, and at least one genomic element.<span class=\"Apple-converted-space\">  </span>The exception to this general rule is for species that have no genetics at all – species that are modeled purely on an ecological/behavioral level.<span class=\"Apple-converted-space\">  </span>Such species may be defined by calling <i>none</i> of those initialization functions; in this case, SLiM will default to a zero-length chromosome with mutation and recombination rates of zero.<span class=\"Apple-converted-space\">  </span>A middle ground between these two configuration paths is not allowed; either a species has no genetics, or it fully defines its genetics.</p>\n<p class=\"p2\">One thing worth mentioning is that in the context of an <span class=\"s1\">initialize()</span> callback, the <span class=\"s1\">sim</span> global representing the species being simulated is not defined.<span class=\"Apple-converted-space\">  </span>This is because the state of the simulation is not yet constructed fully, and accessing partially constructed state would not be safe.<span class=\"Apple-converted-space\">  </span>(Similarly, in multispecies models, the <span class=\"s1\">community</span> object and the objects representing individual species are not yet defined.)</p>\n<p class=\"p2\">The above <span class=\"s1\">initialize()</span> callback syntax <i>implicitly</i> declares a single species, with the default name of <span class=\"s1\">sim</span>, and therefore sets up a single-species model.<span class=\"Apple-converted-space\">  </span>It is also possible to <i>explicitly</i> declare a species, which is done with this extended syntax (using a species name of <span class=\"s1\">fox</span> as an example):</p>\n<p class=\"p3\">species fox initialize() { ... }</p>\n<p class=\"p2\">This sets up a multispecies model (although it might, in fact, declare only a single species, <span class=\"s1\">fox</span>; the term “multispecies”, in SLiM parlance, really means “explicitly declared species”, but multispecies models almost always <i>do</i> contain multiple species, so the distinction is unimportant).<span class=\"Apple-converted-space\">  </span>In most respects multispecies models work identically to single-species models, so we will tend to focus on the single-species case in the reference documentation, with a species name of <span class=\"s1\">sim</span>, for simplicity and clarity.</p>\n<p class=\"p2\">In single-species models all initialization can be done in a single <span class=\"s1\">initialize()</span> callback (or you can have more than one, if you wish).<span class=\"Apple-converted-space\">  </span>In multispecies models, each species must be initialized with its own callback(s), as shown above.<span class=\"Apple-converted-space\">  </span>In addition, multispecies models also support an optional community-level initialization callback that is declared as follows:</p>\n<p class=\"p3\">species all initialize() { ... }</p>\n<p class=\"p2\">These callbacks, technically called <i>non-species-specific </i><span class=\"s1\"><i>initialize()</i></span><i> callbacks</i>, provide a place for community-level initialization to occur.<span class=\"Apple-converted-space\">  </span>They are run before any species-specific <span class=\"s1\">initialize()</span> callbacks are run, so you might wish to set up all of your model parameters in one, providing a single location for all parameters.<span class=\"Apple-converted-space\">  </span>In multispecies models, the <span class=\"s1\">initializeModelType()</span> and <span class=\"s1\">initializeInteractionType()</span> functions may only be called from a non-species-specific <span class=\"s1\">initialize()</span> callback, since those aspects of model configuration span the entire community.<span class=\"Apple-converted-space\">  </span>In single-species models, these functions may be called from an ordinary <span class=\"s1\">initialize()</span> callback for simplicity and backward compatibility.</p>\n<p class=\"p2\">Once all <span class=\"s1\">initialize()</span> callbacks have executed, in the order in which they are specified in the SLiM input file, the simulation will begin.<span class=\"Apple-converted-space\">  </span>The tick number at which it starts is determined by the Eidos events you have defined; the first tick in which an Eidos event is scheduled to execute is the tick at which the simulation starts.<span class=\"Apple-converted-space\">  </span>Similarly, the simulation will terminate after the last tick for which a script block (either an event or a callback) is registered to execute, unless the <span class=\"s1\">stop()</span> function or the <span class=\"s1\">simulationFinished()</span> method of <span class=\"s1\">Community</span> or <span class=\"s1\">Species</span> are called to end the simulation earlier.</p>\n<p class=\"p1\"><i>5.13.1<span class=\"Apple-converted-space\">  </span>ITEM: 2. Eidos events</i></p>\n<p class=\"p2\">An Eidos event is a block of Eidos code that is executed every tick, within a tick range, to perform a desired task.<span class=\"Apple-converted-space\">  </span>The syntax of an Eidos event declaration looks like one of these:</p>\n<p class=\"p3\">[id] [t1 [: t2]] first() { ... }<br>\n[id] [t1 [: t2]] early() { ... }<br>\n[id] [t1 [: t2]] late() { ... }</p>\n<p class=\"p2\">The first declaration declares a <span class=\"s1\">first()</span> event that executes first thing in the tick cycle.<span class=\"Apple-converted-space\">  </span>The second declaration declares an <span class=\"s1\">early()</span> event that executes relatively early in the tick cycle.<span class=\"Apple-converted-space\">  </span>The third declaration declares a <span class=\"s1\">late()</span> event that executes near the end of the tick cycle.<span class=\"Apple-converted-space\">  </span>Exactly when these events run depends upon whether the model is a WF model or a nonWF model; see the tick cycle diagrams for those model types.</p>\n<p class=\"p2\">The <span class=\"s1\">id</span> is an optional identifier like <span class=\"s1\">s1</span> (or more generally, <span class=\"s1\">sX</span>, where <span class=\"s1\">X</span> is an integer greater than or equal to <span class=\"s1\">0</span>) that defines an identifier that can be used to refer to the script block.<span class=\"Apple-converted-space\">  </span>In most situations it can be omitted, in which case the <span class=\"s1\">id</span> is implicitly defined as <span class=\"s1\">-1</span>, a placeholder value that essentially represents the lack of an identifier value.<span class=\"Apple-converted-space\">  </span>Supplying an <span class=\"s1\">id</span> is only useful if you wish to manipulate your script blocks programmatically.</p>\n<p class=\"p2\">Then comes a tick or a range of ticks, and then a block of Eidos code enclosed in braces to form a compound statement.<span class=\"Apple-converted-space\">  </span>A trivial example might look like this:</p>\n<p class=\"p3\"><span class=\"s2\">1000</span>:<span class=\"s2\">5000</span> early() {<br>\n<span class=\"Apple-tab-span\">\t</span>catn(<span class=\"s3\">community</span>.tick);<br>\n}</p>\n<p class=\"p2\">This would print the tick number in every tick in the specified range, which is obviously not very exciting.<span class=\"Apple-converted-space\">  </span>The broader point is that the Eidos code in the braces <span class=\"s1\">{}</span> is executed early in every tick within the specified range of ticks.<span class=\"Apple-converted-space\">  </span>In this case, the tick range is <span class=\"s1\">1000</span> to <span class=\"s1\">5000</span>, and so the Eidos event will be executed 4001 times (not 4000!).<span class=\"Apple-converted-space\">  </span>A range of ticks can be given, as in the example above, or a single tick can be given with a single integer:</p>\n<p class=\"p3\"><span class=\"s4\">100</span> late() {<br>\n<span class=\"Apple-tab-span\">\t</span>print(<span class=\"s5\">\"Finished tick 100!\"</span>);<br>\n}</p>\n<p class=\"p2\">The tick range may also be incompletely specified, with a somewhat idiosyncratic syntax.<span class=\"Apple-converted-space\">  </span>A range of <span class=\"s1\">1000:</span> would specify that the event should run in tick <span class=\"s1\">1000</span> and every subsequent tick until the model finishes; a range of <span class=\"s1\">:1000</span> would similarly specify that the event should run in the first tick executed, and every subsequent tick, up to and including tick <span class=\"s1\">1000</span>.</p>\n<p class=\"p2\">In fact, you can omit specifying a tick altogether, in which case the Eidos event runs every tick.<span class=\"Apple-converted-space\">  </span>Since it takes a little time to set up the Eidos interpreter and interpret a script, it is advisable to use the narrowest range of ticks possible; however, that is more of a concern with callbacks, since they might be called many time in every tick, whereas <span class=\"s1\">first()</span>, <span class=\"s1\">early()</span>, and <span class=\"s1\">late()</span> events will just be called once per tick.</p>\n<p class=\"p2\">The ticks specified for a Eidos event block can be any positive integer.<span class=\"Apple-converted-space\">  </span>All blocks that apply to a given time point will be run in <i>definition order</i>; blocks specified higher in the input file will run before those specified lower.<span class=\"Apple-converted-space\">  </span>Sometimes it is desirable to have a script block execute in a tick which is not fixed, but instead depends upon some parameter, defined constant, or calculation; this may be achieved by rescheduling the script block with the <span class=\"s1\">Community</span> method <span class=\"s1\">rescheduleScriptBlock()</span>.</p>\n<p class=\"p2\">In multispecies models, one can optionally provide a <span class=\"s1\">ticks</span> specifier before the definition of an Eidos event, specifying that the event should only run in ticks in which a particular species is active.<span class=\"Apple-converted-space\">  </span>That extended syntax looks like this:</p>\n<p class=\"p3\">[ticks species_name] [id] [t1 [: t2]] first() { ... }<br>\n[ticks species_name] [id] [t1 [: t2]] early() { ... }<br>\n[ticks species_name] [id] [t1 [: t2]] late() { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">species_name</span> should be the name of a species that was explicitly declared in the multispecies model.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">ticks</span> specifier is omitted, the event will run in every tick (within the specified tick range).</p>\n<p class=\"p2\">When Eidos events are executed, several global variables are defined by SLiM for use by the Eidos code.<span class=\"Apple-converted-space\">  </span>Here is a summary of those SLiM globals:</p>\n<p class=\"p4\"><span class=\"s1\">community</span><span class=\"Apple-tab-span\">\t</span>The <span class=\"s1\">Community</span> object for the overall simulation</p>\n<p class=\"p4\"><span class=\"s1\">sim</span><span class=\"Apple-tab-span\">\t</span>A <span class=\"s1\">Species</span> object for the simulated species (in single-species simulations)</p>\n<p class=\"p4\"><span class=\"s1\">g1</span>, <span class=\"s1\">...</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">GenomicElementType</span> objects for defined genomic element types</p>\n<p class=\"p4\"><span class=\"s1\">i1</span>, <span class=\"s1\">...</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">InteractionType</span> objects for defined interaction types</p>\n<p class=\"p4\"><span class=\"s1\">m1</span>, <span class=\"s1\">...</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">MutationType</span> objects representing defined mutation types</p>\n<p class=\"p4\"><span class=\"s1\">p1</span>, <span class=\"s1\">...</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">Subpopulation</span> objects for existing subpopulations</p>\n<p class=\"p4\"><span class=\"s1\">s1</span>, <span class=\"s1\">...</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">SLiMEidosBlock</span> objects for named events and callbacks</p>\n<p class=\"p5\"><span class=\"s1\">self</span><span class=\"Apple-tab-span\">\t</span>A <span class=\"s1\">SLiMEidosBlock</span> object for the script block currently executing</p>\n<p class=\"p2\">In multispecies models, symbols for each species will be defined instead of <span class=\"s1\">sim</span>.<span class=\"Apple-converted-space\">  </span>Note that species symbols such as <span class=\"s1\">sim</span> are <i>not</i> available in <span class=\"s1\">initialize()</span> callbacks, since the species objects have not yet been initialized.<span class=\"Apple-converted-space\">  </span>Similarly, the globals for subpopulations, mutation types, and genomic element types are only available after the point at which those objects have been defined by an <span class=\"s1\">initialize()</span> callback.</p>\n<p class=\"p1\"><i>5.13.2<span class=\"Apple-converted-space\">  </span>ITEM: 3. </i><span class=\"s1\"><i>mutationEffect()</i></span><i> callbacks</i></p>\n<p class=\"p2\">An Eidos callback is a block of Eidos code that is called by SLiM in specific circumstances, to allow the customization of particular actions taken by SLiM while running the simulation of a species.<span class=\"Apple-converted-space\">  </span>Nine types of callbacks are presently supported (in addition to <span class=\"s1\">initialize()</span> callbacks): <span class=\"s1\">mutationEffect()</span> callbacks, discussed here, and <span class=\"s1\">fitnessEffect()</span>, <span class=\"s1\">mateChoice()</span>, <span class=\"s1\">modifyChild()</span>, <span class=\"s1\">recombination()</span>, <span class=\"s1\">interaction()</span>, <span class=\"s1\">reproduction()</span> , <span class=\"s1\">mutation()</span>, and <span class=\"s1\">survival()</span> callbacks.</p>\n<p class=\"p2\">A <span class=\"s1\">mutationEffect()</span> callback is called by SLiM when it is determining the fitness effect of a mutation carried by an individual.<span class=\"Apple-converted-space\">  </span>Normally, the fitness effect of a mutation is determined by the selection coefficient <i>s</i> of the mutation and the dominance coefficient <i>h</i> of the mutation (the latter used only if the individual is heterozygous for the mutation).<span class=\"Apple-converted-space\">  </span>More specifically, the standard calculation for the fitness effect of a mutation takes one of two forms.<span class=\"Apple-converted-space\">  </span>If the individual is homozygous, then the fitness effect is (1+<i>s</i>), or:</p>\n<p class=\"p6\"><i>w</i> = <i>w</i> * (1.0 + selectionCoefficient),</p>\n<p class=\"p7\">where <i>w</i> is the relative fitness of the individual carrying the mutation.<span class=\"Apple-converted-space\">  </span>If the individual is heterozygous, then the dominance coefficient enters the picture, and the fitness effect is (1+<i>hs</i>) or:</p>\n<p class=\"p6\"><i>w</i> = <i>w</i> * (1.0 + dominanceCoeff * selectionCoeff).</p>\n<p class=\"p2\">The dominance coefficient usually comes from the <span class=\"s1\">dominanceCoeff</span> property of the mutation’s <span class=\"s1\">MutationType</span>; if the focal individual has only one non-null haplosome, however, such that the mutation is paired with a null haplosome (i.e., is actually hemizygous, not heterozygous), the <span class=\"s1\">hemizygousDominanceCoeff</span> property of the <span class=\"s1\">MutationType</span> is used instead.</p>\n<p class=\"p2\">That is the standard behavior of SLiM, reviewed here to provide a conceptual baseline.<span class=\"Apple-converted-space\">  </span>Supplying a <span class=\"s1\">mutationEffect()</span> callback allows you to substitute any calculation you wish for the relative fitness effect of a mutation; the new relative fitness effect computation becomes:</p>\n<p class=\"p3\"><span class=\"s6\"><i>w</i> = <i>w</i> * </span>mutationEffect()</p>\n<p class=\"p7\">where <span class=\"s1\">mutationEffect()</span> is the value returned by your callback.<span class=\"Apple-converted-space\">  </span>This value is a multiplicative fitness effect, so <span class=\"s1\">1.0</span> is neutral, unlike the selection coefficient scale where <span class=\"s1\">0.0</span> is neutral; be careful with this distinction!</p>\n<p class=\"p2\">Like Eidos events, <span class=\"s1\">mutationEffect()</span> callbacks are defined as script blocks in the input file, but they use a variation of the syntax for defining an Eidos event:</p>\n<p class=\"p3\">[id] [t1 [: t2]] mutationEffect(&lt;mut-type-id&gt; [, &lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p2\">For example, if the callback were defined as:</p>\n<p class=\"p3\">1000:2000 mutationEffect(m2, p3) { 1.0; }</p>\n<p class=\"p7\">then a relative fitness of <span class=\"s1\">1.0</span> (i.e. neutral) would be used for all mutations of mutation type <span class=\"s1\">m2</span> in subpopulation <span class=\"s1\">p3</span> from tick <span class=\"s1\">1000</span> to tick <span class=\"s1\">2000</span>.<span class=\"Apple-converted-space\">  </span>The very same mutations, if also present in individuals in other subpopulations, would preserve their normal selection coefficient and dominance coefficient in those other subpopulations; this callback would therefore establish spatial heterogeneity in selection, in which mutation type <span class=\"s1\">m2</span> was neutral in subpopulation <span class=\"s1\">p3</span> but under selection in other subpopulations, for the range of ticks given.</p>\n<p class=\"p2\">In multispecies models, callbacks must be defined with a <span class=\"s1\">species</span> specifier that states the species with which species the callback is associated.<span class=\"Apple-converted-space\">  </span>Such a definition looks like this:</p>\n<p class=\"p3\">species species_name [id] [t1 [: t2]] mutationEffect(...) { ... }</p>\n<p class=\"p2\">It is the same syntax, in other words, except for the <span class=\"s1\">species</span> specifier at the beginning, with the name of the species that the callback will modify.<span class=\"Apple-converted-space\">  </span>As with the <span class=\"s1\">ticks</span> specifier for events, this means the callback will only be called in ticks when the species is active; but the <span class=\"s1\">species</span> specifier goes further, making that species the focal species for the callback.</p>\n<p class=\"p2\">In addition to the standard SLiM globals, a <span class=\"s1\">mutationEffect()</span> callback is supplied with some additional information passed through “pseudo-parameters”, variables that are defined by SLiM within the context of the callback’s code to supply the callback with relevant information:</p>\n<p class=\"p8\"><span class=\"s1\">mut</span><span class=\"Apple-tab-span\">\t</span>A <span class=\"s1\">Mutation</span> object, the mutation whose relative fitness is being evaluated</p>\n<p class=\"p8\"><span class=\"s1\">homozygous</span><span class=\"Apple-tab-span\">\t</span>A value of <span class=\"s1\">T</span> (the mutation is homozygous), <span class=\"s1\">F</span> (heterozygous), or <span class=\"s1\">NULL</span> (it is<br>\npaired with a null haplosome, and is thus hemizygous or haploid)</p>\n<p class=\"p8\"><span class=\"s1\">effect</span><span class=\"Apple-tab-span\">\t</span>The default relative fitness value calculated by SLiM</p>\n<p class=\"p8\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The individual carrying this mutation (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p5\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation in which that individual lives</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">mutationEffect()</span> callback to compute a fitness value.<span class=\"Apple-converted-space\">  </span>To implement the standard fitness functions used by SLiM for an autosomal simulation with no null haplosomes involved, for example, you could do something like this:</p>\n<p class=\"p3\">mutationEffect(m1) {<br>\n<span class=\"Apple-tab-span\">\t</span>if (homozygous)<br>\n<span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span>return 1.0 + mut.selectionCoeff;<br>\n<span class=\"Apple-tab-span\">\t</span>else<br>\n<span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span>return 1.0 + mut.mutationType.dominanceCoeff * mut.selectionCoeff;<br>\n}</p>\n<p class=\"p2\">As mentioned above, a relative fitness of <span class=\"s1\">1.0</span> is neutral (whereas a selection coefficient of <span class=\"s1\">0.0</span> is neutral); the <span class=\"s1\">1.0 +</span> in these calculations converts between the selection coefficient scale and the relative fitness scale, and is therefore essential.<span class=\"Apple-converted-space\">  </span>However, the <span class=\"s1\">effect</span> global variable mentioned above would already contain this value, precomputed by SLiM, so you could simply return <span class=\"s1\">effect</span> to get that behavior when you want it:</p>\n<p class=\"p3\">mutationEffect(m1) {<br>\n<span class=\"Apple-tab-span\">\t</span>if (&lt;conditions&gt;)<br>\n<span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span>&lt;custom fitness calculations...&gt;;<br>\n<span class=\"Apple-tab-span\">\t</span>else<br>\n<span class=\"Apple-tab-span\">\t</span><span class=\"Apple-tab-span\">\t</span>return effect;<br>\n}</p>\n<p class=\"p2\">This would return a modified fitness value in certain conditions, but would return the standard fitness value otherwise.</p>\n<p class=\"p2\">More than one <span class=\"s1\">mutationEffect()</span> callback may be defined to operate in the same tick.<span class=\"Apple-converted-space\">  </span>As with Eidos events, multiple callbacks will be called in the order in which they were defined in the input file.<span class=\"Apple-converted-space\">  </span>Furthermore, each callback will be given the <span class=\"s1\">effect</span> value returned by the previous callback – so the value of <span class=\"s1\">effect</span> is not necessarily the default value, in fact, but is the result of all previous <span class=\"s1\">mutationEffect()</span> callbacks for that individual in that tick.<span class=\"Apple-converted-space\">  </span>In this way, the effects of multiple callbacks can “stack”.</p>\n<p class=\"p2\">One caveat to be aware of in WF models is that <span class=\"s1\">mutationEffect()</span> callbacks are called at the end of the tick, just before the next tick begins.<span class=\"Apple-converted-space\">  </span>If you have a <span class=\"s1\">mutationEffect()</span> callback defined for tick <span class=\"s1\">10</span>, for example, it will actually be called at the very end of tick <span class=\"s1\">10</span>, after child generation has finished, after the new children have been promoted to be the next parental generation, and after <span class=\"s1\">late()</span> events have been executed.<span class=\"Apple-converted-space\">  </span>The fitness values calculated will thus be used during tick <span class=\"s1\">11</span>; the fitness values used in tick <span class=\"s1\">10</span> were calculated at the end of tick <span class=\"s1\">9</span>.<span class=\"Apple-converted-space\">  </span>(This is primarily so that SLiMgui, which refreshes its display in between ticks, has computed fitness values at hand that it can use to display the new parental individuals in the proper colors.)<span class=\"Apple-converted-space\">  </span>This is not an issue in nonWF models, since fitness values are used in the same tick in which they are calculated.</p>\n<p class=\"p2\">If the <span class=\"s1\">randomizeCallbacks</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span> is <span class=\"s1\">T</span> (the default), the order in which the fitness of individuals is evaluated will be randomized within each subpopulation.<span class=\"Apple-converted-space\">  </span>This partially mitigates order-dependency issues, although such issues can still arise whenever the effects of a <span class=\"s1\">mutationEffect()</span> callback are not independent.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeCallbacks</span> is <span class=\"s1\">F</span>, the fitness of individuals will be evaluated in sequential order within each subpopulation, greatly increasing the risk of order-dependency problems.</p>\n<p class=\"p2\">Many other possibilities can be implemented with <span class=\"s1\">mutationEffect()</span> callbacks.<span class=\"Apple-converted-space\">  </span>However, since <span class=\"s1\">mutationEffect()</span> callbacks involve Eidos code being executed for the evaluation of fitness of every mutation of every individual (within the tick range, mutation type, and subpopulation specified), they can slow down a simulation considerably, so use them as sparingly as possible.</p>\n<p class=\"p1\"><i>5.13.3<span class=\"Apple-converted-space\">  </span>ITEM: 4. </i><span class=\"s1\"><i>fitnessEffect()</i></span><i> callbacks</i></p>\n<p class=\"p2\">We have already seen <span class=\"s1\">mutationEffect()</span> callbacks, which modify the effect of a given mutation in a focal individual.<span class=\"Apple-converted-space\">  </span>Sometimes it is desirable to model effects upon individual fitness that are not governed by particular mutations (or not directly, at least); fitness effects due to spatial position, or resource acquisition, or behavior such as competitive or altruistic interactions, for example.<span class=\"Apple-converted-space\">  </span>Another situation of this type is when fitness depends upon the overall phenotype of an individual – the height of a tree, say – which might be influenced by genetics, but also by environmental effects, climate, and so forth.<span class=\"Apple-converted-space\">  </span>For these sorts of situations, SLiM provides <span class=\"s1\">fitnessEffect()</span> callbacks.</p>\n<p class=\"p2\">A <span class=\"s1\">fitnessEffect()</span> callback is called by SLiM when it is determining the fitness of an individual – typically, but not always, once per tick during the fitness calculation tick cycle stage.<span class=\"Apple-converted-space\">  </span>Normally, the fitness of a given individual is determined by multiplying together the fitness effects of all mutations possessed by that individual.<span class=\"Apple-converted-space\">  </span>Supplying a <span class=\"s1\">fitnessEffect()</span> callback allows you to add another multiplicative fitness effect into that calculation.<span class=\"Apple-converted-space\">  </span>As with <span class=\"s1\">mutationEffect()</span> callbacks, the value returned by <span class=\"s1\">fitnessEffect()</span> callbacks is a fitness effect, so <span class=\"s1\">1.0</span> is neutral.</p>\n<p class=\"p2\">The syntax for declaring <span class=\"s1\">fitnessEffect()</span> callbacks is similar to that for <span class=\"s1\">mutationEffect()</span> callbacks, but simpler since no mutation type is needed:</p>\n<p class=\"p3\">[id] [t1 [: t2]] fitnessEffect([&lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p2\">(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">For example, if the callback were defined as:</p>\n<p class=\"p3\">1000:2000 fitnessEffect(p3) { 0.75; }</p>\n<p class=\"p2\">then a fitness effect of <span class=\"s1\">0.75</span> would be multiplied into the fitness values of all individuals in subpopulation <span class=\"s1\">p3</span> from tick <span class=\"s1\">1000</span> to tick <span class=\"s1\">2000</span>.</p>\n<p class=\"p2\">Much more interesting, of course, are <span class=\"s1\">fitnessEffect()</span> callbacks that return different fitness effects for different individuals, depending upon their state!<span class=\"Apple-converted-space\">  </span>In addition to the standard SLiM globals, a <span class=\"s1\">fitnessEffect()</span> callback is supplied with some additional information passed through “pseudo-parameters”, variables that are defined by SLiM within the context of the callback’s code to supply the callback with relevant information:</p>\n<p class=\"p8\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The focal individual (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p5\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation in which that individual lives</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">fitnessEffect()</span> callback to compute a fitness effect that depends upon the state of the focal individual.<span class=\"Apple-converted-space\">  </span>The fitness effect for the callback is simply returned as a singleton <span class=\"s1\">float</span> value, as usual.</p>\n<p class=\"p2\">More than one <span class=\"s1\">fitnessEffect()</span> callback may be defined to operate in the same tick.<span class=\"Apple-converted-space\">  </span>Each such callback will provide an independent fitness effect for the focal individual; the results of each <span class=\"s1\">fitnessEffect()</span> callback will be multiplied in to the individual’s fitness.<span class=\"Apple-converted-space\">  </span>These callbacks will generally be called once per individual in each tick, in an order that is formally undefined.</p>\n<p class=\"p2\">Beginning in SLiM 3.0, it is also possible to set the <span class=\"s1\">fitnessScaling</span> property on a subpopulation to scale the fitness values of every individual in the subpopulation by the same constant amount, or to set the <span class=\"s1\">fitnessScaling</span> property on an individual to scale the fitness value of that specific individual.<span class=\"Apple-converted-space\">  </span>These scaling factors are multiplied together with all other fitness effects for an individual to produce the individual’s final fitness value.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">fitnessScaling</span> properties of <span class=\"s1\">Subpopulation</span> and <span class=\"s1\">Individual</span> can often provide similar functionality to <span class=\"s1\">fitnessEffect()</span> callbacks with greater efficiency and simplicity.<span class=\"Apple-converted-space\">  </span>They are reset to <span class=\"s1\">1.0</span> in every tick for which a given species is active, immediately after fitness values are calculated, so they only need to be set when a value other than <span class=\"s1\">1.0</span> is desired.</p>\n<p class=\"p2\">As with <span class=\"s1\">mutationEffect()</span> callbacks, <span class=\"s1\">fitnessEffect()</span> callbacks are called at the end of the tick, just before the next tick begins.<span class=\"Apple-converted-space\">  </span>Also, as with <span class=\"s1\">mutationEffect()</span> callbacks, the order in which <span class=\"s1\">fitnessEffect()</span> callbacks are called will be shuffled when <span class=\"s1\">randomizeCallbacks</span> is enabled, as it is by default, partially mitigating order-dependency issues.</p>\n<p class=\"p2\">The <span class=\"s1\">fitnessEffect()</span> callback mechanism is quite flexible and useful, although it has been considerably eclipsed by the modern modern and efficient <span class=\"s1\">fitnessScaling</span> property mentioned above.<span class=\"Apple-converted-space\">  </span>When efficiency is not at a premium, it remains a clear and expressive paradigm for modeling individual-level fitness effects.<span class=\"Apple-converted-space\">  </span>The performance penalty paid is often not large, since these callbacks are called only once per individual per tick, whereas a <span class=\"s1\">mutationEffect()</span> for a type of mutation that is common in the simulation might be called thousands of times per individual per tick (once per mutation of that type possessed by the focal individual).<span class=\"Apple-converted-space\">  </span>The performance penalty typically becomes severe only when the <span class=\"s1\">fitnessEffect()</span> callback needs to perform calculations, once per focal individual, that would vectorize well if performed across a whole vector of individuals.<span class=\"Apple-converted-space\">  </span>In such cases, <span class=\"s1\">fitnessScaling</span> should be used.</p>\n<p class=\"p1\"><i>5.13.4<span class=\"Apple-converted-space\">  </span>ITEM: 5. </i><span class=\"s1\"><i>mateChoice()</i></span><i> callbacks</i></p>\n<p class=\"p2\">Normally, WF models in SLiM regulate mate choice according to fitness; individuals of higher fitness are more likely to be chosen as mates.<span class=\"Apple-converted-space\">  </span>However, one might wish to simulate more complex mate-choice dynamics such as assortative or disassortative mating, mate search algorithms, and so forth.<span class=\"Apple-converted-space\">  </span>Such dynamics can be handled in WF models with the <span class=\"s1\">mateChoice()</span> callback mechanism.<span class=\"Apple-converted-space\">  </span>(In nonWF models mating is arranged by the script, so there is no need for a callback.)</p>\n<p class=\"p2\">A <span class=\"s1\">mateChoice()</span> callback is established in the input file with a syntax very similar to that of <span class=\"s1\">fitnessEffect()</span> callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] mateChoice([&lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p7\">(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">Note that if a subpopulation is given to which the <span class=\"s1\">mateChoice()</span> callback is to apply, the callback is used for all matings that will generate a <i>child</i> in the stated subpopulation (as opposed to all matings of <i>parents</i> in the stated subpopulation); this distinction is important when migration causes children in one subpopulation to be generated by matings of parents in a different subpopulation.</p>\n<p class=\"p2\">When a <span class=\"s1\">mateChoice()</span> callback is defined, the first parent in a mating is still chosen proportionally according to fitness (if you wish to influence that choice, you can use a <span class=\"s1\">mutationEffect()</span> or <span class=\"s1\">fitnessEffect()</span> callback).<span class=\"Apple-converted-space\">  </span>In a sexual (rather than hermaphroditic) simulation, this will be the female parent; SLiM does not currently support males as the choosy sex.<span class=\"Apple-converted-space\">  </span>The second parent – the male parent, in a sexual simulation – will then be chosen based upon the results of the <span class=\"s1\">mateChoice()</span> callback.</p>\n<p class=\"p2\">More specifically, the callback must return a vector of weights, one for each individual in the subpopulation; SLiM will then choose a parent with probability proportional to weight.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">mateChoice()</span> callback could therefore modify or replace the standard fitness-based weights depending upon some other criterion such as assortativeness.<span class=\"Apple-converted-space\">  </span>A singleton object of type <span class=\"s1\">Individual</span> may be returned instead of a weights vector to indicate that that specific individual has been chosen as the mate (beginning in SLiM 2.3); this could also be achieved by returned a vector of weights in which the chosen mate has a non-zero weight and all other weights are zero, but returning the chosen individual directly is much more efficient.<span class=\"Apple-converted-space\">  </span>A zero-length return vector – as generated by <span class=\"s1\">float(0)</span>, for example – indicates that a suitable mate was not found; in that event, a new first parent will be drawn from the subpopulation.<span class=\"Apple-converted-space\">  </span>Finally, if the callback returns <span class=\"s1\">NULL</span>, that signifies that SLiM should use the standard fitness-based weights to choose a mate; the <span class=\"s1\">mateChoice()</span> callback did not wish to alter the standard behavior for the current mating (this is equivalent to returning the unmodified vector of weights, but returning <span class=\"s1\">NULL</span> is much faster since it allows SLiM to drop into an optimized case).<span class=\"Apple-converted-space\">  </span>Apart from the special cases described above – a singleton <span class=\"s1\">Individual</span>, <span class=\"s1\">float(0)</span>, and <span class=\"s1\">NULL</span> – the returned vector of weights must contain the same number of values as the size of the subpopulation, and all weights must be non-negative.<span class=\"Apple-converted-space\">  </span>Note that the vector of weights is not required to sum to <span class=\"s1\">1</span>, however; SLiM will convert relative weights on any scale to probabilities for you.</p>\n<p class=\"p2\">If the sum of the returned weights vector is zero, SLiM treats it as meaning the same thing as a return of <span class=\"s1\">float(0)</span> – a suitable mate could not be found, and a new first parent will thus be drawn.<span class=\"Apple-converted-space\">  </span>(This is a change in policy beginning in SLiM 2.3; prior to that, returning a vector of sum zero was considered a runtime error.)<span class=\"Apple-converted-space\">  </span>There is a subtle difference in semantics between this and a return of <span class=\"s1\">float(0)</span>: returning <span class=\"s1\">float(0)</span> immediately short-circuits mate choice for the current first parent, whereas returning a vector of zeros allows further applicable <span class=\"s1\">mateChoice()</span> callbacks to be called, one of which might “rescue” the first parent by returning a non-zero weights vector or an individual.<span class=\"Apple-converted-space\">  </span>In most models this distinction is irrelevant, since chaining <span class=\"s1\">mateChoice()</span> callbacks is uncommon.<span class=\"Apple-converted-space\">  </span>When the choice is otherwise unimportant, returning <span class=\"s1\">float(0)</span> will be handled more quickly by SLiM.</p>\n<p class=\"p2\">In addition to the standard SLiM globals, a <span class=\"s1\">mateChoice()</span> callback is supplied with some additional information passed through “pseudo-parameters”:</p>\n<p class=\"p9\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The parent already chosen (the female, in sexual simulations)</p>\n<p class=\"p9\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation into which the offspring will be placed</p>\n<p class=\"p9\"><span class=\"s1\">sourceSubpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation from which the parents are being chosen</p>\n<p class=\"p10\"><span class=\"s1\">weights</span><span class=\"Apple-tab-span\">\t</span>The standard fitness-based weights for all individuals</p>\n<p class=\"p2\">If sex is enabled, the <span class=\"s1\">mateChoice()</span> callback must ensure that the appropriate weights are zero and nonzero to guarantee that all eligible mates are male (since the first parent chosen is always female, as explained above).<span class=\"Apple-converted-space\">  </span>In other words, weights for females must be <span class=\"s1\">0</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">weights</span> vector given to the callback is guaranteed to satisfy this constraint.<span class=\"Apple-converted-space\">  </span>If sex is not enabled – in a hermaphroditic simulation, in other words – this constraint does not apply.</p>\n<p class=\"p2\">For example, a simple <span class=\"s1\">mateChoice()</span> callback might look like this:</p>\n<p class=\"p3\">1000:2000 mateChoice(p2) {<br>\n<span class=\"Apple-tab-span\">\t</span>return weights ^ 2;<br>\n}</p>\n<p class=\"p2\">This defines a <span class=\"s1\">mateChoice()</span> callback for ticks <span class=\"s1\">1000</span> to <span class=\"s1\">2000</span> for subpopulation <span class=\"s1\">p2</span>.<span class=\"Apple-converted-space\">  </span>The callback simply transforms the standard fitness-based probabilities by squaring them.<span class=\"Apple-converted-space\">  </span>Code like this could represent a situation in which fitness and mate choice proceed normally in one subpopulation (<span class=\"s1\">p1</span>, here, presumably), but are altered by the effects of a social dominance hierarchy or male-male competition in another subpopulation (<span class=\"s1\">p2</span>, here), such that the highest-fitness individuals tend to be chosen as mates more often than their (perhaps survival-based) fitness values would otherwise suggest.<span class=\"Apple-converted-space\">  </span>Note that by basing the returned weights on the <span class=\"s1\">weights</span> vector supplied by SLiM, the requirement that females be given weights of <span class=\"s1\">0</span> is finessed; in other situations, care would need to be taken to ensure that.</p>\n<p class=\"p2\">More than one <span class=\"s1\">mateChoice()</span> callback may be defined to operate in the same tick.<span class=\"Apple-converted-space\">  </span>As with Eidos events, multiple callbacks will be called in the order in which they were defined.<span class=\"Apple-converted-space\">  </span>Furthermore, each callback will be given the <span class=\"s1\">weights</span> vector returned by the previous callback – so the value of <span class=\"s1\">weights</span> is not necessarily the default fitness-based weights, in fact, but is the result of all previous <span class=\"s1\">weights()</span> callbacks for the current mate-choice event.<span class=\"Apple-converted-space\">  </span>In this way, the effects of multiple callbacks can “stack”.<span class=\"Apple-converted-space\">  </span>If any <span class=\"s1\">mateChoice()</span> callback returns <span class=\"s1\">float(0)</span>, however – indicating that no eligible mates exist, as described above – then the remainder of the callback chain will be short-circuited and a new first parent will immediately be chosen.</p>\n<p class=\"p2\">Note that matings in SLiM do not proceed in random order.<span class=\"Apple-converted-space\">  </span>Offspring are generated for each subpopulation in turn, and within each subpopulation the order of offspring generation is also non-random with respect to both the source subpopulation and the sex of the offspring.<span class=\"Apple-converted-space\">  </span>It is important, therefore, that <span class=\"s1\">mateChoice()</span> callbacks are not in any way biased by the offspring generation order; they should not treat matings early in the process any differently than matings late in the process.<span class=\"Apple-converted-space\">  </span>Any failure to guarantee such invariance could lead to large biases in the simulation outcome.<span class=\"Apple-converted-space\">  </span>In particular, it is usually dangerous to activate or deactivate <span class=\"s1\">mateChoice()</span> callbacks while offspring generation is in progress.</p>\n<p class=\"p2\">A wide variety of mate choice algorithms can easily be implemented with <span class=\"s1\">mateChoice()</span> callbacks.<span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">mateChoice()</span> callbacks can be particularly slow since they are called for every proposed mating, and the vector of mating weights can be large and slow to process.</p>\n<p class=\"p1\"><i>5.13.5<span class=\"Apple-converted-space\">  </span>ITEM: 6. </i><span class=\"s1\"><i>modifyChild()</i></span><i> callbacks</i></p>\n<p class=\"p2\">Normally, a SLiM simulation defines child generation with its rules regarding selfing versus crossing, recombination, mutation, and so forth.<span class=\"Apple-converted-space\">  </span>However, one might wish to modify these rules in particular circumstances – by preventing particular children from being generated, by modifying the generated children in particular ways, or by generating children oneself.<span class=\"Apple-converted-space\">  </span>All of these dynamics can be handled in SLiM with the <span class=\"s1\">modifyChild()</span> callback mechanism.</p>\n<p class=\"p2\">A <span class=\"s1\">modifyChild()</span> callback is established in the input file with a syntax very similar to that of other callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] modifyChild([&lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">modifyChild()</span> callback may optionally be restricted to the children generated to occupy a specified subpopulation.<span class=\"Apple-converted-space\">  </span>(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">When a <span class=\"s1\">modifyChild()</span> callback is called, a parent or parents have already been chosen, and a candidate child has already been generated.<span class=\"Apple-converted-space\">  </span>The parent or parents are provided to the callback, as is the generated child.<span class=\"Apple-converted-space\">  </span>The callback may accept the generated child, modify it, substitute completely different genetic information for it, or reject it (causing a new parent or parents to be selected and a new child to be generated, which will again be passed to the callback).</p>\n<p class=\"p2\">In addition to the standard SLiM globals, a <span class=\"s1\">modifyChild()</span> callback is supplied with additional information passed through “pseudo-parameters”:</p>\n<p class=\"p11\"><span class=\"s1\">child</span><span class=\"Apple-tab-span\">\t</span>The generated child (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p11\"><span class=\"s1\">isCloning</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">T</span> if the child is the result of cloning</p>\n<p class=\"p11\"><span class=\"s1\">isSelfing</span><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">T</span> if the child is the result of selfing (but see note below)</p>\n<p class=\"p11\"><span class=\"s1\">parent1</span><span class=\"Apple-tab-span\">\t</span>The first parent (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p11\"><span class=\"s1\">parent2</span><span class=\"Apple-tab-span\">\t</span>The second parent (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p11\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation in which the child will live</p>\n<p class=\"p12\"><span class=\"s1\">sourceSubpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation of the parents (<span class=\"s1\">==subpop</span> if not a migration mating)</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">modifyChild()</span> callback to decide upon a course of action.<span class=\"Apple-converted-space\">  </span>The haplosomes of child (available as <span class=\"s1\">child.haplosomes</span>) may be modified by the callback; whatever mutations they contain on exit will be used for the new child.<span class=\"Apple-converted-space\">  </span>Alternatively, they may be left unmodified (to accept the generated child as is).<span class=\"Apple-converted-space\">  </span>The child’s haplosomes may be thought of as the two gametes that will fuse to produce the fertilized egg that results in a new offspring; for a biparental cross involving diploid autosomes, <span class=\"s1\">child.haploidGenome1</span> is the gamete contributed by the first parent (the female, if sex is turned on), and <span class=\"s1\">child.haploidGenome2</span> is the gamete contributed by the second parent (the male, if sex is turned on).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">child</span> object itself may also be modified – for example, to set the spatial position of the child.</p>\n<p class=\"p2\">Importantly, a <span class=\"s1\">logical</span> singleton return value is required from <span class=\"s1\">modifyChild()</span> callbacks.<span class=\"Apple-converted-space\">  </span>Normally this should be <span class=\"s1\">T</span>, indicating that generation of the child may proceed (with whatever modifications might have been made to the child’s haplosomes).<span class=\"Apple-converted-space\">  </span>A return value of <span class=\"s1\">F</span> indicates that generation of this child should not continue; this will cause new parent(s) to be drawn, a new child to be generated, and a new call to the <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">modifyChild()</span> callback that always returns <span class=\"s1\">F</span> can cause SLiM to hang, so be careful that it is guaranteed that your callback has a nonzero probability of returning <span class=\"s1\">T</span> for every state your simulation can reach.</p>\n<p class=\"p2\">Note that <span class=\"s1\">isSelfing</span> is <span class=\"s1\">T</span> only when a mating was explicitly set up to be a selfing event by SLiM; an individual may also mate with itself by chance (by drawing itself as a mate) even when SLiM did not explicitly set up a selfing event, which one might term <i>incidental</i> selfing.<span class=\"Apple-converted-space\">  </span>If you need to know whether a mating event was an incidental selfing event, you can compare the parents; self-fertilization will always entail <span class=\"s1\">parent1==parent2</span>, even when <span class=\"s1\">isSelfing</span> is <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>Since selfing is enabled only in non-sexual simulations, <span class=\"s1\">isSelfing</span> will always be <span class=\"s1\">F</span> in sexual simulations (and incidental selfing is also impossible in sexual simulations).</p>\n<p class=\"p2\">Note that matings in SLiM do not proceed in random order.<span class=\"Apple-converted-space\">  </span>Offspring are generated for each subpopulation in turn, and within each subpopulation the order of offspring generation is also non-random with respect to the source subpopulation, the sex of the offspring, and the reproductive mode (selfing, cloning, or autogamy).<span class=\"Apple-converted-space\">  </span>It is important, therefore, that <span class=\"s1\">modifyChild()</span> callbacks are not in any way biased by the offspring generation order; they should not treat offspring generated early in the process any differently than offspring generated late in the process.<span class=\"Apple-converted-space\">  </span>Similar to <span class=\"s1\">mateChoice()</span> callbacks, any failure to guarantee such invariance could lead to large biases in the simulation outcome.<span class=\"Apple-converted-space\">  </span>In particular, it is usually dangerous to activate or deactivate <span class=\"s1\">modifyChild()</span> callbacks while offspring generation is in progress.<span class=\"Apple-converted-space\">  </span>When SLiM sees that <span class=\"s1\">mateChoice()</span> or <span class=\"s1\">modifyChild()</span> callbacks are defined, it randomizes the order of child generation within each subpopulation, so this issue is mitigated somewhat.<span class=\"Apple-converted-space\">  </span>However, offspring are still generated for each subpopulation in turn.<span class=\"Apple-converted-space\">  </span>Furthermore, in ticks without active callbacks offspring generation order will not be randomized (making the order of parents nonrandom in the next generation), with possible side effects.<span class=\"Apple-converted-space\">  </span>In short, order-dependency issues are possible and must be handled very carefully.</p>\n<p class=\"p2\">As with the other callback types, multiple <span class=\"s1\">modifyChild()</span> callbacks may be registered and active.<span class=\"Apple-converted-space\">  </span>In this case, all registered and active callbacks will be called for each child generated, in the order that the callbacks were registered.<span class=\"Apple-converted-space\">  </span>If a <span class=\"s1\">modifyChild()</span> callback returns <span class=\"s1\">F</span>, however, indicating that the child should not be generated, the remaining callbacks in the chain will not be called.</p>\n<p class=\"p2\">There are many different ways in which a <span class=\"s1\">modifyChild()</span> callback could be used in a simulation.<span class=\"Apple-converted-space\">  </span>In nonWF models, <span class=\"s1\">modifyChild()</span> callbacks are often unnecessary since each generated child is available to the script in the models’ <span class=\"s1\">reproduction()</span> callback anyway; but they may be used if desired.</p>\n<p class=\"p1\"><i>5.13.6<span class=\"Apple-converted-space\">  </span>ITEM: 7. </i><span class=\"s1\"><i>recombination()</i></span><i> callbacks</i></p>\n<p class=\"p2\">Typically, a simulation sets up a recombination map at the beginning of the run with <span class=\"s1\">initializeRecombinationRate()</span>, and that map is used for the duration of the run.<span class=\"Apple-converted-space\">  </span>Less commonly, the recombination map is changed dynamically from tick to tick, with <span class=\"s1\">Chromosome</span>’s method <span class=\"s1\">setRecombinationRate()</span>; but still, a single recombination map applies for all individuals of a species in a given tick.<span class=\"Apple-converted-space\">  </span>However, in unusual circumstances a simulation may need to modify the way that recombination works on an individual basis; for this, the <span class=\"s1\">recombination()</span> callback mechanism is provided.<span class=\"Apple-converted-space\">  </span>This can be useful for models involving chromosomal inversions that prevent recombination within a region for some individuals, for example, or for models of the evolution of recombination.</p>\n<p class=\"p2\">A <span class=\"s1\">recombination()</span> callback is defined with a syntax much like that of other callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] recombination([&lt;subpop-id&gt; [, &lt;chromosome-id&gt;]]) { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">recombination()</span> callback will be called during the generation of every gamete during the tick(s) in which it is active.<span class=\"Apple-converted-space\">  </span>It may optionally be restricted to apply only to gametes generated by parents in a specified subpopulation, using the <span class=\"s1\">&lt;subpop-id&gt;</span> specifier.<span class=\"Apple-converted-space\">  </span>In addition, in multi-chromosome models it may optionally be restricted to apply only to a specified chromosome, using the <span class=\"s1\">&lt;chromosome-id&gt;</span> specifier, which may be either the <span class=\"s1\">id</span> or the <span class=\"s1\">symbol</span> of a chromosome defined in the species.<span class=\"Apple-converted-space\">  </span>(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">When a <span class=\"s1\">recombination()</span> callback is called, a parent has already been chosen to generate a gamete, and candidate recombination breakpoints for use in recombining the parental haplosomes have been drawn.<span class=\"Apple-converted-space\">  </span>The relevant haplosomes of the focal parent are provided to the callback, as is the focal parent itself (as an <span class=\"s1\">Individual</span> object) and the subpopulation in which it resides.<span class=\"Apple-converted-space\">  </span>Furthermore, the proposed breakpoints are provided to the callback.<span class=\"Apple-converted-space\">  </span>The callback may modify these breakpoints in order to change the breakpoints used, in which case it must return <span class=\"s1\">T</span> to indicate that changes were made, or it may leave the proposed breakpoints unmodified, in which case it must return <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>(The behavior of SLiM is undefined if the callback returns the wrong <span class=\"s1\">logical</span> value.)</p>\n<p class=\"p2\">In addition to the standard SLiM globals, then, a <span class=\"s1\">recombination()</span> callback is supplied with additional information passed through “pseudo-parameters”:</p>\n<p class=\"p9\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The focal parent that is generating a gamete</p>\n<p class=\"p9\"><span class=\"s1\">haplosome1</span><span class=\"Apple-tab-span\">\t</span>One haplosome of the focal parent; this is the initial copy strand</p>\n<p class=\"p9\"><span class=\"s1\">haplosome2</span><span class=\"Apple-tab-span\">\t</span>The other haplosome of the focal parent</p>\n<p class=\"p9\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation to which the focal parent belongs</p>\n<p class=\"p13\"><span class=\"s1\">breakpoints</span><span class=\"Apple-tab-span\">\t</span>An <span class=\"s1\">integer</span> vector of crossover breakpoints</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">recombination()</span> callback to determine the final recombination breakpoints used by SLiM.<span class=\"Apple-converted-space\">  </span>If values are set into <span class=\"s1\">breakpoints</span>, the new values must be of type <span class=\"s1\">integer</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">breakpoints</span> is modified by the callback, <span class=\"s1\">T</span> should be returned, otherwise <span class=\"s1\">F</span> should be returned (this is a speed optimization, so that SLiM does not have to spend time checking for changes when no changes have been made).</p>\n<p class=\"p2\">The positions specified in <span class=\"s1\">breakpoints</span> mean that a crossover will occur immediately <i>before</i> the specified base position (between the preceding base and the specified base, in other words).<span class=\"Apple-converted-space\">  </span>The haplosome specified by <span class=\"s1\">haplosome1</span> will be used as the initial copy strand when SLiM executes the recombination; this cannot presently be changed by the callback.<span class=\"Apple-converted-space\">  </span>(Note that <span class=\"s1\">haplosome1</span> and <span class=\"s1\">haplosome2</span> will be haplosomes from <span class=\"s1\">individual</span>, but their order may be swapped, depending on which is the initial copy strand!)</p>\n<p class=\"p2\">In this design, the recombination callback does not specify a custom recombination map.<span class=\"Apple-converted-space\">  </span>Instead, the callback can add or remove breakpoints at specific locations.<span class=\"Apple-converted-space\">  </span>To implement a chromosomal inversion, for example, if the parent is heterozygous for the inversion mutation then crossovers within the inversion region are removed by the callback.<span class=\"Apple-converted-space\">  </span>As another example, to implement a model of the evolution of the overall recombination rate, a model could (1) set the global recombination rate to the highest rate attainable in the simulation, (2) for each individual, within the <span class=\"s1\">recombination()</span> callback, calculate the fraction of that maximum rate that the focal individual would experience based upon its genetics, and (3) probabilistically remove proposed crossover points based upon random uniform draws compared to that threshold fraction, thus achieving the individual effective recombination rate desired.<span class=\"Apple-converted-space\">  </span>Other similar treatments could actually vary the effective recombination map, not just the overall rate, by removing proposed crossovers with probabilities that depend upon their position, allowing for the evolution of localized recombination hot-spots and cold-spots.<span class=\"Apple-converted-space\">  </span>Crossovers may also be added, not just removed, by <span class=\"s1\">recombination()</span> callbacks.</p>\n<p class=\"p2\">In SLiM 3.3 the recombination model in SLiM was redesigned.<span class=\"Apple-converted-space\">  </span>This required a corresponding redesign of <span class=\"s1\">recombination()</span> callbacks.<span class=\"Apple-converted-space\">  </span>In particular, the <span class=\"s1\">gcStarts</span> and <span class=\"s1\">gcEnds</span> pseudo-parameters to <span class=\"s1\">recombination()</span> callbacks were removed.<span class=\"Apple-converted-space\">  </span>In the present design, the callback receives “crossover breakpoints” information only, in the <span class=\"s1\">breakpoints</span> pseudo-parameter; it receives no information about gene conversion.<span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">recombination()</span> callbacks can still be used with the “DSB” recombination model; at the point when the callback is called, the pattern of gene conversion tracts will have been simplified down to a vector of crossover breakpoints.<span class=\"Apple-converted-space\">  </span>“Complex” gene conversion tracts, however, involving heteroduplex mismatch repair, are not compatible with <span class=\"s1\">recombination()</span> callbacks, since there is presently no way for them to be specified to the callback.</p>\n<p class=\"p2\">Note that the positions in <span class=\"s1\">breakpoints</span> are not, in the general case, guaranteed to be sorted or uniqued; in other words, positions may appear out of order, and the same position may appear more than once.<span class=\"Apple-converted-space\">  </span>After all <span class=\"s1\">recombination()</span> callbacks have completed, the positions from <span class=\"s1\">breakpoints</span> will be sorted, uniqued, and used as the crossover points in generating the prospective gamete haplosome.<span class=\"Apple-converted-space\">  </span>The essential point here is that if the same position occurs more than once, across <span class=\"s1\">breakpoints</span>, the multiple occurrences of the position do not cancel; SLiM does not cross over and then “cross back over” given a pair of identical positions.<span class=\"Apple-converted-space\">  </span>Instead, the multiple occurrences of the position will simply be uniqued down to a single occurrence.</p>\n<p class=\"p2\">As with the other callback types, multiple <span class=\"s1\">recombination()</span> callbacks may be registered and active.<span class=\"Apple-converted-space\">  </span>In this case, all registered and active callbacks will be called for each gamete generated, in the order that the callbacks were registered.</p>\n<p class=\"p1\"><i>5.13.7<span class=\"Apple-converted-space\">  </span>ITEM: 8. </i><span class=\"s1\"><i>interaction()</i></span><i> callbacks</i></p>\n<p class=\"p2\">The <span class=\"s1\">InteractionType</span> class provides various built-in interaction functions that translate from distances to interaction strengths.<span class=\"Apple-converted-space\">  </span>However, it may sometimes be useful to define a custom function for that purpose; for that reason, SLiM allows <span class=\"s1\">interaction()</span> callbacks to be defined that modify the standard interaction strength calculated by <span class=\"s1\">InteractionType</span>.<span class=\"Apple-converted-space\">  </span>In particular, this mechanism allows the strength of interactions to depend upon not only the distance between individuals, but also the genetics and other state of the individuals, the spatial position of the individuals, and other environmental variables.</p>\n<p class=\"p2\">An <span class=\"s1\">interaction()</span> callback is called by SLiM when it is determining the strength of the interaction between one individual (the <i>receiver</i> of the interaction) and another individual (the <i>exerter</i> of the interaction).<span class=\"Apple-converted-space\">  </span>This generally occurs when an interaction query is made to <span class=\"s1\">InteractionType</span>, as a side effect of serving that query.<span class=\"Apple-converted-space\">  </span>This means that <span class=\"s1\">interaction()</span> callbacks may be called at a variety of points in the tick cycle, unlike the other callback types in SLiM, which are each called at a specific point.<span class=\"Apple-converted-space\">  </span>If you write an <span class=\"s1\">interaction()</span> callback, you need to take this into account; assuming that the tick cycle is at a particular stage, or even that the tick or cycle is the same as it was when <span class=\"s1\">evaluate()</span> was called, may be dangerous.</p>\n<p class=\"p2\">When an interaction strength is needed, the first thing SLiM does is calculate the default interaction strength using the interaction function that has been defined for the <span class=\"s1\">InteractionType</span>.<span class=\"Apple-converted-space\">  </span>If the receiver is the same as the exerter, the interaction strength is always zero; and in spatial simulations if the distance between the receiver and the exerter is greater than the maximum distance set for the <span class=\"s1\">InteractionType</span>, the interaction strength is also always zero.<span class=\"Apple-converted-space\">  </span>In these cases, <span class=\"s1\">interaction()</span> callbacks will not be called, and there is no way to redefine these interaction strengths.</p>\n<p class=\"p2\">Otherwise, SLiM will then call <span class=\"s1\">interaction()</span> callbacks that apply to the interaction type and exerter subpopulation for the interaction being evaluated.<span class=\"Apple-converted-space\">  </span>An <span class=\"s1\">interaction()</span> callback is defined with a variation of the syntax used for other callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] interaction(&lt;int-type-id&gt; [, &lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p2\">For example, if the callback were defined as:</p>\n<p class=\"p3\">1000:2000 interaction(i2, p3) { 1.0; }</p>\n<p class=\"p7\">then an interaction strength of <span class=\"s1\">1.0</span> would be used for all interactions of interaction type <span class=\"s1\">i2</span>, for exerters in subpopulation <span class=\"s1\">p3</span>, from tick <span class=\"s1\">1000</span> to tick <span class=\"s1\">2000</span>.</p>\n<p class=\"p2\">Beginning in SLiM 4, the receiver and exerter may be in different subpopulations from each other – or even, in multispecies models, in different species altogether.<span class=\"Apple-converted-space\">  </span>For the subpopulation id in the <span class=\"s1\">interaction()</span> callback declaration, it does not matter which subpopulation the receiver is in; if the exerter is in <span class=\"s1\">p3</span>, for the above example, then the <span class=\"s1\">interaction()</span> callback will be called regardless of the receiver’s subpopulation (assuming other preconditions are also met, such as the tick range and the interaction type id).<span class=\"Apple-converted-space\">  </span>This means that <span class=\"s1\">interaction()</span> callbacks are not species-specific, unlike other callback types; even if an <span class=\"s1\">interaction()</span> callback is declared to be specific to exerters in <span class=\"s1\">p3</span>, as above, receivers can still be in a different species.<span class=\"Apple-converted-space\">  </span>With no subpopulation id specified, <span class=\"s1\">interaction()</span> callbacks are even more general: the <span class=\"s1\">InteractionType</span> can then be evaluated and queried for receivers and exerters belonging to any species.<span class=\"Apple-converted-space\">  </span>For this reason, in multispecies models <span class=\"s1\">interaction()</span> callbacks must be declared using a species specifier of <span class=\"s1\">species all</span>, unlike all other SLiM callback types; it is not legal to declare an <span class=\"s1\">interaction()</span> callback as species-specific.<span class=\"Apple-converted-space\">  </span>Note that there is no way to declare an <span class=\"s1\">interaction()</span> callback as applying only to receivers in a given subpopulation; if that functionality is desired, you can test <span class=\"s1\">receiver.subpopulation</span> in your callback code and act accordingly.</p>\n<p class=\"p2\">In addition to the standard SLiM globals, an <span class=\"s1\">interaction()</span> callback is supplied with some additional information passed through “pseudo-parameters”:</p>\n<p class=\"p8\"><span class=\"s1\">distance</span><span class=\"Apple-tab-span\">\t</span>The distance from receiver to exerter, in spatial simulations; <span class=\"s1\">NAN</span> otherwise</p>\n<p class=\"p8\"><span class=\"s1\">strength</span><span class=\"Apple-tab-span\">\t</span>The default interaction strength calculated by the interaction function</p>\n<p class=\"p8\"><span class=\"s1\">receiver</span><span class=\"Apple-tab-span\">\t</span>The individual receiving the interaction (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p5\"><span class=\"s1\">exerter</span><span class=\"Apple-tab-span\">\t</span>The individual exerting the interaction (an object of class <span class=\"s1\">Individual</span>)</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">interaction()</span> callback to compute an interaction strength.<span class=\"Apple-converted-space\">  </span>To simply use the default interaction strength that SLiM would use if a callback had not been defined for interaction type <span class=\"s1\">i1</span>, for example, you could do this:</p>\n<p class=\"p3\">interaction(i1) {<br>\n<span class=\"Apple-tab-span\">\t</span>return strength;<br>\n}</p>\n<p class=\"p2\">Usually an <span class=\"s1\">interaction()</span> callback will modify that default strength based upon factors such as the genetics of the receiver and/or the exerter, the spatial positions of the two individuals, or some other simulation state.<span class=\"Apple-converted-space\">  </span>Any finite <span class=\"s1\">float</span> value greater than or equal to <span class=\"s1\">0.0</span> may be returned.<span class=\"Apple-converted-space\">  </span>The value returned will be not be cached by SLiM; if the interaction strength between the same two individuals is needed again later, the <span class=\"s1\">interaction()</span> callback will be called again (something to keep in mind if the interaction strength includes a stochastic component).<span class=\"Apple-converted-space\">  </span>Note that the provided <span class=\"s1\">distance</span> and <span class=\"s1\">strength</span> values are based upon the spatial positions of the exerter and receiver when <span class=\"s1\">evaluate()</span> was called, not their current spatial positions, if they have moved since the interaction was evaluated.</p>\n<p class=\"p2\">More than one <span class=\"s1\">interaction()</span> callback may be defined to operate in the same tick.<span class=\"Apple-converted-space\">  </span>As with other callbacks, multiple callbacks will be called in the order in which they were defined in the input file.<span class=\"Apple-converted-space\">  </span>Furthermore, each callback will be given the <span class=\"s1\">strength</span> value returned by the previous callback – so the value of <span class=\"s1\">strength</span> is not necessarily the default value, in fact, but is the result of all previous <span class=\"s1\">interaction()</span> callbacks for the interaction in question.<span class=\"Apple-converted-space\">  </span>In this way, the effects of multiple callbacks can “stack”.</p>\n<p class=\"p2\">The <span class=\"s1\">interaction()</span> callback mechanism is extremely powerful and flexible, allowing any sort of user-defined interactions whatsoever to be queried dynamically using the methods of <span class=\"s1\">InteractionType</span>.<span class=\"Apple-converted-space\">  </span>However, in the general case a simulation may call for the evaluation of the interaction strength between each individual and every other individual, making the computation of the full interaction network an O(<i>N</i><span class=\"s7\"><sup>2</sup></span>) problem.<span class=\"Apple-converted-space\">  </span>Since <span class=\"s1\">interaction()</span> callbacks may be called for each of those <i>N</i><span class=\"s7\"><sup>2</sup></span> interaction evaluations, they can slow down a simulation considerably, so it is recommended that they be used sparingly.<span class=\"Apple-converted-space\">  </span>This is the reason that the various interaction functions of <span class=\"s1\">InteractionType</span> were provided; when an interaction does not depend upon individual state, the intention is to avoid the necessity of an <span class=\"s1\">interaction()</span> callback altogether.<span class=\"Apple-converted-space\">  </span>Furthermore, constraining the number of cases in which interaction strengths need to be calculated – using a short maximum interaction distance, querying the nearest neighbors of the focal individual rather than querying all possible interactions with that individual, and specifying the reciprocality and sex segregation of the <span class=\"s1\">InteractionType</span>, for example – may greatly decrease the computational overhead of interaction evaluation.</p>\n<p class=\"p1\"><i>5.13.8<span class=\"Apple-converted-space\">  </span>ITEM: 9. </i><span class=\"s1\"><i>reproduction()</i></span><i> callbacks</i></p>\n<p class=\"p2\">In WF models (the default model type in SLiM), the SLiM core manages the reproduction of individuals in each tick.<span class=\"Apple-converted-space\">  </span>In nonWF models, however, reproduction is managed by the model script, in <span class=\"s1\">reproduction()</span> callbacks.<span class=\"Apple-converted-space\">  </span>These callbacks may only be defined in nonWF models.</p>\n<p class=\"p2\">A <span class=\"s1\">reproduction()</span> callback is defined with a syntax much like that of other callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] reproduction([&lt;subpop-id&gt; [, &lt;sex&gt;]]) { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">reproduction()</span> callback will be called once for each individual during the tick(s) in which it is active.<span class=\"Apple-converted-space\">  </span>It may optionally be restricted to apply only to individuals in a specified subpopulation, using the <span class=\"s1\">&lt;subpop-id&gt;</span> specifier; this may be a subpopulation specifier such as <span class=\"s1\">p1</span>, or <span class=\"s1\">NULL</span> indicating no restriction.<span class=\"Apple-converted-space\">  </span>It may also optionally be restricted to apply only to individuals of a specified sex (in sexual models), using the <span class=\"s1\">&lt;sex&gt;</span> specifier; this may be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span>, or <span class=\"s1\">NULL</span> indicating no restriction.<span class=\"Apple-converted-space\">  </span>(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">When a <span class=\"s1\">reproduction()</span> callback is called, SLiM’s expectation is that the callback will trigger the reproduction of a focal individual by making method calls to add new offspring individuals.<span class=\"Apple-converted-space\">  </span>Typically the offspring added are the offspring of the focal individual, and typically they are added to the subpopulation to which the focal individual belongs, but neither of these is required; a <span class=\"s1\">reproduction()</span> callback may add offspring generated by any parent(s), to any subpopulation in the focal species.<span class=\"Apple-converted-space\">  </span>The focal individual is provided to the callback (as an <span class=\"s1\">Individual</span> object), as is the subpopulation in which it resides.</p>\n<p class=\"p2\">A common alternative pattern is for a <span class=\"s1\">reproduction()</span> callback to ignore the focal individual and generate all of the offspring for a species for the current tick, from all parents.<span class=\"Apple-converted-space\">  </span>The callback then sets <span class=\"s1\">self.active</span> to <span class=\"s1\">0</span>, preventing itself from being called again in the current tick; this callback design therefore executes once per tick.<span class=\"Apple-converted-space\">  </span>This can be useful if individuals influence each other’s offspring generation (as in a monogamous-mating model, for example); it can also simply be more efficient when producing offspring in bulk.</p>\n<p class=\"p2\">In addition to the usual SLiM globals, then, a <span class=\"s1\">reproduction()</span> callback is supplied with additional information passed through global variables:</p>\n<p class=\"p9\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The focal individual that is expected to reproduce</p>\n<p class=\"p13\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation to which the focal individual belongs</p>\n<p class=\"p2\">At present, the return value from <span class=\"s1\">reproduction()</span> callbacks is not used, and must be <span class=\"s1\">void</span> (i.e., a value may not be returned).<span class=\"Apple-converted-space\">  </span>It is possible that other return values will be defined in future.</p>\n<p class=\"p2\">It is possible, of course, to do actions unrelated to reproduction inside <span class=\"s1\">reproduction()</span> callbacks, but it is not recommended.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">first()</span> event phase of the current tick provides an opportunity for actions immediately before reproduction, and the <span class=\"s1\">early()</span> event phase of the current tick provides an opportunity for actions immediately after reproduction, so only actions that are intertwined with reproduction itself should occur in <span class=\"s1\">reproduction()</span> callbacks.<span class=\"Apple-converted-space\">  </span>Besides providing conceptual clarity, following this design principle will also decrease the probability of bugs, since actions that are unrelated to reproduction should usually not influence or be influenced by the dynamics of reproduction.</p>\n<p class=\"p2\">If the <span class=\"s1\">randomizeCallbacks</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span> is <span class=\"s1\">T</span> (the default), the order in which individuals are given an opportunity to reproduce with a call to <span class=\"s1\">reproduction()</span> callbacks will be randomized within each subpopulation.<span class=\"Apple-converted-space\">  </span>This partially mitigates order-dependency issues, although such issues can still arise whenever the effects of a <span class=\"s1\">reproduction()</span> callback are not independent.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeCallbacks</span> is <span class=\"s1\">F</span>, individuals will be given their opportunity to reproduce in sequential order within each subpopulation, greatly increasing the risk of order-dependency problems.</p>\n<p class=\"p2\">As with the other callback types, multiple <span class=\"s1\">reproduction()</span> callbacks may be registered and active.<span class=\"Apple-converted-space\">  </span>In this case, all registered and active callbacks will be called for each individual, in the order that the callbacks were registered.</p>\n<p class=\"p1\"><i>5.13.9<span class=\"Apple-converted-space\">  </span>ITEM: 10. </i><span class=\"s1\"><i>mutation()</i></span><i> callbacks</i></p>\n<p class=\"p2\">SLiM auto-generates new mutations according to the current mutation rate (or rate map) and the genetic structure defined by genomic elements, their genomic element types, the mutation types those genomic element types draw from, and the distribution of fitness effects defined by those mutation types.<span class=\"Apple-converted-space\">  </span>In nucleotide-based models, the nucleotide sequence and the mutation matrix also play a role in determining both the rate of mutation and the nucleotide mutated to.<span class=\"Apple-converted-space\">  </span>In some models it can be desirable to modify these dynamics in some way – altering the selection coefficients of new mutations in some way, changing the mutation type used, dictating the nucleotide to be used, replacing the proposed mutation with a pre-existing mutation at the same position, or even suppressing the proposed mutation altogether.<span class=\"Apple-converted-space\">  </span>To achieve this, one may define a <span class=\"s1\">mutation()</span> callback.</p>\n<p class=\"p2\">A <span class=\"s1\">mutation()</span> callback is defined as:</p>\n<p class=\"p3\">[id] [t1 [: t2]] mutation([&lt;mut-type-id&gt; [, &lt;subpop-id&gt;]]) { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">mutation()</span> callback will be called once for each new auto-generated mutation during the tick(s) in which the callback is active.<span class=\"Apple-converted-space\">  </span>It may optionally be restricted to apply only to mutations of a particular mutation type, using the <span class=\"s1\">&lt;mut-type-id&gt;</span> specifier; this may be a mutation type specifier such as <span class=\"s1\">m1</span>, or <span class=\"s1\">NULL</span> indicating no restriction.<span class=\"Apple-converted-space\">  </span>It may also optionally be restricted to individuals generated by a specified subpopulation (usually – see below for discussion), using the <span class=\"s1\">&lt;subpop-id&gt;</span> specifier; this should be a subpopulation specifier such as <span class=\"s1\">p1</span>.<span class=\"Apple-converted-space\">  </span>(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">When a <span class=\"s1\">mutation()</span> callback is called, a focal mutation (provided to the callback as an object of type <span class=\"s1\">Mutation</span>) has just been created by SLiM, referencing a particular position in a parental haplosome (also provided, as an object of type <span class=\"s1\">Haplosome</span>).<span class=\"Apple-converted-space\">  </span>The mutation will not be added to that parental haplosome; rather, the parental haplosome is being copied, during reproduction, to make a gamete or an offspring haplosome, and the mutation is, conceptually, a copying error made during that process.<span class=\"Apple-converted-space\">  </span>It will be added to the offspring haplosome that is the end result of the copying process (which may also involve recombination with another haplosome).<span class=\"Apple-converted-space\">  </span>At the point that the <span class=\"s1\">mutation()</span> callback is called, the offspring haplosome is not yet created, however, and so it cannot be accessed from within the <span class=\"s1\">mutation()</span> callback; the <span class=\"s1\">mutation()</span> callback can affect only the mutation itself, not the haplosome to which the mutation will be added.</p>\n<p class=\"p2\">In addition to the standard SLiM globals, then, a <span class=\"s1\">mutation()</span> callback is supplied with additional information passed through global variables:</p>\n<p class=\"p9\"><span class=\"s1\">mut</span><span class=\"Apple-tab-span\">\t</span>The focal mutation that is being modified or reviewed</p>\n<p class=\"p9\"><span class=\"s1\">haplosome</span><span class=\"Apple-tab-span\">\t</span>The parental haplosome that is being copied</p>\n<p class=\"p9\"><span class=\"s1\">element</span><span class=\"Apple-tab-span\">\t</span>The genomic element that controls the mutation site</p>\n<p class=\"p9\"><span class=\"s1\">originalNuc</span><span class=\"Apple-tab-span\">\t</span>The nucleotide (<span class=\"s1\">0</span>/<span class=\"s1\">1</span>/<span class=\"s1\">2</span>/<span class=\"s1\">3</span> for <span class=\"s1\">A</span>/<span class=\"s1\">C</span>/<span class=\"s1\">G</span>/<span class=\"s1\">T</span>) originally at the mutating position</p>\n<p class=\"p9\"><span class=\"s1\">parent</span><span class=\"Apple-tab-span\">\t</span>The parent which is generating the offspring haplosome</p>\n<p class=\"p13\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation to which the parent belongs</p>\n<p class=\"p2\">The <span class=\"s1\">mutation()</span> callback has three possible returns: <span class=\"s1\">T</span>, <span class=\"s1\">F</span>, or (beginning in SLiM 3.5) a singleton object of type <span class=\"s1\">Mutation</span>.<span class=\"Apple-converted-space\">  </span>A return of <span class=\"s1\">T</span> indicates that the proposed mutation should be used in generating the offspring haplosome (perhaps with modifications made by the callback).<span class=\"Apple-converted-space\">  </span>Conversely, a return of <span class=\"s1\">F</span> indicates that the proposed mutation should be suppressed.<span class=\"Apple-converted-space\">  </span>If a proposed mutation is suppressed, SLiM will not try again; one fewer mutations will be generated during reproduction than would otherwise have been true.<span class=\"Apple-converted-space\">  </span>Returning <span class=\"s1\">F</span> will therefore mean that the realized mutation rate in the model will be lower than the expected mutation rate.<span class=\"Apple-converted-space\">  </span>Finally, a return of an object of type <span class=\"s1\">Mutation</span> replaces the proposed mutation (<span class=\"s1\">mut</span>) with the mutation returned; the offspring haplosomes being generated will contain the returned mutation.<span class=\"Apple-converted-space\">  </span>The position of the returned mutation must match that of the proposed mutation.<span class=\"Apple-converted-space\">  </span>This provides a mechanism for a <span class=\"s1\">mutation()</span> callback to make SLiM re-use existing mutations instead of generating new mutations, which can be useful.</p>\n<p class=\"p2\">The callback may perform a variety of actions related to the generated mutation.<span class=\"Apple-converted-space\">  </span>The selection coefficient of the mutation can be changed with <span class=\"s1\">setSelectionCoefficient()</span>, and the mutation type of the mutation can be changed with <span class=\"s1\">setMutationType()</span>; the <span class=\"s1\">drawSelectionCoefficient()</span> method of <span class=\"s1\">MutationType</span> may also be useful here.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">tag</span> property value may be set for the mutation, and named values may be attached to the mutation with <span class=\"s1\">setValue()</span>.<span class=\"Apple-converted-space\">  </span>In nucleotide-based models, the <span class=\"s1\">nucleotide</span> (or <span class=\"s1\">nucleotideValue</span>) property of the mutation may also be changed; note that the original nucleotide at the focal position in the parental haplosome is provided through <span class=\"s1\">originalNuc</span> (it could be retrieved with <span class=\"s1\">haplosome.nucleotides()</span>, but SLiM already has it at hand anyway).<span class=\"Apple-converted-space\">  </span>All of these modifications to the new mutation may be based upon the state of the parent, including its genetic state, or upon any other model state.</p>\n<p class=\"p2\">It is possible, of course, to do actions unrelated to mutation inside <span class=\"s1\">mutation()</span> callbacks, but it is not recommended; <span class=\"s1\">first()</span>, <span class=\"s1\">early()</span>, and <span class=\"s1\">late()</span> events should be used for general-purpose scripting.<span class=\"Apple-converted-space\">  </span>Besides providing conceptual clarity, following this design principle will also decrease the probability of bugs, since actions that are unrelated to mutation should not influence or be influenced by the dynamics of mutation.</p>\n<p class=\"p2\">The proposed mutation will not appear in the <span class=\"s1\">sim.mutations</span> vector of segregating mutations until it has been added to a haplosome; it will therefore not be visible in that vector within its own <span class=\"s1\">mutation()</span> callback invocation, and indeed, may not be visible in subsequent callbacks during the reproduction tick cycle stage until such time as the offspring individual being generated has been completed.<span class=\"Apple-converted-space\">  </span>If that offspring is ultimately rejected, in particular by a <span class=\"s1\">modifyChild()</span> callback, the proposed mutation may not be used by SLiM at all.<span class=\"Apple-converted-space\">  </span>It may therefore be unwise to assume, in a <span class=\"s1\">mutation()</span> callback, that the focal mutation will ultimately be added to the simulation, depending upon the rest of the model’s script.</p>\n<p class=\"p2\">There is one subtlety to be mentioned here, having to do with subpopulations.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpop</span> pseudo-parameter discussed above is always the subpopulation of the parent which possesses the haplosome that is being copied and is mutating; there is no ambiguity about that whatsoever.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">&lt;subpop-id&gt;</span> specified in the <span class=\"s1\">mutation()</span> callback declaration, however, is a bit more subtle; above it was said that it restricts the callback “to individuals generated by a specified subpopulation”, and that is usually true but requires some explanation.<span class=\"Apple-converted-space\">  </span>In WF models, recall that migrants are generated in a source subpopulation and placed in a target subpopulation, as a model of juvenile migration; in that context, the <span class=\"s1\">&lt;subpop-id&gt;</span> specifies the <i>source</i> subpopulation to which the <span class=\"s1\">mutation()</span> callback will be restricted.<span class=\"Apple-converted-space\">  </span>In nonWF models, offspring are generated by the <span class=\"s1\">add...()</span> family of <span class=\"s1\">Subpopulation</span> methods, which can cross individuals from two different subpopulations and place the result in a third target subpopulation; in that context, in general, the <span class=\"s1\">&lt;subpop-id&gt;</span> specifies the source subpopulation that is generating the particular <i>gamete</i> that is sustaining a mutation during its production.<span class=\"Apple-converted-space\">  </span>The exception to this rule is <span class=\"s1\">addRecombinant()</span> and <span class=\"s1\">addMultiRecombinant()</span>; since there are four different source subpopulations potentially in play there per mutation, it was deemed simpler in that case for the <span class=\"s1\">&lt;subpop-id&gt;</span> to specify the <i>target</i> subpopulation to which the <span class=\"s1\">mutation()</span> callback will be restricted.<span class=\"Apple-converted-space\">  </span>If restriction to the source subpopulation is needed with <span class=\"s1\">addRecombinant()</span> or <span class=\"s1\">addMultiRecombinant()</span>, the <span class=\"s1\">subpop</span> pseudo-parameter may be consulted rather than using <span class=\"s1\">&lt;subpop-id&gt;</span>.</p>\n<p class=\"p2\">Note that <span class=\"s1\">mutation()</span> callbacks are only called for mutations that are auto-generated by SLiM, as a consequence of the mutation rate and the genetic structure defined.<span class=\"Apple-converted-space\">  </span>Mutations that are created in script, using <span class=\"s1\">addNewMutation()</span> or <span class=\"s1\">addNewDrawnMutation()</span>, will not trigger <span class=\"s1\">mutation()</span> callbacks; but of course the script may modify or tailor such added mutations in whatever way is desired, so there is no need for callbacks in that situation.</p>\n<p class=\"p2\">As with the other callback types, multiple <span class=\"s1\">mutation()</span> callbacks may be registered and active.<span class=\"Apple-converted-space\">  </span>In this case, all registered and active callbacks will be called for each generated mutation to which they apply, in the order that the callbacks were registered.</p>\n<p class=\"p1\"><i>5.13.10<span class=\"Apple-converted-space\">  </span>ITEM: 11. </i><span class=\"s1\"><i>survival()</i></span><i> callbacks</i></p>\n<p class=\"p2\">In nonWF models, a selection phase in the tick cycle results in mortality; individuals survive or die based upon their fitness.<span class=\"Apple-converted-space\">  </span>In most cases this standard behavior is sufficient; but occasionally it can be useful to observe the survival decisions SLiM makes (to log out information about dying individuals, for example), to modify those decisions (influencing which individuals live and which die, perhaps based upon factors other than genetics), or even to short-circuit mortality completely (moving dead individuals into a “cold storage” subpopulation for later use, perhaps).<span class=\"Apple-converted-space\">  </span>To accomplish such goals, one can the <span class=\"s1\">survival()</span> callback mechanism to override SLiM’s default behavior.<span class=\"Apple-converted-space\">  </span>Note that in WF models, since they always model non-overlapping generations, the entire parental generation dies in each tick regardless of fitness; <span class=\"s1\">survival()</span> callbacks therefore apply only to nonWF models.</p>\n<p class=\"p2\">A <span class=\"s1\">survival()</span> callback is defined with a syntax much like that of other callbacks:</p>\n<p class=\"p3\">[id] [t1 [: t2]] survival([&lt;subpop-id&gt;]) { ... }</p>\n<p class=\"p2\">The <span class=\"s1\">survival()</span> callback will be called during the selection phase of the tick cycle of nonWF models, during the tick(s) in which it is active.<span class=\"Apple-converted-space\">  </span>By default it will be called once per individual in the entire population (whether slated for survival or not); it may optionally be restricted to apply only to individuals in a specified subpopulation, using the <span class=\"s1\">&lt;subpop-id&gt;</span> specifier.<span class=\"Apple-converted-space\">  </span>(In multispecies models, the definition must be preceded by a <span class=\"s1\">species</span> specification as usual.)</p>\n<p class=\"p2\">When a <span class=\"s1\">survival()</span> callback is called, a focal individual has already been evaluated by SLiM regarding its survival; a final fitness value for the individual has been calculated, and a random uniform draw in <span class=\"s1\">[0,1]</span> has been generated that determines whether the individual is to survive (a draw less than the individual’s fitness) or die (a draw greater than or equal to the individual’s fitness).<span class=\"Apple-converted-space\">  </span>The focal individual is provided to the callback, as is the subpopulation in which it resides.<span class=\"Apple-converted-space\">  </span>Furthermore, the preliminary decision (whether the focal individual will survive or not), the focal individual’s fitness, and the random draw made by SLiM to determine survival are also provided to the callback.<span class=\"Apple-converted-space\">  </span>The callback may return <span class=\"s1\">NULL</span> to accept SLiM’s decision, or may return <span class=\"s1\">T</span> to indicate that the individual should survive, or <span class=\"s1\">F</span> to indicate that it should die, regardless of its fitness and the random deviate drawn.<span class=\"Apple-converted-space\">  </span>The callback may also return a singleton <span class=\"s1\">Subpopulation</span> object to indicate the individual should remain alive but should be moved to that subpopulation (note that calling <span class=\"s1\">takeMigrants()</span> during the survival phase is illegal, because SLiM is busy modifying the population’s internal state).</p>\n<p class=\"p2\">In addition to the standard SLiM globals, then, a <span class=\"s1\">survival()</span> callback is supplied with additional information passed through “pseudo-parameters”:</p>\n<p class=\"p9\"><span class=\"s1\">individual</span><span class=\"Apple-tab-span\">\t</span>The focal individual that will live or die</p>\n<p class=\"p9\"><span class=\"s1\">subpop</span><span class=\"Apple-tab-span\">\t</span>The subpopulation to which the focal individual belongs</p>\n<p class=\"p9\"><span class=\"s1\">surviving</span><span class=\"Apple-tab-span\">\t</span>A <span class=\"s1\">logical</span> value indicating SLiM’s preliminary decision (<span class=\"s1\">T</span> == survival)</p>\n<p class=\"p9\"><span class=\"s1\">fitness</span><span class=\"Apple-tab-span\">\t</span>The focal individual’s fitness</p>\n<p class=\"p13\"><span class=\"s1\">draw</span><span class=\"Apple-tab-span\">\t</span>SLiM’s random uniform deviate, which determined the preliminary decision</p>\n<p class=\"p2\">These may be used in the <span class=\"s1\">survival()</span> callback to determine the final decision.</p>\n<p class=\"p2\">While <span class=\"s1\">survival()</span> callbacks are still being called, no decisions are put into effect; no individuals actually die, and none are moved to a new <span class=\"s1\">Subpopulation</span> if that was requested.<span class=\"Apple-converted-space\">  </span>In effect, SLiM pre-plans the fate of every individual completely without modifying the model state at all.<span class=\"Apple-converted-space\">  </span>After all <span class=\"s1\">survival()</span> callbacks have completed for every individual, the planned fates for every individual will then be executed, without any opportunity for further intervention through callbacks.<span class=\"Apple-converted-space\">  </span>It is therefore legal to inspect subpopulations and individuals inside a <span class=\"s1\">survival()</span> callback, but it should be understood that previously made decisions about the fates of other individuals will not yet have any visible effect.<span class=\"Apple-converted-space\">  </span>It is generally a good idea for the decisions rendered by <span class=\"s1\">survival()</span> callbacks to be independent anyway, to avoid biases due to order-dependency.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">randomizeCallbacks</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span> is <span class=\"s1\">T</span> (the default), the order in which <span class=\"s1\">survival()</span> callbacks are called on individuals will be randomized within each subpopulation; nevertheless, order-dependency issues can occur if callback effects are not independent.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeCallbacks</span> is <span class=\"s1\">F</span>, the order in which individuals are evaluated within each subpopulation is not guaranteed to be random, and order-dependency problems are thus even more likely.</p>\n<p class=\"p2\">It is worth noting that if <span class=\"s1\">survival()</span> callbacks are used, “fitness” in the model is then no longer really fitness; the model is making its own decisions about which individuals live and die, and those decisions are the true determinant of fitness in the biological sense.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">survival()</span> callback that makes its own decisions regarding survival with no regard for SLiM’s calculated fitness values can completely alter the pattern of selection in a population, rendering all of SLiM’s fitness machinery – selection and dominance coefficients, <span class=\"s1\">fitnessScaling</span> values, etc. – completely irrelevant.<span class=\"Apple-converted-space\">  </span>To avoid highly counterintuitive and confusing effects, it is thus generally a good idea to use of <span class=\"s1\">survival()</span> callbacks only when it is strictly necessary to achieve a desired outcome.</p>\n<p class=\"p2\">As with the other callback types, multiple <span class=\"s1\">survival()</span> callbacks may be registered and active.<span class=\"Apple-converted-space\">  </span>In this case, all registered and active callbacks will be called for each individual evaluated, in the order that the callbacks were registered.</p>\n<p class=\"p14\"><span class=\"s8\"></span><br></p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/SLiMHelpClasses.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"2487.7\">\n  <style type=\"text/css\">\n    p.p1 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p3 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo}\n    p.p4 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima}\n    p.p5 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo; color: #000000}\n    p.p6 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #000000}\n    p.p7 {margin: 0.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #000000}\n    p.p8 {margin: 0.0px 0.0px 9.0px 27.4px; font: 9.0px Menlo; color: #000000}\n    p.p9 {margin: 6.0px 0.0px 3.0px 0.0px; font: 9.0px Menlo}\n    p.p10 {margin: 3.0px 0.0px 3.0px 27.4px; font: 9.0px Menlo; color: #000000}\n    p.p11 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima; color: #000000}\n    p.p12 {margin: 6.0px 0.0px 3.0px 0.0px; font: 11.0px Optima; color: #000000}\n    p.p13 {margin: 3.0px 0.0px 3.0px 27.4px; font: 11.0px Optima}\n    p.p14 {margin: 3.0px 0.0px 3.0px 27.4px; font: 11.0px Optima; color: #000000}\n    p.p15 {margin: 2.0px 0.0px 2.0px 0.0px; text-indent: 13.7px; font: 11.0px 'Times New Roman'; min-height: 12.0px}\n    p.p16 {margin: 3.0px 0.0px 3.0px 27.4px; font: 9.0px Menlo}\n    span.s1 {font: 9.0px Menlo}\n    span.s2 {font: 10.0px 'Times New Roman'}\n    span.s3 {font-kerning: none}\n    span.s4 {font: 9.0px Menlo; font-kerning: none}\n    span.s5 {color: #000000}\n    span.s6 {font: 9.0px Menlo; color: #000000}\n    span.s7 {font-kerning: none; color: #000000}\n    span.s8 {font: 9.0px Menlo; font-kerning: none; color: #000000}\n    span.s9 {font: 9.0px 'Times New Roman'}\n    span.s10 {font: 11.0px Optima}\n    span.s11 {font: 10.0px Optima}\n    span.s12 {text-decoration: underline ; color: #0000ff}\n    span.s13 {font: 6.7px 'Times New Roman'}\n    span.s14 {font: 10.0px 'Lucida Grande'}\n    span.s15 {font: 10.0px 'Times New Roman'; color: #000000}\n    span.s16 {font: 11.0px 'Times New Roman'}\n    span.s17 {font: 11.0px Helvetica}\n    span.s18 {font: 6.7px Optima}\n    span.s19 {font: 10.0px Optima; color: #000000}\n    span.s20 {font: 6.7px Optima; font-kerning: none}\n    span.Apple-tab-span {white-space:pre}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><b>5.2<span class=\"Apple-converted-space\">  </span>Class Chromosome</b></p>\n<p class=\"p2\"><i>5.2.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Chromosome</i></span><i> properties</i></p>\n<p class=\"p3\">colorSubstitution &lt;–&gt; (string$)</p>\n<p class=\"p4\">The color used to display substitutions in SLiMgui when both mutations and substitutions are being displayed in the chromosome view.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">colorSubstitution</span> is the empty string, <span class=\"s1\">\"\"</span>, SLiMgui will defer to the color scheme of each <span class=\"s1\">MutationType</span>, just as it does when only substitutions are being displayed.<span class=\"Apple-converted-space\">  </span>The default, <span class=\"s1\">\"3333FF\"</span>, causes all substitutions to be shown as dark blue when displayed in conjunction with mutations, to prevent the view from becoming too noisy.<span class=\"Apple-converted-space\">  </span>Note that when substitutions are displayed without mutations also being displayed, this value is ignored by SLiMgui and the substitutions use the color scheme of each <span class=\"s1\">MutationType</span><span class=\"s2\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">geneConversionEnabled =&gt; (logical$)</span></p>\n<p class=\"p6\"><span class=\"s3\">When gene conversion has been enabled by calling </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\">, switching to the DSB recombination model, this property is </span><span class=\"s4\">T</span><span class=\"s3\">; otherwise, when using the crossover breakpoints model, it is </span><span class=\"s4\">F</span><span class=\"s3\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">geneConversionGCBias =&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The gene conversion bias coefficient, which expresses a bias in the resolution of heteroduplex mismatches in complex gene conversion tracts.<span class=\"Apple-converted-space\">  </span>When gene conversion has not been enabled by calling </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\">, this property will be unavailable.</span></p>\n<p class=\"p5\"><span class=\"s3\">geneConversionNonCrossoverFraction =&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The fraction of double-stranded breaks that result in non-crossover events.<span class=\"Apple-converted-space\">  </span>When gene conversion has not been enabled by calling </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\">, this property will be unavailable.</span></p>\n<p class=\"p5\"><span class=\"s3\">geneConversionMeanLength =&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The mean length of a gene conversion tract (in base positions).<span class=\"Apple-converted-space\">  </span>When gene conversion has not been enabled by calling </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\">, this property will be unavailable.</span></p>\n<p class=\"p5\"><span class=\"s3\">geneConversionSimpleConversionFraction =&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The fraction of gene conversion tracts that are “simple” (i.e., not involving resolution of heteroduplex mismatches); the remainder will be “complex”.<span class=\"Apple-converted-space\">  </span>When gene conversion has not been enabled by calling </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\">, this property will be unavailable.</span></p>\n<p class=\"p3\">genomicElements =&gt; (object&lt;GenomicElement&gt;)</p>\n<p class=\"p6\"><span class=\"s5\">All of the </span><span class=\"s6\">GenomicElement</span><span class=\"s5\"> objects that comprise the chromosome</span>, in sorted order (not necessarily in the order in which they were defined).</p>\n<p class=\"p5\"><span class=\"s3\">hotspotEndPositions =&gt; (integer)</span></p>\n<p class=\"p6\"><span class=\"s3\">The end positions for hotspot map regions along the chromosome.<span class=\"Apple-converted-space\">  </span>Each hotspot map region is assumed to start at the position following the end of the previous hotspot map region; in other words, the regions are assumed to be contiguous.<span class=\"Apple-converted-space\">  </span>When using sex-specific hotspot maps, this property will unavailable; see </span><span class=\"s4\">hotspotEndPositionsF</span><span class=\"s3\"> and </span><span class=\"s4\">hotspotEndPositionsM</span><span class=\"s3\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">hotspotEndPositionsF =&gt; (integer)</span></p>\n<p class=\"p6\"><span class=\"s3\">The end positions for hotspot map regions for females, when using sex-specific hotspot maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">hotspotEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p5\"><span class=\"s3\">hotspotEndPositionsM =&gt; (integer)</span></p>\n<p class=\"p6\"><span class=\"s3\">The end positions for hotspot map regions for males, when using sex-specific hotspot maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">hotspotEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p5\"><span class=\"s3\">hotspotMultipliers =&gt; (float)</span></p>\n<p class=\"p6\"><span class=\"s3\">The hotspot multiplier for each of the hotspot map regions specified by </span><span class=\"s4\">hotspotEndPositions</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>When using sex-specific hotspot maps, this property will be unavailable; see </span><span class=\"s4\">hotspotMultipliersF</span><span class=\"s3\"> and </span><span class=\"s4\">hotspotMultipliersM</span><span class=\"s3\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">hotspotMultipliersF =&gt; (float)</span></p>\n<p class=\"p6\"><span class=\"s3\">The hotspot multiplier for each of the hotspot map regions specified by </span><span class=\"s4\">hotspotEndPositionsF</span><span class=\"s3\">, when using sex-specific hotspot maps; unavailable otherwise.</span></p>\n<p class=\"p5\"><span class=\"s3\">hotspotMultipliersM =&gt; (float)</span></p>\n<p class=\"p6\"><span class=\"s3\">The hotspot multiplier for each of the hotspot map regions specified by </span><span class=\"s4\">hotspotEndPositionsM</span><span class=\"s3\">, when using sex-specific hotspot maps; unavailable otherwise.</span></p>\n<p class=\"p5\">id =&gt; (integer$)</p>\n<p class=\"p6\">The id for the chromosome, as given to <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>For an implicitly defined chromosome, the <span class=\"s1\">id</span> will be <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">id</span> can be used to refer to the chromosome; see also <span class=\"s1\">symbol</span>.</p>\n<p class=\"p5\">intrinsicPloidy =&gt; (integer$)</p>\n<p class=\"p6\">The intrinsic ploidy of the chromosome, meaning the number of haplosome objects that are allocated in each individual, associated with the chromosome (even if some of those haplosomes are null haplosomes acting as placeholders).<span class=\"Apple-converted-space\">  </span>This is a consequence of the chromosome’s type.<span class=\"Apple-converted-space\">  </span>Chromosome types <span class=\"s1\">\"A\"</span>, <span class=\"s1\">\"X\"</span>, and <span class=\"s1\">\"Z\"</span> are intrinsically diploid (and thus this property would have the value <span class=\"s1\">2</span>), as are the backwards-compatibility chromosome types <span class=\"s1\">\"H-\"</span> and <span class=\"s1\">\"-Y\"</span>.<span class=\"Apple-converted-space\">  </span>All other chromosome types are intrinsically haploid (and thus this property would have the value <span class=\"s1\">1</span>).</p>\n<p class=\"p5\">isSexChromosome =&gt; (logical$)</p>\n<p class=\"p6\">Indicates whether the chromosome is a sex chromosome (T) or not (F).<span class=\"Apple-converted-space\">  </span>This is a consequence of the chromosome’s type.<span class=\"Apple-converted-space\">  </span>Chromosome types <span class=\"s1\">\"X\"</span>, <span class=\"s1\">\"Y\"</span>, <span class=\"s1\">\"Z\"</span>, and <span class=\"s1\">\"W\"</span> are considered sex chromosomes, as is the backwards-compatibility type <span class=\"s1\">\"-Y\"</span>; all other chromosome types are not.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">sexChromosomes</span> property of <span class=\"s1\">Species</span>.</p>\n<p class=\"p5\">lastPosition =&gt; (integer$)</p>\n<p class=\"p6\">The last valid position in the chromosome; equal to <span class=\"s1\">length-1</span>, where <span class=\"s1\">length</span> is the length as given to <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>For an implicitly defined chromosome, the chromosome’s last position is determined by the <i>maximum</i> of the end of the last genomic element, the end of the last recombination region, and the end of the last mutation map region (or hotspot map region).<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">length</span>.</p>\n<p class=\"p5\">length =&gt; (integer$)</p>\n<p class=\"p6\">The length of the chromosome (meaning the number of valid base positions it contains), as given to <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>The length is simply equal to the last position plus <span class=\"s1\">1</span>, since the chromosome always starts at <span class=\"s1\">0</span>.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">lastPosition</span>.</p>\n<p class=\"p3\">mutationEndPositions =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for mutation rate regions along the chromosome.<span class=\"Apple-converted-space\">  </span>Each mutation rate region is assumed to start at the position following the end of the previous mutation rate region; in other words, the regions are assumed to be contiguous.<span class=\"Apple-converted-space\">  </span>When using sex-specific mutation rate maps, this property will unavailable; see </span><span class=\"s4\">mutationEndPositionsF</span><span class=\"s3\"> and </span><span class=\"s4\">mutationEndPositionsM</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">mutationEndPositionsF =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for mutation rate regions for females, when using sex-specific mutation rate maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">mutationEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">mutationEndPositionsM =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for mutation rate regions for males, when using sex-specific mutation rate maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">mutationEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">mutationRates =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The mutation rate for each of the mutation rate regions specified by </span><span class=\"s4\">mutationEndPositions</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>When using sex-specific mutation rate maps, this property will be unavailable; see </span><span class=\"s4\">mutationRatesF</span><span class=\"s3\"> and </span><span class=\"s4\">mutationRatesM</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">mutationRatesF =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The mutation rate for each of the mutation rate regions specified by </span><span class=\"s4\">mutationEndPositionsF</span><span class=\"s3\">, when using sex-specific mutation rate maps; unavailable otherwise.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">mutationRatesM =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The mutation rate for each of the mutation rate regions specified by </span><span class=\"s4\">mutationEndPositionsM</span><span class=\"s3\">, when using sex-specific mutation rate maps; unavailable otherwise.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p5\">name &lt;–&gt; (string$)</p>\n<p class=\"p6\">The name of the chromosome, as given to <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>The chromosome name is not used by SLiM, and may be whatever you wish.</p>\n<p class=\"p3\">overallMutationRate =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall mutation rate across the whole chromosome determining the overall number of mutation events that will occur anywhere in the chromosome, as calculated from the individual mutation ranges and rates as well as the coverage of the chromosome by genomic elements (since mutations are only generated within genomic elements, regardless of the mutation rate map).<span class=\"Apple-converted-space\">  </span>When using sex-specific mutation rate maps, this property will unavailable; see </span><span class=\"s4\">overallMutationRateF</span><span class=\"s3\"> and </span><span class=\"s4\">overallMutationRateM</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">overallMutationRateF =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall mutation rate for females, when using sex-specific mutation rate maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">overallMutationRate</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">overallMutationRateM =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall mutation rate for males, when using sex-specific mutation rate maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">overallMutationRate</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p6\"><span class=\"s3\">This property is unavailable in nucleotide-based models.</span></p>\n<p class=\"p3\">overallRecombinationRate =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall recombination rate across the whole chromosome determining the overall number of recombination events that will occur anywhere in the chromosome, as calculated from the individual recombination ranges and rates.<span class=\"Apple-converted-space\">  </span>When using sex-specific recombination maps, this property will unavailable; see </span><span class=\"s4\">overallRecombinationRateF</span><span class=\"s3\"> and </span><span class=\"s4\">overallRecombinationRateM</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">overallRecombinationRateF =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall recombination rate for females, when using sex-specific recombination maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">overallRecombinationRate</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p3\">overallRecombinationRateM =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s3\">The overall recombination rate for males, when using sex-specific recombination maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">overallRecombinationRate</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p3\">recombinationEndPositions =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for recombination regions along the chromosome.<span class=\"Apple-converted-space\">  </span>Each recombination region is assumed to start at the position following the end of the previous recombination region; in other words, the regions are assumed to be contiguous.<span class=\"Apple-converted-space\">  </span>When using sex-specific recombination maps, this property will unavailable; see </span><span class=\"s4\">recombinationEndPositionsF</span><span class=\"s3\"> and </span><span class=\"s4\">recombinationEndPositionsM</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">recombinationEndPositionsF =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for recombination regions for females, when using sex-specific recombination maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">recombinationEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p3\">recombinationEndPositionsM =&gt; (integer)</p>\n<p class=\"p6\"><span class=\"s3\">The end positions for recombination regions for males, when using sex-specific recombination maps; unavailable otherwise.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">recombinationEndPositions</span><span class=\"s3\"> for further explanation.</span></p>\n<p class=\"p3\">recombinationRates =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The recombination rate for each of the recombination regions specified by </span><span class=\"s4\">recombinationEndPositions</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>When using sex-specific recombination maps, this property will unavailable; see </span><span class=\"s4\">recombinationRatesF</span><span class=\"s3\"> and </span><span class=\"s4\">recombinationRatesM</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">recombinationRatesF =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The recombination rate for each of the recombination regions specified by </span><span class=\"s4\">recombinationEndPositionsF</span><span class=\"s3\">, when using sex-specific recombination maps; unavailable otherwise.</span></p>\n<p class=\"p3\">recombinationRatesM =&gt; (float)</p>\n<p class=\"p6\"><span class=\"s3\">The recombination rate for each of the recombination regions specified by </span><span class=\"s4\">recombinationEndPositionsM</span><span class=\"s3\">, when using sex-specific recombination maps; unavailable otherwise.</span></p>\n<p class=\"p3\">species =&gt; (object&lt;Species&gt;$)</p>\n<p class=\"p6\"><span class=\"s3\">The species to which the target object belongs.</span></p>\n<p class=\"p5\">symbol =&gt; (string$)</p>\n<p class=\"p6\">The symbol for the chromosome, as given to <span class=\"s1\">initializeChromosome()</span>; see the documentation for that function.<span class=\"Apple-converted-space\">  </span>For an implicitly defined chromosome, the symbol is <span class=\"s1\">\"A\"</span> for non-sexual models, and for sexual models (for historical reasons) is determined by the model type passed to <span class=\"s1\">initializeSex()</span> as documented there.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">symbol</span> can be used to refer to the chromosome; see also <span class=\"s1\">id</span>.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p5\">type =&gt; (string$)</p>\n<p class=\"p6\">The type of the chromosome, as given to <span class=\"s1\">initializeChromosome()</span>; see the documentation for that function for a list of the supported chromosome types.<span class=\"Apple-converted-space\">  </span>For an implicitly defined chromosome, the type is <span class=\"s1\">\"A\"</span> for non-sexual models, and for sexual models (for historical reasons) is determined by the model type passed to <span class=\"s1\">initializeSex()</span> as documented there.</p>\n<p class=\"p2\"><i>5.2.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Chromosome</i></span><i> methods</i></p>\n<p class=\"p5\"><span class=\"s3\">– (is)ancestralNucleotides([Ni$ start = NULL], [Ni$ end = NULL], [string$ format = \"string\"])</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns the ancestral nucleotide sequence originally supplied to </span><span class=\"s4\">initializeAncestralNucleotides()</span><span class=\"s3\">, including any sequence changes due to nucleotide mutations that have fixed and substituted.<span class=\"Apple-converted-space\">  </span>This nucleotide sequence is the reference sequence for positions in a haplosome that do not contain a nucleotide-based mutation.<span class=\"Apple-converted-space\">  </span>The range of the returned sequence may be constrained by a start position given in </span><span class=\"s4\">start</span><span class=\"s3\"> and/or an end position given in </span><span class=\"s4\">end</span><span class=\"s3\">; nucleotides will be returned from </span><span class=\"s4\">start</span><span class=\"s3\"> to </span><span class=\"s4\">end</span><span class=\"s3\">, inclusive.<span class=\"Apple-converted-space\">  </span>The default value of </span><span class=\"s4\">NULL</span><span class=\"s3\"> for </span><span class=\"s4\">start</span><span class=\"s3\"> and </span><span class=\"s4\">end</span><span class=\"s3\"> represent the first and last base positions of the chromosome, respectively.</span></p>\n<p class=\"p6\"><span class=\"s3\">The format of the returned sequence is controlled by the </span><span class=\"s4\">format</span><span class=\"s3\"> parameter.<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"string\"</span><span class=\"s3\"> will return the sequence as a singleton </span><span class=\"s4\">string</span><span class=\"s3\"> (e.g., </span><span class=\"s4\">\"TATA\"</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"char\"</span><span class=\"s3\"> will return a </span><span class=\"s4\">string</span><span class=\"s3\"> vector with one element per nucleotide (e.g., </span><span class=\"s4\">\"T\"</span><span class=\"s3\">, </span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"T\"</span><span class=\"s3\">, </span><span class=\"s4\">\"A\"</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"integer\"</span><span class=\"s3\"> will return an </span><span class=\"s4\">integer</span><span class=\"s3\"> vector with values A=</span><span class=\"s4\">0</span><span class=\"s3\">, C=</span><span class=\"s4\">1</span><span class=\"s3\">, G=</span><span class=\"s4\">2</span><span class=\"s3\">, T=</span><span class=\"s4\">3</span><span class=\"s3\"> (e.g., </span><span class=\"s4\">3</span><span class=\"s3\">, </span><span class=\"s4\">0</span><span class=\"s3\">, </span><span class=\"s4\">3</span><span class=\"s3\">, </span><span class=\"s4\">0</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>If the sequence returned is likely to be long, the </span><span class=\"s4\">\"string\"</span><span class=\"s3\"> format will be the most memory-efficient, and may also be the fastest (but may be harder to work with).</span></p>\n<p class=\"p6\"><span class=\"s3\">For purposes related to interpreting the nucleotide sequence as a coding sequence, a format of </span><span class=\"s4\">\"codon\"</span><span class=\"s3\"> is also supported.<span class=\"Apple-converted-space\">  </span>This format will return an </span><span class=\"s4\">integer</span><span class=\"s3\"> vector with values from </span><span class=\"s4\">0</span><span class=\"s3\"> to </span><span class=\"s4\">63</span><span class=\"s3\">, based upon successive nucleotide triplets in the sequence (which, for this format, must have a length that is a multiple of three).<span class=\"Apple-converted-space\">  </span>The codon value for a given nucleotide triplet XYZ is 16X + 4Y + Z, where X, Y, and Z have the usual values A=</span><span class=\"s4\">0</span><span class=\"s3\">, C=</span><span class=\"s4\">1</span><span class=\"s3\">, G=</span><span class=\"s4\">2</span><span class=\"s3\">, T=</span><span class=\"s4\">3</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>For example, the triplet AAA has a codon value of </span><span class=\"s4\">0</span><span class=\"s3\">, AAC is </span><span class=\"s4\">1</span><span class=\"s3\">, AAG is </span><span class=\"s4\">2</span><span class=\"s3\">, AAT is </span><span class=\"s4\">3</span><span class=\"s3\">, ACA is </span><span class=\"s4\">4</span><span class=\"s3\">, and on upward to TTT which is </span><span class=\"s4\">63</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If the nucleotide sequence AACACATTT is requested in codon format, the codon vector </span><span class=\"s4\">1 4 63</span><span class=\"s3\"> will therefore be returned.<span class=\"Apple-converted-space\">  </span>These codon values can be useful in themselves; they can also be passed to </span><span class=\"s4\">codonToAminoAcid()</span><span class=\"s3\"> to translate them into the corresponding amino acid sequence if desired.</span></p>\n<p class=\"p5\"><span class=\"s5\">– </span><span class=\"s3\">(integer)drawBreakpoints([No&lt;Individual&gt;$ parent = NULL], [Ni$ n = NULL])</span></p>\n<p class=\"p6\"><span class=\"s3\">Draw recombination breakpoints, using the chromosome’s recombination rate map, the current gene conversion parameters, and (in some cases – see below) any active and applicable </span><span class=\"s4\">recombination()</span><span class=\"s3\"> callbacks.<span class=\"Apple-converted-space\">  </span>The number of breakpoints to generate, </span><span class=\"s4\">n</span><span class=\"s3\">, may be supplied; if it is </span><span class=\"s4\">NULL</span><span class=\"s3\"> (the default), the number of breakpoints will be drawn based upon the overall recombination rate and the chromosome length (following the standard procedure in SLiM).<span class=\"Apple-converted-space\">  </span>Note that if the double-stranded breaks model has been chosen, the number of breakpoints generated will probably not be equal to the number requested, because most breakpoints will entail gene conversion tracts, which entail additional crossover breakpoints.</span></p>\n<p class=\"p6\">It is generally recommended that the parent individual be supplied to this method, but <span class=\"s1\">parent</span> is <span class=\"s1\">NULL</span> by default.<span class=\"Apple-converted-space\">  </span>The individual supplied in <span class=\"s1\">parent</span> is used for two purposes.<span class=\"Apple-converted-space\">  </span>First, in sexual models that define separate recombination rate maps for males versus females, the sex of <span class=\"s1\">parent</span> will be used to determine which map is used; in this case, a non-<span class=\"s1\">NULL</span> value <i>must</i> be supplied for <span class=\"s1\">parent</span>, since the choice of recombination rate map must be determined.<span class=\"Apple-converted-space\">  </span>Second, in models that define <span class=\"s1\">recombination()</span> callbacks, <span class=\"s1\">parent</span> is used to determine the various pseudo-parameters that are passed to <span class=\"s1\">recombination()</span> callbacks (<span class=\"s1\">individual</span>, <span class=\"s1\">haplosome1</span>, <span class=\"s1\">haplosome2</span>, <span class=\"s1\">subpop</span>), and the subpopulation to which <span class=\"s1\">parent</span> belongs is used to select which <span class=\"s1\">recombination()</span> callbacks are applicable; given the necessity of this information, <span class=\"s1\">recombination()</span> callbacks will not be called as a side effect of this method if <span class=\"s1\">parent</span> is <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>Apart from these two uses, <span class=\"s1\">parent</span> is not used, and the caller does not guarantee that the generated breakpoints will actually be used to recombine the haplosomes of <span class=\"s1\">parent</span> in particular.<span class=\"Apple-converted-space\">  </span>If a <span class=\"s1\">recombination()</span> callback is called, <span class=\"s1\">haplosome1</span> for that callback will always be the first haplosome of <span class=\"s1\">parent</span> for the chromosome; in other words, <span class=\"s1\">drawBreakpoints()</span> will always treat the first haplosome of a homologous pair as the initial copy strand.<span class=\"Apple-converted-space\">  </span>If the caller wishes to randomly choose an initial copy strand (which is usually desirable), they should do that themselves (note that the <span class=\"s1\">addRecombinant()</span> and <span class=\"s1\">addMultiRecombinant()</span> methods have a flag to facilitate this).</p>\n<p class=\"p5\">– (object&lt;GenomicElement&gt;)genomicElementForPosition(integer positions)</p>\n<p class=\"p6\">Returns a vector of <span class=\"s1\">GenomicElement</span> objects corresponding to the given vector <span class=\"s1\">positions</span>, which contains base positions along the chromosome.<span class=\"Apple-converted-space\">  </span>If every position lies within a defined genomic element, the returned vector will have the same length as <span class=\"s1\">positions</span>, and will correspond one-to-one with it.<span class=\"Apple-converted-space\">  </span>However, if a position in <span class=\"s1\">positions</span> is not within a genomic element, no <span class=\"s1\">GenomicElement</span> object will be present for it in the returned vector, and so the returned vector will no longer have the same length as <span class=\"s1\">positions</span>, and will no longer correspond one-to-one with it.<span class=\"Apple-converted-space\">  </span>The method <span class=\"s1\">hasGenomicElementForPosition()</span> can be used to detect this circumstance.</p>\n<p class=\"p5\">– (logical)hasGenomicElementForPosition(integer positions)</p>\n<p class=\"p6\">Returns a <span class=\"s1\">logical</span> vector corresponding to the given vector <span class=\"s1\">positions</span>, which contains base positions along the chromosome.<span class=\"Apple-converted-space\">  </span>The returned vector will have the same length as <span class=\"s1\">positions</span>, and will correspond one-to-one with it, containing <span class=\"s1\">T</span> if the corresponding position lies inside a genomic element, or <span class=\"s1\">F</span> if it does not.<span class=\"Apple-converted-space\">  </span>The method <span class=\"s1\">genomicElementForPosition()</span> can be used to look up the <span class=\"s1\">GenomicElement</span> objects themselves.</p>\n<p class=\"p5\"><span class=\"s3\">– (integer$)setAncestralNucleotides(is sequence)</span></p>\n<p class=\"p6\"><span class=\"s3\">This method, which may be called only in nucleotide-based models, replaces the ancestral nucleotide sequence for the model.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s4\">sequence</span><span class=\"s3\"> parameter is interpreted exactly as it is in the </span><span class=\"s4\">initializeAncestralSequence()</span><span class=\"s3\"> function; see that documentation for details.<span class=\"Apple-converted-space\">  </span>The length of the ancestral sequence is returned.</span></p>\n<p class=\"p6\"><span class=\"s3\">It is unusual to replace the ancestral sequence in a running simulation, since the nucleotide states of segregating and fixed mutations will depend upon the original ancestral sequence.<span class=\"Apple-converted-space\">  </span>It can be useful when loading a new population state with </span><span class=\"s4\">readHaplosomesFromMS()</span><span class=\"s3\"> or </span><span class=\"s4\">readHaplosomesFromVCF()</span><span class=\"s3\">, such as when resetting the simulation state to an earlier state in a conditional simulation; however, that is more commonly done using </span><span class=\"s4\">readFromPopulationFile()</span><span class=\"s3\"> with a SLiM or </span><span class=\"s4\">.trees</span><span class=\"s3\"> file.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (void)setGeneConversion(numeric$ nonCrossoverFraction, numeric$ meanLength, numeric$ simpleConversionFraction, [numeric$ bias = 0])</span></p>\n<p class=\"p6\"><span class=\"s3\">This method switches the recombination model to the “double-stranded break (DSB)” model (if it is not already set to that), and configures the details of the gene conversion tracts that will therefore be modeled.<span class=\"Apple-converted-space\">  </span>The meanings and effects of the parameters exactly mirror the </span><span class=\"s4\">initializeGeneConversion()</span><span class=\"s3\"> function.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (void)setHotspotMap(numeric multipliers, [Ni ends = NULL], [string$ sex = \"*\"])</span></p>\n<p class=\"p6\"><span class=\"s3\">In nucleotide-based models, set the mutation rate <i>multiplier</i> along the chromosome.<span class=\"Apple-converted-space\">  </span>There are two ways to call this method.<span class=\"Apple-converted-space\">  </span>If the optional </span><span class=\"s4\">ends</span><span class=\"s3\"> parameter is </span><span class=\"s4\">NULL</span><span class=\"s3\"> (the default), then </span><span class=\"s4\">multipliers</span><span class=\"s3\"> must be a singleton value that specifies a single multiplier to be used along the entire chromosome.<span class=\"Apple-converted-space\">  </span>If, on the other hand, </span><span class=\"s4\">ends</span><span class=\"s3\"> is supplied, then </span><span class=\"s4\">multipliers</span><span class=\"s3\"> and </span><span class=\"s4\">ends</span><span class=\"s3\"> must be the same length, and the values in </span><span class=\"s4\">ends</span><span class=\"s3\"> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, </span><span class=\"s4\">multipliers</span><span class=\"s3\"> and </span><span class=\"s4\">ends</span><span class=\"s3\"> taken together specify the multipliers to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in </span><span class=\"s4\">ends</span><span class=\"s3\"> should extend to the end of the chromosome (as previously determined, during simulation initialization).<span class=\"Apple-converted-space\">  </span>See the </span><span class=\"s4\">initializeHotspotMap()</span><span class=\"s3\"> function for further discussion of precisely how these multipliers and positions are interpreted.</span></p>\n<p class=\"p6\"><span class=\"s3\">If the optional </span><span class=\"s4\">sex</span><span class=\"s3\"> parameter is </span><span class=\"s4\">\"*\"</span><span class=\"s3\"> (the default), then the supplied hotspot map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations </span><span class=\"s4\">sex</span><span class=\"s3\"> may be </span><span class=\"s4\">\"M\"</span><span class=\"s3\"> or </span><span class=\"s4\">\"F\"</span><span class=\"s3\"> instead, in which case the supplied hotspot map is used only for that sex.<span class=\"Apple-converted-space\">  </span>Note that whether sex-specific hotspot maps will be used is set by the way that the simulation is initially configured with </span><span class=\"s4\">initializeHotspot()</span><span class=\"s3\">, and cannot be changed with this method; so if the simulation was set up to use sex-specific hotspot maps then sex must be </span><span class=\"s4\">\"M\"</span><span class=\"s3\"> or </span><span class=\"s4\">\"F\"</span><span class=\"s3\"> here, whereas if it was set up not to, then sex must be </span><span class=\"s4\">\"*\"</span><span class=\"s3\"> or unsupplied here.<span class=\"Apple-converted-space\">  </span>If a simulation needs sex-specific hotspot maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.</span></p>\n<p class=\"p6\"><span class=\"s3\">The hotspot map is normally constant in simulations, so be sure you know what you are doing.</span></p>\n<p class=\"p3\">– (void)setMutationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])</p>\n<p class=\"p4\">Set the mutation rate per base position per <span class=\"s7\">gamete</span>.<span class=\"Apple-converted-space\">  </span>There are two ways to call this method.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">ends</span> parameter is <span class=\"s1\">NULL</span> (the default), then <span class=\"s1\">rates</span> must be a singleton value that specifies a single mutation rate to be used along the entire chromosome.<span class=\"Apple-converted-space\">  </span>If, on the other hand, <span class=\"s1\">ends</span> is supplied, then <span class=\"s1\">rates</span> and <span class=\"s1\">ends</span> must be the same length, and the values in <span class=\"s1\">ends</span> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, <span class=\"s1\">rates</span> and <span class=\"s1\">ends</span> taken together specify the mutation rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in <span class=\"s1\">ends</span> should extend to the end of the chromosome (as previously determined, during simulation initialization).<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">initializeMutationRate()</span> function for further discussion of precisely how these rates and positions are interpreted.</p>\n<p class=\"p4\">If the optional <span class=\"s1\">sex</span> parameter is <span class=\"s1\">\"*\"</span> (the default), then the supplied mutation rate map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations <span class=\"s1\">sex</span> may be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> instead, in which case the supplied mutation rate map is used only for that sex.<span class=\"Apple-converted-space\">  </span>Note that whether sex-specific mutation rate maps will be used is set by the way that the simulation is initially configured with <span class=\"s1\">initializeMutationRate()</span>, and cannot be changed with this method; so if the simulation was set up to use sex-specific mutation rate maps then sex must be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> here, whereas if it was set up not to, then sex must be <span class=\"s1\">\"*\"</span> or unsupplied here.<span class=\"Apple-converted-space\">  </span>If a simulation needs sex-specific mutation rate maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.</p>\n<p class=\"p4\">The mutation rate intervals are normally a constant in simulations, so be sure you know what you are doing.</p>\n<p class=\"p6\"><span class=\"s3\">In nucleotide-based models, </span><span class=\"s4\">setMutationRate()</span><span class=\"s3\"> may not be called.<span class=\"Apple-converted-space\">  </span>If variation in the mutation rate along the chromosome is desired, </span><span class=\"s4\">setHotspotMap()</span><span class=\"s3\"> should be used.</span></p>\n<p class=\"p3\">– (void)setRecombinationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])</p>\n<p class=\"p4\">Set the recombination rate per base position per <span class=\"s7\">gamete</span>.<span class=\"Apple-converted-space\">  </span><span class=\"s7\">All rates must be in the interval [</span><span class=\"s8\">0.0</span><span class=\"s7\">, </span><span class=\"s8\">0.5</span><span class=\"s7\">].<span class=\"Apple-converted-space\">  </span></span>There are two ways to call this method.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">ends</span> parameter is <span class=\"s1\">NULL</span> (the default), then <span class=\"s1\">rates</span> must be a singleton value that specifies a single recombination rate to be used along the entire chromosome.<span class=\"Apple-converted-space\">  </span>If, on the other hand, <span class=\"s1\">ends</span> is supplied, then <span class=\"s1\">rates</span> and <span class=\"s1\">ends</span> must be the same length, and the values in <span class=\"s1\">ends</span> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, <span class=\"s1\">rates</span> and <span class=\"s1\">ends</span> taken together specify the recombination rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in <span class=\"s1\">ends</span> should extend to the end of the chromosome (as previously determined, during simulation initialization).<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">initializeRecombinationRate()</span> function for further discussion of precisely how these rates and positions are interpreted.</p>\n<p class=\"p4\">If the optional <span class=\"s1\">sex</span> parameter is <span class=\"s1\">\"*\"</span> (the default), then the supplied recombination rate map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations <span class=\"s1\">sex</span> may be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> instead, in which case the supplied recombination map is used only for that sex.<span class=\"Apple-converted-space\">  </span>Note that whether sex-specific recombination maps will be used is set by the way that the simulation is initially configured with <span class=\"s1\">initializeRecombinationRate()</span>, and cannot be changed with this method; so if the simulation was set up to use sex-specific recombination maps then sex must be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> here, whereas if it was set up not to, then sex must be <span class=\"s1\">\"*\"</span> or unsupplied here.<span class=\"Apple-converted-space\">  </span>If a simulation needs sex-specific recombination maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.</p>\n<p class=\"p4\">The recombination intervals are normally a constant in simulations, so be sure you know what you are doing.</p>\n<p class=\"p1\"><b>5.3<span class=\"Apple-converted-space\">  </span>Class Community</b></p>\n<p class=\"p2\"><i>5.3.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Community</i></span><i> properties</i></p>\n<p class=\"p5\">allGenomicElementTypes =&gt; (object&lt;GenomicElementType&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">GenomicElementType</span> objects defined in the simulation.<span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p5\">allInteractionTypes =&gt; (object&lt;InteractionType&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">InteractionType</span> objects defined in the simulation.<span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p5\">allMutationTypes =&gt; (object&lt;MutationType&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">MutationType</span> objects defined in the simulation.<span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p5\">allScriptBlocks =&gt; (object&lt;SLiMEidosBlock&gt;)</p>\n<p class=\"p6\">All registered <span class=\"s1\">SLiMEidosBlock</span> objects in the simulation.<span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p5\">allSpecies =&gt; (object&lt;Species&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">Species</span> objects defined in the simulation (in species declaration order).</p>\n<p class=\"p5\">allSubpopulations =&gt; (object&lt;Subpopulation&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">Subpopulation</span> objects defined in the simulation.</p>\n<p class=\"p5\">cycleStage =&gt; (string$)</p>\n<p class=\"p6\">The current cycle stage, as a <span class=\"s1\">string</span>.<span class=\"Apple-converted-space\">  </span>The values of this property essentially mirror the cycle stages of WF and nonWF models.<span class=\"Apple-converted-space\">  </span>Common values include <span class=\"s1\">\"first\"</span> (during execution of <span class=\"s1\">first()</span> events), <span class=\"s1\">\"early\"</span> (during execution of <span class=\"s1\">early()</span> events), <span class=\"s1\">\"reproduction\"</span> (during offspring generation), <span class=\"s1\">\"fitness\"</span> (during fitness evaluation), <span class=\"s1\">\"survival\"</span> (while applying selection and mortality in nonWF models), and <span class=\"s1\">\"late\"</span> (during execution of <span class=\"s1\">late()</span> events).</p>\n<p class=\"p6\">Other possible values include <span class=\"s1\">\"begin\"</span> (during internal setup before each cycle), <span class=\"s1\">\"tally\"</span> (while tallying mutation reference counts and removing fixed mutations), <span class=\"s1\">\"swap\"</span> (while swapping the offspring generation into the parental generation in WF models), <span class=\"s1\">\"end\"</span> (during internal bookkeeping after each cycle), and <span class=\"s1\">\"console\"</span> (during the in-between-ticks state in which commands in SLiMgui’s Eidos console are executed).<span class=\"Apple-converted-space\">  </span>It would probably be a good idea not to use this latter set of values; they are probably not user-visible during ordinary model execution anyway.</p>\n<p class=\"p6\">During execution of <span class=\"s1\">initialize()</span> callbacks, no <span class=\"s1\">Community</span> object yet exists and so this property cannot be accessed.<span class=\"Apple-converted-space\">  </span>To detect this state, use <span class=\"s1\">exists(\"community\")</span>; if that is <span class=\"s1\">F</span>, <span class=\"s1\">community</span> does not exist, and therefore your code is executing during <span class=\"s1\">initialize()</span> callbacks (or outside of SLiM entirely, in some other Eidos-based context).</p>\n<p class=\"p5\">logFiles =&gt; (object&lt;LogFile&gt;)</p>\n<p class=\"p6\">The <span class=\"s1\">LogFile</span> objects being used in the simulation.</p>\n<p class=\"p3\">modelType =&gt; (string$)</p>\n<p class=\"p6\"><span class=\"s3\">The type of model being simulated, as specified in </span><span class=\"s4\">initializeSLiMModelType()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This will be </span><span class=\"s4\">\"WF\"</span><span class=\"s3\"> for WF models (Wright-Fisher models, the default), or </span><span class=\"s4\">\"nonWF\"</span><span class=\"s3\"> for nonWF models (non-Wright-Fisher models).</span><span class=\"Apple-converted-space\">  </span>This must be the same for all species in the community; it is therefore a property on <span class=\"s1\">Community</span>, not <span class=\"s1\">Species</span>.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to the simulation.</p>\n<p class=\"p3\">tick &lt;–&gt; (integer$)</p>\n<p class=\"p4\">The current tick number.</p>\n<p class=\"p5\">verbosity &lt;–&gt; (integer$)</p>\n<p class=\"p6\">The verbosity level, for SLiM’s logging of information about the simulation.<span class=\"Apple-converted-space\">  </span>This is <span class=\"s1\">1</span> by default, but can be changed at the command line with the <span class=\"s1\">-l[ong]</span> option.<span class=\"Apple-converted-space\">  </span>It is provided here so that scripts can consult it to govern the level of verbosity of their own output, or set the verbosity level for particular sections of their code.<span class=\"Apple-converted-space\">  </span>A verbosity level of 0 suppresses most of SLiM’s optional output; 2 adds some extra output beyond SLiM’s standard output.</p>\n<p class=\"p2\"><i>5.3.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Community</i></span><i> methods</i></p>\n<p class=\"p5\">– (object&lt;LogFile&gt;$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = \",\"], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL], [logical$ header = T])</p>\n<p class=\"p6\">Creates and returns a new <span class=\"s1\">LogFile</span> object that logs data from the simulation (see the documentation for the <span class=\"s1\">LogFile</span> class for details).<span class=\"Apple-converted-space\">  </span>Logged data will be written to the file at <span class=\"s1\">filePath</span>, overwriting any existing file at that path by default, or appending to it instead if <span class=\"s1\">append</span> is <span class=\"s1\">T</span> (successive rows of the log table will always be appended to the previously written content, of course).<span class=\"Apple-converted-space\">  </span>Before the header line for the log is written out, any <span class=\"s1\">string</span> elements in <span class=\"s1\">initialContents</span> will be written first, separated by newlines, allowing for a user-defined file header.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">compress</span> is <span class=\"s1\">T</span>, the contents will be compressed with <span class=\"s1\">zlib</span> as they are written, and the standard <span class=\"s1\">.gz</span> extension for gzip-compressed files will be appended to the filename in <span class=\"s1\">filePath</span> if it is not already present.</p>\n<p class=\"p6\">The <span class=\"s1\">sep</span> parameter specifies the separator between data values within a row.<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s1\">\",\"</span> will generate a “comma-separated value” (CSV) file, while passing <span class=\"s1\">sep=\"\\t\"</span> will use a tab separator instead to generate a “tab-separated value” (TSV) file.<span class=\"Apple-converted-space\">  </span>Other values for <span class=\"s1\">sep</span> may also be used, but are less standard.</p>\n<p class=\"p6\">LogTable supports periodic automatic logging of a new row of data, enabled by supplying a non-<span class=\"s1\">NULL</span> value for <span class=\"s1\">logInterval</span>.<span class=\"Apple-converted-space\">  </span>In this case, a new row will be logged (as if <span class=\"s1\">logRow()</span> were called on the <span class=\"s1\">LogFile</span>) at the end of every <span class=\"s1\">logInterval</span> ticks (just before the tick counter increments, in both WF and nonWF models), starting at the end of the tick in which the <span class=\"s1\">LogFile</span> was created.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">logInterval</span> of <span class=\"s1\">1</span> will cause automatic logging at the end of every tick, whereas a <span class=\"s1\">logInterval</span> of <span class=\"s1\">NULL</span> disables automatic logging.<span class=\"Apple-converted-space\">  </span>Automatic logging can always be disabled or reconfigured later with the <span class=\"s1\">LogFile</span> method <span class=\"s1\">setLogInterval()</span>, or logging can be triggered manually by calling <span class=\"s1\">logRow()</span>.</p>\n<p class=\"p6\">When compression is enabled, <span class=\"s1\">LogFile</span> flushes new data lazily by default, for performance reasons, buffering data for multiple rows before writing to disk.<span class=\"Apple-converted-space\">  </span>Passing a non-<span class=\"s1\">NULL</span> value for <span class=\"s1\">flushInterval</span> requests a flush every <span class=\"s1\">flushInterval</span> rows (with a value of <span class=\"s1\">1</span> providing unbuffered operation).<span class=\"Apple-converted-space\">  </span>Note that flushing very frequently will likely result in both lower performance and a larger final file size (in one simple test, <span class=\"s1\">48943</span> bytes instead of <span class=\"s1\">4280</span> bytes, or more than a 10× increase in size).<span class=\"Apple-converted-space\">  </span>Alternatively, passing a very large value for <span class=\"s1\">flushInterval</span> will effectively disable automatic flushing, except at the end of the simulation (but be aware that this may use a large amount of memory for large log files).<span class=\"Apple-converted-space\">  </span>In any case, the log file will be created immediately, with its requested initial contents; the initial write is not buffered.<span class=\"Apple-converted-space\">  </span>When compression is not enabled, the <span class=\"s1\">flushInterval</span> setting is ignored.</p>\n<p class=\"p6\">The <span class=\"s1\">header</span> parameter controls whether a header line is written out at the beginning of logging.<span class=\"Apple-converted-space\">  </span>If it is <span class=\"s1\">T</span> (the default), a header line is written out; if <span class=\"s1\">F</span>, no header is written.<span class=\"Apple-converted-space\">  </span>Suppressing the header output can be useful if you are using <span class=\"s1\">LogFile</span> to append data to an existing file that already has a header line.</p>\n<p class=\"p6\">The <span class=\"s1\">LogFile</span> documentation discusses how to configure and use <span class=\"s1\">LogFile</span> to write out the data you are interested in from your simulation.</p>\n<p class=\"p5\">– (integer$)estimatedLastTick(void)</p>\n<p class=\"p6\">Returns SLiM’s current estimate of the last tick in which the model will execute.<span class=\"Apple-converted-space\">  </span>Because script blocks can be added, removed, and rescheduled, and because the simulation may end prematurely (due to a call to <span class=\"s1\">simulationFinished()</span>, for example), this is only an estimate, and may change over time.</p>\n<p class=\"p3\">– (void)deregisterScriptBlock(io&lt;SLiMEidosBlock&gt; scriptBlocks)</p>\n<p class=\"p4\">All <span class=\"s1\">SLiMEidosBlock</span> objects specified by <span class=\"s1\">scriptBlocks</span> (either with <span class=\"s1\">SLiMEidosBlock</span> objects or with <span class=\"s1\">integer</span> identifiers) will be scheduled for deregistration.<span class=\"Apple-converted-space\">  </span>The deregistered blocks remain valid, and may even still be executed in the current stage of the current tick; the blocks are not actually deregistered and deallocated until sometime after the currently executing script block has completed.<span class=\"Apple-converted-space\">  </span>To immediately prevent a script block from executing, even when it is scheduled to execute in the current stage of the current tick, use the <span class=\"s1\">active</span> property of the script block.</p>\n<p class=\"p5\">– (object&lt;GenomicElementType&gt;)genomicElementTypesWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">GenomicElementType</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">GenomicElementType</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p5\">– (object&lt;InteractionType&gt;)interactionTypesWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">InteractionType</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">InteractionType</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p5\">– (object&lt;MutationType&gt;)mutationTypesWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">MutationType</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">MutationType</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)outputUsage(void)</span></p>\n<p class=\"p6\">Output the current memory usage of the simulation to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>The specifics of what is printed, and in what format, should not be relied upon as they may change from version to version of SLiM.<span class=\"Apple-converted-space\">  </span>This method is primarily useful for understanding where the memory usage of a simulation predominantly resides, for debugging or optimization.<span class=\"Apple-converted-space\">  </span>Note that it does not capture <i>all</i> memory usage by the process; rather, it summarizes the memory usage by SLiM and Eidos in directly allocated objects and buffers.<span class=\"Apple-converted-space\">  </span>To get the same memory usage reported by <span class=\"s1\">outputUsage()</span>, but as a <span class=\"s1\">float$</span> value, use the <span class=\"s1\">Community</span> method <span class=\"s1\">usage()</span>.<span class=\"Apple-converted-space\">  </span>To get the <i>total</i> memory usage of the running process (either current or peak), use the Eidos function <span class=\"s1\">usage()</span>.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerEarlyEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL]<span class=\"s5\">, [No&lt;Species&gt;$ ticksSpec = NULL]</span>)</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">early()</span> event in the current simulation, with optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks<span class=\"s5\"> (and, for multispecies models, optional ticks specifier </span><span class=\"s6\">ticksSpec</span><span class=\"s5\">)</span> limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered event is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p5\">– (object&lt;SLiMEidosBlock&gt;$)registerFirstEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL], [No&lt;Species&gt;$ ticksSpec = NULL])</p>\n<p class=\"p6\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">first()</span> event in the current simulation, with optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks (and, for multispecies models, optional ticks specifier <span class=\"s1\">ticksSpec</span>) limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered event is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerInteractionCallback(Nis$ id, string$ source, io&lt;InteractionType&gt;$ intType, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">interaction()</span> callback in the current simulation<span class=\"s5\"> (global to the community)</span>, with a required interaction type <span class=\"s1\">intType</span> (which may be an <span class=\"s1\">integer</span> identifier), optional exerter subpopulation <span class=\"s1\">subpop</span> (which may also be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations), and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it will be eligible to execute the next time an <span class=\"s1\">InteractionType</span> is evaluated.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerLateEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL]<span class=\"s5\">, [No&lt;Species&gt;$ ticksSpec = NULL]</span>)</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">late()</span> event in the current simulation, with optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks<span class=\"s5\"> (and, for multispecies models, optional ticks specifier </span><span class=\"s6\">ticksSpec</span><span class=\"s5\">)</span> limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered event is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p5\">– (object&lt;SLiMEidosBlock&gt;$)rescheduleScriptBlock(io&lt;SLiMEidosBlock&gt;$ block, [Ni$ start = NULL], [Ni$ end = NULL], [Ni ticks = NULL])</p>\n<p class=\"p6\">Reschedule the target script block given by <span class=\"s1\">block</span> to execute in a specified set of ticks.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">block</span> parameter may be either an <span class=\"s1\">integer</span> representing the ID of the desired script block, or a <span class=\"s1\">SLiMScriptBlock</span> specified directly.<span class=\"Apple-converted-space\">  </span>The target script block, <span class=\"s1\">block</span>, is returned.</p>\n<p class=\"p6\">The first way to specify the tick set is with <span class=\"s1\">start</span> and <span class=\"s1\">end</span> parameter values; <span class=\"s1\">block</span> will then execute from <span class=\"s1\">start</span> to <span class=\"s1\">end</span>, inclusive.</p>\n<p class=\"p6\">The second way to specify the tick set is using the <span class=\"s1\">ticks</span> parameter, specifying each tick in which the block should execute.<span class=\"Apple-converted-space\">  </span>The vector supplied for <span class=\"s1\">ticks</span> does not need to be in sorted order, but it must not contain any duplicates.</p>\n<p class=\"p6\">It can sometimes be better to handle script block scheduling in other ways.<span class=\"Apple-converted-space\">  </span>If an <span class=\"s1\">early()</span> event needs to execute every tenth tick over the whole duration of a long model run, for example, it might not be advisable to use a call like <span class=\"s1\">community.rescheduleScriptBlock(s1, ticks=seq(10, 100000, 10))</span> for that purpose, since that would make things complicated for SLiM’s scheduler.<span class=\"Apple-converted-space\">  </span>Instead, it might be preferable to add a test such as <span class=\"s1\">if (community.tick % 10 != 0) return;</span> at the beginning of the event.<span class=\"Apple-converted-space\">  </span>It is legal to reschedule a script block while the block is executing; a call like <span class=\"s1\">community.rescheduleScriptBlock(self, community.tick + 10, community.tick + 10);</span> made inside a given block would therefore also cause the block to execute every tenth tick, although this sort of self-rescheduling code is probably harder to read, maintain, and debug.</p>\n<p class=\"p6\">Whichever way of specifying the tick set is used, <span class=\"s1\">block</span> may continue to be executed during the current tick cycle stage even after it has been rescheduled, unless it is made inactive using its <span class=\"s1\">active</span> property, and similarly, the block may not execute during the current tick cycle stage if it was not already scheduled to do so.<span class=\"Apple-converted-space\">  </span>Rescheduling script blocks during the tick and tick cycle stage in which they are executing, or in which they are intended to execute, should be avoided.<span class=\"Apple-converted-space\">  </span>Also, note that script blocks which are open-ended (i.e., with no specified end tick), are not used in determining whether the end of the simulation has been reached (because then the simulation would run forever).</p>\n<p class=\"p6\">Note that new script blocks can also be created and scheduled using the <span class=\"s1\">register...()</span> methods of <span class=\"s1\">Community</span> and <span class=\"s1\">Species</span>; by using the same source as a template script block, the template can be duplicated and scheduled for different ticks, perhaps with modifications or variations.<span class=\"Apple-converted-space\">  </span>In multispecies models, note that blocks may not run due to their <span class=\"s1\">species</span> or <span class=\"s1\">ticks</span> specifier, even in ticks in which they are scheduled to run.</p>\n<p class=\"p5\">– (object&lt;SLiMEidosBlock&gt;)scriptBlocksWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">SLiMEidosBlock</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">SLiMEidosBlock</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p3\">– (void)simulationFinished(void)</p>\n<p class=\"p4\">Declare the current simulation finished.<span class=\"Apple-converted-space\">  </span>Normally SLiM ends a simulation when, at the end of a tick, there are no script events or callbacks registered for any future tick (excluding scripts with no declared end tick).<span class=\"Apple-converted-space\">  </span>If you wish to end a simulation before this condition is met, a call to <span class=\"s1\">simulationFinished()</span> will cause the current simulation to end at the end of the current tick.<span class=\"Apple-converted-space\">  </span>For example, a simulation might self-terminate if a test for a dynamic equilibrium condition is satisfied.<span class=\"Apple-converted-space\">  </span>Note that the current tick will finish executing; if you want the simulation to stop immediately, you can use the Eidos method <span class=\"s1\">stop()</span>, which raises an error condition.</p>\n<p class=\"p5\">– (object&lt;Species&gt;)speciesWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">Species</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">Species</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p5\">– (object&lt;Subpopulation&gt;)subpopulationsWithIDs(integer ids)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">Subpopulation</span> objects with <span class=\"s1\">id</span> values matching the values in <span class=\"s1\">ids</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">Subpopulation</span> object can be found with a given <span class=\"s1\">id</span>, an error results.</p>\n<p class=\"p5\">– (object&lt;Subpopulation&gt;)subpopulationsWithNames(string names)</p>\n<p class=\"p6\">Find and return the <span class=\"s1\">Subpopulation</span> objects with <span class=\"s1\">name</span> values matching the values in <span class=\"s1\">names</span>.<span class=\"Apple-converted-space\">  </span>If no matching <span class=\"s1\">Subpopulation</span> object can be found with a given name, an error results.</p>\n<p class=\"p5\">– (float$)usage(void)</p>\n<p class=\"p6\">Return the current memory usage of the simulation.<span class=\"Apple-converted-space\">  </span>The specifics of what is totalled up should not be relied upon as it may change from version to version of SLiM.<span class=\"Apple-converted-space\">  </span>This method is primarily useful for understanding where the memory usage of a simulation predominantly resides, for debugging or optimization.<span class=\"Apple-converted-space\">  </span>Note that it does not capture <i>all</i> memory usage by the process; rather, it summarizes the memory usage by SLiM and Eidos in directly allocated objects and buffers.<span class=\"Apple-converted-space\">  </span>To see details of this internal memory usage, use the <span class=\"s1\">Community</span> method <span class=\"s1\">outputUsage()</span>.<span class=\"Apple-converted-space\">  </span>To get the <i>total</i> memory usage of the running process (either current or peak), use the Eidos function <span class=\"s1\">usage()</span>.</p>\n<p class=\"p1\"><b>5.4<span class=\"Apple-converted-space\">  </span>Class Haplosome</b></p>\n<p class=\"p2\"><i>5.4.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Haplosome</i></span><i> properties</i></p>\n<p class=\"p5\">chromosome =&gt; (object&lt;Chromosome&gt;$)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> object which this haplosome represents; for example, if this haplosome represents the X sex chromosome in a particular individual, then this property provides the <span class=\"s1\">Chromosome</span> object that defines the genetic structure of the X sex chromosome in that individual’s species.</p>\n<p class=\"p5\">chromosomeSubposition =&gt; (integer$)</p>\n<p class=\"p6\">The position index of the haplosome, within the set of haplosomes associated with the <span class=\"s1\">Chromosome</span> object which this haplosome represents.<span class=\"Apple-converted-space\">  </span>For example, if an individual in a multi-chromosome model has two haplosomes that represent a given chromosome within its <span class=\"s1\">haplosomes</span> vector, the first of those haplosomes will have a <span class=\"s1\">chromosomeSubposition</span> value of <span class=\"s1\">0</span>, the second will have a <span class=\"s1\">chromosomeSubposition</span> value of <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>For an intrinsically diploid chromosome in individuals generated by a standard biparental cross, the first haplosome (at subposition <span class=\"s1\">0</span>) came from its first parent (the female parent, in sexual models), and the second haplosome (at subposition <span class=\"s1\">1</span>) came from its second parent (the male parent, in sexual models).</p>\n<p class=\"p5\"><span class=\"s3\">haplosomePedigreeID =&gt; (integer$)</span></p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span> or tree-sequence recording is turned on with <span class=\"s1\">initializeTreeSeq()</span>, <span class=\"s1\">haplosomePedigreeID</span> is a “semi-unique” non-negative identifier for each haplosome in a simulation, never re-used throughout the duration of the simulation run.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">haplosomePedigreeID</span> of a given haplosome will be equal to either <span class=\"s1\">(2*pedigreeID)</span> or <span class=\"s1\">(2*pedigreeID + 1)</span> of the individual that the haplosome belongs to (the former for a first haplosome of the individual, the latter for a second haplosome of the individual if one exists); this invariant relationship is guaranteed.</p>\n<p class=\"p6\">This value is “semi-unique” in the sense that it is shared by <i>all</i> of the first haplosomes of an individual, or by <i>all</i> of the second haplosomes of an individual.<span class=\"Apple-converted-space\">  </span>In a single-chromosome model, a given individual will have just one first haplosome, and perhaps (depending on the chromosome type) one second haplosome, and so the value of <span class=\"s1\">haplosomePedigreeID</span> for each of those haplosomes will be truly unique.<span class=\"Apple-converted-space\">  </span>In a multi-chromosome model, however, an individual has a first haplosome for each chromosome, and perhaps (depending on the chromosome types) a second haplosome for each chromosome.<span class=\"Apple-converted-space\">  </span>In that case, the value of <span class=\"s1\">haplosomePedigreeID</span> is unique in the sense that it is different for each individual, but it is <i>not</i> unique in the sense that it will be shared by other haplosomes within the same individual – shared by all the first haplosomes, or shared by all the second haplosomes.<span class=\"Apple-converted-space\">  </span>This “semi-uniqueness” is intentional; it allows <span class=\"s1\">haplosomePedigreeID</span> to be used as a “key” that associates the haplosomes of an individual across disparate datasets, such as across the different tree sequences for each chromosome that are produced by tree-sequence recording in a multi-chromosome model.<span class=\"Apple-converted-space\">  </span>See sections 1.5.1 and 8.3 for further discussion of multi-chromosome models.</p>\n<p class=\"p6\">If neither pedigree tracking nor tree-sequence recording is enabled, this property is unavailable.</p>\n<p class=\"p5\"><span class=\"s3\">individual =&gt; (object&lt;Individual&gt;$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The </span><span class=\"s4\">Individual</span><span class=\"s3\"> object to which this haplosome belongs.</span></p>\n<p class=\"p3\">isNullHaplosome =&gt; (logical$)</p>\n<p class=\"p6\"><span class=\"s1\">T</span> if the haplosome is a “null” haplosome, <span class=\"s1\">F</span> if it is an ordinary haplosome object.<span class=\"Apple-converted-space\">  </span>Null haplosomes are used as placeholders when a real haplosome doesn’t exist in a particular slot, allowing SLiM’s code to operate in the same way across a wide variety of genomic configurations.<span class=\"Apple-converted-space\">  </span>For example, when simulating chromosome type <span class=\"s1\">\"X\"</span> (an X chromosome), the second haplosome for that chromosome in males will be a null haplosome, preserving a constant number of haplosomes for all individuals even though males have one X while females have two.<span class=\"Apple-converted-space\">  </span>Null haplosomes should not be accessed or manipulated.</p>\n<p class=\"p5\">mutationCount =&gt; (integer$)</p>\n<p class=\"p6\">The number of <span class=\"s1\">Mutation</span> objects present in this haplosome.<span class=\"Apple-converted-space\">  </span>This property is provided as a convenience, and for efficiency; the result of <span class=\"s1\">haplosome.mutationCount</span> will be equal to <span class=\"s1\">size(haplosome.mutations)</span>.</p>\n<p class=\"p5\">mutations =&gt; (object&lt;Mutation&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">Mutation</span> objects present in this haplosome.<span class=\"Apple-converted-space\">  </span>If you only need the number of mutations present, use the <span class=\"s1\">mutationCount</span> property.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>Note that the <span class=\"s1\">Haplosome</span> objects used by SLiM are new with every new individual, so the <span class=\"s1\">tag</span> value of each new offspring haplosome generated in each tick will be initially undefined.</p>\n<p class=\"p2\"><i>5.4.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Haplosome</i></span><i> methods</i></p>\n<p class=\"p3\">+ (void)addMutations(object&lt;Mutation&gt; mutations)</p>\n<p class=\"p6\">Add the existing mutations in <span class=\"s1\">mutations</span> to the target haplosomes, if they are not already present (if they are already present, they will be ignored), and if the addition is not prevented by the mutation stacking policy (see the <span class=\"s1\">mutationStackPolicy</span> property of <span class=\"s1\">MutationType</span>).<span class=\"Apple-converted-space\">  </span>All target haplosomes and all mutations in <span class=\"s1\">mutations</span> must be associated with the same <span class=\"s1\">Chromosome</span> object; attempting to add a mutation to a haplosome associated with a different chromosome will raise an error.</p>\n<p class=\"p6\">Calling this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p6\">Note that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the <span class=\"s1\">age</span> of the individual is greater than <span class=\"s1\">0</span>), to prevent the possibility of inconsistencies in the recorded tree sequence.</p>\n<p class=\"p3\">+ (object&lt;Mutation&gt;)addNewDrawnMutation(io&lt;MutationType&gt; mutationType, integer position, [Nio&lt;Subpopulation&gt; originSubpop = NULL]<span class=\"s7\">, [Nis nucleotide = NULL]</span>)</p>\n<p class=\"p6\">Add new mutations to the target haplosomes with the specified <span class=\"s1\">mutationType</span> (specified by the <span class=\"s1\">MutationType</span> object or by <span class=\"s1\">integer</span> identifier), <span class=\"s1\">position</span>, <span class=\"s1\">originTick</span> (which may be <span class=\"s1\">NULL</span>, the default, to specify the current tick; otherwise, beginning in SLiM 3.5, it must be equal to the current tick anyway, as other uses of this property have been deprecated), and <span class=\"s1\">originSubpop</span> (specified by the <span class=\"s1\">Subpopulation</span> object or by <span class=\"s1\">integer</span> identifier, or by <span class=\"s1\">NULL</span>, the default, to specify the subpopulation to which the first target haplosome belongs).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">originSubpop</span> is supplied as an <span class=\"s1\">integer</span>, it is intentionally not checked for validity; you may use arbitrary values of <span class=\"s1\">originSubpop</span> to “tag” the mutations that you create.<span class=\"Apple-converted-space\">  </span>The selection coefficients of the mutations are drawn from their mutation types; <span class=\"s1\">addNewMutation()</span> may be used instead if you wish to specify selection coefficients.<span class=\"Apple-converted-space\">  </span>All of the target haplosomes must be associated with the same <span class=\"s1\">Chromosome</span> object, since each new mutation is added to all of the target haplosomes.</p>\n<p class=\"p6\"><span class=\"s3\">In non-nucleotide-based models, </span><span class=\"s4\">mutationType</span><span class=\"s3\"> will always be a non-nucleotide-based mutation type, and so </span><span class=\"s4\">nucleotide</span><span class=\"s3\"> must be </span><span class=\"s4\">NULL</span><span class=\"s3\"> (the default).<span class=\"Apple-converted-space\">  </span>In a nucleotide-based model, </span><span class=\"s4\">mutationType</span><span class=\"s3\"> might still be non-nucleotide-based (in which case </span><span class=\"s4\">nucleotide</span><span class=\"s3\"> must still be </span><span class=\"s4\">NULL</span><span class=\"s3\">), or </span><span class=\"s4\">mutationType</span><span class=\"s3\"> might be nucleotide-based, in which case a non-</span><span class=\"s4\">NULL</span><span class=\"s3\"> value must be supplied for </span><span class=\"s4\">nucleotide</span><span class=\"s3\">, specifying the nucleotide(s) to be associated with the new mutation(s).<span class=\"Apple-converted-space\">  </span>Nucleotides may be specified with string values (</span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"C\"</span><span class=\"s3\">, </span><span class=\"s4\">\"G\"</span><span class=\"s3\">, or </span><span class=\"s4\">\"T\"</span><span class=\"s3\">), or with integer values (A=</span><span class=\"s4\">0</span><span class=\"s3\">, C=</span><span class=\"s4\">1</span><span class=\"s3\">, G=</span><span class=\"s4\">2</span><span class=\"s3\">, T=</span><span class=\"s4\">3</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>If a nucleotide mutation already exists at the mutating position, it is replaced automatically in accordance with the stacking policy for nucleotide-based mutation types.<span class=\"Apple-converted-space\">  </span>No check is performed that a new mutation’s nucleotide differs from the ancestral sequence, or that its selection coefficient is consistent with other mutations that may already exist at the given position with the same nucleotide; model consistency is the responsibility of the model.</span></p>\n<p class=\"p4\">Beginning in SLiM 2.5 this method is vectorized, so all of these parameters may be singletons (in which case that single value is used for all mutations created by the call) or non-singleton vectors (in which case one element is used for each corresponding mutation created).<span class=\"Apple-converted-space\">  </span>Non-singleton parameters must match in length, since their elements need to be matched up one-to-one.</p>\n<p class=\"p4\">The new mutations created by this method are returned, even if their actual addition is prevented by the mutation stacking policy (see the <span class=\"s1\">mutationStackPolicy</span> property of <span class=\"s1\">MutationType</span>).<span class=\"Apple-converted-space\">  </span>However, the order of the mutations in the returned vector is not guaranteed to be the same as the order in which the values are specified in parameter vectors, unless the <span class=\"s1\">position</span> parameter is specified in ascending order.<span class=\"Apple-converted-space\">  </span>In other words, pre-sorting the parameters to this method into ascending order by position, using <span class=\"s1\">order()</span> and subsetting, will guarantee that the order of the returned vector of mutations corresponds to the order of elements in the parameters to this method; otherwise, no such guarantee exists.</p>\n<p class=\"p4\">Beginning in SLiM 2.1, this is a class method, not an instance method.<span class=\"Apple-converted-space\">  </span>This means that it does not get multiplexed out to all of the elements of the receiver (which would add a different new mutation to each element); instead, it is performed as a single operation, adding the same new mutation objects to all of the elements of the receiver.<span class=\"Apple-converted-space\">  </span>Before SLiM 2.1, to add the same mutations to multiple haplosomes, it was necessary to call <span class=\"s1\">addNewDrawnMutation()</span> on one of the haplosomes, and then add the returned <span class=\"s1\">Mutation</span> object to all of the other haplosomes using <span class=\"s1\">addMutations()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>That is not necessary in SLiM 2.1 and later, because of this change (although doing it the old way does no harm and produces identical behavior).<span class=\"Apple-converted-space\">  </span>Pre-2.1 code that actually relied upon the old multiplexing behavior will no longer work correctly (but this is expected to be an extremely rare pattern of usage).</p>\n<p class=\"p7\">Before SLiM 4, this method also took a <span class=\"s1\">originGeneration</span> parameter.<span class=\"Apple-converted-space\">  </span>This was deprecated (the origin generation was then required to be equal to the current generation, for internal consistency), and was removed in SLiM 4.</p>\n<p class=\"p4\">Calling this will normally affect the fitness values calculated at the end of the current tick (but not sooner); if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p6\">Note that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the <span class=\"s1\">age</span> of the individual is greater than <span class=\"s1\">0</span>), to prevent the possibility of inconsistencies in the recorded tree sequence.</p>\n<p class=\"p3\">+ (object&lt;Mutation&gt;)addNewMutation(io&lt;MutationType&gt; mutationType, numeric selectionCoeff, integer position, [Nio&lt;Subpopulation&gt; originSubpop = NULL]<span class=\"s7\">, [Nis nucleotide = NULL]</span>)</p>\n<p class=\"p6\">Add new mutations to the target haplosomes with the specified <span class=\"s1\">mutationType</span> (specified by the <span class=\"s1\">MutationType</span> object or by <span class=\"s1\">integer</span> identifier), <span class=\"s1\">selectionCoeff</span>, <span class=\"s1\">position</span>, <span class=\"s1\">originTick</span> (which may be <span class=\"s1\">NULL</span>, the default, to specify the current tick; otherwise, beginning in SLiM 3.5, it must be equal to the current tick anyway, as other uses of this property have been deprecated), and <span class=\"s1\">originSubpop</span> (specified by the <span class=\"s1\">Subpopulation</span> object or by <span class=\"s1\">integer</span> identifier, or by <span class=\"s1\">NULL</span>, the default, to specify the subpopulation to which the first target haplosome belongs).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">originSubpop</span> is supplied as an <span class=\"s1\">integer</span>, it is intentionally not checked for validity; you may use arbitrary values of <span class=\"s1\">originSubpop</span> to “tag” the mutations that you create.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">addNewDrawnMutation()</span> method may be used instead if you wish selection coefficients to be drawn from the mutation types of the mutations.<span class=\"Apple-converted-space\">  </span>All of the target haplosomes must be associated with the same <span class=\"s1\">Chromosome</span> object, since each new mutation is added to all of the target haplosomes.</p>\n<p class=\"p6\"><span class=\"s3\">In non-nucleotide-based models, </span><span class=\"s4\">mutationType</span><span class=\"s3\"> will always be a non-nucleotide-based mutation type, and so </span><span class=\"s4\">nucleotide</span><span class=\"s3\"> must be </span><span class=\"s4\">NULL</span><span class=\"s3\"> (the default).<span class=\"Apple-converted-space\">  </span>In a nucleotide-based model, </span><span class=\"s4\">mutationType</span><span class=\"s3\"> might still be non-nucleotide-based (in which case </span><span class=\"s4\">nucleotide</span><span class=\"s3\"> must still be </span><span class=\"s4\">NULL</span><span class=\"s3\">), or </span><span class=\"s4\">mutationType</span><span class=\"s3\"> might be nucleotide-based, in which case a non-</span><span class=\"s4\">NULL</span><span class=\"s3\"> value must be supplied for </span><span class=\"s4\">nucleotide</span><span class=\"s3\">, specifying the nucleotide(s) to be associated with the new mutation(s).<span class=\"Apple-converted-space\">  </span>Nucleotides may be specified with string values (</span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"C\"</span><span class=\"s3\">, </span><span class=\"s4\">\"G\"</span><span class=\"s3\">, or </span><span class=\"s4\">\"T\"</span><span class=\"s3\">), or with integer values (A=</span><span class=\"s4\">0</span><span class=\"s3\">, C=</span><span class=\"s4\">1</span><span class=\"s3\">, G=</span><span class=\"s4\">2</span><span class=\"s3\">, T=</span><span class=\"s4\">3</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>If a nucleotide mutation already exists at the mutating position, it is replaced automatically in accordance with the stacking policy for nucleotide-based mutation types.<span class=\"Apple-converted-space\">  </span>No check is performed that a new mutation’s nucleotide differs from the ancestral sequence, or that its selection coefficient is consistent with other mutations that may already exist at the given position with the same nucleotide; model consistency is the responsibility of the model.</span></p>\n<p class=\"p4\">The new mutations created by this method are returned, even if their actual addition is prevented by the mutation stacking policy (see the <span class=\"s1\">mutationStackPolicy</span> property of <span class=\"s1\">MutationType</span>).<span class=\"Apple-converted-space\">  </span>However, the order of the mutations in the returned vector is not guaranteed to be the same as the order in which the values are specified in parameter vectors, unless the <span class=\"s1\">position</span> parameter is specified in ascending order.<span class=\"Apple-converted-space\">  </span>In other words, pre-sorting the parameters to this method into ascending order by position, using <span class=\"s1\">order()</span> and subsetting, will guarantee that the order of the returned vector of mutations corresponds to the order of elements in the parameters to this method; otherwise, no such guarantee exists.</p>\n<p class=\"p4\">Beginning in SLiM 2.1, this is a class method, not an instance method.<span class=\"Apple-converted-space\">  </span>This means that it does not get multiplexed out to all of the elements of the receiver (which would add a different new mutation to each element); instead, it is performed as a single operation, adding the same new mutation object to all of the elements of the receiver.<span class=\"Apple-converted-space\">  </span>Before SLiM 2.1, to add the same mutation to multiple haplosomes, it was necessary to call <span class=\"s1\">addNewMutation()</span> on one of the haplosomes, and then add the returned <span class=\"s1\">Mutation</span> object to all of the other haplosomes using <span class=\"s1\">addMutations()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>That is not necessary in SLiM 2.1 and later, because of this change (although doing it the old way does no harm and produces identical behavior).<span class=\"Apple-converted-space\">  </span>Pre-2.1 code that actually relied upon the old multiplexing behavior will no longer work correctly (but this is expected to be an extremely rare pattern of usage).</p>\n<p class=\"p7\">Before SLiM 4, this method also took a <span class=\"s1\">originGeneration</span> parameter.<span class=\"Apple-converted-space\">  </span>This was deprecated (the origin generation was then required to be equal to the current generation, for internal consistency), and was removed in SLiM 4.</p>\n<p class=\"p4\">Calling this will normally affect the fitness values calculated at the end of the current tick (but not sooner); if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p6\">Note that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the <span class=\"s1\">age</span> of the individual is greater than <span class=\"s1\">0</span>), to prevent the possibility of inconsistencies in the recorded tree sequence.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(<span class=\"s7\">Nlo&lt;Mutation&gt;$</span>)containsMarkerMutation(io&lt;MutationType&gt;$ mutType, integer$<span class=\"s9\"> </span>position<span class=\"s7\">, [logical$ returnMutation = F]</span>)</p>\n<p class=\"p4\">Returns <span class=\"s1\">T</span> if the haplosome contains a mutation of type <span class=\"s1\">mutType</span> at <span class=\"s1\">position</span>, <span class=\"s1\">F</span> otherwise<span class=\"s7\"> (if </span><span class=\"s8\">returnMutation</span><span class=\"s7\"> has its default value of </span><span class=\"s8\">F</span><span class=\"s7\">; see below)</span>.<span class=\"Apple-converted-space\">  </span>This method is, as its name suggests, intended for checking for “marker mutations”: mutations of a special mutation type that are not literally mutations in the usual sense, but instead are added in to particular haplosomes to mark them as possessing some property.<span class=\"Apple-converted-space\">  </span>Marker mutations are not typically added by SLiM’s mutation-generating machinery; instead they are added explicitly with <span class=\"s1\">addNewMutation()</span> or <span class=\"s1\">addNewDrawnMutation()</span> at a known, constant position in the haplosome.<span class=\"Apple-converted-space\">  </span>This method provides a check for whether a marker mutation of a given type exists in a particular haplosome; because the position to check is known in advance, that check can be done much faster than the equivalent check with <span class=\"s1\">containsMutations()</span> or <span class=\"s1\">countOfMutationsOfType()</span>, using a binary search of the haplosome.</p>\n<p class=\"p6\"><span class=\"s3\">If </span><span class=\"s4\">returnMutation</span><span class=\"s3\"> is </span><span class=\"s4\">T</span><span class=\"s3\"> (an option added in SLiM 3), this method returns the actual mutation found, rather than just </span><span class=\"s4\">T</span><span class=\"s3\"> or </span><span class=\"s4\">F</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>More specifically, the <i>first</i> mutation found of </span><span class=\"s4\">mutType</span><span class=\"s3\"> at </span><span class=\"s4\">position</span><span class=\"s3\"> will be returned; if more than one such mutation exists in the target haplosome, which one is returned is not defined.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">returnMutation</span><span class=\"s3\"> is T and no mutation of </span><span class=\"s4\">mutType</span><span class=\"s3\"> is found at </span><span class=\"s4\">position</span><span class=\"s3\">, </span><span class=\"s4\">NULL</span><span class=\"s3\"> will be returned.</span></p>\n<p class=\"p3\">– (logical)containsMutations(object&lt;Mutation&gt; mutations)</p>\n<p class=\"p6\">Returns a <span class=\"s1\">logical</span> vector indicating whether each of the mutations in <span class=\"s1\">mutations</span> is present in the target haplosome; each element in the returned vector indicates whether the corresponding mutation is present (<span class=\"s1\">T</span>) or absent (<span class=\"s1\">F</span>).<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p6\">Note that the mutations must be associated with the same chromosome as the target haplosome, otherwise an error is raised.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">containsMutations()</span> method of <span class=\"s1\">Individual</span> does not have this restriction, since it checks for mutations across all of the haplosomes of the target individual.<span class=\"Apple-converted-space\">  </span>This restriction is intended to find logic errors, since it seems to make little sense to check for a mutation in a haplosome for the wrong chromosome; but if this restriction proves inconvenient in common situations, it could be relaxed.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(integer$)countOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns the number of mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the haplosome.<span class=\"Apple-converted-space\">  </span>If you need a vector of the matching <span class=\"s1\">Mutation</span> objects, rather than just a count, use <span class=\"s1\">-mutationsOfType()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p5\">+ (integer)mutationCountsInHaplosomes([No&lt;Mutation&gt; mutations = NULL])</p>\n<p class=\"p6\">Return an <span class=\"s1\">integer</span> vector with the frequency counts of all of the <span class=\"s1\">Mutation</span> objects passed in <span class=\"s1\">mutations</span>, within the target <span class=\"s1\">Haplosome</span> vector.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">mutations</span> argument is <span class=\"s1\">NULL</span> (the default), frequency counts will be returned for all of the active <span class=\"s1\">Mutation</span> objects in the species – the same <span class=\"s1\">Mutation</span> objects, and in the same order, as would be returned by the <span class=\"s1\">mutations</span> property of <span class=\"s1\">sim</span>, in other words.</p>\n<p class=\"p6\">In multi-chromosome models, you might often wish to obtain counts only for mutations associated with one particular chromosome.<span class=\"Apple-converted-space\">  </span>In that case, you would probably want to pass a vector of the mutations associated with that specific chromosome, as obtained from the <span class=\"s1\">subsetMutations()</span> method of <span class=\"s1\">Species</span>, rather than passing <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>(Passing <span class=\"s1\">NULL</span> in that scenario would give you counts of <span class=\"s1\">0</span> for all of the mutations associated with other chromosomes in the model.)</p>\n<p class=\"p6\">See the <span class=\"s1\">+mutationFrequenciesInHaplosomes()</span> method to obtain <span class=\"s1\">float</span> frequencies instead of <span class=\"s1\">integer</span> counts.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">Species</span> methods <span class=\"s1\">mutationCounts()</span> and <span class=\"s1\">mutationFrequencies()</span>, which might be more efficient for getting counts/frequencies for whole subpopulations or for the whole species.</p>\n<p class=\"p5\">+ (float)mutationFrequenciesInHaplosomes([No&lt;Mutation&gt; mutations = NULL])</p>\n<p class=\"p6\">Return a <span class=\"s1\">float</span> vector with the frequencies of all of the <span class=\"s1\">Mutation</span> objects passed in <span class=\"s1\">mutations</span>, within the target <span class=\"s1\">Haplosome</span> vector.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">mutations</span> argument is <span class=\"s1\">NULL</span> (the default), frequencies will be returned for all of the active <span class=\"s1\">Mutation</span> objects in the species – the same <span class=\"s1\">Mutation</span> objects, and in the same order, as would be returned by the <span class=\"s1\">mutations</span> property of <span class=\"s1\">sim</span>, in other words.</p>\n<p class=\"p6\">In multi-chromosome models, the frequency of each mutation is assessed within the subset of target haplosomes that are associated with the same chromosome.<span class=\"Apple-converted-space\">  </span>In other words, if a mutation is associated with chromosome 1, and the target haplosomes are associated with both chromosomes 1 and 2, the frequency of the mutation will be calculated only within the haplosomes for chromosome 1 (as you would expect).<span class=\"Apple-converted-space\">  </span>However, you might often wish to obtain frequencies only for mutations associated with one particular chromosome.<span class=\"Apple-converted-space\">  </span>In that case, you would probably want to pass a vector of the mutations associated with that specific chromosome, as obtained from the <span class=\"s1\">subsetMutations()</span> method of <span class=\"s1\">Species</span>, rather than passing <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>(Passing <span class=\"s1\">NULL</span> in that scenario would give you frequencies of <span class=\"s1\">0</span> for all of the mutations associated with other chromosomes in the model.)</p>\n<p class=\"p6\">See the <span class=\"s1\">+mutationCountsInHaplosomes()</span> method to obtain <span class=\"s1\">integer</span> counts instead of <span class=\"s1\">float</span> frequencies.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">Species</span> methods <span class=\"s1\">mutationCounts()</span> and <span class=\"s1\">mutationFrequencies()</span>, which might be more efficient for getting counts/frequencies for whole subpopulations or for the whole species.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(object&lt;Mutation&gt;)mutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns an <span class=\"s1\">object</span> vector of all the mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the haplosome.<span class=\"Apple-converted-space\">  </span>If you just need a count of the matching <span class=\"s1\">Mutation</span> objects, rather than a vector of the matches, use <span class=\"s1\">-countOfMutationsOfType()</span>; if you need just the positions of matching <span class=\"s1\">Mutation</span> objects, use <span class=\"s1\">-positionsOfMutationsOfType()</span>; and if you are aiming for a sum of the selection coefficients of matching <span class=\"s1\">Mutation</span> objects, use <span class=\"s1\">-sumOfMutationsOfType()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.<span class=\"s5\"><span class=\"Apple-converted-space\">  </span>See also </span><span class=\"s6\">substitutionsOfType()</span><span class=\"s5\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (is)nucleotides([Ni$ start = NULL], [Ni$ end = NULL], [string$ format = \"string\"])</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns the nucleotide sequence for the haplosome.<span class=\"Apple-converted-space\">  </span>This is the current ancestral sequence, as would be returned by the </span><span class=\"s4\">Chromosome</span><span class=\"s3\"> method </span><span class=\"s4\">ancestralNucleotides()</span><span class=\"s3\">, with the nucleotides for any nucleotide-based mutations in the haplosome overlaid.<span class=\"Apple-converted-space\">  </span>The range of the returned sequence may be constrained by a start position given in </span><span class=\"s4\">start</span><span class=\"s3\"> and/or an end position given in </span><span class=\"s4\">end</span><span class=\"s3\">; nucleotides will be returned from </span><span class=\"s4\">start</span><span class=\"s3\"> to </span><span class=\"s4\">end</span><span class=\"s3\">, inclusive.<span class=\"Apple-converted-space\">  </span>The default value of </span><span class=\"s4\">NULL</span><span class=\"s3\"> for </span><span class=\"s4\">start</span><span class=\"s3\"> and </span><span class=\"s4\">end</span><span class=\"s3\"> represent the first and last base positions of the chromosome, respectively.</span></p>\n<p class=\"p6\"><span class=\"s3\">The format of the returned sequence is controlled by the </span><span class=\"s4\">format</span><span class=\"s3\"> parameter.<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"string\"</span><span class=\"s3\"> will return the sequence as a singleton </span><span class=\"s4\">string</span><span class=\"s3\"> (e.g., </span><span class=\"s4\">\"TATA\"</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"char\"</span><span class=\"s3\"> will return a </span><span class=\"s4\">string</span><span class=\"s3\"> vector with one element per nucleotide (e.g., </span><span class=\"s4\">\"T\"</span><span class=\"s3\">, </span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"T\"</span><span class=\"s3\">, </span><span class=\"s4\">\"A\"</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"integer\"</span><span class=\"s3\"> will return an </span><span class=\"s4\">integer</span><span class=\"s3\"> vector with values A=</span><span class=\"s4\">0</span><span class=\"s3\">, C=</span><span class=\"s4\">1</span><span class=\"s3\">, G=</span><span class=\"s4\">2</span><span class=\"s3\">, T=</span><span class=\"s4\">3</span><span class=\"s3\"> (e.g., </span><span class=\"s4\">3</span><span class=\"s3\">, </span><span class=\"s4\">0</span><span class=\"s3\">, </span><span class=\"s4\">3</span><span class=\"s3\">, </span><span class=\"s4\">0</span><span class=\"s3\">).<span class=\"Apple-converted-space\">  </span>A format of </span><span class=\"s4\">\"codon\"</span><span class=\"s3\"> will return an </span><span class=\"s4\">integer</span><span class=\"s3\"> vector with values from </span><span class=\"s4\">0</span><span class=\"s3\"> to </span><span class=\"s4\">63</span><span class=\"s3\">, based upon successive nucleotide triplets in the sequence (which, for this format, must have a length that is a multiple of three); see the </span><span class=\"s4\">ancestralNucleotides()</span><span class=\"s3\"> documentation for details.<span class=\"Apple-converted-space\">  </span>If the sequence returned is likely to be long, the </span><span class=\"s4\">\"string\"</span><span class=\"s3\"> format will be the most memory-efficient, and may also be the fastest (but may be harder to work with).</span></p>\n<p class=\"p6\"><span class=\"s3\">Several helper functions are provided for working with sequences, such as </span><span class=\"s4\">nucleotideCounts()</span><span class=\"s3\"> to get the counts of A/C/G/T nucleotides in a sequence, </span><span class=\"s4\">nucleotideFrequencies()</span><span class=\"s3\"> to get the same information as frequencies, and </span><span class=\"s4\">codonsToAminoAcids()</span><span class=\"s3\"> to convert a codon sequence (such as provided by the codon format described above) to an amino acid sequence.</span></p>\n<p class=\"p3\">+ (void)outputHaplosomes([Ns$ filePath = NULL], [logical$ append = F]<span class=\"s5\">, [logical$ objectTags = F]</span>)</p>\n<p class=\"p6\">Output the target haplosomes in SLiM’s native format.<span class=\"Apple-converted-space\">  </span>This low-level output method may be used to output any sample of <span class=\"s1\">Haplosome</span> objects associated with a single chromosome.<span class=\"Apple-converted-space\">  </span>The Eidos function <span class=\"s1\">sample()</span> may be useful for constructing custom samples, as may the SLiM class <span class=\"s1\">Individual</span>.<span class=\"Apple-converted-space\">  </span>For output of a sample from a single <span class=\"s1\">Subpopulation</span>, the <span class=\"s1\">outputSample()</span> method of <span class=\"s1\">Subpopulation</span> may be more straightforward to use.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output is directed to SLiM’s standard output.<span class=\"Apple-converted-space\">  </span>Otherwise, the output is sent to the file specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">objectTags</span> parameter may be used to request that tag values for objects be written out.<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity; if it turned on (<span class=\"s1\">T</span>), the <span class=\"s1\">tag</span> property values of all haplosomes and mutations in the output will be written.<span class=\"Apple-converted-space\">  </span>If there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with <span class=\"s1\">setValue()</span>, and so forth, you should persist that state in separate files using calls such as <span class=\"s1\">writeFile()</span>.</p>\n<p class=\"p4\">See <span class=\"s1\">output</span><span class=\"s6\">HaplosomesTo</span><span class=\"s1\">MS()</span> and <span class=\"s1\">output</span><span class=\"s6\">HaplosomesTo</span><span class=\"s1\">VCF()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p3\">+ (void)output<span class=\"s5\">HaplosomesTo</span>MS([Ns$ filePath = NULL], [logical$ append = F]<span class=\"s7\">, [logical$ filterMonomorphic = F]</span>)</p>\n<p class=\"p6\">Output the target haplosomes in MS format.<span class=\"Apple-converted-space\">  </span>This low-level output method may be used to output any sample of <span class=\"s1\">Haplosome</span> objects associated with a single chromosome.<span class=\"Apple-converted-space\">  </span>The Eidos function <span class=\"s1\">sample()</span> may be useful for constructing custom samples, as may the SLiM class <span class=\"s1\">Individual</span>.<span class=\"Apple-converted-space\">  </span>For output of a sample from a single <span class=\"s1\">Subpopulation</span>, the <span class=\"s1\">outputMSSample()</span> of <span class=\"s1\">Subpopulation</span> may be more straightforward to use.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output is directed to SLiM’s standard output.<span class=\"Apple-converted-space\">  </span>Otherwise, the output is sent to the file specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>Positions in the output will span the interval [0,1].</p>\n<p class=\"p6\"><span class=\"s3\">If </span><span class=\"s4\">filterMonomorphic</span><span class=\"s3\"> is </span><span class=\"s4\">F</span><span class=\"s3\"> (the default), all mutations that are present in the sample will be included in the output.<span class=\"Apple-converted-space\">  </span>This means that some mutations may be included that are actually monomorphic within the sample (i.e., that exist in <i>every</i> sampled haplosome, and are thus apparently fixed).<span class=\"Apple-converted-space\">  </span>These may be filtered out with </span><span class=\"s4\">filterMonomorphic = T</span><span class=\"s3\"> if desired; note that this option means that some mutations that do exist in the sampled haplosomes might not be included in the output, simply because they exist in every sampled haplosome.</span></p>\n<p class=\"p4\">See <span class=\"s1\">outputHaplosomes()</span> and <span class=\"s1\">output</span><span class=\"s6\">HaplosomesTo</span><span class=\"s1\">VCF()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\"><span class=\"s5\">+ (void)output</span>HaplosomesTo<span class=\"s5\">VCF([Ns$ filePath = NULL], [logical$ outputMultiallelics = T], [logical$ append = F]</span><span class=\"s3\">, [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T]</span>, [logical$ groupAsIndividuals = T]<span class=\"s5\">)</span></p>\n<p class=\"p6\">Output the target haplosomes in VCF format.<span class=\"Apple-converted-space\">  </span>This low-level output method may be used to output any sample of <span class=\"s1\">Haplosome</span> objects associated with a single chromosome.<span class=\"Apple-converted-space\">  </span>The Eidos function <span class=\"s1\">sample()</span> may be useful for constructing custom samples, as may the SLiM class <span class=\"s1\">Individual</span>.<span class=\"Apple-converted-space\">  </span>For output of a sample from a single <span class=\"s1\">Subpopulation</span>, the <span class=\"s1\">outputVCFSample()</span> method of <span class=\"s1\">Subpopulation</span> may be more straightforward to use.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output is directed to SLiM’s standard output.<span class=\"Apple-converted-space\">  </span>Otherwise, the output is sent to the file specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.</p>\n<p class=\"p6\">The parameters <span class=\"s1\">outputMultiallelics</span>, <span class=\"s1\">simplifyNucleotides</span>, and <span class=\"s1\">outputNonnucleotides</span> affect the format of the output produced.</p>\n<p class=\"p6\">With <span class=\"s1\">groupAsIndividuals</span> being <span class=\"s1\">T</span> (the default), the target haplosome vector should be structured as if it represents all of the haplosomes for some set of individuals, for a single focal chromosome.<span class=\"Apple-converted-space\">  </span>All haplosomes for the focal chromosome should be present, including null haplosomes.<span class=\"Apple-converted-space\">  </span>It should provide all of the haplosomes for the first individual (for the chosen chromosome); then for the second individual; and so forth.<span class=\"Apple-converted-space\">  </span>The haplosomes in the target haplosome vector do not, in fact, need to belong to individuals in SLiM following this pattern; they just need to specify well-formed individuals in the VCF output.<span class=\"Apple-converted-space\">  </span>For an intrinsically haploid chromosome, the target haplosome for a given output individual is used to generate a haploid call (<span class=\"s1\">0</span> or <span class=\"s1\">1</span>) for that individual; if the haplosome is a null haplosome, the call will be <span class=\"s1\">~</span> (an ASCII tilde). For example, calls for (non-null) Y haplosomes in males will be emitted as <span class=\"s1\">0</span> or <span class=\"s1\">1</span>, whereas calls for the (null) Y haplosomes in females will be emitted as <span class=\"s1\">~</span>.<span class=\"Apple-converted-space\">  </span>For an intrinsically diploid chromosome, the pair of target haplosomes for a given individual is used to generate a call for that individual, but null haplosomes are allowed (in the patterns expected by SLiM given the chromosome type).<span class=\"Apple-converted-space\">  </span>For example, a pair of non-null haplosomes for an X chromosome will be emitted as a diploid call (such as <span class=\"s1\">1|0</span>) for a female (XX), but if the second haplosome of the pair is a null haplosome, the pair will be emitted as a haploid call (<span class=\"s1\">0</span> or <span class=\"s1\">1</span>) for a male (X).<span class=\"Apple-converted-space\">  </span>If the first haplosome of the pair were a null haplosome for an X chromosome, an error would be raised, since that is not an allowed pattern in SLiM (as discussed in the documentation for the <span class=\"s1\">Chromosome</span> class).<span class=\"Apple-converted-space\">  </span>For a diploid autosome of type <span class=\"s1\">\"A\"</span>, however, any pattern is legal, but the VCF format cannot distinguish between a non-null haplosome first and a null haplosome second, versus a null haplosome first and a non-null haplosome second; both will be emitted as a haploid call (<span class=\"s1\">0</span> or <span class=\"s1\">1</span>).<span class=\"Apple-converted-space\">  </span>For a diploid autosome of type <span class=\"s1\">\"A\"</span>, if both haplosomes are null the call will be <span class=\"s1\">~</span>.<span class=\"Apple-converted-space\">  </span>The VCF specification does not actually seem to discuss sex chromosomes, but this design is intended to follow standard usage.</p>\n<p class=\"p6\">With <span class=\"s1\">groupAsIndividuals</span> being <span class=\"s1\">F</span>, the focal chromosome is treated as being intrinsically haploid whether it is or not; each haplosome will be called as a haploid sample whether the chromosome type is diploid or haploid.<span class=\"Apple-converted-space\">  </span>This provides more detailed and accurate information; the exact state of each haplosome will be represented with either <span class=\"s1\">0</span>, <span class=\"s1\">1</span>, or (for null haplosomes) <span class=\"s1\">~</span>, rather than the state of a pair of haplosomes being represented as a single call in a way that can sometimes be ambiguous, as discussed above.<span class=\"Apple-converted-space\">  </span>However, the resulting output might confuse some VCF parsers that expect diploid calls for individuals, and it will not be as obvious which calls in the output belong to a given diploid individual.</p>\n<p class=\"p6\">See <span class=\"s1\">outputHaplosomesToMS()</span> and <span class=\"s1\">outputHaplosomes()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p3\">– (integer)positionsOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns the positions of mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the haplosome.<span class=\"Apple-converted-space\">  </span>If you need a vector of the matching <span class=\"s1\">Mutation</span> objects, rather than just positions, use <span class=\"s1\">-mutationsOfType()</span>.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p5\"><span class=\"s3\">+ (</span><span class=\"s5\">object</span><span class=\"s3\">&lt;Mutation&gt;)readHaplosomesFromMS(string$ filePath, io&lt;MutationType&gt;$ mutationType)</span></p>\n<p class=\"p6\">Read new mutations from the MS format file at <span class=\"s1\">filePath</span> and add them to the target haplosomes.<span class=\"Apple-converted-space\">  </span>The number of target haplosomes must match the number of haplosomes represented in the MS file, and all target haplosomes must be associated with the same chromosome, and must not be null haplosomes.<span class=\"Apple-converted-space\">  </span>The target haplosomes correspond, in order, to the call lines in the MS file.<span class=\"Apple-converted-space\">  </span>To read into all of the non-null haplosomes in a given subpopulation <span class=\"s1\">pN</span> in a single-chromosome model, simply call <span class=\"s1\">pN.haplosomesNonNull.</span><span class=\"s4\">readHaplosomesFromMS</span><span class=\"s1\">()</span>, assuming the subpopulation’s size matches that of the MS file.<span class=\"Apple-converted-space\">  </span>A vector containing all of the mutations created by <span class=\"s4\">readHaplosomesFromMS</span><span class=\"s1\">()</span> is returned.</p>\n<p class=\"p6\">Each mutation is created at the position specified in the file, using the mutation type given by <span class=\"s1\">mutationType</span>.<span class=\"Apple-converted-space\">  </span>Positions are expected to be in [0,1], and are scaled to the length of the chromosome by multiplying by the last valid base position of the chromosome (i.e., one less than the chromosome length).<span class=\"Apple-converted-space\">  </span>Selection coefficients are drawn from the mutation type.<span class=\"Apple-converted-space\">  </span>The population of origin for each mutation is set to <span class=\"s1\">-1</span>, and the tick of origin is set to the current tick.<span class=\"Apple-converted-space\">  </span>In a nucleotide-based model, if <span class=\"s1\">mutationType</span> is nucleotide-based, a random nucleotide different from the ancestral nucleotide at the position will be chosen with equal probability.</p>\n<p class=\"p5\"><span class=\"s3\">+ (</span><span class=\"s5\">object</span><span class=\"s3\">&lt;Mutation&gt;)readHaplosomesFromVCF(string$ filePath, [Nio&lt;MutationType&gt;$ mutationType = NULL])</span></p>\n<p class=\"p6\">Read new mutations from the VCF format file at <span class=\"s1\">filePath</span> and add them to the target haplosomes.<span class=\"Apple-converted-space\">  </span>The number of target haplosomes must match the number of haplosomes represented in the VCF file (i.e., two times the number of diploid samples plus one times the number of haploid samples).<span class=\"Apple-converted-space\">  </span>To read into all of the haplosomes in a given subpopulation <span class=\"s1\">pN</span> in a single-chromosome model, simply call <span class=\"s1\">pN.haplosomes.readHaplosomesFromVCF()</span>, assuming the subpopulation’s size matches that of the VCF file taking ploidy into account.<span class=\"Apple-converted-space\">  </span>A vector containing all of the mutations created by <span class=\"s1\">readHaplosomesFromVCF()</span> is returned.</p>\n<p class=\"p6\">This method and the <span class=\"s1\">readIndividualsFromVCF()</span> method of <span class=\"s1\">Individual</span> provide two alternative ways of reading VCF data, focused in the perspective of either haplosomes (this method) or individuals (the <span class=\"s1\">Individual</span> method).<span class=\"Apple-converted-space\">  </span>See the documentation of <span class=\"s1\">readIndividualsFromVCF()</span> for discussion of the pros and cons of each approach; that discussion will not be duplicated here.</p>\n<p class=\"p6\">SLiM’s VCF parsing is quite primitive.<span class=\"Apple-converted-space\">  </span>The header is parsed only inasmuch as SLiM looks to see whether SLiM-specific VCF fields are defined or not; the rest of the header information is ignored.<span class=\"Apple-converted-space\">  </span>Call lines are assumed to follow the format:</p>\n<p class=\"p8\">#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT i0...iN</p>\n<p class=\"p6\">The <span class=\"s1\">CHROM</span> field is largely ignored, but <span class=\"s1\">readHaplosomesFromVCF()</span> does check that its value is identical across all call lines, to prevent the genetic data for more than one chromosome from being glommed together nonsensically; the input VCF file must contain data for just a single chromosome.<span class=\"Apple-converted-space\">  </span>In single-chromosome models the <span class=\"s1\">CHROM</span> field is not otherwise checked or validated.<span class=\"Apple-converted-space\">  </span>In multi-chromosome models, <span class=\"s1\">readHaplosomesFromVCF()</span> imposes some additional restrictions.<span class=\"Apple-converted-space\">  </span>First, all haplosomes in the target vector must be associated with the same single focal chromosome.<span class=\"Apple-converted-space\">  </span>Second, the <span class=\"s1\">CHROM</span> field for every call line in the VCF file must match the <span class=\"s1\">symbol</span> property of that focal chromosome; the VCF file must indicate that it specifically matches the focal chromosome associated with the target haplosomes.<span class=\"Apple-converted-space\">  </span>These restrictions boil down to the fact that <span class=\"s1\">readHaplosomesFromVCF()</span> only reads data for a single chromosome.<span class=\"Apple-converted-space\">  </span>If you wish to read multi-chromosome VCF data into a multi-chromosome SLiM model, the <span class=\"s1\">readIndividualsFromVCF()</span> method provided by the <span class=\"s1\">Individual</span> class supports that functionality (because it can work at the level of individuals, rather than haplosomes, making it possible to match calls to the corresponding haplosomes in a reasonable way).<span class=\"Apple-converted-space\">  </span>Alternatively, you can call <span class=\"s1\">readHaplosomesFromVCF()</span> multiple times to read data for different chromosomes one by one.</p>\n<p class=\"p6\">The <span class=\"s1\">ID</span>, <span class=\"s1\">QUAL</span>, <span class=\"s1\">FILTER</span>, and <span class=\"s1\">FORMAT</span> fields are ignored, and information in the genotype fields beyond the <span class=\"s1\">GT</span> genotype subfield are also ignored.<span class=\"Apple-converted-space\">  </span>SLiM’s own VCF annotations are honored; in particular, mutations will be created using the given values of <span class=\"s1\">MID</span>, <span class=\"s1\">S</span>, <span class=\"s1\">PO</span>, <span class=\"s1\">TO</span>, and <span class=\"s1\">MT</span> if those subfields are present, and <span class=\"s1\">DOM</span>, if it is present, must match the dominance coefficient of the mutation type.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">mutationType</span> (a <span class=\"s1\">MutationType</span> object or id) will be used for any mutations that have no supplied mutation type id in the <span class=\"s1\">MT</span> subfield; if <span class=\"s1\">mutationType</span> would be used but is <span class=\"s1\">NULL</span> an error will result.<span class=\"Apple-converted-space\">  </span>Mutation IDs supplied in <span class=\"s1\">MID</span> will be used if no mutation IDs have been used in the simulation so far; if any have been used, it is difficult for SLiM to guarantee that there are no conflicts, so a warning will be emitted and the <span class=\"s1\">MID</span> values will be ignored.<span class=\"Apple-converted-space\">  </span>If selection coefficients are not supplied with the <span class=\"s1\">S</span> subfield, they will be drawn from the mutation type used for the mutation.<span class=\"Apple-converted-space\">  </span>If a population of origin is not supplied with the <span class=\"s1\">PO</span> subfield, <span class=\"s1\">-1</span> will be used.<span class=\"Apple-converted-space\">  </span>If a tick of origin is not supplied with the <span class=\"s1\">TO</span> subfield (or a generation of origin <span class=\"s1\">GO</span> field, which was the SLiM convention before SLiM 4), the current tick will be used.</p>\n<p class=\"p6\"><span class=\"s1\">REF</span> and <span class=\"s1\">ALT</span> must always be comprised of simple nucleotides (<span class=\"s1\">A</span>/<span class=\"s1\">C</span>/<span class=\"s1\">G</span>/<span class=\"s1\">T</span>) rather than values representing indels or other complex states.<span class=\"Apple-converted-space\">  </span>Beyond this, the handling of the <span class=\"s1\">REF</span> and <span class=\"s1\">ALT</span> fields depends upon several factors.<span class=\"Apple-converted-space\">  </span>In non-nucleotide-based models, we have the first case: (1) These fields are ignored, although they are still checked for conformance.<span class=\"Apple-converted-space\">  </span>In nucleotide-based models, when a header definition for SLiM’s <span class=\"s1\">NONNUC</span> tag is present (as when nucleotide-based output is generated by SLiM) there are two further possibilities, given as (2) and (3) here: (2) If a <span class=\"s1\">NONNUC</span> field is present in the <span class=\"s1\">INFO</span> field the call line is taken to represent a non-nucleotide-based mutation, and <span class=\"s1\">REF</span> and <span class=\"s1\">ALT</span> are again ignored; in this case the mutation type used must be non-nucleotide-based.<span class=\"Apple-converted-space\">  </span>(3) If a <span class=\"s1\">NONNUC</span> field is <i>not</i> present the call line is taken to represent a nucleotide-based mutation; in this case, the mutation type used must be nucleotide-based, and the specified reference nucleotide must match the existing ancestral nucleotide at the given position.<span class=\"Apple-converted-space\">  </span>Finally, in nucleotide-based models, when a header definition for SLiM’s <span class=\"s1\">NONNUC</span> tag is <i>not</i> present (as when loading a non-SLiM-generated VCF file), there is a remaining possibility: (4) The mutation type used will govern the way nucleotides are handled.<span class=\"Apple-converted-space\">  </span>In this case, if the mutation type used for a mutation is nucleotide-based, the nucleotide provided in the VCF file for that allele will be used, whereas if the mutation type is non-nucleotide-based, the nucleotide provided will be ignored.</p>\n<p class=\"p6\">If multiple alleles using the same nucleotide at the same position are specified in the VCF file, a separate mutation will be created for each, mirroring SLiM’s behavior with independent mutational lineages when writing VCF.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">MULTIALLELIC</span> flag is ignored by <span class=\"s1\">readHaplosomesFromVCF()</span>; call lines for mutations at the same base position in the same haplosome will result in stacked mutations whether or not <span class=\"s1\">MULTIALLELIC</span> is present.</p>\n<p class=\"p6\">The target haplosomes correspond, in order, to the haploid or diploid calls provided for <span class=\"s1\">i0</span>…<span class=\"s1\">iN</span> (the sample IDs) in the VCF file.<span class=\"Apple-converted-space\">  </span>Null haplosomes in the target vector will be skipped, and will not be used to correspond to any of the calls for <span class=\"s1\">i0</span>…<span class=\"s1\">iN</span>; however, care should be taken in this case that the haplosomes in the VCF file correspond to the target haplosomes in the manner desired.</p>\n<p class=\"p6\">A call of <span class=\"s1\">~</span> (an ASCII tilde character) for an individual <span class=\"s1\">i0</span>…<span class=\"s1\">iN</span> is taken to indicate that that individual possesses no genetic information for the chromosome; it lacks that chromosome entirely.<span class=\"Apple-converted-space\">  </span>For example, if the VCF file represents Y-chromosome data, female individuals should have calls of <span class=\"s1\">~</span>.<span class=\"Apple-converted-space\">  </span>This is treated differently than a call of <span class=\"s1\">0</span><span class=\"Apple-converted-space\">  </span>or <span class=\"s1\">0|0</span>; a call of <span class=\"s1\">0</span> matches that call to a non-null target haplosome (but does not add the called mutation to that haplosome), and a call of <span class=\"s1\">0|0</span> matches two non-null target haplosomes (but does not add the called mutation to either), whereas a call of <span class=\"s1\">~</span> is simply skipped, without matching to any haplosome in the target vector, mirroring the fact that <span class=\"s1\">readHaplosomesFromVCF()</span> skips over null haplosomes in the target haplosome vector.<span class=\"Apple-converted-space\">  </span>(When reading Y-chromosome data, a female’s null Y haplosome could be omitted from the target haplosome vector, or it could be present since it would be skipped anyway – as stated above, all null haplosomes are skipped.)<span class=\"Apple-converted-space\">  </span>Note that these semantics using <span class=\"s1\">~</span> are non-standard; the VCF standard does not seem to say anything about how sex chromosomes should be represented (or anything about other types of chromosomes that might be absent from some individuals), so the usage of <span class=\"s1\">~</span> was invented for SLiM.<span class=\"Apple-converted-space\">  </span>This is an area where standardization is very much needed.</p>\n<p class=\"p5\"><span class=\"s3\">+ (void)removeMutations([No&lt;Mutation&gt; mutations = NULL], [logical$ substitute = F])</span></p>\n<p class=\"p6\">Remove the mutations in <span class=\"s1\">mutations</span> from the target haplosomes, if they are present (if they are not present, they will be ignored).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">NULL</span> is passed for <span class=\"s1\">mutations</span> (which is the default), then all mutations will be removed from the target haplosomes; in this case, <span class=\"s1\">substitute</span> must be <span class=\"s1\">F</span> (a specific vector of mutations to be substituted is required).<span class=\"Apple-converted-space\">  </span>Note that the <span class=\"s1\">Mutation</span> objects removed remain valid, and will still be in the simulation’s mutation registry (i.e., will be returned by the <span class=\"s1\">Species</span> property <span class=\"s1\">mutations</span>), until the next tick.<span class=\"Apple-converted-space\">  </span>All target haplosomes and all mutations in <span class=\"s1\">mutations</span> must be associated with the same <span class=\"s1\">Chromosome</span> object; attempting to remove a mutation from a haplosome associated with a different chromosome will raise an error.</p>\n<p class=\"p6\"><span class=\"s3\">Removing mutations will normally affect the fitness values calculated at the end of the current tick; if you want current fitness values to be affected, you can call the </span><span class=\"s4\">Species</span><span class=\"s3\"> method </span><span class=\"s4\">recalculateFitness()</span><span class=\"s3\"> – but see the documentation of that method for caveats.</span></p>\n<p class=\"p6\"><span class=\"s3\">The optional parameter </span><span class=\"s4\">substitute</span><span class=\"s3\"> was added in SLiM 2.2, with a default of </span><span class=\"s4\">F</span><span class=\"s3\"> for backward compatibility.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">substitute</span><span class=\"s3\"> is </span><span class=\"s4\">T</span><span class=\"s3\">, </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects will be created for all of the removed mutations so that they are recorded in the simulation as having fixed, just as if they had reached fixation and been removed by SLiM’s own internal machinery.<span class=\"Apple-converted-space\">  </span>This will occur regardless of whether the mutations have in fact fixed, regardless of the </span><span class=\"s4\">convertToSubstitution</span><span class=\"s3\"> property of the relevant mutation types, and regardless of whether all copies of the mutations have even been removed from the simulation (making it possible to create </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects for mutations that are still segregating).<span class=\"Apple-converted-space\">  </span>It is up to the caller to perform whatever checks are necessary to preserve the integrity of the simulation’s records.<span class=\"Apple-converted-space\">  </span>Typically </span><span class=\"s4\">substitute</span><span class=\"s3\"> will only be set to </span><span class=\"s4\">T</span><span class=\"s3\"> in the context of calls like </span><span class=\"s4\">sim.subpopulations.haplosomes.removeMutations(muts, T)</span><span class=\"s3\">, such that the substituted mutations are guaranteed to be entirely removed from circulation.<span class=\"Apple-converted-space\">  </span>As mentioned above, </span><span class=\"s4\">substitute</span><span class=\"s3\"> may not be </span><span class=\"s4\">T</span><span class=\"s3\"> if </span><span class=\"s4\">mutations</span><span class=\"s3\"> is </span><span class=\"s4\">NULL</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(float$)sumOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns the sum of the selection coefficients of all mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the haplosome.<span class=\"Apple-converted-space\">  </span>This is often useful in models that use a particular mutation type to represent QTLs with additive effects; in that context, <span class=\"s1\">sumOfMutationsOfType()</span> will provide the sum of the additive effects of the QTLs for the given mutation type.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.<span class=\"Apple-converted-space\">  </span>Note that this method also exists on <span class=\"s1\">Individual</span>, for cases in which the sum across both haplosomes of an individual is desired.</p>\n<p class=\"p1\"><b>5.5<span class=\"Apple-converted-space\">  </span>Class GenomicElement</b></p>\n<p class=\"p2\"><i>5.5.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>GenomicElement</i></span><i> properties</i></p>\n<p class=\"p3\">endPosition =&gt; (integer$)</p>\n<p class=\"p4\">The last position in the chromosome contained by this genomic element.</p>\n<p class=\"p3\">genomicElementType =&gt; (object&lt;GenomicElementType&gt;$)</p>\n<p class=\"p4\">The <span class=\"s1\">GenomicElementType</span> object that defines the behavior of this genomic element.</p>\n<p class=\"p3\">startPosition =&gt; (integer$)</p>\n<p class=\"p4\">The first position in the chromosome contained by this genomic element.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p2\"><i>5.5.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>GenomicElement</i></span><i> methods</i></p>\n<p class=\"p3\">– (void)setGenomicElementType(io&lt;GenomicElementType&gt;$ genomicElementType)</p>\n<p class=\"p4\">Set the genomic element type used for a genomic element.<span class=\"Apple-converted-space\">  </span>The genomicElementType parameter should supply the new genomic element type for the element, either as a <span class=\"s1\">GenomicElementType</span> object or as an <span class=\"s1\">integer</span> identifier.<span class=\"Apple-converted-space\">  </span>The genomic element type for a genomic element is normally a constant in simulations, so be sure you know what you are doing.</p>\n<p class=\"p1\"><b>5.6<span class=\"Apple-converted-space\">  </span>Class GenomicElementType</b></p>\n<p class=\"p2\"><i>5.6.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>GenomicElementType</i></span><i> properties</i></p>\n<p class=\"p3\">color &lt;–&gt; (string$)</p>\n<p class=\"p4\">The color used to display genomic elements of this type in SLiMgui.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">color</span> is the empty string, <span class=\"s1\">\"\"</span>, SLiMgui’s default color scheme is used; this is the default for new <span class=\"s1\">GenomicElementType</span> objects.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this genomic element type; for genomic element type <span class=\"s1\">g3</span>, for example, this is <span class=\"s1\">3</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">mutationFractions =&gt; (float)</p>\n<p class=\"p4\">For each <span class=\"s1\">MutationType</span> represented in this genomic element type, this property has the corresponding fraction of all mutations that will be drawn from that <span class=\"s1\">MutationType</span><span class=\"s2\">.</span></p>\n<p class=\"p5\"><span class=\"s3\">mutationMatrix =&gt; (float)</span></p>\n<p class=\"p6\"><span class=\"s3\">The nucleotide mutation matrix used for this genomic element type, set up by </span><span class=\"s4\">initializeGenomicElementType()</span><span class=\"s3\"> and </span><span class=\"s4\">setMutationMatrix()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This property is only defined in nucleotide-based models; it is unavailable otherwise.</span></p>\n<p class=\"p3\">mutationTypes =&gt; (object&lt;MutationType&gt;)</p>\n<p class=\"p4\">The <span class=\"s1\">MutationType</span> instances used by this genomic element type.</p>\n<p class=\"p3\">species =&gt; (object&lt;Species&gt;$)</p>\n<p class=\"p6\"><span class=\"s3\">The species to which the target object belongs.</span></p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to genomic element types.</p>\n<p class=\"p9\"><span class=\"s10\"><i>5.6.2<span class=\"Apple-converted-space\">  </span></i></span><i>GenomicElementType</i><span class=\"s10\"><i> methods</i></span></p>\n<p class=\"p3\">– (void)setMutationFractions(io&lt;MutationType&gt; mutationTypes, numeric proportions)</p>\n<p class=\"p4\">Set the mutation type fractions contributing to a genomic element type.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">mutationTypes</span> vector should supply the mutation types used by the genomic element (either as <span class=\"s1\">MutationType</span> objects or as <span class=\"s1\">integer</span> identifiers), and the <span class=\"s1\">proportions</span> vector should be of equal length, specifying the relative proportion of mutations that will be drawn from each corresponding type.<span class=\"Apple-converted-space\">  </span>This is normally a constant in simulations, so be sure you know what you are doing.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)setMutationMatrix(float mutationMatrix)</span></p>\n<p class=\"p6\"><span class=\"s3\">Sets a new nucleotide mutation matrix for the genomic element type.<span class=\"Apple-converted-space\">  </span>This replaces the mutation matrix originally set by </span><span class=\"s4\">initializeGenomicElementType()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This method may only be called in nucleotide-based models.</span></p>\n<p class=\"p1\"><b>5.7<span class=\"Apple-converted-space\">  </span>Class Individual</b></p>\n<p class=\"p2\"><i>5.7.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Individual</i></span><i> properties</i></p>\n<p class=\"p3\">age <span class=\"s7\">&lt;–&gt;</span> (integer$)</p>\n<p class=\"p6\">The age of the individual, measured in cycles.<span class=\"Apple-converted-space\">  </span>A newly generated offspring individual will have an age of <span class=\"s1\">0</span> in the same tick in which it was created.<span class=\"Apple-converted-space\">  </span>The age of every individual is incremented by one at the same point that its species cycle counter is incremented, at the end of the tick cycle, <i>if and only if</i> its species was active in that tick.<span class=\"Apple-converted-space\">  </span>The age of individuals may be changed; usually this only makes sense when setting up the initial state of a model, however.</p>\n<p class=\"p3\">color &lt;–&gt; (string$)</p>\n<p class=\"p6\">The color used to display the individual in SLiMgui.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span> (see the Eidos manual).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">color</span> is the empty string, <span class=\"s1\">\"\"</span>, SLiMgui’s default (fitness-based) color scheme is used; this is the default for new <span class=\"s1\">Individual</span> objects.<span class=\"Apple-converted-space\">  </span>Note that named colors will be converted to RGB internally, so the value of this property will always be a hexadecimal RGB color string (or <span class=\"s1\">\"\"</span>).</p>\n<p class=\"p5\"><span class=\"s3\">fitnessScaling &lt;–&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">A </span><span class=\"s4\">float</span><span class=\"s3\"> scaling factor applied to the individual’s fitness (i.e., the fitness value computed for the individual will be multiplied by this value).<span class=\"Apple-converted-space\">  </span>This provides a simple, fast way to modify the fitness of an individual; conceptually it is similar to returning a fitness effect for the individual from a </span><span class=\"s4\">fitnessEffect()</span><span class=\"s3\"> callback, but without the complexity and performance overhead of implementing such a callback.<span class=\"Apple-converted-space\">  </span>To scale the fitness of all individuals in a subpopulation by the same factor, see the </span><span class=\"s4\">fitnessScaling</span><span class=\"s3\"> property of </span><span class=\"s4\">Subpopulation</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The value of </span><span class=\"s4\">fitnessScaling</span><span class=\"s3\"> is reset to </span><span class=\"s4\">1.0</span><span class=\"s3\"> every tick, so that any scaling factor set lasts for only a single tick.<span class=\"Apple-converted-space\">  </span>This reset occurs immediately after fitness values are calculated, in both WF and nonWF models.</span></p>\n<p class=\"p5\">haploidGenome1 =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">A vector of all <span class=\"s1\">Haplosome</span> objects associated with this individual that are attributed to its first parent (the female parent, in sexual models).<span class=\"Apple-converted-space\">  </span>This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.<span class=\"Apple-converted-space\">  </span>The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>For chromosomes with two associated haplosomes (types <span class=\"s1\">\"A\"</span>, <span class=\"s1\">\"X\"</span>, <span class=\"s1\">\"Z\"</span>, <span class=\"s1\">\"H-\"</span>, and <span class=\"s1\">\"-Y\"</span>), the first haplosome is assumed to be from the first parent, and is thus included, whereas the second haplosome is assumed to be from the second parent and is thus not included.<span class=\"Apple-converted-space\">  </span>For chromosomes with one associated haplosome that is inherited from the female/first parent in one way or another (types <span class=\"s1\">\"W\"</span>, <span class=\"s1\">\"HF\"</span>, and <span class=\"s1\">\"FL\"</span>), that haplosome is always included.<span class=\"Apple-converted-space\">  </span>For type <span class=\"s1\">\"H\"</span>, the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is included.<span class=\"Apple-converted-space\">  </span>Other chromosome types (<span class=\"s1\">\"Y\"</span>, <span class=\"s1\">\"HM\"</span>, <span class=\"s1\">\"ML\"</span>) are never included.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">haploidGenome1NonNull</span> property and the <span class=\"s1\">haplosomesForChromosomes()</span> method.</p>\n<p class=\"p5\">haploidGenome1NonNull =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">This provides the same vector of haplosomes as the <span class=\"s1\">haploidGenome1</span> property, except that null haplosomes are not included in this property.<span class=\"Apple-converted-space\">  </span>This is a convenience shorthand, sometimes useful in models that involve null haplosomes.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">haplosomesForChromosomes()</span> method.</p>\n<p class=\"p5\">haploidGenome2 =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">A vector of all <span class=\"s1\">Haplosome</span> objects associated with this individual that are attributed to its second parent (the male parent, in sexual models).<span class=\"Apple-converted-space\">  </span>This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.<span class=\"Apple-converted-space\">  </span>The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>For chromosomes with two associated haplosomes (types <span class=\"s1\">\"A\"</span>, <span class=\"s1\">\"X\"</span>, <span class=\"s1\">\"Z\"</span>, <span class=\"s1\">\"H-\"</span>, and<span class=\"s1\">\"-Y\"</span>), the second haplosome is assumed to be from the second parent, and is thus included, whereas the first haplosome is assumed to be from the first parent and is thus not included.<span class=\"Apple-converted-space\">  </span>For chromosomes with one associated haplosome that is inherited from the male/second parent in one way or another (types <span class=\"s1\">\"Y\"</span>, <span class=\"s1\">\"HM\"</span>, and <span class=\"s1\">\"ML\"</span>), that haplosome is always included.<span class=\"Apple-converted-space\">  </span>For type <span class=\"s1\">\"H\"</span>, the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is not included.<span class=\"Apple-converted-space\">  </span>Other chromosome types (<span class=\"s1\">\"W\"</span>, <span class=\"s1\">\"HF\"</span>, <span class=\"s1\">\"FL\"</span>) are never included.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">haploidGenome2NonNull</span> property and the <span class=\"s1\">haplosomesForChromosomes()</span> method.</p>\n<p class=\"p5\">haploidGenome2NonNull =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">This provides the same vector of haplosomes as the <span class=\"s1\">haploidGenome2</span> property, except that null haplosomes are not included in this property.<span class=\"Apple-converted-space\">  </span>This is a convenience shorthand, sometimes useful in models that involve null haplosomes.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">haplosomesForChromosomes()</span> method.</p>\n<p class=\"p5\">haplosomes =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">A vector of all <span class=\"s1\">Haplosome</span> objects associated with this individual, in the order in which the chromosomes were defined for the species.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">haplosomesNonNull</span>, <span class=\"s1\">haploidGenome1</span>, <span class=\"s1\">haploidGenome1NonNull</span>, <span class=\"s1\">haploidGenome2</span>, and <span class=\"s1\">haploidGenome2NonNull</span> properties and the <span class=\"s1\">haplosomesForChromosomes()</span> method.</p>\n<p class=\"p5\">haplosomesNonNull =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">A vector of all <span class=\"s1\">Haplosome</span> objects associated with this individual, in the order in which the chromosomes were defined for the species (as with the <span class=\"s1\">haplosomes</span> property), but excluding any null haplosomes from the returned vector.<span class=\"Apple-converted-space\">  </span>This is a convenience shorthand, sometimes useful in models that involve null haplosomes.</p>\n<p class=\"p3\">index =&gt; (integer$)</p>\n<p class=\"p4\">The index of the individual in the <span class=\"s1\">individuals</span> vector of its <span class=\"s1\">Subpopulation</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">meanParentAge =&gt; (float$)</p>\n<p class=\"p6\">The average age of the parents of this individual, measured in cycles.<span class=\"Apple-converted-space\">  </span>Parentless individuals will have a <span class=\"s1\">meanParentAge</span> of <span class=\"s1\">0.0</span>.<span class=\"Apple-converted-space\">  </span>The mean parent age is determined when a new offspring is generated, from the <span class=\"s1\">age</span> property of the parent or parents involved in generating the offspring.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">addRecombinant()</span> and <span class=\"s1\">addMultiRecombinant()</span> that is somewhat complex; see those methods for details.</p>\n<p class=\"p5\"><span class=\"s3\">migrant =&gt; (logical$)</span></p>\n<p class=\"p6\"><span class=\"s3\">Set to </span><span class=\"s6\">T</span><span class=\"s3\"> if the individual is a recent migrant, </span><span class=\"s6\">F</span><span class=\"s3\"> otherwise.<span class=\"Apple-converted-space\">  </span>The definition of “recent” depends upon the model type (WF or nonWF).</span></p>\n<p class=\"p6\"><span class=\"s3\">In WF models, this flag is set at the point when a new child is generated if it is a migrant (i.e., if its source subpopulation is not the same as its subpopulation), and remains valid, with the same value, for the rest of the individual’s lifetime.</span></p>\n<p class=\"p6\"><span class=\"s3\">In nonWF models, this flag is </span><span class=\"s6\">F</span><span class=\"s3\"> for all new individuals, is set to </span><span class=\"s6\">F</span><span class=\"s3\"> in all individuals at the end of the reproduction tick cycle stage, and is set to </span><span class=\"s6\">T</span><span class=\"s3\"> on all individuals moved to a new subpopulation by</span><span class=\"s6\"> takeMigrants()</span><span class=\"s3\"> or a </span><span class=\"s6\">survival()</span><span class=\"s3\"> callback; the </span><span class=\"s6\">T</span><span class=\"s3\"> value set by </span><span class=\"s6\">takeMigrants()</span><span class=\"s3\"> or </span><span class=\"s6\">survival()</span><span class=\"s3\"> will remain until it is reset at the end of the next reproduction tick cycle stage.</span></p>\n<p class=\"p3\">pedigreeID =&gt; (integer$)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span> or tree-sequence recording is turned on with <span class=\"s1\">initializeTreeSeq()</span>, <span class=\"s1\">pedigreeID</span> is a unique non-negative identifier for each individual in a simulation, never re-used throughout the duration of the simulation run.<span class=\"Apple-converted-space\">  </span>If neither pedigree tracking nor tree-sequence recording is enabled, this property is unavailable.</p>\n<p class=\"p3\">pedigreeParentIDs =&gt; (integer)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">pedigreeParentIDs</span> contains the values of <span class=\"s1\">pedigreeID</span> that were possessed by the parents of an individual; it is thus a vector of two values.<span class=\"Apple-converted-space\">  </span>If pedigree tracking is not enabled, this property is unavailable.<span class=\"Apple-converted-space\">  </span>Parental values may be <span class=\"s1\">-1</span> if insufficient ticks have elapsed for that information to be available (because the simulation just started, or because a subpopulation is new).</p>\n<p class=\"p3\">pedigreeGrandparentIDs =&gt; (integer)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">pedigreeGrandparentIDs</span> contains the values of <span class=\"s1\">pedigreeID</span> that were possessed by the grandparents of an individual; it is thus a vector of four values.<span class=\"Apple-converted-space\">  </span>If pedigree tracking is not enabled, this property is unavailable.<span class=\"Apple-converted-space\">  </span>Grandparental values may be <span class=\"s1\">-1</span> if insufficient ticks have elapsed for that information to be available (because the simulation just started, or because a subpopulation is new).</p>\n<p class=\"p5\">reproductiveOutput =&gt; (integer$)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">reproductiveOutput</span> contains the number of offspring for which this individual has been a parent.<span class=\"Apple-converted-space\">  </span>If pedigree tracking is not enabled, this property is unavailable.<span class=\"Apple-converted-space\">  </span>If an individual is a parent by cloning or selfing, or as <i>both</i> parents for a biparental mating, this value is incremented by two.<span class=\"Apple-converted-space\">  </span>Involvement of an individual as a parent for an <span class=\"s1\">addRecombinant()</span> or <span class=\"s1\">addMultiRecombinant()</span> call does not change this property’s value, since the reproductive contribution in that case is unclear; one must conduct separate bookkeeping for that case if necessary, or use tree-sequence recording to infer it from the inheritance record.</p>\n<p class=\"p10\"><span class=\"s11\">See also the </span>Subpopulation<span class=\"s11\"> property </span>lifetimeReproductiveOutput<span class=\"s11\">.</span></p>\n<p class=\"p3\">sex =&gt; (string$)</p>\n<p class=\"p4\">The sex of the individual.<span class=\"Apple-converted-space\">  </span>This will be <span class=\"s1\">\"H\"</span> if sex is not enabled in the simulation (i.e., for hermaphrodites), otherwise <span class=\"s1\">\"F\"</span> or <span class=\"s1\">\"M\"</span> as appropriate.</p>\n<p class=\"p3\">spatialPosition =&gt; (float)</p>\n<p class=\"p4\">The spatial position of the individual.<span class=\"Apple-converted-space\">  </span>The length of the <span class=\"s1\">spatialPosition</span> property (the number of coordinates in the spatial position of an individual) depends upon the spatial dimensionality declared with <span class=\"s1\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>If the spatial dimensionality is zero (as it is by default), it is an error to access this property.<span class=\"Apple-converted-space\">  </span>The elements of this property are identical to the values of the <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">z</span> properties (if those properties are encompassed by the spatial dimensionality of the simulation).<span class=\"Apple-converted-space\">  </span>In other words, if the declared dimensionality is <span class=\"s1\">\"xy\"</span><span class=\"s2\">,</span> the <span class=\"s1\">individual.spatialPosition</span> property is equivalent to <span class=\"s1\">c(individual.x, individual.y)</span>; <span class=\"s1\">individual.z</span> is not used since it is not encompassed by the simulation’s dimensionality.</p>\n<p class=\"p3\">subpopulation =&gt; (object&lt;Subpopulation&gt;$)</p>\n<p class=\"p4\">The <span class=\"s1\">Subpopulation</span> object to which the individual belongs.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value (as opposed to <span class=\"s1\">tagF</span>, which is of type <span class=\"s1\">float</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to individuals.<span class=\"Apple-converted-space\">  </span><span class=\"s5\">Note that the </span><span class=\"s6\">Individual</span><span class=\"s5\"> objects used by SLiM are new for every new offspring, so the </span><span class=\"s6\">tag</span><span class=\"s5\"> value of each new offspring generated in each tick will be initially undefined.</span></p>\n<p class=\"p3\">tagF &lt;–&gt; (float$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">float</span> value (as opposed to <span class=\"s1\">tag</span>, which is of type <span class=\"s1\">integer</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagF</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagF</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to individuals.</p>\n<p class=\"p4\">Note that at present, although many classes in SLiM have an <span class=\"s1\">integer</span>-type <span class=\"s1\">tag</span> property, only <span class=\"s1\">Individual</span> has a <span class=\"s1\">float</span>-type <span class=\"s1\">tagF</span> property, because attaching model state to individuals seems to be particularly common and useful.<span class=\"Apple-converted-space\">  </span>If a <span class=\"s1\">tagF</span> property would be helpful on another class, it would be easy to add.</p>\n<p class=\"p4\">See the description of the <span class=\"s1\">tag</span> property above for additional comments.</p>\n<p class=\"p5\">tagL0 &lt;–&gt; (logical$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">logical</span> value (see also <span class=\"s1\">tag</span> and <span class=\"s1\">tagF</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL0</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL0</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to individuals.</p>\n<p class=\"p5\">tagL1 &lt;–&gt; (logical$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">logical</span> value (see also <span class=\"s1\">tag</span> and <span class=\"s1\">tagF</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL1</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL1</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to individuals.</p>\n<p class=\"p5\">tagL2 &lt;–&gt; (logical$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">logical</span> value (see also <span class=\"s1\">tag</span> and <span class=\"s1\">tagF</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL2</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL2</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to individuals.</p>\n<p class=\"p5\">tagL3 &lt;–&gt; (logical$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">logical</span> value (see also <span class=\"s1\">tag</span> and <span class=\"s1\">tagF</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL3</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL3</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to individuals.</p>\n<p class=\"p5\">tagL4 &lt;–&gt; (logical$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">logical</span> value (see also <span class=\"s1\">tag</span> and <span class=\"s1\">tagF</span>).<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL4</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tagL4</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to individuals.</p>\n<p class=\"p3\">uniqueMutations =&gt; (object&lt;Mutation&gt;)</p>\n<p class=\"p6\">All of the <span class=\"s1\">Mutation</span> objects present in this individual.<span class=\"Apple-converted-space\">  </span>Mutations present in homologous haplosomes will occur only once in this property, and the mutations for a given chromosome will be given in sorted order by <span class=\"s1\">position</span>, so in single-chromosome simulations this property is similar to <span class=\"s1\">sortBy(unique(individual.haplosomes.mutations), \"position\")</span>.<span class=\"Apple-converted-space\">  </span>(Even with a single chromosome it is not identical to that call, since if multiple mutations exist at the exact same position, they might be sorted differently by this method than they would be by <span class=\"s1\">sortBy()</span>.)<span class=\"Apple-converted-space\">  </span>This method is provided primarily for speed; it executes much faster than the Eidos equivalent above.<span class=\"Apple-converted-space\">  </span>Indeed, it is faster than just <span class=\"s1\">individual.haplosomes.mutations</span>, and gives uniquing and sorting on top of that, so it is advantageous unless duplicate entries for homozygous mutations are actually needed.<span class=\"Apple-converted-space\">  </span>For more flexibility, see the method <span class=\"s1\">mutationsFromHaplosomes()</span>.</p>\n<p class=\"p5\">x &lt;–&gt; (float$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">float</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">x</span> is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">x</span> is not used by SLiM unless the optional “continuous space” facility is enabled with the <span class=\"s1\">dimensionality</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span>, in which case <span class=\"s1\">x</span> will be understood to represent the <i>x</i> coordinate of the individual in space.<span class=\"Apple-converted-space\">  </span>If continuous space is not enabled, you may use <span class=\"s1\">x</span> as an additional tag value of type <span class=\"s1\">float</span>.</p>\n<p class=\"p5\">xy =&gt; (float)</p>\n<p class=\"p6\">This property provides joint read-only access to the <span class=\"s1\">x</span> and <span class=\"s1\">y</span> properties; they are returned as a two-element <span class=\"s1\">float</span> vector.<span class=\"Apple-converted-space\">  </span>This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.<span class=\"Apple-converted-space\">  </span>See the documentation for the separate properties <span class=\"s1\">x</span> and <span class=\"s1\">y</span> for further comments.</p>\n<p class=\"p5\">xyz =&gt; (float)</p>\n<p class=\"p6\">This property provides joint read-only access to the <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">z</span> properties; they are returned as a three-element <span class=\"s1\">float</span> vector.<span class=\"Apple-converted-space\">  </span>This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.<span class=\"Apple-converted-space\">  </span>See the documentation for the separate properties <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">z</span> for further comments.</p>\n<p class=\"p5\">xz =&gt; (float)</p>\n<p class=\"p6\">This property provides joint read-only access to the <span class=\"s1\">x</span> and <span class=\"s1\">z</span> properties; they are returned as a two-element <span class=\"s1\">float</span> vector.<span class=\"Apple-converted-space\">  </span>This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.<span class=\"Apple-converted-space\">  </span>See the documentation for the separate properties <span class=\"s1\">x</span> and <span class=\"s1\">z</span> for further comments.</p>\n<p class=\"p5\">y &lt;–&gt; (float$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">float</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">y</span> is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">y</span> is not used by SLiM unless the optional “continuous space” facility is enabled with the <span class=\"s1\">dimensionality</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span>, in which case <span class=\"s1\">y</span> will be understood to represent the <i>y</i> coordinate of the individual in space (if the dimensionality is <span class=\"s1\">\"xy\"</span> or <span class=\"s1\">\"xyz\"</span>).<span class=\"Apple-converted-space\">  </span>If continuous space is not enabled, or the dimensionality is not <span class=\"s1\">\"xy\"</span> or <span class=\"s1\">\"xyz\"</span>, you may use <span class=\"s1\">y</span> as an additional tag value of type <span class=\"s1\">float</span>.</p>\n<p class=\"p5\">yz =&gt; (float)</p>\n<p class=\"p6\">This property provides joint read-only access to the <span class=\"s1\">y</span> and <span class=\"s1\">z</span> properties; they are returned as a two-element <span class=\"s1\">float</span> vector.<span class=\"Apple-converted-space\">  </span>This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.<span class=\"Apple-converted-space\">  </span>See the documentation for the separate properties <span class=\"s1\">y</span> and <span class=\"s1\">z</span> for further comments.</p>\n<p class=\"p5\">z &lt;–&gt; (float$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">float</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">z</span> is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">z</span> is not used by SLiM unless the optional “continuous space” facility is enabled with the <span class=\"s1\">dimensionality</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span>, in which case <span class=\"s1\">z</span> will be understood to represent the <i>z</i> coordinate of the individual in space (if the dimensionality is <span class=\"s1\">\"xyz\"</span>).<span class=\"Apple-converted-space\">  </span>If continuous space is not enabled, or the dimensionality is not <span class=\"s1\">\"xyz\"</span>, you may use <span class=\"s1\">z</span> as an additional tag value of type <span class=\"s1\">float</span>.</p>\n<p class=\"p2\"><i>5.7.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Individual</i></span><i> methods</i></p>\n<p class=\"p3\">– (logical)containsMutations(object&lt;Mutation&gt; mutations)</p>\n<p class=\"p6\">Returns a <span class=\"s1\">logical</span> vector indicating whether each of the mutations in <span class=\"s1\">mutations</span> is present in the individual (in any of its haplosomes); each element in the returned vector indicates whether the corresponding mutation is present (<span class=\"s1\">T</span>) or absent (<span class=\"s1\">F</span>).<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(integer$)countOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p6\">Returns the number of mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the individual (in all of its haplosomes; a mutation that is present in both homologous haplosomes counts twice).<span class=\"Apple-converted-space\">  </span>If you need a vector of the matching <span class=\"s1\">Mutation</span> objects, rather than just a count, you should probably use <span class=\"s1\">mutationsFromHaplosomes()</span>.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p5\">– (object&lt;Haplosome&gt;)haplosomesForChromosomes([Niso&lt;Chromosome&gt; chromosomes = NULL], [Ni$ index = NULL], [logical$ includeNulls = T])</p>\n<p class=\"p6\">Returns a vector containing the haplosomes of the target individual that correspond to the chromosomes passed in <span class=\"s1\">chromosomes</span> (following the order of the <span class=\"s1\">chromosomes</span> property of <span class=\"s1\">Individual</span>).<span class=\"Apple-converted-space\">  </span>Chromosomes can be specified by id (<span class=\"s1\">integer</span>), by symbol (<span class=\"s1\">string</span>) or by the <span class=\"s1\">Chromosome</span> objects themselves; if <span class=\"s1\">NULL</span> is passed (the default), all chromosomes defined for the species are used, in the order in which they were defined.</p>\n<p class=\"p6\">For chromosomes that are intrinsically diploid (types <span class=\"s1\">\"A\"</span>, <span class=\"s1\">\"X\"</span>, and <span class=\"s1\">\"Z\"</span>, as well as the <span class=\"s1\">\"H-\"</span> and <span class=\"s1\">\"-Y\"</span> backward-compatibility chromosome types), <span class=\"s1\">index</span> can be <span class=\"s1\">0</span> or <span class=\"s1\">1</span>, requesting only the first or second haplosome, respectively, for that chromosome; for other chromosome types, <span class=\"s1\">index</span> is ignored.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">includeNulls</span> is <span class=\"s1\">T</span> (the default), any null haplosomes corresponding to the specified chromosomes are included in the result; if it is <span class=\"s1\">F</span>, null haplosomes are excluded.<span class=\"Apple-converted-space\">  </span>See also the properties <span class=\"s1\">haplosomes</span>, <span class=\"s1\">haplosomesNonNull</span>, <span class=\"s1\">haploidGenome1</span>, <span class=\"s1\">haploidGenome1NonNull</span>, <span class=\"s1\">haploidGenome2</span>, and <span class=\"s1\">haploidGenome2NonNull</span>.</p>\n<p class=\"p5\">– (object&lt;Mutation&gt;)mutationsFromHaplosomes(string$ category, [Nio&lt;MutationType&gt;$ mutType = NULL], [Niso&lt;Chromosome&gt; chromosomes = NULL])</p>\n<p class=\"p6\">Returns a vector of mutations from the haplosomes of the target individual.<span class=\"Apple-converted-space\">  </span>Several options are provided that filter which mutations are returned.</p>\n<p class=\"p6\">The <span class=\"s1\">category</span> parameter must be one of five supported values: <span class=\"s1\">\"unique\"</span>, <span class=\"s1\">\"homozygous\"</span>, <span class=\"s1\">\"heterozygous\"</span>, <span class=\"s1\">\"hemizygous\"</span>, or <span class=\"s1\">\"all\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">category</span> is <span class=\"s1\">\"unique\"</span>, a given mutation will be returned only once, whether it is present homozygously or heterozygously (or hemizygously, for that matter); this mode of operation is similar to the <span class=\"s1\">uniqueMutations</span> property, but provides more control due to the other options provided by this method.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">category</span> is <span class=\"s1\">\"homozygous\"</span>, a given mutation will be returned only if it is present homozygously (in both of the homologous haplosomes for a given chromosome).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">category</span> is <span class=\"s1\">\"heterozygous\"</span>, a given mutation will be returned only if it is present heterozygously (in only one of the two homologous non-null haplosomes for a given chromosome).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">category</span> is <span class=\"s1\">\"hemizygous\"</span>, a given mutation will be returned only if it is present hemizygously (in one haplosome for an intrinsically diploid chromosome, when the other haplosome is a null haplosome).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">category</span> is <span class=\"s1\">\"all\"</span>, a given mutation will be returned each time that it occurs in the haplosomes of the individual; in other words, it will be present in the returned vector <i>twice</i> if it is homozygous, <i>once</i> if it is heterozygous or hemizygous.<span class=\"Apple-converted-space\">  </span>Mutations in the single haplosome of an intrinsically haploid chromosome will be returned for <span class=\"s1\">category</span> values of <span class=\"s1\">\"unique\"</span>, <span class=\"s1\">\"homozygous\"</span>, and <span class=\"s1\">\"all\"</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">mutType</span> parameter may be <span class=\"s1\">NULL</span>, or may specify a mutation type by its <span class=\"s1\">integer</span> id or with the <span class=\"s1\">MutationType</span> object itself.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">mutType</span> is <span class=\"s1\">NULL</span> (the default), mutations of every mutation type are returned; no filtering by mutation type is done.<span class=\"Apple-converted-space\">  </span>Otherwise, only mutations of the specified mutation type will be returned.</p>\n<p class=\"p6\">The <span class=\"s1\">chromosomes</span> parameter may be <span class=\"s1\">NULL</span>, or may provide a vector of chromosomes specified by their <span class=\"s1\">integer</span> id, <span class=\"s1\">string</span> symbol, or with the <span class=\"s1\">Chromosome</span> object itself.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">chromosomes</span> is <span class=\"s1\">NULL</span> (the default), mutations associated with every chromosome are returned; no filtering by chromosome is done.<span class=\"Apple-converted-space\">  </span>Otherwise, only mutations associated with the specified chromosomes will be returned.</p>\n<p class=\"p6\">The returned vector will contain tranches of mutations, one tranche per chromosome, in the order that the chromosomes were specified (if <span class=\"s1\">chromosomes</span> is non-<span class=\"s1\">NULL</span>) or the order the chromosomes were defined in the model (if <span class=\"s1\">chromosomes</span> is <span class=\"s1\">NULL</span>).<span class=\"Apple-converted-space\">  </span>Within a given tranche, the mutations for that chromosome will be returned in sorted order by <span class=\"s1\">position</span>.<span class=\"Apple-converted-space\">  </span>(If more than one mutation associated with a given chromosome exists at the same position, the order in which those mutations are returned is undefined.)</p>\n<p class=\"p6\">This method replaces the deprecated method <span class=\"s1\">uniqueMutationsOfType()</span>, while providing additional useful options.<span class=\"Apple-converted-space\">  </span>It is particularly useful for efficient, vectorized assessment of the homozygous versus heterozygous state of the mutations contained by an individual, which is otherwise difficult to assess efficiently.</p>\n<p class=\"p5\">+ (void)outputIndividuals([Ns$ filePath = NULL], [logical$ append = F], [Niso&lt;Chromosome&gt;$ chromosome = NULL], [logical$ spatialPositions = T], [logical$ ages = T], [logical$ ancestralNucleotides = F], [logical$ pedigreeIDs = F], [logical$ objectTags = F])</p>\n<p class=\"p6\">Output the state of the target vector of individuals in SLiM's own format.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>This method is quite similar to the <span class=\"s1\">Species</span> method <span class=\"s1\">outputFull()</span>, but (1) it can produce output for any vector of individuals, not always for the entire population; (2) it does not support output in a binary format; (3) it can produce output regarding the genetics for all chromosomes or for just one focal chromosome; and (4) there is no corresponding read method, as r<span class=\"s1\">eadFromPopulationFile()</span> can read the data saved by <span class=\"s1\">outputFull()</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">chromosome</span> parameter specifies a focal chromosome for which the genetics of the target individuals will be output.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">chromosome</span> is <span class=\"s1\">NULL</span>, all chromosomes will be output; otherwise, <span class=\"s1\">chromosome</span> may specify the focal chromosome with an <span class=\"s1\">integer</span> chromosome id, a <span class=\"s1\">string</span> chromosome symbol, or a <span class=\"s1\">Chromosome</span> object.</p>\n<p class=\"p6\">The <span class=\"s1\">spatialPositions</span> parameter may be used to control the output of the spatial positions of individuals in species for which continuous space has been enabled using the <span class=\"s1\">dimensionality</span> option of <span class=\"s1\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">spatialPositions</span> is <span class=\"s1\">F</span>, the output will not contain spatial positions.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">spatialPositions</span> is <span class=\"s1\">T</span>, spatial position information will be output if it is available.<span class=\"Apple-converted-space\">  </span>If the species does not have continuous space enabled, the <span class=\"s1\">spatialPositions</span> parameter will be ignored.</p>\n<p class=\"p6\">The <span class=\"s1\">ages</span> parameter may be used to control the output of the ages of individuals in nonWF simulations.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">ages</span> is <span class=\"s1\">F</span>, the output will not contain ages.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">ages</span> is <span class=\"s1\">T</span>, ages will be output for nonWF models.<span class=\"Apple-converted-space\">  </span>In WF simulations, the <span class=\"s1\">ages</span> parameter will be ignored.</p>\n<p class=\"p6\">The <span class=\"s1\">ancestralNucleotides</span> parameter may be used to control the output of the ancestral nucleotide sequence in nucleotide-based models.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">ancestralNucleotides</span> is <span class=\"s1\">F</span>, the output will not contain ancestral nucleotide information.<span class=\"Apple-converted-space\">  </span>This option is provided because the ancestral sequence may be quite large, for models with a long chromosome.<span class=\"Apple-converted-space\">  </span>If the model is not nucleotide-based (as enabled with the <span class=\"s1\">nucleotideBased</span> parameter to <span class=\"s1\">initializeSLiMOptions()</span>), the <span class=\"s1\">ancestralNucleotides</span> parameter will be ignored.<span class=\"Apple-converted-space\">  </span>Note that in nucleotide-based models the output format will <i>always</i> include the nucleotides associated with any nucleotide-based mutations; the <span class=\"s1\">ancestralNucleotides</span> flag governs only the ancestral sequence.</p>\n<p class=\"p6\">The <span class=\"s1\">pedigreeIDs</span> parameter may be used to request that pedigree IDs be written out.<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity.<span class=\"Apple-converted-space\">  </span>This option may only be used if SLiM’s optional pedigree tracking has been enabled with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>.</p>\n<p class=\"p6\">Finally, the <span class=\"s1\">objectTags</span> parameter may be used to request that tag values for objects be written out.<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity; if it turned on (<span class=\"s1\">T</span>), the values of all tags for all objects of supported classes (<span class=\"s1\">Chromosome</span>, <span class=\"s1\">Individual</span>, <span class=\"s1\">Haplosome</span>, <span class=\"s1\">Mutation</span>) will be written.<span class=\"Apple-converted-space\">  </span>For individuals, the <span class=\"s1\">tag</span>, <span class=\"s1\">tagF</span>, <span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span> properties will be written; for chromosomes, haplosomes, and mutations, the <span class=\"s1\">tag</span> property will be written.<span class=\"Apple-converted-space\">  </span>If there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with <span class=\"s1\">setValue()</span>, and so forth, you should persist that state in separate files using calls such as <span class=\"s1\">writeFile()</span>.</p>\n<p class=\"p6\">Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\">+ (void)outputIndividualsToVCF([Ns$ filePath = NULL], [logical$ append = F], [Niso&lt;Chromosome&gt;$ chromosome = NULL], [logical$ outputMultiallelics = T], [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T])</p>\n<p class=\"p6\">Output the state of the target vector of individuals in VCF format.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>This method is quite similar to the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">outputVCFSample()</span>, but (1) it can produce output for any vector of individuals, rather than sampling from a single population; (2) it can produce output regarding the genetics for all chromosomes or for just one focal chromosome, whereas <span class=\"s1\">outputVCFSample()</span> can only output data for a single chromosome; and (3) because it can output genetic information for more than one chromosome, the <span class=\"s1\">groupAsIndividuals</span> option provided by <span class=\"s1\">outputVCFSample()</span> is not available for <span class=\"s1\">outputIndividualsToVCF()</span>; each VCF sample has to correspond directly to one individual.</p>\n<p class=\"p6\">The <span class=\"s1\">chromosome</span> parameter specifies a focal chromosome for which the genetics of the target individuals will be output.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">chromosome</span> is <span class=\"s1\">NULL</span>, all chromosomes will be output (distinguished in the VCF output by the chromosome symbol output in the <span class=\"s1\">CHROM</span> column); otherwise, <span class=\"s1\">chromosome</span> may specify the focal chromosome with an <span class=\"s1\">integer</span> chromosome id, a <span class=\"s1\">string</span> chromosome symbol, or a <span class=\"s1\">Chromosome</span> object.</p>\n<p class=\"p6\">The parameters <span class=\"s1\">outputMultiallelics</span>, <span class=\"s1\">simplifyNucleotides</span>, and <span class=\"s1\">outputNonnucleotides</span> affect the format of the output produced.</p>\n<p class=\"p6\">Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\">+ (object&lt;Mutation&gt;)readIndividualsFromVCF(string$ filePath, [Nio&lt;MutationType&gt;$ mutationType = NULL])</p>\n<p class=\"p6\">Read new mutations from the VCF format file at <span class=\"s1\">filePath</span> and add them to the target individuals.<span class=\"Apple-converted-space\">  </span>The number of target individuals must match the number of samples represented in the VCF file; each sample will be associated with a corresponding target individual, in the order that the samples and the target individuals are provided.<span class=\"Apple-converted-space\">  </span>To read into all of the individuals in a given subpopulation <span class=\"s1\">pN</span>, simply call <span class=\"s1\">pN.individuals.readIndividualsFromVCF()</span>, assuming the subpopulation’s size matches the number of samples in the VCF file.<span class=\"Apple-converted-space\">  </span>A vector containing all of the mutations created by <span class=\"s1\">readIndividualsFromVCF()</span> is returned (not necessarily in the order of the corresponding VCF call lines).</p>\n<p class=\"p6\">This method and the <span class=\"s1\">readHaplosomesFromVCF()</span> method of <span class=\"s1\">Haplosome</span> provide two alternative ways of reading VCF data, focused on the perspective of either individuals (this method) or haplosomes (the <span class=\"s1\">Haplosome</span> method).<span class=\"Apple-converted-space\">  </span>As described above, this method draws a correspondence between VCF samples and individuals, whereas the <span class=\"s1\">Haplosome</span> method draws a correspondence between VCF calls and haplosomes.<span class=\"Apple-converted-space\">  </span>For example, if a VCF call line contained a series of calls like “<span class=\"s1\">1|1 0|1 1 0 1|0</span>” this method would see that as calls for five individuals, three of which are diploid for the chromosome being called, and two of which are haploid.<span class=\"Apple-converted-space\">  </span>That would make sense if, for example, the chromosome being called is an X chromosome; the diploid individuals would be females, the haploid individuals would be males.<span class=\"Apple-converted-space\">  </span>The vector of target individuals would need to contain two females, then two males, and then a female, so that the structure of the calls matched the haplosome structure of the individuals, or an error would result.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">readHaplosomesFromVCF()</span> method of <span class=\"s1\">Haplosome</span>, on the other hand, would see that same series of calls as corresponding to eight haplosomes, and would assign each call to the corresponding non-null target haplosome, without regard to whether the VCF’s grouping into diploid and haploid calls corresponded to any coherent structure of individuals in the SLiM model.<span class=\"Apple-converted-space\">  </span>Each approach has advantages and disadvantages.<span class=\"Apple-converted-space\">  </span>This method provides much more error-checking and safety when your intention is to read individual-level data from VCF; it can check that the ploidy in the VCF data matches the ploidy of each target individual, and that diploid calls like <span class=\"s1\">1|1</span> get assigned to the two haplosomes of a single individual correctly.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">readHaplosomesFromVCF()</span> method of <span class=\"s1\">Haplosome</span> does not perform such checks, and can push VCF data into any arbitrary set of haplosomes, so it provides more power and flexibility, but less error-checking and less intelligence.</p>\n<p class=\"p6\">Because this method works at the level of individuals, it can read VCF data associated with multiple chromosomes into a multi-chromosome SLiM model and place mutations into the correct haplosomes of each individual based upon the <span class=\"s1\">CHROM</span> column of the VCF file (which <span class=\"s1\">readHaplosomesFromVCF()</span> cannot do).<span class=\"Apple-converted-space\">  </span>For this to work, the values in the <span class=\"s1\">CHROM</span> column of the call lines must correspond exactly to chromosome symbols in the SLiM model, as provided to <span class=\"s1\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>The call lines in the input file may be in any order (they do not have to be sorted by <span class=\"s1\">CHROM</span> value, or any other such requirement).<span class=\"Apple-converted-space\">  </span>The vector of mutations returned will contain all of the mutations created; when reading multi-chromosome data, that returned vector will therefore contain a mix of mutations with different associated chromosomes.<span class=\"Apple-converted-space\">  </span>Alternatively, it would work equally well to make a separate call to <span class=\"s1\">readIndividualsFromVCF()</span> for each chromosome, providing each call with a separate VCF file that contains only the mutations associated with one chromosome; in that case, each call would return only the mutations added to the chromosome associated with that call, which might be more convenient if post-processing of the returned mutations is necessary.</p>\n<p class=\"p6\">As in <span class=\"s1\">readHaplosomesFromVCF()</span>, a call of <span class=\"s1\">~</span> represents the fact that an individual has no genetic information for the chromosome being called; for example, a call line for a mutation on a Y chromosome should have haploid calls for male individuals (they have or do not have the called mutation), and calls of <span class=\"s1\">~</span> for female individuals (they have no Y haplosome at all).<span class=\"Apple-converted-space\">  </span>This convention was invented for SLiM, since the VCF standard does not seem to say anything about how sex chromosomes should be represented (or anything about other types of chromosomes that might be absent from some individuals).</p>\n<p class=\"p6\">The <span class=\"s1\">readHaplosomesFromVCF()</span> method’s documentation provides many important details on how SLiM treats various VCF fields during input; those details will not be repeated here, for brevity.</p>\n<p class=\"p5\">– (float)relatedness(object&lt;Individual&gt; individuals, [Niso&lt;Chromosome&gt;$ chromosome = NULL])</p>\n<p class=\"p6\">Returns a vector containing the degrees of relatedness between the receiver and each of the individuals in <span class=\"s1\">individuals</span>.<span class=\"Apple-converted-space\">  </span>The relatedness between <span class=\"s1\">A</span> and <span class=\"s1\">B</span> is always <span class=\"s1\">1.0</span> if <span class=\"s1\">A</span> and <span class=\"s1\">B</span> are actually the same individual; this facility works even if SLiM’s optional pedigree tracking is not enabled (in which case all other relatedness values will be <span class=\"s1\">0.0</span>).<span class=\"Apple-converted-space\">  </span>Otherwise, if pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, this method will use the pedigree information to construct a relatedness estimate.<span class=\"Apple-converted-space\">  </span>The relatedness is calculated based upon the type of the chromosome specified by <span class=\"s1\">chromosome</span> (as an <span class=\"s1\">integer</span> id, a <span class=\"s1\">string</span> symbol, or a <span class=\"s1\">Chromosome</span> object); if <span class=\"s1\">chromosome</span> is <span class=\"s1\">NULL</span>, it is assumed to be the single chromosome present in the model, or if more than one chromosome is present, an error results and the chromosome must be explicitly given.</p>\n<p class=\"p6\">More specifically, this method uses all available pedigree information from the grandparental and parental pedigree records of <span class=\"s1\">A</span> and <span class=\"s1\">B</span> to compute an estimate of the degree of consanguinity between <span class=\"s1\">A</span> and <span class=\"s1\">B</span>.<span class=\"Apple-converted-space\">  </span>When considering a diploid autosome, siblings have a relatedness of <span class=\"s1\">0.5</span>, as do parents to their children and vice versa; cousins have a relatedness of <span class=\"s1\">0.125</span>; and so forth.<span class=\"Apple-converted-space\">  </span>If, according to the pedigree information available, <span class=\"s1\">A</span> and <span class=\"s1\">B</span> have no blood relationship, the value returned is <span class=\"s1\">0.0</span>.<span class=\"Apple-converted-space\">  </span>Note that the value returned by <span class=\"s1\">relatedness()</span> is what is called the “coefficient of relationship” between the two individuals (Wright, 1922; <a href=\"https://doi.org/10.1086/279872\"><span class=\"s12\">https://doi.org/10.1086/279872</span></a>), and ranges from <span class=\"s1\">0.0</span> to <span class=\"s1\">1.0</span>.</p>\n<p class=\"p6\">There is another commonly used metric of relatedness, called the “kinship coefficient”, that reflects the probability of identity by descent between two individuals <span class=\"s1\">A</span> and <span class=\"s1\">B</span>.<span class=\"Apple-converted-space\">  </span>In general, it is approximately equal to one-half of the coefficient of relationship; if an approximate estimate of the kinship coefficient is acceptable, especially in models in which individuals are expected to be outbred, you can simply divide <span class=\"s1\">relatedness()</span> by two.<span class=\"Apple-converted-space\">  </span>However, it should be noted that Wright’s coefficient of relationship is <i>not</i> a measure of the probability of identity by descent, and so it is not exactly double the kinship coefficient; they actually measure different things.<span class=\"Apple-converted-space\">  </span>More precisely, the relationship between them is <span class=\"s2\"><i>r</i> = 2<i>φ</i>/sqrt((1+<i>f</i></span><span class=\"s13\"><sub>A</sub></span><span class=\"s2\">)(1+<i>f</i></span><span class=\"s13\"><sub>B</sub></span><span class=\"s2\">))</span>, where <span class=\"s2\"><i>r</i></span> is Wright’s coefficient of relatedness, <span class=\"s2\"><i>φ</i></span> is the kinship coefficient, and <span class=\"s2\"><i>f</i></span><span class=\"s13\"><sub>A</sub></span> and <span class=\"s2\"><i>f</i></span><span class=\"s13\"><sub>B</sub></span> are the inbreeding coefficients of <span class=\"s1\">A</span> and <span class=\"s1\">B</span> respectively.</p>\n<p class=\"p6\">Note that this relatedness is simply pedigree-based relatedness, and does not necessarily correspond to genetic relatedness, because of the effects of factors like assortment and recombination.<span class=\"Apple-converted-space\">  </span>If a metric of actual genetic relatedness is desired, tree-sequence recording can be used after simulation is complete, to compute the exact genetic relatedness between individuals based upon the complete ancestry tree (a topic which is beyond the scope of this manual).<span class=\"Apple-converted-space\">  </span>Actual genetic relatedness cannot presently be calculated during a simulation run; the information is implicitly contained in the recorded tree-sequence tables, but calculating it is too computationally expensive to be reasonable.</p>\n<p class=\"p6\">This method assumes that the grandparents (or the parents, if grandparental information is not available) are themselves unrelated and that they are not inbred; this assumption is necessary because we have no information about their parentage, since SLiM’s pedigree tracking information only goes back two generations.<span class=\"Apple-converted-space\">  </span>Be aware that in a model where inbreeding or selfing occurs at all (including “incidental selfing”, where a hermaphroditic individual happens to choose itself as a mate), some level of “background relatedness” will be present and this assumption will be violated.<span class=\"Apple-converted-space\">  </span>In such circumstances, <span class=\"s1\">relatedness()</span> will therefore tend to underestimate the degree of relatedness between individuals, and the greater the degree of inbreeding, the greater the underestimation will be.<span class=\"Apple-converted-space\">  </span>If inbreeding is allowed in a model – and particularly if it is common – the results of <span class=\"s1\">relatedness()</span> should therefore not be taken as an estimate of <i>absolute</i> relatedness, but can still be useful as an estimate of <i>relative</i> relatedness (indicating that, say, A appears from the information available to be more closely related to B than it is to C).</p>\n<p class=\"p6\">See also <span class=\"s1\">sharedParentCount()</span> for a different metric of relatedness.</p>\n<p class=\"p5\"><span class=\"s3\">+ (void)setSpatialPosition(float position)</span></p>\n<p class=\"p6\"><span class=\"s3\">Sets the spatial position of the individual (as accessed through the </span><span class=\"s4\">spatialPosition</span><span class=\"s3\"> property).<span class=\"Apple-converted-space\">  </span>The length of </span><span class=\"s4\">position</span><span class=\"s3\"> (the number of coordinates in the spatial position of an individual) depends upon the spatial dimensionality declared with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If the spatial dimensionality is zero (as it is by default), it is an error to call this method.<span class=\"Apple-converted-space\">  </span>The elements of </span><span class=\"s4\">position</span><span class=\"s3\"> are set into the values of the </span><span class=\"s4\">x</span><span class=\"s3\">, </span><span class=\"s4\">y</span><span class=\"s3\">, and </span><span class=\"s4\">z</span><span class=\"s3\"> properties (if those properties are encompassed by the spatial dimensionality of the simulation).<span class=\"Apple-converted-space\">  </span>In other words, if the declared dimensionality is </span><span class=\"s4\">\"xy\"</span><span class=\"s3\">, calling </span><span class=\"s4\">individual.setSpatialPosition(c(1.0, 0.5))</span><span class=\"s3\"> property is equivalent to </span><span class=\"s4\">individual.x = 1.0; individual.y = 0.5</span><span class=\"s3\">; </span><span class=\"s4\">individual.z</span><span class=\"s3\"> is not set (even if a third value is supplied in </span><span class=\"s4\">position</span><span class=\"s3\">) since it is not encompassed by the simulation’s dimensionality in this example.</span></p>\n<p class=\"p6\"><span class=\"s3\">Note that this is an Eidos class method, somewhat unusually, which allows it to work in a special way when called on a vector of individuals.<span class=\"Apple-converted-space\">  </span>When the target vector of individuals is non-singleton, this method can do one of two things.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">position</span><span class=\"s3\"> contains just a single point (i.e., is equal in length to the spatial dimensionality of the model), the spatial position of all of the target individuals will be set to the given point.<span class=\"Apple-converted-space\">  </span>Alternatively, if </span><span class=\"s4\">position</span><span class=\"s3\"> contains one point per target individual (i.e., is equal in length to the number of individuals multiplied by the spatial dimensionality of the model), the spatial position of each target individual will be set to the corresponding point from </span><span class=\"s4\">position</span><span class=\"s3\"> (where the point data is concatenated, not interleaved, just as it would be returned by accessing the </span><span class=\"s4\">spatialPosition</span><span class=\"s3\"> property on the vector of target individuals).<span class=\"Apple-converted-space\">  </span>Calling this method with a </span><span class=\"s4\">position</span><span class=\"s3\"> vector of any other length is an error.</span></p>\n<p class=\"p5\">– (integer)sharedParentCount(object&lt;Individual&gt; individuals)</p>\n<p class=\"p6\">Returns a vector containing the number of parents shared between the receiver and each of the individuals in <span class=\"s1\">individuals</span>.<span class=\"Apple-converted-space\">  </span>The number of shared parents between <span class=\"s1\">A</span> and <span class=\"s1\">B</span> is always <span class=\"s1\">2</span> if <span class=\"s1\">A</span> and <span class=\"s1\">B</span> are actually the same individual; this facility works even if SLiM’s optional pedigree tracking is not enabled (in which case all other relatedness values will be <span class=\"s1\">0</span>).<span class=\"Apple-converted-space\">  </span>Otherwise, if pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, this method will use the pedigree information to construct a relatedness estimate.</p>\n<p class=\"p6\">More specifically, this method uses the parental pedigree IDs from the pedigree records of a pair of individuals to count the number of shared parents between them, such that full siblings (with all of the same parents) have a count of <span class=\"s1\">2</span>, and half siblings (with half of the same parents) have a count of <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>If possible parents of the two individuals are <span class=\"s1\">A</span>, <span class=\"s1\">B</span>, <span class=\"s1\">C</span>, and <span class=\"s1\">D</span>, then the shared parent count is as follows, for some illustrative examples.<span class=\"Apple-converted-space\">  </span>The first column showing the two parents of the first individual, the second column showing the two parents of the second individual; note that the two parents of an individual can be the same due to cloning or selfing:</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">CD</span> <span class=\"s14\">→</span> <span class=\"s1\">0</span> (no shared parents)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">CC</span> <span class=\"s14\">→</span> <span class=\"s1\">0</span> (no shared parents)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">AC</span> <span class=\"s14\">→</span> <span class=\"s1\">1</span> (half siblings)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">AA</span> <span class=\"s14\">→</span> <span class=\"s1\">1</span> (half siblings)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AA</span> <span class=\"s1\">AB</span> <span class=\"s14\">→</span> <span class=\"s1\">1</span> (half siblings)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">AB</span> <span class=\"s14\">→</span> <span class=\"s1\">2</span> (full siblings)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AB</span> <span class=\"s1\">BA</span> <span class=\"s14\">→</span> <span class=\"s1\">2</span> (full siblings)</p>\n<p class=\"p7\"><span class=\"Apple-tab-span\">\t</span><span class=\"s1\">AA</span> <span class=\"s1\">AA</span> <span class=\"s14\">→</span> <span class=\"s1\">2</span> (full siblings)</p>\n<p class=\"p6\">This method does not estimate consanguinity.<span class=\"Apple-converted-space\">  </span>For example, if one individual is itself a parent of the other individual, that is irrelevant for this method.<span class=\"Apple-converted-space\">  </span>Similarly, in simulations of sex chromosomes, the sexes of the parents are irrelevant, even if no genetic material would have been inherited from a given parent.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">relatedness()</span> for an assessment of pedigree-based relatedness that does estimate the consanguinity of individuals.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">sharedParentCount()</span> method is preferable if your exact question is simply whether individuals are full siblings, half siblings, or non-siblings; in other cases, <span class=\"s1\">relatedness()</span> is probably more useful.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(float$)sumOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns the sum of the selection coefficients of all mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the haplosomes of the individual.<span class=\"Apple-converted-space\">  </span>This is often useful in models that use a particular mutation type to represent QTLs with additive effects; in that context, <span class=\"s1\">sumOfMutationsOfType()</span> will provide the sum of the additive effects of the QTLs for the given mutation type.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.<span class=\"Apple-converted-space\">  </span>Note that this method also exists on <span class=\"s1\">Haplosome</span>, for cases in which the sum for just one haplosome is desired.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(object&lt;Mutation&gt;)uniqueMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p6\"><b>This method has been deprecated, and may be removed in a future release of SLiM.</b><span class=\"Apple-converted-space\">  </span>Its functionality was replaced by <span class=\"s1\">mutationsFromHaplosomes()</span> in SLiM 5.0.</p>\n<p class=\"p6\">Returns an <span class=\"s1\">object</span> vector of all the mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations in the individual.<span class=\"Apple-converted-space\">  </span>Mutations present in both homologous haplosomes will occur only once in the result of this method, and the mutations for a given chromosomes will be given in sorted order by <span class=\"s1\">position</span>, so in single-chromosome simulations this method is similar to <span class=\"s1\">sortBy(unique(individual.haplosomes.mutationsOfType(mutType)), \"position\")</span>.<span class=\"Apple-converted-space\">  </span>(Even with a single chromosome it is not identical to that call, since if multiple mutations exist at the exact same position, they may be sorted differently by this method than they would be by <span class=\"s1\">sortBy()</span>.)<span class=\"Apple-converted-space\">  </span>If you just need a count of the matching <span class=\"s1\">Mutation</span> objects, rather than a vector of the matches, use <span class=\"s1\">-countOfMutationsOfType()</span>.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.<span class=\"Apple-converted-space\">  </span>Indeed, it is faster than just <span class=\"s1\">individual.haplosomes.mutationsOfType(mutType)</span>, and gives uniquing and sorting on top of that, so it is advantageous unless duplicate entries for homozygous mutations are actually needed.</p>\n<p class=\"p5\">+ (integer)zygosityOfMutations([No&lt;Mutation&gt; mutations = NULL], [integer$ hemizygousValue = 1], [integer$ haploidValue = 1])</p>\n<p class=\"p6\">Returns an <span class=\"s1\">integer</span> matrix with the target individuals’ zygosity for all of the <span class=\"s1\">Mutation</span> objects passed in <span class=\"s1\">mutations</span>.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">mutations</span> argument is <span class=\"s1\">NULL</span> (the default), zygosity values will be returned for all of the active <span class=\"s1\">Mutation</span> objects in the species – the same <span class=\"s1\">Mutation</span> objects, and in the same order, as would be returned by the <span class=\"s1\">mutations</span> property of <span class=\"s1\">sim</span>, in other words.<span class=\"Apple-converted-space\">  </span>The returned matrix has one column for each individual and one row for each mutation.</p>\n<p class=\"p6\">For a mutation on a diploid chromosome, the zygosity will be either <span class=\"s1\">0</span> (absent), <span class=\"s1\">1</span> (heterozygous), or <span class=\"s1\">2</span> (homozygous).<span class=\"Apple-converted-space\">  </span>This is the straightforward “base case” that is usually meant by the term “zygosity”.</p>\n<p class=\"p6\">If one of the two haplosomes of an intrinsically diploid chromosome is a null haplosome (as would be the case for an X chromosome in a male individual, for example), mutations present in the non-null haplosome are called “hemizygous”, and the zygosity returned for them is configurable using the <span class=\"s1\">hemizygousValue</span> parameter.<span class=\"Apple-converted-space\">  </span>By default, the zygosity returned for hemizygous mutations is <span class=\"s1\">1</span>.</p>\n<p class=\"p6\">Finally, although the term “zygosity” is not usually used in the context of haploidy, this method nevertheless supports intrinsically haploid chromosomes; the zygosity returned for mutations present on an intrinsically haploid chromosome is configurable using the <span class=\"s1\">haploidValue</span> parameter.<span class=\"Apple-converted-space\">  </span>By default, the zygosity returned for haploid mutations is <span class=\"s1\">1</span>.</p>\n<p class=\"p6\">For a large number of mutations – and especially for a <span class=\"s1\">mutations</span> value of <span class=\"s1\">NULL</span>, representing all mutations in the species – this method should be much more efficient than using methods such as <span class=\"s1\">containsMutations()</span> to assess zygosity.<span class=\"Apple-converted-space\">  </span>Nevertheless, calculating fitness effects in script based upon zygosity will generally be slower than SLiM’s internal fitness calculations.<span class=\"Apple-converted-space\">  </span>Note that for just one or a few mutations – especially if <span class=\"s1\">mutations</span> contains just a small fraction of all of the mutations in the species – this method will probably be much slower than alternative approaches; this method is optimized for the bulk case.</p>\n<p class=\"p6\">See also the method <span class=\"s1\">mutationsFromHaplosomes()</span>, which provides an alternative approach for assessing the zygosity of mutations in an individual.</p>\n<p class=\"p1\"><b>5.8<span class=\"Apple-converted-space\">  </span>Class InteractionType</b></p>\n<p class=\"p2\"><i>5.8.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>InteractionType</i></span><i> properties</i></p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this interaction type; for interaction type <span class=\"s1\">i3</span>, for example, this is <span class=\"s1\">3</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">maxDistance &lt;–&gt; (float$)</p>\n<p class=\"p4\">The maximum distance over which this interaction will be evaluated.<span class=\"Apple-converted-space\">  </span>For inter-individual distances greater than <span class=\"s1\">maxDistance</span><span class=\"s2\">,</span> the interaction strength will be zero.</p>\n<p class=\"p3\">reciprocal =&gt; (logical$)</p>\n<p class=\"p4\">The reciprocality of the interaction, as specified in <span class=\"s1\">initializeInteractionType()</span>.<span class=\"Apple-converted-space\">  </span>This will be <span class=\"s1\">T</span> for reciprocal interactions (those for which the interaction strength of B upon A is equal to the interaction strength of A upon B), and <span class=\"s1\">F</span> otherwise.</p>\n<p class=\"p3\">sexSegregation =&gt; (string$)</p>\n<p class=\"p6\">The sex-segregation of the interaction, as specified in <span class=\"s1\">initializeInteractionType()</span> or with <span class=\"s1\">setConstraints()</span>.<span class=\"Apple-converted-space\">  </span>For non-sexual simulations, this will be <span class=\"s1\">\"**\"</span>.<span class=\"Apple-converted-space\">  </span>For sexual simulations, this <span class=\"s1\">string</span> value indicates the sex of individuals feeling the interaction, and the sex of individuals exerting the interaction; see <span class=\"s1\">initializeInteractionType()</span> for details.</p>\n<p class=\"p3\">spatiality =&gt; (string$)</p>\n<p class=\"p4\">The spatial dimensions used by the interaction, as specified in <span class=\"s1\">initializeInteractionType()</span>.<span class=\"Apple-converted-space\">  </span>This will be <span class=\"s1\">\"\"</span> (the empty string) for non-spatial interactions, or <span class=\"s1\">\"x\"</span>, <span class=\"s1\">\"y\"</span>, <span class=\"s1\">\"z\"</span>, <span class=\"s1\">\"xy\"</span>, <span class=\"s1\">\"xz\"</span>, <span class=\"s1\">\"yz\"</span>, or <span class=\"s1\">\"xyz\"</span>, for interactions using those spatial dimensions respectively.<span class=\"Apple-converted-space\">  </span>The specified dimensions are used to calculate the distances between individuals for this interaction.<span class=\"Apple-converted-space\">  </span>The value of this property is always the same as the value given to <span class=\"s1\">initializeInteractionType()</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to interaction types.</p>\n<p class=\"p2\"><i>5.8.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>InteractionType</i></span><i> methods</i></p>\n<p class=\"p5\">– (float)clippedIntegral(No&lt;Individual&gt; receivers)</p>\n<p class=\"p6\">Returns a vector containing the integral of the interaction function as experienced by each of the individuals in <span class=\"s1\">receivers</span>.<span class=\"Apple-converted-space\">  </span>For each given individual, the interaction function is clipped to the edges of the spatial bounds of the subpopulation that individual inhabits; the individual’s spatial position must be within bounds or an error is raised.<span class=\"Apple-converted-space\">  </span>A periodic boundary will, correctly, not clip the interaction function.<span class=\"Apple-converted-space\">  </span>The interaction function is also clipped to the interaction’s maximum distance; that distance must be less than half of the extent of the spatial bounds in each dimension (so that, for a given dimension, the interaction function is clipped by the spatial bounds on only one side), otherwise an error is raised.<span class=\"Apple-converted-space\">  </span>Note that receiver constraints are not applied; an individual might not actually receive any interactions because of those constraints, but it is still considered to have the same interaction function integral.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">receivers</span> is <span class=\"s1\">NULL</span>, the maximal integral is returned, as would be experienced by an individual farther than the maximum distance from any edge.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver subpopulation, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">The computed value of the integral is not exact; it is calculated by an approximate numerical method designed to be fast, but the error should be fairly small (typically less than 1% from the true value).<span class=\"Apple-converted-space\">  </span>A large amount of computation will occur the first time this method is called (perhaps taking more than a second, depending upon hardware), but subsequent calls should be very fast.<span class=\"Apple-converted-space\">  </span>This method does not invoke <span class=\"s1\">interaction()</span> callbacks; the calculated integrals are only for the interaction function itself, and so will not be accurate if <span class=\"s1\">interaction()</span> callbacks modify the relationship between distance and interaction strength.<span class=\"Apple-converted-space\">  </span>For this reason, the overhead of the first call will <i>not</i> reoccur when individuals move or when the interaction is re-evaluated; for typical models, the initial overhead will be incurred only once.<span class=\"Apple-converted-space\">  </span>The initial overhead will reoccur, however, if the interaction function itself, or the maximum interaction distance, are changed; frequent change of those parameters may render the performance of this method unacceptable.</p>\n<p class=\"p6\">The integral values returned by <span class=\"s1\">clippedIntegral()</span> can be useful for computing interaction metrics that are scaled by the amount of “interaction field” (to coin a term) that is present for a given individual, producing metrics of interaction <i>density</i>.<span class=\"Apple-converted-space\">  </span>Notably, the <span class=\"s1\">localPopulationDensity()</span> method automatically incorporates the mechanics of <span class=\"s1\">clippedIntegral()</span> into the calculations it performs; see that method’s documentation for further discussion of this concept.<span class=\"Apple-converted-space\">  </span>This approach can also be useful with the <span class=\"s1\">interactingNeighborCount()</span> method, provided that the interaction function is of type <span class=\"s1\">\"f\"</span> (since the neighbor count does not depend upon interaction strength).</p>\n<p class=\"p5\">– (float)distance(object&lt;Individual&gt;$ receiver, [No&lt;Individual&gt; exerters = NULL])</p>\n<p class=\"p6\">Returns a vector containing distances between <span class=\"s1\">receiver</span> and the individuals in <span class=\"s1\">exerters</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">exerters</span> is <span class=\"s1\">NULL</span> (the default), then a vector of the distances from <span class=\"s1\">receiver</span> to all individuals in its subpopulation (including itself) is returned; this case may be handled differently internally, for greater speed, so supplying <span class=\"s1\">NULL</span> is preferable to supplying the vector of all individuals in the subpopulation explicitly.<span class=\"Apple-converted-space\">  </span>Otherwise, all individuals in <span class=\"s1\">exerters</span> must belong to a single subpopulation (but not necessarily the same subpopulation as <span class=\"s1\">receiver</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">Importantly, distances are calculated according to the spatiality of the <span class=\"s1\">InteractionType</span> (as declared in <span class=\"s1\">initializeInteractionType()</span>), not the dimensionality of the model as a whole (as declared in <span class=\"s1\">initializeSLiMOptions()</span>).<span class=\"Apple-converted-space\">  </span>The distances returned are therefore the distances that would be used to calculate interaction strengths.<span class=\"Apple-converted-space\">  </span>However, <span class=\"s1\">distance()</span> will return finite distances for all pairs of individuals, even if the individuals are non-interacting due to the maximum interaction distance or the interaction constraints; the <span class=\"s1\">distance()</span> between an individual and itself will thus be <span class=\"s1\">0</span>.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">interactionDistance()</span> for an alternative distance definition.</p>\n<p class=\"p5\">– (float)distanceFromPoint(float point, object&lt;Individual&gt; exerters)</p>\n<p class=\"p6\">Returns a vector containing distances between the point given by the spatial coordinates in <span class=\"s1\">point</span>, which may be thought of as the “receiver”, and individuals in <span class=\"s1\">exerters</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">point</span> vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type’s spatiality is <span class=\"s1\">\"xz\"</span>, for example, then <span class=\"s1\">point[0]</span> is assumed to be an <i>x</i> value, and <span class=\"s1\">point[1]</span> is assumed to be a <i>z</i> value, and <span class=\"s1\">point</span> must be exactly two elements in length.<span class=\"Apple-converted-space\">  </span>Be careful; this means that in general it is not safe to pass an individual’s <span class=\"s1\">spatialPosition</span> property for <span class=\"s1\">point</span>, for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on <span class=\"s1\">Individual</span> exist for getting the individual’s coordinates in a particular spatiality, such as the <span class=\"s1\">xz</span> property for this example.<span class=\"Apple-converted-space\">  </span>A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (<span class=\"s1\">pointPeriodic()</span> may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.</p>\n<p class=\"p6\">All individuals in <span class=\"s1\">exerters</span> must belong to a single subpopulation; the <span class=\"s1\">evaluate()</span> method must have been previously called for that subpopulation, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">Importantly, distances are calculated according to the spatiality of the <span class=\"s1\">InteractionType</span> (as declared in <span class=\"s1\">initializeInteractionType()</span>) not the dimensionality of the model as a whole (as declared in <span class=\"s1\">initializeSLiMOptions()</span>).<span class=\"Apple-converted-space\">  </span>The distances are therefore interaction distances: the distances that are used to calculate interaction strengths.<span class=\"Apple-converted-space\">  </span>However, the maximum interaction distance and interaction constraints are not used.</p>\n<p class=\"p6\">This method replaces the <span class=\"s1\">distanceToPoint()</span> method that existed prior to SLiM 4.</p>\n<p class=\"p5\">– (object)drawByStrength(object&lt;Individual&gt; receiver, [integer$ count = 1], [No&lt;Subpopulation&gt;$ exerterSubpop = NULL], [logical$ returnDict = F])</p>\n<p class=\"p6\">Returns an <span class=\"s1\">object&lt;Individual&gt;</span> vector containing up to <span class=\"s1\">count</span> individuals drawn from <span class=\"s1\">exerterSubpop</span>, or if that is <span class=\"s1\">NULL</span> (the default), then from the subpopulation of <span class=\"s1\">receiver</span>, which must be singleton in the default mode of operation (but see below).<span class=\"Apple-converted-space\">  </span>The probability of drawing particular individuals is proportional to the strength of interaction they exert upon <span class=\"s1\">receiver</span> (which is zero for <span class=\"s1\">receiver</span> itself).<span class=\"Apple-converted-space\">  </span>All exerters must belong to a single subpopulation (but not necessarily the same subpopulation as <span class=\"s1\">receiver</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.</p>\n<p class=\"p6\">This method may be used with either spatial or non-spatial interactions, but will be more efficient with spatial interactions that set a short maximum interaction distance.<span class=\"Apple-converted-space\">  </span>Draws are done with replacement, so the same individual may be drawn more than once; sometimes using <span class=\"s1\">unique()</span> on the result of this call is therefore desirable.<span class=\"Apple-converted-space\">  </span>If more than one draw will be needed, it is much more efficient to use a single call to <span class=\"s1\">drawByStrength()</span>, rather than drawing individuals one at a time.<span class=\"Apple-converted-space\">  </span>Note that if no individuals exert a non-zero interaction strength upon <span class=\"s1\">receiver</span>, the vector returned will be zero-length; it is important to consider this possibility.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, this method has a vectorized mode of operation in which the <span class=\"s1\">receiver</span> parameter may be non-singleton.<span class=\"Apple-converted-space\">  </span>To switch the method to this mode, pass <span class=\"s1\">T</span> for <span class=\"s1\">returnDict</span>, rather than the default of <span class=\"s1\">F</span> (the operation of which is described above).<span class=\"Apple-converted-space\">  </span>In this mode, the return value is a <span class=\"s1\">Dictionary</span> object instead of a vector of <span class=\"s1\">Individual</span> objects.<span class=\"Apple-converted-space\">  </span>This dictionary uses <span class=\"s1\">integer</span> keys that range from <span class=\"s1\">0</span> to <span class=\"s1\">N-1</span>, where <span class=\"s1\">N</span> is the number of individuals passed in <span class=\"s1\">receiver</span>; these keys thus correspond directly to the indices of the individuals in <span class=\"s1\">receiver</span>, and there is one entry in the dictionary for each receiver.<span class=\"Apple-converted-space\">  </span>The value in the dictionary, for a given <span class=\"s1\">integer</span> key, is an <span class=\"s1\">object&lt;Individual&gt;</span> vector with the individuals drawn for the corresponding receiver, exactly as described above for the non-vectorized case.<span class=\"Apple-converted-space\">  </span>The results for each receiver can therefore be obtained from the returned dictionary with <span class=\"s1\">getValue()</span>, passing the index of the receiver.<span class=\"Apple-converted-space\">  </span>The speed of this mode of operation will probably be similar to the speed of making <span class=\"s1\">N</span> separate non-vectorized calls to <span class=\"s1\">drawByStrength()</span>, when running single-threaded.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.<span class=\"Apple-converted-space\">  </span>In this mode of operation, all receivers must belong to the same subpopulation.</p>\n<p class=\"p3\">– (void)evaluate(io&lt;Subpopulation&gt; subpops)</p>\n<p class=\"p6\">Snapshots model state in preparation for the use of the interaction, for the receiver and exerter subpopulations specified by <span class=\"s1\">subpops</span>.<span class=\"Apple-converted-space\">  </span>The subpopulations may be supplied either as <span class=\"s1\">integer</span> IDs, or as <span class=\"s1\">Subpopulation</span> objects.<span class=\"Apple-converted-space\">  </span>This method will discard all previously cached data for the subpopulation(s), and will cache the current spatial positions of all individuals they contain (so that the spatial positions of those individuals may then change without disturbing the state of the interaction at the moment of evaluation).<span class=\"Apple-converted-space\">  </span>It will also cache which individuals in the subpopulation are eligible to act as exerters, according to the configured exerter constraints, but it will <i>not</i> cache such eligibility information for receiver constraints (which are applied at the time a spatial query is made).<span class=\"Apple-converted-space\">  </span>Particular interaction distances and strengths are not computed by <span class=\"s1\">evaluate()</span>, and <span class=\"s1\">interaction()</span> callbacks will not be called in response to this method; that work is deferred until required to satisfy a query (at which point the tick and cycle counters may have advanced, so be careful with the tick ranges used in defining <span class=\"s1\">interaction()</span> callbacks).</p>\n<p class=\"p6\">You must explicitly call <span class=\"s1\">evaluate()</span> at an appropriate time in the tick cycle before the interaction is used, but after any relevant changes have been made to the population.<span class=\"Apple-converted-space\">  </span>SLiM will invalidate any existing interactions after any portion of the tick cycle in which new individuals have been born or existing individuals have died.<span class=\"Apple-converted-space\">  </span>In a WF model, this occurs just before <span class=\"s1\">late()</span> events execute (see the WF tick cycle diagram), so <span class=\"s1\">late()</span> events are often the appropriate place to put <span class=\"s1\">evaluate()</span> calls, but <span class=\"s1\">first()</span> or <span class=\"s1\">early()</span> events can work too if the interaction is not needed until that point in the tick cycle anyway. In nonWF models, on the other hand, new offspring are produced just before <span class=\"s1\">early()</span> events and then individuals die just before <span class=\"s1\">late()</span> events (see the nonWF tick cycle diagram), so interactions will be invalidated twice during each tick cycle.<span class=\"Apple-converted-space\">  </span>This means that in a nonWF model, an interaction that influences reproduction should usually be evaluated in a <span class=\"s1\">first()</span> event, while an interaction that influences fitness or mortality should usually be evaluated in an <span class=\"s1\">early()</span> event (and an interaction that affects both may need to be evaluated at both times).</p>\n<p class=\"p6\">If an interaction is never evaluated for a given subpopulation, it is guaranteed that there will be essentially no memory or computational overhead associated with the interaction for that subpopulation.<span class=\"Apple-converted-space\">  </span>Furthermore, attempting to query an interaction for a receiver or exerter in a subpopulation that has not been evaluated is guaranteed to raise an error.</p>\n<p class=\"p5\">– (integer)interactingNeighborCount(object&lt;Individual&gt; receivers, [No&lt;Subpopulation&gt;$ exerterSubpop = NULL])</p>\n<p class=\"p6\">Returns the number of interacting individuals for each individual in <span class=\"s1\">receivers</span>, within the maximum interaction distance according to the distance metric of the <span class=\"s1\">InteractionType</span>, from among the exerters in <span class=\"s1\">exerterSubpop</span> (or, if that is <span class=\"s1\">NULL</span>, then from among all individuals in the receiver’s subpopulation).<span class=\"Apple-converted-space\">  </span>More specifically, this method counts the number of individuals which can exert an interaction upon each receiver (which does not include the receiver itself).<span class=\"Apple-converted-space\">  </span>All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.</p>\n<p class=\"p6\">This method is similar to <span class=\"s1\">nearestInteractingNeighbors()</span> (when passed a large count so as to guarantee that all interacting individuals are returned), but this method returns only a count of the interacting individuals, not a vector containing the individuals.</p>\n<p class=\"p6\">Note that this method uses interaction eligibility as a criterion; it will not count neighbors that do not exert an interaction upon a given receiver (due to the configured receiver or exerter constraints).<span class=\"Apple-converted-space\">  </span>(It also does not count a receiver as a neighbor of itself.)<span class=\"Apple-converted-space\">  </span>If a count of all neighbors is desired, rather than just interacting neighbors, use <span class=\"s1\">neighborCount()</span>.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p5\"><span class=\"s3\">– (float)interactionDistance(object&lt;Individual&gt;$ receiver, [No&lt;Individual&gt; exerters = NULL])</span></p>\n<p class=\"p6\">Returns a vector containing interaction-dependent distances between <span class=\"s1\">receiver</span> and individuals in <span class=\"s1\">exerters</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">exerters</span> is <span class=\"s1\">NULL</span> (the default), then a vector of the interaction-dependent distances from <span class=\"s1\">receiver</span> to all individuals in its subpopulation (including <span class=\"s1\">receiver</span> itself) is returned; this case may be handled much more efficiently than if a vector of all individuals in the subpopulation is explicitly provided.<span class=\"Apple-converted-space\">  </span>Otherwise, all individuals in <span class=\"s1\">exerters</span> must belong to a single subpopulation (but not necessarily the same subpopulation as <span class=\"s1\">receiver</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">Importantly, distances are calculated according to the spatiality of the <span class=\"s1\">InteractionType</span> (as declared in <span class=\"s1\">initializeInteractionType()</span>), not the dimensionality of the model as a whole (as declared in <span class=\"s1\">initializeSLiMOptions()</span>).<span class=\"Apple-converted-space\">  </span>The distances returned are therefore the distances that would be used to calculate interaction strengths.<span class=\"Apple-converted-space\">  </span>In addition, <span class=\"s1\">interactionDistance()</span> will return <span class=\"s1\">INF</span> as the distance between <span class=\"s1\">receiver</span> and any individual which does not exert an interaction upon <span class=\"s1\">receiver</span>; the <span class=\"s1\">interactionDistance()</span> between an individual and itself will thus be <span class=\"s1\">INF</span>, and likewise for pairs excluded from interacting by receiver constraints, exerter constraints, or the maximum interaction distance of the interaction type.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">distance()</span> for an alternative distance definition.</p>\n<p class=\"p5\">– (float)localPopulationDensity(object&lt;Individual&gt; receivers, [No&lt;Subpopulation&gt;$ exerterSubpop = NULL])</p>\n<p class=\"p6\">Returns a vector of the local population density present at the location of each individual in <span class=\"s1\">receivers</span>, which does not need to be a singleton; indeed, it can be a vector of all of the individuals in a given subpopulation.<span class=\"Apple-converted-space\">  </span>However, all receivers must be in the same subpopulation.<span class=\"Apple-converted-space\">  </span>The local population density is computed from exerters in <span class=\"s1\">exerterSubpop</span>, or if that is <span class=\"s1\">NULL</span> (the default), then from the receiver’s subpopulation.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.</p>\n<p class=\"p6\">Population density is estimated using interaction strengths, effectively doing a kernel density estimate using the interaction function as the kernel.<span class=\"Apple-converted-space\">  </span>What is returned is computed as the total interaction strength present at a given point, divided by the integral of the interaction function around that point after clipping by the spatial bounds of the exerter subpopulation (what one might think of as the amount of “interaction field” around the point).<span class=\"Apple-converted-space\">  </span>This provides an estimate of local population density, in units of individuals per unit area, as a weighted average over the area covered by the interaction function, where the weight of each exerter in the average is the value of the interaction function at that exerter’s position.<span class=\"Apple-converted-space\">  </span>This can also be thought of as a measure of the amount of interaction happening per unit of interaction field in the space surrounding the point.</p>\n<p class=\"p6\">To calculate the clipped integral of the interaction function, this method uses the same numerical estimator used by the <span class=\"s1\">clippedIntegral()</span> method of <span class=\"s1\">InteractionType</span>, and all of the caveats described for that method apply here also; notably, all individuals must be within spatial bounds, the maximum interaction distance must be less than half the spatial extent of the subpopulation, and <span class=\"s1\">interaction()</span> callbacks are not used (and so, for this method, are not allowed to be active).<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s1\">clippedIntegral()</span> for further discussion of the details of these calculations.</p>\n<p class=\"p6\">To calculate the total interaction strength around the position of a receiver, this method uses the same machinery as the <span class=\"s1\">totalOfNeighborStrengths()</span> method of <span class=\"s1\">InteractionType</span>, <i>except</i> that – in contrast to other <span class=\"s1\">InteractionType</span> methods – the interaction strength exerted by the receiver itself is included in the total (if the exerter subpopulation is the receiver’s own subpopulation).<span class=\"Apple-converted-space\">  </span>This is because population density at the location of an individual includes the individual itself.<span class=\"Apple-converted-space\">  </span>If this is not desirable, the <span class=\"s1\">totalOfNeighborStrengths()</span> method should probably be used.</p>\n<p class=\"p6\">To see the point of this method, consider a receiver located near the edge of the spatial bounds of its subpopulation.<span class=\"Apple-converted-space\">  </span>Some portion of the interaction function that surrounds that receiver falls outside the spatial bounds of its subpopulation, and will therefore never contain an interacting exerter.<span class=\"Apple-converted-space\">  </span>If, for example, interaction strengths are used as a measure of competition, this receiver will therefore have an advantage, because it will never feel any competition from the portion of its range that falls outside spatial bounds.<span class=\"Apple-converted-space\">  </span>However, that portion of its range is presumably also not available to the receiver itself, for foraging or hunting, in which case this advantage is not biologically realistic, but is instead just an undesirable “edge effect” artifact.<span class=\"Apple-converted-space\">  </span>Dividing by the integral of the interaction function, clipped to the spatial bounds, provides a way to compensate for this edge effect.<span class=\"Apple-converted-space\">  </span>A nice side effect of using local population densities instead of total interaction strengths is that the maximum interaction strength passed to <span class=\"s1\">setInteractionFunction()</span> no longer matters; it cancels out when the total interaction strength is divided by the receiver’s clipped integral.<span class=\"Apple-converted-space\">  </span>However, the <i>shape</i> of the interaction function does still matter; it determines the relative weights used for exerters at different distances from the position of the receiver.</p>\n<p class=\"p5\">– (object)nearestInteractingNeighbors(object&lt;Individual&gt; receiver, [integer$ count = 1], [No&lt;Subpopulation&gt;$ exerterSubpop = NULL], [logical$ returnDict = F])</p>\n<p class=\"p6\">Returns an <span class=\"s1\">object&lt;Individual&gt;</span> vector containing up to <span class=\"s1\">count</span> interacting individuals that are spatially closest to <span class=\"s1\">receiver</span>, according to the distance metric of the <span class=\"s1\">InteractionType</span>, from among the exerters in <span class=\"s1\">exerterSubpop</span> (or, if that is <span class=\"s1\">NULL</span>, then from among all individuals in the receiver’s subpopulation).<span class=\"Apple-converted-space\">  </span>More specifically, this method returns only individuals which can exert an interaction upon <span class=\"s1\">receiver</span>, which must be singleton in the default mode of operation (but see below).<span class=\"Apple-converted-space\">  </span>To obtain all of the interacting individuals within the maximum interaction distance of <span class=\"s1\">receiver</span>, simply pass a value for <span class=\"s1\">count</span> that is greater than or equal to the size of the exerter subpopulation.<span class=\"Apple-converted-space\">  </span>Note that if fewer than <span class=\"s1\">count</span> interacting individuals are within the maximum interaction distance, the vector returned may be shorter than <span class=\"s1\">count</span>, or even zero-length; it is important to check for this possibility even when requesting a single neighbor.<span class=\"Apple-converted-space\">  </span>If only the number of interacting individuals is needed, use <span class=\"s1\">interactingNeighborCount()</span> instead.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">Note that this method uses interaction eligibility as a criterion; it will not return neighbors that cannot exert an interaction upon the receiver (due to the configured receiver or exerter constraints).<span class=\"Apple-converted-space\">  </span>(It will also never return the receiver as a neighbor of itself.)<span class=\"Apple-converted-space\">  </span>To find all neighbors of a receiver, whether they can interact with it or not, use <span class=\"s1\">nearestNeighbors()</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, this method has a vectorized mode of operation in which the <span class=\"s1\">receiver</span> parameter may be non-singleton.<span class=\"Apple-converted-space\">  </span>To switch the method to this mode, pass <span class=\"s1\">T</span> for <span class=\"s1\">returnDict</span>, rather than the default of <span class=\"s1\">F</span> (the operation of which is described above).<span class=\"Apple-converted-space\">  </span>In this mode, the return value is a <span class=\"s1\">Dictionary</span> object instead of a vector of <span class=\"s1\">Individual</span> objects.<span class=\"Apple-converted-space\">  </span>This dictionary uses <span class=\"s1\">integer</span> keys that range from <span class=\"s1\">0</span> to <span class=\"s1\">N-1</span>, where <span class=\"s1\">N</span> is the number of individuals passed in <span class=\"s1\">receiver</span>; these keys thus correspond directly to the indices of the individuals in <span class=\"s1\">receiver</span>, and there is one entry in the dictionary for each receiver.<span class=\"Apple-converted-space\">  </span>The value in the dictionary, for a given <span class=\"s1\">integer</span> key, is an <span class=\"s1\">object&lt;Individual&gt;</span> vector with the interacting neighbors found for the corresponding receiver, exactly as described above for the non-vectorized case.<span class=\"Apple-converted-space\">  </span>The results for each receiver can therefore be obtained from the returned dictionary with <span class=\"s1\">getValue()</span>, passing the index of the receiver.<span class=\"Apple-converted-space\">  </span>The speed of this mode of operation will probably be similar to the speed of making <span class=\"s1\">N</span> separate non-vectorized calls to <span class=\"s1\">nearestInteractingNeighbors()</span>, when running single-threaded.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.<span class=\"Apple-converted-space\">  </span>In this mode of operation, all receivers must belong to the same subpopulation.</p>\n<p class=\"p5\">– (object)nearestNeighbors(object&lt;Individual&gt; receiver, [integer$ count = 1], [No&lt;Subpopulation&gt;$ exerterSubpop = NULL], [logical$ returnDict = F])</p>\n<p class=\"p6\">Returns an <span class=\"s1\">object&lt;Individual&gt;</span> vector containing up to <span class=\"s1\">count</span> individuals that are spatially closest to <span class=\"s1\">receiver</span>, according to the distance metric of the <span class=\"s1\">InteractionType</span>, from among the exerters in <span class=\"s1\">exerterSubpop</span> (or, if that is <span class=\"s1\">NULL</span>, then from among all individuals in the receiver’s subpopulation).<span class=\"Apple-converted-space\">  </span>In the default mode of operation, <span class=\"s1\">receiver</span> must be singleton (but see below).<span class=\"Apple-converted-space\">  </span>To obtain all of the individuals within the maximum interaction distance of <span class=\"s1\">receiver</span>, simply pass a value for <span class=\"s1\">count</span> that is greater than or equal to the size of <span class=\"s1\">individual</span>’s subpopulation.<span class=\"Apple-converted-space\">  </span>Note that if fewer than <span class=\"s1\">count</span> individuals are within the maximum interaction distance, the vector returned may be shorter than <span class=\"s1\">count</span>, or even zero-length; it is important to check for this possibility even when requesting a single neighbor.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">Note that this method does not use interaction eligibility as a criterion; it will return neighbors that could not interact with the receiver due to the configured receiver or exerter constraints.<span class=\"Apple-converted-space\">  </span>(It will never return the receiver as a neighbor of itself, however.)<span class=\"Apple-converted-space\">  </span>To find only neighbors that are eligible to exert an interaction upon the receiver, use <span class=\"s1\">nearestInteractingNeighbors()</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, this method has a vectorized mode of operation in which the <span class=\"s1\">receiver</span> parameter may be non-singleton.<span class=\"Apple-converted-space\">  </span>To switch the method to this mode, pass <span class=\"s1\">T</span> for <span class=\"s1\">returnDict</span>, rather than the default of <span class=\"s1\">F</span> (the operation of which is described above).<span class=\"Apple-converted-space\">  </span>In this mode, the return value is a <span class=\"s1\">Dictionary</span> object instead of a vector of <span class=\"s1\">Individual</span> objects.<span class=\"Apple-converted-space\">  </span>This dictionary uses <span class=\"s1\">integer</span> keys that range from <span class=\"s1\">0</span> to <span class=\"s1\">N-1</span>, where <span class=\"s1\">N</span> is the number of individuals passed in <span class=\"s1\">receiver</span>; these keys thus correspond directly to the indices of the individuals in <span class=\"s1\">receiver</span>, and there is one entry in the dictionary for each receiver.<span class=\"Apple-converted-space\">  </span>The value in the dictionary, for a given <span class=\"s1\">integer</span> key, is an <span class=\"s1\">object&lt;Individual&gt;</span> vector with the neighbors found for the corresponding receiver, exactly as described above for the non-vectorized case.<span class=\"Apple-converted-space\">  </span>The results for each receiver can therefore be obtained from the returned dictionary with <span class=\"s1\">getValue()</span>, passing the index of the receiver.<span class=\"Apple-converted-space\">  </span>The speed of this mode of operation will probably be similar to the speed of making <span class=\"s1\">N</span> separate non-vectorized calls to <span class=\"s1\">nearestNeighbors()</span>, when running single-threaded.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.<span class=\"Apple-converted-space\">  </span>In this mode of operation, all receivers must belong to the same subpopulation.</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)nearestNeighborsOfPoint(float point, io&lt;Subpopulation&gt;$ exerterSubpop, [integer$ count = 1])</p>\n<p class=\"p6\">Returns up to <span class=\"s1\">count</span> individuals in <span class=\"s1\">exerterSubpop</span> that are spatially closest to the point given by the spatial coordinates in <span class=\"s1\">point</span>, which may be thought of as the “receiver”, according to the distance metric of the <span class=\"s1\">InteractionType</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">point</span> vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type’s spatiality is <span class=\"s1\">\"xz\"</span>, for example, then <span class=\"s1\">point[0]</span> is assumed to be an <i>x</i> value, and <span class=\"s1\">point[1]</span> is assumed to be a <i>z</i> value, and <span class=\"s1\">point</span> must be exactly two elements in length.<span class=\"Apple-converted-space\">  </span>Be careful; this means that in general it is not safe to pass an individual’s <span class=\"s1\">spatialPosition</span> property for <span class=\"s1\">point</span>, for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on <span class=\"s1\">Individual</span> exist for getting the individual’s coordinates in a particular spatiality, such as the <span class=\"s1\">xz</span> property for this example.<span class=\"Apple-converted-space\">  </span>A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (<span class=\"s1\">pointPeriodic()</span> may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.</p>\n<p class=\"p6\">The subpopulation may be supplied either as an <span class=\"s1\">integer</span> ID, or as a <span class=\"s1\">Subpopulation</span> object.<span class=\"Apple-converted-space\">  </span>To obtain all of the individuals within the maximum interaction distance of <span class=\"s1\">point</span>, simply pass a value for <span class=\"s1\">count</span> that is greater than or equal to the size of <span class=\"s1\">exerterSubpop</span>.<span class=\"Apple-converted-space\">  </span>Note that if fewer than <span class=\"s1\">count</span> individuals are within the maximum interaction distance, the vector returned may be shorter than <span class=\"s1\">count</span>, or even zero-length; it is important to check for this possibility even when requesting a single neighbor.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for <span class=\"s1\">exerterSubpop</span>, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p5\">– (integer)neighborCount(object&lt;Individual&gt; receivers, [No&lt;Subpopulation&gt;$ exerterSubpop = NULL])</p>\n<p class=\"p6\">Returns the number of neighbors for each individual in <span class=\"s1\">receivers</span>, within the maximum interaction distance according to the distance metric of the <span class=\"s1\">InteractionType</span>, from among the individuals in <span class=\"s1\">exerterSubpop</span> (or, if that is <span class=\"s1\">NULL</span>, then from among all individuals in the receiver’s subpopulation).<span class=\"Apple-converted-space\">  </span>All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.</p>\n<p class=\"p6\">This method is similar to <span class=\"s1\">nearestNeighbors()</span> (when passed a large count so as to guarantee that all neighbors are returned), but this method returns only a count of the individuals, not a vector containing the individuals.</p>\n<p class=\"p6\">Note that this method does not use interaction eligibility as a criterion; it will count neighbors that cannot exert an interaction upon a receiver (due to the configured receiver or exerter constraints).<span class=\"Apple-converted-space\">  </span>(It still does not count a receiver as a neighbor of itself, however.)<span class=\"Apple-converted-space\">  </span>If a count of only interacting neighbors is desired, use <span class=\"s1\">interactingNeighborCount()</span>.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p5\">– (integer$)neighborCountOfPoint(float point, io&lt;Subpopulation&gt;$ exerterSubpop)</p>\n<p class=\"p6\">Returns the number of individuals in <span class=\"s1\">exerterSubpop</span> that are within the maximum interaction distance of the point given by the spatial coordinates in <span class=\"s1\">point</span>, which may be thought of as the “receiver”, according to the distance metric of the <span class=\"s1\">InteractionType</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">point</span> vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type’s spatiality is <span class=\"s1\">\"xz\"</span>, for example, then <span class=\"s1\">point[0]</span> is assumed to be an <i>x</i> value, and <span class=\"s1\">point[1]</span> is assumed to be a <i>z</i> value, and <span class=\"s1\">point</span> must be exactly two elements in length.<span class=\"Apple-converted-space\">  </span>Be careful; this means that in general it is not safe to pass an individual’s <span class=\"s1\">spatialPosition</span> property for <span class=\"s1\">point</span>, for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on <span class=\"s1\">Individual</span> exist for getting the individual’s coordinates in a particular spatiality, such as the <span class=\"s1\">xz</span> property for this example.<span class=\"Apple-converted-space\">  </span>A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (<span class=\"s1\">pointPeriodic()</span> may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.</p>\n<p class=\"p6\">The subpopulation may be supplied either as an <span class=\"s1\">integer</span> ID, or as a <span class=\"s1\">Subpopulation</span> object.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for <span class=\"s1\">exerterSubpop</span>, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">This method is similar to <span class=\"s1\">nearestNeighborsOfPoint()</span> (when passed a large count so as to guarantee that all neighbors are returned), but this method returns only a count of the individuals, not a vector containing the individuals.</p>\n<p class=\"p5\">– (void)setConstraints(string$ who, [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL], [Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL])</p>\n<p class=\"p6\">Sets constraints upon which individuals can be receivers and/or exerters, making the target <span class=\"s1\">InteractionType</span> measure interactions between only subsets of the population.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">who</span> specifies upon whom the specified constraints apply; it may be <span class=\"s1\">\"exerter\"</span> to set constraints upon exerters, <span class=\"s1\">\"receiver\"</span> to set constraints upon receivers, or <span class=\"s1\">\"both\"</span> to set constraints upon both.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">\"both\"</span> is used, the <i>same</i> constraints are set for both exerters and receivers; <i>different</i> constraints can be set for exerters versus receivers by making a separate call to <span class=\"s1\">setConstraints()</span> for each.<span class=\"Apple-converted-space\">  </span>Constraints only affect queries that involve the concept of interaction; for example, they will affect the result of <span class=\"s1\">nearestInteractingNeighbors()</span>, but not the result of <span class=\"s1\">nearestNeighbors()</span>.<span class=\"Apple-converted-space\">  </span>The constraints specified by a given call to <span class=\"s1\">setConstraints()</span> override all previously set constraints for the category specified (receivers, exerters, or both).</p>\n<p class=\"p6\">There is a general policy for the remaining arguments: they are <span class=\"s1\">NULL</span> by default, and if <span class=\"s1\">NULL</span> is used, it specifies “no constraint” for that property (removing any currently existing constraint for that property).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">sex</span> parameter constrains the sex of individuals; it may be <span class=\"s1\">\"M\"</span> or <span class=\"s1\">“F\"</span> (or <span class=\"s1\">\"*\"</span> as another way of specifying no constraint, for historical reasons).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">sex</span> is <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span>, the individuals to which the constraint is applied (potential receivers/exerters) must belong to a sexual species.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">tag</span> parameter constrains the <span class=\"s1\">tag</span> property of individuals; if this set, the individuals to which the constraint is applied must have defined <span class=\"s1\">tag</span> values.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">minAge</span> and <span class=\"s1\">maxAge</span> properties constrain the <span class=\"s1\">age</span> property of individuals to the given minimum and/or maximum values; these constraints can only be used in nonWF models.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">migrant</span> property constraints the <span class=\"s1\">migrant</span> property of individuals (<span class=\"s1\">T</span> constrains to only migrants, <span class=\"s1\">F</span> to only non-migrants).<span class=\"Apple-converted-space\">  </span>Finally, the <span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span> properties constrain the corresponding <span class=\"s1\">logical</span> properties of individuals, requiring them to be either <span class=\"s1\">T</span> or <span class=\"s1\">F</span> as specified; the individuals to which these constraints are applied must have defined values for the constrained property or properties.<span class=\"Apple-converted-space\">  </span>Again, <span class=\"s1\">NULL</span> should be supplied (as it is by default) for any property which you do not wish to constrain.</p>\n<p class=\"p6\">These constraints may be used in any combination, as desired.<span class=\"Apple-converted-space\">  </span>For example, calling <span class=\"s1\">setConstraints(\"receivers\", sex=\"M\", minAge=5, tagL0=T)</span> constrains the interaction type’s operation so that receivers must be males, with an <span class=\"s1\">age</span> of at least <span class=\"s1\">5</span>, with a <span class=\"s1\">tagL0</span> property value of <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>For that configuration the potential receivers used with the interaction type must be sexual (since <span class=\"s1\">sex</span> is specified), must be in a nonWF model (since <span class=\"s1\">minAge</span> is specified), and must have a defined value for their <span class=\"s1\">tagL0</span> property (since that property is constrained).<span class=\"Apple-converted-space\">  </span>Note that the <span class=\"s1\">sexSegregation</span> parameter to <span class=\"s1\">initializeInteractionType()</span> is a shortcut which does the same thing as the corresponding calls to <span class=\"s1\">setConstraints()</span>.</p>\n<p class=\"p6\">Exerter constraints are applied at <span class=\"s1\">evaluate()</span> time, whereas receiver constraints are applied at query time; see the <span class=\"s1\">InteractionType</span> class documentation for further discussion.<span class=\"Apple-converted-space\">  </span>The interaction constraints for an interaction type are normally a constant in simulations; in any case, they cannot be changed when an interaction has already been evaluated, so either they should be set prior to evaluation, or <span class=\"s1\">unevaluate()</span> should be called first.</p>\n<p class=\"p3\">– (void)setInteractionFunction(string$ functionType, ...)</p>\n<p class=\"p6\">Set the function used to translate spatial distances into interaction strengths for an interaction type.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">functionType</span> may be <span class=\"s1\">\"f\"</span>, in which case the ellipsis <span class=\"s1\">...</span> should supply a <span class=\"s1\">numeric$</span> fixed interaction strength; <span class=\"s1\">\"l\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> maximum strength for a linear function; <span class=\"s1\">\"e\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> maximum strength and a <span class=\"s1\">numeric$</span> lambda (rate) parameter for a negative exponential function; <span class=\"s1\">\"n\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> maximum strength and a <span class=\"s1\">numeric$</span> sigma (standard deviation) parameter for a Gaussian function; <span class=\"s1\">\"c\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> maximum strength and a <span class=\"s1\">numeric$</span> scale parameter for a Cauchy distribution function; or <span class=\"s1\">\"t\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> maximum strength, a <span class=\"s1\">numeric$</span> degrees of freedom, and a <span class=\"s1\">numeric$</span> scale parameter for a <i>t</i>-distribution function.<span class=\"Apple-converted-space\">  </span>See the InteractionType class documentation for discussions of these interaction functions.<span class=\"Apple-converted-space\">  </span>Non-spatial interactions must use function type <span class=\"s1\">\"f\"</span>, since no distance values are available in that case.</p>\n<p class=\"p6\">The interaction function for an interaction type is normally a constant in simulations; in any case, it cannot be changed when an interaction has already been evaluated, so either it should be set prior to evaluation, or <span class=\"s1\">unevaluate()</span> should be called first.</p>\n<p class=\"p5\">– (float)strength(object&lt;Individual&gt;$ receiver, [No&lt;Individual&gt; exerters = NULL])</p>\n<p class=\"p6\">Returns a vector containing the interaction strengths exerted upon <span class=\"s1\">receiver</span> by the individuals in <span class=\"s1\">exerters</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">exerters</span> is <span class=\"s1\">NULL</span> (the default), then a vector of the interaction strengths exerted by all individuals in the subpopulation of <span class=\"s1\">receiver</span> (including <span class=\"s1\">receiver</span> itself, with a strength of <span class=\"s1\">0.0</span>) is returned; this case may be handled much more efficiently than if a vector of all individuals in the subpopulation is explicitly provided.<span class=\"Apple-converted-space\">  </span>Otherwise, all individuals in <span class=\"s1\">exerters</span> must belong to a single subpopulation (but not necessarily the same subpopulation as <span class=\"s1\">receiver</span>).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.</p>\n<p class=\"p6\">If the strengths of interactions exerted by a single individual upon multiple individuals are needed instead (the inverse of what this method provides), multiple calls to this method will be necessary, one per pairwise interaction queried; the interaction engine is not optimized for the inverse case, and so it will likely be quite slow to compute.<span class=\"Apple-converted-space\">  </span>If the interaction is reciprocal and has the same receiver and exerter constraints, the opposite query should provide identical results in a single efficient call (because then the interactions exerted are equal to the interactions received); otherwise, the best approach might be to define a second interaction type representing the inverse interaction that you wish to be able to query efficiently.</p>\n<p class=\"p5\">– (lo&lt;Individual&gt;)testConstraints(object&lt;Individual&gt; individuals, string$ constraints, [logical$ returnIndividuals = F])</p>\n<p class=\"p6\">Tests the individuals in the parameter <span class=\"s1\">individuals</span> against the interaction constraints specified by <span class=\"s1\">constraints</span>.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">constraints</span> may be <span class=\"s1\">\"receiver\"</span> to use the receiver constraints, or <span class=\"s1\">\"exerter\"</span> to use the exerter constraints.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">returnIndividuals</span> is <span class=\"s1\">F</span> (the default), a <span class=\"s1\">logical</span> vector will be returned, with <span class=\"s1\">T</span> values indicating that the corresponding individual satisfied the constraints, <span class=\"s1\">F</span> values indicating that it did not.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">returnIndividuals</span> is <span class=\"s1\">T</span>, an <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span> will be returned containing only those elements of <span class=\"s1\">individuals</span> that satisfied the constraints (in the same order as <span class=\"s1\">individuals</span>).<span class=\"Apple-converted-space\">  </span>Note that unlike most queries, the <span class=\"s1\">InteractionType</span> does not need to have been evaluated before calling this method, and the individuals passed in need not belong to a single population or even a single species.</p>\n<p class=\"p6\">This method can be useful for narrowing a vector of individuals down to just those that satisfy constraints.<span class=\"Apple-converted-space\">  </span>Outside the context of <span class=\"s1\">InteractionType</span>, similar functionality is provided by the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">subsetIndividuals()</span>.<span class=\"Apple-converted-space\">  </span>Note that the use of <span class=\"s1\">testConstraints()</span> is somewhat rare; usually, queries are evaluated across a vector of individuals, each of which might or might not satisfy the defined constraints.<span class=\"Apple-converted-space\">  </span>Individuals that do not satisfy constraints do not participate in interactions, so their interaction strength with other individuals will simply be zero.</p>\n<p class=\"p6\">See the <span class=\"s1\">setConstraints()</span> method to set up constraints, as well as the <span class=\"s1\">sexSegregation</span> parameter to <span class=\"s1\">initializeInteractionType()</span>.<span class=\"Apple-converted-space\">  </span>Note that if the constraints tested involve <span class=\"s1\">tag</span> values (including <span class=\"s1\">tagL0</span> / <span class=\"s1\">tagL1</span> / <span class=\"s1\">tagL2</span> / <span class=\"s1\">tagL3</span> / <span class=\"s1\">tagL4</span>), the corresponding property or properties of the tested individuals must be defined (i.e., must have been set to a value), or an error will result because the constraints cannot be applied.</p>\n<p class=\"p5\">– (float)totalOfNeighborStrengths(object&lt;Individual&gt; receivers, [No&lt;Subpopulation&gt;$ exerterSubpop = NULL])</p>\n<p class=\"p6\">Returns a vector of the total interaction strength felt by each individual in <span class=\"s1\">receivers</span> by the exerters in <span class=\"s1\">exerterSubpop</span> (or, if that is <span class=\"s1\">NULL</span>, then by all individuals in the receiver’s subpopulation).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">receivers</span> parameter does not need to be a singleton; indeed, it can be a vector of all of the individuals in a given subpopulation.<span class=\"Apple-converted-space\">  </span>All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">evaluate()</span> method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s1\">InteractionType</span> is non-spatial, this method may not be called.</p>\n<p class=\"p6\">For one individual, this is essentially the same as calling <span class=\"s1\">nearestInteractingNeighbors()</span> with a large <span class=\"s1\">count</span> so as to obtain the complete vector of all interacting neighbors, calling <span class=\"s1\">strength()</span> for each of those interactions to get each interaction strength, and adding those interaction strengths together with <span class=\"s1\">sum()</span>.<span class=\"Apple-converted-space\">  </span>This method is much faster than that implementation, however, since all of that work is done as a single operation.<span class=\"Apple-converted-space\">  </span>Also, <span class=\"s1\">totalOfNeighborStrengths()</span> can total up interactions for more than one receiver in a single vectorized call.</p>\n<p class=\"p6\">Similarly, for one individual this is essentially the same as calling <span class=\"s1\">strength()</span> to get the interaction strengths between a receiver and all individuals in the exerter subpopulation, and then calling <span class=\"s1\">sum()</span>.<span class=\"Apple-converted-space\">  </span>Again, this method should be much faster, since this algorithm looks only at neighbors, whereas calling <span class=\"s1\">strength()</span> directly assesses interaction strengths with all other individuals.<span class=\"Apple-converted-space\">  </span>This will make a particularly large difference when the subpopulation size is large and the maximum distance of the <span class=\"s1\">InteractionType</span> is small.</p>\n<p class=\"p6\">See <span class=\"s1\">localPopulationDensity()</span> for a related method that calculates the total interaction strength divided by the amount of “interaction field” present for an individual (i.e., the integral of the interaction function clipped to the spatial bounds of the subpopulation) to provide an estimate of the “interaction density” felt by an individual.</p>\n<p class=\"p3\">– (void)unevaluate(void)</p>\n<p class=\"p6\">Discards all evaluation of this interaction, for all subpopulations.<span class=\"Apple-converted-space\">  </span>The state of the <span class=\"s1\">InteractionType</span> is reset to a state prior to evaluation.<span class=\"Apple-converted-space\">  </span>This can be useful if the model state has changed in such a way that the evaluation already conducted is no longer valid.<span class=\"Apple-converted-space\">  </span>For example, if the maximum distance, the interaction function, or the receiver or exerter constraints of the <span class=\"s1\">InteractionType</span> need to be changed with immediate effect, or if the data used by an <span class=\"s1\">interaction()</span> callback has changed in such a way that previously calculated interaction strengths are no longer correct, <span class=\"s1\">unevaluate()</span> allows the interaction to begin again from scratch.</p>\n<p class=\"p6\"><span class=\"s3\">In WF models, all interactions are automatically reset to an unevaluated state at the moment when the new offspring generation becomes the parental generation (at step 4 in the tick cycle).</span></p>\n<p class=\"p6\"><span class=\"s3\">In nonWF models, all interactions are automatically reset to an unevaluated state twice per tick: immediately after </span><span class=\"s4\">reproduction()</span><span class=\"s3\"> callbacks have completed (after step 1 in the tick cycle), and immediately before viability/survival selection (before step 4 in the tick cycle).</span></p>\n<p class=\"p6\"><span class=\"s3\">Given this automatic invalidation, most simulations have no reason to call </span><span class=\"s4\">unevaluate()</span><span class=\"s3\">.</span></p>\n<p class=\"p11\"><b>5.9<span class=\"Apple-converted-space\">  </span>Class LogFile</b></p>\n<p class=\"p12\"><i>5.9.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>LogFile</i></span><i> properties</i></p>\n<p class=\"p5\">filePath =&gt; (string$)</p>\n<p class=\"p6\">The path of the log file being written to.<span class=\"Apple-converted-space\">  </span>This may be changed with <span class=\"s1\">setFilePath()</span>.</p>\n<p class=\"p5\">logInterval =&gt; (integer$)</p>\n<p class=\"p6\">The interval for automatic logging; a new row of data will be logged every <span class=\"s1\">logInterval</span> ticks.<span class=\"Apple-converted-space\">  </span>This may be set with the <span class=\"s1\">logInterval</span> parameter to <span class=\"s1\">createLogFile()</span> and changed with <span class=\"s1\">setLogInterval()</span>.<span class=\"Apple-converted-space\">  </span>If automatic logging has been disabled, this property will be <span class=\"s1\">0</span>.</p>\n<p class=\"p5\">precision &lt;–&gt; (integer$)</p>\n<p class=\"p6\">The precision of <span class=\"s1\">float</span> output.<span class=\"Apple-converted-space\">  </span>To be exact, <span class=\"s1\">precision</span> specifies the preferred number of significant digits that will be output for <span class=\"s1\">float</span> values.<span class=\"Apple-converted-space\">  </span>The default is <span class=\"s1\">6</span>; values in [<span class=\"s1\">1</span>,<span class=\"s1\">22</span>] are legal, but <span class=\"s1\">17</span> is probably the largest value that makes sense given the limits of double-precision floating point.</p>\n<p class=\"p5\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p12\"><i>5.9.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>LogFile</i></span><i> methods</i></p>\n<p class=\"p5\">– (void)addCustomColumn(string$ columnName, string$ source, [* context = NULL])</p>\n<p class=\"p6\">Adds a new data column with its name provided by <span class=\"s1\">columnName</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>The value for the column, when a given row is generated, will be produced by the code supplied in <span class=\"s1\">source</span>, which is expected to return either <span class=\"s1\">NULL</span> (which will write out <span class=\"s1\">NA</span>), or a singleton value of any non-object type.</p>\n<p class=\"p6\">The <span class=\"s1\">context</span> parameter will be set up as a pseudo-parameter, named <span class=\"s1\">context</span>, when <span class=\"s1\">source</span> is called, allowing the same source code to be used to generate values for multiple data columns; you might, for example, pass the <span class=\"s1\">id</span> of the particular <span class=\"s1\">Subpopulation</span> object that you wish <span class=\"s1\">source</span> to use for its calculations, and <span class=\"s1\">source</span> could then use the <span class=\"s1\">Community</span> method <span class=\"s1\">subpopulationsWithIDs()</span> to look up the subpopulation from the <span class=\"s1\">id</span> value provided in <span class=\"s1\">context</span>.</p>\n<p class=\"p6\">Note that the <span class=\"s1\">Subpopulation</span> object itself cannot be passed in <span class=\"s1\">context</span>, because class <span class=\"s1\">Subpopulation</span> is not under retain-release memory management in SLiM, meaning essentially that subpopulation objects can cease to exist unpredictably (because they go extinct, for example).<span class=\"Apple-converted-space\">  </span>A reference to such an object cannot be kept long-term by your script (including by <span class=\"s1\">LogFile</span>), because if the object ceases to exist, the reference would become invalid and a crash would result.<span class=\"Apple-converted-space\">  </span>Passing such an object – one not under retain-release – to <span class=\"s1\">addCustomColumn()</span> will therefore raise an error, to safeguard against that possible crash.<span class=\"Apple-converted-space\">  </span>The workaround for this limitation is to find a way to look up the desired object, such as the suggestion above of using the subpopulation’s <span class=\"s1\">id</span> to look it up.</p>\n<p class=\"p6\">The use of <span class=\"s1\">context</span> is optional; if the default value of <span class=\"s1\">NULL</span> is used, then <span class=\"s1\">context</span> will be <span class=\"s1\">NULL</span> when <span class=\"s1\">source</span> is called.</p>\n<p class=\"p6\">See <span class=\"s1\">addMeanSDColumns()</span> for a useful variant.</p>\n<p class=\"p5\">– (void)addCycle([No&lt;Species&gt;$ species = NULL])</p>\n<p class=\"p6\">Adds a new data column that provides the cycle counter for <span class=\"s1\">species</span> (the same as the value of the <span class=\"s1\">cycle</span> property of that species).<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>In single-species models, <span class=\"s1\">species</span> may be <span class=\"s1\">NULL</span> to indicate that single species.<span class=\"Apple-converted-space\">  </span>The column will simply be named <span class=\"s1\">cycle</span> in single-species models; an underscore and the name of the species will be appended in multispecies models.</p>\n<p class=\"p5\">– (void)addCycleStage(void)</p>\n<p class=\"p6\">Adds a new data column that provides the cycle stage, named <span class=\"s1\">cycle_stage</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>The stage is provided as a <span class=\"s1\">string</span>, and will typically be <span class=\"s1\">\"first\"</span>, <span class=\"s1\">\"early\"</span>, <span class=\"s1\">\"late\"</span>, or <span class=\"s1\">\"end\"</span> (the latter used for the point in time at which end-of-tick automatic logging occurs).<span class=\"Apple-converted-space\">  </span>Other possible values are discussed in the documentation for the <span class=\"s1\">cycleStage</span> property of <span class=\"s1\">Community</span>, which this column reflects.</p>\n<p class=\"p5\">– (void)addKeysAndValuesFrom(object&lt;Dictionary&gt;$ source)</p>\n<p class=\"p6\">This <span class=\"s1\">Dictionary</span> method has an override in <span class=\"s1\">LogFile</span> to make it illegal to call, since <span class=\"s1\">LogFile</span> manages its <span class=\"s1\">Dictionary</span> entries.</p>\n<p class=\"p5\">– (void)addMeanSDColumns(string$ columnName, string$ source, [* context = NULL])</p>\n<p class=\"p6\">Adds two new data columns with names of <span class=\"s1\">columnName_mean</span> and <span class=\"s1\">columnName_sd</span>.<span class=\"Apple-converted-space\">  </span>The new columns will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>When a given row is generated, the code supplied in <span class=\"s1\">source</span> is expected to return either a zero-length vector of any type including <span class=\"s1\">NULL</span> (which will write out <span class=\"s1\">NA</span> to both columns), or a non-zero-length vector of <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> values.<span class=\"Apple-converted-space\">  </span>In the latter case, the result vector will be summarized in the two columns by its mean and standard deviation respectively.<span class=\"Apple-converted-space\">  </span>If the result vector has exactly one value, the standard deviation will be written as <span class=\"s1\">NA</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">context</span> parameter is set up as a pseudo-parameter when <span class=\"s1\">source</span> is called, as described in <span class=\"s1\">addCustomColumn()</span>.<span class=\"Apple-converted-space\">  </span>See the documentation for that method for further discussion of <span class=\"s1\">context</span>, including limitations on its use.</p>\n<p class=\"p5\">– (void)addPopulationSexRatio([No&lt;Species&gt;$ species = NULL])</p>\n<p class=\"p6\">Adds a new data column that provides the population sex ratio M:(M+F) for <span class=\"s1\">species</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>In single-species models, <span class=\"s1\">species</span> may be <span class=\"s1\">NULL</span> to indicate that single species.<span class=\"Apple-converted-space\">  </span>The column will simply be named <span class=\"s1\">sex_ratio</span> in single-species models; an underscore and the name of the species will be appended in multispecies models.<span class=\"Apple-converted-space\">  </span>If the species is hermaphroditic, <span class=\"s1\">NA</span> will be written.</p>\n<p class=\"p5\">– (void)addPopulationSize([No&lt;Species&gt;$ species = NULL])</p>\n<p class=\"p6\">Adds a new data column that provides the total population size for <span class=\"s1\">species</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>In single-species models, <span class=\"s1\">species</span> may be <span class=\"s1\">NULL</span> to indicate that single species.<span class=\"Apple-converted-space\">  </span>The column will simply be named <span class=\"s1\">num_individuals</span> in single-species models; an underscore and the name of the species will be appended in multispecies models.</p>\n<p class=\"p5\">– (void)addSubpopulationSexRatio(io&lt;Subpopulation&gt;$ subpop)</p>\n<p class=\"p6\">Adds a new data column that provides the sex ratio M:(M+F) of the subpopulation <span class=\"s1\">subpop</span>, named <span class=\"s1\">pX_sex_ratio</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>If the subpopulation exists but has a size of zero, <span class=\"s1\">NA</span> will be written.</p>\n<p class=\"p5\">– (void)addSubpopulationSize(io&lt;Subpopulation&gt;$ subpop)</p>\n<p class=\"p6\">Adds a new data column that provides the size of the subpopulation <span class=\"s1\">subpop</span>, named <span class=\"s1\">pX_num_individuals</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>If the subpopulation exists but has a size of zero, <span class=\"s1\">0</span> will be written.</p>\n<p class=\"p5\">– (void)addSuppliedColumn(string$ columnName)</p>\n<p class=\"p6\">Adds a new data column with its name provided by <span class=\"s1\">columnName</span>.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.<span class=\"Apple-converted-space\">  </span>The value for the column is initially undefined, and will be written as <span class=\"s1\">NA</span>.<span class=\"Apple-converted-space\">  </span>A different value may (optionally) be provided by calling <span class=\"s1\">setSuppliedValue()</span> with a value for <span class=\"s1\">columnName</span>.<span class=\"Apple-converted-space\">  </span>That value will be used for the column the next time a row is generated (whether automatically or by a call to <span class=\"s1\">logRow()</span>), and the column’s value will subsequently be undefined again.<span class=\"Apple-converted-space\">  </span>In other words, for any given logged row the default of <span class=\"s1\">NA</span> may be kept, or a different value may be supplied.<span class=\"Apple-converted-space\">  </span>This allows the value for the column to be set at any point during the tick cycle, which can be convenient if the column’s value depends upon transient state that is no longer available at the time the row is logged.</p>\n<p class=\"p5\">– (void)addTick(void)</p>\n<p class=\"p6\">Adds a new data column, named <span class=\"s1\">tick</span>, that provides the tick number for the simulation.<span class=\"Apple-converted-space\">  </span>The new column will be logged each time that a row is generated, either by automatic logging or by a call to <span class=\"s1\">logRow()</span>.</p>\n<p class=\"p5\">– (void)clearKeysAndValues(void)</p>\n<p class=\"p6\">This <span class=\"s1\">Dictionary</span> method has an override in <span class=\"s1\">LogFile</span> to make it illegal to call, since <span class=\"s1\">LogFile</span> manages its <span class=\"s1\">Dictionary</span> entries.</p>\n<p class=\"p5\">– (void)flush(void)</p>\n<p class=\"p6\">Flushes all buffered data to the output file, synchronously.<span class=\"Apple-converted-space\">  </span>This will make the contents of the file on disk be up-to-date with the running simulation.<span class=\"Apple-converted-space\">  </span>Flushing frequently may entail a small performance penalty.<span class=\"Apple-converted-space\">  </span>More importantly, if <span class=\"s1\">.gz</span> compression has been requested with <span class=\"s1\">compress=T</span> the size of the resulting file will be larger – potentially much larger – if <span class=\"s1\">flush()</span> is called frequently.<span class=\"Apple-converted-space\">  </span>Note that automatic periodic flushing can be requested with the <span class=\"s1\">flushInterval</span> parameter to <span class=\"s1\">createLogFile()</span>.</p>\n<p class=\"p5\">– (void)logRow(void)</p>\n<p class=\"p6\">This logs a new row of data, by evaluating all of the generators added to the <span class=\"s1\">LogFile</span> with <span class=\"s1\">add...()</span> calls.<span class=\"Apple-converted-space\">  </span>Note that the new row may be buffered, and thus may not be written out to disk immediately; see <span class=\"s1\">flush()</span>.<span class=\"Apple-converted-space\">  </span>This method may be used instead of, or in conjunction with, automatic logging.</p>\n<p class=\"p6\">You can get the <span class=\"s1\">LogFile</span> instance, in order to call <span class=\"s1\">logRow()</span> on it, from <span class=\"s1\">community.logFiles</span>, or you can remember it in a global constant with <span class=\"s1\">defineConstant()</span>.</p>\n<p class=\"p5\">– (void)setLogInterval([Ni$ logInterval = NULL])</p>\n<p class=\"p6\">Sets the automatic logging interval.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">logInterval</span> of <span class=\"s1\">NULL</span> stops automatic logging immediately.<span class=\"Apple-converted-space\">  </span>Other values request that a new row should be logged (as if <span class=\"s1\">logRow()</span> were called) at the end of every <span class=\"s1\">logInterval</span> ticks (just before the tick count increment, in both WF and nonWF models), starting at the end of the tick in which <span class=\"s1\">setLogInterval()</span> was called.</p>\n<p class=\"p5\">– (void)setFilePath(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [Nl$ compress = NULL], [Ns$ sep = NULL], [Nl$ header = NULL])</p>\n<p class=\"p6\">Redirects the <span class=\"s1\">LogFile</span> to write new rows to a new <span class=\"s1\">filePath</span>.<span class=\"Apple-converted-space\">  </span>Any rows that have been buffered but not flushed will be written to the previous file first, as if <span class=\"s1\">flush()</span> had been called.<span class=\"Apple-converted-space\">  </span>With this call, new <span class=\"s1\">initialContents</span> may be supplied, which will either replace any existing file or will be appended to it, depending upon the value of <span class=\"s1\">append</span>.<span class=\"Apple-converted-space\">  </span>New values may be supplied for <span class=\"s1\">compress</span>, <span class=\"s1\">sep</span>, and <span class=\"s1\">header</span>; the meaning of these parameters is identical to their meaning in <span class=\"s1\">createLogFile()</span>, except that a value of <span class=\"s1\">NULL</span> for these means “do not change this setting from its previous value”.<span class=\"Apple-converted-space\">  </span>In effect, then, this method lets you start a completely new log file at a new path, without having to create and configure a new <span class=\"s1\">LogFile</span> object.<span class=\"Apple-converted-space\">  </span>The new file will be created (or appended) synchronously, with the specified initial contents.</p>\n<p class=\"p5\">– (void)setSuppliedValue(string$ columnName, +$ value)</p>\n<p class=\"p6\">Registers a value, passed in <span class=\"s1\">value</span>, to be used for the supplied column named <span class=\"s1\">columnName</span> when a row is next logged.<span class=\"Apple-converted-space\">  </span>This column must have been added with <span class=\"s1\">addSuppliedColumn()</span>.<span class=\"Apple-converted-space\">  </span>A value of <span class=\"s1\">NULL</span> may be passed to log <span class=\"s1\">NA</span>, but logging <span class=\"s1\">NA</span> is the default behavior for supplied columns in any case.<span class=\"Apple-converted-space\">  </span>Otherwise, the value must be a singleton, and its type should match the values previously supplied for the column (otherwise the log file may be difficult to parse, since the values within the column will not be of one consistent type).<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">addSuppliedColumn()</span> for further details.</p>\n<p class=\"p5\">– (void)setValue(is$ key, * value)</p>\n<p class=\"p6\">This <span class=\"s1\">Dictionary</span> method has an override in <span class=\"s1\">LogFile</span> to make it illegal to call, since <span class=\"s1\">LogFile</span> manages its <span class=\"s1\">Dictionary</span> entries.</p>\n<p class=\"p5\">– (logical$)willAutolog(void)</p>\n<p class=\"p6\">Returns <span class=\"s1\">T</span> if the log file is configured to log a new row automatically at the end of the current tick; otherwise, returns <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>This is useful for calculating a value that will be logged only in ticks when the value is needed.</p>\n<p class=\"p1\"><b>5.10<span class=\"Apple-converted-space\">  </span>Class Mutation</b></p>\n<p class=\"p2\"><i>5.10.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Mutation</i></span><i> properties</i></p>\n<p class=\"p5\">chromosome =&gt; (object&lt;Chromosome&gt;$)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> object with which the mutation is associated.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this mutation.<span class=\"Apple-converted-space\">  </span>Each mutation created during a run receives an immutable identifier that will be unique across the duration of the run.<span class=\"Apple-converted-space\">  </span>These identifiers are not re-used during a run, except that if a population file is loaded from disk, the loaded mutations will receive their original identifier values as saved in the population file.</p>\n<p class=\"p5\">isFixed =&gt; (logical$)</p>\n<p class=\"p6\"><span class=\"s1\">T</span> if the mutation has fixed (in the SLiM sense of having been converted to a <span class=\"s1\">Substitution</span> object), <span class=\"s1\">F</span> otherwise.<span class=\"Apple-converted-space\">  </span>Since fixed/substituted mutations are removed from the simulation, you will only see this flag be <span class=\"s1\">T</span> if you have held onto a mutation beyond its usual lifetime.</p>\n<p class=\"p5\">isSegregating =&gt; (logical$)</p>\n<p class=\"p6\"><span class=\"s1\">T</span> if the mutation is segregating (in the SLiM sense of not having been either lost or converted to a <span class=\"s1\">Substitution</span> object), <span class=\"s1\">F</span> otherwise.<span class=\"Apple-converted-space\">  </span>Since both lost and fixed/substituted mutations are removed from the simulation, you will only see this flag be <span class=\"s1\">F</span> if you have held onto a mutation beyond its usual lifetime.<span class=\"Apple-converted-space\">  </span>Note that if <span class=\"s1\">isSegregating</span> is <span class=\"s1\">F</span>, <span class=\"s1\">isFixed</span> will let you determine whether the mutation is no longer segregating because it was lost, or because it fixed.</p>\n<p class=\"p3\">mutationType =&gt; (object&lt;MutationType&gt;$)</p>\n<p class=\"p4\">The <span class=\"s1\">MutationType</span> from which this mutation was drawn.</p>\n<p class=\"p5\"><span class=\"s3\">nucleotide &lt;–&gt; (string$)</span></p>\n<p class=\"p6\"><span class=\"s3\">A </span><span class=\"s4\">string</span><span class=\"s3\"> representing the nucleotide associated with this mutation; this will be </span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"C\"</span><span class=\"s3\">, </span><span class=\"s4\">\"G\"</span><span class=\"s3\">, or </span><span class=\"s4\">\"T\"</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If the mutation is not nucleotide-based, this property is unavailable.</span></p>\n<p class=\"p5\"><span class=\"s3\">nucleotideValue &lt;–&gt; (integer$)</span></p>\n<p class=\"p6\"><span class=\"s3\">An </span><span class=\"s4\">integer</span><span class=\"s3\"> representing the nucleotide associated with this mutation; this will be </span><span class=\"s4\">0</span><span class=\"s3\"> (A), </span><span class=\"s4\">1</span><span class=\"s3\"> (C), </span><span class=\"s4\">2</span><span class=\"s3\"> (G), or </span><span class=\"s4\">3</span><span class=\"s3\"> (T).<span class=\"Apple-converted-space\">  </span>If the mutation is not nucleotide-based, this property is unavailable.</span></p>\n<p class=\"p3\">originTick =&gt; (integer$)</p>\n<p class=\"p4\">The tick in which this mutation arose.</p>\n<p class=\"p3\">position =&gt; (integer$)</p>\n<p class=\"p4\">The position in the chromosome of this mutation.</p>\n<p class=\"p3\">selectionCoeff =&gt; (float$)</p>\n<p class=\"p6\"><span class=\"s5\">The selection coefficient of the mutation, drawn from the distribution of fitness effects of its </span><span class=\"s6\">MutationType</span><span class=\"s15\">.</span><span class=\"s3\"><span class=\"Apple-converted-space\">  </span>If a mutation has a </span><span class=\"s4\">selectionCoeff</span><span class=\"s3\"> of <i>s</i>, the multiplicative fitness effect of the mutation in a homozygote is 1+<i>s</i>; in a heterozygote it is 1+<i>hs</i>, where <i>h</i> is the dominance coefficient kept by the mutation type.</span></p>\n<p class=\"p4\">Note that this property has a quirk: it is stored internally in SLiM using a single-precision float, not the double-precision float type normally used by Eidos.<span class=\"Apple-converted-space\">  </span>This means that if you set a mutation <span class=\"s1\">mut</span>’s selection coefficient to some number <span class=\"s1\">x</span>, <span class=\"s1\">mut.selectionCoeff==x</span> may be <span class=\"s1\">F</span> due to floating-point rounding error.<span class=\"Apple-converted-space\">  </span>Comparisons of floating-point numbers for exact equality is often a bad idea, but this is one case where it may fail unexpectedly.<span class=\"Apple-converted-space\">  </span>Instead, it is recommended to use the <span class=\"s1\">id</span> or <span class=\"s1\">tag</span> properties to identify particular mutations.</p>\n<p class=\"p3\">subpopID &lt;–&gt; (integer$)</p>\n<p class=\"p4\">The identifier of the subpopulation in which this mutation arose.<span class=\"Apple-converted-space\">  </span>This property can be used to track the ancestry of mutations through their subpopulation of origin.</p>\n<p class=\"p4\">If you don’t care which subpopulation a mutation originated in, the <span class=\"s1\">subpopID</span> may be used as an arbitrary <span class=\"s1\">integer</span> “tag” value for any purpose you wish; SLiM does not do anything with the value of <span class=\"s1\">subpopID</span> except propagate it to <span class=\"s1\">Substitution</span> objects and report it in output.<span class=\"Apple-converted-space\">  </span>(It must still be <span class=\"s1\">&gt;= 0</span>, however, since SLiM object identifiers are limited to nonnegative integers).</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p2\"><i>5.10.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Mutation</i></span><i> methods</i></p>\n<p class=\"p3\">– (void)setMutationType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Set the mutation type of the mutation to <span class=\"s1\">mutType</span> (which may be specified as either an <span class=\"s1\">integer</span> identifier or a <span class=\"s1\">MutationType</span> object).<span class=\"Apple-converted-space\">  </span>This implicitly changes the dominance coefficient of the mutation to that of the new mutation type, since the dominance coefficient is a property of the mutation type.<span class=\"Apple-converted-space\">  </span>On the other hand, the selection coefficient of the mutation is not changed, since it is a property of the mutation object itself; it can be changed explicitly using the <span class=\"s1\">setSelectionCoeff()</span> method if so desired.</p>\n<p class=\"p4\">The mutation type of a mutation is normally a constant in simulations, so be sure you know what you are doing.<span class=\"Apple-converted-space\">  </span>Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p6\"><span class=\"s3\">In nucleotide-based models, a restriction applies: nucleotide-based mutations may not be changed to a non-nucleotide-based mutation type, and non-nucleotide-based mutations may not be changed to a nucleotide-based mutation type.</span></p>\n<p class=\"p3\">– (void)setSelectionCoeff(float$ selectionCoeff)</p>\n<p class=\"p4\">Set the selection coefficient of the mutation to <span class=\"s1\">selectionCoeff</span>.<span class=\"Apple-converted-space\">  </span>The selection coefficient will be changed for all individuals that possess the mutation, since they all share a single <span class=\"s1\">Mutation</span> object (note that the dominance coefficient will remain unchanged, as it is determined by the mutation type).</p>\n<p class=\"p4\">This is normally a constant in simulations, so be sure you know what you are doing; often setting up a <span class=\"s1\">mutationEffect()</span> callback is preferable, in order to modify the selection coefficient in a more limited and controlled fashion.<span class=\"Apple-converted-space\">  </span>Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p1\"><b>5.11<span class=\"Apple-converted-space\">  </span>Class MutationType</b></p>\n<p class=\"p2\"><i>5.11.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>MutationType</i></span><i> properties</i></p>\n<p class=\"p3\">color &lt;–&gt; (string$)</p>\n<p class=\"p4\">The color used to display mutations of this type in SLiMgui.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">color</span> is the empty string, <span class=\"s1\">\"\"</span>, SLiMgui’s default (selection-coefficient–based) color scheme is used; this is the default for new <span class=\"s1\">MutationType</span> objects.</p>\n<p class=\"p3\">colorSubstitution &lt;–&gt; (string$)</p>\n<p class=\"p4\">The color used to display substitutions of this type in SLiMgui (see the discussion for the <span class=\"s1\">colorSubstitution</span> property of the <span class=\"s1\">Chromosome</span> class for details).<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">colorSubstitution</span> is the empty string, <span class=\"s1\">\"\"</span>, SLiMgui’s default (selection-coefficient–based) color scheme is used; this is the default for new <span class=\"s1\">MutationType</span> objects.</p>\n<p class=\"p3\">convertToSubstitution &lt;–&gt; (logical$)</p>\n<p class=\"p6\"><span class=\"s3\">This property governs whether mutations of this mutation type will be converted to </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects when they reach fixation.</span></p>\n<p class=\"p6\"><span class=\"s3\">In WF models this property is </span><span class=\"s4\">T</span><span class=\"s3\"> by default, since conversion to </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects provides large speed benefits; it should be set to </span><span class=\"s4\">F</span><span class=\"s3\"> only if necessary, and only on the mutation types for which it is necessary.<span class=\"Apple-converted-space\">  </span>This might be needed, for example, if you are using a </span><span class=\"s4\">mutationEffect()</span><span class=\"s3\"> callback to implement an epistatic relationship between mutations; a mutation epistatically influencing the fitness of other mutations through a </span><span class=\"s4\">mutationEffect()</span><span class=\"s3\"> callback would need to continue having that influence even after reaching fixation, but if the simulation were to replace the fixed mutation with a </span><span class=\"s4\">Substitution</span><span class=\"s3\"> object the mutation would no longer be considered in fitness calculations (unless the callback explicitly consulted the list of </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects kept by the simulation).<span class=\"Apple-converted-space\">  </span>Other script-defined behaviors in </span><span class=\"s4\">mutationEffect()</span><span class=\"s3\">, </span><span class=\"s4\">interaction()</span><span class=\"s3\">, </span><span class=\"s4\">mateChoice()</span><span class=\"s3\">, </span><span class=\"s4\">modifyChild()</span><span class=\"s3\">, and </span><span class=\"s4\">recombination()</span><span class=\"s3\"> callbacks might also necessitate the disabling of substitution for a given mutation type; this is an important consideration to keep in mind.</span></p>\n<p class=\"p6\"><span class=\"s3\">In contrast, for nonWF models this property is </span><span class=\"s4\">F</span><span class=\"s3\"> by default, because even mutations with no epistatis or other indirect fitness effects will continue to influence the survival probabilities of individuals.<span class=\"Apple-converted-space\">  </span>For nonWF models, only neutral mutation types with no epistasis or other side effects can safely be converted to substitutions upon fixation.<span class=\"Apple-converted-space\">  </span>When such a pure-neutral mutation type is defined in a nonWF model, this property should be set to </span><span class=\"s4\">T</span><span class=\"s3\"> to tell SLiM that substitution is allowed; this may have very large positive effects on performance, so it is important to remember when modeling background neutral mutations.</span></p>\n<p class=\"p6\"><span class=\"s3\">SLiM consults this flag at the end of each tick when deciding whether to substitute each fixed mutation.<span class=\"Apple-converted-space\">  </span>If this flag is </span><span class=\"s4\">T</span><span class=\"s3\">, all eligible fixed mutations will be converted at the end of the current tick, even if they were previously left unconverted because of the previous value of the flag.<span class=\"Apple-converted-space\">  </span>Setting this flag to </span><span class=\"s4\">F</span><span class=\"s3\"> will prevent future substitutions, but will not cause any existing </span><span class=\"s4\">Substitution</span><span class=\"s3\"> objects to be converted back into </span><span class=\"s4\">Mutation</span><span class=\"s3\"> objects.</span></p>\n<p class=\"p3\">distributionParams =&gt; (fs)</p>\n<p class=\"p4\">The parameters that configure the chosen distribution of fitness effects.<span class=\"Apple-converted-space\">  </span>This will be of type <span class=\"s1\">string</span> for DFE type <span class=\"s1\">\"s\"</span>, and type <span class=\"s1\">float</span> for all other DFE types.</p>\n<p class=\"p3\">distributionType =&gt; (string$)</p>\n<p class=\"p4\">The type of distribution of fitness effects; one of <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"g\"</span><span class=\"s2\">,</span> <span class=\"s1\">\"e\"</span><span class=\"s2\">,</span> <span class=\"s1\">\"n\"</span><span class=\"s2\">,</span> <span class=\"s1\">\"w\"</span><span class=\"s2\">,</span> or <span class=\"s1\">\"s\"</span><span class=\"s2\">:</span></p>\n<p class=\"p13\"><span class=\"s1\">\"f\"</span> – A <b>f</b>ixed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type has a single parameter, the selection coefficient <i>s</i> to be used by all mutations of the mutation type.</p>\n<p class=\"p13\"><span class=\"s1\">\"g\"</span> – A <b>g</b>amma-distributed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by two parameters, a shape parameter and a mean value.<span class=\"Apple-converted-space\">  </span>The gamma distribution from which mutations are drawn is given by the probability density function <span class=\"s16\"><i>P</i>(<i>s</i> | </span><span class=\"s17\"><i>α</i></span><span class=\"s16\">,</span><span class=\"s17\"><i>β</i></span><span class=\"s16\">) </span><span class=\"s17\">= [Γ(<i>α</i></span><span class=\"s16\">)</span><span class=\"s17\"><i>βα</i></span><span class=\"s16\">]<sup>−1</sup>exp(−<i>s</i>/</span><span class=\"s17\"><i>β</i></span><span class=\"s16\">)</span>, where <span class=\"s17\"><i>α</i></span> is the shape parameter, and the specified mean for the distribution is equal to <span class=\"s17\"><i>αβ</i></span>.<span class=\"Apple-converted-space\">  </span>Note that this parameterization is the same as for the Eidos function <span class=\"s1\">rgamma()</span>.<span class=\"Apple-converted-space\">  </span>A gamma distribution is often used to model deleterious mutations at functional sites.</p>\n<p class=\"p13\"><span class=\"s1\">\"e\"</span> – An <b>e</b>xponentially-distributed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by a single parameter, the mean of the distribution.<span class=\"Apple-converted-space\">  </span>The exponential distribution from which mutations are drawn is given by the probability density function <span class=\"s16\"><i>P</i>(<i>s</i> | </span><span class=\"s17\"><i>β</i></span><span class=\"s16\">) = </span><span class=\"s17\"><i>β</i></span><span class=\"s16\"><sup>−1</sup>exp(−<i>s</i>/</span><span class=\"s17\"><i>β</i></span><span class=\"s16\">)</span>, where <span class=\"s17\"><i>β</i></span> is the specified mean for the distribution.<span class=\"Apple-converted-space\">  </span>This parameterization is the same as for the Eidos function <span class=\"s1\">rexp()</span>.<span class=\"Apple-converted-space\">  </span>An exponential distribution is often used to model beneficial mutations.</p>\n<p class=\"p13\"><span class=\"s1\">\"n\"</span> – A <b>n</b>ormally-distributed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by two parameters, a mean and a standard deviation.<span class=\"Apple-converted-space\">  </span>The normal distribution from which mutations are drawn is given by the probability density function <span class=\"s16\"><i>P</i>(<i>s</i> | </span><span class=\"s17\"><i>μ</i></span><span class=\"s16\">,</span><span class=\"s17\"><i>σ</i></span><span class=\"s16\">) = (2</span><span class=\"s17\">π<i>σ</i></span><span class=\"s16\"><sup>2</sup>)<sup>−1/2</sup>exp(−(<i>s</i>−</span><span class=\"s17\"><i>μ</i></span><span class=\"s16\">)<sup>2</sup>/2</span><span class=\"s17\"><i>σ</i></span><span class=\"s16\"><sup>2</sup>)</span>, where <span class=\"s17\"><i>μ</i></span> is the mean and <span class=\"s17\"><i>σ</i></span> is the standard deviation.<span class=\"Apple-converted-space\">  </span>This parameterization is the same as for the Eidos function <span class=\"s1\">rnorm()</span>.<span class=\"Apple-converted-space\">  </span>A normal distribution is often used to model mutations that can be either beneficial or deleterious, since both tails of the distribution are unbounded.</p>\n<p class=\"p14\"><span class=\"s1\">\"p\"</span> – A La<b>p</b>lace-distributed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by two parameters, a mean and a scale.<span class=\"Apple-converted-space\">  </span>The Laplace distribution from which mutations are drawn is given by the probability density function <span class=\"s16\"><i>P</i>(<i>s</i> | <i>μ</i>,<i>b</i>) = exp(−|<i>s</i>−<i>μ</i>|/<i>b</i>)/2<i>b</i></span>, where <span class=\"s16\"><i>μ</i></span> is the mean and <span class=\"s16\"><i>b</i></span> is the scale parameter.<span class=\"Apple-converted-space\">  </span>A Laplace distribution is sometimes used to model a mix of both deleterious and beneficial mutations.</p>\n<p class=\"p13\"><span class=\"s1\">\"w\"</span> – A <b>W</b>eibull-distributed fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by a scale parameter and a shape parameter.<span class=\"Apple-converted-space\">  </span>The Weibull distribution from which mutations are drawn is given by the probability density function <span class=\"s16\"><i>P</i>(<i>s</i> | </span><span class=\"s17\"><i>λ</i></span><span class=\"s16\">,<i>k</i>) = (<i>k</i>/</span><span class=\"s17\"><i>λ</i></span><span class=\"s16\"><i><sup>k</sup></i>)<i>s<sup>k</sup></i><sup>−1</sup>exp(−(<i>s</i>/</span><span class=\"s17\"><i>λ</i></span><span class=\"s16\">)<i><sup>k</sup></i>)</span>, where <span class=\"s17\"><i>λ</i></span> is the scale parameter and <span class=\"s16\"><i>k</i></span> is the shape parameter.<span class=\"Apple-converted-space\">  </span>This parameterization is the same as for the Eidos function <span class=\"s1\">rweibull()</span>.<span class=\"Apple-converted-space\">  </span>A Weibull distribution is often used to model mutations following extreme-value theory.</p>\n<p class=\"p13\"><span class=\"s1\">\"s\"</span> – A <b>s</b>cript-based fitness effect.<span class=\"Apple-converted-space\">  </span>This DFE type is specified by a script parameter of type <span class=\"s1\">string</span>, specifying an Eidos script to be executed to produce each new selection coefficient.<span class=\"Apple-converted-space\">  </span>For example, the script <span class=\"s1\">\"return rbinom(1);\"</span> could be used to generate selection coefficients drawn from a binomial distribution, using the Eidos function <span class=\"s1\">rbinom()</span>, even though that mutational distribution is not supported by SLiM directly.<span class=\"Apple-converted-space\">  </span>The script must return a singleton float or integer.</p>\n<p class=\"p13\">Note that these distributions can in principle produce selection coefficients smaller than <span class=\"s1\">-1.0. </span>In that case<span class=\"s16\">,</span> the mutations will be evaluated as “lethal” by SLiM, and the relative fitness of the individual will be set to <span class=\"s1\">0.0</span><span class=\"s16\">.</span></p>\n<p class=\"p3\">dominanceCoeff &lt;–&gt; (float$)</p>\n<p class=\"p4\">The dominance coefficient used for mutations of this type when heterozygous.<span class=\"Apple-converted-space\">  </span>Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p4\">Note that the dominance coefficient is not bounded.<span class=\"Apple-converted-space\">  </span>A dominance coefficient greater than <span class=\"s1\">1.0</span> may be used to achieve an overdominance effect.<span class=\"Apple-converted-space\">  </span>By making the selection coefficient very small and the dominance coefficient very large, an overdominance scenario in which both homozygotes have the same fitness may be approximated, to a nearly arbitrary degree of precision.</p>\n<p class=\"p4\">Note that this property has a quirk: it is stored internally in SLiM using a single-precision float, not the double-precision float type normally used by Eidos.<span class=\"Apple-converted-space\">  </span>This means that if you set a mutation type <span class=\"s1\">muttype</span>’s dominance coefficient to some number <span class=\"s1\">x</span>, <span class=\"s1\">muttype.dominanceCoeff==x</span> may be <span class=\"s1\">F</span> due to floating-point rounding error.<span class=\"Apple-converted-space\">  </span>Comparisons of floating-point numbers for exact equality is often a bad idea, but this is one case where it may fail unexpectedly.<span class=\"Apple-converted-space\">  </span>Instead, it is recommended to use the <span class=\"s1\">id</span> or <span class=\"s1\">tag</span> properties to identify particular mutation types.</p>\n<p class=\"p5\">hemizygousDominanceCoeff &lt;–&gt; (float$)</p>\n<p class=\"p6\">The dominance coefficient used for mutations of this type when they occur opposite a null haplosome (as can occur in sex-chromosome models and models involving a mix of haploids and diploids).<span class=\"Apple-converted-space\">  </span>This defaults to <span class=\"s1\">1.0</span>, and is used only in models where null haplosomes are present; the <span class=\"s1\">dominanceCoeff</span> property is the dominance coefficient used in most circumstances.<span class=\"Apple-converted-space\">  </span>Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the <span class=\"s1\">Species</span> method <span class=\"s1\">recalculateFitness()</span> – but see the documentation of that method for caveats.</p>\n<p class=\"p6\">As with the <span class=\"s1\">dominanceCoeff</span> property, this is stored internally using a single-precision float; see the documentation for <span class=\"s1\">dominanceCoeff</span> for discussion.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this mutation type; for mutation type <span class=\"s1\">m3</span>, for example, this is <span class=\"s1\">3</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">mutationStackGroup &lt;–&gt; (integer$)</p>\n<p class=\"p4\">The group into which this mutation type belongs for purposes of mutation stacking policy.<span class=\"Apple-converted-space\">  </span>This is equal to the mutation type’s <span class=\"s1\">id</span> by default.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">mutationStackPolicy</span>, below, for discussion.</p>\n<p class=\"p6\"><span class=\"s3\">In nucleotide-based models, the stacking group for nucleotide-based mutation types is always </span><span class=\"s4\">-1</span><span class=\"s3\">, and cannot be changed.<span class=\"Apple-converted-space\">  </span>Non-nucleotide-based mutation types may also be set to share the </span><span class=\"s4\">-1</span><span class=\"s3\"> stacking group, if they should participate in the same stacking policy as nucleotide-based mutations, but that would be quite unusual.</span></p>\n<p class=\"p3\">mutationStackPolicy &lt;–&gt; (string$)</p>\n<p class=\"p4\">This property and the <span class=\"s1\">mutationStackGroup</span> property together govern whether mutations of this mutation type’s stacking group can “stack” – can occupy the same position in a single individual.<span class=\"Apple-converted-space\">  </span>A set of mutation types with the same value for <span class=\"s1\">mutationStackGroup</span> is called a “stacking group”, and all mutation types in a given stacking group must have the same <span class=\"s1\">mutationStackPolicy</span> value, which defines the stacking behavior of all mutations of the mutation types in the stacking group.<span class=\"Apple-converted-space\">  </span>In other words, one stacking group might allow its mutations to stack, while another stacking group might not, but the policy within each stacking group must be unambiguous.</p>\n<p class=\"p6\"><span class=\"s3\">This property is </span><span class=\"s4\">\"s\"</span><span class=\"s3\"> by default, indicating that mutations in this stacking group should be allowed to stack without restriction.<span class=\"Apple-converted-space\">  </span>If the policy is set to </span><span class=\"s4\">\"f\"</span><span class=\"s3\">, the <i>first</i> mutation of stacking group at a given site is retained; further mutations of this stacking group at the same site are discarded with no effect.<span class=\"Apple-converted-space\">  </span>This can be useful for modeling one-way changes; once a gene is disabled by a premature stop codon, for example, you might wish to assume, for simplicity, that further mutations cannot alter that fact.<span class=\"Apple-converted-space\">  </span>If the policy is set to </span><span class=\"s4\">\"l\"</span><span class=\"s3\">, the <i>last</i> mutation of this stacking group at a given site is retained; earlier mutation of this stacking group at the same site are discarded.<span class=\"Apple-converted-space\">  </span>This can be useful for modeling an “infinite-alleles” scenario in which every new mutation at a site generates a completely new allele, rather than retaining the previous mutations at the site.</span></p>\n<p class=\"p4\">The mutation stacking policy applies only within the given mutation type’s stacking group; mutations of different stacking groups are always allowed to stack in SLiM.<span class=\"Apple-converted-space\">  </span>The policy applies to all mutations added to the model after the policy is set, whether those mutations are introduced by calls such as <span class=\"s1\">addMutation()</span>, <span class=\"s1\">addNewMutation()</span>, or <span class=\"s1\">addNewDrawnMutation()</span>, or are added by SLiM’s own mutation-generation machinery.<span class=\"Apple-converted-space\">  </span>However, no attempt is made to enforce the policy for mutations already existing at the time the policy is set; typically, therefore, the policy is set in an <span class=\"s1\">initialize()</span> callback so that it applies throughout the simulation.<span class=\"Apple-converted-space\">  </span>The policy is also not enforced upon the mutations loaded from a file with <span class=\"s1\">readFromPopulationFile()</span>; such mutations were governed by whatever stacking policy was in effect when the population file was generated.</p>\n<p class=\"p6\"><span class=\"s3\">In nucleotide-based models, the stacking policy for nucleotide-based mutation types is always </span><span class=\"s4\">\"l\"</span><span class=\"s3\">, and cannot be changed.<span class=\"Apple-converted-space\">  </span>This ensures that new nucleotide mutations always replace the previous nucleotide at a site, and that more than one nucleotide mutation is never present at the same position in a single haplosome.</span></p>\n<p class=\"p5\"><span class=\"s3\">nucleotideBased =&gt; (logical$)</span></p>\n<p class=\"p6\"><span class=\"s3\">If the mutation type was created with </span><span class=\"s4\">initializeMutationType()</span><span class=\"s3\">, it is not nucleotide-based, and this property is </span><span class=\"s4\">F</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If it was created with </span><span class=\"s4\">initializeMutationTypeNuc()</span><span class=\"s3\">, it is nucleotide-based, and this property is </span><span class=\"s4\">T</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>See those methods for further discussion.</span></p>\n<p class=\"p3\">species =&gt; (object&lt;Species&gt;$)</p>\n<p class=\"p6\"><span class=\"s3\">The species to which the target object belongs.</span></p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to mutation types.</p>\n<p class=\"p2\"><i>5.11.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>MutationType</i></span><i> methods</i></p>\n<p class=\"p5\"><span class=\"s3\">– (float)drawSelectionCoefficient([integer$ n = 1])</span></p>\n<p class=\"p6\"><span class=\"s3\">Draws and returns a vector of </span><span class=\"s4\">n</span><span class=\"s3\"> selection coefficients using the currently defined distribution of fitness effects (DFE) for the target mutation type.<span class=\"Apple-converted-space\">  </span>If the DFE is type </span><span class=\"s4\">\"s\"</span><span class=\"s3\">, this method will result in synchronous execution of the DFE’s script.</span></p>\n<p class=\"p3\">– (void)setDistribution(string$ distributionType, ...)</p>\n<p class=\"p6\">Set the distribution of fitness effects for a mutation type.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">distributionType</span> may be <span class=\"s1\">\"f\"</span>, in which case the ellipsis <span class=\"s1\">...</span> should supply a <span class=\"s1\">numeric$</span> fixed selection coefficient; <span class=\"s1\">\"e\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> mean selection coefficient for the exponential distribution; <span class=\"s1\">\"g\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> mean selection coefficient and a <span class=\"s1\">numeric$</span> alpha shape parameter for a gamma distribution; <span class=\"s1\">\"n\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> mean selection coefficient and a <span class=\"s1\">numeric$</span> sigma (standard deviation) parameter for a normal distribution; <span class=\"s1\">\"p\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> mean selection coefficient and a <span class=\"s1\">numeric$</span> scale parameter for a Laplace distribution; <span class=\"s1\">\"w\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> <span class=\"s2\">λ</span> scale parameter and a <span class=\"s1\">numeric$</span> k shape parameter for a Weibull distribution; or <span class=\"s1\">\"s\"</span>, in which case the ellipsis should supply a <span class=\"s1\">string$</span> Eidos script parameter.<span class=\"Apple-converted-space\">  </span>The DFE for a mutation type is normally a constant in simulations, so be sure you know what you are doing.</p>\n<p class=\"p11\"><b>5.12<span class=\"Apple-converted-space\">  </span>Class Plot</b></p>\n<p class=\"p12\"><i>5.12.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Plot</i></span><i> properties</i></p>\n<p class=\"p5\">title =&gt; (string$)</p>\n<p class=\"p6\">The title of the plot, as originally passed to <span class=\"s1\">createPlot()</span>.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">plotWithTitle()</span> method of <span class=\"s1\">SLiMgui</span>.</p>\n<p class=\"p12\"><i>5.12.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Plot</i></span><i> methods</i></p>\n<p class=\"p5\">– (void)abline([Nif a = NULL], [Nif b = NULL], [Nif h = NULL], [Nif v = NULL], [string color = \"red\"], [numeric lwd = 1.0], [float alpha = 1.0])</p>\n<p class=\"p6\">Adds one or more straight lines to the plot.<span class=\"Apple-converted-space\">  </span>There are three supported modes of operation for this method.<span class=\"Apple-converted-space\">  </span>In the first mode, the lines are specified by <span class=\"s1\">a</span> and <span class=\"s1\">b</span>, representing the intercepts and slopes of the lines, respectively; in this case, <span class=\"s1\">a</span> and <span class=\"s1\">b</span> may be the same length, or one of them may be a singleton to provide a single value used for all of the lines specified by the other.<span class=\"Apple-converted-space\">  </span>In the second mode, the lines are specified by <span class=\"s1\">h</span>, representing the <i>y</i>-values of horizontal lines.<span class=\"Apple-converted-space\">  </span>In the third mode, the lines are specified by <span class=\"s1\">v</span>, representing the <i>x</i>-values of vertical lines.<span class=\"Apple-converted-space\">  </span>These modes are mutually exclusive and cannot be mixed within one call to <span class=\"s1\">abline()</span>.<span class=\"Apple-converted-space\">  </span>The new lines will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The lines will be drawn in colors, line widths, and alpha (opacity) values specified by <span class=\"s1\">color</span>, <span class=\"s1\">lwd</span>, and <span class=\"s1\">alpha</span>, each of which may be either a singleton (to provide one value used for all lines) or a vector equal in length to the number of lines plotted (to provide one value per line).<span class=\"Apple-converted-space\">  </span>Alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.</p>\n<p class=\"p6\">See also <span class=\"s1\">lines()</span> and <span class=\"s1\">segments()</span> for more common approaches to line plotting.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">abline()</span> method is different, and more specialized; the lines plotted by it span the full extent of the plot area, and their coordinates are not considered when dynamically resizing the axes of the plot (i.e., when <span class=\"s1\">createPlot()</span> is not passed explicit, non-<span class=\"s1\">NULL</span> values for <span class=\"s1\">xrange</span> or <span class=\"s1\">yrange</span>).<span class=\"Apple-converted-space\">  </span>This is typically useful for plotting things such as expected values and fit lines.</p>\n<p class=\"p5\">– (void)addLegend([Ns$ position = NULL], [Ni$ inset = NULL], [Nif$ labelSize = NULL], [Nif$ lineHeight = NULL], [Nif$ graphicsWidth = NULL], [Nif$ exteriorMargin = NULL], [Nif$ interiorMargin = NULL])</p>\n<p class=\"p6\">Adds a legend to the plot.<span class=\"Apple-converted-space\">  </span>The legend will be displayed within the plot at the location specified by position, which must be <span class=\"s1\">\"topRight\"</span>, <span class=\"s1\">\"topLeft\"</span>, <span class=\"s1\">\"bottomRight\"</span>, or <span class=\"s1\">\"bottomLeft\"</span>, or <span class=\"s1\">NULL</span> (the default) requesting that SLiMgui choose the position.<span class=\"Apple-converted-space\">  </span>The position of the legend will be inset from the chosen corner by a margin <span class=\"s1\">inset</span>, measured in pixels; the default of <span class=\"s1\">NULL</span> allows SLiMgui to choose the inset.</p>\n<p class=\"p6\">The internal layout of the legend is a bit complex, and can be controlled by five parameters; in all cases, the default value of <span class=\"s1\">NULL</span> requests that SLiMgui provide a reasonable default.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">labelSize</span> parameter specifies the font size used for the text labels for each legend entry (measured in “points”, the standard metric of font sizes).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">lineHeight</span> parameter specifies the vertical size, in pixels, of one entry line.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">graphicsWidth</span> parameter species the width, in pixels, of the column used to display the “graphics” (whether a line segment, a point symbol, a swatch, or a combination of those) associated with each entry.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">exteriorMargin</span> parameter specifies the width/height of margins, in pixels, outside of the entries (between the entries and the legend’s frame).<span class=\"Apple-converted-space\">  </span>Finally, the <span class=\"s1\">interiorMargin</span> parameter specifies the width/height of margins, in pixels, vertically between entries, and also between the “graphics” column and the label.<span class=\"Apple-converted-space\">  </span>It is easy to produce a legend that looks terrible, using these layout metrics; SLiMgui does only minimal sanity-checking of their values, to provide maximal flexibility.</p>\n<p class=\"p6\">The legend is initially empty; entries for it can be added with <span class=\"s1\">legendLineEntry()</span>, <span class=\"s1\">legendPointEntry()</span>, and <span class=\"s1\">legendSwatchEntry()</span>.</p>\n<p class=\"p5\">– (void)axis(integer$ side, [Nif at = NULL], [ls labels = T])</p>\n<p class=\"p6\">Configures an axis of the plot.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">side</span> parameter controls which axis is being configured; at present, it may be <span class=\"s1\">1</span> for the <i>x</i>-axis (at the bottom of the plot), or <span class=\"s1\">2</span> for the <i>y</i>-axis (at the left of the plot).</p>\n<p class=\"p6\">The positions of tick marks (and of any associated labels) are controlled by <span class=\"s1\">at</span>; if <span class=\"s1\">at</span> is <span class=\"s1\">NULL</span> (the default) these positions will be computed automatically based upon the range of the data in the plot, otherwise <span class=\"s1\">at</span> must be a vector of <span class=\"s1\">numeric</span> positions.<span class=\"Apple-converted-space\">  </span>Note that the coordinate system of the plot is controlled not by this method, but by the <span class=\"s1\">xrange</span> and <span class=\"s1\">yrange</span> parameters of <span class=\"s1\">createPlot()</span>; <span class=\"s1\">at</span> controls only the positions of axis ticks <i>within</i> that coordinate system.</p>\n<p class=\"p6\">The <span class=\"s1\">labels</span> parameter controls the text labels displayed for ticks; it may be <span class=\"s1\">T</span> (the default) to label ticks with their numeric positions, <span class=\"s1\">F</span> to suppress all tick labels, or a vector of type <span class=\"s1\">string</span>, equal in length to <span class=\"s1\">at</span>, providing the label for each position in <span class=\"s1\">at</span>.<span class=\"Apple-converted-space\">  </span>Label values may be the empty string, <span class=\"s1\">\"\"</span>, if a label at a given position is not desired, and if <span class=\"s1\">labels</span> is <span class=\"s1\">T</span>, some ticks may not receive a label for readability.</p>\n<p class=\"p5\">– (void)image(object$ image, numeric$ x1, numeric$ y1, numeric$ x2, numeric$ y2, [logical$ flipped = F], [float$ alpha = 1.0])</p>\n<p class=\"p6\">Adds image data given by <span class=\"s1\">image</span> to the plot.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a raster (bitmap, pixel) image in the rectangle specified by <span class=\"s1\">x1</span>, <span class=\"s1\">y1</span>, <span class=\"s1\">x2</span>, and <span class=\"s1\">y2</span>, which must be sorted such that <span class=\"s1\">x1 &lt;= x2</span> and <span class=\"s1\">y1 &lt;= y2</span>.<span class=\"Apple-converted-space\">  </span>When <span class=\"s1\">flipped</span> is <span class=\"s1\">F</span> (the default), the plotted image is shown in a default orientation that is typically best given the source of the image; if <span class=\"s1\">flipped</span> is <span class=\"s1\">T</span> the image’s orientation is flipped vertically relative to that default.<span class=\"Apple-converted-space\">  </span>The plotted image will use opacity <span class=\"s1\">alpha</span>; alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>The new image data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The image data may be specified in one of two ways.<span class=\"Apple-converted-space\">  </span>First, <span class=\"s1\">image</span> may be a singleton <span class=\"s1\">Image</span> object.<span class=\"Apple-converted-space\">  </span>In this case, the image is simply plotted inside the rectangle specified by <span class=\"s1\">x1</span>/<span class=\"s1\">y1</span>/<span class=\"s1\">x2</span>/<span class=\"s1\">y2</span>, fully displaying all of its pixels (in contrast to how the grid values of a spatial map area displayed, as described below).<span class=\"Apple-converted-space\">  </span>The image may be either RGB or grayscale.</p>\n<p class=\"p6\">Second, <span class=\"s1\">image</span> may be a singleton <span class=\"s1\">SpatialMap</span> object.<span class=\"Apple-converted-space\">  </span>In this case, the grid values of the spatial map are plotted aligned to the corners of the rectangle specified by <span class=\"s1\">x1</span>/<span class=\"s1\">y1</span>/<span class=\"s1\">x2</span>/<span class=\"s1\">y2</span>, as the map would be used by SLiM; the edge and corner grid points of the map are therefore only partially displayed.<span class=\"Apple-converted-space\">  </span>(If desired, the <span class=\"s1\">gridValues()</span> or <span class=\"s1\">mapImage()</span> methods of <span class=\"s1\">SpatialMap</span> could be used to convert the map to a matrix or <span class=\"s1\">Image</span> representation that could be plotted differently.)<span class=\"Apple-converted-space\">  </span>The spatial map’s display uses the color scheme that was specified for the map.<span class=\"Apple-converted-space\">  </span>The map’s values are not interpolated, regardless of the map’s <span class=\"s1\">interpolate</span> property; only the raw grid data of the spatial map is displayed.<span class=\"Apple-converted-space\">  </span>(If interpolated display is desired, the <span class=\"s1\">interpolate()</span> method of <span class=\"s1\">SpatialMap</span> can be used to increase the grid resolution of the map prior to display.)</p>\n<p class=\"p6\">This method caches the image data being plotted so that plotting the same <span class=\"s1\">SpatialMap</span> or <span class=\"s1\">Image</span> object multiple times is more efficient.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">matrix()</span> method of <span class=\"s1\">Plot</span> for an alternative way of plotting raster data that may be more suitable in some situations, but that is less efficient because it does not provide such caching.</p>\n<p class=\"p5\">– (void)legendLineEntry(string$ label, [string$ color = \"red\"], [numeric$ lwd = 1.0])</p>\n<p class=\"p6\">Adds a legend entry with text <span class=\"s1\">label</span> to the plot.<span class=\"Apple-converted-space\">  </span>The entry will be displayed as a line segment drawn in color <span class=\"s1\">color</span>, using line width <span class=\"s1\">lwd</span>, mirroring the appearance produced by <span class=\"s1\">lines()</span> for the same parameters.<span class=\"Apple-converted-space\">  </span>If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).</p>\n<p class=\"p5\">– (void)legendPointEntry(string$ label, [integer$ symbol = 0], [string$ color = \"red\"], [string$ border = \"black\"], [numeric$ lwd = 1.0], [numeric$ size = 1.0])</p>\n<p class=\"p6\">Adds a legend entry with text <span class=\"s1\">label</span> to the plot.<span class=\"Apple-converted-space\">  </span>The entry will be displayed as a point symbol specified by <span class=\"s1\">symbol</span>, <span class=\"s1\">color</span>, <span class=\"s1\">border</span>, <span class=\"s1\">lwd</span>, and <span class=\"s1\">size</span>, mirroring the appearance produced by <span class=\"s1\">points()</span> for the same parameters; see <span class=\"s1\">points()</span> for further details.<span class=\"Apple-converted-space\">  </span>If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).</p>\n<p class=\"p5\">– (void)legendSwatchEntry(string$ label, [string$ color = \"red\"])</p>\n<p class=\"p6\">Adds a legend entry with text <span class=\"s1\">label</span> to the plot.<span class=\"Apple-converted-space\">  </span>The entry will be displayed as a swatch drawn in color <span class=\"s1\">color</span>.<span class=\"Apple-converted-space\">  </span>If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).</p>\n<p class=\"p5\">– (void)legendTitleEntry(string$ label)</p>\n<p class=\"p6\">Adds a legend entry with text <span class=\"s1\">label</span> to the plot.<span class=\"Apple-converted-space\">  </span>The entry will be displayed as a title, left-aligned with no graphical representation (no line, point, or swatch).<span class=\"Apple-converted-space\">  </span>A label of <span class=\"s1\">\"\"</span>, the empty string, is allowed and will produce a blank line in the legend (for spacing).<span class=\"Apple-converted-space\">  </span>Note that title entries always produce their own separate line in the legend; they do not participate in the overdrawing scheme used for other types of legend entries.</p>\n<p class=\"p5\">– (void)lines(numeric x, numeric y, [string$ color = \"red\"], [numeric$ lwd = 1.0], [float$ alpha = 1.0])</p>\n<p class=\"p6\">Adds line data given by <span class=\"s1\">x</span> and <span class=\"s1\">y</span> to the plot.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a series of connected line segments, following the (<i>x</i>, <i>y</i>) positions given; note that the <span class=\"s1\">x</span> and <span class=\"s1\">y</span> vectors must be the same length.<span class=\"Apple-converted-space\">  </span>The new line data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The lines will be drawn in color <span class=\"s1\">color</span>, using line width <span class=\"s1\">lwd</span>, with opacity <span class=\"s1\">alpha</span>.<span class=\"Apple-converted-space\">  </span>Alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>Unlike <span class=\"s1\">points()</span> and <span class=\"s1\">text()</span>, the parameters <span class=\"s1\">color</span>, <span class=\"s1\">lwd</span>, and <span class=\"s1\">alpha</span> must be singletons, since each point (except the two ends) is shared by two line segments; if you wish to vary the color/width/opacity for each line segment, separate calls to <span class=\"s1\">lines()</span> are necessary, or the <span class=\"s1\">segments()</span> method may be useful. <span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">abline()</span> and <span class=\"s1\">segments()</span>.</p>\n<p class=\"p5\">– (void)matrix(numeric matrix, numeric$ x1, numeric$ y1, numeric$ x2, numeric$ y2, [logical$ flipped = F], [Nif valueRange = NULL], [Ns$ colors = NULL], [float$ alpha = 1.0])</p>\n<p class=\"p6\">Adds image data given by <span class=\"s1\">matrix</span> to the plot.<span class=\"Apple-converted-space\">  </span>The image data must be specified as a <span class=\"s1\">numeric</span> (i.e., <span class=\"s1\">integer</span> or <span class=\"s1\">float</span>) matrix, as for example produced by the <span class=\"s1\">matrix()</span> function in Eidos.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a raster (bitmap, pixel) image in the rectangle specified by <span class=\"s1\">x1</span>, <span class=\"s1\">y1</span>, <span class=\"s1\">x2</span>, and <span class=\"s1\">y2</span>, which must be sorted such that <span class=\"s1\">x1 &lt;= x2</span> and <span class=\"s1\">y1 &lt;= y2</span>.<span class=\"Apple-converted-space\">  </span>When <span class=\"s1\">flipped</span> is <span class=\"s1\">F</span> (the default), the plotted image is shown in a default orientation that matches the orientation of the matrix (with row <span class=\"s1\">0</span> topmost); if <span class=\"s1\">flipped</span> is <span class=\"s1\">T</span> the image’s orientation is flipped vertically relative to that default (with row <span class=\"s1\">0</span> bottommost).</p>\n<p class=\"p6\">Prior to display, the values in the matrix will be rescaled according to the parameter <span class=\"s1\">valueRange</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">valueRange</span> is <span class=\"s1\">NULL</span> (the default), the values will be left unscaled; this is equivalent to passing <span class=\"s1\">c(0,1)</span> for <span class=\"s1\">valueRange</span>.<span class=\"Apple-converted-space\">  </span>Otherwise, <span class=\"s1\">valueRange</span> should be a <span class=\"s1\">numeric</span> vector containing two elements that define the range of values that will be rescaled to span the interval [0, 1] – the range to which the color scheme will then be applied.<span class=\"Apple-converted-space\">  </span>After rescaling the given range to [<span class=\"s1\">0</span>, <span class=\"s1\">1</span>], the resulting values are clamped to the range [<span class=\"s1\">0</span>, <span class=\"s1\">1</span>].<span class=\"Apple-converted-space\">  </span>It is legal for <span class=\"s1\">valueRange[0]</span> to be greater than <span class=\"s1\">valueRange[1]</span>; in this case, the rescaling operation will, in effect, reverse the direction of the color scheme by reversing the ranks of the reordered values.</p>\n<p class=\"p6\">The rescaled and clamped values are then colored according to the color scheme named by <span class=\"s1\">colors</span>, which should be one of the named schemes supported by the Eidos function <span class=\"s1\">colors()</span>: <span class=\"s1\">\"cm\"</span>, <span class=\"s1\">\"heat\"</span>, <span class=\"s1\">\"terrain\"</span>, <span class=\"s1\">\"parula\"</span>, <span class=\"s1\">\"hot\"</span>, <span class=\"s1\">\"jet\"</span>, <span class=\"s1\">\"turbo\"</span>, <span class=\"s1\">\"gray\"</span>, <span class=\"s1\">\"magma\"</span>, <span class=\"s1\">\"inferno\"</span>, <span class=\"s1\">\"plasma\"</span>, <span class=\"s1\">\"viridis\"</span>, or <span class=\"s1\">\"cividis\"</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">colors</span> is <span class=\"s1\">NULL</span> (the default), the color scheme used is the reverse of the <span class=\"s1\">\"gray\"</span> color scheme, shading from black for <span class=\"s1\">0</span> up to white for <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>In all cases, the color scheme is applied across the range [<span class=\"s1\">0</span>, <span class=\"s1\">1</span>] for the rescaled and clamped values.</p>\n<p class=\"p6\">The plotted image will use opacity <span class=\"s1\">alpha</span>; alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>The new image data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">See the <span class=\"s1\">image()</span> method of <span class=\"s1\">Plot</span> for an alternative way of plotting raster data from <span class=\"s1\">SpatialMap</span> and <span class=\"s1\">Image</span> objects that may be more suitable in some situations.</p>\n<p class=\"p5\">– (void)mtext(numeric x, numeric y, string labels, [string color = \"black\"], [numeric size = 10.0], [Nif adj = NULL], [float alpha = 1.0], [numeric angle = 0.0])</p>\n<p class=\"p6\">Adds marginal text data given by <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">labels</span> to the plot.<span class=\"Apple-converted-space\">  </span>The string values in <span class=\"s1\">labels</span> will be plotted at the (<i>x</i>, <i>y</i>) positions given; note that <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">labels</span> must all be the same length.<span class=\"Apple-converted-space\">  </span>This method differs from the <span class=\"s1\">text()</span> method in two respects.<span class=\"Apple-converted-space\">  </span>The first – the reason that this method draws “marginal” text – is that the text drawn is not clipped to the plot area, allowing text to be drawn in the axis and border areas outside the plot itself.<span class=\"Apple-converted-space\">  </span>The second is that the <span class=\"s1\">x</span> and <span class=\"s1\">y</span> coordinates are interpreted differently than other <span class=\"s1\">Plot</span> methods; rather than being in the coordinate system of the plot, they are in a coordinate system in which the plot area spans [0,1] on both axes.<span class=\"Apple-converted-space\">  </span>This is intended to make positioning text outside of the plot area not depend upon the axis ranges of the plot; those axis ranges might vary, but the positions at which <span class=\"s1\">mtext()</span> draws, relative to the plot area, will remain fixed.<span class=\"Apple-converted-space\">  </span>The new marginal text data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The text will be drawn in color <span class=\"s1\">color</span>, at the font size given by <span class=\"s1\">size</span> (measured in “points”, the standard metric of font sizes); the font family and style cannot be controlled at this time.<span class=\"Apple-converted-space\">  </span>Opacity values may be supplied with <span class=\"s1\">alpha</span>; alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>The angle at which the text is drawn can be specified with <span class=\"s1\">angle</span>; angles are measured in degrees, clockwise.<span class=\"Apple-converted-space\">  </span>All of these parameters (<span class=\"s1\">color</span>, <span class=\"s1\">size</span>, <span class=\"s1\">alpha</span>, and <span class=\"s1\">angle</span>) may either be a singleton value applied to all points, or a vector with one value per corresponding point.</p>\n<p class=\"p6\">The exact position of the text, relative to each point (<i>x</i>, <i>y</i>), is adjusted by the optional parameter <span class=\"s1\">adj</span>.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">adj</span>, if specified, must be a vector of length <span class=\"s1\">2</span>, where <span class=\"s1\">adj[0]</span> adjusts the <i>x</i> position and <span class=\"s1\">adj[1]</span> adjusts the <i>y</i> position of the text.<span class=\"Apple-converted-space\">  </span>Relative to a given <i>x</i> position, a value of <span class=\"s1\">0.0</span> aligns the left edge of the text to it; a value of <span class=\"s1\">0.5</span> aligns the center of the text to it; and a value of <span class=\"s1\">1.0</span> aligns the right edge of the text to it.<span class=\"Apple-converted-space\">  </span>Similarly, relative to a given <i>y</i> position, a value of <span class=\"s1\">0.0</span> aligns the bottom edge of the text to it; a value of <span class=\"s1\">0.5</span> aligns the center of the text to it; and a value of <span class=\"s1\">1.0</span> aligns the top edge of the text to it.<span class=\"Apple-converted-space\">  </span>Intermediate values will produce intermediate alignments, and values of <span class=\"s1\">adj</span> outside of [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>] are also allowed.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">adj</span>, <span class=\"s1\">NULL</span>, is equivalent to <span class=\"s1\">c(0.5, 0.5)</span>, aligning the center of the text to (<i>x</i>, <i>y</i>) both horizontally and vertically.</p>\n<p class=\"p5\">– (void)points(numeric x, numeric y, [integer symbol = 0], [string color = \"red\"], [string border = \"black\"], [numeric lwd = 1.0], [numeric size = 1.0], [float alpha = 1.0])</p>\n<p class=\"p6\">Adds point data given by <span class=\"s1\">x</span> and <span class=\"s1\">y</span> to the plot.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a set of point symbols, centered at the (<i>x</i>, <i>y</i>) positions given; note that the <span class=\"s1\">x</span> and <span class=\"s1\">y</span> vectors must be the same length.<span class=\"Apple-converted-space\">  </span>The new point data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The symbol plotted for each point depends upon the value of <span class=\"s1\">symbol</span>.<span class=\"Apple-converted-space\">  </span>In general, symbols will be drawn in color <span class=\"s1\">color</span>, with a line width <span class=\"s1\">lwd</span> used for lines (if any) in the symbol, and an overall size scaled by <span class=\"s1\">size</span>.<span class=\"Apple-converted-space\">  </span>Symbols <span class=\"s1\">21</span>–<span class=\"s1\">25</span> involve both a filled shape and a border line around that shape; for those symbols, the border line will use the color provided by <span class=\"s1\">border</span>, while the filled shape will use color <span class=\"s1\">color</span>.<span class=\"Apple-converted-space\">  </span>Opacity values may be supplied with <span class=\"s1\">alpha</span>; alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>All of these parameters (<span class=\"s1\">symbol</span>, <span class=\"s1\">color</span>, <span class=\"s1\">border</span>, <span class=\"s1\">lwd</span>, <span class=\"s1\">size</span>, and <span class=\"s1\">alpha</span>) may either be a singleton value applied to all points, or a vector with one value per corresponding point.</p>\n<p class=\"p5\">– (void)rects(numeric x1, numeric y1, numeric x2, numeric y2, [string color = \"red\"], [string border = \"black\"], [numeric lwd = 1.0], [float alpha = 1.0])</p>\n<p class=\"p6\">Adds rectangle data given by <span class=\"s1\">x1</span>, <span class=\"s1\">y1</span>, <span class=\"s1\">x2</span>, and <span class=\"s1\">y2</span> to the plot; note that these four vectors must all be the same length.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a series of rectangles, defined by each (<i>x1</i>, <i>y1</i>, <i>x2</i>, <i>y2</i>) quadret providing the left, right, top and bottom of each rectangle.<span class=\"Apple-converted-space\">  </span>The coordinates of each rectangle do not need to be sorted; in other words, it is not required that <span class=\"s1\">x1[i] &lt;= x2[i]</span>, or that <span class=\"s1\">y1[i] &lt;= y2[i]</span>, and different sorting orders for the coordinates of a given rectangle will draw identically.<span class=\"Apple-converted-space\">  </span>The fill of a each rectangle is contained within its coordinates, but the frame of each rectangle is composed of lines of some width, drawn between the vertices of the rectangle, and will therefore extend beyond the coordinates of the rectangle by one-half of the line width; if this is not desired, inset the rectangle coordinates by one-half of the line width to compensate.<span class=\"Apple-converted-space\">  </span>The new rectangle data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The rectangles will be drawn in fill colors <span class=\"s1\">color</span>, with border colors <span class=\"s1\">border</span>, using line widths <span class=\"s1\">lwd</span>, with opacities <span class=\"s1\">alpha</span> applied to both the fill and the border.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">color</span>, <span class=\"s1\">border</span>, <span class=\"s1\">lwd</span>, and <span class=\"s1\">alpha</span> parameters may each be either a singleton value (applying to all rectangles) or a vector with one value per rectangle.<span class=\"Apple-converted-space\">  </span>Alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>If a filled rectangle with no border is desired, a <span class=\"s1\">border</span> value of <span class=\"s1\">\"none\"</span> can be used; similarly, if a framed rectangle with no fill is desired, a <span class=\"s1\">color</span> value of <span class=\"s1\">\"none\"</span> can be used.<span class=\"Apple-converted-space\">  </span>Note that that <span class=\"s1\">\"none\"</span> a special color value supported only by <span class=\"s1\">rects()</span>; it is not part of the standard set of named colors in Eidos.</p>\n<p class=\"p5\">– (void)segments(numeric x1, numeric y1, numeric x2, numeric y2, [string color = \"red\"], [numeric lwd = 1.0], [float alpha = 1.0])</p>\n<p class=\"p6\">Adds line segment data given by <span class=\"s1\">x1</span>, <span class=\"s1\">y1</span>, <span class=\"s1\">x2</span>, and <span class=\"s1\">y2</span> to the plot; note that these four vectors must all be the same length.<span class=\"Apple-converted-space\">  </span>The data will be plotted as a series of unconnected line segments, from each (<i>x1</i>, <i>y1</i>) position to the corresponding (<i>x2</i>, <i>y2</i>) position.<span class=\"Apple-converted-space\">  </span>The new line segment data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The line segments will be drawn in colors <span class=\"s1\">color</span>, using line widths <span class=\"s1\">lwd</span>, with opacities <span class=\"s1\">alpha</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">color</span>, <span class=\"s1\">lwd</span>, and <span class=\"s1\">alpha</span> parameters may each be either a singleton value (applying to all line segments) or a vector with one value per line segment.<span class=\"Apple-converted-space\">  </span>Alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque. <span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">lines()</span> and <span class=\"s1\">abline()</span>.</p>\n<p class=\"p5\">– (void)setBorderless([numeric$ marginLeft = 0.0], [numeric$ marginTop = 0.0], [numeric$ marginRight = 0.0], [numeric$ marginBottom = 0.0])</p>\n<p class=\"p6\">Reconfigures the plot to be borderless – to not display axes, ticks, or the labels for axes and ticks.<span class=\"Apple-converted-space\">  </span>Since those elements are not present, the plot area in borderless plots essentially fills the window’s available area, except for being inset by the margins given in <span class=\"s1\">marginLeft</span>, <span class=\"s1\">marginTop</span>, <span class=\"s1\">marginRight</span>, and <span class=\"s1\">marginBottom</span>, which are specified in pixels.<span class=\"Apple-converted-space\">  </span>The axis ranges are not extended in the usual manner; if the range of the <i>x</i> axis is specified as <span class=\"s1\">c(0,1)</span>, for example, then that is the range actually used for the <i>x</i> axis.<span class=\"Apple-converted-space\">  </span>(This is similar to R’s <span class=\"s1\">\"xaxs\"</span> and <span class=\"s1\">\"yaxs\"</span> being specified as <span class=\"s1\">\"i\"</span>, rather than the usual behavior specified by the default of <span class=\"s1\">\"r\"</span>.)<span class=\"Apple-converted-space\">  </span>If you want the plotted data to have “breathing room” around it, you should therefore specify non-zero margins.</p>\n<p class=\"p6\">Note that the <span class=\"s1\">fullBox</span> parameter of <span class=\"s1\">createPlot()</span> is still honored; for borderless plots, the box is drawn at the outer edge of the margin area.<span class=\"Apple-converted-space\">  </span>If you don’t want the box to overdraw any of the data area of the plot (within the extents of the axes), you should specify each margin value as <span class=\"s1\">1</span> (or greater), to provide a pixel of margin space within which the box will be drawn without impinging upon the plotted data.</p>\n<p class=\"p5\">– (void)text(numeric x, numeric y, string labels, [string color = \"black\"], [numeric size = 10.0], [Nif adj = NULL], [float alpha = 1.0], [numeric angle = 0.0])</p>\n<p class=\"p6\">Adds text data given by <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">labels</span> to the plot.<span class=\"Apple-converted-space\">  </span>The string values in <span class=\"s1\">labels</span> will be plotted at the (<i>x</i>, <i>y</i>) positions given; note that <span class=\"s1\">x</span>, <span class=\"s1\">y</span>, and <span class=\"s1\">labels</span> must all be the same length.<span class=\"Apple-converted-space\">  </span>The new text data will be plotted on top of any previously added data.</p>\n<p class=\"p6\">The text will be drawn in color <span class=\"s1\">color</span>, at the font size given by <span class=\"s1\">size</span> (measured in “points”, the standard metric of font sizes); the font family and style cannot be controlled at this time.<span class=\"Apple-converted-space\">  </span>Opacity values may be supplied with <span class=\"s1\">alpha</span>; alpha values must be in [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>], where <span class=\"s1\">0.0</span> is fully transparent and <span class=\"s1\">1.0</span> is fully opaque.<span class=\"Apple-converted-space\">  </span>The angle at which the text is drawn can be specified with <span class=\"s1\">angle</span>; angles are measured in degrees, clockwise.<span class=\"Apple-converted-space\">  </span>All of these parameters (<span class=\"s1\">color</span>, <span class=\"s1\">size</span>, <span class=\"s1\">alpha</span>, and <span class=\"s1\">angle</span>) may either be a singleton value applied to all points, or a vector with one value per corresponding point.</p>\n<p class=\"p6\">The exact position of the text, relative to each point (<i>x</i>, <i>y</i>), is adjusted by the optional parameter <span class=\"s1\">adj</span>.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">adj</span>, if specified, must be a vector of length <span class=\"s1\">2</span>, where <span class=\"s1\">adj[0]</span> adjusts the <i>x</i> position and <span class=\"s1\">adj[1]</span> adjusts the <i>y</i> position of the text.<span class=\"Apple-converted-space\">  </span>Relative to a given <i>x</i> position, a value of <span class=\"s1\">0.0</span> aligns the left edge of the text to it; a value of <span class=\"s1\">0.5</span> aligns the center of the text to it; and a value of <span class=\"s1\">1.0</span> aligns the right edge of the text to it.<span class=\"Apple-converted-space\">  </span>Similarly, relative to a given <i>y</i> position, a value of <span class=\"s1\">0.0</span> aligns the bottom edge of the text to it; a value of <span class=\"s1\">0.5</span> aligns the center of the text to it; and a value of <span class=\"s1\">1.0</span> aligns the top edge of the text to it.<span class=\"Apple-converted-space\">  </span>Intermediate values will produce intermediate alignments, and values of <span class=\"s1\">adj</span> outside of [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>] are also allowed.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">adj</span>, <span class=\"s1\">NULL</span>, is equivalent to <span class=\"s1\">c(0.5, 0.5)</span>, aligning the center of the text to (<i>x</i>, <i>y</i>) both horizontally and vertically.</p>\n<p class=\"p6\">See also the <span class=\"s1\">mtext()</span> method, for drawing text outside of the plot area.</p>\n<p class=\"p5\">– (void)write(string$ filePath)</p>\n<p class=\"p6\">Writes the plot to the given filesystem path <span class=\"s1\">filePath</span> as a PDF file.<span class=\"Apple-converted-space\">  </span>It is suggested, but not required, that <span class=\"s1\">filePath</span> should end in a <span class=\"s1\">.pdf</span> or <span class=\"s1\">.PDF</span> filename extension.<span class=\"Apple-converted-space\">  </span>If the file cannot be written, an error will result.</p>\n<p class=\"p1\"><b>5.13<span class=\"Apple-converted-space\">  </span>Class SLiMEidosBlock</b></p>\n<p class=\"p2\"><i>5.13.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SLiMEidosBlock</i></span><i> properties</i></p>\n<p class=\"p3\">active &lt;–&gt; (integer$)</p>\n<p class=\"p6\">If this evaluates to <span class=\"s1\">logical</span> <span class=\"s1\">F</span> (i.e., is equal to <span class=\"s1\">0</span>), the script block is inactive and will not be called.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">active</span> for all registered script blocks is reset to <span class=\"s1\">-1</span> at the beginning of each tick, prior to script events being called, thus activating all blocks (except callbacks associated with a species that is not active in that tick, which are deactivated as part of the deactivation of the species).<span class=\"Apple-converted-space\">  </span>Any <span class=\"s1\">integer</span> value other than <span class=\"s1\">-1</span> may be used instead of <span class=\"s1\">-1</span> to represent that a block is active; for example, <span class=\"s1\">active</span> may be used as a counter to make a block execute a fixed number of times in each tick.<span class=\"Apple-converted-space\">  </span>This value is not cached by SLiM; if it is changed, the new value takes effect immediately.<span class=\"Apple-converted-space\">  </span>For example, a callback might be activated and inactivated repeatedly during a single tick.</p>\n<p class=\"p3\">end =&gt; (integer$)</p>\n<p class=\"p4\">The last tick in which the script block is active.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this script block; for script <span class=\"s1\">s3</span>, for example, this is <span class=\"s1\">3</span>.<span class=\"Apple-converted-space\">  </span>A script block for which no <span class=\"s1\">id</span> was given will have an <span class=\"s1\">id</span> of <span class=\"s1\">-1</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">source =&gt; (string$)</p>\n<p class=\"p4\">The source code string of the script block.</p>\n<p class=\"p5\">speciesSpec =&gt; (object&lt;Species&gt;)</p>\n<p class=\"p6\">The <span class=\"s1\">species</span> specifier for the script block.<span class=\"Apple-converted-space\">  </span>The species specifier for a callback block indicates the callback’s associated species; the callback is called to modify the default behavior for that species.<span class=\"Apple-converted-space\">  </span>If the script block has no <span class=\"s1\">species</span> specifier, this property’s value is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Species</span>.<span class=\"Apple-converted-space\">  </span>This property is read-only; normally it is set by preceding the definition of a callback with a <span class=\"s1\">species</span> specifier, of the form <span class=\"s1\">species &lt;species-name&gt;</span>.</p>\n<p class=\"p3\">start =&gt; (integer$)</p>\n<p class=\"p4\">The first tick in which the script block is active.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p5\">ticksSpec =&gt; (object&lt;Species&gt;)</p>\n<p class=\"p6\">The <span class=\"s1\">ticks</span> specifier for the script block.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">ticks</span> specifier for an event block indicates the event’s associated species; the event executes only in ticks when that species is active.<span class=\"Apple-converted-space\">  </span>If the script block has no <span class=\"s1\">ticks</span> specifier, this property’s value is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Species</span>.<span class=\"Apple-converted-space\">  </span>This property is read-only; normally it is set by preceding the definition of an event with a <span class=\"s1\">ticks</span> specifier, of the form <span class=\"s1\">ticks &lt;species-name&gt;</span>.</p>\n<p class=\"p3\">type =&gt; (string$)</p>\n<p class=\"p6\">The type of the script block; this will be <span class=\"s1\">\"first\"</span>, <span class=\"s1\">\"early\"</span>, or <span class=\"s1\">\"late\"</span> for the three types of Eidos events, or <span class=\"s1\">\"initialize\"</span>, <span class=\"s1\">\"fitnessEffect\"</span>, <span class=\"s1\">\"interaction\"</span>, <span class=\"s1\">\"mateChoice\"</span>, <span class=\"s1\">\"modifyChild\"</span>, <span class=\"s1\">\"mutation\"</span>, <span class=\"s1\">\"mutationEffect\"</span>, <span class=\"s1\">\"recombination\"</span>, <span class=\"s1\">\"reproduction\"</span>, or <span class=\"s1\">\"survival\"</span> for the respective types of Eidos callbacks.</p>\n<p class=\"p2\"><i>5.13.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SLiMEidosBlock</i></span><i> methods</i></p>\n<p class=\"p15\"><br></p>\n<p class=\"p1\"><b>5.14<span class=\"Apple-converted-space\">  </span>Class SLiMgui</b></p>\n<p class=\"p2\"><i>5.14.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SLiMgui</i></span><i> properties</i></p>\n<p class=\"p5\"><span class=\"s3\">pid =&gt; (integer$)</span></p>\n<p class=\"p6\"><span class=\"s3\">The Un*x process identifier (commonly called the “pid”) of the running SLiMgui application.<span class=\"Apple-converted-space\">  </span>This can be useful for scripts that wish to use system calls to influence the SLiMgui application.</span></p>\n<p class=\"p2\"><i>5.14.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SLiMgui</i></span><i> methods</i></p>\n<p class=\"p5\">– (No&lt;Plot&gt;$)createPlot(string$ title, [Nif xrange = NULL], [Nif yrange = NULL], [string$ xlab = \"x\"], [string$ ylab = \"y\"], [Nif$ width = NULL], [Nif$ height = NULL], [logical$ horizontalGrid = F], [logical$ verticalGrid = F], [logical$ fullBox = T], [numeric$ axisLabelSize = 15], [numeric$ tickLabelSize = 10])</p>\n<p class=\"p6\">Creates and returns a new custom plot referred to by <span class=\"s1\">title</span>, or restarts and returns the existing plot with that title; if the plot cannot be created (notably, when running under SLiMguiLegacy rather than SLiMgui), <span class=\"s1\">NULL</span> is returned.<span class=\"Apple-converted-space\">  </span>The range for the <i>x</i> and <i>y</i> axes of the plot can optionally be provided in <span class=\"s1\">xrange</span> and <span class=\"s1\">yrange</span>, as vectors of length <span class=\"s1\">2</span> containing the minimum and maximum values for the corresponding axis; the default of <span class=\"s1\">NULL</span> for these parameters requests that the axis ranges be determined heuristically based upon the data subsequently added to the plot.<span class=\"Apple-converted-space\">  </span>Labels for the <i>x</i> and <i>y</i> axes can be provided in <span class=\"s1\">xlab</span> and <span class=\"s1\">ylab</span>; if no axis label is desired, the empty string <span class=\"s1\">\"\"</span> may be passed.<span class=\"Apple-converted-space\">  </span>The width and height of the window itself can optionally be set with <span class=\"s1\">width</span> and <span class=\"s1\">height</span>, in units of pixels (perhaps 70–100 pixels per inch, depending on your screen’s pixel density); the default of <span class=\"s1\">NULL</span> for these parameters requests SLiMgui’s default plot window size.<span class=\"Apple-converted-space\">  </span>The display of horizontal grid lines, vertical grid lines, and a full box around the plot area can be controlled with <span class=\"s1\">horizontalGrid</span>, <span class=\"s1\">verticalGrid</span>, and <span class=\"s1\">fullBox</span> respectively, and the size (in points) of axis and tick labels can be controlled with <span class=\"s1\">axisLabelSize</span> and <span class=\"s1\">tickLabelSize</span> respectively.</p>\n<p class=\"p6\">Once the plot has been created, data can be added to it using <span class=\"s1\">Plot</span> methods such as <span class=\"s1\">lines()</span>, <span class=\"s1\">points()</span>, and <span class=\"s1\">text()</span>.<span class=\"Apple-converted-space\">  </span>As with other plot windows in SLiMgui, the “action button” can be used to access plot configuration options, and to copy or save the final plot as a raster image or a PDF file.</p>\n<p class=\"p5\">– (Nfs)logFileData(object&lt;LogFile&gt;$ logFile, is$ column)</p>\n<p class=\"p6\">Returns a vector containing data from the <span class=\"s1\">LogFile</span> object <span class=\"s1\">logFile</span>, taken from a specified column (identified in <span class=\"s1\">column</span> either by the column’s name or by its zero-based index).<span class=\"Apple-converted-space\">  </span>If the data are all numeric, they will be returned as a <span class=\"s1\">float</span> vector.<span class=\"Apple-converted-space\">  </span>Otherwise – if the data are non-numeric – they will be returned as a <span class=\"s1\">string</span> vector.<span class=\"Apple-converted-space\">  </span>If the specified column does not exist in the log file, <span class=\"s1\">NULL</span> will be returned.</p>\n<p class=\"p6\">This functionality is provided as a method on the <span class=\"s1\">SLiMgui</span> class, rather than on <span class=\"s1\">LogFile</span>, because in SLiMgui logged data is kept in memory anyway, for display in the debugging output viewer window.<span class=\"Apple-converted-space\">  </span>When running at the command line logged data is not kept in memory, and thus is not available.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)openDocument(string$ filePath)</span></p>\n<p class=\"p6\">Open the document at <span class=\"s1\">filePath</span> in SLiMgui, if possible.<span class=\"Apple-converted-space\">  </span>Supported document types include SLiM model files (typically with a <span class=\"s1\">.slim</span> path extension), text files (typically with a <span class=\"s1\">.txt</span> path extension, and opened as untitled model files), and PNG, JPG/JPEG, BMP, and GIF image file formats (typically <span class=\"s1\">.png</span> / <span class=\"s1\">.jpg</span> / <span class=\"s1\">.jpeg</span> / <span class=\"s1\">.bmp</span> / <span class=\"s1\">.gif</span>, respectively).<span class=\"Apple-converted-space\">  </span>(Note that in SLiMguiLegacy, PDF files (<span class=\"s1\">.pdf</span>) are supported but these other image file formats are not.)<span class=\"Apple-converted-space\">  </span>This method can be particularly useful for opening images created by the simulation itself, often by sublaunching a plotting process in R or another environment.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)pauseExecution(void)</span></p>\n<p class=\"p6\"><span class=\"s3\">Pauses a model that is playing in SLiMgui.<span class=\"Apple-converted-space\">  </span>This is essentially equivalent to clicking the “Play” button to stop the execution of the model.<span class=\"Apple-converted-space\">  </span>Execution can be resumed by the user, by clicking the “Play” button again; unlike calling </span><span class=\"s4\">stop()</span><span class=\"s3\"> or </span><span class=\"s4\">simulationFinished()</span><span class=\"s3\">, the simulation is not terminated.<span class=\"Apple-converted-space\">  </span>This method can be useful for debugging or exploratory purposes, to pause the model at a point of interest.<span class=\"Apple-converted-space\">  </span>Execution is paused at the end of the currently executing tick, not mid-tick.</span></p>\n<p class=\"p6\"><span class=\"s3\">If the model is being profiled, or is executing forward to a tick number entered in the tick field, </span><span class=\"s4\">pauseExecution()</span><span class=\"s3\"> will do nothing; by design, </span><span class=\"s4\">pauseExecution()</span><span class=\"s3\"> only pauses execution when SLiMgui is doing a simple “Play” of the model.</span></p>\n<p class=\"p5\">– (No&lt;Plot&gt;$)plotWithTitle(string$ title)</p>\n<p class=\"p6\">Returns an existing plot that was created by <span class=\"s1\">createPlot()</span> with <span class=\"s1\">title</span>; if such a plot does not exist, <span class=\"s1\">NULL</span> is returned.<span class=\"Apple-converted-space\">  </span>Note that other SLiMgui plots cannot be accessed through this method; only plots created by <span class=\"s1\">createPlot()</span> are available in Eidos.</p>\n<p class=\"p11\"><b>5.15<span class=\"Apple-converted-space\">  </span>Class SpatialMap</b></p>\n<p class=\"p5\">(object&lt;SpatialMap&gt;$)SpatialMap(string$ name, object&lt;SpatialMap&gt;$ map)</p>\n<p class=\"p6\">Creates a new <span class=\"s1\">SpatialMap</span> object that is a copy of <span class=\"s1\">map</span>, named <span class=\"s1\">name</span>.</p>\n<p class=\"p12\"><i>5.15.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SpatialMap</i></span><i> properties</i></p>\n<p class=\"p5\">gridDimensions =&gt; (integer)</p>\n<p class=\"p6\">The dimensions of the spatial map’s grid of values, in the order of the components of the map’s spatiality.<span class=\"Apple-converted-space\">  </span>For example, a map with spatiality <span class=\"s1\">\"xz\"</span> and a grid of values that is <span class=\"s1\">500</span> in the <span class=\"s1\">\"x\"</span> dimension by <span class=\"s1\">300</span> in the <span class=\"s1\">\"z\"</span> dimension would return <span class=\"s1\">c(500, 300)</span> for this property.</p>\n<p class=\"p5\">interpolate &lt;–&gt; (logical$)</p>\n<p class=\"p6\">Whether interpolation between grid values is enabled (<span class=\"s1\">T</span>) or disabled (<span class=\"s1\">F</span>).<span class=\"Apple-converted-space\">  </span>The initial value of this property is set by <span class=\"s1\">defineSpatialMap()</span>, but it can be changed.<span class=\"Apple-converted-space\">  </span>The interpolation performed is linear; for cubic interpolation, use the <span class=\"s1\">interpolate()</span> method.</p>\n<p class=\"p5\">name =&gt; (string$)</p>\n<p class=\"p6\">The name of the spatial map, usually as provided to <span class=\"s1\">defineSpatialMap()</span>.<span class=\"Apple-converted-space\">  </span>The names of spatial maps must be unique within any given subpopulation, but the same name may be reused for different spatial maps in different subpopulations.<span class=\"Apple-converted-space\">  </span>The name is used to identify a map for methods such as <span class=\"s1\">spatialMapValue()</span>, and is also used for display in SLiMgui.</p>\n<p class=\"p5\">spatialBounds =&gt; (float)</p>\n<p class=\"p6\">The spatial bounds to which the spatial map is aligned.<span class=\"Apple-converted-space\">  </span>These bounds come from the subpopulation that originally created the map, with the <span class=\"s1\">defineSpatialMap()</span> method, and cannot be subsequently changed.<span class=\"Apple-converted-space\">  </span>All subpopulations that use a given spatial map must match that map’s spatial bounds, so that the map does not stretch or shrink relative to its initial configuration.<span class=\"Apple-converted-space\">  </span>The components of the spatial bounds of a map correspond to the components of the map’s spatiality; for example, a map with spatiality <span class=\"s1\">\"xz\"</span> will have bounds (<span class=\"s1\">x0</span>, <span class=\"s1\">z0</span>, <span class=\"s1\">x1</span>, <span class=\"s1\">z1</span>); bounds for <span class=\"s1\">\"y\"</span> are not included, since that dimension is not used by the spatial map.</p>\n<p class=\"p5\">spatiality =&gt; (string$)</p>\n<p class=\"p6\">The spatiality of the map: the subset of the model’s dimensions that are used by the spatial map.<span class=\"Apple-converted-space\">  </span>The spatiality of a map is configured by <span class=\"s1\">defineSpatialMap()</span> and cannot subsequently be changed.<span class=\"Apple-converted-space\">  </span>For example, a 3D model (with dimensionality <span class=\"s1\">\"xyz\"</span>) might define a 2D spatial map with spatiality <span class=\"s1\">\"xz\"</span>, providing spatial values that do not depend upon the <span class=\"s1\">\"y\"</span> dimension.<span class=\"Apple-converted-space\">  </span>Often, however, the spatiality of a map will match the dimensionality of the model.</p>\n<p class=\"p5\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p6\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods (provided by the <span class=\"s1\">Dictionary</span> class; see the Eidos manual), for another way of attaching state to spatial maps.</p>\n<p class=\"p12\"><i>5.15.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>SpatialMap</i></span><i> methods</i></p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)add(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Adds <span class=\"s1\">x</span> to the spatial map.<span class=\"Apple-converted-space\">  </span>One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, <span class=\"s1\">x</span> is added to each grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each value of <span class=\"s1\">x</span> is added to the corresponding grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of <span class=\"s1\">x</span> is added to the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)blend(ifo&lt;SpatialMap&gt; x, float$ xFraction)</p>\n<p class=\"p6\">Blends <span class=\"s1\">x</span> into the spatial map, giving <span class=\"s1\">x</span> a weight of <span class=\"s1\">xFraction</span> and the existing values in the target spatial map a weight of <span class=\"s1\">1 - xFraction</span>, such that the resulting values in the target spatial map are then given by <span class=\"s1\">x * xFraction + target * (1 - xFraction)</span>.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">xFraction</span> must be in [0.0, 1.0].</p>\n<p class=\"p6\">One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, <span class=\"s1\">x</span> is blended with each grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each value of <span class=\"s1\">x</span> is blended with the corresponding grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of <span class=\"s1\">x</span> is blended with the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (void)changeColors([Nif valueRange = NULL], [Ns colors = NULL])</p>\n<p class=\"p6\">Changes the color scheme for the target spatial map.<span class=\"Apple-converted-space\">  </span>The meaning of <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> are identical to their meaning in <span class=\"s1\">defineSpatialMap()</span>, but are also described here.</p>\n<p class=\"p6\">The <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> parameters travel together; either both are <span class=\"s1\">NULL</span>, or both are specified.<span class=\"Apple-converted-space\">  </span>They control how map values will be transformed into colors, by SLiMgui and by the <span class=\"s1\">mapColor()</span> method.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">valueRange</span> parameter establishes the color-mapped range of spatial map values, as a vector of length two specifying a minimum and maximum; this does not need to match the actual range of values in the map.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">colors</span> parameter then establishes the corresponding colors for values within the interval defined by <span class=\"s1\">valueRange</span>: values less than or equal to <span class=\"s1\">valueRange[0]</span> will map to <span class=\"s1\">colors[0]</span>, values greater than or equal to <span class=\"s1\">valueRange[1]</span> will map to the last <span class=\"s1\">colors</span> value, and intermediate values will shade continuously through the specified vector of colors, with interpolation between adjacent colors to produce a continuous spectrum.<span class=\"Apple-converted-space\">  </span>This is much simpler than it sounds in this description; see the recipes for an illustration of its use.</p>\n<p class=\"p6\">If <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> are both <span class=\"s1\">NULL</span>, a default grayscale color scheme will be used in SLiMgui, but an error will result if <span class=\"s1\">mapColor()</span> is called.</p>\n<p class=\"p5\">– (void)changeValues(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Changes the grid values used for the target spatial map.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">x</span> should be either a <span class=\"s1\">SpatialMap</span> object from which values are taken directly, or a vector, matrix, or array of numeric values as described in the documentation for <span class=\"s1\">defineSpatialMap()</span>.<span class=\"Apple-converted-space\">  </span>Other characteristics of the spatial map, such as its color mapping (if defined), its spatial bounds, and its spatiality, will remain unchanged.<span class=\"Apple-converted-space\">  </span>The grid resolution of the spatial map is allowed to change with this method.<span class=\"Apple-converted-space\">  </span>This method is useful for changing the values of a spatial map over time, such as to implement changes to the landscape’s characteristics due to seasonality, climate change, processes such as fire or urbanization, and so forth.<span class=\"Apple-converted-space\">  </span>As with the original map values provided to <span class=\"s1\">defineSpatialMap()</span>, it is often useful to read map values from a PNG image file using the Eidos class <span class=\"s1\">Image</span>.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)divide(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Divides the spatial map by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, each grid value of the target spatial map is divided by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each grid value of the target spatial map is divided by the corresponding value of <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is divided by the corresponding grid value of <span class=\"s1\">x</span> (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)exp(void)</p>\n<p class=\"p6\">Exponentiates the values of the spatial map.<span class=\"Apple-converted-space\">  </span>More precisely, each grid value <i>x</i> of the target spatial map is exponentiated – replaced by the value <i>e</i><span class=\"s18\"><i><sup>x</sup></i></span>.<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (float)gridValues(void)</p>\n<p class=\"p6\">Returns the values for the spatial map’s grid as a vector (for a 1D map), a matrix (for a 2D map), or an array (for a 3D map).<span class=\"Apple-converted-space\">  </span>The form and orientation of the returned values is such that it could be used to create a new spatial map, with <span class=\"s1\">defineSpatialMap()</span>, which would be identical to the original.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)interpolate(integer$ factor, [string$ method = \"linear\"])</p>\n<p class=\"p6\">Increases the resolution of the spatial map by <span class=\"s1\">factor</span>, changing the dimensions of the spatial map’s grid of values (while leaving its spatial bounds unchanged), by interpolating new values between the existing values.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">factor</span> must be an integer in [<span class=\"s1\">2</span>, <span class=\"s1\">10001</span>], somewhat arbitrarily.<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p6\">For a 1D spatial map, <span class=\"s1\">factor-1</span> new values will be inserted between every pair of values in the original value grid.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">factor</span> of <span class=\"s1\">2</span> would therefore insert one new value between each pair of existing values, thereby increasing the map’s resolution by a factor of two.<span class=\"Apple-converted-space\">  </span>Note that if the spatial map’s original grid dimension was <i>N</i>, the new grid dimension with a <span class=\"s1\">factor</span> of <i>k</i> would be <i>k</i>(<i>N</i>−1)+1, not <i>kN</i>, because new values are inserted only <i>between</i> existing values.<span class=\"Apple-converted-space\">  </span>For 2D and 3D spatial maps, essentially the same process is conducted along each axis of the map’s spatiality, increasing the resolution of the map by <span class=\"s1\">factor</span> in every dimension.</p>\n<p class=\"p6\">If <span class=\"s1\">method</span> is <span class=\"s1\">\"linear\"</span> (the default), linear (or bilinear or trilinear, for 2D/3D maps) interpolation will be used to interpolate the values for the new grid points.<span class=\"Apple-converted-space\">  </span>Alternatively, if <span class=\"s1\">method</span> is <span class=\"s1\">\"nearest\"</span>, the nearest value in the old grid will be used for new grid points; with this method, it is recommended that <span class=\"s1\">factor</span> be odd, not even, to avoid artifacts due to rounding of coordinates midway between the original grid positions.<span class=\"Apple-converted-space\">  </span>If method is <span class=\"s1\">\"cubic\"</span>, cubic (or bicubic, for 2D maps) will be used; this generally produces smoother interpolation with fewer artifacts than <span class=\"s1\">\"linear\"</span>, but it is not supported for 3D maps.<span class=\"Apple-converted-space\">  </span>The choice of interpolation method used here is independent of the map’s <span class=\"s1\">interpolate</span> property.<span class=\"Apple-converted-space\">  </span>Note that while the <span class=\"s1\">\"nearest\"</span> and <span class=\"s1\">\"linear\"</span> interpolation methods will leave the range of values in the map unchanged, <span class=\"s1\">\"cubic\"</span> interpolation may produce interpolated values that are outside the original range of values (by design).<span class=\"Apple-converted-space\">  </span>Periodic boundaries are currently supported only for <span class=\"s1\">\"nearest\"</span>, <span class=\"s1\">\"linear\"</span>, and 1D <span class=\"s1\">\"cubic\"</span> interpolation.</p>\n<p class=\"p5\">– (string)mapColor(numeric value)</p>\n<p class=\"p6\">Uses the spatial map’s color-translation machinery (as defined by the <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> parameters to <span class=\"s1\">defineSpatialMap()</span>) to translate each element of <span class=\"s1\">value</span> into a corresponding color string.<span class=\"Apple-converted-space\">  </span>If the spatial map does not have color-translation capabilities, an error will result.<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s1\">defineSpatialMap()</span> for information regarding the details of color translation.<span class=\"Apple-converted-space\">  </span>See the Eidos manual for further information on color strings.</p>\n<p class=\"p5\">– (object&lt;Image&gt;$)mapImage([Ni$ width = NULL], [Ni$ height = NULL], [logical$ centers = F], [logical$ color = T])</p>\n<p class=\"p6\">Returns an <span class=\"s1\">Image</span> object sampled from the spatial map.<span class=\"Apple-converted-space\">  </span>The image will be <span class=\"s1\">width</span> pixels wide and <span class=\"s1\">height</span> pixels tall; the intrinsic size of the spatial map itself will be used if one of these parameters is <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>The image will be oriented in the same way as it is displayed in SLiMgui (which conceptually entails a transformation from matrix coordinates, which store values by column, to standard image coordinates, which store values by row; see the Eidos manual’s documentation of <span class=\"s1\">Image</span> for details).<span class=\"Apple-converted-space\">  </span>This method may only be called for 2D spatial maps at present.</p>\n<p class=\"p6\">The sampling of the spatial map can be done in one of two ways, as controlled by the <span class=\"s1\">centers</span> parameter.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">centers</span> is <span class=\"s1\">T</span>, a (<span class=\"s1\">width+1</span>) × (<span class=\"s1\">height+1</span>) grid of lines that delineates <span class=\"s1\">width</span> × <span class=\"s1\">height</span> rectangular pixels will be overlaid on top of the spatial map, and values will be sampled from the spatial map at the <i>center</i> of each of these pixels.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">centers</span> is <span class=\"s1\">F</span> (the default), a <span class=\"s1\">width</span> × <span class=\"s1\">height</span> grid of lines will be overlaid on top of the spatial map, and values will be sampled from the spatial map at the <i>vertices</i> of the grid.<span class=\"Apple-converted-space\">  </span>If interpolation is not enabled for the spatial map, these two options will both recover the original matrix of values used to define the spatial map (assuming, here and below, that <span class=\"s1\">width</span> and <span class=\"s1\">height</span> are <span class=\"s1\">NULL</span>).<span class=\"Apple-converted-space\">  </span>If interpolation is enabled for the spatial map, however, <span class=\"s1\">centers == F</span> will recover the original values, but will not capture the “typical” value of each pixel in the image; <span class=\"s1\">centers == T</span>, on the other hand, will not recover the original values, but will capture the “typical” value of each pixel in the image (i.e., the value at the center of each pixel, as produced by interpolation).</p>\n<p class=\"p6\">If <span class=\"s1\">color</span> is <span class=\"s1\">T</span> (the default), the <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> parameters supplied to <span class=\"s1\">defineSpatialMap()</span> will be used to translate map values to RGB color values as described in the documentation of that method, providing the same appearance as in SLiMgui; of course those parameters must have been supplied, otherwise an error will result.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">color</span> is <span class=\"s1\">F</span>, on the other hand, a grayscale image will be produced that directly reflects the map values without color translation.<span class=\"Apple-converted-space\">  </span>In this case, this method needs to translate map values, which can have any <span class=\"s1\">float</span> value, into grayscale pixel values that are integers in [<span class=\"s1\">0</span>, <span class=\"s1\">255</span>].<span class=\"Apple-converted-space\">  </span>To do so, the map values are multiplied by <span class=\"s1\">255.0</span>, clamped to [<span class=\"s1\">0.0</span>, <span class=\"s1\">255.0</span>], and then rounded to the nearest integer.<span class=\"Apple-converted-space\">  </span>This translation scheme essentially assumes that map values are in [0, 1]; for spatial maps that were defined using the <span class=\"s1\">floatK</span> channel of a grayscale PNG image, this should recover the original image’s pixel values.<span class=\"Apple-converted-space\">  </span>(If a different translation scheme is desired, <span class=\"s1\">color=T</span> with the desired <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> should be used.)</p>\n<p class=\"p5\">– (float)mapValue(float point)</p>\n<p class=\"p6\">Uses the spatial map’s mapping machinery (as defined by the <span class=\"s1\">gridSize</span>, <span class=\"s1\">values</span>, and <span class=\"s1\">interpolate</span> parameters to <span class=\"s1\">defineSpatialMap()</span>) to translate the coordinates of <span class=\"s1\">point</span> into a corresponding map value.<span class=\"Apple-converted-space\">  </span>The length of <span class=\"s1\">point</span> must be equal to the spatiality of the spatial map; in other words, for a spatial map with spatiality <span class=\"s1\">\"xz\"</span>, <span class=\"s1\">point</span> must be of length <span class=\"s1\">2</span>, specifying the <i>x</i> and <i>z</i> coordinates of the point to be evaluated.<span class=\"Apple-converted-space\">  </span>Interpolation will automatically be used if it was enabled for the spatial map.<span class=\"Apple-converted-space\">  </span>Point coordinates are clamped into the range defined by the spatial boundaries, even if the spatial boundaries are periodic; use <span class=\"s1\">pointPeriodic()</span> to wrap the point coordinates first if desired.<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s1\">defineSpatialMap()</span> for information regarding the details of value mapping.</p>\n<p class=\"p6\">The <span class=\"s1\">point</span> parameter may also contain more than one point to be looked up.<span class=\"Apple-converted-space\">  </span>In this case, the length of <span class=\"s1\">point</span> must be an exact multiple of the spatiality of the spatial map; for a spatial map with spatiality <span class=\"s1\">\"xz\"</span>, for example, the length of <span class=\"s1\">point</span> must be an exact multiple of <span class=\"s1\">2</span>, and successive pairs of elements from point (elements <span class=\"s1\">0</span> and <span class=\"s1\">1</span>, then elements <span class=\"s1\">2</span> and <span class=\"s1\">3</span>, etc.) will be taken as the <i>x</i> and <i>z</i> coordinates of the points to be evaluated.<span class=\"Apple-converted-space\">  </span>This allows <span class=\"s1\">mapValue()</span> to be used in a vectorized fashion.</p>\n<p class=\"p6\">The <span class=\"s1\">spatialMapValue()</span> method of <span class=\"s1\">Subpopulation</span> provides essentially the same functionality as this method; it may be more convenient to use, for some usage cases, and it checks that the spatial map is actually added to the subpopulation in question, providing an additional consistency check.<span class=\"Apple-converted-space\">  </span>However, either method may be used.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)multiply(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Multiplies the spatial map by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, each grid value of the target spatial map is multiplied by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each grid value of the target spatial map is multiplied by the corresponding value of <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is multiplied by the corresponding grid value of <span class=\"s1\">x</span> (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)power(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Raises the spatial map to the power <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, each grid value of the target spatial map is raised to the power <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each grid value of the target spatial map is raised to the power of the corresponding value of <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is raised to power of the corresponding grid value of <span class=\"s1\">x</span> (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (float)range(void)</p>\n<p class=\"p6\">Returns the range of values contained in the spatial map.<span class=\"Apple-converted-space\">  </span>The result is a <span class=\"s1\">float</span> vector of length <span class=\"s1\">2</span>; the first element is the minimum map value, and the second element is the maximum map value.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)rescale([numeric$ min = 0.0], [numeric$ max = 1.0])</p>\n<p class=\"p6\">Rescales the values of the spatial map to the range [<span class=\"s1\">min</span>, <span class=\"s1\">max</span>].<span class=\"Apple-converted-space\">  </span>By default, the rescaling is to the range [<span class=\"s1\">0.0</span>, <span class=\"s1\">1.0</span>].<span class=\"Apple-converted-space\">  </span>It is required that <span class=\"s1\">min</span> be less than <span class=\"s1\">max</span>, and that both be finite.<span class=\"Apple-converted-space\">  </span>Note that the final range may not be exactly [<span class=\"s1\">min</span>, <span class=\"s1\">max</span>] due to numerical error.<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p5\">– (float)sampleImprovedNearbyPoint(float point, float$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">This variant of <span class=\"s1\">sampleNearbyPoint()</span> samples a Metropolis–Hastings move on the spatial map.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">sampleNearbyPoint()</span> for discussion of the basic idea.<span class=\"Apple-converted-space\">  </span>This method proposes a nearby point drawn from the given kernel.<span class=\"Apple-converted-space\">  </span>If the drawn point has a larger map value than the original point, the new point is returned.<span class=\"Apple-converted-space\">  </span>If the drawn point has a smaller map value than the original point, it is returned with a probability equal to the ratio between its map value and the original map value, otherwise the original point is returned.<span class=\"Apple-converted-space\">  </span>The distribution of points that move (or not) to new locations governed by this method will converge upon the map itself, in a similar manner to how MCMC converges upon the posterior distribution (assuming no other forces, such as birth or death, influence the distribution of individuals).<span class=\"Apple-converted-space\">  </span>Movement governed by this method is “improved” in the sense that points will tend to remain where they are unless the new sampled point is an improvement for them – a higher map value.<span class=\"Apple-converted-space\">  </span>Note that unlike <span class=\"s1\">sampleNearbyPoint()</span>, this method requires that all map values are non-negative.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">point</span> may contain any number of points; the returned vector will contain corresponding points sampled as described above.<span class=\"Apple-converted-space\">  </span>Each supplied point must provide coordinates precisely as specified by the spatiality of the target map; for example, if the target map’s spatiality is <span class=\"s1\">\"xz\"</span> (in an <span class=\"s1\">\"xyz\"</span> species), each point must contain two elements, providing the <i>x</i> and <i>z</i> coordinate.<span class=\"Apple-converted-space\">  </span>Be careful; this means that in general it is not safe to pass an individual’s <span class=\"s1\">spatialPosition</span> property for <span class=\"s1\">point</span>, for example (although it is safe if the spatiality of the map matches the dimensionality of the simulation); other properties on <span class=\"s1\">Individual</span> exist for getting the individual’s coordinates in a particular spatiality, such as the <span class=\"s1\">xz</span> property for this example.<span class=\"Apple-converted-space\">  </span>Supplied points are not required to be within bounds, but since nearby points are sampled from the given kernel and must be within bounds, an infinite loop might result if a supplied point is substantially outside bounds.</p>\n<p class=\"p6\">The kernel is specified with a kernel type, <span class=\"s1\">functionType</span>, followed by zero or more ellipsis arguments; see <span class=\"s1\">smooth()</span> for further information.<span class=\"Apple-converted-space\">  </span>For this method, at present only kernel types <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"l\"</span>, <span class=\"s1\">\"e\"</span>, <span class=\"s1\">\"n\"</span>, and <span class=\"s1\">\"t\"</span> are supported, and type <span class=\"s1\">\"t\"</span> is not presently supported for 3D kernels.<span class=\"Apple-converted-space\">  </span>The parameters that define the kernel’s shape – the ellipsis arguments that follow <span class=\"s1\">functionType</span> – may each, independently, be either a singleton or a vector with length equal to the number of points, providing a separate value for each point being processed.<span class=\"Apple-converted-space\">  </span>In this way, all of the nearby points can be drawn from the same kernel, or each from a separately defined kernel.<span class=\"Apple-converted-space\">  </span>Since <span class=\"s1\">maxDistance</span> and <span class=\"s1\">functionType</span> are required to be singletons, however, their values cannot vary from point to point in the present design.</p>\n<p class=\"p6\">See also the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">deviatePositionsWithMap()</span>, which is conceptually similar to this method.</p>\n<p class=\"p5\">– (float)sampleNearbyPoint(float point, float$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">For a spatial point supplied in <span class=\"s1\">point</span>, returns a nearby point sampled from a kernel weighted by the spatial map’s values.<span class=\"Apple-converted-space\">  </span>Only points within the maximum distance of the kernel, <span class=\"s1\">maxDistance</span>, will be chosen, and the probability that a given point is chosen will be proportional to the density of the kernel at that point multiplied by the value of the map at that point (interpolated, if interpolation is enabled for the map).<span class=\"Apple-converted-space\">  </span>Negative values of the map will be treated as zero.<span class=\"Apple-converted-space\">  </span>The point returned will be within spatial bounds, respecting periodic boundaries if in effect (so there is no need to call <span class=\"s1\">pointPeriodic()</span> on the result).</p>\n<p class=\"p6\">The parameter <span class=\"s1\">point</span> may contain any number of points; the returned vector will contain corresponding points sampled as described above.<span class=\"Apple-converted-space\">  </span>Each supplied point must provide coordinates precisely as specified by the spatiality of the target map; for example, if the target map’s spatiality is <span class=\"s1\">\"xz\"</span> (in an <span class=\"s1\">\"xyz\"</span> species), each point must contain two elements, providing the <i>x</i> and <i>z</i> coordinate.<span class=\"Apple-converted-space\">  </span>Be careful; this means that in general it is not safe to pass an individual’s <span class=\"s1\">spatialPosition</span> property for <span class=\"s1\">point</span>, for example (although it is safe if the spatiality of the map matches the dimensionality of the simulation); other properties on <span class=\"s1\">Individual</span> exist for getting the individual’s coordinates in a particular spatiality, such as the <span class=\"s1\">xz</span> property for this example.<span class=\"Apple-converted-space\">  </span>Supplied points are not required to be within bounds, but since nearby points are sampled from the given kernel and must be within bounds, an infinite loop might result if a supplied point is substantially outside bounds.</p>\n<p class=\"p6\">The kernel is specified with a kernel type, <span class=\"s1\">functionType</span>, followed by zero or more ellipsis arguments; see <span class=\"s1\">smooth()</span> for further information.<span class=\"Apple-converted-space\">  </span>For this method, at present only kernel types <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"l\"</span>, <span class=\"s1\">\"e\"</span>, <span class=\"s1\">\"n\"</span>, and <span class=\"s1\">\"t\"</span> are supported, and type <span class=\"s1\">\"t\"</span> is not presently supported for 3D kernels.<span class=\"Apple-converted-space\">  </span>The parameters that define the kernel’s shape – the ellipsis arguments that follow <span class=\"s1\">functionType</span> – may each, independently, be either a singleton or a vector with length equal to the number of points, providing a separate value for each point being processed.<span class=\"Apple-converted-space\">  </span>In this way, all of the nearby points can be drawn from the same kernel, or each from a separately defined kernel.<span class=\"Apple-converted-space\">  </span>Since <span class=\"s1\">maxDistance</span> and <span class=\"s1\">functionType</span> are required to be singletons, however, their values cannot vary from point to point in the present design.</p>\n<p class=\"p6\">This method can be used to find points in the vicinity of individuals that are favorable – possessing more resources, or better environmental conditions, etc.<span class=\"Apple-converted-space\">  </span>It can also be used to guide the dispersal or foraging behavior of individuals.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">sampleImprovedNearbyPoint()</span> for a variant that may be useful for directed movement across a landscape.<span class=\"Apple-converted-space\">  </span>Note that the algorithm for <span class=\"s1\">sampleNearbyPoint()</span> works by rejection sampling, and so will be very inefficient if the maximum value of the map (anywhere, across the entire map) is much larger than the typical value of the map where individuals are.<span class=\"Apple-converted-space\">  </span>The algorithm for <span class=\"s1\">sampleImprovedNearbyPoint()</span> is different, and does not exhibit this performance issue.</p>\n<p class=\"p6\">See also the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">deviatePositionsWithMap()</span>, which is conceptually similar to this method.</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)smooth(float$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">Smooths (or blurs, one could say) the values of the spatial map by convolution with a kernel.<span class=\"Apple-converted-space\">  </span>The kernel is specified with a maximum distance <span class=\"s1\">maxDistance</span> (beyond which the kernel cuts off to a value of zero), a kernel type <span class=\"s1\">functionType</span> that should be <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"l\"</span>, <span class=\"s1\">\"e\"</span>, <span class=\"s1\">\"n\"</span>, <span class=\"s1\">\"c\"</span>, or <span class=\"s1\">\"t\"</span>, and additional parameters in the ellipsis <span class=\"s1\">...</span> that depend upon the kernel type and further specify its shape.<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p6\">The kernel specification is similar to that for the <span class=\"s1\">setInteractionType()</span> method of <span class=\"s1\">InteractionType</span>, but omits the maximum value of the kernel.<span class=\"Apple-converted-space\">  </span>Specifically, <span class=\"s1\">functionType</span> may be <span class=\"s1\">\"f\"</span>, in which case no ellipsis arguments should be supplied; <span class=\"s1\">\"l\"</span>, similarly with no ellipsis arguments; <span class=\"s1\">\"e\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> lambda (rate) parameter for a negative exponential function; <span class=\"s1\">\"n\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> sigma (standard deviation) parameter for a Gaussian function; <span class=\"s1\">\"c\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> scale parameter for a Cauchy distribution function; or <span class=\"s1\">\"t\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> degrees of freedom and a <span class=\"s1\">numeric$</span> scale parameter for a <i>t</i>-distribution function.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">InteractionType</span> class documentation for discussions of these kernel types.</p>\n<p class=\"p6\">Distance metrics specified to this method, such as <span class=\"s1\">maxDistance</span> and the additional kernel shape parameters, are measured in the distance scale of the spatial map – the same distance scale in which the spatial bounds of the map are specified.<span class=\"Apple-converted-space\">  </span>The operation is performed upon the grid values of the spatial map; distances are internally translated into the scale of the value grid.<span class=\"Apple-converted-space\">  </span>For non-periodic boundaries, clipping at the edge of the spatial map is done; in a 2D map with no periodic boundaries, for example, the weights of edge and corner grid values are adjusted for their partial (one-half and one-quarter) coverage.<span class=\"Apple-converted-space\">  </span>For periodic boundaries, the smoothing operation will automatically wrap around based upon the assumption that the grid values at the two connected edges of the periodic boundary have identical values (which they should, since by definition they represent the same position in space).</p>\n<p class=\"p6\">The density scale of the kernel has no effect and will be normalized; this is the reason that <span class=\"s1\">smooth()</span>, unlike <span class=\"s1\">InteractionType</span>, does not require specification of the maximum value of the kernel.<span class=\"Apple-converted-space\">  </span>This normalization prevents the kernel from increasing or decreasing the average spatial map value (apart from possible edge effects).</p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)subtract(ifo&lt;SpatialMap&gt; x)</p>\n<p class=\"p6\">Subtracts <span class=\"s1\">x</span> from the spatial map.<span class=\"Apple-converted-space\">  </span>One possibility is that <span class=\"s1\">x</span> is a singleton <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> value; in this case, <span class=\"s1\">x</span> is subtracted from each grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>Another possibility is that <span class=\"s1\">x</span> is an <span class=\"s1\">integer</span> or <span class=\"s1\">float</span> vector/matrix/array of the same dimensions as the target spatial map’s grid; in this case, each value of <span class=\"s1\">x</span> is subtracted from the corresponding grid value of the target spatial map.<span class=\"Apple-converted-space\">  </span>The third possibility is that <span class=\"s1\">x</span> is itself a (singleton) spatial map; in this case, each grid value of <span class=\"s1\">x</span> is subtracted from the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).<span class=\"Apple-converted-space\">  </span>The target spatial map is returned, to allow easy chaining of operations.</p>\n<p class=\"p1\"><b>5.16<span class=\"Apple-converted-space\">  </span>Class Species</b></p>\n<p class=\"p2\"><i>5.16.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Species</i></span><i> properties</i></p>\n<p class=\"p5\">avatar =&gt; (string$)</p>\n<p class=\"p6\">The avatar string used to represent this species in SLiMgui.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Avatars are typically one-character strings, often using an emoji that symbolizes the species.<span class=\"Apple-converted-space\">  </span>This property is read-only; its value should be set with the <span class=\"s1\">avatar</span> parameter of <span class=\"s1\">initializeSpecies()</span>.</p>\n<p class=\"p5\">chromosome =&gt; (object&lt;Chromosome&gt;$)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> object used by the species.<span class=\"Apple-converted-space\">  </span>This property may only be accessed in a single-chromosome model; if there are multiple chromosomes (or none), the <span class=\"s1\">chromosomes</span> property must be used instead.</p>\n<p class=\"p5\">chromosomes =&gt; (object&lt;Chromosome&gt;)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> objects used by the species, in the order in which they were defined.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">sexChromosomes</span> property.</p>\n<p class=\"p5\">color =&gt; (string$)</p>\n<p class=\"p6\">The color used to display information about this species in SLiMgui.<span class=\"Apple-converted-space\">  </span>Outside of SLiMgui, this property still exists, but is not used by SLiM.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s1\">\"#RRGGBB\"</span> (see the Eidos manual).<span class=\"Apple-converted-space\">  </span>This property is read-only; its value should be set with the <span class=\"s1\">color</span> parameter of <span class=\"s1\">initializeSpecies()</span>.</p>\n<p class=\"p5\">cycle &lt;–&gt; (integer$)</p>\n<p class=\"p6\">The current cycle count for this species.<span class=\"Apple-converted-space\">  </span>This counter begins at 1, and increments at the end of every tick in which the species is active.<span class=\"Apple-converted-space\">  </span>In models with non-overlapping generations, particularly WF models, this can be thought of as a generation counter.</p>\n<p class=\"p5\">description &lt;–&gt; (string$)</p>\n<p class=\"p6\">A human-readable <span class=\"s1\">string</span> description for the species.<span class=\"Apple-converted-space\">  </span>By default, this is the empty string, <span class=\"s1\">\"\"</span>; however, it may be set to whatever you wish.</p>\n<p class=\"p3\">dimensionality =&gt; (string$)</p>\n<p class=\"p4\">The spatial dimensionality of the simulation for this species, as specified in <span class=\"s1\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>This will be <span class=\"s1\">\"\"</span> (the empty string) for non-spatial simulations (the default), or <span class=\"s1\">\"x\"</span>, <span class=\"s1\">\"xy\"</span>, or <span class=\"s1\">\"xyz\"</span>, for simulations using those spatial dimensions respectively.</p>\n<p class=\"p3\">genomicElementTypes =&gt; (object&lt;GenomicElementType&gt;)</p>\n<p class=\"p6\"><span class=\"s5\">The </span><span class=\"s6\">GenomicElementType</span><span class=\"s5\"> objects being used in the species.</span><span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p5\">id =&gt; (integer$)</p>\n<p class=\"p6\">The identifier for this species.<span class=\"Apple-converted-space\">  </span>Species identifiers are determined by their declaration order in the script; the first declared species is given an <span class=\"s1\">id</span> of <span class=\"s1\">0</span>, the second is given an <span class=\"s1\">id</span> of <span class=\"s1\">1</span>, and so forth.</p>\n<p class=\"p3\">mutationTypes =&gt; (object&lt;MutationType&gt;)</p>\n<p class=\"p6\"><span class=\"s5\">The </span><span class=\"s6\">MutationType</span><span class=\"s5\"> objects being used in the species.</span><span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p3\">mutations =&gt; (object&lt;Mutation&gt;)</p>\n<p class=\"p4\">The <span class=\"s1\">Mutation</span> objects that are currently active in the species.</p>\n<p class=\"p5\">name =&gt; (string$)</p>\n<p class=\"p6\">A human-readable <span class=\"s1\">string</span> name for the subpopulation.<span class=\"Apple-converted-space\">  </span>This is always the declared name of the species, as given in the explicit species declaration in script, and cannot be changed.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">name</span> of a species may appear as a label in SLiMgui, and it can be useful in generating output, debugging, and other purposes.<span class=\"Apple-converted-space\">  </span>See also the description property, which can be changed by the user and used for any purpose.</p>\n<p class=\"p5\"><span class=\"s3\">nucleotideBased =&gt; (logical$)</span></p>\n<p class=\"p6\"><span class=\"s3\">If </span><span class=\"s4\">T</span><span class=\"s3\">, the model for this species is nucleotide-based; if </span><span class=\"s4\">F</span><span class=\"s3\">, it is not.<span class=\"Apple-converted-space\">  </span>See the discussion of the </span><span class=\"s4\">nucleotideBased</span><span class=\"s3\"> parameter to </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\"> for discussion.</span></p>\n<p class=\"p3\">periodicity =&gt; (string$)</p>\n<p class=\"p6\"><span class=\"s3\">The spatial periodicity of the simulation for this species, as specified in </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This will be </span><span class=\"s4\">\"\"</span><span class=\"s3\"> (the empty string) for non-spatial simulations and simulations with no periodic spatial dimensions (the default).<span class=\"Apple-converted-space\">  </span>Otherwise, it will be a string representing the subset of spatial dimensions that have been declared to be periodic, as specified to </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span></p>\n<p class=\"p3\">scriptBlocks =&gt; (object&lt;SLiMEidosBlock&gt;)</p>\n<p class=\"p6\">All registered <span class=\"s1\">SLiMEidosBlock</span> objects in the simulation that have been declared with this species as their <span class=\"s1\">species</span> specifier (<i>not</i> <span class=\"s1\">ticks</span> specifier).<span class=\"Apple-converted-space\">  </span>These will always be callback blocks; callbacks are species-specific, while other types of blocks are not.</p>\n<p class=\"p5\">sexChromosomes =&gt; (object&lt;Chromosome&gt;)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> objects used by the species that represent sex chromosomes, in the order in which they were defined.<span class=\"Apple-converted-space\">  </span>Sex chromosomes are specifically those of type <span class=\"s1\">\"X\"</span>, <span class=\"s1\">\"Y\"</span>, <span class=\"s1\">\"W\"</span>, <span class=\"s1\">\"Z\"</span>, and <span class=\"s1\">\"-Y\"</span>.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">chromosomes</span> property, and the <span class=\"s1\">isSexChromosome</span> property of <span class=\"s1\">Chromosome</span>.</p>\n<p class=\"p3\">sexEnabled =&gt; (logical$)</p>\n<p class=\"p4\">If <span class=\"s1\">T</span>, sex is enabled for this species; if <span class=\"s1\">F</span>, individuals are hermaphroditic.</p>\n<p class=\"p3\">subpopulations =&gt; (object&lt;Subpopulation&gt;)</p>\n<p class=\"p6\"><span class=\"s5\">The </span><span class=\"s6\">Subpopulation</span><span class=\"s5\"> instances currently defined in the species.</span><span class=\"Apple-converted-space\">  </span>These are guaranteed to be in sorted order, by their <span class=\"s1\">id</span> property.</p>\n<p class=\"p3\">substitutions =&gt; (object&lt;Substitution&gt;)</p>\n<p class=\"p4\">A vector of <span class=\"s1\">Substitution</span> objects, representing all mutations that have been fixed in this species.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to the simulation.</p>\n<p class=\"p2\"><i>5.16.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Species</i></span><i> methods</i></p>\n<p class=\"p5\">– (object&lt;Dictionary&gt;$)addPatternForClone(iso&lt;Chromosome&gt;$ chromosome, No&lt;Dictionary&gt;$ pattern, object&lt;Individual&gt;$ parent, [Ns$ sex = NULL])</p>\n<p class=\"p6\">Adds an inheritance dictionary for the specified chromosome to the pattern dictionary <span class=\"s1\">pattern</span>, representing producing a clone of <span class=\"s1\">parent</span>, with sex optionally specified by <span class=\"s1\">sex</span>.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">chromosome</span> can provide a chromosome <span class=\"s1\">id</span> (an <span class=\"s1\">integer</span>), a chromosome <span class=\"s1\">symbol</span> (a <span class=\"s1\">string</span>), or a <span class=\"s1\">Chromosome</span> object.<span class=\"Apple-converted-space\">  </span>The resulting pattern dictionary is intended for use with the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">addMultiRecombinant()</span>; see that method for background on the use of pattern dictionaries.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">pattern</span> must be a <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>), or <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, a new singleton object of class <span class=\"s1\">Dictionary</span> will be created, set up, and returned; otherwise, the returned object is the same object passed in as <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>The inheritance dictionary generated by <span class=\"s1\">addPatternForClone()</span> will be added to <span class=\"s1\">pattern</span> as the value for a particular key.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is already configured to use <span class=\"s1\">string</span> keys, the key used will be the <span class=\"s1\">symbol</span> property of the chromosome; otherwise, including if <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, the key used will be the <span class=\"s1\">id</span> property of the chromosome.<span class=\"Apple-converted-space\">  </span>If the key in question already exists in <span class=\"s1\">pattern</span>, its value will be replaced.</p>\n<p class=\"p6\">The precise inheritance pattern generated by this method depends upon the chromosome’s type; see <span class=\"s1\">initializeChromosome()</span> for a description of the different chromosome types and the ways in which they are inherited.<span class=\"Apple-converted-space\">  </span>The pattern will be the same as would be used by the <span class=\"s1\">addCloned()</span> method for the chromosome.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">sex</span> is <span class=\"s1\">NULL</span>, the sex of the offspring is assumed to be the same as the parent; in non-sexual models, <span class=\"s1\">NULL</span> must be passed.<span class=\"Apple-converted-space\">  </span>If the sex of the offspring will be different from the parent, <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> should be passed; if changing the sex from parent to offspring presents any genetic problems (if the chromosome is a sex chromosome, for example), an error will be raised, but if the chromosome does not depend upon sex, the change of sex will be allowed.<span class=\"Apple-converted-space\">  </span>Note that the generated inheritance dictionary does not encode the offspring sex; the <span class=\"s1\">sex</span> parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.<span class=\"Apple-converted-space\">  </span>The final pattern dictionary passed to <span class=\"s1\">addMultiRecombinant()</span> will be validated against the <span class=\"s1\">sex</span> parameter given to that method.</p>\n<p class=\"p6\">It is typically not necessary to call <span class=\"s1\">addPatternForClone()</span>, since <span class=\"s1\">addMultiRecombinant()</span> will usually automatically infer the correct inheritance pattern from its parental individual <span class=\"s1\">parent1</span> if an inheritance dictionary for the chromosome is not supplied in <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>This method is needed primarily for edge cases, such as if <span class=\"s1\">addMultiRecombinant()</span> is being used to generate a biparental cross, but a particular chromosome should be cloned from just one of the parents in a manner that the biparental cross would not do automatically.</p>\n<p class=\"p5\">– (object&lt;Dictionary&gt;$)addPatternForCross(iso&lt;Chromosome&gt;$ chromosome, No&lt;Dictionary&gt;$ pattern, object&lt;Individual&gt;$ parent1, object&lt;Individual&gt;$ parent2, [Ns$ sex = NULL])</p>\n<p class=\"p6\">Adds an inheritance dictionary for the specified chromosome to the pattern dictionary <span class=\"s1\">pattern</span>, representing a biparental cross between <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> to generate an offspring, with sex optionally specified by <span class=\"s1\">sex</span>.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">chromosome</span> can provide a chromosome <span class=\"s1\">id</span> (an <span class=\"s1\">integer</span>), a chromosome <span class=\"s1\">symbol</span> (a <span class=\"s1\">string</span>), or a <span class=\"s1\">Chromosome</span> object.<span class=\"Apple-converted-space\">  </span>The resulting pattern dictionary is intended for use with the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">addMultiRecombinant()</span>; see that method for background on the use of pattern dictionaries.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">pattern</span> must be a <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>), or <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, a new singleton object of class <span class=\"s1\">Dictionary</span> will be created, set up, and returned; otherwise, the returned object is the same object passed in as <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>The inheritance dictionary generated by <span class=\"s1\">addPatternForCross()</span> will be added to <span class=\"s1\">pattern</span> as the value for a particular key.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is already configured to use <span class=\"s1\">string</span> keys, the key used will be the <span class=\"s1\">symbol</span> property of the chromosome; otherwise, including if <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, the key used will be the <span class=\"s1\">id</span> property of the chromosome.<span class=\"Apple-converted-space\">  </span>If the key in question already exists in <span class=\"s1\">pattern</span>, its value will be replaced.</p>\n<p class=\"p6\">The precise inheritance pattern generated by this method depends upon the chromosome’s type; see <span class=\"s1\">initializeChromosome()</span> for a description of the different chromosome types and the ways in which they are inherited.<span class=\"Apple-converted-space\">  </span>The pattern will be the same as would be used by the <span class=\"s1\">addCrossed()</span> method for the chromosome.<span class=\"Apple-converted-space\">  </span>In some cases, the value of <span class=\"s1\">sex</span> is unimportant and may be left as <span class=\"s1\">NULL</span>; a <span class=\"s1\">NULL</span> value for <span class=\"s1\">sex</span> essentially asserts that the sex of the offspring is unimportant to the inheritance pattern for the chromosome with the given parents.<span class=\"Apple-converted-space\">  </span>If that assertion is untrue – if the sex needs to be known, for example to know how a sex chromosome should be inherited – an error will be raised.<span class=\"Apple-converted-space\">  </span>When the sex needs to be known, <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> must be passed so that the correct inheritance pattern can be generated.<span class=\"Apple-converted-space\">  </span>In non-sexual models, <span class=\"s1\">NULL</span> must be passed.<span class=\"Apple-converted-space\">  </span>Note that the generated inheritance dictionary does not encode the offspring sex; the <span class=\"s1\">sex</span> parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.<span class=\"Apple-converted-space\">  </span>The final pattern dictionary passed to <span class=\"s1\">addMultiRecombinant()</span> will be validated against the <span class=\"s1\">sex</span> parameter given to that method.</p>\n<p class=\"p6\">It is typically not necessary to call <span class=\"s1\">addPatternForCross()</span>, since <span class=\"s1\">addMultiRecombinant()</span> will usually automatically infer the correct inheritance pattern from its parental individuals <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> if an inheritance dictionary for the chromosome is not supplied in <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>This method is needed primarily for edge cases, such as if <span class=\"s1\">addMultiRecombinant()</span> is being used to generate a clonal offspring, but a particular chromosome should be produced with recombination.</p>\n<p class=\"p5\">– (object&lt;Dictionary&gt;$)addPatternForNull(iso&lt;Chromosome&gt;$ chromosome, No&lt;Dictionary&gt;$ pattern, [Ns$ sex = NULL])</p>\n<p class=\"p6\">Adds an inheritance dictionary for the specified chromosome to the pattern dictionary <span class=\"s1\">pattern</span>, representing a non-inheritance event producing null haplosomes, with sex optionally specified by <span class=\"s1\">sex</span>.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">chromosome</span> can provide a chromosome <span class=\"s1\">id</span> (an <span class=\"s1\">integer</span>), a chromosome <span class=\"s1\">symbol</span> (a <span class=\"s1\">string</span>), or a <span class=\"s1\">Chromosome</span> object.<span class=\"Apple-converted-space\">  </span>The resulting pattern dictionary is intended for use with the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">addMultiRecombinant()</span>; see that method for background on the use of pattern dictionaries.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">pattern</span> must be a <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>), or <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, a new singleton object of class <span class=\"s1\">Dictionary</span> will be created, set up, and returned; otherwise, the returned object is the same object passed in as <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>The inheritance dictionary generated by <span class=\"s1\">addPatternForNull()</span> will be added to <span class=\"s1\">pattern</span> as the value for a particular key.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is already configured to use <span class=\"s1\">string</span> keys, the key used will be the <span class=\"s1\">symbol</span> property of the chromosome; otherwise, including if <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, the key used will be the <span class=\"s1\">id</span> property of the chromosome.<span class=\"Apple-converted-space\">  </span>If the key in question already exists in <span class=\"s1\">pattern</span>, its value will be replaced.</p>\n<p class=\"p6\">For all chromosome types, this method will simply produce a null haplosome or haplosomes for the specified chromosome.<span class=\"Apple-converted-space\">  </span>If the chromosome does not allow a null haplosome, an error will be raised.<span class=\"Apple-converted-space\">  </span>In some cases, the value of <span class=\"s1\">sex</span> is unimportant and may be left as <span class=\"s1\">NULL</span>; a <span class=\"s1\">NULL</span> value for <span class=\"s1\">sex</span> essentially asserts that the chromosome allows null haplosomes for any sex.<span class=\"Apple-converted-space\">  </span>If that assertion is untrue – if the sex needs to be known, for example to know whether a null haplosome is allowed for a sex chromosome – an error will be raised.<span class=\"Apple-converted-space\">  </span>When the sex needs to be known, <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> must be passed so that <span class=\"s1\">addPatternForNull()</span> is satisfied that a legal pattern for the chromosome will be generated.<span class=\"Apple-converted-space\">  </span>In non-sexual models, <span class=\"s1\">NULL</span> must be passed.<span class=\"Apple-converted-space\">  </span>Note that the generated inheritance dictionary does not encode the offspring sex; the <span class=\"s1\">sex</span> parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.<span class=\"Apple-converted-space\">  </span>The final pattern dictionary passed to <span class=\"s1\">addMultiRecombinant()</span> will be validated against the <span class=\"s1\">sex</span> parameter given to that method.</p>\n<p class=\"p6\">If only one of the two haplosomes for a diploid chromosome should be a null haplosome, and <span class=\"s1\">addPatternForCrossed()</span> and <span class=\"s1\">addPatternForCloned()</span> would not produce the desired pattern, use <span class=\"s1\">addPatternForRecombinant()</span>, which provides complete control.</p>\n<p class=\"p5\">– (object&lt;Dictionary&gt;$)addPatternForRecombinant(iso&lt;Chromosome&gt;$ chromosome, No&lt;Dictionary&gt;$ pattern, No&lt;Haplosome&gt;$ strand1, No&lt;Haplosome&gt;$ strand2, Ni breaks1, No&lt;Haplosome&gt;$ strand3, No&lt;Haplosome&gt;$ strand4, Ni breaks2, [Ns$ sex = NULL], [logical$ randomizeStrands = T])</p>\n<p class=\"p6\">Adds an inheritance dictionary for the specified chromosome to the pattern dictionary <span class=\"s1\">pattern</span>, representing inheritance by cloning, recombination, or both, to generate an offspring from up to four parental haplosomes, with sex optionally specified by <span class=\"s1\">sex</span>.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">chromosome</span> can provide a chromosome <span class=\"s1\">id</span> (an <span class=\"s1\">integer</span>), a chromosome <span class=\"s1\">symbol</span> (a <span class=\"s1\">string</span>), or a <span class=\"s1\">Chromosome</span> object.<span class=\"Apple-converted-space\">  </span>The resulting pattern dictionary is intended for use with the <span class=\"s1\">Subpopulation</span> method <span class=\"s1\">addMultiRecombinant()</span>; see that method for background on the use of pattern dictionaries.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">pattern</span> must be a <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>), or <span class=\"s1\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, a new singleton object of class <span class=\"s1\">Dictionary</span> will be created, set up, and returned; otherwise, the returned object is the same object passed in as <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>The inheritance dictionary generated by <span class=\"s1\">addPatternForRecombinant()</span> will be added to <span class=\"s1\">pattern</span> as the value for a particular key.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">pattern</span> is already configured to use <span class=\"s1\">string</span> keys, the key used will be the <span class=\"s1\">symbol</span> property of the chromosome; otherwise, including if <span class=\"s1\">pattern</span> is <span class=\"s1\">NULL</span>, the key used will be the <span class=\"s1\">id</span> property of the chromosome.<span class=\"Apple-converted-space\">  </span>If the key in question already exists in <span class=\"s1\">pattern</span>, its value will be replaced.</p>\n<p class=\"p6\">When passed the resulting pattern dictionary, the <span class=\"s1\">addMultiRecombinant()</span> method will produce the first offspring haplosome using the <span class=\"s1\">Haplosome</span> objects <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> with the vector of recombination breakpoints <span class=\"s1\">breaks1</span>, and likewise will produce the second offspring haplosome using <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, and <span class=\"s1\">breaks2</span>.<span class=\"Apple-converted-space\">  </span>If both parental strands for an offspring haplosome are <span class=\"s1\">NULL</span>, the breaks vector must be <span class=\"s1\">NULL</span> or empty, and a null haplosome will be produced.<span class=\"Apple-converted-space\">  </span>If the first parental strand is non-<span class=\"s1\">NULL</span> and the second is <span class=\"s1\">NULL</span> for an offspring haplosome, the breaks vector must again be <span class=\"s1\">NULL</span> or empty, and the first strand will be cloned with mutation.<span class=\"Apple-converted-space\">  </span>If both parental strands for an offspring haplosome are non-<span class=\"s1\">NULL</span>, recombination between the strands will be done using the supplied breaks vector; in this case, if the breaks vector is <span class=\"s1\">NULL</span> then <span class=\"s1\">addMultiRecombinant()</span> will automatically generate breakpoints for the recombination.<span class=\"Apple-converted-space\">  </span>All of these semantics are discussed further in the documentation for <span class=\"s1\">addMultiRecombinant()</span>; this method is just a helper for that method.<span class=\"Apple-converted-space\">  </span>The documentation for <span class=\"s1\">addRecombinant()</span> may also be helpful for understanding the concepts here, since it is the conceptual foundation upon which the very complex architecture of the <span class=\"s1\">addMultiRecombinant()</span> method is built.</p>\n<p class=\"p6\">Unlike <span class=\"s1\">addPatternForClone()</span> and <span class=\"s1\">addPatternForCrossed()</span>, which must infer the inheritance pattern given the chromosome type and the offspring sex, <span class=\"s1\">addPatternForRecombinant()</span> is given the inheritance pattern, and must simply confirm that it is valid.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">sex</span> is <span class=\"s1\">NULL</span> (the default), this validation only needs to check that the inheritance pattern is possible, for some sex.<span class=\"Apple-converted-space\">  </span>For example, if the chromosome type is <span class=\"s1\">\"X\"</span> then the inheritance pattern must produce a non-null first haplosome, and the second haplosome can be null (for a male, X–) or non-null (for a female, XX); other inheritance patterns would fail validation.<span class=\"Apple-converted-space\">  </span>When the sex is known, <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> may optionally be passed to validate against that sex; X– would then fail validation if a female is specified, for example.<span class=\"Apple-converted-space\">  </span>In non-sexual models, <span class=\"s1\">NULL</span> must be passed.<span class=\"Apple-converted-space\">  </span>Note that the generated inheritance dictionary does not encode the offspring sex; the <span class=\"s1\">sex</span> parameter is simply used for validation.<span class=\"Apple-converted-space\">  </span>The final pattern dictionary passed to <span class=\"s1\">addMultiRecombinant()</span> will be validated against the <span class=\"s1\">sex</span> parameter given to that method.</p>\n<p class=\"p6\">The <span class=\"s1\">randomizeStrands</span> parameter indicates whether or not the order of recombining parental strands should be randomized in the inheritance dictionary.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">T</span>, then if <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> are both non-<span class=\"s1\">NULL</span>, their order will be randomized; and similarly for <span class=\"s1\">strand3</span> and <span class=\"s1\">strand4</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">F</span>, no randomization will be done in the inheritance dictionary – but strand order randomization may still be done by <span class=\"s1\">addMultiRecombinant()</span> if <span class=\"s1\">T</span> is passed for its own <span class=\"s1\">randomizeStrands</span> parameter.<span class=\"Apple-converted-space\">  </span>Randomizing the strand order is usually desirable, to avoid an inheritance bias due to a lack of randomization in the initial copy strand.<span class=\"Apple-converted-space\">  </span>Whether you wish to randomize strand order in <span class=\"s1\">addPatternForRecombinant()</span> or in <span class=\"s1\">addMultiRecombinant()</span> is up to you; it is harmless to do it in both places, apart from a small performance penalty, but there is no benefit.</p>\n<p class=\"p6\">Of the family of <span class=\"s1\">addPatternFor...()</span> methods, <span class=\"s1\">addPatternForRecombinant()</span> is the most commonly used.<span class=\"Apple-converted-space\">  </span>Typically, <span class=\"s1\">addMultiRecombinant()</span> can automatically infer the correct inheritance pattern for crossing or cloning (as described in its documentation), but for more complex inheritance patterns, using <span class=\"s1\">addPatternForRecombinant()</span> is necessary (unless you want to build the pattern dictionary yourself).</p>\n<p class=\"p3\">– (object&lt;Subpopulation&gt;$)addSubpop(is$ subpopID, integer$ size, [float$ sexRatio = 0.5]<span class=\"s5\">, [logical$ haploid = F]</span>)</p>\n<p class=\"p6\">Add a new subpopulation with id <span class=\"s1\">subpopID</span> and <span class=\"s1\">size</span> individuals.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpopID</span> parameter may be either an <span class=\"s1\">integer</span> giving the ID of the new subpopulation, or a <span class=\"s1\">string</span> giving the name of the new subpopulation (such as <span class=\"s1\">\"p5\"</span> to specify an ID of 5).<span class=\"Apple-converted-space\">  </span>Only if sex is enabled for the species, the initial sex ratio may optionally be specified as <span class=\"s1\">sexRatio</span> (as the male fraction, M:M+F); if it is not specified, a default of <span class=\"s1\">0.5</span> is used.<span class=\"Apple-converted-space\">  </span>The new subpopulation will be defined as a global variable immediately by this method, and will also be returned by this method.<span class=\"Apple-converted-space\">  </span>Subpopulations added by this method will initially consist of individuals with empty haplosomes.<span class=\"Apple-converted-space\">  </span>In order to model subpopulations that split from an already existing subpopulation, use <span class=\"s1\">addSubpopSplit()</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">haploid</span> parameter defaults to <span class=\"s1\">F</span>, indicating that the generated individuals should adopt their natural ploidy; in particular, type <span class=\"s1\">\"A\"</span> chromosomes should be represented in each individual by two empty haplosomes.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">haploid</span> parameter may instead be <span class=\"s1\">T</span>; in this case, for all chromosomes of type <span class=\"s1\">\"A\"</span> (and only that type), the second haplosome of each new individual will be a null haplosome, rather than an empty haplosome.<span class=\"Apple-converted-space\">  </span>This could be useful in a model of haplodiploidy, for example, to generate initial individuals that are haploid for the autosomal chromosomes of the species.<span class=\"Apple-converted-space\">  </span>For even greater control in nonWF models, you can call <span class=\"s1\">addSubpop()</span> with an initial size of <span class=\"s1\">0</span> and then stock the population with new individuals created however you wish in the next tick’s <span class=\"s1\">reproduction()</span> callback, such as with the <span class=\"s1\">addEmpty()</span> method, providing separate control over the configuration of each individual.</p>\n<p class=\"p3\">– (object&lt;Subpopulation&gt;$)addSubpopSplit(is$ subpopID, integer$ size, io&lt;Subpopulation&gt;$ sourceSubpop, [float$ sexRatio = 0.5])</p>\n<p class=\"p6\">Split off a new subpopulation with id <span class=\"s1\">subpopID</span> and <span class=\"s1\">size</span> individuals derived from subpopulation <span class=\"s1\">sourceSubpop</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpopID</span> parameter may be either an <span class=\"s1\">integer</span> giving the ID of the new subpopulation, or a <span class=\"s1\">string</span> giving the name of the new subpopulation (such as <span class=\"s1\">\"p5\"</span> to specify an ID of 5).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">sourceSubpop</span> parameter may specify the source subpopulation either as a <span class=\"s1\">Subpopulation</span> object or by <span class=\"s1\">integer</span> identifier.<span class=\"Apple-converted-space\">  </span>Only if sex is enabled for the species, the initial sex ratio may optionally be specified as <span class=\"s1\">sexRatio</span> (as the male fraction, M:M+F); if it is not specified, a default of <span class=\"s1\">0.5</span> is used.<span class=\"Apple-converted-space\">  </span>The new subpopulation will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p6\">Subpopulations added by this method will consist of individuals that are clonal copies of individuals from the source subpopulation, randomly chosen with probabilities proportional to fitness.<span class=\"Apple-converted-space\">  </span>The fitness of all of these initial individuals is considered to be 1.0, to avoid a doubled round of selection in the initial tick, given that fitness values were already used to choose the individuals to clone.<span class=\"Apple-converted-space\">  </span>Once this initial set of individuals has mated to produce offspring, the model is effectively of parental individuals in the source subpopulation mating randomly according to fitness, as usual in SLiM, with juveniles migrating to the newly added subpopulation.<span class=\"Apple-converted-space\">  </span>Effectively, then, then new subpopulation is created empty, and is filled by migrating juveniles from the source subpopulation, in accordance with SLiM’s usual model of juvenile migration.</p>\n<p class=\"p5\">– (object&lt;Chromosome&gt;)chromosomesOfType(string$ type)</p>\n<p class=\"p6\">Returns a vector of <span class=\"s1\">Chromosome</span> objects of the chromosome type supplied in <span class=\"s1\">type</span>, in the order if which they were defined.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">type</span> does not correspond to a chromosome type accepted by <span class=\"s1\">initializeChromosome()</span>, an error will be raised.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">chromosomesWithIDs()</span> and <span class=\"s1\">chromosomesWithSymbols()</span>.</p>\n<p class=\"p5\">– (object&lt;Chromosome&gt;)chromosomesWithIDs(integer ids)</p>\n<p class=\"p6\">Returns a vector of <span class=\"s1\">Chromosome</span> objects corresponding to the chromosome ids supplied in <span class=\"s1\">ids</span>, in the same order.<span class=\"Apple-converted-space\">  </span>If any chromosome id in <span class=\"s1\">ids</span> does not correspond to a chromosome in the target species, an error will be raised.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">chromosomesOfType()</span> and <span class=\"s1\">chromosomesWithSymbols()</span>.</p>\n<p class=\"p5\">– (object&lt;Chromosome&gt;)chromosomesWithSymbols(string symbols)</p>\n<p class=\"p6\">Returns a vector of <span class=\"s1\">Chromosome</span> objects corresponding to the chromosome symbols supplied in <span class=\"s1\">symbols</span>, in the same order.<span class=\"Apple-converted-space\">  </span>If any chromosome symbol in <span class=\"s1\">symbols</span> does not correspond to a chromosome in the target species, an error will be raised.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">chromosomesOfType()</span> and <span class=\"s1\">chromosomesWithIDs()</span>.</p>\n<p class=\"p3\"><span class=\"s5\">– </span>(integer$)countOfMutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns the number of mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations that are currently active in the species.<span class=\"Apple-converted-space\">  </span>If you need a vector of the matching <span class=\"s1\">Mutation</span> objects, rather than just a count, use <span class=\"s1\">-mutationsOfType()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>This method is often used to determine whether an introduced mutation is still active (as opposed to being either lost or fixed).<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)individualsWithPedigreeIDs(integer pedigreeIDs, [Nio&lt;Subpopulation&gt; subpops = NULL])</p>\n<p class=\"p6\">Looks up individuals by pedigree ID, optionally within specific subpopulations.<span class=\"Apple-converted-space\">  </span>Pedigree tracking must be turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span> to use this method, otherwise an error will result.<span class=\"Apple-converted-space\">  </span>This method is vectorized; more than one pedigree id may be passed in <span class=\"s1\">pedigreeID</span>, in which case the returned vector will contain all of the individuals for which a match was found (in the same order in which they were supplied).<span class=\"Apple-converted-space\">  </span>If a given id is not found, the returned vector will contain no entry for that id (so the length of the returned vector may not match the length of <span class=\"s1\">pedigreeIDs</span>).<span class=\"Apple-converted-space\">  </span>If none of the given ids were found, the returned vector will be <span class=\"s1\">object&lt;Individual&gt;(0)</span>, an empty <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>.<span class=\"Apple-converted-space\">  </span>If you have more than one pedigree ID to look up, calling this method just once, in vectorized fashion, may be much faster than calling it once for each ID, due to internal optimizations.</p>\n<p class=\"p6\">To find individuals within all subpopulations, pass the default of <span class=\"s1\">NULL</span> for <span class=\"s1\">subpops</span>.<span class=\"Apple-converted-space\">  </span>If you are interested only in matches within a specific subpopulation, pass that subpopulation for <span class=\"s1\">subpops</span>; that will make the search faster.<span class=\"Apple-converted-space\">  </span>Similarly, if you know that a particular subpopulation is the most likely to contain matches, you should supply that subpopulation first in the <span class=\"s1\">subpops</span> vector so that it will be searched first; the supplied subpopulations are searched in order.<span class=\"Apple-converted-space\">  </span>Subpopulations may be supplied either as <span class=\"s1\">integer</span> IDs, or as <span class=\"s1\">Subpopulation</span> objects.</p>\n<p class=\"p5\">– (void)killIndividuals(object&lt;Individual&gt; individuals)</p>\n<p class=\"p6\">Immediately kills the individuals in <span class=\"s1\">individuals</span>.<span class=\"Apple-converted-space\">  </span>This removes them from their subpopulation and gives them an <span class=\"s1\">index</span> value of <span class=\"s1\">-1</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">Individual</span> objects are not freed immediately, since references to them could still exist in local Eidos variables; instead, the individuals are kept in a temporary “graveyard” until they can be freed safely.<span class=\"Apple-converted-space\">  </span>It therefore continues to be safe to use them and their haplosomes, except that accessing their <span class=\"s1\">subpopulation</span> property will raise an error since they no longer have a subpopulation.</p>\n<p class=\"p6\">Note that the indices and order of individuals and haplosomes in all source subpopulations will change unpredictably as a side effect of this method.<span class=\"Apple-converted-space\">  </span>All evaluated interactions are invalidated as a side effect of calling this method.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models, in which mortality is managed manually by the model script.<span class=\"Apple-converted-space\">  </span>In WF models, mortality is managed automatically by the SLiM core when the new offspring generation becomes the parental generation and the previous parental generation dies; mortality does not otherwise occur in WF models.<span class=\"Apple-converted-space\">  </span>In nonWF models, mortality normally occurs during the survival stage of the tick cycle, based upon the fitness values calculated by SLiM, and <span class=\"s1\">survival()</span> callbacks can influence the outcome of that survival stage.<span class=\"Apple-converted-space\">  </span>Calls to <span class=\"s1\">killIndividuals()</span>, on the other hand, can be made at any time during <span class=\"s1\">first()</span>, <span class=\"s1\">early()</span>, or <span class=\"s1\">late()</span> events, and the result cannot be modified by <span class=\"s1\">survival()</span> callbacks; the given individuals are simply immediately killed.<span class=\"Apple-converted-space\">  </span>This method therefore provides an alternative, and relatively rarely used, mortality mechanism that is disconnected from fitness.</p>\n<p class=\"p3\">– (integer)mutationCounts(Nio&lt;Subpopulation&gt; subpops, [No&lt;Mutation&gt; mutations = NULL])</p>\n<p class=\"p4\">Return an <span class=\"s1\">integer</span> vector with the frequency counts of all of the <span class=\"s1\">Mutation</span> objects passed in <span class=\"s1\">mutations</span>, within the <span class=\"s1\">Subpopulation</span> objects in <span class=\"s1\">subpops</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpops</span> argument is required, but you may pass <span class=\"s1\">NULL</span> to get population-wide frequency counts.<span class=\"s5\"><span class=\"Apple-converted-space\">  </span>Subpopulations may be supplied either as </span><span class=\"s6\">integer</span><span class=\"s5\"> IDs, or as </span><span class=\"s6\">Subpopulation</span><span class=\"s5\"> objects.</span><span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">mutations</span> argument is <span class=\"s1\">NULL</span> (the default), frequency counts will be returned for all of the active <span class=\"s1\">Mutation</span> objects in the species – the same <span class=\"s1\">Mutation</span> objects, and in the same order, as would be returned by the <span class=\"s1\">mutations</span> property of <span class=\"s1\">sim</span>, in other words.</p>\n<p class=\"p16\"><span class=\"s11\">See the </span>-mutationFrequencies()<span class=\"s11\"> method to obtain </span>float<span class=\"s11\"> frequencies instead of </span>integer<span class=\"s11\"> counts.</span><span class=\"s19\"><span class=\"Apple-converted-space\">  </span>See also the </span>Haplosome<span class=\"s19\"> methods </span><span class=\"s5\">mutationCountsIn</span>Haplosome<span class=\"s5\">s()</span><span class=\"s19\"> and </span><span class=\"s5\">mutationFrequenciesIn</span>Haplosome<span class=\"s5\">s()</span><span class=\"s19\">.</span></p>\n<p class=\"p3\">– (float)mutationFrequencies(Nio&lt;Subpopulation&gt; subpops, [No&lt;Mutation&gt; mutations = NULL])</p>\n<p class=\"p4\">Return a <span class=\"s1\">float</span> vector with the frequencies of all of the <span class=\"s1\">Mutation</span> objects passed in <span class=\"s1\">mutations</span>, within the <span class=\"s1\">Subpopulation</span> objects in <span class=\"s1\">subpops</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpops</span> argument is required, but you may pass <span class=\"s1\">NULL</span> to get population-wide frequencies.<span class=\"s5\"><span class=\"Apple-converted-space\">  </span>Subpopulations may be supplied either as </span><span class=\"s6\">integer</span><span class=\"s5\"> IDs, or as </span><span class=\"s6\">Subpopulation</span><span class=\"s5\"> objects.</span><span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s1\">mutations</span> argument is <span class=\"s1\">NULL</span> (the default), frequencies will be returned for all of the active <span class=\"s1\">Mutation</span> objects in the species – the same <span class=\"s1\">Mutation</span> objects, and in the same order, as would be returned by the <span class=\"s1\">mutations</span> property of <span class=\"s1\">sim</span>, in other words.</p>\n<p class=\"p16\"><span class=\"s11\">See the </span>-mutationCounts()<span class=\"s11\"> method to obtain </span>integer<span class=\"s11\"> counts instead of </span>float<span class=\"s11\"> frequencies.</span><span class=\"s19\"><span class=\"Apple-converted-space\">  </span>See also the </span>Haplosome<span class=\"s19\"> methods </span><span class=\"s5\">mutationCountsIn</span>Haplosome<span class=\"s5\">s()</span><span class=\"s19\"> and </span><span class=\"s5\">mutationFrequenciesIn</span>Haplosome<span class=\"s5\">s()</span><span class=\"s19\">.</span></p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(object&lt;Mutation&gt;)mutationsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p4\">Returns an <span class=\"s1\">object</span> vector of all the mutations that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the mutations that are currently active in the species.<span class=\"Apple-converted-space\">  </span>If you just need a count of the matching <span class=\"s1\">Mutation</span> objects, rather than a vector of the matches, use <span class=\"s1\">-countOfMutationsOfType()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>This method is often used to look up an introduced mutation at a later point in the simulation, since there is no way to keep persistent references to objects in SLiM.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.</p>\n<p class=\"p3\">– (void)outputFixedMutations([Ns$ filePath = NULL], [logical$ append = F]<span class=\"s5\">, [logical$ objectTags = F]</span>)</p>\n<p class=\"p4\">Output all fixed mutations – all <span class=\"s1\">Substitution</span> objects, in other words – in a SLiM native format.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>Mutations which have fixed but have not been turned into <span class=\"s1\">Substitution</span> objects – typically because <span class=\"s1\">convertToSubstitution</span> has been set to <span class=\"s1\">F</span> for their mutation type – are not output; they are still considered to be segregating mutations by SLiM.</p>\n<p class=\"p6\"><span class=\"s3\">In SLiM 3.3 and later, the output format includes the nucleotides associated with any nucleotide-based mutations.</span></p>\n<p class=\"p6\">In SLiM 5.0 and later, in models with multiple chromosome the output includes the symbol of the chromosome associated with each mutation.</p>\n<p class=\"p6\">Beginning with SLiM 5.0, the <span class=\"s1\">objectTags</span> parameter may be used to request that tag values for substitutions be written out.</p>\n<p class=\"p4\">Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\"><span class=\"s5\">– (void)outputFull([Ns$ filePath = NULL], [logical$ binary = F], [logical$ append = F], [logical$ spatialPositions = T]</span><span class=\"s3\">, [logical$ ages = T], [logical$ ancestralNucleotides = T]</span>, [logical$ pedigreeIDs = F], [logical$ objectTags = F], [logical$ substitutions = F]<span class=\"s5\">)</span></p>\n<p class=\"p4\">Output the state of the entire population.<span class=\"Apple-converted-space\">  </span>If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>When writing to a file, a <span class=\"s1\">logical</span> flag, <span class=\"s1\">binary</span>, may be supplied as well.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">binary</span> is <span class=\"s1\">T</span>, the population state will be written as a binary file instead of a text file (binary data cannot be written to the standard output stream).<span class=\"Apple-converted-space\">  </span>The binary file is usually smaller, and in any case will be read much faster than the corresponding text file would be read.<span class=\"Apple-converted-space\">  </span>Binary files are not guaranteed to be portable between platforms; in other words, a binary file written on one machine may not be readable on a different machine (but in practice it usually will be, unless the platforms being used are fairly unusual).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">binary</span> is <span class=\"s1\">F</span> (the default), a text file will be written.</p>\n<p class=\"p4\">Beginning with SLiM 2.3, the <span class=\"s1\">spatialPositions</span> parameter may be used to control the output of the spatial positions of individuals in species for which continuous space has been enabled using the <span class=\"s1\">dimensionality</span> option of <span class=\"s1\">initializeSLiMOptions()</span><span class=\"s2\">.</span><span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">spatialPositions</span> is <span class=\"s1\">F</span>, the output will not contain spatial positions, and will be identical to the output generated by SLiM 2.1 and later.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">spatialPositions</span> is <span class=\"s1\">T</span>, spatial position information will be output if it is available.<span class=\"Apple-converted-space\">  </span>If the species does not have continuous space enabled, the <span class=\"s1\">spatialPositions</span> parameter will be ignored.<span class=\"Apple-converted-space\">  </span>Positional information may be output for all output destinations – the Eidos output stream, a text file, or a binary file.</p>\n<p class=\"p6\"><span class=\"s3\">Beginning with SLiM 3.0, the </span><span class=\"s4\">ages</span><span class=\"s3\"> parameter may be used to control the output of the ages of individuals in nonWF simulations.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">ages</span><span class=\"s3\"> is </span><span class=\"s4\">F</span><span class=\"s3\">, the output will not contain ages, preserving backward compatibility with the output format of SLiM 2.1 and later.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">ages</span><span class=\"s3\"> is </span><span class=\"s4\">T</span><span class=\"s3\">, ages will be output for nonWF models.<span class=\"Apple-converted-space\">  </span>In WF simulations, the </span><span class=\"s4\">ages</span><span class=\"s3\"> parameter will be ignored.</span></p>\n<p class=\"p6\"><span class=\"s3\">Beginning with SLiM 3.3, the </span><span class=\"s4\">ancestralNucleotides</span><span class=\"s3\"> parameter may be used to control the output of the ancestral nucleotide sequence in nucleotide-based models.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">ancestralNucleotides</span><span class=\"s3\"> is </span><span class=\"s4\">F</span><span class=\"s3\">, the output will not contain ancestral nucleotide information, and so the ancestral sequence will not be restored correctly if the saved file is loaded with </span><span class=\"s4\">readPopulationFile()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This option is provided because the ancestral sequence may be quite large, for models with a long chromosome (e.g., 1 GB if the chromosome is 10</span><span class=\"s20\"><sup>9</sup></span><span class=\"s3\"> bases long, when saved in text format, or 0.25 GB when saved in binary format).<span class=\"Apple-converted-space\">  </span>If the model is not nucleotide-based (as enabled with the </span><span class=\"s4\">nucleotideBased</span><span class=\"s3\"> parameter to </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">), the </span><span class=\"s4\">ancestralNucleotides</span><span class=\"s3\"> parameter will be ignored.<span class=\"Apple-converted-space\">  </span>Note that in nucleotide-based models the output format will <i>always</i> include the nucleotides associated with any nucleotide-based mutations; the </span><span class=\"s4\">ancestralNucleotides</span><span class=\"s3\"> flag governs only the ancestral sequence.</span></p>\n<p class=\"p6\">Beginning with SLiM 3.5, the <span class=\"s1\">pedigreeIDs</span> parameter may be used to request that pedigree IDs be written out (and read in by <span class=\"s1\">readFromPopulationFile()</span>, subsequently).<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity.<span class=\"Apple-converted-space\">  </span>This option may only be used if SLiM’s optional pedigree tracking has been enabled with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>.</p>\n<p class=\"p6\">Beginning with SLiM 5.0, the <span class=\"s1\">objectTags</span> parameter may be used to request that tag values for objects be written out.<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity; if it turned on (<span class=\"s1\">T</span>), the values of all tags for all objects of supported classes (<span class=\"s1\">Chromosome</span>, <span class=\"s1\">Subpopulation</span>, <span class=\"s1\">Individual</span>, <span class=\"s1\">Haplosome</span>, <span class=\"s1\">Mutation</span>, <span class=\"s1\">Substitution</span>) will be written.<span class=\"Apple-converted-space\">  </span>For individuals, the <span class=\"s1\">tag</span>, <span class=\"s1\">tagF</span>, <span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span> properties will be written; for chromosomes, subpopulations, haplosomes, and mutations, the <span class=\"s1\">tag</span> property will be written.<span class=\"Apple-converted-space\">  </span>The saved tag information can be read in by <span class=\"s1\">readFromPopulationFile()</span>, but only if the output is in binary format (<span class=\"s1\">binary=T</span>).<span class=\"Apple-converted-space\">  </span>Note that if there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with <span class=\"s1\">setValue()</span>, and so forth, you should persist that state in separate files using calls such as <span class=\"s1\">writeFile()</span>.</p>\n<p class=\"p6\">Beginning with SLiM 5.0, the <span class=\"s1\">substitutions</span> parameter may be used to request that information about <span class=\"s1\">Substitution</span> objects in the simulation be written out.<span class=\"Apple-converted-space\">  </span>This option is turned off (<span class=\"s1\">F</span>) by default, for brevity.<span class=\"Apple-converted-space\">  </span>The saved substitution information can be read in by <span class=\"s1\">readFromPopulationFile()</span>, but only if the output is in binary format (<span class=\"s1\">binary=T</span>).</p>\n<p class=\"p4\">Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p3\">– (void)outputMutations(object&lt;Mutation&gt; mutations, [Ns$ filePath = NULL], [logical$ append = F]<span class=\"s5\">, [logical$ objectTags = F]</span>)</p>\n<p class=\"p6\"><span class=\"s5\">Output all of the given mutations.<span class=\"Apple-converted-space\">  </span>This can be used to output all mutations of a given mutation type, for example.<span class=\"Apple-converted-space\">  </span></span><span class=\"s3\">If the optional parameter </span><span class=\"s4\">filePath</span><span class=\"s3\"> is </span><span class=\"s4\">NULL</span><span class=\"s3\"> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by </span><span class=\"s4\">filePath</span><span class=\"s3\">, overwriting that file if </span><span class=\"s4\">append</span><span class=\"s3\"> if </span><span class=\"s4\">F</span><span class=\"s3\">, or appending to the end of it if </span><span class=\"s4\">append</span><span class=\"s3\"> is </span><span class=\"s4\">T</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">In SLiM 3.3 and later, the output format includes the nucleotides associated with any nucleotide-based mutations.</span></p>\n<p class=\"p6\">In SLiM 5 and later, in models with multiple chromosome the output includes the symbol of the chromosome associated with each mutation.</p>\n<p class=\"p6\">Beginning with SLiM 5.0, the <span class=\"s1\">objectTags</span> parameter may be used to request that tag values for mutations be written out.</p>\n<p class=\"p4\">Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p3\">– (integer$)readFromPopulationFile(string$ filePath<span class=\"s5\">, [No&lt;Dictionary&gt;$ subpopMap = NULL]</span>)</p>\n<p class=\"p6\">Read from a population file, whether in text or binary format as previously specified to <span class=\"s1\">outputFull()</span>, and return the tick counter value represented by the file’s contents (i.e., the tick at which the file was generated).<span class=\"Apple-converted-space\">  </span>Although this is most commonly used to set up initial populations (often in an Eidos event set to run in tick <span class=\"s1\">1</span>, immediately after simulation initialization), it may be called in any <span class=\"s1\">early()</span> or <span class=\"s1\">late()</span> event; the current state of all populations in the target species will be wiped and replaced by the state in the file at <span class=\"s1\">filePath</span>.<span class=\"Apple-converted-space\">  </span>All Eidos variables that are of type <span class=\"s1\">object</span> and have element class <span class=\"s1\">Subpopulation</span>, <span class=\"s1\">Haplosome</span>, <span class=\"s1\">Mutation</span>, <span class=\"s1\">Individual</span>, or <span class=\"s1\">Substitution</span> will be removed as a side effect of this method if they contain any element that belongs to the target species, because those objects will no longer exist in the SLiM simulation; if you want to preserve any of that state, you should output it or save it to a file prior to this call.<span class=\"Apple-converted-space\">  </span>New symbols (<span class=\"s1\">p1</span>, <span class=\"s1\">p2</span>, etc.) will be defined to refer to the new <span class=\"s1\">Subpopulation</span> objects loaded from the file.<span class=\"Apple-converted-space\">  </span>Note that fitness values are not calculated as a side effect of this call (because the simulation will often need to evaluate interactions or modify other state prior to doing so).</p>\n<p class=\"p6\"><span class=\"s3\">In SLiM 2.3 and later when using the WF model, calling </span><span class=\"s4\">readFromPopulationFile()</span><span class=\"s3\"> from any context other than a </span><span class=\"s4\">late()</span><span class=\"s3\"> event causes a warning; calling from a </span><span class=\"s4\">late()</span><span class=\"s3\"> event is almost always correct in WF models, so that fitness values can be automatically recalculated by SLiM at the usual time in the tick cycle without the need to force their recalculation (see comments on </span><span class=\"s4\">recalculateFitness()</span><span class=\"s3\">).</span></p>\n<p class=\"p6\"><span class=\"s3\">In SLiM 3.0 when using the nonWF model, calling </span><span class=\"s4\">readFromPopulationFile()</span><span class=\"s3\"> from any context other than an </span><span class=\"s4\">early()</span><span class=\"s3\"> event causes a warning; calling from an </span><span class=\"s4\">early()</span><span class=\"s3\"> event is almost always correct in nonWF models, so that fitness values can be automatically recalculated by SLiM at the usual time in the tick cycle without the need to force their recalculation (see comments on </span><span class=\"s4\">recalculateFitness()</span><span class=\"s3\">).</span></p>\n<p class=\"p6\">This method changes the tick and cycle counters to the tick and cycle read from the file.<span class=\"Apple-converted-space\">  </span>If you do not want these counters to be changed, you can change them back after reading, by setting <span class=\"s1\">community.tick</span> and <span class=\"s1\">sim.cycle</span> to whatever values you wish.<span class=\"Apple-converted-space\">  </span>Note that restoring a saved past state and running forward again will not yield the same simulation results, because the random number generator’s state will not be the same; if you wish to ensure reproducibility from a given time point, <span class=\"s1\">setSeed()</span> can be used to establish a new seed value.</p>\n<p class=\"p6\">Any changes made to the structure of the species (mutation types, genomic element types, etc.) will not be wiped and re-established by <span class=\"s1\">readFromPopulationFile()</span>; this method loads only the population’s state, not the species configuration, so care should be taken to ensure that the species structure meshes coherently with the loaded data.<span class=\"Apple-converted-space\">  </span>Indeed, state such as the selfing and cloning rates of subpopulations, and values set onto objects with <span class=\"s1\">setValue()</span>, will also be lost, since it is not saved out by <span class=\"s1\">outputFull()</span>.<span class=\"Apple-converted-space\">  </span>Only information saved by <span class=\"s1\">outputFull()</span> will be restored; all other state associated with the mutations, haplosomes, individuals, and subpopulations in the simulation will be lost, and should be re-established by the model if it is still needed.<span class=\"Apple-converted-space\">  </span>Note that some state is saved by <span class=\"s1\">outputFull()</span> only optionally, such as the <span class=\"s1\">tag</span> values of individuals; if a given option is enabled and the corresponding information is saved, then that information will be restored, otherwise it will not be.</p>\n<p class=\"p6\">As of SLiM 2.3, this method will read and restore the spatial positions of individuals if that information is present in the output file and the species has enabled continuous space.<span class=\"Apple-converted-space\">  </span>If spatial positions are present in the output file but the species has not enabled continuous space (or the number of spatial dimensions does not match), an error will result.<span class=\"Apple-converted-space\">  </span>If the species has enabled continuous space but spatial positions are not present in the output file, the spatial positions of the individuals read will be undefined, but an error is not raised.</p>\n<p class=\"p6\"><span class=\"s3\">As of SLiM 3.0, this method will read and restore the ages of individuals if that information is present in the output file and the simulation is based upon the nonWF model.<span class=\"Apple-converted-space\">  </span>If ages are present but the simulation uses a WF model, an error will result; the WF model does not use age information.<span class=\"Apple-converted-space\">  </span>If ages are not present but the simulation uses a nonWF model, an error will also result; the nonWF model requires age information.</span></p>\n<p class=\"p6\"><span class=\"s3\">As of SLiM 3.3, this method will restore the nucleotides of nucleotide-based mutations, and will restore the ancestral nucleotide sequence, if that information is present in the output file.<span class=\"Apple-converted-space\">  </span>Loading an output file that contains nucleotide information in a non-nucleotide-based model, and <i>vice versa</i>, will produce an error.</span></p>\n<p class=\"p6\">As of SLiM 3.5, this method will read and restore the pedigree IDs of individuals and haplosomes if that information is present in the output file (as requested with <span class=\"s1\">outputFull(pedigreeIDs=T)</span>) <i>and</i> if SLiM’s optional pedigree tracking has been enabled with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>.</p>\n<p class=\"p6\">As of SLiM 5.0, this method will read and restore tag values for objects of supported classes (<span class=\"s1\">Chromosome</span>, <span class=\"s1\">Subpopulation</span>, <span class=\"s1\">Individual</span>, <span class=\"s1\">Haplosome</span>, <span class=\"s1\">Mutation</span>, <span class=\"s1\">Substitution</span>) if they were saved by <span class=\"s1\">outputFull()</span> with its <span class=\"s1\">objectTags=T</span> option.<span class=\"Apple-converted-space\">  </span>This facility is only available when reading binary output from <span class=\"s1\">outputFull()</span>, as chosen by its <span class=\"s1\">binary=T</span> option; otherwise, an error will result.</p>\n<p class=\"p6\">As of SLiM 5.0, this method will read and restore substitutions if they were saved by <span class=\"s1\">outputFull()</span> with its <span class=\"s1\">substitutions=T</span> option.<span class=\"Apple-converted-space\">  </span>This facility is only available when reading binary output from <span class=\"s1\">outputFull()</span>, as chosen by its <span class=\"s1\">binary=T</span> option; otherwise, an error will result.</p>\n<p class=\"p6\">This method can also be used to read tree-sequence information, in the form of single-chromosome <span class=\"s1\">.trees</span> files and multi-chromosome trees archives, as saved by <span class=\"s1\">treeSeqOutput()</span> or generated by the Python <span class=\"s1\">pyslim</span> package.<span class=\"Apple-converted-space\">  </span>Note that the user metadata for a tree-sequence file can be read separately with the <span class=\"s1\">treeSeqMetadata()</span> function.<span class=\"Apple-converted-space\">  </span>Beginning with SLiM 4, the <span class=\"s1\">subpopMap</span> parameter may be supplied to re-order the populations of the input tree sequence when it is loaded in to SLiM.<span class=\"Apple-converted-space\">  </span>This parameter must have a value that is a <span class=\"s1\">Dictionary</span>; the keys of this dictionary should be SLiM population identifiers as <span class=\"s1\">string</span> values (e.g., <span class=\"s1\">\"p2\"</span>), and the values should be indexes of populations in the input tree sequence; a key/value pair of <span class=\"s1\">\"p2\", 4</span> would mean that the fifth population in the input (the one at zero-based index <span class=\"s1\">4</span>) should become <span class=\"s1\">p2</span> on loading into SLiM.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">subpopMap</span> is non-<span class=\"s1\">NULL</span>, <i>all</i> populations in the tree sequence must be explicitly mapped, even if their index will not change and even if they will not be used by SLiM; the only exception is for unused slots in the population table, which can be explicitly remapped but do not have to be.<span class=\"Apple-converted-space\">  </span>For instance, suppose we have a tree sequence in which population <span class=\"s1\">0</span> is unused, population <span class=\"s1\">1</span> is not a SLiM population (for example, an ancestral population produced by <span class=\"s1\">msprime</span>), and population 2 is a SLiM population, and we want to load this in with population 2 as <span class=\"s1\">p0</span> in SLiM.<span class=\"Apple-converted-space\">  </span>To do this, we could supply a value of <span class=\"s1\">Dictionary(\"p0\", 2, \"p1\", 1, \"p2\", 0)</span> for <span class=\"s1\">subpopMap</span>, or we could leave out slot <span class=\"s1\">0</span> since it is unused, with <span class=\"s1\">Dictionary(\"p0\", 2, \"p1\", 1)</span>.<span class=\"Apple-converted-space\">  </span>Although this facility cannot be used to remove populations in the tree sequence, note that it may <i>add</i> populations that will be visible when <span class=\"s1\">treeSeqOutput()</span> is called (although these will not be SLiM populations); if, in this example, we had used <span class=\"s1\">Dictionary(\"p0\", 0, \"p1\", 1, \"p5\", 2)</span> and then we wrote the result out with <span class=\"s1\">treeSeqOutput()</span>, the resulting tree sequence would have six populations, although three of them would be empty and would not be used by SLiM.<span class=\"Apple-converted-space\">  </span>The use of <span class=\"s1\">subpopMap</span> makes it easier to load simulation data that was generated in Python, since that typically uses an id of <span class=\"s1\">0</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpopMap</span> parameter may not be used with file formats other than tree-sequence files, at the present time; setting up the correct subpopulation ids is typically easier when working with those other formats.<span class=\"Apple-converted-space\">  </span>Note the <span class=\"s1\">tskit</span> command-line interface can be used, like <span class=\"s1\">python3 -m tskit populations file.trees</span>, to find out the number of subpopulations in a tree-sequence file and their IDs.</p>\n<p class=\"p6\">When loading a tree sequence, a crosscheck of the loaded data will be performed to ensure that the tree sequence was well-formed and was loaded correctly.<span class=\"Apple-converted-space\">  </span>When running a Release build of SLiM, however, this crosscheck will only occur the first time that <span class=\"s1\">readFromPopulationFile()</span> is called to load a tree sequence; subsequent calls will not perform this crosscheck, for greater speed when running models that load saved population state many times (such as models that are conditional on fixation).<span class=\"Apple-converted-space\">  </span>If you suspect that a tree sequence file might be corrupted, or might be read incorrectly, running a Debug build of SLiM enables crosschecks after every load.</p>\n<p class=\"p3\">– (void)recalculateFitness([Ni$ tick = NULL])</p>\n<p class=\"p6\">Force an immediate recalculation of fitness values for all individuals in all subpopulations.<span class=\"Apple-converted-space\">  </span>Normally fitness values are calculated at a fixed point in each tick, and those values are cached and used until the next recalculation.<span class=\"Apple-converted-space\">  </span>If simulation parameters are changed in script in a way that affects fitness calculations, and if you wish those changes to take effect immediately rather than taking effect at the next automatic recalculation, you may call <span class=\"s1\">recalculateFitness()</span> to force an immediate recalculation and recache.</p>\n<p class=\"p6\">The optional parameter <span class=\"s1\">tick</span> provides the tick for which <span class=\"s1\">mutationEffect()</span> and <span class=\"s1\">fitnessEffect()</span> callbacks should be selected; if it is <span class=\"s1\">NULL</span> (the default), the current tick value for the simulation, <span class=\"s1\">community.tick</span>, is used.<span class=\"Apple-converted-space\">  </span>If you call <span class=\"s1\">recalculateFitness()</span> in an <span class=\"s1\">early()</span> event in a WF model, you may wish this to be <span class=\"s1\">community.tick - 1</span> in order to utilize the <span class=\"s1\">mutationEffect()</span> and <span class=\"s1\">fitnessEffect()</span> callbacks for the previous tick, as if the changes that you have made to fitness-influencing parameters were already in effect at the end of the previous tick when the new generation was first created and evaluated (usually it is simpler to just make such changes in a <span class=\"s1\">late()</span> event instead, however, in which case calling <span class=\"s1\">recalculateFitness()</span> is probably not necessary at all since fitness values will be recalculated immediately afterwards).<span class=\"Apple-converted-space\">  </span>Regardless of the value supplied for <span class=\"s1\">tick</span> here, <span class=\"s1\">community.tick</span> inside callbacks will report the true tick number, so if your callbacks consult that parameter in order to create tick-specific fitness effects you will need to handle the discrepancy somehow.<span class=\"Apple-converted-space\">  </span>(Similar considerations apply for nonWF models that call <span class=\"s1\">recalculateFitness()</span> in a <span class=\"s1\">late()</span> event, which is also not advisable in general.)</p>\n<p class=\"p6\">After this call, the fitness values used for all purposes in SLiM will be the newly calculated values.<span class=\"Apple-converted-space\">  </span>Calling this method will trigger the calling of any enabled and applicable <span class=\"s1\">mutationEffect()</span> and <span class=\"s1\">fitnessEffect()</span> callbacks, so this is quite a heavyweight operation; you should think carefully about what side effects might result (which is why fitness recalculation does not just occur automatically after changes that might affect fitness values).</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerFitnessEffectCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p6\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">fitnessEffect()</span> callback in the current simulation (specific to the target species), with an optional subpopulation <span class=\"s1\">subpop</span> (which may be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations), and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerMateChoiceCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">mateChoice()</span> callback in the current simulation<span class=\"s5\"> (specific to the target species)</span>, with optional subpopulation <span class=\"s1\">subpop</span> (which may be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations) and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerModifyChildCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">modifyChild()</span> callback in the current simulation<span class=\"s5\"> (specific to the target species)</span>, with optional subpopulation <span class=\"s1\">subpop</span> (which may be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations) and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p5\"><span class=\"s3\">– (object&lt;SLiMEidosBlock&gt;$)registerMutationCallback(Nis$ id, string$ source, [Nio&lt;MutationType&gt;$ mutType = NULL], [Nio&lt;Subpopulation&gt;$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</span></p>\n<p class=\"p6\"><span class=\"s3\">Register a block of Eidos source code, represented as the </span><span class=\"s4\">string</span><span class=\"s3\"> singleton </span><span class=\"s4\">source</span><span class=\"s3\">, as an Eidos </span><span class=\"s4\">mutation()</span><span class=\"s3\"> callback in the current simulation</span> (specific to the target species)<span class=\"s3\">, with an optional mutation type </span><span class=\"s4\">mutType</span><span class=\"s3\"> (which may be an </span><span class=\"s4\">integer</span><span class=\"s3\"> mutation type identifier, or </span><span class=\"s4\">NULL</span><span class=\"s3\">, the default, to indicate all mutation types), optional subpopulation </span><span class=\"s4\">subpop</span><span class=\"s3\"> (which may also be an </span><span class=\"s4\">integer</span><span class=\"s3\"> identifier, or </span><span class=\"s4\">NULL</span><span class=\"s3\">, the default, to indicate all subpopulations), and optional </span><span class=\"s4\">start</span><span class=\"s3\"> and </span><span class=\"s4\">end</span><span class=\"s3\"> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier </span><span class=\"s4\">id</span><span class=\"s3\"> (specified as an </span><span class=\"s4\">integer</span><span class=\"s3\">, or as a </span><span class=\"s4\">string</span><span class=\"s3\"> symbolic name such as </span><span class=\"s4\">\"s5\"</span><span class=\"s3\">); this may be </span><span class=\"s4\">NULL</span><span class=\"s3\"> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered </span><span class=\"s4\">SLiMEidosBlock</span><span class=\"s3\"> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new </span><span class=\"s4\">SLiMEidosBlock</span><span class=\"s3\"> will be defined as a global variable immediately by this method, and will also be returned by this method.</span></p>\n<p class=\"p5\">– (object&lt;SLiMEidosBlock&gt;$)registerMutationEffectCallback(Nis$ id, string$ source, io&lt;MutationType&gt;$ mutType, [Nio&lt;Subpopulation&gt;$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p6\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">mutationEffect()</span> callback in the current simulation (specific to the target species), with a required mutation type <span class=\"s1\">mutType</span> (which may be an <span class=\"s1\">integer</span> mutation type identifier), optional subpopulation <span class=\"s1\">subpop</span> (which may also be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations), and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerRecombinationCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL]<span class=\"s5\">, [Niso&lt;Chromosome&gt;$ chromosome = NULL]</span>, [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p6\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">recombination()</span> callback in the current simulation (specific to the target species), with optional subpopulation <span class=\"s1\">subpop</span> (which may be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations) and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>In multi-chromosome models, parameter <span class=\"s1\">chromosome</span>, if non-<span class=\"s1\">NULL</span>, may specify a chromosome to which the callback will apply (as either an <span class=\"s1\">integer</span> id, a <span class=\"s1\">string</span> symbol, or a <span class=\"s1\">Chromosome</span> object); otherwise, <span class=\"s1\">NULL</span> indicates that the callback applies to all chromosomes.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerReproductionCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL], <span class=\"s7\">[Ns$ sex = NULL], </span>[Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p6\"><span class=\"s3\">Register a block of Eidos source code, represented as the </span><span class=\"s4\">string</span><span class=\"s3\"> singleton </span><span class=\"s4\">source</span><span class=\"s3\">, as an Eidos </span><span class=\"s4\">reproduction()</span><span class=\"s3\"> callback in the current simulation</span> (specific to the target species)<span class=\"s3\">, with optional subpopulation </span><span class=\"s4\">subpop</span><span class=\"s3\"> (which may be an </span><span class=\"s4\">integer</span><span class=\"s3\"> identifier, or </span><span class=\"s4\">NULL</span><span class=\"s3\">, the default, to indicate all subpopulations), optional sex-specificity </span><span class=\"s4\">sex</span><span class=\"s3\"> (which may be </span><span class=\"s4\">\"M\"</span><span class=\"s3\"> or </span><span class=\"s4\">\"F\"</span><span class=\"s3\"> in sexual species to make the callback specific to males or females respectively, or </span><span class=\"s4\">NULL</span><span class=\"s3\"> for no sex-specificity), and optional </span><span class=\"s4\">start</span><span class=\"s3\"> and </span><span class=\"s4\">end</span><span class=\"s3\"> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier </span><span class=\"s4\">id</span><span class=\"s3\"> (specified as an </span><span class=\"s4\">integer</span><span class=\"s3\">, or as a </span><span class=\"s4\">string</span><span class=\"s3\"> symbolic name such as </span><span class=\"s4\">\"s5\"</span><span class=\"s3\">); this may be </span><span class=\"s4\">NULL</span><span class=\"s3\"> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered </span><span class=\"s4\">SLiMEidosBlock</span><span class=\"s3\"> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new </span><span class=\"s4\">SLiMEidosBlock</span><span class=\"s3\"> will be defined as a global variable immediately by this method, and will also be returned by this method.</span></p>\n<p class=\"p3\">– (object&lt;SLiMEidosBlock&gt;$)registerSurvivalCallback(Nis$ id, string$ source, [Nio&lt;Subpopulation&gt;$ subpop<span class=\"s9\"> </span>= NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p4\">Register a block of Eidos source code, represented as the <span class=\"s1\">string</span> singleton <span class=\"s1\">source</span>, as an Eidos <span class=\"s1\">survival()</span> callback in the current simulation<span class=\"s5\"> (specific to the target species)</span>, with optional subpopulation <span class=\"s1\">subpop</span> (which may be an <span class=\"s1\">integer</span> identifier, or <span class=\"s1\">NULL</span>, the default, to indicate all subpopulations) and optional <span class=\"s1\">start</span> and <span class=\"s1\">end</span> ticks all limiting its applicability.<span class=\"Apple-converted-space\">  </span>The script block will be given identifier <span class=\"s1\">id</span> (specified as an <span class=\"s1\">integer</span>, or as a <span class=\"s1\">string</span> symbolic name such as <span class=\"s1\">\"s5\"</span>); this may be <span class=\"s1\">NULL</span> if there is no need to be able to refer to the block later.<span class=\"Apple-converted-space\">  </span>The registered callback is added to the end of the list of registered <span class=\"s1\">SLiMEidosBlock</span> objects, and is active immediately; it <i>may</i> be eligible to execute in the current tick.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SLiMEidosBlock</span> will be defined as a global variable immediately by this method, and will also be returned by this method.</p>\n<p class=\"p3\">– (void)simulationFinished(void)</p>\n<p class=\"p6\">Declare the current simulation finished.<span class=\"Apple-converted-space\">  </span>This method is equivalent to the <span class=\"s1\">Community</span> method <span class=\"s1\">simulationFinished()</span>, except that this method is only legal to call in single-species models (to provide backward compatibility).<span class=\"Apple-converted-space\">  </span>It is recommended that new code should call the <span class=\"s1\">Community</span> method; this method may be deprecated in the future.</p>\n<p class=\"p3\">– (void)skipTick(void)</p>\n<p class=\"p6\">Deactivate the target species for the current tick.<span class=\"Apple-converted-space\">  </span>This sets the <span class=\"s1\">active</span> property of the species to <span class=\"s1\">F</span>; it also set the <span class=\"s1\">active</span> property of all callbacks that belong to the species (with the species as their <span class=\"s1\">species</span> specifier) to <span class=\"s1\">F</span>, and sets the active property of all events that are synchronized with the species (with the species as their <span class=\"s1\">ticks</span> specifier) to <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>The cycle counter for the species will not be incremented at the end of the tick.<span class=\"Apple-converted-space\">  </span>This method may only be called in <span class=\"s1\">first()</span> events, to ensure that species are either active or inactive throughout a given tick.</p>\n<p class=\"p5\">– (object&lt;Mutation&gt;)subsetMutations([No&lt;Mutation&gt;$ exclude = NULL], [Nio&lt;MutationType&gt;$ mutType = NULL], [Ni$ position = NULL], [Nis$ nucleotide = NULL], [Ni$ tag = NULL], [Ni$ id = NULL], [Niso&lt;Chromosome&gt; chromosome = NULL])</p>\n<p class=\"p6\">Returns a vector of mutations subset from the list of all active mutations in the species (as would be provided by the <span class=\"s1\">mutations</span> property).<span class=\"Apple-converted-space\">  </span>The parameters specify constraints upon the subset of mutations that will be returned.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">exclude</span>, if non-<span class=\"s1\">NULL</span>, may specify a specific mutation that should not be included (typically the focal mutation in some operation).<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">mutType</span>, if non-<span class=\"s1\">NULL</span>, may specify a mutation type for the mutations to be returned (as either a <span class=\"s1\">MutationType</span> object or an <span class=\"s1\">integer</span> identifier).<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">position</span>, if non-<span class=\"s1\">NULL</span>, may specify a base position for the mutations to be returned.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">nucleotide</span>, if non-<span class=\"s1\">NULL</span>, may specify a nucleotide for the mutations to be returned (either as a string, <span class=\"s1\">\"A\"</span> / <span class=\"s1\">\"C\"</span> / <span class=\"s1\">\"G\"</span> / <span class=\"s1\">\"T\"</span>, or as an integer, <span class=\"s1\">0</span> / <span class=\"s1\">1</span> / <span class=\"s1\">2</span> / <span class=\"s1\">3</span> respectively).<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">tag</span>, if non-<span class=\"s1\">NULL</span>, may specify a tag value for the mutations to be returned.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">id</span>, if non-<span class=\"s1\">NULL</span>, may specify a required value for the <span class=\"s1\">id</span> property of the mutations to be returned.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">chromosome</span>, if non-<span class=\"s1\">NULL</span>, may specify a chromosome or chromosomes with which the mutations returned must be associated (as either <span class=\"s1\">integer</span> ids, <span class=\"s1\">string</span> symbols, or <span class=\"s1\">Chromosome</span> objects).</p>\n<p class=\"p6\">This method is shorthand for getting the <span class=\"s1\">mutations</span> property of the subpopulation, and then using operator <span class=\"s1\">[]</span> to select only mutations with the desired properties; besides being much simpler than the equivalent Eidos code, it is also much faster.<span class=\"Apple-converted-space\">  </span>Note that if you only need to select on mutation type, the <span class=\"s1\">mutationsOfType()</span> method will be even faster.</p>\n<p class=\"p5\">– (object&lt;Substitution&gt;)substitutionsOfType(io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p6\">Returns an <span class=\"s1\">object</span> vector of all the substitutions that are of the type specified by <span class=\"s1\">mutType</span>, out of all of the substitutions that are currently present in the species.<span class=\"Apple-converted-space\">  </span>This method is provided for speed; it is much faster than the corresponding Eidos code.<span class=\"Apple-converted-space\">  </span>See also <span class=\"s1\">mutationsOfType()</span>.</p>\n<p class=\"p5\"><span class=\"s3\">– (logical$)treeSeqCoalesced(void)</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns the coalescence state for the recorded tree sequence at the last simplification.<span class=\"Apple-converted-space\">  </span>The returned value is a logical singleton flag, </span><span class=\"s4\">T</span><span class=\"s3\"> to indicate that full coalescence was observed at the last tree-sequence simplification (meaning that there is a single ancestral individual that roots all ancestry trees at all sites along the chromosome – although not necessarily the <i>same</i> ancestor at all sites), or </span><span class=\"s4\">F</span><span class=\"s3\"> if full coalescence was not observed.<span class=\"Apple-converted-space\">  </span>For simple models, reaching coalescence may indicate that the model has reached an equilibrium state, but this may not be true in models that modify the dynamics of the model during execution by changing migration rates, introducing new mutations programmatically, dictating non-random mating, etc., so be careful not to attach more meaning to coalescence than it is due; some models may require burn-in beyond coalescence to reach equilibrium, or may not have an equilibrium state at all.<span class=\"Apple-converted-space\">  </span>Also note that some actions by a model, such as adding a new subpopulation, may cause the coalescence state to revert from </span><span class=\"s4\">T</span><span class=\"s3\"> back to </span><span class=\"s4\">F</span><span class=\"s3\"> (at the next simplification), so a return value of </span><span class=\"s4\">T</span><span class=\"s3\"> may not necessarily mean that the model is coalesced at the present moment – only that it <i>was</i> coalesced at the last simplification.</span></p>\n<p class=\"p6\"><span class=\"s3\">This method may only be called if tree sequence recording has been turned on with </span><span class=\"s4\">initializeTreeSeq()</span><span class=\"s3\">; in addition, </span><span class=\"s4\">checkCoalescence=T</span><span class=\"s3\"> must have been supplied to </span><span class=\"s4\">initializeTreeSeq()</span><span class=\"s3\">, so that the necessary work is done during each tree-sequence simplification.<span class=\"Apple-converted-space\">  </span>Since this method does not perform coalescence checking itself, but instead simply returns the coalescence state observed at the last simplification, it may be desirable to call </span><span class=\"s4\">treeSeqSimplify()</span><span class=\"s3\"> immediately before </span><span class=\"s4\">treeSeqCoalesced()</span><span class=\"s3\"> to obtain up-to-date information.<span class=\"Apple-converted-space\">  </span>However, the speed penalty of doing this in every tick would be large, and most models do not need this level of precision; usually it is sufficient to know that the model has coalesced, without knowing whether that happened in the current tick or in a recent preceding tick.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (void)treeSeqOutput(string$ path, [logical$ simplify = T], [logical$ includeModel = T], </span>[No&lt;Dictionary&gt;$ metadata = NULL], [logical$ overwriteDirectory = F]<span class=\"s3\">)</span></p>\n<p class=\"p6\">Outputs the current tree sequence recording tables to the path specified by <span class=\"s1\">path</span>.<span class=\"Apple-converted-space\">  </span>This method may only be called if tree sequence recording has been turned on with <span class=\"s1\">initializeTreeSeq()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">simplify</span> is <span class=\"s1\">T</span> (the default), simplification will be done immediately prior to output; this is almost always desirable, unless a model wishes to avoid simplification entirely.<span class=\"Apple-converted-space\">  </span>(Note that if simplification is not done, then all haplosomes since the last simplification will be marked as samples in the resulting tree sequence.)</p>\n<p class=\"p6\">In a model of a single chromosome, a binary tree sequence file will be written to the specified path; a filename extension of <span class=\"s1\">.trees</span> is suggested for this type of file, and such a file is often referred to as a “<span class=\"s1\">.trees</span> file”.<span class=\"Apple-converted-space\">  </span>In a multi-chromosome model, a directory will instead be created at the specified path, and a separate <span class=\"s1\">.trees</span> file will be created within that directory for each chromosome in the model, mirroring the fact that SLiM keeps a separate tree sequence for each chromosome in a multi-chromosome model.<span class=\"Apple-converted-space\">  </span>These <span class=\"s1\">.trees</span> files will be given filenames based upon the <span class=\"s1\">symbol</span> property of each chromosome, as provided to <span class=\"s1\">initializeChromosome()</span>; for example, the tree sequence for a chromosome with symbol <span class=\"s1\">\"X\"</span> will be saved as <span class=\"s1\">chromosome_X.trees</span> within the specified directory.<span class=\"Apple-converted-space\">  </span>For the name of the directory itself, a suffix of <span class=\"s1\">_trees</span> is suggested, rather than <span class=\"s1\">.trees</span>, since the use of dot-extensions in directory names is not common; for example, <span class=\"s1\">\"model_Q_seed_17_trees\"</span> would be a path you might pass to <span class=\"s1\">treeSeqOutput()</span> as a directory name in a multi-chromosome model.<span class=\"Apple-converted-space\">  </span>Such a directory, containing separate <span class=\"s1\">.trees</span> files for each chromosome, is called a “trees archive”.<span class=\"Apple-converted-space\">  </span>Both <span class=\"s1\">.trees</span> files and trees archives can be read by <span class=\"s1\">readFromPopulationFile()</span>, as discussed in its documentation.</p>\n<p class=\"p6\">Normally, the full SLiM script used to generate the tree sequence is written out to the provenance entry of the tree sequence file, to the <span class=\"s1\">model</span> subkey of the <span class=\"s1\">parameters</span> top-level key.<span class=\"Apple-converted-space\">  </span>Supplying <span class=\"s1\">F</span> for <span class=\"s1\">includeModel</span> suppresses output of the full script.</p>\n<p class=\"p6\">A <span class=\"s1\">Dictionary</span> object containing user-generated metadata may be supplied with the <span class=\"s1\">metadata</span> parameter.<span class=\"Apple-converted-space\">  </span>If present, this dictionary will be serialized as JSON and attached to the saved tree sequence under a key named <span class=\"s1\">user_metadata</span>, within the <span class=\"s1\">SLiM</span> key.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">tskit</span> is used to read the tree sequence in Python, this metadata will automatically be deserialized and made available at <span class=\"s1\">ts.metadata[\"SLiM\"][\"user_metadata\"]</span>.<span class=\"Apple-converted-space\">  </span>This metadata dictionary is not used by SLiM, or by <span class=\"s1\">pyslim</span>, <span class=\"s1\">tskit</span>, or <span class=\"s1\">msprime</span>; you may use it for any purpose you wish.<span class=\"Apple-converted-space\">  </span>Note that <span class=\"s1\">metadata</span> may actually be any subclass of <span class=\"s1\">Dictionary</span>, such as a <span class=\"s1\">DataFrame</span>.<span class=\"Apple-converted-space\">  </span>It can even be a <span class=\"s1\">Species</span> object such as <span class=\"s1\">sim</span>, or a <span class=\"s1\">LogFile</span> instance; however, only the keys and values contained by the object’s <span class=\"s1\">Dictionary</span> superclass state will be serialized into the metadata (properties of the subclass will be ignored).<span class=\"Apple-converted-space\">  </span>This metadata dictionary can be recovered from the saved file using the <span class=\"s1\">treeSeqMetadata()</span> function.</p>\n<p class=\"p6\">When saving a single <span class=\"s1\">.trees</span> file, the standard behavior is to overwrite an existing file of the same name; the convenience of this generally outweighs the danger.<span class=\"Apple-converted-space\">  </span>When saving a trees archive, however, that balance shifts; overwriting an entire directory is potentially quite dangerous.<span class=\"Apple-converted-space\">  </span>For this reason, <span class=\"s1\">overwriteDirectory=F</span> (the default) specifies that <span class=\"s1\">treeSeqOutput()</span> should not overwrite an existing directory; it will instead raise an error.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">overwriteDirectory</span> is <span class=\"s1\">T</span>, <span class=\"s1\">treeSeqOutput()</span> will overwrite an existing directory of the same name (if the existing directory can be deleted without permissions errors and so forth), but only if the existing directory is empty or contains only files with a <span class=\"s1\">.trees</span> suffix, for safety; if other files are present, an error will still be raised.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)treeSeqRememberIndividuals(object&lt;Individual&gt; individuals</span>, [logical$ permanent = T]<span class=\"s3\">)</span></p>\n<p class=\"p6\">Mark the individuals specified by <span class=\"s1\">individuals</span> to be kept across tree sequence table simplification.<span class=\"Apple-converted-space\">  </span>This method may only be called if tree sequence recording has been turned on with <span class=\"s1\">initializeTreeSeq()</span>.<span class=\"Apple-converted-space\">  </span>All currently living individuals are always kept across simplification; this method does not need to be called, and indeed should not be called, for that purpose.<span class=\"Apple-converted-space\">  </span>Instead, <span class=\"s1\">treeSeqRememberIndividuals()</span> allows any individual, including dead individuals, to be kept in the final tree sequence.<span class=\"Apple-converted-space\">  </span>Typically this would be used, for example, to keep particular individuals that you wanted to be able to trace ancestry back to in later analysis.<span class=\"Apple-converted-space\">  </span>However, this is not the typical usage pattern for tree sequence recording; most models will not need to call this method.</p>\n<p class=\"p6\">There are two ways to keep individuals across simplification.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">permanent</span> is <span class=\"s1\">T</span> (the default), then the specified individuals will be permanently remembered: their haplosomes will be added to the current sample, and they will always be present in the tree sequence.<span class=\"Apple-converted-space\">  </span>Permanently remembering a large number of individuals will, of course, markedly increase memory usage and runtime.</p>\n<p class=\"p6\">Supplying <span class=\"s1\">F</span> for <span class=\"s1\">permanent</span> will instead mark the individuals only for (temporary) retention: their haplosomes will not be added to the sample, and they will appear in the final tree sequence only if one of their haplosomes is retained across simplification.<span class=\"Apple-converted-space\">  </span>In other words, the rule of thumb for retained individuals is simple: if a haplosome is kept by simplification, the haplosome’s corresponding individual is kept also, <i>if</i> it is retained.<span class=\"Apple-converted-space\">  </span>Note that permanent remembering takes priority; calling this function with <span class=\"s1\">permanent=F</span> on an individual that has previously been permanently remembered will not remove it from the sample.</p>\n<p class=\"p6\">The behavior of simplification for individuals retained with <span class=\"s1\">permanent=F</span> depends upon the value of the <span class=\"s1\">retainCoalescentOnly</span> flag passed to <span class=\"s1\">initializeTreeSeq()</span>; here we will discuss the behavior of that flag in detail.<span class=\"Apple-converted-space\">  </span>First of all, haplosomes are <i>always</i> removed by simplification unless they are (a) part of the final generation (i.e., in a living individual when simplification occurs), (b) ancestral to the final generation, (c) a haplosome of a permanently remembered individual, or (d) ancestral to a permanently remembered individual.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">retainCoalescentOnly</span> is <span class=\"s1\">T</span> (the default), they are <i>also</i> always removed if they are not a branch point (i.e., a coalescent node or most recent common ancestor) in the tree sequence.<span class=\"Apple-converted-space\">  </span>In some cases it may be useful to retain a haplosome and its associated individual when it is simply an intermediate node in the ancestry (i.e., in the middle of a branch).<span class=\"Apple-converted-space\">  </span>This can be enabled by setting <span class=\"s1\">retainCoalescentOnly</span> to <span class=\"s1\">F</span> in your call to <span class=\"s1\">initializeTreeSeq()</span>.<span class=\"Apple-converted-space\">  </span>In this case, ancestral haplosomes that are intermediate (“unary nodes”, in <span class=\"s1\">tskit</span> parlance) and are within an individual that has been retained using the <span class=\"s1\">permanent=F</span> flag here are kept, along with the retained individual itself.<span class=\"Apple-converted-space\">  </span>Since setting <span class=\"s1\">retainCoalescentOnly</span> to <span class=\"s1\">F</span> will prevent the unary nodes for retained individuals from being pruned, simplification may often be unable to prune very much at all from the tree sequence, and memory usage and runtime may increase rapidly.<span class=\"Apple-converted-space\">  </span>If you are retaining many individuals, this setting should therefore be used only with caution; it is not necessary if you are purely interested in the most recent common ancestors.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">pyslim</span> documentation for further discussion of retaining and remembering individuals and the effects of the <span class=\"s1\">retainCoalescentOnly</span> flag.</p>\n<p class=\"p6\"><span class=\"s3\">The metadata (age, location, etc) that are stored in the resulting tree sequence are those values present at either (a) the final generation, </span>if the individual is alive when the tree sequence is output<span class=\"s3\">, or (b) the last time that the individual was remembered, if not.<span class=\"Apple-converted-space\">  </span>Calling </span><span class=\"s4\">treeSeqRememberIndividuals()</span><span class=\"s3\"> on an individual that is already remembered will cause the archived information about the remembered individual to be updated to reflect the individual’s current state.<span class=\"Apple-converted-space\">  </span>A case where this is particularly important is for the spatial location of individuals in continuous-space models.<span class=\"Apple-converted-space\">  </span>SLiM automatically remembers the individuals that comprise the first generation of any new subpopulation created with </span><span class=\"s4\">addSubpop()</span><span class=\"s3\">, for easy recapitation and other analysis.<span class=\"Apple-converted-space\">  </span>However, since these first-generation individuals are remembered at the moment they are created, their spatial locations have not yet been set up, and will contain garbage – and those garbage values will be archived in their remembered state.<span class=\"Apple-converted-space\">  </span>If you need correct spatial locations of first-generation individuals for your post-simulation analysis, you should call </span><span class=\"s4\">treeSeqRememberIndividuals()</span><span class=\"s3\"> explicitly on the first generation, after setting spatial locations, to update the archived information with the correct spatial positions.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (void)treeSeqSimplify(void)</span></p>\n<p class=\"p6\"><span class=\"s3\">Triggers an immediate simplification of the tree sequence recording tables.<span class=\"Apple-converted-space\">  </span>This method may only be called if tree sequence recording has been turned on with </span><span class=\"s4\">initializeTreeSeq()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>A call to this method will free up memory being used by entries that are no longer in the ancestral path of any individual within the current sample (currently living individuals, in other words, plus those explicitly added to the sample with </span><span class=\"s4\">treeSeqRememberIndividuals()</span><span class=\"s3\">), but it can also take a significant amount of time.<span class=\"Apple-converted-space\">  </span>Typically calling this method is not necessary; the automatic simplification performed occasionally by SLiM should be sufficient for most models.</span></p>\n<p class=\"p1\"><b>5.17<span class=\"Apple-converted-space\">  </span>Class Subpopulation</b></p>\n<p class=\"p2\"><i>5.17.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Subpopulation</i></span><i> properties</i></p>\n<p class=\"p3\">cloningRate =&gt; (float)</p>\n<p class=\"p4\">The fraction of children in the next generation that will be produced by cloning (as opposed to biparental mating).<span class=\"Apple-converted-space\">  </span>In non-sexual (i.e. hermaphroditic) simulations, this property is a singleton <span class=\"s1\">float</span> representing the overall subpopulation cloning rate.<span class=\"Apple-converted-space\">  </span>In sexual simulations, this property is a <span class=\"s1\">float</span> vector with two values: the cloning rate for females (at index <span class=\"s1\">0</span>) and for males (at index <span class=\"s1\">1</span>).</p>\n<p class=\"p5\">description &lt;–&gt; (string$)</p>\n<p class=\"p6\">A human-readable <span class=\"s1\">string</span> description for the subpopulation.<span class=\"Apple-converted-space\">  </span>By default, this is the empty string, <span class=\"s1\">\"\"</span>; however, it may be set to whatever you wish.<span class=\"Apple-converted-space\">  </span>When tree-sequence recording is enabled, <span class=\"s1\">description</span> is persisted in the subpopulation’s metadata in tree-sequence output.</p>\n<p class=\"p3\">firstMaleIndex =&gt; (integer$)</p>\n<p class=\"p6\">The index of the first male individual in the subpopulation.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">individuals</span> vector of the subpopulation is sorted into females first and males second; <span class=\"s1\">firstMaleIndex</span> gives the position of the boundary between those sections.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">firstMaleIndex</span> property is also the number of females in the subpopulation, given this design.<span class=\"Apple-converted-space\">  </span>For non-sexual (i.e. hermaphroditic) simulations, the value of this property is undefined and should not be used.</p>\n<p class=\"p5\"><span class=\"s3\">fitnessScaling &lt;–&gt; (float$)</span></p>\n<p class=\"p6\"><span class=\"s3\">A </span><span class=\"s4\">float</span><span class=\"s3\"> scaling factor applied to the fitness of all individuals in this subpopulation (i.e., the fitness value computed for each individual will be multiplied by this value).<span class=\"Apple-converted-space\">  </span>This is primarily of use in nonWF models, where fitness is absolute, rather than in WF models, where fitness is relative (and thus a constant factor multiplied into the fitness of every individual will make no difference); however, it may be used in either type of model.<span class=\"Apple-converted-space\">  </span>This provides a simple, fast way to modify the fitness of all individuals in a subpopulation; conceptually it is similar to returning the same fitness effect for all individuals in the subpopulation from a </span><span class=\"s4\">fitnessEffect()</span><span class=\"s3\"> callback, but without the complexity and performance overhead of implementing such a callback.<span class=\"Apple-converted-space\">  </span>To scale the fitness of individuals by different (individual-specific) factors, see the </span><span class=\"s4\">fitnessScaling</span><span class=\"s3\"> property of </span><span class=\"s4\">Individual</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The value of </span><span class=\"s4\">fitnessScaling</span><span class=\"s3\"> is reset to </span><span class=\"s4\">1.0</span><span class=\"s3\"> every tick, so that any scaling factor set lasts for only a single tick.<span class=\"Apple-converted-space\">  </span>This reset occurs immediately after fitness values are calculated, in both WF and nonWF models.</span></p>\n<p class=\"p5\">haplosomes =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">All of the haplosomes contained by the subpopulation.<span class=\"Apple-converted-space\">  </span>All of the haplosomes for the first individual in the <span class=\"s1\">individuals</span> property are provided, followed by all the haplosomes for the second individual, etc., in the same order as <span class=\"s1\">individuals</span>.</p>\n<p class=\"p5\">haplosomesNonNull =&gt; (object&lt;Haplosome&gt;)</p>\n<p class=\"p6\">All of the haplosomes contained by the subpopulation, as with the <span class=\"s1\">haplosomes</span> property, if all of them are not null haplosomes; any null haplosomes present are excluded from the returned vector.<span class=\"Apple-converted-space\">  </span>This is a convenience shorthand, sometimes useful in models that involve null haplosomes.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this subpopulation; for subpopulation <span class=\"s1\">p3</span>, for example, this is <span class=\"s1\">3</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">immigrantSubpopFractions =&gt; (float)</p>\n<p class=\"p4\">The expected value of the fraction of children in the next generation that are immigrants arriving from particular subpopulations.</p>\n<p class=\"p3\">immigrantSubpopIDs =&gt; (integer)</p>\n<p class=\"p4\">The identifiers of the particular subpopulations from which immigrants will arrive in the next generation.</p>\n<p class=\"p3\">individualCount =&gt; (integer$)</p>\n<p class=\"p4\">The number of individuals in the subpopulation.</p>\n<p class=\"p3\">individuals =&gt; (object&lt;Individual&gt;)</p>\n<p class=\"p6\">All of the individuals contained by the subpopulation.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">sampleIndividuals()</span> and <span class=\"s1\">subsetIndividuals()</span> for fast ways to get a subset of the individuals in a subpopulation.</p>\n<p class=\"p5\">lifetimeReproductiveOutput =&gt; (integer)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">lifetimeReproductiveOutput</span> contains the value of the <span class=\"s1\">Individual</span> property <span class=\"s1\">reproductiveOutput</span> for all individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).<span class=\"Apple-converted-space\">  </span>This allows access to the lifetime reproductive output of individuals in the subpopulation at the end of their lives.<span class=\"Apple-converted-space\">  </span>If pedigree tracking is not on, this property is unavailable.</p>\n<p class=\"p5\">lifetimeReproductiveOutputF =&gt; (integer)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">lifetimeReproductiveOutputF</span> contains the value of the <span class=\"s1\">Individual</span> property <span class=\"s1\">reproductiveOutput</span> for all female individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).<span class=\"Apple-converted-space\">  </span>This property is undefined if separate sexes have not been enabled, or if pedigree tracking is not on.</p>\n<p class=\"p5\">lifetimeReproductiveOutputM =&gt; (integer)</p>\n<p class=\"p6\">If pedigree tracking is turned on with <span class=\"s1\">initializeSLiMOptions(keepPedigrees=T)</span>, <span class=\"s1\">lifetimeReproductiveOutputM</span> contains the value of the <span class=\"s1\">Individual</span> property <span class=\"s1\">reproductiveOutput</span> for all male individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).<span class=\"Apple-converted-space\">  </span>This property is undefined if separate sexes have not been enabled, or if pedigree tracking is not on.</p>\n<p class=\"p5\">name &lt;–&gt; (string$)</p>\n<p class=\"p6\">A human-readable <span class=\"s1\">string</span> name for the subpopulation.<span class=\"Apple-converted-space\">  </span>By default, this is the subpopulation’s symbol as a <span class=\"s1\">string</span>; for subpopulation <span class=\"s1\">p3</span>, for example, <span class=\"s1\">name</span> defaults to <span class=\"s1\">\"p3\"</span>.<span class=\"Apple-converted-space\">  </span>However, it may be set to whatever you wish except that subpopulation names must be unique across time (two different subpopulations may not both have the name <span class=\"s1\">\"foo\"</span>, even if they never exist at the same time).<span class=\"Apple-converted-space\">  </span>A subpopulation’s <span class=\"s1\">name</span> may appear as a label in SLiMgui, and it can be useful in generating output, debugging, and other purposes.<span class=\"Apple-converted-space\">  </span>When tree-sequence recording is enabled, <span class=\"s1\">name</span> is persisted in the subpopulation’s metadata in tree-sequence output, and can then be used in Python to identify the subpopulation; if you plan to take advantage of that feature, <span class=\"s1\">name</span> should follow the syntax of Python identifiers: starting with a letter or underscore <span class=\"s1\">[a-zA-Z_]</span>, followed by letters, digits, or underscores <span class=\"s1\">[a-zA-Z0-9_]</span>, without spaces, hyphens, or other characters.</p>\n<p class=\"p3\">selfingRate =&gt; (float$)</p>\n<p class=\"p4\">The expected value of the fraction of children in the next generation that will be produced by selfing (as opposed to biparental mating).<span class=\"Apple-converted-space\">  </span>Selfing is only possible in non-sexual (i.e. hermaphroditic) simulations; for sexual simulations this property always has a value of <span class=\"s1\">0.0</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">sexRatio =&gt; (float$)</p>\n<p class=\"p4\">For sexual simulations, the sex ratio for the subpopulation.<span class=\"Apple-converted-space\">  </span>This is defined, in SLiM, as the fraction of the subpopulation that is male; in other words, it is actually the M:(M+F) ratio.<span class=\"Apple-converted-space\">  </span>For non-sexual (i.e. hermaphroditic) simulations, this property has an undefined value and should not be used.</p>\n<p class=\"p5\">spatialMaps =&gt; (object&lt;SpatialMap&gt;)</p>\n<p class=\"p6\">The spatial maps that are currently added to the subpopulation.</p>\n<p class=\"p3\">spatialBounds =&gt; (float)</p>\n<p class=\"p4\">The spatial boundaries of the subpopulation.<span class=\"Apple-converted-space\">  </span>The length of the <span class=\"s1\">spatialBounds</span> property depends upon the spatial dimensionality declared with <span class=\"s1\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>If the spatial dimensionality is zero (as it is by default), the value of this property is <span class=\"s1\">float(0)</span> (a zero-length <span class=\"s1\">float</span> vector).<span class=\"Apple-converted-space\">  </span>Otherwise, minimums are supplied for each coordinate used by the dimensionality of the simulation, followed by maximums for each.<span class=\"Apple-converted-space\">  </span>In other words, if the declared dimensionality is <span class=\"s1\">\"xy\"</span>, the <span class=\"s1\">spatialBounds</span> property will contain values <span class=\"s1\">(x0, y0, x1, y1)</span>; bounds for the <i>z</i> coordinate will not be included in that case, since that coordinate is not used in the simulation’s dimensionality.<span class=\"Apple-converted-space\">  </span>This property cannot be set, but the <span class=\"s1\">setSpatialBounds()</span> method may be used to achieve the same thing.</p>\n<p class=\"p3\">species =&gt; (object&lt;Species&gt;$)</p>\n<p class=\"p6\"><span class=\"s3\">The species to which the target object belongs.</span></p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is initially undefined<span class=\"s7\">, and it is an error to try to read it</span>; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.<span class=\"Apple-converted-space\">  </span>See also the <span class=\"s1\">getValue()</span> and <span class=\"s1\">setValue()</span> methods<span class=\"s5\"> (provided by the </span><span class=\"s6\">Dictionary</span><span class=\"s5\"> class; see the Eidos manual)</span>, for another way of attaching state to subpopulations.</p>\n<p class=\"p2\"><i>5.17.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Subpopulation</i></span><i> methods</i></p>\n<p class=\"p5\"><span class=\"s3\">– (object&lt;Individual&gt;)addCloned(object&lt;Individual&gt;$ parent, [integer$ count = 1], [logical$ defer = F])</span></p>\n<p class=\"p6\">Generates a new offspring individual from the given parent by clonal reproduction, queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>The subpopulation of <span class=\"s1\">parent</span> will be used to locate applicable <span class=\"s1\">mutation()</span> and <span class=\"s1\">modifyChild()</span> callbacks governing the generation of the offspring individual.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, the <span class=\"s1\">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class=\"Apple-converted-space\">  </span>Each offspring is generated independently, based upon the given parameters.<span class=\"Apple-converted-space\">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>If all offspring are rejected, <span class=\"s1\">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class=\"s1\">NULL</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, passing <span class=\"s1\">T</span> for <span class=\"s1\">defer</span> requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.<span class=\"Apple-converted-space\">  </span>SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if <span class=\"s1\">defer</span> were <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>Haplosome generation can only be deferred if there are no active <span class=\"s1\">mutation()</span> callbacks; otherwise, an error will result.<span class=\"Apple-converted-space\">  </span>Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a <span class=\"s1\">modifyChild()</span> callback or otherwise).<span class=\"Apple-converted-space\">  </span>There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of <span class=\"s1\">F</span> for <span class=\"s1\">defer</span> is generally preferable since it has fewer restrictions.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).</p>\n<p class=\"p6\">Also beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from <span class=\"s1\">parent</span>; more specifically, the <span class=\"s1\">x</span> property will be inherited in all spatial models (1D/2D/3D), the <span class=\"s1\">y</span> property in 2D/3D models, and the <span class=\"s1\">z</span> property in 3D models.<span class=\"Apple-converted-space\">  </span>Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.<span class=\"Apple-converted-space\">  </span>The parent’s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to <span class=\"s1\">deviatePositions()</span> / <span class=\"s1\">pointDeviated()</span>.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">addCrossed()</span> for further general notes on the addition of new offspring individuals.</p>\n<p class=\"p5\"><span class=\"s3\">– (object&lt;Individual&gt;)addCrossed(object&lt;Individual&gt;$ parent1, object&lt;Individual&gt;$ parent2, [Nfs$ sex = NULL], [integer$ count = 1], [logical$ defer = F])</span></p>\n<p class=\"p6\">Generates a new offspring individual from the given parents by biparental sexual reproduction, queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>Attempting to use a newly generated offspring individual as a mate, or to reference it as a member of the target subpopulation in any other way, will result in an error.<span class=\"Apple-converted-space\">  </span>In most models the returned individual is not used, but it is provided for maximal generality and flexibility.</p>\n<p class=\"p6\">The new offspring individual is generated from <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> by crossing them.<span class=\"Apple-converted-space\">  </span>In sexual models <span class=\"s1\">parent1</span> must be female and <span class=\"s1\">parent2</span> must be male; in hermaphroditic models, <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> are unrestricted.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> are the same individual in a hermaphroditic model, that parent self-fertilizes, or “selfs”, to generate the offspring sexually (note this is not the same as clonal reproduction).<span class=\"Apple-converted-space\">  </span>Such selfing is considered “incidental” by <span class=\"s1\">addCrossed()</span>, however; if the <span class=\"s1\">preventIncidentalSelfing</span> flag of <span class=\"s1\">initializeSLiMOptions()</span> is <span class=\"s1\">T</span>, supplying the same individual for <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> is an error (you must check for and prevent incidental selfing if you set that flag in a nonWF model).<span class=\"Apple-converted-space\">  </span>If non-incidental selfing is desired, <span class=\"s1\">addSelfed()</span> should be used instead.</p>\n<p class=\"p6\">The <span class=\"s1\">sex</span> parameter specifies the sex of the offspring.<span class=\"Apple-converted-space\">  </span>A value of <span class=\"s1\">NULL</span> means “make the default choice”; in non-sexual models it is the only legal value for <span class=\"s1\">sex</span>, and does nothing, whereas in sexual models it causes male or female to be chosen with equal probability.<span class=\"Apple-converted-space\">  </span>A value of <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">sex</span> specifies that the offspring should be male or female, respectively.<span class=\"Apple-converted-space\">  </span>Finally, a <span class=\"s1\">float</span> value from <span class=\"s1\">0.0</span> to <span class=\"s1\">1.0</span> for <span class=\"s1\">sex</span> provides the probability that the offspring will be male; a value of <span class=\"s1\">0.0</span> will produce a female, a value of <span class=\"s1\">1.0</span> will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.<span class=\"Apple-converted-space\">  </span>Unless you wish the bias the sex ratio of offspring, the default value of <span class=\"s1\">NULL</span> should generally be used.</p>\n<p class=\"p6\">Note that any defined, active, and applicable <span class=\"s1\">recombination()</span>, <span class=\"s1\">mutation()</span>, and <span class=\"s1\">modifyChild()</span> callbacks will be called as a side effect of calling this method, before this method even returns.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">recombination()</span> and <span class=\"s1\">mutation()</span> callbacks, the subpopulation of the parent that is generating a given gamete is used; for <span class=\"s1\">modifyChild()</span> callbacks the situation is more complex.<span class=\"Apple-converted-space\">  </span>In most biparental mating events, <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> will belong to the same subpopulation, and <span class=\"s1\">modifyChild()</span> callbacks for that subpopulation will be used, just as in WF models.<span class=\"Apple-converted-space\">  </span>In certain models (such as models of pollen flow and broadcast spawning), however, biparental mating may occur between parents that are not from the same subpopulation; that is legal in nonWF models, and in that case, <span class=\"s1\">modifyChild()</span> callbacks for the subpopulation of <span class=\"s1\">parent1</span> are used (since that is the maternal parent).</p>\n<p class=\"p6\">If the <span class=\"s1\">modifyChild()</span> callback process results in rejection of the proposed child, a new offspring individual is not generated.<span class=\"Apple-converted-space\">  </span>To force the generation of an offspring individual from a given pair of parents, you could loop until <span class=\"s1\">addCrossed()</span> succeeds, but note that if your <span class=\"s1\">modifyChild()</span> callback rejects all proposed children from those particular parents, your model will then hang, so care must be taken with this approach.<span class=\"Apple-converted-space\">  </span>Usually, nonWF models do not force generation of offspring in this manner; rejection of a proposed offspring by a <span class=\"s1\">modifyChild()</span> callback typically represents a phenomenon such as post-mating reproductive isolation or lethal genetic incompatibilities that would reduce the expected litter size, so the default behavior is typically desirable.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, the <span class=\"s1\">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class=\"Apple-converted-space\">  </span>Each offspring is generated independently, based upon the given parameters.<span class=\"Apple-converted-space\">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>If all offspring are rejected, <span class=\"s1\">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class=\"s1\">NULL</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, passing <span class=\"s1\">T</span> for <span class=\"s1\">defer</span> requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.<span class=\"Apple-converted-space\">  </span>SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if <span class=\"s1\">defer</span> were <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>Haplosome generation can only be deferred if there are no active <span class=\"s1\">mutation()</span> or <span class=\"s1\">recombination()</span> callbacks; otherwise, an error will result.<span class=\"Apple-converted-space\">  </span>Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a <span class=\"s1\">modifyChild()</span> callback or otherwise).<span class=\"Apple-converted-space\">  </span>There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of <span class=\"s1\">F</span> for <span class=\"s1\">defer</span> is generally preferable since it has fewer restrictions.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).</p>\n<p class=\"p6\">Also beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from <span class=\"s1\">parent1</span>; more specifically, the <span class=\"s1\">x</span> property will be inherited in all spatial models (1D/2D/3D), the <span class=\"s1\">y</span> property in 2D/3D models, and the <span class=\"s1\">z</span> property in 3D models.<span class=\"Apple-converted-space\">  </span>Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.<span class=\"Apple-converted-space\">  </span>The parent’s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to <span class=\"s1\">deviatePositions()</span> / <span class=\"s1\">pointDeviated()</span>.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models, in which offspring generation is managed manually by the model script; in such models, <span class=\"s1\">addCrossed()</span> must be called only from <span class=\"s1\">reproduction()</span> callbacks, and may not be called at any other time.<span class=\"Apple-converted-space\">  </span>In WF models, offspring generation is managed automatically by the SLiM core.</p>\n<p class=\"p5\"><span class=\"s3\">– (object&lt;Individual&gt;)addEmpty([Nfs$ sex = NULL], [Nl$ haplosome1Null = NULL], [Nl$ haplosome2Null = NULL], [integer$ count = 1])</span></p>\n<p class=\"p6\">Generates a new offspring individual with empty haplosomes (i.e., containing no mutations), queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>No <span class=\"s1\">recombination()</span> or <span class=\"s1\">mutation()</span> callbacks will be called.<span class=\"Apple-converted-space\">  </span>The target subpopulation will be used to locate applicable <span class=\"s1\">modifyChild()</span> callbacks governing the generation of the offspring individual (unlike the other <span class=\"s1\">addX()</span> methods, because there is no parental individual to reference).<span class=\"Apple-converted-space\">  </span>The offspring is considered to have no parents for the purposes of pedigree tracking.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">sex</span> parameter is treated as in <span class=\"s1\">addCrossed()</span>.</p>\n<p class=\"p6\">For all chromosome types except <span class=\"s1\">\"A\"</span>, null haplosomes will be generated as dictated by the sex of the individual and type of the chromosome.<span class=\"Apple-converted-space\">  </span>For example, for chromosome type <span class=\"s1\">\"X\"</span> a female would be generated with two empty haplosomes for that chromosome (XX), whereas a male would be generated with one empty haplosome and one null haplosome (X–, in SLiM parlance).<span class=\"Apple-converted-space\">  </span>For chromosome type <span class=\"s1\">\"H\"</span> an empty haplosome is always generated, not a null haplosome.<span class=\"Apple-converted-space\">  </span>But for chromosome type <span class=\"s1\">\"A\"</span>, in particular, more control is afforded.<span class=\"Apple-converted-space\">  </span>Passing <span class=\"s1\">NULL</span> (the default) or <span class=\"s1\">F</span> for <span class=\"s1\">haplosome1Null</span> will make the first haplosome for every chromosome of type <span class=\"s1\">\"A\"</span> be a non-null (empty) haplosome, the standard behavior.<span class=\"Apple-converted-space\">  </span>More interestingly, passing <span class=\"s1\">T</span> for <span class=\"s1\">haplosome1Null</span> would make the first haplosome for every chromosome of type <span class=\"s1\">\"A\"</span> be a null haplosome.<span class=\"Apple-converted-space\">  </span>Similarly, passing <span class=\"s1\">T</span> for <span class=\"s1\">haplosome2Null</span> would make the second haplosome for every chromosome of type <span class=\"s1\">\"A\"</span> be a null haplosome.<span class=\"Apple-converted-space\">  </span>This option could be useful for situations such as adding new haploids into a haplodiploid model.<span class=\"Apple-converted-space\">  </span>(Separate control over the haploid or diploid configuration of each chromosome of type <span class=\"s1\">\"A\"</span> is not presently supported, but would be a simple extension to the design, by allowing <span class=\"s1\">haplosome1Null</span> and <span class=\"s1\">haplosome2Null</span> to provide a whole vector of <span class=\"s1\">logical</span> flags rather than just a singleton value; please request this feature if you require it.)</p>\n<p class=\"p6\">Beginning in SLiM 4.1, the <span class=\"s1\">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class=\"Apple-converted-space\">  </span>Each offspring is generated independently, based upon the given parameters.<span class=\"Apple-converted-space\">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>If all offspring are rejected, <span class=\"s1\">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class=\"s1\">NULL</span>.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">addCrossed()</span> for further general notes on the addition of new offspring individuals.</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)addMultiRecombinant(object&lt;Dictionary&gt;$ pattern, [Nfs$ sex = NULL], [No&lt;Individual&gt;$ parent1 = NULL], [No&lt;Individual&gt;$ parent2 = NULL], [Nl$ randomizeStrands = NULL], [integer$ count = 1], [logical$ defer = F])</p>\n<p class=\"p6\">Generates a new offspring individual based upon the inheritance pattern specified by <span class=\"s1\">pattern</span>, queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>The “pattern dictionary” supplied in <span class=\"s1\">pattern</span> must be of class <span class=\"s1\">Dictionary</span> (or a subclass of <span class=\"s1\">Dictionary</span>), and more particularly, must be a dictionary of dictionaries structured in a specific way as described below.<span class=\"Apple-converted-space\">  </span>This method is a multi-chromosome version of the <span class=\"s1\">addRecombinant()</span> method.<span class=\"Apple-converted-space\">  </span>For single-chromosome models, using <span class=\"s1\">addRecombinant()</span> will be simpler; and it will be easier to understand this extremely complex method if you understand <span class=\"s1\">addRecombinant()</span> first.</p>\n<p class=\"p6\">The top-level “pattern dictionary” given by <span class=\"s1\">pattern</span> specifies the way in which each chromosome should be handled.<span class=\"Apple-converted-space\">  </span>It can use <span class=\"s1\">integer</span> keys, in which case each key is the <span class=\"s1\">id</span> of a chromosome, or <span class=\"s1\">string</span> keys, in which case each key is the <span class=\"s1\">symbol</span> of a chromosome.<span class=\"Apple-converted-space\">  </span>In either case, a chromosome’s inheritance pattern is specified by an “inheritance dictionary” in <span class=\"s1\">pattern</span> attached to such a chromosome <span class=\"s1\">id</span> or <span class=\"s1\">symbol</span> key.<span class=\"Apple-converted-space\">  </span>That inheritance dictionary should itself contain up to six keys, with the standard names <span class=\"s1\">\"strand1\"</span>, <span class=\"s1\">\"strand2\"</span>, <span class=\"s1\">\"breaks1\"</span>, <span class=\"s1\">\"strand3\"</span>, <span class=\"s1\">\"strand4\"</span>, and <span class=\"s1\">\"breaks2\"</span>.<span class=\"Apple-converted-space\">  </span>Any key which is missing in an inheritance dictionary is assumed to have a value of <span class=\"s1\">NULL</span>, and missing keys will be referred to having a value of <span class=\"s1\">NULL</span> here for simplicity.<span class=\"Apple-converted-space\">  </span>These key-value pairs are used in precisely the same way as the parameters of the same names for <span class=\"s1\">addRecombinant()</span>, to produce the offspring haplosome(s) for each specified chromosome.<span class=\"Apple-converted-space\">  </span>There is some complication regarding how these six values can be used to produce results like crossing, cloning, and selfing, involving as many as four different “parents” for each chromosome; rather than repeating all of that documentation here, please see the <span class=\"s1\">addRecombinant()</span> documentation for more information.<span class=\"Apple-converted-space\">  </span>When an inheritance dictionary is supplied for a particular chromosome, this method uses the six values that dictionary contains (<span class=\"s1\">strand1</span>, <span class=\"s1\">strand2</span>, <span class=\"s1\">breaks1</span>, <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, <span class=\"s1\">breaks2</span>) in exactly the same way as <span class=\"s1\">addRecombinant()</span> does; <span class=\"s1\">addMultiRecombinant()</span> simply supports multiple chromosomes.<span class=\"Apple-converted-space\">  </span>In addition to that, however, <span class=\"s1\">addMultiRecombinant()</span> also allows the pattern dictionary to omit the inheritance dictionaries for particular chromosomes; the behavior of <span class=\"s1\">addMultiRecombinant()</span> in that special case will be described below, after discussing all other aspects of the method’s implementation.</p>\n<p class=\"p6\">The <span class=\"s1\">sex</span> parameter optionally specifies the sex of the offspring.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">NULL</span> for <span class=\"s1\">sex</span> specifies “default behavior”; in a non-sexual model this is the only legal value, and produces a hermaphroditic offspring.<span class=\"Apple-converted-space\">  </span>In a sexual model, the “default behavior” of <span class=\"s1\">NULL</span> is that the offspring’s sex is dictated by the haplosome structure it inherits.<span class=\"Apple-converted-space\">  </span>For example, if <span class=\"s1\">pattern</span> specifies that the offspring will have two non-null haplosomes for a chromosome of type <span class=\"s1\">\"X\"</span>, the sex of the offspring must therefore be female, whereas if it will have one non-null <span class=\"s1\">\"X\"</span> haplosome and one null <span class=\"s1\">\"X\"</span> haplosome, it must therefore be male.<span class=\"Apple-converted-space\">  </span>SLiM will scan through <span class=\"s1\">pattern</span> to determine such constraints and enforce them.<span class=\"Apple-converted-space\">  </span>If the constraints implied by <span class=\"s1\">pattern</span> are not self-consistent (if the offspring would have two non-null <span class=\"s1\">\"X\"</span> haplosomes but also a non-null <span class=\"s1\">\"Y\"</span> haplosome, for example), an error will be raised.<span class=\"Apple-converted-space\">  </span>The constraints defined by each chromosome type, as described in <span class=\"s1\">initializeChromosome()</span>, must always be followed, even when using <span class=\"s1\">addMultiRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">sex</span> is <span class=\"s1\">NULL</span> and <span class=\"s1\">pattern</span> imposes no constraints upon the sex of the offspring, the offspring will be chosen as male or female with equal probability.<span class=\"Apple-converted-space\">  </span>A value of <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">sex</span> specifies that the offspring should be male or female, respectively.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">float</span> value from <span class=\"s1\">0.0</span> to <span class=\"s1\">1.0</span> for <span class=\"s1\">sex</span> provides the probability that the offspring will be male; a value of <span class=\"s1\">0.0</span> will produce a female, a value of <span class=\"s1\">1.0</span> will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.<span class=\"Apple-converted-space\">  </span>In these cases where <span class=\"s1\">sex</span> is not <span class=\"s1\">NULL</span>, SLiM will first determine the sex of the individual as just described, and will then scan through <span class=\"s1\">pattern</span> to confirm that it is compatible with the sex that was determined.<span class=\"Apple-converted-space\">  </span>Again, if there is a conflict an error will be raised; you cannot specify the sex of an individual to be incompatible with the haplosomes that it inherits, and if you specify a sex with a <span class=\"s1\">string</span> or <span class=\"s1\">float</span> value it is up to you to ensure that that is compatible with the specifications in <span class=\"s1\">pattern</span>.<span class=\"Apple-converted-space\">  </span>(If you need more flexibility, you should probably not use a sexual model at all, but simply use chromosome types <span class=\"s1\">\"A\"</span> and <span class=\"s1\">\"H\"</span> in a non-sexual model, track the sex of individuals yourself with a tag value such as <span class=\"s1\">tagL0</span>, and manipulate haplosomes during reproduction however you wish; SLiM then imposes no constraints.)</p>\n<p class=\"p6\">By default, the offspring is considered to have no parents, since there may be more than two “parents” in the general case.<span class=\"Apple-converted-space\">  </span>If specifying parentage is desired, <span class=\"s1\">parent1</span> and/or <span class=\"s1\">parent2</span> may be passed explicitly; this will establish those individuals as the parents of the offspring for purposes of pedigree tracking, and for several other purposes described below.<span class=\"Apple-converted-space\">  </span>If only one of <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> is non-<span class=\"s1\">NULL</span>, that individual will be set as <i>both</i> of the parents of the offspring, mirroring the way that parentage is tracked for other cases such as <span class=\"s1\">addCloned()</span> and <span class=\"s1\">addSelfed()</span>.<span class=\"Apple-converted-space\">  </span>It is not required for <span class=\"s1\">parent1</span> or <span class=\"s1\">parent2</span> to actually be a genetic parent of the offspring at all, although typically they would be.<span class=\"Apple-converted-space\">  </span>To benefit from the full functionality of <span class=\"s1\">addMultiRecombinant()</span> as described below, it is best to supply <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> when possible.</p>\n<p class=\"p6\">The <span class=\"s1\">randomizeStrands</span> parameter is used to control the recombination behavior of <span class=\"s1\">addMultiRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>An inheritance dictionary can specify two parental strands with crossover breakpoints between them to generate one offspring strand with recombination – for example, with the <span class=\"s1\">\"strand1\"</span>, <span class=\"s1\">\"strand2\"</span>, and <span class=\"s1\">\"breaks1\"</span> keys, as described above, but the same is true of the <span class=\"s1\">\"strand3\"</span>, <span class=\"s1\">\"strand4\"</span>, and <span class=\"s1\">\"breaks2\"</span> keys, and the discussion that follows applies to both cases.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">F</span>, the supplied strands are used as given; for example, <span class=\"s1\">\"strand1\"</span> will be the initial copy strand when generating the first gamete to form the offspring.<span class=\"Apple-converted-space\">  </span>This mode should be used if you want explicit control over the initial copy strand; one example would be if your script is explicitly generating all four of the products of a meiosis event.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is T, then if <span class=\"s1\">\"strand1\"</span> and <span class=\"s1\">\"strand2\"</span> are both non-<span class=\"s1\">NULL</span>, 50% of the time they will be swapped, making <span class=\"s1\">\"strand2\"</span> the initial copy strand for the first gamete instead.<span class=\"Apple-converted-space\">  </span>This mode (<span class=\"s1\">randomizeStrands</span>=<span class=\"s1\">T</span>) is usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing <span class=\"s1\">T</span> for <span class=\"s1\">randomizeStrands</span> is recommended unless you specifically desire otherwise.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">NULL</span> in order to force either <span class=\"s1\">T</span> or <span class=\"s1\">F</span> to be explicitly chosen whenever it would make a difference; if it is left as <span class=\"s1\">NULL</span>, an error will be raised if generation of the specified offspring involves recombination, since then SLiM needs to know whether the value is <span class=\"s1\">T</span> or <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>(This unconventional approach has been adopted because the default value was <span class=\"s1\">F</span> prior to SLiM 5, but <span class=\"s1\">T</span> is almost always the correct behavior, as explained above.<span class=\"Apple-converted-space\">  </span>To try to prevent accidental bugs, this new policy was adopted to force the user to explicitly choose <span class=\"s1\">T</span> or <span class=\"s1\">F</span> whenever it matters.)</p>\n<p class=\"p6\">The value of the <span class=\"s1\">meanParentAge</span> property of the generated offspring is calculated from the mean parent age of each of its two haplosomes (whether they turn out to be null haplosomes or not).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">addRecombinant()</span> documentation provides a simple example; for <span class=\"s1\">addMultiRecombinant()</span> the logic is the same, but potentially extended to more than two offspring haplosomes.</p>\n<p class=\"p6\">Callbacks can be involved in offspring generation with <span class=\"s1\">addMultiRecombinant()</span>, but because there are up to four strands with up to four different parents, things are a bit complicated and different from other <span class=\"s1\">add...()</span> methods; the policy described here seems like the best compromise.<span class=\"Apple-converted-space\">  </span>The target subpopulation for the <span class=\"s1\">addMultiRecombinant()</span> call will be used to locate applicable <span class=\"s1\">mutation()</span> and <span class=\"s1\">modifyChild()</span> callbacks governing the generation of the offspring individual.<span class=\"Apple-converted-space\">  </span>On the other hand, <span class=\"s1\">recombination()</span> callbacks will be found based upon the subpopulations to which <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> belong (for reasons discussed further in <span class=\"s1\">drawBreakpoints()</span>); if a parent individual is not supplied, <span class=\"s1\">recombination()</span> callbacks will not be called at all when generating the corresponding offspring haplosome.</p>\n<p class=\"p6\">When breakpoints are explicitly supplied to <span class=\"s1\">addMultiRecombinant()</span> with <span class=\"s1\">breaks1</span> or <span class=\"s1\">breaks2</span>, gene conversion tracts are not well-supported by this method; the <span class=\"s1\">breaks1</span> and <span class=\"s1\">breaks2</span> vectors provide simple crossover breakpoints, which may be used to implement crossovers or simple gene conversion tracts, but complex gene conversion tracts with heteroduplex mismatch repair are not supported in this mode of operation since there is no way to supply the relevant information.<span class=\"Apple-converted-space\">  </span>If, on the other hand, <span class=\"s1\">breaks1</span> or <span class=\"s1\">breaks2</span> is <span class=\"s1\">NULL</span> when generating a haplosome with recombination, then as described above, <span class=\"s1\">addRecombinant()</span> will generate breakpoints internally for that cross, and in this case, complex gene conversion tracts with heteroduplex mismatch repair are supported, since all of the necessary information is available.<span class=\"Apple-converted-space\">  </span>Similarly, if the inheritance dictionary for a given chromosome is omitted from <span class=\"s1\">pattern</span> entirely and a cross between <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> is inferred (as discussed below), the recombination algorithm used will support gene conversion including heteroduplex mismatch repair.</p>\n<p class=\"p6\">Finally, <span class=\"s1\">count</span> is the number of offspring to generate using the given pattern and parameters, and <span class=\"s1\">defer</span> is used for deferral of offspring generation, as described for <span class=\"s1\">addRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>Any other details omitted from this documentation are all as described for <span class=\"s1\">addRecombinant()</span>.</p>\n<p class=\"p6\">Constructing a well-formed pattern dictionary with inheritance dictionaries for every chromosome can be a bit complex and require many lines of code.<span class=\"Apple-converted-space\">  </span>To ease the process, see the <span class=\"s1\">Species</span> methods <span class=\"s1\">addPatternForCross()</span>, <span class=\"s1\">addPatternForClone()</span>, <span class=\"s1\">addPatternForNull()</span>, and <span class=\"s1\">addPatternForRecombinant()</span>, which help you to build a pattern dictionary one inheritance dictionary at a time.<span class=\"Apple-converted-space\">  </span>However, several of these methods will probably be used infrequently, because of the final aspect of <span class=\"s1\">addMultiRecombinant()</span> that we have not yet properly discussed.</p>\n<p class=\"p6\">As mentioned earlier, not all chromosomes need to be specified with an inheritance dictionary in <span class=\"s1\">pattern</span>; whenever SLiM’s default inheritance behavior is well-defined and is desired for a given chromosome, the inheritance dictionary for that chromosome may be omitted, and will be inferred by <span class=\"s1\">addMultiRecombinant()</span> automatically.<span class=\"Apple-converted-space\">  </span>This behavior makes it easy to specify a reproduction event that is, for example, like a regular biparental cross involving many chromosomes, but that uses a different reproductive pattern just for one particular chromosome that behaves in a special way.<span class=\"Apple-converted-space\">  </span>The inferred inheritance dictionary for a given chromosome is based upon the chromosome type, the values of <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span>, and the sex of the offspring (which has, by this point, been determined in all cases).<span class=\"Apple-converted-space\">  </span>The rules for this inference are actually quite simple.<span class=\"Apple-converted-space\">  </span>If both parents are specified (that is, are both non-<span class=\"s1\">NULL</span>), the inferred inheritance dictionary is the same as would be produced by a call to <span class=\"s1\">addPatternForCross()</span> with those two parents, given in that order, for that chromosome, for the determined offspring sex.<span class=\"Apple-converted-space\">  </span>If only one parent is specified (non-<span class=\"s1\">NULL</span>), the inferred inheritance dictionary is the same as would be produced by a call to <span class=\"s1\">addPatternForClone()</span> with that one parent, for that chromosome, for the determined offspring sex.<span class=\"Apple-converted-space\">  </span>If selfing is desired for the inferred inheritance dictionary, pass the same individual for both <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span>; the behavior of <span class=\"s1\">addPatternForCross()</span> in that case is essentially to self the individual, as discussed in that method.<span class=\"Apple-converted-space\">  </span>If the inferred inheritance dictionary for a given chromosome is not well-defined, as discussed in the documentation for <span class=\"s1\">addPatternForCross()</span> and <span class=\"s1\">addPatternForClone()</span>, or if both <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> are <span class=\"s1\">NULL</span>, an error will be raised.<span class=\"Apple-converted-space\">  </span>In such cases, the inheritance dictionary cannot be inferred, and will need to be given explicitly in <span class=\"s1\">pattern</span>.</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)addRecombinant(No&lt;Haplosome&gt;$ strand1, No&lt;Haplosome&gt;$ strand2, Ni breaks1, No&lt;Haplosome&gt;$ strand3, No&lt;Haplosome&gt;$ strand4, Ni breaks2, [Nfs$ sex = NULL], [No&lt;Individual&gt;$ parent1 = NULL], [No&lt;Individual&gt;$ parent2 = NULL], [Nl$ randomizeStrands = NULL], [integer$ count = 1], [logical$ defer = F])</p>\n<p class=\"p6\">Generates a new offspring individual from the given parental haplosomes with the specified crossover breakpoints, queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>This method is an advanced feature; most models will use <span class=\"s1\">addCrossed()</span>, <span class=\"s1\">addSelfed()</span>, or <span class=\"s1\">addCloned()</span> instead.<span class=\"Apple-converted-space\">  </span>This method may only be used in single-chromosome models; in multi-chromosome models, use <span class=\"s1\">addMultiRecombinant()</span>, a more general version of <span class=\"s1\">addRecombinant()</span>.</p>\n<p class=\"p6\">This method supports several possible configurations for <span class=\"s1\">strand1</span>, <span class=\"s1\">strand2</span>, and <span class=\"s1\">breaks1</span> (and the same applies for <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, and <span class=\"s1\">breaks2</span>).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> are both <span class=\"s1\">NULL</span>, the corresponding haplosome in the generated offspring will be a null haplosome; in this case, <span class=\"s1\">breaks1</span> must be <span class=\"s1\">NULL</span> or zero-length.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">strand1</span> is non-<span class=\"s1\">NULL</span> but <span class=\"s1\">strand2</span> is <span class=\"s1\">NULL</span>, the corresponding haplosome in the generated offspring will be a clonal copy of <span class=\"s1\">strand1</span> with mutations added, as from <span class=\"s1\">addCloned()</span>; in this case, <span class=\"s1\">breaks1</span> must again be <span class=\"s1\">NULL</span> or zero-length.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> are both non-<span class=\"s1\">NULL</span>, the corresponding haplosome in the generated offspring will result from recombination between <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> with mutations added, as from <span class=\"s1\">addCrossed()</span>, with <span class=\"s1\">strand1</span> being the initial copy strand by default (but see below).<span class=\"Apple-converted-space\">  </span>Copying will switch between strands at each crossover breakpoint.<span class=\"Apple-converted-space\">  </span>Breakpoints may be supplied in <span class=\"s1\">breaks1</span>, which need not be sorted or uniqued (SLiM will sort and unique the supplied breakpoints internally).<span class=\"Apple-converted-space\">  </span>Alternatively, <span class=\"s1\">breaks1</span> may be <span class=\"s1\">NULL</span>, which requests that <span class=\"s1\">addRecombinant()</span> draw breakpoints automatically to recombine <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span>, following SLiM’s usual breakpoint-drawing algorithm.<span class=\"Apple-converted-space\">  </span>(If you do not want any breakpoints, pass <span class=\"s1\">integer(0)</span>, a zero-length <span class=\"s1\">integer</span> vector, for <span class=\"s1\">breaks1</span>.)<span class=\"Apple-converted-space\">  </span>Finally, it is not currently legal for <span class=\"s1\">strand1</span> to be <span class=\"s1\">NULL</span> and <span class=\"s1\">strand2</span> non-<span class=\"s1\">NULL</span>; that variant may be assigned some meaning in future.<span class=\"Apple-converted-space\">  </span>Again, this discussion applies equally to <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, and <span class=\"s1\">breaks2</span>, <i>mutatis mutandis</i>.<span class=\"Apple-converted-space\">  </span>Null haplosomes may never be passed as any of the four parental strands; pass <span class=\"s1\">NULL</span>, not a null haplosome, if that strand is not inherited from.<span class=\"Apple-converted-space\">  </span>When modeling a chromosome that is intrinsically haploid, such as the Y, <span class=\"s1\">NULL</span> must be passed for <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, and <span class=\"s1\">breaks2</span>; you cannot supply genetic information for an offspring haplosome that will not exist.<span class=\"Apple-converted-space\">  </span>Note that when new mutations are generated by <span class=\"s1\">addRecombinant()</span>, their <span class=\"s1\">subpopID</span> property will be the <span class=\"s1\">id</span> of the offspring’s subpopulation, since the parental subpopulation is ambiguous in the general case; this behavior differs from the other <span class=\"s1\">add...()</span> methods.</p>\n<p class=\"p6\">These semantics allow several uses for <span class=\"s1\">addRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>When all strands are non-<span class=\"s1\">NULL</span>, it is similar to <span class=\"s1\">addCrossed()</span> except that the recombination breakpoints can be specified explicitly, allowing very precise offspring generation without having to override SLiM’s breakpoint generation with a <span class=\"s1\">recombination()</span> callback.<span class=\"Apple-converted-space\">  </span>When only <span class=\"s1\">strand1</span> and <span class=\"s1\">strand3</span> are supplied, it is very similar to <span class=\"s1\">addCloned()</span>, creating a clonal offspring, except that the two parental haplosomes need not belong to the same individual (whatever that might mean biologically).<span class=\"Apple-converted-space\">  </span>Supplying only <span class=\"s1\">strand1</span> is useful for modeling clonally reproducing haploids, or any chromosome type that is intrinsically haploid, such as the Y chromosome.<span class=\"Apple-converted-space\">  </span>For a model of clonally reproducing haploids that undergo horizontal gene transfer (HGT), supplying only <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> will allow HGT from <span class=\"s1\">strand2</span> to replace segments of an otherwise clonal copy of <span class=\"s1\">strand1</span>, while the second haplosome of the generated offspring will be a null haplosome; this could be useful for modeling bacterial conjugation, for example.<span class=\"Apple-converted-space\">  </span>Other variations are also possible.</p>\n<p class=\"p6\">The <span class=\"s1\">sex</span> parameter optionally specifies the sex of the offspring.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">NULL</span> for <span class=\"s1\">sex</span> specifies “default behavior”; in a non-sexual model this is the only legal value, and produces a hermaphroditic offspring.<span class=\"Apple-converted-space\">  </span>In a sexual model, the “default behavior” of <span class=\"s1\">NULL</span> is that the offspring’s sex is dictated by the haplosome structure it inherits.<span class=\"Apple-converted-space\">  </span>For example, if the supplied strands indicate that the offspring will have two non-null haplosomes for a chromosome of type <span class=\"s1\">\"X\"</span>, the sex of the offspring must therefore be female, whereas if it will have one non-null <span class=\"s1\">\"X\"</span> haplosome and one null <span class=\"s1\">\"X\"</span> haplosome, it must therefore be male.<span class=\"Apple-converted-space\">  </span>SLiM will examine the supplied strands to determine such constraints and enforce them.<span class=\"Apple-converted-space\">  </span>The constraints defined by each chromosome type, as described in <span class=\"s1\">initializeChromosome()</span>, must always be followed, even when using <span class=\"s1\">addRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">sex</span> is <span class=\"s1\">NULL</span> and the sex of the offspring is unconstrained, the offspring will be chosen as male or female with equal probability.<span class=\"Apple-converted-space\">  </span>A value of <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">sex</span> specifies that the offspring should be male or female, respectively.<span class=\"Apple-converted-space\">  </span>A <span class=\"s1\">float</span> value from <span class=\"s1\">0.0</span> to <span class=\"s1\">1.0</span> for <span class=\"s1\">sex</span> provides the probability that the offspring will be male; a value of <span class=\"s1\">0.0</span> will produce a female, a value of <span class=\"s1\">1.0</span> will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.<span class=\"Apple-converted-space\">  </span>In these cases where <span class=\"s1\">sex</span> is not <span class=\"s1\">NULL</span>, SLiM will first determine the sex of the individual as just described, and will then examine the supplied strands to confirm that it is compatible with the sex that was determined.<span class=\"Apple-converted-space\">  </span>Again, if there is a conflict an error will be raised; you cannot specify the sex of an individual to be incompatible with the haplosomes that it inherits, and if you specify a sex with a <span class=\"s1\">string</span> or <span class=\"s1\">float</span> value it is up to you to ensure that that is compatible with the supplied strands.<span class=\"Apple-converted-space\">  </span>(If you need more flexibility, you should probably not use a sexual model at all, but simply use chromosome type <span class=\"s1\">\"A\"</span> or <span class=\"s1\">\"H\"</span> in a non-sexual model, track the sex of individuals yourself with a tag value such as <span class=\"s1\">tagL0</span>, and manipulate haplosomes during reproduction however you wish; SLiM then imposes no constraints.)</p>\n<p class=\"p6\">By default, the offspring is considered to have no parents, since there may be more than two “parents” in the general case.<span class=\"Apple-converted-space\">  </span>If specifying parentage is desired, <span class=\"s1\">parent1</span> and/or <span class=\"s1\">parent2</span> may be passed to explicitly; this will establish those individuals as the parents of the offspring for purposes of pedigree tracking, and for several other purposes described below.<span class=\"Apple-converted-space\">  </span>If only one of <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> is non-<span class=\"s1\">NULL</span>, that individual will be set as <i>both</i> of the parents of the offspring, mirroring the way that parentage is tracked for other cases such as <span class=\"s1\">addCloned()</span> and <span class=\"s1\">addSelfed()</span>.<span class=\"Apple-converted-space\">  </span>It is not required for <span class=\"s1\">parent1</span> or <span class=\"s1\">parent2</span> to actually be a genetic parent of the offspring at all, although typically they would be.<span class=\"Apple-converted-space\">  </span>To benefit from the full functionality of <span class=\"s1\">addRecombinant()</span> as described below, it is best to supply <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> when possible.</p>\n<p class=\"p6\">The <span class=\"s1\">randomizeStrands</span> parameter is used to control the recombination behavior of <span class=\"s1\">addRecombinant()</span>.<span class=\"Apple-converted-space\">  </span>As described above, two parental strands with crossover breakpoints between them can be specified to generate one offspring strand with recombination – for example, with the <span class=\"s1\">strand1</span>, <span class=\"s1\">strand2</span>, and <span class=\"s1\">breaks1</span> parameters, but the same is true of the <span class=\"s1\">strand3</span>, <span class=\"s1\">strand4</span>, and <span class=\"s1\">breaks2</span> parameters, and the discussion that follows applies to both cases.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">F</span>, the supplied strands are used as given; for example, <span class=\"s1\">strand1</span> will be the initial copy strand when generating the first gamete to form the offspring.<span class=\"Apple-converted-space\">  </span>This mode should be used if you want explicit control over the initial copy strand; one example would be if your script is explicitly generating all four of the products of a meiosis event.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">T</span>, then if <span class=\"s1\">strand1</span> and <span class=\"s1\">strand2</span> are both non-<span class=\"s1\">NULL</span>, 50% of the time they will be swapped, making <span class=\"s1\">strand2</span> the initial copy strand for the first gamete instead.<span class=\"Apple-converted-space\">  </span>This mode (<span class=\"s1\">randomizeStrands</span>=<span class=\"s1\">T</span>) is usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing <span class=\"s1\">T</span> for <span class=\"s1\">randomizeStrands</span> is recommended unless you specifically desire otherwise.<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s1\">randomizeStrands</span> is <span class=\"s1\">NULL</span> in order to force either <span class=\"s1\">T</span> or <span class=\"s1\">F</span> to be explicitly chosen whenever it would make a difference; if it is left as <span class=\"s1\">NULL</span>, an error will be raised if generation of the specified offspring involves recombination, since then SLiM needs to know whether the value is <span class=\"s1\">T</span> or <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>(This unconventional approach has been adopted because the default value was <span class=\"s1\">F</span> prior to SLiM 5, but <span class=\"s1\">T</span> is almost always the correct behavior, as explained above.<span class=\"Apple-converted-space\">  </span>To try to prevent accidental bugs, this new policy was adopted to force the user to explicitly choose <span class=\"s1\">T</span> or <span class=\"s1\">F</span> whenever it matters.)</p>\n<p class=\"p6\">The value of the <span class=\"s1\">meanParentAge</span> property of the generated offspring is calculated from the mean parent age of each of its two haplosomes (whether they turn out to be null haplosomes or not); that may be an average of two values (if both offspring haplosomes have at least one parent), a single value (if one offspring haplosome has no parent), or no values (if both offspring haplosomes have no parent, in which case <span class=\"s1\">0.0</span> results).<span class=\"Apple-converted-space\">  </span>The mean parent age of a given offspring haplosome is the mean of the ages of the parents of the two strands used to generate that offspring haplosome; if one strand is <span class=\"s1\">NULL</span> then the mean parent age for that offspring haplosome is the age of the parent of the non-<span class=\"s1\">NULL</span> strand, while if both strands are <span class=\"s1\">NULL</span> then that offspring haplosome is parentless and is not used in the final calculation.<span class=\"Apple-converted-space\">  </span>In other words, if one offspring haplosome has two parents with ages A and B, and the other offspring haplosome has one parent with age C, the <span class=\"s1\">meanParentAge</span> of the offspring will be (A+B+C+C) / 4, or equivalently, ((A+B)/2 + C) / 2, not (A+B+C) / 3.</p>\n<p class=\"p6\">Callbacks can be involved in offspring generation with <span class=\"s1\">addRecombinant()</span>, but because there are up to four strands with up to four different parents, things are a bit complicated and different from other <span class=\"s1\">add...()</span> methods; the policy described here seems like the best compromise.<span class=\"Apple-converted-space\">  </span>The target subpopulation for the <span class=\"s1\">addRecombinant()</span> call will be used to locate applicable <span class=\"s1\">mutation()</span> and <span class=\"s1\">modifyChild()</span> callbacks governing the generation of the offspring individual.<span class=\"Apple-converted-space\">  </span>On the other hand, <span class=\"s1\">recombination()</span> callbacks will be found based upon the subpopulations to which <span class=\"s1\">parent1</span> and <span class=\"s1\">parent2</span> belong (for reasons discussed further in <span class=\"s1\">drawBreakpoints()</span>); if a parent individual is not supplied, <span class=\"s1\">recombination()</span> callbacks will not be called at all when generating the corresponding offspring haplosome.</p>\n<p class=\"p6\">When breakpoints are explicitly supplied to <span class=\"s1\">addRecombinant()</span> with <span class=\"s1\">breaks1</span> or <span class=\"s1\">breaks2</span>, gene conversion tracts are not well-supported by this method; the <span class=\"s1\">breaks1</span> and <span class=\"s1\">breaks2</span> vectors provide simple crossover breakpoints, which may be used to implement crossovers or simple gene conversion tracts, but complex gene conversion tracts with heteroduplex mismatch repair are not supported in this mode of operation since there is no way to supply the relevant information.<span class=\"Apple-converted-space\">  </span>If, on the other hand, <span class=\"s1\">breaks1</span> or <span class=\"s1\">breaks2</span> is <span class=\"s1\">NULL</span> when generating a haplosome with recombination, then as described above, <span class=\"s1\">addRecombinant()</span> will generate breakpoints internally for that cross, and in this case, complex gene conversion tracts with heteroduplex mismatch repair are supported, since all of the necessary information is available.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, the <span class=\"s1\">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class=\"Apple-converted-space\">  </span>Each offspring is generated independently, based upon the given parameters.<span class=\"Apple-converted-space\">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>If all offspring are rejected, <span class=\"s1\">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class=\"s1\">NULL</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, passing <span class=\"s1\">T</span> for <span class=\"s1\">defer</span> requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.<span class=\"Apple-converted-space\">  </span>SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if <span class=\"s1\">defer</span> were <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>Haplosome generation can only be deferred if there are no active <span class=\"s1\">mutation()</span> callbacks; otherwise, an error will result.<span class=\"Apple-converted-space\">  </span>Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a <span class=\"s1\">modifyChild()</span> callback or otherwise).<span class=\"Apple-converted-space\">  </span>There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of <span class=\"s1\">F</span> for <span class=\"s1\">defer</span> is generally preferable since it has fewer restrictions.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).</p>\n<p class=\"p6\">Also beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from <span class=\"s1\">parent1</span>; more specifically, the <span class=\"s1\">x</span> property will be inherited in all spatial models (1D/2D/3D), the <span class=\"s1\">y</span> property in 2D/3D models, and the <span class=\"s1\">z</span> property in 3D models.<span class=\"Apple-converted-space\">  </span>Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.<span class=\"Apple-converted-space\">  </span>The parent’s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to <span class=\"s1\">deviatePositions()</span> / <span class=\"s1\">pointDeviated()</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">parent1</span> is <span class=\"s1\">NULL</span>, <span class=\"s1\">parent2</span> will be used; if it is also <span class=\"s1\">NULL</span>, no spatial position will be inherited.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">addCrossed()</span> for further general notes on the addition of new offspring individuals.</p>\n<p class=\"p5\"><span class=\"s3\">– (object&lt;Individual&gt;)addSelfed(object&lt;Individual&gt;$ parent, [integer$ count = 1], [logical$ defer = F])</span></p>\n<p class=\"p6\">Generates a new offspring individual from the given parent by selfing, queues it for addition to the target subpopulation, and returns it.<span class=\"Apple-converted-space\">  </span>The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.<span class=\"Apple-converted-space\">  </span>The subpopulation of <span class=\"s1\">parent</span> will be used to locate applicable <span class=\"s1\">mutation()</span>, <span class=\"s1\">recombination()</span>, and <span class=\"s1\">modifyChild()</span> callbacks governing the generation of the offspring individual.</p>\n<p class=\"p6\">Since selfing requires that <span class=\"s1\">parent</span> act as a source of both a male and a female gamete, this method may be called only in hermaphroditic models; calling it in sexual models will result in an error.<span class=\"Apple-converted-space\">  </span>This method represents a non-incidental selfing event, so the <span class=\"s1\">preventIncidentalSelfing</span> flag of <span class=\"s1\">initializeSLiMOptions()</span> has no effect on this method (in contrast to the behavior of <span class=\"s1\">addCrossed()</span>, where selfing is assumed to be incidental).</p>\n<p class=\"p6\">Beginning in SLiM 4.1, the <span class=\"s1\">count</span> parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).<span class=\"Apple-converted-space\">  </span>Each offspring is generated independently, based upon the given parameters.<span class=\"Apple-converted-space\">  </span>The returned vector contains all generated offspring, except those that were rejected by a <span class=\"s1\">modifyChild()</span> callback.<span class=\"Apple-converted-space\">  </span>If all offspring are rejected, <span class=\"s1\">object&lt;Individual&gt;(0)</span> is returned, which is a zero-length <span class=\"s1\">object</span> vector of class <span class=\"s1\">Individual</span>; note that this is a change in behavior from earlier versions, which would return <span class=\"s1\">NULL</span>.</p>\n<p class=\"p6\">Beginning in SLiM 4.1, passing <span class=\"s1\">T</span> for <span class=\"s1\">defer</span> requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.<span class=\"Apple-converted-space\">  </span>SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if <span class=\"s1\">defer</span> were <span class=\"s1\">F</span>.<span class=\"Apple-converted-space\">  </span>Haplosome generation can only be deferred if there are no active <span class=\"s1\">mutation()</span> or <span class=\"s1\">recombination()</span> callbacks; otherwise, an error will result.<span class=\"Apple-converted-space\">  </span>Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a <span class=\"s1\">modifyChild()</span> callback or otherwise).<span class=\"Apple-converted-space\">  </span>There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of <span class=\"s1\">F</span> for <span class=\"s1\">defer</span> is generally preferable since it has fewer restrictions.<span class=\"Apple-converted-space\">  </span>When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).</p>\n<p class=\"p6\">Also beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from <span class=\"s1\">parent</span>; more specifically, the <span class=\"s1\">x</span> property will be inherited in all spatial models (1D/2D/3D), the <span class=\"s1\">y</span> property in 2D/3D models, and the <span class=\"s1\">z</span> property in 3D models.<span class=\"Apple-converted-space\">  </span>Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.<span class=\"Apple-converted-space\">  </span>The parent’s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to <span class=\"s1\">deviatePositions()</span> / <span class=\"s1\">pointDeviated()</span>.</p>\n<p class=\"p6\">Note that this method is only for use in nonWF models.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">addCrossed()</span> for further general notes on the addition of new offspring individuals.</p>\n<p class=\"p5\">– (void)addSpatialMap(object&lt;SpatialMap&gt;$ map)</p>\n<p class=\"p6\">Adds the given <span class=\"s1\">SpatialMap</span> object, <span class=\"s1\">map</span>, to the subpopulation.<span class=\"Apple-converted-space\">  </span>(The spatial map would have been previously created with a call to <span class=\"s1\">defineSpatialMap()</span> on a different subpopulation; <span class=\"s1\">addSpatialMap()</span> can then be used to add that existing spatial map with other subpopulations, sharing the map between subpopulations.)<span class=\"Apple-converted-space\">  </span>If the map is already added to the target subpopulation, this method does nothing; if a different map with the same name is already added to the subpopulation, an error results (because map names must be unique within each subpopulation).<span class=\"Apple-converted-space\">  </span>The map being added must be compatible with the target subpopulation; in particular, the spatial bounds utilized by the map must exactly match the corresponding spatial bounds for the subpopulation, and the dimensionality of the subpopulation must encompass the spatiality of the map.<span class=\"Apple-converted-space\">  </span>For example, if the map has a spatiality of <span class=\"s1\">\"xz\"</span> then the subpopulation must have a dimensionality of <span class=\"s1\">\"xyz\"</span> so that it encompasses both <span class=\"s1\">\"x\"</span> and <span class=\"s1\">\"z\"</span>, and the subpopulation’s spatial bounds for <span class=\"s1\">\"x\"</span> and <span class=\"s1\">\"z\"</span> must match those for the map (but the spatial bounds for <span class=\"s1\">\"y\"</span> are unimportant, since the map does not use that dimension).</p>\n<p class=\"p6\">Adding a map to a subpopulation is not strictly necessary, at present; one may query a <span class=\"s1\">SpatialMap</span> object directly using <span class=\"s1\">mapValue()</span>, regarding points in a subpopulation, without the map actually having been added to that subpopulation.<span class=\"Apple-converted-space\">  </span>However, it is a good idea to use <span class=\"s1\">addSpatialMap()</span>, both for its compatibility check that prevents unnoticed scripting errors, and because it ensures correct display of the model in SLiMgui.</p>\n<p class=\"p3\">– (float)cachedFitness(Ni indices)</p>\n<p class=\"p6\">The fitness values calculated for the individuals at the indices given are returned.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">NULL</span> is passed, fitness values for all individuals in the subpopulation are returned.<span class=\"Apple-converted-space\">  </span>The fitness values returned are cached values; <span class=\"s1\">mutationEffect()</span> and <span class=\"s1\">fitnessEffect()</span> callbacks are therefore not called as a side effect of this method.<span class=\"Apple-converted-space\">  </span>It is always an error to call <span class=\"s1\">cachedFitness()</span> from inside a <span class=\"s1\">mutationEffect()</span> or <span class=\"s1\">fitnessEffect()</span> callback, since fitness values are in the middle of being set up.<span class=\"Apple-converted-space\">  </span>In WF models, it is also an error to call <span class=\"s1\">cachedFitness()</span> from a <span class=\"s1\">late()</span> event, because fitness values for the new offspring generation have not yet been calculated and are undefined.<span class=\"Apple-converted-space\">  </span>In nonWF models, the population may be a mixture of new and old individuals, so instead, <span class=\"s1\">NAN</span> will be returned as the fitness of any new individuals whose fitness has not yet been calculated.<span class=\"Apple-converted-space\">  </span>When new subpopulations are first created with <span class=\"s1\">addSubpop()</span> or <span class=\"s1\">addSubpopSplit()</span>, the fitness of all of the newly created individuals is considered to be <span class=\"s1\">1.0</span> until fitness values are recalculated.</p>\n<p class=\"p5\"><span class=\"s3\">– (void)configureDisplay([Nf center = NULL], [Nf$ scale = NULL], [Ns$ color = NULL])</span></p>\n<p class=\"p6\"><span class=\"s3\">This method customizes the display of the subpopulation in SLiMgui’s Population Visualization graph.<span class=\"Apple-converted-space\">  </span>When this method is called by a model running outside SLiMgui, it will do nothing except type-checking and bounds-checking its arguments.<span class=\"Apple-converted-space\">  </span>When called by a model running in SLiMgui, the position, size, and color of the subpopulation’s displayed circle can be controlled as specified below.</span></p>\n<p class=\"p6\"><span class=\"s3\">The </span><span class=\"s4\">center</span><span class=\"s3\"> parameter sets the coordinates of the center of the subpopulation’s displayed circle; it must be a </span><span class=\"s4\">float</span><span class=\"s3\"> vector of length two, such that </span><span class=\"s4\">center[0]</span><span class=\"s3\"> provides the <i>x</i>-coordinate and </span><span class=\"s4\">center[1]</span><span class=\"s3\"> provides the <i>y</i>-coordinate.<span class=\"Apple-converted-space\">  </span>The square central area of the Population Visualization occupies scaled coordinates in [0,1] for both <i>x</i> and <i>y</i>, so the values in </span><span class=\"s4\">center</span><span class=\"s3\"> must be within those bounds.<span class=\"Apple-converted-space\">  </span>If a value of </span><span class=\"s4\">NULL</span><span class=\"s3\"> is provided, SLiMgui’s default center will be used (which currently arranges subpopulations in a circle).</span></p>\n<p class=\"p6\"><span class=\"s3\">The </span><span class=\"s4\">scale</span><span class=\"s3\"> parameter sets a scaling factor to be applied to the radius of the subpopulation’s displayed circle.<span class=\"Apple-converted-space\">  </span>The default radius used by SLiMgui is a function of the subpopulation’s number of individuals; this default radius is then multiplied by </span><span class=\"s4\">scale</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If a value of </span><span class=\"s4\">NULL</span><span class=\"s3\"> is provided, the default radius will be used; this is equivalent to supplying a </span><span class=\"s4\">scale</span><span class=\"s3\"> of </span><span class=\"s4\">1.0</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>Typically the same </span><span class=\"s4\">scale</span><span class=\"s3\"> value should be used by all subpopulations, to scale all of their circles up or down uniformly, but that is not required.</span></p>\n<p class=\"p6\"><span class=\"s3\">The </span><span class=\"s4\">color</span><span class=\"s3\"> parameter sets the color to be used for the displayed subpopulation’s circle.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form </span><span class=\"s4\">\"#RRGGBB\"</span><span class=\"s3\"> (see the Eidos manual).<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s4\">color</span><span class=\"s3\"> is </span><span class=\"s4\">NULL</span><span class=\"s3\"> or the empty string, </span><span class=\"s4\">\"\"</span><span class=\"s3\">, SLiMgui’s default (fitness-based) color will be used.</span></p>\n<p class=\"p5\">– (object&lt;SpatialMap&gt;$)defineSpatialMap(string$ name, string$ spatiality, numeric values, [logical$ interpolate = F], [Nif valueRange = NULL], [Ns colors = NULL])</p>\n<p class=\"p6\">Defines a spatial map for the subpopulation; see the <span class=\"s1\">SpatialMap</span> documentation regarding this class.<span class=\"Apple-converted-space\">  </span>The new map is automatically added to the subpopulation; <span class=\"s1\">addSpatialMap()</span> does not need to be called.<span class=\"Apple-converted-space\">  </span>(That method is for sharing the map with additional subpopulations, beyond the one for which the map was originally defined.)<span class=\"Apple-converted-space\">  </span>The new <span class=\"s1\">SpatialMap</span> object is returned, and may be retained permanently using <span class=\"s1\">defineConstant()</span> or <span class=\"s1\">defineGlobal()</span> for convenience.</p>\n<p class=\"p6\">The name of the map is given by <span class=\"s1\">name</span>, and can be used to identify it.<span class=\"Apple-converted-space\">  </span>The map uses the spatial dimensions referenced by <span class=\"s1\">spatiality</span>, which must be a subset of the dimensions defined for the simulation in <span class=\"s1\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>Spatiality <span class=\"s1\">\"x\"</span> is permitted for dimensionality <span class=\"s1\">\"x\"</span>; spatiality <span class=\"s1\">\"x\"</span>, <span class=\"s1\">\"y\"</span>, or <span class=\"s1\">\"xy\"</span> for dimensionality <span class=\"s1\">\"xy\"</span>; and spatiality <span class=\"s1\">\"x\"</span>, <span class=\"s1\">\"y\"</span>, <span class=\"s1\">\"z\"</span>, <span class=\"s1\">\"xy\"</span>, <span class=\"s1\">\"yz\"</span>, <span class=\"s1\">\"xz\"</span>, or <span class=\"s1\">\"xyz\"</span> for dimensionality <span class=\"s1\">\"xyz\"</span>.<span class=\"Apple-converted-space\">  </span>The spatial map is defined by a grid of values supplied in parameter <span class=\"s1\">values</span>.<span class=\"Apple-converted-space\">  </span>That grid of values is aligned with the spatial bounds of the subpopulation, as described in more detail below; the spatial map is therefore coupled to those spatial bounds, and can only be used in subpopulations that match those particular spatial bounds (to avoid stretching or shrinking the map).<span class=\"Apple-converted-space\">  </span>The remaining optional parameters are described below.</p>\n<p class=\"p6\">Note that the semantics of this method changed in SLiM 3.5; in particular, the <span class=\"s1\">gridSize</span> parameter was removed, and the interpretation of the <span class=\"s1\">values</span> parameter changed as described below.<span class=\"Apple-converted-space\">  </span>Existing code written prior to SLiM 3.5 will produce an error, due to the removed <span class=\"s1\">gridSize</span> parameter, and must be revised carefully to obtain the same result, even if <span class=\"s1\">NULL</span> had been passed for <span class=\"s1\">gridSize</span> previously.</p>\n<p class=\"p6\">Beginning in SLiM 3.5, the <span class=\"s1\">values</span> parameter must be a vector/matrix/array with the number of dimensions appropriate for the declared spatiality of the map; for example, a map with spatiality <span class=\"s1\">\"x\"</span> would require a (one-dimensional) vector, spatiality <span class=\"s1\">\"xy\"</span> would require a (two-dimensional) matrix, and a map with spatiality of <span class=\"s1\">\"xyz\"</span> would require a three-dimensional array.<span class=\"Apple-converted-space\">  </span>(See the Eidos manual for discussion of vectors, matrices, and arrays.)<span class=\"Apple-converted-space\">  </span>The data in <span class=\"s1\">values</span> is interpreted in such a way that a two-dimensional matrix of values, with (0, 0) at upper left and values by column, is transformed into the format expected by SLiM, with (0, 0) at lower left and values by row; in other words, the two-dimensional matrix as it prints in the Eidos console will match the appearance of the two-dimensional spatial map as seen in SLiMgui.<span class=\"Apple-converted-space\">  </span><i>This is a change in behavior from versions prior to SLiM 3.5</i>; it ensures that images loaded from disk with the Eidos class <span class=\"s1\">Image</span> can be used directly as spatial maps, achieving the expected orientation, with no need for transposition or flipping.<span class=\"Apple-converted-space\">  </span>If the spatial map is a three-dimensional array, it is read as successive <i>z</i>-axis “planes”, each of which is a two-dimensional matrix that is treated as described above.</p>\n<p class=\"p6\">Moving on to the other parameters of <span class=\"s1\">defineSpatialMap()</span>: if <span class=\"s1\">interpolate</span> is <span class=\"s1\">F</span>, values across the spatial map are not interpolated; the value at a given point is equal to the nearest value defined by the grid of values specified.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">interpolate</span> is <span class=\"s1\">T</span>, values across the spatial map will be interpolated (using linear, bilinear, or trilinear interpolation as appropriate) to produce spatially continuous variation in values.<span class=\"Apple-converted-space\">  </span>In either case, the corners of the value grid are exactly aligned with the corners of the spatial boundaries of the subpopulation as specified by <span class=\"s1\">setSpatialBounds()</span>, and the value grid is then stretched across the spatial extent of the subpopulation in such a manner as to produce equal spacing between the values along each dimension.<span class=\"Apple-converted-space\">  </span>The setting of <span class=\"s1\">interpolation</span> only affects how values between these grid points are calculated: by nearest-neighbor, or by linear interpolation.<span class=\"Apple-converted-space\">  </span>Interpolation of spatial maps with periodic boundaries is not handled specially; to ensure that the edges of a periodic spatial map join smoothly, simply ensure that the grid values at the edges of the map are identical, since they will be coincident after periodic wrapping.<span class=\"Apple-converted-space\">  </span>Note that cubic/bicubic interpolation is generally smoother than linear/bilinear interpolation, with fewer artifacts, but it is substantially slower to calculate; use the <span class=\"s1\">interpolate()</span> method of <span class=\"s1\">SpatialMap</span> to precalculate an interpolated map using cubic/bucubic interpolation.</p>\n<p class=\"p6\">The <span class=\"s1\">valueRange</span> and <span class=\"s1\">colors</span> parameters travel together; either both are unspecified, or both are specified.<span class=\"Apple-converted-space\">  </span>They control how map values will be transformed into colors, by SLiMgui and by the <span class=\"s1\">mapColor()</span> method.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">valueRange</span> parameter establishes the color-mapped range of spatial map values, as a vector of length two specifying a minimum and maximum; this does not need to match the actual range of values in the map.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">colors</span> parameter then establishes the corresponding colors for values within the interval defined by <span class=\"s1\">valueRange</span>: values less than or equal to <span class=\"s1\">valueRange[0]</span> will map to <span class=\"s1\">colors[0]</span>, values greater than or equal to <span class=\"s1\">valueRange[1]</span> will map to the last <span class=\"s1\">colors</span> value, and intermediate values will shade continuously through the specified vector of colors, with interpolation between adjacent colors to produce a continuous spectrum.<span class=\"Apple-converted-space\">  </span>This is much simpler than it sounds in this description; see the recipes for an illustration of its use.</p>\n<p class=\"p6\">Note that at present, SLiMgui will only display spatial maps of spatiality <span class=\"s1\">\"x\"</span>, <span class=\"s1\">\"y\"</span>, or <span class=\"s1\">\"xy\"</span>; the color-mapping parameters will simply be ignored by SLiMgui for other spatiality values (even if the spatiality is a superset of these values; SLiMgui will not attempt to display an <span class=\"s1\">\"xyz\"</span> spatial map, for example, since it has no way to choose which 2D slice through the <i>xyz</i> space it ought to display).<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">mapColor()</span> method will return translated color strings for any spatial map, however, even if SLiMgui is unable to display the spatial map.<span class=\"Apple-converted-space\">  </span>If there are multiple spatial maps that SLiMgui is capable of displaying, it choose one for display by default, but other maps may be selected from the action menu on the individuals view (by clicking on the button with the gear icon).</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)deviatePositions(No&lt;Individual&gt; individuals, string$ boundary, numeric$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">Deviates the spatial positions of the individuals supplied in <span class=\"s1\">individuals</span>, using the provided boundary condition and dispersal kernel.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">individuals</span> is <span class=\"s1\">NULL</span>, the positions of all individuals in the target subpopulation are deviated.<span class=\"Apple-converted-space\">  </span>This method is essentially a more efficient shorthand for getting the spatial positions of <span class=\"s1\">individuals</span> from the <span class=\"s1\">spatialPosition</span> property, deviating those positions with <span class=\"s1\">pointDeviated()</span>, and setting the deviated positions back into <span class=\"s1\">individuals</span> with the <span class=\"s1\">setSpatialPosition()</span> method.</p>\n<p class=\"p6\">The boundary condition <span class=\"s1\">boundary</span> must be one of <span class=\"s1\">\"none\"</span>, <span class=\"s1\">\"periodic\"</span>, <span class=\"s1\">\"reflecting\"</span>, <span class=\"s1\">\"stopping\"</span>, <span class=\"s1\">\"reprising\"</span>, or <span class=\"s1\">\"absorbing\"</span>, and the spatial kernel type <span class=\"s1\">functionType</span> must be one of <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"l\"</span>, <span class=\"s1\">\"e\"</span>, <span class=\"s1\">\"n\"</span>, or <span class=\"s1\">\"t\"</span>, with the ellipsis parameters <span class=\"s1\">...</span> supplying kernel configuration parameters appropriate for that kernel type; see <span class=\"s1\">pointDeviated()</span> for further details.<span class=\"Apple-converted-space\">  </span>As with <span class=\"s1\">pointDeviated()</span>, the ellipsis parameters that follow <span class=\"s1\">functionType</span> may each, independently, be either a singleton or a vector of length equal to <span class=\"s1\">n</span>.<span class=\"Apple-converted-space\">  </span>This allows each individual’s position to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.<span class=\"Apple-converted-space\">  </span>(However, other parameters such as <span class=\"s1\">boundary</span>, <span class=\"s1\">maxDistance</span>, and <span class=\"s1\">functionType</span> must be the same for all of the points, in the present design.)</p>\n<p class=\"p6\">The returned vector contains individuals that did not survive the dispersal process.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">\"absorbing\"</span> boundaries, this will contain the individuals that attempted to disperse beyond the spatial bounds, and in most cases the caller will then kill those individuals – probably by passing them to <span class=\"s1\">killIndividuals()</span>, but perhaps by setting their <span class=\"s1\">fitnessScaling</span> to zero.<span class=\"Apple-converted-space\">  </span>(The positions of the individuals in the returned vector will be the out-of-bounds positions that were drawn for them; rather than killing those individuals, the caller could conceivably handle them in some other way.)<span class=\"Apple-converted-space\">  </span>For all other boundary conditions, the returned vector of individuals will be empty and may be ignored by the caller.</p>\n<p class=\"p5\">– (object&lt;Individual&gt;)deviatePositionsWithMap(No&lt;Individual&gt; individuals, string$ boundary, so&lt;SpatialMap&gt;$ map, numeric$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">Deviates the spatial positions of the individuals supplied in <span class=\"s1\">individuals</span>, using the provided boundary condition and dispersal kernel.<span class=\"Apple-converted-space\">  </span>The supplied <span class=\"s1\">SpatialMap</span> object (or a <span class=\"s1\">string</span> specifying a map by name), <span class=\"s1\">map</span>, is used (in addition to the spatial bounds of the subpopulation) to define which positions are considered to be “out of bounds”, as described below.<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">individuals</span> is <span class=\"s1\">NULL</span>, the positions of all individuals in the target subpopulation are deviated.<span class=\"Apple-converted-space\">  </span>This method is essentially an extension of the <span class=\"s1\">deviatePositions()</span> method, adding bounds-checking using <span class=\"s1\">map</span>; however, there are some differences as described below.</p>\n<p class=\"p6\">The boundary condition <span class=\"s1\">boundary</span> must be either <span class=\"s1\">\"reprising\"</span> or <span class=\"s1\">\"absorbing\"</span>.<span class=\"Apple-converted-space\">  </span>In the simple case where map values are either <span class=\"s1\">0</span> (bad habitat) or <span class=\"s1\">1</span> (good habitat), <span class=\"s1\">\"reprising\"</span> means a new location is drawn conditional on falling within the good habitat; <span class=\"s1\">\"absorbing\"</span> means individuals falling outside the good habitat are “absorbed” (killed, probably).<span class=\"Apple-converted-space\">  </span>The details are discussed below, when <span class=\"s1\">map</span> is discussed.<span class=\"Apple-converted-space\">  </span>Note that the boundary condition <span class=\"s1\">\"none\"</span> is not supported because points must be within the boundaries of the spatial map to be checked.<span class=\"Apple-converted-space\">  </span>Reflecting and stopping boundaries are not supported because, with the spatial map, if a drawn point is considered out-of-bounds it is not clear where the “edge” is, and therefore reflecting off of the edge, or stopping at the edge, are not well-defined.<span class=\"Apple-converted-space\">  </span>Finally, <span class=\"s1\">\"periodic\"</span> is not supported because it does not specify any action to be taken when a drawn point is considered to be “out of bounds” according to the spatial map; instead, this method automatically applies any periodic boundaries that have been defined and then, using the resulting point, checks the subpopulation’s spatial bounds and the spatial map, and applies reprising or absorbing boundaries as requested if the point is “out of bounds”.</p>\n<p class=\"p6\">The spatial map defined by <span class=\"s1\">map</span> must be configured in a specific way.<span class=\"Apple-converted-space\">  </span>First of all, it must be defined in, or added to, the target subpopulation (and thus, by implication, it must match the spatial bounds of the subpopulation.<span class=\"Apple-converted-space\">  </span>Second, its spatiality must be equal to the dimensionality of the species; in an <span class=\"s1\">\"xy\"</span> species, for example, the map must also be <span class=\"s1\">\"xy\"</span>.<span class=\"Apple-converted-space\">  </span>Third, the values in the spatial map must represent “habitability”, in the following sense.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">map</span> at a given drawn point is obtained, symbolized here by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>Next, <span class=\"s1\">x</span> is clamped to the range [<span class=\"s1\">0</span>, <span class=\"s1\">1</span>]; values less than <span class=\"s1\">0</span> become <span class=\"s1\">0</span>, values greater than <span class=\"s1\">1</span> become <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>The resulting <span class=\"s1\">x</span> value is then interpreted as the probability that the point is considered “within bounds” (as far as the spatial map is concerned; points that are outside the subpopulation’s spatial bounds are <i>always</i> considered “out of bounds”).<span class=\"Apple-converted-space\">  </span>If <span class=\"s1\">boundary</span> is <span class=\"s1\">\"reprising\"</span>, <span class=\"s1\">1-x</span> is thus the probability that the point will be redrawn; if boundary is <span class=\"s1\">\"absorbing\"</span>, <span class=\"s1\">1-x</span> is thus the probability that the individual will be considered “absorbed”, as discussed below.<span class=\"Apple-converted-space\">  </span>In this manner, the concept of “out of bounds” is treated as a probability by this method, rather than a binary state.</p>\n<p class=\"p6\">The spatial kernel type <span class=\"s1\">functionType</span> must be one of <span class=\"s1\">\"f\"</span>, <span class=\"s1\">\"l\"</span>, <span class=\"s1\">\"e\"</span>, <span class=\"s1\">\"n\"</span>, or <span class=\"s1\">\"t\"</span>, with the ellipsis parameters <span class=\"s1\">...</span> supplying kernel configuration parameters appropriate for that kernel type; see <span class=\"s1\">pointDeviated()</span> for further details.<span class=\"Apple-converted-space\">  </span>As with <span class=\"s1\">pointDeviated()</span>, the ellipsis parameters that follow <span class=\"s1\">functionType</span> may each, independently, be either a singleton or a vector of length equal to <span class=\"s1\">n</span>.<span class=\"Apple-converted-space\">  </span>This allows each individual’s position to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.<span class=\"Apple-converted-space\">  </span>(However, other parameters such as <span class=\"s1\">boundary</span>, <span class=\"s1\">maxDistance</span>, and <span class=\"s1\">functionType</span> must be the same for all of the points, in the present design.)</p>\n<p class=\"p6\">The returned vector contains individuals that did not survive the dispersal process.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">\"absorbing\"</span> boundaries, this will contain the individuals that attempted to disperse to a point considered “out of bounds” as described above, and in most cases the caller will then kill those individuals – probably by passing them to <span class=\"s1\">killIndividuals()</span>, but perhaps by setting their <span class=\"s1\">fitnessScaling</span> to zero.<span class=\"Apple-converted-space\">  </span>(The positions of the individuals in the returned vector will be the out-of-bounds positions that were drawn for them; rather than killing those individuals, the caller could conceivably handle them in some other way.)<span class=\"Apple-converted-space\">  </span>For all other boundary conditions, the returned vector of individuals will be empty and may be ignored by the caller.</p>\n<p class=\"p6\">See also the <span class=\"s1\">SpatialMap</span> methods <span class=\"s1\">sampleNearbyPoint()</span> and <span class=\"s1\">sampleImprovedNearbyPoint()</span>, which are in some ways conceptually similar to this method.</p>\n<p class=\"p5\">– (object&lt;Haplosome&gt;)haplosomesForChromosomes([Niso&lt;Chromosome&gt; chromosomes = NULL], [Ni$ index = NULL], [logical$ includeNulls = T])</p>\n<p class=\"p6\">Returns a vector containing the subpopulation’s haplosomes that correspond to the chromosomes passed in <span class=\"s1\">chromosomes</span> (following the order of the <span class=\"s1\">chromosomes</span> property of <span class=\"s1\">Individual</span>).<span class=\"Apple-converted-space\">  </span>Chromosomes can be specified by id (<span class=\"s1\">integer</span>), by symbol (<span class=\"s1\">string</span>) or by the <span class=\"s1\">Chromosome</span> objects themselves; if <span class=\"s1\">NULL</span> is passed (the default), all chromosomes defined for the species are used, in the order in which they were defined.</p>\n<p class=\"p6\">This method is equivalent to calling <span class=\"s1\">haplosomesForChromosomes(chromosomes, index, includeNulls)</span> on <span class=\"s1\">subpop.individuals</span>, where <span class=\"s1\">subpop</span> is the target subpopulation.<span class=\"Apple-converted-space\">  </span>It therefore appends together the specified haplosomes from each individual in the subpopulation to form a single vector.<span class=\"Apple-converted-space\">  </span>See the documentation for the <span class=\"s1\">Individual</span> method <span class=\"s1\">haplosomesForChromosomes()</span> for further details, such as on the meaning of the <span class=\"s1\">index</span> and <span class=\"s1\">includeNulls</span> parameters.</p>\n<p class=\"p5\">– (void)outputMSSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [Ns$ filePath = NULL], [logical$ append = F], [logical$ filterMonomorphic = F], [Niso&lt;Chromosome&gt;$ chromosome = NULL])</p>\n<p class=\"p6\">Output a random sample from the subpopulation in MS format.<span class=\"Apple-converted-space\">  </span>Positions in the output will span the interval [0,1].<span class=\"Apple-converted-space\">  </span>A sample of non-null haplosomes (not entire individuals, note) of size <span class=\"s1\">sampleSize</span> from the subpopulation will be output.<span class=\"Apple-converted-space\">  </span>The sample may be done either with or without replacement, as specified by <span class=\"s1\">replace</span>; the default is to sample with replacement.<span class=\"Apple-converted-space\">  </span>A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">requestedSex</span>; passing <span class=\"s1\">\"*\"</span>, the default, indicates that haplosomes from individuals should be selected randomly, without respect to sex.<span class=\"Apple-converted-space\">  </span>If the sampling options provided by this method are not adequate, see the <span class=\"s1\">outputHaplosomesToMS()</span> method of <span class=\"s1\">Haplosome</span> for a more flexible low-level option.</p>\n<p class=\"p6\">If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.</p>\n<p class=\"p6\">If <span class=\"s1\">filterMonomorphic</span> is <span class=\"s1\">F</span> (the default), all mutations that are present in the sample will be included in the output.<span class=\"Apple-converted-space\">  </span>This means that some mutations may be included that are actually monomorphic within the sample (i.e., that exist in <i>every</i> sampled haplosome, and are thus apparently fixed).<span class=\"Apple-converted-space\">  </span>These may be filtered out with <span class=\"s1\">filterMonomorphic = T</span> if desired; note that this option means that some mutations that do exist in the sampled haplosomes might not be included in the output, simply because they exist in every sampled haplosome.</p>\n<p class=\"p6\">The <span class=\"s1\">chromosome</span> parameter identifies the chromosome for which the sample of haplosomes should be taken.<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s1\">NULL</span> may be used only in single-chromosome models where the choice of chromosome is unambiguous.<span class=\"Apple-converted-space\">  </span>In multi-chromosome models, chromosome must be non-<span class=\"s1\">NULL</span>; it must specify the chromosome by id (<span class=\"s1\">integer</span>), by symbol (<span class=\"s1\">string</span>) or by the <span class=\"s1\">Chromosome</span> object itself.</p>\n<p class=\"p6\">See <span class=\"s1\">outputSample()</span> and <span class=\"s1\">outputVCFSample()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\">– (void)outputSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [Ns$ filePath = NULL], [logical$ append = F], [Niso&lt;Chromosome&gt;$ chromosome = NULL])</p>\n<p class=\"p6\">Output a random sample from the subpopulation in SLiM’s native format.<span class=\"Apple-converted-space\">  </span>A sample of non-null haplosomes (not entire individuals, note) of size <span class=\"s1\">sampleSize</span> from the subpopulation will be output.<span class=\"Apple-converted-space\">  </span>The sample may be done either with or without replacement, as specified by <span class=\"s1\">replace</span>; the default is to sample with replacement.<span class=\"Apple-converted-space\">  </span>A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">requestedSex</span>; passing <span class=\"s1\">\"*\"</span>, the default, indicates that haplosomes from individuals should be selected randomly, without respect to sex.<span class=\"Apple-converted-space\">  </span>If the sampling options provided by this method are not adequate, see the <span class=\"s1\">outputHaplosomes()</span> method of <span class=\"s1\">Haplosome</span> for a more flexible low-level option.</p>\n<p class=\"p6\">If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.</p>\n<p class=\"p6\">The <span class=\"s1\">chromosome</span> parameter identifies the chromosome for which the sample of haplosomes should be taken.<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s1\">NULL</span> may be used only in single-chromosome models where the choice of chromosome is unambiguous.<span class=\"Apple-converted-space\">  </span>In multi-chromosome models, chromosome must be non-<span class=\"s1\">NULL</span>; it must specify the chromosome by id (<span class=\"s1\">integer</span>), by symbol (<span class=\"s1\">string</span>) or by the <span class=\"s1\">Chromosome</span> object itself.</p>\n<p class=\"p6\">See <span class=\"s1\">outputMSSample()</span> and <span class=\"s1\">outputVCFSample()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\">– (void)outputVCFSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [logical$ outputMultiallelics = T], [Ns$ filePath = NULL], [logical$ append = F], [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T], [logical$ groupAsIndividuals = T], [Niso&lt;Chromosome&gt;$ chromosome = NULL])</p>\n<p class=\"p6\">Output a random sample from the subpopulation in VCF format.<span class=\"Apple-converted-space\">  </span>A sample of individuals (not haplosomes, note – unlike the <span class=\"s1\">outputSample()</span> and <span class=\"s1\">outputMSSample()</span> methods) of size <span class=\"s1\">sampleSize</span> from the subpopulation will be output.<span class=\"Apple-converted-space\">  </span>The sample may be done either with or without replacement, as specified by <span class=\"s1\">replace</span>; the default is to sample with replacement.<span class=\"Apple-converted-space\">  </span>A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing <span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span> for <span class=\"s1\">requestedSex</span>; passing <span class=\"s1\">\"*\"</span>, the default, indicates that individuals should be selected randomly, without respect to sex.<span class=\"Apple-converted-space\">  </span>If the sampling options provided by this method are not adequate, see the <span class=\"s1\">outputHaplosomesToVCF()</span> method of <span class=\"s1\">Haplosome</span> for a more flexible low-level option.</p>\n<p class=\"p6\">If the optional parameter <span class=\"s1\">filePath</span> is <span class=\"s1\">NULL</span> (the default), output will be sent to Eidos’s output stream.<span class=\"Apple-converted-space\">  </span>Otherwise, output will be sent to the filesystem path specified by <span class=\"s1\">filePath</span>, overwriting that file if <span class=\"s1\">append</span> if <span class=\"s1\">F</span>, or appending to the end of it if <span class=\"s1\">append</span> is <span class=\"s1\">T</span>.</p>\n<p class=\"p10\"><span class=\"s11\">The parameters </span>outputMultiallelics<span class=\"s11\">, </span>simplifyNucleotides<span class=\"s11\">, </span>outputNonnucleotides<span class=\"s11\">, and </span>groupAsIndividuals<span class=\"s11\"> affect the format of the output produced.</span></p>\n<p class=\"p6\">The <span class=\"s1\">chromosome</span> parameter identifies the chromosome for which haplosomes of the sampled individuals should be output.<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s1\">NULL</span> may be used only in single-chromosome models where the choice of chromosome is unambiguous.<span class=\"Apple-converted-space\">  </span>In multi-chromosome models, chromosome must be non-<span class=\"s1\">NULL</span>; it must specify the chromosome by id (<span class=\"s1\">integer</span>), by symbol (<span class=\"s1\">string</span>) or by the <span class=\"s1\">Chromosome</span> object itself.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">symbol</span> property of the chromosome will be output in the <span class=\"s1\">CHROM</span> field of call lines in the VCF output.</p>\n<p class=\"p6\">See <span class=\"s1\">outputMSSample()</span> and <span class=\"s1\">outputSample()</span> for other output formats.<span class=\"Apple-converted-space\">  </span>Output is generally done in a <span class=\"s1\">late()</span> event, so that the output reflects the state of the simulation at the end of a tick.</p>\n<p class=\"p5\">– (float)pointDeviated(integer$ n, float point, string$ boundary, numeric$ maxDistance, string$ functionType, ...)</p>\n<p class=\"p6\">Returns a vector containing <span class=\"s1\">n</span> points that are derived from <span class=\"s1\">point</span> by adding a deviation drawn from a dispersal kernel (specified by <span class=\"s1\">maxDistance</span>, <span class=\"s1\">functionType</span>, and the ellipsis parameters <span class=\"s1\">...</span>, as detailed below) and then applying a boundary condition specified by <span class=\"s1\">boundary</span>.<span class=\"Apple-converted-space\">  </span>This method therefore performs the steps of a simple dispersal algorithm in a single vectorized call.<span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">deviatePositions()</span> for an even more efficient approach.</p>\n<p class=\"p6\">The parameter <span class=\"s1\">point</span> may contain a single point which is deviated and bounded <span class=\"s1\">n</span> independent times, or may contain <span class=\"s1\">n</span> points each of which is deviated and bounded.<span class=\"Apple-converted-space\">  </span>In any case, each point in <span class=\"s1\">point</span> should match the dimensionality of the model – one element in a 1D model, two elements in a 2D model, or three elements in a 3D model.<span class=\"Apple-converted-space\">  </span>This method should not be called in a non-spatial model.</p>\n<p class=\"p6\">The dispersal kernel is specified similarly to other kernel-based methods, such as <span class=\"s1\">setInteractionFunction()</span> and <span class=\"s1\">smooth()</span>.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">pointDeviated()</span>, <span class=\"s1\">functionType</span> may be <span class=\"s1\">\"f\"</span> with no ellipsis arguments <span class=\"s1\">...</span> to use a flat kernel out to <span class=\"s1\">maxDistance</span>; <span class=\"s1\">\"l\"</span> with no ellipsis arguments for a kernel that decreases linearly from the center to zero at <span class=\"s1\">maxDistance</span>; <span class=\"s1\">\"e\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> lambda (rate) parameter for a negative exponential function; <span class=\"s1\">\"n\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> sigma (standard deviation) parameter for a Gaussian function; or <span class=\"s1\">\"t\"</span>, in which case the ellipsis should supply a <span class=\"s1\">numeric$</span> degrees of freedom and a <span class=\"s1\">numeric$</span> scale parameter for a <i>t</i>-distribution function.<span class=\"Apple-converted-space\">  </span>The Cauchy (<span class=\"s1\">\"c\"</span>) kernel is not supported by <span class=\"s1\">pointDeviated()</span> since it is not well-behaved for this purpose, and the Student’s <i>t</i> (<span class=\"s1\">\"t\"</span>) kernel is not allowed in 3D models at present simply because it hasn’t been implemented.<span class=\"Apple-converted-space\">  </span>See the <span class=\"s1\">InteractionType</span> class documentation for more detailed discussion of the available kernel types and their parameters and probability distribution functions.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">pointDeviated()</span>, the ellipsis parameters that follow <span class=\"s1\">functionType</span> may each, independently, be either a singleton or a vector of length equal to <span class=\"s1\">n</span>.<span class=\"Apple-converted-space\">  </span>This allows each point to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.<span class=\"Apple-converted-space\">  </span>(However, other parameters such as <span class=\"s1\">boundary</span>, <span class=\"s1\">maxDistance</span>, and <span class=\"s1\">functionType</span> must be the same for all of the points, in the present design.)</p>\n<p class=\"p6\">The random points returned from this method are drawn from the probability distribution that is radially symmetric and has density proportional to the kernel – in other words, at distance <i>r</i> the density is proportional to the kernel type referred to by <span class=\"s1\">functionType</span>.<span class=\"Apple-converted-space\">  </span>(Said another way, the shape of the <i>cross-section</i> through the probability density function is given by the kernel.)<span class=\"Apple-converted-space\">  </span>For instance, the value of the type <span class=\"s1\">\"e\"</span> (exponential) kernel with rate <i>a</i> at <i>r</i> is proportional to exp(−<i>ar</i>), and so in 2D, the probability density that this method with kernel type <span class=\"s1\">\"e\"</span> draws from has density proportional to p(<i>x</i>, <i>y</i>) = exp(−<i>a</i> sqrt(<i>x</i><span class=\"s18\"><sup>2</sup></span> + <i>y</i><span class=\"s18\"><sup>2</sup></span>)), since <i>r</i> = sqrt(x<span class=\"s18\"><sup>2</sup></span> + y<span class=\"s18\"><sup>2</sup></span>) is the distance.<span class=\"Apple-converted-space\">  </span>Note that the <i>distribution of the distance</i> is not given by the kernel except in 1D: in the type <span class=\"s1\">\"e\"</span> example, the distribution of the distance in 1D is exponential, while in 2D it has density proportional to <i>r</i> exp(−<i>ar</i>) (i.e., Gamma with shape parameter 1).<span class=\"Apple-converted-space\">  </span>For another example, the value of the type <span class=\"s1\">\"n\"</span> (Normal) kernel at <i>r</i> with standard deviation 1 is proportional to exp(−<i>r</i><span class=\"s18\"><sup>2</sup></span> / 2), and so the density is proportional to p(<i>x</i>, <i>y</i>) = exp(−(<i>x</i><span class=\"s18\"><sup>2</sup></span> + <i>y</i><span class=\"s18\"><sup>2</sup></span>) / 2).<span class=\"Apple-converted-space\">  </span>This is the standard bivariate Normal, and equivalent to drawing independent Normals for the <i>x</i> and <i>y</i> directions; however, the Normal is the <i>only</i> distribution for which independent draws along each axis will result in a radially symmetric distribution.<span class=\"Apple-converted-space\">  </span>The distribution of the distance in 2D with type <span class=\"s1\">\"n\"</span> is proportional to <i>r</i> exp(−<i>r</i><span class=\"s18\"><sup>2</sup></span> / 2), i.e., Rayleigh.</p>\n<p class=\"p6\">The boundary condition must be one of <span class=\"s1\">\"none\"</span>, <span class=\"s1\">\"periodic\"</span>, <span class=\"s1\">\"reflecting\"</span>, <span class=\"s1\">\"stopping\"</span>, or <span class=\"s1\">\"reprising\"</span>.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">\"none\"</span>, no boundary condition is enforced; the deviated points are simply returned as is.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">\"periodic\"</span>, <span class=\"s1\">\"reflecting\"</span>, and <span class=\"s1\">\"stopping\"</span>, the boundary condition is enforced just as it is by the <span class=\"s1\">pointPeriodic()</span>, <span class=\"s1\">pointReflected()</span>, and <span class=\"s1\">pointStopped()</span> methods; see their documentation for further details.<span class=\"Apple-converted-space\">  </span>For <span class=\"s1\">\"reprising\"</span>, if the deviated point is out of bounds a new deviated point will be chosen, based upon the same original point, until a point inside bounds is obtained.<span class=\"Apple-converted-space\">  </span>Note that absorbing boundaries (for which being out-of-bounds is lethal) would need to be implemented in script; this method cannot enforce them.<span class=\"Apple-converted-space\">  </span>(Note, however, that the <span class=\"s1\">deviatePositions()</span> method of <span class=\"s1\">Subpopulation</span> can enforce absorbing boundaries.)</p>\n<p class=\"p6\">Note that for the typical usage case, in which <span class=\"s1\">point</span> comes from the <span class=\"s1\">spatialPosition</span> property for a vector of individuals, and the result is then set back onto the same vector of individuals using the <span class=\"s1\">setSpatialPosition()</span> method, the <span class=\"s1\">deviatePositions()</span> method provides an even more efficient alternative.</p>\n<p class=\"p3\">– (logical)pointInBounds(float point)</p>\n<p class=\"p6\"><span class=\"s3\">Returns </span><span class=\"s4\">T</span><span class=\"s3\"> if </span><span class=\"s4\">point</span><span class=\"s3\"> is inside the spatial boundaries of the subpopulation, </span><span class=\"s4\">F</span><span class=\"s3\"> otherwise.<span class=\"Apple-converted-space\">  </span>For example, for a simulation with </span><span class=\"s4\">\"xy\"</span><span class=\"s3\"> dimensionality, if </span><span class=\"s4\">point</span><span class=\"s3\"> contains exactly two values constituting an (<i>x</i>,<i>y</i>) point, the result will be </span><span class=\"s4\">T</span><span class=\"s3\"> if and only if </span><span class=\"s4\">((point[0]&gt;=x0) &amp; (point[0]&lt;=x1) &amp; (point[1]&gt;=y0) &amp; (point[1]&lt;=y1))</span><span class=\"s3\"> given spatial bounds </span><span class=\"s4\">(x0, y0, x1, y1)</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This method is useful for implementing absorbing or reprising boundary conditions.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space has been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The length of </span><span class=\"s4\">point</span><span class=\"s3\"> must be an exact multiple of the dimensionality of the simulation; in other words, </span><span class=\"s4\">point</span><span class=\"s3\"> may contain values comprising more than one point.<span class=\"Apple-converted-space\">  </span>In this case, a </span><span class=\"s4\">logical</span><span class=\"s3\"> vector will be returned in which each element is </span><span class=\"s4\">T</span><span class=\"s3\"> if the corresponding point in </span><span class=\"s4\">point</span><span class=\"s3\"> is inside the spatial boundaries of the subpopulation, </span><span class=\"s4\">F</span><span class=\"s3\"> otherwise.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (float)pointPeriodic(float point)</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns a revised version of </span><span class=\"s4\">point</span><span class=\"s3\"> that has been brought inside the periodic spatial boundaries of the subpopulation (as specified by the </span><span class=\"s4\">periodicity</span><span class=\"s3\"> parameter of </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">) by wrapping around periodic spatial boundaries.<span class=\"Apple-converted-space\">  </span>In brief, if a coordinate of </span><span class=\"s4\">point</span><span class=\"s3\"> lies beyond a periodic spatial boundary, that coordinate is wrapped around the boundary, so that it lies inside the spatial extent by the same magnitude that it previously lay outside, but on the opposite side of the space; in effect, the two edges of the periodic spatial boundary are seamlessly joined.<span class=\"Apple-converted-space\">  </span>This is done iteratively until all coordinates lie inside the subpopulation’s periodic boundaries.<span class=\"Apple-converted-space\">  </span>Note that non-periodic spatial boundaries are not enforced by this method; they should be enforced using </span><span class=\"s4\">pointReflected()</span><span class=\"s3\">, </span><span class=\"s4\">pointStopped()</span><span class=\"s3\">, or some other means of enforcing boundary constraints (which can be used after </span><span class=\"s4\">pointPeriodic()</span><span class=\"s3\"> to bring the remaining coordinates into bounds; coordinates already brought into bounds by </span><span class=\"s4\">pointPeriodic()</span><span class=\"s3\"> will be unaffected by those calls).<span class=\"Apple-converted-space\">  </span>This method is useful for implementing periodic boundary conditions.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space<span class=\"Apple-converted-space\">  </span>and at least one periodic spatial dimension have been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The length of </span><span class=\"s4\">point</span><span class=\"s3\"> must be an exact multiple of the dimensionality of the simulation; in other words, </span><span class=\"s4\">point</span><span class=\"s3\"> may contain values comprising more than one point.<span class=\"Apple-converted-space\">  </span>In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (float)pointReflected(float point)</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns a revised version of </span><span class=\"s4\">point</span><span class=\"s3\"> that has been brought inside the spatial boundaries of the subpopulation by reflection.<span class=\"Apple-converted-space\">  </span>In brief, if a coordinate of </span><span class=\"s4\">point</span><span class=\"s3\"> lies beyond a spatial boundary, that coordinate is reflected across the boundary, so that it lies inside the boundary by the same magnitude that it previously lay outside the boundary.<span class=\"Apple-converted-space\">  </span>This is done iteratively until all coordinates lie inside the subpopulation’s boundaries.<span class=\"Apple-converted-space\">  </span>This method is useful for implementing reflecting boundary conditions.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space has been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The length of </span><span class=\"s4\">point</span><span class=\"s3\"> must be an exact multiple of the dimensionality of the simulation; in other words, </span><span class=\"s4\">point</span><span class=\"s3\"> may contain values comprising more than one point.<span class=\"Apple-converted-space\">  </span>In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (float)pointStopped(float point)</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns a revised version of </span><span class=\"s4\">point</span><span class=\"s3\"> that has been brought inside the spatial boundaries of the subpopulation by clamping.<span class=\"Apple-converted-space\">  </span>In brief, if a coordinate of </span><span class=\"s4\">point</span><span class=\"s3\"> lies beyond a spatial boundary, that coordinate is set to exactly the position of the boundary, so that it lies on the edge of the spatial boundary.<span class=\"Apple-converted-space\">  </span>This method is useful for implementing stopping boundary conditions.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space has been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span></p>\n<p class=\"p6\"><span class=\"s3\">The length of </span><span class=\"s4\">point</span><span class=\"s3\"> must be an exact multiple of the dimensionality of the simulation; in other words, </span><span class=\"s4\">point</span><span class=\"s3\"> may contain values comprising more than one point.<span class=\"Apple-converted-space\">  </span>In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (float)pointUniform([integer$ n = 1])</span></p>\n<p class=\"p6\"><span class=\"s3\">Returns a new point (or points, for </span><span class=\"s4\">n</span><span class=\"s3\"> &gt; 1) generated from uniform draws for each coordinate, within the spatial boundaries of the subpopulation.<span class=\"Apple-converted-space\">  </span>The returned vector will contain </span><span class=\"s4\">n</span><span class=\"s3\"> points, each comprised of a number of coordinates equal to the dimensionality of the simulation, so it will be of total length </span><span class=\"s4\">n</span><span class=\"s3\">*dimensionality.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space has been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.</span><span class=\"Apple-converted-space\">  </span>See <span class=\"s1\">pointUniformWithMap()</span> for an extension to this method which uses a spatial map to govern the probability of a particular point being chosen.</p>\n<p class=\"p5\">– (float)pointUniformWithMap(integer$ n, so&lt;SpatialMap&gt;$ map)</p>\n<p class=\"p6\">Returns a new point (or points, for <span class=\"s1\">n</span> &gt; 1) generated from uniform draws for each coordinate, within the spatial boundaries of the subpopulation, and rejection sampled using the spatial map <span class=\"s1\">map</span> as described below.<span class=\"Apple-converted-space\">  </span>The returned vector will contain <span class=\"s1\">n</span> points, each comprised of a number of coordinates equal to the dimensionality of the simulation, so it will be of total length <span class=\"s1\">n</span>*dimensionality.<span class=\"Apple-converted-space\">  </span>This may only be called in simulations for which continuous space has been enabled with <span class=\"s1\">initializeSLiMOptions()</span>.</p>\n<p class=\"p6\">The spatial map defined by <span class=\"s1\">map</span> must be configured in a specific way.<span class=\"Apple-converted-space\">  </span>First of all, it must be defined in, or added to, the target subpopulation (and thus, by implication, it must match the spatial bounds of the subpopulation, and its spatiality must be compatible with the subpopulation’s dimensionality, as discussed in <span class=\"s1\">defineSpatialMap()</span> and/or <span class=\"s1\">addSpatialMap()</span>).<span class=\"Apple-converted-space\">  </span>Second, the values in the spatial map must represent “habitability”, in the following sense.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">map</span> at a given drawn point is obtained, symbolized here by <span class=\"s1\">x</span>.<span class=\"Apple-converted-space\">  </span>Next, <span class=\"s1\">x</span> is clamped to the range [<span class=\"s1\">0</span>, <span class=\"s1\">1</span>]; values less than <span class=\"s1\">0</span> become <span class=\"s1\">0</span>, values greater than <span class=\"s1\">1</span> become <span class=\"s1\">1</span>.<span class=\"Apple-converted-space\">  </span>The resulting <span class=\"s1\">x</span> value is then interpreted as the probability that the point is considered “within bounds” (as far as the spatial map is concerned; points that are outside the subpopulation’s spatial bounds are <i>always</i> considered “out of bounds”).<span class=\"Apple-converted-space\">  </span>Given this, <span class=\"s1\">1-x</span> is thus the probability that the point will be redrawn because it fell out of bounds.<span class=\"Apple-converted-space\">  </span>Each point will be redrawn repeatedly until a point considered “within bounds” is obtained.</p>\n<p class=\"p5\">– (void)removeSpatialMap(so&lt;SpatialMap&gt;$ map)</p>\n<p class=\"p6\">Removes the <span class=\"s1\">SpatialMap</span> object specified by <span class=\"s1\">map</span> from the subpopulation.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">map</span> may be either a <span class=\"s1\">SpatialMap</span> object, or a <span class=\"s1\">string</span> name for spatial map.<span class=\"Apple-converted-space\">  </span>The map must have been added to the subpopulation with <span class=\"s1\">addSpatialMap()</span>; if it has not been, an error results.<span class=\"Apple-converted-space\">  </span>Removing spatial maps that are no longer in use is optional in most cases.<span class=\"Apple-converted-space\">  </span>It is generally a good idea because it might decrease SLiM’s memory footprint; also, it avoids an error if the subpopulation’s spatial bounds are changed (see <span class=\"s1\">setSpatialBounds()</span>).</p>\n<p class=\"p3\">– (void)removeSubpopulation(void)</p>\n<p class=\"p6\"><span class=\"s3\">Removes this subpopulation from the model.<span class=\"Apple-converted-space\">  </span>The subpopulation is immediately removed from the list of active subpopulations, and the symbol representing the subpopulation is undefined.<span class=\"Apple-converted-space\">  </span>The subpopulation object itself remains unchanged until children are next generated (at which point it is deallocated), but it is no longer part of the simulation and should not be used.</span></p>\n<p class=\"p6\"><span class=\"s3\">Note that this method is only for use in nonWF models, in which there is a distinction between a subpopulation being empty and a subpopulation being removed from the simulation; an empty subpopulation may be re-colonized by migrants, whereas as a removed subpopulation no longer exists at all.<span class=\"Apple-converted-space\">  </span>WF models do not make this distinction; when a subpopulation is empty it is automatically removed.<span class=\"Apple-converted-space\">  </span>WF models should therefore call </span><span class=\"s4\">setSubpopulationSize(0)</span><span class=\"s3\"> instead of this method; </span><span class=\"s4\">setSubpopulationSize()</span><span class=\"s3\"> is the standard way for WF models to change the subpopulation size, including to a size of </span><span class=\"s4\">0</span><span class=\"s3\">.</span></p>\n<p class=\"p5\"><span class=\"s5\">– </span><span class=\"s3\">(object&lt;Individual&gt;)sampleIndividuals(integer$ size, [logical$ replace = F], [No&lt;Individual&gt;$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL]</span>, [Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL]<span class=\"s3\">)</span></p>\n<p class=\"p6\">Returns a vector of individuals, of size less than or equal to parameter <span class=\"s1\">size</span>, sampled from the individuals in the target subpopulation.<span class=\"Apple-converted-space\">  </span>Sampling is done without replacement if <span class=\"s1\">replace</span> is <span class=\"s1\">F</span> (the default), or with replacement if <span class=\"s1\">replace</span> is <span class=\"s1\">T</span>.<span class=\"Apple-converted-space\">  </span>The remaining parameters specify constraints upon the pool of individuals that will be considered candidates for the sampling.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">exclude</span>, if non-<span class=\"s1\">NULL</span>, may specify a specific individual that should not be considered a candidate (typically the focal individual in some operation).<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">sex</span>, if non-<span class=\"s1\">NULL</span>, may specify a sex (<span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span>) for the individuals to be drawn, in sexual models.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">tag</span>, if non-<span class=\"s1\">NULL</span>, may specify a <span class=\"s1\">tag</span> property value for the individuals to be drawn.<span class=\"Apple-converted-space\">  </span>Parameters <span class=\"s1\">minAge</span> and <span class=\"s1\">maxAge</span>, if non-<span class=\"s1\">NULL</span>, may specify a minimum or maximum age for the individuals to be drawn, in nonWF models.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">migrant</span>, if non-<span class=\"s1\">NULL</span>, may specify a required value for the <span class=\"s1\">migrant</span> property of the individuals to be drawn (so <span class=\"s1\">T</span> will require that individuals be migrants, <span class=\"s1\">F</span> will require that they not be).<span class=\"Apple-converted-space\">  </span>Finally, parameters <span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span>, if non-<span class=\"s1\">NULL</span>, may specify a required value (<span class=\"s1\">T</span> or <span class=\"s1\">F</span>) for the corresponding properties (<span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span>) of the individuals to be drawn.<span class=\"Apple-converted-space\">  </span>Note that if any <span class=\"s1\">tag</span>/<span class=\"s1\">tagL</span> parameter is specified as non-<span class=\"s1\">NULL</span>, that <span class=\"s1\">tag</span>/<span class=\"s1\">tagL</span> property must have a defined value for every individual in the subpopulation, otherwise an error may result (although this requirement will not necessarily be checked comprehensively by this method in every invocation).<span class=\"Apple-converted-space\">  </span>If the candidate pool is smaller than the requested sample size, all eligible candidates will be returned (in randomized order); the result will be a zero-length vector if no eligible candidates exist (unlike <span class=\"s1\">sample()</span>).</p>\n<p class=\"p6\"><span class=\"s3\">This method is similar to getting the </span><span class=\"s4\">individuals</span><span class=\"s3\"> property of the subpopulation, using operator </span><span class=\"s4\">[]</span><span class=\"s3\"> to select only individuals with the desired properties, and then using </span><span class=\"s4\">sample()</span><span class=\"s3\"> to sample from that candidate pool.<span class=\"Apple-converted-space\">  </span>However, besides being much simpler than the equivalent Eidos code, it is also much faster, and it does not fail if less than the full sample size is available.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">subsetIndividuals()</span><span class=\"s3\"> for a similar method that returns a full subset, rather than a sample.</span></p>\n<p class=\"p3\">– (void)setCloningRate(numeric rate)</p>\n<p class=\"p4\">Set the cloning rate of this subpopulation.<span class=\"Apple-converted-space\">  </span>The rate is changed to <span class=\"s1\">rate</span>, which should be between 0.0 and 1.0, inclusive (see the SLiM manual for further details).<span class=\"Apple-converted-space\">  </span>Clonal reproduction can be enabled in both non-sexual (i.e. hermaphroditic) and sexual simulations.<span class=\"Apple-converted-space\">  </span>In non-sexual simulations, <span class=\"s1\">rate</span> must be a singleton value representing the overall clonal reproduction rate for the subpopulation.<span class=\"Apple-converted-space\">  </span>In sexual simulations, <span class=\"s1\">rate</span> may be either a singleton (specifying the clonal reproduction rate for both sexes) or a vector containing two numeric values (the female and male cloning rates specified separately, at indices <span class=\"s1\">0</span> and <span class=\"s1\">1</span> respectively).<span class=\"Apple-converted-space\">  </span>During mating and offspring generation, the probability that any given offspring individual will be generated by cloning – by asexual reproduction without gametes or meiosis – will be equal to the cloning rate (for its sex, in sexual simulations) set in the parental (not the offspring!) subpopulation.</p>\n<p class=\"p3\">– (void)setMigrationRates(io&lt;Subpopulation&gt; sourceSubpops, numeric rates)</p>\n<p class=\"p6\">Set the migration rates to this subpopulation from the subpopulations in <span class=\"s1\">sourceSubpops</span> to the corresponding rates specified in <span class=\"s1\">rates</span>; in other words, <span class=\"s1\">rates</span> gives the expected fractions of the children in this subpopulation that will subsequently be generated from parents in the subpopulations <span class=\"s1\">sourceSubpops</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">rates</span> parameter may be a singleton value, in which case that rate is used for all subpopulations in <span class=\"s1\">sourceSubpops</span>.<span class=\"Apple-converted-space\">  </span>This method will only set the migration fractions from the subpopulations given; migration rates from other subpopulations will be left unchanged (explicitly set a zero rate to turn off migration from a given subpopulation).<span class=\"Apple-converted-space\">  </span>The type of <span class=\"s1\">sourceSubpops</span> may be either <span class=\"s1\">integer</span>, specifying subpopulations by identifier, or <span class=\"s1\">object</span>, specifying subpopulations directly.</p>\n<p class=\"p6\">In general it is illegal to try to set the migration rate into a subpopulation from itself; that rate is, by definition, equal to the remainder after all migration from other subpopulations.<span class=\"Apple-converted-space\">  </span>As a special case for convenience, it is legal to set a rate of <span class=\"s1\">0.0</span> for all subpopulations in the species, including the target subpopulation.<span class=\"Apple-converted-space\">  </span>For example, <span class=\"s1\">subpops.setMigrationRates(allSubpops, 0.0)</span> will turn off all migration into the subpopulations in <span class=\"s1\">subpops</span>.<span class=\"Apple-converted-space\">  </span>The given rate of <span class=\"s1\">0.0</span> from a subpop into itself is simply ignored, for this specific case only.</p>\n<p class=\"p3\">– (void)setSelfingRate(numeric$ rate)</p>\n<p class=\"p4\">Set the selfing rate of this subpopulation.<span class=\"Apple-converted-space\">  </span>The rate is changed to <span class=\"s1\">rate</span>, which should be between 0.0 and 1.0, inclusive (see the SLiM manual for further details).<span class=\"Apple-converted-space\">  </span>Selfing can only be enabled in non-sexual (i.e. hermaphroditic) simulations.<span class=\"Apple-converted-space\">  </span>During mating and offspring generation, the probability that any given offspring individual will be generated by selfing – by self-fertilization via gametes produced by meiosis by a single parent – will be equal to the selfing rate set in the parental (not the offspring!) subpopulation.</p>\n<p class=\"p3\">– (void)setSexRatio(float$ sexRatio)</p>\n<p class=\"p4\">Set the sex ratio of this subpopulation to <span class=\"s1\">sexRatio</span>.<span class=\"Apple-converted-space\">  </span>As defined in SLiM, this is actually the fraction of the subpopulation that is male; in other words, the M:(M+F) ratio.<span class=\"Apple-converted-space\">  </span>This will take effect when children are next generated; it does not change the current subpopulation state.<span class=\"Apple-converted-space\">  </span>Unlike the selfing rate, the cloning rate, and migration rates, the sex ratio is deterministic: SLiM will generate offspring that exactly satisfy the requested sex ratio (within integer roundoff limits).</p>\n<p class=\"p3\">– (void)setSpatialBounds(numeric bounds)</p>\n<p class=\"p6\"><span class=\"s3\">Set the spatial boundaries of the subpopulation to </span><span class=\"s4\">bounds</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>This method may be called only for simulations in which continuous space has been enabled with </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>The length of </span><span class=\"s4\">bounds</span><span class=\"s3\"> must be double the spatial dimensionality, so that it supplies both minimum and maximum values for each coordinate.<span class=\"Apple-converted-space\">  </span>More specifically, for a dimensionality of </span><span class=\"s4\">\"x\"</span><span class=\"s3\">, </span><span class=\"s4\">bounds</span><span class=\"s3\"> should supply </span><span class=\"s4\">(x0, x1)</span><span class=\"s3\"> values; for dimensionality </span><span class=\"s4\">\"xy\"</span><span class=\"s3\"> it should supply </span><span class=\"s4\">(x0, y0, x1, y1)</span><span class=\"s3\"> values; and for dimensionality </span><span class=\"s4\">\"xyz\"</span><span class=\"s3\"> it should supply </span><span class=\"s4\">(x0, y0, z0, x1, y1, z1)</span><span class=\"s3\"> (in that order).<span class=\"Apple-converted-space\">  </span>These boundaries will be used by SLiMgui to calibrate the display of the subpopulation, and will be used by methods such as </span><span class=\"s4\">pointInBounds()</span><span class=\"s3\">, </span><span class=\"s4\">pointReflected()</span><span class=\"s3\">, </span><span class=\"s4\">pointStopped()</span><span class=\"s3\">, and </span><span class=\"s4\">pointUniform()</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>The default spatial boundaries for all subpopulations span the interval </span><span class=\"s4\">[0,1]</span><span class=\"s3\"> in each dimension.<span class=\"Apple-converted-space\">  </span>Spatial dimensions that are periodic (as established with the </span><span class=\"s4\">periodicity</span><span class=\"s3\"> parameter to </span><span class=\"s4\">initializeSLiMOptions()</span><span class=\"s3\">) must have a minimum coordinate value of </span><span class=\"s4\">0.0</span><span class=\"s3\"> (a restriction that allows the handling of periodicity to be somewhat more efficient).<span class=\"Apple-converted-space\">  </span>The current spatial bounds for the subpopulation may be obtained through the </span><span class=\"s4\">spatialBounds</span><span class=\"s3\"> property.</span></p>\n<p class=\"p6\">The spatial bounds of a subpopulation are shared with any <span class=\"s1\">SpatialMap</span> objects added to the subpopulation.<span class=\"Apple-converted-space\">  </span>For this reason, once a spatial map has been added to a subpopulation, the spatial bounds of the subpopulation can no longer be changed (because it would stretch or shrink the associated spatial map, which does not seem to make physical sense).<span class=\"Apple-converted-space\">  </span>The bounds for a subpopulation should therefore be configured before any spatial maps are added to it.<span class=\"Apple-converted-space\">  </span>If those bounds do need to change subsequently, any associated spatial maps must first be removed with <span class=\"s1\">removeSpatialMap()</span>, to ensure model consistency.</p>\n<p class=\"p3\">– (void)setSubpopulationSize(integer$ size)</p>\n<p class=\"p4\">Set the size of this subpopulation to <span class=\"s1\">size</span> individuals (see the SLiM manual for further details).<span class=\"Apple-converted-space\">  </span>This will take effect when children are next generated; it does not change the current subpopulation state.<span class=\"Apple-converted-space\">  </span>Setting a subpopulation to a size of 0 does have some immediate effects that serve to disconnect it from the simulation: the subpopulation is removed from the list of active subpopulations, the subpopulation is removed as a source of migration for all other subpopulations, and the symbol representing the subpopulation is undefined.<span class=\"Apple-converted-space\">  </span>In this case, the subpopulation itself remains unchanged until children are next generated (at which point it is deallocated), but it is no longer part of the simulation and should not be used.</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(string)spatialMapColor(string$ name, numeric value)</p>\n<p class=\"p6\"><b>This method has been deprecated, and may be removed in a future release of SLiM.</b><span class=\"Apple-converted-space\">  </span>In SLiM 4.1 and later, use the <span class=\"s1\">SpatialMap</span> method <span class=\"s1\">mapColor()</span> instead, and see that method’s documentation.<span class=\"Apple-converted-space\">  </span>(This method differs only in taking a <span class=\"s1\">name</span> parameter, which is used to look up the spatial map from those that have been added to the subpopulation.)</p>\n<p class=\"p5\">– (object&lt;Image&gt;$)spatialMapImage(string$ name, [Ni$ width = NULL], [Ni$ height = NULL], [logical$ centers = F], [logical$ color = T])</p>\n<p class=\"p6\"><b>This method has been deprecated, and may be removed in a future release of SLiM.</b><span class=\"Apple-converted-space\">  </span>In SLiM 4.1 and later, use the <span class=\"s1\">SpatialMap</span> method <span class=\"s1\">mapImage()</span> instead, and see that method’s documentation.<span class=\"Apple-converted-space\">  </span>(This method differs only in taking a <span class=\"s1\">name</span> parameter, which is used to look up the spatial map from those that have been added to the subpopulation.)</p>\n<p class=\"p3\">–<span class=\"s9\"> </span>(float)spatialMapValue(so&lt;SpatialMap&gt;$ map, float point)</p>\n<p class=\"p6\">Looks up the spatial map specified by <span class=\"s1\">map</span>, and uses its mapping machinery (as defined by the <span class=\"s1\">gridSize</span>, <span class=\"s1\">values</span>, and <span class=\"s1\">interpolate</span> parameters to <span class=\"s1\">defineSpatialMap()</span>) to translate the coordinates of <span class=\"s1\">point</span> into a corresponding map value.<span class=\"Apple-converted-space\">  </span>The parameter <span class=\"s1\">map</span> may specify the map either as a <span class=\"s1\">SpatialMap</span> object, or by its <span class=\"s1\">string</span> name; in either case, the map must have been added to the subpopulation.<span class=\"Apple-converted-space\">  </span>The length of <span class=\"s1\">point</span> must be equal to the spatiality of the spatial map; in other words, for a spatial map with spatiality <span class=\"s1\">\"xz\"</span>, <span class=\"s1\">point</span> must be of length <span class=\"s1\">2</span>, specifying the <i>x</i> and <i>z</i> coordinates of the point to be evaluated.<span class=\"Apple-converted-space\">  </span>Interpolation will automatically be used if it was enabled for the spatial map.<span class=\"Apple-converted-space\">  </span>Point coordinates are clamped into the range defined by the spatial boundaries, even if the spatial boundaries are periodic; use <span class=\"s1\">pointPeriodic()</span> to wrap the point coordinates first if desired.<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s1\">defineSpatialMap()</span> for information regarding the details of value mapping.</p>\n<p class=\"p6\">Beginning in SLiM 3.3, <span class=\"s1\">point</span> may contain more than one point to be looked up.<span class=\"Apple-converted-space\">  </span>In this case, the length of <span class=\"s1\">point</span> must be an exact multiple of the spatiality of the spatial map; for a spatial map with spatiality <span class=\"s1\">\"xz\"</span>, for example, the length of <span class=\"s1\">point</span> must be an exact multiple of <span class=\"s1\">2</span>, and successive pairs of elements from point (elements <span class=\"s1\">0</span> and <span class=\"s1\">1</span>, then elements <span class=\"s1\">2</span> and <span class=\"s1\">3</span>, etc.) will be taken as the <i>x</i> and <i>z</i> coordinates of the points to be evaluated.<span class=\"Apple-converted-space\">  </span>This allows <span class=\"s1\">spatialMapValue()</span> to be used in a vectorized fashion.</p>\n<p class=\"p6\">The <span class=\"s1\">mapValue()</span> method of <span class=\"s1\">SpatialMap</span> provides the same functionality directly on the <span class=\"s1\">SpatialMap</span> class; <span class=\"s1\">spatialMapValue()</span> is provided on <span class=\"s1\">Subpopulation</span> partly for backward compatibility, but also for convenience in some usage cases.</p>\n<p class=\"p5\"><span class=\"s5\">– </span><span class=\"s3\">(object&lt;Individual&gt;)subsetIndividuals([No&lt;Individual&gt;$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL]</span>, [Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL]<span class=\"s3\">)</span></p>\n<p class=\"p6\">Returns a vector of individuals subset from the individuals in the target subpopulation.<span class=\"Apple-converted-space\">  </span>The parameters specify constraints upon the subset of individuals that will be returned.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">exclude</span>, if non-<span class=\"s1\">NULL</span>, may specify a specific individual that should not be included (typically the focal individual in some operation).<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">sex</span>, if non-<span class=\"s1\">NULL</span>, may specify a sex (<span class=\"s1\">\"M\"</span> or <span class=\"s1\">\"F\"</span>) for the individuals to be returned, in sexual models.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">tag</span>, if non-<span class=\"s1\">NULL</span>, may specify a <span class=\"s1\">tag</span> property value for the individuals to be returned.<span class=\"Apple-converted-space\">  </span>Parameters <span class=\"s1\">minAge</span> and <span class=\"s1\">maxAge</span>, if non-<span class=\"s1\">NULL</span>, may specify a minimum or maximum age for the individuals to be returned, in nonWF models.<span class=\"Apple-converted-space\">  </span>Parameter <span class=\"s1\">migrant</span>, if non-<span class=\"s1\">NULL</span>, may specify a required value for the <span class=\"s1\">migrant</span> property of the individuals to be returned (so <span class=\"s1\">T</span> will require that individuals be migrants, <span class=\"s1\">F</span> will require that they not be).<span class=\"Apple-converted-space\">  </span>Finally, parameters <span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span>, if non-<span class=\"s1\">NULL</span>, may specify a required value (<span class=\"s1\">T</span> or <span class=\"s1\">F</span>) for the corresponding properties (<span class=\"s1\">tagL0</span>, <span class=\"s1\">tagL1</span>, <span class=\"s1\">tagL2</span>, <span class=\"s1\">tagL3</span>, and <span class=\"s1\">tagL4</span>) of the individuals to be returned.<span class=\"Apple-converted-space\">  </span>Note that if any <span class=\"s1\">tag</span>/<span class=\"s1\">tagL</span> parameter is specified as non-<span class=\"s1\">NULL</span>, that <span class=\"s1\">tag</span>/<span class=\"s1\">tagL</span> property must have a defined value for every individual in the subpopulation, otherwise an error may result (although this requirement will not necessarily be checked comprehensively by this method in every invocation).</p>\n<p class=\"p6\"><span class=\"s3\">This method is shorthand for getting the </span><span class=\"s4\">individuals</span><span class=\"s3\"> property of the subpopulation, and then using operator </span><span class=\"s4\">[]</span><span class=\"s3\"> to select only individuals with the desired properties; besides being much simpler than the equivalent Eidos code, it is also much faster.<span class=\"Apple-converted-space\">  </span>See </span><span class=\"s4\">sampleIndividuals()</span><span class=\"s3\"> for a similar method that returns a sample taken from a chosen subset of individuals.</span></p>\n<p class=\"p5\"><span class=\"s3\">– (void)takeMigrants(object&lt;Individual&gt; migrants)</span></p>\n<p class=\"p6\"><span class=\"s3\">Immediately moves the individuals in </span><span class=\"s4\">migrants</span><span class=\"s3\"> to the target subpopulation (removing them from their previous subpopulation).<span class=\"Apple-converted-space\">  </span>Individuals in </span><span class=\"s4\">migrants</span><span class=\"s3\"> that are already in the target subpopulation are unaffected.<span class=\"Apple-converted-space\">  </span>Note that the indices and order of individuals and haplosomes in both the target and source subpopulations will change unpredictably as a side effect of this method.</span></p>\n<p class=\"p6\"><span class=\"s3\">Note that this method is only for use in nonWF models, in which migration is managed manually by the model script.<span class=\"Apple-converted-space\">  </span>In WF models, migration is managed automatically by the SLiM core based upon the migration rates set for each subpopulation with </span><span class=\"s4\">setMigrationRates()</span><span class=\"s3\">.</span></p>\n<p class=\"p1\"><b>5.18<span class=\"Apple-converted-space\">  </span>Class Substitution</b></p>\n<p class=\"p2\"><i>5.18.1<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Substitution</i></span><i> properties</i></p>\n<p class=\"p5\">chromosome =&gt; (object&lt;Chromosome&gt;$)</p>\n<p class=\"p6\">The <span class=\"s1\">Chromosome</span> object with which the mutation is associated.</p>\n<p class=\"p3\">id =&gt; (integer$)</p>\n<p class=\"p4\">The identifier for this mutation.<span class=\"Apple-converted-space\">  </span>Each mutation created during a run receives an immutable identifier that will be unique across the duration of the run, and that identifier is carried over to the <span class=\"s1\">Substitution</span> object when the mutation fixes.</p>\n<p class=\"p3\">fixationTick =&gt; (integer$)</p>\n<p class=\"p4\">The tick in which this mutation fixed.</p>\n<p class=\"p3\">mutationType =&gt; (object&lt;MutationType&gt;$)</p>\n<p class=\"p4\">The <span class=\"s1\">MutationType</span> from which this mutation was drawn.</p>\n<p class=\"p5\"><span class=\"s3\">nucleotide =&gt; (string$)</span></p>\n<p class=\"p6\"><span class=\"s3\">A </span><span class=\"s4\">string</span><span class=\"s3\"> representing the nucleotide associated with this mutation; this will be </span><span class=\"s4\">\"A\"</span><span class=\"s3\">, </span><span class=\"s4\">\"C\"</span><span class=\"s3\">, </span><span class=\"s4\">\"G\"</span><span class=\"s3\">, or </span><span class=\"s4\">\"T\"</span><span class=\"s3\">.<span class=\"Apple-converted-space\">  </span>If the mutation is not nucleotide-based, this property is unavailable.</span></p>\n<p class=\"p5\"><span class=\"s3\">nucleotideValue =&gt; (integer$)</span></p>\n<p class=\"p6\"><span class=\"s3\">An </span><span class=\"s4\">integer</span><span class=\"s3\"> representing the nucleotide associated with this mutation; this will be </span><span class=\"s4\">0</span><span class=\"s3\"> (A), </span><span class=\"s4\">1</span><span class=\"s3\"> (C), </span><span class=\"s4\">2</span><span class=\"s3\"> (G), or </span><span class=\"s4\">3</span><span class=\"s3\"> (T).<span class=\"Apple-converted-space\">  </span>If the mutation is not nucleotide-based, this property is unavailable.</span></p>\n<p class=\"p3\">originTick =&gt; (integer$)</p>\n<p class=\"p4\">The tick in which this mutation arose.</p>\n<p class=\"p3\">position =&gt; (integer$)</p>\n<p class=\"p4\">The position in the chromosome of this mutation.</p>\n<p class=\"p3\">selectionCoeff =&gt; (float$)</p>\n<p class=\"p4\">The selection coefficient of the mutation, drawn from the distribution of fitness effects of its <span class=\"s1\">MutationType</span><span class=\"s2\">.</span></p>\n<p class=\"p3\">subpopID &lt;–&gt; (integer$)</p>\n<p class=\"p4\">The identifier of the subpopulation in which this mutation arose.<span class=\"Apple-converted-space\">  </span>This value is carried over from the <span class=\"s1\">Mutation</span> object directly; if a “tag” value was used in the <span class=\"s1\">Mutation</span> object, that value will carry over to the corresponding <span class=\"s1\">Substitution</span> object.<span class=\"Apple-converted-space\">  </span>The <span class=\"s1\">subpopID</span> in <span class=\"s1\">Substitution</span> is a read-write property to allow it to be used as a “tag” in the same way, if the origin subpopulation identifier is not needed.</p>\n<p class=\"p3\">tag &lt;–&gt; (integer$)</p>\n<p class=\"p4\">A user-defined <span class=\"s1\">integer</span> value.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s1\">tag</span> is carried over automatically from the original <span class=\"s1\">Mutation</span> object.<span class=\"Apple-converted-space\">  </span>Apart from that, the value of <span class=\"s1\">tag</span> is not used by SLiM; it is free for you to use.</p>\n<p class=\"p2\"><i>5.18.2<span class=\"Apple-converted-space\">  </span></i><span class=\"s1\"><i>Substitution</i></span><i> methods</i></p>\n<p class=\"p15\"><br></p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help/SLiMHelpFunctions.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n  <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">\n  <title></title>\n  <meta name=\"Generator\" content=\"Cocoa HTML Writer\">\n  <meta name=\"CocoaVersion\" content=\"2487.7\">\n  <style type=\"text/css\">\n    p.p1 {margin: 18.0px 0.0px 3.0px 0.0px; font: 11.0px Optima}\n    p.p2 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo}\n    p.p3 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #000000}\n    p.p4 {margin: 9.0px 0.0px 3.0px 36.0px; text-indent: -22.3px; font: 9.0px Menlo; color: #000000}\n    p.p5 {margin: 0.0px 0.0px 3.0px 45.4px; font: 10.0px Optima; color: #000000}\n    p.p6 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima}\n    p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Menlo; color: #000000}\n    p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Menlo}\n    p.p9 {margin: 3.0px 0.0px 3.0px 27.4px; font: 10.0px Optima; color: #969696}\n    p.p10 {margin: 0.0px 0.0px 3.0px 54.0px; font: 10.0px Optima; color: #000000}\n    p.p11 {margin: 3.0px 0.0px 3.0px 27.4px; font: 11.0px Optima; color: #000000}\n    span.s1 {font-kerning: none}\n    span.s2 {font: 9.0px Menlo; font-kerning: none}\n    span.s3 {font: 9.0px Menlo}\n    span.s4 {font: 6.7px Optima}\n    span.s5 {font-kerning: none; color: #000000}\n    span.s6 {font: 10.0px Optima; font-kerning: none}\n    span.s7 {font: 10.0px 'Times New Roman'}\n    span.s8 {color: #000000}\n    span.s9 {font: 9.0px Menlo; color: #000000}\n    span.s10 {font: 7.0px 'Apple Color Emoji'}\n    span.s11 {font: 6.7px Optima; font-kerning: none}\n    span.s12 {font: 7.3px Optima}\n    span.Apple-tab-span {white-space:pre}\n  </style>\n</head>\n<body>\n<p class=\"p1\"><b>3.1.<span class=\"Apple-converted-space\">  </span>Initialization functions</b></p>\n<p class=\"p2\">(integer$)initializeAncestralNucleotides(is sequence)</p>\n<p class=\"p3\"><span class=\"s1\">This function, which may be called only in nucleotide-based models, supplies an ancestral nucleotide sequence for the model.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s2\">sequence</span><span class=\"s1\"> parameter may be an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector providing nucleotide values (A=0, C=1, G=2, T=3), or a </span><span class=\"s2\">string</span><span class=\"s1\"> vector providing single-character nucleotides (</span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"C\"</span><span class=\"s1\">, </span><span class=\"s2\">\"G\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">), or a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> providing the sequence as one string (</span><span class=\"s2\">\"ACGT...\"</span><span class=\"s1\">), or a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> providing the filesystem path of a FASTA file which will be read in to provide the sequence (if the file contains than one sequence, the first sequence will be used).<span class=\"Apple-converted-space\">  </span>Only A/C/G/T nucleotide values may be provided; other symbols, such as those for amino acids, gaps, or nucleotides of uncertain identity, are not allowed.<span class=\"Apple-converted-space\">  </span>The two semantic meanings of </span><span class=\"s2\">sequence</span><span class=\"s1\"> that involve a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> value are distinguished heuristically; a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> that contains only the letters ACGT will be assumed to be a nucleotide sequence rather than a filename.<span class=\"Apple-converted-space\">  </span>The length of the ancestral sequence is returned.</span></p>\n<p class=\"p3\"><span class=\"s1\">A utility function, </span><span class=\"s2\">randomNucleotides()</span><span class=\"s1\">, is provided by SLiM to assist in generating simple random nucleotide sequences.</span></p>\n<p class=\"p4\">(object&lt;Chromosome&gt;$)initializeChromosome(integer$ id, [Ni$ length = NULL], [string$ type = \"A\"], [Ns$ symbol = NULL], [Ns$ name = NULL], [integer$ mutationRuns = 0])</p>\n<p class=\"p3\">Calling this function, added in SLiM 5, initiates the configuration of a chromosome in the species being initialized.<span class=\"Apple-converted-space\">  </span>The new <span class=\"s3\">Chromosome</span> object is returned, but it is still under construction and will error if used; see below for details.<span class=\"Apple-converted-space\">  </span>That chromosome is then the “focal chromosome” for subsequent genetic initialization functions – specifically, for <span class=\"s3\">initializeAncestralNucleotides()</span>, <span class=\"s3\">initializeGeneConversion()</span>, <span class=\"s3\">initializeGenomicElement()</span>, <span class=\"s3\">initializeHotspotMap()</span>, <span class=\"s3\">initializeMutationRate()</span>, and <span class=\"s3\">initializeRecombinationRate()</span>.<span class=\"Apple-converted-space\">  </span>If you wish to call <span class=\"s3\">initializeChromosome()</span> at all (which is not required), you must call it <i>before</i> calling any of those genetic initialization functions, so that the focal chromosome is created <i>before</i> being configured further; otherwise, SLiM will assume that you want a default single-chromosome model, and when <span class=\"s3\">initializeChromosome()</span> is called later (contradicting that assumption), an error will result.</p>\n<p class=\"p3\">Furthermore, there are some other initialization functions must be called before <span class=\"s3\">initializeChromosome()</span> if they are called at all – specifically, <span class=\"s3\">initializeSex()</span>, <span class=\"s3\">initializeTreeSeq()</span>, <span class=\"s3\">initializeSpecies()</span>, and <span class=\"s3\">initializeSLiMOptions()</span>.<span class=\"Apple-converted-space\">  </span>This is so that <span class=\"s3\">initializeChromosome()</span> knows the context within which the new chromosome is to be created; if these methods have not been called when <span class=\"s3\">initializeChromosome()</span> is called, the default context is assumed (non-sexual, no tree-sequence recording, single-species, non-nucleotide-based), and an error will result downstream if one of those functions is later called (indicating that those assumptions might be incorrect).</p>\n<p class=\"p3\">The parameters to <span class=\"s3\">initializeChromosome()</span> configure the chromosome created.<span class=\"Apple-converted-space\">  </span>They will be discussed out of order here, because that order of presentation will, I hope, be clearer.</p>\n<p class=\"p3\">There are three parameters that in some way identify the chromosome.<span class=\"Apple-converted-space\">  </span>First, the required <span class=\"s3\">id</span> parameter provides an <span class=\"s3\">integer</span> identifier for the chromosome, which can be used to look up the chromosome later in the simulation; it can be any non-negative <span class=\"s3\">integer</span> value, but must be unique within the species (two chromosomes in the same species cannot have the same <span class=\"s3\">id</span>).<span class=\"Apple-converted-space\">  </span>Often it is an empirical chromosome number, for convenience and clarity; if modeling human chromosome 7, for example, you might provide <span class=\"s3\">7</span>.<span class=\"Apple-converted-space\">  </span>Second, the <span class=\"s3\">symbol</span> parameter provides a <span class=\"s3\">string</span> identifier for the chromosome, which can also be used to look up the chromosome later in the simulation.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">NULL</span> (the default) is passed for <span class=\"s3\">symbol</span>, the chromosome’s default <span class=\"s3\">symbol</span> value will be the <span class=\"s3\">string</span> version of its <span class=\"s3\">id</span> (<span class=\"s3\">\"7\"</span> for an <span class=\"s3\">id</span> of <span class=\"s3\">7</span>, for example).<span class=\"Apple-converted-space\">  </span>The chromosome’s <span class=\"s3\">symbol</span> value will be used to identify the chromosome in output – in VCF output, for example, and in SLiMgui.<span class=\"Apple-converted-space\">  </span>It must be non-empty (not <span class=\"s3\">\"\"</span>), no more than five characters long, and unique within the species.<span class=\"Apple-converted-space\">  </span>Third, the <span class=\"s3\">name</span> parameter can be any <span class=\"s3\">string</span> value; if <span class=\"s3\">NULL</span> (the default) is passed, the <span class=\"s3\">name</span> value will be <span class=\"s3\">\"\"</span>.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">name</span> is not used by SLiM, and can be used in any way you wish.</p>\n<p class=\"p3\">The <span class=\"s3\">length</span> parameter sets the length, in base positions, of the chromosome, and must either be <span class=\"s3\">NULL</span>, or an <span class=\"s3\">integer</span> greater than or equal to <span class=\"s3\">1</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">length</span> is <span class=\"s3\">NULL</span>, the length of the chromosome will be calculated after all <span class=\"s3\">initialize()</span> callbacks have been called, as the maximum position referenced by the chromosome’s genomic elements, recombination map, mutation rate map, and (in nucleotide-based models) hotspot map; in other words, the chromosome will be sized to encompass all of the things it contains (which is also the behavior of the implicitly defined chromosome if <span class=\"s3\">initializeChromosome()</span> is not called).<span class=\"Apple-converted-space\">  </span>Otherwise – if <span class=\"s3\">length</span> is specified with an <span class=\"s3\">integer</span> value – the chromosome’s length will be fixed at that value, and the last valid base position in the chromosome will be <span class=\"s3\">length-1</span>.<span class=\"Apple-converted-space\">  </span>Attempting to add a genomic element or a mutation after the last position will raise an error.<span class=\"Apple-converted-space\">  </span>Similarly, the last position of the chromosome must match the last position specified for recombination, mutation, and hotspot maps for that chromosome, but not all positions on a chromosome have to actually be used in the model (i.e., not all positions must be covered by a genomic element).</p>\n<p class=\"p3\">The <span class=\"s3\">type</span> parameter specifies the type of chromosome to be created.<span class=\"Apple-converted-space\">  </span>There are numerous options, and they are somewhat complex.<span class=\"Apple-converted-space\">  </span>They are discussed in more detail in the documentation for class <span class=\"s3\">Chromosome</span>, particularly their specific patterns of inheritance; but they are briefly summarized here for quick reference.<span class=\"Apple-converted-space\">  </span>Note that “–“ below indicates a null haplosome.<span class=\"Apple-converted-space\">  </span>First of all, in hermaphroditic models <span class=\"s3\">type</span> will generally be one of:</p>\n<p class=\"p5\"><span class=\"s3\">\"A\"</span> (autosome), the default, specifying a diploid autosomal chromosome.</p>\n<p class=\"p5\"><span class=\"s3\">\"H\"</span> (haploid), specifying a haploid autosomal chromosome that recombines in biparental crosses.</p>\n<p class=\"p5\"><span class=\"s3\">\"HF\"</span> (haploid female-inherited), specifying a haploid autosomal chromosome that is inherited by both sexes from the first (female) parent in biparental crosses (also allowed in hermaphroditic models for inheritance that is always from the first parent).</p>\n<p class=\"p5\"><span class=\"s3\">\"HM\"</span> (haploid male-inherited), specifying a haploid autosomal chromosome that is inherited by both sexes from the second (male) parent in biparental crosses (also allowed in hermaphroditic models for inheritance that is always from the second parent).</p>\n<p class=\"p3\">Some sex-chromosome types are supported only in sexual models:</p>\n<p class=\"p5\"><span class=\"s3\">\"X\"</span> (X), specifying an X chromosome that is diploid (XX) in females, haploid (X–) in males.</p>\n<p class=\"p5\"><span class=\"s3\">\"Y\"</span> (Y), specifying a Y chromosome that is haploid (Y) in males, absent (–) in females.</p>\n<p class=\"p5\"><span class=\"s3\">\"Z\"</span> (Z), specifying a Z chromosome that is diploid (ZZ) in males, haploid (–Z) in females.</p>\n<p class=\"p5\"><span class=\"s3\">\"W\"</span> (W), specifying a W chromosome that is haploid (W) in females, absent (–) in males.</p>\n<p class=\"p3\">And there are some haploid chromosome types that are also supported only in sexual models:</p>\n<p class=\"p5\"><span class=\"s3\">\"FL\"</span> (female line), specifying a haploid autosomal chromosome that is inherited only by females, from the female parent, and is represented by a null haplosome in males.</p>\n<p class=\"p5\"><span class=\"s3\">\"ML\"</span> (male line), specifying a haploid autosomal chromosome that is inherited only by males, from the male parent, and is represented by a null haplosome in females.</p>\n<p class=\"p3\">Finally, two additional values of <span class=\"s3\">type</span>, <span class=\"s3\">\"H-\"</span> and <span class=\"s3\">\"-Y\"</span>, are supported for backward compatibility (not intended for use in new models).<span class=\"Apple-converted-space\">  </span>They are discussed in the <span class=\"s3\">Chromosome</span> documentation.</p>\n<p class=\"p3\">The <span class=\"s3\">mutationRuns</span> parameter specifies how many mutation runs the chromosome should use.<span class=\"Apple-converted-space\">  </span>Internally, SLiM divides haplosomes into a sequence of consecutive mutation runs, allowing more efficient internal computations.<span class=\"Apple-converted-space\">  </span>The optimal mutation run length is short enough that each mutation run is relatively unlikely to be modified by mutation/recombination events when inherited, but long enough that each mutation run is likely to contain a relatively large number of mutations; these priorities are in tension, so an intermediate balance between them is generally optimal.<span class=\"Apple-converted-space\">  </span>The optimal number of mutation runs will depend on the model’s details, and may also depend upon the machine and even the compiler used to build SLiM.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s3\">mutationRuns</span> parameter is not <span class=\"s3\">0</span>, SLiM will use the value given as the number of mutation runs inside <span class=\"s3\">Haplosome</span> objects for the chromosome.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">mutationRuns</span> is <span class=\"s3\">0</span> (the default), then the behavior depends upon a parameter to the <span class=\"s3\">initializeSLiMOptions()</span> function, <span class=\"s3\">doMutationRunExperiments</span>.<span class=\"Apple-converted-space\">  </span>If that flag is <span class=\"s3\">F</span>, the behavior here is as if <span class=\"s3\">mutationRuns=1</span> had been passed: one mutation run will be used, and mutation run experiments will not be conducted.<span class=\"Apple-converted-space\">  </span>If that flag is <span class=\"s3\">T</span> (the default), then for <span class=\"s3\">mutationRuns=0</span> SLiM will conduct experiments at runtime, using different mutation run counts, to try to determine the number of mutation runs that produces the best performance.<span class=\"Apple-converted-space\">  </span>The value that SLiM’s experiments determine may not be optimal, however, and in any case there is some overhead associated with conducting these experiments; for maximal performance it can thus be beneficial to determine the true optimal value for the simulation yourself, and set it explicitly using this parameter. Specifying the number of mutation runs is an advanced technique, but in some cases it can improve performance significantly.</p>\n<p class=\"p3\">The order in which <span class=\"s3\">initializeChromosome()</span> calls are made is generally unimportant, since the chromosomes assort independently of each other anyway, but SLiM will preserve the order in which they were defined for you (for the <span class=\"s3\">chromosomes</span> property of Species, for display in SLiMgui, for writing out to VCF, and so forth).<span class=\"Apple-converted-space\">  </span>All of the above types of chromosomes can be defined any number of times; you can have any number of autosomal chromosomes, for example.<span class=\"Apple-converted-space\">  </span>In a sexual model you could even have multiple defined sex chromosomes – not in the sense of a female being XX, but in the sense of a female being X<span class=\"s4\"><sub>1</sub></span>X<span class=\"s4\"><sub>1</sub></span>X<span class=\"s4\"><sub>2</sub></span>X<span class=\"s4\"><sub>2</sub></span>, where X<span class=\"s4\"><sub>1</sub></span> and X<span class=\"s4\"><sub>2</sub></span> are two different kinds of X chromosome.<span class=\"Apple-converted-space\">  </span>Similarly, you could define both an X and a Z for a species, if you wish; each would segregate correctly according to the sex of the offspring.<span class=\"Apple-converted-space\">  </span>In sexual models in SLiM the sex of an offspring is determined randomly or given by the user in script; it is not a function of the sex chromosomes present in the individual, although the sex chromosomes present in the individual will correlate with sex.<span class=\"Apple-converted-space\">  </span>In other words, SLiM does not know and does not care what sex-determination system the species is using; the chromosomes follow the sex, rather than the sex following the chromosomes.<span class=\"Apple-converted-space\">  </span>This should allow any sex-determination system to be modeled, even if it is unusual, non-genetic, etc.</p>\n<p class=\"p3\">As stated above, the new <span class=\"s3\">Chromosome</span> object is returned by this call, but it is still under construction so most of its methods and properties will error.<span class=\"Apple-converted-space\">  </span>It will remain in this state until <span class=\"s3\">initialize()</span> callbacks have completed, and will then become active and usable.<span class=\"Apple-converted-space\">  </span>Until that point, there are only a handful of uses that are guaranteed to be allowed: storing it in a variable; remembering it with <span class=\"s3\">defineConstant()</span>; using the methods and properties of its superclasses, notably <span class=\"s3\">Dictionary</span>; setting SLiMgui display-related properties such as <span class=\"s3\">colorSubstitution</span>; getting and setting its <span class=\"s3\">tag</span> property; and accessing those of its properties that were passed to the <span class=\"s3\">initializeChromosome()</span> call, specifically <span class=\"s3\">id</span>, <span class=\"s3\">symbol</span>, <span class=\"s3\">name</span>, <span class=\"s3\">type</span>, <span class=\"s3\">length</span>, and <span class=\"s3\">lastPosition</span>.<span class=\"Apple-converted-space\">  </span>Its other properties, and all <span class=\"s3\">Chromosome</span> methods, will raise an error while in this state.<span class=\"Apple-converted-space\">  </span>This safeguard protects the new <span class=\"s3\">Chromosome</span> object from being used while still in an inconsistent state.</p>\n<p class=\"p4\"><span class=\"s1\">(void)initializeGeneConversion(numeric$ nonCrossoverFraction, numeric$ meanLength, numeric$ simpleConversionFraction, [numeric$ bias = 0], [logical$ redrawLengthsOnFailure = F])</span></p>\n<p class=\"p3\"><span class=\"s1\">Calling this function switches the recombination model from a “simple crossover” model to a “double-stranded break (DSB)” model, and configures the details of the gene conversion tracts that will therefore be modeled.<span class=\"Apple-converted-space\">  </span>The fraction of DSBs that will be modeled as non-crossover events is given by </span><span class=\"s2\">nonCrossoverFraction</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>The mean length of gene conversion tracts (whether associated with crossover or non-crossover events) is given by </span><span class=\"s2\">meanLength</span><span class=\"s1\">; the actual extent of a gene conversion tract will be the sum of two independent draws from a geometric distribution with mean </span><span class=\"s2\">meanLength/2</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>The fraction of gene conversion tracts that are modeled as “simple” is given by </span><span class=\"s2\">simpleConversionFraction</span><span class=\"s1\">; the remainder will be modeled as “complex”, involving repair of heteroduplex mismatches.<span class=\"Apple-converted-space\">  </span>Finally, the </span><span class=\"s2\">GC</span><span class=\"s1\"> bias during heteroduplex mismatch repair is given by </span><span class=\"s2\">bias</span><span class=\"s1\">, with the default of </span><span class=\"s2\">0.0</span><span class=\"s1\"> indicating no bias, </span><span class=\"s2\">1.0</span><span class=\"s1\"> indicating an absolute preference for </span><span class=\"s2\">G</span><span class=\"s1\">/</span><span class=\"s2\">C</span><span class=\"s1\"> mutations over </span><span class=\"s2\">A</span><span class=\"s1\">/</span><span class=\"s2\">T</span><span class=\"s1\"> mutations, and </span><span class=\"s2\">-1.0</span><span class=\"s1\"> indicating an absolute preference for </span><span class=\"s2\">A</span><span class=\"s1\">/</span><span class=\"s2\">T</span><span class=\"s1\"> mutations over </span><span class=\"s2\">G</span><span class=\"s1\">/</span><span class=\"s2\">C</span><span class=\"s1\"> mutations.<span class=\"Apple-converted-space\">  </span>A non-zero bias may only be set in nucleotide-based models.<span class=\"Apple-converted-space\">  </span>This function, and the way that gene conversion is modeled, fundamentally changed in SLiM 3.3.</span></p>\n<p class=\"p3\">Beginning in SLiM 4.1, the <span class=\"s3\">redrawLengthsOnFailure</span> parameter can be used to modify the internal mechanics of layout of gene conversion tracts.<span class=\"Apple-converted-space\">  </span>If it is <span class=\"s3\">F</span> (the default, and the only behavior supported before SLiM 4.1), then if an attempt to lay out gene conversion tracts fails (because the tracts overlap each other, or overlap the start or end of the chromosome), SLiM will try again by drawing new positions for the tracts – essentially shuffling the tracts around to try to find positions for them that don’t overlap.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">redrawLengthsOnFailure</span> is <span class=\"s3\">T</span>, then if an attempt to lay out gene conversion tracts fails, SLiM will try again by drawing new lengths for the tracts, as well as new positions.<span class=\"Apple-converted-space\">  </span>This makes it more likely that layout will succeed, but risks biasing the realized mean tract length downward from the requested mean length (since layout of long tracts is more likely fail due to overlap).<span class=\"Apple-converted-space\">  </span>In either case, if SLiM attempts to lay out gene conversion tracts 100 times without success, an error will result.<span class=\"Apple-converted-space\">  </span>That error indicates that the specified constraints for gene conversion are difficult to satisfy – tracts may commonly be so long that it is difficult or impossible to find an acceptable layout for them within the specified chromosome length.<span class=\"Apple-converted-space\">  </span>Setting <span class=\"s3\">redrawLengthsOnFailure</span> to <span class=\"s3\">T</span> may mitigate this problem, at the price of biasing the mean tract length downward as discussed.</p>\n<p class=\"p4\">(object&lt;GenomicElement&gt;)initializeGenomicElement(io&lt;GenomicElementType&gt; genomicElementType, [Ni start = NULL], [Ni end = NULL])</p>\n<p class=\"p3\"><span class=\"s1\">Add a genomic element to the chromosome at initialization time.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s2\">start</span><span class=\"s1\"> and </span><span class=\"s2\">end</span><span class=\"s1\"> parameters give the first and last base positions to be spanned by the new genomic element.<span class=\"Apple-converted-space\">  </span>The new element will be based upon the genomic element type identified by </span><span class=\"s2\">genomicElementType</span><span class=\"s1\">, which can be either an </span><span class=\"s2\">integer</span><span class=\"s1\">, representing the ID of the desired element type, or an </span><span class=\"s2\">object</span><span class=\"s1\"> of type </span><span class=\"s2\">GenomicElementType</span><span class=\"s1\"> specified directly.</span></p>\n<p class=\"p3\"><span class=\"s1\">Beginning in SLiM 3.3, this function is vectorized: the </span><span class=\"s2\">genomicElementType</span><span class=\"s1\">, </span><span class=\"s2\">start</span><span class=\"s1\">, and </span><span class=\"s2\">end</span><span class=\"s1\"> parameters do not have to be singletons.<span class=\"Apple-converted-space\">  </span>In particular, </span><span class=\"s2\">start</span><span class=\"s1\"> and </span><span class=\"s2\">end</span><span class=\"s1\"> may be of any length, but must be equal in length; each </span><span class=\"s2\">start</span><span class=\"s1\">/</span><span class=\"s2\">end</span><span class=\"s1\"> element pair will generate one new genomic element spanning the given base positions.<span class=\"Apple-converted-space\">  </span>In this case, </span><span class=\"s2\">genomicElementType</span><span class=\"s1\"> may still be a singleton, providing the genomic element type to be used for all of the new genomic elements, or it may be equal in length to </span><span class=\"s2\">start</span><span class=\"s1\"> and </span><span class=\"s2\">end</span><span class=\"s1\">, providing an independent genomic element type for each new element.<span class=\"Apple-converted-space\">  </span>When adding a large number of genomic elements, it will be much faster to add them in order of ascending position with a vectorized call.</span></p>\n<p class=\"p3\">Beginning in SLiM 5, passing <span class=\"s3\">NULL</span> for <span class=\"s3\">start</span> and <span class=\"s3\">end</span> is allowed by <span class=\"s3\">initializeGenomicElement()</span>, but only in one specific case: if the focal chromosome being configured was explicitly defined with <span class=\"s3\">initializeChromosome()</span>, and that focal chromosome was given an explicit length (rather than a length of <span class=\"s3\">NULL</span>).<span class=\"Apple-converted-space\">  </span>In that case, <span class=\"s3\">start</span> and <span class=\"s3\">end</span> may be <span class=\"s3\">NULL</span> (<i>both</i> of them, not just one of them), indicating that the genomic element created should span the entire length of the focal chromosome.<span class=\"Apple-converted-space\">  </span>Since <span class=\"s3\">NULL</span> is now the default value for <span class=\"s3\">start</span> and <span class=\"s3\">end</span>, this makes this common configuration very simple to set up.</p>\n<p class=\"p3\"><span class=\"s1\">The return value provides the genomic element(s) created by the call, in the order in which they were specified in the parameters to </span><span class=\"s2\">initializeGenomicElement()</span><span class=\"s1\">.</span></p>\n<p class=\"p2\">(object&lt;GenomicElementType&gt;$)initializeGenomicElementType(is$ id, io&lt;MutationType&gt; mutationTypes, numeric proportions<span class=\"s5\">, [Nf mutationMatrix = NULL]</span>)</p>\n<p class=\"p6\">Add a genomic element type at initialization time.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> must not already be used for any genomic element type in the simulation.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">mutationTypes</span> vector identifies the mutation types used by the genomic element, and the <span class=\"s3\">proportions</span> vector should be of equal length, specifying the relative proportion of mutations that will be drawn from the corresponding mutation type (proportions do not need to add up to one; they are interpreted relatively).<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> parameter may be either an <span class=\"s3\">integer</span> giving the ID of the new genomic element type, or a <span class=\"s3\">string</span> giving the name of the new genomic element type (such as <span class=\"s3\">\"g5\"</span> to specify an ID of 5).<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">mutationTypes</span> parameter may be either an <span class=\"s3\">integer</span> vector representing the IDs of the desired mutation types, or an <span class=\"s3\">object</span> vector of <span class=\"s3\">MutationType</span> elements specified directly.<span class=\"Apple-converted-space\">  </span>The global symbol for the new genomic element type is immediately available; the return value also provides the new object.</p>\n<p class=\"p3\"><span class=\"s1\">The </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> parameter is </span><span class=\"s2\">NULL</span><span class=\"s1\"> by default, and in non-nucleotide-based models it must be </span><span class=\"s2\">NULL</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>In nucleotide-based models, on the other hand, it must be non-</span><span class=\"s2\">NULL</span><span class=\"s1\">, and therefore must be supplied.<span class=\"Apple-converted-space\">  </span>In that case, </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> should take one of two standard forms.<span class=\"Apple-converted-space\">  </span>For sequence-based mutation rates that depend upon only the single nucleotide at a mutation site, </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> should be a 4×4 </span><span class=\"s2\">float</span><span class=\"s1\"> matrix, specifying mutation rates for an existing nucleotide state (rows from </span><span class=\"s2\">0</span><span class=\"s1\">–</span><span class=\"s2\">3</span><span class=\"s1\"> representing A/C/G/T) to each of the four possible derived nucleotide states (columns, with the same meaning).<span class=\"Apple-converted-space\">  </span>The mutation rates in this matrix are absolute rates, per nucleotide per gamete; they will be used by SLiM directly unless they are multiplied by a factor from the hotspot map (see </span><span class=\"s2\">initializeHotspotMap()</span><span class=\"s1\">).<span class=\"Apple-converted-space\">  </span>Rates in </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> that involve the mutation of a nucleotide to itself (</span><span class=\"s2\">A</span><span class=\"s1\"> to </span><span class=\"s2\">A</span><span class=\"s1\">, </span><span class=\"s2\">C</span><span class=\"s1\"> to </span><span class=\"s2\">C</span><span class=\"s1\">, etc.) are not used by SLiM and must be </span><span class=\"s2\">0.0</span><span class=\"s1\"> by convention.</span></p>\n<p class=\"p3\"><span class=\"s1\">It is important to note that the order of the rows and columns used in SLiM, A/C/G/T, is not a universal convention; other sources will present substitution-rate/transition-rate matrices using different conventions, and so care must be taken when importing such matrices into SLiM.</span></p>\n<p class=\"p3\"><span class=\"s1\">For sequence-based mutation rates that depend upon the trinucleotide sequence centered upon a mutation site (the adjacent bases to the left and right, in other words, as well as the mutating nucleotide itself), </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> should be a 64×4 </span><span class=\"s2\">float</span><span class=\"s1\"> matrix, specifying mutation rates for the central nucleotide of an existing trinucleotide sequence (rows from </span><span class=\"s2\">0</span><span class=\"s1\">–</span><span class=\"s2\">63</span><span class=\"s1\">, representing codons as described in the documentation for the </span><span class=\"s2\">ancestralNucleotides()</span><span class=\"s1\"> method of </span><span class=\"s2\">Chromosome</span><span class=\"s1\">) to each of the four possible derived nucleotide states (columns from </span><span class=\"s2\">0</span><span class=\"s1\">–</span><span class=\"s2\">3</span><span class=\"s1\"> for A/C/G/T as before).<span class=\"Apple-converted-space\">  </span>Note that in every case it is the central nucleotide of the trinucleotide sequence that is mutating, but rates can be specified independently based upon the nucleotides in the first and third positions as well, with this type of mutation matrix.</span></p>\n<p class=\"p3\"><span class=\"s1\">Several helper functions are defined to construct common types of mutation matrices, such as </span><span class=\"s2\">mmJukesCantor()</span><span class=\"s1\"> to create a mutation matrix for a Jukes–Cantor model.</span></p>\n<p class=\"p4\"><span class=\"s1\">(void)initializeHotspotMap(numeric multipliers, [Ni ends = NULL], [string$ sex = \"*\"])</span></p>\n<p class=\"p3\"><span class=\"s1\">In nucleotide-based models, set the mutation rate <i>multiplier</i> along the chromosome.<span class=\"Apple-converted-space\">  </span>Nucleotide-based models define sequence-based mutation rates that are set up with the </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> parameter to </span><span class=\"s2\">initializeGenomicElementType()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>If no hotspot map is specified by calling </span><span class=\"s2\">initializeHotspotMap()</span><span class=\"s1\">, a hotspot map with a multiplier of </span><span class=\"s2\">1.0</span><span class=\"s1\"> across the whole chromosome is assumed (and so the sequence-based rates are the absolute mutation rates used by SLiM).<span class=\"Apple-converted-space\">  </span>A hotspot map modifies the sequence-based rates by scaling them up in some regions, with multipliers greater than </span><span class=\"s2\">1.0</span><span class=\"s1\"> (representing mutational hot spots), and/or scaling them down in some regions, with multipliers less than </span><span class=\"s2\">1.0</span><span class=\"s1\"> (representing mutational cold spots).</span></p>\n<p class=\"p3\"><span class=\"s1\">There are two ways to call this function.<span class=\"Apple-converted-space\">  </span>If the optional </span><span class=\"s2\">ends</span><span class=\"s1\"> parameter is </span><span class=\"s2\">NULL</span><span class=\"s1\"> (the default), then </span><span class=\"s2\">multipliers</span><span class=\"s1\"> must be a singleton value that specifies a single multiplier to be used along the entire chromosome (typically </span><span class=\"s2\">1.0</span><span class=\"s1\">, but not required to be).<span class=\"Apple-converted-space\">  </span>If, on the other hand, </span><span class=\"s2\">ends</span><span class=\"s1\"> is supplied, then </span><span class=\"s2\">multipliers</span><span class=\"s1\"> and </span><span class=\"s2\">ends</span><span class=\"s1\"> must be the same length, and the values in </span><span class=\"s2\">ends</span><span class=\"s1\"> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, </span><span class=\"s2\">multipliers</span><span class=\"s1\"> and </span><span class=\"s2\">ends</span><span class=\"s1\"> taken together specify the multipliers to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in </span><span class=\"s2\">ends</span><span class=\"s1\"> should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).</span></p>\n<p class=\"p3\"><span class=\"s1\">For example, if the following call is made:</span></p>\n<p class=\"p7\"><span class=\"s6\"><span class=\"Apple-tab-span\">\t</span></span><span class=\"s1\">initializeHotspotMap(c(1.0, 1.2), c(5000, 9999));</span></p>\n<p class=\"p3\"><span class=\"s1\">then the result is that the mutation rate multiplier for bases </span><span class=\"s2\">0</span><span class=\"s1\">...</span><span class=\"s2\">5000</span><span class=\"s1\"> (inclusive) will be </span><span class=\"s2\">1.0</span><span class=\"s1\"> (and so the specified sequence-based mutation rates will be used verbatim), and the multiplier for bases </span><span class=\"s2\">5001</span><span class=\"s1\">...</span><span class=\"s2\">9999</span><span class=\"s1\"> (inclusive) will be </span><span class=\"s2\">1.2</span><span class=\"s1\"> (and so the sequence-based mutation rates will be multiplied by 1.2 within the region).</span></p>\n<p class=\"p3\"><span class=\"s1\">Note that mutations are generated by SLiM only within genomic elements, regardless of the hotspot map.<span class=\"Apple-converted-space\">  </span>In effect, the hotspot map given is intersected with the coverage area of the genomic elements defined; areas outside of any genomic element are given a multiplier of zero.<span class=\"Apple-converted-space\">  </span>There is no harm in supplying a hotspot map that specifies multipliers for areas outside of the genomic elements defined; the excess information is simply not used.</span></p>\n<p class=\"p3\"><span class=\"s1\">If the optional </span><span class=\"s2\">sex</span><span class=\"s1\"> parameter is </span><span class=\"s2\">\"*\"</span><span class=\"s1\"> (the default), then the supplied hotspot map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations </span><span class=\"s2\">sex</span><span class=\"s1\"> may be </span><span class=\"s2\">\"M\"</span><span class=\"s1\"> or </span><span class=\"s2\">\"F\"</span><span class=\"s1\"> instead, in which case the supplied hotspot map is used only for that sex (i.e., when generating a gamete from a parent of that sex).<span class=\"Apple-converted-space\">  </span>In this case, two calls must be made to </span><span class=\"s2\">initializeHotspotMap()</span><span class=\"s1\">, one for each sex, even if a multiplier of </span><span class=\"s2\">1.0</span><span class=\"s1\"> is desired for the other sex; no default hotspot map is supplied.</span></p>\n<p class=\"p2\">(object&lt;InteractionType&gt;$)initializeInteractionType(is$ id, string$ spatiality, [logical$ reciprocal = F], [numeric$ maxDistance = INF], [string$ sexSegregation = \"**\"])</p>\n<p class=\"p3\">Add an interaction type at initialization time.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> must not already be used for any interaction type in the simulation.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> parameter may be either an <span class=\"s3\">integer</span> giving the ID of the new interaction type, or a <span class=\"s3\">string</span> giving the name of the new interaction type (such as <span class=\"s3\">\"i5\"</span> to specify an ID of 5).</p>\n<p class=\"p3\">The <span class=\"s3\">spatiality</span> may be <span class=\"s3\">\"\"</span>, for non-spatial interactions (i.e., interactions that do not depend upon the distance between individuals); <span class=\"s3\">\"x\"</span>, <span class=\"s3\">\"y\"</span>, or <span class=\"s3\">\"z\"</span> for one-dimensional interactions; <span class=\"s3\">\"xy\"</span>, <span class=\"s3\">\"xz\"</span>, or <span class=\"s3\">\"yz\"</span> for two-dimensional interactions; or <span class=\"s3\">\"xyz\"</span> for three-dimensional interactions.<span class=\"Apple-converted-space\">  </span>The dimensions referenced by spatiality must be defined as spatial dimensions with <span class=\"s3\">initializeSLiMOptions()</span>; if the simulation has dimensionality <span class=\"s3\">\"xy\"</span>, for example, then interactions in the simulation may have spatiality <span class=\"s3\">\"\"</span>, <span class=\"s3\">\"x\"</span>, <span class=\"s3\">\"y\"</span>, or <span class=\"s3\">\"xy\"</span>, but may not reference spatial dimension <i>z</i> and thus may not have spatiality <span class=\"s3\">\"xz\"</span>, <span class=\"s3\">\"yz\"</span>, or <span class=\"s3\">\"xyz\"</span>.<span class=\"Apple-converted-space\">  </span>If no spatial dimensions have been configured, only non-spatial interactions may be defined.</p>\n<p class=\"p3\">The <span class=\"s3\">reciprocal</span> flag may be <span class=\"s3\">T</span>, in which case the interaction is guaranteed by the user to be <i>reciprocal</i>: whatever the interaction strength is for exerter B upon receiver A, it will be equal (in magnitude and sign) for exerter A upon receiver B.<span class=\"Apple-converted-space\">  </span>In principle, this allows the <span class=\"s3\">InteractionType</span> to reduce the amount of computation necessary by up to a factor of two (although it may or may not be used).<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">reciprocal</span> is <span class=\"s3\">F</span>, the interaction is not guaranteed to be reciprocal and each interaction will be computed independently.<span class=\"Apple-converted-space\">  </span>The built-in interaction formulas are all reciprocal, but if you implement an <span class=\"s3\">interaction()</span> callback, you must consider whether the callback you have implemented preserves reciprocality or not.<span class=\"Apple-converted-space\">  </span>For this reason, the default is <span class=\"s3\">reciprocal=F</span>, so that bugs are not inadvertently introduced by an invalid assumption of reciprocality.<span class=\"Apple-converted-space\">  </span>See below for a note regarding reciprocality in sexual simulations when using the <span class=\"s3\">sexSegregation</span> flag.</p>\n<p class=\"p3\">The <span class=\"s3\">maxDistance</span> parameter supplies the maximum distance over which interactions of this type will be evaluated; at greater distances, the interaction strength is considered to be zero (for efficiency).<span class=\"Apple-converted-space\">  </span>The default value of <span class=\"s3\">maxDistance</span>, <span class=\"s3\">INF</span> (positive infinity), indicates that there is no maximum interaction distance; note that this can make some interaction queries much less efficient, and is therefore not recommended.<span class=\"Apple-converted-space\">  </span>In SLiM 3.1 and later, a warning will be issued if a spatial interaction type is defined with no maximum distance to encourage a maximum distance to be defined.</p>\n<p class=\"p3\">The <span class=\"s3\">sexSegregation</span> parameter governs the applicability of the interaction to each sex, in sexual simulations.<span class=\"Apple-converted-space\">  </span>It does not affect distance calculations in any way; it only modifies the way in which interaction strengths are calculated.<span class=\"Apple-converted-space\">  </span>The default, <span class=\"s3\">\"**\"</span>, implies that the interaction is felt by both sexes (the first character of the <span class=\"s3\">string</span> value) and is exerted by both sexes (the second character of the <span class=\"s3\">string</span> value).<span class=\"Apple-converted-space\">  </span>Either or both characters may be <span class=\"s3\">M</span> or <span class=\"s3\">F</span> instead; for example, <span class=\"s3\">\"MM\"</span> would indicate a male-male interaction, such as male-male competition, whereas <span class=\"s3\">\"FM\"</span> would indicate an interaction influencing only female receivers that is influenced only by male exerters, such as male mating displays that influence female attraction.<span class=\"Apple-converted-space\">  </span>This parameter may be set only to <span class=\"s3\">\"**\"</span> unless sex has been enabled with <span class=\"s3\">initializeSex()</span>.<span class=\"Apple-converted-space\">  </span>Note that a value of <span class=\"s3\">sexSegregation</span> other than <span class=\"s3\">\"**\"</span> may imply some degree of non-reciprocality, but it is not necessary to specify <span class=\"s3\">reciprocal</span> to be <span class=\"s3\">F</span> for this reason; SLiM will take the sex-segregation of the interaction into account for you.<span class=\"Apple-converted-space\">  </span>The value of <span class=\"s3\">reciprocal</span> may therefore be interpreted as meaning: in those cases, if any, in which A interacts with B and B interacts with A, is the interaction strength guaranteed to be the same in both directions?<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">sexSegregation</span> parameter is shorthand for setting sex constraints on the interaction type using the <span class=\"s3\">setConstraints()</span> method; see that method for a more extensive set of constraints that may be used.</p>\n<p class=\"p3\">By default, the interaction strength is <span class=\"s3\">1.0</span> for all interactions within <span class=\"s3\">maxDistance</span>.<span class=\"Apple-converted-space\">  </span>Often it is desirable to change the interaction function using <span class=\"s3\">setInteractionFunction()</span>; modifying interaction strengths can also be achieved with <span class=\"s3\">interaction()</span> callbacks if necessary.<span class=\"Apple-converted-space\">  </span>In any case, interactions beyond <span class=\"s3\">maxDistance</span> always have a strength of <span class=\"s3\">0.0</span>, and the interaction strength of an individual with itself is always <span class=\"s3\">0.0</span>, regardless of the interaction function or callbacks.</p>\n<p class=\"p3\">The global symbol for the new interaction type is immediately available; the return value also provides the new object.<span class=\"Apple-converted-space\">  </span>Note that in multispecies models, <span class=\"s3\">initializeInteractionType()</span> must be called from a non-species-specific <span class=\"s3\">interaction()</span> callback (declared as <span class=\"s3\">species all initialize()</span>), since interactions are managed at the community level.</p>\n<p class=\"p2\">(void)initializeMutationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])</p>\n<p class=\"p3\">Set the mutation rate per base position per gamete.<span class=\"Apple-converted-space\">  </span>To be precise, this mutation rate is the expected mean number of mutations that will occur per base position per gamete; note that this is different from how the recombination rate is defined (see <span class=\"s3\">initializeRecombinationRate()</span>).<span class=\"Apple-converted-space\">  </span>The number of mutations that actually occurs at a given base position when generating an offspring haplosome is, in effect, drawn from a Poisson distribution with that expected mean (but under the hood SLiM uses a mathematically equivalent but much more efficient strategy).<span class=\"Apple-converted-space\">  </span>It is possible for this Poisson draw to indicate that two or more new mutations have arisen at the same base position, particularly when the mutation rate is very high; in this case, the new mutations will be added to the site one at a time, and as always the mutation stacking policy will be followed.</p>\n<p class=\"p3\"><span class=\"s1\">There are two ways to call this function.<span class=\"Apple-converted-space\">  </span>If the optional </span><span class=\"s2\">ends</span><span class=\"s1\"> parameter is </span><span class=\"s2\">NULL</span><span class=\"s1\"> (the default), then </span><span class=\"s2\">rates</span><span class=\"s1\"> must be a singleton value that specifies a single mutation rate to be used along the entire chromosome.<span class=\"Apple-converted-space\">  </span>If, on the other hand, </span><span class=\"s2\">ends</span><span class=\"s1\"> is supplied, then </span><span class=\"s2\">rates</span><span class=\"s1\"> and </span><span class=\"s2\">ends</span><span class=\"s1\"> must be the same length, and the values in </span><span class=\"s2\">ends</span><span class=\"s1\"> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, </span><span class=\"s2\">rates</span><span class=\"s1\"> and </span><span class=\"s2\">ends</span><span class=\"s1\"> taken together specify the mutation rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in </span><span class=\"s2\">ends</span><span class=\"s1\"> should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).</span></p>\n<p class=\"p3\"><span class=\"s1\">For example, if the following call is made:</span></p>\n<p class=\"p8\"><span class=\"s7\"><span class=\"Apple-tab-span\">\t</span></span>initializeMutationRate(c(1e-7, 2.5e-8), c(5000, 9999));</p>\n<p class=\"p3\"><span class=\"s1\">then the result is that the mutation rate for bases </span><span class=\"s2\">0</span><span class=\"s1\">...</span><span class=\"s2\">5000</span><span class=\"s1\"> (inclusive) will be </span><span class=\"s2\">1e-7</span><span class=\"s1\">, and the rate for bases </span><span class=\"s2\">5001</span><span class=\"s1\">...</span><span class=\"s2\">9999</span><span class=\"s1\"> (inclusive) will be </span><span class=\"s2\">2.5e-8</span><span class=\"s1\">.</span></p>\n<p class=\"p3\"><span class=\"s1\">Note that mutations are generated by SLiM only within genomic elements, regardless of the mutation rate map.<span class=\"Apple-converted-space\">  </span>In effect, the mutation rate map given is intersected with the coverage area of the genomic elements defined; areas outside of any genomic element are given a mutation rate of zero.<span class=\"Apple-converted-space\">  </span>There is no harm in supplying a mutation rate map that specifies rates for areas outside of the genomic elements defined; that rate information is simply not used.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s2\">overallMutationRate</span><span class=\"s1\"> family of properties on </span><span class=\"s2\">Chromosome</span><span class=\"s1\"> provide the overall mutation rate after genomic element coverage has been taken into account, so it will reflect the rate at which new mutations will actually be generated in the simulation as configured.</span></p>\n<p class=\"p3\"><span class=\"s1\">If the optional </span><span class=\"s2\">sex</span><span class=\"s1\"> parameter is </span><span class=\"s2\">\"*\"</span><span class=\"s1\"> (the default), then the supplied mutation rate map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations </span><span class=\"s2\">sex</span><span class=\"s1\"> may be </span><span class=\"s2\">\"M\"</span><span class=\"s1\"> or </span><span class=\"s2\">\"F\"</span><span class=\"s1\"> instead, in which case the supplied mutation rate map is used only for that sex (i.e., when generating a gamete from a parent of that sex).<span class=\"Apple-converted-space\">  </span>In this case, two calls must be made to </span><span class=\"s2\">initializeMutationRate()</span><span class=\"s1\">, one for each sex, even if a rate of zero is desired for the other sex; no default mutation rate map is supplied.</span></p>\n<p class=\"p3\"><span class=\"s1\">In nucleotide-based models, </span><span class=\"s2\">initializeMutationRate()</span><span class=\"s1\"> may not be called.<span class=\"Apple-converted-space\">  </span>Instead, the desired sequence-based mutation rate(s) should be expressed in the </span><span class=\"s2\">mutationMatrix</span><span class=\"s1\"> parameter to </span><span class=\"s2\">initializeGenomicElementType()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>If variation in the mutation rate along the chromosome is desired, </span><span class=\"s2\">initializeHotspotMap()</span><span class=\"s1\"> should be used.</span></p>\n<p class=\"p3\">The <span class=\"s3\">initializeMutationRateFromFile()</span> function is a useful convenience function if you wish to read the mutation rate map from a file.</p>\n<p class=\"p4\">(void)initializeMutationRateFromFile(string$ path, integer$ lastPosition, [float$ scale = 1.0e-08], [string$ sep = \"\\t\"], [string$ dec = \".\"], [string$ sex = \"*\"])</p>\n<p class=\"p3\">Set a mutation rate map from data read from the file at <span class=\"s3\">path</span>.<span class=\"Apple-converted-space\">  </span>This function is essentially a wrapper for <span class=\"s3\">initializeMutationRate()</span> that uses <span class=\"s3\">readCSV()</span> and passes the data through.<span class=\"Apple-converted-space\">  </span>The file is expected to contain two columns of data.<span class=\"Apple-converted-space\">  </span>The first column must be <span class=\"s3\">integer</span> start positions for rate map regions; the first region should start at position <span class=\"s3\">0</span> if the map’s positions are <span class=\"s3\">0</span>-based, or at position <span class=\"s3\">1</span> if the map’s positions are <span class=\"s3\">1</span>-based; in the latter case, <span class=\"s3\">1</span> will be subtracted from every position since SLiM uses <span class=\"s3\">0</span>-based positions.<span class=\"Apple-converted-space\">  </span>The second column must be <span class=\"s3\">float</span> rates, relative to the scaling factor specified in <span class=\"s3\">scale</span>; for example, if a given rate is <span class=\"s3\">1.2</span> and <span class=\"s3\">scale</span> is <span class=\"s3\">1e-8</span> (the default), the rate used will be <span class=\"s3\">1.2e-8</span>.<span class=\"Apple-converted-space\">  </span>No column header line should be present; the file should start immediately with numerical data.<span class=\"Apple-converted-space\">  </span>The expected separator between columns is a tab character by default, but may be passed in <span class=\"s3\">sep</span>; the expected decimal separator is a period by default, but may be passed in <span class=\"s3\">dec</span>.<span class=\"Apple-converted-space\">  </span>Once read, the map is converted into a rate map specified with end positions, rather than start positions, and the position given by <span class=\"s3\">lastPosition</span> is used as the end of the last rate region; it should be the last position of the chromosome.</p>\n<p class=\"p3\">See <span class=\"s3\">readCSV()</span> for further details on <span class=\"s3\">sep</span> and <span class=\"s3\">dec</span>, which are passed through to it; and see <span class=\"s3\">initializeMutationRate()</span> for details on how the rate map is validated and used, and how the <span class=\"s3\">sex</span> parameter is used.</p>\n<p class=\"p3\">This function is written in Eidos, and its source code can be viewed with <span class=\"s3\">functionSource()</span>, so you can copy and modify its code if you need to modify its functionality.</p>\n<p class=\"p2\">(object&lt;MutationType&gt;$)initializeMutationType(is$ id, numeric$ dominanceCoeff, string$ distributionType, ...)</p>\n<p class=\"p3\">Add a mutation type at initialization time.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> must not already be used for any mutation type in the simulation.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">id</span> parameter may be either an <span class=\"s3\">integer</span> giving the ID of the new mutation type, or a <span class=\"s3\">string</span> giving the name of the new mutation type (such as <span class=\"s3\">\"m5\"</span> to specify an ID of 5).<span class=\"Apple-converted-space\">  </span>The dominanceCoeff parameter supplies the dominance coefficient for the mutation type; <span class=\"s3\">0.0</span> produces no dominance, <span class=\"s3\">1.0</span> complete dominance, and values greater than <span class=\"s3\">1.0</span>, overdominance.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">distributionType</span> may be <span class=\"s3\">\"f\"</span>, in which case the ellipsis <span class=\"s3\">...</span> should supply a <span class=\"s3\">numeric$</span> fixed selection coefficient; <span class=\"s3\">\"e\"</span>, in which case the ellipsis should supply a <span class=\"s3\">numeric$</span> mean selection coefficient for an exponential distribution; <span class=\"s3\">\"g\"</span>, in which case the ellipsis should supply a <span class=\"s3\">numeric$</span> mean selection coefficient and a <span class=\"s3\">numeric$</span> alpha shape parameter for a gamma distribution; <span class=\"s3\">\"n\"</span>, in which case the ellipsis should supply a <span class=\"s3\">numeric$</span> mean selection coefficient and a <span class=\"s3\">numeric$</span> sigma (standard deviation) parameter for a normal distribution; <span class=\"s3\">\"p\"</span>, in which case the ellipsis should supply a <span class=\"s3\">numeric$</span> mean selection coefficient and a <span class=\"s3\">numeric$</span> scale parameter for a Laplace distribution; <span class=\"s3\">\"w\"</span>, in which case the ellipsis should supply a <span class=\"s3\">numeric$</span> <span class=\"s7\">λ</span> scale parameter and a <span class=\"s3\">numeric$</span> k shape parameter for a Weibull distribution; or <span class=\"s3\">\"s\"</span>, in which case the ellipsis should supply a <span class=\"s3\">string$</span> Eidos script parameter.<span class=\"Apple-converted-space\">  </span>The global symbol for the new mutation type is immediately available; the return value also provides the new object.</p>\n<p class=\"p3\"><span class=\"s1\">Note that by default in WF models, all mutations of a given mutation type will be converted into </span><span class=\"s2\">Substitution</span><span class=\"s1\"> objects when they reach fixation, for efficiency reasons.<span class=\"Apple-converted-space\">  </span>If you need to disable this conversion, to keep mutations of a given type active in the simulation even after they have fixed, you can do so by setting the </span><span class=\"s2\">convertToSubstitution</span><span class=\"s1\"> property of </span><span class=\"s2\">MutationType</span><span class=\"s1\"> to </span><span class=\"s2\">F</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>In contrast, by default in nonWF models mutations will not be converted into </span><span class=\"s2\">Substitution</span><span class=\"s1\"> objects when they reach fixation; </span><span class=\"s2\">convertToSubstitution</span><span class=\"s1\"> is </span><span class=\"s2\">F</span><span class=\"s1\"> by default in nonWF models.<span class=\"Apple-converted-space\">  </span>To enable conversion in nonWF models for neutral mutation types with no indirect fitness effects, you should therefore set </span><span class=\"s2\">convertToSubstitution</span><span class=\"s1\"> to </span><span class=\"s2\">T</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(object&lt;MutationType&gt;$)initializeMutationTypeNuc(is$ id, numeric$ dominanceCoeff, string$ distributionType, ...)</span></p>\n<p class=\"p3\"><span class=\"s1\">Add a nucleotide-based mutation type at initialization time.<span class=\"Apple-converted-space\">  </span>This function is identical to </span><span class=\"s2\">initializeMutationType()</span><span class=\"s1\"> except that the new mutation type will be nucleotide-based – in other words, mutations belonging to the new mutation type will have an associated nucleotide.<span class=\"Apple-converted-space\">  </span>This function may be called only in nucleotide-based models (as enabled by the </span><span class=\"s2\">nucleotideBased</span><span class=\"s1\"> parameter to </span><span class=\"s2\">initializeSLiMOptions()</span><span class=\"s1\">).</span></p>\n<p class=\"p3\"><span class=\"s1\">Nucleotide-based mutations always use a </span><span class=\"s2\">mutationStackGroup</span><span class=\"s1\"> of </span><span class=\"s2\">-1</span><span class=\"s1\"> and a </span><span class=\"s2\">mutationStackPolicy</span><span class=\"s1\"> of </span><span class=\"s2\">\"l\"</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>This ensures that a new nucleotide mutation always replaces any previously existing nucleotide mutation at a given position, regardless of the mutation types of the nucleotide mutations.<span class=\"Apple-converted-space\">  </span>These values are set automatically by </span><span class=\"s2\">initializeMutationTypeNuc()</span><span class=\"s1\">, and may not be changed.</span></p>\n<p class=\"p3\"><span class=\"s1\">See the documentation for </span><span class=\"s2\">initializeMutationType()</span><span class=\"s1\"> for all other discussion.</span></p>\n<p class=\"p2\">(void)initializeRecombinationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])</p>\n<p class=\"p3\">Set the recombination rate per base position per gamete.<span class=\"Apple-converted-space\">  </span>To be precise, this recombination rate is the probability that a breakpoint will occur between one base and the next base; note that this is different from how the mutation rate is defined (see <span class=\"s3\">initializeMutationRate()</span>).<span class=\"Apple-converted-space\">  </span>A recombination rate of 1 centimorgan/Mbp corresponds to a recombination rate of <span class=\"s3\">1e-8</span> in the units used by SLiM.<span class=\"Apple-converted-space\">  </span>All rates must be in the interval [<span class=\"s3\">0.0</span>, <span class=\"s3\">0.5</span>].<span class=\"Apple-converted-space\">  </span>A rate of <span class=\"s3\">0.5</span> implies complete independence between the adjacent bases, which might be used to implement unlinked loci.<span class=\"Apple-converted-space\">  </span>Whether a breakpoint occurs between two bases is then, in effect, determined by a binomial draw with a single trial and the given rate as probability (but under the hood SLiM uses a mathematically equivalent but much more efficient strategy).<span class=\"Apple-converted-space\">  </span>The recombinational process in SLiM will never generate more then one crossover between one base and the next (in one generation/haplosome), and a supplied rate of <span class=\"s3\">0.5</span> will therefore result in an actual probability of <span class=\"s3\">0.5</span> for a crossover at the relevant position.<span class=\"Apple-converted-space\">  </span>(Note that this was not true in SLiM 2.x and earlier, however; their implementation of recombination resulted in a crossover probability of about 39.3% for a rate of <span class=\"s3\">0.5</span>, due to the use of an inaccurate approximation method.<span class=\"Apple-converted-space\">  </span>Recombination rates lower than about <span class=\"s3\">0.01</span> would have been essentially exact, since the approximation error became large only as the rate approached <span class=\"s3\">0.5</span>.)</p>\n<p class=\"p3\">There are two ways to call this function.<span class=\"Apple-converted-space\">  </span>If the optional <span class=\"s3\">ends</span> parameter is <span class=\"s3\">NULL</span> (the default), then <span class=\"s3\">rates</span> must be a singleton value that specifies a single recombination rate to be used along the entire chromosome.<span class=\"Apple-converted-space\">  </span>If, on the other hand, <span class=\"s3\">ends</span> is supplied, then <span class=\"s3\">rates</span> and <span class=\"s3\">ends</span> must be the same length, and the values in <span class=\"s3\">ends</span> must be specified in ascending order.<span class=\"Apple-converted-space\">  </span>In that case, <span class=\"s3\">rates</span> and <span class=\"s3\">ends</span> taken together specify the recombination rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in <span class=\"s3\">ends</span> should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).</p>\n<p class=\"p3\">If the optional <span class=\"s3\">sex</span> parameter is <span class=\"s3\">\"*\"</span> (the default), then the supplied recombination rate map will be used for both sexes (which is the only option for hermaphroditic simulations).<span class=\"Apple-converted-space\">  </span>In sexual simulations <span class=\"s3\">sex</span> may be <span class=\"s3\">\"M\"</span> or <span class=\"s3\">\"F\"</span> instead, in which case the supplied recombination map is used only for that sex.<span class=\"Apple-converted-space\">  </span>In this case, two calls must be made to <span class=\"s3\">initializeRecombinationRate()</span>, one for each sex, even if a rate of zero is desired for the other sex; no default recombination map is supplied.</p>\n<p class=\"p3\">The <span class=\"s3\">initializeRecombinationRateFromFile()</span> function is a useful convenience function if you wish to read the recombination rate map from a file.</p>\n<p class=\"p4\">(void)initializeRecombinationRateFromFile(string$ path, integer$ lastPosition, [float$ scale = 1.0e-08], [string$ sep = \"\\t\"], [string$ dec = \".\"], [string$ sex = \"*\"])</p>\n<p class=\"p3\">Set a recombination rate map from data read from the file at <span class=\"s3\">path</span>.<span class=\"Apple-converted-space\">  </span>This function is essentially a wrapper for <span class=\"s3\">initializeRecombinationRate()</span> that uses <span class=\"s3\">readCSV()</span> and passes the data through.<span class=\"Apple-converted-space\">  </span>The file is expected to contain two columns of data.<span class=\"Apple-converted-space\">  </span>The first column must be <span class=\"s3\">integer</span> start positions for rate map regions; the first region should start at position <span class=\"s3\">0</span> if the map’s positions are <span class=\"s3\">0</span>-based, or at position <span class=\"s3\">1</span> if the map’s positions are <span class=\"s3\">1</span>-based; in the latter case, <span class=\"s3\">1</span> will be subtracted from every position since SLiM uses <span class=\"s3\">0</span>-based positions.<span class=\"Apple-converted-space\">  </span>The second column must be <span class=\"s3\">float</span> rates, relative to the scaling factor specified in <span class=\"s3\">scale</span>; for example, if a given rate is <span class=\"s3\">1.2</span> and <span class=\"s3\">scale</span> is <span class=\"s3\">1e-8</span> (the default), the rate used will be <span class=\"s3\">1.2e-8</span>.<span class=\"Apple-converted-space\">  </span>No column header line should be present; the file should start immediately with numerical data.<span class=\"Apple-converted-space\">  </span>The expected separator between columns is a tab character by default, but may be passed in <span class=\"s3\">sep</span>; the expected decimal separator is a period by default, but may be passed in <span class=\"s3\">dec</span>.<span class=\"Apple-converted-space\">  </span>Once read, the map is converted into a rate map specified with end positions, rather than start positions, and the position given by <span class=\"s3\">lastPosition</span> is used as the end of the last rate region; it should be the last position of the chromosome.</p>\n<p class=\"p3\">See <span class=\"s3\">readCSV()</span> for further details on <span class=\"s3\">sep</span> and <span class=\"s3\">dec</span>, which are passed through to it; and see <span class=\"s3\">initializeRecombinationRate()</span> for details on how the rate map is validated and used, and how the <span class=\"s3\">sex</span> parameter is used.</p>\n<p class=\"p3\">This function is written in Eidos, and its source code can be viewed with <span class=\"s3\">functionSource()</span>, so you can copy and modify its code if you need to modify its functionality.</p>\n<p class=\"p4\">(void)initializeSex([Ns$ chromosomeType = NULL])</p>\n<p class=\"p3\">Enable sex in the simulation.<span class=\"Apple-converted-space\">  </span>Beginning in SLiM 5, this method should generally be passed <span class=\"s3\">NULL</span>, simply indicating that sex should be enabled: individuals will then be male and female (rather than hermaphroditic), biparental crosses will be required to be between a female first parent and a male second parent, and selfing will not be allowed.<span class=\"Apple-converted-space\">  </span>In this new configuration style, if a sexual simulation involving sex chromosomes is desired, the new <span class=\"s3\">initializeChromosome()</span> call should be used to configure the chromosome setup for the simulation.</p>\n<p class=\"p3\">For backward compatibility, the old style of configuring a sexual simulation is still supported, however.<span class=\"Apple-converted-space\">  </span>This implicitly defines a single chromosome, without a call to <span class=\"s3\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>With this old configuration approach, the <span class=\"s3\">chromosomeType</span> parameter to <span class=\"s3\">initializeSex()</span> gives the type of chromosome that should be simulated; this should be <span class=\"s3\">\"A\"</span>, <span class=\"s3\">\"X\"</span>, or <span class=\"s3\">\"Y\"</span>, and this <span class=\"s3\">chromosomeType</span> value will be used as the symbol (<span class=\"s3\">\"A\"</span>, <span class=\"s3\">\"X\"</span>, or <span class=\"s3\">\"Y\"</span>) for the implicit chromosome.<span class=\"Apple-converted-space\">  </span>These legacy chromosome types correspond to the new chromosome types <span class=\"s3\">\"A\"</span>, <span class=\"s3\">\"X\"</span>, and <span class=\"s3\">\"-Y\"</span> respectively (note that it is <i>not</i> <span class=\"s3\">\"Y\"</span>), when using <span class=\"s3\">initializeChromosome()</span>.<span class=\"Apple-converted-space\">  </span>The implicit chromosome’s <span class=\"s3\">id</span> property is always <span class=\"s3\">1</span>.<span class=\"Apple-converted-space\">  </span>This old style of chromosome configuration is much less flexible, however, allowing only these three chromosome types, and only allowing a single chromosome to be set up.<span class=\"Apple-converted-space\">  </span>This backward compatibility mode may be removed for SLiM in the future, and should be considered deprecated; new models should call <span class=\"s3\">initializeChromosome()</span> explicitly instead.</p>\n<p class=\"p3\">There is no way to disable sex once it has been enabled; if you don’t want to have sex, don’t call this function.<span class=\"Apple-converted-space\">  </span>If you require more flexibility with mating types and reproductive strategies than SLiM’s built-in support for sex provides, do not call <span class=\"s3\">initializeSex()</span>; instead, track the sex or mating type of individuals yourself in script (with the <span class=\"s3\">tag</span> property of <span class=\"s3\">Individual</span>, for example), and manage the consequences of that in your script yourself, in terms of which individuals can mate with which, and exactly how the offspring is produced.</p>\n<p class=\"p9\"><span class=\"s8\"><b>The </b></span><span class=\"s9\"><b>xDominanceCoeff</b></span><span class=\"s8\"><b> parameter has been deprecated and removed.</b><span class=\"Apple-converted-space\">  </span>In SLiM 5 and later, use the </span><span class=\"s9\">hemizygousDominanceCoeff</span><span class=\"s8\"> property of </span><span class=\"s9\">MutationType</span><span class=\"s8\"> instead.<span class=\"Apple-converted-space\">  </span></span>If the <span class=\"s3\">chromosomeType</span> is <span class=\"s3\">\"X\"</span>, the optional <span class=\"s3\">xDominanceCoeff</span> parameter can supply the dominance coefficient used when a mutation is present in an XY male, and is thus “heterozygous” (but in a different sense than the heterozygosity of an XX female with one copy of the mutation).</p>\n<p class=\"p2\">(void)initializeSLiMModelType(string$ modelType)</p>\n<p class=\"p3\"><span class=\"s1\">Configure the type of SLiM model used for the simulation.<span class=\"Apple-converted-space\">  </span>At present, one of two model types may be selected.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s2\">modelType</span><span class=\"s1\"> is </span><span class=\"s2\">\"WF\"</span><span class=\"s1\">, SLiM will use a Wright-Fisher (WF) model; this is the model type that has always been supported by SLiM, and is the model type used if </span><span class=\"s2\">initializeSLiMModelType()</span><span class=\"s1\"> is not called.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s2\">modelType</span><span class=\"s1\"> is </span><span class=\"s2\">\"nonWF\"</span><span class=\"s1\">, SLiM will use a non-Wright-Fisher (nonWF) model instead; this is a new model type supported by SLiM 3.0 and above.</span></p>\n<p class=\"p3\"><span class=\"s1\">If </span><span class=\"s2\">initializeSLiMModelType()</span><span class=\"s1\"> is called at all then it must be called before any other initialization function, so that SLiM knows from the outset which features are enabled and which are not.</span></p>\n<p class=\"p2\">(void)initializeSLiMOptions([logical$ keepPedigrees = F], [string$ dimensionality = \"\"], [string$ periodicity = \"\"], [logical$ doMutationRunExperiments = T], [logical$ preventIncidentalSelfing = F]<span class=\"s5\">, [logical$ nucleotideBased = F], [logical$ randomizeCallbacks = T]</span><span class=\"s8\">, [logical$ checkInfiniteLoops = T]</span>)</p>\n<p class=\"p3\"><span class=\"s1\">Configure options for the simulation.<span class=\"Apple-converted-space\">  </span>If </span><span class=\"s2\">initializeSLiMOptions()</span><span class=\"s1\"> is called at all then it must be called before any other initialization function (except </span><span class=\"s2\">initializeSLiMModelType()</span><span class=\"s1\">), so that SLiM knows from the outset which optional features are enabled and which are not.</span></p>\n<p class=\"p3\">If <span class=\"s3\">keepPedigrees</span> is <span class=\"s3\">T</span>, SLiM will keep pedigree information for every individual in the simulation, tracking the identity of its parents and grandparents.<span class=\"Apple-converted-space\">  </span>This allows individuals to assess their degree of pedigree-based relatedness to other individuals (see <span class=\"s3\">Individual</span>’s <span class=\"s3\">relatedness()</span> and <span class=\"s3\">sharedParentCount()</span> methods), as well as allowing a model to find “trios” (two parents and an offspring they generated) using the pedigree properties of <span class=\"s3\">Individual</span>.<span class=\"Apple-converted-space\">  </span>As a side effect of <span class=\"s3\">keepPedigrees</span> being <span class=\"s3\">T</span>, the <span class=\"s3\">pedigreeID</span>, <span class=\"s3\">pedigreeParentIDs</span>, and <span class=\"s3\">pedigreeGrandparentIDs</span> properties of <span class=\"s3\">Individual</span> will have defined values, as will the <span class=\"s3\">haplosomePedigreeID</span> property of <span class=\"s3\">Haplosome</span>.<span class=\"Apple-converted-space\">  </span>Note that pedigree-based relatedness doesn’t necessarily correspond to genetic relatedness, due to effects such as assortment and recombination.<span class=\"Apple-converted-space\">  </span>Beginning in SLiM 3.5, <span class=\"s3\">keepPedigrees=T</span> also enables tracking of individual reproductive output, available through the <span class=\"s3\">reproductiveOutput</span> property of <span class=\"s3\">Individual</span> and the <span class=\"s3\">lifetimeReproductiveOutput</span> property of <span class=\"s3\">Subpopulation</span>.</p>\n<p class=\"p6\">If <span class=\"s3\">dimensionality</span> is not <span class=\"s3\">\"\"</span>, SLiM will enable its optional “continuous space” facility.<span class=\"Apple-converted-space\">  </span>Three values for <span class=\"s3\">dimensionality</span> are presently supported: <span class=\"s3\">\"x\"</span>, <span class=\"s3\">\"xy\"</span>, and <span class=\"s3\">\"xyz\"</span>, specifying that continuous space should be enabled for one, two, or three dimensions, respectively, using (<i>x</i>), (<i>x</i>, <i>y</i>), and (<i>x</i>, <i>y</i>, <i>z</i>) coordinates respectively.<span class=\"Apple-converted-space\">  </span>This has a number of side effects.<span class=\"Apple-converted-space\">  </span>First of all, it means that the specified properties of <span class=\"s3\">Individual</span> (<span class=\"s3\">x</span>, <span class=\"s3\">y</span>, and/or <span class=\"s3\">z</span>) will be interpreted by SLiM as spatial positions; in particular, SLiMgui will use those properties to display subpopulations spatially.<span class=\"Apple-converted-space\">  </span>Second, it allows spatial interactions to be defined, evaluated, and queried using <span class=\"s3\">initializeInteractionType()</span> and <span class=\"s3\">interaction()</span> callbacks.<span class=\"Apple-converted-space\">  </span>And third, it enables the use of any other properties and methods related to continuous space, such as setting the spatial boundaries of subpopulations, which would otherwise raise an error.</p>\n<p class=\"p3\"><span class=\"s1\">If </span><span class=\"s2\">periodicity</span><span class=\"s1\"> is not </span><span class=\"s2\">\"\"</span><span class=\"s1\">, SLiM will designate the specified spatial dimensions as being periodic – wrapping around at the edges of the spatial boundaries of that dimension.<span class=\"Apple-converted-space\">  </span>This option may only be used if the </span><span class=\"s2\">dimensionality</span><span class=\"s1\"> parameter to </span><span class=\"s2\">initializeSLiMOptions()</span><span class=\"s1\"> has been used to enable spatiality in the model, and only spatial dimensions that were specified in the dimensionality of the model may be declared to be periodic (but if desired, it is permissible to make just a subset of those dimensions periodic; it is not an all-or-none proposition).<span class=\"Apple-converted-space\">  </span>For example, if the specified dimensionality is </span><span class=\"s2\">\"xy\"</span><span class=\"s1\">, the model’s periodicity may be </span><span class=\"s2\">\"x\"</span><span class=\"s1\">, </span><span class=\"s2\">\"y\"</span><span class=\"s1\">, or </span><span class=\"s2\">\"xy\"</span><span class=\"s1\"> (or </span><span class=\"s2\">\"\"</span><span class=\"s1\">, the default, to specify that there are no periodic dimensions).<span class=\"Apple-converted-space\">  </span>A one-dimensional periodic model would model a space like the perimeter of a circle.<span class=\"Apple-converted-space\">  </span>A two-dimensional model periodic in one of those dimensions would model a space like a cylinder without its end caps; if periodic in both dimensions, the modeled space is a torus.<span class=\"Apple-converted-space\">  </span>The shapes of three-dimensional periodic models are harder to visualize, but are essentially higher-dimensional analogues of these concepts.<span class=\"Apple-converted-space\">  </span>Periodic boundary conditions are commonly used to model spatial scenarios without “edge effects”, since there are no edges in the periodic spatial dimensions.<span class=\"Apple-converted-space\">  </span>The </span><span class=\"s2\">pointPeriodic()</span><span class=\"s1\"> method of </span><span class=\"s2\">Subpopulation</span><span class=\"s1\"> is typically used in conjunction with this option, to actually implement the periodic boundary condition for the specified dimensions.</span></p>\n<p class=\"p3\">The <span class=\"s3\">doMutationRunExperiments</span> parameter specifies whether SLiM should attempt to conduct experiments at runtime to determine the optimal number of mutation runs used in the model.<span class=\"Apple-converted-space\">  </span>This is a performance optimization.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">doMutationRunExperiments</span> is <span class=\"s3\">T</span> (the default), this optimization is enabled for all chromosomes that do not have an explicitly specified mutation run count; this is generally desirable and may significantly improve performance.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">doMutationRunExperiments</span> is <span class=\"s3\">F</span>, this optimization is disabled and chromosomes that do not have an explicitly specified mutation run count will simply use a single mutation run.<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s3\">initializeChromosome()</span> for further discussion.<span class=\"Apple-converted-space\">  </span>Note that this parameter used to be <span class=\"s3\">[integer$ mutationRuns = 0]</span>, specifying the mutation run count directly.<span class=\"Apple-converted-space\">  </span>That parameter has been moved to <span class=\"s3\">initializeChromosome()</span>, allowing a different mutation run count to be specified for each chromosome in multi-chromosome models.</p>\n<p class=\"p6\">If <span class=\"s3\">preventIncidentalSelfing</span> is <span class=\"s3\">T</span>, incidental selfing in hermaphroditic models will be prevented by SLiM.<span class=\"Apple-converted-space\">  </span>By default (i.e., if <span class=\"s3\">preventIncidentalSelfing</span> is <span class=\"s3\">F</span>), SLiM chooses the first and second parents in a biparental mating event independently.<span class=\"Apple-converted-space\">  </span>It is therefore possible for the same individual to be chosen as both the first and second parent, resulting in selfing events even when the selfing rate is zero.<span class=\"Apple-converted-space\">  </span>In many models this is unimportant, since it happens fairly infrequently and does not have large consequences.<span class=\"Apple-converted-space\">  </span>This behavior is SLiM’s default because it is the simplest option, and produces results that most closely align with simple analytical population genetics models.<span class=\"Apple-converted-space\">  </span>However, in some models this selfing can be undesirable and problematic.<span class=\"Apple-converted-space\">  </span>In particular, models that involve very high variance in fitness or very small effective population sizes may see elevated rates of selfing that substantially influence model results.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">preventIncidentalSelfing</span> is set to <span class=\"s3\">T</span>, all such incidental selfing will be prevented (by choosing a new second parent if the first parent was chosen again).<span class=\"Apple-converted-space\">  </span>Non-incidental selfing, as requested by the selfing rate, will still be permitted.<span class=\"Apple-converted-space\">  </span>Note that if incidental selfing is prevented, SLiM will hang if it is unable to find a different second parent; there must always be at least two individuals in the population with non-zero fitness, and <span class=\"s3\">mateChoice()</span> and <span class=\"s3\">modifyChild()</span> callbacks must not absolutely prevent those two individuals from producing viable offspring.<span class=\"Apple-converted-space\">  </span>Enforcement of the prohibition on incidental selfing will occur after <span class=\"s3\">mateChoice()</span> callbacks have been called (and thus the default mating weights provided to <span class=\"s3\">mateChoice()</span> callbacks will <i>not</i> exclude the first parent!), but will occur before <span class=\"s3\">modifyChild()</span> callbacks are called (so those callbacks may assume that the first and second parents are distinct).</p>\n<p class=\"p3\"><span class=\"s1\">If </span><span class=\"s2\">nucleotideBased</span><span class=\"s1\"> is </span><span class=\"s2\">T</span><span class=\"s1\">, the model will be nucleotide-based.<span class=\"Apple-converted-space\">  </span>In this case, auto-generated mutations (i.e., mutation types used by genomic element types) must be nucleotide-based, and an ancestral nucleotide sequence must be supplied with </span><span class=\"s2\">initializeAncestralNucleotides()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>Non-nucleotide-based mutations may still be used, but may not be referenced by genomic element types.<span class=\"Apple-converted-space\">  </span>A mutation rate (or rate map) may not be supplied with </span><span class=\"s2\">initializeMutationRate()</span><span class=\"s1\">; instead, a hotspot map may (optionally) be supplied with </span><span class=\"s2\">initializeHotspotMap()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>This choice has many consequences across SLiM.<span class=\"Apple-converted-space\"> </span></span></p>\n<p class=\"p3\">If <span class=\"s3\">randomizeCallbacks</span> is <span class=\"s3\">T</span> (the default), the order in which individuals are processed in callbacks will be randomized to make it easier to avoid order-dependency bugs.<span class=\"Apple-converted-space\">  </span>This flag exists because the order of individuals in each subpopulation is non-random; most notably, females always come before males in the individuals vector, but non-random ordering may also occur with respect to things like migrant versus non-migrant status, origin by selfing versus cloning versus biparental mating, and other factors.<span class=\"Apple-converted-space\">  </span>When this option is <span class=\"s3\">F</span>, individuals in a subpopulation are processed in the order of the individuals vector in each tick cycle stage, which may lead to order-dependency issues if there is an enabled callback whose behavior is not fully independent between calls.<span class=\"Apple-converted-space\">  </span>Setting this option to <span class=\"s3\">T</span> will cause individuals within each subpopulation to be processed in a randomized order in each tick cycle stage; specifically, this randomizes the order of calls to <span class=\"s3\">mutationEffect()</span> callbacks in both WF and nonWF models, and calls to <span class=\"s3\">reproduction()</span> and <span class=\"s3\">survival()</span> callbacks in nonWF models.<span class=\"Apple-converted-space\">  </span>Each subpopulation is still processed separately, in sequential order, so order-dependency issues between subpopulations are still possible if callbacks have effects that are not fully independent.<span class=\"Apple-converted-space\">  </span>This feature was added in SLiM 4, breaking backward compatibility; to recover the behavior of previous versions of SLiM, pass <span class=\"s3\">F</span> for this option (but then be very careful about order-dependency issues in your script).<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s3\">T</span> is the safe option, but a small speed penalty is incurred by the randomization of the processing order – for most models the difference will be less than 1%, but in the worst case it may approach 10%.<span class=\"Apple-converted-space\">  </span>Models that do not have any order-dependency issue may therefore run somewhat faster if this is set to <span class=\"s3\">F</span>.<span class=\"Apple-converted-space\">  </span>Note that anywhere that your script uses the <span class=\"s3\">individuals</span> property of <span class=\"s3\">Subpopulation</span>, the order of individuals returned will be non-random (regardless of the setting of this option); you should use <span class=\"s3\">sample()</span> to shuffle the order of the individuals vector if necessary to avoid order-dependency issues in your script.</p>\n<p class=\"p3\">If <span class=\"s3\">checkInfiniteLoops</span> is <span class=\"s3\">T</span> (the default), SLiM and Eidos will check for infinite loops in various circumstances, such as <span class=\"s3\">while</span> and <span class=\"s3\">do–while</span> loops.<span class=\"Apple-converted-space\">  </span>This check is conducted only when running in SLiMgui; at the command line, checks for infinite loops are never conducted regardless of the value of this flag.<span class=\"Apple-converted-space\">  </span>When checking is enabled, an error will be raised if any loop executes more than 10 million times, preventing SLiMgui’s user interface from freezing.<span class=\"Apple-converted-space\">  </span>Normally this is desirable, but if you actually want to execute a loop more than 10 million times, this checking will prove inconvenient.<span class=\"Apple-converted-space\">  </span>In that case, you can pass <span class=\"s3\">F</span> for <span class=\"s3\">checkInfiniteLoops</span> to disable these checks.<span class=\"Apple-converted-space\">  </span>There is no way to turn these checks on or off for individual loops; it is a global setting.</p>\n<p class=\"p6\">This function will likely be extended with further options in the future, added on to the end of the argument list.<span class=\"Apple-converted-space\">  </span>Using named arguments with this call is recommended for readability.<span class=\"Apple-converted-space\">  </span>Note that turning on optional features may increase the runtime and memory footprint of SLiM.</p>\n<p class=\"p4\">(void)initializeSpecies([integer$ tickModulo = 1], [integer$ tickPhase = 1], [string$ avatar = \"\"], [string$ color = \"\"])</p>\n<p class=\"p3\">Configure options for the species being initialized.<span class=\"Apple-converted-space\">  </span>This initialization function may only be called in multispecies models (i.e., models with explicit species declarations); in single-species models, the default values are assumed and cannot be changed.</p>\n<p class=\"p3\">The <span class=\"s3\">tickModulo</span> and <span class=\"s3\">tickPhase</span> parameters determine the activation schedule for the species.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">active</span> property of the species will be set to <span class=\"s3\">T</span> (thus activating the species) every <span class=\"s3\">tickModulo</span> ticks, beginning in tick <span class=\"s3\">tickPhase</span>.<span class=\"Apple-converted-space\">  </span>(However, when the species is activated in a given tick, the <span class=\"s3\">skipTick()</span> method may still be called in a <span class=\"s3\">first()</span> event to deactivate it.)<span class=\"Apple-converted-space\">  </span>See the <span class=\"s3\">active</span> property of <span class=\"s3\">Species</span> for more details.</p>\n<p class=\"p3\">The <span class=\"s3\">avatar</span> parameter, if not <span class=\"s3\">\"\"</span>, sets a <span class=\"s3\">string</span> value used to represent the species graphically, particularly in SLiMgui but perhaps in other contexts also.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">avatar</span> should generally be a single character – usually an emoji corresponding to the species, such as <span class=\"s3\">\"</span><span class=\"s10\">🦊</span><span class=\"s3\">\"</span> for foxes or <span class=\"s3\">\"</span><span class=\"s10\">🐭</span><span class=\"s3\">\"</span> for mice.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">avatar</span> is the empty string, <span class=\"s3\">\"\"</span>, SLiMgui will choose a default avatar.</p>\n<p class=\"p3\">The <span class=\"s3\">color</span> parameter, if not <span class=\"s3\">\"\"</span>, sets a <span class=\"s3\">string</span> color value used to represent the species in SLiMgui.<span class=\"Apple-converted-space\">  </span>Colors may be specified by name, or with hexadecimal RGB values of the form <span class=\"s3\">\"#RRGGBB\"</span> (see the Eidos manual for details).<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">color</span> is the empty string, <span class=\"s3\">\"\"</span>, SLiMgui will choose a default color.</p>\n<p class=\"p4\"><span class=\"s1\">(void)initializeTreeSeq([logical$ recordMutations = T], [Nif$ simplificationRatio = NULL], [Ni$ simplificationInterval = NULL], [logical$ checkCoalescence = F], [logical$ runCrosschecks = F], [logical$ </span>retainCoalescentOnly<span class=\"s1\"> = T]</span>, [Ns$ timeUnit = NULL]<span class=\"s1\">)</span></p>\n<p class=\"p3\">Configure options for tree sequence recording.<span class=\"Apple-converted-space\">  </span>Calling this function turns on tree sequence recording, as a side effect, for later reconstruction of the simulation’s evolutionary dynamics; if you do not want tree sequence recording to be enabled, do not call this function.<span class=\"Apple-converted-space\">  </span>Note that tree-sequence recording internally uses SLiM’s “pedigree tracking” feature to uniquely identify individuals and haplosomes; however, if you want to use pedigree tracking in your script you must still enable it yourself with <span class=\"s3\">initializeSLiMOptions(keepPedigrees=T)</span>.<span class=\"Apple-converted-space\">  </span>A separate tree sequence will be recorded for each chromosome in the simulation, as configured with <span class=\"s3\">initializeChromosome()</span>.</p>\n<p class=\"p3\">The <span class=\"s3\">recordMutations</span> flag controls whether information about individual mutations is recorded or not.<span class=\"Apple-converted-space\">  </span>Such recording takes time and memory, and so can be turned off if only the tree sequence itself is needed, but it is turned on by default since mutation recording is generally useful.</p>\n<p class=\"p3\">The <span class=\"s3\">simplificationRatio</span> and <span class=\"s3\">simplificationInterval</span> parameters control how often automatic simplification of the recorded tree sequence occurs.<span class=\"Apple-converted-space\">  </span>This is a speed–memory tradeoff: more frequent simplification (lower <span class=\"s3\">simplificationRatio</span> or smaller <span class=\"s3\">simplificationInterval</span>) means the stored tree sequences will use less memory, but at a cost of somewhat longer run times.<span class=\"Apple-converted-space\">  </span>Conversely, a larger <span class=\"s3\">simplificationRatio</span> or <span class=\"s3\">simplificationInterval</span> means that SLiM will wait longer between simplifications.<span class=\"Apple-converted-space\">  </span>There are three ways these parameters can be used.<span class=\"Apple-converted-space\">  </span>With the first option, with a non-<span class=\"s3\">NULL</span> <span class=\"s3\">simplificationRatio</span> and a <span class=\"s3\">NULL</span> value for <span class=\"s3\">simplificationInterval</span>, SLiM will try to find an optimal tick interval for simplification such that the ratio of the memory used by the tree sequence tables, (before:after) simplification, is close to the requested ratio. The default of <span class=\"s3\">10</span> (used if both <span class=\"s3\">simplificationRatio</span> and <span class=\"s3\">simplificationInterval</span> are <span class=\"s3\">NULL</span>) thus requests that SLiM try to find a tick interval such that the maximum size of the stored tree sequences is ten times the size after simplification. <span class=\"s3\">INF</span> may be supplied to indicate that automatic simplification should never occur; <span class=\"s3\">0</span> may be supplied to indicate that automatic simplification should be performed at the end of every tick.<span class=\"Apple-converted-space\">  </span>Alternatively – the second option – <span class=\"s3\">simplificationRatio</span> may be <span class=\"s3\">NULL</span> and <span class=\"s3\">simplificationInterval</span> may be set to the interval, in ticks, between simplifications.<span class=\"Apple-converted-space\">  </span>This may provide more reliable performance, but the interval must be chosen carefully to avoid exceeding the available memory.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">simplificationInterval</span> value may be a very large number to specify that simplification should never occur (not <span class=\"s3\">INF</span>, though, since it is an <span class=\"s3\">integer</span> value), or <span class=\"s3\">1</span> to simplify every tick.<span class=\"Apple-converted-space\">  </span>Finally – the third option – both parameters may be non-<span class=\"s3\">NULL</span>, in which case <span class=\"s3\">simplificationRatio</span> is used as described above, while <span class=\"s3\">simplificationInterval</span> provides the <i>initial</i> interval first used by SLiM (and then subsequently increased or decreased to try to match the requested simplification ratio).<span class=\"Apple-converted-space\">  </span>The default initial interval, used when <span class=\"s3\">simplificationInterval</span> is <span class=\"s3\">NULL</span>, is usually <span class=\"s3\">20</span>; this is chosen to be relatively frequent, and thus unlikely to lead to a memory overflow, but it can result in rather slow spool-up for models where the equilibrium simplification interval, as determined by the simplification ratio, is much longer.<span class=\"Apple-converted-space\">  </span>It can therefore be helpful to set a larger initial interval so that the early part of the model run is not excessively bogged down in simplification.</p>\n<p class=\"p3\">The <span class=\"s3\">checkCoalescence</span> parameter controls whether a check for full coalescence is conducted after each simplification.<span class=\"Apple-converted-space\">  </span>If a model will call <span class=\"s3\">treeSeqCoalesced()</span> to check for coalescence during its execution, <span class=\"s3\">checkCoalescence</span> should be set to <span class=\"s3\">T</span>.<span class=\"Apple-converted-space\">  </span>Since the coalescence checks entail a performance penalty, the default of <span class=\"s3\">F</span> is preferable otherwise.<span class=\"Apple-converted-space\">  </span>See the documentation for <span class=\"s3\">treeSeqCoalesced()</span> for further discussion.</p>\n<p class=\"p3\">The <span class=\"s3\">runCrosschecks</span> parameter controls whether cross-checks between SLiM’s internal data structures and the tree-sequence recording data structures will be conducted.<span class=\"Apple-converted-space\">  </span>These two sets of data structures record much the same thing (mutations in haplosomes), but using completely different representations, so such cross-checks can be useful to confirm that the two data structures do indeed represent the same conceptual state.<span class=\"Apple-converted-space\">  </span>This slows down the model considerably, however, and would normally be turned on only for debugging purposes, so it is turned off by default.</p>\n<p class=\"p3\">The <span class=\"s3\">retainCoalescentOnly</span> parameter controls how, exactly, simplification of the tree-sequence data is performed in SLiM (both for auto-simplification and for calls to <span class=\"s3\">treeSeqSimplify()</span>).<span class=\"Apple-converted-space\">  </span>More specifically, this parameter controls the behavior of simplification for individuals and haplosomes that have been “retained” by calling <span class=\"s3\">treeSeqRememberIndividuals()</span> with the parameter <span class=\"s3\">permanent=F</span>.<span class=\"Apple-converted-space\">  </span>The default of <span class=\"s3\">retainCoalescentOnly=T</span> helps to keep the number of retained individuals relatively small, which is helpful if your simulation regularly flags many individuals for retaining.<span class=\"Apple-converted-space\">  </span>In this case, changing <span class=\"s3\">retainCoalescentOnly</span> to <span class=\"s3\">F</span> may dramatically increase memory usage and runtime, in a similar way to permanently remembering all the individuals.<span class=\"Apple-converted-space\">  </span>See the documentation of <span class=\"s3\">treeSeqRememberIndividuals()</span> for further discussion.</p>\n<p class=\"p3\">The <span class=\"s3\">timeUnit</span> parameter controls the time unit stated in the tree sequence when it is saved (which can be accessed through <span class=\"s3\">tskit</span> APIs); it has no effect on the running simulation whatsoever.<span class=\"Apple-converted-space\">  </span>The default value, <span class=\"s3\">NULL</span>, means that a time unit of <span class=\"s3\">\"ticks\"</span> will be used for all model types.<span class=\"Apple-converted-space\">  </span>(In SLiM 3.7 / 3.7.1, <span class=\"s3\">NULL</span> implied a time unit of <span class=\"s3\">\"generations\"</span> for WF models, but <span class=\"s3\">\"ticks\"</span> for nonWF models; given the new multispecies timescale parameters in SLiM 4, a default of <span class=\"s3\">\"ticks\"</span> makes sense in all cases since now even in WF models one tick might not equal one biological generation.)<span class=\"Apple-converted-space\">  </span>It may be helpful to set <span class=\"s3\">timeUnit</span> to <span class=\"s3\">\"generations\"</span> explicitly when modeling non-overlapping generations in which one tick equals one generation, to tell <span class=\"s3\">tskit</span> that the time unit does in fact represent biological generations; doing so may avoid warnings from <span class=\"s3\">tskit</span> or <span class=\"s3\">msprime</span> regarding the time unit, in cases such as recapitation where the simulation timescale is important.</p>\n<p class=\"p1\"><b>3.2.<span class=\"Apple-converted-space\">  </span>Nucleotide utilities</b></p>\n<p class=\"p4\"><span class=\"s1\">(is)codonsToAminoAcids(integer codons, [li$ long = F], [logical$ paste = T])</span></p>\n<p class=\"p3\">Returns the amino acid sequence corresponding to the codon sequence in <span class=\"s3\">codons</span>.<span class=\"Apple-converted-space\">  </span>Codons should be represented with values in [<span class=\"s3\">0</span>, <span class=\"s3\">63</span>] where AAA is <span class=\"s3\">0</span>, AAC is <span class=\"s3\">1</span>, AAG is <span class=\"s3\">2</span>, and TTT is <span class=\"s3\">63</span>; see <span class=\"s3\">ancestralNucleotides()</span> for discussion of this encoding.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">long</span> is <span class=\"s3\">F</span> (the default), the standard single-letter codes for amino acids will be used (where Serine is <span class=\"s3\">\"S\"</span>, etc.); if <span class=\"s3\">long</span> is <span class=\"s3\">T</span>, the standard three-letter codes will be used instead (where Serine is <span class=\"s3\">\"Ser\"</span>, etc.).<span class=\"Apple-converted-space\">  </span>Beginning in SLiM 3.5, if <span class=\"s3\">long</span> is <span class=\"s3\">0</span>, <span class=\"s3\">integer</span> codes will be used as follows (and <span class=\"s3\">paste</span> will be ignored):</p>\n<p class=\"p10\">stop (TAA, TAG, TGA)<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">0</span><br>\nAlanine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">1</span><br>\nArginine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">2</span><br>\nAsparagine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">3</span><br>\nAspartic acid (Aspartate)<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">4</span><br>\nCysteine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">5</span><br>\nGlutamine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">6</span><br>\nGlutamic acid (Glutamate)<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">7</span><br>\nGlycine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">8</span><br>\nHistidine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">9</span><br>\nIsoleucine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">10</span><br>\nLeucine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">11</span><br>\nLysine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">12</span><br>\nMethionine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">13</span><br>\nPhenylalanine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">14</span><br>\nProline<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">15</span><br>\nSerine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">16</span><br>\nThreonine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">17</span><br>\nTryptophan<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">18</span><br>\nTyrosine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">19</span><br>\nValine<span class=\"Apple-tab-span\">\t</span><span class=\"s3\">20</span></p>\n<p class=\"p3\">There does not seem to be a widely used standard for integer coding of amino acids, so SLiM just numbers them alphabetically, making stop codons <span class=\"s3\">0</span>.<span class=\"Apple-converted-space\">  </span>If you want a different coding, you can make your own 64-element vector and use it to convert codons to whatever integer codes you need.<span class=\"Apple-converted-space\">  </span>Other <span class=\"s3\">integer</span> values of <span class=\"s3\">long</span> are reserved for future use (to support other codings), and will currently produce an error.</p>\n<p class=\"p3\">When <span class=\"s3\">long</span> is <span class=\"s3\">T</span> or <span class=\"s3\">F</span> and <span class=\"s3\">paste</span> is <span class=\"s3\">T</span> (the default), the amino acid sequence returned will be a singleton <span class=\"s3\">string</span>, such as <span class=\"s3\">\"LYATI\"</span> (when <span class=\"s3\">long</span> is <span class=\"s3\">F</span>) or <span class=\"s3\">\"Leu-Tyr-Ala-Thr-Ile\"</span> (when <span class=\"s3\">long</span> is <span class=\"s3\">T</span>).<span class=\"Apple-converted-space\">  </span>When <span class=\"s3\">long</span> is <span class=\"s3\">T</span> or <span class=\"s3\">F</span> and <span class=\"s3\">paste</span> is <span class=\"s3\">F</span>, the amino acid sequence will instead be returned as a <span class=\"s3\">string</span> vector, with one element per amino acid, such as <span class=\"s3\">\"L\" \"Y\" \"A\" \"T\" \"I\"</span> (when <span class=\"s3\">long</span> is <span class=\"s3\">F</span>) or <span class=\"s3\">\"Leu\" \"Tyr\" \"Ala\" \"Thr\" \"Ile\"</span> (when <span class=\"s3\">long</span> is <span class=\"s3\">T</span>).<span class=\"Apple-converted-space\">  </span>Using the <span class=\"s3\">paste=T</span> option is considerably faster than using <span class=\"s3\">paste()</span> in script.</p>\n<p class=\"p3\"><span class=\"s1\">This function interprets the supplied codon sequence as the <i>sense</i> strand (i.e., the strand that is <i>not</i> transcribed, and which mirrors the mRNA’s sequence).<span class=\"Apple-converted-space\">  </span>This uses the standard DNA codon table directly.<span class=\"Apple-converted-space\">  </span>For example, if the nucleotide sequence is CAA TTC, that will correspond to a codon vector of </span><span class=\"s2\">16 61</span><span class=\"s1\">, and will result in the amino acid sequence Gln-Phe (</span><span class=\"s2\">\"QF\"</span><span class=\"s1\">).</span></p>\n<p class=\"p4\"><span class=\"s1\">(is)codonsToNucleotides(integer codons, [string$ format = \"string\"])</span></p>\n<p class=\"p3\"><span class=\"s1\">Returns the nucleotide sequence corresponding to the codon sequence supplied in </span><span class=\"s2\">codons</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>Codons should be represented with values in [</span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">63</span><span class=\"s1\">] where AAA is </span><span class=\"s2\">0</span><span class=\"s1\">, AAC is </span><span class=\"s2\">1</span><span class=\"s1\">, AAG is </span><span class=\"s2\">2</span><span class=\"s1\">, and TTT is </span><span class=\"s2\">63</span><span class=\"s1\">; see </span><span class=\"s2\">ancestralNucleotides()</span><span class=\"s1\"> for discussion of this encoding.</span></p>\n<p class=\"p3\"><span class=\"s1\">The </span><span class=\"s2\">format</span><span class=\"s1\"> parameter controls the format of the returned sequence.<span class=\"Apple-converted-space\">  </span>It may be </span><span class=\"s2\">\"string\"</span><span class=\"s1\"> to obtain the sequence as a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> (e.g., </span><span class=\"s2\">\"TATACG\"</span><span class=\"s1\">), </span><span class=\"s2\">\"char\"</span><span class=\"s1\"> to obtain it as a </span><span class=\"s2\">string</span><span class=\"s1\"> vector of single characters (e.g., </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"C\"</span><span class=\"s1\">, </span><span class=\"s2\">\"G\"</span><span class=\"s1\">), or </span><span class=\"s2\">\"integer\"</span><span class=\"s1\"> to obtain it as an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector (e.g., </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">1</span><span class=\"s1\">, </span><span class=\"s2\">2</span><span class=\"s1\">), using SLiM’s standard code of A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(float)mm16To256(float mutationMatrix16)</span></p>\n<p class=\"p3\"><span class=\"s1\">Returns a 64×4 mutation matrix that is functionally identical to the supplied 4×4 mutation matrix in </span><span class=\"s2\">mutationMatrix16</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>The mutation rate for each of the 64 trinucleotides will depend only upon the central nucleotide of the trinucleotide, and will be taken from the corresponding entry for the same nucleotide in </span><span class=\"s2\">mutationMatrix16</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>This function can be used to easily construct a simple trinucleotide-based mutation matrix which can then be modified so that specific trinucleotides sustain a mutation rate that does not depend only upon their central nucleotide.</span></p>\n<p class=\"p3\"><span class=\"s1\">See the documentation for </span><span class=\"s2\">initializeGenomicElementType()</span><span class=\"s1\"> for further discussion of how these 64×4 mutation matrices are interpreted and used.</span></p>\n<p class=\"p4\"><span class=\"s1\">(float)mmJukesCantor(float$ alpha)</span></p>\n<p class=\"p3\"><span class=\"s1\">Returns a mutation matrix representing a Jukes–Cantor (1969) model with mutation rate </span><span class=\"s2\">alpha</span><span class=\"s1\"> to each possible alternative nucleotide at a site.<span class=\"Apple-converted-space\">  </span>This 2×2 matrix is suitable for use with </span><span class=\"s2\">initializeGenomicElementType()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>Note that the actual mutation rate produced by this matrix is </span><span class=\"s2\">3*alpha</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(float)mmKimura(float$ alpha, float$ beta)</span></p>\n<p class=\"p3\"><span class=\"s1\">Returns a mutation matrix representing a Kimura (1980) model with transition rate </span><span class=\"s2\">alpha</span><span class=\"s1\"> and transversion rate </span><span class=\"s2\">beta</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>This 2×2 matrix is suitable for use with </span><span class=\"s2\">initializeGenomicElementType()</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>Note that the actual mutation rate produced by this model is </span><span class=\"s2\">alpha+2*beta</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(integer)nucleotideCounts(is sequence)</span></p>\n<p class=\"p3\"><span class=\"s1\">A convenience function that returns an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector of length four, providing the number of occurrences of A / C / G / T nucleotides, respectively, in the supplied nucleotide sequence.<span class=\"Apple-converted-space\">  </span>The parameter sequence may be a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> (e.g., </span><span class=\"s2\">\"TATA\"</span><span class=\"s1\">), a </span><span class=\"s2\">string</span><span class=\"s1\"> vector of single characters (e.g., </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">), or an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector (e.g., 3, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">), using SLiM’s standard code of A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(float)nucleotideFrequencies(is sequence)</span></p>\n<p class=\"p3\"><span class=\"s1\">A convenience function that returns a </span><span class=\"s2\">float</span><span class=\"s1\"> vector of length four, providing the frequencies of occurrences of A / C / G / T nucleotides, respectively, in the supplied nucleotide sequence.<span class=\"Apple-converted-space\">  </span>The parameter sequence may be a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> (e.g., </span><span class=\"s2\">\"TATA\"</span><span class=\"s1\">), a </span><span class=\"s2\">string</span><span class=\"s1\"> vector of single characters (e.g., </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">), or an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector (e.g., 3, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">), using SLiM’s standard code of A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.</span></p>\n<p class=\"p4\"><span class=\"s1\">(integer)nucleotidesToCodons(is sequence)</span></p>\n<p class=\"p3\"><span class=\"s1\">Returns the codon sequence corresponding to the nucleotide sequence in </span><span class=\"s2\">sequence</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>The codon sequence is an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector with values from </span><span class=\"s2\">0</span><span class=\"s1\"> to </span><span class=\"s2\">63</span><span class=\"s1\">, based upon successive nucleotide triplets in the nucleotide sequence.<span class=\"Apple-converted-space\">  </span>The codon value for a given nucleotide triplet XYZ is 16X + 4Y + Z, where X, Y, and Z have the usual values A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>For example, the triplet AAA has a codon value of </span><span class=\"s2\">0</span><span class=\"s1\">, AAC is </span><span class=\"s2\">1</span><span class=\"s1\">, AAG is </span><span class=\"s2\">2</span><span class=\"s1\">, AAT is </span><span class=\"s2\">3</span><span class=\"s1\">, ACA is </span><span class=\"s2\">4</span><span class=\"s1\">, and on upward to TTT which is </span><span class=\"s2\">63</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>If the nucleotide sequence AACACATTT is passed in, the codon vector </span><span class=\"s2\">1 4 63</span><span class=\"s1\"> will therefore be returned.<span class=\"Apple-converted-space\">  </span>These codon values can be useful in themselves; they can also be passed to </span><span class=\"s2\">codonsToAminoAcids()</span><span class=\"s1\"> to translate them into the corresponding amino acid sequence if desired.</span></p>\n<p class=\"p3\"><span class=\"s1\">The nucleotide sequence in </span><span class=\"s2\">sequence</span><span class=\"s1\"> may be supplied in any of three formats: a </span><span class=\"s2\">string</span><span class=\"s1\"> vector with single-letter nucleotides (e.g., </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">), a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> of nucleotide letters (e.g., </span><span class=\"s2\">\"TATA\"</span><span class=\"s1\">), or an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector of nucleotide values (e.g., </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">) using SLiM’s standard code of A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>If the choice of format is not driven by other considerations, such as ease of manipulation, then the singleton </span><span class=\"s2\">string</span><span class=\"s1\"> format will certainly be the most memory-efficient for long sequences, and will probably also be the fastest.<span class=\"Apple-converted-space\">  </span>The nucleotide sequence provided must be a multiple of three in length, so that it translates to an integral number of codons.</span></p>\n<p class=\"p2\">(is)randomNucleotides(integer$ length, [Nif basis = NULL], [string$ format = \"string\"])</p>\n<p class=\"p3\"><span class=\"s1\">Generates a new random nucleotide sequence with </span><span class=\"s2\">length</span><span class=\"s1\"> bases.<span class=\"Apple-converted-space\">  </span>The four nucleotides ACGT are equally probable if </span><span class=\"s2\">basis</span><span class=\"s1\"> is </span><span class=\"s2\">NULL</span><span class=\"s1\"> (the default); otherwise, </span><span class=\"s2\">basis</span><span class=\"s1\"> may be a 4-element </span><span class=\"s2\">integer</span><span class=\"s1\"> or </span><span class=\"s2\">float</span><span class=\"s1\"> vector providing relative fractions for A, C, G, and T respectively (these need not sum to </span><span class=\"s2\">1.0</span><span class=\"s1\">, as they will be normalized).<span class=\"Apple-converted-space\">  </span>More complex generative models such as Markov processes are not supported intrinsically in SLiM at this time, but arbitrary generated sequences may always be loaded from files on disk.</span></p>\n<p class=\"p3\"><span class=\"s1\">The </span><span class=\"s2\">format</span><span class=\"s1\"> parameter controls the format of the returned sequence.<span class=\"Apple-converted-space\">  </span>It may be </span><span class=\"s2\">\"string\"</span><span class=\"s1\"> to obtain the generated sequence as a singleton </span><span class=\"s2\">string</span><span class=\"s1\"> (e.g., </span><span class=\"s2\">\"TATA\"</span><span class=\"s1\">), </span><span class=\"s2\">\"char\"</span><span class=\"s1\"> to obtain it as a </span><span class=\"s2\">string</span><span class=\"s1\"> vector of single characters (e.g., </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">, </span><span class=\"s2\">\"T\"</span><span class=\"s1\">, </span><span class=\"s2\">\"A\"</span><span class=\"s1\">), or </span><span class=\"s2\">\"integer\"</span><span class=\"s1\"> to obtain it as an </span><span class=\"s2\">integer</span><span class=\"s1\"> vector (e.g., </span><span class=\"s2\">3</span><span class=\"s1\">, </span><span class=\"s2\">0</span><span class=\"s1\">, </span><span class=\"s2\">3, 0</span><span class=\"s1\">), using SLiM’s standard code of A=</span><span class=\"s2\">0</span><span class=\"s1\">, C=</span><span class=\"s2\">1</span><span class=\"s1\">, G=</span><span class=\"s2\">2</span><span class=\"s1\">, T=</span><span class=\"s2\">3</span><span class=\"s1\">.<span class=\"Apple-converted-space\">  </span>For passing directly to </span><span class=\"s2\">initializeAncestralNucleotides()</span><span class=\"s1\">, format </span><span class=\"s2\">\"string\"</span><span class=\"s1\"> (a singleton string) will certainly be the most memory-efficient, and probably also the fastest.<span class=\"Apple-converted-space\">  </span>Memory efficiency can be a significant consideration; the nucleotide sequence for a chromosome of length 10</span><span class=\"s11\"><sup>9</sup></span><span class=\"s1\"> will occupy approximately 1 GB of memory when stored as a singleton string (with one byte per nucleotide), and much more if stored in the other formats.<span class=\"Apple-converted-space\">  </span>However, the other formats can be easier to work with in Eidos, and so may be preferable for relatively short chromosomes if you are manipulating the generated sequence.</span></p>\n<p class=\"p1\"><b>3.3.<span class=\"Apple-converted-space\">  </span>Population genetics utilities</b></p>\n<p class=\"p4\">(float$)calcDxy(object&lt;Haplosome&gt; haplosomes1, object&lt;Haplosome&gt; haplosomes2, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL], [logical$ normalize = F])</p>\n<p class=\"p3\">Calculates the estimated <i>D</i><span class=\"s4\"><sub>xy</sub></span> between two <span class=\"s3\">Haplosome</span> vectors for the set of mutations given in <span class=\"s3\">muts</span>.<span class=\"Apple-converted-space\">  </span><i>D</i><span class=\"s4\"><sub>xy</sub></span> is the expected number of differences between two sequences, typically drawn from two different subpopulations whose haplosomes are given in <span class=\"s3\">haplosomes1</span> and <span class=\"s3\">haplosomes2</span>.<span class=\"Apple-converted-space\">  </span>It is therefore a metric of genetic divergence, comparable in some respects to <i>F</i><span class=\"s4\"><sub>ST</sub></span>; see Cruickshank and Hahn (2014, Molecular Ecology) for a discussion of <i>F</i><span class=\"s4\"><sub>ST</sub></span> versus <i>D</i><span class=\"s4\"><sub>xy</sub></span>.<span class=\"Apple-converted-space\">  </span>This method implements <i>D</i><span class=\"s4\"><sub>xy</sub></span> as defined by Nei (1987) in Molecular Evolutionary Genomics (eq. 10.20), with optimizations for computational efficiency based upon an assumption that that multiallelic loci are rare (this is compatible with the infinite-sites model).</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full haplosomes – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide <i>D</i><span class=\"s4\"><sub>xy</sub></span>.</p>\n<p class=\"p3\">If <span class=\"s3\">normalize</span> is <span class=\"s3\">F</span> (the default), the returned <span class=\"s3\">float</span> value is simply the expected number of differences, following Nei.<span class=\"Apple-converted-space\">  </span>Often, however, it will be desirable to normalize that value by dividing by the length of the sequence considered, yielding the expected number of differences <i>per site</i>, a metric that then does not depend upon the sequence length; passing <span class=\"s3\">normalize=T</span> will return that normalized value, and that is probably what most users of this function will want.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcDxy()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation in <span class=\"s3\">muts</span> as independent in its calculations (similar to <span class=\"s3\">calcPi()</span>); in other words, if mutations are stacked, the <i>D</i><span class=\"s4\"><sub>xy</sub></span> value calculated is <i>by mutation</i>, not <i>by site</i>.<span class=\"Apple-converted-space\">  </span>Similarly, if multiple <span class=\"s3\">Mutation</span> objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each <span class=\"s3\">Mutation</span> object is treated separately for purposes of the calculation, just as if they were at different sites.<span class=\"Apple-converted-space\">  </span>One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of these choices will be negligible; however, in some models these distinctions may be important.<span class=\"Apple-converted-space\">  </span>See <span class=\"s3\">calcPairHeterozygosity()</span> for further discussion.</p>\n<p class=\"p3\">All haplosomes and mutations must be associated with the same chromosome.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">muts</span> is <span class=\"s3\">NULL</span> (the default), all mutations in the population associated with the same chromosome as the given haplosomes will be used.</p>\n<p class=\"p3\">This function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).</p>\n<p class=\"p4\">(float$)calcFST(object&lt;Haplosome&gt; haplosomes1, object&lt;Haplosome&gt; haplosomes2, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p3\">Calculates the <i>F</i><span class=\"s4\"><sub>ST</sub></span> between two <span class=\"s3\">Haplosome</span> vectors – typically, but not necessarily, the haplosomes that constitute two different subpopulations (which we will assume for the purposes of this discussion).<span class=\"Apple-converted-space\">  </span>In general, higher <i>F</i><span class=\"s4\"><sub>ST</sub></span> indicates greater genetic divergence between subpopulations.<span class=\"Apple-converted-space\">  </span>The haplosomes may be associated with more than one chromosome, in a multi-chromosome model; if so, <span class=\"s3\">haplosomes1</span> and <span class=\"s3\">haplosomes2</span> must be associated with the same set of chromosomes, defining the focal set of chromosomes for the calculation.</p>\n<p class=\"p3\">The calculation is done using only the mutations in <span class=\"s3\">muts</span>; if <span class=\"s3\">muts</span> is <span class=\"s3\">NULL</span>, all mutations associated with the focal chromosomes are used.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">muts</span> parameter can be used to calculate the <i>F</i><span class=\"s4\"><sub>ST</sub></span> only for a particular mutation type (by passing only mutations of that type), for example; it can focus the calculation on particular mutations of interest.<span class=\"Apple-converted-space\">  </span>The mutations in <span class=\"s3\">muts</span> must always be associated with the focal chromosomes.</p>\n<p class=\"p3\">If there is a single focal chromosome, the calculation can be narrowed to apply to only a window – a subrange of the focal chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the chromosome-wide <i>F</i><span class=\"s4\"><sub>ST</sub></span>, which is often used to assess the overall level of genetic divergence between sister species or allopatric subpopulations.</p>\n<p class=\"p3\">The code for <span class=\"s3\">calcFST()</span> is, roughly, an Eidos implementation of Wright’s definition of <i>F</i><span class=\"s4\"><sub>ST</sub></span> (but see below for further discussion and clarification):</p>\n<p class=\"p3\"><i>F</i><span class=\"s4\"><sub>ST</sub></span><span class=\"s1\"> = 1 - <i>H</i></span><span class=\"s4\"><sub>S</sub></span><span class=\"s1\"> / <i>H</i></span><span class=\"s4\"><sub>T</sub></span></p>\n<p class=\"p3\">where <i>H</i><span class=\"s4\"><i><sub>S</sub></i></span> is the average heterozygosity in the two subpopulations, and <i>H</i><span class=\"s4\"><i><sub>T </sub></i></span>is the total heterozygosity when both subpopulations are combined.<span class=\"Apple-converted-space\">  </span>In this implementation, the two haplosome vectors are weighted equally, not weighted by their size.<span class=\"Apple-converted-space\">  </span>In SLiM 3, the implementation followed Wright’s definition closely, and returned the <i>average of ratios</i>: <span class=\"s3\">mean(1.0 - H_s/H_t)</span>, in the Eidos code.<span class=\"Apple-converted-space\">  </span>In SLiM 4, it returns the <i>ratio of averages</i> instead: <span class=\"s3\">1.0 - mean(H_s)/mean(H_t)</span>.<span class=\"Apple-converted-space\">  </span>In other words, the <i>F</i><span class=\"s4\"><sub>ST</sub></span> value reported by SLiM 4 is an average across the specified mutations in the two sets of haplosomes, where <span class=\"s3\">H_s</span> and <span class=\"s3\">H_t</span> are first averaged across all specified mutations prior to taking the ratio of the two.<span class=\"Apple-converted-space\">  </span>This ratio of averages is less biased than the average of ratios, and and is generally considered to be best practice (see, e.g., Bhatia et al., 2013).<span class=\"Apple-converted-space\">  </span>This means that the behavior of <span class=\"s3\">calcFST()</span> differs between SLiM 3 and SLiM 4.</p>\n<p class=\"p3\">As can be seen from its equation, the <i>F</i><span class=\"s4\"><sub>ST</sub></span> is undefined if <i>H</i><span class=\"s4\"><i><sub>T</sub></i></span> is zero, which occurs if no mutations are present in the haplosomes provided (given the optionally specified window and set of mutations).<span class=\"Apple-converted-space\">  </span>In that case, <span class=\"s3\">calcFST()</span> will return <span class=\"s3\">NAN</span>.<span class=\"Apple-converted-space\">  </span>It is up to the caller to detect this with <span class=\"s3\">isNAN()</span> and handle it as necessary.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcFST()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation in <span class=\"s3\">muts</span> as independent in the heterozygosity calculations; in other words, if mutations are stacked, the heterozygosity calculated is <i>by mutation</i>, not <i>by site</i>.<span class=\"Apple-converted-space\">  </span>Similarly, if multiple <span class=\"s3\">Mutation</span> objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each <span class=\"s3\">Mutation</span> object is treated separately for purposes of the heterozygosity calculation, just as if they were at different sites.<span class=\"Apple-converted-space\">  </span>One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of these choices will be negligible; however, in some models these distinctions may be important.</p>\n<p class=\"p4\">(float$)calcHeterozygosity(object&lt;Haplosome&gt; haplosomes, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p3\">Calculates the heterozygosity for a vector of haplosomes (containing at least one element), based upon the frequencies of mutations in the haplosomes.<span class=\"Apple-converted-space\">  </span>The result is the <i>expected</i> heterozygosity, for the individuals to which the haplosomes belong, assuming that they are under Hardy-Weinberg equilibrium; this can be compared to the <i>observed</i> heterozygosity of an individual, as calculated by <span class=\"s3\">calcPairHeterozygosity()</span>.<span class=\"Apple-converted-space\">  </span>Often <span class=\"s3\">haplosomes</span> will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.<span class=\"Apple-converted-space\">  </span>By default, with <span class=\"s3\">muts=NULL</span>, the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for <span class=\"s3\">muts</span>.</p>\n<p class=\"p3\">In multi-chromosome models, all of the haplosomes and mutations passed in <span class=\"s3\">haplosomes</span> and <span class=\"s3\">muts</span> must all be associated with the same single chromosome.<span class=\"Apple-converted-space\">  </span>If you wish to calculate heterozygosity across multiple chromosomes, you can simply write a <span class=\"s3\">for</span> loop that calculates it for each chromosome and combines the results; but it is not entirely clear how to weight the chromosomes to produce a single number, especially when sex chromosomes and other chromosomes of variable ploidy might be represented in <span class=\"s3\">haplosomes</span>, so it is not done automatically by this function.</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide heterozygosity.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcHeterozygosity()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation as independent in the heterozygosity calculations.<span class=\"Apple-converted-space\">  </span>One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this choice will be negligible; however, in some models this distinction may be important.<span class=\"Apple-converted-space\">  </span>See <span class=\"s3\">calcPairHeterozygosity()</span> for further discussion.</p>\n<p class=\"p4\">(float$)calcInbreedingLoad(object&lt;Haplosome&gt; haplosomes, [Nio&lt;MutationType&gt;$ mutType = NULL])</p>\n<p class=\"p3\">Calculates inbreeding load (the haploid number of lethal equivalents, or <i>B</i>) for a vector of haplosomes (containing at least one element) passed in <span class=\"s3\">haplosomes</span>.<span class=\"Apple-converted-space\">  </span>The calculation can be limited to a focal mutation type passed in <span class=\"s3\">mutType</span> (which may be either an <span class=\"s3\">integer</span> representing the ID of the desired mutation type, or a <span class=\"s3\">MutationType</span> object specified directly); if <span class=\"s3\">mutType</span> is <span class=\"s3\">NULL</span> (the default), all of the mutations for the focal species will be considered.<span class=\"Apple-converted-space\">  </span>In any case, only deleterious mutations (those with a negative selection coefficient) will be included in the final calculation.</p>\n<p class=\"p3\">The inbreeding load is a measure of the quantity of recessive deleterious variation that is heterozygous in a population and can contribute to fitness declines under inbreeding.<span class=\"Apple-converted-space\">  </span>This function implements the following equation from Morton et al. (1956), which assumes no epistasis and random mating:</p>\n<p class=\"p11\"><i>B</i> = sum(<i>qs</i>) − sum(<i>q</i><span class=\"s12\"><sup>2</sup></span><i>s</i>) − 2sum(<i>q</i>(1−<i>q</i>)<i>sh</i>)</p>\n<p class=\"p3\">where <i>q</i> is the frequency of a given deleterious allele, <i>s</i> is the absolute value of the selection coefficient, and <i>h</i> is its dominance coefficient.<span class=\"Apple-converted-space\">  </span>Note that the implementation, viewable with <span class=\"s3\">functionSource()</span>, sets a maximum |<i>s</i>| of <span class=\"s3\">1.0</span> (i.e., a lethal allele); |<i>s</i>| can sometimes be greater than <span class=\"s3\">1.0</span> when <i>s</i> is drawn from a distribution, but in practice an allele with <i>s</i> &lt; <span class=\"s3\">-1.0</span> has the same lethal effect as when <i>s</i> = <span class=\"s3\">-1.0</span>.<span class=\"Apple-converted-space\">  </span>Also note that this implementation will not work when the model changes the dominance coefficients of mutations using <span class=\"s3\">mutationEffect()</span> callbacks, since it relies on the <span class=\"s3\">dominanceCoeff</span> property of <span class=\"s3\">MutationType</span>. Finally, note that, to estimate the diploid number of lethal equivalents (2<i>B</i>), the result from this function can simply be multiplied by two.</p>\n<p class=\"p3\">This function was contributed by Chris Kyriazis; thanks, Chris!</p>\n<p class=\"p4\">(float)calcLD_D(object&lt;Mutation&gt;$ mut1, [No&lt;Mutation&gt; mut2 = NULL], [No&lt;Haplosome&gt; haplosomes = NULL])</p>\n<p class=\"p3\">Calculates the linkage disequilibrium (LD) coefficient <i>D</i> between a focal mutation <span class=\"s3\">mut1</span> and one or more mutations in <span class=\"s3\">mut2</span>, evaluated across a set of haplosomes given by <span class=\"s3\">haplosomes</span>.<span class=\"Apple-converted-space\">  </span>The result is a <span class=\"s3\">float</span> vector that matches the size and order of <span class=\"s3\">mut2</span>.<span class=\"Apple-converted-space\">  </span>The implementation of this function, viewable with <span class=\"s3\">functionSource()</span>, calculates <i>D</i> as defined by Hill and Robertson (1968, p. 226).<span class=\"Apple-converted-space\">  </span>The coefficient <i>D</i> is within [−<i>p</i>(1−<i>p</i>), <i>p</i>(1−<i>p</i>)], where <i>p</i> is the frequency of the more common mutation (that is, <i>p</i> = max(<i>f</i><span class=\"s4\"><sub>1</sub></span>, <i>f</i><span class=\"s4\"><sub>2</sub></span>) where <i>f</i><span class=\"s4\"><sub>1</sub></span> and <i>f</i><span class=\"s4\"><sub>2</sub></span> are the frequencies of the two mutations for which <i>D</i> is being calculated); for the normalized LD metric <i>r</i><span class=\"s4\"><sup>2</sup></span>, which is within [0, 1], see <span class=\"s3\">calcLD_Rsquared()</span>.<span class=\"Apple-converted-space\">  </span>Departures of <i>D</i> from zero indicate LD; more specifically, <i>D</i> &gt; 0 indicates that the mutations occur together more often than expected by chance (positive linkage), whereas <i>D</i> &lt; 0 indicates they occur together less often than expected by chance (negative linkage).</p>\n<p class=\"p3\">All mutations in <span class=\"s3\">mut2</span> must be associated with the same chromosome as <span class=\"s3\">mut1</span>; this function does not currently calculate LD between mutations associated with different chromosomes.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">mut2</span> is <span class=\"s3\">NULL</span> (the default), all such mutations in the population (including <span class=\"s3\">mut1</span> itself) will be used.<span class=\"Apple-converted-space\">  </span>Similarly, all haplosomes must be associated with the same chromosome as <span class=\"s3\">mut1</span>.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s3\">haplosomes</span> parameter is <span class=\"s3\">NULL</span> (the default), all such haplosomes in the population will be used.</p>\n<p class=\"p3\">This function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).</p>\n<p class=\"p4\">(float)calcLD_Rsquared(object&lt;Mutation&gt;$ mut1, [No&lt;Mutation&gt; mut2 = NULL], [No&lt;Haplosome&gt; haplosomes = NULL], [logical$ squared = T])</p>\n<p class=\"p3\">Calculates the linkage disequilibrium (LD) squared correlation coefficient <i>r</i><span class=\"s4\"><sup>2</sup></span> between a focal mutation <span class=\"s3\">mut1</span> and one or more mutations in <span class=\"s3\">mut2</span>, evaluated across a set of haplosomes given by <span class=\"s3\">haplosomes</span>.<span class=\"Apple-converted-space\">  </span>The result is a <span class=\"s3\">float</span> vector that matches the size and order of <span class=\"s3\">mut2</span>.<span class=\"Apple-converted-space\">  </span>The implementation of this function, viewable with <span class=\"s3\">functionSource()</span>, calculates <i>r</i><span class=\"s4\"><sup>2</sup></span> as defined by Hill and Robertson (1968, p. 227).<span class=\"Apple-converted-space\">  </span>The squared correlation coefficient <i>r</i><span class=\"s4\"><sup>2</sup></span> is a normalized measure of LD within [0, 1] (for the unnormalized LD coefficient <i>D</i>, see <span class=\"s3\">calcLD_D()</span>).<span class=\"Apple-converted-space\">  </span>When <i>r</i><span class=\"s4\"><sup>2</sup></span> = 0, there is no statistical association between the mutations; they co-occur as expected by chance.<span class=\"Apple-converted-space\">  </span>A value of <i>r</i><span class=\"s4\"><sup>2</sup></span> = 1 indicates complete correlation: the mutations either always appear together or never appear together, depending on the sign of the underlying correlation coefficient <i>r</i>.<span class=\"Apple-converted-space\">  </span>To obtain the raw (signed) <i>r</i> value instead of <i>r</i><span class=\"s4\"><sup>2</sup></span>, you can pass <span class=\"s3\">squared=F</span> instead of the default of <span class=\"s3\">T</span>.</p>\n<p class=\"p3\">All mutations in <span class=\"s3\">mut2</span> must be associated with the same chromosome as <span class=\"s3\">mut1</span>; this function does not currently calculate LD between mutations associated with different chromosomes.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">mut2</span> is <span class=\"s3\">NULL</span> (the default), all such mutations in the population (including <span class=\"s3\">mut1</span> itself) will be used.<span class=\"Apple-converted-space\">  </span>Similarly, all haplosomes must be associated with the same chromosome as <span class=\"s3\">mut1</span>.<span class=\"Apple-converted-space\">  </span>If the <span class=\"s3\">haplosomes</span> parameter is <span class=\"s3\">NULL</span> (the default), all such haplosomes in the population will be used.</p>\n<p class=\"p3\">This function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).</p>\n<p class=\"p4\">(float$)calcMeanFroh(object&lt;Individual&gt; individuals, [integer$ minimumLength = 1000000], [Niso&lt;Chromosome&gt;$ chromosome = NULL])</p>\n<p class=\"p3\">Calculates the mean value of the <i>F</i><span class=\"s4\"><sub>roh</sub></span> statistic across the individuals passed in <span class=\"s3\">individuals</span>.<span class=\"Apple-converted-space\">  </span>This statistic is a measure of individual autozygosity, likely resulting from inbreeding, and is calculated based upon “runs of homozygosity”, or ROH, in the genome of an individual.<span class=\"Apple-converted-space\">  </span>Broadly speaking, <i>F</i><span class=\"s4\"><sub>roh</sub></span> is the proportion of an individual’s genome that is spanned by ROH longer than a given threshold length.<span class=\"Apple-converted-space\">  </span>However, it should be noted that there are many different ways of calculating <i>F</i><span class=\"s4\"><sub>roh</sub></span>, producing different results.<span class=\"Apple-converted-space\">  </span>For example, the threshold length might be a given constant, or might be determined statistically from the characteristics of the population.<span class=\"Apple-converted-space\">  </span>Furthermore, some heterozygous sites might be discarded (to compensate for genotyping errors), a minimum SNP density might be required within a sliding window for an ROH to be diagnosed, and so forth – it can get quite complex, as seen in the software PLINK (Purcell et al., 2007) and GARLIC (Szpiech, Blant and Pemberton, 2017).<span class=\"Apple-converted-space\">  </span>The method used by <span class=\"s3\">calcMeanFroh()</span> is the simplest possible method, assessing ROH for each individual directly from the simulated mutations without filtering or modification, and applying a given constant threshold length.<span class=\"Apple-converted-space\">  </span>If a more sophisticated <i>F</i><span class=\"s4\"><sub>roh</sub></span> algorithm is desired, one could modify the implementation of <span class=\"s3\">calcMeanFroh()</span>, which is viewable with <span class=\"s3\">functionSource()</span>, or one could output VCF data from SLiM and analyze it with other tools, perhaps calling out from the running SLiM script with <span class=\"s3\">system()</span>.</p>\n<p class=\"p3\">The threshold ROH length used by <span class=\"s3\">calcMeanFroh()</span> is supplied by the parameter <span class=\"s3\">minimumLength</span>.<span class=\"Apple-converted-space\">  </span>It defaults to <span class=\"s3\">1e6</span>, or 1 Mbp, since that is a length commonly used in the literature, but can be adjusted as desired.</p>\n<p class=\"p3\">The <span class=\"s3\">chromosome</span> parameter can be supplied to focus the <i>F</i><span class=\"s4\"><sub>roh</sub></span> calculation on a specific chromosome; otherwise, the calculation spans all chromosomes for which the individual is actually diploid (without a null haplosome).<span class=\"Apple-converted-space\">  </span>If <i>F</i><span class=\"s4\"><sub>roh</sub></span> cannot be calculated for an individual (due to the presence of null haplosomes for every intrinsically diploid chromosome being analyzed), that individual is omitted from the mean <i>F</i><span class=\"s4\"><sub>roh</sub></span> calculation; for example, if an X chromosome is the focal chromosome being analyzed, all males will be omitted from the mean <i>F</i><span class=\"s4\"><sub>roh</sub></span> calculation.<span class=\"Apple-converted-space\">  </span>If all individuals are omitted from the mean <i>F</i><span class=\"s4\"><sub>roh</sub></span> calculation for this reason, <span class=\"s3\">NAN</span> is returned.</p>\n<p class=\"p3\">This function was developed with advice from Ryan Chaffee.<span class=\"Apple-converted-space\">  </span>Thanks, Ryan!</p>\n<p class=\"p4\">(float$)calcPairHeterozygosity(object&lt;Haplosome&gt;$ haplosome1, object&lt;Haplosome&gt;$ haplosome2, [Ni$ start = NULL], [Ni$ end = NULL], [logical$ infiniteSites = T])</p>\n<p class=\"p3\">Calculates the heterozygosity for a pair of haplosomes; these will typically be two homologous haplosomes of the same diploid individual, but any two haplosomes associated with the same chromosome may be supplied.</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide heterozygosity.</p>\n<p class=\"p3\">The implementation <span class=\"s3\">calcPairHeterozygosity()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation as independent in the heterozygosity calculations by default (i.e., with <span class=\"s3\">infiniteSites=T</span>).<span class=\"Apple-converted-space\">  </span>If mutations are stacked, the heterozygosity calculated therefore depends upon the number of <i>unshared mutations</i>, not the number of <i>differing sites</i>.<span class=\"Apple-converted-space\">  </span>Similarly, if multiple <span class=\"s3\">Mutation</span> objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each <span class=\"s3\">Mutation</span> object is treated separately for purposes of the heterozygosity calculation, just as if they were at different sites.<span class=\"Apple-converted-space\">  </span>One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this choice will be negligible; however, in some models this distinction may be important.<span class=\"Apple-converted-space\">  </span>The behavior of <span class=\"s3\">calcPairHeterozygosity()</span> can be switched to calculate based upon the number of differing sites, rather than the number of unshared mutations, by passing <span class=\"s3\">infiniteSites=F</span>.</p>\n<p class=\"p4\">(float$)calcPi(object&lt;Haplosome&gt; haplosomes, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p3\">Calculates <span class=\"s7\"><i>π</i></span> (nucleotide diversity, a metric of genetic diversity) for a vector of haplosomes (containing at least two elements), based upon the mutations in the haplosomes.<span class=\"Apple-converted-space\">  </span><span class=\"s7\"><i>π</i></span> is computed by calculating the mean number of pairwise differences at each site, summing across all sites, and dividing by the number of sites.<span class=\"Apple-converted-space\">  </span>Therefore, it is interpretable as the number of differences per site expected between two randomly chosen sequences.<span class=\"Apple-converted-space\">  </span>The mathematical formulation (as an estimator of the population parameter <span class=\"s7\"><i>θ</i></span>) is based on work in Nei and Li (1979), Nei and Tajima (1981), and Tajima (1983; equation A3).<span class=\"Apple-converted-space\">  </span>The exact formula used here is common in textbooks (e.g., equations 9.1–9.5 in Li 1997, equation 3.3 in Hahn 2018, or equation 2.2 in Coop 2020).</p>\n<p class=\"p3\">Often <span class=\"s3\">haplosomes</span> will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.<span class=\"Apple-converted-space\">  </span>By default, with <span class=\"s3\">muts=NULL</span>, the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for <span class=\"s3\">muts</span>.</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide value of <span class=\"s7\"><i>π</i></span>.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcPi()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation as independent in the heterozygosity calculations.<span class=\"Apple-converted-space\">  </span>One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with <span class=\"s3\">calcHeterozygosity()</span>.<span class=\"Apple-converted-space\">  </span>Indeed, finite-sites models of <span class=\"s7\"><i>π</i></span> have been derived (Tajima 1996) though are not used here.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.<span class=\"Apple-converted-space\">  </span>See <span class=\"s3\">calcPairHeterozygosity()</span> for further discussion.<span class=\"Apple-converted-space\">  </span>This function was written by Nick Bailey (currently affiliated with CNRS and the Laboratory of Biometry and Evolutionary Biology at University Lyon 1), with helpful input from Peter Ralph and Chase Nelson.</p>\n<p class=\"p4\">(numeric)calcSFS([Ni$ binCount = NULL], [No&lt;Haplosome&gt; haplosomes = NULL], [No&lt;Mutation&gt; muts = NULL], [string$ metric = \"density\"], [logical$ fold = F])</p>\n<p class=\"p3\">Calculates the site frequency spectrum, or SFS, for the mutations specified by <span class=\"s3\">muts</span>, within the haplosomes specified by <span class=\"s3\">haplosomes</span>.<span class=\"Apple-converted-space\">  </span>The site frequency spectrum or SFS (sometimes called the allele frequency spectrum, although some authors distinguish between the two) is essentially a histogram of the frequencies of the mutations within the haplosomes; the first bin spans the lowest range of frequencies (down to a frequency of <span class=\"s3\">0.0</span>, or a count of <span class=\"s3\">1</span>), whereas the last bin spans the highest range of frequencies (up to a frequency of <span class=\"s3\">1.0</span>, or a count equal to number of haplosomes minus one).<span class=\"Apple-converted-space\">  </span>The idea was introduced by Watterson (1975), and will be discussed in any population genetics textbook (e.g., A. Cutter, 2019, pp. 50–52).<span class=\"Apple-converted-space\">  </span>This histogram can be returned as a <span class=\"s3\">float</span> vector of density values for each bin by specifying <span class=\"s3\">\"density\"</span> for <span class=\"s3\">metric</span> (the default), or as an <span class=\"s3\">integer</span> vector of count values for each bin by specifying <span class=\"s3\">\"count\"</span>.</p>\n<p class=\"p3\">There are two modes of operation for <span class=\"s3\">calcSFS()</span>.<span class=\"Apple-converted-space\">  </span>If a specific number of bins is passed for <span class=\"s3\">binCount</span>, then the frequency range <span class=\"s3\">[0.0, 1.0]</span> is subdivided into <span class=\"s3\">binCount</span> intervals of equal width, and the mutations are tallied into those bins according to their frequencies within the haplosomes to produce the histogram.<span class=\"Apple-converted-space\">  </span>In this mode, there will be exactly <span class=\"s3\">binCount</span> elements in the returned vector.<span class=\"Apple-converted-space\">  </span>Note that either <span class=\"s3\">\"density\"</span> or <span class=\"s3\">\"count\"</span> can be chosen in this mode; you can return the frequency bin tallies as either densities or counts.</p>\n<p class=\"p3\">In the other mode of operation, chosen with a <span class=\"s3\">binCount</span> value of <span class=\"s3\">NULL</span>, the bins instead represent the count of the number of occurrences for each mutation, and range from a count of <span class=\"s3\">1</span> (the bin for mutations that occur only once in the haplosomes, sometimes called “singletons”) up to a count of <span class=\"s3\">N-1</span> where <span class=\"s3\">N</span> is the number of haplosomes.<span class=\"Apple-converted-space\">  </span>(Note that mutations occurring in all <span class=\"s3\">N</span> haplosomes are not included in the tally, since they would not be empirically observable.)<span class=\"Apple-converted-space\">  </span>In this mode, there will be exactly <span class=\"s3\">N-1</span> elements in the returned vector.<span class=\"Apple-converted-space\">  </span>Again, either <span class=\"s3\">\"density\"</span> or <span class=\"s3\">\"count\"</span> can be chosen in this mode; you can return the count bin tallies as either densities or counts (it’s a bit confusing, but we’re talking about two different kinds of “counts”, the count of the number of times a mutation occurs in the haplosomes versus the count of the number of mutations that were tallied into a particular count bin).</p>\n<p class=\"p3\">The <span class=\"s3\">haplosomes</span> parameter can be either a vector of <span class=\"s3\">Haplosome</span> objects or <span class=\"s3\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">NULL</span> is passed, <span class=\"s3\">calcSFS()</span> will calculate the SFS across the whole species, using all non-null haplosomes present (and thus there must be only a single species in the model, since an SFS cannot be calculated across multiple species).<span class=\"Apple-converted-space\">  </span>Otherwise, <span class=\"s3\">haplosomes</span> can contain any set of haplosomes desired, such as from the individuals of one subpopulation, several subpopulations, or an entire species.<span class=\"Apple-converted-space\">  </span>However, they must all belong to the same species, and null haplosomes will be automatically and silently excluded from the set.</p>\n<p class=\"p3\">The <span class=\"s3\">muts</span> parameter can be either a vector of <span class=\"s3\">Mutation</span> objects or <span class=\"s3\">NULL</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">NULL</span> is passed, <span class=\"s3\">calcSFS()</span> will calculate the SFS across all mutations belonging to the focal species (as determined from the species of the haplosomes).<span class=\"Apple-converted-space\">  </span>Otherwise, <span class=\"s3\">muts</span> can contain any set of mutations desired, such as mutations belonging to a specific mutation type, mutations within a specific range of positions along the chromosome, or all of the mutations in the focal species.</p>\n<p class=\"p3\">The <span class=\"s3\">binCount</span> and <span class=\"s3\">metric</span> parameters have already been discussed.<span class=\"Apple-converted-space\">  </span>Finally, the <span class=\"s3\">fold</span> parameter, if <span class=\"s3\">T</span>, “folds” the calculated SFS, adding the first and last bins, the second and next-to-last bins, etc., until the center is reached.<span class=\"Apple-converted-space\">  </span>Folding is common when working with empirical data, where one often doesn’t know the “polarity” – which allele at a site is ancestral and which is derived.<span class=\"Apple-converted-space\">  </span>Folding solves this problem, because the polarity then doesn’t matter; the tally for a given mutation ends up in the same bin regardless.<span class=\"Apple-converted-space\">  </span>If the number of bins is even, folding can be performed without ambiguity; the final number of bins is exactly half the original number of bins, and each final bin is the sum of two original bins.<span class=\"Apple-converted-space\">  </span>If the number of bins is odd, the correct treatment of the central bin is somewhat ambiguous.<span class=\"Apple-converted-space\">  </span>In <span class=\"s3\">calcFST()</span>, the central bin is added to itself – doubled – and the number of bins is equal to half the original number of bins rounded up.<span class=\"Apple-converted-space\">  </span>If you would prefer to exclude the central bin altogether – another population treatment – then when the original number of bins is odd, you can simply discard the final value in the returned vector (and, if you wish to work with densities rather than counts, re-normalize the result to sum to 1.0).</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcSFS()</span>, viewable with <span class=\"s3\">functionSource()</span>, tallies each mutation separately, even if more than one mutation occurs at the same position (or is even stacked with another mutation).<span class=\"Apple-converted-space\">  </span>One could regard this choice as embodying an infinite-sites interpretation of the SFS, perhaps; in any case, it follows SLiM’s behavior in other population-genetics utility functions.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.</p>\n<p class=\"p3\">This function is compatible with multi-chromosome models, in the following sense.<span class=\"Apple-converted-space\">  </span>When <span class=\"s3\">binCount</span> is specified with an <span class=\"s3\">integer</span> value, mutations are binned according to their frequencies, as described above.<span class=\"Apple-converted-space\">  </span>In a multi-chromosome model, the haplosomes and mutations used by <span class=\"s3\">calcSFS()</span> may be associated with more than one chromosome, and the frequency assessed for each mutation is its frequency specifically within the haplosomes associated with its chromosome (as you would expect).<span class=\"Apple-converted-space\">  </span>Mutations occurring in different chromosomes can therefore be tallied together into the same frequency bins, and combined into a single SFS; this produces a meaningful SFS.<span class=\"Apple-converted-space\">  </span>(If you want an SFS for just a single chromosome, then of course you can pass just those haplosomes and mutations to <span class=\"s3\">calcSFS()</span>.)<span class=\"Apple-converted-space\">  </span>When <span class=\"s3\">binCount</span> is <span class=\"s3\">NULL</span>, on the other hand, mutations are binned according to their counts, as described above.<span class=\"Apple-converted-space\">  </span>In a multi-chromosome model, it would not make sense to bin counts together from different chromosomes, since those counts might not be on the same scale – the number of haplosomes associated with the various chromosomes might not be equal.<span class=\"Apple-converted-space\">  </span>In this case, <span class=\"s3\">calcSFS()</span> will raise an error if haplosomes from more than one chromosome are supplied, or if haplosomes is <span class=\"s3\">NULL</span> (since it doesn’t know which chromosome to choose).<span class=\"Apple-converted-space\">  </span>If you wish to tally according to counts, with <span class=\"s3\">binCount=NULL</span>, you must pass in a vector of haplosomes associated with a single chromosome.<span class=\"Apple-converted-space\">  </span>(If you know what you are doing and wish to combine counts across multiple chromosomes, you can simply call <span class=\"s3\">calcSFS()</span> once per chromosome, and combine the resulting vectors by adding them together.)</p>\n<p class=\"p3\">Thanks to Ryan Chaffee and Chase Nelson for helpful input.</p>\n<p class=\"p4\">(float$)calcTajimasD(object&lt;Haplosome&gt; haplosomes, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p3\">Calculates Tajima’s <i>D</i> (a test of neutrality based on the allele frequency spectrum) for a vector of haplosomes (containing at least four elements), based upon the mutations in the haplosomes.<span class=\"Apple-converted-space\">  </span>The mathematical formulation is given in Tajima 1989 (equation 38) and remains unchanged (e.g., equations 2.30 in Durrett 2008, 8.4 in Hahn 2018, and 4.44 in Coop 2020).<span class=\"Apple-converted-space\">  </span>Often <span class=\"s3\">haplosomes</span> will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.<span class=\"Apple-converted-space\">  </span>By default, with <span class=\"s3\">muts=NULL</span>, the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for <span class=\"s3\">muts</span>.</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide Tajima’s <i>D</i>.</p>\n<p class=\"p3\">If the genetic diversity contained within the haplosomes is insufficient for the calculation, <span class=\"s3\">calcTajimasD()</span> may return <span class=\"s3\">NAN</span>.<span class=\"Apple-converted-space\">  </span>It is up to the caller to detect this with <span class=\"s3\">isNAN()</span> and handle it as necessary.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcTajimasD()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation as independent in the heterozygosity calculations.<span class=\"Apple-converted-space\">  </span>One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with <span class=\"s3\">calcHeterozygosity()</span>.<span class=\"Apple-converted-space\">  </span>Indeed, Tajima’s <i>D</i> can be modified with finite-sites models of <span class=\"s7\"><i>π</i></span> and <span class=\"s7\"><i>θ</i></span> (Misawa and Tajima 1997) though these are not used here.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.<span class=\"Apple-converted-space\">  </span>See <span class=\"s3\">calcPairHeterozygosity()</span> for further discussion.<span class=\"Apple-converted-space\">  </span>This function was written by Nick Bailey (currently affiliated with CNRS and the Laboratory of Biometry and Evolutionary Biology at University Lyon 1), with helpful input from Peter Ralph.</p>\n<p class=\"p4\">(float$)calcVA(object&lt;Individual&gt; individuals, io&lt;MutationType&gt;$ mutType)</p>\n<p class=\"p3\">Calculates <i>V</i><span class=\"s4\"><sub>A</sub></span>, the additive genetic variance, among a vector of individuals (containing at least two elements) passed in <span class=\"s3\">individuals</span>, in a particular mutation type <span class=\"s3\">mutType</span> that represents quantitative trait loci (QTLs) influencing a quantitative phenotypic trait.<span class=\"Apple-converted-space\">  </span>The <span class=\"s3\">mutType</span> parameter may be either an <span class=\"s3\">integer</span> representing the ID of the desired mutation type, or a <span class=\"s3\">MutationType</span> object specified directly.</p>\n<p class=\"p3\">This function assumes that mutations of type <span class=\"s3\">mutType</span> encode their effect size upon the quantitative trait in their <span class=\"s3\">selectionCoeff</span> property, as is fairly standard in SLiM.<span class=\"Apple-converted-space\">  </span>The implementation of <span class=\"s3\">calcVA()</span>, which is viewable with <span class=\"s3\">functionSource()</span>, is quite simple; if effect sizes are stored elsewhere (such as with <span class=\"s3\">setValue()</span>), a new user-defined function following the pattern of <span class=\"s3\">calcVA()</span> can easily be written.</p>\n<p class=\"p4\">(float$)calcWattersonsTheta(object&lt;Haplosome&gt; haplosomes, [No&lt;Mutation&gt; muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])</p>\n<p class=\"p3\">Calculates Watterson’s theta (a metric of genetic diversity comparable to heterozygosity) for a vector of haplosomes (containing at least one element), based upon the mutations in the haplosomes.<span class=\"Apple-converted-space\">  </span>Often <span class=\"s3\">haplosomes</span> will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.<span class=\"Apple-converted-space\">  </span>By default, with <span class=\"s3\">muts=NULL</span>, the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for <span class=\"s3\">muts</span>.</p>\n<p class=\"p3\">The calculation can be narrowed to apply to only a window – a subrange of the full chromosome – by passing the interval bounds [<span class=\"s3\">start</span>, <span class=\"s3\">end</span>] for the desired window.<span class=\"Apple-converted-space\">  </span>In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.<span class=\"Apple-converted-space\">  </span>The default behavior, with <span class=\"s3\">start</span> and <span class=\"s3\">end</span> of <span class=\"s3\">NULL</span>, provides the haplosome-wide Watterson’s theta.</p>\n<p class=\"p3\">The implementation of <span class=\"s3\">calcWattersonsTheta()</span>, viewable with <span class=\"s3\">functionSource()</span>, treats every mutation as independent in the heterozygosity calculations.<span class=\"Apple-converted-space\">  </span>One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with <span class=\"s3\">calcHeterozygosity()</span>.<span class=\"Apple-converted-space\">  </span>In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.<span class=\"Apple-converted-space\">  </span>See <span class=\"s3\">calcPairHeterozygosity()</span> for further discussion.</p>\n<p class=\"p1\"><b>3.4.<span class=\"Apple-converted-space\">  </span>Other utilities</b></p>\n<p class=\"p4\">(float)summarizeIndividuals(object&lt;Individual&gt; individuals, integer dim, numeric spatialBounds, string$ operation, [Nlif$ empty = 0.0], [logical$ perUnitArea = F], [Ns$ spatiality = NULL])</p>\n<p class=\"p3\">Returns a vector, matrix, or array that summarizes spatial patterns of information related to the individuals in <span class=\"s3\">individuals</span>.<span class=\"Apple-converted-space\">  </span>In essence, those individuals are assigned into <i>bins</i> according to their spatial position, and then a summary value for each bin is calculated based upon the individuals each bin contains.<span class=\"Apple-converted-space\">  </span>The individuals might be binned in one dimension (resulting in a vector of summary values), in two dimensions (resulting in a matrix), or in three dimensions (resulting in an array).<span class=\"Apple-converted-space\">  </span>Typically the spatiality of the result (the dimensions into which the individuals are binned) will match the dimensionality of the model, as indicated by the default value of <span class=\"s3\">NULL</span> for the optional <span class=\"s3\">spatiality</span> parameter; for example, a two-dimensional (<span class=\"s3\">\"xy\"</span>) model would by default produce a two-dimensional matrix as a summary.<span class=\"Apple-converted-space\">  </span>However, a spatiality that is more restrictive than the model dimensionality may be passed; for example, in a two-dimensional (<span class=\"s3\">\"xy\"</span>) model a <span class=\"s3\">spatiality</span> of <span class=\"s3\">\"y\"</span> could be passed to summarize individuals into a vector, rather than a matrix, assigning them to bins based only upon their <i>y</i> position (i.e., the value of their <span class=\"s3\">y</span> property).<span class=\"Apple-converted-space\">  </span>Whatever spatiality is chosen, the parameter <span class=\"s3\">dim</span> provides the dimensions of the desired result, in the same form that the <span class=\"s3\">dim()</span> function does: first the number of rows, then the number of columns, and then the number of planes, as needed (see the Eidos manual for discussion of matrices, arrays, and <span class=\"s3\">dim()</span>).<span class=\"Apple-converted-space\">  </span>The length of <span class=\"s3\">dims</span> must match the requested spatiality; for spatiality <span class=\"s3\">\"xy\"</span>, for example, <span class=\"s3\">dims</span> might be <span class=\"s3\">c(50,100)</span> to request that the returned matrix have <span class=\"s3\">50</span> rows and <span class=\"s3\">100</span> columns.<span class=\"Apple-converted-space\">  </span>The result vector/matrix/array is in the correct orientation to be directly usable as a spatial map, by passing it to the <span class=\"s3\">defineSpatialMap()</span> method of <span class=\"s3\">Subpopulation</span>.<span class=\"Apple-converted-space\">  </span>For further discussion of dimensionality and spatiality, see <span class=\"s3\">initializeInteractionType()</span> and <span class=\"s3\">InteractionType</span>.</p>\n<p class=\"p3\">The <span class=\"s3\">spatialBounds</span> parameter defines the spatial boundaries within which the individuals are binned.<span class=\"Apple-converted-space\">  </span>Typically this is the spatial bounds of a particular subpopulation, within which the individuals reside; for individuals in <span class=\"s3\">p1</span>, for example, you would likely pass <span class=\"s3\">p1.spatialBounds</span> for this.<span class=\"Apple-converted-space\">  </span>However, this is not required; individuals may come from any or all subpopulations in the model, and <span class=\"s3\">spatialBounds</span> may be any bounds of non-zero area (if an individual falls outside of the given spatial bounds, it is excluded, as if it were not in <span class=\"s3\">individuals</span> at all).<span class=\"Apple-converted-space\">  </span>If you have multiple subpopulations that conceptually reside within the same overall coordinate space, for example, that can be accommodated here.<span class=\"Apple-converted-space\">  </span>The bounds are supplied in the dimensionality of the model, in the same form as for <span class=\"s3\">Subpopulation</span>; for an <span class=\"s3\">\"xy\"</span> model, for example, they are supplied as a four-element vector of the form <span class=\"s3\">c(x0, y0, x1, y1)</span> even if the summary is being produced with spatiality <span class=\"s3\">\"y\"</span>.<span class=\"Apple-converted-space\">  </span>To produce the result, a grid with dimensions defined by <span class=\"s3\">dims</span> is conceptually stretched out across the given spatial bounds, such that the <i>centers</i> of the edge and corner grid squares are aligned with the limits of the spatial bounds.<span class=\"Apple-converted-space\">  </span>This matches the way that <span class=\"s3\">defineSpatialMap()</span> defines its maps.</p>\n<p class=\"p3\">The particular summary produced depends upon the parameters <span class=\"s3\">operation</span> and <span class=\"s3\">empty</span>.<span class=\"Apple-converted-space\">  </span>Consider a single grid square represented by a single element in the result.<span class=\"Apple-converted-space\">  </span>That grid square contains zero or more of the individuals in <span class=\"s3\">individuals</span>.<span class=\"Apple-converted-space\">  </span>If it contains zero individuals <i>and</i> <span class=\"s3\">empty</span> is not <span class=\"s3\">NULL</span>, the <span class=\"s3\">empty</span> value is used for the result, regardless of <span class=\"s3\">operation</span>, providing specific, separate control over the treatment of empty grid squares.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">empty</span> is <span class=\"s3\">NULL</span>, this separate control over the treatment of empty grid squares is declined; empty grid squares will be handled through the standard mechanism described next.<span class=\"Apple-converted-space\">  </span>In all other cases for the given grid square – when it contains more than zero individuals, or when <span class=\"s3\">empty</span> is <span class=\"s3\">NULL</span> – <span class=\"s3\">operation</span> is executed as an Eidos <i>lambda</i>, a small snippet of code, supplied as a singleton <span class=\"s3\">string</span>, that is executed in a manner similar to a function call.<span class=\"Apple-converted-space\">  </span>Within the execution of the <span class=\"s3\">operation</span> lambda, a constant named <span class=\"s3\">individuals</span> is defined to be the focal individuals being evaluated – all of the individuals within that grid square.<span class=\"Apple-converted-space\">  </span>This lambda should evaluate to a singleton <span class=\"s3\">logical</span>, <span class=\"s3\">integer</span>, or <span class=\"s3\">float</span> value, comprising the result value for the grid square; these types will all be coerced to <span class=\"s3\">float</span> (<span class=\"s3\">T</span> being <span class=\"s3\">1</span> and <span class=\"s3\">F</span> being <span class=\"s3\">0</span>).</p>\n<p class=\"p3\">Two examples may illustrate the use of <span class=\"s3\">empty</span> and <span class=\"s3\">operation</span>.<span class=\"Apple-converted-space\">  </span>To produce a summary indicating presence/absence, simply use the default of <span class=\"s3\">0.0</span> for <span class=\"s3\">empty</span>, and <span class=\"s3\">\"1.0;</span> <span class=\"s3\">\"</span> (or <span class=\"s3\">\"1;\"</span>, or <span class=\"s3\">\"T;\"</span>) for <span class=\"s3\">operation</span>.<span class=\"Apple-converted-space\">  </span>This will produce <span class=\"s3\">0.0</span> for empty grid squares, and <span class=\"s3\">1.0</span> for those that contain at least one individual.<span class=\"Apple-converted-space\">  </span>Note that the use of <span class=\"s3\">empty</span> is essential here, because <span class=\"s3\">operation</span> doesn’t even check whether individuals are present or not.<span class=\"Apple-converted-space\">  </span>To produce a summary with a count of the number of individuals in each grid square, again use the default of <span class=\"s3\">0.0</span> for <span class=\"s3\">empty</span>, but now use an <span class=\"s3\">operation</span> of <span class=\"s3\">\"individuals.size();\"</span>, counting the number of individuals in each grid square.<span class=\"Apple-converted-space\">  </span>In this case, <span class=\"s3\">empty</span> could be <span class=\"s3\">NULL</span> instead and <span class=\"s3\">operation</span> would still produce the correct result; but using <span class=\"s3\">empty</span> makes <span class=\"s3\">summarizeIndividuals()</span> more efficient since it allows the execution of <span class=\"s3\">operation</span> to be skipped for those squares.</p>\n<p class=\"p3\">Lambdas are not limited in their complexity; they can use <span class=\"s3\">if</span>, <span class=\"s3\">for</span>, etc., and can call methods and functions.<span class=\"Apple-converted-space\">  </span>A typical <span class=\"s3\">operation</span> to compute the mean phenotype in a quantitative genetic model that stores phenotype values in <span class=\"s3\">tagF</span>, for example, would be <span class=\"s3\">\"mean(individuals.tagF);\"</span>, and this is still quite simple compared to what is possible.<span class=\"Apple-converted-space\">  </span>However, keep in mind that the lambda will be evaluated for every grid cell (or at least those that are non-empty), so efficiency can be a concern, and you may wish to pre-calculate values shared by all of the lambda calls, making them available to your lambda code using <span class=\"s3\">defineGlobal()</span> or <span class=\"s3\">defineConstant()</span>.</p>\n<p class=\"p3\">There is one last twist, if <span class=\"s3\">perUnitArea</span> is <span class=\"s3\">T</span>: values are divided by the area (or length, in 1D, or volume, in 3D) that their corresponding grid cell comprises, so that each value is in units of “per unit area” (or “per unit length”, or “per unit volume”).<span class=\"Apple-converted-space\">  </span>The total area of the grid is defined by the spatial bounds, and the area of a given grid cell is defined by the portion of the spatial bounds that is within that cell.<span class=\"Apple-converted-space\">  </span>This is not the same for all grid cells; grid cells that fall partially outside <span class=\"s3\">spatialBounds</span> (because, remember, the <i>centers</i> of the edge/corner grid cells are aligned with the limits of <span class=\"s3\">spatialBounds</span>) will have a smaller area inside the bounds.<span class=\"Apple-converted-space\">  </span>For an <span class=\"s3\">\"xy\"</span> spatiality summary, for example, corner cells have only a quarter of their area inside <span class=\"s3\">spatialBounds</span>, while edge elements have half of their area inside <span class=\"s3\">spatialBounds</span>; for purposes of <span class=\"s3\">perUnitArea</span>, then, their respective areas are ¼ and ½ the area of an interior grid cell.<span class=\"Apple-converted-space\">  </span>By default, <span class=\"s3\">perUnitArea</span> is <span class=\"s3\">F</span>, and no scaling is performed.<span class=\"Apple-converted-space\">  </span>Whether you want <span class=\"s3\">perUnitArea</span> to be <span class=\"s3\">F</span> or <span class=\"s3\">T</span> depends upon whether the summary you are producing is, conceptually, “per unit area”, such as density (individuals per unit area) or local competition strength (total interaction strength per unit area), or is not, such as “mean individual age”, or “maximum <span class=\"s3\">tag</span> value”.<span class=\"Apple-converted-space\">  </span>For the previous example of counting individuals with an operation of <span class=\"s3\">\"individuals.size();\"</span>, a value of <span class=\"s3\">F</span> for <span class=\"s3\">perUnitArea</span> (the default) will produce a simple <i>count</i> of individuals in each grid square, whereas with <span class=\"s3\">T</span> it would produce the <i>density</i> of individuals in each grid square.</p>\n<p class=\"p4\">(object&lt;Dictionary&gt;$)treeSeqMetadata(string$ filePath, [logical$ userData = T])</p>\n<p class=\"p3\">Returns a <span class=\"s3\">Dictionary</span> containing top-level metadata from the <span class=\"s3\">.trees</span> (tree-sequence) file at <span class=\"s3\">filePath</span>.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">userData</span> is <span class=\"s3\">T</span> (the default), the top-level metadata under the <span class=\"s3\">SLiM/user_metadata</span> key is returned; this is the same metadata that can optionally be supplied to <span class=\"s3\">treeSeqOutput()</span> in its <span class=\"s3\">metadata</span> parameter, so it makes it easy to recover metadata that you attached to the tree sequence when it was saved.<span class=\"Apple-converted-space\">  </span>If <span class=\"s3\">userData</span> is <span class=\"s3\">F</span>, the entire top-level metadata <span class=\"s3\">Dictionary</span> object is returned; this can be useful for examining the values of other keys under the <span class=\"s3\">SLiM</span> key, or values inside the top-level dictionary itself that might have been placed there by <span class=\"s3\">msprime</span> or other software.</p>\n<p class=\"p3\">This function can be used to read in parameter values or other saved state (<span class=\"s3\">tag</span> property values, for example), in order to resuscitate the complete state of a simulation that was written to a <span class=\"s3\">.trees</span> file.<span class=\"Apple-converted-space\">  </span>It could be used for more esoteric purposes too, such as to search through <span class=\"s3\">.trees</span> files in a directory (with the help of the Eidos function <span class=\"s3\">filesAtPath()</span>) to find those files that satisfy some metadata criterion.</p>\n</body>\n</html>\n"
  },
  {
    "path": "QtSLiM/help.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>help/SLiMHelpCallbacks.html</file>\n        <file>help/SLiMHelpClasses.html</file>\n        <file>help/SLiMHelpFunctions.html</file>\n        <file>help/EidosHelpFunctions.html</file>\n        <file>help/EidosHelpClasses.html</file>\n        <file>help/EidosHelpOperators.html</file>\n        <file>help/EidosHelpStatements.html</file>\n        <file>help/EidosHelpTypes.html</file>\n        <file>help/TickCycle_nonWF.png</file>\n        <file>help/TickCycle_WF.png</file>\n        <file>help/TickCycle_nonWF_MS.png</file>\n        <file>help/TickCycle_WF_MS.png</file>\n        <file>help/ColorChart.png</file>\n        <file>help/PlotSymbols.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "QtSLiM/icons.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>icons/AppIcon128.png</file>\n        <file>icons/AppIcon1024.png</file>\n        <file>icons/AppIcon16.png</file>\n        <file>icons/AppIcon32.png</file>\n        <file>icons/AppIcon48.png</file>\n        <file>icons/AppIcon64.png</file>\n        <file>icons/AppIcon256.png</file>\n        <file>icons/AppIcon512.png</file>\n        <file>icons/DocIcon16.png</file>\n        <file>icons/DocIcon32.png</file>\n        <file>icons/DocIcon48.png</file>\n        <file>icons/DocIcon64.png</file>\n        <file>icons/DocIcon128.png</file>\n        <file>icons/DocIcon256.png</file>\n        <file>icons/DocIcon512.png</file>\n        <file>icons/GenericDocIcon16.png</file>\n        <file>icons/GenericDocIcon32.png</file>\n        <file>icons/bug.png</file>\n        <file>icons/bug_DARK.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "QtSLiM/main.cpp",
    "content": "#include \"QtSLiMAppDelegate.h\"\n#include \"QtSLiMWindow.h\"\n#include \"QtSLiMPreferences.h\"\n#include \"QtSLiMExtras.h\"\n\n#include <QApplication>\n#include <QCommandLineParser>\n#include <QStyle>\n#include <QStyleFactory>\n#include <QDebug>\n\n#include <locale>\n#include <locale.h>\n\n#include \"eidos_globals.h\"\n#include \"interaction_type.h\"\n\n#if SLIM_LEAK_CHECKING\nstatic void clean_up_leak_false_positives(void)\n{\n\t// This does a little cleanup that helps Valgrind to understand that some things have not been leaked.\n\t// I think perhaps unordered_map keeps values in an unaligned manner that Valgrind doesn't see as pointers.\n\tInteractionType::DeleteSparseVectorFreeList();\n\tFreeSymbolTablePool();\n\tif (gEidos_RNG_Initialized)\n\t\tEidos_FreeRNG();\n}\n\n// Note that we still get some leaks reported, many of which are likely spurious.  That seems to be caused by:\n// https://stackoverflow.com/a/51553776/2752221\n// I'd like to incorporate the fix given there, but I'm not sure where I'm supposed to find <lsan_interface.h>...\n#endif\n\n\n// Force to light mode on macOS\n// To avoid having to make this a .mm file on macOS, we use the Obj-C runtime directly\n// See https://www.mikeash.com/pyblog/objc_msgsends-new-prototype.html for some background\n// This is pretty gross, but this is also why Objective-C is cool!  :->\n// Note that we also have a custom Info.plist file that forces light mode; we try to\n// force light mode in two different ways.  This function is necessary for cmake builds,\n// which do not use the custom Info.plist at this time.  The custom Info.plist is\n// necessary because this function, for some reason, does not succeed in forcing light\n// mode when QtSLiM is built with qmake at the command line.\n// BCH 1/17/2021: We now try to force light mode only when compiled against a Qt version\n// earlier than 5.15.2 (since Qt did not support dark mode well prior to that version).\n// Since the double-click install version is built against 5.15.2, this should mean that\n// most macOS users get dark mode support.  The NSRequiresAquaSystemAppearance key in our\n// QtSLiM_Info.plist file, which was set to <true/> to force light mode, has been\n// removed.  As per the above comment, this may mean that macOS builds against a Qt version\n// earlier than 5.15.2 will not succeed in forcing light mode.  For this reason and others,\n// we now require Qt 5.15.2 when building on macOS (see QtSLiMAppDelegate.cpp).\n// BCH 4/13/2022: Disabling this macos_ForceLightMode() function altogether.  Building against\n// Qt versions prior to 5.15.2 on macOS is no longer supported at all, and linking against\n// libobjc.dylib on macOS 12 has gotten complicated for security reasons (trampolines).\n#ifdef __APPLE__\n#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 2))\n#if 0\n// Include objc headers\n#include <objc/runtime.h>\n#include <objc/message.h>\n\nstatic void macos_ForceLightMode(void)\n{\n    // First we need to make an NSString with value @\"NSAppearanceNameAqua\"; 1 is NSASCIIStringEncoding\n    Class nsstring_class = objc_lookUpClass(\"NSString\");\n    SEL selector_stringWithCString_encoding = sel_registerName(\"stringWithCString:encoding:\");\n    \n    if ((!nsstring_class) || (!selector_stringWithCString_encoding))\n        return;\n    \n    //std::cout << \"nsstring_class == \" << nsstring_class << std::endl;\n    //std::cout << \"class_getName(nsstring_class) == \" << class_getName(nsstring_class) << std::endl;\n    //std::cout << \"selector_stringWithCString_encoding == \" << sel_getName(selector_stringWithCString_encoding) << std::endl;\n    \n    id aquaString = ((id (*)(id, SEL, const char *, int))objc_msgSend)((id)nsstring_class, selector_stringWithCString_encoding, \"NSAppearanceNameAqua\", 1);\n    \n    if (!aquaString)\n        return;\n    \n    //std::cout << \"aquaString == \" << aquaString << std::endl;\n    //std::cout << std::endl;\n    \n    // Next we need to get the named appearance from NSAppearance\n    Class nsappearance_class = objc_lookUpClass(\"NSAppearance\");\n    SEL selector_appearanceNamed = sel_registerName(\"appearanceNamed:\");\n    \n    if ((!nsappearance_class) || (!selector_appearanceNamed))\n        return;\n    \n    //std::cout << \"nsappearance_class == \" << nsappearance_class << std::endl;\n    //std::cout << \"class_getName(nsappearance_class) == \" << class_getName(nsappearance_class) << std::endl;\n    //std::cout << \"selector_appearanceNamed == \" << sel_getName(selector_appearanceNamed) << std::endl;\n    \n    id aquaAppearance = ((id (*)(id, SEL, id))objc_msgSend)((id)nsappearance_class, selector_appearanceNamed, aquaString);\n    \n    if (!aquaAppearance)\n        return;\n    \n    //std::cout << \"aquaAppearance == \" << aquaAppearance << std::endl;\n    //std::cout << std::endl;\n    \n    // Then get the shared NSApp object\n    Class nsapp_class = objc_lookUpClass(\"NSApplication\");\n    SEL selector_sharedApplication = sel_registerName(\"sharedApplication\");\n    \n    if ((!nsapp_class) || (!selector_sharedApplication))\n        return;\n    \n    //std::cout << \"nsapp_class == \" << nsapp_class << std::endl;\n    //std::cout << \"class_getName(nsapp_class) == \" << class_getName(nsapp_class) << std::endl;\n    //std::cout << \"selector_sharedApplication == \" << sel_getName(selector_sharedApplication) << std::endl;\n    \n    id sharedApplication = ((id (*)(id, SEL))objc_msgSend)((id)nsapp_class, selector_sharedApplication);\n    \n    if (!sharedApplication)\n        return;\n    \n    //std::cout << \"sharedApplication == \" << sharedApplication << std::endl;\n    //std::cout << std::endl;\n    \n    // Then call setAppearance: on NSApplication to force light mode\n    SEL selector_setAppearance = sel_registerName(\"setAppearance:\");\n    \n    if (!selector_setAppearance)\n        return;\n    \n    //std::cout << \"selector_setAppearance == \" << sel_getName(selector_setAppearance) << std::endl;\n    //std::cout << std::endl;\n    \n    // -[NSApplication setAppearance:] was added in 10.14, so we need to check availability first\n    if (class_respondsToSelector(nsapp_class, selector_setAppearance))\n        ((void (*)(id, SEL, id))objc_msgSend)(sharedApplication, selector_setAppearance, aquaAppearance);\n}\n#endif\n#endif\n#endif\n\n// This function switches the app to a dark theme, regardless of OS settings.  This is not the same as\n// \"dark mode\" on macOS, and should probably never be used on macOS; it's for Linux, where getting\n// Qt-based apps to obey the windowing system's preferred theme can be a battle.\n// Credit is due to Josip Medved at https://www.medo64.com/2020/08/dark-mode-for-qt-application/\n#ifndef __APPLE__\nstatic void linux_ForceDarkMode(void)\n{\n    QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n    \n    // Josip writes \"Just start with a good style (i.e. Fusion) and adjust its palette.\"  I think he\n    // sets the style to Fusion because some styles don't adjust to a changed palette well; they\n    // just have their own hard-coded palette.  Commenting out this line on macOS, for example,\n    // many UI elements look correctly \"dark\" but scrollers retain their \"light\" appearance.  So, it's\n    // not ideal to override whatever the default style would be, but it seems necessary to guarantee\n    // good results.  I've decided to make this subject to a user pref.\n    if (prefs.forceFusionStylePref())\n    {\n        qApp->setStyle(QStyleFactory::create(\"Fusion\"));\n    }\n    \n    // These numbers are modified from those provided by Josip, to better match the macOS dark mode\n    // appearance for consistency, so that our icons, syntax highlighting colors, etc., work well\n    if (prefs.forceDarkModePref())\n    {\n        QPalette newPalette;\n        newPalette.setColor(QPalette::Window,          QColor( 49,  50,  51));\n        newPalette.setColor(QPalette::WindowText,      QColor(255, 255, 255));\n        newPalette.setColor(QPalette::Base,            QColor( 29,  30,  31));\n        newPalette.setColor(QPalette::AlternateBase,   QColor(  9,  10,  11));\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))\n        newPalette.setColor(QPalette::PlaceholderText, QColor(101, 101, 101));\n#endif\n        newPalette.setColor(QPalette::Text,            QColor(255, 255, 255));\n        newPalette.setColor(QPalette::Button,          QColor( 49,  50,  51));\n        newPalette.setColor(QPalette::ButtonText,      QColor(255, 255, 255));\n        newPalette.setColor(QPalette::BrightText,      QColor(255, 255, 255));\n        newPalette.setColor(QPalette::Highlight,       QColor( 22,  86, 114));\n        newPalette.setColor(QPalette::HighlightedText, QColor(255, 255, 255));\n        \n        newPalette.setColor(QPalette::Light,           QColor( 75,  75,  75));\n        newPalette.setColor(QPalette::Midlight,        QColor( 60,  60,  60));\n        //QPalette::Button should fall approximately midway here\n        newPalette.setColor(QPalette::Mid,             QColor( 35,  35,  35));\n        newPalette.setColor(QPalette::Dark,            QColor( 25,  25,  25));\n        newPalette.setColor(QPalette::Shadow,          QColor( 0,    0,   0));\n        \n        newPalette.setColor(QPalette::Disabled, QPalette::Text,         QColor(101, 101, 101));\n        newPalette.setColor(QPalette::Disabled, QPalette::WindowText,   QColor(101, 101, 101));\n        newPalette.setColor(QPalette::Disabled, QPalette::ButtonText,   QColor(101, 101, 101));\n        \n        qApp->setPalette(newPalette);\n    }\n}\n#endif\n\n\nint main(int argc, char *argv[])\n{\n    // Check that the run-time Qt version matches the compile-time Qt version\n    if (strcmp(qVersion(), QT_VERSION_STR) != 0)\n    {\n        std::cout << \"Run-time Qt version \" << qVersion() << \" does not match compile-time Qt version \" << QT_VERSION_STR << std::endl;\n        exit(EXIT_FAILURE);\n    }\n    \n    // Check for running under ASAN and log to confirm it is enabled; see SLiM.pro to enable it\n#if defined(__has_feature)\n#  if __has_feature(address_sanitizer)\n    std::cout << \"***** ASAN enabled *****\" << std::endl;\n#  endif\n#endif\n    \n    // Start the application\n    QApplication app(argc, argv);\n    QtSLiMAppDelegate appDelegate(nullptr);\n    \n    // Reset the locale to \"C\" regardless of user locale; see issue #81\n    {\n        /*{\n            qDebug() << \"QLocale().name() before:\" << QLocale().name();\n            \n            std::locale loc;\n            std::cout << \"std::locale name() before : \" << loc.name() << std::endl;\n            \n            char *loc_c = setlocale(LC_ALL, NULL);\n            std::cout << \"setlocale() name before :\" << loc_c << std::endl;\n        }*/\n        \n        setlocale(LC_ALL, \"C\");          // Might just do LC_NUMERIC, but let's avoid surprises...\n        QLocale::setDefault(QLocale(\"C\"));\n        \n        /*{\n            qDebug() << \"QLocale().name() after:\" << QLocale().name();\n            \n            std::locale loc;\n            std::cout << \"std::locale name() after : \" << loc.name() << std::endl;\n            \n            char *loc_c = setlocale(LC_ALL, nullptr);\n            std::cout << \"setlocale() name after :\" << loc_c << std::endl;\n        }*/\n        \n        // Test that the locale is working for us; is the decimal separator a period or a comma?\n        double converted_value = strtod(\"0.5\", nullptr);\n        \n        if (fabs(0.5 - converted_value) > 1e-10)\n        {\n            std::cout << \"Locale issue: strtod() is not translating numbers according to the C locale.\";\n            exit(EXIT_FAILURE);\n        }\n    }\n    \n    // On macOS, force light mode appearance.  BCH 1/17/2021: We now try to force light mode only when\n    // compiled against a Qt version earlier than 5.15.2 (since Qt did not support dark mode well prior\n    // to that version).  Since the double-click install version is built against 5.15.2, this should\n    // mean that most macOS users get dark mode support.\n#ifdef __APPLE__\n#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 2))\n#warning Building on macOS with a Qt version less than 5.15.2; dark/light mode may not work correctly\n    //macos_ForceLightMode();\n#endif\n#endif\n    \n    // On Linux, force dark mode appearance if the user has chosen that.  This is Linux-only because\n    // on macOS we follow the macOS dark mode setting, and Qt largely follows it for us.\n#ifndef __APPLE__\n    linux_ForceDarkMode();\n#endif\n    \n    // Tell Qt to use high-DPI pixmaps for icons; not needed in Qt6, which is always high-DPI\n#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))\n    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);\n#endif\n    \n    // On macOS, turn off the automatic quit on last window close, for Qt 5.15.2.\n    // Builds against older Qt versions will just quit on the last window close, because\n    // QTBUG-86874 and QTBUG-86875 prevent this from working.\n#ifdef __APPLE__\n#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 2))\n    app.setQuitOnLastWindowClosed(false);\n#endif\n#endif\n    \n    // Parse the command line\n    QCommandLineParser parser;\n    \n    parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);\n    parser.setApplicationDescription(QCoreApplication::applicationName());\n    parser.addHelpOption();\n    parser.addVersionOption();\n    parser.addPositionalArgument(\"file\", \"The file(s) to open.\");\n    parser.process(app);\n    \n    // Open windows\n    QtSLiMWindow *mainWin = nullptr;\n    const QStringList posArgs = parser.positionalArguments();\n    \n    for (const QString &file : posArgs)\n    {\n        QtSLiMWindow *newWin = new QtSLiMWindow(file);\n        newWin->tile(mainWin);\n        newWin->show();\n        mainWin = newWin;\n    }\n    \n    if (!mainWin)\n    {\n        QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance();\n        \n        if (prefs.appStartupPref() == 1)\n        {\n            // create a new window\n            mainWin = new QtSLiMWindow(QtSLiMWindow::ModelType::WF, /* includeComments */ true);\n        }\n        else if (prefs.appStartupPref() == 2)\n        {\n            // run an open panel, which will return a window to show, or nullptr\n            mainWin = qtSLiMAppDelegate->open(nullptr);\n            \n            // if no file was opened, create a new window after all\n            if (!mainWin)\n                mainWin = new QtSLiMWindow(QtSLiMWindow::ModelType::WF, /* includeComments */ true);\n        }\n    }\n    \n    if (mainWin)\n    {\n        mainWin->show();\n\n        // Ensures the main window is visible and exposed on startup\n        QtSLiMMakeWindowVisibleAndExposed(mainWin);\n    }\n    \n    appDelegate.appDidFinishLaunching(mainWin);\n    \n    // Run the event loop\n    int appReturn = app.exec();\n    \n#if SLIM_LEAK_CHECKING\n    clean_up_leak_false_positives();\n#endif\n    \n    return appReturn;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.1 - Temporally varying selection.txt",
    "content": "// Keywords: environmental change\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // beneficial\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.995,0.005));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n2000:3999 mutationEffect(m2) { return 1.0; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.2 - Spatially varying selection.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"e\", 0.1);   // deleterious in p2\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.1);   // weak migration p2 -> p1\n\tp2.setMigrationRates(p1, 0.5);   // strong migration p1 -> p2\n}\nmutationEffect(m2, p2) { return 1/effect; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis I.txt",
    "content": "// Keywords: gene interactions\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // epistatic mut 1\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.1);  // epistatic mut 2\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);    // epistatic locus 1\n\tinitializeGenomicElementType(\"g3\", m3, 1);    // epistatic locus 2\n\tinitializeGenomicElement(g1, 0, 10000);\n\tinitializeGenomicElement(g2, 10001, 13000);\n\tinitializeGenomicElement(g1, 13001, 70000);\n\tinitializeGenomicElement(g3, 70001, 73000);\n\tinitializeGenomicElement(g1, 73001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m3) {\n\tif (individual.countOfMutationsOfType(m2))\n\t\treturn 0.5;\n\telse\n\t\treturn effect;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis II.txt",
    "content": "// Keywords: gene interactions\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // epistatic mut 1\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.1);  // epistatic mut 2\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);    // epistatic locus 1\n\tinitializeGenomicElementType(\"g3\", m3, 1);    // epistatic locus 2\n\tinitializeGenomicElement(g1, 0, 10000);\n\tinitializeGenomicElement(g2, 10001, 13000);\n\tinitializeGenomicElement(g1, 13001, 70000);\n\tinitializeGenomicElement(g3, 70001, 73000);\n\tinitializeGenomicElement(g1, 73001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m3) {\n\tif (individual.countOfMutationsOfType(m2))\n\t\treturn 0.5;\n\telse\n\t\treturn effect;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // balanced\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\treturn 1.5 - sim.mutationFrequencies(p1, mut);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // positive freq. dep.\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\treturn 1.0 + sim.mutationFrequencies(p1, mut);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection III.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // positive freq. dep.\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\tdominance = asInteger(homozygous) * 0.5 + 0.5;\n\treturn 1.0 + sim.mutationFrequencies(p1, mut) * dominance;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.4.2 - Fitness as a function of population composition, Cultural effects on fitness.txt",
    "content": "// Keywords: culture, non-genetic inheritance\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);   // lactase-promoting\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n10000 early() { sim.simulationFinished(); }\nlate() {\n\t// Assign a cultural group: milk-drinker == T, non-milk-drinker == F\n\tp1.individuals.tagL0 = (runif(1000) < 0.5);\n}\nmutationEffect(m2) {\n\tif (individual.tagL0)\n\t\treturn effect;      // beneficial for milk-drinkers\n\telse\n\t\treturn 1.0;         // neutral for non-milk-drinkers\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.4.3 - Fitness as a function of population composition, Kin selection and the green-beard effect.txt",
    "content": "// Keywords: kin selection, inclusive fitness, selfish gene, greenbeard effect\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // green-beard\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1 late() {\n\ttarget = sample(p1.haplosomes, 100);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1: late() {\n\tp1.individuals.tag = 0;\n\t\n\tfor (rep in 1:50) {\n\t\tindividuals = sample(p1.individuals, 2);\n\t\ti0 = individuals[0];\n\t\ti1 = individuals[1];\n\t\ti0greenbeards = i0.countOfMutationsOfType(m2);\n\t\ti1greenbeards = i1.countOfMutationsOfType(m2);\n\t\t\n\t\tif (i0greenbeards & i1greenbeards) {\n\t\t\talleleSum = i0greenbeards + i1greenbeards;\n\t\t\ti0.tag = i0.tag - alleleSum;       // cost to i0\n\t\t\ti1.tag = i1.tag + alleleSum * 2;   // benefit to i1\n\t\t}\n\t}\n}\nmutationEffect(m2) { return 1.0 + individual.tag / 10; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.5 - Changing selection coefficients with setSelectionCoeff().txt",
    "content": "// Keywords: environmental change, temporal change\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1);    // balanced\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nlate() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\tfor (mut in m2muts, freq in freqs)\n\t\tmut.setSelectionCoeff(0.5 - freq);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.6 - Varying the dominance coefficient among mutations I.txt",
    "content": "// Keywords: dominance coefficients, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.05);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation(m2) {\n\tmut.setValue(\"dom\", runif(1));\n\treturn T;\n}\nmutationEffect(m2) {\n   if (homozygous)\n      return 1.0 + mut.selectionCoeff;\n   else\n      return 1.0 + mut.getValue(\"dom\") * mut.selectionCoeff;\n}\n100000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 10.6 - Varying the dominance coefficient among mutations II.txt",
    "content": "// Keywords: dominance coefficients, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tfor (i in 0:10)\n\t\tinitializeMutationType(i, i * 0.1, \"n\", 0.0, 0.02);\n\tinitializeGenomicElementType(\"g1\", m0, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation(m0) {\n\ts = mut.selectionCoeff;\n\td = asInteger(min(floor(abs(s) * 100.0), 10.0));\n\tmut.setMutationType(d);\n\treturn T;\n}\n100000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 11.1 - Assortative mating.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.setValue(\"FST\", 0.0);\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.1);\n\tp2.setMigrationRates(p1, 0.1);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\nmutationEffect(m2, p2) { return 0.2; }\n2000: early() {\n\t// tag all individuals with their m2 mutation count\n\tinds = sim.subpopulations.individuals;\n\tinds.tag = inds.countOfMutationsOfType(m2);\n\t\n\t// precalculate the mating weights vectors\n\tfor (subpop in c(p1,p2))\n\t{\n\t\thas_m2 = (subpop.individuals.tag > 0);\n\t\tsubpop.setValue(\"weights1\", ifelse(has_m2, 2.0, 1.0));\n\t\tsubpop.setValue(\"weights2\", ifelse(has_m2, 0.5, 1.0));\n\t}\n}\n2000: mateChoice() {\n\tif (individual.tag > 0)\n\t\treturn weights * sourceSubpop.getValue(\"weights1\");\n\telse\n\t\treturn weights * sourceSubpop.getValue(\"weights2\");\n}\n10000: late() {\n\tFST = calcFST(p1.haplosomes, p2.haplosomes);\n\tsim.setValue(\"FST\", sim.getValue(\"FST\") + FST);\n}\n19999 late() {\n\tcat(\"Mean FST at equilibrium: \" + (sim.getValue(\"FST\") / 10000));\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 11.2 - Sequential mate search I.txt",
    "content": "// Keywords: choosy, choosiness, ornament, mate choice\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);     // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.025);  // ornamental\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1:10001 early() {\n\tif (sim.cycle % 1000 == 1) {\n\t\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\t\tosize = fixedMuts * 2 + p1.individuals.countOfMutationsOfType(m2);\n\t\tcatn(sim.cycle + \": Mean ornament size == \" + mean(osize));\n\t}\n}\nmateChoice() {\n\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\tfor (attempt in 1:5)\n\t{\n\t\tmate = sample(p1.individuals, 1, T, weights);\n\t\tosize = fixedMuts * 2 + mate.countOfMutationsOfType(m2);\n\t\t\n\t\tif (runif(1) < log(osize + 1) * 0.1 + attempt * 0.1)\n\t\t\treturn mate;\n\t}\n\treturn float(0);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 11.2 - Sequential mate search II.txt",
    "content": "// Keywords: choosy, choosiness, ornament, mate choice\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);     // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.025);  // ornamental\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1:10001 early() {\n\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\tinds = p1.individuals;\n\tosize = fixedMuts * 2 + inds.countOfMutationsOfType(m2);\n\tinds.tagF = log(osize + 1) * 0.1;\n\t\n\tif (sim.cycle % 1000 == 1)\n\t\tcatn(sim.cycle + \": Mean ornament size == \" + mean(osize));\n}\nmateChoice() {\n\tfor (attempt in 1:5)\n\t{\n\t\tmate = sample(p1.individuals, 1, T, weights);\n\t\t\n\t\tif (runif(1) < mate.tagF + attempt * 0.1)\n\t\t\treturn mate;\n\t}\n\treturn float(0);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 11.3 - Gametophytic self-incompatibility.txt",
    "content": "// Keywords: modifyChild(), plants, pollen\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // S-locus mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 21000);\n\tinitializeGenomicElement(g1, 21001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() {\n\tcat(\"m1 mutation count: \" + sim.countOfMutationsOfType(m1) + \"\\n\");\n\tcat(\"m2 mutation count: \" + sim.countOfMutationsOfType(m2) + \"\\n\");\n}\nmodifyChild(p1) {\n\tpollenSMuts = child.haploidGenome2.mutationsOfType(m2);\n\tstyleSMuts1 = parent1.haploidGenome1.mutationsOfType(m2);\n\tstyleSMuts2 = parent1.haploidGenome2.mutationsOfType(m2);\n\tif (identical(pollenSMuts, styleSMuts1))\n\t\tif (runif(1) < 0.99)\n\t\t\treturn F;\n\tif (identical(pollenSMuts, styleSMuts2))\n\t\tif (runif(1) < 0.99)\n\t\t\treturn F;\n\treturn T;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.1 - Social learning of cultural traits.txt",
    "content": "// Keywords: non-genetic inheritance\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);   // lactase-promoting\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.individuals.tagL0 = (runif(1000) < 0.5);\n}\nmodifyChild() {\n\tparentCulture = mean(c(parent1.tagL0, parent2.tagL0));\n\tchildCulture = (runif(1) < 0.1 + 0.8 * parentCulture);\n\tchild.tagL0 = childCulture;\n\treturn T;\n}\nmutationEffect(m2) {\n\tif (individual.tagL0)\n\t\treturn effect;      // beneficial for milk-drinkers\n\telse\n\t\treturn 1.0;         // neutral for non-milk-drinkers\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.2 - Lethal epistasis I.txt",
    "content": "// Keywords: gene interaction\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);  // mutation A\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.5);  // mutation B\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m2, 10000);  // add A\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m3, 20000);  // add B\n}\nmodifyChild() {\n\thasMutA = any(child.haplosomes.countOfMutationsOfType(m2) > 0);\n\thasMutB = any(child.haplosomes.countOfMutationsOfType(m3) > 0);\n\tif (hasMutA & hasMutB)\n\t\treturn F;\n\treturn T;\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.2 - Lethal epistasis II.txt",
    "content": "// Keywords: gene interaction\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);  // mutation A\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.5);  // mutation B\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m2, 10000);  // add A\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m3, 20000);  // add B\n}\nmodifyChild() {\n\tmutACount = sum(child.haplosomes.countOfMutationsOfType(m2));\n\tmutBCount = sum(child.haplosomes.countOfMutationsOfType(m3));\n\tif ((mutACount == 2) & (mutBCount == 2))\n\t\treturn F;\n\treturn T;\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.3 - Simulating gene drive.txt",
    "content": "// Keywords: migration, dispersal, CRISPR gene drive\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.1);  // MCR complex\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 0:5)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 1:5)\n\t\tsim.subpopulations[i].setMigrationRates(i-1, 0.001);\n\tfor (i in 0:4)\n\t\tsim.subpopulations[i].setMigrationRates(i+1, 0.1);\n}\n100 late() {\n\tp0.haplosomes[0:49].addNewDrawnMutation(m2, 10000);\n}\n100:10000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = any(sim.substitutions.mutationType == m2);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\nmutationEffect(m2) {\n\treturn 1.5 - subpop.id * 0.15;\n}\n100:10000 modifyChild() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 1)\n\t{\n\t\thasMutOnChromosome1 = child.haploidGenome1.containsMutations(mut);\n\t\thasMutOnChromosome2 = child.haploidGenome2.containsMutations(mut);\n\t\tif (hasMutOnChromosome1 & !hasMutOnChromosome2)\n\t\t\tchild.haploidGenome2.addMutations(mut);\n\t\telse if (hasMutOnChromosome2 & !hasMutOnChromosome1)\n\t\t\tchild.haploidGenome1.addMutations(mut);\n\t}\n\treturn T;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.4 - Suppressing hermaphroditic selfing.txt",
    "content": "// Keywords: selfing\n\n// NOTE: This model is now obsolete!  Is it now recommended\n// that you use this call in your initialize() callback\n// instead of following this recipe:\n//\n//    initializeSLiMOptions(preventIncidentalSelfing=T);\n//\n// This recipe still works, but is much slower than using\n// that configuration flag.\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nmodifyChild()\n{\n\t// prevent hermaphroditic selfing\n\tif (parent1 == parent2)\n\t\treturn F;\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 12.5 - Tracking separate sexes in script.txt",
    "content": "// Keywords: separate sexes, sexual model, sex chromosomes, sex ratio, Wolbachia\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.tagL0 = repEach(c(F,T), 250);  // f==F, m==T\n}\nmodifyChild() {\n\tif (parent1.tagL0 == parent2.tagL0)\n\t\treturn F;\n\tchild.tagL0 = (runif(1) <= 0.5);\n\treturn T;\n}\n1: late() {\n\tcatn(\"Sex ratio (M:M+F): \" + mean(p1.individuals.tagL0));\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.1 - Polygenic selection.txt",
    "content": "// Keywords: quantitative trait, polygenic selection\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // QTLs\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 30000);\n\tinitializeGenomicElement(g1, 30001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nfitnessEffect() {\n\tphenotype = individual.countOfMutationsOfType(m2);\n\treturn 1.5 - (phenotype - 10.0)^2 * 0.005;\n}\n5000 late() {\n\tprint(sim.mutationFrequencies(NULL, sim.mutationsOfType(m2)));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.2 - A simple model of variable QTL effect sizes.txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.5);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 30000);\n\tinitializeGenomicElement(g1, 30001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() { sim.addSubpop(\"p1\", 500); }\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.5 - (phenotypes - 10.0)^2 * 0.005;\n\t\n\tif (sim.cycle % 100 == 0)\n\t\tcatn(sim.cycle + \": Mean phenotype == \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.3 - A model of discrete QTL effects across multiple chromosomes.txt",
    "content": "// Keywords: migration, dispersal, QTL, quantitative trait loci\n\ninitialize() {\n\t// neutral mutations in non-coding regions\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// mutations representing alleles in QTLs\n\tscriptForQTLs = \"if (runif(1) < 0.5) -1; else 1;\";\n\tinitializeMutationType(\"m2\", 0.5, \"s\", scriptForQTLs);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tm2.convertToSubstitution = F;\n\tm2.mutationStackPolicy = \"l\";\n\t\n\t// set up our chromosome: 10 QTLs, surrounded by neutral regions\n\tdefineConstant(\"C\", 10);    // number of QTLs / chromosomes\n\tdefineConstant(\"W\", 1000);  // size of neutral buffer on each side\n\t\n\tfor (i in 1:C)\n\t{\n\t\tinitializeChromosome(i, W*2 + 1);\n\t\t\n\t\tinitializeGenomicElement(g1, 0, W-1);\n\t\tinitializeGenomicElement(g2, W, W);\n\t\tinitializeGenomicElement(g1, W+1, W+1 + W-1);\n\t\t\n\t\tinitializeMutationRate(1e-6);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\t\n\t// set up migration; comment these out for zero gene flow\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n\t\n\t// optional: give m2 mutations to everyone, as standing variation\n\tindividuals = sim.subpopulations.individuals;\n\t\n\tfor (i in 1:C)\n\t{\n\t\tg = sim.subpopulations.individuals.haplosomesForChromosomes(i);\n\t\tisPlus = asLogical(rbinom(size(g), 1, 0.5));\n\t\tg[isPlus].addNewMutation(m2, 1.0, W);\n\t\tg[!isPlus].addNewMutation(m2, -1.0, W);\n\t}\n}\nmutationEffect(m2) { return 1.0; }\n1: late() {\n\t// evaluate and save the additive effects of QTLs\n\tfor (subpop in c(p1,p2))\n\t{\n\t\tinds = subpop.individuals;\n\t\tphenotype = inds.sumOfMutationsOfType(m2);\n\t\toptimum = (subpop == p1 ? 10.0 else -10.0);\n\t\tinds.fitnessScaling = 1.0 + dnorm(optimum - phenotype, 0.0, 5.0);\n\t\tinds.tagF = phenotype;\n\t}\n}\nmateChoice() {\n\tphenotype = individual.tagF;\n\tothers = sourceSubpop.individuals.tagF;\n\treturn weights * dnorm(others, phenotype, 5.0);\n}\nc(2,2001) early() {\n\tcat(\"-------------------------------\\n\");\n\tcat(\"Output for end of cycle \" + (sim.cycle - 1) + \":\\n\\n\");\n\t\n\t// Output population fitness values\n\tcat(\"p1 mean fitness = \" + mean(p1.cachedFitness(NULL)) + \"\\n\");\n\tcat(\"p2 mean fitness = \" + mean(p2.cachedFitness(NULL)) + \"\\n\");\n\t\n\t// Output population additive QTL-based phenotypes\n\tcat(\"p1 mean phenotype = \" + mean(p1.individuals.tagF) + \"\\n\");\n\tcat(\"p2 mean phenotype = \" + mean(p2.individuals.tagF) + \"\\n\");\n\t\n\t// Output frequencies of +1/-1 alleles at the QTLs\n\tmuts = sim.mutationsOfType(m2);\n\tplus = muts[muts.selectionCoeff == 1.0];\n\tminus = muts[muts.selectionCoeff == -1.0];\n\t\n\tcat(\"\\nOverall frequencies:\\n\\n\");\n\tfor (i in 1:C)\n\t{\n\t\tiPlus = plus[plus.chromosome.id == i];\n\t\tiMinus = minus[minus.chromosome.id == i];\n\t\tpf = sum(sim.mutationFrequencies(NULL, iPlus));\n\t\tmf = sum(sim.mutationFrequencies(NULL, iMinus));\n\t\tpf1 = sum(sim.mutationFrequencies(p1, iPlus));\n\t\tmf1 = sum(sim.mutationFrequencies(p1, iMinus));\n\t\tpf2 = sum(sim.mutationFrequencies(p2, iPlus));\n\t\tmf2 = sum(sim.mutationFrequencies(p2, iMinus));\n\t\t\n\t\tcat(\"   QTL \" + i + \": f(+) == \" + pf + \", f(-) == \" + mf + \"\\n\");\n\t\tcat(\"         in p1: f(+) == \" + pf1 + \", f(-) == \" + mf1 + \"\\n\");\n\t\tcat(\"         in p2: f(+) == \" + pf2 + \", f(-) == \" + mf2 + \"\\n\\n\");\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.4 - A quantitative genetics model with heritability.txt",
    "content": "// Keywords: QTLs, quantitative trait loci, heritability, environmental variance, breeding values, additive genetic variance\n\ninitialize() {\n\tdefineConstant(\"h2\", 0.1);     // target heritability\n\n\tinitializeMutationRate(1e-6);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);  // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n1: late() {\n\t// sum the additive effects of QTLs\n\tinds = sim.subpopulations.individuals;\n\tadditive = inds.sumOfMutationsOfType(m2);\n\t\n\t// model environmental variance, according to the target heritability\n\tV_A = sd(additive)^2;\n\tV_E = (V_A - h2 * V_A) / h2;    // from h2 == V_A / (V_A + V_E)\n\tenv = rnorm(size(inds), 0.0, sqrt(V_E));\n\t\n\t// set fitness effects and remember phenotypes\n\tphenotypes = additive + env;\n\tinds.fitnessScaling = 1.0 + dnorm(10.0 - phenotypes, 0.0, 5.0);\n\tinds.tagF = phenotypes;\n}\nmutationEffect(m2) {\n\treturn 1.0;   // QTLs are neutral; fitness effects are handled below\n}\n1:100000 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"Mean phenotype:\\n\");\n\t\n\tmeanPhenotype = mean(p1.individuals.tagF);\n\tcat(format(\"%.2f\", meanPhenotype));\n\t\n\t// Run until we reach the fitness peak\n\tif (abs(meanPhenotype - 10.0) > 0.1)\n\t{\n\t\tcat(\", \");\n\t\treturn;\n\t}\n\t\n\tcat(\"\\n\\n-------------------------------\\n\");\n\tcat(\"QTLs at cycle \" + sim.cycle + \":\\n\\n\");\n\t\n\tqtls = sim.mutationsOfType(m2);\n\tf = sim.mutationFrequencies(NULL, qtls);\n\ts = qtls.selectionCoeff;\n\tp = qtls.position;\n\to = qtls.originTick;\n\tindices = order(f, F);\n\t\n\tfor (i in indices)\n\t\tcat(\"   \" + p[i] + \": s = \" + s[i] + \", f == \" + f[i] + \", o == \" + o[i] + \"\\n\");\n\t\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.5 - A QTL-based model with two quantitative phenotypic traits and pleiotropy.txt",
    "content": "// Keywords: QTL, quantitative trait loci, pleiotropy, M-matrix, live plotting, mutation()\n\nfunction (void)updatePlot(void)\n{\n\tif (exists(\"slimgui\"))\n\t{\n\t\tplot = slimgui.createPlot(\"Adaptive Walk\",\n\t\t\txrange=c(-10,30), yrange=c(-30,10),\n\t\t\txlab=\"phenotype 1\", ylab=\"phenotype 2\");\n\t\tplot.points(0, 0, symbol=21, color=\"red\", size=3.0);\n\t\tplot.points(20, -20, symbol=21, color=\"green\", size=3.0);\n\t\tplot.text(0, 4, \"start\", size=15);\n\t\tplot.text(20, -24, \"optimum\", size=15);\n\t\tplot.lines(HIST[,0], HIST[,1], \"black\");\n\t\tplot.points(HIST[,0], HIST[,1], 16, \"black\", size=0.5);\n\t}\n}\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // QTLs\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// g1 is a neutral region, g2 is a QTL\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", c(m1,m2), c(1.0, 0.1));\n\t\n\t// chromosome of length 100 kb with two QTL regions\n\tinitializeGenomicElement(g1, 0, 39999);\n\tinitializeGenomicElement(g2, 40000, 49999);\n\tinitializeGenomicElement(g1, 50000, 79999);\n\tinitializeGenomicElement(g2, 80000, 89999);\n\tinitializeGenomicElement(g1, 90000, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// QTL-related constants used below\n\tdefineConstant(\"QTL_mu\", c(0, 0));\n\tdefineConstant(\"QTL_cov\", 0.25);\n\tdefineConstant(\"QTL_sigma\", matrix(c(1,QTL_cov,QTL_cov,1), nrow=2));\n\tdefineConstant(\"QTL_optima\", c(20, -20));\n\t\n\tcatn(\"\\nQTL DFE means: \");\n\tprint(QTL_mu);\n\tcatn(\"\\nQTL DFE variance-covariance matrix: \");\n\tprint(QTL_sigma);\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tdefineGlobal(\"HIST\", matrix(c(0.0, 0.0), nrow=1));\n\tupdatePlot();\n}\n\nmutation(m2) {\n\t// draw mutational effects for the new m2 mutation\n\teffects = rmvnorm(1, QTL_mu, QTL_sigma);\n\tmut.setValue(\"e0\", effects[0]);\n\tmut.setValue(\"e1\", effects[1]);\n\t\n\t// remember all drawn effects, for our final output\n\told_effects = sim.getValue(\"all_effects\");\n\tsim.setValue(\"all_effects\", rbind(old_effects, effects));\n\t\n\treturn T;\n}\n\nlate() {\n\tfor (ind in sim.subpopulations.individuals)\n\t{\n\t\t// construct phenotypes from additive effects of QTL mutations\n\t\tmuts = ind.haplosomes.mutationsOfType(m2);\n\t\tphenotype0 = size(muts) ? sum(muts.getValue(\"e0\")) else 0.0;\n\t\tphenotype1 = size(muts) ? sum(muts.getValue(\"e1\")) else 0.0;\n\t\tind.setValue(\"phenotype0\", phenotype0);\n\t\tind.setValue(\"phenotype1\", phenotype1);\n\t\t\n\t\t// calculate fitness effects\n\t\teffect0 = 1.0 + dnorm(QTL_optima[0] - phenotype0, 0.0, 20.0) * 10.0;\n\t\teffect1 = 1.0 + dnorm(QTL_optima[1] - phenotype1, 0.0, 20.0) * 10.0;\n\t\tind.fitnessScaling = effect0 * effect1;\n\t}\n}\n\n1:1000000 late() {\n\t// output, run every 1000 cycles\n\tif (sim.cycle % 1000 != 0)\n\t\treturn;\n\t\n\t// print final phenotypes versus their optima\n\tinds = sim.subpopulations.individuals;\n\tp0_mean = mean(inds.getValue(\"phenotype0\"));\n\tp1_mean = mean(inds.getValue(\"phenotype1\"));\n\t\n\tcatn();\n\tcatn(\"Cycle: \" + sim.cycle);\n\tcatn(\"Mean phenotype 0: \" + p0_mean + \" (\" + QTL_optima[0] + \")\");\n\tcatn(\"Mean phenotype 1: \" + p1_mean + \" (\" + QTL_optima[1] + \")\");\n\t\n\t// update our plot\n\tdefineGlobal(\"HIST\", rbind(HIST, c(p0_mean, p1_mean)));\n\tupdatePlot();\n\t\n\t// keep running until we get within 10% of both optima\n\tif ((abs(p0_mean - QTL_optima[0]) > abs(0.1 * QTL_optima[0])) |\n\t\t(abs(p1_mean - QTL_optima[1]) > abs(0.1 * QTL_optima[1])))\n\t\treturn;\n\t\n\t// we are done with the main adaptive walk; print final output\n\t\n\t// get the QTL mutations and their frequencies\n\tm2muts = sim.mutationsOfType(m2);\n\tm2freqs = sim.mutationFrequencies(NULL, m2muts);\n\t\n\t// sort those vectors by frequency\n\to = order(m2freqs, ascending=F);\n\tm2muts = m2muts[o];\n\tm2freqs = m2freqs[o];\n\t\n\t// get the effect sizes\n\tm2e0 = m2muts.getValue(\"e0\");\n\tm2e1 = m2muts.getValue(\"e1\");\n\t\n\t// now output a list of the QTL mutations and their effect sizes\n\tcatn(\"\\nQTL mutations (f: e0, e1):\");\n\tfor (i in seqAlong(m2muts))\n\t\tcatn(m2freqs[i] + \": \" + m2e0[i] + \", \" + m2e1[i]);\n\t\n\t// output covariances\n\tfixed_m2 = m2muts[m2freqs == 1.0];\n\tcov_fixed = cov(fixed_m2.getValue(\"e0\"), fixed_m2.getValue(\"e1\"));\n\teffects = sim.getValue(\"all_effects\");\n\tcov_drawn = cov(drop(effects[,0]), drop(effects[,1]));\n\t\n\tcatn(\"\\nCovariance of effects among fixed QTLs: \" + cov_fixed);\n\tcatn(\"\\nCovariance of effects specified by the QTL DFE: \" + QTL_cov);\n\tcatn(\"\\nCovariance of effects across all QTL draws: \" + cov_drawn);\n\t\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.6 - A variety of fitness functions I (stabilizing selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tscale = dnorm(5.0, 5.0, 2.0);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, 5.0, 2.0) / scale;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.6 - A variety of fitness functions II (directional selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + phenotypes * 0.12;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.6 - A variety of fitness functions III (disruptive selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tscale = dnorm(0.0, 0.0, 2.0);\n\tinds.fitnessScaling = 1.5 - dnorm(phenotypes, 0.0, 2.0) / scale;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.6 - A variety of fitness functions IV (truncation selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tcat(\"Phenotypes: \" + mean(phenotypes));\n}\n10001: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = ifelse(phenotypes < 0.0, 0.0, 1.0);\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n15000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 13.7 - Negative frequency-dependence on a quantitative trait.txt",
    "content": "// Keywords: quantitative trait, negative frequency-dependence, squashed stabilizing selection\n\ninitialize() {\n\tdefineConstant(\"COMP\", T);\t// is competition enabled?\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1:5000 late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tstabilizing = dnorm(phenotypes, 5.0, 2.0) / dnorm(5.0, 5.0, 2.0);\n\tcompetition = sapply(phenotypes, \"sum(dnorm(phenotypes, applyValue, 0.3));\");\n\tcompetition = 1.0 - (competition / size(inds)) / dnorm(0.0, 0.0, 0.3);\n\tinds.fitnessScaling = 1.0 + stabilizing * (COMP ? competition else 1.0);\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n\t\n\tif (exists(\"slimgui\"))\n\t{\n\t\t// plot the relative densities\n\t\tx1 = -2; x2 = 12; step = 0.5;\n\t\tcenters = seq(from=x1, to=x2 + step*0.01, by=step);\n\t\tbreaks = seq(from=x1 - step/2, to=x2 + step*0.51, by=step);\n\t\tintervals = findInterval(phenotypes, breaks, allInside=T);\n\t\tcounts = tabulate(intervals, length(centers) - 1);\n\t\tdensity = counts / max(counts);\n\t\t\n\t\tplot_pheno = slimgui.createPlot(\"Phenotypic Distribution\",\n\t\t\txrange=c(-0.5, 10.5), yrange=c(-0.05, 1.05),\n\t\t\txlab=\"Phenotypic trait value\", ylab=\"Relative density\",\n\t\t\twidth=500, height=250);\n\t\tplot_pheno.axis(1, at=c(0,5,10));\n\t\tplot_pheno.abline(v=5.0, color=\"cornflowerblue\", lwd=2);\n\t\tplot_pheno.lines(centers, density, lwd=2);\n\t\t\n\t\t// plot the fitness function\n\t\tpheno_vals = seq(-2, 12, by=0.1);\n\t\tstabilizing = dnorm(pheno_vals, 5.0, 2.0) / dnorm(5.0, 5.0, 2.0);\n\t\tcompetition = sapply(pheno_vals, \"sum(dnorm(phenotypes, applyValue, 0.3));\");\n\t\tcompetition = 1.0 - (competition / size(inds)) / dnorm(0.0, 0.0, 0.3);\n\t\tfitness = 1.0 + stabilizing * (COMP ? competition else 1.0);\n\t\t\n\t\tplot_fit = slimgui.createPlot(\"Fitness Function\",\n\t\t\txrange=c(-0.5, 10.5), yrange=c(0.95, 2.05),\n\t\t\txlab=\"Phenotypic trait value\", ylab=\"Fitness\",\n\t\t\twidth=500, height=250);\n\t\tplot_fit.axis(1, at=c(0,5,10));\n\t\tplot_fit.abline(v=5.0, color=\"cornflowerblue\", lwd=2);\n\t\tplot_fit.lines(pheno_vals, fitness, lwd=2);\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.1 - Relatedness, inbreeding, and heterozygosity.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees = T);\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n}\nmateChoice() {\n\t// Prefer relatives as mates\n\treturn weights * (individual.relatedness(sourceSubpop.individuals) + 0.01);\n}\n1000 late() {\n\t// Print mean heterozygosity across the population\n\theterozygosity = calcHeterozygosity(p1.haplosomes);\n\tcat(\"Mean heterozygosity = \" + heterozygosity + \"\\n\");\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.10 - Modeling transposable elements.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);               // chromosome length\n\tdefineConstant(\"teInitialCount\", 100);  // initial number of TEs\n\tdefineConstant(\"teJumpP\", 0.0001);      // TE jump probability\n\tdefineConstant(\"teDisableP\", 0.00005);  // disabling mut probability\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// transposon mutation type; also neutral, but red\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"#FF0000\";\n\t\n\t// disabled transposon mutation type; dark red\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"#700000\";\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tsim.tag = 0;\t// the next unique tag value to use for TEs\n\t\n\t// create some transposons at random positions\n\thaplosomes = sim.subpopulations.haplosomes;\n\tpositions = rdunif(teInitialCount, 0, L-1);\n\t\n\tfor (teIndex in 0:(teInitialCount-1))\n\t{\n\t\tpos = positions[teIndex];\n\t\tmut = haplosomes.addNewDrawnMutation(m2, pos);\n\t\tmut.tag = sim.tag;\n\t\tsim.tag = sim.tag + 1;\n\t}\n}\nmodifyChild() {\n\t// disable transposons with rate teDisableP\n\tfor (haplosome in child.haplosomes)\n\t{\n\t\ttes = haplosome.mutationsOfType(m2);\n\t\tteCount = tes.size();\n\t\tmutatedCount = teCount ? rpois(1, teCount * teDisableP) else 0;\n\t\t\n\t\tif (mutatedCount)\n\t\t{\n\t\t\tmutatedTEs = sample(tes, mutatedCount);\n\t\t\t\n\t\t\tfor (te in mutatedTEs)\n\t\t\t{\n\t\t\t\tall_disabledTEs = sim.mutationsOfType(m3);\n\t\t\t\tdisabledTE = all_disabledTEs[all_disabledTEs.tag == te.tag];\n\t\t\t\t\n\t\t\t\tif (size(disabledTE))\n\t\t\t\t{\n\t\t\t\t\t// use the existing disabled TE mutation\n\t\t\t\t\thaplosome.removeMutations(te);\n\t\t\t\t\thaplosome.addMutations(disabledTE);\n\t\t\t\t\tnext;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// make a new disabled TE mutation with the right tag\n\t\t\t\thaplosome.removeMutations(te);\n\t\t\t\tdisabledTE = haplosome.addNewDrawnMutation(m3, te.position);\n\t\t\t\tdisabledTE.tag = te.tag;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn T;\n}\nlate() {\n\t// make active transposons copy themselves with rate teJumpP\n\tfor (individual in sim.subpopulations.individuals)\n\t{\n\t\tfor (haplosome in individual.haplosomes)\n\t\t{\n\t\t\ttes = haplosome.mutationsOfType(m2);\n\t\t\tteCount = tes.size();\n\t\t\tjumpCount = teCount ? rpois(1, teCount * teJumpP) else 0;\n\t\t\t\n\t\t\tif (jumpCount)\n\t\t\t{\n\t\t\t\tjumpTEs = sample(tes, jumpCount);\n\t\t\t\t\n\t\t\t\tfor (te in jumpTEs)\n\t\t\t\t{\n\t\t\t\t\t// make a new TE mutation\n\t\t\t\t\tpos = rdunif(1, 0, L-1);\n\t\t\t\t\tjumpTE = haplosome.addNewDrawnMutation(m2, pos);\n\t\t\t\t\tjumpTE.tag = sim.tag;\n\t\t\t\t\tsim.tag = sim.tag + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n5000 late() {\n\t// print information on each TE, including the fraction of it disabled\n\tall_tes = sortBy(sim.mutationsOfType(m2), \"position\");\n\tall_disabledTEs = sortBy(sim.mutationsOfType(m3), \"position\");\n\thaplosomeCount = size(sim.subpopulations.haplosomes);\n\t\n\tcatn(\"Active TEs:\");\n\tfor (te in all_tes)\n\t{\n\t\tcat(\"   TE at \" + te.position + \": \");\n\t\t\n\t\tactive = sim.mutationCounts(NULL, te);\n\t\tdisabledTE = all_disabledTEs[all_disabledTEs.tag == te.tag];\n\t\t\n\t\tif (size(disabledTE) == 0)\n\t\t{\n\t\t\tdisabled = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdisabled = sim.mutationCounts(NULL, disabledTE);\n\t\t\tall_disabledTEs = all_disabledTEs[all_disabledTEs != disabledTE];\n\t\t}\n\t\t\n\t\ttotal = active + disabled;\n\t\t\n\t\tcat(\"frequency \" + format(\"%0.3f\", total / haplosomeCount) + \", \");\n\t\tcatn(round(active / total * 100) + \"% active\");\n\t}\n\t\n\tcatn(\"\\nCompletely disabled TEs: \");\n\tfor (te in all_disabledTEs)\n\t{\n\t\tfreq = sim.mutationFrequencies(NULL, te);\n\t\tcat(\"   TE at \" + te.position + \": \");\n\t\tcatn(\"frequency \" + format(\"%0.3f\", freq));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.11 - Modeling opposite ends of a chromosome I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeGenomicElement(g1, 9900000, 9999999);\n\tinitializeRecombinationRate(1.5e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.11 - Modeling opposite ends of a chromosome II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeGenomicElement(g1, 100000, 199999);\n\t\n\trates = c(1.5e-7, 0.473642, 1.5e-7);\n\tends = c(99999, 100000, 199999);\n\tinitializeRecombinationRate(rates, ends);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.12 - Visualizing ancestry and admixture with mutation() callbacks.txt",
    "content": "// Keywords: mutation types, tracking, true local ancestry, admixture, introgression, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\t\n\t// neutral and beneficial for p1\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.color = \"yellow\";\n\tm1.colorSubstitution = \"yellow\";\n\t\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.color = \"red\";\n\tm2.colorSubstitution = \"red\";\n\t\n\t// neutral and beneficial for p2\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.color = \"blue\";\n\tm3.colorSubstitution = \"blue\";\n\t\n\tinitializeMutationType(\"m4\", 0.5, \"f\", 0.1);\n\tm4.color = \"green\";\n\tm4.colorSubstitution = \"green\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.0001));\n\tinitializeGenomicElement(g1, 0, 9999999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tsim.addSubpop(\"p2\", 1000);\n}\nmutation(m1, p2)\n{\n\t// use m3 instead of m1, in p2\n\tmut.setMutationType(m3);\n\treturn T;\n}\nmutation(m2, p2)\n{\n\t// use m4 instead of m2, in p2\n\tmut.setMutationType(m4);\n\treturn T;\n}\n10000 early() {\n\tsim.chromosome.setMutationRate(0.0);\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n}\n15000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback I.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\ninitialize() {\n\t// an m2 mutation is \"A\"\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// an m3 mutation is \"a\"\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"cornflowerblue\";\n\t\n\t// enforce mutually exclusive replacement\n\tc(m2,m3).mutationStackGroup = 1;\n\tc(m2,m3).mutationStackPolicy = 'l';\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3), c(1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(1e-4);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// create the canonical mutation objects\n\ttarget = p1.haplosomes[0];\n\ttarget.addNewDrawnMutation(m2, 0:99);\n\tdefineConstant(\"MUT2\", target.mutations);\n\ttarget.removeMutations();\n\ttarget.addNewDrawnMutation(m3, 0:99);\n\tdefineConstant(\"MUT3\", target.mutations);\n\ttarget.removeMutations();\n\t\n\t// start homozygous \"aa\" at every position\n\tp1.haplosomes.addMutations(MUT3);\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"sim.mutationFrequencies(NULL, MUT2);\");\n}\nmutation(m2) {\n\t// unique down to the canonical m2 mutation\n\treturn MUT2[mut.position];\n}\nmutation(m3) {\n\t// unique down to the canonical m3 mutation\n\treturn MUT3[mut.position];\n}\n50000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback II.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\ninitialize() {\n\t// m2 models a biallelic locus; an m2 mutation is \"A\",\n\t// absence of an m2 mutation is \"a\"; \"aa\" is neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// m3 is used for new mutations; new m3 mutations get\n\t// uniqued down to the correct biallelic m2 state\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"cornflowerblue\";\n\t\n\tinitializeGenomicElementType(\"g1\", m3, 1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(1e-4);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// create the permanent m2 mutation objects we will use\n\ttarget = p1.haplosomes[0];\n\ttarget.addNewDrawnMutation(m2, 0:99);\n\tdefineConstant(\"MUT\", target.mutations);\n\t\n\t// then remove them; start with \"aa\" for all individuals\n\ttarget.removeMutations();\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"sim.mutationFrequencies(NULL, MUT);\");\n}\nmutation(m3) {\n\t// if we already have an m2 mutation at the site, allow\n\t// the new m3 mutation; we will remove the stack below\n\tif (haplosome.containsMarkerMutation(m2, mut.position))\n\t\treturn T;\n\t\n\t// no m2 mutation is present, so unique down\n\treturn MUT[mut.position];\n}\nlate() {\n\t// implement back-mutations from A to a\n\tm3muts = sim.mutationsOfType(m3);\n\t\n\t// do we have any m3 mutations segregating?\n\t// if so, we have m2/m3 stacked mutations to remove\n\tif (m3muts.length() > 0)\n\t{\n\t\thaplosomes = sim.subpopulations.haplosomes;\n\t\tcounts = haplosomes.countOfMutationsOfType(m3);\n\t\thasStacked = haplosomes[counts > 0];\n\t\t\n\t\tfor (haplosome in hasStacked)\n\t\t{\n\t\t\tstacked_m3 = haplosome.mutationsOfType(m3);\n\t\t\tstackPositions = stacked_m3.position;\n\t\t\tall_m2 = haplosome.mutationsOfType(m2);\n\t\t\ts = (match(all_m2.position, stackPositions) >= 0);\n\t\t\tstacked_m2 = all_m2[s];\n\t\t\thaplosome.removeMutations(c(stacked_m3, stacked_m2));\n\t\t}\n\t}\n}\n50000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.14 - Modeling biallelic loci in script.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\n// biallelicFrequencies() is used by the LogFile\nfunction (float)biallelicFrequencies(void) {\n\tg = NULL;\n\tfor (ind in p1.individuals)\n\t\tg = rbind(g, ind.getValue('G1'), ind.getValue('G2'));\n\tf = apply(g, 1, \"mean(applyValue);\");\n\treturn f;\n}\n\ninitialize() {\n\tdefineConstant(\"MU\", 1e-4);\n\tdefineConstant(\"L\", 100);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// all individuals start in the \"wild-type\" state\n\t// genomic state is kept in two vectors, G1 and G2\n\tp1.individuals.setValue(\"G1\", rep(F, L));\n\tp1.individuals.setValue(\"G2\", rep(F, L));\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"biallelicFrequencies();\");\n}\nmodifyChild() {\n\t// inherit biallelic loci from parents with recombination and mutation\n\tparentG1 = parent1.getValue(\"G1\");\n\tparentG2 = parent1.getValue(\"G2\");\n\trecombined = ifelse(rbinom(L, 1, 0.5) == 0, parentG1, parentG2);\n\tmutated = ifelse(rbinom(L, 1, MU) == 1, !recombined, recombined);\n\tchild.setValue(\"G1\", mutated);\n\t\n\tparentG1 = parent2.getValue(\"G1\");\n\tparentG2 = parent2.getValue(\"G2\");\n\trecombined = ifelse(rbinom(L, 1, 0.5) == 0, parentG1, parentG2);\n\tmutated = ifelse(rbinom(L, 1, MU) == 1, !recombined, recombined);\n\tchild.setValue(\"G2\", mutated);\n\t\n\treturn T;\n}\n50000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.15 - Using runs of homozygosity (ROH) to track inbreeding.txt",
    "content": "// Keywords: runs of homozygosity, ROH, F_ROH, inbreeding, autozygosity\n\ninitialize() {\n\tinitializeMutationRate(5e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e9-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\tsim.addSubpop(\"p2\", 100);\n\tsim.addSubpop(\"p3\", 100);\n\tp1.setMigrationRates(p2, 0.1);\n\tp2.setMigrationRates(p1, 0.001);\n\tp1.setMigrationRates(p3, 0.001);\n\tp3.setMigrationRates(p1, 0.1);\n\t\n\t// start our histories empty\n\tfor (subpop in c(p1,p2,p3))\n\t{\n\t\tsubpop.setValue(\"FROH_hist\", float(0));\n\t\tsubpop.setValue(\"FROH_hist_tick\", integer(0));\n\t}\n}\n500 early() {\n\tp2.setSubpopulationSize(20);\n}\n700 early() {\n\tp2.setSubpopulationSize(100);\n}\n1400 early() {\n\tp3.setSubpopulationSize(20);\n}\n1600 early() {\n\tp3.setSubpopulationSize(500);\n}\n100:2000 late() {\n\t// in SLiMgui, make a plot every ten ticks\n\tif (exists(\"slimgui\") & (community.tick % 10 == 0))\n\t{\n\t\tplot = slimgui.createPlot(\"Froh history\",\n\t\t\txrange=c(1, community.estimatedLastTick()), yrange=c(0.0,0.5),\n\t\t\txlab=\"Tick\", ylab=\"Mean Froh\", width=500, height=300);\n\t\tplot.addLegend(\"topRight\");\n\t\t\n\t\tfor (subpop in c(p1,p2,p3), color in c(\"red\", \"cornflowerblue\", \"chartreuse3\"))\n\t\t{\n\t\t\tmean_FROH = calcMeanFroh(subpop.individuals);\n\t\t\tFROH_hist = c(subpop.getValue(\"FROH_hist\"), mean_FROH);\n\t\t\tFROH_hist_tick = c(subpop.getValue(\"FROH_hist_tick\"), community.tick);\n\t\t\tsubpop.setValue(\"FROH_hist\", FROH_hist);\n\t\t\tsubpop.setValue(\"FROH_hist_tick\", FROH_hist_tick);\n\t\t\t\n\t\t\tplot.lines(x=FROH_hist_tick, y=FROH_hist, color=color, lwd=2.0);\n\t\t\tplot.legendLineEntry(\"p\" + subpop.id, color, lwd=2.0);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.16 - Visualizing linkage disequilibrium.txt",
    "content": "// Keywords: linkage disequilibrium, LD, custom plotting, recombination, calcLD\n\ninitialize()\n{\n\tsetSeed(2180149919968428688);\n\tdefineConstant(\"L\", 1e7);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1).color=\"red\";  // used for MUT1\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early()\n{\n\tsim.addSubpop(\"p1\", 1000);\n}\n5000 late()\n{\n\t// create the MUT1 mutation that we will track over time\n\tmut1 = sample(p1.haplosomes, 1).addNewDrawnMutation(m2, asInteger(L/2));\n\tdefineGlobal(\"MUT1\", mut1);\n}\n\n5000:10000 late()\n{\n\tallMutsMAF = sim.mutations[sim.mutationFrequencies(p1) >= 0.10];\n\tmuts = sortBy(allMutsMAF, \"position\");\n\t\n\tif (size(muts) == 0)\n\t\treturn;\n\tif (!MUT1.isSegregating)\n\t{\n\t\tcatn(\"The focal mutation fixed or was lost.\");\n\t\tsim.simulationFinished();\n\t\treturn;\n\t}\n\t\n\tld = calcLD_D(MUT1, muts) * 10;     // scale up to make it more visible\n\tr = calcLD_Rsquared(MUT1, muts, squared=F);\n\tr2 = calcLD_Rsquared(MUT1, muts);\n\tp = muts.position;\n\t\n\tplot = slimgui.createPlot(\"LD versus R2\", xrange=c(0,L-1), yrange=c(-1,1),\n\t\txlab=\"tick\", ylab=\"metric\", width=800, height=300);\n\tplot.abline(v=MUT1.position, color=\"red\", lwd=2);\n\tplot.points(p, ld, symbol=16, color=\"cornflowerblue\", size=0.5, alpha=0.1);\n\tplot.points(p, r, symbol=16, color=\"chartreuse3\", size=0.5, alpha=0.1);\n\tplot.points(p, r2, symbol=16, color=\"black\", size=0.5, alpha=0.1);\n\t\n\tf = rep(1/201, 201);   // running average filter, 201 mutations wide\n\tplot.lines(p, filter(ld, f, outside=T), color=\"cornflowerblue\", lwd=2);\n\tplot.lines(p, filter(r, f, outside=T), color=\"chartreuse3\", lwd=2);\n\tplot.lines(p, filter(r2, f, outside=T), color=\"black\", lwd=2);\n\t\n\tplot.addLegend(\"topRight\");\n\tplot.legendPointEntry(\"R2\", symbol=16, color=\"black\", size=0.5);\n\tplot.legendPointEntry(\"R\", symbol=16, color=\"chartreuse3\", size=0.5);\n\tplot.legendPointEntry(\"LD*10\", symbol=16, color=\"cornflowerblue\", size=0.5);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.2 - Mortality-based fitness I.txt",
    "content": "// Keywords: death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.005); // deleterious\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutationEffect(m2)\n{\n\t// convert fecundity-based selection to survival-based selection\n\tif (runif(1) < effect)\n\t\treturn 1.0;\n\telse\n\t\treturn 0.0;\n}\n10000 late() {\n\tsim.outputMutations(sim.mutationsOfType(m2));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.2 - Mortality-based fitness II.txt",
    "content": "// Keywords: death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\t// initially, everybody lives\n\tsim.subpopulations.individuals.tagL0 = F;\n\t\n\t// here be dragons\n\tsample(sim.subpopulations.individuals, 100).tagL0 = T;\n}\nfitnessEffect() {\n\t// individuals tagged for death die here\n\tif (individual.tagL0)\n\t\treturn 0.0;\n\telse\n\t\treturn 1.0;\n}\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.2 - Mortality-based fitness III.txt",
    "content": "// Keywords: fitness, death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\t// here be dragons\n\tsample(sim.subpopulations.individuals, 100).fitnessScaling = 0.0;\n}\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.3 - Reading initial simulation state from an MS output file I.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n20000 late() {\n\tp1.outputMSSample(2000, replace=F, filePath=\"ms.txt\");\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.3 - Reading initial simulation state from an MS output file II.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\t\n\t// READ MS FORMAT INITIAL STATE\n\tlines = readFile(\"ms.txt\");\n\tindex = 0;\n\t\n\t// skip lines until reaching the // line, then skip that line\n\twhile (lines[index] != \"//\")\n\t\tindex = index + 1;\n\tindex = index + 1;\n\t\n\tif (index + 2 + p1.individualCount * 2 > size(lines))\n\t\tstop(\"File is too short; terminating.\");\n\t\n\t// next line should be segsites:\n\tsegsitesLine = lines[index];\n\tindex = index + 1;\n\tparts = strsplit(segsitesLine);\n\tif (size(parts) != 2) stop(\"Malformed segsites.\");\n\tif (parts[0] != \"segsites:\") stop(\"Missing segsites.\");\n\tsegsites = asInteger(parts[1]);\n\t\n\t// and next is positions:\n\tpositionsLine = lines[index];\n\tindex = index + 1;\n\tparts = strsplit(positionsLine);\n\tif (size(parts) != segsites + 1) stop(\"Malformed positions.\");\n\tif (parts[0] != \"positions:\") stop(\"Missing positions.\");\n\tpositions = asFloat(parts[1:(size(parts)-1)]);\n\t\n\t// create all mutations in a haplosome in a dummy subpopulation\n\tsim.addSubpop(\"p2\", 1);\n\tg = p2.haplosomes[0];\n\tL = sim.chromosomes.lastPosition;\n\tintPositions = asInteger(round(positions * L));\n\tmuts = g.addNewMutation(m1, 0.0, intPositions);\n\t\n\t// add the appropriate mutations to each haplosome\n\tfor (g in p1.haplosomes)\n\t{\n\t\tf = asLogical(asInteger(strsplit(lines[index], \"\")));\n\t\tindex = index + 1;\n\t\tg.addMutations(muts[f]);\n\t}\n\t\n\t// remove the dummy subpopulation\n\tp2.setSubpopulationSize(0);\n\t\n\t// (optional) set the tick and cycle to match the save point\n\tcommunity.tick = 20000;\n\tsim.cycle = 20000;\n}\n30000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.4 - Modeling chromosomal inversions with a recombination() callback.txt",
    "content": "// Keywords: recombination suppression, inversion, gamete generation, meiosis\n\ninitialize() {\n\tdefineConstant(\"L\", 1000000);\n\tdefineConstant(\"INV_LENGTH\", 500000);\n\tdefineConstant(\"INV_START\", asInteger(L/2 - INV_LENGTH/2));\n\tdefineConstant(\"INV_END\", INV_START + INV_LENGTH - 1);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral sites\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // start marker\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);  // end marker\n\tc(m2,m3).convertToSubstitution = T;\n\tc(m2,m3).color = \"red\";\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\n\t// give some haplosomes an inversion\n\tinverted = sample(p1.haplosomes, 100);\n\tinverted.addNewDrawnMutation(m2, INV_START);\n\tinverted.addNewDrawnMutation(m3, INV_END);\n}\nmutationEffect(m2) {\n\t// fitness of the inversion is frequency-dependent\n\tf = sim.mutationFrequencies(NULL, mut);\n\treturn 1.0 - (f - 0.5) * 0.2;\n}\n5000 late() {\n\tsim.outputFixedMutations();\n\t\n\t// Assess fixation inside vs. outside the inversion\n\tpos = sim.substitutions.position;\n\tcatn(sum((pos >= INV_START) & (pos < INV_END)) + \" inside.\");\n\tcatn(sum((pos < INV_START) | (pos >= INV_END)) + \" outside.\");\n}\n\nrecombination() {\n\tgm1 = haplosome1.containsMarkerMutation(m2, INV_START);\n\tgm2 = haplosome2.containsMarkerMutation(m2, INV_START);\n\tif (!(gm1 | gm2)) {\n\t\t// homozygote non-inverted\n\t\treturn F;\n\t}\n\tinInv = (breakpoints > INV_START) & (breakpoints <= INV_END);\n\tif (sum(inInv) % 2 == 0) {\n\t\treturn F;\n\t}\n\tif (gm1 & gm2) {\n\t\t// homozygote inverted\n\t\tleft = (breakpoints == INV_START);\n\t\tright = (breakpoints == INV_END + 1);\n\t\tbreakpoints = sort(c(breakpoints[!(left | right)],\n\t\t\tc(INV_START, INV_END + 1)[c(sum(left) == 0, sum(right) == 0)]));\n\t\treturn T;\n\t} else {\n\t\t// heterozygote inverted: resample to get an even number of breakpoints\n\t\t// this is *recursive*: it calls this recombination callback again!\n\t\tbreakpoints = sim.chromosomes.drawBreakpoints(individual);\n\t}\n\treturn T;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.5 - Estimating model parameters with ABC.txt",
    "content": "// Keywords: Approximate Bayesian computation, MCMC, parameter estimation\n\ninitialize() {\n\tinitializeMutationRate(mu);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000 late() { cat(sim.mutations.size() + \"\\n\"); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.6 - Tracking local ancestry along the chromosome.txt",
    "content": "// Keywords: migration, dispersal, admixture, ancestry, introgression\n\ninitialize() {\n\tdefineConstant(\"Z\", 1e9);       // last chromosome position\n\tdefineConstant(\"I\", 1e6);       // interval between markers\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // p1 marker\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // p2 marker\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);   // p3 marker\n\tinitializeMutationType(\"m4\", 0.5, \"e\", 0.5);   // beneficial\n\tc(m1,m2,m3,m4).color = c(\"red\", \"green\", \"blue\", \"white\");\n\tc(m1,m2,m3).convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", m4, 1.0);\n\tinitializeGenomicElement(g1, 0, Z);\n\tinitializeMutationRate(0);\n\tinitializeRecombinationRate(1e-9);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tsim.addSubpop(\"p3\", 500);\n\t\n\t// set up markers in each subpopulation, and add a beneficial mutation\n\tpositions = seq(from=0, to=Z, by=I);\n\tdefineConstant(\"M\", size(positions));\n\tcatn(\"Modeling \" + M + \" ancestry markers.\");\n\t\n\tfor (subpop in c(p1,p2,p3),\n\t     muttype in c(m1,m2,m3),\n\t     symbol in c(\"M1\",\"M2\",\"M3\"))\n\t{\n\t\thaplosomes = subpop.haplosomes;\n\t\tmuts = haplosomes.addNewDrawnMutation(muttype, positions);\n\t\tdefineConstant(symbol, muts);\n\t\t\n\t\tmut = haplosomes.addNewDrawnMutation(m4, integerDiv(Z, 2));\n\t\tcatn(\"Beneficial mutation: s == \" + mut.selectionCoeff);\n\t}\n\t\n\t// set up circular migration between the subpops\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p3, 0.01);\n\tp3.setMigrationRates(p1, 0.01);\n}\n:100000 late() {\n\tif (exists(\"slimgui\")) {\n\t\tplot = slimgui.createPlot(\"Local ancestry\", c(0,1), c(0,1),\n\t\t\txlab=\"Position\", ylab=\"Ancestry fraction\", width=700, height=250);\n\t\tplot.addLegend(labelSize=14, graphicsWidth=20);\n\t\tplot.legendLineEntry(\"p1 ancestry\", \"red\", lwd=3);\n\t\tplot.legendLineEntry(\"p2 ancestry\", \"green\", lwd=3);\n\t\tplot.legendLineEntry(\"p3 ancestry\", \"blue\", lwd=3);\n\t\tplot.abline(v=0.5, color=\"black\", lwd=2);\n\t\t\n\t\tfor (col in c(m1,m2,m3).color, symbol in c(\"M1\",\"M2\",\"M3\"))\n\t\t{\n\t\t\tmutlist = executeLambda(symbol + \";\");\n\t\t\tfreqs = sim.mutationFrequencies(NULL, mutlist);\n\t\t\tplot.lines(seq(0, 1, length=size(freqs)), freqs, color=col, lwd=3);\n\t\t\tplot.abline(h=mean(freqs), color=col);\n\t\t}\n\t}\n\t\n\tif (sim.countOfMutationsOfType(m4) == 0)\n\t\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.7 - Live plotting with R using system().txt",
    "content": "// Keywords: live plotting\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tif (fileExists(\"/usr/bin/Rscript\"))\n\t\tdefineConstant(\"RSCRIPT\", \"/usr/bin/Rscript\");\n\telse if (fileExists(\"/usr/local/bin/Rscript\"))\n\t\tdefineConstant(\"RSCRIPT\", \"/usr/local/bin/Rscript\");\n\telse\n\t\tstop(\"Couldn't find Rscript.\");\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 5000);\n\tsim.setValue(\"fixed\", NULL);\n\t\n\tdefineConstant(\"pngPath\", writeTempFile(\"plot_\", \".png\", \"\"));\n\t\n\t// If we're running in SLiMgui, open a plot window\n\tif (exists(\"slimgui\"))\n\t\tslimgui.openDocument(pngPath);\n}\n1: early() {\n\tif (sim.cycle % 10 == 0)\n\t{\n\t\tcount = sim.substitutions.size();\n\t\tsim.setValue(\"fixed\", c(sim.getValue(\"fixed\"), count));\n\t}\n\t\n\tif (sim.cycle % 1000 != 0)\n\t\treturn;\n\t\n\ty = sim.getValue(\"fixed\");\n\t\n\trstr = paste('{',\n\t\t'x <- (1:' + size(y) + ') * 10',\n\t\t'y <- c(' + paste(y, sep=\", \") + ')',\n\t\t'png(width=4, height=4, units=\"in\", res=72, file=\"' + pngPath + '\")',\n\t\t'par(mar=c(4.0, 4.0, 1.5, 1.5))',\n\t\t'plot(x=x, y=y, xlim=c(0, 50000), ylim=c(0, 500), type=\"l\",',\n\t\t\t'xlab=\"Generation\", ylab=\"Fixed mutations\", cex.axis=0.95,',\n\t\t\t'cex.lab=1.2, mgp=c(2.5, 0.7, 0), col=\"red\", lwd=2,',\n\t\t\t'xaxp=c(0, 50000, 2))',\n\t\t'box()',\n\t\t'dev.off()',\n\t\t'}', sep=\"\\n\");\n\t\n\tscriptPath = writeTempFile(\"plot_\", \".R\", rstr);\n\tsystem(RSCRIPT, args=scriptPath);\n\tdeleteFile(scriptPath);\n}\n50000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.8 - Using mutation rate variation to model varying functional density.txt",
    "content": "// Keywords: mutation rate map, mutation map\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 0.5, \"f\", -0.01);  // deleterious\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// Use the mutation rate map to vary functional density\n\tends = c(20000, 30000, 70000, 90000, 99999);\n\tdensities = c(1e-9, 2e-8, 1e-9, 5e-8, 1e-9);\n\tinitializeMutationRate(densities, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 14.9 - Modeling microsatellites.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);           // chromosome length\n\tdefineConstant(\"msatCount\", 10);    // number of microsats\n\tdefineConstant(\"msatMu\", 0.0001);   // mutation rate per microsat\n\tdefineConstant(\"msatUnique\", T);    // T = unique msats, F = lineages\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// microsatellite mutation type; also neutral, but magenta\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"#900090\";\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// create some microsatellites at random positions\n\thaplosomes = sim.subpopulations.haplosomes;\n\tpositions = rdunif(msatCount, 0, L-1);\n\trepeats = rpois(msatCount, 20) + 5;\n\t\n\tfor (msatIndex in 0:(msatCount-1))\n\t{\n\t\tpos = positions[msatIndex];\n\t\tmut = haplosomes.addNewDrawnMutation(m2, pos);\n\t\tmut.tag = repeats[msatIndex];\n\t}\n\t\n\t// remember the microsat positions for later\n\tdefineConstant(\"msatPositions\", positions);\n}\nmodifyChild() {\n\t// mutate microsatellites with rate msatMu\n\tfor (haplosome in child.haplosomes)\n\t{\n\t\tmutCount = rpois(1, msatMu * msatCount);\n\t\t\n\t\tif (mutCount)\n\t\t{\n\t\t\tmutSites = sample(msatPositions, mutCount);\n\t\t\tmsats = haplosome.mutationsOfType(m2);\n\t\t\t\n\t\t\tfor (mutSite in mutSites)\n\t\t\t{\n\t\t\t\tmsat = msats[msats.position == mutSite];\n\t\t\t\trepeats = msat.tag;\n\t\t\t\t\n\t\t\t\t// modify the number of repeats by adding -1 or +1\n\t\t\t\trepeats = repeats + (rdunif(1, 0, 1) * 2 - 1);\n\t\t\t\t\n\t\t\t\tif (repeats < 5)\n\t\t\t\t\tnext;\n\t\t\t\t\n\t\t\t\t// if we're uniquing microsats, do so now\n\t\t\t\tif (msatUnique)\n\t\t\t\t{\n\t\t\t\t\tall_msats = sim.mutationsOfType(m2);\n\t\t\t\t\tmsatsAtSite = all_msats[all_msats.position == mutSite];\n\t\t\t\t\tmatchingMut = msatsAtSite[msatsAtSite.tag == repeats];\n\t\t\t\t\t\n\t\t\t\t\tif (matchingMut.size() == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome.removeMutations(msat);\n\t\t\t\t\t\thaplosome.addMutations(matchingMut);\n\t\t\t\t\t\tnext;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// make a new mutation with the new repeat count\n\t\t\t\thaplosome.removeMutations(msat);\n\t\t\t\tmsat = haplosome.addNewDrawnMutation(m2, mutSite);\n\t\t\t\tmsat.tag = repeats;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn T;\n}\n10000 late() {\n\t// print frequency information for each microsatellite site\n\tall_msats = sim.mutationsOfType(m2);\n\t\n\tfor (pos in sort(msatPositions))\n\t{\n\t\tcatn(\"Microsatellite at \" + pos + \":\");\n\t\t\n\t\tmsatsAtPos = all_msats[all_msats.position == pos];\n\t\t\n\t\tfor (msat in sortBy(msatsAtPos, \"tag\"))\n\t\t\tcatn(\"   variant with \" + msat.tag + \" repeats: \" +\n\t\t\t\tsim.mutationFrequencies(NULL, msat));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.1 - A minimal nonWF model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.10 - Recording a pedigree.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 10);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// delete any existing pedigree log files\n\tdeleteFile(\"mating.txt\");\n\tdeleteFile(\"death.txt\");\n}\nreproduction() {\n\t// choose a mate and generate an offspring\n\tmate = subpop.sampleIndividuals(1);\n\tchild = subpop.addCrossed(individual, mate);\n\tchild.tag = sim.tag;\n\tsim.tag = sim.tag + 1;\n\t\n\t// log the mating\n\tline = paste(community.tick, individual.tag, mate.tag, child.tag);\n\twriteFile(\"mating.txt\", line, append=T);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\t\n\t// provide initial tags and remember the next tag value\n\tp1.individuals.tag = 1:10;\n\tsim.tag = 11;\n}\nearly() {\n\t// density-dependence\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nsurvival() {\n\tif (!surviving) {\n\t\t// log the death\n\t\tline = community.tick + \" \" + individual.tag;\n\t\twriteFile(\"death.txt\", line, append=T);\n\t}\n\treturn NULL;\n}\n100 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.11 - Dynamic population structure in nonWF models.txt",
    "content": "// Keywords: split, join, vicariance, founder, founding, merge, assimilation, admixture\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// each subpopulation reproduces within itself\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\t// start with two subpops that grow to different sizes\n\tsim.addSubpop(\"p1\", 10).setValue(\"K\", 500);\n\tsim.addSubpop(\"p2\", 10).setValue(\"K\", 600);\n}\nearly() {\n\t// density-dependent regulation for each subpop\n\tfor (subpop in sim.subpopulations) {\n\t\tK = subpop.getValue(\"K\");\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n\t}\n}\n5000 late() { }\n\n//\n// Join p1 and p2 to form p3 in tick 1000\n//\n\n999 late() {\n\t// create a zero-size subpop for the join\n\tsim.addSubpop(\"p3\", 0).setValue(\"K\", 750);\n}\n1000 reproduction() {\n\t// generate juveniles to seed p3\n\tfounderCount = rdunif(1, 10, 20);\n\tp1_inds = p1.individuals;\n\tp2_inds = p2.individuals;\n\tall_inds = c(p1_inds, p2_inds);\n\t\n\tfor (i in seqLen(founderCount))\n\t{\n\t\t// select a first parent with equal probabilities\n\t\tparent1 = sample(all_inds, 1);\n\t\t\n\t\t// select a second parent with a bias toward p2\n\t\tif (rdunif(1) < 0.2)\n\t\t\tparent2 = sample(p1_inds, 1);\n\t\telse\n\t\t\tparent2 = sample(p2_inds, 1);\n\t\t\n\t\t// generate the offspring into p3\n\t\tp3.addCrossed(parent1, parent2);\n\t}\n\t\n\t// we're done, don't run again this tick\n\tself.active = 0;\n}\n1000 early() {\n\t// get rid of p1 and p2 now\n\tc(p1,p2).fitnessScaling = 0.0;\n}\n\n//\n// Split p3 to form a new founder subpop p4 in 2000\n//\n1999 late() {\n\t// create a zero-size subpop for the split\n\tsim.addSubpop(\"p4\", 0).setValue(\"K\", 100);\n}\n2000 reproduction() {\n\t// generate juveniles to seed p4\n\tfounderCount = rdunif(1, 10, 20);\n\tall_inds = p3.individuals;\n\t\n\tfor (i in seqLen(founderCount))\n\t{\n\t\t// select parent1/parent2 with equal probabilities\n\t\tparent1 = sample(all_inds, 1);\n\t\tparent2 = sample(all_inds, 1);\n\t\t\n\t\t// generate the offspring into p4\n\t\tp4.addCrossed(parent1, parent2);\n\t}\n\t\n\t// we're done, don't run again this tick\n\tself.active = 0;\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model I.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, Wright-Fisher, non-overlapping generations, discrete generations\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.0, \"f\", -0.5);\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.05));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tK = sim.getValue(\"K\");\n\t\n\t// parents are chosen randomly, irrespective of fitness\n\tparents1 = p1.sampleIndividuals(K, replace=T);\n\tparents2 = p1.sampleIndividuals(K, replace=T);\n\t\n\tfor (i in seqLen(K))\n\t\tp1.addCrossed(parents1[i], parents2[i]);\n\t\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.setValue(\"K\", 500);\n\tsim.addSubpop(\"p1\", sim.getValue(\"K\"));\n}\nearly()\n{\n\t// parents die; offspring survive proportional to fitness\n\tinds = sim.subpopulations.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model II.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, Wright-Fisher, non-overlapping generations, discrete generations\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.0, \"f\", -0.5);\n\tc(m1,m2).convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.05));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tK = sim.getValue(\"K\");\n\t\n\t// parents are chosen proportional to fitness\n\tinds = p1.individuals;\n\tfitness = p1.cachedFitness(NULL);\n\tparents1 = sample(inds, K, replace=T, weights=fitness);\n\tparents2 = sample(inds, K, replace=T, weights=fitness);\n\t\n\tfor (i in seqLen(K))\n\t\tp1.addCrossed(parents1[i], parents2[i]);\n\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.setValue(\"K\", 500);\n\tsim.addSubpop(\"p1\", sim.getValue(\"K\"));\n}\nsurvival() {\n\t// survival is independent of fitness; parents die, offspring live\n\treturn (individual.age == 0);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.13 - Range expansion in a stepping-stone model I.txt",
    "content": "// Keywords: range expansion, colonization, population spread, migration\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);   // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"M\", 0.01);   // migration probability\n\tdefineConstant(\"R\", 1.04);   // mean reproduction (as first parent)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// individuals reproduce locally, without dispersal\n\tlitterSize = rpois(1, R);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\t// generate each offspring with an independently drawn mate\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tif (mate.size())\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\t// create an initial population of 100 individuals, the rest empty\n\tfor (i in seqLen(N))\n\t\tsim.addSubpop(i, (i == 0) ? 100 else 0);\n}\n1 late() {\n\t// set up a log file\n\tlog = community.createLogFile(\"sim_log.txt\", sep=\"\\t\", logInterval=10);\n\tlog.addCycle();\n\tlog.addPopulationSize();\n\tlog.addMeanSDColumns(\"size\", \"sim.subpopulations.individualCount;\");\n\tlog.addCustomColumn(\"pop_migrants\", \"sum(sim.subpopulations.individuals.migrant);\");\n\tlog.addMeanSDColumns(\"migrants\",\n\t\t\"sapply(sim.subpopulations, 'sum(applyValue.individuals.migrant);');\");\n}\nearly() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// non-overlapping generations; kill off the parental generation\n\tages = inds.age;\n\tinds[ages > 0].fitnessScaling = 0.0;\n\tinds = inds[ages == 0];\n\t\n\t// pre-plan migration of individuals to adjacent subpops\n\tnumMigrants = rbinom(1, inds.size(), M);\n\t\n\tif (numMigrants)\n\t{\n\t\tmigrants = sample(inds, numMigrants);\n\t\tcurrentSubpopID = migrants.subpopulation.id;\n\t\tdisplacement = -1 + rbinom(migrants.size(), 1, 0.5) * 2; // -1 or +1\n\t\tnewSubpopID = currentSubpopID + displacement;\n\t\tactuallyMoving = (newSubpopID >= 0) & (newSubpopID < N);\n\t\t\n\t\tif (sum(actuallyMoving))\n\t\t{\n\t\t\tmigrants = migrants[actuallyMoving];\n\t\t\tnewSubpopID = newSubpopID[actuallyMoving];\n\t\t\t\n\t\t\t// do the pre-planned moves into each subpop in bulk\n\t\t\tfor (subpop in sim.subpopulations)\n\t\t\t\tsubpop.takeMigrants(migrants[newSubpopID == subpop.id]);\n\t\t}\n\t}\n\t\n\t// post-migration density-dependent fitness for each subpop\n\tfor (subpop in sim.subpopulations)\n\t{\n\t\tjuvenileCount = sum(subpop.individuals.age == 0);\n\t\tsubpop.fitnessScaling = K / juvenileCount;\n\t}\n}\n1001 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.13 - Range expansion in a stepping-stone model II.txt",
    "content": "// Keywords: range expansion, colonization, population spread, migration\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);   // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"M\", 0.01);   // migration probability\n\tdefineConstant(\"R\", 1.04);   // mean reproduction (as first parent)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// individuals reproduce locally, without dispersal\n\tlitterSize = rpois(1, R);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\t// generate each offspring with an independently drawn mate\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tif (mate.size())\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\t// create an initial population of 100 individuals, the rest empty\n\tfor (i in seqLen(N))\n\t\tsim.addSubpop(i, (i == 0) ? 100 else 0);\n}\n1 late() {\n\t// set up a log file\n\tlog = community.createLogFile(\"sim_log.txt\", sep=\"\\t\", logInterval=10);\n\tlog.addCycle();\n\tlog.addPopulationSize();\n\tlog.addMeanSDColumns(\"size\", \"sim.subpopulations.individualCount;\");\n\tlog.addCustomColumn(\"pop_migrants\", \"sum(sim.subpopulations.individuals.migrant);\");\n\tlog.addMeanSDColumns(\"migrants\",\n\t\t\"sapply(sim.subpopulations, 'sum(applyValue.individuals.migrant);');\");\n}\nearly() {\n\t// non-overlapping generations; kill off the parental generation\n\tinds = sim.subpopulations.individuals;\n\tsim.killIndividuals(inds[inds.age > 0]);\n\t\n\t// pre-migration density-dependent fitness for each subpop\n\tfor (subpop in sim.subpopulations)\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n}\nsurvival() {\n\t// honor SLiM's survival decision\n\tif (!surviving)\n\t\treturn NULL;\n\t\n\t// migrate with probability M\n\tif (runif(1) >= M)\n\t\treturn NULL;\n\t\n\t// migrate the focal individual to an adjacent subpop\n\tsubpops = sim.subpopulations;\n\tnewSubpopID = subpop.id + (-1 + rbinom(1, 1, 0.5) * 2);\t// -1 or +1\n\tnewSubpop = subpops[subpops.id == newSubpopID];\n\tif (newSubpop.size())\n\t\treturn newSubpop;\n\treturn NULL;\n}\n1001 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.14 - Logistic population growth with the Beverton-Holt model.txt",
    "content": "// Keywords: logistic growth, logistic population model, carrying capacity, density dependence\n\ninitialize() {\n\tdefineConstant(\"K\", 50000);\n\tdefineConstant(\"R\", 1.1);\n\tdefineConstant(\"M\", K / (R - 1));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 50);   // the \"simple model\"\n\tsim.addSubpop(\"p2\", 50);   // Beverton-Holt influencing fecundity\n\tsim.addSubpop(\"p3\", 50);   // Beverton-Holt influencing survival\n\t\n\tlog = community.createLogFile(\"sim_log.txt\", logInterval=1);\n\tlog.addCycle();\n\tlog.addSubpopulationSize(p1);\n\tlog.addSubpopulationSize(p2);\n\tlog.addSubpopulationSize(p3);\n}\nreproduction(p1) {\n\t// p1 simply reproduces with a mean litter size of R, like p3\n\tlitterSize = rpois(1, R);\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nreproduction(p2) {\n\t// p2 reproduces up to the Beverton-Holt equation's target\n\tn_t = subpop.individualCount;\n\tn_t_plus_1 = (R * n_t) / (1 + n_t / M);\n\tmean_litter_size = n_t_plus_1 / n_t;\n\tlitterSize = rpois(1, mean_litter_size);\n\t\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nreproduction(p3) {\n\t// p3 simply reproduces with a mean litter size of R, like p1\n\tlitterSize = rpois(1, R);\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nearly() {\n\t// p1 uses the \"simple model\" with non-overlapping generations\n\tinds = p1.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tn_t_plus_pt5 = sum(inds.age == 0);\n\tp1.fitnessScaling = K / n_t_plus_pt5;\n\t\n\t// p2 has selection only to achieve non-overlapping generations\n\tinds = p2.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\t\n\t// p3 uses the Beverton-Holt equation for survival\n\tinds = p3.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tn_t_plus_pt5 = sum(inds.age == 0);\n\tp3.fitnessScaling = 1 / (1 + (n_t_plus_pt5 / R) / M);\n}\n200 late() {\n\t// log out the final row before plotting\n\tlog = community.logFiles;\n\tlog.logRow();\n\tlog.setLogInterval(NULL);\n\t\n\t// make a final plot\n\tif (exists(\"slimgui\"))\n\t{\n\t\tcycle_data = slimgui.logFileData(log, \"cycle\");\n\t\tp1_data = slimgui.logFileData(log, \"p1_num_individuals\");\n\t\tp2_data = slimgui.logFileData(log, \"p2_num_individuals\");\n\t\tp3_data = slimgui.logFileData(log, \"p3_num_individuals\");\n\t\t\n\t\tplot = slimgui.createPlot(\"Population Growth\",\n\t\t\txlab=\"Generation\", ylab=\"Population size\",\n\t\t\twidth=500, height=250);\n\t\t\n\t\tplot.abline(h=50000, color=\"#999999\", lwd=1.0);\n\t\t\n\t\tplot.lines(cycle_data, p1_data, \"cornflowerblue\", lwd=2);\n\t\tplot.lines(cycle_data, p2_data, \"red\", lwd=2);\n\t\tplot.lines(cycle_data, p3_data, \"chartreuse3\", lwd=2);\n\t\t\n\t\tplot.addLegend(\"topLeft\", inset=0, labelSize=13);\n\t\tplot.legendLineEntry(\"p1\", \"cornflowerblue\", lwd=2);\n\t\tplot.legendLineEntry(\"p2\", \"red\", lwd=2);\n\t\tplot.legendLineEntry(\"p3\", \"chartreuse3\", lwd=2);\n\t\t\n\t\tplot.write(\"Population Growth.pdf\");\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.2 - Age structure (a life table model).txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 30);\n\tdefineConstant(\"L\", c(0.7, 0.0, 0.0, 0.0, 0.25, 0.5, 0.75, 1.0));\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tif (individual.age > 2) {\n\t\tmate = subpop.sampleIndividuals(1, minAge=3);\n\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tp1.individuals.age = rdunif(10, min=0, max=7);\n}\nearly() {\n\t// life table based individual mortality\n\tinds = p1.individuals;\n\tages = inds.age;\n\tmortality = L[ages];\n\tsurvival = 1 - mortality;\n\tinds.fitnessScaling = survival;\n\t\n\t// density-dependence, factoring in individual mortality\n\tp1.fitnessScaling = K / (p1.individualCount * mean(survival));\n}\nlate() {\n\t// print our age distribution after mortality\n\tcatn(sim.cycle + \": \" + paste(sort(p1.individuals.age)));\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.3 - Handling all reproduction at once with big bang reproduction.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tfor (s in sim.subpopulations)\n\t{\n\t\tfor (ind in s.individuals)\n\t\t{\n\t\t\ts.addCrossed(ind, s.sampleIndividuals(1));\n\t\t}\n\t}\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.4 - Monogamous mating and variation in litter size.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// randomize the order of p1.individuals\n\tparents = sample(p1.individuals, p1.individualCount);\n\t\n\t// draw monogamous pairs and generate litters\n\tfor (i in seq(0, p1.individualCount - 2, by=2))\n\t{\n\t\tparent1 = parents[i];\n\t\tparent2 = parents[i + 1];\n\t\tp1.addCrossed(parent1, parent2, count=rpois(1, 2.7));\n\t}\n\t\n\t// disable this callback for this cycle\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.5 - Beneficial mutations and absolute fitness.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);   // dominant beneficial\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tfor (i in 1:5)\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\n100 early() {\n\tmutant = sample(p1.individuals.haplosomes, 10);\n\tmutant.addNewDrawnMutation(m2, 10000);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.6 - A metapopulation extinction-colonization model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, migration, dispersal\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 50);     // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"m\", 0.01);   // migration rate\n\tdefineConstant(\"e\", 0.1);    // subpopulation extinction rate\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tfor (i in 1:N)\n\t\tsim.addSubpop(i, (i == 1) ? 10 else 0);\n}\nearly() {\n\t// random migration\n\tnIndividuals = sum(sim.subpopulations.individualCount);\n\tnMigrants = rpois(1, nIndividuals * m);\n\tmigrants = sample(sim.subpopulations.individuals, nMigrants);\n\t\n\tfor (migrant in migrants)\n\t{\n\t\tdo dest = sample(sim.subpopulations, 1);\n\t\twhile (dest == migrant.subpopulation);\n\t\t\n\t\tdest.takeMigrants(migrant);\n\t}\n\t\n\t// density-dependence and random extinctions\n\tfor (subpop in sim.subpopulations)\n\t{\n\t\tif (runif(1) < e)\n\t\t\tsim.killIndividuals(subpop.individuals);\n\t\telse\n\t\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n\t}\n}\nlate() {\n\tif (sum(sim.subpopulations.individualCount) == 0)\n\t\tstop(\"Global extinction in cycle \" + sim.cycle + \".\");\n}\n2000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.7 - Habitat choice.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, migration, dispersal\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.5, \"e\", 0.1);   // deleterious in p2\n\tm2.color = \"red\";\n\tinitializeMutationType(\"m3\", 0.5, \"e\", 0.1);   // deleterious in p1\n\tm3.color = \"green\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2,m3), c(0.98,0.01,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tdest = sample(sim.subpopulations, 1);\n\tdest.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tsim.addSubpop(\"p2\", 10);\n}\nearly() {\n\t// habitat choice\n\tinds = sim.subpopulations.individuals;\n\tinds_m2 = inds.countOfMutationsOfType(m2);\n\tinds_m3 = inds.countOfMutationsOfType(m3);\n\tpref_p1 = 0.5 + (inds_m2 - inds_m3) * 0.1;\n\tpref_p1 = pmax(pmin(pref_p1, 1.0), 0.0);\n\tinertia = ifelse(inds.subpopulation.id == 1, 1.0, 0.0);\n\tpref_p1 = pref_p1 * 0.75 + inertia * 0.25;\n\tchoice = ifelse(runif(inds.size()) < pref_p1, 1, 2);\n\tmoving = inds[choice != inds.subpopulation.id];\n\tfrom_p1 = moving[moving.subpopulation == p1];\n\tfrom_p2 = moving[moving.subpopulation == p2];\n\tp2.takeMigrants(from_p1);\n\tp1.takeMigrants(from_p2);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n\tp2.fitnessScaling = K / p2.individualCount;\n}\nmutationEffect(m2, p2) { return 1/effect; }\nmutationEffect(m3, p1) { return 1/effect; }\n1000 late() {\n\tfor (id in 1:2)\n\t{\n\t\tsubpop = sim.subpopulations[sim.subpopulations.id == id];\n\t\ts = subpop.individualCount;\n\t\tinds = subpop.individuals;\n\t\tc2 = sum(inds.countOfMutationsOfType(m2));\n\t\tc3 = sum(inds.countOfMutationsOfType(m3));\n\t\tcatn(\"subpop \" + id + \" (\" + s + \"): \" + c2 + \" m2, \" + c3 + \" m3\");\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.8 - Evolutionary rescue after environmental change.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, QTL, quantitative trait loci\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\tdefineConstant(\"opt1\", 0.0);\n\tdefineConstant(\"opt2\", 10.0);\n\tdefineConstant(\"Tdelta\", 10000);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 1.0);  // QTL\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nearly() {\n\t// QTL-based fitness\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m1);\n\toptimum = (sim.cycle < Tdelta) ? opt1 else opt2;\n\tdeviations = optimum - phenotypes;\n\tfitnessFunctionMax = dnorm(0.0, 0.0, 5.0);\n\tadaptation = dnorm(deviations, 0.0, 5.0) / fitnessFunctionMax;\n\tinds.fitnessScaling = 0.1 + adaptation * 0.9;\n\tinds.tagF = phenotypes;   // just for output below\n\t\n\t// density-dependence with a maximum benefit at low density\n\tp1.fitnessScaling = min(K / p1.individualCount, 1.5);\n}\nmutationEffect(m1) { return 1.0; }\nlate() {\n\tif (p1.individualCount == 0)\n\t{\n\t\t// stop at extinction\n\t\tcatn(\"Extinction in cycle \" + sim.cycle + \".\");\n\t\tsim.simulationFinished();\n\t}\n\telse\n\t{\n\t\t// output the phenotypic mean and pop size\n\t\tphenotypes = p1.individuals.tagF;\n\t\t\n\t\tcat(sim.cycle + \": \" + p1.individualCount + \" individuals\");\n\t\tcat(\", phenotype mean \" + mean(phenotypes));\n\t\tif (size(phenotypes) > 1)\n\t\t\tcat(\" (sd \" + sd(phenotypes) + \")\");\n\t\tcatn();\n\t}\n}\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 15.9 - Litter size and parental investment.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, sexual, QTL, quantitative trait loci, reproduction()\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.3);  // QTL\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\n\tif (mate.size())\n\t{\n\t\tqtlValue = individual.tagF;\n\t\texpectedLitterSize = max(0.0, qtlValue + 3);\n\t\tlitterSize = rpois(1, expectedLitterSize);\n\t\tpenalty = 3.0 / litterSize;\n\t\t\n\t\tfor (i in seqLen(litterSize))\n\t\t{\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\toffspring.setValue(\"penalty\", rgamma(1, penalty, 20));\n\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setValue(\"penalty\", 1.0);\n}\nearly() {\n\t// non-overlapping generations\n\tinds = sim.subpopulations.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tinds = inds[inds.age == 0];  // focus on juveniles\n\t\n\t// QTL calculations\n\tinds.tagF = inds.sumOfMutationsOfType(m2);\n\t\n\t// parental investment fitness penalties\n\tinds.fitnessScaling = inds.getValue(\"penalty\");\n\t\n\t// density-dependence for juveniles\n\tp1.fitnessScaling = K / size(inds);\n}\nmutationEffect(m2) { return 1.0; }\nlate() {\n\t// output the phenotypic mean and pop size\n\tqtlValues = p1.individuals.tagF;\n\texpectedSizes = pmax(0.0, qtlValues + 3);\n\t\n\tcat(sim.cycle + \": \" + p1.individualCount + \" individuals\");\n\tcat(\", mean litter size \" + mean(expectedSizes));\n\tcatn();\n}\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.1 - Pollen flow.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 200);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// determine how many ovules were fertilized, out of the total\n\tfertilizedOvules = rbinom(1, 30, 0.5);\n\t\n\t// determine the pollen source for each fertilized ovule\n\tother = (subpop == p1) ? p2 else p1;\n\tpollenSources = ifelse(runif(fertilizedOvules) < 0.99, subpop, other);\n\t\n\t// generate seeds from each fertilized ovule\n\t// the ovule belongs to individual, the pollen comes from source\n\tfor (source in pollenSources)\n\t\tsubpop.addCrossed(individual, source.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tsim.addSubpop(\"p2\", 10);\n}\nearly() {\n\tfor (subpop in sim.subpopulations)\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.10 - Modeling pseudo-autosomal regions (PARs) with addMultiRecombinant().txt",
    "content": "// Keywords: multiple chromosomes, pseudo-autosomal region (PAR)\n\ninitialize() {\n\tdefineConstant(\"A1_LEN\", 2e7);\n\tdefineConstant(\"PAR1_LEN\", 2771479);\n\tdefineConstant(\"PAR2_LEN\", 329513);\n\tdefineConstant(\"X_LEN\", 156040895 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"Y_LEN\", 57227415 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"MU\", 1e-8);\n\tdefineConstant(\"R\", 1e-7);\n\tdefineConstant(\"N\", 500);\n\tdefineConstant(\"REC\", N*10);      // start recording at this tick\n\tdefineConstant(\"RUNTIME\", N*50);  // finish at this tick\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0).convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:5, length in c(A1_LEN, PAR1_LEN, X_LEN, Y_LEN, PAR2_LEN),\n\t\ttype in c(\"A\",\"A\",\"X\",\"Y\",\"A\"), symbol in c(\"A1\",\"P1\",\"X\",\"Y\",\"P2\"))\n\t{\n\t\tchr = initializeChromosome(id, length, type=type, symbol=symbol);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeMutationRate(MU);\n\t\tinitializeRecombinationRate(R);\n\t\tdefineConstant(paste0(\"CHR_\", symbol), chr);\n\t}\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n}\nREC late() {\n\tlog = community.createLogFile(\"PAR_Ne.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addCustomColumn(\"Ne_A1\", \"estimateNe_Heterozygosity(p1, CHR_A1);\");\n\tlog.addCustomColumn(\"Ne_P1\", \"estimateNe_Heterozygosity(p1, CHR_P1);\");\n\tlog.addCustomColumn(\"Ne_X\", \"estimateNe_Heterozygosity(p1, CHR_X);\");\n\tlog.addCustomColumn(\"Ne_Y\", \"estimateNe_Heterozygosity(p1, CHR_Y);\");\n\tlog.addCustomColumn(\"Ne_P2\", \"estimateNe_Heterozygosity(p1, CHR_P2);\");\n\tdefineConstant(\"LOG\", log);\n}\nreproduction()\n{\n\tfor (i in seqLen(N))\n\t{\n\t\tparentF = p1.sampleIndividuals(1, sex=\"F\");\n\t\tparentM = p1.sampleIndividuals(1, sex=\"M\");\n\t\n\t\t// generate breakpoints for the female parent (X recombines)\n\t\tbreaks_F_P1 = CHR_P1.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_X = CHR_X.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_P2 = CHR_P2.drawBreakpoints(parent=parentF);\n\t\t\n\t\t// generate breakpoints for the male parent (only PARs recombine)\n\t\tbreaks_M_P1 = CHR_P1.drawBreakpoints(parent=parentM);\n\t\tbreaks_M_P2 = CHR_P2.drawBreakpoints(parent=parentM);\n\t\t\n\t\t// get the haplosomes for each chromosome in each parent\n\t\tstrands_F_P1 = parentF.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_F_X = parentF.haplosomesForChromosomes(CHR_X);    // 2\n\t\tstrands_F_P2 = parentF.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\tstrands_M_P1 = parentM.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_M_X = parentM.haplosomesForChromosomes(CHR_X)[0]; // 1\n\t\tstrands_M_Y = parentM.haplosomesForChromosomes(CHR_Y);    // 1\n\t\tstrands_M_P2 = parentM.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\t// choose initial copy strand indices for PAR1 in both (coin flip)\n\t\tinitial_F_P1 = rbinom(1, 1, 0.5);\n\t\tinitial_M_P1 = rbinom(1, 1, 0.5);\n\t\t\n\t\t// generate the inheritance dictionary for PAR1\n\t\ts1_F_P1 = strands_F_P1[initial_F_P1];\n\t\ts2_F_P1 = strands_F_P1[1 - initial_F_P1];\n\t\t\n\t\ts1_M_P1 = strands_M_P1[initial_M_P1];\n\t\ts2_M_P1 = strands_M_P1[1 - initial_M_P1];\n\t\t\n\t\tpattern = sim.addPatternForRecombinant(CHR_P1, NULL,\n\t\t\ts1_F_P1, s2_F_P1, breaks_F_P1, s1_M_P1, s2_M_P1, breaks_M_P1,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// the initial strand for the X in the female follows from the\n\t\t// above, because PAR1 is physically linked to the start of the\n\t\t// X; if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_X = initial_F_P1;\n\t\tif (size(breaks_F_P1) % 2 == 1) initial_F_X = 1 - initial_F_X;\n\t\tif (runif(1) < R) initial_F_X = 1 - initial_F_X;\n\t\t\n\t\t// do the same for the male, but the \"initial strand\" is the\n\t\t// X if 0, the Y if 1, and it determines the offspring sex\n\t\tinitial_M_XY = initial_M_P1;\n\t\tif (size(breaks_M_P1) % 2 == 1) initial_M_XY = 1 - initial_M_XY;\n\t\tif (runif(1) < R) initial_M_XY = 1 - initial_M_XY;\n\t\t\n\t\tsex = ((initial_M_XY == 0) ? \"F\" else \"M\");\n\t\t\n\t\t// generate the inheritance dictionaries for the X and Y\n\t\ts1_F_X = strands_F_X[initial_F_X];\n\t\ts2_F_X = strands_F_X[1 - initial_F_X];\n\t\t\n\t\tif (sex == \"F\")\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, strands_M_X, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForNull(CHR_Y, pattern, sex=sex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, NULL, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForClone(CHR_Y, pattern, parent=parentM, sex=sex);\n\t\t}\n\t\t\n\t\t// and the initial copy strand for PAR2 follows from the above,\n\t\t// because PAR2 is physically linked to the end of the X/Y;\n\t\t// if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_P2 = initial_F_X;\n\t\tif (size(breaks_F_X) % 2 == 1) initial_F_P2 = 1 - initial_F_P2;\n\t\tif (runif(1) < R) initial_F_P2 = 1 - initial_F_P2;\n\t\t\n\t\tinitial_M_P2 = initial_M_XY;\n\t\tif (runif(1) < R) initial_M_P2 = 1 - initial_M_P2;\n\t\t\n\t\t// generate the inheritance dictionary for PAR2\n\t\ts1_F_P2 = strands_F_P2[initial_F_P2];\n\t\ts2_F_P2 = strands_F_P2[1 - initial_F_P2];\n\t\t\n\t\ts1_M_P2 = strands_M_P2[initial_M_P2];\n\t\ts2_M_P2 = strands_M_P2[1 - initial_M_P2];\n\t\t\n\t\tsim.addPatternForRecombinant(CHR_P2, pattern,\n\t\t\ts1_F_P2, s2_F_P2, breaks_F_P2, s1_M_P2, s2_M_P2, breaks_M_P2,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// finally, generate the offspring following the pattern dictionary\n\t\tsubpop.addMultiRecombinant(pattern, sex=sex,\n\t\t\tparent1=parentF, parent2=parentM, randomizeStrands=F);\n\t}\n\t\n\tself.active = 0;\n}\n2: early() {\n\t// non-overlapping generations\n\tadults = p1.subsetIndividuals(minAge=1);\n\tsim.killIndividuals(adults);\n}\nREC:(RUNTIME+1) early() {\n\t// plot results that got logged the previous tick (which ended in 0)\n\tif ((community.tick % 10 == 1) & exists(\"slimgui\"))\n\t{\n\t\tticks = slimgui.logFileData(LOG, \"tick\");\n\t\tNe_A1 = slimgui.logFileData(LOG, \"Ne_A1\");\n\t\tNe_P1 = slimgui.logFileData(LOG, \"Ne_P1\");\n\t\tNe_X = slimgui.logFileData(LOG, \"Ne_X\");\n\t\tNe_Y = slimgui.logFileData(LOG, \"Ne_Y\");\n\t\tNe_P2 = slimgui.logFileData(LOG, \"Ne_P2\");\n\t\t\n\t\tplot = slimgui.createPlot(\"Ne Estimates\",\n\t\t\txrange=c(REC, RUNTIME), yrange=c(0, N * 2),\n\t\t\txlab=\"Tick\", ylab=\"Population size\",\n\t\t\twidth=1000, height=400);\n\t\tplot.axis(2, at=c(0, N, N*2));\n\t\t\n\t\tplot.abline(h=N, color=\"black\", lwd=2.0);\n\t\t\n\t\tplot.lines(ticks, Ne_A1, \"chartreuse3\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_A1), color=\"chartreuse3\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_P1, \"turquoise3\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_P1), color=\"turquoise3\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_X, \"red\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_X), color=\"red\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_Y, \"orchid2\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_Y), color=\"orchid2\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_P2, \"cornflowerblue\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_P2), color=\"cornflowerblue\", lwd=1.0);\n\t\t\n\t\tplot.addLegend(\"topLeft\", labelSize=12);\n\t\tplot.legendLineEntry(\"N\", \"black\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (A1)\", \"chartreuse3\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (P1)\", \"turquoise3\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (X)\", \"red\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (Y)\", \"orchid2\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (P2)\", \"cornflowerblue\", lwd=2.0);\n\t\t\n\t\tif (community.tick == RUNTIME + 1)\n\t\t{\n\t\t\tplot.write(\"Ne_EST.pdf\");\n\t\t\tsim.simulationFinished();\n\t\t}\n\t}\n}\n\nfunction (float)estimateNe_Heterozygosity(o<Subpopulation>$ subpop,\n\t[No<Chromosome>$ chromosome = NULL])\n{\n\tif (isNULL(chromosome))\n\t{\n\t\tif (size(sim.chromosomes) == 1)\n\t\t\tchromosome = sim.chromosomes;\n\t\telse\n\t\t\tstop(\"ERROR: in a multi-chrom model, a chromosome must be supplied.\");\n\t}\n\t\n\thaplosomes = subpop.haplosomesForChromosomes(chromosome, includeNulls=F);\n\tpi = calcHeterozygosity(haplosomes);\n\treturn pi / (4 * MU);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.11 - Life-long monogamous mating.txt",
    "content": "// Keywords: monogamy, monogamous mating, nonWF, non-Wright-Fisher\n\ninitialize() {\n\tdefineConstant(\"K\", 500);       // carrying capacity\n\tdefineConstant(\"R_AGE_M\", 3);   // minimum age of reproduction (male)\n\tdefineConstant(\"R_AGE_F\", 4);   // minimum age of reproduction (female)\n\tdefineConstant(\"FECUN\", 0.2);   // mean fecundity per female per tick\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n}\n1 first() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.age = rdunif(K, min=0, max=15);   // initial variation in age\n\tp1.individuals.tag = -1;        // mark all individuals as unmated\n}\nfirst() {\n\t// find mated individuals whose mate has died, and mark them as unmated\n\tmated_individuals = p1.individuals;\n\tmated_individuals = mated_individuals[mated_individuals.tag >= 0];\n\t\n\tif (size(mated_individuals) > 0)\n\t{\n\t\ttags = mated_individuals.tag;\n\t\ttag_counts = tabulate(tags);\n\t\ttags_to_fix = which(tag_counts == 1);\n\t\tunmated_indices = match(tags_to_fix, tags);\n\t\tmated_individuals[unmated_indices].tag = -1;\n\t}\n\t\n\t// find the next tag value to use for new mating pairs\n\tnext_tag = max(p1.individuals.tag) + 1;\n\t\n\t// find unmated individuals that are of reproductive age\n\tunmated_F = p1.subsetIndividuals(sex=\"F\", tag=-1, minAge=R_AGE_F);\n\tunmated_M = p1.subsetIndividuals(sex=\"M\", tag=-1, minAge=R_AGE_M);\n\t\n\t// pair individuals randomly; some individuals may be left unpaired\n\tpair_count = min(size(unmated_F), size(unmated_M));\n\tunmated_F = sample(unmated_F, pair_count, replace=F);\n\tunmated_M = sample(unmated_M, pair_count, replace=F);\n\t\n\tfor (f in unmated_F, m in unmated_M, tag in seqLen(pair_count) + next_tag)\n\t{\n\t\tf.tag = tag;\n\t\tm.tag = tag;\n\t}\n}\nreproduction() {\n\t// find the subset of individuals that have a mate\n\tmated_F = p1.subsetIndividuals(sex=\"F\");\n\tmated_F = mated_F[mated_F.tag >= 0];\n\t\n\tmated_M = p1.subsetIndividuals(sex=\"M\");\n\tmated_M = mated_M[mated_M.tag >= 0];\n\t\n\t// look up the male for each female, by tag\n\tmale_indices = match(mated_F.tag, mated_M.tag);\n\tmated_M = mated_M[male_indices];\n\t\n\tpair_count = size(mated_F);\n\t\n\t// produce offspring from each mated pair\n\tfor (f in mated_F,\n\t\t  m in mated_M,\n\t\t  c in rpois(pair_count, FECUN),\n\t\t  new_tag in seqLen(pair_count))\n\t{\n\t\t// re-tag paired individuals to compact tags down\n\t\tf.tag = new_tag;\n\t\tm.tag = new_tag;\n\t\t\n\t\toffspring = p1.addCrossed(f, m, count=c);\n\t\toffspring.tag = -1;\t// mark offspring as unmated\n\t}\n\t\n\tself.active = 0;\t\t// deactivate for the rest of the tick (\"big bang\")\t\n}\nearly() {\n\t// density-dependent population regulation\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.2 - Following a pedigree.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\nfunction (+)readMatrix(s$ path, [string$ sep = \",\"])\n{\n\tif (!fileExists(path))\n\t\tstop(\"readMatrix(): File not found at path \" + path);\n\tdf = readCSV(path, colNames=F, sep=sep);\n\tm = df.asMatrix();\n\treturn m;\n}\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 10);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// read in the pedigree log files\n\tdefineConstant(\"M\", readMatrix(\"mating.txt\", sep=\"\"));\n\tdefineConstant(\"D\", readMatrix(\"death.txt\", sep=\"\"));\n\t\n\t// extract the ticks for quick lookup\n\tdefineConstant(\"Mt\", drop(M[,0]));\n\tdefineConstant(\"Dt\", drop(D[,0]));\n}\nreproduction() {\n\t// generate all offspring for the tick\n\tm = M[Mt == community.tick,];\n\t\n\tfor (index in seqLen(nrow(m))) {\n\t\trow = m[index,];\n\t\tind = subpop.subsetIndividuals(tag=row[,1]);\n\t\tmate = subpop.subsetIndividuals(tag=row[,2]);\n\t\tchild = subpop.addCrossed(ind, mate);\n\t\tchild.tag = row[,3];\n\t}\n\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\t\n\t// provide initial tags matching the original model\n\tp1.individuals.tag = 1:10;\n}\nearly() {\n\t// execute the predetermined mortality\n\tinds = p1.individuals;\n\tinds.fitnessScaling = 1.0;\n\t\n\td = drop(D[Dt == community.tick, 1]);\n\tindices = match(d, inds.tag);\n\tinds[indices].fitnessScaling = 0.0;\n}\n100 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.3 - Modeling clonal haploid bacteria with horizontal gene transfer.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, clonal, haploid\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 1e5);                      // carrying capacity\n\tdefineConstant(\"L\", 1e5);                      // chromosome length\n\tdefineConstant(\"H\", 0.001);                    // HGT probability\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);   // neutral (unused)\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1);   // beneficial\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, L, type=\"H\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(0);                     // no mutation\n\tinitializeRecombinationRate(0);                // no recombination\n}\nreproduction() {\n\tif (runif(1) < H)\n\t{\n\t\t// horizontal gene transfer from a randomly chosen individual\n\t\tHGTsource = p1.sampleIndividuals(1, exclude=individual).haplosomes;\n\t\t\n\t\t// draw two distinct locations; redraw if we get a duplicate\n\t\tdo breaks = rdunif(2, max=L-1);\n\t\twhile (breaks[0] == breaks[1]);\n\t\t\n\t\t// HGT from breaks[0] forward to breaks[1] on a circular chromosome\n\t\tif (breaks[0] > breaks[1])\n\t\t\tbreaks = c(0, breaks[1], breaks[0]);\n\t\t\n\t\tsubpop.addRecombinant(individual.haplosomes, HGTsource, breaks, NULL, NULL, NULL, randomizeStrands=F);\n\t}\n\telse\n\t{\n\t\t// no horizontal gene transfer; clonal replication\n\t\tsubpop.addCloned(individual);\n\t}\n}\n1 early() {\n\t// start from two bacteria with different beneficial mutations\n\tsim.addSubpop(\"p1\", 2);\n\t\n\th = p1.individuals.haplosomes;\n\th[0].addNewDrawnMutation(m2, asInteger(L * 0.25));\n\th[1].addNewDrawnMutation(m2, asInteger(L * 0.75));\n}\nearly() {\n\t// density-dependent population regulation\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\t// detect fixation/loss of the beneficial mutations\n\tmuts = sim.mutations;\n\tfreqs = sim.mutationFrequencies(NULL, muts);\n\t\n\tif (all(freqs == 1.0))\n\t{\n\t\tcatn(sim.cycle + \": \" + sum(freqs == 1.0) + \" fixed.\");\n\t\tsim.simulationFinished();\n\t}\n}\n1e6 late() { catn(sim.cycle + \": no result.\"); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.4 - Alternation of generations.txt",
    "content": "// Keywords: alternation of generations, sporophyte, gametophyte, sperm, eggs, diploid, haploid, mating system, fertilization, meiosis, reproduction()\n\ninitialize()\n{\n\tdefineConstant(\"K\", 500);     // carrying capacity (diploid)\n\tdefineConstant(\"MU\", 1e-7);   // mutation rate\n\tdefineConstant(\"R\", 1e-7);    // recombination rate\n\tdefineConstant(\"L1\", 1e5-1);  // chromosome end (length - 1)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L1);\n\tinitializeRecombinationRate(R);\n}\n1 early()\n{\n\tsim.addSubpop(\"p1\", K);\n\tsim.addSubpop(\"p2\", 0);\n}\nreproduction(p1)\n{\n\tg_1 = individual.haploidGenome1;\n\tg_2 = individual.haploidGenome2;\n\t\n\tfor (meiosisCount in 1:5)\n\t{\n\t\tif (individual.sex == \"M\")\n\t\t{\n\t\t\tbreaks = sim.chromosomes.drawBreakpoints(individual);\n\t\t\ts_1 = p2.addRecombinant(g_1, g_2, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\ts_2 = p2.addRecombinant(g_2, g_1, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\t\n\t\t\tbreaks = sim.chromosomes.drawBreakpoints(individual);\n\t\t\ts_3 = p2.addRecombinant(g_1, g_2, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\ts_4 = p2.addRecombinant(g_2, g_1, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t}\n\t\telse if (individual.sex == \"F\")\n\t\t{\n\t\t\te = p2.addRecombinant(g_1, g_2, NULL, NULL, NULL, NULL, \"F\", randomizeStrands=T);\n\t\t}\n\t}\n}\nreproduction(p2, \"F\")\n{\n\tmate = p2.sampleIndividuals(1, sex=\"M\", tagL0=F);\n\tmate.tagL0 = T;\n\t\n\tchild = p1.addRecombinant(individual.haploidGenome1, NULL, NULL,\n\t\tmate.haploidGenome1, NULL, NULL);\n}\nearly()\n{\n\tif (sim.cycle % 2 == 0)\n\t{\n\t\tp1.fitnessScaling = 0.0;\n\t\tp2.individuals.tagL0 = F;\n\t\tsim.chromosomes.setMutationRate(0.0);\n\t}\n\telse\n\t{\n\t\tp2.fitnessScaling = 0.0;\n\t\tp1.fitnessScaling = K / p1.individualCount;\n\t\tsim.chromosomes.setMutationRate(MU);\n\t}\n}\n10000 late()\n{\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.5 - Meiotic drive.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, meiotic drive, segregation distortion, intragenomic conflict\n\nfunction (i)driveBreakpoints(o<Haplosome>$ gen1, o<Haplosome>$ gen2)\n{\n\t// start with default breakpoints generated by the chromosome\n\tbreaks = sim.chromosomes.drawBreakpoints();\n\t\n\t// if both haplosomes have the drive, or neither, then just return\n\tgen1has = gen1.containsMarkerMutation(m2, D_pos);\n\tgen2has = gen2.containsMarkerMutation(m2, D_pos);\n\tif (gen1has == gen2has)\n\t\treturn breaks;\n\t\n\t// will the drive be inherited?  do we want it to be?\n\tpolarity = sum(breaks <= D_pos) % 2;   // 0 for gen1, 1 for gen2\n\tpolarityI = (gen1has ? 0 else 1);\n\tdesiredPolarity = (runif(1) < D_prob) ? polarityI else !polarityI;\n\t\n\t// intervene to produce the outcome we want\n\tif (desiredPolarity != polarity)\n\t\treturn c(0, breaks);\n\treturn breaks;\n}\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);        // carrying capacity\n\tdefineConstant(\"D_pos\", 20000);  // meiotic drive allele position\n\tdefineConstant(\"D_prob\", 0.8);   // meiotic drive probability\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeMutationType(\"m2\", 0.1, \"f\", -0.1);  // drive allele\n\tm2.color = \"red\";\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tm = subpop.sampleIndividuals(1);\n\tb1 = driveBreakpoints(individual.haploidGenome1, individual.haploidGenome2);\n\tb2 = driveBreakpoints(m.haploidGenome1, m.haploidGenome2);\n\tsubpop.addRecombinant(individual.haploidGenome1, individual.haploidGenome2, b1, m.haploidGenome1, m.haploidGenome2, b2, randomizeStrands=F);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n100 early() {\n\ttarget = sample(p1.haplosomes, 10);\n\ttarget.addNewDrawnMutation(m2, D_pos);\n}\n100:1000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 0) {\n\t\tcatn(sim.cycle + \": LOST\");\n\t\tsim.simulationFinished();\n\t} else if (sim.mutationFrequencies(NULL, mut) == 1.0) {\n\t\tcatn(sim.cycle + \": FIXED\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.6 - Sperm storage with a survival() callback.txt",
    "content": "// Keywords: survival(), sperm storage\n\n// This model is loosely based upon a model by Anita Lerch.\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeSex();\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\n}\nreproduction(p1) {\n\tmatureFemales = subpop.subsetIndividuals(sex=\"F\", minAge=7);\n\t\n\tfor (female in matureFemales)\n\t{\n\t\tif (female.tag < 0) {\n\t\t\t// the female has not yet chosen a mate, so choose one now\n\t\t\tmate = subpop.sampleIndividuals(1, sex=\"M\", minAge=7);\n\t\t} else {\n\t\t\t// the female has already chosen a mate; look it up by id\n\t\t\tmate = sim.individualsWithPedigreeIDs(female.tag);\n\t\t}\n\t\tif (mate.size()) {\n\t\t\tfemale.tag = mate.pedigreeID;\n\t\t\tsubpop.addCrossed(female, mate, count=rpois(1, 5));\n\t\t} else {\n\t\t\tcatn(sim.cycle + \": No mate found for tag \" + female.tag);\n\t\t}\n\t}\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1inds = p1.individuals;\n\tp1inds.age = rdunif(size(p1.individuals), min=0, max=10);\n\tp1inds.tag = -1;\n\t\n\tsim.addSubpop(\"p1000\", 0);   // cold storage for dead males\n}\nearly() {\n\t// fix all new female tags; faster to do this vectorized\n\toffspringFemales = p1.subsetIndividuals(sex=\"F\", maxAge=0);\n\toffspringFemales.tag = -1;\n\t\n\t// p1 is governed by standard density-dependence\n\tp1.fitnessScaling = K / p1.individualCount;\n\t\n\t// cold storage individuals are kept until unreferenced\n\tp1000.individuals.tag = 0;\n\tmaleRefs = p1.subsetIndividuals(sex=\"F\").tag;\n\tmaleRefs = maleRefs[maleRefs != -1];\n\treferencedDeadMales = sim.individualsWithPedigreeIDs(maleRefs, p1000);\n\treferencedDeadMales.tag = 1;\n}\nsurvival(p1) {\n\t// move dying males into cold storage in case they have mated\n\tif (!surviving)\n\t\tif (individual.sex == \"M\")\n\t\t\treturn p1000;\n\treturn NULL;\n}\nsurvival(p1000) {\n\treturn (individual.tag == 1);\n}\nlate() {\n\tcatn(sim.cycle + \": p1 (\" + p1.individualCount + \")\" +\n\t\t\", p1000 (\" + p1000.individualCount + \")\");\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.7 - Tracking separate sexes in script, nonWF style.txt",
    "content": "// Keywords: automixis, parthenogenesis, sex determination, mating systems, sexual types\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\t// carrying capacity\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// we focus on the reproduction of the females here\n\tif (individual.tagL0 == F)\n\t{\n\t\tif (runif(1) < 0.7)\n\t\t{\n\t\t\t// choose a male mate and produce a son or daughter\n\t\t\tmate = subpop.sampleIndividuals(1, tagL0=T);\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\toffspring.tagL0 = (runif(1) <= 0.5);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// reproduce through automixis to produce a daughter\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\toffspring.tagL0 = F;\n\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\t\n\t// assign random sexes (T = male, F = female)\n\tp1.individuals.tagL0 = (runif(p1.individualCount) <= 0.5);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n1:2000 late() {\n\tratio = mean(p1.individuals.tagL0);\n\tcatn(sim.cycle + \": \" + ratio);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.8 - Modeling haplodiploidy with addRecombinant().txt",
    "content": "// Keywords: mating systems, haplodiploidy, arrhenotoky, bees, wasps, ants, Hymenoptera\n\ninitialize() {\n\tdefineConstant(\"K\", 2000);\n\tdefineConstant(\"P_OFFSPRING_MALE\", 0.8);\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.0, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tm1.hemizygousDominanceCoeff = 1.0;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-6);\n\tinitializeSex();\n}\nreproduction(NULL, \"F\") {\n\tgen1 = individual.haploidGenome1;\n\tgen2 = individual.haploidGenome2;\n\t\n\t// decide whether we're generating a haploid male or a diploid female\n\tif (rbinom(1, 1, P_OFFSPRING_MALE))\n\t{\n\t\t// didn't find a mate; make a haploid male from an unfertilized egg:\n\t\t//\t\t- one haplosome comes from recombination of the female's haplosomes\n\t\t//\t\t- the other haplosome is a null haplosome (a placeholder)\n\t\tsubpop.addRecombinant(gen1, gen2, NULL, NULL, NULL, NULL, \"M\",\n\t\t\trandomizeStrands=T);\n\t}\n\telse\n\t{\n\t\t// found a mate; make a diploid female from a fertilized egg:\n\t\t//\t\t- one haplosome comes from recombination of the female's haplosomes\n\t\t//\t\t- the other haplosome comes from the mate (a haploid male)\n\t\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\tsubpop.addRecombinant(gen1, gen2, NULL, mate.haploidGenome1, NULL, NULL, \"F\",\n\t\t\trandomizeStrands=T);\n\t}\n}\n1 early() {\n\t// make an initial population with the right genetics\n\tmCount = asInteger(K * P_OFFSPRING_MALE);\n\tfCount = K - mCount;\n\tsim.addSubpop(\"p1\", mCount, sexRatio=1.0, haploid=T);\t// males\n\tsim.addSubpop(\"p2\", fCount, sexRatio=0.0, haploid=F);\t// females\n\tp1.takeMigrants(p2.individuals);\n\tp2.removeSubpopulation();\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10000 late() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 16.9 - Complex multi-chromosome inheritance with addMultiRecombinant().txt",
    "content": "// Keywords: multiple chromosomes, inheritance patterns, mating systems\n\ninitialize() {\n\tdefineConstant(\"K\", 500);\t// carrying capacity\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\tids = 1:7;\n\tsymbols = c(\"A\", \"X\", \"Y\", \"P\", \"Q\", \"R\", \"S\");\n\tlengths = c(3e6, 2e6, 1e6, 1e6, 1e6, 1e6, 1e6);\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"H\", \"H\", \"H\");\n\t\n\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeRecombinationRate(1e-7);\n\t\tinitializeGenomicElement(g1);\n\t}\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\n\tpattern = Dictionary();\n\tsim.addPatternForClone(\"P\", pattern, individual);\n\tsim.addPatternForClone(\"Q\", pattern, runif(1) < 0.5 ? individual else mate);\n\tsim.addPatternForCross(\"R\", pattern, individual, mate);\n\tind_hapS = individual.haplosomesForChromosomes(\"S\");\n\tmate_hapS = mate.haplosomesForChromosomes(\"S\");\n\tsim.addPatternForRecombinant(\"S\", pattern, ind_hapS, mate_hapS, NULL,\n\t\tNULL, NULL, NULL);\n\tsubpop.addMultiRecombinant(pattern, parent1=individual, parent2=mate,\n\t\trandomizeStrands=F);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n1000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.1 - A simple 2D continuous-space model.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.10 - A simple biogeographic landscape model.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=30.0);\n\ti1.setInteractionFunction(\"n\", 5.0, 10.0);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=30.0);\n\ti2.setInteractionFunction(\"n\", 1.0, 10.0);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\t\n\tp1.setSpatialBounds(c(0.0, 0.0, 539.0, 216.0));\n\t\n\t// this file is in the recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tmapImage = Image(\"world_map_540x217.png\");\n\tmap = p1.defineSpatialMap(\"world\", \"xy\", 1.0 - mapImage.floatK,\n\t\tvalueRange=c(0.0, 1.0), colors=c(\"#0000CC\", \"#55FF22\"));\n\tdefineConstant(\"WORLD\", map);\n\t\n\t// start near a specific map location\n\tfor (ind in p1.individuals) {\n\t\tind.x = rnorm(1, 300.0, 1.0);\n\t\tind.y = rnorm(1, 100.0, 1.0);\n\t}\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds) / size(inds);\n\tcompetition = pmin(competition, 0.99);\n\tinds.fitnessScaling = 1.0 - competition;\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\treturn i2.strength(individual);\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 2.0);\n\twhile (!p1.pointInBounds(pos));\n\t\n\t// prevent dispersal into water\n\tif (WORLD.mapValue(pos) == 0.0)\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.11 - Local adaptation on a heterogeneous landscape map.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, reprising boundaries, QTL, quantitative trait loci, spatial competition, spatial mate choice\n\ninitialize() {\n\tdefineConstant(\"SIGMA_C\", 0.1);\n\tdefineConstant(\"SIGMA_K\", 0.5);\n\tdefineConstant(\"SIGMA_M\", 0.1);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.1));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"xyz\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"xyz\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setSpatialBounds(c(0.0, 0.0, 0.0, 1.0, 1.0, 1.0));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N));\n\tp1.individuals.z = 0.0;\n\t\n\tdefineConstant(\"MAPVALUES\", matrix(runif(25, 0, 1), ncol=5));\n\tmap = p1.defineSpatialMap(\"map1\", \"xy\", MAPVALUES, interpolate=T,\n\t\tvalueRange=c(0.0, 1.0), colors=c(\"red\", \"yellow\"));\n\tdefineConstant(\"OPTIMUM\", map);\n}\nmodifyChild() {\n\t// set offspring position based on parental position\n\tdo pos = c(parent1.spatialPosition[0:1] + rnorm(2, 0, 0.005), 0.0);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n1: late() {\n\t// construct phenotypes and fitness effects from QTLs\n\tinds = sim.subpopulations.individuals;\n\tphenotype = inds.sumOfMutationsOfType(m2);\n\tlocation = inds.spatialPosition[rep(c(T,T,F), inds.size())];\n\toptimum = OPTIMUM.mapValue(location);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotype, optimum, SIGMA_K);\n\tinds.z = phenotype;\n\t\n\t// color individuals according to phenotype\n\tinds.color = OPTIMUM.mapColor(phenotype);\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n10000 late() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.12 - Periodic spatial boundaries.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, periodic boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\tinitializeInteractionType(\"i1\", \"xy\", reciprocal=T, maxDistance=0.2);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 2000);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(2000));\n}\nlate()\n{\n\ti1.evaluate(p1);\n\tfocus = sample(p1.individuals, 1);\n\ts = i1.strength(focus);\n\tinds = p1.individuals;\n\tfor (i in seqAlong(s))\n\t\tinds[i].color = rgb2color(c(1.0 - s[i], 1.0 - s[i], s[i]));\n\tfocus.color = \"red\";\n}\nmodifyChild() {\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointPeriodic(pos));\n\treturn T;\n}\n1000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.13 - Density-dependent fecundity with summarizeIndividuals().txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, density, competition, regulation, fertility, per unit area\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1000));\n}\nlate() {\n\tinds = p1.individuals;\n\tbounds = p1.spatialBounds;\n\t\n\t// make a density map: 0 is empty, 1 is maximum density\n\tdensity = summarizeIndividuals(inds, c(10, 10), bounds,\n\t\toperation=\"individuals.size();\", empty=0.0, perUnitArea=T);\n\tdensity = density / max(density);\n\tp1.defineSpatialMap(\"density\", \"xy\", density, F,\n\t\trange(density), c(\"black\", \"orange\", \"red\"));\n}\nmodifyChild() {\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.01);\n\tpos = p1.pointReflected(pos);\n\t\n\tif (runif(1) < p1.spatialMapValue(\"density\", pos))\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.14 - Directed dispersal with the SpatialMap class.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial maps, directed dispersal\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(c(0.0, 0.0));\n\tp1.individuals.color = rainbow(K);\n\t\n\tdo {\n\t\tm = matrix(rbinom(16, 1, 0.2), ncol=4, byrow=T);\n\t\tm = cbind(m, m[,0]);\n\t\tm = rbind(m, m[0,]);\n\t} while ((sum(m) == 0) | (sum(m) == 1));\n\t\n\tmap = p1.defineSpatialMap(\"habitat\", \"xy\", m, valueRange=c(0,1), colors=c(\"black\", \"white\"));\n\tdefineConstant(\"MAP\", map);\n}\n2 late() {\n\tMAP.interpolate(15, method=\"cubic\");\n}\n3 late() {\n\tMAP.rescale();\n}\n4 late() {\n\tMAP.smooth(0.3, \"n\", 0.1);\n}\n5 late() {\n\tMAP.rescale();\n}\n6 late() {\n\tMAP.interpolate = T;\n}\n10 late() {\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n}\n11:100000 late() {\n\tinds = p1.individuals;\n\tpos = inds.spatialPosition;\n\tpos = MAP.sampleNearbyPoint(pos, INF, \"n\", 0.002);\n\tinds.setSpatialPosition(pos);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.15 - Spatial competition and spatial mate choice in a nonWF model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, periodic boundaries, selfing\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\tdefineConstant(\"K\", 300);   // carrying capacity\n\tdefineConstant(\"S\", 0.1);   // spatial competition distance\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestNeighbors(individual, 1);\n\t\n\tfor (i in seqLen(rpois(1, 0.1)))\n\t{\n\t\tif (mate.size())\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\telse\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\n\t\t// set offspring position\n\t\tpos = individual.spatialPosition + rnorm(2, 0, 0.02);\n\t\toffspring.setSpatialPosition(p1.pointPeriodic(pos));\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1);\n\t\n\t// random initial positions\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1));\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tcompetition = (competition + 1) / (PI * S^2);\n\tinds.fitnessScaling = K / competition;\n}\nlate()\n{\n\t// move around a bit\n\tfor (ind in p1.individuals)\n\t{\n\t\tnewPos = ind.spatialPosition + runif(2, -0.01, 0.01);\n\t\tind.setSpatialPosition(p1.pointPeriodic(newPos));\n\t}\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.16 - A spatial model with carrying-capacity density.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, selfing, spatial competition, spatial mate choice\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tdefineConstant(\"K\", 300);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.1);   // SIGMA_S, the spatial interaction width\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestNeighbors(individual, 1);\n\t\n\tfor (i in seqLen(rpois(1, 0.1)))\n\t{\n\t\tif (mate.size())\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\telse\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\n\t\t// set offspring position\n\t\tdo pos = individual.spatialPosition + rnorm(2, 0, 0.02);\n\t\twhile (!p1.pointInBounds(pos));\n\t\toffspring.setSpatialPosition(pos);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1);\n\t\n\t// random initial positions\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1));\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.localPopulationDensity(inds);\n\tinds.fitnessScaling = K / competition;\n}\nlate()\n{\n\t// move around a bit\n\tfor (ind in p1.individuals)\n\t{\n\t\tdo newPos = ind.spatialPosition + runif(2, -0.01, 0.01);\n\t\twhile (!p1.pointInBounds(newPos));\n\t\tind.setSpatialPosition(newPos);\n\t}\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.17 - A spatial epidemiological S-I-R model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, periodic boundaries, spatial competition, spatial mate choice, disease, epidemiology, SIR, S-I-R, infection, epidemic, pandemic\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\t\n\tdefineConstant(\"K\", 10000);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.01);    // SIGMA_S, the competition width\n\t\n\tdefineConstant(\"HEALTH_S\", 0);   // susceptible\n\tdefineConstant(\"HEALTH_I\", 1);   // infectious\n\tdefineConstant(\"HEALTH_R\", 2);   // recovered\n\t\n\tdefineConstant(\"FERTILITY\", 0.05);\n\tdefineConstant(\"INFECTIVITY\", 4);\n\tdefineConstant(\"RATE_DEATH\", 0.3);\n\tdefineConstant(\"RATE_CLEAR\", 0.05);\n\tdefineConstant(\"MAX_AGE\", 100.0);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.05);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\tlitterSize = rpois(1, FERTILITY);\n\t\n\tif (litterSize)\n\t{\n\t\tmate = i2.nearestNeighbors(individual, 1);\n\t\t\n\t\tif (mate.size())\n\t\t\tfor (i in seqLen(litterSize))\n\t\t\t{\n\t\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\t\t\n\t\t\t\t// set offspring position and state\n\t\t\t\tpos = individual.spatialPosition + rnorm(2, 0, 0.005);\n\t\t\t\toffspring.setSpatialPosition(p1.pointPeriodic(pos));\n\t\t\t\toffspring.tag = HEALTH_S;\n\t\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n\tp1.individuals.tag = HEALTH_S;\n}\n100 early() {\n\t// seed the infection in a susceptible individual\n\ttarget = p1.sampleIndividuals(1, tag=HEALTH_S);\n\ttarget.tag = HEALTH_I;\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tcompetition = (competition + 1) / (2 * PI * S^2);\n\tinds.fitnessScaling = K / competition;\n\t\n\t// age-based mortality; at age 100 mortality is 100%\n\tage_mortality = sqrt((MAX_AGE - inds.age) / MAX_AGE);\n\tinds.fitnessScaling = inds.fitnessScaling * age_mortality;\n\t\n\t// SIR model\n\tinfected = inds[inds.tag == HEALTH_I];\n\t\n\tfor (ind in infected)\n\t{\n\t\t// make contact with random neighbors each cycle\n\t\tcontacts = i1.drawByStrength(ind, rpois(1, INFECTIVITY));\n\t\t\n\t\tfor (contact in contacts)\n\t\t{\n\t\t\t// if the contact is susceptible, they might get infected\n\t\t\tif (contact.tag == HEALTH_S)\n\t\t\t{\n\t\t\t\tstrength = i1.strength(ind, contact);\n\t\t\t\t\n\t\t\t\tif (runif(1) < strength)\n\t\t\t\t\tcontact.tag = HEALTH_I;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// die with some probability each cycle\n\t\tif (runif(1) < RATE_DEATH)\n\t\t\tind.fitnessScaling = 0.0;\n\t\t\n\t\t// recover with some probability each cycle\n\t\tif (runif(1) < RATE_CLEAR)\n\t\t\tind.tag = HEALTH_R;\n\t}\n}\nlate()\n{\n\tinds = p1.individuals;\n\t\n\t// move around a bit\n\tfor (ind in inds)\n\t{\n\t\tnewPos = ind.spatialPosition + runif(2, -0.005, 0.005);\n\t\tind.setSpatialPosition(p1.pointPeriodic(newPos));\n\t}\n\t\n\t// color according to health status; S=green, I=red, R=blue\n\tinds_tags = inds.tag;\n\tinds[inds_tags == HEALTH_S].color = \"green\";\n\tinds[inds_tags == HEALTH_I].color = \"red\";\n\tinds[inds_tags == HEALTH_R].color = \"blue\";\n}\n1:1000 late() {\n\ttags = p1.individuals.tag;\n\t\n\tcat(sum(tags == HEALTH_S) + \", \" + sum(tags == HEALTH_I) + \", \" +\n\t\tsum(tags == HEALTH_R) + \", \");\n\t\n\tif ((sum(tags == HEALTH_I) == 0) & (sim.cycle >= 100)) {\n\t\tcatn(\"\\nLOST in cycle \" + sim.cycle);\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.18 - A sexual, age-structured spatial model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, selfing, spatial competition, spatial mate choice\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeSex();\n\tdefineConstant(\"K\", 300);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.1);   // SIGMA_S, the spatial interaction width\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n\ti2.setConstraints(\"receiver\", sex=\"F\", minAge=2, maxAge=4);\n\ti2.setConstraints(\"exerter\", sex=\"M\", minAge=2);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction(NULL, \"F\") {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestInteractingNeighbors(individual, 1);\n\t\n\tif (mate.size() > 0)\n\t\tsubpop.addCrossed(individual, mate, count=rpois(1, 1.5));\n}\nearly() {\n\t// first, conduct age-related mortality with killIndividuals()\n\tinds = p1.individuals;\n\tages = inds.age;\n\t\n\tinds4 = inds[ages == 4];\n\tinds5 = inds[ages == 5];\n\tinds6 = inds[ages >= 6];\n\tdeath4 = (runif(inds4.size()) < 0.10);\n\tdeath5 = (runif(inds5.size()) < 0.30);\n\tsim.killIndividuals(c(inds4[death4], inds5[death5], inds6));\n\t\n\t// disperse prior to density-dependence\n\tp1.deviatePositions(NULL, \"reprising\", INF, \"n\", 0.02);\n\t\n\t// spatial competition provides density-dependent selection\n\ti1.evaluate(p1);\n\tinds = p1.individuals;\n\tcompetition = i1.localPopulationDensity(inds);\n\tinds.fitnessScaling = K / competition;\n}\n10000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.19 - Modeling indirect competition mediated by resource availability.txt",
    "content": "// Keywords: resources, foraging, spatial competition, home range, multispecies\n\nspecies all initialize()\n{\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\t// Foraging interaction.\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=1.5);\n\t\n\t// Reproduction interaction.\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=3,\n\t\tsexSegregation=\"FM\");\n}\nspecies resourceNode initialize()\n{\n\tinitializeSpecies(avatar=\"🪣\", color=\"cornflowerblue\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\nspecies forager initialize()\n{\n\tinitializeSpecies(avatar=\"🤤\", color=\"red\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeSex();\n}\n\nticks all 1 early()\n{\n\t// Coordinates for the resource nodes.\n\txs = rep(seq(0.5, 100), 100);\n\tys = repEach(seq(0.5, 100), 100);\n\t\n\t// Add the resource nodes.\n\tresourceNode.addSubpop(\"p1\", 10000);\n\tp1.setSpatialBounds(c(0, 0, 100, 100));\n\tp1.individuals.x = xs;\n\tp1.individuals.y = ys;\n\tp1.individuals.tagF = 10.0;\n\t\n\t// Initialize the population of foragers.\n\tforager.addSubpop(\"p2\", 100000);\n\tp2.setSpatialBounds(p1.spatialBounds);\n\tp2.individuals.setSpatialPosition(p2.pointUniform(p2.individualCount));\n}\n\nticks all 2: first()\n{\n\t// Evaluate the spatial interaction for reproduction.\n\ti2.evaluate(p2);\n}\nspecies forager reproduction(NULL, \"F\")\n{\n\t// Draw the litter size first, and return if it's zero.\n\tlitterSize = rpois(1, 8);\n\tif (litterSize == 0)\n\t\treturn;\n\t\n\t// Draw a random mate from among males in range.\n\tmate = i2.drawByStrength(individual, 1, p2);\n\tif (size(mate) == 0)\n\t\treturn;\n\t\n\t// Produce the offspring.\n\tsubpop.addCrossed(individual, mate, count=litterSize);\n}\n\nticks all 2:100 early()\n{\n\t// Dispersal of new offspring.\n\toffspring = p2.subsetIndividuals(maxAge=0);\n\tp2.deviatePositions(offspring, \"reprising\", INF, \"n\", 1.5);\n\t\n\t// Evaluate the spatial interaction between resource nodes and foragers.\n\ti1.evaluate(c(p2, p1));\n\t\n\t// Survival in this model is based entirely on resource availability.\n\tp2.individuals.fitnessScaling = 0.0;\n\t\n\tfor (node in p1.individuals)\n\t{\n\t\t// Find all foragers within range of the resource node.\n\t\tf = i1.nearestNeighbors(node, p2.individualCount, p2);\n\t\t\n\t\t// Evenly divide resources to all foragers within range.\n\t\tf.fitnessScaling = f.fitnessScaling + node.tagF / size(f);\n\t}\n\t\n\t// In some cases, if the landscape is at very low density, some individuals\n\t// might have a fitnessScaling value > 1.0. This value must be capped.\n\tp2.individuals.fitnessScaling = pmin(p2.individuals.fitnessScaling, 1.0);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.2 - Spatial competition.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries, spatial competition\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// Set up an interaction for spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\n1: late() {\n\t// evaluate interactions before fitness calculations\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\t// spatial competition\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.3 - Boundaries and boundary conditions I (stopping boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, stopping boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Stopping boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointStopped(pos));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.3 - Boundaries and boundary conditions II (reflecting boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reflecting boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Reflecting boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointReflected(pos));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.3 - Boundaries and boundary conditions III (absorbing boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, absorbing boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Absorbing boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tif (!p1.pointInBounds(pos))\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.3 - Boundaries and boundary conditions IV (reprising boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Reprising boundary conditions\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.3 - Boundaries and boundary conditions V (dispersal kernels).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, boundaries, boundary conditions, dispersal kernel\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\t// Dispersal and boundary enforcement\n\tp1.deviatePositions(NULL, \"reprising\", INF, \"n\", 0.02);\n\t\n\t// Evaluate for competition\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.4 - Mate choice with a spatial kernel.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n\ti2.setInteractionFunction(\"n\", 1.0, 0.02);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tinds.fitnessScaling = 1.1 - competition / size(inds);\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.5 - Mate choice with a nearest-neighbor search.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tinds.fitnessScaling = 1.1 - competition / size(inds);\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// nearest-neighbor spatial mate choice\n\tneighbors = i2.nearestNeighbors(individual, 3);\n\treturn (size(neighbors) ? sample(neighbors, 1) else float(0));\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.6 - Divergence due to phenotypic competition with an interaction() callback.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition, interaction()\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"\", reciprocal=T);     // competition\n\ti1.setInteractionFunction(\"f\", 1.0);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.tagF = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\ninteraction(i1) {\n\treturn dnorm(exerter.tagF, receiver.tagF, SIGMA_C) / NORM;\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.tagF;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.7 - Modeling phenotype as a spatial dimension.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeSLiMOptions(dimensionality=\"x\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"x\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSpatialBounds(c(0.0, 10.0));\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.x = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.x;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.8 - Sympatric speciation facilitated by assortative mating.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"SIGMA_M\", 0.5);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeSLiMOptions(dimensionality=\"x\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"x\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"x\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSpatialBounds(c(0.0, 10.0));\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.x = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.x;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 17.9 - Speciation due to spatial variation in selection.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries, QTL, quantitative trait loci, spatial competition, phenotypic competition, spatial mate choice\n\ninitialize() {\n\tdefineConstant(\"SIGMA_C\", 0.1);\n\tdefineConstant(\"SIGMA_K\", 0.5);\n\tdefineConstant(\"SIGMA_M\", 0.1);\n\tdefineConstant(\"SLOPE\", 1.0);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.1));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"xyz\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"xyz\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setSpatialBounds(c(0.0, 0.0, -SLOPE, 1.0, 1.0, SLOPE));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N));\n\tp1.individuals.z = 0.0;\n}\nmodifyChild() {\n\t// set offspring position based on parental position\n\tdo pos = c(parent1.spatialPosition[0:1] + rnorm(2, 0, 0.005), 0.0);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\toptima = (inds.x - 0.5) * SLOPE;\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, optima, SIGMA_K);\n\tinds.z = phenotypes;\n\t\n\t// color individuals according to phenotype\n\tfor (ind in inds)\n\t{\n\t\thue = ((ind.z + SLOPE) / (SLOPE * 2)) * 0.66;\n\t\tind.color = rgb2color(hsv2rgb(c(hue, 1.0, 1.0)));\n\t}\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n1:5001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.z;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.1 - A minimal tree-seq model.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tsim.treeSeqOutput(\"./overlay.trees\");\n}\n\n// Section 17.2's recipe, which is a Python script that overlays\n// neutral mutations onto the .trees file saved here, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq(simplificationRatio=INF, timeUnit=\"generations\");\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 1.0);\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 1e6 - 1);\n\tinitializeRecombinationRate(3e-10);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1e5);\n}\n100 late() {\n\tsample(p1.haplosomes, 1).addNewDrawnMutation(m2, 5e5);\n}\n100:10000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size() != 1)\n\t\tstop(sim.cycle + \": LOST\");\n\telse if (sum(sim.mutationFrequencies(NULL, mut)) == 1.0)\n\t{\n\t\tsim.treeSeqOutput(\"decap.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit, pyslim\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Load the .trees file\nts = tskit.load(\"decap.trees\")    # no simplify!\n\n# Calculate tree heights, giving uncoalesced sites the maximum time\ndef tree_heights(ts):\n    heights = np.zeros(ts.num_trees + 1)\n    for tree in ts.trees():\n        if tree.num_roots > 1:  # not fully coalesced\n            heights[tree.index] = ts.metadata['SLiM']['tick']\n        else:\n            children = tree.children(tree.root)\n            real_root = tree.root if len(children) > 1 else children[0]\n            heights[tree.index] = tree.time(real_root)\n    heights[-1] = heights[-2]  # repeat the last entry for plotting with step\n    return heights\n\n# Plot tree heights before recapitation\nbreakpoints = list(ts.breakpoints())\nheights = tree_heights(ts)\nplt.step(breakpoints, heights, where='post')\nplt.show()\n\n# Recapitate!\nrecap = pyslim.recapitate(ts, ancestral_Ne=1e5, recombination_rate=3e-10, random_seed=1)\nrecap.dump(\"recap.trees\")\n\n# Plot the tree heights after recapitation\nbreakpoints = list(recap.breakpoints())\nheights = tree_heights(recap)\nplt.step(breakpoints, heights, where='post')\nplt.show()\n\n\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.11 - Optimizing tree-sequence simplification.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, simplification\n\ninitialize() {\n\tsetSeed(0);\n\tinitializeTreeSeq(simplificationInterval=1000);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 10000); }\n50001 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.2 - Overlaying neutral mutations.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe, to be run after the section 17.1 recipe\n\nimport msprime, tskit\n\nts = tskit.load(\"./overlay.trees\")\nts = ts.simplify()\n\nfor t in ts.trees():\n    assert t.num_roots == 1, (\"not coalesced! on segment {} to {}\".format(t.interval[0], t.interval[1]))\n\nmutated = msprime.sim_mutations(ts, rate=1e-7, random_seed=1, keep=True)\nmutated.dump(\"./overlay_II.trees\")\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.01, 1.0);  // deleterious\n\tinitializeMutationType(\"m3\", 1.0, \"f\", 0.05);        // introduced\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(0.9, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tdefineConstant(\"simID\", getSeed());\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m3, 10000);\n\tdefineConstant(\"PATH\", tempdir() + \"slim_\" + simID + \".trees\");\n\tsim.outputFull(PATH);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m3) == 0) {\n\t\tif (sum(sim.substitutions.mutationType == m3) == 1) {\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\tsim.readFromPopulationFile(PATH);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, conditional sweep\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.01, 1.0);  // deleterious\n\tinitializeMutationType(\"m3\", 1.0, \"f\", 0.05);        // introduced\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tdefineConstant(\"simID\", getSeed());\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// assign tag values to be preserved\n\tinds = sortBy(sim.subpopulations.individuals, \"pedigreeID\");\n\ttags = rdunif(size(inds), 0, 100000);\n\tinds.tag = tags;\n\t\n\t// record tag values and pedigree IDs in metadata\n\tmetadataDict = Dictionary(\"tags\", tags, \"ids\", inds.pedigreeID);\n\t\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m3, 10000);\n\tdefineConstant(\"PATH\", tempdir() + \"slim_\" + simID + \".trees\");\n\tsim.treeSeqOutput(PATH, metadata=metadataDict);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m3) == 0) {\n\t\tif (sum(sim.substitutions.mutationType == m3) == 1) {\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.treeSeqOutput(\"slim_\" + simID + \"_FIXED.trees\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\tsim.readFromPopulationFile(PATH);\n\t\t\tmetadataDict = treeSeqMetadata(PATH);\n\t\t\ttags = metadataDict.getValue(\"tags\");\n\t\t\tinds = sortBy(sim.subpopulations.individuals, \"pedigreeID\");\n\t\t\tinds.tag = tags;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tdefineConstant(\"N\", 10000);  // pop size\n\tdefineConstant(\"L\", 1e8);    // total chromosome length\n\tdefineConstant(\"L0\", 200e3); // between genes\n\tdefineConstant(\"L1\", 1e3);   // gene length\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8, L-1);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -(5/N), 1.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\t\n\tfor (start in seq(from=L0, to=L-(L0+L1), by=(L0+L1)))\n\t\tinitializeGenomicElement(g2, start, (start+L1)-1);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", N);\n}\n10*N late() {\n\tsim.treeSeqOutput(\"./diversity.trees\");\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe; note that it runs the SLiM model internally, below\n\nimport subprocess, tskit\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Run the SLiM model and load the resulting .trees\nsubprocess.check_output([\"slim\", \"-m\", \"-s\", \"0\", \"./diversity.slim\"])\nts = tskit.load(\"./diversity.trees\")\nts = ts.simplify()\n\n# Measure the tree height at each base position\nheight_for_pos = np.zeros(int(ts.sequence_length))\nfor tree in ts.trees():\n    mean_height = np.mean([tree.time(root) for root in tree.roots])\n    left, right = map(int, tree.interval)\n    height_for_pos[left: right] = mean_height\n\n# Convert heights along chromosome into heights at distances from gene\nheight_for_pos = height_for_pos - np.min(height_for_pos)\nL, L0, L1 = int(1e8), int(200e3), int(1e3)   # total length, length between genes, gene length\ngene_starts = np.arange(L0, L - (L0 + L1) + 1, L0 + L1)\ngene_ends = gene_starts + L1 - 1\nmax_d = L0 // 4\nheight_for_left_dist = np.zeros(max_d)\nheight_for_right_dist = np.zeros(max_d)\nfor d in range(max_d):\n    height_for_left_dist[d] = np.mean(height_for_pos[gene_starts - d - 1])\n    height_for_right_dist[d] = np.mean(height_for_pos[gene_ends + d + 1])\nheight_for_distance = np.hstack([height_for_left_dist[::-1], height_for_right_dist])\ndistances = np.hstack([np.arange(-max_d, 0), np.arange(1, max_d + 1)])\n\n# Make a simple plot\nplt.plot(distances, height_for_distance)\nplt.show()\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, migration, dispersal\n\ninitialize() {\n\tdefineConstant(\"L\", 1e8);\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.1);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tsim.treeSeqRememberIndividuals(sim.subpopulations.individuals);\n\t\n\tp1.haplosomes.addNewDrawnMutation(m1, asInteger(L * 0.2));\n\tp2.haplosomes.addNewDrawnMutation(m1, asInteger(L * 0.8));\n\t\n\tsim.addSubpop(\"p3\", 1000);\n\tp3.setMigrationRates(c(p1, p2), c(0.5, 0.5));\n}\n2 late() {\n\tp3.setMigrationRates(c(p1, p2), c(0.0, 0.0));\n\tp1.setSubpopulationSize(0);\n\tp2.setSubpopulationSize(0);\n}\n2: late() {\n\tif (sim.mutationsOfType(m1).size() == 0)\n\t{\n\t\tsim.treeSeqOutput(\"./admix.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n10000 late() {\n\tstop(\"Did not reach fixation of beneficial alleles.\");\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe; note that it runs the SLiM model internally, below\n\nimport subprocess, tskit\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Run the SLiM model and load the resulting .trees file\nsubprocess.check_output([\"slim\", \"-m\", \"-s\", \"0\", \"./admix.slim\"])\nts = tskit.load(\"./admix.trees\")\n\n# Load the .trees file and assess true local ancestry\nbreaks = np.zeros(ts.num_trees + 1)\nancestry = np.zeros(ts.num_trees + 1)\nfor tree in ts.trees():\n    subpop_sum, subpop_weights = 0, 0\n    for root in tree.roots:\n        leaves_count = tree.num_samples(root) - 1  # subtract one for the root, which is a sample\n        subpop_sum += tree.population(root) * leaves_count\n        subpop_weights += leaves_count\n    breaks[tree.index] = tree.interval[0]\n    ancestry[tree.index] = subpop_sum / subpop_weights\nbreaks[-1] = ts.sequence_length\nancestry[-1] = ancestry[-2]\n\n# Make a simple plot\nplt.plot(breaks, ancestry)\nplt.show()\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.6 - Measuring the coalescence time of a model I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq(checkCoalescence=T);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tif (sim.treeSeqCoalesced())\n\t{\n\t\tcatn(sim.cycle + \": COALESCED\");\n\t\tsim.simulationFinished();\n\t}\n}\n100000 late() {\n\tcatn(\"NO COALESCENCE BY CYCLE 100000\");\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.6 - Measuring the coalescence time of a model II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, deferred scheduling, variable-length burn-in\n\ninitialize() {\n\tinitializeTreeSeq(checkCoalescence=T);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tif (sim.treeSeqCoalesced())\n\t{\n\t\tcatn(community.tick + \": COALESCED\");\n\t\tdefineConstant(\"COALESCE\", community.tick);\n\t\tcommunity.deregisterScriptBlock(self);\n\t}\n}\nCOALESCE+100 late() {\n\tcatn(community.tick + \": FINISHED\");\n\tsim.simulationFinished();\n}\n100000 late() {\n\tcatn(\"NO COALESCENCE BY CYCLE 100000\");\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-10);\n\tinitializeMutationType(\"m1\", 0.5, \"g\", 0.1, 0.1);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.1, 0.1);\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 1.0));\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n20000 late() { sim.treeSeqOutput(\"./selcoeff.trees\"); }\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit\n\nts = tskit.load(\"selcoeff.trees\")\n\n# selection coefficients of all selected mutations\ncoeffs = []\nfor mut in ts.mutations():\n    md = mut.metadata\n    sel = [x[\"selection_coeff\"] for x in md[\"mutation_list\"]]\n    if any([s != 0 for s in sel]):\n        coeffs += sel\n\nb = [x for x in coeffs if x > 0]\nd = [x for x in coeffs if x < 0]\n\nprint(\"Beneficial: \" + str(len(b)) + \", mean \" + str(sum(b) / len(b)))\nprint(\"Deleterious: \" + str(len(d)) + \", mean \" + str(sum(d) / len(d)))\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history I.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport msprime, pyslim\n\nts = msprime.sim_ancestry(samples=5000, population_size=5000, sequence_length=1e8,\n    recombination_rate=1e-8)\nslim_ts = pyslim.annotate(ts, model_type=\"WF\", tick=1)\nslim_ts.dump(\"coalasex.trees\")\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\n// Part I of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.readFromPopulationFile(\"coalasex.trees\");\n\ttarget = sample(sim.subpopulations.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1: late() {\n\tif (sim.mutationsOfType(m2).size() == 0) {\n\t\tprint(sim.substitutions.size() ? \"FIXED\" else \"LOST\");\n\t\tsim.treeSeqOutput(\"coalasex_II.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n2000 early() { sim.simulationFinished(); }\n\n// Part III of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history III.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit\n\nts = tskit.load(\"coalasex_II.trees\").simplify()\n\nfor tree in ts.trees():\n    for root in tree.roots:\n        print(tree.time(root))\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history I.py",
    "content": "# Keywords: Python, nonWF, non-Wright-Fisher, tree-sequence recording, tree sequence recording\n\nimport msprime, pyslim, random\nimport numpy as np\n\nts = msprime.sim_ancestry(samples=5000, population_size=5000,\n    sequence_length=1e8, recombination_rate=1e-8)\n\ntables = ts.dump_tables()\npyslim.annotate_tables(tables, model_type=\"nonWF\", tick=1)\n\n# add sexes and ages\nindividual_metadata = [ind.metadata for ind in tables.individuals]\nfor md in individual_metadata:\n    md[\"sex\"] = random.choice([pyslim.INDIVIDUAL_TYPE_FEMALE, pyslim.INDIVIDUAL_TYPE_MALE])\n    md[\"age\"] = random.choice([0, 1, 2, 3, 4])\n\nims = tables.individuals.metadata_schema\ntables.individuals.packset_metadata(\n        [ims.validate_and_encode_row(md) for md in individual_metadata])\n\n# add selected mutation\nmut_ind_id = random.choice(range(tables.individuals.num_rows))\nmut_node_id = random.choice(np.where(tables.nodes.individual == mut_ind_id)[0])\nmut_node = tables.nodes[mut_node_id]\nmut_metadata = {\n        \"mutation_list\": [\n            {\n              \"mutation_type\": 2,\n              \"selection_coeff\": 0.1,\n              \"subpopulation\": mut_node.population,\n              \"slim_time\": int(tables.metadata['SLiM']['tick'] - mut_node.time),\n              \"nucleotide\": -1\n            }\n        ]\n    }\nsite_num = tables.sites.add_row(position=5000, ancestral_state='')\ntables.mutations.add_row(\n        node=mut_node_id,\n        site=site_num,\n        derived_state='1',\n        time=mut_node.time,\n        metadata=mut_metadata)\n\nslim_ts = tables.tree_sequence()\nslim_ts.dump(\"coalsex.trees\")\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history II.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, sexual, tree-sequence recording, tree sequence recording, reproduction()\n\n// Part I of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeTreeSeq();\n\tinitializeSex();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.convertToSubstitution=T;\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction(NULL, \"F\") {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.readFromPopulationFile(\"coalsex.trees\");\n}\nearly() {\n\tp0.fitnessScaling = 5000 / p0.individualCount;\n}\n1: late() {\n\tif (sim.mutationsOfType(m2).size() == 0) {\n\t\tprint(sim.substitutions.size() ? \"FIXED\" else \"LOST\");\n\t\tsim.treeSeqOutput(\"coalsex_II.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n2000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.1 - A simple neutral nucleotide-based model.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.10 - Varying the mutation rate along the chromosome in a nucleotide-based model.txt",
    "content": "// Keywords: nucleotide-based, hot spot, cold spot, variable mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tm1.color = \"black\";\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmKimura(1.8e-07, 6e-08));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tends = c(sort(sample(0:(L-2), 99)), L-1);\n\tmultipliers = rlnorm(100, 0.0, 0.75);\n\tinitializeHotspotMap(multipliers, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.11 - Modeling GC-biased gene conversion (gBGC).txt",
    "content": "// Keywords: nucleotide-based, gene conversion, GC-bias, GC biased gene conversion, GC content\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"alpha\", 2.5e-6);\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(alpha));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-5);\n\tinitializeGeneConversion(0.7, 1500, 0.80, 0.10);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1:500001 early() {\n\tif (sim.cycle % 1000 == 1) {\n\t\tcat(sim.cycle + \": \");\n\t\tprint(nucleotideFrequencies(sim.chromosomes.ancestralNucleotides()));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.12 - Reading VCF files to create nucleotide-based SNPs.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence, VCF file reading, empirical population, SNPs, 1000 Genomes Project\n\n// The input files used here can be downloaded from http://benhaller.com/slim/recipe_19_12_files.zip\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tlength = initializeAncestralNucleotides(\"hs37d5_chr22_patched.fa\");\n\tdefineConstant(\"L\", length);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationTypeNuc(\"m2\", 0.5, \"f\", 0.0);\n\tm2.color = \"red\";\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(0.0));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 99);\n\tp1.haplosomes.readHaplosomesFromVCF(\"chr22_filtered.recode.vcf\", m1);\n\tp1.setSubpopulationSize(1000);\n}\n5 late() {\n\tmut = sample(sim.mutations, 1);\n\tmut.setMutationType(m2);\n\tmut.setSelectionCoeff(0.5);\n}\n1:2000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size()) {\n\t\tf = sim.mutationFrequencies(p1, mut);\n\t\tcatn(sim.cycle + \": \" + sim.mutations.size() + \", f = \" + f);\n\t\t\n\t\tif (f == 1.0) {\n\t\t\tcatn(\"\\nFIXED in cycle \" + sim.cycle);\n\t\t\tcatn(sim.substitutions.size() + \" substitutions.\");\n\t\t\tcatn(paste(sim.substitutions.nucleotide));\n\t\t\tsim.simulationFinished();\n\t\t}\n\t} else {\n\t\tcatn(sim.cycle + \": \" + sim.mutations.size());\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models I.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeTreeSeq();\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-6));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-6);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n1000 late() { sim.treeSeqOutput(\"recipe_nucleotides.trees\"); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models II.py",
    "content": "# Keywords: Python, nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\nimport tskit, pyslim\nimport numpy as np\n\nts = tskit.load(\"recipe_nucleotides.trees\")\n\nM = [[0 for _ in pyslim.NUCLEOTIDES] for _ in pyslim.NUCLEOTIDES]\nfor mut in ts.mutations():\n    mut_list = mut.metadata[\"mutation_list\"]\n    k = np.argmax([u[\"slim_time\"] for u in mut_list])\n    derived_nuc = mut_list[k][\"nucleotide\"]\n    if mut.parent == -1:\n        acgt = ts.reference_sequence.data[int(ts.site(mut.site).position)]\n        parent_nuc = pyslim.NUCLEOTIDES.index(acgt)\n    else:\n        parent_mut = ts.mutation(mut.parent)\n        assert(parent_mut.site == mut.site)\n        parent_nuc = parent_mut.metadata[\"mutation_list\"][0][\"nucleotide\"]\n    M[parent_nuc][derived_nuc] += 1\n\nprint(\"{}\\t{}\\t{}\".format('ancestral', 'derived', 'count'))\nfor j, a in enumerate(pyslim.NUCLEOTIDES):\n    for k, b in enumerate(pyslim.NUCLEOTIDES):\n        print(\"{}\\t{}\\t{}\".format(a, b, M[j][k]))\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models III.py",
    "content": "# Keywords: Python, nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\nimport tskit, pyslim\nimport numpy as np\n\nts = tskit.load(\"recipe_nucleotides.trees\")\nslim_gen = ts.metadata[\"SLiM\"][\"tick\"]\n\nM = np.zeros((4,4,4,4), dtype='int')\nfor mut in ts.mutations():\n    pos = ts.site(mut.site).position \n    # skip mutations at the end of the sequence\n    if pos > 0 and pos < ts.sequence_length - 1:\n        mut_list = mut.metadata[\"mutation_list\"]\n        k = np.argmax([u[\"slim_time\"] for u in mut_list])\n        derived_nuc = mut_list[k][\"nucleotide\"]\n        pretime = mut.time + 1.0\n        left_nuc = pyslim.nucleotide_at(ts, mut.node, pos - 1, time = pretime)\n        right_nuc = pyslim.nucleotide_at(ts, mut.node, pos + 1, time = pretime)\n        parent_nuc = pyslim.nucleotide_at(ts, mut.node, pos, time = pretime)\n        M[left_nuc, parent_nuc, right_nuc, derived_nuc] += 1\n\nprint(\"{}\\t{}\\t{}\".format('ancestral', 'derived', 'count'))\nfor j0, a0 in enumerate(pyslim.NUCLEOTIDES):\n    for j1, a1 in enumerate(pyslim.NUCLEOTIDES):\n        for j2, a2 in enumerate(pyslim.NUCLEOTIDES):\n            for k, b in enumerate(pyslim.NUCLEOTIDES):\n                print(\"{}{}{}\\t{}{}{}\\t{}\".format(a0, a1, a2, a0, b, a2,\n                        M[j0, j1, j2, k]))\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.14 - Modeling identity by state (IBS) (uniquing mutations with a mutation() callback).txt",
    "content": "// Keywords: IBS, identity by state, IBD, identity by descent, unique down\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(100));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-4 / 3));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(1e-3);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation() {\n\tm = sim.subsetMutations(position=mut.position, nucleotide=mut.nucleotide);\n\tif (m.length())\n\t\treturn m;\n\treturn T;\n}\n1000 late() {\n\tfor (pos in 0:99)\n\t{\n\t\tmuts = sim.subsetMutations(position=pos);\n\t\tnucs = muts.nucleotide;\n\t\tcat(pos + \" : \" + paste(nucs));\n\t\tif (size(nucs) != size(unique(nucs)))\n\t\t\tcat(\"     DUPLICATES!\");\n\t\tcatn();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.15 - Modeling identity by state (IBS) (uniquing back-mutations to the ancestral state).txt",
    "content": "// Keywords: IBS, identity by state, IBD, identity by descent, unique down, back-mutation\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(100));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-4 / 3));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(1e-3);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation() {\n\tm = sim.subsetMutations(position=mut.position, nucleotide=mut.nucleotide);\n\tif (m.length())\n\t\treturn m;\n\treturn T;\n}\nlate() {\n\t// unique new mutations down to the ancestral state\n\tmuts = sim.mutations;\n\tnew_muts = muts[muts.originTick == community.tick];\n\tback_muts = NULL;\n\tfor (mut in new_muts)\n\t{\n\t\tpos = mut.position;\n\t\tif (mut.nucleotide == sim.chromosomes.ancestralNucleotides(pos, pos))\n\t\t\tback_muts = c(back_muts, mut);\n\t}\n\tif (size(back_muts))\n\t\tsim.subpopulations.haplosomes.removeMutations(back_muts);\n}\n1000 late() {\n\tfor (pos in 0:99)\n\t{\n\t\tmuts = sim.subsetMutations(position=pos);\n\t\tnucs = muts.nucleotide;\n\t\tancestral = sim.chromosomes.ancestralNucleotides(pos, pos);\n\t\tcat(pos + \" : \" + paste(nucs));\n\t\tif (size(nucs) != size(unique(nucs)))\n\t\t\tcat(\"     DUPLICATES!\");\n\t\tif (any(nucs == ancestral))\n\t\t\tcat(\"     BACK-MUTATION (\" + ancestral + \")!\");\n\t\tcatn();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.2 - Reading an ancestral nucleotide sequence from a FASTA file.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tdefineConstant(\"L\", initializeAncestralNucleotides(\"FASTA.txt\"));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmKimura(1.8e-07, 6e-08));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.3 - Sequence output from nucleotide-based models.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence\n\ninitialize() {\n\tdefineConstant(\"L\", 10);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-5));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tc = sim.chromosomes;\n\tcatn(\"Ancestral: \" + c.ancestralNucleotides());\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"char\")));\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n\tcatn();\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tcatn(\"Fixed:     \" + paste(sim.substitutions.nucleotide));\n\tcatn(\"Fixed:     \" + paste(sim.substitutions.nucleotideValue));\n\tcatn(\"positions: \" + paste(sim.substitutions.position));\n\tcatn();\n\t\n\tc = sim.chromosomes;\n\tcatn(\"Ancestral: \" + c.ancestralNucleotides());\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"char\")));\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n\tcatn();\n\t\n\tg = p1.haplosomes[0];\n\t\n\tcatn(\"SNPs:      \" + paste(g.mutations.nucleotide));\n\tcatn(\"SNPs:      \" + paste(g.mutations.nucleotideValue));\n\tcatn(\"positions: \" + paste(g.mutations.position));\n\tcatn();\n\t\n\tcatn(\"Derived:   \" + g.nucleotides());\n\tcatn(\"Derived:   \" + paste(g.nucleotides(format=\"char\")));\n\tcatn(\"Derived:   \" + paste(g.nucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.4 - Back-mutations, independent mutational lineages, and VCF output.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 10);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-5));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tg = p1.sampleIndividuals(5).haplosomes;\n\tg.outputHaplosomesToVCF(simplifyNucleotides=F);\n\tg.outputHaplosomesToVCF(simplifyNucleotides=T);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.5 - Modeling elevated CpG mutation rates and equilibrium nucleotide frequencies.txt",
    "content": "// Keywords: nucleotide-based, sequence-based mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"mu\", 7.5e-6);\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\t\n\tmm = mm16To256(mmJukesCantor(mu / 3));\n\txcg = c(\"ACG\", \"CCG\", \"GCG\", \"TCG\");\n\txcg_codons = nucleotidesToCodons(paste0(xcg));\n\tmm[xcg_codons,3] = mm[xcg_codons,3] * 20;  // rates to T\n\tcgx = c(\"CGA\", \"CGC\", \"CGG\", \"CGT\");\n\tcgx_codons = nucleotidesToCodons(paste0(cgx));\n\tmm[cgx_codons,0] = mm[cgx_codons,0] * 20;  // rates to A\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mutationMatrix=mm);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\n1:10000000 early() {\n\tif (sim.cycle % 10000 == 1) {\n\t\tcat(sim.cycle + \": \");\n\t\tprint(nucleotideFrequencies(sim.chromosomes.ancestralNucleotides()));\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.6 - A nucleotide-based model with introduced non-nucleotide-based mutations.txt",
    "content": "// Keywords: nucleotide-based, non-nucleotide-based, mixed model\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsample(p1.haplosomes, 10).addNewDrawnMutation(m2, 20000);\n}\n2000 late() {\n\tprint(sim.mutationsOfType(m2));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.7 - Using standard SLiM fitness effects with nucleotides (modeling synonymous sites).txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(3e5));\n\t\n\tmm = mmJukesCantor(2.5e-8);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);         // neutral\n\tinitializeMutationTypeNuc(\"m2\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(3,3), mm);  // pos 1/2\n\tinitializeGenomicElementType(\"g2\", c(m1,m2), c(5,1), mm);  // pos 3\n\tinitializeRecombinationRate(1e-8);\n\t\n\ttypes = rep(c(g1,g2), 1e5);\n\tstarts = repEach(seqLen(1e5) * 3, 2) + rep(c(0,2), 1e5);\n\tends = starts + rep(c(1,0), 1e5);\n\tinitializeGenomicElement(types, starts, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1e6 late() {\n\tsub = sim.substitutions;\n\tpos3 = (sub.position % 3 == 2);\n\tpos12 = !pos3;\n\t\n\tcatn(size(sub) + \" substitutions occurred.\");\n\tcatn(mean(sub.mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub.mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n\tcatn(size(sub[pos12]) + \" substitutions are at position 1 or 2.\");\n\tcatn(mean(sub[pos12].mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub[pos12].mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n\tcatn(size(sub[pos3]) + \" substitutions are at position 3.\");\n\tcatn(mean(sub[pos3].mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub[pos3].mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.8 - Defining sequence-based fitness effects at the nucleotide level.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e4);\n\tdefineConstant(\"EFF\", c(1.0, 0.1, 1.5, 3.0));\n\tinitializeSLiMOptions(nucleotideBased=T);\n\t\n\tseq = randomNucleotides(100) + 'A' + randomNucleotides(1e4 - 101);\n\tinitializeAncestralNucleotides(seq);\n\t\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\tif (sum(sim.mutations.position == 100) == 0)\n\t\ts1.active = 0;\n}\ns1 fitnessEffect() {\n\tnuc1 = individual.haploidGenome1.nucleotides(100, 100, format=\"integer\");\n\tnuc2 = individual.haploidGenome2.nucleotides(100, 100, format=\"integer\");\n\treturn EFF[nuc1] * EFF[nuc2];\n}\n10000 late() {\n\tsubs = sim.substitutions[sim.substitutions.position == 100];\n\t\n\tfor (sub in subs)\n\t\tcatn(\"Sub to \" + sub.nucleotide + \" in \"  + sub.fixationTick);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 19.9 - Defining sequence-based fitness effects at the amino acid level.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e4);\n\tdefineConstant(\"TAA\", nucleotidesToCodons(\"TAA\"));\n\tdefineConstant(\"TAG\", nucleotidesToCodons(\"TAG\"));\n\tdefineConstant(\"TGA\", nucleotidesToCodons(\"TGA\"));\n\tdefineConstant(\"STOP\", c(TAA, TAG, TGA));\n\tdefineConstant(\"NONSTOP\", (0:63)[match(0:63, STOP) < 0]);\n\t\n\tcodons = sample(NONSTOP, 194, replace=T);\n\tseq1 = randomNucleotides(253);\n\tseq2 = paste0(codonsToNucleotides(codons, format=\"char\")[0:417]);\n\tseq3 = randomNucleotides(200);\n\tseq4 = paste0(codonsToNucleotides(codons, format=\"char\")[418:581]);\n\tseq5 = randomNucleotides(L-1035);\n\tseq = seq1 + seq2 + seq3 + seq4 + seq5;\n\tcatn(\"Initial AA sequence: \" + codonsToAminoAcids(codons));\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(seq);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-6));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nfitnessEffect() {\n\tfor (g in individual.haplosomes)\n\t{\n\t\tseq = g.nucleotides(253, 670) + g.nucleotides(871, 1034);\n\t\tcodons = nucleotidesToCodons(seq);\n\t\tif (sum(match(codons, STOP) >= 0))\n\t\t\treturn 0.0;\n\t}\n\t\n\treturn 1.0;\n}\n100000 late() {\n\tcatn(sim.substitutions.size() + \" fixed mutations.\");\n\t\n\tas1 = sim.chromosomes.ancestralNucleotides(253, 670, \"integer\");\n\tas2 = sim.chromosomes.ancestralNucleotides(871, 1034, \"integer\");\n\tas = c(as1, as2);\n\tcodons = nucleotidesToCodons(as);\n\tcatn(\"Final AA sequence: \" + codonsToAminoAcids(codons));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.1 - A simple multispecies model.txt",
    "content": "// Keywords: multispecies\n\nspecies sim initialize()\n{\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nticks all 1 early()\n{\n\tsim.addSubpop(\"p1\", 500);\n}\nticks all 2000 late()\n{\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.2 - A two-species model.txt",
    "content": "// Keywords: multispecies\n\nspecies fox initialize() {\n\tinitializeSpecies(tickModulo=3, tickPhase=5, avatar=\"🦊\");\n}\nspecies mouse initialize() {\n\tinitializeSpecies(tickModulo=1, tickPhase=1, avatar=\"🐭\");\n}\nticks all 1 early() {\n\tfox.addSubpop(\"p1\", 50);\n\tmouse.addSubpop(\"p2\", 500);\n}\nticks all 2000 late() {\n\tfox.outputFixedMutations();\n\tmouse.outputFixedMutations();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.3 - A deterministic host-parasitoid model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n}\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\nticks all late() {\n\tx1 = p1.individualCount / S;      // host density\n\tx2 = p2.individualCount / S;      // parasitoid density\n\t\n\tx1′ = x1 * exp(R - x1/K - A*x2);  // x1[t+1]\n\tx2′ = x1 * (1 - exp(-A*x2));      // x2[t+1]\n\t\n\tp1.setSubpopulationSize(asInteger(round(S * x1′)));\n\tp2.setSubpopulationSize(asInteger(round(S * x2′)));\n}\nticks all 250 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.4 - An individual-based host-parasitoid model I.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host indicate survival (0) or death (1)\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n}\n\nticks all first()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// assess densities\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// hunt: each parasitoid counts its successes, and\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tP_parasitized = 1 - exp(-A * x2);\n\tkilled = rbinom(hosts.size(), 1, P_parasitized);\n\thosts.tag = killed;\t// 1 means killed\n\thunters = sample(parasitoids, sum(killed), replace=T);\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\tsurvivors = hosts[killed == 0];\n\t\n\t// competition: kill a fraction of survivors; note\n\t// that this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tsurvived = rbinom(survivors.size(), 1, P_survives);\n\tdead = survivors[survived == 0];\t// 1 means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\n\n// non-overlapping generations: parents die, offspring live\nspecies host survival() {\n\treturn (individual.age == 0);\n}\nspecies parasitoid survival() {\n\treturn (individual.age == 0);\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.4 - An individual-based host-parasitoid model II.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host are unused\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n}\n\nspecies host reproduction() {\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\n\nticks all early()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// first, kill off the parental generation\n\thost_age = hosts.age;\n\thosts[host_age > 0].fitnessScaling = 0.0;\n\t\n\tparasitoid_age = parasitoids.age;\n\tparasitoids[parasitoid_age > 0].fitnessScaling = 0.0;\n\t\n\t// narrow down to the juveniles and assess densities\n\thosts = hosts[host_age == 0];\n\tparasitoids = parasitoids[parasitoid_age == 0];\n\t\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// next, hunt; each parasitoid counts its successes\n\tparasitoids.tag = 0;\n\tP_parasitized = 1 - exp(-A * x2);\n\tluck = rbinom(hosts.size(), 1, P_parasitized);\n\tdead = hosts[luck == 1];\n\tdead.fitnessScaling = 0.0;\n\thunters = sample(parasitoids, dead.size(), replace=T);\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\thosts = hosts[luck == 0];\n\t\n\t// finally, competition kills a fraction of survivors\n\t// this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tluck = rbinom(hosts.size(), 1, P_survives);\n\tdead = hosts[luck == 0];\n\tdead.fitnessScaling = 0.0;\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.5 - A continuous-space host-parasitoid model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"SIDE\", 10);\t// one side length; square root of S\n\tdefineConstant(\"S\", SIDE*SIDE);\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tdefineConstant(\"S_P\", 0.5);\t// parasitoid hunting/mating kernel width\n\tdefineConstant(\"S_H\", 0.2);\t// host competition/mating kernel width\n\tdefineConstant(\"D_H\", 0.2);\t// host dispersal kernel width\n\tdefineConstant(\"CROSS_SCRIPT\", \"subpop.addCrossed(individual, mate);\");\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\t// parasitoids looking for things (long search distance)\n\tinitializeInteractionType(1, \"xy\", maxDistance=S_P);\n\ti1.setInteractionFunction(\"l\", 1.0);\n\t\n\t// hosts looking for things (short search distance)\n\tinitializeInteractionType(2, \"xy\", maxDistance=S_H);\n\ti2.setInteractionFunction(\"l\", 1.0);\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\t// tag values in host indicate survival (0) or death (1)\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\t// tag values in parasitoid count successful hunts\n}\n\nticks all 2: first()\n{\n\thost_pop = host.subpopulations;\n\thosts = host_pop.individuals;\n\tparasitoid_pop  = parasitoid.subpopulations;\n\tparasitoids  = parasitoid_pop.individuals;\n\t\n\t// assess densities, per individual\n\ti1.evaluate(c(host_pop, parasitoid_pop));\n\ti2.evaluate(host_pop);\n\tparasitoid_density_byhost = i1.localPopulationDensity(hosts, parasitoid_pop);\n\t\n\t// hunt: each parasitoid counts its successes,\n\t// and remembers the positions of its prey;\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tparasitoids.setValue(\"PREY_POS\", NULL);\n\tP_parasitized_byhost = 1 - exp(-A * parasitoid_density_byhost);\n\tkilled = (runif(hosts.size()) < P_parasitized_byhost);\n\thosts.tag = asInteger(killed);           // T/1 means killed\n\tpreys = hosts[killed];\n\tfor (prey in preys)\n\t{\n\t\thunter = i1.drawByStrength(prey, 1, parasitoid_pop);\n\t\tpreyPos = prey.spatialPosition;\n\t\tpreyPos = c(hunter.getValue(\"PREY_POS\"), preyPos);\n\t\thunter.tag = hunter.tag + 1;\n\t\thunter.setValue(\"PREY_POS\", preyPos);\n\t}\n\tunhunted = hosts[!killed];\n\t\n\t// competition: kill a fraction of unhunted; note\n\t// that this is based on pre-parasitism density\n\thost_density_by_unhunted = i2.localPopulationDensity(unhunted, host_pop);\n\tP_survives_by_unhunted = exp(-host_density_by_unhunted / K);\n\tsurvived = (runif(unhunted.size()) < P_survives_by_unhunted);\n\tdead = unhunted[!survived];\t// T means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tmate = i2.drawByStrength(individual);\n\t\t\n\tif (mate.size())\n\t{\n\t\tlitterSize = rpois(1, exp(R));\n\t\n\t\tif (litterSize > 0)\n\t\t{\n\t\t\toffspring = sapply(seqLen(litterSize), CROSS_SCRIPT);\n\t\t\t\n\t\t\t// vectorized set of offspring spatial positions, based\n\t\t\t// on the first parent position plus dispersal D_H\n\t\t\tpositions = rep(individual.spatialPosition, litterSize);\n\t\t\tpositions = positions + rnorm(litterSize * 2, 0, D_H);\n\t\t\tpositions = p1.pointReflected(positions);\n\t\t\toffspring.setSpatialPosition(positions);\n\t\t}\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = i1.drawByStrength(individual);\n\t\t\n\t\tif (mate.size())\n\t\t{\n\t\t\toffspring = sapply(seqLen(litterSize), CROSS_SCRIPT);\n\t\t\t\n\t\t\t// vectorized set of offspring positions to prey positions\n\t\t\toffspring.setSpatialPosition(individual.getValue(\"PREY_POS\"));\n\t\t}\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tp1.setSpatialBounds(c(0, 0, SIDE, SIDE));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N0_host));\n\t\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n\tp2.setSpatialBounds(c(0, 0, SIDE, SIDE));\n\tp2.individuals.setSpatialPosition(p2.pointUniform(N0_parasitoid));\n}\n\n// non-overlapping generations: parents die, offspring live\nspecies host survival() {\n\treturn (individual.age == 0);\n}\nspecies parasitoid survival() {\n\treturn (individual.age == 0);\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.6 - A coevolutionary host-parasitoid trait-matching model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tdefineConstant(\"S_M\", 1.0);\t// parasitoid/host matching width\n\tdefineConstant(\"S_S\", 2.0);\t// stabilizing fitness function width\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host indicate survival (0) or death (1)\n\t// tagF values in host are QTL-based additive phenotypes\n\t\n\t// one short QTL controlling parasitism avoidance\n\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.1);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n\t// tagF values in parasitoid are QTL-based additive phenotypes\n\t\n\t// one short QTL controlling host trait matching\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.1);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tinitializeGenomicElement(g2, 0, 9999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies host mutationEffect(m1) { return 1.0; }\nspecies parasitoid mutationEffect(m2) { return 1.0; }\n\nticks all 2: first()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// assess densities\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// assess matches between hosts and the mean parasitoid\n\thost_values = hosts.tagF;\n\tparasitoid_values = parasitoids.tagF;\n\tmean_parasitoid = mean(parasitoid_values);\n\tscale = dnorm(0.0, 0.0, S_M);\n\thost_match = dnorm(host_values, mean_parasitoid, S_M) / scale;\n\t\n\t// hunt: each parasitoid counts its successes, and\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tP_parasitized_byhost = 1 - exp(-A * x2 * host_match);\n\tkilled = rbinom(hosts.size(), 1, P_parasitized_byhost);\n\thosts.tag = killed;\t// 1 means killed\n\thunters = sapply(hosts[killed == 1], \"sample(parasitoids, 1, \" +\n\t\t\"weights=dnorm(applyValue.tagF - parasitoid_values, 0.0, S_M));\");\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\tsurvivors = hosts[killed == 0];\n\t\n\t// competition: kill a fraction of survivors; note\n\t// that this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tsurvived = rbinom(survivors.size(), 1, P_survives);\n\tdead = survivors[survived == 0];\t// 1 means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n\t\n\tlog = community.createLogFile(\"host-parasite log.txt\", logInterval=1);\n\tlog.addTick();\n\tlog.addPopulationSize(host);\n\tlog.addMeanSDColumns(\"host\", \"p1.individuals.tagF;\");\n\tlog.addPopulationSize(parasitoid);\n\tlog.addMeanSDColumns(\"parasitoid\", \"p2.individuals.tagF;\");\n}\n\nticks all early() {\n\t// calculate phenotypes and implement stabilizing selection\n\tscale = dnorm(0.0, 0.0, S_S);\n\t\n\thosts = host.subpopulations.individuals;\n\tphenotypes = hosts.sumOfMutationsOfType(m1);\n\thosts.fitnessScaling = dnorm(phenotypes, 0.0, S_S) / scale;\n\thosts.tagF = phenotypes;\n\t\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\tphenotypes = parasitoids.sumOfMutationsOfType(m2);\n\tparasitoids.fitnessScaling = dnorm(phenotypes, 0.0, S_S) / scale;\n\tparasitoids.tagF = phenotypes;\n\t\n\t// non-overlapping generations: parents die, offspring live\n\thosts[hosts.age > 0].fitnessScaling = 0.0;\n\tparasitoids[parasitoids.age > 0].fitnessScaling = 0.0;\n}\n\nticks all 10000 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.7 - A coevolutionary host-parasite matching-allele model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"L\", 1);\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🦌\");\n\t\n\t// one nucleotide controlling infection\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-3));\n\tinitializeGenomicElement(g1, 0, L - 1);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies parasite initialize() {\n\tinitializeSpecies(avatar=\"🐛\");\n\t\n\t// one nucleotide controlling resistance\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m2\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0, mmJukesCantor(1e-3));\n\tinitializeGenomicElement(g2, 0, L - 1);\n\tinitializeRecombinationRate(1e-8);\n}\n\nfunction (float$)nucleotideFreq(o<Species>$ species, s$ nuc) {\n\tnucs = species.subpopulations.individuals.haplosomes.nucleotides();\n\treturn mean(nucs == nuc);\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p0\", 1000);\n\tparasite.addSubpop(\"p1\", 1000);\n\t\n\tlog = community.createLogFile(\"host-parasite log.txt\", logInterval=1);\n\tlog.addTick();\n\tlog.addCustomColumn(\"hA\", \"nucleotideFreq(host, 'A');\");\n\tlog.addCustomColumn(\"hC\", \"nucleotideFreq(host, 'C');\");\n\tlog.addCustomColumn(\"hG\", \"nucleotideFreq(host, 'G');\");\n\tlog.addCustomColumn(\"hT\", \"nucleotideFreq(host, 'T');\");\n\tlog.addCustomColumn(\"pA\", \"nucleotideFreq(parasite, 'A');\");\n\tlog.addCustomColumn(\"pC\", \"nucleotideFreq(parasite, 'C');\");\n\tlog.addCustomColumn(\"pG\", \"nucleotideFreq(parasite, 'G');\");\n\tlog.addCustomColumn(\"pT\", \"nucleotideFreq(parasite, 'T');\");\n}\n\nticks all late() {\n\t// each parasite will pick a random host and try to infect it\n\tparasites = p1.individuals;\n\tchosen_hosts = sample(p0.individuals, size(parasites), replace=T);\n\t\n\tfor (p in parasites, h in chosen_hosts)\n\t{\n\t\t// infection depends upon a match (diploid matching-allele model)\n\t\tall_nucleotides = c(p,h).haplosomes.nucleotides();\n\t\t\n\t\tif (size(unique(all_nucleotides, preserveOrder=F)) == 1)\n\t\t{\n\t\t\t// parasite and host are both homozygous for the same nucleotide(s)\n\t\t\t// with a match, the parasite's fitness increases, the host's decreases\n\t\t\tp.fitnessScaling = 1.5 * p.fitnessScaling;\n\t\t\th.fitnessScaling = 0.5 * h.fitnessScaling;\n\t\t}\n\t}\n}\n\nticks all 2000 late() {\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 20.8 - Within-host reproduction in a host-pathogen model.txt",
    "content": "// Keywords: multispecies, interaction, life history, timescale, parasite, infection, SIR, S-I-R\n\nspecies all initialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\tdefineConstant(\"K_MONKEY\", 100);             // monkey carrying capacity\n\tdefineConstant(\"F_MONKEY\", 3.0);             // monkey fecundity\n\tdefineConstant(\"G_MONKEY\", 20);              // relative generation timescale\n\tdefineConstant(\"P_TRANSMISSION\", 0.0001);    // probability of transmission\n\tdefineConstant(\"SUPPRESSION_μ\", 30000);      // optimal size for suppression\n\tdefineConstant(\"SUPPRESSION_σ\", 10000);      // width for suppression\n\tdefineConstant(\"SUPPRESSION_STRENGTH\", 0.4); // strength of suppression\n\tdefineConstant(\"DEATH\", 100000);             // level for certain death\n}\nspecies monkey initialize() {\n\tinitializeSpecies(tickModulo=G_MONKEY, avatar=\"🐵\", color=\"tan3\");\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeSex();\n\t// pedigree IDs are used to identify host-pathogen matches\n\t// colors: blue == uninfected, yellow -> red == infected, black == dead\n}\nspecies pathogen initialize() {\n\tinitializeSpecies(avatar=\"🦠\", color=\"chartreuse3\");\n\t// pathogen.tag is a counter of the next subpop ID to use\n\t// subpopulation.tag is the pedigree ID of the host for the subpop\n}\n\nticks all 2: first() {\n\tif (p1.individualCount == 0)\n\t\tstop(monkey.avatar + \" extinct\");\n\tif (pathogen.subpopulations.size() == 0)\n\t\tstop(pathogen.avatar + \" extinct\");\n}\n\nspecies monkey reproduction(p1, \"F\") {\n\t// monkeys reproduce sexually, non-monogamously\n\tlitterSize = rpois(1, F_MONKEY);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies pathogen reproduction() {\n\t// the pathogen reproduces clonally\n\tsubpop.addCloned(individual);\n}\n\nticks all 1 early() {\n\tmonkey.addSubpop(\"p1\", K_MONKEY);\n\t\n\t// choose initial hosts carrying the infection\n\tinitial_hosts = p1.sampleIndividuals(5, replace=F);\n\tpathogen.tag = 3;\n\t\n\tfor (initial_host in initial_hosts)\n\t{\n\t\t// make a pathogen subpop for the host\n\t\tpathogen_subpop = pathogen.addSubpop(pathogen.tag, 1);\n\t\tpathogen_subpop.tag = initial_host.pedigreeID;\n\t\tpathogen.tag = pathogen.tag + 1;\n\t}\n\t\n\t// log some basic output\n\tlogfile = community.createLogFile(\"host_pathogen_log.csv\", logInterval=1);\n\tlogfile.addTick();\n\tlogfile.addSubpopulationSize(p1);\n\tlogfile.addPopulationSize(pathogen);\n\tlogfile.addCustomColumn(\"host_count\", \"pathogen.subpopulations.size();\");\n\tlogfile.addMeanSDColumns(\"monkeyAge\", \"p1.individuals.age;\");\n}\n\nticks monkey early() {\n\t// monkey population regulation\n\tp1.fitnessScaling = K_MONKEY / p1.individualCount;\n}\nticks all early() {\n\t// horizontal transmission\n\tif (p1.individualCount > 1)\n\t{\n\t\tpathogenSubpops = pathogen.subpopulations;\n\t\tallPathogens = pathogenSubpops.individuals;\n\t\tisTransmitted = (rbinom(allPathogens.size(), 1, P_TRANSMISSION) == 1);\n\t\tmoving = allPathogens[isTransmitted];\n\t\t\n\t\tfor (ind in moving)\n\t\t{\n\t\t\t// figure out which host we are in\n\t\t\thostID = ind.subpopulation.tag;\n\t\t\tcurrentHost = monkey.individualsWithPedigreeIDs(hostID);\n\t\t\t\n\t\t\t// choose a different host and get its ID\n\t\t\tnewHost = p1.sampleIndividuals(1, exclude=currentHost);\n\t\t\tnewHostID = newHost.pedigreeID;\n\t\t\t\n\t\t\t// find/create a subpop for the new host and move to it\n\t\t\tnewSubpop = pathogenSubpops[pathogenSubpops.tag == newHostID];\n\t\t\t\n\t\t\tif (newSubpop.size() == 0)\n\t\t\t{\n\t\t\t\tnewSubpop = pathogen.addSubpop(pathogen.tag, 0);\n\t\t\t\tpathogen.tag = pathogen.tag + 1;\n\t\t\t\tnewSubpop.tag = newHostID;\n\t\t\t\t\n\t\t\t\t// need to incorporate the new subpop in case it receives another\n\t\t\t\tpathogenSubpops = c(pathogenSubpops, newSubpop);\n\t\t\t}\n\t\t\tnewSubpop.takeMigrants(ind);\n\t\t}\n\t}\n}\nticks all early() {\n\t// disease outcomes: either suppression or mortality\n\tsuppress_scale = SUPPRESSION_STRENGTH / dnorm(0.0, 0.0, SUPPRESSION_σ);\n\t\n\tfor (pathogenSubpop in pathogen.subpopulations)\n\t{\n\t\tpopsize = asFloat(pathogenSubpop.individualCount);\n\t\tP_supp = (dnorm(popsize, SUPPRESSION_μ, SUPPRESSION_σ) * suppress_scale);\n\t\tP_death = popsize / DEATH;\n\t\t\n\t\tif (runif(1) < P_supp)\n\t\t{\n\t\t\t// the infection is suppressed; host lives, pathogen dies\n\t\t\tpathogenSubpop.removeSubpopulation();\n\t\t}\n\t\telse if (runif(1) < P_death)\n\t\t{\n\t\t\t// the host has died; kill it and its pathogens\n\t\t\thost = monkey.individualsWithPedigreeIDs(pathogenSubpop.tag);\n\t\t\tmonkey.killIndividuals(host);\n\t\t\tpathogenSubpop.removeSubpopulation();\n\t\t}\n\t}\n}\nticks all early() {\n\t// color monkeys by their infection level\n\tpathogenSubpops = pathogen.subpopulations;\n\t\n\tfor (host in p1.individuals)\n\t{\n\t\thostID = host.pedigreeID;\n\t\tpathogenSubpop = pathogenSubpops[pathogenSubpops.tag == hostID];\n\t\t\n\t\tif (pathogenSubpop.size() == 1)\n\t\t{\n\t\t\tpathogenCount = pathogenSubpop.individualCount;\n\t\t\thue = max(0.0, 1.0 - pathogenCount / DEATH) * 0.15;\n\t\t\thost.color = rgb2color(hsv2rgb(c(hue, 1, 1)));\n\t\t}\n\t\telse\n\t\t\thost.color = \"cornflowerblue\";\n\t}\n}\n\nspecies monkey survival(p1) {\n\t// when a monkey dies, any pathogens in it die\n\tif (!surviving)\n\t{\n\t\thostID = individual.pedigreeID;\n\t\tpathogenSubpops = pathogen.subpopulations;\n\t\tpathogenSubpop = pathogenSubpops[pathogenSubpops.tag == hostID];\n\t\tpathogenSubpop.removeSubpopulation();\n\t}\n\treturn NULL;\n}\n\nticks all 2000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.1 - A basic neutral simulation.txt",
    "content": "// Keywords: \n\n// set up a simple neutral simulation\ninitialize()\n{\n\t// set the overall mutation rate\n\tinitializeMutationRate(1e-7);\n\t\n\t// m1 mutation type: neutral\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\n\t// g1 genomic element type: uses m1 for all mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// uniform chromosome of length 100 kb\n\tinitializeGenomicElement(g1, 0, 99999);\n\t\n\t// uniform recombination along the chromosome\n\tinitializeRecombinationRate(1e-8);\n}\n\n// create a population of 500 individuals\n1 early()\n{\n\tsim.addSubpop(\"p1\", 500);\n}\n\n// run to tick 10000\n10000 early()\n{\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.1.10 - Using symbolic constants for model parameters.txt",
    "content": "// Keywords: parameter, constant, symbol, global, define\n\ninitialize()\n{\n\t// define some global constants for parameters\n\tdefineConstant(\"MU\", 1e-7);\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"R\", 1e-8);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L - 1);\n\tinitializeRecombinationRate(R);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", N);\n}\n20*N early() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.1 - Basic output, Entire population.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.2 - Basic output, Random population sample.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 late() { p1.outputSample(10); }\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.3 - Basic output, Sampling individuals for output.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.01);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n}\n10000 late() {\n\tallIndividuals = sim.subpopulations.individuals;\n\tw = asFloat(allIndividuals.countOfMutationsOfType(m2) + 1);\n\tsampledIndividuals = sample(allIndividuals, 10, weights=w);\n\tsampledIndividuals.haplosomes.outputHaplosomes();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.4 - Basic output, Substitutions.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 late() { p1.outputSample(10); }\n10000 late() { sim.outputFull(); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.5 - Basic output, Automatic logging with LogFile.txt",
    "content": "// Keywords: migration, dispersal, table output, CSV, TSV, FST\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tsim.addSubpop(\"p2\", 1000);\n\tp1.setMigrationRates(p2, 0.001);\n\tp2.setMigrationRates(p1, 0.001);\n\tlog = community.createLogFile(\"sim_log.txt\", logInterval=10);\n\tlog.addCycle();\n\tlog.addCustomColumn(\"FST\", \"calcFST(p1.haplosomes, p2.haplosomes);\");\n}\n20000 late() { }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 4.2.6 - Basic output, Custom output with Eidos.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n}\n\n// custom MS-style output from a multi-subpop sample\n2000 late() {\n\t// obtain a random sample of haplosomes from the whole population\n\th = sample(sim.subpopulations.haplosomes, 10, T);\n\t\n\t// get the unique mutations in the sample, sorted by position\n\tm = sortBy(unique(h.mutations, preserveOrder=F), \"position\");\n\t\n\t// print the number of segregating sites\n\tcat(\"\\n\\nsegsites: \" + size(m) + \"\\n\");\n\t\n\t// print the positions\n\tpositions = format(\"%.6f\", m.position / sim.chromosomes.lastPosition);\n\tcat(\"positions: \" + paste(positions, sep=\" \") + \"\\n\");\n\t\n\t// print the sampled haplosomes\n\tfor (haplosome in h)\n\t{\n\t\thasMuts = (match(m, haplosome.mutations) >= 0);\n\t\tcat(paste(asInteger(hasMuts), sep=\"\") + \"\\n\");\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.1 - Subpopulation size, Instantaneous changes.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n1000 early() { p1.setSubpopulationSize(100); }\n2000 early() { p1.setSubpopulationSize(1000); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:1099 early() {\n\tnewSize = asInteger(p1.individualCount * 1.03);\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:1099 early() {\n\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth III.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:2000 early() {\n\tif (p1.individualCount < 2000)\n\t{\n\t\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\t\tp1.setSubpopulationSize(newSize);\n\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth IV.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000: early() {\n\tnewSize = round(1.03^(sim.cycle - 999) * 100);\n\tif (newSize > 2000)\n\t\tnewSize = 2000;\n\tp1.setSubpopulationSize(asInteger(newSize));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth V.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000: early() {\n\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\tif (newSize >= 2000)\n\t{\n\t\tnewSize = 2000;\n\t\tcommunity.deregisterScriptBlock(self);\n\t}\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.4 - Subpopulation size, Cyclical changes.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1500); }\nearly() {\n\tnewSize = cos((sim.cycle - 1) / 100) * 500 + 1000;\n\tp1.setSubpopulationSize(asInteger(newSize));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.1.5 - Subpopulation size, Context-dependent changes (Muller's Ratchet).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"e\", -0.01);\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\nearly() {\n\tmeanFitness = mean(p1.cachedFitness(NULL));\n\tnewSize = asInteger(100 * meanFitness);\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.2.1 - Population structure, Adding subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 100);\n\tsim.addSubpop(\"p3\", 1000);\n\tp1.setMigrationRates(c(p2,p3), c(0.2,0.1));\n\tp2.setMigrationRates(c(p1,p3), c(0.8,0.01));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.2.2 - Population structure, Removing subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n100 early() { sim.addSubpop(\"p2\", 100); }\n100:150 early() {\n\tmigrationProgress = (sim.cycle - 100) / 50;\n\tp1.setMigrationRates(p2, 0.2 * migrationProgress);\n\tp2.setMigrationRates(p1, 0.8 * migrationProgress);\n}\n1000 early() { sim.addSubpop(\"p3\", 10); }\n1000:1100 early() {\n\tp3Progress = (sim.cycle - 1000) / 100;\n\tp3.setSubpopulationSize(asInteger(990 * p3Progress + 10));\n\tp1.setMigrationRates(p3, 0.1 * p3Progress);\n\tp2.setMigrationRates(p3, 0.01 * p3Progress);\n}\n2000 early() { p2.setSubpopulationSize(0); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.2.3 - Population structure, Splitting subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n100 early() { sim.addSubpopSplit(\"p2\", 100, p1); }\n100:150 early() {\n\tmigrationProgress = (sim.cycle - 100) / 50;\n\tp1.setMigrationRates(p2, 0.2 * migrationProgress);\n\tp2.setMigrationRates(p1, 0.8 * migrationProgress);\n}\n1000 early() { sim.addSubpopSplit(\"p3\", 10, p2); }\n1000:1100 early() {\n\tp3Progress = (sim.cycle - 1000) / 100;\n\tp3.setSubpopulationSize(asInteger(990 * p3Progress + 10));\n\tp1.setMigrationRates(p3, 0.1 * p3Progress);\n\tp2.setMigrationRates(p3, 0.01 * p3Progress);\n}\n2000 early() { p2.setSubpopulationSize(0); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.2.4 - Population structure, Joining subpopulations.txt",
    "content": "// Keywords: migration, admixture, merging, combining\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 1000);\n}\n1000 early() {\n\t// set up p3 to generate itself entirely from migrants\n\tsim.addSubpop(\"p3\", 300);\n\tp3.setMigrationRates(c(p1, p2), c(0.75, 0.25));\n}\n1000 late() {\n\t// remove the source subpopulations\n\tp3.setMigrationRates(c(p1, p2), c(0.0, 0.0));\n\tp1.setSubpopulationSize(0);\n\tp2.setSubpopulationSize(0);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.3.1 - Migration and admixture, A linear stepping-stone model.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tdefineConstant(\"COUNT\", 10);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 0:(COUNT-1))\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (i in 1:(COUNT-1)) subpops[i].setMigrationRates(i-1, 0.2);\n\tfor (i in 0:(COUNT-2)) subpops[i].setMigrationRates(i+1, 0.05);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.3.2 - Migration and admixture, A non-spatial metapopulation.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsubpopCount = 5;\n\tfor (i in 1:subpopCount)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 1:subpopCount)\n\t\tfor (j in 1:subpopCount)\n\t\t\tif (i != j)\n\t\t\t\tsim.subpopulations[i-1].setMigrationRates(j, 0.05);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.3.3 - Migration and admixture, A two-dimensional subpopulation matrix.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tmetapopSide = 3;\t// number of subpops along one side of the grid\n\tmetapopSize = metapopSide * metapopSide;\n\tfor (i in 1:metapopSize)\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (x in 1:metapopSide)\n\t\tfor (y in 1:metapopSide)\n\t\t{\n\t\t\tdestID = (x - 1) + (y - 1) * metapopSide + 1;\n\t\t\tdestSubpop = subpops[destID - 1];\n\t\t\tif (x > 1)   // left to right\n\t\t\t\tdestSubpop.setMigrationRates(destID - 1, 0.05);\n\t\t\tif (x < metapopSide)   // right to left\n\t\t\t\tdestSubpop.setMigrationRates(destID + 1, 0.05);\n\t\t\tif (y > 1)   // top to bottom\n\t\t\t\tdestSubpop.setMigrationRates(destID - metapopSide, 0.05);\n\t\t\tif (y < metapopSide)   // bottom to top\n\t\t\t\tdestSubpop.setMigrationRates(destID + metapopSide, 0.05);\n\t\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.3.4 - Migration and admixture, A random, sparse spatial metapopulation.txt",
    "content": "// Keywords: migration, dispersal, SLiMgui\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.3);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tmSide = 10;\t// number of subpops along one side of the grid\n\tfor (i in 1:(mSide * mSide))\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (x in 1:mSide)\n\t\tfor (y in 1:mSide)\n\t\t{\n\t\t\tdestID = (x - 1) + (y - 1) * mSide + 1;\n\t\t\tds = subpops[destID - 1];\n\t\t\tif (x > 1)   // left to right\n\t\t\t\tds.setMigrationRates(destID - 1, runif(1, 0.0, 0.05));\n\t\t\tif (x < mSide)   // right to left\n\t\t\t\tds.setMigrationRates(destID + 1, runif(1, 0.0, 0.05));\n\t\t\tif (y > 1)   // top to bottom\n\t\t\t\tds.setMigrationRates(destID - mSide, runif(1, 0.0, 0.05));\n\t\t\tif (y < mSide)   // bottom to top\n\t\t\t\tds.setMigrationRates(destID + mSide, runif(1, 0.0, 0.05));\n\t\t\t\n\t\t\t// set up SLiMgui's population visualization nicely\n\t\t\txd = ((x - 1) / (mSide - 1)) * 0.9 + 0.05;\n\t\t\tyd = ((y - 1) / (mSide - 1)) * 0.9 + 0.05;\n\t\t\tds.configureDisplay(c(xd, yd), 0.4);\n\t\t}\n\t\n\t// remove 25% of the subpopulations\n\tsubpops[sample(0:99, 25)].setSubpopulationSize(0);\n\t\n\t// introduce a beneficial mutation\n\ttarget_subpop = sample(sim.subpopulations, 1);\n\tsample(target_subpop.haplosomes, 10).addNewDrawnMutation(m2, 20000);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.3.5 - Migration and admixture, Reading a migration matrix from a file.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 1:3)\n\t\tsim.addSubpop(i, 1000);\n\tsubpops = sim.subpopulations;\n\t\n\t// this file is in the recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tlines = readFile(\"migration.csv\");\n\tlines = lines[substr(lines, 0, 1) != \"//\"];\n\t\n\tfor (line in lines)\n\t{\n\t\tfields = strsplit(line, \",\");\n\t\ti = asInteger(fields[0]);\n\t\tj = asInteger(fields[1]);\n\t\tm = asFloat(fields[2]);\n\t\t\n\t\tif (i != j)\n\t\t{\n\t\t\tp_i = subpops[subpops.id == i];\n\t\t\tp_j = subpops[subpops.id == j];\n\t\t\tp_j.setMigrationRates(p_i, m);\n\t\t}\n\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution I.txt",
    "content": "// Keywords: migration, dispersal\n\n// Model based on Gravel et al. 2011, doi:10.1073/pnas.1019276108 (hereafter \"paper\")\ninitialize() {\n\tinitializeMutationRate(2.36e-8); // theta=3813.75\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999); // paper uses 4.04e6, 5007837, etc.\n\tinitializeRecombinationRate(1e-8);\n}\n\n// INITIALIZE the ancestral African population of size 7310\n1 early() { sim.addSubpop(\"p1\", asInteger(round(7310.370867595234))); } // paper rounds to 7310\n\n// END BURN-IN period of 10*N=73104 generations (specific to SLiM recipe); EXPAND the African population\n// This occurs (5919.131117 generations)*(25 years)=147978 yr ago; paper rounds to 5920 gens (148000 yr)\n// Thus, simulation should end at generation 1+73104+5919.131117=79024\n73105 early() { p1.setSubpopulationSize(asInteger(round(14474.54608753566))); } // paper rounds to 14474\n\n// SPLIT Eurasians (p2) from Africans (p1) and SET UP MIGRATION between them\n// This occurs 2056.396652 generations (51409.9163 years) ago; paper rounds to 2040 gens (51000 yr)\n// Relative to beginning, this is generation 79024-2056.396652=76968\n76968 early() {\n\tsim.addSubpopSplit(\"p2\", asInteger(round(1861.288190027689)), p1); // paper rounds to 1861\n\tp1.setMigrationRates(c(p2), c(15.24422112e-5)); // paper rounds to 15e-5\n\tp2.setMigrationRates(c(p1), c(15.24422112e-5)); // paper rounds to 15e-5\n}\n\n// SPLIT p2 into European (p2) and East Asian (p3) subpopulations; RESIZE; SET UP MIGRATION between them\n// This occurs 939.8072428 generations (23495.18107 years) ago; paper rounds to 920 gens (23000 yr)\n// Relative to beginning, this is generation 79024-939.8072428=78084\n78084 early() {\n\tsim.addSubpopSplit(\"p3\", asInteger(round(553.8181989)), p2); // paper rounds to 554\n\tp2.setSubpopulationSize(asInteger(round(1032.1046957333444)));  // reduce European size; paper rounds to 1032\n\n\t// Set migration rates for the rest of the simulation\n\tp1.setMigrationRates(c(p2, p3), c(2.54332678e-5, 0.7770583877e-5)); // paper rounds to c(2.5e-5, 0.78e-5)\n\tp2.setMigrationRates(c(p1, p3), c(2.54332678e-5, 3.115817913e-5)); // paper rounds to c(2.5e-5, 3.11e-5)\n\tp3.setMigrationRates(c(p1, p2), c(0.7770583877e-5, 3.115817913e-5)); // paper rounds to c(0.78e-5, 3.11e-5)\n}\n\n// SET UP EXPONENTIAL GROWTH in Europe (p2) and East Asia (p3)\n// Where N(0) is the base subpopulation size and t = gen - 78084:\n//    N(Europe) should be int(round(N(0) * (1 + 0.003784324268)^t)), i.e., growth is r=0.38% per generation\n//    N(East Asia) should be int(round(N(0) * (1 + 0.004780219543)^t)), i.e., growth is r=0.48% per generation\n78084:79024 early() {\n\tt = sim.cycle - 78084;\n\tp2_size = round(1032.1046957333444 * (1 + 0.003784324268)^t); // paper rounds to N(0)=1032 and r=0.0038\n\tp3_size = round(553.8181989 * (1 + 0.004780219543)^t); // paper rounds to N(0)=554 and r=0.0048\n\t\n\tp2.setSubpopulationSize(asInteger(p2_size));\n\tp3.setSubpopulationSize(asInteger(p3_size));\n}\n\n// OUTPUT AND TERMINATE\n// Generation 79024 is the present, i.e., 1 initialize + 73104 burn-in + 5919 evolution\n79024 late() {\n\tp1.outputSample(216); // YRI phase 3 diploid sample of size 108\n\tp2.outputSample(198); // CEU phase 3 diploid sample of size 99\n\tp3.outputSample(206); // CHB phase 3 diploid sample of size 103\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution II.txt",
    "content": "/// # Gravel Model in SLiM\n/// #### _(with Jump Menu annotations)_\n///\n\ninitialize() {\n\tinitializeMutationRate(2.36e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-8);\n}\n\n///\n/// **Demography:**\n\n1 early() /* create p1 */ {\n\tsim.addSubpop(\"p1\", asInteger(round(7310.370867595234)));\n}\n\n73105 early() /* end burn-in */ {\n\tp1.setSubpopulationSize(asInteger(round(14474.54608753566)));\n}\n\n76968 early() /* split p2 from p1 */ {\n\tsim.addSubpopSplit(\"p2\", asInteger(round(1861.288190027689)), p1);\n\tp1.setMigrationRates(c(p2), c(15.24422112e-5));\n\tp2.setMigrationRates(c(p1), c(15.24422112e-5));\n}\n\n78084 early() /* split p3 from p2 */ {\n\tsim.addSubpopSplit(\"p3\", asInteger(round(553.8181989)), p2);\n\tp2.setSubpopulationSize(asInteger(round(1032.1046957333444)));\n\n\tp1.setMigrationRates(c(p2, p3), c(2.54332678e-5, 0.7770583877e-5));\n\tp2.setMigrationRates(c(p1, p3), c(2.54332678e-5, 3.115817913e-5));\n\tp3.setMigrationRates(c(p1, p2), c(0.7770583877e-5, 3.115817913e-5));\n}\n\n78084:79024 early() /* exponential growth */ {\n\tt = sim.cycle - 78084;\n\tp2_size = round(1032.1046957333444 * (1 + 0.003784324268)^t);\n\tp3_size = round(553.8181989 * (1 + 0.004780219543)^t);\n\t\n\tp2.setSubpopulationSize(asInteger(p2_size));\n\tp3.setSubpopulationSize(asInteger(p3_size));\n}\n\n/***/\n/** **Final output:** */\n\n79024 late() {\n\tp1.outputSample(216);\n\tp2.outputSample(198);\n\tp3.outputSample(206);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance I.txt",
    "content": "// Keywords: rescale\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.01);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.8,0.2));\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n50000 early() { p1.setSubpopulationSize(1000); }\n55000 early() { p1.setSubpopulationSize(5000); }\n60000 late() { p1.outputSample(10); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance II.txt",
    "content": "// Keywords: rescale\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.1);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.8,0.2));\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 early() { p1.setSubpopulationSize(100); }\n5500 early() { p1.setSubpopulationSize(500); }\n6000 late() { p1.outputSample(10); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 6.1 - Genomic structure, Part I (Mutation types and fitness effects).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 6.2 - Genomic structure, Part II (Genomic element types).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);          // non-coding\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 6.3 - Genomic structure, Part III (Chromosome organization).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);           // non-coding\n\t\n\t// Generate random genes along an approximately 100000-base chromosome\n\tbase = 0;\n\t\n\twhile (base < 100000) {\n\t\t// make a non-coding region\n\t\tnc_length = rdunif(1, 100, 5000);\n\t\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\tbase = base + nc_length;\n\t\t\n\t\t// make first exon\n\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\tbase = base + ex_length;\n\t\t\n\t\t// make additional intron-exon pairs\n\t\tdo\n\t\t{\n\t\t\tin_length = asInteger(rlnorm(1, log(100), log(1.5))) + 10;\n\t\t\tinitializeGenomicElement(g2, base, base + in_length - 1);\n\t\t\tbase = base + in_length;\n\t\t\t\n\t\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\t\tbase = base + ex_length;\n\t\t}\n\t\twhile (runif(1) < 0.8);  // 20% probability of stopping\n\t}\n\t\n\t// final non-coding region\n\tnc_length = rdunif(1, 100, 5000);\n\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\n\t// single recombination rate\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 6.4 - Genomic structure, Part IV (Custom display colors in SLiMgui).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tm1.color = \"gray40\";\n\tm2.color = \"gray40\";\n\tm3.color = \"red\";\n\tm4.color = \"green\";\n\tm1.colorSubstitution = \"gray20\";\n\tm2.colorSubstitution = \"gray20\";\n\tm3.colorSubstitution = \"#550000\";\n\tm4.colorSubstitution = \"#005500\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);           // non-coding\n\tg1.color = \"cornflowerblue\";\n\tg2.color = \"#00009F\";\n\tg3.color = \"black\";\n\t\n\t// Generate random genes along an approximately 100000-base chromosome\n\tbase = 0;\n\t\n\twhile (base < 100000) {\n\t\t// make a non-coding region\n\t\tnc_length = rdunif(1, 100, 5000);\n\t\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\tbase = base + nc_length;\n\t\t\n\t\t// make first exon\n\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\tbase = base + ex_length;\n\t\t\n\t\t// make additional intron-exon pairs\n\t\tdo\n\t\t{\n\t\t\tin_length = asInteger(rlnorm(1, log(100), log(1.5))) + 10;\n\t\t\tinitializeGenomicElement(g2, base, base + in_length - 1);\n\t\t\tbase = base + in_length;\n\t\t\t\n\t\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\t\tbase = base + ex_length;\n\t\t}\n\t\twhile (runif(1) < 0.8);  // 20% probability of stopping\n\t}\n\t\n\t// final non-coding region\n\tnc_length = rdunif(1, 100, 5000);\n\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\n\t// single recombination rate\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.chromosomes.colorSubstitution = \"\";\n\tsim.addSubpop(\"p1\", 5000);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.1 - Reproduction, Enabling separate sexes.txt",
    "content": "// Keywords: sexual\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.2 - Reproduction, Sex ratios I.txt",
    "content": "// Keywords: sexual, sex ratio\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500, 0.6); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.2 - Reproduction, Sex ratios II.txt",
    "content": "// Keywords: sexual, sex ratio\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1: early() { p1.setSexRatio(runif(1, 0.3, 0.7)); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.3 - Reproduction, Selfing in hermaphroditic populations.txt",
    "content": "// Keywords: selfing\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSelfingRate(0.8);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.4 - Reproduction, Cloning I.txt",
    "content": "// Keywords: clonal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(0.1);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.1.4 - Reproduction, Cloning II.txt",
    "content": "// Keywords: clonal, sexual\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(c(0.5,0.0));\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.2.1 - Recombination, Making a random recombination map.txt",
    "content": "// Keywords: recombination rate map, recombination map\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\t\n\t// 1000 random recombination regions\n\tends = c(sort(sample(0:99998, 999)), 99999);\n\trates = runif(1000, 1e-9, 1e-7);\n\tinitializeRecombinationRate(rates, ends);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.2.2 - Recombination, Reading a recombination map from a file.txt",
    "content": "// Keywords: recombination rate map, recombination map\n\ninitialize() {\n\tdefineConstant(\"L\", 23011544);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\t\n\t// read Drosophila 2L map from Comeron et al. 2012; this is in the\n\t// recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tinitializeRecombinationRateFromFile(\"Comeron_100kb_chr2L.txt\", L-1);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.2.3 - Recombination, Unlinked loci.txt",
    "content": "// Keywords: unlinked loci, free recombination, linkage disequilibrium\n\ninitialize() {\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.2.4 - Recombination, Gene conversion.txt",
    "content": "// Keywords: gene conversion\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\tinitializeGeneConversion(0.2, 500, 1.0);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.1 - Multiple diploid autosomes.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.03, 0.2);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", c(m1, m2), c(1,2));\n\t\n\tinitializeChromosome(1, 1e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeChromosome(2, 2e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeGenomicElement(g2, 1e5, 1e5+5e4-1);\n\tinitializeGenomicElement(g1, 1e5+5e4, 2e5-1);\n\tinitializeMutationRate(2e-7);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n2000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.2 - Clonal haploids and chromosome types.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, type=\"H\");\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(0.0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(1.0);\n}\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.3 - Haploids with recombination.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, 1e5, type=\"H\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.4 - Sex-chromosome evolution and null haplosomes.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tdefineConstant(\"X_LEN\", 156040895);\n\tdefineConstant(\"Y_LEN\", 57227415);\n\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, X_LEN, type=\"X\", symbol=\"X\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeChromosome(2, Y_LEN, type=\"Y\", symbol=\"Y\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.5 - Modeling the full human genome.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// length data: https://www.ncbi.nlm.nih.gov/grc/human/data,\n\t// Human Genome Assembly GRCh38.p14, 2022-02-03\n\tids = 1:24;\n\tsymbols = c(1:22, \"X\", \"Y\");\n\tlengths = c(248956422, 242193529, 198295559, 190214555, 181538259,\n\t\t\t\t\t170805979, 159345973, 145138636, 138394717, 133797422,\n\t\t\t\t\t135086622, 133275309, 114364328, 107043718, 101991189,\n\t\t\t\t\t90338345, 83257441, 80373285, 58617616, 64444167,\n\t\t\t\t\t46709983, 50818468, 156040895, 57227415);\n\ttypes = c(rep(\"A\", 22), \"X\", \"Y\");\n\t\n\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeRecombinationRate(1e-8);   // not used for the Y\n\t\tinitializeGenomicElement(g1);\n\t}\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.6 - A model of bryophytes with UV sex determination.txt",
    "content": "// Keywords: bryophytes, UV sex chromosomes, UV sex determination, haploid recombination, mosses\n\ninitialize() {\n\tinitializeSex();\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:3, type in c(\"H\", \"W\", \"Y\"), symbol in c(\"A\", \"U\", \"V\"))\n\t{\n\t\tinitializeChromosome(id, 1e7, type=type, symbol=symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 8.3.7 - Output from multiple-chromosome models.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:3, type in c(\"A\", \"X\", \"Y\"))\n\t{\n\t\tinitializeChromosome(id, 1e6, type=type, symbol=type);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeMutationRate(1e-8);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n100 late() {\n\tsim.outputFull();\n\t\n\tinds = p1.sampleIndividuals(5);\n\tinds.outputIndividuals();\n\tinds.outputIndividualsToVCF();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.1 - Introducing adaptive mutations.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.10 - Tracking the fate of background mutations.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 3e6);\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.8, \"f\", 0.5);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tdefineConstant(\"BACKGROUND\", target.mutations);\n\tmut = target.addNewDrawnMutation(m2, asInteger(L/2));\n\tdefineConstant(\"SWEEP\", mut);\n}\n1000: late() {\n\tif (!SWEEP.isSegregating & !SWEEP.isFixed)\n\t\tstop(\"LOST\");\n}\n1500 late() {\n\tnonSeg = BACKGROUND[!BACKGROUND.isSegregating];\n\tfixed = nonSeg[nonSeg.isFixed];\n\tlost = nonSeg[!nonSeg.isFixed];\n\twriteFile(\"fixed.txt\", paste(fixed.position, sep=\", \"));\n\twriteFile(\"lost.txt\", paste(lost.position, sep=\", \"));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.11 - Effective population size versus census population size.txt",
    "content": "// Keywords: Ne, parameter estimation\n\ninitialize() {\n\tdefineGlobal(\"N\", 1000);\n\tdefineGlobal(\"L\", 1e7);\n\tdefineGlobal(\"MU\", 1e-7);\n\tdefineGlobal(\"R\", 1e-8);\n\tdefineGlobal(\"S\", 2.0);\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\t\t// neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", S);\t\t// sweep\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(R);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setValue(\"previous_N\", p1.individualCount);\n\t\n\tdefineConstant(\"LOG\", community.createLogFile(\"Ne_log.csv\"));\n\tLOG.addCycle();\n\tLOG.addCustomColumn(\"N(t-1)\", \"p1.getValue('previous_N');\");\n\tLOG.addCustomColumn(\"N(t)\", \"p1.individualCount;\");\n\tLOG.addCustomColumn(\"freq\", \"mutTypeFrequency(m2);\");\n\tLOG.addCustomColumn(\"Ne_heterozygosity\", \"estimateNe_Heterozygosity(p1);\");\n\tLOG.addCustomColumn(\"Ne_inbreeding\", \"estimateNe_Inbreeding(p1);\");\n}\n2: late() {\n\tLOG.logRow();\n\tp1.setValue(\"previous_N\", p1.individualCount);\n}\n10000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, integerDiv(L, 2));\n}\n20000 late() {\n\tsim.simulationFinished();\n}\n\nfunction (float)mutTypeFrequency(o<MutationType>$ mutType)\n{\n\tmuts = sim.mutationsOfType(mutType);\n\tif (muts.size() > 0)\n\t\treturn sim.mutationFrequencies(NULL, muts);\n\treturn NULL;\n}\n\nfunction (float)estimateNe_Heterozygosity(o<Subpopulation>$ subpop,\n\t[No<Chromosome>$ chromosome = NULL])\n{\n\tif (isNULL(chromosome))\n\t{\n\t\tif (size(sim.chromosomes) == 1)\n\t\t\tchromosome = sim.chromosomes;\n\t\telse\n\t\t\tstop(\"ERROR: in a multi-chrom model, a chromosome must be supplied.\");\n\t}\n\t\n\thaplosomes = subpop.haplosomesForChromosomes(chromosome, includeNulls=F);\n\tpi = calcHeterozygosity(haplosomes);\n\treturn pi / (4 * MU);\n}\n\nfunction (integer)tabulateFecundity(o<Subpopulation>$ subpop, i$ previous_N)\n{\n\tparentIDs = subpop.individuals.pedigreeParentIDs;\n\trescaledParentIDs = parentIDs - min(parentIDs);\n\treturn tabulate(rescaledParentIDs, previous_N - 1);\n}\n\nfunction (float)estimateNe_Inbreeding(o<Subpopulation>$ subpop)\n{\n\tprevious_N = subpop.getValue(\"previous_N\");\n\tk = tabulateFecundity(subpop, previous_N);\n\treturn (previous_N * mean(k) - 2) / (mean(k) - 1 + var(k) / mean(k));\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.12 - Observing the site frequency spectrum (SFS) during selective sweeps.txt",
    "content": "// Keywords: site frequency spectrum, SFS, population genetics, statistics, custom plotting\n\ninitialize() {\n\tsetSeed(4806519412125461529);\n\tdefineConstant(\"N\", 1000);\n\tdefineConstant(\"L\", 1e7);\n\tdefineConstant(\"MU\", 1e-7);\n\tdefineConstant(\"BINCOUNT\", 100);\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\ninitialize() {\n\t// Calculate the expected SFS with the same bins as our observed SFS.\n\t// This is tricky because we need to calculate it for the number of samples\n\t// we have (i.e., number of haplosomes), and then re-bin it; maybe there is\n\t// an easier way.  Note that 10000000 is just a constant large enough to\n\t// avoid rounding artifacts in the final curve; it is basically the number\n\t// of \"mutations\" scattered across the original expected SFS in order to\n\t// re-bin it to the final bin count.  Not sure this math is exactly correct.\n\t// It would be great to have a calcExpectedSFS() function built in; if you\n\t// know how to do that exactly correctly, for counts as well as density,\n\t// then please volunteer!\n\texpected = 1 / (1:(2*N-1));\n\texpected = expected / sum(expected);\n\texpected = asInteger(round(expected * 10000000));\n\tbins = asInteger(round(repEach(1:(2*N-1), expected) * (BINCOUNT / (2*N-1))));\n\ttallies = tabulate(bins, maxbin=BINCOUNT-1);\n\tdefineConstant(\"EXPECTED_SFS\", tallies / sum(tallies));\n}\n1 early() {\n\t// make a subpop and start drifting towards equilibrium\n\tsim.addSubpop(\"p1\", N);\n}\n20*N early() {\n\t// start generating rare m2 sweep mutations\n\tg1.setMutationFractions(c(m1, m2), c(1, 0.000001));\n}\n25*N early() {\n\t// stop generating m2 mutations and allow re-equilibration\n\tg1.setMutationFractions(m1, 1);\n}\n1:(35*N) late() {\n\tupdatePlot();\n}\n\nfunction (void)updatePlot(void)\n{\n\tif (exists(\"slimgui\"))\n\t{\n\t\t// get the empirical population SFS\n\t\tsfs_all = calcSFS(BINCOUNT);\n\t\tsfs_m2 = calcSFS(BINCOUNT, muts=sim.mutationsOfType(m2));\n\t\tx = seq(from=0.0, to=1.0, length=BINCOUNT+1) + 0.5/BINCOUNT;\n\t\tx = x[0:(length(x)-2)];\n\t\t\n\t\t// make a plot of the observed vs. expected SFS\n\t\tplot = slimgui.createPlot(\"Site Frequency Spectrum\",\n\t\t\txrange=c(0,1), yrange=c(0,1),\n\t\t\txlab=\"Mutation frequency\", ylab=\"Density (sqrt-transformed)\");\n\t\t\n\t\tplot.lines(x=x, y=sqrt(sfs_all), color=\"black\", lwd=3);\n\t\tplot.lines(x=x, y=sqrt(EXPECTED_SFS), color=\"chartreuse2\", lwd=2);\n\t\tplot.lines(x=x, y=sqrt(sfs_m2), color=\"red\", lwd=1);\n\t\t\n\t\tplot.addLegend(\"topRight\");\n\t\tplot.legendLineEntry(\"observed\", color=\"black\", lwd=3);\n\t\tplot.legendLineEntry(\"expected\", color=\"chartreuse2\", lwd=2);\n\t\tplot.legendLineEntry(\"m2 (sweeps)\", color=\"red\", lwd=2);\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.2 - Making sweeps conditional on fixation.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\t\n\t\tif (fixed)\n\t\t{\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.simulationFinished();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\t\n\t\t\t// go back to tick 1000\n\t\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\t\n\t\t\t// start a newly seeded run\n\t\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\t\n\t\t\t// re-introduce the sweep mutation\n\t\t\ttarget = sample(p1.haplosomes, 1);\n\t\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.3 - Making sweeps conditional on establishment.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000: late() {\n\tmut = sim.mutationsOfType(m2);\n\t\n\tif (size(mut) == 1)\n\t{\n\t\tif (sim.mutationFrequencies(NULL, mut) > 0.1)\n\t\t{\n\t\t\tcat(simID + \": ESTABLISHED\\n\");\n\t\t\tcommunity.deregisterScriptBlock(self);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\n\t\t// go back to tick 1000\n\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\n\t\t// start a newly seeded run\n\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\n\t\t// re-introduce the sweep mutation\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n10000 early() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.4 - Partial sweeps.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:10000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 0)\n\t\tsim.simulationFinished();\n\telse if (mut.selectionCoeff != 0.0)\n\t\tif (sim.mutationFrequencies(NULL, mut) >= 0.5)\n\t\t\tmut.setSelectionCoeff(0.0);\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.5.1 - A soft sweep from recurrent de novo mutations in a large population.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.45, \"f\", 0.5);  // sweep mutation\n\tm1.convertToSubstitution = F;\n\tm1.mutationStackPolicy = \"f\";\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 0);\n\tinitializeRecombinationRate(0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100000);\n}\n1:10000 early() {\n\tcounts = p1.haplosomes.countOfMutationsOfType(m1);\n\tfreq = mean(counts > 0);\n\t\n\tif (freq == 1.0)\n\t{\n\t\tcat(\"\\nTotal mutations: \" + size(sim.mutations) + \"\\n\\n\");\n\t\t\n\t\tfor (mut in sortBy(sim.mutations, \"originTick\"))\n\t\t{\n\t\t\tmutFreq = mean(p1.haplosomes.containsMutations(mut));\n\t\t\tcat(\"Origin \" + mut.originTick + \": \" + mutFreq + \"\\n\");\n\t\t}\n\t\t\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.5.2 - A soft sweep with a fixed de novo mutation schedule.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.45, \"f\", 0.5);   // sweep mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.tag = 0;  // indicate that a mutation has not yet been seen\n}\n1000:1100 late() {\n\tif (sim.cycle % 10 == 0)\n\t{\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\tif (target.countOfMutationsOfType(m2) == 0)\n\t\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n1:10000 late() {\n\tif (p1.tag != sim.countOfMutationsOfType(m2))\n\t{\n\t\tif (any(sim.substitutions.mutationType == m2)) {\n\t\t\tcat(\"Hard sweep ended in cycle \" + sim.cycle + \"\\n\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tp1.tag = sim.countOfMutationsOfType(m2);\n\t\t\tcat(\"Cycle \" + sim.cycle + \": \" + p1.tag + \" lineage(s)\\n\");\n\t\t\t\n\t\t\tif ((p1.tag == 0) & (sim.cycle > 1100)) {\n\t\t\t\tcat(\"Sweep failed to establish.\\n\");\n\t\t\t\tsim.simulationFinished();\n\t\t\t}\n\t\t}\n\t}\n\tif (all(p1.haplosomes.countOfMutationsOfType(m2) > 0)) {\n\t\tcat(\"Soft sweep ended in cycle \" + sim.cycle + \"\\n\");\n\t\tcat(\"Frequencies:\\n\");\n\t\tprint(sim.mutationFrequencies(p1, sim.mutationsOfType(m2)));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.5.3 - A soft sweep with a random de novo mutation schedule.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.1, \"f\", 0.5);    // sweep mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tgens = cumSum(rpois(10, 10));      // make a vector of start gens\n\tgens = gens + (1000 - min(gens));  // align to start at 1000\n\tdefineConstant(\"Z\", max(gens));    // remember the last gen\n\tdefineConstant(\"ADD_GENS\", gens);  // schedule the add events\n}\nADD_GENS late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size() > 0)\n\t\ttarget.addMutations(mut);\n\telse\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1:10000 late() {\n\tif (any(sim.substitutions.mutationType == m2))\n\t{\n\t\tcatn(\"Sweep completed in cycle \" + sim.cycle + \".\");\n\t\tsim.simulationFinished();\n\t}\n\telse if ((sim.countOfMutationsOfType(m2) == 0) & (sim.cycle > Z))\n\t{\n\t\tcatn(\"Soft sweep failed to establish.\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.6.1 - A sweep from standing variation at a random locus.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\tmuts = sim.mutations;\n\tmuts = muts[sim.mutationFrequencies(p1, muts) > 0.1];\n\t\n\tif (size(muts))\n\t{\n\t\tmut = sample(muts, 1);\n\t\tmut.setSelectionCoeff(0.5);\n\t}\n\telse\n\t{\n\t\tcat(\"No contender of sufficient frequency found.\\n\");\n\t}\n}\n1000:10000 late() {\n\tif (sum(sim.mutations.selectionCoeff) == 0.0)\n\t{\n\t\tif (sum(sim.substitutions.selectionCoeff) == 0.0)\n\t\t\tcat(\"Sweep mutation lost in cycle \" + sim.cycle + \"\\n\");\n\t\telse\n\t\t\tcat(\"Sweep mutation reached fixation.\\n\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.6.2 - A sweep from standing variation at a predetermined locus.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.0);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000: late() {\n\tmut = sim.mutationsOfType(m2);\n\t\n\tif (size(mut) == 1)\n\t{\n\t\tif (sim.mutationFrequencies(NULL, mut) > 0.1)\n\t\t{\n\t\t\tcat(simID + \": ESTABLISHED - CONVERTING TO BENEFICIAL\\n\");\n\t\t\tmut.setSelectionCoeff(0.5);\n\t\t\tcommunity.deregisterScriptBlock(self);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcat(simID + \": LOST BEFORE ESTABLISHMENT - RESTARTING\\n\");\n\t\t\n\t\t// go back to tick 1000\n\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\n\t\t// start a newly seeded run\n\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\n\t\t// re-introduce the sweep mutation\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n1000:10000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(simID + ifelse(fixed, \": FIXED\\n\", \": LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.7 - Adaptive introgression.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);    // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsubpopCount = 10;\n\tfor (i in 1:subpopCount)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 2:subpopCount)\n\t\tsim.subpopulations[i-1].setMigrationRates(i-1, 0.01);\n\tfor (i in 1:(subpopCount-1))\n\t\tsim.subpopulations[i-1].setMigrationRates(i+1, 0.2);\n}\n100 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n100:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.8 - Fixation probabilities under Hill-Robertson interference.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.05);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n6000 late() {\n\t// Calculate the fixation probability for a beneficial mutation\n\ts = 0.05;\n\tN = 1000;\n\tp_fix = (1 - exp(-2 * s)) / (1 - exp(-4 * N * s));\n\t\n\t// Calculate the expected number of fixed mutations\n\tn_gens = 1000;  // first 5000 ticks were burn-in\n\tmu = 1e-6;\n\tlocus_size = 100000;\n\texpected = mu * locus_size * n_gens * 2 * N * p_fix;\n\t\n\t// Figure out the actual number of fixations after burn-in\n\tsubs = sim.substitutions;\n\tactual = sum(subs.fixationTick >= 5000);\n\t\n\t// Print a summary of our findings\n\tcat(\"P(fix) = \" + p_fix + \"\\n\");\n\tcat(\"Expected fixations: \" + expected + \"\\n\");\n\tcat(\"Actual fixations: \" + actual + \"\\n\");\n\tcat(\"Ratio, actual/expected: \" + (actual/expected) + \"\\n\");\n}\n"
  },
  {
    "path": "QtSLiM/recipes/Recipe 9.9 - Keeping a reference to a sweep mutation.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tmut = target.addNewDrawnMutation(m2, 10000);\n\tdefineConstant(\"SWEEP\", mut);\n}\n1000:100000 late() {\n\tif (!SWEEP.isSegregating)\n\t{\n\t\tcat(ifelse(SWEEP.isFixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "QtSLiM/recipes/_README.txt",
    "content": "These recipes are all taken directly from SLiM's manual:\n\nHaller, B.C., and Messer, P.W. (2016). SLiM: An Evolutionary Simulation Framework.\n\nSLiM's manual contains full explanations of each recipe, in the corresponding section; please refer to it for further information.  These recipes are provided as separate files for convenience, particularly since copy-paste from the PDF manual often works poorly (but note that SLiMgui now allows you to open these recipes directly from the File menu, also, via the Open Recipe submenu).\n\n--------------------------------------------------------------\n\nThese recipes were all created by Ben Haller, except recipe 5.4, created by Aaron Sams and Chase W. Nelson.\n\nAll recipes are copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\nThey are products of the Messer Lab, http://messerlab.org/slim/\n\nAll of these recipes are a part of SLiM.\n\nSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n--------------------------------------------------------------\n\nThe file Comeron_100kb_chr2L.txt provided here is part of the supplemental data from the paper:\n\nComeron, J.M., Ratnappan, R., and Bailin, S. (2012). The many landscapes of recombination in Drosophila melanogaster. PLoS Genetics 8(10), e1002905.\n\nThis data file is used by recipe 6.1.2.\n\n--------------------------------------------------------------\n\nFor further information, please feel free to contact us:\n\nhttp://messerlab.org/slim/\n\nBen Haller, bhaller@benhaller.com\nPhilipp Messer, philipp.messer@gmail.com\n"
  },
  {
    "path": "QtSLiM/recipes.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>recipes/_README.txt</file>\n        <file>recipes/Recipe 4.1 - A basic neutral simulation.txt</file>\n        <file>recipes/Recipe 4.1.10 - Using symbolic constants for model parameters.txt</file>\n        <file>recipes/Recipe 4.2.1 - Basic output, Entire population.txt</file>\n        <file>recipes/Recipe 4.2.2 - Basic output, Random population sample.txt</file>\n        <file>recipes/Recipe 4.2.3 - Basic output, Sampling individuals for output.txt</file>\n        <file>recipes/Recipe 4.2.4 - Basic output, Substitutions.txt</file>\n        <file>recipes/Recipe 4.2.5 - Basic output, Automatic logging with LogFile.txt</file>\n        <file>recipes/Recipe 4.2.6 - Basic output, Custom output with Eidos.txt</file>\n        <file>recipes/Recipe 5.1.1 - Subpopulation size, Instantaneous changes.txt</file>\n        <file>recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth I.txt</file>\n        <file>recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth II.txt</file>\n        <file>recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth III.txt</file>\n        <file>recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth IV.txt</file>\n        <file>recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth V.txt</file>\n        <file>recipes/Recipe 5.1.4 - Subpopulation size, Cyclical changes.txt</file>\n        <file>recipes/Recipe 5.1.5 - Subpopulation size, Context-dependent changes (Muller's Ratchet).txt</file>\n        <file>recipes/Recipe 5.2.1 - Population structure, Adding subpopulations.txt</file>\n        <file>recipes/Recipe 5.2.2 - Population structure, Removing subpopulations.txt</file>\n        <file>recipes/Recipe 5.2.3 - Population structure, Splitting subpopulations.txt</file>\n        <file>recipes/Recipe 5.2.4 - Population structure, Joining subpopulations.txt</file>\n        <file>recipes/Recipe 5.3.1 - Migration and admixture, A linear stepping-stone model.txt</file>\n        <file>recipes/Recipe 5.3.2 - Migration and admixture, A non-spatial metapopulation.txt</file>\n        <file>recipes/Recipe 5.3.3 - Migration and admixture, A two-dimensional subpopulation matrix.txt</file>\n        <file>recipes/Recipe 5.3.4 - Migration and admixture, A random, sparse spatial metapopulation.txt</file>\n        <file>recipes/Recipe 5.3.5 - Migration and admixture, Reading a migration matrix from a file.txt</file>\n        <file>recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution I.txt</file>\n        <file>recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution II.txt</file>\n        <file>recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance I.txt</file>\n        <file>recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance II.txt</file>\n        <file>recipes/Recipe 6.1 - Genomic structure, Part I (Mutation types and fitness effects).txt</file>\n        <file>recipes/Recipe 6.2 - Genomic structure, Part II (Genomic element types).txt</file>\n        <file>recipes/Recipe 6.3 - Genomic structure, Part III (Chromosome organization).txt</file>\n        <file>recipes/Recipe 6.4 - Genomic structure, Part IV (Custom display colors in SLiMgui).txt</file>\n        <file>recipes/Recipe 8.1.1 - Reproduction, Enabling separate sexes.txt</file>\n        <file>recipes/Recipe 8.1.2 - Reproduction, Sex ratios I.txt</file>\n        <file>recipes/Recipe 8.1.2 - Reproduction, Sex ratios II.txt</file>\n        <file>recipes/Recipe 8.1.3 - Reproduction, Selfing in hermaphroditic populations.txt</file>\n        <file>recipes/Recipe 8.1.4 - Reproduction, Cloning I.txt</file>\n        <file>recipes/Recipe 8.1.4 - Reproduction, Cloning II.txt</file>\n        <file>recipes/Recipe 8.2.1 - Recombination, Making a random recombination map.txt</file>\n        <file>recipes/Recipe 8.2.2 - Recombination, Reading a recombination map from a file.txt</file>\n        <file>recipes/Recipe 8.2.3 - Recombination, Unlinked loci.txt</file>\n        <file>recipes/Recipe 8.2.4 - Recombination, Gene conversion.txt</file>\n        <file>recipes/Recipe 8.3.1 - Multiple diploid autosomes.txt</file>\n        <file>recipes/Recipe 8.3.2 - Clonal haploids and chromosome types.txt</file>\n        <file>recipes/Recipe 8.3.3 - Haploids with recombination.txt</file>\n        <file>recipes/Recipe 8.3.4 - Sex-chromosome evolution and null haplosomes.txt</file>\n        <file>recipes/Recipe 8.3.5 - Modeling the full human genome.txt</file>\n        <file>recipes/Recipe 8.3.6 - A model of bryophytes with UV sex determination.txt</file>\n        <file>recipes/Recipe 8.3.7 - Output from multiple-chromosome models.txt</file>\n        <file>recipes/Recipe 9.1 - Introducing adaptive mutations.txt</file>\n        <file>recipes/Recipe 9.2 - Making sweeps conditional on fixation.txt</file>\n        <file>recipes/Recipe 9.3 - Making sweeps conditional on establishment.txt</file>\n        <file>recipes/Recipe 9.4 - Partial sweeps.txt</file>\n        <file>recipes/Recipe 9.5.1 - A soft sweep from recurrent de novo mutations in a large population.txt</file>\n        <file>recipes/Recipe 9.5.2 - A soft sweep with a fixed de novo mutation schedule.txt</file>\n        <file>recipes/Recipe 9.5.3 - A soft sweep with a random de novo mutation schedule.txt</file>\n        <file>recipes/Recipe 9.6.1 - A sweep from standing variation at a random locus.txt</file>\n        <file>recipes/Recipe 9.6.2 - A sweep from standing variation at a predetermined locus.txt</file>\n        <file>recipes/Recipe 9.7 - Adaptive introgression.txt</file>\n        <file>recipes/Recipe 9.8 - Fixation probabilities under Hill-Robertson interference.txt</file>\n        <file>recipes/Recipe 9.9 - Keeping a reference to a sweep mutation.txt</file>\n        <file>recipes/Recipe 9.10 - Tracking the fate of background mutations.txt</file>\n        <file>recipes/Recipe 9.11 - Effective population size versus census population size.txt</file>\n        <file>recipes/Recipe 9.12 - Observing the site frequency spectrum (SFS) during selective sweeps.txt</file>\n        <file>recipes/Recipe 10.1 - Temporally varying selection.txt</file>\n        <file>recipes/Recipe 10.2 - Spatially varying selection.txt</file>\n        <file>recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis I.txt</file>\n        <file>recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis II.txt</file>\n        <file>recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection I.txt</file>\n        <file>recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection II.txt</file>\n        <file>recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection III.txt</file>\n        <file>recipes/Recipe 10.4.2 - Fitness as a function of population composition, Cultural effects on fitness.txt</file>\n        <file>recipes/Recipe 10.4.3 - Fitness as a function of population composition, Kin selection and the green-beard effect.txt</file>\n        <file>recipes/Recipe 10.5 - Changing selection coefficients with setSelectionCoeff().txt</file>\n        <file>recipes/Recipe 10.6 - Varying the dominance coefficient among mutations I.txt</file>\n        <file>recipes/Recipe 10.6 - Varying the dominance coefficient among mutations II.txt</file>\n        <file>recipes/Recipe 11.1 - Assortative mating.txt</file>\n        <file>recipes/Recipe 11.2 - Sequential mate search I.txt</file>\n        <file>recipes/Recipe 11.2 - Sequential mate search II.txt</file>\n        <file>recipes/Recipe 11.3 - Gametophytic self-incompatibility.txt</file>\n        <file>recipes/Recipe 12.1 - Social learning of cultural traits.txt</file>\n        <file>recipes/Recipe 12.2 - Lethal epistasis I.txt</file>\n        <file>recipes/Recipe 12.2 - Lethal epistasis II.txt</file>\n        <file>recipes/Recipe 12.3 - Simulating gene drive.txt</file>\n        <file>recipes/Recipe 12.4 - Suppressing hermaphroditic selfing.txt</file>\n        <file>recipes/Recipe 12.5 - Tracking separate sexes in script.txt</file>\n        <file>recipes/Recipe 13.1 - Polygenic selection.txt</file>\n        <file>recipes/Recipe 13.2 - A simple model of variable QTL effect sizes.txt</file>\n        <file>recipes/Recipe 13.3 - A model of discrete QTL effects across multiple chromosomes.txt</file>\n        <file>recipes/Recipe 13.4 - A quantitative genetics model with heritability.txt</file>\n        <file>recipes/Recipe 13.5 - A QTL-based model with two quantitative phenotypic traits and pleiotropy.txt</file>\n        <file>recipes/Recipe 13.6 - A variety of fitness functions I (stabilizing selection).txt</file>\n        <file>recipes/Recipe 13.6 - A variety of fitness functions II (directional selection).txt</file>\n        <file>recipes/Recipe 13.6 - A variety of fitness functions III (disruptive selection).txt</file>\n        <file>recipes/Recipe 13.6 - A variety of fitness functions IV (truncation selection).txt</file>\n        <file>recipes/Recipe 13.7 - Negative frequency-dependence on a quantitative trait.txt</file>\n        <file>recipes/Recipe 14.1 - Relatedness, inbreeding, and heterozygosity.txt</file>\n        <file>recipes/Recipe 14.2 - Mortality-based fitness I.txt</file>\n        <file>recipes/Recipe 14.2 - Mortality-based fitness II.txt</file>\n        <file>recipes/Recipe 14.2 - Mortality-based fitness III.txt</file>\n        <file>recipes/Recipe 14.3 - Reading initial simulation state from an MS output file I.txt</file>\n        <file>recipes/Recipe 14.3 - Reading initial simulation state from an MS output file II.txt</file>\n        <file>recipes/Recipe 14.4 - Modeling chromosomal inversions with a recombination() callback.txt</file>\n        <file>recipes/Recipe 14.5 - Estimating model parameters with ABC.txt</file>\n        <file>recipes/Recipe 14.6 - Tracking local ancestry along the chromosome.txt</file>\n        <file>recipes/Recipe 14.7 - Live plotting with R using system().txt</file>\n        <file>recipes/Recipe 14.8 - Using mutation rate variation to model varying functional density.txt</file>\n        <file>recipes/Recipe 14.9 - Modeling microsatellites.txt</file>\n        <file>recipes/Recipe 14.10 - Modeling transposable elements.txt</file>\n        <file>recipes/Recipe 14.11 - Modeling opposite ends of a chromosome I.txt</file>\n        <file>recipes/Recipe 14.11 - Modeling opposite ends of a chromosome II.txt</file>\n        <file>recipes/Recipe 14.12 - Visualizing ancestry and admixture with mutation() callbacks.txt</file>\n        <file>recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback I.txt</file>\n        <file>recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback II.txt</file>\n        <file>recipes/Recipe 14.14 - Modeling biallelic loci in script.txt</file>\n        <file>recipes/Recipe 14.15 - Using runs of homozygosity (ROH) to track inbreeding.txt</file>\n        <file>recipes/Recipe 14.16 - Visualizing linkage disequilibrium.txt</file>\n        <file>recipes/Recipe 15.1 - A minimal nonWF model.txt</file>\n        <file>recipes/Recipe 15.2 - Age structure (a life table model).txt</file>\n        <file>recipes/Recipe 15.4 - Monogamous mating and variation in litter size.txt</file>\n        <file>recipes/Recipe 15.5 - Beneficial mutations and absolute fitness.txt</file>\n        <file>recipes/Recipe 15.6 - A metapopulation extinction-colonization model.txt</file>\n        <file>recipes/Recipe 15.7 - Habitat choice.txt</file>\n        <file>recipes/Recipe 15.8 - Evolutionary rescue after environmental change.txt</file>\n        <file>recipes/Recipe 15.9 - Litter size and parental investment.txt</file>\n        <file>recipes/Recipe 15.10 - Recording a pedigree.txt</file>\n        <file>recipes/Recipe 15.11 - Dynamic population structure in nonWF models.txt</file>\n        <file>recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model I.txt</file>\n        <file>recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model II.txt</file>\n        <file>recipes/Recipe 15.13 - Range expansion in a stepping-stone model I.txt</file>\n        <file>recipes/Recipe 15.13 - Range expansion in a stepping-stone model II.txt</file>\n        <file>recipes/Recipe 15.14 - Logistic population growth with the Beverton-Holt model.txt</file>\n        <file>recipes/Recipe 16.1 - Pollen flow.txt</file>\n        <file>recipes/Recipe 16.2 - Following a pedigree.txt</file>\n        <file>recipes/Recipe 16.3 - Modeling clonal haploid bacteria with horizontal gene transfer.txt</file>\n        <file>recipes/Recipe 16.4 - Alternation of generations.txt</file>\n        <file>recipes/Recipe 16.5 - Meiotic drive.txt</file>\n        <file>recipes/Recipe 16.6 - Sperm storage with a survival() callback.txt</file>\n        <file>recipes/Recipe 16.7 - Tracking separate sexes in script, nonWF style.txt</file>\n        <file>recipes/Recipe 16.8 - Modeling haplodiploidy with addRecombinant().txt</file>\n        <file>recipes/Recipe 16.9 - Complex multi-chromosome inheritance with addMultiRecombinant().txt</file>\n        <file>recipes/Recipe 16.10 - Modeling pseudo-autosomal regions (PARs) with addMultiRecombinant().txt</file>\n        <file>recipes/Recipe 16.11 - Life-long monogamous mating.txt</file>\n        <file>recipes/Recipe 17.1 - A simple 2D continuous-space model.txt</file>\n        <file>recipes/Recipe 17.2 - Spatial competition.txt</file>\n        <file>recipes/Recipe 17.3 - Boundaries and boundary conditions I (stopping boundaries).txt</file>\n        <file>recipes/Recipe 17.3 - Boundaries and boundary conditions II (reflecting boundaries).txt</file>\n        <file>recipes/Recipe 17.3 - Boundaries and boundary conditions III (absorbing boundaries).txt</file>\n        <file>recipes/Recipe 17.3 - Boundaries and boundary conditions IV (reprising boundaries).txt</file>\n        <file>recipes/Recipe 17.3 - Boundaries and boundary conditions V (dispersal kernels).txt</file>\n        <file>recipes/Recipe 17.4 - Mate choice with a spatial kernel.txt</file>\n        <file>recipes/Recipe 17.5 - Mate choice with a nearest-neighbor search.txt</file>\n        <file>recipes/Recipe 17.6 - Divergence due to phenotypic competition with an interaction() callback.txt</file>\n        <file>recipes/Recipe 17.7 - Modeling phenotype as a spatial dimension.txt</file>\n        <file>recipes/Recipe 17.8 - Sympatric speciation facilitated by assortative mating.txt</file>\n        <file>recipes/Recipe 17.9 - Speciation due to spatial variation in selection.txt</file>\n        <file>recipes/Recipe 17.10 - A simple biogeographic landscape model.txt</file>\n        <file>recipes/Recipe 17.11 - Local adaptation on a heterogeneous landscape map.txt</file>\n        <file>recipes/Recipe 17.12 - Periodic spatial boundaries.txt</file>\n        <file>recipes/Recipe 17.13 - Density-dependent fecundity with summarizeIndividuals().txt</file>\n        <file>recipes/Recipe 17.14 - Directed dispersal with the SpatialMap class.txt</file>\n        <file>recipes/Recipe 17.15 - Spatial competition and spatial mate choice in a nonWF model.txt</file>\n        <file>recipes/Recipe 17.16 - A spatial model with carrying-capacity density.txt</file>\n        <file>recipes/Recipe 17.17 - A spatial epidemiological S-I-R model.txt</file>\n        <file>recipes/Recipe 17.18 - A sexual, age-structured spatial model.txt</file>\n        <file>recipes/Recipe 17.19 - Modeling indirect competition mediated by resource availability.txt</file>\n        <file>recipes/Recipe 18.1 - A minimal tree-seq model.txt</file>\n        <file>recipes/Recipe 18.2 - Overlaying neutral mutations.py</file>\n        <file>recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry I.txt</file>\n        <file>recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry II.txt</file>\n        <file>recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) I.txt</file>\n        <file>recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) II.py</file>\n        <file>recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) I.txt</file>\n        <file>recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) II.py</file>\n        <file>recipes/Recipe 18.6 - Measuring the coalescence time of a model I.txt</file>\n        <file>recipes/Recipe 18.6 - Measuring the coalescence time of a model II.txt</file>\n        <file>recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit I.txt</file>\n        <file>recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit II.py</file>\n        <file>recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history I.py</file>\n        <file>recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history II.txt</file>\n        <file>recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history III.py</file>\n        <file>recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history I.py</file>\n        <file>recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history II.txt</file>\n        <file>recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation I.txt</file>\n        <file>recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation II.py</file>\n        <file>recipes/Recipe 18.11 - Optimizing tree-sequence simplification.txt</file>\n        <file>recipes/Recipe 19.1 - A simple neutral nucleotide-based model.txt</file>\n        <file>recipes/Recipe 19.2 - Reading an ancestral nucleotide sequence from a FASTA file.txt</file>\n        <file>recipes/Recipe 19.3 - Sequence output from nucleotide-based models.txt</file>\n        <file>recipes/Recipe 19.4 - Back-mutations, independent mutational lineages, and VCF output.txt</file>\n        <file>recipes/Recipe 19.5 - Modeling elevated CpG mutation rates and equilibrium nucleotide frequencies.txt</file>\n        <file>recipes/Recipe 19.6 - A nucleotide-based model with introduced non-nucleotide-based mutations.txt</file>\n        <file>recipes/Recipe 19.7 - Using standard SLiM fitness effects with nucleotides (modeling synonymous sites).txt</file>\n        <file>recipes/Recipe 19.8 - Defining sequence-based fitness effects at the nucleotide level.txt</file>\n        <file>recipes/Recipe 19.9 - Defining sequence-based fitness effects at the amino acid level.txt</file>\n        <file>recipes/Recipe 19.10 - Varying the mutation rate along the chromosome in a nucleotide-based model.txt</file>\n        <file>recipes/Recipe 19.11 - Modeling GC-biased gene conversion (gBGC).txt</file>\n        <file>recipes/Recipe 19.12 - Reading VCF files to create nucleotide-based SNPs.txt</file>\n        <file>recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models I.txt</file>\n        <file>recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models II.py</file>\n        <file>recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models III.py</file>\n        <file>recipes/Recipe 19.14 - Modeling identity by state (IBS) (uniquing mutations with a mutation() callback).txt</file>\n        <file>recipes/Recipe 19.15 - Modeling identity by state (IBS) (uniquing back-mutations to the ancestral state).txt</file>\n        <file>recipes/Recipe 20.1 - A simple multispecies model.txt</file>\n        <file>recipes/Recipe 20.2 - A two-species model.txt</file>\n        <file>recipes/Recipe 20.3 - A deterministic host-parasitoid model.txt</file>\n        <file>recipes/Recipe 20.4 - An individual-based host-parasitoid model I.txt</file>\n        <file>recipes/Recipe 20.4 - An individual-based host-parasitoid model II.txt</file>\n        <file>recipes/Recipe 20.5 - A continuous-space host-parasitoid model.txt</file>\n        <file>recipes/Recipe 20.6 - A coevolutionary host-parasitoid trait-matching model.txt</file>\n        <file>recipes/Recipe 20.7 - A coevolutionary host-parasite matching-allele model.txt</file>\n        <file>recipes/Recipe 20.8 - Within-host reproduction in a host-pathogen model.txt</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n\t<img alt=\"Screenshot of SLiMgui running on OS X.\" height=\"75%\" width=\"75%\" src=\"https://messerlab.files.wordpress.com/2021/12/slimgui_screenshot.jpg\"/>\n</p>\n\n\n\n<p align=\"justify\">\n\tSLiM is an evolutionary simulation framework that combines a powerful engine for population genetic simulations with the capability of modeling arbitrarily complex evolutionary scenarios. Simulations are configured via the integrated Eidos scripting language that allows interactive control over practically every aspect of the simulated scenarios. The underlying individual-based simulation engine is highly optimized to enable modeling of entire chromosomes in large populations. We also provide a graphical user interface called SLiMgui on macOS, Linux, and Windows for easy simulation set-up, interactive runtime control, and dynamic visualization of simulation output.\n</p>\n\nGitHub Actions | Fedora Copr | Conda\n---|---|---\n![SLiM on GitHub Actions:](https://github.com/MesserLab/SLiM/workflows/tests/badge.svg) | [![Copr build status](https://copr.fedorainfracloud.org/coprs/bacarson/SLiM-Selection_on_Linked_Mutations/package/SLiM/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/bacarson/SLiM-Selection_on_Linked_Mutations/package/SLiM/) | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/slim/badges/platforms.svg)](https://anaconda.org/conda-forge/slim)\n\n:construction: This GitHub repository hosts the <em>upstream, development head version</em> of SLiM and SLiMgui.\n\n:warning: <strong>End users should generally not use these sources; they may contain serious bugs, or may not even compile</strong>.\n\n:heavy_check_mark: The <strong><em>release</em></strong> version of SLiM and SLiMgui is available at [http://messerlab.org/slim/](http://messerlab.org/slim/).\n\n\nLicense\n----------\n\nCopyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n\nSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with SLiM.  If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).\n\nDevelopment & Feedback\n-----------------------------------\n\nSLiM is a product of the Messer Lab, [http://messerlab.org/](http://messerlab.org/), by Benjamin C. Haller and Philipp W. Messer.  SLiM is under active development, and our goal is to make it as broadly useful as possible.  If you have feedback or feature requests, or if you are interested in contributing to SLiM, please contact Ben Haller at [bhaller@mac.com](mailto:bhaller@mac.com). Please note that Philipp is also looking for graduate students and postdocs.\n\nInstallation\n------------\n<em>Looking for Binary Packages / Installers?</em>\n\nThe following subsections summarize what methods for acquiring SLiM (and SLiMgui) are available.  Building from sources is also an option on all platforms; see the next section.  Chapter 2 of the SLiM manual contains much more detail on installation and building of SLiM.  The manual and other SLiM resources can be found at [http://messerlab.org/slim/](http://messerlab.org/slim/#Downloads).\n\n##### macOS\nDownload and double-click the macOS Installer from the SLiM home page at https://messerlab.org/slim/#Downloads.  It will install the `slim` and `eidos` command-line tools, as well as SLiMgui.\n\n##### Linux\n###### Arch & Manjaro\nAny Arch-based distributions *which support the AUR* should be compatible.\n\nhttps://aur.archlinux.org/packages/slim-simulator/\n\n###### Fedora, Red Hat, openSUSE\nDerivative distributions are not guaranteed compatibility with these binary packages. Enable the repository for your operating system; you might also try using the source RPM package to rebuild the package for your system to give you an excellent integration for any RPM-based distribution.\n\nhttps://copr.fedorainfracloud.org/coprs/bacarson/SLiM-Selection_on_Linked_Mutations/\n\n###### Debian & Ubuntu (and any derivatives using dpkg)\nA shell script using the facilities of `dpkg` is available. It uses the CMake install target to integrate SLiMgui with the desktop environment. It has the advantage over building from source that it will check build dependencies for you, and it will automatically remove build artifacts from `/tmp`. Source the script with `curl` following the instructions in the manual.\n\nhttps://raw.githubusercontent.com/MesserLab/SLiM-Extras/master/installation/DebianUbuntuInstall.sh\n\n##### Windows (10 & 11)\n###### Native package (using MSYS2)\nIf you have MSYS2 installed, you can do `pacman -Syu` to update its information (see the SLiM manual for further information).  You can then install SLiM and SLiMgui with:\n\n`pacman -S mingw-w64-x86_64-slim-simulator`\n\n###### WSL2 installation guide\nThe SLiM manual provides detailed instructions on building and installing SLiM and SLiMgui under the WSL2.\n\n\n\nCompilation of SLiM from Source\n----------------------------------\n\nYou can build both SLiM and SLiMgui from sources.  This can be useful, in particular, if you wish to run a recent development version of SLiM, rather than the last released version.  See chapter 2 of the SLiM manual for more information on building from sources on various platforms.\n"
  },
  {
    "path": "SLiM.pro",
    "content": "TEMPLATE = subdirs\n\nSUBDIRS += \\\n    eidos \\\n    core \\\n    QtSLiM \\\n    gsl \\\n    treerec/tskit \\\n    eidos_zlib\n\neidos.depends = gsl eidos_zlib\ncore.depends = gsl eidos_zlib eidos treerec/tskit\nQtSLiM.depends = gsl eidos_zlib eidos core treerec/tskit\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n"
  },
  {
    "path": "SLiM.spec",
    "content": "# Cross-distribution SLiM RPM spec.\n%if %{defined suse_version}\n%if 0%{?suse_version} < 1600\n%global qtNameAndVersion libqt5\n%else\n%global qtNameAndVersion qt6\n%endif\n%endif\n\n%if %{defined fedora}\n%if 0%{?fedora} >= 39\n%global qtNameAndVersion qt6\n%else\n%global qtNameAndVersion qt5\n%endif\n%endif\n\n%if %{defined rhel}\n%if 0%{?epel} >= 9\n# qt6 is only available through EPEL on RHEL 9 and higher\n%global qtNameAndVersion qt6\n%else\n%global qtNameAndVersion qt5\n%endif\n%endif\n\nName:           SLiM\nVersion:        5.2\nRelease:        1%{?dist}\nSummary:        an evolutionary simulation framework\n\nLicense:        GPLv3+\nURL:            https://messerlab.org/slim/\nSource0:        https://github.com/MesserLab/SLiM/archive/refs/tags/v%{version}.tar.gz\n\n# Prevent users of the Copr repository from using Simple Login Manager, due to binary file name conflict.\nConflicts:      slim\n\n# This paragraph of the spec file is old and delicate.\nBuildRequires:  cmake\n# openSUSE Build Requires\n%if %{defined suse_version}\nBuildRequires:  glew-devel\nBuildRequires:  Mesa-libGL-devel\nBuildRequires:  gcc-c++\nBuildRequires:  appstream-glib-devel\n%if 0%{?suse_version} < 1600\nBuildRequires:  %{qtNameAndVersion}-qtbase-devel\n%else\n# only Tumbleweed officially supports Qt6; further, it's \"base\" not \"qtbase\" in Tumbleweed. :(\nBuildRequires:  %{qtNameAndVersion}-base-devel\n%endif\n%else\n# if not on openSUSE\nBuildRequires:  %{qtNameAndVersion}-qtbase-devel\nBuildRequires:  libappstream-glib\n%endif\nExclusiveArch:  x86_64\n\n# RHEL 8 has the oldest point release of 5.15, and is the oldest RHEL supported.\n%if 0%{?rhel} == 8\nRequires: qt5-qtbase >= 5.15.1\n%else\nRequires: %{qtNameAndVersion}-qtbase\n%endif\n\n%description\nSLiM is an evolutionary simulation framework that combines a powerful engine for\npopulation genetic simulations with the capability of modeling arbitrarily\ncomplex evolutionary scenarios. Simulations are configured via the integrated\nEidos scripting language that allows interactive control over practically every\naspect of the simulated evolutionary scenarios. The underlying individual-based\nsimulation engine is highly optimized to enable modeling of entire chromosomes\nin large populations. We also provide a graphical user interface on macOS and\nLinux for easy simulation set-up, interactive runtime control, and dynamical\nvisualization of simulation output.\n\n%prep\n%setup -q\n\n%build\n%if 0%{?rhel} == 8\n%if \"%_vpath_builddir\" != \"%_vpath_srcdir\"\necho \"current directory: %(pwd)\"\necho \"source directory: %_vpath_srcdir\"\necho \"build directory: %_vpath_builddir\"\nmkdir -p %_vpath_builddir\n%else\n%{warn \"The build directory is the same as the source directory on RHEL 8!\"}\n%endif\n\n## Tell CMake where the source directory and the build directory are, directly.\n%cmake -S %_vpath_srcdir -B %_vpath_builddir -DBUILD_SLIMGUI=ON\ncd %_vpath_builddir\n%else\n# rpmbuild is not running on RHEL 8\n%cmake -DBUILD_SLIMGUI=ON\n%endif\n\n%cmake_build\n\n%install\n%if 0%{?rhel} == 8\ncmake --install %_vpath_builddir --prefix %{buildroot}/usr\n%else\n%cmake_install\n%endif\n\n%files\n%{_bindir}/eidos\n%{_bindir}/slim\n%{_bindir}/SLiMgui\n%{_datadir}/applications/org.messerlab.slimgui.desktop\n%{_datadir}/icons/hicolor/scalable/apps/org.messerlab.slimgui.svg\n%{_datadir}/icons/hicolor/scalable/mimetypes/text-slim.svg\n%{_datadir}/icons/hicolor/symbolic/apps/org.messerlab.slimgui-symbolic.svg\n%{_datadir}/metainfo/org.messerlab.slimgui.appdata.xml\n%{_datadir}/metainfo/org.messerlab.slimgui.metainfo.xml\n%{_datadir}/mime/packages/org.messerlab.slimgui-mime.xml\n\n%changelog\n* Fri Apr 11 2026 Ben Haller <bhaller@mac.com> - 5.2-1\n- No changes to the package have been made since the last release.\n- Final candidate 1 for 5.2 release\n\n* Fri Sep 12 2025 Ben Haller <bhaller@mac.com> - 5.1-1\n- No changes to the package have been made since the last release.\n- Final candidate 1 for 5.1 release\n\n* Sat Apr 12 2025 Bryce Carson <bryce.a.carson@gmail.com> - 5.0-1\n- Bump source version to five and use the new /archive/refs/tags/v5.0 path scheme for accessing the tags on GitHub.\n\n* Sun Sep 15 2024 Bryce Carson <bryce.a.carson@gmail.com> - 4.3-2\n- Significant work has been invested into debugging the build of RHEL 8 on COPR. For whatever reason, since 4.0.1-1, we were unable to build on RHEL 8 (or perhaps it was EPEL 8?). Regardless, the ability to build on RHEL 8 and EPEL 8 has been achieved or restored, using conditionals which check what distribution the build is occuring on. These conditionals check the distribution using the defined RPM macros, a reliable system that the operating systems try not to step on each others toes; it'd be nicer if CentOS didn't call itself RHEL, though, but CentOS purposefully tries to be \"bug-compatible\" (if I recall) with RHEL, yet be slightly upstream of it with RHEL. The buildroot (which is the installation prefix within the CHROOT) and the source and build directories must be manually specified when building on RHEL 8 or EPEL 8 systems (which is RHEL 8 + EPEL [the extra packages for enterprise linux repository] for RHEL 8). I don't know what changed amongst the macros, if anything ever did change, but with 4.0.1-1 we were able to build for EPEL 8 two years ago, and then we weren't when I tried however long ago that issue four-hundred and forty cropped up. This has been resolved with the use of conditionals in the RPM preprocessor (do recall that \"if\" is not actually a macro) and RPM macros.\n- Conditionals and macros are used to decide whether to use Qt 6 or Qt 5.\n\n* Mon Sep 02 2024 Bryce Carson <bryce.a.carson@gmail.com> - 4.3-1\n- Changes to the package have occurred. See the following points.\n- Further version checks for various distributions are introduced to allow cross-distribution packaging and building against Qt5 or Qt6, appropriate to the platform.\n- An attempt to fix issue 440 is made\n- See the SLiM release notes on GitHub for information about changes to the packaged software.\n\n* Tue Apr 30 2024 Ben Haller <bhaller@mac.com> - 4.2.2-1\n- No changes to the package have been made since the last release.\n- Ship the fix for the 4.2.1-2 crashing bug as a separate release.\n- Fix an issue with reading of some VCF files.\n\n* Tue Apr 30 2024 Ben Haller <bhaller@mac.com> - 4.2.1-2\n- No changes to the package have been made since the last release.\n- Another fix for a crashing bug under certain conditions.\n\n* Fri Apr 12 2024 Ben Haller <bhaller@mac.com> - 4.2.1-1\n- No changes to the package have been made since the last release.\n- Fix for a crashing bug under certain conditions.\n\n* Wed Mar 20 2024 Bryce Carson <bryce.a.carson@gmail.com> - 4.2-1\n- No changes to the package have been made since the last release. See the SLiM release notes on GitHub for information about changes to the packaged software.\n\n* Mon Dec 4 2023 Bryce Carson <bryce.a.carson@gmail.com> - 4.1-1\n- Final candidate 1 for 4.1 release\n- CMake install of package desktop environment data properly implemented\n- RPM macros adopted\n\n* Tue Sep 27 2022 Bryce Carson <bryce.a.carson@gmail.com> - 4.0.1-2\n- `CMakeLists.txt` improved, so the installation section of the RPM is now simplified.\n- Data files now exist in `data/`, rather than in the root folder of the software.\n\n* Tue Sep 13 2022 Ben Haller <bhaller@mac.com> - 4.0.1-1\n- Final candidate 1 for 4.0.1 release\n\n* Tue Aug 23 2022 Bryce Carson <bryce.a.carson@gmail.com> - 4.0-2\n- Include new changelog entry to identify the date of the new release\n\n* Wed Aug 10 2022 Bryce Carson <bryce.a.carson@gmail.com> - 4.0-1\n- New release\n\n* Sat Feb 12 2022 Bryce Carson <bryce.a.carson@gmail.com> - 3.7.1-1\n- Increment version\n\n* Wed Dec 15 2021 Ben Haller <bhaller@mac.com> - 3.7-1\n- Final candidate 1 for 3.7 release\n- Removed robinhood patch\n- Removed --parallel for cmake since it was no longer working\n\n* Sat Apr 24 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.6-5\n- Fixed email address in previous changelog entry.\n- Included a conflict tag to prevent users of this package from using the conflicting binary in Simple Login Manager.\n\n* Sat Mar 20 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.6-4\n- Added support for openSUSE (with SUSE Linux Enterprise users possibly able to use the openSUSE RPM).\n- Cleaned up the changelog.\n- The `[<jobs>]` argument to the cmake `--parallel` option was removed, so that Copr uses the default number of concurrent processes (and hopefully the maximum number, rather than hardcoding eight processes).\n\n* Wed Mar 3 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.6-3\n- Application of patch to allow building on Fedora 34 and Fedora Rawhide.\n\n* Wed Mar 3 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.6-2\n- Specified required Qt 5.15.2 on Fedora 34.\n- Added package version in previous changelog entry.\n\n* Wed Mar 3 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.6-1\n- New package release.\n- Removed source edits that were addressed upstream.\n\n* Sun Jan 31 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-6\n- spec file improvements; brace expansion used and sorting performed.\n- FreeDesktop compliance improvements; the organization domain and application name are corrected and are now compliant.\n- Source modifications allow Gnome Classic to display the proper application name.\n- The symbolic application icon is now created programmatically from upstream icons in the source, rather than a second source file.\n\n* Thu Jan 28 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-5\n- org.messerlab.slimgui.desktop changed in prep to correct Categories value; fixes desktop integration on Fedora 33 when using Gnome Classic environment.\n- New symbolic icon included; improves desktop integration on Fedora 33 when using Gnome 3 with Wayland.\n- Edited the changelog to not refer to the prep stage as a macro, simply \"prep\", to fix rpmlint warnings.\n\n* Thu Jan 14 2021 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-4\n- org.messerlab.slimgui.desktop changed in prep to correct StartupWMClass and icon; fixes desktop integration on Fedora 33.\n- Sorted changelog in descending chronological order.\n\n* Sun Dec 06 2020 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-3\n- Updated the requires in the .spec file (and thus the package dependencies) to reflect updates to Qt5 on Fedora 33.\n- Qt5 5.15.2 now required on Fedora 33.\n\n* Sun Dec 06 2020 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-2\n- Changed the tar command in .spec file to address discrepancy between GitHub archive URI and downloaded source archive.\n\n* Sun Dec 06 2020 Bryce Carson <bryce.a.carson@gmail.com> - 3.5-1\n- Created new release package\n- Differences from 3.4-8 include removal of necessary source modifications for 3.4\n- The source modifications for 3.4 were addressed by the upstream\n"
  },
  {
    "path": "SLiM.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t98024742215D85880025D29C /* FindRecipePanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98024740215D85880025D29C /* FindRecipePanel.xib */; };\n\t\t980566E225A7C5B9008D3C7F /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t980566E325A7C5B9008D3C7F /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t980566E425A7C5B9008D3C7F /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t980566E525A7C5B9008D3C7F /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t98076614244934A800F6CBB4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98076615244934A800F6CBB4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98076617244934A800F6CBB4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t98076618244934A800F6CBB4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t9807661C244934A800F6CBB4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t9807661D244934A800F6CBB4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t9807661E244934A800F6CBB4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t9807661F244934A800F6CBB4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t98076620244934A800F6CBB4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98076621244934A800F6CBB4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98076622244934A800F6CBB4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98076623244934A800F6CBB4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98076626244934A800F6CBB4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t98076627244934A800F6CBB4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t9807662924493A8F00F6CBB4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t9807662A24493A8F00F6CBB4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t9807662B24493E0B00F6CBB4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t9807662C24493E0B00F6CBB4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t9807662D24493E0B00F6CBB4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t9807662E24493E0B00F6CBB4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t9807662F24493E0B00F6CBB4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t9807663024493E0B00F6CBB4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t9807663124493E0B00F6CBB4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t9807663224493E0B00F6CBB4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t9807663324493E0B00F6CBB4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t9807663424493E0B00F6CBB4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t9807663524493E0B00F6CBB4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t9807663624493E0B00F6CBB4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t9807663724493E0B00F6CBB4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t9807663824493E0B00F6CBB4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t9807663924493E0B00F6CBB4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t9807663A24493E0B00F6CBB4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t9807C0F524BA21B7008CC658 /* slim_test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F324BA21B7008CC658 /* slim_test_core.cpp */; };\n\t\t9807C0F624BA21B7008CC658 /* slim_test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F324BA21B7008CC658 /* slim_test_core.cpp */; };\n\t\t9807C0F824BA21E3008CC658 /* slim_test_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F724BA21E3008CC658 /* slim_test_other.cpp */; };\n\t\t9807C0F924BA21E3008CC658 /* slim_test_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F724BA21E3008CC658 /* slim_test_other.cpp */; };\n\t\t98090FA21B1B8B5800791DBF /* show_browser_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA01B1B8B5800791DBF /* show_browser_H.pdf */; };\n\t\t98090FA31B1B8B5800791DBF /* show_browser.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA11B1B8B5800791DBF /* show_browser.pdf */; };\n\t\t98090FA61B1B978900791DBF /* EidosValueWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98090FA51B1B978900791DBF /* EidosValueWrapper.mm */; };\n\t\t9809DFA02550F32500C4E82D /* log_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9809DF9E2550F32500C4E82D /* log_file.cpp */; };\n\t\t9809DFA12550F32500C4E82D /* log_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9809DF9E2550F32500C4E82D /* log_file.cpp */; };\n\t\t980DD51A1AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 980DD5181AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib */; };\n\t\t980DD51D1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 980DD51C1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm */; };\n\t\t981BAC6A1ACC6E8B0005BE94 /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t981BAC6B1ACC6E8B0005BE94 /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t981DC35028E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t981DC35128E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t981DC35228E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t981DC35328E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t981DC35428E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC35528E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC35628E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC35728E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC35828E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC35928E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC35A28E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC35B28E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC35C28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC35D28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC35E28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC35F28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC36028E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC36128E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC36228E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC36328E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC36428E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC36528E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC36628E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC36728E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC36828E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC36928E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC36A28E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC36B28E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC36C28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC36D28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC36E28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC36F28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC37028E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37128E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37228E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37328E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37428E27300000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC37528E27300000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37628E27300000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC37728E27300000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC37828E27300000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC37928E27300000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC37A28E27300000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC37B28E27300000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC37C28E27300000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t981DC37D28E27301000ABE91 /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t981DC37E28E27301000ABE91 /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t981DC37F28E27301000ABE91 /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t981DC38028E27301000ABE91 /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t981DC38128E27301000ABE91 /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t981DC38228E27301000ABE91 /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t981DC38328E27301000ABE91 /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t981DC38428E27301000ABE91 /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t981DC38528E27301000ABE91 /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t9821E2041ABDBC300036EAEA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9821E2031ABDBC300036EAEA /* QuartzCore.framework */; };\n\t\t98235682252FDCF50096A745 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98235683252FDCF50096A745 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98235684252FDCF50096A745 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98235685252FDCF50096A745 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98235686252FDCF50096A745 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98235689252FE61A0096A745 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t9823568A252FE61A0096A745 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t9823568B252FE61A0096A745 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t9823568C252FE61A0096A745 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t9823568D252FE61A0096A745 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t9825565B1BA32EE80054CB3F /* EidosCocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */; };\n\t\t9825565C1BA32EE80054CB3F /* EidosCocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */; };\n\t\t982556651BA450980054CB3F /* EidosHelpController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 982556641BA450980054CB3F /* EidosHelpController.mm */; };\n\t\t982556661BA450980054CB3F /* EidosHelpController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 982556641BA450980054CB3F /* EidosHelpController.mm */; };\n\t\t982556691BA451D00054CB3F /* EidosHelpWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982556671BA451D00054CB3F /* EidosHelpWindow.xib */; };\n\t\t9825566A1BA451D00054CB3F /* EidosHelpWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982556671BA451D00054CB3F /* EidosHelpWindow.xib */; };\n\t\t9825566C1BA477D60054CB3F /* EidosHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */; };\n\t\t9825566D1BA477D60054CB3F /* EidosHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */; };\n\t\t9825566F1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566E1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf */; };\n\t\t982556A01BA5DFEB0054CB3F /* EidosHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */; };\n\t\t982556A11BA5DFEB0054CB3F /* EidosHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */; };\n\t\t982556A31BA5F0810054CB3F /* SLiMHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 982556A21BA5F0810054CB3F /* SLiMHelpClasses.rtf */; };\n\t\t982556AC1BA8E77C0054CB3F /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 982556AB1BA8E77C0054CB3F /* main.cpp */; };\n\t\t982556B01BA8EF720054CB3F /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t982556B11BA8EF760054CB3F /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t982556B21BA8EF790054CB3F /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t982556B31BA8EF7C0054CB3F /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t982556B41BA8EF7F0054CB3F /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t982556B51BA8EF830054CB3F /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t982556B61BA8EF860054CB3F /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t982556B71BA8EF8A0054CB3F /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t982556B81BA8EF8C0054CB3F /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t982556B91BA8EF8F0054CB3F /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t982556BA1BA8EF930054CB3F /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t982556BB1BA8EF960054CB3F /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t982556BC1BA8EF990054CB3F /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t982663541A3BABD300A0CBBF /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 982663531A3BABD300A0CBBF /* main.cpp */; };\n\t\t982A9DDE1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982A9DDC1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib */; };\n\t\t982B50C62704048E006E91BC /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t982B50C72704048E006E91BC /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t982B50C82704048E006E91BC /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t982B50C92704048E006E91BC /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t98321F911B406417007337A3 /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98321F941B406B67007337A3 /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98321F951B406B67007337A3 /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98321F961B406B67007337A3 /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98330C34294A73AB00B452E2 /* libomp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 98760EDC28CE5E7600CEBC40 /* libomp.dylib */; };\n\t\t98332A9E1FDB98ED00274FF0 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98332A9F1FDB990400274FF0 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98332AA01FDB990500274FF0 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98332AA11FDB990500274FF0 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98332AB41FDBA1E100274FF0 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98332AB51FDBA1E400274FF0 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98332AB61FDBA1E500274FF0 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98332AB71FDBA1E600274FF0 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98332AB91FDBA32200274FF0 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98332ABA1FDBA32500274FF0 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98332ABB1FDBA32500274FF0 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98332ABC1FDBA32500274FF0 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98332AC21FDBA53F00274FF0 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98332AC31FDBA54600274FF0 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98332AC41FDBA54600274FF0 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98332AC51FDBA54700274FF0 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98332AC71FDBA6B600274FF0 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98332AC81FDBA74900274FF0 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98332AC91FDBA74900274FF0 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98332ACA1FDBA74A00274FF0 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98332ACE1FDBA81A00274FF0 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98332ACF1FDBA87D00274FF0 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98332AD01FDBA87D00274FF0 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98332AD11FDBA87E00274FF0 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98332AD71FDBBD1600274FF0 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98332AD81FDBBE3500274FF0 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98332AD91FDBBE3600274FF0 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98332ADA1FDBBE3600274FF0 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98332ADC1FDBC0D000274FF0 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98332ADD1FDBC0D700274FF0 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98332ADE1FDBC0D700274FF0 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98332ADF1FDBC0D800274FF0 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98332AE81FDBC1D900274FF0 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98332AEA1FDBC1D900274FF0 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98332AED1FDBC29400274FF0 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98332AEE1FDBC29500274FF0 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98332AEF1FDBC29500274FF0 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98332AF11FDBC36300274FF0 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98332AF21FDBC36300274FF0 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98332AF31FDBC36400274FF0 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98332AF71FDBC3F100274FF0 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98332AF81FDBC42600274FF0 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98332AF91FDBC42700274FF0 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98332AFA1FDBC42700274FF0 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98332AFC1FDBC4B200274FF0 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98332AFD1FDBC4BB00274FF0 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98332AFE1FDBC4BB00274FF0 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98332AFF1FDBC4BC00274FF0 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98332B031FDBCFC300274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98332B041FDBCFF900274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98332B051FDBCFF900274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98332B061FDBCFF900274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98332B0A1FDBD00800274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98332B0B1FDBD03100274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98332B0C1FDBD03200274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98332B0D1FDBD03200274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98332B111FDBD09800274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98332B121FDBD0F500274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98332B131FDBD0F500274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98332B141FDBD0F600274FF0 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98332B181FDBD13D00274FF0 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98332B191FDBD16500274FF0 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98332B1A1FDBD16500274FF0 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98332B1B1FDBD16600274FF0 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t9836867427CD40CF00683639 /* community.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836867227CD40CF00683639 /* community.cpp */; };\n\t\t9836867527CD40CF00683639 /* community.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836867227CD40CF00683639 /* community.cpp */; };\n\t\t9836868127CD72E900683639 /* community_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836868027CD72E900683639 /* community_eidos.cpp */; };\n\t\t9836868227CD72E900683639 /* community_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836868027CD72E900683639 /* community_eidos.cpp */; };\n\t\t984252C3216FA9930019696A /* FindRecipeController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 984252C2216FA9930019696A /* FindRecipeController.mm */; };\n\t\t98453F401A75A12700C058CB /* dump_output_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F3E1A75A12700C058CB /* dump_output_H.pdf */; };\n\t\t98453F411A75A12700C058CB /* dump_output.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F3F1A75A12700C058CB /* dump_output.pdf */; };\n\t\t98453F441A75AABE00C058CB /* syntax_help_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F421A75AABE00C058CB /* syntax_help_H.pdf */; };\n\t\t98453F451A75AABE00C058CB /* syntax_help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F431A75AABE00C058CB /* syntax_help.pdf */; };\n\t\t98453F561A76004300C058CB /* open_type_drawer_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4C1A76004300C058CB /* open_type_drawer_H.pdf */; };\n\t\t98453F571A76004300C058CB /* open_type_drawer.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4D1A76004300C058CB /* open_type_drawer.pdf */; };\n\t\t98453F581A76004300C058CB /* show_fixed_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4E1A76004300C058CB /* show_fixed_H.pdf */; };\n\t\t98453F591A76004300C058CB /* show_fixed.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4F1A76004300C058CB /* show_fixed.pdf */; };\n\t\t98453F5A1A76004300C058CB /* show_genomicelements_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F501A76004300C058CB /* show_genomicelements_H.pdf */; };\n\t\t98453F5B1A76004300C058CB /* show_genomicelements.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F511A76004300C058CB /* show_genomicelements.pdf */; };\n\t\t98453F5C1A76004300C058CB /* show_mutations_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F521A76004300C058CB /* show_mutations_H.pdf */; };\n\t\t98453F5D1A76004300C058CB /* show_mutations.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F531A76004300C058CB /* show_mutations.pdf */; };\n\t\t98453F5E1A76004300C058CB /* show_recombination_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F541A76004300C058CB /* show_recombination_H.pdf */; };\n\t\t98453F5F1A76004300C058CB /* show_recombination.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F551A76004300C058CB /* show_recombination.pdf */; };\n\t\t98453F621A76041200C058CB /* edit_submenu_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F601A76041200C058CB /* edit_submenu_H.pdf */; };\n\t\t98453F631A76041200C058CB /* edit_submenu.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F611A76041200C058CB /* edit_submenu.pdf */; };\n\t\t984824EE210B9E8F002402A5 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t984824F1210B9F23002402A5 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t984824F2210B9F2C002402A5 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t984824F3210B9F2D002402A5 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t984824F4210B9F2D002402A5 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t984824F5210B9F31002402A5 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t984824F6210B9F32002402A5 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t984824F7210B9F32002402A5 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t984D5FB31E3AF18C00473719 /* EidosTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 984D5FB21E3AF18C00473719 /* EidosTests.mm */; };\n\t\t984D5FB51E3AF1F000473719 /* SLiMTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 984D5FB41E3AF1F000473719 /* SLiMTests.mm */; };\n\t\t9850D8E32063098E006BFD2E /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 9850D8DF2063098E006BFD2E /* tables.c */; };\n\t\t9850D8E9206309A0006BFD2E /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 9850D8DF2063098E006BFD2E /* tables.c */; };\n\t\t985301EC1B72582E001520DF /* change_cloning_rate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985301EB1B72582E001520DF /* change_cloning_rate.pdf */; };\n\t\t9854D25F2278B9F8001D43BC /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2562278B9F7001D43BC /* core.c */; };\n\t\t9854D2602278B9F8001D43BC /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2562278B9F7001D43BC /* core.c */; };\n\t\t9854D2612278B9F8001D43BC /* genotypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2572278B9F7001D43BC /* genotypes.c */; };\n\t\t9854D2622278B9F8001D43BC /* genotypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2572278B9F7001D43BC /* genotypes.c */; };\n\t\t9854D2632278B9F8001D43BC /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2592278B9F8001D43BC /* convert.c */; };\n\t\t9854D2642278B9F8001D43BC /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2592278B9F8001D43BC /* convert.c */; };\n\t\t9854D2652278B9F8001D43BC /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25B2278B9F8001D43BC /* stats.c */; };\n\t\t9854D2662278B9F8001D43BC /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25B2278B9F8001D43BC /* stats.c */; };\n\t\t9854D2672278B9F8001D43BC /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25D2278B9F8001D43BC /* trees.c */; };\n\t\t9854D2682278B9F8001D43BC /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25D2278B9F8001D43BC /* trees.c */; };\n\t\t9857249C1AD08A810047C223 /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t9857249D1AD08A810047C223 /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t985724A11AD34B740047C223 /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t985724A21AD34B740047C223 /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t985724A51AD435310047C223 /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t985724A61AD435310047C223 /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t985724AA1AD4551C0047C223 /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t985724B51AD478630047C223 /* EidosAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724B41AD478630047C223 /* EidosAppDelegate.mm */; };\n\t\t985724B71AD478630047C223 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 985724B61AD478630047C223 /* main.m */; };\n\t\t985724B91AD478630047C223 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 985724B81AD478630047C223 /* Images.xcassets */; };\n\t\t985724BC1AD478630047C223 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 985724BA1AD478630047C223 /* MainMenu.xib */; };\n\t\t985724CF1AD479010047C223 /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t985724D01AD479010047C223 /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t985724D11AD479010047C223 /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t985724D21AD479010047C223 /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t985724D31AD479010047C223 /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t985724D51AD481070047C223 /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t985724D61AD489AA0047C223 /* check_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2231A71F8AD00FFB083 /* check_H.pdf */; };\n\t\t985724D71AD489AA0047C223 /* check.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2241A71F8AD00FFB083 /* check.pdf */; };\n\t\t985724D81AD489AA0047C223 /* delete_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2251A71F8AD00FFB083 /* delete_H.pdf */; };\n\t\t985724D91AD489AA0047C223 /* delete.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2261A71F8AD00FFB083 /* delete.pdf */; };\n\t\t985724DA1AD489AA0047C223 /* syntax_help_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F421A75AABE00C058CB /* syntax_help_H.pdf */; };\n\t\t985724DB1AD489AA0047C223 /* syntax_help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F431A75AABE00C058CB /* syntax_help.pdf */; };\n\t\t985724E01AD4C3310047C223 /* execute_script_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DE1AD4C3310047C223 /* execute_script_H.pdf */; };\n\t\t985724E11AD4C3310047C223 /* execute_script.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DF1AD4C3310047C223 /* execute_script.pdf */; };\n\t\t985724E71AD622880047C223 /* EidosConsoleTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724E61AD622880047C223 /* EidosConsoleTextView.mm */; };\n\t\t985724EA1AD6B9FE0047C223 /* execute_selection_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */; };\n\t\t985724EB1AD6B9FE0047C223 /* execute_selection.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E91AD6B9FE0047C223 /* execute_selection.pdf */; };\n\t\t985724F01AD6D4060047C223 /* show_parse_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EC1AD6D4060047C223 /* show_parse_H.pdf */; };\n\t\t985724F11AD6D4060047C223 /* show_parse.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724ED1AD6D4060047C223 /* show_parse.pdf */; };\n\t\t985724F21AD6D4060047C223 /* show_tokens_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EE1AD6D4060047C223 /* show_tokens_H.pdf */; };\n\t\t985724F31AD6D4060047C223 /* show_tokens.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EF1AD6D4060047C223 /* show_tokens.pdf */; };\n\t\t985724F61AD6DD470047C223 /* show_execution_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F41AD6DD470047C223 /* show_execution_H.pdf */; };\n\t\t985724F71AD6DD470047C223 /* show_execution.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F51AD6DD470047C223 /* show_execution.pdf */; };\n\t\t985D1D8B2808B84F00461CFA /* sparse_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985D1D892808B84F00461CFA /* sparse_vector.cpp */; };\n\t\t985D1D8C2808B84F00461CFA /* sparse_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985D1D892808B84F00461CFA /* sparse_vector.cpp */; };\n\t\t985F3EEA24BA27EC00E712E0 /* slim_test_genetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */; };\n\t\t985F3EEB24BA27EC00E712E0 /* slim_test_genetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */; };\n\t\t985F3EED24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t985F3EEE24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t985F3EEF24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t985F3EF024BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t985F3EF224BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t985F3EF324BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t985F3EF424BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t985F3EF524BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t985F3EF724BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t985F3EF824BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t985F3EF924BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t985F3EFA24BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t985F3EFC24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t985F3EFD24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t985F3EFE24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t985F3EFF24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t985F3F0124BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t985F3F0224BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t985F3F0324BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t985F3F0424BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t985F3F0624BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t985F3F0724BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t985F3F0824BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t985F3F0924BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t985F3F0B24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t985F3F0C24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t985F3F0D24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t985F3F0E24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t98606AEE1DED0DCD00821CFF /* mutation_run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98606AEC1DED0DCD00821CFF /* mutation_run.cpp */; };\n\t\t98606AEF1DED0DCD00821CFF /* mutation_run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98606AEC1DED0DCD00821CFF /* mutation_run.cpp */; };\n\t\t986070EA2AACECD600FD6143 /* spatial_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986070E82AACECD600FD6143 /* spatial_kernel.cpp */; };\n\t\t986070EB2AACECD600FD6143 /* spatial_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986070E82AACECD600FD6143 /* spatial_kernel.cpp */; };\n\t\t986070EC2AACECD600FD6143 /* spatial_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986070E82AACECD600FD6143 /* spatial_kernel.cpp */; };\n\t\t986070ED2AACECD600FD6143 /* spatial_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986070E82AACECD600FD6143 /* spatial_kernel.cpp */; };\n\t\t986151DE2B1679C20083E68F /* slim_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98800DC21B7EDCB50046F5F9 /* slim_test.cpp */; };\n\t\t986151DF2B1679EC0083E68F /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t986151E02B167A080083E68F /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t986151E12B167A0F0083E68F /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t986151E22B167A130083E68F /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t986151E32B167A160083E68F /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t986151E42B167A190083E68F /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t986151E52B167A1C0083E68F /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t986151E62B167A1E0083E68F /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t986151E72B167A210083E68F /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t986151E82B167A280083E68F /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t986151E92B167A2C0083E68F /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t986151EA2B167A2E0083E68F /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t986151EB2B167A320083E68F /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t986151EC2B167A350083E68F /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t986151ED2B167A380083E68F /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t986151EE2B167A3A0083E68F /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t986151EF2B167A3D0083E68F /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t986151F02B167A400083E68F /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t986151F12B167A430083E68F /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t986151F22B167A490083E68F /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t986151F32B167A4D0083E68F /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t986151F42B167A4F0083E68F /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t986151F52B167A520083E68F /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t986151F62B167A550083E68F /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t986151F72B167A580083E68F /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t986151F82B167A5B0083E68F /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t986151F92B167A5E0083E68F /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t986151FA2B167A610083E68F /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t986151FB2B167A640083E68F /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t986151FC2B167A670083E68F /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t986151FD2B167A6A0083E68F /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t986151FE2B167A710083E68F /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t986151FF2B167A7A0083E68F /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t986152002B167A7A0083E68F /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t986152012B167A7A0083E68F /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t986152022B167A7A0083E68F /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t986152032B167A7A0083E68F /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t986152042B167A7A0083E68F /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t986152052B167A7A0083E68F /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t986152062B167A940083E68F /* genotypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2572278B9F7001D43BC /* genotypes.c */; };\n\t\t986152072B167A940083E68F /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 9850D8DF2063098E006BFD2E /* tables.c */; };\n\t\t986152082B167A940083E68F /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2562278B9F7001D43BC /* core.c */; };\n\t\t986152092B167A940083E68F /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2592278B9F8001D43BC /* convert.c */; };\n\t\t9861520A2B167A940083E68F /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25B2278B9F8001D43BC /* stats.c */; };\n\t\t9861520B2B167A940083E68F /* text_input.c in Sources */ = {isa = PBXBuildFile; fileRef = D0A758F620A4CC9800132D2F /* text_input.c */; };\n\t\t9861520C2B167A940083E68F /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25D2278B9F8001D43BC /* trees.c */; };\n\t\t9861520D2B167AED0083E68F /* slim_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9898172D1A59750300F7417C /* slim_globals.cpp */; };\n\t\t9861520E2B167AED0083E68F /* community_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836868027CD72E900683639 /* community_eidos.cpp */; };\n\t\t9861520F2B167AED0083E68F /* mutation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6881A3CCFD0000AD4FC /* mutation.cpp */; };\n\t\t986152102B167AED0083E68F /* genomic_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */; };\n\t\t986152112B167AED0083E68F /* polymorphism.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */; };\n\t\t986152122B167AED0083E68F /* spatial_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */; };\n\t\t986152132B167AED0083E68F /* species_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AC617924BA34ED0001914C /* species_eidos.cpp */; };\n\t\t986152142B167AED0083E68F /* mutation_run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98606AEC1DED0DCD00821CFF /* mutation_run.cpp */; };\n\t\t986152152B167AED0083E68F /* slim_test_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F724BA21E3008CC658 /* slim_test_other.cpp */; };\n\t\t986152162B167AED0083E68F /* spatial_kernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986070E82AACECD600FD6143 /* spatial_kernel.cpp */; };\n\t\t986152172B167AED0083E68F /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6AC1A3CD5D3000AD4FC /* population.cpp */; };\n\t\t986152182B167AED0083E68F /* slim_eidos_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */; };\n\t\t986152192B167AED0083E68F /* slim_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DDAED4221765480038C133 /* slim_functions.cpp */; };\n\t\t9861521A2B167AED0083E68F /* individual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98C92AEB1D0B07A6001C82BC /* individual.cpp */; };\n\t\t9861521B2B167AED0083E68F /* species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9878A93D1A4E57E70007B9D6 /* species.cpp */; };\n\t\t9861521C2B167AED0083E68F /* community.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836867227CD40CF00683639 /* community.cpp */; };\n\t\t9861521D2B167AED0083E68F /* genomic_element_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */; };\n\t\t9861521E2B167AED0083E68F /* substitution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69D1A3CD551000AD4FC /* substitution.cpp */; };\n\t\t9861521F2B167AED0083E68F /* haplosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */; };\n\t\t986152202B167AED0083E68F /* slim_test_genetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */; };\n\t\t986152212B167AED0083E68F /* slim_test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F324BA21B7008CC658 /* slim_test_core.cpp */; };\n\t\t986152222B167AED0083E68F /* subpopulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */; };\n\t\t986152232B167AED0083E68F /* chromosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6971A3CD52A000AD4FC /* chromosome.cpp */; };\n\t\t986152242B167AED0083E68F /* log_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9809DF9E2550F32500C4E82D /* log_file.cpp */; };\n\t\t986152252B167AED0083E68F /* sparse_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985D1D892808B84F00461CFA /* sparse_vector.cpp */; };\n\t\t986152262B167AED0083E68F /* mutation_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */; };\n\t\t986152272B167B4E0083E68F /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t986152282B167B4E0083E68F /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t986152292B167B4E0083E68F /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t9861522A2B167B4E0083E68F /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t9861522B2B167B4E0083E68F /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t9861522C2B167B4E0083E68F /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t9861522D2B167B4E0083E68F /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t9861522E2B167B4E0083E68F /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t9861522F2B167B4E0083E68F /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t986152302B167B4E0083E68F /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t986152312B167B4E0083E68F /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t986152322B167B4E0083E68F /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t986152332B167B4E0083E68F /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t986152342B167B4E0083E68F /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t986152352B167B4E0083E68F /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t986152362B167B4E0083E68F /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t986152372B167B4E0083E68F /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t986152382B167B4E0083E68F /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t986152392B167B4E0083E68F /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t9861523A2B167B4E0083E68F /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t9861523B2B167B4E0083E68F /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t9861523C2B167B4E0083E68F /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t9861523D2B167B4E0083E68F /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t9861523E2B167B4E0083E68F /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t9861523F2B167B4E0083E68F /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t986152402B167B4E0083E68F /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t986152412B167B4E0083E68F /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t986152422B167B4E0083E68F /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t986152432B167B4E0083E68F /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t986152442B167B4E0083E68F /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t986152452B167B4E0083E68F /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t986152462B167B4E0083E68F /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t986152472B167B4E0083E68F /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t986152482B167B4E0083E68F /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t986152492B167B4E0083E68F /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t9861524A2B167B4E0083E68F /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t9861524B2B167B4E0083E68F /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t9861524C2B167B4E0083E68F /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t9861524D2B167B4E0083E68F /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t9861524E2B167B4E0083E68F /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t9861524F2B167B4E0083E68F /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t986152502B167B4E0083E68F /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t986152512B167B4E0083E68F /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t986152522B167B4E0083E68F /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t986152532B167B4E0083E68F /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t986152542B167B4E0083E68F /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t986152552B167B4E0083E68F /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t986152562B167B4E0083E68F /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t986152572B167B4E0083E68F /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t986152582B167B4E0083E68F /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t986152592B167B4E0083E68F /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t9861525A2B167B4E0083E68F /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t9861525B2B167B4E0083E68F /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t9861525C2B167B4E0083E68F /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t9861525D2B167B4E0083E68F /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t9861525E2B167B4E0083E68F /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t9861525F2B167B4E0083E68F /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t986152602B167B4E0083E68F /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t986152612B167B4E0083E68F /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t986152622B167B4E0083E68F /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t986152632B167B4E0083E68F /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t986152642B167B4E0083E68F /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t986152652B167B4E0083E68F /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t986152662B167B4E0083E68F /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t986152672B167B4E0083E68F /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t986152682B167B4E0083E68F /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t986152692B167B4E0083E68F /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t9861526A2B167B4E0083E68F /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t9861526B2B167B4E0083E68F /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t9861526C2B167B4E0083E68F /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t9861526D2B167B4E0083E68F /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t9861526E2B167B4E0083E68F /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t9861526F2B167B4E0083E68F /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t986152702B167B4E0083E68F /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t986152712B167B4E0083E68F /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t986152722B167B4E0083E68F /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t986152732B167B4E0083E68F /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t986152742B167B4E0083E68F /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t986152752B167B4E0083E68F /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t986152762B167C620083E68F /* kastore.c in Sources */ = {isa = PBXBuildFile; fileRef = 987D19A4209A53850030D28D /* kastore.c */; };\n\t\t986152772B167CBE0083E68F /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t986152782B167D0B0083E68F /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t986926D41AA1337A0000E138 /* graph_submenu_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 986926D21AA1337A0000E138 /* graph_submenu_H.pdf */; };\n\t\t986926D51AA1337A0000E138 /* graph_submenu.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 986926D31AA1337A0000E138 /* graph_submenu.pdf */; };\n\t\t986926D91AA140550000E138 /* GraphView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926D81AA140550000E138 /* GraphView.mm */; };\n\t\t986926DC1AA1429D0000E138 /* GraphWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 986926DA1AA1429D0000E138 /* GraphWindow.xib */; };\n\t\t986926DF1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926DE1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm */; };\n\t\t986926E21AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E11AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm */; };\n\t\t986926E51AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E41AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm */; };\n\t\t986926E81AA40AFF0000E138 /* GraphView_FitnessOverTime.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E71AA40AFF0000E138 /* GraphView_FitnessOverTime.mm */; };\n\t\t986926EB1AA6B7480000E138 /* GraphView_PopulationVisualization.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926EA1AA6B7480000E138 /* GraphView_PopulationVisualization.mm */; };\n\t\t986D73E81B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t986D73E91B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t986D73EA1B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t98729AD82A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729AD92A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADA2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADB2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADC2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADD2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADE2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98729ADF2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */; };\n\t\t98760EDD28CE5E7600CEBC40 /* libomp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 98760EDC28CE5E7600CEBC40 /* libomp.dylib */; };\n\t\t98760EDE28CE5E8200CEBC40 /* libomp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 98760EDC28CE5E7600CEBC40 /* libomp.dylib */; };\n\t\t9876E5F51ED5572C00FF9762 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t9876E5F61ED5573700FF9762 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t9876E5F71ED5573700FF9762 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t9876E5F81ED5573800FF9762 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t9876E5FC1ED5599F00FF9762 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t9876E5FD1ED559A600FF9762 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t9876E5FE1ED559A600FF9762 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t9876E5FF1ED559A700FF9762 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t9876E6011ED55A2500FF9762 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t9876E6031ED55A7800FF9762 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t9876E6041ED55A7800FF9762 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t9876E6051ED55A7900FF9762 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t9876E6081ED55B4700FF9762 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t9876E6091ED55B4F00FF9762 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t9876E60A1ED55B4F00FF9762 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t9876E60B1ED55B5000FF9762 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t9876E60D1ED55C0400FF9762 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t9876E60E1ED55C0B00FF9762 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t9876E60F1ED55C0C00FF9762 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t9876E6101ED55C0C00FF9762 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t9876E6121ED55C6B00FF9762 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t9876E6131ED55C7300FF9762 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t9876E6141ED55C7400FF9762 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t9876E6151ED55C7400FF9762 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t9878A93F1A4E57E70007B9D6 /* species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9878A93D1A4E57E70007B9D6 /* species.cpp */; };\n\t\t987A2A0724033856009A636F /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t987A2A0824033856009A636F /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t987A2A0924033856009A636F /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t987A2A0A24033856009A636F /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t987A700F2AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70102AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70112AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70122AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70132AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70142AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70152AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987A70162AE8032100A049E2 /* laplace.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A700E2AE8032100A049E2 /* laplace.c */; };\n\t\t987AD8741B2CBDA70035D6C8 /* show_console_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 987AD8721B2CBDA70035D6C8 /* show_console_H.pdf */; };\n\t\t987AD8751B2CBDA70035D6C8 /* show_console.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 987AD8731B2CBDA70035D6C8 /* show_console.pdf */; };\n\t\t987AD8761B2CBE010035D6C8 /* show_browser_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA01B1B8B5800791DBF /* show_browser_H.pdf */; };\n\t\t987AD8771B2CBE050035D6C8 /* show_browser.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA11B1B8B5800791DBF /* show_browser.pdf */; };\n\t\t987AD8781B2CBE280035D6C8 /* execute_script_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DE1AD4C3310047C223 /* execute_script_H.pdf */; };\n\t\t987AD8791B2CBE2E0035D6C8 /* execute_script.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DF1AD4C3310047C223 /* execute_script.pdf */; };\n\t\t987AD87A1B2CBE330035D6C8 /* execute_selection_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */; };\n\t\t987AD87B1B2CBE360035D6C8 /* execute_selection.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E91AD6B9FE0047C223 /* execute_selection.pdf */; };\n\t\t987AD87C1B2CBE4B0035D6C8 /* show_parse_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EC1AD6D4060047C223 /* show_parse_H.pdf */; };\n\t\t987AD87D1B2CBE4F0035D6C8 /* show_parse.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724ED1AD6D4060047C223 /* show_parse.pdf */; };\n\t\t987AD87E1B2CBE520035D6C8 /* show_tokens_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EE1AD6D4060047C223 /* show_tokens_H.pdf */; };\n\t\t987AD87F1B2CBE550035D6C8 /* show_tokens.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EF1AD6D4060047C223 /* show_tokens.pdf */; };\n\t\t987AD8801B2CBE580035D6C8 /* show_execution_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F41AD6DD470047C223 /* show_execution_H.pdf */; };\n\t\t987AD8811B2CBE5B0035D6C8 /* show_execution.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F51AD6DD470047C223 /* show_execution.pdf */; };\n\t\t987AD8821B2CBF960035D6C8 /* EidosConsoleTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724E61AD622880047C223 /* EidosConsoleTextView.mm */; };\n\t\t987AD8831B2CBF9A0035D6C8 /* EidosValueWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98090FA51B1B978900791DBF /* EidosValueWrapper.mm */; };\n\t\t987AD8861B2CC0C10035D6C8 /* EidosVariableBrowserController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */; };\n\t\t987AD8871B2CC0C10035D6C8 /* EidosVariableBrowserController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */; };\n\t\t987AD88A1B2CDBB80035D6C8 /* EidosConsoleWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */; };\n\t\t987AD88B1B2CDBB80035D6C8 /* EidosConsoleWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */; };\n\t\t987D19A5209A53850030D28D /* kastore.c in Sources */ = {isa = PBXBuildFile; fileRef = 987D19A4209A53850030D28D /* kastore.c */; };\n\t\t987D19A6209A53850030D28D /* kastore.c in Sources */ = {isa = PBXBuildFile; fileRef = 987D19A4209A53850030D28D /* kastore.c */; };\n\t\t98800DC41B7EDCB50046F5F9 /* slim_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98800DC21B7EDCB50046F5F9 /* slim_test.cpp */; };\n\t\t98800DC51B82B6C60046F5F9 /* slim_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98800DC21B7EDCB50046F5F9 /* slim_test.cpp */; };\n\t\t9887946B1EA8804900AE0C8D /* SLiMPDFDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9887946A1EA8804900AE0C8D /* SLiMPDFDocument.mm */; };\n\t\t9887946F1EA8808000AE0C8D /* SLiMPDFWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9887946D1EA8808000AE0C8D /* SLiMPDFWindowController.mm */; };\n\t\t988794701EA8808000AE0C8D /* SLiMPDFWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9887946E1EA8808000AE0C8D /* SLiMPDFWindow.xib */; };\n\t\t988794731EA8C42200AE0C8D /* SLiMPDFView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 988794721EA8C42200AE0C8D /* SLiMPDFView.mm */; };\n\t\t988880EC20744EE900E10172 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t988880ED20744F0100E10172 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t988880EE20744F0100E10172 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t988880EF20744F0200E10172 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t9890D1ED27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t9890D1EE27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t9890D1EF27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t9890D1F027136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t9890D2002713741C001EAE98 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t9892282B1BAE279700429674 /* EidosHelpOperators.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282A1BAE279700429674 /* EidosHelpOperators.rtf */; };\n\t\t9892282C1BAE279700429674 /* EidosHelpOperators.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282A1BAE279700429674 /* EidosHelpOperators.rtf */; };\n\t\t9892282E1BAE27AA00429674 /* EidosHelpTypes.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */; };\n\t\t9892282F1BAE27AA00429674 /* EidosHelpTypes.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */; };\n\t\t989228311BAF496C00429674 /* EidosHelpStatements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228301BAF496C00429674 /* EidosHelpStatements.rtf */; };\n\t\t989228321BAF496C00429674 /* EidosHelpStatements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228301BAF496C00429674 /* EidosHelpStatements.rtf */; };\n\t\t989228341BAFB27300429674 /* SLiMHelpCallbacks.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228331BAFB27300429674 /* SLiMHelpCallbacks.rtf */; };\n\t\t9893C7DD1CDA2D650029AC94 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t9893C7DE1CDA2D650029AC94 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t9893C7DF1CDA2FC10029AC94 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t9893C7E01CDA2FC20029AC94 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t9893C7E31CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t9893C7E41CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t9893C7E51CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t9893C7E61CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t9893C7E91CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t9893C7EA1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t9893C7EB1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t9893C7EC1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t989524A91E40AE74007E62FA /* SLiMDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 989524A81E40AE74007E62FA /* SLiMDocument.mm */; };\n\t\t989790DA1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t989790DB1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t989790DC1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t9898172F1A59750300F7417C /* slim_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9898172D1A59750300F7417C /* slim_globals.cpp */; };\n\t\t989A5BE92525304100E7192D /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t989A5BEA2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t989A5BEB2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t989A5BEC2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t989A5BED2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t98A240591B8E3295005C9A30 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A240581B8E3295005C9A30 /* Cocoa.framework */; };\n\t\t98A2405A1B8E32D0005C9A30 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A240581B8E3295005C9A30 /* Cocoa.framework */; };\n\t\t98A2405D1B8E338E005C9A30 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A2405C1B8E338E005C9A30 /* OpenGL.framework */; };\n\t\t98A2FF891D7DF4D7007E3DB8 /* Recipes in Resources */ = {isa = PBXBuildFile; fileRef = 98A2FF881D7DF4D7007E3DB8 /* Recipes */; };\n\t\t98A4EC941B67C1CD00CD92FD /* EidosConsoleWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */; };\n\t\t98A4EC951B67C1D900CD92FD /* EidosConsoleWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */; };\n\t\t98A5134F1B66B69E005A753D /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98A513501B66B69E005A753D /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98A513511B66B69E005A753D /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98A513541B66B6CA005A753D /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98A513551B66B6CA005A753D /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98A513561B66B6CA005A753D /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98AB597B1B2531F10077CB4A /* slim_eidos_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */; };\n\t\t98AB597C1B2531F10077CB4A /* slim_eidos_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */; };\n\t\t98AC617A24BA34ED0001914C /* species_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AC617924BA34ED0001914C /* species_eidos.cpp */; };\n\t\t98AC617B24BA34ED0001914C /* species_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AC617924BA34ED0001914C /* species_eidos.cpp */; };\n\t\t98ACDC9D253522B80038703F /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98ACDC9E253522B80038703F /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98ACDC9F253522B80038703F /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98ACDCA0253522B80038703F /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98ACDCA1253522B80038703F /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98C0943E1B7663DF00766A9A /* female_symbol.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98C0943C1B7663DF00766A9A /* female_symbol.pdf */; };\n\t\t98C0943F1B7663DF00766A9A /* male_symbol.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98C0943D1B7663DF00766A9A /* male_symbol.pdf */; };\n\t\t98C634442EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C634452EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C634462EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C634472EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C634482EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C634492EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C6344A2EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C6344B2EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C6344C2EF9F632003F12A3 /* dirichlet.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C634432EF9F632003F12A3 /* dirichlet.c */; };\n\t\t98C821241C7A980000548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98C821251C7A980000548839 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98C821261C7A980000548839 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98C821271C7A980000548839 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98C821281C7A980000548839 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98C821291C7A980000548839 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98C8212A1C7A980000548839 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98C8212B1C7A980000548839 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98C8212C1C7A980000548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98C8212D1C7A980000548839 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98C8212E1C7A980000548839 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98C8212F1C7A980000548839 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98C821301C7A980000548839 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98C821311C7A980000548839 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98C821321C7A980000548839 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98C821331C7A980000548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98C821341C7A980000548839 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98C821351C7A980000548839 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98C821361C7A980000548839 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98C821381C7A980000548839 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98C821391C7A980000548839 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98C8213A1C7A980000548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98C8213B1C7A980000548839 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98C8213C1C7A980000548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98C8213D1C7A980000548839 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98C8213E1C7A980000548839 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98C8213F1C7A980000548839 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98C821401C7A980000548839 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98C821411C7A980000548839 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98C821421C7A980000548839 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98C821431C7A983700548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98C821441C7A983700548839 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98C821451C7A983700548839 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98C821461C7A983700548839 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98C821471C7A983700548839 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98C821481C7A983700548839 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98C821491C7A983700548839 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98C8214A1C7A983700548839 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98C8214B1C7A983700548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98C8214C1C7A983700548839 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98C8214D1C7A983700548839 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98C8214E1C7A983700548839 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98C8214F1C7A983700548839 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98C821501C7A983700548839 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98C821511C7A983700548839 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98C821521C7A983700548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98C821531C7A983700548839 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98C821541C7A983700548839 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98C821551C7A983700548839 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98C821561C7A983700548839 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98C821571C7A983700548839 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98C821581C7A983700548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98C821591C7A983700548839 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98C8215A1C7A983700548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98C8215B1C7A983700548839 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98C8215C1C7A983700548839 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98C8215D1C7A983700548839 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98C8215E1C7A983700548839 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98C8215F1C7A983700548839 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98C821601C7A983700548839 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98C821611C7A983800548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98C821621C7A983800548839 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98C821631C7A983800548839 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98C821641C7A983800548839 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98C821651C7A983800548839 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98C821661C7A983800548839 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98C821671C7A983800548839 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98C821681C7A983800548839 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98C821691C7A983800548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98C8216A1C7A983800548839 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98C8216B1C7A983800548839 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98C8216C1C7A983800548839 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98C8216D1C7A983800548839 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98C8216E1C7A983800548839 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98C8216F1C7A983800548839 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98C821701C7A983800548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98C821711C7A983800548839 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98C821721C7A983800548839 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98C821731C7A983800548839 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98C821741C7A983800548839 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98C821751C7A983800548839 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98C821761C7A983800548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98C821771C7A983800548839 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98C821781C7A983800548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98C821791C7A983800548839 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98C8217A1C7A983800548839 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98C8217B1C7A983800548839 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98C8217C1C7A983800548839 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98C8217D1C7A983800548839 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98C8217E1C7A983800548839 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98C8217F1C7A983800548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98C821801C7A983800548839 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98C821811C7A983800548839 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98C821821C7A983800548839 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98C821831C7A983800548839 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98C821841C7A983800548839 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98C821851C7A983800548839 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98C821861C7A983800548839 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98C821871C7A983800548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98C821881C7A983800548839 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98C821891C7A983800548839 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98C8218A1C7A983800548839 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98C8218B1C7A983800548839 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98C8218C1C7A983800548839 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98C8218D1C7A983800548839 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98C8218E1C7A983800548839 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98C8218F1C7A983800548839 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98C821901C7A983800548839 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98C821911C7A983800548839 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98C821921C7A983800548839 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98C821931C7A983800548839 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98C821941C7A983800548839 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98C821951C7A983800548839 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98C821961C7A983800548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98C821971C7A983800548839 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98C821981C7A983800548839 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98C821991C7A983800548839 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98C8219A1C7A983800548839 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98C8219B1C7A983800548839 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98C8219C1C7A983800548839 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98C8219E1C7A99B200548839 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98C8219F1C7A99B200548839 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98C821A01C7A99B200548839 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98C821A11C7A99B200548839 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98C821A31C7A99F000548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98C821A41C7A99F000548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98C821A51C7A99F000548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98C821A61C7A99F000548839 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98C821A91C7A9B1600548839 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98C821AA1C7A9B1600548839 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98C821AB1C7A9B1600548839 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98C821AC1C7A9B1600548839 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98C821AD1C7A9B1600548839 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98C821AE1C7A9B1600548839 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98C821AF1C7A9B1600548839 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98C821B01C7A9B1600548839 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98C821B21C7A9B9F00548839 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98C821B31C7A9B9F00548839 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98C821B41C7A9B9F00548839 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98C821B51C7A9B9F00548839 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98C92AED1D0B07A6001C82BC /* individual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98C92AEB1D0B07A6001C82BC /* individual.cpp */; };\n\t\t98C92AEE1D0B07A6001C82BC /* individual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98C92AEB1D0B07A6001C82BC /* individual.cpp */; };\n\t\t98CEFCEC2AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCED2AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCEE2AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCEF2AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCF02AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCF12AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCF22AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCF32AAFABAA00D2C9B4 /* spline2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */; };\n\t\t98CEFCF42AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCF52AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCF62AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCF72AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCF82AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCF92AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCFA2AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFCFB2AAFABAA00D2C9B4 /* bilinear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */; };\n\t\t98CEFD102AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD112AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD122AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD132AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD142AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD152AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD162AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD172AAFABAA00D2C9B4 /* interp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDA2AAFABAA00D2C9B4 /* interp.c */; };\n\t\t98CEFD182AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD192AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1A2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1B2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1C2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1D2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1E2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD1F2AAFABAA00D2C9B4 /* bicubic.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */; };\n\t\t98CEFD202AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD212AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD222AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD232AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD242AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD252AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD262AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD272AAFABAA00D2C9B4 /* akima.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCDE2AAFABAA00D2C9B4 /* akima.c */; };\n\t\t98CEFD302AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD312AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD322AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD332AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD342AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD352AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD362AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD372AAFABAA00D2C9B4 /* spline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE22AAFABAA00D2C9B4 /* spline.c */; };\n\t\t98CEFD482AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD492AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4A2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4B2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4C2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4D2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4E2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD4F2AAFABAA00D2C9B4 /* interp2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */; };\n\t\t98CEFD502AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD512AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD522AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD532AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD542AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD552AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD562AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD572AAFABAA00D2C9B4 /* linear.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCE62AAFABAA00D2C9B4 /* linear.c */; };\n\t\t98CEFD642AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD652AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD662AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD672AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD682AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD692AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD6A2AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD6B2AAFABAA00D2C9B4 /* accel.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEA2AAFABAA00D2C9B4 /* accel.c */; };\n\t\t98CEFD6C2AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD6D2AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD6E2AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD6F2AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD702AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD712AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD722AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD732AAFABAA00D2C9B4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFCEB2AAFABAA00D2C9B4 /* inline.c */; };\n\t\t98CEFD752AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD762AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD772AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD782AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD792AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD7A2AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD7B2AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD7C2AAFB12F00D2C9B4 /* cspline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD742AAFB12F00D2C9B4 /* cspline.c */; };\n\t\t98CEFD7E2AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD7F2AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD802AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD812AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD822AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD832AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD842AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD852AAFB23E00D2C9B4 /* tridiag.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */; };\n\t\t98CEFD882AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD892AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8A2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8B2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8C2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8D2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8E2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CEFD8F2AAFB4F000D2C9B4 /* view.c in Sources */ = {isa = PBXBuildFile; fileRef = 98CEFD872AAFB4EF00D2C9B4 /* view.c */; };\n\t\t98CF264F1E42DBE200E392D8 /* slim.iconset in Resources */ = {isa = PBXBuildFile; fileRef = 98CF264E1E42DBE200E392D8 /* slim.iconset */; };\n\t\t98CF26521E4353FE00E392D8 /* SLiMDocumentController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98CF26511E4353FE00E392D8 /* SLiMDocumentController.mm */; };\n\t\t98CF51F5294A3FC900557BBA /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t98CF51F6294A3FC900557BBA /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98CF51F7294A3FC900557BBA /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t98CF51F8294A3FC900557BBA /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t98CF51F9294A3FC900557BBA /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98CF51FA294A3FC900557BBA /* slim_eidos_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */; };\n\t\t98CF51FB294A3FC900557BBA /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t98CF51FC294A3FC900557BBA /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98CF51FD294A3FC900557BBA /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t98CF51FE294A3FC900557BBA /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98CF51FF294A3FC900557BBA /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t98CF5200294A3FC900557BBA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C1BA1A6F537B00FFB083 /* main.m */; };\n\t\t98CF5201294A3FC900557BBA /* EidosValueWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98090FA51B1B978900791DBF /* EidosValueWrapper.mm */; };\n\t\t98CF5202294A3FC900557BBA /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98CF5203294A3FC900557BBA /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98CF5204294A3FC900557BBA /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98CF5205294A3FC900557BBA /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98CF5206294A3FC900557BBA /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25D2278B9F8001D43BC /* trees.c */; };\n\t\t98CF5207294A3FC900557BBA /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98CF5208294A3FC900557BBA /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t98CF5209294A3FC900557BBA /* GraphView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926D81AA140550000E138 /* GraphView.mm */; };\n\t\t98CF520A294A3FC900557BBA /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98CF520B294A3FC900557BBA /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98CF520C294A3FC900557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98CF520D294A3FC900557BBA /* interaction_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */; };\n\t\t98CF520E294A3FC900557BBA /* subpopulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */; };\n\t\t98CF520F294A3FC900557BBA /* community.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836867227CD40CF00683639 /* community.cpp */; };\n\t\t98CF5210294A3FC900557BBA /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t98CF5211294A3FC900557BBA /* EidosTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D218C41B2E213200156FC3 /* EidosTextView.mm */; };\n\t\t98CF5212294A3FC900557BBA /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98CF5213294A3FC900557BBA /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t98CF5214294A3FC900557BBA /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98CF5215294A3FC900557BBA /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98CF5216294A3FC900557BBA /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 9850D8DF2063098E006BFD2E /* tables.c */; };\n\t\t98CF5217294A3FC900557BBA /* species_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AC617924BA34ED0001914C /* species_eidos.cpp */; };\n\t\t98CF5218294A3FC900557BBA /* slim_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DDAED4221765480038C133 /* slim_functions.cpp */; };\n\t\t98CF5219294A3FC900557BBA /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t98CF521A294A3FC900557BBA /* FindRecipeController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 984252C2216FA9930019696A /* FindRecipeController.mm */; };\n\t\t98CF521B294A3FC900557BBA /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t98CF521C294A3FC900557BBA /* mutation_run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98606AEC1DED0DCD00821CFF /* mutation_run.cpp */; };\n\t\t98CF521D294A3FC900557BBA /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t98CF521E294A3FC900557BBA /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98CF521F294A3FC900557BBA /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t98CF5220294A3FC900557BBA /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98CF5221294A3FC900557BBA /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98CF5222294A3FC900557BBA /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98CF5223294A3FC900557BBA /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98CF5224294A3FC900557BBA /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t98CF5225294A3FC900557BBA /* slim_test_genetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */; };\n\t\t98CF5226294A3FC900557BBA /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98CF5227294A3FC900557BBA /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98CF5228294A3FC900557BBA /* genomic_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */; };\n\t\t98CF5229294A3FC900557BBA /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98CF522A294A3FC900557BBA /* substitution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69D1A3CD551000AD4FC /* substitution.cpp */; };\n\t\t98CF522B294A3FC900557BBA /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2562278B9F7001D43BC /* core.c */; };\n\t\t98CF522C294A3FC900557BBA /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t98CF522D294A3FC900557BBA /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98CF522E294A3FC900557BBA /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98CF522F294A3FC900557BBA /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t98CF5230294A3FC900557BBA /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t98CF5231294A3FC900557BBA /* EidosHelpController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 982556641BA450980054CB3F /* EidosHelpController.mm */; };\n\t\t98CF5232294A3FC900557BBA /* community_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836868027CD72E900683639 /* community_eidos.cpp */; };\n\t\t98CF5233294A3FC900557BBA /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98CF5234294A3FC900557BBA /* slim_test_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F724BA21E3008CC658 /* slim_test_other.cpp */; };\n\t\t98CF5235294A3FC900557BBA /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t98CF5236294A3FC900557BBA /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98CF5237294A3FC900557BBA /* GraphView_MutationLossTimeHistogram.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E11AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm */; };\n\t\t98CF5238294A3FC900557BBA /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98CF5239294A3FC900557BBA /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98CF523A294A3FC900557BBA /* individual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98C92AEB1D0B07A6001C82BC /* individual.cpp */; };\n\t\t98CF523B294A3FC900557BBA /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t98CF523C294A3FC900557BBA /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98CF523D294A3FC900557BBA /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t98CF523E294A3FC900557BBA /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98CF523F294A3FC900557BBA /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t98CF5240294A3FC900557BBA /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98CF5241294A3FC900557BBA /* CocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C21B1A718EFD00FFB083 /* CocoaExtra.mm */; };\n\t\t98CF5242294A3FC900557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98CF5243294A3FC900557BBA /* slim_test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F324BA21B7008CC658 /* slim_test_core.cpp */; };\n\t\t98CF5244294A3FC900557BBA /* EidosCocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */; };\n\t\t98CF5245294A3FC900557BBA /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98CF5246294A3FC900557BBA /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98CF5247294A3FC900557BBA /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t98CF5248294A3FC900557BBA /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t98CF5249294A3FC900557BBA /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t98CF524A294A3FC900557BBA /* SLiMPDFDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9887946A1EA8804900AE0C8D /* SLiMPDFDocument.mm */; };\n\t\t98CF524B294A3FC900557BBA /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t98CF524C294A3FC900557BBA /* log_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9809DF9E2550F32500C4E82D /* log_file.cpp */; };\n\t\t98CF524D294A3FC900557BBA /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t98CF524E294A3FC900557BBA /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98CF524F294A3FC900557BBA /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6AC1A3CD5D3000AD4FC /* population.cpp */; };\n\t\t98CF5250294A3FC900557BBA /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t98CF5251294A3FC900557BBA /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t98CF5252294A3FC900557BBA /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98CF5254294A3FC900557BBA /* GraphView_FitnessOverTime.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E71AA40AFF0000E138 /* GraphView_FitnessOverTime.mm */; };\n\t\t98CF5255294A3FC900557BBA /* SLiMWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2031A701D5A00FFB083 /* SLiMWindowController.mm */; };\n\t\t98CF5256294A3FC900557BBA /* PopulationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2061A704EA700FFB083 /* PopulationView.mm */; };\n\t\t98CF5257294A3FC900557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98CF5258294A3FC900557BBA /* GraphView_PopulationVisualization.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926EA1AA6B7480000E138 /* GraphView_PopulationVisualization.mm */; };\n\t\t98CF5259294A3FC900557BBA /* EidosPrettyprinter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */; };\n\t\t98CF525A294A3FC900557BBA /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98CF525B294A3FC900557BBA /* genomic_element_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */; };\n\t\t98CF525C294A3FC900557BBA /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C1B81A6F537B00FFB083 /* AppDelegate.mm */; };\n\t\t98CF525D294A3FC900557BBA /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98CF525E294A3FC900557BBA /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98CF525F294A3FC900557BBA /* slim_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98800DC21B7EDCB50046F5F9 /* slim_test.cpp */; };\n\t\t98CF5260294A3FC900557BBA /* sparse_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985D1D892808B84F00461CFA /* sparse_vector.cpp */; };\n\t\t98CF5261294A3FC900557BBA /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t98CF5262294A3FC900557BBA /* mutation_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */; };\n\t\t98CF5263294A3FC900557BBA /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2592278B9F8001D43BC /* convert.c */; };\n\t\t98CF5264294A3FC900557BBA /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t98CF5265294A3FC900557BBA /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t98CF5266294A3FC900557BBA /* polymorphism.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */; };\n\t\t98CF5267294A3FC900557BBA /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98CF5268294A3FC900557BBA /* species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9878A93D1A4E57E70007B9D6 /* species.cpp */; };\n\t\t98CF526A294A3FC900557BBA /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98CF526B294A3FC900557BBA /* text_input.c in Sources */ = {isa = PBXBuildFile; fileRef = D0A758F620A4CC9800132D2F /* text_input.c */; };\n\t\t98CF526C294A3FC900557BBA /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98CF526D294A3FC900557BBA /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t98CF526E294A3FC900557BBA /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t98CF526F294A3FC900557BBA /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t98CF5270294A3FC900557BBA /* ChromosomeView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2091A7086FF00FFB083 /* ChromosomeView.mm */; };\n\t\t98CF5272294A3FC900557BBA /* EidosConsoleTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724E61AD622880047C223 /* EidosConsoleTextView.mm */; };\n\t\t98CF5273294A3FC900557BBA /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t98CF5274294A3FC900557BBA /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98CF5275294A3FC900557BBA /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98CF5276294A3FC900557BBA /* SLiMPDFWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9887946D1EA8808000AE0C8D /* SLiMPDFWindowController.mm */; };\n\t\t98CF5277294A3FC900557BBA /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98CF5278294A3FC900557BBA /* GraphView_MutationFrequencyTrajectory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 980DD51C1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm */; };\n\t\t98CF5279294A3FC900557BBA /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98CF527A294A3FC900557BBA /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t98CF527B294A3FC900557BBA /* SLiMDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 989524A81E40AE74007E62FA /* SLiMDocument.mm */; };\n\t\t98CF527C294A3FC900557BBA /* EidosConsoleWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */; };\n\t\t98CF527D294A3FC900557BBA /* SLiMDocumentController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98CF26511E4353FE00E392D8 /* SLiMDocumentController.mm */; };\n\t\t98CF527E294A3FC900557BBA /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98CF527F294A3FC900557BBA /* GraphView_MutationFixationTimeHistogram.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926E41AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm */; };\n\t\t98CF5280294A3FC900557BBA /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t98CF5281294A3FC900557BBA /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98CF5282294A3FC900557BBA /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98CF5283294A3FC900557BBA /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t98CF5284294A3FC900557BBA /* kastore.c in Sources */ = {isa = PBXBuildFile; fileRef = 987D19A4209A53850030D28D /* kastore.c */; };\n\t\t98CF5285294A3FC900557BBA /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98CF5286294A3FC900557BBA /* chromosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6971A3CD52A000AD4FC /* chromosome.cpp */; };\n\t\t98CF5287294A3FC900557BBA /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t98CF5288294A3FC900557BBA /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98CF5289294A3FC900557BBA /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t98CF528A294A3FC900557BBA /* GraphView_MutationFrequencySpectra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 986926DE1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm */; };\n\t\t98CF528B294A3FC900557BBA /* genotypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2572278B9F7001D43BC /* genotypes.c */; };\n\t\t98CF528C294A3FC900557BBA /* SLiMPDFView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 988794721EA8C42200AE0C8D /* SLiMPDFView.mm */; };\n\t\t98CF528D294A3FC900557BBA /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t98CF528E294A3FC900557BBA /* haplosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */; };\n\t\t98CF528F294A3FC900557BBA /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25B2278B9F8001D43BC /* stats.c */; };\n\t\t98CF5290294A3FC900557BBA /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t98CF5291294A3FC900557BBA /* EidosVariableBrowserController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */; };\n\t\t98CF5292294A3FC900557BBA /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t98CF5293294A3FC900557BBA /* slim_gui.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98EBCD1221F3CFC600B385CF /* slim_gui.mm */; };\n\t\t98CF5294294A3FC900557BBA /* mutation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6881A3CCFD0000AD4FC /* mutation.cpp */; };\n\t\t98CF5295294A3FC900557BBA /* slim_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9898172D1A59750300F7417C /* slim_globals.cpp */; };\n\t\t98CF5296294A3FC900557BBA /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t98CF5297294A3FC900557BBA /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98CF5298294A3FC900557BBA /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98CF5299294A3FC900557BBA /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98CF529A294A3FC900557BBA /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t98CF529B294A3FC900557BBA /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98CF529C294A3FC900557BBA /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98CF529D294A3FC900557BBA /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98CF529E294A3FC900557BBA /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98CF529F294A3FC900557BBA /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98CF52A0294A3FC900557BBA /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98CF52A1294A3FC900557BBA /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t98CF52A3294A3FC900557BBA /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A2405C1B8E338E005C9A30 /* OpenGL.framework */; };\n\t\t98CF52A4294A3FC900557BBA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A240581B8E3295005C9A30 /* Cocoa.framework */; };\n\t\t98CF52A5294A3FC900557BBA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9821E2031ABDBC300036EAEA /* QuartzCore.framework */; };\n\t\t98CF52A6294A3FC900557BBA /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98D4C2151A7187E200FFB083 /* Quartz.framework */; };\n\t\t98CF52A7294A3FC900557BBA /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98D4C20F1A716E0E00FFB083 /* WebKit.framework */; };\n\t\t98CF52A9294A3FC900557BBA /* profile.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98EF4AB51ECDA5EA00CCDB09 /* profile.pdf */; };\n\t\t98CF52AA294A3FC900557BBA /* Recipes in Resources */ = {isa = PBXBuildFile; fileRef = 98A2FF881D7DF4D7007E3DB8 /* Recipes */; };\n\t\t98CF52AB294A3FC900557BBA /* play_step.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F31A70040400FFB083 /* play_step.pdf */; };\n\t\t98CF52AC294A3FC900557BBA /* FindRecipePanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98024740215D85880025D29C /* FindRecipePanel.xib */; };\n\t\t98CF52AD294A3FC900557BBA /* slim.iconset in Resources */ = {isa = PBXBuildFile; fileRef = 98CF264E1E42DBE200E392D8 /* slim.iconset */; };\n\t\t98CF52AE294A3FC900557BBA /* show_parse.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724ED1AD6D4060047C223 /* show_parse.pdf */; };\n\t\t98CF52AF294A3FC900557BBA /* open_type_drawer_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4C1A76004300C058CB /* open_type_drawer_H.pdf */; };\n\t\t98CF52B0294A3FC900557BBA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1BC1A6F537B00FFB083 /* Images.xcassets */; };\n\t\t98CF52B1294A3FC900557BBA /* recycle.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F71A70064800FFB083 /* recycle.pdf */; };\n\t\t98CF52B2294A3FC900557BBA /* check.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2241A71F8AD00FFB083 /* check.pdf */; };\n\t\t98CF52B3294A3FC900557BBA /* remove_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EC1A6FEAB500FFB083 /* remove_subpop.pdf */; };\n\t\t98CF52B4294A3FC900557BBA /* EidosHelpWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982556671BA451D00054CB3F /* EidosHelpWindow.xib */; };\n\t\t98CF52B5294A3FC900557BBA /* execute_selection.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E91AD6B9FE0047C223 /* execute_selection.pdf */; };\n\t\t98CF52B6294A3FC900557BBA /* profile_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98EF4AB41ECDA5EA00CCDB09 /* profile_H.pdf */; };\n\t\t98CF52B7294A3FC900557BBA /* dump_output.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F3F1A75A12700C058CB /* dump_output.pdf */; };\n\t\t98CF52B8294A3FC900557BBA /* show_mutations_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F521A76004300C058CB /* show_mutations_H.pdf */; };\n\t\t98CF52B9294A3FC900557BBA /* dump_output_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F3E1A75A12700C058CB /* dump_output_H.pdf */; };\n\t\t98CF52BA294A3FC900557BBA /* GraphBarRescaleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982A9DDC1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib */; };\n\t\t98CF52BB294A3FC900557BBA /* show_genomicelements_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F501A76004300C058CB /* show_genomicelements_H.pdf */; };\n\t\t98CF52BC294A3FC900557BBA /* SLiMHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566E1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf */; };\n\t\t98CF52BD294A3FC900557BBA /* edit_submenu.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F611A76041200C058CB /* edit_submenu.pdf */; };\n\t\t98CF52BE294A3FC900557BBA /* prettyprint_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */; };\n\t\t98CF52BF294A3FC900557BBA /* EidosHelpStatements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228301BAF496C00429674 /* EidosHelpStatements.rtf */; };\n\t\t98CF52C0294A3FC900557BBA /* change_sex_ratio.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E51A6FD8D600FFB083 /* change_sex_ratio.pdf */; };\n\t\t98CF52C1294A3FC900557BBA /* ProfileReport.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98EA965A1ECC2541006BA35B /* ProfileReport.xib */; };\n\t\t98CF52C2294A3FC900557BBA /* show_console_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 987AD8721B2CBDA70035D6C8 /* show_console_H.pdf */; };\n\t\t98CF52C3294A3FC900557BBA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1BE1A6F537B00FFB083 /* MainMenu.xib */; };\n\t\t98CF52C4294A3FC900557BBA /* show_execution.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F51AD6DD470047C223 /* show_execution.pdf */; };\n\t\t98CF52C5294A3FC900557BBA /* change_cloning_rate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985301EB1B72582E001520DF /* change_cloning_rate.pdf */; };\n\t\t98CF52C6294A3FC900557BBA /* female_symbol.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98C0943C1B7663DF00766A9A /* female_symbol.pdf */; };\n\t\t98CF52C7294A3FC900557BBA /* split_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EF1A6FED4000FFB083 /* split_subpop.pdf */; };\n\t\t98CF52C8294A3FC900557BBA /* show_recombination.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F551A76004300C058CB /* show_recombination.pdf */; };\n\t\t98CF52C9294A3FC900557BBA /* GraphWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 986926DA1AA1429D0000E138 /* GraphWindow.xib */; };\n\t\t98CF52CA294A3FC900557BBA /* GraphAxisRescaleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 980DD5181AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib */; };\n\t\t98CF52CB294A3FC900557BBA /* EidosHelpOperators.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282A1BAE279700429674 /* EidosHelpOperators.rtf */; };\n\t\t98CF52CC294A3FC900557BBA /* add_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EB1A6FEAB500FFB083 /* add_subpop.pdf */; };\n\t\t98CF52CE294A3FC900557BBA /* EidosHelpTypes.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */; };\n\t\t98CF52CF294A3FC900557BBA /* check_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2231A71F8AD00FFB083 /* check_H.pdf */; };\n\t\t98CF52D0294A3FC900557BBA /* show_execution_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F41AD6DD470047C223 /* show_execution_H.pdf */; };\n\t\t98CF52D1294A3FC900557BBA /* SLiMHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 982556A21BA5F0810054CB3F /* SLiMHelpClasses.rtf */; };\n\t\t98CF52D2294A3FC900557BBA /* show_fixed.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4F1A76004300C058CB /* show_fixed.pdf */; };\n\t\t98CF52D3294A3FC900557BBA /* syntax_help_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F421A75AABE00C058CB /* syntax_help_H.pdf */; };\n\t\t98CF52D4294A3FC900557BBA /* graph_submenu_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 986926D21AA1337A0000E138 /* graph_submenu_H.pdf */; };\n\t\t98CF52D5294A3FC900557BBA /* show_parse_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EC1AD6D4060047C223 /* show_parse_H.pdf */; };\n\t\t98CF52D6294A3FC900557BBA /* show_browser.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA11B1B8B5800791DBF /* show_browser.pdf */; };\n\t\t98CF52D7294A3FC900557BBA /* EidosConsoleWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */; };\n\t\t98CF52D8294A3FC900557BBA /* SLiMPDFWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9887946E1EA8808000AE0C8D /* SLiMPDFWindow.xib */; };\n\t\t98CF52D9294A3FC900557BBA /* prettyprint.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */; };\n\t\t98CF52DA294A3FC900557BBA /* syntax_help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F431A75AABE00C058CB /* syntax_help.pdf */; };\n\t\t98CF52DB294A3FC900557BBA /* change_selfing_ratio.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E71A6FDE6E00FFB083 /* change_selfing_ratio.pdf */; };\n\t\t98CF52DC294A3FC900557BBA /* change_folder.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98DD5F002155B857009062EE /* change_folder.pdf */; };\n\t\t98CF52DD294A3FC900557BBA /* open_type_drawer.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4D1A76004300C058CB /* open_type_drawer.pdf */; };\n\t\t98CF52DF294A3FC900557BBA /* EidosHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */; };\n\t\t98CF52E0294A3FC900557BBA /* show_tokens.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EF1AD6D4060047C223 /* show_tokens.pdf */; };\n\t\t98CF52E1294A3FC900557BBA /* edit_submenu_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F601A76041200C058CB /* edit_submenu_H.pdf */; };\n\t\t98CF52E2294A3FC900557BBA /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C20B1A715F6100FFB083 /* AboutWindow.xib */; };\n\t\t98CF52E3294A3FC900557BBA /* play_step_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FA1A700DC100FFB083 /* play_step_H.pdf */; };\n\t\t98CF52E4294A3FC900557BBA /* show_recombination_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F541A76004300C058CB /* show_recombination_H.pdf */; };\n\t\t98CF52E5294A3FC900557BBA /* EidosHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */; };\n\t\t98CF52E6294A3FC900557BBA /* male_symbol.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98C0943D1B7663DF00766A9A /* male_symbol.pdf */; };\n\t\t98CF52E7294A3FC900557BBA /* recycle_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FB1A700DC100FFB083 /* recycle_H.pdf */; };\n\t\t98CF52E8294A3FC900557BBA /* show_mutations.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F531A76004300C058CB /* show_mutations.pdf */; };\n\t\t98CF52E9294A3FC900557BBA /* execute_selection_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */; };\n\t\t98CF52EA294A3FC900557BBA /* change_folder_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98DD5F012155B857009062EE /* change_folder_H.pdf */; };\n\t\t98CF52EB294A3FC900557BBA /* play_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F91A700DC100FFB083 /* play_H.pdf */; };\n\t\t98CF52ED294A3FC900557BBA /* SLiMHelpCallbacks.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228331BAFB27300429674 /* SLiMHelpCallbacks.rtf */; };\n\t\t98CF52EE294A3FC900557BBA /* execute_script.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DF1AD4C3310047C223 /* execute_script.pdf */; };\n\t\t98CF52EF294A3FC900557BBA /* graph_submenu.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 986926D31AA1337A0000E138 /* graph_submenu.pdf */; };\n\t\t98CF52F0294A3FC900557BBA /* show_fixed_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F4E1A76004300C058CB /* show_fixed_H.pdf */; };\n\t\t98CF52F1294A3FC900557BBA /* execute_script_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DE1AD4C3310047C223 /* execute_script_H.pdf */; };\n\t\t98CF52F2294A3FC900557BBA /* SLiMWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FF1A70192A00FFB083 /* SLiMWindow.xib */; };\n\t\t98CF52F3294A3FC900557BBA /* show_browser_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA01B1B8B5800791DBF /* show_browser_H.pdf */; };\n\t\t98CF52F4294A3FC900557BBA /* play.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F41A70040400FFB083 /* play.pdf */; };\n\t\t98CF52F5294A3FC900557BBA /* change_migration.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F11A6FEEAB00FFB083 /* change_migration.pdf */; };\n\t\t98CF52F6294A3FC900557BBA /* show_console.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 987AD8731B2CBDA70035D6C8 /* show_console.pdf */; };\n\t\t98CF52F7294A3FC900557BBA /* show_tokens_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EE1AD6D4060047C223 /* show_tokens_H.pdf */; };\n\t\t98CF52F8294A3FC900557BBA /* delete.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2261A71F8AD00FFB083 /* delete.pdf */; };\n\t\t98CF52F9294A3FC900557BBA /* delete_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2251A71F8AD00FFB083 /* delete_H.pdf */; };\n\t\t98CF52FA294A3FC900557BBA /* Tips in Resources */ = {isa = PBXBuildFile; fileRef = 98F65D551DF14DA40058BD29 /* Tips */; };\n\t\t98CF52FB294A3FC900557BBA /* change_size.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E91A6FE7FC00FFB083 /* change_size.pdf */; };\n\t\t98CF52FC294A3FC900557BBA /* show_genomicelements.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F511A76004300C058CB /* show_genomicelements.pdf */; };\n\t\t98CF533B294A4B5300557BBA /* libomp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 98760EDC28CE5E7600CEBC40 /* libomp.dylib */; };\n\t\t98CF5399294A714200557BBA /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98CF539A294A714200557BBA /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98CF539B294A714200557BBA /* eidos_functions_matrices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */; };\n\t\t98CF539C294A714200557BBA /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t98CF539D294A714200557BBA /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98CF539E294A714200557BBA /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t98CF539F294A714200557BBA /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98CF53A0294A714200557BBA /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98CF53A1294A714200557BBA /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98CF53A2294A714200557BBA /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t98CF53A3294A714200557BBA /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t98CF53A4294A714200557BBA /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98CF53A5294A714200557BBA /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98CF53A6294A714200557BBA /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98CF53A7294A714200557BBA /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t98CF53A8294A714200557BBA /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t98CF53A9294A714200557BBA /* eidos_functions_stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */; };\n\t\t98CF53AA294A714200557BBA /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98CF53AB294A714200557BBA /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98CF53AC294A714200557BBA /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98CF53AD294A714200557BBA /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t98CF53AE294A714200557BBA /* eidos_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */; };\n\t\t98CF53AF294A714200557BBA /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98CF53B0294A714200557BBA /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t98CF53B1294A714200557BBA /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98CF53B2294A714200557BBA /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98CF53B3294A714200557BBA /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t98CF53B4294A714200557BBA /* eidos_functions_strings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */; };\n\t\t98CF53B5294A714200557BBA /* eidos_functions_colors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */; };\n\t\t98CF53B6294A714200557BBA /* eidos_functions_files.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */; };\n\t\t98CF53B7294A714200557BBA /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t98CF53B8294A714200557BBA /* EidosCocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */; };\n\t\t98CF53B9294A714200557BBA /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98CF53BA294A714200557BBA /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98CF53BB294A714200557BBA /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98CF53BC294A714200557BBA /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t98CF53BD294A714200557BBA /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98CF53BE294A714200557BBA /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98CF53BF294A714200557BBA /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98CF53C0294A714200557BBA /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98CF53C1294A714200557BBA /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98CF53C2294A714200557BBA /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98CF53C3294A714200557BBA /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t98CF53C4294A714200557BBA /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t98CF53C5294A714200557BBA /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98CF53C6294A714200557BBA /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98CF53C7294A714200557BBA /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98CF53C8294A714200557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98CF53C9294A714200557BBA /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98CF53CA294A714200557BBA /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98CF53CB294A714200557BBA /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98CF53CC294A714200557BBA /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98CF53CD294A714200557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98CF53CE294A714200557BBA /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98CF53CF294A714200557BBA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 985724B61AD478630047C223 /* main.m */; };\n\t\t98CF53D0294A714200557BBA /* eidos_functions_values.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */; };\n\t\t98CF53D1294A714200557BBA /* EidosValueWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98090FA51B1B978900791DBF /* EidosValueWrapper.mm */; };\n\t\t98CF53D2294A714200557BBA /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98CF53D3294A714200557BBA /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t98CF53D4294A714200557BBA /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98CF53D5294A714200557BBA /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98CF53D6294A714200557BBA /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98CF53D7294A714200557BBA /* EidosTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D218C41B2E213200156FC3 /* EidosTextView.mm */; };\n\t\t98CF53D8294A714200557BBA /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98CF53D9294A714200557BBA /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98CF53DA294A714200557BBA /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98CF53DB294A714200557BBA /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98CF53DC294A714200557BBA /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t98CF53DD294A714200557BBA /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98CF53DE294A714200557BBA /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98CF53DF294A714200557BBA /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98CF53E0294A714200557BBA /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98CF53E1294A714200557BBA /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t98CF53E2294A714200557BBA /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98CF53E3294A714200557BBA /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t98CF53E4294A714200557BBA /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t98CF53E5294A714200557BBA /* eidos_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */; };\n\t\t98CF53E6294A714200557BBA /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t98CF53E7294A714200557BBA /* EidosHelpController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 982556641BA450980054CB3F /* EidosHelpController.mm */; };\n\t\t98CF53E8294A714200557BBA /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98CF53E9294A714200557BBA /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t98CF53EA294A714200557BBA /* EidosVariableBrowserController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */; };\n\t\t98CF53EB294A714200557BBA /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t98CF53EC294A714200557BBA /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98CF53ED294A714200557BBA /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t98CF53EE294A714200557BBA /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98CF53EF294A714200557BBA /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t98CF53F0294A714200557BBA /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98CF53F1294A714200557BBA /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98CF53F2294A714200557BBA /* EidosAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724B41AD478630047C223 /* EidosAppDelegate.mm */; };\n\t\t98CF53F3294A714200557BBA /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t98CF53F4294A714200557BBA /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98CF53F5294A714200557BBA /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t98CF53F6294A714200557BBA /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98CF53F7294A714200557BBA /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t98CF53F8294A714200557BBA /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98CF53F9294A714200557BBA /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t98CF53FA294A714200557BBA /* EidosConsoleTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 985724E61AD622880047C223 /* EidosConsoleTextView.mm */; };\n\t\t98CF53FB294A714200557BBA /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t98CF53FC294A714200557BBA /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t98CF53FD294A714200557BBA /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t98CF53FE294A714200557BBA /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98CF53FF294A714200557BBA /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98CF5400294A714200557BBA /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t98CF5401294A714200557BBA /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t98CF5402294A714200557BBA /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t98CF5403294A714200557BBA /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t98CF5404294A714200557BBA /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t98CF5405294A714200557BBA /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98CF5406294A714200557BBA /* EidosConsoleWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */; };\n\t\t98CF5407294A714200557BBA /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t98CF5408294A714200557BBA /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98CF5409294A714200557BBA /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98CF540A294A714200557BBA /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98CF540B294A714200557BBA /* EidosPrettyprinter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */; };\n\t\t98CF540C294A714200557BBA /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t98CF540D294A714200557BBA /* eidos_functions_distributions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */; };\n\t\t98CF540E294A714200557BBA /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98CF5410294A714200557BBA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A240581B8E3295005C9A30 /* Cocoa.framework */; };\n\t\t98CF5412294A714200557BBA /* show_parse_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EC1AD6D4060047C223 /* show_parse_H.pdf */; };\n\t\t98CF5413294A714200557BBA /* show_parse.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724ED1AD6D4060047C223 /* show_parse.pdf */; };\n\t\t98CF5414294A714200557BBA /* execute_script.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DF1AD4C3310047C223 /* execute_script.pdf */; };\n\t\t98CF5415294A714200557BBA /* check_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2231A71F8AD00FFB083 /* check_H.pdf */; };\n\t\t98CF5416294A714200557BBA /* EidosHelpOperators.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282A1BAE279700429674 /* EidosHelpOperators.rtf */; };\n\t\t98CF5417294A714200557BBA /* execute_script_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724DE1AD4C3310047C223 /* execute_script_H.pdf */; };\n\t\t98CF5418294A714200557BBA /* EidosHelpStatements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 989228301BAF496C00429674 /* EidosHelpStatements.rtf */; };\n\t\t98CF5419294A714200557BBA /* EidosHelpFunctions.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */; };\n\t\t98CF541A294A714200557BBA /* EidosHelpTypes.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */; };\n\t\t98CF541B294A714200557BBA /* prettyprint_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */; };\n\t\t98CF541C294A714200557BBA /* EidosHelpClasses.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */; };\n\t\t98CF541D294A714200557BBA /* show_browser_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA01B1B8B5800791DBF /* show_browser_H.pdf */; };\n\t\t98CF541E294A714200557BBA /* EidosHelpWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 982556671BA451D00054CB3F /* EidosHelpWindow.xib */; };\n\t\t98CF541F294A714200557BBA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 985724B81AD478630047C223 /* Images.xcassets */; };\n\t\t98CF5420294A714200557BBA /* show_execution.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F51AD6DD470047C223 /* show_execution.pdf */; };\n\t\t98CF5421294A714200557BBA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 985724BA1AD478630047C223 /* MainMenu.xib */; };\n\t\t98CF5422294A714200557BBA /* syntax_help_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F421A75AABE00C058CB /* syntax_help_H.pdf */; };\n\t\t98CF5423294A714200557BBA /* EidosAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98EFE6321ADD92BC00CBEC78 /* EidosAboutWindow.xib */; };\n\t\t98CF5424294A714200557BBA /* delete.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2261A71F8AD00FFB083 /* delete.pdf */; };\n\t\t98CF5425294A714200557BBA /* delete_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2251A71F8AD00FFB083 /* delete_H.pdf */; };\n\t\t98CF5426294A714200557BBA /* syntax_help.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98453F431A75AABE00C058CB /* syntax_help.pdf */; };\n\t\t98CF5427294A714200557BBA /* show_tokens.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EF1AD6D4060047C223 /* show_tokens.pdf */; };\n\t\t98CF5428294A714200557BBA /* EidosConsoleWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */; };\n\t\t98CF5429294A714200557BBA /* check.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2241A71F8AD00FFB083 /* check.pdf */; };\n\t\t98CF542A294A714200557BBA /* prettyprint.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */; };\n\t\t98CF542B294A714200557BBA /* execute_selection.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E91AD6B9FE0047C223 /* execute_selection.pdf */; };\n\t\t98CF542C294A714200557BBA /* show_tokens_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724EE1AD6D4060047C223 /* show_tokens_H.pdf */; };\n\t\t98CF542D294A714200557BBA /* execute_selection_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */; };\n\t\t98CF542E294A714200557BBA /* show_execution_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 985724F41AD6DD470047C223 /* show_execution_H.pdf */; };\n\t\t98CF542F294A714200557BBA /* show_browser.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98090FA11B1B8B5800791DBF /* show_browser.pdf */; };\n\t\t98D218C51B2E213200156FC3 /* EidosTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D218C41B2E213200156FC3 /* EidosTextView.mm */; };\n\t\t98D218C61B2E213200156FC3 /* EidosTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D218C41B2E213200156FC3 /* EidosTextView.mm */; };\n\t\t98D4C1B91A6F537B00FFB083 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C1B81A6F537B00FFB083 /* AppDelegate.mm */; };\n\t\t98D4C1BB1A6F537B00FFB083 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C1BA1A6F537B00FFB083 /* main.m */; };\n\t\t98D4C1BD1A6F537B00FFB083 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1BC1A6F537B00FFB083 /* Images.xcassets */; };\n\t\t98D4C1C01A6F537B00FFB083 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1BE1A6F537B00FFB083 /* MainMenu.xib */; };\n\t\t98D4C1D31A6F541200FFB083 /* slim_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9898172D1A59750300F7417C /* slim_globals.cpp */; };\n\t\t98D4C1D41A6F541700FFB083 /* species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9878A93D1A4E57E70007B9D6 /* species.cpp */; };\n\t\t98D4C1D61A6F541F00FFB083 /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98D4C1D81A6F542600FFB083 /* mutation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6881A3CCFD0000AD4FC /* mutation.cpp */; };\n\t\t98D4C1D91A6F542900FFB083 /* mutation_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */; };\n\t\t98D4C1DB1A6F542F00FFB083 /* genomic_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */; };\n\t\t98D4C1DC1A6F543200FFB083 /* genomic_element_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */; };\n\t\t98D4C1DD1A6F543600FFB083 /* chromosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6971A3CD52A000AD4FC /* chromosome.cpp */; };\n\t\t98D4C1DE1A6F543900FFB083 /* polymorphism.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */; };\n\t\t98D4C1DF1A6F543C00FFB083 /* substitution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69D1A3CD551000AD4FC /* substitution.cpp */; };\n\t\t98D4C1E11A6F544500FFB083 /* haplosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */; };\n\t\t98D4C1E21A6F544800FFB083 /* subpopulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */; };\n\t\t98D4C1E31A6F544B00FFB083 /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6AC1A3CD5D3000AD4FC /* population.cpp */; };\n\t\t98D4C1E61A6FD8D600FFB083 /* change_sex_ratio.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E51A6FD8D600FFB083 /* change_sex_ratio.pdf */; };\n\t\t98D4C1E81A6FDE6E00FFB083 /* change_selfing_ratio.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E71A6FDE6E00FFB083 /* change_selfing_ratio.pdf */; };\n\t\t98D4C1EA1A6FE7FC00FFB083 /* change_size.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1E91A6FE7FC00FFB083 /* change_size.pdf */; };\n\t\t98D4C1ED1A6FEAB500FFB083 /* add_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EB1A6FEAB500FFB083 /* add_subpop.pdf */; };\n\t\t98D4C1EE1A6FEAB500FFB083 /* remove_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EC1A6FEAB500FFB083 /* remove_subpop.pdf */; };\n\t\t98D4C1F01A6FED4000FFB083 /* split_subpop.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1EF1A6FED4000FFB083 /* split_subpop.pdf */; };\n\t\t98D4C1F21A6FEEAB00FFB083 /* change_migration.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F11A6FEEAB00FFB083 /* change_migration.pdf */; };\n\t\t98D4C1F51A70040400FFB083 /* play_step.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F31A70040400FFB083 /* play_step.pdf */; };\n\t\t98D4C1F61A70040400FFB083 /* play.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F41A70040400FFB083 /* play.pdf */; };\n\t\t98D4C1F81A70064800FFB083 /* recycle.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F71A70064800FFB083 /* recycle.pdf */; };\n\t\t98D4C1FC1A700DC100FFB083 /* play_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1F91A700DC100FFB083 /* play_H.pdf */; };\n\t\t98D4C1FD1A700DC100FFB083 /* play_step_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FA1A700DC100FFB083 /* play_step_H.pdf */; };\n\t\t98D4C1FE1A700DC100FFB083 /* recycle_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FB1A700DC100FFB083 /* recycle_H.pdf */; };\n\t\t98D4C2011A70192A00FFB083 /* SLiMWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C1FF1A70192A00FFB083 /* SLiMWindow.xib */; };\n\t\t98D4C2041A701D5A00FFB083 /* SLiMWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2031A701D5A00FFB083 /* SLiMWindowController.mm */; };\n\t\t98D4C2071A704EA700FFB083 /* PopulationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2061A704EA700FFB083 /* PopulationView.mm */; };\n\t\t98D4C20A1A7086FF00FFB083 /* ChromosomeView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C2091A7086FF00FFB083 /* ChromosomeView.mm */; };\n\t\t98D4C20D1A715F6100FFB083 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C20B1A715F6100FFB083 /* AboutWindow.xib */; };\n\t\t98D4C2101A716E0E00FFB083 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98D4C20F1A716E0E00FFB083 /* WebKit.framework */; };\n\t\t98D4C2161A7187E200FFB083 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98D4C2151A7187E200FFB083 /* Quartz.framework */; };\n\t\t98D4C21C1A718EFD00FFB083 /* CocoaExtra.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D4C21B1A718EFD00FFB083 /* CocoaExtra.mm */; };\n\t\t98D4C2271A71F8AD00FFB083 /* check_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2231A71F8AD00FFB083 /* check_H.pdf */; };\n\t\t98D4C2281A71F8AD00FFB083 /* check.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2241A71F8AD00FFB083 /* check.pdf */; };\n\t\t98D4C2291A71F8AD00FFB083 /* delete_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2251A71F8AD00FFB083 /* delete_H.pdf */; };\n\t\t98D4C22A1A71F8AD00FFB083 /* delete.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D4C2261A71F8AD00FFB083 /* delete.pdf */; };\n\t\t98D524631F2E6AFB005AD9A6 /* prettyprint_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */; };\n\t\t98D524641F2E6AFB005AD9A6 /* prettyprint.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */; };\n\t\t98D524651F2E6B08005AD9A6 /* prettyprint_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */; };\n\t\t98D524661F2E6B0B005AD9A6 /* prettyprint.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */; };\n\t\t98D524691F2EB4DD005AD9A6 /* EidosPrettyprinter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */; };\n\t\t98D5246A1F2EB4DD005AD9A6 /* EidosPrettyprinter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */; };\n\t\t98D7D65C2AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D65D2AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D65E2AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D65F2AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D6602AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D6612AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D6622AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D6632AB24C40002AFE34 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D65B2AB24C40002AFE34 /* tdist.c */; };\n\t\t98D7D6652AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D6662AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D6672AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D6682AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D6692AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D66A2AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D66B2AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7D66C2AB24CBC002AFE34 /* chisq.c in Sources */ = {isa = PBXBuildFile; fileRef = 98D7D6642AB24CBC002AFE34 /* chisq.c */; };\n\t\t98D7EB8528CE557C00DEAAC4 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98D7EB8628CE557C00DEAAC4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98D7EB8728CE557C00DEAAC4 /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t98D7EB8828CE557C00DEAAC4 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98D7EB8928CE557C00DEAAC4 /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98D7EB8A28CE557C00DEAAC4 /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98D7EB8B28CE557C00DEAAC4 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98D7EB8C28CE557C00DEAAC4 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98D7EB8D28CE557C00DEAAC4 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98D7EB8E28CE557C00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98D7EB8F28CE557C00DEAAC4 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98D7EB9028CE557C00DEAAC4 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98D7EB9128CE557C00DEAAC4 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98D7EB9228CE557C00DEAAC4 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t98D7EB9328CE557C00DEAAC4 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t98D7EB9428CE557C00DEAAC4 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98D7EB9528CE557C00DEAAC4 /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t98D7EB9628CE557C00DEAAC4 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98D7EB9728CE557C00DEAAC4 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t98D7EB9828CE557C00DEAAC4 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98D7EB9928CE557C00DEAAC4 /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t98D7EB9A28CE557C00DEAAC4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t98D7EB9B28CE557C00DEAAC4 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98D7EB9C28CE557C00DEAAC4 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t98D7EB9D28CE557C00DEAAC4 /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98D7EB9E28CE557C00DEAAC4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98D7EB9F28CE557C00DEAAC4 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98D7EBA028CE557C00DEAAC4 /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98D7EBA128CE557C00DEAAC4 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t98D7EBA228CE557C00DEAAC4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t98D7EBA328CE557C00DEAAC4 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t98D7EBA428CE557C00DEAAC4 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98D7EBA528CE557C00DEAAC4 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98D7EBA628CE557C00DEAAC4 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98D7EBA728CE557C00DEAAC4 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t98D7EBA828CE557C00DEAAC4 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98D7EBA928CE557C00DEAAC4 /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t98D7EBAA28CE557C00DEAAC4 /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t98D7EBAB28CE557C00DEAAC4 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98D7EBAC28CE557C00DEAAC4 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98D7EBAD28CE557C00DEAAC4 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98D7EBAE28CE557C00DEAAC4 /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98D7EBAF28CE557C00DEAAC4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98D7EBB028CE557C00DEAAC4 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t98D7EBB128CE557C00DEAAC4 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98D7EBB228CE557C00DEAAC4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98D7EBB328CE557C00DEAAC4 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98D7EBB428CE557C00DEAAC4 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t98D7EBB528CE557C00DEAAC4 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98D7EBB628CE557C00DEAAC4 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t98D7EBB728CE557C00DEAAC4 /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t98D7EBB828CE557C00DEAAC4 /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98D7EBB928CE557C00DEAAC4 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98D7EBBA28CE557C00DEAAC4 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98D7EBBB28CE557C00DEAAC4 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98D7EBBC28CE557C00DEAAC4 /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t98D7EBBD28CE557C00DEAAC4 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98D7EBBE28CE557C00DEAAC4 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t98D7EBBF28CE557C00DEAAC4 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t98D7EBC028CE557C00DEAAC4 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t98D7EBC128CE557C00DEAAC4 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98D7EBC228CE557C00DEAAC4 /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t98D7EBC328CE557C00DEAAC4 /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t98D7EBC428CE557C00DEAAC4 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t98D7EBC528CE557C00DEAAC4 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98D7EBC628CE557C00DEAAC4 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98D7EBC728CE557C00DEAAC4 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98D7EBC828CE557C00DEAAC4 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98D7EBC928CE557C00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98D7EBCA28CE557C00DEAAC4 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98D7EBCB28CE557C00DEAAC4 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98D7EBCC28CE557C00DEAAC4 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98D7EBCD28CE557C00DEAAC4 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t98D7EBCE28CE557C00DEAAC4 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t98D7EBCF28CE557C00DEAAC4 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t98D7EBD028CE557C00DEAAC4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t98D7EBD128CE557C00DEAAC4 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98D7EBD228CE557C00DEAAC4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t98D7EBD328CE557C00DEAAC4 /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t98D7EBD428CE557C00DEAAC4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98D7EBD528CE557C00DEAAC4 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98D7EBD628CE557C00DEAAC4 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98D7EBD728CE557C00DEAAC4 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98D7EBD828CE557C00DEAAC4 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98D7EBD928CE557C00DEAAC4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t98D7EBDA28CE557C00DEAAC4 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98D7EBDB28CE557C00DEAAC4 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 982556AB1BA8E77C0054CB3F /* main.cpp */; };\n\t\t98D7EBDC28CE557C00DEAAC4 /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t98D7EBDD28CE557C00DEAAC4 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t98D7EBDE28CE557C00DEAAC4 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98D7EBDF28CE557C00DEAAC4 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98D7EBE028CE557C00DEAAC4 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t98D7EBE128CE557C00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98D7EBE228CE557C00DEAAC4 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98D7EBE328CE557C00DEAAC4 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98D7EBE428CE557C00DEAAC4 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t98D7EBE528CE557C00DEAAC4 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t98D7EBE628CE557C00DEAAC4 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98D7EBE728CE557C00DEAAC4 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98D7EBE828CE557C00DEAAC4 /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98D7ECA128CE58FC00DEAAC4 /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98D7ECA228CE58FC00DEAAC4 /* eidos_type_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */; };\n\t\t98D7ECA328CE58FC00DEAAC4 /* eidos_call_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */; };\n\t\t98D7ECA428CE58FC00DEAAC4 /* dgemv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ADB1FDBC0D000274FF0 /* dgemv.c */; };\n\t\t98D7ECA528CE58FC00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B0F1FDBD09800274FF0 /* init.c */; };\n\t\t98D7ECA628CE58FC00DEAAC4 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FA1C7A980000548839 /* gamma.c */; };\n\t\t98D7ECA728CE58FC00DEAAC4 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FB1C7A980000548839 /* gauss.c */; };\n\t\t98D7ECA828CE58FC00DEAAC4 /* eidos_test_operators_arithmetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */; };\n\t\t98D7ECA928CE58FC00DEAAC4 /* eidos_test_functions_statistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */; };\n\t\t98D7ECAA28CE58FC00DEAAC4 /* log.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211A1C7A980000548839 /* log.c */; };\n\t\t98D7ECAB28CE58FC00DEAAC4 /* slim_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98800DC21B7EDCB50046F5F9 /* slim_test.cpp */; };\n\t\t98D7ECAC28CE58FC00DEAAC4 /* expint.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E60C1ED55C0400FF9762 /* expint.c */; };\n\t\t98D7ECAD28CE58FC00DEAAC4 /* elementary.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210C1C7A980000548839 /* elementary.c */; };\n\t\t98D7ECAE28CE58FC00DEAAC4 /* mvgauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332A9D1FDB98ED00274FF0 /* mvgauss.c */; };\n\t\t98D7ECAF28CE58FC00DEAAC4 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B161FDBD13D00274FF0 /* copy.c */; };\n\t\t98D7ECB028CE58FC00DEAAC4 /* eidos_class_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235688252FE61A0096A745 /* eidos_class_Image.cpp */; };\n\t\t98D7ECB128CE58FC00DEAAC4 /* shuffle.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821B11C7A9B9F00548839 /* shuffle.c */; };\n\t\t98D7ECB228CE58FC00DEAAC4 /* stats.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25B2278B9F8001D43BC /* stats.c */; };\n\t\t98D7ECB328CE58FC00DEAAC4 /* mutation_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */; };\n\t\t98D7ECB428CE58FC00DEAAC4 /* mutation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6881A3CCFD0000AD4FC /* mutation.cpp */; };\n\t\t98D7ECB528CE58FC00DEAAC4 /* coerce.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821201C7A980000548839 /* coerce.c */; };\n\t\t98D7ECB628CE58FC00DEAAC4 /* dtrmv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB81FDBA32200274FF0 /* dtrmv.c */; };\n\t\t98D7ECB728CE58FC00DEAAC4 /* gamma_inc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6001ED55A2500FF9762 /* gamma_inc.c */; };\n\t\t98D7ECB828CE58FC00DEAAC4 /* slim_test_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F724BA21E3008CC658 /* slim_test_other.cpp */; };\n\t\t98D7ECB928CE58FC00DEAAC4 /* vector.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC61FDBA6B600274FF0 /* vector.c */; };\n\t\t98D7ECBA28CE58FC00DEAAC4 /* eidos_script.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */; };\n\t\t98D7ECBB28CE58FC00DEAAC4 /* gaussinv.c in Sources */ = {isa = PBXBuildFile; fileRef = 987A2A0524033856009A636F /* gaussinv.c */; };\n\t\t98D7ECBC28CE58FC00DEAAC4 /* erfc.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6071ED55B4700FF9762 /* erfc.c */; };\n\t\t98D7ECBD28CE58FC00DEAAC4 /* gausszig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FC1C7A980000548839 /* gausszig.c */; };\n\t\t98D7ECBE28CE58FC00DEAAC4 /* community_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836868027CD72E900683639 /* community_eidos.cpp */; };\n\t\t98D7ECBF28CE58FC00DEAAC4 /* ddot.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824ED210B9E8F002402A5 /* ddot.c */; };\n\t\t98D7ECC028CE58FC00DEAAC4 /* species.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9878A93D1A4E57E70007B9D6 /* species.cpp */; };\n\t\t98D7ECC128CE58FC00DEAAC4 /* eidos_beep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */; };\n\t\t98D7ECC228CE58FC00DEAAC4 /* fdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 980566E125A7C5B9008D3C7F /* fdist.c */; };\n\t\t98D7ECC328CE58FC00DEAAC4 /* matrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AFB1FDBC4B200274FF0 /* matrix.c */; };\n\t\t98D7ECC428CE58FC00DEAAC4 /* submatrix.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE51FDBC1D900274FF0 /* submatrix.c */; };\n\t\t98D7ECC528CE58FC00DEAAC4 /* psi.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211C1C7A980000548839 /* psi.c */; };\n\t\t98D7ECC628CE58FC00DEAAC4 /* binomial_tpe.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F81C7A980000548839 /* binomial_tpe.c */; };\n\t\t98D7ECC728CE58FC00DEAAC4 /* eidos_test_functions_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */; };\n\t\t98D7ECC828CE58FC00DEAAC4 /* haplosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */; };\n\t\t98D7ECC928CE58FC00DEAAC4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076609244934A800F6CBB4 /* zutil.c */; };\n\t\t98D7ECCA28CE58FC00DEAAC4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D25D2278B9F8001D43BC /* trees.c */; };\n\t\t98D7ECCB28CE58FC00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B011FDBCFC300274FF0 /* init.c */; };\n\t\t98D7ECCC28CE58FC00DEAAC4 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EC1C7A980000548839 /* stream.c */; };\n\t\t98D7ECCD28CE58FC00DEAAC4 /* slim_test_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9807C0F324BA21B7008CC658 /* slim_test_core.cpp */; };\n\t\t98D7ECCE28CE58FC00DEAAC4 /* eidos_ast_node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A513521B66B6CA005A753D /* eidos_ast_node.cpp */; };\n\t\t98D7ECCF28CE58FC00DEAAC4 /* chromosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6971A3CD52A000AD4FC /* chromosome.cpp */; };\n\t\t98D7ECD028CE58FC00DEAAC4 /* eidos_test_functions_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */; };\n\t\t98D7ECD128CE58FC00DEAAC4 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E91C7A980000548839 /* error.c */; };\n\t\t98D7ECD228CE58FC00DEAAC4 /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 9850D8DF2063098E006BFD2E /* tables.c */; };\n\t\t98D7ECD328CE58FC00DEAAC4 /* slim_eidos_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */; };\n\t\t98D7ECD428CE58FC00DEAAC4 /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2592278B9F8001D43BC /* convert.c */; };\n\t\t98D7ECD528CE58FC00DEAAC4 /* eidos_test_operators_other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */; };\n\t\t98D7ECD628CE58FC00DEAAC4 /* eidos_test_functions_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */; };\n\t\t98D7ECD728CE58FC00DEAAC4 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076605244934A800F6CBB4 /* deflate.c */; };\n\t\t98D7ECD828CE58FC00DEAAC4 /* gamma.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821101C7A980000548839 /* gamma.c */; };\n\t\t98D7ECD928CE58FC00DEAAC4 /* nbinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 982B50C52704048E006E91BC /* nbinomial.c */; };\n\t\t98D7ECDA28CE58FC00DEAAC4 /* poisson.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821001C7A980000548839 /* poisson.c */; };\n\t\t98D7ECDB28CE58FC00DEAAC4 /* sparse_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985D1D892808B84F00461CFA /* sparse_vector.cpp */; };\n\t\t98D7ECDC28CE58FC00DEAAC4 /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6AC1A3CD5D3000AD4FC /* population.cpp */; };\n\t\t98D7ECDD28CE58FC00DEAAC4 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E6111ED55C6B00FF9762 /* beta.c */; };\n\t\t98D7ECDE28CE58FC00DEAAC4 /* rowcol.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AE31FDBC1D900274FF0 /* rowcol.c */; };\n\t\t98D7ECDF28CE58FC00DEAAC4 /* taus.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821071C7A980000548839 /* taus.c */; };\n\t\t98D7ECE028CE58FC00DEAAC4 /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98D7ECE128CE58FC00DEAAC4 /* geometric.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A81C7A9B1600548839 /* geometric.c */; };\n\t\t98D7ECE228CE58FC00DEAAC4 /* eidos_token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98A5134D1B66B69E005A753D /* eidos_token.cpp */; };\n\t\t98D7ECE328CE58FC00DEAAC4 /* core.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2562278B9F7001D43BC /* core.c */; };\n\t\t98D7ECE428CE58FC00DEAAC4 /* minmax.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8219D1C7A99B200548839 /* minmax.c */; };\n\t\t98D7ECE528CE58FC00DEAAC4 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660F244934A800F6CBB4 /* trees.c */; };\n\t\t98D7ECE628CE58FC00DEAAC4 /* xerbla.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AC11FDBA53F00274FF0 /* xerbla.c */; };\n\t\t98D7ECE728CE58FC00DEAAC4 /* eidos_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A71AD4551C0047C223 /* eidos_test.cpp */; };\n\t\t98D7ECE828CE58FC00DEAAC4 /* blas.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AB31FDBA1E100274FF0 /* blas.c */; };\n\t\t98D7ECE928CE58FC00DEAAC4 /* log_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9809DF9E2550F32500C4E82D /* log_file.cpp */; };\n\t\t98D7ECEA28CE58FC00DEAAC4 /* eidos_class_Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */; };\n\t\t98D7ECEB28CE58FC00DEAAC4 /* individual.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98C92AEB1D0B07A6001C82BC /* individual.cpp */; };\n\t\t98D7ECEC28CE58FC00DEAAC4 /* GitSHA1_Xcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DC983D289986B300160DD8 /* GitSHA1_Xcode.cpp */; };\n\t\t98D7ECED28CE58FC00DEAAC4 /* eidos_class_Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98ACDC9C253522B80038703F /* eidos_class_Object.cpp */; };\n\t\t98D7ECEE28CE58FC00DEAAC4 /* lodepng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98235681252FDCF50096A745 /* lodepng.cpp */; };\n\t\t98D7ECEF28CE58FC00DEAAC4 /* mutation_run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98606AEC1DED0DCD00821CFF /* mutation_run.cpp */; };\n\t\t98D7ECF028CE58FC00DEAAC4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E51C7A980000548839 /* inline.c */; };\n\t\t98D7ECF128CE58FC00DEAAC4 /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98D7ECF228CE58FC00DEAAC4 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076603244934A800F6CBB4 /* compress.c */; };\n\t\t98D7ECF328CE58FC00DEAAC4 /* genomic_element_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */; };\n\t\t98D7ECF428CE58FC00DEAAC4 /* discrete.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A71C7A9B1600548839 /* discrete.c */; };\n\t\t98D7ECF528CE58FC00DEAAC4 /* exponential.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F91C7A980000548839 /* exponential.c */; };\n\t\t98D7ECF628CE58FC00DEAAC4 /* eidos_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985724A31AD435310047C223 /* eidos_value.cpp */; };\n\t\t98D7ECF728CE58FC00DEAAC4 /* eidos_type_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */; };\n\t\t98D7ECF828CE58FC00DEAAC4 /* eidos_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249F1AD34B740047C223 /* eidos_functions.cpp */; };\n\t\t98D7ECF928CE58FC00DEAAC4 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211B1C7A980000548839 /* pow_int.c */; };\n\t\t98D7ECFA28CE58FC00DEAAC4 /* weibull.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821011C7A980000548839 /* weibull.c */; };\n\t\t98D7ECFB28CE58FC00DEAAC4 /* fdiv.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821211C7A980000548839 /* fdiv.c */; };\n\t\t98D7ECFC28CE58FC00DEAAC4 /* cholesky.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AD51FDBBD1600274FF0 /* cholesky.c */; };\n\t\t98D7ECFD28CE58FC00DEAAC4 /* kastore.c in Sources */ = {isa = PBXBuildFile; fileRef = 987D19A4209A53850030D28D /* kastore.c */; };\n\t\t98D7ECFE28CE58FC00DEAAC4 /* tdist.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5F41ED5572C00FF9762 /* tdist.c */; };\n\t\t98D7ECFF28CE58FC00DEAAC4 /* polymorphism.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */; };\n\t\t98D7ED0028CE58FC00DEAAC4 /* eidos_class_TestElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */; };\n\t\t98D7ED0128CE58FC00DEAAC4 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 982663531A3BABD300A0CBBF /* main.cpp */; };\n\t\t98D7ED0228CE58FC00DEAAC4 /* slim_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DDAED4221765480038C133 /* slim_functions.cpp */; };\n\t\t98D7ED0328CE58FC00DEAAC4 /* gauss.c in Sources */ = {isa = PBXBuildFile; fileRef = 9876E5FB1ED5599F00FF9762 /* gauss.c */; };\n\t\t98D7ED0428CE58FC00DEAAC4 /* cauchy.c in Sources */ = {isa = PBXBuildFile; fileRef = 988880EB20744EE800E10172 /* cauchy.c */; };\n\t\t98D7ED0528CE58FC00DEAAC4 /* substitution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69D1A3CD551000AD4FC /* substitution.cpp */; };\n\t\t98D7ED0628CE58FC00DEAAC4 /* genotypes.c in Sources */ = {isa = PBXBuildFile; fileRef = 9854D2572278B9F7001D43BC /* genotypes.c */; };\n\t\t98D7ED0728CE58FC00DEAAC4 /* exp.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8210F1C7A980000548839 /* exp.c */; };\n\t\t98D7ED0828CE58FC00DEAAC4 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660E244934A800F6CBB4 /* gzwrite.c */; };\n\t\t98D7ED0928CE58FC00DEAAC4 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = 98076612244934A800F6CBB4 /* adler32.c */; };\n\t\t98D7ED0A28CE58FC00DEAAC4 /* trig.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211D1C7A980000548839 /* trig.c */; };\n\t\t98D7ED0B28CE58FC00DEAAC4 /* eidos_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98321F921B406B67007337A3 /* eidos_globals.cpp */; };\n\t\t98D7ED0C28CE58FC00DEAAC4 /* slim_test_genetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */; };\n\t\t98D7ED0D28CE58FC00DEAAC4 /* multinomial.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FF1C7A980000548839 /* multinomial.c */; };\n\t\t98D7ED0E28CE58FC00DEAAC4 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332B081FDBD00800274FF0 /* init.c */; };\n\t\t98D7ED0F28CE58FC00DEAAC4 /* math.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820E61C7A980000548839 /* math.c */; };\n\t\t98D7ED1028CE58FC00DEAAC4 /* genomic_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */; };\n\t\t98D7ED1128CE58FC00DEAAC4 /* slim_globals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9898172D1A59750300F7417C /* slim_globals.cpp */; };\n\t\t98D7ED1228CE58FC00DEAAC4 /* interaction_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */; };\n\t\t98D7ED1328CE58FC00DEAAC4 /* subpopulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */; };\n\t\t98D7ED1428CE58FC00DEAAC4 /* swap.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332AF51FDBC3F100274FF0 /* swap.c */; };\n\t\t98D7ED1528CE58FC00DEAAC4 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807660D244934A800F6CBB4 /* gzlib.c */; };\n\t\t98D7ED1628CE58FC00DEAAC4 /* species_eidos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98AC617924BA34ED0001914C /* species_eidos.cpp */; };\n\t\t98D7ED1728CE58FC00DEAAC4 /* mt.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821051C7A980000548839 /* mt.c */; };\n\t\t98D7ED1828CE58FC00DEAAC4 /* eidos_interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9857249A1AD08A810047C223 /* eidos_interpreter.cpp */; };\n\t\t98D7ED1928CE58FC00DEAAC4 /* inline.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821041C7A980000548839 /* inline.c */; };\n\t\t98D7ED1A28CE58FC00DEAAC4 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820EB1C7A980000548839 /* message.c */; };\n\t\t98D7ED1B28CE58FC00DEAAC4 /* dtrsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 984824F0210B9F23002402A5 /* dtrsv.c */; };\n\t\t98D7ED1C28CE58FC00DEAAC4 /* infnan.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821231C7A980000548839 /* infnan.c */; };\n\t\t98D7ED1D28CE58FC00DEAAC4 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 9807662824493A8F00F6CBB4 /* crc32.c */; };\n\t\t98D7ED1E28CE58FC00DEAAC4 /* zeta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C8211E1C7A980000548839 /* zeta.c */; };\n\t\t98D7ED1F28CE58FC00DEAAC4 /* eidos_class_DataFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */; };\n\t\t98D7ED2028CE58FC00DEAAC4 /* rng.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821061C7A980000548839 /* rng.c */; };\n\t\t98D7ED2128CE58FC00DEAAC4 /* oper.c in Sources */ = {isa = PBXBuildFile; fileRef = 98332ACC1FDBA81A00274FF0 /* oper.c */; };\n\t\t98D7ED2228CE58FC00DEAAC4 /* beta.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820F71C7A980000548839 /* beta.c */; };\n\t\t98D7ED2328CE58FC00DEAAC4 /* text_input.c in Sources */ = {isa = PBXBuildFile; fileRef = D0A758F620A4CC9800132D2F /* text_input.c */; };\n\t\t98D7ED2428CE58FC00DEAAC4 /* pow_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C821A21C7A99F000548839 /* pow_int.c */; };\n\t\t98D7ED2528CE58FC00DEAAC4 /* eidos_test_operators_comparison.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */; };\n\t\t98D7ED2628CE58FC00DEAAC4 /* lognormal.c in Sources */ = {isa = PBXBuildFile; fileRef = 98C820FE1C7A980000548839 /* lognormal.c */; };\n\t\t98D7ED2728CE58FC00DEAAC4 /* community.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9836867227CD40CF00683639 /* community.cpp */; };\n\t\t98DB3D6F1E6122AE00E2C200 /* interaction_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */; };\n\t\t98DB3D701E6122AE00E2C200 /* interaction_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */; };\n\t\t98DB3D711E6122AE00E2C200 /* interaction_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */; };\n\t\t98DC9841289986B300160DD8 /* GitSHA1_Xcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DC983D289986B300160DD8 /* GitSHA1_Xcode.cpp */; };\n\t\t98DD5F022155B857009062EE /* change_folder.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98DD5F002155B857009062EE /* change_folder.pdf */; };\n\t\t98DD5F032155B857009062EE /* change_folder_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98DD5F012155B857009062EE /* change_folder_H.pdf */; };\n\t\t98DDAED6221765480038C133 /* slim_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DDAED4221765480038C133 /* slim_functions.cpp */; };\n\t\t98DDAED7221765480038C133 /* slim_functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DDAED4221765480038C133 /* slim_functions.cpp */; };\n\t\t98DE4C131B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98DE4C141B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98DE4C151B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */; };\n\t\t98DEB47E2AA632AA00ABE60F /* spatial_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */; };\n\t\t98DEB47F2AA632AA00ABE60F /* spatial_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */; };\n\t\t98DEB4802AA632AA00ABE60F /* spatial_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */; };\n\t\t98DEB4812AA632AA00ABE60F /* spatial_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */; };\n\t\t98E684402B694F09000B3B65 /* plot.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98E6843E2B694F09000B3B65 /* plot.mm */; };\n\t\t98E684412B694F09000B3B65 /* plot.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98E6843E2B694F09000B3B65 /* plot.mm */; };\n\t\t98E9A68A1A3CCFD0000AD4FC /* mutation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6881A3CCFD0000AD4FC /* mutation.cpp */; };\n\t\t98E9A6901A3CD4CF000AD4FC /* mutation_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */; };\n\t\t98E9A6931A3CD4EF000AD4FC /* genomic_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */; };\n\t\t98E9A6961A3CD51A000AD4FC /* genomic_element_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */; };\n\t\t98E9A6991A3CD52A000AD4FC /* chromosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6971A3CD52A000AD4FC /* chromosome.cpp */; };\n\t\t98E9A69C1A3CD542000AD4FC /* polymorphism.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */; };\n\t\t98E9A69F1A3CD551000AD4FC /* substitution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A69D1A3CD551000AD4FC /* substitution.cpp */; };\n\t\t98E9A6A81A3CD5A0000AD4FC /* haplosome.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */; };\n\t\t98E9A6AB1A3CD5BB000AD4FC /* subpopulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */; };\n\t\t98E9A6AE1A3CD5D3000AD4FC /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6AC1A3CD5D3000AD4FC /* population.cpp */; };\n\t\t98E9A6B81A3CE35E000AD4FC /* eidos_rng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */; };\n\t\t98EA965C1ECC2541006BA35B /* ProfileReport.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98EA965A1ECC2541006BA35B /* ProfileReport.xib */; };\n\t\t98EBCD1421F3CFC600B385CF /* slim_gui.mm in Sources */ = {isa = PBXBuildFile; fileRef = 98EBCD1221F3CFC600B385CF /* slim_gui.mm */; };\n\t\t98EDB4CF2E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D02E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D12E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D22E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D32E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D42E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D52E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D62E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4D72E652F4A00CC8798 /* lu.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4CE2E652F4A00CC8798 /* lu.c */; };\n\t\t98EDB4E32E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E42E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E52E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E62E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E72E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E82E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4E92E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4EA2E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4EB2E65366E00CC8798 /* daxpy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4E22E65366E00CC8798 /* daxpy.c */; };\n\t\t98EDB4EE2E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4EF2E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F02E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F12E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F22E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F32E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F42E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F52E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F62E65389600CC8798 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4ED2E65389600CC8798 /* init.c */; };\n\t\t98EDB4F82E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4F92E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FA2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FB2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FC2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FD2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FE2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB4FF2E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB5002E6538F200CC8798 /* permutation.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB4F72E6538F200CC8798 /* permutation.c */; };\n\t\t98EDB5022E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5032E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5042E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5052E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5062E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5072E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5082E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5092E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB50A2E65399600CC8798 /* permute.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5012E65399600CC8798 /* permute.c */; };\n\t\t98EDB5112E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5122E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5132E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5142E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5152E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5162E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5172E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5182E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EDB5192E65410C00CC8798 /* copy.c in Sources */ = {isa = PBXBuildFile; fileRef = 98EDB5102E65410C00CC8798 /* copy.c */; };\n\t\t98EF4AB61ECDA5EA00CCDB09 /* profile_H.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98EF4AB41ECDA5EA00CCDB09 /* profile_H.pdf */; };\n\t\t98EF4AB71ECDA5EA00CCDB09 /* profile.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 98EF4AB51ECDA5EA00CCDB09 /* profile.pdf */; };\n\t\t98EFE62F1ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98EFE6301ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98EFE6311ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */; };\n\t\t98EFE6341ADD92BC00CBEC78 /* EidosAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98EFE6321ADD92BC00CBEC78 /* EidosAboutWindow.xib */; };\n\t\t98F65D561DF14DA50058BD29 /* Tips in Resources */ = {isa = PBXBuildFile; fileRef = 98F65D551DF14DA40058BD29 /* Tips */; };\n\t\tD0A758F720A4CC9800132D2F /* text_input.c in Sources */ = {isa = PBXBuildFile; fileRef = D0A758F620A4CC9800132D2F /* text_input.c */; };\n\t\tD0A758F920A4CCCF00132D2F /* text_input.c in Sources */ = {isa = PBXBuildFile; fileRef = D0A758F620A4CC9800132D2F /* text_input.c */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t984D5FAD1E3AF0D200473719 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 982663481A3BABD300A0CBBF /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 98D4C1B21A6F537B00FFB083;\n\t\t\tremoteInfo = SLiMgui;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t982556A71BA8E77B0054CB3F /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n\t\t9826634E1A3BABD300A0CBBF /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n\t\t98D7EBEA28CE557C00DEAAC4 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n\t\t98D7ED2928CE58FC00DEAAC4 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = /usr/share/man/man1/;\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t98024741215D85880025D29C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/FindRecipePanel.xib; sourceTree = \"<group>\"; };\n\t\t980566E125A7C5B9008D3C7F /* fdist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fdist.c; sourceTree = \"<group>\"; };\n\t\t98076602244934A800F6CBB4 /* zutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zutil.h; sourceTree = \"<group>\"; };\n\t\t98076603244934A800F6CBB4 /* compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = \"<group>\"; };\n\t\t98076604244934A800F6CBB4 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = \"<group>\"; };\n\t\t98076605244934A800F6CBB4 /* deflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = deflate.c; sourceTree = \"<group>\"; };\n\t\t98076606244934A800F6CBB4 /* trees.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trees.h; sourceTree = \"<group>\"; };\n\t\t98076608244934A800F6CBB4 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = \"<group>\"; };\n\t\t98076609244934A800F6CBB4 /* zutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zutil.c; sourceTree = \"<group>\"; };\n\t\t9807660A244934A800F6CBB4 /* deflate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = deflate.h; sourceTree = \"<group>\"; };\n\t\t9807660B244934A800F6CBB4 /* gzguts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gzguts.h; sourceTree = \"<group>\"; };\n\t\t9807660C244934A800F6CBB4 /* zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zlib.h; sourceTree = \"<group>\"; };\n\t\t9807660D244934A800F6CBB4 /* gzlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzlib.c; sourceTree = \"<group>\"; };\n\t\t9807660E244934A800F6CBB4 /* gzwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzwrite.c; sourceTree = \"<group>\"; };\n\t\t9807660F244934A800F6CBB4 /* trees.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trees.c; sourceTree = \"<group>\"; };\n\t\t98076611244934A800F6CBB4 /* crc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crc32.h; sourceTree = \"<group>\"; };\n\t\t98076612244934A800F6CBB4 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adler32.c; sourceTree = \"<group>\"; };\n\t\t98076613244934A800F6CBB4 /* zconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zconf.h; sourceTree = \"<group>\"; };\n\t\t9807662824493A8F00F6CBB4 /* crc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = crc32.c; sourceTree = \"<group>\"; };\n\t\t9807C0F324BA21B7008CC658 /* slim_test_core.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = slim_test_core.cpp; sourceTree = \"<group>\"; };\n\t\t9807C0F724BA21E3008CC658 /* slim_test_other.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = slim_test_other.cpp; sourceTree = \"<group>\"; };\n\t\t98090FA01B1B8B5800791DBF /* show_browser_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_browser_H.pdf; sourceTree = \"<group>\"; };\n\t\t98090FA11B1B8B5800791DBF /* show_browser.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_browser.pdf; sourceTree = \"<group>\"; };\n\t\t98090FA41B1B978900791DBF /* EidosValueWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosValueWrapper.h; sourceTree = \"<group>\"; };\n\t\t98090FA51B1B978900791DBF /* EidosValueWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosValueWrapper.mm; sourceTree = \"<group>\"; };\n\t\t9809DF9E2550F32500C4E82D /* log_file.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = log_file.cpp; sourceTree = \"<group>\"; };\n\t\t9809DF9F2550F32500C4E82D /* log_file.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = log_file.h; sourceTree = \"<group>\"; };\n\t\t9809F8BD24F32B3E00D312E4 /* eidos_tinycolormap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_tinycolormap.h; sourceTree = \"<group>\"; };\n\t\t980B6A6428CE642D0075B192 /* eidos_multi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = eidos_multi.entitlements; sourceTree = \"<group>\"; };\n\t\t980B6A6528CE64310075B192 /* slim_multi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = slim_multi.entitlements; sourceTree = \"<group>\"; };\n\t\t980DD5191AAE42F900D5B7B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/GraphAxisRescaleSheet.xib; sourceTree = \"<group>\"; };\n\t\t980DD51B1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_MutationFrequencyTrajectory.h; sourceTree = \"<group>\"; };\n\t\t980DD51C1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_MutationFrequencyTrajectory.mm; sourceTree = \"<group>\"; };\n\t\t98186DB8254A8B1600F9118C /* robin_hood.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = robin_hood.h; sourceTree = \"<group>\"; };\n\t\t981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_script.cpp; sourceTree = \"<group>\"; };\n\t\t981BAC691ACC6E8B0005BE94 /* eidos_script.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_script.h; sourceTree = \"<group>\"; };\n\t\t981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_files.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_math.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_colors.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_matrices.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_values.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_distributions.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_strings.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_other.cpp; sourceTree = \"<group>\"; };\n\t\t981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions_stats.cpp; sourceTree = \"<group>\"; };\n\t\t9821E2031ABDBC300036EAEA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };\n\t\t98235681252FDCF50096A745 /* lodepng.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lodepng.cpp; sourceTree = \"<group>\"; };\n\t\t98235687252FDD120096A745 /* lodepng.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lodepng.h; sourceTree = \"<group>\"; };\n\t\t98235688252FE61A0096A745 /* eidos_class_Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_class_Image.cpp; sourceTree = \"<group>\"; };\n\t\t9823568E252FE62F0096A745 /* eidos_class_Image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_class_Image.h; sourceTree = \"<group>\"; };\n\t\t9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosCocoaExtra.mm; sourceTree = \"<group>\"; };\n\t\t9825565D1BA32F030054CB3F /* EidosCocoaExtra.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EidosCocoaExtra.h; sourceTree = \"<group>\"; };\n\t\t9825565E1BA358EC0054CB3F /* EidosVariableBrowserControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosVariableBrowserControllerDelegate.h; sourceTree = \"<group>\"; };\n\t\t982556621BA35DF00054CB3F /* EidosConsoleTextViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EidosConsoleTextViewDelegate.h; sourceTree = \"<group>\"; };\n\t\t982556631BA450980054CB3F /* EidosHelpController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosHelpController.h; sourceTree = \"<group>\"; };\n\t\t982556641BA450980054CB3F /* EidosHelpController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosHelpController.mm; sourceTree = \"<group>\"; };\n\t\t982556681BA451D00054CB3F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/EidosHelpWindow.xib; sourceTree = \"<group>\"; };\n\t\t9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = EidosHelpFunctions.rtf; sourceTree = \"<group>\"; };\n\t\t9825566E1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = SLiMHelpFunctions.rtf; sourceTree = \"<group>\"; };\n\t\t9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = EidosHelpClasses.rtf; sourceTree = \"<group>\"; };\n\t\t982556A21BA5F0810054CB3F /* SLiMHelpClasses.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = SLiMHelpClasses.rtf; sourceTree = \"<group>\"; };\n\t\t982556A91BA8E77B0054CB3F /* eidos */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = eidos; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t982556AB1BA8E77C0054CB3F /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = \"<group>\"; };\n\t\t982663501A3BABD300A0CBBF /* slim */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = slim; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t982663531A3BABD300A0CBBF /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = \"<group>\"; };\n\t\t982A9DDD1FCA9FF0007BA3DF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/GraphBarRescaleSheet.xib; sourceTree = \"<group>\"; };\n\t\t982B50C52704048E006E91BC /* nbinomial.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nbinomial.c; sourceTree = \"<group>\"; };\n\t\t98321F921B406B67007337A3 /* eidos_globals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_globals.cpp; sourceTree = \"<group>\"; };\n\t\t98321F931B406B67007337A3 /* eidos_globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_globals.h; sourceTree = \"<group>\"; };\n\t\t98330C48294AB34300B452E2 /* eidos_test_parallel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_test_parallel.h; sourceTree = \"<group>\"; };\n\t\t98332A9D1FDB98ED00274FF0 /* mvgauss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mvgauss.c; sourceTree = \"<group>\"; };\n\t\t98332AA51FDB997E00274FF0 /* gsl_matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_matrix.h; path = matrix/gsl_matrix.h; sourceTree = \"<group>\"; };\n\t\t98332AA71FDB99AA00274FF0 /* gsl_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_vector.h; path = vector/gsl_vector.h; sourceTree = \"<group>\"; };\n\t\t98332AA81FDB9B3F00274FF0 /* gsl_vector_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_vector_double.h; path = vector/gsl_vector_double.h; sourceTree = \"<group>\"; };\n\t\t98332AA91FDB9B5100274FF0 /* gsl_matrix_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_matrix_double.h; path = matrix/gsl_matrix_double.h; sourceTree = \"<group>\"; };\n\t\t98332AAB1FDB9C7C00274FF0 /* gsl_block_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_block_double.h; path = block/gsl_block_double.h; sourceTree = \"<group>\"; };\n\t\t98332AAC1FDB9C7C00274FF0 /* gsl_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_block.h; path = block/gsl_block.h; sourceTree = \"<group>\"; };\n\t\t98332AAD1FDB9C7C00274FF0 /* gsl_check_range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_check_range.h; path = block/gsl_check_range.h; sourceTree = \"<group>\"; };\n\t\t98332AAF1FDB9E1500274FF0 /* gsl_blas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_blas.h; path = blas/gsl_blas.h; sourceTree = \"<group>\"; };\n\t\t98332AB01FDB9FA600274FF0 /* gsl_blas_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_blas_types.h; path = blas/gsl_blas_types.h; sourceTree = \"<group>\"; };\n\t\t98332AB21FDBA00000274FF0 /* gsl_cblas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_cblas.h; path = cblas/gsl_cblas.h; sourceTree = \"<group>\"; };\n\t\t98332AB31FDBA1E100274FF0 /* blas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blas.c; path = blas/blas.c; sourceTree = \"<group>\"; };\n\t\t98332AB81FDBA32200274FF0 /* dtrmv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dtrmv.c; path = cblas/dtrmv.c; sourceTree = \"<group>\"; };\n\t\t98332ABD1FDBA36500274FF0 /* cblas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cblas.h; path = cblas/cblas.h; sourceTree = \"<group>\"; };\n\t\t98332ABE1FDBA3A700274FF0 /* error_cblas_l2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error_cblas_l2.h; path = cblas/error_cblas_l2.h; sourceTree = \"<group>\"; };\n\t\t98332ABF1FDBA3D700274FF0 /* error_cblas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error_cblas.h; path = cblas/error_cblas.h; sourceTree = \"<group>\"; };\n\t\t98332AC01FDBA41100274FF0 /* source_trmv_r.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = source_trmv_r.h; path = cblas/source_trmv_r.h; sourceTree = \"<group>\"; };\n\t\t98332AC11FDBA53F00274FF0 /* xerbla.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xerbla.c; path = cblas/xerbla.c; sourceTree = \"<group>\"; };\n\t\t98332AC61FDBA6B600274FF0 /* vector.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vector.c; path = vector/vector.c; sourceTree = \"<group>\"; };\n\t\t98332ACB1FDBA81A00274FF0 /* oper_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = oper_source.inc; path = vector/oper_source.inc; sourceTree = \"<group>\"; };\n\t\t98332ACC1FDBA81A00274FF0 /* oper.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = oper.c; path = vector/oper.c; sourceTree = \"<group>\"; };\n\t\t98332AD21FDBA8B500274FF0 /* templates_off.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = templates_off.h; sourceTree = \"<group>\"; };\n\t\t98332AD31FDBA8B500274FF0 /* templates_on.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = templates_on.h; sourceTree = \"<group>\"; };\n\t\t98332AD51FDBBD1600274FF0 /* cholesky.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cholesky.c; path = linalg/cholesky.c; sourceTree = \"<group>\"; };\n\t\t98332AD61FDBBD1600274FF0 /* gsl_linalg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_linalg.h; path = linalg/gsl_linalg.h; sourceTree = \"<group>\"; };\n\t\t98332ADB1FDBC0D000274FF0 /* dgemv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dgemv.c; path = cblas/dgemv.c; sourceTree = \"<group>\"; };\n\t\t98332AE01FDBC11000274FF0 /* source_gemv_r.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = source_gemv_r.h; path = cblas/source_gemv_r.h; sourceTree = \"<group>\"; };\n\t\t98332AE31FDBC1D900274FF0 /* rowcol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rowcol.c; path = matrix/rowcol.c; sourceTree = \"<group>\"; };\n\t\t98332AE41FDBC1D900274FF0 /* submatrix_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = submatrix_source.inc; path = matrix/submatrix_source.inc; sourceTree = \"<group>\"; };\n\t\t98332AE51FDBC1D900274FF0 /* submatrix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = submatrix.c; path = matrix/submatrix.c; sourceTree = \"<group>\"; };\n\t\t98332AEB1FDBC1F600274FF0 /* rowcol_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = rowcol_source.inc; path = matrix/rowcol_source.inc; sourceTree = \"<group>\"; };\n\t\t98332AF01FDBC30100274FF0 /* view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = view.h; path = matrix/view.h; sourceTree = \"<group>\"; };\n\t\t98332AF41FDBC3F100274FF0 /* swap_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = swap_source.inc; path = matrix/swap_source.inc; sourceTree = \"<group>\"; };\n\t\t98332AF51FDBC3F100274FF0 /* swap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = swap.c; path = matrix/swap.c; sourceTree = \"<group>\"; };\n\t\t98332AFB1FDBC4B200274FF0 /* matrix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = matrix.c; path = matrix/matrix.c; sourceTree = \"<group>\"; };\n\t\t98332B001FDBCFC300274FF0 /* init_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = init_source.inc; path = matrix/init_source.inc; sourceTree = \"<group>\"; };\n\t\t98332B011FDBCFC300274FF0 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = init.c; path = matrix/init.c; sourceTree = \"<group>\"; };\n\t\t98332B071FDBD00800274FF0 /* init_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = init_source.inc; path = vector/init_source.inc; sourceTree = \"<group>\"; };\n\t\t98332B081FDBD00800274FF0 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = init.c; path = vector/init.c; sourceTree = \"<group>\"; };\n\t\t98332B0E1FDBD09800274FF0 /* init_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = init_source.inc; path = block/init_source.inc; sourceTree = \"<group>\"; };\n\t\t98332B0F1FDBD09800274FF0 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = init.c; path = block/init.c; sourceTree = \"<group>\"; };\n\t\t98332B151FDBD13D00274FF0 /* copy_source.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = copy_source.inc; path = matrix/copy_source.inc; sourceTree = \"<group>\"; };\n\t\t98332B161FDBD13D00274FF0 /* copy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = copy.c; path = matrix/copy.c; sourceTree = \"<group>\"; };\n\t\t9836867227CD40CF00683639 /* community.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = community.cpp; sourceTree = \"<group>\"; };\n\t\t9836867327CD40CF00683639 /* community.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = community.h; sourceTree = \"<group>\"; };\n\t\t9836868027CD72E900683639 /* community_eidos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = community_eidos.cpp; sourceTree = \"<group>\"; };\n\t\t984252C1216FA9930019696A /* FindRecipeController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FindRecipeController.h; sourceTree = \"<group>\"; };\n\t\t984252C2216FA9930019696A /* FindRecipeController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FindRecipeController.mm; sourceTree = \"<group>\"; };\n\t\t98453F3E1A75A12700C058CB /* dump_output_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = dump_output_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F3F1A75A12700C058CB /* dump_output.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = dump_output.pdf; sourceTree = \"<group>\"; };\n\t\t98453F421A75AABE00C058CB /* syntax_help_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = syntax_help_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F431A75AABE00C058CB /* syntax_help.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = syntax_help.pdf; sourceTree = \"<group>\"; };\n\t\t98453F4C1A76004300C058CB /* open_type_drawer_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = open_type_drawer_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F4D1A76004300C058CB /* open_type_drawer.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = open_type_drawer.pdf; sourceTree = \"<group>\"; };\n\t\t98453F4E1A76004300C058CB /* show_fixed_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_fixed_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F4F1A76004300C058CB /* show_fixed.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_fixed.pdf; sourceTree = \"<group>\"; };\n\t\t98453F501A76004300C058CB /* show_genomicelements_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_genomicelements_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F511A76004300C058CB /* show_genomicelements.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_genomicelements.pdf; sourceTree = \"<group>\"; };\n\t\t98453F521A76004300C058CB /* show_mutations_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_mutations_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F531A76004300C058CB /* show_mutations.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_mutations.pdf; sourceTree = \"<group>\"; };\n\t\t98453F541A76004300C058CB /* show_recombination_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_recombination_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F551A76004300C058CB /* show_recombination.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_recombination.pdf; sourceTree = \"<group>\"; };\n\t\t98453F601A76041200C058CB /* edit_submenu_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = edit_submenu_H.pdf; sourceTree = \"<group>\"; };\n\t\t98453F611A76041200C058CB /* edit_submenu.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = edit_submenu.pdf; sourceTree = \"<group>\"; };\n\t\t984824ED210B9E8F002402A5 /* ddot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ddot.c; path = cblas/ddot.c; sourceTree = \"<group>\"; };\n\t\t984824EF210B9EE6002402A5 /* source_dot_r.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = source_dot_r.h; path = cblas/source_dot_r.h; sourceTree = \"<group>\"; };\n\t\t984824F0210B9F23002402A5 /* dtrsv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dtrsv.c; path = cblas/dtrsv.c; sourceTree = \"<group>\"; };\n\t\t984824F8210B9F63002402A5 /* source_trsv_r.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = source_trsv_r.h; path = cblas/source_trsv_r.h; sourceTree = \"<group>\"; };\n\t\t984D5FA81E3AF0D200473719 /* EidosSLiMTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EidosSLiMTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t984D5FAC1E3AF0D200473719 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t984D5FB21E3AF18C00473719 /* EidosTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosTests.mm; sourceTree = \"<group>\"; };\n\t\t984D5FB41E3AF1F000473719 /* SLiMTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMTests.mm; sourceTree = \"<group>\"; };\n\t\t984F20AF298087850079D4D2 /* slim_test_parallel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = slim_test_parallel.h; sourceTree = \"<group>\"; };\n\t\t9850D8DF2063098E006BFD2E /* tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tables.c; path = treerec/tskit/tables.c; sourceTree = \"<group>\"; };\n\t\t985301EB1B72582E001520DF /* change_cloning_rate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_cloning_rate.pdf; sourceTree = \"<group>\"; };\n\t\t9854D2562278B9F7001D43BC /* core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = core.c; path = treerec/tskit/core.c; sourceTree = \"<group>\"; };\n\t\t9854D2572278B9F7001D43BC /* genotypes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = genotypes.c; path = treerec/tskit/genotypes.c; sourceTree = \"<group>\"; };\n\t\t9854D2582278B9F7001D43BC /* genotypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = genotypes.h; path = treerec/tskit/genotypes.h; sourceTree = \"<group>\"; };\n\t\t9854D2592278B9F8001D43BC /* convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = convert.c; path = treerec/tskit/convert.c; sourceTree = \"<group>\"; };\n\t\t9854D25A2278B9F8001D43BC /* convert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert.h; path = treerec/tskit/convert.h; sourceTree = \"<group>\"; };\n\t\t9854D25B2278B9F8001D43BC /* stats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stats.c; path = treerec/tskit/stats.c; sourceTree = \"<group>\"; };\n\t\t9854D25C2278B9F8001D43BC /* stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stats.h; path = treerec/tskit/stats.h; sourceTree = \"<group>\"; };\n\t\t9854D25D2278B9F8001D43BC /* trees.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trees.c; path = treerec/tskit/trees.c; sourceTree = \"<group>\"; };\n\t\t9854D25E2278B9F8001D43BC /* core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = core.h; path = treerec/tskit/core.h; sourceTree = \"<group>\"; };\n\t\t9857249A1AD08A810047C223 /* eidos_interpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_interpreter.cpp; sourceTree = \"<group>\"; };\n\t\t9857249B1AD08A810047C223 /* eidos_interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_interpreter.h; sourceTree = \"<group>\"; };\n\t\t9857249F1AD34B740047C223 /* eidos_functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_functions.cpp; sourceTree = \"<group>\"; };\n\t\t985724A01AD34B740047C223 /* eidos_functions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_functions.h; sourceTree = \"<group>\"; };\n\t\t985724A31AD435310047C223 /* eidos_value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_value.cpp; sourceTree = \"<group>\"; };\n\t\t985724A41AD435310047C223 /* eidos_value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_value.h; sourceTree = \"<group>\"; };\n\t\t985724A71AD4551C0047C223 /* eidos_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test.cpp; sourceTree = \"<group>\"; };\n\t\t985724A81AD4551C0047C223 /* eidos_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_test.h; sourceTree = \"<group>\"; };\n\t\t985724AF1AD478630047C223 /* EidosScribe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EidosScribe.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t985724B21AD478630047C223 /* EidosScribe-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = \"EidosScribe-Info.plist\"; sourceTree = \"<group>\"; };\n\t\t985724B31AD478630047C223 /* EidosAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EidosAppDelegate.h; sourceTree = \"<group>\"; };\n\t\t985724B41AD478630047C223 /* EidosAppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosAppDelegate.mm; sourceTree = \"<group>\"; };\n\t\t985724B61AD478630047C223 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t985724B81AD478630047C223 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\t985724BB1AD478630047C223 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\t985724DE1AD4C3310047C223 /* execute_script_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = execute_script_H.pdf; sourceTree = \"<group>\"; };\n\t\t985724DF1AD4C3310047C223 /* execute_script.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = execute_script.pdf; sourceTree = \"<group>\"; };\n\t\t985724E51AD622880047C223 /* EidosConsoleTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosConsoleTextView.h; sourceTree = \"<group>\"; };\n\t\t985724E61AD622880047C223 /* EidosConsoleTextView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosConsoleTextView.mm; sourceTree = \"<group>\"; };\n\t\t985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = execute_selection_H.pdf; sourceTree = \"<group>\"; };\n\t\t985724E91AD6B9FE0047C223 /* execute_selection.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = execute_selection.pdf; sourceTree = \"<group>\"; };\n\t\t985724EC1AD6D4060047C223 /* show_parse_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_parse_H.pdf; sourceTree = \"<group>\"; };\n\t\t985724ED1AD6D4060047C223 /* show_parse.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_parse.pdf; sourceTree = \"<group>\"; };\n\t\t985724EE1AD6D4060047C223 /* show_tokens_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_tokens_H.pdf; sourceTree = \"<group>\"; };\n\t\t985724EF1AD6D4060047C223 /* show_tokens.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_tokens.pdf; sourceTree = \"<group>\"; };\n\t\t985724F41AD6DD470047C223 /* show_execution_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_execution_H.pdf; sourceTree = \"<group>\"; };\n\t\t985724F51AD6DD470047C223 /* show_execution.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_execution.pdf; sourceTree = \"<group>\"; };\n\t\t9857E33A1BB58DAE00F1C8A9 /* eidos_intrusive_ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_intrusive_ptr.h; sourceTree = \"<group>\"; };\n\t\t985A11861BBA07CB009EE1FF /* eidos_object_pool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_object_pool.h; sourceTree = \"<group>\"; };\n\t\t985D1D892808B84F00461CFA /* sparse_vector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = sparse_vector.cpp; sourceTree = \"<group>\"; };\n\t\t985D1D8A2808B84F00461CFA /* sparse_vector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sparse_vector.h; sourceTree = \"<group>\"; };\n\t\t985DCFD52B1ED7340025B0D5 /* PARALLEL */ = {isa = PBXFileReference; lastKnownFileType = text; path = PARALLEL; sourceTree = \"<group>\"; };\n\t\t985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = slim_test_genetics.cpp; sourceTree = \"<group>\"; };\n\t\t985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_operators_other.cpp; sourceTree = \"<group>\"; };\n\t\t985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_functions_other.cpp; sourceTree = \"<group>\"; };\n\t\t985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_functions_math.cpp; sourceTree = \"<group>\"; };\n\t\t985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_functions_vector.cpp; sourceTree = \"<group>\"; };\n\t\t985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_operators_arithmetic.cpp; sourceTree = \"<group>\"; };\n\t\t985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_operators_comparison.cpp; sourceTree = \"<group>\"; };\n\t\t985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_test_functions_statistics.cpp; sourceTree = \"<group>\"; };\n\t\t986021081A3BB504001BDCFE /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\t98606AEC1DED0DCD00821CFF /* mutation_run.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutation_run.cpp; sourceTree = \"<group>\"; };\n\t\t98606AED1DED0DCD00821CFF /* mutation_run.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutation_run.h; sourceTree = \"<group>\"; };\n\t\t986070E82AACECD600FD6143 /* spatial_kernel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = spatial_kernel.cpp; sourceTree = \"<group>\"; };\n\t\t986070E92AACECD600FD6143 /* spatial_kernel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spatial_kernel.h; sourceTree = \"<group>\"; };\n\t\t986764A92089066A00E81B2E /* tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tables.h; path = treerec/tskit/tables.h; sourceTree = \"<group>\"; };\n\t\t986926D21AA1337A0000E138 /* graph_submenu_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = graph_submenu_H.pdf; sourceTree = \"<group>\"; };\n\t\t986926D31AA1337A0000E138 /* graph_submenu.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = graph_submenu.pdf; sourceTree = \"<group>\"; };\n\t\t986926D71AA140550000E138 /* GraphView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView.h; sourceTree = \"<group>\"; };\n\t\t986926D81AA140550000E138 /* GraphView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView.mm; sourceTree = \"<group>\"; };\n\t\t986926DB1AA1429D0000E138 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/GraphWindow.xib; sourceTree = \"<group>\"; };\n\t\t986926DD1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_MutationFrequencySpectra.h; sourceTree = \"<group>\"; };\n\t\t986926DE1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_MutationFrequencySpectra.mm; sourceTree = \"<group>\"; };\n\t\t986926E01AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_MutationLossTimeHistogram.h; sourceTree = \"<group>\"; };\n\t\t986926E11AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_MutationLossTimeHistogram.mm; sourceTree = \"<group>\"; };\n\t\t986926E31AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_MutationFixationTimeHistogram.h; sourceTree = \"<group>\"; };\n\t\t986926E41AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_MutationFixationTimeHistogram.mm; sourceTree = \"<group>\"; };\n\t\t986926E61AA40AFF0000E138 /* GraphView_FitnessOverTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_FitnessOverTime.h; sourceTree = \"<group>\"; };\n\t\t986926E71AA40AFF0000E138 /* GraphView_FitnessOverTime.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_FitnessOverTime.mm; sourceTree = \"<group>\"; };\n\t\t986926E91AA6B7480000E138 /* GraphView_PopulationVisualization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphView_PopulationVisualization.h; sourceTree = \"<group>\"; };\n\t\t986926EA1AA6B7480000E138 /* GraphView_PopulationVisualization.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphView_PopulationVisualization.mm; sourceTree = \"<group>\"; };\n\t\t986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_call_signature.cpp; sourceTree = \"<group>\"; };\n\t\t986D73E71B07E89E007FBB70 /* eidos_call_signature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_call_signature.h; sourceTree = \"<group>\"; };\n\t\t98729ACD2A87A93500E81662 /* eidos_sorting.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_sorting.h; sourceTree = \"<group>\"; };\n\t\t98729ACE2A87AAB700E81662 /* eidos_sorting.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; path = eidos_sorting.inc; sourceTree = \"<group>\"; };\n\t\t98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_sorting.cpp; sourceTree = \"<group>\"; };\n\t\t9873B12328CE26CD00582D83 /* eidos_openmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_openmp.h; sourceTree = \"<group>\"; };\n\t\t98760EDC28CE5E7600CEBC40 /* libomp.dylib */ = {isa = PBXFileReference; lastKnownFileType = \"compiled.mach-o.dylib\"; name = libomp.dylib; path = /usr/local/lib/libomp.dylib; sourceTree = \"<group>\"; };\n\t\t9876E5F31ED5572C00FF9762 /* gsl_cdf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gsl_cdf.h; path = cdf/gsl_cdf.h; sourceTree = \"<group>\"; };\n\t\t9876E5F41ED5572C00FF9762 /* tdist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tdist.c; path = cdf/tdist.c; sourceTree = \"<group>\"; };\n\t\t9876E5F91ED557B000FF9762 /* beta_inc.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = beta_inc.inc; path = cdf/beta_inc.inc; sourceTree = \"<group>\"; };\n\t\t9876E5FB1ED5599F00FF9762 /* gauss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gauss.c; path = cdf/gauss.c; sourceTree = \"<group>\"; };\n\t\t9876E6001ED55A2500FF9762 /* gamma_inc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamma_inc.c; sourceTree = \"<group>\"; };\n\t\t9876E6021ED55A6E00FF9762 /* gsl_sf_erf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_erf.h; sourceTree = \"<group>\"; };\n\t\t9876E6061ED55AD600FF9762 /* gsl_sf_expint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_expint.h; sourceTree = \"<group>\"; };\n\t\t9876E6071ED55B4700FF9762 /* erfc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = erfc.c; sourceTree = \"<group>\"; };\n\t\t9876E60C1ED55C0400FF9762 /* expint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = expint.c; sourceTree = \"<group>\"; };\n\t\t9876E6111ED55C6B00FF9762 /* beta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = beta.c; sourceTree = \"<group>\"; };\n\t\t9878A93D1A4E57E70007B9D6 /* species.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = species.cpp; sourceTree = \"<group>\"; };\n\t\t9878A93E1A4E57E70007B9D6 /* species.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = species.h; sourceTree = \"<group>\"; };\n\t\t987A2A0524033856009A636F /* gaussinv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gaussinv.c; path = cdf/gaussinv.c; sourceTree = \"<group>\"; };\n\t\t987A2A0624033856009A636F /* rat_eval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rat_eval.h; path = cdf/rat_eval.h; sourceTree = \"<group>\"; };\n\t\t987A700E2AE8032100A049E2 /* laplace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = laplace.c; sourceTree = \"<group>\"; };\n\t\t987AD8721B2CBDA70035D6C8 /* show_console_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_console_H.pdf; sourceTree = \"<group>\"; };\n\t\t987AD8731B2CBDA70035D6C8 /* show_console.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = show_console.pdf; sourceTree = \"<group>\"; };\n\t\t987AD8841B2CC0C10035D6C8 /* EidosVariableBrowserController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosVariableBrowserController.h; sourceTree = \"<group>\"; };\n\t\t987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosVariableBrowserController.mm; sourceTree = \"<group>\"; };\n\t\t987AD8881B2CDBB80035D6C8 /* EidosConsoleWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosConsoleWindowController.h; sourceTree = \"<group>\"; };\n\t\t987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosConsoleWindowController.mm; sourceTree = \"<group>\"; };\n\t\t987D19A3209A53850030D28D /* kastore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kastore.h; path = treerec/tskit/kastore/kastore.h; sourceTree = \"<group>\"; };\n\t\t987D19A4209A53850030D28D /* kastore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = kastore.c; path = treerec/tskit/kastore/kastore.c; sourceTree = \"<group>\"; };\n\t\t987D30EA2EF482AA0096621B /* eidos_simd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_simd.h; sourceTree = \"<group>\"; };\n\t\t98800DC21B7EDCB50046F5F9 /* slim_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slim_test.cpp; sourceTree = \"<group>\"; };\n\t\t98800DC31B7EDCB50046F5F9 /* slim_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slim_test.h; sourceTree = \"<group>\"; };\n\t\t98833AEA1C7A9E8D0072DBAC /* _README */ = {isa = PBXFileReference; lastKnownFileType = text; path = _README; sourceTree = \"<group>\"; };\n\t\t98833AEB1C7A9E8D0072DBAC /* AUTHORS */ = {isa = PBXFileReference; lastKnownFileType = text; path = AUTHORS; sourceTree = \"<group>\"; };\n\t\t98833AEC1C7A9E8D0072DBAC /* COPYING */ = {isa = PBXFileReference; lastKnownFileType = text; path = COPYING; sourceTree = \"<group>\"; };\n\t\t98833AED1C7A9E8D0072DBAC /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = \"<group>\"; };\n\t\t98833AEE1C7A9E8D0072DBAC /* THANKS */ = {isa = PBXFileReference; lastKnownFileType = text; path = THANKS; sourceTree = \"<group>\"; };\n\t\t988794691EA8804900AE0C8D /* SLiMPDFDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMPDFDocument.h; sourceTree = \"<group>\"; };\n\t\t9887946A1EA8804900AE0C8D /* SLiMPDFDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMPDFDocument.mm; sourceTree = \"<group>\"; };\n\t\t9887946C1EA8808000AE0C8D /* SLiMPDFWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMPDFWindowController.h; sourceTree = \"<group>\"; };\n\t\t9887946D1EA8808000AE0C8D /* SLiMPDFWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMPDFWindowController.mm; sourceTree = \"<group>\"; };\n\t\t9887946E1EA8808000AE0C8D /* SLiMPDFWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SLiMPDFWindow.xib; sourceTree = \"<group>\"; };\n\t\t988794711EA8C42200AE0C8D /* SLiMPDFView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMPDFView.h; sourceTree = \"<group>\"; };\n\t\t988794721EA8C42200AE0C8D /* SLiMPDFView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMPDFView.mm; sourceTree = \"<group>\"; };\n\t\t988880EB20744EE800E10172 /* cauchy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cauchy.c; sourceTree = \"<group>\"; };\n\t\t9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_class_DataFrame.cpp; sourceTree = \"<group>\"; };\n\t\t9890D1EC27136BB7001EAE98 /* eidos_class_DataFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_class_DataFrame.h; sourceTree = \"<group>\"; };\n\t\t9892282A1BAE279700429674 /* EidosHelpOperators.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = EidosHelpOperators.rtf; sourceTree = \"<group>\"; };\n\t\t9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = EidosHelpTypes.rtf; sourceTree = \"<group>\"; };\n\t\t989228301BAF496C00429674 /* EidosHelpStatements.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = EidosHelpStatements.rtf; sourceTree = \"<group>\"; };\n\t\t989228331BAFB27300429674 /* SLiMHelpCallbacks.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = SLiMHelpCallbacks.rtf; sourceTree = \"<group>\"; };\n\t\t9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_beep.cpp; sourceTree = \"<group>\"; };\n\t\t9893C7DC1CDA2D650029AC94 /* eidos_beep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_beep.h; sourceTree = \"<group>\"; };\n\t\t9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_type_table.cpp; sourceTree = \"<group>\"; };\n\t\t9893C7E21CDFCF0D0029AC94 /* eidos_type_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_type_table.h; sourceTree = \"<group>\"; };\n\t\t9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_type_interpreter.cpp; sourceTree = \"<group>\"; };\n\t\t9893C7E81CDFE9870029AC94 /* eidos_type_interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_type_interpreter.h; sourceTree = \"<group>\"; };\n\t\t989524A71E40AE74007E62FA /* SLiMDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMDocument.h; sourceTree = \"<group>\"; };\n\t\t989524A81E40AE74007E62FA /* SLiMDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMDocument.mm; sourceTree = \"<group>\"; };\n\t\t989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_class_TestElement.cpp; sourceTree = \"<group>\"; };\n\t\t989790D91AF3D0E100C6B14C /* eidos_class_TestElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_class_TestElement.h; sourceTree = \"<group>\"; };\n\t\t9898172D1A59750300F7417C /* slim_globals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slim_globals.cpp; sourceTree = \"<group>\"; };\n\t\t9898172E1A59750300F7417C /* slim_globals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slim_globals.h; sourceTree = \"<group>\"; };\n\t\t989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_class_Dictionary.cpp; sourceTree = \"<group>\"; };\n\t\t989F495127DBB7D600B07B7D /* QtSLiM */ = {isa = PBXFileReference; lastKnownFileType = folder; path = QtSLiM; sourceTree = \"<group>\"; };\n\t\t98A02F931BA1E3E1002DDE54 /* EidosTextViewDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EidosTextViewDelegate.h; sourceTree = \"<group>\"; };\n\t\t98A02F941BA1E648002DDE54 /* EidosConsoleWindowControllerDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EidosConsoleWindowControllerDelegate.h; sourceTree = \"<group>\"; };\n\t\t98A240581B8E3295005C9A30 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };\n\t\t98A2405C1B8E338E005C9A30 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };\n\t\t98A2FF881D7DF4D7007E3DB8 /* Recipes */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Recipes; path = SLiMgui/Recipes; sourceTree = \"<group>\"; };\n\t\t98A4EC931B67C1CD00CD92FD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/EidosConsoleWindow.xib; sourceTree = \"<group>\"; };\n\t\t98A5134D1B66B69E005A753D /* eidos_token.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_token.cpp; sourceTree = \"<group>\"; };\n\t\t98A5134E1B66B69E005A753D /* eidos_token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_token.h; sourceTree = \"<group>\"; };\n\t\t98A513521B66B6CA005A753D /* eidos_ast_node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_ast_node.cpp; sourceTree = \"<group>\"; };\n\t\t98A513531B66B6CA005A753D /* eidos_ast_node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_ast_node.h; sourceTree = \"<group>\"; };\n\t\t98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slim_eidos_block.cpp; sourceTree = \"<group>\"; };\n\t\t98AB597A1B2531F10077CB4A /* slim_eidos_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slim_eidos_block.h; sourceTree = \"<group>\"; };\n\t\t98AC617924BA34ED0001914C /* species_eidos.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = species_eidos.cpp; sourceTree = \"<group>\"; };\n\t\t98ACDC9B2534CA120038703F /* eidos_class_Dictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_class_Dictionary.h; sourceTree = \"<group>\"; };\n\t\t98ACDC9C253522B80038703F /* eidos_class_Object.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_class_Object.cpp; sourceTree = \"<group>\"; };\n\t\t98ACDCA2253522D40038703F /* eidos_class_Object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_class_Object.h; sourceTree = \"<group>\"; };\n\t\t98AF84641CB307300030D1EB /* VERSIONS */ = {isa = PBXFileReference; lastKnownFileType = text; path = VERSIONS; sourceTree = \"<group>\"; };\n\t\t98B8AF8625A2BE7200C95D66 /* json.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json.hpp; sourceTree = \"<group>\"; };\n\t\t98B8AF8725A2BE7200C95D66 /* json_fwd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json_fwd.hpp; sourceTree = \"<group>\"; };\n\t\t98C0943C1B7663DF00766A9A /* female_symbol.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = female_symbol.pdf; sourceTree = \"<group>\"; };\n\t\t98C0943D1B7663DF00766A9A /* male_symbol.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = male_symbol.pdf; sourceTree = \"<group>\"; };\n\t\t98C634432EF9F632003F12A3 /* dirichlet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dirichlet.c; sourceTree = \"<group>\"; };\n\t\t98C820E11C7A980000548839 /* build.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = build.h; sourceTree = \"<group>\"; };\n\t\t98C820E31C7A980000548839 /* gsl_complex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_complex.h; sourceTree = \"<group>\"; };\n\t\t98C820E41C7A980000548839 /* gsl_complex_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_complex_math.h; sourceTree = \"<group>\"; };\n\t\t98C820E51C7A980000548839 /* inline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inline.c; sourceTree = \"<group>\"; };\n\t\t98C820E61C7A980000548839 /* math.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = math.c; sourceTree = \"<group>\"; };\n\t\t98C820E71C7A980000548839 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = \"<group>\"; };\n\t\t98C820E91C7A980000548839 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = \"<group>\"; };\n\t\t98C820EA1C7A980000548839 /* gsl_message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_message.h; sourceTree = \"<group>\"; };\n\t\t98C820EB1C7A980000548839 /* message.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = message.c; sourceTree = \"<group>\"; };\n\t\t98C820EC1C7A980000548839 /* stream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stream.c; sourceTree = \"<group>\"; };\n\t\t98C820ED1C7A980000548839 /* gsl_errno.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_errno.h; sourceTree = \"<group>\"; };\n\t\t98C820EE1C7A980000548839 /* gsl_inline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_inline.h; sourceTree = \"<group>\"; };\n\t\t98C820EF1C7A980000548839 /* gsl_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_machine.h; sourceTree = \"<group>\"; };\n\t\t98C820F01C7A980000548839 /* gsl_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_math.h; sourceTree = \"<group>\"; };\n\t\t98C820F11C7A980000548839 /* gsl_minmax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_minmax.h; sourceTree = \"<group>\"; };\n\t\t98C820F21C7A980000548839 /* gsl_nan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_nan.h; sourceTree = \"<group>\"; };\n\t\t98C820F31C7A980000548839 /* gsl_pow_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_pow_int.h; sourceTree = \"<group>\"; };\n\t\t98C820F41C7A980000548839 /* gsl_precision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_precision.h; sourceTree = \"<group>\"; };\n\t\t98C820F51C7A980000548839 /* gsl_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_types.h; sourceTree = \"<group>\"; };\n\t\t98C820F71C7A980000548839 /* beta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = beta.c; sourceTree = \"<group>\"; };\n\t\t98C820F81C7A980000548839 /* binomial_tpe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = binomial_tpe.c; sourceTree = \"<group>\"; };\n\t\t98C820F91C7A980000548839 /* exponential.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exponential.c; sourceTree = \"<group>\"; };\n\t\t98C820FA1C7A980000548839 /* gamma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamma.c; sourceTree = \"<group>\"; };\n\t\t98C820FB1C7A980000548839 /* gauss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gauss.c; sourceTree = \"<group>\"; };\n\t\t98C820FC1C7A980000548839 /* gausszig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gausszig.c; sourceTree = \"<group>\"; };\n\t\t98C820FD1C7A980000548839 /* gsl_randist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_randist.h; sourceTree = \"<group>\"; };\n\t\t98C820FE1C7A980000548839 /* lognormal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lognormal.c; sourceTree = \"<group>\"; };\n\t\t98C820FF1C7A980000548839 /* multinomial.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = multinomial.c; sourceTree = \"<group>\"; };\n\t\t98C821001C7A980000548839 /* poisson.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = poisson.c; sourceTree = \"<group>\"; };\n\t\t98C821011C7A980000548839 /* weibull.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = weibull.c; sourceTree = \"<group>\"; };\n\t\t98C821031C7A980000548839 /* gsl_rng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_rng.h; sourceTree = \"<group>\"; };\n\t\t98C821041C7A980000548839 /* inline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inline.c; sourceTree = \"<group>\"; };\n\t\t98C821051C7A980000548839 /* mt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mt.c; sourceTree = \"<group>\"; };\n\t\t98C821061C7A980000548839 /* rng.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rng.c; sourceTree = \"<group>\"; };\n\t\t98C821071C7A980000548839 /* taus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = taus.c; sourceTree = \"<group>\"; };\n\t\t98C821091C7A980000548839 /* cheb_eval.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; path = cheb_eval.inc; sourceTree = \"<group>\"; };\n\t\t98C8210A1C7A980000548839 /* chebyshev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chebyshev.h; sourceTree = \"<group>\"; };\n\t\t98C8210B1C7A980000548839 /* check.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = check.h; sourceTree = \"<group>\"; };\n\t\t98C8210C1C7A980000548839 /* elementary.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = elementary.c; sourceTree = \"<group>\"; };\n\t\t98C8210D1C7A980000548839 /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = \"<group>\"; };\n\t\t98C8210E1C7A980000548839 /* eval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eval.h; sourceTree = \"<group>\"; };\n\t\t98C8210F1C7A980000548839 /* exp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exp.c; sourceTree = \"<group>\"; };\n\t\t98C821101C7A980000548839 /* gamma.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamma.c; sourceTree = \"<group>\"; };\n\t\t98C821111C7A980000548839 /* gsl_sf_elementary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_elementary.h; sourceTree = \"<group>\"; };\n\t\t98C821121C7A980000548839 /* gsl_sf_exp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_exp.h; sourceTree = \"<group>\"; };\n\t\t98C821131C7A980000548839 /* gsl_sf_gamma.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_gamma.h; sourceTree = \"<group>\"; };\n\t\t98C821141C7A980000548839 /* gsl_sf_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_log.h; sourceTree = \"<group>\"; };\n\t\t98C821151C7A980000548839 /* gsl_sf_pow_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_pow_int.h; sourceTree = \"<group>\"; };\n\t\t98C821161C7A980000548839 /* gsl_sf_psi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_psi.h; sourceTree = \"<group>\"; };\n\t\t98C821171C7A980000548839 /* gsl_sf_result.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_result.h; sourceTree = \"<group>\"; };\n\t\t98C821181C7A980000548839 /* gsl_sf_trig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_trig.h; sourceTree = \"<group>\"; };\n\t\t98C821191C7A980000548839 /* gsl_sf_zeta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sf_zeta.h; sourceTree = \"<group>\"; };\n\t\t98C8211A1C7A980000548839 /* log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = log.c; sourceTree = \"<group>\"; };\n\t\t98C8211B1C7A980000548839 /* pow_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pow_int.c; sourceTree = \"<group>\"; };\n\t\t98C8211C1C7A980000548839 /* psi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = psi.c; sourceTree = \"<group>\"; };\n\t\t98C8211D1C7A980000548839 /* trig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trig.c; sourceTree = \"<group>\"; };\n\t\t98C8211E1C7A980000548839 /* zeta.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zeta.c; sourceTree = \"<group>\"; };\n\t\t98C821201C7A980000548839 /* coerce.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coerce.c; sourceTree = \"<group>\"; };\n\t\t98C821211C7A980000548839 /* fdiv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fdiv.c; sourceTree = \"<group>\"; };\n\t\t98C821221C7A980000548839 /* gsl_sys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_sys.h; sourceTree = \"<group>\"; };\n\t\t98C821231C7A980000548839 /* infnan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = infnan.c; sourceTree = \"<group>\"; };\n\t\t98C8219D1C7A99B200548839 /* minmax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = minmax.c; sourceTree = \"<group>\"; };\n\t\t98C821A21C7A99F000548839 /* pow_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pow_int.c; sourceTree = \"<group>\"; };\n\t\t98C821A71C7A9B1600548839 /* discrete.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = discrete.c; sourceTree = \"<group>\"; };\n\t\t98C821A81C7A9B1600548839 /* geometric.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = geometric.c; sourceTree = \"<group>\"; };\n\t\t98C821B11C7A9B9F00548839 /* shuffle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = shuffle.c; sourceTree = \"<group>\"; };\n\t\t98C92AEB1D0B07A6001C82BC /* individual.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = individual.cpp; sourceTree = \"<group>\"; };\n\t\t98C92AEC1D0B07A6001C82BC /* individual.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = individual.h; sourceTree = \"<group>\"; };\n\t\t98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spline2d.c; sourceTree = \"<group>\"; };\n\t\t98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bilinear.c; sourceTree = \"<group>\"; };\n\t\t98CEFCD82AAFABAA00D2C9B4 /* gsl_interp2d.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_interp2d.h; sourceTree = \"<group>\"; };\n\t\t98CEFCDA2AAFABAA00D2C9B4 /* interp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interp.c; sourceTree = \"<group>\"; };\n\t\t98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bicubic.c; sourceTree = \"<group>\"; };\n\t\t98CEFCDC2AAFABAA00D2C9B4 /* gsl_interp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_interp.h; sourceTree = \"<group>\"; };\n\t\t98CEFCDD2AAFABAA00D2C9B4 /* integ_eval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = integ_eval.h; sourceTree = \"<group>\"; };\n\t\t98CEFCDE2AAFABAA00D2C9B4 /* akima.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = akima.c; sourceTree = \"<group>\"; };\n\t\t98CEFCE12AAFABAA00D2C9B4 /* gsl_spline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_spline.h; sourceTree = \"<group>\"; };\n\t\t98CEFCE22AAFABAA00D2C9B4 /* spline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spline.c; sourceTree = \"<group>\"; };\n\t\t98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = interp2d.c; sourceTree = \"<group>\"; };\n\t\t98CEFCE62AAFABAA00D2C9B4 /* linear.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = linear.c; sourceTree = \"<group>\"; };\n\t\t98CEFCE82AAFABAA00D2C9B4 /* gsl_spline2d.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_spline2d.h; sourceTree = \"<group>\"; };\n\t\t98CEFCEA2AAFABAA00D2C9B4 /* accel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = accel.c; sourceTree = \"<group>\"; };\n\t\t98CEFCEB2AAFABAA00D2C9B4 /* inline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inline.c; sourceTree = \"<group>\"; };\n\t\t98CEFD742AAFB12F00D2C9B4 /* cspline.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cspline.c; sourceTree = \"<group>\"; };\n\t\t98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tridiag.c; path = linalg/tridiag.c; sourceTree = \"<group>\"; };\n\t\t98CEFD862AAFB24700D2C9B4 /* tridiag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tridiag.h; path = linalg/tridiag.h; sourceTree = \"<group>\"; };\n\t\t98CEFD872AAFB4EF00D2C9B4 /* view.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = view.c; path = vector/view.c; sourceTree = \"<group>\"; };\n\t\t98CEFD902AAFB55500D2C9B4 /* view.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = view.h; path = vector/view.h; sourceTree = \"<group>\"; };\n\t\t98CEFD912AAFB58100D2C9B4 /* view_source.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; name = view_source.inc; path = vector/view_source.inc; sourceTree = \"<group>\"; };\n\t\t98CF264E1E42DBE200E392D8 /* slim.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; path = slim.iconset; sourceTree = \"<group>\"; };\n\t\t98CF26501E4353FE00E392D8 /* SLiMDocumentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMDocumentController.h; sourceTree = \"<group>\"; };\n\t\t98CF26511E4353FE00E392D8 /* SLiMDocumentController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMDocumentController.mm; sourceTree = \"<group>\"; };\n\t\t98CF5301294A3FC900557BBA /* SLiMguiLegacy_multi.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SLiMguiLegacy_multi.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98CF5302294A3FC900557BBA /* SLiMguiLegacy_multi-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"SLiMguiLegacy_multi-Info.plist\"; path = \"SLiMgui/SLiMguiLegacy_multi-Info.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t98CF5346294A5F3900557BBA /* SLiMguiLegacy_multi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SLiMguiLegacy_multi.entitlements; sourceTree = \"<group>\"; };\n\t\t98CF5434294A714200557BBA /* EidosScribe_multi.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EidosScribe_multi.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98CF5435294A714200557BBA /* EidosScribe_multi-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"EidosScribe_multi-Info.plist\"; path = \"EidosScribe/EidosScribe_multi-Info.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t98CF5451294A725300557BBA /* EidosScribe_multi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = EidosScribe_multi.entitlements; path = EidosScribe/EidosScribe_multi.entitlements; sourceTree = SOURCE_ROOT; };\n\t\t98D218C31B2E213200156FC3 /* EidosTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosTextView.h; sourceTree = \"<group>\"; };\n\t\t98D218C41B2E213200156FC3 /* EidosTextView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosTextView.mm; sourceTree = \"<group>\"; };\n\t\t98D2C3B21F91C56E00E5EB3A /* eidos_test_builtins.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eidos_test_builtins.h; sourceTree = \"<group>\"; };\n\t\t98D4C1B31A6F537B00FFB083 /* SLiMguiLegacy.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SLiMguiLegacy.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98D4C1B61A6F537B00FFB083 /* SLiMguiLegacy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"SLiMguiLegacy-Info.plist\"; path = \"SLiMgui/SLiMguiLegacy-Info.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t98D4C1B71A6F537B00FFB083 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t98D4C1B81A6F537B00FFB083 /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = \"<group>\"; };\n\t\t98D4C1BA1A6F537B00FFB083 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t98D4C1BC1A6F537B00FFB083 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = \"<group>\"; };\n\t\t98D4C1BF1A6F537B00FFB083 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\t98D4C1E51A6FD8D600FFB083 /* change_sex_ratio.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_sex_ratio.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1E71A6FDE6E00FFB083 /* change_selfing_ratio.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_selfing_ratio.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1E91A6FE7FC00FFB083 /* change_size.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_size.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1EB1A6FEAB500FFB083 /* add_subpop.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = add_subpop.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1EC1A6FEAB500FFB083 /* remove_subpop.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = remove_subpop.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1EF1A6FED4000FFB083 /* split_subpop.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = split_subpop.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1F11A6FEEAB00FFB083 /* change_migration.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_migration.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1F31A70040400FFB083 /* play_step.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = play_step.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1F41A70040400FFB083 /* play.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = play.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1F71A70064800FFB083 /* recycle.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = recycle.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1F91A700DC100FFB083 /* play_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = play_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1FA1A700DC100FFB083 /* play_step_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = play_step_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C1FB1A700DC100FFB083 /* recycle_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = recycle_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C2001A70192A00FFB083 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SLiMWindow.xib; sourceTree = \"<group>\"; };\n\t\t98D4C2021A701D5A00FFB083 /* SLiMWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SLiMWindowController.h; sourceTree = \"<group>\"; };\n\t\t98D4C2031A701D5A00FFB083 /* SLiMWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SLiMWindowController.mm; sourceTree = \"<group>\"; };\n\t\t98D4C2051A704EA700FFB083 /* PopulationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopulationView.h; sourceTree = \"<group>\"; };\n\t\t98D4C2061A704EA700FFB083 /* PopulationView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PopulationView.mm; sourceTree = \"<group>\"; };\n\t\t98D4C2081A7086FF00FFB083 /* ChromosomeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChromosomeView.h; sourceTree = \"<group>\"; };\n\t\t98D4C2091A7086FF00FFB083 /* ChromosomeView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ChromosomeView.mm; sourceTree = \"<group>\"; };\n\t\t98D4C20C1A715F6100FFB083 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AboutWindow.xib; sourceTree = \"<group>\"; };\n\t\t98D4C20F1A716E0E00FFB083 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };\n\t\t98D4C2131A71838400FFB083 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/HelpWindow.xib; sourceTree = \"<group>\"; };\n\t\t98D4C2151A7187E200FFB083 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; };\n\t\t98D4C21A1A718EFD00FFB083 /* CocoaExtra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaExtra.h; sourceTree = \"<group>\"; };\n\t\t98D4C21B1A718EFD00FFB083 /* CocoaExtra.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CocoaExtra.mm; sourceTree = \"<group>\"; };\n\t\t98D4C2231A71F8AD00FFB083 /* check_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = check_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C2241A71F8AD00FFB083 /* check.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = check.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C2251A71F8AD00FFB083 /* delete_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = delete_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D4C2261A71F8AD00FFB083 /* delete.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = delete.pdf; sourceTree = \"<group>\"; };\n\t\t98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = prettyprint_H.pdf; sourceTree = \"<group>\"; };\n\t\t98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = prettyprint.pdf; sourceTree = \"<group>\"; };\n\t\t98D524671F2EB4DD005AD9A6 /* EidosPrettyprinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EidosPrettyprinter.h; sourceTree = \"<group>\"; };\n\t\t98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EidosPrettyprinter.mm; sourceTree = \"<group>\"; };\n\t\t98D7D65B2AB24C40002AFE34 /* tdist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tdist.c; sourceTree = \"<group>\"; };\n\t\t98D7D6642AB24CBC002AFE34 /* chisq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chisq.c; sourceTree = \"<group>\"; };\n\t\t98D7EBEE28CE557C00DEAAC4 /* eidos_multi */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = eidos_multi; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98D7ED2D28CE58FC00DEAAC4 /* slim_multi */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = slim_multi; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t98D957882EB53494008314C1 /* pcg_extras.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pcg_extras.hpp; sourceTree = \"<group>\"; };\n\t\t98D957892EB53494008314C1 /* pcg_random.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pcg_random.hpp; sourceTree = \"<group>\"; };\n\t\t98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = interaction_type.cpp; sourceTree = \"<group>\"; };\n\t\t98DB3D6E1E6122AE00E2C200 /* interaction_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interaction_type.h; sourceTree = \"<group>\"; };\n\t\t98DC9838289986B300160DD8 /* GitSHA1.cpp.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GitSHA1.cpp.in; sourceTree = \"<group>\"; };\n\t\t98DC9839289986B300160DD8 /* GetGitRevisionDescription.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GetGitRevisionDescription.cmake; sourceTree = \"<group>\"; };\n\t\t98DC983A289986B300160DD8 /* GetGitRevisionDescription.cmake.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GetGitRevisionDescription.cmake.in; sourceTree = \"<group>\"; };\n\t\t98DC983B289986B300160DD8 /* AboutTheseModules.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AboutTheseModules.cmake; sourceTree = \"<group>\"; };\n\t\t98DC983C289986B300160DD8 /* GitSHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GitSHA1.h; sourceTree = \"<group>\"; };\n\t\t98DC983D289986B300160DD8 /* GitSHA1_Xcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GitSHA1_Xcode.cpp; sourceTree = \"<group>\"; };\n\t\t98DC983E289986B300160DD8 /* LICENSE_1_0.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE_1_0.txt; sourceTree = \"<group>\"; };\n\t\t98DC983F289986B300160DD8 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = \"<group>\"; };\n\t\t98DC9840289986B300160DD8 /* _README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = _README.txt; sourceTree = \"<group>\"; };\n\t\t98DC98512899919A00160DD8 /* GitSHA1_qmake.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GitSHA1_qmake.cpp; sourceTree = \"<group>\"; };\n\t\t98DD5F002155B857009062EE /* change_folder.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_folder.pdf; sourceTree = \"<group>\"; };\n\t\t98DD5F012155B857009062EE /* change_folder_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = change_folder_H.pdf; sourceTree = \"<group>\"; };\n\t\t98DDAED4221765480038C133 /* slim_functions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = slim_functions.cpp; sourceTree = \"<group>\"; };\n\t\t98DDAED5221765480038C133 /* slim_functions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = slim_functions.h; sourceTree = \"<group>\"; };\n\t\t98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_property_signature.cpp; sourceTree = \"<group>\"; };\n\t\t98DE4C121B6F9657004FDF5F /* eidos_property_signature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_property_signature.h; sourceTree = \"<group>\"; };\n\t\t98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = spatial_map.cpp; sourceTree = \"<group>\"; };\n\t\t98DEB47D2AA632AA00ABE60F /* spatial_map.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spatial_map.h; sourceTree = \"<group>\"; };\n\t\t98E6843E2B694F09000B3B65 /* plot.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = plot.mm; sourceTree = \"<group>\"; };\n\t\t98E6843F2B694F09000B3B65 /* plot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plot.h; sourceTree = \"<group>\"; };\n\t\t98E9A6881A3CCFD0000AD4FC /* mutation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutation.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6891A3CCFD0000AD4FC /* mutation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutation.h; sourceTree = \"<group>\"; };\n\t\t98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mutation_type.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A68F1A3CD4CF000AD4FC /* mutation_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mutation_type.h; sourceTree = \"<group>\"; };\n\t\t98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = genomic_element.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6921A3CD4EF000AD4FC /* genomic_element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = genomic_element.h; sourceTree = \"<group>\"; };\n\t\t98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = genomic_element_type.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6951A3CD51A000AD4FC /* genomic_element_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = genomic_element_type.h; sourceTree = \"<group>\"; };\n\t\t98E9A6971A3CD52A000AD4FC /* chromosome.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chromosome.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6981A3CD52A000AD4FC /* chromosome.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chromosome.h; sourceTree = \"<group>\"; };\n\t\t98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = polymorphism.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A69B1A3CD542000AD4FC /* polymorphism.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = polymorphism.h; sourceTree = \"<group>\"; };\n\t\t98E9A69D1A3CD551000AD4FC /* substitution.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = substitution.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A69E1A3CD551000AD4FC /* substitution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = substitution.h; sourceTree = \"<group>\"; };\n\t\t98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = haplosome.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6A71A3CD5A0000AD4FC /* haplosome.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = haplosome.h; sourceTree = \"<group>\"; };\n\t\t98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = subpopulation.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6AA1A3CD5BB000AD4FC /* subpopulation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = subpopulation.h; sourceTree = \"<group>\"; };\n\t\t98E9A6AC1A3CD5D3000AD4FC /* population.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = population.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6AD1A3CD5D3000AD4FC /* population.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = population.h; sourceTree = \"<group>\"; };\n\t\t98E9A6B21A3CE299000AD4FC /* TO_DO */ = {isa = PBXFileReference; lastKnownFileType = text; path = TO_DO; sourceTree = \"<group>\"; };\n\t\t98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_rng.cpp; sourceTree = \"<group>\"; };\n\t\t98E9A6B71A3CE35E000AD4FC /* eidos_rng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_rng.h; sourceTree = \"<group>\"; };\n\t\t98EA965B1ECC2541006BA35B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ProfileReport.xib; sourceTree = \"<group>\"; };\n\t\t98EBCD1221F3CFC600B385CF /* slim_gui.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = slim_gui.mm; sourceTree = \"<group>\"; };\n\t\t98EBCD1321F3CFC600B385CF /* slim_gui.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = slim_gui.h; sourceTree = \"<group>\"; };\n\t\t98EDB4CE2E652F4A00CC8798 /* lu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lu.c; path = linalg/lu.c; sourceTree = \"<group>\"; };\n\t\t98EDB4DF2E65300500CC8798 /* gsl_permute_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_permute_vector.h; sourceTree = \"<group>\"; };\n\t\t98EDB4E02E65326800CC8798 /* gsl_permutation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_permutation.h; sourceTree = \"<group>\"; };\n\t\t98EDB4E12E65340200CC8798 /* gsl_permute_vector_double.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsl_permute_vector_double.h; sourceTree = \"<group>\"; };\n\t\t98EDB4E22E65366E00CC8798 /* daxpy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daxpy.c; path = cblas/daxpy.c; sourceTree = \"<group>\"; };\n\t\t98EDB4EC2E65381500CC8798 /* source_axpy_r.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = source_axpy_r.h; path = cblas/source_axpy_r.h; sourceTree = \"<group>\"; };\n\t\t98EDB4ED2E65389600CC8798 /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = \"<group>\"; };\n\t\t98EDB4F72E6538F200CC8798 /* permutation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = permutation.c; sourceTree = \"<group>\"; };\n\t\t98EDB5012E65399600CC8798 /* permute.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = permute.c; sourceTree = \"<group>\"; };\n\t\t98EDB50B2E6539A500CC8798 /* permute_source.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; path = permute_source.inc; sourceTree = \"<group>\"; };\n\t\t98EDB50C2E653A0300CC8798 /* gsl_permute.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gsl_permute.h; sourceTree = \"<group>\"; };\n\t\t98EDB50D2E653A5300CC8798 /* gsl_permute_double.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gsl_permute_double.h; sourceTree = \"<group>\"; };\n\t\t98EDB50E2E653BA400CC8798 /* gsl_permute_matrix_double.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gsl_permute_matrix_double.h; sourceTree = \"<group>\"; };\n\t\t98EDB50F2E653BA400CC8798 /* gsl_permute_matrix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gsl_permute_matrix.h; sourceTree = \"<group>\"; };\n\t\t98EDB5102E65410C00CC8798 /* copy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = copy.c; path = vector/copy.c; sourceTree = \"<group>\"; };\n\t\t98EDB51A2E65412C00CC8798 /* copy_source.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; name = copy_source.inc; path = vector/copy_source.inc; sourceTree = \"<group>\"; };\n\t\t98EF4AB41ECDA5EA00CCDB09 /* profile_H.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = profile_H.pdf; sourceTree = \"<group>\"; };\n\t\t98EF4AB51ECDA5EA00CCDB09 /* profile.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = profile.pdf; sourceTree = \"<group>\"; };\n\t\t98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eidos_symbol_table.cpp; sourceTree = \"<group>\"; };\n\t\t98EFE62E1ADB611100CBEC78 /* eidos_symbol_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eidos_symbol_table.h; sourceTree = \"<group>\"; };\n\t\t98EFE6331ADD92BC00CBEC78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/EidosAboutWindow.xib; sourceTree = \"<group>\"; };\n\t\t98F65D551DF14DA40058BD29 /* Tips */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Tips; path = SLiMgui/Tips; sourceTree = \"<group>\"; };\n\t\t98FF384D228AFDD900A96440 /* SLiMgui.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SLiMgui.entitlements; sourceTree = \"<group>\"; };\n\t\t98FF384E228AFE1E00A96440 /* EidosScribe.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EidosScribe.entitlements; sourceTree = \"<group>\"; };\n\t\tD05AC1EA20B47EC400FFD319 /* text_input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = text_input.h; path = treerec/tskit/text_input.h; sourceTree = \"<group>\"; };\n\t\tD0A758F620A4CC9800132D2F /* text_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = text_input.c; path = treerec/tskit/text_input.c; sourceTree = \"<group>\"; };\n\t\tD0A758F820A4CCC900132D2F /* trees.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = trees.h; path = treerec/tskit/trees.h; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t982556A61BA8E77B0054CB3F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t9826634D1A3BABD300A0CBBF /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t984D5FA51E3AF0D200473719 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t985724AC1AD478630047C223 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98A240591B8E3295005C9A30 /* Cocoa.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF52A2294A3FC900557BBA /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CF52A3294A3FC900557BBA /* OpenGL.framework in Frameworks */,\n\t\t\t\t98CF52A4294A3FC900557BBA /* Cocoa.framework in Frameworks */,\n\t\t\t\t98CF52A5294A3FC900557BBA /* QuartzCore.framework in Frameworks */,\n\t\t\t\t98CF52A6294A3FC900557BBA /* Quartz.framework in Frameworks */,\n\t\t\t\t98CF52A7294A3FC900557BBA /* WebKit.framework in Frameworks */,\n\t\t\t\t98CF533B294A4B5300557BBA /* libomp.dylib in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF540F294A714200557BBA /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CF5410294A714200557BBA /* Cocoa.framework in Frameworks */,\n\t\t\t\t98330C34294A73AB00B452E2 /* libomp.dylib in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D4C1B01A6F537B00FFB083 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98A2405D1B8E338E005C9A30 /* OpenGL.framework in Frameworks */,\n\t\t\t\t98A2405A1B8E32D0005C9A30 /* Cocoa.framework in Frameworks */,\n\t\t\t\t9821E2041ABDBC300036EAEA /* QuartzCore.framework in Frameworks */,\n\t\t\t\t98D4C2161A7187E200FFB083 /* Quartz.framework in Frameworks */,\n\t\t\t\t98D4C2101A716E0E00FFB083 /* WebKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D7EBE928CE557C00DEAAC4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98760EDD28CE5E7600CEBC40 /* libomp.dylib in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D7ED2828CE58FC00DEAAC4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98760EDE28CE5E8200CEBC40 /* libomp.dylib in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t98076601244934A800F6CBB4 /* eidos_zlib */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98076608244934A800F6CBB4 /* README */,\n\t\t\t\t98076604244934A800F6CBB4 /* ChangeLog */,\n\t\t\t\t9807660C244934A800F6CBB4 /* zlib.h */,\n\t\t\t\t98076613244934A800F6CBB4 /* zconf.h */,\n\t\t\t\t98076611244934A800F6CBB4 /* crc32.h */,\n\t\t\t\t9807662824493A8F00F6CBB4 /* crc32.c */,\n\t\t\t\t98076602244934A800F6CBB4 /* zutil.h */,\n\t\t\t\t98076609244934A800F6CBB4 /* zutil.c */,\n\t\t\t\t98076606244934A800F6CBB4 /* trees.h */,\n\t\t\t\t9807660F244934A800F6CBB4 /* trees.c */,\n\t\t\t\t9807660A244934A800F6CBB4 /* deflate.h */,\n\t\t\t\t98076605244934A800F6CBB4 /* deflate.c */,\n\t\t\t\t9807660B244934A800F6CBB4 /* gzguts.h */,\n\t\t\t\t98076603244934A800F6CBB4 /* compress.c */,\n\t\t\t\t9807660D244934A800F6CBB4 /* gzlib.c */,\n\t\t\t\t9807660E244934A800F6CBB4 /* gzwrite.c */,\n\t\t\t\t98076612244934A800F6CBB4 /* adler32.c */,\n\t\t\t);\n\t\t\tpath = eidos_zlib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t981DC34328E26F09000ABE91 /* dependencies */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9857E33A1BB58DAE00F1C8A9 /* eidos_intrusive_ptr.h */,\n\t\t\t\t985A11861BBA07CB009EE1FF /* eidos_object_pool.h */,\n\t\t\t\t9809F8BD24F32B3E00D312E4 /* eidos_tinycolormap.h */,\n\t\t\t\t98729ACD2A87A93500E81662 /* eidos_sorting.h */,\n\t\t\t\t98729AD72A87DFBE00E81662 /* eidos_sorting.cpp */,\n\t\t\t\t98729ACE2A87AAB700E81662 /* eidos_sorting.inc */,\n\t\t\t\t9893C7DC1CDA2D650029AC94 /* eidos_beep.h */,\n\t\t\t\t9893C7DB1CDA2D650029AC94 /* eidos_beep.cpp */,\n\t\t\t\t98B8AF8725A2BE7200C95D66 /* json_fwd.hpp */,\n\t\t\t\t98B8AF8625A2BE7200C95D66 /* json.hpp */,\n\t\t\t\t98235687252FDD120096A745 /* lodepng.h */,\n\t\t\t\t98235681252FDCF50096A745 /* lodepng.cpp */,\n\t\t\t\t98186DB8254A8B1600F9118C /* robin_hood.h */,\n\t\t\t\t98D957882EB53494008314C1 /* pcg_extras.hpp */,\n\t\t\t\t98D957892EB53494008314C1 /* pcg_random.hpp */,\n\t\t\t);\n\t\t\tname = dependencies;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t981DC34428E26F10000ABE91 /* unit tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t989790D91AF3D0E100C6B14C /* eidos_class_TestElement.h */,\n\t\t\t\t989790D81AF3D0E100C6B14C /* eidos_class_TestElement.cpp */,\n\t\t\t\t985724A81AD4551C0047C223 /* eidos_test.h */,\n\t\t\t\t985724A71AD4551C0047C223 /* eidos_test.cpp */,\n\t\t\t\t985F3F0024BA307200E712E0 /* eidos_test_operators_arithmetic.cpp */,\n\t\t\t\t985F3F0524BA310100E712E0 /* eidos_test_operators_comparison.cpp */,\n\t\t\t\t985F3EEC24BA2A5D00E712E0 /* eidos_test_operators_other.cpp */,\n\t\t\t\t985F3EF624BA2DD300E712E0 /* eidos_test_functions_math.cpp */,\n\t\t\t\t985F3F0A24BA31D900E712E0 /* eidos_test_functions_statistics.cpp */,\n\t\t\t\t985F3EFB24BA2F1500E712E0 /* eidos_test_functions_vector.cpp */,\n\t\t\t\t985F3EF124BA2A8C00E712E0 /* eidos_test_functions_other.cpp */,\n\t\t\t\t98D2C3B21F91C56E00E5EB3A /* eidos_test_builtins.h */,\n\t\t\t\t98330C48294AB34300B452E2 /* eidos_test_parallel.h */,\n\t\t\t);\n\t\t\tname = \"unit tests\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t981DC34528E26F17000ABE91 /* Eidos classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98ACDCA2253522D40038703F /* eidos_class_Object.h */,\n\t\t\t\t98ACDC9C253522B80038703F /* eidos_class_Object.cpp */,\n\t\t\t\t98ACDC9B2534CA120038703F /* eidos_class_Dictionary.h */,\n\t\t\t\t989A5BE82525304100E7192D /* eidos_class_Dictionary.cpp */,\n\t\t\t\t9890D1EC27136BB7001EAE98 /* eidos_class_DataFrame.h */,\n\t\t\t\t9890D1EB27136BB7001EAE98 /* eidos_class_DataFrame.cpp */,\n\t\t\t\t9823568E252FE62F0096A745 /* eidos_class_Image.h */,\n\t\t\t\t98235688252FE61A0096A745 /* eidos_class_Image.cpp */,\n\t\t\t);\n\t\t\tname = \"Eidos classes\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t981DC34628E26F1E000ABE91 /* Eidos functions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t985724A01AD34B740047C223 /* eidos_functions.h */,\n\t\t\t\t9857249F1AD34B740047C223 /* eidos_functions.cpp */,\n\t\t\t\t981DC34828E26F8A000ABE91 /* eidos_functions_math.cpp */,\n\t\t\t\t981DC34F28E26F8B000ABE91 /* eidos_functions_stats.cpp */,\n\t\t\t\t981DC34C28E26F8A000ABE91 /* eidos_functions_distributions.cpp */,\n\t\t\t\t981DC34B28E26F8A000ABE91 /* eidos_functions_values.cpp */,\n\t\t\t\t981DC34D28E26F8A000ABE91 /* eidos_functions_strings.cpp */,\n\t\t\t\t981DC34A28E26F8A000ABE91 /* eidos_functions_matrices.cpp */,\n\t\t\t\t981DC34728E26F8A000ABE91 /* eidos_functions_files.cpp */,\n\t\t\t\t981DC34928E26F8A000ABE91 /* eidos_functions_colors.cpp */,\n\t\t\t\t981DC34E28E26F8B000ABE91 /* eidos_functions_other.cpp */,\n\t\t\t);\n\t\t\tname = \"Eidos functions\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982556AA1BA8E77C0054CB3F /* eidostool */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t982556AB1BA8E77C0054CB3F /* main.cpp */,\n\t\t\t);\n\t\t\tpath = eidostool;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982663471A3BABD300A0CBBF = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t985DCFD52B1ED7340025B0D5 /* PARALLEL */,\n\t\t\t\t98E9A6B21A3CE299000AD4FC /* TO_DO */,\n\t\t\t\t986021081A3BB504001BDCFE /* LICENSE */,\n\t\t\t\t98AF84641CB307300030D1EB /* VERSIONS */,\n\t\t\t\t98DC9837289986B300160DD8 /* cmake */,\n\t\t\t\t98C820E01C7A980000548839 /* gsl */,\n\t\t\t\t98BCF14F200C5FDB00CB2837 /* treerec */,\n\t\t\t\t98076601244934A800F6CBB4 /* eidos_zlib */,\n\t\t\t\t9857249E1AD34B120047C223 /* eidos */,\n\t\t\t\t982663521A3BABD300A0CBBF /* core */,\n\t\t\t\t982556AA1BA8E77C0054CB3F /* eidostool */,\n\t\t\t\t985724B01AD478630047C223 /* EidosScribe */,\n\t\t\t\t98D4C1B41A6F537B00FFB083 /* SLiMgui */,\n\t\t\t\t98A2FF881D7DF4D7007E3DB8 /* Recipes */,\n\t\t\t\t98F65D551DF14DA40058BD29 /* Tips */,\n\t\t\t\t989F495127DBB7D600B07B7D /* QtSLiM */,\n\t\t\t\t98A2405B1B8E32F4005C9A30 /* Shared Frameworks */,\n\t\t\t\t984D5FA91E3AF0D200473719 /* EidosSLiMTests */,\n\t\t\t\t982663511A3BABD300A0CBBF /* Products */,\n\t\t\t\t98760EDB28CE5E7600CEBC40 /* Frameworks */,\n\t\t\t\t980B6A6428CE642D0075B192 /* eidos_multi.entitlements */,\n\t\t\t\t980B6A6528CE64310075B192 /* slim_multi.entitlements */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982663511A3BABD300A0CBBF /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t982663501A3BABD300A0CBBF /* slim */,\n\t\t\t\t98D4C1B31A6F537B00FFB083 /* SLiMguiLegacy.app */,\n\t\t\t\t985724AF1AD478630047C223 /* EidosScribe.app */,\n\t\t\t\t982556A91BA8E77B0054CB3F /* eidos */,\n\t\t\t\t984D5FA81E3AF0D200473719 /* EidosSLiMTests.xctest */,\n\t\t\t\t98D7EBEE28CE557C00DEAAC4 /* eidos_multi */,\n\t\t\t\t98D7ED2D28CE58FC00DEAAC4 /* slim_multi */,\n\t\t\t\t98CF5301294A3FC900557BBA /* SLiMguiLegacy_multi.app */,\n\t\t\t\t98CF5434294A714200557BBA /* EidosScribe_multi.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982663521A3BABD300A0CBBF /* core */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t982663531A3BABD300A0CBBF /* main.cpp */,\n\t\t\t\t9898172E1A59750300F7417C /* slim_globals.h */,\n\t\t\t\t9898172D1A59750300F7417C /* slim_globals.cpp */,\n\t\t\t\t98DDAED5221765480038C133 /* slim_functions.h */,\n\t\t\t\t98DDAED4221765480038C133 /* slim_functions.cpp */,\n\t\t\t\t98AB597A1B2531F10077CB4A /* slim_eidos_block.h */,\n\t\t\t\t98AB59791B2531F10077CB4A /* slim_eidos_block.cpp */,\n\t\t\t\t9836867327CD40CF00683639 /* community.h */,\n\t\t\t\t9836867227CD40CF00683639 /* community.cpp */,\n\t\t\t\t9836868027CD72E900683639 /* community_eidos.cpp */,\n\t\t\t\t9878A93E1A4E57E70007B9D6 /* species.h */,\n\t\t\t\t9878A93D1A4E57E70007B9D6 /* species.cpp */,\n\t\t\t\t98AC617924BA34ED0001914C /* species_eidos.cpp */,\n\t\t\t\t98E9A6981A3CD52A000AD4FC /* chromosome.h */,\n\t\t\t\t98E9A6971A3CD52A000AD4FC /* chromosome.cpp */,\n\t\t\t\t98E9A6AD1A3CD5D3000AD4FC /* population.h */,\n\t\t\t\t98E9A6AC1A3CD5D3000AD4FC /* population.cpp */,\n\t\t\t\t98E9A6AA1A3CD5BB000AD4FC /* subpopulation.h */,\n\t\t\t\t98E9A6A91A3CD5BB000AD4FC /* subpopulation.cpp */,\n\t\t\t\t98C92AEC1D0B07A6001C82BC /* individual.h */,\n\t\t\t\t98C92AEB1D0B07A6001C82BC /* individual.cpp */,\n\t\t\t\t98E9A6A71A3CD5A0000AD4FC /* haplosome.h */,\n\t\t\t\t98E9A6A61A3CD5A0000AD4FC /* haplosome.cpp */,\n\t\t\t\t98606AED1DED0DCD00821CFF /* mutation_run.h */,\n\t\t\t\t98606AEC1DED0DCD00821CFF /* mutation_run.cpp */,\n\t\t\t\t98E9A6891A3CCFD0000AD4FC /* mutation.h */,\n\t\t\t\t98E9A6881A3CCFD0000AD4FC /* mutation.cpp */,\n\t\t\t\t98E9A69E1A3CD551000AD4FC /* substitution.h */,\n\t\t\t\t98E9A69D1A3CD551000AD4FC /* substitution.cpp */,\n\t\t\t\t98E9A6921A3CD4EF000AD4FC /* genomic_element.h */,\n\t\t\t\t98E9A6911A3CD4EF000AD4FC /* genomic_element.cpp */,\n\t\t\t\t98E9A6951A3CD51A000AD4FC /* genomic_element_type.h */,\n\t\t\t\t98E9A6941A3CD51A000AD4FC /* genomic_element_type.cpp */,\n\t\t\t\t98E9A68F1A3CD4CF000AD4FC /* mutation_type.h */,\n\t\t\t\t98E9A68E1A3CD4CF000AD4FC /* mutation_type.cpp */,\n\t\t\t\t98E9A69B1A3CD542000AD4FC /* polymorphism.h */,\n\t\t\t\t98E9A69A1A3CD542000AD4FC /* polymorphism.cpp */,\n\t\t\t\t985D1D8A2808B84F00461CFA /* sparse_vector.h */,\n\t\t\t\t985D1D892808B84F00461CFA /* sparse_vector.cpp */,\n\t\t\t\t986070E92AACECD600FD6143 /* spatial_kernel.h */,\n\t\t\t\t986070E82AACECD600FD6143 /* spatial_kernel.cpp */,\n\t\t\t\t98DB3D6E1E6122AE00E2C200 /* interaction_type.h */,\n\t\t\t\t98DB3D6D1E6122AE00E2C200 /* interaction_type.cpp */,\n\t\t\t\t98DEB47D2AA632AA00ABE60F /* spatial_map.h */,\n\t\t\t\t98DEB47C2AA632AA00ABE60F /* spatial_map.cpp */,\n\t\t\t\t9809DF9F2550F32500C4E82D /* log_file.h */,\n\t\t\t\t9809DF9E2550F32500C4E82D /* log_file.cpp */,\n\t\t\t\t98800DC31B7EDCB50046F5F9 /* slim_test.h */,\n\t\t\t\t98800DC21B7EDCB50046F5F9 /* slim_test.cpp */,\n\t\t\t\t9807C0F324BA21B7008CC658 /* slim_test_core.cpp */,\n\t\t\t\t985F3EE924BA27EC00E712E0 /* slim_test_genetics.cpp */,\n\t\t\t\t9807C0F724BA21E3008CC658 /* slim_test_other.cpp */,\n\t\t\t\t984F20AF298087850079D4D2 /* slim_test_parallel.h */,\n\t\t\t);\n\t\t\tpath = core;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AA41FDB996800274FF0 /* matrix */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AA51FDB997E00274FF0 /* gsl_matrix.h */,\n\t\t\t\t98332AA91FDB9B5100274FF0 /* gsl_matrix_double.h */,\n\t\t\t\t98332AF01FDBC30100274FF0 /* view.h */,\n\t\t\t\t98332AFB1FDBC4B200274FF0 /* matrix.c */,\n\t\t\t\t98332B151FDBD13D00274FF0 /* copy_source.inc */,\n\t\t\t\t98332B161FDBD13D00274FF0 /* copy.c */,\n\t\t\t\t98332B001FDBCFC300274FF0 /* init_source.inc */,\n\t\t\t\t98332B011FDBCFC300274FF0 /* init.c */,\n\t\t\t\t98332AEB1FDBC1F600274FF0 /* rowcol_source.inc */,\n\t\t\t\t98332AE31FDBC1D900274FF0 /* rowcol.c */,\n\t\t\t\t98332AE41FDBC1D900274FF0 /* submatrix_source.inc */,\n\t\t\t\t98332AE51FDBC1D900274FF0 /* submatrix.c */,\n\t\t\t\t98332AF41FDBC3F100274FF0 /* swap_source.inc */,\n\t\t\t\t98332AF51FDBC3F100274FF0 /* swap.c */,\n\t\t\t);\n\t\t\tname = matrix;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AA61FDB998700274FF0 /* vector */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AA71FDB99AA00274FF0 /* gsl_vector.h */,\n\t\t\t\t98332AA81FDB9B3F00274FF0 /* gsl_vector_double.h */,\n\t\t\t\t98332AC61FDBA6B600274FF0 /* vector.c */,\n\t\t\t\t98EDB51A2E65412C00CC8798 /* copy_source.inc */,\n\t\t\t\t98EDB5102E65410C00CC8798 /* copy.c */,\n\t\t\t\t98332B071FDBD00800274FF0 /* init_source.inc */,\n\t\t\t\t98332B081FDBD00800274FF0 /* init.c */,\n\t\t\t\t98332ACB1FDBA81A00274FF0 /* oper_source.inc */,\n\t\t\t\t98332ACC1FDBA81A00274FF0 /* oper.c */,\n\t\t\t\t98CEFD912AAFB58100D2C9B4 /* view_source.inc */,\n\t\t\t\t98CEFD902AAFB55500D2C9B4 /* view.h */,\n\t\t\t\t98CEFD872AAFB4EF00D2C9B4 /* view.c */,\n\t\t\t);\n\t\t\tname = vector;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AAA1FDB9C6D00274FF0 /* block */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AAB1FDB9C7C00274FF0 /* gsl_block_double.h */,\n\t\t\t\t98332AAC1FDB9C7C00274FF0 /* gsl_block.h */,\n\t\t\t\t98332AAD1FDB9C7C00274FF0 /* gsl_check_range.h */,\n\t\t\t\t98332B0E1FDBD09800274FF0 /* init_source.inc */,\n\t\t\t\t98332B0F1FDBD09800274FF0 /* init.c */,\n\t\t\t);\n\t\t\tname = block;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AAE1FDB9E0000274FF0 /* blas */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AB31FDBA1E100274FF0 /* blas.c */,\n\t\t\t\t98332AAF1FDB9E1500274FF0 /* gsl_blas.h */,\n\t\t\t\t98332AB01FDB9FA600274FF0 /* gsl_blas_types.h */,\n\t\t\t);\n\t\t\tname = blas;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AB11FDB9FF000274FF0 /* cblas */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AB21FDBA00000274FF0 /* gsl_cblas.h */,\n\t\t\t\t98332ABD1FDBA36500274FF0 /* cblas.h */,\n\t\t\t\t98332ABF1FDBA3D700274FF0 /* error_cblas.h */,\n\t\t\t\t98332ABE1FDBA3A700274FF0 /* error_cblas_l2.h */,\n\t\t\t\t98EDB4EC2E65381500CC8798 /* source_axpy_r.h */,\n\t\t\t\t984824EF210B9EE6002402A5 /* source_dot_r.h */,\n\t\t\t\t98332AE01FDBC11000274FF0 /* source_gemv_r.h */,\n\t\t\t\t98332AC01FDBA41100274FF0 /* source_trmv_r.h */,\n\t\t\t\t984824F8210B9F63002402A5 /* source_trsv_r.h */,\n\t\t\t\t98332AC11FDBA53F00274FF0 /* xerbla.c */,\n\t\t\t\t98EDB4E22E65366E00CC8798 /* daxpy.c */,\n\t\t\t\t984824ED210B9E8F002402A5 /* ddot.c */,\n\t\t\t\t98332ADB1FDBC0D000274FF0 /* dgemv.c */,\n\t\t\t\t98332AB81FDBA32200274FF0 /* dtrmv.c */,\n\t\t\t\t984824F0210B9F23002402A5 /* dtrsv.c */,\n\t\t\t);\n\t\t\tname = cblas;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98332AD41FDBBCC600274FF0 /* linalg */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98332AD61FDBBD1600274FF0 /* gsl_linalg.h */,\n\t\t\t\t98332AD51FDBBD1600274FF0 /* cholesky.c */,\n\t\t\t\t98EDB4CE2E652F4A00CC8798 /* lu.c */,\n\t\t\t\t98CEFD862AAFB24700D2C9B4 /* tridiag.h */,\n\t\t\t\t98CEFD7D2AAFB23E00D2C9B4 /* tridiag.c */,\n\t\t\t);\n\t\t\tname = linalg;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t984D5FA91E3AF0D200473719 /* EidosSLiMTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t984D5FB41E3AF1F000473719 /* SLiMTests.mm */,\n\t\t\t\t984D5FB21E3AF18C00473719 /* EidosTests.mm */,\n\t\t\t\t984D5FAC1E3AF0D200473719 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = EidosSLiMTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9857249E1AD34B120047C223 /* eidos */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9873B12328CE26CD00582D83 /* eidos_openmp.h */,\n\t\t\t\t987D30EA2EF482AA0096621B /* eidos_simd.h */,\n\t\t\t\t98E9A6B71A3CE35E000AD4FC /* eidos_rng.h */,\n\t\t\t\t98E9A6B61A3CE35E000AD4FC /* eidos_rng.cpp */,\n\t\t\t\t98321F931B406B67007337A3 /* eidos_globals.h */,\n\t\t\t\t98321F921B406B67007337A3 /* eidos_globals.cpp */,\n\t\t\t\t98A5134E1B66B69E005A753D /* eidos_token.h */,\n\t\t\t\t98A5134D1B66B69E005A753D /* eidos_token.cpp */,\n\t\t\t\t98A513531B66B6CA005A753D /* eidos_ast_node.h */,\n\t\t\t\t98A513521B66B6CA005A753D /* eidos_ast_node.cpp */,\n\t\t\t\t981BAC691ACC6E8B0005BE94 /* eidos_script.h */,\n\t\t\t\t981BAC681ACC6E8B0005BE94 /* eidos_script.cpp */,\n\t\t\t\t98EFE62E1ADB611100CBEC78 /* eidos_symbol_table.h */,\n\t\t\t\t98EFE62D1ADB611100CBEC78 /* eidos_symbol_table.cpp */,\n\t\t\t\t985724A41AD435310047C223 /* eidos_value.h */,\n\t\t\t\t985724A31AD435310047C223 /* eidos_value.cpp */,\n\t\t\t\t986D73E71B07E89E007FBB70 /* eidos_call_signature.h */,\n\t\t\t\t986D73E61B07E89E007FBB70 /* eidos_call_signature.cpp */,\n\t\t\t\t98DE4C121B6F9657004FDF5F /* eidos_property_signature.h */,\n\t\t\t\t98DE4C111B6F9657004FDF5F /* eidos_property_signature.cpp */,\n\t\t\t\t9857249B1AD08A810047C223 /* eidos_interpreter.h */,\n\t\t\t\t9857249A1AD08A810047C223 /* eidos_interpreter.cpp */,\n\t\t\t\t9893C7E21CDFCF0D0029AC94 /* eidos_type_table.h */,\n\t\t\t\t9893C7E11CDFCF0D0029AC94 /* eidos_type_table.cpp */,\n\t\t\t\t9893C7E81CDFE9870029AC94 /* eidos_type_interpreter.h */,\n\t\t\t\t9893C7E71CDFE9870029AC94 /* eidos_type_interpreter.cpp */,\n\t\t\t\t981DC34628E26F1E000ABE91 /* Eidos functions */,\n\t\t\t\t981DC34528E26F17000ABE91 /* Eidos classes */,\n\t\t\t\t981DC34428E26F10000ABE91 /* unit tests */,\n\t\t\t\t981DC34328E26F09000ABE91 /* dependencies */,\n\t\t\t);\n\t\t\tpath = eidos;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t985724B01AD478630047C223 /* EidosScribe */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t985724B31AD478630047C223 /* EidosAppDelegate.h */,\n\t\t\t\t985724B41AD478630047C223 /* EidosAppDelegate.mm */,\n\t\t\t\t9825565D1BA32F030054CB3F /* EidosCocoaExtra.h */,\n\t\t\t\t9825565A1BA32EE80054CB3F /* EidosCocoaExtra.mm */,\n\t\t\t\t98D218C31B2E213200156FC3 /* EidosTextView.h */,\n\t\t\t\t98A02F931BA1E3E1002DDE54 /* EidosTextViewDelegate.h */,\n\t\t\t\t98D218C41B2E213200156FC3 /* EidosTextView.mm */,\n\t\t\t\t985724E51AD622880047C223 /* EidosConsoleTextView.h */,\n\t\t\t\t982556621BA35DF00054CB3F /* EidosConsoleTextViewDelegate.h */,\n\t\t\t\t985724E61AD622880047C223 /* EidosConsoleTextView.mm */,\n\t\t\t\t987AD8881B2CDBB80035D6C8 /* EidosConsoleWindowController.h */,\n\t\t\t\t98A02F941BA1E648002DDE54 /* EidosConsoleWindowControllerDelegate.h */,\n\t\t\t\t987AD8891B2CDBB80035D6C8 /* EidosConsoleWindowController.mm */,\n\t\t\t\t987AD8841B2CC0C10035D6C8 /* EidosVariableBrowserController.h */,\n\t\t\t\t9825565E1BA358EC0054CB3F /* EidosVariableBrowserControllerDelegate.h */,\n\t\t\t\t987AD8851B2CC0C10035D6C8 /* EidosVariableBrowserController.mm */,\n\t\t\t\t98090FA41B1B978900791DBF /* EidosValueWrapper.h */,\n\t\t\t\t98090FA51B1B978900791DBF /* EidosValueWrapper.mm */,\n\t\t\t\t982556631BA450980054CB3F /* EidosHelpController.h */,\n\t\t\t\t982556641BA450980054CB3F /* EidosHelpController.mm */,\n\t\t\t\t98D524671F2EB4DD005AD9A6 /* EidosPrettyprinter.h */,\n\t\t\t\t98D524681F2EB4DD005AD9A6 /* EidosPrettyprinter.mm */,\n\t\t\t\t985724B81AD478630047C223 /* Images.xcassets */,\n\t\t\t\t985724BA1AD478630047C223 /* MainMenu.xib */,\n\t\t\t\t98EFE6321ADD92BC00CBEC78 /* EidosAboutWindow.xib */,\n\t\t\t\t98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */,\n\t\t\t\t982556671BA451D00054CB3F /* EidosHelpWindow.xib */,\n\t\t\t\t9825566B1BA477D60054CB3F /* EidosHelpFunctions.rtf */,\n\t\t\t\t9825569F1BA5DFEB0054CB3F /* EidosHelpClasses.rtf */,\n\t\t\t\t9892282A1BAE279700429674 /* EidosHelpOperators.rtf */,\n\t\t\t\t9892282D1BAE27AA00429674 /* EidosHelpTypes.rtf */,\n\t\t\t\t989228301BAF496C00429674 /* EidosHelpStatements.rtf */,\n\t\t\t\t98A4EC911B67C02000CD92FD /* buttons */,\n\t\t\t\t985724B11AD478630047C223 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = EidosScribe;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t985724B11AD478630047C223 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t985724B21AD478630047C223 /* EidosScribe-Info.plist */,\n\t\t\t\t98CF5435294A714200557BBA /* EidosScribe_multi-Info.plist */,\n\t\t\t\t98FF384E228AFE1E00A96440 /* EidosScribe.entitlements */,\n\t\t\t\t98CF5451294A725300557BBA /* EidosScribe_multi.entitlements */,\n\t\t\t\t985724B61AD478630047C223 /* main.m */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t986926D61AA13D340000E138 /* Graphing */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98E6843F2B694F09000B3B65 /* plot.h */,\n\t\t\t\t98E6843E2B694F09000B3B65 /* plot.mm */,\n\t\t\t\t986926D71AA140550000E138 /* GraphView.h */,\n\t\t\t\t986926D81AA140550000E138 /* GraphView.mm */,\n\t\t\t\t986926DD1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.h */,\n\t\t\t\t986926DE1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm */,\n\t\t\t\t986926E01AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.h */,\n\t\t\t\t986926E11AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm */,\n\t\t\t\t986926E31AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.h */,\n\t\t\t\t986926E41AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm */,\n\t\t\t\t986926E61AA40AFF0000E138 /* GraphView_FitnessOverTime.h */,\n\t\t\t\t986926E71AA40AFF0000E138 /* GraphView_FitnessOverTime.mm */,\n\t\t\t\t986926E91AA6B7480000E138 /* GraphView_PopulationVisualization.h */,\n\t\t\t\t986926EA1AA6B7480000E138 /* GraphView_PopulationVisualization.mm */,\n\t\t\t\t980DD51B1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.h */,\n\t\t\t\t980DD51C1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm */,\n\t\t\t\t986926DA1AA1429D0000E138 /* GraphWindow.xib */,\n\t\t\t\t980DD5181AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib */,\n\t\t\t\t982A9DDC1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib */,\n\t\t\t);\n\t\t\tname = Graphing;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98760EDB28CE5E7600CEBC40 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98760EDC28CE5E7600CEBC40 /* libomp.dylib */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9876E5F21ED5571C00FF9762 /* cdf */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t987A2A0524033856009A636F /* gaussinv.c */,\n\t\t\t\t987A2A0624033856009A636F /* rat_eval.h */,\n\t\t\t\t9876E5F31ED5572C00FF9762 /* gsl_cdf.h */,\n\t\t\t\t9876E5F91ED557B000FF9762 /* beta_inc.inc */,\n\t\t\t\t9876E5FB1ED5599F00FF9762 /* gauss.c */,\n\t\t\t\t9876E5F41ED5572C00FF9762 /* tdist.c */,\n\t\t\t);\n\t\t\tname = cdf;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t987D19A2209A535E0030D28D /* kastore */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t987D19A3209A53850030D28D /* kastore.h */,\n\t\t\t\t987D19A4209A53850030D28D /* kastore.c */,\n\t\t\t);\n\t\t\tname = kastore;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t988794681EA87FC300AE0C8D /* PDF */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t988794691EA8804900AE0C8D /* SLiMPDFDocument.h */,\n\t\t\t\t9887946A1EA8804900AE0C8D /* SLiMPDFDocument.mm */,\n\t\t\t\t9887946C1EA8808000AE0C8D /* SLiMPDFWindowController.h */,\n\t\t\t\t9887946D1EA8808000AE0C8D /* SLiMPDFWindowController.mm */,\n\t\t\t\t988794711EA8C42200AE0C8D /* SLiMPDFView.h */,\n\t\t\t\t988794721EA8C42200AE0C8D /* SLiMPDFView.mm */,\n\t\t\t\t9887946E1EA8808000AE0C8D /* SLiMPDFWindow.xib */,\n\t\t\t);\n\t\t\tname = PDF;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98A2405B1B8E32F4005C9A30 /* Shared Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98A240581B8E3295005C9A30 /* Cocoa.framework */,\n\t\t\t);\n\t\t\tname = \"Shared Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98A4EC911B67C02000CD92FD /* buttons */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98090FA01B1B8B5800791DBF /* show_browser_H.pdf */,\n\t\t\t\t98090FA11B1B8B5800791DBF /* show_browser.pdf */,\n\t\t\t\t98D4C2231A71F8AD00FFB083 /* check_H.pdf */,\n\t\t\t\t98D4C2241A71F8AD00FFB083 /* check.pdf */,\n\t\t\t\t98D524611F2E6AFB005AD9A6 /* prettyprint_H.pdf */,\n\t\t\t\t98D524621F2E6AFB005AD9A6 /* prettyprint.pdf */,\n\t\t\t\t98D4C2251A71F8AD00FFB083 /* delete_H.pdf */,\n\t\t\t\t98D4C2261A71F8AD00FFB083 /* delete.pdf */,\n\t\t\t\t985724DE1AD4C3310047C223 /* execute_script_H.pdf */,\n\t\t\t\t985724DF1AD4C3310047C223 /* execute_script.pdf */,\n\t\t\t\t985724E81AD6B9FE0047C223 /* execute_selection_H.pdf */,\n\t\t\t\t985724E91AD6B9FE0047C223 /* execute_selection.pdf */,\n\t\t\t\t98453F421A75AABE00C058CB /* syntax_help_H.pdf */,\n\t\t\t\t98453F431A75AABE00C058CB /* syntax_help.pdf */,\n\t\t\t\t985724EC1AD6D4060047C223 /* show_parse_H.pdf */,\n\t\t\t\t985724ED1AD6D4060047C223 /* show_parse.pdf */,\n\t\t\t\t985724EE1AD6D4060047C223 /* show_tokens_H.pdf */,\n\t\t\t\t985724EF1AD6D4060047C223 /* show_tokens.pdf */,\n\t\t\t\t985724F41AD6DD470047C223 /* show_execution_H.pdf */,\n\t\t\t\t985724F51AD6DD470047C223 /* show_execution.pdf */,\n\t\t\t);\n\t\t\tpath = buttons;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98BCF14F200C5FDB00CB2837 /* treerec */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t987D19A2209A535E0030D28D /* kastore */,\n\t\t\t\t9854D25A2278B9F8001D43BC /* convert.h */,\n\t\t\t\t9854D2592278B9F8001D43BC /* convert.c */,\n\t\t\t\t9854D25E2278B9F8001D43BC /* core.h */,\n\t\t\t\t9854D2562278B9F7001D43BC /* core.c */,\n\t\t\t\t9854D2582278B9F7001D43BC /* genotypes.h */,\n\t\t\t\t9854D2572278B9F7001D43BC /* genotypes.c */,\n\t\t\t\t9854D25C2278B9F8001D43BC /* stats.h */,\n\t\t\t\t9854D25B2278B9F8001D43BC /* stats.c */,\n\t\t\t\tD05AC1EA20B47EC400FFD319 /* text_input.h */,\n\t\t\t\tD0A758F620A4CC9800132D2F /* text_input.c */,\n\t\t\t\t986764A92089066A00E81B2E /* tables.h */,\n\t\t\t\t9850D8DF2063098E006BFD2E /* tables.c */,\n\t\t\t\tD0A758F820A4CCC900132D2F /* trees.h */,\n\t\t\t\t9854D25D2278B9F8001D43BC /* trees.c */,\n\t\t\t);\n\t\t\tname = treerec;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C820E01C7A980000548839 /* gsl */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98833AEA1C7A9E8D0072DBAC /* _README */,\n\t\t\t\t98833AEB1C7A9E8D0072DBAC /* AUTHORS */,\n\t\t\t\t98833AEC1C7A9E8D0072DBAC /* COPYING */,\n\t\t\t\t98833AED1C7A9E8D0072DBAC /* README */,\n\t\t\t\t98833AEE1C7A9E8D0072DBAC /* THANKS */,\n\t\t\t\t98C820E11C7A980000548839 /* build.h */,\n\t\t\t\t98C820E71C7A980000548839 /* config.h */,\n\t\t\t\t98C820ED1C7A980000548839 /* gsl_errno.h */,\n\t\t\t\t98C820EE1C7A980000548839 /* gsl_inline.h */,\n\t\t\t\t98C820EF1C7A980000548839 /* gsl_machine.h */,\n\t\t\t\t98C820F01C7A980000548839 /* gsl_math.h */,\n\t\t\t\t98C820F11C7A980000548839 /* gsl_minmax.h */,\n\t\t\t\t98C820F21C7A980000548839 /* gsl_nan.h */,\n\t\t\t\t98C820F31C7A980000548839 /* gsl_pow_int.h */,\n\t\t\t\t98C820F41C7A980000548839 /* gsl_precision.h */,\n\t\t\t\t98C820F51C7A980000548839 /* gsl_types.h */,\n\t\t\t\t98332AD21FDBA8B500274FF0 /* templates_off.h */,\n\t\t\t\t98332AD31FDBA8B500274FF0 /* templates_on.h */,\n\t\t\t\t98332AAE1FDB9E0000274FF0 /* blas */,\n\t\t\t\t98332AAA1FDB9C6D00274FF0 /* block */,\n\t\t\t\t98332AB11FDB9FF000274FF0 /* cblas */,\n\t\t\t\t9876E5F21ED5571C00FF9762 /* cdf */,\n\t\t\t\t98C820E21C7A980000548839 /* complex */,\n\t\t\t\t98C820E81C7A980000548839 /* err */,\n\t\t\t\t98CEFCD32AAFABAA00D2C9B4 /* interpolation */,\n\t\t\t\t98332AD41FDBBCC600274FF0 /* linalg */,\n\t\t\t\t98332AA41FDB996800274FF0 /* matrix */,\n\t\t\t\t98EDB4DE2E65300500CC8798 /* permutation */,\n\t\t\t\t98C820F61C7A980000548839 /* randist */,\n\t\t\t\t98C821021C7A980000548839 /* rng */,\n\t\t\t\t98C821081C7A980000548839 /* specfunc */,\n\t\t\t\t98C8211F1C7A980000548839 /* sys */,\n\t\t\t\t98332AA61FDB998700274FF0 /* vector */,\n\t\t\t);\n\t\t\tpath = gsl;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C820E21C7A980000548839 /* complex */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C820E31C7A980000548839 /* gsl_complex.h */,\n\t\t\t\t98C820E41C7A980000548839 /* gsl_complex_math.h */,\n\t\t\t\t98C820E51C7A980000548839 /* inline.c */,\n\t\t\t\t98C820E61C7A980000548839 /* math.c */,\n\t\t\t);\n\t\t\tpath = complex;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C820E81C7A980000548839 /* err */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C820EA1C7A980000548839 /* gsl_message.h */,\n\t\t\t\t98C820E91C7A980000548839 /* error.c */,\n\t\t\t\t98C820EB1C7A980000548839 /* message.c */,\n\t\t\t\t98C820EC1C7A980000548839 /* stream.c */,\n\t\t\t);\n\t\t\tpath = err;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C820F61C7A980000548839 /* randist */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C820FD1C7A980000548839 /* gsl_randist.h */,\n\t\t\t\t98C820F71C7A980000548839 /* beta.c */,\n\t\t\t\t98C820F81C7A980000548839 /* binomial_tpe.c */,\n\t\t\t\t988880EB20744EE800E10172 /* cauchy.c */,\n\t\t\t\t98D7D6642AB24CBC002AFE34 /* chisq.c */,\n\t\t\t\t98C634432EF9F632003F12A3 /* dirichlet.c */,\n\t\t\t\t98C821A71C7A9B1600548839 /* discrete.c */,\n\t\t\t\t98C820F91C7A980000548839 /* exponential.c */,\n\t\t\t\t980566E125A7C5B9008D3C7F /* fdist.c */,\n\t\t\t\t98C820FA1C7A980000548839 /* gamma.c */,\n\t\t\t\t98C820FB1C7A980000548839 /* gauss.c */,\n\t\t\t\t98C820FC1C7A980000548839 /* gausszig.c */,\n\t\t\t\t98C821A81C7A9B1600548839 /* geometric.c */,\n\t\t\t\t987A700E2AE8032100A049E2 /* laplace.c */,\n\t\t\t\t98C820FE1C7A980000548839 /* lognormal.c */,\n\t\t\t\t98C820FF1C7A980000548839 /* multinomial.c */,\n\t\t\t\t98332A9D1FDB98ED00274FF0 /* mvgauss.c */,\n\t\t\t\t982B50C52704048E006E91BC /* nbinomial.c */,\n\t\t\t\t98C821001C7A980000548839 /* poisson.c */,\n\t\t\t\t98C821B11C7A9B9F00548839 /* shuffle.c */,\n\t\t\t\t98D7D65B2AB24C40002AFE34 /* tdist.c */,\n\t\t\t\t98C821011C7A980000548839 /* weibull.c */,\n\t\t\t);\n\t\t\tpath = randist;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C821021C7A980000548839 /* rng */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C821031C7A980000548839 /* gsl_rng.h */,\n\t\t\t\t98C821041C7A980000548839 /* inline.c */,\n\t\t\t\t98C821051C7A980000548839 /* mt.c */,\n\t\t\t\t98C821061C7A980000548839 /* rng.c */,\n\t\t\t\t98C821071C7A980000548839 /* taus.c */,\n\t\t\t);\n\t\t\tpath = rng;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C821081C7A980000548839 /* specfunc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C8210A1C7A980000548839 /* chebyshev.h */,\n\t\t\t\t98C8210B1C7A980000548839 /* check.h */,\n\t\t\t\t98C8210D1C7A980000548839 /* error.h */,\n\t\t\t\t98C8210E1C7A980000548839 /* eval.h */,\n\t\t\t\t98C821111C7A980000548839 /* gsl_sf_elementary.h */,\n\t\t\t\t9876E6021ED55A6E00FF9762 /* gsl_sf_erf.h */,\n\t\t\t\t98C821121C7A980000548839 /* gsl_sf_exp.h */,\n\t\t\t\t9876E6061ED55AD600FF9762 /* gsl_sf_expint.h */,\n\t\t\t\t98C821131C7A980000548839 /* gsl_sf_gamma.h */,\n\t\t\t\t98C821141C7A980000548839 /* gsl_sf_log.h */,\n\t\t\t\t98C821151C7A980000548839 /* gsl_sf_pow_int.h */,\n\t\t\t\t98C821161C7A980000548839 /* gsl_sf_psi.h */,\n\t\t\t\t98C821171C7A980000548839 /* gsl_sf_result.h */,\n\t\t\t\t98C821181C7A980000548839 /* gsl_sf_trig.h */,\n\t\t\t\t98C821191C7A980000548839 /* gsl_sf_zeta.h */,\n\t\t\t\t98C821091C7A980000548839 /* cheb_eval.inc */,\n\t\t\t\t9876E6111ED55C6B00FF9762 /* beta.c */,\n\t\t\t\t98C8210C1C7A980000548839 /* elementary.c */,\n\t\t\t\t9876E6071ED55B4700FF9762 /* erfc.c */,\n\t\t\t\t98C8210F1C7A980000548839 /* exp.c */,\n\t\t\t\t9876E60C1ED55C0400FF9762 /* expint.c */,\n\t\t\t\t98C821101C7A980000548839 /* gamma.c */,\n\t\t\t\t9876E6001ED55A2500FF9762 /* gamma_inc.c */,\n\t\t\t\t98C8211A1C7A980000548839 /* log.c */,\n\t\t\t\t98C8211B1C7A980000548839 /* pow_int.c */,\n\t\t\t\t98C8211C1C7A980000548839 /* psi.c */,\n\t\t\t\t98C8211D1C7A980000548839 /* trig.c */,\n\t\t\t\t98C8211E1C7A980000548839 /* zeta.c */,\n\t\t\t);\n\t\t\tpath = specfunc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98C8211F1C7A980000548839 /* sys */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98C821221C7A980000548839 /* gsl_sys.h */,\n\t\t\t\t98C821201C7A980000548839 /* coerce.c */,\n\t\t\t\t98C821211C7A980000548839 /* fdiv.c */,\n\t\t\t\t98C821231C7A980000548839 /* infnan.c */,\n\t\t\t\t98C8219D1C7A99B200548839 /* minmax.c */,\n\t\t\t\t98C821A21C7A99F000548839 /* pow_int.c */,\n\t\t\t);\n\t\t\tpath = sys;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98CEFCD32AAFABAA00D2C9B4 /* interpolation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98CEFCD42AAFABAA00D2C9B4 /* spline2d.c */,\n\t\t\t\t98CEFCD52AAFABAA00D2C9B4 /* bilinear.c */,\n\t\t\t\t98CEFCD82AAFABAA00D2C9B4 /* gsl_interp2d.h */,\n\t\t\t\t98CEFCDA2AAFABAA00D2C9B4 /* interp.c */,\n\t\t\t\t98CEFD742AAFB12F00D2C9B4 /* cspline.c */,\n\t\t\t\t98CEFCDB2AAFABAA00D2C9B4 /* bicubic.c */,\n\t\t\t\t98CEFCDC2AAFABAA00D2C9B4 /* gsl_interp.h */,\n\t\t\t\t98CEFCDD2AAFABAA00D2C9B4 /* integ_eval.h */,\n\t\t\t\t98CEFCDE2AAFABAA00D2C9B4 /* akima.c */,\n\t\t\t\t98CEFCE12AAFABAA00D2C9B4 /* gsl_spline.h */,\n\t\t\t\t98CEFCE22AAFABAA00D2C9B4 /* spline.c */,\n\t\t\t\t98CEFCE52AAFABAA00D2C9B4 /* interp2d.c */,\n\t\t\t\t98CEFCE62AAFABAA00D2C9B4 /* linear.c */,\n\t\t\t\t98CEFCE82AAFABAA00D2C9B4 /* gsl_spline2d.h */,\n\t\t\t\t98CEFCEA2AAFABAA00D2C9B4 /* accel.c */,\n\t\t\t\t98CEFCEB2AAFABAA00D2C9B4 /* inline.c */,\n\t\t\t);\n\t\t\tpath = interpolation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C1B41A6F537B00FFB083 /* SLiMgui */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98EBCD1321F3CFC600B385CF /* slim_gui.h */,\n\t\t\t\t98EBCD1221F3CFC600B385CF /* slim_gui.mm */,\n\t\t\t\t986926D61AA13D340000E138 /* Graphing */,\n\t\t\t\t988794681EA87FC300AE0C8D /* PDF */,\n\t\t\t\t98D4C21A1A718EFD00FFB083 /* CocoaExtra.h */,\n\t\t\t\t98D4C21B1A718EFD00FFB083 /* CocoaExtra.mm */,\n\t\t\t\t98D4C1B71A6F537B00FFB083 /* AppDelegate.h */,\n\t\t\t\t98D4C1B81A6F537B00FFB083 /* AppDelegate.mm */,\n\t\t\t\t989524A71E40AE74007E62FA /* SLiMDocument.h */,\n\t\t\t\t989524A81E40AE74007E62FA /* SLiMDocument.mm */,\n\t\t\t\t98CF26501E4353FE00E392D8 /* SLiMDocumentController.h */,\n\t\t\t\t98CF26511E4353FE00E392D8 /* SLiMDocumentController.mm */,\n\t\t\t\t98D4C2021A701D5A00FFB083 /* SLiMWindowController.h */,\n\t\t\t\t98D4C2031A701D5A00FFB083 /* SLiMWindowController.mm */,\n\t\t\t\t98D4C2051A704EA700FFB083 /* PopulationView.h */,\n\t\t\t\t98D4C2061A704EA700FFB083 /* PopulationView.mm */,\n\t\t\t\t98D4C2081A7086FF00FFB083 /* ChromosomeView.h */,\n\t\t\t\t98D4C2091A7086FF00FFB083 /* ChromosomeView.mm */,\n\t\t\t\t984252C1216FA9930019696A /* FindRecipeController.h */,\n\t\t\t\t984252C2216FA9930019696A /* FindRecipeController.mm */,\n\t\t\t\t98D4C1BE1A6F537B00FFB083 /* MainMenu.xib */,\n\t\t\t\t98D4C1FF1A70192A00FFB083 /* SLiMWindow.xib */,\n\t\t\t\t98D4C20B1A715F6100FFB083 /* AboutWindow.xib */,\n\t\t\t\t98D4C2121A71838400FFB083 /* HelpWindow.xib */,\n\t\t\t\t98EA965A1ECC2541006BA35B /* ProfileReport.xib */,\n\t\t\t\t98024740215D85880025D29C /* FindRecipePanel.xib */,\n\t\t\t\t9825566E1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf */,\n\t\t\t\t982556A21BA5F0810054CB3F /* SLiMHelpClasses.rtf */,\n\t\t\t\t989228331BAFB27300429674 /* SLiMHelpCallbacks.rtf */,\n\t\t\t\t98D4C1E41A6FD8D600FFB083 /* buttons */,\n\t\t\t\t98D4C1B51A6F537B00FFB083 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = SLiMgui;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C1B51A6F537B00FFB083 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98D4C1BC1A6F537B00FFB083 /* Images.xcassets */,\n\t\t\t\t98CF264E1E42DBE200E392D8 /* slim.iconset */,\n\t\t\t\t98D4C1B61A6F537B00FFB083 /* SLiMguiLegacy-Info.plist */,\n\t\t\t\t98CF5302294A3FC900557BBA /* SLiMguiLegacy_multi-Info.plist */,\n\t\t\t\t98FF384D228AFDD900A96440 /* SLiMgui.entitlements */,\n\t\t\t\t98CF5346294A5F3900557BBA /* SLiMguiLegacy_multi.entitlements */,\n\t\t\t\t98D4C1BA1A6F537B00FFB083 /* main.m */,\n\t\t\t\t98A2405C1B8E338E005C9A30 /* OpenGL.framework */,\n\t\t\t\t98D4C2151A7187E200FFB083 /* Quartz.framework */,\n\t\t\t\t9821E2031ABDBC300036EAEA /* QuartzCore.framework */,\n\t\t\t\t98D4C20F1A716E0E00FFB083 /* WebKit.framework */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C1E41A6FD8D600FFB083 /* buttons */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98DD5F012155B857009062EE /* change_folder_H.pdf */,\n\t\t\t\t98DD5F002155B857009062EE /* change_folder.pdf */,\n\t\t\t\t98C0943C1B7663DF00766A9A /* female_symbol.pdf */,\n\t\t\t\t98C0943D1B7663DF00766A9A /* male_symbol.pdf */,\n\t\t\t\t987AD8721B2CBDA70035D6C8 /* show_console_H.pdf */,\n\t\t\t\t987AD8731B2CBDA70035D6C8 /* show_console.pdf */,\n\t\t\t\t986926D21AA1337A0000E138 /* graph_submenu_H.pdf */,\n\t\t\t\t986926D31AA1337A0000E138 /* graph_submenu.pdf */,\n\t\t\t\t98453F4C1A76004300C058CB /* open_type_drawer_H.pdf */,\n\t\t\t\t98453F4D1A76004300C058CB /* open_type_drawer.pdf */,\n\t\t\t\t98453F601A76041200C058CB /* edit_submenu_H.pdf */,\n\t\t\t\t98453F611A76041200C058CB /* edit_submenu.pdf */,\n\t\t\t\t98453F4E1A76004300C058CB /* show_fixed_H.pdf */,\n\t\t\t\t98453F4F1A76004300C058CB /* show_fixed.pdf */,\n\t\t\t\t98453F501A76004300C058CB /* show_genomicelements_H.pdf */,\n\t\t\t\t98453F511A76004300C058CB /* show_genomicelements.pdf */,\n\t\t\t\t98453F521A76004300C058CB /* show_mutations_H.pdf */,\n\t\t\t\t98453F531A76004300C058CB /* show_mutations.pdf */,\n\t\t\t\t98453F541A76004300C058CB /* show_recombination_H.pdf */,\n\t\t\t\t98453F551A76004300C058CB /* show_recombination.pdf */,\n\t\t\t\t98453F3E1A75A12700C058CB /* dump_output_H.pdf */,\n\t\t\t\t98453F3F1A75A12700C058CB /* dump_output.pdf */,\n\t\t\t\t98D4C1F31A70040400FFB083 /* play_step.pdf */,\n\t\t\t\t98D4C1FA1A700DC100FFB083 /* play_step_H.pdf */,\n\t\t\t\t98D4C1F41A70040400FFB083 /* play.pdf */,\n\t\t\t\t98D4C1F91A700DC100FFB083 /* play_H.pdf */,\n\t\t\t\t98EF4AB51ECDA5EA00CCDB09 /* profile.pdf */,\n\t\t\t\t98EF4AB41ECDA5EA00CCDB09 /* profile_H.pdf */,\n\t\t\t\t98D4C1F71A70064800FFB083 /* recycle.pdf */,\n\t\t\t\t98D4C1FB1A700DC100FFB083 /* recycle_H.pdf */,\n\t\t\t\t98D4C1F11A6FEEAB00FFB083 /* change_migration.pdf */,\n\t\t\t\t98D4C1E71A6FDE6E00FFB083 /* change_selfing_ratio.pdf */,\n\t\t\t\t985301EB1B72582E001520DF /* change_cloning_rate.pdf */,\n\t\t\t\t98D4C1E51A6FD8D600FFB083 /* change_sex_ratio.pdf */,\n\t\t\t\t98D4C1E91A6FE7FC00FFB083 /* change_size.pdf */,\n\t\t\t\t98D4C1EB1A6FEAB500FFB083 /* add_subpop.pdf */,\n\t\t\t\t98D4C1EC1A6FEAB500FFB083 /* remove_subpop.pdf */,\n\t\t\t\t98D4C1EF1A6FED4000FFB083 /* split_subpop.pdf */,\n\t\t\t);\n\t\t\tpath = buttons;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98DC9837289986B300160DD8 /* cmake */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98DC9838289986B300160DD8 /* GitSHA1.cpp.in */,\n\t\t\t\t98DC9839289986B300160DD8 /* GetGitRevisionDescription.cmake */,\n\t\t\t\t98DC983A289986B300160DD8 /* GetGitRevisionDescription.cmake.in */,\n\t\t\t\t98DC983B289986B300160DD8 /* AboutTheseModules.cmake */,\n\t\t\t\t98DC983C289986B300160DD8 /* GitSHA1.h */,\n\t\t\t\t98DC983D289986B300160DD8 /* GitSHA1_Xcode.cpp */,\n\t\t\t\t98DC98512899919A00160DD8 /* GitSHA1_qmake.cpp */,\n\t\t\t\t98DC983E289986B300160DD8 /* LICENSE_1_0.txt */,\n\t\t\t\t98DC983F289986B300160DD8 /* README.markdown */,\n\t\t\t\t98DC9840289986B300160DD8 /* _README.txt */,\n\t\t\t);\n\t\t\tpath = cmake;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98EDB4DE2E65300500CC8798 /* permutation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t98EDB50C2E653A0300CC8798 /* gsl_permute.h */,\n\t\t\t\t98EDB50D2E653A5300CC8798 /* gsl_permute_double.h */,\n\t\t\t\t98EDB50F2E653BA400CC8798 /* gsl_permute_matrix.h */,\n\t\t\t\t98EDB50E2E653BA400CC8798 /* gsl_permute_matrix_double.h */,\n\t\t\t\t98EDB4E12E65340200CC8798 /* gsl_permute_vector_double.h */,\n\t\t\t\t98EDB4E02E65326800CC8798 /* gsl_permutation.h */,\n\t\t\t\t98EDB4DF2E65300500CC8798 /* gsl_permute_vector.h */,\n\t\t\t\t98EDB4ED2E65389600CC8798 /* init.c */,\n\t\t\t\t98EDB5012E65399600CC8798 /* permute.c */,\n\t\t\t\t98EDB50B2E6539A500CC8798 /* permute_source.inc */,\n\t\t\t\t98EDB4F72E6538F200CC8798 /* permutation.c */,\n\t\t\t);\n\t\t\tpath = permutation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t982556A81BA8E77B0054CB3F /* eidos */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 982556AD1BA8E77C0054CB3F /* Build configuration list for PBXNativeTarget \"eidos\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t982556A51BA8E77B0054CB3F /* Sources */,\n\t\t\t\t982556A61BA8E77B0054CB3F /* Frameworks */,\n\t\t\t\t982556A71BA8E77B0054CB3F /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = eidos;\n\t\t\tproductName = eidos;\n\t\t\tproductReference = 982556A91BA8E77B0054CB3F /* eidos */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\t9826634F1A3BABD300A0CBBF /* SLiM */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 982663571A3BABD300A0CBBF /* Build configuration list for PBXNativeTarget \"SLiM\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t9826634C1A3BABD300A0CBBF /* Sources */,\n\t\t\t\t9826634D1A3BABD300A0CBBF /* Frameworks */,\n\t\t\t\t9826634E1A3BABD300A0CBBF /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SLiM;\n\t\t\tproductName = SLiM;\n\t\t\tproductReference = 982663501A3BABD300A0CBBF /* slim */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\t984D5FA71E3AF0D200473719 /* EidosSLiMTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 984D5FB11E3AF0D200473719 /* Build configuration list for PBXNativeTarget \"EidosSLiMTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t984D5FA41E3AF0D200473719 /* Sources */,\n\t\t\t\t984D5FA51E3AF0D200473719 /* Frameworks */,\n\t\t\t\t984D5FA61E3AF0D200473719 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t984D5FAE1E3AF0D200473719 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = EidosSLiMTests;\n\t\t\tproductName = EidosSLiMTests;\n\t\t\tproductReference = 984D5FA81E3AF0D200473719 /* EidosSLiMTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t985724AE1AD478630047C223 /* EidosScribe */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 985724C91AD478640047C223 /* Build configuration list for PBXNativeTarget \"EidosScribe\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t985724AB1AD478630047C223 /* Sources */,\n\t\t\t\t985724AC1AD478630047C223 /* Frameworks */,\n\t\t\t\t985724AD1AD478630047C223 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EidosScribe;\n\t\t\tproductName = SLiMscribe;\n\t\t\tproductReference = 985724AF1AD478630047C223 /* EidosScribe.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t98CF51F3294A3FC900557BBA /* SLiMguiLegacy_multi */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98CF52FE294A3FC900557BBA /* Build configuration list for PBXNativeTarget \"SLiMguiLegacy_multi\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98CF51F4294A3FC900557BBA /* Sources */,\n\t\t\t\t98CF52A2294A3FC900557BBA /* Frameworks */,\n\t\t\t\t98CF52A8294A3FC900557BBA /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SLiMguiLegacy_multi;\n\t\t\tproductName = SLiMgui;\n\t\t\tproductReference = 98CF5301294A3FC900557BBA /* SLiMguiLegacy_multi.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t98CF5397294A714200557BBA /* EidosScribe_multi */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98CF5431294A714200557BBA /* Build configuration list for PBXNativeTarget \"EidosScribe_multi\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98CF5398294A714200557BBA /* Sources */,\n\t\t\t\t98CF540F294A714200557BBA /* Frameworks */,\n\t\t\t\t98CF5411294A714200557BBA /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = EidosScribe_multi;\n\t\t\tproductName = SLiMscribe;\n\t\t\tproductReference = 98CF5434294A714200557BBA /* EidosScribe_multi.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t98D4C1B21A6F537B00FFB083 /* SLiMguiLegacy */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98D4C1CD1A6F537C00FFB083 /* Build configuration list for PBXNativeTarget \"SLiMguiLegacy\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98D4C1AF1A6F537B00FFB083 /* Sources */,\n\t\t\t\t98D4C1B01A6F537B00FFB083 /* Frameworks */,\n\t\t\t\t98D4C1B11A6F537B00FFB083 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SLiMguiLegacy;\n\t\t\tproductName = SLiMgui;\n\t\t\tproductReference = 98D4C1B31A6F537B00FFB083 /* SLiMguiLegacy.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t98D7EB8328CE557C00DEAAC4 /* eidos_multi */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98D7EBEB28CE557C00DEAAC4 /* Build configuration list for PBXNativeTarget \"eidos_multi\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98D7EB8428CE557C00DEAAC4 /* Sources */,\n\t\t\t\t98D7EBE928CE557C00DEAAC4 /* Frameworks */,\n\t\t\t\t98D7EBEA28CE557C00DEAAC4 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = eidos_multi;\n\t\t\tproductName = eidos;\n\t\t\tproductReference = 98D7EBEE28CE557C00DEAAC4 /* eidos_multi */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n\t\t98D7EC9F28CE58FC00DEAAC4 /* slim_multi */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 98D7ED2A28CE58FC00DEAAC4 /* Build configuration list for PBXNativeTarget \"slim_multi\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t98D7ECA028CE58FC00DEAAC4 /* Sources */,\n\t\t\t\t98D7ED2828CE58FC00DEAAC4 /* Frameworks */,\n\t\t\t\t98D7ED2928CE58FC00DEAAC4 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = slim_multi;\n\t\t\tproductName = SLiM;\n\t\t\tproductReference = 98D7ED2D28CE58FC00DEAAC4 /* slim_multi */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t982663481A3BABD300A0CBBF /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1210;\n\t\t\t\tORGANIZATIONNAME = \"Messer Lab, http://messerlab.org/software/\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t982556A81BA8E77B0054CB3F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.4;\n\t\t\t\t\t};\n\t\t\t\t\t9826634F1A3BABD300A0CBBF = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1.1;\n\t\t\t\t\t};\n\t\t\t\t\t984D5FA71E3AF0D200473719 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.2.1;\n\t\t\t\t\t\tDevelopmentTeam = C5P6M43RZ7;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = 98D4C1B21A6F537B00FFB083;\n\t\t\t\t\t};\n\t\t\t\t\t985724AE1AD478630047C223 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1.1;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.HardenedRuntime = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t98D4C1B21A6F537B00FFB083 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1.1;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.HardenedRuntime = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 9826634B1A3BABD300A0CBBF /* Build configuration list for PBXProject \"SLiM\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 982663471A3BABD300A0CBBF;\n\t\t\tproductRefGroup = 982663511A3BABD300A0CBBF /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t9826634F1A3BABD300A0CBBF /* SLiM */,\n\t\t\t\t98D4C1B21A6F537B00FFB083 /* SLiMguiLegacy */,\n\t\t\t\t98CF51F3294A3FC900557BBA /* SLiMguiLegacy_multi */,\n\t\t\t\t985724AE1AD478630047C223 /* EidosScribe */,\n\t\t\t\t98CF5397294A714200557BBA /* EidosScribe_multi */,\n\t\t\t\t982556A81BA8E77B0054CB3F /* eidos */,\n\t\t\t\t984D5FA71E3AF0D200473719 /* EidosSLiMTests */,\n\t\t\t\t98D7EB8328CE557C00DEAAC4 /* eidos_multi */,\n\t\t\t\t98D7EC9F28CE58FC00DEAAC4 /* slim_multi */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t984D5FA61E3AF0D200473719 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t985724AD1AD478630047C223 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t985724F01AD6D4060047C223 /* show_parse_H.pdf in Resources */,\n\t\t\t\t985724F11AD6D4060047C223 /* show_parse.pdf in Resources */,\n\t\t\t\t985724E11AD4C3310047C223 /* execute_script.pdf in Resources */,\n\t\t\t\t985724D61AD489AA0047C223 /* check_H.pdf in Resources */,\n\t\t\t\t9892282C1BAE279700429674 /* EidosHelpOperators.rtf in Resources */,\n\t\t\t\t985724E01AD4C3310047C223 /* execute_script_H.pdf in Resources */,\n\t\t\t\t989228321BAF496C00429674 /* EidosHelpStatements.rtf in Resources */,\n\t\t\t\t9825566D1BA477D60054CB3F /* EidosHelpFunctions.rtf in Resources */,\n\t\t\t\t9892282F1BAE27AA00429674 /* EidosHelpTypes.rtf in Resources */,\n\t\t\t\t98D524631F2E6AFB005AD9A6 /* prettyprint_H.pdf in Resources */,\n\t\t\t\t982556A11BA5DFEB0054CB3F /* EidosHelpClasses.rtf in Resources */,\n\t\t\t\t98090FA21B1B8B5800791DBF /* show_browser_H.pdf in Resources */,\n\t\t\t\t9825566A1BA451D00054CB3F /* EidosHelpWindow.xib in Resources */,\n\t\t\t\t985724B91AD478630047C223 /* Images.xcassets in Resources */,\n\t\t\t\t985724F71AD6DD470047C223 /* show_execution.pdf in Resources */,\n\t\t\t\t985724BC1AD478630047C223 /* MainMenu.xib in Resources */,\n\t\t\t\t985724DA1AD489AA0047C223 /* syntax_help_H.pdf in Resources */,\n\t\t\t\t98EFE6341ADD92BC00CBEC78 /* EidosAboutWindow.xib in Resources */,\n\t\t\t\t985724D91AD489AA0047C223 /* delete.pdf in Resources */,\n\t\t\t\t985724D81AD489AA0047C223 /* delete_H.pdf in Resources */,\n\t\t\t\t985724DB1AD489AA0047C223 /* syntax_help.pdf in Resources */,\n\t\t\t\t985724F31AD6D4060047C223 /* show_tokens.pdf in Resources */,\n\t\t\t\t98A4EC941B67C1CD00CD92FD /* EidosConsoleWindow.xib in Resources */,\n\t\t\t\t985724D71AD489AA0047C223 /* check.pdf in Resources */,\n\t\t\t\t98D524641F2E6AFB005AD9A6 /* prettyprint.pdf in Resources */,\n\t\t\t\t985724EB1AD6B9FE0047C223 /* execute_selection.pdf in Resources */,\n\t\t\t\t985724F21AD6D4060047C223 /* show_tokens_H.pdf in Resources */,\n\t\t\t\t985724EA1AD6B9FE0047C223 /* execute_selection_H.pdf in Resources */,\n\t\t\t\t985724F61AD6DD470047C223 /* show_execution_H.pdf in Resources */,\n\t\t\t\t98090FA31B1B8B5800791DBF /* show_browser.pdf in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF52A8294A3FC900557BBA /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CF52A9294A3FC900557BBA /* profile.pdf in Resources */,\n\t\t\t\t98CF52AA294A3FC900557BBA /* Recipes in Resources */,\n\t\t\t\t98CF52AB294A3FC900557BBA /* play_step.pdf in Resources */,\n\t\t\t\t98CF52AC294A3FC900557BBA /* FindRecipePanel.xib in Resources */,\n\t\t\t\t98CF52AD294A3FC900557BBA /* slim.iconset in Resources */,\n\t\t\t\t98CF52AE294A3FC900557BBA /* show_parse.pdf in Resources */,\n\t\t\t\t98CF52AF294A3FC900557BBA /* open_type_drawer_H.pdf in Resources */,\n\t\t\t\t98CF52B0294A3FC900557BBA /* Images.xcassets in Resources */,\n\t\t\t\t98CF52B1294A3FC900557BBA /* recycle.pdf in Resources */,\n\t\t\t\t98CF52B2294A3FC900557BBA /* check.pdf in Resources */,\n\t\t\t\t98CF52B3294A3FC900557BBA /* remove_subpop.pdf in Resources */,\n\t\t\t\t98CF52B4294A3FC900557BBA /* EidosHelpWindow.xib in Resources */,\n\t\t\t\t98CF52B5294A3FC900557BBA /* execute_selection.pdf in Resources */,\n\t\t\t\t98CF52B6294A3FC900557BBA /* profile_H.pdf in Resources */,\n\t\t\t\t98CF52B7294A3FC900557BBA /* dump_output.pdf in Resources */,\n\t\t\t\t98CF52B8294A3FC900557BBA /* show_mutations_H.pdf in Resources */,\n\t\t\t\t98CF52B9294A3FC900557BBA /* dump_output_H.pdf in Resources */,\n\t\t\t\t98CF52BA294A3FC900557BBA /* GraphBarRescaleSheet.xib in Resources */,\n\t\t\t\t98CF52BB294A3FC900557BBA /* show_genomicelements_H.pdf in Resources */,\n\t\t\t\t98CF52BC294A3FC900557BBA /* SLiMHelpFunctions.rtf in Resources */,\n\t\t\t\t98CF52BD294A3FC900557BBA /* edit_submenu.pdf in Resources */,\n\t\t\t\t98CF52BE294A3FC900557BBA /* prettyprint_H.pdf in Resources */,\n\t\t\t\t98CF52BF294A3FC900557BBA /* EidosHelpStatements.rtf in Resources */,\n\t\t\t\t98CF52C0294A3FC900557BBA /* change_sex_ratio.pdf in Resources */,\n\t\t\t\t98CF52C1294A3FC900557BBA /* ProfileReport.xib in Resources */,\n\t\t\t\t98CF52C2294A3FC900557BBA /* show_console_H.pdf in Resources */,\n\t\t\t\t98CF52C3294A3FC900557BBA /* MainMenu.xib in Resources */,\n\t\t\t\t98CF52C4294A3FC900557BBA /* show_execution.pdf in Resources */,\n\t\t\t\t98CF52C5294A3FC900557BBA /* change_cloning_rate.pdf in Resources */,\n\t\t\t\t98CF52C6294A3FC900557BBA /* female_symbol.pdf in Resources */,\n\t\t\t\t98CF52C7294A3FC900557BBA /* split_subpop.pdf in Resources */,\n\t\t\t\t98CF52C8294A3FC900557BBA /* show_recombination.pdf in Resources */,\n\t\t\t\t98CF52C9294A3FC900557BBA /* GraphWindow.xib in Resources */,\n\t\t\t\t98CF52CA294A3FC900557BBA /* GraphAxisRescaleSheet.xib in Resources */,\n\t\t\t\t98CF52CB294A3FC900557BBA /* EidosHelpOperators.rtf in Resources */,\n\t\t\t\t98CF52CC294A3FC900557BBA /* add_subpop.pdf in Resources */,\n\t\t\t\t98CF52CE294A3FC900557BBA /* EidosHelpTypes.rtf in Resources */,\n\t\t\t\t98CF52CF294A3FC900557BBA /* check_H.pdf in Resources */,\n\t\t\t\t98CF52D0294A3FC900557BBA /* show_execution_H.pdf in Resources */,\n\t\t\t\t98CF52D1294A3FC900557BBA /* SLiMHelpClasses.rtf in Resources */,\n\t\t\t\t98CF52D2294A3FC900557BBA /* show_fixed.pdf in Resources */,\n\t\t\t\t98CF52D3294A3FC900557BBA /* syntax_help_H.pdf in Resources */,\n\t\t\t\t98CF52D4294A3FC900557BBA /* graph_submenu_H.pdf in Resources */,\n\t\t\t\t98CF52D5294A3FC900557BBA /* show_parse_H.pdf in Resources */,\n\t\t\t\t98CF52D6294A3FC900557BBA /* show_browser.pdf in Resources */,\n\t\t\t\t98CF52D7294A3FC900557BBA /* EidosConsoleWindow.xib in Resources */,\n\t\t\t\t98CF52D8294A3FC900557BBA /* SLiMPDFWindow.xib in Resources */,\n\t\t\t\t98CF52D9294A3FC900557BBA /* prettyprint.pdf in Resources */,\n\t\t\t\t98CF52DA294A3FC900557BBA /* syntax_help.pdf in Resources */,\n\t\t\t\t98CF52DB294A3FC900557BBA /* change_selfing_ratio.pdf in Resources */,\n\t\t\t\t98CF52DC294A3FC900557BBA /* change_folder.pdf in Resources */,\n\t\t\t\t98CF52DD294A3FC900557BBA /* open_type_drawer.pdf in Resources */,\n\t\t\t\t98CF52DF294A3FC900557BBA /* EidosHelpClasses.rtf in Resources */,\n\t\t\t\t98CF52E0294A3FC900557BBA /* show_tokens.pdf in Resources */,\n\t\t\t\t98CF52E1294A3FC900557BBA /* edit_submenu_H.pdf in Resources */,\n\t\t\t\t98CF52E2294A3FC900557BBA /* AboutWindow.xib in Resources */,\n\t\t\t\t98CF52E3294A3FC900557BBA /* play_step_H.pdf in Resources */,\n\t\t\t\t98CF52E4294A3FC900557BBA /* show_recombination_H.pdf in Resources */,\n\t\t\t\t98CF52E5294A3FC900557BBA /* EidosHelpFunctions.rtf in Resources */,\n\t\t\t\t98CF52E6294A3FC900557BBA /* male_symbol.pdf in Resources */,\n\t\t\t\t98CF52E7294A3FC900557BBA /* recycle_H.pdf in Resources */,\n\t\t\t\t98CF52E8294A3FC900557BBA /* show_mutations.pdf in Resources */,\n\t\t\t\t98CF52E9294A3FC900557BBA /* execute_selection_H.pdf in Resources */,\n\t\t\t\t98CF52EA294A3FC900557BBA /* change_folder_H.pdf in Resources */,\n\t\t\t\t98CF52EB294A3FC900557BBA /* play_H.pdf in Resources */,\n\t\t\t\t98CF52ED294A3FC900557BBA /* SLiMHelpCallbacks.rtf in Resources */,\n\t\t\t\t98CF52EE294A3FC900557BBA /* execute_script.pdf in Resources */,\n\t\t\t\t98CF52EF294A3FC900557BBA /* graph_submenu.pdf in Resources */,\n\t\t\t\t98CF52F0294A3FC900557BBA /* show_fixed_H.pdf in Resources */,\n\t\t\t\t98CF52F1294A3FC900557BBA /* execute_script_H.pdf in Resources */,\n\t\t\t\t98CF52F2294A3FC900557BBA /* SLiMWindow.xib in Resources */,\n\t\t\t\t98CF52F3294A3FC900557BBA /* show_browser_H.pdf in Resources */,\n\t\t\t\t98CF52F4294A3FC900557BBA /* play.pdf in Resources */,\n\t\t\t\t98CF52F5294A3FC900557BBA /* change_migration.pdf in Resources */,\n\t\t\t\t98CF52F6294A3FC900557BBA /* show_console.pdf in Resources */,\n\t\t\t\t98CF52F7294A3FC900557BBA /* show_tokens_H.pdf in Resources */,\n\t\t\t\t98CF52F8294A3FC900557BBA /* delete.pdf in Resources */,\n\t\t\t\t98CF52F9294A3FC900557BBA /* delete_H.pdf in Resources */,\n\t\t\t\t98CF52FA294A3FC900557BBA /* Tips in Resources */,\n\t\t\t\t98CF52FB294A3FC900557BBA /* change_size.pdf in Resources */,\n\t\t\t\t98CF52FC294A3FC900557BBA /* show_genomicelements.pdf in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF5411294A714200557BBA /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CF5412294A714200557BBA /* show_parse_H.pdf in Resources */,\n\t\t\t\t98CF5413294A714200557BBA /* show_parse.pdf in Resources */,\n\t\t\t\t98CF5414294A714200557BBA /* execute_script.pdf in Resources */,\n\t\t\t\t98CF5415294A714200557BBA /* check_H.pdf in Resources */,\n\t\t\t\t98CF5416294A714200557BBA /* EidosHelpOperators.rtf in Resources */,\n\t\t\t\t98CF5417294A714200557BBA /* execute_script_H.pdf in Resources */,\n\t\t\t\t98CF5418294A714200557BBA /* EidosHelpStatements.rtf in Resources */,\n\t\t\t\t98CF5419294A714200557BBA /* EidosHelpFunctions.rtf in Resources */,\n\t\t\t\t98CF541A294A714200557BBA /* EidosHelpTypes.rtf in Resources */,\n\t\t\t\t98CF541B294A714200557BBA /* prettyprint_H.pdf in Resources */,\n\t\t\t\t98CF541C294A714200557BBA /* EidosHelpClasses.rtf in Resources */,\n\t\t\t\t98CF541D294A714200557BBA /* show_browser_H.pdf in Resources */,\n\t\t\t\t98CF541E294A714200557BBA /* EidosHelpWindow.xib in Resources */,\n\t\t\t\t98CF541F294A714200557BBA /* Images.xcassets in Resources */,\n\t\t\t\t98CF5420294A714200557BBA /* show_execution.pdf in Resources */,\n\t\t\t\t98CF5421294A714200557BBA /* MainMenu.xib in Resources */,\n\t\t\t\t98CF5422294A714200557BBA /* syntax_help_H.pdf in Resources */,\n\t\t\t\t98CF5423294A714200557BBA /* EidosAboutWindow.xib in Resources */,\n\t\t\t\t98CF5424294A714200557BBA /* delete.pdf in Resources */,\n\t\t\t\t98CF5425294A714200557BBA /* delete_H.pdf in Resources */,\n\t\t\t\t98CF5426294A714200557BBA /* syntax_help.pdf in Resources */,\n\t\t\t\t98CF5427294A714200557BBA /* show_tokens.pdf in Resources */,\n\t\t\t\t98CF5428294A714200557BBA /* EidosConsoleWindow.xib in Resources */,\n\t\t\t\t98CF5429294A714200557BBA /* check.pdf in Resources */,\n\t\t\t\t98CF542A294A714200557BBA /* prettyprint.pdf in Resources */,\n\t\t\t\t98CF542B294A714200557BBA /* execute_selection.pdf in Resources */,\n\t\t\t\t98CF542C294A714200557BBA /* show_tokens_H.pdf in Resources */,\n\t\t\t\t98CF542D294A714200557BBA /* execute_selection_H.pdf in Resources */,\n\t\t\t\t98CF542E294A714200557BBA /* show_execution_H.pdf in Resources */,\n\t\t\t\t98CF542F294A714200557BBA /* show_browser.pdf in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D4C1B11A6F537B00FFB083 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98EF4AB71ECDA5EA00CCDB09 /* profile.pdf in Resources */,\n\t\t\t\t98A2FF891D7DF4D7007E3DB8 /* Recipes in Resources */,\n\t\t\t\t98D4C1F51A70040400FFB083 /* play_step.pdf in Resources */,\n\t\t\t\t98024742215D85880025D29C /* FindRecipePanel.xib in Resources */,\n\t\t\t\t98CF264F1E42DBE200E392D8 /* slim.iconset in Resources */,\n\t\t\t\t987AD87D1B2CBE4F0035D6C8 /* show_parse.pdf in Resources */,\n\t\t\t\t98453F561A76004300C058CB /* open_type_drawer_H.pdf in Resources */,\n\t\t\t\t98D4C1BD1A6F537B00FFB083 /* Images.xcassets in Resources */,\n\t\t\t\t98D4C1F81A70064800FFB083 /* recycle.pdf in Resources */,\n\t\t\t\t98D4C2281A71F8AD00FFB083 /* check.pdf in Resources */,\n\t\t\t\t98D4C1EE1A6FEAB500FFB083 /* remove_subpop.pdf in Resources */,\n\t\t\t\t982556691BA451D00054CB3F /* EidosHelpWindow.xib in Resources */,\n\t\t\t\t987AD87B1B2CBE360035D6C8 /* execute_selection.pdf in Resources */,\n\t\t\t\t98EF4AB61ECDA5EA00CCDB09 /* profile_H.pdf in Resources */,\n\t\t\t\t98453F411A75A12700C058CB /* dump_output.pdf in Resources */,\n\t\t\t\t98453F5C1A76004300C058CB /* show_mutations_H.pdf in Resources */,\n\t\t\t\t98453F401A75A12700C058CB /* dump_output_H.pdf in Resources */,\n\t\t\t\t982A9DDE1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib in Resources */,\n\t\t\t\t98453F5A1A76004300C058CB /* show_genomicelements_H.pdf in Resources */,\n\t\t\t\t9825566F1BA4FAD00054CB3F /* SLiMHelpFunctions.rtf in Resources */,\n\t\t\t\t98453F631A76041200C058CB /* edit_submenu.pdf in Resources */,\n\t\t\t\t98D524651F2E6B08005AD9A6 /* prettyprint_H.pdf in Resources */,\n\t\t\t\t989228311BAF496C00429674 /* EidosHelpStatements.rtf in Resources */,\n\t\t\t\t98D4C1E61A6FD8D600FFB083 /* change_sex_ratio.pdf in Resources */,\n\t\t\t\t98EA965C1ECC2541006BA35B /* ProfileReport.xib in Resources */,\n\t\t\t\t987AD8741B2CBDA70035D6C8 /* show_console_H.pdf in Resources */,\n\t\t\t\t98D4C1C01A6F537B00FFB083 /* MainMenu.xib in Resources */,\n\t\t\t\t987AD8811B2CBE5B0035D6C8 /* show_execution.pdf in Resources */,\n\t\t\t\t985301EC1B72582E001520DF /* change_cloning_rate.pdf in Resources */,\n\t\t\t\t98C0943E1B7663DF00766A9A /* female_symbol.pdf in Resources */,\n\t\t\t\t98D4C1F01A6FED4000FFB083 /* split_subpop.pdf in Resources */,\n\t\t\t\t98453F5F1A76004300C058CB /* show_recombination.pdf in Resources */,\n\t\t\t\t986926DC1AA1429D0000E138 /* GraphWindow.xib in Resources */,\n\t\t\t\t980DD51A1AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib in Resources */,\n\t\t\t\t9892282B1BAE279700429674 /* EidosHelpOperators.rtf in Resources */,\n\t\t\t\t98D4C1ED1A6FEAB500FFB083 /* add_subpop.pdf in Resources */,\n\t\t\t\t9892282E1BAE27AA00429674 /* EidosHelpTypes.rtf in Resources */,\n\t\t\t\t98D4C2271A71F8AD00FFB083 /* check_H.pdf in Resources */,\n\t\t\t\t987AD8801B2CBE580035D6C8 /* show_execution_H.pdf in Resources */,\n\t\t\t\t982556A31BA5F0810054CB3F /* SLiMHelpClasses.rtf in Resources */,\n\t\t\t\t98453F591A76004300C058CB /* show_fixed.pdf in Resources */,\n\t\t\t\t98453F441A75AABE00C058CB /* syntax_help_H.pdf in Resources */,\n\t\t\t\t986926D41AA1337A0000E138 /* graph_submenu_H.pdf in Resources */,\n\t\t\t\t987AD87C1B2CBE4B0035D6C8 /* show_parse_H.pdf in Resources */,\n\t\t\t\t987AD8771B2CBE050035D6C8 /* show_browser.pdf in Resources */,\n\t\t\t\t98A4EC951B67C1D900CD92FD /* EidosConsoleWindow.xib in Resources */,\n\t\t\t\t988794701EA8808000AE0C8D /* SLiMPDFWindow.xib in Resources */,\n\t\t\t\t98D524661F2E6B0B005AD9A6 /* prettyprint.pdf in Resources */,\n\t\t\t\t98453F451A75AABE00C058CB /* syntax_help.pdf in Resources */,\n\t\t\t\t98D4C1E81A6FDE6E00FFB083 /* change_selfing_ratio.pdf in Resources */,\n\t\t\t\t98DD5F022155B857009062EE /* change_folder.pdf in Resources */,\n\t\t\t\t98453F571A76004300C058CB /* open_type_drawer.pdf in Resources */,\n\t\t\t\t982556A01BA5DFEB0054CB3F /* EidosHelpClasses.rtf in Resources */,\n\t\t\t\t987AD87F1B2CBE550035D6C8 /* show_tokens.pdf in Resources */,\n\t\t\t\t98453F621A76041200C058CB /* edit_submenu_H.pdf in Resources */,\n\t\t\t\t98D4C20D1A715F6100FFB083 /* AboutWindow.xib in Resources */,\n\t\t\t\t98D4C1FD1A700DC100FFB083 /* play_step_H.pdf in Resources */,\n\t\t\t\t98453F5E1A76004300C058CB /* show_recombination_H.pdf in Resources */,\n\t\t\t\t9825566C1BA477D60054CB3F /* EidosHelpFunctions.rtf in Resources */,\n\t\t\t\t98C0943F1B7663DF00766A9A /* male_symbol.pdf in Resources */,\n\t\t\t\t98D4C1FE1A700DC100FFB083 /* recycle_H.pdf in Resources */,\n\t\t\t\t98453F5D1A76004300C058CB /* show_mutations.pdf in Resources */,\n\t\t\t\t987AD87A1B2CBE330035D6C8 /* execute_selection_H.pdf in Resources */,\n\t\t\t\t98DD5F032155B857009062EE /* change_folder_H.pdf in Resources */,\n\t\t\t\t98D4C1FC1A700DC100FFB083 /* play_H.pdf in Resources */,\n\t\t\t\t989228341BAFB27300429674 /* SLiMHelpCallbacks.rtf in Resources */,\n\t\t\t\t987AD8791B2CBE2E0035D6C8 /* execute_script.pdf in Resources */,\n\t\t\t\t986926D51AA1337A0000E138 /* graph_submenu.pdf in Resources */,\n\t\t\t\t98453F581A76004300C058CB /* show_fixed_H.pdf in Resources */,\n\t\t\t\t987AD8781B2CBE280035D6C8 /* execute_script_H.pdf in Resources */,\n\t\t\t\t98D4C2011A70192A00FFB083 /* SLiMWindow.xib in Resources */,\n\t\t\t\t987AD8761B2CBE010035D6C8 /* show_browser_H.pdf in Resources */,\n\t\t\t\t98D4C1F61A70040400FFB083 /* play.pdf in Resources */,\n\t\t\t\t98D4C1F21A6FEEAB00FFB083 /* change_migration.pdf in Resources */,\n\t\t\t\t987AD8751B2CBDA70035D6C8 /* show_console.pdf in Resources */,\n\t\t\t\t987AD87E1B2CBE520035D6C8 /* show_tokens_H.pdf in Resources */,\n\t\t\t\t98D4C22A1A71F8AD00FFB083 /* delete.pdf in Resources */,\n\t\t\t\t98D4C2291A71F8AD00FFB083 /* delete_H.pdf in Resources */,\n\t\t\t\t98F65D561DF14DA50058BD29 /* Tips in Resources */,\n\t\t\t\t98D4C1EA1A6FE7FC00FFB083 /* change_size.pdf in Resources */,\n\t\t\t\t98453F5B1A76004300C058CB /* show_genomicelements.pdf in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t982556A51BA8E77B0054CB3F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98C8219A1C7A983800548839 /* coerce.c in Sources */,\n\t\t\t\t9807663724493E0B00F6CBB4 /* compress.c in Sources */,\n\t\t\t\t987A70142AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t981DC36728E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98CEFD712AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t982556B61BA8EF860054CB3F /* eidos_value.cpp in Sources */,\n\t\t\t\t98C821801C7A983800548839 /* math.c in Sources */,\n\t\t\t\t98ACDCA0253522B80038703F /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t982556B21BA8EF790054CB3F /* eidos_token.cpp in Sources */,\n\t\t\t\t98332ADA1FDBBE3600274FF0 /* cholesky.c in Sources */,\n\t\t\t\t98332AA11FDB990500274FF0 /* mvgauss.c in Sources */,\n\t\t\t\t98332AC51FDBA54700274FF0 /* xerbla.c in Sources */,\n\t\t\t\t981DC36B28E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t981DC36F28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98332B141FDBD0F600274FF0 /* init.c in Sources */,\n\t\t\t\t981DC35728E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t981DC35328E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98C821881C7A983800548839 /* gauss.c in Sources */,\n\t\t\t\t98C821B51C7A9B9F00548839 /* shuffle.c in Sources */,\n\t\t\t\t98CEFCF92AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98C821861C7A983800548839 /* exponential.c in Sources */,\n\t\t\t\t98D7D6612AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t9876E60B1ED55B5000FF9762 /* erfc.c in Sources */,\n\t\t\t\t981DC35F28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98C634492EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t9876E6101ED55C0C00FF9762 /* expint.c in Sources */,\n\t\t\t\t98C821981C7A983800548839 /* trig.c in Sources */,\n\t\t\t\t982556BC1BA8EF990054CB3F /* eidos_test.cpp in Sources */,\n\t\t\t\t98332AD11FDBA87E00274FF0 /* oper.c in Sources */,\n\t\t\t\t9823568C252FE61A0096A745 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98332AFA1FDBC42700274FF0 /* swap.c in Sources */,\n\t\t\t\t989A5BEC2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t9807663624493E0B00F6CBB4 /* deflate.c in Sources */,\n\t\t\t\t98CEFD7A2AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98C821811C7A983800548839 /* error.c in Sources */,\n\t\t\t\t98EDB5162E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t985F3F0424BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t98CEFD4D2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t98CEFD552AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t982556B01BA8EF720054CB3F /* eidos_rng.cpp in Sources */,\n\t\t\t\t98EDB4FD2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98C8218E1C7A983800548839 /* inline.c in Sources */,\n\t\t\t\t98C821B01C7A9B1600548839 /* geometric.c in Sources */,\n\t\t\t\t98CEFD152AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t982556B31BA8EF7C0054CB3F /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t9893C7DE1CDA2D650029AC94 /* eidos_beep.cpp in Sources */,\n\t\t\t\t9807663A24493E0B00F6CBB4 /* adler32.c in Sources */,\n\t\t\t\t98D7D66A2AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t9876E5FF1ED559A700FF9762 /* gauss.c in Sources */,\n\t\t\t\t98C821991C7A983800548839 /* zeta.c in Sources */,\n\t\t\t\t98C8218B1C7A983800548839 /* multinomial.c in Sources */,\n\t\t\t\t98C821851C7A983800548839 /* binomial_tpe.c in Sources */,\n\t\t\t\t988880EF20744F0200E10172 /* cauchy.c in Sources */,\n\t\t\t\t98C8219C1C7A983800548839 /* infnan.c in Sources */,\n\t\t\t\t982556BA1BA8EF930054CB3F /* eidos_functions.cpp in Sources */,\n\t\t\t\t981DC37328E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t982556B91BA8EF8F0054CB3F /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98EDB4F32E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t98C8218F1C7A983800548839 /* mt.c in Sources */,\n\t\t\t\t98C821891C7A983800548839 /* gausszig.c in Sources */,\n\t\t\t\t98C821821C7A983800548839 /* message.c in Sources */,\n\t\t\t\t982556B81BA8EF8C0054CB3F /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98C8217F1C7A983800548839 /* inline.c in Sources */,\n\t\t\t\t985F3F0E24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98729ADD2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98C821AC1C7A9B1600548839 /* discrete.c in Sources */,\n\t\t\t\t98EDB5072E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98EDB4E82E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t9807663924493E0B00F6CBB4 /* gzwrite.c in Sources */,\n\t\t\t\t98CEFD252AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98CEFD352AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98C8218C1C7A983800548839 /* poisson.c in Sources */,\n\t\t\t\t9893C7E61CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98C821931C7A983800548839 /* exp.c in Sources */,\n\t\t\t\t985F3EF524BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t982556B41BA8EF7F0054CB3F /* eidos_script.cpp in Sources */,\n\t\t\t\t982556B51BA8EF830054CB3F /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t981DC36328E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98332AF31FDBC36400274FF0 /* submatrix.c in Sources */,\n\t\t\t\t98C821A11C7A99B200548839 /* minmax.c in Sources */,\n\t\t\t\t98CEFCF12AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98C821A61C7A99F000548839 /* pow_int.c in Sources */,\n\t\t\t\t987A2A0A24033856009A636F /* gaussinv.c in Sources */,\n\t\t\t\t98CEFD832AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98C821951C7A983800548839 /* log.c in Sources */,\n\t\t\t\t9876E6051ED55A7900FF9762 /* gamma_inc.c in Sources */,\n\t\t\t\t985F3EFF24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t9890D1F027136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98C821911C7A983800548839 /* taus.c in Sources */,\n\t\t\t\t981DC35B28E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t982556B71BA8EF8A0054CB3F /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t982B50C92704048E006E91BC /* nbinomial.c in Sources */,\n\t\t\t\t98CEFD8D2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t985F3EF024BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98C8218A1C7A983800548839 /* lognormal.c in Sources */,\n\t\t\t\t98332ACA1FDBA74A00274FF0 /* vector.c in Sources */,\n\t\t\t\t98C8219B1C7A983800548839 /* fdiv.c in Sources */,\n\t\t\t\t98332AFF1FDBC4BC00274FF0 /* matrix.c in Sources */,\n\t\t\t\t98332B0D1FDBD03200274FF0 /* init.c in Sources */,\n\t\t\t\t98C8218D1C7A983800548839 /* weibull.c in Sources */,\n\t\t\t\t98332AB71FDBA1E600274FF0 /* blas.c in Sources */,\n\t\t\t\t98235685252FDCF50096A745 /* lodepng.cpp in Sources */,\n\t\t\t\t984824F7210B9F32002402A5 /* ddot.c in Sources */,\n\t\t\t\t985F3EFA24BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t985F3F0924BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t9807663824493E0B00F6CBB4 /* gzlib.c in Sources */,\n\t\t\t\t98CEFD692AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98332ABC1FDBA32500274FF0 /* dtrmv.c in Sources */,\n\t\t\t\t9807663324493E0B00F6CBB4 /* crc32.c in Sources */,\n\t\t\t\t98EDB4D42E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t980566E525A7C5B9008D3C7F /* fdist.c in Sources */,\n\t\t\t\t9807663524493E0B00F6CBB4 /* trees.c in Sources */,\n\t\t\t\t98C821941C7A983800548839 /* gamma.c in Sources */,\n\t\t\t\t98C821841C7A983800548839 /* beta.c in Sources */,\n\t\t\t\t98332B1B1FDBD16600274FF0 /* copy.c in Sources */,\n\t\t\t\t98332AEF1FDBC29500274FF0 /* rowcol.c in Sources */,\n\t\t\t\t9807663424493E0B00F6CBB4 /* zutil.c in Sources */,\n\t\t\t\t98C821971C7A983800548839 /* psi.c in Sources */,\n\t\t\t\t982556AC1BA8E77C0054CB3F /* main.cpp in Sources */,\n\t\t\t\t982556BB1BA8EF960054CB3F /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t9876E6151ED55C7400FF9762 /* beta.c in Sources */,\n\t\t\t\t98C821961C7A983800548839 /* pow_int.c in Sources */,\n\t\t\t\t98C821921C7A983800548839 /* elementary.c in Sources */,\n\t\t\t\t9893C7EC1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98332B061FDBCFF900274FF0 /* init.c in Sources */,\n\t\t\t\t98C821831C7A983800548839 /* stream.c in Sources */,\n\t\t\t\t98C821901C7A983800548839 /* rng.c in Sources */,\n\t\t\t\t984824F4210B9F2D002402A5 /* dtrsv.c in Sources */,\n\t\t\t\t98CEFD1D2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t9876E5F81ED5573800FF9762 /* tdist.c in Sources */,\n\t\t\t\t98332ADF1FDBC0D800274FF0 /* dgemv.c in Sources */,\n\t\t\t\t98C821871C7A983800548839 /* gamma.c in Sources */,\n\t\t\t\t982556B11BA8EF760054CB3F /* eidos_globals.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t9826634C1A3BABD300A0CBBF /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CEFD502AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98EFE62F1ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t9893C7E91CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t986D73E81B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98C6344A2EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98CEFD102AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98332ADC1FDBC0D000274FF0 /* dgemv.c in Sources */,\n\t\t\t\t98332B111FDBD09800274FF0 /* init.c in Sources */,\n\t\t\t\t98C8212C1C7A980000548839 /* gamma.c in Sources */,\n\t\t\t\t98729AD82A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98C8212D1C7A980000548839 /* gauss.c in Sources */,\n\t\t\t\t985F3F0124BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t985F3F0B24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98C8213B1C7A980000548839 /* log.c in Sources */,\n\t\t\t\t981DC35428E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98CEFD302AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98EDB4E32E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98800DC41B7EDCB50046F5F9 /* slim_test.cpp in Sources */,\n\t\t\t\t9876E60D1ED55C0400FF9762 /* expint.c in Sources */,\n\t\t\t\t98C821381C7A980000548839 /* elementary.c in Sources */,\n\t\t\t\t98332A9E1FDB98ED00274FF0 /* mvgauss.c in Sources */,\n\t\t\t\t98332B181FDBD13D00274FF0 /* copy.c in Sources */,\n\t\t\t\t98235689252FE61A0096A745 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98C821B21C7A9B9F00548839 /* shuffle.c in Sources */,\n\t\t\t\t9854D2652278B9F8001D43BC /* stats.c in Sources */,\n\t\t\t\t981DC36428E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t981DC37028E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98E9A6901A3CD4CF000AD4FC /* mutation_type.cpp in Sources */,\n\t\t\t\t98DEB47E2AA632AA00ABE60F /* spatial_map.cpp in Sources */,\n\t\t\t\t98E9A68A1A3CCFD0000AD4FC /* mutation.cpp in Sources */,\n\t\t\t\t98C821401C7A980000548839 /* coerce.c in Sources */,\n\t\t\t\t98332AB91FDBA32200274FF0 /* dtrmv.c in Sources */,\n\t\t\t\t9876E6011ED55A2500FF9762 /* gamma_inc.c in Sources */,\n\t\t\t\t9807C0F824BA21E3008CC658 /* slim_test_other.cpp in Sources */,\n\t\t\t\t98332AC71FDBA6B600274FF0 /* vector.c in Sources */,\n\t\t\t\t981BAC6A1ACC6E8B0005BE94 /* eidos_script.cpp in Sources */,\n\t\t\t\t987A2A0724033856009A636F /* gaussinv.c in Sources */,\n\t\t\t\t9876E6081ED55B4700FF9762 /* erfc.c in Sources */,\n\t\t\t\t98C8212E1C7A980000548839 /* gausszig.c in Sources */,\n\t\t\t\t9836868127CD72E900683639 /* community_eidos.cpp in Sources */,\n\t\t\t\t98EDB4CF2E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t984824EE210B9E8F002402A5 /* ddot.c in Sources */,\n\t\t\t\t9878A93F1A4E57E70007B9D6 /* species.cpp in Sources */,\n\t\t\t\t9893C7DD1CDA2D650029AC94 /* eidos_beep.cpp in Sources */,\n\t\t\t\t980566E225A7C5B9008D3C7F /* fdist.c in Sources */,\n\t\t\t\t98332AFC1FDBC4B200274FF0 /* matrix.c in Sources */,\n\t\t\t\t98332AEA1FDBC1D900274FF0 /* submatrix.c in Sources */,\n\t\t\t\t98C8213D1C7A980000548839 /* psi.c in Sources */,\n\t\t\t\t98C8212A1C7A980000548839 /* binomial_tpe.c in Sources */,\n\t\t\t\t985F3EF724BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98E9A6A81A3CD5A0000AD4FC /* haplosome.cpp in Sources */,\n\t\t\t\t98CEFD202AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t981DC35028E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98CEFD882AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t9807661C244934A800F6CBB4 /* zutil.c in Sources */,\n\t\t\t\t98CEFD482AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t9854D2672278B9F8001D43BC /* trees.c in Sources */,\n\t\t\t\t98332B031FDBCFC300274FF0 /* init.c in Sources */,\n\t\t\t\t98C821281C7A980000548839 /* stream.c in Sources */,\n\t\t\t\t9807C0F524BA21B7008CC658 /* slim_test_core.cpp in Sources */,\n\t\t\t\t98A513541B66B6CA005A753D /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98E9A6991A3CD52A000AD4FC /* chromosome.cpp in Sources */,\n\t\t\t\t985F3EF224BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98C821261C7A980000548839 /* error.c in Sources */,\n\t\t\t\t9850D8E32063098E006BFD2E /* tables.c in Sources */,\n\t\t\t\t98AB597B1B2531F10077CB4A /* slim_eidos_block.cpp in Sources */,\n\t\t\t\t9854D2632278B9F8001D43BC /* convert.c in Sources */,\n\t\t\t\t985F3EED24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t985F3EFC24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98EDB5022E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98076617244934A800F6CBB4 /* deflate.c in Sources */,\n\t\t\t\t98EDB4F82E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98C8213A1C7A980000548839 /* gamma.c in Sources */,\n\t\t\t\t982B50C62704048E006E91BC /* nbinomial.c in Sources */,\n\t\t\t\t98C821311C7A980000548839 /* poisson.c in Sources */,\n\t\t\t\t985D1D8B2808B84F00461CFA /* sparse_vector.cpp in Sources */,\n\t\t\t\t98E9A6AE1A3CD5D3000AD4FC /* population.cpp in Sources */,\n\t\t\t\t9876E6121ED55C6B00FF9762 /* beta.c in Sources */,\n\t\t\t\t98332AE81FDBC1D900274FF0 /* rowcol.c in Sources */,\n\t\t\t\t98C821361C7A980000548839 /* taus.c in Sources */,\n\t\t\t\t98E9A6B81A3CE35E000AD4FC /* eidos_rng.cpp in Sources */,\n\t\t\t\t98C821AD1C7A9B1600548839 /* geometric.c in Sources */,\n\t\t\t\t98CEFD182AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t98A5134F1B66B69E005A753D /* eidos_token.cpp in Sources */,\n\t\t\t\t9854D25F2278B9F8001D43BC /* core.c in Sources */,\n\t\t\t\t98C8219E1C7A99B200548839 /* minmax.c in Sources */,\n\t\t\t\t98076622244934A800F6CBB4 /* trees.c in Sources */,\n\t\t\t\t981DC36C28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98332AC21FDBA53F00274FF0 /* xerbla.c in Sources */,\n\t\t\t\t98D7D6652AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t985724D51AD481070047C223 /* eidos_test.cpp in Sources */,\n\t\t\t\t98CEFD752AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98EDB5112E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t986070EA2AACECD600FD6143 /* spatial_kernel.cpp in Sources */,\n\t\t\t\t98332AB41FDBA1E100274FF0 /* blas.c in Sources */,\n\t\t\t\t9809DFA02550F32500C4E82D /* log_file.cpp in Sources */,\n\t\t\t\t989A5BE92525304100E7192D /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98C92AED1D0B07A6001C82BC /* individual.cpp in Sources */,\n\t\t\t\t98DC9841289986B300160DD8 /* GitSHA1_Xcode.cpp in Sources */,\n\t\t\t\t98ACDC9D253522B80038703F /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98235682252FDCF50096A745 /* lodepng.cpp in Sources */,\n\t\t\t\t98606AEE1DED0DCD00821CFF /* mutation_run.cpp in Sources */,\n\t\t\t\t98C821241C7A980000548839 /* inline.c in Sources */,\n\t\t\t\t98CEFD6C2AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98DE4C131B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98076614244934A800F6CBB4 /* compress.c in Sources */,\n\t\t\t\t98E9A6961A3CD51A000AD4FC /* genomic_element_type.cpp in Sources */,\n\t\t\t\t98CEFD642AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98C821A91C7A9B1600548839 /* discrete.c in Sources */,\n\t\t\t\t98C8212B1C7A980000548839 /* exponential.c in Sources */,\n\t\t\t\t985724A51AD435310047C223 /* eidos_value.cpp in Sources */,\n\t\t\t\t9893C7E31CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t985724A11AD34B740047C223 /* eidos_functions.cpp in Sources */,\n\t\t\t\t981DC36028E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98C8213C1C7A980000548839 /* pow_int.c in Sources */,\n\t\t\t\t98C821321C7A980000548839 /* weibull.c in Sources */,\n\t\t\t\t98C821411C7A980000548839 /* fdiv.c in Sources */,\n\t\t\t\t98CEFCEC2AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98332AD71FDBBD1600274FF0 /* cholesky.c in Sources */,\n\t\t\t\t987D19A5209A53850030D28D /* kastore.c in Sources */,\n\t\t\t\t9876E5F51ED5572C00FF9762 /* tdist.c in Sources */,\n\t\t\t\t98E9A69C1A3CD542000AD4FC /* polymorphism.cpp in Sources */,\n\t\t\t\t989790DA1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t987A700F2AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t982663541A3BABD300A0CBBF /* main.cpp in Sources */,\n\t\t\t\t981DC36828E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98D7D65C2AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98DDAED6221765480038C133 /* slim_functions.cpp in Sources */,\n\t\t\t\t9876E5FC1ED5599F00FF9762 /* gauss.c in Sources */,\n\t\t\t\t98EDB4EE2E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t988880EC20744EE900E10172 /* cauchy.c in Sources */,\n\t\t\t\t98E9A69F1A3CD551000AD4FC /* substitution.cpp in Sources */,\n\t\t\t\t9854D2612278B9F8001D43BC /* genotypes.c in Sources */,\n\t\t\t\t981DC35828E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98C821391C7A980000548839 /* exp.c in Sources */,\n\t\t\t\t98076620244934A800F6CBB4 /* gzwrite.c in Sources */,\n\t\t\t\t98CEFD7E2AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98076626244934A800F6CBB4 /* adler32.c in Sources */,\n\t\t\t\t98C8213E1C7A980000548839 /* trig.c in Sources */,\n\t\t\t\t98321F941B406B67007337A3 /* eidos_globals.cpp in Sources */,\n\t\t\t\t985F3EEA24BA27EC00E712E0 /* slim_test_genetics.cpp in Sources */,\n\t\t\t\t98C821301C7A980000548839 /* multinomial.c in Sources */,\n\t\t\t\t98332B0A1FDBD00800274FF0 /* init.c in Sources */,\n\t\t\t\t98C821251C7A980000548839 /* math.c in Sources */,\n\t\t\t\t98E9A6931A3CD4EF000AD4FC /* genomic_element.cpp in Sources */,\n\t\t\t\t9898172F1A59750300F7417C /* slim_globals.cpp in Sources */,\n\t\t\t\t98DB3D6F1E6122AE00E2C200 /* interaction_type.cpp in Sources */,\n\t\t\t\t98E9A6AB1A3CD5BB000AD4FC /* subpopulation.cpp in Sources */,\n\t\t\t\t98332AF71FDBC3F100274FF0 /* swap.c in Sources */,\n\t\t\t\t9807661E244934A800F6CBB4 /* gzlib.c in Sources */,\n\t\t\t\t98AC617A24BA34ED0001914C /* species_eidos.cpp in Sources */,\n\t\t\t\t98C821341C7A980000548839 /* mt.c in Sources */,\n\t\t\t\t9857249C1AD08A810047C223 /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98C821331C7A980000548839 /* inline.c in Sources */,\n\t\t\t\t98C821271C7A980000548839 /* message.c in Sources */,\n\t\t\t\t984824F1210B9F23002402A5 /* dtrsv.c in Sources */,\n\t\t\t\t98C821421C7A980000548839 /* infnan.c in Sources */,\n\t\t\t\t9807662924493A8F00F6CBB4 /* crc32.c in Sources */,\n\t\t\t\t98C8213F1C7A980000548839 /* zeta.c in Sources */,\n\t\t\t\t9890D1ED27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98C821351C7A980000548839 /* rng.c in Sources */,\n\t\t\t\t98332ACE1FDBA81A00274FF0 /* oper.c in Sources */,\n\t\t\t\t98C821291C7A980000548839 /* beta.c in Sources */,\n\t\t\t\tD0A758F720A4CC9800132D2F /* text_input.c in Sources */,\n\t\t\t\t98C821A31C7A99F000548839 /* pow_int.c in Sources */,\n\t\t\t\t985F3F0624BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98C8212F1C7A980000548839 /* lognormal.c in Sources */,\n\t\t\t\t981DC35C28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98CEFCF42AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t9836867427CD40CF00683639 /* community.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t984D5FA41E3AF0D200473719 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t986152112B167AED0083E68F /* polymorphism.cpp in Sources */,\n\t\t\t\t986152632B167B4E0083E68F /* beta.c in Sources */,\n\t\t\t\t9861526C2B167B4E0083E68F /* multinomial.c in Sources */,\n\t\t\t\t986152712B167B4E0083E68F /* dtrsv.c in Sources */,\n\t\t\t\t98C634462EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t9861525E2B167B4E0083E68F /* laplace.c in Sources */,\n\t\t\t\t986151FD2B167A6A0083E68F /* eidos_rng.cpp in Sources */,\n\t\t\t\t986152732B167B4E0083E68F /* binomial_tpe.c in Sources */,\n\t\t\t\t986152672B167B4E0083E68F /* spline2d.c in Sources */,\n\t\t\t\t986152612B167B4E0083E68F /* dgemv.c in Sources */,\n\t\t\t\t986152482B167B4E0083E68F /* fdist.c in Sources */,\n\t\t\t\t9861525A2B167B4E0083E68F /* interp.c in Sources */,\n\t\t\t\t9861521F2B167AED0083E68F /* haplosome.cpp in Sources */,\n\t\t\t\t986152572B167B4E0083E68F /* mt.c in Sources */,\n\t\t\t\t986152182B167AED0083E68F /* slim_eidos_block.cpp in Sources */,\n\t\t\t\t9861520D2B167AED0083E68F /* slim_globals.cpp in Sources */,\n\t\t\t\t98EDB4E92E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t986152462B167B4E0083E68F /* infnan.c in Sources */,\n\t\t\t\t986151F12B167A430083E68F /* eidos_functions.cpp in Sources */,\n\t\t\t\t9861521D2B167AED0083E68F /* genomic_element_type.cpp in Sources */,\n\t\t\t\t986152212B167AED0083E68F /* slim_test_core.cpp in Sources */,\n\t\t\t\t986152762B167C620083E68F /* kastore.c in Sources */,\n\t\t\t\t986152782B167D0B0083E68F /* eidos_sorting.cpp in Sources */,\n\t\t\t\t9861525C2B167B4E0083E68F /* gaussinv.c in Sources */,\n\t\t\t\t986151E22B167A130083E68F /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t9861520B2B167A940083E68F /* text_input.c in Sources */,\n\t\t\t\t986152502B167B4E0083E68F /* gamma_inc.c in Sources */,\n\t\t\t\t9861526E2B167B4E0083E68F /* dtrmv.c in Sources */,\n\t\t\t\t9861521A2B167AED0083E68F /* individual.cpp in Sources */,\n\t\t\t\t986152042B167A7A0083E68F /* crc32.c in Sources */,\n\t\t\t\t986152192B167AED0083E68F /* slim_functions.cpp in Sources */,\n\t\t\t\t986151F02B167A400083E68F /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t9861520A2B167A940083E68F /* stats.c in Sources */,\n\t\t\t\t986151E52B167A1C0083E68F /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t986151E82B167A280083E68F /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t9861526B2B167B4E0083E68F /* submatrix.c in Sources */,\n\t\t\t\t986152052B167A7A0083E68F /* compress.c in Sources */,\n\t\t\t\t986152702B167B4E0083E68F /* nbinomial.c in Sources */,\n\t\t\t\t986152252B167AED0083E68F /* sparse_vector.cpp in Sources */,\n\t\t\t\t9861524F2B167B4E0083E68F /* message.c in Sources */,\n\t\t\t\t98EDB4D52E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t9861522B2B167B4E0083E68F /* interp2d.c in Sources */,\n\t\t\t\t986152692B167B4E0083E68F /* minmax.c in Sources */,\n\t\t\t\t986152552B167B4E0083E68F /* inline.c in Sources */,\n\t\t\t\t986152582B167B4E0083E68F /* exp.c in Sources */,\n\t\t\t\t9861523E2B167B4E0083E68F /* oper.c in Sources */,\n\t\t\t\t986151FC2B167A670083E68F /* eidos_globals.cpp in Sources */,\n\t\t\t\t9861522A2B167B4E0083E68F /* math.c in Sources */,\n\t\t\t\t986152122B167AED0083E68F /* spatial_map.cpp in Sources */,\n\t\t\t\t9861524B2B167B4E0083E68F /* error.c in Sources */,\n\t\t\t\t986152222B167AED0083E68F /* subpopulation.cpp in Sources */,\n\t\t\t\t9861522F2B167B4E0083E68F /* linear.c in Sources */,\n\t\t\t\t986151EE2B167A3A0083E68F /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t986152382B167B4E0083E68F /* tridiag.c in Sources */,\n\t\t\t\t986152372B167B4E0083E68F /* weibull.c in Sources */,\n\t\t\t\t986152752B167B4E0083E68F /* view.c in Sources */,\n\t\t\t\t986152302B167B4E0083E68F /* init.c in Sources */,\n\t\t\t\t9861525F2B167B4E0083E68F /* beta.c in Sources */,\n\t\t\t\t986151F42B167A4F0083E68F /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98DB3D711E6122AE00E2C200 /* interaction_type.cpp in Sources */,\n\t\t\t\t9861523C2B167B4E0083E68F /* pow_int.c in Sources */,\n\t\t\t\t986151EB2B167A320083E68F /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t986152012B167A7A0083E68F /* trees.c in Sources */,\n\t\t\t\t986152442B167B4E0083E68F /* stream.c in Sources */,\n\t\t\t\t986151F92B167A5E0083E68F /* eidos_script.cpp in Sources */,\n\t\t\t\t986152522B167B4E0083E68F /* akima.c in Sources */,\n\t\t\t\t986151E72B167A210083E68F /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t9861521E2B167AED0083E68F /* substitution.cpp in Sources */,\n\t\t\t\t9861522D2B167B4E0083E68F /* fdiv.c in Sources */,\n\t\t\t\t98EDB5082E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t986152652B167B4E0083E68F /* shuffle.c in Sources */,\n\t\t\t\t98EDB4FE2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t9861526F2B167B4E0083E68F /* rowcol.c in Sources */,\n\t\t\t\t98ACDCA1253522B80038703F /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t986151F22B167A490083E68F /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t986151E62B167A1E0083E68F /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t986151E02B167A080083E68F /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t9861524C2B167B4E0083E68F /* expint.c in Sources */,\n\t\t\t\t9861526A2B167B4E0083E68F /* matrix.c in Sources */,\n\t\t\t\t986152152B167AED0083E68F /* slim_test_other.cpp in Sources */,\n\t\t\t\t986152022B167A7A0083E68F /* gzlib.c in Sources */,\n\t\t\t\t986151F32B167A4D0083E68F /* eidos_type_table.cpp in Sources */,\n\t\t\t\t986151E42B167A190083E68F /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t984D5FB51E3AF1F000473719 /* SLiMTests.mm in Sources */,\n\t\t\t\t986152772B167CBE0083E68F /* eidos_beep.cpp in Sources */,\n\t\t\t\t986151EF2B167A3D0083E68F /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t986152142B167AED0083E68F /* mutation_run.cpp in Sources */,\n\t\t\t\t986152172B167AED0083E68F /* population.cpp in Sources */,\n\t\t\t\t9861524E2B167B4E0083E68F /* bilinear.c in Sources */,\n\t\t\t\t986151F82B167A5B0083E68F /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t986152332B167B4E0083E68F /* tdist.c in Sources */,\n\t\t\t\t9861525D2B167B4E0083E68F /* gauss.c in Sources */,\n\t\t\t\t98EDB5172E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t98235686252FDCF50096A745 /* lodepng.cpp in Sources */,\n\t\t\t\t986152292B167B4E0083E68F /* vector.c in Sources */,\n\t\t\t\t986152342B167B4E0083E68F /* bicubic.c in Sources */,\n\t\t\t\t986152202B167AED0083E68F /* slim_test_genetics.cpp in Sources */,\n\t\t\t\t986152362B167B4E0083E68F /* zeta.c in Sources */,\n\t\t\t\t986151EA2B167A2E0083E68F /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t989A5BED2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t986152642B167B4E0083E68F /* gamma.c in Sources */,\n\t\t\t\t9861521B2B167AED0083E68F /* species.cpp in Sources */,\n\t\t\t\t986152162B167AED0083E68F /* spatial_kernel.cpp in Sources */,\n\t\t\t\t986152562B167B4E0083E68F /* coerce.c in Sources */,\n\t\t\t\t986152592B167B4E0083E68F /* init.c in Sources */,\n\t\t\t\t986152662B167B4E0083E68F /* init.c in Sources */,\n\t\t\t\t9861524A2B167B4E0083E68F /* ddot.c in Sources */,\n\t\t\t\t986152602B167B4E0083E68F /* lognormal.c in Sources */,\n\t\t\t\t9861523D2B167B4E0083E68F /* exponential.c in Sources */,\n\t\t\t\t986151E12B167A0F0083E68F /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t986152232B167AED0083E68F /* chromosome.cpp in Sources */,\n\t\t\t\t986152032B167A7A0083E68F /* zutil.c in Sources */,\n\t\t\t\t9861520C2B167A940083E68F /* trees.c in Sources */,\n\t\t\t\t986151F52B167A520083E68F /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t986151DE2B1679C20083E68F /* slim_test.cpp in Sources */,\n\t\t\t\t986152102B167AED0083E68F /* genomic_element.cpp in Sources */,\n\t\t\t\t986152512B167B4E0083E68F /* geometric.c in Sources */,\n\t\t\t\t986151FB2B167A640083E68F /* eidos_token.cpp in Sources */,\n\t\t\t\t986152682B167B4E0083E68F /* cholesky.c in Sources */,\n\t\t\t\t986152002B167A7A0083E68F /* gzwrite.c in Sources */,\n\t\t\t\t986152272B167B4E0083E68F /* taus.c in Sources */,\n\t\t\t\t986152092B167A940083E68F /* convert.c in Sources */,\n\t\t\t\t986152262B167AED0083E68F /* mutation_type.cpp in Sources */,\n\t\t\t\t986152312B167B4E0083E68F /* gamma.c in Sources */,\n\t\t\t\t9861522C2B167B4E0083E68F /* discrete.c in Sources */,\n\t\t\t\t986152412B167B4E0083E68F /* poisson.c in Sources */,\n\t\t\t\t9861522E2B167B4E0083E68F /* pow_int.c in Sources */,\n\t\t\t\t986152082B167A940083E68F /* core.c in Sources */,\n\t\t\t\t986151F62B167A550083E68F /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98EDB4F42E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t986152132B167AED0083E68F /* species_eidos.cpp in Sources */,\n\t\t\t\t986152242B167AED0083E68F /* log_file.cpp in Sources */,\n\t\t\t\t9861520F2B167AED0083E68F /* mutation.cpp in Sources */,\n\t\t\t\t986152542B167B4E0083E68F /* erfc.c in Sources */,\n\t\t\t\t9861525B2B167B4E0083E68F /* swap.c in Sources */,\n\t\t\t\t986152352B167B4E0083E68F /* trig.c in Sources */,\n\t\t\t\t986152722B167B4E0083E68F /* copy.c in Sources */,\n\t\t\t\t986152492B167B4E0083E68F /* cspline.c in Sources */,\n\t\t\t\t986152072B167A940083E68F /* tables.c in Sources */,\n\t\t\t\t986152432B167B4E0083E68F /* tdist.c in Sources */,\n\t\t\t\t986152452B167B4E0083E68F /* gausszig.c in Sources */,\n\t\t\t\t986151E32B167A160083E68F /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t986151DF2B1679EC0083E68F /* eidos_test.cpp in Sources */,\n\t\t\t\t986151E92B167A2C0083E68F /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t986151EC2B167A350083E68F /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t984D5FB31E3AF18C00473719 /* EidosTests.mm in Sources */,\n\t\t\t\t986152472B167B4E0083E68F /* elementary.c in Sources */,\n\t\t\t\t986151F72B167A580083E68F /* eidos_value.cpp in Sources */,\n\t\t\t\t9861521C2B167AED0083E68F /* community.cpp in Sources */,\n\t\t\t\t986152322B167B4E0083E68F /* inline.c in Sources */,\n\t\t\t\t986151FA2B167A610083E68F /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t986152402B167B4E0083E68F /* accel.c in Sources */,\n\t\t\t\t986152742B167B4E0083E68F /* gauss.c in Sources */,\n\t\t\t\t986151FF2B167A7A0083E68F /* deflate.c in Sources */,\n\t\t\t\t9861526D2B167B4E0083E68F /* mvgauss.c in Sources */,\n\t\t\t\t986152622B167B4E0083E68F /* blas.c in Sources */,\n\t\t\t\t986152392B167B4E0083E68F /* log.c in Sources */,\n\t\t\t\t9823568D252FE61A0096A745 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t986151ED2B167A380083E68F /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t9861523F2B167B4E0083E68F /* inline.c in Sources */,\n\t\t\t\t986152282B167B4E0083E68F /* rng.c in Sources */,\n\t\t\t\t9890D2002713741C001EAE98 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t9861520E2B167AED0083E68F /* community_eidos.cpp in Sources */,\n\t\t\t\t9861524D2B167B4E0083E68F /* psi.c in Sources */,\n\t\t\t\t9861523B2B167B4E0083E68F /* spline.c in Sources */,\n\t\t\t\t986152532B167B4E0083E68F /* xerbla.c in Sources */,\n\t\t\t\t986152062B167A940083E68F /* genotypes.c in Sources */,\n\t\t\t\t986151FE2B167A710083E68F /* adler32.c in Sources */,\n\t\t\t\t986152422B167B4E0083E68F /* cauchy.c in Sources */,\n\t\t\t\t9861523A2B167B4E0083E68F /* chisq.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t985724AB1AD478630047C223 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CEFD812AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98332AF91FDBC42700274FF0 /* swap.c in Sources */,\n\t\t\t\t98C821A01C7A99B200548839 /* minmax.c in Sources */,\n\t\t\t\t981DC35E28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t985724D21AD479010047C223 /* eidos_functions.cpp in Sources */,\n\t\t\t\t98C821621C7A983800548839 /* math.c in Sources */,\n\t\t\t\t9876E60F1ED55C0C00FF9762 /* expint.c in Sources */,\n\t\t\t\t98C8217C1C7A983800548839 /* coerce.c in Sources */,\n\t\t\t\t98C821651C7A983800548839 /* stream.c in Sources */,\n\t\t\t\t98321F961B406B67007337A3 /* eidos_globals.cpp in Sources */,\n\t\t\t\t985724CF1AD479010047C223 /* eidos_script.cpp in Sources */,\n\t\t\t\t9807663024493E0B00F6CBB4 /* gzlib.c in Sources */,\n\t\t\t\t98EDB5052E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98C821741C7A983800548839 /* elementary.c in Sources */,\n\t\t\t\t98EDB4FB2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98332ABB1FDBA32500274FF0 /* dtrmv.c in Sources */,\n\t\t\t\t98C8216E1C7A983800548839 /* poisson.c in Sources */,\n\t\t\t\t9876E6041ED55A7800FF9762 /* gamma_inc.c in Sources */,\n\t\t\t\t9807663224493E0B00F6CBB4 /* adler32.c in Sources */,\n\t\t\t\t98CEFD1B2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t981DC37228E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98C8216D1C7A983800548839 /* multinomial.c in Sources */,\n\t\t\t\t98332AB61FDBA1E500274FF0 /* blas.c in Sources */,\n\t\t\t\t98C8216F1C7A983800548839 /* weibull.c in Sources */,\n\t\t\t\t986D73EA1B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t981DC36E28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98A513511B66B69E005A753D /* eidos_token.cpp in Sources */,\n\t\t\t\t9876E5FE1ED559A600FF9762 /* gauss.c in Sources */,\n\t\t\t\t98332ADE1FDBC0D700274FF0 /* dgemv.c in Sources */,\n\t\t\t\t98C821611C7A983800548839 /* inline.c in Sources */,\n\t\t\t\t9876E6141ED55C7400FF9762 /* beta.c in Sources */,\n\t\t\t\t981DC36A28E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t981DC35A28E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t981DC35228E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t985F3F0824BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t9825565C1BA32EE80054CB3F /* EidosCocoaExtra.mm in Sources */,\n\t\t\t\t98321F911B406417007337A3 /* eidos_rng.cpp in Sources */,\n\t\t\t\t98C821671C7A983800548839 /* binomial_tpe.c in Sources */,\n\t\t\t\t98C821AB1C7A9B1600548839 /* discrete.c in Sources */,\n\t\t\t\t98EDB4E62E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t9893C7E51CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98ACDC9F253522B80038703F /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98CEFD782AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t9807662F24493E0B00F6CBB4 /* compress.c in Sources */,\n\t\t\t\t98C8216B1C7A983800548839 /* gausszig.c in Sources */,\n\t\t\t\t98C821AF1C7A9B1600548839 /* geometric.c in Sources */,\n\t\t\t\t98C821631C7A983800548839 /* error.c in Sources */,\n\t\t\t\t98EFE6311ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t985F3EF924BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t985F3EF424BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98332AC41FDBA54600274FF0 /* xerbla.c in Sources */,\n\t\t\t\t98C821731C7A983800548839 /* taus.c in Sources */,\n\t\t\t\t9807662D24493E0B00F6CBB4 /* trees.c in Sources */,\n\t\t\t\t98332B0C1FDBD03200274FF0 /* init.c in Sources */,\n\t\t\t\t98A513561B66B6CA005A753D /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98C821701C7A983800548839 /* inline.c in Sources */,\n\t\t\t\t98C821B41C7A9B9F00548839 /* shuffle.c in Sources */,\n\t\t\t\t98332B1A1FDBD16500274FF0 /* copy.c in Sources */,\n\t\t\t\t98CEFD532AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98332B131FDBD0F500274FF0 /* init.c in Sources */,\n\t\t\t\t98332AD01FDBA87D00274FF0 /* oper.c in Sources */,\n\t\t\t\t985724B71AD478630047C223 /* main.m in Sources */,\n\t\t\t\t981DC36228E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98CEFCF72AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98090FA61B1B978900791DBF /* EidosValueWrapper.mm in Sources */,\n\t\t\t\t98D7D65F2AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98CEFD6F2AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98C8217B1C7A983800548839 /* zeta.c in Sources */,\n\t\t\t\t9807662E24493E0B00F6CBB4 /* deflate.c in Sources */,\n\t\t\t\t98C821721C7A983800548839 /* rng.c in Sources */,\n\t\t\t\t98332AD91FDBBE3600274FF0 /* cholesky.c in Sources */,\n\t\t\t\t98C8216C1C7A983800548839 /* lognormal.c in Sources */,\n\t\t\t\t98D218C61B2E213200156FC3 /* EidosTextView.mm in Sources */,\n\t\t\t\t98C821751C7A983800548839 /* exp.c in Sources */,\n\t\t\t\t98C821771C7A983800548839 /* log.c in Sources */,\n\t\t\t\t98C821781C7A983800548839 /* pow_int.c in Sources */,\n\t\t\t\t98332AF21FDBC36300274FF0 /* submatrix.c in Sources */,\n\t\t\t\t98CEFD332AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t9807662C24493E0B00F6CBB4 /* zutil.c in Sources */,\n\t\t\t\t98332AFE1FDBC4BB00274FF0 /* matrix.c in Sources */,\n\t\t\t\t98235684252FDCF50096A745 /* lodepng.cpp in Sources */,\n\t\t\t\t98C8217A1C7A983800548839 /* trig.c in Sources */,\n\t\t\t\t98CEFD232AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98332AC91FDBA74900274FF0 /* vector.c in Sources */,\n\t\t\t\t98CEFD672AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98EDB5142E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t988880EE20744F0100E10172 /* cauchy.c in Sources */,\n\t\t\t\t98C8217D1C7A983800548839 /* fdiv.c in Sources */,\n\t\t\t\t985724D01AD479010047C223 /* eidos_value.cpp in Sources */,\n\t\t\t\t987A2A0924033856009A636F /* gaussinv.c in Sources */,\n\t\t\t\t981DC35628E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t989A5BEB2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t982556661BA450980054CB3F /* EidosHelpController.mm in Sources */,\n\t\t\t\t98332AEE1FDBC29500274FF0 /* rowcol.c in Sources */,\n\t\t\t\t9890D1EF27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t987AD8871B2CC0C10035D6C8 /* EidosVariableBrowserController.mm in Sources */,\n\t\t\t\t98EDB4F12E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t987A70122AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t98729ADB2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t9807662B24493E0B00F6CBB4 /* crc32.c in Sources */,\n\t\t\t\t98CEFD132AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98CEFCEF2AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98C821661C7A983800548839 /* beta.c in Sources */,\n\t\t\t\t985F3EFE24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98C634452EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98C821791C7A983800548839 /* psi.c in Sources */,\n\t\t\t\t98CEFD8B2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t985724D31AD479010047C223 /* eidos_test.cpp in Sources */,\n\t\t\t\t98EDB4D22E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t98C8217E1C7A983800548839 /* infnan.c in Sources */,\n\t\t\t\t98DE4C151B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98CEFD4B2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t985724B51AD478630047C223 /* EidosAppDelegate.mm in Sources */,\n\t\t\t\t9876E5F71ED5573700FF9762 /* tdist.c in Sources */,\n\t\t\t\t9807663124493E0B00F6CBB4 /* gzwrite.c in Sources */,\n\t\t\t\t9893C7E01CDA2FC20029AC94 /* eidos_beep.cpp in Sources */,\n\t\t\t\t98C821711C7A983800548839 /* mt.c in Sources */,\n\t\t\t\t980566E425A7C5B9008D3C7F /* fdist.c in Sources */,\n\t\t\t\t98C821761C7A983800548839 /* gamma.c in Sources */,\n\t\t\t\t984824F6210B9F32002402A5 /* ddot.c in Sources */,\n\t\t\t\t985724E71AD622880047C223 /* EidosConsoleTextView.mm in Sources */,\n\t\t\t\t989790DC1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t9876E60A1ED55B4F00FF9762 /* erfc.c in Sources */,\n\t\t\t\t985724D11AD479010047C223 /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98D7D6682AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t98C8216A1C7A983800548839 /* gauss.c in Sources */,\n\t\t\t\t98C821681C7A983800548839 /* exponential.c in Sources */,\n\t\t\t\t984824F3210B9F2D002402A5 /* dtrsv.c in Sources */,\n\t\t\t\t985F3F0D24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t9893C7EB1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t982B50C82704048E006E91BC /* nbinomial.c in Sources */,\n\t\t\t\t9823568B252FE61A0096A745 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98C821A51C7A99F000548839 /* pow_int.c in Sources */,\n\t\t\t\t987AD88B1B2CDBB80035D6C8 /* EidosConsoleWindowController.mm in Sources */,\n\t\t\t\t985F3EEF24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98332B051FDBCFF900274FF0 /* init.c in Sources */,\n\t\t\t\t98332AA01FDB990500274FF0 /* mvgauss.c in Sources */,\n\t\t\t\t98C821641C7A983800548839 /* message.c in Sources */,\n\t\t\t\t98D5246A1F2EB4DD005AD9A6 /* EidosPrettyprinter.mm in Sources */,\n\t\t\t\t985F3F0324BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t981DC36628E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98C821691C7A983800548839 /* gamma.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF51F4294A3FC900557BBA /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CF51F5294A3FC900557BBA /* nbinomial.c in Sources */,\n\t\t\t\t98CF51F6294A3FC900557BBA /* eidos_globals.cpp in Sources */,\n\t\t\t\t98CF51F7294A3FC900557BBA /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t98CF51F8294A3FC900557BBA /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98CF51F9294A3FC900557BBA /* pow_int.c in Sources */,\n\t\t\t\t98CF51FA294A3FC900557BBA /* slim_eidos_block.cpp in Sources */,\n\t\t\t\t98CF51FB294A3FC900557BBA /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98CF51FC294A3FC900557BBA /* geometric.c in Sources */,\n\t\t\t\t98CF51FD294A3FC900557BBA /* eidos_script.cpp in Sources */,\n\t\t\t\t98CF51FE294A3FC900557BBA /* beta.c in Sources */,\n\t\t\t\t98CF51FF294A3FC900557BBA /* ddot.c in Sources */,\n\t\t\t\t98CF5200294A3FC900557BBA /* main.m in Sources */,\n\t\t\t\t98CF5201294A3FC900557BBA /* EidosValueWrapper.mm in Sources */,\n\t\t\t\t98CF5202294A3FC900557BBA /* inline.c in Sources */,\n\t\t\t\t98CEFD122AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98CF5203294A3FC900557BBA /* error.c in Sources */,\n\t\t\t\t98CF5204294A3FC900557BBA /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98CF5205294A3FC900557BBA /* oper.c in Sources */,\n\t\t\t\t98CF5206294A3FC900557BBA /* trees.c in Sources */,\n\t\t\t\t98CF5207294A3FC900557BBA /* eidos_rng.cpp in Sources */,\n\t\t\t\t98CEFCF62AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98CF5208294A3FC900557BBA /* eidos_beep.cpp in Sources */,\n\t\t\t\t98CF5209294A3FC900557BBA /* GraphView.mm in Sources */,\n\t\t\t\t98CF520A294A3FC900557BBA /* stream.c in Sources */,\n\t\t\t\t98CEFD662AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98CF520B294A3FC900557BBA /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t98CF520C294A3FC900557BBA /* init.c in Sources */,\n\t\t\t\t98CF520D294A3FC900557BBA /* interaction_type.cpp in Sources */,\n\t\t\t\t98CF520E294A3FC900557BBA /* subpopulation.cpp in Sources */,\n\t\t\t\t98CF520F294A3FC900557BBA /* community.cpp in Sources */,\n\t\t\t\t98CF5210294A3FC900557BBA /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98CF5211294A3FC900557BBA /* EidosTextView.mm in Sources */,\n\t\t\t\t98CF5212294A3FC900557BBA /* swap.c in Sources */,\n\t\t\t\t98CF5213294A3FC900557BBA /* eidos_test.cpp in Sources */,\n\t\t\t\t98CF5214294A3FC900557BBA /* dgemv.c in Sources */,\n\t\t\t\t98CF5215294A3FC900557BBA /* binomial_tpe.c in Sources */,\n\t\t\t\t98CF5216294A3FC900557BBA /* tables.c in Sources */,\n\t\t\t\t98CF5217294A3FC900557BBA /* species_eidos.cpp in Sources */,\n\t\t\t\t98729ADA2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98CF5218294A3FC900557BBA /* slim_functions.cpp in Sources */,\n\t\t\t\t98CF5219294A3FC900557BBA /* deflate.c in Sources */,\n\t\t\t\t98CF521A294A3FC900557BBA /* FindRecipeController.mm in Sources */,\n\t\t\t\t98CF521B294A3FC900557BBA /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98CF521C294A3FC900557BBA /* mutation_run.cpp in Sources */,\n\t\t\t\t987A70112AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t98CF521D294A3FC900557BBA /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98CF521E294A3FC900557BBA /* copy.c in Sources */,\n\t\t\t\t98CF521F294A3FC900557BBA /* tdist.c in Sources */,\n\t\t\t\t98CF5220294A3FC900557BBA /* message.c in Sources */,\n\t\t\t\t98CF5221294A3FC900557BBA /* multinomial.c in Sources */,\n\t\t\t\t98CF5222294A3FC900557BBA /* rng.c in Sources */,\n\t\t\t\t98CF5223294A3FC900557BBA /* taus.c in Sources */,\n\t\t\t\t98CEFD6E2AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98CF5224294A3FC900557BBA /* gaussinv.c in Sources */,\n\t\t\t\t98CF5225294A3FC900557BBA /* slim_test_genetics.cpp in Sources */,\n\t\t\t\t98CF5226294A3FC900557BBA /* blas.c in Sources */,\n\t\t\t\t98CF5227294A3FC900557BBA /* mt.c in Sources */,\n\t\t\t\t98CF5228294A3FC900557BBA /* genomic_element.cpp in Sources */,\n\t\t\t\t98CF5229294A3FC900557BBA /* pow_int.c in Sources */,\n\t\t\t\t98CF522A294A3FC900557BBA /* substitution.cpp in Sources */,\n\t\t\t\t98CF522B294A3FC900557BBA /* core.c in Sources */,\n\t\t\t\t98CF522C294A3FC900557BBA /* beta.c in Sources */,\n\t\t\t\t98EDB5132E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t98CF522D294A3FC900557BBA /* exponential.c in Sources */,\n\t\t\t\t98CF522E294A3FC900557BBA /* poisson.c in Sources */,\n\t\t\t\t98CF522F294A3FC900557BBA /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98CF5230294A3FC900557BBA /* gauss.c in Sources */,\n\t\t\t\t98CF5231294A3FC900557BBA /* EidosHelpController.mm in Sources */,\n\t\t\t\t98CF5232294A3FC900557BBA /* community_eidos.cpp in Sources */,\n\t\t\t\t98EDB4FA2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98CF5233294A3FC900557BBA /* lodepng.cpp in Sources */,\n\t\t\t\t98CF5234294A3FC900557BBA /* slim_test_other.cpp in Sources */,\n\t\t\t\t98CF5235294A3FC900557BBA /* eidos_value.cpp in Sources */,\n\t\t\t\t98CF5236294A3FC900557BBA /* fdiv.c in Sources */,\n\t\t\t\t98CF5237294A3FC900557BBA /* GraphView_MutationLossTimeHistogram.mm in Sources */,\n\t\t\t\t98CF5238294A3FC900557BBA /* trig.c in Sources */,\n\t\t\t\t98CEFD222AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98CF5239294A3FC900557BBA /* exp.c in Sources */,\n\t\t\t\t98CF523A294A3FC900557BBA /* individual.cpp in Sources */,\n\t\t\t\t98CF523B294A3FC900557BBA /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98CF523C294A3FC900557BBA /* weibull.c in Sources */,\n\t\t\t\t98CF523D294A3FC900557BBA /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98CF523E294A3FC900557BBA /* lognormal.c in Sources */,\n\t\t\t\t98CF523F294A3FC900557BBA /* gamma_inc.c in Sources */,\n\t\t\t\t98CF5240294A3FC900557BBA /* trees.c in Sources */,\n\t\t\t\t98CF5241294A3FC900557BBA /* CocoaExtra.mm in Sources */,\n\t\t\t\t98CF5242294A3FC900557BBA /* init.c in Sources */,\n\t\t\t\t98CF5243294A3FC900557BBA /* slim_test_core.cpp in Sources */,\n\t\t\t\t98CF5244294A3FC900557BBA /* EidosCocoaExtra.mm in Sources */,\n\t\t\t\t98CEFCEE2AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98EDB4F02E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t98CF5245294A3FC900557BBA /* gamma.c in Sources */,\n\t\t\t\t98CF5246294A3FC900557BBA /* dtrmv.c in Sources */,\n\t\t\t\t98CF5247294A3FC900557BBA /* crc32.c in Sources */,\n\t\t\t\t98CF5248294A3FC900557BBA /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98DEB4802AA632AA00ABE60F /* spatial_map.cpp in Sources */,\n\t\t\t\t98CF5249294A3FC900557BBA /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98CF524A294A3FC900557BBA /* SLiMPDFDocument.mm in Sources */,\n\t\t\t\t98CF524B294A3FC900557BBA /* eidos_functions.cpp in Sources */,\n\t\t\t\t98CEFD8A2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t98CF524C294A3FC900557BBA /* log_file.cpp in Sources */,\n\t\t\t\t98CEFD522AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98CF524D294A3FC900557BBA /* zutil.c in Sources */,\n\t\t\t\t98CF524E294A3FC900557BBA /* gauss.c in Sources */,\n\t\t\t\t98CF524F294A3FC900557BBA /* population.cpp in Sources */,\n\t\t\t\t98CF5250294A3FC900557BBA /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98CF5251294A3FC900557BBA /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98C634472EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98CF5252294A3FC900557BBA /* elementary.c in Sources */,\n\t\t\t\t986070EC2AACECD600FD6143 /* spatial_kernel.cpp in Sources */,\n\t\t\t\t98CF5254294A3FC900557BBA /* GraphView_FitnessOverTime.mm in Sources */,\n\t\t\t\t98CF5255294A3FC900557BBA /* SLiMWindowController.mm in Sources */,\n\t\t\t\t98CF5256294A3FC900557BBA /* PopulationView.mm in Sources */,\n\t\t\t\t98CF5257294A3FC900557BBA /* init.c in Sources */,\n\t\t\t\t98CF5258294A3FC900557BBA /* GraphView_PopulationVisualization.mm in Sources */,\n\t\t\t\t98CF5259294A3FC900557BBA /* EidosPrettyprinter.mm in Sources */,\n\t\t\t\t98CF525A294A3FC900557BBA /* coerce.c in Sources */,\n\t\t\t\t98CF525B294A3FC900557BBA /* genomic_element_type.cpp in Sources */,\n\t\t\t\t98CF525C294A3FC900557BBA /* AppDelegate.mm in Sources */,\n\t\t\t\t98CF525D294A3FC900557BBA /* shuffle.c in Sources */,\n\t\t\t\t98CF525E294A3FC900557BBA /* gamma.c in Sources */,\n\t\t\t\t98CF525F294A3FC900557BBA /* slim_test.cpp in Sources */,\n\t\t\t\t98CF5260294A3FC900557BBA /* sparse_vector.cpp in Sources */,\n\t\t\t\t98CF5261294A3FC900557BBA /* expint.c in Sources */,\n\t\t\t\t98CF5262294A3FC900557BBA /* mutation_type.cpp in Sources */,\n\t\t\t\t98CF5263294A3FC900557BBA /* convert.c in Sources */,\n\t\t\t\t98CEFD4A2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t98CF5264294A3FC900557BBA /* gzlib.c in Sources */,\n\t\t\t\t98CF5265294A3FC900557BBA /* erfc.c in Sources */,\n\t\t\t\t98CF5266294A3FC900557BBA /* polymorphism.cpp in Sources */,\n\t\t\t\t98EDB4E52E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98CF5267294A3FC900557BBA /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98CEFD322AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98CF5268294A3FC900557BBA /* species.cpp in Sources */,\n\t\t\t\t98CF526A294A3FC900557BBA /* zeta.c in Sources */,\n\t\t\t\t98CF526B294A3FC900557BBA /* text_input.c in Sources */,\n\t\t\t\t98CF526C294A3FC900557BBA /* log.c in Sources */,\n\t\t\t\t98CF526D294A3FC900557BBA /* cauchy.c in Sources */,\n\t\t\t\t98CF526E294A3FC900557BBA /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98CF526F294A3FC900557BBA /* fdist.c in Sources */,\n\t\t\t\t98CF5270294A3FC900557BBA /* ChromosomeView.mm in Sources */,\n\t\t\t\t98CF5272294A3FC900557BBA /* EidosConsoleTextView.mm in Sources */,\n\t\t\t\t98CF5273294A3FC900557BBA /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98CF5274294A3FC900557BBA /* vector.c in Sources */,\n\t\t\t\t98CEFD772AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98CF5275294A3FC900557BBA /* math.c in Sources */,\n\t\t\t\t98CF5276294A3FC900557BBA /* SLiMPDFWindowController.mm in Sources */,\n\t\t\t\t98CF5277294A3FC900557BBA /* matrix.c in Sources */,\n\t\t\t\t98CF5278294A3FC900557BBA /* GraphView_MutationFrequencyTrajectory.mm in Sources */,\n\t\t\t\t98CF5279294A3FC900557BBA /* compress.c in Sources */,\n\t\t\t\t98CF527A294A3FC900557BBA /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98CF527B294A3FC900557BBA /* SLiMDocument.mm in Sources */,\n\t\t\t\t98CF527C294A3FC900557BBA /* EidosConsoleWindowController.mm in Sources */,\n\t\t\t\t98CF527D294A3FC900557BBA /* SLiMDocumentController.mm in Sources */,\n\t\t\t\t98CF527E294A3FC900557BBA /* mvgauss.c in Sources */,\n\t\t\t\t98CF527F294A3FC900557BBA /* GraphView_MutationFixationTimeHistogram.mm in Sources */,\n\t\t\t\t98CF5280294A3FC900557BBA /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98CF5281294A3FC900557BBA /* rowcol.c in Sources */,\n\t\t\t\t98CF5282294A3FC900557BBA /* gausszig.c in Sources */,\n\t\t\t\t98CF5283294A3FC900557BBA /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98D7D6672AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t98CF5284294A3FC900557BBA /* kastore.c in Sources */,\n\t\t\t\t98CF5285294A3FC900557BBA /* gzwrite.c in Sources */,\n\t\t\t\t98CF5286294A3FC900557BBA /* chromosome.cpp in Sources */,\n\t\t\t\t98CF5287294A3FC900557BBA /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98CF5288294A3FC900557BBA /* psi.c in Sources */,\n\t\t\t\t98CF5289294A3FC900557BBA /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98E684412B694F09000B3B65 /* plot.mm in Sources */,\n\t\t\t\t98CF528A294A3FC900557BBA /* GraphView_MutationFrequencySpectra.mm in Sources */,\n\t\t\t\t98CF528B294A3FC900557BBA /* genotypes.c in Sources */,\n\t\t\t\t98CF528C294A3FC900557BBA /* SLiMPDFView.mm in Sources */,\n\t\t\t\t98CF528D294A3FC900557BBA /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98CEFD802AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98CF528E294A3FC900557BBA /* haplosome.cpp in Sources */,\n\t\t\t\t98CF528F294A3FC900557BBA /* stats.c in Sources */,\n\t\t\t\t98CF5290294A3FC900557BBA /* adler32.c in Sources */,\n\t\t\t\t98CF5291294A3FC900557BBA /* EidosVariableBrowserController.mm in Sources */,\n\t\t\t\t98EDB4D12E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t98CF5292294A3FC900557BBA /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98CF5293294A3FC900557BBA /* slim_gui.mm in Sources */,\n\t\t\t\t98CF5294294A3FC900557BBA /* mutation.cpp in Sources */,\n\t\t\t\t98CF5295294A3FC900557BBA /* slim_globals.cpp in Sources */,\n\t\t\t\t98D7D65E2AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98CF5296294A3FC900557BBA /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t98EDB5042E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98CF5297294A3FC900557BBA /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98CF5298294A3FC900557BBA /* submatrix.c in Sources */,\n\t\t\t\t98CF5299294A3FC900557BBA /* eidos_token.cpp in Sources */,\n\t\t\t\t98CF529A294A3FC900557BBA /* dtrsv.c in Sources */,\n\t\t\t\t98CF529B294A3FC900557BBA /* infnan.c in Sources */,\n\t\t\t\t98CEFD1A2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t98CF529C294A3FC900557BBA /* cholesky.c in Sources */,\n\t\t\t\t98CF529D294A3FC900557BBA /* xerbla.c in Sources */,\n\t\t\t\t98CF529E294A3FC900557BBA /* discrete.c in Sources */,\n\t\t\t\t98CF529F294A3FC900557BBA /* minmax.c in Sources */,\n\t\t\t\t98CF52A0294A3FC900557BBA /* inline.c in Sources */,\n\t\t\t\t98CF52A1294A3FC900557BBA /* eidos_interpreter.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98CF5398294A714200557BBA /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CEFD822AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98CF5399294A714200557BBA /* swap.c in Sources */,\n\t\t\t\t98CF539A294A714200557BBA /* minmax.c in Sources */,\n\t\t\t\t98CF539B294A714200557BBA /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98CF539C294A714200557BBA /* eidos_functions.cpp in Sources */,\n\t\t\t\t98CF539D294A714200557BBA /* math.c in Sources */,\n\t\t\t\t98CF539E294A714200557BBA /* expint.c in Sources */,\n\t\t\t\t98CF539F294A714200557BBA /* coerce.c in Sources */,\n\t\t\t\t98CF53A0294A714200557BBA /* stream.c in Sources */,\n\t\t\t\t98CF53A1294A714200557BBA /* eidos_globals.cpp in Sources */,\n\t\t\t\t98CF53A2294A714200557BBA /* eidos_script.cpp in Sources */,\n\t\t\t\t98CF53A3294A714200557BBA /* gzlib.c in Sources */,\n\t\t\t\t98EDB5062E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98CF53A4294A714200557BBA /* elementary.c in Sources */,\n\t\t\t\t98EDB4FC2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98CF53A5294A714200557BBA /* dtrmv.c in Sources */,\n\t\t\t\t98CF53A6294A714200557BBA /* poisson.c in Sources */,\n\t\t\t\t98CF53A7294A714200557BBA /* gamma_inc.c in Sources */,\n\t\t\t\t98CF53A8294A714200557BBA /* adler32.c in Sources */,\n\t\t\t\t98CEFD1C2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t98CF53A9294A714200557BBA /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98CF53AA294A714200557BBA /* multinomial.c in Sources */,\n\t\t\t\t98CF53AB294A714200557BBA /* blas.c in Sources */,\n\t\t\t\t98CF53AC294A714200557BBA /* weibull.c in Sources */,\n\t\t\t\t98CF53AD294A714200557BBA /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98CF53AE294A714200557BBA /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98CF53AF294A714200557BBA /* eidos_token.cpp in Sources */,\n\t\t\t\t98CF53B0294A714200557BBA /* gauss.c in Sources */,\n\t\t\t\t98CF53B1294A714200557BBA /* dgemv.c in Sources */,\n\t\t\t\t98CF53B2294A714200557BBA /* inline.c in Sources */,\n\t\t\t\t98CF53B3294A714200557BBA /* beta.c in Sources */,\n\t\t\t\t98CF53B4294A714200557BBA /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98CF53B5294A714200557BBA /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98CF53B6294A714200557BBA /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98CF53B7294A714200557BBA /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98CF53B8294A714200557BBA /* EidosCocoaExtra.mm in Sources */,\n\t\t\t\t98CF53B9294A714200557BBA /* eidos_rng.cpp in Sources */,\n\t\t\t\t98CF53BA294A714200557BBA /* binomial_tpe.c in Sources */,\n\t\t\t\t98CF53BB294A714200557BBA /* discrete.c in Sources */,\n\t\t\t\t98EDB4E72E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98CF53BC294A714200557BBA /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98CF53BD294A714200557BBA /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98CEFD792AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98CF53BE294A714200557BBA /* compress.c in Sources */,\n\t\t\t\t98CF53BF294A714200557BBA /* gausszig.c in Sources */,\n\t\t\t\t98CF53C0294A714200557BBA /* geometric.c in Sources */,\n\t\t\t\t98CF53C1294A714200557BBA /* error.c in Sources */,\n\t\t\t\t98CF53C2294A714200557BBA /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t98CF53C3294A714200557BBA /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98CF53C4294A714200557BBA /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98CF53C5294A714200557BBA /* xerbla.c in Sources */,\n\t\t\t\t98CF53C6294A714200557BBA /* taus.c in Sources */,\n\t\t\t\t98CF53C7294A714200557BBA /* trees.c in Sources */,\n\t\t\t\t98CF53C8294A714200557BBA /* init.c in Sources */,\n\t\t\t\t98CF53C9294A714200557BBA /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98CF53CA294A714200557BBA /* inline.c in Sources */,\n\t\t\t\t98CF53CB294A714200557BBA /* shuffle.c in Sources */,\n\t\t\t\t98CF53CC294A714200557BBA /* copy.c in Sources */,\n\t\t\t\t98CEFD542AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98CF53CD294A714200557BBA /* init.c in Sources */,\n\t\t\t\t98CF53CE294A714200557BBA /* oper.c in Sources */,\n\t\t\t\t98CF53CF294A714200557BBA /* main.m in Sources */,\n\t\t\t\t98CF53D0294A714200557BBA /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98CEFCF82AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98CF53D1294A714200557BBA /* EidosValueWrapper.mm in Sources */,\n\t\t\t\t98D7D6602AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98CEFD702AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98CF53D2294A714200557BBA /* zeta.c in Sources */,\n\t\t\t\t98CF53D3294A714200557BBA /* deflate.c in Sources */,\n\t\t\t\t98CF53D4294A714200557BBA /* rng.c in Sources */,\n\t\t\t\t98CF53D5294A714200557BBA /* cholesky.c in Sources */,\n\t\t\t\t98CF53D6294A714200557BBA /* lognormal.c in Sources */,\n\t\t\t\t98CF53D7294A714200557BBA /* EidosTextView.mm in Sources */,\n\t\t\t\t98CF53D8294A714200557BBA /* exp.c in Sources */,\n\t\t\t\t98CF53D9294A714200557BBA /* log.c in Sources */,\n\t\t\t\t98CF53DA294A714200557BBA /* pow_int.c in Sources */,\n\t\t\t\t98CF53DB294A714200557BBA /* submatrix.c in Sources */,\n\t\t\t\t98CEFD342AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98CF53DC294A714200557BBA /* zutil.c in Sources */,\n\t\t\t\t98CF53DD294A714200557BBA /* matrix.c in Sources */,\n\t\t\t\t98CF53DE294A714200557BBA /* lodepng.cpp in Sources */,\n\t\t\t\t98CF53DF294A714200557BBA /* trig.c in Sources */,\n\t\t\t\t98CEFD242AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98CF53E0294A714200557BBA /* vector.c in Sources */,\n\t\t\t\t98CEFD682AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98EDB5152E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t98CF53E1294A714200557BBA /* cauchy.c in Sources */,\n\t\t\t\t98CF53E2294A714200557BBA /* fdiv.c in Sources */,\n\t\t\t\t98CF53E3294A714200557BBA /* eidos_value.cpp in Sources */,\n\t\t\t\t98CF53E4294A714200557BBA /* gaussinv.c in Sources */,\n\t\t\t\t98CF53E5294A714200557BBA /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98CF53E6294A714200557BBA /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98CF53E7294A714200557BBA /* EidosHelpController.mm in Sources */,\n\t\t\t\t98CF53E8294A714200557BBA /* rowcol.c in Sources */,\n\t\t\t\t98CF53E9294A714200557BBA /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98CF53EA294A714200557BBA /* EidosVariableBrowserController.mm in Sources */,\n\t\t\t\t98EDB4F22E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t987A70132AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t98729ADC2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98CF53EB294A714200557BBA /* crc32.c in Sources */,\n\t\t\t\t98CEFD142AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98CEFCF02AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98CF53EC294A714200557BBA /* beta.c in Sources */,\n\t\t\t\t98CF53ED294A714200557BBA /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98C634482EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98CF53EE294A714200557BBA /* psi.c in Sources */,\n\t\t\t\t98CEFD8C2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t98CF53EF294A714200557BBA /* eidos_test.cpp in Sources */,\n\t\t\t\t98EDB4D32E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t98CF53F0294A714200557BBA /* infnan.c in Sources */,\n\t\t\t\t98CF53F1294A714200557BBA /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98CEFD4C2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t98CF53F2294A714200557BBA /* EidosAppDelegate.mm in Sources */,\n\t\t\t\t98CF53F3294A714200557BBA /* tdist.c in Sources */,\n\t\t\t\t98CF53F4294A714200557BBA /* gzwrite.c in Sources */,\n\t\t\t\t98CF53F5294A714200557BBA /* eidos_beep.cpp in Sources */,\n\t\t\t\t98CF53F6294A714200557BBA /* mt.c in Sources */,\n\t\t\t\t98CF53F7294A714200557BBA /* fdist.c in Sources */,\n\t\t\t\t98CF53F8294A714200557BBA /* gamma.c in Sources */,\n\t\t\t\t98CF53F9294A714200557BBA /* ddot.c in Sources */,\n\t\t\t\t98CF53FA294A714200557BBA /* EidosConsoleTextView.mm in Sources */,\n\t\t\t\t98CF53FB294A714200557BBA /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t98CF53FC294A714200557BBA /* erfc.c in Sources */,\n\t\t\t\t98CF53FD294A714200557BBA /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98D7D6692AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t98CF53FE294A714200557BBA /* gauss.c in Sources */,\n\t\t\t\t98CF53FF294A714200557BBA /* exponential.c in Sources */,\n\t\t\t\t98CF5400294A714200557BBA /* dtrsv.c in Sources */,\n\t\t\t\t98CF5401294A714200557BBA /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98CF5402294A714200557BBA /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98CF5403294A714200557BBA /* nbinomial.c in Sources */,\n\t\t\t\t98CF5404294A714200557BBA /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98CF5405294A714200557BBA /* pow_int.c in Sources */,\n\t\t\t\t98CF5406294A714200557BBA /* EidosConsoleWindowController.mm in Sources */,\n\t\t\t\t98CF5407294A714200557BBA /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98CF5408294A714200557BBA /* init.c in Sources */,\n\t\t\t\t98CF5409294A714200557BBA /* mvgauss.c in Sources */,\n\t\t\t\t98CF540A294A714200557BBA /* message.c in Sources */,\n\t\t\t\t98CF540B294A714200557BBA /* EidosPrettyprinter.mm in Sources */,\n\t\t\t\t98CF540C294A714200557BBA /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t98CF540D294A714200557BBA /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98CF540E294A714200557BBA /* gamma.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D4C1AF1A6F537B00FFB083 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t982B50C72704048E006E91BC /* nbinomial.c in Sources */,\n\t\t\t\t98321F951B406B67007337A3 /* eidos_globals.cpp in Sources */,\n\t\t\t\t989790DB1AF3D0E100C6B14C /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t981DC36D28E26F8B000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98C8215A1C7A983700548839 /* pow_int.c in Sources */,\n\t\t\t\t98AB597C1B2531F10077CB4A /* slim_eidos_block.cpp in Sources */,\n\t\t\t\t981DC37128E26F8B000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98C821AE1C7A9B1600548839 /* geometric.c in Sources */,\n\t\t\t\t981BAC6B1ACC6E8B0005BE94 /* eidos_script.cpp in Sources */,\n\t\t\t\t98C821481C7A983700548839 /* beta.c in Sources */,\n\t\t\t\t984824F5210B9F31002402A5 /* ddot.c in Sources */,\n\t\t\t\t98D4C1BB1A6F537B00FFB083 /* main.m in Sources */,\n\t\t\t\t987AD8831B2CBF9A0035D6C8 /* EidosValueWrapper.mm in Sources */,\n\t\t\t\t98C821521C7A983700548839 /* inline.c in Sources */,\n\t\t\t\t98CEFD112AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98C821451C7A983700548839 /* error.c in Sources */,\n\t\t\t\t98DE4C141B6F9657004FDF5F /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98332ACF1FDBA87D00274FF0 /* oper.c in Sources */,\n\t\t\t\t9854D2682278B9F8001D43BC /* trees.c in Sources */,\n\t\t\t\t98D4C1D61A6F541F00FFB083 /* eidos_rng.cpp in Sources */,\n\t\t\t\t98CEFCF52AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t9893C7DF1CDA2FC10029AC94 /* eidos_beep.cpp in Sources */,\n\t\t\t\t986926D91AA140550000E138 /* GraphView.mm in Sources */,\n\t\t\t\t98C821471C7A983700548839 /* stream.c in Sources */,\n\t\t\t\t98CEFD652AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98EFE6301ADB611100CBEC78 /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t98332B0B1FDBD03100274FF0 /* init.c in Sources */,\n\t\t\t\t98DB3D701E6122AE00E2C200 /* interaction_type.cpp in Sources */,\n\t\t\t\t98D4C1E21A6F544800FFB083 /* subpopulation.cpp in Sources */,\n\t\t\t\t9836867527CD40CF00683639 /* community.cpp in Sources */,\n\t\t\t\t985F3F0724BA310100E712E0 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98D218C51B2E213200156FC3 /* EidosTextView.mm in Sources */,\n\t\t\t\t98332AF81FDBC42600274FF0 /* swap.c in Sources */,\n\t\t\t\t985724AA1AD4551C0047C223 /* eidos_test.cpp in Sources */,\n\t\t\t\t98332ADD1FDBC0D700274FF0 /* dgemv.c in Sources */,\n\t\t\t\t98C821491C7A983700548839 /* binomial_tpe.c in Sources */,\n\t\t\t\t9850D8E9206309A0006BFD2E /* tables.c in Sources */,\n\t\t\t\t98AC617B24BA34ED0001914C /* species_eidos.cpp in Sources */,\n\t\t\t\t98729AD92A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98DDAED7221765480038C133 /* slim_functions.cpp in Sources */,\n\t\t\t\t98076618244934A800F6CBB4 /* deflate.c in Sources */,\n\t\t\t\t984252C3216FA9930019696A /* FindRecipeController.mm in Sources */,\n\t\t\t\t981DC35928E26F8B000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98606AEF1DED0DCD00821CFF /* mutation_run.cpp in Sources */,\n\t\t\t\t987A70102AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t985F3EF824BA2DD300E712E0 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98332B191FDBD16500274FF0 /* copy.c in Sources */,\n\t\t\t\t9876E5F61ED5573700FF9762 /* tdist.c in Sources */,\n\t\t\t\t98C821461C7A983700548839 /* message.c in Sources */,\n\t\t\t\t98C8214F1C7A983700548839 /* multinomial.c in Sources */,\n\t\t\t\t98C821541C7A983700548839 /* rng.c in Sources */,\n\t\t\t\t98C821551C7A983700548839 /* taus.c in Sources */,\n\t\t\t\t98CEFD6D2AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t987A2A0824033856009A636F /* gaussinv.c in Sources */,\n\t\t\t\t985F3EEB24BA27EC00E712E0 /* slim_test_genetics.cpp in Sources */,\n\t\t\t\t98332AB51FDBA1E400274FF0 /* blas.c in Sources */,\n\t\t\t\t98C821531C7A983700548839 /* mt.c in Sources */,\n\t\t\t\t98D4C1DB1A6F542F00FFB083 /* genomic_element.cpp in Sources */,\n\t\t\t\t98C821A41C7A99F000548839 /* pow_int.c in Sources */,\n\t\t\t\t98D4C1DF1A6F543C00FFB083 /* substitution.cpp in Sources */,\n\t\t\t\t9854D2602278B9F8001D43BC /* core.c in Sources */,\n\t\t\t\t9876E6131ED55C7300FF9762 /* beta.c in Sources */,\n\t\t\t\t98EDB5122E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t98C8214A1C7A983700548839 /* exponential.c in Sources */,\n\t\t\t\t98C821501C7A983700548839 /* poisson.c in Sources */,\n\t\t\t\t981DC35D28E26F8B000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t9876E5FD1ED559A600FF9762 /* gauss.c in Sources */,\n\t\t\t\t982556651BA450980054CB3F /* EidosHelpController.mm in Sources */,\n\t\t\t\t9836868227CD72E900683639 /* community_eidos.cpp in Sources */,\n\t\t\t\t98EDB4F92E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98235683252FDCF50096A745 /* lodepng.cpp in Sources */,\n\t\t\t\t9807C0F924BA21E3008CC658 /* slim_test_other.cpp in Sources */,\n\t\t\t\t985724A61AD435310047C223 /* eidos_value.cpp in Sources */,\n\t\t\t\t98C8215F1C7A983700548839 /* fdiv.c in Sources */,\n\t\t\t\t986926E21AA3DD6C0000E138 /* GraphView_MutationLossTimeHistogram.mm in Sources */,\n\t\t\t\t98C8215C1C7A983700548839 /* trig.c in Sources */,\n\t\t\t\t98CEFD212AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98C821571C7A983700548839 /* exp.c in Sources */,\n\t\t\t\t98C92AEE1D0B07A6001C82BC /* individual.cpp in Sources */,\n\t\t\t\t981DC36528E26F8B000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98C821511C7A983700548839 /* weibull.c in Sources */,\n\t\t\t\t9893C7E41CDFCF0D0029AC94 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98C8214E1C7A983700548839 /* lognormal.c in Sources */,\n\t\t\t\t9876E6031ED55A7800FF9762 /* gamma_inc.c in Sources */,\n\t\t\t\t98076623244934A800F6CBB4 /* trees.c in Sources */,\n\t\t\t\t98D4C21C1A718EFD00FFB083 /* CocoaExtra.mm in Sources */,\n\t\t\t\t98332B041FDBCFF900274FF0 /* init.c in Sources */,\n\t\t\t\t9807C0F624BA21B7008CC658 /* slim_test_core.cpp in Sources */,\n\t\t\t\t9825565B1BA32EE80054CB3F /* EidosCocoaExtra.mm in Sources */,\n\t\t\t\t98CEFCED2AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98EDB4EF2E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t98C821581C7A983700548839 /* gamma.c in Sources */,\n\t\t\t\t98332ABA1FDBA32500274FF0 /* dtrmv.c in Sources */,\n\t\t\t\t9807662A24493A8F00F6CBB4 /* crc32.c in Sources */,\n\t\t\t\t985F3F0C24BA31D900E712E0 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98DEB47F2AA632AA00ABE60F /* spatial_map.cpp in Sources */,\n\t\t\t\t985F3EF324BA2A8C00E712E0 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t9887946B1EA8804900AE0C8D /* SLiMPDFDocument.mm in Sources */,\n\t\t\t\t985724A21AD34B740047C223 /* eidos_functions.cpp in Sources */,\n\t\t\t\t98CEFD892AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t9809DFA12550F32500C4E82D /* log_file.cpp in Sources */,\n\t\t\t\t98CEFD512AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t9807661D244934A800F6CBB4 /* zutil.c in Sources */,\n\t\t\t\t98C8214C1C7A983700548839 /* gauss.c in Sources */,\n\t\t\t\t98D4C1E31A6F544B00FFB083 /* population.cpp in Sources */,\n\t\t\t\t985F3EFD24BA2F1500E712E0 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t989A5BEA2525304100E7192D /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98C6344C2EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98C821561C7A983700548839 /* elementary.c in Sources */,\n\t\t\t\t986070EB2AACECD600FD6143 /* spatial_kernel.cpp in Sources */,\n\t\t\t\t986926E81AA40AFF0000E138 /* GraphView_FitnessOverTime.mm in Sources */,\n\t\t\t\t98D4C2041A701D5A00FFB083 /* SLiMWindowController.mm in Sources */,\n\t\t\t\t98D4C2071A704EA700FFB083 /* PopulationView.mm in Sources */,\n\t\t\t\t98332B121FDBD0F500274FF0 /* init.c in Sources */,\n\t\t\t\t986926EB1AA6B7480000E138 /* GraphView_PopulationVisualization.mm in Sources */,\n\t\t\t\t98D524691F2EB4DD005AD9A6 /* EidosPrettyprinter.mm in Sources */,\n\t\t\t\t98C8215E1C7A983700548839 /* coerce.c in Sources */,\n\t\t\t\t98D4C1DC1A6F543200FFB083 /* genomic_element_type.cpp in Sources */,\n\t\t\t\t98D4C1B91A6F537B00FFB083 /* AppDelegate.mm in Sources */,\n\t\t\t\t98C821B31C7A9B9F00548839 /* shuffle.c in Sources */,\n\t\t\t\t98C8214B1C7A983700548839 /* gamma.c in Sources */,\n\t\t\t\t98800DC51B82B6C60046F5F9 /* slim_test.cpp in Sources */,\n\t\t\t\t985D1D8C2808B84F00461CFA /* sparse_vector.cpp in Sources */,\n\t\t\t\t9876E60E1ED55C0B00FF9762 /* expint.c in Sources */,\n\t\t\t\t98D4C1D91A6F542900FFB083 /* mutation_type.cpp in Sources */,\n\t\t\t\t9854D2642278B9F8001D43BC /* convert.c in Sources */,\n\t\t\t\t98CEFD492AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t9807661F244934A800F6CBB4 /* gzlib.c in Sources */,\n\t\t\t\t9876E6091ED55B4F00FF9762 /* erfc.c in Sources */,\n\t\t\t\t98D4C1DE1A6F543900FFB083 /* polymorphism.cpp in Sources */,\n\t\t\t\t98EDB4E42E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98ACDC9E253522B80038703F /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98CEFD312AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98D4C1D41A6F541700FFB083 /* species.cpp in Sources */,\n\t\t\t\t98C8215D1C7A983700548839 /* zeta.c in Sources */,\n\t\t\t\tD0A758F920A4CCCF00132D2F /* text_input.c in Sources */,\n\t\t\t\t98C821591C7A983700548839 /* log.c in Sources */,\n\t\t\t\t988880ED20744F0100E10172 /* cauchy.c in Sources */,\n\t\t\t\t986D73E91B07E89E007FBB70 /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t980566E325A7C5B9008D3C7F /* fdist.c in Sources */,\n\t\t\t\t98D4C20A1A7086FF00FFB083 /* ChromosomeView.mm in Sources */,\n\t\t\t\t987AD8821B2CBF960035D6C8 /* EidosConsoleTextView.mm in Sources */,\n\t\t\t\t9823568A252FE61A0096A745 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98332AC81FDBA74900274FF0 /* vector.c in Sources */,\n\t\t\t\t98CEFD762AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98C821441C7A983700548839 /* math.c in Sources */,\n\t\t\t\t9887946F1EA8808000AE0C8D /* SLiMPDFWindowController.mm in Sources */,\n\t\t\t\t98332AFD1FDBC4BB00274FF0 /* matrix.c in Sources */,\n\t\t\t\t980DD51D1AB0B01F00D5B7B8 /* GraphView_MutationFrequencyTrajectory.mm in Sources */,\n\t\t\t\t98076615244934A800F6CBB4 /* compress.c in Sources */,\n\t\t\t\t985F3EEE24BA2A5D00E712E0 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t989524A91E40AE74007E62FA /* SLiMDocument.mm in Sources */,\n\t\t\t\t987AD88A1B2CDBB80035D6C8 /* EidosConsoleWindowController.mm in Sources */,\n\t\t\t\t98CF26521E4353FE00E392D8 /* SLiMDocumentController.mm in Sources */,\n\t\t\t\t98332A9F1FDB990400274FF0 /* mvgauss.c in Sources */,\n\t\t\t\t986926E51AA3FF000000E138 /* GraphView_MutationFixationTimeHistogram.mm in Sources */,\n\t\t\t\t981DC35128E26F8B000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98332AED1FDBC29400274FF0 /* rowcol.c in Sources */,\n\t\t\t\t98C8214D1C7A983700548839 /* gausszig.c in Sources */,\n\t\t\t\t9893C7EA1CDFE9870029AC94 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98D7D6662AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t987D19A6209A53850030D28D /* kastore.c in Sources */,\n\t\t\t\t98076621244934A800F6CBB4 /* gzwrite.c in Sources */,\n\t\t\t\t98D4C1DD1A6F543600FFB083 /* chromosome.cpp in Sources */,\n\t\t\t\t981DC36128E26F8B000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98C8215B1C7A983700548839 /* psi.c in Sources */,\n\t\t\t\t981DC36928E26F8B000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98E684402B694F09000B3B65 /* plot.mm in Sources */,\n\t\t\t\t986926DF1AA14CF10000E138 /* GraphView_MutationFrequencySpectra.mm in Sources */,\n\t\t\t\t9854D2622278B9F8001D43BC /* genotypes.c in Sources */,\n\t\t\t\t988794731EA8C42200AE0C8D /* SLiMPDFView.mm in Sources */,\n\t\t\t\t9890D1EE27136BB7001EAE98 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98CEFD7F2AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98D4C1E11A6F544500FFB083 /* haplosome.cpp in Sources */,\n\t\t\t\t9854D2662278B9F8001D43BC /* stats.c in Sources */,\n\t\t\t\t98076627244934A800F6CBB4 /* adler32.c in Sources */,\n\t\t\t\t987AD8861B2CC0C10035D6C8 /* EidosVariableBrowserController.mm in Sources */,\n\t\t\t\t98EDB4D02E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t981DC35528E26F8B000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98EBCD1421F3CFC600B385CF /* slim_gui.mm in Sources */,\n\t\t\t\t98D4C1D81A6F542600FFB083 /* mutation.cpp in Sources */,\n\t\t\t\t98D4C1D31A6F541200FFB083 /* slim_globals.cpp in Sources */,\n\t\t\t\t98D7D65D2AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t985F3F0224BA307200E712E0 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t98EDB5032E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98A513551B66B6CA005A753D /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98332AF11FDBC36300274FF0 /* submatrix.c in Sources */,\n\t\t\t\t98A513501B66B69E005A753D /* eidos_token.cpp in Sources */,\n\t\t\t\t984824F2210B9F2C002402A5 /* dtrsv.c in Sources */,\n\t\t\t\t98C821601C7A983700548839 /* infnan.c in Sources */,\n\t\t\t\t98CEFD192AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t98332AD81FDBBE3500274FF0 /* cholesky.c in Sources */,\n\t\t\t\t98332AC31FDBA54600274FF0 /* xerbla.c in Sources */,\n\t\t\t\t98C821AA1C7A9B1600548839 /* discrete.c in Sources */,\n\t\t\t\t98C8219F1C7A99B200548839 /* minmax.c in Sources */,\n\t\t\t\t98C821431C7A983700548839 /* inline.c in Sources */,\n\t\t\t\t9857249D1AD08A810047C223 /* eidos_interpreter.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D7EB8428CE557C00DEAAC4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98D7EB8528CE557C00DEAAC4 /* coerce.c in Sources */,\n\t\t\t\t98D7EB8628CE557C00DEAAC4 /* compress.c in Sources */,\n\t\t\t\t987A70152AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t98D7EB8728CE557C00DEAAC4 /* eidos_value.cpp in Sources */,\n\t\t\t\t98CEFD722AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98D7EB8828CE557C00DEAAC4 /* math.c in Sources */,\n\t\t\t\t98D7EB8928CE557C00DEAAC4 /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98D7EB8A28CE557C00DEAAC4 /* eidos_token.cpp in Sources */,\n\t\t\t\t98D7EB8B28CE557C00DEAAC4 /* cholesky.c in Sources */,\n\t\t\t\t98D7EB8C28CE557C00DEAAC4 /* mvgauss.c in Sources */,\n\t\t\t\t98D7EB8D28CE557C00DEAAC4 /* xerbla.c in Sources */,\n\t\t\t\t98D7EB8E28CE557C00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7EB8F28CE557C00DEAAC4 /* gauss.c in Sources */,\n\t\t\t\t98D7EB9028CE557C00DEAAC4 /* shuffle.c in Sources */,\n\t\t\t\t98D7EB9128CE557C00DEAAC4 /* exponential.c in Sources */,\n\t\t\t\t98D7EB9228CE557C00DEAAC4 /* erfc.c in Sources */,\n\t\t\t\t98D7EB9328CE557C00DEAAC4 /* expint.c in Sources */,\n\t\t\t\t98D7EB9428CE557C00DEAAC4 /* trig.c in Sources */,\n\t\t\t\t98D7EB9528CE557C00DEAAC4 /* eidos_test.cpp in Sources */,\n\t\t\t\t98CEFCFA2AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98D7EB9628CE557C00DEAAC4 /* oper.c in Sources */,\n\t\t\t\t98D7D6622AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98D7EB9728CE557C00DEAAC4 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98D7EB9828CE557C00DEAAC4 /* swap.c in Sources */,\n\t\t\t\t98C6344B2EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98D7EB9928CE557C00DEAAC4 /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98D7EB9A28CE557C00DEAAC4 /* deflate.c in Sources */,\n\t\t\t\t98D7EB9B28CE557C00DEAAC4 /* error.c in Sources */,\n\t\t\t\t98D7EB9C28CE557C00DEAAC4 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t98D7EB9D28CE557C00DEAAC4 /* eidos_rng.cpp in Sources */,\n\t\t\t\t98D7EB9E28CE557C00DEAAC4 /* inline.c in Sources */,\n\t\t\t\t98D7EB9F28CE557C00DEAAC4 /* geometric.c in Sources */,\n\t\t\t\t98D7EBA028CE557C00DEAAC4 /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98CEFD7B2AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98D7EBA128CE557C00DEAAC4 /* eidos_beep.cpp in Sources */,\n\t\t\t\t98EDB5182E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t98D7EBA228CE557C00DEAAC4 /* adler32.c in Sources */,\n\t\t\t\t98CEFD4E2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t98CEFD562AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98D7EBA328CE557C00DEAAC4 /* gauss.c in Sources */,\n\t\t\t\t98EDB4FF2E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t98D7EBA428CE557C00DEAAC4 /* zeta.c in Sources */,\n\t\t\t\t98D7EBA528CE557C00DEAAC4 /* multinomial.c in Sources */,\n\t\t\t\t98CEFD162AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98D7EBA628CE557C00DEAAC4 /* binomial_tpe.c in Sources */,\n\t\t\t\t98D7EBA728CE557C00DEAAC4 /* cauchy.c in Sources */,\n\t\t\t\t98D7EBA828CE557C00DEAAC4 /* infnan.c in Sources */,\n\t\t\t\t98D7D66B2AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t98D7EBA928CE557C00DEAAC4 /* eidos_functions.cpp in Sources */,\n\t\t\t\t98D7EBAA28CE557C00DEAAC4 /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98D7EBAB28CE557C00DEAAC4 /* mt.c in Sources */,\n\t\t\t\t981DC37428E27300000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t98D7EBAC28CE557C00DEAAC4 /* gausszig.c in Sources */,\n\t\t\t\t98D7EBAD28CE557C00DEAAC4 /* message.c in Sources */,\n\t\t\t\t98D7EBAE28CE557C00DEAAC4 /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98D7EBAF28CE557C00DEAAC4 /* inline.c in Sources */,\n\t\t\t\t98D7EBB028CE557C00DEAAC4 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98EDB4F52E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t981DC37C28E27300000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98D7EBB128CE557C00DEAAC4 /* discrete.c in Sources */,\n\t\t\t\t98D7EBB228CE557C00DEAAC4 /* gzwrite.c in Sources */,\n\t\t\t\t98D7EBB328CE557C00DEAAC4 /* poisson.c in Sources */,\n\t\t\t\t98D7EBB428CE557C00DEAAC4 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98D7EBB528CE557C00DEAAC4 /* exp.c in Sources */,\n\t\t\t\t98729ADE2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98D7EBB628CE557C00DEAAC4 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98EDB5092E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98EDB4EA2E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98D7EBB728CE557C00DEAAC4 /* eidos_script.cpp in Sources */,\n\t\t\t\t98CEFD262AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98CEFD362AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t981DC37B28E27300000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98D7EBB828CE557C00DEAAC4 /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t98D7EBB928CE557C00DEAAC4 /* submatrix.c in Sources */,\n\t\t\t\t981DC37728E27300000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98D7EBBA28CE557C00DEAAC4 /* minmax.c in Sources */,\n\t\t\t\t981DC37828E27300000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98D7EBBB28CE557C00DEAAC4 /* pow_int.c in Sources */,\n\t\t\t\t98D7EBBC28CE557C00DEAAC4 /* gaussinv.c in Sources */,\n\t\t\t\t98D7EBBD28CE557C00DEAAC4 /* log.c in Sources */,\n\t\t\t\t98CEFCF22AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t981DC37928E27300000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98D7EBBE28CE557C00DEAAC4 /* gamma_inc.c in Sources */,\n\t\t\t\t98CEFD842AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98D7EBBF28CE557C00DEAAC4 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98D7EBC028CE557C00DEAAC4 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t981DC37628E27300000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98D7EBC128CE557C00DEAAC4 /* taus.c in Sources */,\n\t\t\t\t98D7EBC228CE557C00DEAAC4 /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98D7EBC328CE557C00DEAAC4 /* nbinomial.c in Sources */,\n\t\t\t\t98D7EBC428CE557C00DEAAC4 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98D7EBC528CE557C00DEAAC4 /* lognormal.c in Sources */,\n\t\t\t\t98CEFD8E2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t98D7EBC628CE557C00DEAAC4 /* vector.c in Sources */,\n\t\t\t\t98D7EBC728CE557C00DEAAC4 /* fdiv.c in Sources */,\n\t\t\t\t981DC37A28E27300000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98D7EBC828CE557C00DEAAC4 /* matrix.c in Sources */,\n\t\t\t\t98D7EBC928CE557C00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7EBCA28CE557C00DEAAC4 /* weibull.c in Sources */,\n\t\t\t\t98D7EBCB28CE557C00DEAAC4 /* blas.c in Sources */,\n\t\t\t\t98D7EBCC28CE557C00DEAAC4 /* lodepng.cpp in Sources */,\n\t\t\t\t98D7EBCD28CE557C00DEAAC4 /* ddot.c in Sources */,\n\t\t\t\t98D7EBCE28CE557C00DEAAC4 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98D7EBCF28CE557C00DEAAC4 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98D7EBD028CE557C00DEAAC4 /* gzlib.c in Sources */,\n\t\t\t\t98D7EBD128CE557C00DEAAC4 /* dtrmv.c in Sources */,\n\t\t\t\t98CEFD6A2AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98D7EBD228CE557C00DEAAC4 /* crc32.c in Sources */,\n\t\t\t\t98D7EBD328CE557C00DEAAC4 /* fdist.c in Sources */,\n\t\t\t\t98EDB4D62E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t981DC37528E27300000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98D7EBD428CE557C00DEAAC4 /* trees.c in Sources */,\n\t\t\t\t98D7EBD528CE557C00DEAAC4 /* gamma.c in Sources */,\n\t\t\t\t98D7EBD628CE557C00DEAAC4 /* beta.c in Sources */,\n\t\t\t\t98D7EBD728CE557C00DEAAC4 /* copy.c in Sources */,\n\t\t\t\t98D7EBD828CE557C00DEAAC4 /* rowcol.c in Sources */,\n\t\t\t\t98D7EBD928CE557C00DEAAC4 /* zutil.c in Sources */,\n\t\t\t\t98D7EBDA28CE557C00DEAAC4 /* psi.c in Sources */,\n\t\t\t\t98D7EBDB28CE557C00DEAAC4 /* main.cpp in Sources */,\n\t\t\t\t98D7EBDC28CE557C00DEAAC4 /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t98D7EBDD28CE557C00DEAAC4 /* beta.c in Sources */,\n\t\t\t\t98D7EBDE28CE557C00DEAAC4 /* pow_int.c in Sources */,\n\t\t\t\t98D7EBDF28CE557C00DEAAC4 /* elementary.c in Sources */,\n\t\t\t\t98D7EBE028CE557C00DEAAC4 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98D7EBE128CE557C00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7EBE228CE557C00DEAAC4 /* stream.c in Sources */,\n\t\t\t\t98D7EBE328CE557C00DEAAC4 /* rng.c in Sources */,\n\t\t\t\t98D7EBE428CE557C00DEAAC4 /* dtrsv.c in Sources */,\n\t\t\t\t98CEFD1E2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t98D7EBE528CE557C00DEAAC4 /* tdist.c in Sources */,\n\t\t\t\t98D7EBE628CE557C00DEAAC4 /* dgemv.c in Sources */,\n\t\t\t\t98D7EBE728CE557C00DEAAC4 /* gamma.c in Sources */,\n\t\t\t\t98D7EBE828CE557C00DEAAC4 /* eidos_globals.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t98D7ECA028CE58FC00DEAAC4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t98CEFD572AAFABAA00D2C9B4 /* linear.c in Sources */,\n\t\t\t\t98D7ECA128CE58FC00DEAAC4 /* eidos_symbol_table.cpp in Sources */,\n\t\t\t\t98D7ECA228CE58FC00DEAAC4 /* eidos_type_interpreter.cpp in Sources */,\n\t\t\t\t98D7ECA328CE58FC00DEAAC4 /* eidos_call_signature.cpp in Sources */,\n\t\t\t\t98C634442EF9F632003F12A3 /* dirichlet.c in Sources */,\n\t\t\t\t98CEFD172AAFABAA00D2C9B4 /* interp.c in Sources */,\n\t\t\t\t98D7ECA428CE58FC00DEAAC4 /* dgemv.c in Sources */,\n\t\t\t\t98D7ECA528CE58FC00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7ECA628CE58FC00DEAAC4 /* gamma.c in Sources */,\n\t\t\t\t98729ADF2A87DFBE00E81662 /* eidos_sorting.cpp in Sources */,\n\t\t\t\t98D7ECA728CE58FC00DEAAC4 /* gauss.c in Sources */,\n\t\t\t\t98D7ECA828CE58FC00DEAAC4 /* eidos_test_operators_arithmetic.cpp in Sources */,\n\t\t\t\t981DC38528E27301000ABE91 /* eidos_functions_files.cpp in Sources */,\n\t\t\t\t98D7ECA928CE58FC00DEAAC4 /* eidos_test_functions_statistics.cpp in Sources */,\n\t\t\t\t98D7ECAA28CE58FC00DEAAC4 /* log.c in Sources */,\n\t\t\t\t98CEFD372AAFABAA00D2C9B4 /* spline.c in Sources */,\n\t\t\t\t98EDB4EB2E65366E00CC8798 /* daxpy.c in Sources */,\n\t\t\t\t98D7ECAB28CE58FC00DEAAC4 /* slim_test.cpp in Sources */,\n\t\t\t\t98D7ECAC28CE58FC00DEAAC4 /* expint.c in Sources */,\n\t\t\t\t981DC38028E27301000ABE91 /* eidos_functions_math.cpp in Sources */,\n\t\t\t\t98D7ECAD28CE58FC00DEAAC4 /* elementary.c in Sources */,\n\t\t\t\t98D7ECAE28CE58FC00DEAAC4 /* mvgauss.c in Sources */,\n\t\t\t\t98D7ECAF28CE58FC00DEAAC4 /* copy.c in Sources */,\n\t\t\t\t98D7ECB028CE58FC00DEAAC4 /* eidos_class_Image.cpp in Sources */,\n\t\t\t\t98D7ECB128CE58FC00DEAAC4 /* shuffle.c in Sources */,\n\t\t\t\t98D7ECB228CE58FC00DEAAC4 /* stats.c in Sources */,\n\t\t\t\t98D7ECB328CE58FC00DEAAC4 /* mutation_type.cpp in Sources */,\n\t\t\t\t98D7ECB428CE58FC00DEAAC4 /* mutation.cpp in Sources */,\n\t\t\t\t98DEB4812AA632AA00ABE60F /* spatial_map.cpp in Sources */,\n\t\t\t\t98D7ECB528CE58FC00DEAAC4 /* coerce.c in Sources */,\n\t\t\t\t98D7ECB628CE58FC00DEAAC4 /* dtrmv.c in Sources */,\n\t\t\t\t98D7ECB728CE58FC00DEAAC4 /* gamma_inc.c in Sources */,\n\t\t\t\t98D7ECB828CE58FC00DEAAC4 /* slim_test_other.cpp in Sources */,\n\t\t\t\t981DC38428E27301000ABE91 /* eidos_functions_distributions.cpp in Sources */,\n\t\t\t\t98D7ECB928CE58FC00DEAAC4 /* vector.c in Sources */,\n\t\t\t\t98D7ECBA28CE58FC00DEAAC4 /* eidos_script.cpp in Sources */,\n\t\t\t\t98D7ECBB28CE58FC00DEAAC4 /* gaussinv.c in Sources */,\n\t\t\t\t98D7ECBC28CE58FC00DEAAC4 /* erfc.c in Sources */,\n\t\t\t\t98D7ECBD28CE58FC00DEAAC4 /* gausszig.c in Sources */,\n\t\t\t\t98D7ECBE28CE58FC00DEAAC4 /* community_eidos.cpp in Sources */,\n\t\t\t\t98EDB4D72E652F4A00CC8798 /* lu.c in Sources */,\n\t\t\t\t98D7ECBF28CE58FC00DEAAC4 /* ddot.c in Sources */,\n\t\t\t\t98D7ECC028CE58FC00DEAAC4 /* species.cpp in Sources */,\n\t\t\t\t98D7ECC128CE58FC00DEAAC4 /* eidos_beep.cpp in Sources */,\n\t\t\t\t98D7ECC228CE58FC00DEAAC4 /* fdist.c in Sources */,\n\t\t\t\t98D7ECC328CE58FC00DEAAC4 /* matrix.c in Sources */,\n\t\t\t\t98D7ECC428CE58FC00DEAAC4 /* submatrix.c in Sources */,\n\t\t\t\t981DC38228E27301000ABE91 /* eidos_functions_values.cpp in Sources */,\n\t\t\t\t98D7ECC528CE58FC00DEAAC4 /* psi.c in Sources */,\n\t\t\t\t98D7ECC628CE58FC00DEAAC4 /* binomial_tpe.c in Sources */,\n\t\t\t\t98D7ECC728CE58FC00DEAAC4 /* eidos_test_functions_math.cpp in Sources */,\n\t\t\t\t98CEFD272AAFABAA00D2C9B4 /* akima.c in Sources */,\n\t\t\t\t98D7ECC828CE58FC00DEAAC4 /* haplosome.cpp in Sources */,\n\t\t\t\t98CEFD8F2AAFB4F000D2C9B4 /* view.c in Sources */,\n\t\t\t\t98D7ECC928CE58FC00DEAAC4 /* zutil.c in Sources */,\n\t\t\t\t98CEFD4F2AAFABAA00D2C9B4 /* interp2d.c in Sources */,\n\t\t\t\t98D7ECCA28CE58FC00DEAAC4 /* trees.c in Sources */,\n\t\t\t\t98D7ECCB28CE58FC00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7ECCC28CE58FC00DEAAC4 /* stream.c in Sources */,\n\t\t\t\t98D7ECCD28CE58FC00DEAAC4 /* slim_test_core.cpp in Sources */,\n\t\t\t\t98D7ECCE28CE58FC00DEAAC4 /* eidos_ast_node.cpp in Sources */,\n\t\t\t\t98D7ECCF28CE58FC00DEAAC4 /* chromosome.cpp in Sources */,\n\t\t\t\t98D7ECD028CE58FC00DEAAC4 /* eidos_test_functions_other.cpp in Sources */,\n\t\t\t\t98D7ECD128CE58FC00DEAAC4 /* error.c in Sources */,\n\t\t\t\t98D7ECD228CE58FC00DEAAC4 /* tables.c in Sources */,\n\t\t\t\t98D7ECD328CE58FC00DEAAC4 /* slim_eidos_block.cpp in Sources */,\n\t\t\t\t98D7ECD428CE58FC00DEAAC4 /* convert.c in Sources */,\n\t\t\t\t98D7ECD528CE58FC00DEAAC4 /* eidos_test_operators_other.cpp in Sources */,\n\t\t\t\t98D7ECD628CE58FC00DEAAC4 /* eidos_test_functions_vector.cpp in Sources */,\n\t\t\t\t98EDB50A2E65399600CC8798 /* permute.c in Sources */,\n\t\t\t\t98D7ECD728CE58FC00DEAAC4 /* deflate.c in Sources */,\n\t\t\t\t98EDB5002E6538F200CC8798 /* permutation.c in Sources */,\n\t\t\t\t981DC38128E27301000ABE91 /* eidos_functions_matrices.cpp in Sources */,\n\t\t\t\t98D7ECD828CE58FC00DEAAC4 /* gamma.c in Sources */,\n\t\t\t\t98D7ECD928CE58FC00DEAAC4 /* nbinomial.c in Sources */,\n\t\t\t\t98D7ECDA28CE58FC00DEAAC4 /* poisson.c in Sources */,\n\t\t\t\t98D7ECDB28CE58FC00DEAAC4 /* sparse_vector.cpp in Sources */,\n\t\t\t\t98D7ECDC28CE58FC00DEAAC4 /* population.cpp in Sources */,\n\t\t\t\t98D7ECDD28CE58FC00DEAAC4 /* beta.c in Sources */,\n\t\t\t\t981DC37E28E27301000ABE91 /* eidos_functions_stats.cpp in Sources */,\n\t\t\t\t98D7ECDE28CE58FC00DEAAC4 /* rowcol.c in Sources */,\n\t\t\t\t98D7ECDF28CE58FC00DEAAC4 /* taus.c in Sources */,\n\t\t\t\t98CEFD1F2AAFABAA00D2C9B4 /* bicubic.c in Sources */,\n\t\t\t\t981DC37D28E27301000ABE91 /* eidos_functions_other.cpp in Sources */,\n\t\t\t\t981DC37F28E27301000ABE91 /* eidos_functions_strings.cpp in Sources */,\n\t\t\t\t98D7ECE028CE58FC00DEAAC4 /* eidos_rng.cpp in Sources */,\n\t\t\t\t98D7ECE128CE58FC00DEAAC4 /* geometric.c in Sources */,\n\t\t\t\t98D7ECE228CE58FC00DEAAC4 /* eidos_token.cpp in Sources */,\n\t\t\t\t98D7ECE328CE58FC00DEAAC4 /* core.c in Sources */,\n\t\t\t\t98D7D66C2AB24CBC002AFE34 /* chisq.c in Sources */,\n\t\t\t\t98D7ECE428CE58FC00DEAAC4 /* minmax.c in Sources */,\n\t\t\t\t98CEFD7C2AAFB12F00D2C9B4 /* cspline.c in Sources */,\n\t\t\t\t98EDB5192E65410C00CC8798 /* copy.c in Sources */,\n\t\t\t\t986070ED2AACECD600FD6143 /* spatial_kernel.cpp in Sources */,\n\t\t\t\t98D7ECE528CE58FC00DEAAC4 /* trees.c in Sources */,\n\t\t\t\t98D7ECE628CE58FC00DEAAC4 /* xerbla.c in Sources */,\n\t\t\t\t98D7ECE728CE58FC00DEAAC4 /* eidos_test.cpp in Sources */,\n\t\t\t\t98D7ECE828CE58FC00DEAAC4 /* blas.c in Sources */,\n\t\t\t\t98D7ECE928CE58FC00DEAAC4 /* log_file.cpp in Sources */,\n\t\t\t\t98D7ECEA28CE58FC00DEAAC4 /* eidos_class_Dictionary.cpp in Sources */,\n\t\t\t\t98D7ECEB28CE58FC00DEAAC4 /* individual.cpp in Sources */,\n\t\t\t\t98D7ECEC28CE58FC00DEAAC4 /* GitSHA1_Xcode.cpp in Sources */,\n\t\t\t\t98D7ECED28CE58FC00DEAAC4 /* eidos_class_Object.cpp in Sources */,\n\t\t\t\t98CEFD732AAFABAA00D2C9B4 /* inline.c in Sources */,\n\t\t\t\t98D7ECEE28CE58FC00DEAAC4 /* lodepng.cpp in Sources */,\n\t\t\t\t98D7ECEF28CE58FC00DEAAC4 /* mutation_run.cpp in Sources */,\n\t\t\t\t98D7ECF028CE58FC00DEAAC4 /* inline.c in Sources */,\n\t\t\t\t98CEFD6B2AAFABAA00D2C9B4 /* accel.c in Sources */,\n\t\t\t\t98D7ECF128CE58FC00DEAAC4 /* eidos_property_signature.cpp in Sources */,\n\t\t\t\t98D7ECF228CE58FC00DEAAC4 /* compress.c in Sources */,\n\t\t\t\t98D7ECF328CE58FC00DEAAC4 /* genomic_element_type.cpp in Sources */,\n\t\t\t\t98D7ECF428CE58FC00DEAAC4 /* discrete.c in Sources */,\n\t\t\t\t98D7ECF528CE58FC00DEAAC4 /* exponential.c in Sources */,\n\t\t\t\t98D7ECF628CE58FC00DEAAC4 /* eidos_value.cpp in Sources */,\n\t\t\t\t98D7ECF728CE58FC00DEAAC4 /* eidos_type_table.cpp in Sources */,\n\t\t\t\t98D7ECF828CE58FC00DEAAC4 /* eidos_functions.cpp in Sources */,\n\t\t\t\t98D7ECF928CE58FC00DEAAC4 /* pow_int.c in Sources */,\n\t\t\t\t98CEFCF32AAFABAA00D2C9B4 /* spline2d.c in Sources */,\n\t\t\t\t98D7ECFA28CE58FC00DEAAC4 /* weibull.c in Sources */,\n\t\t\t\t98D7ECFB28CE58FC00DEAAC4 /* fdiv.c in Sources */,\n\t\t\t\t98D7ECFC28CE58FC00DEAAC4 /* cholesky.c in Sources */,\n\t\t\t\t98D7ECFD28CE58FC00DEAAC4 /* kastore.c in Sources */,\n\t\t\t\t98D7ECFE28CE58FC00DEAAC4 /* tdist.c in Sources */,\n\t\t\t\t987A70162AE8032100A049E2 /* laplace.c in Sources */,\n\t\t\t\t98D7ECFF28CE58FC00DEAAC4 /* polymorphism.cpp in Sources */,\n\t\t\t\t98D7ED0028CE58FC00DEAAC4 /* eidos_class_TestElement.cpp in Sources */,\n\t\t\t\t98D7D6632AB24C40002AFE34 /* tdist.c in Sources */,\n\t\t\t\t98D7ED0128CE58FC00DEAAC4 /* main.cpp in Sources */,\n\t\t\t\t98D7ED0228CE58FC00DEAAC4 /* slim_functions.cpp in Sources */,\n\t\t\t\t98EDB4F62E65389600CC8798 /* init.c in Sources */,\n\t\t\t\t98D7ED0328CE58FC00DEAAC4 /* gauss.c in Sources */,\n\t\t\t\t98D7ED0428CE58FC00DEAAC4 /* cauchy.c in Sources */,\n\t\t\t\t98D7ED0528CE58FC00DEAAC4 /* substitution.cpp in Sources */,\n\t\t\t\t98D7ED0628CE58FC00DEAAC4 /* genotypes.c in Sources */,\n\t\t\t\t981DC38328E27301000ABE91 /* eidos_functions_colors.cpp in Sources */,\n\t\t\t\t98D7ED0728CE58FC00DEAAC4 /* exp.c in Sources */,\n\t\t\t\t98CEFD852AAFB23E00D2C9B4 /* tridiag.c in Sources */,\n\t\t\t\t98D7ED0828CE58FC00DEAAC4 /* gzwrite.c in Sources */,\n\t\t\t\t98D7ED0928CE58FC00DEAAC4 /* adler32.c in Sources */,\n\t\t\t\t98D7ED0A28CE58FC00DEAAC4 /* trig.c in Sources */,\n\t\t\t\t98D7ED0B28CE58FC00DEAAC4 /* eidos_globals.cpp in Sources */,\n\t\t\t\t98D7ED0C28CE58FC00DEAAC4 /* slim_test_genetics.cpp in Sources */,\n\t\t\t\t98D7ED0D28CE58FC00DEAAC4 /* multinomial.c in Sources */,\n\t\t\t\t98D7ED0E28CE58FC00DEAAC4 /* init.c in Sources */,\n\t\t\t\t98D7ED0F28CE58FC00DEAAC4 /* math.c in Sources */,\n\t\t\t\t98D7ED1028CE58FC00DEAAC4 /* genomic_element.cpp in Sources */,\n\t\t\t\t98D7ED1128CE58FC00DEAAC4 /* slim_globals.cpp in Sources */,\n\t\t\t\t98D7ED1228CE58FC00DEAAC4 /* interaction_type.cpp in Sources */,\n\t\t\t\t98D7ED1328CE58FC00DEAAC4 /* subpopulation.cpp in Sources */,\n\t\t\t\t98D7ED1428CE58FC00DEAAC4 /* swap.c in Sources */,\n\t\t\t\t98D7ED1528CE58FC00DEAAC4 /* gzlib.c in Sources */,\n\t\t\t\t98D7ED1628CE58FC00DEAAC4 /* species_eidos.cpp in Sources */,\n\t\t\t\t98D7ED1728CE58FC00DEAAC4 /* mt.c in Sources */,\n\t\t\t\t98D7ED1828CE58FC00DEAAC4 /* eidos_interpreter.cpp in Sources */,\n\t\t\t\t98D7ED1928CE58FC00DEAAC4 /* inline.c in Sources */,\n\t\t\t\t98D7ED1A28CE58FC00DEAAC4 /* message.c in Sources */,\n\t\t\t\t98D7ED1B28CE58FC00DEAAC4 /* dtrsv.c in Sources */,\n\t\t\t\t98D7ED1C28CE58FC00DEAAC4 /* infnan.c in Sources */,\n\t\t\t\t98D7ED1D28CE58FC00DEAAC4 /* crc32.c in Sources */,\n\t\t\t\t98D7ED1E28CE58FC00DEAAC4 /* zeta.c in Sources */,\n\t\t\t\t98D7ED1F28CE58FC00DEAAC4 /* eidos_class_DataFrame.cpp in Sources */,\n\t\t\t\t98D7ED2028CE58FC00DEAAC4 /* rng.c in Sources */,\n\t\t\t\t98D7ED2128CE58FC00DEAAC4 /* oper.c in Sources */,\n\t\t\t\t98D7ED2228CE58FC00DEAAC4 /* beta.c in Sources */,\n\t\t\t\t98D7ED2328CE58FC00DEAAC4 /* text_input.c in Sources */,\n\t\t\t\t98D7ED2428CE58FC00DEAAC4 /* pow_int.c in Sources */,\n\t\t\t\t98D7ED2528CE58FC00DEAAC4 /* eidos_test_operators_comparison.cpp in Sources */,\n\t\t\t\t98D7ED2628CE58FC00DEAAC4 /* lognormal.c in Sources */,\n\t\t\t\t98CEFCFB2AAFABAA00D2C9B4 /* bilinear.c in Sources */,\n\t\t\t\t98D7ED2728CE58FC00DEAAC4 /* community.cpp in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t984D5FAE1E3AF0D200473719 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 98D4C1B21A6F537B00FFB083 /* SLiMguiLegacy */;\n\t\t\ttargetProxy = 984D5FAD1E3AF0D200473719 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t98024740215D85880025D29C /* FindRecipePanel.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98024741215D85880025D29C /* Base */,\n\t\t\t);\n\t\t\tname = FindRecipePanel.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t980DD5181AAE42F900D5B7B8 /* GraphAxisRescaleSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t980DD5191AAE42F900D5B7B8 /* Base */,\n\t\t\t);\n\t\t\tname = GraphAxisRescaleSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982556671BA451D00054CB3F /* EidosHelpWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t982556681BA451D00054CB3F /* Base */,\n\t\t\t);\n\t\t\tname = EidosHelpWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t982A9DDC1FCA9FF0007BA3DF /* GraphBarRescaleSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t982A9DDD1FCA9FF0007BA3DF /* Base */,\n\t\t\t);\n\t\t\tname = GraphBarRescaleSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t985724BA1AD478630047C223 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t985724BB1AD478630047C223 /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t986926DA1AA1429D0000E138 /* GraphWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t986926DB1AA1429D0000E138 /* Base */,\n\t\t\t);\n\t\t\tname = GraphWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98A4EC921B67C1CD00CD92FD /* EidosConsoleWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98A4EC931B67C1CD00CD92FD /* Base */,\n\t\t\t);\n\t\t\tname = EidosConsoleWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C1BE1A6F537B00FFB083 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98D4C1BF1A6F537B00FFB083 /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C1FF1A70192A00FFB083 /* SLiMWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98D4C2001A70192A00FFB083 /* Base */,\n\t\t\t);\n\t\t\tname = SLiMWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C20B1A715F6100FFB083 /* AboutWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98D4C20C1A715F6100FFB083 /* Base */,\n\t\t\t);\n\t\t\tname = AboutWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98D4C2121A71838400FFB083 /* HelpWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98D4C2131A71838400FFB083 /* Base */,\n\t\t\t);\n\t\t\tname = HelpWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98EA965A1ECC2541006BA35B /* ProfileReport.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98EA965B1ECC2541006BA35B /* Base */,\n\t\t\t);\n\t\t\tname = ProfileReport.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t98EFE6321ADD92BC00CBEC78 /* EidosAboutWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t98EFE6331ADD92BC00CBEC78 /* Base */,\n\t\t\t);\n\t\t\tname = EidosAboutWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t982556AE1BA8E77C0054CB3F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t982556AF1BA8E77C0054CB3F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t982663551A3BABD300A0CBBF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_WARN_ASSIGN_ENUM = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CXX0X_EXTENSIONS = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;\n\t\t\t\tGCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;\n\t\t\t\tGCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;\n\t\t\t\tGCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_SIGN_COMPARE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNKNOWN_PRAGMAS = YES;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_LABEL = YES;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-fno-math-errno\",\n\t\t\t\t);\n\t\t\t\tPER_ARCH_CFLAGS_arm64 = \"-DEIDOS_HAS_NEON=1\";\n\t\t\t\tPER_ARCH_CFLAGS_x86_64 = \"-mavx2 -mfma -DEIDOS_HAS_AVX2=1 -DEIDOS_HAS_FMA=1\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSTRIP_STYLE = debugging;\n\t\t\t\tWARNING_CFLAGS = \"-Wimplicit-fallthrough\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t982663561A3BABD300A0CBBF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_WARN_ASSIGN_ENUM = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CXX0X_EXTENSIONS = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 3;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;\n\t\t\t\tGCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;\n\t\t\t\tGCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;\n\t\t\t\tGCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;\n\t\t\t\tGCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;\n\t\t\t\tGCC_WARN_SHADOW = YES;\n\t\t\t\tGCC_WARN_SIGN_COMPARE = YES;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNKNOWN_PRAGMAS = YES;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_LABEL = YES;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-fno-math-errno\",\n\t\t\t\t);\n\t\t\t\tPER_ARCH_CFLAGS_arm64 = \"-DEIDOS_HAS_NEON=1\";\n\t\t\t\tPER_ARCH_CFLAGS_x86_64 = \"-mavx2 -mfma -DEIDOS_HAS_AVX2=1 -DEIDOS_HAS_FMA=1\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSTRIP_STYLE = debugging;\n\t\t\t\tWARNING_CFLAGS = \"-Wimplicit-fallthrough\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t982663581A3BABD300A0CBBF /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\tTSK_TRACE_ERRORS,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tPRODUCT_NAME = slim;\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t982663591A3BABD300A0CBBF /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = \"SLIMPROFILING=0\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tPRODUCT_NAME = slim;\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t984D5FAF1E3AF0D200473719 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = C5P6M43RZ7;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tINFOPLIST_FILE = EidosSLiMTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.stick.EidosSLiMTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t984D5FB01E3AF0D200473719 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEVELOPMENT_TEAM = C5P6M43RZ7;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tINFOPLIST_FILE = EidosSLiMTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.stick.EidosSLiMTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t985724CA1AD478640047C223 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"EidosScribe/EidosScribe-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t985724CB1AD478640047C223 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = EIDOS_GUI;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"EidosScribe/EidosScribe-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98CF52FF294A3FC900557BBA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = SLiMgui/SLiMguiLegacy_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"SLIMGUI=1\",\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"SLiMgui/SLiMguiLegacy_multi-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/ /usr/local/include/\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98CF5300294A3FC900557BBA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = SLiMgui/SLiMguiLegacy_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"SLIMGUI=1\",\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t\t\"SLIMPROFILING=1\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"SLiMgui/SLiMguiLegacy_multi-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/ /usr/local/include/\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98CF5432294A714200557BBA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = EidosScribe/EidosScribe_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"EidosScribe/EidosScribe_multi-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = /usr/local/include/;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98CF5433294A714200557BBA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = EidosScribe/EidosScribe_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = EIDOS_GUI;\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"EidosScribe/EidosScribe_multi-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = /usr/local/include/;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98D4C1CE1A6F537C00FFB083 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"SLIMGUI=1\",\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t\tTSK_TRACE_ERRORS,\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"SLiMgui/SLiMguiLegacy-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98D4C1CF1A6F537C00FFB083 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"SLIMGUI=1\",\n\t\t\t\t\tEIDOS_GUI,\n\t\t\t\t\t\"SLIMPROFILING=1\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_UNUSED_PARAMETER = NO;\n\t\t\t\tGCC_WARN_UNUSED_VALUE = NO;\n\t\t\t\tINFOPLIST_FILE = \"SLiMgui/SLiMguiLegacy-Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"edu.MesserLab.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98D7EBEC28CE557C00DEAAC4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = eidos_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMPILER_INDEX_STORE_ENABLE = NO;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = /usr/local/include/;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98D7EBED28CE557C00DEAAC4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = eidos_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMPILER_INDEX_STORE_ENABLE = NO;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = /usr/local/include/;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t98D7ED2B28CE58FC00DEAAC4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = slim_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMPILER_INDEX_STORE_ENABLE = NO;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/ /usr/local/include/\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t98D7ED2C28CE58FC00DEAAC4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = slim_multi.entitlements;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMPILER_INDEX_STORE_ENABLE = NO;\n\t\t\t\tENABLE_HARDENED_RUNTIME = YES;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = \"SLIMPROFILING=0\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = /usr/local/lib/;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CFLAGS = (\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"$(OTHER_CPLUSPLUSFLAGS)\",\n\t\t\t\t\t\"-Xclang\",\n\t\t\t\t\t\"-fopenmp\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSYSTEM_HEADER_SEARCH_PATHS = \"\\\"${SRCROOT}\\\"/treerec/ \\\"${SRCROOT}\\\"/treerec/tskit/kastore/ /usr/local/include/\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t982556AD1BA8E77C0054CB3F /* Build configuration list for PBXNativeTarget \"eidos\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t982556AE1BA8E77C0054CB3F /* Debug */,\n\t\t\t\t982556AF1BA8E77C0054CB3F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t9826634B1A3BABD300A0CBBF /* Build configuration list for PBXProject \"SLiM\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t982663551A3BABD300A0CBBF /* Debug */,\n\t\t\t\t982663561A3BABD300A0CBBF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t982663571A3BABD300A0CBBF /* Build configuration list for PBXNativeTarget \"SLiM\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t982663581A3BABD300A0CBBF /* Debug */,\n\t\t\t\t982663591A3BABD300A0CBBF /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t984D5FB11E3AF0D200473719 /* Build configuration list for PBXNativeTarget \"EidosSLiMTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t984D5FAF1E3AF0D200473719 /* Debug */,\n\t\t\t\t984D5FB01E3AF0D200473719 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t985724C91AD478640047C223 /* Build configuration list for PBXNativeTarget \"EidosScribe\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t985724CA1AD478640047C223 /* Debug */,\n\t\t\t\t985724CB1AD478640047C223 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98CF52FE294A3FC900557BBA /* Build configuration list for PBXNativeTarget \"SLiMguiLegacy_multi\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98CF52FF294A3FC900557BBA /* Debug */,\n\t\t\t\t98CF5300294A3FC900557BBA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98CF5431294A714200557BBA /* Build configuration list for PBXNativeTarget \"EidosScribe_multi\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98CF5432294A714200557BBA /* Debug */,\n\t\t\t\t98CF5433294A714200557BBA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98D4C1CD1A6F537C00FFB083 /* Build configuration list for PBXNativeTarget \"SLiMguiLegacy\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98D4C1CE1A6F537C00FFB083 /* Debug */,\n\t\t\t\t98D4C1CF1A6F537C00FFB083 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98D7EBEB28CE557C00DEAAC4 /* Build configuration list for PBXNativeTarget \"eidos_multi\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98D7EBEC28CE557C00DEAAC4 /* Debug */,\n\t\t\t\t98D7EBED28CE557C00DEAAC4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t98D7ED2A28CE58FC00DEAAC4 /* Build configuration list for PBXNativeTarget \"slim_multi\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t98D7ED2B28CE58FC00DEAAC4 /* Debug */,\n\t\t\t\t98D7ED2C28CE58FC00DEAAC4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 982663481A3BABD300A0CBBF /* Project object */;\n}\n"
  },
  {
    "path": "SLiM.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:SLiM.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "SLiM.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SLiM.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/EidosScribe.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"985724AE1AD478630047C223\"\n               BuildableName = \"EidosScribe.app\"\n               BlueprintName = \"EidosScribe\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"985724C01AD478640047C223\"\n               BuildableName = \"SLiMscribeTests.xctest\"\n               BlueprintName = \"SLiMscribeTests\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"985724AE1AD478630047C223\"\n            BuildableName = \"EidosScribe.app\"\n            BlueprintName = \"EidosScribe\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"985724C01AD478640047C223\"\n               BuildableName = \"SLiMscribeTests.xctest\"\n               BlueprintName = \"SLiMscribeTests\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"985724AE1AD478630047C223\"\n            BuildableName = \"EidosScribe.app\"\n            BlueprintName = \"EidosScribe\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"985724AE1AD478630047C223\"\n            BuildableName = \"EidosScribe.app\"\n            BlueprintName = \"EidosScribe\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/EidosScribe_multi.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1220\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98CF5397294A714200557BBA\"\n               BuildableName = \"EidosScribe_multi.app\"\n               BlueprintName = \"EidosScribe_multi\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98CF5397294A714200557BBA\"\n            BuildableName = \"EidosScribe_multi.app\"\n            BlueprintName = \"EidosScribe_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98CF5397294A714200557BBA\"\n            BuildableName = \"EidosScribe_multi.app\"\n            BlueprintName = \"EidosScribe_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/SLiM.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"9826634F1A3BABD300A0CBBF\"\n               BuildableName = \"slim\"\n               BlueprintName = \"SLiM\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"9826634F1A3BABD300A0CBBF\"\n            BuildableName = \"slim\"\n            BlueprintName = \"SLiM\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"9826634F1A3BABD300A0CBBF\"\n            BuildableName = \"slim\"\n            BlueprintName = \"SLiM\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-version\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-usage\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-time\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-d MUTDEFS=\\&apos;initializeMutationType(\\\\&quot;m1\\\\&quot;, 0.5, &quot;f&quot;, 0.0);\\&apos; &quot;/Users/bhaller/Desktop/cmdline test.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-long\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-seed 1\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-mem\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-define &quot;N=1000&quot; -d &quot;THETA=5&quot; -d &quot;mu=THETA/(4*N)&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testEidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testSLiM\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-x\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-d foo=&apos;bar&apos;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/Documents/Research/MesserLab/SLiM_project/SLiM-Benchmarks/models/turnover_nonWF.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/Documents/Research/MesserLab/SLiM_project/SLiM-Benchmarks/models/turnover_WF.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/DocumentsSynced/Research/Messer lab/SLiM test suite/test scripts/009 linear island.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/DocumentsSynced/Research/Messer lab/SLiM test suite/test scripts/011.1 full Gravel 1MR.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/DocumentsSynced/Research/Messer lab/SLiM test suite/test scripts/023 gametophytic self-incompatibility.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"9826634F1A3BABD300A0CBBF\"\n            BuildableName = \"slim\"\n            BlueprintName = \"SLiM\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-seed 1418961197 /Users/bhaller/SLiM_examples/input_example_3.txt\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-seed 15\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Desktop/mutrun_burnin.slim\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/SLiM_multi.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1220\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98D7EC9F28CE58FC00DEAAC4\"\n               BuildableName = \"slim_multi\"\n               BlueprintName = \"slim_multi\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D7EC9F28CE58FC00DEAAC4\"\n            BuildableName = \"slim_multi\"\n            BlueprintName = \"slim_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-version\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-usage\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-time\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-mem\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-seed 1\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-maxthreads 4\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testEidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testSLiM\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/Desktop/benchmarking/SLiM-Benchmarks/models/E_sum_float.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/Desktop/benchmarking/SLiM-Benchmarks/models/S_interactingNeighborCount_2D.slim&quot;\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"&quot;/Users/bhaller/Desktop/benchmarking/SLiM-Benchmarks/models/S_totalOfNeighborStrengths_2D.slim&quot;\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D7EC9F28CE58FC00DEAAC4\"\n            BuildableName = \"slim_multi\"\n            BlueprintName = \"slim_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/SLiMguiLegacy.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98D4C1B21A6F537B00FFB083\"\n               BuildableName = \"SLiMguiLegacy.app\"\n               BlueprintName = \"SLiMguiLegacy\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98D4C1C41A6F537C00FFB083\"\n               BuildableName = \"SLiMguiTests.xctest\"\n               BlueprintName = \"SLiMguiTests\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D4C1B21A6F537B00FFB083\"\n            BuildableName = \"SLiMguiLegacy.app\"\n            BlueprintName = \"SLiMguiLegacy\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"984D5FA71E3AF0D200473719\"\n               BuildableName = \"EidosSLiMTests.xctest\"\n               BlueprintName = \"EidosSLiMTests\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D4C1B21A6F537B00FFB083\"\n            BuildableName = \"SLiMguiLegacy.app\"\n            BlueprintName = \"SLiMguiLegacy\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-NSBindingDebugLogLevel 1\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints YES\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D4C1B21A6F537B00FFB083\"\n            BuildableName = \"SLiMguiLegacy.app\"\n            BlueprintName = \"SLiMguiLegacy\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/SLiMguiLegacy_multi.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1220\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98CF51F3294A3FC900557BBA\"\n               BuildableName = \"SLiMguiLegacy_multi.app\"\n               BlueprintName = \"SLiMguiLegacy_multi\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98CF51F3294A3FC900557BBA\"\n            BuildableName = \"SLiMguiLegacy_multi.app\"\n            BlueprintName = \"SLiMguiLegacy_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98CF51F3294A3FC900557BBA\"\n            BuildableName = \"SLiMguiLegacy_multi.app\"\n            BlueprintName = \"SLiMguiLegacy_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/eidos.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"982556A81BA8E77B0054CB3F\"\n               BuildableName = \"eidos\"\n               BlueprintName = \"eidos\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"982556A81BA8E77B0054CB3F\"\n            BuildableName = \"eidos\"\n            BlueprintName = \"eidos\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"982556A81BA8E77B0054CB3F\"\n            BuildableName = \"eidos\"\n            BlueprintName = \"eidos\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-v\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-usage\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testEidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-time\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-mem\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Eidos_examples/Eratosthenes.eidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Desktop/beep.txt\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Eidos_examples/NestedLoops.eidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Eidos_examples/ArrayAccess.eidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"/Users/bhaller/Eidos_examples/Random.eidos\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"982556A81BA8E77B0054CB3F\"\n            BuildableName = \"eidos\"\n            BlueprintName = \"eidos\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiM.xcodeproj/xcshareddata/xcschemes/eidos_multi.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1220\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"98D7EB8328CE557C00DEAAC4\"\n               BuildableName = \"eidos_multi\"\n               BlueprintName = \"eidos_multi\"\n               ReferencedContainer = \"container:SLiM.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D7EB8328CE557C00DEAAC4\"\n            BuildableName = \"eidos_multi\"\n            BlueprintName = \"eidos_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <CommandLineArguments>\n         <CommandLineArgument\n            argument = \"-v\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-usage\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-testEidos\"\n            isEnabled = \"YES\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-time\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n         <CommandLineArgument\n            argument = \"-mem\"\n            isEnabled = \"NO\">\n         </CommandLineArgument>\n      </CommandLineArguments>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"98D7EB8328CE557C00DEAAC4\"\n            BuildableName = \"eidos_multi\"\n            BlueprintName = \"eidos_multi\"\n            ReferencedContainer = \"container:SLiM.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "SLiMgui/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/20/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#import <WebKit/WebView.h>\n#import <Quartz/Quartz.h>\n\n#include <string>\n\n\n@class SLiMWindowController;\n@class EidosTextView;\n\n\n// User defaults keys\nextern NSString *defaultsLaunchActionKey;\nextern NSString *defaultsDisplayFontSizeKey;\nextern NSString *defaultsSyntaxHighlightScriptKey;\nextern NSString *defaultsSyntaxHighlightOutputKey;\nextern NSString *defaultsPlaySoundParseSuccessKey;\nextern NSString *defaultsPlaySoundParseFailureKey;\n\n\n@interface AppDelegate : NSObject <NSApplicationDelegate>\n{\n\tstd::string app_cwd_;\t\t// the app's current working directory, set up by applicationWillFinishLaunching:\n\tbool launchedFromShell_;\t// TRUE if launched from shell, FALSE if launched from Finder/other\n}\n\n@property (nonatomic, retain) IBOutlet NSMenu *openRecipesMenu;\n\n- (std::string &)SLiMguiCurrentWorkingDirectory;\n- (bool)launchedFromShell;\n\n- (IBAction)resetSuppressionFlags:(id)sender;\n\n- (IBAction)showAboutWindow:(id)sender;\n\n- (IBAction)showHelp:(id)sender;\n- (IBAction)sendFeedback:(id)sender;\n- (IBAction)slimWorkshops:(id)sender;\n- (IBAction)mailingListAnnounce:(id)sender;\n- (IBAction)mailingListDiscuss:(id)sender;\n- (IBAction)showMesserLab:(id)sender;\n- (IBAction)showBenHaller:(id)sender;\n- (IBAction)showStickSoftware:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/AppDelegate.mm",
    "content": "//\n//  AppDelegate.m\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/20/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"AppDelegate.h\"\n#import \"SLiMWindowController.h\"\n#import \"SLiMDocument.h\"\n#import \"SLiMDocumentController.h\"\n#import \"EidosHelpController.h\"\n#import \"CocoaExtra.h\"\n#import \"EidosCocoaExtra.h\"\n#import \"eidos_beep.h\"\n#import \"slim_gui.h\"\n#import \"plot.h\"\n#import <WebKit/WebKit.h>\n\n#include <stdio.h>\n#include <unistd.h>\n\n\n// User defaults keys\nNSString *defaultsLaunchActionKey = @\"LaunchAction\";\nNSString *defaultsDisplayFontSizeKey = @\"DisplayFontSize\";\nNSString *defaultsSyntaxHighlightScriptKey = @\"SyntaxHighlightScript\";\nNSString *defaultsSyntaxHighlightOutputKey = @\"SyntaxHighlightOutput\";\nNSString *defaultsPlaySoundParseSuccessKey = @\"PlaySoundParseSuccess\";\nNSString *defaultsPlaySoundParseFailureKey = @\"PlaySoundParseFailure\";\n\ntypedef enum SLiMLaunchAction\n{\n\tkLaunchDoNothing = 0,\n\tkLaunchNewScriptWindow,\n\tkLaunchRunOpenPanel\n} SLiMLaunchAction;\n\n\n@interface AppDelegate () <NSApplicationDelegate>\n{\n\t// About window cruft\n\tIBOutlet NSWindow *aboutWindow;\n\tIBOutlet NSTextField *aboutVersionTextField;\n\tIBOutlet NSTextField *messerLabLineTextField;\n\tIBOutlet NSTextField *benHallerLineTextField;\n\tIBOutlet NSTextField *licenseTextField;\n\t\n\t// Help window cruft; kept for possible resurrection, see -showHelp:\n\t//IBOutlet NSWindow *helpWindow;\n\t//IBOutlet PDFView *helpPDFView;\n}\n@end\n\n\n@implementation AppDelegate\n\n@synthesize openRecipesMenu;\n\n+ (void)initialize\n{\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:@{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsLaunchActionKey : @(kLaunchNewScriptWindow),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsDisplayFontSizeKey : @11,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsSyntaxHighlightScriptKey : @YES,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsSyntaxHighlightOutputKey : @YES,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsPlaySoundParseSuccessKey : @YES,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  defaultsPlaySoundParseFailureKey : @YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  }];\n}\n\n- (void)dealloc\n{\n\t[self setOpenRecipesMenu:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)setUpRecipesMenu\n{\n\t[openRecipesMenu removeAllItems];\n\t\n\t// Add the Find Recipe... menu item and separator\n\t{\n\t\tNSMenuItem *menuItem = [openRecipesMenu addItemWithTitle:@\"Find Recipe...\" action:@selector(findRecipe:) keyEquivalent:@\"O\"];\n\t\t\n\t\t[menuItem setTarget:[NSDocumentController sharedDocumentController]];\n\t\t\n\t\t[openRecipesMenu addItem:[NSMenuItem separatorItem]];\n\t}\n\t\n\t// Find recipes in our bundle\n\tNSURL *urlForRecipesFolder = [[NSBundle mainBundle] URLForResource:@\"Recipes\" withExtension:@\"\"];\n\tNSFileManager *fm = [NSFileManager defaultManager];\n\tNSDirectoryEnumerator *dirEnum = [fm enumeratorAtURL:urlForRecipesFolder includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey] options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants) errorHandler:nil];\n\tNSMutableArray *recipeNames = [NSMutableArray array];\n\t\n\tfor (NSURL *fileURL in dirEnum)\n\t{\n\t\tNSNumber *isDirectory = nil;\n\t\t\n\t\t[fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];\n\t\t\n\t\tif (![isDirectory boolValue])\n\t\t{\n\t\t\tNSString *name = nil;\n\t\t\t\n\t\t\t[fileURL getResourceValue:&name forKey:NSURLNameKey error:nil];\n\t\t\t\n\t\t\tif ([name hasPrefix:@\"Recipe \"])\n\t\t\t{\n\t\t\t\tif ([name hasSuffix:@\".txt\"])\n\t\t\t\t{\n\t\t\t\t\t// Remove the .txt extension for SLiM models\n\t\t\t\t\tNSString *trimmedName = [name substringWithRange:NSMakeRange(7, [name length] - 11)];\n\t\t\t\t\t\n\t\t\t\t\t[recipeNames addObject:trimmedName];\n\t\t\t\t}\n\t\t\t\telse if ([name hasSuffix:@\".py\"])\n\t\t\t\t{\n\t\t\t\t\t// Leave the .py extension for Python models\n\t\t\t\t\tNSString *trimmedName = [name substringWithRange:NSMakeRange(7, [name length] - 7)];\n\t\t\t\t\t\n\t\t\t\t\t[recipeNames addObject:[trimmedName stringByAppendingString:@\" 🐍\"]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t[recipeNames sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {\n\t\treturn [(NSString *)obj1 compare:(NSString *)obj2 options:NSNumericSearch];\n\t}];\n\t\n\tNSString *previousItemChapter = nil;\n\tNSMenu *chapterSubmenu = nil;\n\t\n\tfor (NSString *recipeName in recipeNames)\n\t{\n\t\tNSUInteger firstDotIndex = [recipeName rangeOfString:@\".\"].location;\n\t\tNSString *recipeChapter = (firstDotIndex != NSNotFound) ? [recipeName substringToIndex:firstDotIndex] : nil;\n\t\t\n\t\t// Create a submenu for each chapter\n\t\tif (recipeChapter && ![recipeChapter isEqualToString:previousItemChapter])\n\t\t{\n\t\t\tint recipeChapterValue = [recipeChapter intValue];\n\t\t\tNSString *chapterName = nil;\n\t\t\t\n\t\t\tswitch (recipeChapterValue)\n\t\t\t{\n\t\t\t\tcase 4: chapterName = @\"Getting started: Neutral evolution in a panmictic population\";\t\tbreak;\n\t\t\t\tcase 5: chapterName = @\"Demography and population structure\";\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase 6: chapterName = @\"Mutation types, genomic elements, and chromosome structure\";\t\tbreak;\n\t\t\t\tcase 7: chapterName = @\"SLiMgui visualizations for polymorphism patterns\";\t\t\t\t\tbreak;\n\t\t\t\tcase 8: chapterName = @\"Reproduction, meiosis, and multiple chromosomes\";\t\t\t\t\tbreak;\n\t\t\t\tcase 9:\tchapterName = @\"Selective sweeps\";\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase 10:chapterName = @\"Context-dependent selection using mutationEffect() callbacks\";\t\tbreak;\n\t\t\t\tcase 11:chapterName = @\"Complex mating schemes using mateChoice() callbacks\";\t\t\t\tbreak;\n\t\t\t\tcase 12:chapterName = @\"Direct child modifications using modifyChild() callbacks\";\t\t\tbreak;\n\t\t\t\tcase 13:chapterName = @\"Phenotypes, fitness functions, quantitative traits, and QTLs\";\t\tbreak;\n\t\t\t\tcase 14:chapterName = @\"Advanced WF models\";\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase 15:chapterName = @\"Going beyond Wright-Fisher models: nonWF model recipes\";\t\t\tbreak;\n\t\t\t\tcase 16:chapterName = @\"Advanced nonWF techniques for managing reproduction\";\t\t\t\tbreak;\n\t\t\t\tcase 17:chapterName = @\"Continuous-space models, interactions, and spatial maps\";\t\t\tbreak;\n\t\t\t\tcase 18:chapterName = @\"Tree-sequence recording: tracking population history\";\t\t\t\tbreak;\n\t\t\t\tcase 19:chapterName = @\"Modeling explicit nucleotides\";\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase 20:chapterName = @\"Multispecies modeling\";\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase 23:chapterName = @\"Parallel SLiM: Running SLiM multithreaded\";\t\t\t\t\t\t\tbreak;\n\t\t\t\tdefault: break;\n\t\t\t}\n\t\t\t\n\t\t\tif (chapterName)\n\t\t\t{\n\t\t\t\tNSString *fullChapterName = [NSString stringWithFormat:@\"%d – %@\", recipeChapterValue, chapterName];\n\t\t\t\tNSMenuItem *mainItem = [openRecipesMenu addItemWithTitle:fullChapterName action:NULL keyEquivalent:@\"\"];\n\t\t\t\t\n\t\t\t\tchapterSubmenu = [[[NSMenu alloc] init] autorelease];\n\t\t\t\t\n\t\t\t\t[mainItem setSubmenu:chapterSubmenu];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tNSLog(@\"unrecognized chapter value %d\", recipeChapterValue);\n\t\t\t\tNSBeep();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Move on to the current chapter\n\t\tpreviousItemChapter = recipeChapter;\n\t\t\n\t\t// And now add the menu item for the recipe\n\t\tNSMenuItem *menuItem = [chapterSubmenu addItemWithTitle:recipeName action:@selector(openRecipe:) keyEquivalent:@\"\"];\n\t\t\n\t\t[menuItem setTarget:[NSDocumentController sharedDocumentController]];\n\t}\n}\n\n- (void)applicationWillFinishLaunching:(NSNotification *)aNotification\n{\n\t// Determine whether we were launched from a shell or from something else (Finder, Xcode, etc.)\n\tlaunchedFromShell_ = (isatty(fileno(stdin)) == 1) && !SLiM_AmIBeingDebugged();\n\t//NSLog(@\"launched from %@\", launchedFromShell_ ? @\"shell\" : @\"Finder\");\n\t\n    // Require light appearance, at least for now; supporting dark mode would require custom art etc.\n    if ([NSApp respondsToSelector:@selector(setAppearance:)])\n        [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];\n    \n\t// Install our custom beep handler\n\tEidos_Beep = &Eidos_Beep_MACOS;\n\t\n\t// Warm up our back ends before anything else happens, including our own class objects\n#ifdef _OPENMP\n\t// Multithreading in SLiMguiLegacy is not for end user use; this is for testing/debugging only.\n\t// We always use 4 threads; we don't want to hog the whole machine, just run with a couple threads.\n\t// We pass false for active_threads to let the worker threads sleep, otherwise the CPU is pegged\n\t// the whole time SLiMgui is running, even when sitting idle.\n\tEidos_WarmUpOpenMP(&std::cout, true, 4, false, /* default per-task thread counts */ \"\");\n#endif\n\t\n\tSLiM_ConfigureContext();\n\tEidos_WarmUp();\n\tSLiM_WarmUp();\n\t\n\tgSLiM_Plot_Class = new Plot_Class(gStr_Plot, gEidosDictionaryUnretained_Class);\n\tgSLiM_Plot_Class->CacheDispatchTables();\n\t\n\tgSLiM_SLiMgui_Class = new SLiMgui_Class(gStr_SLiMgui, gEidosDictionaryUnretained_Class);\n\tgSLiM_SLiMgui_Class->CacheDispatchTables();\n\t\n\t// QtSLiM frees the RNG that Eidos_WarmUp() just made, here.  We could do that too; it would\n\t// do no harm.  But with the initialization order in SLiMguiLegacy, it will be freed by\n\t// startNewSimulationFromScript anyway, before any problems arise.\n\t\n\t// Remember our current working directory, to return to whenever we are not inside SLiM/Eidos\n\tapp_cwd_ = Eidos_CurrentDirectory();\n\t//NSLog(@\"current directory == %s\", app_cwd_.c_str());\n\t\n\t// Create the Open Recipes menu\n\t[self setUpRecipesMenu];\n}\n\n- (std::string &)SLiMguiCurrentWorkingDirectory\n{\n\treturn app_cwd_;\n}\n\n- (bool)launchedFromShell\n{\n\treturn launchedFromShell_;\n}\n\n- (void)applicationDidFinishLaunching:(NSNotification *)aNotification\n{\n\t// check for required fonts, to prevent problems downstream\n\tNSFont *times = [NSFont fontWithName:@\"Times New Roman\" size:13.0];\n\tNSFont *menlo = [NSFont fontWithName:@\"Menlo\" size:13.0];\n\tNSFont *optima = [NSFont fontWithName:@\"Optima\" size:13.0];\n\tNSFont *optima_b = [NSFont fontWithName:@\"Optima-Bold\" size:13.0];\n\tNSFont *optima_i = [NSFont fontWithName:@\"Optima-Italic\" size:13.0];\n\tNSString *fontName = nil;\n\t\n\tif (!times)\t\t\t\tfontName = @\"Times New Roman\";\n\telse if (!menlo)\t\tfontName = @\"Menlo\";\n\telse if (!optima)\t\tfontName = @\"Optima\";\n\telse if (!optima_b)\t\tfontName = @\"Optima-Bold\";\n\telse if (!optima_i)\t\tfontName = @\"Optima-Italic\";\n\t\n\tif (fontName)\n\t{\n\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\n\t\t[alert setAlertStyle:NSAlertStyleCritical];\n\t\t[alert setMessageText:@\"Missing font\"];\n\t\t[alert setInformativeText:[NSString stringWithFormat:@\"The standard system font %@ is required for SLiMgui to run, but appears to be missing.  Please check your macOS installation.\\n\\nSLiMgui will now exit.\", fontName]];\n\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t\n\t\t[alert runModal];\n\t\t[[NSApplication sharedApplication] terminate:nil];\n\t\treturn;\n\t}\n\t\n\t// perform the launch action\n\tSLiMLaunchAction launchAction = (SLiMLaunchAction)[[NSUserDefaults standardUserDefaults] integerForKey:defaultsLaunchActionKey];\n\t\n\tswitch (launchAction)\n\t{\n\t\tcase kLaunchDoNothing:\n\t\t\tbreak;\n\t\tcase kLaunchNewScriptWindow:\n\t\t\t[self performSelector:@selector(openNewDocumentIfNeeded:) withObject:nil afterDelay:0.01];\n\t\t\tbreak;\n\t\tcase kLaunchRunOpenPanel:\n\t\t\t[[NSDocumentController sharedDocumentController] openDocument:nil];\n\t\t\tbreak;\n\t}\n\t\n\t// The tips window has been removed so I don't have to maintain it, but the sources remain in the repository.  BCH 3/3/2022\n\t//[TipsWindowController showTipsWindowOnLaunch];\n}\n\n- (void)openNewDocumentIfNeeded:(id)sender\n{\n\tNSUInteger documentCount = [[[NSDocumentController sharedDocumentController] documents] count];\n\t\n\t// Open an untitled document if there is no document (restored, opened)\n\tif (documentCount == 0)\n\t{\n\t\tSLiMDocument *doc = [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:NULL];\n\t\t\n\t\t[doc setTransient:YES];\n\t\t[[doc slimWindowController] displayStartupMessage];\n\t}\n}\n\n- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender\n{\n\t// Prevent AppKit from opening a new untitled window on launch.  We do this because we do this ourselves\n\t// instead; and we do it ourselves instead because Apple seems to have screwed it up.  (I.e., sometimes\n\t// this method does not get called even when no other document is being restored.)\n\treturn NO;\n}\n\n- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag\n{\n\t// Prevent a new untitled window from opening if we are already running, have no open windows, and are activated.\n\t// This is non-standard behavior, but I really hate the standard behavior, so.\n\treturn NO;\n}\n\n- (void)applicationWillTerminate:(NSNotification *)aNotification\n{\n}\n\n- (IBAction)resetSuppressionFlags:(id)sender\n{\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\t[defaults removeObjectForKey:EidosDefaultsSuppressScriptCheckSuccessPanelKey];\n\t\n\t// The tips window has been removed so I don't have to maintain it, but the sources remain in the repository.  BCH 3/3/2022\n\t//[defaults removeObjectForKey:SLiMDefaultsShowTipsPanelKey];\n\t//[defaults removeObjectForKey:SLiMDefaultsTipsIndexKey];\n}\n\n\n//\n//\tAbout window management\n//\n\n- (IBAction)showAboutWindow:(id)sender\n{\n\t[[NSBundle mainBundle] loadNibNamed:@\"AboutWindow\" owner:self topLevelObjects:NULL];\n\t\n\t// The window is the top-level object in this nib.  It will release itself when closed, so we will retain it on its behalf here.\n\t// Note that the aboutWindow and aboutWebView outlets do not get zeroed out when the about window closes; but we only use them here.\n\t[aboutWindow retain];\n\t\n//\t// And we need to make our WebView load our README.html file\n//\tNSString *readmeURL = [[[NSBundle mainBundle] URLForResource:@\"README\" withExtension:@\"html\"] absoluteString];\n//\t\n//\t[aboutWebView setShouldCloseWithWindow:YES];\n//\t[aboutWebView setMainFrameURL:readmeURL];\n\t\n\t// Set our version number string\n\tNSString *bundleVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"CFBundleShortVersionString\"];\n\tNSString *versionString = [NSString stringWithFormat:@\"version %@\", bundleVersionString];\n\t\n\t[aboutVersionTextField setStringValue:versionString];\n\t\n\t// Fix up hyperlinks\n\t[messerLabLineTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://messerlab.org/slim/\"] onText:@\"http://messerlab.org/slim/\"];\n\t[benHallerLineTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://benhaller.com/\"] onText:@\"http://benhaller.com/\"];\n\t[licenseTextField eidosSetHyperlink:[NSURL URLWithString:@\"http://www.gnu.org/licenses/\"] onText:@\"http://www.gnu.org/licenses/\"];\n\t\n\t// Now that everything is set up, show the window\n\t[aboutWindow makeKeyAndOrderFront:nil];\n}\n\n- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id <WebPolicyDecisionListener>)listener\n{\n\tif ([actionInformation objectForKey:WebActionElementKey])\n\t{\n\t\t[listener ignore];\n\t\t[[NSWorkspace sharedWorkspace] openURL:[request URL]];\n\t}\n\telse\n\t{\n\t\t[listener use];\n\t}\n}\n\n\n//\n//\tHelp\n//\n\n- (IBAction)showHelp:(id)sender\n{\n\t/*\n\tif (!helpWindow)\n\t{\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"HelpWindow\" owner:self topLevelObjects:NULL];\n\t\t\n\t\t// The window is the top-level object in this nib.  It will not release itself when closed, so it will stay around forever\n\t\t// (to improve reopening speed).  We retain it here on its behalf.\n\t\t[helpWindow retain];\n\t\t\n\t\t// And we need to make our WebView load our README.html file\n\t\tNSURL *manualURL = [[NSBundle mainBundle] URLForResource:@\"SLiM_manual\" withExtension:@\"pdf\"];\n\t\t\n\t\t[helpPDFView setDocument:[[[PDFDocument alloc] initWithURL:manualURL] autorelease]];\n\t}\n\t\n\t// Now that everything is set up, show the window\n\t[helpWindow makeKeyAndOrderFront:nil];\n\t*/\n\t\n\t// We used to show the SLiM 1.8 manual as a PDF in a separate window.  That code is commented out above.\n\t// I've left HelpWindow.xib in the project, in case we want to go back to doing that sort of thing; but\n\t// for now, we show the script help window.\n\t[[EidosHelpController sharedController] showWindow];\n}\n\n- (IBAction)sendFeedback:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"mailto:philipp.messer@gmail.com?subject=SLiM%20Feedback\"]];\n}\n\n- (IBAction)slimWorkshops:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://benhaller.com/workshops/workshops.html\"]];\n}\n\n- (IBAction)mailingListAnnounce:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"https://groups.google.com/d/forum/slim-announce\"]];\n}\n\n- (IBAction)mailingListDiscuss:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"https://groups.google.com/d/forum/slim-discuss\"]];\n}\n\n- (IBAction)showSlimHomePage:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://messerlab.org/slim/\"]];\n}\n\n- (IBAction)showSlimExtrasPage:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"https://github.com/MesserLab/SLiM-Extras\"]];\n}\n\n- (IBAction)showSlimPublication:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"https://doi.org/10.1093/molbev/msw211\"]];\n}\n\n- (IBAction)showMesserLab:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://messerlab.org/\"]];\n}\n\n- (IBAction)showBenHaller:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://www.benhaller.com/\"]];\n}\n\n- (IBAction)showStickSoftware:(id)sender\n{\n\t[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@\"http://www.sticksoftware.com/\"]];\n}\n\n// Dummy actions; see validateMenuItem:\n- (IBAction)play:(id)sender {}\n- (IBAction)profile:(id)sender {}\n- (IBAction)toggleConsoleVisibility:(id)sender {}\n- (IBAction)toggleBrowserVisibility:(id)sender {}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\t// Handle validation for menu items that really belong to SLiMWindowController.  This provides a default validation\n\t// for these menu items when no SLiMWindowController is receiving.  The point is to reset the titles of these menu\n\t// items back to their base state, not just to disable them (which would happen anyway).\n\tif (sel == @selector(play:))\n\t{\n\t\t[menuItem setTitle:@\"Play\"];\n\t\treturn NO;\n\t}\n\tif (sel == @selector(profile:))\n\t{\n\t\t[menuItem setTitle:@\"Profile\"];\n\t\treturn NO;\n\t}\n\tif (sel == @selector(toggleConsoleVisibility:))\n\t{\n\t\t[menuItem setTitle:@\"Show Eidos Console\"];\n\t\treturn NO;\n\t}\n\tif (sel == @selector(toggleBrowserVisibility:))\n\t{\n\t\t[menuItem setTitle:@\"Show Variable Browser\"];\n\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/Base.lproj/AboutWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"AppDelegate\">\n            <connections>\n                <outlet property=\"aboutVersionTextField\" destination=\"WB2-cU-hkd\" id=\"CNZ-WA-EUh\"/>\n                <outlet property=\"aboutWindow\" destination=\"QvC-M9-y7g\" id=\"7vI-I4-hc5\"/>\n                <outlet property=\"benHallerLineTextField\" destination=\"9KH-lz-tf6\" id=\"XIG-vn-iuX\"/>\n                <outlet property=\"licenseTextField\" destination=\"Khq-in-4x8\" id=\"jGW-BO-KlO\"/>\n                <outlet property=\"messerLabLineTextField\" destination=\"C4q-EC-cXM\" id=\"aA6-UQ-o81\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"745\" width=\"621\" height=\"439\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1417\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"621\" height=\"426\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CxN-ue-roS\">\n                        <rect key=\"frame\" x=\"20\" y=\"278\" width=\"128\" height=\"128\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"128\" id=\"rVI-r9-sd7\"/>\n                            <constraint firstAttribute=\"width\" constant=\"128\" id=\"sfg-xt-7oO\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"NSApplicationIcon\" id=\"6vw-j2-cwW\"/>\n                    </imageView>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wDw-79-A4b\">\n                        <rect key=\"frame\" x=\"175\" y=\"367\" width=\"338\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"SLiMguiLegacy : A graphical user interface for SLiM\" id=\"sJB-jI-icR\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9KH-lz-tf6\">\n                        <rect key=\"frame\" x=\"175\" y=\"302\" width=\"267\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"By Benjamin C. Haller, http://benhaller.com/\" id=\"cag-MY-und\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"C4q-EC-cXM\">\n                        <rect key=\"frame\" x=\"175\" y=\"343\" width=\"351\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Messer Lab, Cornell University, http://messerlab.org/slim/\" id=\"jqg-yt-Wpi\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cD8-Mz-qIr\">\n                        <rect key=\"frame\" x=\"175\" y=\"326\" width=\"390\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Copyright © 2016–2025 Benjamin C. Haller.  All rights reserved.\" id=\"jZm-bw-sGW\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WB2-cU-hkd\">\n                        <rect key=\"frame\" x=\"409\" y=\"399\" width=\"204\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"200\" id=\"SBS-mC-L6n\"/>\n                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"kLz-az-BTI\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"version\" id=\"15F-WF-Zi9\">\n                            <font key=\"font\" metaFont=\"menu\" size=\"11\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Khq-in-4x8\">\n                        <rect key=\"frame\" x=\"46\" y=\"40\" width=\"529\" height=\"208\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"525\" id=\"RZq-0f-pKI\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"xpC-h2-wjV\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">SLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with SLiM. If not, see http://www.gnu.org/licenses/.\n\nPlease see the SLiM manual for credits and license information for code that has been incorporated into SLiM from other authors.</string>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Khq-in-4x8\" secondAttribute=\"trailing\" constant=\"48\" id=\"2CV-ji-UcW\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Khq-in-4x8\" secondAttribute=\"bottom\" constant=\"40\" id=\"6XZ-EZ-OTI\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"cD8-Mz-qIr\" secondAttribute=\"trailing\" constant=\"48\" id=\"8qw-4r-wox\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"WB2-cU-hkd\" secondAttribute=\"trailing\" constant=\"10\" id=\"DNR-LT-Q4b\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"wDw-79-A4b\" secondAttribute=\"trailing\" constant=\"48\" id=\"GLQ-Zc-4NI\"/>\n                    <constraint firstItem=\"C4q-EC-cXM\" firstAttribute=\"leading\" secondItem=\"wDw-79-A4b\" secondAttribute=\"leading\" id=\"HW0-by-DLL\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"trailing\" constant=\"48\" id=\"I3C-ed-3yk\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"leading\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"leading\" id=\"JdI-QS-ppx\"/>\n                    <constraint firstItem=\"WB2-cU-hkd\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"10\" id=\"Jzj-ki-KJ3\"/>\n                    <constraint firstItem=\"WB2-cU-hkd\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"48\" id=\"Qu2-Jz-c4p\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"top\" secondItem=\"wDw-79-A4b\" secondAttribute=\"bottom\" constant=\"-39\" id=\"SgS-FZ-ZOF\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"top\" secondItem=\"C4q-EC-cXM\" secondAttribute=\"bottom\" constant=\"1\" id=\"TsK-bf-Azp\"/>\n                    <constraint firstItem=\"Khq-in-4x8\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"48\" id=\"Vdb-Fz-zuX\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"b1f-cV-8HA\"/>\n                    <constraint firstItem=\"cD8-Mz-qIr\" firstAttribute=\"leading\" secondItem=\"9KH-lz-tf6\" secondAttribute=\"leading\" id=\"chO-2v-wka\"/>\n                    <constraint firstItem=\"C4q-EC-cXM\" firstAttribute=\"top\" secondItem=\"wDw-79-A4b\" secondAttribute=\"bottom\" constant=\"8\" id=\"iNQ-B5-u82\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"9KH-lz-tf6\" secondAttribute=\"trailing\" constant=\"48\" id=\"sQV-oY-RnS\"/>\n                    <constraint firstItem=\"9KH-lz-tf6\" firstAttribute=\"top\" secondItem=\"cD8-Mz-qIr\" secondAttribute=\"bottom\" constant=\"8\" id=\"sch-36-LNf\"/>\n                    <constraint firstItem=\"Khq-in-4x8\" firstAttribute=\"top\" secondItem=\"CxN-ue-roS\" secondAttribute=\"bottom\" constant=\"30\" id=\"vXy-xu-99m\"/>\n                    <constraint firstItem=\"wDw-79-A4b\" firstAttribute=\"leading\" secondItem=\"CxN-ue-roS\" secondAttribute=\"trailing\" constant=\"29\" id=\"z2U-EL-tOb\"/>\n                    <constraint firstItem=\"CxN-ue-roS\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"zxo-Hp-C8e\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"957.5\" y=\"659\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSApplicationIcon\" width=\"32\" height=\"32\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/FindRecipePanel.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"14109\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"14109\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"FindRecipeController\">\n            <connections>\n                <outlet property=\"buttonOK\" destination=\"Pkh-by-JBm\" id=\"Pml-5e-wa2\"/>\n                <outlet property=\"keyword1TextField\" destination=\"lgH-0C-2Hp\" id=\"aUG-m2-Nuy\"/>\n                <outlet property=\"keyword2TextField\" destination=\"48P-k9-e1x\" id=\"8BQ-DF-DO9\"/>\n                <outlet property=\"keyword3TextField\" destination=\"mF8-Sh-jOJ\" id=\"8oC-In-xUR\"/>\n                <outlet property=\"matchTableView\" destination=\"VaG-4K-Vrh\" id=\"kzz-YW-Jc6\"/>\n                <outlet property=\"scriptPreview\" destination=\"s2s-uB-cfR\" id=\"GjQ-Kx-CFf\"/>\n                <outlet property=\"window\" destination=\"QvC-M9-y7g\" id=\"F7U-Pk-Y7K\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Find Recipe Panel\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" titleVisibility=\"hidden\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"649\" height=\"667\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"699\" height=\"740\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z1G-AL-Ueu\">\n                        <rect key=\"frame\" x=\"20\" y=\"672\" width=\"48\" height=\"48\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"48\" id=\"XaJ-xD-sfh\"/>\n                            <constraint firstAttribute=\"height\" constant=\"48\" id=\"eN1-uZ-hJ8\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"NSApplicationIcon\" id=\"nF6-NW-k95\"/>\n                    </imageView>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pju-DG-dA4\">\n                        <rect key=\"frame\" x=\"86\" y=\"703\" width=\"79\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Find Recipe\" id=\"JCf-yX-VP2\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" preferredMaxLayoutWidth=\"488\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L3K-nW-f6P\">\n                        <rect key=\"frame\" x=\"86\" y=\"678\" width=\"340\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Enter search keywords and select a match from the list.\" id=\"rZF-Hg-87F\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pkh-by-JBm\">\n                        <rect key=\"frame\" x=\"603\" y=\"13\" width=\"82\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"OK\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"YI5-D0-8Bh\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"okButtonPressed:\" target=\"-2\" id=\"hxg-Ms-R3X\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p3J-0n-RwH\">\n                        <rect key=\"frame\" x=\"521\" y=\"13\" width=\"82\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"e8F-3D-CKg\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancelButtonPressed:\" target=\"-2\" id=\"atG-l7-dr9\"/>\n                        </connections>\n                    </button>\n                    <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c0p-OA-wsz\">\n                        <rect key=\"frame\" x=\"102\" y=\"633\" width=\"67\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Keywords:\" id=\"S9H-ke-4W6\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lgH-0C-2Hp\" userLabel=\"Keyword1\">\n                        <rect key=\"frame\" x=\"179\" y=\"630\" width=\"500\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"500\" id=\"g65-Wf-uRB\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"ykF-lC-m63\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"rag-nH-c5A\"/>\n                        </connections>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"48P-k9-e1x\" userLabel=\"Keyword2\">\n                        <rect key=\"frame\" x=\"179\" y=\"591\" width=\"500\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"Mnm-um-H28\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"oP9-xS-xnK\"/>\n                        </connections>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mF8-Sh-jOJ\" userLabel=\"Keyword3\">\n                        <rect key=\"frame\" x=\"179\" y=\"552\" width=\"500\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"8gk-Id-KZd\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"klZ-eM-sWE\"/>\n                        </connections>\n                    </textField>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TsW-TI-bI2\">\n                        <rect key=\"frame\" x=\"104\" y=\"381\" width=\"575\" height=\"114\"/>\n                        <clipView key=\"contentView\" id=\"jYU-hq-hUM\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"573\" height=\"112\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" viewBased=\"YES\" id=\"VaG-4K-Vrh\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"573\" height=\"112\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"\" editable=\"NO\" width=\"570\" minWidth=\"40\" maxWidth=\"1000\" id=\"itd-WT-mxi\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Recipe\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" title=\"Text Cell\" id=\"ELM-zt-cfK\">\n                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView id=\"y2o-iU-TPc\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"570\" height=\"17\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" fixedFrame=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lra-fE-fCo\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"570\" height=\"17\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"laC-PR-7Iq\">\n                                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"lra-fE-fCo\" id=\"XqA-to-i8A\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <action trigger=\"doubleAction\" selector=\"okButtonPressed:\" target=\"-2\" id=\"UIg-3O-LHJ\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"rch-UG-b5D\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"eU2-VE-haY\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"114\" id=\"j8W-NK-7Up\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"BC8-s1-lWO\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"223\" height=\"15\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"f4C-6x-t2o\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1aw-Cd-0bt\">\n                        <rect key=\"frame\" x=\"416\" y=\"615\" width=\"27\" height=\"13\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"AND\" id=\"OZb-RF-JDK\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"10\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"axo-nj-Ciz\">\n                        <rect key=\"frame\" x=\"416\" y=\"576\" width=\"27\" height=\"13\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"AND\" id=\"MjM-iP-rOd\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"10\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pVM-XW-ZVx\">\n                        <rect key=\"frame\" x=\"102\" y=\"507\" width=\"60\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Matches:\" id=\"ewq-qC-EB0\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zyN-et-64I\">\n                        <rect key=\"frame\" x=\"104\" y=\"69\" width=\"575\" height=\"300\"/>\n                        <clipView key=\"contentView\" id=\"vQf-lm-Vhq\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"558\" height=\"298\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView importsGraphics=\"NO\" verticallyResizable=\"YES\" usesFontPanel=\"YES\" findStyle=\"panel\" continuousSpellChecking=\"YES\" allowsUndo=\"YES\" usesRuler=\"YES\" allowsNonContiguousLayout=\"YES\" quoteSubstitution=\"YES\" dashSubstitution=\"YES\" smartInsertDelete=\"YES\" id=\"s2s-uB-cfR\" customClass=\"EidosTextView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"558\" height=\"298\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    <size key=\"minSize\" width=\"558\" height=\"298\"/>\n                                    <size key=\"maxSize\" width=\"558\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </textView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"300\" id=\"M8d-qx-R89\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"Dl3-J6-4mC\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"CA5-YW-603\">\n                            <rect key=\"frame\" x=\"559\" y=\"1\" width=\"15\" height=\"298\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"48P-k9-e1x\" firstAttribute=\"width\" secondItem=\"lgH-0C-2Hp\" secondAttribute=\"width\" id=\"1oI-yL-Asc\"/>\n                    <constraint firstItem=\"TsW-TI-bI2\" firstAttribute=\"top\" secondItem=\"pVM-XW-ZVx\" secondAttribute=\"bottom\" constant=\"12\" id=\"1rL-TI-AIY\"/>\n                    <constraint firstItem=\"Z1G-AL-Ueu\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"20x-BI-a4X\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"p3J-0n-RwH\" secondAttribute=\"bottom\" constant=\"20\" id=\"2gI-4C-PgC\"/>\n                    <constraint firstItem=\"zyN-et-64I\" firstAttribute=\"leading\" secondItem=\"TsW-TI-bI2\" secondAttribute=\"leading\" id=\"2yo-Fo-daP\"/>\n                    <constraint firstItem=\"mF8-Sh-jOJ\" firstAttribute=\"top\" secondItem=\"axo-nj-Ciz\" secondAttribute=\"bottom\" constant=\"2\" id=\"6bK-Z8-dSY\"/>\n                    <constraint firstItem=\"mF8-Sh-jOJ\" firstAttribute=\"width\" secondItem=\"48P-k9-e1x\" secondAttribute=\"width\" id=\"70y-g9-kB2\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"lgH-0C-2Hp\" secondAttribute=\"trailing\" constant=\"20\" id=\"7To-9w-vQo\"/>\n                    <constraint firstItem=\"lgH-0C-2Hp\" firstAttribute=\"leading\" secondItem=\"c0p-OA-wsz\" secondAttribute=\"trailing\" constant=\"12\" id=\"8Hv-2r-k0h\"/>\n                    <constraint firstItem=\"axo-nj-Ciz\" firstAttribute=\"centerX\" secondItem=\"48P-k9-e1x\" secondAttribute=\"centerX\" id=\"8KV-90-pIW\"/>\n                    <constraint firstItem=\"Pju-DG-dA4\" firstAttribute=\"top\" secondItem=\"Z1G-AL-Ueu\" secondAttribute=\"top\" id=\"BDh-GK-opl\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"pVM-XW-ZVx\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"ENv-29-WoF\"/>\n                    <constraint firstItem=\"TsW-TI-bI2\" firstAttribute=\"trailing\" secondItem=\"mF8-Sh-jOJ\" secondAttribute=\"trailing\" id=\"ESY-ed-w0s\"/>\n                    <constraint firstItem=\"1aw-Cd-0bt\" firstAttribute=\"centerX\" secondItem=\"lgH-0C-2Hp\" secondAttribute=\"centerX\" id=\"F5L-rm-oO2\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"L3K-nW-f6P\" secondAttribute=\"trailing\" constant=\"20\" id=\"GFg-l4-f97\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Pju-DG-dA4\" secondAttribute=\"trailing\" constant=\"20\" id=\"LLd-xJ-Bs6\"/>\n                    <constraint firstItem=\"pVM-XW-ZVx\" firstAttribute=\"top\" secondItem=\"mF8-Sh-jOJ\" secondAttribute=\"bottom\" constant=\"28\" id=\"LvS-mh-P5Q\"/>\n                    <constraint firstItem=\"pVM-XW-ZVx\" firstAttribute=\"leading\" secondItem=\"c0p-OA-wsz\" secondAttribute=\"leading\" id=\"NLg-CW-YCF\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Pkh-by-JBm\" secondAttribute=\"trailing\" constant=\"20\" id=\"OTa-Ho-Fub\"/>\n                    <constraint firstItem=\"zyN-et-64I\" firstAttribute=\"trailing\" secondItem=\"TsW-TI-bI2\" secondAttribute=\"trailing\" id=\"Qff-lc-Nnh\"/>\n                    <constraint firstItem=\"48P-k9-e1x\" firstAttribute=\"top\" secondItem=\"1aw-Cd-0bt\" secondAttribute=\"bottom\" constant=\"2\" id=\"Txh-J6-1gd\"/>\n                    <constraint firstItem=\"L3K-nW-f6P\" firstAttribute=\"leading\" secondItem=\"Pju-DG-dA4\" secondAttribute=\"leading\" id=\"WA4-6Q-3hM\"/>\n                    <constraint firstItem=\"Pju-DG-dA4\" firstAttribute=\"leading\" secondItem=\"Z1G-AL-Ueu\" secondAttribute=\"trailing\" constant=\"20\" id=\"aFl-oo-e6c\"/>\n                    <constraint firstItem=\"c0p-OA-wsz\" firstAttribute=\"baseline\" secondItem=\"lgH-0C-2Hp\" secondAttribute=\"baseline\" id=\"cD0-lR-tDb\"/>\n                    <constraint firstItem=\"axo-nj-Ciz\" firstAttribute=\"top\" secondItem=\"48P-k9-e1x\" secondAttribute=\"bottom\" constant=\"2\" id=\"dAh-sp-aNT\"/>\n                    <constraint firstItem=\"Z1G-AL-Ueu\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"emp-TE-GWk\"/>\n                    <constraint firstItem=\"Pkh-by-JBm\" firstAttribute=\"leading\" secondItem=\"p3J-0n-RwH\" secondAttribute=\"trailing\" constant=\"12\" id=\"eoA-Su-JRu\"/>\n                    <constraint firstItem=\"zyN-et-64I\" firstAttribute=\"top\" secondItem=\"TsW-TI-bI2\" secondAttribute=\"bottom\" constant=\"12\" id=\"f6i-vf-1v3\"/>\n                    <constraint firstItem=\"1aw-Cd-0bt\" firstAttribute=\"top\" secondItem=\"lgH-0C-2Hp\" secondAttribute=\"bottom\" constant=\"2\" id=\"faW-Bc-rrZ\"/>\n                    <constraint firstItem=\"Pkh-by-JBm\" firstAttribute=\"top\" secondItem=\"zyN-et-64I\" secondAttribute=\"bottom\" constant=\"28\" id=\"kTs-JH-lt2\"/>\n                    <constraint firstItem=\"TsW-TI-bI2\" firstAttribute=\"leading\" secondItem=\"c0p-OA-wsz\" secondAttribute=\"leading\" id=\"m9s-cy-ZIl\"/>\n                    <constraint firstItem=\"48P-k9-e1x\" firstAttribute=\"leading\" secondItem=\"mF8-Sh-jOJ\" secondAttribute=\"leading\" id=\"nJ3-ek-YW5\"/>\n                    <constraint firstItem=\"p3J-0n-RwH\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"o3b-TT-m9b\"/>\n                    <constraint firstItem=\"c0p-OA-wsz\" firstAttribute=\"top\" secondItem=\"L3K-nW-f6P\" secondAttribute=\"bottom\" constant=\"28\" id=\"p9A-h0-1CL\"/>\n                    <constraint firstItem=\"c0p-OA-wsz\" firstAttribute=\"leading\" secondItem=\"L3K-nW-f6P\" secondAttribute=\"leading\" constant=\"16\" id=\"pbU-jX-080\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Pkh-by-JBm\" secondAttribute=\"bottom\" constant=\"20\" id=\"uSQ-zC-nMO\"/>\n                    <constraint firstItem=\"lgH-0C-2Hp\" firstAttribute=\"leading\" secondItem=\"48P-k9-e1x\" secondAttribute=\"leading\" id=\"yAU-R4-hOO\"/>\n                    <constraint firstItem=\"L3K-nW-f6P\" firstAttribute=\"top\" secondItem=\"Pju-DG-dA4\" secondAttribute=\"bottom\" constant=\"8\" id=\"yfk-FG-Ckh\"/>\n                    <constraint firstItem=\"Pkh-by-JBm\" firstAttribute=\"width\" secondItem=\"p3J-0n-RwH\" secondAttribute=\"width\" id=\"yoy-eI-Ug3\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"196.5\" y=\"109.5\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSApplicationIcon\" width=\"128\" height=\"128\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/GraphAxisRescaleSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"GraphView\">\n            <connections>\n                <outlet property=\"rescaleSheet\" destination=\"QvC-M9-y7g\" id=\"iGf-WO-CrD\"/>\n                <outlet property=\"rescaleSheetMajorIntervalTextfield\" destination=\"QwP-Ft-UJn\" id=\"Ca9-X3-T7M\"/>\n                <outlet property=\"rescaleSheetMaxTextfield\" destination=\"bCT-cz-zb6\" id=\"WUB-uT-WOe\"/>\n                <outlet property=\"rescaleSheetMinTextfield\" destination=\"RyO-8A-lUQ\" id=\"nRj-Z4-T2a\"/>\n                <outlet property=\"rescaleSheetMinorModulusTextfield\" destination=\"opo-AA-SKp\" id=\"3FJ-KE-z3L\"/>\n                <outlet property=\"rescaleSheetTickPrecisionTextfield\" destination=\"xdI-6R-qQx\" id=\"9uB-Vb-ehd\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"298\" height=\"262\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" misplaced=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"298\" height=\"262\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vca-7J-W4R\">\n                        <rect key=\"frame\" x=\"18\" y=\"225\" width=\"251\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"247\" id=\"gRS-iv-dJw\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Choose a configuration for the axis:\" id=\"SnA-AW-dLy\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L5X-37-E4y\">\n                        <rect key=\"frame\" x=\"43\" y=\"183\" width=\"101\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"97\" id=\"WOn-ec-wVR\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Minimum value:\" id=\"i3l-FR-WoS\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RyO-8A-lUQ\">\n                        <rect key=\"frame\" x=\"182\" y=\"181\" width=\"96\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"1000000000\" drawsBackground=\"YES\" id=\"WiW-ch-7g5\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"4\" id=\"a5i-Jn-8T8\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"spN-cW-ouk\">\n                        <rect key=\"frame\" x=\"43\" y=\"155\" width=\"105\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"101\" id=\"hBc-Oa-H5W\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Maximum value:\" id=\"ZJt-HI-cEk\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bCT-cz-zb6\">\n                        <rect key=\"frame\" x=\"182\" y=\"153\" width=\"96\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"1000000000\" drawsBackground=\"YES\" id=\"Sxp-et-bz5\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"4\" id=\"z3I-es-r7g\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FgM-D6-wRd\">\n                        <rect key=\"frame\" x=\"43\" y=\"127\" width=\"118\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"114\" id=\"gII-a8-PEx\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Major tick interval:\" id=\"ule-e1-72g\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sSf-Vc-fEZ\">\n                        <rect key=\"frame\" x=\"43\" y=\"99\" width=\"127\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"123\" id=\"jHB-MR-wuQ\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Minor tick divisions:\" id=\"TVk-hl-r1D\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QwP-Ft-UJn\">\n                        <rect key=\"frame\" x=\"182\" y=\"125\" width=\"96\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"1000000000\" drawsBackground=\"YES\" id=\"g5f-yE-KYJ\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"4\" id=\"eSg-2L-IL6\">\n                                <real key=\"minimum\" value=\"9.9999999999999995e-08\"/>\n                            </numberFormatter>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"opo-AA-SKp\">\n                        <rect key=\"frame\" x=\"182\" y=\"97\" width=\"96\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"96\" id=\"HMy-B0-hUD\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"10\" drawsBackground=\"YES\" id=\"lQv-of-zI1\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" allowsFloats=\"NO\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"4\" id=\"4gF-sB-aMH\">\n                                <real key=\"minimum\" value=\"1\"/>\n                                <real key=\"maximum\" value=\"10\"/>\n                            </numberFormatter>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3Z5-BW-GqJ\">\n                        <rect key=\"frame\" x=\"201\" y=\"13\" width=\"83\" height=\"32\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"71\" id=\"eAN-oq-YL2\"/>\n                        </constraints>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"OK\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Pq9-we-hp7\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"rescaleSheetOK:\" target=\"-2\" id=\"ebe-yJ-Qp3\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jRg-v5-FGY\">\n                        <rect key=\"frame\" x=\"118\" y=\"13\" width=\"83\" height=\"32\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"71\" id=\"zg5-O5-Gl4\"/>\n                        </constraints>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"80q-fw-0sd\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"rescaleSheetCancel:\" target=\"-2\" id=\"g0u-aX-ndS\"/>\n                        </connections>\n                    </button>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"64d-ID-bmZ\">\n                        <rect key=\"frame\" x=\"43\" y=\"71\" width=\"127\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"123\" id=\"gOj-9u-dEB\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Tick label precision:\" id=\"V6L-MC-qrF\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xdI-6R-qQx\">\n                        <rect key=\"frame\" x=\"182\" y=\"69\" width=\"96\" height=\"22\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"10\" drawsBackground=\"YES\" id=\"SLi-iW-wsp\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" allowsFloats=\"NO\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"4\" id=\"oO2-oE-ZME\">\n                                <real key=\"minimum\" value=\"0.0\"/>\n                                <real key=\"maximum\" value=\"5\"/>\n                            </numberFormatter>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"bCT-cz-zb6\" firstAttribute=\"trailing\" secondItem=\"QwP-Ft-UJn\" secondAttribute=\"trailing\" id=\"21p-kB-111\"/>\n                    <constraint firstItem=\"RyO-8A-lUQ\" firstAttribute=\"baseline\" secondItem=\"L5X-37-E4y\" secondAttribute=\"baseline\" id=\"4NV-16-JGP\"/>\n                    <constraint firstItem=\"sSf-Vc-fEZ\" firstAttribute=\"top\" secondItem=\"FgM-D6-wRd\" secondAttribute=\"bottom\" constant=\"11\" id=\"7jN-6z-0lB\"/>\n                    <constraint firstItem=\"spN-cW-ouk\" firstAttribute=\"baseline\" secondItem=\"bCT-cz-zb6\" secondAttribute=\"baseline\" id=\"8fI-dk-TQN\"/>\n                    <constraint firstItem=\"QwP-Ft-UJn\" firstAttribute=\"width\" secondItem=\"bCT-cz-zb6\" secondAttribute=\"width\" id=\"8h6-QR-nkC\"/>\n                    <constraint firstItem=\"3Z5-BW-GqJ\" firstAttribute=\"leading\" secondItem=\"jRg-v5-FGY\" secondAttribute=\"trailing\" constant=\"12\" id=\"AeW-HM-Zvz\"/>\n                    <constraint firstItem=\"spN-cW-ouk\" firstAttribute=\"top\" secondItem=\"L5X-37-E4y\" secondAttribute=\"bottom\" constant=\"11\" id=\"BMI-FS-uix\"/>\n                    <constraint firstItem=\"opo-AA-SKp\" firstAttribute=\"leading\" secondItem=\"sSf-Vc-fEZ\" secondAttribute=\"trailing\" constant=\"14\" id=\"CpS-qE-haT\"/>\n                    <constraint firstItem=\"L5X-37-E4y\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"45\" id=\"DNK-wD-Ba9\"/>\n                    <constraint firstItem=\"vca-7J-W4R\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"DTj-h3-ckA\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"opo-AA-SKp\" secondAttribute=\"trailing\" constant=\"20\" id=\"FhQ-qg-vj6\"/>\n                    <constraint firstItem=\"xdI-6R-qQx\" firstAttribute=\"width\" secondItem=\"opo-AA-SKp\" secondAttribute=\"width\" id=\"GpS-iq-g0d\"/>\n                    <constraint firstItem=\"vca-7J-W4R\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"H3N-FN-9HJ\"/>\n                    <constraint firstItem=\"xdI-6R-qQx\" firstAttribute=\"leading\" secondItem=\"64d-ID-bmZ\" secondAttribute=\"trailing\" constant=\"14\" id=\"K36-mX-zUx\"/>\n                    <constraint firstItem=\"opo-AA-SKp\" firstAttribute=\"trailing\" secondItem=\"QwP-Ft-UJn\" secondAttribute=\"trailing\" id=\"LBT-Xn-H2H\"/>\n                    <constraint firstItem=\"xdI-6R-qQx\" firstAttribute=\"top\" secondItem=\"opo-AA-SKp\" secondAttribute=\"bottom\" constant=\"6\" id=\"MyX-Y7-9oi\"/>\n                    <constraint firstItem=\"jRg-v5-FGY\" firstAttribute=\"bottom\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"bottom\" id=\"OXE-vs-9Mc\"/>\n                    <constraint firstItem=\"RyO-8A-lUQ\" firstAttribute=\"width\" secondItem=\"bCT-cz-zb6\" secondAttribute=\"width\" id=\"Q5w-rt-ZxK\"/>\n                    <constraint firstItem=\"xdI-6R-qQx\" firstAttribute=\"baseline\" secondItem=\"64d-ID-bmZ\" secondAttribute=\"baseline\" id=\"Rhj-jl-PQV\"/>\n                    <constraint firstItem=\"sSf-Vc-fEZ\" firstAttribute=\"leading\" secondItem=\"FgM-D6-wRd\" secondAttribute=\"leading\" id=\"Soy-BV-JRj\"/>\n                    <constraint firstItem=\"FgM-D6-wRd\" firstAttribute=\"baseline\" secondItem=\"QwP-Ft-UJn\" secondAttribute=\"baseline\" id=\"Wro-qa-Kfy\"/>\n                    <constraint firstItem=\"L5X-37-E4y\" firstAttribute=\"top\" secondItem=\"vca-7J-W4R\" secondAttribute=\"bottom\" constant=\"25\" id=\"X37-V5-Kcr\"/>\n                    <constraint firstItem=\"spN-cW-ouk\" firstAttribute=\"leading\" secondItem=\"L5X-37-E4y\" secondAttribute=\"leading\" id=\"Ybj-8L-JXn\"/>\n                    <constraint firstItem=\"sSf-Vc-fEZ\" firstAttribute=\"leading\" secondItem=\"64d-ID-bmZ\" secondAttribute=\"leading\" id=\"Zno-Bc-cpe\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"trailing\" constant=\"20\" id=\"b7V-5K-lCr\"/>\n                    <constraint firstItem=\"opo-AA-SKp\" firstAttribute=\"width\" secondItem=\"QwP-Ft-UJn\" secondAttribute=\"width\" id=\"dvG-NQ-tQH\"/>\n                    <constraint firstItem=\"FgM-D6-wRd\" firstAttribute=\"top\" secondItem=\"spN-cW-ouk\" secondAttribute=\"bottom\" constant=\"11\" id=\"eGD-Bd-VcD\"/>\n                    <constraint firstItem=\"spN-cW-ouk\" firstAttribute=\"leading\" secondItem=\"FgM-D6-wRd\" secondAttribute=\"leading\" id=\"oVZ-A6-yLj\"/>\n                    <constraint firstItem=\"opo-AA-SKp\" firstAttribute=\"baseline\" secondItem=\"sSf-Vc-fEZ\" secondAttribute=\"baseline\" id=\"okq-xP-1Ut\"/>\n                    <constraint firstItem=\"3Z5-BW-GqJ\" firstAttribute=\"top\" secondItem=\"xdI-6R-qQx\" secondAttribute=\"bottom\" constant=\"28\" id=\"ox1-QS-g3c\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"skY-bW-Lsw\"/>\n                    <constraint firstItem=\"64d-ID-bmZ\" firstAttribute=\"top\" secondItem=\"sSf-Vc-fEZ\" secondAttribute=\"bottom\" constant=\"11\" id=\"toH-Dg-Vah\"/>\n                    <constraint firstItem=\"RyO-8A-lUQ\" firstAttribute=\"trailing\" secondItem=\"bCT-cz-zb6\" secondAttribute=\"trailing\" id=\"vPP-Du-nce\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"958\" y=\"676\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/GraphBarRescaleSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16G29\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"GraphView\">\n            <connections>\n                <outlet property=\"rescaleBarsSheet\" destination=\"QvC-M9-y7g\" id=\"uQf-ua-opJ\"/>\n                <outlet property=\"rescaleBarsSheetCountTextfield\" destination=\"RyO-8A-lUQ\" id=\"WtQ-kx-PbC\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"232\" height=\"168\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1057\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"232\" height=\"168\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vca-7J-W4R\">\n                        <rect key=\"frame\" x=\"18\" y=\"131\" width=\"134\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Choose a bar count:\" id=\"SnA-AW-dLy\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L5X-37-E4y\">\n                        <rect key=\"frame\" x=\"43\" y=\"89\" width=\"101\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"97\" id=\"WOn-ec-wVR\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Bar count:\" id=\"i3l-FR-WoS\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RyO-8A-lUQ\">\n                        <rect key=\"frame\" x=\"142\" y=\"86\" width=\"70\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"70\" id=\"WiP-7I-x9u\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"100\" drawsBackground=\"YES\" id=\"WiW-ch-7g5\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" numberStyle=\"decimal\" allowsFloats=\"NO\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"10000\" maximumFractionDigits=\"4\" id=\"a5i-Jn-8T8\">\n                                <real key=\"minimum\" value=\"1\"/>\n                                <real key=\"maximum\" value=\"10000\"/>\n                            </numberFormatter>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3Z5-BW-GqJ\">\n                        <rect key=\"frame\" x=\"135\" y=\"13\" width=\"83\" height=\"32\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"71\" id=\"eAN-oq-YL2\"/>\n                        </constraints>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"OK\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Pq9-we-hp7\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"rescaleBarSheetOK:\" target=\"-2\" id=\"Kgq-sw-zXr\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jRg-v5-FGY\">\n                        <rect key=\"frame\" x=\"52\" y=\"13\" width=\"83\" height=\"32\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"71\" id=\"zg5-O5-Gl4\"/>\n                        </constraints>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"80q-fw-0sd\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"rescaleBarSheetCancel:\" target=\"-2\" id=\"gYK-0l-Tsn\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"RyO-8A-lUQ\" firstAttribute=\"baseline\" secondItem=\"L5X-37-E4y\" secondAttribute=\"baseline\" id=\"4NV-16-JGP\"/>\n                    <constraint firstItem=\"3Z5-BW-GqJ\" firstAttribute=\"top\" secondItem=\"RyO-8A-lUQ\" secondAttribute=\"bottom\" constant=\"45\" id=\"4RO-eb-oGB\"/>\n                    <constraint firstItem=\"3Z5-BW-GqJ\" firstAttribute=\"leading\" secondItem=\"jRg-v5-FGY\" secondAttribute=\"trailing\" constant=\"12\" id=\"AeW-HM-Zvz\"/>\n                    <constraint firstItem=\"L5X-37-E4y\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"45\" id=\"DNK-wD-Ba9\"/>\n                    <constraint firstItem=\"vca-7J-W4R\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"DTj-h3-ckA\"/>\n                    <constraint firstItem=\"vca-7J-W4R\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"H3N-FN-9HJ\"/>\n                    <constraint firstItem=\"jRg-v5-FGY\" firstAttribute=\"bottom\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"bottom\" id=\"OXE-vs-9Mc\"/>\n                    <constraint firstItem=\"L5X-37-E4y\" firstAttribute=\"top\" secondItem=\"vca-7J-W4R\" secondAttribute=\"bottom\" constant=\"25\" id=\"X37-V5-Kcr\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"trailing\" constant=\"20\" id=\"b7V-5K-lCr\"/>\n                    <constraint firstItem=\"RyO-8A-lUQ\" firstAttribute=\"leading\" secondItem=\"L5X-37-E4y\" secondAttribute=\"trailing\" id=\"mgH-aY-8LC\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"3Z5-BW-GqJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"skY-bW-Lsw\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"RyO-8A-lUQ\" secondAttribute=\"trailing\" constant=\"20\" id=\"tAo-jJ-jWR\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"958\" y=\"676\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/GraphWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"SLiMWindowController\">\n            <connections>\n                <outlet property=\"graphWindow\" destination=\"QvC-M9-y7g\" id=\"mRM-bL-YbH\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Graph\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" hidesOnDeactivate=\"YES\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\" utility=\"YES\" nonactivatingPanel=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" rightStrut=\"YES\" topStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"2217\" y=\"1250\" width=\"300\" height=\"300\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <value key=\"minSize\" type=\"size\" width=\"250\" height=\"250\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"300\" height=\"300\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"HKp-7A-xuM\"/>\n            </connections>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/HelpWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n        <plugIn identifier=\"com.apple.pdfkit.ibplugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"AppDelegate\">\n            <connections>\n                <outlet property=\"helpPDFView\" destination=\"UsV-kh-X2r\" id=\"VDp-Ga-aan\"/>\n                <outlet property=\"helpWindow\" destination=\"QvC-M9-y7g\" id=\"x1T-ey-mh6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"SLiM Manual\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"846\" height=\"693\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"846\" height=\"693\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <pdfView autoresizesSubviews=\"NO\" wantsLayer=\"YES\" autoScales=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UsV-kh-X2r\" userLabel=\"ManualView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"846\" height=\"693\"/>\n                    </pdfView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"UsV-kh-X2r\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" id=\"4BL-iO-FU1\"/>\n                    <constraint firstItem=\"UsV-kh-X2r\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" id=\"4SE-jJ-hfj\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"UsV-kh-X2r\" secondAttribute=\"trailing\" id=\"Jda-xh-lpq\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"UsV-kh-X2r\" secondAttribute=\"bottom\" id=\"x29-lt-Swj\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"734\" y=\"477.5\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"22505\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"SLiMApp\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\">\n            <connections>\n                <outlet property=\"openRecipesMenu\" destination=\"mx1-xb-Nlg\" id=\"pqJ-4r-4yQ\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"838-4t-D39\" userLabel=\"SLiM Document Controller\" customClass=\"SLiMDocumentController\"/>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"SLiMguiLegacy\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"SLiMguiLegacy\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About SLiMguiLegacy\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showAboutWindow:\" target=\"Voe-Tx-rLC\" id=\"F92-YX-t7y\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\">\n                                <connections>\n                                    <action selector=\"makeKeyAndOrderFront:\" target=\"cET-rW-zho\" id=\"ksB-YE-yaE\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide SLiMguiLegacy\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit SLiMguiLegacy\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                        <items>\n                            <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                <connections>\n                                    <action selector=\"newDocument:\" target=\"-1\" id=\"4Si-XN-c54\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"New (nonWF)\" keyEquivalent=\"N\" id=\"LKX-cu-Eht\">\n                                <connections>\n                                    <action selector=\"newNonWFDocument:\" target=\"-1\" id=\"lcJ-f9-qvh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                <connections>\n                                    <action selector=\"openDocument:\" target=\"-1\" id=\"bVn-NM-KNZ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                    <items>\n                                        <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"clearRecentDocuments:\" target=\"-1\" id=\"Daa-9d-B3U\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Open Recipe\" id=\"Nuz-hf-1eb\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Open Recipe\" id=\"mx1-xb-Nlg\">\n                                    <items>\n                                        <menuItem title=\"Item\" id=\"dEH-0s-iT4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                            <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                <connections>\n                                    <action selector=\"performClose:\" target=\"-1\" id=\"HmO-Ls-i7Q\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"FOH-MY-HoQ\">\n                                <connections>\n                                    <action selector=\"saveDocument:\" target=\"-1\" id=\"nmz-Mk-g6b\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Mba-jh-XE9\">\n                                <connections>\n                                    <action selector=\"saveDocumentAs:\" target=\"-1\" id=\"Vow-xY-MZe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"fZ7-ye-Fv9\">\n                                <connections>\n                                    <action selector=\"revertDocumentToSaved:\" target=\"-1\" id=\"tJQ-op-CyX\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"gwe-3i-esM\"/>\n                            <menuItem title=\"Export Script...\" id=\"gMO-ZD-eo1\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"exportScript:\" target=\"-1\" id=\"OIF-da-O99\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Export Output...\" id=\"HJb-0L-PzV\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"exportOutput:\" target=\"-1\" id=\"oa4-mp-Id1\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                            <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"runPageLayout:\" target=\"-1\" id=\"Din-rz-gC5\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                <connections>\n                                    <action selector=\"print:\" target=\"-1\" id=\"qaZ-4w-aoO\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy As Paragraph\" alternate=\"YES\" keyEquivalent=\"c\" id=\"aCf-e4-BZo\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"copyAsParagraph:\" target=\"-1\" id=\"kFH-Em-nAI\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cD7-Qs-BN4\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"NDo-RZ-v9R\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"HOh-sY-3ay\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4xB-3z-IfV\"/>\n                            <menuItem title=\"Shift Left\" keyEquivalent=\"[\" id=\"xnc-5H-dp6\">\n                                <connections>\n                                    <action selector=\"shiftSelectionLeft:\" target=\"-1\" id=\"FuZ-kl-yoZ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Shift Right\" keyEquivalent=\"]\" id=\"9Sz-1z-S4Y\">\n                                <connections>\n                                    <action selector=\"shiftSelectionRight:\" target=\"-1\" id=\"Ti2-BW-a7D\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Comment / Uncomment\" keyEquivalent=\"/\" id=\"qeL-Wf-K5w\">\n                                <connections>\n                                    <action selector=\"commentUncommentSelection:\" target=\"-1\" id=\"HoO-wP-OdZ\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Simulation\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Simulation\" id=\"lGi-Wg-1SI\">\n                        <items>\n                            <menuItem title=\"Step\" keyEquivalent=\"\" id=\"C9p-mA-fVt\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"playOneStep:\" target=\"-1\" id=\"SjN-uK-tIt\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Play\" keyEquivalent=\"\" id=\"EyD-tq-95A\">\n                                <connections>\n                                    <action selector=\"play:\" target=\"-1\" id=\"AGn-8l-Bub\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Profile\" id=\"m8l-Qj-poH\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"profile:\" target=\"-1\" id=\"aA4-H4-VS2\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Recycle\" keyEquivalent=\"\" id=\"MtH-g3-zh4\">\n                                <connections>\n                                    <action selector=\"recycle:\" target=\"-1\" id=\"Jo1-Sx-pAg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"0Gd-Zb-sPj\"/>\n                            <menuItem title=\"Change Working Directory...\" id=\"acZ-a2-D3c\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"changeWorkingDirectory:\" target=\"-1\" id=\"CFg-Tr-6bV\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"RrU-a1-ejQ\"/>\n                            <menuItem title=\"Graph Mutation Frequency Spectrum\" id=\"FSt-J5-XHJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphMutationFrequencySpectrum:\" target=\"-1\" id=\"LYQ-tN-PAb\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Graph Mutation Frequency Trajectories\" id=\"Srz-OG-dXi\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphMutationFrequencyTrajectories:\" target=\"-1\" id=\"y1p-AO-MeW\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Graph Mutation Loss Time Histogram\" id=\"it8-Wc-Cdo\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphMutationLossTimeHistogram:\" target=\"-1\" id=\"ap5-sJ-NXp\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Graph Mutation Fixation Time Histogram\" id=\"IK3-Na-aV4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphMutationFixationTimeHistogram:\" target=\"-1\" id=\"MV9-Od-bJH\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Graph Fitness ~ Time\" id=\"EEv-Te-bqv\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphFitnessOverTime:\" target=\"-1\" id=\"fnL-UF-XS8\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Graph Population Visualization\" id=\"QMY-a7-PG1\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"graphPopulationVisualization:\" target=\"-1\" id=\"yhD-GA-1K7\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"y3S-hm-vJt\"/>\n                            <menuItem title=\"Dump Population State\" keyEquivalent=\"\" id=\"7LZ-Ir-BDL\">\n                                <connections>\n                                    <action selector=\"dumpPopulationToOutput:\" target=\"-1\" id=\"V9u-uo-yiz\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Script\" id=\"dw5-Kx-j6q\" userLabel=\"Script\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Script\" id=\"tqb-Wc-Wzy\">\n                        <items>\n                            <menuItem title=\"Check Script\" keyEquivalent=\"=\" id=\"6iN-PX-KmV\">\n                                <connections>\n                                    <action selector=\"checkScript:\" target=\"-1\" id=\"3hw-Wc-h8c\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Prettyprint Script\" keyEquivalent=\"=\" id=\"JuO-il-2gw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"prettyprintScript:\" target=\"-1\" id=\"Gp8-NU-SBY\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show Script Help\" id=\"u9S-Gc-HU7\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showScriptHelp:\" target=\"-1\" id=\"93p-9I-4d4\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"sQb-7H-9SD\"/>\n                            <menuItem title=\"Show Variable Browser\" keyEquivalent=\"b\" id=\"L7T-eW-32O\">\n                                <connections>\n                                    <action selector=\"toggleBrowserVisibility:\" target=\"-1\" id=\"aec-EB-Oib\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show Eidos Console\" keyEquivalent=\"E\" id=\"FdT-5U-1HN\">\n                                <connections>\n                                    <action selector=\"toggleConsoleVisibility:\" target=\"-1\" id=\"OkK-Io-4ij\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"HGB-qg-Jeh\"/>\n                            <menuItem title=\"Clear Output\" keyEquivalent=\"k\" id=\"Oi2-aT-uau\">\n                                <connections>\n                                    <action selector=\"clearOutput:\" target=\"-1\" id=\"vEb-WY-99A\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"aHz-1a-shY\"/>\n                            <menuItem title=\"Execute Selection\" id=\"c4h-gc-RSR\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                                <connections>\n                                    <action selector=\"executeSelection:\" target=\"-1\" id=\"kOR-ZG-Zu9\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Execute All\" id=\"2SN-ZE-qHc\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"executeAll:\" target=\"-1\" id=\"CXc-6D-hgz\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"bkY-ut-fvs\"/>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"d9X-fb-9Kh\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"B01-9u-yA0\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                        <items>\n                            <menuItem title=\"SLiMguiLegacy Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                <connections>\n                                    <action selector=\"showHelp:\" target=\"Voe-Tx-rLC\" id=\"1Sw-II-Pnj\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"SLiM Workshops\" id=\"yub-Vr-tTZ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"slimWorkshops:\" target=\"Voe-Tx-rLC\" id=\"NP1-Ma-HXd\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"akG-Ew-mj0\"/>\n                            <menuItem title=\"Send Feedback on SLiM\" id=\"op4-ap-h8O\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"sendFeedback:\" target=\"Voe-Tx-rLC\" id=\"fZs-8U-H1X\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Mailing List: slim-announce\" id=\"0z5-95-PGp\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"mailingListAnnounce:\" target=\"Voe-Tx-rLC\" id=\"2mT-z1-X0Z\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Mailing List: slim-discuss\" id=\"P55-d4-Gg2\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"mailingListDiscuss:\" target=\"Voe-Tx-rLC\" id=\"7sc-gc-PXU\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"iTy-zx-Yi2\"/>\n                            <menuItem title=\"SLiM Home Page\" id=\"vIK-TB-KPI\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showSlimHomePage:\" target=\"Voe-Tx-rLC\" id=\"R8x-VO-uO1\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"SLiM-Extras on GitHub\" id=\"MLQ-w3-xwG\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showSlimExtrasPage:\" target=\"Voe-Tx-rLC\" id=\"bE2-8U-QpS\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Haller &amp; Messer 2017 MBE\" id=\"9r1-EZ-j3E\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showSlimPublication:\" target=\"Voe-Tx-rLC\" id=\"vFg-ZU-Q56\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About the Messer Lab\" id=\"AGL-3n-d6g\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showMesserLab:\" target=\"Voe-Tx-rLC\" id=\"g28-5s-ZAa\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About Ben Haller\" id=\"DnV-Km-JKi\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showBenHaller:\" target=\"Voe-Tx-rLC\" id=\"tcc-jV-hEH\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"About Stick Software\" id=\"HY8-Fb-dK8\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showStickSoftware:\" target=\"Voe-Tx-rLC\" id=\"zWX-XV-w92\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"-258\" y=\"-504\"/>\n        </menu>\n        <window title=\"SLiMguiLegacy Preferences\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" hidesOnDeactivate=\"YES\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"cET-rW-zho\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"272\" y=\"199\" width=\"268\" height=\"431\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1728\" height=\"1079\"/>\n            <view key=\"contentView\" id=\"ae8-oN-lQF\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"268\" height=\"431\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pFc-cT-SJr\">\n                        <rect key=\"frame\" x=\"32\" y=\"205\" width=\"128\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"In the script area\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"9pj-Hb-YGA\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.SyntaxHighlightScript\" id=\"E5P-Jd-Zih\"/>\n                        </connections>\n                    </button>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LNo-up-hn1\">\n                        <rect key=\"frame\" x=\"32\" y=\"183\" width=\"134\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"In the output area\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"ihE-H7-bQ0\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.SyntaxHighlightOutput\" id=\"bnx-Hd-3Wk\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PHC-Yj-PFy\">\n                        <rect key=\"frame\" x=\"18\" y=\"230\" width=\"180\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Enable syntax highlighting:\" id=\"oD3-D6-zvA\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VCf-DB-Pyy\">\n                        <rect key=\"frame\" x=\"18\" y=\"293\" width=\"115\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Display font size:\" id=\"A2o-Lb-mVo\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2D7-na-mil\">\n                        <rect key=\"frame\" x=\"13\" y=\"55\" width=\"242\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Reset suppressed alert panels\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"BiX-hI-4aP\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"resetSuppressionFlags:\" target=\"Voe-Tx-rLC\" id=\"sy4-nE-cpj\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eMc-AI-9kI\">\n                        <rect key=\"frame\" x=\"40\" y=\"20\" width=\"197\" height=\"34\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"193\" id=\"aqY-r4-K0p\"/>\n                            <constraint firstAttribute=\"height\" constant=\"34\" id=\"n6Z-vi-0Wq\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"This resets all of the &quot;do not show this message again&quot; flags across SLiMgui.\" id=\"4ej-zf-A5j\">\n                            <font key=\"font\" size=\"11\" name=\"HelveticaNeue-Italic\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6sR-dN-vyi\">\n                        <rect key=\"frame\" x=\"18\" y=\"148\" width=\"195\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"When checking script syntax:\" id=\"GjS-PY-od2\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eGw-cr-yvD\">\n                        <rect key=\"frame\" x=\"32\" y=\"123\" width=\"164\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Play sound on success\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"3e1-wW-7r7\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.PlaySoundParseSuccess\" id=\"9mA-T4-sK2\"/>\n                        </connections>\n                    </button>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A87-L1-NNH\">\n                        <rect key=\"frame\" x=\"32\" y=\"101\" width=\"152\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Play sound on failure\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"tjb-mF-4Z6\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.PlaySoundParseFailure\" id=\"ol0-B0-hQe\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Yf-hO-IoP\">\n                        <rect key=\"frame\" x=\"18\" y=\"395\" width=\"189\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"When SLiMguiLegacy starts:\" id=\"dL6-Sg-GED\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <matrix verticalHuggingPriority=\"750\" allowsEmptySelection=\"NO\" autorecalculatesCellSize=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gPW-po-YSE\">\n                        <rect key=\"frame\" x=\"33\" y=\"329\" width=\"213\" height=\"58\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <size key=\"cellSize\" width=\"213\" height=\"18\"/>\n                        <size key=\"intercellSpacing\" width=\"4\" height=\"2\"/>\n                        <buttonCell key=\"prototype\" type=\"radio\" title=\"Radio\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"UXn-kw-QHE\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <cells>\n                            <column>\n                                <buttonCell type=\"radio\" title=\"Do nothing\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"38J-Rc-60d\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <buttonCell type=\"radio\" title=\"Open a new simulation window\" imagePosition=\"left\" alignment=\"left\" tag=\"1\" inset=\"2\" id=\"KVC-1D-Pzo\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <buttonCell type=\"radio\" title=\"Ask for a script file to open\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"z53-pF-XCf\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                            </column>\n                        </cells>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"selectedTag\" keyPath=\"values.LaunchAction\" id=\"lOC-BL-9zx\"/>\n                        </connections>\n                    </matrix>\n                    <stepper horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fUY-QK-PRE\">\n                        <rect key=\"frame\" x=\"64\" y=\"259\" width=\"19\" height=\"28\"/>\n                        <stepperCell key=\"cell\" continuous=\"YES\" alignment=\"left\" minValue=\"9\" maxValue=\"30\" doubleValue=\"11\" id=\"CFF-pU-pUU\"/>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.DisplayFontSize\" id=\"lde-VA-Uvc\"/>\n                        </connections>\n                    </stepper>\n                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KpB-tT-jSj\">\n                        <rect key=\"frame\" x=\"85\" y=\"266\" width=\"42\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"points\" id=\"E9s-Wo-eYy\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" textCompletion=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1i1-DN-XAq\">\n                        <rect key=\"frame\" x=\"34\" y=\"263\" width=\"30\" height=\"21\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"30\" id=\"vBs-sL-kPy\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"wIq-Lp-aN0\">\n                            <numberFormatter key=\"formatter\" formatterBehavior=\"default10_4\" numberStyle=\"decimal\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"3\" id=\"tJt-EI-o9d\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <connections>\n                            <binding destination=\"sPi-91-YoN\" name=\"value\" keyPath=\"values.DisplayFontSize\" id=\"QoX-3F-08Q\"/>\n                        </connections>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"eMc-AI-9kI\" firstAttribute=\"top\" secondItem=\"2D7-na-mil\" secondAttribute=\"bottom\" constant=\"8\" id=\"3LG-8M-ZXe\"/>\n                    <constraint firstItem=\"PHC-Yj-PFy\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"20\" id=\"7cj-vA-vdn\"/>\n                    <constraint firstItem=\"pFc-cT-SJr\" firstAttribute=\"leading\" secondItem=\"PHC-Yj-PFy\" secondAttribute=\"leading\" constant=\"14\" id=\"95H-c3-iHx\"/>\n                    <constraint firstItem=\"fUY-QK-PRE\" firstAttribute=\"bottom\" secondItem=\"1i1-DN-XAq\" secondAttribute=\"bottom\" id=\"9ZI-XU-yi6\"/>\n                    <constraint firstItem=\"1Yf-hO-IoP\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"20\" id=\"Ck3-6q-awX\"/>\n                    <constraint firstItem=\"2D7-na-mil\" firstAttribute=\"top\" secondItem=\"A87-L1-NNH\" secondAttribute=\"bottom\" constant=\"20\" id=\"DQj-gB-iJO\"/>\n                    <constraint firstItem=\"eMc-AI-9kI\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"42\" id=\"EbN-xR-7ba\"/>\n                    <constraint firstItem=\"gPW-po-YSE\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"33\" id=\"Eep-LB-BE6\"/>\n                    <constraint firstItem=\"1i1-DN-XAq\" firstAttribute=\"leading\" secondItem=\"VCf-DB-Pyy\" secondAttribute=\"leading\" constant=\"14\" id=\"ISe-jE-8Al\"/>\n                    <constraint firstItem=\"fUY-QK-PRE\" firstAttribute=\"leading\" secondItem=\"1i1-DN-XAq\" secondAttribute=\"trailing\" constant=\"3\" id=\"JCD-Ov-r5D\"/>\n                    <constraint firstItem=\"LNo-up-hn1\" firstAttribute=\"top\" secondItem=\"pFc-cT-SJr\" secondAttribute=\"bottom\" constant=\"6\" id=\"MRq-3j-fVb\"/>\n                    <constraint firstItem=\"KpB-tT-jSj\" firstAttribute=\"baseline\" secondItem=\"1i1-DN-XAq\" secondAttribute=\"baseline\" id=\"Skw-iC-nXY\"/>\n                    <constraint firstItem=\"1Yf-hO-IoP\" firstAttribute=\"top\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"top\" constant=\"20\" id=\"WSw-eo-ddk\"/>\n                    <constraint firstItem=\"pFc-cT-SJr\" firstAttribute=\"leading\" secondItem=\"LNo-up-hn1\" secondAttribute=\"leading\" id=\"WhB-aX-WW0\"/>\n                    <constraint firstItem=\"6sR-dN-vyi\" firstAttribute=\"top\" secondItem=\"LNo-up-hn1\" secondAttribute=\"bottom\" constant=\"20\" id=\"XCj-lM-31Q\"/>\n                    <constraint firstItem=\"VCf-DB-Pyy\" firstAttribute=\"top\" secondItem=\"gPW-po-YSE\" secondAttribute=\"bottom\" constant=\"20\" id=\"cM4-UJ-IjF\"/>\n                    <constraint firstItem=\"eGw-cr-yvD\" firstAttribute=\"top\" secondItem=\"6sR-dN-vyi\" secondAttribute=\"bottom\" constant=\"8\" id=\"dc2-AF-tIw\"/>\n                    <constraint firstItem=\"1i1-DN-XAq\" firstAttribute=\"top\" secondItem=\"VCf-DB-Pyy\" secondAttribute=\"bottom\" constant=\"9\" id=\"dmR-HJ-Jbu\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"2D7-na-mil\" secondAttribute=\"trailing\" constant=\"20\" id=\"eHu-2w-eC4\"/>\n                    <constraint firstItem=\"2D7-na-mil\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"20\" id=\"f0O-dg-uSc\"/>\n                    <constraint firstItem=\"A87-L1-NNH\" firstAttribute=\"top\" secondItem=\"eGw-cr-yvD\" secondAttribute=\"bottom\" constant=\"6\" id=\"gmv-w9-7UO\"/>\n                    <constraint firstItem=\"pFc-cT-SJr\" firstAttribute=\"top\" secondItem=\"PHC-Yj-PFy\" secondAttribute=\"bottom\" constant=\"8\" id=\"j1L-jL-oIZ\"/>\n                    <constraint firstItem=\"VCf-DB-Pyy\" firstAttribute=\"leading\" secondItem=\"1Yf-hO-IoP\" secondAttribute=\"leading\" id=\"jb9-qH-XSS\"/>\n                    <constraint firstItem=\"KpB-tT-jSj\" firstAttribute=\"leading\" secondItem=\"fUY-QK-PRE\" secondAttribute=\"trailing\" constant=\"7\" id=\"lVS-zL-gOV\"/>\n                    <constraint firstItem=\"eGw-cr-yvD\" firstAttribute=\"leading\" secondItem=\"A87-L1-NNH\" secondAttribute=\"leading\" id=\"lco-jM-7rK\"/>\n                    <constraint firstItem=\"gPW-po-YSE\" firstAttribute=\"top\" secondItem=\"1Yf-hO-IoP\" secondAttribute=\"bottom\" constant=\"8\" id=\"mIa-h9-UNi\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"eMc-AI-9kI\" secondAttribute=\"bottom\" constant=\"20\" id=\"qA1-y5-R1v\"/>\n                    <constraint firstItem=\"6sR-dN-vyi\" firstAttribute=\"leading\" secondItem=\"ae8-oN-lQF\" secondAttribute=\"leading\" constant=\"20\" id=\"uKX-UX-cJz\"/>\n                    <constraint firstItem=\"eGw-cr-yvD\" firstAttribute=\"leading\" secondItem=\"6sR-dN-vyi\" secondAttribute=\"leading\" constant=\"14\" id=\"v6l-li-kBs\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"2220\" y=\"1276.5\"/>\n        </window>\n        <userDefaultsController representsSharedInstance=\"YES\" id=\"sPi-91-YoN\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ProfileReport.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16E195\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"SLiMWindowController\">\n            <connections>\n                <outlet property=\"profileTextView\" destination=\"so4-Sh-6Yc\" id=\"NxI-u6-xMm\"/>\n                <outlet property=\"profileWindow\" destination=\"xGd-2i-Ejv\" id=\"JYE-K7-cBr\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Profile Report\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"xGd-2i-Ejv\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"207\" width=\"480\" height=\"620\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1057\"/>\n            <value key=\"minSize\" type=\"size\" width=\"300\" height=\"300\"/>\n            <view key=\"contentView\" id=\"VbR-7O-UvS\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"620\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <scrollView wantsLayer=\"YES\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zDJ-sY-gR3\">\n                        <rect key=\"frame\" x=\"-1\" y=\"-1\" width=\"482\" height=\"622\"/>\n                        <clipView key=\"contentView\" id=\"sru-0y-bkx\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"465\" height=\"620\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView editable=\"NO\" importsGraphics=\"NO\" findStyle=\"bar\" allowsCharacterPickerTouchBarItem=\"NO\" textCompletion=\"NO\" id=\"so4-Sh-6Yc\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"465\" height=\"620\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    <size key=\"minSize\" width=\"465\" height=\"620\"/>\n                                    <size key=\"maxSize\" width=\"465\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"akw-jM-CfJ\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"Ldt-qg-ZQF\">\n                            <rect key=\"frame\" x=\"466\" y=\"1\" width=\"15\" height=\"620\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"zDJ-sY-gR3\" firstAttribute=\"leading\" secondItem=\"VbR-7O-UvS\" secondAttribute=\"leading\" constant=\"-1\" id=\"0UT-ye-4Z9\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"zDJ-sY-gR3\" secondAttribute=\"bottom\" constant=\"-1\" id=\"ZnJ-Qk-sh9\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"zDJ-sY-gR3\" secondAttribute=\"trailing\" constant=\"-1\" id=\"acs-TK-XZI\"/>\n                    <constraint firstItem=\"zDJ-sY-gR3\" firstAttribute=\"top\" secondItem=\"VbR-7O-UvS\" secondAttribute=\"top\" constant=\"-1\" id=\"dZs-4O-JTh\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"122\" y=\"103\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/SLiMWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"22505\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"SLiMWindowController\">\n            <connections>\n                <outlet property=\"bottomSplitView\" destination=\"SJd-UQ-477\" id=\"eia-VP-ZNw\"/>\n                <outlet property=\"browserButton\" destination=\"02L-Zx-QDl\" id=\"IB3-WZ-ptP\"/>\n                <outlet property=\"buttonForDrawer\" destination=\"3fa-Za-QvL\" id=\"I6i-kh-1gO\"/>\n                <outlet property=\"chromosomeOverview\" destination=\"KMS-2V-Mrb\" id=\"tJ6-LQ-ybJ\"/>\n                <outlet property=\"chromosomeZoomed\" destination=\"nQF-Rr-G8N\" id=\"5Ui-I9-Vky\"/>\n                <outlet property=\"consoleButton\" destination=\"aPl-XV-6R5\" id=\"tR9-uy-AYS\"/>\n                <outlet property=\"cycleTextField\" destination=\"SK3-fM-QuU\" id=\"oG9-gV-gt0\"/>\n                <outlet property=\"drawer\" destination=\"Sdd-Vl-XmH\" id=\"so7-Og-cHF\"/>\n                <outlet property=\"genomicElementTypeColorColumn\" destination=\"hiN-OA-WpD\" id=\"mFt-in-zk9\"/>\n                <outlet property=\"genomicElementTypeIDColumn\" destination=\"mYu-Tp-AnJ\" id=\"JiS-2G-IkK\"/>\n                <outlet property=\"genomicElementTypeMutationTypesColumn\" destination=\"HQN-n3-bmZ\" id=\"H2y-BR-Tbk\"/>\n                <outlet property=\"genomicElementTypeTableView\" destination=\"YFd-nW-pee\" id=\"xaz-sG-Q9p\"/>\n                <outlet property=\"graphCommandsButton\" destination=\"jBY-mF-gPl\" id=\"dAJ-ZH-555\"/>\n                <outlet property=\"graphCommandsMenu\" destination=\"QoY-ma-dgb\" id=\"Dpv-Lw-uS6\"/>\n                <outlet property=\"interactionTypeIDColumn\" destination=\"hAe-bE-z3P\" id=\"vsP-mw-fwL\"/>\n                <outlet property=\"interactionTypeIFParamsColumn\" destination=\"f1e-l7-uRu\" id=\"5VD-Cf-wJi\"/>\n                <outlet property=\"interactionTypeIFTypeColumn\" destination=\"t83-do-i1l\" id=\"hgK-f6-3dK\"/>\n                <outlet property=\"interactionTypeMaxDistanceColumn\" destination=\"qx8-ov-fWV\" id=\"kMM-O9-l1h\"/>\n                <outlet property=\"interactionTypeTableView\" destination=\"Kyc-Yl-d6g\" id=\"OH6-gW-Rdn\"/>\n                <outlet property=\"mutTypeDFEParamsColumn\" destination=\"QI1-51-Ixv\" id=\"JJE-du-qEX\"/>\n                <outlet property=\"mutTypeDFETypeColumn\" destination=\"yb0-yM-lTy\" id=\"ULb-9G-ITm\"/>\n                <outlet property=\"mutTypeDominanceColumn\" destination=\"YfC-9j-8Mz\" id=\"ZWT-nB-hCV\"/>\n                <outlet property=\"mutTypeIDColumn\" destination=\"c5C-lt-ckm\" id=\"NHG-t0-Q6x\"/>\n                <outlet property=\"mutTypeTableView\" destination=\"cuy-J5-PqR\" id=\"gm3-FO-1ZO\"/>\n                <outlet property=\"outputTextView\" destination=\"z1f-09-60b\" id=\"cxO-DR-24N\"/>\n                <outlet property=\"overallSplitView\" destination=\"z2G-lE-wPw\" id=\"zV4-oC-bHc\"/>\n                <outlet property=\"overallTopView\" destination=\"cof-JC-B5l\" id=\"kOx-o4-i8A\"/>\n                <outlet property=\"overallTopViewConstraint1\" destination=\"Bhr-F3-Lg8\" id=\"Rfi-GV-1nb\"/>\n                <outlet property=\"overallTopViewConstraint2\" destination=\"O8k-wp-S9X\" id=\"4Jb-r8-sLN\"/>\n                <outlet property=\"overallTopViewConstraint3\" destination=\"gr9-E8-Mqg\" id=\"JQn-7c-QrN\"/>\n                <outlet property=\"overallTopViewConstraint4\" destination=\"kpd-fj-71C\" id=\"iiF-XZ-T04\"/>\n                <outlet property=\"playButton\" destination=\"epB-1i-iSd\" id=\"p9h-Dk-2Ef\"/>\n                <outlet property=\"playOneStepButton\" destination=\"KIv-hd-PKz\" id=\"iG0-8v-TvJ\"/>\n                <outlet property=\"playSpeedSlider\" destination=\"kRU-NC-9qC\" id=\"OCZ-BC-3AA\"/>\n                <outlet property=\"populationErrorView\" destination=\"1i8-ZT-cwT\" id=\"YPZ-YZ-MwD\"/>\n                <outlet property=\"populationView\" destination=\"sjX-UH-cdK\" id=\"lGd-gX-Uvf\"/>\n                <outlet property=\"profileButton\" destination=\"mKg-N7-deE\" id=\"9D0-yJ-h60\"/>\n                <outlet property=\"recycleButton\" destination=\"eXF-cI-cZK\" id=\"70v-TA-ZZ2\"/>\n                <outlet property=\"scriptBlocksEndColumn\" destination=\"pZn-5h-Ysy\" id=\"9h4-Qd-PNS\"/>\n                <outlet property=\"scriptBlocksIDColumn\" destination=\"dCL-Kg-IzO\" id=\"tXZ-Cg-eXB\"/>\n                <outlet property=\"scriptBlocksStartColumn\" destination=\"6U4-H9-ZJJ\" id=\"p6S-R7-LVn\"/>\n                <outlet property=\"scriptBlocksTableView\" destination=\"7Xo-DL-2qY\" id=\"RI2-Ad-2Fo\"/>\n                <outlet property=\"scriptBlocksTypeColumn\" destination=\"Ar2-sx-Oqi\" id=\"XHg-tm-cjR\"/>\n                <outlet property=\"scriptStatusTextField\" destination=\"qCd-b9-dko\" id=\"5iT-h5-7dy\"/>\n                <outlet property=\"scriptTextView\" destination=\"N45-af-9rm\" id=\"6Xj-6h-le2\"/>\n                <outlet property=\"showFixedSubstitutionsButton\" destination=\"sC1-aa-1AY\" id=\"5Fj-Kv-Omt\"/>\n                <outlet property=\"showGenomicElementsButton\" destination=\"57G-Tr-aOB\" id=\"p7J-Vg-Y1W\"/>\n                <outlet property=\"showMutationsButton\" destination=\"MPC-lP-uVU\" id=\"Qm6-Js-ooL\"/>\n                <outlet property=\"showRecombinationIntervalsButton\" destination=\"LwJ-mt-MjQ\" id=\"ug0-W8-hrL\"/>\n                <outlet property=\"speciesBar\" destination=\"yft-oc-j5g\" id=\"8BT-uc-7lQ\"/>\n                <outlet property=\"speciesBarBottomConstraint\" destination=\"xiD-GK-pM3\" id=\"OTA-Bk-1zN\"/>\n                <outlet property=\"subpopFemaleCloningRateColumn\" destination=\"abH-RI-Xxq\" id=\"hDU-CK-aVO\"/>\n                <outlet property=\"subpopIDColumn\" destination=\"JUP-60-29u\" id=\"YJq-gt-Ih8\"/>\n                <outlet property=\"subpopMaleCloningRateColumn\" destination=\"3aN-DZ-0sG\" id=\"K1M-fV-gYa\"/>\n                <outlet property=\"subpopSelfingRateColumn\" destination=\"Hbw-nw-0u9\" id=\"gfE-84-TCH\"/>\n                <outlet property=\"subpopSexRatioColumn\" destination=\"ago-k9-R5M\" id=\"K7F-aa-oGS\"/>\n                <outlet property=\"subpopSizeColumn\" destination=\"GUM-4Z-3XN\" id=\"DS3-JF-48S\"/>\n                <outlet property=\"subpopTableView\" destination=\"l73-oi-ONH\" id=\"aVQ-t4-IpA\"/>\n                <outlet property=\"tickProgressIndicator\" destination=\"VWw-o4-Pjo\" id=\"WWC-sx-PDY\"/>\n                <outlet property=\"tickTextField\" destination=\"Yfj-bi-uzJ\" id=\"6VM-ah-81R\"/>\n                <outlet property=\"window\" destination=\"HDg-UE-KLh\" id=\"uWw-R9-SvB\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"SLiMgui\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"SLiMgui\" animationBehavior=\"default\" id=\"HDg-UE-KLh\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"740\" y=\"50\" width=\"1180\" height=\"978\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1728\" height=\"1079\"/>\n            <value key=\"minSize\" type=\"size\" width=\"650\" height=\"100\"/>\n            <view key=\"contentView\" id=\"esE-Q8-bJT\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1180\" height=\"978\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <splitView autosaveName=\"\" dividerStyle=\"paneSplitter\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"z2G-lE-wPw\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1180\" height=\"978\"/>\n                        <subviews>\n                            <customView id=\"cof-JC-B5l\" customClass=\"SLiMLayoutRoundoffView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1180\" height=\"393\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SJ3-be-U3c\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1180\" height=\"393\"/>\n                                        <subviews>\n                                            <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gYT-79-LuL\" userLabel=\"Bordered Scroll View - SLiM Table View\">\n                                                <rect key=\"frame\" x=\"15\" y=\"109\" width=\"257\" height=\"237\"/>\n                                                <clipView key=\"contentView\" id=\"W1T-hP-cku\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"255\" height=\"235\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <subviews>\n                                                        <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"Pg2-UV-Ozl\" id=\"l73-oi-ONH\" userLabel=\"SLiM Table View\" customClass=\"SLiMTableView\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"255\" height=\"212\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                            <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <tableColumns>\n                                                                <tableColumn editable=\"NO\" width=\"32\" minWidth=\"32\" maxWidth=\"32\" headerToolTip=\"the Eidos identifier for the subpopulation\" id=\"JUP-60-29u\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"ID\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"GPN-CF-F0Y\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                                <tableColumn editable=\"NO\" width=\"48\" minWidth=\"30\" maxWidth=\"150\" headerToolTip=\"the subpopulation size\" id=\"GUM-4Z-3XN\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"N\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"QQs-82-L0y\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                                <tableColumn editable=\"NO\" width=\"37\" minWidth=\"37\" maxWidth=\"37\" headerToolTip=\"the selfing rate of the subpopulation\" id=\"Hbw-nw-0u9\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"self\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"bPx-d2-jUg\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                                <tableColumn editable=\"NO\" width=\"37\" minWidth=\"37\" maxWidth=\"37\" headerToolTip=\"the cloning rate of the subpopulation, for females\" id=\"abH-RI-Xxq\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"fcl\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"nhD-g0-ttl\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                                <tableColumn editable=\"NO\" width=\"37\" minWidth=\"37\" maxWidth=\"37\" headerToolTip=\"the cloning rate of the subpopulation, for males\" id=\"3aN-DZ-0sG\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"mcl\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"EmN-1t-BRn\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                                <tableColumn editable=\"NO\" width=\"37\" minWidth=\"37\" maxWidth=\"37\" headerToolTip=\"the sex ratio of the subpopulation, M:(M+F)\" id=\"ago-k9-R5M\">\n                                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"sex\">\n                                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tableHeaderCell>\n                                                                    <textFieldCell key=\"dataCell\" controlSize=\"small\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"center\" title=\"Text Cell\" id=\"Leu-be-kEe\">\n                                                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </textFieldCell>\n                                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                                </tableColumn>\n                                                            </tableColumns>\n                                                            <connections>\n                                                                <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"1aP-fb-Qiu\">\n                                                                    <dictionary key=\"options\">\n                                                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                    </dictionary>\n                                                                </binding>\n                                                                <outlet property=\"dataSource\" destination=\"-2\" id=\"6jO-vN-t6I\"/>\n                                                                <outlet property=\"delegate\" destination=\"-2\" id=\"Q3a-Vi-ZZE\"/>\n                                                            </connections>\n                                                        </tableView>\n                                                    </subviews>\n                                                </clipView>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"257\" id=\"PI4-wd-zFt\"/>\n                                                </constraints>\n                                                <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"M6Z-DH-ONF\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </scroller>\n                                                <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"LtZ-kw-GFb\">\n                                                    <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </scroller>\n                                                <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"Pg2-UV-Ozl\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"255\" height=\"23\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </tableHeaderView>\n                                            </scrollView>\n                                            <openGLView wantsLayer=\"YES\" colorSize=\"5bit_RGB_8bit_Alpha\" useAuxiliaryDepthBufferStencil=\"NO\" useDoubleBufferingEnabled=\"YES\" allowOffline=\"YES\" wantsBestResolutionOpenGLSurface=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sjX-UH-cdK\" customClass=\"PopulationView\">\n                                                <rect key=\"frame\" x=\"292\" y=\"109\" width=\"657\" height=\"269\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"123\" id=\"kRR-52-LFB\"/>\n                                                </constraints>\n                                            </openGLView>\n                                            <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KMS-2V-Mrb\" customClass=\"ChromosomeView\">\n                                                <rect key=\"frame\" x=\"13\" y=\"85\" width=\"1089\" height=\"14\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"14\" id=\"iIj-zH-vsV\"/>\n                                                </constraints>\n                                            </customView>\n                                            <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nQF-Rr-G8N\" customClass=\"ChromosomeView\">\n                                                <rect key=\"frame\" x=\"13\" y=\"10\" width=\"1089\" height=\"65\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"65\" id=\"JPS-fW-ATa\"/>\n                                                </constraints>\n                                            </customView>\n                                            <button toolTip=\"step one tick\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KIv-hd-PKz\">\n                                                <rect key=\"frame\" x=\"969\" y=\"317\" width=\"60\" height=\"62\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"play_step\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"play_step_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Cxo-uM-PHU\">\n                                                    <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"62\" id=\"Vv1-iX-VsS\"/>\n                                                    <constraint firstAttribute=\"width\" constant=\"60\" id=\"rdv-0R-Jfy\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"playOneStep:\" target=\"-2\" id=\"3qa-EP-u0q\"/>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"continuousPlayOn\" previousBinding=\"ft9-At-7Dj\" id=\"0aX-af-Yss\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"reachedSimulationEnd\" id=\"ft9-At-7Dj\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled3\" keyPath=\"tickPlayOn\" previousBinding=\"0aX-af-Yss\" id=\"M9v-LL-oxr\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"play simulation continuously\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"epB-1i-iSd\">\n                                                <rect key=\"frame\" x=\"1037\" y=\"317\" width=\"60\" height=\"62\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"play\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"play_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"rYT-zi-9QC\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"62\" id=\"7Ja-OP-gnh\"/>\n                                                    <constraint firstAttribute=\"width\" constant=\"60\" id=\"cOX-g3-QpN\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"play:\" target=\"-2\" id=\"VCD-6t-QM8\"/>\n                                                    <binding destination=\"-2\" name=\"enabled3\" keyPath=\"profilePlayOn\" previousBinding=\"yrO-xY-7SO\" id=\"7kJ-07-A2N\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"reachedSimulationEnd\" id=\"LTa-Hh-WOu\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"LTa-Hh-WOu\" id=\"yrO-xY-7SO\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"profile simulation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mKg-N7-deE\">\n                                                <rect key=\"frame\" x=\"1077\" y=\"353\" width=\"30\" height=\"32\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"profile\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"profile_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"40U-MC-Ckj\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"30\" id=\"1df-ha-jBo\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"32\" id=\"a7f-2b-5gS\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"profile:\" target=\"-2\" id=\"j7F-r8-HWX\"/>\n                                                    <binding destination=\"-2\" name=\"enabled3\" keyPath=\"nonProfilePlayOn\" previousBinding=\"Q14-og-oZd\" id=\"XDu-nT-A9O\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"reachedSimulationEnd\" id=\"WOD-xX-ttM\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"WOD-xX-ttM\" id=\"Q14-og-oZd\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"recycle simulation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eXF-cI-cZK\">\n                                                <rect key=\"frame\" x=\"1105\" y=\"317\" width=\"60\" height=\"62\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"recycle\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"recycle_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"OHT-FK-3O8\">\n                                                    <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"60\" id=\"4tc-V6-kZY\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"62\" id=\"aPK-yN-EYQ\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"recycle:\" target=\"-2\" id=\"owa-01-mi9\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"continuousPlayOn\" id=\"BXX-cv-rTI\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"BXX-cv-rTI\" id=\"FHo-2v-ARn\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bdq-3V-iQ8\">\n                                                <rect key=\"frame\" x=\"967\" y=\"272\" width=\"36\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Tick:\" id=\"fmB-1c-4a3\">\n                                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"K0I-2S-JQz\"/>\n                                                </connections>\n                                            </textField>\n                                            <textField toolTip=\"the tick that is about to execute\" focusRingType=\"none\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yfj-bi-uzJ\" customClass=\"SLiMAutoselectTextField\">\n                                                <rect key=\"frame\" x=\"1035\" y=\"269\" width=\"130\" height=\"21\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" title=\"1\" drawsBackground=\"YES\" id=\"bq2-MX-jxa\">\n                                                    <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" localizesFormat=\"NO\" numberStyle=\"decimal\" allowsFloats=\"NO\" usesGroupingSeparator=\"NO\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"3\" id=\"9R9-Iu-e40\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <connections>\n                                                    <action selector=\"tickChanged:\" target=\"-2\" id=\"K1Y-aZ-2cJ\"/>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"continuousPlayOn\" previousBinding=\"R3R-Ti-8Uv\" id=\"5Uy-xn-4YD\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"editable2\" keyPath=\"continuousPlayOn\" previousBinding=\"ujI-gv-nt7\" id=\"ma4-Jn-SxF\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"reachedSimulationEnd\" previousBinding=\"uVp-iR-DOG\" id=\"R3R-Ti-8Uv\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"editable\" keyPath=\"reachedSimulationEnd\" id=\"ujI-gv-nt7\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled3\" keyPath=\"tickPlayOn\" previousBinding=\"5Uy-xn-4YD\" id=\"Ecc-Z5-RXh\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"editable3\" keyPath=\"tickPlayOn\" previousBinding=\"ma4-Jn-SxF\" id=\"uVp-iR-DOG\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </textField>\n                                            <slider toolTip=\"simulation playing speed\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kRU-NC-9qC\">\n                                                <rect key=\"frame\" x=\"1033\" y=\"296\" width=\"68\" height=\"17\"/>\n                                                <sliderCell key=\"cell\" controlSize=\"mini\" continuous=\"YES\" state=\"on\" alignment=\"left\" maxValue=\"1\" doubleValue=\"1\" tickMarkPosition=\"below\" sliderType=\"linear\" id=\"kmr-mp-1sk\"/>\n                                                <connections>\n                                                    <action selector=\"playSpeedChanged:\" target=\"-2\" id=\"PVe-yr-IZh\"/>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"invalidSimulation\" previousBinding=\"dqx-gZ-HEj\" id=\"Pi1-PL-TtM\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"tickPlayOn\" id=\"dqx-gZ-HEj\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </slider>\n                                            <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" maxValue=\"100\" displayedWhenStopped=\"NO\" bezeled=\"NO\" indeterminate=\"YES\" controlSize=\"small\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VWw-o4-Pjo\">\n                                                <rect key=\"frame\" x=\"1010\" y=\"271\" width=\"16\" height=\"16\"/>\n                                            </progressIndicator>\n                                            <button toolTip=\"open/close object tables drawer\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3fa-Za-QvL\">\n                                                <rect key=\"frame\" x=\"1140\" y=\"78\" width=\"25\" height=\"27\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"open_type_drawer\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"open_type_drawer_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Dm4-xg-0ds\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"27\" id=\"4gq-2g-xvB\"/>\n                                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"g48-FM-gxG\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"drawerButtonToggled:\" target=\"-2\" id=\"DLd-gY-khQ\"/>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"toggle rate map visibility\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LwJ-mt-MjQ\">\n                                                <rect key=\"frame\" x=\"1111\" y=\"49\" width=\"25\" height=\"27\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_recombination\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_recombination_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"NBm-PA-GYK\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"27\" id=\"4J9-f9-mpe\"/>\n                                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"FN0-OD-97g\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"showRecombinationIntervalsButtonToggled:\" target=\"-2\" id=\"e5b-9e-AJ2\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"9BS-bN-H04\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"toggle genomic element visibility\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"57G-Tr-aOB\">\n                                                <rect key=\"frame\" x=\"1140\" y=\"49\" width=\"25\" height=\"27\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_genomicelements\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_genomicelements_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Khh-xo-2e0\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"CcM-qY-jmu\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"27\" id=\"ba8-3w-fLF\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"showGenomicElementsButtonToggled:\" target=\"-2\" id=\"tBB-CB-bKJ\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"WJp-LY-owe\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"toggle mutation visibility\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MPC-lP-uVU\">\n                                                <rect key=\"frame\" x=\"1111\" y=\"20\" width=\"25\" height=\"27\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_mutations\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_mutations_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"FIP-qN-mJZ\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"C1r-iq-hEs\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"27\" id=\"fR0-Jl-R4D\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"showMutationsButtonToggled:\" target=\"-2\" id=\"0jC-oj-oAj\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"HKd-Bq-cIz\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button toolTip=\"toggle fixed substitution visibility\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sC1-aa-1AY\">\n                                                <rect key=\"frame\" x=\"1140\" y=\"20\" width=\"25\" height=\"27\"/>\n                                                <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_fixed\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_fixed_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"NAi-Yf-wxz\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"mmQ-Qq-kYs\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"27\" id=\"oUP-Ah-wLY\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <action selector=\"showFixedSubstitutionsButtonToggled:\" target=\"-2\" id=\"fiR-do-Wbo\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"S9t-eF-WBj\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <customView hidden=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1i8-ZT-cwT\" customClass=\"PopulationErrorView\">\n                                                <rect key=\"frame\" x=\"292\" y=\"109\" width=\"657\" height=\"269\"/>\n                                            </customView>\n                                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8pr-59-g4r\">\n                                                <rect key=\"frame\" x=\"967\" y=\"242\" width=\"45\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Cycle:\" id=\"iJF-fn-UC7\">\n                                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"Qi9-TV-fJu\"/>\n                                                </connections>\n                                            </textField>\n                                            <textField toolTip=\"the cycle that will execute next\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SK3-fM-QuU\">\n                                                <rect key=\"frame\" x=\"1035\" y=\"240\" width=\"130\" height=\"21\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"6Dx-Ud-xy8\">\n                                                    <numberFormatter key=\"formatter\" formatterBehavior=\"custom10_4\" localizesFormat=\"NO\" numberStyle=\"decimal\" allowsFloats=\"NO\" usesGroupingSeparator=\"NO\" formatWidth=\"-1\" minimumIntegerDigits=\"1\" maximumIntegerDigits=\"2000000000\" maximumFractionDigits=\"3\" id=\"qL7-n7-QG8\"/>\n                                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"continuousPlayOn\" id=\"jJn-V4-PjH\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled3\" keyPath=\"reachedSimulationEnd\" previousBinding=\"Sfs-Ra-e08\" id=\"62K-du-SBa\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"jJn-V4-PjH\" id=\"Sfs-Ra-e08\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </textField>\n                                            <segmentedControl verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yft-oc-j5g\">\n                                                <rect key=\"frame\" x=\"13\" y=\"355\" width=\"123\" height=\"24\"/>\n                                                <segmentedCell key=\"cell\" borderStyle=\"border\" alignment=\"left\" style=\"rounded\" trackingMode=\"selectOne\" id=\"OAY-i8-ktG\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <segments>\n                                                        <segment label=\"X xxxxx\"/>\n                                                        <segment label=\"Y yyyyy\" selected=\"YES\" tag=\"1\"/>\n                                                    </segments>\n                                                </segmentedCell>\n                                                <connections>\n                                                    <action selector=\"speciesBarChanged:\" target=\"-2\" id=\"1tu-vP-DDK\"/>\n                                                </connections>\n                                            </segmentedControl>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"SK3-fM-QuU\" firstAttribute=\"leading\" secondItem=\"8pr-59-g4r\" secondAttribute=\"trailing\" constant=\"25\" id=\"0pH-Uz-gPw\"/>\n                                            <constraint firstItem=\"MPC-lP-uVU\" firstAttribute=\"top\" secondItem=\"LwJ-mt-MjQ\" secondAttribute=\"bottom\" constant=\"2\" id=\"1UM-lb-Fey\"/>\n                                            <constraint firstItem=\"Yfj-bi-uzJ\" firstAttribute=\"top\" secondItem=\"kRU-NC-9qC\" secondAttribute=\"bottom\" constant=\"8\" id=\"1eG-Ec-HKM\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"eXF-cI-cZK\" secondAttribute=\"trailing\" constant=\"15\" id=\"3F8-Yv-UIR\"/>\n                                            <constraint firstItem=\"epB-1i-iSd\" firstAttribute=\"leading\" secondItem=\"kRU-NC-9qC\" secondAttribute=\"leading\" constant=\"2\" id=\"3qI-rE-8al\"/>\n                                            <constraint firstItem=\"57G-Tr-aOB\" firstAttribute=\"leading\" secondItem=\"LwJ-mt-MjQ\" secondAttribute=\"trailing\" constant=\"4\" id=\"5O2-8m-7lT\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"nQF-Rr-G8N\" secondAttribute=\"bottom\" constant=\"10\" id=\"6I6-UZ-CRE\"/>\n                                            <constraint firstItem=\"nQF-Rr-G8N\" firstAttribute=\"top\" secondItem=\"KMS-2V-Mrb\" secondAttribute=\"bottom\" constant=\"10\" id=\"809-sA-R79\"/>\n                                            <constraint firstItem=\"KIv-hd-PKz\" firstAttribute=\"leading\" secondItem=\"Bdq-3V-iQ8\" secondAttribute=\"leading\" id=\"8vQ-GM-6Oy\"/>\n                                            <constraint firstItem=\"yft-oc-j5g\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"gYT-79-LuL\" secondAttribute=\"trailing\" id=\"9VU-DJ-EiT\"/>\n                                            <constraint firstItem=\"epB-1i-iSd\" firstAttribute=\"trailing\" secondItem=\"kRU-NC-9qC\" secondAttribute=\"trailing\" constant=\"-2\" id=\"9fC-VY-d0v\"/>\n                                            <constraint firstItem=\"1i8-ZT-cwT\" firstAttribute=\"leading\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"leading\" id=\"B8o-nz-zbE\"/>\n                                            <constraint firstItem=\"LwJ-mt-MjQ\" firstAttribute=\"leading\" secondItem=\"MPC-lP-uVU\" secondAttribute=\"leading\" id=\"BkA-pJ-HYh\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"3fa-Za-QvL\" secondAttribute=\"trailing\" constant=\"15\" id=\"CzW-XH-NX5\"/>\n                                            <constraint firstItem=\"LwJ-mt-MjQ\" firstAttribute=\"leading\" secondItem=\"nQF-Rr-G8N\" secondAttribute=\"trailing\" constant=\"9\" id=\"DJx-7X-M1a\"/>\n                                            <constraint firstItem=\"sjX-UH-cdK\" firstAttribute=\"top\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"top\" constant=\"15\" id=\"E9K-yv-hOl\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"57G-Tr-aOB\" secondAttribute=\"trailing\" constant=\"15\" id=\"EaR-pw-uZm\"/>\n                                            <constraint firstItem=\"sjX-UH-cdK\" firstAttribute=\"leading\" secondItem=\"gYT-79-LuL\" secondAttribute=\"trailing\" constant=\"20\" id=\"GER-9e-c56\"/>\n                                            <constraint firstItem=\"epB-1i-iSd\" firstAttribute=\"leading\" secondItem=\"KIv-hd-PKz\" secondAttribute=\"trailing\" constant=\"8\" id=\"IRk-z7-f7T\"/>\n                                            <constraint firstItem=\"3fa-Za-QvL\" firstAttribute=\"top\" secondItem=\"KMS-2V-Mrb\" secondAttribute=\"top\" constant=\"-6\" id=\"KtX-Ea-Cw0\"/>\n                                            <constraint firstItem=\"yft-oc-j5g\" firstAttribute=\"top\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"top\" constant=\"15\" id=\"LDB-Zj-sxG\"/>\n                                            <constraint firstItem=\"SK3-fM-QuU\" firstAttribute=\"trailing\" secondItem=\"Yfj-bi-uzJ\" secondAttribute=\"trailing\" id=\"LSL-e2-CxJ\"/>\n                                            <constraint firstItem=\"epB-1i-iSd\" firstAttribute=\"top\" secondItem=\"mKg-N7-deE\" secondAttribute=\"bottom\" constant=\"-26\" id=\"MXR-dr-7JN\"/>\n                                            <constraint firstItem=\"sC1-aa-1AY\" firstAttribute=\"leading\" secondItem=\"MPC-lP-uVU\" secondAttribute=\"trailing\" constant=\"4\" id=\"NGC-0B-DiO\"/>\n                                            <constraint firstItem=\"LwJ-mt-MjQ\" firstAttribute=\"top\" secondItem=\"57G-Tr-aOB\" secondAttribute=\"top\" id=\"NPM-o4-6dB\"/>\n                                            <constraint firstItem=\"KIv-hd-PKz\" firstAttribute=\"leading\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"trailing\" constant=\"20\" id=\"Php-jl-KQR\"/>\n                                            <constraint firstItem=\"1i8-ZT-cwT\" firstAttribute=\"bottom\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"bottom\" id=\"QMg-Lf-Lup\"/>\n                                            <constraint firstItem=\"gYT-79-LuL\" firstAttribute=\"leading\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"leading\" constant=\"15\" id=\"RaN-xq-QIZ\"/>\n                                            <constraint firstItem=\"KIv-hd-PKz\" firstAttribute=\"top\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"top\" constant=\"14\" id=\"ReT-5u-JuH\"/>\n                                            <constraint firstItem=\"1i8-ZT-cwT\" firstAttribute=\"trailing\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"trailing\" id=\"SOl-il-mic\"/>\n                                            <constraint firstItem=\"eXF-cI-cZK\" firstAttribute=\"trailing\" secondItem=\"Yfj-bi-uzJ\" secondAttribute=\"trailing\" id=\"TwT-bI-bNb\"/>\n                                            <constraint firstItem=\"1i8-ZT-cwT\" firstAttribute=\"top\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"top\" id=\"Tyk-kF-vMa\"/>\n                                            <constraint firstItem=\"nQF-Rr-G8N\" firstAttribute=\"leading\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"leading\" constant=\"13\" id=\"VCu-pV-Ew0\"/>\n                                            <constraint firstItem=\"sC1-aa-1AY\" firstAttribute=\"top\" secondItem=\"57G-Tr-aOB\" secondAttribute=\"bottom\" constant=\"2\" id=\"X3F-kO-Fr0\"/>\n                                            <constraint firstItem=\"eXF-cI-cZK\" firstAttribute=\"leading\" secondItem=\"epB-1i-iSd\" secondAttribute=\"trailing\" constant=\"8\" id=\"Zhw-Fa-4p6\"/>\n                                            <constraint firstItem=\"KMS-2V-Mrb\" firstAttribute=\"leading\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"leading\" constant=\"13\" id=\"aJb-cQ-YWD\"/>\n                                            <constraint firstItem=\"yft-oc-j5g\" firstAttribute=\"leading\" secondItem=\"gYT-79-LuL\" secondAttribute=\"leading\" id=\"fLk-Vj-zIe\"/>\n                                            <constraint firstItem=\"kRU-NC-9qC\" firstAttribute=\"top\" secondItem=\"epB-1i-iSd\" secondAttribute=\"bottom\" constant=\"6\" id=\"gab-YI-p0S\"/>\n                                            <constraint firstItem=\"KMS-2V-Mrb\" firstAttribute=\"width\" secondItem=\"nQF-Rr-G8N\" secondAttribute=\"width\" id=\"hzb-ik-LI8\"/>\n                                            <constraint firstItem=\"eXF-cI-cZK\" firstAttribute=\"top\" secondItem=\"epB-1i-iSd\" secondAttribute=\"top\" id=\"ibK-E9-puS\"/>\n                                            <constraint firstItem=\"Bdq-3V-iQ8\" firstAttribute=\"bottom\" secondItem=\"VWw-o4-Pjo\" secondAttribute=\"bottom\" constant=\"-1\" id=\"llL-Va-nnn\"/>\n                                            <constraint firstItem=\"LwJ-mt-MjQ\" firstAttribute=\"top\" secondItem=\"nQF-Rr-G8N\" secondAttribute=\"top\" constant=\"-1\" id=\"mBg-MN-5to\"/>\n                                            <constraint firstItem=\"VWw-o4-Pjo\" firstAttribute=\"leading\" secondItem=\"Bdq-3V-iQ8\" secondAttribute=\"trailing\" constant=\"9\" id=\"pCu-QP-RtD\"/>\n                                            <constraint firstItem=\"epB-1i-iSd\" firstAttribute=\"top\" secondItem=\"KIv-hd-PKz\" secondAttribute=\"top\" id=\"pnS-73-RN0\"/>\n                                            <constraint firstItem=\"gYT-79-LuL\" firstAttribute=\"bottom\" secondItem=\"1i8-ZT-cwT\" secondAttribute=\"bottom\" id=\"u70-S5-h2X\"/>\n                                            <constraint firstItem=\"KMS-2V-Mrb\" firstAttribute=\"top\" secondItem=\"sjX-UH-cdK\" secondAttribute=\"bottom\" constant=\"10\" id=\"uQe-Eb-jXh\"/>\n                                            <constraint firstItem=\"SK3-fM-QuU\" firstAttribute=\"leading\" secondItem=\"Yfj-bi-uzJ\" secondAttribute=\"leading\" id=\"vDE-O3-YUj\"/>\n                                            <constraint firstItem=\"8pr-59-g4r\" firstAttribute=\"leading\" secondItem=\"Bdq-3V-iQ8\" secondAttribute=\"leading\" id=\"wq4-z5-OJb\"/>\n                                            <constraint firstItem=\"SK3-fM-QuU\" firstAttribute=\"firstBaseline\" secondItem=\"8pr-59-g4r\" secondAttribute=\"firstBaseline\" id=\"xHx-GQ-9gs\"/>\n                                            <constraint firstItem=\"SK3-fM-QuU\" firstAttribute=\"top\" secondItem=\"Yfj-bi-uzJ\" secondAttribute=\"bottom\" constant=\"8\" id=\"xUG-V6-nFJ\"/>\n                                            <constraint firstItem=\"Bdq-3V-iQ8\" firstAttribute=\"baseline\" secondItem=\"Yfj-bi-uzJ\" secondAttribute=\"baseline\" id=\"xUd-e3-o5G\"/>\n                                            <constraint firstItem=\"gYT-79-LuL\" firstAttribute=\"top\" secondItem=\"yft-oc-j5g\" secondAttribute=\"bottom\" constant=\"10\" id=\"xiD-GK-pM3\"/>\n                                            <constraint firstItem=\"mKg-N7-deE\" firstAttribute=\"leading\" secondItem=\"epB-1i-iSd\" secondAttribute=\"trailing\" constant=\"-20\" id=\"yBh-ld-fov\"/>\n                                        </constraints>\n                                    </customView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"trailing\" id=\"Bhr-F3-Lg8\"/>\n                                    <constraint firstItem=\"SJ3-be-U3c\" firstAttribute=\"leading\" secondItem=\"cof-JC-B5l\" secondAttribute=\"leading\" id=\"O8k-wp-S9X\"/>\n                                    <constraint firstItem=\"SJ3-be-U3c\" firstAttribute=\"top\" secondItem=\"cof-JC-B5l\" secondAttribute=\"top\" id=\"gr9-E8-Mqg\"/>\n                                    <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"294\" id=\"k64-6X-mEB\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"SJ3-be-U3c\" secondAttribute=\"bottom\" id=\"kpd-fj-71C\"/>\n                                </constraints>\n                            </customView>\n                            <customView id=\"Y6t-XW-IC8\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"403\" width=\"1180\" height=\"575\"/>\n                                <autoresizingMask key=\"autoresizingMask\"/>\n                                <subviews>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"150\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qCd-b9-dko\">\n                                        <rect key=\"frame\" x=\"15\" y=\"15\" width=\"1150\" height=\"18\"/>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"Q41-yU-9YD\">\n                                            <font key=\"font\" size=\"11\" name=\"Menlo-Regular\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <splitView autosaveName=\"\" vertical=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SJd-UQ-477\">\n                                        <rect key=\"frame\" x=\"6\" y=\"32\" width=\"1168\" height=\"538\"/>\n                                        <subviews>\n                                            <customView id=\"cas-KD-TD2\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"584\" height=\"538\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                <subviews>\n                                                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yeL-B5-ZLS\" userLabel=\"Bordered Scroll View - Eidos Text View\">\n                                                        <rect key=\"frame\" x=\"9\" y=\"0.0\" width=\"575\" height=\"512\"/>\n                                                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"lOc-28-sSJ\">\n                                                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"558\" height=\"510\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                            <subviews>\n                                                                <textView importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" findStyle=\"bar\" allowsUndo=\"YES\" id=\"N45-af-9rm\" userLabel=\"Eidos Text View\" customClass=\"EidosTextView\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"558\" height=\"510\"/>\n                                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <size key=\"minSize\" width=\"558\" height=\"510\"/>\n                                                                    <size key=\"maxSize\" width=\"1123\" height=\"10000000\"/>\n                                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <connections>\n                                                                        <binding destination=\"-2\" name=\"editable\" keyPath=\"continuousPlayOn\" id=\"44K-3N-tcx\">\n                                                                            <dictionary key=\"options\">\n                                                                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                            </dictionary>\n                                                                        </binding>\n                                                                        <binding destination=\"-2\" name=\"editable2\" keyPath=\"tickPlayOn\" previousBinding=\"44K-3N-tcx\" id=\"QIW-Y3-rzT\">\n                                                                            <dictionary key=\"options\">\n                                                                                <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                                                <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                                                <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                                                <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                            </dictionary>\n                                                                        </binding>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"6Cg-zL-V3T\"/>\n                                                                    </connections>\n                                                                </textView>\n                                                            </subviews>\n                                                        </clipView>\n                                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"FDW-HP-OHI\">\n                                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                        </scroller>\n                                                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"aj2-y0-Lhv\">\n                                                            <rect key=\"frame\" x=\"559\" y=\"1\" width=\"15\" height=\"510\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                        </scroller>\n                                                    </scrollView>\n                                                    <button toolTip=\"check script syntax\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SAG-aF-oTT\" userLabel=\"Check Script Button\">\n                                                        <rect key=\"frame\" x=\"9\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"check\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"check_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"DXP-Jw-OQ3\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"RIq-r4-vDp\"/>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"jPz-bf-YxD\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"checkScript:\" target=\"-2\" id=\"Tzc-ZZ-S5W\"/>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"continuousPlayOn\" id=\"n3s-mW-AaJ\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                            <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"n3s-mW-AaJ\" id=\"N77-2R-Zoq\">\n                                                                <dictionary key=\"options\">\n                                                                    <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0fj-1F-Ipl\">\n                                                        <rect key=\"frame\" x=\"127\" y=\"518\" width=\"119\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Input Commands:\" id=\"5TY-HF-5xK\">\n                                                            <font key=\"font\" metaFont=\"systemBold\"/>\n                                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <button toolTip=\"scripting help\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lnH-Vh-Iwz\" userLabel=\"Script Help Button\">\n                                                        <rect key=\"frame\" x=\"55\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"syntax_help\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"syntax_help_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"uGp-51-Lem\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"YC1-of-YFY\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"dHN-qx-bVJ\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"showScriptHelp:\" target=\"-2\" id=\"R6V-TU-6uQ\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button toolTip=\"show/hide Eidos console\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aPl-XV-6R5\">\n                                                        <rect key=\"frame\" x=\"78\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_console\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_console_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"efp-zE-fTb\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"Fln-18-1SY\"/>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"oJv-9T-R4T\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"toggleConsoleVisibility:\" target=\"-2\" id=\"S9a-zL-vcz\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button toolTip=\"show/hide Eidos variable browser\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"02L-Zx-QDl\" userLabel=\"Variable Browser Button\">\n                                                        <rect key=\"frame\" x=\"101\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"show_browser\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"show_browser_H\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"u9U-vi-gge\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" changeContents=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"9am-gN-1cK\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"lng-51-msY\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"toggleBrowserVisibility:\" target=\"-2\" id=\"5tc-7r-IRA\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button toolTip=\"prettyprint script\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ge3-vP-zZp\" userLabel=\"Prettyprint Button\">\n                                                        <rect key=\"frame\" x=\"32\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"prettyprint\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"prettyprint_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ghZ-di-p9F\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"QUX-Ha-Gk7\"/>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"rxe-WV-cBh\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"prettyprintScript:\" target=\"-2\" id=\"uUv-Zd-UNT\"/>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"continuousPlayOn\" id=\"sYs-sI-hg6\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                            <binding destination=\"-2\" name=\"enabled2\" keyPath=\"tickPlayOn\" previousBinding=\"sYs-sI-hg6\" id=\"F1l-dP-Wrl\">\n                                                                <dictionary key=\"options\">\n                                                                    <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                                    <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"0fj-1F-Ipl\" firstAttribute=\"leading\" secondItem=\"02L-Zx-QDl\" secondAttribute=\"trailing\" constant=\"8\" id=\"4du-7e-ujj\"/>\n                                                    <constraint firstItem=\"lnH-Vh-Iwz\" firstAttribute=\"bottom\" secondItem=\"aPl-XV-6R5\" secondAttribute=\"bottom\" id=\"5Bh-f4-LqY\"/>\n                                                    <constraint firstItem=\"SAG-aF-oTT\" firstAttribute=\"leading\" secondItem=\"cas-KD-TD2\" secondAttribute=\"leading\" constant=\"9\" id=\"67B-Nf-WaO\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"yeL-B5-ZLS\" secondAttribute=\"trailing\" id=\"BFU-9F-N49\"/>\n                                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"263\" id=\"Ong-rz-g6T\"/>\n                                                    <constraint firstItem=\"yeL-B5-ZLS\" firstAttribute=\"leading\" secondItem=\"cas-KD-TD2\" secondAttribute=\"leading\" constant=\"9\" id=\"Wez-lZ-RKs\"/>\n                                                    <constraint firstItem=\"ge3-vP-zZp\" firstAttribute=\"bottom\" secondItem=\"SAG-aF-oTT\" secondAttribute=\"bottom\" id=\"Wui-6l-Rm4\"/>\n                                                    <constraint firstItem=\"yeL-B5-ZLS\" firstAttribute=\"top\" secondItem=\"cas-KD-TD2\" secondAttribute=\"top\" constant=\"26\" id=\"aS3-CL-9Qc\"/>\n                                                    <constraint firstItem=\"0fj-1F-Ipl\" firstAttribute=\"top\" secondItem=\"cas-KD-TD2\" secondAttribute=\"top\" constant=\"4\" id=\"cqQ-pm-0tq\"/>\n                                                    <constraint firstItem=\"ge3-vP-zZp\" firstAttribute=\"bottom\" secondItem=\"lnH-Vh-Iwz\" secondAttribute=\"bottom\" id=\"fCi-nd-sRr\"/>\n                                                    <constraint firstItem=\"0fj-1F-Ipl\" firstAttribute=\"bottom\" secondItem=\"SAG-aF-oTT\" secondAttribute=\"bottom\" constant=\"-2\" id=\"hCG-Sg-XIW\"/>\n                                                    <constraint firstItem=\"02L-Zx-QDl\" firstAttribute=\"leading\" secondItem=\"aPl-XV-6R5\" secondAttribute=\"trailing\" constant=\"3\" id=\"jwA-5a-wkm\"/>\n                                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"0fj-1F-Ipl\" secondAttribute=\"trailing\" constant=\"1\" id=\"nQF-EU-g9n\"/>\n                                                    <constraint firstItem=\"lnH-Vh-Iwz\" firstAttribute=\"leading\" secondItem=\"ge3-vP-zZp\" secondAttribute=\"trailing\" constant=\"3\" id=\"qXu-vv-QUk\"/>\n                                                    <constraint firstItem=\"aPl-XV-6R5\" firstAttribute=\"leading\" secondItem=\"lnH-Vh-Iwz\" secondAttribute=\"trailing\" constant=\"3\" id=\"r5l-Nb-fFj\"/>\n                                                    <constraint firstItem=\"aPl-XV-6R5\" firstAttribute=\"bottom\" secondItem=\"02L-Zx-QDl\" secondAttribute=\"bottom\" id=\"rBc-fK-WiC\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"yeL-B5-ZLS\" secondAttribute=\"bottom\" id=\"vKN-YU-Eiw\"/>\n                                                    <constraint firstItem=\"ge3-vP-zZp\" firstAttribute=\"leading\" secondItem=\"SAG-aF-oTT\" secondAttribute=\"trailing\" constant=\"3\" id=\"w8M-GG-2Sx\"/>\n                                                </constraints>\n                                            </customView>\n                                            <customView id=\"xzw-Z6-mJs\">\n                                                <rect key=\"frame\" x=\"593\" y=\"0.0\" width=\"575\" height=\"538\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                <subviews>\n                                                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fql-QB-8ET\" userLabel=\"Bordered Scroll View - Eidos Text View\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"566\" height=\"512\"/>\n                                                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"Fsf-qx-R06\">\n                                                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"549\" height=\"510\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                            <subviews>\n                                                                <textView editable=\"NO\" importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" findStyle=\"bar\" allowsUndo=\"YES\" allowsNonContiguousLayout=\"YES\" id=\"z1f-09-60b\" userLabel=\"Eidos Text View\" customClass=\"EidosTextView\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"549\" height=\"510\"/>\n                                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <size key=\"minSize\" width=\"549\" height=\"510\"/>\n                                                                    <size key=\"maxSize\" width=\"1123\" height=\"10000000\"/>\n                                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"c3D-5f-8j3\"/>\n                                                                    </connections>\n                                                                </textView>\n                                                            </subviews>\n                                                        </clipView>\n                                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"L6p-za-ybQ\">\n                                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                        </scroller>\n                                                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"gGs-i5-zPb\">\n                                                            <rect key=\"frame\" x=\"550\" y=\"1\" width=\"15\" height=\"510\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                        </scroller>\n                                                    </scrollView>\n                                                    <button toolTip=\"clear output log\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CMF-cK-m13\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"delete\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"delete_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"qBn-5M-A1i\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"FKj-XX-l10\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"son-ze-4qq\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"clearOutput:\" target=\"-2\" id=\"OOx-Wc-Wy4\"/>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"vi5-3f-azI\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"25p-qC-Ntg\">\n                                                        <rect key=\"frame\" x=\"49\" y=\"518\" width=\"83\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Run Output:\" id=\"mtR-8d-kHj\">\n                                                            <font key=\"font\" metaFont=\"systemBold\"/>\n                                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                        <connections>\n                                                            <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"WQ2-tO-e2B\"/>\n                                                        </connections>\n                                                    </textField>\n                                                    <button toolTip=\"dump population state\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kDh-Fw-f06\">\n                                                        <rect key=\"frame\" x=\"23\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"dump_output\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"dump_output_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"3DM-1V-rPm\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"PPw-YS-gFo\"/>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"iUB-cU-r0N\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"dumpPopulationToOutput:\" target=\"-2\" id=\"kWy-Yp-t7q\"/>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"g4L-Cw-cE8\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                    <button toolTip=\"show a graph\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jBY-mF-gPl\" userLabel=\"SLiM Menu Button\" customClass=\"SLiMMenuButton\">\n                                                        <rect key=\"frame\" x=\"150\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"graph_submenu\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"graph_submenu_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"adY-8u-J23\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"KJG-l7-7ce\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"yxs-Pk-tdg\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"Ghv-mX-Qp0\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                    <button toolTip=\"change working directory\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Egy-bI-OBh\">\n                                                        <rect key=\"frame\" x=\"546\" y=\"516\" width=\"20\" height=\"22\"/>\n                                                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"change_folder\" imagePosition=\"only\" alignment=\"center\" alternateImage=\"change_folder_H\" state=\"on\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"GRU-4T-yEL\">\n                                                            <behavior key=\"behavior\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"LZE-xd-FP4\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"20\" id=\"m4D-2J-gZG\"/>\n                                                        </constraints>\n                                                        <connections>\n                                                            <action selector=\"changeWorkingDirectory:\" target=\"-2\" id=\"3nE-nX-o58\"/>\n                                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"wsb-nR-7wK\">\n                                                                <dictionary key=\"options\">\n                                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"jBY-mF-gPl\" firstAttribute=\"leading\" secondItem=\"25p-qC-Ntg\" secondAttribute=\"trailing\" constant=\"20\" id=\"0pM-0w-2iT\"/>\n                                                    <constraint firstItem=\"kDh-Fw-f06\" firstAttribute=\"leading\" secondItem=\"CMF-cK-m13\" secondAttribute=\"trailing\" constant=\"3\" id=\"7tm-sU-ZbI\"/>\n                                                    <constraint firstItem=\"Fql-QB-8ET\" firstAttribute=\"leading\" secondItem=\"xzw-Z6-mJs\" secondAttribute=\"leading\" id=\"CRd-ab-fqz\"/>\n                                                    <constraint firstItem=\"25p-qC-Ntg\" firstAttribute=\"leading\" secondItem=\"kDh-Fw-f06\" secondAttribute=\"trailing\" constant=\"8\" id=\"FML-Tr-eCR\"/>\n                                                    <constraint firstItem=\"kDh-Fw-f06\" firstAttribute=\"top\" secondItem=\"CMF-cK-m13\" secondAttribute=\"top\" id=\"Fe3-SF-24F\"/>\n                                                    <constraint firstItem=\"Fql-QB-8ET\" firstAttribute=\"top\" secondItem=\"xzw-Z6-mJs\" secondAttribute=\"top\" constant=\"26\" id=\"HpL-4y-89B\"/>\n                                                    <constraint firstItem=\"25p-qC-Ntg\" firstAttribute=\"bottom\" secondItem=\"CMF-cK-m13\" secondAttribute=\"bottom\" constant=\"-2\" id=\"Mfl-Lc-tvJ\"/>\n                                                    <constraint firstItem=\"Egy-bI-OBh\" firstAttribute=\"bottom\" secondItem=\"jBY-mF-gPl\" secondAttribute=\"bottom\" id=\"R8x-Z3-wbX\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Fql-QB-8ET\" secondAttribute=\"bottom\" id=\"eG1-oE-QGw\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Egy-bI-OBh\" secondAttribute=\"trailing\" constant=\"9\" id=\"ijE-xI-aMY\"/>\n                                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"263\" id=\"kXv-BX-gKL\"/>\n                                                    <constraint firstItem=\"jBY-mF-gPl\" firstAttribute=\"bottom\" secondItem=\"kDh-Fw-f06\" secondAttribute=\"bottom\" id=\"oKg-uN-fcd\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Fql-QB-8ET\" secondAttribute=\"trailing\" constant=\"9\" id=\"xcc-xQ-3Xc\"/>\n                                                    <constraint firstItem=\"CMF-cK-m13\" firstAttribute=\"leading\" secondItem=\"xzw-Z6-mJs\" secondAttribute=\"leading\" id=\"zCT-7f-R20\"/>\n                                                </constraints>\n                                            </customView>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"25p-qC-Ntg\" firstAttribute=\"baseline\" secondItem=\"0fj-1F-Ipl\" secondAttribute=\"baseline\" id=\"HeB-r6-WGf\"/>\n                                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"150\" id=\"OSt-Ho-LlA\"/>\n                                        </constraints>\n                                        <holdingPriorities>\n                                            <real value=\"250\"/>\n                                            <real value=\"250\"/>\n                                        </holdingPriorities>\n                                        <connections>\n                                            <outlet property=\"delegate\" destination=\"-2\" id=\"bR3-qB-Bu7\"/>\n                                        </connections>\n                                    </splitView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"qCd-b9-dko\" secondAttribute=\"bottom\" constant=\"15\" id=\"5cV-4c-YZV\"/>\n                                    <constraint firstItem=\"SJd-UQ-477\" firstAttribute=\"top\" secondItem=\"Y6t-XW-IC8\" secondAttribute=\"top\" constant=\"5\" id=\"8G9-KG-IFF\"/>\n                                    <constraint firstItem=\"qCd-b9-dko\" firstAttribute=\"top\" secondItem=\"SJd-UQ-477\" secondAttribute=\"bottom\" constant=\"-1\" id=\"AMr-AA-wrG\"/>\n                                    <constraint firstItem=\"qCd-b9-dko\" firstAttribute=\"leading\" secondItem=\"Y6t-XW-IC8\" secondAttribute=\"leading\" constant=\"15\" id=\"I9H-qR-m2t\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"SJd-UQ-477\" secondAttribute=\"trailing\" constant=\"6\" id=\"N5F-Ms-NK0\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"qCd-b9-dko\" secondAttribute=\"trailing\" constant=\"15\" id=\"QLQ-Pj-bX6\"/>\n                                    <constraint firstItem=\"SJd-UQ-477\" firstAttribute=\"leading\" secondItem=\"Y6t-XW-IC8\" secondAttribute=\"leading\" constant=\"6\" id=\"aq3-hO-I32\"/>\n                                    <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"150\" id=\"sJ8-4M-1P9\"/>\n                                </constraints>\n                            </customView>\n                        </subviews>\n                        <holdingPriorities>\n                            <real value=\"250\"/>\n                            <real value=\"250\"/>\n                        </holdingPriorities>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"Ajc-kg-q9W\"/>\n                        </connections>\n                    </splitView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"z2G-lE-wPw\" firstAttribute=\"top\" secondItem=\"esE-Q8-bJT\" secondAttribute=\"top\" id=\"0Vv-Hx-1X9\"/>\n                    <constraint firstItem=\"z2G-lE-wPw\" firstAttribute=\"leading\" secondItem=\"esE-Q8-bJT\" secondAttribute=\"leading\" id=\"H7T-IP-pj0\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"z2G-lE-wPw\" secondAttribute=\"bottom\" id=\"dLS-Ac-19j\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"z2G-lE-wPw\" secondAttribute=\"trailing\" id=\"t1n-33-mUz\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"6Gd-nE-pDY\"/>\n                <outlet property=\"initialFirstResponder\" destination=\"N45-af-9rm\" id=\"HpY-hf-Oyx\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-57\" y=\"151\"/>\n        </window>\n        <customView id=\"epY-pE-S4h\" userLabel=\"Drawer Content View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"280\" height=\"739\"/>\n            <autoresizingMask key=\"autoresizingMask\"/>\n            <subviews>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DPt-AC-FkI\">\n                    <rect key=\"frame\" x=\"18\" y=\"703\" width=\"109\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Mutation Types:\" id=\"kbX-rh-UR0\">\n                        <font key=\"font\" metaFont=\"systemBold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"2mq-SA-JiA\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4rT-qK-JNW\">\n                    <rect key=\"frame\" x=\"18\" y=\"524\" width=\"164\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Genomic Element Types:\" id=\"j3V-NJ-ulW\">\n                        <font key=\"font\" metaFont=\"systemBold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"Xrs-N1-0x8\"/>\n                    </connections>\n                </textField>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7GG-eb-uRQ\">\n                    <rect key=\"frame\" x=\"32\" y=\"559\" width=\"228\" height=\"136\"/>\n                    <clipView key=\"contentView\" id=\"kOe-M0-icb\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"226\" height=\"134\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"bNE-qm-DmG\" id=\"cuy-J5-PqR\" userLabel=\"SLiM Table View\" customClass=\"SLiMTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"111\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"c5C-lt-ckm\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"ID\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"0Sg-ca-WWc\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"YfC-9j-8Mz\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"h\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"cU6-Yd-ajG\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"50\" minWidth=\"50\" maxWidth=\"50\" id=\"yb0-yM-lTy\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"DFE\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"wjb-oe-0c2\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"65\" minWidth=\"65\" maxWidth=\"500\" id=\"QI1-51-Ixv\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Params\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"fgn-Ic-Key\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"Plv-xk-rWi\">\n                                        <dictionary key=\"options\">\n                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                        </dictionary>\n                                    </binding>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"nei-UY-F7D\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"PZl-A7-dzU\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"dCE-DQ-skE\">\n                        <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"1IA-b0-dsX\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" id=\"bNE-qm-DmG\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"23\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sez-rK-O1h\">\n                    <rect key=\"frame\" x=\"32\" y=\"379\" width=\"228\" height=\"137\"/>\n                    <clipView key=\"contentView\" id=\"y9i-Z5-n1Q\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"226\" height=\"135\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"8xi-NL-17O\" id=\"YFd-nW-pee\" userLabel=\"SLiM Table View\" customClass=\"SLiMTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"112\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"mYu-Tp-AnJ\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"ID\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"CTV-az-n0D\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"hiN-OA-WpD\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"center\" title=\"Color\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"2We-xC-Kdg\" customClass=\"SLiMColorCell\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"120\" minWidth=\"120\" maxWidth=\"500\" id=\"HQN-n3-bmZ\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Mutation types\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"mMo-hj-X06\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"tHh-Sf-inq\">\n                                        <dictionary key=\"options\">\n                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                        </dictionary>\n                                    </binding>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"jfb-rY-J27\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"lJn-DU-1zY\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"1bV-Dp-xL5\">\n                        <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"Ni5-6s-Xke\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" id=\"8xi-NL-17O\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"23\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L7m-fP-gXR\">\n                    <rect key=\"frame\" x=\"18\" y=\"165\" width=\"91\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Eidos Blocks:\" id=\"OOa-Ar-p63\">\n                        <font key=\"font\" metaFont=\"systemBold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"T9M-1z-VdX\"/>\n                    </connections>\n                </textField>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8qO-Fw-xcP\">\n                    <rect key=\"frame\" x=\"32\" y=\"20\" width=\"228\" height=\"137\"/>\n                    <clipView key=\"contentView\" id=\"RTN-L2-LBh\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"226\" height=\"135\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"NXa-cS-jsO\" id=\"7Xo-DL-2qY\" userLabel=\"SLiM Table View\" customClass=\"SLiMTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"112\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"dCL-Kg-IzO\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"ID\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"zff-sY-yV9\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"60\" minWidth=\"60\" maxWidth=\"60\" id=\"6U4-H9-ZJJ\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Start\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"ORi-C1-Szv\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"60\" minWidth=\"60\" maxWidth=\"60\" id=\"pZn-5h-Ysy\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"End\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"hEu-df-trY\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"500\" id=\"Ar2-sx-Oqi\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Type\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"gGP-sN-FeZ\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"O2M-wq-fqN\">\n                                        <dictionary key=\"options\">\n                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                        </dictionary>\n                                    </binding>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"36S-X5-25k\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"WK9-Pt-CTN\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"l1i-oT-WJF\">\n                        <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"bJW-GP-cAS\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" id=\"NXa-cS-jsO\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"23\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n                <textField focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" allowsCharacterPickerTouchBarItem=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f5M-vb-jNw\">\n                    <rect key=\"frame\" x=\"18\" y=\"344\" width=\"122\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Interaction Types:\" id=\"Pwf-6p-rWo\">\n                        <font key=\"font\" metaFont=\"systemBold\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"textColor\" keyPath=\"colorForWindowLabels\" id=\"uVp-yd-XS5\"/>\n                    </connections>\n                </textField>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"D7Y-iI-hMH\">\n                    <rect key=\"frame\" x=\"32\" y=\"200\" width=\"228\" height=\"136\"/>\n                    <clipView key=\"contentView\" id=\"LcT-aO-1Uj\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"226\" height=\"134\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"P1H-2s-yo1\" id=\"Kyc-Yl-d6g\" userLabel=\"SLiM Table View\" customClass=\"SLiMTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"111\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"hAe-bE-z3P\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"ID\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"NsP-7d-yFo\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"40\" minWidth=\"40\" maxWidth=\"40\" id=\"qx8-ov-fWV\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"max\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"s0f-Nh-dIL\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"50\" minWidth=\"50\" maxWidth=\"50\" id=\"t83-do-i1l\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"IF\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"BM1-cr-hVG\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn editable=\"NO\" width=\"65\" minWidth=\"65\" maxWidth=\"500\" id=\"f1e-l7-uRu\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Params\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" refusesFirstResponder=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"9C7-ys-E8c\">\n                                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"invalidSimulation\" id=\"1Of-U1-xhx\">\n                                        <dictionary key=\"options\">\n                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                        </dictionary>\n                                    </binding>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"mvJ-QA-8C0\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"P6b-fu-JFd\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"qYr-b6-aNC\">\n                        <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"weq-U3-lap\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" id=\"P1H-2s-yo1\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"226\" height=\"23\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"DPt-AC-FkI\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"20\" id=\"2f1-yg-ltN\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"8qO-Fw-xcP\" secondAttribute=\"bottom\" constant=\"20\" id=\"3VA-TX-sOD\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"sez-rK-O1h\" secondAttribute=\"trailing\" constant=\"20\" id=\"3t7-Oe-LeJ\"/>\n                <constraint firstItem=\"7GG-eb-uRQ\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"32\" id=\"4ts-H1-0lY\"/>\n                <constraint firstItem=\"7GG-eb-uRQ\" firstAttribute=\"top\" secondItem=\"DPt-AC-FkI\" secondAttribute=\"bottom\" constant=\"8\" id=\"6ML-XP-36J\"/>\n                <constraint firstItem=\"L7m-fP-gXR\" firstAttribute=\"top\" secondItem=\"D7Y-iI-hMH\" secondAttribute=\"bottom\" constant=\"19\" id=\"7JQ-84-hVN\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"f5M-vb-jNw\" secondAttribute=\"trailing\" constant=\"10\" id=\"8v9-O4-m6b\"/>\n                <constraint firstItem=\"f5M-vb-jNw\" firstAttribute=\"top\" secondItem=\"sez-rK-O1h\" secondAttribute=\"bottom\" constant=\"19\" id=\"A7M-g3-4PJ\"/>\n                <constraint firstItem=\"DPt-AC-FkI\" firstAttribute=\"top\" secondItem=\"epY-pE-S4h\" secondAttribute=\"top\" constant=\"20\" id=\"GIq-5a-8Us\"/>\n                <constraint firstItem=\"sez-rK-O1h\" firstAttribute=\"top\" secondItem=\"4rT-qK-JNW\" secondAttribute=\"bottom\" constant=\"8\" id=\"Jzb-yq-FRZ\"/>\n                <constraint firstItem=\"L7m-fP-gXR\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"20\" id=\"LAo-2P-GjR\"/>\n                <constraint firstItem=\"7GG-eb-uRQ\" firstAttribute=\"height\" secondItem=\"sez-rK-O1h\" secondAttribute=\"height\" id=\"SeL-cp-Vt5\"/>\n                <constraint firstItem=\"4rT-qK-JNW\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"20\" id=\"TfF-Jd-UZ5\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"7GG-eb-uRQ\" secondAttribute=\"trailing\" constant=\"20\" id=\"U7g-Jx-Z8E\"/>\n                <constraint firstItem=\"sez-rK-O1h\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"32\" id=\"Ubq-TQ-6RA\"/>\n                <constraint firstItem=\"8qO-Fw-xcP\" firstAttribute=\"top\" secondItem=\"L7m-fP-gXR\" secondAttribute=\"bottom\" constant=\"8\" id=\"a7p-OP-uZa\"/>\n                <constraint firstItem=\"8qO-Fw-xcP\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"32\" id=\"aOF-Ka-Bij\"/>\n                <constraint firstItem=\"D7Y-iI-hMH\" firstAttribute=\"top\" secondItem=\"f5M-vb-jNw\" secondAttribute=\"bottom\" constant=\"8\" id=\"blV-fL-h6T\"/>\n                <constraint firstItem=\"f5M-vb-jNw\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"20\" id=\"cb0-hn-k63\"/>\n                <constraint firstItem=\"D7Y-iI-hMH\" firstAttribute=\"leading\" secondItem=\"epY-pE-S4h\" secondAttribute=\"leading\" constant=\"32\" id=\"f7s-dw-ytm\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"4rT-qK-JNW\" secondAttribute=\"trailing\" constant=\"10\" id=\"fS3-1A-lQW\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"D7Y-iI-hMH\" secondAttribute=\"trailing\" constant=\"20\" id=\"g38-jF-drd\"/>\n                <constraint firstItem=\"sez-rK-O1h\" firstAttribute=\"height\" secondItem=\"D7Y-iI-hMH\" secondAttribute=\"height\" id=\"gpS-8E-leh\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"L7m-fP-gXR\" secondAttribute=\"trailing\" constant=\"10\" id=\"tez-TO-4NP\"/>\n                <constraint firstItem=\"4rT-qK-JNW\" firstAttribute=\"top\" secondItem=\"7GG-eb-uRQ\" secondAttribute=\"bottom\" constant=\"19\" id=\"uhx-Sh-xfH\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"DPt-AC-FkI\" secondAttribute=\"trailing\" constant=\"10\" id=\"vrM-qy-Uw6\"/>\n                <constraint firstItem=\"D7Y-iI-hMH\" firstAttribute=\"height\" secondItem=\"8qO-Fw-xcP\" secondAttribute=\"height\" id=\"xmG-Ni-v80\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"8qO-Fw-xcP\" secondAttribute=\"trailing\" constant=\"20\" id=\"yOB-cO-Vhi\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"1553\" y=\"227.5\"/>\n        </customView>\n        <drawer trailingOffset=\"15\" id=\"Sdd-Vl-XmH\">\n            <size key=\"contentSize\" width=\"100\" height=\"100\"/>\n            <size key=\"maxContentSize\" width=\"10000\" height=\"10000\"/>\n            <connections>\n                <outlet property=\"contentView\" destination=\"epY-pE-S4h\" id=\"Vjb-WG-Yt3\"/>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"qDN-Yd-ldY\"/>\n                <outlet property=\"parentWindow\" destination=\"HDg-UE-KLh\" id=\"acS-Je-qvY\"/>\n            </connections>\n        </drawer>\n        <menu showsStateColumn=\"NO\" id=\"QoY-ma-dgb\" userLabel=\"Graphing Menu\">\n            <items>\n                <menuItem title=\"Graph Mutation Frequency Spectrum\" id=\"nSF-EQ-VGe\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphMutationFrequencySpectrum:\" target=\"-2\" id=\"bbc-a2-8IW\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Graph Mutation Frequency Trajectories\" id=\"ASe-bx-TuV\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphMutationFrequencyTrajectories:\" target=\"-2\" id=\"fQW-Xn-eE7\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"b9k-cg-lbP\"/>\n                <menuItem title=\"Graph Mutation Loss Time Histogram\" id=\"8Ee-IZ-PpP\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphMutationLossTimeHistogram:\" target=\"-2\" id=\"LeH-pF-s22\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Graph Mutation Fixation Time Histogram\" id=\"Waz-s6-S1f\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphMutationFixationTimeHistogram:\" target=\"-2\" id=\"vMf-WV-ZAB\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"zJe-LO-zb2\"/>\n                <menuItem title=\"Graph Fitness ~ Time\" id=\"8Ps-Pg-wy4\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphFitnessOverTime:\" target=\"-2\" id=\"faq-1c-L7I\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"UKb-k9-QkM\"/>\n                <menuItem title=\"Graph Population Visualization\" id=\"fua-cP-IJn\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"graphPopulationVisualization:\" target=\"-2\" id=\"f4v-7h-YUt\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"639.5\" y=\"1055.5\"/>\n        </menu>\n        <userDefaultsController representsSharedInstance=\"YES\" id=\"DGe-bX-uu6\"/>\n    </objects>\n    <resources>\n        <image name=\"change_folder\" width=\"138\" height=\"138\"/>\n        <image name=\"change_folder_H\" width=\"138\" height=\"138\"/>\n        <image name=\"check\" width=\"137\" height=\"137\"/>\n        <image name=\"check_H\" width=\"137\" height=\"137\"/>\n        <image name=\"delete\" width=\"137\" height=\"137\"/>\n        <image name=\"delete_H\" width=\"137\" height=\"137\"/>\n        <image name=\"dump_output\" width=\"136\" height=\"136\"/>\n        <image name=\"dump_output_H\" width=\"136\" height=\"136\"/>\n        <image name=\"graph_submenu\" width=\"136\" height=\"136\"/>\n        <image name=\"graph_submenu_H\" width=\"136\" height=\"136\"/>\n        <image name=\"open_type_drawer\" width=\"136\" height=\"136\"/>\n        <image name=\"open_type_drawer_H\" width=\"68\" height=\"68\"/>\n        <image name=\"play\" width=\"264\" height=\"264\"/>\n        <image name=\"play_H\" width=\"264\" height=\"264\"/>\n        <image name=\"play_step\" width=\"264\" height=\"264\"/>\n        <image name=\"play_step_H\" width=\"264\" height=\"264\"/>\n        <image name=\"prettyprint\" width=\"137\" height=\"137\"/>\n        <image name=\"prettyprint_H\" width=\"137\" height=\"138\"/>\n        <image name=\"profile\" width=\"133\" height=\"133\"/>\n        <image name=\"profile_H\" width=\"133\" height=\"133\"/>\n        <image name=\"recycle\" width=\"264\" height=\"264\"/>\n        <image name=\"recycle_H\" width=\"264\" height=\"264\"/>\n        <image name=\"show_browser\" width=\"137\" height=\"137\"/>\n        <image name=\"show_browser_H\" width=\"137\" height=\"137\"/>\n        <image name=\"show_console\" width=\"136\" height=\"136\"/>\n        <image name=\"show_console_H\" width=\"68\" height=\"68\"/>\n        <image name=\"show_fixed\" width=\"136\" height=\"136\"/>\n        <image name=\"show_fixed_H\" width=\"136\" height=\"136\"/>\n        <image name=\"show_genomicelements\" width=\"136\" height=\"136\"/>\n        <image name=\"show_genomicelements_H\" width=\"136\" height=\"136\"/>\n        <image name=\"show_mutations\" width=\"136\" height=\"136\"/>\n        <image name=\"show_mutations_H\" width=\"136\" height=\"136\"/>\n        <image name=\"show_recombination\" width=\"136\" height=\"136\"/>\n        <image name=\"show_recombination_H\" width=\"136\" height=\"136\"/>\n        <image name=\"syntax_help\" width=\"137\" height=\"137\"/>\n        <image name=\"syntax_help_H\" width=\"137\" height=\"137\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptModSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod\">\n            <connections>\n                <outlet property=\"customViewPlaceholder\" destination=\"Ci1-Jv-en4\" id=\"UH5-Lx-oaA\"/>\n                <outlet property=\"insertAndExecuteButton\" destination=\"34a-7k-94q\" id=\"JuW-1k-H0y\"/>\n                <outlet property=\"insertOnlyButton\" destination=\"0A7-1L-X7y\" id=\"djV-sR-smL\"/>\n                <outlet property=\"recycleImageTextField\" destination=\"nSe-qQ-LLu\" id=\"Kkd-7p-BRu\"/>\n                <outlet property=\"recycleWarning\" destination=\"Oum-Fp-7oC\" id=\"zbc-Dp-4fP\"/>\n                <outlet property=\"recycleWarningHeightConstraint\" destination=\"0Pe-7u-Jw4\" id=\"bhh-Ta-p17\"/>\n                <outlet property=\"scriptModSheet\" destination=\"QvC-M9-y7g\" id=\"Ofq-3M-UjU\"/>\n                <outlet property=\"sheetTitleTextField\" destination=\"9jF-K1-9EN\" id=\"mEc-Pt-s0B\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"ScriptMod Sheet\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"421\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"421\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"34a-7k-94q\">\n                        <rect key=\"frame\" x=\"319\" y=\"13\" width=\"147\" height=\"32\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"135\" id=\"PzG-up-fq4\"/>\n                        </constraints>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Insert &amp; Recycle\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"h34-IA-sbs\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"configureSheetInsertExecute:\" target=\"-2\" id=\"S1v-Ga-s4Z\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0A7-1L-X7y\">\n                        <rect key=\"frame\" x=\"319\" y=\"46\" width=\"147\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Insert Only\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"gEC-FR-e9M\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"configureSheetInsert:\" target=\"-2\" id=\"c5V-7k-R0g\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f1F-Vs-kd6\">\n                        <rect key=\"frame\" x=\"14\" y=\"13\" width=\"83\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"J74-fu-rdi\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"configureSheetCancel:\" target=\"-2\" id=\"NOr-SL-ATQ\"/>\n                        </connections>\n                    </button>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nSe-qQ-LLu\">\n                        <rect key=\"frame\" x=\"291\" y=\"12\" width=\"28\" height=\"39\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" enabled=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"♻️\" id=\"zQ6-Ac-Urr\">\n                            <font key=\"font\" size=\"24\" name=\"AppleColorEmoji\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <customView placeholderIntrinsicWidth=\"480\" placeholderIntrinsicHeight=\"188\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ci1-Jv-en4\" customClass=\"ScriptModSubclassViewPlaceholder\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"154\" width=\"480\" height=\"191\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"280\" id=\"Qsn-4p-zTJ\"/>\n                        </constraints>\n                    </customView>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" verticalCompressionResistancePriority=\"250\" misplaced=\"YES\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oum-Fp-7oC\">\n                        <rect key=\"frame\" x=\"118\" y=\"74\" width=\"245\" height=\"75\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"75\" id=\"0Pe-7u-Jw4\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" enabled=\"NO\" sendsActionOnEndEditing=\"YES\" id=\"51l-tc-lfr\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">This action cannot be executed while a\nsimulation is running; a recycle will be\nnecessary for the action to take effect.</string>\n                            <color key=\"textColor\" name=\"disabledControlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <imageView horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"J3R-Qk-Jd9\">\n                        <rect key=\"frame\" x=\"20\" y=\"353\" width=\"48\" height=\"48\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"48\" id=\"eZE-oK-Ieb\"/>\n                            <constraint firstAttribute=\"height\" constant=\"48\" id=\"olv-GF-Ogn\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"NSApplicationIcon\" id=\"Tol-Ec-WJB\"/>\n                    </imageView>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7Lj-Ga-jfd\">\n                        <rect key=\"frame\" x=\"86\" y=\"384\" width=\"163\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Simulation Modification:\" id=\"zam-SA-ymZ\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9jF-K1-9EN\">\n                        <rect key=\"frame\" x=\"86\" y=\"359\" width=\"38\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Label\" id=\"A4U-xl-mfS\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"9jF-K1-9EN\" firstAttribute=\"leading\" secondItem=\"7Lj-Ga-jfd\" secondAttribute=\"leading\" id=\"2HB-CJ-R55\"/>\n                    <constraint firstItem=\"7Lj-Ga-jfd\" firstAttribute=\"leading\" secondItem=\"J3R-Qk-Jd9\" secondAttribute=\"trailing\" constant=\"20\" id=\"2YJ-aE-Rzl\"/>\n                    <constraint firstItem=\"Oum-Fp-7oC\" firstAttribute=\"top\" secondItem=\"Ci1-Jv-en4\" secondAttribute=\"bottom\" constant=\"5\" id=\"44R-2q-P1u\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Ci1-Jv-en4\" secondAttribute=\"trailing\" id=\"98x-85-y1u\"/>\n                    <constraint firstItem=\"Ci1-Jv-en4\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" id=\"HNV-bj-T3g\"/>\n                    <constraint firstAttribute=\"centerX\" secondItem=\"Oum-Fp-7oC\" secondAttribute=\"centerX\" id=\"K6S-6k-N5S\"/>\n                    <constraint firstItem=\"34a-7k-94q\" firstAttribute=\"top\" secondItem=\"0A7-1L-X7y\" secondAttribute=\"bottom\" constant=\"12\" id=\"MZ5-wR-g80\"/>\n                    <constraint firstItem=\"Ci1-Jv-en4\" firstAttribute=\"top\" secondItem=\"J3R-Qk-Jd9\" secondAttribute=\"bottom\" constant=\"8\" id=\"RBZ-Dz-3O5\"/>\n                    <constraint firstItem=\"f1F-Vs-kd6\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"T7a-rv-jh8\"/>\n                    <constraint firstItem=\"34a-7k-94q\" firstAttribute=\"leading\" secondItem=\"nSe-qQ-LLu\" secondAttribute=\"trailing\" constant=\"8\" id=\"TNI-sf-PSw\"/>\n                    <constraint firstItem=\"7Lj-Ga-jfd\" firstAttribute=\"top\" secondItem=\"J3R-Qk-Jd9\" secondAttribute=\"top\" id=\"VHY-QC-h7a\"/>\n                    <constraint firstItem=\"J3R-Qk-Jd9\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"YCJ-FJ-mIr\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"0A7-1L-X7y\" secondAttribute=\"trailing\" constant=\"20\" id=\"Yqz-4D-7Xr\"/>\n                    <constraint firstItem=\"9jF-K1-9EN\" firstAttribute=\"top\" secondItem=\"7Lj-Ga-jfd\" secondAttribute=\"bottom\" constant=\"8\" id=\"cfQ-pc-wCX\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"f1F-Vs-kd6\" secondAttribute=\"bottom\" constant=\"20\" id=\"ciX-fR-FWr\"/>\n                    <constraint firstItem=\"J3R-Qk-Jd9\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"20\" id=\"gIH-MD-o77\"/>\n                    <constraint firstItem=\"34a-7k-94q\" firstAttribute=\"width\" secondItem=\"0A7-1L-X7y\" secondAttribute=\"width\" id=\"ieB-6i-Bdg\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"34a-7k-94q\" secondAttribute=\"bottom\" constant=\"20\" id=\"om5-7f-aCa\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"nSe-qQ-LLu\" secondAttribute=\"bottom\" constant=\"12\" id=\"pb2-9u-fJA\"/>\n                    <constraint firstItem=\"0A7-1L-X7y\" firstAttribute=\"top\" secondItem=\"Oum-Fp-7oC\" secondAttribute=\"bottom\" id=\"sGf-ne-9WX\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"34a-7k-94q\" secondAttribute=\"trailing\" constant=\"20\" id=\"t0F-kj-IqP\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"1002\" y=\"619\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSApplicationIcon\" width=\"128\" height=\"128\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddGenomicElement.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddGenomicElement\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"endPositionTextField\" destination=\"BVc-Q3-esT\" id=\"yRd-aT-yHJ\"/>\n                <outlet property=\"genomicElementTypePopUpButton\" destination=\"BlU-kC-voe\" id=\"Wio-5G-LC4\"/>\n                <outlet property=\"startPositionTextField\" destination=\"hsR-7t-6Qj\" id=\"IRz-qu-5jF\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"390\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"145\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Genomic element type:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"191\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Start position on chromosome:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"243\" y=\"98\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"245\" y=\"64\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"YqX-fV-w5X\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"H8i-rj-Tcx\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"184\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"End position on chromosome:\" id=\"tjO-5l-a4O\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BVc-Q3-esT\">\n                    <rect key=\"frame\" x=\"245\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"0RB-hb-O2v\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"gtE-rw-SMk\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"M3r-3v-GNU\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"1Zh-vm-x6K\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"BVc-Q3-esT\" secondAttribute=\"leading\" id=\"84e-ce-lGw\"/>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"baseline\" secondItem=\"BVc-Q3-esT\" secondAttribute=\"baseline\" id=\"CnG-sh-6aP\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"top\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"20\" id=\"G7J-ZP-uIu\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"Hnu-aK-3fr\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"trailing\" secondItem=\"BVc-Q3-esT\" secondAttribute=\"trailing\" id=\"JPx-5A-gXr\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"leading\" id=\"QuI-F8-N5M\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"H8i-rj-Tcx\" secondAttribute=\"bottom\" constant=\"30\" id=\"byC-Un-Eb6\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652\" y=\"754\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddGenomicElementType.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddGenomicElementType\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"genomicElementTypeTextField\" destination=\"ZPc-65-xxE\" id=\"1rS-5D-NPW\"/>\n                <outlet property=\"mutationType1PopUp\" destination=\"roc-a0-gQ4\" id=\"JT6-AI-Hqz\"/>\n                <outlet property=\"mutationType1ProportionLabel\" destination=\"MNC-OH-9jP\" id=\"ash-58-67J\"/>\n                <outlet property=\"mutationType1ProportionTextField\" destination=\"cTD-YU-teQ\" id=\"FGx-1v-ddd\"/>\n                <outlet property=\"mutationType2PopUp\" destination=\"u7s-fM-TqQ\" id=\"HTB-l8-AV5\"/>\n                <outlet property=\"mutationType2ProportionLabel\" destination=\"u32-Ve-nuw\" id=\"JBg-HH-IBN\"/>\n                <outlet property=\"mutationType2ProportionTextField\" destination=\"Mci-yh-wDI\" id=\"unw-Tx-itR\"/>\n                <outlet property=\"mutationType3PopUp\" destination=\"BXy-ri-7FB\" id=\"pW1-iz-37v\"/>\n                <outlet property=\"mutationType3ProportionLabel\" destination=\"a1D-q8-j06\" id=\"Y9P-M9-Cn2\"/>\n                <outlet property=\"mutationType3ProportionTextField\" destination=\"bMJ-5i-sZC\" id=\"45E-oX-WO3\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"368\" height=\"299\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"215\" width=\"155\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Mutation type (required):\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cOx-n1-K14\">\n                    <rect key=\"frame\" x=\"48\" y=\"252\" width=\"161\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Genomic element type ID:\" id=\"ka4-JZ-KPg\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"64\" y=\"178\" width=\"123\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Relative proportion:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"223\" y=\"175\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZPc-65-xxE\">\n                    <rect key=\"frame\" x=\"233\" y=\"249\" width=\"85\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"bV4-f4-Ufu\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"xPv-XB-juX\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wuS-fR-NLv\">\n                    <rect key=\"frame\" x=\"221\" y=\"252\" width=\"12\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"g\" id=\"T89-Dc-d53\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sjz-yG-jNG\">\n                    <rect key=\"frame\" x=\"48\" y=\"141\" width=\"153\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Mutation type (optional):\" id=\"V5w-og-aQ8\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u32-Ve-nuw\">\n                    <rect key=\"frame\" x=\"64\" y=\"104\" width=\"123\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Relative proportion:\" id=\"dxU-L5-olu\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mci-yh-wDI\">\n                    <rect key=\"frame\" x=\"223\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"gU0-Tt-mHo\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gmt-DC-xJL\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u7s-fM-TqQ\">\n                    <rect key=\"frame\" x=\"221\" y=\"135\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"3Xo-h9-LNV\" id=\"A1J-ex-bcm\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"U1z-t7-huI\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"3Xo-h9-LNV\"/>\n                                <menuItem title=\"Item 2\" id=\"kfv-5D-pGw\"/>\n                                <menuItem title=\"Item 3\" id=\"hgT-NP-JdN\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"3x2-wG-Vq5\"/>\n                    </connections>\n                </popUpButton>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8c-ix-Lrx\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"153\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Mutation type (optional):\" id=\"5iH-xf-6ta\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"a1D-q8-j06\">\n                    <rect key=\"frame\" x=\"64\" y=\"30\" width=\"123\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Relative proportion:\" id=\"4lL-Dn-jSI\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bMJ-5i-sZC\">\n                    <rect key=\"frame\" x=\"223\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"dXh-p2-myg\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Rt2-Hk-sbY\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BXy-ri-7FB\">\n                    <rect key=\"frame\" x=\"221\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"fi7-Ns-La9\" id=\"Pb3-fl-NEb\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ytX-bq-h7i\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"fi7-Ns-La9\"/>\n                                <menuItem title=\"Item 2\" id=\"y3Q-Mb-Q3i\"/>\n                                <menuItem title=\"Item 3\" id=\"7K4-50-Lps\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"6NN-xl-T30\"/>\n                    </connections>\n                </popUpButton>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"roc-a0-gQ4\">\n                    <rect key=\"frame\" x=\"221\" y=\"209\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"oTi-Pj-wM8\" id=\"TQN-sm-J8P\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"zDo-Tu-ch7\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"oTi-Pj-wM8\"/>\n                                <menuItem title=\"Item 2\" id=\"tYa-tP-v2c\"/>\n                                <menuItem title=\"Item 3\" id=\"TXX-pz-udw\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"2Ca-kk-T9a\"/>\n                <constraint firstItem=\"roc-a0-gQ4\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"2He-St-13n\"/>\n                <constraint firstItem=\"wuS-fR-NLv\" firstAttribute=\"baseline\" secondItem=\"ZPc-65-xxE\" secondAttribute=\"baseline\" id=\"4y7-be-FH3\"/>\n                <constraint firstItem=\"a1D-q8-j06\" firstAttribute=\"leading\" secondItem=\"M8c-ix-Lrx\" secondAttribute=\"leading\" constant=\"16\" id=\"7U7-cv-GYV\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"9LN-QE-mOr\"/>\n                <constraint firstItem=\"wuS-fR-NLv\" firstAttribute=\"leading\" secondItem=\"cOx-n1-K14\" secondAttribute=\"trailing\" constant=\"16\" id=\"9u5-4Y-LdH\"/>\n                <constraint firstItem=\"sjz-yG-jNG\" firstAttribute=\"leading\" secondItem=\"M8c-ix-Lrx\" secondAttribute=\"leading\" id=\"Aag-iu-MPn\"/>\n                <constraint firstItem=\"BXy-ri-7FB\" firstAttribute=\"baseline\" secondItem=\"M8c-ix-Lrx\" secondAttribute=\"baseline\" id=\"C9y-zE-CJz\"/>\n                <constraint firstItem=\"u7s-fM-TqQ\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"Cq0-Yw-fCf\"/>\n                <constraint firstItem=\"u32-Ve-nuw\" firstAttribute=\"top\" secondItem=\"sjz-yG-jNG\" secondAttribute=\"bottom\" constant=\"20\" id=\"EVP-Mm-2Gx\"/>\n                <constraint firstItem=\"bMJ-5i-sZC\" firstAttribute=\"baseline\" secondItem=\"a1D-q8-j06\" secondAttribute=\"baseline\" id=\"LsD-R3-1Ed\"/>\n                <constraint firstItem=\"ZPc-65-xxE\" firstAttribute=\"leading\" secondItem=\"wuS-fR-NLv\" secondAttribute=\"trailing\" constant=\"2\" id=\"Nea-lM-hZh\"/>\n                <constraint firstItem=\"sjz-yG-jNG\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"Pjy-Od-I4L\"/>\n                <constraint firstItem=\"BXy-ri-7FB\" firstAttribute=\"leading\" secondItem=\"bMJ-5i-sZC\" secondAttribute=\"leading\" id=\"QrU-00-uSd\"/>\n                <constraint firstItem=\"Mci-yh-wDI\" firstAttribute=\"baseline\" secondItem=\"u32-Ve-nuw\" secondAttribute=\"baseline\" id=\"QvB-Xl-isa\"/>\n                <constraint firstItem=\"Mci-yh-wDI\" firstAttribute=\"leading\" secondItem=\"BXy-ri-7FB\" secondAttribute=\"leading\" id=\"Rpa-b2-TQ8\"/>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"baseline\" secondItem=\"ZPc-65-xxE\" secondAttribute=\"baseline\" id=\"Rsn-0V-xVq\"/>\n                <constraint firstItem=\"a1D-q8-j06\" firstAttribute=\"top\" secondItem=\"M8c-ix-Lrx\" secondAttribute=\"bottom\" constant=\"20\" id=\"Sgk-sN-FlN\"/>\n                <constraint firstItem=\"Mci-yh-wDI\" firstAttribute=\"trailing\" secondItem=\"BXy-ri-7FB\" secondAttribute=\"trailing\" id=\"WfQ-SH-HfU\"/>\n                <constraint firstItem=\"roc-a0-gQ4\" firstAttribute=\"baseline\" secondItem=\"cXU-20-n64\" secondAttribute=\"baseline\" id=\"Zf3-d2-7zv\"/>\n                <constraint firstItem=\"Mci-yh-wDI\" firstAttribute=\"leading\" secondItem=\"u7s-fM-TqQ\" secondAttribute=\"leading\" id=\"bmM-Me-L6h\"/>\n                <constraint firstItem=\"ZPc-65-xxE\" firstAttribute=\"trailing\" secondItem=\"roc-a0-gQ4\" secondAttribute=\"trailing\" id=\"eAf-sj-Xk9\"/>\n                <constraint firstItem=\"M8c-ix-Lrx\" firstAttribute=\"top\" secondItem=\"u32-Ve-nuw\" secondAttribute=\"bottom\" constant=\"20\" id=\"eHq-zY-yVZ\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"wuS-fR-NLv\" firstAttribute=\"leading\" secondItem=\"roc-a0-gQ4\" secondAttribute=\"leading\" id=\"fcN-nj-fHX\"/>\n                <constraint firstItem=\"roc-a0-gQ4\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"h70-MB-OAH\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"a1D-q8-j06\" secondAttribute=\"bottom\" constant=\"30\" id=\"hjl-Dh-RFf\"/>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"lNV-n1-Tc7\"/>\n                <constraint firstItem=\"sjz-yG-jNG\" firstAttribute=\"leading\" secondItem=\"u32-Ve-nuw\" secondAttribute=\"leading\" constant=\"-16\" id=\"nz9-ol-D4Q\"/>\n                <constraint firstItem=\"Mci-yh-wDI\" firstAttribute=\"trailing\" secondItem=\"u7s-fM-TqQ\" secondAttribute=\"trailing\" id=\"pgD-ES-Sz5\"/>\n                <constraint firstItem=\"u7s-fM-TqQ\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"qWd-aa-DX3\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" constant=\"16\" id=\"rvE-oe-CEB\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"cOx-n1-K14\" secondAttribute=\"bottom\" constant=\"20\" id=\"tJg-nU-3hq\"/>\n                <constraint firstItem=\"sjz-yG-jNG\" firstAttribute=\"baseline\" secondItem=\"u7s-fM-TqQ\" secondAttribute=\"baseline\" id=\"tbw-OB-2P7\"/>\n                <constraint firstItem=\"sjz-yG-jNG\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"urT-2X-mpx\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n                <constraint firstItem=\"BXy-ri-7FB\" firstAttribute=\"trailing\" secondItem=\"bMJ-5i-sZC\" secondAttribute=\"trailing\" id=\"vf5-EW-TJC\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" constant=\"50\" id=\"ytj-dS-ngZ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"1165\" y=\"822.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddMutationType.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddMutationType\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"dfeMatrix\" destination=\"Z6u-JF-pWh\" id=\"8r1-0N-Ua2\"/>\n                <outlet property=\"dominanceCoeffTextField\" destination=\"cTD-YU-teQ\" id=\"6GX-oh-1ry\"/>\n                <outlet property=\"expDFEParamsLabel\" destination=\"hlU-1m-oiW\" id=\"Gg5-0l-6N6\"/>\n                <outlet property=\"expMeanSelCoeffTextField\" destination=\"A9m-zx-Cqm\" id=\"fIm-aO-6mN\"/>\n                <outlet property=\"fixedDFEParamsLabel\" destination=\"51m-Ec-JxJ\" id=\"QuC-T3-FJL\"/>\n                <outlet property=\"fixedSelCoeffTextField\" destination=\"KCS-12-u90\" id=\"0LK-7z-ZYO\"/>\n                <outlet property=\"gammaAlphaTextField\" destination=\"bod-vy-Nug\" id=\"0Aa-Xy-qv5\"/>\n                <outlet property=\"gammaDFEParamsLabel1\" destination=\"dEy-Kr-vHN\" id=\"5sV-uv-add\"/>\n                <outlet property=\"gammaDFEParamsLabel2\" destination=\"oPv-qF-akv\" id=\"bkH-AE-nSQ\"/>\n                <outlet property=\"gammaMeanSelCoeffTextField\" destination=\"4a1-Sa-eLB\" id=\"5xc-oT-AFG\"/>\n                <outlet property=\"mutationTypeTextField\" destination=\"ZPc-65-xxE\" id=\"3jw-4d-QCH\"/>\n                <outlet property=\"normalDFEParamsLabel1\" destination=\"2Or-GI-HyT\" id=\"ihY-Fh-4dq\"/>\n                <outlet property=\"normalDFEParamsLabel2\" destination=\"OT8-yW-g1p\" id=\"XLv-Ni-7y5\"/>\n                <outlet property=\"normalMeanSelCoeffTextField\" destination=\"GJg-kH-xu5\" id=\"dje-Bd-Xfh\"/>\n                <outlet property=\"normalSigmaTextField\" destination=\"61g-qU-gAZ\" id=\"rPf-L9-x3U\"/>\n                <outlet property=\"weibullDFEParamsLabel1\" destination=\"1Um-3K-XYf\" id=\"evl-jK-ou7\"/>\n                <outlet property=\"weibullDFEParamsLabel2\" destination=\"J9d-Mh-tJR\" id=\"6L2-SQ-pNb\"/>\n                <outlet property=\"weibullKTextField\" destination=\"3ZV-r4-Vn6\" id=\"dNI-J0-ila\"/>\n                <outlet property=\"weibullLambdaTextField\" destination=\"F9h-B3-u6X\" id=\"Zfk-2H-5vS\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"387\" height=\"339\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"255\" width=\"144\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Dominance coefficient:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cOx-n1-K14\">\n                    <rect key=\"frame\" x=\"48\" y=\"292\" width=\"108\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Mutation type ID:\" id=\"ka4-JZ-KPg\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"218\" width=\"184\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Distribution of fitness effects:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"51m-Ec-JxJ\">\n                    <rect key=\"frame\" x=\"172\" y=\"181\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"s = \" id=\"QVF-8i-swT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"242\" y=\"252\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KCS-12-u90\">\n                    <rect key=\"frame\" x=\"199\" y=\"178\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"4U8-g7-oZ4\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"oxU-SC-a2j\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"0Gz-6n-Ld4\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hlU-1m-oiW\">\n                    <rect key=\"frame\" x=\"172\" y=\"144\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"s̄ = \" id=\"dCz-4I-Nym\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A9m-zx-Cqm\">\n                    <rect key=\"frame\" x=\"199\" y=\"141\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"KDx-hC-AxA\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"nBd-4L-ZHy\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"qi7-F7-CLR\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dEy-Kr-vHN\">\n                    <rect key=\"frame\" x=\"172\" y=\"107\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"s̄ = \" id=\"3OX-P4-Cea\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4a1-Sa-eLB\">\n                    <rect key=\"frame\" x=\"199\" y=\"104\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"LJZ-il-ARl\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"hEB-Pz-C9d\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"3dN-hi-dbU\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oPv-qF-akv\">\n                    <rect key=\"frame\" x=\"264\" y=\"107\" width=\"28\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"α = \" id=\"8qc-7K-3QJ\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bod-vy-Nug\">\n                    <rect key=\"frame\" x=\"292\" y=\"104\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"xXX-u8-4QK\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"iBY-n0-IgG\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"aBM-f9-tpg\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Or-GI-HyT\">\n                    <rect key=\"frame\" x=\"172\" y=\"70\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"s̄ = \" id=\"9jb-Qb-sT9\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GJg-kH-xu5\">\n                    <rect key=\"frame\" x=\"199\" y=\"67\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"UAC-GE-38U\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"cOo-xa-JH3\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"F7d-cK-PWq\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"61g-qU-gAZ\">\n                    <rect key=\"frame\" x=\"292\" y=\"67\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"5gG-so-1gn\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"Ssh-Ha-sAA\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"P7w-RM-CrM\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZPc-65-xxE\">\n                    <rect key=\"frame\" x=\"256\" y=\"289\" width=\"81\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"bV4-f4-Ufu\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"xPv-XB-juX\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wuS-fR-NLv\">\n                    <rect key=\"frame\" x=\"240\" y=\"292\" width=\"16\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"m\" id=\"T89-Dc-d53\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <matrix verticalHuggingPriority=\"750\" allowsEmptySelection=\"NO\" autorecalculatesCellSize=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z6u-JF-pWh\">\n                    <rect key=\"frame\" x=\"67\" y=\"32\" width=\"97\" height=\"166\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"166\" id=\"dke-gV-f4d\"/>\n                        <constraint firstAttribute=\"width\" constant=\"97\" id=\"rMF-YE-lXI\"/>\n                    </constraints>\n                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    <size key=\"cellSize\" width=\"97\" height=\"18\"/>\n                    <size key=\"intercellSpacing\" width=\"4\" height=\"19\"/>\n                    <buttonCell key=\"prototype\" type=\"radio\" title=\"Radio\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"0Nx-KX-KYI\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <cells>\n                        <column>\n                            <buttonCell type=\"radio\" title=\"Fixed:\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"3BF-OH-txs\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Exponential:\" imagePosition=\"left\" alignment=\"left\" tag=\"1\" inset=\"2\" id=\"u5Z-HQ-9XT\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Gamma:\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"Fmq-Tn-Unz\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Normal:\" imagePosition=\"left\" alignment=\"left\" tag=\"3\" inset=\"2\" id=\"vkF-Y6-w2M\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Weibull:\" imagePosition=\"left\" alignment=\"left\" tag=\"4\" inset=\"2\" id=\"FwA-qa-qWV\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </column>\n                    </cells>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"ysw-bp-ky0\"/>\n                    </connections>\n                </matrix>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OT8-yW-g1p\">\n                    <rect key=\"frame\" x=\"264\" y=\"70\" width=\"28\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"σ = \" id=\"Kwb-o4-EZY\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Um-3K-XYf\">\n                    <rect key=\"frame\" x=\"172\" y=\"33\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"λ = \" id=\"i9E-rs-Mb7\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"F9h-B3-u6X\">\n                    <rect key=\"frame\" x=\"199\" y=\"30\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"aIt-nP-dDp\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"sf5-Qb-LUa\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"JiH-8K-z7g\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3ZV-r4-Vn6\">\n                    <rect key=\"frame\" x=\"292\" y=\"30\" width=\"45\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"45\" id=\"zMe-Ls-G8u\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"Bg4-tg-uLp\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"uEj-nv-h5R\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"J9d-Mh-tJR\">\n                    <rect key=\"frame\" x=\"264\" y=\"33\" width=\"27\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"k = \" id=\"f0a-Cf-Unb\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"2Or-GI-HyT\" firstAttribute=\"top\" secondItem=\"dEy-Kr-vHN\" secondAttribute=\"bottom\" constant=\"20\" id=\"02Y-bq-KM9\"/>\n                <constraint firstItem=\"oPv-qF-akv\" firstAttribute=\"leading\" secondItem=\"4a1-Sa-eLB\" secondAttribute=\"trailing\" constant=\"22\" id=\"0l7-j3-BxZ\"/>\n                <constraint firstItem=\"bod-vy-Nug\" firstAttribute=\"baseline\" secondItem=\"oPv-qF-akv\" secondAttribute=\"baseline\" id=\"1DE-B6-Etc\"/>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"2Ca-kk-T9a\"/>\n                <constraint firstItem=\"J9d-Mh-tJR\" firstAttribute=\"leading\" secondItem=\"F9h-B3-u6X\" secondAttribute=\"trailing\" constant=\"22\" id=\"2ka-bZ-Hmd\"/>\n                <constraint firstItem=\"bod-vy-Nug\" firstAttribute=\"leading\" secondItem=\"oPv-qF-akv\" secondAttribute=\"trailing\" constant=\"2\" id=\"3B9-te-Wpc\"/>\n                <constraint firstItem=\"OT8-yW-g1p\" firstAttribute=\"leading\" secondItem=\"GJg-kH-xu5\" secondAttribute=\"trailing\" constant=\"22\" id=\"3V2-eE-eqh\"/>\n                <constraint firstItem=\"wuS-fR-NLv\" firstAttribute=\"baseline\" secondItem=\"ZPc-65-xxE\" secondAttribute=\"baseline\" id=\"4y7-be-FH3\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"Z6u-JF-pWh\" secondAttribute=\"leading\" constant=\"-17\" id=\"6Pf-C2-YLb\"/>\n                <constraint firstItem=\"GJg-kH-xu5\" firstAttribute=\"baseline\" secondItem=\"2Or-GI-HyT\" secondAttribute=\"baseline\" id=\"7af-zr-jRk\"/>\n                <constraint firstItem=\"KCS-12-u90\" firstAttribute=\"leading\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"leading\" id=\"7ut-cD-aEB\"/>\n                <constraint firstItem=\"4a1-Sa-eLB\" firstAttribute=\"trailing\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"trailing\" id=\"Chg-1q-Iq0\"/>\n                <constraint firstItem=\"F9h-B3-u6X\" firstAttribute=\"baseline\" secondItem=\"J9d-Mh-tJR\" secondAttribute=\"baseline\" id=\"DHu-1K-7cv\"/>\n                <constraint firstItem=\"2Or-GI-HyT\" firstAttribute=\"leading\" secondItem=\"dEy-Kr-vHN\" secondAttribute=\"leading\" id=\"Glj-KR-ima\"/>\n                <constraint firstItem=\"4a1-Sa-eLB\" firstAttribute=\"baseline\" secondItem=\"oPv-qF-akv\" secondAttribute=\"baseline\" id=\"HY4-RO-sKd\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"leading\" secondItem=\"Z6u-JF-pWh\" secondAttribute=\"trailing\" constant=\"10\" id=\"HmE-zI-YqF\"/>\n                <constraint firstItem=\"1Um-3K-XYf\" firstAttribute=\"top\" secondItem=\"2Or-GI-HyT\" secondAttribute=\"bottom\" constant=\"20\" id=\"HoN-HQ-Oub\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"F9h-B3-u6X\" firstAttribute=\"baseline\" secondItem=\"1Um-3K-XYf\" secondAttribute=\"baseline\" id=\"Mgn-SN-IU9\"/>\n                <constraint firstItem=\"Z6u-JF-pWh\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"N3p-4x-woB\"/>\n                <constraint firstItem=\"ZPc-65-xxE\" firstAttribute=\"leading\" secondItem=\"wuS-fR-NLv\" secondAttribute=\"trailing\" constant=\"2\" id=\"Nea-lM-hZh\"/>\n                <constraint firstItem=\"61g-qU-gAZ\" firstAttribute=\"leading\" secondItem=\"OT8-yW-g1p\" secondAttribute=\"trailing\" constant=\"2\" id=\"ORQ-zX-JyS\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"leading\" secondItem=\"51m-Ec-JxJ\" secondAttribute=\"leading\" id=\"OhR-TY-mXL\"/>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"baseline\" secondItem=\"ZPc-65-xxE\" secondAttribute=\"baseline\" id=\"Rsn-0V-xVq\"/>\n                <constraint firstItem=\"51m-Ec-JxJ\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"Xz6-7G-0xy\"/>\n                <constraint firstItem=\"51m-Ec-JxJ\" firstAttribute=\"baseline\" secondItem=\"KCS-12-u90\" secondAttribute=\"baseline\" id=\"ZGs-w7-Cvj\"/>\n                <constraint firstItem=\"wuS-fR-NLv\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"ZRr-7Y-gz6\"/>\n                <constraint firstItem=\"ZPc-65-xxE\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"ar7-fv-2Eb\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"baseline\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"baseline\" id=\"b6v-je-T8U\"/>\n                <constraint firstItem=\"1Um-3K-XYf\" firstAttribute=\"leading\" secondItem=\"2Or-GI-HyT\" secondAttribute=\"leading\" id=\"blF-KA-Wj3\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"leading\" secondItem=\"dEy-Kr-vHN\" secondAttribute=\"leading\" id=\"chS-76-wFo\"/>\n                <constraint firstItem=\"GJg-kH-xu5\" firstAttribute=\"leading\" secondItem=\"2Or-GI-HyT\" secondAttribute=\"trailing\" constant=\"2\" id=\"eNG-JY-AgW\"/>\n                <constraint firstItem=\"61g-qU-gAZ\" firstAttribute=\"baseline\" secondItem=\"OT8-yW-g1p\" secondAttribute=\"baseline\" id=\"eft-Op-oRN\"/>\n                <constraint firstItem=\"dEy-Kr-vHN\" firstAttribute=\"top\" secondItem=\"hlU-1m-oiW\" secondAttribute=\"bottom\" constant=\"20\" id=\"ep7-e7-QH6\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"top\" secondItem=\"51m-Ec-JxJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"jKP-Ze-h8v\"/>\n                <constraint firstItem=\"3ZV-r4-Vn6\" firstAttribute=\"leading\" secondItem=\"J9d-Mh-tJR\" secondAttribute=\"trailing\" constant=\"3\" id=\"jgi-Qm-uAq\"/>\n                <constraint firstItem=\"cOx-n1-K14\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"lNV-n1-Tc7\"/>\n                <constraint firstItem=\"F9h-B3-u6X\" firstAttribute=\"leading\" secondItem=\"1Um-3K-XYf\" secondAttribute=\"trailing\" constant=\"2\" id=\"lll-77-fSm\"/>\n                <constraint firstItem=\"4a1-Sa-eLB\" firstAttribute=\"baseline\" secondItem=\"dEy-Kr-vHN\" secondAttribute=\"baseline\" id=\"lt9-XZ-w6V\"/>\n                <constraint firstItem=\"GJg-kH-xu5\" firstAttribute=\"baseline\" secondItem=\"OT8-yW-g1p\" secondAttribute=\"baseline\" id=\"mlJ-Cz-Rih\"/>\n                <constraint firstItem=\"4a1-Sa-eLB\" firstAttribute=\"leading\" secondItem=\"dEy-Kr-vHN\" secondAttribute=\"trailing\" constant=\"2\" id=\"npk-Jd-sIY\"/>\n                <constraint firstItem=\"3ZV-r4-Vn6\" firstAttribute=\"baseline\" secondItem=\"J9d-Mh-tJR\" secondAttribute=\"baseline\" id=\"nu3-n4-shn\"/>\n                <constraint firstItem=\"bod-vy-Nug\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"oal-RV-tw1\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"F9h-B3-u6X\" secondAttribute=\"bottom\" constant=\"30\" id=\"tHp-kU-71z\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"cOx-n1-K14\" secondAttribute=\"bottom\" constant=\"20\" id=\"tJg-nU-3hq\"/>\n                <constraint firstItem=\"4a1-Sa-eLB\" firstAttribute=\"leading\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"leading\" id=\"tjM-0y-aS5\"/>\n                <constraint firstItem=\"KCS-12-u90\" firstAttribute=\"trailing\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"trailing\" id=\"uYY-dN-yPQ\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" constant=\"50\" id=\"ytj-dS-ngZ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"1164.5\" y=\"776\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddRecombinationRate.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10117\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddRecombinationRate\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"recombinationRateTextField\" destination=\"BVc-Q3-esT\" id=\"r1G-af-2jw\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"372\" height=\"77\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"H8i-rj-Tcx\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"126\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Recombination rate:\" id=\"tjO-5l-a4O\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BVc-Q3-esT\">\n                    <rect key=\"frame\" x=\"227\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"0RB-hb-O2v\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"gtE-rw-SMk\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"M3r-3v-GNU\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"baseline\" secondItem=\"BVc-Q3-esT\" secondAttribute=\"baseline\" id=\"CnG-sh-6aP\"/>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"U8o-Hn-TuS\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"H8i-rj-Tcx\" secondAttribute=\"bottom\" constant=\"30\" id=\"byC-Un-Eb6\"/>\n                <constraint firstItem=\"H8i-rj-Tcx\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"jX8-6i-KUy\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"BVc-Q3-esT\" secondAttribute=\"trailing\" constant=\"50\" id=\"nBi-l8-ATd\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"522\" y=\"589.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddSexConfiguration.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddSexConfiguration\">\n            <connections>\n                <outlet property=\"chromosomeTypeMatrix\" destination=\"Z6u-JF-pWh\" id=\"2EG-N4-PEQ\"/>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"dominanceCoeffLabel\" destination=\"hlU-1m-oiW\" id=\"eKO-2i-b9t\"/>\n                <outlet property=\"dominanceCoeffTextField\" destination=\"A9m-zx-Cqm\" id=\"dit-j9-8gM\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"376\" height=\"191\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"144\" width=\"120\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Chromosome type:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hlU-1m-oiW\">\n                    <rect key=\"frame\" x=\"205\" y=\"70\" width=\"28\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"d = \" id=\"dCz-4I-Nym\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField toolTip=\"dominance coefficient for X-linked loci\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A9m-zx-Cqm\">\n                    <rect key=\"frame\" x=\"231\" y=\"67\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"KDx-hC-AxA\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"nBd-4L-ZHy\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"qi7-F7-CLR\"/>\n                    </connections>\n                </textField>\n                <matrix toolTip=\"chromosome to model\" verticalHuggingPriority=\"750\" allowsEmptySelection=\"NO\" autorecalculatesCellSize=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z6u-JF-pWh\">\n                    <rect key=\"frame\" x=\"67\" y=\"30\" width=\"120\" height=\"94\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"94\" id=\"dke-gV-f4d\"/>\n                        <constraint firstAttribute=\"width\" constant=\"120\" id=\"rMF-YE-lXI\"/>\n                    </constraints>\n                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    <size key=\"cellSize\" width=\"118\" height=\"18\"/>\n                    <size key=\"intercellSpacing\" width=\"4\" height=\"19\"/>\n                    <buttonCell key=\"prototype\" type=\"radio\" title=\"Radio\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"0Nx-KX-KYI\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <cells>\n                        <column>\n                            <buttonCell type=\"radio\" title=\"Autosome\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"3BF-OH-txs\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"X chromosome:\" imagePosition=\"left\" alignment=\"left\" tag=\"1\" inset=\"2\" id=\"u5Z-HQ-9XT\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Y chromosome\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"Fmq-Tn-Unz\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </column>\n                    </cells>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"ysw-bp-ky0\"/>\n                    </connections>\n                </matrix>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"06W-1z-040\"/>\n                <constraint firstItem=\"Z6u-JF-pWh\" firstAttribute=\"centerY\" secondItem=\"hlU-1m-oiW\" secondAttribute=\"centerY\" constant=\"1.5\" id=\"4Z6-C9-p7k\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"Z6u-JF-pWh\" secondAttribute=\"leading\" constant=\"-17\" id=\"6Pf-C2-YLb\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"trailing\" constant=\"50\" id=\"82g-b7-HDg\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"leading\" secondItem=\"Z6u-JF-pWh\" secondAttribute=\"trailing\" constant=\"20\" id=\"HmE-zI-YqF\"/>\n                <constraint firstItem=\"Z6u-JF-pWh\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"N3p-4x-woB\"/>\n                <constraint firstItem=\"A9m-zx-Cqm\" firstAttribute=\"leading\" secondItem=\"hlU-1m-oiW\" secondAttribute=\"trailing\" id=\"TyM-lo-q0e\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"Z6u-JF-pWh\" secondAttribute=\"bottom\" constant=\"30\" id=\"ZKf-28-32C\"/>\n                <constraint firstItem=\"hlU-1m-oiW\" firstAttribute=\"baseline\" secondItem=\"A9m-zx-Cqm\" secondAttribute=\"baseline\" id=\"b6v-je-T8U\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"fXS-UM-lOX\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"1165\" y=\"776\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_AddSubpop.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_AddSubpop\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"subpopSizeTextField\" destination=\"hsR-7t-6Qj\" id=\"n4d-S2-ZYs\"/>\n                <outlet property=\"subpopTextField\" destination=\"6Df-tQ-Vse\" id=\"b51-pX-tQi\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"364\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"148\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for addition:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"138\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to add:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"165\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Added subpopulation size:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"219\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6Df-tQ-Vse\">\n                    <rect key=\"frame\" x=\"229\" y=\"64\" width=\"85\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"33G-kc-ztx\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"OSI-dg-OKT\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"219\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6zZ-IL-QHt\">\n                    <rect key=\"frame\" x=\"217\" y=\"67\" width=\"12\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"p\" id=\"RB1-pr-vh0\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"6Df-tQ-Vse\" firstAttribute=\"leading\" secondItem=\"6zZ-IL-QHt\" secondAttribute=\"trailing\" constant=\"2\" id=\"4b1-sZ-mwQ\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"6zZ-IL-QHt\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"FqE-vY-IAS\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"6zZ-IL-QHt\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"Lmb-da-ejG\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"QvM-8Y-maA\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"baseline\" secondItem=\"6Df-tQ-Vse\" secondAttribute=\"baseline\" id=\"i9e-gv-zDS\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"6Df-tQ-Vse\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"mYT-o5-puS\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"trailing\" secondItem=\"6Df-tQ-Vse\" secondAttribute=\"trailing\" id=\"v9Q-Oa-Li4\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_ChangeCloning.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_ChangeCloning\">\n            <connections>\n                <outlet property=\"cloningRateTextField\" destination=\"hsR-7t-6Qj\" id=\"pnM-Eq-BNN\"/>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"399\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"144\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for change:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"160\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to change:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"200\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"New subpopulation cloning rate:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"254\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"252\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"254\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652.5\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_ChangeMigration.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_ChangeMigration\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"migrationRateTextField\" destination=\"hsR-7t-6Qj\" id=\"aWO-x6-EdU\"/>\n                <outlet property=\"sourceSubpopPopUpButton\" destination=\"1Ju-FG-xG6\" id=\"bAt-hK-chp\"/>\n                <outlet property=\"targetSubpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"sNd-OF-Ax1\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"340\" height=\"188\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"141\" width=\"135\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for resize:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"137\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Target subpopulation:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GQV-5w-gus\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"141\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Source subpopulation:\" id=\"bDo-aM-1xx\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"123\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"New migration rate:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"195\" y=\"138\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"193\" y=\"98\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"CPm-n0-J94\"/>\n                    </connections>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"195\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Ju-FG-xG6\">\n                    <rect key=\"frame\" x=\"193\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"fQY-zg-Ge1\" id=\"JDf-XK-upq\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"aF5-15-yJC\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"fQY-zg-Ge1\"/>\n                                <menuItem title=\"Item 2\" id=\"Sg6-pY-HQv\"/>\n                                <menuItem title=\"Item 3\" id=\"yLg-0x-4PC\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <action selector=\"validateControls:\" target=\"-2\" id=\"c7q-x7-Stm\"/>\n                    </connections>\n                </popUpButton>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"1Ju-FG-xG6\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"ETH-IF-x3B\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"1Ju-FG-xG6\" secondAttribute=\"leading\" id=\"N53-ti-U32\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"GQV-5w-gus\" secondAttribute=\"bottom\" constant=\"20\" id=\"Z6V-51-Ahv\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"1Ju-FG-xG6\" secondAttribute=\"trailing\" id=\"aXa-en-zbm\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"GQV-5w-gus\" secondAttribute=\"leading\" id=\"bDk-kg-RUR\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"1Ju-FG-xG6\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"gzi-O3-DdU\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"GQV-5w-gus\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"leading\" id=\"jIF-RF-ps3\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"GQV-5w-gus\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"nLf-kQ-SYv\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"1Ju-FG-xG6\" firstAttribute=\"baseline\" secondItem=\"GQV-5w-gus\" secondAttribute=\"baseline\" id=\"reu-Ef-vCw\"/>\n                <constraint firstItem=\"1Ju-FG-xG6\" firstAttribute=\"leading\" secondItem=\"GQV-5w-gus\" secondAttribute=\"trailing\" constant=\"8\" id=\"v3A-L1-YJj\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652.5\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_ChangeSelfing.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_ChangeSelfing\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"selfingRateTextField\" destination=\"hsR-7t-6Qj\" id=\"Adq-Fr-a7c\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"395\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"144\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for change:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"160\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to change:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"196\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"New subpopulation selfing rate:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"250\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"248\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"250\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652.5\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_ChangeSexRatio.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_ChangeSexRatio\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"sexRatioTextField\" destination=\"hsR-7t-6Qj\" id=\"KMx-bb-fHy\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"379\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"144\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for change:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"160\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to change:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"180\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"New subpopulation sex ratio:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"234\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"232\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"234\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652.5\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_ChangeSubpopSize.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_ChangeSubpopSize\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n                <outlet property=\"subpopSizeTextField\" destination=\"hsR-7t-6Qj\" id=\"n4d-S2-ZYs\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"351\" height=\"151\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"135\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for resize:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"151\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to resize:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"152\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"New subpopulation size:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"206\" y=\"101\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"204\" y=\"61\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"206\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652.5\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_OutputFixedMutations.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_OutputFixedMutations\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"338\" height=\"77\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"139\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for output:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"193\" y=\"27\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"trailing\" constant=\"8\" id=\"NL2-ye-dYk\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"30\" id=\"QyK-xp-h34\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" constant=\"50\" id=\"oQk-EW-HwX\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_OutputFullPopulation.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_OutputFullPopulation\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"filenameTextField\" destination=\"hsR-7t-6Qj\" id=\"xNG-iY-CC4\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"493\" height=\"114\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"139\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for output:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"131\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Filename or file path:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"193\" y=\"64\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"193\" y=\"27\" width=\"250\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"250\" id=\"BNs-Oq-Oij\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"EFF-6H-9Sz\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"trailing\" constant=\"8\" id=\"NL2-ye-dYk\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"QvM-8Y-maA\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"prt-o4-Deb\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"30\" id=\"qrF-9o-0ao\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_OutputSubpopSample.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_OutputSubpopSample\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"sampleSizeTextField\" destination=\"hsR-7t-6Qj\" id=\"apC-j4-peK\"/>\n                <outlet property=\"sampleWithReplacementCheckbox\" destination=\"TjJ-nx-Qb8\" id=\"vVd-Nj-zul\"/>\n                <outlet property=\"sampledSexMatrix\" destination=\"dfP-Ze-LJe\" id=\"A3L-Oz-yOw\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n                <outlet property=\"useFormatMatrix\" destination=\"hJq-Nw-0S0\" id=\"JBO-h5-KXz\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"388\" height=\"324\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"277\" width=\"139\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for output:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"240\" width=\"159\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to sample:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"203\" width=\"81\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Sample size:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9nO-6z-CmL\">\n                    <rect key=\"frame\" x=\"48\" y=\"146\" width=\"115\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Take sample from:\" id=\"0R1-4K-zdd\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"213\" y=\"274\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"211\" y=\"234\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"213\" y=\"200\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n                <matrix verticalHuggingPriority=\"1000\" allowsEmptySelection=\"NO\" autorecalculatesCellSize=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dfP-Ze-LJe\">\n                    <rect key=\"frame\" x=\"211\" y=\"105\" width=\"120\" height=\"58\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"120\" id=\"ohS-0B-z2G\"/>\n                    </constraints>\n                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    <size key=\"cellSize\" width=\"105\" height=\"18\"/>\n                    <size key=\"intercellSpacing\" width=\"4\" height=\"2\"/>\n                    <buttonCell key=\"prototype\" type=\"radio\" title=\"Radio\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"tbX-OZ-Mg6\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <cells>\n                        <column>\n                            <buttonCell type=\"radio\" title=\"All individuals\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"0vP-mS-XHz\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Males only\" imagePosition=\"left\" alignment=\"left\" tag=\"1\" inset=\"2\" id=\"eEc-wd-Gk3\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"Females only\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"ETv-kK-Nnw\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </column>\n                    </cells>\n                </matrix>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1z6-PP-cMp\">\n                    <rect key=\"frame\" x=\"48\" y=\"71\" width=\"119\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Use output format:\" id=\"x3D-8E-M65\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <matrix verticalHuggingPriority=\"1000\" allowsEmptySelection=\"NO\" autorecalculatesCellSize=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hJq-Nw-0S0\">\n                    <rect key=\"frame\" x=\"211\" y=\"30\" width=\"65\" height=\"58\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"65\" id=\"iAl-Gc-NQR\"/>\n                    </constraints>\n                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    <size key=\"cellSize\" width=\"65\" height=\"18\"/>\n                    <size key=\"intercellSpacing\" width=\"4\" height=\"2\"/>\n                    <buttonCell key=\"prototype\" type=\"radio\" title=\"Radio\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"xn9-2d-u8m\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <cells>\n                        <column>\n                            <buttonCell type=\"radio\" title=\"SLiM\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"18J-5b-jQJ\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"MS\" imagePosition=\"left\" alignment=\"left\" tag=\"1\" inset=\"2\" id=\"xlO-sn-8WB\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <buttonCell type=\"radio\" title=\"VCF\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"Oji-Ai-GwQ\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </column>\n                    </cells>\n                </matrix>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TjJ-nx-Qb8\">\n                    <rect key=\"frame\" x=\"211\" y=\"178\" width=\"129\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"With replacement\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"7JR-mV-f3b\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"hJq-Nw-0S0\" secondAttribute=\"bottom\" constant=\"30\" id=\"5ii-4e-RWE\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"80\" id=\"BpD-Uj-dEX\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"baseline\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"baseline\" id=\"DXQ-6B-rNl\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"EDO-iY-N3s\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"TjJ-nx-Qb8\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"KA4-Yu-NJr\"/>\n                <constraint firstItem=\"9nO-6z-CmL\" firstAttribute=\"top\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"40\" id=\"LMB-2q-XHR\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"dfP-Ze-LJe\" firstAttribute=\"top\" secondItem=\"TjJ-nx-Qb8\" secondAttribute=\"bottom\" constant=\"17\" id=\"NG8-Wv-4C7\"/>\n                <constraint firstItem=\"hJq-Nw-0S0\" firstAttribute=\"top\" secondItem=\"dfP-Ze-LJe\" secondAttribute=\"bottom\" constant=\"17\" id=\"QAT-WH-mNV\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"trailing\" constant=\"8\" id=\"YiE-Rf-grI\"/>\n                <constraint firstItem=\"dfP-Ze-LJe\" firstAttribute=\"leading\" secondItem=\"TjJ-nx-Qb8\" secondAttribute=\"leading\" constant=\"-2\" id=\"Z8N-7B-QEz\"/>\n                <constraint firstItem=\"1z6-PP-cMp\" firstAttribute=\"top\" secondItem=\"hJq-Nw-0S0\" secondAttribute=\"top\" id=\"f38-X7-vTW\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"TjJ-nx-Qb8\" firstAttribute=\"top\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"bottom\" constant=\"6\" id=\"gIo-Gq-03A\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"hPe-Rl-ZPf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"9nO-6z-CmL\" firstAttribute=\"top\" secondItem=\"dfP-Ze-LJe\" secondAttribute=\"top\" id=\"oSG-83-ECT\"/>\n                <constraint firstItem=\"9nO-6z-CmL\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"leading\" id=\"rTB-w3-n4z\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n                <constraint firstItem=\"hJq-Nw-0S0\" firstAttribute=\"leading\" secondItem=\"dfP-Ze-LJe\" secondAttribute=\"leading\" id=\"xMJ-0S-pXc\"/>\n                <constraint firstItem=\"9nO-6z-CmL\" firstAttribute=\"leading\" secondItem=\"1z6-PP-cMp\" secondAttribute=\"leading\" id=\"y7v-JS-w5P\"/>\n                <constraint firstItem=\"1z6-PP-cMp\" firstAttribute=\"top\" secondItem=\"9nO-6z-CmL\" secondAttribute=\"bottom\" constant=\"58\" id=\"yjD-HV-2wR\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"1416\" y=\"895\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_RemoveSubpop.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_RemoveSubpop\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"subpopPopUpButton\" destination=\"BlU-kC-voe\" id=\"Mkj-zc-vTL\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"359\" height=\"114\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"147\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for removal:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"160\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to remove:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"214\" y=\"64\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BlU-kC-voe\">\n                    <rect key=\"frame\" x=\"212\" y=\"24\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zWb-ks-v7K\" id=\"cyH-24-qrh\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"ZVk-uM-lFH\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"zWb-ks-v7K\"/>\n                                <menuItem title=\"Item 2\" id=\"dx0-7u-T8h\"/>\n                                <menuItem title=\"Item 3\" id=\"Stc-jE-1eT\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"Qzw-sV-SCM\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"XuI-kX-Zwc\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"30\" id=\"YZH-V3-CCm\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"BlU-kC-voe\" secondAttribute=\"trailing\" constant=\"50\" id=\"dgu-hK-E0N\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"trailing\" constant=\"8\" id=\"gPx-ei-lIX\"/>\n                <constraint firstItem=\"BlU-kC-voe\" firstAttribute=\"trailing\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"trailing\" id=\"hBC-IA-f2m\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"956.5\" y=\"697.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/ScriptMod_SplitSubpop.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10116\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"ScriptMod_SplitSubpop\">\n            <connections>\n                <outlet property=\"customViewFromSubclass\" destination=\"c22-O7-iKe\" id=\"s7Y-JH-wAr\"/>\n                <outlet property=\"generationTextField\" destination=\"cTD-YU-teQ\" id=\"Fae-WN-sqf\"/>\n                <outlet property=\"sourceSubpopPopUpButton\" destination=\"yPJ-4f-6Oa\" id=\"V9i-ah-61C\"/>\n                <outlet property=\"subpopSizeTextField\" destination=\"hsR-7t-6Qj\" id=\"n4d-S2-ZYs\"/>\n                <outlet property=\"subpopTextField\" destination=\"6Df-tQ-Vse\" id=\"b51-pX-tQi\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView placeholderIntrinsicWidth=\"362\" placeholderIntrinsicHeight=\"197\" id=\"c22-O7-iKe\" customClass=\"ScriptModSubclassViewPlaceholder\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"364\" height=\"188\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cXU-20-n64\">\n                    <rect key=\"frame\" x=\"48\" y=\"141\" width=\"125\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Generation for split:\" id=\"Teb-5E-ffj\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MNC-OH-9jP\">\n                    <rect key=\"frame\" x=\"48\" y=\"104\" width=\"138\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Subpopulation to add:\" id=\"RcV-Ss-pQT\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M8O-Rd-GEL\">\n                    <rect key=\"frame\" x=\"48\" y=\"67\" width=\"165\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Added subpopulation size:\" id=\"TZd-C3-yca\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Udk-R6-3wo\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"141\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Source subpopulation:\" id=\"CDW-mN-sSa\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cTD-YU-teQ\">\n                    <rect key=\"frame\" x=\"219\" y=\"138\" width=\"95\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"95\" id=\"5cw-Ku-huL\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"B2k-1g-UVm\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"vnx-QO-T2l\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6Df-tQ-Vse\">\n                    <rect key=\"frame\" x=\"229\" y=\"101\" width=\"85\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" id=\"33G-kc-ztx\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"OSI-dg-OKT\"/>\n                    </connections>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hsR-7t-6Qj\">\n                    <rect key=\"frame\" x=\"219\" y=\"64\" width=\"95\" height=\"22\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" id=\"tQp-ap-zPS\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"Gfd-y4-v2D\"/>\n                    </connections>\n                </textField>\n                <textField horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6zZ-IL-QHt\">\n                    <rect key=\"frame\" x=\"217\" y=\"104\" width=\"12\" height=\"17\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"p\" id=\"RB1-pr-vh0\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yPJ-4f-6Oa\">\n                    <rect key=\"frame\" x=\"217\" y=\"24\" width=\"100\" height=\"26\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Item 1\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"3Xv-is-dHL\" id=\"weS-6Z-Y2H\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"menu\"/>\n                        <menu key=\"menu\" id=\"Loh-Yh-PLZ\">\n                            <items>\n                                <menuItem title=\"Item 1\" state=\"on\" id=\"3Xv-is-dHL\"/>\n                                <menuItem title=\"Item 2\" id=\"Yh7-F9-N1g\"/>\n                                <menuItem title=\"Item 3\" id=\"sch-ph-Ufn\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                </popUpButton>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"Udk-R6-3wo\" secondAttribute=\"bottom\" constant=\"30\" id=\"2aA-tD-YKl\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"yPJ-4f-6Oa\" secondAttribute=\"leading\" id=\"2cx-7g-Th8\"/>\n                <constraint firstItem=\"6Df-tQ-Vse\" firstAttribute=\"leading\" secondItem=\"6zZ-IL-QHt\" secondAttribute=\"trailing\" constant=\"2\" id=\"4b1-sZ-mwQ\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" constant=\"50\" id=\"51g-mI-sxo\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"trailing\" secondItem=\"yPJ-4f-6Oa\" secondAttribute=\"trailing\" id=\"9DE-8m-jlg\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"top\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"bottom\" constant=\"20\" id=\"DJP-Az-dmk\"/>\n                <constraint firstItem=\"6zZ-IL-QHt\" firstAttribute=\"leading\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"leading\" id=\"FqE-vY-IAS\"/>\n                <constraint firstItem=\"hsR-7t-6Qj\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"trailing\" constant=\"8\" id=\"HSh-7n-ya1\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"leading\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"leading\" id=\"I8d-kZ-5lO\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"leading\" secondItem=\"cXU-20-n64\" secondAttribute=\"leading\" id=\"Iwa-jv-2Zf\"/>\n                <constraint firstItem=\"6zZ-IL-QHt\" firstAttribute=\"baseline\" secondItem=\"MNC-OH-9jP\" secondAttribute=\"baseline\" id=\"Lmb-da-ejG\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"baseline\" secondItem=\"cTD-YU-teQ\" secondAttribute=\"baseline\" id=\"MLV-gG-702\"/>\n                <constraint firstItem=\"M8O-Rd-GEL\" firstAttribute=\"baseline\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"baseline\" id=\"OmR-9M-vmM\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"leading\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"leading\" id=\"QvM-8Y-maA\"/>\n                <constraint firstItem=\"Udk-R6-3wo\" firstAttribute=\"leading\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"leading\" id=\"ZXh-ZE-mp4\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"top\" secondItem=\"cXU-20-n64\" secondAttribute=\"bottom\" constant=\"20\" id=\"fMU-Dl-l5F\"/>\n                <constraint firstItem=\"MNC-OH-9jP\" firstAttribute=\"baseline\" secondItem=\"6Df-tQ-Vse\" secondAttribute=\"baseline\" id=\"i9e-gv-zDS\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"top\" secondItem=\"c22-O7-iKe\" secondAttribute=\"top\" constant=\"30\" id=\"kud-DO-7qr\"/>\n                <constraint firstItem=\"6Df-tQ-Vse\" firstAttribute=\"trailing\" secondItem=\"hsR-7t-6Qj\" secondAttribute=\"trailing\" id=\"mYT-o5-puS\"/>\n                <constraint firstItem=\"Udk-R6-3wo\" firstAttribute=\"top\" secondItem=\"M8O-Rd-GEL\" secondAttribute=\"bottom\" constant=\"20\" id=\"tLf-MW-0qv\"/>\n                <constraint firstItem=\"cXU-20-n64\" firstAttribute=\"leading\" secondItem=\"c22-O7-iKe\" secondAttribute=\"leading\" constant=\"50\" id=\"v6m-nW-NUk\"/>\n                <constraint firstItem=\"cTD-YU-teQ\" firstAttribute=\"trailing\" secondItem=\"6Df-tQ-Vse\" secondAttribute=\"trailing\" id=\"v9Q-Oa-Li4\"/>\n                <constraint firstItem=\"Udk-R6-3wo\" firstAttribute=\"baseline\" secondItem=\"yPJ-4f-6Oa\" secondAttribute=\"baseline\" id=\"xrH-kK-1Wt\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"652\" y=\"713.5\"/>\n        </customView>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/Base.lproj/TipsWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15G1108\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10117\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TipsWindowController\">\n            <connections>\n                <outlet property=\"nextButton\" destination=\"GCr-Tz-8BW\" id=\"8NV-cE-uwg\"/>\n                <outlet property=\"suppressPanelCheckbox\" destination=\"Irc-Ps-N5J\" id=\"dnf-QT-44g\"/>\n                <outlet property=\"tipsNumberTextField\" destination=\"Qde-d6-9gj\" id=\"rDW-cX-2gV\"/>\n                <outlet property=\"tipsTextView\" destination=\"LKh-uC-Ber\" id=\"hGI-Vb-bRO\"/>\n                <outlet property=\"tipsWindow\" destination=\"QvC-M9-y7g\" id=\"0Po-NR-ona\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" oneShot=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\" utility=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"496\" width=\"554\" height=\"365\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1057\"/>\n            <value key=\"minSize\" type=\"size\" width=\"554\" height=\"300\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"700\" height=\"700\"/>\n            <view key=\"contentView\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"554\" height=\"365\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Irc-Ps-N5J\">\n                        <rect key=\"frame\" x=\"18\" y=\"40\" width=\"270\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Do not show the tips &amp; tricks panel again\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"Aps-Sf-WWj\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dg7-gG-ZUk\">\n                        <rect key=\"frame\" x=\"18\" y=\"20\" width=\"265\" height=\"14\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"This setting can be reset in the Preferences panel\" id=\"Pfe-lE-DRG\">\n                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XbE-nS-GtT\">\n                        <rect key=\"frame\" x=\"20\" y=\"76\" width=\"514\" height=\"234\"/>\n                        <clipView key=\"contentView\" id=\"ICh-ra-L9E\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"497\" height=\"232\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView editable=\"NO\" findStyle=\"bar\" continuousSpellChecking=\"YES\" verticallyResizable=\"YES\" quoteSubstitution=\"YES\" dashSubstitution=\"YES\" smartInsertDelete=\"YES\" id=\"LKh-uC-Ber\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"497\" height=\"232\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                    <size key=\"minSize\" width=\"497\" height=\"232\"/>\n                                    <size key=\"maxSize\" width=\"514\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"497\" height=\"232\"/>\n                                    <size key=\"maxSize\" width=\"514\" height=\"10000000\"/>\n                                </textView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"Tc7-x0-mD9\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"YjF-mK-62x\">\n                            <rect key=\"frame\" x=\"498\" y=\"1\" width=\"15\" height=\"232\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dPa-k3-9bZ\">\n                        <rect key=\"frame\" x=\"18\" y=\"324\" width=\"159\" height=\"29\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"SLiM Tips &amp; Tricks\" id=\"UOo-id-RJd\">\n                            <font key=\"font\" size=\"20\" name=\"Optima-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button toolTip=\"Close the tips panel\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2En-t8-7AM\">\n                        <rect key=\"frame\" x=\"468\" y=\"13\" width=\"72\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Done\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"7k3-9M-5w8\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"doneButtonClicked:\" target=\"-2\" id=\"tjs-zd-Tgv\"/>\n                        </connections>\n                    </button>\n                    <button toolTip=\"Advance to the next tip\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GCr-Tz-8BW\">\n                        <rect key=\"frame\" x=\"396\" y=\"13\" width=\"72\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Next\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"SLW-as-FZN\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"nextButtonClicked:\" target=\"-2\" id=\"BwR-WA-Jf2\"/>\n                        </connections>\n                    </button>\n                    <button toolTip=\"Rewind to the first tip\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AB7-FY-CPv\">\n                        <rect key=\"frame\" x=\"324\" y=\"13\" width=\"72\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"&lt;&lt;\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"AhH-VN-osH\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"rewindButtonClicked:\" target=\"-2\" id=\"4Nf-Ki-fUd\"/>\n                        </connections>\n                    </button>\n                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Qde-d6-9gj\">\n                        <rect key=\"frame\" x=\"509\" y=\"324\" width=\"27\" height=\"29\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"#1\" id=\"eec-Y5-S2Z\">\n                            <font key=\"font\" size=\"20\" name=\"Optima-Regular\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"2En-t8-7AM\" firstAttribute=\"leading\" secondItem=\"GCr-Tz-8BW\" secondAttribute=\"trailing\" constant=\"12\" id=\"3qC-A6-1jH\"/>\n                    <constraint firstItem=\"GCr-Tz-8BW\" firstAttribute=\"width\" secondItem=\"2En-t8-7AM\" secondAttribute=\"width\" id=\"55H-ae-9fO\"/>\n                    <constraint firstItem=\"AB7-FY-CPv\" firstAttribute=\"width\" secondItem=\"GCr-Tz-8BW\" secondAttribute=\"width\" id=\"5jG-gR-EpU\"/>\n                    <constraint firstItem=\"Irc-Ps-N5J\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"7O4-hf-nij\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"XbE-nS-GtT\" secondAttribute=\"trailing\" constant=\"20\" id=\"BRQ-BD-vhb\"/>\n                    <constraint firstItem=\"dPa-k3-9bZ\" firstAttribute=\"top\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"top\" constant=\"12\" id=\"DZI-Ps-9Rg\"/>\n                    <constraint firstItem=\"XbE-nS-GtT\" firstAttribute=\"top\" secondItem=\"dPa-k3-9bZ\" secondAttribute=\"bottom\" constant=\"14\" id=\"F2V-BU-v8u\"/>\n                    <constraint firstItem=\"Dg7-gG-ZUk\" firstAttribute=\"top\" secondItem=\"Irc-Ps-N5J\" secondAttribute=\"bottom\" constant=\"8\" id=\"FbC-7A-gxn\"/>\n                    <constraint firstItem=\"GCr-Tz-8BW\" firstAttribute=\"baseline\" secondItem=\"2En-t8-7AM\" secondAttribute=\"baseline\" id=\"O3k-fT-f46\"/>\n                    <constraint firstItem=\"dPa-k3-9bZ\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"OU6-mG-jTH\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"2En-t8-7AM\" secondAttribute=\"bottom\" constant=\"20\" id=\"S0Y-be-3E8\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Qde-d6-9gj\" secondAttribute=\"trailing\" constant=\"20\" id=\"UgQ-zm-aVj\"/>\n                    <constraint firstItem=\"Qde-d6-9gj\" firstAttribute=\"baseline\" secondItem=\"dPa-k3-9bZ\" secondAttribute=\"baseline\" id=\"arR-37-Xd6\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Dg7-gG-ZUk\" secondAttribute=\"bottom\" constant=\"20\" id=\"dsh-8i-QQV\"/>\n                    <constraint firstItem=\"AB7-FY-CPv\" firstAttribute=\"baseline\" secondItem=\"GCr-Tz-8BW\" secondAttribute=\"baseline\" id=\"jC4-nP-XFN\"/>\n                    <constraint firstItem=\"GCr-Tz-8BW\" firstAttribute=\"leading\" secondItem=\"AB7-FY-CPv\" secondAttribute=\"trailing\" constant=\"12\" id=\"m09-Iq-vIl\"/>\n                    <constraint firstItem=\"Irc-Ps-N5J\" firstAttribute=\"top\" secondItem=\"XbE-nS-GtT\" secondAttribute=\"bottom\" constant=\"20\" id=\"oEp-eU-kta\"/>\n                    <constraint firstItem=\"Dg7-gG-ZUk\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"tWQ-s2-yEo\"/>\n                    <constraint firstItem=\"XbE-nS-GtT\" firstAttribute=\"leading\" secondItem=\"EiT-Mj-1SZ\" secondAttribute=\"leading\" constant=\"20\" id=\"tWY-fI-zJz\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"2En-t8-7AM\" secondAttribute=\"trailing\" constant=\"20\" id=\"zKv-KD-EfL\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"Am8-VI-dTm\"/>\n                <outlet property=\"initialFirstResponder\" destination=\"2En-t8-7AM\" id=\"z6p-YB-m7L\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"798\" y=\"492.5\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/ChromosomeView.h",
    "content": "//\n//  ChromosomeView.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#import \"CocoaExtra.h\"\n#include \"slim_globals.h\"\n\n#include <vector>\n\n\nclass Chromosome;\n\nextern NSString *SLiMChromosomeSelectionChangedNotification;\n\n\n@interface ChromosomeView : NSView\n{\n@public\n\t// Display options\n\tstd::vector<slim_objectid_t> display_muttypes_;\t// if empty, display all mutation types; otherwise, display only the muttypes chosen\n}\n\n@property (nonatomic) BOOL enabled;\n@property (nonatomic) BOOL overview;\n\n@property (nonatomic) BOOL shouldDrawGenomicElements;\n@property (nonatomic) BOOL shouldDrawRateMaps;\n@property (nonatomic) BOOL shouldDrawMutations;\n@property (nonatomic) BOOL shouldDrawFixedSubstitutions;\n\n- (NSRange)displayedRangeForChromosome:(Chromosome *)chromosome;\t// the full chromosome range\n\n- (void)setNeedsDisplayInInterior;\t// set to need display only within the interior; avoid redrawing ticks unnecessarily\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/ChromosomeView.mm",
    "content": "//\n//  ChromosomeView.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"ChromosomeView.h\"\n#import \"SLiMWindowController.h\"\n#import \"CocoaExtra.h\"\n\n#include \"community.h\"\n\n\nNSString *SLiMChromosomeSelectionChangedNotification = @\"SLiMChromosomeSelectionChangedNotification\";\n\nstatic NSDictionary *tickAttrs = nil;\nstatic const int numberOfTicksPlusOne = 4;\nstatic const int tickLength = 5;\nstatic const int heightForTicks = 16;\nstatic const int spaceBetweenChromosomes = 5;\n\n\n@implementation ChromosomeView\n\n@synthesize shouldDrawGenomicElements, shouldDrawFixedSubstitutions, shouldDrawMutations, shouldDrawRateMaps;\n\n+ (void)initialize\n{\n\tif (!tickAttrs)\n\t\ttickAttrs = [@{NSForegroundColorAttributeName : [NSColor blackColor], NSFontAttributeName : [NSFont systemFontOfSize:9.0]} retain];\n\t\n\t[self exposeBinding:@\"enabled\"];\n}\n\n- (id)initWithFrame:(NSRect)frameRect\n{\n\tif (self = [super initWithFrame:frameRect])\n\t{\n\t\t// this is not called for objects in the nib (I imagine initWithCoder: is instead); put stuff in awakeFromNib\n\t}\n\t\n\treturn self;\n}\n\n- (void)setEnabled:(BOOL)enabled\n{\n\tif (_enabled != enabled)\n\t{\n\t\t_enabled = enabled;\n\t\t[self setNeedsDisplayAll];\n\t}\n}\n\n- (void)setOverview:(BOOL)overview\n{\n\tif (_overview != overview)\n\t{\n\t\t_overview = overview;\n\t\t[self setNeedsDisplayAll];\n\t}\n}\n\n- (void)awakeFromNib\n{\n\tdisplay_muttypes_.clear();\n\t\n\t[self bind:@\"enabled\" toObject:[[self window] windowController] withKeyPath:@\"invalidSimulation\" options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];\n}\n\n- (void)dealloc\n{\n\t[self unbind:@\"enabled\"];\n\t\n\t[super dealloc];\n}\n\n- (NSRange)displayedRangeForChromosome:(Chromosome *)chromosome\n{\n\tslim_position_t chromosomeLastPosition = chromosome->last_position_;\n\t\n\treturn NSMakeRange(0, chromosomeLastPosition + 1);\t// chromosomeLastPosition + 1 bases are encompassed\n}\n\n- (NSRect)rectEncompassingBase:(slim_position_t)startBase toBase:(slim_position_t)endBase interiorRect:(NSRect)interiorRect displayedRange:(NSRange)displayedRange\n{\n\tdouble startFraction = (startBase - (slim_position_t)displayedRange.location) / (double)(displayedRange.length);\n\tdouble leftEdgeDouble = interiorRect.origin.x + startFraction * interiorRect.size.width;\n\tdouble endFraction = (endBase + 1 - (slim_position_t)displayedRange.location) / (double)(displayedRange.length);\n\tdouble rightEdgeDouble = interiorRect.origin.x + endFraction * interiorRect.size.width;\n\tint leftEdge, rightEdge;\n\t\n\tif (rightEdgeDouble - leftEdgeDouble > 1.0)\n\t{\n\t\t// If the range spans a width of more than one pixel, then use the maximal pixel range\n\t\tleftEdge = (int)floor(leftEdgeDouble);\n\t\trightEdge = (int)ceil(rightEdgeDouble);\n\t}\n\telse\n\t{\n\t\t// If the range spans a pixel or less, make sure that we end up with a range that is one pixel wide, even if the left-right positions span a pixel boundary\n\t\tleftEdge = (int)floor(leftEdgeDouble);\n\t\trightEdge = leftEdge + 1;\n\t}\n\t\n\treturn NSMakeRect(leftEdge, interiorRect.origin.y, rightEdge - leftEdge, interiorRect.size.height);\n}\n\n- (NSRect)contentRect\n{\n\tNSRect bounds = [self bounds];\n\t\n\t// Two things are going on here.  The width gets inset by two pixels on each side because our frame is outset that much from our apparent frame, to\n\t// make room for the selection knobs to spill over a bit.  The height gets adjusted because our \"content rect\" does not include our ticks.\n\tif ([self overview])\n\t\treturn NSMakeRect(bounds.origin.x + 2, bounds.origin.y, bounds.size.width - 4, bounds.size.height);\n\telse\n\t\treturn NSMakeRect(bounds.origin.x + 2, bounds.origin.y + heightForTicks, bounds.size.width - 4, bounds.size.height - heightForTicks);\n}\n\n- (NSRect)interiorRect\n{\n\treturn NSInsetRect([self contentRect], 1, 1);\n}\n\n- (void)setNeedsDisplayAll\n{\n\t[self setNeedsDisplay:YES];\n}\n\n- (void)setNeedsDisplayInInterior\n{\n\t[self setNeedsDisplayInRect:[self interiorRect]];\n}\n\n// This is a fast macro for when all we need is the offset of a base from the left edge of interiorRect; interiorRect.origin.x is not added here!\n// This is based on the same math as rectEncompassingBase:toBase:interiorRect:displayedRange: above, and must be kept in synch with that method.\n#define LEFT_OFFSET_OF_BASE(startBase, interiorRect, displayedRange) ((int)floor(((startBase - (slim_position_t)displayedRange.location) / (double)(displayedRange.length)) * interiorRect.size.width))\n\n- (slim_position_t)baseForPosition:(double)position interiorRect:(NSRect)interiorRect displayedRange:(NSRange)displayedRange\n{\n\tdouble fraction = (position - interiorRect.origin.x) / interiorRect.size.width;\n\tslim_position_t base = (slim_position_t)floor(fraction * (displayedRange.length + 1) + displayedRange.location);\n\t\n\treturn base;\n}\n\n- (void)drawTicksInContentRect:(NSRect)contentRect withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tNSRect interiorRect = NSInsetRect(contentRect, 1, 1);\n\t\n\tif (displayedRange.length == 0)\n\t{\n\t\t// Handle the \"no genetics\" case separately\n\t\tif (![self overview])\n\t\t{\n\t\t\tNSAttributedString *tickAttrLabel = [[NSAttributedString alloc] initWithString:@\"no genetics\" attributes:tickAttrs];\n\t\t\tNSSize tickLabelSize = [tickAttrLabel size];\n\t\t\tint tickLabelX = (int)floor(interiorRect.origin.x + (interiorRect.size.width - tickLabelSize.width) / 2.0);\n\t\t\t\n\t\t\t[tickAttrLabel drawAtPoint:NSMakePoint(tickLabelX, contentRect.origin.y - 14)];\n\t\t\t[tickAttrLabel release];\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\t\n\tint64_t lastTickIndex = numberOfTicksPlusOne;\n\t\n\t// Display fewer ticks when we are displaying a very small number of positions\n\tlastTickIndex = MIN(lastTickIndex, ((int64_t)displayedRange.length + 1) / 3);\n\t\n\tdouble tickIndexDivisor = ((lastTickIndex == 0) ? 1.0 : (double)lastTickIndex);\t\t// avoid a divide by zero when we are displaying a single site\n\t\n\t// BCH 12/25/2024: Start by measuring the tick labels and figuring out who fits.  FIXME we could be even smarter\n\t// and switch to scientific notation if things get too crowded, but I'll leave that for another day.\n\tdouble widthAllLabels = 0.0, widthLeftRightLabels = 0.0, widthRightLabelOnly = 0.0;\n\t\n\tfor (int tickIndex = 0; tickIndex <= lastTickIndex; ++tickIndex)\n\t{\n\t\tslim_position_t tickBase = (slim_position_t)displayedRange.location + (slim_position_t)ceil((displayedRange.length - 1) * (tickIndex / tickIndexDivisor));\t// -1 because we are choosing an in-between-base position that falls, at most, to the left of the last base\n\t\tNSString *tickLabel;\n\t\t\n\t\tif (tickBase >= 1e10)\n\t\t\ttickLabel = [NSString stringWithFormat:@\"%.6e\", (double)tickBase];\n\t\telse\n\t\t\ttickLabel = [NSString stringWithFormat:@\"%lld\", (long long int)tickBase];\n\t\t\n\t\tNSAttributedString *tickAttrLabel = [[NSAttributedString alloc] initWithString:tickLabel attributes:tickAttrs];\n\t\tNSSize tickLabelSize = [tickAttrLabel size];\n\t\tint tickLabelWidth = 5 + (int)tickLabelSize.width;\n\t\t[tickAttrLabel release];\n\t\t\n\t\twidthAllLabels += tickLabelWidth;\n\t\tif (tickIndex == 0)\n\t\t{\n\t\t\twidthLeftRightLabels += tickLabelWidth;\n\t\t}\n\t\tif (tickIndex == lastTickIndex)\n\t\t{\n\t\t\twidthLeftRightLabels += tickLabelWidth;\n\t\t\twidthRightLabelOnly += tickLabelWidth;\n\t\t}\n\t}\n\t\n\tfor (int tickIndex = 0; tickIndex <= lastTickIndex; ++tickIndex)\n\t{\n\t\t// BCH 12/25/2024: If we're not going to draw the middle tick labels, skip their tick marks also;\n\t\t// and if we're not going to draw any tick labels at all, then skip drawing all the tick marks\n\t\tint interiorWidth = (int)interiorRect.size.width;\n\t\t\n\t\tif ((widthRightLabelOnly > interiorWidth) ||\n\t\t\t((widthAllLabels > interiorWidth) && (tickIndex != 0) && (tickIndex != lastTickIndex)))\n\t\t\tcontinue;\n\t\t\n\t\tslim_position_t tickBase = (slim_position_t)displayedRange.location + (slim_position_t)ceil((displayedRange.length - 1) * (tickIndex / tickIndexDivisor));\t// -1 because we are choosing an in-between-base position that falls, at most, to the left of the last base\n\t\tNSRect tickRect = [self rectEncompassingBase:tickBase toBase:tickBase interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\n\t\ttickRect.origin.y = contentRect.origin.y - tickLength;\n\t\ttickRect.size.height = tickLength;\n\t\t\n\t\t// if we are displaying a single site or two sites, make a tick mark one pixel wide, rather than a very wide one, which looks weird\n\t\tif (displayedRange.length <= 2)\n\t\t{\n\t\t\ttickRect.origin.x = (int)floor(tickRect.origin.x + tickRect.size.width / 2.0 - 0.5);\n\t\t\ttickRect.size.width = 1.0;\n\t\t}\n\t\t\n\t\t[[NSColor colorWithCalibratedWhite:0.5 alpha:1.0] set];\n\t\tNSRectFill(tickRect);\n\t\t\n\t\t// BCH 12/25/2024: Using the measurements taken above, decide whether to draw this tick label or not\n\t\tif (widthAllLabels > interiorWidth)\n\t\t{\n\t\t\tif ((tickIndex != 0) && (tickIndex != lastTickIndex))\n\t\t\t\tcontinue;\n\t\t\tif (widthLeftRightLabels > interiorWidth)\n\t\t\t{\n\t\t\t\tif (tickIndex != lastTickIndex)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (widthRightLabelOnly > interiorWidth)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// BCH 15 May 2018: display in scientific notation for positions at or above 1e10, as it gets a bit ridiculous...\n\t\tNSString *tickLabel;\n\t\t\n\t\tif (tickBase >= 1e10)\n\t\t\ttickLabel = [NSString stringWithFormat:@\"%.6e\", (double)tickBase];\n\t\telse\n\t\t\ttickLabel = [NSString stringWithFormat:@\"%lld\", (long long int)tickBase];\n\t\t\n\t\tNSAttributedString *tickAttrLabel = [[NSAttributedString alloc] initWithString:tickLabel attributes:tickAttrs];\n\t\tNSSize tickLabelSize = [tickAttrLabel size];\n\t\tint tickLabelX = (int)floor(tickRect.origin.x + tickRect.size.width / 2.0);\n\t\tBOOL forceCenteredLabel = (displayedRange.length <= 101);\t// a selected subrange is never <=101 length, so this is safe even with large chromosomes\n\t\t\n\t\tif ((tickIndex == lastTickIndex) && !forceCenteredLabel)\n\t\t\ttickLabelX -= (int)round(tickLabelSize.width - 2);\n\t\telse if ((tickIndex > 0) || forceCenteredLabel)\n\t\t\ttickLabelX -= (int)round(tickLabelSize.width / 2.0);\n\t\t\n\t\t[tickAttrLabel drawAtPoint:NSMakePoint(tickLabelX, contentRect.origin.y - (tickLength + 12))];\n\t\t[tickAttrLabel release];\n\t}\n}\n\n- (void)drawGenomicElementsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tCGFloat previousIntervalLeftEdge = -10000;\n\t\n\tfor (GenomicElement *genomicElement : chromosome->GenomicElements())\n\t{\n\t\tslim_position_t startPosition = genomicElement->start_position_;\n\t\tslim_position_t endPosition = genomicElement->end_position_;\n\t\tNSRect elementRect = [self rectEncompassingBase:startPosition toBase:endPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\tBOOL widthOne = (elementRect.size.width == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (elementRect.origin.x == previousIntervalLeftEdge))\n\t\t{\n\t\t\telementRect.origin.x++;\n\t\t\telementRect.size.width--;\n\t\t}\n\t\t\n\t\t// draw only the visible part, if any\n\t\telementRect = NSIntersectionRect(elementRect, interiorRect);\n\t\t\n\t\tif (!NSIsEmptyRect(elementRect))\n\t\t{\n\t\t\tGenomicElementType *geType = genomicElement->genomic_element_type_ptr_;\n\t\t\tNSColor *elementColor = [controller colorForGenomicElementType:geType withID:geType->genomic_element_type_id_];\n\t\t\t\n\t\t\t[elementColor set];\n\t\t\tNSRectFill(elementRect);\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = elementRect.origin.x;\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t}\n}\n\n- (void)_drawRateMapIntervalsInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange ends:(std::vector<slim_position_t> &)ends rates:(std::vector<double> &)rates\n{\n\tint recombinationIntervalCount = (int)ends.size();\n\tslim_position_t intervalStartPosition = 0;\n\tCGFloat previousIntervalLeftEdge = -10000;\n\t\n\tfor (int interval = 0; interval < recombinationIntervalCount; ++interval)\n\t{\n\t\tslim_position_t intervalEndPosition = ends[interval];\n\t\tdouble intervalRate = rates[interval];\n\t\tNSRect intervalRect = [self rectEncompassingBase:intervalStartPosition toBase:intervalEndPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\tBOOL widthOne = (intervalRect.size.width == 1);\n\t\t\n\t\t// We want to avoid overdrawing width-one intervals, which are important but small, so if the previous interval was width-one,\n\t\t// and we are not, and we are about to overdraw it, then we scoot our left edge over one pixel to leave it alone.\n\t\tif (!widthOne && (intervalRect.origin.x == previousIntervalLeftEdge))\n\t\t{\n\t\t\tintervalRect.origin.x++;\n\t\t\tintervalRect.size.width--;\n\t\t}\n\t\t\n\t\t// draw only the visible part, if any\n\t\tintervalRect = NSIntersectionRect(intervalRect, interiorRect);\n\t\t\n\t\tif (!NSIsEmptyRect(intervalRect))\n\t\t{\n\t\t\t// color according to how \"hot\" the region is\n\t\t\tdouble brightness = 0.0;\n\t\t\tdouble saturation = 1.0;\n\t\t\t\n\t\t\tif (intervalRate > 0.0)\n\t\t\t{\n\t\t\t\tif (intervalRate > 1.0e-8)\n\t\t\t\t{\n\t\t\t\t\tif (intervalRate < 5.0e-8)\n\t\t\t\t\t{\n\t\t\t\t\t\tbrightness = 0.5 + 0.5 * ((intervalRate - 1.0e-8) / 4.0e-8);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tbrightness = 1.0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (intervalRate < 1.0e-7)\n\t\t\t\t\t\t\tsaturation = 1.0 - ((intervalRate - 5.0e-8) * 2.0e7);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsaturation = 0.0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbrightness = 0.5;\n\t\t\t\t}\n\t\t\t}\n\t\t\tNSColor *intervalColor = [NSColor colorWithCalibratedHue:0.65 saturation:saturation brightness:brightness alpha:1.0];\n\t\t\t\n\t\t\t[intervalColor set];\n\t\t\tNSRectFill(intervalRect);\n\t\t\t\n\t\t\t// if this interval is just one pixel wide, we want to try to make it visible, by avoiding overdrawing it; so we remember its location\n\t\t\tif (widthOne)\n\t\t\t\tpreviousIntervalLeftEdge = intervalRect.origin.x;\n\t\t\telse\n\t\t\t\tpreviousIntervalLeftEdge = -10000;\n\t\t}\n\t\t\n\t\t// the next interval starts at the next base after this one ended\n\t\tintervalStartPosition = intervalEndPosition + 1;\n\t}\n}\n\n- (void)drawRecombinationIntervalsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tif (chromosome->single_recombination_map_)\n\t{\n\t\t[self _drawRateMapIntervalsInInteriorRect:interiorRect withController:controller displayedRange:displayedRange ends:chromosome->recombination_end_positions_H_ rates:chromosome->recombination_rates_H_];\n\t}\n\telse\n\t{\n\t\tNSRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tCGFloat halfHeight = ceil(interiorRect.size.height / 2.0);\n\t\tCGFloat remainingHeight = interiorRect.size.height - halfHeight;\n\t\t\n\t\ttopInteriorRect.size.height = halfHeight;\n\t\ttopInteriorRect.origin.y += remainingHeight;\n\t\tbottomInteriorRect.size.height = remainingHeight;\n\t\t\n\t\t[self _drawRateMapIntervalsInInteriorRect:topInteriorRect withController:controller displayedRange:displayedRange ends:chromosome->recombination_end_positions_M_ rates:chromosome->recombination_rates_M_];\n\t\t[self _drawRateMapIntervalsInInteriorRect:bottomInteriorRect withController:controller displayedRange:displayedRange ends:chromosome->recombination_end_positions_F_ rates:chromosome->recombination_rates_F_];\n\t}\n}\n\n- (void)drawMutationIntervalsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tif (chromosome->single_mutation_map_)\n\t{\n\t\t[self _drawRateMapIntervalsInInteriorRect:interiorRect withController:controller displayedRange:displayedRange ends:chromosome->mutation_end_positions_H_ rates:chromosome->mutation_rates_H_];\n\t}\n\telse\n\t{\n\t\tNSRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tCGFloat halfHeight = ceil(interiorRect.size.height / 2.0);\n\t\tCGFloat remainingHeight = interiorRect.size.height - halfHeight;\n\t\t\n\t\ttopInteriorRect.size.height = halfHeight;\n\t\ttopInteriorRect.origin.y += remainingHeight;\n\t\tbottomInteriorRect.size.height = remainingHeight;\n\t\t\n\t\t[self _drawRateMapIntervalsInInteriorRect:topInteriorRect withController:controller displayedRange:displayedRange ends:chromosome->mutation_end_positions_M_ rates:chromosome->mutation_rates_M_];\n\t\t[self _drawRateMapIntervalsInInteriorRect:bottomInteriorRect withController:controller displayedRange:displayedRange ends:chromosome->mutation_end_positions_F_ rates:chromosome->mutation_rates_F_];\n\t}\n}\n\n- (void)drawRateMapsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tBOOL recombinationWorthShowing = NO;\n\tBOOL mutationWorthShowing = NO;\n\t\n\tif (chromosome->single_mutation_map_)\n\t\tmutationWorthShowing = (chromosome->mutation_end_positions_H_.size() > 1);\n\telse\n\t\tmutationWorthShowing = ((chromosome->mutation_end_positions_M_.size() > 1) || (chromosome->mutation_end_positions_F_.size() > 1));\n\t\n\tif (chromosome->single_recombination_map_)\n\t\trecombinationWorthShowing = (chromosome->recombination_end_positions_H_.size() > 1);\n\telse\n\t\trecombinationWorthShowing = ((chromosome->recombination_end_positions_M_.size() > 1) || (chromosome->recombination_end_positions_F_.size() > 1));\n\t\n\t// If neither map is worth showing, we show just the recombination map, to mirror the behavior of 2.4 and earlier\n\tif ((!mutationWorthShowing && !recombinationWorthShowing) || (!mutationWorthShowing && recombinationWorthShowing))\n\t{\n\t\t[self drawRecombinationIntervalsInInteriorRect:interiorRect chromosome:chromosome withController:controller displayedRange:displayedRange];\n\t}\n\telse if (mutationWorthShowing && !recombinationWorthShowing)\n\t{\n\t\t[self drawMutationIntervalsInInteriorRect:interiorRect chromosome:chromosome withController:controller displayedRange:displayedRange];\n\t}\n\telse\t// mutationWorthShowing && recombinationWorthShowing\n\t{\n\t\tNSRect topInteriorRect = interiorRect, bottomInteriorRect = interiorRect;\n\t\tCGFloat halfHeight = ceil(interiorRect.size.height / 2.0);\n\t\tCGFloat remainingHeight = interiorRect.size.height - halfHeight;\n\t\t\n\t\ttopInteriorRect.size.height = halfHeight;\n\t\ttopInteriorRect.origin.y += remainingHeight;\n\t\tbottomInteriorRect.size.height = remainingHeight;\n\t\t\n\t\t[self drawRecombinationIntervalsInInteriorRect:topInteriorRect chromosome:chromosome withController:controller displayedRange:displayedRange];\n\t\t[self drawMutationIntervalsInInteriorRect:bottomInteriorRect chromosome:chromosome withController:controller displayedRange:displayedRange];\n\t}\n}\n\n- (void)drawFixedSubstitutionsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tdouble scalingFactor = 0.8; // used to be controller->selectionColorScale;\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tbool chromosomeHasDefaultColor = !chromosome->color_sub_.empty();\n\t\n\tfloat colorRed = 0.2f, colorGreen = 0.2f, colorBlue = 1.0f;\n\t\n\tif (chromosomeHasDefaultColor)\n\t{\n\t\tcolorRed = chromosome->color_sub_red_;\n\t\tcolorGreen = chromosome->color_sub_green_;\n\t\tcolorBlue = chromosome->color_sub_blue_;\n\t}\n\t\n\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tif ((substitutions.size() < 1000) || (displayedRange.length < interiorRect.size.width))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n\t\t\tif (substitution->mutation_type_ptr_->mutation_type_displayed_)\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tNSRect substitutionTickRect = [self rectEncompassingBase:substitutionPosition toBase:substitutionPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\n\t\t\t\tif (!shouldDrawMutations || !chromosomeHasDefaultColor)\n\t\t\t\t{\n\t\t\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue, to contrast\n\t\t\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:mutType->color_sub_red_ green:mutType->color_sub_green_ blue:mutType->color_sub_blue_ alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(substitution->selection_coeff_, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tNSRectFill(substitutionTickRect);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We have a lot of substitutions, so do a radix sort, as we do in drawMutationsInInteriorRect: below.\n\t\tint displayPixelWidth = (int)interiorRect.size.width;\n\t\tconst Substitution **subBuffer = (const Substitution **)calloc(displayPixelWidth, sizeof(Substitution *));\n\t\t\n\t\tfor (const Substitution *substitution : substitutions)\n\t\t{\n\t\t\tif (substitution->mutation_type_ptr_->mutation_type_displayed_)\n\t\t\t{\n\t\t\t\tslim_position_t substitutionPosition = substitution->position_;\n\t\t\t\tdouble startFraction = (substitutionPosition - (slim_position_t)displayedRange.location) / (double)(displayedRange.length);\n\t\t\t\tint xPos = (int)floor(startFraction * interiorRect.size.width);\n\t\t\t\t\n\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\tsubBuffer[xPos] = substitution;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (shouldDrawMutations && chromosomeHasDefaultColor)\n\t\t{\n\t\t\t// If we're drawing mutations as well, then substitutions just get colored blue, to contrast\n\t\t\tNSRect mutationTickRect = NSMakeRect(interiorRect.origin.x, interiorRect.origin.y, 1, interiorRect.size.height);\n\t\t\t\n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n\t\t\t\t\tmutationTickRect.origin.x = interiorRect.origin.x + binIndex;\n\t\t\t\t\tmutationTickRect.size.width = 1;\n\t\t\t\t\t\n\t\t\t\t\t// consolidate adjacent lines together, since they are all the same color\n\t\t\t\t\twhile ((binIndex + 1 < displayPixelWidth) && subBuffer[binIndex + 1])\n\t\t\t\t\t{\n\t\t\t\t\t\tmutationTickRect.size.width++;\n\t\t\t\t\t\tbinIndex++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If we're not drawing mutations as well, then substitutions get colored by selection coefficient, like mutations\n\t\t\tNSRect mutationTickRect = NSMakeRect(interiorRect.origin.x, interiorRect.origin.y, 1, interiorRect.size.height);\n\t\t\t\n\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t{\n\t\t\t\tconst Substitution *substitution = subBuffer[binIndex];\n\t\t\t\t\n\t\t\t\tif (substitution)\n\t\t\t\t{\n\t\t\t\t\tconst MutationType *mutType = substitution->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_sub_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:mutType->color_sub_red_ green:mutType->color_sub_green_ blue:mutType->color_sub_blue_ alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(substitution->selection_coeff_, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmutationTickRect.origin.x = interiorRect.origin.x + binIndex;\n\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(subBuffer);\n\t}\n}\n\n- (void)updateDisplayedMutationTypes\n{\n\t// We use a flag in MutationType to indicate whether we're drawing that type or not; we update those flags here,\n\t// before every drawing of mutations, from the vector of mutation type IDs that we keep internally\n\tSLiMWindowController *controller = (SLiMWindowController *)[[self window] windowController];\n\t\n\tif (controller)\n\t{\n\t\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\t\t\n\t\tif (displaySpecies)\n\t\t{\n\t\t\tstd::map<slim_objectid_t,MutationType*> &muttypes = displaySpecies->mutation_types_;\n\t\t\t\n\t\t\tfor (auto muttype_iter : muttypes)\n\t\t\t{\n\t\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\t\n\t\t\t\tif (display_muttypes_.size())\n\t\t\t\t{\n\t\t\t\t\tslim_objectid_t muttype_id = muttype->mutation_type_id_;\n\t\t\t\t\t\n\t\t\t\t\tmuttype->mutation_type_displayed_ = (std::find(display_muttypes_.begin(), display_muttypes_.end(), muttype_id) != display_muttypes_.end());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmuttype->mutation_type_displayed_ = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)drawMutationsInInteriorRect:(NSRect)interiorRect chromosome:(Chromosome *)chromosome withController:(SLiMWindowController *)controller displayedRange:(NSRange)displayedRange\n{\n\tdouble scalingFactor = 0.8; // used to be controller->selectionColorScale;\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\tPopulation &pop = displaySpecies->population_;\n\tdouble totalHaplosomeCount = chromosome->gui_total_haplosome_count_;\t\t\t\t// this includes only haplosomes in the selected subpopulations\n\tint registry_size;\n\tconst MutationIndex *registry = pop.MutationRegistry(&registry_size);\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tif ((registry_size < 1000) || (displayedRange.length < interiorRect.size.width))\n\t{\n\t\t// This is the simple version of the display code, avoiding the memory allocations and such\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tif (mutation->chromosome_index_ == chromosome_index)\t// display only mutations in the displayed chromosome\n\t\t\t{\n\t\t\t\tconst MutationType *mutType = mutation->mutation_type_ptr_;\n\t\t\t\t\n\t\t\t\tif (mutType->mutation_type_displayed_)\n\t\t\t\t{\n\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\tNSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\n\t\t\t\t\tif (!mutType->color_.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:mutType->color_red_ green:mutType->color_green_ blue:mutType->color_blue_ alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfloat colorRed = 0.0, colorGreen = 0.0, colorBlue = 0.0;\n\t\t\t\t\t\tRGBForSelectionCoeff(mutation->selection_coeff_, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmutationTickRect.size.height = (int)ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.size.height);\n\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We have a lot of mutations, so let's try to be smarter.  It's hard to be smarter.  The overhead from allocating the NSColors and such\n\t\t// is pretty negligible; practially all the time is spent in NSRectFill().  Unfortunately, NSRectFillListWithColors() provides basically\n\t\t// no speedup; Apple doesn't appear to have optimized it.  So, here's what I came up with.  For each mutation type that uses a fixed DFE,\n\t\t// and thus a fixed color, we can do a radix sort of mutations into bins corresponding to each pixel in our displayed image.  Then we\n\t\t// can draw each bin just once, making one bar for the highest bar in that bin.  Mutations from non-fixed DFEs, and mutations which have\n\t\t// had their selection coefficient changed, will be drawn at the end in the usual (slow) way.\n\t\tfloat colorRed = 0.0, colorGreen = 0.0, colorBlue = 0.0;\n\t\tint displayPixelWidth = (int)interiorRect.size.width;\n\t\tint16_t *heightBuffer = (int16_t *)malloc(displayPixelWidth * sizeof(int16_t));\n\t\tbool *mutationsPlotted = (bool *)calloc(registry_size, sizeof(bool));\t// faster than using gui_scratch_reference_count_ because of cache locality\n\t\tint64_t remainingMutations = registry_size;\n\t\t\n\t\t// First zero out the scratch refcount, which we use to track which mutations we have drawn already\n\t\t//for (int mutIndex = 0; mutIndex < mutationCount; ++mutIndex)\n\t\t//\tmutations[mutIndex]->gui_scratch_reference_count_ = 0;\n\t\t\n\t\t// Then loop through the declared mutation types\n\t\tfor (auto mutationTypeIter : displaySpecies->mutation_types_)\n\t\t{\n\t\t\tMutationType *mut_type = mutationTypeIter.second;\n\t\t\t\n\t\t\tif (mut_type->mutation_type_displayed_)\n\t\t\t{\n\t\t\t\tbool mut_type_fixed_color = !mut_type->color_.empty();\n\t\t\t\t\n\t\t\t\t// We optimize fixed-DFE mutation types only, and those using a fixed color set by the user\n\t\t\t\tif ((mut_type->dfe_type_ == DFEType::kFixed) || mut_type_fixed_color)\n\t\t\t\t{\n\t\t\t\t\tslim_selcoeff_t mut_type_selcoeff = (mut_type_fixed_color ? 0.0 : (slim_selcoeff_t)mut_type->dfe_parameters_[0]);\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_BZERO(heightBuffer, displayPixelWidth * sizeof(int16_t));\n\t\t\t\t\t\n\t\t\t\t\t// Scan through the mutation list for mutations of this type with the right selcoeff\n\t\t\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mutation->mutation_type_ptr_ == mut_type) && (mut_type_fixed_color || (mutation->selection_coeff_ == mut_type_selcoeff)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutation->chromosome_index_ == chromosome_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// includes only refs from the selected subpopulations\n\t\t\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\t\t\tint16_t height = (int16_t)ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.size.height);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t\t\t\tif (height > heightBuffer[xPos])\n\t\t\t\t\t\t\t\t\t\theightBuffer[xPos] = height;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\t\tmutationsPlotted[registry_index] = true;\n\t\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Now draw all of the mutations we found, by looping through our radix bins\n\t\t\t\t\tif (mut_type_fixed_color)\n\t\t\t\t\t{\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:mut_type->color_red_ green:mut_type->color_green_ blue:mut_type->color_blue_ alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tRGBForSelectionCoeff(mut_type_selcoeff, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\tint height = heightBuffer[binIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (height)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNSRect mutationTickRect = NSMakeRect(interiorRect.origin.x + binIndex, interiorRect.origin.y, 1, height);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We're not displaying this mutation type, so we need to mark off all the mutations belonging to it as handled\n\t\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\t{\n\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n\t\t\t\t\t\n\t\t\t\t\tif (mutation->mutation_type_ptr_ == mut_type)\n\t\t\t\t\t{\n\t\t\t\t\t\t// tally this mutation as handled\n\t\t\t\t\t\t//mutation->gui_scratch_reference_count_ = 1;\n\t\t\t\t\t\tmutationsPlotted[registry_index] = true;\n\t\t\t\t\t\t--remainingMutations;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Draw any undrawn mutations on top; these are guaranteed not to use a fixed color set by the user, since those are all handled above\n\t\tif (remainingMutations)\n\t\t{\n\t\t\tif (remainingMutations < 1000)\n\t\t\t{\n\t\t\t\t// Plot the remainder by brute force, since there are not that many\n\t\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[registry_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutation->chromosome_index_ == chromosome_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t\tNSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmutationTickRect.size.height = (int)ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.size.height);\n\t\t\t\t\t\t\tRGBForSelectionCoeff(mutation->selection_coeff_, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// OK, we have a lot of mutations left to draw.  Here we will again use the radix sort trick, to keep track of only the tallest bar in each column\n\t\t\t\tMutationIndex *mutationBuffer = (MutationIndex *)calloc(displayPixelWidth, sizeof(MutationIndex));\n\t\t\t\t\n\t\t\t\tEIDOS_BZERO(heightBuffer, displayPixelWidth * sizeof(int16_t));\n\t\t\t\t\n\t\t\t\t// Find the tallest bar in each column\n\t\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\t{\n\t\t\t\t\t//if (mutation->gui_scratch_reference_count_ == 0)\n\t\t\t\t\tif (!mutationsPlotted[registry_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mutationBlockIndex = registry[registry_index];\n\t\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + mutationBlockIndex;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutation->chromosome_index_ == chromosome_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_refcount_t mutationRefCount = mutation->gui_reference_count_;\t\t// this includes only references made from the selected subpopulations\n\t\t\t\t\t\t\tslim_position_t mutationPosition = mutation->position_;\n\t\t\t\t\t\t\t//NSRect mutationTickRect = [self rectEncompassingBase:mutationPosition toBase:mutationPosition interiorRect:interiorRect displayedRange:displayedRange];\n\t\t\t\t\t\t\t//int xPos = (int)(mutationTickRect.origin.x - interiorRect.origin.x);\n\t\t\t\t\t\t\tint xPos = LEFT_OFFSET_OF_BASE(mutationPosition, interiorRect, displayedRange);\n\t\t\t\t\t\t\tint16_t height = (int16_t)ceil((mutationRefCount / totalHaplosomeCount) * interiorRect.size.height);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((xPos >= 0) && (xPos < displayPixelWidth))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (height > heightBuffer[xPos])\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\theightBuffer[xPos] = height;\n\t\t\t\t\t\t\t\t\tmutationBuffer[xPos] = mutationBlockIndex;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now plot the bars\n\t\t\t\tfor (int binIndex = 0; binIndex < displayPixelWidth; ++binIndex)\n\t\t\t\t{\n\t\t\t\t\tint height = heightBuffer[binIndex];\n\t\t\t\t\t\n\t\t\t\t\tif (height)\n\t\t\t\t\t{\n\t\t\t\t\t\tNSRect mutationTickRect = NSMakeRect(interiorRect.origin.x + binIndex, interiorRect.origin.y, 1, height);\n\t\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + mutationBuffer[binIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tRGBForSelectionCoeff(mutation->selection_coeff_, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t\t\t\t[[NSColor colorWithCalibratedRed:colorRed green:colorGreen blue:colorBlue alpha:1.0] set];\n\t\t\t\t\t\tNSRectFill(mutationTickRect);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfree(mutationBuffer);\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(heightBuffer);\n\t\tfree(mutationsPlotted);\n\t}\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tSLiMWindowController *controller = (SLiMWindowController *)[[self window] windowController];\n\tbool ready = ([self enabled] && ![controller invalidSimulation]);\n\tNSRect contentRect = [self contentRect];\n\tNSRect interiorRect = [self interiorRect];\n\t\n\t// if the simulation is at tick 0, it is not ready\n\tif (ready)\n\t\tif (controller->community->Tick() == 0)\n\t\t\tready = NO;\n\t\n\tif (ready)\n\t{\n\t\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\t\tconst std::vector<Chromosome *> &chromosomes = displaySpecies->Chromosomes();\n\t\tint chromosomeCount = (int)chromosomes.size();\n\t\tint64_t availableWidth = (int64_t)(contentRect.size.width - (chromosomeCount * 2) - (chromosomeCount - 1) * spaceBetweenChromosomes);\n\t\tint64_t totalLength = 0;\n\t\t\n\t\tfor (Chromosome *chrom : chromosomes)\n\t\t{\n\t\t\tslim_position_t chromLength = (chrom->last_position_ + 1);\n\t\t\t\n\t\t\ttotalLength += chromLength;\n\t\t}\n\t\t\n\t\tint64_t remainingLength = totalLength;\n\t\tint leftPosition = (int)contentRect.origin.x;\n\t\t\n\t\tfor (Chromosome *chrom : chromosomes)\n\t\t{\n\t\t\tdouble scale = (double)availableWidth / remainingLength;\n\t\t\tslim_position_t chromLength = (chrom->last_position_ + 1);\n\t\t\tint width = (int)round(chromLength * scale);\n\t\t\tint paddedWidth = 2 + width;\n\t\t\tNSRect chromContentRect = NSMakeRect(leftPosition, contentRect.origin.y, paddedWidth, contentRect.size.height);\n\t\t\tNSRect chromInteriorRect = NSInsetRect(chromContentRect, 1, 1);\n\t\t\t\n\t\t\t// erase the content area itself\n\t\t\t[[NSColor colorWithCalibratedWhite:0.0 alpha:1.0] set];\n\t\t\tNSRectFill(chromInteriorRect);\n\t\t\t\n\t\t\tNSRange displayedRange = [self displayedRangeForChromosome:chrom];\n\t\t\t\n\t\t\tBOOL splitHeight = (shouldDrawRateMaps && shouldDrawGenomicElements);\n\t\t\tNSRect topInteriorRect = chromInteriorRect, bottomInteriorRect = chromInteriorRect;\n\t\t\tCGFloat halfHeight = ceil(chromInteriorRect.size.height / 2.0);\n\t\t\tCGFloat remainingHeight = chromInteriorRect.size.height - halfHeight;\n\t\t\t\n\t\t\ttopInteriorRect.size.height = halfHeight;\n\t\t\ttopInteriorRect.origin.y += remainingHeight;\n\t\t\tbottomInteriorRect.size.height = remainingHeight;\n\t\t\t\n\t\t\t// draw ticks at bottom of content rect\n\t\t\tif (![self overview] && !NSContainsRect(chromInteriorRect, dirtyRect))\n\t\t\t\t[self drawTicksInContentRect:chromContentRect withController:controller displayedRange:displayedRange];\n\t\t\t\n\t\t\t// draw recombination intervals in interior\n\t\t\tif (shouldDrawRateMaps)\n\t\t\t\t[self drawRateMapsInInteriorRect:(splitHeight ? topInteriorRect : chromInteriorRect) chromosome:chrom withController:controller displayedRange:displayedRange];\n\t\t\t\n\t\t\t// draw genomic elements in interior\n\t\t\tif (shouldDrawGenomicElements)\n\t\t\t\t[self drawGenomicElementsInInteriorRect:(splitHeight ? bottomInteriorRect : chromInteriorRect) chromosome:chrom withController:controller displayedRange:displayedRange];\n\t\t\t\n\t\t\t// figure out which mutation types we're displaying\n\t\t\tif (shouldDrawFixedSubstitutions || shouldDrawMutations)\n\t\t\t\t[self updateDisplayedMutationTypes];\n\t\t\t\n\t\t\t// draw fixed substitutions in interior\n\t\t\tif (shouldDrawFixedSubstitutions)\n\t\t\t\t[self drawFixedSubstitutionsInInteriorRect:chromInteriorRect chromosome:chrom withController:controller displayedRange:displayedRange];\n\t\t\t\n\t\t\t// draw mutations in interior\n\t\t\tif (shouldDrawMutations)\n\t\t\t\t[self drawMutationsInInteriorRect:chromInteriorRect chromosome:chrom withController:controller displayedRange:displayedRange];\n\t\t\t\n\t\t\t// frame near the end, so that any roundoff errors that caused overdrawing by a pixel get cleaned up\n\t\t\t[[NSColor colorWithCalibratedWhite:0.6 alpha:1.0] set];\n\t\t\tNSFrameRect(chromContentRect);\n\t\t\t\n\t\t\tleftPosition += (paddedWidth + spaceBetweenChromosomes);\n\t\t\tavailableWidth -= width;\n\t\t\tremainingLength -= chromLength;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// erase the content area itself\n\t\t[[NSColor colorWithCalibratedWhite:0.88 alpha:1.0] set];\n\t\tNSRectFill(interiorRect);\n\t\t\n\t\t// frame\n\t\t[[NSColor colorWithCalibratedWhite:0.6 alpha:1.0] set];\n\t\tNSFrameRect(contentRect);\n\t}\n}\n\n- (IBAction)filterMutations:(id)sender\n{\n\tNSMenuItem *senderMenuItem = (NSMenuItem *)sender;\n\tslim_objectid_t muttype_id = (int)[senderMenuItem tag];\n\t\n\tif (muttype_id == -1)\n\t{\n\t\tdisplay_muttypes_.clear();\n\t}\n\telse\n\t{\n\t\tauto present_iter = std::find(display_muttypes_.begin(), display_muttypes_.end(), muttype_id);\n\t\t\n\t\tif (present_iter == display_muttypes_.end())\n\t\t{\n\t\t\t// this mut-type is not being displayed, so add it to our display list\n\t\t\tdisplay_muttypes_.emplace_back(muttype_id);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this mut-type is being displayed, so remove it from our display list\n\t\t\tdisplay_muttypes_.erase(present_iter);\n\t\t}\n\t}\n\t\n\t[self setNeedsDisplayAll];\n}\n\t\n- (IBAction)filterNonNeutral:(id)sender\n{\n\tSLiMWindowController *controller = (SLiMWindowController *)[[self window] windowController];\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tdisplay_muttypes_.clear();\n\t\t\n\t\tstd::map<slim_objectid_t,MutationType*> &muttypes = displaySpecies->mutation_types_;\n\t\t\n\t\tfor (auto muttype_iter : muttypes)\n\t\t{\n\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\tslim_objectid_t muttype_id = muttype->mutation_type_id_;\n\t\t\t\n\t\t\tif ((muttype->dfe_type_ != DFEType::kFixed) || (muttype->dfe_parameters_[0] != 0.0))\n\t\t\t\tdisplay_muttypes_.emplace_back(muttype_id);\n\t\t}\n\t\t\n\t\t[self setNeedsDisplayAll];\n\t}\n}\n\n- (NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tSLiMWindowController *controller = (SLiMWindowController *)[[self window] windowController];\n\t\n\tif (![controller invalidSimulation] && ![[controller window] attachedSheet] && ![self overview] && [self enabled])\n\t{\n\t\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\t\t\n\t\tif (displaySpecies)\n\t\t{\n\t\t\tstd::map<slim_objectid_t,MutationType*> &muttypes = displaySpecies->mutation_types_;\n\t\t\t\n\t\t\tif (muttypes.size() > 0)\n\t\t\t{\n\t\t\t\tNSMenu *menu = [[NSMenu alloc] initWithTitle:@\"chromosome_menu\"];\n\t\t\t\tNSMenuItem *menuItem;\n\t\t\t\t\n\t\t\t\tmenuItem = [menu addItemWithTitle:@\"Display All Mutations\" action:@selector(filterMutations:) keyEquivalent:@\"\"];\n\t\t\t\t[menuItem setTag:-1];\n\t\t\t\t[menuItem setTarget:self];\n\t\t\t\t\n\t\t\t\tif (display_muttypes_.size() == 0)\n\t\t\t\t\t[menuItem setState:NSOnState];\n\t\t\t\t\n\t\t\t\t// Make a sorted list of all mutation types we know – those that exist, and those that used to exist that we are displaying\n\t\t\t\tstd::vector<slim_objectid_t> all_muttypes;\n\t\t\t\t\n\t\t\t\tfor (auto muttype_iter : muttypes)\n\t\t\t\t{\n\t\t\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\t\tslim_objectid_t muttype_id = muttype->mutation_type_id_;\n\t\t\t\t\t\n\t\t\t\t\tall_muttypes.emplace_back(muttype_id);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tall_muttypes.insert(all_muttypes.end(), display_muttypes_.begin(), display_muttypes_.end());\n\t\t\t\t\n\t\t\t\t// Avoid building a huge menu, which will hang the app\n\t\t\t\tif (all_muttypes.size() <= 500)\n\t\t\t\t{\n\t\t\t\t\tstd::sort(all_muttypes.begin(), all_muttypes.end());\n\t\t\t\t\tall_muttypes.resize(std::distance(all_muttypes.begin(), std::unique(all_muttypes.begin(), all_muttypes.end())));\n\t\t\t\t\t\n\t\t\t\t\t// Then add menu items for each of those muttypes\n\t\t\t\t\tfor (slim_objectid_t muttype_id : all_muttypes)\n\t\t\t\t\t{\n\t\t\t\t\t\tmenuItem = [menu addItemWithTitle:[NSString stringWithFormat:@\"Display m%d\", (int)muttype_id] action:@selector(filterMutations:) keyEquivalent:@\"\"];\n\t\t\t\t\t\t[menuItem setTag:muttype_id];\n\t\t\t\t\t\t[menuItem setTarget:self];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (std::find(display_muttypes_.begin(), display_muttypes_.end(), muttype_id) != display_muttypes_.end())\n\t\t\t\t\t\t\t[menuItem setState:NSOnState];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\t\t\t\n\t\t\t\tmenuItem = [menu addItemWithTitle:@\"Select Non-Neutral MutationTypes\" action:@selector(filterNonNeutral:) keyEquivalent:@\"\"];\n\t\t\t\t[menuItem setTarget:self];\n\t\t\t\t\n\t\t\t\treturn [menu autorelease];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn nil;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/CocoaExtra.h",
    "content": "//\n//  CocoaExtra.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/22/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n@class SLiMWindowController;\nclass MutationType;\nclass InteractionType;\n\n// Returns true if we are running under the debugger\nbool SLiM_AmIBeingDebugged(void);\n\n// An NSTableView subclass that avoids becoming first responder; annoying that this is necessary, sigh...\n@interface SLiMTableView : NSTableView\n@end\n\n// A button that runs a pop-up menu when clicked\n@interface SLiMMenuButton : NSButton\n@property (nonatomic, retain) NSMenu *slimMenu;\n@end\n\n// A cell that draws a color swatch, used in the genomic element type tableview; note it is a subclass of NSTextFieldCell only for IB convenience...\n@interface SLiMColorCell : NSTextFieldCell\n@end\n\nvoid RGBForFitness(double fitness, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor);\nvoid RGBForSelectionCoeff(double selectionCoeff, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor);\n\n// Classes to show a selection index marker when dragging out a selection in a ChromosomeView\n@interface SLiMSelectionView : NSView\n@end\n\n@interface SLiMSelectionMarker : NSPanel\n@property (nonatomic, retain) NSString *label;\n@property (nonatomic) NSPoint tipPoint;\n@property (nonatomic) BOOL isLeftMarker;\n\n+ (instancetype)new;\t// makes a new marker, not shown; set it up with a label and tip point and then call orderFront:\n\n@end\n\n// Classes to show a custom tooltip view; this code is derived from SLiMSelectionView / SLiMSelectionMarker\n// This is not a general-purpose class really; it is specifically for labeling the Play Speed slider\n@interface SLiMPlaySliderToolTipView : NSView\n@end\n\n@interface SLiMPlaySliderToolTipWindow : NSPanel\n@property (nonatomic, retain) NSString *label;\n@property (nonatomic) NSPoint tipPoint;\n\n+ (instancetype)new;\t// makes a new marker, not shown; set it up with a label and tip point and then call orderFront:\n\n@end\n\n// Classes to show a custom tooltip view displaying a graph of a mutation type's DFE in the muttype table view\n// Now also used for similarly displaying an interaction type's IF in the interaction type table view\n@interface SLiMFunctionGraphToolTipView : NSView\n@end\n\n@interface SLiMFunctionGraphToolTipWindow : NSPanel\n@property (nonatomic, assign) MutationType *mutType;\n@property (nonatomic, assign) InteractionType *interactionType;\n@property (nonatomic) NSPoint tipPoint;\n\n+ (instancetype)new;\t// makes a new marker, not shown; set it up with a mutType/intType and tip point and then call orderFront:\n\n@end\n\n\n// A category to help us position windows visibly\n@interface NSScreen (SLiMWindowFrames)\n+ (BOOL)visibleCandidateWindowFrame:(NSRect)candidateFrame;\n@end\n\n// A category to add sorting of menus\n@interface NSPopUpButton (SLiMSorting)\n- (void)slimSortMenuItemsByTag;\n@end\n\n// A category to add tinting of NSPopUpButton, used in the ScriptMod panels for validation\n@interface NSButton (SLiMTinting)\n- (void)slimSetTintColor:(NSColor *)tintColor;\n@end\n\n// This is a vestigial tail left over from the old ScriptMod class of SLiMguiLegacy; I ripped out that class completely,\n// but a few other places in the code used its validation logic for their own purposes, so I've moved that to CocoaExtra.\n@interface ScriptMod : NSObject\n+ (BOOL)validIntValueInTextField:(NSTextField *)textfield withMin:(int64_t)minValue max:(int64_t)maxValue;\n+ (BOOL)validFloatValueInTextField:(NSTextField *)textfield withMin:(double)minValue max:(double)maxValue;\n+ (NSColor *)backgroundColorForValidationState:(BOOL)valid;\n@end\n\n// A subclass to make an NSTextView that selects its content when clicked, for the tick textfield\n@interface SLiMAutoselectTextField : NSTextField\n@end\n\n// A subclass for a view that forces its (single) subview to match its own bounds, except that a half-pixel\n// alignment in this view will be corrected in the subview; this makes OpenGL views play nice with Retina.\n// This code is not general-purpose at the moment, it works only specifically with SLiMgui's view setup.\n@interface SLiMLayoutRoundoffView : NSView\n@end\n\n@interface NSString (SLiMBytes)\n+ (NSString *)stringForByteCount:(int64_t)bytes;\n@end\n\n@interface NSColor (SLiMHeatColors)\n+ (NSColor *)slimColorForFraction:(double)fraction;\n@end\n\n@interface NSAttributedString (SLiMBytes)\n+ (NSAttributedString *)attributedStringForByteCount:(int64_t)bytes total:(double)total attributes:(NSDictionary *)attrs;\n@end\n\n// Create a path for a temporary file; see https://stackoverflow.com/a/8307013/2752221\n// Code is originally from https://developer.apple.com/library/archive/samplecode/SimpleURLConnections/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009245\n@interface NSString (SLiMTempFiles)\n+ (NSString *)slimPathForTemporaryFileWithPrefix:(NSString *)prefix;\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/CocoaExtra.mm",
    "content": "//\n//  CocoaExtra.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/22/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"CocoaExtra.h\"\n#import \"AppDelegate.h\"\n\n#include \"eidos_rng.h\"\n#include \"mutation_type.h\"\n#include \"interaction_type.h\"\n\n// for SLiM_AmIBeingDebugged()\n#include <assert.h>\n#include <stdbool.h>\n#include <sys/types.h>\n#include <unistd.h>\n#include <sys/sysctl.h>\n#include <ctime>\n\n// From Apple tech note #1361, https://developer.apple.com/library/archive/qa/qa1361/_index.html\n// see https://stackoverflow.com/a/2200786/2752221\nbool SLiM_AmIBeingDebugged(void)\n    // Returns true if the current process is being debugged (either \n    // running under the debugger or has a debugger attached post facto).\n{\n    int                 junk;\n    int                 mib[4];\n    struct kinfo_proc   info;\n    size_t              size;\n\n    // Initialize the flags so that, if sysctl fails for some bizarre \n    // reason, we get a predictable result.\n\n    info.kp_proc.p_flag = 0;\n\n    // Initialize mib, which tells sysctl the info we want, in this case\n    // we're looking for information about a specific process ID.\n\n    mib[0] = CTL_KERN;\n    mib[1] = KERN_PROC;\n    mib[2] = KERN_PROC_PID;\n    mib[3] = getpid();\n\n    // Call sysctl.\n\n    size = sizeof(info);\n    junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);\n    assert(junk == 0);\n\n    // We're being debugged if the P_TRACED flag is set.\n\n    return ( (info.kp_proc.p_flag & P_TRACED) != 0 );\n}\n\n@implementation SLiMTableView\n\n- (BOOL)acceptsFirstResponder\n{\n\treturn NO;\n}\n\n@end\n\n\nconst float greenBrightness = 0.8f;\n\nvoid RGBForFitness(double value, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor)\n{\n\t// apply the scaling factor\n\tvalue = (value - 1.0) * scalingFactor + 1.0;\n\t\n\tif (value <= 0.5)\n\t{\n\t\t// value <= 0.5 is a shade of red, going down to black\n\t\t*colorRed = (float)(value * 2.0);\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value >= 2.0)\n\t{\n\t\t// value >= 2.0 is a shade of green, going up to white\n\t\t*colorRed = (float)((value - 2.0) * greenBrightness / value);\n\t\t*colorGreen = greenBrightness;\n\t\t*colorBlue = (float)((value - 2.0) * greenBrightness / value);\n\t}\n\telse if (value <= 1.0)\n\t{\n\t\t// value <= 1.0 (but > 0.5) goes from red (unfit) to yellow (neutral)\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = (float)((value - 0.5) * 2.0);\n\t\t*colorBlue = 0.0;\n\t}\n\telse\t// 1.0 < value < 2.0\n\t{\n\t\t// value > 1.0 (but < 2.0) goes from yellow (neutral) to green (fit)\n\t\t*colorRed = (float)(2.0 - value);\n\t\t*colorGreen = (float)(greenBrightness + (1.0 - greenBrightness) * (2.0 - value));\n\t\t*colorBlue = 0.0;\n\t}\n}\n\nvoid RGBForSelectionCoeff(double value, float *colorRed, float *colorGreen, float *colorBlue, double scalingFactor)\n{\n\t// apply a scaling factor; this could be user-adjustible since different models have different relevant fitness ranges\n\tvalue *= scalingFactor;\n\t\n\t// and add 1, just so we can re-use the same code as in RGBForFitness()\n\tvalue += 1.0;\n\t\n\tif (value <= 0.0)\n\t{\n\t\t// value <= 0.0 is the darkest shade of red we use\n\t\t*colorRed = 0.5;\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value <= 0.5)\n\t{\n\t\t// value <= 0.5 is a shade of red, going down toward black\n\t\t*colorRed = (float)(value + 0.5);\n\t\t*colorGreen = 0.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value < 1.0)\n\t{\n\t\t// value <= 1.0 (but > 0.5) goes from red (very unfit) to orange (nearly neutral)\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = (float)((value - 0.5) * 1.0);\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value == 1.0)\n\t{\n\t\t// exactly neutral mutations are yellow\n\t\t*colorRed = 1.0;\n\t\t*colorGreen = 1.0;\n\t\t*colorBlue = 0.0;\n\t}\n\telse if (value <= 1.5)\n\t{\n\t\t// value > 1.0 (but < 1.5) goes from green (nearly neutral) to cyan (fit)\n\t\t*colorRed = 0.0;\n\t\t*colorGreen = greenBrightness;\n\t\t*colorBlue = (float)((value - 1.0) * 2.0);\n\t}\n\telse if (value <= 2.0)\n\t{\n\t\t// value > 1.5 (but < 2.0) goes from cyan (fit) to blue (very fit)\n\t\t*colorRed = 0.0;\n\t\t*colorGreen = (float)(greenBrightness * ((2.0 - value) * 2.0));\n\t\t*colorBlue = 1.0;\n\t}\n\telse // (value > 2.0)\n\t{\n\t\t// value > 2.0 is a shade of blue, going up toward white\n\t\t*colorRed = (float)((value - 2.0) * 0.75 / value);\n\t\t*colorGreen = (float)((value - 2.0) * 0.75 / value);\n\t\t*colorBlue = 1.0;\n\t}\n}\n\n\n@implementation SLiMMenuButton\n\n- (void)dealloc\n{\n\t[self setSlimMenu:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)fixMenu\n{\n\tNSMenu *menu = [self slimMenu];\n\tNSDictionary *itemAttrs = @{NSFontAttributeName : [NSFont systemFontOfSize:12.0]};\n\t\n\tfor (int i = 0; i < [menu numberOfItems]; ++i)\n\t{\n\t\tNSMenuItem *menuItem = [menu itemAtIndex:i];\n\t\tNSString *title = [menuItem title];\n\t\tNSAttributedString *attrTitle = [[NSAttributedString alloc] initWithString:title attributes:itemAttrs];\n\t\t\n\t\t[menuItem setAttributedTitle:attrTitle];\n\t\t[attrTitle release];\n\t}\n}\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\t// We do not call super; we do mouse tracking entirely ourselves\n\t//[super mouseDown:theEvent];\n\t\n\tif ([self isEnabled])\n\t{\n\t\tNSRect bounds = [self bounds];\n\t\t\n\t\t[self highlight:YES];\n\t\t\n\t\t[self fixMenu];\n\t\t[[self slimMenu] popUpMenuPositioningItem:nil atLocation:NSMakePoint(bounds.size.width * 0.80 - 1, bounds.size.height * 0.80 + 1) inView:self];\n\t\t\n\t\t[self highlight:NO];\n\t}\n}\n\n- (void)mouseDragged:(NSEvent *)theEvent\n{\n\t// We do not call super; we do mouse tracking entirely ourselves\n\t//[super mouseDragged:theEvent];\n}\n\n- (void)mouseUp:(NSEvent *)theEvent\n{\n\t// We do not call super; we do mouse tracking entirely ourselves\n\t//[super mouseDown:theEvent];\n}\n\n@end\n\n@implementation SLiMColorCell\n\n- (void)setObjectValue:(id)objectValue\n{\n\t// Ensure that only NSColor objects are set as our object value\n\tif ([objectValue isKindOfClass:[NSColor class]])\n\t\t[super setObjectValue:objectValue];\n}\n\n- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView\n{\n\tNSRect swatchFrame = NSInsetRect(cellFrame, 1, 1);\n\t\n\t// Make our swatch be square, if we have enough room to do it\n\tif (swatchFrame.size.width > swatchFrame.size.height)\n\t{\n\t\tswatchFrame.origin.x = (int)round(swatchFrame.origin.x + (swatchFrame.size.width - swatchFrame.size.height) / 2.0);\n\t\tswatchFrame.size.width = swatchFrame.size.height;\n\t}\n\t\n\t[[NSColor blackColor] set];\n\tNSFrameRect(swatchFrame);\n\t\n\t[(NSColor *)[self objectValue] set];\n\tNSRectFill(NSInsetRect(swatchFrame, 1, 1));\n}\n\n@end\n\n\n@implementation SLiMSelectionView\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tstatic NSDictionary *labelAttrs = nil;\n\t\n\tif (!labelAttrs)\n\t\tlabelAttrs = [@{NSFontAttributeName : [NSFont fontWithName:@\"Times New Roman\" size:10], NSForegroundColorAttributeName : [NSColor blackColor]} retain];\n\t\n\tNSRect bounds = [self bounds];\n\tSLiMSelectionMarker *marker = (SLiMSelectionMarker *)[self window];\n\tNSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:[marker label] attributes:labelAttrs];\n\tNSSize labelStringSize = [attrLabel size];\n\tNSSize labelSize = NSMakeSize(round(labelStringSize.width + 8.0), round(labelStringSize.height + 1.0));\n\tNSRect labelRect = NSMakeRect(bounds.origin.x + round(bounds.size.width / 2.0), bounds.origin.y + bounds.size.height - labelSize.height, labelSize.width, labelSize.height);\n\t\n\tif ([marker isLeftMarker])\n\t\tlabelRect.origin.x -= round(labelSize.width - 1.0);\n\t\n\t// Frame our whole bounds, for debugging; note that we draw in only a portion of our bounds, and the rest is transparent\n\t//[[NSColor blackColor] set];\n\t//NSFrameRect(bounds);\n\t\n#if 0\n\t// Debugging code: frame and fill our label rect without using NSBezierPath\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.2 brightness:1.0 alpha:1.0] set];\n\tNSRectFill(labelRect);\n\t\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.2 brightness:0.3 alpha:1.0] set];\n\tNSFrameRect(labelRect);\n#else\n\t// Production code: use NSBezierPath to get a label that has a tag off of it\n\tNSBezierPath *bez = [NSBezierPath bezierPath];\n\tNSRect ilr = NSInsetRect(labelRect, 0.5, 0.5);\t// inset by 0.5 to place us mid-pixel, so stroke looks good\n\tconst double tagHeight = 5.0;\n\t\n\tif ([marker isLeftMarker])\n\t{\n\t\t// label rect with a diagonal tag down from the right edge\n\t\t[bez moveToPoint:NSMakePoint(ilr.origin.x, ilr.origin.y)];\n\t\t[bez relativeLineToPoint:NSMakePoint(ilr.size.width - tagHeight, 0)];\n\t\t[bez relativeLineToPoint:NSMakePoint(tagHeight, -tagHeight)];\n\t\t[bez relativeLineToPoint:NSMakePoint(0, ilr.size.height + tagHeight)];\n\t\t[bez relativeLineToPoint:NSMakePoint(-ilr.size.width, 0)];\n\t\t[bez closePath];\n\t}\n\telse\n\t{\n\t\t// label rect with a diagonal tag down from the right edge\n\t\t[bez moveToPoint:NSMakePoint(ilr.origin.x + ilr.size.width, ilr.origin.y)];\n\t\t[bez relativeLineToPoint:NSMakePoint(- (ilr.size.width - tagHeight), 0)];\n\t\t[bez relativeLineToPoint:NSMakePoint(-tagHeight, -tagHeight)];\n\t\t[bez relativeLineToPoint:NSMakePoint(0, ilr.size.height + tagHeight)];\n\t\t[bez relativeLineToPoint:NSMakePoint(ilr.size.width, 0)];\n\t\t[bez closePath];\n\t}\n\t\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.2 brightness:1.0 alpha:1.0] set];\n\t[bez fill];\n\t\n\t[[NSColor blackColor] set];\n\t[bez setLineWidth:1.0];\n\t[bez stroke];\n#endif\n\t\n\t[attrLabel drawAtPoint:NSMakePoint(labelRect.origin.x + 4, labelRect.origin.y + 1)];\n\t[attrLabel release];\n}\n\n- (BOOL)isOpaque\n{\n\treturn NO;\n}\n\n@end\n\n@implementation SLiMSelectionMarker\n\n// makes a new marker with no label and no tip point, not shown\n+ (instancetype)new\n{\n\treturn [[[self class] alloc] initWithContentRect:NSMakeRect(0, 0, 150, 20) styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:YES];\t// 150x20 should suffice, unless we change our font size...\n}\n\n- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag\n{\n\tif (self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag])\n\t{\n\t\t[self setFloatingPanel:YES];\n\t\t[self setBecomesKeyOnlyIfNeeded:YES];\n\t\t[self setHasShadow:NO];\n\t\t[self setOpaque:NO];\n\t\t[self setBackgroundColor:[NSColor clearColor]];\n\t\t\n\t\tSLiMSelectionView *view = [[SLiMSelectionView alloc] initWithFrame:contentRect];\n\t\t\n\t\t[self setContentView:view];\n\t\t[view release];\n\t\t\n\t\t_tipPoint = NSMakePoint(round(contentRect.origin.x + contentRect.size.width / 2.0), contentRect.origin.y);\n\t\t_label = [@\"1000000000\" retain];\n\t}\n\t\n\treturn self;\n}\n\t\n- (void)dealloc\n{\n\t[self setLabel:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)setLabel:(NSString *)label\n{\n\tif (![_label isEqualToString:label])\n\t{\n\t\t[label retain];\n\t\t[_label release];\n\t\t_label = label;\n\t\t\n\t\t[[self contentView] setNeedsDisplay:YES];\n\t}\n}\n\n- (void)setTipPoint:(NSPoint)tipPoint\n{\n\tif (!NSEqualPoints(_tipPoint, tipPoint))\n\t{\n\t\tNSPoint origin = [self frame].origin;\n\t\t\n\t\torigin.x += (tipPoint.x - _tipPoint.x);\n\t\torigin.y += (tipPoint.y - _tipPoint.y);\n\t\t\n\t\t_tipPoint = tipPoint;\n\t\t\n\t\t[self setFrameOrigin:origin];\n\t}\n}\n\n@end\n\n\n@implementation SLiMPlaySliderToolTipView\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tstatic NSDictionary *labelAttrs = nil;\n\t\n\tif (!labelAttrs)\n\t\tlabelAttrs = [@{NSFontAttributeName : [NSFont fontWithName:@\"Times New Roman\" size:10], NSForegroundColorAttributeName : [NSColor blackColor]} retain];\n\t\n\tNSRect bounds = [self bounds];\n\tSLiMPlaySliderToolTipWindow *tooltipWindow = (SLiMPlaySliderToolTipWindow *)[self window];\n\tNSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:[tooltipWindow label] attributes:labelAttrs];\n\tNSSize labelStringSize = [attrLabel size];\n\tNSSize labelSize = NSMakeSize(round(labelStringSize.width + 8.0), round(labelStringSize.height + 1.0));\n\tNSRect labelRect = NSMakeRect(bounds.origin.x, bounds.origin.y + bounds.size.height - labelSize.height, labelSize.width, labelSize.height);\n\t\n\t// Frame our whole bounds, for debugging; note that we draw in only a portion of our bounds, and the rest is transparent\n\t//[[NSColor blackColor] set];\n\t//NSFrameRect(bounds);\n\t\n\t// Frame and fill our label rect\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.2 brightness:1.0 alpha:1.0] set];\n\tNSRectFill(labelRect);\n\t\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.2 brightness:0.3 alpha:1.0] set];\n\tNSFrameRect(labelRect);\n\t\n\t[attrLabel drawAtPoint:NSMakePoint(labelRect.origin.x + 4, labelRect.origin.y + 1)];\n\t[attrLabel release];\n}\n\n- (BOOL)isOpaque\n{\n\treturn NO;\n}\n\n@end\n\n@implementation SLiMPlaySliderToolTipWindow\n\n// makes a new marker with no label and no tip point, not shown\n+ (instancetype)new\n{\n\treturn [[[self class] alloc] initWithContentRect:NSMakeRect(0, 0, 50, 20) styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:YES];\t// 50x20 should suffice, unless we change our font size...\n}\n\n- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag\n{\n\tif (self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag])\n\t{\n\t\t[self setFloatingPanel:YES];\n\t\t[self setBecomesKeyOnlyIfNeeded:YES];\n\t\t[self setHasShadow:NO];\n\t\t[self setOpaque:NO];\n\t\t[self setBackgroundColor:[NSColor clearColor]];\n\t\t\n\t\tSLiMPlaySliderToolTipView *view = [[SLiMPlaySliderToolTipView alloc] initWithFrame:contentRect];\n\t\t\n\t\t[self setContentView:view];\n\t\t[view release];\n\t\t\n\t\t_tipPoint = NSMakePoint(contentRect.origin.x, contentRect.origin.y);\n\t\t_label = [@\"1000000000\" retain];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[self setLabel:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)setLabel:(NSString *)label\n{\n\tif (![_label isEqualToString:label])\n\t{\n\t\t[label retain];\n\t\t[_label release];\n\t\t_label = label;\n\t\t\n\t\t[[self contentView] setNeedsDisplay:YES];\n\t}\n}\n\n- (void)setTipPoint:(NSPoint)tipPoint\n{\n\tif (!NSEqualPoints(_tipPoint, tipPoint))\n\t{\n\t\tNSPoint origin = [self frame].origin;\n\t\t\n\t\torigin.x += (tipPoint.x - _tipPoint.x);\n\t\torigin.y += (tipPoint.y - _tipPoint.y);\n\t\t\n\t\t_tipPoint = tipPoint;\n\t\t\n\t\t[self setFrameOrigin:origin];\n\t}\n}\n\n@end\n\n\n@implementation SLiMFunctionGraphToolTipView\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tstatic NSDictionary *labelAttrs = nil;\n\tstatic NSDictionary *questionMarkAttrs = nil;\n\t\n\tif (!labelAttrs)\n\t{\n\t\tlabelAttrs = [@{NSFontAttributeName : [NSFont fontWithName:@\"Times New Roman\" size:9], NSForegroundColorAttributeName : [NSColor blackColor]} retain];\n\t\tquestionMarkAttrs = [@{NSFontAttributeName : [NSFont fontWithName:@\"Times New Roman\" size:18], NSForegroundColorAttributeName : [NSColor blackColor]} retain];\n\t}\n\t\n\tNSRect bounds = [self bounds];\n\tSLiMFunctionGraphToolTipWindow *tooltipWindow = (SLiMFunctionGraphToolTipWindow *)[self window];\n\t\n\t// Frame and fill our label rect\n\t[[NSColor colorWithCalibratedHue:0.0 saturation:0.0 brightness:0.95 alpha:1.0] set];\n\tNSRectFill(bounds);\n\t\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.0 brightness:0.75 alpha:1.0] set];\n\tNSFrameRect(bounds);\n\t\n\t// Plan our plotting\n\tMutationType *mut_type = [tooltipWindow mutType];\n\tInteractionType *interaction_type = [tooltipWindow interactionType];\n\t\n\tif ((!mut_type && !interaction_type) || (mut_type && interaction_type))\n\t\treturn;\n\t\n\tint sample_size;\n\tstd::vector<double> draws;\n\tbool draw_positive = false, draw_negative = false;\n\tbool heights_negative = false;\n\tdouble axis_min, axis_max;\n\tbool draw_axis_midpoint = true, custom_axis_max = false;\n\t\n\tif (mut_type)\n\t{\n\t\t// Generate draws for a mutation type; this case is stochastic, based upon a large number of DFE samples.\n\t\t// Draw all the values we will plot; we need our own private RNG so we don't screw up the simulation's.\n\t\t// Drawing selection coefficients could raise, if they are type \"s\" and there is an error in the script,\n\t\t// so we run the sampling inside a try/catch block; if we get a raise, we just show a \"?\" in the plot.\n\t\tstatic bool rng_initialized = false;\n\t\tstatic Eidos_RNG_State local_rng;\n\t\t\n\t\tsample_size = (mut_type->dfe_type_ == DFEType::kScript) ? 100000 : 1000000;\t// large enough to make curves pretty smooth, small enough to be reasonably fast\n\t\tdraws.reserve(sample_size);\n\t\t\n\t\tif (!rng_initialized)\n\t\t{\n\t\t\t_Eidos_InitializeOneRNG(local_rng);\n\t\t\trng_initialized = true;\n\t\t}\n\t\t\n\t\t_Eidos_SetOneRNGSeed(local_rng, 10);\t\t// arbitrary seed, but the same seed every time\n\t\t\n\t\tEidos_RNG_State *slim_rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\n\t\tstd::swap(local_rng, *slim_rng_state);\t// swap in our local RNG for DrawSelectionCoefficient()\n\t\t\n\t\t//std::clock_t start = std::clock();\n\t\t\n\t\ttry\n\t\t{\n\t\t\tfor (int sample_count = 0; sample_count < sample_size; ++sample_count)\n\t\t\t{\n\t\t\t\tdouble draw = mut_type->DrawSelectionCoefficient();\n\t\t\t\t\n\t\t\t\tdraws.emplace_back(draw);\n\t\t\t\t\n\t\t\t\tif (draw < 0.0)\t\t\tdraw_negative = true;\n\t\t\t\telse if (draw > 0.0)\tdraw_positive = true;\n\t\t\t}\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tdraws.clear();\n\t\t\tdraw_negative = true;\n\t\t\tdraw_positive = true;\n\t\t}\n\t\t\n\t\t//NSLog(@\"Draws took %f seconds\", (std::clock() - start) / (double)CLOCKS_PER_SEC);\n\t\t\n\t\tstd::swap(local_rng, *slim_rng_state);\t// swap out our local RNG; restore the standard RNG\n\t\t\n\t\t// figure out axis limits\n\t\tif (draw_negative && !draw_positive)\n\t\t{\n\t\t\taxis_min = -1.0;\n\t\t\taxis_max = 0.0;\n\t\t}\n\t\telse if (draw_positive && !draw_negative)\n\t\t{\n\t\t\taxis_min = 0.0;\n\t\t\taxis_max = 1.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\taxis_min = -1.0;\n\t\t\taxis_max = 1.0;\n\t\t}\n\t}\n\telse // if (interaction_type)\n\t{\n\t\t// Since interaction types are deterministic, we don't need draws; we will just calculate our\n\t\t// bin heights directly below.\n\t\tsample_size = 0;\n\t\tdraw_negative = false;\n\t\tdraw_positive = true;\n\t\taxis_min = 0.0;\n\t\tif ((interaction_type->max_distance_ < 1.0) || std::isinf(interaction_type->max_distance_))\n\t\t{\n\t\t\taxis_max = 1.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\taxis_max = interaction_type->max_distance_;\n\t\t\tdraw_axis_midpoint = false;\n\t\t\tcustom_axis_max = true;\n\t\t}\n\t\theights_negative = (interaction_type->if_param1_ < 0.0);\t// this is a negative-strength interaction, if T\n\t}\n\t\n\t// Draw the graph axes and ticks\n\tNSRect graphRect = NSMakeRect(bounds.origin.x + 6, bounds.origin.y + (heights_negative ? 5 : 14), bounds.size.width - 12, bounds.size.height - 20);\n\tCGFloat axis_y = (heights_negative ? graphRect.origin.y + graphRect.size.height - 1 : graphRect.origin.y);\n\tCGFloat tickoff3 = (heights_negative ? 1 : -3);\n\tCGFloat tickoff1 = (heights_negative ? 1 : -1);\n\t\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.0 brightness:0.2 alpha:1.0] set];\n\tNSRectFill(NSMakeRect(graphRect.origin.x, axis_y, graphRect.size.width, 1));\n\t\n\tNSRectFill(NSMakeRect(graphRect.origin.x, axis_y + tickoff3, 1, 3));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.125, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.25, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.375, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.5, axis_y + tickoff3, 1, 3));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.625, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.75, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + (graphRect.size.width - 1) * 0.875, axis_y + tickoff1, 1, 1));\n\tNSRectFill(NSMakeRect(graphRect.origin.x + graphRect.size.width - 1, axis_y + tickoff3, 1, 3));\n\t\n\t// Draw the axis labels\n\tstd::ostringstream ss;\n\tss << axis_max;\n\tstd::string ss_str = ss.str();\n\tNSString *axis_max_pretty_string = [NSString stringWithUTF8String:ss_str.c_str()];\n\t\n\tNSString *axis_min_label = (axis_min == 0.0 ? @\"0\" : @\"−1\");\n\tNSString *axis_half_label = (axis_min == 0.0 ? @\"0.5\" : (axis_max == 0.0 ? @\"−0.5\" : @\"0\"));\n\tNSString *axis_max_label = (custom_axis_max ? axis_max_pretty_string : (axis_max == 0.0 ? @\"0\" : @\"1\"));\n\tNSSize min_label_size = [axis_min_label sizeWithAttributes:labelAttrs];\n\tNSSize half_label_size = [axis_half_label sizeWithAttributes:labelAttrs];\n\tNSSize max_label_size = [axis_max_label sizeWithAttributes:labelAttrs];\n\tdouble min_label_halfwidth = round(min_label_size.width / 2.0);\n\tdouble half_label_halfwidth = round(half_label_size.width / 2.0);\n\tdouble max_label_halfwidth = round(max_label_size.width / 2.0);\n\tCGFloat label_y = (heights_negative ? bounds.origin.y + bounds.size.height - 12 : bounds.origin.y + 1);\n\t\n\t[axis_min_label drawAtPoint:NSMakePoint(bounds.origin.x + 7 - min_label_halfwidth, label_y) withAttributes:labelAttrs];\n\tif (draw_axis_midpoint)\n\t\t[axis_half_label drawAtPoint:NSMakePoint(bounds.origin.x + 38.5 - half_label_halfwidth, label_y) withAttributes:labelAttrs];\n\tif (custom_axis_max)\n\t\t[axis_max_label drawAtPoint:NSMakePoint(bounds.origin.x + 72 - round(max_label_size.width), label_y) withAttributes:labelAttrs];\n\telse\n\t\t[axis_max_label drawAtPoint:NSMakePoint(bounds.origin.x + 70 - max_label_halfwidth, label_y) withAttributes:labelAttrs];\n\t\n\t// If we had an exception while drawing values, just show a question mark and return\n\tif (mut_type && !draws.size())\n\t{\n\t\tNSString *questionMark = @\"?\";\n\t\tNSSize q_size = [questionMark sizeWithAttributes:questionMarkAttrs];\n\t\tdouble q_halfwidth = round(q_size.width / 2.0);\n\t\t\n\t\t[questionMark drawAtPoint:NSMakePoint(bounds.origin.x + bounds.size.width / 2.0 - q_halfwidth, bounds.origin.y + 22) withAttributes:questionMarkAttrs];\n\t\treturn;\n\t}\n\t\n\tNSRect interiorRect = NSMakeRect(graphRect.origin.x, graphRect.origin.y + (heights_negative ? 0 : 2), graphRect.size.width, graphRect.size.height - 2);\n\t\n\t// Tabulate the distribution from the samples we took; the math here is a bit subtle, because when we are doing a -1 to +1 axis\n\t// we want those values to fall at bin centers, but when we're doing 0 to +1 or -1 to 0 we want 0 to fall at the bin edge.\n\tint half_bin_count = (int)round(interiorRect.size.width);\n\tint bin_count = half_bin_count * 2;\t\t\t\t\t\t\t\t// 2x bins to look nice on Retina displays\n\tdouble *bins = (double *)calloc(bin_count, sizeof(double));\n\t\n\tif (sample_size)\n\t{\n\t\t// sample-based tabulation into a histogram; mutation types only, right now\n\t\tfor (int sample_count = 0; sample_count < sample_size; ++sample_count)\n\t\t{\n\t\t\tdouble sel_coeff = draws[sample_count];\n\t\t\tint bin_index;\n\t\t\t\n\t\t\tif ((axis_min == -1.0) && (axis_max == 1.0))\n\t\t\t\tbin_index = (int)floor(((sel_coeff + 1.0) / 2.0) * (bin_count - 1) + 0.5);\n\t\t\telse if ((axis_min == -1.0) && (axis_max == 0.0))\n\t\t\t\tbin_index = (int)ceil((sel_coeff + 1.0) * (bin_count - 1 - 0.5) + 0.5);\t\t// 0.0 maps to bin_count - 1, -1.0 maps to the center of bin 0\n\t\t\telse // if ((axis_min == 0.0) && (axis_max == 1.0))\n\t\t\t\tbin_index = (int)floor(sel_coeff * (bin_count - 1 + 0.5));\t\t\t\t\t// 0.0 maps to 0, 1.0 maps to the center of bin_count - 1\n\t\t\t\n\t\t\tif ((bin_index >= 0) && (bin_index < bin_count))\n\t\t\t\tbins[bin_index]++;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// non-sample-based construction of a function by evaluation; interaction types only, right now\n\t\tdouble max_x = interaction_type->max_distance_;\n\t\t\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tdouble bin_left = (bin_index / (double)bin_count) * axis_max;\n\t\t\tdouble bin_right = ((bin_index + 1) / (double)bin_count) * axis_max;\n\t\t\tdouble total_value = 0.0;\n\t\t\t\n\t\t\tfor (int evaluate_index = 0; evaluate_index <= 999; ++evaluate_index)\n\t\t\t{\n\t\t\t\tdouble evaluate_x = bin_left + (bin_right - bin_left) / 999;\n\t\t\t\t\n\t\t\t\tif (evaluate_x < max_x)\n\t\t\t\t\ttotal_value += interaction_type->CalculateStrengthNoCallbacks(evaluate_x);\n\t\t\t}\n\t\t\t\n\t\t\tbins[bin_index] = total_value / 1000.0;\n\t\t}\n\t}\n\t\n\t// If we only have samples equal to zero, replicate the center column for symmetry\n\tif (!draw_positive && !draw_negative)\n\t{\n\t\tdouble zero_count = std::max(bins[half_bin_count - 1], bins[half_bin_count]);\t// whichever way it rounds...\n\t\t\n\t\tbins[half_bin_count - 1] = zero_count;\n\t\tbins[half_bin_count] = zero_count;\n\t}\n\t\n\t// Find the maximum-magnitude bin count\n\tdouble max_bin = 0;\n\t\n\tif (heights_negative)\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t\tmax_bin = std::min(max_bin, bins[bin_index]);\n\t}\n\telse\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t\tmax_bin = std::max(max_bin, bins[bin_index]);\n\t}\n\t\n\t// Plot the bins\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.0 brightness:0.0 alpha:1.0] set];\n\t\n\tif (heights_negative)\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tif (bins[bin_index] < 0)\n\t\t\t{\n\t\t\t\tdouble height = interiorRect.size.height * (bins[bin_index] / max_bin);\n\t\t\t\t\n\t\t\t\tNSRectFill(NSMakeRect(interiorRect.origin.x + bin_index * 0.5, interiorRect.origin.y + interiorRect.size.height - height, 0.5, height));\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int bin_index = 0; bin_index < bin_count; ++bin_index)\n\t\t{\n\t\t\tif (bins[bin_index] > 0)\n\t\t\t\tNSRectFill(NSMakeRect(interiorRect.origin.x + bin_index * 0.5, interiorRect.origin.y, 0.5, interiorRect.size.height * (bins[bin_index] / max_bin)));\n\t\t}\n\t}\n\t\n\tfree(bins);\n}\n\n- (BOOL)isOpaque\n{\n\treturn YES;\n}\n\n@end\n\n@implementation SLiMFunctionGraphToolTipWindow\n\n// makes a new marker with no label and no tip point, not shown\n+ (instancetype)new\n{\n\treturn [[[self class] alloc] initWithContentRect:NSMakeRect(0, 0, 77, 50) styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:YES];\n}\n\n- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag\n{\n\tif (self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag])\n\t{\n\t\t[self setFloatingPanel:YES];\n\t\t[self setBecomesKeyOnlyIfNeeded:YES];\n\t\t[self setHasShadow:NO];\n\t\t[self setOpaque:NO];\n\t\t[self setBackgroundColor:[NSColor clearColor]];\n\t\t\n\t\tSLiMFunctionGraphToolTipView *view = [[SLiMFunctionGraphToolTipView alloc] initWithFrame:contentRect];\n\t\t\n\t\t[self setContentView:view];\n\t\t[view release];\n\t\t\n\t\t_tipPoint = NSMakePoint(contentRect.origin.x, contentRect.origin.y);\n\t\t_mutType = nullptr;\n\t\t_interactionType = nullptr;\n\t}\n\t\n\treturn self;\n}\n\n- (void)setMutType:(MutationType *)mutType\n{\n\tif (_mutType != mutType)\n\t{\n\t\t_mutType = mutType;\n\t\t\n\t\t[[self contentView] setNeedsDisplay:YES];\n\t}\n}\n\n- (void)setInteractionType:(InteractionType *)interactionType\n{\n\tif (_interactionType != interactionType)\n\t{\n\t\t_interactionType = interactionType;\n\t\t\n\t\t[[self contentView] setNeedsDisplay:YES];\n\t}\n}\n\n- (void)setTipPoint:(NSPoint)tipPoint\n{\n\tif (!NSEqualPoints(_tipPoint, tipPoint))\n\t{\n\t\tNSPoint origin = [self frame].origin;\n\t\t\n\t\torigin.x += (tipPoint.x - _tipPoint.x);\n\t\torigin.y += (tipPoint.y - _tipPoint.y);\n\t\t\n\t\t_tipPoint = tipPoint;\n\t\t\n\t\t[self setFrameOrigin:origin];\n\t}\n}\n\n@end\n\n\n@implementation NSScreen (SLiMWindowFrames)\n\n+ (BOOL)visibleCandidateWindowFrame:(NSRect)candidateFrame\n{\n\tNSArray *screens = [NSScreen screens];\n\tNSUInteger nScreens = [screens count];\n\t\n\tfor (NSUInteger i = 0; i < nScreens; ++i)\n\t{\n\t\tNSScreen *screen = [screens objectAtIndex:i];\n\t\tNSRect screenFrame = [screen visibleFrame];\n\t\t\n\t\tif (NSContainsRect(screenFrame, candidateFrame))\n\t\t\treturn YES;\n\t}\n\t\n\treturn NO;\n}\n\n@end\n\n\n@implementation NSPopUpButton (SLiMSorting)\n\n- (void)slimSortMenuItemsByTag\n{\n\tNSMenu *menu = [self menu];\n\tint nItems = (int)[menu numberOfItems];\n\t\n\t// completely dumb bubble sort; not worth worrying about\n\tdo\n\t{\n\t\tBOOL foundSwap = NO;\n\t\t\n\t\tfor (int i = 0; i < nItems - 1; ++i)\n\t\t{\n\t\t\tNSMenuItem *firstItem = [menu itemAtIndex:i];\n\t\t\tNSMenuItem *secondItem = [menu itemAtIndex:i + 1];\n\t\t\tNSInteger firstTag = [firstItem tag];\n\t\t\tNSInteger secondTag = [secondItem tag];\n\t\t\t\n\t\t\tif (firstTag > secondTag)\n\t\t\t{\n\t\t\t\t[secondItem retain];\n\t\t\t\t[menu removeItemAtIndex:i + 1];\n\t\t\t\t[menu insertItem:secondItem atIndex:i];\n\t\t\t\t[secondItem release];\n\t\t\t\t\n\t\t\t\tfoundSwap = YES;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!foundSwap)\n\t\t\tbreak;\n\t}\n\twhile (YES);\n}\n\n@end\n\n@implementation NSButton (SLiMTinting)\n\n- (void)slimSetTintColor:(NSColor *)tintColor\n{\n\t[self setContentFilters:[NSArray array]];\n\t\n\tif (tintColor)\n\t{\n\t\tif (!self.layer)\n\t\t\t[self setWantsLayer:YES];\n\t\t\n\t\tCIFilter *tintFilter = [CIFilter filterWithName:@\"CIColorMatrix\"];\n\t\t\n\t\tif (tintFilter)\n\t\t{\n\t\t\tCGFloat redComponent = [tintColor redComponent];\n\t\t\tCGFloat greenComponent = [tintColor greenComponent];\n\t\t\tCGFloat blueComponent = [tintColor blueComponent];\n\t\t\t\n\t\t\t//NSLog(@\"tintColor: redComponent == %f, greenComponent == %f, blueComponent == %f\", redComponent, greenComponent, blueComponent);\n\t\t\t\n\t\t\t// The goal is to use CIColorMatrix to multiply color components so that white turns into tintColor; these vectors do that\n\t\t\tCIVector *rVector = [CIVector vectorWithX:redComponent Y:0.0 Z:0.0 W:0.0];\n\t\t\tCIVector *gVector = [CIVector vectorWithX:0.0 Y:greenComponent Z:0.0 W:0.0];\n\t\t\tCIVector *bVector = [CIVector vectorWithX:0.0 Y:0.0 Z:blueComponent W:0.0];\n\t\t\t\n\t\t\t[tintFilter setDefaults];\n\t\t\t[tintFilter setValue:rVector forKey:@\"inputRVector\"];\n\t\t\t[tintFilter setValue:gVector forKey:@\"inputGVector\"];\n\t\t\t[tintFilter setValue:bVector forKey:@\"inputBVector\"];\n\t\t\t\n\t\t\t[self setContentFilters:@[tintFilter]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSLog(@\"could not create [CIFilter filterWithName:@\\\"CIColorMatrix\\\"]\");\n\t\t}\n\t}\n\telse\n\t{\n\t\t// BCH added 21 May 2017: revert to non-layer-backed when tinting is removed.  This restores the previous behavior\n\t\t// of the view, which is important for making the play and profile buttons draw correctly where they overlap.  The\n\t\t// doc does not explicitly say that setWantsLayer:NO removes the layer, but in practice it does seem to.\n\t\tif (self.layer)\n\t\t\t[self setWantsLayer:NO];\n\t}\n\t\n\t[self setNeedsDisplay];\n\t[self.layer setNeedsDisplay];\n}\n\n@end\n\n// This is a vestigial tail left over from the old ScriptMod class of SLiMguiLegacy; I ripped out that class completely,\n// but a few other places in the code used its validation logic for their own purposes, so I've moved that to CocoaExtra.\n\n@implementation ScriptMod\n\n+ (NSColor *)validationErrorColor\n{\n\tstatic NSColor *color = nil;\n\t\n\tif (!color)\n\t\tcolor = [[NSColor colorWithCalibratedHue:0.0 saturation:0.15 brightness:1.0 alpha:1.0] retain];\n\t\n\treturn color;\n}\n\n+ (NSRegularExpression *)regexForInt\n{\n\tstatic NSRegularExpression *regex = nil;\n\t\n\tif (!regex)\n\t\tregex = [[NSRegularExpression alloc] initWithPattern:@\"^[0-9]+$\" options:0 error:NULL];\n\t\n\treturn regex;\n}\n\n+ (NSRegularExpression *)regexForFloat\n{\n\tstatic NSRegularExpression *regex = nil;\n\t\n\tif (!regex)\n\t\tregex = [[NSRegularExpression alloc] initWithPattern:@\"^\\\\-?[0-9]+(\\\\.[0-9]*)?$\" options:0 error:NULL];\n\t\n\treturn regex;\n}\n\n+ (BOOL)validIntValueInTextField:(NSTextField *)textfield withMin:(int64_t)minValue max:(int64_t)maxValue\n{\n\tNSString *stringValue = [textfield stringValue];\n\tint64_t intValue = [[textfield stringValue] longLongValue];\n\t\n\tif ([stringValue length] == 0)\n\t\treturn NO;\n\t\n\tif ([[ScriptMod regexForInt] numberOfMatchesInString:stringValue options:0 range:NSMakeRange(0, [stringValue length])] == 0)\n\t\treturn NO;\n\t\n\tif (intValue < minValue)\n\t\treturn NO;\n\t\n\tif (intValue > maxValue)\n\t\treturn NO;\n\t\n\treturn YES;\n}\n\n+ (BOOL)validFloatValueInTextField:(NSTextField *)textfield withMin:(double)minValue max:(double)maxValue\n{\n\treturn [self validFloatValueInTextField:textfield withMin:minValue max:maxValue excludingMin:NO excludingMax:NO];\n}\n\n+ (BOOL)validFloatValueInTextField:(NSTextField *)textfield withMin:(double)minValue max:(double)maxValue excludingMin:(BOOL)excludeMin excludingMax:(BOOL)excludeMax\n{\n\tNSString *stringValue = [textfield stringValue];\n\tdouble doubleValue = [textfield doubleValue];\n\t\n\tif ([stringValue length] == 0)\n\t\treturn NO;\n\t\n\tif ([[ScriptMod regexForFloat] numberOfMatchesInString:stringValue options:0 range:NSMakeRange(0, [stringValue length])] == 0)\n\t\treturn NO;\n\t\n\tif (doubleValue < minValue)\n\t\treturn NO;\n\t\n\tif (excludeMin && (doubleValue == minValue))\n\t\treturn NO;\n\t\n\tif (doubleValue > maxValue)\n\t\treturn NO;\n\t\n\tif (excludeMax && (doubleValue == maxValue))\n\t\treturn NO;\n\t\n\treturn YES;\n}\n\n+ (NSColor *)backgroundColorForValidationState:(BOOL)valid\n{\n\treturn (valid ? [NSColor whiteColor] : [ScriptMod validationErrorColor]);\n}\n\n@end\n\n@implementation SLiMAutoselectTextField\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\t[[self currentEditor] selectAll:nil];\n}\n\n@end\n\n@implementation SLiMLayoutRoundoffView\n\n- (void)layout\n{\n\t// We want to manually layout our (single) subview, to correct for subpixel positioning that screws up our drawing.\n\t// The documentation for -layout is abysmal, but it turns out what you want to do is remove all constraints from the\n\t// view that you want to manually lay out, so that the autolayout code is not fighting with you, and *then* use\n\t// -layout in the superview of that view to manually set the frame of the subview.  We remove the relevant constraints\n\t// in -windowDidLoad in SLiMWindowController.  Here we just check for a half-pixel position in our own bounds, and if\n\t// present, tweak our subview's frame to remove it.  Seems to work; took hours upon hours to figure out.  :-<\n\tNSArray *subviews = [self subviews];\n\t\n\tif ([subviews count] == 1)\n\t{\n\t\tNSView *subview = [subviews objectAtIndex:0];\n\t\tNSRect selfBounds = [self frame];\n\t\tNSRect frame = selfBounds;\n\t\t\n\t\tif (selfBounds.size.height != round(selfBounds.size.height))\n\t\t{\n\t\t\tframe.origin.y += 0.5;\n\t\t\tframe.size.height -= 0.5;\n\t\t}\n\t\t\n\t\t//NSLog(@\"selfBounds: %@\", NSStringFromRect(selfBounds));\n\t\t//NSLog(@\"frame: %@\", NSStringFromRect(frame));\n\t\t\n\t\t[subview setFrame:frame];\n\t\t[subview setNeedsLayout:YES];\n\t}\n\t\n\t[super layout];\n}\n\n@end\n\n\n// Work around Apple's bug that they never fix that causes console logs on startup\n// Thanks to TyngJJ on https://forums.developer.apple.com/thread/49052 for this workaround\n// FIXME check whether they have fixed it yet, from time to time...\n\n@interface NSWindow (FirstResponding)  \n-(void)_setFirstResponder:(NSResponder *)responder;  \n@end  \n@interface NSDrawerWindow : NSWindow  \n@end  \n@implementation NSDrawerWindow (FirstResponding)  \n-(void)_setFirstResponder:(NSResponder *)responder {  \n\tif (![responder isKindOfClass:NSView.class] || [(NSView *)responder window] == self)  \n\t\t[super _setFirstResponder:responder];  \n}  \n@end  \n\n@implementation NSString (SLiMBytes)\n+ (NSString *)stringForByteCount:(int64_t)bytes\n{\n\tif (bytes > 512LL * 1024L * 1024L * 1024L)\n\t\treturn [NSString stringWithFormat:@\"%0.2f TB\", bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)];\n\telse if (bytes > 512L * 1024L * 1024L)\n\t\treturn [NSString stringWithFormat:@\"%0.2f GB\", bytes / (1024.0 * 1024.0 * 1024.0)];\n\telse if (bytes > 512L * 1024L)\n\t\treturn [NSString stringWithFormat:@\"%0.2f MB\", bytes / (1024.0 * 1024.0)];\n\telse if (bytes > 512L)\n\t\treturn [NSString stringWithFormat:@\"%0.2f KB\", bytes / 1024.0];\n\telse\n\t\treturn [NSString stringWithFormat:@\"%lld bytes\", (long long int)bytes];\n}\n@end\n\n@implementation NSColor (SLiMHeatColors)\n#define SLIM_YELLOW_FRACTION 0.10\n#define SLIM_SATURATION 0.75\n\n+ (NSColor *)slimColorForFraction:(double)fraction\n{\n\tif (fraction < SLIM_YELLOW_FRACTION)\n\t{\n\t\t// small fractions fall on a ramp from white (0.0) to yellow (SLIM_YELLOW_FRACTION)\n\t\treturn [NSColor colorWithCalibratedHue:(1.0 / 6.0) saturation:(fraction / SLIM_YELLOW_FRACTION) * SLIM_SATURATION brightness:1.0 alpha:1.0];\n\t}\n\telse\n\t{\n\t\t// larger fractions ramp from yellow (SLIM_YELLOW_FRACTION) to red (1.0)\n\t\treturn [NSColor colorWithCalibratedHue:(1.0 / 6.0) * (1.0 - (fraction - SLIM_YELLOW_FRACTION) / (1.0 - SLIM_YELLOW_FRACTION)) saturation:SLIM_SATURATION brightness:1.0 alpha:1.0];\n\t}\n}\n@end\n\n@implementation NSAttributedString (SLiMBytes)\n+ (NSAttributedString *)attributedStringForByteCount:(int64_t)bytes total:(double)total attributes:(NSDictionary *)attrs\n{\n\tNSString *byteString = [NSString stringForByteCount:bytes];\n\tdouble fraction = bytes / total;\n\tNSColor *fractionColor = [NSColor slimColorForFraction:fraction];\n\tNSMutableDictionary *colorAttrs = [NSMutableDictionary dictionaryWithDictionary:attrs];\n\t\n\t[colorAttrs setObject:fractionColor forKey:NSBackgroundColorAttributeName];\n\t\n\treturn [[[NSAttributedString alloc] initWithString:byteString attributes:colorAttrs] autorelease];\n}\n@end\n\n// Create a path for a temporary file; see https://stackoverflow.com/a/8307013/2752221\n// Code is originally from https://developer.apple.com/library/archive/samplecode/SimpleURLConnections/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009245\n@implementation NSString (SLiMTempFiles)\n+ (NSString *)slimPathForTemporaryFileWithPrefix:(NSString *)prefix\n{\n\tNSString *  result;\n\tCFUUIDRef   uuid;\n\tCFStringRef uuidStr;\n\t\n\tuuid = CFUUIDCreate(NULL);\n\tassert(uuid != NULL);\n\t\n\tuuidStr = CFUUIDCreateString(NULL, uuid);\n\tassert(uuidStr != NULL);\n\t\n\tresult = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@\"%@-%@\", prefix, uuidStr]];\n\tassert(result != nil);\n\t\n\tCFRelease(uuidStr);\n\tCFRelease(uuid);\n\t\n\treturn result;\n}\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/FindRecipeController.h",
    "content": "//\n//  FindRecipeController.h\n//  SLiM\n//\n//  Created by Ben Haller on 10/11/18.\n//  Copyright (c) 2018-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#import \"EidosTextView.h\"\n\n\n@interface FindRecipeController : NSWindowController <NSTableViewDataSource, NSTableViewDelegate, NSTextFieldDelegate>\n{\n\tNSArray *recipeFilenames;\n\tNSArray *recipeContents;\n\t\n\tNSArray *matchRecipeFilenames;\n\t\n\tIBOutlet NSTextField *keyword1TextField;\n\tIBOutlet NSTextField *keyword2TextField;\n\tIBOutlet NSTextField *keyword3TextField;\n\tIBOutlet NSButton *buttonOK;\n\tIBOutlet NSTableView *matchTableView;\n\tIBOutlet EidosTextView *scriptPreview;\n}\n\n+ (void)runFindRecipesPanel;\n\n- (IBAction)okButtonPressed:(id)sender;\n- (IBAction)cancelButtonPressed:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/FindRecipeController.mm",
    "content": "//\n//  FindRecipeController.m\n//  SLiMgui\n//\n//  Created by Ben Haller on 10/11/18.\n//  Copyright (c) 2018-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"FindRecipeController.h\"\n#import \"SLiMDocumentController.h\"\n#import \"AppDelegate.h\"\n\n\n@implementation FindRecipeController\n\n+ (void)runFindRecipesPanel\n{\n\tFindRecipeController *controller = [[FindRecipeController alloc] initWithWindowNibName:@\"FindRecipePanel\"];\n\t\n\t[[NSApplication sharedApplication] runModalForWindow:[controller window]];\n\t\n\t[[controller window] close];\n\t[controller release];\n}\n\n- (void)loadRecipes\n{\n\tNSURL *urlForRecipesFolder = [[NSBundle mainBundle] URLForResource:@\"Recipes\" withExtension:@\"\"];\n\tNSFileManager *fm = [NSFileManager defaultManager];\n\tNSDirectoryEnumerator *dirEnum = [fm enumeratorAtURL:urlForRecipesFolder includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey] options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants) errorHandler:nil];\n\tNSMutableArray *filenames = [NSMutableArray array];\n\t\n\tfor (NSURL *fileURL in dirEnum)\n\t{\n\t\tNSNumber *isDirectory = nil;\n\t\t\n\t\t[fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];\n\t\t\n\t\tif (![isDirectory boolValue])\n\t\t{\n\t\t\tNSString *name = nil;\n\t\t\t\n\t\t\t[fileURL getResourceValue:&name forKey:NSURLNameKey error:nil];\n\t\t\t\n\t\t\tif ([name hasPrefix:@\"Recipe \"])\n\t\t\t\t[filenames addObject:name];\n\t\t}\n\t}\n\t\n\t[filenames sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {\n\t\treturn [(NSString *)obj1 compare:(NSString *)obj2 options:NSNumericSearch];\n\t}];\n\t\n\trecipeFilenames = [filenames retain];\n\tmatchRecipeFilenames = [recipeFilenames retain];\n\t\n\t// Look up recipe file contents and cache them\n\tNSMutableArray *contents = [NSMutableArray array];\n\t\n\tfor (NSString *filename : recipeFilenames)\n\t{\n\t\tNSString *filePath = [[urlForRecipesFolder path] stringByAppendingPathComponent:filename];\n\t\tNSString *fileContents = [NSString stringWithContentsOfFile:filePath usedEncoding:nil error:nil];\n\t\t\n\t\t[contents addObject:fileContents];\n\t}\n\t\n\trecipeContents = [contents retain];\n}\n\n- (NSString *)displayStringForRecipeFilename:(NSString *)name\n{\n\tif ([name hasSuffix:@\".txt\"])\n\t{\n\t\t// Remove the .txt extension for SLiM models\n\t\tname = [name substringWithRange:NSMakeRange(7, [name length] - 11)];\n\t}\n\telse if ([name hasSuffix:@\".py\"])\n\t{\n\t\t// Leave the .py extension for Python models\n\t\tname = [name substringWithRange:NSMakeRange(7, [name length] - 7)];\n\t\tname = [name stringByAppendingString:@\" 🐍\"];\n\t}\n\t\n\treturn name;\n}\n\n- (BOOL)recipeIndex:(int)recipeIndex matchesKeyword:(NSString *)keyword\n{\n\t// an empty keyword matches all recipes\n\tif (!keyword || ([keyword length] == 0))\n\t\treturn YES;\n\t\n\t// look for a match in the filename\n\tNSString *filename = [recipeFilenames objectAtIndex:recipeIndex];\n\t\n\tif ([filename rangeOfString:keyword options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch].location != NSNotFound)\n\t\treturn YES;\n\t\n\t// look for a match in the file contents\n\tNSString *contents = [recipeContents objectAtIndex:recipeIndex];\n\t\n\tif ([contents rangeOfString:keyword options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch].location != NSNotFound)\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (void)constructMatchList\n{\n\tNSMutableArray *matches = [NSMutableArray array];\n\tNSString *keyword1 = [keyword1TextField stringValue];\n\tNSString *keyword2 = [keyword2TextField stringValue];\n\tNSString *keyword3 = [keyword3TextField stringValue];\n\t\n\tfor (int i = 0; i < (int)[recipeFilenames count]; ++i)\n\t{\n\t\tif ([self recipeIndex:i matchesKeyword:keyword1] && [self recipeIndex:i matchesKeyword:keyword2] && [self recipeIndex:i matchesKeyword:keyword3])\n\t\t\t[matches addObject:[recipeFilenames objectAtIndex:i]];\n\t}\n\t\n\t[matchRecipeFilenames release];\n\tmatchRecipeFilenames = [matches retain];\n}\n\n- (void)dealloc\n{\n\t[recipeFilenames release];\n\trecipeFilenames = nil;\n\t\n\t[recipeContents release];\n\trecipeContents = nil;\n\t\n\t[matchRecipeFilenames release];\n\tmatchRecipeFilenames = nil;\n\t\n\t[super dealloc];\n}\n\n- (void)windowDidLoad\n{\n    [super windowDidLoad];\n    \n\t[self loadRecipes];\n\t[matchTableView reloadData];\n\t[matchTableView setNeedsDisplay];\n\t\n\t[self validateOK];\n\t\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\t[scriptPreview setSyntaxColoring:[defaults boolForKey:defaultsSyntaxHighlightScriptKey] ? kEidosSyntaxColoringEidos : kEidosSyntaxColoringNone];\n\t[scriptPreview setDisplayFontSize:10];\n}\n\n- (void)validateOK\n{\n\t[buttonOK setEnabled:([matchTableView numberOfSelectedRows] > 0)];\n}\n\n- (void)updatePreview\n{\n\tNSInteger selectedRowIndex = [matchTableView selectedRow];\n\t\n\tif (selectedRowIndex == -1)\n\t{\n\t\t[scriptPreview setString:@\"\"];\n\t}\n\telse\n\t{\n\t\tNSString *filename = [matchRecipeFilenames objectAtIndex:selectedRowIndex];\n\t\tNSBundle *bundle = [NSBundle mainBundle];\n\t\tNSURL *urlForRecipe = [bundle URLForResource:[filename stringByDeletingPathExtension] withExtension:[filename pathExtension] subdirectory:@\"Recipes\"];\n\t\tNSString *scriptString = [NSString stringWithContentsOfURL:urlForRecipe usedEncoding:NULL error:NULL];\n\t\t\n\t\t[scriptPreview setString:scriptString];\n\t\t[scriptPreview recolorAfterChanges];\n\t\t[self highlightPreview];\n\t}\n}\n\n- (void)highlightPreview\n{\n\t// Highlight matches in the selected recipe\n\t[scriptPreview clearHighlightMatches];\n\t\n\tNSString *keyword1 = [keyword1TextField stringValue];\n\tNSString *keyword2 = [keyword2TextField stringValue];\n\tNSString *keyword3 = [keyword3TextField stringValue];\n\t\n\tif ([keyword1 length])\n\t\t[scriptPreview highlightMatchesForString:keyword1];\n\tif ([keyword2 length])\n\t\t[scriptPreview highlightMatchesForString:keyword2];\n\tif ([keyword3 length])\n\t\t[scriptPreview highlightMatchesForString:keyword3];\n}\n\n- (void)keywordChanged:(id)sender\n{\n\t// Remember the title of the currently selected recipes\n\tNSInteger selectedRowIndex = [matchTableView selectedRow];\n\tNSString *selectedRowText = nil;\n\t\n\tif (selectedRowIndex != -1)\n\t\tselectedRowText = [[matchRecipeFilenames objectAtIndex:selectedRowIndex] retain];\n\t\n\t// Filter the recipe list by the keywords entered\n\t[self constructMatchList];\n\t\n\t// Reload the tableview with recipes that match the new keywords\n\t[matchTableView reloadData];\n\t\n\t// Restore the selection to the extent possible\n\tif (selectedRowText)\n\t{\n\t\tBOOL foundSelection = NO;\n\t\t\n\t\tfor (NSInteger i = 0; i < [matchTableView numberOfRows]; ++i)\n\t\t{\n\t\t\tNSString *rowText = [matchRecipeFilenames objectAtIndex:i];\n\t\t\t\n\t\t\tif ([rowText isEqualToString:selectedRowText])\n\t\t\t{\n\t\t\t\t[matchTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:i] byExtendingSelection:NO];\n\t\t\t\tfoundSelection = YES;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (foundSelection)\n\t\t{\n\t\t\t[self highlightPreview];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// tableViewSelectionDidChange: is not called when the selection is lost by reloadData\n\t\t\t[self validateOK];\n\t\t\t[self updatePreview];\n\t\t}\n\t\t\n\t\t[selectedRowText release];\n\t}\n}\n\n- (IBAction)okButtonPressed:(id)sender\n{\n\t// Open the selected recipe(s)\n\tNSInteger selectedRowIndex = [matchTableView selectedRow];\n\t\n\tif (selectedRowIndex != -1)\n\t\t[[NSDocumentController sharedDocumentController] openRecipeWithFilename:[matchRecipeFilenames objectAtIndex:selectedRowIndex]];\n\t\n\t// Then terminate the modal run loop\n\t[[NSApplication sharedApplication] stopModal];\n}\n\n- (IBAction)cancelButtonPressed:(id)sender\n{\n\t// Terminate the modal run loop\n\t[[NSApplication sharedApplication] abortModal];\n}\n\n// NSTableViewDataSource\n#pragma mark -\n#pragma mark NSTableViewDataSource\n\n- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView\n{\n\treturn [matchRecipeFilenames count];\n}\n\n- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tif ((row < 0) || (row >= (NSInteger)[matchRecipeFilenames count]))\n\t\treturn nil;\n\t\n\treturn [self displayStringForRecipeFilename:[matchRecipeFilenames objectAtIndex:row]];\n}\n\n- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\t// This is mostly Apple boilerplate code; I couldn't get a cell-based table to work, so I gave up and made it view-based\n\t\n\t// Get an existing cell with the MyView identifier if it exists\n\tNSTextField *result = [tableView makeViewWithIdentifier:@\"MyView\" owner:self];\n\t\n\t// There is no existing cell to reuse so create a new one\n\tif (result == nil) {\n\t\t// Create the new NSTextField with a frame of the {0,0} with the width of the table.\n\t\t// Note that the height of the frame is not really relevant, because the row height will modify the height.\n\t\tresult = [[NSTextField alloc] initWithFrame:NSZeroRect];\n\t\t\n\t\t// The identifier of the NSTextField instance is set to MyView.\n\t\t// This allows the cell to be reused.\n\t\tresult.identifier = @\"MyView\";\n\t\t\n\t\t// BCH: configure the textfield view to look the way we want; could get it from the nib instead but this is easy\n\t\t[result setBordered:NO];\n\t\t[result setDrawsBackground:NO];\n\t\t[result setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];\n\t\t\n\t\t// the truncation of lines with ellipses works, but expansion tooltips only show when the row is selected, grr\n\t\t[[result cell] setLineBreakMode:NSLineBreakByTruncatingTail];\n\t\t[[result cell] setTruncatesLastVisibleLine:YES];\n\t\t[result setAllowsExpansionToolTips:YES];\n\t\t\n\t\t// make the textfield uneditable\n\t\t[result setEditable:NO];\n\t}\n\t\n\treturn result;\n}\n\n// NSTableViewDelegate\n#pragma mark -\n#pragma mark NSTableViewDelegate\n\n- (void)tableViewSelectionDidChange:(NSNotification *)notification\n{\n\t[self validateOK];\n\t[self updatePreview];\n}\n\n// NSTextFieldDelegate\n#pragma mark -\n#pragma mark NSTextFieldDelegate\n\n- (void)controlTextDidChange:(NSNotification *)obj\n{\n\t[self keywordChanged:nil];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView.h",
    "content": "//\n//  GraphView.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include \"slim_globals.h\"\n\n\n@class SLiMWindowController;\n\n\n// A quick and dirty macro to enable rounding of coordinates to the nearest pixel only when we are not generating PDF\n// FIXME this ought to be revisited in the light of Retina displays, printing, etc.\n#define SLIM_SCREEN_ROUND(x)\t\t(generatingPDF ? (x) : round(x))\n\n\n@interface GraphView : NSView\n{\n\tstd::string focalSpeciesName;\t\t\t\t\t\t\t// we keep the name of our focal species, since a pointer would be unsafe\n\tstd::string focalSpeciesAvatar;\t\t\t\t\t\t\t// cached so we can display it even when the simulation is invalid\n\t\n\t// set to YES during a copy: operation, to allow customization\n\tBOOL generatingPDF;\n\t\n\t// caching for drawing speed is up to subclasses, if they want to do it, but we provide minimal support in GraphView to make it work smoothly\n\t// this flag is to prevent recursion in the drawing code, and to disable drawing of things that don't belong in a cache, such as the legend\n\tBOOL cachingNow;\n\t\n\t// GraphAxisRescaleSheet outlets\n\tIBOutlet NSWindow *rescaleSheet;\n\tIBOutlet NSTextField *rescaleSheetMinTextfield;\n\tIBOutlet NSTextField *rescaleSheetMaxTextfield;\n\tIBOutlet NSTextField *rescaleSheetMajorIntervalTextfield;\n\tIBOutlet NSTextField *rescaleSheetMinorModulusTextfield;\n\tIBOutlet NSTextField *rescaleSheetTickPrecisionTextfield;\n\t\n\t// GraphBarRescaleSheet outlets\n\tIBOutlet NSWindow *rescaleBarsSheet;\n\tIBOutlet NSTextField *rescaleBarsSheetCountTextfield;\n}\n\n@property (nonatomic, assign) SLiMWindowController *slimWindowController;\n\n@property (nonatomic) BOOL showXAxis;\n@property (nonatomic) BOOL allowXAxisUserRescale;\n@property (nonatomic) BOOL xAxisIsUserRescaled;\n@property (nonatomic) BOOL showXAxisTicks;\n@property (nonatomic) double xAxisMin, xAxisMax;\n@property (nonatomic) double xAxisMajorTickInterval, xAxisMinorTickInterval;\n@property (nonatomic) int xAxisMajorTickModulus, xAxisTickValuePrecision;\n@property (nonatomic, retain) NSAttributedString *xAxisLabel;\n\n@property (nonatomic) BOOL showYAxis;\n@property (nonatomic) BOOL allowYAxisUserRescale;\n@property (nonatomic) BOOL yAxisIsUserRescaled;\n@property (nonatomic) BOOL showYAxisTicks;\n@property (nonatomic) double yAxisMin, yAxisMax;\n@property (nonatomic) double yAxisMajorTickInterval, yAxisMinorTickInterval;\n@property (nonatomic) int yAxisMajorTickModulus, yAxisTickValuePrecision;\n@property (nonatomic, retain) NSAttributedString *yAxisLabel;\n\n@property (nonatomic) BOOL legendVisible;\n@property (nonatomic) BOOL showHorizontalGridLines;\n@property (nonatomic) BOOL showVerticalGridLines;\n@property (nonatomic) BOOL showFullBox;\n\n@property (nonatomic) BOOL tweakXAxisTickLabelAlignment;\n\n+ (NSString *)labelFontName;\n+ (NSDictionary *)attributesForAxisLabels;\n+ (NSDictionary *)attributesForTickLabels;\n+ (NSDictionary *)attributesForLegendLabels;\n+ (NSColor *)gridLineColor;\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller;\t\t// designated initializer\n\n- (Species *)focalDisplaySpecies;\n- (void)updateSpeciesBadge;\n\n- (void)cleanup;\n\n- (void)setXAxisLabelString:(NSString *)labelString;\n- (void)setYAxisLabelString:(NSString *)labelString;\n\n- (NSRect)interiorRectForBounds:(NSRect)bounds;\n\n- (double)plotToDeviceX:(double)plotx withInteriorRect:(NSRect)interiorRect;\n- (double)plotToDeviceY:(double)ploty withInteriorRect:(NSRect)interiorRect;\n- (double)roundPlotToDeviceX:(double)plotx withInteriorRect:(NSRect)interiorRect;\t// rounded off to the nearest midpixel\n- (double)roundPlotToDeviceY:(double)ploty withInteriorRect:(NSRect)interiorRect;\t// rounded off to the nearest midpixel\n\n- (void)willDrawWithInteriorRect:(NSRect)interiorRect andController:(SLiMWindowController *)controller;\t\t// called prior to drawing, to allow dynamic axis rescaling and other adjustments\n\n- (void)drawXAxisTicksWithInteriorRect:(NSRect)interiorRect;\n- (void)drawXAxisWithInteriorRect:(NSRect)interiorRect;\n\n- (void)drawYAxisTicksWithInteriorRect:(NSRect)interiorRect;\n- (void)drawYAxisWithInteriorRect:(NSRect)interiorRect;\n\n- (void)drawVerticalGridLinesWithInteriorRect:(NSRect)interiorRect;\n- (void)drawHorizontalGridLinesWithInteriorRect:(NSRect)interiorRect;\n\n- (void)drawMessage:(NSString *)messageString inRect:(NSRect)rect;\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller;\n\n- (NSArray *)legendKey;\t\t\t\t\t\t\t// subclasses can provide an NSArray of key entries, each an NSArray of an NSString and an NSColor\n- (NSSize)legendSize;\t\t\t\t\t\t\t// unless overridden, this calls -legendKey and follows its intructions\n- (void)drawLegendInRect:(NSRect)legendRect;\t// unless overridden, this calls -legendKey and follows its intructions\n\n- (IBAction)rescaleSheetOK:(id)sender;\n- (IBAction)rescaleSheetCancel:(id)sender;\n- (IBAction)userRescaleXAxis:(id)sender;\n- (IBAction)userRescaleYAxis:(id)sender;\n\n- (IBAction)copy:(id)sender;\n- (IBAction)saveGraph:(id)sender;\n- (IBAction)copyData:(id)sender;\n- (IBAction)saveData:(id)sender;\n- (NSString *)dateline;\n\n- (NSMenu *)menuForEvent:(NSEvent *)theEvent;\n- (void)subclassAddItemsToMenu:(NSMenu *)menu forEvent:(NSEvent *)theEvent;\t// subclasses normally add their menu items here so they appear above the copy graph/data menu items\n\n- (void)invalidateDrawingCache;\t\t\t// GraphView does not keep a drawing cache, but it supports having one; this gets called in situations when such a cache would be invalidated\n- (void)graphWindowResized;\t\t\t\t// called by SLiMWindowController to let the GraphView do whatever recalculation, cache invalidation, etc. it might want to do\n- (void)controllerRecycled;\t\t\t\t// called by SLiMWindowController when the simulation is recycled, to let the GraphView do whatever re-initialization is needed\n- (void)controllerSelectionChanged;\t\t// called by SLiMWindowController when the selection changes, to let the GraphView respond\n- (void)controllerTickFinished;\t\t\t// called by SLiMWindowController when a simulation tick ends, to allow per-tick data gathering; redrawing should not be done here\n- (void)updateAfterTick;\t\t\t\t// by default, calls setNeedsDisplay:YES; can also perform other updating work\n\n// Additional properties that conceptually belong to PrefabAdditions below\n@property (nonatomic) int histogramBinCount;\t\t// provided for barplots\n@property (nonatomic) BOOL allowXAxisBinRescale;\t// if YES, the GraphView will provide a context menu item and run a panel to set the bar count\n\n@end\n\n@interface GraphView (PrefabAdditions)\n\n// A prefab method to set up a good x axis to span the tick range, whatever it might be\n- (void)setXAxisRangeFromTick;\n\n// a prefab legend that shows all of the mutation types, with color swatches and labels\n- (NSArray *)mutationTypeLegendKey;\n\n// a prefab method to draw simple barplots\n- (void)drawBarplotInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller buffer:(double *)buffer binCount:(int)binCount firstBinValue:(double)firstBinValue binWidth:(double)binWidth;\n\n// a prefab method to draw grouped barplots\n- (void)drawGroupedBarplotInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller buffer:(double *)buffer subBinCount:(int)subBinCount mainBinCount:(int)mainBinCount firstBinValue:(double)firstBinValue mainBinWidth:(double)mainBinWidth;\n\n@end\n\n@interface GraphView (OptionalSubclassMethods)\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView.mm",
    "content": "//\n//  GraphView.m\n//  SLiM\n//\n//  Created by Ben Haller on 2/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView.h\"\n#import \"SLiMWindowController.h\"\n\n#import \"species.h\"\n#include \"community.h\"\n\n\n\n@implementation GraphView\n\n+ (NSString *)labelFontName\n{\n\treturn @\"Times New Roman\";\n}\n\n+ (NSDictionary *)attributesForAxisLabels\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:[self labelFontName] size:14]} retain];\n\t\n\treturn attrs;\n}\n\n+ (NSDictionary *)attributesForAvatars\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:[self labelFontName] size:12]} retain];\n\t\n\treturn attrs;\n}\n\n+ (NSDictionary *)attributesForTickLabels\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:[self labelFontName] size:10]} retain];\n\t\n\treturn attrs;\n}\n\n+ (NSDictionary *)attributesForLegendLabels\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:[self labelFontName] size:10]} retain];\n\t\n\treturn attrs;\n}\n\n+ (NSColor *)gridLineColor\n{\n\tstatic NSColor *gridColor = nil;\n\t\n\tif (!gridColor)\n\t\tgridColor = [[NSColor colorWithCalibratedWhite:0.85 alpha:1.0] retain];\n\t\n\treturn gridColor;\n}\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect])\n\t{\n\t\t[self setSlimWindowController:controller];\n\t\tfocalSpeciesName = [controller focalDisplaySpecies]->name_;\n\t\t\n\t\t_showXAxis = TRUE;\n\t\t_allowXAxisUserRescale = TRUE;\n\t\t_showXAxisTicks = TRUE;\n\t\t\n\t\t_showYAxis = TRUE;\n\t\t_allowYAxisUserRescale = TRUE;\n\t\t_showYAxisTicks = TRUE;\n\t\t\n\t\t_xAxisMin = 0.0;\n\t\t_xAxisMax = 1.0;\n\t\t_xAxisMajorTickInterval = 0.5;\n\t\t_xAxisMinorTickInterval = 0.25;\n\t\t_xAxisMajorTickModulus = 2;\n\t\t_xAxisTickValuePrecision = 1;\n\n\t\t_yAxisMin = 0.0;\n\t\t_yAxisMax = 1.0;\n\t\t_yAxisMajorTickInterval = 0.5;\n\t\t_yAxisMinorTickInterval = 0.25;\n\t\t_yAxisMajorTickModulus = 2;\n\t\t_yAxisTickValuePrecision = 1;\n\t\t\n\t\t_xAxisLabel = [[NSAttributedString alloc] initWithString:@\"This is the x-axis, yo\" attributes:[[self class] attributesForAxisLabels]];\n\t\t_yAxisLabel = [[NSAttributedString alloc] initWithString:@\"This is the y-axis, yo\" attributes:[[self class] attributesForAxisLabels]];\n\t\t\n\t\t_legendVisible = YES;\n\t\t_showHorizontalGridLines = NO;\n\t\t_showVerticalGridLines = NO;\n\t\t_showFullBox = NO;\n\t}\n\t\n\treturn self;\n}\n\n- (Species *)focalDisplaySpecies\n{\n\t// We look up our focal species object by name every time, since keeping a pointer to it would be unsafe\n\t// Before initialize() is done species have not been created, so we return nullptr in that case\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (controller && controller->community && (controller->community->Tick() >= 1))\n\t\treturn controller->community->SpeciesWithName(focalSpeciesName);\n\t\n\treturn nullptr;\n}\n\n- (void)updateSpeciesBadge\n{\n\tSpecies *graphSpecies = [self focalDisplaySpecies];\n\t\n\t// Cache our graphSpecies avatar whenever we're in a valid state, because it could change,\n\t// and because we want to be able to display it even when the sim is in an invalid state\n\tif (graphSpecies)\n\t{\n\t\tif (graphSpecies->community_.all_species_.size() > 1)\n\t\t\tfocalSpeciesAvatar = graphSpecies->avatar_;\n\t\telse\n\t\t\tfocalSpeciesAvatar = \"\";\n\t}\n}\n\n- (void)cleanup\n{\n\t//NSLog(@\"[GraphView cleanup]\");\n\t\n\t[self invalidateDrawingCache];\n\t\n\t[_xAxisLabel release];\n\t_xAxisLabel = nil;\n\t\n\t[_yAxisLabel release];\n\t_yAxisLabel = nil;\n\t\n\t_slimWindowController = nil;\n}\n\n- (void)dealloc\n{\n\t[self cleanup];\n\t\n\t//NSLog(@\"[GraphView dealloc]\");\n\t[super dealloc];\n}\n\n- (void)setXAxisLabelString:(NSString *)labelString\n{\n\t[self setXAxisLabel:[[[NSAttributedString alloc] initWithString:labelString attributes:[[self class] attributesForAxisLabels]] autorelease]];\n}\n\n- (void)setYAxisLabelString:(NSString *)labelString\n{\n\t[self setYAxisLabel:[[[NSAttributedString alloc] initWithString:labelString attributes:[[self class] attributesForAxisLabels]] autorelease]];\n}\n\n- (NSRect)interiorRectForBounds:(NSRect)bounds\n{\n\tNSRect interiorRect = bounds;\n\t\n\t// For now, 10 pixels margin on a side if there is no axis, 40 pixels margin if there is an axis\n\t\n\tif ([self showXAxis])\n\t{\n\t\tinteriorRect.origin.x += 50;\n\t\tinteriorRect.size.width -= 60;\n\t}\n\telse\n\t{\n\t\tinteriorRect.origin.x += 10;\n\t\tinteriorRect.size.width -= 20;\n\t}\n\t\n\tif ([self showYAxis])\n\t{\n\t\tinteriorRect.origin.y += 50;\n\t\tinteriorRect.size.height -= 60;\n\t}\n\telse\n\t{\n\t\tinteriorRect.origin.y += 10;\n\t\tinteriorRect.size.height -= 20;\n\t}\n\t\n\treturn interiorRect;\n}\n\n- (double)plotToDeviceX:(double)plotx withInteriorRect:(NSRect)interiorRect\n{\n\tdouble fractionAlongAxis = (plotx - _xAxisMin) / (_xAxisMax - _xAxisMin);\n\t\n\t// We go from the center of the first pixel to the center of the last pixel\n\treturn (fractionAlongAxis * (interiorRect.size.width - 1.0) + interiorRect.origin.x) + 0.5;\n}\n\n- (double)plotToDeviceY:(double)ploty withInteriorRect:(NSRect)interiorRect\n{\n\tdouble fractionAlongAxis = (ploty - _yAxisMin) / (_yAxisMax - _yAxisMin);\n\t\n\t// We go from the center of the first pixel to the center of the last pixel\n\treturn (fractionAlongAxis * (interiorRect.size.height - 1.0) + interiorRect.origin.y) + 0.5;\n}\n\n- (double)roundPlotToDeviceX:(double)plotx withInteriorRect:(NSRect)interiorRect\n{\n\tdouble fractionAlongAxis = (plotx - _xAxisMin) / (_xAxisMax - _xAxisMin);\n\t\n\t// We go from the center of the first pixel to the center of the last pixel, rounded off to pixel midpoints\n\treturn SLIM_SCREEN_ROUND(fractionAlongAxis * (interiorRect.size.width - 1.0) + interiorRect.origin.x) + 0.5;\n}\n\n- (double)roundPlotToDeviceY:(double)ploty withInteriorRect:(NSRect)interiorRect\n{\n\tdouble fractionAlongAxis = (ploty - _yAxisMin) / (_yAxisMax - _yAxisMin);\n\t\n\t// We go from the center of the first pixel to the center of the last pixel, rounded off to pixel midpoints\n\treturn SLIM_SCREEN_ROUND(fractionAlongAxis * (interiorRect.size.height - 1.0) + interiorRect.origin.y) + 0.5;\n}\n\n- (void)willDrawWithInteriorRect:(NSRect)interiorRect andController:(SLiMWindowController *)controller\n{\n}\n\n- (void)drawXAxisTicksWithInteriorRect:(NSRect)interiorRect\n{\n\tNSDictionary *tickAttributes = [[self class] attributesForTickLabels];\n\tNSBezierPath *path = [NSBezierPath bezierPath];\n\tdouble axisMin = [self xAxisMin];\n\tdouble axisMax = [self xAxisMax];\n\tdouble minorTickInterval = [self xAxisMinorTickInterval];\n\tint majorTickModulus = [self xAxisMajorTickModulus];\n\tint tickValuePrecision = [self xAxisTickValuePrecision];\n\tdouble tickValue;\n\tint tickIndex;\n\t\n\tfor (tickValue = axisMin, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n\t{\n\t\tBOOL isMajorTick = ((tickIndex % majorTickModulus) == 0);\n\t\tdouble xValueForTick = SLIM_SCREEN_ROUND(interiorRect.origin.x + (interiorRect.size.width - 1) * ((tickValue - axisMin) / (axisMax - axisMin))) + 0.5;\n\t\t\n\t\t//NSLog(@\"tickValue == %f, isMajorTick == %@, xValueForTick == %f\", tickValue, isMajorTick ? @\"YES\" : @\"NO\", xValueForTick);\n\t\t\n\t\t[path moveToPoint:NSMakePoint(xValueForTick, interiorRect.origin.y - (isMajorTick ? 6 : 3))];\n\t\t[path lineToPoint:NSMakePoint(xValueForTick, interiorRect.origin.y - 0.5)];\n\t\t\n\t\tif (isMajorTick)\n\t\t{\n\t\t\tdouble labelValueForTick;\n\t\t\t\n\t\t\tlabelValueForTick = tickValue;\n\t\t\t\n\t\t\tNSString *labelText = [NSString stringWithFormat:@\"%.*f\", tickValuePrecision, labelValueForTick];\n\t\t\tNSAttributedString *attributedLabel = [[NSMutableAttributedString alloc] initWithString:labelText attributes:tickAttributes];\n\t\t\tNSSize labelSize = [attributedLabel size];\n\t\t\tdouble labelY = interiorRect.origin.y - (labelSize.height + 4);\n\t\t\t\n\t\t\tif ([self tweakXAxisTickLabelAlignment])\n\t\t\t{\n\t\t\t\tif (tickValue == axisMin)\n\t\t\t\t\t[attributedLabel drawAtPoint:NSMakePoint(xValueForTick - 2.0, labelY)];\n\t\t\t\telse if (tickValue == axisMax)\n\t\t\t\t\t[attributedLabel drawAtPoint:NSMakePoint(xValueForTick - SLIM_SCREEN_ROUND(labelSize.width) + 2.0, labelY)];\n\t\t\t\telse\n\t\t\t\t\t[attributedLabel drawAtPoint:NSMakePoint(xValueForTick - SLIM_SCREEN_ROUND(labelSize.width / 2.0), labelY)];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[attributedLabel drawAtPoint:NSMakePoint(xValueForTick - SLIM_SCREEN_ROUND(labelSize.width / 2.0), labelY)];\n\t\t\t}\n\t\t\t[attributedLabel release];\n\t\t}\n\t}\n\t\n\t[path setLineWidth:1.0];\n\t[[NSColor blackColor] set];\n\t[path stroke];\n}\n\n- (void)drawXAxisWithInteriorRect:(NSRect)interiorRect\n{\n\tint yAxisFudge = [self showYAxis] ? 1 : 0;\n\tNSRect axisRect = NSMakeRect(interiorRect.origin.x - yAxisFudge, interiorRect.origin.y - 1, interiorRect.size.width + yAxisFudge, 1);\n\t\n\t[[NSColor blackColor] set];\n\tNSRectFill(axisRect);\n\t\n\t// show label\n\tNSAttributedString *label = [self xAxisLabel];\n\tNSSize labelSize = [label size];\n\t\n\t[label drawAtPoint:NSMakePoint(interiorRect.origin.x + (interiorRect.size.width - labelSize.width) / 2.0, interiorRect.origin.y - 45)];\n}\n\n- (void)drawYAxisTicksWithInteriorRect:(NSRect)interiorRect\n{\n\tNSDictionary *tickAttributes = [[self class] attributesForTickLabels];\n\tNSBezierPath *path = [NSBezierPath bezierPath];\n\tdouble axisMin = [self yAxisMin];\n\tdouble axisMax = [self yAxisMax];\n\tdouble minorTickInterval = [self yAxisMinorTickInterval];\n\tint majorTickModulus = [self yAxisMajorTickModulus];\n\tint tickValuePrecision = [self yAxisTickValuePrecision];\n\tdouble tickValue;\n\tint tickIndex;\n\t\n\tfor (tickValue = axisMin, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n\t{\n\t\tBOOL isMajorTick = ((tickIndex % majorTickModulus) == 0);\n\t\tdouble yValueForTick = SLIM_SCREEN_ROUND(interiorRect.origin.y + (interiorRect.size.height - 1) * ((tickValue - axisMin) / (axisMax - axisMin))) + 0.5;\n\t\t\n\t\t//NSLog(@\"tickValue == %f, isMajorTick == %@, yValueForTick == %f\", tickValue, isMajorTick ? @\"YES\" : @\"NO\", yValueForTick);\n\t\t\n\t\t[path moveToPoint:NSMakePoint(interiorRect.origin.x - (isMajorTick ? 6 : 3), yValueForTick)];\n\t\t[path lineToPoint:NSMakePoint(interiorRect.origin.x - 0.5, yValueForTick)];\n\t\t\n\t\tif (isMajorTick)\n\t\t{\n\t\t\tdouble labelValueForTick;\n\t\t\t\n\t\t\tlabelValueForTick = tickValue;\n\t\t\t\n\t\t\tNSString *labelText = [NSString stringWithFormat:@\"%.*f\", tickValuePrecision, labelValueForTick];\n\t\t\tNSAttributedString *attributedLabel = [[NSMutableAttributedString alloc] initWithString:labelText attributes:tickAttributes];\n\t\t\tNSSize labelSize = [attributedLabel size];\n\t\t\t\n\t\t\t[attributedLabel drawAtPoint:NSMakePoint(interiorRect.origin.x - (labelSize.width + 8), yValueForTick - SLIM_SCREEN_ROUND(labelSize.height / 2.0) + 2)];\n\t\t\t[attributedLabel release];\n\t\t}\n\t}\n\t\n\t[path setLineWidth:1.0];\n\t[[NSColor blackColor] set];\n\t[path stroke];\n}\n\n- (void)drawYAxisWithInteriorRect:(NSRect)interiorRect\n{\n\tint xAxisFudge = [self showXAxis] ? 1 : 0;\n\tNSRect axisRect = NSMakeRect(interiorRect.origin.x - 1, interiorRect.origin.y - xAxisFudge, 1, interiorRect.size.height + xAxisFudge);\n\t\n\t[[NSColor blackColor] set];\n\tNSRectFill(axisRect);\n\t\n\t// show label, rotated\n\tNSAttributedString *label = [self yAxisLabel];\n\tNSSize labelSize = [label size];\n\t\n\t[NSGraphicsContext saveGraphicsState];\n\t\n\tNSAffineTransform *transform = [NSAffineTransform transform];\n\t[transform translateXBy:interiorRect.origin.x - 30 yBy:interiorRect.origin.y + SLIM_SCREEN_ROUND(interiorRect.size.height / 2.0)];\n\t[transform rotateByDegrees:90];\n\t[transform concat];\n\t[label drawAtPoint:NSMakePoint(SLIM_SCREEN_ROUND(-labelSize.width / 2.0), 0)];\n\t\n\t[NSGraphicsContext restoreGraphicsState];\n}\n\n- (void)drawFullBoxWithInteriorRect:(NSRect)interiorRect\n{\n\tNSRect axisRect;\n\t\n\t// upper x axis\n\tint yAxisFudge = [self showYAxis] ? 1 : 0;\n\t\n\taxisRect = NSMakeRect(interiorRect.origin.x - yAxisFudge, interiorRect.origin.y + interiorRect.size.height, interiorRect.size.width + yAxisFudge + 1, 1);\n\t\n\t[[NSColor blackColor] set];\n\tNSRectFill(axisRect);\n\t\n\t// right-hand y axis\n\tint xAxisFudge = [self showXAxis] ? 1 : 0;\n\t\n\taxisRect = NSMakeRect(interiorRect.origin.x + interiorRect.size.width, interiorRect.origin.y - xAxisFudge, 1, interiorRect.size.height + xAxisFudge + 1);\n\t\n\t[[NSColor blackColor] set];\n\tNSRectFill(axisRect);\n}\n\n- (void)drawVerticalGridLinesWithInteriorRect:(NSRect)interiorRect\n{\n\tNSBezierPath *path = [NSBezierPath bezierPath];\n\tdouble axisMin = [self xAxisMin];\n\tdouble axisMax = [self xAxisMax];\n\tdouble minorTickInterval = [self xAxisMinorTickInterval];\n\tdouble tickValue;\n\tint tickIndex;\n\t\n\tfor (tickValue = axisMin, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n\t{\n\t\tdouble xValueForTick = SLIM_SCREEN_ROUND(interiorRect.origin.x + (interiorRect.size.width - 1) * ((tickValue - axisMin) / (axisMax - axisMin))) + 0.5;\n\t\t\n\t\tif (fabs((xValueForTick - 0.5) - interiorRect.origin.x) < 0.001)\n\t\t\tcontinue;\n\t\tif ((fabs((xValueForTick - 0.5) - (interiorRect.origin.x + interiorRect.size.width - 1)) < 0.001) && [self showFullBox])\n\t\t\tcontinue;\n\t\t\n\t\t[path moveToPoint:NSMakePoint(xValueForTick, interiorRect.origin.y - 0.01)];\n\t\t[path lineToPoint:NSMakePoint(xValueForTick, interiorRect.origin.y + interiorRect.size.height + 0.01)];\n\t}\n\t\n\t[path setLineWidth:1.0];\n\t[[[self class] gridLineColor] set];\n\t[path stroke];\n}\n\n- (void)drawHorizontalGridLinesWithInteriorRect:(NSRect)interiorRect\n{\n\tNSBezierPath *path = [NSBezierPath bezierPath];\n\tdouble axisMin = [self yAxisMin];\n\tdouble axisMax = [self yAxisMax];\n\tdouble minorTickInterval = [self yAxisMinorTickInterval];\n\tdouble tickValue;\n\tint tickIndex;\n\t\n\tfor (tickValue = axisMin, tickIndex = 0; tickValue <= (axisMax + minorTickInterval / 10.0); tickValue += minorTickInterval, tickIndex++)\n\t{\n\t\tdouble yValueForTick = SLIM_SCREEN_ROUND(interiorRect.origin.y + (interiorRect.size.height - 1) * ((tickValue - axisMin) / (axisMax - axisMin))) + 0.5;\n\t\t\n\t\tif (fabs((yValueForTick - 0.5) - interiorRect.origin.y) < 0.001)\n\t\t\tcontinue;\n\t\tif ((fabs((yValueForTick - 0.5) - (interiorRect.origin.y + interiorRect.size.height - 1)) < 0.001) && [self showFullBox])\n\t\t\tcontinue;\n\t\t\n\t\t[path moveToPoint:NSMakePoint(interiorRect.origin.x - 0.01, yValueForTick)];\n\t\t[path lineToPoint:NSMakePoint(interiorRect.origin.x + interiorRect.size.width + 0.01, yValueForTick)];\n\t}\n\t\n\t[path setLineWidth:1.0];\n\t[[[self class] gridLineColor] set];\n\t[path stroke];\n}\n\n- (void)drawMessage:(NSString *)messageString inRect:(NSRect)rect\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:[[self class] labelFontName] size:16], NSForegroundColorAttributeName : [NSColor colorWithCalibratedWhite:0.4 alpha:1.0]} retain];\n\t\t\n\tNSAttributedString *attrMessage = [[NSAttributedString alloc] initWithString:messageString attributes:attrs];\n\tNSPoint centerPoint = NSMakePoint(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height / 2);\n\tNSSize messageSize = [attrMessage size];\n\tNSPoint drawPoint = NSMakePoint(SLIM_SCREEN_ROUND(centerPoint.x - messageSize.width / 2.0), SLIM_SCREEN_ROUND(centerPoint.y - messageSize.height / 2.0));\n\t\n\t[attrMessage drawAtPoint:drawPoint];\n\t[attrMessage release];\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\t[[NSColor colorWithCalibratedHue:0.15 saturation:0.15 brightness:1.0 alpha:1.0] set];\n\tNSRectFill(interiorRect);\n}\n\n- (NSArray *)legendKey\n{\n\treturn nil;\n}\n\n- (NSSize)legendSize\n{\n\tNSArray *legendKey = [self legendKey];\n\tNSInteger legendEntryCount = [legendKey count];\n\tconst int legendRowHeight = 15;\n\tNSDictionary *legendAttrs = [[self class] attributesForLegendLabels];\n\t__block NSSize legendSize = NSMakeSize(0, legendRowHeight * legendEntryCount - 6);\n\t\n\t[legendKey enumerateObjectsUsingBlock:^(NSArray *legendEntry, NSUInteger idx, BOOL *stop) {\n\t\tNSString *labelString = [legendEntry objectAtIndex:0];\n\t\tNSAttributedString *label = [[NSAttributedString alloc] initWithString:labelString attributes:legendAttrs];\n\t\tNSSize labelSize = [label size];\n\t\t\n\t\tlegendSize.width = MAX(legendSize.width, 0 + (legendRowHeight - 6) + 5 + labelSize.width);\n\t\t[label release];\n\t}];\n\t\n\treturn legendSize;\n}\n\n- (void)drawLegendInRect:(NSRect)legendRect\n{\n\tNSArray *legendKey = [self legendKey];\n\tNSInteger legendEntryCount = [legendKey count];\n\tconst int legendRowHeight = 15;\n\tNSDictionary *legendAttrs = [[self class] attributesForLegendLabels];\n\t\n\t[legendKey enumerateObjectsUsingBlock:^(NSArray *legendEntry, NSUInteger idx, BOOL *stop) {\n\t\tNSRect swatchRect = NSMakeRect(legendRect.origin.x, legendRect.origin.y + ((legendEntryCount - 1) * legendRowHeight - 3) - idx * legendRowHeight + 3, legendRowHeight - 6, legendRowHeight - 6);\n\t\tNSString *labelString = [legendEntry objectAtIndex:0];\n\t\tNSAttributedString *label = [[NSAttributedString alloc] initWithString:labelString attributes:legendAttrs];\n\t\tNSColor *entryColor = [legendEntry objectAtIndex:1];\n\t\t\n\t\t[entryColor set];\n\t\tNSRectFill(swatchRect);\n\t\t\n\t\t[[NSColor blackColor] set];\n\t\tNSFrameRect(swatchRect);\n\t\t\n\t\t[label drawAtPoint:NSMakePoint(swatchRect.origin.x + swatchRect.size.width + 5, swatchRect.origin.y - 2)];\n\t\t[label release];\n\t}];\n}\n\n- (void)drawLegendInInteriorRect:(NSRect)interiorRect\n{\n\tNSSize legendSize = [self legendSize];\n\t\n\tlegendSize.width = ceil(legendSize.width);\n\tlegendSize.height = ceil(legendSize.height);\n\t\n\tif ((legendSize.width > 0.0) && (legendSize.height > 0.0))\n\t{\n\t\tconst int legendMargin = 10;\n\t\tNSRect legendRect = NSMakeRect(0, 0, legendSize.width + legendMargin + legendMargin, legendSize.height + legendMargin + legendMargin);\n\t\t\n\t\t// Position the legend in the upper right, for now; this should be configurable\n\t\tlegendRect.origin.x = interiorRect.origin.x + interiorRect.size.width - legendRect.size.width;\n\t\tlegendRect.origin.y = interiorRect.origin.y + interiorRect.size.height - legendRect.size.height;\n\t\t\n\t\t// Frame the legend and erase it with a slightly translucent wash\n\t\t[[NSColor colorWithCalibratedWhite:0.95 alpha:0.9] set];\n\t\tNSRectFillUsingOperation(legendRect, NSCompositingOperationSourceOver);\n\t\t\n\t\t[[NSColor colorWithCalibratedWhite:0.3 alpha:1.0] set];\n\t\tNSFrameRect(legendRect);\n\t\t\n\t\t// Inset and draw the legend content\n\t\tlegendRect = NSInsetRect(legendRect, legendMargin, legendMargin);\n\t\t\n\t\t[self drawLegendInRect:legendRect];\n\t}\n}\n\n- (void)drawSpeciesAvatar\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSRect bounds = [self bounds];\n\t\n\tif (controller->community->all_species_.size() > 1)\n\t{\n\t\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\t\n\t\tif (displaySpecies)\n\t\t{\n\t\t\tNSDictionary *avatarAttrs = [[self class] attributesForAvatars];\n\t\t\tNSString *avatarString = [NSString stringWithUTF8String:displaySpecies->avatar_.c_str()];\n\t\t\tNSAttributedString *avatar = [[NSAttributedString alloc] initWithString:avatarString attributes:avatarAttrs];\n\t\t\t\n\t\t\t[avatar drawAtPoint:NSMakePoint(bounds.origin.x + bounds.size.width - 23, bounds.origin.x + 7)];\n\t\t\t[avatar release];\n\t\t}\n\t}\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tNSRect bounds = [self bounds];\n\t\n\t// Erase background\n\t[[NSColor whiteColor] set];\n\tNSRectFill(dirtyRect);\n\t\n\t// Get our controller and test for validity, so subclasses don't have to worry about this\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (!controller || [controller invalidSimulation])\n\t{\n\t\t[self drawMessage:@\"   invalid\\nsimulation\" inRect:bounds];\n\t}\n\telse if (controller->community->Tick() == 0)\n\t{\n\t\t[self drawMessage:@\" no\\ndata\" inRect:bounds];\n\t}\n\telse if (![self focalDisplaySpecies])\n\t{\n\t\t// The species name no longer refers to a species in the community\n\t\t[self drawMessage:@\"missing\\nspecies\" inRect:bounds];\n\t}\n\telse\n\t{\n\t\tNSRect interiorRect = [self interiorRectForBounds:bounds];\n\t\t\n\t\t[self willDrawWithInteriorRect:interiorRect andController:controller];\n\t\t\n\t\t// Draw grid lines, if requested, and if tick marks are turned on for the corresponding axis\n\t\tif ([self showHorizontalGridLines] && [self showYAxis] && [self showYAxisTicks])\n\t\t\t[self drawHorizontalGridLinesWithInteriorRect:interiorRect];\n\t\t\n\t\tif ([self showVerticalGridLines] && [self showXAxis] && [self showXAxisTicks])\n\t\t\t[self drawVerticalGridLinesWithInteriorRect:interiorRect];\n\t\t\n\t\t// Draw the interior of the graph; this will be overridden by the subclass\n\t\t// We clip the interior drawing to the interior rect, so outliers get clipped out\n\t\t[NSGraphicsContext saveGraphicsState];\n\t\t[[NSBezierPath bezierPathWithRect:NSInsetRect(interiorRect, -0.1, -0.1)] addClip];\n\t\t\n\t\t[self drawGraphInInteriorRect:interiorRect withController:controller];\n\t\t\n\t\t[NSGraphicsContext restoreGraphicsState];\n\t\t\n\t\t// If we're caching, skip all overdrawing, since it cannot be cached (it would then appear under new drawing that supplements the cache)\n\t\tif (!cachingNow)\n\t\t{\n\t\t\t// Overdraw axes, ticks, and axis labels, if requested\n\t\t\tif ([self showXAxis] && [self showXAxisTicks])\n\t\t\t\t[self drawXAxisTicksWithInteriorRect:interiorRect];\n\t\t\t\n\t\t\tif ([self showYAxis] && [self showYAxisTicks])\n\t\t\t\t[self drawYAxisTicksWithInteriorRect:interiorRect];\n\t\t\t\n\t\t\tif ([self showXAxis])\n\t\t\t\t[self drawXAxisWithInteriorRect:interiorRect];\n\t\t\t\n\t\t\tif ([self showYAxis])\n\t\t\t\t[self drawYAxisWithInteriorRect:interiorRect];\n\t\t\t\n\t\t\tif ([self showFullBox])\n\t\t\t\t[self drawFullBoxWithInteriorRect:interiorRect];\n\t\t\t\n\t\t\t// Overdraw the legend\n\t\t\tif ([self legendVisible])\n\t\t\t\t[self drawLegendInInteriorRect:interiorRect];\n\t\t\t\n\t\t\t// Overdraw the species avatar\n\t\t\t[self drawSpeciesAvatar];\n\t\t}\n\t}\n}\n\n- (IBAction)toggleLegend:(id)sender\n{\n\t[self setLegendVisible:![self legendVisible]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleHorizontalGridLines:(id)sender\n{\n\t[self setShowHorizontalGridLines:![self showHorizontalGridLines]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleVerticalGridLines:(id)sender\n{\n\t[self setShowVerticalGridLines:![self showVerticalGridLines]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleFullBox:(id)sender\n{\n\t[self setShowFullBox:![self showFullBox]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)rescaleSheetOK:(id)sender\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSWindow *window = [controller window];\n\t\n\t// Give our textfields a chance to validate\n\tif (![rescaleSheet makeFirstResponder:nil])\n\t\treturn;\n\t\n\t[window endSheet:rescaleSheet returnCode:NSAlertFirstButtonReturn];\n}\n\n- (IBAction)rescaleSheetCancel:(id)sender\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSWindow *window = [controller window];\n\t\n\t[window endSheet:rescaleSheet returnCode:NSAlertSecondButtonReturn];\n}\n\n- (IBAction)userRescaleXAxis:(id)sender\n{\n\tif ([self allowXAxisUserRescale])\n\t{\n\t\tSLiMWindowController *controller = [self slimWindowController];\n\t\tNSWindow *window = [controller window];\n\t\t\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"GraphAxisRescaleSheet\" owner:self topLevelObjects:NULL];\n\t\t[rescaleSheet retain];\n\t\t\n\t\t[rescaleSheetMinTextfield setDoubleValue:[self xAxisMin]];\n\t\t[rescaleSheetMaxTextfield setDoubleValue:[self xAxisMax]];\n\t\t[rescaleSheetMajorIntervalTextfield setDoubleValue:[self xAxisMajorTickInterval]];\n\t\t[rescaleSheetMinorModulusTextfield setIntValue:[self xAxisMajorTickModulus]];\n\t\t[rescaleSheetTickPrecisionTextfield setIntValue:[self xAxisTickValuePrecision]];\n\t\t\n\t\t[window beginSheet:rescaleSheet completionHandler:^(NSModalResponse returnCode) {\n\t\t\tif (returnCode == NSAlertFirstButtonReturn)\n\t\t\t{\n\t\t\t\tdouble newMin = [rescaleSheetMinTextfield doubleValue];\n\t\t\t\tdouble newMax = [rescaleSheetMaxTextfield doubleValue];\n\t\t\t\tdouble newMajorInterval = [rescaleSheetMajorIntervalTextfield doubleValue];\n\t\t\t\tint newModulus = [rescaleSheetMinorModulusTextfield intValue];\n\t\t\t\tint newPrecision = [rescaleSheetTickPrecisionTextfield intValue];\n\t\t\t\tdouble newMinorInterval = newMajorInterval / newModulus;\n\t\t\t\t\n\t\t\t\t[self setXAxisMin:newMin];\n\t\t\t\t[self setXAxisMax:newMax];\n\t\t\t\t[self setXAxisMajorTickInterval:newMajorInterval];\n\t\t\t\t[self setXAxisMajorTickModulus:newModulus];\n\t\t\t\t[self setXAxisMinorTickInterval:newMinorInterval];\n\t\t\t\t[self setXAxisTickValuePrecision:newPrecision];\n\t\t\t\t[self setXAxisIsUserRescaled:YES];\n\t\t\t\t\n\t\t\t\t[self invalidateDrawingCache];\n\t\t\t\t[self setNeedsDisplay:YES];\n\t\t\t}\n\t\t\t\n\t\t\t[rescaleSheet autorelease];\n\t\t\trescaleSheet = nil;\n\t\t}];\n\t}\n}\n\n- (IBAction)userRescaleYAxis:(id)sender\n{\n\tif ([self allowYAxisUserRescale])\n\t{\n\t\tSLiMWindowController *controller = [self slimWindowController];\n\t\tNSWindow *window = [controller window];\n\t\t\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"GraphAxisRescaleSheet\" owner:self topLevelObjects:NULL];\n\t\t[rescaleSheet retain];\n\t\t\n\t\t[rescaleSheetMinTextfield setDoubleValue:[self yAxisMin]];\n\t\t[rescaleSheetMaxTextfield setDoubleValue:[self yAxisMax]];\n\t\t[rescaleSheetMajorIntervalTextfield setDoubleValue:[self yAxisMajorTickInterval]];\n\t\t[rescaleSheetMinorModulusTextfield setIntValue:[self yAxisMajorTickModulus]];\n\t\t[rescaleSheetTickPrecisionTextfield setIntValue:[self yAxisTickValuePrecision]];\n\t\t\n\t\t[window beginSheet:rescaleSheet completionHandler:^(NSModalResponse returnCode) {\n\t\t\tif (returnCode == NSAlertFirstButtonReturn)\n\t\t\t{\n\t\t\t\tdouble newMin = [rescaleSheetMinTextfield doubleValue];\n\t\t\t\tdouble newMax = [rescaleSheetMaxTextfield doubleValue];\n\t\t\t\tdouble newMajorInterval = [rescaleSheetMajorIntervalTextfield doubleValue];\n\t\t\t\tint newModulus = [rescaleSheetMinorModulusTextfield intValue];\n\t\t\t\tint newPrecision = [rescaleSheetTickPrecisionTextfield intValue];\n\t\t\t\tdouble newMinorInterval = newMajorInterval / newModulus;\n\t\t\t\t\n\t\t\t\t[self setYAxisMin:newMin];\n\t\t\t\t[self setYAxisMax:newMax];\n\t\t\t\t[self setYAxisMajorTickInterval:newMajorInterval];\n\t\t\t\t[self setYAxisMajorTickModulus:newModulus];\n\t\t\t\t[self setYAxisMinorTickInterval:newMinorInterval];\n\t\t\t\t[self setYAxisTickValuePrecision:newPrecision];\n\t\t\t\t[self setYAxisIsUserRescaled:YES];\n\t\t\t\t\n\t\t\t\t[self invalidateDrawingCache];\n\t\t\t\t[self setNeedsDisplay:YES];\n\t\t\t}\n\t\t\t\n\t\t\t[rescaleSheet autorelease];\n\t\t\trescaleSheet = nil;\n\t\t}];\n\t}\n}\n\n- (IBAction)rescaleBarSheetOK:(id)sender\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSWindow *window = [controller window];\n\t\n\t// Give our textfields a chance to validate\n\tif (![rescaleBarsSheet makeFirstResponder:nil])\n\t\treturn;\n\t\n\t[window endSheet:rescaleBarsSheet returnCode:NSAlertFirstButtonReturn];\n}\n\n- (IBAction)rescaleBarSheetCancel:(id)sender\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSWindow *window = [controller window];\n\t\n\t[window endSheet:rescaleBarsSheet returnCode:NSAlertSecondButtonReturn];\n}\n\n- (IBAction)userRescaleXBars:(id)sender\n{\n\tif ([self allowXAxisBinRescale])\n\t{\n\t\tSLiMWindowController *controller = [self slimWindowController];\n\t\tNSWindow *window = [controller window];\n\t\t\n\t\t[[NSBundle mainBundle] loadNibNamed:@\"GraphBarRescaleSheet\" owner:self topLevelObjects:NULL];\n\t\t[rescaleBarsSheet retain];\n\t\t\n\t\t[rescaleBarsSheetCountTextfield setIntValue:[self histogramBinCount]];\n\t\t\n\t\t[window beginSheet:rescaleBarsSheet completionHandler:^(NSModalResponse returnCode) {\n\t\t\tif (returnCode == NSAlertFirstButtonReturn)\n\t\t\t{\n\t\t\t\tint newBinCount = [rescaleBarsSheetCountTextfield intValue];\n\t\t\t\t\n\t\t\t\t[self setHistogramBinCount:newBinCount];\n\t\t\t\t\n\t\t\t\t[self invalidateDrawingCache];\n\t\t\t\t[self setNeedsDisplay:YES];\n\t\t\t}\n\t\t\t\n\t\t\t[rescaleBarsSheet autorelease];\n\t\t\trescaleBarsSheet = nil;\n\t\t}];\n\t}\n}\n\n- (IBAction)copy:(id)sender\n{\n\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\t\n\t[pasteboard declareTypes:@[NSPDFPboardType] owner:self];\n\t\n\t// We set generatingPDF to allow customization for PDF generation, such as not rounding to pixel values\n\tgeneratingPDF = YES;\n\t[self writePDFInsideRect:[self bounds] toPasteboard:pasteboard];\n\tgeneratingPDF = NO;\n}\n\n- (IBAction)saveGraph:(id)sender\n{\n\t// We set generatingPDF to allow customization for PDF generation, such as not rounding to pixel values\n\tgeneratingPDF = YES;\n\tNSData *pdfData = [self dataWithPDFInsideRect:[self bounds]];\n\tgeneratingPDF = NO;\n\t\n\tSLiMWindowController *controller = [self slimWindowController];\n\tNSSavePanel *sp = [[NSSavePanel savePanel] retain];\n\t\n\t[sp setTitle:@\"Export Graph\"];\n\t[sp setNameFieldLabel:@\"Export As:\"];\n\t[sp setMessage:@\"Export the graph to a file:\"];\n\t[sp setExtensionHidden:NO];\n\t[sp setCanSelectHiddenExtension:NO];\n\t[sp setAllowedFileTypes:@[@\"pdf\"]];\n\t\n\t[sp beginSheetModalForWindow:[controller window] completionHandler:^(NSInteger result) {\n\t\tif (result == NSModalResponseOK)\n\t\t{\n\t\t\t[pdfData writeToURL:[sp URL] atomically:YES];\n\t\t\t\n\t\t\t[sp autorelease];\n\t\t}\n\t}];\n}\n\n- (NSString *)dateline\n{\n\tNSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterMediumStyle];\n\t\n\treturn [NSString stringWithFormat:@\"# %@\", dateString];\n}\n\n- (IBAction)copyData:(id)sender\n{\n\tif ([self respondsToSelector:@selector(stringForDataWithController:)])\n\t{\n\t\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\t\t\n\t\t[pasteboard declareTypes:@[NSStringPboardType] owner:self];\n\t\t[pasteboard setString:[self stringForDataWithController:[self slimWindowController]] forType:NSStringPboardType];\n\t}\n}\n\n- (IBAction)saveData:(id)sender\n{\n\tif ([self respondsToSelector:@selector(stringForDataWithController:)])\n\t{\n\t\tSLiMWindowController *controller = [self slimWindowController];\n\t\tNSString *dataString = [self stringForDataWithController:controller];\n\t\tNSSavePanel *sp = [[NSSavePanel savePanel] retain];\n\t\t\n\t\t[sp setTitle:@\"Export Data\"];\n\t\t[sp setNameFieldLabel:@\"Export As:\"];\n\t\t[sp setMessage:@\"Export the graph data to a file:\"];\n\t\t[sp setExtensionHidden:NO];\n\t\t[sp setCanSelectHiddenExtension:NO];\n\t\t[sp setAllowedFileTypes:@[@\"txt\"]];\n\t\t\n\t\t[sp beginSheetModalForWindow:[controller window] completionHandler:^(NSInteger result) {\n\t\t\tif (result == NSModalResponseOK)\n\t\t\t{\n\t\t\t\t[dataString writeToURL:[sp URL] atomically:YES encoding:NSUTF8StringEncoding error:NULL];\n\t\t\t\t\n\t\t\t\t[sp autorelease];\n\t\t\t}\n\t\t}];\n\t}\n}\n\n- (NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (![controller invalidSimulation] && ![[controller window] attachedSheet] && [self focalDisplaySpecies])\n\t{\n\t\tBOOL addedItems = NO;\n\t\tNSMenu *menu = [[NSMenu alloc] initWithTitle:@\"graph_menu\"];\n\t\t\n\t\t// Toggle legend visibility\n\t\tNSSize legendSize = [self legendSize];\n\t\t\n\t\tif ((legendSize.width > 0.0) && (legendSize.height > 0.0))\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self legendVisible] ? @\"Hide Legend\" : @\"Show Legend\") action:@selector(toggleLegend:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Toggle horizontal grid line visibility\n\t\tif ([self showYAxis] && [self showYAxisTicks])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self showHorizontalGridLines] ? @\"Hide Horizontal Grid\" : @\"Show Horizontal Grid\") action:@selector(toggleHorizontalGridLines:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Toggle vertical grid line visibility\n\t\tif ([self showXAxis] && [self showXAxisTicks])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self showVerticalGridLines] ? @\"Hide Vertical Grid\" : @\"Show Vertical Grid\") action:@selector(toggleVerticalGridLines:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Toggle box visibility\n\t\tif ([self showXAxis] && [self showYAxis])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self showFullBox] ? @\"Hide Full Box\" : @\"Show Full Box\") action:@selector(toggleFullBox:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Add a separator if we had any visibility-toggle menu items above\n\t\tif (addedItems)\n\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\taddedItems = NO;\n\t\t\n\t\t// Rescale x axis\n\t\tif ([self showXAxis] && [self showXAxisTicks] && [self allowXAxisUserRescale])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:@\"Change X Axis Scale...\" action:@selector(userRescaleXAxis:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\tif ([self histogramBinCount] && [self allowXAxisBinRescale])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:@\"Change X Bar Count...\" action:@selector(userRescaleXBars:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Rescale y axis\n\t\tif ([self showYAxis] && [self showYAxisTicks] && [self allowYAxisUserRescale])\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:@\"Change Y Axis Scale...\" action:@selector(userRescaleYAxis:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t\taddedItems = YES;\n\t\t}\n\t\t\n\t\t// Add a separator if we had any visibility-toggle menu items above\n\t\tif (addedItems)\n\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\taddedItems = NO;\n\t\t(void)addedItems;\t// dead store above is deliberate\n\t\t\n\t\t// Allow a subclass to introduce menu items here, above the copy/export menu items, which belong at the bottom; we are responsible for adding a separator afterwards if needed\n\t\tNSInteger preSubclassItemCount = [menu numberOfItems];\n\t\t\n\t\t[self subclassAddItemsToMenu:menu forEvent:theEvent];\n\t\t\n\t\tif (preSubclassItemCount != [menu numberOfItems])\n\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\t\n\t\t// Copy/export the graph image\n\t\t{\n\t\t\tNSMenuItem *menuItem;\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Copy Graph\" action:@selector(copy:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTarget:self];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Export Graph...\" action:@selector(saveGraph:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t\t\n\t\t// Copy/export the data to the clipboard\n\t\tif ([self respondsToSelector:@selector(stringForDataWithController:)])\n\t\t{\n\t\t\tNSMenuItem *menuItem;\n\t\t\t\n\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Copy Data\" action:@selector(copyData:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTarget:self];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Export Data...\" action:@selector(saveData:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t\t\n\t\treturn [menu autorelease];\n\t}\n\t\n\treturn nil;\n}\n\n- (void)subclassAddItemsToMenu:(NSMenu *)menu forEvent:(NSEvent *)theEvent\n{\n}\n\n- (void)invalidateDrawingCache\n{\n\t// GraphView has no drawing cache, but it supports the idea of one\n}\n\n- (void)graphWindowResized\n{\n\t[self invalidateDrawingCache];\n}\n\n- (void)controllerRecycled\n{\n\t[self updateSpeciesBadge];\n\t[self invalidateDrawingCache];\n\t[self setNeedsDisplay:YES];\n}\n\n- (void)controllerSelectionChanged\n{\n}\n\n- (void)controllerTickFinished\n{\n}\n\n- (void)updateAfterTick\n{\n\t[self updateSpeciesBadge];\n\t[self setNeedsDisplay:YES];\n}\n\n@end\n\n\n@implementation GraphView (PrefabAdditions)\n\n- (void)setXAxisRangeFromTick\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tCommunity &community = *controller->community;\n\t\n\t// We can't get the estimated last tick until tick ranges are known\n\tif (community.Tick() < 1)\n\t\treturn;\n\t\n\tslim_tick_t lastTick = community.EstimatedLastTick();\n\t\n\t// The last tick could be just about anything, so we need some smart axis setup code here – a problem we neglect elsewhere\n\t// since we use hard-coded axis setups in other places.  The goal is to (1) have the axis max be >= lastTick, (2) have the axis\n\t// max be == lastTick if lastTick is a reasonably round number (a single-digit multiple of a power of 10, say), (3) have just a few\n\t// other major tick intervals drawn, so labels don't collide or look crowded, and (4) have a few minor tick intervals in between\n\t// the majors.  Labels that are single-digit multiples of powers of 10 are to be strongly preferred.\n\tdouble lower10power = pow(10.0, floor(log10(lastTick)));\t// 8000 gives 1000, 1000 gives 1000, 10000 gives 10000\n\tdouble lower5mult = lower10power / 2.0;\t\t\t\t\t\t// 8000 gives 500, 1000 gives 500, 10000 gives 5000\n\tdouble axisMax = ceil(lastTick / lower5mult) * lower5mult;\t// 8000 gives 8000, 7500 gives 7500, 1100 gives 1500\n\tdouble contained5mults = axisMax / lower5mult;\t\t\t\t// 8000 gives 16, 7500 gives 15, 1100 gives 3, 1000 gives 2\n\t\n\tif (contained5mults <= 3)\n\t{\n\t\t// We have a max like 1500 that divides into 5mults well, so do that\n\t\t[self setXAxisMax:axisMax];\n\t\t[self setXAxisMajorTickInterval:lower5mult];\n\t\t[self setXAxisMinorTickInterval:lower5mult / 5];\n\t\t[self setXAxisMajorTickModulus:5];\n\t\t[self setXAxisTickValuePrecision:0];\n\t}\n\telse\n\t{\n\t\t// We have a max like 7000 that does not divide into 5mults well; for simplicity, we just always divide these in two\n\t\t[self setXAxisMax:axisMax];\n\t\t[self setXAxisMajorTickInterval:axisMax / 2];\n\t\t[self setXAxisMinorTickInterval:axisMax / 4];\n\t\t[self setXAxisMajorTickModulus:2];\n\t\t[self setXAxisTickValuePrecision:0];\n\t}\n}\n\n- (NSArray *)mutationTypeLegendKey\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (!displaySpecies)\n\t\treturn nil;\n\t\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\t\n\t// if we only have one mutation type, do not show a legend\n\tif (mutationTypeCount < 2)\n\t\treturn nil;\n\t\n\tNSMutableArray *legendKey = [NSMutableArray array];\n\t\n\t// first we put in placeholders\n\tfor (auto mutationTypeIter = displaySpecies->mutation_types_.begin(); mutationTypeIter != displaySpecies->mutation_types_.end(); ++mutationTypeIter)\n\t\t[legendKey addObject:@\"placeholder\"];\n\t\n\t// then we replace the placeholders with lines, but we do it out of order, according to mutation_type_index_ values\n\tfor (auto mutationTypeIter = displaySpecies->mutation_types_.begin(); mutationTypeIter != displaySpecies->mutation_types_.end(); ++mutationTypeIter)\n\t{\n\t\tMutationType *mutationType = (*mutationTypeIter).second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\tNSString *labelString = [NSString stringWithFormat:@\"m%lld\", (long long int)mutationType->mutation_type_id_];\n\t\t\n\t\t[legendKey replaceObjectAtIndex:mutationTypeIndex withObject:@[labelString, [SLiMWindowController blackContrastingColorForIndex:mutationTypeIndex]]];\n\t}\n\t\n\treturn legendKey;\n}\n\n- (void)drawGroupedBarplotInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller buffer:(double *)buffer subBinCount:(int)subBinCount mainBinCount:(int)mainBinCount firstBinValue:(double)firstBinValue mainBinWidth:(double)mainBinWidth\n{\n\t// Decide on a display style; if we have lots of width, then we draw bars with a fill color, spaced out nicely,\n\t// but if we are cramped for space then we draw solid black bars.  Note the latter style does not really\n\t// work with sub-bins; not much we can do about that, since we don't have the room to draw...\n\tint interiorWidth = (int)interiorRect.size.width;\n\tint totalBarCount = subBinCount * mainBinCount;\n\tint drawStyle = 0;\n\t\n\tif (totalBarCount * 7 + 1 <= interiorWidth)\t\t\t\t// room for space, space, space, frame, fill, fill, frame...\n\t\tdrawStyle = 0;\n\telse if (totalBarCount * 5 + 1 <= interiorWidth)\t\t// room for space, frame, fill, fill, frame...\n\t\tdrawStyle = 1;\n\telse if (totalBarCount * 2 + 1 <= interiorWidth)\t\t// room for frame, fill, [frame]...\n\t\tdrawStyle = 2;\n\telse\n\t{\n\t\t[[NSColor blackColor] set];\n\t\tdrawStyle = 3;\n\t}\n\t\n\tfor (int mainBinIndex = 0; mainBinIndex < mainBinCount; ++mainBinIndex)\n\t{\n\t\tdouble binMinValue = mainBinIndex * mainBinWidth + firstBinValue;\n\t\tdouble binMaxValue = (mainBinIndex + 1) * mainBinWidth + firstBinValue;\n\t\tdouble barLeft = [self roundPlotToDeviceX:binMinValue withInteriorRect:interiorRect];\n\t\tdouble barRight = [self roundPlotToDeviceX:binMaxValue withInteriorRect:interiorRect];\n\t\t\n\t\tswitch (drawStyle)\n\t\t{\n\t\t\tcase 0: barLeft += 1.5; barRight -= 1.5; break;\n\t\t\tcase 1: barLeft += 0.5; barRight -= 0.5; break;\n\t\t\tcase 2: barLeft -= 0.5; barRight += 0.5; break;\n\t\t\tcase 3: barLeft -= 0.5; barRight += 0.5; break;\n\t\t}\n\t\t\n\t\tfor (int subBinIndex = 0; subBinIndex < subBinCount; ++subBinIndex)\n\t\t{\n\t\t\tint actualBinIndex = subBinIndex + mainBinIndex * subBinCount;\n\t\t\tdouble binValue = buffer[actualBinIndex];\n\t\t\tdouble barBottom = interiorRect.origin.y - 1;\n\t\t\tdouble barTop = (binValue == 0 ? interiorRect.origin.y - 1 : [self roundPlotToDeviceY:binValue withInteriorRect:interiorRect] + 0.5);\n\t\t\tNSRect barRect = NSMakeRect(barLeft, barBottom, barRight - barLeft, barTop - barBottom);\n\t\t\t\n\t\t\tif (barRect.size.height > 0.0)\n\t\t\t{\n\t\t\t\t// subdivide into sub-bars for each mutation type, if there is more than one\n\t\t\t\tif (subBinCount > 1)\n\t\t\t\t{\n\t\t\t\t\tdouble barWidth = barRect.size.width;\n\t\t\t\t\tdouble subBarWidth = (barWidth - 1) / subBinCount;\n\t\t\t\t\tdouble subbarLeft = SLIM_SCREEN_ROUND(barRect.origin.x + subBinIndex * subBarWidth);\n\t\t\t\t\tdouble subbarRight = SLIM_SCREEN_ROUND(barRect.origin.x + (subBinIndex + 1) * subBarWidth) + 1;\n\t\t\t\t\t\n\t\t\t\t\tbarRect.origin.x = subbarLeft;\n\t\t\t\t\tbarRect.size.width = subbarRight - subbarLeft;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// fill and frame\n\t\t\t\tif (drawStyle == 3)\n\t\t\t\t{\n\t\t\t\t\tNSRectFill(barRect);\n\t\t\t\t\tNSFrameRect(barRect);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[[SLiMWindowController blackContrastingColorForIndex:subBinIndex] set];\n\t\t\t\t\tNSRectFill(barRect);\n\t\t\t\t\t\n\t\t\t\t\t[[NSColor blackColor] set];\n\t\t\t\t\tNSFrameRect(barRect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)drawBarplotInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller buffer:(double *)buffer binCount:(int)binCount firstBinValue:(double)firstBinValue binWidth:(double)binWidth\n{\n\t[self drawGroupedBarplotInInteriorRect:interiorRect withController:controller buffer:buffer subBinCount:1 mainBinCount:binCount firstBinValue:firstBinValue mainBinWidth:binWidth];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_FitnessOverTime.h",
    "content": "//\n//  GraphView_FitnessOverTime.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots a histogram of the distribution of times to loss of mutations.  The data is gathered by SLiM, so it is quite simple.\n \n */\n\n\n#import \"GraphView.h\"\n\n\n@interface GraphView_FitnessOverTime : GraphView\n{\n\tNSImage *drawingCache;\n\tslim_tick_t drawingCacheTick;\n}\n\n@property (nonatomic) BOOL showSubpopulations;\n@property (nonatomic) BOOL drawLines;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_FitnessOverTime.mm",
    "content": "//\n//  GraphView_FitnessOverTime.m\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_FitnessOverTime.h\"\n#import \"SLiMWindowController.h\"\n\n#include \"community.h\"\n\n\n@implementation GraphView_FitnessOverTime\n\n- (void)invalidateDrawingCache\n{\n\t[drawingCache release];\n\tdrawingCache = nil;\n\tdrawingCacheTick = 0;\n}\n\n- (void)setDefaultYAxisRange\n{\n\t[self setYAxisMin:0.9];\n\t[self setYAxisMax:1.1];\t\t// dynamic\n\t[self setYAxisMajorTickInterval:0.1];\n\t[self setYAxisMinorTickInterval:0.02];\n\t[self setYAxisMajorTickModulus:5];\n\t[self setYAxisTickValuePrecision:1];\n}\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t//[self setXAxisRangeFromTick];\t// the end tick is not yet known\n\t\t[self setDefaultYAxisRange];\n\t\t\n\t\t[self setXAxisLabelString:@\"Tick\"];\n\t\t[self setYAxisLabelString:@\"Fitness (rescaled)\"];\n\t\t\n\t\t[self setAllowXAxisUserRescale:YES];\n\t\t[self setAllowYAxisUserRescale:YES];\n\t\t\n\t\t[self setShowHorizontalGridLines:YES];\n\t\t[self setTweakXAxisTickLabelAlignment:YES];\n\t\t\n\t\t[self setShowSubpopulations:YES];\n\t}\n\t\n\treturn self;\n}\n\n- (void)controllerRecycled\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (![controller invalidSimulation])\n\t{\n\t\tif (![self yAxisIsUserRescaled])\n\t\t\t[self setDefaultYAxisRange];\n\t\t//if (![self xAxisIsUserRescaled])\t// the end tick is not yet known\n\t\t//\t[self setXAxisRangeFromTick];\n\t\t\n\t\t[self setNeedsDisplay:YES];\n\t}\n\t\n\t[super controllerRecycled];\n}\n\n- (void)controllerSelectionChanged\n{\n\t[self invalidateDrawingCache];\n\t[self setNeedsDisplay:YES];\n\t\n\t[super controllerSelectionChanged];\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (void)updateAfterTick\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\t// BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n\tif (displaySpecies && ![self xAxisIsUserRescaled])\n\t\t[self setXAxisRangeFromTick];\n\t\n\tif (displaySpecies && ![self yAxisIsUserRescaled])\n\t{\n\t\tPopulation &pop = displaySpecies->population_;\n\t\tdouble minHistory = INFINITY;\n\t\tdouble maxHistory = -INFINITY;\n\t\tBOOL showSubpops = [self showSubpopulations] && (pop.fitness_histories_.size() > 2);\n\t\t\n\t\tfor (auto history_record_iter : pop.fitness_histories_)\n\t\t{\n\t\t\tif (showSubpops || (history_record_iter.first == -1))\n\t\t\t{\n\t\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\t\tdouble *history = history_record.history_;\n\t\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\t\n\t\t\t\t// find the min and max history value\n\t\t\t\tfor (int i = 0; i < historyLength; ++i)\n\t\t\t\t{\n\t\t\t\t\tdouble historyEntry = history[i];\n\t\t\t\t\t\n\t\t\t\t\tif (!isnan(historyEntry))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (historyEntry > maxHistory)\n\t\t\t\t\t\t\tmaxHistory = historyEntry;\n\t\t\t\t\t\tif (historyEntry < minHistory)\n\t\t\t\t\t\t\tminHistory = historyEntry;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// set axis range to encompass the data\n\t\tif (!isinf(minHistory) && !isinf(maxHistory))\n\t\t{\n\t\t\tif ((minHistory < 0.9) || (maxHistory > 1.1))\t// if we're outside our original axis range...\n\t\t\t{\n\t\t\t\tdouble axisMin = (minHistory < 0.5 ? 0.0 : 0.5);\t// either 0.0 or 0.5\n\t\t\t\tdouble axisMax = ceil(maxHistory * 2.0) / 2.0;\t\t// 1.5, 2.0, 2.5, ...\n\t\t\t\t\n\t\t\t\tif (axisMax < 1.5)\n\t\t\t\t\taxisMax = 1.5;\n\t\t\t\t\n\t\t\t\tif ((axisMin != [self yAxisMin]) || (axisMax != [self yAxisMax]))\n\t\t\t\t{\n\t\t\t\t\t[self setYAxisMin:axisMin];\n\t\t\t\t\t[self setYAxisMax:axisMax];\n\t\t\t\t\t[self setYAxisMajorTickInterval:0.5];\n\t\t\t\t\t[self setYAxisMinorTickInterval:0.25];\n\t\t\t\t\t[self setYAxisMajorTickModulus:2];\n\t\t\t\t\t[self setYAxisTickValuePrecision:1];\n\t\t\t\t\t\n\t\t\t\t\t[self invalidateDrawingCache];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t[super updateAfterTick];\n}\n\n- (void)drawPointGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tslim_tick_t completedTicks = controller->community->Tick() - 1;\n\t\n\t// The tick counter can get set backwards, in which case our drawing cache is invalid – it contains drawing of things in the\n\t// future that may no longer happen.  So we need to detect that case and invalidate our cache.\n\tif (!cachingNow && drawingCache && (drawingCacheTick > completedTicks))\n\t{\n\t\t//NSLog(@\"backward tick change detected, invalidating drawing cache\");\n\t\t[self invalidateDrawingCache];\n\t}\n\t\n\t// If we're not caching, then: if our cache is invalid OR we have crossed a 1000-tick boundary since we last cached, cache an image\n\tif (!cachingNow && (!drawingCache || ((completedTicks / 1000) > (drawingCacheTick / 1000))))\n\t{\n\t\t[self invalidateDrawingCache];\n\t\t\n\t\tNSBitmapImageRep *bitmap = [self bitmapImageRepForCachingDisplayInRect:interiorRect];\n\t\t\n\t\tcachingNow = YES;\n\t\t//NSLog(@\"recaching!  completedTicks == %d\", completedTicks);\n\t\t[bitmap setSize:interiorRect.size];\n\t\t[self cacheDisplayInRect:interiorRect toBitmapImageRep:bitmap];\n\t\tdrawingCache = [[NSImage alloc] initWithSize:interiorRect.size];\n\t\t[drawingCache addRepresentation:bitmap];\n\t\tdrawingCacheTick = completedTicks;\n\t\tcachingNow = NO;\n\t}\n\t\n\t// Now draw our cache, if we have one\n\tif (drawingCache)\n\t\t[drawingCache drawInRect:interiorRect];\n\t\n\t// Draw fixation events\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n\t\t\n\t\t// If we are caching, draw all events; if we are not, draw only those that are not already in the cache\n\t\tif (!cachingNow && (fixation_tick < drawingCacheTick))\n\t\t\tcontinue;\n\t\t\n\t\tdouble substitutionX = [self plotToDeviceX:fixation_tick withInteriorRect:interiorRect];\n\t\tNSRect substitutionRect = NSMakeRect(substitutionX - 0.5, interiorRect.origin.x, 1.0, interiorRect.size.height);\n\t\t\n\t\t[[NSColor colorWithCalibratedRed:0.2 green:0.2 blue:1.0 alpha:0.2] set];\n\t\tNSRectFillUsingOperation(substitutionRect, NSCompositingOperationSourceOver);\n\t}\n\t\n\t// Draw the fitness history as a scatter plot; better suited to caching of the image\n\tBOOL showSubpops = [self showSubpopulations] && (pop.fitness_histories_.size() > 2);\n\tBOOL drawSubpopsGray = (showSubpops && (pop.fitness_histories_.size() > 8));\t// 7 subpops + pop\n\t\n\t// First draw subpops\n\tif (showSubpops)\n\t{\n\t\tfor (auto history_record_iter : pop.fitness_histories_)\n\t\t{\n\t\t\tif (history_record_iter.first != -1)\n\t\t\t{\n\t\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\t\tdouble *history = history_record.history_;\n\t\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\t\n\t\t\t\tif (drawSubpopsGray)\n\t\t\t\t\t[[NSColor colorWithCalibratedWhite:0.5 alpha:1.0] set];\n\t\t\t\telse\n\t\t\t\t\t[[SLiMWindowController whiteContrastingColorForIndex:history_record_iter.first] set];\n\t\t\t\t\n\t\t\t\t// If we're caching now, draw all points; otherwise, if we have a cache, draw only additional points\n\t\t\t\tslim_tick_t firstHistoryEntryToDraw = (cachingNow ? 0 : (drawingCache ? drawingCacheTick : 0));\n\t\t\t\t\n\t\t\t\tfor (slim_tick_t i = firstHistoryEntryToDraw; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t\t{\n\t\t\t\t\tdouble historyEntry = history[i];\n\t\t\t\t\t\n\t\t\t\t\tif (!isnan(historyEntry))\n\t\t\t\t\t{\n\t\t\t\t\t\tNSPoint historyPoint = NSMakePoint([self plotToDeviceX:i withInteriorRect:interiorRect], [self plotToDeviceY:historyEntry withInteriorRect:interiorRect]);\n\t\t\t\t\t\t\n\t\t\t\t\t\tNSRectFill(NSMakeRect(historyPoint.x - 0.5, historyPoint.y - 0.5, 1.0, 1.0));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Then draw the mean population fitness\n\tfor (auto history_record_iter : pop.fitness_histories_)\n\t{\n\t\tif (history_record_iter.first == -1)\n\t\t{\n\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\tdouble *history = history_record.history_;\n\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\n\t\t\t[[NSColor blackColor] set];\n\t\t\t\n\t\t\t// If we're caching now, draw all points; otherwise, if we have a cache, draw only additional points\n\t\t\tslim_tick_t firstHistoryEntryToDraw = (cachingNow ? 0 : (drawingCache ? drawingCacheTick : 0));\n\t\t\t\n\t\t\tfor (slim_tick_t i = firstHistoryEntryToDraw; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t{\n\t\t\t\tdouble historyEntry = history[i];\n\t\t\t\t\n\t\t\t\tif (!isnan(historyEntry))\n\t\t\t\t{\n\t\t\t\t\tNSPoint historyPoint = NSMakePoint([self plotToDeviceX:i withInteriorRect:interiorRect], [self plotToDeviceY:historyEntry withInteriorRect:interiorRect]);\n\t\t\t\t\t\n\t\t\t\t\tNSRectFill(NSMakeRect(historyPoint.x - 0.5, historyPoint.y - 0.5, 1.0, 1.0));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)drawLineGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tslim_tick_t completedTicks = controller->community->Tick() - 1;\n\t\n\t// Draw fixation events\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n\t\tdouble substitutionX = [self plotToDeviceX:fixation_tick withInteriorRect:interiorRect];\n\t\tNSRect substitutionRect = NSMakeRect(substitutionX - 0.5, interiorRect.origin.x, 1.0, interiorRect.size.height);\n\t\t\n\t\t[[NSColor colorWithCalibratedRed:0.2 green:0.2 blue:1.0 alpha:0.2] set];\n\t\tNSRectFillUsingOperation(substitutionRect, NSCompositingOperationSourceOver);\n\t}\n\t\n\t// Draw the fitness history as a scatter plot; better suited to caching of the image\n\tBOOL showSubpops = [self showSubpopulations] && (pop.fitness_histories_.size() > 2);\n\tBOOL drawSubpopsGray = (showSubpops && (pop.fitness_histories_.size() > 8));\t// 7 subpops + pop\n\t\n\t// First draw subpops\n\tif (showSubpops)\n\t{\n\t\tfor (auto history_record_iter : pop.fitness_histories_)\n\t\t{\n\t\t\tif (history_record_iter.first != -1)\n\t\t\t{\n\t\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\t\tdouble *history = history_record.history_;\n\t\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\tNSBezierPath *linePath = [NSBezierPath bezierPath];\n\t\t\t\tBOOL startedLine = NO;\n\t\t\t\t\n\t\t\t\tfor (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t\t{\n\t\t\t\t\tdouble historyEntry = history[i];\n\t\t\t\t\t\n\t\t\t\t\tif (isnan(historyEntry))\n\t\t\t\t\t{\n\t\t\t\t\t\tstartedLine = NO;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tNSPoint historyPoint = NSMakePoint([self plotToDeviceX:i withInteriorRect:interiorRect], [self plotToDeviceY:historyEntry withInteriorRect:interiorRect]);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (startedLine)\t[linePath lineToPoint:historyPoint];\n\t\t\t\t\t\telse\t\t\t\t[linePath moveToPoint:historyPoint];\n\t\t\t\t\t\t\n\t\t\t\t\t\tstartedLine = YES;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (drawSubpopsGray)\n\t\t\t\t\t[[NSColor colorWithCalibratedWhite:0.5 alpha:1.0] set];\n\t\t\t\telse\n\t\t\t\t\t[[SLiMWindowController whiteContrastingColorForIndex:history_record_iter.first] set];\n\t\t\t\t\n\t\t\t\t[linePath setLineWidth:1.0];\n\t\t\t\t[linePath stroke];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Then draw the mean population fitness\n\tfor (auto history_record_iter : pop.fitness_histories_)\n\t{\n\t\tif (history_record_iter.first == -1)\n\t\t{\n\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\tdouble *history = history_record.history_;\n\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\tNSBezierPath *linePath = [NSBezierPath bezierPath];\n\t\t\tBOOL startedLine = NO;\n\t\t\t\n\t\t\tfor (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t{\n\t\t\t\tdouble historyEntry = history[i];\n\t\t\t\t\n\t\t\t\tif (isnan(historyEntry))\n\t\t\t\t{\n\t\t\t\t\tstartedLine = NO;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSPoint historyPoint = NSMakePoint([self plotToDeviceX:i withInteriorRect:interiorRect], [self plotToDeviceY:historyEntry withInteriorRect:interiorRect]);\n\t\t\t\t\t\n\t\t\t\t\tif (startedLine)\t[linePath lineToPoint:historyPoint];\n\t\t\t\t\telse\t\t\t\t[linePath moveToPoint:historyPoint];\n\t\t\t\t\t\n\t\t\t\t\tstartedLine = YES;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t[[NSColor blackColor] set];\n\t\t\t[linePath setLineWidth:1.5];\n\t\t\t[linePath stroke];\n\t\t}\n\t}\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tif ([self drawLines])\n\t\t[self drawLineGraphInInteriorRect:interiorRect withController:controller];\n\telse\n\t\t[self drawPointGraphInInteriorRect:interiorRect withController:controller];\n}\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller\n{\n\tNSMutableString *string = [NSMutableString stringWithString:@\"# Graph data: fitness ~ tick\\n\"];\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tslim_tick_t completedTicks = controller->community->Tick() - 1;\n\t\n\t[string appendString:[self dateline]];\n\t\n\t// Fixation events\n\t[string appendString:@\"\\n\\n# Fixation ticks:\\n\"];\n\t\n\tstd::vector<Substitution*> &substitutions = pop.substitutions_;\n\t\n\tfor (const Substitution *substitution : substitutions)\n\t{\n\t\tslim_tick_t fixation_tick = substitution->fixation_tick_;\n\t\t\n\t\t[string appendFormat:@\"%lld, \", (long long int)fixation_tick];\n\t}\n\t\n\t// Fitness history\n\t[string appendString:@\"\\n\\n# Fitness history:\\n\"];\n\t\n\tfor (auto history_record_iter : pop.fitness_histories_)\n\t{\n\t\tif (history_record_iter.first == -1)\n\t\t{\n\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\tdouble *history = history_record.history_;\n\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\n\t\t\tfor (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t\t[string appendFormat:@\"%.4f, \", history[i]];\n\t\t\t\n\t\t\t[string appendString:@\"\\n\"];\n\t\t}\n\t}\n\t\n\t// Subpopulation fitness histories\n\tBOOL showSubpops = [self showSubpopulations] && (pop.fitness_histories_.size() > 2);\n\t\n\tif (showSubpops)\n\t{\n\t\tfor (auto history_record_iter : pop.fitness_histories_)\n\t\t{\n\t\t\tif (history_record_iter.first != -1)\n\t\t\t{\n\t\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\t\tdouble *history = history_record.history_;\n\t\t\t\tslim_tick_t historyLength = history_record.history_length_;\n\t\t\t\t\n\t\t\t\t[string appendFormat:@\"\\n\\n# Fitness history (subpopulation p%d):\\n\", history_record_iter.first];\n\t\t\t\t\n\t\t\t\tfor (slim_tick_t i = 0; (i < historyLength) && (i < completedTicks); ++i)\n\t\t\t\t\t[string appendFormat:@\"%.4f, \", history[i]];\n\t\t\t\t\n\t\t\t\t[string appendString:@\"\\n\"];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Get rid of extra commas\n\t[string replaceOccurrencesOfString:@\", \\n\" withString:@\"\\n\" options:0 range:NSMakeRange(0, [string length])];\n\t\n\treturn string;\n}\n\n- (NSArray *)legendKey\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tBOOL showSubpops = [self showSubpopulations] && (pop.fitness_histories_.size() > 2);\n\tBOOL drawSubpopsGray = (showSubpops && (pop.fitness_histories_.size() > 8));\t// 7 subpops + pop\n\t\n\tif (!showSubpops)\n\t\treturn nil;\n\t\n\tNSMutableArray *legendKey = [NSMutableArray array];\n\t\n\t[legendKey addObject:@[@\"All\", [NSColor blackColor]]];\n\t\n\tif (drawSubpopsGray)\n\t{\n\t\t[legendKey addObject:@[@\"pX\", [NSColor colorWithCalibratedWhite:0.5 alpha:1.0]]];\n\t}\n\telse\n\t{\n\t\tfor (auto history_record_iter : pop.fitness_histories_)\n\t\t{\n\t\t\tif (history_record_iter.first != -1)\n\t\t\t{\n\t\t\t\tNSString *labelString = [NSString stringWithFormat:@\"p%lld\", (long long int)history_record_iter.first];\n\t\t\t\t\n\t\t\t\t[legendKey addObject:@[labelString, [SLiMWindowController whiteContrastingColorForIndex:history_record_iter.first]]];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn legendKey;\n}\n\n- (IBAction)toggleShowSubpopulations:(id)sender\n{\n\t[self setShowSubpopulations:![self showSubpopulations]];\n\t[self invalidateDrawingCache];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleDrawLines:(id)sender\n{\n\t[self setDrawLines:![self drawLines]];\n\t[self invalidateDrawingCache];\n\t[self setNeedsDisplay:YES];\n}\n\n- (void)subclassAddItemsToMenu:(NSMenu *)menu forEvent:(NSEvent *)theEvent\n{\n\tif (menu)\n\t{\n\t\tNSMenuItem *menuItem;\n\t\t\n\t\tmenuItem = [menu addItemWithTitle:([self showSubpopulations] ? @\"Hide Subpopulations\" : @\"Show Subpopulations\") action:@selector(toggleShowSubpopulations:) keyEquivalent:@\"\"];\n\t\t[menuItem setTarget:self];\n\t\t\n\t\tmenuItem = [menu addItemWithTitle:([self drawLines] ? @\"Draw Points (Faster)\" : @\"Draw Lines (Slower)\") action:@selector(toggleDrawLines:) keyEquivalent:@\"\"];\n\t\t[menuItem setTarget:self];\n\t}\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFixationTimeHistogram.h",
    "content": "//\n//  GraphView_MutationFixationTimeHistogram.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots a histogram of the distribution of times to loss of mutations.  The data is gathered by SLiM, so it is quite simple.\n \n */\n\n\n#import \"GraphView.h\"\n\n\n@interface GraphView_MutationFixationTimeHistogram : GraphView\n{\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFixationTimeHistogram.mm",
    "content": "//\n//  GraphView_MutationFixationTimeHistogram.m\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_MutationFixationTimeHistogram.h\"\n#import \"SLiMWindowController.h\"\n\n\n@implementation GraphView_MutationFixationTimeHistogram\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t[self setHistogramBinCount:10];\n\t\t//[self setAllowXAxisBinRescale:YES];\t// not supported yet\n\t\t\n\t\t[self setXAxisMax:1000];\n\t\t[self setXAxisMajorTickInterval:200];\n\t\t[self setXAxisMinorTickInterval:100];\n\t\t[self setXAxisMajorTickModulus:2];\n\t\t[self setXAxisTickValuePrecision:0];\n\t\t\n\t\t[self setXAxisLabelString:@\"Mutation fixation time\"];\n\t\t[self setYAxisLabelString:@\"Proportion of fixed mutations\"];\n\t\t\n\t\t[self setAllowXAxisUserRescale:NO];\n\t\t[self setAllowYAxisUserRescale:YES];\n\t\t\n\t\t[self setShowHorizontalGridLines:YES];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (double *)fixationTimeDataWithController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tint binCount = [self histogramBinCount];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\tslim_tick_t *histogram = displaySpecies->population_.mutation_fixation_times_;\n\tint64_t histogramBins = (int64_t)displaySpecies->population_.mutation_fixation_tick_slots_;\t// fewer than binCount * mutationTypeCount may exist\n\tstatic double *rebin = NULL;\n\tstatic uint32_t rebinBins = 0;\n\tuint32_t usedRebinBins = binCount * mutationTypeCount;\n\t\n\t// re-bin for display; SLiM bins every 10 ticks, but right now we want to plot every 100 ticks as a bin\n\tif (!rebin || (rebinBins < usedRebinBins))\n\t{\n\t\trebinBins = usedRebinBins;\n\t\trebin = (double *)realloc(rebin, rebinBins * sizeof(double));\n\t}\n\t\n\tfor (unsigned int i = 0; i < usedRebinBins; ++i)\n\t\trebin[i] = 0.0;\n\t\n\tfor (int i = 0; i < binCount * 10; ++i)\n\t{\n\t\tfor (int j = 0; j < mutationTypeCount; ++j)\n\t\t{\n\t\t\tint histIndex = j + i * mutationTypeCount;\n\t\t\t\n\t\t\tif (histIndex < histogramBins)\n\t\t\t\trebin[j + (i / 10) * mutationTypeCount] += histogram[histIndex];\n\t\t}\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tuint32_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += (int64_t)rebin[binIndex];\n\t\t}\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\trebin[binIndex] /= (double)total;\n\t\t}\n\t}\n\t\n\treturn rebin;\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tdouble *plotData = [self fixationTimeDataWithController:controller];\n\tint binCount = [self histogramBinCount];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\t\n\t// plot our histogram bars\n\t[self drawGroupedBarplotInInteriorRect:interiorRect withController:controller buffer:plotData subBinCount:mutationTypeCount mainBinCount:binCount firstBinValue:0.0 mainBinWidth:100.0];\n}\n\n- (NSArray *)legendKey\n{\n\treturn [self mutationTypeLegendKey];\t// we use the prefab mutation type legend\n}\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller\n{\n\tNSMutableString *string = [NSMutableString stringWithString:@\"# Graph data: Mutation fixation time histogram\\n\"];\n\t\n\t[string appendString:[self dateline]];\n\t[string appendString:@\"\\n\\n\"];\n\t\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tdouble *plotData = [self fixationTimeDataWithController:controller];\n\tint binCount = [self histogramBinCount];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\t\n\tfor (auto mutationTypeIter = displaySpecies->mutation_types_.begin(); mutationTypeIter != displaySpecies->mutation_types_.end(); ++mutationTypeIter)\n\t{\n\t\tMutationType *mutationType = (*mutationTypeIter).second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n\t\t[string appendFormat:@\"\\\"m%lld\\\", \", (long long int)mutationType->mutation_type_id_];\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n\t\t\t[string appendFormat:@\"%.4f, \", plotData[histIndex]];\n\t\t}\n\t\t\n\t\t[string appendString:@\"\\n\"];\n\t}\n\t\n\t// Get rid of extra commas\n\t[string replaceOccurrencesOfString:@\", \\n\" withString:@\"\\n\" options:0 range:NSMakeRange(0, [string length])];\n\t\n\treturn string;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFrequencySpectra.h",
    "content": "//\n//  GraphView_MutationFrequencySpectra.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots a histogram of the frequencies of the mutations present in the whole population.  In other words, it loops\n through all of the mutations, determines their frequencies in the population, and bins those frequences to show as a histogram.\n Determining the frequences of mutations is actually done automatically by SLiM, stored in reference_count_, so this is pretty\n strightforward.\n \n */\n\n\n#import \"GraphView.h\"\n\n\n@interface GraphView_MutationFrequencySpectra : GraphView\n{\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFrequencySpectra.mm",
    "content": "//\n//  GraphView_MutationFrequencySpectra.m\n//  SLiM\n//\n//  Created by Ben Haller on 2/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_MutationFrequencySpectra.h\"\n#import \"SLiMWindowController.h\"\n\n\n@implementation GraphView_MutationFrequencySpectra\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t[self setHistogramBinCount:10];\n\t\t[self setAllowXAxisBinRescale:YES];\n\t\t\n\t\t[self setXAxisMajorTickInterval:0.2];\n\t\t[self setXAxisMinorTickInterval:0.1];\n\t\t[self setXAxisMajorTickModulus:2];\n\t\t[self setXAxisTickValuePrecision:1];\n\t\t\n\t\t[self setXAxisLabelString:@\"Mutation frequency\"];\n\t\t[self setYAxisLabelString:@\"Proportion of mutations\"];\n\t\t\n\t\t[self setAllowXAxisUserRescale:NO];\n\t\t[self setAllowYAxisUserRescale:YES];\n\t\t\n\t\t[self setShowHorizontalGridLines:YES];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (double *)mutationFrequencySpectrumWithController:(SLiMWindowController *)controller mutationTypeCount:(int)mutationTypeCount\n{\n\tstatic uint32_t *spectrum = NULL;\t\t\t// used for tallying\n\tstatic double *doubleSpectrum = NULL;\t// not used for tallying, to avoid precision issues\n\tstatic uint32_t spectrumBins = 0;\n\tint binCount = [self histogramBinCount];\n\tuint32_t usedSpectrumBins = binCount * mutationTypeCount;\n\t\n\t// allocate our bins\n\tif (!spectrum || (spectrumBins < usedSpectrumBins))\n\t{\n\t\tspectrumBins = usedSpectrumBins;\n\t\tspectrum = (uint32_t *)realloc(spectrum, spectrumBins * sizeof(uint32_t));\n\t\tdoubleSpectrum = (double *)realloc(doubleSpectrum, spectrumBins * sizeof(double));\n\t}\n\t\n\t// clear our bins\n\tfor (unsigned int i = 0; i < usedSpectrumBins; ++i)\n\t\tspectrum[i] = 0;\n\t\n\t// tally into our bins\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\t\n\tpop.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\t// update tallies; usually this will just use the cache set up by Population::MaintainMutationRegistry()\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\tint registry_size;\n\tconst MutationIndex *registry = pop.MutationRegistry(&registry_size);\n\t\n\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t{\n\t\tconst Mutation *mutation = mut_block_ptr + registry[registry_index];\n\t\t\n\t\tChromosome *mut_chromosome = displaySpecies->Chromosomes()[mutation->chromosome_index_];\n\t\tslim_refcount_t mutationRefCount = *(refcount_block_ptr + mutation->BlockIndex());\n\t\tdouble mutationFrequency = mutationRefCount / mut_chromosome->total_haplosome_count_;\n\t\tint mutationBin = (int)floor(mutationFrequency * binCount);\n\t\tint mutationTypeIndex = mutation->mutation_type_ptr_->mutation_type_index_;\n\t\t\n\t\tif (mutationBin == binCount)\n\t\t\tmutationBin = binCount - 1;\n\t\t\n\t\t(spectrum[mutationTypeIndex + mutationBin * mutationTypeCount])++;\t// bins in sequence for each mutation type within one frequency bin, then again for the next frequency bin, etc.\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tuint32_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += spectrum[binIndex];\n\t\t}\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\tdoubleSpectrum[binIndex] = spectrum[binIndex] / (double)total;\n\t\t}\n\t}\n\t\n\t// return the final tally; note this is a pointer in to our static ivar, and must not be freed!\n\treturn doubleSpectrum;\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tint binCount = [self histogramBinCount];\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\tdouble *spectrum = [self mutationFrequencySpectrumWithController:controller mutationTypeCount:mutationTypeCount];\n\t\n\t// plot our histogram bars\n\t[self drawGroupedBarplotInInteriorRect:interiorRect withController:controller buffer:spectrum subBinCount:mutationTypeCount mainBinCount:binCount firstBinValue:0.0 mainBinWidth:(1.0 / binCount)];\n}\n\n- (NSArray *)legendKey\n{\n\treturn [self mutationTypeLegendKey];\t// we use the prefab mutation type legend\n}\n\n- (void)controllerSelectionChanged\n{\n\t[self setNeedsDisplay:YES];\n}\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller\n{\n\tNSMutableString *string = [NSMutableString stringWithString:@\"# Graph data: Mutation frequency spectrum\\n\"];\n\t\n\t[string appendString:[self dateline]];\n\t[string appendString:@\"\\n\\n\"];\n\t\n\tint binCount = [self histogramBinCount];\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\tdouble *plotData = [self mutationFrequencySpectrumWithController:controller mutationTypeCount:mutationTypeCount];\n\t\n\tfor (auto mutationTypeIter = displaySpecies->mutation_types_.begin(); mutationTypeIter != displaySpecies->mutation_types_.end(); ++mutationTypeIter)\n\t{\n\t\tMutationType *mutationType = (*mutationTypeIter).second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n\t\t[string appendFormat:@\"\\\"m%lld\\\", \", (long long int)mutationType->mutation_type_id_];\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n\t\t\t[string appendFormat:@\"%.4f, \", plotData[histIndex]];\n\t\t}\n\t\t\n\t\t[string appendString:@\"\\n\"];\n\t}\n\t\n\t// Get rid of extra commas\n\t[string replaceOccurrencesOfString:@\", \\n\" withString:@\"\\n\" options:0 range:NSMakeRange(0, [string length])];\n\t\n\treturn string;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFrequencyTrajectory.h",
    "content": "//\n//  GraphView_MutationFrequencyTrajectory.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots frequency trajectories over time of all of the individual mutations within a mutation type.\n \n */\n\n\n#import \"GraphView.h\"\n\n#include \"mutation.h\"\n#include \"mutation_type.h\"\n\n\n@class MutationFrequencyHistory;\n\n\n@interface GraphView_MutationFrequencyTrajectory : GraphView\n{\n\tNSMutableDictionary *frequencyHistoryDict;\t\t\t\t// dictionary of MutationFrequencyHistory objects with NSNumber (long long) keys\n\tNSMutableArray *frequencyHistoryColdStorageLost;\t\t// array of MutationFrequencyHistory objects that have been lost\n\tNSMutableArray *frequencyHistoryColdStorageFixed;\t\t// array of MutationFrequencyHistory objects that have been fixed\n\t\n\tNSPopUpButton *subpopulationButton;\n\tNSPopUpButton *mutationTypeButton;\n\t\n\tslim_tick_t lastTick;\t\t\t\t\t\t\t\t\t// the last tick data was gathered for; used to detect a backward move in time\n}\n\n// The subpop and mutation type selected; -1 indicates no current selection (which will be fixed as soon as the menu is populated)\n@property (nonatomic) slim_objectid_t selectedSubpopulationID;\n@property (nonatomic) int selectedMutationTypeIndex;\n@property (nonatomic) BOOL plotLostMutations;\n@property (nonatomic) BOOL plotFixedMutations;\n@property (nonatomic) BOOL plotActiveMutations;\n@property (nonatomic) BOOL useColorsForPlotting;\n\n- (NSPopUpButton *)addPopUpWithAction:(SEL)action;\n- (BOOL)addSubpopulationsToMenu;\n- (BOOL)addMutationTypesToMenu;\n- (void)setConstraintsForPopups;\n\n- (IBAction)subpopulationPopupChanged:(id)sender;\n- (IBAction)mutationTypePopupChanged:(id)sender;\n\n@end\n\n\n// We want to keep a history of frequency values for each mutation of the chosen mutation type in the\n// chosen subpopulation.  The history of a mutation should persist after it has vanished, and if a\n// new mutation object gets allocated at the same memory location, it should be treated as a distinct\n// mutation; so we can't use pointers to identify mutations.  Instead, we keep data on them using a\n// unique 64-bit ID generated only when SLiM is running under SLiMgui.  At the end of a tick,\n// we loop through all mutations in the registry, and add an entry for that mutation in our data store.\n// This is probably O(n^2), but so it goes.  It should only be used for mutation types that generate\n// few mutations; if somebody tries to plot every mutation in a common mutation-type, they will suffer.\n\n@interface MutationFrequencyHistory : NSObject\n{\n@public\n\t// The 64-bit mutation ID is how we keep track of the mutation we reference; its pointer might go stale and be reused.\n\tslim_mutationid_t mutationID;\n\t\n\t// Mostly we are just a malloced array of uint16s.  The data we're storing is doubles, conceptually, but to minimize our memory footprint\n\t// (which might be very large!) we convert the doubles, which are guaranteed to be in the range [0.0, 1.0], to uint16s in the range\n\t// [0, UINT16_MAX] (65535).  The buffer size is the number of entries allocated, the entry count is the number used so far, and the\n\t// base tick is the first tick recorded; the assumption is that entries are then sequential without gaps.\n\tint bufferSize, entryCount;\n\tslim_tick_t baseTick;\n\tuint16_t *entries;\n\t\n\t// Remember our mutation type so we can set our line color, etc., if we wish\n\tconst MutationType *mutationType;\n\t\n\t// Finally, we keep a flag that we use to figure out if our mutation is dead; if it is, we can be moved into cold storage.\n\tBOOL updated;\n}\n\n- (instancetype)initWithEntry:(uint16_t)value forMutation:(const Mutation *)mutation atBaseTick:(slim_tick_t)tick;\n- (void)addEntry:(uint16_t)value;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationFrequencyTrajectory.mm",
    "content": "//\n//  GraphView_MutationFrequencyTrajectory.m\n//  SLiM\n//\n//  Created by Ben Haller on 3/11/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_MutationFrequencyTrajectory.h\"\n#import \"SLiMWindowController.h\"\n\n#include \"community.h\"\n\n\n@implementation GraphView_MutationFrequencyTrajectory\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t//[self setXAxisRangeFromTick];\t// the end tick is not yet known\n\t\t\n\t\t[self setXAxisLabelString:@\"Tick\"];\n\t\t[self setYAxisLabelString:@\"Frequency\"];\n\t\t\n\t\t[self setAllowXAxisUserRescale:YES];\n\t\t[self setAllowYAxisUserRescale:YES];\n\t\t\n\t\t[self setShowHorizontalGridLines:YES];\n\t\t[self setTweakXAxisTickLabelAlignment:YES];\n\t\t\n\t\t// Start with no selected subpop or mutation-type; these will be set to the first menu item added when menus are constructed\n\t\t_selectedSubpopulationID = -1;\n\t\t_selectedMutationTypeIndex = -1;\n\t\t\n\t\t// Start plotting lost mutations, by default\n\t\t_plotLostMutations = YES;\n\t\t_plotFixedMutations = YES;\n\t\t_plotActiveMutations = YES;\n\t\t_useColorsForPlotting = YES;\n\t\t\n\t\t// Make our pop-up menu buttons\n\t\tsubpopulationButton = [self addPopUpWithAction:@selector(subpopulationPopupChanged:)];\n\t\tmutationTypeButton = [self addPopUpWithAction:@selector(mutationTypePopupChanged:)];\n\t\t\n\t\t[self addSubpopulationsToMenu];\n\t\t[self addMutationTypesToMenu];\n\t\t[self setConstraintsForPopups];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[self invalidateCachedData];\n\t\n\t[super dealloc];\n}\n\n- (NSPopUpButton *)addPopUpWithAction:(SEL)action\n{\n\tNSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(10, 10, 100, 47) pullsDown:NO];\n\t[popupButton setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeMini]]];\n\t[popupButton setControlSize:NSControlSizeMini];\n\t[popupButton setAutoenablesItems:NO];\n\t[popupButton setTarget:self];\n\t[popupButton setAction:action];\n\t\n\t[popupButton addItemWithTitle:@\"foo\"];\n\t\n\t// Resize the popup using its intrinsic size\n\t[popupButton sizeToFit];\n\t\n\tNSSize intrinsicSize = [popupButton intrinsicContentSize];\n\t[popupButton setFrame:NSMakeRect(10, 10, intrinsicSize.width, intrinsicSize.height)];\n\t[popupButton setTranslatesAutoresizingMaskIntoConstraints:NO];\n\t\n\t// Add the popup as a subview\n\t[self addSubview:[popupButton autorelease]];\n\t\n\treturn popupButton;\n}\n\n- (void)setConstraintsForPopups\n{\n\tNSDictionary *viewsDictionary = @{@\"subpopulationButton\" : subpopulationButton, @\"mutationTypeButton\" : mutationTypeButton};\n\t\n\t[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"|-6-[subpopulationButton]-6-[mutationTypeButton]\" options:0 metrics:nil views:viewsDictionary]];\n\t[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:[subpopulationButton]-6-|\" options:0 metrics:nil views:viewsDictionary]];\n\t[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@\"V:[mutationTypeButton]-6-|\" options:0 metrics:nil views:viewsDictionary]];\n}\n\n- (BOOL)addSubpopulationsToMenu\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tNSMenuItem *lastItem;\n\tslim_objectid_t firstTag = -1;\n\t\n\t// Depopulate and populate the menu\n\t[subpopulationButton removeAllItems];\n\n\tif (displaySpecies)\n\t{\n\t\tPopulation &population = displaySpecies->population_;\n\t\t\n\t\tfor (auto popIter = population.subpops_.begin(); popIter != population.subpops_.end(); ++popIter)\n\t\t{\n\t\t\tslim_objectid_t subpopID = popIter->first;\n\t\t\t//Subpopulation *subpop = popIter->second;\n\t\t\tNSString *subpopString = [NSString stringWithFormat:@\"p%lld\", (long long int)subpopID];\n\t\t\t\n\t\t\t[subpopulationButton addItemWithTitle:subpopString];\n\t\t\tlastItem = [subpopulationButton lastItem];\n\t\t\t[lastItem setTag:subpopID];\n\t\t\t\n\t\t\t// Remember the first item we add; we will use this item's tag to make a selection if needed\n\t\t\tif (firstTag == -1)\n\t\t\t\tfirstTag = subpopID;\n\t\t}\n\t}\n\t\n\t[subpopulationButton slimSortMenuItemsByTag];\n\t\n\t// If it is empty, disable it\n\tBOOL hasItems = ([subpopulationButton numberOfItems] >= 1);\n\t\n\t[subpopulationButton setEnabled:hasItems];\n\t\n\t// Fix the selection and then select the chosen subpopulation\n\tif (hasItems)\n\t{\n\t\tNSInteger indexOfTag = [subpopulationButton indexOfItemWithTag:[self selectedSubpopulationID]];\n\t\t\n\t\tif (indexOfTag == -1)\n\t\t\t[self setSelectedSubpopulationID:-1];\n\t\tif ([self selectedSubpopulationID] == -1)\n\t\t\t[self setSelectedSubpopulationID:firstTag];\n\t\t\n\t\t[subpopulationButton selectItemWithTag:[self selectedSubpopulationID]];\n\t\t[subpopulationButton synchronizeTitleAndSelectedItem];\n\t}\n\t\n\treturn hasItems;\t// YES if we found at least one subpop to add to the menu, NO otherwise\n}\n\n- (BOOL)addMutationTypesToMenu\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tNSMenuItem *lastItem;\n\tint firstTag = -1;\n\t\n\t// Depopulate and populate the menu\n\t[mutationTypeButton removeAllItems];\n\t\n\tif (displaySpecies)\n\t{\n\t\tstd::map<slim_objectid_t,MutationType*> &mutationTypes = displaySpecies->mutation_types_;\n\t\t\n\t\tfor (auto mutTypeIter = mutationTypes.begin(); mutTypeIter != mutationTypes.end(); ++mutTypeIter)\n\t\t{\n\t\t\tMutationType *mutationType = mutTypeIter->second;\n\t\t\tslim_objectid_t mutationTypeID = mutationType->mutation_type_id_;\n\t\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\n\t\t\tNSString *mutationTypeString = [NSString stringWithFormat:@\"m%lld\", (long long int)mutationTypeID];\n\t\t\t\n\t\t\t[mutationTypeButton addItemWithTitle:mutationTypeString];\n\t\t\tlastItem = [mutationTypeButton lastItem];\n\t\t\t[lastItem setTag:mutationTypeIndex];\n\t\t\t\n\t\t\t// Remember the first item we add; we will use this item's tag to make a selection if needed\n\t\t\tif (firstTag == -1)\n\t\t\t\tfirstTag = mutationTypeIndex;\n\t\t}\n\t}\n\t\n\t[mutationTypeButton slimSortMenuItemsByTag];\n\t\n\t// If it is empty, disable it\n\tBOOL hasItems = ([mutationTypeButton numberOfItems] >= 1);\n\t\n\t[mutationTypeButton setEnabled:hasItems];\n\t\n\t// Fix the selection and then select the chosen mutation type\n\tif (hasItems)\n\t{\n\t\tNSInteger indexOfTag = [mutationTypeButton indexOfItemWithTag:[self selectedMutationTypeIndex]];\n\t\t\n\t\tif (indexOfTag == -1)\n\t\t\t[self setSelectedMutationTypeIndex:-1];\n\t\tif ([self selectedMutationTypeIndex] == -1)\n\t\t\t[self setSelectedMutationTypeIndex:firstTag];\n\t\t\n\t\t[mutationTypeButton selectItemWithTag:[self selectedMutationTypeIndex]];\n\t\t[mutationTypeButton synchronizeTitleAndSelectedItem];\n\t}\n\t\n\treturn hasItems;\t// YES if we found at least one muttype to add to the menu, NO otherwise\n}\n\n- (void)invalidateCachedData\n{\n//\tSLiMWindowController *controller = [self slimWindowController];\n//\tSpecies &species = controller->community->single_species_;\n//\tslim_tick_t tick = community->Tick();\n//\t\n//\tNSLog(@\"-invalidateCachedData called at tick %d\", tick);\n\t\n\tif (frequencyHistoryDict)\n\t{\n\t\t[frequencyHistoryDict release];\n\t\tfrequencyHistoryDict = nil;\n\t}\n\t\n\tif (frequencyHistoryColdStorageLost)\n\t{\n\t\t[frequencyHistoryColdStorageLost release];\n\t\tfrequencyHistoryColdStorageLost = nil;\n\t}\n\t\n\tif (frequencyHistoryColdStorageFixed)\n\t{\n\t\t[frequencyHistoryColdStorageFixed release];\n\t\tfrequencyHistoryColdStorageFixed = nil;\n\t}\n}\n\n- (void)fetchDataForFinishedTick\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\tCommunity &community = *controller->community;\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (!displaySpecies)\n\t\treturn;\n\t\n\tPopulation &population = displaySpecies->population_;\n\tint registry_size;\n\tconst MutationIndex *registry = population.MutationRegistry(&registry_size);\n\tstatic BOOL alreadyHere = NO;\n\t\n\t// Check that the subpop we're supposed to be surveying exists; if not, bail.\n\tBOOL foundSelectedSubpop = NO;\n\tBOOL foundSelectedMutType = NO;\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population.subpops_)\n\t\tif (subpop_pair.first == _selectedSubpopulationID)\t// find our chosen subpop\n\t\t\tfoundSelectedSubpop = YES;\n\t\n\tfor (const std::pair<const slim_objectid_t,MutationType*> &subpop_pair : displaySpecies->mutation_types_)\n\t\tif (subpop_pair.second->mutation_type_index_ == _selectedMutationTypeIndex)\t// find our chosen muttype\n\t\t\tfoundSelectedMutType = YES;\n\t\n\t// Make sure we have a selected subpop if possible.  Our menu might not have been loaded, or our chosen subpop might have vanished.\n\tif ((_selectedSubpopulationID == -1) || !foundSelectedSubpop)\n\t{\n\t\t// Call -addSubpopulationsToMenu to reload our subpop menu and choose a subpop.  This will call us, so we use a static flag to prevent re-entrancy.\n\t\talreadyHere = YES;\n\t\tfoundSelectedSubpop = [self addSubpopulationsToMenu];\n\t\talreadyHere = NO;\n\t}\n\t\n\t// Make sure we have a selected muttype if possible.  Our menu might not have been loaded, or our chosen muttype might have vanished.\n\tif ((_selectedMutationTypeIndex == -1) || !foundSelectedMutType)\n\t{\n\t\t// Call -addMutationTypesToMenu to reload our muttype menu and choose a muttype.  This will call us, so we use a static flag to prevent re-entrancy.\n\t\talreadyHere = YES;\n\t\tfoundSelectedMutType = [self addMutationTypesToMenu];\n\t\talreadyHere = NO;\n\t}\n\t\n\tif (!foundSelectedSubpop || !foundSelectedMutType)\n\t\treturn;\n\t\n\tif (!frequencyHistoryDict)\n\t\tfrequencyHistoryDict = [[NSMutableDictionary alloc] init];\n\tif (!frequencyHistoryColdStorageLost)\n\t\tfrequencyHistoryColdStorageLost = [[NSMutableArray alloc] init];\n\tif (!frequencyHistoryColdStorageFixed)\n\t\tfrequencyHistoryColdStorageFixed = [[NSMutableArray alloc] init];\n\n\t// Start by zeroing out the \"updated\" flags; this is how we find dead mutations\n\t[frequencyHistoryDict enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, MutationFrequencyHistory *history, BOOL *stop) {\n\t\thistory->updated = NO;\n\t}];\n\t\n\t//\n\t// this code is a slightly modified clone of the code in Population::TallyMutationReferences; here we scan only the\n\t// subpopulation that is being displayed in this graph, and tally into gui_scratch_reference_count only\n\t// BCH 4/21/2023: This could use mutrun use counts to run faster...\n\t//\n\tint haplosome_count_per_individual = displaySpecies->HaplosomeCountPerIndividual();\n\tint subpop_total_haplosome_count = 0;\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tconst MutationIndex *registry_iter = registry;\n\tconst MutationIndex *registry_iter_end = registry + registry_size;\n\t\n\tfor (; registry_iter != registry_iter_end; ++registry_iter)\n\t\t(mut_block_ptr + *registry_iter)->gui_scratch_reference_count_ = 0;\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population.subpops_)\n\t{\n\t\tif (subpop_pair.first == _selectedSubpopulationID)\t// tally only within our chosen subpop\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\tconst MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst Mutation *mutation = mut_block_ptr + *haplosome_iter;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (mutation->mutation_type_ptr_->mutation_type_index_ == _selectedMutationTypeIndex)\n\t\t\t\t\t\t\t\t\t(mutation->gui_scratch_reference_count_)++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpop_total_haplosome_count++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Now we can run through the mutations and use the tallies in gui_scratch_reference_count to update our histories\n\tfor (registry_iter = registry; registry_iter != registry_iter_end; ++registry_iter)\n\t{\n\t\tconst Mutation *mutation = mut_block_ptr + *registry_iter;\n\t\tslim_refcount_t refcount = mutation->gui_scratch_reference_count_;\n\t\t\n\t\tif (refcount)\n\t\t{\n\t\t\tuint16_t value = (uint16_t)((refcount * (unsigned long long)UINT16_MAX) / subpop_total_haplosome_count);\t// FIXME static analyzer says potential divide by zero here\n\t\t\tNSNumber *mutationIDNumber = [[NSNumber alloc] initWithLongLong:mutation->mutation_id_];\n\t\t\tMutationFrequencyHistory *history = [frequencyHistoryDict objectForKey:mutationIDNumber];\n\t\t\t\n\t\t\t//NSLog(@\"mutation refcount %d has uint16_t value %d, found history %p for id %lld\", refcount, value, history, (long long int)(mutation->mutation_id_));\n\t\t\t\n\t\t\tif (history)\n\t\t\t{\n\t\t\t\t// We have a history for this mutation, so we just need to add an entry; this sets the updated flag\n\t\t\t\t[history addEntry:value];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// No history, so we make one starting at this tick; this also sets the updated flag\n\t\t\t\t// Note we use Tick() - 1, because the tick counter has already been advanced to the next tick\n\t\t\t\thistory = [[MutationFrequencyHistory alloc] initWithEntry:value forMutation:mutation atBaseTick:community.Tick() - 1];\n\t\t\t\t\n\t\t\t\t[frequencyHistoryDict setObject:history forKey:mutationIDNumber];\n\t\t\t\t[history release];\n\t\t\t}\n\t\t\t\n\t\t\t[mutationIDNumber release];\n\t\t}\n\t}\n\t\n\t// OK, now every mutation that has frequency >0 in our subpop has got a current entry.  But what about mutations that used to circulate,\n\t// but don't any more?  These could still be active in a different subpop, or they might be gone – lost or fixed.  For the former case,\n\t// we need to add an entry with frequency zero.  For the latter case, we need to put their history into \"cold storage\" for efficiency.\n\t__block NSMutableDictionary *historiesToAddToColdStorage = nil;\n\t\n\t[frequencyHistoryDict enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, MutationFrequencyHistory *history, BOOL *stop) {\n\t\tif (!history->updated)\n\t\t{\n\t\t\tslim_mutationid_t historyID = history->mutationID;\n\t\t\tconst MutationIndex *mutation_iter = registry;\n\t\t\tconst MutationIndex *mutation_iter_end = registry + registry_size;\n\t\t\tBOOL mutationStillExists = NO;\n\t\t\t\n\t\t\tfor ( ; mutation_iter != mutation_iter_end; ++mutation_iter)\n\t\t\t{\n\t\t\t\tconst Mutation *mutation = mut_block_ptr + *mutation_iter;\n\t\t\t\tslim_mutationid_t mutationID = mutation->mutation_id_;\n\t\t\t\t\n\t\t\t\tif (historyID == mutationID)\n\t\t\t\t{\n\t\t\t\t\tmutationStillExists = YES;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (mutationStillExists)\n\t\t\t{\n\t\t\t\t// The mutation is still around, so just add a zero entry for it\n\t\t\t\t[history addEntry:0];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The mutation is gone, so we need to put its history into cold storage, but we can't modify\n\t\t\t\t// our dictionary since we are enumerating it, so we just make a record and do it below\n\t\t\t\tif (historiesToAddToColdStorage)\n\t\t\t\t\t[historiesToAddToColdStorage setObject:history forKey:key];\n\t\t\t\telse\n\t\t\t\t\thistoriesToAddToColdStorage = [[NSMutableDictionary alloc] initWithObjectsAndKeys:history, key, nil];\n\t\t\t}\n\t\t}\n\t}];\n\t\n\t// Now, if historiesToAddToColdStorage is non-nil, we have histories to put into cold storage; do it now\n\tif (historiesToAddToColdStorage)\n\t{\n\t\t[historiesToAddToColdStorage enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, MutationFrequencyHistory *history, BOOL *stop) {\n\t\t\t// The remaining tricky bit is that we have to figure out whether the vanished mutation was fixed or lost; we do this by\n\t\t\t// scanning through all our Substitution objects, which use the same unique IDs as Mutations use.  We need to know this\n\t\t\t// for two reasons: to add the final entry for the mutation, and to put it into the correct cold storage array.\n\t\t\tslim_mutationid_t mutationID = history->mutationID;\n\t\t\tBOOL wasFixed = NO;\n\t\t\t\n\t\t\tstd::vector<Substitution*> &substitutions = population.substitutions_;\n\t\t\t\n\t\t\tfor (const Substitution *substitution : substitutions)\n\t\t\t{\n\t\t\t\tif (substitution->mutation_id_ == mutationID)\n\t\t\t\t{\n\t\t\t\t\twasFixed = YES;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (wasFixed)\n\t\t\t{\n\t\t\t\t[history addEntry:UINT16_MAX];\n\t\t\t\t[frequencyHistoryColdStorageFixed addObject:history];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[history addEntry:0];\n\t\t\t\t[frequencyHistoryColdStorageLost addObject:history];\n\t\t\t}\n\t\t\t\n\t\t\t[frequencyHistoryDict removeObjectForKey:key];\n\t\t}];\n\t\t[historiesToAddToColdStorage release];\n\t}\n\t\n\t//NSLog(@\"frequencyHistoryDict has %lld entries, frequencyHistoryColdStorageLost has %lld entries, frequencyHistoryColdStorageFixed has %lld entries\", (long long int)[frequencyHistoryDict count], (long long int)[frequencyHistoryColdStorageLost count], (long long int)[frequencyHistoryColdStorageFixed count]);\n\t\n\tlastTick = community.Tick();\n}\n\n- (void)setSelectedSubpopulationID:(slim_objectid_t)newID\n{\n\tif (_selectedSubpopulationID != newID)\n\t{\n\t\t_selectedSubpopulationID = newID;\n\t\t\n\t\t[self invalidateCachedData];\n\t\t[self fetchDataForFinishedTick];\n\t\t[self setNeedsDisplay:YES];\n\t}\n}\n\n- (void)setSelectedMutationTypeIndex:(int)newIndex\n{\n\tif (_selectedMutationTypeIndex != newIndex)\n\t{\n\t\t_selectedMutationTypeIndex = newIndex;\n\t\t\n\t\t[self invalidateCachedData];\n\t\t[self fetchDataForFinishedTick];\n\t\t[self setNeedsDisplay:YES];\n\t}\n}\n\n- (IBAction)subpopulationPopupChanged:(id)sender\n{\n\t[self setSelectedSubpopulationID:SLiMClampToObjectidType([subpopulationButton selectedTag])];\n}\n\n- (IBAction)mutationTypePopupChanged:(id)sender\n{\n\t[self setSelectedMutationTypeIndex:(int)[mutationTypeButton selectedTag]];\n}\n\n- (void)controllerRecycled\n{\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (![controller invalidSimulation])\n\t{\n\t\t//if (![self xAxisIsUserRescaled])\n\t\t//\t[self setXAxisRangeFromTick];\t// the end tick is not yet known\n\t\t\n\t\t[self setNeedsDisplay:YES];\n\t}\n\t\n\t// Remake our popups, whether or not the controller is valid\n\t[self invalidateCachedData];\n\t[self addSubpopulationsToMenu];\n\t[self addMutationTypesToMenu];\n\t\n\t[super controllerRecycled];\n}\n\n- (void)controllerTickFinished\n{\n\t[super controllerTickFinished];\n\t\n\t// Check for an unexpected change in tick, in which case we invalidate all our histories and start over\n\tSLiMWindowController *controller = [self slimWindowController];\n\tCommunity *community = controller->community;\n\t\n\tif (lastTick != community->Tick() - 1)\n\t{\n\t\t[self invalidateCachedData];\n\t\t[self setNeedsDisplay:YES];\n\t}\n\t\n\t// Fetch and store the frequencies for all mutations of the selected mutation type(s), within the subpopulation selected\n\t[self fetchDataForFinishedTick];\n}\n\n- (void)updateAfterTick\n{\n\t// BCH 3/20/2024: We set the x axis range each tick, because the end tick is now invalid until after initialize() callbacks\n\tif (![self xAxisIsUserRescaled])\n\t\t[self setXAxisRangeFromTick];\n\t\n\t// Rebuild the subpop and muttype menus; this has the side effect of checking and fixing our selections, and that,\n\t// in turn, will have the side effect of invaliding our cache and fetching new data if needed\n\t[self addSubpopulationsToMenu];\n\t[self addMutationTypesToMenu];\n\t\n\t[super updateAfterTick];\n}\n\n- (void)drawHistory:(MutationFrequencyHistory *)history inInteriorRect:(NSRect)interiorRect\n{\n\tint entryCount = history->entryCount;\n\t\n\tif (entryCount > 1)\t\t// one entry just generates a moveto\n\t{\n\t\tuint16_t *entries = history->entries;\n\t\tNSBezierPath *linePath = [NSBezierPath bezierPath];\n\t\tuint16_t firstValue = *entries;\n\t\tdouble firstFrequency = ((double)firstValue) / UINT16_MAX;\n\t\tslim_tick_t tick = history->baseTick;\n\t\tNSPoint firstPoint = NSMakePoint([self plotToDeviceX:tick withInteriorRect:interiorRect], [self plotToDeviceY:firstFrequency withInteriorRect:interiorRect]);\n\t\t\n\t\t[linePath moveToPoint:firstPoint];\n\t\t\n\t\tfor (int entryIndex = 1; entryIndex < entryCount; ++entryIndex)\n\t\t{\n\t\t\tuint16_t value = entries[entryIndex];\n\t\t\tdouble frequency = ((double)value) / UINT16_MAX;\n\t\t\tNSPoint nextPoint = NSMakePoint([self plotToDeviceX:++tick withInteriorRect:interiorRect], [self plotToDeviceY:frequency withInteriorRect:interiorRect]);\n\t\t\t\n\t\t\t[linePath lineToPoint:nextPoint];\n\t\t}\n\t\t\n\t\t[linePath setLineWidth:1.0];\n\t\t[linePath stroke];\n\t}\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tBOOL plotInColor = [self useColorsForPlotting];\n\t\n\tif (!plotInColor)\n\t\t[[NSColor blackColor] set];\n\t\n\t// Go through all our history entries and draw a line for each.  First we draw the ones in cold storage, then the active ones.\n\tif ([self plotLostMutations])\n\t{\n\t\tif (plotInColor)\n\t\t\t[[NSColor redColor] set];\n\t\t\n\t\t[frequencyHistoryColdStorageLost enumerateObjectsUsingBlock:^(MutationFrequencyHistory *history, NSUInteger idx, BOOL *stop) {\n\t\t\t[self drawHistory:history inInteriorRect:interiorRect];\n\t\t}];\n\t}\n\t\n\tif ([self plotFixedMutations])\n\t{\n\t\tif (plotInColor)\n\t\t\t[[NSColor colorWithCalibratedRed:0.4 green:0.4 blue:1.0 alpha:1.0] set];\n\t\t\n\t\t[frequencyHistoryColdStorageFixed enumerateObjectsUsingBlock:^(MutationFrequencyHistory *history, NSUInteger idx, BOOL *stop) {\n\t\t\t[self drawHistory:history inInteriorRect:interiorRect];\n\t\t}];\n\t}\n\t\n\tif ([self plotActiveMutations])\n\t{\n\t\tif (plotInColor)\n\t\t\t[[NSColor blackColor] set];\n\t\t\n\t\t[frequencyHistoryDict enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, MutationFrequencyHistory *history, BOOL *stop) {\n\t\t\t[self drawHistory:history inInteriorRect:interiorRect];\n\t\t}];\n\t}\n}\n\n- (IBAction)toggleShowLostMutations:(id)sender\n{\n\t[self setPlotLostMutations:![self plotLostMutations]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleShowFixedMutations:(id)sender\n{\n\t[self setPlotFixedMutations:![self plotFixedMutations]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleShowActiveMutations:(id)sender\n{\n\t[self setPlotActiveMutations:![self plotActiveMutations]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)toggleUseColorsForPlotting:(id)sender\n{\n\t[self setUseColorsForPlotting:![self useColorsForPlotting]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (IBAction)copy:(id)sender\n{\n\t// Hide our popups around the call to super, so they don't appear in the snapshot\n\t[subpopulationButton setHidden:YES];\n\t[mutationTypeButton setHidden:YES];\n\t\n\t[super copy:sender];\n\t\n\t[subpopulationButton setHidden:NO];\n\t[mutationTypeButton setHidden:NO];\n}\n\n- (IBAction)saveGraph:(id)sender\n{\n\t// Hide our popups around the call to super, so they don't appear in the snapshot\n\t[subpopulationButton setHidden:YES];\n\t[mutationTypeButton setHidden:YES];\n\t\n\t[super saveGraph:sender];\n\t\n\t[subpopulationButton setHidden:NO];\n\t[mutationTypeButton setHidden:NO];\n}\n\n- (void)subclassAddItemsToMenu:(NSMenu *)menu forEvent:(NSEvent *)theEvent\n{\n\tif (menu)\n\t{\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self plotLostMutations] ? @\"Hide Lost Mutations\" : @\"Show Lost Mutations\") action:@selector(toggleShowLostMutations:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t\t\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self plotFixedMutations] ? @\"Hide Fixed Mutations\" : @\"Show Fixed Mutations\") action:@selector(toggleShowFixedMutations:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t\t\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self plotActiveMutations] ? @\"Hide Active Mutations\" : @\"Show Active Mutations\") action:@selector(toggleShowActiveMutations:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t\t\n\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\t\n\t\t{\n\t\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self useColorsForPlotting] ? @\"Black Plot Lines\" : @\"Colored Plot Lines\") action:@selector(toggleUseColorsForPlotting:) keyEquivalent:@\"\"];\n\t\t\t\n\t\t\t[menuItem setTarget:self];\n\t\t}\n\t}\n}\n\n- (NSArray *)legendKey\n{\n\tif ([self useColorsForPlotting])\n\t{\n\t\tNSMutableArray *legendKey = [NSMutableArray array];\n\t\t\n\t\tif ([self plotLostMutations])\n\t\t\t[legendKey addObject:@[@\"lost\", [NSColor redColor]]];\n\t\t\n\t\tif ([self plotFixedMutations])\n\t\t\t[legendKey addObject:@[@\"fixed\", [NSColor colorWithCalibratedRed:0.4 green:0.4 blue:1.0 alpha:1.0]]];\n\t\t\n\t\tif ([self plotActiveMutations])\n\t\t\t[legendKey addObject:@[@\"active\", [NSColor blackColor]]];\n\t\t\n\t\treturn legendKey;\n\t}\n\t\n\treturn nil;\n}\n\n- (void)appendEntriesFromArray:(NSArray *)array toString:(NSMutableString *)string completedTicks:(slim_tick_t)completedTicks\n{\n\t[array enumerateObjectsUsingBlock:^(MutationFrequencyHistory *history, NSUInteger idx, BOOL *stop) {\n\t\tint entryCount = history->entryCount;\n\t\tslim_tick_t baseTick = history->baseTick;\n\t\t\n\t\tfor (slim_tick_t tick = 1; tick <= completedTicks; ++tick)\n\t\t{\n\t\t\tif (tick < baseTick)\n\t\t\t\t[string appendString:@\"NA, \"];\n\t\t\telse if (tick - baseTick < entryCount)\n\t\t\t\t[string appendFormat:@\"%.4f, \", ((double)history->entries[tick - baseTick]) / UINT16_MAX];\n\t\t\telse\n\t\t\t\t[string appendString:@\"NA, \"];\n\t\t}\n\t\t\n\t\t[string appendString:@\"\\n\"];\n\t}];\n}\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller\n{\n\tNSMutableString *string = [NSMutableString stringWithString:@\"# Graph data: fitness trajectories\\n\"];\n\tslim_tick_t completedTicks = controller->community->Tick() - 1;\n\t\n\t[string appendString:[self dateline]];\n\t\n\tif ([self plotLostMutations])\n\t{\n\t\t[string appendString:@\"\\n\\n# Lost mutations:\\n\"];\n\t\t[self appendEntriesFromArray:frequencyHistoryColdStorageLost toString:string completedTicks:completedTicks];\n\t}\n\t\n\tif ([self plotFixedMutations])\n\t{\n\t\t[string appendString:@\"\\n\\n# Fixed mutations:\\n\"];\n\t\t[self appendEntriesFromArray:frequencyHistoryColdStorageFixed toString:string completedTicks:completedTicks];\n\t}\n\t\n\tif ([self plotActiveMutations])\n\t{\n\t\t[string appendString:@\"\\n\\n# Active mutations:\\n\"];\n\t\t[self appendEntriesFromArray:[frequencyHistoryDict allValues] toString:string completedTicks:completedTicks];\n\t}\n\t\n\t// Get rid of extra commas\n\t[string replaceOccurrencesOfString:@\", \\n\" withString:@\"\\n\" options:0 range:NSMakeRange(0, [string length])];\n\t\n\treturn string;\n}\n\n@end\n\n\n@implementation MutationFrequencyHistory\n\n- (instancetype)initWithEntry:(uint16_t)value forMutation:(const Mutation *)mutation atBaseTick:(slim_tick_t)tick\n{\n\tif (self = [super init])\n\t{\n\t\tmutationID = mutation->mutation_id_;\n\t\tmutationType = mutation->mutation_type_ptr_;\n\t\tbaseTick = tick;\n\t\t\n\t\tbufferSize = 0;\n\t\tentryCount = 0;\n\t\t[self addEntry:value];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\tif (entries)\n\t{\n\t\tfree(entries);\n\t\tentries = NULL;\n\t\t\n\t\tbufferSize = 0;\n\t\tentryCount = 0;\n\t}\n\t\n\t[super dealloc];\n}\n\n- (void)addEntry:(uint16_t)value\n{\n\tif (entryCount == bufferSize)\n\t{\n\t\t// We need to expand\n\t\tbufferSize += 1024;\n\t\tentries = (uint16_t *)realloc(entries, bufferSize * sizeof(uint16_t));\n\t}\n\t\n\tentries[entryCount++] = value;\n\tupdated = YES;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationLossTimeHistogram.h",
    "content": "//\n//  GraphView_MutationLossTimeHistogram.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots a histogram of the distribution of times to loss of mutations.  The data is gathered by SLiM, so it is quite simple.\n \n */\n\n\n#import \"GraphView.h\"\n\n\n@interface GraphView_MutationLossTimeHistogram : GraphView\n{\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_MutationLossTimeHistogram.mm",
    "content": "//\n//  GraphView_MutationLossTimeHistogram.m\n//  SLiM\n//\n//  Created by Ben Haller on 3/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_MutationLossTimeHistogram.h\"\n#import \"SLiMWindowController.h\"\n\n\n@implementation GraphView_MutationLossTimeHistogram\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t[self setHistogramBinCount:10];\n\t\t//[self setAllowXAxisBinRescale:YES];\t// not supported yet\n\t\t\n\t\t[self setXAxisMax:100];\n\t\t[self setXAxisMajorTickInterval:20];\n\t\t[self setXAxisMinorTickInterval:10];\n\t\t[self setXAxisMajorTickModulus:2];\n\t\t[self setXAxisTickValuePrecision:0];\n\t\t\n\t\t[self setXAxisLabelString:@\"Mutation loss time\"];\n\t\t[self setYAxisLabelString:@\"Proportion of lost mutations\"];\n\t\t\n\t\t[self setAllowXAxisUserRescale:NO];\n\t\t[self setAllowYAxisUserRescale:YES];\n\t\t\n\t\t[self setShowHorizontalGridLines:YES];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (double *)lossTimeDataWithController:(SLiMWindowController *)controller\n{\n\tint binCount = [self histogramBinCount];\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\tslim_tick_t *histogram = displaySpecies->population_.mutation_loss_times_;\n\tint64_t histogramBins = (int64_t)displaySpecies->population_.mutation_loss_tick_slots_;\t// fewer than binCount * mutationTypeCount may exist\n\tstatic double *rebin = NULL;\n\tstatic uint32_t rebinBins = 0;\n\tuint32_t usedRebinBins = binCount * mutationTypeCount;\n\t\n\t// re-bin for display; use double, normalize, etc.\n\tif (!rebin || (rebinBins < usedRebinBins))\n\t{\n\t\trebinBins = usedRebinBins;\n\t\trebin = (double *)realloc(rebin, rebinBins * sizeof(double));\n\t}\n\t\n\tfor (unsigned int i = 0; i < usedRebinBins; ++i)\n\t\trebin[i] = 0.0;\n\t\n\tfor (int i = 0; i < binCount; ++i)\n\t{\n\t\tfor (int j = 0; j < mutationTypeCount; ++j)\n\t\t{\n\t\t\tint histIndex = j + i * mutationTypeCount;\n\t\t\t\n\t\t\tif (histIndex < histogramBins)\n\t\t\t\trebin[histIndex] += histogram[histIndex];\n\t\t}\n\t}\n\t\n\t// normalize within each mutation type\n\tfor (int mutationTypeIndex = 0; mutationTypeIndex < mutationTypeCount; ++mutationTypeIndex)\n\t{\n\t\tuint32_t total = 0;\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\ttotal += (int64_t)rebin[binIndex];\n\t\t}\n\t\t\n\t\tfor (int bin = 0; bin < binCount; ++bin)\n\t\t{\n\t\t\tint binIndex = mutationTypeIndex + bin * mutationTypeCount;\n\t\t\t\n\t\t\trebin[binIndex] /= (double)total;\n\t\t}\n\t}\n\t\n\treturn rebin;\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tdouble *plotData = [self lossTimeDataWithController:controller];\n\tint binCount = [self histogramBinCount];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\t\n\t// plot our histogram bars\n\t[self drawGroupedBarplotInInteriorRect:interiorRect withController:controller buffer:plotData subBinCount:mutationTypeCount mainBinCount:binCount firstBinValue:0.0 mainBinWidth:10.0];\n}\n\n- (NSArray *)legendKey\n{\n\treturn [self mutationTypeLegendKey];\t// we use the prefab mutation type legend\n}\n\n- (NSString *)stringForDataWithController:(SLiMWindowController *)controller\n{\n\tNSMutableString *string = [NSMutableString stringWithString:@\"# Graph data: Mutation loss time histogram\\n\"];\n\t\n\t[string appendString:[self dateline]];\n\t[string appendString:@\"\\n\\n\"];\n\t\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tdouble *plotData = [self lossTimeDataWithController:controller];\n\tint binCount = [self histogramBinCount];\n\tint mutationTypeCount = (int)displaySpecies->mutation_types_.size();\n\t\n\tfor (auto mutationTypeIter = displaySpecies->mutation_types_.begin(); mutationTypeIter != displaySpecies->mutation_types_.end(); ++mutationTypeIter)\n\t{\n\t\tMutationType *mutationType = (*mutationTypeIter).second;\n\t\tint mutationTypeIndex = mutationType->mutation_type_index_;\t\t// look up the index used for this mutation type in the history info; not necessarily sequential!\n\t\t\n\t\t[string appendFormat:@\"\\\"m%lld\\\", \", (long long int)mutationType->mutation_type_id_];\n\t\t\n\t\tfor (int i = 0; i < binCount; ++i)\n\t\t{\n\t\t\tint histIndex = mutationTypeIndex + i * mutationTypeCount;\n\t\t\t\n\t\t\t[string appendFormat:@\"%.4f, \", plotData[histIndex]];\n\t\t}\n\t\t\n\t\t[string appendString:@\"\\n\"];\n\t}\n\t\n\t// Get rid of extra commas\n\t[string replaceOccurrencesOfString:@\", \\n\" withString:@\"\\n\" options:0 range:NSMakeRange(0, [string length])];\n\t\n\treturn string;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_PopulationVisualization.h",
    "content": "//\n//  GraphView_PopulationVisualization.h\n//  SLiM\n//\n//  Created by Ben Haller on 3/3/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n \n This graph plots a visualization of all of the populations, their size, their average fitness, and the migration between them\n \n */\n\n\n#import \"GraphView.h\"\n\n\n@interface GraphView_PopulationVisualization : GraphView\n{\n}\n\n@property (nonatomic) BOOL optimizePositions;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/GraphView_PopulationVisualization.mm",
    "content": "//\n//  GraphView_PopulationVisualization.m\n//  SLiM\n//\n//  Created by Ben Haller on 3/3/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"GraphView_PopulationVisualization.h\"\n#import \"SLiMWindowController.h\"\n\n#include \"community.h\"\n\n\n@implementation GraphView_PopulationVisualization\n\n- (id)initWithFrame:(NSRect)frameRect withController:(SLiMWindowController *)controller\n{\n\tif (self = [super initWithFrame:frameRect withController:controller])\n\t{\n\t\t[self setShowXAxis:NO];\n\t\t[self setShowYAxis:NO];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (NSRect)rectForSubpop:(Subpopulation *)subpop centeredAt:(NSPoint)center\n{\n\t// figure out the right radius, clamped to reasonable limits\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tslim_popsize_t clampedSubpopSize = subpopSize;\n\t\n\tif (clampedSubpopSize < 200)\n\t\tclampedSubpopSize = 200;\n\tif (clampedSubpopSize > 10000)\n\t\tclampedSubpopSize = 10000;\n\t\n\tdouble subpopRadius = sqrt(clampedSubpopSize) / 500;\t// size 10,000 has radius 0.2\n\t\n\tif (subpop->gui_radius_scaling_from_user_)\n\t\tsubpopRadius *= subpop->gui_radius_scaling_;\n\t\n\t// draw the circle\n\tNSRect subpopRect = NSMakeRect(center.x - subpopRadius, center.y - subpopRadius, 2.0 * subpopRadius, 2.0 * subpopRadius);\n\t\n\treturn subpopRect;\n}\n\n- (void)drawSubpop:(Subpopulation *)subpop withID:(slim_objectid_t)subpopID centeredAt:(NSPoint)center controller:(SLiMWindowController *)controller\n{\n\tstatic NSDictionary *blackLabelAttrs = nil, *whiteLabelAttrs = nil;\n\t\n\tif (!blackLabelAttrs)\n\t\tblackLabelAttrs = [@{NSFontAttributeName : [NSFont fontWithName:[GraphView labelFontName] size:0.04], NSForegroundColorAttributeName : [NSColor blackColor]} retain];\n\tif (!whiteLabelAttrs)\n\t\twhiteLabelAttrs = [@{NSFontAttributeName : [NSFont fontWithName:[GraphView labelFontName] size:0.04], NSForegroundColorAttributeName : [NSColor whiteColor]} retain];\n\t\n\t// figure out the right radius, clamped to reasonable limits\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tslim_popsize_t clampedSubpopSize = subpopSize;\n\t\n\tif (clampedSubpopSize < 200)\n\t\tclampedSubpopSize = 200;\n\tif (clampedSubpopSize > 10000)\n\t\tclampedSubpopSize = 10000;\n\t\n\tdouble subpopRadius = sqrt(clampedSubpopSize) / 500;\t// size 10,000 has radius 0.2\n\t\n\tif (subpop->gui_radius_scaling_from_user_)\n\t\tsubpopRadius *= subpop->gui_radius_scaling_;\n\t\n\tsubpop->gui_radius_ = subpopRadius;\n\t\n\t// determine the color\n\tfloat colorRed = 0.0, colorGreen = 0.0, colorBlue = 0.0;\n\t\n\tif (subpop->gui_color_from_user_)\n\t{\n\t\tcolorRed = subpop->gui_color_red_;\n\t\tcolorGreen = subpop->gui_color_green_;\n\t\tcolorBlue = subpop->gui_color_blue_;\n\t}\n\telse\n\t{\n\t\t// calculate the color from the mean fitness of the population\n\t\t// we normalize fitness values with subpopFitnessScaling so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\tconst double fitnessScalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\t\tdouble fitness = ((subpopSize == 0) ? -10000.0 : subpop->parental_mean_unscaled_fitness_);\n\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, fitnessScalingFactor);\n\t}\n\t\n\tNSColor *color = [NSColor colorWithDeviceRed:colorRed green:colorGreen blue:colorBlue alpha:1.0];\t// device, to match OpenGL\n\t\n\t// draw the circle\n\tNSRect subpopRect = NSMakeRect(center.x - subpopRadius, center.y - subpopRadius, 2.0 * subpopRadius, 2.0 * subpopRadius);\n\tNSBezierPath *subpopCircle = [NSBezierPath bezierPathWithOvalInRect:subpopRect];\n\t\n\t[color set];\n\t[subpopCircle fill];\n\t\n\t[[NSColor blackColor] set];\n\t[subpopCircle setLineWidth:0.002];\n\t[subpopCircle stroke];\n\t\n\t// label it with the subpopulation ID\n\tNSString *popString = [NSString stringWithFormat:@\"p%lld\", (long long int)subpopID];\n\tdouble brightness = 0.299 * colorRed + 0.587 * colorGreen + 0.114 * colorBlue;\n\tNSDictionary *labelAttrs;\n\tdouble scaling = 1.0;\n\t\n\tif (subpop->gui_radius_scaling_from_user_ && (subpop->gui_radius_scaling_ != 1.0))\n\t{\n\t\tscaling = subpop->gui_radius_scaling_;\n\t\tlabelAttrs = @{NSFontAttributeName : [NSFont fontWithName:[GraphView labelFontName] size:(0.04 * scaling)], NSForegroundColorAttributeName : ((brightness > 0.5) ? [NSColor blackColor] : [NSColor whiteColor])};\n\t}\n\telse\n\t{\n\t\tlabelAttrs = ((brightness > 0.5) ? blackLabelAttrs : whiteLabelAttrs);\n\t}\n\t\n\tNSAttributedString *popLabel = [[NSAttributedString alloc] initWithString:popString attributes:labelAttrs];\n\tNSSize labelSize = [popLabel size];\n\t\n\t// Note that labelSize.height seems to be clamped to a minimum of 1.0, although labelSize.width is not, which is odd; the math here seems to work...\n\tNSPoint drawPoint = NSMakePoint(center.x - labelSize.width / 2, center.y - labelSize.height - 0.008 * scaling);\n\t\n\t//NSLog(@\"center = %@\", NSStringFromPoint(center));\n\t//NSLog(@\"labelSize = %@\", NSStringFromSize(labelSize));\n\t//NSLog(@\"drawPoint = %@\", NSStringFromPoint(drawPoint));\n\t\n\t[popLabel drawAtPoint:drawPoint];\n\t[popLabel release];\n}\n\n- (void)drawArrowFromSubpop:(Subpopulation *)sourceSubpop toSubpop:(Subpopulation *)destSubpop migrantFraction:(double)migrantFraction\n{\n\tdouble destCenterX = destSubpop->gui_center_x_;\n\tdouble destCenterY = destSubpop->gui_center_y_;\n\tdouble sourceCenterX = sourceSubpop->gui_center_x_;\n\tdouble sourceCenterY = sourceSubpop->gui_center_y_;\n\t\n\t// we want to draw an arrow connecting these two subpops; first, we need to figure out the endpoints\n\t// they start and end a small fixed distance outside of the source/dest subpop circles\n\tdouble vectorDX = (destCenterX - sourceCenterX);\n\tdouble vectorDY = (destCenterY - sourceCenterY);\n\tdouble vectorLength = sqrt(vectorDX * vectorDX + vectorDY * vectorDY);\n\tdouble sourceEndWeight = (0.01 + sourceSubpop->gui_radius_) / vectorLength;\n\tdouble sourceEndX = sourceCenterX + (destCenterX - sourceCenterX) * sourceEndWeight;\n\tdouble sourceEndY = sourceCenterY + (destCenterY - sourceCenterY) * sourceEndWeight;\n\tdouble destEndWeight = (0.01 + destSubpop->gui_radius_) / vectorLength;\n\tdouble destEndX = destCenterX + (sourceCenterX - destCenterX) * destEndWeight;\n\tdouble destEndY = destCenterY + (sourceCenterY - destCenterY) * destEndWeight;\n\t\n\t// now, using those endpoints, we have a \"partial vector\" that goes from just outside the source subpop circle to\n\t// just outside the dest subpop circle; this partial vector will be the basis for the bezier that we draw, but we\n\t// need to calculate control points to make the bezier curve outward, using a perpendicular vector\n\tdouble partVecDX = destEndX - sourceEndX;\t// dx/dy for the partial vector from source to dest that we have just calculated\n\tdouble partVecDY = destEndY - sourceEndY;\n\tdouble partVecLength = sqrt(partVecDX * partVecDX + partVecDY * partVecDY);\t\t// the length of that partial vector\n\tdouble perpendicularFromSourceDX = partVecDY;\t\t// a vector perpendicular to that partial vector, by clockwise rotation\n\tdouble perpendicularFromSourceDY = -partVecDX;\n\tdouble controlPoint1X = sourceEndX + partVecDX * 0.3 + perpendicularFromSourceDX * 0.1;\n\tdouble controlPoint1Y = sourceEndY + partVecDY * 0.3 + perpendicularFromSourceDY * 0.1;\n\tdouble controlPoint2X = destEndX - partVecDX * 0.3 + perpendicularFromSourceDX * 0.1;\n\tdouble controlPoint2Y = destEndY - partVecDY * 0.3 + perpendicularFromSourceDY * 0.1;\n\t\n\t// now we figure out our line width, and we calculate a spatial translation of the bezier to shift in slightly off of\n\t// the midline, based on the line width, so that incoming and outgoing vectors do not overlap at the start/end points\n\tdouble lineWidth = 0.001 * (sqrt(migrantFraction) / 0.03);\t// non-linear line width scale\n\tdouble finalShiftMagnitude = MAX(lineWidth * 0.75, 0.010);\n\tdouble finalShiftX = perpendicularFromSourceDX * finalShiftMagnitude / partVecLength;\n\tdouble finalShiftY = perpendicularFromSourceDY * finalShiftMagnitude / partVecLength;\n\tdouble arrowheadSize = MAX(lineWidth * 1.5, 0.008);\n\t\n\t// we have to use a clipping path to cut back the destination end of the vector, to make room for the arrowhead\n\t[NSGraphicsContext saveGraphicsState];\n\t\n\tdouble clipRadius = vectorLength - (destSubpop->gui_radius_ + arrowheadSize + 0.01);\n\tNSRect clipCircle = NSMakeRect(sourceCenterX - clipRadius, sourceCenterY - clipRadius, clipRadius * 2, clipRadius * 2);\n\tNSBezierPath *clipBezier = [NSBezierPath bezierPathWithOvalInRect:clipCircle];\n\t\n//\t[[NSColor redColor] set];\n//\t[clipBezier setLineWidth:0.001];\n//\t[clipBezier stroke];\n\t[clipBezier addClip];\n\t\n\t// now draw the curved line connecting the subpops\n\tNSBezierPath *bezierLines = [NSBezierPath bezierPath];\n\tdouble shiftedSourceEndX = sourceEndX + finalShiftX, shiftedSourceEndY = sourceEndY + finalShiftY;\n\tdouble shiftedDestEndX = destEndX + finalShiftX, shiftedDestEndY = destEndY + finalShiftY;\n\tdouble shiftedControl1X = controlPoint1X + finalShiftX, shiftedControl1Y = controlPoint1Y + finalShiftY;\n\tdouble shiftedControl2X = controlPoint2X + finalShiftX, shiftedControl2Y = controlPoint2Y + finalShiftY;\n\t\n\t[bezierLines moveToPoint:NSMakePoint(shiftedSourceEndX, shiftedSourceEndY)];\n\t//[bezierLines lineToPoint:NSMakePoint(shiftedDestEndX, shiftedDestEndY)];\n\t[bezierLines curveToPoint:NSMakePoint(shiftedDestEndX, shiftedDestEndY)\n\t\t\t\tcontrolPoint1:NSMakePoint(shiftedControl1X, shiftedControl1Y)\n\t\t\t\tcontrolPoint2:NSMakePoint(shiftedControl2X, shiftedControl2Y)];\n\t\n\t[[NSColor blackColor] set];\n\t[bezierLines setLineWidth:lineWidth];\n\t[bezierLines stroke];\n\t\n\t// restore the clipping path\n\t[NSGraphicsContext restoreGraphicsState];\n\t\n\t// draw the arrowhead; this is oriented along the line from (shiftedDestEndX, shiftedDestEndY) to (shiftedControl2X, shiftedControl2Y),\n\t// of length partVecLength, and is calculated using a perpendicular off of that vector\n\tNSBezierPath *bezierArrowheads = [NSBezierPath bezierPath];\n\tdouble angleCorrectionFactor = (arrowheadSize / partVecLength) * 0.5;\t// large arrowheads need to be tilted closer to the source-dest pop line\n\t//NSLog(@\"angleCorrectionFactor == %f (arrowheadSize == %f, partVecLength == %f)\", angleCorrectionFactor, arrowheadSize, partVecLength);\n\tdouble headInsideX = shiftedControl2X * (1 - angleCorrectionFactor) + shiftedSourceEndX * angleCorrectionFactor;\n\tdouble headInsideY = shiftedControl2Y * (1 - angleCorrectionFactor) + shiftedSourceEndY * angleCorrectionFactor;\n\tdouble headMidlineDX = headInsideX - shiftedDestEndX, headMidlineDY = headInsideY - shiftedDestEndY;\n\tdouble headMidlineLength = sqrt(headMidlineDX * headMidlineDX + headMidlineDY * headMidlineDY);\n\tdouble headMidlineNormDX = (headMidlineDX / headMidlineLength) * arrowheadSize;\t\t\t\t\t// normalized to have length arrowheadSize\n\tdouble headMidlineNormDY = (headMidlineDY / headMidlineLength) * arrowheadSize;\n\tdouble headPerpendicular1DX = headMidlineNormDY, headPerpendicular1DY = -headMidlineNormDX;\t\t// perpendicular to the normalized midline\n\tdouble headPerpendicular2DX = -headMidlineNormDY, headPerpendicular2DY = headMidlineNormDX;\t\t// just the negation of perpendicular 1\n\t\n\t[bezierArrowheads moveToPoint:NSMakePoint(shiftedDestEndX, shiftedDestEndY)];\n\t[bezierArrowheads lineToPoint:NSMakePoint(shiftedDestEndX + headMidlineNormDX * 1.75 + headPerpendicular1DX * 0.9, shiftedDestEndY + headMidlineNormDY * 1.75 + headPerpendicular1DY * 0.9)];\n\t[bezierArrowheads lineToPoint:NSMakePoint(shiftedDestEndX + headMidlineNormDX * 1.2, shiftedDestEndY + headMidlineNormDY * 1.2)];\n\t[bezierArrowheads lineToPoint:NSMakePoint(shiftedDestEndX + headMidlineNormDX * 1.75 + headPerpendicular2DX * 0.9, shiftedDestEndY + headMidlineNormDY * 1.75 + headPerpendicular2DY * 0.9)];\n\t[bezierArrowheads closePath];\n\t\n\t[[NSColor blackColor] set];\n\t[bezierArrowheads fill];\n}\n\nBOOL is_line_intersection(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y);\nBOOL is_line_intersection(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y)\n{\n\tdouble s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom;\n\ts10_x = p1_x - p0_x;\n\ts10_y = p1_y - p0_y;\n\ts32_x = p3_x - p2_x;\n\ts32_y = p3_y - p2_y;\n\t\n\tdenom = s10_x * s32_y - s32_x * s10_y;\n\tif (denom == 0)\n\t\treturn FALSE; // Collinear\n\tbool denomPositive = denom > 0;\n\t\n\ts02_x = p0_x - p2_x;\n\ts02_y = p0_y - p2_y;\n\ts_numer = s10_x * s02_y - s10_y * s02_x;\n\tif ((s_numer < 0) == denomPositive)\n\t\treturn FALSE; // No collision\n\t\n\tt_numer = s32_x * s02_y - s32_y * s02_x;\n\tif ((t_numer < 0) == denomPositive)\n\t\treturn FALSE; // No collision\n\t\n\tif (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))\n\t\treturn FALSE; // No collision\n\t\n\treturn TRUE;\n}\n\n- (double)scorePositionsWithX:(double *)center_x y:(double *)center_y connected:(BOOL *)connected count:(int)subpopCount\n{\n\tdouble score = 0.0;\n\tdouble meanEdge = 0.0;\n\tint edgeCount = 0;\n\tdouble minx = INFINITY, maxy = -INFINITY;\n\t\n\t// First we calculate the mean edge length; we will consider this the optimum length\n\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tdouble x = center_x[subpopIndex];\n\t\tdouble y = center_y[subpopIndex];\n\t\t\n\t\t// If any node has a NaN value, that is an immediate disqualifier; I'm not sure how it happens, but it occasionally does\n\t\tif (isnan(x) || isnan(y))\n\t\t\treturn -100000000;\n\t\t\n\t\tif (x < minx) minx = x;\n\t\tif (y > maxy) maxy = y;\n\t\t\n\t\tfor (int sourceIndex = subpopIndex + 1; sourceIndex < subpopCount; ++sourceIndex)\n\t\t{\n\t\t\tif (connected[subpopIndex * subpopCount + sourceIndex])\n\t\t\t{\n\t\t\t\tdouble dx = x - center_x[sourceIndex];\n\t\t\t\tdouble dy = y - center_y[sourceIndex];\n\t\t\t\tdouble distanceSquared = dx * dx + dy * dy;\n\t\t\t\tdouble distance = sqrt(distanceSquared);\n\t\t\t\t\n\t\t\t\tmeanEdge += distance;\n\t\t\t\tedgeCount++;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tmeanEdge /= edgeCount;\n\t\n\t// Add a little score if the first subpop is near the upper left\n\tif ((fabs(center_x[0] - minx) < 0.05) && (fabs(center_y[0] - maxy) < 0.05))\n\t{\n\t\tscore += 0.01;\n\t\t\n\t\t// Add a little more score if the second subpop is to its right in roughly the same row\n\t\tif ((center_x[1] - center_x[0] > meanEdge/2) && (fabs(center_y[0] - center_y[1]) < 0.05))\n\t\t\tscore += 0.01;\n\t}\n\t\n\t// Score distances and crossings\n\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tdouble x = center_x[subpopIndex];\n\t\tdouble y = center_y[subpopIndex];\n\t\t\n\t\tfor (int sourceIndex = subpopIndex + 1; sourceIndex < subpopCount; ++sourceIndex)\n\t\t{\n\t\t\tdouble dx = x - center_x[sourceIndex];\n\t\t\tdouble dy = y - center_y[sourceIndex];\n\t\t\tdouble distanceSquared = dx * dx + dy * dy;\n\t\t\tdouble distance = sqrt(distanceSquared);\n\t\t\t\n\t\t\t// being closer than k invokes a penalty\n\t\t\tif (distance < meanEdge)\n\t\t\t\tscore -= (meanEdge - distance);\n\t\t\t\n\t\t\t// on the other hand, distance between connected subpops is very bad; this is above all what we want to optimize\n\t\t\tif (connected[subpopIndex * subpopCount + sourceIndex])\n\t\t\t{\n\t\t\t\tif (distance > meanEdge)\n\t\t\t\t\tscore -= (distance - meanEdge);\n\t\t\t\t\n\t\t\t\t// Detect crossings\n\t\t\t\tfor (int secondSubpop = subpopIndex + 1; secondSubpop < subpopCount; ++secondSubpop)\n\t\t\t\t\tfor (int secondSource = secondSubpop + 1; secondSource < subpopCount; ++secondSource)\n\t\t\t\t\t\tif (connected[secondSubpop * subpopCount + secondSource])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble x0 = x, x1 = center_x[sourceIndex], x2 = center_x[secondSubpop], x3 = center_x[secondSource];\n\t\t\t\t\t\t\tdouble y0 = y, y1 = center_y[sourceIndex], y2 = center_y[secondSubpop], y3 = center_y[secondSource];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// I test intersection with slightly shortened line segments, because I don't want endpoints that touch to be marked as intersections\n\t\t\t\t\t\t\tif (is_line_intersection(x0*0.99 + x1*0.01, y0*0.99 + y1*0.01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x0*0.01 + x1*0.99, y0*0.01 + y1*0.99,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x2*0.99 + x3*0.01, y2*0.99 + y3*0.01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t x2*0.01 + x3*0.99, y2*0.01 + y3*0.99))\n\t\t\t\t\t\t\t\tscore -= 100;\n\t\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn score;\n}\n\n// This is a simple implementation of the algorithm of Fruchterman and Reingold 1991;\n// there are better algorithms out there, but this one is simple...\n- (void)optimizeSubpopPositionsWithController:(SLiMWindowController *)controller\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tint subpopCount = (int)pop.subpops_.size();\n\t\n\tif (subpopCount == 0)\n\t\treturn;\n\t\n\tdouble width = 0.58, length = 0.58;\t\t// allows for the radii of the vertices at max subpop size\n\tdouble area = width * length;\n\tdouble k = sqrt(area / subpopCount);\n\tdouble kSquared = k * k;\n\tBOOL *connected;\n\t\n\tconnected = (BOOL *)calloc(subpopCount * subpopCount, sizeof(BOOL));\n\t\n\t// We start by figuring out connectivity\n\tauto subpopIter = pop.subpops_.begin();\n\t\n\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,double> &fractions_pair : subpop->migrant_fractions_)\n\t\t{\n\t\t\tslim_objectid_t migrant_source_id = fractions_pair.first;\n\t\t\t\n\t\t\t// We need to get from the source ID to the index of the source subpop in the pop array\n\t\t\tauto sourceIter = pop.subpops_.begin();\n\t\t\tint sourceIndex;\n\t\t\t\n\t\t\tfor (sourceIndex = 0; sourceIndex < subpopCount; ++sourceIndex)\n\t\t\t{\n\t\t\t\tif ((*sourceIter).first == migrant_source_id)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t++sourceIter;\n\t\t\t}\n\t\t\t\n\t\t\tif (sourceIndex == subpopCount)\n\t\t\t{\n\t\t\t\tfree(connected);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t// Mark the connection bidirectionally\n\t\t\tconnected[subpopIndex * subpopCount + sourceIndex] = YES;\n\t\t\tconnected[sourceIndex * subpopCount + subpopIndex] = YES;\n\t\t}\n\t\t\n\t\t++subpopIter;\n\t}\n\t\n\tdouble *pos_x, *pos_y;\t\t// vertex positions\n\tdouble *disp_x, *disp_y;\t// vertex forces/displacements\n\tdouble *best_x, *best_y;\t// best vertex positions from multiple runs\n\tdouble best_score = -INFINITY;\n\t\n\tpos_x = (double *)malloc(sizeof(double) * subpopCount);\n\tpos_y = (double *)malloc(sizeof(double) * subpopCount);\n\tdisp_x = (double *)malloc(sizeof(double) * subpopCount);\n\tdisp_y = (double *)malloc(sizeof(double) * subpopCount);\n\tbest_x = (double *)malloc(sizeof(double) * subpopCount);\n\tbest_y = (double *)malloc(sizeof(double) * subpopCount);\n\t\n\t// We do multiple separate runs from different starting configurations, to try to find the optimal solution\n\tfor (int trialIteration = 0; trialIteration < 50; ++trialIteration)\n\t{\n\t\tdouble temperature = width / 5.0;\n\t\t\n\t\t// initialize positions; this is basically the G := (V,E) step of the Fruchterman & Reingold algorithm\n\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t{\n\t\t\tpos_x[subpopIndex] = (random() / (double)INT32_MAX) * width - width/2;\n\t\t\tpos_y[subpopIndex] = (random() / (double)INT32_MAX) * length - length/2;\n\t\t}\n\t\t\n\t\t// Then we do the core loop of the Fruchterman & Reingold algorithm, which calculates forces and displacements\n\t\tfor (int optimizeIteration = 1; optimizeIteration < 1000; ++optimizeIteration)\n\t\t{\n\t\t\t// Calculate repulsive forces\n\t\t\tfor (int v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tdisp_x[v] = 0.0;\n\t\t\t\tdisp_y[v] = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int u = 0; u < subpopCount; ++u)\n\t\t\t\t{\n\t\t\t\t\tif (u != v)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble delta_x = pos_x[v] - pos_x[u];\n\t\t\t\t\t\tdouble delta_y = pos_y[v] - pos_y[u];\n\t\t\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\t\t\tdouble multiplier = kSquared / delta_magnitude_squared;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// This is a speed-optimized version of the pseudocode version commented out below\n\t\t\t\t\t\tdisp_x[v] += delta_x * multiplier;\n\t\t\t\t\t\tdisp_y[v] += delta_y * multiplier;\n\t\t\t\t\t\t\n\t\t\t\t\t\t//double delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\t\t\n\t\t\t\t\t\t//disp_x[v] += (delta_x / delta_magnitude) * (kSquared / delta_magnitude);\n\t\t\t\t\t\t//disp_y[v] += (delta_y / delta_magnitude) * (kSquared / delta_magnitude);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Calculate attractive forces\n\t\t\tfor (int v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tfor (int u = v + 1; u < subpopCount; ++u)\n\t\t\t\t{\n\t\t\t\t\tif (connected[v * subpopCount + u])\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is an edge between u and v\n\t\t\t\t\t\tdouble delta_x = pos_x[v] - pos_x[u];\n\t\t\t\t\t\tdouble delta_y = pos_y[v] - pos_y[u];\n\t\t\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\t\t\tdouble delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\t\tdouble multiplier = (delta_magnitude_squared / k) / delta_magnitude;\n\t\t\t\t\t\tdouble delta_multiplier_x = delta_x * multiplier;\n\t\t\t\t\t\tdouble delta_multiplier_y = delta_y * multiplier;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdisp_x[v] -= delta_multiplier_x;\n\t\t\t\t\t\tdisp_y[v] -= delta_multiplier_y;\n\t\t\t\t\t\tdisp_x[u] += delta_multiplier_x;\n\t\t\t\t\t\tdisp_y[u] += delta_multiplier_y;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Limit max displacement to temperature t and prevent displacement outside frame\n\t\t\tfor (int v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tdouble delta_x = disp_x[v];\n\t\t\t\tdouble delta_y = disp_y[v];\n\t\t\t\tdouble delta_magnitude_squared = delta_x * delta_x + delta_y * delta_y;\n\t\t\t\tdouble delta_magnitude = sqrt(delta_magnitude_squared);\n\t\t\t\t\n\t\t\t\tif (delta_magnitude < temperature)\n\t\t\t\t{\n\t\t\t\t\tpos_x[v] += disp_x[v];\n\t\t\t\t\tpos_y[v] += disp_y[v];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tpos_x[v] += (disp_x[v] / delta_magnitude) * temperature;\n\t\t\t\t\tpos_y[v] += (disp_y[v] / delta_magnitude) * temperature;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (pos_x[v] < -width/2) pos_x[v] = -width/2;\n\t\t\t\tif (pos_y[v] < -length/2) pos_y[v] = -length/2;\n\t\t\t\tif (pos_x[v] > width/2) pos_x[v] = width/2;\n\t\t\t\tif (pos_y[v] > length/2) pos_y[v] = length/2;\n\t\t\t}\n\t\t\t\n\t\t\t// reduce the temperature as the layout approaches a better configuration\n\t\t\t// Fruchterman & Reingold are vague about exactly what they did here, but there is a rapid cooling phase (quenching)\n\t\t\t// and then a constant low-temperature phase (simmering); I've taken a guess at what that might look like\n\t\t\ttemperature = temperature * 0.95;\n\t\t\t\n\t\t\tif (temperature < 0.002)\n\t\t\t\ttemperature = 0.002;\n\t\t}\n\t\t\n\t\t// Test the final candidate and keep the best candidate\n\t\tdouble candidate_score = [self scorePositionsWithX:pos_x y:pos_y connected:connected count:subpopCount];\n\t\t\n\t\tif (candidate_score > best_score)\n\t\t{\n\t\t\tfor (int v = 0; v < subpopCount; ++v)\n\t\t\t{\n\t\t\t\tbest_x[v] = pos_x[v];\n\t\t\t\tbest_y[v] = pos_y[v];\n\t\t\t}\n\t\t\tbest_score = candidate_score;\n\t\t\t//NSLog(@\"better candidate, new score == %f\", best_score);\n\t\t}\n\t}\n\t\n\t// Finally, we set the positions we have arrived at back into the subpops\n\tsubpopIter = pop.subpops_.begin();\n\t\n\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t{\n\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\n\t\tsubpop->gui_center_x_ = best_x[subpopIndex] + 0.5;\n\t\tsubpop->gui_center_y_ = best_y[subpopIndex] + 0.5;\n\t\tsubpop->gui_center_from_user_ = false;\t\t// optimization overrides previously set display settings\n\t\t++subpopIter;\n\t}\n\t\n\tfree(pos_x);\n\tfree(pos_y);\n\tfree(disp_x);\n\tfree(disp_y);\n\tfree(connected);\n\tfree(best_x);\n\tfree(best_y);\n}\n\n- (void)drawGraphInInteriorRect:(NSRect)interiorRect withController:(SLiMWindowController *)controller\n{\n\tCommunity &community = *controller->community;\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\tint subpopCount = (int)pop.subpops_.size();\n\t\n\tif (subpopCount == 0)\n\t{\n\t\t[self drawMessage:@\"no subpopulations\" inRect:interiorRect];\n\t\treturn;\n\t}\n\t\n\t// First, we transform our coordinate system so that a square of size (1,1) fits maximally and centered\n\t[NSGraphicsContext saveGraphicsState];\n\t\n\tNSAffineTransform *transform = [NSAffineTransform transform];\n\tif (interiorRect.size.width > interiorRect.size.height)\n\t{\n\t\t[transform translateXBy:interiorRect.origin.x yBy:interiorRect.origin.y];\n\t\t[transform translateXBy:SLIM_SCREEN_ROUND((interiorRect.size.width - interiorRect.size.height) / 2) yBy:0];\n\t\t[transform scaleBy:interiorRect.size.height];\n\t}\n\telse\n\t{\n\t\t[transform translateXBy:interiorRect.origin.x yBy:interiorRect.origin.y];\n\t\t[transform translateXBy:0 yBy:SLIM_SCREEN_ROUND((interiorRect.size.height - interiorRect.size.width) / 2)];\n\t\t[transform scaleBy:interiorRect.size.width];\n\t}\n\t[transform concat];\n\t\n\t// test frame\n\t//[[NSColor blackColor] set];\n\t//NSFrameRectWithWidth(NSMakeRect(0, 0, 1, 1), 0.002);\n\t\n\tif (subpopCount == 1)\n\t{\n\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\n\t\t// a single subpop is shown as a circle at the center\n\t\t[self drawSubpop:(*subpopIter).second withID:(*subpopIter).first centeredAt:NSMakePoint(0.5, 0.5) controller:controller];\n\t}\n\telse if (subpopCount > 1)\n\t{\n\t\t// first we distribute our subpops in a ring\n\t\tBOOL allUserConfigured = true;\n\t\t\n\t\t{\n\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\tdouble theta = (M_PI * 2.0 / subpopCount) * subpopIndex + M_PI_2;\n\t\t\t\t\n\t\t\t\tif (!subpop->gui_center_from_user_)\n\t\t\t\t{\n\t\t\t\t\tsubpop->gui_center_x_ = 0.5 - cos(theta) * 0.29;\n\t\t\t\t\tsubpop->gui_center_y_ = 0.5 + sin(theta) * 0.29;\n\t\t\t\t\tallUserConfigured = false;\n\t\t\t\t}\n\t\t\t\t++subpopIter;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if position optimization is on, we do that to optimize the positions of the subpops\n\t\tif ((community.ModelType() == SLiMModelType::kModelTypeWF) && _optimizePositions && (subpopCount > 2))\n\t\t\t[self optimizeSubpopPositionsWithController:controller];\n\t\t\n\t\tif (!allUserConfigured)\n\t\t{\n\t\t\t// then do some sizing, to figure out the maximum extent of our subpops\n\t\t\tNSRect boundingBox = NSZeroRect;\n\t\t\t\n\t\t\t{\n\t\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\t\n\t\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\t\t\n\t\t\t\t\tNSPoint center = NSMakePoint(subpop->gui_center_x_, subpop->gui_center_y_);\n\t\t\t\t\tNSRect subpopRect = [self rectForSubpop:subpop centeredAt:center];\n\t\t\t\t\t\n\t\t\t\t\tboundingBox = ((subpopIndex == 0) ? subpopRect : NSUnionRect(boundingBox, subpopRect));\n\t\t\t\t\t\n\t\t\t\t\t++subpopIter;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// then we translate our coordinate system so that the subpops are centered within our (0, 0, 1, 1) box\n\t\t\tdouble offsetX = ((1.0 - boundingBox.size.width) / 2.0) - boundingBox.origin.x;\n\t\t\tdouble offsetY = ((1.0 - boundingBox.size.height) / 2.0) - boundingBox.origin.y;\n\t\t\t\n\t\t\tNSAffineTransform *offsetTransform = [NSAffineTransform transform];\n\t\t\t[offsetTransform translateXBy:offsetX yBy:offsetY];\n\t\t\t[offsetTransform concat];\n\t\t}\n\t\t\n\t\t// then we draw the subpops\n\t\t{\n\t\t\tauto subpopIter = pop.subpops_.begin();\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < subpopCount; ++subpopIndex)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = (*subpopIter).second;\n\t\t\t\tslim_objectid_t subpopID = (*subpopIter).first;\n\t\t\t\tNSPoint center = NSMakePoint(subpop->gui_center_x_, subpop->gui_center_y_);\n\t\t\t\t\n\t\t\t\t[self drawSubpop:subpop withID:subpopID centeredAt:center controller:controller];\n\t\t\t\t++subpopIter;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// in the multipop case, we need to draw migration arrows, too\n\t\t{\n\t\t\tfor (auto destSubpopIter = pop.subpops_.begin(); destSubpopIter != pop.subpops_.end(); ++destSubpopIter)\n\t\t\t{\n\t\t\t\tSubpopulation *destSubpop = (*destSubpopIter).second;\n\t\t\t\tstd::map<slim_objectid_t,double> &destMigrants = (community.ModelType() == SLiMModelType::kModelTypeWF) ? destSubpop->migrant_fractions_ : destSubpop->gui_migrants_;\n\t\t\t\t\n\t\t\t\tfor (auto sourceSubpopIter = destMigrants.begin(); sourceSubpopIter != destMigrants.end(); ++sourceSubpopIter)\n\t\t\t\t{\n\t\t\t\t\tslim_objectid_t sourceSubpopID = (*sourceSubpopIter).first;\n\t\t\t\t\tauto sourceSubpopPair = pop.subpops_.find(sourceSubpopID);\n\t\t\t\t\t\n\t\t\t\t\tif (sourceSubpopPair != pop.subpops_.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tSubpopulation *sourceSubpop = sourceSubpopPair->second;\n\t\t\t\t\t\tdouble migrantFraction = (*sourceSubpopIter).second;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// The gui_migrants_ map is raw migration counts, which need to be converted to a fraction of the sourceSubpop pre-migration size\n\t\t\t\t\t\tif (community.ModelType() == SLiMModelType::kModelTypeNonWF)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (sourceSubpop->gui_premigration_size_ <= 0)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmigrantFraction /= sourceSubpop->gui_premigration_size_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (migrantFraction < 0.0)\n\t\t\t\t\t\t\t\tmigrantFraction = 0.0;\n\t\t\t\t\t\t\tif (migrantFraction > 1.0)\n\t\t\t\t\t\t\t\tmigrantFraction = 1.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t[self drawArrowFromSubpop:sourceSubpop toSubpop:destSubpop migrantFraction:migrantFraction];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// We're done with our transformed coordinate system\n\t[NSGraphicsContext restoreGraphicsState];\n}\n\n- (IBAction)toggleOptimizedPositions:(id)sender\n{\n\t[self setOptimizePositions:![self optimizePositions]];\n\t[self setNeedsDisplay:YES];\n}\n\n- (void)subclassAddItemsToMenu:(NSMenu *)menu forEvent:(NSEvent *)theEvent\n{\n\tif (menu)\n\t{\n\t\tNSMenuItem *menuItem = [menu addItemWithTitle:([self optimizePositions] ? @\"Standard Positions\" : @\"Optimized Positions\") action:@selector(toggleOptimizedPositions:) keyEquivalent:@\"\"];\n\t\t\n\t\t[menuItem setTarget:self];\n\t}\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\tSLiMWindowController *controller = [self slimWindowController];\n\t\n\tif (!controller)\n\t\treturn NO;\n\t\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tPopulation &pop = displaySpecies->population_;\n\t\n\tif (sel == @selector(toggleOptimizedPositions:))\n\t{\n\t\t// If any subpop has a user-defined center, disable position optimization; it doesn't know how to\n\t\t// handle those, and there's no way to revert back after it messes things up, and so forth\n\t\tfor (auto subpopIter = pop.subpops_.begin(); subpopIter != pop.subpops_.end(); ++subpopIter)\n\t\t\tif (((*subpopIter).second)->gui_center_from_user_)\n\t\t\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"AppIcon_16x16.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"AppIcon_16x16@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"filename\" : \"AppIcon_32x32.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"AppIcon_32x32@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"32x32\"\n    },\n    {\n      \"filename\" : \"AppIcon_128x128.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"AppIcon_128x128@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"128x128\"\n    },\n    {\n      \"filename\" : \"AppIcon_256x256.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"AppIcon_256x256@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"256x256\"\n    },\n    {\n      \"filename\" : \"AppIcon_512x512.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"512x512\"\n    },\n    {\n      \"filename\" : \"AppIcon_512x512@2x.png\",\n      \"idiom\" : \"mac\",\n      \"scale\" : \"2x\",\n      \"size\" : \"512x512\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "SLiMgui/PopulationView.h",
    "content": "//\n//  PopulationView.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include \"subpopulation.h\"\n#include <map>\n\n\ntypedef struct {\n\tint backgroundType;\t\t\t\t// 0 == black, 1 == gray, 2 == white, 3 == named spatial map; if no preference has been set, no entry will exist\n\tstd::string spatialMapName;\t\t// the name of the spatial map chosen, for backgroundType == 3\n} PopulationViewBackgroundSettings;\n\n@interface PopulationView : NSOpenGLView\n{\n\t// display mode: 0 == individuals (non-spatial), 1 == individuals (spatial)\n\tint displayMode;\n\t\n\t// display background preferences, kept indexed by subpopulation id\n\tstd::map<slim_objectid_t, PopulationViewBackgroundSettings> backgroundSettings;\n\tslim_objectid_t lastContextMenuSubpopID;\n\t\n\t// subview tiling, kept indexed by subpopulation id\n\tstd::map<slim_objectid_t, NSRect> subpopTiles;\n}\n\n// Outlets connected to objects in PopulationViewOptionsSheet.xib\n@property (nonatomic, retain) IBOutlet NSWindow *displayOptionsSheet;\n@property (nonatomic, assign) IBOutlet NSTextField *binCountTextField;\n@property (nonatomic, assign) IBOutlet NSTextField *fitnessMinTextField;\n@property (nonatomic, assign) IBOutlet NSTextField *fitnessMaxTextField;\n@property (nonatomic, assign) IBOutlet NSButton *okButton;\n\n- (BOOL)tileSubpopulations:(std::vector<Subpopulation*> &)selectedSubpopulations;\n\n@end\n\n\n// This subclass is for displaying an error message in the population view, which is hard to do in an NSOpenGLView\n@interface PopulationErrorView : NSView\n{\n}\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/PopulationView.mm",
    "content": "//\n//  PopulationView.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"PopulationView.h\"\n#import \"SLiMWindowController.h\"\n#import \"CocoaExtra.h\"\n\n#import <OpenGL/OpenGL.h>\n#include <OpenGL/glu.h>\n#include <GLKit/GLKMatrix4.h>\n\n#include \"community.h\"\n\n\nstatic const int kMaxGLRects = 2000;\t\t\t\t// 2000 rects\nstatic const int kMaxVertices = kMaxGLRects * 4;\t// 4 vertices each\n\n\n@implementation PopulationView\n\n- (void)initializeDisplayOptions\n{\n\tdisplayMode = -1;\t// don't know yet whether the model is spatial or not, which will determine our initial choice\n}\n\n- (instancetype)initWithCoder:(NSCoder *)coder\n{\n\tif (self = [super initWithCoder:coder])\n\t{\n\t\t[self initializeDisplayOptions];\n\t}\n\t\n\treturn self;\n}\n\n- (instancetype)initWithFrame:(NSRect)frameRect\n{\n\tif (self = [super initWithFrame:frameRect])\n\t{\n\t\t[self initializeDisplayOptions];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t//NSLog(@\"[PopulationView dealloc]\");\n\t[self setDisplayOptionsSheet:nil];\n\t\n\t[super dealloc];\n}\n\n/*\n// BCH 4/19/2019: these subclass methods are not needed, and are generating a warning in Xcode 10.2, so I'm removing them\n \n// Called after being summoned from a NIB/XIB.\n- (void)prepareOpenGL\n{\n}\n\n// Adjust the OpenGL viewport in response to window resize\n- (void)reshape\n{\n}\n*/\n\n- (void)drawViewFrameInBounds:(NSRect)bounds\n{\n\tint ox = (int)bounds.origin.x, oy = (int)bounds.origin.y;\n\t\n\tglColor3f(0.77f, 0.77f, 0.77f);\n\tglRecti(ox, oy, ox + 1, oy + (int)bounds.size.height);\n\tglRecti(ox + 1, oy, ox + (int)bounds.size.width - 1, oy + 1);\n\tglRecti(ox + (int)bounds.size.width - 1, oy, ox + (int)bounds.size.width, oy + (int)bounds.size.height);\n\tglRecti(ox + 1, oy + (int)bounds.size.height - 1, ox + (int)bounds.size.width - 1, oy + (int)bounds.size.height);\n}\n\n- (void)drawIndividualsFromSubpopulation:(Subpopulation *)subpop inArea:(NSRect)bounds\n{\n\t//\n\t//\tNOTE this code is parallel to the code in canDisplayIndividualsFromSubpopulation:inArea: and should be maintained in parallel\n\t//\n\t\n\tdouble scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tint squareSize, viewColumns = 0, viewRows = 0;\n\t\n\t// first figure out the biggest square size that will allow us to display the whole subpopulation\n\tfor (squareSize = 20; squareSize > 1; --squareSize)\n\t{\n\t\tviewColumns = (int)floor((bounds.size.width - 3) / squareSize);\n\t\tviewRows = (int)floor((bounds.size.height - 3) / squareSize);\n\t\t\n\t\tif (viewColumns * viewRows > subpopSize)\n\t\t{\n\t\t\t// If we have an empty row at the bottom, then break for sure; this allows us to look nice and symmetrical\n\t\t\tif ((subpopSize - 1) / viewColumns < viewRows - 1)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Otherwise, break only if we are getting uncomfortably small; otherwise, let's drop down one square size to allow symmetry\n\t\t\tif (squareSize <= 5)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tif (squareSize > 1)\n\t{\n\t\tint squareSpacing = 0;\n\t\t\n\t\t// Convert square area to space between squares if possible\n\t\tif (squareSize > 2)\n\t\t{\n\t\t\t--squareSize;\n\t\t\t++squareSpacing;\n\t\t}\n\t\tif (squareSize > 5)\n\t\t{\n\t\t\t--squareSize;\n\t\t\t++squareSpacing;\n\t\t}\n\t\t\n\t\tdouble excessSpaceX = bounds.size.width - ((squareSize + squareSpacing) * viewColumns - squareSpacing);\n\t\tdouble excessSpaceY = bounds.size.height - ((squareSize + squareSpacing) * viewRows - squareSpacing);\n\t\tint offsetX = (int)floor(excessSpaceX / 2.0);\n\t\tint offsetY = (int)floor(excessSpaceY / 2.0);\n\t\t\n\t\t// If we have an empty row at the bottom, then we can use the same value for offsetY as for offsetX, for symmetry\n\t\tif ((subpopSize - 1) / viewColumns < viewRows - 1)\n\t\t\toffsetY = offsetX;\n\t\t\n\t\tNSRect individualArea = NSMakeRect(bounds.origin.x + offsetX, bounds.origin.y + offsetY, bounds.size.width - offsetX, bounds.size.height - offsetY);\n\t\t\n\t\tstatic float *glArrayVertices = nil;\n\t\tstatic float *glArrayColors = nil;\n\t\tint individualArrayIndex, displayListIndex;\n\t\tfloat *vertices = NULL, *colors = NULL;\n\t\t\n\t\t// Set up the vertex and color arrays\n\t\tif (!glArrayVertices)\n\t\t\tglArrayVertices = (float *)malloc(kMaxVertices * 2 * sizeof(float));\t\t// 2 floats per vertex, kMaxVertices vertices\n\t\t\n\t\tif (!glArrayColors)\n\t\t\tglArrayColors = (float *)malloc(kMaxVertices * 4 * sizeof(float));\t\t// 4 floats per color, kMaxVertices colors\n\t\t\n\t\t// Set up to draw rects\n\t\tdisplayListIndex = 0;\n\t\t\n\t\tvertices = glArrayVertices;\n\t\tglEnableClientState(GL_VERTEX_ARRAY);\n\t\tglVertexPointer(2, GL_FLOAT, 0, glArrayVertices);\n\t\t\n\t\tcolors = glArrayColors;\n\t\tglEnableClientState(GL_COLOR_ARRAY);\n\t\tglColorPointer(4, GL_FLOAT, 0, glArrayColors);\n\t\t\n\t\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t\t{\n\t\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n\t\t\tfloat left = (float)(individualArea.origin.x + (individualArrayIndex % viewColumns) * (squareSize + squareSpacing));\n\t\t\tfloat top = (float)(individualArea.origin.y + (individualArrayIndex / viewColumns) * (squareSize + squareSpacing));\n\t\t\tfloat right = left + squareSize;\n\t\t\tfloat bottom = top + squareSize;\n\t\t\t\n\t\t\t*(vertices++) = left;\n\t\t\t*(vertices++) = top;\n\t\t\t*(vertices++) = left;\n\t\t\t*(vertices++) = bottom;\n\t\t\t*(vertices++) = right;\n\t\t\t*(vertices++) = bottom;\n\t\t\t*(vertices++) = right;\n\t\t\t*(vertices++) = top;\n\t\t\t\n\t\t\t// dark gray default, for a fitness of NaN; should never happen\n\t\t\tfloat colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n\t\t\tIndividual &individual = *subpop->parent_individuals_[individualArrayIndex];\n\t\t\t\n\t\t\tif (Individual::s_any_individual_color_set_ && individual.color_set_)\n\t\t\t{\n\t\t\t\tcolorRed = individual.colorR_ / 255.0F;\n\t\t\t\tcolorGreen = individual.colorG_ / 255.0F;\n\t\t\t\tcolorBlue = individual.colorB_ / 255.0F;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// use individual trait values to determine color; we use fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n\t\t\t\t// we use cached_unscaled_fitness_ so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\t\t\tdouble fitness = individual.cached_unscaled_fitness_;\n\t\t\t\t\n\t\t\t\tif (!std::isnan(fitness))\n\t\t\t\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t\t}\n\t\t\t\n\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = colorRed;\n\t\t\t\t*(colors++) = colorGreen;\n\t\t\t\t*(colors++) = colorBlue;\n\t\t\t\t*(colors++) = colorAlpha;\n\t\t\t}\n\t\t\t\n\t\t\tdisplayListIndex++;\n\t\t\t\n\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t{\n\t\t\t\t// Draw our arrays\n\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\n\t\t\t\t// And get ready to draw more\n\t\t\t\tvertices = glArrayVertices;\n\t\t\t\tcolors = glArrayColors;\n\t\t\t\tdisplayListIndex = 0;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Draw any leftovers\n\t\tif (displayListIndex)\n\t\t{\n\t\t\t// Draw our arrays\n\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t}\n\t\t\n\t\t// Draw a gear\n\t\t// This is an experiment with drawing an \"action\" button on top of the view contents using OpenGL.\n\t\t// The results are decent on a Retina display, but not great on a regular display.  In any case\n\t\t// I think having the action button drawn on top of view contents ends up looking strange.\n\t\t// Unfortunately there doesn't seem to be anywhere good to put such buttons; so we'll stick with\n\t\t// context menus for now.  BCH 1/27/2019\n#if 0\n\t\t{\n\t\t\tdouble cx = bounds.size.width - 13.0, cy = 13.0;\n\t\t\tdouble radius = 8.0;\n\t\t\tfloat button_color = 1.0f;\n\t\t\tfloat outline_color = 0.60f;\n\t\t\t\n\t\t\t// ***** draw the off-white button disc as a triangle fan\n\t\t\tvertices = glArrayVertices;\n\t\t\tcolors = glArrayColors;\n\t\t\tdisplayListIndex = 0;\n\t\t\t\n\t\t\t// center point\n\t\t\t*(vertices++) = (float)cx;\n\t\t\t*(vertices++) = (float)cy;\n\t\t\tdisplayListIndex++;\n\t\t\t\n\t\t\t// fan points\n\t\t\tfor (int j = 0; j <= 32; ++j)\n\t\t\t{\n\t\t\t\tdouble angle = (j / (32.0)) * (2.0 * M_PI);\n\t\t\t\tdouble r = radius * 1.30;\n\t\t\t\t\n\t\t\t\t*(vertices++) = (float)(cx + cos(angle) * r);\n\t\t\t\t*(vertices++) = (float)(cy + sin(angle) * r);\n\t\t\t\tdisplayListIndex++;\n\t\t\t}\n\t\t\t\n\t\t\t// colors\n\t\t\tfor (int j = 0; j < displayListIndex; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = 1.0f;\n\t\t\t}\n\t\t\t\n\t\t\tglDrawArrays(GL_TRIANGLE_FAN, 0, displayListIndex);\n\t\t\t\n\t\t\t// ***** outline the button with gray\n\t\t\tcolors = glArrayColors;\n\t\t\t\n\t\t\tfor (int j = 0; j < displayListIndex; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = outline_color;\n\t\t\t\t*(colors++) = outline_color;\n\t\t\t\t*(colors++) = outline_color;\n\t\t\t\t*(colors++) = 1.0f;\n\t\t\t}\n\t\t\t\n\t\t\tglLineWidth(2.0);\n\t\t\tglEnable(GL_LINE_SMOOTH);\n\t\t\tglEnable(GL_BLEND);\n\t\t\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\t\t\n\t\t\tglDrawArrays(GL_LINE_LOOP, 1, displayListIndex - 2);\n\t\t\t\n\t\t\tglLineWidth(1.0);\n\t\t\tglDisable(GL_LINE_SMOOTH);\n\t\t\tglDisable(GL_BLEND);\n\t\t\t\n\t\t\t// ***** draw the gear polygon as a triangle fan\n\t\t\tvertices = glArrayVertices;\n\t\t\tcolors = glArrayColors;\n\t\t\tdisplayListIndex = 0;\n\t\t\t\n\t\t\t// center point\n\t\t\t*(vertices++) = (float)cx;\n\t\t\t*(vertices++) = (float)cy;\n\t\t\tdisplayListIndex++;\n\t\t\t\n\t\t\t// fan points\n\t\t\tfor (int j = 0; j <= 8 * 6; ++j)\n\t\t\t{\n\t\t\t\tdouble angle = (j / (8.0 * 6.0)) * (2.0 * M_PI);\n\t\t\t\tint tooth_step = (j + 1) % 6;\t// 6 steps per tooth\n\t\t\t\tdouble r = (tooth_step < 3) ? radius : radius * 0.7;\n\t\t\t\t\n\t\t\t\t*(vertices++) = (float)(cx + cos(angle) * r);\n\t\t\t\t*(vertices++) = (float)(cy + sin(angle) * r);\n\t\t\t\tdisplayListIndex++;\n\t\t\t}\n\t\t\t\n\t\t\t// colors\n\t\t\tfor (int j = 0; j < displayListIndex; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = 0.3f;\n\t\t\t\t*(colors++) = 0.3f;\n\t\t\t\t*(colors++) = 0.3f;\n\t\t\t\t*(colors++) = 1.0f;\n\t\t\t}\n\t\t\t\n\t\t\tglDrawArrays(GL_TRIANGLE_FAN, 0, displayListIndex);\n\t\t\t\n\t\t\t// ***** draw the gear outline, to antialias it\n\t\t\tcolors = glArrayColors;\n\t\t\t\n\t\t\tfor (int j = 0; j < displayListIndex; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = 1.0f;\n\t\t\t}\n\t\t\t\n\t\t\tglLineWidth(1.0);\n\t\t\tglEnable(GL_LINE_SMOOTH);\n\t\t\tglEnable(GL_BLEND);\n\t\t\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\t\t\n\t\t\tglDrawArrays(GL_LINE_LOOP, 1, displayListIndex - 2);\n\t\t\t\n\t\t\tglLineWidth(1.0);\n\t\t\tglDisable(GL_LINE_SMOOTH);\n\t\t\tglDisable(GL_BLEND);\n\t\t\t\n\t\t\t// ***** draw the interior circle\n\t\t\tvertices = glArrayVertices;\n\t\t\tcolors = glArrayColors;\n\t\t\tdisplayListIndex = 0;\n\t\t\t\n\t\t\t// center point\n\t\t\t*(vertices++) = (float)cx;\n\t\t\t*(vertices++) = (float)cy;\n\t\t\tdisplayListIndex++;\n\t\t\t\n\t\t\t// fan points\n\t\t\tfor (int j = 0; j <= 16; ++j)\n\t\t\t{\n\t\t\t\tdouble angle = (j / 16.0) * (2.0 * M_PI);\n\t\t\t\tdouble r = radius * 0.25;\n\t\t\t\t\n\t\t\t\t*(vertices++) = (float)(cx + cos(angle) * r);\n\t\t\t\t*(vertices++) = (float)(cy + sin(angle) * r);\n\t\t\t\tdisplayListIndex++;\n\t\t\t}\n\t\t\t\n\t\t\t// colors\n\t\t\tfor (int j = 0; j < displayListIndex; ++j)\n\t\t\t{\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = button_color;\n\t\t\t\t*(colors++) = 1.0f;\n\t\t\t}\n\t\t\t\n\t\t\tglDrawArrays(GL_TRIANGLE_FAN, 0, displayListIndex);\n\t\t\t\n\t\t\t// ***** draw the inner circle outline, to antialias it\n\t\t\tglLineWidth(1.0);\n\t\t\tglEnable(GL_LINE_SMOOTH);\n\t\t\tglEnable(GL_BLEND);\n\t\t\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\t\t\n\t\t\tglDrawArrays(GL_LINE_LOOP, 1, displayListIndex - 2);\n\t\t\t\n\t\t\tglLineWidth(1.0);\n\t\t\tglDisable(GL_LINE_SMOOTH);\n\t\t\tglDisable(GL_BLEND);\n\t\t}\n#endif\n\t\t\n\t\tglDisableClientState(GL_VERTEX_ARRAY);\n\t\tglDisableClientState(GL_COLOR_ARRAY);\n\t}\n\telse\n\t{\n\t\t// This is what we do if we cannot display a subpopulation because there are too many individuals in it to display\n\t\tglColor3f(0.9f, 0.9f, 1.0f);\n\t\t\n\t\tint ox = (int)bounds.origin.x, oy = (int)bounds.origin.y;\n\t\t\n\t\tglRecti(ox + 1, oy + 1, ox + (int)bounds.size.width - 1, oy + (int)bounds.size.height - 1);\n\t}\n}\n\n#define SLIM_MAX_HISTOGRAM_BINS\t\t100\n\n- (void)cacheDisplayBufferForMap:(SpatialMap *)background_map subpopulation:(Subpopulation *)subpop\n{\n\t// Cache a display buffer for the given background map.  This method should be called only in the 2D \"xy\"\n\t// case; in the 1D case we can't know the maximum width ahead of time, so we just draw rects without caching,\n\t// and in the 3D \"xyz\" case we don't know which z-slice to use so we can't display the spatial map.\n\t// The window might be too narrow to display a full-size map right now, but we want to premake a full-size map.\n\t// The sizing logic here is taken from drawRect:, assuming that we are not constrained in width.\n\t\n\t// By the way, it may occur to the reader to wonder why we keep the buffer as uint8_t values, given that we\n\t// convert to and from uin8_t for the display code that uses float RGB components.  My rationale is that\n\t// this drastically cuts the amount of memory that has to be accessed, and that the display code, in particular,\n\t// is probably memory-bound since most of the work is done in the GPU.  I haven't done any speed tests to\n\t// confirm that hunch, though.  In any case, it's plenty fast and I don't see significant display artifacts.\n\t\n\tNSRect full_bounds = NSInsetRect([self bounds], 1, 1);\n\tint max_height = (int)full_bounds.size.height;\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\tdouble subpopAspect = bounds_x_size / bounds_y_size;\n\tint max_width = (int)round(max_height * subpopAspect);\n\t\n\t// If we have a display buffer of the wrong size, free it.  This should only happen when the user changes\n\t// the Subpopulation's spatialBounds after it has displayed; it should not happen with a window resize.\n\t// The user has no way to change the map or the colormap except to set a whole new map, which will also\n\t// result in the old one being freed, so we're already safe in those circumstances.\n\tif (background_map->display_buffer_ && ((background_map->buffer_width_ != max_width) || (background_map->buffer_height_ != max_height)))\n\t{\n\t\tfree(background_map->display_buffer_);\n\t\tbackground_map->display_buffer_ = nullptr;\n\t}\n\t\n\t// Now allocate and validate the display buffer if we haven't already done so.\n\tif (!background_map->display_buffer_)\n\t{\n\t\tuint8_t *display_buf = (uint8_t *)malloc(max_width * max_height * 3 * sizeof(uint8_t));\n\t\tbackground_map->display_buffer_ = display_buf;\n\t\tbackground_map->buffer_width_ = max_width;\n\t\tbackground_map->buffer_height_ = max_height;\n\t\t\n\t\tuint8_t *buf_ptr = display_buf;\n\t\tint64_t xsize = background_map->grid_size_[0];\n\t\tint64_t ysize = background_map->grid_size_[1];\n\t\tdouble *values = background_map->values_;\n\t\tbool interpolate = background_map->interpolate_;\n\t\t\n\t\tfor (int y = 0; y < max_height; y++)\n\t\t{\n\t\t\tfor (int x = 0; x < max_width; x++)\n\t\t\t{\n\t\t\t\t// Look up the nearest map point and get its value; interpolate if requested\n\t\t\t\tdouble x_fraction = (x + 0.5) / max_width;\t\t// pixel center\n\t\t\t\tdouble y_fraction = (y + 0.5) / max_height;\t\t// pixel center\n\t\t\t\tdouble value;\n\t\t\t\t\n\t\t\t\tif (interpolate)\n\t\t\t\t{\n\t\t\t\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\t\t\t\tdouble y_map = y_fraction * (ysize - 1);\n\t\t\t\t\tint x1_map = (int)floor(x_map);\n\t\t\t\t\tint y1_map = (int)floor(y_map);\n\t\t\t\t\tint x2_map = (int)ceil(x_map);\n\t\t\t\t\tint y2_map = (int)ceil(y_map);\n\t\t\t\t\tdouble fraction_x2 = x_map - x1_map;\n\t\t\t\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\t\t\t\tdouble fraction_y2 = y_map - y1_map;\n\t\t\t\t\tdouble fraction_y1 = 1.0 - fraction_y2;\n\t\t\t\t\tdouble value_x1_y1 = values[x1_map + y1_map * xsize] * fraction_x1 * fraction_y1;\n\t\t\t\t\tdouble value_x2_y1 = values[x2_map + y1_map * xsize] * fraction_x2 * fraction_y1;\n\t\t\t\t\tdouble value_x1_y2 = values[x1_map + y2_map * xsize] * fraction_x1 * fraction_y2;\n\t\t\t\t\tdouble value_x2_y2 = values[x2_map + y2_map * xsize] * fraction_x2 * fraction_y2;\n\t\t\t\t\t\n\t\t\t\t\tvalue = value_x1_y1 + value_x2_y1 + value_x1_y2 + value_x2_y2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\t\t\t\tint y_map = (int)round(y_fraction * (ysize - 1));\n\t\t\t\t\t\n\t\t\t\t\tvalue = values[x_map + y_map * xsize];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Given the (interpolated?) value, look up the color, interpolating if necessary\n\t\t\t\tdouble rgb[3];\n\t\t\t\t\n\t\t\t\tbackground_map->ColorForValue(value, rgb);\n\t\t\t\t\n\t\t\t\t// Write the color values to the buffer\n\t\t\t\t*(buf_ptr++) = (uint8_t)round(rgb[0] * 255.0);\n\t\t\t\t*(buf_ptr++) = (uint8_t)round(rgb[1] * 255.0);\n\t\t\t\t*(buf_ptr++) = (uint8_t)round(rgb[2] * 255.0);\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)_drawBackgroundSpatialMap:(SpatialMap *)background_map inBounds:(NSRect)bounds forSubpopulation:(Subpopulation *)subpop\n{\n\t// We have a spatial map with a color map, so use it to draw the background\n\tint bounds_x1 = (int)bounds.origin.x;\n\tint bounds_y1 = (int)bounds.origin.y;\n\tint bounds_x2 = (int)(bounds.origin.x + bounds.size.width);\n\tint bounds_y2 = (int)(bounds.origin.y + bounds.size.height);\n\t\n\t//glColor3f(0.0, 0.0, 0.0);\n\t//glRecti(bounds_x1, bounds_y1, bounds_x2, bounds_y2);\n\t\n\tstatic float *glArrayVertices = nil;\n\tstatic float *glArrayColors = nil;\n\tint displayListIndex;\n\tfloat *vertices = NULL, *colors = NULL;\n\t\n\t// Set up the vertex and color arrays\n\tif (!glArrayVertices)\n\t\tglArrayVertices = (float *)malloc(kMaxVertices * 2 * sizeof(float));\t\t// 2 floats per vertex, kMaxVertices vertices\n\t\n\tif (!glArrayColors)\n\t\tglArrayColors = (float *)malloc(kMaxVertices * 4 * sizeof(float));\t\t// 4 floats per color, kMaxVertices colors\n\t\n\t// Set up to draw rects\n\tdisplayListIndex = 0;\n\t\n\tvertices = glArrayVertices;\n\tglEnableClientState(GL_VERTEX_ARRAY);\n\tglVertexPointer(2, GL_FLOAT, 0, glArrayVertices);\n\t\n\tcolors = glArrayColors;\n\tglEnableClientState(GL_COLOR_ARRAY);\n\tglColorPointer(4, GL_FLOAT, 0, glArrayColors);\n\t\n\tif (background_map->spatiality_ == 1)\n\t{\n\t\t// This is the spatiality \"x\" and \"y\" cases; they are the only 1D spatiality values for which SLiMgui will draw\n\t\t// In the 1D case we can't cache a display buffer, since we don't know what aspect ratio to use, so we just\n\t\t// draw rects.  Whether those rects are horizontal or vertical will depend on the spatiality of the map.  Most\n\t\t// of the code is identical, though, because of the way we handle dimensions, so we share the two cases here.\n\t\tbool spatiality_is_x = (background_map->spatiality_string_ == \"x\");\n\t\tint64_t xsize = background_map->grid_size_[0];\n\t\tdouble *values = background_map->values_;\n\t\t\n\t\tif (background_map->interpolate_)\n\t\t{\n\t\t\t// Interpolation, so we need to draw every line individually\n\t\t\tint min_coord = (spatiality_is_x ? bounds_x1 : bounds_y1);\n\t\t\tint max_coord = (spatiality_is_x ? bounds_x2 : bounds_y2);\n\t\t\t\n\t\t\tfor (int x = min_coord; x < max_coord; ++x)\n\t\t\t{\n\t\t\t\tdouble x_fraction = (x + 0.5 - min_coord) / (max_coord - min_coord);\t// values evaluated at pixel centers\n\t\t\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\t\t\tint x1_map = (int)floor(x_map);\n\t\t\t\tint x2_map = (int)ceil(x_map);\n\t\t\t\tdouble fraction_x2 = x_map - x1_map;\n\t\t\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\t\t\tdouble value_x1 = values[x1_map] * fraction_x1;\n\t\t\t\tdouble value_x2 = values[x2_map] * fraction_x2;\n\t\t\t\tdouble value = value_x1 + value_x2;\n\t\t\t\t\n\t\t\t\tint x1, x2, y1, y2;\n\t\t\t\t\n\t\t\t\tif (spatiality_is_x)\n\t\t\t\t{\n\t\t\t\t\tx1 = x;\n\t\t\t\t\tx2 = x + 1;\n\t\t\t\t\ty1 = bounds_y1;\n\t\t\t\t\ty2 = bounds_y2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ty1 = (max_coord - 1) - x + min_coord;\t// flip for y, to use Cartesian coordinates\n\t\t\t\t\ty2 = y1 + 1;\n\t\t\t\t\tx1 = bounds_x1;\n\t\t\t\t\tx2 = bounds_x2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat rgb[3];\n\t\t\t\t\n\t\t\t\tbackground_map->ColorForValue(value, rgb);\n\t\t\t\t\n\t\t\t\t//glColor3f(red, green, blue);\n\t\t\t\t//glRecti(x1, y1, x2, y2);\n\t\t\t\t\n\t\t\t\t*(vertices++) = x1;\n\t\t\t\t*(vertices++) = y1;\n\t\t\t\t*(vertices++) = x1;\n\t\t\t\t*(vertices++) = y2;\n\t\t\t\t*(vertices++) = x2;\n\t\t\t\t*(vertices++) = y2;\n\t\t\t\t*(vertices++) = x2;\n\t\t\t\t*(vertices++) = y1;\n\t\t\t\t\n\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t{\n\t\t\t\t\t*(colors++) = rgb[0];\n\t\t\t\t\t*(colors++) = rgb[1];\n\t\t\t\t\t*(colors++) = rgb[2];\n\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdisplayListIndex++;\n\t\t\t\t\n\t\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t\t{\n\t\t\t\t\t// Draw our arrays\n\t\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\t\n\t\t\t\t\t// And get ready to draw more\n\t\t\t\t\tvertices = glArrayVertices;\n\t\t\t\t\tcolors = glArrayColors;\n\t\t\t\t\tdisplayListIndex = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No interpolation, so we can draw whole grid blocks\n\t\t\tfor (int x = 0; x < xsize; x++)\n\t\t\t{\n\t\t\t\tdouble value = (spatiality_is_x ? values[x] : values[(xsize - 1) - x]);\t// flip for y, to use Cartesian coordinates\n\t\t\t\tint x1, x2, y1, y2;\n\t\t\t\t\n\t\t\t\tif (spatiality_is_x)\n\t\t\t\t{\n\t\t\t\t\tx1 = (int)round(((x - 0.5) / (xsize - 1)) * bounds.size.width + bounds.origin.x);\n\t\t\t\t\tx2 = (int)round(((x + 0.5) / (xsize - 1)) * bounds.size.width + bounds.origin.x);\n\t\t\t\t\t\n\t\t\t\t\tif (x1 < bounds_x1) x1 = bounds_x1;\n\t\t\t\t\tif (x2 > bounds_x2) x2 = bounds_x2;\n\t\t\t\t\t\n\t\t\t\t\ty1 = bounds_y1;\n\t\t\t\t\ty2 = bounds_y2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ty1 = (int)round(((x - 0.5) / (xsize - 1)) * bounds.size.height + bounds.origin.y);\n\t\t\t\t\ty2 = (int)round(((x + 0.5) / (xsize - 1)) * bounds.size.height + bounds.origin.y);\n\t\t\t\t\t\n\t\t\t\t\tif (y1 < bounds_y1) y1 = bounds_y1;\n\t\t\t\t\tif (y2 > bounds_y2) y2 = bounds_y2;\n\t\t\t\t\t\n\t\t\t\t\tx1 = bounds_x1;\n\t\t\t\t\tx2 = bounds_x2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat rgb[3];\n\t\t\t\t\n\t\t\t\tbackground_map->ColorForValue(value, rgb);\n\t\t\t\t\n\t\t\t\t//glColor3f(red, green, blue);\n\t\t\t\t//glRecti(x1, y1, x2, y2);\n\t\t\t\t\n\t\t\t\t*(vertices++) = x1;\n\t\t\t\t*(vertices++) = y1;\n\t\t\t\t*(vertices++) = x1;\n\t\t\t\t*(vertices++) = y2;\n\t\t\t\t*(vertices++) = x2;\n\t\t\t\t*(vertices++) = y2;\n\t\t\t\t*(vertices++) = x2;\n\t\t\t\t*(vertices++) = y1;\n\t\t\t\t\n\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t{\n\t\t\t\t\t*(colors++) = rgb[0];\n\t\t\t\t\t*(colors++) = rgb[1];\n\t\t\t\t\t*(colors++) = rgb[2];\n\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdisplayListIndex++;\n\t\t\t\t\n\t\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t\t{\n\t\t\t\t\t// Draw our arrays\n\t\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\t\n\t\t\t\t\t// And get ready to draw more\n\t\t\t\t\tvertices = glArrayVertices;\n\t\t\t\t\tcolors = glArrayColors;\n\t\t\t\t\tdisplayListIndex = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse // if (background_map->spatiality_ == 2)\n\t{\n\t\t// This is the spatiality \"xy\" case; it is the only 2D spatiality for which SLiMgui will draw\n\t\t\n\t\t// First, cache the display buffer if needed.  If this succeeds, we'll use it.\n\t\t// It should always succeed, so the tile-drawing code below is dead code, kept for parallelism with the 1D case.\n\t\t[self cacheDisplayBufferForMap:background_map subpopulation:subpop];\n\t\t\n\t\tuint8_t *display_buf = background_map->display_buffer_;\n\t\t\n\t\tif (display_buf)\n\t\t{\n\t\t\t// Use a cached display buffer to draw.\n\t\t\tint buf_width = background_map->buffer_width_;\n\t\t\tint buf_height = background_map->buffer_height_;\n\t\t\tbool display_full_size = (((int)bounds.size.width == buf_width) && ((int)bounds.size.height == buf_height));\n\t\t\tfloat scale_x = (float)(bounds.size.width / buf_width);\n\t\t\tfloat scale_y = (float)(bounds.size.height / buf_height);\n\t\t\t\n\t\t\t// Then run through the pixels in the display buffer and draw them; this could be done\n\t\t\t// with some sort of OpenGL image-drawing method instead, but it's actually already\n\t\t\t// remarkably fast, at least on my machine, and drawing an image with OpenGL seems very\n\t\t\t// gross, and I tried it once before and couldn't get it to work well...\n\t\t\tfor (int y = 0; y < buf_height; y++)\n\t\t\t{\n\t\t\t\t// We flip the buffer vertically; it's the simplest way to get it into the right coordinate space\n\t\t\t\tuint8_t *buf_ptr = display_buf + ((buf_height - 1) - y) * buf_width * 3;\n\t\t\t\t\n\t\t\t\tfor (int x = 0; x < buf_width; x++)\n\t\t\t\t{\n\t\t\t\t\tfloat red = *(buf_ptr++) / 255.0f;\n\t\t\t\t\tfloat green = *(buf_ptr++) / 255.0f;\n\t\t\t\t\tfloat blue = *(buf_ptr++) / 255.0f;\n\t\t\t\t\tfloat left, right, top, bottom;\n\t\t\t\t\t\n\t\t\t\t\tif (display_full_size)\n\t\t\t\t\t{\n\t\t\t\t\t\tleft = bounds_x1 + x;\n\t\t\t\t\t\tright = left + 1.0f;\n\t\t\t\t\t\ttop = bounds_y1 + y;\n\t\t\t\t\t\tbottom = top + 1.0f;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tleft = bounds_x1 + x * scale_x;\n\t\t\t\t\t\tright = bounds_x1 + (x + 1) * scale_x;\n\t\t\t\t\t\ttop = bounds_y1 + y * scale_y;\n\t\t\t\t\t\tbottom = bounds_y1 + (y + 1) * scale_y;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t*(vertices++) = left;\n\t\t\t\t\t*(vertices++) = top;\n\t\t\t\t\t*(vertices++) = left;\n\t\t\t\t\t*(vertices++) = bottom;\n\t\t\t\t\t*(vertices++) = right;\n\t\t\t\t\t*(vertices++) = bottom;\n\t\t\t\t\t*(vertices++) = right;\n\t\t\t\t\t*(vertices++) = top;\n\t\t\t\t\t\n\t\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t\t{\n\t\t\t\t\t\t*(colors++) = red;\n\t\t\t\t\t\t*(colors++) = green;\n\t\t\t\t\t\t*(colors++) = blue;\n\t\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdisplayListIndex++;\n\t\t\t\t\t\n\t\t\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Draw our arrays\n\t\t\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// And get ready to draw more\n\t\t\t\t\t\tvertices = glArrayVertices;\n\t\t\t\t\t\tcolors = glArrayColors;\n\t\t\t\t\t\tdisplayListIndex = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Draw rects for each map tile, without caching.  Not as slow as you might expect,\n\t\t\t// but for really big maps it does get cumbersome.  This is dead code now, overridden\n\t\t\t// by the buffer-drawing code above, which also handles interpolation correctly.\n\t\t\tint64_t xsize = background_map->grid_size_[0];\n\t\t\tint64_t ysize = background_map->grid_size_[1];\n\t\t\tdouble *values = background_map->values_;\n\t\t\tint n_colors = background_map->n_colors_;\n\t\t\t\n\t\t\tfor (int y = 0; y < ysize; y++)\n\t\t\t{\n\t\t\t\tint y1 = (int)round(((y - 0.5) / (ysize - 1)) * bounds.size.height + bounds.origin.y);\n\t\t\t\tint y2 = (int)round(((y + 0.5) / (ysize - 1)) * bounds.size.height + bounds.origin.y);\n\t\t\t\t\n\t\t\t\tif (y1 < bounds_y1) y1 = bounds_y1;\n\t\t\t\tif (y2 > bounds_y2) y2 = bounds_y2;\n\t\t\t\t\n\t\t\t\t// Flip our display, since our coordinate system is flipped relative to our buffer\n\t\t\t\tdouble *values_row = values + ((ysize - 1) - y) * xsize;\n\t\t\t\t\n\t\t\t\tfor (int x = 0; x < xsize; x++)\n\t\t\t\t{\n\t\t\t\t\tdouble value = *(values_row + x);\n\t\t\t\t\tint x1 = (int)round(((x - 0.5) / (xsize - 1)) * bounds.size.width + bounds.origin.x);\n\t\t\t\t\tint x2 = (int)round(((x + 0.5) / (xsize - 1)) * bounds.size.width + bounds.origin.x);\n\t\t\t\t\t\n\t\t\t\t\tif (x1 < bounds_x1) x1 = bounds_x1;\n\t\t\t\t\tif (x2 > bounds_x2) x2 = bounds_x2;\n\t\t\t\t\t\n\t\t\t\t\tfloat value_fraction = (background_map->colors_min_ < background_map->colors_max_) ? (float)((value - background_map->colors_min_) / (background_map->colors_max_ - background_map->colors_min_)) : 0.0f;\n\t\t\t\t\tfloat color_index = value_fraction * (n_colors - 1);\n\t\t\t\t\tint color_index_1 = (int)floorf(color_index);\n\t\t\t\t\tint color_index_2 = (int)ceilf(color_index);\n\t\t\t\t\t\n\t\t\t\t\tif (color_index_1 < 0) color_index_1 = 0;\n\t\t\t\t\tif (color_index_1 >= n_colors) color_index_1 = n_colors - 1;\n\t\t\t\t\tif (color_index_2 < 0) color_index_2 = 0;\n\t\t\t\t\tif (color_index_2 >= n_colors) color_index_2 = n_colors - 1;\n\t\t\t\t\t\n\t\t\t\t\tfloat color_2_weight = color_index - color_index_1;\n\t\t\t\t\tfloat color_1_weight = 1.0f - color_2_weight;\n\t\t\t\t\t\n\t\t\t\t\tfloat red1 = background_map->red_components_[color_index_1];\n\t\t\t\t\tfloat green1 = background_map->green_components_[color_index_1];\n\t\t\t\t\tfloat blue1 = background_map->blue_components_[color_index_1];\n\t\t\t\t\tfloat red2 = background_map->red_components_[color_index_2];\n\t\t\t\t\tfloat green2 = background_map->green_components_[color_index_2];\n\t\t\t\t\tfloat blue2 = background_map->blue_components_[color_index_2];\n\t\t\t\t\tfloat red = red1 * color_1_weight + red2 * color_2_weight;\n\t\t\t\t\tfloat green = green1 * color_1_weight + green2 * color_2_weight;\n\t\t\t\t\tfloat blue = blue1 * color_1_weight + blue2 * color_2_weight;\n\t\t\t\t\t\n\t\t\t\t\t//glColor3f(red, green, blue);\n\t\t\t\t\t//glRecti(x1, y1, x2, y2);\n\t\t\t\t\t\n\t\t\t\t\t*(vertices++) = x1;\n\t\t\t\t\t*(vertices++) = y1;\n\t\t\t\t\t*(vertices++) = x1;\n\t\t\t\t\t*(vertices++) = y2;\n\t\t\t\t\t*(vertices++) = x2;\n\t\t\t\t\t*(vertices++) = y2;\n\t\t\t\t\t*(vertices++) = x2;\n\t\t\t\t\t*(vertices++) = y1;\n\t\t\t\t\t\n\t\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t\t{\n\t\t\t\t\t\t*(colors++) = red;\n\t\t\t\t\t\t*(colors++) = green;\n\t\t\t\t\t\t*(colors++) = blue;\n\t\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdisplayListIndex++;\n\t\t\t\t\t\n\t\t\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Draw our arrays\n\t\t\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// And get ready to draw more\n\t\t\t\t\t\tvertices = glArrayVertices;\n\t\t\t\t\t\tcolors = glArrayColors;\n\t\t\t\t\t\tdisplayListIndex = 0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t//std::cout << \"x = \" << x << \", y = \" << y << \", value = \" << value << \": color_index = \" << color_index << \", color_index_1 = \" << color_index_1 << \", color_index_2 = \" << color_index_2 << \", color_1_weight = \" << color_1_weight << \", color_2_weight = \" << color_2_weight << \", red = \" << red << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Draw any leftovers\n\tif (displayListIndex)\n\t{\n\t\t// Draw our arrays\n\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t}\n\t\n\tglDisableClientState(GL_VERTEX_ARRAY);\n\tglDisableClientState(GL_COLOR_ARRAY);\n\t\n#if 0\n\t// Experimental feature: draw boxes showing where the grid nodes are, since that is rather confusing!\n\tNSRect individualArea = NSMakeRect(bounds.origin.x, bounds.origin.y, bounds.size.width - 1, bounds.size.height - 1);\n\tint64_t xsize = background_map->grid_size_[0];\n\tint64_t ysize = background_map->grid_size_[1];\n\tdouble *values = background_map->values_;\n\t\n\tif ((xsize <= 51) && (ysize <= 51))\n\t{\n\t\t// Set up to draw rects\n\t\tdisplayListIndex = 0;\n\t\t\n\t\tvertices = glArrayVertices;\n\t\tglEnableClientState(GL_VERTEX_ARRAY);\n\t\tglVertexPointer(2, GL_FLOAT, 0, glArrayVertices);\n\t\t\n\t\tcolors = glArrayColors;\n\t\tglEnableClientState(GL_COLOR_ARRAY);\n\t\tglColorPointer(4, GL_FLOAT, 0, glArrayColors);\n\t\t\n\t\t// first pass we draw squares to make outlines, second pass we draw the interiors in color\n\t\tfor (int pass = 0; pass <= 1; ++pass)\n\t\t{\n\t\t\tfor (int x = 0; x < xsize; ++x)\n\t\t\t{\n\t\t\t\tfor (int y = 0; y < ysize; ++y)\n\t\t\t\t{\n\t\t\t\t\tfloat position_x = x / (float)(xsize - 1);\t// 0 to 1\n\t\t\t\t\tfloat position_y = y / (float)(ysize - 1);\t// 0 to 1\n\t\t\t\t\t\n\t\t\t\t\tfloat centerX = (float)(individualArea.origin.x + round(position_x * individualArea.size.width) + 0.5);\n\t\t\t\t\tfloat centerY = (float)(individualArea.origin.y + individualArea.size.height - round(position_y * individualArea.size.height) + 0.5);\n\t\t\t\t\tconst float margin = ((pass == 0) ? 5.5f : 3.5f);\n\t\t\t\t\tfloat left = centerX - margin;\n\t\t\t\t\tfloat top = centerY - margin;\n\t\t\t\t\tfloat right = centerX + margin;\n\t\t\t\t\tfloat bottom = centerY + margin;\n\t\t\t\t\t\n\t\t\t\t\tif (left < individualArea.origin.x)\n\t\t\t\t\t\tleft = (float)individualArea.origin.x;\n\t\t\t\t\tif (top < individualArea.origin.y)\n\t\t\t\t\t\ttop = (float)individualArea.origin.y;\n\t\t\t\t\tif (right > individualArea.origin.x + individualArea.size.width)\n\t\t\t\t\t\tright = (float)(individualArea.origin.x + individualArea.size.width);\n\t\t\t\t\tif (bottom > individualArea.origin.y + individualArea.size.height)\n\t\t\t\t\t\tbottom = (float)(individualArea.origin.y + individualArea.size.height);\n\t\t\t\t\t\n\t\t\t\t\t*(vertices++) = left;\n\t\t\t\t\t*(vertices++) = top;\n\t\t\t\t\t*(vertices++) = left;\n\t\t\t\t\t*(vertices++) = bottom;\n\t\t\t\t\t*(vertices++) = right;\n\t\t\t\t\t*(vertices++) = bottom;\n\t\t\t\t\t*(vertices++) = right;\n\t\t\t\t\t*(vertices++) = top;\n\t\t\t\t\t\n\t\t\t\t\tif (pass == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t\t\t\t*(colors++) = 0.25;\n\t\t\t\t\t\t\t*(colors++) = 0.25;\n\t\t\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// look up the map's color at this grid point\n\t\t\t\t\t\tfloat rgb[3];\n\t\t\t\t\t\tdouble value = values[x + y * xsize];\n\t\t\t\t\t\t\n\t\t\t\t\t\tbackground_map->ColorForValue(value, rgb);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t*(colors++) = rgb[0];\n\t\t\t\t\t\t\t*(colors++) = rgb[1];\n\t\t\t\t\t\t\t*(colors++) = rgb[2];\n\t\t\t\t\t\t\t*(colors++) = 1.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdisplayListIndex++;\n\t\t\t\t\t\n\t\t\t\t\t// If we've filled our buffers, get ready to draw more\n\t\t\t\t\tif (displayListIndex == kMaxGLRects)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Draw our arrays\n\t\t\t\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// And get ready to draw more\n\t\t\t\t\t\tvertices = glArrayVertices;\n\t\t\t\t\t\tcolors = glArrayColors;\n\t\t\t\t\t\tdisplayListIndex = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Draw any leftovers\n\t\tif (displayListIndex)\n\t\t{\n\t\t\t// Draw our arrays\n\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t}\n\t\t\n\t\tglDisableClientState(GL_VERTEX_ARRAY);\n\t\tglDisableClientState(GL_COLOR_ARRAY);\n\t}\n#endif\n}\n\n- (void)chooseDefaultBackgroundSettings:(PopulationViewBackgroundSettings *)background map:(SpatialMap **)returnMap forSubpopulation:(Subpopulation *)subpop\n{\n\t// black by default\n\tbackground->backgroundType = 0;\n\t\n\t// if there are spatial maps defined, we try to choose one, requiring \"x\" or \"y\" or \"xy\", and requiring\n\t// a color map to be defined, and preferring 2D over 1D, providing the same default behavior as SLiM 2.x\n\tSpatialMapMap &spatial_maps = subpop->spatial_maps_;\n\tSpatialMap *background_map = nullptr;\n\tstd::string background_map_name;\n\t\n\tfor (const auto &map_pair : spatial_maps)\n\t{\n\t\tSpatialMap *map = map_pair.second;\n\t\t\n\t\t// a map must be \"x\", \"y\", or \"xy\", and must have a defined color map, for us to choose it as a default at all\n\t\tif (((map->spatiality_string_ == \"x\") || (map->spatiality_string_ == \"y\") || (map->spatiality_string_ == \"xy\")) && (map->n_colors_ > 0))\n\t\t{\n\t\t\t// the map is usable, so now we check whether it's better than the map we previously found, if any\n\t\t\tif ((!background_map) || (map->spatiality_ > background_map->spatiality_))\n\t\t\t{\n\t\t\t\tbackground_map = map;\n\t\t\t\tbackground_map_name = map_pair.first;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (background_map)\n\t{\n\t\tbackground->backgroundType = 3;\n\t\tbackground->spatialMapName = background_map_name;\n\t\t*returnMap = background_map;\n\t}\n}\n\n- (void)drawSpatialBackgroundInBounds:(NSRect)bounds forSubpopulation:(Subpopulation *)subpop dimensionality:(int)dimensionality\n{\n\tauto backgroundIter = backgroundSettings.find(subpop->subpopulation_id_);\n\tPopulationViewBackgroundSettings background;\n\tSpatialMap *background_map = nil;\n\t\n\tif (backgroundIter == backgroundSettings.end())\n\t{\n\t\t// The user has not made a choice, so choose a temporary default.  We don't want this choice to \"stick\",\n\t\t// so that we can, e.g., begin as black and then change to a spatial map if one is defined.\n\t\t[self chooseDefaultBackgroundSettings:&background map:&background_map forSubpopulation:subpop];\n\t}\n\telse\n\t{\n\t\t// The user has made a choice; verify that it is acceptable, and then use it.\n\t\tbackground = backgroundIter->second;\n\t\t\n\t\tif (background.backgroundType == 3)\n\t\t{\n\t\t\tSpatialMapMap &spatial_maps = subpop->spatial_maps_;\n\t\t\tauto map_iter = spatial_maps.find(background.spatialMapName);\n\t\t\t\n\t\t\tif (map_iter != spatial_maps.end())\n\t\t\t{\n\t\t\t\tbackground_map = map_iter->second;\n\t\t\t\t\n\t\t\t\t// if the user somehow managed to choose a map that is not of an acceptable dimensionality, reject it here\n\t\t\t\tif ((background_map->spatiality_string_ != \"x\") && (background_map->spatiality_string_ != \"y\") && (background_map->spatiality_string_ != \"xy\"))\n\t\t\t\t\tbackground_map = nil;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if we're supposed to use a background map but we couldn't find it, or it's unacceptable, revert to black\n\t\tif ((background.backgroundType == 3) && !background_map)\n\t\t\tbackground.backgroundType = 0;\n\t}\n\t\n\tif ((background.backgroundType == 3) && background_map)\n\t{\n\t\t[self _drawBackgroundSpatialMap:background_map inBounds:bounds forSubpopulation:subpop];\n\t}\n\telse\n\t{\n\t\t// No background map, so just clear to the preferred background color\n\t\tint backgroundColor = background.backgroundType;\n\t\t\n\t\tif (backgroundColor == 0)\n\t\t\tglColor3f(0.0, 0.0, 0.0);\n\t\telse if (backgroundColor == 1)\n\t\t\tglColor3f(0.3f, 0.3f, 0.3f);\n\t\telse if (backgroundColor == 2)\n\t\t\tglColor3f(1.0, 1.0, 1.0);\n\t\telse\n\t\t\tglColor3f(0.0, 0.0, 0.0);\n\t\t\n\t\tglRecti((int)bounds.origin.x, (int)bounds.origin.y, (int)(bounds.origin.x + bounds.size.width), (int)(bounds.origin.y + bounds.size.height));\n\t}\n}\n\n- (void)drawSpatialIndividualsFromSubpopulation:(Subpopulation *)subpop inArea:(NSRect)bounds dimensionality:(int)dimensionality\n{\n\tSLiMWindowController *controller = [[self window] windowController];\n\tdouble scalingFactor = 0.8; // used to be controller->fitnessColorScale;\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\t\n\tNSRect individualArea = NSMakeRect(bounds.origin.x, bounds.origin.y, bounds.size.width - 1, bounds.size.height - 1);\n\t\n\tstatic float *glArrayVertices = nil;\n\tstatic float *glArrayColors = nil;\n\tint individualArrayIndex, displayListIndex;\n\tfloat *vertices = NULL, *colors = NULL;\n\t\n\t// Set up the vertex and color arrays\n\tif (!glArrayVertices)\n\t\tglArrayVertices = (float *)malloc(kMaxVertices * 2 * sizeof(float));\t\t// 2 floats per vertex, kMaxVertices vertices\n\t\n\tif (!glArrayColors)\n\t\tglArrayColors = (float *)malloc(kMaxVertices * 4 * sizeof(float));\t\t// 4 floats per color, kMaxVertices colors\n\t\n\t// Set up to draw rects\n\tdisplayListIndex = 0;\n\t\n\tvertices = glArrayVertices;\n\tglEnableClientState(GL_VERTEX_ARRAY);\n\tglVertexPointer(2, GL_FLOAT, 0, glArrayVertices);\n\t\n\tcolors = glArrayColors;\n\tglEnableClientState(GL_COLOR_ARRAY);\n\tglColorPointer(4, GL_FLOAT, 0, glArrayColors);\n\t\n\t// First we outline all individuals\n\tif (dimensionality == 1)\n\t\tsrandom(controller->community->Tick());\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n\t\tIndividual &individual = *subpop->parent_individuals_[individualArrayIndex];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n\t\t\tposition_x = (float)((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = (float)(random() / (double)INT32_MAX);\n\t\t\t\n\t\t\tif ((position_x < 0.0) || (position_x > 1.0))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tposition_x = (float)((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = (float)((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0) || (position_x > 1.0) || (position_y < 0.0) || (position_y > 1.0))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tfloat centerX = (float)(individualArea.origin.x + round(position_x * individualArea.size.width) + 0.5);\n\t\tfloat centerY = (float)(individualArea.origin.y + individualArea.size.height - round(position_y * individualArea.size.height) + 0.5);\n\t\t\n\t\tfloat left = centerX - 2.5f;\n\t\tfloat top = centerY - 2.5f;\n\t\tfloat right = centerX + 2.5f;\n\t\tfloat bottom = centerY + 2.5f;\n\t\t\n\t\tif (left < individualArea.origin.x) left = (float)individualArea.origin.x;\n\t\tif (top < individualArea.origin.y) top = (float)individualArea.origin.y;\n\t\tif (right > individualArea.origin.x + individualArea.size.width + 1) right = (float)(individualArea.origin.x + individualArea.size.width + 1);\n\t\tif (bottom > individualArea.origin.y + individualArea.size.height + 1) bottom = (float)(individualArea.origin.y + individualArea.size.height + 1);\n\t\t\n\t\t*(vertices++) = left;\n\t\t*(vertices++) = top;\n\t\t*(vertices++) = left;\n\t\t*(vertices++) = bottom;\n\t\t*(vertices++) = right;\n\t\t*(vertices++) = bottom;\n\t\t*(vertices++) = right;\n\t\t*(vertices++) = top;\n\t\t\n\t\tfor (int j = 0; j < 4; ++j)\n\t\t{\n\t\t\t*(colors++) = 0.25;\n\t\t\t*(colors++) = 0.25;\n\t\t\t*(colors++) = 0.25;\n\t\t\t*(colors++) = 1.0;\n\t\t}\n\t\t\n\t\tdisplayListIndex++;\n\t\t\n\t\t// If we've filled our buffers, get ready to draw more\n\t\tif (displayListIndex == kMaxGLRects)\n\t\t{\n\t\t\t// Draw our arrays\n\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\n\t\t\t// And get ready to draw more\n\t\t\tvertices = glArrayVertices;\n\t\t\tcolors = glArrayColors;\n\t\t\tdisplayListIndex = 0;\n\t\t}\n\t}\n\t\n\t// Then we draw all individuals\n\tif (dimensionality == 1)\n\t\tsrandom(controller->community->Tick());\n\t\n\tfor (individualArrayIndex = 0; individualArrayIndex < subpopSize; ++individualArrayIndex)\n\t{\n\t\t// Figure out the rect to draw in; note we now use individualArrayIndex here, because the hit-testing code doesn't have an easy way to calculate the displayed individual index...\n\t\tIndividual &individual = *subpop->parent_individuals_[individualArrayIndex];\n\t\tfloat position_x, position_y;\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n\t\t\tposition_x = (float)((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = (float)(random() / (double)INT32_MAX);\n\t\t\t\n\t\t\tif ((position_x < 0.0) || (position_x > 1.0))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tposition_x = (float)((individual.spatial_x_ - bounds_x0) / bounds_x_size);\n\t\t\tposition_y = (float)((individual.spatial_y_ - bounds_y0) / bounds_y_size);\n\t\t\t\n\t\t\tif ((position_x < 0.0) || (position_x > 1.0) || (position_y < 0.0) || (position_y > 1.0))\t\t// skip points that are out of bounds\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tfloat centerX = (float)(individualArea.origin.x + round(position_x * individualArea.size.width) + 0.5);\n\t\tfloat centerY = (float)(individualArea.origin.y + individualArea.size.height - round(position_y * individualArea.size.height) + 0.5);\n\t\tfloat left = centerX - 1.5f;\n\t\tfloat top = centerY - 1.5f;\n\t\tfloat right = centerX + 1.5f;\n\t\tfloat bottom = centerY + 1.5f;\n\t\t\n\t\t// clipping deliberately not done here; because individual rects are 3x3, they will fall at most one pixel\n\t\t// outside our drawing area, and thus the flaw will be covered by the view frame when it overdraws\n\t\t\n\t\t*(vertices++) = left;\n\t\t*(vertices++) = top;\n\t\t*(vertices++) = left;\n\t\t*(vertices++) = bottom;\n\t\t*(vertices++) = right;\n\t\t*(vertices++) = bottom;\n\t\t*(vertices++) = right;\n\t\t*(vertices++) = top;\n\t\t\n\t\t// dark gray default, for a fitness of NaN; should never happen\n\t\tfloat colorRed = 0.3f, colorGreen = 0.3f, colorBlue = 0.3f, colorAlpha = 1.0;\n\t\t\n\t\tif (Individual::s_any_individual_color_set_ && individual.color_set_)\n\t\t{\n\t\t\tcolorRed = individual.colorR_ / 255.0F;\n\t\t\tcolorGreen = individual.colorG_ / 255.0F;\n\t\t\tcolorBlue = individual.colorB_ / 255.0F;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// use individual trait values to determine color; we used fitness values cached in UpdateFitness, so we don't have to call out to mutationEffect() callbacks\n\t\t\t// we normalize fitness values with subpopFitnessScaling so individual fitness, unscaled by subpopulation fitness, is used for coloring\n\t\t\tdouble fitness = individual.cached_unscaled_fitness_;\n\t\t\t\n\t\t\tif (!std::isnan(fitness))\n\t\t\t\tRGBForFitness(fitness, &colorRed, &colorGreen, &colorBlue, scalingFactor);\n\t\t}\n\t\t\n\t\tfor (int j = 0; j < 4; ++j)\n\t\t{\n\t\t\t*(colors++) = colorRed;\n\t\t\t*(colors++) = colorGreen;\n\t\t\t*(colors++) = colorBlue;\n\t\t\t*(colors++) = colorAlpha;\n\t\t}\n\t\t\n\t\tdisplayListIndex++;\n\t\t\n\t\t// If we've filled our buffers, get ready to draw more\n\t\tif (displayListIndex == kMaxGLRects)\n\t\t{\n\t\t\t// Draw our arrays\n\t\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t\t\t\n\t\t\t// And get ready to draw more\n\t\t\tvertices = glArrayVertices;\n\t\t\tcolors = glArrayColors;\n\t\t\tdisplayListIndex = 0;\n\t\t}\n\t}\n\t\n\t// Draw any leftovers\n\tif (displayListIndex)\n\t{\n\t\t// Draw our arrays\n\t\tglDrawArrays(GL_QUADS, 0, 4 * displayListIndex);\n\t}\n\t\n\tglDisableClientState(GL_VERTEX_ARRAY);\n\tglDisableClientState(GL_COLOR_ARRAY);\n}\n\n- (void)drawRect:(NSRect)rect\n{\n\t//\n\t//\tNOTE this code is parallel to code in tileSubpopulations: and both should be maintained!\n\t//\n\t\n\tNSRect bounds = [self bounds];\n\tSLiMWindowController *controller = [[self window] windowController];\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\tstd::vector<Subpopulation*> selectedSubpopulations = [controller selectedSubpopulations];\n\tint selectedSubpopCount = (int)(selectedSubpopulations.size());\n\t\n\t// Decide on our display mode\n\tif (displaySpecies && (controller->community->Tick() >= 1))\n\t{\n\t\tif (displayMode == -1)\n\t\t\tdisplayMode = ((displaySpecies->spatial_dimensionality_ == 0) ? 0 : 1);\n\t\tif ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ == 0))\n\t\t\tdisplayMode = 0;\n\t}\n\t\n\t// Update the viewport; using backingBounds here instead of bounds makes the view hi-res-aware,\n\t// while still remaining point-based since the ortho projection we use below uses bounds.\n\tNSRect backingBounds = [self convertRectToBacking:bounds];\n\t\n\tglViewport(0, 0, (int)backingBounds.size.width, (int)backingBounds.size.height);\n\t\n\t// Update the projection\n\tglMatrixMode(GL_PROJECTION);\n\tGLKMatrix4 orthoMat = GLKMatrix4MakeOrtho(0.0, (int)bounds.size.width, (int)bounds.size.height, 0.0, -1.0f, 1.0f);\n\tglLoadMatrixf(orthoMat.m);\n\tglMatrixMode(GL_MODELVIEW);\n\t\n\tif (selectedSubpopCount == 0)\n\t{\n\t\t// clear to a shade of gray\n\t\tglColor3f(0.9f, 0.9f, 0.9f);\n\t\tglRecti(0, 0, (int)bounds.size.width, (int)bounds.size.height);\n\t\t\n\t\t// Frame our view\n\t\t[self drawViewFrameInBounds:bounds];\n\t}\n\telse if (selectedSubpopCount > 10)\n\t{\n\t\t// We should be hidden in this case, but just in case, let's draw...\n\t\t\n\t\t// clear to our \"too much information\" shade\n\t\tglColor3f(0.9f, 0.9f, 1.0f);\n\t\tglRecti(0, 0, (int)bounds.size.width, (int)bounds.size.height);\n\t\t\n\t\t// Frame our view\n\t\t[self drawViewFrameInBounds:bounds];\n\t}\n\telse\n\t{\n\t\tif (selectedSubpopulations.size() > 1)\n\t\t{\n\t\t\t// Clear to background gray; FIXME at present this hard-codes the OS X 10.10 background color...\n\t\t\tglColor3f(0.93f, 0.93f, 0.93f);\n\t\t\tglRecti(0, 0, (int)bounds.size.width, (int)bounds.size.height);\n\t\t}\n\t\t\n\t\tfor (Subpopulation *subpop : selectedSubpopulations)\n\t\t{\n\t\t\tauto tileIter = subpopTiles.find(subpop->subpopulation_id_);\n\t\t\t\n\t\t\tif (tileIter != subpopTiles.end())\n\t\t\t{\n\t\t\t\tNSRect tileBounds = tileIter->second;\n\t\t\t\t\n\t\t\t\tif ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ == 1))\n\t\t\t\t{\n\t\t\t\t\t[self drawSpatialBackgroundInBounds:tileBounds forSubpopulation:subpop dimensionality:displaySpecies->spatial_dimensionality_];\n\t\t\t\t\t[self drawSpatialIndividualsFromSubpopulation:subpop inArea:NSInsetRect(tileBounds, 1, 1) dimensionality:displaySpecies->spatial_dimensionality_];\n\t\t\t\t\t[self drawViewFrameInBounds:tileBounds];\n\t\t\t\t}\n\t\t\t\telse if ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ > 1))\n\t\t\t\t{\n\t\t\t\t\t// clear to a shade of gray\n\t\t\t\t\tglColor3f(0.9f, 0.9f, 0.9f);\n\t\t\t\t\tglRecti((int)tileBounds.origin.x, (int)tileBounds.origin.y, (int)(tileBounds.origin.x + tileBounds.size.width), (int)(tileBounds.origin.y + tileBounds.size.height));\n\t\t\t\t\t\n\t\t\t\t\t// Frame our view\n\t\t\t\t\t[self drawViewFrameInBounds:tileBounds];\n\t\t\t\t\t\n\t\t\t\t\t// Now determine a subframe and draw spatial information inside that.\n\t\t\t\t\tNSRect spatialDisplayBounds = [self spatialDisplayBoundsForSubpopulation:subpop tileBounds:tileBounds];\n\t\t\t\t\t\n\t\t\t\t\t[self drawSpatialBackgroundInBounds:spatialDisplayBounds forSubpopulation:subpop dimensionality:displaySpecies->spatial_dimensionality_];\n\t\t\t\t\t[self drawSpatialIndividualsFromSubpopulation:subpop inArea:spatialDisplayBounds dimensionality:displaySpecies->spatial_dimensionality_];\n\t\t\t\t\t[self drawViewFrameInBounds:NSInsetRect(spatialDisplayBounds, -1, -1)];\n\t\t\t\t}\n\t\t\t\telse\t// displayMode == 0\n\t\t\t\t{\n\t\t\t\t\t// Clear to white\n\t\t\t\t\tglColor3f(1.0, 1.0, 1.0);\n\t\t\t\t\tglRecti((int)tileBounds.origin.x, (int)tileBounds.origin.y, (int)(tileBounds.origin.x + tileBounds.size.width), (int)(tileBounds.origin.y + tileBounds.size.height));\n\t\t\t\t\t\n\t\t\t\t\t[self drawViewFrameInBounds:tileBounds];\n\t\t\t\t\t[self drawIndividualsFromSubpopulation:subpop inArea:tileBounds];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t[[self openGLContext] flushBuffer];\n}\n\n\n//\n//\tSubarea tiling\n//\n#pragma mark Subarea tiling\n\n- (BOOL)tileSubpopulations:(std::vector<Subpopulation*> &)selectedSubpopulations\n{\n\t//\n\t//\tNOTE this code is parallel to code in drawRect: and both should be maintained!\n\t//\n\t\n\t// We will decide upon new tiles for our subpopulations here, so start out empty\n\tsubpopTiles.clear();\n\t\n\tNSRect bounds = [self bounds];\n\tSLiMWindowController *controller = [[self window] windowController];\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\tint selectedSubpopCount = (int)selectedSubpopulations.size();\n\t\n\t// Decide on our display mode\n\tif (displaySpecies && (controller->community->Tick() >= 1))\n\t{\n\t\tif (displayMode == -1)\n\t\t\tdisplayMode = ((displaySpecies->spatial_dimensionality_ == 0) ? 0 : 1);\n\t\tif ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ == 0))\n\t\t\tdisplayMode = 0;\n\t}\n\t\n\tif (selectedSubpopCount == 0)\n\t{\n\t\treturn YES;\n\t}\n\telse if (selectedSubpopCount > 10)\n\t{\n\t\treturn NO;\n\t}\n\telse if (selectedSubpopCount == 1)\n\t{\n\t\tSubpopulation *selectedSubpop = selectedSubpopulations[0];\n\t\t\n\t\tsubpopTiles.emplace(selectedSubpop->subpopulation_id_, bounds);\n\t\t\n\t\tif ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ == 1))\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t\telse if ((displayMode == 1) && (displaySpecies->spatial_dimensionality_ > 1))\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn [self canDisplayIndividualsFromSubpopulation:selectedSubpop inArea:bounds];\n\t\t}\n\t}\n\telse if (displayMode == 1)\n\t{\n\t\t// spatial display adaptively finds the layout the maximizes the pixel area covered, and cannot fail\n\t\tint64_t bestTotalExtent = 0;\n\t\t\n\t\tfor (int rowCount = 1; rowCount <= selectedSubpopCount; ++rowCount)\n\t\t{\n\t\t\tint columnCount = (int)ceil(selectedSubpopCount / (double)rowCount);\n\t\t\tint interBoxSpace = 5;\n\t\t\tint totalInterboxHeight = interBoxSpace * (rowCount - 1);\n\t\t\tint totalInterboxWidth = interBoxSpace * (columnCount - 1);\n\t\t\tdouble boxWidth = (bounds.size.width - totalInterboxWidth) / (double)columnCount;\n\t\t\tdouble boxHeight = (bounds.size.height - totalInterboxHeight) / (double)rowCount;\n\t\t\tstd::map<slim_objectid_t, NSRect> candidateTiles;\n\t\t\tint64_t totalExtent = 0;\n\t\t\t\n\t\t\tfor (int subpopIndex = 0; subpopIndex < selectedSubpopCount; subpopIndex++)\n\t\t\t{\n\t\t\t\tint columnIndex = subpopIndex % columnCount;\n\t\t\t\tint rowIndex = subpopIndex / columnCount;\n\t\t\t\tdouble boxLeft = round(bounds.origin.x + columnIndex * (interBoxSpace + boxWidth));\n\t\t\t\tdouble boxRight = round(bounds.origin.x + columnIndex * (interBoxSpace + boxWidth) + boxWidth);\n\t\t\t\tdouble boxTop = round(bounds.origin.y + rowIndex * (interBoxSpace + boxHeight));\n\t\t\t\tdouble boxBottom = round(bounds.origin.y + rowIndex * (interBoxSpace + boxHeight) + boxHeight);\n\t\t\t\tNSRect boxBounds = NSMakeRect(boxLeft, boxTop, boxRight - boxLeft, boxBottom - boxTop);\n\t\t\t\tSubpopulation *subpop = selectedSubpopulations[subpopIndex];\n\t\t\t\t\n\t\t\t\tcandidateTiles.emplace(subpop->subpopulation_id_, boxBounds);\n\t\t\t\t\n\t\t\t\t// find out what pixel area actually gets used by this box, and use that to choose the optimal layout\n\t\t\t\tNSRect spatialDisplayBounds = [self spatialDisplayBoundsForSubpopulation:subpop tileBounds:boxBounds];\n\t\t\t\tint64_t extent = (int64_t)spatialDisplayBounds.size.width * (int64_t)spatialDisplayBounds.size.height;\n\t\t\t\t\n\t\t\t\ttotalExtent += extent;\n\t\t\t}\n\t\t\t\n\t\t\tif (totalExtent > bestTotalExtent)\n\t\t\t{\n\t\t\t\tbestTotalExtent = totalExtent;\n\t\t\t\tstd::swap(subpopTiles, candidateTiles);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn YES;\n\t}\n\telse\t// displayMode == 0\n\t{\n\t\t// non-spatial display always uses vertically stacked maximum-width tiles, but can fail if they are too small\n\t\tint interBoxSpace = 5;\n\t\tint totalInterbox = interBoxSpace * (selectedSubpopCount - 1);\n\t\tdouble boxHeight = (bounds.size.height - totalInterbox) / (double)selectedSubpopCount;\n\t\t\n\t\tfor (int subpopIndex = 0; subpopIndex < selectedSubpopCount; subpopIndex++)\n\t\t{\n\t\t\tdouble boxTop = round(bounds.origin.y + subpopIndex * (interBoxSpace + boxHeight));\n\t\t\tdouble boxBottom = round(bounds.origin.y + subpopIndex * (interBoxSpace + boxHeight) + boxHeight);\n\t\t\tNSRect boxBounds = NSMakeRect(bounds.origin.x, boxTop, bounds.size.width, boxBottom - boxTop);\n\t\t\tSubpopulation *subpop = selectedSubpopulations[subpopIndex];\n\t\t\t\n\t\t\tsubpopTiles.emplace(subpop->subpopulation_id_, boxBounds);\n\t\t\t\n\t\t\tif (![self canDisplayIndividualsFromSubpopulation:subpop inArea:boxBounds])\n\t\t\t{\n\t\t\t\tsubpopTiles.clear();\n\t\t\t\treturn NO;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn YES;\n\t}\n}\n\n- (BOOL)canDisplayIndividualsFromSubpopulation:(Subpopulation *)subpop inArea:(NSRect)bounds\n{\n\t//\n\t//\tNOTE this code is parallel to the code in drawIndividualsFromSubpopulation:inArea: and should be maintained in parallel\n\t//\n\t\n\tslim_popsize_t subpopSize = subpop->parent_subpop_size_;\n\tint squareSize, viewColumns = 0, viewRows = 0;\n\t\n\t// first figure out the biggest square size that will allow us to display the whole subpopulation\n\tfor (squareSize = 20; squareSize > 1; --squareSize)\n\t{\n\t\tviewColumns = (int)floor((bounds.size.width - 3) / squareSize);\n\t\tviewRows = (int)floor((bounds.size.height - 3) / squareSize);\n\t\t\n\t\tif (viewColumns * viewRows > subpopSize)\n\t\t{\n\t\t\t// If we have an empty row at the bottom, then break for sure; this allows us to look nice and symmetrical\n\t\t\tif ((subpopSize - 1) / viewColumns < viewRows - 1)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Otherwise, break only if we are getting uncomfortably small; otherwise, let's drop down one square size to allow symmetry\n\t\t\tif (squareSize <= 5)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn (squareSize > 1);\n}\n\n- (NSRect)spatialDisplayBoundsForSubpopulation:(Subpopulation *)subpop tileBounds:(NSRect)tileBounds\n{\n\t// Determine a subframe for drawing spatial information inside.  The subframe we use is the maximal subframe\n\t// with integer boundaries that preserves, as closely as possible, the aspect ratio of the subpop's bounds.\n\tNSRect spatialDisplayBounds = NSInsetRect(tileBounds, 1, 1);\n\tdouble displayAspect = spatialDisplayBounds.size.width / spatialDisplayBounds.size.height;\n\tdouble bounds_x0 = subpop->bounds_x0_, bounds_x1 = subpop->bounds_x1_;\n\tdouble bounds_y0 = subpop->bounds_y0_, bounds_y1 = subpop->bounds_y1_;\n\tdouble bounds_x_size = bounds_x1 - bounds_x0, bounds_y_size = bounds_y1 - bounds_y0;\n\tdouble subpopAspect = bounds_x_size / bounds_y_size;\n\t\n\tif (subpopAspect > displayAspect)\n\t{\n\t\t// The display bounds will need to shrink vertically to match the subpop\n\t\tdouble idealSize = round(spatialDisplayBounds.size.width / subpopAspect);\n\t\tdouble roundedOffset = round((spatialDisplayBounds.size.height - idealSize) / 2.0);\n\t\t\n\t\tspatialDisplayBounds.origin.y += roundedOffset;\n\t\tspatialDisplayBounds.size.height = idealSize;\n\t}\n\telse if (subpopAspect < displayAspect)\n\t{\n\t\t// The display bounds will need to shrink horizontally to match the subpop\n\t\tdouble idealSize = round(spatialDisplayBounds.size.height * subpopAspect);\n\t\tdouble roundedOffset = round((spatialDisplayBounds.size.width - idealSize) / 2.0);\n\t\t\n\t\tspatialDisplayBounds.origin.x += roundedOffset;\n\t\tspatialDisplayBounds.size.width = idealSize;\n\t}\n\t\n\treturn spatialDisplayBounds;\n}\n\n\n//\n//\tActions\n//\n#pragma mark Actions\n\n- (IBAction)setDisplayStyle:(id)sender\n{\n\tNSMenuItem *senderMenuItem = (NSMenuItem *)sender;\n\t\n\tdisplayMode = (int)[senderMenuItem tag];\n\t[self setNeedsDisplay:YES];\n\t[[[self window] windowController] updatePopulationViewHiding];\n}\n\n- (IBAction)setDisplayBackground:(id)sender\n{\n\tNSMenuItem *senderMenuItem = (NSMenuItem *)sender;\n\tint newDisplayBackground = (int)([senderMenuItem tag] - 10);\n\tauto backgroundIter = backgroundSettings.find(lastContextMenuSubpopID);\n\tPopulationViewBackgroundSettings *background = ((backgroundIter == backgroundSettings.end()) ? nil : &backgroundIter->second);\n\tstd::string mapName;\n\t\n\t// If the user has selected a spatial map, extract its name\n\tif (newDisplayBackground == 3)\n\t{\n\t\tNSString *menuItemTitle = [senderMenuItem title];\n\t\tNSArray<NSString *> *parts = [menuItemTitle componentsSeparatedByString:@\"\\\"\"];\n\t\t\n\t\tif ([parts count] == 5)\n\t\t{\n\t\t\tNSString *mapNameString = [parts objectAtIndex:1];\n\t\t\tconst char *mapNameString_inner = [mapNameString UTF8String];\n\t\t\t\n\t\t\tmapName = std::string(mapNameString_inner);\n\t\t}\n\t\t\n\t\tif (mapName.length() == 0)\n\t\t\treturn;\n\t}\n\t\n\tif (background)\n\t{\n\t\tbackground->backgroundType = newDisplayBackground;\n\t\tbackground->spatialMapName = mapName;\n\t\t[self setNeedsDisplay:YES];\n\t}\n\telse\n\t{\n\t\tbackgroundSettings.emplace(lastContextMenuSubpopID, PopulationViewBackgroundSettings{newDisplayBackground, mapName});\n\t\t[self setNeedsDisplay:YES];\n\t}\n}\n\n- (NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tSLiMWindowController *controller = [[self window] windowController];\n\tSpecies *displaySpecies = [controller focalDisplaySpecies];\n\tbool disableAll = false;\n\t\n\t// When the simulation is not valid and initialized, the context menu is disabled\n\tif (!displaySpecies || (controller->community->Tick() < 1))\n\t\tdisableAll = true;\n\t\n\tNSMenu *menu = [[NSMenu alloc] initWithTitle:@\"population_menu\"];\n\tNSMenuItem *menuItem;\n\t\n\t[menu setAutoenablesItems:NO];\n\t\n\tmenuItem = [menu addItemWithTitle:@\"Display Individuals (non-spatial)\" action:@selector(setDisplayStyle:) keyEquivalent:@\"\"];\n\t[menuItem setTag:0];\n\t[menuItem setTarget:self];\n\t[menuItem setEnabled:!disableAll];\n\t\n\tmenuItem = [menu addItemWithTitle:@\"Display Individuals (spatial)\" action:@selector(setDisplayStyle:) keyEquivalent:@\"\"];\n\t[menuItem setTag:1];\n\t[menuItem setTarget:self];\n\t[menuItem setEnabled:(!disableAll && (displaySpecies->spatial_dimensionality_ > 0))];\n\t\n\tmenuItem = [menu addItemWithTitle:@\"Display Fitness Line Plot (per subpopulation)...\" action:@selector(setDisplayStyle:) keyEquivalent:@\"\"];\n\t[menuItem setTag:2];\n\t[menuItem setTarget:self];\n\t[menuItem setEnabled:!disableAll];\n\t\n\tmenuItem = [menu addItemWithTitle:@\"Display Fitness Bar Plot (aggregated)...\" action:@selector(setDisplayStyle:) keyEquivalent:@\"\"];\n\t[menuItem setTag:3];\n\t[menuItem setTarget:self];\n\t[menuItem setEnabled:!disableAll];\n\t\n\t// Check the item corresponding to our current display preference, if any\n\tif (!disableAll)\n\t{\n\t\tmenuItem = [menu itemWithTag:displayMode];\n\t\t[menuItem setState:NSOnState];\n\t}\n\t\n\t// If we're displaying spatially, provide background options (colors, spatial maps)\n\tif (!disableAll && (displaySpecies->spatial_dimensionality_ > 0) && (displayMode == 1))\n\t{\n\t\t// determine which subpopulation the click was in\n\t\tstd::vector<Subpopulation*> selectedSubpopulations = [controller selectedSubpopulations];\n\t\tSubpopulation *subpopForEvent = nullptr;\n\t\tNSPoint eventPoint = [theEvent locationInWindow];\n\t\tNSPoint viewPoint = [self convertPoint:eventPoint fromView:nil];\n\t\t\n\t\t// our tile coordinates are in the OpenGL coordinate system, which has the origin at top left\n\t\tviewPoint.y = [self bounds].size.height - viewPoint.y;\n\t\t\n\t\tfor (Subpopulation *subpop : selectedSubpopulations)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop->subpopulation_id_;\n\t\t\tauto tileIter = subpopTiles.find(subpop_id);\n\t\t\t\n\t\t\tif (tileIter != subpopTiles.end())\n\t\t\t{\n\t\t\t\tNSRect tileRect = tileIter->second;\n\t\t\t\t\n\t\t\t\tif (NSPointInRect(viewPoint, tileRect))\n\t\t\t\t{\n\t\t\t\t\tsubpopForEvent = subpop;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (subpopForEvent)\n\t\t{\n\t\t\t[menu addItem:[NSMenuItem separatorItem]];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:[NSString stringWithFormat:@\"Background for p%d:\", subpopForEvent->subpopulation_id_] action:NULL keyEquivalent:@\"\"];\n\t\t\t[menuItem setTag:-1];\n\t\t\t[menuItem setEnabled:false];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Black Background\" action:@selector(setDisplayBackground:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTag:10];\n\t\t\t[menuItem setTarget:self];\n\t\t\t[menuItem setEnabled:!disableAll];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"Gray Background\" action:@selector(setDisplayBackground:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTag:11];\n\t\t\t[menuItem setTarget:self];\n\t\t\t[menuItem setEnabled:!disableAll];\n\t\t\t\n\t\t\tmenuItem = [menu addItemWithTitle:@\"White Background\" action:@selector(setDisplayBackground:) keyEquivalent:@\"\"];\n\t\t\t[menuItem setTag:12];\n\t\t\t[menuItem setTarget:self];\n\t\t\t[menuItem setEnabled:!disableAll];\n\t\t\t\n\t\t\t// look for spatial maps to offer as choices; need to scan the defined maps for the ones we can use\n\t\t\tSpatialMapMap &spatial_maps = subpopForEvent->spatial_maps_;\n\t\t\t\n\t\t\tfor (const auto &map_pair : spatial_maps)\n\t\t\t{\n\t\t\t\tSpatialMap *map = map_pair.second;\n\t\t\t\t\n\t\t\t\t// We used to display only maps with a color scale; now we just make up a color scale if none is given.  Only\n\t\t\t\t// \"x\", \"y\", and \"xy\" maps are considered displayable; We can't display a z coordinate, and we can't display\n\t\t\t\t// even the x or y portion of \"xz\", \"yz\", and \"xyz\" maps since we don't know which z-slice to use.\n\t\t\t\tbool displayable = ((map->spatiality_string_ == \"x\") || (map->spatiality_string_ == \"y\") || (map->spatiality_string_ == \"xy\"));\n\t\t\t\tNSString *menuItemTitle;\n\t\t\t\t\n\t\t\t\tif (map->spatiality_ == 1)\n\t\t\t\t\tmenuItemTitle = [NSString stringWithFormat:@\"Spatial Map \\\"%s\\\" (\\\"%s\\\", %d)\", map_pair.first.c_str(), map->spatiality_string_.c_str(), (int)map->grid_size_[0]];\n\t\t\t\telse if (map->spatiality_ == 2)\n\t\t\t\t\tmenuItemTitle = [NSString stringWithFormat:@\"Spatial Map \\\"%s\\\" (\\\"%s\\\", %d×%d)\", map_pair.first.c_str(), map->spatiality_string_.c_str(), (int)map->grid_size_[0], (int)map->grid_size_[1]];\n\t\t\t\telse // (map->spatiality_ == 3)\n\t\t\t\t\tmenuItemTitle = [NSString stringWithFormat:@\"Spatial Map \\\"%s\\\" (\\\"%s\\\", %d×%d×%d)\", map_pair.first.c_str(), map->spatiality_string_.c_str(), (int)map->grid_size_[0], (int)map->grid_size_[1], (int)map->grid_size_[2]];\n\t\t\t\t\n\t\t\t\tmenuItem = [menu addItemWithTitle:menuItemTitle action:@selector(setDisplayBackground:) keyEquivalent:@\"\"];\n\t\t\t\t[menuItem setTag:13];\n\t\t\t\t[menuItem setTarget:self];\n\t\t\t\t[menuItem setEnabled:(!disableAll && displayable)];\n\t\t\t}\n\t\t\t\n\t\t\t// check the menu item for the preferred display option; if we're in auto mode, don't check anything (could put a dash by the currently chosen style?)\n\t\t\tauto backgroundIter = backgroundSettings.find(subpopForEvent->subpopulation_id_);\n\t\t\tPopulationViewBackgroundSettings *background = ((backgroundIter == backgroundSettings.end()) ? nil : &backgroundIter->second);\n\t\t\t\n\t\t\tif (background)\n\t\t\t{\n\t\t\t\tmenuItem = nil;\n\t\t\t\t\n\t\t\t\tif (background->backgroundType == 3)\n\t\t\t\t{\n\t\t\t\t\t// We have to find the menu item to check by scanning and looking for the right title\n\t\t\t\t\tNSString *chosenMapPrefix = [NSString stringWithFormat:@\"Spatial Map \\\"%s\\\" (\\\"\", background->spatialMapName.c_str()];\n\t\t\t\t\tNSArray<NSMenuItem *> *menuItems = [menu itemArray];\n\t\t\t\t\t\n\t\t\t\t\tfor (NSMenuItem *item : menuItems)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ([[item title] hasPrefix:chosenMapPrefix])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmenuItem = item;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We can find the menu item to check by tag\n\t\t\t\t\tmenuItem = [menu itemWithTag:background->backgroundType + 10];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t[menuItem setState:NSOnState];\n\t\t\t}\n\t\t\t\n\t\t\t// remember which subpopulation this context menu is for\n\t\t\tlastContextMenuSubpopID = subpopForEvent->subpopulation_id_;\n\t\t}\n\t}\n\t\n\treturn [menu autorelease];\n}\n\n@end\n\n\n@implementation PopulationErrorView\n\n- (void)drawMessage:(NSString *)messageString inRect:(NSRect)rect\n{\n\tstatic NSDictionary *attrs = nil;\n\t\n\tif (!attrs)\n\t\tattrs = [@{NSFontAttributeName : [NSFont fontWithName:@\"Times New Roman\" size:14], NSForegroundColorAttributeName : [NSColor colorWithCalibratedWhite:0.4 alpha:1.0]} retain];\n\t\n\tNSAttributedString *attrMessage = [[NSAttributedString alloc] initWithString:messageString attributes:attrs];\n\tNSPoint centerPoint = NSMakePoint(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height / 2);\n\tNSSize messageSize = [attrMessage size];\n\tNSPoint drawPoint = NSMakePoint(centerPoint.x - messageSize.width / 2.0, centerPoint.y - messageSize.height / 2.0);\n\t\n\t[attrMessage drawAtPoint:drawPoint];\n\t[attrMessage release];\n}\n\n- (void)drawRect:(NSRect)rect\n{\n\tNSRect bounds = [self bounds];\n\t\n\t// Erase background\n\t[[NSColor colorWithDeviceWhite:0.9 alpha:1.0] set];\n\tNSRectFill(bounds);\n\t\n\t// Frame the view\n\t[[NSColor colorWithDeviceWhite:0.77 alpha:1.0] set];\n\tNSFrameRect(bounds);\n\t\n\t// Draw the message\n\t[self drawMessage:@\"too many subpops\\n   or individuals\\n     to display –\\n  control-click to\\n select a different\\n    display mode\" inRect:NSInsetRect(bounds, 1, 1)];\n}\n\n- (BOOL)isOpaque\n{\n\treturn YES;\n}\n\n- (NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tSLiMWindowController *controller = [[self window] windowController];\n\tPopulationView *popView = controller->populationView;\n\t\n\treturn [popView menuForEvent:theEvent];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.1 - Temporally varying selection.txt",
    "content": "// Keywords: environmental change\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // beneficial\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.995,0.005));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n2000:3999 mutationEffect(m2) { return 1.0; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.2 - Spatially varying selection.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"e\", 0.1);   // deleterious in p2\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.1);   // weak migration p2 -> p1\n\tp2.setMigrationRates(p1, 0.5);   // strong migration p1 -> p2\n}\nmutationEffect(m2, p2) { return 1/effect; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis I.txt",
    "content": "// Keywords: gene interactions\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // epistatic mut 1\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.1);  // epistatic mut 2\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);    // epistatic locus 1\n\tinitializeGenomicElementType(\"g3\", m3, 1);    // epistatic locus 2\n\tinitializeGenomicElement(g1, 0, 10000);\n\tinitializeGenomicElement(g2, 10001, 13000);\n\tinitializeGenomicElement(g1, 13001, 70000);\n\tinitializeGenomicElement(g3, 70001, 73000);\n\tinitializeGenomicElement(g1, 73001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m3) {\n\tif (individual.countOfMutationsOfType(m2))\n\t\treturn 0.5;\n\telse\n\t\treturn effect;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.3.1 - Fitness as a function of genomic background, Epistasis II.txt",
    "content": "// Keywords: gene interactions\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);  // epistatic mut 1\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.1);  // epistatic mut 2\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);    // epistatic locus 1\n\tinitializeGenomicElementType(\"g3\", m3, 1);    // epistatic locus 2\n\tinitializeGenomicElement(g1, 0, 10000);\n\tinitializeGenomicElement(g2, 10001, 13000);\n\tinitializeGenomicElement(g1, 13001, 70000);\n\tinitializeGenomicElement(g3, 70001, 73000);\n\tinitializeGenomicElement(g1, 73001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m3) {\n\tif (individual.countOfMutationsOfType(m2))\n\t\treturn 0.5;\n\telse\n\t\treturn effect;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // balanced\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\treturn 1.5 - sim.mutationFrequencies(p1, mut);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // positive freq. dep.\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\treturn 1.0 + sim.mutationFrequencies(p1, mut);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.4.1 - Fitness as a function of population composition, Frequency-dependent selection III.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);    // positive freq. dep.\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\nmutationEffect(m2) {\n\tdominance = asInteger(homozygous) * 0.5 + 0.5;\n\treturn 1.0 + sim.mutationFrequencies(p1, mut) * dominance;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.4.2 - Fitness as a function of population composition, Cultural effects on fitness.txt",
    "content": "// Keywords: culture, non-genetic inheritance\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);   // lactase-promoting\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n10000 early() { sim.simulationFinished(); }\nlate() {\n\t// Assign a cultural group: milk-drinker == T, non-milk-drinker == F\n\tp1.individuals.tagL0 = (runif(1000) < 0.5);\n}\nmutationEffect(m2) {\n\tif (individual.tagL0)\n\t\treturn effect;      // beneficial for milk-drinkers\n\telse\n\t\treturn 1.0;         // neutral for non-milk-drinkers\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.4.3 - Fitness as a function of population composition, Kin selection and the green-beard effect.txt",
    "content": "// Keywords: kin selection, inclusive fitness, selfish gene, greenbeard effect\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // green-beard\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1 late() {\n\ttarget = sample(p1.haplosomes, 100);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1: late() {\n\tp1.individuals.tag = 0;\n\t\n\tfor (rep in 1:50) {\n\t\tindividuals = sample(p1.individuals, 2);\n\t\ti0 = individuals[0];\n\t\ti1 = individuals[1];\n\t\ti0greenbeards = i0.countOfMutationsOfType(m2);\n\t\ti1greenbeards = i1.countOfMutationsOfType(m2);\n\t\t\n\t\tif (i0greenbeards & i1greenbeards) {\n\t\t\talleleSum = i0greenbeards + i1greenbeards;\n\t\t\ti0.tag = i0.tag - alleleSum;       // cost to i0\n\t\t\ti1.tag = i1.tag + alleleSum * 2;   // benefit to i1\n\t\t}\n\t}\n}\nmutationEffect(m2) { return 1.0 + individual.tag / 10; }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.5 - Changing selection coefficients with setSelectionCoeff().txt",
    "content": "// Keywords: environmental change, temporal change\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);    // neutral\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1);    // balanced\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(999,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nlate() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\tfor (mut in m2muts, freq in freqs)\n\t\tmut.setSelectionCoeff(0.5 - freq);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.6 - Varying the dominance coefficient among mutations I.txt",
    "content": "// Keywords: dominance coefficients, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.05);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation(m2) {\n\tmut.setValue(\"dom\", runif(1));\n\treturn T;\n}\nmutationEffect(m2) {\n   if (homozygous)\n      return 1.0 + mut.selectionCoeff;\n   else\n      return 1.0 + mut.getValue(\"dom\") * mut.selectionCoeff;\n}\n100000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 10.6 - Varying the dominance coefficient among mutations II.txt",
    "content": "// Keywords: dominance coefficients, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tfor (i in 0:10)\n\t\tinitializeMutationType(i, i * 0.1, \"n\", 0.0, 0.02);\n\tinitializeGenomicElementType(\"g1\", m0, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation(m0) {\n\ts = mut.selectionCoeff;\n\td = asInteger(min(floor(abs(s) * 100.0), 10.0));\n\tmut.setMutationType(d);\n\treturn T;\n}\n100000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 11.1 - Assortative mating.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.setValue(\"FST\", 0.0);\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.1);\n\tp2.setMigrationRates(p1, 0.1);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\nmutationEffect(m2, p2) { return 0.2; }\n2000: early() {\n\t// tag all individuals with their m2 mutation count\n\tinds = sim.subpopulations.individuals;\n\tinds.tag = inds.countOfMutationsOfType(m2);\n\t\n\t// precalculate the mating weights vectors\n\tfor (subpop in c(p1,p2))\n\t{\n\t\thas_m2 = (subpop.individuals.tag > 0);\n\t\tsubpop.setValue(\"weights1\", ifelse(has_m2, 2.0, 1.0));\n\t\tsubpop.setValue(\"weights2\", ifelse(has_m2, 0.5, 1.0));\n\t}\n}\n2000: mateChoice() {\n\tif (individual.tag > 0)\n\t\treturn weights * sourceSubpop.getValue(\"weights1\");\n\telse\n\t\treturn weights * sourceSubpop.getValue(\"weights2\");\n}\n10000: late() {\n\tFST = calcFST(p1.haplosomes, p2.haplosomes);\n\tsim.setValue(\"FST\", sim.getValue(\"FST\") + FST);\n}\n19999 late() {\n\tcat(\"Mean FST at equilibrium: \" + (sim.getValue(\"FST\") / 10000));\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 11.2 - Sequential mate search I.txt",
    "content": "// Keywords: choosy, choosiness, ornament, mate choice\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);     // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.025);  // ornamental\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1:10001 early() {\n\tif (sim.cycle % 1000 == 1) {\n\t\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\t\tosize = fixedMuts * 2 + p1.individuals.countOfMutationsOfType(m2);\n\t\tcatn(sim.cycle + \": Mean ornament size == \" + mean(osize));\n\t}\n}\nmateChoice() {\n\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\tfor (attempt in 1:5)\n\t{\n\t\tmate = sample(p1.individuals, 1, T, weights);\n\t\tosize = fixedMuts * 2 + mate.countOfMutationsOfType(m2);\n\t\t\n\t\tif (runif(1) < log(osize + 1) * 0.1 + attempt * 0.1)\n\t\t\treturn mate;\n\t}\n\treturn float(0);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 11.2 - Sequential mate search II.txt",
    "content": "// Keywords: choosy, choosiness, ornament, mate choice\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);     // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.025);  // ornamental\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1:10001 early() {\n\tfixedMuts = sum(sim.substitutions.mutationType == m2);\n\tinds = p1.individuals;\n\tosize = fixedMuts * 2 + inds.countOfMutationsOfType(m2);\n\tinds.tagF = log(osize + 1) * 0.1;\n\t\n\tif (sim.cycle % 1000 == 1)\n\t\tcatn(sim.cycle + \": Mean ornament size == \" + mean(osize));\n}\nmateChoice() {\n\tfor (attempt in 1:5)\n\t{\n\t\tmate = sample(p1.individuals, 1, T, weights);\n\t\t\n\t\tif (runif(1) < mate.tagF + attempt * 0.1)\n\t\t\treturn mate;\n\t}\n\treturn float(0);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 11.3 - Gametophytic self-incompatibility.txt",
    "content": "// Keywords: modifyChild(), plants, pollen\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // S-locus mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 21000);\n\tinitializeGenomicElement(g1, 21001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() {\n\tcat(\"m1 mutation count: \" + sim.countOfMutationsOfType(m1) + \"\\n\");\n\tcat(\"m2 mutation count: \" + sim.countOfMutationsOfType(m2) + \"\\n\");\n}\nmodifyChild(p1) {\n\tpollenSMuts = child.haploidGenome2.mutationsOfType(m2);\n\tstyleSMuts1 = parent1.haploidGenome1.mutationsOfType(m2);\n\tstyleSMuts2 = parent1.haploidGenome2.mutationsOfType(m2);\n\tif (identical(pollenSMuts, styleSMuts1))\n\t\tif (runif(1) < 0.99)\n\t\t\treturn F;\n\tif (identical(pollenSMuts, styleSMuts2))\n\t\tif (runif(1) < 0.99)\n\t\t\treturn F;\n\treturn T;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.1 - Social learning of cultural traits.txt",
    "content": "// Keywords: non-genetic inheritance\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);   // lactase-promoting\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.99,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.individuals.tagL0 = (runif(1000) < 0.5);\n}\nmodifyChild() {\n\tparentCulture = mean(c(parent1.tagL0, parent2.tagL0));\n\tchildCulture = (runif(1) < 0.1 + 0.8 * parentCulture);\n\tchild.tagL0 = childCulture;\n\treturn T;\n}\nmutationEffect(m2) {\n\tif (individual.tagL0)\n\t\treturn effect;      // beneficial for milk-drinkers\n\telse\n\t\treturn 1.0;         // neutral for non-milk-drinkers\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.2 - Lethal epistasis I.txt",
    "content": "// Keywords: gene interaction\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);  // mutation A\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.5);  // mutation B\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m2, 10000);  // add A\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m3, 20000);  // add B\n}\nmodifyChild() {\n\thasMutA = any(child.haplosomes.countOfMutationsOfType(m2) > 0);\n\thasMutB = any(child.haplosomes.countOfMutationsOfType(m3) > 0);\n\tif (hasMutA & hasMutB)\n\t\treturn F;\n\treturn T;\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.2 - Lethal epistasis II.txt",
    "content": "// Keywords: gene interaction\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);  // mutation A\n\tm2.convertToSubstitution = F;\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.5);  // mutation B\n\tm3.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m2, 10000);  // add A\n\tsample(p1.haplosomes, 20).addNewDrawnMutation(m3, 20000);  // add B\n}\nmodifyChild() {\n\tmutACount = sum(child.haplosomes.countOfMutationsOfType(m2));\n\tmutBCount = sum(child.haplosomes.countOfMutationsOfType(m3));\n\tif ((mutACount == 2) & (mutBCount == 2))\n\t\treturn F;\n\treturn T;\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.3 - Simulating gene drive.txt",
    "content": "// Keywords: migration, dispersal, CRISPR gene drive\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.1);  // MCR complex\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 0:5)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 1:5)\n\t\tsim.subpopulations[i].setMigrationRates(i-1, 0.001);\n\tfor (i in 0:4)\n\t\tsim.subpopulations[i].setMigrationRates(i+1, 0.1);\n}\n100 late() {\n\tp0.haplosomes[0:49].addNewDrawnMutation(m2, 10000);\n}\n100:10000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = any(sim.substitutions.mutationType == m2);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\nmutationEffect(m2) {\n\treturn 1.5 - subpop.id * 0.15;\n}\n100:10000 modifyChild() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 1)\n\t{\n\t\thasMutOnChromosome1 = child.haploidGenome1.containsMutations(mut);\n\t\thasMutOnChromosome2 = child.haploidGenome2.containsMutations(mut);\n\t\tif (hasMutOnChromosome1 & !hasMutOnChromosome2)\n\t\t\tchild.haploidGenome2.addMutations(mut);\n\t\telse if (hasMutOnChromosome2 & !hasMutOnChromosome1)\n\t\t\tchild.haploidGenome1.addMutations(mut);\n\t}\n\treturn T;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.4 - Suppressing hermaphroditic selfing.txt",
    "content": "// Keywords: selfing\n\n// NOTE: This model is now obsolete!  Is it now recommended\n// that you use this call in your initialize() callback\n// instead of following this recipe:\n//\n//    initializeSLiMOptions(preventIncidentalSelfing=T);\n//\n// This recipe still works, but is much slower than using\n// that configuration flag.\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nmodifyChild()\n{\n\t// prevent hermaphroditic selfing\n\tif (parent1 == parent2)\n\t\treturn F;\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 12.5 - Tracking separate sexes in script.txt",
    "content": "// Keywords: separate sexes, sexual model, sex chromosomes, sex ratio, Wolbachia\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.tagL0 = repEach(c(F,T), 250);  // f==F, m==T\n}\nmodifyChild() {\n\tif (parent1.tagL0 == parent2.tagL0)\n\t\treturn F;\n\tchild.tagL0 = (runif(1) <= 0.5);\n\treturn T;\n}\n1: late() {\n\tcatn(\"Sex ratio (M:M+F): \" + mean(p1.individuals.tagL0));\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.1 - Polygenic selection.txt",
    "content": "// Keywords: quantitative trait, polygenic selection\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // QTLs\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 30000);\n\tinitializeGenomicElement(g1, 30001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\nfitnessEffect() {\n\tphenotype = individual.countOfMutationsOfType(m2);\n\treturn 1.5 - (phenotype - 10.0)^2 * 0.005;\n}\n5000 late() {\n\tprint(sim.mutationFrequencies(NULL, sim.mutationsOfType(m2)));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.2 - A simple model of variable QTL effect sizes.txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.5);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1);\n\tinitializeGenomicElementType(\"g2\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 20000);\n\tinitializeGenomicElement(g2, 20001, 30000);\n\tinitializeGenomicElement(g1, 30001, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() { sim.addSubpop(\"p1\", 500); }\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.5 - (phenotypes - 10.0)^2 * 0.005;\n\t\n\tif (sim.cycle % 100 == 0)\n\t\tcatn(sim.cycle + \": Mean phenotype == \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.3 - A model of discrete QTL effects across multiple chromosomes.txt",
    "content": "// Keywords: migration, dispersal, QTL, quantitative trait loci\n\ninitialize() {\n\t// neutral mutations in non-coding regions\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// mutations representing alleles in QTLs\n\tscriptForQTLs = \"if (runif(1) < 0.5) -1; else 1;\";\n\tinitializeMutationType(\"m2\", 0.5, \"s\", scriptForQTLs);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tm2.convertToSubstitution = F;\n\tm2.mutationStackPolicy = \"l\";\n\t\n\t// set up our chromosome: 10 QTLs, surrounded by neutral regions\n\tdefineConstant(\"C\", 10);    // number of QTLs / chromosomes\n\tdefineConstant(\"W\", 1000);  // size of neutral buffer on each side\n\t\n\tfor (i in 1:C)\n\t{\n\t\tinitializeChromosome(i, W*2 + 1);\n\t\t\n\t\tinitializeGenomicElement(g1, 0, W-1);\n\t\tinitializeGenomicElement(g2, W, W);\n\t\tinitializeGenomicElement(g1, W+1, W+1 + W-1);\n\t\t\n\t\tinitializeMutationRate(1e-6);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\t\n\t// set up migration; comment these out for zero gene flow\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n\t\n\t// optional: give m2 mutations to everyone, as standing variation\n\tindividuals = sim.subpopulations.individuals;\n\t\n\tfor (i in 1:C)\n\t{\n\t\tg = sim.subpopulations.individuals.haplosomesForChromosomes(i);\n\t\tisPlus = asLogical(rbinom(size(g), 1, 0.5));\n\t\tg[isPlus].addNewMutation(m2, 1.0, W);\n\t\tg[!isPlus].addNewMutation(m2, -1.0, W);\n\t}\n}\nmutationEffect(m2) { return 1.0; }\n1: late() {\n\t// evaluate and save the additive effects of QTLs\n\tfor (subpop in c(p1,p2))\n\t{\n\t\tinds = subpop.individuals;\n\t\tphenotype = inds.sumOfMutationsOfType(m2);\n\t\toptimum = (subpop == p1 ? 10.0 else -10.0);\n\t\tinds.fitnessScaling = 1.0 + dnorm(optimum - phenotype, 0.0, 5.0);\n\t\tinds.tagF = phenotype;\n\t}\n}\nmateChoice() {\n\tphenotype = individual.tagF;\n\tothers = sourceSubpop.individuals.tagF;\n\treturn weights * dnorm(others, phenotype, 5.0);\n}\nc(2,2001) early() {\n\tcat(\"-------------------------------\\n\");\n\tcat(\"Output for end of cycle \" + (sim.cycle - 1) + \":\\n\\n\");\n\t\n\t// Output population fitness values\n\tcat(\"p1 mean fitness = \" + mean(p1.cachedFitness(NULL)) + \"\\n\");\n\tcat(\"p2 mean fitness = \" + mean(p2.cachedFitness(NULL)) + \"\\n\");\n\t\n\t// Output population additive QTL-based phenotypes\n\tcat(\"p1 mean phenotype = \" + mean(p1.individuals.tagF) + \"\\n\");\n\tcat(\"p2 mean phenotype = \" + mean(p2.individuals.tagF) + \"\\n\");\n\t\n\t// Output frequencies of +1/-1 alleles at the QTLs\n\tmuts = sim.mutationsOfType(m2);\n\tplus = muts[muts.selectionCoeff == 1.0];\n\tminus = muts[muts.selectionCoeff == -1.0];\n\t\n\tcat(\"\\nOverall frequencies:\\n\\n\");\n\tfor (i in 1:C)\n\t{\n\t\tiPlus = plus[plus.chromosome.id == i];\n\t\tiMinus = minus[minus.chromosome.id == i];\n\t\tpf = sum(sim.mutationFrequencies(NULL, iPlus));\n\t\tmf = sum(sim.mutationFrequencies(NULL, iMinus));\n\t\tpf1 = sum(sim.mutationFrequencies(p1, iPlus));\n\t\tmf1 = sum(sim.mutationFrequencies(p1, iMinus));\n\t\tpf2 = sum(sim.mutationFrequencies(p2, iPlus));\n\t\tmf2 = sum(sim.mutationFrequencies(p2, iMinus));\n\t\t\n\t\tcat(\"   QTL \" + i + \": f(+) == \" + pf + \", f(-) == \" + mf + \"\\n\");\n\t\tcat(\"         in p1: f(+) == \" + pf1 + \", f(-) == \" + mf1 + \"\\n\");\n\t\tcat(\"         in p2: f(+) == \" + pf2 + \", f(-) == \" + mf2 + \"\\n\\n\");\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.4 - A quantitative genetics model with heritability.txt",
    "content": "// Keywords: QTLs, quantitative trait loci, heritability, environmental variance, breeding values, additive genetic variance\n\ninitialize() {\n\tdefineConstant(\"h2\", 0.1);     // target heritability\n\n\tinitializeMutationRate(1e-6);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);  // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n1: late() {\n\t// sum the additive effects of QTLs\n\tinds = sim.subpopulations.individuals;\n\tadditive = inds.sumOfMutationsOfType(m2);\n\t\n\t// model environmental variance, according to the target heritability\n\tV_A = sd(additive)^2;\n\tV_E = (V_A - h2 * V_A) / h2;    // from h2 == V_A / (V_A + V_E)\n\tenv = rnorm(size(inds), 0.0, sqrt(V_E));\n\t\n\t// set fitness effects and remember phenotypes\n\tphenotypes = additive + env;\n\tinds.fitnessScaling = 1.0 + dnorm(10.0 - phenotypes, 0.0, 5.0);\n\tinds.tagF = phenotypes;\n}\nmutationEffect(m2) {\n\treturn 1.0;   // QTLs are neutral; fitness effects are handled below\n}\n1:100000 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"Mean phenotype:\\n\");\n\t\n\tmeanPhenotype = mean(p1.individuals.tagF);\n\tcat(format(\"%.2f\", meanPhenotype));\n\t\n\t// Run until we reach the fitness peak\n\tif (abs(meanPhenotype - 10.0) > 0.1)\n\t{\n\t\tcat(\", \");\n\t\treturn;\n\t}\n\t\n\tcat(\"\\n\\n-------------------------------\\n\");\n\tcat(\"QTLs at cycle \" + sim.cycle + \":\\n\\n\");\n\t\n\tqtls = sim.mutationsOfType(m2);\n\tf = sim.mutationFrequencies(NULL, qtls);\n\ts = qtls.selectionCoeff;\n\tp = qtls.position;\n\to = qtls.originTick;\n\tindices = order(f, F);\n\t\n\tfor (i in indices)\n\t\tcat(\"   \" + p[i] + \": s = \" + s[i] + \", f == \" + f[i] + \", o == \" + o[i] + \"\\n\");\n\t\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.5 - A QTL-based model with two quantitative phenotypic traits and pleiotropy.txt",
    "content": "// Keywords: QTL, quantitative trait loci, pleiotropy, M-matrix, live plotting, mutation()\n\nfunction (void)updatePlot(void)\n{\n\tif (exists(\"slimgui\"))\n\t{\n\t\tplot = slimgui.createPlot(\"Adaptive Walk\",\n\t\t\txrange=c(-10,30), yrange=c(-30,10),\n\t\t\txlab=\"phenotype 1\", ylab=\"phenotype 2\");\n\t\tplot.points(0, 0, symbol=21, color=\"red\", size=3.0);\n\t\tplot.points(20, -20, symbol=21, color=\"green\", size=3.0);\n\t\tplot.text(0, 4, \"start\", size=15);\n\t\tplot.text(20, -24, \"optimum\", size=15);\n\t\tplot.lines(HIST[,0], HIST[,1], \"black\");\n\t\tplot.points(HIST[,0], HIST[,1], 16, \"black\", size=0.5);\n\t}\n}\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // QTLs\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// g1 is a neutral region, g2 is a QTL\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", c(m1,m2), c(1.0, 0.1));\n\t\n\t// chromosome of length 100 kb with two QTL regions\n\tinitializeGenomicElement(g1, 0, 39999);\n\tinitializeGenomicElement(g2, 40000, 49999);\n\tinitializeGenomicElement(g1, 50000, 79999);\n\tinitializeGenomicElement(g2, 80000, 89999);\n\tinitializeGenomicElement(g1, 90000, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// QTL-related constants used below\n\tdefineConstant(\"QTL_mu\", c(0, 0));\n\tdefineConstant(\"QTL_cov\", 0.25);\n\tdefineConstant(\"QTL_sigma\", matrix(c(1,QTL_cov,QTL_cov,1), nrow=2));\n\tdefineConstant(\"QTL_optima\", c(20, -20));\n\t\n\tcatn(\"\\nQTL DFE means: \");\n\tprint(QTL_mu);\n\tcatn(\"\\nQTL DFE variance-covariance matrix: \");\n\tprint(QTL_sigma);\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tdefineGlobal(\"HIST\", matrix(c(0.0, 0.0), nrow=1));\n\tupdatePlot();\n}\n\nmutation(m2) {\n\t// draw mutational effects for the new m2 mutation\n\teffects = rmvnorm(1, QTL_mu, QTL_sigma);\n\tmut.setValue(\"e0\", effects[0]);\n\tmut.setValue(\"e1\", effects[1]);\n\t\n\t// remember all drawn effects, for our final output\n\told_effects = sim.getValue(\"all_effects\");\n\tsim.setValue(\"all_effects\", rbind(old_effects, effects));\n\t\n\treturn T;\n}\n\nlate() {\n\tfor (ind in sim.subpopulations.individuals)\n\t{\n\t\t// construct phenotypes from additive effects of QTL mutations\n\t\tmuts = ind.haplosomes.mutationsOfType(m2);\n\t\tphenotype0 = size(muts) ? sum(muts.getValue(\"e0\")) else 0.0;\n\t\tphenotype1 = size(muts) ? sum(muts.getValue(\"e1\")) else 0.0;\n\t\tind.setValue(\"phenotype0\", phenotype0);\n\t\tind.setValue(\"phenotype1\", phenotype1);\n\t\t\n\t\t// calculate fitness effects\n\t\teffect0 = 1.0 + dnorm(QTL_optima[0] - phenotype0, 0.0, 20.0) * 10.0;\n\t\teffect1 = 1.0 + dnorm(QTL_optima[1] - phenotype1, 0.0, 20.0) * 10.0;\n\t\tind.fitnessScaling = effect0 * effect1;\n\t}\n}\n\n1:1000000 late() {\n\t// output, run every 1000 cycles\n\tif (sim.cycle % 1000 != 0)\n\t\treturn;\n\t\n\t// print final phenotypes versus their optima\n\tinds = sim.subpopulations.individuals;\n\tp0_mean = mean(inds.getValue(\"phenotype0\"));\n\tp1_mean = mean(inds.getValue(\"phenotype1\"));\n\t\n\tcatn();\n\tcatn(\"Cycle: \" + sim.cycle);\n\tcatn(\"Mean phenotype 0: \" + p0_mean + \" (\" + QTL_optima[0] + \")\");\n\tcatn(\"Mean phenotype 1: \" + p1_mean + \" (\" + QTL_optima[1] + \")\");\n\t\n\t// update our plot\n\tdefineGlobal(\"HIST\", rbind(HIST, c(p0_mean, p1_mean)));\n\tupdatePlot();\n\t\n\t// keep running until we get within 10% of both optima\n\tif ((abs(p0_mean - QTL_optima[0]) > abs(0.1 * QTL_optima[0])) |\n\t\t(abs(p1_mean - QTL_optima[1]) > abs(0.1 * QTL_optima[1])))\n\t\treturn;\n\t\n\t// we are done with the main adaptive walk; print final output\n\t\n\t// get the QTL mutations and their frequencies\n\tm2muts = sim.mutationsOfType(m2);\n\tm2freqs = sim.mutationFrequencies(NULL, m2muts);\n\t\n\t// sort those vectors by frequency\n\to = order(m2freqs, ascending=F);\n\tm2muts = m2muts[o];\n\tm2freqs = m2freqs[o];\n\t\n\t// get the effect sizes\n\tm2e0 = m2muts.getValue(\"e0\");\n\tm2e1 = m2muts.getValue(\"e1\");\n\t\n\t// now output a list of the QTL mutations and their effect sizes\n\tcatn(\"\\nQTL mutations (f: e0, e1):\");\n\tfor (i in seqAlong(m2muts))\n\t\tcatn(m2freqs[i] + \": \" + m2e0[i] + \", \" + m2e1[i]);\n\t\n\t// output covariances\n\tfixed_m2 = m2muts[m2freqs == 1.0];\n\tcov_fixed = cov(fixed_m2.getValue(\"e0\"), fixed_m2.getValue(\"e1\"));\n\teffects = sim.getValue(\"all_effects\");\n\tcov_drawn = cov(drop(effects[,0]), drop(effects[,1]));\n\t\n\tcatn(\"\\nCovariance of effects among fixed QTLs: \" + cov_fixed);\n\tcatn(\"\\nCovariance of effects specified by the QTL DFE: \" + QTL_cov);\n\tcatn(\"\\nCovariance of effects across all QTL draws: \" + cov_drawn);\n\t\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.6 - A variety of fitness functions I (stabilizing selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tscale = dnorm(5.0, 5.0, 2.0);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, 5.0, 2.0) / scale;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.6 - A variety of fitness functions II (directional selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + phenotypes * 0.12;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.6 - A variety of fitness functions III (disruptive selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tscale = dnorm(0.0, 0.0, 2.0);\n\tinds.fitnessScaling = 1.5 - dnorm(phenotypes, 0.0, 2.0) / scale;\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n5000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.6 - A variety of fitness functions IV (truncation selection).txt",
    "content": "// Keywords: quantitative trait\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tcat(\"Phenotypes: \" + mean(phenotypes));\n}\n10001: late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = ifelse(phenotypes < 0.0, 0.0, 1.0);\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n}\n15000 late() {\n\tm2muts = sim.mutationsOfType(m2);\n\tfreqs = sim.mutationFrequencies(NULL, m2muts);\n\teffects = m2muts.selectionCoeff;\n\tcatn();\n\tprint(cbind(freqs, effects));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 13.7 - Negative frequency-dependence on a quantitative trait.txt",
    "content": "// Keywords: quantitative trait, negative frequency-dependence, squashed stabilizing selection\n\ninitialize() {\n\tdefineConstant(\"COMP\", T);\t// is competition enabled?\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.15);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tcat(\"Phenotypes: 0\");\n}\n1:5000 late() {\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tstabilizing = dnorm(phenotypes, 5.0, 2.0) / dnorm(5.0, 5.0, 2.0);\n\tcompetition = sapply(phenotypes, \"sum(dnorm(phenotypes, applyValue, 0.3));\");\n\tcompetition = 1.0 - (competition / size(inds)) / dnorm(0.0, 0.0, 0.3);\n\tinds.fitnessScaling = 1.0 + stabilizing * (COMP ? competition else 1.0);\n\t\n\tif (sim.cycle % 10 == 0)\n\t\tcat(\", \" + mean(phenotypes));\n\t\n\tif (exists(\"slimgui\"))\n\t{\n\t\t// plot the relative densities\n\t\tx1 = -2; x2 = 12; step = 0.5;\n\t\tcenters = seq(from=x1, to=x2 + step*0.01, by=step);\n\t\tbreaks = seq(from=x1 - step/2, to=x2 + step*0.51, by=step);\n\t\tintervals = findInterval(phenotypes, breaks, allInside=T);\n\t\tcounts = tabulate(intervals, length(centers) - 1);\n\t\tdensity = counts / max(counts);\n\t\t\n\t\tplot_pheno = slimgui.createPlot(\"Phenotypic Distribution\",\n\t\t\txrange=c(-0.5, 10.5), yrange=c(-0.05, 1.05),\n\t\t\txlab=\"Phenotypic trait value\", ylab=\"Relative density\",\n\t\t\twidth=500, height=250);\n\t\tplot_pheno.axis(1, at=c(0,5,10));\n\t\tplot_pheno.abline(v=5.0, color=\"cornflowerblue\", lwd=2);\n\t\tplot_pheno.lines(centers, density, lwd=2);\n\t\t\n\t\t// plot the fitness function\n\t\tpheno_vals = seq(-2, 12, by=0.1);\n\t\tstabilizing = dnorm(pheno_vals, 5.0, 2.0) / dnorm(5.0, 5.0, 2.0);\n\t\tcompetition = sapply(pheno_vals, \"sum(dnorm(phenotypes, applyValue, 0.3));\");\n\t\tcompetition = 1.0 - (competition / size(inds)) / dnorm(0.0, 0.0, 0.3);\n\t\tfitness = 1.0 + stabilizing * (COMP ? competition else 1.0);\n\t\t\n\t\tplot_fit = slimgui.createPlot(\"Fitness Function\",\n\t\t\txrange=c(-0.5, 10.5), yrange=c(0.95, 2.05),\n\t\t\txlab=\"Phenotypic trait value\", ylab=\"Fitness\",\n\t\t\twidth=500, height=250);\n\t\tplot_fit.axis(1, at=c(0,5,10));\n\t\tplot_fit.abline(v=5.0, color=\"cornflowerblue\", lwd=2);\n\t\tplot_fit.lines(pheno_vals, fitness, lwd=2);\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.1 - Relatedness, inbreeding, and heterozygosity.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees = T);\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n}\nmateChoice() {\n\t// Prefer relatives as mates\n\treturn weights * (individual.relatedness(sourceSubpop.individuals) + 0.01);\n}\n1000 late() {\n\t// Print mean heterozygosity across the population\n\theterozygosity = calcHeterozygosity(p1.haplosomes);\n\tcat(\"Mean heterozygosity = \" + heterozygosity + \"\\n\");\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.10 - Modeling transposable elements.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);               // chromosome length\n\tdefineConstant(\"teInitialCount\", 100);  // initial number of TEs\n\tdefineConstant(\"teJumpP\", 0.0001);      // TE jump probability\n\tdefineConstant(\"teDisableP\", 0.00005);  // disabling mut probability\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// transposon mutation type; also neutral, but red\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"#FF0000\";\n\t\n\t// disabled transposon mutation type; dark red\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"#700000\";\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tsim.tag = 0;\t// the next unique tag value to use for TEs\n\t\n\t// create some transposons at random positions\n\thaplosomes = sim.subpopulations.haplosomes;\n\tpositions = rdunif(teInitialCount, 0, L-1);\n\t\n\tfor (teIndex in 0:(teInitialCount-1))\n\t{\n\t\tpos = positions[teIndex];\n\t\tmut = haplosomes.addNewDrawnMutation(m2, pos);\n\t\tmut.tag = sim.tag;\n\t\tsim.tag = sim.tag + 1;\n\t}\n}\nmodifyChild() {\n\t// disable transposons with rate teDisableP\n\tfor (haplosome in child.haplosomes)\n\t{\n\t\ttes = haplosome.mutationsOfType(m2);\n\t\tteCount = tes.size();\n\t\tmutatedCount = teCount ? rpois(1, teCount * teDisableP) else 0;\n\t\t\n\t\tif (mutatedCount)\n\t\t{\n\t\t\tmutatedTEs = sample(tes, mutatedCount);\n\t\t\t\n\t\t\tfor (te in mutatedTEs)\n\t\t\t{\n\t\t\t\tall_disabledTEs = sim.mutationsOfType(m3);\n\t\t\t\tdisabledTE = all_disabledTEs[all_disabledTEs.tag == te.tag];\n\t\t\t\t\n\t\t\t\tif (size(disabledTE))\n\t\t\t\t{\n\t\t\t\t\t// use the existing disabled TE mutation\n\t\t\t\t\thaplosome.removeMutations(te);\n\t\t\t\t\thaplosome.addMutations(disabledTE);\n\t\t\t\t\tnext;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// make a new disabled TE mutation with the right tag\n\t\t\t\thaplosome.removeMutations(te);\n\t\t\t\tdisabledTE = haplosome.addNewDrawnMutation(m3, te.position);\n\t\t\t\tdisabledTE.tag = te.tag;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn T;\n}\nlate() {\n\t// make active transposons copy themselves with rate teJumpP\n\tfor (individual in sim.subpopulations.individuals)\n\t{\n\t\tfor (haplosome in individual.haplosomes)\n\t\t{\n\t\t\ttes = haplosome.mutationsOfType(m2);\n\t\t\tteCount = tes.size();\n\t\t\tjumpCount = teCount ? rpois(1, teCount * teJumpP) else 0;\n\t\t\t\n\t\t\tif (jumpCount)\n\t\t\t{\n\t\t\t\tjumpTEs = sample(tes, jumpCount);\n\t\t\t\t\n\t\t\t\tfor (te in jumpTEs)\n\t\t\t\t{\n\t\t\t\t\t// make a new TE mutation\n\t\t\t\t\tpos = rdunif(1, 0, L-1);\n\t\t\t\t\tjumpTE = haplosome.addNewDrawnMutation(m2, pos);\n\t\t\t\t\tjumpTE.tag = sim.tag;\n\t\t\t\t\tsim.tag = sim.tag + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n5000 late() {\n\t// print information on each TE, including the fraction of it disabled\n\tall_tes = sortBy(sim.mutationsOfType(m2), \"position\");\n\tall_disabledTEs = sortBy(sim.mutationsOfType(m3), \"position\");\n\thaplosomeCount = size(sim.subpopulations.haplosomes);\n\t\n\tcatn(\"Active TEs:\");\n\tfor (te in all_tes)\n\t{\n\t\tcat(\"   TE at \" + te.position + \": \");\n\t\t\n\t\tactive = sim.mutationCounts(NULL, te);\n\t\tdisabledTE = all_disabledTEs[all_disabledTEs.tag == te.tag];\n\t\t\n\t\tif (size(disabledTE) == 0)\n\t\t{\n\t\t\tdisabled = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdisabled = sim.mutationCounts(NULL, disabledTE);\n\t\t\tall_disabledTEs = all_disabledTEs[all_disabledTEs != disabledTE];\n\t\t}\n\t\t\n\t\ttotal = active + disabled;\n\t\t\n\t\tcat(\"frequency \" + format(\"%0.3f\", total / haplosomeCount) + \", \");\n\t\tcatn(round(active / total * 100) + \"% active\");\n\t}\n\t\n\tcatn(\"\\nCompletely disabled TEs: \");\n\tfor (te in all_disabledTEs)\n\t{\n\t\tfreq = sim.mutationFrequencies(NULL, te);\n\t\tcat(\"   TE at \" + te.position + \": \");\n\t\tcatn(\"frequency \" + format(\"%0.3f\", freq));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.11 - Modeling opposite ends of a chromosome I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeGenomicElement(g1, 9900000, 9999999);\n\tinitializeRecombinationRate(1.5e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.11 - Modeling opposite ends of a chromosome II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeGenomicElement(g1, 100000, 199999);\n\t\n\trates = c(1.5e-7, 0.473642, 1.5e-7);\n\tends = c(99999, 100000, 199999);\n\tinitializeRecombinationRate(rates, ends);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.12 - Visualizing ancestry and admixture with mutation() callbacks.txt",
    "content": "// Keywords: mutation types, tracking, true local ancestry, admixture, introgression, mutation()\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\t\n\t// neutral and beneficial for p1\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.color = \"yellow\";\n\tm1.colorSubstitution = \"yellow\";\n\t\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.color = \"red\";\n\tm2.colorSubstitution = \"red\";\n\t\n\t// neutral and beneficial for p2\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.color = \"blue\";\n\tm3.colorSubstitution = \"blue\";\n\t\n\tinitializeMutationType(\"m4\", 0.5, \"f\", 0.1);\n\tm4.color = \"green\";\n\tm4.colorSubstitution = \"green\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.0001));\n\tinitializeGenomicElement(g1, 0, 9999999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tsim.addSubpop(\"p2\", 1000);\n}\nmutation(m1, p2)\n{\n\t// use m3 instead of m1, in p2\n\tmut.setMutationType(m3);\n\treturn T;\n}\nmutation(m2, p2)\n{\n\t// use m4 instead of m2, in p2\n\tmut.setMutationType(m4);\n\treturn T;\n}\n10000 early() {\n\tsim.chromosome.setMutationRate(0.0);\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n}\n15000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback I.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\ninitialize() {\n\t// an m2 mutation is \"A\"\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// an m3 mutation is \"a\"\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"cornflowerblue\";\n\t\n\t// enforce mutually exclusive replacement\n\tc(m2,m3).mutationStackGroup = 1;\n\tc(m2,m3).mutationStackPolicy = 'l';\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3), c(1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(1e-4);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// create the canonical mutation objects\n\ttarget = p1.haplosomes[0];\n\ttarget.addNewDrawnMutation(m2, 0:99);\n\tdefineConstant(\"MUT2\", target.mutations);\n\ttarget.removeMutations();\n\ttarget.addNewDrawnMutation(m3, 0:99);\n\tdefineConstant(\"MUT3\", target.mutations);\n\ttarget.removeMutations();\n\t\n\t// start homozygous \"aa\" at every position\n\tp1.haplosomes.addMutations(MUT3);\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"sim.mutationFrequencies(NULL, MUT2);\");\n}\nmutation(m2) {\n\t// unique down to the canonical m2 mutation\n\treturn MUT2[mut.position];\n}\nmutation(m3) {\n\t// unique down to the canonical m3 mutation\n\treturn MUT3[mut.position];\n}\n50000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.13 - Modeling biallelic loci with a mutation() callback II.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\ninitialize() {\n\t// m2 models a biallelic locus; an m2 mutation is \"A\",\n\t// absence of an m2 mutation is \"a\"; \"aa\" is neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\t// m3 is used for new mutations; new m3 mutations get\n\t// uniqued down to the correct biallelic m2 state\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.convertToSubstitution = F;\n\tm3.color = \"cornflowerblue\";\n\t\n\tinitializeGenomicElementType(\"g1\", m3, 1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(1e-4);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// create the permanent m2 mutation objects we will use\n\ttarget = p1.haplosomes[0];\n\ttarget.addNewDrawnMutation(m2, 0:99);\n\tdefineConstant(\"MUT\", target.mutations);\n\t\n\t// then remove them; start with \"aa\" for all individuals\n\ttarget.removeMutations();\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"sim.mutationFrequencies(NULL, MUT);\");\n}\nmutation(m3) {\n\t// if we already have an m2 mutation at the site, allow\n\t// the new m3 mutation; we will remove the stack below\n\tif (haplosome.containsMarkerMutation(m2, mut.position))\n\t\treturn T;\n\t\n\t// no m2 mutation is present, so unique down\n\treturn MUT[mut.position];\n}\nlate() {\n\t// implement back-mutations from A to a\n\tm3muts = sim.mutationsOfType(m3);\n\t\n\t// do we have any m3 mutations segregating?\n\t// if so, we have m2/m3 stacked mutations to remove\n\tif (m3muts.length() > 0)\n\t{\n\t\thaplosomes = sim.subpopulations.haplosomes;\n\t\tcounts = haplosomes.countOfMutationsOfType(m3);\n\t\thasStacked = haplosomes[counts > 0];\n\t\t\n\t\tfor (haplosome in hasStacked)\n\t\t{\n\t\t\tstacked_m3 = haplosome.mutationsOfType(m3);\n\t\t\tstackPositions = stacked_m3.position;\n\t\t\tall_m2 = haplosome.mutationsOfType(m2);\n\t\t\ts = (match(all_m2.position, stackPositions) >= 0);\n\t\t\tstacked_m2 = all_m2[s];\n\t\t\thaplosome.removeMutations(c(stacked_m3, stacked_m2));\n\t\t}\n\t}\n}\n50000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.14 - Modeling biallelic loci in script.txt",
    "content": "// Keywords: identity by state, uniquing, unique down, back mutation, two alleles\n\n// biallelicFrequencies() is used by the LogFile\nfunction (float)biallelicFrequencies(void) {\n\tg = NULL;\n\tfor (ind in p1.individuals)\n\t\tg = rbind(g, ind.getValue('G1'), ind.getValue('G2'));\n\tf = apply(g, 1, \"mean(applyValue);\");\n\treturn f;\n}\n\ninitialize() {\n\tdefineConstant(\"MU\", 1e-4);\n\tdefineConstant(\"L\", 100);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\t// all individuals start in the \"wild-type\" state\n\t// genomic state is kept in two vectors, G1 and G2\n\tp1.individuals.setValue(\"G1\", rep(F, L));\n\tp1.individuals.setValue(\"G2\", rep(F, L));\n\t\n\t// log results\n\tlog = community.createLogFile(\"freq.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addMeanSDColumns(\"freq\", \"biallelicFrequencies();\");\n}\nmodifyChild() {\n\t// inherit biallelic loci from parents with recombination and mutation\n\tparentG1 = parent1.getValue(\"G1\");\n\tparentG2 = parent1.getValue(\"G2\");\n\trecombined = ifelse(rbinom(L, 1, 0.5) == 0, parentG1, parentG2);\n\tmutated = ifelse(rbinom(L, 1, MU) == 1, !recombined, recombined);\n\tchild.setValue(\"G1\", mutated);\n\t\n\tparentG1 = parent2.getValue(\"G1\");\n\tparentG2 = parent2.getValue(\"G2\");\n\trecombined = ifelse(rbinom(L, 1, 0.5) == 0, parentG1, parentG2);\n\tmutated = ifelse(rbinom(L, 1, MU) == 1, !recombined, recombined);\n\tchild.setValue(\"G2\", mutated);\n\t\n\treturn T;\n}\n50000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.15 - Using runs of homozygosity (ROH) to track inbreeding.txt",
    "content": "// Keywords: runs of homozygosity, ROH, F_ROH, inbreeding, autozygosity\n\ninitialize() {\n\tinitializeMutationRate(5e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e9-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\tsim.addSubpop(\"p2\", 100);\n\tsim.addSubpop(\"p3\", 100);\n\tp1.setMigrationRates(p2, 0.1);\n\tp2.setMigrationRates(p1, 0.001);\n\tp1.setMigrationRates(p3, 0.001);\n\tp3.setMigrationRates(p1, 0.1);\n\t\n\t// start our histories empty\n\tfor (subpop in c(p1,p2,p3))\n\t{\n\t\tsubpop.setValue(\"FROH_hist\", float(0));\n\t\tsubpop.setValue(\"FROH_hist_tick\", integer(0));\n\t}\n}\n500 early() {\n\tp2.setSubpopulationSize(20);\n}\n700 early() {\n\tp2.setSubpopulationSize(100);\n}\n1400 early() {\n\tp3.setSubpopulationSize(20);\n}\n1600 early() {\n\tp3.setSubpopulationSize(500);\n}\n100:2000 late() {\n\t// in SLiMgui, make a plot every ten ticks\n\tif (exists(\"slimgui\") & (community.tick % 10 == 0))\n\t{\n\t\tplot = slimgui.createPlot(\"Froh history\",\n\t\t\txrange=c(1, community.estimatedLastTick()), yrange=c(0.0,0.5),\n\t\t\txlab=\"Tick\", ylab=\"Mean Froh\", width=500, height=300);\n\t\tplot.addLegend(\"topRight\");\n\t\t\n\t\tfor (subpop in c(p1,p2,p3), color in c(\"red\", \"cornflowerblue\", \"chartreuse3\"))\n\t\t{\n\t\t\tmean_FROH = calcMeanFroh(subpop.individuals);\n\t\t\tFROH_hist = c(subpop.getValue(\"FROH_hist\"), mean_FROH);\n\t\t\tFROH_hist_tick = c(subpop.getValue(\"FROH_hist_tick\"), community.tick);\n\t\t\tsubpop.setValue(\"FROH_hist\", FROH_hist);\n\t\t\tsubpop.setValue(\"FROH_hist_tick\", FROH_hist_tick);\n\t\t\t\n\t\t\tplot.lines(x=FROH_hist_tick, y=FROH_hist, color=color, lwd=2.0);\n\t\t\tplot.legendLineEntry(\"p\" + subpop.id, color, lwd=2.0);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.16 - Visualizing linkage disequilibrium.txt",
    "content": "// Keywords: linkage disequilibrium, LD, custom plotting, recombination, calcLD\n\ninitialize()\n{\n\tsetSeed(2180149919968428688);\n\tdefineConstant(\"L\", 1e7);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1).color=\"red\";  // used for MUT1\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early()\n{\n\tsim.addSubpop(\"p1\", 1000);\n}\n5000 late()\n{\n\t// create the MUT1 mutation that we will track over time\n\tmut1 = sample(p1.haplosomes, 1).addNewDrawnMutation(m2, asInteger(L/2));\n\tdefineGlobal(\"MUT1\", mut1);\n}\n\n5000:10000 late()\n{\n\tallMutsMAF = sim.mutations[sim.mutationFrequencies(p1) >= 0.10];\n\tmuts = sortBy(allMutsMAF, \"position\");\n\t\n\tif (size(muts) == 0)\n\t\treturn;\n\tif (!MUT1.isSegregating)\n\t{\n\t\tcatn(\"The focal mutation fixed or was lost.\");\n\t\tsim.simulationFinished();\n\t\treturn;\n\t}\n\t\n\tld = calcLD_D(MUT1, muts) * 10;     // scale up to make it more visible\n\tr = calcLD_Rsquared(MUT1, muts, squared=F);\n\tr2 = calcLD_Rsquared(MUT1, muts);\n\tp = muts.position;\n\t\n\tplot = slimgui.createPlot(\"LD versus R2\", xrange=c(0,L-1), yrange=c(-1,1),\n\t\txlab=\"tick\", ylab=\"metric\", width=800, height=300);\n\tplot.abline(v=MUT1.position, color=\"red\", lwd=2);\n\tplot.points(p, ld, symbol=16, color=\"cornflowerblue\", size=0.5, alpha=0.1);\n\tplot.points(p, r, symbol=16, color=\"chartreuse3\", size=0.5, alpha=0.1);\n\tplot.points(p, r2, symbol=16, color=\"black\", size=0.5, alpha=0.1);\n\t\n\tf = rep(1/201, 201);   // running average filter, 201 mutations wide\n\tplot.lines(p, filter(ld, f, outside=T), color=\"cornflowerblue\", lwd=2);\n\tplot.lines(p, filter(r, f, outside=T), color=\"chartreuse3\", lwd=2);\n\tplot.lines(p, filter(r2, f, outside=T), color=\"black\", lwd=2);\n\t\n\tplot.addLegend(\"topRight\");\n\tplot.legendPointEntry(\"R2\", symbol=16, color=\"black\", size=0.5);\n\tplot.legendPointEntry(\"R\", symbol=16, color=\"chartreuse3\", size=0.5);\n\tplot.legendPointEntry(\"LD*10\", symbol=16, color=\"cornflowerblue\", size=0.5);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.2 - Mortality-based fitness I.txt",
    "content": "// Keywords: death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.005); // deleterious\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutationEffect(m2)\n{\n\t// convert fecundity-based selection to survival-based selection\n\tif (runif(1) < effect)\n\t\treturn 1.0;\n\telse\n\t\treturn 0.0;\n}\n10000 late() {\n\tsim.outputMutations(sim.mutationsOfType(m2));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.2 - Mortality-based fitness II.txt",
    "content": "// Keywords: death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\t// initially, everybody lives\n\tsim.subpopulations.individuals.tagL0 = F;\n\t\n\t// here be dragons\n\tsample(sim.subpopulations.individuals, 100).tagL0 = T;\n}\nfitnessEffect() {\n\t// individuals tagged for death die here\n\tif (individual.tagL0)\n\t\treturn 0.0;\n\telse\n\t\treturn 1.0;\n}\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.2 - Mortality-based fitness III.txt",
    "content": "// Keywords: fitness, death, survival\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\t// here be dragons\n\tsample(sim.subpopulations.individuals, 100).fitnessScaling = 0.0;\n}\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.3 - Reading initial simulation state from an MS output file I.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n20000 late() {\n\tp1.outputMSSample(2000, replace=F, filePath=\"ms.txt\");\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.3 - Reading initial simulation state from an MS output file II.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\t\n\t// READ MS FORMAT INITIAL STATE\n\tlines = readFile(\"ms.txt\");\n\tindex = 0;\n\t\n\t// skip lines until reaching the // line, then skip that line\n\twhile (lines[index] != \"//\")\n\t\tindex = index + 1;\n\tindex = index + 1;\n\t\n\tif (index + 2 + p1.individualCount * 2 > size(lines))\n\t\tstop(\"File is too short; terminating.\");\n\t\n\t// next line should be segsites:\n\tsegsitesLine = lines[index];\n\tindex = index + 1;\n\tparts = strsplit(segsitesLine);\n\tif (size(parts) != 2) stop(\"Malformed segsites.\");\n\tif (parts[0] != \"segsites:\") stop(\"Missing segsites.\");\n\tsegsites = asInteger(parts[1]);\n\t\n\t// and next is positions:\n\tpositionsLine = lines[index];\n\tindex = index + 1;\n\tparts = strsplit(positionsLine);\n\tif (size(parts) != segsites + 1) stop(\"Malformed positions.\");\n\tif (parts[0] != \"positions:\") stop(\"Missing positions.\");\n\tpositions = asFloat(parts[1:(size(parts)-1)]);\n\t\n\t// create all mutations in a haplosome in a dummy subpopulation\n\tsim.addSubpop(\"p2\", 1);\n\tg = p2.haplosomes[0];\n\tL = sim.chromosomes.lastPosition;\n\tintPositions = asInteger(round(positions * L));\n\tmuts = g.addNewMutation(m1, 0.0, intPositions);\n\t\n\t// add the appropriate mutations to each haplosome\n\tfor (g in p1.haplosomes)\n\t{\n\t\tf = asLogical(asInteger(strsplit(lines[index], \"\")));\n\t\tindex = index + 1;\n\t\tg.addMutations(muts[f]);\n\t}\n\t\n\t// remove the dummy subpopulation\n\tp2.setSubpopulationSize(0);\n\t\n\t// (optional) set the tick and cycle to match the save point\n\tcommunity.tick = 20000;\n\tsim.cycle = 20000;\n}\n30000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.4 - Modeling chromosomal inversions with a recombination() callback.txt",
    "content": "// Keywords: recombination suppression, inversion, gamete generation, meiosis\n\ninitialize() {\n\tdefineConstant(\"L\", 1000000);\n\tdefineConstant(\"INV_LENGTH\", 500000);\n\tdefineConstant(\"INV_START\", asInteger(L/2 - INV_LENGTH/2));\n\tdefineConstant(\"INV_END\", INV_START + INV_LENGTH - 1);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral sites\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);  // start marker\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);  // end marker\n\tc(m2,m3).convertToSubstitution = T;\n\tc(m2,m3).color = \"red\";\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\n\t// give some haplosomes an inversion\n\tinverted = sample(p1.haplosomes, 100);\n\tinverted.addNewDrawnMutation(m2, INV_START);\n\tinverted.addNewDrawnMutation(m3, INV_END);\n}\nmutationEffect(m2) {\n\t// fitness of the inversion is frequency-dependent\n\tf = sim.mutationFrequencies(NULL, mut);\n\treturn 1.0 - (f - 0.5) * 0.2;\n}\n5000 late() {\n\tsim.outputFixedMutations();\n\t\n\t// Assess fixation inside vs. outside the inversion\n\tpos = sim.substitutions.position;\n\tcatn(sum((pos >= INV_START) & (pos < INV_END)) + \" inside.\");\n\tcatn(sum((pos < INV_START) | (pos >= INV_END)) + \" outside.\");\n}\n\nrecombination() {\n\tgm1 = haplosome1.containsMarkerMutation(m2, INV_START);\n\tgm2 = haplosome2.containsMarkerMutation(m2, INV_START);\n\tif (!(gm1 | gm2)) {\n\t\t// homozygote non-inverted\n\t\treturn F;\n\t}\n\tinInv = (breakpoints > INV_START) & (breakpoints <= INV_END);\n\tif (sum(inInv) % 2 == 0) {\n\t\treturn F;\n\t}\n\tif (gm1 & gm2) {\n\t\t// homozygote inverted\n\t\tleft = (breakpoints == INV_START);\n\t\tright = (breakpoints == INV_END + 1);\n\t\tbreakpoints = sort(c(breakpoints[!(left | right)],\n\t\t\tc(INV_START, INV_END + 1)[c(sum(left) == 0, sum(right) == 0)]));\n\t\treturn T;\n\t} else {\n\t\t// heterozygote inverted: resample to get an even number of breakpoints\n\t\t// this is *recursive*: it calls this recombination callback again!\n\t\tbreakpoints = sim.chromosomes.drawBreakpoints(individual);\n\t}\n\treturn T;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.5 - Estimating model parameters with ABC.txt",
    "content": "// Keywords: Approximate Bayesian computation, MCMC, parameter estimation\n\ninitialize() {\n\tinitializeMutationRate(mu);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000 late() { cat(sim.mutations.size() + \"\\n\"); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.6 - Tracking local ancestry along the chromosome.txt",
    "content": "// Keywords: migration, dispersal, admixture, ancestry, introgression\n\ninitialize() {\n\tdefineConstant(\"Z\", 1e9);       // last chromosome position\n\tdefineConstant(\"I\", 1e6);       // interval between markers\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // p1 marker\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);   // p2 marker\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);   // p3 marker\n\tinitializeMutationType(\"m4\", 0.5, \"e\", 0.5);   // beneficial\n\tc(m1,m2,m3,m4).color = c(\"red\", \"green\", \"blue\", \"white\");\n\tc(m1,m2,m3).convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", m4, 1.0);\n\tinitializeGenomicElement(g1, 0, Z);\n\tinitializeMutationRate(0);\n\tinitializeRecombinationRate(1e-9);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tsim.addSubpop(\"p3\", 500);\n\t\n\t// set up markers in each subpopulation, and add a beneficial mutation\n\tpositions = seq(from=0, to=Z, by=I);\n\tdefineConstant(\"M\", size(positions));\n\tcatn(\"Modeling \" + M + \" ancestry markers.\");\n\t\n\tfor (subpop in c(p1,p2,p3),\n\t     muttype in c(m1,m2,m3),\n\t     symbol in c(\"M1\",\"M2\",\"M3\"))\n\t{\n\t\thaplosomes = subpop.haplosomes;\n\t\tmuts = haplosomes.addNewDrawnMutation(muttype, positions);\n\t\tdefineConstant(symbol, muts);\n\t\t\n\t\tmut = haplosomes.addNewDrawnMutation(m4, integerDiv(Z, 2));\n\t\tcatn(\"Beneficial mutation: s == \" + mut.selectionCoeff);\n\t}\n\t\n\t// set up circular migration between the subpops\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p3, 0.01);\n\tp3.setMigrationRates(p1, 0.01);\n}\n:100000 late() {\n\tif (exists(\"slimgui\")) {\n\t\tplot = slimgui.createPlot(\"Local ancestry\", c(0,1), c(0,1),\n\t\t\txlab=\"Position\", ylab=\"Ancestry fraction\", width=700, height=250);\n\t\tplot.addLegend(labelSize=14, graphicsWidth=20);\n\t\tplot.legendLineEntry(\"p1 ancestry\", \"red\", lwd=3);\n\t\tplot.legendLineEntry(\"p2 ancestry\", \"green\", lwd=3);\n\t\tplot.legendLineEntry(\"p3 ancestry\", \"blue\", lwd=3);\n\t\tplot.abline(v=0.5, color=\"black\", lwd=2);\n\t\t\n\t\tfor (col in c(m1,m2,m3).color, symbol in c(\"M1\",\"M2\",\"M3\"))\n\t\t{\n\t\t\tmutlist = executeLambda(symbol + \";\");\n\t\t\tfreqs = sim.mutationFrequencies(NULL, mutlist);\n\t\t\tplot.lines(seq(0, 1, length=size(freqs)), freqs, color=col, lwd=3);\n\t\t\tplot.abline(h=mean(freqs), color=col);\n\t\t}\n\t}\n\t\n\tif (sim.countOfMutationsOfType(m4) == 0)\n\t\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.7 - Live plotting with R using system().txt",
    "content": "// Keywords: live plotting\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tif (fileExists(\"/usr/bin/Rscript\"))\n\t\tdefineConstant(\"RSCRIPT\", \"/usr/bin/Rscript\");\n\telse if (fileExists(\"/usr/local/bin/Rscript\"))\n\t\tdefineConstant(\"RSCRIPT\", \"/usr/local/bin/Rscript\");\n\telse\n\t\tstop(\"Couldn't find Rscript.\");\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 5000);\n\tsim.setValue(\"fixed\", NULL);\n\t\n\tdefineConstant(\"pngPath\", writeTempFile(\"plot_\", \".png\", \"\"));\n\t\n\t// If we're running in SLiMgui, open a plot window\n\tif (exists(\"slimgui\"))\n\t\tslimgui.openDocument(pngPath);\n}\n1: early() {\n\tif (sim.cycle % 10 == 0)\n\t{\n\t\tcount = sim.substitutions.size();\n\t\tsim.setValue(\"fixed\", c(sim.getValue(\"fixed\"), count));\n\t}\n\t\n\tif (sim.cycle % 1000 != 0)\n\t\treturn;\n\t\n\ty = sim.getValue(\"fixed\");\n\t\n\trstr = paste('{',\n\t\t'x <- (1:' + size(y) + ') * 10',\n\t\t'y <- c(' + paste(y, sep=\", \") + ')',\n\t\t'png(width=4, height=4, units=\"in\", res=72, file=\"' + pngPath + '\")',\n\t\t'par(mar=c(4.0, 4.0, 1.5, 1.5))',\n\t\t'plot(x=x, y=y, xlim=c(0, 50000), ylim=c(0, 500), type=\"l\",',\n\t\t\t'xlab=\"Generation\", ylab=\"Fixed mutations\", cex.axis=0.95,',\n\t\t\t'cex.lab=1.2, mgp=c(2.5, 0.7, 0), col=\"red\", lwd=2,',\n\t\t\t'xaxp=c(0, 50000, 2))',\n\t\t'box()',\n\t\t'dev.off()',\n\t\t'}', sep=\"\\n\");\n\t\n\tscriptPath = writeTempFile(\"plot_\", \".R\", rstr);\n\tsystem(RSCRIPT, args=scriptPath);\n\tdeleteFile(scriptPath);\n}\n50000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.8 - Using mutation rate variation to model varying functional density.txt",
    "content": "// Keywords: mutation rate map, mutation map\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 0.5, \"f\", -0.01);  // deleterious\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// Use the mutation rate map to vary functional density\n\tends = c(20000, 30000, 70000, 90000, 99999);\n\tdensities = c(1e-9, 2e-8, 1e-9, 5e-8, 1e-9);\n\tinitializeMutationRate(densities, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n200000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 14.9 - Modeling microsatellites.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);           // chromosome length\n\tdefineConstant(\"msatCount\", 10);    // number of microsats\n\tdefineConstant(\"msatMu\", 0.0001);   // mutation rate per microsat\n\tdefineConstant(\"msatUnique\", T);    // T = unique msats, F = lineages\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);  // neutral\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// microsatellite mutation type; also neutral, but magenta\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"#900090\";\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// create some microsatellites at random positions\n\thaplosomes = sim.subpopulations.haplosomes;\n\tpositions = rdunif(msatCount, 0, L-1);\n\trepeats = rpois(msatCount, 20) + 5;\n\t\n\tfor (msatIndex in 0:(msatCount-1))\n\t{\n\t\tpos = positions[msatIndex];\n\t\tmut = haplosomes.addNewDrawnMutation(m2, pos);\n\t\tmut.tag = repeats[msatIndex];\n\t}\n\t\n\t// remember the microsat positions for later\n\tdefineConstant(\"msatPositions\", positions);\n}\nmodifyChild() {\n\t// mutate microsatellites with rate msatMu\n\tfor (haplosome in child.haplosomes)\n\t{\n\t\tmutCount = rpois(1, msatMu * msatCount);\n\t\t\n\t\tif (mutCount)\n\t\t{\n\t\t\tmutSites = sample(msatPositions, mutCount);\n\t\t\tmsats = haplosome.mutationsOfType(m2);\n\t\t\t\n\t\t\tfor (mutSite in mutSites)\n\t\t\t{\n\t\t\t\tmsat = msats[msats.position == mutSite];\n\t\t\t\trepeats = msat.tag;\n\t\t\t\t\n\t\t\t\t// modify the number of repeats by adding -1 or +1\n\t\t\t\trepeats = repeats + (rdunif(1, 0, 1) * 2 - 1);\n\t\t\t\t\n\t\t\t\tif (repeats < 5)\n\t\t\t\t\tnext;\n\t\t\t\t\n\t\t\t\t// if we're uniquing microsats, do so now\n\t\t\t\tif (msatUnique)\n\t\t\t\t{\n\t\t\t\t\tall_msats = sim.mutationsOfType(m2);\n\t\t\t\t\tmsatsAtSite = all_msats[all_msats.position == mutSite];\n\t\t\t\t\tmatchingMut = msatsAtSite[msatsAtSite.tag == repeats];\n\t\t\t\t\t\n\t\t\t\t\tif (matchingMut.size() == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome.removeMutations(msat);\n\t\t\t\t\t\thaplosome.addMutations(matchingMut);\n\t\t\t\t\t\tnext;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// make a new mutation with the new repeat count\n\t\t\t\thaplosome.removeMutations(msat);\n\t\t\t\tmsat = haplosome.addNewDrawnMutation(m2, mutSite);\n\t\t\t\tmsat.tag = repeats;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn T;\n}\n10000 late() {\n\t// print frequency information for each microsatellite site\n\tall_msats = sim.mutationsOfType(m2);\n\t\n\tfor (pos in sort(msatPositions))\n\t{\n\t\tcatn(\"Microsatellite at \" + pos + \":\");\n\t\t\n\t\tmsatsAtPos = all_msats[all_msats.position == pos];\n\t\t\n\t\tfor (msat in sortBy(msatsAtPos, \"tag\"))\n\t\t\tcatn(\"   variant with \" + msat.tag + \" repeats: \" +\n\t\t\t\tsim.mutationFrequencies(NULL, msat));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.1 - A minimal nonWF model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.10 - Recording a pedigree.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 10);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// delete any existing pedigree log files\n\tdeleteFile(\"mating.txt\");\n\tdeleteFile(\"death.txt\");\n}\nreproduction() {\n\t// choose a mate and generate an offspring\n\tmate = subpop.sampleIndividuals(1);\n\tchild = subpop.addCrossed(individual, mate);\n\tchild.tag = sim.tag;\n\tsim.tag = sim.tag + 1;\n\t\n\t// log the mating\n\tline = paste(community.tick, individual.tag, mate.tag, child.tag);\n\twriteFile(\"mating.txt\", line, append=T);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\t\n\t// provide initial tags and remember the next tag value\n\tp1.individuals.tag = 1:10;\n\tsim.tag = 11;\n}\nearly() {\n\t// density-dependence\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nsurvival() {\n\tif (!surviving) {\n\t\t// log the death\n\t\tline = community.tick + \" \" + individual.tag;\n\t\twriteFile(\"death.txt\", line, append=T);\n\t}\n\treturn NULL;\n}\n100 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.11 - Dynamic population structure in nonWF models.txt",
    "content": "// Keywords: split, join, vicariance, founder, founding, merge, assimilation, admixture\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// each subpopulation reproduces within itself\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\t// start with two subpops that grow to different sizes\n\tsim.addSubpop(\"p1\", 10).setValue(\"K\", 500);\n\tsim.addSubpop(\"p2\", 10).setValue(\"K\", 600);\n}\nearly() {\n\t// density-dependent regulation for each subpop\n\tfor (subpop in sim.subpopulations) {\n\t\tK = subpop.getValue(\"K\");\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n\t}\n}\n5000 late() { }\n\n//\n// Join p1 and p2 to form p3 in tick 1000\n//\n\n999 late() {\n\t// create a zero-size subpop for the join\n\tsim.addSubpop(\"p3\", 0).setValue(\"K\", 750);\n}\n1000 reproduction() {\n\t// generate juveniles to seed p3\n\tfounderCount = rdunif(1, 10, 20);\n\tp1_inds = p1.individuals;\n\tp2_inds = p2.individuals;\n\tall_inds = c(p1_inds, p2_inds);\n\t\n\tfor (i in seqLen(founderCount))\n\t{\n\t\t// select a first parent with equal probabilities\n\t\tparent1 = sample(all_inds, 1);\n\t\t\n\t\t// select a second parent with a bias toward p2\n\t\tif (rdunif(1) < 0.2)\n\t\t\tparent2 = sample(p1_inds, 1);\n\t\telse\n\t\t\tparent2 = sample(p2_inds, 1);\n\t\t\n\t\t// generate the offspring into p3\n\t\tp3.addCrossed(parent1, parent2);\n\t}\n\t\n\t// we're done, don't run again this tick\n\tself.active = 0;\n}\n1000 early() {\n\t// get rid of p1 and p2 now\n\tc(p1,p2).fitnessScaling = 0.0;\n}\n\n//\n// Split p3 to form a new founder subpop p4 in 2000\n//\n1999 late() {\n\t// create a zero-size subpop for the split\n\tsim.addSubpop(\"p4\", 0).setValue(\"K\", 100);\n}\n2000 reproduction() {\n\t// generate juveniles to seed p4\n\tfounderCount = rdunif(1, 10, 20);\n\tall_inds = p3.individuals;\n\t\n\tfor (i in seqLen(founderCount))\n\t{\n\t\t// select parent1/parent2 with equal probabilities\n\t\tparent1 = sample(all_inds, 1);\n\t\tparent2 = sample(all_inds, 1);\n\t\t\n\t\t// generate the offspring into p4\n\t\tp4.addCrossed(parent1, parent2);\n\t}\n\t\n\t// we're done, don't run again this tick\n\tself.active = 0;\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model I.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, Wright-Fisher, non-overlapping generations, discrete generations\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.0, \"f\", -0.5);\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.05));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tK = sim.getValue(\"K\");\n\t\n\t// parents are chosen randomly, irrespective of fitness\n\tparents1 = p1.sampleIndividuals(K, replace=T);\n\tparents2 = p1.sampleIndividuals(K, replace=T);\n\t\n\tfor (i in seqLen(K))\n\t\tp1.addCrossed(parents1[i], parents2[i]);\n\t\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.setValue(\"K\", 500);\n\tsim.addSubpop(\"p1\", sim.getValue(\"K\"));\n}\nearly()\n{\n\t// parents die; offspring survive proportional to fitness\n\tinds = sim.subpopulations.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.12 - Implementing a Wright-Fisher model with a nonWF model II.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, Wright-Fisher, non-overlapping generations, discrete generations\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.0, \"f\", -0.5);\n\tc(m1,m2).convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 0.05));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tK = sim.getValue(\"K\");\n\t\n\t// parents are chosen proportional to fitness\n\tinds = p1.individuals;\n\tfitness = p1.cachedFitness(NULL);\n\tparents1 = sample(inds, K, replace=T, weights=fitness);\n\tparents2 = sample(inds, K, replace=T, weights=fitness);\n\t\n\tfor (i in seqLen(K))\n\t\tp1.addCrossed(parents1[i], parents2[i]);\n\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.setValue(\"K\", 500);\n\tsim.addSubpop(\"p1\", sim.getValue(\"K\"));\n}\nsurvival() {\n\t// survival is independent of fitness; parents die, offspring live\n\treturn (individual.age == 0);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.13 - Range expansion in a stepping-stone model I.txt",
    "content": "// Keywords: range expansion, colonization, population spread, migration\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);   // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"M\", 0.01);   // migration probability\n\tdefineConstant(\"R\", 1.04);   // mean reproduction (as first parent)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// individuals reproduce locally, without dispersal\n\tlitterSize = rpois(1, R);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\t// generate each offspring with an independently drawn mate\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tif (mate.size())\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\t// create an initial population of 100 individuals, the rest empty\n\tfor (i in seqLen(N))\n\t\tsim.addSubpop(i, (i == 0) ? 100 else 0);\n}\n1 late() {\n\t// set up a log file\n\tlog = community.createLogFile(\"sim_log.txt\", sep=\"\\t\", logInterval=10);\n\tlog.addCycle();\n\tlog.addPopulationSize();\n\tlog.addMeanSDColumns(\"size\", \"sim.subpopulations.individualCount;\");\n\tlog.addCustomColumn(\"pop_migrants\", \"sum(sim.subpopulations.individuals.migrant);\");\n\tlog.addMeanSDColumns(\"migrants\",\n\t\t\"sapply(sim.subpopulations, 'sum(applyValue.individuals.migrant);');\");\n}\nearly() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// non-overlapping generations; kill off the parental generation\n\tages = inds.age;\n\tinds[ages > 0].fitnessScaling = 0.0;\n\tinds = inds[ages == 0];\n\t\n\t// pre-plan migration of individuals to adjacent subpops\n\tnumMigrants = rbinom(1, inds.size(), M);\n\t\n\tif (numMigrants)\n\t{\n\t\tmigrants = sample(inds, numMigrants);\n\t\tcurrentSubpopID = migrants.subpopulation.id;\n\t\tdisplacement = -1 + rbinom(migrants.size(), 1, 0.5) * 2; // -1 or +1\n\t\tnewSubpopID = currentSubpopID + displacement;\n\t\tactuallyMoving = (newSubpopID >= 0) & (newSubpopID < N);\n\t\t\n\t\tif (sum(actuallyMoving))\n\t\t{\n\t\t\tmigrants = migrants[actuallyMoving];\n\t\t\tnewSubpopID = newSubpopID[actuallyMoving];\n\t\t\t\n\t\t\t// do the pre-planned moves into each subpop in bulk\n\t\t\tfor (subpop in sim.subpopulations)\n\t\t\t\tsubpop.takeMigrants(migrants[newSubpopID == subpop.id]);\n\t\t}\n\t}\n\t\n\t// post-migration density-dependent fitness for each subpop\n\tfor (subpop in sim.subpopulations)\n\t{\n\t\tjuvenileCount = sum(subpop.individuals.age == 0);\n\t\tsubpop.fitnessScaling = K / juvenileCount;\n\t}\n}\n1001 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.13 - Range expansion in a stepping-stone model II.txt",
    "content": "// Keywords: range expansion, colonization, population spread, migration\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);   // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"M\", 0.01);   // migration probability\n\tdefineConstant(\"R\", 1.04);   // mean reproduction (as first parent)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// individuals reproduce locally, without dispersal\n\tlitterSize = rpois(1, R);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\t// generate each offspring with an independently drawn mate\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tif (mate.size())\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\t// create an initial population of 100 individuals, the rest empty\n\tfor (i in seqLen(N))\n\t\tsim.addSubpop(i, (i == 0) ? 100 else 0);\n}\n1 late() {\n\t// set up a log file\n\tlog = community.createLogFile(\"sim_log.txt\", sep=\"\\t\", logInterval=10);\n\tlog.addCycle();\n\tlog.addPopulationSize();\n\tlog.addMeanSDColumns(\"size\", \"sim.subpopulations.individualCount;\");\n\tlog.addCustomColumn(\"pop_migrants\", \"sum(sim.subpopulations.individuals.migrant);\");\n\tlog.addMeanSDColumns(\"migrants\",\n\t\t\"sapply(sim.subpopulations, 'sum(applyValue.individuals.migrant);');\");\n}\nearly() {\n\t// non-overlapping generations; kill off the parental generation\n\tinds = sim.subpopulations.individuals;\n\tsim.killIndividuals(inds[inds.age > 0]);\n\t\n\t// pre-migration density-dependent fitness for each subpop\n\tfor (subpop in sim.subpopulations)\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n}\nsurvival() {\n\t// honor SLiM's survival decision\n\tif (!surviving)\n\t\treturn NULL;\n\t\n\t// migrate with probability M\n\tif (runif(1) >= M)\n\t\treturn NULL;\n\t\n\t// migrate the focal individual to an adjacent subpop\n\tsubpops = sim.subpopulations;\n\tnewSubpopID = subpop.id + (-1 + rbinom(1, 1, 0.5) * 2);\t// -1 or +1\n\tnewSubpop = subpops[subpops.id == newSubpopID];\n\tif (newSubpop.size())\n\t\treturn newSubpop;\n\treturn NULL;\n}\n1001 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.14 - Logistic population growth with the Beverton-Holt model.txt",
    "content": "// Keywords: logistic growth, logistic population model, carrying capacity, density dependence\n\ninitialize() {\n\tdefineConstant(\"K\", 50000);\n\tdefineConstant(\"R\", 1.1);\n\tdefineConstant(\"M\", K / (R - 1));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 50);   // the \"simple model\"\n\tsim.addSubpop(\"p2\", 50);   // Beverton-Holt influencing fecundity\n\tsim.addSubpop(\"p3\", 50);   // Beverton-Holt influencing survival\n\t\n\tlog = community.createLogFile(\"sim_log.txt\", logInterval=1);\n\tlog.addCycle();\n\tlog.addSubpopulationSize(p1);\n\tlog.addSubpopulationSize(p2);\n\tlog.addSubpopulationSize(p3);\n}\nreproduction(p1) {\n\t// p1 simply reproduces with a mean litter size of R, like p3\n\tlitterSize = rpois(1, R);\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nreproduction(p2) {\n\t// p2 reproduces up to the Beverton-Holt equation's target\n\tn_t = subpop.individualCount;\n\tn_t_plus_1 = (R * n_t) / (1 + n_t / M);\n\tmean_litter_size = n_t_plus_1 / n_t;\n\tlitterSize = rpois(1, mean_litter_size);\n\t\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nreproduction(p3) {\n\t// p3 simply reproduces with a mean litter size of R, like p1\n\tlitterSize = rpois(1, R);\n\tfor (i in seqLen(litterSize))\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\nearly() {\n\t// p1 uses the \"simple model\" with non-overlapping generations\n\tinds = p1.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tn_t_plus_pt5 = sum(inds.age == 0);\n\tp1.fitnessScaling = K / n_t_plus_pt5;\n\t\n\t// p2 has selection only to achieve non-overlapping generations\n\tinds = p2.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\t\n\t// p3 uses the Beverton-Holt equation for survival\n\tinds = p3.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tn_t_plus_pt5 = sum(inds.age == 0);\n\tp3.fitnessScaling = 1 / (1 + (n_t_plus_pt5 / R) / M);\n}\n200 late() {\n\t// log out the final row before plotting\n\tlog = community.logFiles;\n\tlog.logRow();\n\tlog.setLogInterval(NULL);\n\t\n\t// make a final plot\n\tif (exists(\"slimgui\"))\n\t{\n\t\tcycle_data = slimgui.logFileData(log, \"cycle\");\n\t\tp1_data = slimgui.logFileData(log, \"p1_num_individuals\");\n\t\tp2_data = slimgui.logFileData(log, \"p2_num_individuals\");\n\t\tp3_data = slimgui.logFileData(log, \"p3_num_individuals\");\n\t\t\n\t\tplot = slimgui.createPlot(\"Population Growth\",\n\t\t\txlab=\"Generation\", ylab=\"Population size\",\n\t\t\twidth=500, height=250);\n\t\t\n\t\tplot.abline(h=50000, color=\"#999999\", lwd=1.0);\n\t\t\n\t\tplot.lines(cycle_data, p1_data, \"cornflowerblue\", lwd=2);\n\t\tplot.lines(cycle_data, p2_data, \"red\", lwd=2);\n\t\tplot.lines(cycle_data, p3_data, \"chartreuse3\", lwd=2);\n\t\t\n\t\tplot.addLegend(\"topLeft\", inset=0, labelSize=13);\n\t\tplot.legendLineEntry(\"p1\", \"cornflowerblue\", lwd=2);\n\t\tplot.legendLineEntry(\"p2\", \"red\", lwd=2);\n\t\tplot.legendLineEntry(\"p3\", \"chartreuse3\", lwd=2);\n\t\t\n\t\tplot.write(\"Population Growth.pdf\");\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.2 - Age structure (a life table model).txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 30);\n\tdefineConstant(\"L\", c(0.7, 0.0, 0.0, 0.0, 0.25, 0.5, 0.75, 1.0));\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tif (individual.age > 2) {\n\t\tmate = subpop.sampleIndividuals(1, minAge=3);\n\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tp1.individuals.age = rdunif(10, min=0, max=7);\n}\nearly() {\n\t// life table based individual mortality\n\tinds = p1.individuals;\n\tages = inds.age;\n\tmortality = L[ages];\n\tsurvival = 1 - mortality;\n\tinds.fitnessScaling = survival;\n\t\n\t// density-dependence, factoring in individual mortality\n\tp1.fitnessScaling = K / (p1.individualCount * mean(survival));\n}\nlate() {\n\t// print our age distribution after mortality\n\tcatn(sim.cycle + \": \" + paste(sort(p1.individuals.age)));\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.3 - Handling all reproduction at once with big bang reproduction.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tfor (s in sim.subpopulations)\n\t{\n\t\tfor (ind in s.individuals)\n\t\t{\n\t\t\ts.addCrossed(ind, s.sampleIndividuals(1));\n\t\t}\n\t}\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.4 - Monogamous mating and variation in litter size.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// randomize the order of p1.individuals\n\tparents = sample(p1.individuals, p1.individualCount);\n\t\n\t// draw monogamous pairs and generate litters\n\tfor (i in seq(0, p1.individualCount - 2, by=2))\n\t{\n\t\tparent1 = parents[i];\n\t\tparent2 = parents[i + 1];\n\t\tp1.addCrossed(parent1, parent2, count=rpois(1, 2.7));\n\t}\n\t\n\t// disable this callback for this cycle\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.5 - Beneficial mutations and absolute fitness.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);   // dominant beneficial\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tfor (i in 1:5)\n\t\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\n100 early() {\n\tmutant = sample(p1.individuals.haplosomes, 10);\n\tmutant.addNewDrawnMutation(m2, 10000);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\tinds = p1.individuals;\n\tcatn(sim.cycle + \": \" + size(inds) + \" (\" + max(inds.age) + \")\");\n}\n2000 late() {\n\tsim.outputFull(ages=T);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.6 - A metapopulation extinction-colonization model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, migration, dispersal\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 50);     // carrying capacity per subpop\n\tdefineConstant(\"N\", 10);     // number of subpopulations\n\tdefineConstant(\"m\", 0.01);   // migration rate\n\tdefineConstant(\"e\", 0.1);    // subpopulation extinction rate\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tfor (i in 1:N)\n\t\tsim.addSubpop(i, (i == 1) ? 10 else 0);\n}\nearly() {\n\t// random migration\n\tnIndividuals = sum(sim.subpopulations.individualCount);\n\tnMigrants = rpois(1, nIndividuals * m);\n\tmigrants = sample(sim.subpopulations.individuals, nMigrants);\n\t\n\tfor (migrant in migrants)\n\t{\n\t\tdo dest = sample(sim.subpopulations, 1);\n\t\twhile (dest == migrant.subpopulation);\n\t\t\n\t\tdest.takeMigrants(migrant);\n\t}\n\t\n\t// density-dependence and random extinctions\n\tfor (subpop in sim.subpopulations)\n\t{\n\t\tif (runif(1) < e)\n\t\t\tsim.killIndividuals(subpop.individuals);\n\t\telse\n\t\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n\t}\n}\nlate() {\n\tif (sum(sim.subpopulations.individualCount) == 0)\n\t\tstop(\"Global extinction in cycle \" + sim.cycle + \".\");\n}\n2000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.7 - Habitat choice.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, migration, dispersal\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.5, \"e\", 0.1);   // deleterious in p2\n\tm2.color = \"red\";\n\tinitializeMutationType(\"m3\", 0.5, \"e\", 0.1);   // deleterious in p1\n\tm3.color = \"green\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2,m3), c(0.98,0.01,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tdest = sample(sim.subpopulations, 1);\n\tdest.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tsim.addSubpop(\"p2\", 10);\n}\nearly() {\n\t// habitat choice\n\tinds = sim.subpopulations.individuals;\n\tinds_m2 = inds.countOfMutationsOfType(m2);\n\tinds_m3 = inds.countOfMutationsOfType(m3);\n\tpref_p1 = 0.5 + (inds_m2 - inds_m3) * 0.1;\n\tpref_p1 = pmax(pmin(pref_p1, 1.0), 0.0);\n\tinertia = ifelse(inds.subpopulation.id == 1, 1.0, 0.0);\n\tpref_p1 = pref_p1 * 0.75 + inertia * 0.25;\n\tchoice = ifelse(runif(inds.size()) < pref_p1, 1, 2);\n\tmoving = inds[choice != inds.subpopulation.id];\n\tfrom_p1 = moving[moving.subpopulation == p1];\n\tfrom_p2 = moving[moving.subpopulation == p2];\n\tp2.takeMigrants(from_p1);\n\tp1.takeMigrants(from_p2);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n\tp2.fitnessScaling = K / p2.individualCount;\n}\nmutationEffect(m2, p2) { return 1/effect; }\nmutationEffect(m3, p1) { return 1/effect; }\n1000 late() {\n\tfor (id in 1:2)\n\t{\n\t\tsubpop = sim.subpopulations[sim.subpopulations.id == id];\n\t\ts = subpop.individualCount;\n\t\tinds = subpop.individuals;\n\t\tc2 = sum(inds.countOfMutationsOfType(m2));\n\t\tc3 = sum(inds.countOfMutationsOfType(m3));\n\t\tcatn(\"subpop \" + id + \" (\" + s + \"): \" + c2 + \" m2, \" + c3 + \" m3\");\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.8 - Evolutionary rescue after environmental change.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, QTL, quantitative trait loci\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\n\tdefineConstant(\"opt1\", 0.0);\n\tdefineConstant(\"opt2\", 10.0);\n\tdefineConstant(\"Tdelta\", 10000);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 1.0);  // QTL\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nearly() {\n\t// QTL-based fitness\n\tinds = sim.subpopulations.individuals;\n\tphenotypes = inds.sumOfMutationsOfType(m1);\n\toptimum = (sim.cycle < Tdelta) ? opt1 else opt2;\n\tdeviations = optimum - phenotypes;\n\tfitnessFunctionMax = dnorm(0.0, 0.0, 5.0);\n\tadaptation = dnorm(deviations, 0.0, 5.0) / fitnessFunctionMax;\n\tinds.fitnessScaling = 0.1 + adaptation * 0.9;\n\tinds.tagF = phenotypes;   // just for output below\n\t\n\t// density-dependence with a maximum benefit at low density\n\tp1.fitnessScaling = min(K / p1.individualCount, 1.5);\n}\nmutationEffect(m1) { return 1.0; }\nlate() {\n\tif (p1.individualCount == 0)\n\t{\n\t\t// stop at extinction\n\t\tcatn(\"Extinction in cycle \" + sim.cycle + \".\");\n\t\tsim.simulationFinished();\n\t}\n\telse\n\t{\n\t\t// output the phenotypic mean and pop size\n\t\tphenotypes = p1.individuals.tagF;\n\t\t\n\t\tcat(sim.cycle + \": \" + p1.individualCount + \" individuals\");\n\t\tcat(\", phenotype mean \" + mean(phenotypes));\n\t\tif (size(phenotypes) > 1)\n\t\t\tcat(\" (sd \" + sd(phenotypes) + \")\");\n\t\tcatn();\n\t}\n}\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 15.9 - Litter size and parental investment.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, sexual, QTL, quantitative trait loci, reproduction()\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.3);  // QTL\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\n\tif (mate.size())\n\t{\n\t\tqtlValue = individual.tagF;\n\t\texpectedLitterSize = max(0.0, qtlValue + 3);\n\t\tlitterSize = rpois(1, expectedLitterSize);\n\t\tpenalty = 3.0 / litterSize;\n\t\t\n\t\tfor (i in seqLen(litterSize))\n\t\t{\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\toffspring.setValue(\"penalty\", rgamma(1, penalty, 20));\n\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setValue(\"penalty\", 1.0);\n}\nearly() {\n\t// non-overlapping generations\n\tinds = sim.subpopulations.individuals;\n\tinds[inds.age > 0].fitnessScaling = 0.0;\n\tinds = inds[inds.age == 0];  // focus on juveniles\n\t\n\t// QTL calculations\n\tinds.tagF = inds.sumOfMutationsOfType(m2);\n\t\n\t// parental investment fitness penalties\n\tinds.fitnessScaling = inds.getValue(\"penalty\");\n\t\n\t// density-dependence for juveniles\n\tp1.fitnessScaling = K / size(inds);\n}\nmutationEffect(m2) { return 1.0; }\nlate() {\n\t// output the phenotypic mean and pop size\n\tqtlValues = p1.individuals.tagF;\n\texpectedSizes = pmax(0.0, qtlValues + 3);\n\t\n\tcat(sim.cycle + \": \" + p1.individualCount + \" individuals\");\n\tcat(\", mean litter size \" + mean(expectedSizes));\n\tcatn();\n}\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.1 - Pollen flow.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 200);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// determine how many ovules were fertilized, out of the total\n\tfertilizedOvules = rbinom(1, 30, 0.5);\n\t\n\t// determine the pollen source for each fertilized ovule\n\tother = (subpop == p1) ? p2 else p1;\n\tpollenSources = ifelse(runif(fertilizedOvules) < 0.99, subpop, other);\n\t\n\t// generate seeds from each fertilized ovule\n\t// the ovule belongs to individual, the pollen comes from source\n\tfor (source in pollenSources)\n\t\tsubpop.addCrossed(individual, source.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\tsim.addSubpop(\"p2\", 10);\n}\nearly() {\n\tfor (subpop in sim.subpopulations)\n\t\tsubpop.fitnessScaling = K / subpop.individualCount;\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.10 - Modeling pseudo-autosomal regions (PARs) with addMultiRecombinant().txt",
    "content": "// Keywords: multiple chromosomes, pseudo-autosomal region (PAR)\n\ninitialize() {\n\tdefineConstant(\"A1_LEN\", 2e7);\n\tdefineConstant(\"PAR1_LEN\", 2771479);\n\tdefineConstant(\"PAR2_LEN\", 329513);\n\tdefineConstant(\"X_LEN\", 156040895 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"Y_LEN\", 57227415 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"MU\", 1e-8);\n\tdefineConstant(\"R\", 1e-7);\n\tdefineConstant(\"N\", 500);\n\tdefineConstant(\"REC\", N*10);      // start recording at this tick\n\tdefineConstant(\"RUNTIME\", N*50);  // finish at this tick\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0).convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:5, length in c(A1_LEN, PAR1_LEN, X_LEN, Y_LEN, PAR2_LEN),\n\t\ttype in c(\"A\",\"A\",\"X\",\"Y\",\"A\"), symbol in c(\"A1\",\"P1\",\"X\",\"Y\",\"P2\"))\n\t{\n\t\tchr = initializeChromosome(id, length, type=type, symbol=symbol);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeMutationRate(MU);\n\t\tinitializeRecombinationRate(R);\n\t\tdefineConstant(paste0(\"CHR_\", symbol), chr);\n\t}\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n}\nREC late() {\n\tlog = community.createLogFile(\"PAR_Ne.csv\", logInterval=10);\n\tlog.addTick();\n\tlog.addCustomColumn(\"Ne_A1\", \"estimateNe_Heterozygosity(p1, CHR_A1);\");\n\tlog.addCustomColumn(\"Ne_P1\", \"estimateNe_Heterozygosity(p1, CHR_P1);\");\n\tlog.addCustomColumn(\"Ne_X\", \"estimateNe_Heterozygosity(p1, CHR_X);\");\n\tlog.addCustomColumn(\"Ne_Y\", \"estimateNe_Heterozygosity(p1, CHR_Y);\");\n\tlog.addCustomColumn(\"Ne_P2\", \"estimateNe_Heterozygosity(p1, CHR_P2);\");\n\tdefineConstant(\"LOG\", log);\n}\nreproduction()\n{\n\tfor (i in seqLen(N))\n\t{\n\t\tparentF = p1.sampleIndividuals(1, sex=\"F\");\n\t\tparentM = p1.sampleIndividuals(1, sex=\"M\");\n\t\n\t\t// generate breakpoints for the female parent (X recombines)\n\t\tbreaks_F_P1 = CHR_P1.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_X = CHR_X.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_P2 = CHR_P2.drawBreakpoints(parent=parentF);\n\t\t\n\t\t// generate breakpoints for the male parent (only PARs recombine)\n\t\tbreaks_M_P1 = CHR_P1.drawBreakpoints(parent=parentM);\n\t\tbreaks_M_P2 = CHR_P2.drawBreakpoints(parent=parentM);\n\t\t\n\t\t// get the haplosomes for each chromosome in each parent\n\t\tstrands_F_P1 = parentF.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_F_X = parentF.haplosomesForChromosomes(CHR_X);    // 2\n\t\tstrands_F_P2 = parentF.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\tstrands_M_P1 = parentM.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_M_X = parentM.haplosomesForChromosomes(CHR_X)[0]; // 1\n\t\tstrands_M_Y = parentM.haplosomesForChromosomes(CHR_Y);    // 1\n\t\tstrands_M_P2 = parentM.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\t// choose initial copy strand indices for PAR1 in both (coin flip)\n\t\tinitial_F_P1 = rbinom(1, 1, 0.5);\n\t\tinitial_M_P1 = rbinom(1, 1, 0.5);\n\t\t\n\t\t// generate the inheritance dictionary for PAR1\n\t\ts1_F_P1 = strands_F_P1[initial_F_P1];\n\t\ts2_F_P1 = strands_F_P1[1 - initial_F_P1];\n\t\t\n\t\ts1_M_P1 = strands_M_P1[initial_M_P1];\n\t\ts2_M_P1 = strands_M_P1[1 - initial_M_P1];\n\t\t\n\t\tpattern = sim.addPatternForRecombinant(CHR_P1, NULL,\n\t\t\ts1_F_P1, s2_F_P1, breaks_F_P1, s1_M_P1, s2_M_P1, breaks_M_P1,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// the initial strand for the X in the female follows from the\n\t\t// above, because PAR1 is physically linked to the start of the\n\t\t// X; if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_X = initial_F_P1;\n\t\tif (size(breaks_F_P1) % 2 == 1) initial_F_X = 1 - initial_F_X;\n\t\tif (runif(1) < R) initial_F_X = 1 - initial_F_X;\n\t\t\n\t\t// do the same for the male, but the \"initial strand\" is the\n\t\t// X if 0, the Y if 1, and it determines the offspring sex\n\t\tinitial_M_XY = initial_M_P1;\n\t\tif (size(breaks_M_P1) % 2 == 1) initial_M_XY = 1 - initial_M_XY;\n\t\tif (runif(1) < R) initial_M_XY = 1 - initial_M_XY;\n\t\t\n\t\tsex = ((initial_M_XY == 0) ? \"F\" else \"M\");\n\t\t\n\t\t// generate the inheritance dictionaries for the X and Y\n\t\ts1_F_X = strands_F_X[initial_F_X];\n\t\ts2_F_X = strands_F_X[1 - initial_F_X];\n\t\t\n\t\tif (sex == \"F\")\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, strands_M_X, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForNull(CHR_Y, pattern, sex=sex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, NULL, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForClone(CHR_Y, pattern, parent=parentM, sex=sex);\n\t\t}\n\t\t\n\t\t// and the initial copy strand for PAR2 follows from the above,\n\t\t// because PAR2 is physically linked to the end of the X/Y;\n\t\t// if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_P2 = initial_F_X;\n\t\tif (size(breaks_F_X) % 2 == 1) initial_F_P2 = 1 - initial_F_P2;\n\t\tif (runif(1) < R) initial_F_P2 = 1 - initial_F_P2;\n\t\t\n\t\tinitial_M_P2 = initial_M_XY;\n\t\tif (runif(1) < R) initial_M_P2 = 1 - initial_M_P2;\n\t\t\n\t\t// generate the inheritance dictionary for PAR2\n\t\ts1_F_P2 = strands_F_P2[initial_F_P2];\n\t\ts2_F_P2 = strands_F_P2[1 - initial_F_P2];\n\t\t\n\t\ts1_M_P2 = strands_M_P2[initial_M_P2];\n\t\ts2_M_P2 = strands_M_P2[1 - initial_M_P2];\n\t\t\n\t\tsim.addPatternForRecombinant(CHR_P2, pattern,\n\t\t\ts1_F_P2, s2_F_P2, breaks_F_P2, s1_M_P2, s2_M_P2, breaks_M_P2,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// finally, generate the offspring following the pattern dictionary\n\t\tsubpop.addMultiRecombinant(pattern, sex=sex,\n\t\t\tparent1=parentF, parent2=parentM, randomizeStrands=F);\n\t}\n\t\n\tself.active = 0;\n}\n2: early() {\n\t// non-overlapping generations\n\tadults = p1.subsetIndividuals(minAge=1);\n\tsim.killIndividuals(adults);\n}\nREC:(RUNTIME+1) early() {\n\t// plot results that got logged the previous tick (which ended in 0)\n\tif ((community.tick % 10 == 1) & exists(\"slimgui\"))\n\t{\n\t\tticks = slimgui.logFileData(LOG, \"tick\");\n\t\tNe_A1 = slimgui.logFileData(LOG, \"Ne_A1\");\n\t\tNe_P1 = slimgui.logFileData(LOG, \"Ne_P1\");\n\t\tNe_X = slimgui.logFileData(LOG, \"Ne_X\");\n\t\tNe_Y = slimgui.logFileData(LOG, \"Ne_Y\");\n\t\tNe_P2 = slimgui.logFileData(LOG, \"Ne_P2\");\n\t\t\n\t\tplot = slimgui.createPlot(\"Ne Estimates\",\n\t\t\txrange=c(REC, RUNTIME), yrange=c(0, N * 2),\n\t\t\txlab=\"Tick\", ylab=\"Population size\",\n\t\t\twidth=1000, height=400);\n\t\tplot.axis(2, at=c(0, N, N*2));\n\t\t\n\t\tplot.abline(h=N, color=\"black\", lwd=2.0);\n\t\t\n\t\tplot.lines(ticks, Ne_A1, \"chartreuse3\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_A1), color=\"chartreuse3\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_P1, \"turquoise3\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_P1), color=\"turquoise3\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_X, \"red\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_X), color=\"red\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_Y, \"orchid2\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_Y), color=\"orchid2\", lwd=1.0);\n\t\t\n\t\tplot.lines(ticks, Ne_P2, \"cornflowerblue\", lwd=2.0);\n\t\tplot.abline(h=mean(Ne_P2), color=\"cornflowerblue\", lwd=1.0);\n\t\t\n\t\tplot.addLegend(\"topLeft\", labelSize=12);\n\t\tplot.legendLineEntry(\"N\", \"black\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (A1)\", \"chartreuse3\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (P1)\", \"turquoise3\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (X)\", \"red\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (Y)\", \"orchid2\", lwd=2.0);\n\t\tplot.legendLineEntry(\"Ne (P2)\", \"cornflowerblue\", lwd=2.0);\n\t\t\n\t\tif (community.tick == RUNTIME + 1)\n\t\t{\n\t\t\tplot.write(\"Ne_EST.pdf\");\n\t\t\tsim.simulationFinished();\n\t\t}\n\t}\n}\n\nfunction (float)estimateNe_Heterozygosity(o<Subpopulation>$ subpop,\n\t[No<Chromosome>$ chromosome = NULL])\n{\n\tif (isNULL(chromosome))\n\t{\n\t\tif (size(sim.chromosomes) == 1)\n\t\t\tchromosome = sim.chromosomes;\n\t\telse\n\t\t\tstop(\"ERROR: in a multi-chrom model, a chromosome must be supplied.\");\n\t}\n\t\n\thaplosomes = subpop.haplosomesForChromosomes(chromosome, includeNulls=F);\n\tpi = calcHeterozygosity(haplosomes);\n\treturn pi / (4 * MU);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.11 - Life-long monogamous mating.txt",
    "content": "// Keywords: monogamy, monogamous mating, nonWF, non-Wright-Fisher\n\ninitialize() {\n\tdefineConstant(\"K\", 500);       // carrying capacity\n\tdefineConstant(\"R_AGE_M\", 3);   // minimum age of reproduction (male)\n\tdefineConstant(\"R_AGE_F\", 4);   // minimum age of reproduction (female)\n\tdefineConstant(\"FECUN\", 0.2);   // mean fecundity per female per tick\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n}\n1 first() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.age = rdunif(K, min=0, max=15);   // initial variation in age\n\tp1.individuals.tag = -1;        // mark all individuals as unmated\n}\nfirst() {\n\t// find mated individuals whose mate has died, and mark them as unmated\n\tmated_individuals = p1.individuals;\n\tmated_individuals = mated_individuals[mated_individuals.tag >= 0];\n\t\n\tif (size(mated_individuals) > 0)\n\t{\n\t\ttags = mated_individuals.tag;\n\t\ttag_counts = tabulate(tags);\n\t\ttags_to_fix = which(tag_counts == 1);\n\t\tunmated_indices = match(tags_to_fix, tags);\n\t\tmated_individuals[unmated_indices].tag = -1;\n\t}\n\t\n\t// find the next tag value to use for new mating pairs\n\tnext_tag = max(p1.individuals.tag) + 1;\n\t\n\t// find unmated individuals that are of reproductive age\n\tunmated_F = p1.subsetIndividuals(sex=\"F\", tag=-1, minAge=R_AGE_F);\n\tunmated_M = p1.subsetIndividuals(sex=\"M\", tag=-1, minAge=R_AGE_M);\n\t\n\t// pair individuals randomly; some individuals may be left unpaired\n\tpair_count = min(size(unmated_F), size(unmated_M));\n\tunmated_F = sample(unmated_F, pair_count, replace=F);\n\tunmated_M = sample(unmated_M, pair_count, replace=F);\n\t\n\tfor (f in unmated_F, m in unmated_M, tag in seqLen(pair_count) + next_tag)\n\t{\n\t\tf.tag = tag;\n\t\tm.tag = tag;\n\t}\n}\nreproduction() {\n\t// find the subset of individuals that have a mate\n\tmated_F = p1.subsetIndividuals(sex=\"F\");\n\tmated_F = mated_F[mated_F.tag >= 0];\n\t\n\tmated_M = p1.subsetIndividuals(sex=\"M\");\n\tmated_M = mated_M[mated_M.tag >= 0];\n\t\n\t// look up the male for each female, by tag\n\tmale_indices = match(mated_F.tag, mated_M.tag);\n\tmated_M = mated_M[male_indices];\n\t\n\tpair_count = size(mated_F);\n\t\n\t// produce offspring from each mated pair\n\tfor (f in mated_F,\n\t\t  m in mated_M,\n\t\t  c in rpois(pair_count, FECUN),\n\t\t  new_tag in seqLen(pair_count))\n\t{\n\t\t// re-tag paired individuals to compact tags down\n\t\tf.tag = new_tag;\n\t\tm.tag = new_tag;\n\t\t\n\t\toffspring = p1.addCrossed(f, m, count=c);\n\t\toffspring.tag = -1;\t// mark offspring as unmated\n\t}\n\t\n\tself.active = 0;\t\t// deactivate for the rest of the tick (\"big bang\")\t\n}\nearly() {\n\t// density-dependent population regulation\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.2 - Following a pedigree.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher\n\nfunction (+)readMatrix(s$ path, [string$ sep = \",\"])\n{\n\tif (!fileExists(path))\n\t\tstop(\"readMatrix(): File not found at path \" + path);\n\tdf = readCSV(path, colNames=F, sep=sep);\n\tm = df.asMatrix();\n\treturn m;\n}\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 10);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// read in the pedigree log files\n\tdefineConstant(\"M\", readMatrix(\"mating.txt\", sep=\"\"));\n\tdefineConstant(\"D\", readMatrix(\"death.txt\", sep=\"\"));\n\t\n\t// extract the ticks for quick lookup\n\tdefineConstant(\"Mt\", drop(M[,0]));\n\tdefineConstant(\"Dt\", drop(D[,0]));\n}\nreproduction() {\n\t// generate all offspring for the tick\n\tm = M[Mt == community.tick,];\n\t\n\tfor (index in seqLen(nrow(m))) {\n\t\trow = m[index,];\n\t\tind = subpop.subsetIndividuals(tag=row[,1]);\n\t\tmate = subpop.subsetIndividuals(tag=row[,2]);\n\t\tchild = subpop.addCrossed(ind, mate);\n\t\tchild.tag = row[,3];\n\t}\n\t\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n\t\n\t// provide initial tags matching the original model\n\tp1.individuals.tag = 1:10;\n}\nearly() {\n\t// execute the predetermined mortality\n\tinds = p1.individuals;\n\tinds.fitnessScaling = 1.0;\n\t\n\td = drop(D[Dt == community.tick, 1]);\n\tindices = match(d, inds.tag);\n\tinds[indices].fitnessScaling = 0.0;\n}\n100 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.3 - Modeling clonal haploid bacteria with horizontal gene transfer.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, clonal, haploid\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 1e5);                      // carrying capacity\n\tdefineConstant(\"L\", 1e5);                      // chromosome length\n\tdefineConstant(\"H\", 0.001);                    // HGT probability\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);   // neutral (unused)\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.1);   // beneficial\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, L, type=\"H\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(0);                     // no mutation\n\tinitializeRecombinationRate(0);                // no recombination\n}\nreproduction() {\n\tif (runif(1) < H)\n\t{\n\t\t// horizontal gene transfer from a randomly chosen individual\n\t\tHGTsource = p1.sampleIndividuals(1, exclude=individual).haplosomes;\n\t\t\n\t\t// draw two distinct locations; redraw if we get a duplicate\n\t\tdo breaks = rdunif(2, max=L-1);\n\t\twhile (breaks[0] == breaks[1]);\n\t\t\n\t\t// HGT from breaks[0] forward to breaks[1] on a circular chromosome\n\t\tif (breaks[0] > breaks[1])\n\t\t\tbreaks = c(0, breaks[1], breaks[0]);\n\t\t\n\t\tsubpop.addRecombinant(individual.haplosomes, HGTsource, breaks, NULL, NULL, NULL, randomizeStrands=F);\n\t}\n\telse\n\t{\n\t\t// no horizontal gene transfer; clonal replication\n\t\tsubpop.addCloned(individual);\n\t}\n}\n1 early() {\n\t// start from two bacteria with different beneficial mutations\n\tsim.addSubpop(\"p1\", 2);\n\t\n\th = p1.individuals.haplosomes;\n\th[0].addNewDrawnMutation(m2, asInteger(L * 0.25));\n\th[1].addNewDrawnMutation(m2, asInteger(L * 0.75));\n}\nearly() {\n\t// density-dependent population regulation\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n\t// detect fixation/loss of the beneficial mutations\n\tmuts = sim.mutations;\n\tfreqs = sim.mutationFrequencies(NULL, muts);\n\t\n\tif (all(freqs == 1.0))\n\t{\n\t\tcatn(sim.cycle + \": \" + sum(freqs == 1.0) + \" fixed.\");\n\t\tsim.simulationFinished();\n\t}\n}\n1e6 late() { catn(sim.cycle + \": no result.\"); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.4 - Alternation of generations.txt",
    "content": "// Keywords: alternation of generations, sporophyte, gametophyte, sperm, eggs, diploid, haploid, mating system, fertilization, meiosis, reproduction()\n\ninitialize()\n{\n\tdefineConstant(\"K\", 500);     // carrying capacity (diploid)\n\tdefineConstant(\"MU\", 1e-7);   // mutation rate\n\tdefineConstant(\"R\", 1e-7);    // recombination rate\n\tdefineConstant(\"L1\", 1e5-1);  // chromosome end (length - 1)\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L1);\n\tinitializeRecombinationRate(R);\n}\n1 early()\n{\n\tsim.addSubpop(\"p1\", K);\n\tsim.addSubpop(\"p2\", 0);\n}\nreproduction(p1)\n{\n\tg_1 = individual.haploidGenome1;\n\tg_2 = individual.haploidGenome2;\n\t\n\tfor (meiosisCount in 1:5)\n\t{\n\t\tif (individual.sex == \"M\")\n\t\t{\n\t\t\tbreaks = sim.chromosomes.drawBreakpoints(individual);\n\t\t\ts_1 = p2.addRecombinant(g_1, g_2, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\ts_2 = p2.addRecombinant(g_2, g_1, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\t\n\t\t\tbreaks = sim.chromosomes.drawBreakpoints(individual);\n\t\t\ts_3 = p2.addRecombinant(g_1, g_2, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t\ts_4 = p2.addRecombinant(g_2, g_1, breaks, NULL, NULL, NULL, \"M\", randomizeStrands=F);\n\t\t}\n\t\telse if (individual.sex == \"F\")\n\t\t{\n\t\t\te = p2.addRecombinant(g_1, g_2, NULL, NULL, NULL, NULL, \"F\", randomizeStrands=T);\n\t\t}\n\t}\n}\nreproduction(p2, \"F\")\n{\n\tmate = p2.sampleIndividuals(1, sex=\"M\", tagL0=F);\n\tmate.tagL0 = T;\n\t\n\tchild = p1.addRecombinant(individual.haploidGenome1, NULL, NULL,\n\t\tmate.haploidGenome1, NULL, NULL);\n}\nearly()\n{\n\tif (sim.cycle % 2 == 0)\n\t{\n\t\tp1.fitnessScaling = 0.0;\n\t\tp2.individuals.tagL0 = F;\n\t\tsim.chromosomes.setMutationRate(0.0);\n\t}\n\telse\n\t{\n\t\tp2.fitnessScaling = 0.0;\n\t\tp1.fitnessScaling = K / p1.individualCount;\n\t\tsim.chromosomes.setMutationRate(MU);\n\t}\n}\n10000 late()\n{\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.5 - Meiotic drive.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, meiotic drive, segregation distortion, intragenomic conflict\n\nfunction (i)driveBreakpoints(o<Haplosome>$ gen1, o<Haplosome>$ gen2)\n{\n\t// start with default breakpoints generated by the chromosome\n\tbreaks = sim.chromosomes.drawBreakpoints();\n\t\n\t// if both haplosomes have the drive, or neither, then just return\n\tgen1has = gen1.containsMarkerMutation(m2, D_pos);\n\tgen2has = gen2.containsMarkerMutation(m2, D_pos);\n\tif (gen1has == gen2has)\n\t\treturn breaks;\n\t\n\t// will the drive be inherited?  do we want it to be?\n\tpolarity = sum(breaks <= D_pos) % 2;   // 0 for gen1, 1 for gen2\n\tpolarityI = (gen1has ? 0 else 1);\n\tdesiredPolarity = (runif(1) < D_prob) ? polarityI else !polarityI;\n\t\n\t// intervene to produce the outcome we want\n\tif (desiredPolarity != polarity)\n\t\treturn c(0, breaks);\n\treturn breaks;\n}\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);        // carrying capacity\n\tdefineConstant(\"D_pos\", 20000);  // meiotic drive allele position\n\tdefineConstant(\"D_prob\", 0.8);   // meiotic drive probability\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeMutationType(\"m2\", 0.1, \"f\", -0.1);  // drive allele\n\tm2.color = \"red\";\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\tm = subpop.sampleIndividuals(1);\n\tb1 = driveBreakpoints(individual.haploidGenome1, individual.haploidGenome2);\n\tb2 = driveBreakpoints(m.haploidGenome1, m.haploidGenome2);\n\tsubpop.addRecombinant(individual.haploidGenome1, individual.haploidGenome2, b1, m.haploidGenome1, m.haploidGenome2, b2, randomizeStrands=F);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n100 early() {\n\ttarget = sample(p1.haplosomes, 10);\n\ttarget.addNewDrawnMutation(m2, D_pos);\n}\n100:1000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 0) {\n\t\tcatn(sim.cycle + \": LOST\");\n\t\tsim.simulationFinished();\n\t} else if (sim.mutationFrequencies(NULL, mut) == 1.0) {\n\t\tcatn(sim.cycle + \": FIXED\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.6 - Sperm storage with a survival() callback.txt",
    "content": "// Keywords: survival(), sperm storage\n\n// This model is loosely based upon a model by Anita Lerch.\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeSex();\n\tdefineConstant(\"K\", 500);\n\t\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\n}\nreproduction(p1) {\n\tmatureFemales = subpop.subsetIndividuals(sex=\"F\", minAge=7);\n\t\n\tfor (female in matureFemales)\n\t{\n\t\tif (female.tag < 0) {\n\t\t\t// the female has not yet chosen a mate, so choose one now\n\t\t\tmate = subpop.sampleIndividuals(1, sex=\"M\", minAge=7);\n\t\t} else {\n\t\t\t// the female has already chosen a mate; look it up by id\n\t\t\tmate = sim.individualsWithPedigreeIDs(female.tag);\n\t\t}\n\t\tif (mate.size()) {\n\t\t\tfemale.tag = mate.pedigreeID;\n\t\t\tsubpop.addCrossed(female, mate, count=rpois(1, 5));\n\t\t} else {\n\t\t\tcatn(sim.cycle + \": No mate found for tag \" + female.tag);\n\t\t}\n\t}\n\tself.active = 0;\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1inds = p1.individuals;\n\tp1inds.age = rdunif(size(p1.individuals), min=0, max=10);\n\tp1inds.tag = -1;\n\t\n\tsim.addSubpop(\"p1000\", 0);   // cold storage for dead males\n}\nearly() {\n\t// fix all new female tags; faster to do this vectorized\n\toffspringFemales = p1.subsetIndividuals(sex=\"F\", maxAge=0);\n\toffspringFemales.tag = -1;\n\t\n\t// p1 is governed by standard density-dependence\n\tp1.fitnessScaling = K / p1.individualCount;\n\t\n\t// cold storage individuals are kept until unreferenced\n\tp1000.individuals.tag = 0;\n\tmaleRefs = p1.subsetIndividuals(sex=\"F\").tag;\n\tmaleRefs = maleRefs[maleRefs != -1];\n\treferencedDeadMales = sim.individualsWithPedigreeIDs(maleRefs, p1000);\n\treferencedDeadMales.tag = 1;\n}\nsurvival(p1) {\n\t// move dying males into cold storage in case they have mated\n\tif (!surviving)\n\t\tif (individual.sex == \"M\")\n\t\t\treturn p1000;\n\treturn NULL;\n}\nsurvival(p1000) {\n\treturn (individual.tag == 1);\n}\nlate() {\n\tcatn(sim.cycle + \": p1 (\" + p1.individualCount + \")\" +\n\t\t\", p1000 (\" + p1000.individualCount + \")\");\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.7 - Tracking separate sexes in script, nonWF style.txt",
    "content": "// Keywords: automixis, parthenogenesis, sex determination, mating systems, sexual types\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tdefineConstant(\"K\", 500);\t// carrying capacity\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction() {\n\t// we focus on the reproduction of the females here\n\tif (individual.tagL0 == F)\n\t{\n\t\tif (runif(1) < 0.7)\n\t\t{\n\t\t\t// choose a male mate and produce a son or daughter\n\t\t\tmate = subpop.sampleIndividuals(1, tagL0=T);\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\toffspring.tagL0 = (runif(1) <= 0.5);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// reproduce through automixis to produce a daughter\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\toffspring.tagL0 = F;\n\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\t\n\t// assign random sexes (T = male, F = female)\n\tp1.individuals.tagL0 = (runif(p1.individualCount) <= 0.5);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n1:2000 late() {\n\tratio = mean(p1.individuals.tagL0);\n\tcatn(sim.cycle + \": \" + ratio);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.8 - Modeling haplodiploidy with addRecombinant().txt",
    "content": "// Keywords: mating systems, haplodiploidy, arrhenotoky, bees, wasps, ants, Hymenoptera\n\ninitialize() {\n\tdefineConstant(\"K\", 2000);\n\tdefineConstant(\"P_OFFSPRING_MALE\", 0.8);\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.0, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\tm1.hemizygousDominanceCoeff = 1.0;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-6);\n\tinitializeSex();\n}\nreproduction(NULL, \"F\") {\n\tgen1 = individual.haploidGenome1;\n\tgen2 = individual.haploidGenome2;\n\t\n\t// decide whether we're generating a haploid male or a diploid female\n\tif (rbinom(1, 1, P_OFFSPRING_MALE))\n\t{\n\t\t// didn't find a mate; make a haploid male from an unfertilized egg:\n\t\t//\t\t- one haplosome comes from recombination of the female's haplosomes\n\t\t//\t\t- the other haplosome is a null haplosome (a placeholder)\n\t\tsubpop.addRecombinant(gen1, gen2, NULL, NULL, NULL, NULL, \"M\",\n\t\t\trandomizeStrands=T);\n\t}\n\telse\n\t{\n\t\t// found a mate; make a diploid female from a fertilized egg:\n\t\t//\t\t- one haplosome comes from recombination of the female's haplosomes\n\t\t//\t\t- the other haplosome comes from the mate (a haploid male)\n\t\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\tsubpop.addRecombinant(gen1, gen2, NULL, mate.haploidGenome1, NULL, NULL, \"F\",\n\t\t\trandomizeStrands=T);\n\t}\n}\n1 early() {\n\t// make an initial population with the right genetics\n\tmCount = asInteger(K * P_OFFSPRING_MALE);\n\tfCount = K - mCount;\n\tsim.addSubpop(\"p1\", mCount, sexRatio=1.0, haploid=T);\t// males\n\tsim.addSubpop(\"p2\", fCount, sexRatio=0.0, haploid=F);\t// females\n\tp1.takeMigrants(p2.individuals);\n\tp2.removeSubpopulation();\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10000 late() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 16.9 - Complex multi-chromosome inheritance with addMultiRecombinant().txt",
    "content": "// Keywords: multiple chromosomes, inheritance patterns, mating systems\n\ninitialize() {\n\tdefineConstant(\"K\", 500);\t// carrying capacity\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\tids = 1:7;\n\tsymbols = c(\"A\", \"X\", \"Y\", \"P\", \"Q\", \"R\", \"S\");\n\tlengths = c(3e6, 2e6, 1e6, 1e6, 1e6, 1e6, 1e6);\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"H\", \"H\", \"H\");\n\t\n\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeRecombinationRate(1e-7);\n\t\tinitializeGenomicElement(g1);\n\t}\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\n\tpattern = Dictionary();\n\tsim.addPatternForClone(\"P\", pattern, individual);\n\tsim.addPatternForClone(\"Q\", pattern, runif(1) < 0.5 ? individual else mate);\n\tsim.addPatternForCross(\"R\", pattern, individual, mate);\n\tind_hapS = individual.haplosomesForChromosomes(\"S\");\n\tmate_hapS = mate.haplosomesForChromosomes(\"S\");\n\tsim.addPatternForRecombinant(\"S\", pattern, ind_hapS, mate_hapS, NULL,\n\t\tNULL, NULL, NULL);\n\tsubpop.addMultiRecombinant(pattern, parent1=individual, parent2=mate,\n\t\trandomizeStrands=F);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n1000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.1 - A simple 2D continuous-space model.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.10 - A simple biogeographic landscape model.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=30.0);\n\ti1.setInteractionFunction(\"n\", 5.0, 10.0);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=30.0);\n\ti2.setInteractionFunction(\"n\", 1.0, 10.0);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\t\n\tp1.setSpatialBounds(c(0.0, 0.0, 539.0, 216.0));\n\t\n\t// this file is in the recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tmapImage = Image(\"world_map_540x217.png\");\n\tmap = p1.defineSpatialMap(\"world\", \"xy\", 1.0 - mapImage.floatK,\n\t\tvalueRange=c(0.0, 1.0), colors=c(\"#0000CC\", \"#55FF22\"));\n\tdefineConstant(\"WORLD\", map);\n\t\n\t// start near a specific map location\n\tfor (ind in p1.individuals) {\n\t\tind.x = rnorm(1, 300.0, 1.0);\n\t\tind.y = rnorm(1, 100.0, 1.0);\n\t}\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds) / size(inds);\n\tcompetition = pmin(competition, 0.99);\n\tinds.fitnessScaling = 1.0 - competition;\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\treturn i2.strength(individual);\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 2.0);\n\twhile (!p1.pointInBounds(pos));\n\t\n\t// prevent dispersal into water\n\tif (WORLD.mapValue(pos) == 0.0)\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.11 - Local adaptation on a heterogeneous landscape map.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, reprising boundaries, QTL, quantitative trait loci, spatial competition, spatial mate choice\n\ninitialize() {\n\tdefineConstant(\"SIGMA_C\", 0.1);\n\tdefineConstant(\"SIGMA_K\", 0.5);\n\tdefineConstant(\"SIGMA_M\", 0.1);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.1));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"xyz\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"xyz\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setSpatialBounds(c(0.0, 0.0, 0.0, 1.0, 1.0, 1.0));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N));\n\tp1.individuals.z = 0.0;\n\t\n\tdefineConstant(\"MAPVALUES\", matrix(runif(25, 0, 1), ncol=5));\n\tmap = p1.defineSpatialMap(\"map1\", \"xy\", MAPVALUES, interpolate=T,\n\t\tvalueRange=c(0.0, 1.0), colors=c(\"red\", \"yellow\"));\n\tdefineConstant(\"OPTIMUM\", map);\n}\nmodifyChild() {\n\t// set offspring position based on parental position\n\tdo pos = c(parent1.spatialPosition[0:1] + rnorm(2, 0, 0.005), 0.0);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n1: late() {\n\t// construct phenotypes and fitness effects from QTLs\n\tinds = sim.subpopulations.individuals;\n\tphenotype = inds.sumOfMutationsOfType(m2);\n\tlocation = inds.spatialPosition[rep(c(T,T,F), inds.size())];\n\toptimum = OPTIMUM.mapValue(location);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotype, optimum, SIGMA_K);\n\tinds.z = phenotype;\n\t\n\t// color individuals according to phenotype\n\tinds.color = OPTIMUM.mapColor(phenotype);\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n10000 late() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.12 - Periodic spatial boundaries.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, periodic boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\tinitializeInteractionType(\"i1\", \"xy\", reciprocal=T, maxDistance=0.2);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 2000);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(2000));\n}\nlate()\n{\n\ti1.evaluate(p1);\n\tfocus = sample(p1.individuals, 1);\n\ts = i1.strength(focus);\n\tinds = p1.individuals;\n\tfor (i in seqAlong(s))\n\t\tinds[i].color = rgb2color(c(1.0 - s[i], 1.0 - s[i], s[i]));\n\tfocus.color = \"red\";\n}\nmodifyChild() {\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointPeriodic(pos));\n\treturn T;\n}\n1000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.13 - Density-dependent fecundity with summarizeIndividuals().txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial map, density, competition, regulation, fertility, per unit area\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1000));\n}\nlate() {\n\tinds = p1.individuals;\n\tbounds = p1.spatialBounds;\n\t\n\t// make a density map: 0 is empty, 1 is maximum density\n\tdensity = summarizeIndividuals(inds, c(10, 10), bounds,\n\t\toperation=\"individuals.size();\", empty=0.0, perUnitArea=T);\n\tdensity = density / max(density);\n\tp1.defineSpatialMap(\"density\", \"xy\", density, F,\n\t\trange(density), c(\"black\", \"orange\", \"red\"));\n}\nmodifyChild() {\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.01);\n\tpos = p1.pointReflected(pos);\n\t\n\tif (runif(1) < p1.spatialMapValue(\"density\", pos))\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.14 - Directed dispersal with the SpatialMap class.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, spatial maps, directed dispersal\n\ninitialize() {\n\tdefineConstant(\"K\", 1000);\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(c(0.0, 0.0));\n\tp1.individuals.color = rainbow(K);\n\t\n\tdo {\n\t\tm = matrix(rbinom(16, 1, 0.2), ncol=4, byrow=T);\n\t\tm = cbind(m, m[,0]);\n\t\tm = rbind(m, m[0,]);\n\t} while ((sum(m) == 0) | (sum(m) == 1));\n\t\n\tmap = p1.defineSpatialMap(\"habitat\", \"xy\", m, valueRange=c(0,1), colors=c(\"black\", \"white\"));\n\tdefineConstant(\"MAP\", map);\n}\n2 late() {\n\tMAP.interpolate(15, method=\"cubic\");\n}\n3 late() {\n\tMAP.rescale();\n}\n4 late() {\n\tMAP.smooth(0.3, \"n\", 0.1);\n}\n5 late() {\n\tMAP.rescale();\n}\n6 late() {\n\tMAP.interpolate = T;\n}\n10 late() {\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n}\n11:100000 late() {\n\tinds = p1.individuals;\n\tpos = inds.spatialPosition;\n\tpos = MAP.sampleNearbyPoint(pos, INF, \"n\", 0.002);\n\tinds.setSpatialPosition(pos);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.15 - Spatial competition and spatial mate choice in a nonWF model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, periodic boundaries, selfing\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\tdefineConstant(\"K\", 300);   // carrying capacity\n\tdefineConstant(\"S\", 0.1);   // spatial competition distance\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestNeighbors(individual, 1);\n\t\n\tfor (i in seqLen(rpois(1, 0.1)))\n\t{\n\t\tif (mate.size())\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\telse\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\n\t\t// set offspring position\n\t\tpos = individual.spatialPosition + rnorm(2, 0, 0.02);\n\t\toffspring.setSpatialPosition(p1.pointPeriodic(pos));\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1);\n\t\n\t// random initial positions\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1));\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tcompetition = (competition + 1) / (PI * S^2);\n\tinds.fitnessScaling = K / competition;\n}\nlate()\n{\n\t// move around a bit\n\tfor (ind in p1.individuals)\n\t{\n\t\tnewPos = ind.spatialPosition + runif(2, -0.01, 0.01);\n\t\tind.setSpatialPosition(p1.pointPeriodic(newPos));\n\t}\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.16 - A spatial model with carrying-capacity density.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, selfing, spatial competition, spatial mate choice\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tdefineConstant(\"K\", 300);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.1);   // SIGMA_S, the spatial interaction width\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestNeighbors(individual, 1);\n\t\n\tfor (i in seqLen(rpois(1, 0.1)))\n\t{\n\t\tif (mate.size())\n\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\telse\n\t\t\toffspring = subpop.addSelfed(individual);\n\t\t\n\t\t// set offspring position\n\t\tdo pos = individual.spatialPosition + rnorm(2, 0, 0.02);\n\t\twhile (!p1.pointInBounds(pos));\n\t\toffspring.setSpatialPosition(pos);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1);\n\t\n\t// random initial positions\n\tp1.individuals.setSpatialPosition(p1.pointUniform(1));\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.localPopulationDensity(inds);\n\tinds.fitnessScaling = K / competition;\n}\nlate()\n{\n\t// move around a bit\n\tfor (ind in p1.individuals)\n\t{\n\t\tdo newPos = ind.spatialPosition + runif(2, -0.01, 0.01);\n\t\twhile (!p1.pointInBounds(newPos));\n\t\tind.setSpatialPosition(newPos);\n\t}\n}\n10000 late() {\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.17 - A spatial epidemiological S-I-R model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, periodic boundaries, spatial competition, spatial mate choice, disease, epidemiology, SIR, S-I-R, infection, epidemic, pandemic\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\t\n\tdefineConstant(\"K\", 10000);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.01);    // SIGMA_S, the competition width\n\t\n\tdefineConstant(\"HEALTH_S\", 0);   // susceptible\n\tdefineConstant(\"HEALTH_I\", 1);   // infectious\n\tdefineConstant(\"HEALTH_R\", 2);   // recovered\n\t\n\tdefineConstant(\"FERTILITY\", 0.05);\n\tdefineConstant(\"INFECTIVITY\", 4);\n\tdefineConstant(\"RATE_DEATH\", 0.3);\n\tdefineConstant(\"RATE_CLEAR\", 0.05);\n\tdefineConstant(\"MAX_AGE\", 100.0);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.convertToSubstitution = T;\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.05);\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction() {\n\tlitterSize = rpois(1, FERTILITY);\n\t\n\tif (litterSize)\n\t{\n\t\tmate = i2.nearestNeighbors(individual, 1);\n\t\t\n\t\tif (mate.size())\n\t\t\tfor (i in seqLen(litterSize))\n\t\t\t{\n\t\t\t\toffspring = subpop.addCrossed(individual, mate);\n\t\t\t\t\n\t\t\t\t// set offspring position and state\n\t\t\t\tpos = individual.spatialPosition + rnorm(2, 0, 0.005);\n\t\t\t\toffspring.setSpatialPosition(p1.pointPeriodic(pos));\n\t\t\t\toffspring.tag = HEALTH_S;\n\t\t\t}\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n\tp1.individuals.tag = HEALTH_S;\n}\n100 early() {\n\t// seed the infection in a susceptible individual\n\ttarget = p1.sampleIndividuals(1, tag=HEALTH_S);\n\ttarget.tag = HEALTH_I;\n}\nearly() {\n\ti1.evaluate(p1);\n\t\n\t// spatial competition provides density-dependent selection\n\tinds = p1.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tcompetition = (competition + 1) / (2 * PI * S^2);\n\tinds.fitnessScaling = K / competition;\n\t\n\t// age-based mortality; at age 100 mortality is 100%\n\tage_mortality = sqrt((MAX_AGE - inds.age) / MAX_AGE);\n\tinds.fitnessScaling = inds.fitnessScaling * age_mortality;\n\t\n\t// SIR model\n\tinfected = inds[inds.tag == HEALTH_I];\n\t\n\tfor (ind in infected)\n\t{\n\t\t// make contact with random neighbors each cycle\n\t\tcontacts = i1.drawByStrength(ind, rpois(1, INFECTIVITY));\n\t\t\n\t\tfor (contact in contacts)\n\t\t{\n\t\t\t// if the contact is susceptible, they might get infected\n\t\t\tif (contact.tag == HEALTH_S)\n\t\t\t{\n\t\t\t\tstrength = i1.strength(ind, contact);\n\t\t\t\t\n\t\t\t\tif (runif(1) < strength)\n\t\t\t\t\tcontact.tag = HEALTH_I;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// die with some probability each cycle\n\t\tif (runif(1) < RATE_DEATH)\n\t\t\tind.fitnessScaling = 0.0;\n\t\t\n\t\t// recover with some probability each cycle\n\t\tif (runif(1) < RATE_CLEAR)\n\t\t\tind.tag = HEALTH_R;\n\t}\n}\nlate()\n{\n\tinds = p1.individuals;\n\t\n\t// move around a bit\n\tfor (ind in inds)\n\t{\n\t\tnewPos = ind.spatialPosition + runif(2, -0.005, 0.005);\n\t\tind.setSpatialPosition(p1.pointPeriodic(newPos));\n\t}\n\t\n\t// color according to health status; S=green, I=red, R=blue\n\tinds_tags = inds.tag;\n\tinds[inds_tags == HEALTH_S].color = \"green\";\n\tinds[inds_tags == HEALTH_I].color = \"red\";\n\tinds[inds_tags == HEALTH_R].color = \"blue\";\n}\n1:1000 late() {\n\ttags = p1.individuals.tag;\n\t\n\tcat(sum(tags == HEALTH_S) + \", \" + sum(tags == HEALTH_I) + \", \" +\n\t\tsum(tags == HEALTH_R) + \", \");\n\t\n\tif ((sum(tags == HEALTH_I) == 0) & (sim.cycle >= 100)) {\n\t\tcatn(\"\\nLOST in cycle \" + sim.cycle);\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.18 - A sexual, age-structured spatial model.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, continuous space, continuous spatial landscape, selfing, spatial competition, spatial mate choice\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeSex();\n\tdefineConstant(\"K\", 300);   // carrying-capacity density\n\tdefineConstant(\"S\", 0.1);   // SIGMA_S, the spatial interaction width\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=S * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, S);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n\ti2.setConstraints(\"receiver\", sex=\"F\", minAge=2, maxAge=4);\n\ti2.setConstraints(\"exerter\", sex=\"M\", minAge=2);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(K));\n}\n2: first() {\n\t// look for mates\n\ti2.evaluate(p1);\n}\nreproduction(NULL, \"F\") {\n\t// choose our nearest neighbor as a mate, within the max distance\n\tmate = i2.nearestInteractingNeighbors(individual, 1);\n\t\n\tif (mate.size() > 0)\n\t\tsubpop.addCrossed(individual, mate, count=rpois(1, 1.5));\n}\nearly() {\n\t// first, conduct age-related mortality with killIndividuals()\n\tinds = p1.individuals;\n\tages = inds.age;\n\t\n\tinds4 = inds[ages == 4];\n\tinds5 = inds[ages == 5];\n\tinds6 = inds[ages >= 6];\n\tdeath4 = (runif(inds4.size()) < 0.10);\n\tdeath5 = (runif(inds5.size()) < 0.30);\n\tsim.killIndividuals(c(inds4[death4], inds5[death5], inds6));\n\t\n\t// disperse prior to density-dependence\n\tp1.deviatePositions(NULL, \"reprising\", INF, \"n\", 0.02);\n\t\n\t// spatial competition provides density-dependent selection\n\ti1.evaluate(p1);\n\tinds = p1.individuals;\n\tcompetition = i1.localPopulationDensity(inds);\n\tinds.fitnessScaling = K / competition;\n}\n10000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.19 - Modeling indirect competition mediated by resource availability.txt",
    "content": "// Keywords: resources, foraging, spatial competition, home range, multispecies\n\nspecies all initialize()\n{\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\t// Foraging interaction.\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=1.5);\n\t\n\t// Reproduction interaction.\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=3,\n\t\tsexSegregation=\"FM\");\n}\nspecies resourceNode initialize()\n{\n\tinitializeSpecies(avatar=\"🪣\", color=\"cornflowerblue\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\nspecies forager initialize()\n{\n\tinitializeSpecies(avatar=\"🤤\", color=\"red\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeSex();\n}\n\nticks all 1 early()\n{\n\t// Coordinates for the resource nodes.\n\txs = rep(seq(0.5, 100), 100);\n\tys = repEach(seq(0.5, 100), 100);\n\t\n\t// Add the resource nodes.\n\tresourceNode.addSubpop(\"p1\", 10000);\n\tp1.setSpatialBounds(c(0, 0, 100, 100));\n\tp1.individuals.x = xs;\n\tp1.individuals.y = ys;\n\tp1.individuals.tagF = 10.0;\n\t\n\t// Initialize the population of foragers.\n\tforager.addSubpop(\"p2\", 100000);\n\tp2.setSpatialBounds(p1.spatialBounds);\n\tp2.individuals.setSpatialPosition(p2.pointUniform(p2.individualCount));\n}\n\nticks all 2: first()\n{\n\t// Evaluate the spatial interaction for reproduction.\n\ti2.evaluate(p2);\n}\nspecies forager reproduction(NULL, \"F\")\n{\n\t// Draw the litter size first, and return if it's zero.\n\tlitterSize = rpois(1, 8);\n\tif (litterSize == 0)\n\t\treturn;\n\t\n\t// Draw a random mate from among males in range.\n\tmate = i2.drawByStrength(individual, 1, p2);\n\tif (size(mate) == 0)\n\t\treturn;\n\t\n\t// Produce the offspring.\n\tsubpop.addCrossed(individual, mate, count=litterSize);\n}\n\nticks all 2:100 early()\n{\n\t// Dispersal of new offspring.\n\toffspring = p2.subsetIndividuals(maxAge=0);\n\tp2.deviatePositions(offspring, \"reprising\", INF, \"n\", 1.5);\n\t\n\t// Evaluate the spatial interaction between resource nodes and foragers.\n\ti1.evaluate(c(p2, p1));\n\t\n\t// Survival in this model is based entirely on resource availability.\n\tp2.individuals.fitnessScaling = 0.0;\n\t\n\tfor (node in p1.individuals)\n\t{\n\t\t// Find all foragers within range of the resource node.\n\t\tf = i1.nearestNeighbors(node, p2.individualCount, p2);\n\t\t\n\t\t// Evenly divide resources to all foragers within range.\n\t\tf.fitnessScaling = f.fitnessScaling + node.tagF / size(f);\n\t}\n\t\n\t// In some cases, if the landscape is at very low density, some individuals\n\t// might have a fitnessScaling value > 1.0. This value must be capped.\n\tp2.individuals.fitnessScaling = pmin(p2.individuals.fitnessScaling, 1.0);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.2 - Spatial competition.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries, spatial competition\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// Set up an interaction for spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\n1: late() {\n\t// evaluate interactions before fitness calculations\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\t// spatial competition\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.3 - Boundaries and boundary conditions I (stopping boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, stopping boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Stopping boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointStopped(pos));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.3 - Boundaries and boundary conditions II (reflecting boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reflecting boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Reflecting boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tchild.setSpatialPosition(p1.pointReflected(pos));\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.3 - Boundaries and boundary conditions III (absorbing boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, absorbing boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Absorbing boundary conditions\n\tpos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\tif (!p1.pointInBounds(pos))\n\t\treturn F;\n\t\n\tchild.setSpatialPosition(pos);\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.3 - Boundaries and boundary conditions IV (reprising boundaries).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\nmodifyChild() {\n\t// Reprising boundary conditions\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.3 - Boundaries and boundary conditions V (dispersal kernels).txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, boundaries, boundary conditions, dispersal kernel\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);  // competition\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// Initial positions are random within spatialBounds\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\t// Dispersal and boundary enforcement\n\tp1.deviatePositions(NULL, \"reprising\", INF, \"n\", 0.02);\n\t\n\t// Evaluate for competition\n\ti1.evaluate(p1);\n}\nfitnessEffect() {\n\ttotalStrength = i1.totalOfNeighborStrengths(individual);\n\treturn 1.1 - totalStrength / p1.individualCount;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.4 - Mate choice with a spatial kernel.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n\t\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n\ti2.setInteractionFunction(\"n\", 1.0, 0.02);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tinds.fitnessScaling = 1.1 - competition / size(inds);\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.5 - Mate choice with a nearest-neighbor search.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// spatial competition\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.3);\n\ti1.setInteractionFunction(\"n\", 3.0, 0.1);\n\n\t// spatial mate choice\n\tinitializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=0.1);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.individuals.setSpatialPosition(p1.pointUniform(500));\n}\n1: late() {\n\ti1.evaluate(p1);\n\tinds = sim.subpopulations.individuals;\n\tcompetition = i1.totalOfNeighborStrengths(inds);\n\tinds.fitnessScaling = 1.1 - competition / size(inds);\n}\n2: first() {\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// nearest-neighbor spatial mate choice\n\tneighbors = i2.nearestNeighbors(individual, 3);\n\treturn (size(neighbors) ? sample(neighbors, 1) else float(0));\n}\nmodifyChild() {\n\tdo pos = parent1.spatialPosition + rnorm(2, 0, 0.02);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.6 - Divergence due to phenotypic competition with an interaction() callback.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition, interaction()\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"\", reciprocal=T);     // competition\n\ti1.setInteractionFunction(\"f\", 1.0);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.tagF = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\ninteraction(i1) {\n\treturn dnorm(exerter.tagF, receiver.tagF, SIGMA_C) / NORM;\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.tagF;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.7 - Modeling phenotype as a spatial dimension.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeSLiMOptions(dimensionality=\"x\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeInteractionType(1, \"x\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSpatialBounds(c(0.0, 10.0));\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.x = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.x;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.8 - Sympatric speciation facilitated by assortative mating.txt",
    "content": "// Keywords: QTL, quantitative trait loci, phenotypic competition\n\ninitialize() {\n\tdefineConstant(\"OPTIMUM\", 5.0);\n\tdefineConstant(\"SIGMA_K\", 1.0);\n\tdefineConstant(\"SIGMA_C\", 0.4);\n\tdefineConstant(\"SIGMA_M\", 0.5);\n\tdefineConstant(\"NORM\", dnorm(0.0, mean=0, sd=SIGMA_C));\n\t\n\tinitializeSLiMOptions(dimensionality=\"x\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.01));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"x\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"x\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSpatialBounds(c(0.0, 10.0));\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, OPTIMUM, SIGMA_K);\n\tinds.x = phenotypes;\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n1:2001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.x;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 17.9 - Speciation due to spatial variation in selection.txt",
    "content": "// Keywords: continuous space, continuous spatial landscape, reprising boundaries, QTL, quantitative trait loci, spatial competition, phenotypic competition, spatial mate choice\n\ninitialize() {\n\tdefineConstant(\"SIGMA_C\", 0.1);\n\tdefineConstant(\"SIGMA_K\", 0.5);\n\tdefineConstant(\"SIGMA_M\", 0.1);\n\tdefineConstant(\"SLOPE\", 1.0);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);        // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 1.0);   // QTL\n\tm2.convertToSubstitution = F;\n\t\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1, 0.1));\n\tinitializeGenomicElement(g1, 0, 1e5 - 1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\t// competition\n\tinitializeInteractionType(1, \"xyz\", reciprocal=T, maxDistance=SIGMA_C * 3);\n\ti1.setInteractionFunction(\"n\", 1.0, SIGMA_C);\n\t\n\t// mate choice\n\tinitializeInteractionType(2, \"xyz\", reciprocal=T, maxDistance=SIGMA_M * 3);\n\ti2.setInteractionFunction(\"n\", 1.0, SIGMA_M);\n}\nmutationEffect(m2) { return 1.0; }\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setSpatialBounds(c(0.0, 0.0, -SLOPE, 1.0, 1.0, SLOPE));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N));\n\tp1.individuals.z = 0.0;\n}\nmodifyChild() {\n\t// set offspring position based on parental position\n\tdo pos = c(parent1.spatialPosition[0:1] + rnorm(2, 0, 0.005), 0.0);\n\twhile (!p1.pointInBounds(pos));\n\tchild.setSpatialPosition(pos);\n\t\n\treturn T;\n}\n1: late() {\n\tinds = sim.subpopulations.individuals;\n\t\n\t// construct phenotypes and fitness effects from QTLs\n\tphenotypes = inds.sumOfMutationsOfType(m2);\n\toptima = (inds.x - 0.5) * SLOPE;\n\tinds.fitnessScaling = 1.0 + dnorm(phenotypes, optima, SIGMA_K);\n\tinds.z = phenotypes;\n\t\n\t// color individuals according to phenotype\n\tfor (ind in inds)\n\t{\n\t\thue = ((ind.z + SLOPE) / (SLOPE * 2)) * 0.66;\n\t\tind.color = rgb2color(hsv2rgb(c(hue, 1.0, 1.0)));\n\t}\n\t\n\t// evaluate phenotypic competition\n\ti1.evaluate(p1);\n\tcompetition = sapply(inds, \"sum(i1.strength(applyValue));\");\n\teffects = 1.0 - competition / size(inds);\n\tinds.fitnessScaling = inds.fitnessScaling * effects;\n}\n2: first() {\n\t// evaluate mate choice in preparation for reproduction\n\ti2.evaluate(p1);\n}\nmateChoice() {\n\t// spatial mate choice\n\treturn i2.strength(individual);\n}\n1:5001 late() {\n\tif (sim.cycle == 1)\n\t\tcat(\"  cyc    mean      sd\\n\");\n\t\n\tif (sim.cycle % 100 == 1)\n\t{\n\t\tphenotypes = p1.individuals.z;\n\t\tcat(format(\"%5d  \", sim.cycle));\n\t\tcat(format(\"%6.2f  \", mean(phenotypes)));\n\t\tcat(format(\"%6.2f\\n\", sd(phenotypes)));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.1 - A minimal tree-seq model.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tsim.treeSeqOutput(\"./overlay.trees\");\n}\n\n// Section 17.2's recipe, which is a Python script that overlays\n// neutral mutations onto the .trees file saved here, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq(simplificationRatio=INF, timeUnit=\"generations\");\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 1.0);\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m2, 1);\n\tinitializeGenomicElement(g1, 0, 1e6 - 1);\n\tinitializeRecombinationRate(3e-10);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1e5);\n}\n100 late() {\n\tsample(p1.haplosomes, 1).addNewDrawnMutation(m2, 5e5);\n}\n100:10000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size() != 1)\n\t\tstop(sim.cycle + \": LOST\");\n\telse if (sum(sim.mutationFrequencies(NULL, mut)) == 1.0)\n\t{\n\t\tsim.treeSeqOutput(\"decap.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.10 - Adding a neutral burn-in after simulation with recapitation II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit, pyslim\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Load the .trees file\nts = tskit.load(\"decap.trees\")    # no simplify!\n\n# Calculate tree heights, giving uncoalesced sites the maximum time\ndef tree_heights(ts):\n    heights = np.zeros(ts.num_trees + 1)\n    for tree in ts.trees():\n        if tree.num_roots > 1:  # not fully coalesced\n            heights[tree.index] = ts.metadata['SLiM']['tick']\n        else:\n            children = tree.children(tree.root)\n            real_root = tree.root if len(children) > 1 else children[0]\n            heights[tree.index] = tree.time(real_root)\n    heights[-1] = heights[-2]  # repeat the last entry for plotting with step\n    return heights\n\n# Plot tree heights before recapitation\nbreakpoints = list(ts.breakpoints())\nheights = tree_heights(ts)\nplt.step(breakpoints, heights, where='post')\nplt.show()\n\n# Recapitate!\nrecap = pyslim.recapitate(ts, ancestral_Ne=1e5, recombination_rate=3e-10, random_seed=1)\nrecap.dump(\"recap.trees\")\n\n# Plot the tree heights after recapitation\nbreakpoints = list(recap.breakpoints())\nheights = tree_heights(recap)\nplt.step(breakpoints, heights, where='post')\nplt.show()\n\n\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.11 - Optimizing tree-sequence simplification.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, simplification\n\ninitialize() {\n\tsetSeed(0);\n\tinitializeTreeSeq(simplificationInterval=1000);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 10000); }\n50001 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.2 - Overlaying neutral mutations.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe, to be run after the section 17.1 recipe\n\nimport msprime, tskit\n\nts = tskit.load(\"./overlay.trees\")\nts = ts.simplify()\n\nfor t in ts.trees():\n    assert t.num_roots == 1, (\"not coalesced! on segment {} to {}\".format(t.interval[0], t.interval[1]))\n\nmutated = msprime.sim_mutations(ts, rate=1e-7, random_seed=1, keep=True)\nmutated.dump(\"./overlay_II.trees\")\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.01, 1.0);  // deleterious\n\tinitializeMutationType(\"m3\", 1.0, \"f\", 0.05);        // introduced\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(0.9, 0.1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tdefineConstant(\"simID\", getSeed());\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m3, 10000);\n\tdefineConstant(\"PATH\", tempdir() + \"slim_\" + simID + \".trees\");\n\tsim.outputFull(PATH);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m3) == 0) {\n\t\tif (sum(sim.substitutions.mutationType == m3) == 1) {\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\tsim.readFromPopulationFile(PATH);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.3 - Simulation conditional upon fixation of a sweep, preserving ancestry II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, conditional sweep\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.01, 1.0);  // deleterious\n\tinitializeMutationType(\"m3\", 1.0, \"f\", 0.05);        // introduced\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tdefineConstant(\"simID\", getSeed());\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// assign tag values to be preserved\n\tinds = sortBy(sim.subpopulations.individuals, \"pedigreeID\");\n\ttags = rdunif(size(inds), 0, 100000);\n\tinds.tag = tags;\n\t\n\t// record tag values and pedigree IDs in metadata\n\tmetadataDict = Dictionary(\"tags\", tags, \"ids\", inds.pedigreeID);\n\t\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m3, 10000);\n\tdefineConstant(\"PATH\", tempdir() + \"slim_\" + simID + \".trees\");\n\tsim.treeSeqOutput(PATH, metadata=metadataDict);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m3) == 0) {\n\t\tif (sum(sim.substitutions.mutationType == m3) == 1) {\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.treeSeqOutput(\"slim_\" + simID + \"_FIXED.trees\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\tsim.readFromPopulationFile(PATH);\n\t\t\tmetadataDict = treeSeqMetadata(PATH);\n\t\t\ttags = metadataDict.getValue(\"tags\");\n\t\t\tinds = sortBy(sim.subpopulations.individuals, \"pedigreeID\");\n\t\t\tinds.tag = tags;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tdefineConstant(\"N\", 10000);  // pop size\n\tdefineConstant(\"L\", 1e8);    // total chromosome length\n\tdefineConstant(\"L0\", 200e3); // between genes\n\tdefineConstant(\"L1\", 1e3);   // gene length\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8, L-1);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -(5/N), 1.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\t\n\tfor (start in seq(from=L0, to=L-(L0+L1), by=(L0+L1)))\n\t\tinitializeGenomicElement(g2, start, (start+L1)-1);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", N);\n}\n10*N late() {\n\tsim.treeSeqOutput(\"./diversity.trees\");\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.4 - Detecting the dip in diversity (analyzing tree heights in Python) II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe; note that it runs the SLiM model internally, below\n\nimport subprocess, tskit\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Run the SLiM model and load the resulting .trees\nsubprocess.check_output([\"slim\", \"-m\", \"-s\", \"0\", \"./diversity.slim\"])\nts = tskit.load(\"./diversity.trees\")\nts = ts.simplify()\n\n# Measure the tree height at each base position\nheight_for_pos = np.zeros(int(ts.sequence_length))\nfor tree in ts.trees():\n    mean_height = np.mean([tree.time(root) for root in tree.roots])\n    left, right = map(int, tree.interval)\n    height_for_pos[left: right] = mean_height\n\n# Convert heights along chromosome into heights at distances from gene\nheight_for_pos = height_for_pos - np.min(height_for_pos)\nL, L0, L1 = int(1e8), int(200e3), int(1e3)   # total length, length between genes, gene length\ngene_starts = np.arange(L0, L - (L0 + L1) + 1, L0 + L1)\ngene_ends = gene_starts + L1 - 1\nmax_d = L0 // 4\nheight_for_left_dist = np.zeros(max_d)\nheight_for_right_dist = np.zeros(max_d)\nfor d in range(max_d):\n    height_for_left_dist[d] = np.mean(height_for_pos[gene_starts - d - 1])\n    height_for_right_dist[d] = np.mean(height_for_pos[gene_ends + d + 1])\nheight_for_distance = np.hstack([height_for_left_dist[::-1], height_for_right_dist])\ndistances = np.hstack([np.arange(-max_d, 0), np.arange(1, max_d + 1)])\n\n# Make a simple plot\nplt.plot(distances, height_for_distance)\nplt.show()\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, migration, dispersal\n\ninitialize() {\n\tdefineConstant(\"L\", 1e8);\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.1);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tsim.treeSeqRememberIndividuals(sim.subpopulations.individuals);\n\t\n\tp1.haplosomes.addNewDrawnMutation(m1, asInteger(L * 0.2));\n\tp2.haplosomes.addNewDrawnMutation(m1, asInteger(L * 0.8));\n\t\n\tsim.addSubpop(\"p3\", 1000);\n\tp3.setMigrationRates(c(p1, p2), c(0.5, 0.5));\n}\n2 late() {\n\tp3.setMigrationRates(c(p1, p2), c(0.0, 0.0));\n\tp1.setSubpopulationSize(0);\n\tp2.setSubpopulationSize(0);\n}\n2: late() {\n\tif (sim.mutationsOfType(m1).size() == 0)\n\t{\n\t\tsim.treeSeqOutput(\"./admix.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n10000 late() {\n\tstop(\"Did not reach fixation of beneficial alleles.\");\n}\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.5 - Mapping admixture (analyzing ancestry in Python) II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\n# This is a Python recipe; note that it runs the SLiM model internally, below\n\nimport subprocess, tskit\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n# Run the SLiM model and load the resulting .trees file\nsubprocess.check_output([\"slim\", \"-m\", \"-s\", \"0\", \"./admix.slim\"])\nts = tskit.load(\"./admix.trees\")\n\n# Load the .trees file and assess true local ancestry\nbreaks = np.zeros(ts.num_trees + 1)\nancestry = np.zeros(ts.num_trees + 1)\nfor tree in ts.trees():\n    subpop_sum, subpop_weights = 0, 0\n    for root in tree.roots:\n        leaves_count = tree.num_samples(root) - 1  # subtract one for the root, which is a sample\n        subpop_sum += tree.population(root) * leaves_count\n        subpop_weights += leaves_count\n    breaks[tree.index] = tree.interval[0]\n    ancestry[tree.index] = subpop_sum / subpop_weights\nbreaks[-1] = ts.sequence_length\nancestry[-1] = ancestry[-2]\n\n# Make a simple plot\nplt.plot(breaks, ancestry)\nplt.show()\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.6 - Measuring the coalescence time of a model I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq(checkCoalescence=T);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tif (sim.treeSeqCoalesced())\n\t{\n\t\tcatn(sim.cycle + \": COALESCED\");\n\t\tsim.simulationFinished();\n\t}\n}\n100000 late() {\n\tcatn(\"NO COALESCENCE BY CYCLE 100000\");\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.6 - Measuring the coalescence time of a model II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording, deferred scheduling, variable-length burn-in\n\ninitialize() {\n\tinitializeTreeSeq(checkCoalescence=T);\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1: late() {\n\tif (sim.treeSeqCoalesced())\n\t{\n\t\tcatn(community.tick + \": COALESCED\");\n\t\tdefineConstant(\"COALESCE\", community.tick);\n\t\tcommunity.deregisterScriptBlock(self);\n\t}\n}\nCOALESCE+100 late() {\n\tcatn(community.tick + \": FINISHED\");\n\tsim.simulationFinished();\n}\n100000 late() {\n\tcatn(\"NO COALESCENCE BY CYCLE 100000\");\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit I.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(1e-10);\n\tinitializeMutationType(\"m1\", 0.5, \"g\", 0.1, 0.1);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.1, 0.1);\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1.0, 1.0));\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n20000 late() { sim.treeSeqOutput(\"./selcoeff.trees\"); }\n\n// Part II of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.7 - Analyzing selection coefficients in Python with tskit II.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit\n\nts = tskit.load(\"selcoeff.trees\")\n\n# selection coefficients of all selected mutations\ncoeffs = []\nfor mut in ts.mutations():\n    md = mut.metadata\n    sel = [x[\"selection_coeff\"] for x in md[\"mutation_list\"]]\n    if any([s != 0 for s in sel]):\n        coeffs += sel\n\nb = [x for x in coeffs if x > 0]\nd = [x for x in coeffs if x < 0]\n\nprint(\"Beneficial: \" + str(len(b)) + \", mean \" + str(sum(b) / len(b)))\nprint(\"Deleterious: \" + str(len(d)) + \", mean \" + str(sum(d) / len(d)))\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history I.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport msprime, pyslim\n\nts = msprime.sim_ancestry(samples=5000, population_size=5000, sequence_length=1e8,\n    recombination_rate=1e-8)\nslim_ts = pyslim.annotate(ts, model_type=\"WF\", tick=1)\nslim_ts.dump(\"coalasex.trees\")\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history II.txt",
    "content": "// Keywords: tree-sequence recording, tree sequence recording\n\n// Part I of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n\ninitialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.readFromPopulationFile(\"coalasex.trees\");\n\ttarget = sample(sim.subpopulations.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1: late() {\n\tif (sim.mutationsOfType(m2).size() == 0) {\n\t\tprint(sim.substitutions.size() ? \"FIXED\" else \"LOST\");\n\t\tsim.treeSeqOutput(\"coalasex_II.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n2000 early() { sim.simulationFinished(); }\n\n// Part III of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.8 - Starting a hermaphroditic WF model with a coalescent history III.py",
    "content": "# Keywords: Python, tree-sequence recording, tree sequence recording\n\nimport tskit\n\nts = tskit.load(\"coalasex_II.trees\").simplify()\n\nfor tree in ts.trees():\n    for root in tree.roots:\n        print(tree.time(root))\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history I.py",
    "content": "# Keywords: Python, nonWF, non-Wright-Fisher, tree-sequence recording, tree sequence recording\n\nimport msprime, pyslim, random\nimport numpy as np\n\nts = msprime.sim_ancestry(samples=5000, population_size=5000,\n    sequence_length=1e8, recombination_rate=1e-8)\n\ntables = ts.dump_tables()\npyslim.annotate_tables(tables, model_type=\"nonWF\", tick=1)\n\n# add sexes and ages\nindividual_metadata = [ind.metadata for ind in tables.individuals]\nfor md in individual_metadata:\n    md[\"sex\"] = random.choice([pyslim.INDIVIDUAL_TYPE_FEMALE, pyslim.INDIVIDUAL_TYPE_MALE])\n    md[\"age\"] = random.choice([0, 1, 2, 3, 4])\n\nims = tables.individuals.metadata_schema\ntables.individuals.packset_metadata(\n        [ims.validate_and_encode_row(md) for md in individual_metadata])\n\n# add selected mutation\nmut_ind_id = random.choice(range(tables.individuals.num_rows))\nmut_node_id = random.choice(np.where(tables.nodes.individual == mut_ind_id)[0])\nmut_node = tables.nodes[mut_node_id]\nmut_metadata = {\n        \"mutation_list\": [\n            {\n              \"mutation_type\": 2,\n              \"selection_coeff\": 0.1,\n              \"subpopulation\": mut_node.population,\n              \"slim_time\": int(tables.metadata['SLiM']['tick'] - mut_node.time),\n              \"nucleotide\": -1\n            }\n        ]\n    }\nsite_num = tables.sites.add_row(position=5000, ancestral_state='')\ntables.mutations.add_row(\n        node=mut_node_id,\n        site=site_num,\n        derived_state='1',\n        time=mut_node.time,\n        metadata=mut_metadata)\n\nslim_ts = tables.tree_sequence()\nslim_ts.dump(\"coalsex.trees\")\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 18.9 - Starting a sexual nonWF model with a coalescent history II.txt",
    "content": "// Keywords: nonWF, non-Wright-Fisher, sexual, tree-sequence recording, tree sequence recording, reproduction()\n\n// Part I of this recipe, which is a Python script, may be found in\n// the Recipes archive downloadable at https://messerlab.org/slim/\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeTreeSeq();\n\tinitializeSex();\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.convertToSubstitution=T;\n\tinitializeGenomicElementType(\"g1\", m2, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e8-1);\n\tinitializeRecombinationRate(1e-8);\n}\nreproduction(NULL, \"F\") {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.readFromPopulationFile(\"coalsex.trees\");\n}\nearly() {\n\tp0.fitnessScaling = 5000 / p0.individualCount;\n}\n1: late() {\n\tif (sim.mutationsOfType(m2).size() == 0) {\n\t\tprint(sim.substitutions.size() ? \"FIXED\" else \"LOST\");\n\t\tsim.treeSeqOutput(\"coalsex_II.trees\");\n\t\tsim.simulationFinished();\n\t}\n}\n2000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.1 - A simple neutral nucleotide-based model.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e6);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.10 - Varying the mutation rate along the chromosome in a nucleotide-based model.txt",
    "content": "// Keywords: nucleotide-based, hot spot, cold spot, variable mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tm1.color = \"black\";\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmKimura(1.8e-07, 6e-08));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tends = c(sort(sample(0:(L-2), 99)), L-1);\n\tmultipliers = rlnorm(100, 0.0, 0.75);\n\tinitializeHotspotMap(multipliers, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.11 - Modeling GC-biased gene conversion (gBGC).txt",
    "content": "// Keywords: nucleotide-based, gene conversion, GC-bias, GC biased gene conversion, GC content\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"alpha\", 2.5e-6);\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(alpha));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-5);\n\tinitializeGeneConversion(0.7, 1500, 0.80, 0.10);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1:500001 early() {\n\tif (sim.cycle % 1000 == 1) {\n\t\tcat(sim.cycle + \": \");\n\t\tprint(nucleotideFrequencies(sim.chromosomes.ancestralNucleotides()));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.12 - Reading VCF files to create nucleotide-based SNPs.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence, VCF file reading, empirical population, SNPs, 1000 Genomes Project\n\n// The input files used here can be downloaded from http://benhaller.com/slim/recipe_19_12_files.zip\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tlength = initializeAncestralNucleotides(\"hs37d5_chr22_patched.fa\");\n\tdefineConstant(\"L\", length);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationTypeNuc(\"m2\", 0.5, \"f\", 0.0);\n\tm2.color = \"red\";\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(0.0));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 99);\n\tp1.haplosomes.readHaplosomesFromVCF(\"chr22_filtered.recode.vcf\", m1);\n\tp1.setSubpopulationSize(1000);\n}\n5 late() {\n\tmut = sample(sim.mutations, 1);\n\tmut.setMutationType(m2);\n\tmut.setSelectionCoeff(0.5);\n}\n1:2000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size()) {\n\t\tf = sim.mutationFrequencies(p1, mut);\n\t\tcatn(sim.cycle + \": \" + sim.mutations.size() + \", f = \" + f);\n\t\t\n\t\tif (f == 1.0) {\n\t\t\tcatn(\"\\nFIXED in cycle \" + sim.cycle);\n\t\t\tcatn(sim.substitutions.size() + \" substitutions.\");\n\t\t\tcatn(paste(sim.substitutions.nucleotide));\n\t\t\tsim.simulationFinished();\n\t\t}\n\t} else {\n\t\tcatn(sim.cycle + \": \" + sim.mutations.size());\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models I.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeTreeSeq();\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-6));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-6);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n1000 late() { sim.treeSeqOutput(\"recipe_nucleotides.trees\"); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models II.py",
    "content": "# Keywords: Python, nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\nimport tskit, pyslim\nimport numpy as np\n\nts = tskit.load(\"recipe_nucleotides.trees\")\n\nM = [[0 for _ in pyslim.NUCLEOTIDES] for _ in pyslim.NUCLEOTIDES]\nfor mut in ts.mutations():\n    mut_list = mut.metadata[\"mutation_list\"]\n    k = np.argmax([u[\"slim_time\"] for u in mut_list])\n    derived_nuc = mut_list[k][\"nucleotide\"]\n    if mut.parent == -1:\n        acgt = ts.reference_sequence.data[int(ts.site(mut.site).position)]\n        parent_nuc = pyslim.NUCLEOTIDES.index(acgt)\n    else:\n        parent_mut = ts.mutation(mut.parent)\n        assert(parent_mut.site == mut.site)\n        parent_nuc = parent_mut.metadata[\"mutation_list\"][0][\"nucleotide\"]\n    M[parent_nuc][derived_nuc] += 1\n\nprint(\"{}\\t{}\\t{}\".format('ancestral', 'derived', 'count'))\nfor j, a in enumerate(pyslim.NUCLEOTIDES):\n    for k, b in enumerate(pyslim.NUCLEOTIDES):\n        print(\"{}\\t{}\\t{}\".format(a, b, M[j][k]))\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.13 - Tree-sequence recording and nucleotide-based models III.py",
    "content": "# Keywords: Python, nucleotide-based, nucleotide sequence, sequence-based mutation rate\n\nimport tskit, pyslim\nimport numpy as np\n\nts = tskit.load(\"recipe_nucleotides.trees\")\nslim_gen = ts.metadata[\"SLiM\"][\"tick\"]\n\nM = np.zeros((4,4,4,4), dtype='int')\nfor mut in ts.mutations():\n    pos = ts.site(mut.site).position \n    # skip mutations at the end of the sequence\n    if pos > 0 and pos < ts.sequence_length - 1:\n        mut_list = mut.metadata[\"mutation_list\"]\n        k = np.argmax([u[\"slim_time\"] for u in mut_list])\n        derived_nuc = mut_list[k][\"nucleotide\"]\n        pretime = mut.time + 1.0\n        left_nuc = pyslim.nucleotide_at(ts, mut.node, pos - 1, time = pretime)\n        right_nuc = pyslim.nucleotide_at(ts, mut.node, pos + 1, time = pretime)\n        parent_nuc = pyslim.nucleotide_at(ts, mut.node, pos, time = pretime)\n        M[left_nuc, parent_nuc, right_nuc, derived_nuc] += 1\n\nprint(\"{}\\t{}\\t{}\".format('ancestral', 'derived', 'count'))\nfor j0, a0 in enumerate(pyslim.NUCLEOTIDES):\n    for j1, a1 in enumerate(pyslim.NUCLEOTIDES):\n        for j2, a2 in enumerate(pyslim.NUCLEOTIDES):\n            for k, b in enumerate(pyslim.NUCLEOTIDES):\n                print(\"{}{}{}\\t{}{}{}\\t{}\".format(a0, a1, a2, a0, b, a2,\n                        M[j0, j1, j2, k]))\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.14 - Modeling identity by state (IBS) (uniquing mutations with a mutation() callback).txt",
    "content": "// Keywords: IBS, identity by state, IBD, identity by descent, unique down\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(100));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-4 / 3));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(1e-3);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation() {\n\tm = sim.subsetMutations(position=mut.position, nucleotide=mut.nucleotide);\n\tif (m.length())\n\t\treturn m;\n\treturn T;\n}\n1000 late() {\n\tfor (pos in 0:99)\n\t{\n\t\tmuts = sim.subsetMutations(position=pos);\n\t\tnucs = muts.nucleotide;\n\t\tcat(pos + \" : \" + paste(nucs));\n\t\tif (size(nucs) != size(unique(nucs)))\n\t\t\tcat(\"     DUPLICATES!\");\n\t\tcatn();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.15 - Modeling identity by state (IBS) (uniquing back-mutations to the ancestral state).txt",
    "content": "// Keywords: IBS, identity by state, IBD, identity by descent, unique down, back-mutation\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(100));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-4 / 3));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(1e-3);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nmutation() {\n\tm = sim.subsetMutations(position=mut.position, nucleotide=mut.nucleotide);\n\tif (m.length())\n\t\treturn m;\n\treturn T;\n}\nlate() {\n\t// unique new mutations down to the ancestral state\n\tmuts = sim.mutations;\n\tnew_muts = muts[muts.originTick == community.tick];\n\tback_muts = NULL;\n\tfor (mut in new_muts)\n\t{\n\t\tpos = mut.position;\n\t\tif (mut.nucleotide == sim.chromosomes.ancestralNucleotides(pos, pos))\n\t\t\tback_muts = c(back_muts, mut);\n\t}\n\tif (size(back_muts))\n\t\tsim.subpopulations.haplosomes.removeMutations(back_muts);\n}\n1000 late() {\n\tfor (pos in 0:99)\n\t{\n\t\tmuts = sim.subsetMutations(position=pos);\n\t\tnucs = muts.nucleotide;\n\t\tancestral = sim.chromosomes.ancestralNucleotides(pos, pos);\n\t\tcat(pos + \" : \" + paste(nucs));\n\t\tif (size(nucs) != size(unique(nucs)))\n\t\t\tcat(\"     DUPLICATES!\");\n\t\tif (any(nucs == ancestral))\n\t\t\tcat(\"     BACK-MUTATION (\" + ancestral + \")!\");\n\t\tcatn();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.2 - Reading an ancestral nucleotide sequence from a FASTA file.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tdefineConstant(\"L\", initializeAncestralNucleotides(\"FASTA.txt\"));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmKimura(1.8e-07, 6e-08));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n2000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.3 - Sequence output from nucleotide-based models.txt",
    "content": "// Keywords: nucleotide-based, nucleotide sequence\n\ninitialize() {\n\tdefineConstant(\"L\", 10);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-5));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tc = sim.chromosomes;\n\tcatn(\"Ancestral: \" + c.ancestralNucleotides());\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"char\")));\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n\tcatn();\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tcatn(\"Fixed:     \" + paste(sim.substitutions.nucleotide));\n\tcatn(\"Fixed:     \" + paste(sim.substitutions.nucleotideValue));\n\tcatn(\"positions: \" + paste(sim.substitutions.position));\n\tcatn();\n\t\n\tc = sim.chromosomes;\n\tcatn(\"Ancestral: \" + c.ancestralNucleotides());\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"char\")));\n\tcatn(\"Ancestral: \" + paste(c.ancestralNucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n\tcatn();\n\t\n\tg = p1.haplosomes[0];\n\t\n\tcatn(\"SNPs:      \" + paste(g.mutations.nucleotide));\n\tcatn(\"SNPs:      \" + paste(g.mutations.nucleotideValue));\n\tcatn(\"positions: \" + paste(g.mutations.position));\n\tcatn();\n\t\n\tcatn(\"Derived:   \" + g.nucleotides());\n\tcatn(\"Derived:   \" + paste(g.nucleotides(format=\"char\")));\n\tcatn(\"Derived:   \" + paste(g.nucleotides(format=\"integer\")));\n\tcatn(\"positions: \" + paste(0:(L-1)));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.4 - Back-mutations, independent mutational lineages, and VCF output.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 10);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-5));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n}\n5000 late() {\n\tg = p1.sampleIndividuals(5).haplosomes;\n\tg.outputHaplosomesToVCF(simplifyNucleotides=F);\n\tg.outputHaplosomesToVCF(simplifyNucleotides=T);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.5 - Modeling elevated CpG mutation rates and equilibrium nucleotide frequencies.txt",
    "content": "// Keywords: nucleotide-based, sequence-based mutation rate\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"mu\", 7.5e-6);\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\t\n\tmm = mm16To256(mmJukesCantor(mu / 3));\n\txcg = c(\"ACG\", \"CCG\", \"GCG\", \"TCG\");\n\txcg_codons = nucleotidesToCodons(paste0(xcg));\n\tmm[xcg_codons,3] = mm[xcg_codons,3] * 20;  // rates to T\n\tcgx = c(\"CGA\", \"CGC\", \"CGG\", \"CGT\");\n\tcgx_codons = nucleotidesToCodons(paste0(cgx));\n\tmm[cgx_codons,0] = mm[cgx_codons,0] * 20;  // rates to A\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mutationMatrix=mm);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 10);\n}\n1:10000000 early() {\n\tif (sim.cycle % 10000 == 1) {\n\t\tcat(sim.cycle + \": \");\n\t\tprint(nucleotideFrequencies(sim.chromosomes.ancestralNucleotides()));\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.6 - A nucleotide-based model with introduced non-nucleotide-based mutations.txt",
    "content": "// Keywords: nucleotide-based, non-nucleotide-based, mixed model\n\ninitialize() {\n\tdefineConstant(\"L\", 1e5);\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\tm2.convertToSubstitution = F;\n\tm2.color = \"red\";\n\t\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 500);\n\tsample(p1.haplosomes, 10).addNewDrawnMutation(m2, 20000);\n}\n2000 late() {\n\tprint(sim.mutationsOfType(m2));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.7 - Using standard SLiM fitness effects with nucleotides (modeling synonymous sites).txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(3e5));\n\t\n\tmm = mmJukesCantor(2.5e-8);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);         // neutral\n\tinitializeMutationTypeNuc(\"m2\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(3,3), mm);  // pos 1/2\n\tinitializeGenomicElementType(\"g2\", c(m1,m2), c(5,1), mm);  // pos 3\n\tinitializeRecombinationRate(1e-8);\n\t\n\ttypes = rep(c(g1,g2), 1e5);\n\tstarts = repEach(seqLen(1e5) * 3, 2) + rep(c(0,2), 1e5);\n\tends = starts + rep(c(1,0), 1e5);\n\tinitializeGenomicElement(types, starts, ends);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1e6 late() {\n\tsub = sim.substitutions;\n\tpos3 = (sub.position % 3 == 2);\n\tpos12 = !pos3;\n\t\n\tcatn(size(sub) + \" substitutions occurred.\");\n\tcatn(mean(sub.mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub.mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n\tcatn(size(sub[pos12]) + \" substitutions are at position 1 or 2.\");\n\tcatn(mean(sub[pos12].mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub[pos12].mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n\tcatn(size(sub[pos3]) + \" substitutions are at position 3.\");\n\tcatn(mean(sub[pos3].mutationType == m1)*100 + \"% are neutral.\");\n\tcatn(mean(sub[pos3].mutationType == m2)*100 + \"% are non-neutral.\");\n\tcatn();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.8 - Defining sequence-based fitness effects at the nucleotide level.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e4);\n\tdefineConstant(\"EFF\", c(1.0, 0.1, 1.5, 3.0));\n\tinitializeSLiMOptions(nucleotideBased=T);\n\t\n\tseq = randomNucleotides(100) + 'A' + randomNucleotides(1e4 - 101);\n\tinitializeAncestralNucleotides(seq);\n\t\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-7));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nlate() {\n\tif (sum(sim.mutations.position == 100) == 0)\n\t\ts1.active = 0;\n}\ns1 fitnessEffect() {\n\tnuc1 = individual.haploidGenome1.nucleotides(100, 100, format=\"integer\");\n\tnuc2 = individual.haploidGenome2.nucleotides(100, 100, format=\"integer\");\n\treturn EFF[nuc1] * EFF[nuc2];\n}\n10000 late() {\n\tsubs = sim.substitutions[sim.substitutions.position == 100];\n\t\n\tfor (sub in subs)\n\t\tcatn(\"Sub to \" + sub.nucleotide + \" in \"  + sub.fixationTick);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 19.9 - Defining sequence-based fitness effects at the amino acid level.txt",
    "content": "// Keywords: nucleotide-based\n\ninitialize() {\n\tdefineConstant(\"L\", 1e4);\n\tdefineConstant(\"TAA\", nucleotidesToCodons(\"TAA\"));\n\tdefineConstant(\"TAG\", nucleotidesToCodons(\"TAG\"));\n\tdefineConstant(\"TGA\", nucleotidesToCodons(\"TGA\"));\n\tdefineConstant(\"STOP\", c(TAA, TAG, TGA));\n\tdefineConstant(\"NONSTOP\", (0:63)[match(0:63, STOP) < 0]);\n\t\n\tcodons = sample(NONSTOP, 194, replace=T);\n\tseq1 = randomNucleotides(253);\n\tseq2 = paste0(codonsToNucleotides(codons, format=\"char\")[0:417]);\n\tseq3 = randomNucleotides(200);\n\tseq4 = paste0(codonsToNucleotides(codons, format=\"char\")[418:581]);\n\tseq5 = randomNucleotides(L-1035);\n\tseq = seq1 + seq2 + seq3 + seq4 + seq5;\n\tcatn(\"Initial AA sequence: \" + codonsToAminoAcids(codons));\n\t\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(seq);\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(2.5e-6));\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\nfitnessEffect() {\n\tfor (g in individual.haplosomes)\n\t{\n\t\tseq = g.nucleotides(253, 670) + g.nucleotides(871, 1034);\n\t\tcodons = nucleotidesToCodons(seq);\n\t\tif (sum(match(codons, STOP) >= 0))\n\t\t\treturn 0.0;\n\t}\n\t\n\treturn 1.0;\n}\n100000 late() {\n\tcatn(sim.substitutions.size() + \" fixed mutations.\");\n\t\n\tas1 = sim.chromosomes.ancestralNucleotides(253, 670, \"integer\");\n\tas2 = sim.chromosomes.ancestralNucleotides(871, 1034, \"integer\");\n\tas = c(as1, as2);\n\tcodons = nucleotidesToCodons(as);\n\tcatn(\"Final AA sequence: \" + codonsToAminoAcids(codons));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.1 - A simple multispecies model.txt",
    "content": "// Keywords: multispecies\n\nspecies sim initialize()\n{\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\nticks all 1 early()\n{\n\tsim.addSubpop(\"p1\", 500);\n}\nticks all 2000 late()\n{\n\tsim.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.2 - A two-species model.txt",
    "content": "// Keywords: multispecies\n\nspecies fox initialize() {\n\tinitializeSpecies(tickModulo=3, tickPhase=5, avatar=\"🦊\");\n}\nspecies mouse initialize() {\n\tinitializeSpecies(tickModulo=1, tickPhase=1, avatar=\"🐭\");\n}\nticks all 1 early() {\n\tfox.addSubpop(\"p1\", 50);\n\tmouse.addSubpop(\"p2\", 500);\n}\nticks all 2000 late() {\n\tfox.outputFixedMutations();\n\tmouse.outputFixedMutations();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.3 - A deterministic host-parasitoid model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n}\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\nticks all late() {\n\tx1 = p1.individualCount / S;      // host density\n\tx2 = p2.individualCount / S;      // parasitoid density\n\t\n\tx1′ = x1 * exp(R - x1/K - A*x2);  // x1[t+1]\n\tx2′ = x1 * (1 - exp(-A*x2));      // x2[t+1]\n\t\n\tp1.setSubpopulationSize(asInteger(round(S * x1′)));\n\tp2.setSubpopulationSize(asInteger(round(S * x2′)));\n}\nticks all 250 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.4 - An individual-based host-parasitoid model I.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host indicate survival (0) or death (1)\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n}\n\nticks all first()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// assess densities\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// hunt: each parasitoid counts its successes, and\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tP_parasitized = 1 - exp(-A * x2);\n\tkilled = rbinom(hosts.size(), 1, P_parasitized);\n\thosts.tag = killed;\t// 1 means killed\n\thunters = sample(parasitoids, sum(killed), replace=T);\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\tsurvivors = hosts[killed == 0];\n\t\n\t// competition: kill a fraction of survivors; note\n\t// that this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tsurvived = rbinom(survivors.size(), 1, P_survives);\n\tdead = survivors[survived == 0];\t// 1 means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\n\n// non-overlapping generations: parents die, offspring live\nspecies host survival() {\n\treturn (individual.age == 0);\n}\nspecies parasitoid survival() {\n\treturn (individual.age == 0);\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.4 - An individual-based host-parasitoid model II.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host are unused\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n}\n\nspecies host reproduction() {\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n}\n\nticks all early()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// first, kill off the parental generation\n\thost_age = hosts.age;\n\thosts[host_age > 0].fitnessScaling = 0.0;\n\t\n\tparasitoid_age = parasitoids.age;\n\tparasitoids[parasitoid_age > 0].fitnessScaling = 0.0;\n\t\n\t// narrow down to the juveniles and assess densities\n\thosts = hosts[host_age == 0];\n\tparasitoids = parasitoids[parasitoid_age == 0];\n\t\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// next, hunt; each parasitoid counts its successes\n\tparasitoids.tag = 0;\n\tP_parasitized = 1 - exp(-A * x2);\n\tluck = rbinom(hosts.size(), 1, P_parasitized);\n\tdead = hosts[luck == 1];\n\tdead.fitnessScaling = 0.0;\n\thunters = sample(parasitoids, dead.size(), replace=T);\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\thosts = hosts[luck == 0];\n\t\n\t// finally, competition kills a fraction of survivors\n\t// this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tluck = rbinom(hosts.size(), 1, P_survives);\n\tdead = hosts[luck == 0];\n\tdead.fitnessScaling = 0.0;\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.5 - A continuous-space host-parasitoid model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"SIDE\", 10);\t// one side length; square root of S\n\tdefineConstant(\"S\", SIDE*SIDE);\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tdefineConstant(\"S_P\", 0.5);\t// parasitoid hunting/mating kernel width\n\tdefineConstant(\"S_H\", 0.2);\t// host competition/mating kernel width\n\tdefineConstant(\"D_H\", 0.2);\t// host dispersal kernel width\n\tdefineConstant(\"CROSS_SCRIPT\", \"subpop.addCrossed(individual, mate);\");\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\t// parasitoids looking for things (long search distance)\n\tinitializeInteractionType(1, \"xy\", maxDistance=S_P);\n\ti1.setInteractionFunction(\"l\", 1.0);\n\t\n\t// hosts looking for things (short search distance)\n\tinitializeInteractionType(2, \"xy\", maxDistance=S_H);\n\ti2.setInteractionFunction(\"l\", 1.0);\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\t// tag values in host indicate survival (0) or death (1)\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\t// tag values in parasitoid count successful hunts\n}\n\nticks all 2: first()\n{\n\thost_pop = host.subpopulations;\n\thosts = host_pop.individuals;\n\tparasitoid_pop  = parasitoid.subpopulations;\n\tparasitoids  = parasitoid_pop.individuals;\n\t\n\t// assess densities, per individual\n\ti1.evaluate(c(host_pop, parasitoid_pop));\n\ti2.evaluate(host_pop);\n\tparasitoid_density_byhost = i1.localPopulationDensity(hosts, parasitoid_pop);\n\t\n\t// hunt: each parasitoid counts its successes,\n\t// and remembers the positions of its prey;\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tparasitoids.setValue(\"PREY_POS\", NULL);\n\tP_parasitized_byhost = 1 - exp(-A * parasitoid_density_byhost);\n\tkilled = (runif(hosts.size()) < P_parasitized_byhost);\n\thosts.tag = asInteger(killed);           // T/1 means killed\n\tpreys = hosts[killed];\n\tfor (prey in preys)\n\t{\n\t\thunter = i1.drawByStrength(prey, 1, parasitoid_pop);\n\t\tpreyPos = prey.spatialPosition;\n\t\tpreyPos = c(hunter.getValue(\"PREY_POS\"), preyPos);\n\t\thunter.tag = hunter.tag + 1;\n\t\thunter.setValue(\"PREY_POS\", preyPos);\n\t}\n\tunhunted = hosts[!killed];\n\t\n\t// competition: kill a fraction of unhunted; note\n\t// that this is based on pre-parasitism density\n\thost_density_by_unhunted = i2.localPopulationDensity(unhunted, host_pop);\n\tP_survives_by_unhunted = exp(-host_density_by_unhunted / K);\n\tsurvived = (runif(unhunted.size()) < P_survives_by_unhunted);\n\tdead = unhunted[!survived];\t// T means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tmate = i2.drawByStrength(individual);\n\t\t\n\tif (mate.size())\n\t{\n\t\tlitterSize = rpois(1, exp(R));\n\t\n\t\tif (litterSize > 0)\n\t\t{\n\t\t\toffspring = sapply(seqLen(litterSize), CROSS_SCRIPT);\n\t\t\t\n\t\t\t// vectorized set of offspring spatial positions, based\n\t\t\t// on the first parent position plus dispersal D_H\n\t\t\tpositions = rep(individual.spatialPosition, litterSize);\n\t\t\tpositions = positions + rnorm(litterSize * 2, 0, D_H);\n\t\t\tpositions = p1.pointReflected(positions);\n\t\t\toffspring.setSpatialPosition(positions);\n\t\t}\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = i1.drawByStrength(individual);\n\t\t\n\t\tif (mate.size())\n\t\t{\n\t\t\toffspring = sapply(seqLen(litterSize), CROSS_SCRIPT);\n\t\t\t\n\t\t\t// vectorized set of offspring positions to prey positions\n\t\t\toffspring.setSpatialPosition(individual.getValue(\"PREY_POS\"));\n\t\t}\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tp1.setSpatialBounds(c(0, 0, SIDE, SIDE));\n\tp1.individuals.setSpatialPosition(p1.pointUniform(N0_host));\n\t\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n\tp2.setSpatialBounds(c(0, 0, SIDE, SIDE));\n\tp2.individuals.setSpatialPosition(p2.pointUniform(N0_parasitoid));\n}\n\n// non-overlapping generations: parents die, offspring live\nspecies host survival() {\n\treturn (individual.age == 0);\n}\nspecies parasitoid survival() {\n\treturn (individual.age == 0);\n}\n\nticks all 250 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.6 - A coevolutionary host-parasitoid trait-matching model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"K\", 100);\n\tdefineConstant(\"R\", log(20));\n\tdefineConstant(\"A\", 0.015);\n\tdefineConstant(\"S\", 10^2);    // larger is more stable, but slower\n\tdefineConstant(\"N0_host\", asInteger((135.6217 + 0.01) * S));\n\tdefineConstant(\"N0_parasitoid\", asInteger((109.3010 + 0.01) * S));\n\t\n\tdefineConstant(\"S_M\", 1.0);\t// parasitoid/host matching width\n\tdefineConstant(\"S_S\", 2.0);\t// stabilizing fitness function width\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🐛\", color=\"cornflowerblue\");\n\t// tag values in host indicate survival (0) or death (1)\n\t// tagF values in host are QTL-based additive phenotypes\n\t\n\t// one short QTL controlling parasitism avoidance\n\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.1);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies parasitoid initialize() {\n\tinitializeSpecies(avatar=\"🦟\", color=\"red\");\n\t// tag values in parasitoid count successful hunts\n\t// tagF values in parasitoid are QTL-based additive phenotypes\n\t\n\t// one short QTL controlling host trait matching\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.1);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0);\n\tinitializeGenomicElement(g2, 0, 9999);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies host mutationEffect(m1) { return 1.0; }\nspecies parasitoid mutationEffect(m2) { return 1.0; }\n\nticks all 2: first()\n{\n\thosts = host.subpopulations.individuals;\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\t\n\t// assess densities\n\tx1 = hosts.size() / S;          // host density\n\tx2 = parasitoids.size() / S;    // parasitoid density\n\t\n\t// assess matches between hosts and the mean parasitoid\n\thost_values = hosts.tagF;\n\tparasitoid_values = parasitoids.tagF;\n\tmean_parasitoid = mean(parasitoid_values);\n\tscale = dnorm(0.0, 0.0, S_M);\n\thost_match = dnorm(host_values, mean_parasitoid, S_M) / scale;\n\t\n\t// hunt: each parasitoid counts its successes, and\n\t// each host tracks whether it was killed\n\tparasitoids.tag = 0;\n\tP_parasitized_byhost = 1 - exp(-A * x2 * host_match);\n\tkilled = rbinom(hosts.size(), 1, P_parasitized_byhost);\n\thosts.tag = killed;\t// 1 means killed\n\thunters = sapply(hosts[killed == 1], \"sample(parasitoids, 1, \" +\n\t\t\"weights=dnorm(applyValue.tagF - parasitoid_values, 0.0, S_M));\");\n\tfor (hunter in hunters)\n\t\thunter.tag = hunter.tag + 1;\n\tsurvivors = hosts[killed == 0];\n\t\n\t// competition: kill a fraction of survivors; note\n\t// that this is based on pre-parasitism density\n\tP_survives = exp(-x1 / K);\n\tsurvived = rbinom(survivors.size(), 1, P_survives);\n\tdead = survivors[survived == 0];\t// 1 means survived\n\tdead.tag = 1;\t\t\t\t\t\t// mark as dead\n}\n\nspecies host reproduction() {\n\t// only hosts tagged 0 (survived) get to reproduce\n\tif (individual.tag != 0)\n\t\treturn;\n\t\n\t// reproduce each host with a mean of exp(r) offspring\n\tlitterSize = rpois(1, exp(R));\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies parasitoid reproduction() {\n\t// reproduce each parasitoid as many times as it parasitized\n\tlitterSize = individual.tag;\n\t\n\tif (litterSize > 0)\n\t{\n\t\tmate = subpop.sampleIndividuals(1, exclude=individual);\n\t\tfor (i in seqLen(litterSize))\n\t\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p1\", N0_host);\n\tparasitoid.addSubpop(\"p2\", N0_parasitoid);\n\t\n\tlog = community.createLogFile(\"host-parasite log.txt\", logInterval=1);\n\tlog.addTick();\n\tlog.addPopulationSize(host);\n\tlog.addMeanSDColumns(\"host\", \"p1.individuals.tagF;\");\n\tlog.addPopulationSize(parasitoid);\n\tlog.addMeanSDColumns(\"parasitoid\", \"p2.individuals.tagF;\");\n}\n\nticks all early() {\n\t// calculate phenotypes and implement stabilizing selection\n\tscale = dnorm(0.0, 0.0, S_S);\n\t\n\thosts = host.subpopulations.individuals;\n\tphenotypes = hosts.sumOfMutationsOfType(m1);\n\thosts.fitnessScaling = dnorm(phenotypes, 0.0, S_S) / scale;\n\thosts.tagF = phenotypes;\n\t\n\tparasitoids  = parasitoid.subpopulations.individuals;\n\tphenotypes = parasitoids.sumOfMutationsOfType(m2);\n\tparasitoids.fitnessScaling = dnorm(phenotypes, 0.0, S_S) / scale;\n\tparasitoids.tagF = phenotypes;\n\t\n\t// non-overlapping generations: parents die, offspring live\n\thosts[hosts.age > 0].fitnessScaling = 0.0;\n\tparasitoids[parasitoids.age > 0].fitnessScaling = 0.0;\n}\n\nticks all 10000 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.7 - A coevolutionary host-parasite matching-allele model.txt",
    "content": "// Keywords: multispecies, interaction\n\nspecies all initialize() {\n\tdefineConstant(\"L\", 1);\n}\nspecies host initialize() {\n\tinitializeSpecies(avatar=\"🦌\");\n\t\n\t// one nucleotide controlling infection\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0, mmJukesCantor(1e-3));\n\tinitializeGenomicElement(g1, 0, L - 1);\n\tinitializeRecombinationRate(1e-8);\n}\nspecies parasite initialize() {\n\tinitializeSpecies(avatar=\"🐛\");\n\t\n\t// one nucleotide controlling resistance\n\tinitializeSLiMOptions(nucleotideBased=T);\n\tinitializeAncestralNucleotides(randomNucleotides(L));\n\tinitializeMutationTypeNuc(\"m2\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g2\", m2, 1.0, mmJukesCantor(1e-3));\n\tinitializeGenomicElement(g2, 0, L - 1);\n\tinitializeRecombinationRate(1e-8);\n}\n\nfunction (float$)nucleotideFreq(o<Species>$ species, s$ nuc) {\n\tnucs = species.subpopulations.individuals.haplosomes.nucleotides();\n\treturn mean(nucs == nuc);\n}\n\nticks all 1 early() {\n\thost.addSubpop(\"p0\", 1000);\n\tparasite.addSubpop(\"p1\", 1000);\n\t\n\tlog = community.createLogFile(\"host-parasite log.txt\", logInterval=1);\n\tlog.addTick();\n\tlog.addCustomColumn(\"hA\", \"nucleotideFreq(host, 'A');\");\n\tlog.addCustomColumn(\"hC\", \"nucleotideFreq(host, 'C');\");\n\tlog.addCustomColumn(\"hG\", \"nucleotideFreq(host, 'G');\");\n\tlog.addCustomColumn(\"hT\", \"nucleotideFreq(host, 'T');\");\n\tlog.addCustomColumn(\"pA\", \"nucleotideFreq(parasite, 'A');\");\n\tlog.addCustomColumn(\"pC\", \"nucleotideFreq(parasite, 'C');\");\n\tlog.addCustomColumn(\"pG\", \"nucleotideFreq(parasite, 'G');\");\n\tlog.addCustomColumn(\"pT\", \"nucleotideFreq(parasite, 'T');\");\n}\n\nticks all late() {\n\t// each parasite will pick a random host and try to infect it\n\tparasites = p1.individuals;\n\tchosen_hosts = sample(p0.individuals, size(parasites), replace=T);\n\t\n\tfor (p in parasites, h in chosen_hosts)\n\t{\n\t\t// infection depends upon a match (diploid matching-allele model)\n\t\tall_nucleotides = c(p,h).haplosomes.nucleotides();\n\t\t\n\t\tif (size(unique(all_nucleotides, preserveOrder=F)) == 1)\n\t\t{\n\t\t\t// parasite and host are both homozygous for the same nucleotide(s)\n\t\t\t// with a match, the parasite's fitness increases, the host's decreases\n\t\t\tp.fitnessScaling = 1.5 * p.fitnessScaling;\n\t\t\th.fitnessScaling = 0.5 * h.fitnessScaling;\n\t\t}\n\t}\n}\n\nticks all 2000 late() {\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 20.8 - Within-host reproduction in a host-pathogen model.txt",
    "content": "// Keywords: multispecies, interaction, life history, timescale, parasite, infection, SIR, S-I-R\n\nspecies all initialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\t\n\tdefineConstant(\"K_MONKEY\", 100);             // monkey carrying capacity\n\tdefineConstant(\"F_MONKEY\", 3.0);             // monkey fecundity\n\tdefineConstant(\"G_MONKEY\", 20);              // relative generation timescale\n\tdefineConstant(\"P_TRANSMISSION\", 0.0001);    // probability of transmission\n\tdefineConstant(\"SUPPRESSION_μ\", 30000);      // optimal size for suppression\n\tdefineConstant(\"SUPPRESSION_σ\", 10000);      // width for suppression\n\tdefineConstant(\"SUPPRESSION_STRENGTH\", 0.4); // strength of suppression\n\tdefineConstant(\"DEATH\", 100000);             // level for certain death\n}\nspecies monkey initialize() {\n\tinitializeSpecies(tickModulo=G_MONKEY, avatar=\"🐵\", color=\"tan3\");\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeSex();\n\t// pedigree IDs are used to identify host-pathogen matches\n\t// colors: blue == uninfected, yellow -> red == infected, black == dead\n}\nspecies pathogen initialize() {\n\tinitializeSpecies(avatar=\"🦠\", color=\"chartreuse3\");\n\t// pathogen.tag is a counter of the next subpop ID to use\n\t// subpopulation.tag is the pedigree ID of the host for the subpop\n}\n\nticks all 2: first() {\n\tif (p1.individualCount == 0)\n\t\tstop(monkey.avatar + \" extinct\");\n\tif (pathogen.subpopulations.size() == 0)\n\t\tstop(pathogen.avatar + \" extinct\");\n}\n\nspecies monkey reproduction(p1, \"F\") {\n\t// monkeys reproduce sexually, non-monogamously\n\tlitterSize = rpois(1, F_MONKEY);\n\t\n\tfor (i in seqLen(litterSize))\n\t{\n\t\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\tsubpop.addCrossed(individual, mate);\n\t}\n}\nspecies pathogen reproduction() {\n\t// the pathogen reproduces clonally\n\tsubpop.addCloned(individual);\n}\n\nticks all 1 early() {\n\tmonkey.addSubpop(\"p1\", K_MONKEY);\n\t\n\t// choose initial hosts carrying the infection\n\tinitial_hosts = p1.sampleIndividuals(5, replace=F);\n\tpathogen.tag = 3;\n\t\n\tfor (initial_host in initial_hosts)\n\t{\n\t\t// make a pathogen subpop for the host\n\t\tpathogen_subpop = pathogen.addSubpop(pathogen.tag, 1);\n\t\tpathogen_subpop.tag = initial_host.pedigreeID;\n\t\tpathogen.tag = pathogen.tag + 1;\n\t}\n\t\n\t// log some basic output\n\tlogfile = community.createLogFile(\"host_pathogen_log.csv\", logInterval=1);\n\tlogfile.addTick();\n\tlogfile.addSubpopulationSize(p1);\n\tlogfile.addPopulationSize(pathogen);\n\tlogfile.addCustomColumn(\"host_count\", \"pathogen.subpopulations.size();\");\n\tlogfile.addMeanSDColumns(\"monkeyAge\", \"p1.individuals.age;\");\n}\n\nticks monkey early() {\n\t// monkey population regulation\n\tp1.fitnessScaling = K_MONKEY / p1.individualCount;\n}\nticks all early() {\n\t// horizontal transmission\n\tif (p1.individualCount > 1)\n\t{\n\t\tpathogenSubpops = pathogen.subpopulations;\n\t\tallPathogens = pathogenSubpops.individuals;\n\t\tisTransmitted = (rbinom(allPathogens.size(), 1, P_TRANSMISSION) == 1);\n\t\tmoving = allPathogens[isTransmitted];\n\t\t\n\t\tfor (ind in moving)\n\t\t{\n\t\t\t// figure out which host we are in\n\t\t\thostID = ind.subpopulation.tag;\n\t\t\tcurrentHost = monkey.individualsWithPedigreeIDs(hostID);\n\t\t\t\n\t\t\t// choose a different host and get its ID\n\t\t\tnewHost = p1.sampleIndividuals(1, exclude=currentHost);\n\t\t\tnewHostID = newHost.pedigreeID;\n\t\t\t\n\t\t\t// find/create a subpop for the new host and move to it\n\t\t\tnewSubpop = pathogenSubpops[pathogenSubpops.tag == newHostID];\n\t\t\t\n\t\t\tif (newSubpop.size() == 0)\n\t\t\t{\n\t\t\t\tnewSubpop = pathogen.addSubpop(pathogen.tag, 0);\n\t\t\t\tpathogen.tag = pathogen.tag + 1;\n\t\t\t\tnewSubpop.tag = newHostID;\n\t\t\t\t\n\t\t\t\t// need to incorporate the new subpop in case it receives another\n\t\t\t\tpathogenSubpops = c(pathogenSubpops, newSubpop);\n\t\t\t}\n\t\t\tnewSubpop.takeMigrants(ind);\n\t\t}\n\t}\n}\nticks all early() {\n\t// disease outcomes: either suppression or mortality\n\tsuppress_scale = SUPPRESSION_STRENGTH / dnorm(0.0, 0.0, SUPPRESSION_σ);\n\t\n\tfor (pathogenSubpop in pathogen.subpopulations)\n\t{\n\t\tpopsize = asFloat(pathogenSubpop.individualCount);\n\t\tP_supp = (dnorm(popsize, SUPPRESSION_μ, SUPPRESSION_σ) * suppress_scale);\n\t\tP_death = popsize / DEATH;\n\t\t\n\t\tif (runif(1) < P_supp)\n\t\t{\n\t\t\t// the infection is suppressed; host lives, pathogen dies\n\t\t\tpathogenSubpop.removeSubpopulation();\n\t\t}\n\t\telse if (runif(1) < P_death)\n\t\t{\n\t\t\t// the host has died; kill it and its pathogens\n\t\t\thost = monkey.individualsWithPedigreeIDs(pathogenSubpop.tag);\n\t\t\tmonkey.killIndividuals(host);\n\t\t\tpathogenSubpop.removeSubpopulation();\n\t\t}\n\t}\n}\nticks all early() {\n\t// color monkeys by their infection level\n\tpathogenSubpops = pathogen.subpopulations;\n\t\n\tfor (host in p1.individuals)\n\t{\n\t\thostID = host.pedigreeID;\n\t\tpathogenSubpop = pathogenSubpops[pathogenSubpops.tag == hostID];\n\t\t\n\t\tif (pathogenSubpop.size() == 1)\n\t\t{\n\t\t\tpathogenCount = pathogenSubpop.individualCount;\n\t\t\thue = max(0.0, 1.0 - pathogenCount / DEATH) * 0.15;\n\t\t\thost.color = rgb2color(hsv2rgb(c(hue, 1, 1)));\n\t\t}\n\t\telse\n\t\t\thost.color = \"cornflowerblue\";\n\t}\n}\n\nspecies monkey survival(p1) {\n\t// when a monkey dies, any pathogens in it die\n\tif (!surviving)\n\t{\n\t\thostID = individual.pedigreeID;\n\t\tpathogenSubpops = pathogen.subpopulations;\n\t\tpathogenSubpop = pathogenSubpops[pathogenSubpops.tag == hostID];\n\t\tpathogenSubpop.removeSubpopulation();\n\t}\n\treturn NULL;\n}\n\nticks all 2000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.1 - A basic neutral simulation.txt",
    "content": "// Keywords: \n\n// set up a simple neutral simulation\ninitialize()\n{\n\t// set the overall mutation rate\n\tinitializeMutationRate(1e-7);\n\t\n\t// m1 mutation type: neutral\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\n\t// g1 genomic element type: uses m1 for all mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// uniform chromosome of length 100 kb\n\tinitializeGenomicElement(g1, 0, 99999);\n\t\n\t// uniform recombination along the chromosome\n\tinitializeRecombinationRate(1e-8);\n}\n\n// create a population of 500 individuals\n1 early()\n{\n\tsim.addSubpop(\"p1\", 500);\n}\n\n// run to tick 10000\n10000 early()\n{\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.1.10 - Using symbolic constants for model parameters.txt",
    "content": "// Keywords: parameter, constant, symbol, global, define\n\ninitialize()\n{\n\t// define some global constants for parameters\n\tdefineConstant(\"MU\", 1e-7);\n\tdefineConstant(\"L\", 1e5);\n\tdefineConstant(\"R\", 1e-8);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L - 1);\n\tinitializeRecombinationRate(R);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", N);\n}\n20*N early() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.1 - Basic output, Entire population.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.2 - Basic output, Random population sample.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 late() { p1.outputSample(10); }\n10000 late() { sim.outputFull(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.3 - Basic output, Sampling individuals for output.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.01);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1.0,0.01));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n}\n10000 late() {\n\tallIndividuals = sim.subpopulations.individuals;\n\tw = asFloat(allIndividuals.countOfMutationsOfType(m2) + 1);\n\tsampledIndividuals = sample(allIndividuals, 10, weights=w);\n\tsampledIndividuals.haplosomes.outputHaplosomes();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.4 - Basic output, Substitutions.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 late() { p1.outputSample(10); }\n10000 late() { sim.outputFull(); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.5 - Basic output, Automatic logging with LogFile.txt",
    "content": "// Keywords: migration, dispersal, table output, CSV, TSV, FST\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n\tsim.addSubpop(\"p2\", 1000);\n\tp1.setMigrationRates(p2, 0.001);\n\tp2.setMigrationRates(p1, 0.001);\n\tlog = community.createLogFile(\"sim_log.txt\", logInterval=10);\n\tlog.addCycle();\n\tlog.addCustomColumn(\"FST\", \"calcFST(p1.haplosomes, p2.haplosomes);\");\n}\n20000 late() { }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 4.2.6 - Basic output, Custom output with Eidos.txt",
    "content": "// Keywords: MS format\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 500);\n}\n\n// custom MS-style output from a multi-subpop sample\n2000 late() {\n\t// obtain a random sample of haplosomes from the whole population\n\th = sample(sim.subpopulations.haplosomes, 10, T);\n\t\n\t// get the unique mutations in the sample, sorted by position\n\tm = sortBy(unique(h.mutations, preserveOrder=F), \"position\");\n\t\n\t// print the number of segregating sites\n\tcat(\"\\n\\nsegsites: \" + size(m) + \"\\n\");\n\t\n\t// print the positions\n\tpositions = format(\"%.6f\", m.position / sim.chromosomes.lastPosition);\n\tcat(\"positions: \" + paste(positions, sep=\" \") + \"\\n\");\n\t\n\t// print the sampled haplosomes\n\tfor (haplosome in h)\n\t{\n\t\thasMuts = (match(m, haplosome.mutations) >= 0);\n\t\tcat(paste(asInteger(hasMuts), sep=\"\") + \"\\n\");\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.1 - Subpopulation size, Instantaneous changes.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1000); }\n1000 early() { p1.setSubpopulationSize(100); }\n2000 early() { p1.setSubpopulationSize(1000); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth I.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:1099 early() {\n\tnewSize = asInteger(p1.individualCount * 1.03);\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth II.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:1099 early() {\n\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth III.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000:2000 early() {\n\tif (p1.individualCount < 2000)\n\t{\n\t\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\t\tp1.setSubpopulationSize(newSize);\n\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth IV.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000: early() {\n\tnewSize = round(1.03^(sim.cycle - 999) * 100);\n\tif (newSize > 2000)\n\t\tnewSize = 2000;\n\tp1.setSubpopulationSize(asInteger(newSize));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.2 - Subpopulation size, Exponential growth V.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000: early() {\n\tnewSize = asInteger(round(1.03^(sim.cycle - 999) * 100));\n\tif (newSize >= 2000)\n\t{\n\t\tnewSize = 2000;\n\t\tcommunity.deregisterScriptBlock(self);\n\t}\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.4 - Subpopulation size, Cyclical changes.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 1500); }\nearly() {\n\tnewSize = cos((sim.cycle - 1) / 100) * 500 + 1000;\n\tp1.setSubpopulationSize(asInteger(newSize));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.1.5 - Subpopulation size, Context-dependent changes (Muller's Ratchet).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"e\", -0.01);\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\nearly() {\n\tmeanFitness = mean(p1.cachedFitness(NULL));\n\tnewSize = asInteger(100 * meanFitness);\n\tp1.setSubpopulationSize(newSize);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.2.1 - Population structure, Adding subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 100);\n\tsim.addSubpop(\"p3\", 1000);\n\tp1.setMigrationRates(c(p2,p3), c(0.2,0.1));\n\tp2.setMigrationRates(c(p1,p3), c(0.8,0.01));\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.2.2 - Population structure, Removing subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n100 early() { sim.addSubpop(\"p2\", 100); }\n100:150 early() {\n\tmigrationProgress = (sim.cycle - 100) / 50;\n\tp1.setMigrationRates(p2, 0.2 * migrationProgress);\n\tp2.setMigrationRates(p1, 0.8 * migrationProgress);\n}\n1000 early() { sim.addSubpop(\"p3\", 10); }\n1000:1100 early() {\n\tp3Progress = (sim.cycle - 1000) / 100;\n\tp3.setSubpopulationSize(asInteger(990 * p3Progress + 10));\n\tp1.setMigrationRates(p3, 0.1 * p3Progress);\n\tp2.setMigrationRates(p3, 0.01 * p3Progress);\n}\n2000 early() { p2.setSubpopulationSize(0); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.2.3 - Population structure, Splitting subpopulations.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n100 early() { sim.addSubpopSplit(\"p2\", 100, p1); }\n100:150 early() {\n\tmigrationProgress = (sim.cycle - 100) / 50;\n\tp1.setMigrationRates(p2, 0.2 * migrationProgress);\n\tp2.setMigrationRates(p1, 0.8 * migrationProgress);\n}\n1000 early() { sim.addSubpopSplit(\"p3\", 10, p2); }\n1000:1100 early() {\n\tp3Progress = (sim.cycle - 1000) / 100;\n\tp3.setSubpopulationSize(asInteger(990 * p3Progress + 10));\n\tp1.setMigrationRates(p3, 0.1 * p3Progress);\n\tp2.setMigrationRates(p3, 0.01 * p3Progress);\n}\n2000 early() { p2.setSubpopulationSize(0); }\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.2.4 - Population structure, Joining subpopulations.txt",
    "content": "// Keywords: migration, admixture, merging, combining\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tsim.addSubpop(\"p2\", 1000);\n}\n1000 early() {\n\t// set up p3 to generate itself entirely from migrants\n\tsim.addSubpop(\"p3\", 300);\n\tp3.setMigrationRates(c(p1, p2), c(0.75, 0.25));\n}\n1000 late() {\n\t// remove the source subpopulations\n\tp3.setMigrationRates(c(p1, p2), c(0.0, 0.0));\n\tp1.setSubpopulationSize(0);\n\tp2.setSubpopulationSize(0);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.3.1 - Migration and admixture, A linear stepping-stone model.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tdefineConstant(\"COUNT\", 10);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 0:(COUNT-1))\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (i in 1:(COUNT-1)) subpops[i].setMigrationRates(i-1, 0.2);\n\tfor (i in 0:(COUNT-2)) subpops[i].setMigrationRates(i+1, 0.05);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.3.2 - Migration and admixture, A non-spatial metapopulation.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsubpopCount = 5;\n\tfor (i in 1:subpopCount)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 1:subpopCount)\n\t\tfor (j in 1:subpopCount)\n\t\t\tif (i != j)\n\t\t\t\tsim.subpopulations[i-1].setMigrationRates(j, 0.05);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.3.3 - Migration and admixture, A two-dimensional subpopulation matrix.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tmetapopSide = 3;\t// number of subpops along one side of the grid\n\tmetapopSize = metapopSide * metapopSide;\n\tfor (i in 1:metapopSize)\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (x in 1:metapopSide)\n\t\tfor (y in 1:metapopSide)\n\t\t{\n\t\t\tdestID = (x - 1) + (y - 1) * metapopSide + 1;\n\t\t\tdestSubpop = subpops[destID - 1];\n\t\t\tif (x > 1)   // left to right\n\t\t\t\tdestSubpop.setMigrationRates(destID - 1, 0.05);\n\t\t\tif (x < metapopSide)   // right to left\n\t\t\t\tdestSubpop.setMigrationRates(destID + 1, 0.05);\n\t\t\tif (y > 1)   // top to bottom\n\t\t\t\tdestSubpop.setMigrationRates(destID - metapopSide, 0.05);\n\t\t\tif (y < metapopSide)   // bottom to top\n\t\t\t\tdestSubpop.setMigrationRates(destID + metapopSide, 0.05);\n\t\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.3.4 - Migration and admixture, A random, sparse spatial metapopulation.txt",
    "content": "// Keywords: migration, dispersal, SLiMgui\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.3);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 late() {\n\tmSide = 10;\t// number of subpops along one side of the grid\n\tfor (i in 1:(mSide * mSide))\n\t\tsim.addSubpop(i, 500);\n\t\n\tsubpops = sim.subpopulations;\n\tfor (x in 1:mSide)\n\t\tfor (y in 1:mSide)\n\t\t{\n\t\t\tdestID = (x - 1) + (y - 1) * mSide + 1;\n\t\t\tds = subpops[destID - 1];\n\t\t\tif (x > 1)   // left to right\n\t\t\t\tds.setMigrationRates(destID - 1, runif(1, 0.0, 0.05));\n\t\t\tif (x < mSide)   // right to left\n\t\t\t\tds.setMigrationRates(destID + 1, runif(1, 0.0, 0.05));\n\t\t\tif (y > 1)   // top to bottom\n\t\t\t\tds.setMigrationRates(destID - mSide, runif(1, 0.0, 0.05));\n\t\t\tif (y < mSide)   // bottom to top\n\t\t\t\tds.setMigrationRates(destID + mSide, runif(1, 0.0, 0.05));\n\t\t\t\n\t\t\t// set up SLiMgui's population visualization nicely\n\t\t\txd = ((x - 1) / (mSide - 1)) * 0.9 + 0.05;\n\t\t\tyd = ((y - 1) / (mSide - 1)) * 0.9 + 0.05;\n\t\t\tds.configureDisplay(c(xd, yd), 0.4);\n\t\t}\n\t\n\t// remove 25% of the subpopulations\n\tsubpops[sample(0:99, 25)].setSubpopulationSize(0);\n\t\n\t// introduce a beneficial mutation\n\ttarget_subpop = sample(sim.subpopulations, 1);\n\tsample(target_subpop.haplosomes, 10).addNewDrawnMutation(m2, 20000);\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.3.5 - Migration and admixture, Reading a migration matrix from a file.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 1:3)\n\t\tsim.addSubpop(i, 1000);\n\tsubpops = sim.subpopulations;\n\t\n\t// this file is in the recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tlines = readFile(\"migration.csv\");\n\tlines = lines[substr(lines, 0, 1) != \"//\"];\n\t\n\tfor (line in lines)\n\t{\n\t\tfields = strsplit(line, \",\");\n\t\ti = asInteger(fields[0]);\n\t\tj = asInteger(fields[1]);\n\t\tm = asFloat(fields[2]);\n\t\t\n\t\tif (i != j)\n\t\t{\n\t\t\tp_i = subpops[subpops.id == i];\n\t\t\tp_j = subpops[subpops.id == j];\n\t\t\tp_j.setMigrationRates(p_i, m);\n\t\t}\n\t}\n}\n10000 late() { sim.outputFixedMutations(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution I.txt",
    "content": "// Keywords: migration, dispersal\n\n// Model based on Gravel et al. 2011, doi:10.1073/pnas.1019276108 (hereafter \"paper\")\ninitialize() {\n\tinitializeMutationRate(2.36e-8); // theta=3813.75\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999); // paper uses 4.04e6, 5007837, etc.\n\tinitializeRecombinationRate(1e-8);\n}\n\n// INITIALIZE the ancestral African population of size 7310\n1 early() { sim.addSubpop(\"p1\", asInteger(round(7310.370867595234))); } // paper rounds to 7310\n\n// END BURN-IN period of 10*N=73104 generations (specific to SLiM recipe); EXPAND the African population\n// This occurs (5919.131117 generations)*(25 years)=147978 yr ago; paper rounds to 5920 gens (148000 yr)\n// Thus, simulation should end at generation 1+73104+5919.131117=79024\n73105 early() { p1.setSubpopulationSize(asInteger(round(14474.54608753566))); } // paper rounds to 14474\n\n// SPLIT Eurasians (p2) from Africans (p1) and SET UP MIGRATION between them\n// This occurs 2056.396652 generations (51409.9163 years) ago; paper rounds to 2040 gens (51000 yr)\n// Relative to beginning, this is generation 79024-2056.396652=76968\n76968 early() {\n\tsim.addSubpopSplit(\"p2\", asInteger(round(1861.288190027689)), p1); // paper rounds to 1861\n\tp1.setMigrationRates(c(p2), c(15.24422112e-5)); // paper rounds to 15e-5\n\tp2.setMigrationRates(c(p1), c(15.24422112e-5)); // paper rounds to 15e-5\n}\n\n// SPLIT p2 into European (p2) and East Asian (p3) subpopulations; RESIZE; SET UP MIGRATION between them\n// This occurs 939.8072428 generations (23495.18107 years) ago; paper rounds to 920 gens (23000 yr)\n// Relative to beginning, this is generation 79024-939.8072428=78084\n78084 early() {\n\tsim.addSubpopSplit(\"p3\", asInteger(round(553.8181989)), p2); // paper rounds to 554\n\tp2.setSubpopulationSize(asInteger(round(1032.1046957333444)));  // reduce European size; paper rounds to 1032\n\n\t// Set migration rates for the rest of the simulation\n\tp1.setMigrationRates(c(p2, p3), c(2.54332678e-5, 0.7770583877e-5)); // paper rounds to c(2.5e-5, 0.78e-5)\n\tp2.setMigrationRates(c(p1, p3), c(2.54332678e-5, 3.115817913e-5)); // paper rounds to c(2.5e-5, 3.11e-5)\n\tp3.setMigrationRates(c(p1, p2), c(0.7770583877e-5, 3.115817913e-5)); // paper rounds to c(0.78e-5, 3.11e-5)\n}\n\n// SET UP EXPONENTIAL GROWTH in Europe (p2) and East Asia (p3)\n// Where N(0) is the base subpopulation size and t = gen - 78084:\n//    N(Europe) should be int(round(N(0) * (1 + 0.003784324268)^t)), i.e., growth is r=0.38% per generation\n//    N(East Asia) should be int(round(N(0) * (1 + 0.004780219543)^t)), i.e., growth is r=0.48% per generation\n78084:79024 early() {\n\tt = sim.cycle - 78084;\n\tp2_size = round(1032.1046957333444 * (1 + 0.003784324268)^t); // paper rounds to N(0)=1032 and r=0.0038\n\tp3_size = round(553.8181989 * (1 + 0.004780219543)^t); // paper rounds to N(0)=554 and r=0.0048\n\t\n\tp2.setSubpopulationSize(asInteger(p2_size));\n\tp3.setSubpopulationSize(asInteger(p3_size));\n}\n\n// OUTPUT AND TERMINATE\n// Generation 79024 is the present, i.e., 1 initialize + 73104 burn-in + 5919 evolution\n79024 late() {\n\tp1.outputSample(216); // YRI phase 3 diploid sample of size 108\n\tp2.outputSample(198); // CEU phase 3 diploid sample of size 99\n\tp3.outputSample(206); // CHB phase 3 diploid sample of size 103\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.4 - The Gravel et al. (2011) model of human evolution II.txt",
    "content": "/// # Gravel Model in SLiM\n/// #### _(with Jump Menu annotations)_\n///\n\ninitialize() {\n\tinitializeMutationRate(2.36e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-8);\n}\n\n///\n/// **Demography:**\n\n1 early() /* create p1 */ {\n\tsim.addSubpop(\"p1\", asInteger(round(7310.370867595234)));\n}\n\n73105 early() /* end burn-in */ {\n\tp1.setSubpopulationSize(asInteger(round(14474.54608753566)));\n}\n\n76968 early() /* split p2 from p1 */ {\n\tsim.addSubpopSplit(\"p2\", asInteger(round(1861.288190027689)), p1);\n\tp1.setMigrationRates(c(p2), c(15.24422112e-5));\n\tp2.setMigrationRates(c(p1), c(15.24422112e-5));\n}\n\n78084 early() /* split p3 from p2 */ {\n\tsim.addSubpopSplit(\"p3\", asInteger(round(553.8181989)), p2);\n\tp2.setSubpopulationSize(asInteger(round(1032.1046957333444)));\n\n\tp1.setMigrationRates(c(p2, p3), c(2.54332678e-5, 0.7770583877e-5));\n\tp2.setMigrationRates(c(p1, p3), c(2.54332678e-5, 3.115817913e-5));\n\tp3.setMigrationRates(c(p1, p2), c(0.7770583877e-5, 3.115817913e-5));\n}\n\n78084:79024 early() /* exponential growth */ {\n\tt = sim.cycle - 78084;\n\tp2_size = round(1032.1046957333444 * (1 + 0.003784324268)^t);\n\tp3_size = round(553.8181989 * (1 + 0.004780219543)^t);\n\t\n\tp2.setSubpopulationSize(asInteger(p2_size));\n\tp3.setSubpopulationSize(asInteger(p3_size));\n}\n\n/***/\n/** **Final output:** */\n\n79024 late() {\n\tp1.outputSample(216);\n\tp2.outputSample(198);\n\tp3.outputSample(206);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance I.txt",
    "content": "// Keywords: rescale\n\ninitialize() {\n\tinitializeMutationRate(1e-8);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.01);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.8,0.2));\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n50000 early() { p1.setSubpopulationSize(1000); }\n55000 early() { p1.setSubpopulationSize(5000); }\n60000 late() { p1.outputSample(10); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 5.5 - Rescaling population sizes to improve simulation performance II.txt",
    "content": "// Keywords: rescale\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.1);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(0.8,0.2));\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n5000 early() { p1.setSubpopulationSize(100); }\n5500 early() { p1.setSubpopulationSize(500); }\n6000 late() { p1.outputSample(10); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 6.1 - Genomic structure, Part I (Mutation types and fitness effects).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 6.2 - Genomic structure, Part II (Genomic element types).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);          // non-coding\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 6.3 - Genomic structure, Part III (Chromosome organization).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);           // non-coding\n\t\n\t// Generate random genes along an approximately 100000-base chromosome\n\tbase = 0;\n\t\n\twhile (base < 100000) {\n\t\t// make a non-coding region\n\t\tnc_length = rdunif(1, 100, 5000);\n\t\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\tbase = base + nc_length;\n\t\t\n\t\t// make first exon\n\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\tbase = base + ex_length;\n\t\t\n\t\t// make additional intron-exon pairs\n\t\tdo\n\t\t{\n\t\t\tin_length = asInteger(rlnorm(1, log(100), log(1.5))) + 10;\n\t\t\tinitializeGenomicElement(g2, base, base + in_length - 1);\n\t\t\tbase = base + in_length;\n\t\t\t\n\t\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\t\tbase = base + ex_length;\n\t\t}\n\t\twhile (runif(1) < 0.8);  // 20% probability of stopping\n\t}\n\t\n\t// final non-coding region\n\tnc_length = rdunif(1, 100, 5000);\n\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\n\t// single recombination rate\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 5000); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 6.4 - Genomic structure, Part IV (Custom display colors in SLiMgui).txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // non-coding\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);         // synonymous\n\tinitializeMutationType(\"m3\", 0.1, \"g\", -0.03, 0.2);  // deleterious\n\tinitializeMutationType(\"m4\", 0.8, \"e\", 0.1);         // beneficial\n\tm1.color = \"gray40\";\n\tm2.color = \"gray40\";\n\tm3.color = \"red\";\n\tm4.color = \"green\";\n\tm1.colorSubstitution = \"gray20\";\n\tm2.colorSubstitution = \"gray20\";\n\tm3.colorSubstitution = \"#550000\";\n\tm4.colorSubstitution = \"#005500\";\n\t\n\tinitializeGenomicElementType(\"g1\", c(m2,m3,m4), c(2,8,0.1));  // exon\n\tinitializeGenomicElementType(\"g2\", c(m1,m3), c(9,1));       // intron\n\tinitializeGenomicElementType(\"g3\", c(m1), 1);           // non-coding\n\tg1.color = \"cornflowerblue\";\n\tg2.color = \"#00009F\";\n\tg3.color = \"black\";\n\t\n\t// Generate random genes along an approximately 100000-base chromosome\n\tbase = 0;\n\t\n\twhile (base < 100000) {\n\t\t// make a non-coding region\n\t\tnc_length = rdunif(1, 100, 5000);\n\t\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\tbase = base + nc_length;\n\t\t\n\t\t// make first exon\n\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\tbase = base + ex_length;\n\t\t\n\t\t// make additional intron-exon pairs\n\t\tdo\n\t\t{\n\t\t\tin_length = asInteger(rlnorm(1, log(100), log(1.5))) + 10;\n\t\t\tinitializeGenomicElement(g2, base, base + in_length - 1);\n\t\t\tbase = base + in_length;\n\t\t\t\n\t\t\tex_length = asInteger(rlnorm(1, log(50), log(2))) + 1;\n\t\t\tinitializeGenomicElement(g1, base, base + ex_length - 1);\n\t\t\tbase = base + ex_length;\n\t\t}\n\t\twhile (runif(1) < 0.8);  // 20% probability of stopping\n\t}\n\t\n\t// final non-coding region\n\tnc_length = rdunif(1, 100, 5000);\n\tinitializeGenomicElement(g3, base, base + nc_length - 1);\n\t\n\t// single recombination rate\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.chromosomes.colorSubstitution = \"\";\n\tsim.addSubpop(\"p1\", 5000);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.1 - Reproduction, Enabling separate sexes.txt",
    "content": "// Keywords: sexual\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.2 - Reproduction, Sex ratios I.txt",
    "content": "// Keywords: sexual, sex ratio\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500, 0.6); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.2 - Reproduction, Sex ratios II.txt",
    "content": "// Keywords: sexual, sex ratio\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1: early() { p1.setSexRatio(runif(1, 0.3, 0.7)); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.3 - Reproduction, Selfing in hermaphroditic populations.txt",
    "content": "// Keywords: selfing\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setSelfingRate(0.8);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.4 - Reproduction, Cloning I.txt",
    "content": "// Keywords: clonal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(0.1);\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.1.4 - Reproduction, Cloning II.txt",
    "content": "// Keywords: clonal, sexual\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(c(0.5,0.0));\n}\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.2.1 - Recombination, Making a random recombination map.txt",
    "content": "// Keywords: recombination rate map, recombination map\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\t\n\t// 1000 random recombination regions\n\tends = c(sort(sample(0:99998, 999)), 99999);\n\trates = runif(1000, 1e-9, 1e-7);\n\tinitializeRecombinationRate(rates, ends);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.2.2 - Recombination, Reading a recombination map from a file.txt",
    "content": "// Keywords: recombination rate map, recombination map\n\ninitialize() {\n\tdefineConstant(\"L\", 23011544);\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\t\n\t// read Drosophila 2L map from Comeron et al. 2012; this is in the\n\t// recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip\n\tinitializeRecombinationRateFromFile(\"Comeron_100kb_chr2L.txt\", L-1);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.2.3 - Recombination, Unlinked loci.txt",
    "content": "// Keywords: unlinked loci, free recombination, linkage disequilibrium\n\ninitialize() {\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeRecombinationRate(0.5);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.2.4 - Recombination, Gene conversion.txt",
    "content": "// Keywords: gene conversion\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n\tinitializeGeneConversion(0.2, 500, 1.0);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.1 - Multiple diploid autosomes.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.03, 0.2);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", c(m1, m2), c(1,2));\n\t\n\tinitializeChromosome(1, 1e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeChromosome(2, 2e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeGenomicElement(g2, 1e5, 1e5+5e4-1);\n\tinitializeGenomicElement(g1, 1e5+5e4, 2e5-1);\n\tinitializeMutationRate(2e-7);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n2000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.2 - Clonal haploids and chromosome types.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, type=\"H\");\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(0.0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.setCloningRate(1.0);\n}\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.3 - Haploids with recombination.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, 1e5, type=\"H\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.4 - Sex-chromosome evolution and null haplosomes.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tdefineConstant(\"X_LEN\", 156040895);\n\tdefineConstant(\"Y_LEN\", 57227415);\n\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, X_LEN, type=\"X\", symbol=\"X\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeChromosome(2, Y_LEN, type=\"Y\", symbol=\"Y\");\n\tinitializeGenomicElement(g1);\n\tinitializeMutationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n10000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.5 - Modeling the full human genome.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\t// length data: https://www.ncbi.nlm.nih.gov/grc/human/data,\n\t// Human Genome Assembly GRCh38.p14, 2022-02-03\n\tids = 1:24;\n\tsymbols = c(1:22, \"X\", \"Y\");\n\tlengths = c(248956422, 242193529, 198295559, 190214555, 181538259,\n\t\t\t\t\t170805979, 159345973, 145138636, 138394717, 133797422,\n\t\t\t\t\t135086622, 133275309, 114364328, 107043718, 101991189,\n\t\t\t\t\t90338345, 83257441, 80373285, 58617616, 64444167,\n\t\t\t\t\t46709983, 50818468, 156040895, 57227415);\n\ttypes = c(rep(\"A\", 22), \"X\", \"Y\");\n\t\n\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeRecombinationRate(1e-8);   // not used for the Y\n\t\tinitializeGenomicElement(g1);\n\t}\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n1000 early() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.6 - A model of bryophytes with UV sex determination.txt",
    "content": "// Keywords: bryophytes, UV sex chromosomes, UV sex determination, haploid recombination, mosses\n\ninitialize() {\n\tinitializeSex();\n\t\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:3, type in c(\"H\", \"W\", \"Y\"), symbol in c(\"A\", \"U\", \"V\"))\n\t{\n\t\tinitializeChromosome(id, 1e7, type=type, symbol=symbol);\n\t\tinitializeMutationRate(1e-7);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n\n20000 late() { sim.simulationFinished(); }\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 8.3.7 - Output from multiple-chromosome models.txt",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:3, type in c(\"A\", \"X\", \"Y\"))\n\t{\n\t\tinitializeChromosome(id, 1e6, type=type, symbol=type);\n\t\tinitializeGenomicElement(g1);\n\t\tinitializeMutationRate(1e-8);\n\t\tinitializeRecombinationRate(1e-8);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n100 late() {\n\tsim.outputFull();\n\t\n\tinds = p1.sampleIndividuals(5);\n\tinds.outputIndividuals();\n\tinds.outputIndividualsToVCF();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.1 - Introducing adaptive mutations.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.10 - Tracking the fate of background mutations.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tdefineConstant(\"L\", 3e6);\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.8, \"f\", 0.5);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tdefineConstant(\"BACKGROUND\", target.mutations);\n\tmut = target.addNewDrawnMutation(m2, asInteger(L/2));\n\tdefineConstant(\"SWEEP\", mut);\n}\n1000: late() {\n\tif (!SWEEP.isSegregating & !SWEEP.isFixed)\n\t\tstop(\"LOST\");\n}\n1500 late() {\n\tnonSeg = BACKGROUND[!BACKGROUND.isSegregating];\n\tfixed = nonSeg[nonSeg.isFixed];\n\tlost = nonSeg[!nonSeg.isFixed];\n\twriteFile(\"fixed.txt\", paste(fixed.position, sep=\", \"));\n\twriteFile(\"lost.txt\", paste(lost.position, sep=\", \"));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.11 - Effective population size versus census population size.txt",
    "content": "// Keywords: Ne, parameter estimation\n\ninitialize() {\n\tdefineGlobal(\"N\", 1000);\n\tdefineGlobal(\"L\", 1e7);\n\tdefineGlobal(\"MU\", 1e-7);\n\tdefineGlobal(\"R\", 1e-8);\n\tdefineGlobal(\"S\", 2.0);\n\tinitializeSLiMOptions(keepPedigrees=T);\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\t\t// neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", S);\t\t// sweep\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(R);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setValue(\"previous_N\", p1.individualCount);\n\t\n\tdefineConstant(\"LOG\", community.createLogFile(\"Ne_log.csv\"));\n\tLOG.addCycle();\n\tLOG.addCustomColumn(\"N(t-1)\", \"p1.getValue('previous_N');\");\n\tLOG.addCustomColumn(\"N(t)\", \"p1.individualCount;\");\n\tLOG.addCustomColumn(\"freq\", \"mutTypeFrequency(m2);\");\n\tLOG.addCustomColumn(\"Ne_heterozygosity\", \"estimateNe_Heterozygosity(p1);\");\n\tLOG.addCustomColumn(\"Ne_inbreeding\", \"estimateNe_Inbreeding(p1);\");\n}\n2: late() {\n\tLOG.logRow();\n\tp1.setValue(\"previous_N\", p1.individualCount);\n}\n10000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, integerDiv(L, 2));\n}\n20000 late() {\n\tsim.simulationFinished();\n}\n\nfunction (float)mutTypeFrequency(o<MutationType>$ mutType)\n{\n\tmuts = sim.mutationsOfType(mutType);\n\tif (muts.size() > 0)\n\t\treturn sim.mutationFrequencies(NULL, muts);\n\treturn NULL;\n}\n\nfunction (float)estimateNe_Heterozygosity(o<Subpopulation>$ subpop,\n\t[No<Chromosome>$ chromosome = NULL])\n{\n\tif (isNULL(chromosome))\n\t{\n\t\tif (size(sim.chromosomes) == 1)\n\t\t\tchromosome = sim.chromosomes;\n\t\telse\n\t\t\tstop(\"ERROR: in a multi-chrom model, a chromosome must be supplied.\");\n\t}\n\t\n\thaplosomes = subpop.haplosomesForChromosomes(chromosome, includeNulls=F);\n\tpi = calcHeterozygosity(haplosomes);\n\treturn pi / (4 * MU);\n}\n\nfunction (integer)tabulateFecundity(o<Subpopulation>$ subpop, i$ previous_N)\n{\n\tparentIDs = subpop.individuals.pedigreeParentIDs;\n\trescaledParentIDs = parentIDs - min(parentIDs);\n\treturn tabulate(rescaledParentIDs, previous_N - 1);\n}\n\nfunction (float)estimateNe_Inbreeding(o<Subpopulation>$ subpop)\n{\n\tprevious_N = subpop.getValue(\"previous_N\");\n\tk = tabulateFecundity(subpop, previous_N);\n\treturn (previous_N * mean(k) - 2) / (mean(k) - 1 + var(k) / mean(k));\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.12 - Observing the site frequency spectrum (SFS) during selective sweeps.txt",
    "content": "// Keywords: site frequency spectrum, SFS, population genetics, statistics, custom plotting\n\ninitialize() {\n\tsetSeed(4806519412125461529);\n\tdefineConstant(\"N\", 1000);\n\tdefineConstant(\"L\", 1e7);\n\tdefineConstant(\"MU\", 1e-7);\n\tdefineConstant(\"BINCOUNT\", 100);\n\tinitializeMutationRate(MU);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.5);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(1e-8);\n}\ninitialize() {\n\t// Calculate the expected SFS with the same bins as our observed SFS.\n\t// This is tricky because we need to calculate it for the number of samples\n\t// we have (i.e., number of haplosomes), and then re-bin it; maybe there is\n\t// an easier way.  Note that 10000000 is just a constant large enough to\n\t// avoid rounding artifacts in the final curve; it is basically the number\n\t// of \"mutations\" scattered across the original expected SFS in order to\n\t// re-bin it to the final bin count.  Not sure this math is exactly correct.\n\t// It would be great to have a calcExpectedSFS() function built in; if you\n\t// know how to do that exactly correctly, for counts as well as density,\n\t// then please volunteer!\n\texpected = 1 / (1:(2*N-1));\n\texpected = expected / sum(expected);\n\texpected = asInteger(round(expected * 10000000));\n\tbins = asInteger(round(repEach(1:(2*N-1), expected) * (BINCOUNT / (2*N-1))));\n\ttallies = tabulate(bins, maxbin=BINCOUNT-1);\n\tdefineConstant(\"EXPECTED_SFS\", tallies / sum(tallies));\n}\n1 early() {\n\t// make a subpop and start drifting towards equilibrium\n\tsim.addSubpop(\"p1\", N);\n}\n20*N early() {\n\t// start generating rare m2 sweep mutations\n\tg1.setMutationFractions(c(m1, m2), c(1, 0.000001));\n}\n25*N early() {\n\t// stop generating m2 mutations and allow re-equilibration\n\tg1.setMutationFractions(m1, 1);\n}\n1:(35*N) late() {\n\tupdatePlot();\n}\n\nfunction (void)updatePlot(void)\n{\n\tif (exists(\"slimgui\"))\n\t{\n\t\t// get the empirical population SFS\n\t\tsfs_all = calcSFS(BINCOUNT);\n\t\tsfs_m2 = calcSFS(BINCOUNT, muts=sim.mutationsOfType(m2));\n\t\tx = seq(from=0.0, to=1.0, length=BINCOUNT+1) + 0.5/BINCOUNT;\n\t\tx = x[0:(length(x)-2)];\n\t\t\n\t\t// make a plot of the observed vs. expected SFS\n\t\tplot = slimgui.createPlot(\"Site Frequency Spectrum\",\n\t\t\txrange=c(0,1), yrange=c(0,1),\n\t\t\txlab=\"Mutation frequency\", ylab=\"Density (sqrt-transformed)\");\n\t\t\n\t\tplot.lines(x=x, y=sqrt(sfs_all), color=\"black\", lwd=3);\n\t\tplot.lines(x=x, y=sqrt(EXPECTED_SFS), color=\"chartreuse2\", lwd=2);\n\t\tplot.lines(x=x, y=sqrt(sfs_m2), color=\"red\", lwd=1);\n\t\t\n\t\tplot.addLegend(\"topRight\");\n\t\tplot.legendLineEntry(\"observed\", color=\"black\", lwd=3);\n\t\tplot.legendLineEntry(\"expected\", color=\"chartreuse2\", lwd=2);\n\t\tplot.legendLineEntry(\"m2 (sweeps)\", color=\"red\", lwd=2);\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.2 - Making sweeps conditional on fixation.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\t\n\t\tif (fixed)\n\t\t{\n\t\t\tcat(simID + \": FIXED\\n\");\n\t\t\tsim.simulationFinished();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\t\n\t\t\t// go back to tick 1000\n\t\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\t\n\t\t\t// start a newly seeded run\n\t\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\t\n\t\t\t// re-introduce the sweep mutation\n\t\t\ttarget = sample(p1.haplosomes, 1);\n\t\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.3 - Making sweeps conditional on establishment.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000: late() {\n\tmut = sim.mutationsOfType(m2);\n\t\n\tif (size(mut) == 1)\n\t{\n\t\tif (sim.mutationFrequencies(NULL, mut) > 0.1)\n\t\t{\n\t\t\tcat(simID + \": ESTABLISHED\\n\");\n\t\t\tcommunity.deregisterScriptBlock(self);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcat(simID + \": LOST - RESTARTING\\n\");\n\t\t\n\t\t// go back to tick 1000\n\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\n\t\t// start a newly seeded run\n\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\n\t\t// re-introduce the sweep mutation\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n10000 early() {\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.4 - Partial sweeps.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000:10000 late() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 0)\n\t\tsim.simulationFinished();\n\telse if (mut.selectionCoeff != 0.0)\n\t\tif (sim.mutationFrequencies(NULL, mut) >= 0.5)\n\t\t\tmut.setSelectionCoeff(0.0);\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.5.1 - A soft sweep from recurrent de novo mutations in a large population.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-5);\n\tinitializeMutationType(\"m1\", 0.45, \"f\", 0.5);  // sweep mutation\n\tm1.convertToSubstitution = F;\n\tm1.mutationStackPolicy = \"f\";\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 0);\n\tinitializeRecombinationRate(0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100000);\n}\n1:10000 early() {\n\tcounts = p1.haplosomes.countOfMutationsOfType(m1);\n\tfreq = mean(counts > 0);\n\t\n\tif (freq == 1.0)\n\t{\n\t\tcat(\"\\nTotal mutations: \" + size(sim.mutations) + \"\\n\\n\");\n\t\t\n\t\tfor (mut in sortBy(sim.mutations, \"originTick\"))\n\t\t{\n\t\t\tmutFreq = mean(p1.haplosomes.containsMutations(mut));\n\t\t\tcat(\"Origin \" + mut.originTick + \": \" + mutFreq + \"\\n\");\n\t\t}\n\t\t\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.5.2 - A soft sweep with a fixed de novo mutation schedule.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.45, \"f\", 0.5);   // sweep mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\tp1.tag = 0;  // indicate that a mutation has not yet been seen\n}\n1000:1100 late() {\n\tif (sim.cycle % 10 == 0)\n\t{\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\tif (target.countOfMutationsOfType(m2) == 0)\n\t\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n1:10000 late() {\n\tif (p1.tag != sim.countOfMutationsOfType(m2))\n\t{\n\t\tif (any(sim.substitutions.mutationType == m2)) {\n\t\t\tcat(\"Hard sweep ended in cycle \" + sim.cycle + \"\\n\");\n\t\t\tsim.simulationFinished();\n\t\t} else {\n\t\t\tp1.tag = sim.countOfMutationsOfType(m2);\n\t\t\tcat(\"Cycle \" + sim.cycle + \": \" + p1.tag + \" lineage(s)\\n\");\n\t\t\t\n\t\t\tif ((p1.tag == 0) & (sim.cycle > 1100)) {\n\t\t\t\tcat(\"Sweep failed to establish.\\n\");\n\t\t\t\tsim.simulationFinished();\n\t\t\t}\n\t\t}\n\t}\n\tif (all(p1.haplosomes.countOfMutationsOfType(m2) > 0)) {\n\t\tcat(\"Soft sweep ended in cycle \" + sim.cycle + \"\\n\");\n\t\tcat(\"Frequencies:\\n\");\n\t\tprint(sim.mutationFrequencies(p1, sim.mutationsOfType(m2)));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.5.3 - A soft sweep with a random de novo mutation schedule.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.1, \"f\", 0.5);    // sweep mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tgens = cumSum(rpois(10, 10));      // make a vector of start gens\n\tgens = gens + (1000 - min(gens));  // align to start at 1000\n\tdefineConstant(\"Z\", max(gens));    // remember the last gen\n\tdefineConstant(\"ADD_GENS\", gens);  // schedule the add events\n}\nADD_GENS late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tmut = sim.mutationsOfType(m2);\n\tif (mut.size() > 0)\n\t\ttarget.addMutations(mut);\n\telse\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1:10000 late() {\n\tif (any(sim.substitutions.mutationType == m2))\n\t{\n\t\tcatn(\"Sweep completed in cycle \" + sim.cycle + \".\");\n\t\tsim.simulationFinished();\n\t}\n\telse if ((sim.countOfMutationsOfType(m2) == 0) & (sim.cycle > Z))\n\t{\n\t\tcatn(\"Soft sweep failed to establish.\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.6.1 - A sweep from standing variation at a random locus.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\tmuts = sim.mutations;\n\tmuts = muts[sim.mutationFrequencies(p1, muts) > 0.1];\n\t\n\tif (size(muts))\n\t{\n\t\tmut = sample(muts, 1);\n\t\tmut.setSelectionCoeff(0.5);\n\t}\n\telse\n\t{\n\t\tcat(\"No contender of sufficient frequency found.\\n\");\n\t}\n}\n1000:10000 late() {\n\tif (sum(sim.mutations.selectionCoeff) == 0.0)\n\t{\n\t\tif (sum(sim.substitutions.selectionCoeff) == 0.0)\n\t\t\tcat(\"Sweep mutation lost in cycle \" + sim.cycle + \"\\n\");\n\t\telse\n\t\t\tcat(\"Sweep mutation reached fixation.\\n\");\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.6.2 - A sweep from standing variation at a predetermined locus.txt",
    "content": "// Keywords: conditional sweep\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.0);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\t// save this run's identifier, used to save and restore\n\tdefineConstant(\"simID\", getSeed());\n\t\n\tsim.addSubpop(\"p1\", 500);\n}\n1000 late() {\n\t// save the state of the simulation\n\tsim.outputFull(tempdir() + \"slim_\" + simID + \".txt\");\n\t\n\t// introduce the sweep mutation\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n1000: late() {\n\tmut = sim.mutationsOfType(m2);\n\t\n\tif (size(mut) == 1)\n\t{\n\t\tif (sim.mutationFrequencies(NULL, mut) > 0.1)\n\t\t{\n\t\t\tcat(simID + \": ESTABLISHED - CONVERTING TO BENEFICIAL\\n\");\n\t\t\tmut.setSelectionCoeff(0.5);\n\t\t\tcommunity.deregisterScriptBlock(self);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcat(simID + \": LOST BEFORE ESTABLISHMENT - RESTARTING\\n\");\n\t\t\n\t\t// go back to tick 1000\n\t\tsim.readFromPopulationFile(tempdir() + \"slim_\" + simID + \".txt\");\n\t\t\n\t\t// start a newly seeded run\n\t\tsetSeed(rdunif(1, 0, asInteger(2^62) - 1));\n\t\t\n\t\t// re-introduce the sweep mutation\n\t\ttarget = sample(p1.haplosomes, 1);\n\t\ttarget.addNewDrawnMutation(m2, 10000);\n\t}\n}\n1000:10000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(simID + ifelse(fixed, \": FIXED\\n\", \": LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.7 - Adaptive introgression.txt",
    "content": "// Keywords: migration, dispersal\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);    // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsubpopCount = 10;\n\tfor (i in 1:subpopCount)\n\t\tsim.addSubpop(i, 500);\n\tfor (i in 2:subpopCount)\n\t\tsim.subpopulations[i-1].setMigrationRates(i-1, 0.01);\n\tfor (i in 1:(subpopCount-1))\n\t\tsim.subpopulations[i-1].setMigrationRates(i+1, 0.2);\n}\n100 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\ttarget.addNewDrawnMutation(m2, 10000);\n}\n100:100000 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = (sum(sim.substitutions.mutationType == m2) == 1);\n\t\tcat(ifelse(fixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.8 - Fixation probabilities under Hill-Robertson interference.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.05);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 1000);\n}\n6000 late() {\n\t// Calculate the fixation probability for a beneficial mutation\n\ts = 0.05;\n\tN = 1000;\n\tp_fix = (1 - exp(-2 * s)) / (1 - exp(-4 * N * s));\n\t\n\t// Calculate the expected number of fixed mutations\n\tn_gens = 1000;  // first 5000 ticks were burn-in\n\tmu = 1e-6;\n\tlocus_size = 100000;\n\texpected = mu * locus_size * n_gens * 2 * N * p_fix;\n\t\n\t// Figure out the actual number of fixations after burn-in\n\tsubs = sim.substitutions;\n\tactual = sum(subs.fixationTick >= 5000);\n\t\n\t// Print a summary of our findings\n\tcat(\"P(fix) = \" + p_fix + \"\\n\");\n\tcat(\"Expected fixations: \" + expected + \"\\n\");\n\tcat(\"Actual fixations: \" + actual + \"\\n\");\n\tcat(\"Ratio, actual/expected: \" + (actual/expected) + \"\\n\");\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/Recipe 9.9 - Keeping a reference to a sweep mutation.txt",
    "content": "// Keywords: \n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 1.0, \"f\", 0.5);  // introduced mutation\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 500); }\n1000 late() {\n\ttarget = sample(p1.haplosomes, 1);\n\tmut = target.addNewDrawnMutation(m2, 10000);\n\tdefineConstant(\"SWEEP\", mut);\n}\n1000:100000 late() {\n\tif (!SWEEP.isSegregating)\n\t{\n\t\tcat(ifelse(SWEEP.isFixed, \"FIXED\\n\", \"LOST\\n\"));\n\t\tsim.simulationFinished();\n\t}\n}\n"
  },
  {
    "path": "SLiMgui/Recipes/_README.txt",
    "content": "These recipes are all taken directly from SLiM's manual:\n\nHaller, B.C., and Messer, P.W. (2016). SLiM: An Evolutionary Simulation Framework.\n\nSLiM's manual contains full explanations of each recipe, in the corresponding section; please refer to it for further information.  These recipes are provided as separate files for convenience, particularly since copy-paste from the PDF manual often works poorly (but note that SLiMgui now allows you to open these recipes directly from the File menu, also, via the Open Recipe submenu).\n\n--------------------------------------------------------------\n\nThese recipes were all created by Ben Haller, except recipe 5.4, created by Aaron Sams and Chase W. Nelson.\n\nAll recipes are copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\nThey are products of the Messer Lab, http://messerlab.org/slim/\n\nAll of these recipes are a part of SLiM.\n\nSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n--------------------------------------------------------------\n\nThe file Comeron_100kb_chr2L.txt provided here is part of the supplemental data from the paper:\n\nComeron, J.M., Ratnappan, R., and Bailin, S. (2012). The many landscapes of recombination in Drosophila melanogaster. PLoS Genetics 8(10), e1002905.\n\nThis data file is used by recipe 6.1.2.\n\n--------------------------------------------------------------\n\nFor further information, please feel free to contact us:\n\nhttp://messerlab.org/slim/\n\nBen Haller, bhaller@benhaller.com\nPhilipp Messer, philipp.messer@gmail.com\n"
  },
  {
    "path": "SLiMgui/SLiMDocument.h",
    "content": "//\n//  SLiMDocument.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/31/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n@class SLiMWindowController;\n\n\n@interface SLiMDocument : NSDocument\n{\n\t// This is our model, effectively.  We don't really follow MVC very closely at all.  When we are getting created, we have to use\n\t// this ivar to save our model state temporarily, because a SLiMWindowController is not yet created for us to stuff the model\n\t// into.  That is the only time we use this ivar, though; once the controller is created, it keeps the model for us.  Not the\n\t// most elegant design; probably a bunch of stuff should move from SLiMWindowController over to here.\n\tNSString *documentScriptString;\n\t\n\t// Change count tracking relative to our last recycle (which is change count 0)\n\tint slimChangeCount;\n\t\n\t// Transient document support\n\tBOOL transient;\n}\n\n@property (retain, nonatomic) NSString *recipeName;\n\n+ (NSString *)defaultWFScriptString;\n+ (NSString *)defaultNonWFScriptString;\n\n- (NSString *)documentScriptString;\n- (void)setDocumentScriptString:(NSString *)newString;\n\n- (SLiMWindowController *)slimWindowController;\n\n- (BOOL)changedSinceRecycle;\n- (void)resetSLiMChangeCount;\n\n// Transient documents\n- (BOOL)isTransient;\n- (void)setTransient:(BOOL)flag;\n- (BOOL)isTransientAndCanBeReplaced;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMDocument.mm",
    "content": "//\n//  SLiMDocument.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/31/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMDocument.h\"\n#import \"SLiMWindowController.h\"\n#import \"SLiMDocumentController.h\"\n\n\n@implementation SLiMDocument\n\n+ (NSString *)defaultWFScriptString\n{\n\tstatic NSString *str = @\"// set up a simple neutral simulation\\n\"\n\t\"initialize() {\\n\"\n\t\"\tinitializeMutationRate(1e-7);\\n\"\n\t\"\t\\n\"\n\t\"\t// m1 mutation type: neutral\\n\"\n\t\"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n\t\"\t\\n\"\n\t\"\t// g1 genomic element type: uses m1 for all mutations\\n\"\n\t\"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n\t\"\t\\n\"\n\t\"\t// uniform chromosome of length 100 kb with uniform recombination\\n\"\n\t\"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n\t\"\tinitializeRecombinationRate(1e-8);\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// create a population of 500 individuals\\n\"\n\t\"1 early() {\\n\"\n\t\"\tsim.addSubpop(\\\"p1\\\", 500);\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// output samples of 10 haplosomes periodically, all fixed mutations at end\\n\"\n\t\"1000 late() { p1.outputSample(10); }\\n\"\n\t\"2000 late() { p1.outputSample(10); }\\n\"\n\t\"2000 late() { sim.outputFixedMutations(); }\\n\";\n\t\n\treturn str;\n}\n\n+ (NSString *)defaultNonWFScriptString\n{\n\tstatic NSString *str = @\"// set up a simple neutral nonWF simulation\\n\"\n\t\"initialize() {\\n\"\n\t\"\tinitializeSLiMModelType(\\\"nonWF\\\");\\n\"\n\t\"\tdefineConstant(\\\"K\\\", 500);\t// carrying capacity\\n\"\n\t\"\t\\n\"\n\t\"\t// neutral mutations, which are allowed to fix\\n\"\n\t\"\tinitializeMutationType(\\\"m1\\\", 0.5, \\\"f\\\", 0.0);\\n\"\n\t\"\tm1.convertToSubstitution = T;\\n\"\n\t\"\t\\n\"\n\t\"\tinitializeGenomicElementType(\\\"g1\\\", m1, 1.0);\\n\"\n\t\"\tinitializeGenomicElement(g1, 0, 99999);\\n\"\n\t\"\tinitializeMutationRate(1e-7);\\n\"\n\t\"\tinitializeRecombinationRate(1e-8);\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// each individual reproduces itself once\\n\"\n\t\"reproduction() {\\n\"\n\t\"\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1));\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// create an initial population of 10 individuals\\n\"\n\t\"1 early() {\\n\"\n\t\"\tsim.addSubpop(\\\"p1\\\", 10);\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// provide density-dependent selection\\n\"\n\t\"early() {\\n\"\n\t\"\tp1.fitnessScaling = K / p1.individualCount;\\n\"\n\t\"}\\n\"\n\t\"\\n\"\n\t\"// output all fixed mutations at end\\n\"\n\t\"2000 late() { sim.outputFixedMutations(); }\\n\";\n\t\n\treturn str;\n}\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\t//[[self undoManager] disableUndoRegistration];\n\t\t\n\t\tif ([(SLiMDocumentController *)[NSDocumentController sharedDocumentController] creatingNonWFDocument])\n\t\t\tdocumentScriptString = [[SLiMDocument defaultNonWFScriptString] retain];\n\t\telse\n\t\t\tdocumentScriptString = [[SLiMDocument defaultWFScriptString] retain];\n\t\t\n\t\t//[[self undoManager] enableUndoRegistration];\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t//NSLog(@\"[SLiMDocument dealloc]\");\n\t\n\t[documentScriptString release];\n\tdocumentScriptString = nil;\n\t\n\t[self setRecipeName:nil];\n\t\n\t[super dealloc];\n}\n\n- (NSString *)documentScriptString\n{\n\treturn documentScriptString;\n}\n\n- (SLiMWindowController *)slimWindowController\n{\n\tNSArray *controllers = [self windowControllers];\n\t\n\tif ([controllers count] > 0)\n\t{\n\t\tNSWindowController *mainController = [controllers objectAtIndex:0];\n\t\t\n\t\tif ([mainController isKindOfClass:[SLiMWindowController class]])\n\t\t\treturn (SLiMWindowController *)mainController;\n\t}\n\t\n\treturn nil;\n}\n\n- (void)makeWindowControllers\n{\n\tNSArray *myControllers = [self windowControllers];\n\t\n\t// If this document displaced a transient document, it will already have been assigned\n\t// a window controller. If that is not the case, create one.\n\tif ([myControllers count] == 0)\n\t{\n\t\tSLiMWindowController *controller = [[[SLiMWindowController alloc] init] autorelease];\n\t\t\n\t\t[controller setShouldCloseDocument:YES];\n\t\t[self addWindowController:controller];\n\t}\n}\n\n- (void)windowControllerDidLoadNib:(NSWindowController *)aController\n{\n\t// Note this method is not called, because we override -makeWindowControllers\n    [super windowControllerDidLoadNib:aController];\n}\n\n- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError\n{\n\tif ([typeName isEqualToString:@\"edu.messerlab.slim\"])\n\t{\n\t\tSLiMWindowController *controller = [[self windowControllers] objectAtIndex:0];\n\t\tNSString *curScriptString = [controller->scriptTextView string];\n\t\tNSData *data = [curScriptString dataUsingEncoding:NSUTF8StringEncoding];\n\t\t\n\t\tif (!data && outError)\n\t\t\t*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileWriteInapplicableStringEncodingError userInfo:@{ NSLocalizedDescriptionKey : @\"The script could not be converted to UTF-8 encoding.\"}];\n\t\t\n\t\t[controller->scriptTextView breakUndoCoalescing];\n\t\t\n\t\treturn data;\n\t}\n\t\n    if (outError)\n        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:nil];\n\t\n    return nil;\n}\n\n- (void)setDocumentScriptString:(NSString *)newString\n{\n\t[newString retain];\n\t[documentScriptString release];\n\tdocumentScriptString = newString;\n\t\n\tSLiMWindowController *mainController = [self slimWindowController];\n\t\n\tif (mainController)\n\t{\n\t\t[mainController->scriptTextView setString:newString];\n\t\t[mainController->scriptTextView recolorAfterChanges];\n\t\t[mainController recycle:nil];\n\t}\n}\n\n- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError\n{\n\tif ([typeName isEqualToString:@\"edu.messerlab.slim\"])\n\t{\n\t\tNSString *scriptString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];\n\t\tBOOL lossy = false;\n\t\t\n\t\tif (!scriptString)\n\t\t\t[NSString stringEncodingForData:data encodingOptions:@{NSStringEncodingDetectionSuggestedEncodingsKey: @[[NSNumber numberWithUnsignedInt:NSUTF8StringEncoding], [NSNumber numberWithUnsignedInt:NSUTF16StringEncoding], [NSNumber numberWithUnsignedInt:NSASCIIStringEncoding], [NSNumber numberWithUnsignedInt:NSISOLatin1StringEncoding]]} convertedString:&scriptString usedLossyConversion:&lossy];\n\t\t\n\t\t[self setDocumentScriptString:scriptString];\n\t\t\n\t\treturn YES;\n\t}\n\telse if ([typeName isEqualToString:@\"public.plain-text\"])\n\t{\n\t\tNSString *scriptString = nil;\n\t\tBOOL lossy = false;\n\t\t\n\t\t[NSString stringEncodingForData:data encodingOptions:@{NSStringEncodingDetectionSuggestedEncodingsKey: @[[NSNumber numberWithUnsignedInt:NSUTF8StringEncoding], [NSNumber numberWithUnsignedInt:NSUTF16StringEncoding], [NSNumber numberWithUnsignedInt:NSASCIIStringEncoding], [NSNumber numberWithUnsignedInt:NSISOLatin1StringEncoding]]} convertedString:&scriptString usedLossyConversion:&lossy];\n\t\t\n\t\t[self setDocumentScriptString:scriptString];\n\t\t\n\t\treturn YES;\n\t}\n\t\n    if (outError) {\n        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:nil];\n    }\n    return NO;\n}\n\n- (BOOL)prepareSavePanel:(NSSavePanel *)savePanel\n{\n\t[savePanel setTitle:@\"Save Script\"];\n\t[savePanel setMessage:@\"Save the simulation script to a file:\"];\n\t[savePanel setExtensionHidden:NO];\n\t[savePanel setCanSelectHiddenExtension:NO];\n\t\n\treturn YES;\n}\n\n// Do our own tracking of the change count.  We do this so that we know whether the script is in\n// the same state it was in when we last recycled, or has been changed.  If it has been changed,\n// we add a highlight under the recycle button to suggest to the user that they might want to\n// recycle to bring their changes into force.\n- (void)updateChangeCount:(NSDocumentChangeType)change\n{\n\t// When a document is changed, it ceases to be transient.\n\t[self setTransient:NO];\n\t\n\t[super updateChangeCount:change];\n\t\n\t// Mask off flags in the high bits.  Apple is not explicit about this, but NSChangeDiscardable\n\t// is 256, and acts as a flag bit, so it seems reasonable to assume this for future compatibility.\n\tNSDocumentChangeType maskedChange = (NSDocumentChangeType)(change & 0x00FF);\n\t\n\tif ((maskedChange == NSChangeDone) || (maskedChange == NSChangeRedone))\n\t\tslimChangeCount++;\n\telse if (maskedChange == NSChangeUndone)\n\t\tslimChangeCount--;\n\t\n\t[[self slimWindowController] updateRecycleHighlightForChangeCount:slimChangeCount];\n}\n\n- (BOOL)changedSinceRecycle\n{\n\treturn !(slimChangeCount == 0);\n}\n\n- (void)resetSLiMChangeCount\n{\n\tslimChangeCount = 0;\n\t\n\t[[self slimWindowController] updateRecycleHighlightForChangeCount:slimChangeCount];\n}\n\n\n// Transient document support: adapted from TextEdit.  A transient document is an untitled document that\n// was opened automatically. If a real document is opened before the transient document is edited, the\n// real document should replace the transient. If a transient document is edited, it ceases to be transient. \n\n- (BOOL)isTransient\n{\n\treturn transient;\n}\n\n- (void)setTransient:(BOOL)flag\n{\n\ttransient = flag;\n}\n\n- (BOOL)isTransientAndCanBeReplaced\n{\n\tif (![self isTransient])\n\t\treturn NO;\n\t\n\t// We can't replace transient document that have sheets on them.\n\tfor (NSWindowController *controller in [self windowControllers])\n\t\tif ([[controller window] attachedSheet])\n\t\t\treturn NO;\n\t\n\treturn YES;\n}\n\n\n// Opt out of all of Apple's autosaving, versioning, etc.  Partly because I dislike those features,\n// partly because I don't want a user's model to be saved until they explicitly save since\n// modeling often involves a lot of trial and error, partly because I'm not sure how versioning\n// in OS X interacts with sharing files with Linux.\n\n+ (BOOL)autosavesInPlace\n{\n    return NO;\n}\n\n+ (BOOL)autosavesDrafts\n{\n\treturn NO;\n}\n\n+ (BOOL)preservesVersions\n{\n\treturn NO;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMDocumentController.h",
    "content": "//\n//  SLiMDocumentController.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/2/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n// This class provides some additional functionality to support transient documents.  It is instantiated in MainMenu.xib,\n// and thus becomes the shared document controller for the app.\n\n\n@class SLiMDocument;\n\n\n@interface SLiMDocumentController : NSDocumentController\n{\n}\n\n@property (nonatomic) BOOL creatingNonWFDocument;\t\t// a flag set across newNonWFDocument: to signal that the new document is a nonWF document, not a WF document\n\n- (SLiMDocument *)transientDocumentToReplace;\n- (void)replaceTransientDocument:(NSArray *)documents;\n\n- (void)openRecipeWithFilename:(NSString *)filename;\n\n- (IBAction)newNonWFDocument:(id)sender;\n- (IBAction)findRecipe:(id)sender;\n- (IBAction)openRecipe:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMDocumentController.mm",
    "content": "//\n//  SLiMDocumentController.m\n//  SLiM\n//\n//  Created by Ben Haller on 2/2/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMDocumentController.h\"\n#import \"SLiMDocument.h\"\n#import \"SLiMPDFDocument.h\"\n#import \"FindRecipeController.h\"\n#import \"CocoaExtra.h\"\n\n\n@implementation SLiMDocumentController\n\n- (SLiMDocument *)transientDocumentToReplace\n{\n\tNSArray *documents = [self documents];\n\t\n\tif ([documents count] == 1)\n\t{\n\t\tNSDocument *firstDoc = [documents objectAtIndex:0];\n\t\t\n\t\tif ([firstDoc isKindOfClass:[SLiMDocument class]])\n\t\t{\n\t\t\tSLiMDocument *slimDoc = (SLiMDocument *)firstDoc;\n\t\t\t\n\t\t\tif ([slimDoc isTransientAndCanBeReplaced])\n\t\t\t\treturn slimDoc;\n\t\t}\n\t}\n\t\n\treturn nil;\n}\n\n- (void)replaceTransientDocument:(NSArray *)documents\n{\n\tSLiMDocument *transientDoc = [documents objectAtIndex:0], *doc = [documents objectAtIndex:1];\n\t\n\tNSArray *controllersToTransfer = [[transientDoc windowControllers] copy];\n\tNSEnumerator *controllerEnum = [controllersToTransfer objectEnumerator];\n\tNSWindowController *controller;\n\t\n\t[controllersToTransfer makeObjectsPerformSelector:@selector(retain)];\n\t\n\twhile (controller = [controllerEnum nextObject])\n\t{\n\t\t[doc addWindowController:controller];\n\t\t[transientDoc removeWindowController:controller];\n\t}\n\t[transientDoc close];\n\t\n\t[controllersToTransfer makeObjectsPerformSelector:@selector(release)];\n\t[controllersToTransfer release];\n\t\n\t// Push the model into the new doc again, so that it gets flushed out to the window controller that really manages it\n\t[doc setDocumentScriptString:[doc documentScriptString]];\n}\n\n// When a document is opened, check to see whether there is a document that is already open, and whether it is transient.\n// If so, transfer the document's window controllers and close the transient document.\n- (void)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument completionHandler:(nonnull void (^)(NSDocument * _Nullable, BOOL, NSError * _Nullable))completionHandler\n{\n\tSLiMDocument *transientDoc = [self transientDocumentToReplace];\n\t\n\tif (transientDoc)\n\t{\n\t\t// Defer display so we can replace the transient document first.  We have to have our own handler to intercept the result,\n\t\t// process it, and then call our caller's completion handler.\n\t\t[super openDocumentWithContentsOfURL:absoluteURL display:NO completionHandler:(^ void (NSDocument *typelessDoc, BOOL already_open, NSError *error)\n\t\t{\n\t\t\tif (typelessDoc)\n\t\t\t{\n\t\t\t\tif ([typelessDoc isKindOfClass:[SLiMDocument class]])\n\t\t\t\t{\n\t\t\t\t\tSLiMDocument *doc = (SLiMDocument *)typelessDoc;\n\t\t\t\t\t\n\t\t\t\t\t[self replaceTransientDocument:[NSArray arrayWithObjects:transientDoc, doc, nil]];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (displayDocument)\n\t\t\t\t{\n\t\t\t\t\t[typelessDoc makeWindowControllers];\n\t\t\t\t\t[typelessDoc showWindows];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tcompletionHandler(typelessDoc, NO, error);\n\t\t})];\n\t}\n\telse\n\t{\n\t\t[super openDocumentWithContentsOfURL:absoluteURL display:displayDocument completionHandler:completionHandler];\n\t}\n}\n\n- (IBAction)newNonWFDocument:(id)sender\n{\n\t@try {\n\t\t_creatingNonWFDocument = YES;\n\t\t\n\t\t[self newDocument:sender];\n\t}\n\t@finally\n\t{\n\t\t_creatingNonWFDocument = NO;\n\t}\n}\n\n- (IBAction)findRecipe:(id)sender\n{\n\t[FindRecipeController runFindRecipesPanel];\n}\n\n- (void)openRecipeWithFilename:(NSString *)filename\n{\n\tif ([[filename pathExtension] isEqualToString:@\"py\"])\n\t{\n\t\tNSBundle *bundle = [NSBundle mainBundle];\n\t\tNSURL *urlForRecipe = [bundle URLForResource:[filename stringByDeletingPathExtension] withExtension:[filename pathExtension] subdirectory:@\"Recipes\"];\n\t\t\n\t\tif (urlForRecipe)\n\t\t{\n\t\t\t// Duplicate the file into /tmp; there seems to be no protection against the user modifying files inside the app bundle!\n\t\t\t// Setting the stationery bit wouldn't work either, I guess; I guess it would create a duplicate file inside the app bundle :-O\n\t\t\t// This all seems pretty broken; maybe it's because I'm running under Xcode, but I want it to behave right even in that case.\n\t\t\t// This at least prevents the user from seeing/modifying the file inside the app bundle, but it will have a weird name/path.\n\t\t\tNSFileManager *fm = [NSFileManager defaultManager];\n\t\t\tNSString *tempPath = [NSString slimPathForTemporaryFileWithPrefix:[filename stringByDeletingPathExtension]];\n\t\t\tNSString *tempFile = [tempPath stringByAppendingPathExtension:@\"py\"];\n\t\t\t\n\t\t\t[fm copyItemAtPath:[urlForRecipe path] toPath:tempFile error:NULL];\n\t\t\t\n\t\t\t// Then open Python files in whatever app the user has set up for that\n\t\t\t[[NSWorkspace sharedWorkspace] openFile:tempFile];\n\t\t}\n\t}\n\telse if ([[filename pathExtension] isEqualToString:@\"txt\"])\n\t{\n\t\tNSBundle *bundle = [NSBundle mainBundle];\n\t\tNSURL *urlForRecipe = [bundle URLForResource:[filename stringByDeletingPathExtension] withExtension:[filename pathExtension] subdirectory:@\"Recipes\"];\n\t\t\n\t\tif (urlForRecipe)\n\t\t{\n\t\t\tNSString *scriptString = [NSString stringWithContentsOfURL:urlForRecipe usedEncoding:NULL error:NULL];\n\t\t\t\n\t\t\tif (scriptString)\n\t\t\t{\n\t\t\t\tSLiMDocument *transientDoc = [self transientDocumentToReplace];\n\t\t\t\tNSDocument *typelessDoc = [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:NO error:NULL];\n\t\t\t\t\n\t\t\t\tif (typelessDoc && [typelessDoc isKindOfClass:[SLiMDocument class]])\n\t\t\t\t{\n\t\t\t\t\tSLiMDocument *doc = (SLiMDocument *)typelessDoc;\n\t\t\t\t\t\n\t\t\t\t\tif (transientDoc)\n\t\t\t\t\t\t[self replaceTransientDocument:[NSArray arrayWithObjects:transientDoc, doc, nil]];\n\t\t\t\t\t\n\t\t\t\t\t[doc makeWindowControllers];\n\t\t\t\t\t[doc showWindows];\n\t\t\t\t\t\n\t\t\t\t\t[doc setDocumentScriptString:scriptString];\n\t\t\t\t\t\n\t\t\t\t\tNSString *recipeName = [filename stringByDeletingPathExtension];\n\t\t\t\t\t\n\t\t\t\t\tif ([recipeName hasPrefix:@\"Recipe \"])\n\t\t\t\t\t\trecipeName = [recipeName substringFromIndex:7];\n\t\t\t\t\t\n\t\t\t\t\t[doc setRecipeName:recipeName];\t\t\t// tell the doc it's a recipe doc, so it can manage its title properly\n\t\t\t\t\t[[doc slimWindowController] synchronizeWindowTitleWithDocumentName];\t// remake the window title\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tNSLog(@\"Unrecognized recipe extension %@\", [filename pathExtension]);\n\t\tNSBeep();\n\t}\n}\n\n- (IBAction)openRecipe:(id)sender\n{\n\tNSMenuItem *senderMenuItem = (NSMenuItem *)sender;\n\tNSString *recipeName = [senderMenuItem title];\n\t\n\tif ([recipeName hasSuffix:@\".py 🐍\"])\n\t{\n\t\tNSString *trimmedRecipeName = [recipeName stringByReplacingOccurrencesOfString:@\" 🐍\" withString:@\"\"];\n\t\tNSString *fullRecipeName = [NSString stringWithFormat:@\"Recipe %@\", trimmedRecipeName];\n\t\t\n\t\t[self openRecipeWithFilename:fullRecipeName];\n\t}\n\telse\n\t{\n\t\tNSString *fullRecipeName = [[NSString stringWithFormat:@\"Recipe %@\", recipeName] stringByAppendingPathExtension:@\"txt\"];\n\t\t\n\t\t[self openRecipeWithFilename:fullRecipeName];\n\t}\n}\n\n// When a second document is added, the first document's transient status is cleared.\n// This happens when the user selects \"New\" when a transient document already exists.\n- (void)addDocument:(NSDocument *)newDoc\n{\n\tNSArray *documents = [self documents];\n\t\n\tif ([documents count] == 1)\n\t{\n\t\tNSDocument *firstDoc = [documents objectAtIndex:0];\n\t\t\n\t\tif ([firstDoc isKindOfClass:[SLiMDocument class]])\n\t\t{\n\t\t\tSLiMDocument *slimDoc = (SLiMDocument *)firstDoc;\n\t\t\t\n\t\t\tif ([slimDoc isTransient])\n\t\t\t\t[slimDoc setTransient:NO];\n\t\t}\n\t}\n\t\n\t[super addDocument:newDoc];\n}\n\n- (void)noteNewRecentDocument:(NSDocument *)document\n{\n\t// prevent PDF documents from being added to the recent documents list\n\tif ([document isKindOfClass:[SLiMPDFDocument class]])\n\t\treturn;\n\t\n\t[super noteNewRecentDocument:document];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMHelpCallbacks.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2709\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Italic;\\f1\\fnil\\fcharset0 Menlo-Italic;\\f2\\fswiss\\fcharset0 Optima-Regular;\n\\f3\\fnil\\fcharset0 Menlo-Regular;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;\\red28\\green0\\blue207;\\red63\\green110\\blue116;\n\\red20\\green0\\blue196;\\red181\\green0\\blue19;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;\\cssrgb\\c15223\\c16313\\c84844;\\cssrgb\\c30795\\c50445\\c52970;\n\\cssrgb\\c10980\\c0\\c81176;\\cssrgb\\c76863\\c10196\\c8627;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i\\fs22 \\cf0 5.13.0  ITEM: 1. \n\\f1\\fs18 initialize()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 Before a SLiM simulation can be run, the various classes underlying the simulation need to be set up with an initial configuration.  Simulation configuration in SLiM is done in \n\\f1\\i\\fs18 initialize()\n\\f0\\fs22  callbacks\n\\f2\\i0  that run prior to the beginning of simulation execution.  For our present purposes, the idea is very simple; in your input file, you can write something like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 initialize()\\uc0\\u8232 \\{\\u8232 \t...\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 initialize()\n\\f2\\fs22  declaration specifies that the script block is to be executed as an \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback before the simulation starts.  The script between the braces \n\\f3\\fs18 \\{\\}\n\\f2\\fs22  would set up various aspects of the simulation by calling \n\\f0\\i initialization functions\n\\f2\\i0 .  These are SLiM functions that may be called only in an \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback, and their names begin with \n\\f3\\fs18 initialize\n\\f2\\fs22  to mark them clearly as such.  You may also use other Eidos functionality in these callbacks; for example, you might automate generating a complex genetic structure containing many genes by using a \n\\f3\\fs18 for\n\\f2\\fs22  loop.\\\nIn general, it is required for a species to set up its genetic structure in an \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback with calls to \n\\f3\\fs18 initializeMutationRate()\n\\f2\\fs22 , \n\\f3\\fs18 initializeRecombinationRate()\n\\f2\\fs22 , \n\\f3\\fs18 initializeMutationType()\n\\f2\\fs22 , \n\\f3\\fs18 initializeGenomicElementType()\n\\f2\\fs22 , and \n\\f3\\fs18 initializeGenomicElement()\n\\f2\\fs22 ; species must call all of these, setting up at least one mutation type, at least one genomic element type, and at least one genomic element.  The exception to this general rule is for species that have no genetics at all \\'96 species that are modeled purely on an ecological/behavioral level.  Such species may be defined by calling \n\\f0\\i none\n\\f2\\i0  of those initialization functions; in this case, SLiM will default to a zero-length chromosome with mutation and recombination rates of zero.  A middle ground between these two configuration paths is not allowed; either a species has no genetics, or it fully defines its genetics.\\\nOne thing worth mentioning is that in the context of an \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback, the \n\\f3\\fs18 sim\n\\f2\\fs22  global representing the species being simulated is not defined.  This is because the state of the simulation is not yet constructed fully, and accessing partially constructed state would not be safe.  (Similarly, in multispecies models, the \n\\f3\\fs18 community\n\\f2\\fs22  object and the objects representing individual species are not yet defined.)\\\nThe above \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback syntax \n\\f0\\i implicitly\n\\f2\\i0  declares a single species, with the default name of \n\\f3\\fs18 sim\n\\f2\\fs22 , and therefore sets up a single-species model.  It is also possible to \n\\f0\\i explicitly\n\\f2\\i0  declare a species, which is done with this extended syntax (using a species name of \n\\f3\\fs18 fox\n\\f2\\fs22  as an example):\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 species fox initialize() \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 This sets up a multispecies model (although it might, in fact, declare only a single species, \n\\f3\\fs18 fox\n\\f2\\fs22 ; the term \\'93multispecies\\'94, in SLiM parlance, really means \\'93explicitly declared species\\'94, but multispecies models almost always \n\\f0\\i do\n\\f2\\i0  contain multiple species, so the distinction is unimportant).  In most respects multispecies models work identically to single-species models, so we will tend to focus on the single-species case in the reference documentation, with a species name of \n\\f3\\fs18 sim\n\\f2\\fs22 , for simplicity and clarity.\\\nIn single-species models all initialization can be done in a single \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback (or you can have more than one, if you wish).  In multispecies models, each species must be initialized with its own callback(s), as shown above.  In addition, multispecies models also support an optional community-level initialization callback that is declared as follows:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 species all initialize() \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 These callbacks, technically called \n\\f0\\i non-species-specific \n\\f1\\fs18 initialize()\n\\f0\\fs22  callbacks\n\\f2\\i0 , provide a place for community-level initialization to occur.  They are run before any species-specific \n\\f3\\fs18 initialize()\n\\f2\\fs22  callbacks are run, so you might wish to set up all of your model parameters in one, providing a single location for all parameters.  In multispecies models, the \n\\f3\\fs18 initializeModelType()\n\\f2\\fs22  and \n\\f3\\fs18 initializeInteractionType()\n\\f2\\fs22  functions may only be called from a non-species-specific \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback, since those aspects of model configuration span the entire community.  In single-species models, these functions may be called from an ordinary \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback for simplicity and backward compatibility.\\\nOnce all \n\\f3\\fs18 initialize()\n\\f2\\fs22  callbacks have executed, in the order in which they are specified in the SLiM input file, the simulation will begin.  The tick number at which it starts is determined by the Eidos events you have defined; the first tick in which an Eidos event is scheduled to execute is the tick at which the simulation starts.  Similarly, the simulation will terminate after the last tick for which a script block (either an event or a callback) is registered to execute, unless the \n\\f3\\fs18 stop()\n\\f2\\fs22  function or the \n\\f3\\fs18 simulationFinished()\n\\f2\\fs22  method of \n\\f3\\fs18 Community\n\\f2\\fs22  or \n\\f3\\fs18 Species\n\\f2\\fs22  are called to end the simulation earlier.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 5.13.1  ITEM: 2. Eidos events\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 An Eidos event is a block of Eidos code that is executed every tick, within a tick range, to perform a desired task.  The syntax of an Eidos event declaration looks like one of these:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] first() \\{ ... \\}\\uc0\\u8232 [id] [t1 [: t2]] early() \\{ ... \\}\\u8232 [id] [t1 [: t2]] late() \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The first declaration declares a \n\\f3\\fs18 first()\n\\f2\\fs22  event that executes first thing in the tick cycle.  The second declaration declares an \n\\f3\\fs18 early()\n\\f2\\fs22  event that executes relatively early in the tick cycle.  The third declaration declares a \n\\f3\\fs18 late()\n\\f2\\fs22  event that executes near the end of the tick cycle.  Exactly when these events run depends upon whether the model is a WF model or a nonWF model; see the tick cycle diagrams for those model types.\\\nThe \n\\f3\\fs18 id\n\\f2\\fs22  is an optional identifier like \n\\f3\\fs18 s1\n\\f2\\fs22  (or more generally, \n\\f3\\fs18 sX\n\\f2\\fs22 , where \n\\f3\\fs18 X\n\\f2\\fs22  is an integer greater than or equal to \n\\f3\\fs18 0\n\\f2\\fs22 ) that defines an identifier that can be used to refer to the script block.  In most situations it can be omitted, in which case the \n\\f3\\fs18 id\n\\f2\\fs22  is implicitly defined as \n\\f3\\fs18 -1\n\\f2\\fs22 , a placeholder value that essentially represents the lack of an identifier value.  Supplying an \n\\f3\\fs18 id\n\\f2\\fs22  is only useful if you wish to manipulate your script blocks programmatically.\\\nThen comes a tick or a range of ticks, and then a block of Eidos code enclosed in braces to form a compound statement.  A trivial example might look like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf3 1000\\cf2 :\\cf3 5000\\cf2  early() \\{\\uc0\\u8232 \tcatn(\\cf4 community\\cf2 .tick);\\uc0\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 This would print the tick number in every tick in the specified range, which is obviously not very exciting.  The broader point is that the Eidos code in the braces \n\\f3\\fs18 \\{\\}\n\\f2\\fs22  is executed early in every tick within the specified range of ticks.  In this case, the tick range is \n\\f3\\fs18 1000\n\\f2\\fs22  to \n\\f3\\fs18 5000\n\\f2\\fs22 , and so the Eidos event will be executed 4001 times (not 4000!).  A range of ticks can be given, as in the example above, or a single tick can be given with a single integer:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf5 100\\cf2  late() \\{\\uc0\\u8232 \tprint(\\cf6 \"Finished tick 100!\"\\cf2 );\\uc0\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The tick range may also be incompletely specified, with a somewhat idiosyncratic syntax.  A range of \n\\f3\\fs18 1000:\n\\f2\\fs22  would specify that the event should run in tick \n\\f3\\fs18 1000\n\\f2\\fs22  and every subsequent tick until the model finishes; a range of \n\\f3\\fs18 :1000\n\\f2\\fs22  would similarly specify that the event should run in the first tick executed, and every subsequent tick, up to and including tick \n\\f3\\fs18 1000\n\\f2\\fs22 .\\\nIn fact, you can omit specifying a tick altogether, in which case the Eidos event runs every tick.  Since it takes a little time to set up the Eidos interpreter and interpret a script, it is advisable to use the narrowest range of ticks possible; however, that is more of a concern with callbacks, since they might be called many time in every tick, whereas \n\\f3\\fs18 first()\n\\f2\\fs22 , \n\\f3\\fs18 early()\n\\f2\\fs22 , and \n\\f3\\fs18 late()\n\\f2\\fs22  events will just be called once per tick.\\\nThe ticks specified for a Eidos event block can be any positive integer.  All blocks that apply to a given time point will be run in \n\\f0\\i definition order\n\\f2\\i0 ; blocks specified higher in the input file will run before those specified lower.  Sometimes it is desirable to have a script block execute in a tick which is not fixed, but instead depends upon some parameter, defined constant, or calculation; this may be achieved by rescheduling the script block with the \n\\f3\\fs18 Community\n\\f2\\fs22  method \n\\f3\\fs18 rescheduleScriptBlock()\n\\f2\\fs22 .\\\nIn multispecies models, one can optionally provide a \n\\f3\\fs18 ticks\n\\f2\\fs22  specifier before the definition of an Eidos event, specifying that the event should only run in ticks in which a particular species is active.  That extended syntax looks like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [ticks species_name] [id] [t1 [: t2]] first() \\{ ... \\}\\uc0\\u8232 [ticks species_name] [id] [t1 [: t2]] early() \\{ ... \\}\\u8232 [ticks species_name] [id] [t1 [: t2]] late() \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 species_name\n\\f2\\fs22  should be the name of a species that was explicitly declared in the multispecies model.  If the \n\\f3\\fs18 ticks\n\\f2\\fs22  specifier is omitted, the event will run in every tick (within the specified tick range).\\\nWhen Eidos events are executed, several global variables are defined by SLiM for use by the Eidos code.  Here is a summary of those SLiM globals:\\\n\\pard\\tx1980\\tx2880\\pardeftab720\\li1890\\fi-1343\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 community\n\\f2\\fs22 \tThe \n\\f3\\fs18 Community\n\\f2\\fs22  object for the overall simulation\\\n\n\\f3\\fs18 sim\n\\f2\\fs22 \tA \n\\f3\\fs18 Species\n\\f2\\fs22  object for the simulated species (in single-species simulations)\\\n\n\\f3\\fs18 g1\n\\f2\\fs22 , \n\\f3\\fs18 ...\n\\f2\\fs22 \t\n\\f3\\fs18 GenomicElementType\n\\f2\\fs22  objects for defined genomic element types\\\n\n\\f3\\fs18 i1\n\\f2\\fs22 , \n\\f3\\fs18 ...\n\\f2\\fs22 \t\n\\f3\\fs18 InteractionType\n\\f2\\fs22  objects for defined interaction types\\\n\n\\f3\\fs18 m1\n\\f2\\fs22 , \n\\f3\\fs18 ...\n\\f2\\fs22 \t\n\\f3\\fs18 MutationType\n\\f2\\fs22  objects representing defined mutation types\\\n\n\\f3\\fs18 p1\n\\f2\\fs22 , \n\\f3\\fs18 ...\n\\f2\\fs22 \t\n\\f3\\fs18 Subpopulation\n\\f2\\fs22  objects for existing subpopulations\\\n\n\\f3\\fs18 s1\n\\f2\\fs22 , \n\\f3\\fs18 ...\n\\f2\\fs22 \t\n\\f3\\fs18 SLiMEidosBlock\n\\f2\\fs22  objects for named events and callbacks\\\n\\pard\\tx1980\\tx2880\\pardeftab720\\li1890\\fi-1343\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 self\n\\f2\\fs22 \tA \n\\f3\\fs18 SLiMEidosBlock\n\\f2\\fs22  object for the script block currently executing\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 In multispecies models, symbols for each species will be defined instead of \n\\f3\\fs18 sim\n\\f2\\fs22 .  Note that species symbols such as \n\\f3\\fs18 sim\n\\f2\\fs22  are \n\\f0\\i not\n\\f2\\i0  available in \n\\f3\\fs18 initialize()\n\\f2\\fs22  callbacks, since the species objects have not yet been initialized.  Similarly, the globals for subpopulations, mutation types, and genomic element types are only available after the point at which those objects have been defined by an \n\\f3\\fs18 initialize()\n\\f2\\fs22  callback.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.2  ITEM: 3. \n\\f1\\fs18 mutationEffect()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 An Eidos callback is a block of Eidos code that is called by SLiM in specific circumstances, to allow the customization of particular actions taken by SLiM while running the simulation of a species.  Nine types of callbacks are presently supported (in addition to \n\\f3\\fs18 initialize()\n\\f2\\fs22  callbacks): \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, discussed here, and \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22 , \n\\f3\\fs18 mateChoice()\n\\f2\\fs22 , \n\\f3\\fs18 modifyChild()\n\\f2\\fs22 , \n\\f3\\fs18 recombination()\n\\f2\\fs22 , \n\\f3\\fs18 interaction()\n\\f2\\fs22 , \n\\f3\\fs18 reproduction()\n\\f2\\fs22  , \n\\f3\\fs18 mutation()\n\\f2\\fs22 , and \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks.\\\nA \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback is called by SLiM when it is determining the fitness effect of a mutation carried by an individual.  Normally, the fitness effect of a mutation is determined by the selection coefficient \n\\f0\\i s\n\\f2\\i0  of the mutation and the dominance coefficient \n\\f0\\i h\n\\f2\\i0  of the mutation (the latter used only if the individual is heterozygous for the mutation).  More specifically, the standard calculation for the fitness effect of a mutation takes one of two forms.  If the individual is homozygous, then the fitness effect is (1+\n\\f0\\i s\n\\f2\\i0 ), or:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f0\\i \\cf2 w\n\\f2\\i0  = \n\\f0\\i w\n\\f2\\i0  * (1.0 + selectionCoefficient),\\\n\\pard\\pardeftab397\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 where \n\\f0\\i w\n\\f2\\i0  is the relative fitness of the individual carrying the mutation.  If the individual is heterozygous, then the dominance coefficient enters the picture, and the fitness effect is (1+\n\\f0\\i hs\n\\f2\\i0 ) or:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f0\\i \\cf2 w\n\\f2\\i0  = \n\\f0\\i w\n\\f2\\i0  * (1.0 + dominanceCoeff * selectionCoeff).\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 The dominance coefficient usually comes from the \n\\f3\\fs18 dominanceCoeff\n\\f2\\fs22  property of the mutation\\'92s \n\\f3\\fs18 MutationType\n\\f2\\fs22 ; if the focal individual has only one non-null haplosome, however, such that the mutation is paired with a null haplosome (i.e., is actually hemizygous, not heterozygous), the \n\\f3\\fs18 hemizygousDominanceCoeff\n\\f2\\fs22  property of the \n\\f3\\fs18 MutationType\n\\f2\\fs22  is used instead.\\\nThat is the standard behavior of SLiM, reviewed here to provide a conceptual baseline.  Supplying a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback allows you to substitute any calculation you wish for the relative fitness effect of a mutation; the new relative fitness effect computation becomes:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f0\\i \\cf2 w\n\\f2\\i0  = \n\\f0\\i w\n\\f2\\i0  * \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22 \\\n\\pard\\pardeftab397\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 where \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  is the value returned by your callback.  This value is a multiplicative fitness effect, so \n\\f3\\fs18 1.0\n\\f2\\fs22  is neutral, unlike the selection coefficient scale where \n\\f3\\fs18 0.0\n\\f2\\fs22  is neutral; be careful with this distinction!\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 Like Eidos events, \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks are defined as script blocks in the input file, but they use a variation of the syntax for defining an Eidos event:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] mutationEffect(<mut-type-id> [, <subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 For example, if the callback were defined as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 1000:2000 mutationEffect(m2, p3) \\{ 1.0; \\}\\\n\\pard\\pardeftab397\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 then a relative fitness of \n\\f3\\fs18 1.0\n\\f2\\fs22  (i.e. neutral) would be used for all mutations of mutation type \n\\f3\\fs18 m2\n\\f2\\fs22  in subpopulation \n\\f3\\fs18 p3\n\\f2\\fs22  from tick \n\\f3\\fs18 1000\n\\f2\\fs22  to tick \n\\f3\\fs18 2000\n\\f2\\fs22 .  The very same mutations, if also present in individuals in other subpopulations, would preserve their normal selection coefficient and dominance coefficient in those other subpopulations; this callback would therefore establish spatial heterogeneity in selection, in which mutation type \n\\f3\\fs18 m2\n\\f2\\fs22  was neutral in subpopulation \n\\f3\\fs18 p3\n\\f2\\fs22  but under selection in other subpopulations, for the range of ticks given.\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 In multispecies models, callbacks must be defined with a \n\\f3\\fs18 species\n\\f2\\fs22  specifier that states the species with which species the callback is associated.  Such a definition looks like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 species species_name [id] [t1 [: t2]] mutationEffect(...) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 It is the same syntax, in other words, except for the \n\\f3\\fs18 species\n\\f2\\fs22  specifier at the beginning, with the name of the species that the callback will modify.  As with the \n\\f3\\fs18 ticks\n\\f2\\fs22  specifier for events, this means the callback will only be called in ticks when the species is active; but the \n\\f3\\fs18 species\n\\f2\\fs22  specifier goes further, making that species the focal species for the callback.\\\nIn addition to the standard SLiM globals, a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback is supplied with some additional information passed through \\'93pseudo-parameters\\'94, variables that are defined by SLiM within the context of the callback\\'92s code to supply the callback with relevant information:\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1886\\fi-1339\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mut\n\\f2\\fs22 \tA \n\\f3\\fs18 Mutation\n\\f2\\fs22  object, the mutation whose relative fitness is being evaluated\\\n\n\\f3\\fs18 homozygous\n\\f2\\fs22 \tA value of \n\\f3\\fs18 T\n\\f2\\fs22  (the mutation is homozygous), \n\\f3\\fs18 F\n\\f2\\fs22  (heterozygous), or \n\\f3\\fs18 NULL\n\\f2\\fs22  (it is\\uc0\\u8232 paired with a null haplosome, and is thus hemizygous or haploid)\\\n\n\\f3\\fs18 effect\n\\f2\\fs22 \tThe default relative fitness value calculated by SLiM\\\n\n\\f3\\fs18 individual\n\\f2\\fs22 \tThe individual carrying this mutation (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1890\\fi-1343\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 subpop\n\\f2\\fs22 \tThe subpopulation in which that individual lives\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 These may be used in the \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback to compute a fitness value.  To implement the standard fitness functions used by SLiM for an autosomal simulation with no null haplosomes involved, for example, you could do something like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mutationEffect(m1) \\{\\uc0\\u8232 \tif (homozygous)\\u8232 \t\treturn 1.0 + mut.selectionCoeff;\\u8232 \telse\\u8232 \t\treturn 1.0 + mut.mutationType.dominanceCoeff * mut.selectionCoeff;\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 As mentioned above, a relative fitness of \n\\f3\\fs18 1.0\n\\f2\\fs22  is neutral (whereas a selection coefficient of \n\\f3\\fs18 0.0\n\\f2\\fs22  is neutral); the \n\\f3\\fs18 1.0 +\n\\f2\\fs22  in these calculations converts between the selection coefficient scale and the relative fitness scale, and is therefore essential.  However, the \n\\f3\\fs18 effect\n\\f2\\fs22  global variable mentioned above would already contain this value, precomputed by SLiM, so you could simply return \n\\f3\\fs18 effect\n\\f2\\fs22  to get that behavior when you want it:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mutationEffect(m1) \\{\\uc0\\u8232 \tif (<conditions>)\\u8232 \t\t<custom fitness calculations...>;\\u8232 \telse\\u8232 \t\treturn effect;\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 This would return a modified fitness value in certain conditions, but would return the standard fitness value otherwise.\\\nMore than one \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback may be defined to operate in the same tick.  As with Eidos events, multiple callbacks will be called in the order in which they were defined in the input file.  Furthermore, each callback will be given the \n\\f3\\fs18 effect\n\\f2\\fs22  value returned by the previous callback \\'96 so the value of \n\\f3\\fs18 effect\n\\f2\\fs22  is not necessarily the default value, in fact, but is the result of all previous \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks for that individual in that tick.  In this way, the effects of multiple callbacks can \\'93stack\\'94.\\\nOne caveat to be aware of in WF models is that \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks are called at the end of the tick, just before the next tick begins.  If you have a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback defined for tick \n\\f3\\fs18 10\n\\f2\\fs22 , for example, it will actually be called at the very end of tick \n\\f3\\fs18 10\n\\f2\\fs22 , after child generation has finished, after the new children have been promoted to be the next parental generation, and after \n\\f3\\fs18 late()\n\\f2\\fs22  events have been executed.  The fitness values calculated will thus be used during tick \n\\f3\\fs18 11\n\\f2\\fs22 ; the fitness values used in tick \n\\f3\\fs18 10\n\\f2\\fs22  were calculated at the end of tick \n\\f3\\fs18 9\n\\f2\\fs22 .  (This is primarily so that SLiMgui, which refreshes its display in between ticks, has computed fitness values at hand that it can use to display the new parental individuals in the proper colors.)  This is not an issue in nonWF models, since fitness values are used in the same tick in which they are calculated.\\\nIf the \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f2\\fs22  is \n\\f3\\fs18 T\n\\f2\\fs22  (the default), the order in which the fitness of individuals is evaluated will be randomized within each subpopulation.  This partially mitigates order-dependency issues, although such issues can still arise whenever the effects of a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callback are not independent.  If \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  is \n\\f3\\fs18 F\n\\f2\\fs22 , the fitness of individuals will be evaluated in sequential order within each subpopulation, greatly increasing the risk of order-dependency problems.\\\nMany other possibilities can be implemented with \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks.  However, since \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks involve Eidos code being executed for the evaluation of fitness of every mutation of every individual (within the tick range, mutation type, and subpopulation specified), they can slow down a simulation considerably, so use them as sparingly as possible.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 5.13.3  ITEM: 4. \n\\f1\\fs18 fitnessEffect()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 We have already seen \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, which modify the effect of a given mutation in a focal individual.  Sometimes it is desirable to model effects upon individual fitness that are not governed by particular mutations (or not directly, at least); fitness effects due to spatial position, or resource acquisition, or behavior such as competitive or altruistic interactions, for example.  Another situation of this type is when fitness depends upon the overall phenotype of an individual \\'96 the height of a tree, say \\'96 which might be influenced by genetics, but also by environmental effects, climate, and so forth.  For these sorts of situations, SLiM provides \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks.\\\nA \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback is called by SLiM when it is determining the fitness of an individual \\'96 typically, but not always, once per tick during the fitness calculation tick cycle stage.  Normally, the fitness of a given individual is determined by multiplying together the fitness effects of all mutations possessed by that individual.  Supplying a \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback allows you to add another multiplicative fitness effect into that calculation.  As with \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, the value returned by \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks is a fitness effect, so \n\\f3\\fs18 1.0\n\\f2\\fs22  is neutral.\\\nThe syntax for declaring \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks is similar to that for \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, but simpler since no mutation type is needed:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] fitnessEffect([<subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nFor example, if the callback were defined as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 1000:2000 fitnessEffect(p3) \\{ 0.75; \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 then a fitness effect of \n\\f3\\fs18 0.75\n\\f2\\fs22  would be multiplied into the fitness values of all individuals in subpopulation \n\\f3\\fs18 p3\n\\f2\\fs22  from tick \n\\f3\\fs18 1000\n\\f2\\fs22  to tick \n\\f3\\fs18 2000\n\\f2\\fs22 .\\\nMuch more interesting, of course, are \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks that return different fitness effects for different individuals, depending upon their state!  In addition to the standard SLiM globals, a \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback is supplied with some additional information passed through \\'93pseudo-parameters\\'94, variables that are defined by SLiM within the context of the callback\\'92s code to supply the callback with relevant information:\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1886\\fi-1339\\partightenfactor0\n\n\\f3\\fs18 \\cf2 individual\n\\f2\\fs22 \tThe focal individual (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1890\\fi-1343\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 subpop\n\\f2\\fs22 \tThe subpopulation in which that individual lives\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 These may be used in the \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback to compute a fitness effect that depends upon the state of the focal individual.  The fitness effect for the callback is simply returned as a singleton \n\\f3\\fs18 float\n\\f2\\fs22  value, as usual.\\\nMore than one \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback may be defined to operate in the same tick.  Each such callback will provide an independent fitness effect for the focal individual; the results of each \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback will be multiplied in to the individual\\'92s fitness.  These callbacks will generally be called once per individual in each tick, in an order that is formally undefined.\\\nBeginning in SLiM 3.0, it is also possible to set the \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  property on a subpopulation to scale the fitness values of every individual in the subpopulation by the same constant amount, or to set the \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  property on an individual to scale the fitness value of that specific individual.  These scaling factors are multiplied together with all other fitness effects for an individual to produce the individual\\'92s final fitness value.  The \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  properties of \n\\f3\\fs18 Subpopulation\n\\f2\\fs22  and \n\\f3\\fs18 Individual\n\\f2\\fs22  can often provide similar functionality to \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks with greater efficiency and simplicity.  They are reset to \n\\f3\\fs18 1.0\n\\f2\\fs22  in every tick for which a given species is active, immediately after fitness values are calculated, so they only need to be set when a value other than \n\\f3\\fs18 1.0\n\\f2\\fs22  is desired.\\\nAs with \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks are called at the end of the tick, just before the next tick begins.  Also, as with \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  callbacks, the order in which \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks are called will be shuffled when \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  is enabled, as it is by default, partially mitigating order-dependency issues.\\\nThe \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback mechanism is quite flexible and useful, although it has been considerably eclipsed by the modern modern and efficient \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  property mentioned above.  When efficiency is not at a premium, it remains a clear and expressive paradigm for modeling individual-level fitness effects.  The performance penalty paid is often not large, since these callbacks are called only once per individual per tick, whereas a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  for a type of mutation that is common in the simulation might be called thousands of times per individual per tick (once per mutation of that type possessed by the focal individual).  The performance penalty typically becomes severe only when the \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback needs to perform calculations, once per focal individual, that would vectorize well if performed across a whole vector of individuals.  In such cases, \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  should be used.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 5.13.4  ITEM: 5. \n\\f1\\fs18 mateChoice()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 Normally, WF models in SLiM regulate mate choice according to fitness; individuals of higher fitness are more likely to be chosen as mates.  However, one might wish to simulate more complex mate-choice dynamics such as assortative or disassortative mating, mate search algorithms, and so forth.  Such dynamics can be handled in WF models with the \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback mechanism.  (In nonWF models mating is arranged by the script, so there is no need for a callback.)\\\nA \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback is established in the input file with a syntax very similar to that of \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] mateChoice([<subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 Note that if a subpopulation is given to which the \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback is to apply, the callback is used for all matings that will generate a \n\\f0\\i child\n\\f2\\i0  in the stated subpopulation (as opposed to all matings of \n\\f0\\i parents\n\\f2\\i0  in the stated subpopulation); this distinction is important when migration causes children in one subpopulation to be generated by matings of parents in a different subpopulation.\\\nWhen a \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback is defined, the first parent in a mating is still chosen proportionally according to fitness (if you wish to influence that choice, you can use a \n\\f3\\fs18 mutationEffect()\n\\f2\\fs22  or \n\\f3\\fs18 fitnessEffect()\n\\f2\\fs22  callback).  In a sexual (rather than hermaphroditic) simulation, this will be the female parent; SLiM does not currently support males as the choosy sex.  The second parent \\'96 the male parent, in a sexual simulation \\'96 will then be chosen based upon the results of the \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback.\\\nMore specifically, the callback must return a vector of weights, one for each individual in the subpopulation; SLiM will then choose a parent with probability proportional to weight.  The \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback could therefore modify or replace the standard fitness-based weights depending upon some other criterion such as assortativeness.  A singleton object of type \n\\f3\\fs18 Individual\n\\f2\\fs22  may be returned instead of a weights vector to indicate that that specific individual has been chosen as the mate (beginning in SLiM 2.3); this could also be achieved by returned a vector of weights in which the chosen mate has a non-zero weight and all other weights are zero, but returning the chosen individual directly is much more efficient.  A zero-length return vector \\'96 as generated by \n\\f3\\fs18 float(0)\n\\f2\\fs22 , for example \\'96 indicates that a suitable mate was not found; in that event, a new first parent will be drawn from the subpopulation.  Finally, if the callback returns \n\\f3\\fs18 NULL\n\\f2\\fs22 , that signifies that SLiM should use the standard fitness-based weights to choose a mate; the \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback did not wish to alter the standard behavior for the current mating (this is equivalent to returning the unmodified vector of weights, but returning \n\\f3\\fs18 NULL\n\\f2\\fs22  is much faster since it allows SLiM to drop into an optimized case).  Apart from the special cases described above \\'96 a singleton \n\\f3\\fs18 Individual\n\\f2\\fs22 , \n\\f3\\fs18 float(0)\n\\f2\\fs22 , and \n\\f3\\fs18 NULL\n\\f2\\fs22  \\'96 the returned vector of weights must contain the same number of values as the size of the subpopulation, and all weights must be non-negative.  Note that the vector of weights is not required to sum to \n\\f3\\fs18 1\n\\f2\\fs22 , however; SLiM will convert relative weights on any scale to probabilities for you.\\\nIf the sum of the returned weights vector is zero, SLiM treats it as meaning the same thing as a return of \n\\f3\\fs18 float(0)\n\\f2\\fs22  \\'96 a suitable mate could not be found, and a new first parent will thus be drawn.  (This is a change in policy beginning in SLiM 2.3; prior to that, returning a vector of sum zero was considered a runtime error.)  There is a subtle difference in semantics between this and a return of \n\\f3\\fs18 float(0)\n\\f2\\fs22 : returning \n\\f3\\fs18 float(0)\n\\f2\\fs22  immediately short-circuits mate choice for the current first parent, whereas returning a vector of zeros allows further applicable \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks to be called, one of which might \\'93rescue\\'94 the first parent by returning a non-zero weights vector or an individual.  In most models this distinction is irrelevant, since chaining \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks is uncommon.  When the choice is otherwise unimportant, returning \n\\f3\\fs18 float(0)\n\\f2\\fs22  will be handled more quickly by SLiM.\\\nIn addition to the standard SLiM globals, a \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback is supplied with some additional information passed through \\'93pseudo-parameters\\'94:\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\partightenfactor0\n\n\\f3\\fs18 \\cf2 individual\n\\f2\\fs22 \tThe parent already chosen (the female, in sexual simulations)\\\n\n\\f3\\fs18 subpop\n\\f2\\fs22 \tThe subpopulation into which the offspring will be placed\n\\f3\\fs18 \\\nsourceSubpop\n\\f2\\fs22 \tThe subpopulation from which the parents are being chosen\n\\f3\\fs18 \\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2070\\fi-1523\\sa180\\partightenfactor0\n\\cf2 weights\n\\f2\\fs22 \tThe standard fitness-based weights for all individuals\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 If sex is enabled, the \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback must ensure that the appropriate weights are zero and nonzero to guarantee that all eligible mates are male (since the first parent chosen is always female, as explained above).  In other words, weights for females must be \n\\f3\\fs18 0\n\\f2\\fs22 .  The \n\\f3\\fs18 weights\n\\f2\\fs22  vector given to the callback is guaranteed to satisfy this constraint.  If sex is not enabled \\'96 in a hermaphroditic simulation, in other words \\'96 this constraint does not apply.\\\nFor example, a simple \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback might look like this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 1000:2000 mateChoice(p2) \\{\\uc0\\u8232 \treturn weights ^ 2;\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 This defines a \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback for ticks \n\\f3\\fs18 1000\n\\f2\\fs22  to \n\\f3\\fs18 2000\n\\f2\\fs22  for subpopulation \n\\f3\\fs18 p2\n\\f2\\fs22 .  The callback simply transforms the standard fitness-based probabilities by squaring them.  Code like this could represent a situation in which fitness and mate choice proceed normally in one subpopulation (\n\\f3\\fs18 p1\n\\f2\\fs22 , here, presumably), but are altered by the effects of a social dominance hierarchy or male-male competition in another subpopulation (\n\\f3\\fs18 p2\n\\f2\\fs22 , here), such that the highest-fitness individuals tend to be chosen as mates more often than their (perhaps survival-based) fitness values would otherwise suggest.  Note that by basing the returned weights on the \n\\f3\\fs18 weights\n\\f2\\fs22  vector supplied by SLiM, the requirement that females be given weights of \n\\f3\\fs18 0\n\\f2\\fs22  is finessed; in other situations, care would need to be taken to ensure that.\\\nMore than one \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback may be defined to operate in the same tick.  As with Eidos events, multiple callbacks will be called in the order in which they were defined.  Furthermore, each callback will be given the \n\\f3\\fs18 weights\n\\f2\\fs22  vector returned by the previous callback \\'96 so the value of \n\\f3\\fs18 weights\n\\f2\\fs22  is not necessarily the default fitness-based weights, in fact, but is the result of all previous \n\\f3\\fs18 weights()\n\\f2\\fs22  callbacks for the current mate-choice event.  In this way, the effects of multiple callbacks can \\'93stack\\'94.  If any \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callback returns \n\\f3\\fs18 float(0)\n\\f2\\fs22 , however \\'96 indicating that no eligible mates exist, as described above \\'96 then the remainder of the callback chain will be short-circuited and a new first parent will immediately be chosen.\\\nNote that matings in SLiM do not proceed in random order.  Offspring are generated for each subpopulation in turn, and within each subpopulation the order of offspring generation is also non-random with respect to both the source subpopulation and the sex of the offspring.  It is important, therefore, that \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks are not in any way biased by the offspring generation order; they should not treat matings early in the process any differently than matings late in the process.  Any failure to guarantee such invariance could lead to large biases in the simulation outcome.  In particular, it is usually dangerous to activate or deactivate \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks while offspring generation is in progress.\\\nA wide variety of mate choice algorithms can easily be implemented with \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks.  However, \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks can be particularly slow since they are called for every proposed mating, and the vector of mating weights can be large and slow to process.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.5  ITEM: 6. \n\\f1\\fs18 modifyChild()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 Normally, a SLiM simulation defines child generation with its rules regarding selfing versus crossing, recombination, mutation, and so forth.  However, one might wish to modify these rules in particular circumstances \\'96 by preventing particular children from being generated, by modifying the generated children in particular ways, or by generating children oneself.  All of these dynamics can be handled in SLiM with the \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback mechanism.\\\nA \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback is established in the input file with a syntax very similar to that of other callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] modifyChild([<subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback may optionally be restricted to the children generated to occupy a specified subpopulation.  (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nWhen a \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback is called, a parent or parents have already been chosen, and a candidate child has already been generated.  The parent or parents are provided to the callback, as is the generated child.  The callback may accept the generated child, modify it, substitute completely different genetic information for it, or reject it (causing a new parent or parents to be selected and a new child to be generated, which will again be passed to the callback).\\\nIn addition to the standard SLiM globals, a \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback is supplied with additional information passed through \\'93pseudo-parameters\\'94:\\\n\\pard\\tx2520\\pardeftab720\\li1080\\fi-533\\partightenfactor0\n\n\\f3\\fs18 \\cf2 child\n\\f2\\fs22 \tThe generated child (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\n\\f3\\fs18 isCloning\n\\f2\\fs22 \t\n\\f3\\fs18 T\n\\f2\\fs22  if the child is the result of cloning\\\n\n\\f3\\fs18 isSelfing\n\\f2\\fs22 \t\n\\f3\\fs18 T\n\\f2\\fs22  if the child is the result of selfing (but see note below)\\\n\n\\f3\\fs18 parent1\n\\f2\\fs22 \tThe first parent (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\n\\f3\\fs18 parent2\n\\f2\\fs22 \tThe second parent (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\n\\f3\\fs18 subpop\n\\f2\\fs22 \tThe subpopulation in which the child will live\\\n\\pard\\tx2520\\pardeftab720\\li1080\\fi-533\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 sourceSubpop\n\\f2\\fs22 \tThe subpopulation of the parents (\n\\f3\\fs18 ==subpop\n\\f2\\fs22  if not a migration mating)\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 These may be used in the \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback to decide upon a course of action.  The haplosomes of child (available as \n\\f3\\fs18 child.haplosomes\n\\f2\\fs22 ) may be modified by the callback; whatever mutations they contain on exit will be used for the new child.  Alternatively, they may be left unmodified (to accept the generated child as is).  The child\\'92s haplosomes may be thought of as the two gametes that will fuse to produce the fertilized egg that results in a new offspring; for a biparental cross involving diploid autosomes, \n\\f3\\fs18 child.haploidGenome1\n\\f2\\fs22  is the gamete contributed by the first parent (the female, if sex is turned on), and \n\\f3\\fs18 child.haploidGenome2\n\\f2\\fs22  is the gamete contributed by the second parent (the male, if sex is turned on).  The \n\\f3\\fs18 child\n\\f2\\fs22  object itself may also be modified \\'96 for example, to set the spatial position of the child.\\\nImportantly, a \n\\f3\\fs18 logical\n\\f2\\fs22  singleton return value is required from \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks.  Normally this should be \n\\f3\\fs18 T\n\\f2\\fs22 , indicating that generation of the child may proceed (with whatever modifications might have been made to the child\\'92s haplosomes).  A return value of \n\\f3\\fs18 F\n\\f2\\fs22  indicates that generation of this child should not continue; this will cause new parent(s) to be drawn, a new child to be generated, and a new call to the \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback.  A \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback that always returns \n\\f3\\fs18 F\n\\f2\\fs22  can cause SLiM to hang, so be careful that it is guaranteed that your callback has a nonzero probability of returning \n\\f3\\fs18 T\n\\f2\\fs22  for every state your simulation can reach.\\\nNote that \n\\f3\\fs18 isSelfing\n\\f2\\fs22  is \n\\f3\\fs18 T\n\\f2\\fs22  only when a mating was explicitly set up to be a selfing event by SLiM; an individual may also mate with itself by chance (by drawing itself as a mate) even when SLiM did not explicitly set up a selfing event, which one might term \n\\f0\\i incidental\n\\f2\\i0  selfing.  If you need to know whether a mating event was an incidental selfing event, you can compare the parents; self-fertilization will always entail \n\\f3\\fs18 parent1==parent2\n\\f2\\fs22 , even when \n\\f3\\fs18 isSelfing\n\\f2\\fs22  is \n\\f3\\fs18 F\n\\f2\\fs22 .  Since selfing is enabled only in non-sexual simulations, \n\\f3\\fs18 isSelfing\n\\f2\\fs22  will always be \n\\f3\\fs18 F\n\\f2\\fs22  in sexual simulations (and incidental selfing is also impossible in sexual simulations).\\\nNote that matings in SLiM do not proceed in random order.  Offspring are generated for each subpopulation in turn, and within each subpopulation the order of offspring generation is also non-random with respect to the source subpopulation, the sex of the offspring, and the reproductive mode (selfing, cloning, or autogamy).  It is important, therefore, that \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks are not in any way biased by the offspring generation order; they should not treat offspring generated early in the process any differently than offspring generated late in the process.  Similar to \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  callbacks, any failure to guarantee such invariance could lead to large biases in the simulation outcome.  In particular, it is usually dangerous to activate or deactivate \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks while offspring generation is in progress.  When SLiM sees that \n\\f3\\fs18 mateChoice()\n\\f2\\fs22  or \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks are defined, it randomizes the order of child generation within each subpopulation, so this issue is mitigated somewhat.  However, offspring are still generated for each subpopulation in turn.  Furthermore, in ticks without active callbacks offspring generation order will not be randomized (making the order of parents nonrandom in the next generation), with possible side effects.  In short, order-dependency issues are possible and must be handled very carefully.\\\nAs with the other callback types, multiple \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks may be registered and active.  In this case, all registered and active callbacks will be called for each child generated, in the order that the callbacks were registered.  If a \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback returns \n\\f3\\fs18 F\n\\f2\\fs22 , however, indicating that the child should not be generated, the remaining callbacks in the chain will not be called.\\\nThere are many different ways in which a \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback could be used in a simulation.  In nonWF models, \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callbacks are often unnecessary since each generated child is available to the script in the models\\'92 \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback anyway; but they may be used if desired.\\cf0 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 5.13.6  ITEM: 7. \n\\f1\\fs18 recombination()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 Typically, a simulation sets up a recombination map at the beginning of the run with \n\\f3\\fs18 initializeRecombinationRate()\n\\f2\\fs22 , and that map is used for the duration of the run.  Less commonly, the recombination map is changed dynamically from tick to tick, with \n\\f3\\fs18 Chromosome\n\\f2\\fs22 \\'92s method \n\\f3\\fs18 setRecombinationRate()\n\\f2\\fs22 ; but still, a single recombination map applies for all individuals of a species in a given tick.  However, in unusual circumstances a simulation may need to modify the way that recombination works on an individual basis; for this, the \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback mechanism is provided.  This can be useful for models involving chromosomal inversions that prevent recombination within a region for some individuals, for example, or for models of the evolution of recombination.\\\nA \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback is defined with a syntax much like that of other callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] recombination([<subpop-id> [, <chromosome-id>]]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback will be called during the generation of every gamete during the tick(s) in which it is active.  It may optionally be restricted to apply only to gametes generated by parents in a specified subpopulation, using the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifier.  In addition, in multi-chromosome models it may optionally be restricted to apply only to a specified chromosome, using the \n\\f3\\fs18 <chromosome-id>\n\\f2\\fs22  specifier, which may be either the \n\\f3\\fs18 id\n\\f2\\fs22  or the \n\\f3\\fs18 symbol\n\\f2\\fs22  of a chromosome defined in the species.  (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nWhen a \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback is called, a parent has already been chosen to generate a gamete, and candidate recombination breakpoints for use in recombining the parental haplosomes have been drawn.  The relevant haplosomes of the focal parent are provided to the callback, as is the focal parent itself (as an \n\\f3\\fs18 Individual\n\\f2\\fs22  object) and the subpopulation in which it resides.  Furthermore, the proposed breakpoints are provided to the callback.  The callback may modify these breakpoints in order to change the breakpoints used, in which case it must return \n\\f3\\fs18 T\n\\f2\\fs22  to indicate that changes were made, or it may leave the proposed breakpoints unmodified, in which case it must return \n\\f3\\fs18 F\n\\f2\\fs22 .  (The behavior of SLiM is undefined if the callback returns the wrong \n\\f3\\fs18 logical\n\\f2\\fs22  value.)\\\nIn addition to the standard SLiM globals, then, a \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback is supplied with additional information passed through \\'93pseudo-parameters\\'94:\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\partightenfactor0\n\n\\f3\\fs18 \\cf2 individual\n\\f2\\fs22 \tThe focal parent that is generating a gamete\\\n\n\\f3\\fs18 haplosome1\n\\f2\\fs22 \tOne haplosome of the focal parent; this is the initial copy strand\\\n\n\\f3\\fs18 haplosome2\n\\f2\\fs22 \tThe other haplosome of the focal parent\n\\f3\\fs18 \\\nsubpop\n\\f2\\fs22 \tThe subpopulation to which the focal parent belongs\n\\f3\\fs18 \\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\sa180\\partightenfactor0\n\\cf2 breakpoints\n\\f2\\fs22 \tAn \n\\f3\\fs18 integer\n\\f2\\fs22  vector of crossover breakpoints\n\\f3\\fs18 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 These may be used in the \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback to determine the final recombination breakpoints used by SLiM.  If values are set into \n\\f3\\fs18 breakpoints\n\\f2\\fs22 , the new values must be of type \n\\f3\\fs18 integer\n\\f2\\fs22 .  If \n\\f3\\fs18 breakpoints\n\\f2\\fs22  is modified by the callback, \n\\f3\\fs18 T\n\\f2\\fs22  should be returned, otherwise \n\\f3\\fs18 F\n\\f2\\fs22  should be returned (this is a speed optimization, so that SLiM does not have to spend time checking for changes when no changes have been made).\\\nThe positions specified in \n\\f3\\fs18 breakpoints\n\\f2\\fs22  mean that a crossover will occur immediately \n\\f0\\i before\n\\f2\\i0  the specified base position (between the preceding base and the specified base, in other words).  The haplosome specified by \n\\f3\\fs18 haplosome1\n\\f2\\fs22  will be used as the initial copy strand when SLiM executes the recombination; this cannot presently be changed by the callback.  (Note that \n\\f3\\fs18 haplosome1\n\\f2\\fs22  and \n\\f3\\fs18 haplosome2\n\\f2\\fs22  will be haplosomes from \n\\f3\\fs18 individual\n\\f2\\fs22 , but their order may be swapped, depending on which is the initial copy strand!)\\\nIn this design, the recombination callback does not specify a custom recombination map.  Instead, the callback can add or remove breakpoints at specific locations.  To implement a chromosomal inversion, for example, if the parent is heterozygous for the inversion mutation then crossovers within the inversion region are removed by the callback.  As another example, to implement a model of the evolution of the overall recombination rate, a model could (1) set the global recombination rate to the highest rate attainable in the simulation, (2) for each individual, within the \n\\f3\\fs18 recombination()\n\\f2\\fs22  callback, calculate the fraction of that maximum rate that the focal individual would experience based upon its genetics, and (3) probabilistically remove proposed crossover points based upon random uniform draws compared to that threshold fraction, thus achieving the individual effective recombination rate desired.  Other similar treatments could actually vary the effective recombination map, not just the overall rate, by removing proposed crossovers with probabilities that depend upon their position, allowing for the evolution of localized recombination hot-spots and cold-spots.  Crossovers may also be added, not just removed, by \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks.\\\nIn SLiM 3.3 the recombination model in SLiM was redesigned.  This required a corresponding redesign of \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks.  In particular, the \n\\f3\\fs18 gcStarts\n\\f2\\fs22  and \n\\f3\\fs18 gcEnds\n\\f2\\fs22  pseudo-parameters to \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks were removed.  In the present design, the callback receives \\'93crossover breakpoints\\'94 information only, in the \n\\f3\\fs18 breakpoints\n\\f2\\fs22  pseudo-parameter; it receives no information about gene conversion.  However, \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks can still be used with the \\'93DSB\\'94 recombination model; at the point when the callback is called, the pattern of gene conversion tracts will have been simplified down to a vector of crossover breakpoints.  \\'93Complex\\'94 gene conversion tracts, however, involving heteroduplex mismatch repair, are not compatible with \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks, since there is presently no way for them to be specified to the callback.\\\nNote that the positions in \n\\f3\\fs18 breakpoints\n\\f2\\fs22  are not, in the general case, guaranteed to be sorted or uniqued; in other words, positions may appear out of order, and the same position may appear more than once.  After all \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks have completed, the positions from \n\\f3\\fs18 breakpoints\n\\f2\\fs22  will be sorted, uniqued, and used as the crossover points in generating the prospective gamete haplosome.  The essential point here is that if the same position occurs more than once, across \n\\f3\\fs18 breakpoints\n\\f2\\fs22 , the multiple occurrences of the position do not cancel; SLiM does not cross over and then \\'93cross back over\\'94 given a pair of identical positions.  Instead, the multiple occurrences of the position will simply be uniqued down to a single occurrence.\\\nAs with the other callback types, multiple \n\\f3\\fs18 recombination()\n\\f2\\fs22  callbacks may be registered and active.  In this case, all registered and active callbacks will be called for each gamete generated, in the order that the callbacks were registered.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.7  ITEM: 8. \n\\f1\\fs18 interaction()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 The \n\\f3\\fs18 InteractionType\n\\f2\\fs22  class provides various built-in interaction functions that translate from distances to interaction strengths.  However, it may sometimes be useful to define a custom function for that purpose; for that reason, SLiM allows \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks to be defined that modify the standard interaction strength calculated by \n\\f3\\fs18 InteractionType\n\\f2\\fs22 .  In particular, this mechanism allows the strength of interactions to depend upon not only the distance between individuals, but also the genetics and other state of the individuals, the spatial position of the individuals, and other environmental variables.\\\nAn \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback is called by SLiM when it is determining the strength of the interaction between one individual (the \n\\f0\\i receiver\n\\f2\\i0  of the interaction) and another individual (the \n\\f0\\i exerter\n\\f2\\i0  of the interaction).  This generally occurs when an interaction query is made to \n\\f3\\fs18 InteractionType\n\\f2\\fs22 , as a side effect of serving that query.  This means that \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks may be called at a variety of points in the tick cycle, unlike the other callback types in SLiM, which are each called at a specific point.  If you write an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback, you need to take this into account; assuming that the tick cycle is at a particular stage, or even that the tick or cycle is the same as it was when \n\\f3\\fs18 evaluate()\n\\f2\\fs22  was called, may be dangerous.\\\nWhen an interaction strength is needed, the first thing SLiM does is calculate the default interaction strength using the interaction function that has been defined for the \n\\f3\\fs18 InteractionType\n\\f2\\fs22 .  If the receiver is the same as the exerter, the interaction strength is always zero; and in spatial simulations if the distance between the receiver and the exerter is greater than the maximum distance set for the \n\\f3\\fs18 InteractionType\n\\f2\\fs22 , the interaction strength is also always zero.  In these cases, \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks will not be called, and there is no way to redefine these interaction strengths.\\\nOtherwise, SLiM will then call \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks that apply to the interaction type and exerter subpopulation for the interaction being evaluated.  An \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback is defined with a variation of the syntax used for other callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] interaction(<int-type-id> [, <subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 For example, if the callback were defined as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 1000:2000 interaction(i2, p3) \\{ 1.0; \\}\\\n\\pard\\pardeftab397\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 then an interaction strength of \n\\f3\\fs18 1.0\n\\f2\\fs22  would be used for all interactions of interaction type \n\\f3\\fs18 i2\n\\f2\\fs22 , for exerters in subpopulation \n\\f3\\fs18 p3\n\\f2\\fs22 , from tick \n\\f3\\fs18 1000\n\\f2\\fs22  to tick \n\\f3\\fs18 2000\n\\f2\\fs22 .\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 Beginning in SLiM 4, the receiver and exerter may be in different subpopulations from each other \\'96 or even, in multispecies models, in different species altogether.  For the subpopulation id in the \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback declaration, it does not matter which subpopulation the receiver is in; if the exerter is in \n\\f3\\fs18 p3\n\\f2\\fs22 , for the above example, then the \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback will be called regardless of the receiver\\'92s subpopulation (assuming other preconditions are also met, such as the tick range and the interaction type id).  This means that \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks are not species-specific, unlike other callback types; even if an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback is declared to be specific to exerters in \n\\f3\\fs18 p3\n\\f2\\fs22 , as above, receivers can still be in a different species.  With no subpopulation id specified, \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks are even more general: the \n\\f3\\fs18 InteractionType\n\\f2\\fs22  can then be evaluated and queried for receivers and exerters belonging to any species.  For this reason, in multispecies models \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks must be declared using a species specifier of \n\\f3\\fs18 species all\n\\f2\\fs22 , unlike all other SLiM callback types; it is not legal to declare an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback as species-specific.  Note that there is no way to declare an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback as applying only to receivers in a given subpopulation; if that functionality is desired, you can test \n\\f3\\fs18 receiver.subpopulation\n\\f2\\fs22  in your callback code and act accordingly.\\\nIn addition to the standard SLiM globals, an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback is supplied with some additional information passed through \\'93pseudo-parameters\\'94:\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1886\\fi-1339\\partightenfactor0\n\n\\f3\\fs18 \\cf2 distance\n\\f2\\fs22 \tThe distance from receiver to exerter, in spatial simulations; \n\\f3\\fs18 NAN\n\\f2\\fs22  otherwise\\\n\n\\f3\\fs18 strength\n\\f2\\fs22 \tThe default interaction strength calculated by the interaction function\\\n\n\\f3\\fs18 receiver\n\\f2\\fs22 \tThe individual receiving the interaction (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\\pard\\tx1890\\tx2880\\pardeftab720\\li1890\\fi-1343\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 exerter\n\\f2\\fs22 \tThe individual exerting the interaction (an object of class \n\\f3\\fs18 Individual\n\\f2\\fs22 )\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 These may be used in the \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback to compute an interaction strength.  To simply use the default interaction strength that SLiM would use if a callback had not been defined for interaction type \n\\f3\\fs18 i1\n\\f2\\fs22 , for example, you could do this:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 interaction(i1) \\{\\uc0\\u8232 \treturn strength;\\u8232 \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 Usually an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback will modify that default strength based upon factors such as the genetics of the receiver and/or the exerter, the spatial positions of the two individuals, or some other simulation state.  Any finite \n\\f3\\fs18 float\n\\f2\\fs22  value greater than or equal to \n\\f3\\fs18 0.0\n\\f2\\fs22  may be returned.  The value returned will be not be cached by SLiM; if the interaction strength between the same two individuals is needed again later, the \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback will be called again (something to keep in mind if the interaction strength includes a stochastic component).  Note that the provided \n\\f3\\fs18 distance\n\\f2\\fs22  and \n\\f3\\fs18 strength\n\\f2\\fs22  values are based upon the spatial positions of the exerter and receiver when \n\\f3\\fs18 evaluate()\n\\f2\\fs22  was called, not their current spatial positions, if they have moved since the interaction was evaluated.\\\nMore than one \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback may be defined to operate in the same tick.  As with other callbacks, multiple callbacks will be called in the order in which they were defined in the input file.  Furthermore, each callback will be given the \n\\f3\\fs18 strength\n\\f2\\fs22  value returned by the previous callback \\'96 so the value of \n\\f3\\fs18 strength\n\\f2\\fs22  is not necessarily the default value, in fact, but is the result of all previous \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks for the interaction in question.  In this way, the effects of multiple callbacks can \\'93stack\\'94.\\\nThe \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback mechanism is extremely powerful and flexible, allowing any sort of user-defined interactions whatsoever to be queried dynamically using the methods of \n\\f3\\fs18 InteractionType\n\\f2\\fs22 .  However, in the general case a simulation may call for the evaluation of the interaction strength between each individual and every other individual, making the computation of the full interaction network an O(\n\\f0\\i N\n\\f2\\i0\\fs14\\fsmilli7333 \\super 2\n\\fs22 \\nosupersub ) problem.  Since \n\\f3\\fs18 interaction()\n\\f2\\fs22  callbacks may be called for each of those \n\\f0\\i N\n\\f2\\i0\\fs14\\fsmilli7333 \\super 2\n\\fs22 \\nosupersub  interaction evaluations, they can slow down a simulation considerably, so it is recommended that they be used sparingly.  This is the reason that the various interaction functions of \n\\f3\\fs18 InteractionType\n\\f2\\fs22  were provided; when an interaction does not depend upon individual state, the intention is to avoid the necessity of an \n\\f3\\fs18 interaction()\n\\f2\\fs22  callback altogether.  Furthermore, constraining the number of cases in which interaction strengths need to be calculated \\'96 using a short maximum interaction distance, querying the nearest neighbors of the focal individual rather than querying all possible interactions with that individual, and specifying the reciprocality and sex segregation of the \n\\f3\\fs18 InteractionType\n\\f2\\fs22 , for example \\'96 may greatly decrease the computational overhead of interaction evaluation.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.8  ITEM: 9. \n\\f1\\fs18 reproduction()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 In WF models (the default model type in SLiM), the SLiM core manages the reproduction of individuals in each tick.  In nonWF models, however, reproduction is managed by the model script, in \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks.  These callbacks may only be defined in nonWF models.\\\nA \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback is defined with a syntax much like that of other callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] reproduction([<subpop-id> [, <sex>]]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback will be called once for each individual during the tick(s) in which it is active.  It may optionally be restricted to apply only to individuals in a specified subpopulation, using the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifier; this may be a subpopulation specifier such as \n\\f3\\fs18 p1\n\\f2\\fs22 , or \n\\f3\\fs18 NULL\n\\f2\\fs22  indicating no restriction.  It may also optionally be restricted to apply only to individuals of a specified sex (in sexual models), using the \n\\f3\\fs18 <sex>\n\\f2\\fs22  specifier; this may be \n\\f3\\fs18 \"M\"\n\\f2\\fs22  or \n\\f3\\fs18 \"F\"\n\\f2\\fs22 , or \n\\f3\\fs18 NULL\n\\f2\\fs22  indicating no restriction.  (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nWhen a \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback is called, SLiM\\'92s expectation is that the callback will trigger the reproduction of a focal individual by making method calls to add new offspring individuals.  Typically the offspring added are the offspring of the focal individual, and typically they are added to the subpopulation to which the focal individual belongs, but neither of these is required; a \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback may add offspring generated by any parent(s), to any subpopulation in the focal species.  The focal individual is provided to the callback (as an \n\\f3\\fs18 Individual\n\\f2\\fs22  object), as is the subpopulation in which it resides.\\\nA common alternative pattern is for a \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback to ignore the focal individual and generate all of the offspring for a species for the current tick, from all parents.  The callback then sets \n\\f3\\fs18 self.active\n\\f2\\fs22  to \n\\f3\\fs18 0\n\\f2\\fs22 , preventing itself from being called again in the current tick; this callback design therefore executes once per tick.  This can be useful if individuals influence each other\\'92s offspring generation (as in a monogamous-mating model, for example); it can also simply be more efficient when producing offspring in bulk.\\\nIn addition to the usual SLiM globals, then, a \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback is supplied with additional information passed through global variables:\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\partightenfactor0\n\n\\f3\\fs18 \\cf2 individual\n\\f2\\fs22 \tThe focal individual that is expected to reproduce\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 subpop\n\\f2\\fs22 \tThe subpopulation to which the focal individual belongs\n\\f3\\fs18 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 At present, the return value from \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks is not used, and must be \n\\f3\\fs18 void\n\\f2\\fs22  (i.e., a value may not be returned).  It is possible that other return values will be defined in future.\\\nIt is possible, of course, to do actions unrelated to reproduction inside \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks, but it is not recommended.  The \n\\f3\\fs18 first()\n\\f2\\fs22  event phase of the current tick provides an opportunity for actions immediately before reproduction, and the \n\\f3\\fs18 early()\n\\f2\\fs22  event phase of the current tick provides an opportunity for actions immediately after reproduction, so only actions that are intertwined with reproduction itself should occur in \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks.  Besides providing conceptual clarity, following this design principle will also decrease the probability of bugs, since actions that are unrelated to reproduction should usually not influence or be influenced by the dynamics of reproduction.\\\nIf the \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f2\\fs22  is \n\\f3\\fs18 T\n\\f2\\fs22  (the default), the order in which individuals are given an opportunity to reproduce with a call to \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks will be randomized within each subpopulation.  This partially mitigates order-dependency issues, although such issues can still arise whenever the effects of a \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callback are not independent.  If \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  is \n\\f3\\fs18 F\n\\f2\\fs22 , individuals will be given their opportunity to reproduce in sequential order within each subpopulation, greatly increasing the risk of order-dependency problems.\\\nAs with the other callback types, multiple \n\\f3\\fs18 reproduction()\n\\f2\\fs22  callbacks may be registered and active.  In this case, all registered and active callbacks will be called for each individual, in the order that the callbacks were registered.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.9  ITEM: 10. \n\\f1\\fs18 mutation()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 SLiM auto-generates new mutations according to the current mutation rate (or rate map) and the genetic structure defined by genomic elements, their genomic element types, the mutation types those genomic element types draw from, and the distribution of fitness effects defined by those mutation types.  In nucleotide-based models, the nucleotide sequence and the mutation matrix also play a role in determining both the rate of mutation and the nucleotide mutated to.  In some models it can be desirable to modify these dynamics in some way \\'96 altering the selection coefficients of new mutations in some way, changing the mutation type used, dictating the nucleotide to be used, replacing the proposed mutation with a pre-existing mutation at the same position, or even suppressing the proposed mutation altogether.  To achieve this, one may define a \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback.\\\nA \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback is defined as:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] mutation([<mut-type-id> [, <subpop-id>]]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback will be called once for each new auto-generated mutation during the tick(s) in which the callback is active.  It may optionally be restricted to apply only to mutations of a particular mutation type, using the \n\\f3\\fs18 <mut-type-id>\n\\f2\\fs22  specifier; this may be a mutation type specifier such as \n\\f3\\fs18 m1\n\\f2\\fs22 , or \n\\f3\\fs18 NULL\n\\f2\\fs22  indicating no restriction.  It may also optionally be restricted to individuals generated by a specified subpopulation (usually \\'96 see below for discussion), using the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifier; this should be a subpopulation specifier such as \n\\f3\\fs18 p1\n\\f2\\fs22 .  (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nWhen a \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback is called, a focal mutation (provided to the callback as an object of type \n\\f3\\fs18 Mutation\n\\f2\\fs22 ) has just been created by SLiM, referencing a particular position in a parental haplosome (also provided, as an object of type \n\\f3\\fs18 Haplosome\n\\f2\\fs22 ).  The mutation will not be added to that parental haplosome; rather, the parental haplosome is being copied, during reproduction, to make a gamete or an offspring haplosome, and the mutation is, conceptually, a copying error made during that process.  It will be added to the offspring haplosome that is the end result of the copying process (which may also involve recombination with another haplosome).  At the point that the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback is called, the offspring haplosome is not yet created, however, and so it cannot be accessed from within the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback; the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback can affect only the mutation itself, not the haplosome to which the mutation will be added.\\\nIn addition to the standard SLiM globals, then, a \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback is supplied with additional information passed through global variables:\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mut\n\\f2\\fs22 \tThe focal mutation that is being modified or reviewed\\\n\n\\f3\\fs18 haplosome\n\\f2\\fs22 \tThe parental haplosome that is being copied\\\n\n\\f3\\fs18 element\n\\f2\\fs22 \tThe genomic element that controls the mutation site\\\n\n\\f3\\fs18 originalNuc\n\\f2\\fs22 \tThe nucleotide (\n\\f3\\fs18 0\n\\f2\\fs22 /\n\\f3\\fs18 1\n\\f2\\fs22 /\n\\f3\\fs18 2\n\\f2\\fs22 /\n\\f3\\fs18 3\n\\f2\\fs22  for \n\\f3\\fs18 A\n\\f2\\fs22 /\n\\f3\\fs18 C\n\\f2\\fs22 /\n\\f3\\fs18 G\n\\f2\\fs22 /\n\\f3\\fs18 T\n\\f2\\fs22 ) originally at the mutating position\\\n\n\\f3\\fs18 parent\n\\f2\\fs22 \tThe parent which is generating the offspring haplosome\n\\f3\\fs18 \\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\sa180\\partightenfactor0\n\\cf2 subpop\n\\f2\\fs22 \tThe subpopulation to which the parent belongs\n\\f3\\fs18 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback has three possible returns: \n\\f3\\fs18 T\n\\f2\\fs22 , \n\\f3\\fs18 F\n\\f2\\fs22 , or (beginning in SLiM 3.5) a singleton object of type \n\\f3\\fs18 Mutation\n\\f2\\fs22 .  A return of \n\\f3\\fs18 T\n\\f2\\fs22  indicates that the proposed mutation should be used in generating the offspring haplosome (perhaps with modifications made by the callback).  Conversely, a return of \n\\f3\\fs18 F\n\\f2\\fs22  indicates that the proposed mutation should be suppressed.  If a proposed mutation is suppressed, SLiM will not try again; one fewer mutations will be generated during reproduction than would otherwise have been true.  Returning \n\\f3\\fs18 F\n\\f2\\fs22  will therefore mean that the realized mutation rate in the model will be lower than the expected mutation rate.  Finally, a return of an object of type \n\\f3\\fs18 Mutation\n\\f2\\fs22  replaces the proposed mutation (\n\\f3\\fs18 mut\n\\f2\\fs22 ) with the mutation returned; the offspring haplosomes being generated will contain the returned mutation.  The position of the returned mutation must match that of the proposed mutation.  This provides a mechanism for a \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback to make SLiM re-use existing mutations instead of generating new mutations, which can be useful.\\\nThe callback may perform a variety of actions related to the generated mutation.  The selection coefficient of the mutation can be changed with \n\\f3\\fs18 setSelectionCoefficient()\n\\f2\\fs22 , and the mutation type of the mutation can be changed with \n\\f3\\fs18 setMutationType()\n\\f2\\fs22 ; the \n\\f3\\fs18 drawSelectionCoefficient()\n\\f2\\fs22  method of \n\\f3\\fs18 MutationType\n\\f2\\fs22  may also be useful here.  A \n\\f3\\fs18 tag\n\\f2\\fs22  property value may be set for the mutation, and named values may be attached to the mutation with \n\\f3\\fs18 setValue()\n\\f2\\fs22 .  In nucleotide-based models, the \n\\f3\\fs18 nucleotide\n\\f2\\fs22  (or \n\\f3\\fs18 nucleotideValue\n\\f2\\fs22 ) property of the mutation may also be changed; note that the original nucleotide at the focal position in the parental haplosome is provided through \n\\f3\\fs18 originalNuc\n\\f2\\fs22  (it could be retrieved with \n\\f3\\fs18 haplosome.nucleotides()\n\\f2\\fs22 , but SLiM already has it at hand anyway).  All of these modifications to the new mutation may be based upon the state of the parent, including its genetic state, or upon any other model state.\\\nIt is possible, of course, to do actions unrelated to mutation inside \n\\f3\\fs18 mutation()\n\\f2\\fs22  callbacks, but it is not recommended; \n\\f3\\fs18 first()\n\\f2\\fs22 , \n\\f3\\fs18 early()\n\\f2\\fs22 , and \n\\f3\\fs18 late()\n\\f2\\fs22  events should be used for general-purpose scripting.  Besides providing conceptual clarity, following this design principle will also decrease the probability of bugs, since actions that are unrelated to mutation should not influence or be influenced by the dynamics of mutation.\\\nThe proposed mutation will not appear in the \n\\f3\\fs18 sim.mutations\n\\f2\\fs22  vector of segregating mutations until it has been added to a haplosome; it will therefore not be visible in that vector within its own \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback invocation, and indeed, may not be visible in subsequent callbacks during the reproduction tick cycle stage until such time as the offspring individual being generated has been completed.  If that offspring is ultimately rejected, in particular by a \n\\f3\\fs18 modifyChild()\n\\f2\\fs22  callback, the proposed mutation may not be used by SLiM at all.  It may therefore be unwise to assume, in a \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback, that the focal mutation will ultimately be added to the simulation, depending upon the rest of the model\\'92s script.\\\nThere is one subtlety to be mentioned here, having to do with subpopulations.  The \n\\f3\\fs18 subpop\n\\f2\\fs22  pseudo-parameter discussed above is always the subpopulation of the parent which possesses the haplosome that is being copied and is mutating; there is no ambiguity about that whatsoever.  The \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specified in the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback declaration, however, is a bit more subtle; above it was said that it restricts the callback \\'93to individuals generated by a specified subpopulation\\'94, and that is usually true but requires some explanation.  In WF models, recall that migrants are generated in a source subpopulation and placed in a target subpopulation, as a model of juvenile migration; in that context, the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifies the \n\\f0\\i source\n\\f2\\i0  subpopulation to which the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback will be restricted.  In nonWF models, offspring are generated by the \n\\f3\\fs18 add...()\n\\f2\\fs22  family of \n\\f3\\fs18 Subpopulation\n\\f2\\fs22  methods, which can cross individuals from two different subpopulations and place the result in a third target subpopulation; in that context, in general, the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifies the source subpopulation that is generating the particular \n\\f0\\i gamete\n\\f2\\i0  that is sustaining a mutation during its production.  The exception to this rule is \n\\f3\\fs18 addRecombinant()\n\\f2\\fs22  and \n\\f3\\fs18 addMultiRecombinant()\n\\f2\\fs22 ; since there are four different source subpopulations potentially in play there per mutation, it was deemed simpler in that case for the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  to specify the \n\\f0\\i target\n\\f2\\i0  subpopulation to which the \n\\f3\\fs18 mutation()\n\\f2\\fs22  callback will be restricted.  If restriction to the source subpopulation is needed with \n\\f3\\fs18 addRecombinant()\n\\f2\\fs22  or \n\\f3\\fs18 addMultiRecombinant()\n\\f2\\fs22 , the \n\\f3\\fs18 subpop\n\\f2\\fs22  pseudo-parameter may be consulted rather than using \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22 .\\\nNote that \n\\f3\\fs18 mutation()\n\\f2\\fs22  callbacks are only called for mutations that are auto-generated by SLiM, as a consequence of the mutation rate and the genetic structure defined.  Mutations that are created in script, using \n\\f3\\fs18 addNewMutation()\n\\f2\\fs22  or \n\\f3\\fs18 addNewDrawnMutation()\n\\f2\\fs22 , will not trigger \n\\f3\\fs18 mutation()\n\\f2\\fs22  callbacks; but of course the script may modify or tailor such added mutations in whatever way is desired, so there is no need for callbacks in that situation.\\\nAs with the other callback types, multiple \n\\f3\\fs18 mutation()\n\\f2\\fs22  callbacks may be registered and active.  In this case, all registered and active callbacks will be called for each generated mutation to which they apply, in the order that the callbacks were registered.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f0\\i \\cf0 \\kerning1\\expnd0\\expndtw0 5.13.10  ITEM: 11. \n\\f1\\fs18 survival()\n\\f0\\fs22  callbacks\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\i0 \\cf2 In nonWF models, a selection phase in the tick cycle results in mortality; individuals survive or die based upon their fitness.  In most cases this standard behavior is sufficient; but occasionally it can be useful to observe the survival decisions SLiM makes (to log out information about dying individuals, for example), to modify those decisions (influencing which individuals live and which die, perhaps based upon factors other than genetics), or even to short-circuit mortality completely (moving dead individuals into a \\'93cold storage\\'94 subpopulation for later use, perhaps).  To accomplish such goals, one can the \n\\f3\\fs18 survival()\n\\f2\\fs22  callback mechanism to override SLiM\\'92s default behavior.  Note that in WF models, since they always model non-overlapping generations, the entire parental generation dies in each tick regardless of fitness; \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks therefore apply only to nonWF models.\\\nA \n\\f3\\fs18 survival()\n\\f2\\fs22  callback is defined with a syntax much like that of other callbacks:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sb180\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 [id] [t1 [: t2]] survival([<subpop-id>]) \\{ ... \\}\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 The \n\\f3\\fs18 survival()\n\\f2\\fs22  callback will be called during the selection phase of the tick cycle of nonWF models, during the tick(s) in which it is active.  By default it will be called once per individual in the entire population (whether slated for survival or not); it may optionally be restricted to apply only to individuals in a specified subpopulation, using the \n\\f3\\fs18 <subpop-id>\n\\f2\\fs22  specifier.  (In multispecies models, the definition must be preceded by a \n\\f3\\fs18 species\n\\f2\\fs22  specification as usual.)\\\nWhen a \n\\f3\\fs18 survival()\n\\f2\\fs22  callback is called, a focal individual has already been evaluated by SLiM regarding its survival; a final fitness value for the individual has been calculated, and a random uniform draw in \n\\f3\\fs18 [0,1]\n\\f2\\fs22  has been generated that determines whether the individual is to survive (a draw less than the individual\\'92s fitness) or die (a draw greater than or equal to the individual\\'92s fitness).  The focal individual is provided to the callback, as is the subpopulation in which it resides.  Furthermore, the preliminary decision (whether the focal individual will survive or not), the focal individual\\'92s fitness, and the random draw made by SLiM to determine survival are also provided to the callback.  The callback may return \n\\f3\\fs18 NULL\n\\f2\\fs22  to accept SLiM\\'92s decision, or may return \n\\f3\\fs18 T\n\\f2\\fs22  to indicate that the individual should survive, or \n\\f3\\fs18 F\n\\f2\\fs22  to indicate that it should die, regardless of its fitness and the random deviate drawn.  The callback may also return a singleton \n\\f3\\fs18 Subpopulation\n\\f2\\fs22  object to indicate the individual should remain alive but should be moved to that subpopulation (note that calling \n\\f3\\fs18 takeMigrants()\n\\f2\\fs22  during the survival phase is illegal, because SLiM is busy modifying the population\\'92s internal state).\\\nIn addition to the standard SLiM globals, then, a \n\\f3\\fs18 survival()\n\\f2\\fs22  callback is supplied with additional information passed through \\'93pseudo-parameters\\'94:\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\partightenfactor0\n\n\\f3\\fs18 \\cf2 individual\n\\f2\\fs22 \tThe focal individual that will live or die\\\n\n\\f3\\fs18 subpop\n\\f2\\fs22 \tThe subpopulation to which the focal individual belongs\\\n\n\\f3\\fs18 surviving\n\\f2\\fs22 \tA \n\\f3\\fs18 logical\n\\f2\\fs22  value indicating SLiM\\'92s preliminary decision (\n\\f3\\fs18 T\n\\f2\\fs22  == survival)\\\n\n\\f3\\fs18 fitness\n\\f2\\fs22 \tThe focal individual\\'92s fitness\\\n\\pard\\tx2070\\tx2880\\pardeftab720\\li2073\\fi-1526\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 draw\n\\f2\\fs22 \tSLiM\\'92s random uniform deviate, which determined the preliminary decision\n\\f3\\fs18 \\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f2\\fs22 \\cf2 These may be used in the \n\\f3\\fs18 survival()\n\\f2\\fs22  callback to determine the final decision.\\\nWhile \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks are still being called, no decisions are put into effect; no individuals actually die, and none are moved to a new \n\\f3\\fs18 Subpopulation\n\\f2\\fs22  if that was requested.  In effect, SLiM pre-plans the fate of every individual completely without modifying the model state at all.  After all \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks have completed for every individual, the planned fates for every individual will then be executed, without any opportunity for further intervention through callbacks.  It is therefore legal to inspect subpopulations and individuals inside a \n\\f3\\fs18 survival()\n\\f2\\fs22  callback, but it should be understood that previously made decisions about the fates of other individuals will not yet have any visible effect.  It is generally a good idea for the decisions rendered by \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks to be independent anyway, to avoid biases due to order-dependency.  If the \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f2\\fs22  is \n\\f3\\fs18 T\n\\f2\\fs22  (the default), the order in which \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks are called on individuals will be randomized within each subpopulation; nevertheless, order-dependency issues can occur if callback effects are not independent.  If \n\\f3\\fs18 randomizeCallbacks\n\\f2\\fs22  is \n\\f3\\fs18 F\n\\f2\\fs22 , the order in which individuals are evaluated within each subpopulation is not guaranteed to be random, and order-dependency problems are thus even more likely.\\\nIt is worth noting that if \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks are used, \\'93fitness\\'94 in the model is then no longer really fitness; the model is making its own decisions about which individuals live and die, and those decisions are the true determinant of fitness in the biological sense.  A \n\\f3\\fs18 survival()\n\\f2\\fs22  callback that makes its own decisions regarding survival with no regard for SLiM\\'92s calculated fitness values can completely alter the pattern of selection in a population, rendering all of SLiM\\'92s fitness machinery \\'96 selection and dominance coefficients, \n\\f3\\fs18 fitnessScaling\n\\f2\\fs22  values, etc. \\'96 completely irrelevant.  To avoid highly counterintuitive and confusing effects, it is thus generally a good idea to use of \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks only when it is strictly necessary to achieve a desired outcome.\\\nAs with the other callback types, multiple \n\\f3\\fs18 survival()\n\\f2\\fs22  callbacks may be registered and active.  In this case, all registered and active callbacks will be called for each individual evaluated, in the order that the callbacks were registered.\\\n\\pard\\pardeftab543\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\n\\\n}"
  },
  {
    "path": "SLiMgui/SLiMHelpClasses.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Bold;\\f1\\fswiss\\fcharset0 Optima-Italic;\\f2\\fnil\\fcharset0 Menlo-Italic;\n\\f3\\fnil\\fcharset0 Menlo-Regular;\\f4\\fswiss\\fcharset0 Optima-Regular;\\f5\\froman\\fcharset0 TimesNewRomanPSMT;\n\\f6\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;\\f7\\fnil\\fcharset0 LucidaGrande;\\f8\\fswiss\\fcharset0 Helvetica-Oblique;\n\\f9\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;\\red0\\green0\\blue255;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;\\cssrgb\\c0\\c0\\c100000;}\n\\margl1440\\margr1440\\vieww9000\\viewh19740\\viewkind0\n\\deftab720\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.2  Class Chromosome\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.2.1  \n\\f2\\fs18 Chromosome\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 colorSubstitution <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The color used to display substitutions in SLiMgui when both mutations and substitutions are being displayed in the chromosome view.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20 .  If \n\\f3\\fs18 colorSubstitution\n\\f4\\fs20  is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui will defer to the color scheme of each \n\\f3\\fs18 MutationType\n\\f4\\fs20 , just as it does when only substitutions are being displayed.  The default, \n\\f3\\fs18 \"3333FF\"\n\\f4\\fs20 , causes all substitutions to be shown as dark blue when displayed in conjunction with mutations, to prevent the view from becoming too noisy.  Note that when substitutions are displayed without mutations also being displayed, this value is ignored by SLiMgui and the substitutions use the color scheme of each \n\\f3\\fs18 MutationType\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\ngeneConversionEnabled => (logical$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 When gene conversion has been enabled by calling \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20 , switching to the DSB recombination model, this property is \n\\f3\\fs18 T\n\\f4\\fs20 ; otherwise, when using the crossover breakpoints model, it is \n\\f3\\fs18 F\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 geneConversionGCBias => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The gene conversion bias coefficient, which expresses a bias in the resolution of heteroduplex mismatches in complex gene conversion tracts.  When gene conversion has not been enabled by calling \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20 , this property will be unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 geneConversionNonCrossoverFraction => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The fraction of double-stranded breaks that result in non-crossover events.  When gene conversion has not been enabled by calling \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20 , this property will be unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 geneConversionMeanLength => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The mean length of a gene conversion tract (in base positions).  When gene conversion has not been enabled by calling \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20 , this property will be unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 geneConversionSimpleConversionFraction => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The fraction of gene conversion tracts that are \\'93simple\\'94 (i.e., not involving resolution of heteroduplex mismatches); the remainder will be \\'93complex\\'94.  When gene conversion has not been enabled by calling \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20 , this property will be unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 genomicElements => (object<GenomicElement>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 All of the \n\\f3\\fs18 GenomicElement\n\\f4\\fs20  objects that comprise the chromosome\\cf2 , in sorted order (not necessarily in the order in which they were defined).\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nhotspotEndPositions => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The end positions for hotspot map regions along the chromosome.  Each hotspot map region is assumed to start at the position following the end of the previous hotspot map region; in other words, the regions are assumed to be contiguous.  When using sex-specific hotspot maps, this property will unavailable; see \n\\f3\\fs18 hotspotEndPositionsF\n\\f4\\fs20  and \n\\f3\\fs18 hotspotEndPositionsM\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hotspotEndPositionsF => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The end positions for hotspot map regions for females, when using sex-specific hotspot maps; unavailable otherwise.  See \n\\f3\\fs18 hotspotEndPositions\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hotspotEndPositionsM => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The end positions for hotspot map regions for males, when using sex-specific hotspot maps; unavailable otherwise.  See \n\\f3\\fs18 hotspotEndPositions\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hotspotMultipliers => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The hotspot multiplier for each of the hotspot map regions specified by \n\\f3\\fs18 hotspotEndPositions\n\\f4\\fs20 .  When using sex-specific hotspot maps, this property will be unavailable; see \n\\f3\\fs18 hotspotMultipliersF\n\\f4\\fs20  and \n\\f3\\fs18 hotspotMultipliersM\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hotspotMultipliersF => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The hotspot multiplier for each of the hotspot map regions specified by \n\\f3\\fs18 hotspotEndPositionsF\n\\f4\\fs20 , when using sex-specific hotspot maps; unavailable otherwise.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hotspotMultipliersM => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The hotspot multiplier for each of the hotspot map regions specified by \n\\f3\\fs18 hotspotEndPositionsM\n\\f4\\fs20 , when using sex-specific hotspot maps; unavailable otherwise.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The id for the chromosome, as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  For an implicitly defined chromosome, the \n\\f3\\fs18 id\n\\f4\\fs20  will be \n\\f3\\fs18 1\n\\f4\\fs20 .  The \n\\f3\\fs18 id\n\\f4\\fs20  can be used to refer to the chromosome; see also \n\\f3\\fs18 symbol\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 intrinsicPloidy => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The intrinsic ploidy of the chromosome, meaning the number of haplosome objects that are allocated in each individual, associated with the chromosome (even if some of those haplosomes are null haplosomes acting as placeholders).  This is a consequence of the chromosome\\'92s type.  Chromosome types \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"Z\"\n\\f4\\fs20  are intrinsically diploid (and thus this property would have the value \n\\f3\\fs18 2\n\\f4\\fs20 ), as are the backwards-compatibility chromosome types \n\\f3\\fs18 \"H-\"\n\\f4\\fs20  and \n\\f3\\fs18 \"-Y\"\n\\f4\\fs20 .  All other chromosome types are intrinsically haploid (and thus this property would have the value \n\\f3\\fs18 1\n\\f4\\fs20 ).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 isSexChromosome => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Indicates whether the chromosome is a sex chromosome (T) or not (F).  This is a consequence of the chromosome\\'92s type.  Chromosome types \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Z\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"W\"\n\\f4\\fs20  are considered sex chromosomes, as is the backwards-compatibility type \n\\f3\\fs18 \"-Y\"\n\\f4\\fs20 ; all other chromosome types are not.  See also the \n\\f3\\fs18 sexChromosomes\n\\f4\\fs20  property of \n\\f3\\fs18 Species\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 lastPosition => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The last valid position in the chromosome; equal to \n\\f3\\fs18 length-1\n\\f4\\fs20 , where \n\\f3\\fs18 length\n\\f4\\fs20  is the length as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  For an implicitly defined chromosome, the chromosome\\'92s last position is determined by the \n\\f1\\i maximum\n\\f4\\i0  of the end of the last genomic element, the end of the last recombination region, and the end of the last mutation map region (or hotspot map region).  See also \n\\f3\\fs18 length\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 length => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The length of the chromosome (meaning the number of valid base positions it contains), as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  The length is simply equal to the last position plus \n\\f3\\fs18 1\n\\f4\\fs20 , since the chromosome always starts at \n\\f3\\fs18 0\n\\f4\\fs20 .  See also \n\\f3\\fs18 lastPosition\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationEndPositions => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for mutation rate regions along the chromosome.  Each mutation rate region is assumed to start at the position following the end of the previous mutation rate region; in other words, the regions are assumed to be contiguous.  When using sex-specific mutation rate maps, this property will unavailable; see \n\\f3\\fs18 mutationEndPositionsF\n\\f4\\fs20  and \n\\f3\\fs18 mutationEndPositionsM\n\\f4\\fs20 .\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationEndPositionsF => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for mutation rate regions for females, when using sex-specific mutation rate maps; unavailable otherwise.  See \n\\f3\\fs18 mutationEndPositions\n\\f4\\fs20  for further explanation.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationEndPositionsM => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for mutation rate regions for males, when using sex-specific mutation rate maps; unavailable otherwise.  See \n\\f3\\fs18 mutationEndPositions\n\\f4\\fs20  for further explanation.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationRates => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe mutation rate for each of the mutation rate regions specified by \n\\f3\\fs18 mutationEndPositions\n\\f4\\fs20 .  When using sex-specific mutation rate maps, this property will be unavailable; see \n\\f3\\fs18 mutationRatesF\n\\f4\\fs20  and \n\\f3\\fs18 mutationRatesM\n\\f4\\fs20 .\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationRatesF => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe mutation rate for each of the mutation rate regions specified by \n\\f3\\fs18 mutationEndPositionsF\n\\f4\\fs20 , when using sex-specific mutation rate maps; unavailable otherwise.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationRatesM => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe mutation rate for each of the mutation rate regions specified by \n\\f3\\fs18 mutationEndPositionsM\n\\f4\\fs20 , when using sex-specific mutation rate maps; unavailable otherwise.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 name <\\'96> (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The name of the chromosome, as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  The chromosome name is not used by SLiM, and may be whatever you wish.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 overallMutationRate => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall mutation rate across the whole chromosome determining the overall number of mutation events that will occur anywhere in the chromosome, as calculated from the individual mutation ranges and rates as well as the coverage of the chromosome by genomic elements (since mutations are only generated within genomic elements, regardless of the mutation rate map).  When using sex-specific mutation rate maps, this property will unavailable; see \n\\f3\\fs18 overallMutationRateF\n\\f4\\fs20  and \n\\f3\\fs18 overallMutationRateM\n\\f4\\fs20 .\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 overallMutationRateF => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall mutation rate for females, when using sex-specific mutation rate maps; unavailable otherwise.  See \n\\f3\\fs18 overallMutationRate\n\\f4\\fs20  for further explanation.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 overallMutationRateM => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall mutation rate for males, when using sex-specific mutation rate maps; unavailable otherwise.  See \n\\f3\\fs18 overallMutationRate\n\\f4\\fs20  for further explanation.\\\nThis property is unavailable in nucleotide-based models.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 overallRecombinationRate => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall recombination rate across the whole chromosome determining the overall number of recombination events that will occur anywhere in the chromosome, as calculated from the individual recombination ranges and rates.  When using sex-specific recombination maps, this property will unavailable; see \n\\f3\\fs18 overallRecombinationRateF\n\\f4\\fs20  and \n\\f3\\fs18 overallRecombinationRateM\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 overallRecombinationRateF => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall recombination rate for females, when using sex-specific recombination maps; unavailable otherwise.  See \n\\f3\\fs18 overallRecombinationRate\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 overallRecombinationRateM => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe overall recombination rate for males, when using sex-specific recombination maps; unavailable otherwise.  See \n\\f3\\fs18 overallRecombinationRate\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationEndPositions => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for recombination regions along the chromosome.  Each recombination region is assumed to start at the position following the end of the previous recombination region; in other words, the regions are assumed to be contiguous.  When using sex-specific recombination maps, this property will unavailable; see \n\\f3\\fs18 recombinationEndPositionsF\n\\f4\\fs20  and \n\\f3\\fs18 recombinationEndPositionsM\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationEndPositionsF => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for recombination regions for females, when using sex-specific recombination maps; unavailable otherwise.  See \n\\f3\\fs18 recombinationEndPositions\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationEndPositionsM => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe end positions for recombination regions for males, when using sex-specific recombination maps; unavailable otherwise.  See \n\\f3\\fs18 recombinationEndPositions\n\\f4\\fs20  for further explanation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationRates => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe recombination rate for each of the recombination regions specified by \n\\f3\\fs18 recombinationEndPositions\n\\f4\\fs20 .  When using sex-specific recombination maps, this property will unavailable; see \n\\f3\\fs18 recombinationRatesF\n\\f4\\fs20  and \n\\f3\\fs18 recombinationRatesM\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationRatesF => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe recombination rate for each of the recombination regions specified by \n\\f3\\fs18 recombinationEndPositionsF\n\\f4\\fs20 , when using sex-specific recombination maps; unavailable otherwise.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 recombinationRatesM => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe recombination rate for each of the recombination regions specified by \n\\f3\\fs18 recombinationEndPositionsM\n\\f4\\fs20 , when using sex-specific recombination maps; unavailable otherwise.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 species => (object<Species>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe species to which the target object belongs.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 symbol => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The symbol for the chromosome, as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 ; see the documentation for that function.  For an implicitly defined chromosome, the symbol is \n\\f3\\fs18 \"A\"\n\\f4\\fs20  for non-sexual models, and for sexual models (for historical reasons) is determined by the model type passed to \n\\f3\\fs18 initializeSex()\n\\f4\\fs20  as documented there.  The \n\\f3\\fs18 symbol\n\\f4\\fs20  can be used to refer to the chromosome; see also \n\\f3\\fs18 id\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 type => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The type of the chromosome, as given to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 ; see the documentation for that function for a list of the supported chromosome types.  For an implicitly defined chromosome, the type is \n\\f3\\fs18 \"A\"\n\\f4\\fs20  for non-sexual models, and for sexual models (for historical reasons) is determined by the model type passed to \n\\f3\\fs18 initializeSex()\n\\f4\\fs20  as documented there.\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.2.2  \n\\f2\\fs18 Chromosome\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(is)ancestralNucleotides([Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [string$\\'a0format\\'a0=\\'a0\"string\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the ancestral nucleotide sequence originally supplied to \n\\f3\\fs18 initializeAncestralNucleotides()\n\\f4\\fs20 , including any sequence changes due to nucleotide mutations that have fixed and substituted.  This nucleotide sequence is the reference sequence for positions in a haplosome that do not contain a nucleotide-based mutation.  The range of the returned sequence may be constrained by a start position given in \n\\f3\\fs18 start\n\\f4\\fs20  and/or an end position given in \n\\f3\\fs18 end\n\\f4\\fs20 ; nucleotides will be returned from \n\\f3\\fs18 start\n\\f4\\fs20  to \n\\f3\\fs18 end\n\\f4\\fs20 , inclusive.  The default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  represent the first and last base positions of the chromosome, respectively.\\\nThe format of the returned sequence is controlled by the \n\\f3\\fs18 format\n\\f4\\fs20  parameter.  A format of \n\\f3\\fs18 \"string\"\n\\f4\\fs20  will return the sequence as a singleton \n\\f3\\fs18 string\n\\f4\\fs20  (e.g., \n\\f3\\fs18 \"TATA\"\n\\f4\\fs20 ).  A format of \n\\f3\\fs18 \"char\"\n\\f4\\fs20  will return a \n\\f3\\fs18 string\n\\f4\\fs20  vector with one element per nucleotide (e.g., \n\\f3\\fs18 \"T\"\n\\f4\\fs20 , \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"T\"\n\\f4\\fs20 , \n\\f3\\fs18 \"A\"\n\\f4\\fs20 ).  A format of \n\\f3\\fs18 \"integer\"\n\\f4\\fs20  will return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with values A=\n\\f3\\fs18 0\n\\f4\\fs20 , C=\n\\f3\\fs18 1\n\\f4\\fs20 , G=\n\\f3\\fs18 2\n\\f4\\fs20 , T=\n\\f3\\fs18 3\n\\f4\\fs20  (e.g., \n\\f3\\fs18 3\n\\f4\\fs20 , \n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 3\n\\f4\\fs20 , \n\\f3\\fs18 0\n\\f4\\fs20 ).  If the sequence returned is likely to be long, the \n\\f3\\fs18 \"string\"\n\\f4\\fs20  format will be the most memory-efficient, and may also be the fastest (but may be harder to work with).\\\nFor purposes related to interpreting the nucleotide sequence as a coding sequence, a format of \n\\f3\\fs18 \"codon\"\n\\f4\\fs20  is also supported.  This format will return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with values from \n\\f3\\fs18 0\n\\f4\\fs20  to \n\\f3\\fs18 63\n\\f4\\fs20 , based upon successive nucleotide triplets in the sequence (which, for this format, must have a length that is a multiple of three).  The codon value for a given nucleotide triplet XYZ is 16X\\'a0+\\'a04Y\\'a0+\\'a0Z, where X, Y, and Z have the usual values A=\n\\f3\\fs18 0\n\\f4\\fs20 , C=\n\\f3\\fs18 1\n\\f4\\fs20 , G=\n\\f3\\fs18 2\n\\f4\\fs20 , T=\n\\f3\\fs18 3\n\\f4\\fs20 .  For example, the triplet AAA has a codon value of \n\\f3\\fs18 0\n\\f4\\fs20 , AAC is \n\\f3\\fs18 1\n\\f4\\fs20 , AAG is \n\\f3\\fs18 2\n\\f4\\fs20 , AAT is \n\\f3\\fs18 3\n\\f4\\fs20 , ACA is \n\\f3\\fs18 4\n\\f4\\fs20 , and on upward to TTT which is \n\\f3\\fs18 63\n\\f4\\fs20 .  If the nucleotide sequence AACACATTT is requested in codon format, the codon vector \n\\f3\\fs18 1 4 63\n\\f4\\fs20  will therefore be returned.  These codon values can be useful in themselves; they can also be passed to \n\\f3\\fs18 codonToAminoAcid()\n\\f4\\fs20  to translate them into the corresponding amino acid sequence if desired.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0\\cf2 \\expnd0\\expndtw0\\kerning0\n(integer)drawBreakpoints([No<Individual>$\\'a0parent\\'a0=\\'a0NULL], [Ni$\\'a0n\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Draw recombination breakpoints, using the chromosome\\'92s recombination rate map, the current gene conversion parameters, and (in some cases \\'96 see below) any active and applicable \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks.  The number of breakpoints to generate, \n\\f3\\fs18 n\n\\f4\\fs20 , may be supplied; if it is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), the number of breakpoints will be drawn based upon the overall recombination rate and the chromosome length (following the standard procedure in SLiM).  Note that if the double-stranded breaks model has been chosen, the number of breakpoints generated will probably not be equal to the number requested, because most breakpoints will entail gene conversion tracts, which entail additional crossover breakpoints.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 It is generally recommended that the parent individual be supplied to this method, but \n\\f3\\fs18 parent\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  by default.  The individual supplied in \n\\f3\\fs18 parent\n\\f4\\fs20  is used for two purposes.  First, in sexual models that define separate recombination rate maps for males versus females, the sex of \n\\f3\\fs18 parent\n\\f4\\fs20  will be used to determine which map is used; in this case, a non-\n\\f3\\fs18 NULL\n\\f4\\fs20  value \n\\f1\\i must\n\\f4\\i0  be supplied for \n\\f3\\fs18 parent\n\\f4\\fs20 , since the choice of recombination rate map must be determined.  Second, in models that define \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks, \n\\f3\\fs18 parent\n\\f4\\fs20  is used to determine the various pseudo-parameters that are passed to \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks (\n\\f3\\fs18 individual\n\\f4\\fs20 , \n\\f3\\fs18 haplosome1\n\\f4\\fs20 , \n\\f3\\fs18 haplosome2\n\\f4\\fs20 , \n\\f3\\fs18 subpop\n\\f4\\fs20 ), and the subpopulation to which \n\\f3\\fs18 parent\n\\f4\\fs20  belongs is used to select which \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks are applicable; given the necessity of this information, \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks will not be called as a side effect of this method if \n\\f3\\fs18 parent\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 .  Apart from these two uses, \n\\f3\\fs18 parent\n\\f4\\fs20  is not used, and the caller does not guarantee that the generated breakpoints will actually be used to recombine the haplosomes of \n\\f3\\fs18 parent\n\\f4\\fs20  in particular.  If a \n\\f3\\fs18 recombination()\n\\f4\\fs20  callback is called, \n\\f3\\fs18 haplosome1\n\\f4\\fs20  for that callback will always be the first haplosome of \n\\f3\\fs18 parent\n\\f4\\fs20  for the chromosome; in other words, \n\\f3\\fs18 drawBreakpoints()\n\\f4\\fs20  will always treat the first haplosome of a homologous pair as the initial copy strand.  If the caller wishes to randomly choose an initial copy strand (which is usually desirable), they should do that themselves (note that the \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  and \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  methods have a flag to facilitate this).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<GenomicElement>)genomicElementForPosition(integer\\'a0positions)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of \n\\f3\\fs18 GenomicElement\n\\f4\\fs20  objects corresponding to the given vector \n\\f3\\fs18 positions\n\\f4\\fs20 , which contains base positions along the chromosome.  If every position lies within a defined genomic element, the returned vector will have the same length as \n\\f3\\fs18 positions\n\\f4\\fs20 , and will correspond one-to-one with it.  However, if a position in \n\\f3\\fs18 positions\n\\f4\\fs20  is not within a genomic element, no \n\\f3\\fs18 GenomicElement\n\\f4\\fs20  object will be present for it in the returned vector, and so the returned vector will no longer have the same length as \n\\f3\\fs18 positions\n\\f4\\fs20 , and will no longer correspond one-to-one with it.  The method \n\\f3\\fs18 hasGenomicElementForPosition()\n\\f4\\fs20  can be used to detect this circumstance.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(logical)hasGenomicElementForPosition(integer\\'a0positions)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a \n\\f3\\fs18 logical\n\\f4\\fs20  vector corresponding to the given vector \n\\f3\\fs18 positions\n\\f4\\fs20 , which contains base positions along the chromosome.  The returned vector will have the same length as \n\\f3\\fs18 positions\n\\f4\\fs20 , and will correspond one-to-one with it, containing \n\\f3\\fs18 T\n\\f4\\fs20  if the corresponding position lies inside a genomic element, or \n\\f3\\fs18 F\n\\f4\\fs20  if it does not.  The method \n\\f3\\fs18 genomicElementForPosition()\n\\f4\\fs20  can be used to look up the \n\\f3\\fs18 GenomicElement\n\\f4\\fs20  objects themselves.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(integer$)setAncestralNucleotides(is\\'a0sequence)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This method, which may be called only in nucleotide-based models, replaces the ancestral nucleotide sequence for the model.  The \n\\f3\\fs18 sequence\n\\f4\\fs20  parameter is interpreted exactly as it is in the \n\\f3\\fs18 initializeAncestralSequence()\n\\f4\\fs20  function; see that documentation for details.  The length of the ancestral sequence is returned.\\\nIt is unusual to replace the ancestral sequence in a running simulation, since the nucleotide states of segregating and fixed mutations will depend upon the original ancestral sequence.  It can be useful when loading a new population state with \n\\f3\\fs18 readHaplosomesFromMS()\n\\f4\\fs20  or \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20 , such as when resetting the simulation state to an earlier state in a conditional simulation; however, that is more commonly done using \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20  with a SLiM or \n\\f3\\fs18 .trees\n\\f4\\fs20  file.\n\\f1\\i \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(void)setGeneConversion(numeric$\\'a0nonCrossoverFraction, numeric$\\'a0meanLength, numeric$\\'a0simpleConversionFraction, [numeric$\\'a0bias\\'a0=\\'a00])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This method switches the recombination model to the \\'93double-stranded break (DSB)\\'94 model (if it is not already set to that), and configures the details of the gene conversion tracts that will therefore be modeled.  The meanings and effects of the parameters exactly mirror the \n\\f3\\fs18 initializeGeneConversion()\n\\f4\\fs20  function.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setHotspotMap(numeric\\'a0multipliers, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 In nucleotide-based models, set the mutation rate \n\\f1\\i multiplier\n\\f4\\i0  along the chromosome.  There are two ways to call this method.  If the optional \n\\f3\\fs18 ends\n\\f4\\fs20  parameter is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then \n\\f3\\fs18 multipliers\n\\f4\\fs20  must be a singleton value that specifies a single multiplier to be used along the entire chromosome.  If, on the other hand, \n\\f3\\fs18 ends\n\\f4\\fs20  is supplied, then \n\\f3\\fs18 multipliers\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  must be the same length, and the values in \n\\f3\\fs18 ends\n\\f4\\fs20  must be specified in ascending order.  In that case, \n\\f3\\fs18 multipliers\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  taken together specify the multipliers to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f3\\fs18 ends\n\\f4\\fs20  should extend to the end of the chromosome (as previously determined, during simulation initialization).  See the \n\\f3\\fs18 initializeHotspotMap()\n\\f4\\fs20  function for further discussion of precisely how these multipliers and positions are interpreted.\\\nIf the optional \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is \n\\f3\\fs18 \"*\"\n\\f4\\fs20  (the default), then the supplied hotspot map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f3\\fs18 sex\n\\f4\\fs20  may be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  instead, in which case the supplied hotspot map is used only for that sex.  Note that whether sex-specific hotspot maps will be used is set by the way that the simulation is initially configured with \n\\f3\\fs18 initializeHotspot()\n\\f4\\fs20 , and cannot be changed with this method; so if the simulation was set up to use sex-specific hotspot maps then sex must be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  here, whereas if it was set up not to, then sex must be \n\\f3\\fs18 \"*\"\n\\f4\\fs20  or unsupplied here.  If a simulation needs sex-specific hotspot maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.\\\nThe hotspot map is normally constant in simulations, so be sure you know what you are doing.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(void)setMutationRate(numeric\\'a0rates, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the mutation rate per base position per \\cf2 \\expnd0\\expndtw0\\kerning0\ngamete\\cf0 \\kerning1\\expnd0\\expndtw0 .  There are two ways to call this method.  If the optional \n\\f3\\fs18 ends\n\\f4\\fs20  parameter is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then \n\\f3\\fs18 rates\n\\f4\\fs20  must be a singleton value that specifies a single mutation rate to be used along the entire chromosome.  If, on the other hand, \n\\f3\\fs18 ends\n\\f4\\fs20  is supplied, then \n\\f3\\fs18 rates\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  must be the same length, and the values in \n\\f3\\fs18 ends\n\\f4\\fs20  must be specified in ascending order.  In that case, \n\\f3\\fs18 rates\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  taken together specify the mutation rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f3\\fs18 ends\n\\f4\\fs20  should extend to the end of the chromosome (as previously determined, during simulation initialization).  See the \n\\f3\\fs18 initializeMutationRate()\n\\f4\\fs20  function for further discussion of precisely how these rates and positions are interpreted.\\\nIf the optional \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is \n\\f3\\fs18 \"*\"\n\\f4\\fs20  (the default), then the supplied mutation rate map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f3\\fs18 sex\n\\f4\\fs20  may be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  instead, in which case the supplied mutation rate map is used only for that sex.  Note that whether sex-specific mutation rate maps will be used is set by the way that the simulation is initially configured with \n\\f3\\fs18 initializeMutationRate()\n\\f4\\fs20 , and cannot be changed with this method; so if the simulation was set up to use sex-specific mutation rate maps then sex must be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  here, whereas if it was set up not to, then sex must be \n\\f3\\fs18 \"*\"\n\\f4\\fs20  or unsupplied here.  If a simulation needs sex-specific mutation rate maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.\\\nThe mutation rate intervals are normally a constant in simulations, so be sure you know what you are doing.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn nucleotide-based models, \n\\f3\\fs18 setMutationRate()\n\\f4\\fs20  may not be called.  If variation in the mutation rate along the chromosome is desired, \n\\f3\\fs18 setHotspotMap()\n\\f4\\fs20  should be used.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(void)setRecombinationRate(numeric\\'a0rates, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the recombination rate per base position per \\cf2 \\expnd0\\expndtw0\\kerning0\ngamete\\cf0 \\kerning1\\expnd0\\expndtw0 .  \\cf2 \\expnd0\\expndtw0\\kerning0\nAll rates must be in the interval [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 0.5\n\\f4\\fs20 ].  \\cf0 \\kerning1\\expnd0\\expndtw0 There are two ways to call this method.  If the optional \n\\f3\\fs18 ends\n\\f4\\fs20  parameter is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then \n\\f3\\fs18 rates\n\\f4\\fs20  must be a singleton value that specifies a single recombination rate to be used along the entire chromosome.  If, on the other hand, \n\\f3\\fs18 ends\n\\f4\\fs20  is supplied, then \n\\f3\\fs18 rates\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  must be the same length, and the values in \n\\f3\\fs18 ends\n\\f4\\fs20  must be specified in ascending order.  In that case, \n\\f3\\fs18 rates\n\\f4\\fs20  and \n\\f3\\fs18 ends\n\\f4\\fs20  taken together specify the recombination rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f3\\fs18 ends\n\\f4\\fs20  should extend to the end of the chromosome (as previously determined, during simulation initialization).  See the \n\\f3\\fs18 initializeRecombinationRate()\n\\f4\\fs20  function for further discussion of precisely how these rates and positions are interpreted.\\\nIf the optional \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is \n\\f3\\fs18 \"*\"\n\\f4\\fs20  (the default), then the supplied recombination rate map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f3\\fs18 sex\n\\f4\\fs20  may be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  instead, in which case the supplied recombination map is used only for that sex.  Note that whether sex-specific recombination maps will be used is set by the way that the simulation is initially configured with \n\\f3\\fs18 initializeRecombinationRate()\n\\f4\\fs20 , and cannot be changed with this method; so if the simulation was set up to use sex-specific recombination maps then sex must be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  here, whereas if it was set up not to, then sex must be \n\\f3\\fs18 \"*\"\n\\f4\\fs20  or unsupplied here.  If a simulation needs sex-specific recombination maps only some of the time, the male and female maps can simply be set to be identical the rest of the time.\\\nThe recombination intervals are normally a constant in simulations, so be sure you know what you are doing.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.3  Class Community\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.3.1  \n\\f2\\fs18 Community\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 allGenomicElementTypes => (object<GenomicElementType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  objects defined in the simulation.  These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 allInteractionTypes => (object<InteractionType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  objects defined in the simulation.  These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 allMutationTypes => (object<MutationType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects defined in the simulation.  These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 allScriptBlocks => (object<SLiMEidosBlock>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects in the simulation.  These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 allSpecies => (object<Species>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 Species\n\\f4\\fs20  objects defined in the simulation (in species declaration order).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 allSubpopulations => (object<Subpopulation>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects defined in the simulation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 cycleStage => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The current cycle stage, as a \n\\f3\\fs18 string\n\\f4\\fs20 .  The values of this property essentially mirror the cycle stages of WF and nonWF models.  Common values include \n\\f3\\fs18 \"first\"\n\\f4\\fs20  (during execution of \n\\f3\\fs18 first()\n\\f4\\fs20  events), \n\\f3\\fs18 \"early\"\n\\f4\\fs20  (during execution of \n\\f3\\fs18 early()\n\\f4\\fs20  events), \n\\f3\\fs18 \"reproduction\"\n\\f4\\fs20  (during offspring generation), \n\\f3\\fs18 \"fitness\"\n\\f4\\fs20  (during fitness evaluation), \n\\f3\\fs18 \"survival\"\n\\f4\\fs20  (while applying selection and mortality in nonWF models), and \n\\f3\\fs18 \"late\"\n\\f4\\fs20  (during execution of \n\\f3\\fs18 late()\n\\f4\\fs20  events).\\\nOther possible values include \n\\f3\\fs18 \"begin\"\n\\f4\\fs20  (during internal setup before each cycle), \n\\f3\\fs18 \"tally\"\n\\f4\\fs20  (while tallying mutation reference counts and removing fixed mutations), \n\\f3\\fs18 \"swap\"\n\\f4\\fs20  (while swapping the offspring generation into the parental generation in WF models), \n\\f3\\fs18 \"end\"\n\\f4\\fs20  (during internal bookkeeping after each cycle), and \n\\f3\\fs18 \"console\"\n\\f4\\fs20  (during the in-between-ticks state in which commands in SLiMgui\\'92s Eidos console are executed).  It would probably be a good idea not to use this latter set of values; they are probably not user-visible during ordinary model execution anyway.\\\nDuring execution of \n\\f3\\fs18 initialize()\n\\f4\\fs20  callbacks, no \n\\f3\\fs18 Community\n\\f4\\fs20  object yet exists and so this property cannot be accessed.  To detect this state, use \n\\f3\\fs18 exists(\"community\")\n\\f4\\fs20 ; if that is \n\\f3\\fs18 F\n\\f4\\fs20 , \n\\f3\\fs18 community\n\\f4\\fs20  does not exist, and therefore your code is executing during \n\\f3\\fs18 initialize()\n\\f4\\fs20  callbacks (or outside of SLiM entirely, in some other Eidos-based context).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 logFiles => (object<LogFile>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 LogFile\n\\f4\\fs20  objects being used in the simulation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 modelType => (string$)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe type of model being simulated, as specified in \n\\f3\\fs18 initializeSLiMModelType()\n\\f4\\fs20 .  This will be \n\\f3\\fs18 \"WF\"\n\\f4\\fs20  for WF models (Wright-Fisher models, the default), or \n\\f3\\fs18 \"nonWF\"\n\\f4\\fs20  for nonWF models (non-Wright-Fisher models).\\kerning1\\expnd0\\expndtw0   This must be the same for all species in the community; it is therefore a property on \n\\f3\\fs18 Community\n\\f4\\fs20 , not \n\\f3\\fs18 Species\n\\f4\\fs20 .\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to the simulation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tick <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The current tick number.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 verbosity <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The verbosity level, for SLiM\\'92s logging of information about the simulation.  This is \n\\f3\\fs18 1\n\\f4\\fs20  by default, but can be changed at the command line with the \n\\f3\\fs18 -l[ong]\n\\f4\\fs20  option.  It is provided here so that scripts can consult it to govern the level of verbosity of their own output, or set the verbosity level for particular sections of their code.  A verbosity level of 0 suppresses most of SLiM\\'92s optional output; 2 adds some extra output beyond SLiM\\'92s standard output.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.3.2  \n\\f2\\fs18 Community\n\\f1\\fs22  methods\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(object<LogFile>$)createLogFile(string$\\'a0filePath, [Ns\\'a0initialContents\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [logical$\\'a0compress\\'a0=\\'a0F], [string$\\'a0sep\\'a0=\\'a0\",\"], [Ni$\\'a0logInterval\\'a0=\\'a0NULL], [Ni$\\'a0flushInterval\\'a0=\\'a0NULL], [logical$\\'a0header\\'a0=\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Creates and returns a new \n\\f3\\fs18 LogFile\n\\f4\\fs20  object that logs data from the simulation (see the documentation for the \n\\f3\\fs18 LogFile\n\\f4\\fs20  class for details).  Logged data will be written to the file at \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting any existing file at that path by default, or appending to it instead if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (successive rows of the log table will always be appended to the previously written content, of course).  Before the header line for the log is written out, any \n\\f3\\fs18 string\n\\f4\\fs20  elements in \n\\f3\\fs18 initialContents\n\\f4\\fs20  will be written first, separated by newlines, allowing for a user-defined file header.  If \n\\f3\\fs18 compress\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , the contents will be compressed with \n\\f3\\fs18 zlib\n\\f4\\fs20  as they are written, and the standard \n\\f3\\fs18 .gz\n\\f4\\fs20  extension for gzip-compressed files will be appended to the filename in \n\\f3\\fs18 filePath\n\\f4\\fs20  if it is not already present.\\\nThe \n\\f3\\fs18 sep\n\\f4\\fs20  parameter specifies the separator between data values within a row.  The default of \n\\f3\\fs18 \",\"\n\\f4\\fs20  will generate a \\'93comma-separated value\\'94 (CSV) file, while passing \n\\f3\\fs18 sep=\"\\\\t\"\n\\f4\\fs20  will use a tab separator instead to generate a \\'93tab-separated value\\'94 (TSV) file.  Other values for \n\\f3\\fs18 sep\n\\f4\\fs20  may also be used, but are less standard.\\\nLogTable supports periodic automatic logging of a new row of data, enabled by supplying a non-\n\\f3\\fs18 NULL\n\\f4\\fs20  value for \n\\f3\\fs18 logInterval\n\\f4\\fs20 .  In this case, a new row will be logged (as if \n\\f3\\fs18 logRow()\n\\f4\\fs20  were called on the \n\\f3\\fs18 LogFile\n\\f4\\fs20 ) at the end of every \n\\f3\\fs18 logInterval\n\\f4\\fs20  ticks (just before the tick counter increments, in both WF and nonWF models), starting at the end of the tick in which the \n\\f3\\fs18 LogFile\n\\f4\\fs20  was created.  A \n\\f3\\fs18 logInterval\n\\f4\\fs20  of \n\\f3\\fs18 1\n\\f4\\fs20  will cause automatic logging at the end of every tick, whereas a \n\\f3\\fs18 logInterval\n\\f4\\fs20  of \n\\f3\\fs18 NULL\n\\f4\\fs20  disables automatic logging.  Automatic logging can always be disabled or reconfigured later with the \n\\f3\\fs18 LogFile\n\\f4\\fs20  method \n\\f3\\fs18 setLogInterval()\n\\f4\\fs20 , or logging can be triggered manually by calling \n\\f3\\fs18 logRow()\n\\f4\\fs20 .\\\nWhen compression is enabled, \n\\f3\\fs18 LogFile\n\\f4\\fs20  flushes new data lazily by default, for performance reasons, buffering data for multiple rows before writing to disk.  Passing a non-\n\\f3\\fs18 NULL\n\\f4\\fs20  value for \n\\f3\\fs18 flushInterval\n\\f4\\fs20  requests a flush every \n\\f3\\fs18 flushInterval\n\\f4\\fs20  rows (with a value of \n\\f3\\fs18 1\n\\f4\\fs20  providing unbuffered operation).  Note that flushing very frequently will likely result in both lower performance and a larger final file size (in one simple test, \n\\f3\\fs18 48943\n\\f4\\fs20  bytes instead of \n\\f3\\fs18 4280\n\\f4\\fs20  bytes, or more than a 10\\'d7 increase in size).  Alternatively, passing a very large value for \n\\f3\\fs18 flushInterval\n\\f4\\fs20  will effectively disable automatic flushing, except at the end of the simulation (but be aware that this may use a large amount of memory for large log files).  In any case, the log file will be created immediately, with its requested initial contents; the initial write is not buffered.  When compression is not enabled, the \n\\f3\\fs18 flushInterval\n\\f4\\fs20  setting is ignored.\\\nThe \n\\f3\\fs18 header\n\\f4\\fs20  parameter controls whether a header line is written out at the beginning of logging.  If it is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), a header line is written out; if \n\\f3\\fs18 F\n\\f4\\fs20 , no header is written.  Suppressing the header output can be useful if you are using \n\\f3\\fs18 LogFile\n\\f4\\fs20  to append data to an existing file that already has a header line.\\\nThe \n\\f3\\fs18 LogFile\n\\f4\\fs20  documentation discusses how to configure and use \n\\f3\\fs18 LogFile\n\\f4\\fs20  to write out the data you are interested in from your simulation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(integer$)estimatedLastTick(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns SLiM\\'92s current estimate of the last tick in which the model will execute.  Because script blocks can be added, removed, and rescheduled, and because the simulation may end prematurely (due to a call to \n\\f3\\fs18 simulationFinished()\n\\f4\\fs20 , for example), this is only an estimate, and may change over time.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)deregisterScriptBlock(io<SLiMEidosBlock>\\'a0scriptBlocks)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 All \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects specified by \n\\f3\\fs18 scriptBlocks\n\\f4\\fs20  (either with \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects or with \n\\f3\\fs18 integer\n\\f4\\fs20  identifiers) will be scheduled for deregistration.  The deregistered blocks remain valid, and may even still be executed in the current stage of the current tick; the blocks are not actually deregistered and deallocated until sometime after the currently executing script block has completed.  To immediately prevent a script block from executing, even when it is scheduled to execute in the current stage of the current tick, use the \n\\f3\\fs18 active\n\\f4\\fs20  property of the script block.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<GenomicElementType>)genomicElementTypesWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<InteractionType>)interactionTypesWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 InteractionType\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<MutationType>)mutationTypesWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 MutationType\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(void)outputUsage(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Output the current memory usage of the simulation to Eidos\\'92s output stream.  The specifics of what is printed, and in what format, should not be relied upon as they may change from version to version of SLiM.  This method is primarily useful for understanding where the memory usage of a simulation predominantly resides, for debugging or optimization.  Note that it does not capture \n\\f1\\i all\n\\f4\\i0  memory usage by the process; rather, it summarizes the memory usage by SLiM and Eidos in directly allocated objects and buffers.  To get the same memory usage reported by \n\\f3\\fs18 outputUsage()\n\\f4\\fs20 , but as a \n\\f3\\fs18 float$\n\\f4\\fs20  value, use the \n\\f3\\fs18 Community\n\\f4\\fs20  method \n\\f3\\fs18 usage()\n\\f4\\fs20 .  To get the \n\\f1\\i total\n\\f4\\i0  memory usage of the running process (either current or peak), use the Eidos function \n\\f3\\fs18 usage()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerEarlyEvent(Nis$\\'a0id, string$\\'a0source, [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL]\\cf2 , [No<Species>$\\'a0ticksSpec\\'a0=\\'a0NULL]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 early()\n\\f4\\fs20  event in the current simulation, with optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks\\cf2  (and, for multispecies models, optional ticks specifier \n\\f3\\fs18 ticksSpec\n\\f4\\fs20 )\\cf0  limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered event is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SLiMEidosBlock>$)registerFirstEvent(Nis$\\'a0id, string$\\'a0source, [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [No<Species>$\\'a0ticksSpec\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 first()\n\\f4\\fs20  event in the current simulation, with optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks (and, for multispecies models, optional ticks specifier \n\\f3\\fs18 ticksSpec\n\\f4\\fs20 ) limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered event is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerInteractionCallback(Nis$\\'a0id, string$\\'a0source, io<InteractionType>$\\'a0intType, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 interaction()\n\\f4\\fs20  callback in the current simulation\\cf2  (global to the community)\\cf0 , with a required interaction type \n\\f3\\fs18 intType\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier), optional exerter subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may also be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations), and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it will be eligible to execute the next time an \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is evaluated.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerLateEvent(Nis$\\'a0id, string$\\'a0source, [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL]\\cf2 , [No<Species>$\\'a0ticksSpec\\'a0=\\'a0NULL]\\cf0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 late()\n\\f4\\fs20  event in the current simulation, with optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks\\cf2  (and, for multispecies models, optional ticks specifier \n\\f3\\fs18 ticksSpec\n\\f4\\fs20 )\\cf0  limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered event is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SLiMEidosBlock>$)rescheduleScriptBlock(io<SLiMEidosBlock>$\\'a0block, [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [Ni\\'a0ticks\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Reschedule the target script block given by \n\\f3\\fs18 block\n\\f4\\fs20  to execute in a specified set of ticks.  The \n\\f3\\fs18 block\n\\f4\\fs20  parameter may be either an \n\\f3\\fs18 integer\n\\f4\\fs20  representing the ID of the desired script block, or a \n\\f3\\fs18 SLiMScriptBlock\n\\f4\\fs20  specified directly.  The target script block, \n\\f3\\fs18 block\n\\f4\\fs20 , is returned.\\\nThe first way to specify the tick set is with \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  parameter values; \n\\f3\\fs18 block\n\\f4\\fs20  will then execute from \n\\f3\\fs18 start\n\\f4\\fs20  to \n\\f3\\fs18 end\n\\f4\\fs20 , inclusive.\\\nThe second way to specify the tick set is using the \n\\f3\\fs18 ticks\n\\f4\\fs20  parameter, specifying each tick in which the block should execute.  The vector supplied for \n\\f3\\fs18 ticks\n\\f4\\fs20  does not need to be in sorted order, but it must not contain any duplicates.\\\nIt can sometimes be better to handle script block scheduling in other ways.  If an \n\\f3\\fs18 early()\n\\f4\\fs20  event needs to execute every tenth tick over the whole duration of a long model run, for example, it might not be advisable to use a call like \n\\f3\\fs18 community.rescheduleScriptBlock(s1, ticks=seq(10, 100000, 10))\n\\f4\\fs20  for that purpose, since that would make things complicated for SLiM\\'92s scheduler.  Instead, it might be preferable to add a test such as \n\\f3\\fs18 if (community.tick % 10 != 0) return;\n\\f4\\fs20  at the beginning of the event.  It is legal to reschedule a script block while the block is executing; a call like \n\\f3\\fs18 community.rescheduleScriptBlock(self, community.tick + 10, community.tick + 10);\n\\f4\\fs20  made inside a given block would therefore also cause the block to execute every tenth tick, although this sort of self-rescheduling code is probably harder to read, maintain, and debug.\\\nWhichever way of specifying the tick set is used, \n\\f3\\fs18 block\n\\f4\\fs20  may continue to be executed during the current tick cycle stage even after it has been rescheduled, unless it is made inactive using its \n\\f3\\fs18 active\n\\f4\\fs20  property, and similarly, the block may not execute during the current tick cycle stage if it was not already scheduled to do so.  Rescheduling script blocks during the tick and tick cycle stage in which they are executing, or in which they are intended to execute, should be avoided.  Also, note that script blocks which are open-ended (i.e., with no specified end tick), are not used in determining whether the end of the simulation has been reached (because then the simulation would run forever).\\\nNote that new script blocks can also be created and scheduled using the \n\\f3\\fs18 register...()\n\\f4\\fs20  methods of \n\\f3\\fs18 Community\n\\f4\\fs20  and \n\\f3\\fs18 Species\n\\f4\\fs20 ; by using the same source as a template script block, the template can be duplicated and scheduled for different ticks, perhaps with modifications or variations.  In multispecies models, note that blocks may not run due to their \n\\f3\\fs18 species\n\\f4\\fs20  or \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier, even in ticks in which they are scheduled to run.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SLiMEidosBlock>)scriptBlocksWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)simulationFinished(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Declare the current simulation finished.  Normally SLiM ends a simulation when, at the end of a tick, there are no script events or callbacks registered for any future tick (excluding scripts with no declared end tick).  If you wish to end a simulation before this condition is met, a call to \n\\f3\\fs18 simulationFinished()\n\\f4\\fs20  will cause the current simulation to end at the end of the current tick.  For example, a simulation might self-terminate if a test for a dynamic equilibrium condition is satisfied.  Note that the current tick will finish executing; if you want the simulation to stop immediately, you can use the Eidos method \n\\f3\\fs18 stop()\n\\f4\\fs20 , which raises an error condition.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Species>)speciesWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 Species\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 Species\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Subpopulation>)subpopulationsWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects with \n\\f3\\fs18 id\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 ids\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object can be found with a given \n\\f3\\fs18 id\n\\f4\\fs20 , an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Subpopulation>)subpopulationsWithNames(string\\'a0names)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Find and return the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects with \n\\f3\\fs18 name\n\\f4\\fs20  values matching the values in \n\\f3\\fs18 names\n\\f4\\fs20 .  If no matching \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object can be found with a given name, an error results.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float$)usage(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Return the current memory usage of the simulation.  The specifics of what is totalled up should not be relied upon as it may change from version to version of SLiM.  This method is primarily useful for understanding where the memory usage of a simulation predominantly resides, for debugging or optimization.  Note that it does not capture \n\\f1\\i all\n\\f4\\i0  memory usage by the process; rather, it summarizes the memory usage by SLiM and Eidos in directly allocated objects and buffers.  To see details of this internal memory usage, use the \n\\f3\\fs18 Community\n\\f4\\fs20  method \n\\f3\\fs18 outputUsage()\n\\f4\\fs20 .  To get the \n\\f1\\i total\n\\f4\\i0  memory usage of the running process (either current or peak), use the Eidos function \n\\f3\\fs18 usage()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.4  Class Haplosome\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.4.1  \n\\f2\\fs18 Haplosome\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 chromosome => (object<Chromosome>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object which this haplosome represents; for example, if this haplosome represents the X sex chromosome in a particular individual, then this property provides the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object that defines the genetic structure of the X sex chromosome in that individual\\'92s species.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 chromosomeSubposition => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The position index of the haplosome, within the set of haplosomes associated with the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object which this haplosome represents.  For example, if an individual in a multi-chromosome model has two haplosomes that represent a given chromosome within its \n\\f3\\fs18 haplosomes\n\\f4\\fs20  vector, the first of those haplosomes will have a \n\\f3\\fs18 chromosomeSubposition\n\\f4\\fs20  value of \n\\f3\\fs18 0\n\\f4\\fs20 , the second will have a \n\\f3\\fs18 chromosomeSubposition\n\\f4\\fs20  value of \n\\f3\\fs18 1\n\\f4\\fs20 .  For an intrinsically diploid chromosome in individuals generated by a standard biparental cross, the first haplosome (at subposition \n\\f3\\fs18 0\n\\f4\\fs20 ) came from its first parent (the female parent, in sexual models), and the second haplosome (at subposition \n\\f3\\fs18 1\n\\f4\\fs20 ) came from its second parent (the male parent, in sexual models).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nhaplosomePedigreeID => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20  or tree-sequence recording is turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 , \n\\f3\\fs18 haplosomePedigreeID\n\\f4\\fs20  is a \\'93semi-unique\\'94 non-negative identifier for each haplosome in a simulation, never re-used throughout the duration of the simulation run.  The \n\\f3\\fs18 haplosomePedigreeID\n\\f4\\fs20  of a given haplosome will be equal to either \n\\f3\\fs18 (2*pedigreeID)\n\\f4\\fs20  or \n\\f3\\fs18 (2*pedigreeID + 1)\n\\f4\\fs20  of the individual that the haplosome belongs to (the former for a first haplosome of the individual, the latter for a second haplosome of the individual if one exists); this invariant relationship is guaranteed.\\\nThis value is \\'93semi-unique\\'94 in the sense that it is shared by \n\\f1\\i all\n\\f4\\i0  of the first haplosomes of an individual, or by \n\\f1\\i all\n\\f4\\i0  of the second haplosomes of an individual.  In a single-chromosome model, a given individual will have just one first haplosome, and perhaps (depending on the chromosome type) one second haplosome, and so the value of \n\\f3\\fs18 haplosomePedigreeID\n\\f4\\fs20  for each of those haplosomes will be truly unique.  In a multi-chromosome model, however, an individual has a first haplosome for each chromosome, and perhaps (depending on the chromosome types) a second haplosome for each chromosome.  In that case, the value of \n\\f3\\fs18 haplosomePedigreeID\n\\f4\\fs20  is unique in the sense that it is different for each individual, but it is \n\\f1\\i not\n\\f4\\i0  unique in the sense that it will be shared by other haplosomes within the same individual \\'96 shared by all the first haplosomes, or shared by all the second haplosomes.  This \\'93semi-uniqueness\\'94 is intentional; it allows \n\\f3\\fs18 haplosomePedigreeID\n\\f4\\fs20  to be used as a \\'93key\\'94 that associates the haplosomes of an individual across disparate datasets, such as across the different tree sequences for each chromosome that are produced by tree-sequence recording in a multi-chromosome model.  See sections 1.5.1 and 8.3 for further discussion of multi-chromosome models.\\\nIf neither pedigree tracking nor tree-sequence recording is enabled, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nindividual => (object<Individual>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Individual\n\\f4\\fs20  object to which this haplosome belongs.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 isNullHaplosome => (logical$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 T\n\\f4\\fs20  if the haplosome is a \\'93null\\'94 haplosome, \n\\f3\\fs18 F\n\\f4\\fs20  if it is an ordinary haplosome object.  Null haplosomes are used as placeholders when a real haplosome doesn\\'92t exist in a particular slot, allowing SLiM\\'92s code to operate in the same way across a wide variety of genomic configurations.  For example, when simulating chromosome type \n\\f3\\fs18 \"X\"\n\\f4\\fs20  (an X chromosome), the second haplosome for that chromosome in males will be a null haplosome, preserving a constant number of haplosomes for all individuals even though males have one X while females have two.  Null haplosomes should not be accessed or manipulated.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mutationCount => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The number of \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects present in this haplosome.  This property is provided as a convenience, and for efficiency; the result of \n\\f3\\fs18 haplosome.mutationCount\n\\f4\\fs20  will be equal to \n\\f3\\fs18 size(haplosome.mutations)\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 mutations => (object<Mutation>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects present in this haplosome.  If you only need the number of mutations present, use the \n\\f3\\fs18 mutationCount\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  Note that the \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects used by SLiM are new with every new individual, so the \n\\f3\\fs18 tag\n\\f4\\fs20  value of each new offspring haplosome generated in each tick will be initially undefined.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.4.2  \n\\f2\\fs18 Haplosome\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 +\\'a0(void)addMutations(object<Mutation>\\'a0mutations)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Add the existing mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  to the target haplosomes, if they are not already present (if they are already present, they will be ignored), and if the addition is not prevented by the mutation stacking policy (see the \n\\f3\\fs18 mutationStackPolicy\n\\f4\\fs20  property of \n\\f3\\fs18 MutationType\n\\f4\\fs20 ).  All target haplosomes and all mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  must be associated with the same \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object; attempting to add a mutation to a haplosome associated with a different chromosome will raise an error.\\\nCalling this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\nNote that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the \n\\f3\\fs18 age\n\\f4\\fs20  of the individual is greater than \n\\f3\\fs18 0\n\\f4\\fs20 ), to prevent the possibility of inconsistencies in the recorded tree sequence.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 +\\'a0(object<Mutation>)addNewDrawnMutation(io<MutationType>\\'a0mutationType, integer\\'a0position, [Nio<Subpopulation>\\'a0originSubpop\\'a0=\\'a0NULL]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [Nis\\'a0nucleotide\\'a0=\\'a0NULL]\\cf0 \\kerning1\\expnd0\\expndtw0 )\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Add new mutations to the target haplosomes with the specified \n\\f3\\fs18 mutationType\n\\f4\\fs20  (specified by the \n\\f3\\fs18 MutationType\n\\f4\\fs20  object or by \n\\f3\\fs18 integer\n\\f4\\fs20  identifier), \n\\f3\\fs18 position\n\\f4\\fs20 , \n\\f3\\fs18 originTick\n\\f4\\fs20  (which may be \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to specify the current tick; otherwise, beginning in SLiM 3.5, it must be equal to the current tick anyway, as other uses of this property have been deprecated), and \n\\f3\\fs18 originSubpop\n\\f4\\fs20  (specified by the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object or by \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or by \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to specify the subpopulation to which the first target haplosome belongs).  If \n\\f3\\fs18 originSubpop\n\\f4\\fs20  is supplied as an \n\\f3\\fs18 integer\n\\f4\\fs20 , it is intentionally not checked for validity; you may use arbitrary values of \n\\f3\\fs18 originSubpop\n\\f4\\fs20  to \\'93tag\\'94 the mutations that you create.  The selection coefficients of the mutations are drawn from their mutation types; \n\\f3\\fs18 addNewMutation()\n\\f4\\fs20  may be used instead if you wish to specify selection coefficients.  All of the target haplosomes must be associated with the same \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object, since each new mutation is added to all of the target haplosomes.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn non-nucleotide-based models, \n\\f3\\fs18 mutationType\n\\f4\\fs20  will always be a non-nucleotide-based mutation type, and so \n\\f3\\fs18 nucleotide\n\\f4\\fs20  must be \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default).  In a nucleotide-based model, \n\\f3\\fs18 mutationType\n\\f4\\fs20  might still be non-nucleotide-based (in which case \n\\f3\\fs18 nucleotide\n\\f4\\fs20  must still be \n\\f3\\fs18 NULL\n\\f4\\fs20 ), or \n\\f3\\fs18 mutationType\n\\f4\\fs20  might be nucleotide-based, in which case a non-\n\\f3\\fs18 NULL\n\\f4\\fs20  value must be supplied for \n\\f3\\fs18 nucleotide\n\\f4\\fs20 , specifying the nucleotide(s) to be associated with the new mutation(s).  Nucleotides may be specified with string values (\n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"C\"\n\\f4\\fs20 , \n\\f3\\fs18 \"G\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"T\"\n\\f4\\fs20 ), or with integer values (A=\n\\f3\\fs18 0\n\\f4\\fs20 , C=\n\\f3\\fs18 1\n\\f4\\fs20 , G=\n\\f3\\fs18 2\n\\f4\\fs20 , T=\n\\f3\\fs18 3\n\\f4\\fs20 ).  If a nucleotide mutation already exists at the mutating position, it is replaced automatically in accordance with the stacking policy for nucleotide-based mutation types.  No check is performed that a new mutation\\'92s nucleotide differs from the ancestral sequence, or that its selection coefficient is consistent with other mutations that may already exist at the given position with the same nucleotide; model consistency is the responsibility of the model.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 Beginning in SLiM 2.5 this method is vectorized, so all of these parameters may be singletons (in which case that single value is used for all mutations created by the call) or non-singleton vectors (in which case one element is used for each corresponding mutation created).  Non-singleton parameters must match in length, since their elements need to be matched up one-to-one.\\\nThe new mutations created by this method are returned, even if their actual addition is prevented by the mutation stacking policy (see the \n\\f3\\fs18 mutationStackPolicy\n\\f4\\fs20  property of \n\\f3\\fs18 MutationType\n\\f4\\fs20 ).  However, the order of the mutations in the returned vector is not guaranteed to be the same as the order in which the values are specified in parameter vectors, unless the \n\\f3\\fs18 position\n\\f4\\fs20  parameter is specified in ascending order.  In other words, pre-sorting the parameters to this method into ascending order by position, using \n\\f3\\fs18 order()\n\\f4\\fs20  and subsetting, will guarantee that the order of the returned vector of mutations corresponds to the order of elements in the parameters to this method; otherwise, no such guarantee exists.\\\nBeginning in SLiM 2.1, this is a class method, not an instance method.  This means that it does not get multiplexed out to all of the elements of the receiver (which would add a different new mutation to each element); instead, it is performed as a single operation, adding the same new mutation objects to all of the elements of the receiver.  Before SLiM 2.1, to add the same mutations to multiple haplosomes, it was necessary to call \n\\f3\\fs18 addNewDrawnMutation()\n\\f4\\fs20  on one of the haplosomes, and then add the returned \n\\f3\\fs18 Mutation\n\\f4\\fs20  object to all of the other haplosomes using \n\\f3\\fs18 addMutations()\n\\f5\\fs20 .\n\\f4   That is not necessary in SLiM 2.1 and later, because of this change (although doing it the old way does no harm and produces identical behavior).  Pre-2.1 code that actually relied upon the old multiplexing behavior will no longer work correctly (but this is expected to be an extremely rare pattern of usage).\\\n\\pard\\pardeftab720\\li547\\ri720\\sa60\\partightenfactor0\n\\cf2 Before SLiM 4, this method also took a \n\\f3\\fs18 originGeneration\n\\f4\\fs20  parameter.  This was deprecated (the origin generation was then required to be equal to the current generation, for internal consistency), and was removed in SLiM 4.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Calling this will normally affect the fitness values calculated at the end of the current tick (but not sooner); if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Note that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the \n\\f3\\fs18 age\n\\f4\\fs20  of the individual is greater than \n\\f3\\fs18 0\n\\f4\\fs20 ), to prevent the possibility of inconsistencies in the recorded tree sequence.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 +\\'a0(object<Mutation>)addNewMutation(io<MutationType>\\'a0mutationType, numeric\\'a0selectionCoeff, integer\\'a0position, [Nio<Subpopulation>\\'a0originSubpop\\'a0=\\'a0NULL]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [Nis\\'a0nucleotide\\'a0=\\'a0NULL]\\cf0 \\kerning1\\expnd0\\expndtw0 )\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Add new mutations to the target haplosomes with the specified \n\\f3\\fs18 mutationType\n\\f4\\fs20  (specified by the \n\\f3\\fs18 MutationType\n\\f4\\fs20  object or by \n\\f3\\fs18 integer\n\\f4\\fs20  identifier), \n\\f3\\fs18 selectionCoeff\n\\f4\\fs20 , \n\\f3\\fs18 position\n\\f4\\fs20 , \n\\f3\\fs18 originTick\n\\f4\\fs20  (which may be \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to specify the current tick; otherwise, beginning in SLiM 3.5, it must be equal to the current tick anyway, as other uses of this property have been deprecated), and \n\\f3\\fs18 originSubpop\n\\f4\\fs20  (specified by the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object or by \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or by \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to specify the subpopulation to which the first target haplosome belongs).  If \n\\f3\\fs18 originSubpop\n\\f4\\fs20  is supplied as an \n\\f3\\fs18 integer\n\\f4\\fs20 , it is intentionally not checked for validity; you may use arbitrary values of \n\\f3\\fs18 originSubpop\n\\f4\\fs20  to \\'93tag\\'94 the mutations that you create.  The \n\\f3\\fs18 addNewDrawnMutation()\n\\f4\\fs20  method may be used instead if you wish selection coefficients to be drawn from the mutation types of the mutations.  All of the target haplosomes must be associated with the same \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object, since each new mutation is added to all of the target haplosomes.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn non-nucleotide-based models, \n\\f3\\fs18 mutationType\n\\f4\\fs20  will always be a non-nucleotide-based mutation type, and so \n\\f3\\fs18 nucleotide\n\\f4\\fs20  must be \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default).  In a nucleotide-based model, \n\\f3\\fs18 mutationType\n\\f4\\fs20  might still be non-nucleotide-based (in which case \n\\f3\\fs18 nucleotide\n\\f4\\fs20  must still be \n\\f3\\fs18 NULL\n\\f4\\fs20 ), or \n\\f3\\fs18 mutationType\n\\f4\\fs20  might be nucleotide-based, in which case a non-\n\\f3\\fs18 NULL\n\\f4\\fs20  value must be supplied for \n\\f3\\fs18 nucleotide\n\\f4\\fs20 , specifying the nucleotide(s) to be associated with the new mutation(s).  Nucleotides may be specified with string values (\n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"C\"\n\\f4\\fs20 , \n\\f3\\fs18 \"G\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"T\"\n\\f4\\fs20 ), or with integer values (A=\n\\f3\\fs18 0\n\\f4\\fs20 , C=\n\\f3\\fs18 1\n\\f4\\fs20 , G=\n\\f3\\fs18 2\n\\f4\\fs20 , T=\n\\f3\\fs18 3\n\\f4\\fs20 ).  If a nucleotide mutation already exists at the mutating position, it is replaced automatically in accordance with the stacking policy for nucleotide-based mutation types.  No check is performed that a new mutation\\'92s nucleotide differs from the ancestral sequence, or that its selection coefficient is consistent with other mutations that may already exist at the given position with the same nucleotide; model consistency is the responsibility of the model.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 The new mutations created by this method are returned, even if their actual addition is prevented by the mutation stacking policy (see the \n\\f3\\fs18 mutationStackPolicy\n\\f4\\fs20  property of \n\\f3\\fs18 MutationType\n\\f4\\fs20 ).  However, the order of the mutations in the returned vector is not guaranteed to be the same as the order in which the values are specified in parameter vectors, unless the \n\\f3\\fs18 position\n\\f4\\fs20  parameter is specified in ascending order.  In other words, pre-sorting the parameters to this method into ascending order by position, using \n\\f3\\fs18 order()\n\\f4\\fs20  and subsetting, will guarantee that the order of the returned vector of mutations corresponds to the order of elements in the parameters to this method; otherwise, no such guarantee exists.\\\nBeginning in SLiM 2.1, this is a class method, not an instance method.  This means that it does not get multiplexed out to all of the elements of the receiver (which would add a different new mutation to each element); instead, it is performed as a single operation, adding the same new mutation object to all of the elements of the receiver.  Before SLiM 2.1, to add the same mutation to multiple haplosomes, it was necessary to call \n\\f3\\fs18 addNewMutation()\n\\f4\\fs20  on one of the haplosomes, and then add the returned \n\\f3\\fs18 Mutation\n\\f4\\fs20  object to all of the other haplosomes using \n\\f3\\fs18 addMutations()\n\\f5\\fs20 .\n\\f4   That is not necessary in SLiM 2.1 and later, because of this change (although doing it the old way does no harm and produces identical behavior).  Pre-2.1 code that actually relied upon the old multiplexing behavior will no longer work correctly (but this is expected to be an extremely rare pattern of usage).\\\n\\pard\\pardeftab720\\li547\\ri720\\sa60\\partightenfactor0\n\\cf2 Before SLiM 4, this method also took a \n\\f3\\fs18 originGeneration\n\\f4\\fs20  parameter.  This was deprecated (the origin generation was then required to be equal to the current generation, for internal consistency), and was removed in SLiM 4.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Calling this will normally affect the fitness values calculated at the end of the current tick (but not sooner); if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Note that in nonWF models that use tree-sequence recording, mutations cannot be added to an individual after the tick in which the individual is created (i.e., when the \n\\f3\\fs18 age\n\\f4\\fs20  of the individual is greater than \n\\f3\\fs18 0\n\\f4\\fs20 ), to prevent the possibility of inconsistencies in the recorded tree sequence.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (\\cf2 \\expnd0\\expndtw0\\kerning0\nNlo<Mutation>$\\cf0 \\kerning1\\expnd0\\expndtw0 )containsMarkerMutation(io<MutationType>$\\'a0mutType, integer$\n\\f5 \\'a0\n\\f3 position\\cf2 \\expnd0\\expndtw0\\kerning0\n, [logical$\\'a0returnMutation\\'a0=\\'a0F]\\cf0 \\kerning1\\expnd0\\expndtw0 )\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns \n\\f3\\fs18 T\n\\f4\\fs20  if the haplosome contains a mutation of type \n\\f3\\fs18 mutType\n\\f4\\fs20  at \n\\f3\\fs18 position\n\\f4\\fs20 , \n\\f3\\fs18 F\n\\f4\\fs20  otherwise\\cf2 \\expnd0\\expndtw0\\kerning0\n (if \n\\f3\\fs18 returnMutation\n\\f4\\fs20  has its default value of \n\\f3\\fs18 F\n\\f4\\fs20 ; see below)\\cf0 \\kerning1\\expnd0\\expndtw0 .  This method is, as its name suggests, intended for checking for \\'93marker mutations\\'94: mutations of a special mutation type that are not literally mutations in the usual sense, but instead are added in to particular haplosomes to mark them as possessing some property.  Marker mutations are not typically added by SLiM\\'92s mutation-generating machinery; instead they are added explicitly with \n\\f3\\fs18 addNewMutation()\n\\f4\\fs20  or \n\\f3\\fs18 addNewDrawnMutation()\n\\f4\\fs20  at a known, constant position in the haplosome.  This method provides a check for whether a marker mutation of a given type exists in a particular haplosome; because the position to check is known in advance, that check can be done much faster than the equivalent check with \n\\f3\\fs18 containsMutations()\n\\f4\\fs20  or \n\\f3\\fs18 countOfMutationsOfType()\n\\f4\\fs20 , using a binary search of the haplosome.\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4 \\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f3\\fs18 returnMutation\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (an option added in SLiM 3), this method returns the actual mutation found, rather than just \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20 .  More specifically, the \n\\f1\\i first\n\\f4\\i0  mutation found of \n\\f3\\fs18 mutType\n\\f4\\fs20  at \n\\f3\\fs18 position\n\\f4\\fs20  will be returned; if more than one such mutation exists in the target haplosome, which one is returned is not defined.  If \n\\f3\\fs18 returnMutation\n\\f4\\fs20  is T and no mutation of \n\\f3\\fs18 mutType\n\\f4\\fs20  is found at \n\\f3\\fs18 position\n\\f4\\fs20 , \n\\f3\\fs18 NULL\n\\f4\\fs20  will be returned.\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(logical)containsMutations(object<Mutation>\\'a0mutations)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a \n\\f3\\fs18 logical\n\\f4\\fs20  vector indicating whether each of the mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  is present in the target haplosome; each element in the returned vector indicates whether the corresponding mutation is present (\n\\f3\\fs18 T\n\\f4\\fs20 ) or absent (\n\\f3\\fs18 F\n\\f4\\fs20 ).  This method is provided for speed; it is much faster than the corresponding Eidos code.\\\nNote that the mutations must be associated with the same chromosome as the target haplosome, otherwise an error is raised.  The \n\\f3\\fs18 containsMutations()\n\\f4\\fs20  method of \n\\f3\\fs18 Individual\n\\f4\\fs20  does not have this restriction, since it checks for mutations across all of the haplosomes of the target individual.  This restriction is intended to find logic errors, since it seems to make little sense to check for a mutation in a haplosome for the wrong chromosome; but if this restriction proves inconvenient in common situations, it could be relaxed.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (integer$)countOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns the number of mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the haplosome.  If you need a vector of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than just a count, use \n\\f3\\fs18 -mutationsOfType()\n\\f5\\fs20 .\n\\f4   This method is provided for speed; it is much faster than the corresponding Eidos code.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(integer)mutationCountsInHaplosomes([No<Mutation>\\'a0mutations\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with the frequency counts of all of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects passed in \n\\f3\\fs18 mutations\n\\f4\\fs20 , within the target \n\\f3\\fs18 Haplosome\n\\f4\\fs20  vector.  If the optional \n\\f3\\fs18 mutations\n\\f4\\fs20  argument is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), frequency counts will be returned for all of the active \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects in the species \\'96 the same \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, and in the same order, as would be returned by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of \n\\f3\\fs18 sim\n\\f4\\fs20 , in other words.\\\nIn multi-chromosome models, you might often wish to obtain counts only for mutations associated with one particular chromosome.  In that case, you would probably want to pass a vector of the mutations associated with that specific chromosome, as obtained from the \n\\f3\\fs18 subsetMutations()\n\\f4\\fs20  method of \n\\f3\\fs18 Species\n\\f4\\fs20 , rather than passing \n\\f3\\fs18 NULL\n\\f4\\fs20 .  (Passing \n\\f3\\fs18 NULL\n\\f4\\fs20  in that scenario would give you counts of \n\\f3\\fs18 0\n\\f4\\fs20  for all of the mutations associated with other chromosomes in the model.)\\\nSee the \n\\f3\\fs18 +mutationFrequenciesInHaplosomes()\n\\f4\\fs20  method to obtain \n\\f3\\fs18 float\n\\f4\\fs20  frequencies instead of \n\\f3\\fs18 integer\n\\f4\\fs20  counts.  See also the \n\\f3\\fs18 Species\n\\f4\\fs20  methods \n\\f3\\fs18 mutationCounts()\n\\f4\\fs20  and \n\\f3\\fs18 mutationFrequencies()\n\\f4\\fs20 , which might be more efficient for getting counts/frequencies for whole subpopulations or for the whole species.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(float)mutationFrequenciesInHaplosomes([No<Mutation>\\'a0mutations\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Return a \n\\f3\\fs18 float\n\\f4\\fs20  vector with the frequencies of all of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects passed in \n\\f3\\fs18 mutations\n\\f4\\fs20 , within the target \n\\f3\\fs18 Haplosome\n\\f4\\fs20  vector.  If the optional \n\\f3\\fs18 mutations\n\\f4\\fs20  argument is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), frequencies will be returned for all of the active \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects in the species \\'96 the same \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, and in the same order, as would be returned by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of \n\\f3\\fs18 sim\n\\f4\\fs20 , in other words.\\\nIn multi-chromosome models, the frequency of each mutation is assessed within the subset of target haplosomes that are associated with the same chromosome.  In other words, if a mutation is associated with chromosome 1, and the target haplosomes are associated with both chromosomes 1 and 2, the frequency of the mutation will be calculated only within the haplosomes for chromosome 1 (as you would expect).  However, you might often wish to obtain frequencies only for mutations associated with one particular chromosome.  In that case, you would probably want to pass a vector of the mutations associated with that specific chromosome, as obtained from the \n\\f3\\fs18 subsetMutations()\n\\f4\\fs20  method of \n\\f3\\fs18 Species\n\\f4\\fs20 , rather than passing \n\\f3\\fs18 NULL\n\\f4\\fs20 .  (Passing \n\\f3\\fs18 NULL\n\\f4\\fs20  in that scenario would give you frequencies of \n\\f3\\fs18 0\n\\f4\\fs20  for all of the mutations associated with other chromosomes in the model.)\\\nSee the \n\\f3\\fs18 +mutationCountsInHaplosomes()\n\\f4\\fs20  method to obtain \n\\f3\\fs18 integer\n\\f4\\fs20  counts instead of \n\\f3\\fs18 float\n\\f4\\fs20  frequencies.  See also the \n\\f3\\fs18 Species\n\\f4\\fs20  methods \n\\f3\\fs18 mutationCounts()\n\\f4\\fs20  and \n\\f3\\fs18 mutationFrequencies()\n\\f4\\fs20 , which might be more efficient for getting counts/frequencies for whole subpopulations or for the whole species.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (object<Mutation>)mutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns an \n\\f3\\fs18 object\n\\f4\\fs20  vector of all the mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the haplosome.  If you just need a count of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than a vector of the matches, use \n\\f3\\fs18 -countOfMutationsOfType()\n\\f4\\fs20 ; if you need just the positions of matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, use \n\\f3\\fs18 -positionsOfMutationsOfType()\n\\f4\\fs20 ; and if you are aiming for a sum of the selection coefficients of matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, use \n\\f3\\fs18 -sumOfMutationsOfType()\n\\f5\\fs20 .\n\\f4   This method is provided for speed; it is much faster than the corresponding Eidos code.\\cf2   See also \n\\f3\\fs18 substitutionsOfType()\n\\f4\\fs20 .\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(is)nucleotides([Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [string$\\'a0format\\'a0=\\'a0\"string\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the nucleotide sequence for the haplosome.  This is the current ancestral sequence, as would be returned by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  method \n\\f3\\fs18 ancestralNucleotides()\n\\f4\\fs20 , with the nucleotides for any nucleotide-based mutations in the haplosome overlaid.  The range of the returned sequence may be constrained by a start position given in \n\\f3\\fs18 start\n\\f4\\fs20  and/or an end position given in \n\\f3\\fs18 end\n\\f4\\fs20 ; nucleotides will be returned from \n\\f3\\fs18 start\n\\f4\\fs20  to \n\\f3\\fs18 end\n\\f4\\fs20 , inclusive.  The default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  represent the first and last base positions of the chromosome, respectively.\\\nThe format of the returned sequence is controlled by the \n\\f3\\fs18 format\n\\f4\\fs20  parameter.  A format of \n\\f3\\fs18 \"string\"\n\\f4\\fs20  will return the sequence as a singleton \n\\f3\\fs18 string\n\\f4\\fs20  (e.g., \n\\f3\\fs18 \"TATA\"\n\\f4\\fs20 ).  A format of \n\\f3\\fs18 \"char\"\n\\f4\\fs20  will return a \n\\f3\\fs18 string\n\\f4\\fs20  vector with one element per nucleotide (e.g., \n\\f3\\fs18 \"T\"\n\\f4\\fs20 , \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"T\"\n\\f4\\fs20 , \n\\f3\\fs18 \"A\"\n\\f4\\fs20 ).  A format of \n\\f3\\fs18 \"integer\"\n\\f4\\fs20  will return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with values A=\n\\f3\\fs18 0\n\\f4\\fs20 , C=\n\\f3\\fs18 1\n\\f4\\fs20 , G=\n\\f3\\fs18 2\n\\f4\\fs20 , T=\n\\f3\\fs18 3\n\\f4\\fs20  (e.g., \n\\f3\\fs18 3\n\\f4\\fs20 , \n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 3\n\\f4\\fs20 , \n\\f3\\fs18 0\n\\f4\\fs20 ).  A format of \n\\f3\\fs18 \"codon\"\n\\f4\\fs20  will return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with values from \n\\f3\\fs18 0\n\\f4\\fs20  to \n\\f3\\fs18 63\n\\f4\\fs20 , based upon successive nucleotide triplets in the sequence (which, for this format, must have a length that is a multiple of three); see the \n\\f3\\fs18 ancestralNucleotides()\n\\f4\\fs20  documentation for details.  If the sequence returned is likely to be long, the \n\\f3\\fs18 \"string\"\n\\f4\\fs20  format will be the most memory-efficient, and may also be the fastest (but may be harder to work with).\\\nSeveral helper functions are provided for working with sequences, such as \n\\f3\\fs18 nucleotideCounts()\n\\f4\\fs20  to get the counts of A/C/G/T nucleotides in a sequence, \n\\f3\\fs18 nucleotideFrequencies()\n\\f4\\fs20  to get the same information as frequencies, and \n\\f3\\fs18 codonsToAminoAcids()\n\\f4\\fs20  to convert a codon sequence (such as provided by the codon format described above) to an amino acid sequence.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 +\\'a0(void)outputHaplosomes([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F]\\cf2 , [logical$\\'a0objectTags\\'a0=\\'a0F]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output the target haplosomes in SLiM\\'92s native format.  This low-level output method may be used to output any sample of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with a single chromosome.  The Eidos function \n\\f3\\fs18 sample()\n\\f4\\fs20  may be useful for constructing custom samples, as may the SLiM class \n\\f3\\fs18 Individual\n\\f4\\fs20 .  For output of a sample from a single \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , the \n\\f3\\fs18 outputSample()\n\\f4\\fs20  method of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  may be more straightforward to use.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output is directed to SLiM\\'92s standard output.  Otherwise, the output is sent to the file specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 objectTags\n\\f4\\fs20  parameter may be used to request that tag values for objects be written out.  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity; if it turned on (\n\\f3\\fs18 T\n\\f4\\fs20 ), the \n\\f3\\fs18 tag\n\\f4\\fs20  property values of all haplosomes and mutations in the output will be written.  If there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with \n\\f3\\fs18 setValue()\n\\f4\\fs20 , and so forth, you should persist that state in separate files using calls such as \n\\f3\\fs18 writeFile()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 See \n\\f3\\fs18 output\\cf2 HaplosomesTo\\cf0 MS()\n\\f4\\fs20  and \n\\f3\\fs18 output\\cf2 HaplosomesTo\\cf0 VCF()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 +\\'a0(void)output\\cf2 HaplosomesTo\\cf0 MS([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [logical$\\'a0filterMonomorphic\\'a0=\\'a0F]\\cf0 \\kerning1\\expnd0\\expndtw0 )\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output the target haplosomes in MS format.  This low-level output method may be used to output any sample of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with a single chromosome.  The Eidos function \n\\f3\\fs18 sample()\n\\f4\\fs20  may be useful for constructing custom samples, as may the SLiM class \n\\f3\\fs18 Individual\n\\f4\\fs20 .  For output of a sample from a single \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , the \n\\f3\\fs18 outputMSSample()\n\\f4\\fs20  of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  may be more straightforward to use.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output is directed to SLiM\\'92s standard output.  Otherwise, the output is sent to the file specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .  Positions in the output will span the interval [0,1].\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f3\\fs18 filterMonomorphic\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), all mutations that are present in the sample will be included in the output.  This means that some mutations may be included that are actually monomorphic within the sample (i.e., that exist in \n\\f1\\i every\n\\f4\\i0  sampled haplosome, and are thus apparently fixed).  These may be filtered out with \n\\f3\\fs18 filterMonomorphic = T\n\\f4\\fs20  if desired; note that this option means that some mutations that do exist in the sampled haplosomes might not be included in the output, simply because they exist in every sampled haplosome.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 See \n\\f3\\fs18 outputHaplosomes()\n\\f4\\fs20  and \n\\f3\\fs18 output\\cf2 HaplosomesTo\\cf0 VCF()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 +\\'a0(void)output\\cf2 HaplosomesTo\\cf0 VCF([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0outputMultiallelics\\'a0=\\'a0T], [logical$\\'a0append\\'a0=\\'a0F]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [logical$\\'a0simplifyNucleotides\\'a0=\\'a0F], [logical$\\'a0outputNonnucleotides\\'a0=\\'a0T]\\kerning1\\expnd0\\expndtw0 , [logical$\\'a0groupAsIndividuals\\'a0=\\'a0T]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output the target haplosomes in VCF format.  This low-level output method may be used to output any sample of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with a single chromosome.  The Eidos function \n\\f3\\fs18 sample()\n\\f4\\fs20  may be useful for constructing custom samples, as may the SLiM class \n\\f3\\fs18 Individual\n\\f4\\fs20 .  For output of a sample from a single \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , the \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20  method of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  may be more straightforward to use.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output is directed to SLiM\\'92s standard output.  Otherwise, the output is sent to the file specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\\\nThe parameters \n\\f3\\fs18 outputMultiallelics\n\\f4\\fs20 , \n\\f3\\fs18 simplifyNucleotides\n\\f4\\fs20 , and \n\\f3\\fs18 outputNonnucleotides\n\\f4\\fs20  affect the format of the output produced.\\\nWith \n\\f3\\fs18 groupAsIndividuals\n\\f4\\fs20  being \n\\f3\\fs18 T\n\\f4\\fs20  (the default), the target haplosome vector should be structured as if it represents all of the haplosomes for some set of individuals, for a single focal chromosome.  All haplosomes for the focal chromosome should be present, including null haplosomes.  It should provide all of the haplosomes for the first individual (for the chosen chromosome); then for the second individual; and so forth.  The haplosomes in the target haplosome vector do not, in fact, need to belong to individuals in SLiM following this pattern; they just need to specify well-formed individuals in the VCF output.  For an intrinsically haploid chromosome, the target haplosome for a given output individual is used to generate a haploid call (\n\\f3\\fs18 0\n\\f4\\fs20  or \n\\f3\\fs18 1\n\\f4\\fs20 ) for that individual; if the haplosome is a null haplosome, the call will be \n\\f3\\fs18 ~\n\\f4\\fs20  (an ASCII tilde). For example, calls for (non-null) Y haplosomes in males will be emitted as \n\\f3\\fs18 0\n\\f4\\fs20  or \n\\f3\\fs18 1\n\\f4\\fs20 , whereas calls for the (null) Y haplosomes in females will be emitted as \n\\f3\\fs18 ~\n\\f4\\fs20 .  For an intrinsically diploid chromosome, the pair of target haplosomes for a given individual is used to generate a call for that individual, but null haplosomes are allowed (in the patterns expected by SLiM given the chromosome type).  For example, a pair of non-null haplosomes for an X chromosome will be emitted as a diploid call (such as \n\\f3\\fs18 1|0\n\\f4\\fs20 ) for a female (XX), but if the second haplosome of the pair is a null haplosome, the pair will be emitted as a haploid call (\n\\f3\\fs18 0\n\\f4\\fs20  or \n\\f3\\fs18 1\n\\f4\\fs20 ) for a male (X).  If the first haplosome of the pair were a null haplosome for an X chromosome, an error would be raised, since that is not an allowed pattern in SLiM (as discussed in the documentation for the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  class).  For a diploid autosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , however, any pattern is legal, but the VCF format cannot distinguish between a non-null haplosome first and a null haplosome second, versus a null haplosome first and a non-null haplosome second; both will be emitted as a haploid call (\n\\f3\\fs18 0\n\\f4\\fs20  or \n\\f3\\fs18 1\n\\f4\\fs20 ).  For a diploid autosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , if both haplosomes are null the call will be \n\\f3\\fs18 ~\n\\f4\\fs20 .  The VCF specification does not actually seem to discuss sex chromosomes, but this design is intended to follow standard usage.\\\nWith \n\\f3\\fs18 groupAsIndividuals\n\\f4\\fs20  being \n\\f3\\fs18 F\n\\f4\\fs20 , the focal chromosome is treated as being intrinsically haploid whether it is or not; each haplosome will be called as a haploid sample whether the chromosome type is diploid or haploid.  This provides more detailed and accurate information; the exact state of each haplosome will be represented with either \n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 , or (for null haplosomes) \n\\f3\\fs18 ~\n\\f4\\fs20 , rather than the state of a pair of haplosomes being represented as a single call in a way that can sometimes be ambiguous, as discussed above.  However, the resulting output might confuse some VCF parsers that expect diploid calls for individuals, and it will not be as obvious which calls in the output belong to a given diploid individual.\\\nSee \n\\f3\\fs18 outputHaplosomesToMS()\n\\f4\\fs20  and \n\\f3\\fs18 outputHaplosomes()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(integer)positionsOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns the positions of mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the haplosome.  If you need a vector of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than just positions, use \n\\f3\\fs18 -mutationsOfType()\n\\f4\\fs20 .  This method is provided for speed; it is much faster than the corresponding Eidos code.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n+\\'a0(\\cf0 \\kerning1\\expnd0\\expndtw0 object\\cf2 \\expnd0\\expndtw0\\kerning0\n<Mutation>)readHaplosomesFromMS(string$\\'a0filePath, io<MutationType>$\\'a0mutationType)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Read new mutations from the MS format file at \n\\f3\\fs18 filePath\n\\f4\\fs20  and add them to the target haplosomes.  The number of target haplosomes must match the number of haplosomes represented in the MS file, and all target haplosomes must be associated with the same chromosome, and must not be null haplosomes.  The target haplosomes correspond, in order, to the call lines in the MS file.  To read into all of the non-null haplosomes in a given subpopulation \n\\f3\\fs18 pN\n\\f4\\fs20  in a single-chromosome model, simply call \n\\f3\\fs18 pN.haplosomesNonNull.\\expnd0\\expndtw0\\kerning0\nreadHaplosomesFromMS\\kerning1\\expnd0\\expndtw0 ()\n\\f4\\fs20 , assuming the subpopulation\\'92s size matches that of the MS file.  A vector containing all of the mutations created by \n\\f3\\fs18 \\expnd0\\expndtw0\\kerning0\nreadHaplosomesFromMS\\kerning1\\expnd0\\expndtw0 ()\n\\f4\\fs20  is returned.\\\nEach mutation is created at the position specified in the file, using the mutation type given by \n\\f3\\fs18 mutationType\n\\f4\\fs20 .  Positions are expected to be in [0,1], and are scaled to the length of the chromosome by multiplying by the last valid base position of the chromosome (i.e., one less than the chromosome length).  Selection coefficients are drawn from the mutation type.  The population of origin for each mutation is set to \n\\f3\\fs18 -1\n\\f4\\fs20 , and the tick of origin is set to the current tick.  In a nucleotide-based model, if \n\\f3\\fs18 mutationType\n\\f4\\fs20  is nucleotide-based, a random nucleotide different from the ancestral nucleotide at the position will be chosen with equal probability.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n+\\'a0(\\cf0 \\kerning1\\expnd0\\expndtw0 object\\cf2 \\expnd0\\expndtw0\\kerning0\n<Mutation>)readHaplosomesFromVCF(string$\\'a0filePath, [Nio<MutationType>$\\'a0mutationType\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Read new mutations from the VCF format file at \n\\f3\\fs18 filePath\n\\f4\\fs20  and add them to the target haplosomes.  The number of target haplosomes must match the number of haplosomes represented in the VCF file (i.e., two times the number of diploid samples plus one times the number of haploid samples).  To read into all of the haplosomes in a given subpopulation \n\\f3\\fs18 pN\n\\f4\\fs20  in a single-chromosome model, simply call \n\\f3\\fs18 pN.haplosomes.readHaplosomesFromVCF()\n\\f4\\fs20 , assuming the subpopulation\\'92s size matches that of the VCF file taking ploidy into account.  A vector containing all of the mutations created by \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  is returned.\\\nThis method and the \n\\f3\\fs18 readIndividualsFromVCF()\n\\f4\\fs20  method of \n\\f3\\fs18 Individual\n\\f4\\fs20  provide two alternative ways of reading VCF data, focused in the perspective of either haplosomes (this method) or individuals (the \n\\f3\\fs18 Individual\n\\f4\\fs20  method).  See the documentation of \n\\f3\\fs18 readIndividualsFromVCF()\n\\f4\\fs20  for discussion of the pros and cons of each approach; that discussion will not be duplicated here.\\\nSLiM\\'92s VCF parsing is quite primitive.  The header is parsed only inasmuch as SLiM looks to see whether SLiM-specific VCF fields are defined or not; the rest of the header information is ignored.  Call lines are assumed to follow the format:\\\n\\pard\\tx990\\tx1260\\tx1530\\tx1800\\tx2070\\tx2340\\tx2610\\tx2880\\tx3150\\tx3420\\pardeftab720\\li547\\ri720\\sl264\\slmult1\\sa180\\partightenfactor0\n\n\\f3\\fs18 \\cf2 #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT i0...iN\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 CHROM\n\\f4\\fs20  field is largely ignored, but \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  does check that its value is identical across all call lines, to prevent the genetic data for more than one chromosome from being glommed together nonsensically; the input VCF file must contain data for just a single chromosome.  In single-chromosome models the \n\\f3\\fs18 CHROM\n\\f4\\fs20  field is not otherwise checked or validated.  In multi-chromosome models, \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  imposes some additional restrictions.  First, all haplosomes in the target vector must be associated with the same single focal chromosome.  Second, the \n\\f3\\fs18 CHROM\n\\f4\\fs20  field for every call line in the VCF file must match the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of that focal chromosome; the VCF file must indicate that it specifically matches the focal chromosome associated with the target haplosomes.  These restrictions boil down to the fact that \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  only reads data for a single chromosome.  If you wish to read multi-chromosome VCF data into a multi-chromosome SLiM model, the \n\\f3\\fs18 readIndividualsFromVCF()\n\\f4\\fs20  method provided by the \n\\f3\\fs18 Individual\n\\f4\\fs20  class supports that functionality (because it can work at the level of individuals, rather than haplosomes, making it possible to match calls to the corresponding haplosomes in a reasonable way).  Alternatively, you can call \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  multiple times to read data for different chromosomes one by one.\\\nThe \n\\f3\\fs18 ID\n\\f4\\fs20 , \n\\f3\\fs18 QUAL\n\\f4\\fs20 , \n\\f3\\fs18 FILTER\n\\f4\\fs20 , and \n\\f3\\fs18 FORMAT\n\\f4\\fs20  fields are ignored, and information in the genotype fields beyond the \n\\f3\\fs18 GT\n\\f4\\fs20  genotype subfield are also ignored.  SLiM\\'92s own VCF annotations are honored; in particular, mutations will be created using the given values of \n\\f3\\fs18 MID\n\\f4\\fs20 , \n\\f3\\fs18 S\n\\f4\\fs20 , \n\\f3\\fs18 PO\n\\f4\\fs20 , \n\\f3\\fs18 TO\n\\f4\\fs20 , and \n\\f3\\fs18 MT\n\\f4\\fs20  if those subfields are present, and \n\\f3\\fs18 DOM\n\\f4\\fs20 , if it is present, must match the dominance coefficient of the mutation type.  The parameter \n\\f3\\fs18 mutationType\n\\f4\\fs20  (a \n\\f3\\fs18 MutationType\n\\f4\\fs20  object or id) will be used for any mutations that have no supplied mutation type id in the \n\\f3\\fs18 MT\n\\f4\\fs20  subfield; if \n\\f3\\fs18 mutationType\n\\f4\\fs20  would be used but is \n\\f3\\fs18 NULL\n\\f4\\fs20  an error will result.  Mutation IDs supplied in \n\\f3\\fs18 MID\n\\f4\\fs20  will be used if no mutation IDs have been used in the simulation so far; if any have been used, it is difficult for SLiM to guarantee that there are no conflicts, so a warning will be emitted and the \n\\f3\\fs18 MID\n\\f4\\fs20  values will be ignored.  If selection coefficients are not supplied with the \n\\f3\\fs18 S\n\\f4\\fs20  subfield, they will be drawn from the mutation type used for the mutation.  If a population of origin is not supplied with the \n\\f3\\fs18 PO\n\\f4\\fs20  subfield, \n\\f3\\fs18 -1\n\\f4\\fs20  will be used.  If a tick of origin is not supplied with the \n\\f3\\fs18 TO\n\\f4\\fs20  subfield (or a generation of origin \n\\f3\\fs18 GO\n\\f4\\fs20  field, which was the SLiM convention before SLiM 4), the current tick will be used.\\\n\n\\f3\\fs18 REF\n\\f4\\fs20  and \n\\f3\\fs18 ALT\n\\f4\\fs20  must always be comprised of simple nucleotides (\n\\f3\\fs18 A\n\\f4\\fs20 /\n\\f3\\fs18 C\n\\f4\\fs20 /\n\\f3\\fs18 G\n\\f4\\fs20 /\n\\f3\\fs18 T\n\\f4\\fs20 ) rather than values representing indels or other complex states.  Beyond this, the handling of the \n\\f3\\fs18 REF\n\\f4\\fs20  and \n\\f3\\fs18 ALT\n\\f4\\fs20  fields depends upon several factors.  In non-nucleotide-based models, we have the first case: (1)\\'a0These fields are ignored, although they are still checked for conformance.  In nucleotide-based models, when a header definition for SLiM\\'92s \n\\f3\\fs18 NONNUC\n\\f4\\fs20  tag is present (as when nucleotide-based output is generated by SLiM) there are two further possibilities, given as (2) and (3) here: (2)\\'a0If a \n\\f3\\fs18 NONNUC\n\\f4\\fs20  field is present in the \n\\f3\\fs18 INFO\n\\f4\\fs20  field the call line is taken to represent a non-nucleotide-based mutation, and \n\\f3\\fs18 REF\n\\f4\\fs20  and \n\\f3\\fs18 ALT\n\\f4\\fs20  are again ignored; in this case the mutation type used must be non-nucleotide-based.  (3)\\'a0If a \n\\f3\\fs18 NONNUC\n\\f4\\fs20  field is \n\\f1\\i not\n\\f4\\i0  present the call line is taken to represent a nucleotide-based mutation; in this case, the mutation type used must be nucleotide-based, and the specified reference nucleotide must match the existing ancestral nucleotide at the given position.  Finally, in nucleotide-based models, when a header definition for SLiM\\'92s \n\\f3\\fs18 NONNUC\n\\f4\\fs20  tag is \n\\f1\\i not\n\\f4\\i0  present (as when loading a non-SLiM-generated VCF file), there is a remaining possibility: (4)\\'a0The mutation type used will govern the way nucleotides are handled.  In this case, if the mutation type used for a mutation is nucleotide-based, the nucleotide provided in the VCF file for that allele will be used, whereas if the mutation type is non-nucleotide-based, the nucleotide provided will be ignored.\\\nIf multiple alleles using the same nucleotide at the same position are specified in the VCF file, a separate mutation will be created for each, mirroring SLiM\\'92s behavior with independent mutational lineages when writing VCF.  The \n\\f3\\fs18 MULTIALLELIC\n\\f4\\fs20  flag is ignored by \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20 ; call lines for mutations at the same base position in the same haplosome will result in stacked mutations whether or not \n\\f3\\fs18 MULTIALLELIC\n\\f4\\fs20  is present.\\\nThe target haplosomes correspond, in order, to the haploid or diploid calls provided for \n\\f3\\fs18 i0\n\\f4\\fs20 \\'85\n\\f3\\fs18 iN\n\\f4\\fs20  (the sample IDs) in the VCF file.  Null haplosomes in the target vector will be skipped, and will not be used to correspond to any of the calls for \n\\f3\\fs18 i0\n\\f4\\fs20 \\'85\n\\f3\\fs18 iN\n\\f4\\fs20 ; however, care should be taken in this case that the haplosomes in the VCF file correspond to the target haplosomes in the manner desired.\\\nA call of \n\\f3\\fs18 ~\n\\f4\\fs20  (an ASCII tilde character) for an individual \n\\f3\\fs18 i0\n\\f4\\fs20 \\'85\n\\f3\\fs18 iN\n\\f4\\fs20  is taken to indicate that that individual possesses no genetic information for the chromosome; it lacks that chromosome entirely.  For example, if the VCF file represents Y-chromosome data, female individuals should have calls of \n\\f3\\fs18 ~\n\\f4\\fs20 .  This is treated differently than a call of \n\\f3\\fs18 0\n\\f4\\fs20   or \n\\f3\\fs18 0|0\n\\f4\\fs20 ; a call of \n\\f3\\fs18 0\n\\f4\\fs20  matches that call to a non-null target haplosome (but does not add the called mutation to that haplosome), and a call of \n\\f3\\fs18 0|0\n\\f4\\fs20  matches two non-null target haplosomes (but does not add the called mutation to either), whereas a call of \n\\f3\\fs18 ~\n\\f4\\fs20  is simply skipped, without matching to any haplosome in the target vector, mirroring the fact that \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  skips over null haplosomes in the target haplosome vector.  (When reading Y-chromosome data, a female\\'92s null Y haplosome could be omitted from the target haplosome vector, or it could be present since it would be skipped anyway \\'96 as stated above, all null haplosomes are skipped.)  Note that these semantics using \n\\f3\\fs18 ~\n\\f4\\fs20  are non-standard; the VCF standard does not seem to say anything about how sex chromosomes should be represented (or anything about other types of chromosomes that might be absent from some individuals), so the usage of \n\\f3\\fs18 ~\n\\f4\\fs20  was invented for SLiM.  This is an area where standardization is very much needed.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n+\\'a0(void)removeMutations([No<Mutation>\\'a0mutations\\'a0=\\'a0NULL], [logical$\\'a0substitute\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Remove the mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  from the target haplosomes, if they are present (if they are not present, they will be ignored).  If \n\\f3\\fs18 NULL\n\\f4\\fs20  is passed for \n\\f3\\fs18 mutations\n\\f4\\fs20  (which is the default), then all mutations will be removed from the target haplosomes; in this case, \n\\f3\\fs18 substitute\n\\f4\\fs20  must be \n\\f3\\fs18 F\n\\f4\\fs20  (a specific vector of mutations to be substituted is required).  Note that the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects removed remain valid, and will still be in the simulation\\'92s mutation registry (i.e., will be returned by the \n\\f3\\fs18 Species\n\\f4\\fs20  property \n\\f3\\fs18 mutations\n\\f4\\fs20 ), until the next tick.  All target haplosomes and all mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  must be associated with the same \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object; attempting to remove a mutation from a haplosome associated with a different chromosome will raise an error.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nRemoving mutations will normally affect the fitness values calculated at the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\nThe optional parameter \n\\f3\\fs18 substitute\n\\f4\\fs20  was added in SLiM 2.2, with a default of \n\\f3\\fs18 F\n\\f4\\fs20  for backward compatibility.  If \n\\f3\\fs18 substitute\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects will be created for all of the removed mutations so that they are recorded in the simulation as having fixed, just as if they had reached fixation and been removed by SLiM\\'92s own internal machinery.  This will occur regardless of whether the mutations have in fact fixed, regardless of the \n\\f3\\fs18 convertToSubstitution\n\\f4\\fs20  property of the relevant mutation types, and regardless of whether all copies of the mutations have even been removed from the simulation (making it possible to create \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects for mutations that are still segregating).  It is up to the caller to perform whatever checks are necessary to preserve the integrity of the simulation\\'92s records.  Typically \n\\f3\\fs18 substitute\n\\f4\\fs20  will only be set to \n\\f3\\fs18 T\n\\f4\\fs20  in the context of calls like \n\\f3\\fs18 sim.subpopulations.haplosomes.removeMutations(muts, T)\n\\f4\\fs20 , such that the substituted mutations are guaranteed to be entirely removed from circulation.  As mentioned above, \n\\f3\\fs18 substitute\n\\f4\\fs20  may not be \n\\f3\\fs18 T\n\\f4\\fs20  if \n\\f3\\fs18 mutations\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\n\\f5 \\'a0\n\\f3 (float$)sumOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns the sum of the selection coefficients of all mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the haplosome.  This is often useful in models that use a particular mutation type to represent QTLs with additive effects; in that context, \n\\f3\\fs18 sumOfMutationsOfType()\n\\f4\\fs20  will provide the sum of the additive effects of the QTLs for the given mutation type.  This method is provided for speed; it is much faster than the corresponding Eidos code.  Note that this method also exists on \n\\f3\\fs18 Individual\n\\f4\\fs20 , for cases in which the sum across both haplosomes of an individual is desired.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.5  Class GenomicElement\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.5.1  \n\\f2\\fs18 GenomicElement\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 endPosition => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The last position in the chromosome contained by this genomic element.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 genomicElementType => (object<GenomicElementType>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  object that defines the behavior of this genomic element.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 startPosition => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The first position in the chromosome contained by this genomic element.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.5.2  \n\\f2\\fs18 GenomicElement\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 \\'96\\'a0(void)setGenomicElementType(io<GenomicElementType>$\\'a0genomicElementType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the genomic element type used for a genomic element.  The genomicElementType parameter should supply the new genomic element type for the element, either as a \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  object or as an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier.  The genomic element type for a genomic element is normally a constant in simulations, so be sure you know what you are doing.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.6  Class GenomicElementType\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.6.1  \n\\f2\\fs18 GenomicElementType\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 color <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The color used to display genomic elements of this type in SLiMgui.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20 .  If \n\\f3\\fs18 color\n\\f4\\fs20  is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui\\'92s default color scheme is used; this is the default for new \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  objects.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this genomic element type; for genomic element type \n\\f3\\fs18 g3\n\\f4\\fs20 , for example, this is \n\\f3\\fs18 3\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationFractions => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 For each \n\\f3\\fs18 MutationType\n\\f4\\fs20  represented in this genomic element type, this property has the corresponding fraction of all mutations that will be drawn from that \n\\f3\\fs18 MutationType\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nmutationMatrix => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The nucleotide mutation matrix used for this genomic element type, set up by \n\\f3\\fs18 initializeGenomicElementType()\n\\f4\\fs20  and \n\\f3\\fs18 setMutationMatrix()\n\\f4\\fs20 .  This property is only defined in nucleotide-based models; it is unavailable otherwise.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationTypes => (object<MutationType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 MutationType\n\\f4\\fs20  instances used by this genomic element type.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 species => (object<Species>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe species to which the target object belongs.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to genomic element types.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.6.2  \n\\f2\\fs18 GenomicElementType\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 \\'96\\'a0(void)setMutationFractions(io<MutationType>\\'a0mutationTypes, numeric\\'a0proportions)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the mutation type fractions contributing to a genomic element type.  The \n\\f3\\fs18 mutationTypes\n\\f4\\fs20  vector should supply the mutation types used by the genomic element (either as \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects or as \n\\f3\\fs18 integer\n\\f4\\fs20  identifiers), and the \n\\f3\\fs18 proportions\n\\f4\\fs20  vector should be of equal length, specifying the relative proportion of mutations that will be drawn from each corresponding type.  This is normally a constant in simulations, so be sure you know what you are doing.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(void)setMutationMatrix(float\\'a0mutationMatrix)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Sets a new nucleotide mutation matrix for the genomic element type.  This replaces the mutation matrix originally set by \n\\f3\\fs18 initializeGenomicElementType()\n\\f4\\fs20 .  This method may only be called in nucleotide-based models.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 \\kerning1\\expnd0\\expndtw0 5.7  Class Individual\\\n\\pard\\pardeftab397\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.7.1  \n\\f2\\fs18 Individual\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 age \\cf2 \\expnd0\\expndtw0\\kerning0\n<\\'96>\\cf0 \\kerning1\\expnd0\\expndtw0  (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The age of the individual, measured in cycles.  A newly generated offspring individual will have an age of \n\\f3\\fs18 0\n\\f4\\fs20  in the same tick in which it was created.  The age of every individual is incremented by one at the same point that its species cycle counter is incremented, at the end of the tick cycle, \n\\f1\\i if and only if\n\\f4\\i0  its species was active in that tick.  The age of individuals may be changed; usually this only makes sense when setting up the initial state of a model, however.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 color <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The color used to display the individual in SLiMgui.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20  (see the Eidos manual).  If \n\\f3\\fs18 color\n\\f4\\fs20  is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui\\'92s default (fitness-based) color scheme is used; this is the default for new \n\\f3\\fs18 Individual\n\\f4\\fs20  objects.  Note that named colors will be converted to RGB internally, so the value of this property will always be a hexadecimal RGB color string (or \n\\f3\\fs18 \"\"\n\\f4\\fs20 ).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nfitnessScaling <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A \n\\f3\\fs18 float\n\\f4\\fs20  scaling factor applied to the individual\\'92s fitness (i.e., the fitness value computed for the individual will be multiplied by this value).  This provides a simple, fast way to modify the fitness of an individual; conceptually it is similar to returning a fitness effect for the individual from a \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callback, but without the complexity and performance overhead of implementing such a callback.  To scale the fitness of all individuals in a subpopulation by the same factor, see the \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  property of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 .\\\nThe value of \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  is reset to \n\\f3\\fs18 1.0\n\\f4\\fs20  every tick, so that any scaling factor set lasts for only a single tick.  This reset occurs immediately after fitness values are calculated, in both WF and nonWF models.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 haploidGenome1 => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector of all \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with this individual that are attributed to its first parent (the female parent, in sexual models).  This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.  The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  For chromosomes with two associated haplosomes (types \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Z\"\n\\f4\\fs20 , \n\\f3\\fs18 \"H-\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"-Y\"\n\\f4\\fs20 ), the first haplosome is assumed to be from the first parent, and is thus included, whereas the second haplosome is assumed to be from the second parent and is thus not included.  For chromosomes with one associated haplosome that is inherited from the female/first parent in one way or another (types \n\\f3\\fs18 \"W\"\n\\f4\\fs20 , \n\\f3\\fs18 \"HF\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"FL\"\n\\f4\\fs20 ), that haplosome is always included.  For type \n\\f3\\fs18 \"H\"\n\\f4\\fs20 , the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is included.  Other chromosome types (\n\\f3\\fs18 \"Y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"HM\"\n\\f4\\fs20 , \n\\f3\\fs18 \"ML\"\n\\f4\\fs20 ) are never included.  See also the \n\\f3\\fs18 haploidGenome1NonNull\n\\f4\\fs20  property and the \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haploidGenome1NonNull => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This provides the same vector of haplosomes as the \n\\f3\\fs18 haploidGenome1\n\\f4\\fs20  property, except that null haplosomes are not included in this property.  This is a convenience shorthand, sometimes useful in models that involve null haplosomes.  See also the \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haploidGenome2 => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector of all \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with this individual that are attributed to its second parent (the male parent, in sexual models).  This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.  The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  For chromosomes with two associated haplosomes (types \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Z\"\n\\f4\\fs20 , \n\\f3\\fs18 \"H-\"\n\\f4\\fs20 , and\n\\f3\\fs18 \"-Y\"\n\\f4\\fs20 ), the second haplosome is assumed to be from the second parent, and is thus included, whereas the first haplosome is assumed to be from the first parent and is thus not included.  For chromosomes with one associated haplosome that is inherited from the male/second parent in one way or another (types \n\\f3\\fs18 \"Y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"HM\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"ML\"\n\\f4\\fs20 ), that haplosome is always included.  For type \n\\f3\\fs18 \"H\"\n\\f4\\fs20 , the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is not included.  Other chromosome types (\n\\f3\\fs18 \"W\"\n\\f4\\fs20 , \n\\f3\\fs18 \"HF\"\n\\f4\\fs20 , \n\\f3\\fs18 \"FL\"\n\\f4\\fs20 ) are never included.  See also the \n\\f3\\fs18 haploidGenome2NonNull\n\\f4\\fs20  property and the \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haploidGenome2NonNull => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This provides the same vector of haplosomes as the \n\\f3\\fs18 haploidGenome2\n\\f4\\fs20  property, except that null haplosomes are not included in this property.  This is a convenience shorthand, sometimes useful in models that involve null haplosomes.  See also the \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haplosomes => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector of all \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with this individual, in the order in which the chromosomes were defined for the species.  See also the \n\\f3\\fs18 haplosomesNonNull\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome1\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome1NonNull\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome2\n\\f4\\fs20 , and \n\\f3\\fs18 haploidGenome2NonNull\n\\f4\\fs20  properties and the \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haplosomesNonNull => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A vector of all \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects associated with this individual, in the order in which the chromosomes were defined for the species (as with the \n\\f3\\fs18 haplosomes\n\\f4\\fs20  property), but excluding any null haplosomes from the returned vector.  This is a convenience shorthand, sometimes useful in models that involve null haplosomes.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 index => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The index of the individual in the \n\\f3\\fs18 individuals\n\\f4\\fs20  vector of its \n\\f3\\fs18 Subpopulation\n\\f5\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 meanParentAge => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The average age of the parents of this individual, measured in cycles.  Parentless individuals will have a \n\\f3\\fs18 meanParentAge\n\\f4\\fs20  of \n\\f3\\fs18 0.0\n\\f4\\fs20 .  The mean parent age is determined when a new offspring is generated, from the \n\\f3\\fs18 age\n\\f4\\fs20  property of the parent or parents involved in generating the offspring.  For \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  and \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  that is somewhat complex; see those methods for details.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nmigrant => (logical$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Set to \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 T\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n if the individual is a recent migrant, \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 F\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n otherwise.  The definition of \\'93recent\\'94 depends upon the model type (WF or nonWF).\\\nIn WF models, this flag is set at the point when a new child is generated if it is a migrant (i.e., if its source subpopulation is not the same as its subpopulation), and remains valid, with the same value, for the rest of the individual\\'92s lifetime.\\\nIn nonWF models, this flag is \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 F\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n for all new individuals, is set to \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 F\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n in all individuals at the end of the reproduction tick cycle stage, and is set to \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 T\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n on all individuals moved to a new subpopulation by\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0  takeMigrants()\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n or a \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 survival()\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n callback; the \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 T\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n value set by \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 takeMigrants()\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n or \n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 survival()\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n will remain until it is reset at the end of the next reproduction tick cycle stage.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 pedigreeID => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20  or tree-sequence recording is turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 , \n\\f3\\fs18 pedigreeID\n\\f4\\fs20  is a unique non-negative identifier for each individual in a simulation, never re-used throughout the duration of the simulation run.  If neither pedigree tracking nor tree-sequence recording is enabled, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 pedigreeParentIDs => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 pedigreeParentIDs\n\\f4\\fs20  contains the values of \n\\f3\\fs18 pedigreeID\n\\f4\\fs20  that were possessed by the parents of an individual; it is thus a vector of two values.  If pedigree tracking is not enabled, this property is unavailable.  Parental values may be \n\\f3\\fs18 -1\n\\f4\\fs20  if insufficient ticks have elapsed for that information to be available (because the simulation just started, or because a subpopulation is new).\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 pedigreeGrandparentIDs => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 pedigreeGrandparentIDs\n\\f4\\fs20  contains the values of \n\\f3\\fs18 pedigreeID\n\\f4\\fs20  that were possessed by the grandparents of an individual; it is thus a vector of four values.  If pedigree tracking is not enabled, this property is unavailable.  Grandparental values may be \n\\f3\\fs18 -1\n\\f4\\fs20  if insufficient ticks have elapsed for that information to be available (because the simulation just started, or because a subpopulation is new).\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 reproductiveOutput => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 reproductiveOutput\n\\f4\\fs20  contains the number of offspring for which this individual has been a parent.  If pedigree tracking is not enabled, this property is unavailable.  If an individual is a parent by cloning or selfing, or as \n\\f1\\i both\n\\f4\\i0  parents for a biparental mating, this value is incremented by two.  Involvement of an individual as a parent for an \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  or \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  call does not change this property\\'92s value, since the reproductive contribution in that case is unclear; one must conduct separate bookkeeping for that case if necessary, or use tree-sequence recording to infer it from the inheritance record.\\\nSee also the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  property \n\\f3\\fs18 lifetimeReproductiveOutput\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 sex => (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The sex of the individual.  This will be \n\\f3\\fs18 \"H\"\n\\f4\\fs20  if sex is not enabled in the simulation (i.e., for hermaphrodites), otherwise \n\\f3\\fs18 \"F\"\n\\f4\\fs20  or \n\\f3\\fs18 \"M\"\n\\f4\\fs20  as appropriate.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 spatialPosition => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The spatial position of the individual.  The length of the \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property (the number of coordinates in the spatial position of an individual) depends upon the spatial dimensionality declared with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  If the spatial dimensionality is zero (as it is by default), it is an error to access this property.  The elements of this property are identical to the values of the \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 z\n\\f4\\fs20  properties (if those properties are encompassed by the spatial dimensionality of the simulation).  In other words, if the declared dimensionality is \n\\f3\\fs18 \"xy\"\n\\f5\\fs20 ,\n\\f4  the \n\\f3\\fs18 individual.spatialPosition\n\\f4\\fs20  property is equivalent to \n\\f3\\fs18 c(individual.x,\\'a0individual.y)\n\\f4\\fs20 ; \n\\f3\\fs18 individual.z\n\\f4\\fs20  is not used since it is not encompassed by the simulation\\'92s dimensionality.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 subpopulation => (object<Subpopulation>$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object to which the individual belongs.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value (as opposed to \n\\f3\\fs18 tagF\n\\f4\\fs20 , which is of type \n\\f3\\fs18 float\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to individuals.  \\cf2 Note that the \n\\f3\\fs18 Individual\n\\f4\\fs20  objects used by SLiM are new for every new offspring, so the \n\\f3\\fs18 tag\n\\f4\\fs20  value of each new offspring generated in each tick will be initially undefined.\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tagF <\\'96> (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 float\n\\f4\\fs20  value (as opposed to \n\\f3\\fs18 tag\n\\f4\\fs20 , which is of type \n\\f3\\fs18 integer\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagF\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagF\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to individuals.\\\nNote that at present, although many classes in SLiM have an \n\\f3\\fs18 integer\n\\f4\\fs20 -type \n\\f3\\fs18 tag\n\\f4\\fs20  property, only \n\\f3\\fs18 Individual\n\\f4\\fs20  has a \n\\f3\\fs18 float\n\\f4\\fs20 -type \n\\f3\\fs18 tagF\n\\f4\\fs20  property, because attaching model state to individuals seems to be particularly common and useful.  If a \n\\f3\\fs18 tagF\n\\f4\\fs20  property would be helpful on another class, it would be easy to add.\\\nSee the description of the \n\\f3\\fs18 tag\n\\f4\\fs20  property above for additional comments.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tagL0 <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 logical\n\\f4\\fs20  value (see also \n\\f3\\fs18 tag\n\\f4\\fs20  and \n\\f3\\fs18 tagF\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagL0\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagL0\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to individuals.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tagL1 <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 logical\n\\f4\\fs20  value (see also \n\\f3\\fs18 tag\n\\f4\\fs20  and \n\\f3\\fs18 tagF\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagL1\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagL1\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to individuals.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tagL2 <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 logical\n\\f4\\fs20  value (see also \n\\f3\\fs18 tag\n\\f4\\fs20  and \n\\f3\\fs18 tagF\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagL2\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagL2\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to individuals.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tagL3 <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 logical\n\\f4\\fs20  value (see also \n\\f3\\fs18 tag\n\\f4\\fs20  and \n\\f3\\fs18 tagF\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagL3\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagL3\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to individuals.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tagL4 <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 logical\n\\f4\\fs20  value (see also \n\\f3\\fs18 tag\n\\f4\\fs20  and \n\\f3\\fs18 tagF\n\\f4\\fs20 ).  The value of \n\\f3\\fs18 tagL4\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tagL4\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to individuals.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 uniqueMutations => (object<Mutation>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects present in this individual.  Mutations present in homologous haplosomes will occur only once in this property, and the mutations for a given chromosome will be given in sorted order by \n\\f3\\fs18 position\n\\f4\\fs20 , so in single-chromosome simulations this property is similar to \n\\f3\\fs18 sortBy(unique(individual.haplosomes.mutations), \"position\")\n\\f4\\fs20 .  (Even with a single chromosome it is not identical to that call, since if multiple mutations exist at the exact same position, they might be sorted differently by this method than they would be by \n\\f3\\fs18 sortBy()\n\\f4\\fs20 .)  This method is provided primarily for speed; it executes much faster than the Eidos equivalent above.  Indeed, it is faster than just \n\\f3\\fs18 individual.haplosomes.mutations\n\\f4\\fs20 , and gives uniquing and sorting on top of that, so it is advantageous unless duplicate entries for homozygous mutations are actually needed.  For more flexibility, see the method \n\\f3\\fs18 mutationsFromHaplosomes()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 x <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 float\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 x\n\\f4\\fs20  is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 x\n\\f4\\fs20  is not used by SLiM unless the optional \\'93continuous space\\'94 facility is enabled with the \n\\f3\\fs18 dimensionality\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 , in which case \n\\f3\\fs18 x\n\\f4\\fs20  will be understood to represent the \n\\f1\\i x\n\\f4\\i0  coordinate of the individual in space.  If continuous space is not enabled, you may use \n\\f3\\fs18 x\n\\f4\\fs20  as an additional tag value of type \n\\f3\\fs18 float\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 xy => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This property provides joint read-only access to the \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  properties; they are returned as a two-element \n\\f3\\fs18 float\n\\f4\\fs20  vector.  This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.  See the documentation for the separate properties \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  for further comments.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 xyz => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This property provides joint read-only access to the \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 z\n\\f4\\fs20  properties; they are returned as a three-element \n\\f3\\fs18 float\n\\f4\\fs20  vector.  This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.  See the documentation for the separate properties \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 z\n\\f4\\fs20  for further comments.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 xz => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This property provides joint read-only access to the \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 z\n\\f4\\fs20  properties; they are returned as a two-element \n\\f3\\fs18 float\n\\f4\\fs20  vector.  This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.  See the documentation for the separate properties \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 z\n\\f4\\fs20  for further comments.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 y <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 float\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 y\n\\f4\\fs20  is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 y\n\\f4\\fs20  is not used by SLiM unless the optional \\'93continuous space\\'94 facility is enabled with the \n\\f3\\fs18 dimensionality\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 , in which case \n\\f3\\fs18 y\n\\f4\\fs20  will be understood to represent the \n\\f1\\i y\n\\f4\\i0  coordinate of the individual in space (if the dimensionality is \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  or \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 ).  If continuous space is not enabled, or the dimensionality is not \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  or \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 , you may use \n\\f3\\fs18 y\n\\f4\\fs20  as an additional tag value of type \n\\f3\\fs18 float\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 yz => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This property provides joint read-only access to the \n\\f3\\fs18 y\n\\f4\\fs20  and \n\\f3\\fs18 z\n\\f4\\fs20  properties; they are returned as a two-element \n\\f3\\fs18 float\n\\f4\\fs20  vector.  This can be useful in complex spatial models in which the spatiality of interactions/maps differs from the overall dimensionality of the model.  See the documentation for the separate properties \n\\f3\\fs18 y\n\\f4\\fs20  and \n\\f3\\fs18 z\n\\f4\\fs20  for further comments.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 z <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 float\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 z\n\\f4\\fs20  is initially undefined (i.e., has an effectively random value that could be different every time you run your model); if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 z\n\\f4\\fs20  is not used by SLiM unless the optional \\'93continuous space\\'94 facility is enabled with the \n\\f3\\fs18 dimensionality\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 , in which case \n\\f3\\fs18 z\n\\f4\\fs20  will be understood to represent the \n\\f1\\i z\n\\f4\\i0  coordinate of the individual in space (if the dimensionality is \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 ).  If continuous space is not enabled, or the dimensionality is not \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 , you may use \n\\f3\\fs18 z\n\\f4\\fs20  as an additional tag value of type \n\\f3\\fs18 float\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.7.2  \n\\f2\\fs18 Individual\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 \\'96\\'a0(logical)containsMutations(object<Mutation>\\'a0mutations)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a \n\\f3\\fs18 logical\n\\f4\\fs20  vector indicating whether each of the mutations in \n\\f3\\fs18 mutations\n\\f4\\fs20  is present in the individual (in any of its haplosomes); each element in the returned vector indicates whether the corresponding mutation is present (\n\\f3\\fs18 T\n\\f4\\fs20 ) or absent (\n\\f3\\fs18 F\n\\f4\\fs20 ).  This method is provided for speed; it is much faster than the corresponding Eidos code.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (integer$)countOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the number of mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the individual (in all of its haplosomes; a mutation that is present in both homologous haplosomes counts twice).  If you need a vector of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than just a count, you should probably use \n\\f3\\fs18 mutationsFromHaplosomes()\n\\f4\\fs20 .  This method is provided for speed; it is much faster than the corresponding Eidos code.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome>\\'a0chromosomes\\'a0=\\'a0NULL], [Ni$\\'a0index\\'a0=\\'a0NULL], [logical$\\'a0includeNulls\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the haplosomes of the target individual that correspond to the chromosomes passed in \n\\f3\\fs18 chromosomes\n\\f4\\fs20  (following the order of the \n\\f3\\fs18 chromosomes\n\\f4\\fs20  property of \n\\f3\\fs18 Individual\n\\f4\\fs20 ).  Chromosomes can be specified by id (\n\\f3\\fs18 integer\n\\f4\\fs20 ), by symbol (\n\\f3\\fs18 string\n\\f4\\fs20 ) or by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects themselves; if \n\\f3\\fs18 NULL\n\\f4\\fs20  is passed (the default), all chromosomes defined for the species are used, in the order in which they were defined.\\\nFor chromosomes that are intrinsically diploid (types \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"Z\"\n\\f4\\fs20 , as well as the \n\\f3\\fs18 \"H-\"\n\\f4\\fs20  and \n\\f3\\fs18 \"-Y\"\n\\f4\\fs20  backward-compatibility chromosome types), \n\\f3\\fs18 index\n\\f4\\fs20  can be \n\\f3\\fs18 0\n\\f4\\fs20  or \n\\f3\\fs18 1\n\\f4\\fs20 , requesting only the first or second haplosome, respectively, for that chromosome; for other chromosome types, \n\\f3\\fs18 index\n\\f4\\fs20  is ignored.  If \n\\f3\\fs18 includeNulls\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), any null haplosomes corresponding to the specified chromosomes are included in the result; if it is \n\\f3\\fs18 F\n\\f4\\fs20 , null haplosomes are excluded.  See also the properties \n\\f3\\fs18 haplosomes\n\\f4\\fs20 , \n\\f3\\fs18 haplosomesNonNull\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome1\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome1NonNull\n\\f4\\fs20 , \n\\f3\\fs18 haploidGenome2\n\\f4\\fs20 , and \n\\f3\\fs18 haploidGenome2NonNull\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Mutation>)mutationsFromHaplosomes(string$\\'a0category, [Nio<MutationType>$\\'a0mutType\\'a0=\\'a0NULL], [Niso<Chromosome>\\'a0chromosomes\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of mutations from the haplosomes of the target individual.  Several options are provided that filter which mutations are returned.\\\nThe \n\\f3\\fs18 category\n\\f4\\fs20  parameter must be one of five supported values: \n\\f3\\fs18 \"unique\"\n\\f4\\fs20 , \n\\f3\\fs18 \"homozygous\"\n\\f4\\fs20 , \n\\f3\\fs18 \"heterozygous\"\n\\f4\\fs20 , \n\\f3\\fs18 \"hemizygous\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"all\"\n\\f4\\fs20 .  If \n\\f3\\fs18 category\n\\f4\\fs20  is \n\\f3\\fs18 \"unique\"\n\\f4\\fs20 , a given mutation will be returned only once, whether it is present homozygously or heterozygously (or hemizygously, for that matter); this mode of operation is similar to the \n\\f3\\fs18 uniqueMutations\n\\f4\\fs20  property, but provides more control due to the other options provided by this method.  If \n\\f3\\fs18 category\n\\f4\\fs20  is \n\\f3\\fs18 \"homozygous\"\n\\f4\\fs20 , a given mutation will be returned only if it is present homozygously (in both of the homologous haplosomes for a given chromosome).  If \n\\f3\\fs18 category\n\\f4\\fs20  is \n\\f3\\fs18 \"heterozygous\"\n\\f4\\fs20 , a given mutation will be returned only if it is present heterozygously (in only one of the two homologous non-null haplosomes for a given chromosome).  If \n\\f3\\fs18 category\n\\f4\\fs20  is \n\\f3\\fs18 \"hemizygous\"\n\\f4\\fs20 , a given mutation will be returned only if it is present hemizygously (in one haplosome for an intrinsically diploid chromosome, when the other haplosome is a null haplosome).  If \n\\f3\\fs18 category\n\\f4\\fs20  is \n\\f3\\fs18 \"all\"\n\\f4\\fs20 , a given mutation will be returned each time that it occurs in the haplosomes of the individual; in other words, it will be present in the returned vector \n\\f1\\i twice\n\\f4\\i0  if it is homozygous, \n\\f1\\i once\n\\f4\\i0  if it is heterozygous or hemizygous.  Mutations in the single haplosome of an intrinsically haploid chromosome will be returned for \n\\f3\\fs18 category\n\\f4\\fs20  values of \n\\f3\\fs18 \"unique\"\n\\f4\\fs20 , \n\\f3\\fs18 \"homozygous\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"all\"\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 mutType\n\\f4\\fs20  parameter may be \n\\f3\\fs18 NULL\n\\f4\\fs20 , or may specify a mutation type by its \n\\f3\\fs18 integer\n\\f4\\fs20  id or with the \n\\f3\\fs18 MutationType\n\\f4\\fs20  object itself.  If \n\\f3\\fs18 mutType\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), mutations of every mutation type are returned; no filtering by mutation type is done.  Otherwise, only mutations of the specified mutation type will be returned.\\\nThe \n\\f3\\fs18 chromosomes\n\\f4\\fs20  parameter may be \n\\f3\\fs18 NULL\n\\f4\\fs20 , or may provide a vector of chromosomes specified by their \n\\f3\\fs18 integer\n\\f4\\fs20  id, \n\\f3\\fs18 string\n\\f4\\fs20  symbol, or with the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object itself.  If \n\\f3\\fs18 chromosomes\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), mutations associated with every chromosome are returned; no filtering by chromosome is done.  Otherwise, only mutations associated with the specified chromosomes will be returned.\\\nThe returned vector will contain tranches of mutations, one tranche per chromosome, in the order that the chromosomes were specified (if \n\\f3\\fs18 chromosomes\n\\f4\\fs20  is non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ) or the order the chromosomes were defined in the model (if \n\\f3\\fs18 chromosomes\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 ).  Within a given tranche, the mutations for that chromosome will be returned in sorted order by \n\\f3\\fs18 position\n\\f4\\fs20 .  (If more than one mutation associated with a given chromosome exists at the same position, the order in which those mutations are returned is undefined.)\\\nThis method replaces the deprecated method \n\\f3\\fs18 uniqueMutationsOfType()\n\\f4\\fs20 , while providing additional useful options.  It is particularly useful for efficient, vectorized assessment of the homozygous versus heterozygous state of the mutations contained by an individual, which is otherwise difficult to assess efficiently.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(void)outputIndividuals([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL], [logical$\\'a0spatialPositions\\'a0=\\'a0T], [logical$\\'a0ages\\'a0=\\'a0T], [logical$\\'a0ancestralNucleotides\\'a0=\\'a0F], [logical$\\'a0pedigreeIDs\\'a0=\\'a0F], [logical$\\'a0objectTags\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output the state of the target vector of individuals in SLiM's own format.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .  This method is quite similar to the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 outputFull()\n\\f4\\fs20 , but (1)\\'a0it can produce output for any vector of individuals, not always for the entire population; (2)\\'a0it does not support output in a binary format; (3)\\'a0it can produce output regarding the genetics for all chromosomes or for just one focal chromosome; and (4)\\'a0there is no corresponding read method, as r\n\\f3\\fs18 eadFromPopulationFile()\n\\f4\\fs20  can read the data saved by \n\\f3\\fs18 outputFull()\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 chromosome\n\\f4\\fs20  parameter specifies a focal chromosome for which the genetics of the target individuals will be output.  If \n\\f3\\fs18 chromosome\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , all chromosomes will be output; otherwise, \n\\f3\\fs18 chromosome\n\\f4\\fs20  may specify the focal chromosome with an \n\\f3\\fs18 integer\n\\f4\\fs20  chromosome id, a \n\\f3\\fs18 string\n\\f4\\fs20  chromosome symbol, or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.\\\nThe \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  parameter may be used to control the output of the spatial positions of individuals in species for which continuous space has been enabled using the \n\\f3\\fs18 dimensionality\n\\f4\\fs20  option of \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  If \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain spatial positions.  If \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , spatial position information will be output if it is available.  If the species does not have continuous space enabled, the \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  parameter will be ignored.\\\nThe \n\\f3\\fs18 ages\n\\f4\\fs20  parameter may be used to control the output of the ages of individuals in nonWF simulations.  If \n\\f3\\fs18 ages\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain ages.  If \n\\f3\\fs18 ages\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , ages will be output for nonWF models.  In WF simulations, the \n\\f3\\fs18 ages\n\\f4\\fs20  parameter will be ignored.\\\nThe \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  parameter may be used to control the output of the ancestral nucleotide sequence in nucleotide-based models.  If \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain ancestral nucleotide information.  This option is provided because the ancestral sequence may be quite large, for models with a long chromosome.  If the model is not nucleotide-based (as enabled with the \n\\f3\\fs18 nucleotideBased\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ), the \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  parameter will be ignored.  Note that in nucleotide-based models the output format will \n\\f1\\i always\n\\f4\\i0  include the nucleotides associated with any nucleotide-based mutations; the \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  flag governs only the ancestral sequence.\\\nThe \n\\f3\\fs18 pedigreeIDs\n\\f4\\fs20  parameter may be used to request that pedigree IDs be written out.  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity.  This option may only be used if SLiM\\'92s optional pedigree tracking has been enabled with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 .\\\nFinally, the \n\\f3\\fs18 objectTags\n\\f4\\fs20  parameter may be used to request that tag values for objects be written out.  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity; if it turned on (\n\\f3\\fs18 T\n\\f4\\fs20 ), the values of all tags for all objects of supported classes (\n\\f3\\fs18 Chromosome\n\\f4\\fs20 , \n\\f3\\fs18 Individual\n\\f4\\fs20 , \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , \n\\f3\\fs18 Mutation\n\\f4\\fs20 ) will be written.  For individuals, the \n\\f3\\fs18 tag\n\\f4\\fs20 , \n\\f3\\fs18 tagF\n\\f4\\fs20 , \n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20  properties will be written; for chromosomes, haplosomes, and mutations, the \n\\f3\\fs18 tag\n\\f4\\fs20  property will be written.  If there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with \n\\f3\\fs18 setValue()\n\\f4\\fs20 , and so forth, you should persist that state in separate files using calls such as \n\\f3\\fs18 writeFile()\n\\f4\\fs20 .\\\nOutput is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(void)outputIndividualsToVCF([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL], [logical$\\'a0outputMultiallelics\\'a0=\\'a0T], [logical$\\'a0simplifyNucleotides\\'a0=\\'a0F], [logical$\\'a0outputNonnucleotides\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output the state of the target vector of individuals in VCF format.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .  This method is quite similar to the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20 , but (1)\\'a0it can produce output for any vector of individuals, rather than sampling from a single population; (2)\\'a0it can produce output regarding the genetics for all chromosomes or for just one focal chromosome, whereas \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20  can only output data for a single chromosome; and (3)\\'a0because it can output genetic information for more than one chromosome, the \n\\f3\\fs18 groupAsIndividuals\n\\f4\\fs20  option provided by \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20  is not available for \n\\f3\\fs18 outputIndividualsToVCF()\n\\f4\\fs20 ; each VCF sample has to correspond directly to one individual.\\\nThe \n\\f3\\fs18 chromosome\n\\f4\\fs20  parameter specifies a focal chromosome for which the genetics of the target individuals will be output.  If \n\\f3\\fs18 chromosome\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , all chromosomes will be output (distinguished in the VCF output by the chromosome symbol output in the \n\\f3\\fs18 CHROM\n\\f4\\fs20  column); otherwise, \n\\f3\\fs18 chromosome\n\\f4\\fs20  may specify the focal chromosome with an \n\\f3\\fs18 integer\n\\f4\\fs20  chromosome id, a \n\\f3\\fs18 string\n\\f4\\fs20  chromosome symbol, or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.\\\nThe parameters \n\\f3\\fs18 outputMultiallelics\n\\f4\\fs20 , \n\\f3\\fs18 simplifyNucleotides\n\\f4\\fs20 , and \n\\f3\\fs18 outputNonnucleotides\n\\f4\\fs20  affect the format of the output produced.\\\nOutput is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(object<Mutation>)readIndividualsFromVCF(string$\\'a0filePath, [Nio<MutationType>$\\'a0mutationType\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Read new mutations from the VCF format file at \n\\f3\\fs18 filePath\n\\f4\\fs20  and add them to the target individuals.  The number of target individuals must match the number of samples represented in the VCF file; each sample will be associated with a corresponding target individual, in the order that the samples and the target individuals are provided.  To read into all of the individuals in a given subpopulation \n\\f3\\fs18 pN\n\\f4\\fs20 , simply call \n\\f3\\fs18 pN.individuals.readIndividualsFromVCF()\n\\f4\\fs20 , assuming the subpopulation\\'92s size matches the number of samples in the VCF file.  A vector containing all of the mutations created by \n\\f3\\fs18 readIndividualsFromVCF()\n\\f4\\fs20  is returned (not necessarily in the order of the corresponding VCF call lines).\\\nThis method and the \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  provide two alternative ways of reading VCF data, focused on the perspective of either individuals (this method) or haplosomes (the \n\\f3\\fs18 Haplosome\n\\f4\\fs20  method).  As described above, this method draws a correspondence between VCF samples and individuals, whereas the \n\\f3\\fs18 Haplosome\n\\f4\\fs20  method draws a correspondence between VCF calls and haplosomes.  For example, if a VCF call line contained a series of calls like \\'93\n\\f3\\fs18 1|1 0|1 1 0 1|0\n\\f4\\fs20 \\'94 this method would see that as calls for five individuals, three of which are diploid for the chromosome being called, and two of which are haploid.  That would make sense if, for example, the chromosome being called is an X chromosome; the diploid individuals would be females, the haploid individuals would be males.  The vector of target individuals would need to contain two females, then two males, and then a female, so that the structure of the calls matched the haplosome structure of the individuals, or an error would result.  The \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , on the other hand, would see that same series of calls as corresponding to eight haplosomes, and would assign each call to the corresponding non-null target haplosome, without regard to whether the VCF\\'92s grouping into diploid and haploid calls corresponded to any coherent structure of individuals in the SLiM model.  Each approach has advantages and disadvantages.  This method provides much more error-checking and safety when your intention is to read individual-level data from VCF; it can check that the ploidy in the VCF data matches the ploidy of each target individual, and that diploid calls like \n\\f3\\fs18 1|1\n\\f4\\fs20  get assigned to the two haplosomes of a single individual correctly.  The \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  does not perform such checks, and can push VCF data into any arbitrary set of haplosomes, so it provides more power and flexibility, but less error-checking and less intelligence.\\\nBecause this method works at the level of individuals, it can read VCF data associated with multiple chromosomes into a multi-chromosome SLiM model and place mutations into the correct haplosomes of each individual based upon the \n\\f3\\fs18 CHROM\n\\f4\\fs20  column of the VCF file (which \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  cannot do).  For this to work, the values in the \n\\f3\\fs18 CHROM\n\\f4\\fs20  column of the call lines must correspond exactly to chromosome symbols in the SLiM model, as provided to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 .  The call lines in the input file may be in any order (they do not have to be sorted by \n\\f3\\fs18 CHROM\n\\f4\\fs20  value, or any other such requirement).  The vector of mutations returned will contain all of the mutations created; when reading multi-chromosome data, that returned vector will therefore contain a mix of mutations with different associated chromosomes.  Alternatively, it would work equally well to make a separate call to \n\\f3\\fs18 readIndividualsFromVCF()\n\\f4\\fs20  for each chromosome, providing each call with a separate VCF file that contains only the mutations associated with one chromosome; in that case, each call would return only the mutations added to the chromosome associated with that call, which might be more convenient if post-processing of the returned mutations is necessary.\\\nAs in \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20 , a call of \n\\f3\\fs18 ~\n\\f4\\fs20  represents the fact that an individual has no genetic information for the chromosome being called; for example, a call line for a mutation on a Y chromosome should have haploid calls for male individuals (they have or do not have the called mutation), and calls of \n\\f3\\fs18 ~\n\\f4\\fs20  for female individuals (they have no Y haplosome at all).  This convention was invented for SLiM, since the VCF standard does not seem to say anything about how sex chromosomes should be represented (or anything about other types of chromosomes that might be absent from some individuals).\\\nThe \n\\f3\\fs18 readHaplosomesFromVCF()\n\\f4\\fs20  method\\'92s documentation provides many important details on how SLiM treats various VCF fields during input; those details will not be repeated here, for brevity.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)relatedness(object<Individual>\\'a0individuals, [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the degrees of relatedness between the receiver and each of the individuals in \n\\f3\\fs18 individuals\n\\f4\\fs20 .  The relatedness between \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  is always \n\\f3\\fs18 1.0\n\\f4\\fs20  if \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  are actually the same individual; this facility works even if SLiM\\'92s optional pedigree tracking is not enabled (in which case all other relatedness values will be \n\\f3\\fs18 0.0\n\\f4\\fs20 ).  Otherwise, if pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , this method will use the pedigree information to construct a relatedness estimate.  The relatedness is calculated based upon the type of the chromosome specified by \n\\f3\\fs18 chromosome\n\\f4\\fs20  (as an \n\\f3\\fs18 integer\n\\f4\\fs20  id, a \n\\f3\\fs18 string\n\\f4\\fs20  symbol, or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object); if \n\\f3\\fs18 chromosome\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , it is assumed to be the single chromosome present in the model, or if more than one chromosome is present, an error results and the chromosome must be explicitly given.\\\nMore specifically, this method uses all available pedigree information from the grandparental and parental pedigree records of \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  to compute an estimate of the degree of consanguinity between \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20 .  When considering a diploid autosome, siblings have a relatedness of \n\\f3\\fs18 0.5\n\\f4\\fs20 , as do parents to their children and vice versa; cousins have a relatedness of \n\\f3\\fs18 0.125\n\\f4\\fs20 ; and so forth.  If, according to the pedigree information available, \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  have no blood relationship, the value returned is \n\\f3\\fs18 0.0\n\\f4\\fs20 .  Note that the value returned by \n\\f3\\fs18 relatedness()\n\\f4\\fs20  is what is called the \\'93coefficient of relationship\\'94 between the two individuals (Wright, 1922; {\\field{\\*\\fldinst{HYPERLINK \"https://doi.org/10.1086/279872\"}}{\\fldrslt \\cf3 \\ul \\ulc3 https://doi.org/10.1086/279872}}), and ranges from \n\\f3\\fs18 0.0\n\\f4\\fs20  to \n\\f3\\fs18 1.0\n\\f4\\fs20 .\\\nThere is another commonly used metric of relatedness, called the \\'93kinship coefficient\\'94, that reflects the probability of identity by descent between two individuals \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20 .  In general, it is approximately equal to one-half of the coefficient of relationship; if an approximate estimate of the kinship coefficient is acceptable, especially in models in which individuals are expected to be outbred, you can simply divide \n\\f3\\fs18 relatedness()\n\\f4\\fs20  by two.  However, it should be noted that Wright\\'92s coefficient of relationship is \n\\f1\\i not\n\\f4\\i0  a measure of the probability of identity by descent, and so it is not exactly double the kinship coefficient; they actually measure different things.  More precisely, the relationship between them is \n\\f6\\i r\n\\f5\\i0 \\'a0=\\'a02\n\\f6\\i \\uc0\\u966 \n\\f5\\i0 /sqrt((1+\n\\f6\\i f\n\\f5\\i0\\fs13\\fsmilli6667 \\sub A\n\\fs20 \\nosupersub )(1+\n\\f6\\i f\n\\f5\\i0\\fs13\\fsmilli6667 \\sub B\n\\fs20 \\nosupersub ))\n\\f4 , where \n\\f6\\i r\n\\f4\\i0  is Wright\\'92s coefficient of relatedness, \n\\f6\\i \\uc0\\u966 \n\\f4\\i0  is the kinship coefficient, and \n\\f6\\i f\n\\f5\\i0\\fs13\\fsmilli6667 \\sub A\n\\f4\\fs20 \\nosupersub  and \n\\f6\\i f\n\\f5\\i0\\fs13\\fsmilli6667 \\sub B\n\\f4\\fs20 \\nosupersub  are the inbreeding coefficients of \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  respectively.\\\nNote that this relatedness is simply pedigree-based relatedness, and does not necessarily correspond to genetic relatedness, because of the effects of factors like assortment and recombination.  If a metric of actual genetic relatedness is desired, tree-sequence recording can be used after simulation is complete, to compute the exact genetic relatedness between individuals based upon the complete ancestry tree (a topic which is beyond the scope of this manual).  Actual genetic relatedness cannot presently be calculated during a simulation run; the information is implicitly contained in the recorded tree-sequence tables, but calculating it is too computationally expensive to be reasonable.\\\nThis method assumes that the grandparents (or the parents, if grandparental information is not available) are themselves unrelated and that they are not inbred; this assumption is necessary because we have no information about their parentage, since SLiM\\'92s pedigree tracking information only goes back two generations.  Be aware that in a model where inbreeding or selfing occurs at all (including \\'93incidental selfing\\'94, where a hermaphroditic individual happens to choose itself as a mate), some level of \\'93background relatedness\\'94 will be present and this assumption will be violated.  In such circumstances, \n\\f3\\fs18 relatedness()\n\\f4\\fs20  will therefore tend to underestimate the degree of relatedness between individuals, and the greater the degree of inbreeding, the greater the underestimation will be.  If inbreeding is allowed in a model \\'96 and particularly if it is common \\'96 the results of \n\\f3\\fs18 relatedness()\n\\f4\\fs20  should therefore not be taken as an estimate of \n\\f1\\i absolute\n\\f4\\i0  relatedness, but can still be useful as an estimate of \n\\f1\\i relative\n\\f4\\i0  relatedness (indicating that, say, A appears from the information available to be more closely related to B than it is to C).\\\nSee also \n\\f3\\fs18 sharedParentCount()\n\\f4\\fs20  for a different metric of relatedness.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n+\\'a0(void)setSpatialPosition(float\\'a0position)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Sets the spatial position of the individual (as accessed through the \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property).  The length of \n\\f3\\fs18 position\n\\f4\\fs20  (the number of coordinates in the spatial position of an individual) depends upon the spatial dimensionality declared with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  If the spatial dimensionality is zero (as it is by default), it is an error to call this method.  The elements of \n\\f3\\fs18 position\n\\f4\\fs20  are set into the values of the \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 z\n\\f4\\fs20  properties (if those properties are encompassed by the spatial dimensionality of the simulation).  In other words, if the declared dimensionality is \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 , calling \n\\f3\\fs18 individual.setSpatialPosition(c(1.0, 0.5))\n\\f4\\fs20  property is equivalent to \n\\f3\\fs18 individual.x\\'a0=\\'a01.0; individual.y\\'a0=\\'a00.5\n\\f4\\fs20 ; \n\\f3\\fs18 individual.z\n\\f4\\fs20  is not set (even if a third value is supplied in \n\\f3\\fs18 position\n\\f4\\fs20 ) since it is not encompassed by the simulation\\'92s dimensionality in this example.\\\nNote that this is an Eidos class method, somewhat unusually, which allows it to work in a special way when called on a vector of individuals.  When the target vector of individuals is non-singleton, this method can do one of two things.  If \n\\f3\\fs18 position\n\\f4\\fs20  contains just a single point (i.e., is equal in length to the spatial dimensionality of the model), the spatial position of all of the target individuals will be set to the given point.  Alternatively, if \n\\f3\\fs18 position\n\\f4\\fs20  contains one point per target individual (i.e., is equal in length to the number of individuals multiplied by the spatial dimensionality of the model), the spatial position of each target individual will be set to the corresponding point from \n\\f3\\fs18 position\n\\f4\\fs20  (where the point data is concatenated, not interleaved, just as it would be returned by accessing the \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property on the vector of target individuals).  Calling this method with a \n\\f3\\fs18 position\n\\f4\\fs20  vector of any other length is an error.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(integer)sharedParentCount(object<Individual>\\'a0individuals)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the number of parents shared between the receiver and each of the individuals in \n\\f3\\fs18 individuals\n\\f4\\fs20 .  The number of shared parents between \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  is always \n\\f3\\fs18 2\n\\f4\\fs20  if \n\\f3\\fs18 A\n\\f4\\fs20  and \n\\f3\\fs18 B\n\\f4\\fs20  are actually the same individual; this facility works even if SLiM\\'92s optional pedigree tracking is not enabled (in which case all other relatedness values will be \n\\f3\\fs18 0\n\\f4\\fs20 ).  Otherwise, if pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , this method will use the pedigree information to construct a relatedness estimate.\\\nMore specifically, this method uses the parental pedigree IDs from the pedigree records of a pair of individuals to count the number of shared parents between them, such that full siblings (with all of the same parents) have a count of \n\\f3\\fs18 2\n\\f4\\fs20 , and half siblings (with half of the same parents) have a count of \n\\f3\\fs18 1\n\\f4\\fs20 .  If possible parents of the two individuals are \n\\f3\\fs18 A\n\\f4\\fs20 , \n\\f3\\fs18 B\n\\f4\\fs20 , \n\\f3\\fs18 C\n\\f4\\fs20 , and \n\\f3\\fs18 D\n\\f4\\fs20 , then the shared parent count is as follows, for some illustrative examples.  The first column showing the two parents of the first individual, the second column showing the two parents of the second individual; note that the two parents of an individual can be the same due to cloning or selfing:\\\n\\pard\\pardeftab720\\li547\\sa60\\partightenfactor0\n\\cf2 \t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 CD\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 0\n\\f4\\fs20  (no shared parents)\\\n\t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 CC\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 0\n\\f4\\fs20  (no shared parents)\\\n\t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 AC\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 1\n\\f4\\fs20  (half siblings)\\\n\t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 AA\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 1\n\\f4\\fs20  (half siblings)\\\n\t\n\\f3\\fs18 AA\n\\f4\\fs20  \n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 1\n\\f4\\fs20  (half siblings)\\\n\t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 2\n\\f4\\fs20  (full siblings)\\\n\t\n\\f3\\fs18 AB\n\\f4\\fs20  \n\\f3\\fs18 BA\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 2\n\\f4\\fs20  (full siblings)\\\n\t\n\\f3\\fs18 AA\n\\f4\\fs20  \n\\f3\\fs18 AA\n\\f4\\fs20  \n\\f7 \\uc0\\u8594 \n\\f4  \n\\f3\\fs18 2\n\\f4\\fs20  (full siblings)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 This method does not estimate consanguinity.  For example, if one individual is itself a parent of the other individual, that is irrelevant for this method.  Similarly, in simulations of sex chromosomes, the sexes of the parents are irrelevant, even if no genetic material would have been inherited from a given parent.  See \n\\f3\\fs18 relatedness()\n\\f4\\fs20  for an assessment of pedigree-based relatedness that does estimate the consanguinity of individuals.  The \n\\f3\\fs18 sharedParentCount()\n\\f4\\fs20  method is preferable if your exact question is simply whether individuals are full siblings, half siblings, or non-siblings; in other cases, \n\\f3\\fs18 relatedness()\n\\f4\\fs20  is probably more useful.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (float$)sumOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns the sum of the selection coefficients of all mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the haplosomes of the individual.  This is often useful in models that use a particular mutation type to represent QTLs with additive effects; in that context, \n\\f3\\fs18 sumOfMutationsOfType()\n\\f4\\fs20  will provide the sum of the additive effects of the QTLs for the given mutation type.  This method is provided for speed; it is much faster than the corresponding Eidos code.  Note that this method also exists on \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , for cases in which the sum for just one haplosome is desired.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (object<Mutation>)uniqueMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 This method has been deprecated, and may be removed in a future release of SLiM.\n\\f4\\b0   Its functionality was replaced by \n\\f3\\fs18 mutationsFromHaplosomes()\n\\f4\\fs20  in SLiM 5.0.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Returns an \n\\f3\\fs18 object\n\\f4\\fs20  vector of all the mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations in the individual.  Mutations present in both homologous haplosomes will occur only once in the result of this method, and the mutations for a given chromosomes will be given in sorted order by \n\\f3\\fs18 position\n\\f4\\fs20 , so in single-chromosome simulations this method is similar to \n\\f3\\fs18 sortBy(unique(individual.haplosomes.mutationsOfType(mutType)), \"position\")\n\\f4\\fs20 .  (Even with a single chromosome it is not identical to that call, since if multiple mutations exist at the exact same position, they may be sorted differently by this method than they would be by \n\\f3\\fs18 sortBy()\n\\f4\\fs20 .)  If you just need a count of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than a vector of the matches, use \n\\f3\\fs18 -countOfMutationsOfType()\n\\f4\\fs20 .  This method is provided for speed; it is much faster than the corresponding Eidos code.  Indeed, it is faster than just \n\\f3\\fs18 individual.haplosomes.mutationsOfType(mutType)\n\\f4\\fs20 , and gives uniquing and sorting on top of that, so it is advantageous unless duplicate entries for homozygous mutations are actually needed.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 +\\'a0(integer)zygosityOfMutations([No<Mutation>\\'a0mutations\\'a0=\\'a0NULL], [integer$\\'a0hemizygousValue\\'a0=\\'a01], [integer$\\'a0haploidValue\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 integer\n\\f4\\fs20  matrix with the target individuals\\'92 zygosity for all of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects passed in \n\\f3\\fs18 mutations\n\\f4\\fs20 .  If the optional \n\\f3\\fs18 mutations\n\\f4\\fs20  argument is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), zygosity values will be returned for all of the active \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects in the species \\'96 the same \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, and in the same order, as would be returned by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of \n\\f3\\fs18 sim\n\\f4\\fs20 , in other words.  The returned matrix has one column for each individual and one row for each mutation.\\\nFor a mutation on a diploid chromosome, the zygosity will be either \n\\f3\\fs18 0\n\\f4\\fs20  (absent), \n\\f3\\fs18 1\n\\f4\\fs20  (heterozygous), or \n\\f3\\fs18 2\n\\f4\\fs20  (homozygous).  This is the straightforward \\'93base case\\'94 that is usually meant by the term \\'93zygosity\\'94.\\\nIf one of the two haplosomes of an intrinsically diploid chromosome is a null haplosome (as would be the case for an X chromosome in a male individual, for example), mutations present in the non-null haplosome are called \\'93hemizygous\\'94, and the zygosity returned for them is configurable using the \n\\f3\\fs18 hemizygousValue\n\\f4\\fs20  parameter.  By default, the zygosity returned for hemizygous mutations is \n\\f3\\fs18 1\n\\f4\\fs20 .\\\nFinally, although the term \\'93zygosity\\'94 is not usually used in the context of haploidy, this method nevertheless supports intrinsically haploid chromosomes; the zygosity returned for mutations present on an intrinsically haploid chromosome is configurable using the \n\\f3\\fs18 haploidValue\n\\f4\\fs20  parameter.  By default, the zygosity returned for haploid mutations is \n\\f3\\fs18 1\n\\f4\\fs20 .\\\nFor a large number of mutations \\'96 and especially for a \n\\f3\\fs18 mutations\n\\f4\\fs20  value of \n\\f3\\fs18 NULL\n\\f4\\fs20 , representing all mutations in the species \\'96 this method should be much more efficient than using methods such as \n\\f3\\fs18 containsMutations()\n\\f4\\fs20  to assess zygosity.  Nevertheless, calculating fitness effects in script based upon zygosity will generally be slower than SLiM\\'92s internal fitness calculations.  Note that for just one or a few mutations \\'96 especially if \n\\f3\\fs18 mutations\n\\f4\\fs20  contains just a small fraction of all of the mutations in the species \\'96 this method will probably be much slower than alternative approaches; this method is optimized for the bulk case.\\\nSee also the method \n\\f3\\fs18 mutationsFromHaplosomes()\n\\f4\\fs20 , which provides an alternative approach for assessing the zygosity of mutations in an individual.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.8  Class InteractionType\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.8.1  \n\\f2\\fs18 InteractionType\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this interaction type; for interaction type \n\\f3\\fs18 i3\n\\f4\\fs20 , for example, this is \n\\f3\\fs18 3\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 maxDistance <\\'96> (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The maximum distance over which this interaction will be evaluated.  For inter-individual distances greater than \n\\f3\\fs18 maxDistance\n\\f5\\fs20 ,\n\\f4  the interaction strength will be zero.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 reciprocal => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The reciprocality of the interaction, as specified in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 .  This will be \n\\f3\\fs18 T\n\\f4\\fs20  for reciprocal interactions (those for which the interaction strength of B upon A is equal to the interaction strength of A upon B), and \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 sexSegregation => (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The sex-segregation of the interaction, as specified in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20  or with \n\\f3\\fs18 setConstraints()\n\\f4\\fs20 .  For non-sexual simulations, this will be \n\\f3\\fs18 \"**\"\n\\f4\\fs20 .  For sexual simulations, this \n\\f3\\fs18 string\n\\f4\\fs20  value indicates the sex of individuals feeling the interaction, and the sex of individuals exerting the interaction; see \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20  for details.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 spatiality => (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The spatial dimensions used by the interaction, as specified in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 .  This will be \n\\f3\\fs18 \"\"\n\\f4\\fs20  (the empty string) for non-spatial interactions, or \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 \"y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"z\"\n\\f4\\fs20 , \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 , \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , \n\\f3\\fs18 \"yz\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 , for interactions using those spatial dimensions respectively.  The specified dimensions are used to calculate the distances between individuals for this interaction.  The value of this property is always the same as the value given to \n\\f3\\fs18 initializeInteractionType()\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to interaction types.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.8.2  \n\\f2\\fs18 InteractionType\n\\f1\\fs22  methods\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(float)clippedIntegral(No<Individual>\\'a0receivers)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the integral of the interaction function as experienced by each of the individuals in \n\\f3\\fs18 receivers\n\\f4\\fs20 .  For each given individual, the interaction function is clipped to the edges of the spatial bounds of the subpopulation that individual inhabits; the individual\\'92s spatial position must be within bounds or an error is raised.  A periodic boundary will, correctly, not clip the interaction function.  The interaction function is also clipped to the interaction\\'92s maximum distance; that distance must be less than half of the extent of the spatial bounds in each dimension (so that, for a given dimension, the interaction function is clipped by the spatial bounds on only one side), otherwise an error is raised.  Note that receiver constraints are not applied; an individual might not actually receive any interactions because of those constraints, but it is still considered to have the same interaction function integral.  If \n\\f3\\fs18 receivers\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the maximal integral is returned, as would be experienced by an individual farther than the maximum distance from any edge.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver subpopulation, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nThe computed value of the integral is not exact; it is calculated by an approximate numerical method designed to be fast, but the error should be fairly small (typically less than 1% from the true value).  A large amount of computation will occur the first time this method is called (perhaps taking more than a second, depending upon hardware), but subsequent calls should be very fast.  This method does not invoke \n\\f3\\fs18 interaction()\n\\f4\\fs20  callbacks; the calculated integrals are only for the interaction function itself, and so will not be accurate if \n\\f3\\fs18 interaction()\n\\f4\\fs20  callbacks modify the relationship between distance and interaction strength.  For this reason, the overhead of the first call will \n\\f1\\i not\n\\f4\\i0  reoccur when individuals move or when the interaction is re-evaluated; for typical models, the initial overhead will be incurred only once.  The initial overhead will reoccur, however, if the interaction function itself, or the maximum interaction distance, are changed; frequent change of those parameters may render the performance of this method unacceptable.\\\nThe integral values returned by \n\\f3\\fs18 clippedIntegral()\n\\f4\\fs20  can be useful for computing interaction metrics that are scaled by the amount of \\'93interaction field\\'94 (to coin a term) that is present for a given individual, producing metrics of interaction \n\\f1\\i density\n\\f4\\i0 .  Notably, the \n\\f3\\fs18 localPopulationDensity()\n\\f4\\fs20  method automatically incorporates the mechanics of \n\\f3\\fs18 clippedIntegral()\n\\f4\\fs20  into the calculations it performs; see that method\\'92s documentation for further discussion of this concept.  This approach can also be useful with the \n\\f3\\fs18 interactingNeighborCount()\n\\f4\\fs20  method, provided that the interaction function is of type \n\\f3\\fs18 \"f\"\n\\f4\\fs20  (since the neighbor count does not depend upon interaction strength).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)distance(object<Individual>$\\'a0receiver, [No<Individual>\\'a0exerters\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing distances between \n\\f3\\fs18 receiver\n\\f4\\fs20  and the individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20 .  If \n\\f3\\fs18 exerters\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then a vector of the distances from \n\\f3\\fs18 receiver\n\\f4\\fs20  to all individuals in its subpopulation (including itself) is returned; this case may be handled differently internally, for greater speed, so supplying \n\\f3\\fs18 NULL\n\\f4\\fs20  is preferable to supplying the vector of all individuals in the subpopulation explicitly.  Otherwise, all individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20  must belong to a single subpopulation (but not necessarily the same subpopulation as \n\\f3\\fs18 receiver\n\\f4\\fs20 ).  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nImportantly, distances are calculated according to the spatiality of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  (as declared in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 ), not the dimensionality of the model as a whole (as declared in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ).  The distances returned are therefore the distances that would be used to calculate interaction strengths.  However, \n\\f3\\fs18 distance()\n\\f4\\fs20  will return finite distances for all pairs of individuals, even if the individuals are non-interacting due to the maximum interaction distance or the interaction constraints; the \n\\f3\\fs18 distance()\n\\f4\\fs20  between an individual and itself will thus be \n\\f3\\fs18 0\n\\f4\\fs20 .  See \n\\f3\\fs18 interactionDistance()\n\\f4\\fs20  for an alternative distance definition.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)distanceFromPoint(float\\'a0point, object<Individual>\\'a0exerters)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing distances between the point given by the spatial coordinates in \n\\f3\\fs18 point\n\\f4\\fs20 , which may be thought of as the \\'93receiver\\'94, and individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20 .  The \n\\f3\\fs18 point\n\\f4\\fs20  vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type\\'92s spatiality is \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , for example, then \n\\f3\\fs18 point[0]\n\\f4\\fs20  is assumed to be an \n\\f1\\i x\n\\f4\\i0  value, and \n\\f3\\fs18 point[1]\n\\f4\\fs20  is assumed to be a \n\\f1\\i z\n\\f4\\i0  value, and \n\\f3\\fs18 point\n\\f4\\fs20  must be exactly two elements in length.  Be careful; this means that in general it is not safe to pass an individual\\'92s \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for \n\\f3\\fs18 point\n\\f4\\fs20 , for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on \n\\f3\\fs18 Individual\n\\f4\\fs20  exist for getting the individual\\'92s coordinates in a particular spatiality, such as the \n\\f3\\fs18 xz\n\\f4\\fs20  property for this example.  A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (\n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.\\\nAll individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20  must belong to a single subpopulation; the \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for that subpopulation, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nImportantly, distances are calculated according to the spatiality of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  (as declared in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 ) not the dimensionality of the model as a whole (as declared in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ).  The distances are therefore interaction distances: the distances that are used to calculate interaction strengths.  However, the maximum interaction distance and interaction constraints are not used.\\\nThis method replaces the \n\\f3\\fs18 distanceToPoint()\n\\f4\\fs20  method that existed prior to SLiM 4.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object)drawByStrength(object<Individual>\\'a0receiver, [integer$\\'a0count\\'a0=\\'a01], [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL], [logical$\\'a0returnDict\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector containing up to \n\\f3\\fs18 count\n\\f4\\fs20  individuals drawn from \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20 , or if that is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then from the subpopulation of \n\\f3\\fs18 receiver\n\\f4\\fs20 , which must be singleton in the default mode of operation (but see below).  The probability of drawing particular individuals is proportional to the strength of interaction they exert upon \n\\f3\\fs18 receiver\n\\f4\\fs20  (which is zero for \n\\f3\\fs18 receiver\n\\f4\\fs20  itself).  All exerters must belong to a single subpopulation (but not necessarily the same subpopulation as \n\\f3\\fs18 receiver\n\\f4\\fs20 ).  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.\\\nThis method may be used with either spatial or non-spatial interactions, but will be more efficient with spatial interactions that set a short maximum interaction distance.  Draws are done with replacement, so the same individual may be drawn more than once; sometimes using \n\\f3\\fs18 unique()\n\\f4\\fs20  on the result of this call is therefore desirable.  If more than one draw will be needed, it is much more efficient to use a single call to \n\\f3\\fs18 drawByStrength()\n\\f4\\fs20 , rather than drawing individuals one at a time.  Note that if no individuals exert a non-zero interaction strength upon \n\\f3\\fs18 receiver\n\\f4\\fs20 , the vector returned will be zero-length; it is important to consider this possibility.\\\nBeginning in SLiM 4.1, this method has a vectorized mode of operation in which the \n\\f3\\fs18 receiver\n\\f4\\fs20  parameter may be non-singleton.  To switch the method to this mode, pass \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 returnDict\n\\f4\\fs20 , rather than the default of \n\\f3\\fs18 F\n\\f4\\fs20  (the operation of which is described above).  In this mode, the return value is a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object instead of a vector of \n\\f3\\fs18 Individual\n\\f4\\fs20  objects.  This dictionary uses \n\\f3\\fs18 integer\n\\f4\\fs20  keys that range from \n\\f3\\fs18 0\n\\f4\\fs20  to \n\\f3\\fs18 N-1\n\\f4\\fs20 , where \n\\f3\\fs18 N\n\\f4\\fs20  is the number of individuals passed in \n\\f3\\fs18 receiver\n\\f4\\fs20 ; these keys thus correspond directly to the indices of the individuals in \n\\f3\\fs18 receiver\n\\f4\\fs20 , and there is one entry in the dictionary for each receiver.  The value in the dictionary, for a given \n\\f3\\fs18 integer\n\\f4\\fs20  key, is an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector with the individuals drawn for the corresponding receiver, exactly as described above for the non-vectorized case.  The results for each receiver can therefore be obtained from the returned dictionary with \n\\f3\\fs18 getValue()\n\\f4\\fs20 , passing the index of the receiver.  The speed of this mode of operation will probably be similar to the speed of making \n\\f3\\fs18 N\n\\f4\\fs20  separate non-vectorized calls to \n\\f3\\fs18 drawByStrength()\n\\f4\\fs20 , when running single-threaded.  When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.  In this mode of operation, all receivers must belong to the same subpopulation.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)evaluate(io<Subpopulation>\\'a0subpops)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Snapshots model state in preparation for the use of the interaction, for the receiver and exerter subpopulations specified by \n\\f3\\fs18 subpops\n\\f4\\fs20 .  The subpopulations may be supplied either as \n\\f3\\fs18 integer\n\\f4\\fs20  IDs, or as \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects.  This method will discard all previously cached data for the subpopulation(s), and will cache the current spatial positions of all individuals they contain (so that the spatial positions of those individuals may then change without disturbing the state of the interaction at the moment of evaluation).  It will also cache which individuals in the subpopulation are eligible to act as exerters, according to the configured exerter constraints, but it will \n\\f1\\i not\n\\f4\\i0  cache such eligibility information for receiver constraints (which are applied at the time a spatial query is made).  Particular interaction distances and strengths are not computed by \n\\f3\\fs18 evaluate()\n\\f4\\fs20 , and \n\\f3\\fs18 interaction()\n\\f4\\fs20  callbacks will not be called in response to this method; that work is deferred until required to satisfy a query (at which point the tick and cycle counters may have advanced, so be careful with the tick ranges used in defining \n\\f3\\fs18 interaction()\n\\f4\\fs20  callbacks).\\\nYou must explicitly call \n\\f3\\fs18 evaluate()\n\\f4\\fs20  at an appropriate time in the tick cycle before the interaction is used, but after any relevant changes have been made to the population.  SLiM will invalidate any existing interactions after any portion of the tick cycle in which new individuals have been born or existing individuals have died.  In a WF model, this occurs just before \n\\f3\\fs18 late()\n\\f4\\fs20  events execute (see the WF tick cycle diagram), so \n\\f3\\fs18 late()\n\\f4\\fs20  events are often the appropriate place to put \n\\f3\\fs18 evaluate()\n\\f4\\fs20  calls, but \n\\f3\\fs18 first()\n\\f4\\fs20  or \n\\f3\\fs18 early()\n\\f4\\fs20  events can work too if the interaction is not needed until that point in the tick cycle anyway. In nonWF models, on the other hand, new offspring are produced just before \n\\f3\\fs18 early()\n\\f4\\fs20  events and then individuals die just before \n\\f3\\fs18 late()\n\\f4\\fs20  events (see the nonWF tick cycle diagram), so interactions will be invalidated twice during each tick cycle.  This means that in a nonWF model, an interaction that influences reproduction should usually be evaluated in a \n\\f3\\fs18 first()\n\\f4\\fs20  event, while an interaction that influences fitness or mortality should usually be evaluated in an \n\\f3\\fs18 early()\n\\f4\\fs20  event (and an interaction that affects both may need to be evaluated at both times).\\\nIf an interaction is never evaluated for a given subpopulation, it is guaranteed that there will be essentially no memory or computational overhead associated with the interaction for that subpopulation.  Furthermore, attempting to query an interaction for a receiver or exerter in a subpopulation that has not been evaluated is guaranteed to raise an error.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(integer)interactingNeighborCount(object<Individual>\\'a0receivers, [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the number of interacting individuals for each individual in \n\\f3\\fs18 receivers\n\\f4\\fs20 , within the maximum interaction distance according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , from among the exerters in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  (or, if that is \n\\f3\\fs18 NULL\n\\f4\\fs20 , then from among all individuals in the receiver\\'92s subpopulation).  More specifically, this method counts the number of individuals which can exert an interaction upon each receiver (which does not include the receiver itself).  All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.\\\nThis method is similar to \n\\f3\\fs18 nearestInteractingNeighbors()\n\\f4\\fs20  (when passed a large count so as to guarantee that all interacting individuals are returned), but this method returns only a count of the interacting individuals, not a vector containing the individuals.\\\nNote that this method uses interaction eligibility as a criterion; it will not count neighbors that do not exert an interaction upon a given receiver (due to the configured receiver or exerter constraints).  (It also does not count a receiver as a neighbor of itself.)  If a count of all neighbors is desired, rather than just interacting neighbors, use \n\\f3\\fs18 neighborCount()\n\\f4\\fs20 .  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(float)interactionDistance(object<Individual>$\\'a0receiver, [No<Individual>\\'a0exerters\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns a vector containing interaction-dependent distances between \n\\f3\\fs18 receiver\n\\f4\\fs20  and individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20 .  If \n\\f3\\fs18 exerters\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then a vector of the interaction-dependent distances from \n\\f3\\fs18 receiver\n\\f4\\fs20  to all individuals in its subpopulation (including \n\\f3\\fs18 receiver\n\\f4\\fs20  itself) is returned; this case may be handled much more efficiently than if a vector of all individuals in the subpopulation is explicitly provided.  Otherwise, all individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20  must belong to a single subpopulation (but not necessarily the same subpopulation as \n\\f3\\fs18 receiver\n\\f4\\fs20 ).  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nImportantly, distances are calculated according to the spatiality of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  (as declared in \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 ), not the dimensionality of the model as a whole (as declared in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ).  The distances returned are therefore the distances that would be used to calculate interaction strengths.  In addition, \n\\f3\\fs18 interactionDistance()\n\\f4\\fs20  will return \n\\f3\\fs18 INF\n\\f4\\fs20  as the distance between \n\\f3\\fs18 receiver\n\\f4\\fs20  and any individual which does not exert an interaction upon \n\\f3\\fs18 receiver\n\\f4\\fs20 ; the \n\\f3\\fs18 interactionDistance()\n\\f4\\fs20  between an individual and itself will thus be \n\\f3\\fs18 INF\n\\f4\\fs20 , and likewise for pairs excluded from interacting by receiver constraints, exerter constraints, or the maximum interaction distance of the interaction type.  See \n\\f3\\fs18 distance()\n\\f4\\fs20  for an alternative distance definition.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)localPopulationDensity(object<Individual>\\'a0receivers, [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of the local population density present at the location of each individual in \n\\f3\\fs18 receivers\n\\f4\\fs20 , which does not need to be a singleton; indeed, it can be a vector of all of the individuals in a given subpopulation.  However, all receivers must be in the same subpopulation.  The local population density is computed from exerters in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20 , or if that is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then from the receiver\\'92s subpopulation.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.\\\nPopulation density is estimated using interaction strengths, effectively doing a kernel density estimate using the interaction function as the kernel.  What is returned is computed as the total interaction strength present at a given point, divided by the integral of the interaction function around that point after clipping by the spatial bounds of the exerter subpopulation (what one might think of as the amount of \\'93interaction field\\'94 around the point).  This provides an estimate of local population density, in units of individuals per unit area, as a weighted average over the area covered by the interaction function, where the weight of each exerter in the average is the value of the interaction function at that exerter\\'92s position.  This can also be thought of as a measure of the amount of interaction happening per unit of interaction field in the space surrounding the point.\\\nTo calculate the clipped integral of the interaction function, this method uses the same numerical estimator used by the \n\\f3\\fs18 clippedIntegral()\n\\f4\\fs20  method of \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , and all of the caveats described for that method apply here also; notably, all individuals must be within spatial bounds, the maximum interaction distance must be less than half the spatial extent of the subpopulation, and \n\\f3\\fs18 interaction()\n\\f4\\fs20  callbacks are not used (and so, for this method, are not allowed to be active).  See the documentation for \n\\f3\\fs18 clippedIntegral()\n\\f4\\fs20  for further discussion of the details of these calculations.\\\nTo calculate the total interaction strength around the position of a receiver, this method uses the same machinery as the \n\\f3\\fs18 totalOfNeighborStrengths()\n\\f4\\fs20  method of \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , \n\\f1\\i except\n\\f4\\i0  that \\'96 in contrast to other \n\\f3\\fs18 InteractionType\n\\f4\\fs20  methods \\'96 the interaction strength exerted by the receiver itself is included in the total (if the exerter subpopulation is the receiver\\'92s own subpopulation).  This is because population density at the location of an individual includes the individual itself.  If this is not desirable, the \n\\f3\\fs18 totalOfNeighborStrengths()\n\\f4\\fs20  method should probably be used.\\\nTo see the point of this method, consider a receiver located near the edge of the spatial bounds of its subpopulation.  Some portion of the interaction function that surrounds that receiver falls outside the spatial bounds of its subpopulation, and will therefore never contain an interacting exerter.  If, for example, interaction strengths are used as a measure of competition, this receiver will therefore have an advantage, because it will never feel any competition from the portion of its range that falls outside spatial bounds.  However, that portion of its range is presumably also not available to the receiver itself, for foraging or hunting, in which case this advantage is not biologically realistic, but is instead just an undesirable \\'93edge effect\\'94 artifact.  Dividing by the integral of the interaction function, clipped to the spatial bounds, provides a way to compensate for this edge effect.  A nice side effect of using local population densities instead of total interaction strengths is that the maximum interaction strength passed to \n\\f3\\fs18 setInteractionFunction()\n\\f4\\fs20  no longer matters; it cancels out when the total interaction strength is divided by the receiver\\'92s clipped integral.  However, the \n\\f1\\i shape\n\\f4\\i0  of the interaction function does still matter; it determines the relative weights used for exerters at different distances from the position of the receiver.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object)nearestInteractingNeighbors(object<Individual>\\'a0receiver, [integer$\\'a0count\\'a0=\\'a01], [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL], [logical$\\'a0returnDict\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector containing up to \n\\f3\\fs18 count\n\\f4\\fs20  interacting individuals that are spatially closest to \n\\f3\\fs18 receiver\n\\f4\\fs20 , according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , from among the exerters in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  (or, if that is \n\\f3\\fs18 NULL\n\\f4\\fs20 , then from among all individuals in the receiver\\'92s subpopulation).  More specifically, this method returns only individuals which can exert an interaction upon \n\\f3\\fs18 receiver\n\\f4\\fs20 , which must be singleton in the default mode of operation (but see below).  To obtain all of the interacting individuals within the maximum interaction distance of \n\\f3\\fs18 receiver\n\\f4\\fs20 , simply pass a value for \n\\f3\\fs18 count\n\\f4\\fs20  that is greater than or equal to the size of the exerter subpopulation.  Note that if fewer than \n\\f3\\fs18 count\n\\f4\\fs20  interacting individuals are within the maximum interaction distance, the vector returned may be shorter than \n\\f3\\fs18 count\n\\f4\\fs20 , or even zero-length; it is important to check for this possibility even when requesting a single neighbor.  If only the number of interacting individuals is needed, use \n\\f3\\fs18 interactingNeighborCount()\n\\f4\\fs20  instead.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nNote that this method uses interaction eligibility as a criterion; it will not return neighbors that cannot exert an interaction upon the receiver (due to the configured receiver or exerter constraints).  (It will also never return the receiver as a neighbor of itself.)  To find all neighbors of a receiver, whether they can interact with it or not, use \n\\f3\\fs18 nearestNeighbors()\n\\f4\\fs20 .\\\nBeginning in SLiM 4.1, this method has a vectorized mode of operation in which the \n\\f3\\fs18 receiver\n\\f4\\fs20  parameter may be non-singleton.  To switch the method to this mode, pass \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 returnDict\n\\f4\\fs20 , rather than the default of \n\\f3\\fs18 F\n\\f4\\fs20  (the operation of which is described above).  In this mode, the return value is a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object instead of a vector of \n\\f3\\fs18 Individual\n\\f4\\fs20  objects.  This dictionary uses \n\\f3\\fs18 integer\n\\f4\\fs20  keys that range from \n\\f3\\fs18 0\n\\f4\\fs20  to \n\\f3\\fs18 N-1\n\\f4\\fs20 , where \n\\f3\\fs18 N\n\\f4\\fs20  is the number of individuals passed in \n\\f3\\fs18 receiver\n\\f4\\fs20 ; these keys thus correspond directly to the indices of the individuals in \n\\f3\\fs18 receiver\n\\f4\\fs20 , and there is one entry in the dictionary for each receiver.  The value in the dictionary, for a given \n\\f3\\fs18 integer\n\\f4\\fs20  key, is an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector with the interacting neighbors found for the corresponding receiver, exactly as described above for the non-vectorized case.  The results for each receiver can therefore be obtained from the returned dictionary with \n\\f3\\fs18 getValue()\n\\f4\\fs20 , passing the index of the receiver.  The speed of this mode of operation will probably be similar to the speed of making \n\\f3\\fs18 N\n\\f4\\fs20  separate non-vectorized calls to \n\\f3\\fs18 nearestInteractingNeighbors()\n\\f4\\fs20 , when running single-threaded.  When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.  In this mode of operation, all receivers must belong to the same subpopulation.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object)nearestNeighbors(object<Individual>\\'a0receiver, [integer$\\'a0count\\'a0=\\'a01], [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL], [logical$\\'a0returnDict\\'a0=\\'a0F])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector containing up to \n\\f3\\fs18 count\n\\f4\\fs20  individuals that are spatially closest to \n\\f3\\fs18 receiver\n\\f4\\fs20 , according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , from among the exerters in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  (or, if that is \n\\f3\\fs18 NULL\n\\f4\\fs20 , then from among all individuals in the receiver\\'92s subpopulation).  In the default mode of operation, \n\\f3\\fs18 receiver\n\\f4\\fs20  must be singleton (but see below).  To obtain all of the individuals within the maximum interaction distance of \n\\f3\\fs18 receiver\n\\f4\\fs20 , simply pass a value for \n\\f3\\fs18 count\n\\f4\\fs20  that is greater than or equal to the size of \n\\f3\\fs18 individual\n\\f4\\fs20 \\'92s subpopulation.  Note that if fewer than \n\\f3\\fs18 count\n\\f4\\fs20  individuals are within the maximum interaction distance, the vector returned may be shorter than \n\\f3\\fs18 count\n\\f4\\fs20 , or even zero-length; it is important to check for this possibility even when requesting a single neighbor.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Note that this method does not use interaction eligibility as a criterion; it will return neighbors that could not interact with the receiver due to the configured receiver or exerter constraints.  (It will never return the receiver as a neighbor of itself, however.)  To find only neighbors that are eligible to exert an interaction upon the receiver, use \n\\f3\\fs18 nearestInteractingNeighbors()\n\\f4\\fs20 .\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Beginning in SLiM 4.1, this method has a vectorized mode of operation in which the \n\\f3\\fs18 receiver\n\\f4\\fs20  parameter may be non-singleton.  To switch the method to this mode, pass \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 returnDict\n\\f4\\fs20 , rather than the default of \n\\f3\\fs18 F\n\\f4\\fs20  (the operation of which is described above).  In this mode, the return value is a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object instead of a vector of \n\\f3\\fs18 Individual\n\\f4\\fs20  objects.  This dictionary uses \n\\f3\\fs18 integer\n\\f4\\fs20  keys that range from \n\\f3\\fs18 0\n\\f4\\fs20  to \n\\f3\\fs18 N-1\n\\f4\\fs20 , where \n\\f3\\fs18 N\n\\f4\\fs20  is the number of individuals passed in \n\\f3\\fs18 receiver\n\\f4\\fs20 ; these keys thus correspond directly to the indices of the individuals in \n\\f3\\fs18 receiver\n\\f4\\fs20 , and there is one entry in the dictionary for each receiver.  The value in the dictionary, for a given \n\\f3\\fs18 integer\n\\f4\\fs20  key, is an \n\\f3\\fs18 object<Individual>\n\\f4\\fs20  vector with the neighbors found for the corresponding receiver, exactly as described above for the non-vectorized case.  The results for each receiver can therefore be obtained from the returned dictionary with \n\\f3\\fs18 getValue()\n\\f4\\fs20 , passing the index of the receiver.  The speed of this mode of operation will probably be similar to the speed of making \n\\f3\\fs18 N\n\\f4\\fs20  separate non-vectorized calls to \n\\f3\\fs18 nearestNeighbors()\n\\f4\\fs20 , when running single-threaded.  When running multi-threaded, however, a substantial performance improvement may be realized by using the vectorized version of this method, since the queries can then be executed in parallel.  In this mode of operation, all receivers must belong to the same subpopulation.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)nearestNeighborsOfPoint(float\\'a0point, io<Subpopulation>$\\'a0exerterSubpop, [integer$\\'a0count\\'a0=\\'a01])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns up to \n\\f3\\fs18 count\n\\f4\\fs20  individuals in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  that are spatially closest to the point given by the spatial coordinates in \n\\f3\\fs18 point\n\\f4\\fs20 , which may be thought of as the \\'93receiver\\'94, according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 .  The \n\\f3\\fs18 point\n\\f4\\fs20  vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type\\'92s spatiality is \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , for example, then \n\\f3\\fs18 point[0]\n\\f4\\fs20  is assumed to be an \n\\f1\\i x\n\\f4\\i0  value, and \n\\f3\\fs18 point[1]\n\\f4\\fs20  is assumed to be a \n\\f1\\i z\n\\f4\\i0  value, and \n\\f3\\fs18 point\n\\f4\\fs20  must be exactly two elements in length.  Be careful; this means that in general it is not safe to pass an individual\\'92s \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for \n\\f3\\fs18 point\n\\f4\\fs20 , for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on \n\\f3\\fs18 Individual\n\\f4\\fs20  exist for getting the individual\\'92s coordinates in a particular spatiality, such as the \n\\f3\\fs18 xz\n\\f4\\fs20  property for this example.  A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (\n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.\\\nThe subpopulation may be supplied either as an \n\\f3\\fs18 integer\n\\f4\\fs20  ID, or as a \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object.  To obtain all of the individuals within the maximum interaction distance of \n\\f3\\fs18 point\n\\f4\\fs20 , simply pass a value for \n\\f3\\fs18 count\n\\f4\\fs20  that is greater than or equal to the size of \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20 .  Note that if fewer than \n\\f3\\fs18 count\n\\f4\\fs20  individuals are within the maximum interaction distance, the vector returned may be shorter than \n\\f3\\fs18 count\n\\f4\\fs20 , or even zero-length; it is important to check for this possibility even when requesting a single neighbor.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20 , and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(integer)neighborCount(object<Individual>\\'a0receivers, [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the number of neighbors for each individual in \n\\f3\\fs18 receivers\n\\f4\\fs20 , within the maximum interaction distance according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , from among the individuals in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  (or, if that is \n\\f3\\fs18 NULL\n\\f4\\fs20 , then from among all individuals in the receiver\\'92s subpopulation).  All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 This method is similar to \n\\f3\\fs18 nearestNeighbors()\n\\f4\\fs20  (when passed a large count so as to guarantee that all neighbors are returned), but this method returns only a count of the individuals, not a vector containing the individuals.\\\nNote that this method does not use interaction eligibility as a criterion; it will count neighbors that cannot exert an interaction upon a receiver (due to the configured receiver or exerter constraints).  (It still does not count a receiver as a neighbor of itself, however.)  If a count of only interacting neighbors is desired, use \n\\f3\\fs18 interactingNeighborCount()\n\\f4\\fs20 .  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(integer$)neighborCountOfPoint(float\\'a0point, io<Subpopulation>$\\'a0exerterSubpop)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the number of individuals in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  that are within the maximum interaction distance of the point given by the spatial coordinates in \n\\f3\\fs18 point\n\\f4\\fs20 , which may be thought of as the \\'93receiver\\'94, according to the distance metric of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20 .  The \n\\f3\\fs18 point\n\\f4\\fs20  vector is interpreted as providing coordinates precisely as specified by the spatiality of the interaction type; if the interaction type\\'92s spatiality is \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , for example, then \n\\f3\\fs18 point[0]\n\\f4\\fs20  is assumed to be an \n\\f1\\i x\n\\f4\\i0  value, and \n\\f3\\fs18 point[1]\n\\f4\\fs20  is assumed to be a \n\\f1\\i z\n\\f4\\i0  value, and \n\\f3\\fs18 point\n\\f4\\fs20  must be exactly two elements in length.  Be careful; this means that in general it is not safe to pass an individual\\'92s \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for \n\\f3\\fs18 point\n\\f4\\fs20 , for example (although it is safe if the spatiality of the interaction matches the dimensionality of the simulation); other properties on \n\\f3\\fs18 Individual\n\\f4\\fs20  exist for getting the individual\\'92s coordinates in a particular spatiality, such as the \n\\f3\\fs18 xz\n\\f4\\fs20  property for this example.  A coordinate for a periodic spatial dimension must be within the spatial bounds for that dimension, since coordinates outside of periodic bounds are meaningless (\n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  may be used to ensure this); coordinates for non-periodic spatial dimensions are not restricted.\\\nThe subpopulation may be supplied either as an \n\\f3\\fs18 integer\n\\f4\\fs20  ID, or as a \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20 , and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\nThis method is similar to \n\\f3\\fs18 nearestNeighborsOfPoint()\n\\f4\\fs20  (when passed a large count so as to guarantee that all neighbors are returned), but this method returns only a count of the individuals, not a vector containing the individuals.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setConstraints(string$\\'a0who, [Ns$\\'a0sex\\'a0=\\'a0NULL], [Ni$\\'a0tag\\'a0=\\'a0NULL], [Ni$\\'a0minAge\\'a0=\\'a0NULL], [Ni$\\'a0maxAge\\'a0=\\'a0NULL], [Nl$\\'a0migrant\\'a0=\\'a0NULL], [Nl$\\'a0tagL0\\'a0=\\'a0NULL], [Nl$\\'a0tagL1\\'a0=\\'a0NULL], [Nl$\\'a0tagL2\\'a0=\\'a0NULL], [Nl$\\'a0tagL3\\'a0=\\'a0NULL], [Nl$\\'a0tagL4\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Sets constraints upon which individuals can be receivers and/or exerters, making the target \n\\f3\\fs18 InteractionType\n\\f4\\fs20  measure interactions between only subsets of the population.  The parameter \n\\f3\\fs18 who\n\\f4\\fs20  specifies upon whom the specified constraints apply; it may be \n\\f3\\fs18 \"exerter\"\n\\f4\\fs20  to set constraints upon exerters, \n\\f3\\fs18 \"receiver\"\n\\f4\\fs20  to set constraints upon receivers, or \n\\f3\\fs18 \"both\"\n\\f4\\fs20  to set constraints upon both.  If \n\\f3\\fs18 \"both\"\n\\f4\\fs20  is used, the \n\\f1\\i same\n\\f4\\i0  constraints are set for both exerters and receivers; \n\\f1\\i different\n\\f4\\i0  constraints can be set for exerters versus receivers by making a separate call to \n\\f3\\fs18 setConstraints()\n\\f4\\fs20  for each.  Constraints only affect queries that involve the concept of interaction; for example, they will affect the result of \n\\f3\\fs18 nearestInteractingNeighbors()\n\\f4\\fs20 , but not the result of \n\\f3\\fs18 nearestNeighbors()\n\\f4\\fs20 .  The constraints specified by a given call to \n\\f3\\fs18 setConstraints()\n\\f4\\fs20  override all previously set constraints for the category specified (receivers, exerters, or both).\\\nThere is a general policy for the remaining arguments: they are \n\\f3\\fs18 NULL\n\\f4\\fs20  by default, and if \n\\f3\\fs18 NULL\n\\f4\\fs20  is used, it specifies \\'93no constraint\\'94 for that property (removing any currently existing constraint for that property).  The \n\\f3\\fs18 sex\n\\f4\\fs20  parameter constrains the sex of individuals; it may be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \\'93F\"\n\\f4\\fs20  (or \n\\f3\\fs18 \"*\"\n\\f4\\fs20  as another way of specifying no constraint, for historical reasons).  If \n\\f3\\fs18 sex\n\\f4\\fs20  is \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20 , the individuals to which the constraint is applied (potential receivers/exerters) must belong to a sexual species.  The \n\\f3\\fs18 tag\n\\f4\\fs20  parameter constrains the \n\\f3\\fs18 tag\n\\f4\\fs20  property of individuals; if this set, the individuals to which the constraint is applied must have defined \n\\f3\\fs18 tag\n\\f4\\fs20  values.  The \n\\f3\\fs18 minAge\n\\f4\\fs20  and \n\\f3\\fs18 maxAge\n\\f4\\fs20  properties constrain the \n\\f3\\fs18 age\n\\f4\\fs20  property of individuals to the given minimum and/or maximum values; these constraints can only be used in nonWF models.  The \n\\f3\\fs18 migrant\n\\f4\\fs20  property constraints the \n\\f3\\fs18 migrant\n\\f4\\fs20  property of individuals (\n\\f3\\fs18 T\n\\f4\\fs20  constrains to only migrants, \n\\f3\\fs18 F\n\\f4\\fs20  to only non-migrants).  Finally, the \n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20  properties constrain the corresponding \n\\f3\\fs18 logical\n\\f4\\fs20  properties of individuals, requiring them to be either \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20  as specified; the individuals to which these constraints are applied must have defined values for the constrained property or properties.  Again, \n\\f3\\fs18 NULL\n\\f4\\fs20  should be supplied (as it is by default) for any property which you do not wish to constrain.\\\nThese constraints may be used in any combination, as desired.  For example, calling \n\\f3\\fs18 setConstraints(\"receivers\", sex=\"M\", minAge=5, tagL0=T)\n\\f4\\fs20  constrains the interaction type\\'92s operation so that receivers must be males, with an \n\\f3\\fs18 age\n\\f4\\fs20  of at least \n\\f3\\fs18 5\n\\f4\\fs20 , with a \n\\f3\\fs18 tagL0\n\\f4\\fs20  property value of \n\\f3\\fs18 T\n\\f4\\fs20 .  For that configuration the potential receivers used with the interaction type must be sexual (since \n\\f3\\fs18 sex\n\\f4\\fs20  is specified), must be in a nonWF model (since \n\\f3\\fs18 minAge\n\\f4\\fs20  is specified), and must have a defined value for their \n\\f3\\fs18 tagL0\n\\f4\\fs20  property (since that property is constrained).  Note that the \n\\f3\\fs18 sexSegregation\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20  is a shortcut which does the same thing as the corresponding calls to \n\\f3\\fs18 setConstraints()\n\\f4\\fs20 .\\\nExerter constraints are applied at \n\\f3\\fs18 evaluate()\n\\f4\\fs20  time, whereas receiver constraints are applied at query time; see the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  class documentation for further discussion.  The interaction constraints for an interaction type are normally a constant in simulations; in any case, they cannot be changed when an interaction has already been evaluated, so either they should be set prior to evaluation, or \n\\f3\\fs18 unevaluate()\n\\f4\\fs20  should be called first.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setInteractionFunction(string$\\'a0functionType, ...)\n\\f5 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Set the function used to translate spatial distances into interaction strengths for an interaction type.  The \n\\f3\\fs18 functionType\n\\f4\\fs20  may be \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , in which case the ellipsis \n\\f3\\fs18 ...\n\\f4\\fs20  should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  fixed interaction strength; \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  maximum strength for a linear function; \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  maximum strength and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  lambda (rate) parameter for a negative exponential function; \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  maximum strength and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  sigma (standard deviation) parameter for a Gaussian function; \n\\f3\\fs18 \"c\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  maximum strength and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a Cauchy distribution function; or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  maximum strength, a \n\\f3\\fs18 numeric$\n\\f4\\fs20  degrees of freedom, and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a \n\\f1\\i t\n\\f4\\i0 -distribution function.  See the InteractionType class documentation for discussions of these interaction functions.  Non-spatial interactions must use function type \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , since no distance values are available in that case.\\\nThe interaction function for an interaction type is normally a constant in simulations; in any case, it cannot be changed when an interaction has already been evaluated, so either it should be set prior to evaluation, or \n\\f3\\fs18 unevaluate()\n\\f4\\fs20  should be called first.\n\\f5 \\cf0 \\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)strength(object<Individual>$\\'a0receiver, [No<Individual>\\'a0exerters\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the interaction strengths exerted upon \n\\f3\\fs18 receiver\n\\f4\\fs20  by the individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20 .  If \n\\f3\\fs18 exerters\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), then a vector of the interaction strengths exerted by all individuals in the subpopulation of \n\\f3\\fs18 receiver\n\\f4\\fs20  (including \n\\f3\\fs18 receiver\n\\f4\\fs20  itself, with a strength of \n\\f3\\fs18 0.0\n\\f4\\fs20 ) is returned; this case may be handled much more efficiently than if a vector of all individuals in the subpopulation is explicitly provided.  Otherwise, all individuals in \n\\f3\\fs18 exerters\n\\f4\\fs20  must belong to a single subpopulation (but not necessarily the same subpopulation as \n\\f3\\fs18 receiver\n\\f4\\fs20 ).  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 If the strengths of interactions exerted by a single individual upon multiple individuals are needed instead (the inverse of what this method provides), multiple calls to this method will be necessary, one per pairwise interaction queried; the interaction engine is not optimized for the inverse case, and so it will likely be quite slow to compute.  If the interaction is reciprocal and has the same receiver and exerter constraints, the opposite query should provide identical results in a single efficient call (because then the interactions exerted are equal to the interactions received); otherwise, the best approach might be to define a second interaction type representing the inverse interaction that you wish to be able to query efficiently.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(lo<Individual>)testConstraints(object<Individual>\\'a0individuals, string$\\'a0constraints, [logical$\\'a0returnIndividuals\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Tests the individuals in the parameter \n\\f3\\fs18 individuals\n\\f4\\fs20  against the interaction constraints specified by \n\\f3\\fs18 constraints\n\\f4\\fs20 .  The value of \n\\f3\\fs18 constraints\n\\f4\\fs20  may be \n\\f3\\fs18 \"receiver\"\n\\f4\\fs20  to use the receiver constraints, or \n\\f3\\fs18 \"exerter\"\n\\f4\\fs20  to use the exerter constraints.  If \n\\f3\\fs18 returnIndividuals\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), a \n\\f3\\fs18 logical\n\\f4\\fs20  vector will be returned, with \n\\f3\\fs18 T\n\\f4\\fs20  values indicating that the corresponding individual satisfied the constraints, \n\\f3\\fs18 F\n\\f4\\fs20  values indicating that it did not.  If \n\\f3\\fs18 returnIndividuals\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , an \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20  will be returned containing only those elements of \n\\f3\\fs18 individuals\n\\f4\\fs20  that satisfied the constraints (in the same order as \n\\f3\\fs18 individuals\n\\f4\\fs20 ).  Note that unlike most queries, the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  does not need to have been evaluated before calling this method, and the individuals passed in need not belong to a single population or even a single species.\\\nThis method can be useful for narrowing a vector of individuals down to just those that satisfy constraints.  Outside the context of \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , similar functionality is provided by the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 subsetIndividuals()\n\\f4\\fs20 .  Note that the use of \n\\f3\\fs18 testConstraints()\n\\f4\\fs20  is somewhat rare; usually, queries are evaluated across a vector of individuals, each of which might or might not satisfy the defined constraints.  Individuals that do not satisfy constraints do not participate in interactions, so their interaction strength with other individuals will simply be zero.\\\nSee the \n\\f3\\fs18 setConstraints()\n\\f4\\fs20  method to set up constraints, as well as the \n\\f3\\fs18 sexSegregation\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeInteractionType()\n\\f4\\fs20 .  Note that if the constraints tested involve \n\\f3\\fs18 tag\n\\f4\\fs20  values (including \n\\f3\\fs18 tagL0\n\\f4\\fs20  / \n\\f3\\fs18 tagL1\n\\f4\\fs20  / \n\\f3\\fs18 tagL2\n\\f4\\fs20  / \n\\f3\\fs18 tagL3\n\\f4\\fs20  / \n\\f3\\fs18 tagL4\n\\f4\\fs20 ), the corresponding property or properties of the tested individuals must be defined (i.e., must have been set to a value), or an error will result because the constraints cannot be applied.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)totalOfNeighborStrengths(object<Individual>\\'a0receivers, [No<Subpopulation>$\\'a0exerterSubpop\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of the total interaction strength felt by each individual in \n\\f3\\fs18 receivers\n\\f4\\fs20  by the exerters in \n\\f3\\fs18 exerterSubpop\n\\f4\\fs20  (or, if that is \n\\f3\\fs18 NULL\n\\f4\\fs20 , then by all individuals in the receiver\\'92s subpopulation).  The \n\\f3\\fs18 receivers\n\\f4\\fs20  parameter does not need to be a singleton; indeed, it can be a vector of all of the individuals in a given subpopulation.  All of the receivers must belong to a single subpopulation, and all of the exerters must belong to a single subpopulation, but those two subpopulations do not need to be the same.  The \n\\f3\\fs18 evaluate()\n\\f4\\fs20  method must have been previously called for the receiver and exerter subpopulations, and positions saved at evaluation time will be used.  If the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is non-spatial, this method may not be called.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 For one individual, this is essentially the same as calling \n\\f3\\fs18 nearestInteractingNeighbors()\n\\f4\\fs20  with a large \n\\f3\\fs18 count\n\\f4\\fs20  so as to obtain the complete vector of all interacting neighbors, calling \n\\f3\\fs18 strength()\n\\f4\\fs20  for each of those interactions to get each interaction strength, and adding those interaction strengths together with \n\\f3\\fs18 sum()\n\\f4\\fs20 .  This method is much faster than that implementation, however, since all of that work is done as a single operation.  Also, \n\\f3\\fs18 totalOfNeighborStrengths()\n\\f4\\fs20  can total up interactions for more than one receiver in a single vectorized call.\\\nSimilarly, for one individual this is essentially the same as calling \n\\f3\\fs18 strength()\n\\f4\\fs20  to get the interaction strengths between a receiver and all individuals in the exerter subpopulation, and then calling \n\\f3\\fs18 sum()\n\\f4\\fs20 .  Again, this method should be much faster, since this algorithm looks only at neighbors, whereas calling \n\\f3\\fs18 strength()\n\\f4\\fs20  directly assesses interaction strengths with all other individuals.  This will make a particularly large difference when the subpopulation size is large and the maximum distance of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is small.\\\nSee \n\\f3\\fs18 localPopulationDensity()\n\\f4\\fs20  for a related method that calculates the total interaction strength divided by the amount of \\'93interaction field\\'94 present for an individual (i.e., the integral of the interaction function clipped to the spatial bounds of the subpopulation) to provide an estimate of the \\'93interaction density\\'94 felt by an individual.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)unevaluate(void)\n\\f5 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Discards all evaluation of this interaction, for all subpopulations.  The state of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  is reset to a state prior to evaluation.  This can be useful if the model state has changed in such a way that the evaluation already conducted is no longer valid.  For example, if the maximum distance, the interaction function, or the receiver or exerter constraints of the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  need to be changed with immediate effect, or if the data used by an \n\\f3\\fs18 interaction()\n\\f4\\fs20  callback has changed in such a way that previously calculated interaction strengths are no longer correct, \n\\f3\\fs18 unevaluate()\n\\f4\\fs20  allows the interaction to begin again from scratch.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn WF models, all interactions are automatically reset to an unevaluated state at the moment when the new offspring generation becomes the parental generation (at step 4 in the tick cycle).\\\nIn nonWF models, all interactions are automatically reset to an unevaluated state twice per tick: immediately after \n\\f3\\fs18 reproduction()\n\\f4\\fs20  callbacks have completed (after step 1 in the tick cycle), and immediately before viability/survival selection (before step 4 in the tick cycle).\\\nGiven this automatic invalidation, most simulations have no reason to call \n\\f3\\fs18 unevaluate()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 \\kerning1\\expnd0\\expndtw0 5.9  Class LogFile\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf2 5.9.1  \n\\f2\\fs18 LogFile\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 filePath => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The path of the log file being written to.  This may be changed with \n\\f3\\fs18 setFilePath()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 logInterval => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The interval for automatic logging; a new row of data will be logged every \n\\f3\\fs18 logInterval\n\\f4\\fs20  ticks.  This may be set with the \n\\f3\\fs18 logInterval\n\\f4\\fs20  parameter to \n\\f3\\fs18 createLogFile()\n\\f4\\fs20  and changed with \n\\f3\\fs18 setLogInterval()\n\\f4\\fs20 .  If automatic logging has been disabled, this property will be \n\\f3\\fs18 0\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 precision <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The precision of \n\\f3\\fs18 float\n\\f4\\fs20  output.  To be exact, \n\\f3\\fs18 precision\n\\f4\\fs20  specifies the preferred number of significant digits that will be output for \n\\f3\\fs18 float\n\\f4\\fs20  values.  The default is \n\\f3\\fs18 6\n\\f4\\fs20 ; values in [\n\\f3\\fs18 1\n\\f4\\fs20 ,\n\\f3\\fs18 22\n\\f4\\fs20 ] are legal, but \n\\f3\\fs18 17\n\\f4\\fs20  is probably the largest value that makes sense given the limits of double-precision floating point.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.9.2  \n\\f2\\fs18 LogFile\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(void)addCustomColumn(string$\\'a0columnName, string$\\'a0source, [*\\'a0context\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column with its name provided by \n\\f3\\fs18 columnName\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  The value for the column, when a given row is generated, will be produced by the code supplied in \n\\f3\\fs18 source\n\\f4\\fs20 , which is expected to return either \n\\f3\\fs18 NULL\n\\f4\\fs20  (which will write out \n\\f3\\fs18 NA\n\\f4\\fs20 ), or a singleton value of any non-object type.\\\nThe \n\\f3\\fs18 context\n\\f4\\fs20  parameter will be set up as a pseudo-parameter, named \n\\f3\\fs18 context\n\\f4\\fs20 , when \n\\f3\\fs18 source\n\\f4\\fs20  is called, allowing the same source code to be used to generate values for multiple data columns; you might, for example, pass the \n\\f3\\fs18 id\n\\f4\\fs20  of the particular \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object that you wish \n\\f3\\fs18 source\n\\f4\\fs20  to use for its calculations, and \n\\f3\\fs18 source\n\\f4\\fs20  could then use the \n\\f3\\fs18 Community\n\\f4\\fs20  method \n\\f3\\fs18 subpopulationsWithIDs()\n\\f4\\fs20  to look up the subpopulation from the \n\\f3\\fs18 id\n\\f4\\fs20  value provided in \n\\f3\\fs18 context\n\\f4\\fs20 .\\\nNote that the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object itself cannot be passed in \n\\f3\\fs18 context\n\\f4\\fs20 , because class \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  is not under retain-release memory management in SLiM, meaning essentially that subpopulation objects can cease to exist unpredictably (because they go extinct, for example).  A reference to such an object cannot be kept long-term by your script (including by \n\\f3\\fs18 LogFile\n\\f4\\fs20 ), because if the object ceases to exist, the reference would become invalid and a crash would result.  Passing such an object \\'96 one not under retain-release \\'96 to \n\\f3\\fs18 addCustomColumn()\n\\f4\\fs20  will therefore raise an error, to safeguard against that possible crash.  The workaround for this limitation is to find a way to look up the desired object, such as the suggestion above of using the subpopulation\\'92s \n\\f3\\fs18 id\n\\f4\\fs20  to look it up.\\\nThe use of \n\\f3\\fs18 context\n\\f4\\fs20  is optional; if the default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  is used, then \n\\f3\\fs18 context\n\\f4\\fs20  will be \n\\f3\\fs18 NULL\n\\f4\\fs20  when \n\\f3\\fs18 source\n\\f4\\fs20  is called.\\\nSee \n\\f3\\fs18 addMeanSDColumns()\n\\f4\\fs20  for a useful variant.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addCycle([No<Species>$\\'a0species\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the cycle counter for \n\\f3\\fs18 species\n\\f4\\fs20  (the same as the value of the \n\\f3\\fs18 cycle\n\\f4\\fs20  property of that species).  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  In single-species models, \n\\f3\\fs18 species\n\\f4\\fs20  may be \n\\f3\\fs18 NULL\n\\f4\\fs20  to indicate that single species.  The column will simply be named \n\\f3\\fs18 cycle\n\\f4\\fs20  in single-species models; an underscore and the name of the species will be appended in multispecies models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addCycleStage(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the cycle stage, named \n\\f3\\fs18 cycle_stage\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  The stage is provided as a \n\\f3\\fs18 string\n\\f4\\fs20 , and will typically be \n\\f3\\fs18 \"first\"\n\\f4\\fs20 , \n\\f3\\fs18 \"early\"\n\\f4\\fs20 , \n\\f3\\fs18 \"late\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"end\"\n\\f4\\fs20  (the latter used for the point in time at which end-of-tick automatic logging occurs).  Other possible values are discussed in the documentation for the \n\\f3\\fs18 cycleStage\n\\f4\\fs20  property of \n\\f3\\fs18 Community\n\\f4\\fs20 , which this column reflects.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addKeysAndValuesFrom(object<Dictionary>$\\'a0source)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method has an override in \n\\f3\\fs18 LogFile\n\\f4\\fs20  to make it illegal to call, since \n\\f3\\fs18 LogFile\n\\f4\\fs20  manages its \n\\f3\\fs18 Dictionary\n\\f4\\fs20  entries.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addMeanSDColumns(string$\\'a0columnName, string$\\'a0source, [*\\'a0context\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds two new data columns with names of \n\\f3\\fs18 columnName_mean\n\\f4\\fs20  and \n\\f3\\fs18 columnName_sd\n\\f4\\fs20 .  The new columns will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  When a given row is generated, the code supplied in \n\\f3\\fs18 source\n\\f4\\fs20  is expected to return either a zero-length vector of any type including \n\\f3\\fs18 NULL\n\\f4\\fs20  (which will write out \n\\f3\\fs18 NA\n\\f4\\fs20  to both columns), or a non-zero-length vector of \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  values.  In the latter case, the result vector will be summarized in the two columns by its mean and standard deviation respectively.  If the result vector has exactly one value, the standard deviation will be written as \n\\f3\\fs18 NA\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 context\n\\f4\\fs20  parameter is set up as a pseudo-parameter when \n\\f3\\fs18 source\n\\f4\\fs20  is called, as described in \n\\f3\\fs18 addCustomColumn()\n\\f4\\fs20 .  See the documentation for that method for further discussion of \n\\f3\\fs18 context\n\\f4\\fs20 , including limitations on its use.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addPopulationSexRatio([No<Species>$\\'a0species\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the population sex ratio M:(M+F) for \n\\f3\\fs18 species\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  In single-species models, \n\\f3\\fs18 species\n\\f4\\fs20  may be \n\\f3\\fs18 NULL\n\\f4\\fs20  to indicate that single species.  The column will simply be named \n\\f3\\fs18 sex_ratio\n\\f4\\fs20  in single-species models; an underscore and the name of the species will be appended in multispecies models.  If the species is hermaphroditic, \n\\f3\\fs18 NA\n\\f4\\fs20  will be written.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addPopulationSize([No<Species>$\\'a0species\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the total population size for \n\\f3\\fs18 species\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  In single-species models, \n\\f3\\fs18 species\n\\f4\\fs20  may be \n\\f3\\fs18 NULL\n\\f4\\fs20  to indicate that single species.  The column will simply be named \n\\f3\\fs18 num_individuals\n\\f4\\fs20  in single-species models; an underscore and the name of the species will be appended in multispecies models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addSubpopulationSexRatio(io<Subpopulation>$\\'a0subpop)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the sex ratio M:(M+F) of the subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20 , named \n\\f3\\fs18 pX_sex_ratio\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  If the subpopulation exists but has a size of zero, \n\\f3\\fs18 NA\n\\f4\\fs20  will be written.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addSubpopulationSize(io<Subpopulation>$\\'a0subpop)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column that provides the size of the subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20 , named \n\\f3\\fs18 pX_num_individuals\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  If the subpopulation exists but has a size of zero, \n\\f3\\fs18 0\n\\f4\\fs20  will be written.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addSuppliedColumn(string$\\'a0columnName)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column with its name provided by \n\\f3\\fs18 columnName\n\\f4\\fs20 .  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .  The value for the column is initially undefined, and will be written as \n\\f3\\fs18 NA\n\\f4\\fs20 .  A different value may (optionally) be provided by calling \n\\f3\\fs18 setSuppliedValue()\n\\f4\\fs20  with a value for \n\\f3\\fs18 columnName\n\\f4\\fs20 .  That value will be used for the column the next time a row is generated (whether automatically or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 ), and the column\\'92s value will subsequently be undefined again.  In other words, for any given logged row the default of \n\\f3\\fs18 NA\n\\f4\\fs20  may be kept, or a different value may be supplied.  This allows the value for the column to be set at any point during the tick cycle, which can be convenient if the column\\'92s value depends upon transient state that is no longer available at the time the row is logged.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addTick(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a new data column, named \n\\f3\\fs18 tick\n\\f4\\fs20 , that provides the tick number for the simulation.  The new column will be logged each time that a row is generated, either by automatic logging or by a call to \n\\f3\\fs18 logRow()\n\\f4\\fs20 .\n\\f3\\fs18 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\\cf2 \\'96\\'a0(void)clearKeysAndValues(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method has an override in \n\\f3\\fs18 LogFile\n\\f4\\fs20  to make it illegal to call, since \n\\f3\\fs18 LogFile\n\\f4\\fs20  manages its \n\\f3\\fs18 Dictionary\n\\f4\\fs20  entries.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)flush(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Flushes all buffered data to the output file, synchronously.  This will make the contents of the file on disk be up-to-date with the running simulation.  Flushing frequently may entail a small performance penalty.  More importantly, if \n\\f3\\fs18 .gz\n\\f4\\fs20  compression has been requested with \n\\f3\\fs18 compress=T\n\\f4\\fs20  the size of the resulting file will be larger \\'96 potentially much larger \\'96 if \n\\f3\\fs18 flush()\n\\f4\\fs20  is called frequently.  Note that automatic periodic flushing can be requested with the \n\\f3\\fs18 flushInterval\n\\f4\\fs20  parameter to \n\\f3\\fs18 createLogFile()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)logRow(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This logs a new row of data, by evaluating all of the generators added to the \n\\f3\\fs18 LogFile\n\\f4\\fs20  with \n\\f3\\fs18 add...()\n\\f4\\fs20  calls.  Note that the new row may be buffered, and thus may not be written out to disk immediately; see \n\\f3\\fs18 flush()\n\\f4\\fs20 .  This method may be used instead of, or in conjunction with, automatic logging.\\\nYou can get the \n\\f3\\fs18 LogFile\n\\f4\\fs20  instance, in order to call \n\\f3\\fs18 logRow()\n\\f4\\fs20  on it, from \n\\f3\\fs18 community.logFiles\n\\f4\\fs20 , or you can remember it in a global constant with \n\\f3\\fs18 defineConstant()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setLogInterval([Ni$\\'a0logInterval\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Sets the automatic logging interval.  A \n\\f3\\fs18 logInterval\n\\f4\\fs20  of \n\\f3\\fs18 NULL\n\\f4\\fs20  stops automatic logging immediately.  Other values request that a new row should be logged (as if \n\\f3\\fs18 logRow()\n\\f4\\fs20  were called) at the end of every \n\\f3\\fs18 logInterval\n\\f4\\fs20  ticks (just before the tick count increment, in both WF and nonWF models), starting at the end of the tick in which \n\\f3\\fs18 setLogInterval()\n\\f4\\fs20  was called.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setFilePath(string$\\'a0filePath, [Ns\\'a0initialContents\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [Nl$\\'a0compress\\'a0=\\'a0NULL], [Ns$\\'a0sep\\'a0=\\'a0NULL], [Nl$\\'a0header\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Redirects the \n\\f3\\fs18 LogFile\n\\f4\\fs20  to write new rows to a new \n\\f3\\fs18 filePath\n\\f4\\fs20 .  Any rows that have been buffered but not flushed will be written to the previous file first, as if \n\\f3\\fs18 flush()\n\\f4\\fs20  had been called.  With this call, new \n\\f3\\fs18 initialContents\n\\f4\\fs20  may be supplied, which will either replace any existing file or will be appended to it, depending upon the value of \n\\f3\\fs18 append\n\\f4\\fs20 .  New values may be supplied for \n\\f3\\fs18 compress\n\\f4\\fs20 , \n\\f3\\fs18 sep\n\\f4\\fs20 , and \n\\f3\\fs18 header\n\\f4\\fs20 ; the meaning of these parameters is identical to their meaning in \n\\f3\\fs18 createLogFile()\n\\f4\\fs20 , except that a value of \n\\f3\\fs18 NULL\n\\f4\\fs20  for these means \\'93do not change this setting from its previous value\\'94.  In effect, then, this method lets you start a completely new log file at a new path, without having to create and configure a new \n\\f3\\fs18 LogFile\n\\f4\\fs20  object.  The new file will be created (or appended) synchronously, with the specified initial contents.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setSuppliedValue(string$\\'a0columnName, +$\\'a0value)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Registers a value, passed in \n\\f3\\fs18 value\n\\f4\\fs20 , to be used for the supplied column named \n\\f3\\fs18 columnName\n\\f4\\fs20  when a row is next logged.  This column must have been added with \n\\f3\\fs18 addSuppliedColumn()\n\\f4\\fs20 .  A value of \n\\f3\\fs18 NULL\n\\f4\\fs20  may be passed to log \n\\f3\\fs18 NA\n\\f4\\fs20 , but logging \n\\f3\\fs18 NA\n\\f4\\fs20  is the default behavior for supplied columns in any case.  Otherwise, the value must be a singleton, and its type should match the values previously supplied for the column (otherwise the log file may be difficult to parse, since the values within the column will not be of one consistent type).  See \n\\f3\\fs18 addSuppliedColumn()\n\\f4\\fs20  for further details.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setValue(is$\\'a0key, *\\'a0value)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This \n\\f3\\fs18 Dictionary\n\\f4\\fs20  method has an override in \n\\f3\\fs18 LogFile\n\\f4\\fs20  to make it illegal to call, since \n\\f3\\fs18 LogFile\n\\f4\\fs20  manages its \n\\f3\\fs18 Dictionary\n\\f4\\fs20  entries.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(logical$)willAutolog(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns \n\\f3\\fs18 T\n\\f4\\fs20  if the log file is configured to log a new row automatically at the end of the current tick; otherwise, returns \n\\f3\\fs18 F\n\\f4\\fs20 .  This is useful for calculating a value that will be logged only in ticks when the value is needed.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.10  Class Mutation\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.10.1  \n\\f2\\fs18 Mutation\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 chromosome => (object<Chromosome>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object with which the mutation is associated.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this mutation.  Each mutation created during a run receives an immutable identifier that will be unique across the duration of the run.  These identifiers are not re-used during a run, except that if a population file is loaded from disk, the loaded mutations will receive their original identifier values as saved in the population file.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 isFixed => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 T\n\\f4\\fs20  if the mutation has fixed (in the SLiM sense of having been converted to a \n\\f3\\fs18 Substitution\n\\f4\\fs20  object), \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.  Since fixed/substituted mutations are removed from the simulation, you will only see this flag be \n\\f3\\fs18 T\n\\f4\\fs20  if you have held onto a mutation beyond its usual lifetime.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 isSegregating => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 T\n\\f4\\fs20  if the mutation is segregating (in the SLiM sense of not having been either lost or converted to a \n\\f3\\fs18 Substitution\n\\f4\\fs20  object), \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.  Since both lost and fixed/substituted mutations are removed from the simulation, you will only see this flag be \n\\f3\\fs18 F\n\\f4\\fs20  if you have held onto a mutation beyond its usual lifetime.  Note that if \n\\f3\\fs18 isSegregating\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , \n\\f3\\fs18 isFixed\n\\f4\\fs20  will let you determine whether the mutation is no longer segregating because it was lost, or because it fixed.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationType => (object<MutationType>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 MutationType\n\\f4\\fs20  from which this mutation was drawn.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nnucleotide <\\'96> (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A \n\\f3\\fs18 string\n\\f4\\fs20  representing the nucleotide associated with this mutation; this will be \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"C\"\n\\f4\\fs20 , \n\\f3\\fs18 \"G\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"T\"\n\\f4\\fs20 .  If the mutation is not nucleotide-based, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 nucleotideValue <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 An \n\\f3\\fs18 integer\n\\f4\\fs20  representing the nucleotide associated with this mutation; this will be \n\\f3\\fs18 0\n\\f4\\fs20  (A), \n\\f3\\fs18 1\n\\f4\\fs20  (C), \n\\f3\\fs18 2\n\\f4\\fs20  (G), or \n\\f3\\fs18 3\n\\f4\\fs20  (T).  If the mutation is not nucleotide-based, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 originTick => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The tick in which this mutation arose.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 position => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The position in the chromosome of this mutation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 selectionCoeff => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The selection coefficient of the mutation, drawn from the distribution of fitness effects of its \n\\f3\\fs18 MutationType\n\\f5\\fs20 .\n\\f4 \\cf2 \\expnd0\\expndtw0\\kerning0\n  If a mutation has a \n\\f3\\fs18 selectionCoeff\n\\f4\\fs20  of \n\\f1\\i s\n\\f4\\i0 , the multiplicative fitness effect of the mutation in a homozygote is 1+\n\\f1\\i s\n\\f4\\i0 ; in a heterozygote it is 1+\n\\f1\\i hs\n\\f4\\i0 , where \n\\f1\\i h\n\\f4\\i0  is the dominance coefficient kept by the mutation type.\n\\f5 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\n\\f4 Note that this property has a quirk: it is stored internally in SLiM using a single-precision float, not the double-precision float type normally used by Eidos.  This means that if you set a mutation \n\\f3\\fs18 mut\n\\f4\\fs20 \\'92s selection coefficient to some number \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 mut.selectionCoeff==x\n\\f4\\fs20  may be \n\\f3\\fs18 F\n\\f4\\fs20  due to floating-point rounding error.  Comparisons of floating-point numbers for exact equality is often a bad idea, but this is one case where it may fail unexpectedly.  Instead, it is recommended to use the \n\\f3\\fs18 id\n\\f4\\fs20  or \n\\f3\\fs18 tag\n\\f4\\fs20  properties to identify particular mutations.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 subpopID <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier of the subpopulation in which this mutation arose.  This property can be used to track the ancestry of mutations through their subpopulation of origin.\\\nIf you don\\'92t care which subpopulation a mutation originated in, the \n\\f3\\fs18 subpopID\n\\f4\\fs20  may be used as an arbitrary \n\\f3\\fs18 integer\n\\f4\\fs20  \\'93tag\\'94 value for any purpose you wish; SLiM does not do anything with the value of \n\\f3\\fs18 subpopID\n\\f4\\fs20  except propagate it to \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects and report it in output.  (It must still be \n\\f3\\fs18 >= 0\n\\f4\\fs20 , however, since SLiM object identifiers are limited to nonnegative integers).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.10.2  \n\\f2\\fs18 Mutation\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 \\'96\\'a0(void)setMutationType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the mutation type of the mutation to \n\\f3\\fs18 mutType\n\\f4\\fs20  (which may be specified as either an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier or a \n\\f3\\fs18 MutationType\n\\f4\\fs20  object).  This implicitly changes the dominance coefficient of the mutation to that of the new mutation type, since the dominance coefficient is a property of the mutation type.  On the other hand, the selection coefficient of the mutation is not changed, since it is a property of the mutation object itself; it can be changed explicitly using the \n\\f3\\fs18 setSelectionCoeff()\n\\f4\\fs20  method if so desired.\\\nThe mutation type of a mutation is normally a constant in simulations, so be sure you know what you are doing.  Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn nucleotide-based models, a restriction applies: nucleotide-based mutations may not be changed to a non-nucleotide-based mutation type, and non-nucleotide-based mutations may not be changed to a nucleotide-based mutation type.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(void)setSelectionCoeff(float$\\'a0selectionCoeff)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the selection coefficient of the mutation to \n\\f3\\fs18 selectionCoeff\n\\f4\\fs20 .  The selection coefficient will be changed for all individuals that possess the mutation, since they all share a single \n\\f3\\fs18 Mutation\n\\f4\\fs20  object (note that the dominance coefficient will remain unchanged, as it is determined by the mutation type).\\\nThis is normally a constant in simulations, so be sure you know what you are doing; often setting up a \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  callback is preferable, in order to modify the selection coefficient in a more limited and controlled fashion.  Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.11  Class MutationType\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.11.1  \n\\f2\\fs18 MutationType\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 color <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The color used to display mutations of this type in SLiMgui.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20 .  If \n\\f3\\fs18 color\n\\f4\\fs20  is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui\\'92s default (selection-coefficient\\'96based) color scheme is used; this is the default for new \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 colorSubstitution <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The color used to display substitutions of this type in SLiMgui (see the discussion for the \n\\f3\\fs18 colorSubstitution\n\\f4\\fs20  property of the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  class for details).  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20 .  If \n\\f3\\fs18 colorSubstitution\n\\f4\\fs20  is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui\\'92s default (selection-coefficient\\'96based) color scheme is used; this is the default for new \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 convertToSubstitution <\\'96> (logical$)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThis property governs whether mutations of this mutation type will be converted to \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects when they reach fixation.\\\nIn WF models this property is \n\\f3\\fs18 T\n\\f4\\fs20  by default, since conversion to \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects provides large speed benefits; it should be set to \n\\f3\\fs18 F\n\\f4\\fs20  only if necessary, and only on the mutation types for which it is necessary.  This might be needed, for example, if you are using a \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  callback to implement an epistatic relationship between mutations; a mutation epistatically influencing the fitness of other mutations through a \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  callback would need to continue having that influence even after reaching fixation, but if the simulation were to replace the fixed mutation with a \n\\f3\\fs18 Substitution\n\\f4\\fs20  object the mutation would no longer be considered in fitness calculations (unless the callback explicitly consulted the list of \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects kept by the simulation).  Other script-defined behaviors in \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20 , \n\\f3\\fs18 interaction()\n\\f4\\fs20 , \n\\f3\\fs18 mateChoice()\n\\f4\\fs20 , \n\\f3\\fs18 modifyChild()\n\\f4\\fs20 , and \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks might also necessitate the disabling of substitution for a given mutation type; this is an important consideration to keep in mind.\\\nIn contrast, for nonWF models this property is \n\\f3\\fs18 F\n\\f4\\fs20  by default, because even mutations with no epistatis or other indirect fitness effects will continue to influence the survival probabilities of individuals.  For nonWF models, only neutral mutation types with no epistasis or other side effects can safely be converted to substitutions upon fixation.  When such a pure-neutral mutation type is defined in a nonWF model, this property should be set to \n\\f3\\fs18 T\n\\f4\\fs20  to tell SLiM that substitution is allowed; this may have very large positive effects on performance, so it is important to remember when modeling background neutral mutations.\\\nSLiM consults this flag at the end of each tick when deciding whether to substitute each fixed mutation.  If this flag is \n\\f3\\fs18 T\n\\f4\\fs20 , all eligible fixed mutations will be converted at the end of the current tick, even if they were previously left unconverted because of the previous value of the flag.  Setting this flag to \n\\f3\\fs18 F\n\\f4\\fs20  will prevent future substitutions, but will not cause any existing \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects to be converted back into \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 distributionParams => (fs)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The parameters that configure the chosen distribution of fitness effects.  This will be of type \n\\f3\\fs18 string\n\\f4\\fs20  for DFE type \n\\f3\\fs18 \"s\"\n\\f4\\fs20 , and type \n\\f3\\fs18 float\n\\f4\\fs20  for all other DFE types.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 distributionType => (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The type of distribution of fitness effects; one of \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"g\"\n\\f5\\fs20 ,\n\\f4  \n\\f3\\fs18 \"e\"\n\\f5\\fs20 ,\n\\f4  \n\\f3\\fs18 \"n\"\n\\f5\\fs20 ,\n\\f4  \n\\f3\\fs18 \"w\"\n\\f5\\fs20 ,\n\\f4  or \n\\f3\\fs18 \"s\"\n\\f5\\fs20 :\\\n\n\\f3\\fs18 \"f\"\n\\f4\\fs22  \\'96 A \n\\f0\\b f\n\\f4\\b0 ixed fitness effect.  This DFE type has a single parameter, the selection coefficient \n\\f1\\i s\n\\f4\\i0  to be used by all mutations of the mutation type.\\\n\n\\f3\\fs18 \"g\"\n\\f4\\fs22  \\'96 A \n\\f0\\b g\n\\f4\\b0 amma-distributed fitness effect.  This DFE type is specified by two parameters, a shape parameter and a mean value.  The gamma distribution from which mutations are drawn is given by the probability density function \n\\f6\\i P\n\\f5\\i0 (\n\\f6\\i s\n\\f5\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u945 \n\\f5\\i0 ,\n\\f8\\i \\uc0\\u946 \n\\f5\\i0 )\\'a0\n\\f9 = [\\uc0\\u915 (\n\\f8\\i \\uc0\\u945 \n\\f5\\i0 )\n\\f8\\i \\uc0\\u946 \\u945 \n\\f5\\i0 ]\\super \\uc0\\u8722 1\\nosupersub exp(\\uc0\\u8722 \n\\f6\\i s\n\\f5\\i0 /\n\\f8\\i \\uc0\\u946 \n\\f5\\i0 )\n\\f4 , where \n\\f8\\i \\uc0\\u945 \n\\f4\\i0  is the shape parameter, and the specified mean for the distribution is equal to \n\\f8\\i \\uc0\\u945 \\u946 \n\\f4\\i0 .  Note that this parameterization is the same as for the Eidos function \n\\f3\\fs18 rgamma()\n\\f4\\fs22 .  A gamma distribution is often used to model deleterious mutations at functional sites.\\\n\n\\f3\\fs18 \"e\"\n\\f4\\fs22  \\'96 An \n\\f0\\b e\n\\f4\\b0 xponentially-distributed fitness effect.  This DFE type is specified by a single parameter, the mean of the distribution.  The exponential distribution from which mutations are drawn is given by the probability density function \n\\f6\\i P\n\\f5\\i0 (\n\\f6\\i s\n\\f5\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u946 \n\\f5\\i0 )\\'a0= \n\\f8\\i \\uc0\\u946 \n\\f5\\i0 \\super \\uc0\\u8722 1\\nosupersub exp(\\uc0\\u8722 \n\\f6\\i s\n\\f5\\i0 /\n\\f8\\i \\uc0\\u946 \n\\f5\\i0 )\n\\f4 , where \n\\f8\\i \\uc0\\u946 \n\\f4\\i0  is the specified mean for the distribution.  This parameterization is the same as for the Eidos function \n\\f3\\fs18 rexp()\n\\f4\\fs22 .  An exponential distribution is often used to model beneficial mutations.\\\n\n\\f3\\fs18 \"n\"\n\\f4\\fs22  \\'96 A \n\\f0\\b n\n\\f4\\b0 ormally-distributed fitness effect.  This DFE type is specified by two parameters, a mean and a standard deviation.  The normal distribution from which mutations are drawn is given by the probability density function \n\\f6\\i P\n\\f5\\i0 (\n\\f6\\i s\n\\f5\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u956 \n\\f5\\i0 ,\n\\f8\\i \\uc0\\u963 \n\\f5\\i0 )\\'a0= (2\n\\f9 \\uc0\\u960 \n\\f8\\i \\uc0\\u963 \n\\f5\\i0 \\super 2\\nosupersub )\\super \\uc0\\u8722 1/2\\nosupersub exp(\\uc0\\u8722 (\n\\f6\\i s\n\\f5\\i0 \\uc0\\u8722 \n\\f8\\i \\uc0\\u956 \n\\f5\\i0 )\\super 2\\nosupersub /2\n\\f8\\i \\uc0\\u963 \n\\f5\\i0 \\super 2\\nosupersub )\n\\f4 , where \n\\f8\\i \\uc0\\u956 \n\\f4\\i0  is the mean and \n\\f8\\i \\uc0\\u963 \n\\f4\\i0  is the standard deviation.  This parameterization is the same as for the Eidos function \n\\f3\\fs18 rnorm()\n\\f4\\fs22 .  A normal distribution is often used to model mutations that can be either beneficial or deleterious, since both tails of the distribution are unbounded.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \"p\"\n\\f4\\fs22  \\'96 A La\n\\f0\\b p\n\\f4\\b0 lace-distributed fitness effect.  This DFE type is specified by two parameters, a mean and a scale.  The Laplace distribution from which mutations are drawn is given by the probability density function \n\\f6\\i P\n\\f5\\i0 (\n\\f6\\i s\n\\f5\\i0 \\'a0|\\'a0\n\\f6\\i \\uc0\\u956 \n\\f5\\i0 ,\n\\f6\\i b\n\\f5\\i0 )\\'a0= exp(\\uc0\\u8722 |\n\\f6\\i s\n\\f5\\i0 \\uc0\\u8722 \n\\f6\\i \\uc0\\u956 \n\\f5\\i0 |/\n\\f6\\i b\n\\f5\\i0 )/2\n\\f6\\i b\n\\f4\\i0 , where \n\\f6\\i \\uc0\\u956 \n\\f4\\i0  is the mean and \n\\f6\\i b\n\\f4\\i0  is the scale parameter.  A Laplace distribution is sometimes used to model a mix of both deleterious and beneficial mutations.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \"w\"\n\\f4\\fs22  \\'96 A \n\\f0\\b W\n\\f4\\b0 eibull-distributed fitness effect.  This DFE type is specified by a scale parameter and a shape parameter.  The Weibull distribution from which mutations are drawn is given by the probability density function \n\\f6\\i P\n\\f5\\i0 (\n\\f6\\i s\n\\f5\\i0 \\'a0|\\'a0\n\\f8\\i \\uc0\\u955 \n\\f5\\i0 ,\n\\f6\\i k\n\\f5\\i0 )\\'a0= (\n\\f6\\i k\n\\f5\\i0 /\n\\f8\\i \\uc0\\u955 \n\\f6 \\super k\n\\f5\\i0 \\nosupersub )\n\\f6\\i s\\super k\n\\f5\\i0 \\uc0\\u8722 1\\nosupersub exp(\\uc0\\u8722 (\n\\f6\\i s\n\\f5\\i0 /\n\\f8\\i \\uc0\\u955 \n\\f5\\i0 )\n\\f6\\i \\super k\n\\f5\\i0 \\nosupersub )\n\\f4 , where \n\\f8\\i \\uc0\\u955 \n\\f4\\i0  is the scale parameter and \n\\f6\\i k\n\\f4\\i0  is the shape parameter.  This parameterization is the same as for the Eidos function \n\\f3\\fs18 rweibull()\n\\f4\\fs22 .  A Weibull distribution is often used to model mutations following extreme-value theory.\\\n\n\\f3\\fs18 \"s\"\n\\f4\\fs22  \\'96 A \n\\f0\\b s\n\\f4\\b0 cript-based fitness effect.  This DFE type is specified by a script parameter of type \n\\f3\\fs18 string\n\\f4\\fs22 , specifying an Eidos script to be executed to produce each new selection coefficient.  For example, the script \n\\f3\\fs18 \"return rbinom(1);\"\n\\f4\\fs22  could be used to generate selection coefficients drawn from a binomial distribution, using the Eidos function \n\\f3\\fs18 rbinom()\n\\f4\\fs22 , even though that mutational distribution is not supported by SLiM directly.  The script must return a singleton float or integer.\\\nNote that these distributions can in principle produce selection coefficients smaller than \n\\f3\\fs18 -1.0. \n\\f4\\fs22 In that case\n\\f5 ,\n\\f4  the mutations will be evaluated as \\'93lethal\\'94 by SLiM, and the relative fitness of the individual will be set to \n\\f3\\fs18 0.0\n\\f5\\fs22 .\n\\fs20 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 dominanceCoeff <\\'96> (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The dominance coefficient used for mutations of this type when heterozygous.  Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\nNote that the dominance coefficient is not bounded.  A dominance coefficient greater than \n\\f3\\fs18 1.0\n\\f4\\fs20  may be used to achieve an overdominance effect.  By making the selection coefficient very small and the dominance coefficient very large, an overdominance scenario in which both homozygotes have the same fitness may be approximated, to a nearly arbitrary degree of precision.\\\nNote that this property has a quirk: it is stored internally in SLiM using a single-precision float, not the double-precision float type normally used by Eidos.  This means that if you set a mutation type \n\\f3\\fs18 muttype\n\\f4\\fs20 \\'92s dominance coefficient to some number \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 muttype.dominanceCoeff==x\n\\f4\\fs20  may be \n\\f3\\fs18 F\n\\f4\\fs20  due to floating-point rounding error.  Comparisons of floating-point numbers for exact equality is often a bad idea, but this is one case where it may fail unexpectedly.  Instead, it is recommended to use the \n\\f3\\fs18 id\n\\f4\\fs20  or \n\\f3\\fs18 tag\n\\f4\\fs20  properties to identify particular mutation types.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 hemizygousDominanceCoeff <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The dominance coefficient used for mutations of this type when they occur opposite a null haplosome (as can occur in sex-chromosome models and models involving a mix of haploids and diploids).  This defaults to \n\\f3\\fs18 1.0\n\\f4\\fs20 , and is used only in models where null haplosomes are present; the \n\\f3\\fs18 dominanceCoeff\n\\f4\\fs20  property is the dominance coefficient used in most circumstances.  Changing this will normally affect the fitness values calculated toward the end of the current tick; if you want current fitness values to be affected, you can call the \n\\f3\\fs18 Species\n\\f4\\fs20  method \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  \\'96 but see the documentation of that method for caveats.\\\nAs with the \n\\f3\\fs18 dominanceCoeff\n\\f4\\fs20  property, this is stored internally using a single-precision float; see the documentation for \n\\f3\\fs18 dominanceCoeff\n\\f4\\fs20  for discussion.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this mutation type; for mutation type \n\\f3\\fs18 m3\n\\f4\\fs20 , for example, this is \n\\f3\\fs18 3\n\\f5\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationStackGroup <\\'96> (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The group into which this mutation type belongs for purposes of mutation stacking policy.  This is equal to the mutation type\\'92s \n\\f3\\fs18 id\n\\f4\\fs20  by default.  See \n\\f3\\fs18 mutationStackPolicy\n\\f4\\fs20 , below, for discussion.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn nucleotide-based models, the stacking group for nucleotide-based mutation types is always \n\\f3\\fs18 -1\n\\f4\\fs20 , and cannot be changed.  Non-nucleotide-based mutation types may also be set to share the \n\\f3\\fs18 -1\n\\f4\\fs20  stacking group, if they should participate in the same stacking policy as nucleotide-based mutations, but that would be quite unusual.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 mutationStackPolicy <\\'96> (string$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 This property and the \n\\f3\\fs18 mutationStackGroup\n\\f4\\fs20  property together govern whether mutations of this mutation type\\'92s stacking group can \\'93stack\\'94 \\'96 can occupy the same position in a single individual.  A set of mutation types with the same value for \n\\f3\\fs18 mutationStackGroup\n\\f4\\fs20  is called a \\'93stacking group\\'94, and all mutation types in a given stacking group must have the same \n\\f3\\fs18 mutationStackPolicy\n\\f4\\fs20  value, which defines the stacking behavior of all mutations of the mutation types in the stacking group.  In other words, one stacking group might allow its mutations to stack, while another stacking group might not, but the policy within each stacking group must be unambiguous.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThis property is \n\\f3\\fs18 \"s\"\n\\f4\\fs20  by default, indicating that mutations in this stacking group should be allowed to stack without restriction.  If the policy is set to \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , the \n\\f1\\i first\n\\f4\\i0  mutation of stacking group at a given site is retained; further mutations of this stacking group at the same site are discarded with no effect.  This can be useful for modeling one-way changes; once a gene is disabled by a premature stop codon, for example, you might wish to assume, for simplicity, that further mutations cannot alter that fact.  If the policy is set to \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , the \n\\f1\\i last\n\\f4\\i0  mutation of this stacking group at a given site is retained; earlier mutation of this stacking group at the same site are discarded.  This can be useful for modeling an \\'93infinite-alleles\\'94 scenario in which every new mutation at a site generates a completely new allele, rather than retaining the previous mutations at the site.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 The mutation stacking policy applies only within the given mutation type\\'92s stacking group; mutations of different stacking groups are always allowed to stack in SLiM.  The policy applies to all mutations added to the model after the policy is set, whether those mutations are introduced by calls such as \n\\f3\\fs18 addMutation()\n\\f4\\fs20 , \n\\f3\\fs18 addNewMutation()\n\\f4\\fs20 , or \n\\f3\\fs18 addNewDrawnMutation()\n\\f4\\fs20 , or are added by SLiM\\'92s own mutation-generation machinery.  However, no attempt is made to enforce the policy for mutations already existing at the time the policy is set; typically, therefore, the policy is set in an \n\\f3\\fs18 initialize()\n\\f4\\fs20  callback so that it applies throughout the simulation.  The policy is also not enforced upon the mutations loaded from a file with \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 ; such mutations were governed by whatever stacking policy was in effect when the population file was generated.\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4 \\cf2 \\expnd0\\expndtw0\\kerning0\nIn nucleotide-based models, the stacking policy for nucleotide-based mutation types is always \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , and cannot be changed.  This ensures that new nucleotide mutations always replace the previous nucleotide at a site, and that more than one nucleotide mutation is never present at the same position in a single haplosome.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 nucleotideBased => (logical$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If the mutation type was created with \n\\f3\\fs18 initializeMutationType()\n\\f4\\fs20 , it is not nucleotide-based, and this property is \n\\f3\\fs18 F\n\\f4\\fs20 .  If it was created with \n\\f3\\fs18 initializeMutationTypeNuc()\n\\f4\\fs20 , it is nucleotide-based, and this property is \n\\f3\\fs18 T\n\\f4\\fs20 .  See those methods for further discussion.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 species => (object<Species>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe species to which the target object belongs.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to mutation types.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.11.2  \n\\f2\\fs18 MutationType\n\\f1\\fs22  methods\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(float)drawSelectionCoefficient([integer$\\'a0n\\'a0=\\'a01])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Draws and returns a vector of \n\\f3\\fs18 n\n\\f4\\fs20  selection coefficients using the currently defined distribution of fitness effects (DFE) for the target mutation type.  If the DFE is type \n\\f3\\fs18 \"s\"\n\\f4\\fs20 , this method will result in synchronous execution of the DFE\\'92s script.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(void)setDistribution(string$\\'a0distributionType, ...)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Set the distribution of fitness effects for a mutation type.  The \n\\f3\\fs18 distributionType\n\\f4\\fs20  may be \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , in which case the ellipsis \n\\f3\\fs18 ...\n\\f4\\fs20  should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  fixed selection coefficient; \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  mean selection coefficient for the exponential distribution; \n\\f3\\fs18 \"g\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  mean selection coefficient and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  alpha shape parameter for a gamma distribution; \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  mean selection coefficient and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  sigma (standard deviation) parameter for a normal distribution; \n\\f3\\fs18 \"p\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  mean selection coefficient and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a Laplace distribution; \n\\f3\\fs18 \"w\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  \n\\f5 \\uc0\\u955 \n\\f4  scale parameter and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  k shape parameter for a Weibull distribution; or \n\\f3\\fs18 \"s\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 string$\n\\f4\\fs20  Eidos script parameter.  The DFE for a mutation type is normally a constant in simulations, so be sure you know what you are doing.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.12  Class Plot\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf2 5.12.1  \n\\f2\\fs18 Plot\n\\f1\\fs22  properties\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 title => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The title of the plot, as originally passed to \n\\f3\\fs18 createPlot()\n\\f4\\fs20 .  See also the \n\\f3\\fs18 plotWithTitle()\n\\f4\\fs20  method of \n\\f3\\fs18 SLiMgui\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.12.2  \n\\f2\\fs18 Plot\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(void)abline([Nif\\'a0a\\'a0=\\'a0NULL], [Nif\\'a0b\\'a0=\\'a0NULL], [Nif\\'a0h\\'a0=\\'a0NULL], [Nif\\'a0v\\'a0=\\'a0NULL], [string\\'a0color\\'a0=\\'a0\"red\"], [numeric\\'a0lwd\\'a0=\\'a01.0], [float\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds one or more straight lines to the plot.  There are three supported modes of operation for this method.  In the first mode, the lines are specified by \n\\f3\\fs18 a\n\\f4\\fs20  and \n\\f3\\fs18 b\n\\f4\\fs20 , representing the intercepts and slopes of the lines, respectively; in this case, \n\\f3\\fs18 a\n\\f4\\fs20  and \n\\f3\\fs18 b\n\\f4\\fs20  may be the same length, or one of them may be a singleton to provide a single value used for all of the lines specified by the other.  In the second mode, the lines are specified by \n\\f3\\fs18 h\n\\f4\\fs20 , representing the \n\\f1\\i y\n\\f4\\i0 -values of horizontal lines.  In the third mode, the lines are specified by \n\\f3\\fs18 v\n\\f4\\fs20 , representing the \n\\f1\\i x\n\\f4\\i0 -values of vertical lines.  These modes are mutually exclusive and cannot be mixed within one call to \n\\f3\\fs18 abline()\n\\f4\\fs20 .  The new lines will be plotted on top of any previously added data.\\\nThe lines will be drawn in colors, line widths, and alpha (opacity) values specified by \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , and \n\\f3\\fs18 alpha\n\\f4\\fs20 , each of which may be either a singleton (to provide one value used for all lines) or a vector equal in length to the number of lines plotted (to provide one value per line).  Alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.\\\nSee also \n\\f3\\fs18 lines()\n\\f4\\fs20  and \n\\f3\\fs18 segments()\n\\f4\\fs20  for more common approaches to line plotting.  The \n\\f3\\fs18 abline()\n\\f4\\fs20  method is different, and more specialized; the lines plotted by it span the full extent of the plot area, and their coordinates are not considered when dynamically resizing the axes of the plot (i.e., when \n\\f3\\fs18 createPlot()\n\\f4\\fs20  is not passed explicit, non-\n\\f3\\fs18 NULL\n\\f4\\fs20  values for \n\\f3\\fs18 xrange\n\\f4\\fs20  or \n\\f3\\fs18 yrange\n\\f4\\fs20 ).  This is typically useful for plotting things such as expected values and fit lines.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addLegend([Ns$\\'a0position\\'a0=\\'a0NULL], [Ni$\\'a0inset\\'a0=\\'a0NULL], [Nif$\\'a0labelSize\\'a0=\\'a0NULL], [Nif$\\'a0lineHeight\\'a0=\\'a0NULL], [Nif$\\'a0graphicsWidth\\'a0=\\'a0NULL], [Nif$\\'a0exteriorMargin\\'a0=\\'a0NULL], [Nif$\\'a0interiorMargin\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a legend to the plot.  The legend will be displayed within the plot at the location specified by position, which must be \n\\f3\\fs18 \"topRight\"\n\\f4\\fs20 , \n\\f3\\fs18 \"topLeft\"\n\\f4\\fs20 , \n\\f3\\fs18 \"bottomRight\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"bottomLeft\"\n\\f4\\fs20 , or \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default) requesting that SLiMgui choose the position.  The position of the legend will be inset from the chosen corner by a margin \n\\f3\\fs18 inset\n\\f4\\fs20 , measured in pixels; the default of \n\\f3\\fs18 NULL\n\\f4\\fs20  allows SLiMgui to choose the inset.\\\nThe internal layout of the legend is a bit complex, and can be controlled by five parameters; in all cases, the default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  requests that SLiMgui provide a reasonable default.  The \n\\f3\\fs18 labelSize\n\\f4\\fs20  parameter specifies the font size used for the text labels for each legend entry (measured in \\'93points\\'94, the standard metric of font sizes).  The \n\\f3\\fs18 lineHeight\n\\f4\\fs20  parameter specifies the vertical size, in pixels, of one entry line.  The \n\\f3\\fs18 graphicsWidth\n\\f4\\fs20  parameter species the width, in pixels, of the column used to display the \\'93graphics\\'94 (whether a line segment, a point symbol, a swatch, or a combination of those) associated with each entry.  The \n\\f3\\fs18 exteriorMargin\n\\f4\\fs20  parameter specifies the width/height of margins, in pixels, outside of the entries (between the entries and the legend\\'92s frame).  Finally, the \n\\f3\\fs18 interiorMargin\n\\f4\\fs20  parameter specifies the width/height of margins, in pixels, vertically between entries, and also between the \\'93graphics\\'94 column and the label.  It is easy to produce a legend that looks terrible, using these layout metrics; SLiMgui does only minimal sanity-checking of their values, to provide maximal flexibility.\\\nThe legend is initially empty; entries for it can be added with \n\\f3\\fs18 legendLineEntry()\n\\f4\\fs20 , \n\\f3\\fs18 legendPointEntry()\n\\f4\\fs20 , and \n\\f3\\fs18 legendSwatchEntry()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)axis(integer$\\'a0side, [Nif\\'a0at\\'a0=\\'a0NULL], [ls\\'a0labels\\'a0=\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Configures an axis of the plot.  The \n\\f3\\fs18 side\n\\f4\\fs20  parameter controls which axis is being configured; at present, it may be \n\\f3\\fs18 1\n\\f4\\fs20  for the \n\\f1\\i x\n\\f4\\i0 -axis (at the bottom of the plot), or \n\\f3\\fs18 2\n\\f4\\fs20  for the \n\\f1\\i y\n\\f4\\i0 -axis (at the left of the plot).\\\nThe positions of tick marks (and of any associated labels) are controlled by \n\\f3\\fs18 at\n\\f4\\fs20 ; if \n\\f3\\fs18 at\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default) these positions will be computed automatically based upon the range of the data in the plot, otherwise \n\\f3\\fs18 at\n\\f4\\fs20  must be a vector of \n\\f3\\fs18 numeric\n\\f4\\fs20  positions.  Note that the coordinate system of the plot is controlled not by this method, but by the \n\\f3\\fs18 xrange\n\\f4\\fs20  and \n\\f3\\fs18 yrange\n\\f4\\fs20  parameters of \n\\f3\\fs18 createPlot()\n\\f4\\fs20 ; \n\\f3\\fs18 at\n\\f4\\fs20  controls only the positions of axis ticks \n\\f1\\i within\n\\f4\\i0  that coordinate system.\\\nThe \n\\f3\\fs18 labels\n\\f4\\fs20  parameter controls the text labels displayed for ticks; it may be \n\\f3\\fs18 T\n\\f4\\fs20  (the default) to label ticks with their numeric positions, \n\\f3\\fs18 F\n\\f4\\fs20  to suppress all tick labels, or a vector of type \n\\f3\\fs18 string\n\\f4\\fs20 , equal in length to \n\\f3\\fs18 at\n\\f4\\fs20 , providing the label for each position in \n\\f3\\fs18 at\n\\f4\\fs20 .  Label values may be the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , if a label at a given position is not desired, and if \n\\f3\\fs18 labels\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , some ticks may not receive a label for readability.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)image(object$\\'a0image, numeric$\\'a0x1, numeric$\\'a0y1, numeric$\\'a0x2, numeric$\\'a0y2, [logical$\\'a0flipped\\'a0=\\'a0F], [float$\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds image data given by \n\\f3\\fs18 image\n\\f4\\fs20  to the plot.  The data will be plotted as a raster (bitmap, pixel) image in the rectangle specified by \n\\f3\\fs18 x1\n\\f4\\fs20 , \n\\f3\\fs18 y1\n\\f4\\fs20 , \n\\f3\\fs18 x2\n\\f4\\fs20 , and \n\\f3\\fs18 y2\n\\f4\\fs20 , which must be sorted such that \n\\f3\\fs18 x1\\'a0<=\\'a0x2\n\\f4\\fs20  and \n\\f3\\fs18 y1\\'a0<=\\'a0y2\n\\f4\\fs20 .  When \n\\f3\\fs18 flipped\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), the plotted image is shown in a default orientation that is typically best given the source of the image; if \n\\f3\\fs18 flipped\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  the image\\'92s orientation is flipped vertically relative to that default.  The plotted image will use opacity \n\\f3\\fs18 alpha\n\\f4\\fs20 ; alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  The new image data will be plotted on top of any previously added data.\\\nThe image data may be specified in one of two ways.  First, \n\\f3\\fs18 image\n\\f4\\fs20  may be a singleton \n\\f3\\fs18 Image\n\\f4\\fs20  object.  In this case, the image is simply plotted inside the rectangle specified by \n\\f3\\fs18 x1\n\\f4\\fs20 /\n\\f3\\fs18 y1\n\\f4\\fs20 /\n\\f3\\fs18 x2\n\\f4\\fs20 /\n\\f3\\fs18 y2\n\\f4\\fs20 , fully displaying all of its pixels (in contrast to how the grid values of a spatial map area displayed, as described below).  The image may be either RGB or grayscale.\\\nSecond, \n\\f3\\fs18 image\n\\f4\\fs20  may be a singleton \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object.  In this case, the grid values of the spatial map are plotted aligned to the corners of the rectangle specified by \n\\f3\\fs18 x1\n\\f4\\fs20 /\n\\f3\\fs18 y1\n\\f4\\fs20 /\n\\f3\\fs18 x2\n\\f4\\fs20 /\n\\f3\\fs18 y2\n\\f4\\fs20 , as the map would be used by SLiM; the edge and corner grid points of the map are therefore only partially displayed.  (If desired, the \n\\f3\\fs18 gridValues()\n\\f4\\fs20  or \n\\f3\\fs18 mapImage()\n\\f4\\fs20  methods of \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  could be used to convert the map to a matrix or \n\\f3\\fs18 Image\n\\f4\\fs20  representation that could be plotted differently.)  The spatial map\\'92s display uses the color scheme that was specified for the map.  The map\\'92s values are not interpolated, regardless of the map\\'92s \n\\f3\\fs18 interpolate\n\\f4\\fs20  property; only the raw grid data of the spatial map is displayed.  (If interpolated display is desired, the \n\\f3\\fs18 interpolate()\n\\f4\\fs20  method of \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  can be used to increase the grid resolution of the map prior to display.)\\\nThis method caches the image data being plotted so that plotting the same \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  or \n\\f3\\fs18 Image\n\\f4\\fs20  object multiple times is more efficient.  See the \n\\f3\\fs18 matrix()\n\\f4\\fs20  method of \n\\f3\\fs18 Plot\n\\f4\\fs20  for an alternative way of plotting raster data that may be more suitable in some situations, but that is less efficient because it does not provide such caching.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)legendLineEntry(string$\\'a0label, [string$\\'a0color\\'a0=\\'a0\"red\"], [numeric$\\'a0lwd\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a legend entry with text \n\\f3\\fs18 label\n\\f4\\fs20  to the plot.  The entry will be displayed as a line segment drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 , using line width \n\\f3\\fs18 lwd\n\\f4\\fs20 , mirroring the appearance produced by \n\\f3\\fs18 lines()\n\\f4\\fs20  for the same parameters.  If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)legendPointEntry(string$\\'a0label, [integer$\\'a0symbol\\'a0=\\'a00], [string$\\'a0color\\'a0=\\'a0\"red\"], [string$\\'a0border\\'a0=\\'a0\"black\"], [numeric$\\'a0lwd\\'a0=\\'a01.0], [numeric$\\'a0size\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a legend entry with text \n\\f3\\fs18 label\n\\f4\\fs20  to the plot.  The entry will be displayed as a point symbol specified by \n\\f3\\fs18 symbol\n\\f4\\fs20 , \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 border\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , and \n\\f3\\fs18 size\n\\f4\\fs20 , mirroring the appearance produced by \n\\f3\\fs18 points()\n\\f4\\fs20  for the same parameters; see \n\\f3\\fs18 points()\n\\f4\\fs20  for further details.  If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)legendSwatchEntry(string$\\'a0label, [string$\\'a0color\\'a0=\\'a0\"red\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a legend entry with text \n\\f3\\fs18 label\n\\f4\\fs20  to the plot.  The entry will be displayed as a swatch drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 .  If one or more other legend entries already exist with the same label, the new entry will be drawn on top of the previously set entries for that label (allowing legend entries that display both a line and a point, for example).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)legendTitleEntry(string$\\'a0label)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds a legend entry with text \n\\f3\\fs18 label\n\\f4\\fs20  to the plot.  The entry will be displayed as a title, left-aligned with no graphical representation (no line, point, or swatch).  A label of \n\\f3\\fs18 \"\"\n\\f4\\fs20 , the empty string, is allowed and will produce a blank line in the legend (for spacing).  Note that title entries always produce their own separate line in the legend; they do not participate in the overdrawing scheme used for other types of legend entries.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)lines(numeric\\'a0x, numeric\\'a0y, [string$\\'a0color\\'a0=\\'a0\"red\"], [numeric$\\'a0lwd\\'a0=\\'a01.0], [float$\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds line data given by \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  to the plot.  The data will be plotted as a series of connected line segments, following the (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) positions given; note that the \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  vectors must be the same length.  The new line data will be plotted on top of any previously added data.\\\nThe lines will be drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 , using line width \n\\f3\\fs18 lwd\n\\f4\\fs20 , with opacity \n\\f3\\fs18 alpha\n\\f4\\fs20 .  Alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  Unlike \n\\f3\\fs18 points()\n\\f4\\fs20  and \n\\f3\\fs18 text()\n\\f4\\fs20 , the parameters \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , and \n\\f3\\fs18 alpha\n\\f4\\fs20  must be singletons, since each point (except the two ends) is shared by two line segments; if you wish to vary the color/width/opacity for each line segment, separate calls to \n\\f3\\fs18 lines()\n\\f4\\fs20  are necessary, or the \n\\f3\\fs18 segments()\n\\f4\\fs20  method may be useful.   See also \n\\f3\\fs18 abline()\n\\f4\\fs20  and \n\\f3\\fs18 segments()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)matrix(numeric\\'a0matrix, numeric$\\'a0x1, numeric$\\'a0y1, numeric$\\'a0x2, numeric$\\'a0y2, [logical$\\'a0flipped\\'a0=\\'a0F], [Nif\\'a0valueRange\\'a0=\\'a0NULL], [Ns$\\'a0colors\\'a0=\\'a0NULL], [float$\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds image data given by \n\\f3\\fs18 matrix\n\\f4\\fs20  to the plot.  The image data must be specified as a \n\\f3\\fs18 numeric\n\\f4\\fs20  (i.e., \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20 ) matrix, as for example produced by the \n\\f3\\fs18 matrix()\n\\f4\\fs20  function in Eidos.  The data will be plotted as a raster (bitmap, pixel) image in the rectangle specified by \n\\f3\\fs18 x1\n\\f4\\fs20 , \n\\f3\\fs18 y1\n\\f4\\fs20 , \n\\f3\\fs18 x2\n\\f4\\fs20 , and \n\\f3\\fs18 y2\n\\f4\\fs20 , which must be sorted such that \n\\f3\\fs18 x1\\'a0<=\\'a0x2\n\\f4\\fs20  and \n\\f3\\fs18 y1\\'a0<=\\'a0y2\n\\f4\\fs20 .  When \n\\f3\\fs18 flipped\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), the plotted image is shown in a default orientation that matches the orientation of the matrix (with row \n\\f3\\fs18 0\n\\f4\\fs20  topmost); if \n\\f3\\fs18 flipped\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  the image\\'92s orientation is flipped vertically relative to that default (with row \n\\f3\\fs18 0\n\\f4\\fs20  bottommost).\\\nPrior to display, the values in the matrix will be rescaled according to the parameter \n\\f3\\fs18 valueRange\n\\f4\\fs20 .  If \n\\f3\\fs18 valueRange\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), the values will be left unscaled; this is equivalent to passing \n\\f3\\fs18 c(0,1)\n\\f4\\fs20  for \n\\f3\\fs18 valueRange\n\\f4\\fs20 .  Otherwise, \n\\f3\\fs18 valueRange\n\\f4\\fs20  should be a \n\\f3\\fs18 numeric\n\\f4\\fs20  vector containing two elements that define the range of values that will be rescaled to span the interval [0, 1] \\'96 the range to which the color scheme will then be applied.  After rescaling the given range to [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 ], the resulting values are clamped to the range [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 ].  It is legal for \n\\f3\\fs18 valueRange[0]\n\\f4\\fs20  to be greater than \n\\f3\\fs18 valueRange[1]\n\\f4\\fs20 ; in this case, the rescaling operation will, in effect, reverse the direction of the color scheme by reversing the ranks of the reordered values.\\\nThe rescaled and clamped values are then colored according to the color scheme named by \n\\f3\\fs18 colors\n\\f4\\fs20 , which should be one of the named schemes supported by the Eidos function \n\\f3\\fs18 colors()\n\\f4\\fs20 : \n\\f3\\fs18 \"cm\"\n\\f4\\fs20 , \n\\f3\\fs18 \"heat\"\n\\f4\\fs20 , \n\\f3\\fs18 \"terrain\"\n\\f4\\fs20 , \n\\f3\\fs18 \"parula\"\n\\f4\\fs20 , \n\\f3\\fs18 \"hot\"\n\\f4\\fs20 , \n\\f3\\fs18 \"jet\"\n\\f4\\fs20 , \n\\f3\\fs18 \"turbo\"\n\\f4\\fs20 , \n\\f3\\fs18 \"gray\"\n\\f4\\fs20 , \n\\f3\\fs18 \"magma\"\n\\f4\\fs20 , \n\\f3\\fs18 \"inferno\"\n\\f4\\fs20 , \n\\f3\\fs18 \"plasma\"\n\\f4\\fs20 , \n\\f3\\fs18 \"viridis\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"cividis\"\n\\f4\\fs20 .  If \n\\f3\\fs18 colors\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), the color scheme used is the reverse of the \n\\f3\\fs18 \"gray\"\n\\f4\\fs20  color scheme, shading from black for \n\\f3\\fs18 0\n\\f4\\fs20  up to white for \n\\f3\\fs18 1\n\\f4\\fs20 .  In all cases, the color scheme is applied across the range [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 ] for the rescaled and clamped values.\\\nThe plotted image will use opacity \n\\f3\\fs18 alpha\n\\f4\\fs20 ; alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  The new image data will be plotted on top of any previously added data.\\\nSee the \n\\f3\\fs18 image()\n\\f4\\fs20  method of \n\\f3\\fs18 Plot\n\\f4\\fs20  for an alternative way of plotting raster data from \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  and \n\\f3\\fs18 Image\n\\f4\\fs20  objects that may be more suitable in some situations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)mtext(numeric\\'a0x, numeric\\'a0y, string\\'a0labels, [string\\'a0color\\'a0=\\'a0\"black\"], [numeric\\'a0size\\'a0=\\'a010.0], [Nif\\'a0adj\\'a0=\\'a0NULL], [float\\'a0alpha\\'a0=\\'a01.0], [numeric\\'a0angle\\'a0=\\'a00.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds marginal text data given by \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 labels\n\\f4\\fs20  to the plot.  The string values in \n\\f3\\fs18 labels\n\\f4\\fs20  will be plotted at the (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) positions given; note that \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 labels\n\\f4\\fs20  must all be the same length.  This method differs from the \n\\f3\\fs18 text()\n\\f4\\fs20  method in two respects.  The first \\'96 the reason that this method draws \\'93marginal\\'94 text \\'96 is that the text drawn is not clipped to the plot area, allowing text to be drawn in the axis and border areas outside the plot itself.  The second is that the \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  coordinates are interpreted differently than other \n\\f3\\fs18 Plot\n\\f4\\fs20  methods; rather than being in the coordinate system of the plot, they are in a coordinate system in which the plot area spans [0,1] on both axes.  This is intended to make positioning text outside of the plot area not depend upon the axis ranges of the plot; those axis ranges might vary, but the positions at which \n\\f3\\fs18 mtext()\n\\f4\\fs20  draws, relative to the plot area, will remain fixed.  The new marginal text data will be plotted on top of any previously added data.\\\nThe text will be drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 , at the font size given by \n\\f3\\fs18 size\n\\f4\\fs20  (measured in \\'93points\\'94, the standard metric of font sizes); the font family and style cannot be controlled at this time.  Opacity values may be supplied with \n\\f3\\fs18 alpha\n\\f4\\fs20 ; alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  The angle at which the text is drawn can be specified with \n\\f3\\fs18 angle\n\\f4\\fs20 ; angles are measured in degrees, clockwise.  All of these parameters (\n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 size\n\\f4\\fs20 , \n\\f3\\fs18 alpha\n\\f4\\fs20 , and \n\\f3\\fs18 angle\n\\f4\\fs20 ) may either be a singleton value applied to all points, or a vector with one value per corresponding point.\\\nThe exact position of the text, relative to each point (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ), is adjusted by the optional parameter \n\\f3\\fs18 adj\n\\f4\\fs20 .  The value of \n\\f3\\fs18 adj\n\\f4\\fs20 , if specified, must be a vector of length \n\\f3\\fs18 2\n\\f4\\fs20 , where \n\\f3\\fs18 adj[0]\n\\f4\\fs20  adjusts the \n\\f1\\i x\n\\f4\\i0  position and \n\\f3\\fs18 adj[1]\n\\f4\\fs20  adjusts the \n\\f1\\i y\n\\f4\\i0  position of the text.  Relative to a given \n\\f1\\i x\n\\f4\\i0  position, a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  aligns the left edge of the text to it; a value of \n\\f3\\fs18 0.5\n\\f4\\fs20  aligns the center of the text to it; and a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  aligns the right edge of the text to it.  Similarly, relative to a given \n\\f1\\i y\n\\f4\\i0  position, a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  aligns the bottom edge of the text to it; a value of \n\\f3\\fs18 0.5\n\\f4\\fs20  aligns the center of the text to it; and a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  aligns the top edge of the text to it.  Intermediate values will produce intermediate alignments, and values of \n\\f3\\fs18 adj\n\\f4\\fs20  outside of [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ] are also allowed.  The default value of \n\\f3\\fs18 adj\n\\f4\\fs20 , \n\\f3\\fs18 NULL\n\\f4\\fs20 , is equivalent to \n\\f3\\fs18 c(0.5,\\'a00.5)\n\\f4\\fs20 , aligning the center of the text to (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) both horizontally and vertically.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)points(numeric\\'a0x, numeric\\'a0y, [integer\\'a0symbol\\'a0=\\'a00], [string\\'a0color\\'a0=\\'a0\"red\"], [string\\'a0border\\'a0=\\'a0\"black\"], [numeric\\'a0lwd\\'a0=\\'a01.0], [numeric\\'a0size\\'a0=\\'a01.0], [float\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds point data given by \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  to the plot.  The data will be plotted as a set of point symbols, centered at the (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) positions given; note that the \n\\f3\\fs18 x\n\\f4\\fs20  and \n\\f3\\fs18 y\n\\f4\\fs20  vectors must be the same length.  The new point data will be plotted on top of any previously added data.\\\nThe symbol plotted for each point depends upon the value of \n\\f3\\fs18 symbol\n\\f4\\fs20 .  In general, symbols will be drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 , with a line width \n\\f3\\fs18 lwd\n\\f4\\fs20  used for lines (if any) in the symbol, and an overall size scaled by \n\\f3\\fs18 size\n\\f4\\fs20 .  Symbols \n\\f3\\fs18 21\n\\f4\\fs20 \\'96\n\\f3\\fs18 25\n\\f4\\fs20  involve both a filled shape and a border line around that shape; for those symbols, the border line will use the color provided by \n\\f3\\fs18 border\n\\f4\\fs20 , while the filled shape will use color \n\\f3\\fs18 color\n\\f4\\fs20 .  Opacity values may be supplied with \n\\f3\\fs18 alpha\n\\f4\\fs20 ; alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  All of these parameters (\n\\f3\\fs18 symbol\n\\f4\\fs20 , \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 border\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , \n\\f3\\fs18 size\n\\f4\\fs20 , and \n\\f3\\fs18 alpha\n\\f4\\fs20 ) may either be a singleton value applied to all points, or a vector with one value per corresponding point.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)rects(numeric\\'a0x1, numeric\\'a0y1, numeric\\'a0x2, numeric\\'a0y2, [string\\'a0color\\'a0=\\'a0\"red\"], [string\\'a0border\\'a0=\\'a0\"black\"], [numeric\\'a0lwd\\'a0=\\'a01.0], [float\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds rectangle data given by \n\\f3\\fs18 x1\n\\f4\\fs20 , \n\\f3\\fs18 y1\n\\f4\\fs20 , \n\\f3\\fs18 x2\n\\f4\\fs20 , and \n\\f3\\fs18 y2\n\\f4\\fs20  to the plot; note that these four vectors must all be the same length.  The data will be plotted as a series of rectangles, defined by each (\n\\f1\\i x1\n\\f4\\i0 , \n\\f1\\i y1\n\\f4\\i0 , \n\\f1\\i x2\n\\f4\\i0 , \n\\f1\\i y2\n\\f4\\i0 ) quadret providing the left, right, top and bottom of each rectangle.  The coordinates of each rectangle do not need to be sorted; in other words, it is not required that \n\\f3\\fs18 x1[i] <= x2[i]\n\\f4\\fs20 , or that \n\\f3\\fs18 y1[i] <= y2[i]\n\\f4\\fs20 , and different sorting orders for the coordinates of a given rectangle will draw identically.  The fill of a each rectangle is contained within its coordinates, but the frame of each rectangle is composed of lines of some width, drawn between the vertices of the rectangle, and will therefore extend beyond the coordinates of the rectangle by one-half of the line width; if this is not desired, inset the rectangle coordinates by one-half of the line width to compensate.  The new rectangle data will be plotted on top of any previously added data.\\\nThe rectangles will be drawn in fill colors \n\\f3\\fs18 color\n\\f4\\fs20 , with border colors \n\\f3\\fs18 border\n\\f4\\fs20 , using line widths \n\\f3\\fs18 lwd\n\\f4\\fs20 , with opacities \n\\f3\\fs18 alpha\n\\f4\\fs20  applied to both the fill and the border.  The \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 border\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , and \n\\f3\\fs18 alpha\n\\f4\\fs20  parameters may each be either a singleton value (applying to all rectangles) or a vector with one value per rectangle.  Alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  If a filled rectangle with no border is desired, a \n\\f3\\fs18 border\n\\f4\\fs20  value of \n\\f3\\fs18 \"none\"\n\\f4\\fs20  can be used; similarly, if a framed rectangle with no fill is desired, a \n\\f3\\fs18 color\n\\f4\\fs20  value of \n\\f3\\fs18 \"none\"\n\\f4\\fs20  can be used.  Note that that \n\\f3\\fs18 \"none\"\n\\f4\\fs20  a special color value supported only by \n\\f3\\fs18 rects()\n\\f4\\fs20 ; it is not part of the standard set of named colors in Eidos.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)segments(numeric\\'a0x1, numeric\\'a0y1, numeric\\'a0x2, numeric\\'a0y2, [string\\'a0color\\'a0=\\'a0\"red\"], [numeric\\'a0lwd\\'a0=\\'a01.0], [float\\'a0alpha\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds line segment data given by \n\\f3\\fs18 x1\n\\f4\\fs20 , \n\\f3\\fs18 y1\n\\f4\\fs20 , \n\\f3\\fs18 x2\n\\f4\\fs20 , and \n\\f3\\fs18 y2\n\\f4\\fs20  to the plot; note that these four vectors must all be the same length.  The data will be plotted as a series of unconnected line segments, from each (\n\\f1\\i x1\n\\f4\\i0 , \n\\f1\\i y1\n\\f4\\i0 ) position to the corresponding (\n\\f1\\i x2\n\\f4\\i0 , \n\\f1\\i y2\n\\f4\\i0 ) position.  The new line segment data will be plotted on top of any previously added data.\\\nThe line segments will be drawn in colors \n\\f3\\fs18 color\n\\f4\\fs20 , using line widths \n\\f3\\fs18 lwd\n\\f4\\fs20 , with opacities \n\\f3\\fs18 alpha\n\\f4\\fs20 .  The \n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 lwd\n\\f4\\fs20 , and \n\\f3\\fs18 alpha\n\\f4\\fs20  parameters may each be either a singleton value (applying to all line segments) or a vector with one value per line segment.  Alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.   See also \n\\f3\\fs18 lines()\n\\f4\\fs20  and \n\\f3\\fs18 abline()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)setBorderless([numeric$\\'a0marginLeft\\'a0=\\'a00.0], [numeric$\\'a0marginTop\\'a0=\\'a00.0], [numeric$\\'a0marginRight\\'a0=\\'a00.0], [numeric$\\'a0marginBottom\\'a0=\\'a00.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Reconfigures the plot to be borderless \\'96 to not display axes, ticks, or the labels for axes and ticks.  Since those elements are not present, the plot area in borderless plots essentially fills the window\\'92s available area, except for being inset by the margins given in \n\\f3\\fs18 marginLeft\n\\f4\\fs20 , \n\\f3\\fs18 marginTop\n\\f4\\fs20 , \n\\f3\\fs18 marginRight\n\\f4\\fs20 , and \n\\f3\\fs18 marginBottom\n\\f4\\fs20 , which are specified in pixels.  The axis ranges are not extended in the usual manner; if the range of the \n\\f1\\i x\n\\f4\\i0  axis is specified as \n\\f3\\fs18 c(0,1)\n\\f4\\fs20 , for example, then that is the range actually used for the \n\\f1\\i x\n\\f4\\i0  axis.  (This is similar to R\\'92s \n\\f3\\fs18 \"xaxs\"\n\\f4\\fs20  and \n\\f3\\fs18 \"yaxs\"\n\\f4\\fs20  being specified as \n\\f3\\fs18 \"i\"\n\\f4\\fs20 , rather than the usual behavior specified by the default of \n\\f3\\fs18 \"r\"\n\\f4\\fs20 .)  If you want the plotted data to have \\'93breathing room\\'94 around it, you should therefore specify non-zero margins.\\\nNote that the \n\\f3\\fs18 fullBox\n\\f4\\fs20  parameter of \n\\f3\\fs18 createPlot()\n\\f4\\fs20  is still honored; for borderless plots, the box is drawn at the outer edge of the margin area.  If you don\\'92t want the box to overdraw any of the data area of the plot (within the extents of the axes), you should specify each margin value as \n\\f3\\fs18 1\n\\f4\\fs20  (or greater), to provide a pixel of margin space within which the box will be drawn without impinging upon the plotted data.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)text(numeric\\'a0x, numeric\\'a0y, string\\'a0labels, [string\\'a0color\\'a0=\\'a0\"black\"], [numeric\\'a0size\\'a0=\\'a010.0], [Nif\\'a0adj\\'a0=\\'a0NULL], [float\\'a0alpha\\'a0=\\'a01.0], [numeric\\'a0angle\\'a0=\\'a00.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds text data given by \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 labels\n\\f4\\fs20  to the plot.  The string values in \n\\f3\\fs18 labels\n\\f4\\fs20  will be plotted at the (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) positions given; note that \n\\f3\\fs18 x\n\\f4\\fs20 , \n\\f3\\fs18 y\n\\f4\\fs20 , and \n\\f3\\fs18 labels\n\\f4\\fs20  must all be the same length.  The new text data will be plotted on top of any previously added data.\\\nThe text will be drawn in color \n\\f3\\fs18 color\n\\f4\\fs20 , at the font size given by \n\\f3\\fs18 size\n\\f4\\fs20  (measured in \\'93points\\'94, the standard metric of font sizes); the font family and style cannot be controlled at this time.  Opacity values may be supplied with \n\\f3\\fs18 alpha\n\\f4\\fs20 ; alpha values must be in [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ], where \n\\f3\\fs18 0.0\n\\f4\\fs20  is fully transparent and \n\\f3\\fs18 1.0\n\\f4\\fs20  is fully opaque.  The angle at which the text is drawn can be specified with \n\\f3\\fs18 angle\n\\f4\\fs20 ; angles are measured in degrees, clockwise.  All of these parameters (\n\\f3\\fs18 color\n\\f4\\fs20 , \n\\f3\\fs18 size\n\\f4\\fs20 , \n\\f3\\fs18 alpha\n\\f4\\fs20 , and \n\\f3\\fs18 angle\n\\f4\\fs20 ) may either be a singleton value applied to all points, or a vector with one value per corresponding point.\\\nThe exact position of the text, relative to each point (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ), is adjusted by the optional parameter \n\\f3\\fs18 adj\n\\f4\\fs20 .  The value of \n\\f3\\fs18 adj\n\\f4\\fs20 , if specified, must be a vector of length \n\\f3\\fs18 2\n\\f4\\fs20 , where \n\\f3\\fs18 adj[0]\n\\f4\\fs20  adjusts the \n\\f1\\i x\n\\f4\\i0  position and \n\\f3\\fs18 adj[1]\n\\f4\\fs20  adjusts the \n\\f1\\i y\n\\f4\\i0  position of the text.  Relative to a given \n\\f1\\i x\n\\f4\\i0  position, a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  aligns the left edge of the text to it; a value of \n\\f3\\fs18 0.5\n\\f4\\fs20  aligns the center of the text to it; and a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  aligns the right edge of the text to it.  Similarly, relative to a given \n\\f1\\i y\n\\f4\\i0  position, a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  aligns the bottom edge of the text to it; a value of \n\\f3\\fs18 0.5\n\\f4\\fs20  aligns the center of the text to it; and a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  aligns the top edge of the text to it.  Intermediate values will produce intermediate alignments, and values of \n\\f3\\fs18 adj\n\\f4\\fs20  outside of [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ] are also allowed.  The default value of \n\\f3\\fs18 adj\n\\f4\\fs20 , \n\\f3\\fs18 NULL\n\\f4\\fs20 , is equivalent to \n\\f3\\fs18 c(0.5,\\'a00.5)\n\\f4\\fs20 , aligning the center of the text to (\n\\f1\\i x\n\\f4\\i0 , \n\\f1\\i y\n\\f4\\i0 ) both horizontally and vertically.\\\nSee also the \n\\f3\\fs18 mtext()\n\\f4\\fs20  method, for drawing text outside of the plot area.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)write(string$\\'a0filePath)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Writes the plot to the given filesystem path \n\\f3\\fs18 filePath\n\\f4\\fs20  as a PDF file.  It is suggested, but not required, that \n\\f3\\fs18 filePath\n\\f4\\fs20  should end in a \n\\f3\\fs18 .pdf\n\\f4\\fs20  or \n\\f3\\fs18 .PDF\n\\f4\\fs20  filename extension.  If the file cannot be written, an error will result.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.13  Class SLiMEidosBlock\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.13.1  \n\\f2\\fs18 SLiMEidosBlock\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 active <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If this evaluates to \n\\f3\\fs18 logical\n\\f4\\fs20  \n\\f3\\fs18 F\n\\f4\\fs20  (i.e., is equal to \n\\f3\\fs18 0\n\\f4\\fs20 ), the script block is inactive and will not be called.  The value of \n\\f3\\fs18 active\n\\f4\\fs20  for all registered script blocks is reset to \n\\f3\\fs18 -1\n\\f4\\fs20  at the beginning of each tick, prior to script events being called, thus activating all blocks (except callbacks associated with a species that is not active in that tick, which are deactivated as part of the deactivation of the species).  Any \n\\f3\\fs18 integer\n\\f4\\fs20  value other than \n\\f3\\fs18 -1\n\\f4\\fs20  may be used instead of \n\\f3\\fs18 -1\n\\f4\\fs20  to represent that a block is active; for example, \n\\f3\\fs18 active\n\\f4\\fs20  may be used as a counter to make a block execute a fixed number of times in each tick.  This value is not cached by SLiM; if it is changed, the new value takes effect immediately.  For example, a callback might be activated and inactivated repeatedly during a single tick.\\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 end => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The last tick in which the script block is active.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this script block; for script \n\\f3\\fs18 s3\n\\f4\\fs20 , for example, this is \n\\f3\\fs18 3\n\\f4\\fs20 .  A script block for which no \n\\f3\\fs18 id\n\\f4\\fs20  was given will have an \n\\f3\\fs18 id\n\\f4\\fs20  of \n\\f3\\fs18 -1\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 source => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The source code string of the script block.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 speciesSpec => (object<Species>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 species\n\\f4\\fs20  specifier for the script block.  The species specifier for a callback block indicates the callback\\'92s associated species; the callback is called to modify the default behavior for that species.  If the script block has no \n\\f3\\fs18 species\n\\f4\\fs20  specifier, this property\\'92s value is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Species\n\\f4\\fs20 .  This property is read-only; normally it is set by preceding the definition of a callback with a \n\\f3\\fs18 species\n\\f4\\fs20  specifier, of the form \n\\f3\\fs18 species <species-name>\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 start => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The first tick in which the script block is active.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 ticksSpec => (object<Species>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier for the script block.  The \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier for an event block indicates the event\\'92s associated species; the event executes only in ticks when that species is active.  If the script block has no \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier, this property\\'92s value is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Species\n\\f4\\fs20 .  This property is read-only; normally it is set by preceding the definition of an event with a \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier, of the form \n\\f3\\fs18 ticks <species-name>\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 type => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The type of the script block; this will be \n\\f3\\fs18 \"first\"\n\\f4\\fs20 , \n\\f3\\fs18 \"early\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"late\"\n\\f4\\fs20  for the three types of Eidos events, or \n\\f3\\fs18 \"initialize\"\n\\f4\\fs20 , \n\\f3\\fs18 \"fitnessEffect\"\n\\f4\\fs20 , \n\\f3\\fs18 \"interaction\"\n\\f4\\fs20 , \n\\f3\\fs18 \"mateChoice\"\n\\f4\\fs20 , \n\\f3\\fs18 \"modifyChild\"\n\\f4\\fs20 , \n\\f3\\fs18 \"mutation\"\n\\f4\\fs20 , \n\\f3\\fs18 \"mutationEffect\"\n\\f4\\fs20 , \n\\f3\\fs18 \"recombination\"\n\\f4\\fs20 , \n\\f3\\fs18 \"reproduction\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"survival\"\n\\f4\\fs20  for the respective types of Eidos callbacks.\n\\f3\\fs18 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.13.2  \n\\f2\\fs18 SLiMEidosBlock\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f5\\i0 \\cf0 \\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b \\cf0 5.14  Class SLiMgui\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.14.1  \n\\f2\\fs18 SLiMgui\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\npid => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The Un*x process identifier (commonly called the \\'93pid\\'94) of the running SLiMgui application.  This can be useful for scripts that wish to use system calls to influence the SLiMgui application.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 \\kerning1\\expnd0\\expndtw0 5.14.2  \n\\f2\\fs18 SLiMgui\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(No<Plot>$)createPlot(string$\\'a0title, [Nif\\'a0xrange\\'a0=\\'a0NULL], [Nif\\'a0yrange\\'a0=\\'a0NULL], [string$\\'a0xlab\\'a0=\\'a0\"x\"], [string$\\'a0ylab\\'a0=\\'a0\"y\"], [Nif$\\'a0width\\'a0=\\'a0NULL], [Nif$\\'a0height\\'a0=\\'a0NULL], [logical$\\'a0horizontalGrid\\'a0=\\'a0F], [logical$\\'a0verticalGrid\\'a0=\\'a0F], [logical$\\'a0fullBox\\'a0=\\'a0T], [numeric$\\'a0axisLabelSize\\'a0=\\'a015], [numeric$\\'a0tickLabelSize\\'a0=\\'a010])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Creates and returns a new custom plot referred to by \n\\f3\\fs18 title\n\\f4\\fs20 , or restarts and returns the existing plot with that title; if the plot cannot be created (notably, when running under SLiMguiLegacy rather than SLiMgui), \n\\f3\\fs18 NULL\n\\f4\\fs20  is returned.  The range for the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i y\n\\f4\\i0  axes of the plot can optionally be provided in \n\\f3\\fs18 xrange\n\\f4\\fs20  and \n\\f3\\fs18 yrange\n\\f4\\fs20 , as vectors of length \n\\f3\\fs18 2\n\\f4\\fs20  containing the minimum and maximum values for the corresponding axis; the default of \n\\f3\\fs18 NULL\n\\f4\\fs20  for these parameters requests that the axis ranges be determined heuristically based upon the data subsequently added to the plot.  Labels for the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i y\n\\f4\\i0  axes can be provided in \n\\f3\\fs18 xlab\n\\f4\\fs20  and \n\\f3\\fs18 ylab\n\\f4\\fs20 ; if no axis label is desired, the empty string \n\\f3\\fs18 \"\"\n\\f4\\fs20  may be passed.  The width and height of the window itself can optionally be set with \n\\f3\\fs18 width\n\\f4\\fs20  and \n\\f3\\fs18 height\n\\f4\\fs20 , in units of pixels (perhaps 70\\'96100 pixels per inch, depending on your screen\\'92s pixel density); the default of \n\\f3\\fs18 NULL\n\\f4\\fs20  for these parameters requests SLiMgui\\'92s default plot window size.  The display of horizontal grid lines, vertical grid lines, and a full box around the plot area can be controlled with \n\\f3\\fs18 horizontalGrid\n\\f4\\fs20 , \n\\f3\\fs18 verticalGrid\n\\f4\\fs20 , and \n\\f3\\fs18 fullBox\n\\f4\\fs20  respectively, and the size (in points) of axis and tick labels can be controlled with \n\\f3\\fs18 axisLabelSize\n\\f4\\fs20  and \n\\f3\\fs18 tickLabelSize\n\\f4\\fs20  respectively.\\\nOnce the plot has been created, data can be added to it using \n\\f3\\fs18 Plot\n\\f4\\fs20  methods such as \n\\f3\\fs18 lines()\n\\f4\\fs20 , \n\\f3\\fs18 points()\n\\f4\\fs20 , and \n\\f3\\fs18 text()\n\\f4\\fs20 .  As with other plot windows in SLiMgui, the \\'93action button\\'94 can be used to access plot configuration options, and to copy or save the final plot as a raster image or a PDF file.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(Nfs)logFileData(object<LogFile>$\\'a0logFile, is$\\'a0column)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing data from the \n\\f3\\fs18 LogFile\n\\f4\\fs20  object \n\\f3\\fs18 logFile\n\\f4\\fs20 , taken from a specified column (identified in \n\\f3\\fs18 column\n\\f4\\fs20  either by the column\\'92s name or by its zero-based index).  If the data are all numeric, they will be returned as a \n\\f3\\fs18 float\n\\f4\\fs20  vector.  Otherwise \\'96 if the data are non-numeric \\'96 they will be returned as a \n\\f3\\fs18 string\n\\f4\\fs20  vector.  If the specified column does not exist in the log file, \n\\f3\\fs18 NULL\n\\f4\\fs20  will be returned.\\\nThis functionality is provided as a method on the \n\\f3\\fs18 SLiMgui\n\\f4\\fs20  class, rather than on \n\\f3\\fs18 LogFile\n\\f4\\fs20 , because in SLiMgui logged data is kept in memory anyway, for display in the debugging output viewer window.  When running at the command line logged data is not kept in memory, and thus is not available.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(void)openDocument(string$\\'a0filePath)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Open the document at \n\\f3\\fs18 filePath\n\\f4\\fs20  in SLiMgui, if possible.  Supported document types include SLiM model files (typically with a \n\\f3\\fs18 .slim\n\\f4\\fs20  path extension), text files (typically with a \n\\f3\\fs18 .txt\n\\f4\\fs20  path extension, and opened as untitled model files), and PNG, JPG/JPEG, BMP, and GIF image file formats (typically \n\\f3\\fs18 .png\n\\f4\\fs20  / \n\\f3\\fs18 .jpg\n\\f4\\fs20  / \n\\f3\\fs18 .jpeg\n\\f4\\fs20  / \n\\f3\\fs18 .bmp\n\\f4\\fs20  / \n\\f3\\fs18 .gif\n\\f4\\fs20 , respectively).  (Note that in SLiMguiLegacy, PDF files (\n\\f3\\fs18 .pdf\n\\f4\\fs20 ) are supported but these other image file formats are not.)  This method can be particularly useful for opening images created by the simulation itself, often by sublaunching a plotting process in R or another environment.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)pauseExecution(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Pauses a model that is playing in SLiMgui.  This is essentially equivalent to clicking the \\'93Play\\'94 button to stop the execution of the model.  Execution can be resumed by the user, by clicking the \\'93Play\\'94 button again; unlike calling \n\\f3\\fs18 stop()\n\\f4\\fs20  or \n\\f3\\fs18 simulationFinished()\n\\f4\\fs20 , the simulation is not terminated.  This method can be useful for debugging or exploratory purposes, to pause the model at a point of interest.  Execution is paused at the end of the currently executing tick, not mid-tick.\\\nIf the model is being profiled, or is executing forward to a tick number entered in the tick field, \n\\f3\\fs18 pauseExecution()\n\\f4\\fs20  will do nothing; by design, \n\\f3\\fs18 pauseExecution()\n\\f4\\fs20  only pauses execution when SLiMgui is doing a simple \\'93Play\\'94 of the model.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(No<Plot>$)plotWithTitle(string$\\'a0title)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an existing plot that was created by \n\\f3\\fs18 createPlot()\n\\f4\\fs20  with \n\\f3\\fs18 title\n\\f4\\fs20 ; if such a plot does not exist, \n\\f3\\fs18 NULL\n\\f4\\fs20  is returned.  Note that other SLiMgui plots cannot be accessed through this method; only plots created by \n\\f3\\fs18 createPlot()\n\\f4\\fs20  are available in Eidos.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf2 5.15  Class SpatialMap\n\\f4\\b0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 (object<SpatialMap>$)SpatialMap(string$\\'a0name, object<SpatialMap>$\\'a0map)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Creates a new \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object that is a copy of \n\\f3\\fs18 map\n\\f4\\fs20 , named \n\\f3\\fs18 name\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.15.1  \n\\f2\\fs18 SpatialMap\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 gridDimensions => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The dimensions of the spatial map\\'92s grid of values, in the order of the components of the map\\'92s spatiality.  For example, a map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20  and a grid of values that is \n\\f3\\fs18 500\n\\f4\\fs20  in the \n\\f3\\fs18 \"x\"\n\\f4\\fs20  dimension by \n\\f3\\fs18 300\n\\f4\\fs20  in the \n\\f3\\fs18 \"z\"\n\\f4\\fs20  dimension would return \n\\f3\\fs18 c(500, 300)\n\\f4\\fs20  for this property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 interpolate <\\'96> (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Whether interpolation between grid values is enabled (\n\\f3\\fs18 T\n\\f4\\fs20 ) or disabled (\n\\f3\\fs18 F\n\\f4\\fs20 ).  The initial value of this property is set by \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 , but it can be changed.  The interpolation performed is linear; for cubic interpolation, use the \n\\f3\\fs18 interpolate()\n\\f4\\fs20  method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 name => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The name of the spatial map, usually as provided to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 .  The names of spatial maps must be unique within any given subpopulation, but the same name may be reused for different spatial maps in different subpopulations.  The name is used to identify a map for methods such as \n\\f3\\fs18 spatialMapValue()\n\\f4\\fs20 , and is also used for display in SLiMgui.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 spatialBounds => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The spatial bounds to which the spatial map is aligned.  These bounds come from the subpopulation that originally created the map, with the \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  method, and cannot be subsequently changed.  All subpopulations that use a given spatial map must match that map\\'92s spatial bounds, so that the map does not stretch or shrink relative to its initial configuration.  The components of the spatial bounds of a map correspond to the components of the map\\'92s spatiality; for example, a map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20  will have bounds (\n\\f3\\fs18 x0\n\\f4\\fs20 , \n\\f3\\fs18 z0\n\\f4\\fs20 , \n\\f3\\fs18 x1\n\\f4\\fs20 , \n\\f3\\fs18 z1\n\\f4\\fs20 ); bounds for \n\\f3\\fs18 \"y\"\n\\f4\\fs20  are not included, since that dimension is not used by the spatial map.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 spatiality => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The spatiality of the map: the subset of the model\\'92s dimensions that are used by the spatial map.  The spatiality of a map is configured by \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  and cannot subsequently be changed.  For example, a 3D model (with dimensionality \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 ) might define a 2D spatial map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , providing spatial values that do not depend upon the \n\\f3\\fs18 \"y\"\n\\f4\\fs20  dimension.  Often, however, the spatiality of a map will match the dimensionality of the model.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined, and it is an error to try to read it; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual), for another way of attaching state to spatial maps.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf2 5.15.2  \n\\f2\\fs18 SpatialMap\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)add(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds \n\\f3\\fs18 x\n\\f4\\fs20  to the spatial map.  One possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, \n\\f3\\fs18 x\n\\f4\\fs20  is added to each grid value of the target spatial map.  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each value of \n\\f3\\fs18 x\n\\f4\\fs20  is added to the corresponding grid value of the target spatial map.  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of \n\\f3\\fs18 x\n\\f4\\fs20  is added to the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)blend(ifo<SpatialMap>\\'a0x, float$\\'a0xFraction)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Blends \n\\f3\\fs18 x\n\\f4\\fs20  into the spatial map, giving \n\\f3\\fs18 x\n\\f4\\fs20  a weight of \n\\f3\\fs18 xFraction\n\\f4\\fs20  and the existing values in the target spatial map a weight of \n\\f3\\fs18 1 - xFraction\n\\f4\\fs20 , such that the resulting values in the target spatial map are then given by \n\\f3\\fs18 x\\'a0*\\'a0xFraction + target\\'a0*\\'a0(1\\'a0-\\'a0xFraction)\n\\f4\\fs20 .  The value of \n\\f3\\fs18 xFraction\n\\f4\\fs20  must be in [0.0, 1.0].\\\nOne possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, \n\\f3\\fs18 x\n\\f4\\fs20  is blended with each grid value of the target spatial map.  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each value of \n\\f3\\fs18 x\n\\f4\\fs20  is blended with the corresponding grid value of the target spatial map.  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of \n\\f3\\fs18 x\n\\f4\\fs20  is blended with the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)changeColors([Nif\\'a0valueRange\\'a0=\\'a0NULL], [Ns\\'a0colors\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Changes the color scheme for the target spatial map.  The meaning of \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  are identical to their meaning in \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 , but are also described here.\\\nThe \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  parameters travel together; either both are \n\\f3\\fs18 NULL\n\\f4\\fs20 , or both are specified.  They control how map values will be transformed into colors, by SLiMgui and by the \n\\f3\\fs18 mapColor()\n\\f4\\fs20  method.  The \n\\f3\\fs18 valueRange\n\\f4\\fs20  parameter establishes the color-mapped range of spatial map values, as a vector of length two specifying a minimum and maximum; this does not need to match the actual range of values in the map.  The \n\\f3\\fs18 colors\n\\f4\\fs20  parameter then establishes the corresponding colors for values within the interval defined by \n\\f3\\fs18 valueRange\n\\f4\\fs20 : values less than or equal to \n\\f3\\fs18 valueRange[0]\n\\f4\\fs20  will map to \n\\f3\\fs18 colors[0]\n\\f4\\fs20 , values greater than or equal to \n\\f3\\fs18 valueRange[1]\n\\f4\\fs20  will map to the last \n\\f3\\fs18 colors\n\\f4\\fs20  value, and intermediate values will shade continuously through the specified vector of colors, with interpolation between adjacent colors to produce a continuous spectrum.  This is much simpler than it sounds in this description; see the recipes for an illustration of its use.\\\nIf \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  are both \n\\f3\\fs18 NULL\n\\f4\\fs20 , a default grayscale color scheme will be used in SLiMgui, but an error will result if \n\\f3\\fs18 mapColor()\n\\f4\\fs20  is called.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)changeValues(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Changes the grid values used for the target spatial map.  The parameter \n\\f3\\fs18 x\n\\f4\\fs20  should be either a \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object from which values are taken directly, or a vector, matrix, or array of numeric values as described in the documentation for \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 .  Other characteristics of the spatial map, such as its color mapping (if defined), its spatial bounds, and its spatiality, will remain unchanged.  The grid resolution of the spatial map is allowed to change with this method.  This method is useful for changing the values of a spatial map over time, such as to implement changes to the landscape\\'92s characteristics due to seasonality, climate change, processes such as fire or urbanization, and so forth.  As with the original map values provided to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 , it is often useful to read map values from a PNG image file using the Eidos class \n\\f3\\fs18 Image\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)divide(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Divides the spatial map by \n\\f3\\fs18 x\n\\f4\\fs20 .  One possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, each grid value of the target spatial map is divided by \n\\f3\\fs18 x\n\\f4\\fs20 .  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each grid value of the target spatial map is divided by the corresponding value of \n\\f3\\fs18 x\n\\f4\\fs20 .  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is divided by the corresponding grid value of \n\\f3\\fs18 x\n\\f4\\fs20  (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)exp(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Exponentiates the values of the spatial map.  More precisely, each grid value \n\\f1\\i x\n\\f4\\i0  of the target spatial map is exponentiated \\'96 replaced by the value \n\\f1\\i e\n\\fs13\\fsmilli6667 \\super x\n\\f4\\i0\\fs20 \\nosupersub .  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)gridValues(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the values for the spatial map\\'92s grid as a vector (for a 1D map), a matrix (for a 2D map), or an array (for a 3D map).  The form and orientation of the returned values is such that it could be used to create a new spatial map, with \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 , which would be identical to the original.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)interpolate(integer$\\'a0factor, [string$\\'a0method\\'a0=\\'a0\"linear\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Increases the resolution of the spatial map by \n\\f3\\fs18 factor\n\\f4\\fs20 , changing the dimensions of the spatial map\\'92s grid of values (while leaving its spatial bounds unchanged), by interpolating new values between the existing values.  The parameter \n\\f3\\fs18 factor\n\\f4\\fs20  must be an integer in [\n\\f3\\fs18 2\n\\f4\\fs20 , \n\\f3\\fs18 10001\n\\f4\\fs20 ], somewhat arbitrarily.  The target spatial map is returned, to allow easy chaining of operations.\\\nFor a 1D spatial map, \n\\f3\\fs18 factor-1\n\\f4\\fs20  new values will be inserted between every pair of values in the original value grid.  A \n\\f3\\fs18 factor\n\\f4\\fs20  of \n\\f3\\fs18 2\n\\f4\\fs20  would therefore insert one new value between each pair of existing values, thereby increasing the map\\'92s resolution by a factor of two.  Note that if the spatial map\\'92s original grid dimension was \n\\f1\\i N\n\\f4\\i0 , the new grid dimension with a \n\\f3\\fs18 factor\n\\f4\\fs20  of \n\\f1\\i k\n\\f4\\i0  would be \n\\f1\\i k\n\\f4\\i0 (\n\\f1\\i N\n\\f4\\i0 \\uc0\\u8722 1)+1, not \n\\f1\\i kN\n\\f4\\i0 , because new values are inserted only \n\\f1\\i between\n\\f4\\i0  existing values.  For 2D and 3D spatial maps, essentially the same process is conducted along each axis of the map\\'92s spatiality, increasing the resolution of the map by \n\\f3\\fs18 factor\n\\f4\\fs20  in every dimension.\\\nIf \n\\f3\\fs18 method\n\\f4\\fs20  is \n\\f3\\fs18 \"linear\"\n\\f4\\fs20  (the default), linear (or bilinear or trilinear, for 2D/3D maps) interpolation will be used to interpolate the values for the new grid points.  Alternatively, if \n\\f3\\fs18 method\n\\f4\\fs20  is \n\\f3\\fs18 \"nearest\"\n\\f4\\fs20 , the nearest value in the old grid will be used for new grid points; with this method, it is recommended that \n\\f3\\fs18 factor\n\\f4\\fs20  be odd, not even, to avoid artifacts due to rounding of coordinates midway between the original grid positions.  If method is \n\\f3\\fs18 \"cubic\"\n\\f4\\fs20 , cubic (or bicubic, for 2D maps) will be used; this generally produces smoother interpolation with fewer artifacts than \n\\f3\\fs18 \"linear\"\n\\f4\\fs20 , but it is not supported for 3D maps.  The choice of interpolation method used here is independent of the map\\'92s \n\\f3\\fs18 interpolate\n\\f4\\fs20  property.  Note that while the \n\\f3\\fs18 \"nearest\"\n\\f4\\fs20  and \n\\f3\\fs18 \"linear\"\n\\f4\\fs20  interpolation methods will leave the range of values in the map unchanged, \n\\f3\\fs18 \"cubic\"\n\\f4\\fs20  interpolation may produce interpolated values that are outside the original range of values (by design).  Periodic boundaries are currently supported only for \n\\f3\\fs18 \"nearest\"\n\\f4\\fs20 , \n\\f3\\fs18 \"linear\"\n\\f4\\fs20 , and 1D \n\\f3\\fs18 \"cubic\"\n\\f4\\fs20  interpolation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(string)mapColor(numeric\\'a0value)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Uses the spatial map\\'92s color-translation machinery (as defined by the \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  parameters to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 ) to translate each element of \n\\f3\\fs18 value\n\\f4\\fs20  into a corresponding color string.  If the spatial map does not have color-translation capabilities, an error will result.  See the documentation for \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  for information regarding the details of color translation.  See the Eidos manual for further information on color strings.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Image>$)mapImage([Ni$\\'a0width\\'a0=\\'a0NULL], [Ni$\\'a0height\\'a0=\\'a0NULL], [logical$\\'a0centers\\'a0=\\'a0F], [logical$\\'a0color\\'a0=\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 Image\n\\f4\\fs20  object sampled from the spatial map.  The image will be \n\\f3\\fs18 width\n\\f4\\fs20  pixels wide and \n\\f3\\fs18 height\n\\f4\\fs20  pixels tall; the intrinsic size of the spatial map itself will be used if one of these parameters is \n\\f3\\fs18 NULL\n\\f4\\fs20 .  The image will be oriented in the same way as it is displayed in SLiMgui (which conceptually entails a transformation from matrix coordinates, which store values by column, to standard image coordinates, which store values by row; see the Eidos manual\\'92s documentation of \n\\f3\\fs18 Image\n\\f4\\fs20  for details).  This method may only be called for 2D spatial maps at present.\\\nThe sampling of the spatial map can be done in one of two ways, as controlled by the \n\\f3\\fs18 centers\n\\f4\\fs20  parameter.  If \n\\f3\\fs18 centers\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , a (\n\\f3\\fs18 width+1\n\\f4\\fs20 ) \\'d7 (\n\\f3\\fs18 height+1\n\\f4\\fs20 ) grid of lines that delineates \n\\f3\\fs18 width\n\\f4\\fs20  \\'d7 \n\\f3\\fs18 height\n\\f4\\fs20  rectangular pixels will be overlaid on top of the spatial map, and values will be sampled from the spatial map at the \n\\f1\\i center\n\\f4\\i0  of each of these pixels.  If \n\\f3\\fs18 centers\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), a \n\\f3\\fs18 width\n\\f4\\fs20  \\'d7 \n\\f3\\fs18 height\n\\f4\\fs20  grid of lines will be overlaid on top of the spatial map, and values will be sampled from the spatial map at the \n\\f1\\i vertices\n\\f4\\i0  of the grid.  If interpolation is not enabled for the spatial map, these two options will both recover the original matrix of values used to define the spatial map (assuming, here and below, that \n\\f3\\fs18 width\n\\f4\\fs20  and \n\\f3\\fs18 height\n\\f4\\fs20  are \n\\f3\\fs18 NULL\n\\f4\\fs20 ).  If interpolation is enabled for the spatial map, however, \n\\f3\\fs18 centers == F\n\\f4\\fs20  will recover the original values, but will not capture the \\'93typical\\'94 value of each pixel in the image; \n\\f3\\fs18 centers == T\n\\f4\\fs20 , on the other hand, will not recover the original values, but will capture the \\'93typical\\'94 value of each pixel in the image (i.e., the value at the center of each pixel, as produced by interpolation).\\\nIf \n\\f3\\fs18 color\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), the \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  parameters supplied to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  will be used to translate map values to RGB color values as described in the documentation of that method, providing the same appearance as in SLiMgui; of course those parameters must have been supplied, otherwise an error will result.  If \n\\f3\\fs18 color\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , on the other hand, a grayscale image will be produced that directly reflects the map values without color translation.  In this case, this method needs to translate map values, which can have any \n\\f3\\fs18 float\n\\f4\\fs20  value, into grayscale pixel values that are integers in [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 255\n\\f4\\fs20 ].  To do so, the map values are multiplied by \n\\f3\\fs18 255.0\n\\f4\\fs20 , clamped to [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 255.0\n\\f4\\fs20 ], and then rounded to the nearest integer.  This translation scheme essentially assumes that map values are in [0, 1]; for spatial maps that were defined using the \n\\f3\\fs18 floatK\n\\f4\\fs20  channel of a grayscale PNG image, this should recover the original image\\'92s pixel values.  (If a different translation scheme is desired, \n\\f3\\fs18 color=T\n\\f4\\fs20  with the desired \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  should be used.)\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)mapValue(float\\'a0point)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Uses the spatial map\\'92s mapping machinery (as defined by the \n\\f3\\fs18 gridSize\n\\f4\\fs20 , \n\\f3\\fs18 values\n\\f4\\fs20 , and \n\\f3\\fs18 interpolate\n\\f4\\fs20  parameters to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 ) to translate the coordinates of \n\\f3\\fs18 point\n\\f4\\fs20  into a corresponding map value.  The length of \n\\f3\\fs18 point\n\\f4\\fs20  must be equal to the spatiality of the spatial map; in other words, for a spatial map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , \n\\f3\\fs18 point\n\\f4\\fs20  must be of length \n\\f3\\fs18 2\n\\f4\\fs20 , specifying the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinates of the point to be evaluated.  Interpolation will automatically be used if it was enabled for the spatial map.  Point coordinates are clamped into the range defined by the spatial boundaries, even if the spatial boundaries are periodic; use \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  to wrap the point coordinates first if desired.  See the documentation for \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  for information regarding the details of value mapping.\\\nThe \n\\f3\\fs18 point\n\\f4\\fs20  parameter may also contain more than one point to be looked up.  In this case, the length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the spatiality of the spatial map; for a spatial map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , for example, the length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of \n\\f3\\fs18 2\n\\f4\\fs20 , and successive pairs of elements from point (elements \n\\f3\\fs18 0\n\\f4\\fs20  and \n\\f3\\fs18 1\n\\f4\\fs20 , then elements \n\\f3\\fs18 2\n\\f4\\fs20  and \n\\f3\\fs18 3\n\\f4\\fs20 , etc.) will be taken as the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinates of the points to be evaluated.  This allows \n\\f3\\fs18 mapValue()\n\\f4\\fs20  to be used in a vectorized fashion.\\\nThe \n\\f3\\fs18 spatialMapValue()\n\\f4\\fs20  method of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  provides essentially the same functionality as this method; it may be more convenient to use, for some usage cases, and it checks that the spatial map is actually added to the subpopulation in question, providing an additional consistency check.  However, either method may be used.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)multiply(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Multiplies the spatial map by \n\\f3\\fs18 x\n\\f4\\fs20 .  One possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, each grid value of the target spatial map is multiplied by \n\\f3\\fs18 x\n\\f4\\fs20 .  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each grid value of the target spatial map is multiplied by the corresponding value of \n\\f3\\fs18 x\n\\f4\\fs20 .  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is multiplied by the corresponding grid value of \n\\f3\\fs18 x\n\\f4\\fs20  (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)power(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Raises the spatial map to the power \n\\f3\\fs18 x\n\\f4\\fs20 .  One possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, each grid value of the target spatial map is raised to the power \n\\f3\\fs18 x\n\\f4\\fs20 .  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each grid value of the target spatial map is raised to the power of the corresponding value of \n\\f3\\fs18 x\n\\f4\\fs20 .  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of the target spatial map is raised to power of the corresponding grid value of \n\\f3\\fs18 x\n\\f4\\fs20  (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)range(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the range of values contained in the spatial map.  The result is a \n\\f3\\fs18 float\n\\f4\\fs20  vector of length \n\\f3\\fs18 2\n\\f4\\fs20 ; the first element is the minimum map value, and the second element is the maximum map value.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)rescale([numeric$\\'a0min\\'a0=\\'a00.0], [numeric$\\'a0max\\'a0=\\'a01.0])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Rescales the values of the spatial map to the range [\n\\f3\\fs18 min\n\\f4\\fs20 , \n\\f3\\fs18 max\n\\f4\\fs20 ].  By default, the rescaling is to the range [\n\\f3\\fs18 0.0\n\\f4\\fs20 , \n\\f3\\fs18 1.0\n\\f4\\fs20 ].  It is required that \n\\f3\\fs18 min\n\\f4\\fs20  be less than \n\\f3\\fs18 max\n\\f4\\fs20 , and that both be finite.  Note that the final range may not be exactly [\n\\f3\\fs18 min\n\\f4\\fs20 , \n\\f3\\fs18 max\n\\f4\\fs20 ] due to numerical error.  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)sampleImprovedNearbyPoint(float\\'a0point, float$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This variant of \n\\f3\\fs18 sampleNearbyPoint()\n\\f4\\fs20  samples a Metropolis\\'96Hastings move on the spatial map.  See \n\\f3\\fs18 sampleNearbyPoint()\n\\f4\\fs20  for discussion of the basic idea.  This method proposes a nearby point drawn from the given kernel.  If the drawn point has a larger map value than the original point, the new point is returned.  If the drawn point has a smaller map value than the original point, it is returned with a probability equal to the ratio between its map value and the original map value, otherwise the original point is returned.  The distribution of points that move (or not) to new locations governed by this method will converge upon the map itself, in a similar manner to how MCMC converges upon the posterior distribution (assuming no other forces, such as birth or death, influence the distribution of individuals).  Movement governed by this method is \\'93improved\\'94 in the sense that points will tend to remain where they are unless the new sampled point is an improvement for them \\'96 a higher map value.  Note that unlike \n\\f3\\fs18 sampleNearbyPoint()\n\\f4\\fs20 , this method requires that all map values are non-negative.\\\nThe parameter \n\\f3\\fs18 point\n\\f4\\fs20  may contain any number of points; the returned vector will contain corresponding points sampled as described above.  Each supplied point must provide coordinates precisely as specified by the spatiality of the target map; for example, if the target map\\'92s spatiality is \n\\f3\\fs18 \"xz\"\n\\f4\\fs20  (in an \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  species), each point must contain two elements, providing the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinate.  Be careful; this means that in general it is not safe to pass an individual\\'92s \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for \n\\f3\\fs18 point\n\\f4\\fs20 , for example (although it is safe if the spatiality of the map matches the dimensionality of the simulation); other properties on \n\\f3\\fs18 Individual\n\\f4\\fs20  exist for getting the individual\\'92s coordinates in a particular spatiality, such as the \n\\f3\\fs18 xz\n\\f4\\fs20  property for this example.  Supplied points are not required to be within bounds, but since nearby points are sampled from the given kernel and must be within bounds, an infinite loop might result if a supplied point is substantially outside bounds.\\\nThe kernel is specified with a kernel type, \n\\f3\\fs18 functionType\n\\f4\\fs20 , followed by zero or more ellipsis arguments; see \n\\f3\\fs18 smooth()\n\\f4\\fs20  for further information.  For this method, at present only kernel types \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"t\"\n\\f4\\fs20  are supported, and type \n\\f3\\fs18 \"t\"\n\\f4\\fs20  is not presently supported for 3D kernels.  The parameters that define the kernel\\'92s shape \\'96 the ellipsis arguments that follow \n\\f3\\fs18 functionType\n\\f4\\fs20  \\'96 may each, independently, be either a singleton or a vector with length equal to the number of points, providing a separate value for each point being processed.  In this way, all of the nearby points can be drawn from the same kernel, or each from a separately defined kernel.  Since \n\\f3\\fs18 maxDistance\n\\f4\\fs20  and \n\\f3\\fs18 functionType\n\\f4\\fs20  are required to be singletons, however, their values cannot vary from point to point in the present design.\\\nSee also the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 deviatePositionsWithMap()\n\\f4\\fs20 , which is conceptually similar to this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)sampleNearbyPoint(float\\'a0point, float$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 For a spatial point supplied in \n\\f3\\fs18 point\n\\f4\\fs20 , returns a nearby point sampled from a kernel weighted by the spatial map\\'92s values.  Only points within the maximum distance of the kernel, \n\\f3\\fs18 maxDistance\n\\f4\\fs20 , will be chosen, and the probability that a given point is chosen will be proportional to the density of the kernel at that point multiplied by the value of the map at that point (interpolated, if interpolation is enabled for the map).  Negative values of the map will be treated as zero.  The point returned will be within spatial bounds, respecting periodic boundaries if in effect (so there is no need to call \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  on the result).\\\nThe parameter \n\\f3\\fs18 point\n\\f4\\fs20  may contain any number of points; the returned vector will contain corresponding points sampled as described above.  Each supplied point must provide coordinates precisely as specified by the spatiality of the target map; for example, if the target map\\'92s spatiality is \n\\f3\\fs18 \"xz\"\n\\f4\\fs20  (in an \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  species), each point must contain two elements, providing the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinate.  Be careful; this means that in general it is not safe to pass an individual\\'92s \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for \n\\f3\\fs18 point\n\\f4\\fs20 , for example (although it is safe if the spatiality of the map matches the dimensionality of the simulation); other properties on \n\\f3\\fs18 Individual\n\\f4\\fs20  exist for getting the individual\\'92s coordinates in a particular spatiality, such as the \n\\f3\\fs18 xz\n\\f4\\fs20  property for this example.  Supplied points are not required to be within bounds, but since nearby points are sampled from the given kernel and must be within bounds, an infinite loop might result if a supplied point is substantially outside bounds.\\\nThe kernel is specified with a kernel type, \n\\f3\\fs18 functionType\n\\f4\\fs20 , followed by zero or more ellipsis arguments; see \n\\f3\\fs18 smooth()\n\\f4\\fs20  for further information.  For this method, at present only kernel types \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"t\"\n\\f4\\fs20  are supported, and type \n\\f3\\fs18 \"t\"\n\\f4\\fs20  is not presently supported for 3D kernels.  The parameters that define the kernel\\'92s shape \\'96 the ellipsis arguments that follow \n\\f3\\fs18 functionType\n\\f4\\fs20  \\'96 may each, independently, be either a singleton or a vector with length equal to the number of points, providing a separate value for each point being processed.  In this way, all of the nearby points can be drawn from the same kernel, or each from a separately defined kernel.  Since \n\\f3\\fs18 maxDistance\n\\f4\\fs20  and \n\\f3\\fs18 functionType\n\\f4\\fs20  are required to be singletons, however, their values cannot vary from point to point in the present design.\\\nThis method can be used to find points in the vicinity of individuals that are favorable \\'96 possessing more resources, or better environmental conditions, etc.  It can also be used to guide the dispersal or foraging behavior of individuals.  See \n\\f3\\fs18 sampleImprovedNearbyPoint()\n\\f4\\fs20  for a variant that may be useful for directed movement across a landscape.  Note that the algorithm for \n\\f3\\fs18 sampleNearbyPoint()\n\\f4\\fs20  works by rejection sampling, and so will be very inefficient if the maximum value of the map (anywhere, across the entire map) is much larger than the typical value of the map where individuals are.  The algorithm for \n\\f3\\fs18 sampleImprovedNearbyPoint()\n\\f4\\fs20  is different, and does not exhibit this performance issue.\\\nSee also the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 deviatePositionsWithMap()\n\\f4\\fs20 , which is conceptually similar to this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)smooth(float$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Smooths (or blurs, one could say) the values of the spatial map by convolution with a kernel.  The kernel is specified with a maximum distance \n\\f3\\fs18 maxDistance\n\\f4\\fs20  (beyond which the kernel cuts off to a value of zero), a kernel type \n\\f3\\fs18 functionType\n\\f4\\fs20  that should be \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , \n\\f3\\fs18 \"c\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , and additional parameters in the ellipsis \n\\f3\\fs18 ...\n\\f4\\fs20  that depend upon the kernel type and further specify its shape.  The target spatial map is returned, to allow easy chaining of operations.\\\nThe kernel specification is similar to that for the \n\\f3\\fs18 setInteractionType()\n\\f4\\fs20  method of \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , but omits the maximum value of the kernel.  Specifically, \n\\f3\\fs18 functionType\n\\f4\\fs20  may be \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , in which case no ellipsis arguments should be supplied; \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , similarly with no ellipsis arguments; \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  lambda (rate) parameter for a negative exponential function; \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  sigma (standard deviation) parameter for a Gaussian function; \n\\f3\\fs18 \"c\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a Cauchy distribution function; or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  degrees of freedom and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a \n\\f1\\i t\n\\f4\\i0 -distribution function.  See the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  class documentation for discussions of these kernel types.\\\nDistance metrics specified to this method, such as \n\\f3\\fs18 maxDistance\n\\f4\\fs20  and the additional kernel shape parameters, are measured in the distance scale of the spatial map \\'96 the same distance scale in which the spatial bounds of the map are specified.  The operation is performed upon the grid values of the spatial map; distances are internally translated into the scale of the value grid.  For non-periodic boundaries, clipping at the edge of the spatial map is done; in a 2D map with no periodic boundaries, for example, the weights of edge and corner grid values are adjusted for their partial (one-half and one-quarter) coverage.  For periodic boundaries, the smoothing operation will automatically wrap around based upon the assumption that the grid values at the two connected edges of the periodic boundary have identical values (which they should, since by definition they represent the same position in space).\\\nThe density scale of the kernel has no effect and will be normalized; this is the reason that \n\\f3\\fs18 smooth()\n\\f4\\fs20 , unlike \n\\f3\\fs18 InteractionType\n\\f4\\fs20 , does not require specification of the maximum value of the kernel.  This normalization prevents the kernel from increasing or decreasing the average spatial map value (apart from possible edge effects).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<SpatialMap>$)subtract(ifo<SpatialMap>\\'a0x)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Subtracts \n\\f3\\fs18 x\n\\f4\\fs20  from the spatial map.  One possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is a singleton \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value; in this case, \n\\f3\\fs18 x\n\\f4\\fs20  is subtracted from each grid value of the target spatial map.  Another possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is an \n\\f3\\fs18 integer\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  vector/matrix/array of the same dimensions as the target spatial map\\'92s grid; in this case, each value of \n\\f3\\fs18 x\n\\f4\\fs20  is subtracted from the corresponding grid value of the target spatial map.  The third possibility is that \n\\f3\\fs18 x\n\\f4\\fs20  is itself a (singleton) spatial map; in this case, each grid value of \n\\f3\\fs18 x\n\\f4\\fs20  is subtracted from the corresponding grid value of the target spatial map (and thus the two spatial maps must match in their spatiality, their spatial bounds, and their grid dimensions).  The target spatial map is returned, to allow easy chaining of operations.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.16  Class Species\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.16.1  \n\\f2\\fs18 Species\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 avatar => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The avatar string used to represent this species in SLiMgui.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Avatars are typically one-character strings, often using an emoji that symbolizes the species.  This property is read-only; its value should be set with the \n\\f3\\fs18 avatar\n\\f4\\fs20  parameter of \n\\f3\\fs18 initializeSpecies()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 chromosome => (object<Chromosome>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object used by the species.  This property may only be accessed in a single-chromosome model; if there are multiple chromosomes (or none), the \n\\f3\\fs18 chromosomes\n\\f4\\fs20  property must be used instead.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 chromosomes => (object<Chromosome>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects used by the species, in the order in which they were defined.  See also the \n\\f3\\fs18 sexChromosomes\n\\f4\\fs20  property.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 color => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The color used to display information about this species in SLiMgui.  Outside of SLiMgui, this property still exists, but is not used by SLiM.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20  (see the Eidos manual).  This property is read-only; its value should be set with the \n\\f3\\fs18 color\n\\f4\\fs20  parameter of \n\\f3\\fs18 initializeSpecies()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 cycle <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The current cycle count for this species.  This counter begins at 1, and increments at the end of every tick in which the species is active.  In models with non-overlapping generations, particularly WF models, this can be thought of as a generation counter.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 description <\\'96> (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A human-readable \n\\f3\\fs18 string\n\\f4\\fs20  description for the species.  By default, this is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 ; however, it may be set to whatever you wish.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 dimensionality => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The spatial dimensionality of the simulation for this species, as specified in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  This will be \n\\f3\\fs18 \"\"\n\\f4\\fs20  (the empty string) for non-spatial simulations (the default), or \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 , for simulations using those spatial dimensions respectively.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 genomicElementTypes => (object<GenomicElementType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 GenomicElementType\n\\f4\\fs20  objects being used in the species.\\cf2   These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The identifier for this species.  Species identifiers are determined by their declaration order in the script; the first declared species is given an \n\\f3\\fs18 id\n\\f4\\fs20  of \n\\f3\\fs18 0\n\\f4\\fs20 , the second is given an \n\\f3\\fs18 id\n\\f4\\fs20  of \n\\f3\\fs18 1\n\\f4\\fs20 , and so forth.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationTypes => (object<MutationType>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 MutationType\n\\f4\\fs20  objects being used in the species.\\cf2   These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutations => (object<Mutation>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects that are currently active in the species.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 name => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A human-readable \n\\f3\\fs18 string\n\\f4\\fs20  name for the subpopulation.  This is always the declared name of the species, as given in the explicit species declaration in script, and cannot be changed.  The \n\\f3\\fs18 name\n\\f4\\fs20  of a species may appear as a label in SLiMgui, and it can be useful in generating output, debugging, and other purposes.  See also the description property, which can be changed by the user and used for any purpose.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nnucleotideBased => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If \n\\f3\\fs18 T\n\\f4\\fs20 , the model for this species is nucleotide-based; if \n\\f3\\fs18 F\n\\f4\\fs20 , it is not.  See the discussion of the \n\\f3\\fs18 nucleotideBased\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20  for discussion.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 periodicity => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe spatial periodicity of the simulation for this species, as specified in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  This will be \n\\f3\\fs18 \"\"\n\\f4\\fs20  (the empty string) for non-spatial simulations and simulations with no periodic spatial dimensions (the default).  Otherwise, it will be a string representing the subset of spatial dimensions that have been declared to be periodic, as specified to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 scriptBlocks => (object<SLiMEidosBlock>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects in the simulation that have been declared with this species as their \n\\f3\\fs18 species\n\\f4\\fs20  specifier (\n\\f1\\i not\n\\f4\\i0  \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier).  These will always be callback blocks; callbacks are species-specific, while other types of blocks are not.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 sexChromosomes => (object<Chromosome>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects used by the species that represent sex chromosomes, in the order in which they were defined.  Sex chromosomes are specifically those of type \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"W\"\n\\f4\\fs20 , \n\\f3\\fs18 \"Z\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"-Y\"\n\\f4\\fs20 .  See also the \n\\f3\\fs18 chromosomes\n\\f4\\fs20  property, and the \n\\f3\\fs18 isSexChromosome\n\\f4\\fs20  property of \n\\f3\\fs18 Chromosome\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 sexEnabled => (logical$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 If \n\\f3\\fs18 T\n\\f4\\fs20 , sex is enabled for this species; if \n\\f3\\fs18 F\n\\f4\\fs20 , individuals are hermaphroditic.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 subpopulations => (object<Subpopulation>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  instances currently defined in the species.\\cf2   These are guaranteed to be in sorted order, by their \n\\f3\\fs18 id\n\\f4\\fs20  property.\n\\f5 \\cf0 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 substitutions => (object<Substitution>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A vector of \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects, representing all mutations that have been fixed in this species.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to the simulation.\n\\f5 \\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.16.2  \n\\f2\\fs18 Species\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\'96\\'a0(object<Dictionary>$)addPatternForClone(iso<Chromosome>$\\'a0chromosome, No<Dictionary>$\\'a0pattern, object<Individual>$\\'a0parent, [Ns$\\'a0sex\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds an inheritance dictionary for the specified chromosome to the pattern dictionary \n\\f3\\fs18 pattern\n\\f4\\fs20 , representing producing a clone of \n\\f3\\fs18 parent\n\\f4\\fs20 , with sex optionally specified by \n\\f3\\fs18 sex\n\\f4\\fs20 .  The parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20  can provide a chromosome \n\\f3\\fs18 id\n\\f4\\fs20  (an \n\\f3\\fs18 integer\n\\f4\\fs20 ), a chromosome \n\\f3\\fs18 symbol\n\\f4\\fs20  (a \n\\f3\\fs18 string\n\\f4\\fs20 ), or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.  The resulting pattern dictionary is intended for use with the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 ; see that method for background on the use of pattern dictionaries.\\\nThe parameter \n\\f3\\fs18 pattern\n\\f4\\fs20  must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ), or \n\\f3\\fs18 NULL\n\\f4\\fs20 .  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , a new singleton object of class \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will be created, set up, and returned; otherwise, the returned object is the same object passed in as \n\\f3\\fs18 pattern\n\\f4\\fs20 .  The inheritance dictionary generated by \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20  will be added to \n\\f3\\fs18 pattern\n\\f4\\fs20  as the value for a particular key.  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is already configured to use \n\\f3\\fs18 string\n\\f4\\fs20  keys, the key used will be the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of the chromosome; otherwise, including if \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the key used will be the \n\\f3\\fs18 id\n\\f4\\fs20  property of the chromosome.  If the key in question already exists in \n\\f3\\fs18 pattern\n\\f4\\fs20 , its value will be replaced.\\\nThe precise inheritance pattern generated by this method depends upon the chromosome\\'92s type; see \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20  for a description of the different chromosome types and the ways in which they are inherited.  The pattern will be the same as would be used by the \n\\f3\\fs18 addCloned()\n\\f4\\fs20  method for the chromosome.  If \n\\f3\\fs18 sex\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the sex of the offspring is assumed to be the same as the parent; in non-sexual models, \n\\f3\\fs18 NULL\n\\f4\\fs20  must be passed.  If the sex of the offspring will be different from the parent, \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  should be passed; if changing the sex from parent to offspring presents any genetic problems (if the chromosome is a sex chromosome, for example), an error will be raised, but if the chromosome does not depend upon sex, the change of sex will be allowed.  Note that the generated inheritance dictionary does not encode the offspring sex; the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.  The final pattern dictionary passed to \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will be validated against the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter given to that method.\\\nIt is typically not necessary to call \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20 , since \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will usually automatically infer the correct inheritance pattern from its parental individual \n\\f3\\fs18 parent1\n\\f4\\fs20  if an inheritance dictionary for the chromosome is not supplied in \n\\f3\\fs18 pattern\n\\f4\\fs20 .  This method is needed primarily for edge cases, such as if \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  is being used to generate a biparental cross, but a particular chromosome should be cloned from just one of the parents in a manner that the biparental cross would not do automatically.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Dictionary>$)addPatternForCross(iso<Chromosome>$\\'a0chromosome, No<Dictionary>$\\'a0pattern, object<Individual>$\\'a0parent1, object<Individual>$\\'a0parent2, [Ns$\\'a0sex\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds an inheritance dictionary for the specified chromosome to the pattern dictionary \n\\f3\\fs18 pattern\n\\f4\\fs20 , representing a biparental cross between \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  to generate an offspring, with sex optionally specified by \n\\f3\\fs18 sex\n\\f4\\fs20 .  The parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20  can provide a chromosome \n\\f3\\fs18 id\n\\f4\\fs20  (an \n\\f3\\fs18 integer\n\\f4\\fs20 ), a chromosome \n\\f3\\fs18 symbol\n\\f4\\fs20  (a \n\\f3\\fs18 string\n\\f4\\fs20 ), or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.  The resulting pattern dictionary is intended for use with the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 ; see that method for background on the use of pattern dictionaries.\\\nThe parameter \n\\f3\\fs18 pattern\n\\f4\\fs20  must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ), or \n\\f3\\fs18 NULL\n\\f4\\fs20 .  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , a new singleton object of class \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will be created, set up, and returned; otherwise, the returned object is the same object passed in as \n\\f3\\fs18 pattern\n\\f4\\fs20 .  The inheritance dictionary generated by \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20  will be added to \n\\f3\\fs18 pattern\n\\f4\\fs20  as the value for a particular key.  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is already configured to use \n\\f3\\fs18 string\n\\f4\\fs20  keys, the key used will be the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of the chromosome; otherwise, including if \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the key used will be the \n\\f3\\fs18 id\n\\f4\\fs20  property of the chromosome.  If the key in question already exists in \n\\f3\\fs18 pattern\n\\f4\\fs20 , its value will be replaced.\\\nThe precise inheritance pattern generated by this method depends upon the chromosome\\'92s type; see \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20  for a description of the different chromosome types and the ways in which they are inherited.  The pattern will be the same as would be used by the \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  method for the chromosome.  In some cases, the value of \n\\f3\\fs18 sex\n\\f4\\fs20  is unimportant and may be left as \n\\f3\\fs18 NULL\n\\f4\\fs20 ; a \n\\f3\\fs18 NULL\n\\f4\\fs20  value for \n\\f3\\fs18 sex\n\\f4\\fs20  essentially asserts that the sex of the offspring is unimportant to the inheritance pattern for the chromosome with the given parents.  If that assertion is untrue \\'96 if the sex needs to be known, for example to know how a sex chromosome should be inherited \\'96 an error will be raised.  When the sex needs to be known, \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  must be passed so that the correct inheritance pattern can be generated.  In non-sexual models, \n\\f3\\fs18 NULL\n\\f4\\fs20  must be passed.  Note that the generated inheritance dictionary does not encode the offspring sex; the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.  The final pattern dictionary passed to \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will be validated against the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter given to that method.\\\nIt is typically not necessary to call \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20 , since \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will usually automatically infer the correct inheritance pattern from its parental individuals \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  if an inheritance dictionary for the chromosome is not supplied in \n\\f3\\fs18 pattern\n\\f4\\fs20 .  This method is needed primarily for edge cases, such as if \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  is being used to generate a clonal offspring, but a particular chromosome should be produced with recombination.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Dictionary>$)addPatternForNull(iso<Chromosome>$\\'a0chromosome, No<Dictionary>$\\'a0pattern, [Ns$\\'a0sex\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds an inheritance dictionary for the specified chromosome to the pattern dictionary \n\\f3\\fs18 pattern\n\\f4\\fs20 , representing a non-inheritance event producing null haplosomes, with sex optionally specified by \n\\f3\\fs18 sex\n\\f4\\fs20 .  The parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20  can provide a chromosome \n\\f3\\fs18 id\n\\f4\\fs20  (an \n\\f3\\fs18 integer\n\\f4\\fs20 ), a chromosome \n\\f3\\fs18 symbol\n\\f4\\fs20  (a \n\\f3\\fs18 string\n\\f4\\fs20 ), or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.  The resulting pattern dictionary is intended for use with the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 ; see that method for background on the use of pattern dictionaries.\\\nThe parameter \n\\f3\\fs18 pattern\n\\f4\\fs20  must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ), or \n\\f3\\fs18 NULL\n\\f4\\fs20 .  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , a new singleton object of class \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will be created, set up, and returned; otherwise, the returned object is the same object passed in as \n\\f3\\fs18 pattern\n\\f4\\fs20 .  The inheritance dictionary generated by \n\\f3\\fs18 addPatternForNull()\n\\f4\\fs20  will be added to \n\\f3\\fs18 pattern\n\\f4\\fs20  as the value for a particular key.  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is already configured to use \n\\f3\\fs18 string\n\\f4\\fs20  keys, the key used will be the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of the chromosome; otherwise, including if \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the key used will be the \n\\f3\\fs18 id\n\\f4\\fs20  property of the chromosome.  If the key in question already exists in \n\\f3\\fs18 pattern\n\\f4\\fs20 , its value will be replaced.\\\nFor all chromosome types, this method will simply produce a null haplosome or haplosomes for the specified chromosome.  If the chromosome does not allow a null haplosome, an error will be raised.  In some cases, the value of \n\\f3\\fs18 sex\n\\f4\\fs20  is unimportant and may be left as \n\\f3\\fs18 NULL\n\\f4\\fs20 ; a \n\\f3\\fs18 NULL\n\\f4\\fs20  value for \n\\f3\\fs18 sex\n\\f4\\fs20  essentially asserts that the chromosome allows null haplosomes for any sex.  If that assertion is untrue \\'96 if the sex needs to be known, for example to know whether a null haplosome is allowed for a sex chromosome \\'96 an error will be raised.  When the sex needs to be known, \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  must be passed so that \n\\f3\\fs18 addPatternForNull()\n\\f4\\fs20  is satisfied that a legal pattern for the chromosome will be generated.  In non-sexual models, \n\\f3\\fs18 NULL\n\\f4\\fs20  must be passed.  Note that the generated inheritance dictionary does not encode the offspring sex; the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is simply used to determine and validate the inheritance pattern for the specified chromosome.  The final pattern dictionary passed to \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will be validated against the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter given to that method.\\\nIf only one of the two haplosomes for a diploid chromosome should be a null haplosome, and \n\\f3\\fs18 addPatternForCrossed()\n\\f4\\fs20  and \n\\f3\\fs18 addPatternForCloned()\n\\f4\\fs20  would not produce the desired pattern, use \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20 , which provides complete control.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Dictionary>$)addPatternForRecombinant(iso<Chromosome>$\\'a0chromosome, No<Dictionary>$\\'a0pattern, No<Haplosome>$\\'a0strand1, No<Haplosome>$\\'a0strand2, Ni\\'a0breaks1, No<Haplosome>$\\'a0strand3, No<Haplosome>$\\'a0strand4, Ni\\'a0breaks2, [Ns$\\'a0sex\\'a0=\\'a0NULL], [logical$\\'a0randomizeStrands\\'a0=\\'a0T])\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds an inheritance dictionary for the specified chromosome to the pattern dictionary \n\\f3\\fs18 pattern\n\\f4\\fs20 , representing inheritance by cloning, recombination, or both, to generate an offspring from up to four parental haplosomes, with sex optionally specified by \n\\f3\\fs18 sex\n\\f4\\fs20 .  The parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20  can provide a chromosome \n\\f3\\fs18 id\n\\f4\\fs20  (an \n\\f3\\fs18 integer\n\\f4\\fs20 ), a chromosome \n\\f3\\fs18 symbol\n\\f4\\fs20  (a \n\\f3\\fs18 string\n\\f4\\fs20 ), or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object.  The resulting pattern dictionary is intended for use with the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  method \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 ; see that method for background on the use of pattern dictionaries.\\\nThe parameter \n\\f3\\fs18 pattern\n\\f4\\fs20  must be a \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ), or \n\\f3\\fs18 NULL\n\\f4\\fs20 .  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , a new singleton object of class \n\\f3\\fs18 Dictionary\n\\f4\\fs20  will be created, set up, and returned; otherwise, the returned object is the same object passed in as \n\\f3\\fs18 pattern\n\\f4\\fs20 .  The inheritance dictionary generated by \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20  will be added to \n\\f3\\fs18 pattern\n\\f4\\fs20  as the value for a particular key.  If \n\\f3\\fs18 pattern\n\\f4\\fs20  is already configured to use \n\\f3\\fs18 string\n\\f4\\fs20  keys, the key used will be the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of the chromosome; otherwise, including if \n\\f3\\fs18 pattern\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the key used will be the \n\\f3\\fs18 id\n\\f4\\fs20  property of the chromosome.  If the key in question already exists in \n\\f3\\fs18 pattern\n\\f4\\fs20 , its value will be replaced.\\\nWhen passed the resulting pattern dictionary, the \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  method will produce the first offspring haplosome using the \n\\f3\\fs18 Haplosome\n\\f4\\fs20  objects \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  with the vector of recombination breakpoints \n\\f3\\fs18 breaks1\n\\f4\\fs20 , and likewise will produce the second offspring haplosome using \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , and \n\\f3\\fs18 breaks2\n\\f4\\fs20 .  If both parental strands for an offspring haplosome are \n\\f3\\fs18 NULL\n\\f4\\fs20 , the breaks vector must be \n\\f3\\fs18 NULL\n\\f4\\fs20  or empty, and a null haplosome will be produced.  If the first parental strand is non-\n\\f3\\fs18 NULL\n\\f4\\fs20  and the second is \n\\f3\\fs18 NULL\n\\f4\\fs20  for an offspring haplosome, the breaks vector must again be \n\\f3\\fs18 NULL\n\\f4\\fs20  or empty, and the first strand will be cloned with mutation.  If both parental strands for an offspring haplosome are non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , recombination between the strands will be done using the supplied breaks vector; in this case, if the breaks vector is \n\\f3\\fs18 NULL\n\\f4\\fs20  then \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will automatically generate breakpoints for the recombination.  All of these semantics are discussed further in the documentation for \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 ; this method is just a helper for that method.  The documentation for \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  may also be helpful for understanding the concepts here, since it is the conceptual foundation upon which the very complex architecture of the \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  method is built.\\\nUnlike \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20  and \n\\f3\\fs18 addPatternForCrossed()\n\\f4\\fs20 , which must infer the inheritance pattern given the chromosome type and the offspring sex, \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20  is given the inheritance pattern, and must simply confirm that it is valid.  If \n\\f3\\fs18 sex\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), this validation only needs to check that the inheritance pattern is possible, for some sex.  For example, if the chromosome type is \n\\f3\\fs18 \"X\"\n\\f4\\fs20  then the inheritance pattern must produce a non-null first haplosome, and the second haplosome can be null (for a male, X\\'96) or non-null (for a female, XX); other inheritance patterns would fail validation.  When the sex is known, \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  may optionally be passed to validate against that sex; X\\'96 would then fail validation if a female is specified, for example.  In non-sexual models, \n\\f3\\fs18 NULL\n\\f4\\fs20  must be passed.  Note that the generated inheritance dictionary does not encode the offspring sex; the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is simply used for validation.  The final pattern dictionary passed to \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  will be validated against the \n\\f3\\fs18 sex\n\\f4\\fs20  parameter given to that method.\\\nThe \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  parameter indicates whether or not the order of recombining parental strands should be randomized in the inheritance dictionary.  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , then if \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  are both non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , their order will be randomized; and similarly for \n\\f3\\fs18 strand3\n\\f4\\fs20  and \n\\f3\\fs18 strand4\n\\f4\\fs20 .  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , no randomization will be done in the inheritance dictionary \\'96 but strand order randomization may still be done by \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  if \n\\f3\\fs18 T\n\\f4\\fs20  is passed for its own \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  parameter.  Randomizing the strand order is usually desirable, to avoid an inheritance bias due to a lack of randomization in the initial copy strand.  Whether you wish to randomize strand order in \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20  or in \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  is up to you; it is harmless to do it in both places, apart from a small performance penalty, but there is no benefit.\\\nOf the family of \n\\f3\\fs18 addPatternFor...()\n\\f4\\fs20  methods, \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20  is the most commonly used.  Typically, \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  can automatically infer the correct inheritance pattern for crossing or cloning (as described in its documentation), but for more complex inheritance patterns, using \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20  is necessary (unless you want to build the pattern dictionary yourself).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<Subpopulation>$)addSubpop(is$\\'a0subpopID, integer$\\'a0size, [float$\\'a0sexRatio\\'a0=\\'a00.5]\\cf2 , [logical$\\'a0haploid\\'a0=\\'a0F]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Add a new subpopulation with id \n\\f3\\fs18 subpopID\n\\f4\\fs20  and \n\\f3\\fs18 size\n\\f4\\fs20  individuals.  The \n\\f3\\fs18 subpopID\n\\f4\\fs20  parameter may be either an \n\\f3\\fs18 integer\n\\f4\\fs20  giving the ID of the new subpopulation, or a \n\\f3\\fs18 string\n\\f4\\fs20  giving the name of the new subpopulation (such as \n\\f3\\fs18 \"p5\"\n\\f4\\fs20  to specify an ID of 5).  Only if sex is enabled for the species, the initial sex ratio may optionally be specified as \n\\f3\\fs18 sexRatio\n\\f4\\fs20  (as the male fraction, M:M+F); if it is not specified, a default of \n\\f3\\fs18 0.5\n\\f4\\fs20  is used.  The new subpopulation will be defined as a global variable immediately by this method, and will also be returned by this method.  Subpopulations added by this method will initially consist of individuals with empty haplosomes.  In order to model subpopulations that split from an already existing subpopulation, use \n\\f3\\fs18 addSubpopSplit()\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 haploid\n\\f4\\fs20  parameter defaults to \n\\f3\\fs18 F\n\\f4\\fs20 , indicating that the generated individuals should adopt their natural ploidy; in particular, type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  chromosomes should be represented in each individual by two empty haplosomes.  The \n\\f3\\fs18 haploid\n\\f4\\fs20  parameter may instead be \n\\f3\\fs18 T\n\\f4\\fs20 ; in this case, for all chromosomes of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  (and only that type), the second haplosome of each new individual will be a null haplosome, rather than an empty haplosome.  This could be useful in a model of haplodiploidy, for example, to generate initial individuals that are haploid for the autosomal chromosomes of the species.  For even greater control in nonWF models, you can call \n\\f3\\fs18 addSubpop()\n\\f4\\fs20  with an initial size of \n\\f3\\fs18 0\n\\f4\\fs20  and then stock the population with new individuals created however you wish in the next tick\\'92s \n\\f3\\fs18 reproduction()\n\\f4\\fs20  callback, such as with the \n\\f3\\fs18 addEmpty()\n\\f4\\fs20  method, providing separate control over the configuration of each individual.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<Subpopulation>$)addSubpopSplit(is$\\'a0subpopID, integer$\\'a0size, io<Subpopulation>$\\'a0sourceSubpop, [float$\\'a0sexRatio\\'a0=\\'a00.5])\n\\f5 \\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Split off a new subpopulation with id \n\\f3\\fs18 subpopID\n\\f4\\fs20  and \n\\f3\\fs18 size\n\\f4\\fs20  individuals derived from subpopulation \n\\f3\\fs18 sourceSubpop\n\\f4\\fs20 .  The \n\\f3\\fs18 subpopID\n\\f4\\fs20  parameter may be either an \n\\f3\\fs18 integer\n\\f4\\fs20  giving the ID of the new subpopulation, or a \n\\f3\\fs18 string\n\\f4\\fs20  giving the name of the new subpopulation (such as \n\\f3\\fs18 \"p5\"\n\\f4\\fs20  to specify an ID of 5).  The \n\\f3\\fs18 sourceSubpop\n\\f4\\fs20  parameter may specify the source subpopulation either as a \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  object or by \n\\f3\\fs18 integer\n\\f4\\fs20  identifier.  Only if sex is enabled for the species, the initial sex ratio may optionally be specified as \n\\f3\\fs18 sexRatio\n\\f4\\fs20  (as the male fraction, M:M+F); if it is not specified, a default of \n\\f3\\fs18 0.5\n\\f4\\fs20  is used.  The new subpopulation will be defined as a global variable immediately by this method, and will also be returned by this method.\\\nSubpopulations added by this method will consist of individuals that are clonal copies of individuals from the source subpopulation, randomly chosen with probabilities proportional to fitness.  The fitness of all of these initial individuals is considered to be 1.0, to avoid a doubled round of selection in the initial tick, given that fitness values were already used to choose the individuals to clone.  Once this initial set of individuals has mated to produce offspring, the model is effectively of parental individuals in the source subpopulation mating randomly according to fitness, as usual in SLiM, with juveniles migrating to the newly added subpopulation.  Effectively, then, then new subpopulation is created empty, and is filled by migrating juveniles from the source subpopulation, in accordance with SLiM\\'92s usual model of juvenile migration.\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Chromosome>)chromosomesOfType(string$\\'a0type)\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects of the chromosome type supplied in \n\\f3\\fs18 type\n\\f4\\fs20 , in the order if which they were defined.  If \n\\f3\\fs18 type\n\\f4\\fs20  does not correspond to a chromosome type accepted by \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 , an error will be raised.  See also \n\\f3\\fs18 chromosomesWithIDs()\n\\f4\\fs20  and \n\\f3\\fs18 chromosomesWithSymbols()\n\\f4\\fs20 .\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Chromosome>)chromosomesWithIDs(integer\\'a0ids)\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects corresponding to the chromosome ids supplied in \n\\f3\\fs18 ids\n\\f4\\fs20 , in the same order.  If any chromosome id in \n\\f3\\fs18 ids\n\\f4\\fs20  does not correspond to a chromosome in the target species, an error will be raised.  See also \n\\f3\\fs18 chromosomesOfType()\n\\f4\\fs20  and \n\\f3\\fs18 chromosomesWithSymbols()\n\\f4\\fs20 .\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Chromosome>)chromosomesWithSymbols(string\\'a0symbols)\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects corresponding to the chromosome symbols supplied in \n\\f3\\fs18 symbols\n\\f4\\fs20 , in the same order.  If any chromosome symbol in \n\\f3\\fs18 symbols\n\\f4\\fs20  does not correspond to a chromosome in the target species, an error will be raised.  See also \n\\f3\\fs18 chromosomesOfType()\n\\f4\\fs20  and \n\\f3\\fs18 chromosomesWithIDs()\n\\f4\\fs20 .\\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0\\cf0 (integer$)countOfMutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns the number of mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations that are currently active in the species.  If you need a vector of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than just a count, use \n\\f3\\fs18 -mutationsOfType()\n\\f5\\fs20 .\n\\f4   This method is often used to determine whether an introduced mutation is still active (as opposed to being either lost or fixed).  This method is provided for speed; it is much faster than the corresponding Eidos code.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)individualsWithPedigreeIDs(integer\\'a0pedigreeIDs, [Nio<Subpopulation>\\'a0subpops\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Looks up individuals by pedigree ID, optionally within specific subpopulations.  Pedigree tracking must be turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20  to use this method, otherwise an error will result.  This method is vectorized; more than one pedigree id may be passed in \n\\f3\\fs18 pedigreeID\n\\f4\\fs20 , in which case the returned vector will contain all of the individuals for which a match was found (in the same order in which they were supplied).  If a given id is not found, the returned vector will contain no entry for that id (so the length of the returned vector may not match the length of \n\\f3\\fs18 pedigreeIDs\n\\f4\\fs20 ).  If none of the given ids were found, the returned vector will be \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20 , an empty \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 .  If you have more than one pedigree ID to look up, calling this method just once, in vectorized fashion, may be much faster than calling it once for each ID, due to internal optimizations.\\\nTo find individuals within all subpopulations, pass the default of \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 subpops\n\\f4\\fs20 .  If you are interested only in matches within a specific subpopulation, pass that subpopulation for \n\\f3\\fs18 subpops\n\\f4\\fs20 ; that will make the search faster.  Similarly, if you know that a particular subpopulation is the most likely to contain matches, you should supply that subpopulation first in the \n\\f3\\fs18 subpops\n\\f4\\fs20  vector so that it will be searched first; the supplied subpopulations are searched in order.  Subpopulations may be supplied either as \n\\f3\\fs18 integer\n\\f4\\fs20  IDs, or as \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)killIndividuals(object<Individual>\\'a0individuals)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Immediately kills the individuals in \n\\f3\\fs18 individuals\n\\f4\\fs20 .  This removes them from their subpopulation and gives them an \n\\f3\\fs18 index\n\\f4\\fs20  value of \n\\f3\\fs18 -1\n\\f4\\fs20 .  The \n\\f3\\fs18 Individual\n\\f4\\fs20  objects are not freed immediately, since references to them could still exist in local Eidos variables; instead, the individuals are kept in a temporary \\'93graveyard\\'94 until they can be freed safely.  It therefore continues to be safe to use them and their haplosomes, except that accessing their \n\\f3\\fs18 subpopulation\n\\f4\\fs20  property will raise an error since they no longer have a subpopulation.\\\nNote that the indices and order of individuals and haplosomes in all source subpopulations will change unpredictably as a side effect of this method.  All evaluated interactions are invalidated as a side effect of calling this method.\\\nNote that this method is only for use in nonWF models, in which mortality is managed manually by the model script.  In WF models, mortality is managed automatically by the SLiM core when the new offspring generation becomes the parental generation and the previous parental generation dies; mortality does not otherwise occur in WF models.  In nonWF models, mortality normally occurs during the survival stage of the tick cycle, based upon the fitness values calculated by SLiM, and \n\\f3\\fs18 survival()\n\\f4\\fs20  callbacks can influence the outcome of that survival stage.  Calls to \n\\f3\\fs18 killIndividuals()\n\\f4\\fs20 , on the other hand, can be made at any time during \n\\f3\\fs18 first()\n\\f4\\fs20 , \n\\f3\\fs18 early()\n\\f4\\fs20 , or \n\\f3\\fs18 late()\n\\f4\\fs20  events, and the result cannot be modified by \n\\f3\\fs18 survival()\n\\f4\\fs20  callbacks; the given individuals are simply immediately killed.  This method therefore provides an alternative, and relatively rarely used, mortality mechanism that is disconnected from fitness.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(integer)mutationCounts(Nio<Subpopulation>\\'a0subpops, [No<Mutation>\\'a0mutations\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Return an \n\\f3\\fs18 integer\n\\f4\\fs20  vector with the frequency counts of all of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects passed in \n\\f3\\fs18 mutations\n\\f4\\fs20 , within the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects in \n\\f3\\fs18 subpops\n\\f4\\fs20 .  The \n\\f3\\fs18 subpops\n\\f4\\fs20  argument is required, but you may pass \n\\f3\\fs18 NULL\n\\f4\\fs20  to get population-wide frequency counts.\\cf2   Subpopulations may be supplied either as \n\\f3\\fs18 integer\n\\f4\\fs20  IDs, or as \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects.\\cf0   If the optional \n\\f3\\fs18 mutations\n\\f4\\fs20  argument is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), frequency counts will be returned for all of the active \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects in the species \\'96 the same \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, and in the same order, as would be returned by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of \n\\f3\\fs18 sim\n\\f4\\fs20 , in other words.\\\nSee the \n\\f3\\fs18 -mutationFrequencies()\n\\f4\\fs20  method to obtain \n\\f3\\fs18 float\n\\f4\\fs20  frequencies instead of \n\\f3\\fs18 integer\n\\f4\\fs20  counts.\\cf2   See also the \n\\f3\\fs18 \\cf0 Haplosome\n\\f4\\fs20 \\cf2  methods \n\\f3\\fs18 mutationCountsIn\\cf0 Haplosome\\cf2 s()\n\\f4\\fs20  and \n\\f3\\fs18 mutationFrequenciesIn\\cf0 Haplosome\\cf2 s()\n\\f4\\fs20 .\n\\f5 \\cf0 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(float)mutationFrequencies(Nio<Subpopulation>\\'a0subpops, [No<Mutation>\\'a0mutations\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Return a \n\\f3\\fs18 float\n\\f4\\fs20  vector with the frequencies of all of the \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects passed in \n\\f3\\fs18 mutations\n\\f4\\fs20 , within the \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects in \n\\f3\\fs18 subpops\n\\f4\\fs20 .  The \n\\f3\\fs18 subpops\n\\f4\\fs20  argument is required, but you may pass \n\\f3\\fs18 NULL\n\\f4\\fs20  to get population-wide frequencies.\\cf2   Subpopulations may be supplied either as \n\\f3\\fs18 integer\n\\f4\\fs20  IDs, or as \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects.\\cf0   If the optional \n\\f3\\fs18 mutations\n\\f4\\fs20  argument is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), frequencies will be returned for all of the active \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects in the species \\'96 the same \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, and in the same order, as would be returned by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of \n\\f3\\fs18 sim\n\\f4\\fs20 , in other words.\n\\f5 \\\n\n\\f4 See the \n\\f3\\fs18 -mutationCounts()\n\\f4\\fs20  method to obtain \n\\f3\\fs18 integer\n\\f4\\fs20  counts instead of \n\\f3\\fs18 float\n\\f4\\fs20  frequencies.\\cf2   See also the \n\\f3\\fs18 \\cf0 Haplosome\n\\f4\\fs20 \\cf2  methods \n\\f3\\fs18 mutationCountsIn\\cf0 Haplosome\\cf2 s()\n\\f4\\fs20  and \n\\f3\\fs18 mutationFrequenciesIn\\cf0 Haplosome\\cf2 s()\n\\f4\\fs20 .\n\\f5 \\cf0 \\\n\\pard\\pardeftab529\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (object<Mutation>)mutationsOfType(io<MutationType>$\\'a0mutType)\n\\f5 \\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Returns an \n\\f3\\fs18 object\n\\f4\\fs20  vector of all the mutations that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the mutations that are currently active in the species.  If you just need a count of the matching \n\\f3\\fs18 Mutation\n\\f4\\fs20  objects, rather than a vector of the matches, use \n\\f3\\fs18 -countOfMutationsOfType()\n\\f5\\fs20 .\n\\f4   This method is often used to look up an introduced mutation at a later point in the simulation, since there is no way to keep persistent references to objects in SLiM.  This method is provided for speed; it is much faster than the corresponding Eidos code.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)outputFixedMutations([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F]\\cf2 , [logical$\\'a0objectTags\\'a0=\\'a0F]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Output all fixed mutations \\'96 all \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects, in other words \\'96 in a SLiM native format.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f5\\fs20 .\n\\f4   Mutations which have fixed but have not been turned into \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects \\'96 typically because \n\\f3\\fs18 convertToSubstitution\n\\f4\\fs20  has been set to \n\\f3\\fs18 F\n\\f4\\fs20  for their mutation type \\'96 are not output; they are still considered to be segregating mutations by SLiM.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn SLiM 3.3 and later, the output format includes the nucleotides associated with any nucleotide-based mutations.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 In SLiM 5.0 and later, in models with multiple chromosome the output includes the symbol of the chromosome associated with each mutation.\\\nBeginning with SLiM 5.0, the \n\\f3\\fs18 objectTags\n\\f4\\fs20  parameter may be used to request that tag values for substitutions be written out.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)outputFull([Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0binary\\'a0=\\'a0F], [logical$\\'a0append\\'a0=\\'a0F], [logical$\\'a0spatialPositions\\'a0=\\'a0T]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [logical$\\'a0ages\\'a0=\\'a0T], [logical$\\'a0ancestralNucleotides\\'a0=\\'a0T]\\kerning1\\expnd0\\expndtw0 , [logical$\\'a0pedigreeIDs\\'a0=\\'a0F], [logical$\\'a0objectTags\\'a0=\\'a0F], [logical$\\'a0substitutions\\'a0=\\'a0F]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Output the state of the entire population.  If the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f5\\fs20 .\n\\f4   When writing to a file, a \n\\f3\\fs18 logical\n\\f4\\fs20  flag, \n\\f3\\fs18 binary\n\\f4\\fs20 , may be supplied as well.  If \n\\f3\\fs18 binary\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , the population state will be written as a binary file instead of a text file (binary data cannot be written to the standard output stream).  The binary file is usually smaller, and in any case will be read much faster than the corresponding text file would be read.  Binary files are not guaranteed to be portable between platforms; in other words, a binary file written on one machine may not be readable on a different machine (but in practice it usually will be, unless the platforms being used are fairly unusual).  If \n\\f3\\fs18 binary\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), a text file will be written.\\\nBeginning with SLiM 2.3, the \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  parameter may be used to control the output of the spatial positions of individuals in species for which continuous space has been enabled using the \n\\f3\\fs18 dimensionality\n\\f4\\fs20  option of \n\\f3\\fs18 initializeSLiMOptions()\n\\f5\\fs20 .\n\\f4   If \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain spatial positions, and will be identical to the output generated by SLiM 2.1 and later.  If \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , spatial position information will be output if it is available.  If the species does not have continuous space enabled, the \n\\f3\\fs18 spatialPositions\n\\f4\\fs20  parameter will be ignored.  Positional information may be output for all output destinations \\'96 the Eidos output stream, a text file, or a binary file.\n\\f5 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4 \\cf2 \\expnd0\\expndtw0\\kerning0\nBeginning with SLiM 3.0, the \n\\f3\\fs18 ages\n\\f4\\fs20  parameter may be used to control the output of the ages of individuals in nonWF simulations.  If \n\\f3\\fs18 ages\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain ages, preserving backward compatibility with the output format of SLiM 2.1 and later.  If \n\\f3\\fs18 ages\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , ages will be output for nonWF models.  In WF simulations, the \n\\f3\\fs18 ages\n\\f4\\fs20  parameter will be ignored.\\\nBeginning with SLiM 3.3, the \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  parameter may be used to control the output of the ancestral nucleotide sequence in nucleotide-based models.  If \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the output will not contain ancestral nucleotide information, and so the ancestral sequence will not be restored correctly if the saved file is loaded with \n\\f3\\fs18 readPopulationFile()\n\\f4\\fs20 .  This option is provided because the ancestral sequence may be quite large, for models with a long chromosome (e.g., 1 GB if the chromosome is 10\n\\fs13\\fsmilli6667 \\super 9\n\\fs20 \\nosupersub  bases long, when saved in text format, or 0.25 GB when saved in binary format).  If the model is not nucleotide-based (as enabled with the \n\\f3\\fs18 nucleotideBased\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ), the \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  parameter will be ignored.  Note that in nucleotide-based models the output format will \n\\f1\\i always\n\\f4\\i0  include the nucleotides associated with any nucleotide-based mutations; the \n\\f3\\fs18 ancestralNucleotides\n\\f4\\fs20  flag governs only the ancestral sequence.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 Beginning with SLiM 3.5, the \n\\f3\\fs18 pedigreeIDs\n\\f4\\fs20  parameter may be used to request that pedigree IDs be written out (and read in by \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 , subsequently).  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity.  This option may only be used if SLiM\\'92s optional pedigree tracking has been enabled with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 .\\\nBeginning with SLiM 5.0, the \n\\f3\\fs18 objectTags\n\\f4\\fs20  parameter may be used to request that tag values for objects be written out.  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity; if it turned on (\n\\f3\\fs18 T\n\\f4\\fs20 ), the values of all tags for all objects of supported classes (\n\\f3\\fs18 Chromosome\n\\f4\\fs20 , \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , \n\\f3\\fs18 Individual\n\\f4\\fs20 , \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , \n\\f3\\fs18 Mutation\n\\f4\\fs20 , \n\\f3\\fs18 Substitution\n\\f4\\fs20 ) will be written.  For individuals, the \n\\f3\\fs18 tag\n\\f4\\fs20 , \n\\f3\\fs18 tagF\n\\f4\\fs20 , \n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20  properties will be written; for chromosomes, subpopulations, haplosomes, and mutations, the \n\\f3\\fs18 tag\n\\f4\\fs20  property will be written.  The saved tag information can be read in by \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 , but only if the output is in binary format (\n\\f3\\fs18 binary=T\n\\f4\\fs20 ).  Note that if there is other state that you wish you persist, such as tags on objects of other classes, values attached to objects with \n\\f3\\fs18 setValue()\n\\f4\\fs20 , and so forth, you should persist that state in separate files using calls such as \n\\f3\\fs18 writeFile()\n\\f4\\fs20 .\\\nBeginning with SLiM 5.0, the \n\\f3\\fs18 substitutions\n\\f4\\fs20  parameter may be used to request that information about \n\\f3\\fs18 Substitution\n\\f4\\fs20  objects in the simulation be written out.  This option is turned off (\n\\f3\\fs18 F\n\\f4\\fs20 ) by default, for brevity.  The saved substitution information can be read in by \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 , but only if the output is in binary format (\n\\f3\\fs18 binary=T\n\\f4\\fs20 ).\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)outputMutations(object<Mutation>\\'a0mutations, [Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F]\\cf2 , [logical$\\'a0objectTags\\'a0=\\'a0F]\\cf0 )\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Output all of the given mutations.  This can be used to output all mutations of a given mutation type, for example.  \\cf2 \\expnd0\\expndtw0\\kerning0\nIf the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\n\\f5 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4 \\cf2 \\expnd0\\expndtw0\\kerning0\nIn SLiM 3.3 and later, the output format includes the nucleotides associated with any nucleotide-based mutations.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 In SLiM 5 and later, in models with multiple chromosome the output includes the symbol of the chromosome associated with each mutation.\\\nBeginning with SLiM 5.0, the \n\\f3\\fs18 objectTags\n\\f4\\fs20  parameter may be used to request that tag values for mutations be written out.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(integer$)readFromPopulationFile(string$\\'a0filePath\\cf2 , [No<Dictionary>$\\'a0subpopMap\\'a0=\\'a0NULL]\\cf0 )\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Read from a population file, whether in text or binary format as previously specified to \n\\f3\\fs18 outputFull()\n\\f4\\fs20 , and return the tick counter value represented by the file\\'92s contents (i.e., the tick at which the file was generated).  Although this is most commonly used to set up initial populations (often in an Eidos event set to run in tick \n\\f3\\fs18 1\n\\f4\\fs20 , immediately after simulation initialization), it may be called in any \n\\f3\\fs18 early()\n\\f4\\fs20  or \n\\f3\\fs18 late()\n\\f4\\fs20  event; the current state of all populations in the target species will be wiped and replaced by the state in the file at \n\\f3\\fs18 filePath\n\\f4\\fs20 .  All Eidos variables that are of type \n\\f3\\fs18 object\n\\f4\\fs20  and have element class \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , \n\\f3\\fs18 Mutation\n\\f4\\fs20 , \n\\f3\\fs18 Individual\n\\f4\\fs20 , or \n\\f3\\fs18 Substitution\n\\f4\\fs20  will be removed as a side effect of this method if they contain any element that belongs to the target species, because those objects will no longer exist in the SLiM simulation; if you want to preserve any of that state, you should output it or save it to a file prior to this call.  New symbols (\n\\f3\\fs18 p1\n\\f4\\fs20 , \n\\f3\\fs18 p2\n\\f4\\fs20 , etc.) will be defined to refer to the new \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  objects loaded from the file.  Note that fitness values are not calculated as a side effect of this call (because the simulation will often need to evaluate interactions or modify other state prior to doing so).\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIn SLiM 2.3 and later when using the WF model, calling \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20  from any context other than a \n\\f3\\fs18 late()\n\\f4\\fs20  event causes a warning; calling from a \n\\f3\\fs18 late()\n\\f4\\fs20  event is almost always correct in WF models, so that fitness values can be automatically recalculated by SLiM at the usual time in the tick cycle without the need to force their recalculation (see comments on \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20 ).\\\nIn SLiM 3.0 when using the nonWF model, calling \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20  from any context other than an \n\\f3\\fs18 early()\n\\f4\\fs20  event causes a warning; calling from an \n\\f3\\fs18 early()\n\\f4\\fs20  event is almost always correct in nonWF models, so that fitness values can be automatically recalculated by SLiM at the usual time in the tick cycle without the need to force their recalculation (see comments on \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20 ).\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 This method changes the tick and cycle counters to the tick and cycle read from the file.  If you do not want these counters to be changed, you can change them back after reading, by setting \n\\f3\\fs18 community.tick\n\\f4\\fs20  and \n\\f3\\fs18 sim.cycle\n\\f4\\fs20  to whatever values you wish.  Note that restoring a saved past state and running forward again will not yield the same simulation results, because the random number generator\\'92s state will not be the same; if you wish to ensure reproducibility from a given time point, \n\\f3\\fs18 setSeed()\n\\f4\\fs20  can be used to establish a new seed value.\\\nAny changes made to the structure of the species (mutation types, genomic element types, etc.) will not be wiped and re-established by \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 ; this method loads only the population\\'92s state, not the species configuration, so care should be taken to ensure that the species structure meshes coherently with the loaded data.  Indeed, state such as the selfing and cloning rates of subpopulations, and values set onto objects with \n\\f3\\fs18 setValue()\n\\f4\\fs20 , will also be lost, since it is not saved out by \n\\f3\\fs18 outputFull()\n\\f4\\fs20 .  Only information saved by \n\\f3\\fs18 outputFull()\n\\f4\\fs20  will be restored; all other state associated with the mutations, haplosomes, individuals, and subpopulations in the simulation will be lost, and should be re-established by the model if it is still needed.  Note that some state is saved by \n\\f3\\fs18 outputFull()\n\\f4\\fs20  only optionally, such as the \n\\f3\\fs18 tag\n\\f4\\fs20  values of individuals; if a given option is enabled and the corresponding information is saved, then that information will be restored, otherwise it will not be.\\\nAs of SLiM 2.3, this method will read and restore the spatial positions of individuals if that information is present in the output file and the species has enabled continuous space.  If spatial positions are present in the output file but the species has not enabled continuous space (or the number of spatial dimensions does not match), an error will result.  If the species has enabled continuous space but spatial positions are not present in the output file, the spatial positions of the individuals read will be undefined, but an error is not raised.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nAs of SLiM 3.0, this method will read and restore the ages of individuals if that information is present in the output file and the simulation is based upon the nonWF model.  If ages are present but the simulation uses a WF model, an error will result; the WF model does not use age information.  If ages are not present but the simulation uses a nonWF model, an error will also result; the nonWF model requires age information.\\\nAs of SLiM 3.3, this method will restore the nucleotides of nucleotide-based mutations, and will restore the ancestral nucleotide sequence, if that information is present in the output file.  Loading an output file that contains nucleotide information in a non-nucleotide-based model, and \n\\f1\\i vice versa\n\\f4\\i0 , will produce an error.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 As of SLiM 3.5, this method will read and restore the pedigree IDs of individuals and haplosomes if that information is present in the output file (as requested with \n\\f3\\fs18 outputFull(pedigreeIDs=T)\n\\f4\\fs20 ) \n\\f1\\i and\n\\f4\\i0  if SLiM\\'92s optional pedigree tracking has been enabled with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 .\\\nAs of SLiM 5.0, this method will read and restore tag values for objects of supported classes (\n\\f3\\fs18 Chromosome\n\\f4\\fs20 , \n\\f3\\fs18 Subpopulation\n\\f4\\fs20 , \n\\f3\\fs18 Individual\n\\f4\\fs20 , \n\\f3\\fs18 Haplosome\n\\f4\\fs20 , \n\\f3\\fs18 Mutation\n\\f4\\fs20 , \n\\f3\\fs18 Substitution\n\\f4\\fs20 ) if they were saved by \n\\f3\\fs18 outputFull()\n\\f4\\fs20  with its \n\\f3\\fs18 objectTags=T\n\\f4\\fs20  option.  This facility is only available when reading binary output from \n\\f3\\fs18 outputFull()\n\\f4\\fs20 , as chosen by its \n\\f3\\fs18 binary=T\n\\f4\\fs20  option; otherwise, an error will result.\\\nAs of SLiM 5.0, this method will read and restore substitutions if they were saved by \n\\f3\\fs18 outputFull()\n\\f4\\fs20  with its \n\\f3\\fs18 substitutions=T\n\\f4\\fs20  option.  This facility is only available when reading binary output from \n\\f3\\fs18 outputFull()\n\\f4\\fs20 , as chosen by its \n\\f3\\fs18 binary=T\n\\f4\\fs20  option; otherwise, an error will result.\\\nThis method can also be used to read tree-sequence information, in the form of single-chromosome \n\\f3\\fs18 .trees\n\\f4\\fs20  files and multi-chromosome trees archives, as saved by \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20  or generated by the Python \n\\f3\\fs18 pyslim\n\\f4\\fs20  package.  Note that the user metadata for a tree-sequence file can be read separately with the \n\\f3\\fs18 treeSeqMetadata()\n\\f4\\fs20  function.  Beginning with SLiM 4, the \n\\f3\\fs18 subpopMap\n\\f4\\fs20  parameter may be supplied to re-order the populations of the input tree sequence when it is loaded in to SLiM.  This parameter must have a value that is a \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ; the keys of this dictionary should be SLiM population identifiers as \n\\f3\\fs18 string\n\\f4\\fs20  values (e.g., \n\\f3\\fs18 \"p2\"\n\\f4\\fs20 ), and the values should be indexes of populations in the input tree sequence; a key/value pair of \n\\f3\\fs18 \"p2\", 4\n\\f4\\fs20  would mean that the fifth population in the input (the one at zero-based index \n\\f3\\fs18 4\n\\f4\\fs20 ) should become \n\\f3\\fs18 p2\n\\f4\\fs20  on loading into SLiM.  If \n\\f3\\fs18 subpopMap\n\\f4\\fs20  is non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , \n\\f1\\i all\n\\f4\\i0  populations in the tree sequence must be explicitly mapped, even if their index will not change and even if they will not be used by SLiM; the only exception is for unused slots in the population table, which can be explicitly remapped but do not have to be.  For instance, suppose we have a tree sequence in which population \n\\f3\\fs18 0\n\\f4\\fs20  is unused, population \n\\f3\\fs18 1\n\\f4\\fs20  is not a SLiM population (for example, an ancestral population produced by \n\\f3\\fs18 msprime\n\\f4\\fs20 ), and population 2 is a SLiM population, and we want to load this in with population 2 as \n\\f3\\fs18 p0\n\\f4\\fs20  in SLiM.  To do this, we could supply a value of \n\\f3\\fs18 Dictionary(\"p0\", 2, \"p1\", 1, \"p2\", 0)\n\\f4\\fs20  for \n\\f3\\fs18 subpopMap\n\\f4\\fs20 , or we could leave out slot \n\\f3\\fs18 0\n\\f4\\fs20  since it is unused, with \n\\f3\\fs18 Dictionary(\"p0\", 2, \"p1\", 1)\n\\f4\\fs20 .  Although this facility cannot be used to remove populations in the tree sequence, note that it may \n\\f1\\i add\n\\f4\\i0  populations that will be visible when \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20  is called (although these will not be SLiM populations); if, in this example, we had used \n\\f3\\fs18 Dictionary(\"p0\", 0, \"p1\", 1, \"p5\", 2)\n\\f4\\fs20  and then we wrote the result out with \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20 , the resulting tree sequence would have six populations, although three of them would be empty and would not be used by SLiM.  The use of \n\\f3\\fs18 subpopMap\n\\f4\\fs20  makes it easier to load simulation data that was generated in Python, since that typically uses an id of \n\\f3\\fs18 0\n\\f4\\fs20 .  The \n\\f3\\fs18 subpopMap\n\\f4\\fs20  parameter may not be used with file formats other than tree-sequence files, at the present time; setting up the correct subpopulation ids is typically easier when working with those other formats.  Note the \n\\f3\\fs18 tskit\n\\f4\\fs20  command-line interface can be used, like \n\\f3\\fs18 python3 -m tskit populations file.trees\n\\f4\\fs20 , to find out the number of subpopulations in a tree-sequence file and their IDs.\\\nWhen loading a tree sequence, a crosscheck of the loaded data will be performed to ensure that the tree sequence was well-formed and was loaded correctly.  When running a Release build of SLiM, however, this crosscheck will only occur the first time that \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20  is called to load a tree sequence; subsequent calls will not perform this crosscheck, for greater speed when running models that load saved population state many times (such as models that are conditional on fixation).  If you suspect that a tree sequence file might be corrupted, or might be read incorrectly, running a Debug build of SLiM enables crosschecks after every load.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)recalculateFitness([Ni$\\'a0tick\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Force an immediate recalculation of fitness values for all individuals in all subpopulations.  Normally fitness values are calculated at a fixed point in each tick, and those values are cached and used until the next recalculation.  If simulation parameters are changed in script in a way that affects fitness calculations, and if you wish those changes to take effect immediately rather than taking effect at the next automatic recalculation, you may call \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  to force an immediate recalculation and recache.\\\nThe optional parameter \n\\f3\\fs18 tick\n\\f4\\fs20  provides the tick for which \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  and \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callbacks should be selected; if it is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), the current tick value for the simulation, \n\\f3\\fs18 community.tick\n\\f4\\fs20 , is used.  If you call \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  in an \n\\f3\\fs18 early()\n\\f4\\fs20  event in a WF model, you may wish this to be \n\\f3\\fs18 community.tick - 1\n\\f4\\fs20  in order to utilize the \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  and \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callbacks for the previous tick, as if the changes that you have made to fitness-influencing parameters were already in effect at the end of the previous tick when the new generation was first created and evaluated (usually it is simpler to just make such changes in a \n\\f3\\fs18 late()\n\\f4\\fs20  event instead, however, in which case calling \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  is probably not necessary at all since fitness values will be recalculated immediately afterwards).  Regardless of the value supplied for \n\\f3\\fs18 tick\n\\f4\\fs20  here, \n\\f3\\fs18 community.tick\n\\f4\\fs20  inside callbacks will report the true tick number, so if your callbacks consult that parameter in order to create tick-specific fitness effects you will need to handle the discrepancy somehow.  (Similar considerations apply for nonWF models that call \n\\f3\\fs18 recalculateFitness()\n\\f4\\fs20  in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, which is also not advisable in general.)\\\nAfter this call, the fitness values used for all purposes in SLiM will be the newly calculated values.  Calling this method will trigger the calling of any enabled and applicable \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  and \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callbacks, so this is quite a heavyweight operation; you should think carefully about what side effects might result (which is why fitness recalculation does not just occur automatically after changes that might affect fitness values).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerFitnessEffectCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callback in the current simulation (specific to the target species), with an optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations), and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerMateChoiceCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 mateChoice()\n\\f4\\fs20  callback in the current simulation\\cf2  (specific to the target species)\\cf0 , with optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations) and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerModifyChildCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback in the current simulation\\cf2  (specific to the target species)\\cf0 , with optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations) and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(object<SLiMEidosBlock>$)registerMutationCallback(Nis$\\'a0id, string$\\'a0source, [Nio<MutationType>$\\'a0mutType\\'a0=\\'a0NULL], [Nio<Subpopulation>$\\'a0subpop\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 mutation()\n\\f4\\fs20  callback in the current simulation\\kerning1\\expnd0\\expndtw0  (specific to the target species)\\expnd0\\expndtw0\\kerning0\n, with an optional mutation type \n\\f3\\fs18 mutType\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  mutation type identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all mutation types), optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may also be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations), and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(object<SLiMEidosBlock>$)registerMutationEffectCallback(Nis$\\'a0id, string$\\'a0source, io<MutationType>$\\'a0mutType, [Nio<Subpopulation>$\\'a0subpop\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  callback in the current simulation (specific to the target species), with a required mutation type \n\\f3\\fs18 mutType\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  mutation type identifier), optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may also be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations), and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerRecombinationCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL]\\cf2 , [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL]\\cf0 , [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 recombination()\n\\f4\\fs20  callback in the current simulation (specific to the target species), with optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations) and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  In multi-chromosome models, parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a chromosome to which the callback will apply (as either an \n\\f3\\fs18 integer\n\\f4\\fs20  id, a \n\\f3\\fs18 string\n\\f4\\fs20  symbol, or a \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object); otherwise, \n\\f3\\fs18 NULL\n\\f4\\fs20  indicates that the callback applies to all chromosomes.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(object<SLiMEidosBlock>$)registerReproductionCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL], \\cf2 \\expnd0\\expndtw0\\kerning0\n[Ns$\\'a0sex\\'a0=\\'a0NULL], \\cf0 \\kerning1\\expnd0\\expndtw0 [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nRegister a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 reproduction()\n\\f4\\fs20  callback in the current simulation\\kerning1\\expnd0\\expndtw0  (specific to the target species)\\expnd0\\expndtw0\\kerning0\n, with optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations), optional sex-specificity \n\\f3\\fs18 sex\n\\f4\\fs20  (which may be \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  in sexual species to make the callback specific to males or females respectively, or \n\\f3\\fs18 NULL\n\\f4\\fs20  for no sex-specificity), and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(object<SLiMEidosBlock>$)registerSurvivalCallback(Nis$\\'a0id, string$\\'a0source, [Nio<Subpopulation>$\\'a0subpop\n\\f5 \\'a0\n\\f3 =\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Register a block of Eidos source code, represented as the \n\\f3\\fs18 string\n\\f4\\fs20  singleton \n\\f3\\fs18 source\n\\f4\\fs20 , as an Eidos \n\\f3\\fs18 survival()\n\\f4\\fs20  callback in the current simulation\\cf2  (specific to the target species)\\cf0 , with optional subpopulation \n\\f3\\fs18 subpop\n\\f4\\fs20  (which may be an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier, or \n\\f3\\fs18 NULL\n\\f4\\fs20 , the default, to indicate all subpopulations) and optional \n\\f3\\fs18 start\n\\f4\\fs20  and \n\\f3\\fs18 end\n\\f4\\fs20  ticks all limiting its applicability.  The script block will be given identifier \n\\f3\\fs18 id\n\\f4\\fs20  (specified as an \n\\f3\\fs18 integer\n\\f4\\fs20 , or as a \n\\f3\\fs18 string\n\\f4\\fs20  symbolic name such as \n\\f3\\fs18 \"s5\"\n\\f4\\fs20 ); this may be \n\\f3\\fs18 NULL\n\\f4\\fs20  if there is no need to be able to refer to the block later.  The registered callback is added to the end of the list of registered \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  objects, and is active immediately; it \n\\f1\\i may\n\\f4\\i0  be eligible to execute in the current tick.  The new \n\\f3\\fs18 SLiMEidosBlock\n\\f4\\fs20  will be defined as a global variable immediately by this method, and will also be returned by this method.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)simulationFinished(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Declare the current simulation finished.  This method is equivalent to the \n\\f3\\fs18 Community\n\\f4\\fs20  method \n\\f3\\fs18 simulationFinished()\n\\f4\\fs20 , except that this method is only legal to call in single-species models (to provide backward compatibility).  It is recommended that new code should call the \n\\f3\\fs18 Community\n\\f4\\fs20  method; this method may be deprecated in the future.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)skipTick(void)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Deactivate the target species for the current tick.  This sets the \n\\f3\\fs18 active\n\\f4\\fs20  property of the species to \n\\f3\\fs18 F\n\\f4\\fs20 ; it also set the \n\\f3\\fs18 active\n\\f4\\fs20  property of all callbacks that belong to the species (with the species as their \n\\f3\\fs18 species\n\\f4\\fs20  specifier) to \n\\f3\\fs18 F\n\\f4\\fs20 , and sets the active property of all events that are synchronized with the species (with the species as their \n\\f3\\fs18 ticks\n\\f4\\fs20  specifier) to \n\\f3\\fs18 F\n\\f4\\fs20 .  The cycle counter for the species will not be incremented at the end of the tick.  This method may only be called in \n\\f3\\fs18 first()\n\\f4\\fs20  events, to ensure that species are either active or inactive throughout a given tick.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Mutation>)subsetMutations([No<Mutation>$\\'a0exclude\\'a0=\\'a0NULL], [Nio<MutationType>$\\'a0mutType\\'a0=\\'a0NULL], [Ni$\\'a0position\\'a0=\\'a0NULL], [Nis$\\'a0nucleotide\\'a0=\\'a0NULL], [Ni$\\'a0tag\\'a0=\\'a0NULL], [Ni$\\'a0id\\'a0=\\'a0NULL], [Niso<Chromosome>\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of mutations subset from the list of all active mutations in the species (as would be provided by the \n\\f3\\fs18 mutations\n\\f4\\fs20  property).  The parameters specify constraints upon the subset of mutations that will be returned.  Parameter \n\\f3\\fs18 exclude\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a specific mutation that should not be included (typically the focal mutation in some operation).  Parameter \n\\f3\\fs18 mutType\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a mutation type for the mutations to be returned (as either a \n\\f3\\fs18 MutationType\n\\f4\\fs20  object or an \n\\f3\\fs18 integer\n\\f4\\fs20  identifier).  Parameter \n\\f3\\fs18 position\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a base position for the mutations to be returned.  Parameter \n\\f3\\fs18 nucleotide\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a nucleotide for the mutations to be returned (either as a string, \n\\f3\\fs18 \"A\"\n\\f4\\fs20  / \n\\f3\\fs18 \"C\"\n\\f4\\fs20  / \n\\f3\\fs18 \"G\"\n\\f4\\fs20  / \n\\f3\\fs18 \"T\"\n\\f4\\fs20 , or as an integer, \n\\f3\\fs18 0\n\\f4\\fs20  / \n\\f3\\fs18 1\n\\f4\\fs20  / \n\\f3\\fs18 2\n\\f4\\fs20  / \n\\f3\\fs18 3\n\\f4\\fs20  respectively).  Parameter \n\\f3\\fs18 tag\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a tag value for the mutations to be returned.  Parameter \n\\f3\\fs18 id\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a required value for the \n\\f3\\fs18 id\n\\f4\\fs20  property of the mutations to be returned.  Parameter \n\\f3\\fs18 chromosome\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a chromosome or chromosomes with which the mutations returned must be associated (as either \n\\f3\\fs18 integer\n\\f4\\fs20  ids, \n\\f3\\fs18 string\n\\f4\\fs20  symbols, or \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects).\\\nThis method is shorthand for getting the \n\\f3\\fs18 mutations\n\\f4\\fs20  property of the subpopulation, and then using operator \n\\f3\\fs18 []\n\\f4\\fs20  to select only mutations with the desired properties; besides being much simpler than the equivalent Eidos code, it is also much faster.  Note that if you only need to select on mutation type, the \n\\f3\\fs18 mutationsOfType()\n\\f4\\fs20  method will be even faster.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Substitution>)substitutionsOfType(io<MutationType>$\\'a0mutType)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns an \n\\f3\\fs18 object\n\\f4\\fs20  vector of all the substitutions that are of the type specified by \n\\f3\\fs18 mutType\n\\f4\\fs20 , out of all of the substitutions that are currently present in the species.  This method is provided for speed; it is much faster than the corresponding Eidos code.  See also \n\\f3\\fs18 mutationsOfType()\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(logical$)treeSeqCoalesced(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns the coalescence state for the recorded tree sequence at the last simplification.  The returned value is a logical singleton flag, \n\\f3\\fs18 T\n\\f4\\fs20  to indicate that full coalescence was observed at the last tree-sequence simplification (meaning that there is a single ancestral individual that roots all ancestry trees at all sites along the chromosome \\'96 although not necessarily the \n\\f1\\i same\n\\f4\\i0  ancestor at all sites), or \n\\f3\\fs18 F\n\\f4\\fs20  if full coalescence was not observed.  For simple models, reaching coalescence may indicate that the model has reached an equilibrium state, but this may not be true in models that modify the dynamics of the model during execution by changing migration rates, introducing new mutations programmatically, dictating non-random mating, etc., so be careful not to attach more meaning to coalescence than it is due; some models may require burn-in beyond coalescence to reach equilibrium, or may not have an equilibrium state at all.  Also note that some actions by a model, such as adding a new subpopulation, may cause the coalescence state to revert from \n\\f3\\fs18 T\n\\f4\\fs20  back to \n\\f3\\fs18 F\n\\f4\\fs20  (at the next simplification), so a return value of \n\\f3\\fs18 T\n\\f4\\fs20  may not necessarily mean that the model is coalesced at the present moment \\'96 only that it \n\\f1\\i was\n\\f4\\i0  coalesced at the last simplification.\\\nThis method may only be called if tree sequence recording has been turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 ; in addition, \n\\f3\\fs18 checkCoalescence=T\n\\f4\\fs20  must have been supplied to \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 , so that the necessary work is done during each tree-sequence simplification.  Since this method does not perform coalescence checking itself, but instead simply returns the coalescence state observed at the last simplification, it may be desirable to call \n\\f3\\fs18 treeSeqSimplify()\n\\f4\\fs20  immediately before \n\\f3\\fs18 treeSeqCoalesced()\n\\f4\\fs20  to obtain up-to-date information.  However, the speed penalty of doing this in every tick would be large, and most models do not need this level of precision; usually it is sufficient to know that the model has coalesced, without knowing whether that happened in the current tick or in a recent preceding tick.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)treeSeqOutput(string$\\'a0path, [logical$\\'a0simplify\\'a0=\\'a0T], [logical$\\'a0includeModel\\'a0=\\'a0T], \\kerning1\\expnd0\\expndtw0 [No<Dictionary>$\\'a0metadata\\'a0=\\'a0NULL], [logical$\\'a0overwriteDirectory\\'a0=\\'a0F]\\expnd0\\expndtw0\\kerning0\n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Outputs the current tree sequence recording tables to the path specified by \n\\f3\\fs18 path\n\\f4\\fs20 .  This method may only be called if tree sequence recording has been turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 .  If \n\\f3\\fs18 simplify\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), simplification will be done immediately prior to output; this is almost always desirable, unless a model wishes to avoid simplification entirely.  (Note that if simplification is not done, then all haplosomes since the last simplification will be marked as samples in the resulting tree sequence.)\\\nIn a model of a single chromosome, a binary tree sequence file will be written to the specified path; a filename extension of \n\\f3\\fs18 .trees\n\\f4\\fs20  is suggested for this type of file, and such a file is often referred to as a \\'93\n\\f3\\fs18 .trees\n\\f4\\fs20  file\\'94.  In a multi-chromosome model, a directory will instead be created at the specified path, and a separate \n\\f3\\fs18 .trees\n\\f4\\fs20  file will be created within that directory for each chromosome in the model, mirroring the fact that SLiM keeps a separate tree sequence for each chromosome in a multi-chromosome model.  These \n\\f3\\fs18 .trees\n\\f4\\fs20  files will be given filenames based upon the \n\\f3\\fs18 symbol\n\\f4\\fs20  property of each chromosome, as provided to \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 ; for example, the tree sequence for a chromosome with symbol \n\\f3\\fs18 \"X\"\n\\f4\\fs20  will be saved as \n\\f3\\fs18 chromosome_X.trees\n\\f4\\fs20  within the specified directory.  For the name of the directory itself, a suffix of \n\\f3\\fs18 _trees\n\\f4\\fs20  is suggested, rather than \n\\f3\\fs18 .trees\n\\f4\\fs20 , since the use of dot-extensions in directory names is not common; for example, \n\\f3\\fs18 \"model_Q_seed_17_trees\"\n\\f4\\fs20  would be a path you might pass to \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20  as a directory name in a multi-chromosome model.  Such a directory, containing separate \n\\f3\\fs18 .trees\n\\f4\\fs20  files for each chromosome, is called a \\'93trees archive\\'94.  Both \n\\f3\\fs18 .trees\n\\f4\\fs20  files and trees archives can be read by \n\\f3\\fs18 readFromPopulationFile()\n\\f4\\fs20 , as discussed in its documentation.\\\nNormally, the full SLiM script used to generate the tree sequence is written out to the provenance entry of the tree sequence file, to the \n\\f3\\fs18 model\n\\f4\\fs20  subkey of the \n\\f3\\fs18 parameters\n\\f4\\fs20  top-level key.  Supplying \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 includeModel\n\\f4\\fs20  suppresses output of the full script.\\\nA \n\\f3\\fs18 Dictionary\n\\f4\\fs20  object containing user-generated metadata may be supplied with the \n\\f3\\fs18 metadata\n\\f4\\fs20  parameter.  If present, this dictionary will be serialized as JSON and attached to the saved tree sequence under a key named \n\\f3\\fs18 user_metadata\n\\f4\\fs20 , within the \n\\f3\\fs18 SLiM\n\\f4\\fs20  key.  If \n\\f3\\fs18 tskit\n\\f4\\fs20  is used to read the tree sequence in Python, this metadata will automatically be deserialized and made available at \n\\f3\\fs18 ts.metadata[\"SLiM\"][\"user_metadata\"]\n\\f4\\fs20 .  This metadata dictionary is not used by SLiM, or by \n\\f3\\fs18 pyslim\n\\f4\\fs20 , \n\\f3\\fs18 tskit\n\\f4\\fs20 , or \n\\f3\\fs18 msprime\n\\f4\\fs20 ; you may use it for any purpose you wish.  Note that \n\\f3\\fs18 metadata\n\\f4\\fs20  may actually be any subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 , such as a \n\\f3\\fs18 DataFrame\n\\f4\\fs20 .  It can even be a \n\\f3\\fs18 Species\n\\f4\\fs20  object such as \n\\f3\\fs18 sim\n\\f4\\fs20 , or a \n\\f3\\fs18 LogFile\n\\f4\\fs20  instance; however, only the keys and values contained by the object\\'92s \n\\f3\\fs18 Dictionary\n\\f4\\fs20  superclass state will be serialized into the metadata (properties of the subclass will be ignored).  This metadata dictionary can be recovered from the saved file using the \n\\f3\\fs18 treeSeqMetadata()\n\\f4\\fs20  function.\\\nWhen saving a single \n\\f3\\fs18 .trees\n\\f4\\fs20  file, the standard behavior is to overwrite an existing file of the same name; the convenience of this generally outweighs the danger.  When saving a trees archive, however, that balance shifts; overwriting an entire directory is potentially quite dangerous.  For this reason, \n\\f3\\fs18 overwriteDirectory=F\n\\f4\\fs20  (the default) specifies that \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20  should not overwrite an existing directory; it will instead raise an error.  If \n\\f3\\fs18 overwriteDirectory\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , \n\\f3\\fs18 treeSeqOutput()\n\\f4\\fs20  will overwrite an existing directory of the same name (if the existing directory can be deleted without permissions errors and so forth), but only if the existing directory is empty or contains only files with a \n\\f3\\fs18 .trees\n\\f4\\fs20  suffix, for safety; if other files are present, an error will still be raised.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(void)treeSeqRememberIndividuals(object<Individual>\\'a0individuals\\kerning1\\expnd0\\expndtw0 , [logical$\\'a0permanent\\'a0=\\'a0T]\\expnd0\\expndtw0\\kerning0\n)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Mark the individuals specified by \n\\f3\\fs18 individuals\n\\f4\\fs20  to be kept across tree sequence table simplification.  This method may only be called if tree sequence recording has been turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 .  All currently living individuals are always kept across simplification; this method does not need to be called, and indeed should not be called, for that purpose.  Instead, \n\\f3\\fs18 treeSeqRememberIndividuals()\n\\f4\\fs20  allows any individual, including dead individuals, to be kept in the final tree sequence.  Typically this would be used, for example, to keep particular individuals that you wanted to be able to trace ancestry back to in later analysis.  However, this is not the typical usage pattern for tree sequence recording; most models will not need to call this method.\\\nThere are two ways to keep individuals across simplification.  If \n\\f3\\fs18 permanent\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), then the specified individuals will be permanently remembered: their haplosomes will be added to the current sample, and they will always be present in the tree sequence.  Permanently remembering a large number of individuals will, of course, markedly increase memory usage and runtime.\\\nSupplying \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 permanent\n\\f4\\fs20  will instead mark the individuals only for (temporary) retention: their haplosomes will not be added to the sample, and they will appear in the final tree sequence only if one of their haplosomes is retained across simplification.  In other words, the rule of thumb for retained individuals is simple: if a haplosome is kept by simplification, the haplosome\\'92s corresponding individual is kept also, \n\\f1\\i if\n\\f4\\i0  it is retained.  Note that permanent remembering takes priority; calling this function with \n\\f3\\fs18 permanent=F\n\\f4\\fs20  on an individual that has previously been permanently remembered will not remove it from the sample.\\\nThe behavior of simplification for individuals retained with \n\\f3\\fs18 permanent=F\n\\f4\\fs20  depends upon the value of the \n\\f3\\fs18 retainCoalescentOnly\n\\f4\\fs20  flag passed to \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 ; here we will discuss the behavior of that flag in detail.  First of all, haplosomes are \n\\f1\\i always\n\\f4\\i0  removed by simplification unless they are (a) part of the final generation (i.e., in a living individual when simplification occurs), (b) ancestral to the final generation, (c) a haplosome of a permanently remembered individual, or (d) ancestral to a permanently remembered individual.  If \n\\f3\\fs18 retainCoalescentOnly\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20  (the default), they are \n\\f1\\i also\n\\f4\\i0  always removed if they are not a branch point (i.e., a coalescent node or most recent common ancestor) in the tree sequence.  In some cases it may be useful to retain a haplosome and its associated individual when it is simply an intermediate node in the ancestry (i.e., in the middle of a branch).  This can be enabled by setting \n\\f3\\fs18 retainCoalescentOnly\n\\f4\\fs20  to \n\\f3\\fs18 F\n\\f4\\fs20  in your call to \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 .  In this case, ancestral haplosomes that are intermediate (\\'93unary nodes\\'94, in \n\\f3\\fs18 tskit\n\\f4\\fs20  parlance) and are within an individual that has been retained using the \n\\f3\\fs18 permanent=F\n\\f4\\fs20  flag here are kept, along with the retained individual itself.  Since setting \n\\f3\\fs18 retainCoalescentOnly\n\\f4\\fs20  to \n\\f3\\fs18 F\n\\f4\\fs20  will prevent the unary nodes for retained individuals from being pruned, simplification may often be unable to prune very much at all from the tree sequence, and memory usage and runtime may increase rapidly.  If you are retaining many individuals, this setting should therefore be used only with caution; it is not necessary if you are purely interested in the most recent common ancestors.  See the \n\\f3\\fs18 pyslim\n\\f4\\fs20  documentation for further discussion of retaining and remembering individuals and the effects of the \n\\f3\\fs18 retainCoalescentOnly\n\\f4\\fs20  flag.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThe metadata (age, location, etc) that are stored in the resulting tree sequence are those values present at either (a) the final generation, \\kerning1\\expnd0\\expndtw0 if the individual is alive when the tree sequence is output\\expnd0\\expndtw0\\kerning0\n, or (b) the last time that the individual was remembered, if not.  Calling \n\\f3\\fs18 treeSeqRememberIndividuals()\n\\f4\\fs20  on an individual that is already remembered will cause the archived information about the remembered individual to be updated to reflect the individual\\'92s current state.  A case where this is particularly important is for the spatial location of individuals in continuous-space models.  SLiM automatically remembers the individuals that comprise the first generation of any new subpopulation created with \n\\f3\\fs18 addSubpop()\n\\f4\\fs20 , for easy recapitation and other analysis.  However, since these first-generation individuals are remembered at the moment they are created, their spatial locations have not yet been set up, and will contain garbage \\'96 and those garbage values will be archived in their remembered state.  If you need correct spatial locations of first-generation individuals for your post-simulation analysis, you should call \n\\f3\\fs18 treeSeqRememberIndividuals()\n\\f4\\fs20  explicitly on the first generation, after setting spatial locations, to update the archived information with the correct spatial positions.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)treeSeqSimplify(void)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Triggers an immediate simplification of the tree sequence recording tables.  This method may only be called if tree sequence recording has been turned on with \n\\f3\\fs18 initializeTreeSeq()\n\\f4\\fs20 .  A call to this method will free up memory being used by entries that are no longer in the ancestral path of any individual within the current sample (currently living individuals, in other words, plus those explicitly added to the sample with \n\\f3\\fs18 treeSeqRememberIndividuals()\n\\f4\\fs20 ), but it can also take a significant amount of time.  Typically calling this method is not necessary; the automatic simplification performed occasionally by SLiM should be sufficient for most models.\\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 \\kerning1\\expnd0\\expndtw0 5.17  Class Subpopulation\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.17.1  \n\\f2\\fs18 Subpopulation\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf0 cloningRate => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The fraction of children in the next generation that will be produced by cloning (as opposed to biparental mating).  In non-sexual (i.e. hermaphroditic) simulations, this property is a singleton \n\\f3\\fs18 float\n\\f4\\fs20  representing the overall subpopulation cloning rate.  In sexual simulations, this property is a \n\\f3\\fs18 float\n\\f4\\fs20  vector with two values: the cloning rate for females (at index \n\\f3\\fs18 0\n\\f4\\fs20 ) and for males (at index \n\\f3\\fs18 1\n\\f4\\fs20 ).\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 description <\\'96> (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A human-readable \n\\f3\\fs18 string\n\\f4\\fs20  description for the subpopulation.  By default, this is the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 ; however, it may be set to whatever you wish.  When tree-sequence recording is enabled, \n\\f3\\fs18 description\n\\f4\\fs20  is persisted in the subpopulation\\'92s metadata in tree-sequence output.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 firstMaleIndex => (integer$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The index of the first male individual in the subpopulation.  The \n\\f3\\fs18 individuals\n\\f4\\fs20  vector of the subpopulation is sorted into females first and males second; \n\\f3\\fs18 firstMaleIndex\n\\f4\\fs20  gives the position of the boundary between those sections.  The \n\\f3\\fs18 firstMaleIndex\n\\f4\\fs20  property is also the number of females in the subpopulation, given this design.  For non-sexual (i.e. hermaphroditic) simulations, the value of this property is undefined and should not be used.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nfitnessScaling <\\'96> (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A \n\\f3\\fs18 float\n\\f4\\fs20  scaling factor applied to the fitness of all individuals in this subpopulation (i.e., the fitness value computed for each individual will be multiplied by this value).  This is primarily of use in nonWF models, where fitness is absolute, rather than in WF models, where fitness is relative (and thus a constant factor multiplied into the fitness of every individual will make no difference); however, it may be used in either type of model.  This provides a simple, fast way to modify the fitness of all individuals in a subpopulation; conceptually it is similar to returning the same fitness effect for all individuals in the subpopulation from a \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callback, but without the complexity and performance overhead of implementing such a callback.  To scale the fitness of individuals by different (individual-specific) factors, see the \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  property of \n\\f3\\fs18 Individual\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 The value of \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  is reset to \n\\f3\\fs18 1.0\n\\f4\\fs20  every tick, so that any scaling factor set lasts for only a single tick.  This reset occurs immediately after fitness values are calculated, in both WF and nonWF models.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 haplosomes => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the haplosomes contained by the subpopulation.  All of the haplosomes for the first individual in the \n\\f3\\fs18 individuals\n\\f4\\fs20  property are provided, followed by all the haplosomes for the second individual, etc., in the same order as \n\\f3\\fs18 individuals\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 haplosomesNonNull => (object<Haplosome>)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the haplosomes contained by the subpopulation, as with the \n\\f3\\fs18 haplosomes\n\\f4\\fs20  property, if all of them are not null haplosomes; any null haplosomes present are excluded from the returned vector.  This is a convenience shorthand, sometimes useful in models that involve null haplosomes.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this subpopulation; for subpopulation \n\\f3\\fs18 p3\n\\f4\\fs20 , for example, this is \n\\f3\\fs18 3\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 immigrantSubpopFractions => (float)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The expected value of the fraction of children in the next generation that are immigrants arriving from particular subpopulations.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 immigrantSubpopIDs => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifiers of the particular subpopulations from which immigrants will arrive in the next generation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 individualCount => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The number of individuals in the subpopulation.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 individuals => (object<Individual>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 All of the individuals contained by the subpopulation.  See the \n\\f3\\fs18 sampleIndividuals()\n\\f4\\fs20  and \n\\f3\\fs18 subsetIndividuals()\n\\f4\\fs20  for fast ways to get a subset of the individuals in a subpopulation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 lifetimeReproductiveOutput => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 lifetimeReproductiveOutput\n\\f4\\fs20  contains the value of the \n\\f3\\fs18 Individual\n\\f4\\fs20  property \n\\f3\\fs18 reproductiveOutput\n\\f4\\fs20  for all individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).  This allows access to the lifetime reproductive output of individuals in the subpopulation at the end of their lives.  If pedigree tracking is not on, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 lifetimeReproductiveOutputF => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 lifetimeReproductiveOutputF\n\\f4\\fs20  contains the value of the \n\\f3\\fs18 Individual\n\\f4\\fs20  property \n\\f3\\fs18 reproductiveOutput\n\\f4\\fs20  for all female individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).  This property is undefined if separate sexes have not been enabled, or if pedigree tracking is not on.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 lifetimeReproductiveOutputM => (integer)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 If pedigree tracking is turned on with \n\\f3\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f4\\fs20 , \n\\f3\\fs18 lifetimeReproductiveOutputM\n\\f4\\fs20  contains the value of the \n\\f3\\fs18 Individual\n\\f4\\fs20  property \n\\f3\\fs18 reproductiveOutput\n\\f4\\fs20  for all male individuals in the subpopulation that died in the last viability/survival tick cycle stage (or, for WF models, immediately after reproduction).  This property is undefined if separate sexes have not been enabled, or if pedigree tracking is not on.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 name <\\'96> (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A human-readable \n\\f3\\fs18 string\n\\f4\\fs20  name for the subpopulation.  By default, this is the subpopulation\\'92s symbol as a \n\\f3\\fs18 string\n\\f4\\fs20 ; for subpopulation \n\\f3\\fs18 p3\n\\f4\\fs20 , for example, \n\\f3\\fs18 name\n\\f4\\fs20  defaults to \n\\f3\\fs18 \"p3\"\n\\f4\\fs20 .  However, it may be set to whatever you wish except that subpopulation names must be unique across time (two different subpopulations may not both have the name \n\\f3\\fs18 \"foo\"\n\\f4\\fs20 , even if they never exist at the same time).  A subpopulation\\'92s \n\\f3\\fs18 name\n\\f4\\fs20  may appear as a label in SLiMgui, and it can be useful in generating output, debugging, and other purposes.  When tree-sequence recording is enabled, \n\\f3\\fs18 name\n\\f4\\fs20  is persisted in the subpopulation\\'92s metadata in tree-sequence output, and can then be used in Python to identify the subpopulation; if you plan to take advantage of that feature, \n\\f3\\fs18 name\n\\f4\\fs20  should follow the syntax of Python identifiers: starting with a letter or underscore \n\\f3\\fs18 [a-zA-Z_]\n\\f4\\fs20 , followed by letters, digits, or underscores \n\\f3\\fs18 [a-zA-Z0-9_]\n\\f4\\fs20 , without spaces, hyphens, or other characters.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 selfingRate => (float$)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The expected value of the fraction of children in the next generation that will be produced by selfing (as opposed to biparental mating).  Selfing is only possible in non-sexual (i.e. hermaphroditic) simulations; for sexual simulations this property always has a value of \n\\f3\\fs18 0.0\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 sexRatio => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 For sexual simulations, the sex ratio for the subpopulation.  This is defined, in SLiM, as the fraction of the subpopulation that is male; in other words, it is actually the M:(M+F) ratio.  For non-sexual (i.e. hermaphroditic) simulations, this property has an undefined value and should not be used.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 spatialMaps => (object<SpatialMap>)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The spatial maps that are currently added to the subpopulation.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 spatialBounds => (float)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The spatial boundaries of the subpopulation.  The length of the \n\\f3\\fs18 spatialBounds\n\\f4\\fs20  property depends upon the spatial dimensionality declared with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  If the spatial dimensionality is zero (as it is by default), the value of this property is \n\\f3\\fs18 float(0)\n\\f4\\fs20  (a zero-length \n\\f3\\fs18 float\n\\f4\\fs20  vector).  Otherwise, minimums are supplied for each coordinate used by the dimensionality of the simulation, followed by maximums for each.  In other words, if the declared dimensionality is \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 , the \n\\f3\\fs18 spatialBounds\n\\f4\\fs20  property will contain values \n\\f3\\fs18 (x0,\\'a0y0,\\'a0x1,\\'a0y1)\n\\f4\\fs20 ; bounds for the \n\\f1\\i z\n\\f4\\i0  coordinate will not be included in that case, since that coordinate is not used in the simulation\\'92s dimensionality.  This property cannot be set, but the \n\\f3\\fs18 setSpatialBounds()\n\\f4\\fs20  method may be used to achieve the same thing.\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 species => (object<Species>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe species to which the target object belongs.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is initially undefined\\cf2 \\expnd0\\expndtw0\\kerning0\n, and it is an error to try to read it\\cf0 \\kerning1\\expnd0\\expndtw0 ; if you wish it to have a defined value, you must arrange that yourself by explicitly setting its value prior to using it elsewhere in your code.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.  See also the \n\\f3\\fs18 getValue()\n\\f4\\fs20  and \n\\f3\\fs18 setValue()\n\\f4\\fs20  methods\\cf2  (provided by the \n\\f3\\fs18 Dictionary\n\\f4\\fs20  class; see the Eidos manual)\\cf0 , for another way of attaching state to subpopulations.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.17.2  \n\\f2\\fs18 Subpopulation\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(object<Individual>)addCloned(object<Individual>$\\'a0parent, [integer$\\'a0count\\'a0=\\'a01], [logical$\\'a0defer\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Generates a new offspring individual from the given parent by clonal reproduction, queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  The subpopulation of \n\\f3\\fs18 parent\n\\f4\\fs20  will be used to locate applicable \n\\f3\\fs18 mutation()\n\\f4\\fs20  and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks governing the generation of the offspring individual.\\\nBeginning in SLiM 4.1, the \n\\f3\\fs18 count\n\\f4\\fs20  parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).  Each offspring is generated independently, based upon the given parameters.  The returned vector contains all generated offspring, except those that were rejected by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback.  If all offspring are rejected, \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20  is returned, which is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 ; note that this is a change in behavior from earlier versions, which would return \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\nBeginning in SLiM 4.1, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.  SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if \n\\f3\\fs18 defer\n\\f4\\fs20  were \n\\f3\\fs18 F\n\\f4\\fs20 .  Haplosome generation can only be deferred if there are no active \n\\f3\\fs18 mutation()\n\\f4\\fs20  callbacks; otherwise, an error will result.  Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback or otherwise).  There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  is generally preferable since it has fewer restrictions.  When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).\\\nAlso beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from \n\\f3\\fs18 parent\n\\f4\\fs20 ; more specifically, the \n\\f3\\fs18 x\n\\f4\\fs20  property will be inherited in all spatial models (1D/2D/3D), the \n\\f3\\fs18 y\n\\f4\\fs20  property in 2D/3D models, and the \n\\f3\\fs18 z\n\\f4\\fs20  property in 3D models.  Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.  The parent\\'92s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  / \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 .\\\nNote that this method is only for use in nonWF models.  See \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  for further general notes on the addition of new offspring individuals.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(object<Individual>)addCrossed(object<Individual>$\\'a0parent1, object<Individual>$\\'a0parent2, [Nfs$\\'a0sex\\'a0=\\'a0NULL], [integer$\\'a0count\\'a0=\\'a01], [logical$\\'a0defer\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Generates a new offspring individual from the given parents by biparental sexual reproduction, queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  Attempting to use a newly generated offspring individual as a mate, or to reference it as a member of the target subpopulation in any other way, will result in an error.  In most models the returned individual is not used, but it is provided for maximal generality and flexibility.\\\nThe new offspring individual is generated from \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  by crossing them.  In sexual models \n\\f3\\fs18 parent1\n\\f4\\fs20  must be female and \n\\f3\\fs18 parent2\n\\f4\\fs20  must be male; in hermaphroditic models, \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  are unrestricted.  If \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  are the same individual in a hermaphroditic model, that parent self-fertilizes, or \\'93selfs\\'94, to generate the offspring sexually (note this is not the same as clonal reproduction).  Such selfing is considered \\'93incidental\\'94 by \n\\f3\\fs18 addCrossed()\n\\f4\\fs20 , however; if the \n\\f3\\fs18 preventIncidentalSelfing\n\\f4\\fs20  flag of \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , supplying the same individual for \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  is an error (you must check for and prevent incidental selfing if you set that flag in a nonWF model).  If non-incidental selfing is desired, \n\\f3\\fs18 addSelfed()\n\\f4\\fs20  should be used instead.\\\nThe \n\\f3\\fs18 sex\n\\f4\\fs20  parameter specifies the sex of the offspring.  A value of \n\\f3\\fs18 NULL\n\\f4\\fs20  means \\'93make the default choice\\'94; in non-sexual models it is the only legal value for \n\\f3\\fs18 sex\n\\f4\\fs20 , and does nothing, whereas in sexual models it causes male or female to be chosen with equal probability.  A value of \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  specifies that the offspring should be male or female, respectively.  Finally, a \n\\f3\\fs18 float\n\\f4\\fs20  value from \n\\f3\\fs18 0.0\n\\f4\\fs20  to \n\\f3\\fs18 1.0\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  provides the probability that the offspring will be male; a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  will produce a female, a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.  Unless you wish the bias the sex ratio of offspring, the default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  should generally be used.\\\nNote that any defined, active, and applicable \n\\f3\\fs18 recombination()\n\\f4\\fs20 , \n\\f3\\fs18 mutation()\n\\f4\\fs20 , and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks will be called as a side effect of calling this method, before this method even returns.  For \n\\f3\\fs18 recombination()\n\\f4\\fs20  and \n\\f3\\fs18 mutation()\n\\f4\\fs20  callbacks, the subpopulation of the parent that is generating a given gamete is used; for \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks the situation is more complex.  In most biparental mating events, \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  will belong to the same subpopulation, and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks for that subpopulation will be used, just as in WF models.  In certain models (such as models of pollen flow and broadcast spawning), however, biparental mating may occur between parents that are not from the same subpopulation; that is legal in nonWF models, and in that case, \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks for the subpopulation of \n\\f3\\fs18 parent1\n\\f4\\fs20  are used (since that is the maternal parent).\\\nIf the \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback process results in rejection of the proposed child, a new offspring individual is not generated.  To force the generation of an offspring individual from a given pair of parents, you could loop until \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  succeeds, but note that if your \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback rejects all proposed children from those particular parents, your model will then hang, so care must be taken with this approach.  Usually, nonWF models do not force generation of offspring in this manner; rejection of a proposed offspring by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback typically represents a phenomenon such as post-mating reproductive isolation or lethal genetic incompatibilities that would reduce the expected litter size, so the default behavior is typically desirable.\\\nBeginning in SLiM 4.1, the \n\\f3\\fs18 count\n\\f4\\fs20  parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).  Each offspring is generated independently, based upon the given parameters.  The returned vector contains all generated offspring, except those that were rejected by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback.  If all offspring are rejected, \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20  is returned, which is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 ; note that this is a change in behavior from earlier versions, which would return \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\nBeginning in SLiM 4.1, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.  SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if \n\\f3\\fs18 defer\n\\f4\\fs20  were \n\\f3\\fs18 F\n\\f4\\fs20 .  Haplosome generation can only be deferred if there are no active \n\\f3\\fs18 mutation()\n\\f4\\fs20  or \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks; otherwise, an error will result.  Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback or otherwise).  There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  is generally preferable since it has fewer restrictions.  When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).\\\nAlso beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from \n\\f3\\fs18 parent1\n\\f4\\fs20 ; more specifically, the \n\\f3\\fs18 x\n\\f4\\fs20  property will be inherited in all spatial models (1D/2D/3D), the \n\\f3\\fs18 y\n\\f4\\fs20  property in 2D/3D models, and the \n\\f3\\fs18 z\n\\f4\\fs20  property in 3D models.  Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.  The parent\\'92s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  / \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 .\\\nNote that this method is only for use in nonWF models, in which offspring generation is managed manually by the model script; in such models, \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  must be called only from \n\\f3\\fs18 reproduction()\n\\f4\\fs20  callbacks, and may not be called at any other time.  In WF models, offspring generation is managed automatically by the SLiM core.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(object<Individual>)addEmpty([Nfs$\\'a0sex\\'a0=\\'a0NULL], [Nl$\\'a0haplosome1Null\\'a0=\\'a0NULL], [Nl$\\'a0haplosome2Null\\'a0=\\'a0NULL], [integer$\\'a0count\\'a0=\\'a01])\\\n\\pard\\pardeftab529\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Generates a new offspring individual with empty haplosomes (i.e., containing no mutations), queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  No \n\\f3\\fs18 recombination()\n\\f4\\fs20  or \n\\f3\\fs18 mutation()\n\\f4\\fs20  callbacks will be called.  The target subpopulation will be used to locate applicable \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks governing the generation of the offspring individual (unlike the other \n\\f3\\fs18 addX()\n\\f4\\fs20  methods, because there is no parental individual to reference).  The offspring is considered to have no parents for the purposes of pedigree tracking.  The \n\\f3\\fs18 sex\n\\f4\\fs20  parameter is treated as in \n\\f3\\fs18 addCrossed()\n\\f4\\fs20 .\\\nFor all chromosome types except \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , null haplosomes will be generated as dictated by the sex of the individual and type of the chromosome.  For example, for chromosome type \n\\f3\\fs18 \"X\"\n\\f4\\fs20  a female would be generated with two empty haplosomes for that chromosome (XX), whereas a male would be generated with one empty haplosome and one null haplosome (X\\'96, in SLiM parlance).  For chromosome type \n\\f3\\fs18 \"H\"\n\\f4\\fs20  an empty haplosome is always generated, not a null haplosome.  But for chromosome type \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , in particular, more control is afforded.  Passing \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default) or \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 haplosome1Null\n\\f4\\fs20  will make the first haplosome for every chromosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  be a non-null (empty) haplosome, the standard behavior.  More interestingly, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 haplosome1Null\n\\f4\\fs20  would make the first haplosome for every chromosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  be a null haplosome.  Similarly, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 haplosome2Null\n\\f4\\fs20  would make the second haplosome for every chromosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  be a null haplosome.  This option could be useful for situations such as adding new haploids into a haplodiploid model.  (Separate control over the haploid or diploid configuration of each chromosome of type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  is not presently supported, but would be a simple extension to the design, by allowing \n\\f3\\fs18 haplosome1Null\n\\f4\\fs20  and \n\\f3\\fs18 haplosome2Null\n\\f4\\fs20  to provide a whole vector of \n\\f3\\fs18 logical\n\\f4\\fs20  flags rather than just a singleton value; please request this feature if you require it.)\\\nBeginning in SLiM 4.1, the \n\\f3\\fs18 count\n\\f4\\fs20  parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).  Each offspring is generated independently, based upon the given parameters.  The returned vector contains all generated offspring, except those that were rejected by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback.  If all offspring are rejected, \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20  is returned, which is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 ; note that this is a change in behavior from earlier versions, which would return \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\nNote that this method is only for use in nonWF models.  See \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  for further general notes on the addition of new offspring individuals.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)addMultiRecombinant(object<Dictionary>$\\'a0pattern, [Nfs$\\'a0sex\\'a0=\\'a0NULL], [No<Individual>$\\'a0parent1\\'a0=\\'a0NULL], [No<Individual>$\\'a0parent2\\'a0=\\'a0NULL], [Nl$\\'a0randomizeStrands\\'a0=\\'a0NULL], [integer$\\'a0count\\'a0=\\'a01], [logical$\\'a0defer\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Generates a new offspring individual based upon the inheritance pattern specified by \n\\f3\\fs18 pattern\n\\f4\\fs20 , queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  The \\'93pattern dictionary\\'94 supplied in \n\\f3\\fs18 pattern\n\\f4\\fs20  must be of class \n\\f3\\fs18 Dictionary\n\\f4\\fs20  (or a subclass of \n\\f3\\fs18 Dictionary\n\\f4\\fs20 ), and more particularly, must be a dictionary of dictionaries structured in a specific way as described below.  This method is a multi-chromosome version of the \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  method.  For single-chromosome models, using \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  will be simpler; and it will be easier to understand this extremely complex method if you understand \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  first.\\\nThe top-level \\'93pattern dictionary\\'94 given by \n\\f3\\fs18 pattern\n\\f4\\fs20  specifies the way in which each chromosome should be handled.  It can use \n\\f3\\fs18 integer\n\\f4\\fs20  keys, in which case each key is the \n\\f3\\fs18 id\n\\f4\\fs20  of a chromosome, or \n\\f3\\fs18 string\n\\f4\\fs20  keys, in which case each key is the \n\\f3\\fs18 symbol\n\\f4\\fs20  of a chromosome.  In either case, a chromosome\\'92s inheritance pattern is specified by an \\'93inheritance dictionary\\'94 in \n\\f3\\fs18 pattern\n\\f4\\fs20  attached to such a chromosome \n\\f3\\fs18 id\n\\f4\\fs20  or \n\\f3\\fs18 symbol\n\\f4\\fs20  key.  That inheritance dictionary should itself contain up to six keys, with the standard names \n\\f3\\fs18 \"strand1\"\n\\f4\\fs20 , \n\\f3\\fs18 \"strand2\"\n\\f4\\fs20 , \n\\f3\\fs18 \"breaks1\"\n\\f4\\fs20 , \n\\f3\\fs18 \"strand3\"\n\\f4\\fs20 , \n\\f3\\fs18 \"strand4\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"breaks2\"\n\\f4\\fs20 .  Any key which is missing in an inheritance dictionary is assumed to have a value of \n\\f3\\fs18 NULL\n\\f4\\fs20 , and missing keys will be referred to having a value of \n\\f3\\fs18 NULL\n\\f4\\fs20  here for simplicity.  These key-value pairs are used in precisely the same way as the parameters of the same names for \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 , to produce the offspring haplosome(s) for each specified chromosome.  There is some complication regarding how these six values can be used to produce results like crossing, cloning, and selfing, involving as many as four different \\'93parents\\'94 for each chromosome; rather than repeating all of that documentation here, please see the \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  documentation for more information.  When an inheritance dictionary is supplied for a particular chromosome, this method uses the six values that dictionary contains (\n\\f3\\fs18 strand1\n\\f4\\fs20 , \n\\f3\\fs18 strand2\n\\f4\\fs20 , \n\\f3\\fs18 breaks1\n\\f4\\fs20 , \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , \n\\f3\\fs18 breaks2\n\\f4\\fs20 ) in exactly the same way as \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  does; \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  simply supports multiple chromosomes.  In addition to that, however, \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  also allows the pattern dictionary to omit the inheritance dictionaries for particular chromosomes; the behavior of \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  in that special case will be described below, after discussing all other aspects of the method\\'92s implementation.\\\nThe \n\\f3\\fs18 sex\n\\f4\\fs20  parameter optionally specifies the sex of the offspring.  The default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  specifies \\'93default behavior\\'94; in a non-sexual model this is the only legal value, and produces a hermaphroditic offspring.  In a sexual model, the \\'93default behavior\\'94 of \n\\f3\\fs18 NULL\n\\f4\\fs20  is that the offspring\\'92s sex is dictated by the haplosome structure it inherits.  For example, if \n\\f3\\fs18 pattern\n\\f4\\fs20  specifies that the offspring will have two non-null haplosomes for a chromosome of type \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , the sex of the offspring must therefore be female, whereas if it will have one non-null \n\\f3\\fs18 \"X\"\n\\f4\\fs20  haplosome and one null \n\\f3\\fs18 \"X\"\n\\f4\\fs20  haplosome, it must therefore be male.  SLiM will scan through \n\\f3\\fs18 pattern\n\\f4\\fs20  to determine such constraints and enforce them.  If the constraints implied by \n\\f3\\fs18 pattern\n\\f4\\fs20  are not self-consistent (if the offspring would have two non-null \n\\f3\\fs18 \"X\"\n\\f4\\fs20  haplosomes but also a non-null \n\\f3\\fs18 \"Y\"\n\\f4\\fs20  haplosome, for example), an error will be raised.  The constraints defined by each chromosome type, as described in \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 , must always be followed, even when using \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 .  If \n\\f3\\fs18 sex\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  and \n\\f3\\fs18 pattern\n\\f4\\fs20  imposes no constraints upon the sex of the offspring, the offspring will be chosen as male or female with equal probability.  A value of \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  specifies that the offspring should be male or female, respectively.  A \n\\f3\\fs18 float\n\\f4\\fs20  value from \n\\f3\\fs18 0.0\n\\f4\\fs20  to \n\\f3\\fs18 1.0\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  provides the probability that the offspring will be male; a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  will produce a female, a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.  In these cases where \n\\f3\\fs18 sex\n\\f4\\fs20  is not \n\\f3\\fs18 NULL\n\\f4\\fs20 , SLiM will first determine the sex of the individual as just described, and will then scan through \n\\f3\\fs18 pattern\n\\f4\\fs20  to confirm that it is compatible with the sex that was determined.  Again, if there is a conflict an error will be raised; you cannot specify the sex of an individual to be incompatible with the haplosomes that it inherits, and if you specify a sex with a \n\\f3\\fs18 string\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value it is up to you to ensure that that is compatible with the specifications in \n\\f3\\fs18 pattern\n\\f4\\fs20 .  (If you need more flexibility, you should probably not use a sexual model at all, but simply use chromosome types \n\\f3\\fs18 \"A\"\n\\f4\\fs20  and \n\\f3\\fs18 \"H\"\n\\f4\\fs20  in a non-sexual model, track the sex of individuals yourself with a tag value such as \n\\f3\\fs18 tagL0\n\\f4\\fs20 , and manipulate haplosomes during reproduction however you wish; SLiM then imposes no constraints.)\\\nBy default, the offspring is considered to have no parents, since there may be more than two \\'93parents\\'94 in the general case.  If specifying parentage is desired, \n\\f3\\fs18 parent1\n\\f4\\fs20  and/or \n\\f3\\fs18 parent2\n\\f4\\fs20  may be passed explicitly; this will establish those individuals as the parents of the offspring for purposes of pedigree tracking, and for several other purposes described below.  If only one of \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  is non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , that individual will be set as \n\\f1\\i both\n\\f4\\i0  of the parents of the offspring, mirroring the way that parentage is tracked for other cases such as \n\\f3\\fs18 addCloned()\n\\f4\\fs20  and \n\\f3\\fs18 addSelfed()\n\\f4\\fs20 .  It is not required for \n\\f3\\fs18 parent1\n\\f4\\fs20  or \n\\f3\\fs18 parent2\n\\f4\\fs20  to actually be a genetic parent of the offspring at all, although typically they would be.  To benefit from the full functionality of \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  as described below, it is best to supply \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  when possible.\\\nThe \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  parameter is used to control the recombination behavior of \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 .  An inheritance dictionary can specify two parental strands with crossover breakpoints between them to generate one offspring strand with recombination \\'96 for example, with the \n\\f3\\fs18 \"strand1\"\n\\f4\\fs20 , \n\\f3\\fs18 \"strand2\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"breaks1\"\n\\f4\\fs20  keys, as described above, but the same is true of the \n\\f3\\fs18 \"strand3\"\n\\f4\\fs20 , \n\\f3\\fs18 \"strand4\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"breaks2\"\n\\f4\\fs20  keys, and the discussion that follows applies to both cases.  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the supplied strands are used as given; for example, \n\\f3\\fs18 \"strand1\"\n\\f4\\fs20  will be the initial copy strand when generating the first gamete to form the offspring.  This mode should be used if you want explicit control over the initial copy strand; one example would be if your script is explicitly generating all four of the products of a meiosis event.  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is T, then if \n\\f3\\fs18 \"strand1\"\n\\f4\\fs20  and \n\\f3\\fs18 \"strand2\"\n\\f4\\fs20  are both non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , 50% of the time they will be swapped, making \n\\f3\\fs18 \"strand2\"\n\\f4\\fs20  the initial copy strand for the first gamete instead.  This mode (\n\\f3\\fs18 randomizeStrands\n\\f4\\fs20 =\n\\f3\\fs18 T\n\\f4\\fs20 ) is usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is recommended unless you specifically desire otherwise.  The default value of \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  in order to force either \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20  to be explicitly chosen whenever it would make a difference; if it is left as \n\\f3\\fs18 NULL\n\\f4\\fs20 , an error will be raised if generation of the specified offspring involves recombination, since then SLiM needs to know whether the value is \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20 .  (This unconventional approach has been adopted because the default value was \n\\f3\\fs18 F\n\\f4\\fs20  prior to SLiM 5, but \n\\f3\\fs18 T\n\\f4\\fs20  is almost always the correct behavior, as explained above.  To try to prevent accidental bugs, this new policy was adopted to force the user to explicitly choose \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20  whenever it matters.)\\\nThe value of the \n\\f3\\fs18 meanParentAge\n\\f4\\fs20  property of the generated offspring is calculated from the mean parent age of each of its two haplosomes (whether they turn out to be null haplosomes or not).  The \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  documentation provides a simple example; for \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  the logic is the same, but potentially extended to more than two offspring haplosomes.\\\nCallbacks can be involved in offspring generation with \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 , but because there are up to four strands with up to four different parents, things are a bit complicated and different from other \n\\f3\\fs18 add...()\n\\f4\\fs20  methods; the policy described here seems like the best compromise.  The target subpopulation for the \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  call will be used to locate applicable \n\\f3\\fs18 mutation()\n\\f4\\fs20  and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks governing the generation of the offspring individual.  On the other hand, \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks will be found based upon the subpopulations to which \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  belong (for reasons discussed further in \n\\f3\\fs18 drawBreakpoints()\n\\f4\\fs20 ); if a parent individual is not supplied, \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks will not be called at all when generating the corresponding offspring haplosome.\\\nWhen breakpoints are explicitly supplied to \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  with \n\\f3\\fs18 breaks1\n\\f4\\fs20  or \n\\f3\\fs18 breaks2\n\\f4\\fs20 , gene conversion tracts are not well-supported by this method; the \n\\f3\\fs18 breaks1\n\\f4\\fs20  and \n\\f3\\fs18 breaks2\n\\f4\\fs20  vectors provide simple crossover breakpoints, which may be used to implement crossovers or simple gene conversion tracts, but complex gene conversion tracts with heteroduplex mismatch repair are not supported in this mode of operation since there is no way to supply the relevant information.  If, on the other hand, \n\\f3\\fs18 breaks1\n\\f4\\fs20  or \n\\f3\\fs18 breaks2\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  when generating a haplosome with recombination, then as described above, \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  will generate breakpoints internally for that cross, and in this case, complex gene conversion tracts with heteroduplex mismatch repair are supported, since all of the necessary information is available.  Similarly, if the inheritance dictionary for a given chromosome is omitted from \n\\f3\\fs18 pattern\n\\f4\\fs20  entirely and a cross between \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  is inferred (as discussed below), the recombination algorithm used will support gene conversion including heteroduplex mismatch repair.\\\nFinally, \n\\f3\\fs18 count\n\\f4\\fs20  is the number of offspring to generate using the given pattern and parameters, and \n\\f3\\fs18 defer\n\\f4\\fs20  is used for deferral of offspring generation, as described for \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .  Any other details omitted from this documentation are all as described for \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .\\\nConstructing a well-formed pattern dictionary with inheritance dictionaries for every chromosome can be a bit complex and require many lines of code.  To ease the process, see the \n\\f3\\fs18 Species\n\\f4\\fs20  methods \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20 , \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20 , \n\\f3\\fs18 addPatternForNull()\n\\f4\\fs20 , and \n\\f3\\fs18 addPatternForRecombinant()\n\\f4\\fs20 , which help you to build a pattern dictionary one inheritance dictionary at a time.  However, several of these methods will probably be used infrequently, because of the final aspect of \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  that we have not yet properly discussed.\\\nAs mentioned earlier, not all chromosomes need to be specified with an inheritance dictionary in \n\\f3\\fs18 pattern\n\\f4\\fs20 ; whenever SLiM\\'92s default inheritance behavior is well-defined and is desired for a given chromosome, the inheritance dictionary for that chromosome may be omitted, and will be inferred by \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20  automatically.  This behavior makes it easy to specify a reproduction event that is, for example, like a regular biparental cross involving many chromosomes, but that uses a different reproductive pattern just for one particular chromosome that behaves in a special way.  The inferred inheritance dictionary for a given chromosome is based upon the chromosome type, the values of \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20 , and the sex of the offspring (which has, by this point, been determined in all cases).  The rules for this inference are actually quite simple.  If both parents are specified (that is, are both non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ), the inferred inheritance dictionary is the same as would be produced by a call to \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20  with those two parents, given in that order, for that chromosome, for the determined offspring sex.  If only one parent is specified (non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ), the inferred inheritance dictionary is the same as would be produced by a call to \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20  with that one parent, for that chromosome, for the determined offspring sex.  If selfing is desired for the inferred inheritance dictionary, pass the same individual for both \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20 ; the behavior of \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20  in that case is essentially to self the individual, as discussed in that method.  If the inferred inheritance dictionary for a given chromosome is not well-defined, as discussed in the documentation for \n\\f3\\fs18 addPatternForCross()\n\\f4\\fs20  and \n\\f3\\fs18 addPatternForClone()\n\\f4\\fs20 , or if both \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  are \n\\f3\\fs18 NULL\n\\f4\\fs20 , an error will be raised.  In such cases, the inheritance dictionary cannot be inferred, and will need to be given explicitly in \n\\f3\\fs18 pattern\n\\f4\\fs20 .\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)addRecombinant(No<Haplosome>$\\'a0strand1, No<Haplosome>$\\'a0strand2, Ni\\'a0breaks1, No<Haplosome>$\\'a0strand3, No<Haplosome>$\\'a0strand4, Ni\\'a0breaks2, [Nfs$\\'a0sex\\'a0=\\'a0NULL], [No<Individual>$\\'a0parent1\\'a0=\\'a0NULL], [No<Individual>$\\'a0parent2\\'a0=\\'a0NULL], [Nl$\\'a0randomizeStrands\\'a0=\\'a0NULL], [integer$\\'a0count\\'a0=\\'a01], [logical$\\'a0defer\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Generates a new offspring individual from the given parental haplosomes with the specified crossover breakpoints, queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  This method is an advanced feature; most models will use \n\\f3\\fs18 addCrossed()\n\\f4\\fs20 , \n\\f3\\fs18 addSelfed()\n\\f4\\fs20 , or \n\\f3\\fs18 addCloned()\n\\f4\\fs20  instead.  This method may only be used in single-chromosome models; in multi-chromosome models, use \n\\f3\\fs18 addMultiRecombinant()\n\\f4\\fs20 , a more general version of \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .\\\nThis method supports several possible configurations for \n\\f3\\fs18 strand1\n\\f4\\fs20 , \n\\f3\\fs18 strand2\n\\f4\\fs20 , and \n\\f3\\fs18 breaks1\n\\f4\\fs20  (and the same applies for \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , and \n\\f3\\fs18 breaks2\n\\f4\\fs20 ).  If \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  are both \n\\f3\\fs18 NULL\n\\f4\\fs20 , the corresponding haplosome in the generated offspring will be a null haplosome; in this case, \n\\f3\\fs18 breaks1\n\\f4\\fs20  must be \n\\f3\\fs18 NULL\n\\f4\\fs20  or zero-length.  If \n\\f3\\fs18 strand1\n\\f4\\fs20  is non-\n\\f3\\fs18 NULL\n\\f4\\fs20  but \n\\f3\\fs18 strand2\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the corresponding haplosome in the generated offspring will be a clonal copy of \n\\f3\\fs18 strand1\n\\f4\\fs20  with mutations added, as from \n\\f3\\fs18 addCloned()\n\\f4\\fs20 ; in this case, \n\\f3\\fs18 breaks1\n\\f4\\fs20  must again be \n\\f3\\fs18 NULL\n\\f4\\fs20  or zero-length.  If \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  are both non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , the corresponding haplosome in the generated offspring will result from recombination between \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  with mutations added, as from \n\\f3\\fs18 addCrossed()\n\\f4\\fs20 , with \n\\f3\\fs18 strand1\n\\f4\\fs20  being the initial copy strand by default (but see below).  Copying will switch between strands at each crossover breakpoint.  Breakpoints may be supplied in \n\\f3\\fs18 breaks1\n\\f4\\fs20 , which need not be sorted or uniqued (SLiM will sort and unique the supplied breakpoints internally).  Alternatively, \n\\f3\\fs18 breaks1\n\\f4\\fs20  may be \n\\f3\\fs18 NULL\n\\f4\\fs20 , which requests that \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  draw breakpoints automatically to recombine \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20 , following SLiM\\'92s usual breakpoint-drawing algorithm.  (If you do not want any breakpoints, pass \n\\f3\\fs18 integer(0)\n\\f4\\fs20 , a zero-length \n\\f3\\fs18 integer\n\\f4\\fs20  vector, for \n\\f3\\fs18 breaks1\n\\f4\\fs20 .)  Finally, it is not currently legal for \n\\f3\\fs18 strand1\n\\f4\\fs20  to be \n\\f3\\fs18 NULL\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ; that variant may be assigned some meaning in future.  Again, this discussion applies equally to \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , and \n\\f3\\fs18 breaks2\n\\f4\\fs20 , \n\\f1\\i mutatis mutandis\n\\f4\\i0 .  Null haplosomes may never be passed as any of the four parental strands; pass \n\\f3\\fs18 NULL\n\\f4\\fs20 , not a null haplosome, if that strand is not inherited from.  When modeling a chromosome that is intrinsically haploid, such as the Y, \n\\f3\\fs18 NULL\n\\f4\\fs20  must be passed for \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , and \n\\f3\\fs18 breaks2\n\\f4\\fs20 ; you cannot supply genetic information for an offspring haplosome that will not exist.  Note that when new mutations are generated by \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 , their \n\\f3\\fs18 subpopID\n\\f4\\fs20  property will be the \n\\f3\\fs18 id\n\\f4\\fs20  of the offspring\\'92s subpopulation, since the parental subpopulation is ambiguous in the general case; this behavior differs from the other \n\\f3\\fs18 add...()\n\\f4\\fs20  methods.\\\nThese semantics allow several uses for \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .  When all strands are non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , it is similar to \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  except that the recombination breakpoints can be specified explicitly, allowing very precise offspring generation without having to override SLiM\\'92s breakpoint generation with a \n\\f3\\fs18 recombination()\n\\f4\\fs20  callback.  When only \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand3\n\\f4\\fs20  are supplied, it is very similar to \n\\f3\\fs18 addCloned()\n\\f4\\fs20 , creating a clonal offspring, except that the two parental haplosomes need not belong to the same individual (whatever that might mean biologically).  Supplying only \n\\f3\\fs18 strand1\n\\f4\\fs20  is useful for modeling clonally reproducing haploids, or any chromosome type that is intrinsically haploid, such as the Y chromosome.  For a model of clonally reproducing haploids that undergo horizontal gene transfer (HGT), supplying only \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  will allow HGT from \n\\f3\\fs18 strand2\n\\f4\\fs20  to replace segments of an otherwise clonal copy of \n\\f3\\fs18 strand1\n\\f4\\fs20 , while the second haplosome of the generated offspring will be a null haplosome; this could be useful for modeling bacterial conjugation, for example.  Other variations are also possible.\\\nThe \n\\f3\\fs18 sex\n\\f4\\fs20  parameter optionally specifies the sex of the offspring.  The default value of \n\\f3\\fs18 NULL\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  specifies \\'93default behavior\\'94; in a non-sexual model this is the only legal value, and produces a hermaphroditic offspring.  In a sexual model, the \\'93default behavior\\'94 of \n\\f3\\fs18 NULL\n\\f4\\fs20  is that the offspring\\'92s sex is dictated by the haplosome structure it inherits.  For example, if the supplied strands indicate that the offspring will have two non-null haplosomes for a chromosome of type \n\\f3\\fs18 \"X\"\n\\f4\\fs20 , the sex of the offspring must therefore be female, whereas if it will have one non-null \n\\f3\\fs18 \"X\"\n\\f4\\fs20  haplosome and one null \n\\f3\\fs18 \"X\"\n\\f4\\fs20  haplosome, it must therefore be male.  SLiM will examine the supplied strands to determine such constraints and enforce them.  The constraints defined by each chromosome type, as described in \n\\f3\\fs18 initializeChromosome()\n\\f4\\fs20 , must always be followed, even when using \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .  If \n\\f3\\fs18 sex\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  and the sex of the offspring is unconstrained, the offspring will be chosen as male or female with equal probability.  A value of \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  specifies that the offspring should be male or female, respectively.  A \n\\f3\\fs18 float\n\\f4\\fs20  value from \n\\f3\\fs18 0.0\n\\f4\\fs20  to \n\\f3\\fs18 1.0\n\\f4\\fs20  for \n\\f3\\fs18 sex\n\\f4\\fs20  provides the probability that the offspring will be male; a value of \n\\f3\\fs18 0.0\n\\f4\\fs20  will produce a female, a value of \n\\f3\\fs18 1.0\n\\f4\\fs20  will produce a male, and for intermediate values SLiM will draw the sex of the offspring randomly according to the specified probability.  In these cases where \n\\f3\\fs18 sex\n\\f4\\fs20  is not \n\\f3\\fs18 NULL\n\\f4\\fs20 , SLiM will first determine the sex of the individual as just described, and will then examine the supplied strands to confirm that it is compatible with the sex that was determined.  Again, if there is a conflict an error will be raised; you cannot specify the sex of an individual to be incompatible with the haplosomes that it inherits, and if you specify a sex with a \n\\f3\\fs18 string\n\\f4\\fs20  or \n\\f3\\fs18 float\n\\f4\\fs20  value it is up to you to ensure that that is compatible with the supplied strands.  (If you need more flexibility, you should probably not use a sexual model at all, but simply use chromosome type \n\\f3\\fs18 \"A\"\n\\f4\\fs20  or \n\\f3\\fs18 \"H\"\n\\f4\\fs20  in a non-sexual model, track the sex of individuals yourself with a tag value such as \n\\f3\\fs18 tagL0\n\\f4\\fs20 , and manipulate haplosomes during reproduction however you wish; SLiM then imposes no constraints.)\\\nBy default, the offspring is considered to have no parents, since there may be more than two \\'93parents\\'94 in the general case.  If specifying parentage is desired, \n\\f3\\fs18 parent1\n\\f4\\fs20  and/or \n\\f3\\fs18 parent2\n\\f4\\fs20  may be passed to explicitly; this will establish those individuals as the parents of the offspring for purposes of pedigree tracking, and for several other purposes described below.  If only one of \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  is non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , that individual will be set as \n\\f1\\i both\n\\f4\\i0  of the parents of the offspring, mirroring the way that parentage is tracked for other cases such as \n\\f3\\fs18 addCloned()\n\\f4\\fs20  and \n\\f3\\fs18 addSelfed()\n\\f4\\fs20 .  It is not required for \n\\f3\\fs18 parent1\n\\f4\\fs20  or \n\\f3\\fs18 parent2\n\\f4\\fs20  to actually be a genetic parent of the offspring at all, although typically they would be.  To benefit from the full functionality of \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  as described below, it is best to supply \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  when possible.\\\nThe \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  parameter is used to control the recombination behavior of \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 .  As described above, two parental strands with crossover breakpoints between them can be specified to generate one offspring strand with recombination \\'96 for example, with the \n\\f3\\fs18 strand1\n\\f4\\fs20 , \n\\f3\\fs18 strand2\n\\f4\\fs20 , and \n\\f3\\fs18 breaks1\n\\f4\\fs20  parameters, but the same is true of the \n\\f3\\fs18 strand3\n\\f4\\fs20 , \n\\f3\\fs18 strand4\n\\f4\\fs20 , and \n\\f3\\fs18 breaks2\n\\f4\\fs20  parameters, and the discussion that follows applies to both cases.  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , the supplied strands are used as given; for example, \n\\f3\\fs18 strand1\n\\f4\\fs20  will be the initial copy strand when generating the first gamete to form the offspring.  This mode should be used if you want explicit control over the initial copy strand; one example would be if your script is explicitly generating all four of the products of a meiosis event.  If \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , then if \n\\f3\\fs18 strand1\n\\f4\\fs20  and \n\\f3\\fs18 strand2\n\\f4\\fs20  are both non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , 50% of the time they will be swapped, making \n\\f3\\fs18 strand2\n\\f4\\fs20  the initial copy strand for the first gamete instead.  This mode (\n\\f3\\fs18 randomizeStrands\n\\f4\\fs20 =\n\\f3\\fs18 T\n\\f4\\fs20 ) is usually the desired behavior, to avoid an inheritance bias due to a lack of randomization in the initial copy strand, so passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is recommended unless you specifically desire otherwise.  The default value of \n\\f3\\fs18 randomizeStrands\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  in order to force either \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20  to be explicitly chosen whenever it would make a difference; if it is left as \n\\f3\\fs18 NULL\n\\f4\\fs20 , an error will be raised if generation of the specified offspring involves recombination, since then SLiM needs to know whether the value is \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20 .  (This unconventional approach has been adopted because the default value was \n\\f3\\fs18 F\n\\f4\\fs20  prior to SLiM 5, but \n\\f3\\fs18 T\n\\f4\\fs20  is almost always the correct behavior, as explained above.  To try to prevent accidental bugs, this new policy was adopted to force the user to explicitly choose \n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20  whenever it matters.)\\\nThe value of the \n\\f3\\fs18 meanParentAge\n\\f4\\fs20  property of the generated offspring is calculated from the mean parent age of each of its two haplosomes (whether they turn out to be null haplosomes or not); that may be an average of two values (if both offspring haplosomes have at least one parent), a single value (if one offspring haplosome has no parent), or no values (if both offspring haplosomes have no parent, in which case \n\\f3\\fs18 0.0\n\\f4\\fs20  results).  The mean parent age of a given offspring haplosome is the mean of the ages of the parents of the two strands used to generate that offspring haplosome; if one strand is \n\\f3\\fs18 NULL\n\\f4\\fs20  then the mean parent age for that offspring haplosome is the age of the parent of the non-\n\\f3\\fs18 NULL\n\\f4\\fs20  strand, while if both strands are \n\\f3\\fs18 NULL\n\\f4\\fs20  then that offspring haplosome is parentless and is not used in the final calculation.  In other words, if one offspring haplosome has two parents with ages A and B, and the other offspring haplosome has one parent with age C, the \n\\f3\\fs18 meanParentAge\n\\f4\\fs20  of the offspring will be (A+B+C+C)\\'a0/\\'a04, or equivalently, ((A+B)/2\\'a0+\\'a0C)\\'a0/\\'a02, not (A+B+C)\\'a0/\\'a03.\\\nCallbacks can be involved in offspring generation with \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20 , but because there are up to four strands with up to four different parents, things are a bit complicated and different from other \n\\f3\\fs18 add...()\n\\f4\\fs20  methods; the policy described here seems like the best compromise.  The target subpopulation for the \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  call will be used to locate applicable \n\\f3\\fs18 mutation()\n\\f4\\fs20  and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks governing the generation of the offspring individual.  On the other hand, \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks will be found based upon the subpopulations to which \n\\f3\\fs18 parent1\n\\f4\\fs20  and \n\\f3\\fs18 parent2\n\\f4\\fs20  belong (for reasons discussed further in \n\\f3\\fs18 drawBreakpoints()\n\\f4\\fs20 ); if a parent individual is not supplied, \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks will not be called at all when generating the corresponding offspring haplosome.\\\nWhen breakpoints are explicitly supplied to \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  with \n\\f3\\fs18 breaks1\n\\f4\\fs20  or \n\\f3\\fs18 breaks2\n\\f4\\fs20 , gene conversion tracts are not well-supported by this method; the \n\\f3\\fs18 breaks1\n\\f4\\fs20  and \n\\f3\\fs18 breaks2\n\\f4\\fs20  vectors provide simple crossover breakpoints, which may be used to implement crossovers or simple gene conversion tracts, but complex gene conversion tracts with heteroduplex mismatch repair are not supported in this mode of operation since there is no way to supply the relevant information.  If, on the other hand, \n\\f3\\fs18 breaks1\n\\f4\\fs20  or \n\\f3\\fs18 breaks2\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  when generating a haplosome with recombination, then as described above, \n\\f3\\fs18 addRecombinant()\n\\f4\\fs20  will generate breakpoints internally for that cross, and in this case, complex gene conversion tracts with heteroduplex mismatch repair are supported, since all of the necessary information is available.\\\nBeginning in SLiM 4.1, the \n\\f3\\fs18 count\n\\f4\\fs20  parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).  Each offspring is generated independently, based upon the given parameters.  The returned vector contains all generated offspring, except those that were rejected by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback.  If all offspring are rejected, \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20  is returned, which is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 ; note that this is a change in behavior from earlier versions, which would return \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\nBeginning in SLiM 4.1, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.  SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if \n\\f3\\fs18 defer\n\\f4\\fs20  were \n\\f3\\fs18 F\n\\f4\\fs20 .  Haplosome generation can only be deferred if there are no active \n\\f3\\fs18 mutation()\n\\f4\\fs20  callbacks; otherwise, an error will result.  Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback or otherwise).  There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  is generally preferable since it has fewer restrictions.  When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).\\\nAlso beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from \n\\f3\\fs18 parent1\n\\f4\\fs20 ; more specifically, the \n\\f3\\fs18 x\n\\f4\\fs20  property will be inherited in all spatial models (1D/2D/3D), the \n\\f3\\fs18 y\n\\f4\\fs20  property in 2D/3D models, and the \n\\f3\\fs18 z\n\\f4\\fs20  property in 3D models.  Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.  The parent\\'92s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  / \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 .  If \n\\f3\\fs18 parent1\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , \n\\f3\\fs18 parent2\n\\f4\\fs20  will be used; if it is also \n\\f3\\fs18 NULL\n\\f4\\fs20 , no spatial position will be inherited.\\\nNote that this method is only for use in nonWF models.  See \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  for further general notes on the addition of new offspring individuals.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(object<Individual>)addSelfed(object<Individual>$\\'a0parent, [integer$\\'a0count\\'a0=\\'a01], [logical$\\'a0defer\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Generates a new offspring individual from the given parent by selfing, queues it for addition to the target subpopulation, and returns it.  The new offspring will not be visible as a member of the target subpopulation until the end of the offspring generation tick cycle stage.  The subpopulation of \n\\f3\\fs18 parent\n\\f4\\fs20  will be used to locate applicable \n\\f3\\fs18 mutation()\n\\f4\\fs20 , \n\\f3\\fs18 recombination()\n\\f4\\fs20 , and \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callbacks governing the generation of the offspring individual.\\\nSince selfing requires that \n\\f3\\fs18 parent\n\\f4\\fs20  act as a source of both a male and a female gamete, this method may be called only in hermaphroditic models; calling it in sexual models will result in an error.  This method represents a non-incidental selfing event, so the \n\\f3\\fs18 preventIncidentalSelfing\n\\f4\\fs20  flag of \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20  has no effect on this method (in contrast to the behavior of \n\\f3\\fs18 addCrossed()\n\\f4\\fs20 , where selfing is assumed to be incidental).\\\nBeginning in SLiM 4.1, the \n\\f3\\fs18 count\n\\f4\\fs20  parameter dictates how many offspring will be generated (previously, exactly one offspring was generated).  Each offspring is generated independently, based upon the given parameters.  The returned vector contains all generated offspring, except those that were rejected by a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback.  If all offspring are rejected, \n\\f3\\fs18 object<Individual>(0)\n\\f4\\fs20  is returned, which is a zero-length \n\\f3\\fs18 object\n\\f4\\fs20  vector of class \n\\f3\\fs18 Individual\n\\f4\\fs20 ; note that this is a change in behavior from earlier versions, which would return \n\\f3\\fs18 NULL\n\\f4\\fs20 .\\\nBeginning in SLiM 4.1, passing \n\\f3\\fs18 T\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  requests that the generation of the haplosomes of the produced offspring be deferred until the end of the reproduction phase.  SLiM may or may not honor this request; if not, the offspring will be generated synchronously just as if \n\\f3\\fs18 defer\n\\f4\\fs20  were \n\\f3\\fs18 F\n\\f4\\fs20 .  Haplosome generation can only be deferred if there are no active \n\\f3\\fs18 mutation()\n\\f4\\fs20  or \n\\f3\\fs18 recombination()\n\\f4\\fs20  callbacks; otherwise, an error will result.  Furthermore, when haplosome generation is deferred the mutations of the haplosomes of the generated offspring may not be accessed until reproduction is complete (whether from a \n\\f3\\fs18 modifyChild()\n\\f4\\fs20  callback or otherwise).  There is little or no advantage to deferring haplosome generation when running single-threaded; in that case, the default of \n\\f3\\fs18 F\n\\f4\\fs20  for \n\\f3\\fs18 defer\n\\f4\\fs20  is generally preferable since it has fewer restrictions.  When running multi-threaded, deferring haplosome generation allows that task to be done in parallel (which is the reason this option exists).\\\nAlso beginning in SLiM 4.1, in spatial models the spatial position of the offspring will be inherited (i.e., copied) from \n\\f3\\fs18 parent\n\\f4\\fs20 ; more specifically, the \n\\f3\\fs18 x\n\\f4\\fs20  property will be inherited in all spatial models (1D/2D/3D), the \n\\f3\\fs18 y\n\\f4\\fs20  property in 2D/3D models, and the \n\\f3\\fs18 z\n\\f4\\fs20  property in 3D models.  Properties not inherited will be left uninitialized, as they were prior to SLiM 4.1.  The parent\\'92s spatial position is probably not desirable in itself; the intention here is to make it easy to model the natal dispersal of all the new offspring for a given tick with a single vectorized call to \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  / \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 .\\\nNote that this method is only for use in nonWF models.  See \n\\f3\\fs18 addCrossed()\n\\f4\\fs20  for further general notes on the addition of new offspring individuals.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)addSpatialMap(object<SpatialMap>$\\'a0map)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Adds the given \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object, \n\\f3\\fs18 map\n\\f4\\fs20 , to the subpopulation.  (The spatial map would have been previously created with a call to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  on a different subpopulation; \n\\f3\\fs18 addSpatialMap()\n\\f4\\fs20  can then be used to add that existing spatial map with other subpopulations, sharing the map between subpopulations.)  If the map is already added to the target subpopulation, this method does nothing; if a different map with the same name is already added to the subpopulation, an error results (because map names must be unique within each subpopulation).  The map being added must be compatible with the target subpopulation; in particular, the spatial bounds utilized by the map must exactly match the corresponding spatial bounds for the subpopulation, and the dimensionality of the subpopulation must encompass the spatiality of the map.  For example, if the map has a spatiality of \n\\f3\\fs18 \"xz\"\n\\f4\\fs20  then the subpopulation must have a dimensionality of \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  so that it encompasses both \n\\f3\\fs18 \"x\"\n\\f4\\fs20  and \n\\f3\\fs18 \"z\"\n\\f4\\fs20 , and the subpopulation\\'92s spatial bounds for \n\\f3\\fs18 \"x\"\n\\f4\\fs20  and \n\\f3\\fs18 \"z\"\n\\f4\\fs20  must match those for the map (but the spatial bounds for \n\\f3\\fs18 \"y\"\n\\f4\\fs20  are unimportant, since the map does not use that dimension).\\\nAdding a map to a subpopulation is not strictly necessary, at present; one may query a \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object directly using \n\\f3\\fs18 mapValue()\n\\f4\\fs20 , regarding points in a subpopulation, without the map actually having been added to that subpopulation.  However, it is a good idea to use \n\\f3\\fs18 addSpatialMap()\n\\f4\\fs20 , both for its compatibility check that prevents unnoticed scripting errors, and because it ensures correct display of the model in SLiMgui.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(float)cachedFitness(Ni\\'a0indices)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The fitness values calculated for the individuals at the indices given are returned.  If \n\\f3\\fs18 NULL\n\\f4\\fs20  is passed, fitness values for all individuals in the subpopulation are returned.  The fitness values returned are cached values; \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  and \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callbacks are therefore not called as a side effect of this method.  It is always an error to call \n\\f3\\fs18 cachedFitness()\n\\f4\\fs20  from inside a \n\\f3\\fs18 mutationEffect()\n\\f4\\fs20  or \n\\f3\\fs18 fitnessEffect()\n\\f4\\fs20  callback, since fitness values are in the middle of being set up.  In WF models, it is also an error to call \n\\f3\\fs18 cachedFitness()\n\\f4\\fs20  from a \n\\f3\\fs18 late()\n\\f4\\fs20  event, because fitness values for the new offspring generation have not yet been calculated and are undefined.  In nonWF models, the population may be a mixture of new and old individuals, so instead, \n\\f3\\fs18 NAN\n\\f4\\fs20  will be returned as the fitness of any new individuals whose fitness has not yet been calculated.  When new subpopulations are first created with \n\\f3\\fs18 addSubpop()\n\\f4\\fs20  or \n\\f3\\fs18 addSubpopSplit()\n\\f4\\fs20 , the fitness of all of the newly created individuals is considered to be \n\\f3\\fs18 1.0\n\\f4\\fs20  until fitness values are recalculated.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\'96\\'a0(void)configureDisplay([Nf\\'a0center\\'a0=\\'a0NULL], [Nf$\\'a0scale\\'a0=\\'a0NULL], [Ns$\\'a0color\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 This method customizes the display of the subpopulation in SLiMgui\\'92s Population Visualization graph.  When this method is called by a model running outside SLiMgui, it will do nothing except type-checking and bounds-checking its arguments.  When called by a model running in SLiMgui, the position, size, and color of the subpopulation\\'92s displayed circle can be controlled as specified below.\\\nThe \n\\f3\\fs18 center\n\\f4\\fs20  parameter sets the coordinates of the center of the subpopulation\\'92s displayed circle; it must be a \n\\f3\\fs18 float\n\\f4\\fs20  vector of length two, such that \n\\f3\\fs18 center[0]\n\\f4\\fs20  provides the \n\\f1\\i x\n\\f4\\i0 -coordinate and \n\\f3\\fs18 center[1]\n\\f4\\fs20  provides the \n\\f1\\i y\n\\f4\\i0 -coordinate.  The square central area of the Population Visualization occupies scaled coordinates in [0,1] for both \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i y\n\\f4\\i0 , so the values in \n\\f3\\fs18 center\n\\f4\\fs20  must be within those bounds.  If a value of \n\\f3\\fs18 NULL\n\\f4\\fs20  is provided, SLiMgui\\'92s default center will be used (which currently arranges subpopulations in a circle).\\\nThe \n\\f3\\fs18 scale\n\\f4\\fs20  parameter sets a scaling factor to be applied to the radius of the subpopulation\\'92s displayed circle.  The default radius used by SLiMgui is a function of the subpopulation\\'92s number of individuals; this default radius is then multiplied by \n\\f3\\fs18 scale\n\\f4\\fs20 .  If a value of \n\\f3\\fs18 NULL\n\\f4\\fs20  is provided, the default radius will be used; this is equivalent to supplying a \n\\f3\\fs18 scale\n\\f4\\fs20  of \n\\f3\\fs18 1.0\n\\f4\\fs20 .  Typically the same \n\\f3\\fs18 scale\n\\f4\\fs20  value should be used by all subpopulations, to scale all of their circles up or down uniformly, but that is not required.\\\nThe \n\\f3\\fs18 color\n\\f4\\fs20  parameter sets the color to be used for the displayed subpopulation\\'92s circle.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f3\\fs18 \"#RRGGBB\"\n\\f4\\fs20  (see the Eidos manual).  If \n\\f3\\fs18 color\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  or the empty string, \n\\f3\\fs18 \"\"\n\\f4\\fs20 , SLiMgui\\'92s default (fitness-based) color will be used.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(object<SpatialMap>$)defineSpatialMap(string$\\'a0name, string$\\'a0spatiality, numeric\\'a0values, [logical$\\'a0interpolate\\'a0=\\'a0F], [Nif\\'a0valueRange\\'a0=\\'a0NULL], [Ns\\'a0colors\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Defines a spatial map for the subpopulation; see the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  documentation regarding this class.  The new map is automatically added to the subpopulation; \n\\f3\\fs18 addSpatialMap()\n\\f4\\fs20  does not need to be called.  (That method is for sharing the map with additional subpopulations, beyond the one for which the map was originally defined.)  The new \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object is returned, and may be retained permanently using \n\\f3\\fs18 defineConstant()\n\\f4\\fs20  or \n\\f3\\fs18 defineGlobal()\n\\f4\\fs20  for convenience.\\\nThe name of the map is given by \n\\f3\\fs18 name\n\\f4\\fs20 , and can be used to identify it.  The map uses the spatial dimensions referenced by \n\\f3\\fs18 spatiality\n\\f4\\fs20 , which must be a subset of the dimensions defined for the simulation in \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  Spatiality \n\\f3\\fs18 \"x\"\n\\f4\\fs20  is permitted for dimensionality \n\\f3\\fs18 \"x\"\n\\f4\\fs20 ; spatiality \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 \"y\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  for dimensionality \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 ; and spatiality \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 \"y\"\n\\f4\\fs20 , \n\\f3\\fs18 \"z\"\n\\f4\\fs20 , \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 , \n\\f3\\fs18 \"yz\"\n\\f4\\fs20 , \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  for dimensionality \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20 .  The spatial map is defined by a grid of values supplied in parameter \n\\f3\\fs18 values\n\\f4\\fs20 .  That grid of values is aligned with the spatial bounds of the subpopulation, as described in more detail below; the spatial map is therefore coupled to those spatial bounds, and can only be used in subpopulations that match those particular spatial bounds (to avoid stretching or shrinking the map).  The remaining optional parameters are described below.\\\nNote that the semantics of this method changed in SLiM 3.5; in particular, the \n\\f3\\fs18 gridSize\n\\f4\\fs20  parameter was removed, and the interpretation of the \n\\f3\\fs18 values\n\\f4\\fs20  parameter changed as described below.  Existing code written prior to SLiM 3.5 will produce an error, due to the removed \n\\f3\\fs18 gridSize\n\\f4\\fs20  parameter, and must be revised carefully to obtain the same result, even if \n\\f3\\fs18 NULL\n\\f4\\fs20  had been passed for \n\\f3\\fs18 gridSize\n\\f4\\fs20  previously.\\\nBeginning in SLiM 3.5, the \n\\f3\\fs18 values\n\\f4\\fs20  parameter must be a vector/matrix/array with the number of dimensions appropriate for the declared spatiality of the map; for example, a map with spatiality \n\\f3\\fs18 \"x\"\n\\f4\\fs20  would require a (one-dimensional) vector, spatiality \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  would require a (two-dimensional) matrix, and a map with spatiality of \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  would require a three-dimensional array.  (See the Eidos manual for discussion of vectors, matrices, and arrays.)  The data in \n\\f3\\fs18 values\n\\f4\\fs20  is interpreted in such a way that a two-dimensional matrix of values, with (0, 0) at upper left and values by column, is transformed into the format expected by SLiM, with (0, 0) at lower left and values by row; in other words, the two-dimensional matrix as it prints in the Eidos console will match the appearance of the two-dimensional spatial map as seen in SLiMgui.  \n\\f1\\i This is a change in behavior from versions prior to SLiM 3.5\n\\f4\\i0 ; it ensures that images loaded from disk with the Eidos class \n\\f3\\fs18 Image\n\\f4\\fs20  can be used directly as spatial maps, achieving the expected orientation, with no need for transposition or flipping.  If the spatial map is a three-dimensional array, it is read as successive \n\\f1\\i z\n\\f4\\i0 -axis \\'93planes\\'94, each of which is a two-dimensional matrix that is treated as described above.\\\nMoving on to the other parameters of \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 : if \n\\f3\\fs18 interpolate\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20 , values across the spatial map are not interpolated; the value at a given point is equal to the nearest value defined by the grid of values specified.  If \n\\f3\\fs18 interpolate\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 , values across the spatial map will be interpolated (using linear, bilinear, or trilinear interpolation as appropriate) to produce spatially continuous variation in values.  In either case, the corners of the value grid are exactly aligned with the corners of the spatial boundaries of the subpopulation as specified by \n\\f3\\fs18 setSpatialBounds()\n\\f4\\fs20 , and the value grid is then stretched across the spatial extent of the subpopulation in such a manner as to produce equal spacing between the values along each dimension.  The setting of \n\\f3\\fs18 interpolation\n\\f4\\fs20  only affects how values between these grid points are calculated: by nearest-neighbor, or by linear interpolation.  Interpolation of spatial maps with periodic boundaries is not handled specially; to ensure that the edges of a periodic spatial map join smoothly, simply ensure that the grid values at the edges of the map are identical, since they will be coincident after periodic wrapping.  Note that cubic/bicubic interpolation is generally smoother than linear/bilinear interpolation, with fewer artifacts, but it is substantially slower to calculate; use the \n\\f3\\fs18 interpolate()\n\\f4\\fs20  method of \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  to precalculate an interpolated map using cubic/bucubic interpolation.\\\nThe \n\\f3\\fs18 valueRange\n\\f4\\fs20  and \n\\f3\\fs18 colors\n\\f4\\fs20  parameters travel together; either both are unspecified, or both are specified.  They control how map values will be transformed into colors, by SLiMgui and by the \n\\f3\\fs18 mapColor()\n\\f4\\fs20  method.  The \n\\f3\\fs18 valueRange\n\\f4\\fs20  parameter establishes the color-mapped range of spatial map values, as a vector of length two specifying a minimum and maximum; this does not need to match the actual range of values in the map.  The \n\\f3\\fs18 colors\n\\f4\\fs20  parameter then establishes the corresponding colors for values within the interval defined by \n\\f3\\fs18 valueRange\n\\f4\\fs20 : values less than or equal to \n\\f3\\fs18 valueRange[0]\n\\f4\\fs20  will map to \n\\f3\\fs18 colors[0]\n\\f4\\fs20 , values greater than or equal to \n\\f3\\fs18 valueRange[1]\n\\f4\\fs20  will map to the last \n\\f3\\fs18 colors\n\\f4\\fs20  value, and intermediate values will shade continuously through the specified vector of colors, with interpolation between adjacent colors to produce a continuous spectrum.  This is much simpler than it sounds in this description; see the recipes for an illustration of its use.\\\nNote that at present, SLiMgui will only display spatial maps of spatiality \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 \"y\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 ; the color-mapping parameters will simply be ignored by SLiMgui for other spatiality values (even if the spatiality is a superset of these values; SLiMgui will not attempt to display an \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  spatial map, for example, since it has no way to choose which 2D slice through the \n\\f1\\i xyz\n\\f4\\i0  space it ought to display).  The \n\\f3\\fs18 mapColor()\n\\f4\\fs20  method will return translated color strings for any spatial map, however, even if SLiMgui is unable to display the spatial map.  If there are multiple spatial maps that SLiMgui is capable of displaying, it choose one for display by default, but other maps may be selected from the action menu on the individuals view (by clicking on the button with the gear icon).\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)deviatePositions(No<Individual>\\'a0individuals, string$\\'a0boundary, numeric$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Deviates the spatial positions of the individuals supplied in \n\\f3\\fs18 individuals\n\\f4\\fs20 , using the provided boundary condition and dispersal kernel.  If \n\\f3\\fs18 individuals\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the positions of all individuals in the target subpopulation are deviated.  This method is essentially a more efficient shorthand for getting the spatial positions of \n\\f3\\fs18 individuals\n\\f4\\fs20  from the \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property, deviating those positions with \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 , and setting the deviated positions back into \n\\f3\\fs18 individuals\n\\f4\\fs20  with the \n\\f3\\fs18 setSpatialPosition()\n\\f4\\fs20  method.\\\nThe boundary condition \n\\f3\\fs18 boundary\n\\f4\\fs20  must be one of \n\\f3\\fs18 \"none\"\n\\f4\\fs20 , \n\\f3\\fs18 \"periodic\"\n\\f4\\fs20 , \n\\f3\\fs18 \"reflecting\"\n\\f4\\fs20 , \n\\f3\\fs18 \"stopping\"\n\\f4\\fs20 , \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20 , and the spatial kernel type \n\\f3\\fs18 functionType\n\\f4\\fs20  must be one of \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , with the ellipsis parameters \n\\f3\\fs18 ...\n\\f4\\fs20  supplying kernel configuration parameters appropriate for that kernel type; see \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20  for further details.  As with \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 , the ellipsis parameters that follow \n\\f3\\fs18 functionType\n\\f4\\fs20  may each, independently, be either a singleton or a vector of length equal to \n\\f3\\fs18 n\n\\f4\\fs20 .  This allows each individual\\'92s position to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.  (However, other parameters such as \n\\f3\\fs18 boundary\n\\f4\\fs20 , \n\\f3\\fs18 maxDistance\n\\f4\\fs20 , and \n\\f3\\fs18 functionType\n\\f4\\fs20  must be the same for all of the points, in the present design.)\\\nThe returned vector contains individuals that did not survive the dispersal process.  For \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20  boundaries, this will contain the individuals that attempted to disperse beyond the spatial bounds, and in most cases the caller will then kill those individuals \\'96 probably by passing them to \n\\f3\\fs18 killIndividuals()\n\\f4\\fs20 , but perhaps by setting their \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  to zero.  (The positions of the individuals in the returned vector will be the out-of-bounds positions that were drawn for them; rather than killing those individuals, the caller could conceivably handle them in some other way.)  For all other boundary conditions, the returned vector of individuals will be empty and may be ignored by the caller.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Individual>)deviatePositionsWithMap(No<Individual>\\'a0individuals, string$\\'a0boundary, so<SpatialMap>$\\'a0map, numeric$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Deviates the spatial positions of the individuals supplied in \n\\f3\\fs18 individuals\n\\f4\\fs20 , using the provided boundary condition and dispersal kernel.  The supplied \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object (or a \n\\f3\\fs18 string\n\\f4\\fs20  specifying a map by name), \n\\f3\\fs18 map\n\\f4\\fs20 , is used (in addition to the spatial bounds of the subpopulation) to define which positions are considered to be \\'93out of bounds\\'94, as described below.  If \n\\f3\\fs18 individuals\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20 , the positions of all individuals in the target subpopulation are deviated.  This method is essentially an extension of the \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  method, adding bounds-checking using \n\\f3\\fs18 map\n\\f4\\fs20 ; however, there are some differences as described below.\\\nThe boundary condition \n\\f3\\fs18 boundary\n\\f4\\fs20  must be either \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20  or \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20 .  In the simple case where map values are either \n\\f3\\fs18 0\n\\f4\\fs20  (bad habitat) or \n\\f3\\fs18 1\n\\f4\\fs20  (good habitat), \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20  means a new location is drawn conditional on falling within the good habitat; \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20  means individuals falling outside the good habitat are \\'93absorbed\\'94 (killed, probably).  The details are discussed below, when \n\\f3\\fs18 map\n\\f4\\fs20  is discussed.  Note that the boundary condition \n\\f3\\fs18 \"none\"\n\\f4\\fs20  is not supported because points must be within the boundaries of the spatial map to be checked.  Reflecting and stopping boundaries are not supported because, with the spatial map, if a drawn point is considered out-of-bounds it is not clear where the \\'93edge\\'94 is, and therefore reflecting off of the edge, or stopping at the edge, are not well-defined.  Finally, \n\\f3\\fs18 \"periodic\"\n\\f4\\fs20  is not supported because it does not specify any action to be taken when a drawn point is considered to be \\'93out of bounds\\'94 according to the spatial map; instead, this method automatically applies any periodic boundaries that have been defined and then, using the resulting point, checks the subpopulation\\'92s spatial bounds and the spatial map, and applies reprising or absorbing boundaries as requested if the point is \\'93out of bounds\\'94.\\\nThe spatial map defined by \n\\f3\\fs18 map\n\\f4\\fs20  must be configured in a specific way.  First of all, it must be defined in, or added to, the target subpopulation (and thus, by implication, it must match the spatial bounds of the subpopulation.  Second, its spatiality must be equal to the dimensionality of the species; in an \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  species, for example, the map must also be \n\\f3\\fs18 \"xy\"\n\\f4\\fs20 .  Third, the values in the spatial map must represent \\'93habitability\\'94, in the following sense.  The value of \n\\f3\\fs18 map\n\\f4\\fs20  at a given drawn point is obtained, symbolized here by \n\\f3\\fs18 x\n\\f4\\fs20 .  Next, \n\\f3\\fs18 x\n\\f4\\fs20  is clamped to the range [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 ]; values less than \n\\f3\\fs18 0\n\\f4\\fs20  become \n\\f3\\fs18 0\n\\f4\\fs20 , values greater than \n\\f3\\fs18 1\n\\f4\\fs20  become \n\\f3\\fs18 1\n\\f4\\fs20 .  The resulting \n\\f3\\fs18 x\n\\f4\\fs20  value is then interpreted as the probability that the point is considered \\'93within bounds\\'94 (as far as the spatial map is concerned; points that are outside the subpopulation\\'92s spatial bounds are \n\\f1\\i always\n\\f4\\i0  considered \\'93out of bounds\\'94).  If \n\\f3\\fs18 boundary\n\\f4\\fs20  is \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20 , \n\\f3\\fs18 1-x\n\\f4\\fs20  is thus the probability that the point will be redrawn; if boundary is \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20 , \n\\f3\\fs18 1-x\n\\f4\\fs20  is thus the probability that the individual will be considered \\'93absorbed\\'94, as discussed below.  In this manner, the concept of \\'93out of bounds\\'94 is treated as a probability by this method, rather than a binary state.\\\nThe spatial kernel type \n\\f3\\fs18 functionType\n\\f4\\fs20  must be one of \n\\f3\\fs18 \"f\"\n\\f4\\fs20 , \n\\f3\\fs18 \"l\"\n\\f4\\fs20 , \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , with the ellipsis parameters \n\\f3\\fs18 ...\n\\f4\\fs20  supplying kernel configuration parameters appropriate for that kernel type; see \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20  for further details.  As with \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 , the ellipsis parameters that follow \n\\f3\\fs18 functionType\n\\f4\\fs20  may each, independently, be either a singleton or a vector of length equal to \n\\f3\\fs18 n\n\\f4\\fs20 .  This allows each individual\\'92s position to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.  (However, other parameters such as \n\\f3\\fs18 boundary\n\\f4\\fs20 , \n\\f3\\fs18 maxDistance\n\\f4\\fs20 , and \n\\f3\\fs18 functionType\n\\f4\\fs20  must be the same for all of the points, in the present design.)\\\nThe returned vector contains individuals that did not survive the dispersal process.  For \n\\f3\\fs18 \"absorbing\"\n\\f4\\fs20  boundaries, this will contain the individuals that attempted to disperse to a point considered \\'93out of bounds\\'94 as described above, and in most cases the caller will then kill those individuals \\'96 probably by passing them to \n\\f3\\fs18 killIndividuals()\n\\f4\\fs20 , but perhaps by setting their \n\\f3\\fs18 fitnessScaling\n\\f4\\fs20  to zero.  (The positions of the individuals in the returned vector will be the out-of-bounds positions that were drawn for them; rather than killing those individuals, the caller could conceivably handle them in some other way.)  For all other boundary conditions, the returned vector of individuals will be empty and may be ignored by the caller.\\\nSee also the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  methods \n\\f3\\fs18 sampleNearbyPoint()\n\\f4\\fs20  and \n\\f3\\fs18 sampleImprovedNearbyPoint()\n\\f4\\fs20 , which are in some ways conceptually similar to this method.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome>\\'a0chromosomes\\'a0=\\'a0NULL], [Ni$\\'a0index\\'a0=\\'a0NULL], [logical$\\'a0includeNulls\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing the subpopulation\\'92s haplosomes that correspond to the chromosomes passed in \n\\f3\\fs18 chromosomes\n\\f4\\fs20  (following the order of the \n\\f3\\fs18 chromosomes\n\\f4\\fs20  property of \n\\f3\\fs18 Individual\n\\f4\\fs20 ).  Chromosomes can be specified by id (\n\\f3\\fs18 integer\n\\f4\\fs20 ), by symbol (\n\\f3\\fs18 string\n\\f4\\fs20 ) or by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  objects themselves; if \n\\f3\\fs18 NULL\n\\f4\\fs20  is passed (the default), all chromosomes defined for the species are used, in the order in which they were defined.\\\nThis method is equivalent to calling \n\\f3\\fs18 haplosomesForChromosomes(chromosomes, index, includeNulls)\n\\f4\\fs20  on \n\\f3\\fs18 subpop.individuals\n\\f4\\fs20 , where \n\\f3\\fs18 subpop\n\\f4\\fs20  is the target subpopulation.  It therefore appends together the specified haplosomes from each individual in the subpopulation to form a single vector.  See the documentation for the \n\\f3\\fs18 Individual\n\\f4\\fs20  method \n\\f3\\fs18 haplosomesForChromosomes()\n\\f4\\fs20  for further details, such as on the meaning of the \n\\f3\\fs18 index\n\\f4\\fs20  and \n\\f3\\fs18 includeNulls\n\\f4\\fs20  parameters.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)outputMSSample(integer$\\'a0sampleSize, [logical$\\'a0replace\\'a0=\\'a0T], [string$\\'a0requestedSex\\'a0=\\'a0\"*\"], [Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [logical$\\'a0filterMonomorphic\\'a0=\\'a0F], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output a random sample from the subpopulation in MS format.  Positions in the output will span the interval [0,1].  A sample of non-null haplosomes (not entire individuals, note) of size \n\\f3\\fs18 sampleSize\n\\f4\\fs20  from the subpopulation will be output.  The sample may be done either with or without replacement, as specified by \n\\f3\\fs18 replace\n\\f4\\fs20 ; the default is to sample with replacement.  A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 requestedSex\n\\f4\\fs20 ; passing \n\\f3\\fs18 \"*\"\n\\f4\\fs20 , the default, indicates that haplosomes from individuals should be selected randomly, without respect to sex.  If the sampling options provided by this method are not adequate, see the \n\\f3\\fs18 outputHaplosomesToMS()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  for a more flexible low-level option.\\\nIf the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\\\nIf \n\\f3\\fs18 filterMonomorphic\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), all mutations that are present in the sample will be included in the output.  This means that some mutations may be included that are actually monomorphic within the sample (i.e., that exist in \n\\f1\\i every\n\\f4\\i0  sampled haplosome, and are thus apparently fixed).  These may be filtered out with \n\\f3\\fs18 filterMonomorphic = T\n\\f4\\fs20  if desired; note that this option means that some mutations that do exist in the sampled haplosomes might not be included in the output, simply because they exist in every sampled haplosome.\\\nThe \n\\f3\\fs18 chromosome\n\\f4\\fs20  parameter identifies the chromosome for which the sample of haplosomes should be taken.  The default of \n\\f3\\fs18 NULL\n\\f4\\fs20  may be used only in single-chromosome models where the choice of chromosome is unambiguous.  In multi-chromosome models, chromosome must be non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ; it must specify the chromosome by id (\n\\f3\\fs18 integer\n\\f4\\fs20 ), by symbol (\n\\f3\\fs18 string\n\\f4\\fs20 ) or by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object itself.\\\nSee \n\\f3\\fs18 outputSample()\n\\f4\\fs20  and \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)outputSample(integer$\\'a0sampleSize, [logical$\\'a0replace\\'a0=\\'a0T], [string$\\'a0requestedSex\\'a0=\\'a0\"*\"], [Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output a random sample from the subpopulation in SLiM\\'92s native format.  A sample of non-null haplosomes (not entire individuals, note) of size \n\\f3\\fs18 sampleSize\n\\f4\\fs20  from the subpopulation will be output.  The sample may be done either with or without replacement, as specified by \n\\f3\\fs18 replace\n\\f4\\fs20 ; the default is to sample with replacement.  A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 requestedSex\n\\f4\\fs20 ; passing \n\\f3\\fs18 \"*\"\n\\f4\\fs20 , the default, indicates that haplosomes from individuals should be selected randomly, without respect to sex.  If the sampling options provided by this method are not adequate, see the \n\\f3\\fs18 outputHaplosomes()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  for a more flexible low-level option.\\\nIf the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\\\nThe \n\\f3\\fs18 chromosome\n\\f4\\fs20  parameter identifies the chromosome for which the sample of haplosomes should be taken.  The default of \n\\f3\\fs18 NULL\n\\f4\\fs20  may be used only in single-chromosome models where the choice of chromosome is unambiguous.  In multi-chromosome models, chromosome must be non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ; it must specify the chromosome by id (\n\\f3\\fs18 integer\n\\f4\\fs20 ), by symbol (\n\\f3\\fs18 string\n\\f4\\fs20 ) or by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object itself.\\\nSee \n\\f3\\fs18 outputMSSample()\n\\f4\\fs20  and \n\\f3\\fs18 outputVCFSample()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)outputVCFSample(integer$\\'a0sampleSize, [logical$\\'a0replace\\'a0=\\'a0T], [string$\\'a0requestedSex\\'a0=\\'a0\"*\"], [logical$\\'a0outputMultiallelics\\'a0=\\'a0T], [Ns$\\'a0filePath\\'a0=\\'a0NULL], [logical$\\'a0append\\'a0=\\'a0F], [logical$\\'a0simplifyNucleotides\\'a0=\\'a0F], [logical$\\'a0outputNonnucleotides\\'a0=\\'a0T], [logical$\\'a0groupAsIndividuals\\'a0=\\'a0T], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Output a random sample from the subpopulation in VCF format.  A sample of individuals (not haplosomes, note \\'96 unlike the \n\\f3\\fs18 outputSample()\n\\f4\\fs20  and \n\\f3\\fs18 outputMSSample()\n\\f4\\fs20  methods) of size \n\\f3\\fs18 sampleSize\n\\f4\\fs20  from the subpopulation will be output.  The sample may be done either with or without replacement, as specified by \n\\f3\\fs18 replace\n\\f4\\fs20 ; the default is to sample with replacement.  A particular sex of individuals may be requested for the sample, for simulations in which sex is enabled, by passing \n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20  for \n\\f3\\fs18 requestedSex\n\\f4\\fs20 ; passing \n\\f3\\fs18 \"*\"\n\\f4\\fs20 , the default, indicates that individuals should be selected randomly, without respect to sex.  If the sampling options provided by this method are not adequate, see the \n\\f3\\fs18 outputHaplosomesToVCF()\n\\f4\\fs20  method of \n\\f3\\fs18 Haplosome\n\\f4\\fs20  for a more flexible low-level option.\\\nIf the optional parameter \n\\f3\\fs18 filePath\n\\f4\\fs20  is \n\\f3\\fs18 NULL\n\\f4\\fs20  (the default), output will be sent to Eidos\\'92s output stream.  Otherwise, output will be sent to the filesystem path specified by \n\\f3\\fs18 filePath\n\\f4\\fs20 , overwriting that file if \n\\f3\\fs18 append\n\\f4\\fs20  if \n\\f3\\fs18 F\n\\f4\\fs20 , or appending to the end of it if \n\\f3\\fs18 append\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .\\\nThe parameters \n\\f3\\fs18 outputMultiallelics\n\\f4\\fs20 , \n\\f3\\fs18 simplifyNucleotides\n\\f4\\fs20 , \n\\f3\\fs18 outputNonnucleotides\n\\f4\\fs20 , and \n\\f3\\fs18 groupAsIndividuals\n\\f4\\fs20  affect the format of the output produced.\\\nThe \n\\f3\\fs18 chromosome\n\\f4\\fs20  parameter identifies the chromosome for which haplosomes of the sampled individuals should be output.  The default of \n\\f3\\fs18 NULL\n\\f4\\fs20  may be used only in single-chromosome models where the choice of chromosome is unambiguous.  In multi-chromosome models, chromosome must be non-\n\\f3\\fs18 NULL\n\\f4\\fs20 ; it must specify the chromosome by id (\n\\f3\\fs18 integer\n\\f4\\fs20 ), by symbol (\n\\f3\\fs18 string\n\\f4\\fs20 ) or by the \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object itself.  The \n\\f3\\fs18 symbol\n\\f4\\fs20  property of the chromosome will be output in the \n\\f3\\fs18 CHROM\n\\f4\\fs20  field of call lines in the VCF output.\\\nSee \n\\f3\\fs18 outputMSSample()\n\\f4\\fs20  and \n\\f3\\fs18 outputSample()\n\\f4\\fs20  for other output formats.  Output is generally done in a \n\\f3\\fs18 late()\n\\f4\\fs20  event, so that the output reflects the state of the simulation at the end of a tick.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)pointDeviated(integer$\\'a0n, float\\'a0point, string$\\'a0boundary, numeric$\\'a0maxDistance, string$\\'a0functionType, ...)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector containing \n\\f3\\fs18 n\n\\f4\\fs20  points that are derived from \n\\f3\\fs18 point\n\\f4\\fs20  by adding a deviation drawn from a dispersal kernel (specified by \n\\f3\\fs18 maxDistance\n\\f4\\fs20 , \n\\f3\\fs18 functionType\n\\f4\\fs20 , and the ellipsis parameters \n\\f3\\fs18 ...\n\\f4\\fs20 , as detailed below) and then applying a boundary condition specified by \n\\f3\\fs18 boundary\n\\f4\\fs20 .  This method therefore performs the steps of a simple dispersal algorithm in a single vectorized call.  See \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  for an even more efficient approach.\\\nThe parameter \n\\f3\\fs18 point\n\\f4\\fs20  may contain a single point which is deviated and bounded \n\\f3\\fs18 n\n\\f4\\fs20  independent times, or may contain \n\\f3\\fs18 n\n\\f4\\fs20  points each of which is deviated and bounded.  In any case, each point in \n\\f3\\fs18 point\n\\f4\\fs20  should match the dimensionality of the model \\'96 one element in a 1D model, two elements in a 2D model, or three elements in a 3D model.  This method should not be called in a non-spatial model.\\\nThe dispersal kernel is specified similarly to other kernel-based methods, such as \n\\f3\\fs18 setInteractionFunction()\n\\f4\\fs20  and \n\\f3\\fs18 smooth()\n\\f4\\fs20 .  For \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 , \n\\f3\\fs18 functionType\n\\f4\\fs20  may be \n\\f3\\fs18 \"f\"\n\\f4\\fs20  with no ellipsis arguments \n\\f3\\fs18 ...\n\\f4\\fs20  to use a flat kernel out to \n\\f3\\fs18 maxDistance\n\\f4\\fs20 ; \n\\f3\\fs18 \"l\"\n\\f4\\fs20  with no ellipsis arguments for a kernel that decreases linearly from the center to zero at \n\\f3\\fs18 maxDistance\n\\f4\\fs20 ; \n\\f3\\fs18 \"e\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  lambda (rate) parameter for a negative exponential function; \n\\f3\\fs18 \"n\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  sigma (standard deviation) parameter for a Gaussian function; or \n\\f3\\fs18 \"t\"\n\\f4\\fs20 , in which case the ellipsis should supply a \n\\f3\\fs18 numeric$\n\\f4\\fs20  degrees of freedom and a \n\\f3\\fs18 numeric$\n\\f4\\fs20  scale parameter for a \n\\f1\\i t\n\\f4\\i0 -distribution function.  The Cauchy (\n\\f3\\fs18 \"c\"\n\\f4\\fs20 ) kernel is not supported by \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20  since it is not well-behaved for this purpose, and the Student\\'92s \n\\f1\\i t\n\\f4\\i0  (\n\\f3\\fs18 \"t\"\n\\f4\\fs20 ) kernel is not allowed in 3D models at present simply because it hasn\\'92t been implemented.  See the \n\\f3\\fs18 InteractionType\n\\f4\\fs20  class documentation for more detailed discussion of the available kernel types and their parameters and probability distribution functions.  For \n\\f3\\fs18 pointDeviated()\n\\f4\\fs20 , the ellipsis parameters that follow \n\\f3\\fs18 functionType\n\\f4\\fs20  may each, independently, be either a singleton or a vector of length equal to \n\\f3\\fs18 n\n\\f4\\fs20 .  This allows each point to be deviated with a different kernel, representing, for example, the movements of individuals with differing dispersal capabilities/propensities.  (However, other parameters such as \n\\f3\\fs18 boundary\n\\f4\\fs20 , \n\\f3\\fs18 maxDistance\n\\f4\\fs20 , and \n\\f3\\fs18 functionType\n\\f4\\fs20  must be the same for all of the points, in the present design.)\\\nThe random points returned from this method are drawn from the probability distribution that is radially symmetric and has density proportional to the kernel \\'96 in other words, at distance \n\\f1\\i r\n\\f4\\i0  the density is proportional to the kernel type referred to by \n\\f3\\fs18 functionType\n\\f4\\fs20 .  (Said another way, the shape of the \n\\f1\\i cross-section\n\\f4\\i0  through the probability density function is given by the kernel.)  For instance, the value of the type \n\\f3\\fs18 \"e\"\n\\f4\\fs20  (exponential) kernel with rate \n\\f1\\i a\n\\f4\\i0  at \n\\f1\\i r\n\\f4\\i0  is proportional to exp(\\uc0\\u8722 \n\\f1\\i ar\n\\f4\\i0 ), and so in 2D, the probability density that this method with kernel type \n\\f3\\fs18 \"e\"\n\\f4\\fs20  draws from has density proportional to p(\n\\f1\\i x\n\\f4\\i0 ,\\'a0\n\\f1\\i y\n\\f4\\i0 )\\'a0=\\'a0exp(\\uc0\\u8722 \n\\f1\\i a\n\\f4\\i0 \\'a0sqrt(\n\\f1\\i x\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0+\\'a0\n\\f1\\i y\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub )), since \n\\f1\\i r\n\\f4\\i0 \\'a0=\\'a0sqrt(x\n\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0+\\'a0y\n\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub ) is the distance.  Note that the \n\\f1\\i distribution of the distance\n\\f4\\i0  is not given by the kernel except in 1D: in the type\\'a0\n\\f3\\fs18 \"e\"\n\\f4\\fs20 \\'a0example, the distribution of the distance in 1D is exponential, while in 2D it has density proportional to \n\\f1\\i r\n\\f4\\i0 \\'a0exp(\\uc0\\u8722 \n\\f1\\i ar\n\\f4\\i0 ) (i.e., Gamma with shape parameter 1).  For another example, the value of the type \n\\f3\\fs18 \"n\"\n\\f4\\fs20  (Normal) kernel at \n\\f1\\i r\n\\f4\\i0  with standard deviation 1 is proportional to exp(\\uc0\\u8722 \n\\f1\\i r\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0/\\'a02), and so the density is proportional to\\'a0p(\n\\f1\\i x\n\\f4\\i0 ,\\'a0\n\\f1\\i y\n\\f4\\i0 )\\'a0=\\'a0exp(\\uc0\\u8722 (\n\\f1\\i x\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0+\\'a0\n\\f1\\i y\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub )\\'a0/\\'a02).  This is the standard bivariate Normal, and equivalent to drawing independent Normals for the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i y\n\\f4\\i0  directions; however, the Normal is the \n\\f1\\i only\n\\f4\\i0  distribution for which independent draws along each axis will result in a radially symmetric distribution.  The distribution of the distance in 2D with type \n\\f3\\fs18 \"n\"\n\\f4\\fs20  is proportional to \n\\f1\\i r\n\\f4\\i0 \\'a0exp(\\uc0\\u8722 \n\\f1\\i r\n\\f4\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0/\\'a02), i.e., Rayleigh.\\\nThe boundary condition must be one of \n\\f3\\fs18 \"none\"\n\\f4\\fs20 , \n\\f3\\fs18 \"periodic\"\n\\f4\\fs20 , \n\\f3\\fs18 \"reflecting\"\n\\f4\\fs20 , \n\\f3\\fs18 \"stopping\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20 .  For \n\\f3\\fs18 \"none\"\n\\f4\\fs20 , no boundary condition is enforced; the deviated points are simply returned as is.  For \n\\f3\\fs18 \"periodic\"\n\\f4\\fs20 , \n\\f3\\fs18 \"reflecting\"\n\\f4\\fs20 , and \n\\f3\\fs18 \"stopping\"\n\\f4\\fs20 , the boundary condition is enforced just as it is by the \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20 , \n\\f3\\fs18 pointReflected()\n\\f4\\fs20 , and \n\\f3\\fs18 pointStopped()\n\\f4\\fs20  methods; see their documentation for further details.  For \n\\f3\\fs18 \"reprising\"\n\\f4\\fs20 , if the deviated point is out of bounds a new deviated point will be chosen, based upon the same original point, until a point inside bounds is obtained.  Note that absorbing boundaries (for which being out-of-bounds is lethal) would need to be implemented in script; this method cannot enforce them.  (Note, however, that the \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  method of \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  can enforce absorbing boundaries.)\\\nNote that for the typical usage case, in which \n\\f3\\fs18 point\n\\f4\\fs20  comes from the \n\\f3\\fs18 spatialPosition\n\\f4\\fs20  property for a vector of individuals, and the result is then set back onto the same vector of individuals using the \n\\f3\\fs18 setSpatialPosition()\n\\f4\\fs20  method, the \n\\f3\\fs18 deviatePositions()\n\\f4\\fs20  method provides an even more efficient alternative.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(logical)pointInBounds(float\\'a0point)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nReturns \n\\f3\\fs18 T\n\\f4\\fs20  if \n\\f3\\fs18 point\n\\f4\\fs20  is inside the spatial boundaries of the subpopulation, \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.  For example, for a simulation with \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  dimensionality, if \n\\f3\\fs18 point\n\\f4\\fs20  contains exactly two values constituting an (\n\\f1\\i x\n\\f4\\i0 ,\n\\f1\\i y\n\\f4\\i0 ) point, the result will be \n\\f3\\fs18 T\n\\f4\\fs20  if and only if \n\\f3\\fs18 ((point[0]>=x0) & (point[0]<=x1) & (point[1]>=y0) & (point[1]<=y1))\n\\f4\\fs20  given spatial bounds \n\\f3\\fs18 (x0, y0, x1, y1)\n\\f4\\fs20 .  This method is useful for implementing absorbing or reprising boundary conditions.  This may only be called in simulations for which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\nThe length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the dimensionality of the simulation; in other words, \n\\f3\\fs18 point\n\\f4\\fs20  may contain values comprising more than one point.  In this case, a \n\\f3\\fs18 logical\n\\f4\\fs20  vector will be returned in which each element is \n\\f3\\fs18 T\n\\f4\\fs20  if the corresponding point in \n\\f3\\fs18 point\n\\f4\\fs20  is inside the spatial boundaries of the subpopulation, \n\\f3\\fs18 F\n\\f4\\fs20  otherwise.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)pointPeriodic(float\\'a0point)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a revised version of \n\\f3\\fs18 point\n\\f4\\fs20  that has been brought inside the periodic spatial boundaries of the subpopulation (as specified by the \n\\f3\\fs18 periodicity\n\\f4\\fs20  parameter of \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ) by wrapping around periodic spatial boundaries.  In brief, if a coordinate of \n\\f3\\fs18 point\n\\f4\\fs20  lies beyond a periodic spatial boundary, that coordinate is wrapped around the boundary, so that it lies inside the spatial extent by the same magnitude that it previously lay outside, but on the opposite side of the space; in effect, the two edges of the periodic spatial boundary are seamlessly joined.  This is done iteratively until all coordinates lie inside the subpopulation\\'92s periodic boundaries.  Note that non-periodic spatial boundaries are not enforced by this method; they should be enforced using \n\\f3\\fs18 pointReflected()\n\\f4\\fs20 , \n\\f3\\fs18 pointStopped()\n\\f4\\fs20 , or some other means of enforcing boundary constraints (which can be used after \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  to bring the remaining coordinates into bounds; coordinates already brought into bounds by \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  will be unaffected by those calls).  This method is useful for implementing periodic boundary conditions.  This may only be called in simulations for which continuous space  and at least one periodic spatial dimension have been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\nThe length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the dimensionality of the simulation; in other words, \n\\f3\\fs18 point\n\\f4\\fs20  may contain values comprising more than one point.  In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)pointReflected(float\\'a0point)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a revised version of \n\\f3\\fs18 point\n\\f4\\fs20  that has been brought inside the spatial boundaries of the subpopulation by reflection.  In brief, if a coordinate of \n\\f3\\fs18 point\n\\f4\\fs20  lies beyond a spatial boundary, that coordinate is reflected across the boundary, so that it lies inside the boundary by the same magnitude that it previously lay outside the boundary.  This is done iteratively until all coordinates lie inside the subpopulation\\'92s boundaries.  This method is useful for implementing reflecting boundary conditions.  This may only be called in simulations for which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\nThe length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the dimensionality of the simulation; in other words, \n\\f3\\fs18 point\n\\f4\\fs20  may contain values comprising more than one point.  In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)pointStopped(float\\'a0point)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a revised version of \n\\f3\\fs18 point\n\\f4\\fs20  that has been brought inside the spatial boundaries of the subpopulation by clamping.  In brief, if a coordinate of \n\\f3\\fs18 point\n\\f4\\fs20  lies beyond a spatial boundary, that coordinate is set to exactly the position of the boundary, so that it lies on the edge of the spatial boundary.  This method is useful for implementing stopping boundary conditions.  This may only be called in simulations for which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\nThe length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the dimensionality of the simulation; in other words, \n\\f3\\fs18 point\n\\f4\\fs20  may contain values comprising more than one point.  In this case, each point will be processed as described above and a new vector containing all of the processed points will be returned.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(float)pointUniform([integer$\\'a0n\\'a0=\\'a01])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a new point (or points, for \n\\f3\\fs18 n\n\\f4\\fs20  > 1) generated from uniform draws for each coordinate, within the spatial boundaries of the subpopulation.  The returned vector will contain \n\\f3\\fs18 n\n\\f4\\fs20  points, each comprised of a number of coordinates equal to the dimensionality of the simulation, so it will be of total length \n\\f3\\fs18 n\n\\f4\\fs20 *dimensionality.  This may only be called in simulations for which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\kerning1\\expnd0\\expndtw0   See \n\\f3\\fs18 pointUniformWithMap()\n\\f4\\fs20  for an extension to this method which uses a spatial map to govern the probability of a particular point being chosen.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(float)pointUniformWithMap(integer$\\'a0n, so<SpatialMap>$\\'a0map)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a new point (or points, for \n\\f3\\fs18 n\n\\f4\\fs20  > 1) generated from uniform draws for each coordinate, within the spatial boundaries of the subpopulation, and rejection sampled using the spatial map \n\\f3\\fs18 map\n\\f4\\fs20  as described below.  The returned vector will contain \n\\f3\\fs18 n\n\\f4\\fs20  points, each comprised of a number of coordinates equal to the dimensionality of the simulation, so it will be of total length \n\\f3\\fs18 n\n\\f4\\fs20 *dimensionality.  This may only be called in simulations for which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .\\\nThe spatial map defined by \n\\f3\\fs18 map\n\\f4\\fs20  must be configured in a specific way.  First of all, it must be defined in, or added to, the target subpopulation (and thus, by implication, it must match the spatial bounds of the subpopulation, and its spatiality must be compatible with the subpopulation\\'92s dimensionality, as discussed in \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  and/or \n\\f3\\fs18 addSpatialMap()\n\\f4\\fs20 ).  Second, the values in the spatial map must represent \\'93habitability\\'94, in the following sense.  The value of \n\\f3\\fs18 map\n\\f4\\fs20  at a given drawn point is obtained, symbolized here by \n\\f3\\fs18 x\n\\f4\\fs20 .  Next, \n\\f3\\fs18 x\n\\f4\\fs20  is clamped to the range [\n\\f3\\fs18 0\n\\f4\\fs20 , \n\\f3\\fs18 1\n\\f4\\fs20 ]; values less than \n\\f3\\fs18 0\n\\f4\\fs20  become \n\\f3\\fs18 0\n\\f4\\fs20 , values greater than \n\\f3\\fs18 1\n\\f4\\fs20  become \n\\f3\\fs18 1\n\\f4\\fs20 .  The resulting \n\\f3\\fs18 x\n\\f4\\fs20  value is then interpreted as the probability that the point is considered \\'93within bounds\\'94 (as far as the spatial map is concerned; points that are outside the subpopulation\\'92s spatial bounds are \n\\f1\\i always\n\\f4\\i0  considered \\'93out of bounds\\'94).  Given this, \n\\f3\\fs18 1-x\n\\f4\\fs20  is thus the probability that the point will be redrawn because it fell out of bounds.  Each point will be redrawn repeatedly until a point considered \\'93within bounds\\'94 is obtained.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)removeSpatialMap(so<SpatialMap>$\\'a0map)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Removes the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object specified by \n\\f3\\fs18 map\n\\f4\\fs20  from the subpopulation.  The parameter \n\\f3\\fs18 map\n\\f4\\fs20  may be either a \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object, or a \n\\f3\\fs18 string\n\\f4\\fs20  name for spatial map.  The map must have been added to the subpopulation with \n\\f3\\fs18 addSpatialMap()\n\\f4\\fs20 ; if it has not been, an error results.  Removing spatial maps that are no longer in use is optional in most cases.  It is generally a good idea because it might decrease SLiM\\'92s memory footprint; also, it avoids an error if the subpopulation\\'92s spatial bounds are changed (see \n\\f3\\fs18 setSpatialBounds()\n\\f4\\fs20 ).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)removeSubpopulation(void)\n\\f5 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nRemoves this subpopulation from the model.  The subpopulation is immediately removed from the list of active subpopulations, and the symbol representing the subpopulation is undefined.  The subpopulation object itself remains unchanged until children are next generated (at which point it is deallocated), but it is no longer part of the simulation and should not be used.\\\nNote that this method is only for use in nonWF models, in which there is a distinction between a subpopulation being empty and a subpopulation being removed from the simulation; an empty subpopulation may be re-colonized by migrants, whereas as a removed subpopulation no longer exists at all.  WF models do not make this distinction; when a subpopulation is empty it is automatically removed.  WF models should therefore call \n\\f3\\fs18 setSubpopulationSize(0)\n\\f4\\fs20  instead of this method; \n\\f3\\fs18 setSubpopulationSize()\n\\f4\\fs20  is the standard way for WF models to change the subpopulation size, including to a size of \n\\f3\\fs18 0\n\\f4\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0\\cf2 \\expnd0\\expndtw0\\kerning0\n(object<Individual>)sampleIndividuals(integer$\\'a0size, [logical$\\'a0replace\\'a0=\\'a0F], [No<Individual>$\\'a0exclude\\'a0=\\'a0NULL], [Ns$\\'a0sex\\'a0=\\'a0NULL], [Ni$\\'a0tag\\'a0=\\'a0NULL], [Ni$\\'a0minAge\\'a0=\\'a0NULL], [Ni$\\'a0maxAge\\'a0=\\'a0NULL], [Nl$\\'a0migrant\\'a0=\\'a0NULL]\\kerning1\\expnd0\\expndtw0 , [Nl$\\'a0tagL0\\'a0=\\'a0NULL], [Nl$\\'a0tagL1\\'a0=\\'a0NULL], [Nl$\\'a0tagL2\\'a0=\\'a0NULL], [Nl$\\'a0tagL3\\'a0=\\'a0NULL], [Nl$\\'a0tagL4\\'a0=\\'a0NULL]\\expnd0\\expndtw0\\kerning0\n)\n\\f5 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of individuals, of size less than or equal to parameter \n\\f3\\fs18 size\n\\f4\\fs20 , sampled from the individuals in the target subpopulation.  Sampling is done without replacement if \n\\f3\\fs18 replace\n\\f4\\fs20  is \n\\f3\\fs18 F\n\\f4\\fs20  (the default), or with replacement if \n\\f3\\fs18 replace\n\\f4\\fs20  is \n\\f3\\fs18 T\n\\f4\\fs20 .  The remaining parameters specify constraints upon the pool of individuals that will be considered candidates for the sampling.  Parameter \n\\f3\\fs18 exclude\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a specific individual that should not be considered a candidate (typically the focal individual in some operation).  Parameter \n\\f3\\fs18 sex\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a sex (\n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20 ) for the individuals to be drawn, in sexual models.  Parameter \n\\f3\\fs18 tag\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a \n\\f3\\fs18 tag\n\\f4\\fs20  property value for the individuals to be drawn.  Parameters \n\\f3\\fs18 minAge\n\\f4\\fs20  and \n\\f3\\fs18 maxAge\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a minimum or maximum age for the individuals to be drawn, in nonWF models.  Parameter \n\\f3\\fs18 migrant\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a required value for the \n\\f3\\fs18 migrant\n\\f4\\fs20  property of the individuals to be drawn (so \n\\f3\\fs18 T\n\\f4\\fs20  will require that individuals be migrants, \n\\f3\\fs18 F\n\\f4\\fs20  will require that they not be).  Finally, parameters \n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a required value (\n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20 ) for the corresponding properties (\n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20 ) of the individuals to be drawn.  Note that if any \n\\f3\\fs18 tag\n\\f4\\fs20 /\n\\f3\\fs18 tagL\n\\f4\\fs20  parameter is specified as non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , that \n\\f3\\fs18 tag\n\\f4\\fs20 /\n\\f3\\fs18 tagL\n\\f4\\fs20  property must have a defined value for every individual in the subpopulation, otherwise an error may result (although this requirement will not necessarily be checked comprehensively by this method in every invocation).  If the candidate pool is smaller than the requested sample size, all eligible candidates will be returned (in randomized order); the result will be a zero-length vector if no eligible candidates exist (unlike \n\\f3\\fs18 sample()\n\\f4\\fs20 ).\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThis method is similar to getting the \n\\f3\\fs18 individuals\n\\f4\\fs20  property of the subpopulation, using operator \n\\f3\\fs18 []\n\\f4\\fs20  to select only individuals with the desired properties, and then using \n\\f3\\fs18 sample()\n\\f4\\fs20  to sample from that candidate pool.  However, besides being much simpler than the equivalent Eidos code, it is also much faster, and it does not fail if less than the full sample size is available.  See \n\\f3\\fs18 subsetIndividuals()\n\\f4\\fs20  for a similar method that returns a full subset, rather than a sample.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 \\'96\\'a0(void)setCloningRate(numeric\\'a0rate)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the cloning rate of this subpopulation.  The rate is changed to \n\\f3\\fs18 rate\n\\f4\\fs20 , which should be between 0.0 and 1.0, inclusive (see the SLiM manual for further details).  Clonal reproduction can be enabled in both non-sexual (i.e. hermaphroditic) and sexual simulations.  In non-sexual simulations, \n\\f3\\fs18 rate\n\\f4\\fs20  must be a singleton value representing the overall clonal reproduction rate for the subpopulation.  In sexual simulations, \n\\f3\\fs18 rate\n\\f4\\fs20  may be either a singleton (specifying the clonal reproduction rate for both sexes) or a vector containing two numeric values (the female and male cloning rates specified separately, at indices \n\\f3\\fs18 0\n\\f4\\fs20  and \n\\f3\\fs18 1\n\\f4\\fs20  respectively).  During mating and offspring generation, the probability that any given offspring individual will be generated by cloning \\'96 by asexual reproduction without gametes or meiosis \\'96 will be equal to the cloning rate (for its sex, in sexual simulations) set in the parental (not the offspring!) subpopulation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setMigrationRates(io<Subpopulation>\\'a0sourceSubpops, numeric\\'a0rates)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Set the migration rates to this subpopulation from the subpopulations in \n\\f3\\fs18 sourceSubpops\n\\f4\\fs20  to the corresponding rates specified in \n\\f3\\fs18 rates\n\\f4\\fs20 ; in other words, \n\\f3\\fs18 rates\n\\f4\\fs20  gives the expected fractions of the children in this subpopulation that will subsequently be generated from parents in the subpopulations \n\\f3\\fs18 sourceSubpops\n\\f4\\fs20 .  The \n\\f3\\fs18 rates\n\\f4\\fs20  parameter may be a singleton value, in which case that rate is used for all subpopulations in \n\\f3\\fs18 sourceSubpops\n\\f4\\fs20 .  This method will only set the migration fractions from the subpopulations given; migration rates from other subpopulations will be left unchanged (explicitly set a zero rate to turn off migration from a given subpopulation).  The type of \n\\f3\\fs18 sourceSubpops\n\\f4\\fs20  may be either \n\\f3\\fs18 integer\n\\f4\\fs20 , specifying subpopulations by identifier, or \n\\f3\\fs18 object\n\\f4\\fs20 , specifying subpopulations directly.\\\nIn general it is illegal to try to set the migration rate into a subpopulation from itself; that rate is, by definition, equal to the remainder after all migration from other subpopulations.  As a special case for convenience, it is legal to set a rate of \n\\f3\\fs18 0.0\n\\f4\\fs20  for all subpopulations in the species, including the target subpopulation.  For example, \n\\f3\\fs18 subpops.setMigrationRates(allSubpops, 0.0)\n\\f4\\fs20  will turn off all migration into the subpopulations in \n\\f3\\fs18 subpops\n\\f4\\fs20 .  The given rate of \n\\f3\\fs18 0.0\n\\f4\\fs20  from a subpop into itself is simply ignored, for this specific case only.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setSelfingRate(numeric$\\'a0rate)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the selfing rate of this subpopulation.  The rate is changed to \n\\f3\\fs18 rate\n\\f4\\fs20 , which should be between 0.0 and 1.0, inclusive (see the SLiM manual for further details).  Selfing can only be enabled in non-sexual (i.e. hermaphroditic) simulations.  During mating and offspring generation, the probability that any given offspring individual will be generated by selfing \\'96 by self-fertilization via gametes produced by meiosis by a single parent \\'96 will be equal to the selfing rate set in the parental (not the offspring!) subpopulation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setSexRatio(float$\\'a0sexRatio)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the sex ratio of this subpopulation to \n\\f3\\fs18 sexRatio\n\\f4\\fs20 .  As defined in SLiM, this is actually the fraction of the subpopulation that is male; in other words, the M:(M+F) ratio.  This will take effect when children are next generated; it does not change the current subpopulation state.  Unlike the selfing rate, the cloning rate, and migration rates, the sex ratio is deterministic: SLiM will generate offspring that exactly satisfy the requested sex ratio (within integer roundoff limits).\n\\f5 \\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setSpatialBounds(numeric\\'a0bounds)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nSet the spatial boundaries of the subpopulation to \n\\f3\\fs18 bounds\n\\f4\\fs20 .  This method may be called only for simulations in which continuous space has been enabled with \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 .  The length of \n\\f3\\fs18 bounds\n\\f4\\fs20  must be double the spatial dimensionality, so that it supplies both minimum and maximum values for each coordinate.  More specifically, for a dimensionality of \n\\f3\\fs18 \"x\"\n\\f4\\fs20 , \n\\f3\\fs18 bounds\n\\f4\\fs20  should supply \n\\f3\\fs18 (x0,\\'a0x1)\n\\f4\\fs20  values; for dimensionality \n\\f3\\fs18 \"xy\"\n\\f4\\fs20  it should supply \n\\f3\\fs18 (x0,\\'a0y0,\\'a0x1,\\'a0y1)\n\\f4\\fs20  values; and for dimensionality \n\\f3\\fs18 \"xyz\"\n\\f4\\fs20  it should supply \n\\f3\\fs18 (x0,\\'a0y0,\\'a0z0,\\'a0x1,\\'a0y1,\\'a0z1)\n\\f4\\fs20  (in that order).  These boundaries will be used by SLiMgui to calibrate the display of the subpopulation, and will be used by methods such as \n\\f3\\fs18 pointInBounds()\n\\f4\\fs20 , \n\\f3\\fs18 pointReflected()\n\\f4\\fs20 , \n\\f3\\fs18 pointStopped()\n\\f4\\fs20 , and \n\\f3\\fs18 pointUniform()\n\\f4\\fs20 .  The default spatial boundaries for all subpopulations span the interval \n\\f3\\fs18 [0,1]\n\\f4\\fs20  in each dimension.  Spatial dimensions that are periodic (as established with the \n\\f3\\fs18 periodicity\n\\f4\\fs20  parameter to \n\\f3\\fs18 initializeSLiMOptions()\n\\f4\\fs20 ) must have a minimum coordinate value of \n\\f3\\fs18 0.0\n\\f4\\fs20  (a restriction that allows the handling of periodicity to be somewhat more efficient).  The current spatial bounds for the subpopulation may be obtained through the \n\\f3\\fs18 spatialBounds\n\\f4\\fs20  property.\\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 The spatial bounds of a subpopulation are shared with any \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  objects added to the subpopulation.  For this reason, once a spatial map has been added to a subpopulation, the spatial bounds of the subpopulation can no longer be changed (because it would stretch or shrink the associated spatial map, which does not seem to make physical sense).  The bounds for a subpopulation should therefore be configured before any spatial maps are added to it.  If those bounds do need to change subsequently, any associated spatial maps must first be removed with \n\\f3\\fs18 removeSpatialMap()\n\\f4\\fs20 , to ensure model consistency.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0(void)setSubpopulationSize(integer$\\'a0size)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 Set the size of this subpopulation to \n\\f3\\fs18 size\n\\f4\\fs20  individuals (see the SLiM manual for further details).  This will take effect when children are next generated; it does not change the current subpopulation state.  Setting a subpopulation to a size of 0 does have some immediate effects that serve to disconnect it from the simulation: the subpopulation is removed from the list of active subpopulations, the subpopulation is removed as a source of migration for all other subpopulations, and the symbol representing the subpopulation is undefined.  In this case, the subpopulation itself remains unchanged until children are next generated (at which point it is deallocated), but it is no longer part of the simulation and should not be used.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (string)spatialMapColor(string$\\'a0name, numeric\\'a0value)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 This method has been deprecated, and may be removed in a future release of SLiM.\n\\f4\\b0   In SLiM 4.1 and later, use the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  method \n\\f3\\fs18 mapColor()\n\\f4\\fs20  instead, and see that method\\'92s documentation.  (This method differs only in taking a \n\\f3\\fs18 name\n\\f4\\fs20  parameter, which is used to look up the spatial map from those that have been added to the subpopulation.)\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(object<Image>$)spatialMapImage(string$\\'a0name, [Ni$\\'a0width\\'a0=\\'a0NULL], [Ni$\\'a0height\\'a0=\\'a0NULL], [logical$\\'a0centers\\'a0=\\'a0F], [logical$\\'a0color\\'a0=\\'a0T])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b\\fs20 \\cf2 This method has been deprecated, and may be removed in a future release of SLiM.\n\\f4\\b0   In SLiM 4.1 and later, use the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  method \n\\f3\\fs18 mapImage()\n\\f4\\fs20  instead, and see that method\\'92s documentation.  (This method differs only in taking a \n\\f3\\fs18 name\n\\f4\\fs20  parameter, which is used to look up the spatial map from those that have been added to the subpopulation.)\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\n\\f5 \\'a0\n\\f3 (float)spatialMapValue(so<SpatialMap>$\\'a0map, float\\'a0point)\n\\f5 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Looks up the spatial map specified by \n\\f3\\fs18 map\n\\f4\\fs20 , and uses its mapping machinery (as defined by the \n\\f3\\fs18 gridSize\n\\f4\\fs20 , \n\\f3\\fs18 values\n\\f4\\fs20 , and \n\\f3\\fs18 interpolate\n\\f4\\fs20  parameters to \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20 ) to translate the coordinates of \n\\f3\\fs18 point\n\\f4\\fs20  into a corresponding map value.  The parameter \n\\f3\\fs18 map\n\\f4\\fs20  may specify the map either as a \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  object, or by its \n\\f3\\fs18 string\n\\f4\\fs20  name; in either case, the map must have been added to the subpopulation.  The length of \n\\f3\\fs18 point\n\\f4\\fs20  must be equal to the spatiality of the spatial map; in other words, for a spatial map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , \n\\f3\\fs18 point\n\\f4\\fs20  must be of length \n\\f3\\fs18 2\n\\f4\\fs20 , specifying the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinates of the point to be evaluated.  Interpolation will automatically be used if it was enabled for the spatial map.  Point coordinates are clamped into the range defined by the spatial boundaries, even if the spatial boundaries are periodic; use \n\\f3\\fs18 pointPeriodic()\n\\f4\\fs20  to wrap the point coordinates first if desired.  See the documentation for \n\\f3\\fs18 defineSpatialMap()\n\\f4\\fs20  for information regarding the details of value mapping.\\\nBeginning in SLiM 3.3, \n\\f3\\fs18 point\n\\f4\\fs20  may contain more than one point to be looked up.  In this case, the length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of the spatiality of the spatial map; for a spatial map with spatiality \n\\f3\\fs18 \"xz\"\n\\f4\\fs20 , for example, the length of \n\\f3\\fs18 point\n\\f4\\fs20  must be an exact multiple of \n\\f3\\fs18 2\n\\f4\\fs20 , and successive pairs of elements from point (elements \n\\f3\\fs18 0\n\\f4\\fs20  and \n\\f3\\fs18 1\n\\f4\\fs20 , then elements \n\\f3\\fs18 2\n\\f4\\fs20  and \n\\f3\\fs18 3\n\\f4\\fs20 , etc.) will be taken as the \n\\f1\\i x\n\\f4\\i0  and \n\\f1\\i z\n\\f4\\i0  coordinates of the points to be evaluated.  This allows \n\\f3\\fs18 spatialMapValue()\n\\f4\\fs20  to be used in a vectorized fashion.\\\nThe \n\\f3\\fs18 mapValue()\n\\f4\\fs20  method of \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  provides the same functionality directly on the \n\\f3\\fs18 SpatialMap\n\\f4\\fs20  class; \n\\f3\\fs18 spatialMapValue()\n\\f4\\fs20  is provided on \n\\f3\\fs18 Subpopulation\n\\f4\\fs20  partly for backward compatibility, but also for convenience in some usage cases.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\'96\\'a0\\cf2 \\expnd0\\expndtw0\\kerning0\n(object<Individual>)subsetIndividuals([No<Individual>$\\'a0exclude\\'a0=\\'a0NULL], [Ns$\\'a0sex\\'a0=\\'a0NULL], [Ni$\\'a0tag\\'a0=\\'a0NULL], [Ni$\\'a0minAge\\'a0=\\'a0NULL], [Ni$\\'a0maxAge\\'a0=\\'a0NULL], [Nl$\\'a0migrant\\'a0=\\'a0NULL]\\kerning1\\expnd0\\expndtw0 , [Nl$\\'a0tagL0\\'a0=\\'a0NULL], [Nl$\\'a0tagL1\\'a0=\\'a0NULL], [Nl$\\'a0tagL2\\'a0=\\'a0NULL], [Nl$\\'a0tagL3\\'a0=\\'a0NULL], [Nl$\\'a0tagL4\\'a0=\\'a0NULL]\\expnd0\\expndtw0\\kerning0\n)\n\\f5 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Returns a vector of individuals subset from the individuals in the target subpopulation.  The parameters specify constraints upon the subset of individuals that will be returned.  Parameter \n\\f3\\fs18 exclude\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a specific individual that should not be included (typically the focal individual in some operation).  Parameter \n\\f3\\fs18 sex\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a sex (\n\\f3\\fs18 \"M\"\n\\f4\\fs20  or \n\\f3\\fs18 \"F\"\n\\f4\\fs20 ) for the individuals to be returned, in sexual models.  Parameter \n\\f3\\fs18 tag\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a \n\\f3\\fs18 tag\n\\f4\\fs20  property value for the individuals to be returned.  Parameters \n\\f3\\fs18 minAge\n\\f4\\fs20  and \n\\f3\\fs18 maxAge\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a minimum or maximum age for the individuals to be returned, in nonWF models.  Parameter \n\\f3\\fs18 migrant\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a required value for the \n\\f3\\fs18 migrant\n\\f4\\fs20  property of the individuals to be returned (so \n\\f3\\fs18 T\n\\f4\\fs20  will require that individuals be migrants, \n\\f3\\fs18 F\n\\f4\\fs20  will require that they not be).  Finally, parameters \n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20 , if non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , may specify a required value (\n\\f3\\fs18 T\n\\f4\\fs20  or \n\\f3\\fs18 F\n\\f4\\fs20 ) for the corresponding properties (\n\\f3\\fs18 tagL0\n\\f4\\fs20 , \n\\f3\\fs18 tagL1\n\\f4\\fs20 , \n\\f3\\fs18 tagL2\n\\f4\\fs20 , \n\\f3\\fs18 tagL3\n\\f4\\fs20 , and \n\\f3\\fs18 tagL4\n\\f4\\fs20 ) of the individuals to be returned.  Note that if any \n\\f3\\fs18 tag\n\\f4\\fs20 /\n\\f3\\fs18 tagL\n\\f4\\fs20  parameter is specified as non-\n\\f3\\fs18 NULL\n\\f4\\fs20 , that \n\\f3\\fs18 tag\n\\f4\\fs20 /\n\\f3\\fs18 tagL\n\\f4\\fs20  property must have a defined value for every individual in the subpopulation, otherwise an error may result (although this requirement will not necessarily be checked comprehensively by this method in every invocation).\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThis method is shorthand for getting the \n\\f3\\fs18 individuals\n\\f4\\fs20  property of the subpopulation, and then using operator \n\\f3\\fs18 []\n\\f4\\fs20  to select only individuals with the desired properties; besides being much simpler than the equivalent Eidos code, it is also much faster.  See \n\\f3\\fs18 sampleIndividuals()\n\\f4\\fs20  for a similar method that returns a sample taken from a chosen subset of individuals.\\\n\\pard\\pardeftab397\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\'96\\'a0(void)takeMigrants(object<Individual>\\'a0migrants)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 Immediately moves the individuals in \n\\f3\\fs18 migrants\n\\f4\\fs20  to the target subpopulation (removing them from their previous subpopulation).  Individuals in \n\\f3\\fs18 migrants\n\\f4\\fs20  that are already in the target subpopulation are unaffected.  Note that the indices and order of individuals and haplosomes in both the target and source subpopulations will change unpredictably as a side effect of this method.\\\nNote that this method is only for use in nonWF models, in which migration is managed manually by the model script.  In WF models, migration is managed automatically by the SLiM core based upon the migration rates set for each subpopulation with \n\\f3\\fs18 setMigrationRates()\n\\f4\\fs20 .\n\\f5 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 5.18  Class Substitution\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\b0 \\cf0 5.18.1  \n\\f2\\fs18 Substitution\n\\f1\\fs22  properties\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\i0\\fs18 \\cf2 chromosome => (object<Chromosome>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 The \n\\f3\\fs18 Chromosome\n\\f4\\fs20  object with which the mutation is associated.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 id => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier for this mutation.  Each mutation created during a run receives an immutable identifier that will be unique across the duration of the run, and that identifier is carried over to the \n\\f3\\fs18 Substitution\n\\f4\\fs20  object when the mutation fixes.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 fixationTick => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The tick in which this mutation fixed.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 mutationType => (object<MutationType>$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The \n\\f3\\fs18 MutationType\n\\f4\\fs20  from which this mutation was drawn.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\nnucleotide => (string$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 A \n\\f3\\fs18 string\n\\f4\\fs20  representing the nucleotide associated with this mutation; this will be \n\\f3\\fs18 \"A\"\n\\f4\\fs20 , \n\\f3\\fs18 \"C\"\n\\f4\\fs20 , \n\\f3\\fs18 \"G\"\n\\f4\\fs20 , or \n\\f3\\fs18 \"T\"\n\\f4\\fs20 .  If the mutation is not nucleotide-based, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf2 nucleotideValue => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf2 An \n\\f3\\fs18 integer\n\\f4\\fs20  representing the nucleotide associated with this mutation; this will be \n\\f3\\fs18 0\n\\f4\\fs20  (A), \n\\f3\\fs18 1\n\\f4\\fs20  (C), \n\\f3\\fs18 2\n\\f4\\fs20  (G), or \n\\f3\\fs18 3\n\\f4\\fs20  (T).  If the mutation is not nucleotide-based, this property is unavailable.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 originTick => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The tick in which this mutation arose.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 position => (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The position in the chromosome of this mutation.\n\\f5 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 selectionCoeff => (float$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The selection coefficient of the mutation, drawn from the distribution of fitness effects of its \n\\f3\\fs18 MutationType\n\\f5\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 subpopID <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 The identifier of the subpopulation in which this mutation arose.  This value is carried over from the \n\\f3\\fs18 Mutation\n\\f4\\fs20  object directly; if a \\'93tag\\'94 value was used in the \n\\f3\\fs18 Mutation\n\\f4\\fs20  object, that value will carry over to the corresponding \n\\f3\\fs18 Substitution\n\\f4\\fs20  object.  The \n\\f3\\fs18 subpopID\n\\f4\\fs20  in \n\\f3\\fs18 Substitution\n\\f4\\fs20  is a read-write property to allow it to be used as a \\'93tag\\'94 in the same way, if the origin subpopulation identifier is not needed.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f3\\fs18 \\cf0 tag <\\'96> (integer$)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f4\\fs20 \\cf0 A user-defined \n\\f3\\fs18 integer\n\\f4\\fs20  value.  The value of \n\\f3\\fs18 tag\n\\f4\\fs20  is carried over automatically from the original \n\\f3\\fs18 Mutation\n\\f4\\fs20  object.  Apart from that, the value of \n\\f3\\fs18 tag\n\\f4\\fs20  is not used by SLiM; it is free for you to use.\\\n\\pard\\pardeftab720\\ri720\\sb120\\sa60\\partightenfactor0\n\n\\f1\\i\\fs22 \\cf0 5.18.2  \n\\f2\\fs18 Substitution\n\\f1\\fs22  methods\\\n\\pard\\pardeftab397\\fi274\\ri720\\sb40\\sa40\\partightenfactor0\n\n\\f5\\i0 \\cf0 \\\n}"
  },
  {
    "path": "SLiMgui/SLiMHelpFunctions.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2761\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Bold;\\f1\\fnil\\fcharset0 Menlo-Regular;\\f2\\fswiss\\fcharset0 Optima-Regular;\n\\f3\\fswiss\\fcharset0 Optima-Italic;\\f4\\froman\\fcharset0 TimesNewRomanPSMT;\\f5\\fnil\\fcharset0 Menlo-Bold;\n\\f6\\fnil\\fcharset0 AppleColorEmoji;\\f7\\froman\\fcharset0 TimesNewRomanPS-ItalicMT;}\n{\\colortbl;\\red255\\green255\\blue255;\\red0\\green0\\blue0;\\red150\\green150\\blue150;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c0\\c0\\c0;\\cssrgb\\c65500\\c65500\\c65500;}\n\\margl1440\\margr1440\\vieww9000\\viewh8400\\viewkind0\n\\deftab397\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.1.  Initialization functions\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf0 (integer$)initializeAncestralNucleotides(is\\'a0sequence)\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nThis function, which may be called only in nucleotide-based models, supplies an ancestral nucleotide sequence for the model.  The \n\\f1\\fs18 sequence\n\\f2\\fs20  parameter may be an \n\\f1\\fs18 integer\n\\f2\\fs20  vector providing nucleotide values (A=0, C=1, G=2, T=3), or a \n\\f1\\fs18 string\n\\f2\\fs20  vector providing single-character nucleotides (\n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"C\"\n\\f2\\fs20 , \n\\f1\\fs18 \"G\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 ), or a singleton \n\\f1\\fs18 string\n\\f2\\fs20  providing the sequence as one string (\n\\f1\\fs18 \"ACGT...\"\n\\f2\\fs20 ), or a singleton \n\\f1\\fs18 string\n\\f2\\fs20  providing the filesystem path of a FASTA file which will be read in to provide the sequence (if the file contains than one sequence, the first sequence will be used).  Only A/C/G/T nucleotide values may be provided; other symbols, such as those for amino acids, gaps, or nucleotides of uncertain identity, are not allowed.  The two semantic meanings of \n\\f1\\fs18 sequence\n\\f2\\fs20  that involve a singleton \n\\f1\\fs18 string\n\\f2\\fs20  value are distinguished heuristically; a singleton \n\\f1\\fs18 string\n\\f2\\fs20  that contains only the letters ACGT will be assumed to be a nucleotide sequence rather than a filename.  The length of the ancestral sequence is returned.\\\nA utility function, \n\\f1\\fs18 randomNucleotides()\n\\f2\\fs20 , is provided by SLiM to assist in generating simple random nucleotide sequences.\n\\f3\\i \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\i0\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (object<Chromosome>$)initializeChromosome(integer$\\'a0id, [Ni$\\'a0length\\'a0=\\'a0NULL], [string$\\'a0type\\'a0=\\'a0\"A\"], [Ns$\\'a0symbol\\'a0=\\'a0NULL], [Ns$\\'a0name\\'a0=\\'a0NULL], [integer$\\'a0mutationRuns\\'a0=\\'a00])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calling this function, added in SLiM\\'a05, initiates the configuration of a chromosome in the species being initialized.  The new \n\\f1\\fs18 Chromosome\n\\f2\\fs20  object is returned, but it is still under construction and will error if used; see below for details.  That chromosome is then the \\'93focal chromosome\\'94 for subsequent genetic initialization functions \\'96 specifically, for \n\\f1\\fs18 initializeAncestralNucleotides()\n\\f2\\fs20 , \n\\f1\\fs18 initializeGeneConversion()\n\\f2\\fs20 , \n\\f1\\fs18 initializeGenomicElement()\n\\f2\\fs20 , \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20 , \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20 , and \n\\f1\\fs18 initializeRecombinationRate()\n\\f2\\fs20 .  If you wish to call \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  at all (which is not required), you must call it \n\\f3\\i before\n\\f2\\i0  calling any of those genetic initialization functions, so that the focal chromosome is created \n\\f3\\i before\n\\f2\\i0  being configured further; otherwise, SLiM will assume that you want a default single-chromosome model, and when \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  is called later (contradicting that assumption), an error will result.\\\nFurthermore, there are some other initialization functions must be called before \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  if they are called at all \\'96 specifically, \n\\f1\\fs18 initializeSex()\n\\f2\\fs20 , \n\\f1\\fs18 initializeTreeSeq()\n\\f2\\fs20 , \n\\f1\\fs18 initializeSpecies()\n\\f2\\fs20 , and \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20 .  This is so that \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  knows the context within which the new chromosome is to be created; if these methods have not been called when \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  is called, the default context is assumed (non-sexual, no tree-sequence recording, single-species, non-nucleotide-based), and an error will result downstream if one of those functions is later called (indicating that those assumptions might be incorrect).\\\nThe parameters to \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  configure the chromosome created.  They will be discussed out of order here, because that order of presentation will, I hope, be clearer.\\\nThere are three parameters that in some way identify the chromosome.  First, the required \n\\f1\\fs18 id\n\\f2\\fs20  parameter provides an \n\\f1\\fs18 integer\n\\f2\\fs20  identifier for the chromosome, which can be used to look up the chromosome later in the simulation; it can be any non-negative \n\\f1\\fs18 integer\n\\f2\\fs20  value, but must be unique within the species (two chromosomes in the same species cannot have the same \n\\f1\\fs18 id\n\\f2\\fs20 ).  Often it is an empirical chromosome number, for convenience and clarity; if modeling human chromosome 7, for example, you might provide \n\\f1\\fs18 7\n\\f2\\fs20 .  Second, the \n\\f1\\fs18 symbol\n\\f2\\fs20  parameter provides a \n\\f1\\fs18 string\n\\f2\\fs20  identifier for the chromosome, which can also be used to look up the chromosome later in the simulation.  If \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default) is passed for \n\\f1\\fs18 symbol\n\\f2\\fs20 , the chromosome\\'92s default \n\\f1\\fs18 symbol\n\\f2\\fs20  value will be the \n\\f1\\fs18 string\n\\f2\\fs20  version of its \n\\f1\\fs18 id\n\\f2\\fs20  (\n\\f1\\fs18 \"7\"\n\\f2\\fs20  for an \n\\f1\\fs18 id\n\\f2\\fs20  of \n\\f1\\fs18 7\n\\f2\\fs20 , for example).  The chromosome\\'92s \n\\f1\\fs18 symbol\n\\f2\\fs20  value will be used to identify the chromosome in output \\'96 in VCF output, for example, and in SLiMgui.  It must be non-empty (not \n\\f1\\fs18 \"\"\n\\f2\\fs20 ), no more than five characters long, and unique within the species.  Third, the \n\\f1\\fs18 name\n\\f2\\fs20  parameter can be any \n\\f1\\fs18 string\n\\f2\\fs20  value; if \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default) is passed, the \n\\f1\\fs18 name\n\\f2\\fs20  value will be \n\\f1\\fs18 \"\"\n\\f2\\fs20 .  The \n\\f1\\fs18 name\n\\f2\\fs20  is not used by SLiM, and can be used in any way you wish.\\\nThe \n\\f1\\fs18 length\n\\f2\\fs20  parameter sets the length, in base positions, of the chromosome, and must either be \n\\f1\\fs18 NULL\n\\f2\\fs20 , or an \n\\f1\\fs18 integer\n\\f2\\fs20  greater than or equal to \n\\f1\\fs18 1\n\\f2\\fs20 .  If \n\\f1\\fs18 length\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20 , the length of the chromosome will be calculated after all \n\\f1\\fs18 initialize()\n\\f2\\fs20  callbacks have been called, as the maximum position referenced by the chromosome\\'92s genomic elements, recombination map, mutation rate map, and (in nucleotide-based models) hotspot map; in other words, the chromosome will be sized to encompass all of the things it contains (which is also the behavior of the implicitly defined chromosome if \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  is not called).  Otherwise \\'96 if \n\\f1\\fs18 length\n\\f2\\fs20  is specified with an \n\\f1\\fs18 integer\n\\f2\\fs20  value \\'96 the chromosome\\'92s length will be fixed at that value, and the last valid base position in the chromosome will be \n\\f1\\fs18 length-1\n\\f2\\fs20 .  Attempting to add a genomic element or a mutation after the last position will raise an error.  Similarly, the last position of the chromosome must match the last position specified for recombination, mutation, and hotspot maps for that chromosome, but not all positions on a chromosome have to actually be used in the model (i.e., not all positions must be covered by a genomic element).\\\nThe \n\\f1\\fs18 type\n\\f2\\fs20  parameter specifies the type of chromosome to be created.  There are numerous options, and they are somewhat complex.  They are discussed in more detail in the documentation for class \n\\f1\\fs18 Chromosome\n\\f2\\fs20 , particularly their specific patterns of inheritance; but they are briefly summarized here for quick reference.  Note that \\'93\\'96\\'93 below indicates a null haplosome.  First of all, in hermaphroditic models \n\\f1\\fs18 type\n\\f2\\fs20  will generally be one of:\\\n\\pard\\pardeftab720\\li907\\ri360\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \"A\"\n\\f2\\fs20  (autosome), the default, specifying a diploid autosomal chromosome.\\\n\n\\f1\\fs18 \"H\"\n\\f2\\fs20  (haploid), specifying a haploid autosomal chromosome that recombines in biparental crosses.\\\n\n\\f1\\fs18 \"HF\"\n\\f2\\fs20  (haploid female-inherited), specifying a haploid autosomal chromosome that is inherited by both sexes from the first (female) parent in biparental crosses (also allowed in hermaphroditic models for inheritance that is always from the first parent).\\\n\n\\f1\\fs18 \"HM\"\n\\f2\\fs20  (haploid male-inherited), specifying a haploid autosomal chromosome that is inherited by both sexes from the second (male) parent in biparental crosses (also allowed in hermaphroditic models for inheritance that is always from the second parent).\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Some sex-chromosome types are supported only in sexual models:\\\n\\pard\\pardeftab720\\li907\\ri360\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \"X\"\n\\f2\\fs20  (X), specifying an X chromosome that is diploid (XX) in females, haploid (X\\'96) in males.\\\n\n\\f1\\fs18 \"Y\"\n\\f2\\fs20  (Y), specifying a Y chromosome that is haploid (Y) in males, absent (\\'96) in females.\\\n\n\\f1\\fs18 \"Z\"\n\\f2\\fs20  (Z), specifying a Z chromosome that is diploid (ZZ) in males, haploid (\\'96Z) in females.\\\n\n\\f1\\fs18 \"W\"\n\\f2\\fs20  (W), specifying a W chromosome that is haploid (W) in females, absent (\\'96) in males.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 And there are some haploid chromosome types that are also supported only in sexual models:\\\n\\pard\\pardeftab720\\li907\\ri360\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \"FL\"\n\\f2\\fs20  (female line), specifying a haploid autosomal chromosome that is inherited only by females, from the female parent, and is represented by a null haplosome in males.\\\n\n\\f1\\fs18 \"ML\"\n\\f2\\fs20  (male line), specifying a haploid autosomal chromosome that is inherited only by males, from the male parent, and is represented by a null haplosome in females.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 Finally, two additional values of \n\\f1\\fs18 type\n\\f2\\fs20 , \n\\f1\\fs18 \"H-\"\n\\f2\\fs20  and \n\\f1\\fs18 \"-Y\"\n\\f2\\fs20 , are supported for backward compatibility (not intended for use in new models).  They are discussed in the \n\\f1\\fs18 Chromosome\n\\f2\\fs20  documentation.\\\nThe \n\\f1\\fs18 mutationRuns\n\\f2\\fs20  parameter specifies how many mutation runs the chromosome should use.  Internally, SLiM divides haplosomes into a sequence of consecutive mutation runs, allowing more efficient internal computations.  The optimal mutation run length is short enough that each mutation run is relatively unlikely to be modified by mutation/recombination events when inherited, but long enough that each mutation run is likely to contain a relatively large number of mutations; these priorities are in tension, so an intermediate balance between them is generally optimal.  The optimal number of mutation runs will depend on the model\\'92s details, and may also depend upon the machine and even the compiler used to build SLiM.  If the \n\\f1\\fs18 mutationRuns\n\\f2\\fs20  parameter is not \n\\f1\\fs18 0\n\\f2\\fs20 , SLiM will use the value given as the number of mutation runs inside \n\\f1\\fs18 Haplosome\n\\f2\\fs20  objects for the chromosome.  If \n\\f1\\fs18 mutationRuns\n\\f2\\fs20  is \n\\f1\\fs18 0\n\\f2\\fs20  (the default), then the behavior depends upon a parameter to the \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20  function, \n\\f1\\fs18 doMutationRunExperiments\n\\f2\\fs20 .  If that flag is \n\\f1\\fs18 F\n\\f2\\fs20 , the behavior here is as if \n\\f1\\fs18 mutationRuns=1\n\\f2\\fs20  had been passed: one mutation run will be used, and mutation run experiments will not be conducted.  If that flag is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), then for \n\\f1\\fs18 mutationRuns=0\n\\f2\\fs20  SLiM will conduct experiments at runtime, using different mutation run counts, to try to determine the number of mutation runs that produces the best performance.  The value that SLiM\\'92s experiments determine may not be optimal, however, and in any case there is some overhead associated with conducting these experiments; for maximal performance it can thus be beneficial to determine the true optimal value for the simulation yourself, and set it explicitly using this parameter. Specifying the number of mutation runs is an advanced technique, but in some cases it can improve performance significantly.\\\nThe order in which \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  calls are made is generally unimportant, since the chromosomes assort independently of each other anyway, but SLiM will preserve the order in which they were defined for you (for the \n\\f1\\fs18 chromosomes\n\\f2\\fs20  property of Species, for display in SLiMgui, for writing out to VCF, and so forth).  All of the above types of chromosomes can be defined any number of times; you can have any number of autosomal chromosomes, for example.  In a sexual model you could even have multiple defined sex chromosomes \\'96 not in the sense of a female being XX, but in the sense of a female being X\n\\fs13\\fsmilli6667 \\sub 1\n\\fs20 \\nosupersub X\n\\fs13\\fsmilli6667 \\sub 1\n\\fs20 \\nosupersub X\n\\fs13\\fsmilli6667 \\sub 2\n\\fs20 \\nosupersub X\n\\fs13\\fsmilli6667 \\sub 2\n\\fs20 \\nosupersub , where X\n\\fs13\\fsmilli6667 \\sub 1\n\\fs20 \\nosupersub  and X\n\\fs13\\fsmilli6667 \\sub 2\n\\fs20 \\nosupersub  are two different kinds of X chromosome.  Similarly, you could define both an X and a Z for a species, if you wish; each would segregate correctly according to the sex of the offspring.  In sexual models in SLiM the sex of an offspring is determined randomly or given by the user in script; it is not a function of the sex chromosomes present in the individual, although the sex chromosomes present in the individual will correlate with sex.  In other words, SLiM does not know and does not care what sex-determination system the species is using; the chromosomes follow the sex, rather than the sex following the chromosomes.  This should allow any sex-determination system to be modeled, even if it is unusual, non-genetic, etc.\\\nAs stated above, the new \n\\f1\\fs18 Chromosome\n\\f2\\fs20  object is returned by this call, but it is still under construction so most of its methods and properties will error.  It will remain in this state until \n\\f1\\fs18 initialize()\n\\f2\\fs20  callbacks have completed, and will then become active and usable.  Until that point, there are only a handful of uses that are guaranteed to be allowed: storing it in a variable; remembering it with \n\\f1\\fs18 defineConstant()\n\\f2\\fs20 ; using the methods and properties of its superclasses, notably \n\\f1\\fs18 Dictionary\n\\f2\\fs20 ; setting SLiMgui display-related properties such as \n\\f1\\fs18 colorSubstitution\n\\f2\\fs20 ; getting and setting its \n\\f1\\fs18 tag\n\\f2\\fs20  property; and accessing those of its properties that were passed to the \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  call, specifically \n\\f1\\fs18 id\n\\f2\\fs20 , \n\\f1\\fs18 symbol\n\\f2\\fs20 , \n\\f1\\fs18 name\n\\f2\\fs20 , \n\\f1\\fs18 type\n\\f2\\fs20 , \n\\f1\\fs18 length\n\\f2\\fs20 , and \n\\f1\\fs18 lastPosition\n\\f2\\fs20 .  Its other properties, and all \n\\f1\\fs18 Chromosome\n\\f2\\fs20  methods, will raise an error while in this state.  This safeguard protects the new \n\\f1\\fs18 Chromosome\n\\f2\\fs20  object from being used while still in an inconsistent state.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(void)initializeGeneConversion(numeric$\\'a0nonCrossoverFraction, numeric$\\'a0meanLength, numeric$\\'a0simpleConversionFraction, [numeric$\\'a0bias\\'a0=\\'a00], [logical$\\'a0redrawLengthsOnFailure\\'a0=\\'a0F])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calling this function switches the recombination model from a \\'93simple crossover\\'94 model to a \\'93double-stranded break (DSB)\\'94 model, and configures the details of the gene conversion tracts that will therefore be modeled.  The fraction of DSBs that will be modeled as non-crossover events is given by \n\\f1\\fs18 nonCrossoverFraction\n\\f2\\fs20 .  The mean length of gene conversion tracts (whether associated with crossover or non-crossover events) is given by \n\\f1\\fs18 meanLength\n\\f2\\fs20 ; the actual extent of a gene conversion tract will be the sum of two independent draws from a geometric distribution with mean \n\\f1\\fs18 meanLength/2\n\\f2\\fs20 .  The fraction of gene conversion tracts that are modeled as \\'93simple\\'94 is given by \n\\f1\\fs18 simpleConversionFraction\n\\f2\\fs20 ; the remainder will be modeled as \\'93complex\\'94, involving repair of heteroduplex mismatches.  Finally, the \n\\f1\\fs18 GC\n\\f2\\fs20  bias during heteroduplex mismatch repair is given by \n\\f1\\fs18 bias\n\\f2\\fs20 , with the default of \n\\f1\\fs18 0.0\n\\f2\\fs20  indicating no bias, \n\\f1\\fs18 1.0\n\\f2\\fs20  indicating an absolute preference for \n\\f1\\fs18 G\n\\f2\\fs20 /\n\\f1\\fs18 C\n\\f2\\fs20  mutations over \n\\f1\\fs18 A\n\\f2\\fs20 /\n\\f1\\fs18 T\n\\f2\\fs20  mutations, and \n\\f1\\fs18 -1.0\n\\f2\\fs20  indicating an absolute preference for \n\\f1\\fs18 A\n\\f2\\fs20 /\n\\f1\\fs18 T\n\\f2\\fs20  mutations over \n\\f1\\fs18 G\n\\f2\\fs20 /\n\\f1\\fs18 C\n\\f2\\fs20  mutations.  A non-zero bias may only be set in nucleotide-based models.  This function, and the way that gene conversion is modeled, fundamentally changed in SLiM 3.3.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 Beginning in SLiM 4.1, the \n\\f1\\fs18 redrawLengthsOnFailure\n\\f2\\fs20  parameter can be used to modify the internal mechanics of layout of gene conversion tracts.  If it is \n\\f1\\fs18 F\n\\f2\\fs20  (the default, and the only behavior supported before SLiM 4.1), then if an attempt to lay out gene conversion tracts fails (because the tracts overlap each other, or overlap the start or end of the chromosome), SLiM will try again by drawing new positions for the tracts \\'96 essentially shuffling the tracts around to try to find positions for them that don\\'92t overlap.  If \n\\f1\\fs18 redrawLengthsOnFailure\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 , then if an attempt to lay out gene conversion tracts fails, SLiM will try again by drawing new lengths for the tracts, as well as new positions.  This makes it more likely that layout will succeed, but risks biasing the realized mean tract length downward from the requested mean length (since layout of long tracts is more likely fail due to overlap).  In either case, if SLiM attempts to lay out gene conversion tracts 100 times without success, an error will result.  That error indicates that the specified constraints for gene conversion are difficult to satisfy \\'96 tracts may commonly be so long that it is difficult or impossible to find an acceptable layout for them within the specified chromosome length.  Setting \n\\f1\\fs18 redrawLengthsOnFailure\n\\f2\\fs20  to \n\\f1\\fs18 T\n\\f2\\fs20  may mitigate this problem, at the price of biasing the mean tract length downward as discussed.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (object<GenomicElement>)initializeGenomicElement(io<GenomicElementType>\\'a0genomicElementType, [Ni\\'a0start\\'a0=\\'a0NULL], [Ni\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nAdd a genomic element to the chromosome at initialization time.  The \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  parameters give the first and last base positions to be spanned by the new genomic element.  The new element will be based upon the genomic element type identified by \n\\f1\\fs18 genomicElementType\n\\f2\\fs20 , which can be either an \n\\f1\\fs18 integer\n\\f2\\fs20 , representing the ID of the desired element type, or an \n\\f1\\fs18 object\n\\f2\\fs20  of type \n\\f1\\fs18 GenomicElementType\n\\f2\\fs20  specified directly.\\\nBeginning in SLiM 3.3, this function is vectorized: the \n\\f1\\fs18 genomicElementType\n\\f2\\fs20 , \n\\f1\\fs18 start\n\\f2\\fs20 , and \n\\f1\\fs18 end\n\\f2\\fs20  parameters do not have to be singletons.  In particular, \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  may be of any length, but must be equal in length; each \n\\f1\\fs18 start\n\\f2\\fs20 /\n\\f1\\fs18 end\n\\f2\\fs20  element pair will generate one new genomic element spanning the given base positions.  In this case, \n\\f1\\fs18 genomicElementType\n\\f2\\fs20  may still be a singleton, providing the genomic element type to be used for all of the new genomic elements, or it may be equal in length to \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20 , providing an independent genomic element type for each new element.  When adding a large number of genomic elements, it will be much faster to add them in order of ascending position with a vectorized call.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 Beginning in SLiM 5, passing \n\\f1\\fs18 NULL\n\\f2\\fs20  for \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  is allowed by \n\\f1\\fs18 initializeGenomicElement()\n\\f2\\fs20 , but only in one specific case: if the focal chromosome being configured was explicitly defined with \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20 , and that focal chromosome was given an explicit length (rather than a length of \n\\f1\\fs18 NULL\n\\f2\\fs20 ).  In that case, \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  may be \n\\f1\\fs18 NULL\n\\f2\\fs20  (\n\\f3\\i both\n\\f2\\i0  of them, not just one of them), indicating that the genomic element created should span the entire length of the focal chromosome.  Since \n\\f1\\fs18 NULL\n\\f2\\fs20  is now the default value for \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20 , this makes this common configuration very simple to set up.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThe return value provides the genomic element(s) created by the call, in the order in which they were specified in the parameters to \n\\f1\\fs18 initializeGenomicElement()\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (object<GenomicElementType>$)initializeGenomicElementType(is$\\'a0id, io<MutationType>\\'a0mutationTypes, numeric\\'a0proportions\\cf2 \\expnd0\\expndtw0\\kerning0\n, [Nf\\'a0mutationMatrix\\'a0=\\'a0NULL]\\cf0 \\kerning1\\expnd0\\expndtw0 )\n\\f4 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf0 Add a genomic element type at initialization time.  The \n\\f1\\fs18 id\n\\f2\\fs20  must not already be used for any genomic element type in the simulation.  The \n\\f1\\fs18 mutationTypes\n\\f2\\fs20  vector identifies the mutation types used by the genomic element, and the \n\\f1\\fs18 proportions\n\\f2\\fs20  vector should be of equal length, specifying the relative proportion of mutations that will be drawn from the corresponding mutation type (proportions do not need to add up to one; they are interpreted relatively).  The \n\\f1\\fs18 id\n\\f2\\fs20  parameter may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  giving the ID of the new genomic element type, or a \n\\f1\\fs18 string\n\\f2\\fs20  giving the name of the new genomic element type (such as \n\\f1\\fs18 \"g5\"\n\\f2\\fs20  to specify an ID of 5).  The \n\\f1\\fs18 mutationTypes\n\\f2\\fs20  parameter may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  vector representing the IDs of the desired mutation types, or an \n\\f1\\fs18 object\n\\f2\\fs20  vector of \n\\f1\\fs18 MutationType\n\\f2\\fs20  elements specified directly.  The global symbol for the new genomic element type is immediately available; the return value also provides the new object.\n\\f4 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2 \\cf2 \\expnd0\\expndtw0\\kerning0\nThe \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  by default, and in non-nucleotide-based models it must be \n\\f1\\fs18 NULL\n\\f2\\fs20 .  In nucleotide-based models, on the other hand, it must be non-\n\\f1\\fs18 NULL\n\\f2\\fs20 , and therefore must be supplied.  In that case, \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  should take one of two standard forms.  For sequence-based mutation rates that depend upon only the single nucleotide at a mutation site, \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  should be a 4\\'d74 \n\\f1\\fs18 float\n\\f2\\fs20  matrix, specifying mutation rates for an existing nucleotide state (rows from \n\\f1\\fs18 0\n\\f2\\fs20 \\'96\n\\f1\\fs18 3\n\\f2\\fs20  representing A/C/G/T) to each of the four possible derived nucleotide states (columns, with the same meaning).  The mutation rates in this matrix are absolute rates, per nucleotide per gamete; they will be used by SLiM directly unless they are multiplied by a factor from the hotspot map (see \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20 ).  Rates in \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  that involve the mutation of a nucleotide to itself (\n\\f1\\fs18 A\n\\f2\\fs20  to \n\\f1\\fs18 A\n\\f2\\fs20 , \n\\f1\\fs18 C\n\\f2\\fs20  to \n\\f1\\fs18 C\n\\f2\\fs20 , etc.) are not used by SLiM and must be \n\\f1\\fs18 0.0\n\\f2\\fs20  by convention.\\\nIt is important to note that the order of the rows and columns used in SLiM, A/C/G/T, is not a universal convention; other sources will present substitution-rate/transition-rate matrices using different conventions, and so care must be taken when importing such matrices into SLiM.\\\nFor sequence-based mutation rates that depend upon the trinucleotide sequence centered upon a mutation site (the adjacent bases to the left and right, in other words, as well as the mutating nucleotide itself), \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  should be a 64\\'d74 \n\\f1\\fs18 float\n\\f2\\fs20  matrix, specifying mutation rates for the central nucleotide of an existing trinucleotide sequence (rows from \n\\f1\\fs18 0\n\\f2\\fs20 \\'96\n\\f1\\fs18 63\n\\f2\\fs20 , representing codons as described in the documentation for the \n\\f1\\fs18 ancestralNucleotides()\n\\f2\\fs20  method of \n\\f1\\fs18 Chromosome\n\\f2\\fs20 ) to each of the four possible derived nucleotide states (columns from \n\\f1\\fs18 0\n\\f2\\fs20 \\'96\n\\f1\\fs18 3\n\\f2\\fs20  for A/C/G/T as before).  Note that in every case it is the central nucleotide of the trinucleotide sequence that is mutating, but rates can be specified independently based upon the nucleotides in the first and third positions as well, with this type of mutation matrix.\\\nSeveral helper functions are defined to construct common types of mutation matrices, such as \n\\f1\\fs18 mmJukesCantor()\n\\f2\\fs20  to create a mutation matrix for a Jukes\\'96Cantor model.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)initializeHotspotMap(numeric\\'a0multipliers, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 In nucleotide-based models, set the mutation rate \n\\f3\\i multiplier\n\\f2\\i0  along the chromosome.  Nucleotide-based models define sequence-based mutation rates that are set up with the \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  parameter to \n\\f1\\fs18 initializeGenomicElementType()\n\\f2\\fs20 .  If no hotspot map is specified by calling \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20 , a hotspot map with a multiplier of \n\\f1\\fs18 1.0\n\\f2\\fs20  across the whole chromosome is assumed (and so the sequence-based rates are the absolute mutation rates used by SLiM).  A hotspot map modifies the sequence-based rates by scaling them up in some regions, with multipliers greater than \n\\f1\\fs18 1.0\n\\f2\\fs20  (representing mutational hot spots), and/or scaling them down in some regions, with multipliers less than \n\\f1\\fs18 1.0\n\\f2\\fs20  (representing mutational cold spots).\\\nThere are two ways to call this function.  If the optional \n\\f1\\fs18 ends\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), then \n\\f1\\fs18 multipliers\n\\f2\\fs20  must be a singleton value that specifies a single multiplier to be used along the entire chromosome (typically \n\\f1\\fs18 1.0\n\\f2\\fs20 , but not required to be).  If, on the other hand, \n\\f1\\fs18 ends\n\\f2\\fs20  is supplied, then \n\\f1\\fs18 multipliers\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  must be the same length, and the values in \n\\f1\\fs18 ends\n\\f2\\fs20  must be specified in ascending order.  In that case, \n\\f1\\fs18 multipliers\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  taken together specify the multipliers to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f1\\fs18 ends\n\\f2\\fs20  should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).\\\nFor example, if the following call is made:\\\n\\pard\\pardeftab720\\ri720\\partightenfactor0\n\\cf2 \t\n\\f1\\fs18 initializeHotspotMap(c(1.0, 1.2), c(5000, 9999));\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 then the result is that the mutation rate multiplier for bases \n\\f1\\fs18 0\n\\f2\\fs20 ...\n\\f1\\fs18 5000\n\\f2\\fs20  (inclusive) will be \n\\f1\\fs18 1.0\n\\f2\\fs20  (and so the specified sequence-based mutation rates will be used verbatim), and the multiplier for bases \n\\f1\\fs18 5001\n\\f2\\fs20 ...\n\\f1\\fs18 9999\n\\f2\\fs20  (inclusive) will be \n\\f1\\fs18 1.2\n\\f2\\fs20  (and so the sequence-based mutation rates will be multiplied by 1.2 within the region).\\\nNote that mutations are generated by SLiM only within genomic elements, regardless of the hotspot map.  In effect, the hotspot map given is intersected with the coverage area of the genomic elements defined; areas outside of any genomic element are given a multiplier of zero.  There is no harm in supplying a hotspot map that specifies multipliers for areas outside of the genomic elements defined; the excess information is simply not used.\\\nIf the optional \n\\f1\\fs18 sex\n\\f2\\fs20  parameter is \n\\f1\\fs18 \"*\"\n\\f2\\fs20  (the default), then the supplied hotspot map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f1\\fs18 sex\n\\f2\\fs20  may be \n\\f1\\fs18 \"M\"\n\\f2\\fs20  or \n\\f1\\fs18 \"F\"\n\\f2\\fs20  instead, in which case the supplied hotspot map is used only for that sex (i.e., when generating a gamete from a parent of that sex).  In this case, two calls must be made to \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20 , one for each sex, even if a multiplier of \n\\f1\\fs18 1.0\n\\f2\\fs20  is desired for the other sex; no default hotspot map is supplied.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (object<InteractionType>$)initializeInteractionType(is$\\'a0id, string$\\'a0spatiality, [logical$\\'a0reciprocal\\'a0=\\'a0F], [numeric$\\'a0maxDistance\\'a0=\\'a0INF], [string$\\'a0sexSegregation\\'a0=\\'a0\"**\"])\n\\f4 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Add an interaction type at initialization time.  The \n\\f1\\fs18 id\n\\f2\\fs20  must not already be used for any interaction type in the simulation.  The \n\\f1\\fs18 id\n\\f2\\fs20  parameter may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  giving the ID of the new interaction type, or a \n\\f1\\fs18 string\n\\f2\\fs20  giving the name of the new interaction type (such as \n\\f1\\fs18 \"i5\"\n\\f2\\fs20  to specify an ID of 5).\\\nThe \n\\f1\\fs18 spatiality\n\\f2\\fs20  may be \n\\f1\\fs18 \"\"\n\\f2\\fs20 , for non-spatial interactions (i.e., interactions that do not depend upon the distance between individuals); \n\\f1\\fs18 \"x\"\n\\f2\\fs20 , \n\\f1\\fs18 \"y\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"z\"\n\\f2\\fs20  for one-dimensional interactions; \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , \n\\f1\\fs18 \"xz\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"yz\"\n\\f2\\fs20  for two-dimensional interactions; or \n\\f1\\fs18 \"xyz\"\n\\f2\\fs20  for three-dimensional interactions.  The dimensions referenced by spatiality must be defined as spatial dimensions with \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20 ; if the simulation has dimensionality \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , for example, then interactions in the simulation may have spatiality \n\\f1\\fs18 \"\"\n\\f2\\fs20 , \n\\f1\\fs18 \"x\"\n\\f2\\fs20 , \n\\f1\\fs18 \"y\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , but may not reference spatial dimension \n\\f3\\i z\n\\f2\\i0  and thus may not have spatiality \n\\f1\\fs18 \"xz\"\n\\f2\\fs20 , \n\\f1\\fs18 \"yz\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"xyz\"\n\\f2\\fs20 .  If no spatial dimensions have been configured, only non-spatial interactions may be defined.\\\nThe \n\\f1\\fs18 reciprocal\n\\f2\\fs20  flag may be \n\\f1\\fs18 T\n\\f2\\fs20 , in which case the interaction is guaranteed by the user to be \n\\f3\\i reciprocal\n\\f2\\i0 : whatever the interaction strength is for exerter B upon receiver A, it will be equal (in magnitude and sign) for exerter A upon receiver B.  In principle, this allows the \n\\f1\\fs18 InteractionType\n\\f2\\fs20  to reduce the amount of computation necessary by up to a factor of two (although it may or may not be used).  If \n\\f1\\fs18 reciprocal\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 , the interaction is not guaranteed to be reciprocal and each interaction will be computed independently.  The built-in interaction formulas are all reciprocal, but if you implement an \n\\f1\\fs18 interaction()\n\\f2\\fs20  callback, you must consider whether the callback you have implemented preserves reciprocality or not.  For this reason, the default is \n\\f1\\fs18 reciprocal=F\n\\f2\\fs20 , so that bugs are not inadvertently introduced by an invalid assumption of reciprocality.  See below for a note regarding reciprocality in sexual simulations when using the \n\\f1\\fs18 sexSegregation\n\\f2\\fs20  flag.\\\nThe \n\\f1\\fs18 maxDistance\n\\f2\\fs20  parameter supplies the maximum distance over which interactions of this type will be evaluated; at greater distances, the interaction strength is considered to be zero (for efficiency).  The default value of \n\\f1\\fs18 maxDistance\n\\f2\\fs20 , \n\\f1\\fs18 INF\n\\f2\\fs20  (positive infinity), indicates that there is no maximum interaction distance; note that this can make some interaction queries much less efficient, and is therefore not recommended.  In SLiM 3.1 and later, a warning will be issued if a spatial interaction type is defined with no maximum distance to encourage a maximum distance to be defined.\\\nThe \n\\f1\\fs18 sexSegregation\n\\f2\\fs20  parameter governs the applicability of the interaction to each sex, in sexual simulations.  It does not affect distance calculations in any way; it only modifies the way in which interaction strengths are calculated.  The default, \n\\f1\\fs18 \"**\"\n\\f2\\fs20 , implies that the interaction is felt by both sexes (the first character of the \n\\f1\\fs18 string\n\\f2\\fs20  value) and is exerted by both sexes (the second character of the \n\\f1\\fs18 string\n\\f2\\fs20  value).  Either or both characters may be \n\\f1\\fs18 M\n\\f2\\fs20  or \n\\f1\\fs18 F\n\\f2\\fs20  instead; for example, \n\\f1\\fs18 \"MM\"\n\\f2\\fs20  would indicate a male-male interaction, such as male-male competition, whereas \n\\f1\\fs18 \"FM\"\n\\f2\\fs20  would indicate an interaction influencing only female receivers that is influenced only by male exerters, such as male mating displays that influence female attraction.  This parameter may be set only to \n\\f1\\fs18 \"**\"\n\\f2\\fs20  unless sex has been enabled with \n\\f1\\fs18 initializeSex()\n\\f2\\fs20 .  Note that a value of \n\\f1\\fs18 sexSegregation\n\\f2\\fs20  other than \n\\f1\\fs18 \"**\"\n\\f2\\fs20  may imply some degree of non-reciprocality, but it is not necessary to specify \n\\f1\\fs18 reciprocal\n\\f2\\fs20  to be \n\\f1\\fs18 F\n\\f2\\fs20  for this reason; SLiM will take the sex-segregation of the interaction into account for you.  The value of \n\\f1\\fs18 reciprocal\n\\f2\\fs20  may therefore be interpreted as meaning: in those cases, if any, in which A interacts with B and B interacts with A, is the interaction strength guaranteed to be the same in both directions?  The \n\\f1\\fs18 sexSegregation\n\\f2\\fs20  parameter is shorthand for setting sex constraints on the interaction type using the \n\\f1\\fs18 setConstraints()\n\\f2\\fs20  method; see that method for a more extensive set of constraints that may be used.\\\nBy default, the interaction strength is \n\\f1\\fs18 1.0\n\\f2\\fs20  for all interactions within \n\\f1\\fs18 maxDistance\n\\f2\\fs20 .  Often it is desirable to change the interaction function using \n\\f1\\fs18 setInteractionFunction()\n\\f2\\fs20 ; modifying interaction strengths can also be achieved with \n\\f1\\fs18 interaction()\n\\f2\\fs20  callbacks if necessary.  In any case, interactions beyond \n\\f1\\fs18 maxDistance\n\\f2\\fs20  always have a strength of \n\\f1\\fs18 0.0\n\\f2\\fs20 , and the interaction strength of an individual with itself is always \n\\f1\\fs18 0.0\n\\f2\\fs20 , regardless of the interaction function or callbacks.\\\nThe global symbol for the new interaction type is immediately available; the return value also provides the new object.  Note that in multispecies models, \n\\f1\\fs18 initializeInteractionType()\n\\f2\\fs20  must be called from a non-species-specific \n\\f1\\fs18 interaction()\n\\f2\\fs20  callback (declared as \n\\f1\\fs18 species all initialize()\n\\f2\\fs20 ), since interactions are managed at the community level.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)initializeMutationRate(numeric\\'a0rates, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\n\\f4 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Set the mutation rate per base position per gamete.  To be precise, this mutation rate is the expected mean number of mutations that will occur per base position per gamete; note that this is different from how the recombination rate is defined (see \n\\f1\\fs18 initializeRecombinationRate()\n\\f2\\fs20 ).  The number of mutations that actually occurs at a given base position when generating an offspring haplosome is, in effect, drawn from a Poisson distribution with that expected mean (but under the hood SLiM uses a mathematically equivalent but much more efficient strategy).  It is possible for this Poisson draw to indicate that two or more new mutations have arisen at the same base position, particularly when the mutation rate is very high; in this case, the new mutations will be added to the site one at a time, and as always the mutation stacking policy will be followed.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nThere are two ways to call this function.  If the optional \n\\f1\\fs18 ends\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), then \n\\f1\\fs18 rates\n\\f2\\fs20  must be a singleton value that specifies a single mutation rate to be used along the entire chromosome.  If, on the other hand, \n\\f1\\fs18 ends\n\\f2\\fs20  is supplied, then \n\\f1\\fs18 rates\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  must be the same length, and the values in \n\\f1\\fs18 ends\n\\f2\\fs20  must be specified in ascending order.  In that case, \n\\f1\\fs18 rates\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  taken together specify the mutation rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f1\\fs18 ends\n\\f2\\fs20  should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).\\\nFor example, if the following call is made:\\\n\\pard\\pardeftab720\\ri720\\partightenfactor0\n\n\\f4 \\cf0 \\kerning1\\expnd0\\expndtw0 \t\n\\f1\\fs18 initializeMutationRate(c(1e-7, 2.5e-8), c(5000, 9999));\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nthen the result is that the mutation rate for bases \n\\f1\\fs18 0\n\\f2\\fs20 ...\n\\f1\\fs18 5000\n\\f2\\fs20  (inclusive) will be \n\\f1\\fs18 1e-7\n\\f2\\fs20 , and the rate for bases \n\\f1\\fs18 5001\n\\f2\\fs20 ...\n\\f1\\fs18 9999\n\\f2\\fs20  (inclusive) will be \n\\f1\\fs18 2.5e-8\n\\f2\\fs20 .\\\nNote that mutations are generated by SLiM only within genomic elements, regardless of the mutation rate map.  In effect, the mutation rate map given is intersected with the coverage area of the genomic elements defined; areas outside of any genomic element are given a mutation rate of zero.  There is no harm in supplying a mutation rate map that specifies rates for areas outside of the genomic elements defined; that rate information is simply not used.  The \n\\f1\\fs18 overallMutationRate\n\\f2\\fs20  family of properties on \n\\f1\\fs18 Chromosome\n\\f2\\fs20  provide the overall mutation rate after genomic element coverage has been taken into account, so it will reflect the rate at which new mutations will actually be generated in the simulation as configured.\\\nIf the optional \n\\f1\\fs18 sex\n\\f2\\fs20  parameter is \n\\f1\\fs18 \"*\"\n\\f2\\fs20  (the default), then the supplied mutation rate map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f1\\fs18 sex\n\\f2\\fs20  may be \n\\f1\\fs18 \"M\"\n\\f2\\fs20  or \n\\f1\\fs18 \"F\"\n\\f2\\fs20  instead, in which case the supplied mutation rate map is used only for that sex (i.e., when generating a gamete from a parent of that sex).  In this case, two calls must be made to \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20 , one for each sex, even if a rate of zero is desired for the other sex; no default mutation rate map is supplied.\n\\f3\\i \\\n\n\\f2\\i0 In nucleotide-based models, \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20  may not be called.  Instead, the desired sequence-based mutation rate(s) should be expressed in the \n\\f1\\fs18 mutationMatrix\n\\f2\\fs20  parameter to \n\\f1\\fs18 initializeGenomicElementType()\n\\f2\\fs20 .  If variation in the mutation rate along the chromosome is desired, \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20  should be used.\n\\f3\\i \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\i0 \\cf2 \\kerning1\\expnd0\\expndtw0 The \n\\f1\\fs18 initializeMutationRateFromFile()\n\\f2\\fs20  function is a useful convenience function if you wish to read the mutation rate map from a file.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)initializeMutationRateFromFile(string$\\'a0path, integer$\\'a0lastPosition, [float$\\'a0scale\\'a0=\\'a01.0e-08], [string$\\'a0sep\\'a0=\\'a0\"\\\\t\"], [string$\\'a0dec\\'a0=\\'a0\".\"], [string$\\'a0sex\\'a0=\\'a0\"*\"])\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Set a mutation rate map from data read from the file at \n\\f1\\fs18 path\n\\f2\\fs20 .  This function is essentially a wrapper for \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20  that uses \n\\f1\\fs18 readCSV()\n\\f2\\fs20  and passes the data through.  The file is expected to contain two columns of data.  The first column must be \n\\f1\\fs18 integer\n\\f2\\fs20  start positions for rate map regions; the first region should start at position \n\\f1\\fs18 0\n\\f2\\fs20  if the map\\'92s positions are \n\\f1\\fs18 0\n\\f2\\fs20 -based, or at position \n\\f1\\fs18 1\n\\f2\\fs20  if the map\\'92s positions are \n\\f1\\fs18 1\n\\f2\\fs20 -based; in the latter case, \n\\f1\\fs18 1\n\\f2\\fs20  will be subtracted from every position since SLiM uses \n\\f1\\fs18 0\n\\f2\\fs20 -based positions.  The second column must be \n\\f1\\fs18 float\n\\f2\\fs20  rates, relative to the scaling factor specified in \n\\f1\\fs18 scale\n\\f2\\fs20 ; for example, if a given rate is \n\\f1\\fs18 1.2\n\\f2\\fs20  and \n\\f1\\fs18 scale\n\\f2\\fs20  is \n\\f1\\fs18 1e-8\n\\f2\\fs20  (the default), the rate used will be \n\\f1\\fs18 1.2e-8\n\\f2\\fs20 .  No column header line should be present; the file should start immediately with numerical data.  The expected separator between columns is a tab character by default, but may be passed in \n\\f1\\fs18 sep\n\\f2\\fs20 ; the expected decimal separator is a period by default, but may be passed in \n\\f1\\fs18 dec\n\\f2\\fs20 .  Once read, the map is converted into a rate map specified with end positions, rather than start positions, and the position given by \n\\f1\\fs18 lastPosition\n\\f2\\fs20  is used as the end of the last rate region; it should be the last position of the chromosome.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 See \n\\f1\\fs18 readCSV()\n\\f2\\fs20  for further details on \n\\f1\\fs18 sep\n\\f2\\fs20  and \n\\f1\\fs18 dec\n\\f2\\fs20 , which are passed through to it; and see \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20  for details on how the rate map is validated and used, and how the \n\\f1\\fs18 sex\n\\f2\\fs20  parameter is used.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 This function is written in Eidos, and its source code can be viewed with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , so you can copy and modify its code if you need to modify its functionality.\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (object<MutationType>$)initializeMutationType(is$\\'a0id, numeric$\\'a0dominanceCoeff, string$\\'a0distributionType, ...)\n\\f4 \\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Add a mutation type at initialization time.  The \n\\f1\\fs18 id\n\\f2\\fs20  must not already be used for any mutation type in the simulation.  The \n\\f1\\fs18 id\n\\f2\\fs20  parameter may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  giving the ID of the new mutation type, or a \n\\f1\\fs18 string\n\\f2\\fs20  giving the name of the new mutation type (such as \n\\f1\\fs18 \"m5\"\n\\f2\\fs20  to specify an ID of 5).  The dominanceCoeff parameter supplies the dominance coefficient for the mutation type; \n\\f1\\fs18 0.0\n\\f2\\fs20  produces no dominance, \n\\f1\\fs18 1.0\n\\f2\\fs20  complete dominance, and values greater than \n\\f1\\fs18 1.0\n\\f2\\fs20 , overdominance.  The \n\\f1\\fs18 distributionType\n\\f2\\fs20  may be \n\\f1\\fs18 \"f\"\n\\f2\\fs20 , in which case the ellipsis \n\\f1\\fs18 ...\n\\f2\\fs20  should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  fixed selection coefficient; \n\\f1\\fs18 \"e\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  mean selection coefficient for an exponential distribution; \n\\f1\\fs18 \"g\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  mean selection coefficient and a \n\\f1\\fs18 numeric$\n\\f2\\fs20  alpha shape parameter for a gamma distribution; \n\\f1\\fs18 \"n\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  mean selection coefficient and a \n\\f1\\fs18 numeric$\n\\f2\\fs20  sigma (standard deviation) parameter for a normal distribution; \n\\f1\\fs18 \"p\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  mean selection coefficient and a \n\\f1\\fs18 numeric$\n\\f2\\fs20  scale parameter for a Laplace distribution; \n\\f1\\fs18 \"w\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 numeric$\n\\f2\\fs20  \n\\f4 \\uc0\\u955 \n\\f2  scale parameter and a \n\\f1\\fs18 numeric$\n\\f2\\fs20  k shape parameter for a Weibull distribution; or \n\\f1\\fs18 \"s\"\n\\f2\\fs20 , in which case the ellipsis should supply a \n\\f1\\fs18 string$\n\\f2\\fs20  Eidos script parameter.  The global symbol for the new mutation type is immediately available; the return value also provides the new object.\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nNote that by default in WF models, all mutations of a given mutation type will be converted into \n\\f1\\fs18 Substitution\n\\f2\\fs20  objects when they reach fixation, for efficiency reasons.  If you need to disable this conversion, to keep mutations of a given type active in the simulation even after they have fixed, you can do so by setting the \n\\f1\\fs18 convertToSubstitution\n\\f2\\fs20  property of \n\\f1\\fs18 MutationType\n\\f2\\fs20  to \n\\f1\\fs18 F\n\\f2\\fs20 .  In contrast, by default in nonWF models mutations will not be converted into \n\\f1\\fs18 Substitution\n\\f2\\fs20  objects when they reach fixation; \n\\f1\\fs18 convertToSubstitution\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20  by default in nonWF models.  To enable conversion in nonWF models for neutral mutation types with no indirect fitness effects, you should therefore set \n\\f1\\fs18 convertToSubstitution\n\\f2\\fs20  to \n\\f1\\fs18 T\n\\f2\\fs20 .\\\n\\pard\\pardeftab543\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (object<MutationType>$)initializeMutationTypeNuc(is$\\'a0id, numeric$\\'a0dominanceCoeff, string$\\'a0distributionType, ...)\\\n\\pard\\pardeftab543\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Add a nucleotide-based mutation type at initialization time.  This function is identical to \n\\f1\\fs18 initializeMutationType()\n\\f2\\fs20  except that the new mutation type will be nucleotide-based \\'96 in other words, mutations belonging to the new mutation type will have an associated nucleotide.  This function may be called only in nucleotide-based models (as enabled by the \n\\f1\\fs18 nucleotideBased\n\\f2\\fs20  parameter to \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20 ).\\\nNucleotide-based mutations always use a \n\\f1\\fs18 mutationStackGroup\n\\f2\\fs20  of \n\\f1\\fs18 -1\n\\f2\\fs20  and a \n\\f1\\fs18 mutationStackPolicy\n\\f2\\fs20  of \n\\f1\\fs18 \"l\"\n\\f2\\fs20 .  This ensures that a new nucleotide mutation always replaces any previously existing nucleotide mutation at a given position, regardless of the mutation types of the nucleotide mutations.  These values are set automatically by \n\\f1\\fs18 initializeMutationTypeNuc()\n\\f2\\fs20 , and may not be changed.\\\nSee the documentation for \n\\f1\\fs18 initializeMutationType()\n\\f2\\fs20  for all other discussion.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (void)initializeRecombinationRate(numeric\\'a0rates, [Ni\\'a0ends\\'a0=\\'a0NULL], [string$\\'a0sex\\'a0=\\'a0\"*\"])\n\\f4 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Set the recombination rate per base position per gamete.  To be precise, this recombination rate is the probability that a breakpoint will occur between one base and the next base; note that this is different from how the mutation rate is defined (see \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20 ).  A recombination rate of 1 centimorgan/Mbp corresponds to a recombination rate of \n\\f1\\fs18 1e-8\n\\f2\\fs20  in the units used by SLiM.  All rates must be in the interval [\n\\f1\\fs18 0.0\n\\f2\\fs20 , \n\\f1\\fs18 0.5\n\\f2\\fs20 ].  A rate of \n\\f1\\fs18 0.5\n\\f2\\fs20  implies complete independence between the adjacent bases, which might be used to implement unlinked loci.  Whether a breakpoint occurs between two bases is then, in effect, determined by a binomial draw with a single trial and the given rate as probability (but under the hood SLiM uses a mathematically equivalent but much more efficient strategy).  The recombinational process in SLiM will never generate more then one crossover between one base and the next (in one generation/haplosome), and a supplied rate of \n\\f1\\fs18 0.5\n\\f2\\fs20  will therefore result in an actual probability of \n\\f1\\fs18 0.5\n\\f2\\fs20  for a crossover at the relevant position.  (Note that this was not true in SLiM 2.x and earlier, however; their implementation of recombination resulted in a crossover probability of about 39.3% for a rate of \n\\f1\\fs18 0.5\n\\f2\\fs20 , due to the use of an inaccurate approximation method.  Recombination rates lower than about \n\\f1\\fs18 0.01\n\\f2\\fs20  would have been essentially exact, since the approximation error became large only as the rate approached \n\\f1\\fs18 0.5\n\\f2\\fs20 .)\\\nThere are two ways to call this function.  If the optional \n\\f1\\fs18 ends\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), then \n\\f1\\fs18 rates\n\\f2\\fs20  must be a singleton value that specifies a single recombination rate to be used along the entire chromosome.  If, on the other hand, \n\\f1\\fs18 ends\n\\f2\\fs20  is supplied, then \n\\f1\\fs18 rates\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  must be the same length, and the values in \n\\f1\\fs18 ends\n\\f2\\fs20  must be specified in ascending order.  In that case, \n\\f1\\fs18 rates\n\\f2\\fs20  and \n\\f1\\fs18 ends\n\\f2\\fs20  taken together specify the recombination rates to be used along successive contiguous stretches of the chromosome, from beginning to end; the last position specified in \n\\f1\\fs18 ends\n\\f2\\fs20  should extend to the end of the chromosome (i.e. at least to the end of the last genomic element, if not further).\\\nIf the optional \n\\f1\\fs18 sex\n\\f2\\fs20  parameter is \n\\f1\\fs18 \"*\"\n\\f2\\fs20  (the default), then the supplied recombination rate map will be used for both sexes (which is the only option for hermaphroditic simulations).  In sexual simulations \n\\f1\\fs18 sex\n\\f2\\fs20  may be \n\\f1\\fs18 \"M\"\n\\f2\\fs20  or \n\\f1\\fs18 \"F\"\n\\f2\\fs20  instead, in which case the supplied recombination map is used only for that sex.  In this case, two calls must be made to \n\\f1\\fs18 initializeRecombinationRate()\n\\f2\\fs20 , one for each sex, even if a rate of zero is desired for the other sex; no default recombination map is supplied.\\\nThe \n\\f1\\fs18 initializeRecombinationRateFromFile()\n\\f2\\fs20  function is a useful convenience function if you wish to read the recombination rate map from a file.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)initializeRecombinationRateFromFile(string$\\'a0path, integer$\\'a0lastPosition, [float$\\'a0scale\\'a0=\\'a01.0e-08], [string$\\'a0sep\\'a0=\\'a0\"\\\\t\"], [string$\\'a0dec\\'a0=\\'a0\".\"], [string$\\'a0sex\\'a0=\\'a0\"*\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Set a recombination rate map from data read from the file at \n\\f1\\fs18 path\n\\f2\\fs20 .  This function is essentially a wrapper for \n\\f1\\fs18 initializeRecombinationRate()\n\\f2\\fs20  that uses \n\\f1\\fs18 readCSV()\n\\f2\\fs20  and passes the data through.  The file is expected to contain two columns of data.  The first column must be \n\\f1\\fs18 integer\n\\f2\\fs20  start positions for rate map regions; the first region should start at position \n\\f1\\fs18 0\n\\f2\\fs20  if the map\\'92s positions are \n\\f1\\fs18 0\n\\f2\\fs20 -based, or at position \n\\f1\\fs18 1\n\\f2\\fs20  if the map\\'92s positions are \n\\f1\\fs18 1\n\\f2\\fs20 -based; in the latter case, \n\\f1\\fs18 1\n\\f2\\fs20  will be subtracted from every position since SLiM uses \n\\f1\\fs18 0\n\\f2\\fs20 -based positions.  The second column must be \n\\f1\\fs18 float\n\\f2\\fs20  rates, relative to the scaling factor specified in \n\\f1\\fs18 scale\n\\f2\\fs20 ; for example, if a given rate is \n\\f1\\fs18 1.2\n\\f2\\fs20  and \n\\f1\\fs18 scale\n\\f2\\fs20  is \n\\f1\\fs18 1e-8\n\\f2\\fs20  (the default), the rate used will be \n\\f1\\fs18 1.2e-8\n\\f2\\fs20 .  No column header line should be present; the file should start immediately with numerical data.  The expected separator between columns is a tab character by default, but may be passed in \n\\f1\\fs18 sep\n\\f2\\fs20 ; the expected decimal separator is a period by default, but may be passed in \n\\f1\\fs18 dec\n\\f2\\fs20 .  Once read, the map is converted into a rate map specified with end positions, rather than start positions, and the position given by \n\\f1\\fs18 lastPosition\n\\f2\\fs20  is used as the end of the last rate region; it should be the last position of the chromosome.\\\nSee \n\\f1\\fs18 readCSV()\n\\f2\\fs20  for further details on \n\\f1\\fs18 sep\n\\f2\\fs20  and \n\\f1\\fs18 dec\n\\f2\\fs20 , which are passed through to it; and see \n\\f1\\fs18 initializeRecombinationRate()\n\\f2\\fs20  for details on how the rate map is validated and used, and how the \n\\f1\\fs18 sex\n\\f2\\fs20  parameter is used.\\\nThis function is written in Eidos, and its source code can be viewed with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , so you can copy and modify its code if you need to modify its functionality.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)initializeSex([Ns$\\'a0chromosomeType\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Enable sex in the simulation.  Beginning in SLiM 5, this method should generally be passed \n\\f1\\fs18 NULL\n\\f2\\fs20 , simply indicating that sex should be enabled: individuals will then be male and female (rather than hermaphroditic), biparental crosses will be required to be between a female first parent and a male second parent, and selfing will not be allowed.  In this new configuration style, if a sexual simulation involving sex chromosomes is desired, the new \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  call should be used to configure the chromosome setup for the simulation.\\\nFor backward compatibility, the old style of configuring a sexual simulation is still supported, however.  This implicitly defines a single chromosome, without a call to \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20 .  With this old configuration approach, the \n\\f1\\fs18 chromosomeType\n\\f2\\fs20  parameter to \n\\f1\\fs18 initializeSex()\n\\f2\\fs20  gives the type of chromosome that should be simulated; this should be \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"X\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"Y\"\n\\f2\\fs20 , and this \n\\f1\\fs18 chromosomeType\n\\f2\\fs20  value will be used as the symbol (\n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"X\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"Y\"\n\\f2\\fs20 ) for the implicit chromosome.  These legacy chromosome types correspond to the new chromosome types \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"X\"\n\\f2\\fs20 , and \n\\f1\\fs18 \"-Y\"\n\\f2\\fs20  respectively (note that it is \n\\f3\\i not\n\\f2\\i0  \n\\f1\\fs18 \"Y\"\n\\f2\\fs20 ), when using \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20 .  The implicit chromosome\\'92s \n\\f1\\fs18 id\n\\f2\\fs20  property is always \n\\f1\\fs18 1\n\\f2\\fs20 .  This old style of chromosome configuration is much less flexible, however, allowing only these three chromosome types, and only allowing a single chromosome to be set up.  This backward compatibility mode may be removed for SLiM in the future, and should be considered deprecated; new models should call \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  explicitly instead.\\\nThere is no way to disable sex once it has been enabled; if you don\\'92t want to have sex, don\\'92t call this function.  If you require more flexibility with mating types and reproductive strategies than SLiM\\'92s built-in support for sex provides, do not call \n\\f1\\fs18 initializeSex()\n\\f2\\fs20 ; instead, track the sex or mating type of individuals yourself in script (with the \n\\f1\\fs18 tag\n\\f2\\fs20  property of \n\\f1\\fs18 Individual\n\\f2\\fs20 , for example), and manage the consequences of that in your script yourself, in terms of which individuals can mate with which, and exactly how the offspring is produced.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f0\\b \\cf2 The \n\\f5\\fs18 xDominanceCoeff\n\\f0\\fs20  parameter has been deprecated and removed.\n\\f2\\b0   In SLiM 5 and later, use the \n\\f1\\fs18 hemizygousDominanceCoeff\n\\f2\\fs20  property of \n\\f1\\fs18 MutationType\n\\f2\\fs20  instead.  \\cf3 If the \n\\f1\\fs18 chromosomeType\n\\f2\\fs20  is \n\\f1\\fs18 \"X\"\n\\f2\\fs20 , the optional \n\\f1\\fs18 xDominanceCoeff\n\\f2\\fs20  parameter can supply the dominance coefficient used when a mutation is present in an XY male, and is thus \\'93heterozygous\\'94 (but in a different sense than the heterozygosity of an XX female with one copy of the mutation).\\cf2 \\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 (void)initializeSLiMModelType(string$\\'a0modelType)\n\\f4 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nConfigure the type of SLiM model used for the simulation.  At present, one of two model types may be selected.  If \n\\f1\\fs18 modelType\n\\f2\\fs20  is \n\\f1\\fs18 \"WF\"\n\\f2\\fs20 , SLiM will use a Wright-Fisher (WF) model; this is the model type that has always been supported by SLiM, and is the model type used if \n\\f1\\fs18 initializeSLiMModelType()\n\\f2\\fs20  is not called.  If \n\\f1\\fs18 modelType\n\\f2\\fs20  is \n\\f1\\fs18 \"nonWF\"\n\\f2\\fs20 , SLiM will use a non-Wright-Fisher (nonWF) model instead; this is a new model type supported by SLiM 3.0 and above.\\\nIf \n\\f1\\fs18 initializeSLiMModelType()\n\\f2\\fs20  is called at all then it must be called before any other initialization function, so that SLiM knows from the outset which features are enabled and which are not.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (void)initializeSLiMOptions([logical$\\'a0keepPedigrees\\'a0=\\'a0F], [string$\\'a0dimensionality\\'a0=\\'a0\"\"], [string$\\'a0periodicity\\'a0=\\'a0\"\"], [logical$\\'a0doMutationRunExperiments\\'a0=\\'a0T], [logical$\\'a0preventIncidentalSelfing\\'a0=\\'a0F]\\cf2 \\expnd0\\expndtw0\\kerning0\n, [logical$\\'a0nucleotideBased\\'a0=\\'a0F], [logical$\\'a0randomizeCallbacks\\'a0=\\'a0T]\\kerning1\\expnd0\\expndtw0 , [logical$\\'a0checkInfiniteLoops\\'a0=\\'a0T]\\cf0 )\n\\f4 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nConfigure options for the simulation.  If \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20  is called at all then it must be called before any other initialization function (except \n\\f1\\fs18 initializeSLiMModelType()\n\\f2\\fs20 ), so that SLiM knows from the outset which optional features are enabled and which are not.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 If \n\\f1\\fs18 keepPedigrees\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 , SLiM will keep pedigree information for every individual in the simulation, tracking the identity of its parents and grandparents.  This allows individuals to assess their degree of pedigree-based relatedness to other individuals (see \n\\f1\\fs18 Individual\n\\f2\\fs20 \\'92s \n\\f1\\fs18 relatedness()\n\\f2\\fs20  and \n\\f1\\fs18 sharedParentCount()\n\\f2\\fs20  methods), as well as allowing a model to find \\'93trios\\'94 (two parents and an offspring they generated) using the pedigree properties of \n\\f1\\fs18 Individual\n\\f2\\fs20 .  As a side effect of \n\\f1\\fs18 keepPedigrees\n\\f2\\fs20  being \n\\f1\\fs18 T\n\\f2\\fs20 , the \n\\f1\\fs18 pedigreeID\n\\f2\\fs20 , \n\\f1\\fs18 pedigreeParentIDs\n\\f2\\fs20 , and \n\\f1\\fs18 pedigreeGrandparentIDs\n\\f2\\fs20  properties of \n\\f1\\fs18 Individual\n\\f2\\fs20  will have defined values, as will the \n\\f1\\fs18 haplosomePedigreeID\n\\f2\\fs20  property of \n\\f1\\fs18 Haplosome\n\\f2\\fs20 .  Note that pedigree-based relatedness doesn\\'92t necessarily correspond to genetic relatedness, due to effects such as assortment and recombination.  Beginning in SLiM 3.5, \n\\f1\\fs18 keepPedigrees=T\n\\f2\\fs20  also enables tracking of individual reproductive output, available through the \n\\f1\\fs18 reproductiveOutput\n\\f2\\fs20  property of \n\\f1\\fs18 Individual\n\\f2\\fs20  and the \n\\f1\\fs18 lifetimeReproductiveOutput\n\\f2\\fs20  property of \n\\f1\\fs18 Subpopulation\n\\f2\\fs20 .\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 If \n\\f1\\fs18 dimensionality\n\\f2\\fs20  is not \n\\f1\\fs18 \"\"\n\\f2\\fs20 , SLiM will enable its optional \\'93continuous space\\'94 facility.  Three values for \n\\f1\\fs18 dimensionality\n\\f2\\fs20  are presently supported: \n\\f1\\fs18 \"x\"\n\\f2\\fs20 , \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , and \n\\f1\\fs18 \"xyz\"\n\\f2\\fs20 , specifying that continuous space should be enabled for one, two, or three dimensions, respectively, using (\n\\f3\\i x\n\\f2\\i0 ), (\n\\f3\\i x\n\\f2\\i0 , \n\\f3\\i y\n\\f2\\i0 ), and (\n\\f3\\i x\n\\f2\\i0 , \n\\f3\\i y\n\\f2\\i0 , \n\\f3\\i z\n\\f2\\i0 ) coordinates respectively.  This has a number of side effects.  First of all, it means that the specified properties of \n\\f1\\fs18 Individual\n\\f2\\fs20  (\n\\f1\\fs18 x\n\\f2\\fs20 , \n\\f1\\fs18 y\n\\f2\\fs20 , and/or \n\\f1\\fs18 z\n\\f2\\fs20 ) will be interpreted by SLiM as spatial positions; in particular, SLiMgui will use those properties to display subpopulations spatially.  Second, it allows spatial interactions to be defined, evaluated, and queried using \n\\f1\\fs18 initializeInteractionType()\n\\f2\\fs20  and \n\\f1\\fs18 interaction()\n\\f2\\fs20  callbacks.  And third, it enables the use of any other properties and methods related to continuous space, such as setting the spatial boundaries of subpopulations, which would otherwise raise an error.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f1\\fs18 periodicity\n\\f2\\fs20  is not \n\\f1\\fs18 \"\"\n\\f2\\fs20 , SLiM will designate the specified spatial dimensions as being periodic \\'96 wrapping around at the edges of the spatial boundaries of that dimension.  This option may only be used if the \n\\f1\\fs18 dimensionality\n\\f2\\fs20  parameter to \n\\f1\\fs18 initializeSLiMOptions()\n\\f2\\fs20  has been used to enable spatiality in the model, and only spatial dimensions that were specified in the dimensionality of the model may be declared to be periodic (but if desired, it is permissible to make just a subset of those dimensions periodic; it is not an all-or-none proposition).  For example, if the specified dimensionality is \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , the model\\'92s periodicity may be \n\\f1\\fs18 \"x\"\n\\f2\\fs20 , \n\\f1\\fs18 \"y\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"xy\"\n\\f2\\fs20  (or \n\\f1\\fs18 \"\"\n\\f2\\fs20 , the default, to specify that there are no periodic dimensions).  A one-dimensional periodic model would model a space like the perimeter of a circle.  A two-dimensional model periodic in one of those dimensions would model a space like a cylinder without its end caps; if periodic in both dimensions, the modeled space is a torus.  The shapes of three-dimensional periodic models are harder to visualize, but are essentially higher-dimensional analogues of these concepts.  Periodic boundary conditions are commonly used to model spatial scenarios without \\'93edge effects\\'94, since there are no edges in the periodic spatial dimensions.  The \n\\f1\\fs18 pointPeriodic()\n\\f2\\fs20  method of \n\\f1\\fs18 Subpopulation\n\\f2\\fs20  is typically used in conjunction with this option, to actually implement the periodic boundary condition for the specified dimensions.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 The \n\\f1\\fs18 doMutationRunExperiments\n\\f2\\fs20  parameter specifies whether SLiM should attempt to conduct experiments at runtime to determine the optimal number of mutation runs used in the model.  This is a performance optimization.  If \n\\f1\\fs18 doMutationRunExperiments\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), this optimization is enabled for all chromosomes that do not have an explicitly specified mutation run count; this is generally desirable and may significantly improve performance.  If \n\\f1\\fs18 doMutationRunExperiments\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 , this optimization is disabled and chromosomes that do not have an explicitly specified mutation run count will simply use a single mutation run.  See the documentation for \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20  for further discussion.  Note that this parameter used to be \n\\f1\\fs18 [integer$\\'a0mutationRuns\\'a0=\\'a00]\n\\f2\\fs20 , specifying the mutation run count directly.  That parameter has been moved to \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20 , allowing a different mutation run count to be specified for each chromosome in multi-chromosome models.\\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 \\kerning1\\expnd0\\expndtw0 If \n\\f1\\fs18 preventIncidentalSelfing\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 , incidental selfing in hermaphroditic models will be prevented by SLiM.  By default (i.e., if \n\\f1\\fs18 preventIncidentalSelfing\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 ), SLiM chooses the first and second parents in a biparental mating event independently.  It is therefore possible for the same individual to be chosen as both the first and second parent, resulting in selfing events even when the selfing rate is zero.  In many models this is unimportant, since it happens fairly infrequently and does not have large consequences.  This behavior is SLiM\\'92s default because it is the simplest option, and produces results that most closely align with simple analytical population genetics models.  However, in some models this selfing can be undesirable and problematic.  In particular, models that involve very high variance in fitness or very small effective population sizes may see elevated rates of selfing that substantially influence model results.  If \n\\f1\\fs18 preventIncidentalSelfing\n\\f2\\fs20  is set to \n\\f1\\fs18 T\n\\f2\\fs20 , all such incidental selfing will be prevented (by choosing a new second parent if the first parent was chosen again).  Non-incidental selfing, as requested by the selfing rate, will still be permitted.  Note that if incidental selfing is prevented, SLiM will hang if it is unable to find a different second parent; there must always be at least two individuals in the population with non-zero fitness, and \n\\f1\\fs18 mateChoice()\n\\f2\\fs20  and \n\\f1\\fs18 modifyChild()\n\\f2\\fs20  callbacks must not absolutely prevent those two individuals from producing viable offspring.  Enforcement of the prohibition on incidental selfing will occur after \n\\f1\\fs18 mateChoice()\n\\f2\\fs20  callbacks have been called (and thus the default mating weights provided to \n\\f1\\fs18 mateChoice()\n\\f2\\fs20  callbacks will \n\\f3\\i not\n\\f2\\i0  exclude the first parent!), but will occur before \n\\f1\\fs18 modifyChild()\n\\f2\\fs20  callbacks are called (so those callbacks may assume that the first and second parents are distinct).\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\expnd0\\expndtw0\\kerning0\nIf \n\\f1\\fs18 nucleotideBased\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 , the model will be nucleotide-based.  In this case, auto-generated mutations (i.e., mutation types used by genomic element types) must be nucleotide-based, and an ancestral nucleotide sequence must be supplied with \n\\f1\\fs18 initializeAncestralNucleotides()\n\\f2\\fs20 .  Non-nucleotide-based mutations may still be used, but may not be referenced by genomic element types.  A mutation rate (or rate map) may not be supplied with \n\\f1\\fs18 initializeMutationRate()\n\\f2\\fs20 ; instead, a hotspot map may (optionally) be supplied with \n\\f1\\fs18 initializeHotspotMap()\n\\f2\\fs20 .  This choice has many consequences across SLiM. \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 \\kerning1\\expnd0\\expndtw0 If \n\\f1\\fs18 randomizeCallbacks\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), the order in which individuals are processed in callbacks will be randomized to make it easier to avoid order-dependency bugs.  This flag exists because the order of individuals in each subpopulation is non-random; most notably, females always come before males in the individuals vector, but non-random ordering may also occur with respect to things like migrant versus non-migrant status, origin by selfing versus cloning versus biparental mating, and other factors.  When this option is \n\\f1\\fs18 F\n\\f2\\fs20 , individuals in a subpopulation are processed in the order of the individuals vector in each tick cycle stage, which may lead to order-dependency issues if there is an enabled callback whose behavior is not fully independent between calls.  Setting this option to \n\\f1\\fs18 T\n\\f2\\fs20  will cause individuals within each subpopulation to be processed in a randomized order in each tick cycle stage; specifically, this randomizes the order of calls to \n\\f1\\fs18 mutationEffect()\n\\f2\\fs20  callbacks in both WF and nonWF models, and calls to \n\\f1\\fs18 reproduction()\n\\f2\\fs20  and \n\\f1\\fs18 survival()\n\\f2\\fs20  callbacks in nonWF models.  Each subpopulation is still processed separately, in sequential order, so order-dependency issues between subpopulations are still possible if callbacks have effects that are not fully independent.  This feature was added in SLiM 4, breaking backward compatibility; to recover the behavior of previous versions of SLiM, pass \n\\f1\\fs18 F\n\\f2\\fs20  for this option (but then be very careful about order-dependency issues in your script).  The default of \n\\f1\\fs18 T\n\\f2\\fs20  is the safe option, but a small speed penalty is incurred by the randomization of the processing order \\'96 for most models the difference will be less than 1%, but in the worst case it may approach 10%.  Models that do not have any order-dependency issue may therefore run somewhat faster if this is set to \n\\f1\\fs18 F\n\\f2\\fs20 .  Note that anywhere that your script uses the \n\\f1\\fs18 individuals\n\\f2\\fs20  property of \n\\f1\\fs18 Subpopulation\n\\f2\\fs20 , the order of individuals returned will be non-random (regardless of the setting of this option); you should use \n\\f1\\fs18 sample()\n\\f2\\fs20  to shuffle the order of the individuals vector if necessary to avoid order-dependency issues in your script.\\\nIf \n\\f1\\fs18 checkInfiniteLoops\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), SLiM and Eidos will check for infinite loops in various circumstances, such as \n\\f1\\fs18 while\n\\f2\\fs20  and \n\\f1\\fs18 do\\'96while\n\\f2\\fs20  loops.  This check is conducted only when running in SLiMgui; at the command line, checks for infinite loops are never conducted regardless of the value of this flag.  When checking is enabled, an error will be raised if any loop executes more than 10 million times, preventing SLiMgui\\'92s user interface from freezing.  Normally this is desirable, but if you actually want to execute a loop more than 10 million times, this checking will prove inconvenient.  In that case, you can pass \n\\f1\\fs18 F\n\\f2\\fs20  for \n\\f1\\fs18 checkInfiniteLoops\n\\f2\\fs20  to disable these checks.  There is no way to turn these checks on or off for individual loops; it is a global setting.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf0 This function will likely be extended with further options in the future, added on to the end of the argument list.  Using named arguments with this call is recommended for readability.  Note that turning on optional features may increase the runtime and memory footprint of SLiM.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (void)initializeSpecies([integer$\\'a0tickModulo\\'a0=\\'a01], [integer$\\'a0tickPhase\\'a0=\\'a01], [string$\\'a0avatar\\'a0=\\'a0\"\"], [string$\\'a0color\\'a0=\\'a0\"\"])\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Configure options for the species being initialized.  This initialization function may only be called in multispecies models (i.e., models with explicit species declarations); in single-species models, the default values are assumed and cannot be changed.\\\nThe \n\\f1\\fs18 tickModulo\n\\f2\\fs20  and \n\\f1\\fs18 tickPhase\n\\f2\\fs20  parameters determine the activation schedule for the species.  The \n\\f1\\fs18 active\n\\f2\\fs20  property of the species will be set to \n\\f1\\fs18 T\n\\f2\\fs20  (thus activating the species) every \n\\f1\\fs18 tickModulo\n\\f2\\fs20  ticks, beginning in tick \n\\f1\\fs18 tickPhase\n\\f2\\fs20 .  (However, when the species is activated in a given tick, the \n\\f1\\fs18 skipTick()\n\\f2\\fs20  method may still be called in a \n\\f1\\fs18 first()\n\\f2\\fs20  event to deactivate it.)  See the \n\\f1\\fs18 active\n\\f2\\fs20  property of \n\\f1\\fs18 Species\n\\f2\\fs20  for more details.\\\nThe \n\\f1\\fs18 avatar\n\\f2\\fs20  parameter, if not \n\\f1\\fs18 \"\"\n\\f2\\fs20 , sets a \n\\f1\\fs18 string\n\\f2\\fs20  value used to represent the species graphically, particularly in SLiMgui but perhaps in other contexts also.  The \n\\f1\\fs18 avatar\n\\f2\\fs20  should generally be a single character \\'96 usually an emoji corresponding to the species, such as \n\\f1\\fs18 \"\n\\f6\\fs14 \\uc0\\u55358 \\u56714 \n\\f1\\fs18 \"\n\\f2\\fs20  for foxes or \n\\f1\\fs18 \"\n\\f6\\fs14 \\uc0\\u55357 \\u56365 \n\\f1\\fs18 \"\n\\f2\\fs20  for mice.  If \n\\f1\\fs18 avatar\n\\f2\\fs20  is the empty string, \n\\f1\\fs18 \"\"\n\\f2\\fs20 , SLiMgui will choose a default avatar.\\\nThe \n\\f1\\fs18 color\n\\f2\\fs20  parameter, if not \n\\f1\\fs18 \"\"\n\\f2\\fs20 , sets a \n\\f1\\fs18 string\n\\f2\\fs20  color value used to represent the species in SLiMgui.  Colors may be specified by name, or with hexadecimal RGB values of the form \n\\f1\\fs18 \"#RRGGBB\"\n\\f2\\fs20  (see the Eidos manual for details).  If \n\\f1\\fs18 color\n\\f2\\fs20  is the empty string, \n\\f1\\fs18 \"\"\n\\f2\\fs20 , SLiMgui will choose a default color.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(void)initializeTreeSeq([logical$\\'a0recordMutations\\'a0=\\'a0T], [Nif$\\'a0simplificationRatio\\'a0=\\'a0NULL], [Ni$\\'a0simplificationInterval\\'a0=\\'a0NULL], [logical$\\'a0checkCoalescence\\'a0=\\'a0F], [logical$\\'a0runCrosschecks\\'a0=\\'a0F], [logical$\\'a0\\kerning1\\expnd0\\expndtw0 retainCoalescentOnly\\expnd0\\expndtw0\\kerning0\n\\'a0=\\'a0T]\\kerning1\\expnd0\\expndtw0 , [Ns$\\'a0timeUnit\\'a0=\\'a0NULL]\\expnd0\\expndtw0\\kerning0\n)\n\\f4 \\cf0 \\kerning1\\expnd0\\expndtw0 \\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Configure options for tree sequence recording.  Calling this function turns on tree sequence recording, as a side effect, for later reconstruction of the simulation\\'92s evolutionary dynamics; if you do not want tree sequence recording to be enabled, do not call this function.  Note that tree-sequence recording internally uses SLiM\\'92s \\'93pedigree tracking\\'94 feature to uniquely identify individuals and haplosomes; however, if you want to use pedigree tracking in your script you must still enable it yourself with \n\\f1\\fs18 initializeSLiMOptions(keepPedigrees=T)\n\\f2\\fs20 .  A separate tree sequence will be recorded for each chromosome in the simulation, as configured with \n\\f1\\fs18 initializeChromosome()\n\\f2\\fs20 .\\\nThe \n\\f1\\fs18 recordMutations\n\\f2\\fs20  flag controls whether information about individual mutations is recorded or not.  Such recording takes time and memory, and so can be turned off if only the tree sequence itself is needed, but it is turned on by default since mutation recording is generally useful.\\\nThe \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  and \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  parameters control how often automatic simplification of the recorded tree sequence occurs.  This is a speed\\'96memory tradeoff: more frequent simplification (lower \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  or smaller \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20 ) means the stored tree sequences will use less memory, but at a cost of somewhat longer run times.  Conversely, a larger \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  or \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  means that SLiM will wait longer between simplifications.  There are three ways these parameters can be used.  With the first option, with a non-\n\\f1\\fs18 NULL\n\\f2\\fs20  \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  and a \n\\f1\\fs18 NULL\n\\f2\\fs20  value for \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20 , SLiM will try to find an optimal tick interval for simplification such that the ratio of the memory used by the tree sequence tables, (before:after) simplification, is close to the requested ratio. The default of \n\\f1\\fs18 10\n\\f2\\fs20  (used if both \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  and \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  are \n\\f1\\fs18 NULL\n\\f2\\fs20 ) thus requests that SLiM try to find a tick interval such that the maximum size of the stored tree sequences is ten times the size after simplification. \n\\f1\\fs18 INF\n\\f2\\fs20  may be supplied to indicate that automatic simplification should never occur; \n\\f1\\fs18 0\n\\f2\\fs20  may be supplied to indicate that automatic simplification should be performed at the end of every tick.  Alternatively \\'96 the second option \\'96 \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  may be \n\\f1\\fs18 NULL\n\\f2\\fs20  and \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  may be set to the interval, in ticks, between simplifications.  This may provide more reliable performance, but the interval must be chosen carefully to avoid exceeding the available memory.  The \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  value may be a very large number to specify that simplification should never occur (not \n\\f1\\fs18 INF\n\\f2\\fs20 , though, since it is an \n\\f1\\fs18 integer\n\\f2\\fs20  value), or \n\\f1\\fs18 1\n\\f2\\fs20  to simplify every tick.  Finally \\'96 the third option \\'96 both parameters may be non-\n\\f1\\fs18 NULL\n\\f2\\fs20 , in which case \n\\f1\\fs18 simplificationRatio\n\\f2\\fs20  is used as described above, while \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  provides the \n\\f3\\i initial\n\\f2\\i0  interval first used by SLiM (and then subsequently increased or decreased to try to match the requested simplification ratio).  The default initial interval, used when \n\\f1\\fs18 simplificationInterval\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20 , is usually \n\\f1\\fs18 20\n\\f2\\fs20 ; this is chosen to be relatively frequent, and thus unlikely to lead to a memory overflow, but it can result in rather slow spool-up for models where the equilibrium simplification interval, as determined by the simplification ratio, is much longer.  It can therefore be helpful to set a larger initial interval so that the early part of the model run is not excessively bogged down in simplification.\\\nThe \n\\f1\\fs18 checkCoalescence\n\\f2\\fs20  parameter controls whether a check for full coalescence is conducted after each simplification.  If a model will call \n\\f1\\fs18 treeSeqCoalesced()\n\\f2\\fs20  to check for coalescence during its execution, \n\\f1\\fs18 checkCoalescence\n\\f2\\fs20  should be set to \n\\f1\\fs18 T\n\\f2\\fs20 .  Since the coalescence checks entail a performance penalty, the default of \n\\f1\\fs18 F\n\\f2\\fs20  is preferable otherwise.  See the documentation for \n\\f1\\fs18 treeSeqCoalesced()\n\\f2\\fs20  for further discussion.\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 The \n\\f1\\fs18 runCrosschecks\n\\f2\\fs20  parameter controls whether cross-checks between SLiM\\'92s internal data structures and the tree-sequence recording data structures will be conducted.  These two sets of data structures record much the same thing (mutations in haplosomes), but using completely different representations, so such cross-checks can be useful to confirm that the two data structures do indeed represent the same conceptual state.  This slows down the model considerably, however, and would normally be turned on only for debugging purposes, so it is turned off by default.\\\n\\pard\\pardeftab720\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 The \n\\f1\\fs18 retainCoalescentOnly\n\\f2\\fs20  parameter controls how, exactly, simplification of the tree-sequence data is performed in SLiM (both for auto-simplification and for calls to \n\\f1\\fs18 treeSeqSimplify()\n\\f2\\fs20 ).  More specifically, this parameter controls the behavior of simplification for individuals and haplosomes that have been \\'93retained\\'94 by calling \n\\f1\\fs18 treeSeqRememberIndividuals()\n\\f2\\fs20  with the parameter \n\\f1\\fs18 permanent=F\n\\f2\\fs20 .  The default of \n\\f1\\fs18 retainCoalescentOnly=T\n\\f2\\fs20  helps to keep the number of retained individuals relatively small, which is helpful if your simulation regularly flags many individuals for retaining.  In this case, changing \n\\f1\\fs18 retainCoalescentOnly\n\\f2\\fs20  to \n\\f1\\fs18 F\n\\f2\\fs20  may dramatically increase memory usage and runtime, in a similar way to permanently remembering all the individuals.  See the documentation of \n\\f1\\fs18 treeSeqRememberIndividuals()\n\\f2\\fs20  for further discussion.\\\nThe \n\\f1\\fs18 timeUnit\n\\f2\\fs20  parameter controls the time unit stated in the tree sequence when it is saved (which can be accessed through \n\\f1\\fs18 tskit\n\\f2\\fs20  APIs); it has no effect on the running simulation whatsoever.  The default value, \n\\f1\\fs18 NULL\n\\f2\\fs20 , means that a time unit of \n\\f1\\fs18 \"ticks\"\n\\f2\\fs20  will be used for all model types.  (In SLiM 3.7 / 3.7.1, \n\\f1\\fs18 NULL\n\\f2\\fs20  implied a time unit of \n\\f1\\fs18 \"generations\"\n\\f2\\fs20  for WF models, but \n\\f1\\fs18 \"ticks\"\n\\f2\\fs20  for nonWF models; given the new multispecies timescale parameters in SLiM 4, a default of \n\\f1\\fs18 \"ticks\"\n\\f2\\fs20  makes sense in all cases since now even in WF models one tick might not equal one biological generation.)  It may be helpful to set \n\\f1\\fs18 timeUnit\n\\f2\\fs20  to \n\\f1\\fs18 \"generations\"\n\\f2\\fs20  explicitly when modeling non-overlapping generations in which one tick equals one generation, to tell \n\\f1\\fs18 tskit\n\\f2\\fs20  that the time unit does in fact represent biological generations; doing so may avoid warnings from \n\\f1\\fs18 tskit\n\\f2\\fs20  or \n\\f1\\fs18 msprime\n\\f2\\fs20  regarding the time unit, in cases such as recapitation where the simulation timescale is important.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.2.  Nucleotide utilities\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\b0\\fs18 \\cf2 \\expnd0\\expndtw0\\kerning0\n(is)codonsToAminoAcids(integer\\'a0codons, [li$\\'a0long\\'a0=\\'a0F], [logical$\\'a0paste\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\kerning1\\expnd0\\expndtw0 Returns the amino acid sequence corresponding to the codon sequence in \n\\f1\\fs18 codons\n\\f2\\fs20 .  Codons should be represented with values in [\n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 63\n\\f2\\fs20 ] where AAA is \n\\f1\\fs18 0\n\\f2\\fs20 , AAC is \n\\f1\\fs18 1\n\\f2\\fs20 , AAG is \n\\f1\\fs18 2\n\\f2\\fs20 , and TTT is \n\\f1\\fs18 63\n\\f2\\fs20 ; see \n\\f1\\fs18 ancestralNucleotides()\n\\f2\\fs20  for discussion of this encoding.  If \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20  (the default), the standard single-letter codes for amino acids will be used (where Serine is \n\\f1\\fs18 \"S\"\n\\f2\\fs20 , etc.); if \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 , the standard three-letter codes will be used instead (where Serine is \n\\f1\\fs18 \"Ser\"\n\\f2\\fs20 , etc.).  Beginning in SLiM 3.5, if \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 integer\n\\f2\\fs20  codes will be used as follows (and \n\\f1\\fs18 paste\n\\f2\\fs20  will be ignored):\\\n\\pard\\tx3780\\pardeftab720\\li1080\\sa60\\partightenfactor0\n\\cf2 stop (TAA, TAG, TGA)\t\n\\f1\\fs18 0\n\\f2\\fs20 \\uc0\\u8232 Alanine\t\n\\f1\\fs18 1\n\\f2\\fs20 \\uc0\\u8232 Arginine\t\n\\f1\\fs18 2\n\\f2\\fs20 \\uc0\\u8232 Asparagine\t\n\\f1\\fs18 3\n\\f2\\fs20 \\uc0\\u8232 Aspartic acid (Aspartate)\t\n\\f1\\fs18 4\n\\f2\\fs20 \\uc0\\u8232 Cysteine\t\n\\f1\\fs18 5\n\\f2\\fs20 \\uc0\\u8232 Glutamine\t\n\\f1\\fs18 6\n\\f2\\fs20 \\uc0\\u8232 Glutamic acid (Glutamate)\t\n\\f1\\fs18 7\n\\f2\\fs20 \\uc0\\u8232 Glycine\t\n\\f1\\fs18 8\n\\f2\\fs20 \\uc0\\u8232 Histidine\t\n\\f1\\fs18 9\n\\f2\\fs20 \\uc0\\u8232 Isoleucine\t\n\\f1\\fs18 10\n\\f2\\fs20 \\uc0\\u8232 Leucine\t\n\\f1\\fs18 11\n\\f2\\fs20 \\uc0\\u8232 Lysine\t\n\\f1\\fs18 12\n\\f2\\fs20 \\uc0\\u8232 Methionine\t\n\\f1\\fs18 13\n\\f2\\fs20 \\uc0\\u8232 Phenylalanine\t\n\\f1\\fs18 14\n\\f2\\fs20 \\uc0\\u8232 Proline\t\n\\f1\\fs18 15\n\\f2\\fs20 \\uc0\\u8232 Serine\t\n\\f1\\fs18 16\n\\f2\\fs20 \\uc0\\u8232 Threonine\t\n\\f1\\fs18 17\n\\f2\\fs20 \\uc0\\u8232 Tryptophan\t\n\\f1\\fs18 18\n\\f2\\fs20 \\uc0\\u8232 Tyrosine\t\n\\f1\\fs18 19\n\\f2\\fs20 \\uc0\\u8232 Valine\t\n\\f1\\fs18 20\n\\f2\\fs20 \\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\\cf2 There does not seem to be a widely used standard for integer coding of amino acids, so SLiM just numbers them alphabetically, making stop codons \n\\f1\\fs18 0\n\\f2\\fs20 .  If you want a different coding, you can make your own 64-element vector and use it to convert codons to whatever integer codes you need.  Other \n\\f1\\fs18 integer\n\\f2\\fs20  values of \n\\f1\\fs18 long\n\\f2\\fs20  are reserved for future use (to support other codings), and will currently produce an error.\\\nWhen \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  or \n\\f1\\fs18 F\n\\f2\\fs20  and \n\\f1\\fs18 paste\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), the amino acid sequence returned will be a singleton \n\\f1\\fs18 string\n\\f2\\fs20 , such as \n\\f1\\fs18 \"LYATI\"\n\\f2\\fs20  (when \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 ) or \n\\f1\\fs18 \"Leu-Tyr-Ala-Thr-Ile\"\n\\f2\\fs20  (when \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 ).  When \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  or \n\\f1\\fs18 F\n\\f2\\fs20  and \n\\f1\\fs18 paste\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 , the amino acid sequence will instead be returned as a \n\\f1\\fs18 string\n\\f2\\fs20  vector, with one element per amino acid, such as \n\\f1\\fs18 \"L\" \"Y\" \"A\" \"T\" \"I\"\n\\f2\\fs20  (when \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 ) or \n\\f1\\fs18 \"Leu\" \"Tyr\" \"Ala\" \"Thr\" \"Ile\"\n\\f2\\fs20  (when \n\\f1\\fs18 long\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 ).  Using the \n\\f1\\fs18 paste=T\n\\f2\\fs20  option is considerably faster than using \n\\f1\\fs18 paste()\n\\f2\\fs20  in script.\\expnd0\\expndtw0\\kerning0\n\\\nThis function interprets the supplied codon sequence as the \n\\f3\\i sense\n\\f2\\i0  strand (i.e., the strand that is \n\\f3\\i not\n\\f2\\i0  transcribed, and which mirrors the mRNA\\'92s sequence).  This uses the standard DNA codon table directly.  For example, if the nucleotide sequence is CAA TTC, that will correspond to a codon vector of \n\\f1\\fs18 16 61\n\\f2\\fs20 , and will result in the amino acid sequence Gln-Phe (\n\\f1\\fs18 \"QF\"\n\\f2\\fs20 ).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (is)codonsToNucleotides(integer\\'a0codons, [string$\\'a0format\\'a0=\\'a0\"string\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns the nucleotide sequence corresponding to the codon sequence supplied in \n\\f1\\fs18 codons\n\\f2\\fs20 .  Codons should be represented with values in [\n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 63\n\\f2\\fs20 ] where AAA is \n\\f1\\fs18 0\n\\f2\\fs20 , AAC is \n\\f1\\fs18 1\n\\f2\\fs20 , AAG is \n\\f1\\fs18 2\n\\f2\\fs20 , and TTT is \n\\f1\\fs18 63\n\\f2\\fs20 ; see \n\\f1\\fs18 ancestralNucleotides()\n\\f2\\fs20  for discussion of this encoding.\\\nThe \n\\f1\\fs18 format\n\\f2\\fs20  parameter controls the format of the returned sequence.  It may be \n\\f1\\fs18 \"string\"\n\\f2\\fs20  to obtain the sequence as a singleton \n\\f1\\fs18 string\n\\f2\\fs20  (e.g., \n\\f1\\fs18 \"TATACG\"\n\\f2\\fs20 ), \n\\f1\\fs18 \"char\"\n\\f2\\fs20  to obtain it as a \n\\f1\\fs18 string\n\\f2\\fs20  vector of single characters (e.g., \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"C\"\n\\f2\\fs20 , \n\\f1\\fs18 \"G\"\n\\f2\\fs20 ), or \n\\f1\\fs18 \"integer\"\n\\f2\\fs20  to obtain it as an \n\\f1\\fs18 integer\n\\f2\\fs20  vector (e.g., \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 1\n\\f2\\fs20 , \n\\f1\\fs18 2\n\\f2\\fs20 ), using SLiM\\'92s standard code of A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)mm16To256(float\\'a0mutationMatrix16)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns a 64\\'d74 mutation matrix that is functionally identical to the supplied 4\\'d74 mutation matrix in \n\\f1\\fs18 mutationMatrix16\n\\f2\\fs20 .  The mutation rate for each of the 64 trinucleotides will depend only upon the central nucleotide of the trinucleotide, and will be taken from the corresponding entry for the same nucleotide in \n\\f1\\fs18 mutationMatrix16\n\\f2\\fs20 .  This function can be used to easily construct a simple trinucleotide-based mutation matrix which can then be modified so that specific trinucleotides sustain a mutation rate that does not depend only upon their central nucleotide.\\\nSee the documentation for \n\\f1\\fs18 initializeGenomicElementType()\n\\f2\\fs20  for further discussion of how these 64\\'d74 mutation matrices are interpreted and used.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)mmJukesCantor(float$\\'a0alpha)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns a mutation matrix representing a Jukes\\'96Cantor (1969) model with mutation rate \n\\f1\\fs18 alpha\n\\f2\\fs20  to each possible alternative nucleotide at a site.  This 2\\'d72 matrix is suitable for use with \n\\f1\\fs18 initializeGenomicElementType()\n\\f2\\fs20 .  Note that the actual mutation rate produced by this matrix is \n\\f1\\fs18 3*alpha\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)mmKimura(float$\\'a0alpha, float$\\'a0beta)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns a mutation matrix representing a Kimura (1980) model with transition rate \n\\f1\\fs18 alpha\n\\f2\\fs20  and transversion rate \n\\f1\\fs18 beta\n\\f2\\fs20 .  This 2\\'d72 matrix is suitable for use with \n\\f1\\fs18 initializeGenomicElementType()\n\\f2\\fs20 .  Note that the actual mutation rate produced by this model is \n\\f1\\fs18 alpha+2*beta\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)nucleotideCounts(is\\'a0sequence)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 A convenience function that returns an \n\\f1\\fs18 integer\n\\f2\\fs20  vector of length four, providing the number of occurrences of A / C / G / T nucleotides, respectively, in the supplied nucleotide sequence.  The parameter sequence may be a singleton \n\\f1\\fs18 string\n\\f2\\fs20  (e.g., \n\\f1\\fs18 \"TATA\"\n\\f2\\fs20 ), a \n\\f1\\fs18 string\n\\f2\\fs20  vector of single characters (e.g., \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 ), or an \n\\f1\\fs18 integer\n\\f2\\fs20  vector (e.g., 3, \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 ), using SLiM\\'92s standard code of A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)nucleotideFrequencies(is\\'a0sequence)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 A convenience function that returns a \n\\f1\\fs18 float\n\\f2\\fs20  vector of length four, providing the frequencies of occurrences of A / C / G / T nucleotides, respectively, in the supplied nucleotide sequence.  The parameter sequence may be a singleton \n\\f1\\fs18 string\n\\f2\\fs20  (e.g., \n\\f1\\fs18 \"TATA\"\n\\f2\\fs20 ), a \n\\f1\\fs18 string\n\\f2\\fs20  vector of single characters (e.g., \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 ), or an \n\\f1\\fs18 integer\n\\f2\\fs20  vector (e.g., 3, \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 ), using SLiM\\'92s standard code of A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (integer)nucleotidesToCodons(is\\'a0sequence)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns the codon sequence corresponding to the nucleotide sequence in \n\\f1\\fs18 sequence\n\\f2\\fs20 .  The codon sequence is an \n\\f1\\fs18 integer\n\\f2\\fs20  vector with values from \n\\f1\\fs18 0\n\\f2\\fs20  to \n\\f1\\fs18 63\n\\f2\\fs20 , based upon successive nucleotide triplets in the nucleotide sequence.  The codon value for a given nucleotide triplet XYZ is 16X\\'a0+\\'a04Y\\'a0+\\'a0Z, where X, Y, and Z have the usual values A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .  For example, the triplet AAA has a codon value of \n\\f1\\fs18 0\n\\f2\\fs20 , AAC is \n\\f1\\fs18 1\n\\f2\\fs20 , AAG is \n\\f1\\fs18 2\n\\f2\\fs20 , AAT is \n\\f1\\fs18 3\n\\f2\\fs20 , ACA is \n\\f1\\fs18 4\n\\f2\\fs20 , and on upward to TTT which is \n\\f1\\fs18 63\n\\f2\\fs20 .  If the nucleotide sequence AACACATTT is passed in, the codon vector \n\\f1\\fs18 1 4 63\n\\f2\\fs20  will therefore be returned.  These codon values can be useful in themselves; they can also be passed to \n\\f1\\fs18 codonsToAminoAcids()\n\\f2\\fs20  to translate them into the corresponding amino acid sequence if desired.\\\nThe nucleotide sequence in \n\\f1\\fs18 sequence\n\\f2\\fs20  may be supplied in any of three formats: a \n\\f1\\fs18 string\n\\f2\\fs20  vector with single-letter nucleotides (e.g., \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 ), a singleton \n\\f1\\fs18 string\n\\f2\\fs20  of nucleotide letters (e.g., \n\\f1\\fs18 \"TATA\"\n\\f2\\fs20 ), or an \n\\f1\\fs18 integer\n\\f2\\fs20  vector of nucleotide values (e.g., \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 ) using SLiM\\'92s standard code of A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .  If the choice of format is not driven by other considerations, such as ease of manipulation, then the singleton \n\\f1\\fs18 string\n\\f2\\fs20  format will certainly be the most memory-efficient for long sequences, and will probably also be the fastest.  The nucleotide sequence provided must be a multiple of three in length, so that it translates to an integral number of codons.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf0 \\kerning1\\expnd0\\expndtw0 (is)randomNucleotides(integer$\\'a0length, [Nif\\'a0basis\\'a0=\\'a0NULL], [string$\\'a0format\\'a0=\\'a0\"string\"])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\nGenerates a new random nucleotide sequence with \n\\f1\\fs18 length\n\\f2\\fs20  bases.  The four nucleotides ACGT are equally probable if \n\\f1\\fs18 basis\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default); otherwise, \n\\f1\\fs18 basis\n\\f2\\fs20  may be a 4-element \n\\f1\\fs18 integer\n\\f2\\fs20  or \n\\f1\\fs18 float\n\\f2\\fs20  vector providing relative fractions for A, C, G, and T respectively (these need not sum to \n\\f1\\fs18 1.0\n\\f2\\fs20 , as they will be normalized).  More complex generative models such as Markov processes are not supported intrinsically in SLiM at this time, but arbitrary generated sequences may always be loaded from files on disk.\\\nThe \n\\f1\\fs18 format\n\\f2\\fs20  parameter controls the format of the returned sequence.  It may be \n\\f1\\fs18 \"string\"\n\\f2\\fs20  to obtain the generated sequence as a singleton \n\\f1\\fs18 string\n\\f2\\fs20  (e.g., \n\\f1\\fs18 \"TATA\"\n\\f2\\fs20 ), \n\\f1\\fs18 \"char\"\n\\f2\\fs20  to obtain it as a \n\\f1\\fs18 string\n\\f2\\fs20  vector of single characters (e.g., \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 , \n\\f1\\fs18 \"T\"\n\\f2\\fs20 , \n\\f1\\fs18 \"A\"\n\\f2\\fs20 ), or \n\\f1\\fs18 \"integer\"\n\\f2\\fs20  to obtain it as an \n\\f1\\fs18 integer\n\\f2\\fs20  vector (e.g., \n\\f1\\fs18 3\n\\f2\\fs20 , \n\\f1\\fs18 0\n\\f2\\fs20 , \n\\f1\\fs18 3, 0\n\\f2\\fs20 ), using SLiM\\'92s standard code of A=\n\\f1\\fs18 0\n\\f2\\fs20 , C=\n\\f1\\fs18 1\n\\f2\\fs20 , G=\n\\f1\\fs18 2\n\\f2\\fs20 , T=\n\\f1\\fs18 3\n\\f2\\fs20 .  For passing directly to \n\\f1\\fs18 initializeAncestralNucleotides()\n\\f2\\fs20 , format \n\\f1\\fs18 \"string\"\n\\f2\\fs20  (a singleton string) will certainly be the most memory-efficient, and probably also the fastest.  Memory efficiency can be a significant consideration; the nucleotide sequence for a chromosome of length 10\n\\fs13\\fsmilli6667 \\super 9\n\\fs20 \\nosupersub  will occupy approximately 1 GB of memory when stored as a singleton string (with one byte per nucleotide), and much more if stored in the other formats.  However, the other formats can be easier to work with in Eidos, and so may be preferable for relatively short chromosomes if you are manipulating the generated sequence.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 \\kerning1\\expnd0\\expndtw0 3.3.  Population genetics utilities\n\\f2\\b0\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (float$)calcDxy(object<Haplosome>\\'a0haplosomes1, object<Haplosome>\\'a0haplosomes2, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [logical$\\'a0normalize\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the estimated \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub  between two \n\\f1\\fs18 Haplosome\n\\f2\\fs20  vectors for the set of mutations given in \n\\f1\\fs18 muts\n\\f2\\fs20 .  \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub  is the expected number of differences between two sequences, typically drawn from two different subpopulations whose haplosomes are given in \n\\f1\\fs18 haplosomes1\n\\f2\\fs20  and \n\\f1\\fs18 haplosomes2\n\\f2\\fs20 .  It is therefore a metric of genetic divergence, comparable in some respects to \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub ; see Cruickshank and Hahn (2014, Molecular Ecology) for a discussion of \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  versus \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub .  This method implements \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub  as defined by Nei (1987) in Molecular Evolutionary Genomics (eq. 10.20), with optimizations for computational efficiency based upon an assumption that that multiallelic loci are rare (this is compatible with the infinite-sites model).\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full haplosomes \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub .\\\nIf \n\\f1\\fs18 normalize\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20  (the default), the returned \n\\f1\\fs18 float\n\\f2\\fs20  value is simply the expected number of differences, following Nei.  Often, however, it will be desirable to normalize that value by dividing by the length of the sequence considered, yielding the expected number of differences \n\\f3\\i per site\n\\f2\\i0 , a metric that then does not depend upon the sequence length; passing \n\\f1\\fs18 normalize=T\n\\f2\\fs20  will return that normalized value, and that is probably what most users of this function will want.\\\nThe implementation of \n\\f1\\fs18 calcDxy()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation in \n\\f1\\fs18 muts\n\\f2\\fs20  as independent in its calculations (similar to \n\\f1\\fs18 calcPi()\n\\f2\\fs20 ); in other words, if mutations are stacked, the \n\\f3\\i D\n\\f2\\i0\\fs13\\fsmilli6667 \\sub xy\n\\fs20 \\nosupersub  value calculated is \n\\f3\\i by mutation\n\\f2\\i0 , not \n\\f3\\i by site\n\\f2\\i0 .  Similarly, if multiple \n\\f1\\fs18 Mutation\n\\f2\\fs20  objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each \n\\f1\\fs18 Mutation\n\\f2\\fs20  object is treated separately for purposes of the calculation, just as if they were at different sites.  One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of these choices will be negligible; however, in some models these distinctions may be important.  See \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  for further discussion.\\\nAll haplosomes and mutations must be associated with the same chromosome.  If \n\\f1\\fs18 muts\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all mutations in the population associated with the same chromosome as the given haplosomes will be used.\\\nThis function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcFST(object<Haplosome>\\'a0haplosomes1, object<Haplosome>\\'a0haplosomes2, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  between two \n\\f1\\fs18 Haplosome\n\\f2\\fs20  vectors \\'96 typically, but not necessarily, the haplosomes that constitute two different subpopulations (which we will assume for the purposes of this discussion).  In general, higher \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  indicates greater genetic divergence between subpopulations.  The haplosomes may be associated with more than one chromosome, in a multi-chromosome model; if so, \n\\f1\\fs18 haplosomes1\n\\f2\\fs20  and \n\\f1\\fs18 haplosomes2\n\\f2\\fs20  must be associated with the same set of chromosomes, defining the focal set of chromosomes for the calculation.\\\nThe calculation is done using only the mutations in \n\\f1\\fs18 muts\n\\f2\\fs20 ; if \n\\f1\\fs18 muts\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20 , all mutations associated with the focal chromosomes are used.  The \n\\f1\\fs18 muts\n\\f2\\fs20  parameter can be used to calculate the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  only for a particular mutation type (by passing only mutations of that type), for example; it can focus the calculation on particular mutations of interest.  The mutations in \n\\f1\\fs18 muts\n\\f2\\fs20  must always be associated with the focal chromosomes.\\\nIf there is a single focal chromosome, the calculation can be narrowed to apply to only a window \\'96 a subrange of the focal chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the chromosome-wide \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub , which is often used to assess the overall level of genetic divergence between sister species or allopatric subpopulations.\\\nThe code for \n\\f1\\fs18 calcFST()\n\\f2\\fs20  is, roughly, an Eidos implementation of Wright\\'92s definition of \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  (but see below for further discussion and clarification):\\\n\n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\expnd0\\expndtw0\\kerning0\n\\nosupersub  = 1 - \n\\f3\\i H\n\\f2\\i0\\fs13\\fsmilli6667 \\kerning1\\expnd0\\expndtw0 \\sub S\n\\fs20 \\expnd0\\expndtw0\\kerning0\n\\nosupersub  / \n\\f3\\i H\n\\f2\\i0\\fs13\\fsmilli6667 \\kerning1\\expnd0\\expndtw0 \\sub T\n\\fs20 \\expnd0\\expndtw0\\kerning0\n\\nosupersub \\\n\\kerning1\\expnd0\\expndtw0 where \n\\f3\\i H\n\\fs13\\fsmilli6667 \\sub S\n\\f2\\i0\\fs20 \\nosupersub  is the average heterozygosity in the two subpopulations, and \n\\f3\\i H\n\\fs13\\fsmilli6667 \\sub T \n\\f2\\i0\\fs20 \\nosupersub is the total heterozygosity when both subpopulations are combined.  In this implementation, the two haplosome vectors are weighted equally, not weighted by their size.  In SLiM 3, the implementation followed Wright\\'92s definition closely, and returned the \n\\f3\\i average of ratios\n\\f2\\i0 : \n\\f1\\fs18 mean(1.0 - H_s/H_t)\n\\f2\\fs20 , in the Eidos code.  In SLiM 4, it returns the \n\\f3\\i ratio of averages\n\\f2\\i0  instead: \n\\f1\\fs18 1.0 - mean(H_s)/mean(H_t)\n\\f2\\fs20 .  In other words, the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  value reported by SLiM 4 is an average across the specified mutations in the two sets of haplosomes, where \n\\f1\\fs18 H_s\n\\f2\\fs20  and \n\\f1\\fs18 H_t\n\\f2\\fs20  are first averaged across all specified mutations prior to taking the ratio of the two.  This ratio of averages is less biased than the average of ratios, and and is generally considered to be best practice (see, e.g., Bhatia et al., 2013).  This means that the behavior of \n\\f1\\fs18 calcFST()\n\\f2\\fs20  differs between SLiM 3 and SLiM 4.\\\nAs can be seen from its equation, the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub ST\n\\fs20 \\nosupersub  is undefined if \n\\f3\\i H\n\\fs13\\fsmilli6667 \\sub T\n\\f2\\i0\\fs20 \\nosupersub  is zero, which occurs if no mutations are present in the haplosomes provided (given the optionally specified window and set of mutations).  In that case, \n\\f1\\fs18 calcFST()\n\\f2\\fs20  will return \n\\f1\\fs18 NAN\n\\f2\\fs20 .  It is up to the caller to detect this with \n\\f1\\fs18 isNAN()\n\\f2\\fs20  and handle it as necessary.\\\nThe implementation of \n\\f1\\fs18 calcFST()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation in \n\\f1\\fs18 muts\n\\f2\\fs20  as independent in the heterozygosity calculations; in other words, if mutations are stacked, the heterozygosity calculated is \n\\f3\\i by mutation\n\\f2\\i0 , not \n\\f3\\i by site\n\\f2\\i0 .  Similarly, if multiple \n\\f1\\fs18 Mutation\n\\f2\\fs20  objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each \n\\f1\\fs18 Mutation\n\\f2\\fs20  object is treated separately for purposes of the heterozygosity calculation, just as if they were at different sites.  One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of these choices will be negligible; however, in some models these distinctions may be important.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcHeterozygosity(object<Haplosome>\\'a0haplosomes, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the heterozygosity for a vector of haplosomes (containing at least one element), based upon the frequencies of mutations in the haplosomes.  The result is the \n\\f3\\i expected\n\\f2\\i0  heterozygosity, for the individuals to which the haplosomes belong, assuming that they are under Hardy-Weinberg equilibrium; this can be compared to the \n\\f3\\i observed\n\\f2\\i0  heterozygosity of an individual, as calculated by \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20 .  Often \n\\f1\\fs18 haplosomes\n\\f2\\fs20  will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.  By default, with \n\\f1\\fs18 muts=NULL\n\\f2\\fs20 , the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for \n\\f1\\fs18 muts\n\\f2\\fs20 .\\\nIn multi-chromosome models, all of the haplosomes and mutations passed in \n\\f1\\fs18 haplosomes\n\\f2\\fs20  and \n\\f1\\fs18 muts\n\\f2\\fs20  must all be associated with the same single chromosome.  If you wish to calculate heterozygosity across multiple chromosomes, you can simply write a \n\\f1\\fs18 for\n\\f2\\fs20  loop that calculates it for each chromosome and combines the results; but it is not entirely clear how to weight the chromosomes to produce a single number, especially when sex chromosomes and other chromosomes of variable ploidy might be represented in \n\\f1\\fs18 haplosomes\n\\f2\\fs20 , so it is not done automatically by this function.\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide heterozygosity.\\\nThe implementation of \n\\f1\\fs18 calcHeterozygosity()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation as independent in the heterozygosity calculations.  One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this choice will be negligible; however, in some models this distinction may be important.  See \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  for further discussion.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcInbreedingLoad(object<Haplosome>\\'a0haplosomes, [Nio<MutationType>$\\'a0mutType\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates inbreeding load (the haploid number of lethal equivalents, or \n\\f3\\i B\n\\f2\\i0 ) for a vector of haplosomes (containing at least one element) passed in \n\\f1\\fs18 haplosomes\n\\f2\\fs20 .  The calculation can be limited to a focal mutation type passed in \n\\f1\\fs18 mutType\n\\f2\\fs20  (which may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  representing the ID of the desired mutation type, or a \n\\f1\\fs18 MutationType\n\\f2\\fs20  object specified directly); if \n\\f1\\fs18 mutType\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all of the mutations for the focal species will be considered.  In any case, only deleterious mutations (those with a negative selection coefficient) will be included in the final calculation.\\\nThe inbreeding load is a measure of the quantity of recessive deleterious variation that is heterozygous in a population and can contribute to fitness declines under inbreeding.  This function implements the following equation from Morton et al. (1956), which assumes no epistasis and random mating:\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f3\\i\\fs22 \\cf2 B\n\\f2\\i0  = sum(\n\\f3\\i qs\n\\f2\\i0 ) \\uc0\\u8722  sum(\n\\f3\\i q\n\\f2\\i0\\fs14\\fsmilli7333 \\super 2\n\\f3\\i\\fs22 \\nosupersub s\n\\f2\\i0 ) \\uc0\\u8722  2sum(\n\\f3\\i q\n\\f2\\i0 (1\\uc0\\u8722 \n\\f3\\i q\n\\f2\\i0 )\n\\f3\\i sh\n\\f2\\i0 )\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\fs20 \\cf2 where \n\\f3\\i q\n\\f2\\i0  is the frequency of a given deleterious allele, \n\\f3\\i s\n\\f2\\i0  is the absolute value of the selection coefficient, and \n\\f3\\i h\n\\f2\\i0  is its dominance coefficient.  Note that the implementation, viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , sets a maximum |\n\\f3\\i s\n\\f2\\i0 | of \n\\f1\\fs18 1.0\n\\f2\\fs20  (i.e., a lethal allele); |\n\\f3\\i s\n\\f2\\i0 | can sometimes be greater than \n\\f1\\fs18 1.0\n\\f2\\fs20  when \n\\f3\\i s\n\\f2\\i0  is drawn from a distribution, but in practice an allele with \n\\f3\\i s\n\\f2\\i0 \\'a0<\\'a0\n\\f1\\fs18 -1.0\n\\f2\\fs20  has the same lethal effect as when \n\\f3\\i s\n\\f2\\i0 \\'a0=\\'a0\n\\f1\\fs18 -1.0\n\\f2\\fs20 .  Also note that this implementation will not work when the model changes the dominance coefficients of mutations using \n\\f1\\fs18 mutationEffect()\n\\f2\\fs20  callbacks, since it relies on the \n\\f1\\fs18 dominanceCoeff\n\\f2\\fs20  property of \n\\f1\\fs18 MutationType\n\\f2\\fs20 . Finally, note that, to estimate the diploid number of lethal equivalents (2\n\\f3\\i B\n\\f2\\i0 ), the result from this function can simply be multiplied by two.\\\nThis function was contributed by Chris Kyriazis; thanks, Chris!\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)calcLD_D(object<Mutation>$\\'a0mut1, [No<Mutation>\\'a0mut2\\'a0=\\'a0NULL], [No<Haplosome>\\'a0haplosomes\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the linkage disequilibrium (LD) coefficient \n\\f3\\i D\n\\f2\\i0  between a focal mutation \n\\f1\\fs18 mut1\n\\f2\\fs20  and one or more mutations in \n\\f1\\fs18 mut2\n\\f2\\fs20 , evaluated across a set of haplosomes given by \n\\f1\\fs18 haplosomes\n\\f2\\fs20 .  The result is a \n\\f1\\fs18 float\n\\f2\\fs20  vector that matches the size and order of \n\\f1\\fs18 mut2\n\\f2\\fs20 .  The implementation of this function, viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , calculates \n\\f3\\i D\n\\f2\\i0  as defined by Hill and Robertson (1968, p. 226).  The coefficient \n\\f3\\i D\n\\f2\\i0  is within [\\uc0\\u8722 \n\\f3\\i p\n\\f2\\i0 (1\\uc0\\u8722 \n\\f3\\i p\n\\f2\\i0 ), \n\\f3\\i p\n\\f2\\i0 (1\\uc0\\u8722 \n\\f3\\i p\n\\f2\\i0 )], where \n\\f3\\i p\n\\f2\\i0  is the frequency of the more common mutation (that is, \n\\f3\\i p\n\\f2\\i0 \\'a0=\\'a0max(\n\\f3\\i f\n\\f2\\i0\\fs13\\fsmilli6667 \\sub 1\n\\fs20 \\nosupersub , \n\\f3\\i f\n\\f2\\i0\\fs13\\fsmilli6667 \\sub 2\n\\fs20 \\nosupersub ) where \n\\f3\\i f\n\\f2\\i0\\fs13\\fsmilli6667 \\sub 1\n\\fs20 \\nosupersub  and \n\\f3\\i f\n\\f2\\i0\\fs13\\fsmilli6667 \\sub 2\n\\fs20 \\nosupersub  are the frequencies of the two mutations for which \n\\f3\\i D\n\\f2\\i0  is being calculated); for the normalized LD metric \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub , which is within [0, 1], see \n\\f1\\fs18 calcLD_Rsquared()\n\\f2\\fs20 .  Departures of \n\\f3\\i D\n\\f2\\i0  from zero indicate LD; more specifically, \n\\f3\\i D\n\\f2\\i0 \\'a0>\\'a00 indicates that the mutations occur together more often than expected by chance (positive linkage), whereas \n\\f3\\i D\n\\f2\\i0 \\'a0<\\'a00 indicates they occur together less often than expected by chance (negative linkage).\\\nAll mutations in \n\\f1\\fs18 mut2\n\\f2\\fs20  must be associated with the same chromosome as \n\\f1\\fs18 mut1\n\\f2\\fs20 ; this function does not currently calculate LD between mutations associated with different chromosomes.  If \n\\f1\\fs18 mut2\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all such mutations in the population (including \n\\f1\\fs18 mut1\n\\f2\\fs20  itself) will be used.  Similarly, all haplosomes must be associated with the same chromosome as \n\\f1\\fs18 mut1\n\\f2\\fs20 .  If the \n\\f1\\fs18 haplosomes\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all such haplosomes in the population will be used.\\\nThis function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float)calcLD_Rsquared(object<Mutation>$\\'a0mut1, [No<Mutation>\\'a0mut2\\'a0=\\'a0NULL], [No<Haplosome>\\'a0haplosomes\\'a0=\\'a0NULL], [logical$\\'a0squared\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the linkage disequilibrium (LD) squared correlation coefficient \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub  between a focal mutation \n\\f1\\fs18 mut1\n\\f2\\fs20  and one or more mutations in \n\\f1\\fs18 mut2\n\\f2\\fs20 , evaluated across a set of haplosomes given by \n\\f1\\fs18 haplosomes\n\\f2\\fs20 .  The result is a \n\\f1\\fs18 float\n\\f2\\fs20  vector that matches the size and order of \n\\f1\\fs18 mut2\n\\f2\\fs20 .  The implementation of this function, viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , calculates \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub  as defined by Hill and Robertson (1968, p. 227).  The squared correlation coefficient \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub  is a normalized measure of LD within [0, 1] (for the unnormalized LD coefficient \n\\f3\\i D\n\\f2\\i0 , see \n\\f1\\fs18 calcLD_D()\n\\f2\\fs20 ).  When \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0=\\'a00, there is no statistical association between the mutations; they co-occur as expected by chance.  A value of \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub \\'a0=\\'a01 indicates complete correlation: the mutations either always appear together or never appear together, depending on the sign of the underlying correlation coefficient \n\\f3\\i r\n\\f2\\i0 .  To obtain the raw (signed) \n\\f3\\i r\n\\f2\\i0  value instead of \n\\f3\\i r\n\\f2\\i0\\fs13\\fsmilli6667 \\super 2\n\\fs20 \\nosupersub , you can pass \n\\f1\\fs18 squared=F\n\\f2\\fs20  instead of the default of \n\\f1\\fs18 T\n\\f2\\fs20 .\\\nAll mutations in \n\\f1\\fs18 mut2\n\\f2\\fs20  must be associated with the same chromosome as \n\\f1\\fs18 mut1\n\\f2\\fs20 ; this function does not currently calculate LD between mutations associated with different chromosomes.  If \n\\f1\\fs18 mut2\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all such mutations in the population (including \n\\f1\\fs18 mut1\n\\f2\\fs20  itself) will be used.  Similarly, all haplosomes must be associated with the same chromosome as \n\\f1\\fs18 mut1\n\\f2\\fs20 .  If the \n\\f1\\fs18 haplosomes\n\\f2\\fs20  parameter is \n\\f1\\fs18 NULL\n\\f2\\fs20  (the default), all such haplosomes in the population will be used.\\\nThis function was written by Vitor Sudbrack (currently affiliated with University of Lausanne).\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcMeanFroh(object<Individual>\\'a0individuals, [integer$\\'a0minimumLength\\'a0=\\'a01000000], [Niso<Chromosome>$\\'a0chromosome\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the mean value of the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  statistic across the individuals passed in \n\\f1\\fs18 individuals\n\\f2\\fs20 .  This statistic is a measure of individual autozygosity, likely resulting from inbreeding, and is calculated based upon \\'93runs of homozygosity\\'94, or ROH, in the genome of an individual.  Broadly speaking, \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  is the proportion of an individual\\'92s genome that is spanned by ROH longer than a given threshold length.  However, it should be noted that there are many different ways of calculating \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub , producing different results.  For example, the threshold length might be a given constant, or might be determined statistically from the characteristics of the population.  Furthermore, some heterozygous sites might be discarded (to compensate for genotyping errors), a minimum SNP density might be required within a sliding window for an ROH to be diagnosed, and so forth \\'96 it can get quite complex, as seen in the software PLINK (Purcell et al., 2007) and GARLIC (Szpiech, Blant and Pemberton, 2017).  The method used by \n\\f1\\fs18 calcMeanFroh()\n\\f2\\fs20  is the simplest possible method, assessing ROH for each individual directly from the simulated mutations without filtering or modification, and applying a given constant threshold length.  If a more sophisticated \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  algorithm is desired, one could modify the implementation of \n\\f1\\fs18 calcMeanFroh()\n\\f2\\fs20 , which is viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , or one could output VCF data from SLiM and analyze it with other tools, perhaps calling out from the running SLiM script with \n\\f1\\fs18 system()\n\\f2\\fs20 .\\\nThe threshold ROH length used by \n\\f1\\fs18 calcMeanFroh()\n\\f2\\fs20  is supplied by the parameter \n\\f1\\fs18 minimumLength\n\\f2\\fs20 .  It defaults to \n\\f1\\fs18 1e6\n\\f2\\fs20 , or 1 Mbp, since that is a length commonly used in the literature, but can be adjusted as desired.\\\nThe \n\\f1\\fs18 chromosome\n\\f2\\fs20  parameter can be supplied to focus the \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  calculation on a specific chromosome; otherwise, the calculation spans all chromosomes for which the individual is actually diploid (without a null haplosome).  If \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  cannot be calculated for an individual (due to the presence of null haplosomes for every intrinsically diploid chromosome being analyzed), that individual is omitted from the mean \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  calculation; for example, if an X chromosome is the focal chromosome being analyzed, all males will be omitted from the mean \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  calculation.  If all individuals are omitted from the mean \n\\f3\\i F\n\\f2\\i0\\fs13\\fsmilli6667 \\sub roh\n\\fs20 \\nosupersub  calculation for this reason, \n\\f1\\fs18 NAN\n\\f2\\fs20  is returned.\\\nThis function was developed with advice from Ryan Chaffee.  Thanks, Ryan!\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcPairHeterozygosity(object<Haplosome>$\\'a0haplosome1, object<Haplosome>$\\'a0haplosome2, [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL], [logical$\\'a0infiniteSites\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the heterozygosity for a pair of haplosomes; these will typically be two homologous haplosomes of the same diploid individual, but any two haplosomes associated with the same chromosome may be supplied.\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide heterozygosity.\\\nThe implementation \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation as independent in the heterozygosity calculations by default (i.e., with \n\\f1\\fs18 infiniteSites=T\n\\f2\\fs20 ).  If mutations are stacked, the heterozygosity calculated therefore depends upon the number of \n\\f3\\i unshared mutations\n\\f2\\i0 , not the number of \n\\f3\\i differing sites\n\\f2\\i0 .  Similarly, if multiple \n\\f1\\fs18 Mutation\n\\f2\\fs20  objects exist in different haplosomes at the same site (whether representing different genetic states, or multiple mutational lineages for the same genetic state), each \n\\f1\\fs18 Mutation\n\\f2\\fs20  object is treated separately for purposes of the heterozygosity calculation, just as if they were at different sites.  One could regard these choices as embodying an infinite-sites interpretation of the segregating mutations.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this choice will be negligible; however, in some models this distinction may be important.  The behavior of \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  can be switched to calculate based upon the number of differing sites, rather than the number of unshared mutations, by passing \n\\f1\\fs18 infiniteSites=F\n\\f2\\fs20 .\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcPi(object<Haplosome>\\'a0haplosomes, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates \n\\f7\\i \\uc0\\u960 \n\\f2\\i0  (nucleotide diversity, a metric of genetic diversity) for a vector of haplosomes (containing at least two elements), based upon the mutations in the haplosomes.  \n\\f7\\i \\uc0\\u960 \n\\f2\\i0  is computed by calculating the mean number of pairwise differences at each site, summing across all sites, and dividing by the number of sites.  Therefore, it is interpretable as the number of differences per site expected between two randomly chosen sequences.  The mathematical formulation (as an estimator of the population parameter \n\\f7\\i \\uc0\\u952 \n\\f2\\i0 ) is based on work in Nei and Li (1979), Nei and Tajima (1981), and Tajima (1983; equation A3).  The exact formula used here is common in textbooks (e.g., equations 9.1\\'969.5 in Li 1997, equation 3.3 in Hahn 2018, or equation 2.2 in Coop 2020).\\\nOften \n\\f1\\fs18 haplosomes\n\\f2\\fs20  will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.  By default, with \n\\f1\\fs18 muts=NULL\n\\f2\\fs20 , the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for \n\\f1\\fs18 muts\n\\f2\\fs20 .\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide value of \n\\f7\\i \\uc0\\u960 \n\\f2\\i0 .\\\nThe implementation of \n\\f1\\fs18 calcPi()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation as independent in the heterozygosity calculations.  One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with \n\\f1\\fs18 calcHeterozygosity()\n\\f2\\fs20 .  Indeed, finite-sites models of \n\\f7\\i \\uc0\\u960 \n\\f2\\i0  have been derived (Tajima 1996) though are not used here.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.  See \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  for further discussion.  This function was written by Nick Bailey (currently affiliated with CNRS and the Laboratory of Biometry and Evolutionary Biology at University Lyon 1), with helpful input from Peter Ralph and Chase Nelson.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (numeric)calcSFS([Ni$\\'a0binCount\\'a0=\\'a0NULL], [No<Haplosome>\\'a0haplosomes\\'a0=\\'a0NULL], [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [string$\\'a0metric\\'a0=\\'a0\"density\"], [logical$\\'a0fold\\'a0=\\'a0F])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates the site frequency spectrum, or SFS, for the mutations specified by \n\\f1\\fs18 muts\n\\f2\\fs20 , within the haplosomes specified by \n\\f1\\fs18 haplosomes\n\\f2\\fs20 .  The site frequency spectrum or SFS (sometimes called the allele frequency spectrum, although some authors distinguish between the two) is essentially a histogram of the frequencies of the mutations within the haplosomes; the first bin spans the lowest range of frequencies (down to a frequency of \n\\f1\\fs18 0.0\n\\f2\\fs20 , or a count of \n\\f1\\fs18 1\n\\f2\\fs20 ), whereas the last bin spans the highest range of frequencies (up to a frequency of \n\\f1\\fs18 1.0\n\\f2\\fs20 , or a count equal to number of haplosomes minus one).  The idea was introduced by Watterson (1975), and will be discussed in any population genetics textbook (e.g., A. Cutter, 2019, pp. 50\\'9652).  This histogram can be returned as a \n\\f1\\fs18 float\n\\f2\\fs20  vector of density values for each bin by specifying \n\\f1\\fs18 \"density\"\n\\f2\\fs20  for \n\\f1\\fs18 metric\n\\f2\\fs20  (the default), or as an \n\\f1\\fs18 integer\n\\f2\\fs20  vector of count values for each bin by specifying \n\\f1\\fs18 \"count\"\n\\f2\\fs20 .\\\nThere are two modes of operation for \n\\f1\\fs18 calcSFS()\n\\f2\\fs20 .  If a specific number of bins is passed for \n\\f1\\fs18 binCount\n\\f2\\fs20 , then the frequency range \n\\f1\\fs18 [0.0, 1.0]\n\\f2\\fs20  is subdivided into \n\\f1\\fs18 binCount\n\\f2\\fs20  intervals of equal width, and the mutations are tallied into those bins according to their frequencies within the haplosomes to produce the histogram.  In this mode, there will be exactly \n\\f1\\fs18 binCount\n\\f2\\fs20  elements in the returned vector.  Note that either \n\\f1\\fs18 \"density\"\n\\f2\\fs20  or \n\\f1\\fs18 \"count\"\n\\f2\\fs20  can be chosen in this mode; you can return the frequency bin tallies as either densities or counts.\\\nIn the other mode of operation, chosen with a \n\\f1\\fs18 binCount\n\\f2\\fs20  value of \n\\f1\\fs18 NULL\n\\f2\\fs20 , the bins instead represent the count of the number of occurrences for each mutation, and range from a count of \n\\f1\\fs18 1\n\\f2\\fs20  (the bin for mutations that occur only once in the haplosomes, sometimes called \\'93singletons\\'94) up to a count of \n\\f1\\fs18 N-1\n\\f2\\fs20  where \n\\f1\\fs18 N\n\\f2\\fs20  is the number of haplosomes.  (Note that mutations occurring in all \n\\f1\\fs18 N\n\\f2\\fs20  haplosomes are not included in the tally, since they would not be empirically observable.)  In this mode, there will be exactly \n\\f1\\fs18 N-1\n\\f2\\fs20  elements in the returned vector.  Again, either \n\\f1\\fs18 \"density\"\n\\f2\\fs20  or \n\\f1\\fs18 \"count\"\n\\f2\\fs20  can be chosen in this mode; you can return the count bin tallies as either densities or counts (it\\'92s a bit confusing, but we\\'92re talking about two different kinds of \\'93counts\\'94, the count of the number of times a mutation occurs in the haplosomes versus the count of the number of mutations that were tallied into a particular count bin).\\\nThe \n\\f1\\fs18 haplosomes\n\\f2\\fs20  parameter can be either a vector of \n\\f1\\fs18 Haplosome\n\\f2\\fs20  objects or \n\\f1\\fs18 NULL\n\\f2\\fs20 .  If \n\\f1\\fs18 NULL\n\\f2\\fs20  is passed, \n\\f1\\fs18 calcSFS()\n\\f2\\fs20  will calculate the SFS across the whole species, using all non-null haplosomes present (and thus there must be only a single species in the model, since an SFS cannot be calculated across multiple species).  Otherwise, \n\\f1\\fs18 haplosomes\n\\f2\\fs20  can contain any set of haplosomes desired, such as from the individuals of one subpopulation, several subpopulations, or an entire species.  However, they must all belong to the same species, and null haplosomes will be automatically and silently excluded from the set.\\\nThe \n\\f1\\fs18 muts\n\\f2\\fs20  parameter can be either a vector of \n\\f1\\fs18 Mutation\n\\f2\\fs20  objects or \n\\f1\\fs18 NULL\n\\f2\\fs20 .  If \n\\f1\\fs18 NULL\n\\f2\\fs20  is passed, \n\\f1\\fs18 calcSFS()\n\\f2\\fs20  will calculate the SFS across all mutations belonging to the focal species (as determined from the species of the haplosomes).  Otherwise, \n\\f1\\fs18 muts\n\\f2\\fs20  can contain any set of mutations desired, such as mutations belonging to a specific mutation type, mutations within a specific range of positions along the chromosome, or all of the mutations in the focal species.\\\nThe \n\\f1\\fs18 binCount\n\\f2\\fs20  and \n\\f1\\fs18 metric\n\\f2\\fs20  parameters have already been discussed.  Finally, the \n\\f1\\fs18 fold\n\\f2\\fs20  parameter, if \n\\f1\\fs18 T\n\\f2\\fs20 , \\'93folds\\'94 the calculated SFS, adding the first and last bins, the second and next-to-last bins, etc., until the center is reached.  Folding is common when working with empirical data, where one often doesn\\'92t know the \\'93polarity\\'94 \\'96 which allele at a site is ancestral and which is derived.  Folding solves this problem, because the polarity then doesn\\'92t matter; the tally for a given mutation ends up in the same bin regardless.  If the number of bins is even, folding can be performed without ambiguity; the final number of bins is exactly half the original number of bins, and each final bin is the sum of two original bins.  If the number of bins is odd, the correct treatment of the central bin is somewhat ambiguous.  In \n\\f1\\fs18 calcFST()\n\\f2\\fs20 , the central bin is added to itself \\'96 doubled \\'96 and the number of bins is equal to half the original number of bins rounded up.  If you would prefer to exclude the central bin altogether \\'96 another population treatment \\'96 then when the original number of bins is odd, you can simply discard the final value in the returned vector (and, if you wish to work with densities rather than counts, re-normalize the result to sum to 1.0).\\\nThe implementation of \n\\f1\\fs18 calcSFS()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , tallies each mutation separately, even if more than one mutation occurs at the same position (or is even stacked with another mutation).  One could regard this choice as embodying an infinite-sites interpretation of the SFS, perhaps; in any case, it follows SLiM\\'92s behavior in other population-genetics utility functions.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.\\\nThis function is compatible with multi-chromosome models, in the following sense.  When \n\\f1\\fs18 binCount\n\\f2\\fs20  is specified with an \n\\f1\\fs18 integer\n\\f2\\fs20  value, mutations are binned according to their frequencies, as described above.  In a multi-chromosome model, the haplosomes and mutations used by \n\\f1\\fs18 calcSFS()\n\\f2\\fs20  may be associated with more than one chromosome, and the frequency assessed for each mutation is its frequency specifically within the haplosomes associated with its chromosome (as you would expect).  Mutations occurring in different chromosomes can therefore be tallied together into the same frequency bins, and combined into a single SFS; this produces a meaningful SFS.  (If you want an SFS for just a single chromosome, then of course you can pass just those haplosomes and mutations to \n\\f1\\fs18 calcSFS()\n\\f2\\fs20 .)  When \n\\f1\\fs18 binCount\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20 , on the other hand, mutations are binned according to their counts, as described above.  In a multi-chromosome model, it would not make sense to bin counts together from different chromosomes, since those counts might not be on the same scale \\'96 the number of haplosomes associated with the various chromosomes might not be equal.  In this case, \n\\f1\\fs18 calcSFS()\n\\f2\\fs20  will raise an error if haplosomes from more than one chromosome are supplied, or if haplosomes is \n\\f1\\fs18 NULL\n\\f2\\fs20  (since it doesn\\'92t know which chromosome to choose).  If you wish to tally according to counts, with \n\\f1\\fs18 binCount=NULL\n\\f2\\fs20 , you must pass in a vector of haplosomes associated with a single chromosome.  (If you know what you are doing and wish to combine counts across multiple chromosomes, you can simply call \n\\f1\\fs18 calcSFS()\n\\f2\\fs20  once per chromosome, and combine the resulting vectors by adding them together.)\\\nThanks to Ryan Chaffee and Chase Nelson for helpful input.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcTajimasD(object<Haplosome>\\'a0haplosomes, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates Tajima\\'92s \n\\f3\\i D\n\\f2\\i0  (a test of neutrality based on the allele frequency spectrum) for a vector of haplosomes (containing at least four elements), based upon the mutations in the haplosomes.  The mathematical formulation is given in Tajima 1989 (equation 38) and remains unchanged (e.g., equations 2.30 in Durrett 2008, 8.4 in Hahn 2018, and 4.44 in Coop 2020).  Often \n\\f1\\fs18 haplosomes\n\\f2\\fs20  will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.  By default, with \n\\f1\\fs18 muts=NULL\n\\f2\\fs20 , the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for \n\\f1\\fs18 muts\n\\f2\\fs20 .\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide Tajima\\'92s \n\\f3\\i D\n\\f2\\i0 .\\\nIf the genetic diversity contained within the haplosomes is insufficient for the calculation, \n\\f1\\fs18 calcTajimasD()\n\\f2\\fs20  may return \n\\f1\\fs18 NAN\n\\f2\\fs20 .  It is up to the caller to detect this with \n\\f1\\fs18 isNAN()\n\\f2\\fs20  and handle it as necessary.\\\nThe implementation of \n\\f1\\fs18 calcTajimasD()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation as independent in the heterozygosity calculations.  One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with \n\\f1\\fs18 calcHeterozygosity()\n\\f2\\fs20 .  Indeed, Tajima\\'92s \n\\f3\\i D\n\\f2\\i0  can be modified with finite-sites models of \n\\f7\\i \\uc0\\u960 \n\\f2\\i0  and \n\\f7\\i \\uc0\\u952 \n\\f2\\i0  (Misawa and Tajima 1997) though these are not used here.  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.  See \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  for further discussion.  This function was written by Nick Bailey (currently affiliated with CNRS and the Laboratory of Biometry and Evolutionary Biology at University Lyon 1), with helpful input from Peter Ralph.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcVA(object<Individual>\\'a0individuals, io<MutationType>$\\'a0mutType)\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates \n\\f3\\i V\n\\f2\\i0\\fs13\\fsmilli6667 \\sub A\n\\fs20 \\nosupersub , the additive genetic variance, among a vector of individuals (containing at least two elements) passed in \n\\f1\\fs18 individuals\n\\f2\\fs20 , in a particular mutation type \n\\f1\\fs18 mutType\n\\f2\\fs20  that represents quantitative trait loci (QTLs) influencing a quantitative phenotypic trait.  The \n\\f1\\fs18 mutType\n\\f2\\fs20  parameter may be either an \n\\f1\\fs18 integer\n\\f2\\fs20  representing the ID of the desired mutation type, or a \n\\f1\\fs18 MutationType\n\\f2\\fs20  object specified directly.\\\nThis function assumes that mutations of type \n\\f1\\fs18 mutType\n\\f2\\fs20  encode their effect size upon the quantitative trait in their \n\\f1\\fs18 selectionCoeff\n\\f2\\fs20  property, as is fairly standard in SLiM.  The implementation of \n\\f1\\fs18 calcVA()\n\\f2\\fs20 , which is viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , is quite simple; if effect sizes are stored elsewhere (such as with \n\\f1\\fs18 setValue()\n\\f2\\fs20 ), a new user-defined function following the pattern of \n\\f1\\fs18 calcVA()\n\\f2\\fs20  can easily be written.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (float$)calcWattersonsTheta(object<Haplosome>\\'a0haplosomes, [No<Mutation>\\'a0muts\\'a0=\\'a0NULL], [Ni$\\'a0start\\'a0=\\'a0NULL], [Ni$\\'a0end\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Calculates Watterson\\'92s theta (a metric of genetic diversity comparable to heterozygosity) for a vector of haplosomes (containing at least one element), based upon the mutations in the haplosomes.  Often \n\\f1\\fs18 haplosomes\n\\f2\\fs20  will be all of the haplosomes in a subpopulation, or in the entire population, but any haplosome vector may be used.  By default, with \n\\f1\\fs18 muts=NULL\n\\f2\\fs20 , the calculation is based upon all mutations in the simulation; the calculation can instead be based upon a subset of mutations, such as mutations of a specific mutation type, by passing the desired vector of mutations for \n\\f1\\fs18 muts\n\\f2\\fs20 .\\\nThe calculation can be narrowed to apply to only a window \\'96 a subrange of the full chromosome \\'96 by passing the interval bounds [\n\\f1\\fs18 start\n\\f2\\fs20 , \n\\f1\\fs18 end\n\\f2\\fs20 ] for the desired window.  In this case, the vector of mutations used for the calculation will be subset to include only mutations within the specified window.  The default behavior, with \n\\f1\\fs18 start\n\\f2\\fs20  and \n\\f1\\fs18 end\n\\f2\\fs20  of \n\\f1\\fs18 NULL\n\\f2\\fs20 , provides the haplosome-wide Watterson\\'92s theta.\\\nThe implementation of \n\\f1\\fs18 calcWattersonsTheta()\n\\f2\\fs20 , viewable with \n\\f1\\fs18 functionSource()\n\\f2\\fs20 , treats every mutation as independent in the heterozygosity calculations.  One could regard this choice as embodying an infinite-sites interpretation of the segregating mutations, as with \n\\f1\\fs18 calcHeterozygosity()\n\\f2\\fs20 .  In most biologically realistic models, such genetic states will be quite rare, and so the impact of this assumption will be negligible; however, in some models this distinction may be important.  See \n\\f1\\fs18 calcPairHeterozygosity()\n\\f2\\fs20  for further discussion.\\\n\\pard\\pardeftab397\\ri720\\sb360\\sa60\\partightenfactor0\n\n\\f0\\b\\fs22 \\cf0 3.4.  Other utilities\n\\f2\\b0\\fs20 \\cf2 \\expnd0\\expndtw0\\kerning0\n\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 \\kerning1\\expnd0\\expndtw0 (float)summarizeIndividuals(object<Individual>\\'a0individuals, integer\\'a0dim, numeric\\'a0spatialBounds, string$\\'a0operation, [Nlif$\\'a0empty\\'a0=\\'a00.0], [logical$\\'a0perUnitArea\\'a0=\\'a0F], [Ns$\\'a0spatiality\\'a0=\\'a0NULL])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns a vector, matrix, or array that summarizes spatial patterns of information related to the individuals in \n\\f1\\fs18 individuals\n\\f2\\fs20 .  In essence, those individuals are assigned into \n\\f3\\i bins\n\\f2\\i0  according to their spatial position, and then a summary value for each bin is calculated based upon the individuals each bin contains.  The individuals might be binned in one dimension (resulting in a vector of summary values), in two dimensions (resulting in a matrix), or in three dimensions (resulting in an array).  Typically the spatiality of the result (the dimensions into which the individuals are binned) will match the dimensionality of the model, as indicated by the default value of \n\\f1\\fs18 NULL\n\\f2\\fs20  for the optional \n\\f1\\fs18 spatiality\n\\f2\\fs20  parameter; for example, a two-dimensional (\n\\f1\\fs18 \"xy\"\n\\f2\\fs20 ) model would by default produce a two-dimensional matrix as a summary.  However, a spatiality that is more restrictive than the model dimensionality may be passed; for example, in a two-dimensional (\n\\f1\\fs18 \"xy\"\n\\f2\\fs20 ) model a \n\\f1\\fs18 spatiality\n\\f2\\fs20  of \n\\f1\\fs18 \"y\"\n\\f2\\fs20  could be passed to summarize individuals into a vector, rather than a matrix, assigning them to bins based only upon their \n\\f3\\i y\n\\f2\\i0  position (i.e., the value of their \n\\f1\\fs18 y\n\\f2\\fs20  property).  Whatever spatiality is chosen, the parameter \n\\f1\\fs18 dim\n\\f2\\fs20  provides the dimensions of the desired result, in the same form that the \n\\f1\\fs18 dim()\n\\f2\\fs20  function does: first the number of rows, then the number of columns, and then the number of planes, as needed (see the Eidos manual for discussion of matrices, arrays, and \n\\f1\\fs18 dim()\n\\f2\\fs20 ).  The length of \n\\f1\\fs18 dims\n\\f2\\fs20  must match the requested spatiality; for spatiality \n\\f1\\fs18 \"xy\"\n\\f2\\fs20 , for example, \n\\f1\\fs18 dims\n\\f2\\fs20  might be \n\\f1\\fs18 c(50,100)\n\\f2\\fs20  to request that the returned matrix have \n\\f1\\fs18 50\n\\f2\\fs20  rows and \n\\f1\\fs18 100\n\\f2\\fs20  columns.  The result vector/matrix/array is in the correct orientation to be directly usable as a spatial map, by passing it to the \n\\f1\\fs18 defineSpatialMap()\n\\f2\\fs20  method of \n\\f1\\fs18 Subpopulation\n\\f2\\fs20 .  For further discussion of dimensionality and spatiality, see \n\\f1\\fs18 initializeInteractionType()\n\\f2\\fs20  and \n\\f1\\fs18 InteractionType\n\\f2\\fs20 .\\\nThe \n\\f1\\fs18 spatialBounds\n\\f2\\fs20  parameter defines the spatial boundaries within which the individuals are binned.  Typically this is the spatial bounds of a particular subpopulation, within which the individuals reside; for individuals in \n\\f1\\fs18 p1\n\\f2\\fs20 , for example, you would likely pass \n\\f1\\fs18 p1.spatialBounds\n\\f2\\fs20  for this.  However, this is not required; individuals may come from any or all subpopulations in the model, and \n\\f1\\fs18 spatialBounds\n\\f2\\fs20  may be any bounds of non-zero area (if an individual falls outside of the given spatial bounds, it is excluded, as if it were not in \n\\f1\\fs18 individuals\n\\f2\\fs20  at all).  If you have multiple subpopulations that conceptually reside within the same overall coordinate space, for example, that can be accommodated here.  The bounds are supplied in the dimensionality of the model, in the same form as for \n\\f1\\fs18 Subpopulation\n\\f2\\fs20 ; for an \n\\f1\\fs18 \"xy\"\n\\f2\\fs20  model, for example, they are supplied as a four-element vector of the form \n\\f1\\fs18 c(x0, y0, x1, y1)\n\\f2\\fs20  even if the summary is being produced with spatiality \n\\f1\\fs18 \"y\"\n\\f2\\fs20 .  To produce the result, a grid with dimensions defined by \n\\f1\\fs18 dims\n\\f2\\fs20  is conceptually stretched out across the given spatial bounds, such that the \n\\f3\\i centers\n\\f2\\i0  of the edge and corner grid squares are aligned with the limits of the spatial bounds.  This matches the way that \n\\f1\\fs18 defineSpatialMap()\n\\f2\\fs20  defines its maps.\\\nThe particular summary produced depends upon the parameters \n\\f1\\fs18 operation\n\\f2\\fs20  and \n\\f1\\fs18 empty\n\\f2\\fs20 .  Consider a single grid square represented by a single element in the result.  That grid square contains zero or more of the individuals in \n\\f1\\fs18 individuals\n\\f2\\fs20 .  If it contains zero individuals \n\\f3\\i and\n\\f2\\i0  \n\\f1\\fs18 empty\n\\f2\\fs20  is not \n\\f1\\fs18 NULL\n\\f2\\fs20 , the \n\\f1\\fs18 empty\n\\f2\\fs20  value is used for the result, regardless of \n\\f1\\fs18 operation\n\\f2\\fs20 , providing specific, separate control over the treatment of empty grid squares.  If \n\\f1\\fs18 empty\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20 , this separate control over the treatment of empty grid squares is declined; empty grid squares will be handled through the standard mechanism described next.  In all other cases for the given grid square \\'96 when it contains more than zero individuals, or when \n\\f1\\fs18 empty\n\\f2\\fs20  is \n\\f1\\fs18 NULL\n\\f2\\fs20  \\'96 \n\\f1\\fs18 operation\n\\f2\\fs20  is executed as an Eidos \n\\f3\\i lambda\n\\f2\\i0 , a small snippet of code, supplied as a singleton \n\\f1\\fs18 string\n\\f2\\fs20 , that is executed in a manner similar to a function call.  Within the execution of the \n\\f1\\fs18 operation\n\\f2\\fs20  lambda, a constant named \n\\f1\\fs18 individuals\n\\f2\\fs20  is defined to be the focal individuals being evaluated \\'96 all of the individuals within that grid square.  This lambda should evaluate to a singleton \n\\f1\\fs18 logical\n\\f2\\fs20 , \n\\f1\\fs18 integer\n\\f2\\fs20 , or \n\\f1\\fs18 float\n\\f2\\fs20  value, comprising the result value for the grid square; these types will all be coerced to \n\\f1\\fs18 float\n\\f2\\fs20  (\n\\f1\\fs18 T\n\\f2\\fs20  being \n\\f1\\fs18 1\n\\f2\\fs20  and \n\\f1\\fs18 F\n\\f2\\fs20  being \n\\f1\\fs18 0\n\\f2\\fs20 ).\\\nTwo examples may illustrate the use of \n\\f1\\fs18 empty\n\\f2\\fs20  and \n\\f1\\fs18 operation\n\\f2\\fs20 .  To produce a summary indicating presence/absence, simply use the default of \n\\f1\\fs18 0.0\n\\f2\\fs20  for \n\\f1\\fs18 empty\n\\f2\\fs20 , and \n\\f1\\fs18 \"1.0;\n\\f2\\fs20  \n\\f1\\fs18 \"\n\\f2\\fs20  (or \n\\f1\\fs18 \"1;\"\n\\f2\\fs20 , or \n\\f1\\fs18 \"T;\"\n\\f2\\fs20 ) for \n\\f1\\fs18 operation\n\\f2\\fs20 .  This will produce \n\\f1\\fs18 0.0\n\\f2\\fs20  for empty grid squares, and \n\\f1\\fs18 1.0\n\\f2\\fs20  for those that contain at least one individual.  Note that the use of \n\\f1\\fs18 empty\n\\f2\\fs20  is essential here, because \n\\f1\\fs18 operation\n\\f2\\fs20  doesn\\'92t even check whether individuals are present or not.  To produce a summary with a count of the number of individuals in each grid square, again use the default of \n\\f1\\fs18 0.0\n\\f2\\fs20  for \n\\f1\\fs18 empty\n\\f2\\fs20 , but now use an \n\\f1\\fs18 operation\n\\f2\\fs20  of \n\\f1\\fs18 \"individuals.size();\"\n\\f2\\fs20 , counting the number of individuals in each grid square.  In this case, \n\\f1\\fs18 empty\n\\f2\\fs20  could be \n\\f1\\fs18 NULL\n\\f2\\fs20  instead and \n\\f1\\fs18 operation\n\\f2\\fs20  would still produce the correct result; but using \n\\f1\\fs18 empty\n\\f2\\fs20  makes \n\\f1\\fs18 summarizeIndividuals()\n\\f2\\fs20  more efficient since it allows the execution of \n\\f1\\fs18 operation\n\\f2\\fs20  to be skipped for those squares.\\\nLambdas are not limited in their complexity; they can use \n\\f1\\fs18 if\n\\f2\\fs20 , \n\\f1\\fs18 for\n\\f2\\fs20 , etc., and can call methods and functions.  A typical \n\\f1\\fs18 operation\n\\f2\\fs20  to compute the mean phenotype in a quantitative genetic model that stores phenotype values in \n\\f1\\fs18 tagF\n\\f2\\fs20 , for example, would be \n\\f1\\fs18 \"mean(individuals.tagF);\"\n\\f2\\fs20 , and this is still quite simple compared to what is possible.  However, keep in mind that the lambda will be evaluated for every grid cell (or at least those that are non-empty), so efficiency can be a concern, and you may wish to pre-calculate values shared by all of the lambda calls, making them available to your lambda code using \n\\f1\\fs18 defineGlobal()\n\\f2\\fs20  or \n\\f1\\fs18 defineConstant()\n\\f2\\fs20 .\\\nThere is one last twist, if \n\\f1\\fs18 perUnitArea\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20 : values are divided by the area (or length, in 1D, or volume, in 3D) that their corresponding grid cell comprises, so that each value is in units of \\'93per unit area\\'94 (or \\'93per unit length\\'94, or \\'93per unit volume\\'94).  The total area of the grid is defined by the spatial bounds, and the area of a given grid cell is defined by the portion of the spatial bounds that is within that cell.  This is not the same for all grid cells; grid cells that fall partially outside \n\\f1\\fs18 spatialBounds\n\\f2\\fs20  (because, remember, the \n\\f3\\i centers\n\\f2\\i0  of the edge/corner grid cells are aligned with the limits of \n\\f1\\fs18 spatialBounds\n\\f2\\fs20 ) will have a smaller area inside the bounds.  For an \n\\f1\\fs18 \"xy\"\n\\f2\\fs20  spatiality summary, for example, corner cells have only a quarter of their area inside \n\\f1\\fs18 spatialBounds\n\\f2\\fs20 , while edge elements have half of their area inside \n\\f1\\fs18 spatialBounds\n\\f2\\fs20 ; for purposes of \n\\f1\\fs18 perUnitArea\n\\f2\\fs20 , then, their respective areas are \\'bc and \\'bd the area of an interior grid cell.  By default, \n\\f1\\fs18 perUnitArea\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 , and no scaling is performed.  Whether you want \n\\f1\\fs18 perUnitArea\n\\f2\\fs20  to be \n\\f1\\fs18 F\n\\f2\\fs20  or \n\\f1\\fs18 T\n\\f2\\fs20  depends upon whether the summary you are producing is, conceptually, \\'93per unit area\\'94, such as density (individuals per unit area) or local competition strength (total interaction strength per unit area), or is not, such as \\'93mean individual age\\'94, or \\'93maximum \n\\f1\\fs18 tag\n\\f2\\fs20  value\\'94.  For the previous example of counting individuals with an operation of \n\\f1\\fs18 \"individuals.size();\"\n\\f2\\fs20 , a value of \n\\f1\\fs18 F\n\\f2\\fs20  for \n\\f1\\fs18 perUnitArea\n\\f2\\fs20  (the default) will produce a simple \n\\f3\\i count\n\\f2\\i0  of individuals in each grid square, whereas with \n\\f1\\fs18 T\n\\f2\\fs20  it would produce the \n\\f3\\i density\n\\f2\\i0  of individuals in each grid square.\\\n\\pard\\pardeftab720\\li720\\fi-446\\ri720\\sb180\\sa60\\partightenfactor0\n\n\\f1\\fs18 \\cf2 (object<Dictionary>$)treeSeqMetadata(string$\\'a0filePath, [logical$\\'a0userData\\'a0=\\'a0T])\\\n\\pard\\pardeftab397\\li547\\ri720\\sb60\\sa60\\partightenfactor0\n\n\\f2\\fs20 \\cf2 Returns a \n\\f1\\fs18 Dictionary\n\\f2\\fs20  containing top-level metadata from the \n\\f1\\fs18 .trees\n\\f2\\fs20  (tree-sequence) file at \n\\f1\\fs18 filePath\n\\f2\\fs20 .  If \n\\f1\\fs18 userData\n\\f2\\fs20  is \n\\f1\\fs18 T\n\\f2\\fs20  (the default), the top-level metadata under the \n\\f1\\fs18 SLiM/user_metadata\n\\f2\\fs20  key is returned; this is the same metadata that can optionally be supplied to \n\\f1\\fs18 treeSeqOutput()\n\\f2\\fs20  in its \n\\f1\\fs18 metadata\n\\f2\\fs20  parameter, so it makes it easy to recover metadata that you attached to the tree sequence when it was saved.  If \n\\f1\\fs18 userData\n\\f2\\fs20  is \n\\f1\\fs18 F\n\\f2\\fs20 , the entire top-level metadata \n\\f1\\fs18 Dictionary\n\\f2\\fs20  object is returned; this can be useful for examining the values of other keys under the \n\\f1\\fs18 SLiM\n\\f2\\fs20  key, or values inside the top-level dictionary itself that might have been placed there by \n\\f1\\fs18 msprime\n\\f2\\fs20  or other software.\\\nThis function can be used to read in parameter values or other saved state (\n\\f1\\fs18 tag\n\\f2\\fs20  property values, for example), in order to resuscitate the complete state of a simulation that was written to a \n\\f1\\fs18 .trees\n\\f2\\fs20  file.  It could be used for more esoteric purposes too, such as to search through \n\\f1\\fs18 .trees\n\\f2\\fs20  files in a directory (with the help of the Eidos function \n\\f1\\fs18 filesAtPath()\n\\f2\\fs20 ) to find those files that satisfy some metadata criterion.\\\n}"
  },
  {
    "path": "SLiMgui/SLiMPDFDocument.h",
    "content": "//\n//  SLiMPDFDocument.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\n@interface SLiMPDFDocument : NSDocument\n{\n\tNSData *pdfData;\t\t\t// we hold onto the NSData we are given as our \"model\"\n\tNSDate *modificationDate;\t// we have to track the mod date of our file to tell when it changes\n}\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMPDFDocument.mm",
    "content": "//\n//  SLiMPDFDocument.mm\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMPDFDocument.h\"\n#import \"SLiMPDFWindowController.h\"\n\n\n@implementation SLiMPDFDocument\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[super dealloc];\n}\n\n- (SLiMPDFWindowController *)slimPDFWindowController\n{\n\tNSArray *controllers = [self windowControllers];\n\t\n\tif ([controllers count] > 0)\n\t{\n\t\tNSWindowController *mainController = [controllers objectAtIndex:0];\n\t\t\n\t\tif ([mainController isKindOfClass:[SLiMPDFWindowController class]])\n\t\t\treturn (SLiMPDFWindowController *)mainController;\n\t}\n\t\n\treturn nil;\n}\n\n- (void)givePDFData:(NSData *)data toController:(SLiMPDFWindowController *)controller\n{\n\t// Get our window controller to display the PDF data we have\n\tif (pdfData && [pdfData length])\n\t{\n\t\tPDFDocument *doc = [[PDFDocument alloc] initWithData:pdfData];\n\t\t\n\t\t[controller setDisplayPDFDocument:doc];\n\t\t[doc release];\n\t}\n\telse\n\t{\n\t\t[controller setDisplayPDFDocument:nil];\n\t}\n}\n\n- (void)makeWindowControllers\n{\n\tNSArray *myControllers = [self windowControllers];\n\t\n\t// If this document displaced a transient document, it will already have been assigned\n\t// a window controller. If that is not the case, create one.\n\tif ([myControllers count] == 0)\n\t{\n\t\tSLiMPDFWindowController *controller = [[[SLiMPDFWindowController alloc] init] autorelease];\n\t\t\n\t\t[self addWindowController:controller];\n\t\t[self givePDFData:pdfData toController:controller];\n\t}\n}\n\n- (void)windowControllerDidLoadNib:(NSWindowController *)aController\n{\n\t// Note this method is not called, because we override -makeWindowControllers\n\t[super windowControllerDidLoadNib:aController];\n}\n\n- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError * _Nullable *)outError\n{\n\tif ([super readFromURL:url ofType:typeName error:outError])\n\t{\n\t\tNSString *filePath = [url path];\n\t\tNSFileManager *fm = [NSFileManager defaultManager];\n\t\t\n\t\t[modificationDate release];\n\t\tmodificationDate = [[[fm attributesOfItemAtPath:filePath error:nil] fileModificationDate] retain];\n\t\t\n\t\treturn YES;\n\t}\n\t\n\treturn NO;\n}\n\n- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError\n{\n\tif ([typeName isEqualToString:@\"com.adobe.pdf\"])\n\t{\n\t\tif (pdfData != data)\n\t\t{\n\t\t\t[pdfData release];\n\t\t\tpdfData = [data retain];\n\t\t}\n\t\t\n\t\tSLiMPDFWindowController *controller = [self slimPDFWindowController];\n\t\t\n\t\tif (controller)\n\t\t\t[self givePDFData:pdfData toController:controller];\n\t\t\n\t\treturn YES;\n\t}\n\t\n    if (outError)\n        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:nil];\n    return NO;\n}\n\n- (void)revertAfterChange:(id)sender\n{\n\tNSURL *fileURL  = [self fileURL];\n\tNSString *filePath = [fileURL path];\n\tNSFileManager *fm = [NSFileManager defaultManager];\n\tNSDate *newModDate = [[fm attributesOfItemAtPath:filePath error:nil] fileModificationDate];\n\t\n\tif ([newModDate timeIntervalSinceDate:modificationDate] > 0.0)\n\t{\n\t\t//NSLog(@\"   reverting...\");\n\t\t\n\t\tNSURL *url = [self fileURL];\n\t\t[self revertToContentsOfURL:url ofType:@\"com.adobe.pdf\" error:NULL];\n\t}\n}\n\n- (void)presentedItemDidChange\n{\n\t//NSLog(@\"presentedItemDidChange\");\n\t\n\t[self performSelectorOnMainThread:@selector(revertAfterChange:) withObject:nil waitUntilDone:NO];\n}\n\n+ (NSArray<NSString *> *)writableTypes\n{\n\treturn [NSArray array];\n}\n\n+ (BOOL)isNativeType:(NSString *)type\n{\n\treturn NO;\n}\n\n- (void)copy:(id)sender\n{\n\tif (pdfData && [pdfData length])\n\t{\n\t\tNSPasteboard *pasteboard = [NSPasteboard generalPasteboard];\n\t\t\n\t\t[pasteboard declareTypes:@[NSPDFPboardType] owner:self];\n\t\t[pasteboard setData:pdfData forType:NSPDFPboardType];\n\t}\n}\n\n- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item\n{\n\t// I would have expected that returning an empty array for writeableTypes would cause Save As...\n\t// to be disabled, but that is apparently not the case.  I can't find any better way than this.\n\tif ([item action] == @selector(saveDocumentAs:))\n\t\treturn NO;\n\n\tif ([item action] == @selector(copy:))\n\t\treturn (pdfData && [pdfData length]);\n\t\n\t//NSLog(@\"sel = %@\", NSStringFromSelector([item action]));\n\t\n\treturn [super validateUserInterfaceItem:item];\n}\n\n+ (BOOL)autosavesInPlace\n{\n\treturn NO;\n}\n\n+ (BOOL)autosavesDrafts\n{\n\treturn NO;\n}\n\n+ (BOOL)preservesVersions\n{\n\treturn NO;\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMPDFView.h",
    "content": "//\n//  SLiMPDFView.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Quartz/Quartz.h>\n\n\n@interface SLiMPDFView : NSView\n{\n}\n\n@property (nonatomic, retain) PDFDocument *document;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMPDFView.mm",
    "content": "//\n//  SLiMPDFView.m\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMPDFView.h\"\n\n\n@implementation SLiMPDFView\n\n- (instancetype)initWithFrame:(NSRect)frameRect\n{\n\tif (self = [super initWithFrame:frameRect])\n\t{\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[_document release];\n\t_document = nil;\n\t\n\t[super dealloc];\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tNSRect bounds = [self bounds];\n\t\n\t[[NSColor darkGrayColor] set];\n\tNSRectFill(bounds);\n\t\n\tif (_document)\n\t{\n\t\t// thanks to https://ryanbritton.com/2015/09/correctly-drawing-pdfs-in-cocoa/ for this code\n\t\t\n\t\tCGSize drawingSize = {bounds.size.width, bounds.size.height};\n\t\t\n\t\t// Document Loading\n\t\tCGPDFDocumentRef pdfDocument = [_document documentRef];\n\t\tCGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, 1);\n\t\t\n\t\t// Start by getting the crop box since only its contents should be drawn\n\t\tCGRect cropBox = CGPDFPageGetBoxRect(page, kCGPDFCropBox);\n\t\t\n\t\t// Account for rotation of the page to figure out the size to create the context. Like images, \n\t\t// rotation can be represented by one of two ways in a PDF: the contents can be pre-rotated\n\t\t// in which case nothing needs to be done or the document can have its rotation value set and\n\t\t// it means we need to apply the rotation as an affine transformation when drawing\n\t\tNSInteger rotationAngle = CGPDFPageGetRotationAngle(page);\n\t\tCGFloat angleInRadians = -rotationAngle * (M_PI / 180);\n\t\tCGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);\n\t\tCGRect rotatedCropRect = CGRectApplyAffineTransform(cropBox, transform);\n\t\t\n\t\t// Figure out the closest size we can draw the PDF at that's no larger than drawingSize\n\t\tCGRect bestFit = CGRectMake(0, 0, 0, 0);\n\t\tdouble rotatedCropRectAspect = rotatedCropRect.size.width / rotatedCropRect.size.height;\n\t\tdouble drawingSizeAspect = drawingSize.width / drawingSize.height;\n\t\t\n\t\tif (rotatedCropRectAspect > drawingSizeAspect)\n\t\t{\n\t\t\tbestFit.size.width = drawingSize.width;\n\t\t\tbestFit.size.height = round(rotatedCropRect.size.height * (drawingSize.width / rotatedCropRect.size.width));\n\t\t\tbestFit.origin.y = round((drawingSize.height - bestFit.size.height) / 2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbestFit.size.width = round(rotatedCropRect.size.width * (drawingSize.height / rotatedCropRect.size.height));\n\t\t\tbestFit.size.height = drawingSize.height;\n\t\t\tbestFit.origin.x = round((drawingSize.width - bestFit.size.width) / 2);\n\t\t}\n\t\t\n\t\tCGFloat scale = CGRectGetHeight(bestFit) / CGRectGetHeight(rotatedCropRect);\n\t\t\n\t\t// Get the drawing context\n\t\tCGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];\n\t\t\n\t\t// Create the affine transformation matrix to align the PDF's CropBox to our drawing context.\n\t\t//transform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, CGRectMake(0, 0, CGRectGetWidth(bestFit), CGRectGetHeight(bestFit)), 0, true);\n\t\ttransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, bestFit, 0, true);\n\t\t\n\t\tif (scale > 1)\n\t\t{\n\t\t\t// Since CGPDFPageGetDrawingTransform won't scale up, we need to do it manually\n\t\t\ttransform = CGAffineTransformTranslate(transform, CGRectGetMidX(cropBox), CGRectGetMidY(cropBox));\n\t\t\ttransform = CGAffineTransformScale(transform, scale, scale);\n\t\t\ttransform = CGAffineTransformTranslate(transform, -CGRectGetMidX(cropBox), -CGRectGetMidY(cropBox));\n\t\t}\n\t\t\n\t\tCGContextConcatCTM(context, transform);\n\t\t\n\t\t// Clip the drawing to the CropBox\n\t\tCGContextAddRect(context, cropBox);\n\t\tCGContextClip(context);\n\t\t\n\t\t[[NSColor whiteColor] set];\n\t\tNSRectFill(cropBox);\n\t\t\n\t\tCGContextDrawPDFPage(context, page);\n\t}\n}\n\n- (BOOL)isOpaque\n{\n\treturn YES;\n}\n\n- (void)setDocument:(PDFDocument *)document\n{\n\t[document retain];\n\t[_document release];\n\t_document = document;\n\t\n\t[self setNeedsDisplay:YES];\n}\n\n- (NSMenu *)menu\n{\n\tNSMenu *menu = [[NSMenu alloc] initWithTitle:@\"pdf_menu\"];\n\tNSMenuItem *menuItem;\n\t\n\tmenuItem = [menu addItemWithTitle:@\"Copy\" action:@selector(copy:) keyEquivalent:@\"\"];\n\t[menuItem setTarget:[[[self window] windowController] document]];\n\t\n\treturn [menu autorelease];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMPDFWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"12118\" systemVersion=\"16E195\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"12118\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"SLiMPDFWindowController\">\n            <connections>\n                <outlet property=\"pdfView\" destination=\"zyc-5H-BAu\" id=\"1OF-By-wmr\"/>\n                <outlet property=\"window\" destination=\"F0z-JX-Cv5\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" animationBehavior=\"default\" id=\"F0z-JX-Cv5\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"300\" height=\"300\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1057\"/>\n            <value key=\"minSize\" type=\"size\" width=\"150\" height=\"150\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"se5-gp-TjO\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"300\" height=\"300\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zyc-5H-BAu\" customClass=\"SLiMPDFView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"300\" height=\"300\"/>\n                    </customView>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"zyc-5H-BAu\" secondAttribute=\"trailing\" id=\"2W3-y2-5hg\"/>\n                    <constraint firstItem=\"zyc-5H-BAu\" firstAttribute=\"top\" secondItem=\"se5-gp-TjO\" secondAttribute=\"top\" id=\"Kh7-WS-yGb\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"zyc-5H-BAu\" secondAttribute=\"bottom\" id=\"ZIf-Wf-4so\"/>\n                    <constraint firstItem=\"zyc-5H-BAu\" firstAttribute=\"leading\" secondItem=\"se5-gp-TjO\" secondAttribute=\"leading\" id=\"hJZ-a6-rju\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"0bl-1N-AYu\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-938\" y=\"66\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "SLiMgui/SLiMPDFWindowController.h",
    "content": "//\n//  SLiMPDFWindowController.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n#import <Quartz/Quartz.h>\n\n#import \"SLiMPDFView.h\"\n\n\n@interface SLiMPDFWindowController : NSWindowController\n{\n\tIBOutlet SLiMPDFView *pdfView;\n}\n\n@property (nonatomic, retain) PDFDocument *displayPDFDocument;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMPDFWindowController.mm",
    "content": "//\n//  SLiMPDFWindowController.mm\n//  SLiM\n//\n//  Created by Ben Haller on 4/20/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMPDFWindowController.h\"\n\n\n@implementation SLiMPDFWindowController\n\n- (instancetype)init\n{\n\tif (self = [super initWithWindowNibName:@\"SLiMPDFWindow\"])\n\t{\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\tpdfView = nil;\n\t[self setDisplayPDFDocument:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)windowDidLoad\n{\n    [super windowDidLoad];\n    \n\t[pdfView setDocument:_displayPDFDocument];\n}\n\n- (void)setDisplayPDFDocument:(PDFDocument *)doc\n{\n\tif (doc != _displayPDFDocument)\n\t{\n\t\t[doc retain];\n\t\t[_displayPDFDocument release];\n\t\t_displayPDFDocument = doc;\n\t\t\n\t\t[pdfView setDocument:_displayPDFDocument];\n\t}\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMWindowController.h",
    "content": "//\n//  SLiMWindowController.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n#include \"eidos_rng.h\"\n#include \"species.h\"\n#include \"slim_gui.h\"\n#import \"ChromosomeView.h\"\n#import \"PopulationView.h\"\n#import \"GraphView.h\"\n#import \"CocoaExtra.h\"\n#import \"EidosTextView.h\"\n#import \"EidosTextViewDelegate.h\"\n#import \"EidosConsoleTextView.h\"\n#import \"EidosConsoleWindowController.h\"\n#import \"EidosConsoleWindowControllerDelegate.h\"\n\n#include <ctime>\n\n\nclass Community;\n\n\n@interface SLiMWindowController : NSWindowController <NSTableViewDelegate, NSTableViewDataSource, NSSplitViewDelegate, NSTextViewDelegate, EidosConsoleWindowControllerDelegate, EidosTextViewDelegate>\n{\n@public\n\tNSString *scriptString;\t\t\t\t\t// the script string that we are running on right now; not the same as the script textview!\n\tCommunity *community;\t\t\t\t\t// the simulation instance for this window\n\tSpecies *focalSpecies;\t\t\t\t\t// NOT OWNED: a pointer to the focal species in community; do not use, call focalDisplaySpecies()\n\tstd::string focalSpeciesName;\t\t\t// the name of the focal species, for persistence across recycles\n\tSLiMgui *slimgui;\t\t\t\t\t\t// the SLiMgui Eidos class instance for this window\n\t\n\t// state variables that are globals in Eidos and SLiM; we swap these in and out as needed, to provide each sim with its own context\n\tbool sim_RNG_initialized;\n#ifndef _OPENMP\n\tEidos_RNG_State sim_RNG_SINGLE;\n#else\n\tstd::vector<Eidos_RNG_State *> sim_RNG_PERTHREAD;\t// pointers to per-thread allocations, for \"first touch\" optimization\n#endif\n\tslim_pedigreeid_t sim_next_pedigree_id;\n\tslim_mutationid_t sim_next_mutation_id;\n\tbool sim_suppress_warnings;\n\tstd::string sim_working_dir;\t\t\t// the current working dir that we will return to when executing SLiM/Eidos code\n\tstd::string sim_requested_working_dir;\t// the last working dir set by the user with the SLiMgui button/menu; we return to it on recycle\n\t\n\t// play-related variables; note that continuousPlayOn covers both profiling and non-profiling runs, whereas profilePlayOn\n\t// and nonProfilePlayOn cover those cases individually; this is for simplicity in enable bindings in the nib\n\tBOOL invalidSimulation, continuousPlayOn, profilePlayOn, nonProfilePlayOn, tickPlayOn, reachedSimulationEnd, hasImported;\n\tslim_tick_t targetTick;\n\tNSDate *continuousPlayStartDate;\n\tuint64_t continuousPlayTicksCompleted;\n\tint partialUpdateCount;\n\tSLiMPlaySliderToolTipWindow *playSpeedToolTipWindow;\n\t\n\t// display-related variables\n\tNSMutableDictionary *genomicElementColorRegistry;\n\tBOOL zoomedChromosomeShowsRateMaps;\n\tBOOL zoomedChromosomeShowsGenomicElements;\n\tBOOL zoomedChromosomeShowsMutations;\n\tBOOL zoomedChromosomeShowsFixedSubstitutions;\n\tBOOL reloadingSubpopTableview;\n\tBOOL reloadingSpeciesBar;\n\t\n\t// outlets\n\tIBOutlet NSButton *buttonForDrawer;\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n\tIBOutlet NSDrawer *drawer;\n#pragma GCC diagnostic pop\n\t\n\tIBOutlet NSTableView *mutTypeTableView;\n\tIBOutlet NSTableColumn *mutTypeIDColumn;\n\tIBOutlet NSTableColumn *mutTypeDominanceColumn;\n\tIBOutlet NSTableColumn *mutTypeDFETypeColumn;\n\tIBOutlet NSTableColumn *mutTypeDFEParamsColumn;\n\t\n\tIBOutlet NSTableView *genomicElementTypeTableView;\n\tIBOutlet NSTableColumn *genomicElementTypeIDColumn;\n\tIBOutlet NSTableColumn *genomicElementTypeColorColumn;\n\tIBOutlet NSTableColumn *genomicElementTypeMutationTypesColumn;\n\t\n\tIBOutlet NSTableView *interactionTypeTableView;\n\tIBOutlet NSTableColumn *interactionTypeIDColumn;\n\tIBOutlet NSTableColumn *interactionTypeMaxDistanceColumn;\n\tIBOutlet NSTableColumn *interactionTypeIFTypeColumn;\n\tIBOutlet NSTableColumn *interactionTypeIFParamsColumn;\n\t\n\tIBOutlet NSTableView *scriptBlocksTableView;\n\tIBOutlet NSTableColumn *scriptBlocksIDColumn;\n\tIBOutlet NSTableColumn *scriptBlocksStartColumn;\n\tIBOutlet NSTableColumn *scriptBlocksEndColumn;\n\tIBOutlet NSTableColumn *scriptBlocksTypeColumn;\n\t\n\tIBOutlet NSSplitView *overallSplitView;\n\tIBOutlet NSView *overallTopView;\n\tIBOutlet NSLayoutConstraint *overallTopViewConstraint1;\n\tIBOutlet NSLayoutConstraint *overallTopViewConstraint2;\n\tIBOutlet NSLayoutConstraint *overallTopViewConstraint3;\n\tIBOutlet NSLayoutConstraint *overallTopViewConstraint4;\n\t\n\tIBOutlet NSButton *playOneStepButton;\n\tIBOutlet NSButton *playButton;\n\tIBOutlet NSButton *profileButton;\n\tIBOutlet NSButton *recycleButton;\n\tIBOutlet NSSlider *playSpeedSlider;\n\tIBOutlet NSTextField *tickTextField;\n\tIBOutlet NSProgressIndicator *tickProgressIndicator;\n\tIBOutlet NSTextField *cycleTextField;\n\t\n\tIBOutlet NSSplitView *bottomSplitView;\n\tIBOutlet EidosTextView *scriptTextView;\n\tIBOutlet NSTextField *scriptStatusTextField;\n\tIBOutlet EidosTextView *outputTextView;\n\tIBOutlet NSButton *consoleButton;\n\tIBOutlet NSButton *browserButton;\n\t\n\tIBOutlet NSSegmentedControl *speciesBar;\n\tIBOutlet NSLayoutConstraint *speciesBarBottomConstraint;\n\t\n\tIBOutlet NSTableView *subpopTableView;\n\tIBOutlet NSTableColumn *subpopIDColumn;\n\tIBOutlet NSTableColumn *subpopSizeColumn;\n\tIBOutlet NSTableColumn *subpopSelfingRateColumn;\n\tIBOutlet NSTableColumn *subpopMaleCloningRateColumn;\n\tIBOutlet NSTableColumn *subpopFemaleCloningRateColumn;\n\tIBOutlet NSTableColumn *subpopSexRatioColumn;\n\t\n\tIBOutlet PopulationView *populationView;\n\tIBOutlet PopulationErrorView *populationErrorView;\n\t\n\tIBOutlet ChromosomeView *chromosomeOverview;\n\tIBOutlet ChromosomeView *chromosomeZoomed;\n\tIBOutlet NSButton *showRecombinationIntervalsButton;\n\tIBOutlet NSButton *showGenomicElementsButton;\n\tIBOutlet NSButton *showMutationsButton;\n\tIBOutlet NSButton *showFixedSubstitutionsButton;\n\t\n\tIBOutlet SLiMMenuButton *graphCommandsButton;\n\tIBOutlet NSMenu *graphCommandsMenu;\n\t\n\t// Graph window ivars\n\tIBOutlet NSWindow *graphWindow;\t\t\t\t// outlet for GraphWindow.xib; note this does not stay wired up, it is just used transiently\n\t\n\tNSWindow *graphWindowMutationFreqSpectrum;\n\tNSWindow *graphWindowMutationFreqTrajectories;\n\tNSWindow *graphWindowMutationLossTimeHistogram;\n\tNSWindow *graphWindowMutationFixationTimeHistogram;\n\tNSWindow *graphWindowFitnessOverTime;\n\tNSWindow *graphWindowPopulationVisualization;\n\t\t// don't forget to add new graph windows in -dealloc, -updateAfterTick, and -windowWillClose:\n\t\n\tint openedGraphCount;\t\t\t\t\t\t// used for new graph window positioning\n\t\n\t// Other linked windows, such as the haplotype snapshot\n\tNSMutableArray *linkedWindows;\n\t\n\t// Profile Report window ivars\n\tIBOutlet NSWindow *profileWindow;\t\t// outlet for ProfileReport.xib; note this does not stay wired up, it is just used transiently\n\tIBOutlet NSTextView *profileTextView;\t// ditto\n\t\n\t// Misc\n\tbool observingKeyPaths;\n\t\n\tSLiMFunctionGraphToolTipWindow *functionGraphToolTipWindow;\t\t// for previews of muttype DFEs or interaction type IFs\n}\n\n+ (NSColor *)blackContrastingColorForIndex:(int)index;\n+ (NSColor *)whiteContrastingColorForIndex:(int)index;\n\n- (instancetype)init;\n- (instancetype)initWithWindow:(NSWindow *)window __attribute__((unavailable));\n- (instancetype)initWithWindowNibName:(NSString *)windowNibName __attribute__((unavailable));\n- (instancetype)initWithWindowNibName:(NSString *)windowNibName owner:(id)owner __attribute__((unavailable));\n- (instancetype)initWithWindowNibPath:(NSString *)windowNibPath owner:(id)owner __attribute__((unavailable));\n- (instancetype)initWithCoder:(NSCoder *)coder __attribute__((unavailable));\n\n- (void)setScriptStringAndInitializeSimulation:(NSString *)string;\n\n- (Species *)focalDisplaySpecies;\n- (std::vector<Subpopulation*>)selectedSubpopulations;\n- (void)updatePopulationViewHiding;\n\n- (NSColor *)colorForGenomicElementType:(GenomicElementType *)elementType withID:(slim_objectid_t)elementTypeID;\n\n- (void)updateRecycleHighlightForChangeCount:(int)changeCount;\n\n- (void)displayStartupMessage;\n\n\n//\n//\tProperties\n//\n\n@property (nonatomic) BOOL invalidSimulation;\n@property (nonatomic) BOOL continuousPlayOn;\n@property (nonatomic) BOOL profilePlayOn;\n@property (nonatomic) BOOL nonProfilePlayOn;\n@property (nonatomic) BOOL tickPlayOn;\n@property (nonatomic) BOOL reachedSimulationEnd;\n@property (nonatomic, readonly) NSColor *colorForWindowLabels;\n\n@property (nonatomic, retain) IBOutlet EidosConsoleWindowController *consoleController;\n\n\n//\n//\tActions\n//\n\n- (IBAction)speciesBarChanged:(id)sender;\n\n- (IBAction)graphMutationFrequencySpectrum:(id)sender;\n- (IBAction)graphMutationFrequencyTrajectories:(id)sender;\n- (IBAction)graphMutationLossTimeHistogram:(id)sender;\n- (IBAction)graphMutationFixationTimeHistogram:(id)sender;\n- (IBAction)graphFitnessOverTime:(id)sender;\n- (IBAction)graphPopulationVisualization:(id)sender;\n\n- (IBAction)playOneStep:(id)sender;\n- (IBAction)play:(id)sender;\n- (IBAction)profile:(id)sender;\n- (IBAction)recycle:(id)sender;\n- (IBAction)playSpeedChanged:(id)sender;\n- (IBAction)tickChanged:(id)sender;\n\n- (IBAction)checkScript:(id)sender;\n- (IBAction)prettyprintScript:(id)sender;\n- (IBAction)showScriptHelp:(id)sender;\n- (IBAction)toggleConsoleVisibility:(id)sender;\n- (IBAction)toggleBrowserVisibility:(id)sender;\n- (IBAction)clearOutput:(id)sender;\n- (IBAction)dumpPopulationToOutput:(id)sender;\n- (IBAction)changeWorkingDirectory:(id)sender;\n\n- (IBAction)showRecombinationIntervalsButtonToggled:(id)sender;\n- (IBAction)showGenomicElementsButtonToggled:(id)sender;\n- (IBAction)showMutationsButtonToggled:(id)sender;\n- (IBAction)showFixedSubstitutionsButtonToggled:(id)sender;\n\n- (IBAction)drawerButtonToggled:(id)sender;\n\n// This action has been disabled; see comments on the implementation.\n//- (IBAction)importPopulation:(id)sender;\t\t// wired through firstResponder because these are menu items\n\n- (IBAction)exportScript:(id)sender;\t\t\t// wired through firstResponder because these are menu items\n- (IBAction)exportOutput:(id)sender;\t\t\t// wired through firstResponder because these are menu items\n\n//\tEidos SLiMgui method forwards\n- (void)eidos_openDocument:(NSString *)path;\n- (void)eidos_pauseExecution;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMWindowController.mm",
    "content": "//\n//  SLiMWindowController.m\n//  SLiM\n//\n//  Created by Ben Haller on 1/21/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"SLiMWindowController.h\"\n#import \"SLiMDocument.h\"\n#import \"AppDelegate.h\"\n#import \"GraphView_MutationFrequencySpectra.h\"\n#import \"GraphView_MutationLossTimeHistogram.h\"\n#import \"GraphView_MutationFixationTimeHistogram.h\"\n#import \"GraphView_FitnessOverTime.h\"\n#import \"GraphView_PopulationVisualization.h\"\n#import \"GraphView_MutationFrequencyTrajectory.h\"\n#import \"EidosHelpController.h\"\n#import \"EidosPrettyprinter.h\"\n#import \"EidosCocoaExtra.h\"\n\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_type_interpreter.h\"\n#include \"slim_test.h\"\n#include \"slim_gui.h\"\n#include \"community.h\"\n#include \"interaction_type.h\"\n\n#include <iostream>\n#include <sstream>\n#include <iterator>\n#include <stdexcept>\n#include <sys/stat.h>\n#include <ctime>\n#include <csignal>\n\n\n@implementation SLiMWindowController\n\n//\n//\tKVC / KVO / properties\n//\n\n@synthesize invalidSimulation, continuousPlayOn, profilePlayOn, nonProfilePlayOn, reachedSimulationEnd, tickPlayOn;\n\n+ (NSSet *)keyPathsForValuesAffectingColorForWindowLabels\n{\n\treturn [NSSet setWithObjects:@\"invalidSimulation\", nil];\n}\n\n- (NSColor *)getColorForWindowLabels\n{\n\tif (invalidSimulation)\n\t\treturn [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];\n\telse\n\t\treturn [NSColor blackColor];\n}\n\n- (void)setContinuousPlayOn:(BOOL)newFlag\n{\n\tif (continuousPlayOn != newFlag)\n\t{\n\t\tcontinuousPlayOn = newFlag;\n\t\t\n\t\t[_consoleController setInterfaceEnabled:!(continuousPlayOn || tickPlayOn)];\n\t}\n}\n\n- (void)setTickPlayOn:(BOOL)newFlag\n{\n\tif (tickPlayOn != newFlag)\n\t{\n\t\ttickPlayOn = newFlag;\n\t\t\n\t\t[_consoleController setInterfaceEnabled:!(continuousPlayOn || tickPlayOn)];\n\t}\n}\n\n\n//\n//\tCore class methods\n//\n#pragma mark -\n#pragma mark Core class methods\n\n+ (NSColor *)blackContrastingColorForIndex:(int)index\n{\n\tstatic NSColor **colorArray = NULL;\n\t\n\tif (!colorArray)\n\t{\n\t\tcolorArray = (NSColor **)malloc(8 * sizeof(NSColor *));\n\t\t\n\t\tcolorArray[0] = [[NSColor colorWithCalibratedHue:0.65 saturation:0.65 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[1] = [[NSColor colorWithCalibratedHue:0.55 saturation:1.0 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[2] = [[NSColor colorWithCalibratedHue:0.40 saturation:1.0 brightness:0.9 alpha:1.0] retain];\n\t\tcolorArray[3] = [[NSColor colorWithCalibratedHue:0.16 saturation:1.0 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[4] = [[NSColor colorWithCalibratedHue:0.08 saturation:0.65 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[5] = [[NSColor colorWithCalibratedHue:0.00 saturation:0.65 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[6] = [[NSColor colorWithCalibratedHue:0.80 saturation:0.65 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[7] = [[NSColor colorWithCalibratedHue:0.00 saturation:0.0 brightness:0.8 alpha:1.0] retain];\n\t}\n\t\n\treturn ((index >= 0) && (index <= 6)) ? colorArray[index] : colorArray[7];\n}\n\n+ (NSColor *)whiteContrastingColorForIndex:(int)index\n{\n\tstatic NSColor **colorArray = NULL;\n\t\n\tif (!colorArray)\n\t{\n\t\tcolorArray = (NSColor **)malloc(7 * sizeof(NSColor *));\n\t\t\n\t\tcolorArray[0] = [[NSColor colorWithCalibratedHue:0.65 saturation:0.75 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[1] = [[NSColor colorWithCalibratedHue:0.55 saturation:1.0 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[2] = [[NSColor colorWithCalibratedHue:0.40 saturation:1.0 brightness:0.8 alpha:1.0] retain];\n\t\tcolorArray[3] = [[NSColor colorWithCalibratedHue:0.08 saturation:0.75 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[4] = [[NSColor colorWithCalibratedHue:0.00 saturation:0.85 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[5] = [[NSColor colorWithCalibratedHue:0.80 saturation:0.85 brightness:1.0 alpha:1.0] retain];\n\t\tcolorArray[6] = [[NSColor colorWithCalibratedHue:0.00 saturation:0.0 brightness:0.5 alpha:1.0] retain];\n\t}\n\t\n\treturn ((index >= 0) && (index <= 5)) ? colorArray[index] : colorArray[6];\n}\n\n- (instancetype)init\n{\n\tif (self = [super initWithWindowNibName:@\"SLiMWindow\"])\n\t{\n\t\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\t\n\t\t// observe preferences that we care about\n\t\t[defaults addObserver:self forKeyPath:defaultsSyntaxHighlightScriptKey options:0 context:NULL];\n\t\t[defaults addObserver:self forKeyPath:defaultsSyntaxHighlightOutputKey options:0 context:NULL];\n\t\t[defaults addObserver:self forKeyPath:defaultsDisplayFontSizeKey options:0 context:NULL];\n\t\t\n\t\tobservingKeyPaths = YES;\n\t\t\n\t\t// Observe notifications to keep our variable browser toggle button up to date\n\t\t[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(browserWillShow:) name:EidosVariableBrowserWillShowNotification object:nil];\n\t\t[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(browserWillHide:) name:EidosVariableBrowserWillHideNotification object:nil];\n\t\t\n\t\t// set default viewing state; this might come from user defaults on a per-script basis eventually...\n\t\tzoomedChromosomeShowsRateMaps = NO;\n\t\tzoomedChromosomeShowsGenomicElements = NO;\n\t\tzoomedChromosomeShowsMutations = YES;\n\t\tzoomedChromosomeShowsFixedSubstitutions = NO;\n\t\t\n\t\t// We set the working directory for new windows to ~/Desktop/, since it makes no sense for them to use the location of the app.\n\t\t// Each running simulation will track its own working directory, and the user can set it with a button in the SLiMgui window.\n\t\t// BCH 4/2/2020: Per request from PLR, we will now use the Desktop as the default directory only if we were launched by Finder\n\t\t// or equivalent; if we were launched by a shell, we will use the working directory given us by that shell.  See issue #76\n\t\tbool launchedFromShell = [(AppDelegate *)[NSApp delegate] launchedFromShell];\n\t\t\n\t\tif (launchedFromShell)\n\t\t\tsim_working_dir = [(AppDelegate *)[NSApp delegate] SLiMguiCurrentWorkingDirectory];\n\t\telse\n\t\t\tsim_working_dir = Eidos_ResolvedPath(\"~/Desktop\");\n\t\t\n\t\t// Check that our chosen working directory actually exists; if not, use ~\n\t\tstruct stat buffer;\n\t\t\n\t\tif (stat(sim_working_dir.c_str(), &buffer) != 0)\n\t\t\tsim_working_dir = Eidos_ResolvedPath(\"~\");\n\t\t\n\t\tsim_requested_working_dir = sim_working_dir;\t// return to the working dir on recycle unless the user overrides it\n\t}\n\t\n\treturn self;\n}\n\n- (void)cleanup\n{\n\t//NSLog(@\"[SLiMWindowController cleanup]\");\n\t\n\t[[NSNotificationCenter defaultCenter] removeObserver:self];\n\t\n\t[NSObject cancelPreviousPerformRequestsWithTarget:self];\t// _tickPlay:, _continuousPlay:, _continuousProfile:, etc.\n\t\n\t// Disconnect delegate relationships\n\t[overallSplitView setDelegate:nil];\n\toverallSplitView = nil;\n\t\n\t[bottomSplitView setDelegate:nil];\n\tbottomSplitView = nil;\n\t\n\t[scriptTextView setDelegate:nil];\n\tscriptTextView = nil;\n\t\n\t[outputTextView setDelegate:nil];\n\toutputTextView = nil;\n\t\n\t[_consoleController setDelegate:nil];\n\t\n\t// Remove observers\n\tif (observingKeyPaths)\n\t{\n\t\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\t\t[defaults removeObserver:self forKeyPath:defaultsSyntaxHighlightScriptKey context:NULL];\n\t\t[defaults removeObserver:self forKeyPath:defaultsSyntaxHighlightOutputKey context:NULL];\n\t\t[defaults removeObserver:self forKeyPath:defaultsDisplayFontSizeKey context:NULL];\n\t\t\n\t\tobservingKeyPaths = NO;\n\t}\n\t\n\t[[NSNotificationCenter defaultCenter] removeObserver:self];\n\t\n\t[NSObject cancelPreviousPerformRequestsWithTarget:playSpeedToolTipWindow selector:@selector(orderOut:) object:nil];\n\t[playSpeedToolTipWindow orderOut:nil];\n\t[playSpeedToolTipWindow release];\n\tplaySpeedToolTipWindow = nil;\n\t\n\t// Free resources\n\t[scriptString release];\n\tscriptString = nil;\n\t\n\tif (community)\n\t{\n\t\tdelete community;\n\t\tcommunity = nullptr;\n\t\tfocalSpecies = nullptr;\n\t}\n\tif (slimgui)\n\t{\n\t\tdelete slimgui;\n\t\tslimgui = nullptr;\n\t}\n\t\n\tif (sim_RNG_initialized)\n\t{\n#ifndef _OPENMP\n\t\t_Eidos_FreeOneRNG(sim_RNG_SINGLE);\n#else\n\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = sim_RNG_PERTHREAD[threadIndex];\n\t\t\t_Eidos_FreeOneRNG(*rng_state);\n\t\t\tsim_RNG_PERTHREAD[threadIndex] = nullptr;\n\t\t\tfree(rng_state);\n\t\t}\n\t\t\n\t\tsim_RNG_PERTHREAD.resize(0);\n#endif\n\t\tsim_RNG_initialized = false;\n\t\t//NSLog(@\"-[SLiMWindowController cleanup]: freed sim_RNG\");\n\t}\n\t\n\t[self setInvalidSimulation:YES];\n\t\n\t[continuousPlayStartDate release];\n\tcontinuousPlayStartDate = nil;\n\t\n\t[genomicElementColorRegistry release];\n\tgenomicElementColorRegistry = nil;\n\t\n\t// All graph windows attached to this controller need to be closed, since they refer back to us;\n\t// closing them will come back via windowWillClose: and make them release and nil themselves\n\t[self sendAllLinkedViewsSelector:@selector(cleanup)];\n\t[self sendAllLinkedWindowsSelector:@selector(close)];\n\t\n\t[graphWindowMutationFreqSpectrum autorelease];\n\t[graphWindowMutationFreqTrajectories autorelease];\n\t[graphWindowMutationLossTimeHistogram autorelease];\n\t[graphWindowMutationFixationTimeHistogram autorelease];\n\t[graphWindowFitnessOverTime autorelease];\n\t[graphWindowPopulationVisualization autorelease];\n\t\n\tgraphWindowMutationFreqSpectrum = nil;\n\tgraphWindowMutationFreqTrajectories = nil;\n\tgraphWindowMutationLossTimeHistogram = nil;\n\tgraphWindowMutationFixationTimeHistogram = nil;\n\tgraphWindowFitnessOverTime = nil;\n\tgraphWindowPopulationVisualization = nil;\n\t\n\t[linkedWindows autorelease];\n\tlinkedWindows = nil;\n\t\n\t// We also need to close and release our console window and its associated variable browser window.\n\t// We don't track the console or var browser in windowWillClose: since we want those windows to\n\t// continue to exist even when they are hidden, unlike graph windows.\n\t[[_consoleController browserController] hideWindow];\n\t[_consoleController hideWindow];\n\t[self setConsoleController:nil];\n\t\n\t// Also close and let go of our mini-graph tooltip window\n\t[self hideMiniGraphToolTipWindow];\n\t[functionGraphToolTipWindow autorelease];\n\tfunctionGraphToolTipWindow = nil;\n}\n\n- (void)dealloc\n{\n\t//NSLog(@\"[SLiMWindowController dealloc]\");\n\t\n\t[self cleanup];\n\t\n\tif ([self document])\n\t\t[self setDocument:nil];\n\t\n\t[super dealloc];\n}\n\n- (void)setDocument:(id)document\n{\n\t[super setDocument:document];\n\t\n\t// The document currently has our model information, but we keep the model, so we need to pull it over\n\tif ([self document])\n\t\t[self setScriptStringAndInitializeSimulation:[[self document] documentScriptString]];\n}\n\n- (NSString *)windowTitleForDocumentDisplayName:(NSString *)displayName\n{\n\tNSString *superString = [super windowTitleForDocumentDisplayName:displayName];\n\tSLiMDocument *document = [self document];\n\tNSString *recipeName = [document recipeName];\n\tNSURL *docURL = [document fileURL];\n\t\n\t// If we have a recipe name, *and* we are an unsaved (i.e. untitled) document, then we want to customize the window title\n\tif (recipeName && !docURL && [displayName hasPrefix:[document defaultDraftName]])\n\t{\n\t\tNSRange spaceRange = [recipeName rangeOfString:@\" \"];\n\t\t\n\t\tif (spaceRange.location != NSNotFound)\n\t\t{\n\t\t\tNSString *recipeNumber = [recipeName substringToIndex:spaceRange.location];\n\t\t\t\n\t\t\tif ([recipeNumber length])\n\t\t\t\treturn [NSString stringWithFormat:@\"%@ [Recipe %@]\", superString, recipeNumber];\n\t\t}\n\t}\n\t\n\treturn superString;\n}\n\n- (void)browserWillShow:(NSNotification *)note\n{\n\tif ([note object] == [_consoleController browserController])\n\t\t[browserButton setState:NSOnState];\n}\n\n- (void)browserWillHide:(NSNotification *)note\n{\n\tif ([note object] == [_consoleController browserController])\n\t\t[browserButton setState:NSOffState];\n}\n\n- (void)displayStartupMessage\n{\n\tNSDictionary *statusAttrs = [NSDictionary eidosTextAttributesWithColor:[NSColor textColor] size:11.0];\n\tNSString *statusString = [NSString stringWithFormat:@\"SLiM %s, %@ build.\", SLIM_VERSION_STRING,\n#if DEBUG\n\t\t\t\t\t\t\t  @\"debug\"\n#else\n\t\t\t\t\t\t\t  @\"release\"\n#endif\n\t\t\t\t\t\t\t  ];\n\t\n#ifdef _OPENMP\n\tstatusString = [statusString stringByAppendingFormat:@\"  Running SLiM in parallel with %d threads maximum.\", gEidosMaxThreads];\n#endif\n\t\n\tNSMutableAttributedString *statusAttrString = [[[NSMutableAttributedString alloc] initWithString:statusString attributes:statusAttrs] autorelease];\n\t\n\t[statusAttrString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [statusAttrString length])];\n\t[scriptStatusTextField setAttributedStringValue:statusAttrString];\n}\n\n- (void)showTerminationMessage:(NSString *)terminationMessage\n{\n\tNSAlert *alert = [[NSAlert alloc] init];\n\t\n\t[alert setAlertStyle:NSAlertStyleCritical];\n\t[alert setMessageText:@\"Simulation Runtime Error\"];\n\t[alert setInformativeText:[NSString stringWithFormat:@\"%@\\nThis error has invalidated the simulation; it cannot be run further.  Once the script is fixed, you can recycle the simulation and try again.\", terminationMessage]];\n\t[alert addButtonWithTitle:@\"OK\"];\n\t\n\t[alert beginSheetModalForWindow:[self window] completionHandler:^(NSModalResponse returnCode) { [alert autorelease]; [terminationMessage autorelease]; }];\n\t\n\t// Depending on the circumstances of the error, we might be able to select a range in our input file to show what caused the error\n\tif (![[self document] changedSinceRecycle])\n\t\t[scriptTextView selectErrorRange];\n\t\n\t// Show the error in the status bar also\n\tNSString *trimmedError = [terminationMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n\tNSDictionary *errorAttrs = [NSDictionary eidosTextAttributesWithColor:[NSColor redColor] size:11.0];\n\tNSMutableAttributedString *errorAttrString = [[[NSMutableAttributedString alloc] initWithString:trimmedError attributes:errorAttrs] autorelease];\n\t\n\t[errorAttrString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [errorAttrString length])];\n\t[scriptStatusTextField setAttributedStringValue:errorAttrString];\n}\n\n- (void)checkForSimulationTermination\n{\n\tstd::string &&terminationMessage = gEidosTermination.str();\n\t\n\tif (!terminationMessage.empty())\n\t{\n\t\tconst char *cstr = terminationMessage.c_str();\n\t\tNSString *str = [NSString stringWithUTF8String:cstr];\n\t\t\n\t\tgEidosTermination.clear();\n\t\tgEidosTermination.str(\"\");\n\t\t\n\t\t[self performSelector:@selector(showTerminationMessage:) withObject:[str retain] afterDelay:0.0];\t// showTerminationMessage: will release the string\n\t\t\n\t\t// Now we need to clean up so we are in a displayable state.  Note that we don't even attempt to dispose\n\t\t// of the old simulation object; who knows what state it is in, touching it might crash.\n\t\tcommunity = nullptr;\n\t\tfocalSpecies = nullptr;\n\t\tslimgui = nullptr;\n\t\t\n\t\tif (sim_RNG_initialized)\n\t\t{\n#ifndef _OPENMP\n\t\t\t_Eidos_FreeOneRNG(sim_RNG_SINGLE);\n#else\n\t\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t\t{\n\t\t\t\tEidos_RNG_State *rng_state = sim_RNG_PERTHREAD[threadIndex];\n\t\t\t\t_Eidos_FreeOneRNG(*rng_state);\n\t\t\t\tsim_RNG_PERTHREAD[threadIndex] = nullptr;\n\t\t\t\tfree(rng_state);\n\t\t\t}\n\t\t\t\n\t\t\tsim_RNG_PERTHREAD.resize(0);\n#endif\n\t\t\tsim_RNG_initialized = false;\n\t\t\t//NSLog(@\"-[SLiMWindowController checkForSimulationTermination]: freed sim_RNG\");\n\t\t}\n\t\t\n\t\t[self setReachedSimulationEnd:YES];\n\t\t[self setInvalidSimulation:YES];\n\t}\n}\n\n- (void)startNewSimulationFromScript\n{\n\tif (community)\n\t{\n\t\tdelete community;\n\t\tcommunity = nullptr;\n\t\tfocalSpecies = nullptr;\n\t}\n\tif (slimgui)\n\t{\n\t\tdelete slimgui;\n\t\tslimgui = nullptr;\n\t}\n\t\n\t// Reset the number of threads to be used in parallel regions, if it has been changed by parallelSetNumThreads();\n\t// note that we do not save/restore the value across context switches between models, as we do RNGs and such,\n\t// since we don't support end users running SLiMgui multithreaded anyhow\n\tgEidosNumThreads = gEidosMaxThreads;\n\tgEidosNumThreadsOverride = false;\n\tomp_set_num_threads(gEidosMaxThreads);\n\t\n\t// Free the old simulation RNG and make a new one, to have clean state\n\tif (sim_RNG_initialized)\n\t{\n#ifndef _OPENMP\n\t\t_Eidos_FreeOneRNG(sim_RNG_SINGLE);\n#else\n\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = sim_RNG_PERTHREAD[threadIndex];\n\t\t\t_Eidos_FreeOneRNG(*rng_state);\n\t\t\tsim_RNG_PERTHREAD[threadIndex] = nullptr;\n\t\t\tfree(rng_state);\n\t\t}\n\t\t\n\t\tsim_RNG_PERTHREAD.resize(0);\n#endif\n\t\tsim_RNG_initialized = false;\n\t\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: freed sim_RNG\");\n\t}\n\t\n#ifndef _OPENMP\n\t_Eidos_InitializeOneRNG(sim_RNG_SINGLE);\n#else\n\tsim_RNG_PERTHREAD.resize(gEidosMaxThreads);\n\t\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD) num_threads(gEidosMaxThreads)\n\t{\n\t\t// Each thread allocates and initializes its own Eidos_RNG_State, for \"first touch\" optimization\n\t\tint threadnum = omp_get_thread_num();\n\t\tEidos_RNG_State *rng_state = (Eidos_RNG_State *)calloc(1, sizeof(Eidos_RNG_State));\n\t\t_Eidos_InitializeOneRNG(*rng_state);\n\t\tsim_RNG_PERTHREAD[threadnum] = rng_state;\n\t}\n#endif\n\tsim_RNG_initialized = true;\n\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: initialized sim_RNG\");\n\t\n\t// The Eidos RNG may be set up already; if so, get rid of it.  When we are not running, we keep the\n\t// Eidos RNG in an initialized state, to catch errors with the swapping of RNG state.  Nobody should\n\t// use it when we have not swapped in our own RNG.\n\tif (gEidos_RNG_Initialized)\n\t{\n#ifndef _OPENMP\n\t\t_Eidos_FreeOneRNG(gEidos_RNG_SINGLE);\n#else\n\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = gEidos_RNG_PERTHREAD[threadIndex];\n\t\t\t_Eidos_FreeOneRNG(*rng_state);\n\t\t\tgEidos_RNG_PERTHREAD[threadIndex] = nullptr;\n\t\t\tfree(rng_state);\n\t\t}\n\t\t\n\t\t// note that we do not resize the gEidos_RNG_PERTHREAD vector; it stays at its final size\n#endif\n\t\tgEidos_RNG_Initialized = false;\n\t\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: freed gEidos_RNG\");\n\t}\n\t\n\t// Swap in our RNG\n#ifndef _OPENMP\n\tstd::swap(sim_RNG_SINGLE, gEidos_RNG_SINGLE);\n#else\n\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\tstd::swap(sim_RNG_PERTHREAD[threadIndex], gEidos_RNG_PERTHREAD[threadIndex]);\n#endif\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: swapped IN simRNG (sim_RNG_initialized == %@, gEidos_RNG_Initialized == %@)\", sim_RNG_initialized ? @\"YES\" : @\"NO\", gEidos_RNG_Initialized ? @\"YES\" : @\"NO\");\n\t\n\tstd::istringstream infile([scriptString UTF8String]);\n\t\n\ttry\n\t{\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(infile);\n\t\tcommunity->InitializeRNGFromSeed(nullptr);\n\t\tcommunity->FinishInitialization();\n\t\t\n\t\t// Swap out our RNG\n#ifndef _OPENMP\n\t\tstd::swap(sim_RNG_SINGLE, gEidos_RNG_SINGLE);\n#else\n\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t\tstd::swap(sim_RNG_PERTHREAD[threadIndex], gEidos_RNG_PERTHREAD[threadIndex]);\n#endif\n\t\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\t\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: swapped OUT simRNG (sim_RNG_initialized == %@, gEidos_RNG_Initialized == %@)\", sim_RNG_initialized ? @\"YES\" : @\"NO\", gEidos_RNG_Initialized ? @\"YES\" : @\"NO\");\n\t\t\n\t\t// We also reset various Eidos/SLiM instance state; each SLiMgui window is independent\n\t\tsim_next_pedigree_id = 0;\n\t\tsim_next_mutation_id = 0;\n\t\tsim_suppress_warnings = false;\n\t\t\n\t\t// The current working directory was set up in -init to be ~/Desktop, and should not be reset here; if the\n\t\t// user has changed it, that change ought to stick across recycles.  So this bounces us back to the last dir chosen.\n\t\tsim_working_dir = sim_requested_working_dir;\n\t\t\n\t\t[self setReachedSimulationEnd:NO];\n\t\t[self setInvalidSimulation:NO];\n\t\thasImported = NO;\n\t}\n\tcatch (...)\n\t{\n\t\t// BCH 12/25/2022: adding this to swap out our RNG after a raise, seems better...\n#ifndef _OPENMP\n\t\tstd::swap(sim_RNG_SINGLE, gEidos_RNG_SINGLE);\n#else\n\t\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\t\tstd::swap(sim_RNG_PERTHREAD[threadIndex], gEidos_RNG_PERTHREAD[threadIndex]);\n#endif\n\t\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\t\t//NSLog(@\"-[SLiMWindowController startNewSimulationFromScript]: swapped OUT simRNG (sim_RNG_initialized == %@, gEidos_RNG_Initialized == %@)\", sim_RNG_initialized ? @\"YES\" : @\"NO\", gEidos_RNG_Initialized ? @\"YES\" : @\"NO\");\n\t\t\n\t\tif (community)\n\t\t\tcommunity->simulation_valid_ = false;\n\t\t[self setReachedSimulationEnd:YES];\n\t\t[self checkForSimulationTermination];\n\t}\n\t\n\tif (community)\n\t{\n\t\t// make a new SLiMgui instance to represent SLiMgui in Eidos\n\t\tslimgui = new SLiMgui(*community, self);\n\t\t\n\t\t// set up the \"slimgui\" symbol for it immediately\n\t\t// BCH 11/7/2025: note this symbol is now protected in SLiM_ConfigureContext()\n\t\tcommunity->simulation_constants_->InitializeConstantSymbolEntry(slimgui->SymbolTableEntry());\n\t}\n}\n\n- (void)setScriptStringAndInitializeSimulation:(NSString *)string\n{\n\t[scriptString release];\n\tscriptString = [string retain];\n\t\n\t[self startNewSimulationFromScript];\n}\n\n- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context\n{\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\tif (object == defaults)\n\t{\n\t\tif ([keyPath isEqualToString:defaultsSyntaxHighlightScriptKey])\n\t\t{\n\t\t\tif ([defaults boolForKey:defaultsSyntaxHighlightScriptKey])\n\t\t\t\t[scriptTextView setSyntaxColoring:kEidosSyntaxColoringEidos];\n\t\t\telse\n\t\t\t\t[scriptTextView setSyntaxColoring:kEidosSyntaxColoringNone];\n\t\t}\n\t\t\n\t\tif ([keyPath isEqualToString:defaultsSyntaxHighlightOutputKey])\n\t\t{\n\t\t\tif ([defaults boolForKey:defaultsSyntaxHighlightOutputKey])\n\t\t\t\t[outputTextView setSyntaxColoring:kEidosSyntaxColoringOutput];\n\t\t\telse\n\t\t\t\t[outputTextView setSyntaxColoring:kEidosSyntaxColoringNone];\n\t\t}\n\t\t\n\t\tif ([keyPath isEqualToString:defaultsDisplayFontSizeKey])\n\t\t{\n\t\t\tint fontSize = (int)[defaults integerForKey:defaultsDisplayFontSizeKey];\n\t\t\t\n\t\t\t[scriptTextView setDisplayFontSize:fontSize];\n\t\t\t[outputTextView setDisplayFontSize:fontSize];\n\t\t\t\n\t\t\t[[_consoleController scriptTextView] setDisplayFontSize:fontSize];\n\t\t\t[[_consoleController outputTextView] setDisplayFontSize:fontSize];\n\t\t}\n\t}\n}\n\n- (GraphView *)graphViewForGraphWindow:(NSWindow *)window\n{\n\treturn (GraphView *)[window contentView];\n}\n\n- (void)sendAllLinkedViewsSelector:(SEL)selector\n{\n\t[[self graphViewForGraphWindow:graphWindowMutationFreqSpectrum] performSelector:selector];\n\t[[self graphViewForGraphWindow:graphWindowMutationFreqTrajectories] performSelector:selector];\n\t[[self graphViewForGraphWindow:graphWindowMutationLossTimeHistogram] performSelector:selector];\n\t[[self graphViewForGraphWindow:graphWindowMutationFixationTimeHistogram] performSelector:selector];\n\t[[self graphViewForGraphWindow:graphWindowFitnessOverTime] performSelector:selector];\n\t[[self graphViewForGraphWindow:graphWindowPopulationVisualization] performSelector:selector];\n\t\n\tfor (NSWindow *window : linkedWindows)\n\t{\n\t\tNSView *contentView = [window contentView];\n\t\t\n\t\tif ([contentView respondsToSelector:selector])\n\t\t\t[contentView performSelector:selector];\n\t}\n}\n\n- (void)sendAllLinkedWindowsSelector:(SEL)selector\n{\n\t[graphWindowMutationFreqSpectrum performSelector:selector];\n\t[graphWindowMutationFreqTrajectories performSelector:selector];\n\t[graphWindowMutationLossTimeHistogram performSelector:selector];\n\t[graphWindowMutationFixationTimeHistogram performSelector:selector];\n\t[graphWindowFitnessOverTime performSelector:selector];\n\t[graphWindowPopulationVisualization performSelector:selector];\n\t\n\t[linkedWindows makeObjectsPerformSelector:selector];\n}\n\n- (void)updateOutputTextView\n{\n\t// QtSLiM separates these output streams, but we just glom them together\n\tstd::string newOutput = gSLiMOut.str();\n\tnewOutput += gSLiMError.str();\n\t\n\tif (!newOutput.empty())\n\t{\n\t\tconst char *cstr = newOutput.c_str();\n\t\tNSString *str = [NSString stringWithUTF8String:cstr];\n\t\t\n\t\t// So, ideally we would stay pinned at the bottom if the user had scrolled to the bottom, but would stay\n\t\t// at the user's chosen scroll position above the bottom if they chose such a position.  Unfortunately,\n\t\t// this doesn't seem to work.  I'm not quite sure why.  Particularly when large amounts of output get\n\t\t// added quickly, the scroller doesn't seem to catch up, and then it reads here as not being at the\n\t\t// bottom, and so we become unpinned even though we used to be pinned.  I'm going to just give up, for\n\t\t// now, and always scroll to the bottom when new output comes out.  That's what many other such apps\n\t\t// do anyway; it's a little annoying if you're trying to read old output, but so it goes.\n\t\t\n\t\t//NSScrollView *enclosingScrollView = [outputTextView enclosingScrollView];\n\t\tBOOL scrolledToBottom = YES; //(![enclosingScrollView hasVerticalScroller] || [[enclosingScrollView verticalScroller] doubleValue] == 1.0);\n\t\t\n\t\tNSTextStorage *ts = [outputTextView textStorage];\n\t\tNSUInteger tsOriginalLength = [ts length];\n\t\tNSUInteger strLength = [str length];\n\t\t\n\t\t[ts beginEditing];\n\t\t[ts replaceCharactersInRange:NSMakeRange(tsOriginalLength, 0) withString:str];\n\t\t[ts addAttribute:NSFontAttributeName value:[NSFont fontWithName:@\"Menlo\" size:[outputTextView displayFontSize]] range:NSMakeRange(tsOriginalLength, strLength)];\n\t\t[ts endEditing];\n\t\t\n\t\tif ([[NSUserDefaults standardUserDefaults] boolForKey:defaultsSyntaxHighlightOutputKey])\n\t\t\t[outputTextView recolorAfterChanges];\n\t\t\n\t\t// if the user was scrolled to the bottom, we keep them there; otherwise, we let them stay where they were\n\t\tif (scrolledToBottom)\n\t\t\t[outputTextView scrollRangeToVisible:NSMakeRange([[outputTextView string] length], 0)];\n\t\t\n\t\t// clear any error flags set on the stream and empty out its string so it is ready to receive new output\n\t\tgSLiMOut.clear();\n\t\tgSLiMOut.str(\"\");\n\t\t\n\t\tgSLiMError.clear();\n\t\tgSLiMError.str(\"\");\n\t}\n}\n\n- (void)updateTickCounter\n{\n\t//NSLog(@\"updating after tick %d, tickTextField %p\", community->tick_, tickTextField);\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tif (community->tick_ == 0)\n\t\t{\n\t\t\t[tickTextField setStringValue:@\"initialize()\"];\n\t\t\t[cycleTextField setStringValue:@\"initialize()\"];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[tickTextField setIntegerValue:community->tick_];\n\t\t\t[cycleTextField setIntegerValue:displaySpecies->cycle_];\n\t\t}\n\t}\n\telse\n\t{\n\t\t[tickTextField setStringValue:@\"\"];\n\t\t[cycleTextField setStringValue:@\"\"];\n\t}\n}\n\n- (void)updatePopulationViewHiding\n{\n\tstd::vector<Subpopulation*> selectedSubpopulations = [self selectedSubpopulations];\n\tBOOL canDisplayPopulationView = [populationView tileSubpopulations:selectedSubpopulations];\n\t\n\t// Swap between populationView and populationErrorView as needed to show text messages in the pop view area\n\tif (canDisplayPopulationView)\n\t{\n\t\tif ([populationView isHidden])\n\t\t{\n\t\t\t[populationView setHidden:NO];\n\t\t\t[populationErrorView setHidden:YES];\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (![populationView isHidden])\n\t\t{\n\t\t\t[populationView setHidden:YES];\n\t\t\t[populationErrorView setHidden:NO];\n\t\t}\n\t}\n}\n\n- (bool)modelMightBeNonWF\n{\n\t// We don't have any really solid way to tell what the model will do until it is executed, given the dynamic nature of\n\t// Eidos, but this method tries to apply some heuristics to the question to provide a guess that will usually be correct.\n\tif (![self invalidSimulation] && community)\n\t\tif (community->ModelType() == SLiMModelType::kModelTypeNonWF)\n\t\t\treturn YES;\n\t\n\tNSString *string = [scriptTextView string];\n\t\n\tif ([string containsString:@\"initializeSLiMModelType(\\\"nonWF\\\")\"] || [string containsString:@\"initializeSLiMModelType(\\'nonWF\\')\"])\n\t\treturn YES;\n\t\n\treturn NO;\n}\n\n- (void)updateSpeciesBar\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\t// Update the species bar as needed; we do this only after initialization, to avoid a hide/show on recycle of multispecies models\n\tif (community && displaySpecies && (community->Tick() >= 1))\n\t{\n\t\tBOOL speciesBarVisibleNow = ![speciesBar isHidden];\n\t\tbool speciesBarShouldBeVisible = (community->all_species_.size() > 1);\n\t\t\n\t\tif (speciesBarVisibleNow && !speciesBarShouldBeVisible)\n\t\t{\n\t\t\t[speciesBar setEnabled:NO];\n\t\t\t\n\t\t\t[speciesBar setHidden:YES];\n\t\t\t[speciesBarBottomConstraint setConstant:0];\n\t\t\t\n\t\t\treloadingSpeciesBar = true;\n\t\t\t[speciesBar setSegmentCount:0];\n\t\t\treloadingSpeciesBar = false;\n\t\t}\n\t\telse if (!speciesBarVisibleNow && speciesBarShouldBeVisible)\n\t\t{\n\t\t\t[speciesBar setHidden:NO];\n\t\t\t[speciesBarBottomConstraint setConstant:10];\n\t\t\t\n\t\t\tif (([speciesBar segmentCount] == 0) && (community->all_species_.size() > 0))\n\t\t\t{\n\t\t\t\t// add tabs for species when shown\n\t\t\t\tint selectedSpeciesIndex = 0;\n\t\t\t\tint speciesCount = (int)community->all_species_.size(), speciesIndex = 0;\n\t\t\t\tbool avatarsOnly = (speciesCount > 2);\n\t\t\t\t\n\t\t\t\treloadingSpeciesBar = true;\n\t\t\t\t\n\t\t\t\t[speciesBar setSegmentCount:speciesCount];\n\t\t\t\t\n\t\t\t\tfor (Species *species : community->all_species_)\n\t\t\t\t{\n\t\t\t\t\tNSString *tabLabel = [NSString stringWithUTF8String:species->avatar_.c_str()];\n\t\t\t\t\t\n\t\t\t\t\tif (!avatarsOnly)\n\t\t\t\t\t{\n\t\t\t\t\t\ttabLabel = [tabLabel stringByAppendingString:@\" \"];\n\t\t\t\t\t\ttabLabel = [tabLabel stringByAppendingString:[NSString stringWithUTF8String:species->name_.c_str()]];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t[speciesBar setLabel:tabLabel forSegment:speciesIndex];\n\t\t\t\t\t[speciesBar setWidth:0 forSegment:speciesIndex];\n\t\t\t\t\t\n\t\t\t\t\tNSString *tooltipString = [@\"Species \" stringByAppendingString:[NSString stringWithUTF8String:species->name_.c_str()]];\n\t\t\t\t\t\n\t\t\t\t\t[[speciesBar cell] setToolTip:tooltipString forSegment:speciesIndex];\t// do this on the cell because the corresponding NSSegmentedControl API wasn't added until 10.13\n\t\t\t\t\t\n\t\t\t\t\tif (focalSpeciesName.length() && (species->name_.compare(focalSpeciesName) == 0))\n\t\t\t\t\t\tselectedSpeciesIndex = speciesIndex;\n\t\t\t\t\t\n\t\t\t\t\tspeciesIndex++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treloadingSpeciesBar = false;\n\t\t\t\t\n\t\t\t\t//qDebug() << \"selecting index\" << selectedSpeciesIndex << \"for name\" << QString::fromStdString(focalSpeciesName);\n\t\t\t\t[speciesBar setSelectedSegment:selectedSpeciesIndex];\n\t\t\t}\n\t\t\t\n\t\t\t[speciesBar setEnabled:YES];\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Whenever we're invalid or uninitialized, we hide the species bar and disable and remove all the tabs\n\t\t[speciesBar setEnabled:NO];\n\t\t\n\t\t[speciesBar setHidden:YES];\n\t\t[speciesBarBottomConstraint setConstant:0];\n\t\t\n\t\treloadingSpeciesBar = true;\n\t\t[speciesBar setSegmentCount:0];\n\t\treloadingSpeciesBar = false;\n\t}\n}\n\n- (void)updateAfterTickFull:(BOOL)fullUpdate\n{\n\t// fullUpdate is used to suppress some expensive updating to every third update\n\tif (!fullUpdate)\n\t{\n\t\tif (++partialUpdateCount >= 3)\n\t\t{\n\t\t\tpartialUpdateCount = 0;\n\t\t\tfullUpdate = YES;\n\t\t}\n\t}\n\t\n\t// Update the species bar and then fetch the focal species after that update, which might change it\n\t[self updateSpeciesBar];\n\t\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\t// Flush any buffered output to files every full update, so that the user sees changes to the files without too much delay\n\t// NOTE THAT THE WORKING DIRECTORY HAS BEEN CHANGED BACK AT THIS POINT!\n\tif (fullUpdate)\n\t\tif (!Eidos_FlushFiles())\n\t\t\traise(SIGTRAP);\t\t\t// could be improved, but for SLiMguiLegacy this is OK\n\t\n\t// Check whether the simulation has terminated due to an error; if so, show an error message with a delayed perform\n\t[self checkForSimulationTermination];\n\t\n\t// The rest of the code here needs to be careful about the invalid state; we do want to update our controls when invalid, but sim is nil.\n\tif (fullUpdate)\n\t{\n\t\t// FIXME it would be good for this updating to be minimal; reloading the tableview every time, etc., is quite wasteful...\n\t\t[self updateOutputTextView];\n\t\t\n\t\t// Reloading the subpop tableview is tricky, because we need to preserve the selection across the reload, while also noting that the selection is forced\n\t\t// to change when a subpop goes extinct.  The current selection is noted in the gui_selected_ ivar of each subpop.  So what we do here is reload the tableview\n\t\t// while suppressing our usual update of our selection state, and then we try to re-impose our selection state on the new tableview content.  If a subpop\n\t\t// went extinct, we will fail to notice the selection change; but that is OK, since we force an update of populationView and chromosomeZoomed below anyway.\n\t\treloadingSubpopTableview = YES;\n\t\t[subpopTableView reloadData];\n\t\t\n\t\tif (!displaySpecies)\n\t\t{\n\t\t\t[subpopTableView deselectAll:nil];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tPopulation &population = displaySpecies->population_;\n\t\t\tint subpopCount = (int)population.subpops_.size();\n\t\t\tauto popIter = population.subpops_.begin();\n\t\t\tNSMutableIndexSet *indicesToSelect = [NSMutableIndexSet indexSet];\n\t\t\t\n\t\t\tfor (int i = 0; i < subpopCount; ++i)\n\t\t\t{\n\t\t\t\tif (popIter->second->gui_selected_)\n\t\t\t\t\t[indicesToSelect addIndex:i];\n\t\t\t\t\n\t\t\t\tpopIter++;\n\t\t\t}\n\t\t\t\n\t\t\t[subpopTableView selectRowIndexes:indicesToSelect byExtendingSelection:NO];\n\t\t}\n\t\t\n\t\treloadingSubpopTableview = NO;\n\t\t[subpopTableView setNeedsDisplay];\n\t}\n\t\n\t// Now update our other UI, some of which depends upon the state of subpopTableView \n\t[populationView setNeedsDisplay:YES];\n\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t\n\t[self updatePopulationViewHiding];\n\t\n\tif (fullUpdate)\n\t\t[self updateTickCounter];\n\t\n\t// Update stuff that only needs updating when the script is re-parsed, not after every tick\n\tif (!displaySpecies || community->mutation_types_changed_)\n\t{\n\t\t[mutTypeTableView reloadData];\n\t\t[mutTypeTableView setNeedsDisplay];\n\t\t\n\t\tif (community)\n\t\t\tcommunity->mutation_types_changed_ = false;\n\t}\n\t\n\tif (!displaySpecies || community->genomic_element_types_changed_)\n\t{\n\t\t[genomicElementTypeTableView reloadData];\n\t\t[genomicElementTypeTableView setNeedsDisplay];\n\t\t\n\t\tif (community)\n\t\t\tcommunity->genomic_element_types_changed_ = false;\n\t}\n\t\n\tif (!displaySpecies || community->interaction_types_changed_)\n\t{\n\t\t[interactionTypeTableView reloadData];\n\t\t[interactionTypeTableView setNeedsDisplay];\n\t\t\n\t\tif (community)\n\t\t\tcommunity->interaction_types_changed_ = false;\n\t}\n\t\n\tif (!displaySpecies || community->scripts_changed_)\n\t{\n\t\t[scriptBlocksTableView reloadData];\n\t\t[scriptBlocksTableView setNeedsDisplay];\n\t\t\n\t\tif (community)\n\t\t\tcommunity->scripts_changed_ = false;\n\t}\n\t\n\tif (!displaySpecies || community->chromosome_changed_)\n\t{\n\t\t[chromosomeOverview setNeedsDisplay:YES];\n\t\t[chromosomeZoomed setNeedsDisplay:YES];\n\t\t\n\t\tif (community)\n\t\t\tcommunity->chromosome_changed_ = false;\n\t}\n\t\n\t// Update graph windows as well; this will usually trigger a setNeedsDisplay:YES but may do other updating work as well\n\tif (fullUpdate)\n\t\t[self sendAllLinkedViewsSelector:@selector(updateAfterTick)];\n}\n\n- (void)chromosomeSelectionChanged:(NSNotification *)note\n{\n\t[self sendAllLinkedViewsSelector:@selector(controllerSelectionChanged)];\n}\n\n- (void)replaceHeaderForColumn:(NSTableColumn *)column withImageNamed:(NSString *)imageName scaledToSize:(int)imageSize withSexSymbol:(IndividualSex)sexSymbol\n{\n\tNSImage *headerImage = [NSImage imageNamed:imageName];\n\tNSImage *scaledHeaderImage = [headerImage copy];\n\tNSTextAttachment *ta = [[NSTextAttachment alloc] init];\n\t\n\t[scaledHeaderImage setSize:NSMakeSize(imageSize, imageSize)];\n\t[(NSCell *)[ta attachmentCell] setImage:scaledHeaderImage];\n\t\n\tNSMutableAttributedString *attrStr = [[NSAttributedString attributedStringWithAttachment:ta] mutableCopy];\n\t\n\tif (sexSymbol != IndividualSex::kUnspecified)\n\t{\n\t\tNSImage *sexSymbolImage = [NSImage imageNamed:(sexSymbol == IndividualSex::kMale ? @\"male_symbol\" : @\"female_symbol\")];\n\t\tNSImage *scaledSexSymbolImage = [sexSymbolImage copy];\n\t\tNSTextAttachment *sexSymbolAttachment = [[NSTextAttachment alloc] init];\n\t\t\n\t\t[scaledSexSymbolImage setSize:NSMakeSize(14, 14)];\n\t\t[(NSCell *)[sexSymbolAttachment attachmentCell] setImage:scaledSexSymbolImage];\n\t\t\n\t\tNSAttributedString *sexSymbolAttrStr = [NSAttributedString attributedStringWithAttachment:sexSymbolAttachment];\n\t\t\n\t\t[attrStr appendAttributedString:sexSymbolAttrStr];\n\t\t\n\t\t[scaledSexSymbolImage release];\n\t\t[sexSymbolAttachment release];\n\t}\n\t\n\tNSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];\n\t\n\t[paragraphStyle setAlignment:NSTextAlignmentCenter];\n\t[attrStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attrStr length])];\n\t[[column headerCell] setAttributedStringValue:attrStr];\n\t\n\t[attrStr release];\n\t[paragraphStyle release];\n\t[scaledHeaderImage release];\n\t[ta release];\n}\n\n- (void)windowDidLoad\n{\n    [super windowDidLoad];\n\t\n\t// Tell Cocoa that we can go full-screen\n\t[[self window] setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];\n\t\n\t// The splitview sets the size of overallTopView based upon the position of the splitter.  The overallTopView then\n\t// wants to manually manage the size of its subview, as a way of compensating for half-pixel frame positions that\n\t// mess up our OpenGL subviews.  (We have the constraints in the nib so that working in the nib has fully defined\n\t// constraints, even though we don't want them at runtime.)  See SLiMLayoutRoundoffView in CocoaExtra.mm.  Note\n\t// that a side effect of this is that the window doesn't know its minimum width, because the necessary chain of\n\t// constraints is broken by overallTopView; we have to set a minimum width for the window in the nib to make that\n\t// work.  Which seems to work, although it's an unfortunate hack.  The minimum height is governed by constraints\n\t// on the top-level views under the main splitview, however, and thus the minimum height set on the window in the\n\t// nib is ignored.\n\t[overallTopView removeConstraint:overallTopViewConstraint1];\n\t[overallTopView removeConstraint:overallTopViewConstraint2];\n\t[overallTopView removeConstraint:overallTopViewConstraint3];\n\t[overallTopView removeConstraint:overallTopViewConstraint4];\n\t\n\tNSView *subviewOfOverallTopView = [[overallTopView subviews] objectAtIndex:0];\n\t\n\t[subviewOfOverallTopView setAutoresizingMask:NSViewNotSizable];\n\t[subviewOfOverallTopView setTranslatesAutoresizingMaskIntoConstraints:YES];\n\t\n\t// Fix our splitview's position restore, which NSSplitView sometimes screws up\n\t[overallSplitView eidosRestoreAutosavedPositionsWithName:@\"SLiMgui Overall Splitter\"];\n\t[bottomSplitView eidosRestoreAutosavedPositionsWithName:@\"SLiMgui Splitter\"];\n\t\n\t// THEN set the autosave names on the splitviews; this prevents NSSplitView from getting confused\n\t[overallSplitView setAutosaveName:@\"SLiMgui Overall Splitter\"];\n\t[bottomSplitView setAutosaveName:@\"SLiMgui Splitter\"];\n\t\n\t// Change column headers in the subpopulation table to images\n\t[self replaceHeaderForColumn:subpopSelfingRateColumn withImageNamed:@\"change_selfing_ratio\" scaledToSize:14 withSexSymbol:IndividualSex::kUnspecified];\n\t[self replaceHeaderForColumn:subpopFemaleCloningRateColumn withImageNamed:@\"change_cloning_rate\" scaledToSize:14 withSexSymbol:IndividualSex::kFemale];\n\t[self replaceHeaderForColumn:subpopMaleCloningRateColumn withImageNamed:@\"change_cloning_rate\" scaledToSize:14 withSexSymbol:IndividualSex::kMale];\n\t[self replaceHeaderForColumn:subpopSexRatioColumn withImageNamed:@\"change_sex_ratio\" scaledToSize:15 withSexSymbol:IndividualSex::kUnspecified];\n\t\n\t// Set up syntax coloring based on the user's defaults\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\t[scriptTextView setSyntaxColoring:([defaults boolForKey:defaultsSyntaxHighlightScriptKey] ? kEidosSyntaxColoringEidos : kEidosSyntaxColoringNone)];\n\t[outputTextView setSyntaxColoring:([defaults boolForKey:defaultsSyntaxHighlightOutputKey] ? kEidosSyntaxColoringOutput : kEidosSyntaxColoringNone)];\n\t\n\t// fire the observer message for font size, to make it correct; seems like this used to happen automatically but now doesn't?\n\t[self observeValueForKeyPath:defaultsDisplayFontSizeKey ofObject:defaults change:nullptr context:nullptr];\n\t\n\t// Set the script textview to show its string, with correct formatting\n\t[scriptTextView setString:scriptString];\n\t[scriptTextView recolorAfterChanges];\n\t\n\t// Set up our chromosome views to show the proper stuff\n\t[chromosomeOverview setOverview:true];\n\t[chromosomeOverview setShouldDrawGenomicElements:YES];\n\t[chromosomeOverview setShouldDrawMutations:NO];\n\t[chromosomeOverview setShouldDrawFixedSubstitutions:NO];\n\t[chromosomeOverview setShouldDrawRateMaps:NO];\n\t\n\t[chromosomeZoomed setOverview:false];\n\t[chromosomeZoomed setShouldDrawGenomicElements:zoomedChromosomeShowsGenomicElements];\n\t[chromosomeZoomed setShouldDrawMutations:zoomedChromosomeShowsMutations];\n\t[chromosomeZoomed setShouldDrawFixedSubstitutions:zoomedChromosomeShowsFixedSubstitutions];\n\t[chromosomeZoomed setShouldDrawRateMaps:zoomedChromosomeShowsRateMaps];\n\t\n\t[showRecombinationIntervalsButton setState:(zoomedChromosomeShowsRateMaps ? NSOnState : NSOffState)];\n\t[showGenomicElementsButton setState:(zoomedChromosomeShowsGenomicElements ? NSOnState : NSOffState)];\n\t[showMutationsButton setState:(zoomedChromosomeShowsMutations ? NSOnState : NSOffState)];\n\t[showFixedSubstitutionsButton setState:(zoomedChromosomeShowsFixedSubstitutions ? NSOnState : NSOffState)];\n\t\n\t[[NSNotificationCenter defaultCenter] removeObserver:self name:SLiMChromosomeSelectionChangedNotification object:nil];\n\t[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(chromosomeSelectionChanged:) name:SLiMChromosomeSelectionChangedNotification object:chromosomeOverview];\n\t\n\t// Set up our menu buttons with their menus\n\t[graphCommandsButton setSlimMenu:graphCommandsMenu];\n\t\n\t// Configure our drawer; note that the minimum height here actually forces a minimum height on our window too\n\t[drawer setMinContentSize:NSMakeSize(280, 450)];\n\t[drawer setMaxContentSize:NSMakeSize(450, 570)];\n\t[drawer setContentSize:NSMakeSize(280, 570)];\n\t[drawer setLeadingOffset:0.0];\n\t[drawer setTrailingOffset:20.0];\n\t[drawer openOnEdge:NSMaxXEdge];\n\t[drawer close];\n\t\n\t// Update all our UI to reflect the current state of the simulation\n\t[self updateAfterTickFull:YES];\n\t\n\t// Load our console window nib\n\t[[NSBundle mainBundle] loadNibNamed:@\"EidosConsoleWindow\" owner:self topLevelObjects:NULL];\n}\n\n- (Species *)focalDisplaySpecies\n{\n\t// SLiMgui focuses on one species at a time in its main window display; this method should be called to obtain that species.\n\t// This funnel method checks for various invalid states and returns nil; callers should check for a nil return as needed.\n\tif (![self invalidSimulation] && community && community->simulation_valid_)\n\t{\n\t\t// If we have a focal species set already, it must be valid (the community still exists), so return it\n\t\tif (focalSpecies)\n\t\t\treturn focalSpecies;\n\t\t\n\t\t// If not, we'll choose a species from the species list if there are any\n\t\tconst std::vector<Species *> &all_species = community->AllSpecies();\n\t\t\n\t\tif (all_species.size() >= 1)\n\t\t{\n\t\t\t// If we have a species name remembered, try to choose that species again\n\t\t\tif (focalSpeciesName.length())\n\t\t\t{\n\t\t\t\tfor (Species *species : all_species)\n\t\t\t\t{\n\t\t\t\t\tif (species->name_.compare(focalSpeciesName) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfocalSpecies = species;\n\t\t\t\t\t\treturn focalSpecies;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Failing that, choose the first declared species and remember its name\n\t\t\tfocalSpecies = all_species[0];\n\t\t\tfocalSpeciesName = focalSpecies->name_;\n\t\t}\n\t}\n\t\n\treturn nullptr;\n}\n\n- (std::vector<Subpopulation*>)selectedSubpopulations\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\tstd::vector<Subpopulation*> selectedSubpops;\n\t\n\tif (displaySpecies)\n\t{\n\t\tPopulation &population = displaySpecies->population_;\n\t\tint subpopCount = (int)population.subpops_.size();\n\t\tauto popIter = population.subpops_.begin();\n\t\t\n\t\tfor (int i = 0; i < subpopCount; ++i)\n\t\t{\n\t\t\tSubpopulation *subpop = popIter->second;\n\t\t\t\n\t\t\tif (subpop->gui_selected_)\n\t\t\t\tselectedSubpops.emplace_back(subpop);\n\t\t\t\n\t\t\tpopIter++;\n\t\t}\n\t}\n\t\n\treturn selectedSubpops;\n}\n\n- (NSColor *)colorForGenomicElementType:(GenomicElementType *)elementType withID:(slim_objectid_t)elementTypeID\n{\n\tif (elementType && !elementType->color_.empty())\n\t{\n\t\treturn [NSColor colorWithCalibratedRed:elementType->color_red_ green:elementType->color_green_ blue:elementType->color_blue_ alpha:1.0];\n\t}\n\telse\n\t{\n\t\tif (!genomicElementColorRegistry)\n\t\t\tgenomicElementColorRegistry = [[NSMutableDictionary alloc] init];\n\t\t\n\t\tNSNumber *key = [NSNumber numberWithInteger:elementTypeID];\n\t\tNSColor *elementColor = [genomicElementColorRegistry objectForKey:key];\n\t\t\n\t\tif (!elementColor)\n\t\t{\n\t\t\tint elementCount = (int)[genomicElementColorRegistry count];\n\t\t\t\n\t\t\telementColor = [SLiMWindowController blackContrastingColorForIndex:elementCount];\n\t\t\t[genomicElementColorRegistry setObject:elementColor forKey:key];\n\t\t}\n\t\t\n\t\treturn elementColor;\n\t}\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tSEL sel = [menuItem action];\n\t\n\tif (sel == @selector(playOneStep:))\n\t\treturn !(invalidSimulation || continuousPlayOn || tickPlayOn || reachedSimulationEnd);\n\tif (sel == @selector(play:))\n\t{\n\t\t[menuItem setTitle:(nonProfilePlayOn ? @\"Stop\" : @\"Play\")];\n\t\t\n\t\treturn !(invalidSimulation || tickPlayOn || reachedSimulationEnd || profilePlayOn);\n\t}\n\tif (sel == @selector(profile:))\n\t{\n\t\t[menuItem setTitle:(profilePlayOn ? @\"Stop\" : @\"Profile\")];\n\t\t\n\t\treturn !(invalidSimulation || tickPlayOn || reachedSimulationEnd || nonProfilePlayOn);\n\t}\n\tif (sel == @selector(recycle:))\n\t\treturn !(continuousPlayOn || tickPlayOn);\n\t\n\tif (sel == @selector(graphMutationFrequencySpectrum:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(graphMutationFrequencyTrajectories:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(graphMutationLossTimeHistogram:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(graphMutationFixationTimeHistogram:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(graphFitnessOverTime:))\n\t\treturn !(invalidSimulation);\n\t\n\tif (sel == @selector(checkScript:))\n\t\treturn !(continuousPlayOn || tickPlayOn);\n\tif (sel == @selector(prettyprintScript:))\n\t\treturn !(continuousPlayOn || tickPlayOn);\n\t\n\tif (sel == @selector(exportScript:))\n\t\treturn !(continuousPlayOn || tickPlayOn);\n\tif (sel == @selector(exportOutput:))\n\t\treturn !(continuousPlayOn || tickPlayOn);\n\t\n\tif (sel == @selector(clearOutput:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(dumpPopulationToOutput:))\n\t\treturn !(invalidSimulation);\n\tif (sel == @selector(changeWorkingDirectory:))\n\t\treturn !(invalidSimulation);\n\t\n\tif (sel == @selector(toggleConsoleVisibility:))\n\t\treturn [_consoleController validateMenuItem:menuItem];\n\tif (sel == @selector(toggleBrowserVisibility:))\n\t\treturn [_consoleController validateMenuItem:menuItem];\n\t\n\treturn YES;\n}\n\n- (void)updateRecycleHighlightForChangeCount:(int)changeCount\n{\n\tif (changeCount)\n\t\t[recycleButton slimSetTintColor:[NSColor colorWithCalibratedHue:0.33 saturation:0.4 brightness:1.0 alpha:1.0]];\n\telse\n\t\t[recycleButton slimSetTintColor:nil];\n}\n\n\n//\n//\tActions\n//\n#pragma mark -\n#pragma mark Actions\n\n- (IBAction)speciesBarChanged:(id)sender\n{\n\t// We don't want to react to automatic tab changes as we are adding or removing tabs from the species bar\n\tif (reloadingSpeciesBar)\n\t\treturn;\n\t\n\tint speciesIndex = (int)[speciesBar selectedSegment];\n\tconst std::vector<Species *> &allSpecies = community->AllSpecies();\n\t\n\tif ((speciesIndex < 0) || (speciesIndex >= (int)allSpecies.size()))\n\t{\n\t\t//qDebug() << \"selectedSpeciesChanged() index\" << speciesIndex << \"out of range\";\n\t\treturn;\n\t}\n\t\n\tfocalSpecies = allSpecies[speciesIndex];\n\tfocalSpeciesName = focalSpecies->name_;\n\t\n\t//qDebug() << \"selectedSpeciesChanged(): changed to species name\" << QString::fromStdString(focalSpeciesName);\n\t\n\t// do a full update to show the state for the new species\n\t[self updateAfterTickFull:YES];\n}\n\n- (void)positionNewGraphWindow:(NSWindow *)window\n{\n\tNSRect windowFrame = [window frame];\n\tNSRect mainWindowFrame = [[self window] frame];\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n\tBOOL drawerIsOpen = ([drawer state] == NSDrawerOpenState);\n#pragma GCC diagnostic pop\n\tint oldOpenedGraphCount = openedGraphCount++;\n\t\n\t// try along the bottom first\n\t{\n\t\tNSRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.origin.x = mainWindowFrame.origin.x + oldOpenedGraphCount * (windowFrame.size.width + 5);\n\t\tcandidateFrame.origin.y = mainWindowFrame.origin.y - (candidateFrame.size.height + 5);\n\t\t\n\t\tif ([NSScreen visibleCandidateWindowFrame:candidateFrame])\n\t\t{\n\t\t\t[window setFrameOrigin:candidateFrame.origin];\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// try on the left side\n\t{\n\t\tNSRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.origin.x = mainWindowFrame.origin.x - (candidateFrame.size.width + 5);\n\t\tcandidateFrame.origin.y = (mainWindowFrame.origin.y + mainWindowFrame.size.height - candidateFrame.size.height) - oldOpenedGraphCount * (windowFrame.size.height + 5);\n\t\t\n\t\tif ([NSScreen visibleCandidateWindowFrame:candidateFrame])\n\t\t{\n\t\t\t[window setFrameOrigin:candidateFrame.origin];\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// unless the drawer is open, let's try on the right side\n\tif (!drawerIsOpen)\n\t{\n\t\tNSRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.origin.x = mainWindowFrame.origin.x + mainWindowFrame.size.width + 5;\n\t\tcandidateFrame.origin.y = (mainWindowFrame.origin.y + mainWindowFrame.size.height - candidateFrame.size.height) - oldOpenedGraphCount * (windowFrame.size.height + 5);\n\t\t\n\t\tif ([NSScreen visibleCandidateWindowFrame:candidateFrame])\n\t\t{\n\t\t\t[window setFrameOrigin:candidateFrame.origin];\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// try along the top\n\t{\n\t\tNSRect candidateFrame = windowFrame;\n\t\t\n\t\tcandidateFrame.origin.x = mainWindowFrame.origin.x + oldOpenedGraphCount * (windowFrame.size.width + 5);\n\t\tcandidateFrame.origin.y = mainWindowFrame.origin.y + mainWindowFrame.size.height + 5;\n\t\t\n\t\tif ([NSScreen visibleCandidateWindowFrame:candidateFrame])\n\t\t{\n\t\t\t[window setFrameOrigin:candidateFrame.origin];\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// if none of those worked, we just leave the window where it got placed out of the nib\n}\n\n- (NSWindow *)graphWindowWithTitle:(NSString *)windowTitle viewClass:(Class)viewClass\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[[NSBundle mainBundle] loadNibNamed:@\"GraphWindow\" owner:self topLevelObjects:NULL];\n\t\n\t// Set the graph window title\n\t[graphWindow setTitle:windowTitle];\n\t\n\t// We substitute in a GraphView subclass here, in place in place of the contentView\n\tNSView *oldContentView = [graphWindow contentView];\n\tNSRect contentRect = [oldContentView frame];\n\tGraphView *graphView = [[viewClass alloc] initWithFrame:contentRect withController:self];\n\t\n\t[graphWindow setContentView:graphView];\n\t[graphView release];\n\t\n\t// Position the graph window prior to showing it\n\t[self positionNewGraphWindow:graphWindow];\n\t\n\t// We use one nib for all graph types, so we transfer the outlet to a separate ivar\n\tNSWindow *returnWindow = graphWindow;\n\t\n\tgraphWindow = nil;\n\treturn returnWindow;\n}\n\n- (IBAction)graphMutationFrequencySpectrum:(id)sender\n{\n\tif (!graphWindowMutationFreqSpectrum)\n\t\tgraphWindowMutationFreqSpectrum = [[self graphWindowWithTitle:@\"Mutation Frequency Spectrum\" viewClass:[GraphView_MutationFrequencySpectra class]] retain];\n\t\n\t[graphWindowMutationFreqSpectrum orderFront:nil];\n}\n\n- (IBAction)graphMutationFrequencyTrajectories:(id)sender\n{\n\tif (!graphWindowMutationFreqTrajectories)\n\t\tgraphWindowMutationFreqTrajectories = [[self graphWindowWithTitle:@\"Mutation Frequency Trajectories\" viewClass:[GraphView_MutationFrequencyTrajectory class]] retain];\n\t\n\t[graphWindowMutationFreqTrajectories orderFront:nil];\n}\n\n- (IBAction)graphMutationLossTimeHistogram:(id)sender\n{\n\tif (!graphWindowMutationLossTimeHistogram)\n\t\tgraphWindowMutationLossTimeHistogram = [[self graphWindowWithTitle:@\"Mutation Loss Time\" viewClass:[GraphView_MutationLossTimeHistogram class]] retain];\n\t\n\t[graphWindowMutationLossTimeHistogram orderFront:nil];\n}\n\n- (IBAction)graphMutationFixationTimeHistogram:(id)sender\n{\n\tif (!graphWindowMutationFixationTimeHistogram)\n\t\tgraphWindowMutationFixationTimeHistogram = [[self graphWindowWithTitle:@\"Mutation Fixation Time\" viewClass:[GraphView_MutationFixationTimeHistogram class]] retain];\n\t\n\t[graphWindowMutationFixationTimeHistogram orderFront:nil];\n}\n\n- (IBAction)graphFitnessOverTime:(id)sender\n{\n\tif (!graphWindowFitnessOverTime)\n\t\tgraphWindowFitnessOverTime = [[self graphWindowWithTitle:@\"Fitness ~ Time\" viewClass:[GraphView_FitnessOverTime class]] retain];\n\t\n\t[graphWindowFitnessOverTime orderFront:nil];\n}\n\n- (IBAction)graphPopulationVisualization:(id)sender\n{\n\tif (!graphWindowPopulationVisualization)\n\t\tgraphWindowPopulationVisualization = [[self graphWindowWithTitle:@\"Population Visualization\" viewClass:[GraphView_PopulationVisualization class]] retain];\n\t\n\t[graphWindowPopulationVisualization orderFront:nil];\n}\n\n#if (SLIMPROFILING == 1)\n\n- (void)displayProfileResults\n{\n\t[[NSBundle mainBundle] loadNibNamed:@\"ProfileReport\" owner:self topLevelObjects:NULL];\n\t\n\t// Set up the report window attributes\n\t[profileWindow setTitle:[NSString stringWithFormat:@\"Profile Report for %@\", [[self window] title]]];\n\t[profileTextView setTextContainerInset:NSMakeSize(5.0, 10.0)];\n\t\n\t// Build the report attributed string\n\tNSMutableAttributedString *content = [[[NSMutableAttributedString alloc] init] autorelease];\n\tNSFont *optima18b = [NSFont fontWithName:@\"Optima-Bold\" size:18.0];\n\tNSFont *optima14b = [NSFont fontWithName:@\"Optima-Bold\" size:14.0];\n\tNSFont *optima13 = [NSFont fontWithName:@\"Optima\" size:13.0];\n\tNSFont *optima13i = [NSFont fontWithName:@\"Optima-Italic\" size:13.0];\n\tNSFont *optima8 = [NSFont fontWithName:@\"Optima\" size:8.0];\n\tNSFont *optima3 = [NSFont fontWithName:@\"Optima\" size:3.0];\n\tNSFont *menlo11 = [NSFont fontWithName:@\"Menlo\" size:11.0];\n\t\n\tNSDictionary *optima14b_d = @{NSFontAttributeName : optima14b};\n\tNSDictionary *optima13_d = @{NSFontAttributeName : optima13};\n\tNSDictionary *optima13i_d = @{NSFontAttributeName : optima13i};\n\tNSDictionary *optima8_d = @{NSFontAttributeName : optima8};\n\tNSDictionary *optima3_d = @{NSFontAttributeName : optima3};\n\tNSDictionary *menlo11_d = @{NSFontAttributeName : menlo11};\n\t\n\tNSDate *profileStartDate = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)community->profile_start_date];\n\tNSDate *profileEndDate = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)community->profile_end_date];\n\t\n\tNSString *startDateString = [NSDateFormatter localizedStringFromDate:profileStartDate dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterMediumStyle];\n\tNSString *endDateString = [NSDateFormatter localizedStringFromDate:profileEndDate dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterMediumStyle];\n\tdouble elapsedWallClockTime = (std::chrono::duration_cast<std::chrono::microseconds>(community->profile_end_clock - community->profile_start_clock).count()) / (double)1000000L;\n\tdouble elapsedCPUTimeInSLiM = community->profile_elapsed_CPU_clock / (double)CLOCKS_PER_SEC;\n\tdouble elapsedWallClockTimeInSLiM = Eidos_ElapsedProfileTime(community->profile_elapsed_wall_clock);\n\tslim_tick_t elapsedSLiMTicks = community->profile_end_tick - community->profile_start_tick;\n\t\n\t[content eidosAppendString:@\"Profile Report\\n\" attributes:@{NSFontAttributeName : optima18b}];\n\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Model: %@\\n\", [[self window] title]] attributes:optima13_d];\n\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Run start: %@\\n\", startDateString] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Run end: %@\\n\", endDateString] attributes:optima13_d];\n\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\n#ifdef _OPENMP\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Maximum parallel threads: %d\\n\", gEidosMaxThreads] attributes:optima13_d];\n\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n#endif\n\t\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Elapsed wall clock time: %0.2f s\\n\", (double)elapsedWallClockTime] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Elapsed wall clock time inside SLiM core (corrected): %0.2f s\\n\", (double)elapsedWallClockTimeInSLiM] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Elapsed CPU time inside SLiM core (uncorrected): %0.2f s\\n\", (double)elapsedCPUTimeInSLiM] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Elapsed ticks: %d%@\\n\", (int)elapsedSLiMTicks, (community->profile_start_tick == 0) ? @\" (including initialize)\" : @\"\"] attributes:optima13_d];\n\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Profile block external overhead: %0.2f ticks (%0.4g s)\\n\", gEidos_ProfileOverheadTicks, gEidos_ProfileOverheadSeconds] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Profile block internal lag: %0.2f ticks (%0.4g s)\\n\", gEidos_ProfileLagTicks, gEidos_ProfileLagSeconds] attributes:optima13_d];\n\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\n\tsize_t total_usage = community->profile_total_memory_usage_Community.totalMemoryUsage + community->profile_total_memory_usage_AllSpecies.totalMemoryUsage;\n\tsize_t average_usage = total_usage / community->total_memory_tallies_;\n\tsize_t last_usage = community->profile_last_memory_usage_Community.totalMemoryUsage + community->profile_last_memory_usage_AllSpecies.totalMemoryUsage;\n\t\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Average tick SLiM memory use: %@\\n\", [NSString stringForByteCount:average_usage]] attributes:optima13_d];\n\t[content eidosAppendString:[NSString stringWithFormat:@\"Final tick SLiM memory use: %@\\n\", [NSString stringForByteCount:last_usage]] attributes:optima13_d];\n\t\n\t\n\t//\n\t//\tCycle stage breakdown\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tbool isWF = (community->ModelType() == SLiMModelType::kModelTypeWF);\n\t\tdouble elapsedStage0Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[0]);\n\t\tdouble elapsedStage1Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[1]);\n\t\tdouble elapsedStage2Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[2]);\n\t\tdouble elapsedStage3Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[3]);\n\t\tdouble elapsedStage4Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[4]);\n\t\tdouble elapsedStage5Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[5]);\n\t\tdouble elapsedStage6Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[6]);\n\t\tdouble elapsedStage7Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[7]);\n\t\tdouble elapsedStage8Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[8]);\n\t\tdouble percentStage0 = (elapsedStage0Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage1 = (elapsedStage1Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage2 = (elapsedStage2Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage3 = (elapsedStage3Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage4 = (elapsedStage4Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage5 = (elapsedStage5Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage6 = (elapsedStage6Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage7 = (elapsedStage7Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage8 = (elapsedStage8Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage0Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage1Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage2Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage3Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage4Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage5Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage6Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage7Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage8Time));\n\t\t\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t[content eidosAppendString:@\"Cycle stage breakdown\\n\" attributes:optima14b_d];\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage0Time, percentStage0] attributes:menlo11_d];\n\t\t[content eidosAppendString:@\" : initialize() callback execution\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage1Time, percentStage1] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 0 – first() event execution\\n\" : @\" : stage 0 – first() event execution\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage2Time, percentStage2] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 1 – early() event execution\\n\" : @\" : stage 1 – offspring generation\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage3Time, percentStage3] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 2 – offspring generation\\n\" : @\" : stage 2 – early() event execution\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage4Time, percentStage4] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 3 – generation swap\\n\" : @\" : stage 3 – fitness calculation\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage5Time, percentStage5] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 4 – bookkeeping (fixed mutation removal, etc.)\\n\" : @\" : stage 4 – viability/survival selection\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage6Time, percentStage6] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 5 – late() event execution\\n\" : @\" : stage 5 – bookkeeping (fixed mutation removal, etc.)\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage7Time, percentStage7] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 6 – fitness calculation\\n\" : @\" : stage 6 – late() event execution\\n\") attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%5.2f%%)\", fw, elapsedStage8Time, percentStage8] attributes:menlo11_d];\n\t\t[content eidosAppendString:(isWF ? @\" : stage 7 – tree sequence auto-simplification\\n\" : @\" : stage 7 – tree sequence auto-simplification\\n\") attributes:optima13_d];\n\t}\n\t\n\t//\n\t//\tCallback type breakdown\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tdouble elapsedTime_first = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventFirst]);\n\t\tdouble elapsedTime_early = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventEarly]);\n\t\tdouble elapsedTime_late = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventLate]);\n\t\tdouble elapsedTime_initialize = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInitializeCallback]);\n\t\tdouble elapsedTime_mutationEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationEffectCallback]);\n\t\tdouble elapsedTime_fitnessEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosFitnessEffectCallback]);\n\t\tdouble elapsedTime_interaction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInteractionCallback]);\n\t\tdouble elapsedTime_matechoice = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMateChoiceCallback]);\n\t\tdouble elapsedTime_modifychild = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosModifyChildCallback]);\n\t\tdouble elapsedTime_recombination = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosRecombinationCallback]);\n\t\tdouble elapsedTime_mutation = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationCallback]);\n\t\tdouble elapsedTime_reproduction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosReproductionCallback]);\n\t\tdouble elapsedTime_survival = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosSurvivalCallback]);\n\t\tdouble percent_first = (elapsedTime_first / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_early = (elapsedTime_early / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_late = (elapsedTime_late / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_initialize = (elapsedTime_initialize / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitness = (elapsedTime_mutationEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitnessglobal = (elapsedTime_fitnessEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_interaction = (elapsedTime_interaction / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_matechoice = (elapsedTime_matechoice / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_modifychild = (elapsedTime_modifychild / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_recombination = (elapsedTime_recombination / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_mutation = (elapsedTime_mutation / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_reproduction = (elapsedTime_reproduction / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_survival = (elapsedTime_survival / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4, fw2 = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_first));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_early));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_late));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_initialize));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutationEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_fitnessEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_interaction));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_matechoice));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_modifychild));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_recombination));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutation));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_reproduction));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_survival));\n\t\t\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_first));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_early));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_late));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_initialize));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitness));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitnessglobal));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_interaction));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_matechoice));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_modifychild));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_recombination));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_mutation));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_reproduction));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_survival));\n\t\t\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t[content eidosAppendString:@\"Callback type breakdown\\n\" attributes:optima14b_d];\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\n\t\t// Note these are out of numeric order, but in cycle stage order\n\t\tif (community->ModelType() == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_initialize, fw2, percent_initialize] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : initialize() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_first, fw2, percent_first] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : first() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_early, fw2, percent_early] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : early() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_matechoice, fw2, percent_matechoice] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : mateChoice() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_recombination, fw2, percent_recombination] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : recombination() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_mutation, fw2, percent_mutation] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : mutation() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_modifychild, fw2, percent_modifychild] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : modifyChild() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_late, fw2, percent_late] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : late() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_mutationEffect, fw2, percent_fitness] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : mutationEffect() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_fitnessEffect, fw2, percent_fitnessglobal] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : fitnessEffect() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_interaction, fw2, percent_interaction] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : interaction() callbacks\\n\" attributes:optima13_d];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_initialize, fw2, percent_initialize] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : initialize() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_first, fw2, percent_first] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : first() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_reproduction, fw2, percent_reproduction] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : reproduction() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_recombination, fw2, percent_recombination] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : recombination() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_mutation, fw2, percent_mutation] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : mutation() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_modifychild, fw2, percent_modifychild] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : modifyChild() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_early, fw2, percent_early] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : early() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_mutationEffect, fw2, percent_fitness] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : mutationEffect() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_fitnessEffect, fw2, percent_fitnessglobal] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : fitnessEffect() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_survival, fw2, percent_survival] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : survival() callbacks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_late, fw2, percent_late] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : late() events\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%*.2f s (%*.2f%%)\", fw, elapsedTime_interaction, fw2, percent_interaction] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" : interaction() callbacks\\n\" attributes:optima13_d];\n\t\t}\n\t}\n\t\n\t//\n\t//\tScript block profiles\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\t{\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\t\n\t\t\t// Convert the profile counts in all script blocks into self counts (excluding the counts of nodes below them)\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t\tif (script_block->type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\t\t// exclude function blocks; not user-visible\n\t\t\t\t\tscript_block->root_node_->ConvertProfileTotalsToSelfCounts();\n\t\t}\n\t\t{\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t\t[content eidosAppendString:@\"Script block profiles (as a fraction of corrected wall clock time)\\n\" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\t[content eidosAppendString:@\"\\n\\n\" attributes:menlo11_d];\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tNSString *script_string = [NSString stringWithUTF8String:script_std_string.c_str()];\n\t\t\t\t\tNSMutableAttributedString *scriptAttrString = [[NSMutableAttributedString alloc] initWithString:script_string attributes:menlo11_d];\n\t\t\t\t\t\n\t\t\t\t\t[self colorScript:scriptAttrString withProfileCountsFromNode:profile_root elapsedTime:elapsedWallClockTimeInSLiM baseIndex:profile_root->token_->token_UTF16_start_];\n\t\t\t\t\t\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%0.2f s (%0.2f%%):\\n\", total_block_time, percent_block_time] attributes:menlo11_d];\n\t\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t\t\n\t\t\t\t\t[content appendAttributedString:scriptAttrString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = YES;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t[content eidosAppendString:@\"(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\" attributes:optima13i_d];\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t\t[content eidosAppendString:@\"Script block profiles (as a fraction of within-block wall clock time)\\n\" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\t[content eidosAppendString:@\"\\n\\n\" attributes:menlo11_d];\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tNSString *script_string = [NSString stringWithUTF8String:script_std_string.c_str()];\n\t\t\t\t\tNSMutableAttributedString *scriptAttrString = [[NSMutableAttributedString alloc] initWithString:script_string attributes:menlo11_d];\n\t\t\t\t\t\n\t\t\t\t\tif (total_block_time > 0.0)\n\t\t\t\t\t\t[self colorScript:scriptAttrString withProfileCountsFromNode:profile_root elapsedTime:total_block_time baseIndex:profile_root->token_->token_UTF16_start_];\n\t\t\t\t\t\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%0.2f s (%0.2f%%):\\n\", total_block_time, percent_block_time] attributes:menlo11_d];\n\t\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t\t\n\t\t\t\t\t[content appendAttributedString:scriptAttrString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = YES;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t[content eidosAppendString:@\"(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\" attributes:optima13i_d];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//\n\t//\tUser-defined functions (if any)\n\t//\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tEidosFunctionMap &function_map = community->FunctionMap();\n\t\tstd::vector<const EidosFunctionSignature *> userDefinedFunctions;\n\t\t\n\t\tfor (auto functionPairIter = function_map.begin(); functionPairIter != function_map.end(); ++functionPairIter)\n\t\t{\n\t\t\tconst EidosFunctionSignature *signature = functionPairIter->second.get();\n\t\t\t\n\t\t\tif (signature->body_script_ && signature->user_defined_)\n\t\t\t{\n\t\t\t\tsignature->body_script_->AST()->ConvertProfileTotalsToSelfCounts();\n\t\t\t\tuserDefinedFunctions.emplace_back(signature);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t\t[content eidosAppendString:@\"User-defined functions (as a fraction of corrected wall clock time)\\n\" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\t[content eidosAppendString:@\"\\n\\n\" attributes:menlo11_d];\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tNSString *script_string = [NSString stringWithUTF8String:script_std_string.c_str()];\n\t\t\t\t\tNSMutableAttributedString *scriptAttrString = [[NSMutableAttributedString alloc] initWithString:script_string attributes:menlo11_d];\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\tNSString *signatureString = [NSString stringWithUTF8String:signature_string.c_str()];\n\t\t\t\t\t\n\t\t\t\t\t[self colorScript:scriptAttrString withProfileCountsFromNode:profile_root elapsedTime:elapsedWallClockTimeInSLiM baseIndex:profile_root->token_->token_UTF16_start_];\n\t\t\t\t\t\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%0.2f s (%0.2f%%):\\n\", total_block_time, percent_block_time] attributes:menlo11_d];\n\t\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%@\\n\", signatureString] attributes:menlo11_d];\n\t\t\t\t\t\n\t\t\t\t\t[content appendAttributedString:scriptAttrString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = YES;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t[content eidosAppendString:@\"(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\" attributes:optima13i_d];\n\t\t\t}\n\t\t}\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t\t[content eidosAppendString:@\"User-defined functions (as a fraction of within-block wall clock time)\\n\" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\n\t\t\tbool firstBlock = true, hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tif (!firstBlock)\n\t\t\t\t\t\t[content eidosAppendString:@\"\\n\\n\" attributes:menlo11_d];\n\t\t\t\t\tfirstBlock = false;\n\t\t\t\t\t\n\t\t\t\t\tconst std::string &script_std_string = profile_root->token_->token_string_;\n\t\t\t\t\tNSString *script_string = [NSString stringWithUTF8String:script_std_string.c_str()];\n\t\t\t\t\tNSMutableAttributedString *scriptAttrString = [[NSMutableAttributedString alloc] initWithString:script_string attributes:menlo11_d];\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\tNSString *signatureString = [NSString stringWithUTF8String:signature_string.c_str()];\n\t\t\t\t\t\n\t\t\t\t\tif (total_block_time > 0.0)\n\t\t\t\t\t\t[self colorScript:scriptAttrString withProfileCountsFromNode:profile_root elapsedTime:total_block_time baseIndex:profile_root->token_->token_UTF16_start_];\n\t\t\t\t\t\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%0.2f s (%0.2f%%):\\n\", total_block_time, percent_block_time] attributes:menlo11_d];\n\t\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%@\\n\", signatureString] attributes:menlo11_d];\n\t\t\t\t\t\n\t\t\t\t\t[content appendAttributedString:scriptAttrString];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = YES;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t{\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\t[content eidosAppendString:@\"(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\" attributes:optima13i_d];\n\t\t\t}\n\t\t}\n\t}\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t//\n\t//\tMutationRun metrics, presented per Species\n\t//\n\tfor (Species *focal_species : community->all_species_)\n\t{\n\t\t[content eidosAppendString:@\"\\n\" attributes:menlo11_d];\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t[content eidosAppendString:@\"MutationRun usage\" attributes:optima14b_d];\n\t\tif (community->all_species_.size() > 1)\n\t\t{\n\t\t\t[content eidosAppendString:@\" (\" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:[NSString stringWithUTF8String:focal_species->avatar_.c_str()] attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\" \" attributes:optima14b_d];\n\t\t\t[content eidosAppendString:[NSString stringWithUTF8String:focal_species->name_.c_str()] attributes:optima14b_d];\n\t\t\t[content eidosAppendString:@\")\" attributes:optima14b_d];\n\t\t}\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima14b_d];\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\n\t\tif (!focal_species->HasGenetics())\n\t\t{\n\t\t\t[content eidosAppendString:@\"(omitted for no-genetics species)\" attributes:optima13i_d];\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t{\n\t\t\tint64_t regime_tallies[3];\n\t\t\tint64_t regime_tallies_total = (int)focal_species->profile_nonneutral_regime_history_.size();\n\t\t\t\n\t\t\tfor (int regime = 0; regime < 3; ++regime)\n\t\t\t\tregime_tallies[regime] = 0;\n\t\t\t\n\t\t\tfor (int32_t regime : focal_species->profile_nonneutral_regime_history_)\n\t\t\t\tif ((regime >= 1) && (regime <= 3))\n\t\t\t\t\tregime_tallies[regime - 1]++;\n\t\t\t\telse\n\t\t\t\t\tregime_tallies_total--;\n\t\t\t\n\t\t\tfor (int regime = 0; regime < 3; ++regime)\n\t\t\t{\n\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%6.2f%%\", (regime_tallies[regime] / (double)regime_tallies_total) * 100.0] attributes:menlo11_d];\n\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\" of ticks : regime %d (%@)\\n\", regime + 1, (regime == 0 ? @\"no mutationEffect() callbacks\" : (regime == 1 ? @\"constant neutral mutationEffect() callbacks only\" : @\"unpredictable mutationEffect() callbacks present\"))] attributes:optima13_d];\n\t\t\t}\n\t\t\t\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t}\n\t\t\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%lld\", (long long int)focal_species->profile_max_mutation_index_] attributes:menlo11_d];\n\t\t[content eidosAppendString:@\" maximum simultaneous mutations\\n\" attributes:optima13_d];\n\t\t\n\t\t\n\t\tconst std::vector<Chromosome *> &chromosomes = focal_species->Chromosomes();\n\t\t\n\t\tfor (Chromosome *focal_chromosome : chromosomes)\n\t\t{\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t\t[content eidosAppendString:@\"Chromosome \" attributes:optima13i_d];\n\t\t\t[content eidosAppendString:[NSString stringWithUTF8String:focal_chromosome->Symbol().c_str()] attributes:optima13i_d];\n\t\t\t[content eidosAppendString:@\":\\n\" attributes:optima13i_d];\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\t\n\t\t\t{\n\t\t\t\tint64_t power_tallies[20];\t// we only go up to 1024 mutruns right now, but this gives us some headroom\n\t\t\t\tint64_t power_tallies_total = (int)focal_chromosome->profile_mutcount_history_.size();\n\t\t\t\t\n\t\t\t\tfor (int power = 0; power < 20; ++power)\n\t\t\t\t\tpower_tallies[power] = 0;\n\t\t\t\t\n\t\t\t\tfor (int32_t count : focal_chromosome->profile_mutcount_history_)\n\t\t\t\t{\n\t\t\t\t\tint power = (int)round(log2(count));\n\t\t\t\t\t\n\t\t\t\t\tpower_tallies[power]++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int power = 0; power < 20; ++power)\n\t\t\t\t{\n\t\t\t\t\tif (power_tallies[power] > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%6.2f%%\", (power_tallies[power] / (double)power_tallies_total) * 100.0] attributes:menlo11_d];\n\t\t\t\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\" of ticks : %d mutation runs per haplosome\\n\", (int)(round(pow(2.0, power)))] attributes:optima13_d];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%lld\", (long long int)focal_chromosome->profile_mutation_total_usage_] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" mutations referenced, summed across all ticks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%lld\", (long long int)focal_chromosome->profile_nonneutral_mutation_total_] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" mutations considered potentially nonneutral\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%0.2f%%\", ((focal_chromosome->profile_mutation_total_usage_ - focal_chromosome->profile_nonneutral_mutation_total_) / (double)focal_chromosome->profile_mutation_total_usage_) * 100.0] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" of mutations excluded from fitness calculations\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t\n\t\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%lld\", (long long int)focal_chromosome->profile_mutrun_total_usage_] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" mutation runs referenced, summed across all ticks\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%lld\", (long long int)focal_chromosome->profile_unique_mutrun_total_] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" unique mutation runs maintained among those\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%6.2f%%\", (focal_chromosome->profile_mutrun_nonneutral_recache_total_ / (double)focal_chromosome->profile_unique_mutrun_total_) * 100.0] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" of mutation run nonneutral caches rebuilt per tick\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:[NSString stringWithFormat:@\"%6.2f%%\", ((focal_chromosome->profile_mutrun_total_usage_ - focal_chromosome->profile_unique_mutrun_total_) / (double)focal_chromosome->profile_mutrun_total_usage_) * 100.0] attributes:menlo11_d];\n\t\t\t[content eidosAppendString:@\" of mutation runs shared among haplosomes\\n\" attributes:optima13_d];\n\t\t}\n\t}\n#endif\n\t\n\t{\n\t\t//\n\t\t//\tMemory usage metrics\n\t\t//\n\t\tSLiMMemoryUsage_Community &mem_tot_C = community->profile_total_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_tot_S = community->profile_total_memory_usage_AllSpecies;\n\t\tSLiMMemoryUsage_Community &mem_last_C = community->profile_last_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_last_S = community->profile_last_memory_usage_AllSpecies;\n\t\tint64_t div = community->total_memory_tallies_;\n\t\tdouble ddiv = community->total_memory_tallies_;\n\t\tdouble average_total = (mem_tot_C.totalMemoryUsage + mem_tot_S.totalMemoryUsage) / ddiv;\n\t\tdouble final_total = mem_last_C.totalMemoryUsage + mem_last_S.totalMemoryUsage;\n\t\t\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima13_d];\n\t\t[content eidosAppendString:@\"SLiM memory usage (average / final tick)\\n\" attributes:optima14b_d];\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima3_d];\n\t\t\n\t\t// Chromosome\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.chromosomeObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.chromosomeObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Chromosome objects (%0.2f / %lld)\\n\", mem_tot_S.chromosomeObjects_count / ddiv, (long long int)mem_last_S.chromosomeObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.chromosomeMutationRateMaps / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.chromosomeMutationRateMaps total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : mutation rate maps\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.chromosomeRecombinationRateMaps / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.chromosomeRecombinationRateMaps total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : recombination rate maps\\n\" attributes:optima13_d];\n\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.chromosomeAncestralSequence / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.chromosomeAncestralSequence total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : ancestral nucleotides\\n\" attributes:optima13_d];\n\t\t\n\t\t// Community\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.communityObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.communityObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : Community object\\n\" attributes:optima13_d];\n\t\t\n\t\t// Haplosome\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.haplosomeObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.haplosomeObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Haplosome objects (%0.2f / %lld)\\n\", mem_tot_S.haplosomeObjects_count / ddiv, (long long int)mem_last_S.haplosomeObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.haplosomeExternalBuffers / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.haplosomeExternalBuffers total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : external MutationRun* buffers\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.haplosomeUnusedPoolSpace / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.haplosomeUnusedPoolSpace total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool space\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.haplosomeUnusedPoolBuffers / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.haplosomeUnusedPoolBuffers total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool buffers\\n\" attributes:optima13_d];\n\t\t\n\t\t// GenomicElement\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.genomicElementObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.genomicElementObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : GenomicElement objects (%0.2f / %lld)\\n\", mem_tot_S.genomicElementObjects_count / ddiv, (long long int)mem_last_S.genomicElementObjects_count] attributes:optima13_d];\n\t\t\n\t\t// GenomicElementType\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.genomicElementTypeObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.genomicElementTypeObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : GenomicElementType objects (%0.2f / %lld)\\n\", mem_tot_S.genomicElementTypeObjects_count / ddiv, (long long int)mem_last_S.genomicElementTypeObjects_count] attributes:optima13_d];\n\t\t\n\t\t// Individual\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.individualObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.individualObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Individual objects (%0.2f / %lld)\\n\", mem_tot_S.individualObjects_count / ddiv, (long long int)mem_last_S.individualObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.individualHaplosomeVectors / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.individualHaplosomeVectors total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : external Haplosome* buffers\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.individualJunkyardAndHaplosomes / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.individualJunkyardAndHaplosomes total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : individuals awaiting reuse\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.individualUnusedPoolSpace / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.individualUnusedPoolSpace total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool space\\n\" attributes:optima13_d];\n\t\t\n\t\t// InteractionType\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.interactionTypeObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.interactionTypeObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : InteractionType objects (%0.2f / %lld)\\n\", mem_tot_C.interactionTypeObjects_count / ddiv, (long long int)mem_last_C.interactionTypeObjects_count] attributes:optima13_d];\n\t\t\n\t\tif (mem_tot_C.interactionTypeObjects_count || mem_last_C.interactionTypeObjects_count)\n\t\t{\n\t\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.interactionTypeKDTrees / div total:average_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.interactionTypeKDTrees total:final_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" : k-d trees\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.interactionTypePositionCaches / div total:average_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.interactionTypePositionCaches total:final_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" : position caches\\n\" attributes:optima13_d];\n\t\t\t\n\t\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.interactionTypeSparseVectorPool / div total:average_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.interactionTypeSparseVectorPool total:final_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" : sparse arrays\\n\" attributes:optima13_d];\n\t\t}\n\t\t\n\t\t// Mutation\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Mutation objects (%0.2f / %lld)\\n\", mem_tot_S.mutationObjects_count / ddiv, (long long int)mem_last_S.mutationObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.mutationRefcountBuffer / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.mutationRefcountBuffer total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : refcount buffer\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.mutationUnusedPoolSpace / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.mutationUnusedPoolSpace total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool space\\n\" attributes:optima13_d];\n\t\t\n\t\t// MutationRun\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationRunObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationRunObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : MutationRun objects (%0.2f / %lld)\\n\", mem_tot_S.mutationRunObjects_count / ddiv, (long long int)mem_last_S.mutationRunObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationRunExternalBuffers / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationRunExternalBuffers total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : external MutationIndex buffers\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationRunNonneutralCaches / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationRunNonneutralCaches total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : nonneutral mutation caches\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationRunUnusedPoolSpace / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationRunUnusedPoolSpace total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool space\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationRunUnusedPoolBuffers / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationRunUnusedPoolBuffers total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : unused pool buffers\\n\" attributes:optima13_d];\n\t\t\n\t\t// MutationType\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.mutationTypeObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.mutationTypeObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : MutationType objects (%0.2f / %lld)\\n\", mem_tot_S.mutationTypeObjects_count / ddiv, (long long int)mem_last_S.mutationTypeObjects_count] attributes:optima13_d];\n\t\t\n\t\t// Species\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.speciesObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.speciesObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Species objects (%0.2f / %lld)\\n\", mem_tot_S.speciesObjects_count / ddiv, (long long int)mem_last_S.speciesObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.speciesTreeSeqTables / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.speciesTreeSeqTables total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : tree-sequence tables\\n\" attributes:optima13_d];\n\t\t\n\t\t// Subpopulation\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.subpopulationObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.subpopulationObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Subpopulation objects (%0.2f / %lld)\\n\", mem_tot_S.subpopulationObjects_count / ddiv, (long long int)mem_last_S.subpopulationObjects_count] attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.subpopulationFitnessCaches / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.subpopulationFitnessCaches total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : fitness caches\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.subpopulationParentTables / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.subpopulationParentTables total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : parent tables\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.subpopulationSpatialMaps / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.subpopulationSpatialMaps total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : spatial maps\\n\" attributes:optima13_d];\n\t\t\n\t\tif (mem_tot_S.subpopulationSpatialMapsDisplay || mem_last_S.subpopulationSpatialMapsDisplay)\n\t\t{\n\t\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.subpopulationSpatialMapsDisplay / div total:average_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.subpopulationSpatialMapsDisplay total:final_total attributes:menlo11_d]];\n\t\t\t[content eidosAppendString:@\" : spatial map display (SLiMgui only)\\n\" attributes:optima13_d];\n\t\t}\n\t\t\n\t\t// Substitution\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_S.substitutionObjects / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_S.substitutionObjects total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:[NSString stringWithFormat:@\" : Substitution objects (%0.2f / %lld)\\n\", mem_tot_S.substitutionObjects_count / ddiv, (long long int)mem_last_S.substitutionObjects_count] attributes:optima13_d];\n\t\t\n\t\t// Eidos\n\t\t[content eidosAppendString:@\"\\n\" attributes:optima8_d];\n\t\t[content eidosAppendString:@\"Eidos:\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.eidosASTNodePool / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.eidosASTNodePool total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : EidosASTNode pool\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.eidosSymbolTablePool / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.eidosSymbolTablePool total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : EidosSymbolTable pool\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.eidosValuePool / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.eidosValuePool total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : EidosValue pool\\n\" attributes:optima13_d];\n\t\t\n\t\t[content eidosAppendString:@\"   \" attributes:menlo11_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_tot_C.fileBuffers / div total:average_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" / \" attributes:optima13_d];\n\t\t[content appendAttributedString:[NSAttributedString attributedStringForByteCount:mem_last_C.fileBuffers total:final_total attributes:menlo11_d]];\n\t\t[content eidosAppendString:@\" : File buffers\" attributes:optima13_d];\n\t}\n\t\n\t// Set the attributed string into the profile report text view\n\tNSTextStorage *ts = [profileTextView textStorage];\n\t\n\t[ts beginEditing];\n\t[ts setAttributedString:content];\n\t[ts endEditing];\n\t\n\t// Show the window and give it ownership over itself\n\t[profileWindow makeKeyAndOrderFront:nil];\n\t[profileWindow retain];\t\t\t\t// it is set to release itself when closed\n\t\n\t// We use one nib for all profile reports, so clear our outlet; the profile now lives as its own independent window\n\tprofileWindow = nil;\n\tprofileTextView = nil;\n}\n\n- (void)colorScript:(NSMutableAttributedString *)script withProfileCountsFromNode:(const EidosASTNode *)node elapsedTime:(double)elapsedTime baseIndex:(int32_t)baseIndex\n{\n\t// First color the range for this node\n\teidos_profile_t count = node->profile_total_;\n\t\n\tif (count > 0)\n\t{\n\t\tint32_t start = 0, end = 0;\n\t\t\n\t\tnode->FullUTF16Range(&start, &end);\n\t\t\n\t\tstart -= baseIndex;\n\t\tend -= baseIndex;\n\t\t\n\t\tNSRange range = NSMakeRange(start, end - start + 1);\n\t\t\n\t\tNSColor *backgroundColor = [NSColor slimColorForFraction:Eidos_ElapsedProfileTime(count) / elapsedTime];\n\t\t\n\t\t[script addAttribute:NSBackgroundColorAttributeName value:backgroundColor range:range];\n\t}\n\t\n\t// Then let child nodes color\n\tfor (const EidosASTNode *child : node->children_)\n\t\t[self colorScript:script withProfileCountsFromNode:child elapsedTime:elapsedTime baseIndex:baseIndex];\n}\n\n#endif\t// (SLIMPROFILING == 1)\n\n- (BOOL)runSimOneTick\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t// This method should always be used when calling out to run the simulation, because it swaps the correct random number\n\t// generator stuff in and out bracketing the call to RunOneTick().  This bracketing would need to be done around\n\t// any other call out to the simulation that caused it to use random numbers, too, such as subsample output.\n\tBOOL stillRunning = YES;\n\t\n\t[self eidosConsoleWindowControllerWillExecuteScript:_consoleController];\n\t\n#if (SLIMPROFILING == 1)\n\tif (profilePlayOn)\n\t{\n\t\t// We put the wall clock measurements on the inside since we want those to be maximally accurate,\n\t\t// as profile report percentages are fractions of the total elapsed wall clock time.\n\t\tstd::clock_t startCPUClock = std::clock();\n\t\tSLIM_PROFILE_BLOCK_START();\n\t\t\n\t\tstillRunning = community->RunOneTick();\n\t\t\n\t\tSLIM_PROFILE_BLOCK_END(community->profile_elapsed_wall_clock);\n\t\tstd::clock_t endCPUClock = std::clock();\n\t\t\n\t\tcommunity->profile_elapsed_CPU_clock += (endCPUClock - startCPUClock);\n\t}\n\telse\n#endif\n\t{\n\t\tstillRunning = community->RunOneTick();\n\t}\n\t\n\t[self eidosConsoleWindowControllerDidExecuteScript:_consoleController];\n\t\n\t// We also want to let graphViews know when each tick has finished, in case they need to pull data from the sim.  Note this\n\t// happens after every tick, not just when we are updating the UI, so drawing and setNeedsDisplay: should not happen here.\n\t[self sendAllLinkedViewsSelector:@selector(controllerTickFinished)];\n\t\n\treturn stillRunning;\n}\n\n- (IBAction)playOneStep:(id)sender\n{\n\tif (!invalidSimulation)\n\t{\n\t\t[_consoleController invalidateSymbolTableAndFunctionMap];\n\t\t[self setReachedSimulationEnd:![self runSimOneTick]];\n\t\t[_consoleController validateSymbolTableAndFunctionMap];\n\t\t[self updateAfterTickFull:YES];\n\t}\n}\n\n- (void)_continuousPlay:(id)sender\n{\n\t// NOTE this code is parallel to the code in _continuousProfile:\n\tif (!invalidSimulation)\n\t{\n\t\tNSDate *startDate = [NSDate date];\n\t\tdouble speedSliderValue = [playSpeedSlider doubleValue];\n\t\tdouble intervalSinceStarting = -[continuousPlayStartDate timeIntervalSinceNow];\n\t\t\n\t\t// Calculate frames per second; this equation must match the equation in playSpeedChanged:\n\t\tdouble maxTicksPerSecond = 1000000000.0;\t// bounded, to allow -eidos_pauseExecution to interrupt us\n\t\t\n\t\tif (speedSliderValue < 0.99999)\n\t\t\tmaxTicksPerSecond = (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * 839;\n\t\t\n\t\t//NSLog(@\"speedSliderValue == %f, maxTicksPerSecond == %f\", speedSliderValue, maxTicksPerSecond);\n\t\t\n\t\t// We keep a local version of reachedSimulationEnd, because calling setReachedSimulationEnd: every tick\n\t\t// can actually be a large drag for simulations that run extremely quickly – it can actually exceed the time\n\t\t// spent running the simulation itself!  Moral of the story, KVO is wicked slow.\n\t\tBOOL reachedEnd = reachedSimulationEnd;\n\t\t\n\t\tdo\n\t\t{\n\t\t\tif (continuousPlayTicksCompleted / intervalSinceStarting >= maxTicksPerSecond)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t@autoreleasepool {\n\t\t\t\treachedEnd = ![self runSimOneTick];\n\t\t\t}\n\t\t\t\n\t\t\tcontinuousPlayTicksCompleted++;\n\t\t}\n\t\twhile (!reachedEnd && (-[startDate timeIntervalSinceNow] < 0.02));\n\t\t\n\t\t[self setReachedSimulationEnd:reachedEnd];\n\t\t\n\t\tif (!reachedSimulationEnd)\n\t\t{\n\t\t\t[self updateAfterTickFull:(-[startDate timeIntervalSinceNow] > 0.04)];\t// if too much time has elapsed, do a full update\n\t\t\t[self performSelector:@selector(_continuousPlay:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// stop playing\n\t\t\t[self updateAfterTickFull:YES];\n\t\t\t[playButton setState:NSOffState];\n\t\t\t[self play:nil];\n\t\t\t\n\t\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t\t[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n}\n\n- (void)_continuousProfile:(id)sender\n{\n\t// NOTE this code is parallel to the code in _continuousPlay:\n\tif (!invalidSimulation)\n\t{\n\t\tNSDate *startDate = [NSDate date];\n\t\t\n\t\t// We keep a local version of reachedSimulationEnd, because calling setReachedSimulationEnd: every tick\n\t\t// can actually be a large drag for simulations that run extremely quickly – it can actually exceed the time\n\t\t// spent running the simulation itself!  Moral of the story, KVO is wicked slow.\n\t\tBOOL reachedEnd = reachedSimulationEnd;\n\t\t\n\t\tif (!reachedEnd)\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\t@autoreleasepool {\n\t\t\t\t\treachedEnd = ![self runSimOneTick];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcontinuousPlayTicksCompleted++;\n\t\t\t}\n\t\t\twhile (!reachedEnd && (-[startDate timeIntervalSinceNow] < 0.02));\n\t\t\t\n\t\t\t[self setReachedSimulationEnd:reachedEnd];\n\t\t}\n\t\t\n\t\tif (!reachedSimulationEnd)\n\t\t{\n\t\t\t[self updateAfterTickFull:(-[startDate timeIntervalSinceNow] > 0.04)];\t// if too much time has elapsed, do a full update\n\t\t\t[self performSelector:@selector(_continuousProfile:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// stop profiling\n\t\t\t[self updateAfterTickFull:YES];\n\t\t\t[profileButton setState:NSOffState];\n\t\t\t[self profile:nil];\n\t\t\t\n\t\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t\t[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n}\n\n- (void)forceImmediateMenuUpdate\n{\n\t// So, the situation is that the simulation has stopped playing because the end of the simulation was reached.  If that happens while the user\n\t// is tracking a menu in the menu bar, the menus do not get updating (enabling, titles) until the user ends menu tracking.  This is sort of a\n\t// bug in Cocoa, I guess; it assumes that state that influences menu bar items does not change while the user is tracking menus, which is false\n\t// in our case, but is true for most applications, I suppose, maybe.  Anyway, we need to force an immediate update in this situation.\n\tNSMenu *mainMenu = [[NSApplication sharedApplication] mainMenu];\n\tNSInteger numberOfSubmenus = [mainMenu numberOfItems];\n\t\n\tfor (int itemIndex = 0; itemIndex < numberOfSubmenus; ++itemIndex)\n\t{\n\t\tNSMenuItem *menuItem = [mainMenu itemAtIndex:itemIndex];\n\t\tNSMenu *submenu = [menuItem submenu];\n\t\t\n\t\t[submenu update];\n\t}\n\t\n\t// Same for our context menus\n\t[graphCommandsMenu update];\n}\n\n- (void)placeSubview:(NSView *)topView aboveSubview:(NSView *)bottomView\n{\n\tNSView *topSuperview = [topView superview];\n\tNSView *bottomSuperview = [bottomView superview];\n\t\n\tif (topSuperview == bottomSuperview)\n\t{\n\t\tNSMutableArray *subviews = [NSMutableArray arrayWithArray:[topSuperview subviews]];\n\t\t\n\t\t[topView retain];\n\t\t[subviews removeObject:topView];\n\t\t\n\t\tNSUInteger bottomIndex = [subviews indexOfObjectIdenticalTo:bottomView];\n\t\t\n\t\t[subviews insertObject:topView atIndex:bottomIndex + 1];\n\t\t[topView release];\n\t\t\n\t\t[topSuperview setSubviews:subviews];\n\t}\n}\n\n- (void)playOrProfile:(BOOL)isPlayAction\n{\n\tBOOL isProfileAction = !isPlayAction;\t// to avoid having to think in negatives\n\t\n#if DEBUG\n\tif (isProfileAction)\n\t{\n\t\t[profileButton setState:NSOffState];\n\t\t\n\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\n\t\t[alert setAlertStyle:NSAlertStyleWarning];\n\t\t[alert setMessageText:@\"Release build required\"];\n\t\t[alert setInformativeText:@\"In order to obtain accurate timing information that is relevant to the actual runtime of a model, profiling requires that you are running a Release build of SLiMgui.  If you are running SLiMgui from within Xcode, please choose the Release build configuration from the Edit Scheme panel.\"];\n\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t[alert setShowsSuppressionButton:NO];\n\t\t\n\t\t[alert beginSheetModalForWindow:[self window] completionHandler:^(NSModalResponse returnCode) {\n\t\t\t[alert autorelease];\n\t\t}];\n\t\t\n\t\treturn;\n\t}\n#endif\n\t\n#if (SLIMPROFILING != 1)\n\tif (isProfileAction)\n\t{\n\t\t[profileButton setState:NSOffState];\n\t\t\n\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\n\t\t[alert setAlertStyle:NSAlertStyleWarning];\n\t\t[alert setMessageText:@\"Profiling disabled\"];\n\t\t[alert setInformativeText:@\"Profiling has been disabled in this build of SLiMgui.  If you are running SLiMgui from within Xcode, please change the definition of SLIMPROFILING to 1 in the SLiMgui target.\"];\n\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t[alert setShowsSuppressionButton:NO];\n\t\t\n\t\t[alert beginSheetModalForWindow:[self window] completionHandler:^(NSModalResponse returnCode) {\n\t\t\t[alert autorelease];\n\t\t}];\n\t\t\n\t\treturn;\n\t}\n#endif\n\t\n\tif (!continuousPlayOn)\n\t{\n\t\t// keep the button on; this works for the button itself automatically, but when the menu item is chosen this is needed\n\t\tif (isProfileAction)\n\t\t{\n\t\t\t[profileButton setState:NSOnState];\n\t\t\t[profileButton slimSetTintColor:[NSColor colorWithCalibratedHue:0.0 saturation:0.5 brightness:1.0 alpha:1.0]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[playButton setState:NSOnState];\n\t\t\t[self placeSubview:playButton aboveSubview:profileButton];\n\t\t}\n\t\t\n\t\t// log information needed to track our play speed\n\t\t[continuousPlayStartDate release];\n\t\tcontinuousPlayStartDate = [[NSDate date] retain];\n\t\tcontinuousPlayTicksCompleted = 0;\n\t\t\n\t\t[self setContinuousPlayOn:YES];\n\t\tisProfileAction ? [self setProfilePlayOn:YES] : [self setNonProfilePlayOn:YES];\n\t\t\n\t\t// invalidate the console symbols, and don't validate them until we are done\n\t\t[_consoleController invalidateSymbolTableAndFunctionMap];\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// prepare profiling information if necessary\n\t\tif (isProfileAction)\n\t\t\tcommunity->StartProfiling();\n#endif\n\t\t\n\t\t// start playing/profiling\n\t\tif (isPlayAction)\n\t\t\t[self performSelector:@selector(_continuousPlay:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t\telse\n\t\t\t[self performSelector:@selector(_continuousProfile:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t}\n\telse\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// close out profiling information if necessary\n\t\tif (isProfileAction && community && !invalidSimulation)\n\t\t\tcommunity->StopProfiling();\n#endif\n\t\t\n\t\t// keep the button off; this works for the button itself automatically, but when the menu item is chosen this is needed\n\t\tif (isProfileAction)\n\t\t{\n\t\t\t[profileButton setState:NSOffState];\n\t\t\t[profileButton slimSetTintColor:nil];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[playButton setState:NSOffState];\n\t\t\t[self placeSubview:profileButton aboveSubview:playButton];\n\t\t}\n\t\t\n\t\t// stop our recurring perform request\n\t\tif (isPlayAction)\n\t\t\t[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_continuousPlay:) object:nil];\n\t\telse\n\t\t\t[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_continuousProfile:) object:nil];\n\t\t\n\t\t[self setContinuousPlayOn:NO];\n\t\tisProfileAction ? [self setProfilePlayOn:NO] : [self setNonProfilePlayOn:NO];\n\t\t\n\t\t[_consoleController validateSymbolTableAndFunctionMap];\n\t\t[self updateAfterTickFull:YES];\n\t\t\n\t\t// Work around a bug that when the simulation ends during menu tracking, menus do not update until menu tracking finishes\n\t\tif ([self reachedSimulationEnd])\n\t\t\t[self forceImmediateMenuUpdate];\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// If we just finished profiling, display a report\n\t\tif (isProfileAction && community && !invalidSimulation)\n\t\t\t[self displayProfileResults];\n#endif\n\t}\n}\n\n- (IBAction)play:(id)sender\n{\n\t[self playOrProfile:YES];\n}\n\n- (IBAction)profile:(id)sender\n{\n\t[self playOrProfile:NO];\n}\n\n- (void)_tickPlay:(id)sender\n{\n\t// FIXME would be nice to have a way to stop this prematurely, if an incorrect tick is entered or whatever... BCH 2 Nov. 2017\n\tif (!invalidSimulation)\n\t{\n\t\tNSDate *startDate = [NSDate date];\n\t\t\n\t\t// We keep a local version of reachedSimulationEnd, because calling setReachedSimulationEnd: every tick\n\t\t// can actually be a large drag for simulations that run extremely quickly – it can actually exceed the time\n\t\t// spent running the simulation itself!  Moral of the story, KVO is wicked slow.\n\t\tBOOL reachedEnd = reachedSimulationEnd;\n\t\t\n\t\tdo\n\t\t{\n\t\t\tif (community->tick_ >= targetTick)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t@autoreleasepool {\n\t\t\t\treachedEnd = ![self runSimOneTick];\n\t\t\t}\n\t\t}\n\t\twhile (!reachedEnd && (-[startDate timeIntervalSinceNow] < 0.02));\n\t\t\n\t\t[self setReachedSimulationEnd:reachedEnd];\n\t\t\n\t\tif (!reachedSimulationEnd && !(community->tick_ >= targetTick))\n\t\t{\n\t\t\t[self updateAfterTickFull:(-[startDate timeIntervalSinceNow] > 0.04)];\t// if too much time has elapsed, do a full update\n\t\t\t[self performSelector:@selector(_tickPlay:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// stop playing\n\t\t\t[self updateAfterTickFull:YES];\n\t\t\t[self tickChanged:nil];\n\t\t\t\n\t\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t\t[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n}\n\n- (IBAction)tickChanged:(id)sender\n{\n\tif (!tickPlayOn)\n\t{\n\t\tNSString *tickString = [tickTextField stringValue];\n\t\t\n\t\t// Special-case initialize(); we can never advance to it, since it is first, so we just validate it\n\t\tif ([tickString isEqualToString:@\"initialize()\"])\n\t\t{\n\t\t\tif (community->tick_ != 0)\n\t\t\t{\n\t\t\t\tNSBeep();\n\t\t\t\t[self updateTickCounter];\n\t\t\t}\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Get the integer value from the textfield, since it is not \"initialize()\".  I would like the method used here to be\n\t\t// -longLongValue, but that method does not presently exist on NSControl.   [tickString longLongValue] does not\n\t\t// work properly with the formatter; the formatter adds commas and longLongValue doesn't understand them.  Whatever.\n\t\ttargetTick = SLiMClampToTickType([tickTextField integerValue]);\n\t\t\n\t\t// make sure the requested tick is in range\n\t\tif (community->tick_ >= targetTick)\n\t\t{\n\t\t\tif (community->tick_ > targetTick)\n\t\t\t\tNSBeep();\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// update UI\n\t\t[tickProgressIndicator startAnimation:nil];\n\t\t[self setTickPlayOn:YES];\n\t\t\n\t\t// invalidate the console symbols, and don't validate them until we are done\n\t\t[_consoleController invalidateSymbolTableAndFunctionMap];\n\t\t\n\t\t// get the first responder out of the tick textfield\n\t\t[[self window] performSelector:@selector(makeFirstResponder:) withObject:nil afterDelay:0.0];\n\t\t\n\t\t// start playing\n\t\t[self performSelector:@selector(_tickPlay:) withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];\n\t}\n\telse\n\t{\n\t\t// stop our recurring perform request\n\t\t[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_tickPlay:) object:nil];\n\t\t\n\t\t[self setTickPlayOn:NO];\n\t\t[tickProgressIndicator stopAnimation:nil];\n\t\t\n\t\t[_consoleController validateSymbolTableAndFunctionMap];\n\t\t\n\t\t// Work around a bug that when the simulation ends during menu tracking, menus do not update until menu tracking finishes\n\t\tif ([self reachedSimulationEnd])\n\t\t\t[self forceImmediateMenuUpdate];\n\t}\n}\n\n- (IBAction)recycle:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[_consoleController invalidateSymbolTableAndFunctionMap];\n\t[self clearOutput:nil];\n\t[self setScriptStringAndInitializeSimulation:[scriptTextView string]];\n\t[_consoleController validateSymbolTableAndFunctionMap];\n\t[self updateAfterTickFull:YES];\n\t\n\t// A bit of playing with undo.  We want to break undo coalescing at the point of recycling, so that undo and redo stop\n\t// at the moment that we recycled.  Then we reset a change counter that we use to know if we have changed relative to\n\t// the recycle point, so we can highlight the recycle button to show that the executing script is out of date.\n\t[scriptTextView breakUndoCoalescing];\n\t[[self document] resetSLiMChangeCount];\n\t\n\t// Update the status field so that if the selection is in an initialize...() function the right signature is shown.  This call would\n\t// be more technically correct in -updateAfterTick, but I don't want the tokenization overhead there, it's too heavyweight.  The\n\t// only negative consequence of not having it there is that when the user steps out of initialization time into tick 1, an\n\t// initialize...() function signature may persist in the status bar that should have been changed to \"unrecognized call\" - no biggie.\n\t// BCH 31 May 2016: commenting this out since the status bar is no longer dependent on the simulation state.  We want the\n\t// initialize() functions to show their prototypes in the status bar whether we are in the zero tick or not.\n\t//[self updateStatusFieldFromSelection];\n\n\t[self sendAllLinkedViewsSelector:@selector(controllerRecycled)];\n}\n\n- (IBAction)playSpeedChanged:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t// We want our speed to be from the point when the slider changed, not from when play started\n\t[continuousPlayStartDate release];\n\tcontinuousPlayStartDate = [[NSDate date] retain];\n\tcontinuousPlayTicksCompleted = 1;\t\t// this prevents a new tick from executing every time the slider moves a pixel\n\t\n\t// This method is called whenever playSpeedSlider changes, continuously; we want to show the chosen speed in a tooltip-ish window\n\tdouble speedSliderValue = [playSpeedSlider doubleValue];\n\t\n\t// Calculate frames per second; this equation must match the equation in _continuousPlay:\n\tdouble maxTicksPerSecond = INFINITY;\n\t\n\tif (speedSliderValue < 0.99999)\n\t\tmaxTicksPerSecond = (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * (speedSliderValue + 0.06) * 839;\n\t\n\t// Make a tooltip label string\n\tNSString *fpsString= @\"∞ fps\";\n\t\n\tif (!isinf(maxTicksPerSecond))\n\t{\n\t\tif (maxTicksPerSecond < 1.0)\n\t\t\tfpsString = [NSString stringWithFormat:@\"%.2f fps\", maxTicksPerSecond];\n\t\telse if (maxTicksPerSecond < 10.0)\n\t\t\tfpsString = [NSString stringWithFormat:@\"%.1f fps\", maxTicksPerSecond];\n\t\telse\n\t\t\tfpsString = [NSString stringWithFormat:@\"%.0f fps\", maxTicksPerSecond];\n\t\t\n\t\t//NSLog(@\"fps string: %@\", fpsString);\n\t}\n\t\n\t// Calculate the tooltip origin; this is adjusted for the metrics on OS X 10.12\n\tNSRect sliderRect = [playSpeedSlider alignmentRectForFrame:[playSpeedSlider frame]];\n\tNSPoint tipPoint = sliderRect.origin;\n\t\n\ttipPoint.x += 5 + round((sliderRect.size.width - 11.0) * speedSliderValue);\n\ttipPoint.y += 10;\n\t\n\ttipPoint = [[playSpeedSlider superview] convertPoint:tipPoint toView:nil];\n\tNSRect tipRect = NSMakeRect(tipPoint.x, tipPoint.y, 0, 0);\n\ttipPoint = [[playSpeedSlider window] convertRectToScreen:tipRect].origin;\n\t\n\t// Make the tooltip window, configure it, and display it\n\tif (!playSpeedToolTipWindow)\n\t\tplaySpeedToolTipWindow = [SLiMPlaySliderToolTipWindow new];\n\t\n\t[playSpeedToolTipWindow setLabel:fpsString];\n\t[playSpeedToolTipWindow setTipPoint:tipPoint];\n\t[playSpeedToolTipWindow orderFront:nil];\n\t\n\t// Schedule a hide of the tooltip; this runs only once we're out of the tracking loop, conveniently\n\t[NSObject cancelPreviousPerformRequestsWithTarget:playSpeedToolTipWindow selector:@selector(orderOut:) object:nil];\n\t[playSpeedToolTipWindow performSelector:@selector(orderOut:) withObject:nil afterDelay:0.01];\n}\n\n- (BOOL)checkScriptSuppressSuccessResponse:(BOOL)suppressSuccessResponse\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t// Note this does *not* check out scriptString, which represents the state of the script when the Community object was created\n\t// Instead, it checks the current script in the script TextView – which is not used for anything until the recycle button is clicked.\n\tconst char *cstr = [[scriptTextView string] UTF8String];\n\tNSString *errorDiagnostic = nil;\n\t\n\tif (!cstr)\n\t{\n\t\terrorDiagnostic = [@\"The script string could not be read, possibly due to an encoding problem.\" retain];\n\t}\n\telse\n\t{\n\t\tSLiMEidosScript script(cstr);\n\t\t\n\t\ttry {\n\t\t\tscript.Tokenize();\n\t\t\tscript.ParseSLiMFileToAST();\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tstd::string &&error_diagnostic = Eidos_GetTrimmedRaiseMessage();\n\t\t\terrorDiagnostic = [[NSString stringWithUTF8String:error_diagnostic.c_str()] retain];\n\t\t}\n\t}\n\t\n\tBOOL checkDidSucceed = !errorDiagnostic;\n\t\n\tif (!checkDidSucceed || !suppressSuccessResponse)\n\t{\n\t\t// use our ConsoleWindowController delegate method to play the appropriate sound\n\t\t[self eidosConsoleWindowController:_consoleController checkScriptDidSucceed:checkDidSucceed];\n\t\t\n\t\tif (!checkDidSucceed)\n\t\t{\n\t\t\t// On failure, we show an alert describing the error, and highlight the relevant script line\n\t\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\t\n\t\t\t[alert setAlertStyle:NSAlertStyleWarning];\n\t\t\t[alert setMessageText:@\"Script error\"];\n\t\t\t[alert setInformativeText:errorDiagnostic];\n\t\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t\t\n\t\t\t[alert beginSheetModalForWindow:[self window] completionHandler:^(NSModalResponse returnCode) { [alert autorelease]; }];\n\t\t\t\n\t\t\t[scriptTextView selectErrorRange];\n\t\t\t\n\t\t\t// Show the error in the status bar also\n\t\t\tNSString *trimmedError = [errorDiagnostic stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n\t\t\tNSDictionary *errorAttrs = [NSDictionary eidosTextAttributesWithColor:[NSColor redColor] size:11.0];\n\t\t\tNSMutableAttributedString *errorAttrString = [[[NSMutableAttributedString alloc] initWithString:trimmedError attributes:errorAttrs] autorelease];\n\t\t\t\n\t\t\t[errorAttrString addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithFloat:2.0] range:NSMakeRange(0, [errorAttrString length])];\n\t\t\t[scriptStatusTextField setAttributedStringValue:errorAttrString];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\t\t\n\t\t\t// On success, we optionally show a success alert sheet\n\t\t\tif (![defaults boolForKey:EidosDefaultsSuppressScriptCheckSuccessPanelKey])\n\t\t\t{\n\t\t\t\tNSAlert *alert = [[NSAlert alloc] init];\n\t\t\t\t\n\t\t\t\t[alert setAlertStyle:NSAlertStyleInformational];\n\t\t\t\t[alert setMessageText:@\"No script errors\"];\n\t\t\t\t[alert setInformativeText:@\"No errors found.\"];\n\t\t\t\t[alert addButtonWithTitle:@\"OK\"];\n\t\t\t\t[alert setShowsSuppressionButton:YES];\n\t\t\t\t\n\t\t\t\t[alert beginSheetModalForWindow:[self window] completionHandler:^(NSModalResponse returnCode) {\n\t\t\t\t\tif ([[alert suppressionButton] state] == NSOnState)\n\t\t\t\t\t\t[defaults setBool:YES forKey:EidosDefaultsSuppressScriptCheckSuccessPanelKey];\n\t\t\t\t\t[alert autorelease];\n\t\t\t\t}];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t[errorDiagnostic release];\n\t\n\treturn checkDidSucceed;\n}\n\n- (IBAction)checkScript:(id)sender\n{\n\t[self checkScriptSuppressSuccessResponse:NO];\n}\n\n- (IBAction)prettyprintScript:(id)sender\n{\n\tif ([scriptTextView isEditable])\n\t{\n\t\tif ([self checkScriptSuppressSuccessResponse:YES])\n\t\t{\n\t\t\t// We know the script is syntactically correct, so we can tokenize and parse it without worries\n\t\t\tconst char *cstr = [[scriptTextView string] UTF8String];\n\t\t\tSLiMEidosScript script(cstr);\t// SLiMEidosScript does not override Tokenize(), but it could...\n\t\t\t\n\t\t\tscript.Tokenize(false, true);\t// get whitespace and comment tokens\n\t\t\t\n\t\t\t// Then generate a new script string that is prettyprinted\n\t\t\tconst std::vector<EidosToken> &tokens = script.Tokens();\n\t\t\tNSMutableString *pretty = [NSMutableString string];\n\t\t\t\n\t\t\tif ([EidosPrettyprinter prettyprintTokens:tokens fromScript:script intoString:pretty])\n\t\t\t{\n\t\t\t\tif ([scriptTextView shouldChangeTextInRange:NSMakeRange(0, [[scriptTextView string] length]) replacementString:pretty])\n\t\t\t\t{\n\t\t\t\t\t[scriptTextView setString:pretty];\n\t\t\t\t\t[scriptTextView didChangeText];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNSBeep();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tNSBeep();\n\t\t}\n\t}\n\telse\n\t{\n\t\tNSBeep();\n\t}\n}\n\n- (IBAction)showScriptHelp:(id)sender\n{\n\t[_consoleController showScriptHelp:sender];\n}\n\n- (IBAction)toggleConsoleVisibility:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[_consoleController toggleConsoleVisibility:sender];\n}\n\n- (IBAction)toggleBrowserVisibility:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[[_consoleController browserController] toggleBrowserVisibility:self];\n}\n\n- (IBAction)clearOutput:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[outputTextView setString:@\"\"];\n\t\n\t// Just in case we have any buffered output, clear the output stream\n\tgSLiMOut.clear();\n\tgSLiMOut.str(\"\");\n\t\n\tgSLiMError.clear();\n\tgSLiMError.str(\"\");\n}\n\n- (IBAction)dumpPopulationToOutput:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\ttry\n\t{\n\t\t// BCH 3/6/2022: Note that the species cycle has been added here for SLiM 4, in keeping with SLiM's native output formats.\n\t\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\tslim_tick_t species_cycle = displaySpecies->Cycle();\n\t\t\n\t\t// dump the population: output spatial positions and ages and tags if available, but not ancestral sequence or substitutions\n\t\tIndividual::PrintIndividuals_SLiM(SLIM_OUTSTREAM, nullptr, 0, *displaySpecies, true, true, false, false, true, false, /* p_focal_chromosome */ nullptr);\n\t\t\n\t\t// dump fixed substitutions also; so the dump in SLiMgui is like outputFull() + outputFixedMutations()\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\tSLIM_OUTSTREAM << \"#OUT: \" << community->tick_ << \" \" << species_cycle << \" F \" << std::endl;\n\t\tSLIM_OUTSTREAM << \"Mutations:\" << std::endl;\n\t\t\n\t\tfor (unsigned int i = 0; i < displaySpecies->population_.substitutions_.size(); i++)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << i << \" \";\n\t\t\tdisplaySpecies->population_.substitutions_[i]->PrintForSLiMOutput_Tag(SLIM_OUTSTREAM);\n\t\t}\n\t\t\n\t\t// now send SLIM_OUTSTREAM to the output textview\n\t\t[self updateOutputTextView];\n\t}\n\tcatch (...)\n\t{\n\t}\n}\n\n- (IBAction)changeWorkingDirectory:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tNSOpenPanel *op = [[NSOpenPanel openPanel] retain];\n\t\n\t[op setTitle:@\"Choose Working Directory\"];\n\t[op setNameFieldLabel:@\"Directory:\"];\n\t[op setMessage:@\"Choose a current working directory for this model:\"];\n\t[op setExtensionHidden:NO];\n\t[op setCanChooseFiles:NO];\n\t[op setCanChooseDirectories:YES];\n\t[op setCanCreateDirectories:YES];\n\t\n\t// try to make the panel start in the current working directory (not the last requested dir, the actual dir)\n\tstd::string cwd = sim_working_dir;\n\tNSString *cwd_string = [NSString stringWithUTF8String:cwd.c_str()];\n\tNSString *expanded_path = [cwd_string stringByStandardizingPath];\n\tNSURL *url = [NSURL fileURLWithPath:expanded_path];\n\t[op setDirectoryURL:url];\n\t\n\t[op beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {\n\t\tif (result == NSModalResponseOK)\n\t\t{\n\t\t\tNSURL *fileURL = [op URL];\n\t\t\tconst char *filePath = [fileURL fileSystemRepresentation];\n\t\t\t\n\t\t\tsim_working_dir = filePath;\n\t\t\tsim_requested_working_dir = sim_working_dir;\n\t\t}\n\t}];\n}\n\n- (IBAction)showRecombinationIntervalsButtonToggled:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tBOOL newValue = ([showRecombinationIntervalsButton state] == NSOnState);\n\t\n\tif (newValue != zoomedChromosomeShowsRateMaps)\n\t{\n\t\tzoomedChromosomeShowsRateMaps = newValue;\n\t\t[chromosomeZoomed setShouldDrawRateMaps:zoomedChromosomeShowsRateMaps];\n\t\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t}\n}\n\n- (IBAction)showGenomicElementsButtonToggled:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tBOOL newValue = ([showGenomicElementsButton state] == NSOnState);\n\t\n\tif (newValue != zoomedChromosomeShowsGenomicElements)\n\t{\n\t\tzoomedChromosomeShowsGenomicElements = newValue;\n\t\t[chromosomeZoomed setShouldDrawGenomicElements:zoomedChromosomeShowsGenomicElements];\n\t\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t}\n}\n\n- (IBAction)showMutationsButtonToggled:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tBOOL newValue = ([showMutationsButton state] == NSOnState);\n\t\n\tif (newValue != zoomedChromosomeShowsMutations)\n\t{\n\t\tzoomedChromosomeShowsMutations = newValue;\n\t\t[chromosomeZoomed setShouldDrawMutations:zoomedChromosomeShowsMutations];\n\t\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t}\n}\n\n- (IBAction)showFixedSubstitutionsButtonToggled:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tBOOL newValue = ([showFixedSubstitutionsButton state] == NSOnState);\n\t\n\tif (newValue != zoomedChromosomeShowsFixedSubstitutions)\n\t{\n\t\tzoomedChromosomeShowsFixedSubstitutions = newValue;\n\t\t[chromosomeZoomed setShouldDrawFixedSubstitutions:zoomedChromosomeShowsFixedSubstitutions];\n\t\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t}\n}\n\n- (IBAction)drawerButtonToggled:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\t[drawer toggle:sender];\n}\n\n- (IBAction)exportScript:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tNSSavePanel *sp = [[NSSavePanel savePanel] retain];\n\t\n\t[sp setTitle:@\"Export Script\"];\n\t[sp setNameFieldLabel:@\"Export As:\"];\n\t[sp setMessage:@\"Export the simulation script to a file:\"];\n\t[sp setExtensionHidden:NO];\n\t[sp setCanSelectHiddenExtension:NO];\n\t[sp setAllowedFileTypes:@[@\"txt\"]];\n\t\n\t[sp beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {\n\t\tif (result == NSModalResponseOK)\n\t\t{\n\t\t\t[[scriptTextView string] writeToURL:[sp URL] atomically:YES encoding:NSUTF8StringEncoding error:NULL];\n\t\t\t\n\t\t\t[sp autorelease];\n\t\t}\n\t}];\n}\n\n- (IBAction)exportOutput:(id)sender\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tNSSavePanel *sp = [[NSSavePanel savePanel] retain];\n\t\n\t[sp setTitle:@\"Export Output\"];\n\t[sp setNameFieldLabel:@\"Export As:\"];\n\t[sp setMessage:@\"Export the simulation output to a file:\"];\n\t[sp setExtensionHidden:NO];\n\t[sp setCanSelectHiddenExtension:NO];\n\t[sp setAllowedFileTypes:@[@\"txt\"]];\n\t\n\t[sp beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {\n\t\tif (result == NSModalResponseOK)\n\t\t{\n\t\t\tNSString *currentOutputString = [outputTextView string];\n\t\t\t\n\t\t\t[currentOutputString writeToURL:[sp URL] atomically:YES encoding:NSUTF8StringEncoding error:NULL];\n\t\t\t\n\t\t\t[sp autorelease];\n\t\t}\n\t}];\n}\n\n\n//\n//\tEidos SLiMgui method forwards\n//\n#pragma mark -\n#pragma mark Eidos SLiMgui method forwards\n\n- (void)finish_eidos_pauseExecution:(id)sender\n{\n\t// this gets called by performSelectorOnMainThread: after _continuousPlay: has broken out of its loop\n\t// if the simulation has already ended, or is invalid, or is not in continuous play, it does nothing\n\tif (!invalidSimulation && !reachedSimulationEnd && continuousPlayOn && nonProfilePlayOn && !profilePlayOn && !tickPlayOn)\n\t{\n\t\t[self play:nil];\t// this will simulate a press of the play button to stop continuous play\n\t\t\n\t\t// bounce our icon; if we are not the active app, to signal that the run is done\n\t\t[NSApp requestUserAttention:NSInformationalRequest];\n\t}\n}\n\n- (void)eidos_openDocument:(NSString *)path\n{\n\tNSURL *pathURL = [NSURL fileURLWithPath:path];\n\t\n\t[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:pathURL display:YES completionHandler:(^ void (NSDocument *typelessDoc, BOOL already_open, NSError *error) { })];\n}\n\n- (void)eidos_pauseExecution\n{\n\tif (!invalidSimulation && !reachedSimulationEnd && continuousPlayOn && nonProfilePlayOn && !profilePlayOn && !tickPlayOn)\n\t{\n\t\tcontinuousPlayTicksCompleted = UINT64_MAX - 1;\t\t\t// this will break us out of the loop in _continuousPlay: at the end of this tick\n\t\t[self performSelectorOnMainThread:@selector(finish_eidos_pauseExecution:) withObject:nil waitUntilDone:NO];\t// this will actually stop continuous play\n\t}\n}\n\n\n//\n//\tEidosConsoleWindowControllerDelegate methods\n//\n#pragma mark -\n#pragma mark EidosConsoleWindowControllerDelegate\n\n- (EidosContext *)eidosConsoleWindowControllerEidosContext:(EidosConsoleWindowController *)eidosConsoleController\n{\n\treturn community;\n}\n\n- (void)eidosConsoleWindowControllerAppendWelcomeMessageAddendum:(EidosConsoleWindowController *)eidosConsoleController\n{\n\tEidosConsoleTextView *textView = [_consoleController textView];\n\tNSTextStorage *ts = [textView textStorage];\n\tNSDictionary *outputAttrs = [NSDictionary eidosOutputAttrsWithSize:[textView displayFontSize]];\n\tNSString *bundleVersionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"CFBundleShortVersionString\"];\n\tNSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@\"CFBundleVersion\"];\n\tNSString *versionString = [NSString stringWithFormat:@\"%@ (build %@)\", bundleVersionString, bundleVersion];\n\tNSAttributedString *launchString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@\"Connected to SLiMguiLegacy simulation.\\nSLiM version %@.\\n\", versionString] attributes:outputAttrs];\t// SLIM VERSION\n\tNSAttributedString *dividerString = [[NSAttributedString alloc] initWithString:@\"\\n-----------------------------------------------------\\n\\n\" attributes:outputAttrs];\n\t\n\t[ts beginEditing];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:launchString];\n\t[ts replaceCharactersInRange:NSMakeRange([ts length], 0) withAttributedString:dividerString];\n\t[ts endEditing];\n\t\n\t[launchString release];\n\t[dividerString release];\n\t\n\t// We have some one-time work that we do when the first window opens; this is here instead of\n\t// applicationWillFinishLaunching: because we don't want to mess up gEidos_RNG\n\tstatic BOOL beenHere = NO;\n\t\n\tif (!beenHere)\n\t{\n\t\tbeenHere = YES;\n\t\t\n\t\tEidosHelpController *sharedHelp = [EidosHelpController sharedController];\n\t\t\n\t\tstd::vector<EidosPropertySignature_CSP> context_properties = EidosClass::RegisteredClassProperties(false, true);\n\t\tstd::vector<EidosMethodSignature_CSP> context_methods = EidosClass::RegisteredClassMethods(false, true);\n\t\t\n\t\tconst std::vector<EidosFunctionSignature_CSP> *zg_functions = Community::ZeroTickFunctionSignatures();\n\t\tconst std::vector<EidosFunctionSignature_CSP> *slim_functions = Community::SLiMFunctionSignatures();\n\t\tstd::vector<EidosFunctionSignature_CSP> all_slim_functions;\n\t\t\n\t\tall_slim_functions.insert(all_slim_functions.end(), zg_functions->begin(), zg_functions->end());\n\t\tall_slim_functions.insert(all_slim_functions.end(), slim_functions->begin(), slim_functions->end());\n\t\t\n\t\t[sharedHelp addTopicsFromRTFFile:@\"SLiMHelpFunctions\" underHeading:@\"6. SLiM Functions\" functions:&all_slim_functions methods:nullptr properties:nullptr];\n\t\t[sharedHelp addTopicsFromRTFFile:@\"SLiMHelpClasses\" underHeading:@\"7. SLiM Classes\" functions:nullptr methods:&context_methods properties:&context_properties];\n\t\t[sharedHelp addTopicsFromRTFFile:@\"SLiMHelpCallbacks\" underHeading:@\"8. SLiM Events and Callbacks\" functions:nullptr methods:nullptr properties:nullptr];\n\t\t\n\t\t// Check for completeness of the help documentation, since it's easy to forget to add new functions/properties/methods to the doc\n\t\t[sharedHelp checkDocumentationOfFunctions:&all_slim_functions];\n\t\t\n\t\tfor (EidosClass *class_object : EidosClass::RegisteredClasses(false, true))\n\t\t{\n\t\t\tconst std::string &element_type = class_object->ClassNameForDisplay();\n\t\t\t\n\t\t\tif (!Eidos_string_hasPrefix(element_type, \"_\"))\t\t// internal classes are undocumented\n\t\t\t\t[sharedHelp checkDocumentationOfClass:class_object];\n\t\t}\n\t\t\n\t\t[sharedHelp checkDocumentationForDuplicatePointers];\n\t\t\n\t\t// Run startup tests, iff the option key is down; NOTE THAT THIS CAUSES MASSIVE LEAKING DUE TO RAISES INSIDE EIDOS!\n\t\tif ([NSEvent modifierFlags] & NSEventModifierFlagOption)\n\t\t{\n\t\t\t// We will be executing scripts, so bracket that with our delegate method call\n\t\t\t[self eidosConsoleWindowControllerWillExecuteScript:_consoleController];\n\t\t\t\n\t\t\t// Run the tests\n\t\t\tRunSLiMTests();\n\t\t\t\n\t\t\t// Done executing scripts\n\t\t\t[self eidosConsoleWindowControllerDidExecuteScript:_consoleController];\n\t\t}\n\t}\n}\n\n- (EidosSymbolTable *)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController symbolsFromBaseSymbols:(EidosSymbolTable *)baseSymbols\n{\n\tif (community && !invalidSimulation)\n\t\treturn community->SymbolsFromBaseSymbols(baseSymbols);\n\treturn baseSymbols;\n}\n\n- (EidosFunctionMap *)functionMapForEidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController\n{\n\tif (community && !invalidSimulation)\n\t\treturn &community->FunctionMap();\n\treturn nullptr;\n}\n\n- (void)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController addOptionalFunctionsToMap:(EidosFunctionMap *)functionMap\n{\n\tCommunity::AddZeroTickFunctionsToMap(*functionMap);\n\tCommunity::AddSLiMFunctionsToMap(*functionMap);\n}\n\n- (EidosSyntaxHighlightType)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController tokenStringIsSpecialIdentifier:(const std::string &)token_string\n{\n\tif (token_string.compare(gStr_community) == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsIdentifier;\n\tif (token_string.compare(gStr_sim) == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsIdentifier;\n\tif (token_string.compare(gStr_slimgui) == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsIdentifier;\n\t\n\t// Request that SLiM's callback keywords be highlighted as \"context keywords\", which gives them a special color\n\t// I'm not sure that I'm crazy about this; feels like it makes the color scheme too jumbled.\n\t// Leaving it out for now.  BCH 2 Nov. 2017\n\t/*\n\tif (token_string.compare(\"initialize\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"first\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"early\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"late\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"mutationEffect\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"fitnessEffect\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"mateChoice\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"modifyChild\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"interaction\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"recombination\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"mutation\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"survival\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\tif (token_string.compare(\"reproduction\") == 0)\n\t\treturn EidosSyntaxHighlightType::kHighlightAsContextKeyword;\n\t*/\n\t\n\tint len = (int)token_string.length();\n\t\n\tif (len >= 2)\n\t{\n\t\tunichar first_ch = token_string[0];\n\t\t\n\t\tif ((first_ch == 'p') || (first_ch == 'g') || (first_ch == 'm') || (first_ch == 's') || (first_ch == 'i'))\n\t\t{\n\t\t\tfor (int ch_index = 1; ch_index < len; ++ch_index)\n\t\t\t{\n\t\t\t\tunichar idx_ch = token_string[ch_index];\n\t\t\t\t\n\t\t\t\tif ((idx_ch < '0') || (idx_ch > '9'))\n\t\t\t\t\treturn EidosSyntaxHighlightType::kNoSyntaxHighlight;\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosSyntaxHighlightType::kHighlightAsIdentifier;\n\t\t}\n\t}\n\t\n\treturn EidosSyntaxHighlightType::kNoSyntaxHighlight;\n}\n\n- (NSString *)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController helpTextForClickedText:(NSString *)clickedText\n{\n\t// A few strings which, when option-clicked, should result in more targeted searches.\n\t// @\"initialize\" is deliberately omitted here so that the initialize...() methods also come up.\n\tif ([clickedText isEqualToString:@\"first\"])\t\t\t\treturn @\"Eidos events\";\n\tif ([clickedText isEqualToString:@\"early\"])\t\t\t\treturn @\"Eidos events\";\n\tif ([clickedText isEqualToString:@\"late\"])\t\t\t\treturn @\"Eidos events\";\n\tif ([clickedText isEqualToString:@\"mutationEffect\"])\treturn @\"mutationEffect() callbacks\";\n\tif ([clickedText isEqualToString:@\"fitnessEffect\"])\t\treturn @\"fitnessEffect() callbacks\";\n\tif ([clickedText isEqualToString:@\"interaction\"])\t\treturn @\"interaction() callbacks\";\n\tif ([clickedText isEqualToString:@\"mateChoice\"])\t\treturn @\"mateChoice() callbacks\";\n\tif ([clickedText isEqualToString:@\"modifyChild\"])\t\treturn @\"modifyChild() callbacks\";\n\tif ([clickedText isEqualToString:@\"recombination\"])\t\treturn @\"recombination() callbacks\";\n\tif ([clickedText isEqualToString:@\"mutation\"])\t\t\treturn @\"mutation() callbacks\";\n\tif ([clickedText isEqualToString:@\"survival\"])\t\t\treturn @\"survival() callbacks\";\n\tif ([clickedText isEqualToString:@\"reproduction\"])\t\treturn @\"reproduction() callbacks\";\n\t\n\treturn nil;\n}\n\n- (void)eidosConsoleWindowController:(EidosConsoleWindowController *)eidosConsoleController checkScriptDidSucceed:(BOOL)succeeded\n{\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\n\tif (succeeded)\n\t{\n\t\tif ([defaults boolForKey:defaultsPlaySoundParseSuccessKey])\n\t\t\t[[NSSound soundNamed:@\"Bottle\"] play];\n\t}\n\telse\n\t{\n\t\tif ([defaults boolForKey:defaultsPlaySoundParseFailureKey])\n\t\t\t[[NSSound soundNamed:@\"Ping\"] play];\n\t}\n}\n\n- (void)eidosConsoleWindowControllerWillExecuteScript:(EidosConsoleWindowController *)eidosConsoleController\n{\n\t// Whenever we are about to execute script, we swap in our random number generator; at other times, gEidos_RNG_SINGLE is NULL.\n\t// The goal here is to keep each SLiM window independent in its random number sequence.\n\tif (gEidos_RNG_Initialized)\n\t\tNSLog(@\"eidosConsoleWindowControllerWillExecuteScript: gEidos_rng already set up!\");\n\t\n#ifndef _OPENMP\n\tstd::swap(sim_RNG_SINGLE, gEidos_RNG_SINGLE);\n#else\n\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\tstd::swap(sim_RNG_PERTHREAD[threadIndex], gEidos_RNG_PERTHREAD[threadIndex]);\n#endif\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\t//NSLog(@\"-[SLiMWindowController eidosConsoleWindowControllerWillExecuteScript]: swapped IN simRNG (sim_RNG_initialized == %@, gEidos_RNG_Initialized == %@)\", sim_RNG_initialized ? @\"YES\" : @\"NO\", gEidos_RNG_Initialized ? @\"YES\" : @\"NO\");\n\t\n\t// We also swap in the pedigree id and mutation id counters; each SLiMgui window is independent\n\tgSLiM_next_pedigree_id = sim_next_pedigree_id;\n\tgSLiM_next_mutation_id = sim_next_mutation_id;\n\tgEidosSuppressWarnings = sim_suppress_warnings;\n\t\n\t// Set the current directory to its value for this window\n\terrno = 0;\n\tint retval = chdir(sim_working_dir.c_str());\n\t\n\tif (retval == -1)\n\t\tNSLog(@\"eidosConsoleWindowControllerWillExecuteScript: Unable to set the working directory to %s (error %d)\", sim_working_dir.c_str(), errno);\n}\n\n- (void)eidosConsoleWindowControllerDidExecuteScript:(EidosConsoleWindowController *)eidosConsoleController\n{\n\t// Swap our random number generator back out again; see -eidosConsoleWindowControllerWillExecuteScript\n\t// Note that gEidos_RNG_Initialized can be false; this gets called even when an error has invalidated the simulation\n#ifndef _OPENMP\n\tstd::swap(sim_RNG_SINGLE, gEidos_RNG_SINGLE);\n#else\n\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t\tstd::swap(sim_RNG_PERTHREAD[threadIndex], gEidos_RNG_PERTHREAD[threadIndex]);\n#endif\n\tstd::swap(sim_RNG_initialized, gEidos_RNG_Initialized);\n\t//NSLog(@\"-[SLiMWindowController eidosConsoleWindowControllerDidExecuteScript]: swapped OUT simRNG (sim_RNG_initialized == %@, gEidos_RNG_Initialized == %@)\", sim_RNG_initialized ? @\"YES\" : @\"NO\", gEidos_RNG_Initialized ? @\"YES\" : @\"NO\");\n\t\n\t// Swap out our pedigree id and mutation id counters; see -eidosConsoleWindowControllerWillExecuteScript\n\t// Setting to -100000 here is not necessary, but will maybe help find bugs...\n\tsim_next_pedigree_id = gSLiM_next_pedigree_id;\n\tgSLiM_next_pedigree_id = -100000;\n\t\n\tsim_next_mutation_id = gSLiM_next_mutation_id;\n\tgSLiM_next_mutation_id = -100000;\n\t\n\tsim_suppress_warnings = gEidosSuppressWarnings;\n\tgEidosSuppressWarnings = false;\n\t\n\t// Get the current working directory; each SLiM window has its own cwd, which may have been changed in script since ...WillExecuteScript:\n\tsim_working_dir = Eidos_CurrentDirectory();\n\t\n\t// Return to the app's working directory when not running SLiM/Eidos code\n\tstd::string &app_cwd = [(AppDelegate *)[NSApp delegate] SLiMguiCurrentWorkingDirectory];\n\terrno = 0;\n\tint retval = chdir(app_cwd.c_str());\n\t\n\tif (retval == -1)\n\t\tNSLog(@\"eidosConsoleWindowControllerDidExecuteScript: Unable to set the working directory to %s (error %d)\", app_cwd.c_str(), errno);\n}\n\n- (void)eidosConsoleWindowControllerConsoleWindowWillClose:(EidosConsoleWindowController *)eidosConsoleController\n{\n\t[consoleButton setState:NSOffState];\n}\n\n\n//\n//\tEidosTextViewDelegate methods\n//\n#pragma mark -\n#pragma mark EidosTextViewDelegate\n\n// This is necessary because we are both a EidosTextViewDelegate (for the views we directly contain) and an\n// EidosConsoleWindowControllerDelegate (for the console window we own), and the delegate protocols are similar\n// but not identical.  This protocol just forwards on to the EidosConsoleWindowControllerDelegate methods.\n\n- (EidosSymbolTable *)eidosTextView:(EidosTextView *)eidosTextView symbolsFromBaseSymbols:(EidosSymbolTable *)baseSymbols\n{\n\t// Here we use the symbol table from the console window, rather than calling the console window controller delegate\n\t// method, which would derive a new symbol table – not what we want here\n\treturn [_consoleController symbols];\n}\n\n- (EidosFunctionMap *)functionMapForEidosTextView:(EidosTextView *)eidosTextView\n{\n\treturn [self functionMapForEidosConsoleWindowController:nullptr];\n}\n\n- (void)eidosTextView:(EidosTextView *)eidosTextView addOptionalFunctionsToMap:(EidosFunctionMap *)functionMap\n{\n\t[self eidosConsoleWindowController:nullptr addOptionalFunctionsToMap:functionMap];\n}\n\n- (EidosSyntaxHighlightType)eidosTextView:(EidosTextView *)eidosTextView tokenStringIsSpecialIdentifier:(const std::string &)token_string;\n{\n\treturn [self eidosConsoleWindowController:nullptr tokenStringIsSpecialIdentifier:token_string];\n}\n\n- (NSString *)eidosTextView:(EidosTextView *)eidosTextView helpTextForClickedText:(NSString *)clickedText\n{\n\treturn [self eidosConsoleWindowController:nullptr helpTextForClickedText:clickedText];\n}\n\n- (BOOL)eidosTextView:(EidosTextView *)eidosTextView completionContextWithScriptString:(NSString *)completionScriptString selection:(NSRange)selection typeTable:(EidosTypeTable **)typeTable functionMap:(EidosFunctionMap **)functionMap callTypeTable:(EidosCallTypeTable **)callTypeTable keywords:(NSMutableArray *)keywords argumentNameCompletions:(std::vector<std::string> *)argNameCompletions\n{\n\t// Code completion in the console window and other ancillary EidosTextViews should use the standard code completion\n\t// machinery in EidosTextView.  In the script view, however, we want things to behave somewhat differently.  In\n\t// other contexts, we want the variables and functions available to depend solely upon the current state of the\n\t// simulation; whatever is actually available is what code completion provides.  In the script view, however, we\n\t// want to be smarter than that.  Initialization functions should be available when the user is completing\n\t// inside an initialize() callback, and not available otherwise, regardless of the current simulation state.\n\t// Similarly, variables associated with particular types of callbacks should always be available within those\n\t// callbacks; variables defined in script blocks other than the focal block should not be visible in code\n\t// completion; defined constants should be available everywhere; and it should be assumed that variables with\n\t// names like pX, mX, gX, and sX have their usual types even if they are not presently defined.  This delegate\n\t// method accomplishes all of those things, by replacing the standard EidosTextView completion handling.\n\tif (eidosTextView == scriptTextView)\n\t{\n\t\tstd::string script_string([completionScriptString UTF8String]);\n\t\tSLiMEidosScript script(script_string);\n\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\tstd::cout << \"SLiM script:\\n\" << script_string << std::endl << std::endl;\n#endif\n\t\t\n\t\t// Parse an \"interpreter block\" bounded by an EOF rather than a \"script block\" that requires braces\n\t\tscript.Tokenize(true, false);\t\t\t\t// make bad tokens as needed, do not keep nonsignificant tokens\n\t\tscript.ParseSLiMFileToAST(true);\t\t\t// make bad nodes as needed (i.e. never raise, and produce a correct tree)\n\t\t\n#if EIDOS_DEBUG_COMPLETION\n\t\tstd::ostringstream parse_stream;\n\t\tscript.PrintAST(parse_stream);\n\t\tstd::cout << \"SLiM AST:\\n\" << parse_stream.str() << std::endl << std::endl;\n#endif\n\t\t\n\t\t// Substitute a type table of class SLiMTypeTable and add any defined symbols to it.  We use SLiMTypeTable so that\n\t\t// variables like pX, gX, mX, and sX have a known object type even if they are not presently defined in the simulation.\n\t\t*typeTable = new SLiMTypeTable();\n\t\tEidosSymbolTable *symbols = [_consoleController symbols];\n\t\t\n\t\tif (symbols)\n\t\t\tsymbols->AddSymbolsToTypeTable(*typeTable);\n\t\t\n\t\t// Use the script text view's facility for using type-interpreting to get a \"definitive\" function map.  This way\n\t\t// all functions that are defined, even if below the completion point, end up in the function map.\n\t\t*functionMap = [scriptTextView functionMapForScriptString:[scriptTextView string] includingOptionalFunctions:NO];\n\t\t\n\t\tCommunity::AddSLiMFunctionsToMap(**functionMap);\n\t\t\n\t\t// Now we scan through the children of the root node, each of which is the root of a SLiM script block.  The last\n\t\t// script block is the one we are actually completing inside, but we also want to do a quick scan of any other\n\t\t// blocks we find, solely to add entries for any defineConstant() and defineGlobal() calls we can decode.\n\t\tconst EidosASTNode *script_root = script.AST();\n\t\t\n\t\tif (script_root && (script_root->children_.size() > 0))\n\t\t{\n\t\t\tEidosASTNode *completion_block = script_root->children_.back();\n\t\t\t\n\t\t\t// If the last script block has a range that ends before the start of the selection, then we are completing after the end\n\t\t\t// of that block, at the outer level of the script.  Detect that case and fall through to the handler for it at the end.\n\t\t\tint32_t completion_block_end = completion_block->token_->token_end_;\n\t\t\t\n\t\t\tif ((int)selection.location > completion_block_end)\n\t\t\t{\n\t\t\t\t // Selection is after end of completion_block\n\t\t\t\tcompletion_block = nullptr;\n\t\t\t}\n\t\t\t\n\t\t\tif (completion_block)\n\t\t\t{\n\t\t\t\tfor (EidosASTNode *script_block_node : script_root->children_)\n\t\t\t\t{\n\t\t\t\t\t// skip species/ticks specifiers, which are identifier token nodes at the top level of the AST with one child\n\t\t\t\t\tif ((script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (script_block_node->children_.size() == 1))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// script_block_node can have various children, such as an sX identifier, start and end ticks, a block type\n\t\t\t\t\t// identifier like late(), and then the root node of the compound statement for the script block.  We want to\n\t\t\t\t\t// decode the parts that are important to us, without the complication of making SLiMEidosBlock objects.\n\t\t\t\t\tEidosASTNode *block_statement_root = nullptr;\n\t\t\t\t\tSLiMEidosBlockType block_type = SLiMEidosBlockType::SLiMEidosEventEarly;\t// assume early() by default\n\t\t\t\t\t\n\t\t\t\t\tfor (EidosASTNode *block_child : script_block_node->children_)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *child_token = block_child->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (child_token->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst std::string &child_string = child_token->token_string_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (child_string.compare(gStr_first) == 0)\t\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosEventFirst;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_early) == 0)\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosEventEarly;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_late) == 0)\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosEventLate;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_initialize) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosInitializeCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_fitnessEffect) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosFitnessEffectCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_mutationEffect) == 0)\tblock_type = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_interaction) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosInteractionCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_mateChoice) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_modifyChild) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_recombination) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_mutation) == 0)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosMutationCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_survival) == 0)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosSurvivalCallback;\n\t\t\t\t\t\t\telse if (child_string.compare(gStr_reproduction) == 0)\t\tblock_type = SLiMEidosBlockType::SLiMEidosReproductionCallback;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Check for an sX designation on a script block and, if found, add a symbol for it\n\t\t\t\t\t\t\telse if ((block_child == script_block_node->children_[0]) && (child_string.length() >= 2))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (child_string[0] == 's')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbool all_numeric = true;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tfor (size_t idx = 1; idx < child_string.length(); ++idx)\n\t\t\t\t\t\t\t\t\t\tif (!isdigit(child_string[idx]))\n\t\t\t\t\t\t\t\t\t\t\tall_numeric = false;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (all_numeric)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tEidosGlobalStringID constant_id = EidosStringRegistry::GlobalStringIDForString(child_string);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(constant_id, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (child_token->token_type_ == EidosTokenType::kTokenLBrace)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblock_statement_root = block_child;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (child_token->token_type_ == EidosTokenType::kTokenFunction)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We handle function blocks a bit differently; see below\n\t\t\t\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosUserDefinedFunction;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (block_child->children_.size() >= 4)\n\t\t\t\t\t\t\t\tblock_statement_root = block_child->children_[3];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Now we know the type of the node, and the root node of its compound statement; extract what we want\n\t\t\t\t\tif (block_statement_root)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The species/community symbols are  defined in all blocks except initialize() blocks; we need to add\n\t\t\t\t\t\t// and remove them dynamically so that each block has it defined or not defined as necessary.  Since\n\t\t\t\t\t\t// the completion block is last, the symbols will be correctly defined at the end of this process.\n\t\t\t\t\t\tif (block_type == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::vector<EidosGlobalStringID> symbol_ids = (*typeTable)->AllSymbolIDs();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (EidosGlobalStringID symbol_id : symbol_ids)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosTypeSpecifier typeSpec = (*typeTable)->GetTypeForSymbol(symbol_id);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((typeSpec.type_mask == kEidosValueMaskObject) && ((typeSpec.object_class == gSLiM_Community_Class) || (typeSpec.object_class == gSLiM_Species_Class)))\n\t\t\t\t\t\t\t\t\t(*typeTable)->RemoveTypeForSymbol(symbol_id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_community, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Community_Class});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (community)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (Species *species : community->AllSpecies())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tEidosGlobalStringID species_symbol = species->self_symbol_.first;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(species_symbol, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Species_Class});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// We don't have a community object, so we don't have a vector of species; this is usually because of a failed parse\n\t\t\t\t\t\t\t\t// In this case, we try to keep things functional by just assuming the single-species case and defining \"sim\"\n\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_sim, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Species_Class});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// The slimgui symbol is always available within a block, but not at the top level\n\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_slimgui, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMgui_Class});\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Do the same for the zero-tick functions, which should be defined in initialization() blocks and\n\t\t\t\t\t\t// not in other blocks; we add and remove them dynamically so they are defined as appropriate.  We ought\n\t\t\t\t\t\t// to do this for other block-specific stuff as well (like the stuff below), but it is unlikely to matter.\n\t\t\t\t\t\t// Note that we consider the zero-gen functions to always be defined inside function blocks, since the\n\t\t\t\t\t\t// function might be called from the zero gen (we have no way of knowing definitively).\n\t\t\t\t\t\tif ((block_type == SLiMEidosBlockType::SLiMEidosInitializeCallback) || (block_type == SLiMEidosBlockType::SLiMEidosUserDefinedFunction))\n\t\t\t\t\t\t\tCommunity::AddZeroTickFunctionsToMap(**functionMap);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tCommunity::RemoveZeroTickFunctionsFromMap(**functionMap);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (script_block_node == completion_block)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This is the block we're actually completing in the context of; it is also the last block in the script\n\t\t\t\t\t\t\t// snippet that we're working with.  We want to first define any callback-associated variables for the block.\n\t\t\t\t\t\t\t// Note that self is not defined inside functions, even though they are SLiMEidosBlocks; we pretend we are Eidos.\n\t\t\t\t\t\t\tif (block_type == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\t\t\t\t(*typeTable)->RemoveTypeForSymbol(gID_self);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_self, EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class});\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tswitch (block_type)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->RemoveSymbolsOfClass(gSLiM_Subpopulation_Class);\t// subpops defined upstream from us still do not exist for us\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_mut,\t\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Mutation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_homozygous,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_effect,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_distance,\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_strength,\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_receiver,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_exerter,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_sourceSubpop,\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gEidosID_weights,\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_child,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_parent1,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_isCloning,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_isSelfing,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_parent2,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_sourceSubpop,\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_haplosome1,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_haplosome2,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_breakpoints,\t\tEidosTypeSpecifier{kEidosValueMaskInt, nullptr});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_mut,\t\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Mutation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_parent,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_element,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_GenomicElement_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_haplosome,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_originalNuc,\t\tEidosTypeSpecifier{kEidosValueMaskInt, nullptr});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_surviving,\t\tEidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_fitness,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_draw,\t\t\tEidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_individual,\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Individual_Class});\n\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(gID_subpop,\t\t\tEidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class});\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Similar to the local variables that are defined for callbacks above, here we need to define the parameters to the\n\t\t\t\t\t\t\t\t\t// function, by parsing the relevant AST nodes; this is parallel to EidosTypeInterpreter::TypeEvaluate_FunctionDecl()\n\t\t\t\t\t\t\t\t\tEidosASTNode *function_declaration_node = script_block_node->children_[0];\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *param_list_node = function_declaration_node->children_[2];\n\t\t\t\t\t\t\t\t\tconst std::vector<EidosASTNode *> &param_nodes = param_list_node->children_;\n\t\t\t\t\t\t\t\t\tstd::vector<std::string> used_param_names;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tfor (EidosASTNode *param_node : param_nodes)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tconst std::vector<EidosASTNode *> &param_children = param_node->children_;\n\t\t\t\t\t\t\t\t\t\tint param_children_count = (int)param_children.size();\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif ((param_children_count == 2) || (param_children_count == 3))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tEidosTypeSpecifier &param_type = param_children[0]->typespec_;\n\t\t\t\t\t\t\t\t\t\t\tconst std::string &param_name = param_children[1]->token_->token_string_;\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t// Check param_name; it needs to not be used by another parameter\n\t\t\t\t\t\t\t\t\t\t\tif (std::find(used_param_names.begin(), used_param_names.end(), param_name) != used_param_names.end())\n\t\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\tif (param_children_count >= 2)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t// param_node has 2 or 3 children (type, identifier, [default]); we don't care about default values\n\t\t\t\t\t\t\t\t\t\t\t\t(*typeTable)->SetTypeForSymbol(EidosStringRegistry::GlobalStringIDForString(param_name), param_type);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType: break;\t// never hit\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (script_block_node == completion_block)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Make a type interpreter and add symbols to our type table using it\n\t\t\t\t\t\t\t// We use SLiMTypeInterpreter because we want to pick up definitions of SLiM constants\n\t\t\t\t\t\t\tSLiMTypeInterpreter typeInterpreter(block_statement_root, **typeTable, **functionMap, **callTypeTable);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttypeInterpreter.TypeEvaluateInterpreterBlock_AddArgumentCompletions(argNameCompletions, script_string.length());\t// result not used\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn YES;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This is not the block we're completing in.  We want to add symbols for any constant-defining calls\n\t\t\t\t\t\t\t// in this block; apart from that, this block cannot affect the completion block, due to scoping.\n\t\t\t\t\t\t\t// However, constant-defining calls might use the types of variables, like defineConstant(\"foo\", bar)\n\t\t\t\t\t\t\t// where the type of foo comes from the type of bar; so we need to keep track of all symbols even\n\t\t\t\t\t\t\t// though they will fall out of scope.  We therefore use a separate local type table with a reference\n\t\t\t\t\t\t\t// upward to our main type table.\n\t\t\t\t\t\t\tEidosTypeTable scopedTypeTable(**typeTable);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Make a type interpreter and add symbols to our type table using it\n\t\t\t\t\t\t\t// We use SLiMTypeInterpreter because we want to pick up definitions of SLiM constants\n\t\t\t\t\t\t\tSLiMTypeInterpreter typeInterpreter(block_statement_root, scopedTypeTable, **functionMap, **callTypeTable);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttypeInterpreter.SetExternalTypeTable(*typeTable);\t\t// defined constants/variables should also go into the global scope\n\t\t\t\t\t\t\ttypeInterpreter.TypeEvaluateInterpreterBlock();\t\t\t// result not used\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// We drop through to here if we have a bad or empty script root, or if the final script block (completion_block) didn't\n\t\t// have a compound statement (meaning its starting brace has not yet been typed), or if we're completing outside of any\n\t\t// existing script block.  In these sorts of cases, we want to return completions for the outer level of a SLiM script.\n\t\t// This means that standard Eidos language keywords like \"while\", \"next\", etc. are not legal, but SLiM script block\n\t\t// keywords like \"first\", \"early\", \"late\", \"mutationEffect\", \"fitnessEffect\", \"interaction\", \"mateChoice\", \"modifyChild\",\n\t\t// \"recombination\", \"mutation\", \"survival\", and \"reproduction\" are.  We also add \"species\" and \"ticks\" here for\n\t\t// multispecies models.\n\t\t[keywords removeAllObjects];\n\t\t[keywords addObjectsFromArray:@[\n\t\t\t@\"initialize() {\\n\\n}\\n\",\n\t\t\t@\"first() {\\n\\n}\\n\",\n\t\t\t@\"early() {\\n\\n}\\n\",\n\t\t\t@\"late() {\\n\\n}\\n\",\n\t\t\t@\"mutationEffect() {\\n\\n}\\n\",\n\t\t\t@\"fitnessEffect() {\\n\\n}\\n\",\n\t\t\t@\"interaction() {\\n\\n}\\n\",\n\t\t\t@\"mateChoice() {\\n\\n}\\n\",\n\t\t\t@\"modifyChild() {\\n\\n}\\n\",\n\t\t\t@\"recombination() {\\n\\n}\\n\",\n\t\t\t@\"mutation() {\\n\\n}\\n\",\n\t\t\t@\"survival() {\\n\\n}\\n\",\n\t\t\t@\"reproduction() {\\n\\n}\\n\",\n\t\t\t@\"function (void)name(void) {\\n\\n}\\n\",\n\t\t\t@\"species\",\n\t\t\t@\"ticks\"]];\n\t\t\n\t\t// At the outer level, functions are also not legal\n\t\t(*functionMap)->clear();\n\t\t\n\t\t// And no variables exist except SLiM objects like pX, gX, mX, sX and species symbols\n\t\tstd::vector<EidosGlobalStringID> symbol_ids = (*typeTable)->AllSymbolIDs();\n\t\t\n\t\tfor (EidosGlobalStringID symbol_id : symbol_ids)\n\t\t{\n\t\t\tEidosTypeSpecifier typeSpec = (*typeTable)->GetTypeForSymbol(symbol_id);\n\t\t\t\n\t\t\tif ((typeSpec.type_mask != kEidosValueMaskObject) || (typeSpec.object_class == gSLiM_Community_Class) || (typeSpec.object_class == gSLiM_SLiMgui_Class))\n\t\t\t\t(*typeTable)->RemoveTypeForSymbol(symbol_id);\n\t\t}\n\t\t\n\t\treturn YES;\n\t}\n\t\n\treturn NO;\n}\n\n\n//\n//\tNSWindow delegate methods\n//\n#pragma mark -\n#pragma mark NSWindow delegate\n\n- (void)windowWillClose:(NSNotification *)notification\n{\n\t// We are the delegate of our own window, and of all of our graph windows, too\n\tNSWindow *closingWindow = [notification object];\n\t\n\tif (closingWindow == [self window])\n\t{\n\t\t//NSLog(@\"SLiMWindowController window closing...\");\n\t\t[closingWindow setDelegate:nil];\n\t\t\n\t\t[self cleanup];\n\t\t\n\t\t// NSWindowController takes care of the rest; we don't need to release ourselves, or ask our document to close, or anything\n\t}\n\telse if (closingWindow == graphWindowMutationFreqSpectrum)\n\t{\n\t\t//NSLog(@\"graphWindowMutationFreqSpectrum window closing...\");\n\t\t[graphWindowMutationFreqSpectrum autorelease];\n\t\tgraphWindowMutationFreqSpectrum = nil;\n\t}\n\telse if (closingWindow == graphWindowMutationFreqTrajectories)\n\t{\n\t\t//NSLog(@\"graphWindowMutationFreqTrajectories window closing...\");\n\t\t[graphWindowMutationFreqTrajectories autorelease];\n\t\tgraphWindowMutationFreqTrajectories = nil;\n\t}\n\telse if (closingWindow == graphWindowMutationLossTimeHistogram)\n\t{\n\t\t//NSLog(@\"graphWindowMutationLossTimeHistogram window closing...\");\n\t\t[graphWindowMutationLossTimeHistogram autorelease];\n\t\tgraphWindowMutationLossTimeHistogram = nil;\n\t}\n\telse if (closingWindow == graphWindowMutationFixationTimeHistogram)\n\t{\n\t\t//NSLog(@\"graphWindowMutationFixationTimeHistogram window closing...\");\n\t\t[graphWindowMutationFixationTimeHistogram autorelease];\n\t\tgraphWindowMutationFixationTimeHistogram = nil;\n\t}\n\telse if (closingWindow == graphWindowFitnessOverTime)\n\t{\n\t\t//NSLog(@\"graphWindowFitnessOverTime window closing...\");\n\t\t[graphWindowFitnessOverTime autorelease];\n\t\tgraphWindowFitnessOverTime = nil;\n\t}\n\telse if (closingWindow == graphWindowPopulationVisualization)\n\t{\n\t\t//NSLog(@\"graphWindowPopulationVisualization window closing...\");\n\t\t[graphWindowPopulationVisualization autorelease];\n\t\tgraphWindowPopulationVisualization = nil;\n\t}\n\telse if ([linkedWindows containsObject:closingWindow])\n\t{\n\t\t//NSLog(@\"linked window window closing...\");\n\t\t[linkedWindows removeObject:closingWindow];\n\t}\n\t\n\t// If all of our subsidiary graph windows have been closed, we are effectively back at square one regarding window placement\n\tif (!graphWindowMutationFreqSpectrum && !graphWindowMutationFreqTrajectories && !graphWindowMutationLossTimeHistogram && !graphWindowMutationFixationTimeHistogram && !graphWindowFitnessOverTime && !graphWindowPopulationVisualization)\n\t\topenedGraphCount = 0;\n}\n\n- (void)windowDidResize:(NSNotification *)notification\n{\n\t//[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n\t\n\tNSWindow *resizingWindow = [notification object];\n\tNSView *contentView = [resizingWindow contentView];\n\n\tif ([contentView isKindOfClass:[GraphView class]])\n\t\t[(GraphView *)contentView graphWindowResized];\n\t\n\tif (resizingWindow == [self window])\n\t\t[self updatePopulationViewHiding];\n}\n\n- (void)windowDidMove:(NSNotification *)notification\n{\n\t//[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n}\n\n\n//\n//\tNSTextView delegate methods\n//\n#pragma mark -\n#pragma mark NSTextView delegate\n\n- (void)updateStatusFieldFromSelection\n{\n\tNSAttributedString *attributedSignature = [scriptTextView attributedSignatureForScriptString:[scriptTextView string] selection:[scriptTextView selectedRange]];\n\tNSString *signatureString = [attributedSignature string];\n\t\n\t// Here we do a little quick-and-dirty patching in order to show signatures when inside callback definitions\n\tif ([signatureString hasSuffix:@\"unrecognized call\"])\n\t{\n\t\tconst EidosCallSignature *sig = nullptr;\n\t\t\n\t\tif ([signatureString hasPrefix:@\"initialize()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"initialize\", nullptr, kEidosValueMaskVOID)));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"first()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"first\", nullptr, kEidosValueMaskVOID)));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"early()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"early\", nullptr, kEidosValueMaskVOID)));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"late()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"late\", nullptr, kEidosValueMaskVOID)));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"mutationEffect()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mutationEffect\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_S(\"mutationType\", gSLiM_MutationType_Class)->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"fitnessEffect()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"fitnessEffect\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"interaction()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"interaction\", nullptr, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddObject_S(\"interactionType\", gSLiM_InteractionType_Class)->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"mateChoice()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mateChoice\", nullptr, kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"modifyChild()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"modifyChild\", nullptr, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"recombination()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"recombination\", nullptr, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible)->AddIntString_OSN(\"chromosome\", gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"mutation()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"mutation\", nullptr, kEidosValueMaskLogical | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Mutation_Class))->AddObject_OSN(\"mutationType\", gSLiM_MutationType_Class, gStaticEidosValueNULLInvisible)->AddObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"survival()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"survival\", nullptr, kEidosValueMaskNULL | kEidosValueMaskLogical | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Subpopulation_Class))->AddObject_OS(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\telse if ([signatureString hasPrefix:@\"reproduction()\"])\n\t\t{\n\t\t\tstatic EidosCallSignature_CSP callbackSig = nullptr;\n\t\t\t\n\t\t\tif (!callbackSig)\n\t\t\t\tcallbackSig = EidosCallSignature_CSP((new EidosFunctionSignature(\"reproduction\", nullptr, kEidosValueMaskVOID))->AddObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULLInvisible)->AddString_OSN(\"sex\", gStaticEidosValueNULLInvisible));\n\t\t\t\n\t\t\tsig = callbackSig.get();\n\t\t}\n\t\t\n\t\tif (sig)\n\t\t\tattributedSignature = [NSAttributedString eidosAttributedStringForCallSignature:sig size:11.0];\n\t}\n\t\n\t[scriptStatusTextField setAttributedStringValue:attributedSignature];\n}\n\n- (void)textViewDidChangeSelection:(NSNotification *)notification\n{\n\tNSTextView *textView = (NSTextView *)[notification object];\n\t\n\tif (textView == scriptTextView)\n\t{\n\t\t[self updateStatusFieldFromSelection];\n\t}\n}\n\n\n//\n//\tNSTableView delegate methods\n//\n#pragma mark -\n#pragma mark NSTableView delegate\n\n- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\treturn NO;\n}\n\n- (void)tableViewSelectionDidChange:(NSNotification *)aNotification\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tNSTableView *aTableView = [aNotification object];\n\t\t\n\t\tif (aTableView == subpopTableView && !reloadingSubpopTableview)\t\t// see comment in -updateAfterTick after reloadingSubpopTableview\n\t\t{\n\t\t\tPopulation &population = displaySpecies->population_;\n\t\t\tint subpopCount = (int)population.subpops_.size();\n\t\t\tauto popIter = population.subpops_.begin();\n\t\t\t\n\t\t\tfor (int i = 0; i < subpopCount; ++i)\n\t\t\t{\n\t\t\t\tpopIter->second->gui_selected_ = [subpopTableView isRowSelected:i];\n\t\t\t\tpopIter++;\n\t\t\t}\n\t\t\t\n\t\t\t// If the selection has changed, that means that our private mutation tallies need to be recomputed\n\t\t\tpopulation.InvalidateMutationReferencesCache();\t// force a retally\n\t\t\tpopulation.TallyMutationReferencesAcrossPopulation_SLiMgui();\n\t\t\t\n\t\t\t// It's a bit hard to tell for sure whether we need to update or not, since a selected subpop might have been removed from the tableview;\n\t\t\t// selection changes should not happen often, so we can just always update, I think.\n\t\t\t[populationView setNeedsDisplay:YES];\n\t\t\t[self updatePopulationViewHiding];\n\t\t\t\n\t\t\t[chromosomeZoomed setNeedsDisplayInInterior];\n\t\t}\n\t}\n}\n\n\n//\n//\tNSTableView datasource methods\n//\n#pragma mark -\n#pragma mark NSTableView datasource\n\n- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tif (aTableView == subpopTableView)\n\t\t{\n\t\t\treturn displaySpecies->population_.subpops_.size();\n\t\t}\n\t\telse if (aTableView == mutTypeTableView)\n\t\t{\n\t\t\treturn community->AllMutationTypes().size();\n\t\t}\n\t\telse if (aTableView == genomicElementTypeTableView)\n\t\t{\n\t\t\treturn community->AllGenomicElementTypes().size();\n\t\t}\n\t\telse if (aTableView == interactionTypeTableView)\n\t\t{\n\t\t\treturn community->AllInteractionTypes().size();\n\t\t}\n\t\telse if (aTableView == scriptBlocksTableView)\n\t\t{\n\t\t\treturn community->AllScriptBlocks().size();\n\t\t}\n\t}\n\t\n\treturn 0;\n}\n\n- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tif (aTableView == subpopTableView)\n\t\t{\n\t\t\tPopulation &population = displaySpecies->population_;\n\t\t\tint subpopCount = (int)population.subpops_.size();\n\t\t\t\n\t\t\tif (rowIndex < subpopCount)\n\t\t\t{\n\t\t\t\tauto popIter = population.subpops_.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(popIter, rowIndex);\n\t\t\t\tslim_objectid_t subpop_id = popIter->first;\n\t\t\t\tSubpopulation *subpop = popIter->second;\n\t\t\t\t\n\t\t\t\tif (aTableColumn == subpopIDColumn)\n\t\t\t\t{\n\t\t\t\t\treturn [NSString stringWithFormat:@\"p%lld\", (long long int)subpop_id];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == subpopSizeColumn)\n\t\t\t\t{\n\t\t\t\t\treturn [NSString stringWithFormat:@\"%lld\", (long long int)subpop->parent_subpop_size_];\n\t\t\t\t}\n\t\t\t\telse if (community->ModelType() == SLiMModelType::kModelTypeNonWF)\n\t\t\t\t{\n\t\t\t\t\t// in nonWF models selfing/cloning/sex rates/ratios are emergent, calculated from collected metrics\n\t\t\t\t\tdouble total_offspring = subpop->gui_offspring_cloned_M_ + subpop->gui_offspring_crossed_ + subpop->gui_offspring_empty_ + subpop->gui_offspring_selfed_;\n\t\t\t\t\t\n\t\t\t\t\tif (subpop->sex_enabled_)\n\t\t\t\t\t\ttotal_offspring += subpop->gui_offspring_cloned_F_;\t\t// avoid double-counting clones when we are modeling hermaphrodites\n\t\t\t\t\t\n\t\t\t\t\tif (aTableColumn == subpopSelfingRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!subpop->sex_enabled_ && (total_offspring > 0))\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->gui_offspring_selfed_ / total_offspring];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopFemaleCloningRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (total_offspring > 0)\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->gui_offspring_cloned_F_ / total_offspring];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopMaleCloningRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (total_offspring > 0)\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->gui_offspring_cloned_M_ / total_offspring];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopSexRatioColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (subpop->sex_enabled_ && (subpop->parent_subpop_size_ > 0))\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", 1.0 - subpop->parent_first_male_index_ / (double)subpop->parent_subpop_size_];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn @\"—\";\n\t\t\t\t}\n\t\t\t\telse\t// community->ModelType() == SLiMModelType::kModelTypeWF\n\t\t\t\t{\n\t\t\t\t\tif (aTableColumn == subpopSelfingRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (subpop->sex_enabled_)\n\t\t\t\t\t\t\treturn @\"—\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->selfing_fraction_];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopFemaleCloningRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->female_clone_fraction_];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopMaleCloningRateColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->male_clone_fraction_];\n\t\t\t\t\t}\n\t\t\t\t\telse if (aTableColumn == subpopSexRatioColumn)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (subpop->sex_enabled_)\n\t\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%.2f\", subpop->parent_sex_ratio_];\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn @\"—\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == mutTypeTableView)\n\t\t{\n\t\t\tconst std::map<slim_objectid_t,MutationType*> &mutationTypes = community->AllMutationTypes();\n\t\t\tint mutationTypeCount = (int)mutationTypes.size();\n\t\t\t\n\t\t\tif (rowIndex < mutationTypeCount)\n\t\t\t{\n\t\t\t\tauto mutTypeIter = mutationTypes.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(mutTypeIter, rowIndex);\n\t\t\t\tslim_objectid_t mutTypeID = mutTypeIter->first;\n\t\t\t\tMutationType *mutationType = mutTypeIter->second;\n\t\t\t\t\n\t\t\t\tif (aTableColumn == mutTypeIDColumn)\n\t\t\t\t{\n\t\t\t\t\tNSString *idString = [NSString stringWithFormat:@\"m%lld\", (long long int)mutTypeID];\n\t\t\t\t\t\n\t\t\t\t\tif (community->all_species_.size() > 1)\n\t\t\t\t\t\tidString = [idString stringByAppendingFormat:@\" %@\", [NSString stringWithUTF8String:mutationType->species_.avatar_.c_str()]];\n\t\t\t\t\t\n\t\t\t\t\treturn idString;\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == mutTypeDominanceColumn)\n\t\t\t\t{\n\t\t\t\t\treturn [NSString stringWithFormat:@\"%.3f\", mutationType->dominance_coeff_];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == mutTypeDFETypeColumn)\n\t\t\t\t{\n\t\t\t\t\tswitch (mutationType->dfe_type_)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase DFEType::kFixed:\t\t\treturn @\"fixed\";\n\t\t\t\t\t\tcase DFEType::kGamma:\t\t\treturn @\"gamma\";\n\t\t\t\t\t\tcase DFEType::kExponential:\t\treturn @\"exp\";\n\t\t\t\t\t\tcase DFEType::kNormal:\t\t\treturn @\"normal\";\n\t\t\t\t\t\tcase DFEType::kWeibull:\t\t\treturn @\"Weibull\";\n\t\t\t\t\t\tcase DFEType::kLaplace:\t\t\treturn @\"Laplace\";\n\t\t\t\t\t\tcase DFEType::kScript:\t\t\treturn @\"script\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == mutTypeDFEParamsColumn)\n\t\t\t\t{\n\t\t\t\t\tNSMutableString *paramString = [[NSMutableString alloc] init];\n\t\t\t\t\t\n\t\t\t\t\tif (mutationType->dfe_type_ == DFEType::kScript)\n\t\t\t\t\t{\n\t\t\t\t\t\t// DFE type 's' has parameters of type string\n\t\t\t\t\t\tfor (unsigned int paramIndex = 0; paramIndex < mutationType->dfe_strings_.size(); ++paramIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst char *dfe_string = mutationType->dfe_strings_[paramIndex].c_str();\n\t\t\t\t\t\t\tNSString *ns_dfe_string = [NSString stringWithUTF8String:dfe_string];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t[paramString appendFormat:@\"\\\"%@\\\"\", ns_dfe_string];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (paramIndex < mutationType->dfe_strings_.size() - 1)\n\t\t\t\t\t\t\t\t[paramString appendString:@\", \"];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// All other DFEs have parameters of type double\n\t\t\t\t\t\tfor (unsigned int paramIndex = 0; paramIndex < mutationType->dfe_parameters_.size(); ++paramIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNSString *paramSymbol = @\"\";\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tswitch (mutationType->dfe_type_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcase DFEType::kFixed:\t\t\tparamSymbol = @\"s\"; break;\n\t\t\t\t\t\t\t\tcase DFEType::kGamma:\t\t\tparamSymbol = (paramIndex == 0 ? @\"s̄\" : @\"α\"); break;\n\t\t\t\t\t\t\t\tcase DFEType::kExponential:\t\tparamSymbol = @\"s̄\"; break;\n\t\t\t\t\t\t\t\tcase DFEType::kNormal:\t\t\tparamSymbol = (paramIndex == 0 ? @\"s̄\" : @\"σ\"); break;\n\t\t\t\t\t\t\t\tcase DFEType::kWeibull:\t\t\tparamSymbol = (paramIndex == 0 ? @\"λ\" : @\"k\"); break;\n\t\t\t\t\t\t\t\tcase DFEType::kLaplace:\t\t\tparamSymbol = (paramIndex == 0 ? @\"s̄\" : @\"b\"); break;\n\t\t\t\t\t\t\t\tcase DFEType::kScript:\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t[paramString appendFormat:@\"%@=%.3f\", paramSymbol, mutationType->dfe_parameters_[paramIndex]];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (paramIndex < mutationType->dfe_parameters_.size() - 1)\n\t\t\t\t\t\t\t\t[paramString appendString:@\", \"];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn [paramString autorelease];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == genomicElementTypeTableView)\n\t\t{\n\t\t\tconst std::map<slim_objectid_t,GenomicElementType*> &genomicElementTypes = community->AllGenomicElementTypes();\n\t\t\tint genomicElementTypeCount = (int)genomicElementTypes.size();\n\t\t\t\n\t\t\tif (rowIndex < genomicElementTypeCount)\n\t\t\t{\n\t\t\t\tauto genomicElementTypeIter = genomicElementTypes.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(genomicElementTypeIter, rowIndex);\n\t\t\t\tslim_objectid_t genomicElementTypeID = genomicElementTypeIter->first;\n\t\t\t\tGenomicElementType *genomicElementType = genomicElementTypeIter->second;\n\t\t\t\t\n\t\t\t\tif (aTableColumn == genomicElementTypeIDColumn)\n\t\t\t\t{\n\t\t\t\t\tNSString *idString = [NSString stringWithFormat:@\"g%lld\", (long long int)genomicElementTypeID];\n\t\t\t\t\t\n\t\t\t\t\tif (community->all_species_.size() > 1)\n\t\t\t\t\t\tidString = [idString stringByAppendingFormat:@\" %@\", [NSString stringWithUTF8String:genomicElementType->species_.avatar_.c_str()]];\n\t\t\t\t\t\n\t\t\t\t\treturn idString;\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == genomicElementTypeColorColumn)\n\t\t\t\t{\n\t\t\t\t\treturn [self colorForGenomicElementType:genomicElementType withID:genomicElementTypeID];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == genomicElementTypeMutationTypesColumn)\n\t\t\t\t{\n\t\t\t\t\tNSMutableString *paramString = [[NSMutableString alloc] init];\n\t\t\t\t\t\n\t\t\t\t\tfor (unsigned int mutTypeIndex = 0; mutTypeIndex < genomicElementType->mutation_fractions_.size(); ++mutTypeIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationType *mutType = genomicElementType->mutation_type_ptrs_[mutTypeIndex];\n\t\t\t\t\t\tdouble mutTypeFraction = genomicElementType->mutation_fractions_[mutTypeIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\t[paramString appendFormat:@\"m%lld=%.3f\", (long long int)mutType->mutation_type_id_, mutTypeFraction];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutTypeIndex < genomicElementType->mutation_fractions_.size() - 1)\n\t\t\t\t\t\t\t[paramString appendString:@\", \"];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn [paramString autorelease];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == interactionTypeTableView)\n\t\t{\n\t\t\tconst std::map<slim_objectid_t,InteractionType*> &interactionTypes = community->AllInteractionTypes();\n\t\t\tint interactionTypeCount = (int)interactionTypes.size();\n\t\t\t\n\t\t\tif (rowIndex < interactionTypeCount)\n\t\t\t{\n\t\t\t\tauto interactionTypeIter = interactionTypes.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(interactionTypeIter, rowIndex);\n\t\t\t\tslim_objectid_t interactionTypeID = interactionTypeIter->first;\n\t\t\t\tInteractionType *interactionType = interactionTypeIter->second;\n\t\t\t\t\n\t\t\t\tif (aTableColumn == interactionTypeIDColumn)\n\t\t\t\t{\n\t\t\t\t\tNSString *idString = [NSString stringWithFormat:@\"i%lld\", (long long int)interactionTypeID];\n\t\t\t\t\t\n\t\t\t\t\treturn idString;\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == interactionTypeMaxDistanceColumn)\n\t\t\t\t{\n\t\t\t\t\treturn [NSString stringWithFormat:@\"%.3f\", interactionType->max_distance_];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == interactionTypeIFTypeColumn)\n\t\t\t\t{\n\t\t\t\t\tswitch (interactionType->if_type_)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase SpatialKernelType::kFixed:\t\t\t\treturn @\"fixed\";\n\t\t\t\t\t\tcase SpatialKernelType::kLinear:\t\t\treturn @\"linear\";\n\t\t\t\t\t\tcase SpatialKernelType::kExponential:\t\treturn @\"exp\";\n\t\t\t\t\t\tcase SpatialKernelType::kNormal:\t\t\treturn @\"normal\";\n\t\t\t\t\t\tcase SpatialKernelType::kCauchy:\t\t\treturn @\"Cauchy\";\n\t\t\t\t\t\tcase SpatialKernelType::kStudentsT:\t\t\treturn @\"Student's t\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == interactionTypeIFParamsColumn)\n\t\t\t\t{\n\t\t\t\t\tNSMutableString *paramString = [[NSMutableString alloc] init];\n\t\t\t\t\t\n\t\t\t\t\t// the first parameter is always the maximum interaction strength\n\t\t\t\t\t[paramString appendFormat:@\"f=%.3f\", interactionType->if_param1_];\n\t\t\t\t\t\n\t\t\t\t\t// append second parameters where applicable\n\t\t\t\t\tswitch (interactionType->if_type_)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase SpatialKernelType::kFixed:\n\t\t\t\t\t\tcase SpatialKernelType::kLinear:\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SpatialKernelType::kExponential:\n\t\t\t\t\t\t\t[paramString appendFormat:@\", β=%.3f\", interactionType->if_param2_];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SpatialKernelType::kNormal:\n\t\t\t\t\t\t\t[paramString appendFormat:@\", σ=%.3f\", interactionType->if_param2_];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SpatialKernelType::kCauchy:\n\t\t\t\t\t\t\t[paramString appendFormat:@\", γ=%.3f\", interactionType->if_param2_];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SpatialKernelType::kStudentsT:\n\t\t\t\t\t\t\t[paramString appendFormat:@\", ν=%.3f, σ=%.3f\", interactionType->if_param2_, interactionType->if_param3_];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn [paramString autorelease];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == scriptBlocksTableView)\n\t\t{\n\t\t\tstd::vector<SLiMEidosBlock*> &scriptBlocks = community->AllScriptBlocks();\n\t\t\tint scriptBlockCount = (int)scriptBlocks.size();\n\t\t\t\n\t\t\tif (rowIndex < scriptBlockCount)\n\t\t\t{\n\t\t\t\tSLiMEidosBlock *scriptBlock = scriptBlocks[rowIndex];\n\t\t\t\t\n\t\t\t\tif (aTableColumn == scriptBlocksIDColumn)\n\t\t\t\t{\n\t\t\t\t\tslim_objectid_t block_id = scriptBlock->block_id_;\n\t\t\t\t\tNSString *idString;\n\t\t\t\t\t\n\t\t\t\t\tif (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\t\tidString = @\"—\";\n\t\t\t\t\telse if (block_id == -1)\n\t\t\t\t\t\tidString = @\"—\";\n\t\t\t\t\telse\n\t\t\t\t\t\tidString = [NSString stringWithFormat:@\"s%lld\", (long long int)block_id];\n\t\t\t\t\t\n\t\t\t\t\tif ((community->all_species_.size() > 1) && scriptBlock->species_spec_)\n\t\t\t\t\t\tidString = [idString stringByAppendingFormat:@\" %@\", [NSString stringWithUTF8String:scriptBlock->species_spec_->avatar_.c_str()]];\n\t\t\t\t\telse if ((community->all_species_.size() > 1) && scriptBlock->ticks_spec_)\n\t\t\t\t\t\tidString = [idString stringByAppendingFormat:@\" %@\", [NSString stringWithUTF8String:scriptBlock->ticks_spec_->avatar_.c_str()]];\n\t\t\t\t\t\n\t\t\t\t\treturn idString;\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == scriptBlocksStartColumn)\n\t\t\t\t{\n\t\t\t\t\tif (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\t\treturn @\"—\";\n\t\t\t\t\telse if (!scriptBlock->tick_range_evaluated_)\n\t\t\t\t\t\treturn @\"?\";\n\t\t\t\t\telse if (scriptBlock->tick_range_is_sequence_ == false)\n\t\t\t\t\t\treturn @\"...\";\n\t\t\t\t\telse if (scriptBlock->tick_start_ == -1)\n\t\t\t\t\t\treturn @\"MIN\";\n\t\t\t\t\telse\n\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%lld\", (long long int)scriptBlock->tick_start_];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == scriptBlocksEndColumn)\n\t\t\t\t{\n\t\t\t\t\tif (scriptBlock->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\t\treturn @\"—\";\n\t\t\t\t\telse if (!scriptBlock->tick_range_evaluated_)\n\t\t\t\t\t\treturn @\"?\";\n\t\t\t\t\telse if (scriptBlock->tick_range_is_sequence_ == false)\n\t\t\t\t\t\treturn @\"...\";\n\t\t\t\t\telse if (scriptBlock->tick_end_ == SLIM_MAX_TICK + 1)\n\t\t\t\t\t\treturn @\"MAX\";\n\t\t\t\t\telse\n\t\t\t\t\t\treturn [NSString stringWithFormat:@\"%lld\", (long long int)scriptBlock->tick_end_];\n\t\t\t\t}\n\t\t\t\telse if (aTableColumn == scriptBlocksTypeColumn)\n\t\t\t\t{\n\t\t\t\t\tswitch (scriptBlock->type_)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\treturn @\"first()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\treturn @\"early()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\treturn @\"late()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\treturn @\"initialize()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\treturn @\"mutationEffect()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\treturn @\"fitnessEffect()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\treturn @\"interaction()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\treturn @\"mateChoice()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\treturn @\"modifyChild()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\treturn @\"recombination()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\treturn @\"mutation()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\treturn @\"survival()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\treturn @\"reproduction()\";\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosASTNode *function_decl_node = scriptBlock->root_node_->children_[0];\n\t\t\t\t\t\t\tEidosASTNode *function_name_node = function_decl_node->children_[1];\n\t\t\t\t\t\t\tconst std::string &function_name = function_name_node->token_->token_string_;\n\t\t\t\t\t\t\tNSString *functionName = [NSString stringWithUTF8String:function_name.c_str()];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn [functionName stringByAppendingString:@\"()\"];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\treturn @\"\";\t// never hit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn @\"\";\n}\n\n- (NSString *)tableView:(NSTableView *)aTableView toolTipForCell:(NSCell *)aCell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex mouseLocation:(NSPoint)mouseLocation\n{\n\tSpecies *displaySpecies = [self focalDisplaySpecies];\n\t\n\tif (displaySpecies)\n\t{\n\t\tif (aTableView == scriptBlocksTableView)\n\t\t{\n\t\t\tstd::vector<SLiMEidosBlock*> &scriptBlocks = community->AllScriptBlocks();\n\t\t\tint scriptBlockCount = (int)scriptBlocks.size();\n\t\t\t\n\t\t\tif (rowIndex < scriptBlockCount)\n\t\t\t{\n\t\t\t\tSLiMEidosBlock *scriptBlock = scriptBlocks[rowIndex];\n\t\t\t\tconst char *script_string = scriptBlock->compound_statement_node_->token_->token_string_.c_str();\n\t\t\t\tNSString *ns_script_string = [NSString stringWithUTF8String:script_string];\n\t\t\t\t\n\t\t\t\t// change whitespace to non-breaking spaces; we want to force AppKit not to wrap code\n\t\t\t\t// note this doesn't really prevent AppKit from wrapping our tooltip, and I'd also like to use Monaco 9; I think I need a custom popup to do that...\n\t\t\t\tns_script_string = [ns_script_string stringByReplacingOccurrencesOfString:@\" \" withString:@\"\\u00A0\"];\t\t// second string is an &nbsp;\n\t\t\t\tns_script_string = [ns_script_string stringByReplacingOccurrencesOfString:@\"\\t\" withString:@\"\\u00A0\\u00A0\\u00A0\"];\t\t// second string is three &nbsp;s\n\t\t\t\t\n\t\t\t\treturn ns_script_string;\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == mutTypeTableView)\n\t\t{\n\t\t\tconst std::map<slim_objectid_t,MutationType*> &mutationTypes = community->AllMutationTypes();\n\t\t\tint mutationTypeCount = (int)mutationTypes.size();\n\t\t\t\n\t\t\tif (rowIndex < mutationTypeCount)\n\t\t\t{\n\t\t\t\tauto mutTypeIter = mutationTypes.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(mutTypeIter, rowIndex);\n\t\t\t\tMutationType *mutationType = mutTypeIter->second;\n\t\t\t\t\n\t\t\t\t// If we're already showing the tooltip for this muttype, short-circuit; sometimes we get called twice with no exit\n\t\t\t\tif (functionGraphToolTipWindow && ([functionGraphToolTipWindow mutType] == mutationType))\n\t\t\t\t\treturn (id _Nonnull)nil;\t// get rid of the static analyzer warning\n\t\t\t\t\n\t\t\t\t//NSLog(@\"show DFE tooltip view here for mut ID %d!\", mutationType->mutation_type_id_);\n\t\t\t\t\n\t\t\t\t// Make the tooltip window, configure it, and display it\n\t\t\t\tif (!functionGraphToolTipWindow)\n\t\t\t\t\tfunctionGraphToolTipWindow = [SLiMFunctionGraphToolTipWindow new];\n\t\t\t\t\n\t\t\t\tNSPoint tipPoint = NSMakePoint(mouseLocation.x + 0, mouseLocation.y + 65);\n\t\t\t\t\n\t\t\t\ttipPoint = [[mutTypeTableView superview] convertPoint:tipPoint toView:nil];\n\t\t\t\tNSRect tipRect = NSMakeRect(tipPoint.x, tipPoint.y, 0, 0);\n\t\t\t\ttipPoint = [[mutTypeTableView window] convertRectToScreen:tipRect].origin;\n\t\t\t\t\n\t\t\t\t[functionGraphToolTipWindow setMutType:mutationType];\t// questionable for it to have a pointer to the mutation type, but I can't think of a way to crash it...\n\t\t\t\t[functionGraphToolTipWindow setTipPoint:tipPoint];\n\t\t\t\t[functionGraphToolTipWindow orderFront:nil];\n\t\t\t\t\n\t\t\t\t// Wire it to a tracking area so it gets taken down when the mouse moves; see mouseExited: below\n\t\t\t\tNSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:*rect\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toptions:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  owner:self\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   userInfo:@{@\"mut_id\" : [NSNumber numberWithInteger:mutationType->mutation_type_id_]}];\n\t\t\t\t\n\t\t\t\t[mutTypeTableView addTrackingArea:[trackingArea autorelease]];\n\t\t\t}\n\t\t}\n\t\telse if (aTableView == interactionTypeTableView)\n\t\t{\n\t\t\tconst std::map<slim_objectid_t,InteractionType*> &interactionTypes = community->AllInteractionTypes();\n\t\t\tint interactionTypeCount = (int)interactionTypes.size();\n\t\t\t\n\t\t\tif (rowIndex < interactionTypeCount)\n\t\t\t{\n\t\t\t\tauto interactionTypeIter = interactionTypes.begin();\n\t\t\t\t\n\t\t\t\tstd::advance(interactionTypeIter, rowIndex);\n\t\t\t\tInteractionType *interactionType = interactionTypeIter->second;\n\t\t\t\t\n\t\t\t\t// If we're already showing the tooltip for this muttype, short-circuit; sometimes we get called twice with no exit\n\t\t\t\tif (functionGraphToolTipWindow && ([functionGraphToolTipWindow interactionType] == interactionType))\n\t\t\t\t\treturn (id _Nonnull)nil;\t// get rid of the static analyzer warning\n\t\t\t\t\n\t\t\t\t//NSLog(@\"show DFE tooltip view here for interaction ID %d!\", interactionType->interaction_type_id_);\n\t\t\t\t\n\t\t\t\t// Make the tooltip window, configure it, and display it\n\t\t\t\tif (!functionGraphToolTipWindow)\n\t\t\t\t\tfunctionGraphToolTipWindow = [SLiMFunctionGraphToolTipWindow new];\n\t\t\t\t\n\t\t\t\tNSPoint tipPoint = NSMakePoint(mouseLocation.x + 0, mouseLocation.y + 65);\n\t\t\t\t\n\t\t\t\ttipPoint = [[interactionTypeTableView superview] convertPoint:tipPoint toView:nil];\n\t\t\t\tNSRect tipRect = NSMakeRect(tipPoint.x, tipPoint.y, 0, 0);\n\t\t\t\ttipPoint = [[interactionTypeTableView window] convertRectToScreen:tipRect].origin;\n\t\t\t\t\n\t\t\t\t[functionGraphToolTipWindow setInteractionType:interactionType];\t// questionable for it to have a pointer to the interaction type, but I can't think of a way to crash it...\n\t\t\t\t[functionGraphToolTipWindow setTipPoint:tipPoint];\n\t\t\t\t[functionGraphToolTipWindow orderFront:nil];\n\t\t\t\t\n\t\t\t\t// Wire it to a tracking area so it gets taken down when the mouse moves; see mouseExited: below\n\t\t\t\tNSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:*rect\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toptions:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  owner:self\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   userInfo:@{@\"int_id\" : [NSNumber numberWithInteger:interactionType->interaction_type_id_]}];\n\t\t\t\t\n\t\t\t\t[interactionTypeTableView addTrackingArea:[trackingArea autorelease]];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn (id _Nonnull)nil;\t// get rid of the static analyzer warning\n}\n\n- (void)hideMiniGraphToolTipWindow\n{\n\tif (functionGraphToolTipWindow)\n\t{\n\t\t[functionGraphToolTipWindow orderOut:nil];\n\t\t[functionGraphToolTipWindow setMutType:nullptr];\n\t\t[functionGraphToolTipWindow setInteractionType:nullptr];\n\t}\n}\n\n// Used to take down a custom tooltip window that we may have shown above, displaying a mutation type's DFE\n- (void)mouseExited:(NSEvent *)event\n{\n\tif (!functionGraphToolTipWindow)\n\t\treturn;\n\t\n\tNSTrackingArea *trackingArea = [event trackingArea];\n\tNSDictionary *userInfo = [trackingArea userInfo];\n\tNSObject *mut_id_object = [userInfo objectForKey:@\"mut_id\"];\n\tNSObject *int_id_object = [userInfo objectForKey:@\"int_id\"];\n\t\n\tif ((!mut_id_object && !int_id_object) || (mut_id_object && int_id_object))\n\t\treturn;\n\t\n\tif (mut_id_object)\n\t{\n\t\tslim_objectid_t mut_id = (slim_objectid_t)[(NSNumber *)mut_id_object integerValue];\n\t\t\n\t\tif (mut_id != [functionGraphToolTipWindow mutType]->mutation_type_id_)\n\t\t\treturn;\n\t\t\n\t\t//NSLog(@\"   take down DFE tooltip view here for mut ID %d!\", mut_id);\n\t\t\n\t\t[mutTypeTableView removeTrackingArea:trackingArea];\n\t}\n\telse if (int_id_object)\n\t{\n\t\tslim_objectid_t int_id = (slim_objectid_t)[(NSNumber *)int_id_object integerValue];\n\t\t\n\t\tif (int_id != [functionGraphToolTipWindow interactionType]->interaction_type_id_)\n\t\t\treturn;\n\t\t\n\t\t//NSLog(@\"   take down DFE tooltip view here for interaction ID %d!\", int_id);\n\t\t\n\t\t[interactionTypeTableView removeTrackingArea:trackingArea];\n\t}\n\t\n\t[self hideMiniGraphToolTipWindow];\n}\n\n\n//\n//\tNSSplitView delegate methods\n//\n#pragma mark -\n#pragma mark NSSplitView delegate\n\n- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview\n{\n\treturn YES;\n}\n\n- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex\n{\n\tif (splitView == overallSplitView)\n\t{\n\t\tif (fabs(proposedPosition - 294) < 20)\n\t\t\tproposedPosition = 294;\n\t}\n\t\n\t//NSLog(@\"pos in constrainSplitPosition: %f\", proposedPosition);\n\t\n\treturn proposedPosition;\n}\n\n- (void)splitViewDidResizeSubviews:(NSNotification *)notification\n{\n\t[[self document] setTransient:NO]; // Since the user has taken an interest in the window, clear the document's transient status\n}\n\n\n//\n//\tNSDrawer delegate methods\n//\n#pragma mark -\n#pragma mark NSDrawer delegate\n\n- (void)drawerWillClose:(NSNotification *)notification\n{\n\t[self hideMiniGraphToolTipWindow];\n}\n\n- (void)drawerDidOpen:(NSNotification *)notification\n{\n\t[buttonForDrawer setState:NSOnState];\n}\n\n- (void)drawerDidClose:(NSNotification *)notification\n{\n\t[buttonForDrawer setState:NSOffState];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/SLiMgui.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "SLiMgui/SLiMguiLegacy-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>slim</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeIconFile</key>\n\t\t\t<string>slim.icns</string>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMDocument</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>txt</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>NSStringPboardType</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>public.plain-text</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMDocument</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>pdf</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>application/pdf</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>PDF document</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>com.adobe.pdf</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMPDFDocument</string>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>5.2</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016–2025 Benjamin C. Haller, http://messerlab.org/slim/. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>UTExportedTypeDeclarations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>UTTypeConformsTo</key>\n\t\t\t<array>\n\t\t\t\t<string>public.text</string>\n\t\t\t</array>\n\t\t\t<key>UTTypeDescription</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>UTTypeIconFile</key>\n\t\t\t<string>slim.icns</string>\n\t\t\t<key>UTTypeIdentifier</key>\n\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t<key>UTTypeReferenceURL</key>\n\t\t\t<string>https://messerlab.org/slim/</string>\n\t\t\t<key>UTTypeTagSpecification</key>\n\t\t\t<dict>\n\t\t\t\t<key>com.apple.nspboard-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>NSStringPboardType</string>\n\t\t\t\t</array>\n\t\t\t\t<key>com.apple.ostype</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>SLiM</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.filename-extension</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>slim</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.mime-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>text/plain</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "SLiMgui/SLiMguiLegacy_multi-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>slim</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeIconFile</key>\n\t\t\t<string>slim.icns</string>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMDocument</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>txt</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>text/plain</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>NSStringPboardType</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>public.plain-text</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMDocument</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>pdf</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeMIMETypes</key>\n\t\t\t<array>\n\t\t\t\t<string>application/pdf</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>PDF document</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSItemContentTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>com.adobe.pdf</string>\n\t\t\t</array>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>SLiMPDFDocument</string>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>5.2</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.developer-tools</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016–2025 Benjamin C. Haller, http://messerlab.org/slim/. All rights reserved.</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n\t<key>UTExportedTypeDeclarations</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>UTTypeConformsTo</key>\n\t\t\t<array>\n\t\t\t\t<string>public.text</string>\n\t\t\t</array>\n\t\t\t<key>UTTypeDescription</key>\n\t\t\t<string>SLiM model</string>\n\t\t\t<key>UTTypeIconFile</key>\n\t\t\t<string>slim.icns</string>\n\t\t\t<key>UTTypeIdentifier</key>\n\t\t\t<string>edu.messerlab.slim</string>\n\t\t\t<key>UTTypeReferenceURL</key>\n\t\t\t<string>https://messerlab.org/slim/</string>\n\t\t\t<key>UTTypeTagSpecification</key>\n\t\t\t<dict>\n\t\t\t\t<key>com.apple.nspboard-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>NSStringPboardType</string>\n\t\t\t\t</array>\n\t\t\t\t<key>com.apple.ostype</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>SLiM</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.filename-extension</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>slim</string>\n\t\t\t\t</array>\n\t\t\t\t<key>public.mime-type</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>text/plain</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "SLiMgui/SLiMguiLegacy_multi.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SLiMgui/Tip_END.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 The end\n\\b0\\fs26 \\\n\\\nThat's all the tips available for now!  This panel won't come up again unless you (1) rewind to the first tip now, (2) reset all panels in SLiMgui's Preferences, OR (3) upgrade to a newer version of SLiMgui with additional tips.\\\n\\\nSpeaking of more tips, we're always trying to make SLiM more approachable.  If you have suggestions for new tips (things you found confusing about SLiM when you first started using it, hidden features you only discovered later, etc.), please let us know!  You can email us with suggestions using the \"Send Feedback on SLiM\" menu item in the Help menu:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width4580 \\height2780\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\nNotice there are also menu items there for others ways to stay in touch with us, including the slim-announce and slim-discuss mailing lists and the SLiM home page.  Thanks!  Enjoy SLiM!}"
  },
  {
    "path": "SLiMgui/Tips/Tip 1 optclick for help.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;\\f2\\fnil\\fcharset0 Menlo-Regular;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Option-click for help\n\\b0\\fs26 \\\n\\\nIn SLiMgui, you can option-click on any keyword, function, method, operator, etc., in the script view:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width3800 \\height1720\n}}\n\\f0\\fs26 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nNote the crosshairs cursor.  This will bring up the Help panel with targeted help about the item you option-clicked \\'96 in this case, the \n\\f2\\fs24 initializeMutationRate()\n\\f0\\fs26  function:\\\n\n\\fs18 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 5.tiff \\width9240 \\height3780\n}}\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n(For those not up on the jargon: to \"option-click\" means to hold down the \"option\" key, also knowns as the \"alt\" key, and then click on something.)}"
  },
  {
    "path": "SLiMgui/Tips/Tip 10 generation textfield.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Advancing to a given generation\n\\b0\\fs26 \\\n\\\nIn SLiMgui, there is a text field that shows the generation number:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width3220 \\height600\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis textfield has a hidden feature.  You can click in it to select the generation number, and then type a new number:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width3220 \\height600\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nWhen you press return, SLiMgui will play the simulation forward to the beginning of the generation you specified:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width3220 \\height600\n}}}"
  },
  {
    "path": "SLiMgui/Tips/Tip 11 chromosome subrange.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Displaying a subrange of the chromosome\n\\b0\\fs26 \\\n\\\nSLiMgui displays a mysterious blue strip above the main chromosome view:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width4720 \\height1920\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis strip is for selecting a subrange of the chromosome for display in the view below.  Just click and drag out a selection in the top strip, and the chromosome view will show you information about the selected range:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 3.tiff \\width4720 \\height2160\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nYou can click and drag the selection endpoint flags to adjust the selection, or a simple click in the top strip will go back to displaying the full chromosome.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 12 see script object text.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Seeing the code for defined script objects\n\\b0\\fs26 \\\n\\\nThere's a drawer on SLiMgui's window that can be opened by clicking the drawer button:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width720 \\height720\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe drawer that opens shows some useful additional information about the model running.  You can see a table of the active mutation types, and another of the genomic element types that have been defined, for example.  There is also a table showing the script blocks that have been defined.  There's a little hidden feature in SLiMgui: if you hover the mouse over the entries in that table, the code for the script blocks will be displayed in a tooltip:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width4000 \\height2540\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIn most situations this isn't important, since you can see the code for your script blocks in the script area anyway.  But if your model is dynamically adding and removing script blocks, perhaps with dynamically generated code for the added blocks, this feature can provide a very useful window into what script blocks currently exist in your running model.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 13 speed slider.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 The play speed slider\n\\b0\\fs26 \\\n\\\nThere's a little slider under the Play button in SLiMgui:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width3260 \\height1500\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis slider controls the speed at which SLiMgui plays forward the simulation.  Normally it is set to play at full speed, but it can sometimes be quite useful to slow it down.  This allows you to see the changes in each generation, one by one, without having to click the Step button repeatedly, for example.  It can also be quite useful in teaching situations, so that you can talk over a running model with time to explain what is happening.  Just drag the slider to the speed you want.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 14 console window.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 The Eidos console window\n\\b0\\fs26 \\\n\\\nThere is a full Eidos interpreter console available in SLiMgui, for direct access to the scripting environment while a simulation is running.  Just click on the Console button, at the top of the scripting area of the window:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width920 \\height800\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis opens the console window:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width8140 \\height6540\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIn this window, you can immediately execute any Eidos commands you wish.  These commands can inspect or even alter the state of the currently running simulation.  In the example above, a sorted list of the positions of all segregating mutations in the simulation has been printed.  This can be a good way to experiment with code for a new script event; once you've figured out how to do what you want, you can copy the final code over into your simulation script.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 15 variable browser.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;\\f2\\fnil\\fcharset0 Menlo-Regular;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 The variable browser\n\\b0\\fs26 \\\n\\\nSLiMgui provides an easy way to inspect the state of the objects underlying your running simulation.  Just click on the Variable Browser button at the top of the scripting pane:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width920 \\height800\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis opens the variable browser:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width8760 \\height5320\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nInitially, all of the top-level constants and variables defined in the simulation are displayed (constants are shown in gray, variables in black).  Variables that are objects have subvalues that can be revealed by clicking the disclosure triangle to the left of their name.  Expanding \n\\f2\\fs24 sim\n\\f0\\fs26 , for example, we can see the state defining the \n\\f2\\fs24 SLiMSim\n\\f0\\fs26  object that represents the running simulation:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width8760 \\height5320\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe objects accessible through \n\\f2\\fs24 sim\n\\f0\\fs26 , like \n\\f2\\fs24 sim.chromosome\n\\f0\\fs26 , can be expanded in turn, and you can browse through the whole simulation in this manner.  The browser automatically updates when the simulation changes state, giving you a live view into the internals of SLiM.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 16 chromosome muttypes.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;\\f2\\fnil\\fcharset0 Menlo-Regular;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9340\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Displaying only one mutation type\n\\b0\\fs26 \\\n\\\nSome simulations, particularly those involving neutral background mutations, can present a rather cluttered impression in the chromosome view:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width8420 \\height1260\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis simulation does involve QTLs of mutation type \n\\f2\\fs24 m2\n\\f0\\fs26 , but they're awfully hard to see among all the neutral mutations.  You can bring up a context menu on the chromosome view by right-clicking or control-clicking on it:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 4.tiff \\width8420 \\height1620\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nSelecting \n\\f2\\fs24 m2\n\\f0\\fs26 , the mutation type for the QTLs, then provides an uncluttered view showing only mutations of that type:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width8420 \\height1260\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nWith several mutation types, you can also select any subset of the mutation types for display; in a model with \n\\f2\\fs24 m1\n\\f0\\fs26 , \n\\f2\\fs24 m2\n\\f0\\fs26 , and \n\\f2\\fs24 m3\n\\f0\\fs26 , you could display \n\\f2\\fs24 m1\n\\f0\\fs26  and \n\\f2\\fs24 m3\n\\f0\\fs26  but not \n\\f2\\fs24 m2\n\\f0\\fs26 , for example.\\\n\\\nYou can restore the chromosome view to showing all mutation types by selecting \"Display all mutations\" from the context menu.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 17 population display options.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9340\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Alternative population visualizations\n\\b0\\fs26 \\\n\\\nThe default visualization for the population shows every individual in the selected subpopulations, colored according to fitness:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 6.tiff \\width7720 \\height2920\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis simulation has three subpopulations, one maladapted and two relatively well-adapted.  It can be useful to view the population differently, however.  To do so, control-click or right-click on the population view, and choose a different visualization from the context menu:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 7.tiff \\width7720 \\height2920\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe \"fitness line plot\" style shows one line per supopulation, with the \n\\i x\n\\i0  axis being fitness and the \n\\i y\n\\i0  axis being frequency.  It is therefore a set of superimposed fitness histograms, in essence:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 8.tiff \\width7720 \\height2920\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nHere the patterns of genetic diversity and fitness can be seen in a somewhat different light.  The \"fitness bar plot\" style shows a single histogram for fitness across all of the selected subpopulations:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 9.tiff \\width7720 \\height2920\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nDepending upon what it is you want to know, each of these visualization styles might prove useful.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 18 profiling simulations.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9340\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Profiling simulations\n\\b0\\fs26 \\\n\\\nFor complex simulations that take a long time to run, it can often be useful to find out where SLiM is spending most of its time.  Such an analysis, called a \n\\i profile\n\\i0 , can direct optimization efforts in your modeling, and can even help to find bugs.  Beginning in version 2.4, SLiMgui now supports collecting such profile information for your models.  Just click the small profile button (with the stopwatch icon) that now overlaps the play button:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic profile_button.jpg \\width2860 \\height1400\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe simulation will play forward as if you had clicked play, but it will profile the simulation as it runs.  When the run completes (or when you click the profile button again to stop profiling), SLiMgui will open a profile report window:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic report.jpg \\width6080 \\height2360\n}}\n\\f0\\fs26 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis report contains all sorts of information about the runtime performance of your model; see the SLiM manual for more details.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 19 chromosome haplotypes.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9340\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Displaying haplotypes in the chromosome view\n\\b0\\fs26 \\\n\\\nThe standard frequency-based display used by the chromosome view is useful for seeing the relative frequencies of mutations:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_347793.jpg \\width8420 \\height1260\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nHowever, this display style is unhelpful for seeing patterns of association among mutations, such as linkage disequilibrium and haplotypes that may have established in the population.  For an alternative display style that is better for that purpose, you can bring up a context menu on the chromosome view by right-clicking or control-clicking on it:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_885386.jpg \\width8420 \\height1780\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nSelecting Display Haplotypes provides a display in which a random subset of genomes from the selected subpopulations are displayed, one per pixel row in the view, clustered according to their genetic similarity:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_160492.jpg \\width8420 \\height1260\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis display shows the genetic structure of the population much more clearly (at the loss of some ease of comprehensibility).  You can restore the chromosome view to its default frequency-based display by selecting \"Display Frequencies\" from the context menu.\\\n\\\nNote that a new haplotype plot is also now available as a type of graph is SLiMgui; it provides the same type of visualization, but in a larger window with various options regarding the genetic clustering and the appearance.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 2 autogen script.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Autogenerating script\n\\b0\\fs26 \\\n\\\nSLiMgui provides various commands for automatically generating Eidos script to perform simple simulation tasks.  This is particularly helpful for those who are new to SLiM or to scripting in Eidos.\\\n\\\nFor example, the buttons underneath the subpopulation table let you autogenerate script related to population structure \\'96 adding and removing subpopulations, changing their size or sex ratio or selfing rate, and so forth:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 2.tiff \\width4140 \\height660\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nAutogeneration of commands related to output can be done with a pop-up menu located, logically, near the output pane:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 3.tiff \\width5120 \\height1500\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nAnd autogeneration of commands related to genetic structure, such as adding mutation types, genomic element types, and so forth, can be done with another pop-up menu, next to the chromosome view:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 4.tiff \\width4240 \\height2220\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIn all cases, just select the autogeneration command you want, and a sheet will appear allowing you to configure the new script that SLiMgui will generate for you.  For example, here's the sheet shown to configure a new \"output fixed mutations\" command:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 5.tiff \\width5520 \\height3960\n}}}"
  },
  {
    "path": "SLiMgui/Tips/Tip 20 script prettyprinting.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9360\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Script prettyprinting\n\\b0\\fs26 \\\n\\\nNicely formatted code is much more readable, but fixing the indentation level on all the lines of a script can be tedious.  SLiMgui provides an automated script prettyprinting feature that will fix the indentation of your script for you.  Just click  the Prettyprint Script button, at the top of the scripting area of the window:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_841421.jpg \\width920 \\height720\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis reformats your script by its fixing indentation according to standard conventions.  For example, take this badly-formatted script (for a function that computes the average nucleotide heterozygosity in a subpopulation, available in the SLiM-Extras archive online):\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_120059.jpg \\width8480 \\height3620\n}}\n\\f0\\fs26 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis mess gets cleaned up to this:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_197763.jpg \\width8480 \\height3620\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nMuch better!}"
  },
  {
    "path": "SLiMgui/Tips/Tip 21 MutationType DFE visualization.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1504\\cocoasubrtf830\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;\\f2\\fnil\\fcharset0 Menlo-Regular;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n{\\*\\expandedcolortbl;;}\n\\margl1440\\margr1440\\vieww9360\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 MutationType DFE visualization\n\\b0\\fs26 \\\n\\\nMutation types in SLiM define a distribution of fitness effects, of DFE, from which new mutations of that type are drawn.  This can be a fixed selection coefficient, or a predefined distribution such as a gamma or exponential distribution customized by specified parameters, or even an Eidos script snippet that generates selection coefficients dynamically.  It would be nice to have a way to see the DFE for a given mutation type, to make sure that it has been configured correctly.  SLiMgui provides a way to do this.  First open the drawer on the SLiMgui window by clicking the drawer button:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width720 \\height720\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe drawer that opens shows several tables with supplemental information about the simulation that is running.  The top table shows a list of the mutation types have been defined; for a hypothetical model, it might look like:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_880540.jpg \\width4820 \\height2100\n}}\n\\f0\\fs26 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIf you hover the mouse cursor over the \n\\f2\\fs24 m2\n\\f0\\fs26  line without moving, a small plot appears in a tooltip over the table, showing the DFE for \n\\f2\\fs24 m2\n\\f0\\fs26 :\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_889172.jpg \\width4820 \\height2540\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe gamma distribution used by \n\\f2\\fs24 m3\n\\f0\\fs26  can similarly be seen by hovering the cursor over that line:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_905211.jpg \\width4820 \\height2760\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nNote that the range of the \n\\i x\n\\i0 -axis changes to fit the DFE.  Mutation type \n\\f2\\fs24 m4\n\\f0\\fs26  has a script-based DFE that calls \n\\f2\\fs24 rbinom()\n\\f0\\fs26  to draw a selection from a discrete distribution; that can be visualized in the same way:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic constrictorTemp_595368.jpg \\width4820 \\height3000\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIf there is an error in the script for the DFE, such that SLiMgui can't execute it, a question mark will be displayed in place of the DFE plot.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 3 see prototypes.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fnil\\fcharset0 Menlo-Regular;\\f2\\fswiss\\fcharset0 Helvetica;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 See function/method prototypes\n\\b0\\fs26 \\\n\\\nWhen you're working on a model in SLiMgui, sometimes you just want a quick reminder of the parameters that a function or method requires, without opening up the help window.  Just click to put the insertion point right inside the parentheses () for the call you're interested in.  The \"prototype\" for the function or method will appear in the status bar at the bottom of the SLiMgui window.  Here the insertion point has been placed inside the \n\\f1\\fs24 outputFixedMutations()\n\\f0\\fs26  call:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f2\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width7760 \\height1360\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis shows that \n\\f1\\fs24 outputFixedMutations()\n\\f0\\fs26  is a method that takes two parameters: one named \n\\f1\\fs24 filePath\n\\f0\\fs26  that can be either \n\\f1\\fs24 NULL\n\\f0\\fs26  or a singleton \n\\f1\\fs24 string\n\\f0\\fs26  (with a default of \n\\f1\\fs24 NULL\n\\f0\\fs26 ), and one named \n\\f1\\fs24 append\n\\f0\\fs26  that takes a \n\\f1\\fs24 logical\n\\f0\\fs26  singleton, with a default of \n\\f1\\fs24 F\n\\f0\\fs26 .  See the Eidos manual for details on the format of function/method prototypes.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 4 code completion.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fnil\\fcharset0 Menlo-Regular;\\f2\\fswiss\\fcharset0 Helvetica;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Code completion\n\\b0\\fs26 \\\n\\\nOne of the most powerful tools in the SLiMgui editor is code completion.  This facility lets you insert the names of functions, methods, properties, variables, and keywords automatically, based upon a prefix that you've typed, or with no prefix at all.  For example, if you want to add a call to an output method on the simulation object (\n\\f1\\fs24 sim\n\\f0\\fs26 ), but you can't remember the exact name of the method you want, try typing \n\\f1\\fs24 sim.out\n\\f0\\fs26  and then pressing the <escape> key (probably labeled \"esc\" on your keyboard).  You'll see something like this:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f2\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 6.tiff \\width4000 \\height1860\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe combo box (as it is called) shows all of the methods on \n\\f1\\fs24 sim\n\\f0\\fs26  that start with \n\\f1\\fs24 out\n\\f0\\fs26 .\\\n\\\nSLiMgui is smart enough to know variables you have defined, and to figure out their type in almost all cases.  So suppose you define a variable \n\\f1\\fs24 g\n\\f0\\fs26  that contains \n\\f1\\fs24 Genome\n\\f0\\fs26  objects, and then you autocomplete off of that:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f2\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width3900 \\height3160\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nAs you can see, SLiMgui shows the properties and methods that are specific to the \n\\f1\\fs24 Genome\n\\f0\\fs26  class, because it knows \n\\f1\\fs24 g\n\\f0\\fs26 's type.  If you decide you want the \n\\f1\\fs24 addNewDrawnMutation()\n\\f0\\fs26  method, but you don't want to type it all out, just type \"add\" and press <escape> again.  You will see:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f2\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 5.tiff \\width3900 \\height2060\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThe combo box responds to the arrow keys, so just press the down-arrow key to select the second line, and then press return to accept the completion, leaving you with:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f2\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 4.tiff \\width3900 \\height1260\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nIncidentally, command-. (hold down the command key and press the period key) is also a shortcut for code completion, if you prefer.\\\n}"
  },
  {
    "path": "SLiMgui/Tips/Tip 5 config chromosome view.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Chromosome view display options\n\\b0\\fs26 \\\n\\\nThe chromosome view in SLiMgui is more configurable than you might realize.  There are four buttons to the right of it:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width1240 \\height1240\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nClick them to toggle on/off display of particular aspects of the chromosome.  The M button is on by default; it displays all segregating mutations, with a color that depends on the selection coefficient of the mutation type, and a height that depends on the frequency in the population.  The F button turns on display of fixed mutations as well, showing them as full-height blue lines.  The R button turns on display of the recombination map; this is useful if you have set up the recombination rate to vary along the chromosome.  Finally, the G buttons turns on a color-coded display of the genomic element types used along the chromosome; if you have set up genetic structure, such as introns, exons, UTRs, etc., this display can be quite useful.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 6 fast recipe access.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Opening SLiM cookbook \"recipes\"\n\\b0\\fs26 \\\n\\\nSLiM's manual has a \"cookbook\" section with several dozen different \"recipes\" for a wide variety of models.  There is a quick and easy way to open these recipes in SLiMgui.  Just go to the Open Recipe submenu of the File menu, and all of the recipes in your version of SLiM can be opened directly:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width9240 \\height4300\n}}}"
  },
  {
    "path": "SLiMgui/Tips/Tip 7 comment in out.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Commenting & uncommenting code\n\\b0\\fs26 \\\n\\\nWhen working on a script in SLiMgui, it is often useful to be able to \"comment out\" sections of code to disable them, and then remove the comment characters to re-enable them later.  The editor in SLiMgui makes this easy.  If you select some lines of code:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width4780 \\height1500\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nPress command-/ to comment out the selected lines:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width4780 \\height1500\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nAnd then press command-/ again to uncomment them:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width4780 \\height1500\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nBasically, if the lines are commented out, command-/ will uncomment them; otherwise, it will turn them into a comment.}"
  },
  {
    "path": "SLiMgui/Tips/Tip 8 shift left right.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Indenting & outdenting code\n\\b0\\fs26 \\\n\\\nIt's nice to write properly indented code, following standard coding conventions.  However, it can be annoying doing the formatting by hand, inserting or removing tabs on each line.  SLiMgui provides a facility for easily increasing or decreasing the indentation level of your code.  Just select some lines:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width5340 \\height1620\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nPress command-] to increase the indentation level by inserting tab characters at the beginning of each line:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width5340 \\height1620\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nOr press command-[ to decrease the indentation level by deleting tab characters from the beginning of each line:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic.tiff \\width5340 \\height1620\n}}}"
  },
  {
    "path": "SLiMgui/Tips/Tip 9 help by title or content.rtfd/TXT.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1404\\cocoasubrtf470\n{\\fonttbl\\f0\\fswiss\\fcharset0 Optima-Regular;\\f1\\fswiss\\fcharset0 Helvetica;\\f2\\fnil\\fcharset0 Menlo-Regular;\n}\n{\\colortbl;\\red255\\green255\\blue255;}\n\\margl1440\\margr1440\\vieww19880\\viewh13000\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\b\\fs32 \\cf0 Help search scoping\n\\b0\\fs26 \\\n\\\nThe help window in SLiMgui has a feature that is easy to miss, but quite useful: you can change the scope of your searches in the help.  If you click on the magnifying glass in the search field of the help window, you get a pop-up menu:\\\n\\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f1\\fs24 \\cf0 {{\\NeXTGraphic Pasted Graphic 1.tiff \\width3600 \\height2400\n}}\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\qc\\partightenfactor0\n\n\\f0\\fs26 \\cf0 \\\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\\cf0 \\\nThis allows you to configure the help window to search only in help item titles, or by the full text of the help items.  If you search for \"fixed\" in titles only, for example, you will find only the method \n\\f2\\fs24 outputFixedMutations()\n\\f0\\fs26 , but if you search by content, you will find discussion of fixed mutations in many other sections, such as the \n\\f2\\fs24 convertToSubstitution\n\\f0\\fs26  property of \n\\f2\\fs24 MutationType\n\\f0\\fs26 , and the substitutions property of \n\\f2\\fs24 SLiMSim\n\\f0\\fs26 .}"
  },
  {
    "path": "SLiMgui/TipsWindowController.h",
    "content": "//\n//  TipsWindowController.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/2/16.\n//  Copyright (c) 2016-2022 Philipp Messer.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import <Cocoa/Cocoa.h>\n\n\nextern NSString *SLiMDefaultsShowTipsPanelKey;\nextern NSString *SLiMDefaultsTipsIndexKey;\n\n\n@interface TipsWindowController : NSObject <NSWindowDelegate>\n{\n\tNSArray *tipsFilenames;\n\tNSInteger lastTipShown;\n}\n\n@property (nonatomic, retain) IBOutlet NSPanel *tipsWindow;\n@property (nonatomic, assign) IBOutlet NSTextView *tipsTextView;\n@property (nonatomic, assign) IBOutlet NSTextField *tipsNumberTextField;\n@property (nonatomic, assign) IBOutlet NSButton *suppressPanelCheckbox;\n@property (nonatomic, assign) IBOutlet NSButton *nextButton;\n\n+ (void)showTipsWindowOnLaunch;\n\n\n//\n//\tActions\n//\n\n- (IBAction)rewindButtonClicked:(id)sender;\n- (IBAction)nextButtonClicked:(id)sender;\n- (IBAction)doneButtonClicked:(id)sender;\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/TipsWindowController.m",
    "content": "//\n//  TipsWindowController.m\n//  SLiM\n//\n//  Created by Ben Haller on 12/2/16.\n//  Copyright (c) 2016-2022 Philipp Messer.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#import \"TipsWindowController.h\"\n\n\nNSString *SLiMDefaultsShowTipsPanelKey = @\"ShowTipsPanel\";\nNSString *SLiMDefaultsTipsIndexKey = @\"TipsIndex\";\nNSString *SLiMDefaultsTipsCountKey = @\"TipsCount\";\n\nNSString *SLiMTipsDirectoryName = @\"Tips\";\n\n\n@implementation TipsWindowController\n\n+ (void)initialize\n{\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:@{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SLiMDefaultsShowTipsPanelKey : @YES,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SLiMDefaultsTipsIndexKey : @(-1),\t\t// tip index 0, after advancing automatically\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SLiMDefaultsTipsCountKey : @(15),\t\t// DO NOT CHANGE; this was the number of tips prior to adding this default\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  }];\n}\n\n+ (void)showTipsWindowOnLaunch\n{\n\tif ([[NSUserDefaults standardUserDefaults] boolForKey:SLiMDefaultsShowTipsPanelKey])\n\t{\n\t\tstatic TipsWindowController *controller = nil;\n\t\t\n\t\tif (!controller)\n\t\t\t[[[TipsWindowController alloc] init] autorelease];\n\t\t\n\t\t[controller showTipsPanel];\n\t}\n}\n\n- (instancetype)init\n{\n\tif (self = [super init])\n\t{\n\t\t// Assess the tips on tap\n\t\tNSArray *paths = [[NSBundle mainBundle] pathsForResourcesOfType:nil inDirectory:SLiMTipsDirectoryName];\n\t\t\n\t\ttipsFilenames = [paths valueForKey:@\"lastPathComponent\"];\n\t\ttipsFilenames = [tipsFilenames sortedArrayUsingSelector:@selector(localizedStandardCompare:)];\n\t\t[tipsFilenames retain];\n\t\t\n\t\tNSInteger newTipCount = [tipsFilenames count];\n\t\t\n\t\tlastTipShown = [[NSUserDefaults standardUserDefaults] integerForKey:SLiMDefaultsTipsIndexKey];\n\t\t\n\t\t// If we were showing the \"end tip\" but now we have new tips, then we need to go backwards from the end tip\n\t\tNSInteger oldTipCount = [[NSUserDefaults standardUserDefaults] integerForKey:SLiMDefaultsTipsCountKey];\n\t\t\n\t\tif (newTipCount > oldTipCount)\n\t\t{\n\t\t\tif (lastTipShown == oldTipCount)\n\t\t\t\tlastTipShown--;\n\t\t\t\n\t\t\t[[NSUserDefaults standardUserDefaults] setInteger:newTipCount forKey:SLiMDefaultsTipsCountKey];\n\t\t}\n\t}\n\t\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[self setTipsWindow:nil];\n\t[tipsFilenames release];\n\t\n\t[super dealloc];\n}\n\n- (void)showTipsPanel\n{\n\t// If we've already shown the user all of the available tips, then we don't show the panel again\n\t// until more become available (in a new version of SLiMgui, presumably)\n\tif (lastTipShown >= (NSInteger)[tipsFilenames count])\n\t\treturn;\n\t\n\t// Load the tips panel\n\t[[NSBundle mainBundle] loadNibNamed:@\"TipsWindow\" owner:self topLevelObjects:nil];\n\t\n\tif (_tipsWindow)\n\t{\n\t\t[_tipsWindow setDelegate:self];\n\t\t[self retain];\n\t\t\n\t\t[self nextButtonClicked:nil];\t// advance to the next available tip\n\t\t\n\t\t[_tipsWindow makeKeyAndOrderFront:nil];\n\t}\n}\n\n- (void)windowWillClose:(NSNotification *)notification\n{\n\tbool suppressPanel = ([_suppressPanelCheckbox state] == NSOnState);\n\t\n\tif (suppressPanel)\n\t\t[[NSUserDefaults standardUserDefaults] setBool:NO forKey:SLiMDefaultsShowTipsPanelKey];\n\t\n\t[_tipsWindow setDelegate:nil];\n\t[self autorelease];\n}\n\n\n//\n//\tActions\n//\n\n- (IBAction)rewindButtonClicked:(id)sender\n{\n\tlastTipShown = -1;\n\t\n\t[self nextButtonClicked:nil];\n}\n\n- (IBAction)nextButtonClicked:(id)sender\n{\n\tlastTipShown++;\n\t[[NSUserDefaults standardUserDefaults] setInteger:lastTipShown forKey:SLiMDefaultsTipsIndexKey];\n\t//NSLog(@\"Advanced to %ld\", (long)lastTipShown);\n\t\n\t// Set the enable state of the Next button; but note we allow ourselves to go one over, to show the \"out of tips\" message\n\tbool moreTips = (lastTipShown >= (NSInteger)[tipsFilenames count]);\n\t\n\t[_nextButton setEnabled:!moreTips];\n\t\n\t// Show the tip\n\tNSString *tipPath;\n\t\n\tif (lastTipShown < (NSInteger)[tipsFilenames count])\n\t{\n\t\t// Tip index is in range, so grab one from our filename array\n\t\ttipPath = [[NSBundle mainBundle] pathForResource:[tipsFilenames objectAtIndex:lastTipShown] ofType:nil inDirectory:SLiMTipsDirectoryName];\n\t\t\n\t\t[_tipsNumberTextField setStringValue:[NSString stringWithFormat:@\"#%ld\", (long)lastTipShown + 1]];\n\t}\n\telse\n\t{\n\t\t// Tip index is not in range, so put up the \"out of tips\" message\n\t\ttipPath = [[NSBundle mainBundle] pathForResource:@\"Tip_END.rtfd\" ofType:nil inDirectory:nil];\n\t\t\n\t\t[_tipsNumberTextField setStringValue:@\"∞\"];\n\t}\n\t\n\t[_tipsTextView readRTFDFromFile:tipPath];\n\t[_tipsTextView scrollPoint:NSZeroPoint];\n}\n\n- (IBAction)doneButtonClicked:(id)sender\n{\n\t[_tipsWindow performClose:nil];\n}\n\n@end\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/main.m",
    "content": "//\n//  main.m\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/20/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n#import <Cocoa/Cocoa.h>\n\nint main(int argc, const char * argv[]) {\n\treturn NSApplicationMain(argc, argv);\n}\n"
  },
  {
    "path": "SLiMgui/plot.h",
    "content": "//\n//  plot.h\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/30/2024.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Plot represents a user-created plot in SLiMgui.  It is available only when running under SLiMgui.\n \n */\n\n#ifndef __SLiM__plot__\n#define __SLiM__plot__\n\n\n#include <vector>\n#include <string>\n#include <map>\n\n#include \"eidos_value.h\"\n#include \"slim_globals.h\"\n\n@class SLiMWindowController;\n\n\nextern EidosClass *gSLiM_Plot_Class;\n\n\nclass Plot : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\npublic:\n\t\n\tPlot(const Plot&) = delete;\t\t\t\t\t// no copying\n\tPlot& operator=(const Plot&) = delete;\t\t// no copying\n\tPlot(void);\n\t~Plot(void);\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_abline(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addLegend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_axis(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_image(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_matrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mtext(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass Plot_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tPlot_Class(const Plot_Class &p_original) = delete;\t// no copy-construct\n\tPlot_Class& operator=(const Plot_Class&) = delete;\t// no copying\n\tinline Plot_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* __SLiM__plot__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/plot.mm",
    "content": "//\n//  plot.cpp\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/30/24.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"plot.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#import \"SLiMWindowController.h\"\n\n#include <unistd.h>\n\n\n#pragma mark -\n#pragma mark Plot\n#pragma mark -\n\nPlot::Plot(void)\n{\n}\n\nPlot::~Plot(void)\n{\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *Plot::Class(void) const\n{\n\treturn gSLiM_Plot_Class;\n}\n\nvoid Plot::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP Plot::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t// constants\n\t\tcase gID_title:\n\t\t{\n\t\t\t// The user has no way to access this property in SLiMguiLegacy\n\t\t\treturn gStaticEidosValue_StringEmpty;\n\t\t}\n\t\t\n\t\t// variables\n\t\t\n\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid Plot::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP Plot::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_abline:\t\t\t\treturn ExecuteMethod_abline(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addLegend:\t\t\t\treturn ExecuteMethod_addLegend(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_axis:\t\t\t\t\treturn ExecuteMethod_axis(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_image:\t\t\t\t\treturn ExecuteMethod_image(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_legendLineEntry:\t\treturn ExecuteMethod_legendLineEntry(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_legendPointEntry:\t\treturn ExecuteMethod_legendPointEntry(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_legendSwatchEntry:\t\treturn ExecuteMethod_legendSwatchEntry(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_legendTitleEntry:\t\treturn ExecuteMethod_legendTitleEntry(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_lines:\t\t\t\t\treturn ExecuteMethod_lines(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_matrix:\t\t\t\treturn ExecuteMethod_matrix(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mtext:\t\t\t\t\treturn ExecuteMethod_mtext(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_points:\t\t\t\treturn ExecuteMethod_points(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_rects:\t\t\t\t\treturn ExecuteMethod_rects(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_segments:\t\t\t\treturn ExecuteMethod_segments(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setBorderless:\t\t\treturn ExecuteMethod_setBorderless(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_text:\t\t\t\t\treturn ExecuteMethod_text(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_write:\t\t\treturn ExecuteMethod_write(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (void)abline(...)\n//\nEidosValue_SP Plot::ExecuteMethod_abline(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)addLegend(...)\n//\nEidosValue_SP Plot::ExecuteMethod_addLegend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)axis(...)\n//\nEidosValue_SP Plot::ExecuteMethod_axis(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)image(...)\n//\nEidosValue_SP Plot::ExecuteMethod_image(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendLineEntry(...)\n//\nEidosValue_SP Plot::ExecuteMethod_legendLineEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendPointEntry(...)\n//\nEidosValue_SP Plot::ExecuteMethod_legendPointEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendSwatchEntry(...)\n//\nEidosValue_SP Plot::ExecuteMethod_legendSwatchEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)legendTitleEntry(...)\n//\nEidosValue_SP Plot::ExecuteMethod_legendTitleEntry(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)lines(...)\n//\nEidosValue_SP Plot::ExecuteMethod_lines(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)matrix(...)\n//\nEidosValue_SP Plot::ExecuteMethod_matrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)mtext(...)\n//\nEidosValue_SP Plot::ExecuteMethod_mtext(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)points(...)\n//\nEidosValue_SP Plot::ExecuteMethod_points(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)rects(...)\n//\nEidosValue_SP Plot::ExecuteMethod_rects(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)segments(...)\n//\nEidosValue_SP Plot::ExecuteMethod_segments(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)text(...)\n//\nEidosValue_SP Plot::ExecuteMethod_text(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setBorderless(...)\n//\nEidosValue_SP Plot::ExecuteMethod_setBorderless(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)write(string$ filePath)\n//\nEidosValue_SP Plot::ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// The user has no way to call this method in SLiMguiLegacy, since createPlot() does not return a Plot object.\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tPlot_Class\n//\n#pragma mark -\n#pragma mark Plot_Class\n#pragma mark -\n\nEidosClass *gSLiM_Plot_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Plot_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_title,\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Plot_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_abline, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric_ON(\"a\", gStaticEidosValueNULL)->AddNumeric_ON(\"b\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddNumeric_ON(\"h\", gStaticEidosValueNULL)->AddNumeric_ON(\"v\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addLegend, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_OSN(\"position\", gStaticEidosValueNULL)->AddInt_OSN(\"inset\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddNumeric_OSN(\"labelSize\", gStaticEidosValueNULL)->AddNumeric_OSN(\"lineHeight\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddNumeric_OSN(\"graphicsWidth\", gStaticEidosValueNULL)->AddNumeric_OSN(\"exteriorMargin\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddNumeric_OSN(\"interiorMargin\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_axis, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddInt_S(\"side\")->AddNumeric_ON(\"at\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional, \"labels\", nullptr, gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_image, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddObject_S(gStr_image, nullptr)->AddNumeric_S(\"x1\")->AddNumeric_S(\"y1\")->AddNumeric_S(\"x2\")->AddNumeric_S(\"y2\")\n\t\t\t\t\t\t\t  ->AddLogical_OS(\"flipped\", gStaticEidosValue_LogicalF)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendLineEntry, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_S(\"label\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendPointEntry, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_S(\"label\")->AddInt_OS(\"symbol\", gStaticEidosValue_Integer0)\n\t\t\t\t\t\t\t  ->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddString_OS(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1)->AddNumeric_OS(\"size\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendSwatchEntry, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_S(\"label\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\"))));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_legendTitleEntry, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_S(\"label\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_lines, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString_OS(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"lwd\", gStaticEidosValue_Float1)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_matrix, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"matrix\")->AddNumeric_S(\"x1\")->AddNumeric_S(\"y1\")->AddNumeric_S(\"x2\")->AddNumeric_S(\"y2\")\n\t\t\t\t\t\t\t  ->AddLogical_OS(\"flipped\", gStaticEidosValue_LogicalF)->AddNumeric_ON(\"valueRange\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddString_OSN(\"colors\", gStaticEidosValueNULL)->AddFloat_OS(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mtext, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString(\"labels\")\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"size\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(10)))\n\t\t\t\t\t\t\t  ->AddNumeric_ON(\"adj\", gStaticEidosValueNULL)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"angle\", gStaticEidosValue_Float0));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_points, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddInt_O(\"symbol\", gStaticEidosValue_Integer0)\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddString_O(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddNumeric_O(\"size\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_rects, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x1\")->AddNumeric(\"y1\")->AddNumeric(\"x2\")->AddNumeric(\"y2\")\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddString_O(\"border\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_segments, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x1\")->AddNumeric(\"y1\")->AddNumeric(\"x2\")->AddNumeric(\"y2\")\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"red\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"lwd\", gStaticEidosValue_Float1)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setBorderless, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"marginLeft\", gStaticEidosValue_Float0)->AddNumeric_OS(\"marginTop\", gStaticEidosValue_Float0)\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"marginRight\", gStaticEidosValue_Float0)->AddNumeric_OS(\"marginBottom\", gStaticEidosValue_Float0));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_text, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddNumeric(\"x\")->AddNumeric(\"y\")->AddString(\"labels\")\n\t\t\t\t\t\t\t  ->AddString_O(\"color\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"black\")))\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"size\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(10)))\n\t\t\t\t\t\t\t  ->AddNumeric_ON(\"adj\", gStaticEidosValueNULL)->AddFloat_O(\"alpha\", gStaticEidosValue_Float1)\n\t\t\t\t\t\t\t  ->AddNumeric_O(\"angle\", gStaticEidosValue_Float0));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_write, kEidosValueMaskVOID))\n\t\t\t\t\t\t\t  ->AddString_S(gEidosStr_filePath));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/slim_gui.h",
    "content": "//\n//  slim_gui.h\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/19/19.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class SLiMgui represents the SLiMgui application's Eidos interface.  It is available only when running under SLiMgui.\n \n */\n\n#ifndef __SLiM__slim_gui__\n#define __SLiM__slim_gui__\n\n\n#include <vector>\n#include <string>\n#include <map>\n\n#include \"eidos_value.h\"\n#include \"eidos_symbol_table.h\"\n#include \"slim_globals.h\"\n\n@class SLiMWindowController;\n\n\nextern EidosClass *gSLiM_SLiMgui_Class;\n\n\nclass SLiMgui : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\npublic:\n\t\n\tCommunity &community_;\t\t\t\t\t\t// We have a reference to our community object\n\tSLiMWindowController *controller_;\t\t\t// We have a reference to the SLiMgui window controller for our simulation\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t// for fast setup of the symbol table\n\t\n\tSLiMgui(const SLiMgui&) = delete;\t\t\t\t\t// no copying\n\tSLiMgui& operator=(const SLiMgui&) = delete;\t\t// no copying\n\tSLiMgui(void) = delete;\t\t\t\t\t\t\t\t// no null construction\n\tSLiMgui(Community &p_community, SLiMWindowController *p_controller);\n\t~SLiMgui(void);\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; }\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_createPlot(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_logFileData(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_openDocument(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pauseExecution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_plotWithTitle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass SLiMgui_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tSLiMgui_Class(const SLiMgui_Class &p_original) = delete;\t// no copy-construct\n\tSLiMgui_Class& operator=(const SLiMgui_Class&) = delete;\t// no copying\n\tinline SLiMgui_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* __SLiM__slim_gui__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SLiMgui/slim_gui.mm",
    "content": "//\n//  slim_gui.cpp\n//  SLiMgui\n//\n//  Created by Ben Haller on 1/19/19.\n//  Copyright (c) 2019-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_gui.h\"\n#include \"log_file.h\"\n#include \"plot.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#import \"SLiMWindowController.h\"\n\n#include <unistd.h>\n\n\n#pragma mark -\n#pragma mark SLiMgui\n#pragma mark -\n\nSLiMgui::SLiMgui(Community &p_community, SLiMWindowController *p_controller) :\n\tcommunity_(p_community),\n\tcontroller_(p_controller),\n\tself_symbol_(gID_slimgui, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMgui_Class)))\n{\n}\n\nSLiMgui::~SLiMgui(void)\n{\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *SLiMgui::Class(void) const\n{\n\treturn gSLiM_SLiMgui_Class;\n}\n\nvoid SLiMgui::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP SLiMgui::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t// constants\n\t\tcase gID_pid:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(getpid()));\n\t\t}\n\t\t\n\t\t// variables\n\t\t\n\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid SLiMgui::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP SLiMgui::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_createPlot:\t\t\t\treturn ExecuteMethod_createPlot(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_logFileData:\t\t\t\treturn ExecuteMethod_logFileData(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_openDocument:\t\t\t\treturn ExecuteMethod_openDocument(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pauseExecution:\t\t\treturn ExecuteMethod_pauseExecution(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_plotWithTitle:\t\t\t\treturn ExecuteMethod_plotWithTitle(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (No<Plot>$)createPlot(...)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_createPlot(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tstatic bool beenHere = false;\n\t\n\tif (!beenHere)\n\t{\n\t\t// Emit a warning that this API is unsupported in SLiMguiLegacy.  We warn, not error, so the user does not have to modify\n\t\t// their script to run it in SLiMguiLegacy when it is designed to run under QtSLiM; they just won't get a plot window.\n\t\tstd::cerr << \"WARNING (SLiMgui::ExecuteMethod_createPlot): createPlot() is not supported in SLiMguiLegacy, and does nothing.\" << std::endl;\n\t\tbeenHere = true;\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\n//\t*********************\t– (Nfs)logFileData(o<LogFile>$ logFile, is$ column)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_logFileData(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tstatic bool beenHere = false;\n\t\n\tif (!beenHere)\n\t{\n\t\t// Emit a warning that this API is unsupported in SLiMguiLegacy.  We warn, not error, so the user does not have to modify\n\t\t// their script to run it in SLiMguiLegacy when it is designed to run under QtSLiM; they just won't get data.\n\t\tstd::cerr << \"WARNING (SLiMgui::ExecuteMethod_logFileData): logFileData() is not supported in SLiMguiLegacy, and does nothing.\" << std::endl;\n\t\tbeenHere = true;\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\n//\t*********************\t– (void)openDocument(string$ path)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_openDocument(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tEidosValue_String *filePath_value = (EidosValue_String *)p_arguments[0].get();\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringRefAtIndex_NOCAST(0, nullptr)));\n\tNSString *filePath = [NSString stringWithUTF8String:file_path.c_str()];\n\t\n\t[controller_ eidos_openDocument:filePath];\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)pauseExecution(void)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_pauseExecution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t[controller_ eidos_pauseExecution];\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (No<Plot>$)plotWithTitle(...)\n//\nEidosValue_SP SLiMgui::ExecuteMethod_plotWithTitle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tstatic bool beenHere = false;\n\t\n\tif (!beenHere)\n\t{\n\t\t// Emit a warning that this API is unsupported in SLiMguiLegacy.  We warn, not error, so the user does not have to modify\n\t\t// their script to run it in SLiMguiLegacy when it is designed to run under QtSLiM; they just won't get a plot window.\n\t\tstd::cerr << \"WARNING (SLiMgui::ExecuteMethod_plotWithTitle): plotWithTitle() is not supported in SLiMguiLegacy, and does nothing.\" << std::endl;\n\t\tbeenHere = true;\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\n\n//\n//\tSLiMgui_Class\n//\n#pragma mark -\n#pragma mark SLiMgui_Class\n#pragma mark -\n\nEidosClass *gSLiM_SLiMgui_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *SLiMgui_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_pid,\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *SLiMgui_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_createPlot, kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Plot_Class))->AddString_S(\"title\")\n\t\t\t\t\t\t\t  ->AddNumeric_ON(\"xrange\", gStaticEidosValueNULL)->AddNumeric_ON(\"yrange\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddString_OS(\"xlab\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"x\")))\n\t\t\t\t\t\t\t  ->AddString_OS(\"ylab\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"y\")))\n\t\t\t\t\t\t\t  ->AddNumeric_OSN(\"width\", gStaticEidosValueNULL)->AddNumeric_OSN(\"height\", gStaticEidosValueNULL)\n\t\t\t\t\t\t\t  ->AddLogical_OS(\"horizontalGrid\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"verticalGrid\", gStaticEidosValue_LogicalF)\n\t\t\t\t\t\t\t  ->AddLogical_OS(\"fullBox\", gStaticEidosValue_LogicalT)\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"axisLabelSize\", EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(15)))\n\t\t\t\t\t\t\t  ->AddNumeric_OS(\"tickLabelSize\", EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(10))));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_logFileData, kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString))\n\t\t\t\t\t\t\t  ->AddObject_S(\"logFile\", gSLiM_LogFile_Class)->AddIntString_S(\"column\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_openDocument, kEidosValueMaskVOID))->AddString_S(gEidosStr_filePath));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pauseExecution, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_plotWithTitle, kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Plot_Class))->AddString_S(\"title\"));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "TO_DO",
    "content": "OK, this has turned out not to be a \"to do\" file so much as a place to put useful little snippets and such...\n\n\nnew cmake-based command line building:\n\tcd SLiM\n\tmkdir build\n\tcd build\n\tcmake ..\n\tmake\n\ncause cmake to be re-run (after addition/removal of source files, etc.; this is necessary because we use GLOB with \"file\" in our cmake config):\n\tcd SLiM\n\ttouch ./CMakeLists.txt\n\nlook for exported symbols that are not tagged with \"eidos\" or \"Eidos\" somewhere in the symbol before the parameter list:\n\tnm -g -U -j ./EidosScribe | grep -E -v \"^_+([^_\\r\\n]+_)*[^_]*[Ee]idos\"\n\ndump demangled symbols from SLiMgui:\n\tnm -g -U -j ./SLiMgui | c++filt\n\nsome valgrind commands (set SLIM_LEAK_CHECKING to 1, and change the compile C/C++ flags to -O1 -g):\n\tvalgrind --leak-check=yes --track-origins=yes --expensive-definedness-checks=yes --num-callers=20 ./slim -testEidos\t\t(with Debug version)\n\tvalgrind --leak-check=yes --track-origins=yes --expensive-definedness-checks=yes --num-callers=20 ./slim -testSLiM\t\t(with Debug version)\n\tvalgrind --tool=cachegrind ./slim -seed 1 /Users/bhaller/Desktop/MK_SLiMGUIsim4.txt\t\t(with Release version)\n\t\tcg_annotate --sort=DLmr:1,DLmw:1 cachegrind.out.71431\n\tvalgrind --tool=callgrind ./slim -seed 1 /Users/bhaller/Desktop/MK_SLiMGUIsim4.txt\t\t(with Release version)\n\t\tcallgrind_annotate --tree=both callgrind.out.72015\n\tvalgrind --tool=massif ./slim -seed 1 /Users/bhaller/Desktop/MK_SLiMGUIsim4.txt\t\t\t(with Release version)\n\t\tms_print massif.out.73964\n\tvalgrind --tool=exp-sgcheck ./slim -testEidos\t(with Debug version; not on Darwin yet)\n\tvalgrind --tool=exp-sgcheck ./slim -testSLiM\t(with Debug version; not on Darwin yet)\n\ncpplint.py for checking includes (https://github.com/google/styleguide/tree/gh-pages/cpplint):\n\tcd /Users/bhaller/Documents/Research/MesserLab/SLiM_project/SLiM \n\tpython2.7 /Users/bhaller/bin/cpplint.py --filter=-,+build/include_what_you_use ./core/*.cpp ./eidos/*.cpp ./eidostool/*.cpp ./QtSLiM/*.cpp\n\n\tNOTE: there is a newer repo that I should shift over to using, https://github.com/cpplint/cpplint\n\nclang-tidy with CMake:\n\tsee https://danielsieger.com/blog/2021/12/21/clang-tidy-cmake.html\n\tinstall a good version of clang first: sudo port install clang-17 if you use MacPorts\n\tfind where clang-tidy is living: port contents clang-17 (for me it is at /opt/local/libexec/llvm-17/bin/clang-tidy)\n\tsimilarly locate clang and clang++ (for me, /opt/local/libexec/llvm-17/bin/clang and /opt/local/libexec/llvm-17/bin/clang++)\n\tfix the CMakeLists.txt file to have the correct paths for these things (in the section near the top, \"if(TIDY)\")\n\tmake a build directory for SLiM with mkdir, and cd to it\n\trun cmake (one of the below):\n\t\tcmake -D TIDY=ON path-to-SLiM-repo\n\t\tcmake -D TIDY=ON -D CMAKE_BUILD_TYPE=Debug path-to-SLiM-repo\n\t\tcmake -D TIDY=ON -D CMAKE_BUILD_TYPE=Debug -D CMAKE_PREFIX_PATH=/Users/bhaller/Qt5.15.2/5.15.2/clang_64 -D BUILD_SLIMGUI=ON /Users/bhaller/Documents/Research/MesserLab/SLiM_project/SLiM \n\tmake eidos / make slim / make SLiMgui\n\nCR/LF issues:\n\tfile -e soft <file> tells you what a file is (-e soft turns off \"magic\", which misdiagnoses SLiM files)\n\ttab2space -lf <file> converts a file to Unix-style LF only\n\tconvert all text files in the current directory to use LF: find . -name \\*.txt -exec tab2space -lf {} {} \\; -print\n\ntab issues:\n\tconvert leading spaces to tabs in recipes:\n\t\tfind . -name \\*.txt -exec bash -c 'gunexpand -t 4 --first-only \"$0\" > /tmp/totabbuff && mv /tmp/totabbuff \"$0\"' {} \\; -print\n\nfinding out the generation number of a running simulation in lldb:\n\tlldb /usr/local/bin/slim\n\tprocess attach --pid X (from ps -ax | grep slim)\n\tbreakpoint set --method _RunOneTick\n\tc\n\t(lldb breaks at _RunOneTick...)\n\t\n\tif you have symbols, just p generation_; if not:\n\t\n\tsi (repeat until you reach movl   $0x0, 0x40(%r15) which is perhaps around +30; this is generation_stage_ = SLiMGenerationStage::kStage0PreGeneration)\n\t(now %r15 is the this pointer...)\n\tregister read r15 --format hex\n\tmemory read --size 4 --format x --count 50 `0x00007f9e28413f80`\t\t(where the hex value of r15 goes in the backquotes)\n\tthe generation is at the end of the fourth line, as SLiM is currently set up:\n\t0x7f9e28413fb0: 0x28414310 0x00007f9e 0x00000001 0x000021ef\t\t-> 0x000021ef is the generation\n\tif the memory layout moves, just look for 0x00000007 which will be the generation stage at this point in the code; the generation is immediately before it\n\nreassuring the Clang analyzer that a precondition is met:\n\t#ifdef __clang_analyzer__\n\t\tassert(p_argument_count >= 5);\n\t#endif\n\ncount total lines of code in the project (excluding the gsl code):\n\t( find ./core/ ./eidos/ ./eidostool/ ./EidosScribe ./SLiMgui ./QtSLiM '(' -name '*.mm' -or -name '*.h' -or -name '*.cpp' ')' -print0 | xargs -0 cat ) | wc -l\n\t( find ./core/ ./eidos/ '(' -name '*.mm' -or -name '*.h' -or -name '*.cpp' ')' -print0 | xargs -0 cat ) | wc -l\n\tor better, use cloc (available in MacPorts); see https://stackoverflow.com/a/5121125/2752221\n\na useful LaTeX equation editor:\n\thttps://www.codecogs.com/latex/eqneditor.php\n\nfind all instances of a string (or regex) in the commit history:\n\tgit --no-pager log -G\"pedigree\"\n\t\nto get a text diff of changes to the Xcode project file:\n\tgit --no-pager diff --text SLiM.xcodeproj/project.pbxproj\n\nto dump class memory layouts in Xcode:\n\tadd -Xclang and -fdump-record-layouts to \"Other C++ Flags\" in the project\n\trebuild one file of interest with command-control-B\n\tgo to the Report navigator, click on the build of the file\n\tclick on the compile execution line in the build log, then click on the report viewer icon at the right edge of that line\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "VERSIONS",
    "content": "VERSION HISTORY\n\nThis version history begins with the final release of version 2.0.  Versions prior to 2.0 are lost in the mists of time; since the switch from 1.8 to 2.0 was so large, it was not worth tracking all of the individual changes that were made.\n\nNote that not every commit will be logged here; that is what the Github commit history is for.  The purpose of this file is to record major feature additions, major bug fixes, etc., so that it is easier to track down which version number a particular major change occurred in.  To that end, major changes made in the development head will be logged below; when we decide to roll a new version number and do a new release, all of those development head changes will be reassigned as belonging to the new version number.\n\n\ndevelopment head (in the master branch):\n\tadd a rmultinom() function to draw from a multinomial distribution, matching rmultinom() in R\n\n\nversion 5.2 (Eidos version 4.2):\n\tadd cppcheck support in our cmake config, for development testing purposes\n\tspeed up the SpatialMap smooth() method in 2D without periodicity, since this is important for the Chevy et al. competition algorithm\n\tadd Plot method setBorderless() for making plots without border annotations -- no axes, ticks, labels\n\tfix display of images in Plot; it was antialiasing in some cases (such as PDF generation), which is not desirable\n\tadd segments() call to Plot, for plotting a set of unconnected line segments\n\tadd rects() call to Plot, for plotting a set of rectangles\n\textend text() to support drawing text at an angle, with new [float angle = 0.0] parameter\n\tadd mtext() call to Plot, for drawing text in the margins outside the plot area\n\tadd rowSums() and colSums() functions to Eidos, for use with matrices as a faster alternative to apply()\n\tadd the PCG random number generator, switch to pcg32_fast and pcg64_fast, remove all use of the old taus2 and MT19937-64 generators; note this completely breaks backward reproducibility\n\tfix various bugs involving conflicts between defined constants and other symbols, including #573 and #574; this sets new definition rules that could break some existing scripts (but is unlikely to)\n\tfix #575, QtSLiM terminates early when single-stepping with a rescheduled script block\n\tfix #579, crash in models with (a) tree-seq recording, (b) multiple chromosomes, AND (c) rejection of proposed offspring in modifyChild()\n\tadd readLine() function for obtaining stdin input to running models, thanks to Chris Talbot\n\tfix #580, add isClose() and allClose() Eidos functions for comparison within a given tolerance\n\tshift to macOS 14 as the oldest supported macOS version in GitHub Actions; we no longer test on macOS 13, or with Qt 5.x on macOS (but Qt 5.x still gets tested on other platforms, for now)\n\tSIMD and SLEEF optimizations thanks to Andy Kern:\n\t\tadd SIMD optimization for sqrt(), abs(), floor(), ceil(), trunc(), round(), sum(), product(), https://github.com/MesserLab/SLiM/pull/578\n\t\tfurther SIMD optimizations for exp(), log(), log10(), log2() based on the SLEEF framework (https://github.com/shibatch/sleef), https://github.com/MesserLab/SLiM/pull/587\n\t\tSIMD optimization for dnorm() using the previous SLEEF work, https://github.com/MesserLab/SLiM/pull/588\n\t\tSIMD optimizations for spatial interaction strength calculations, https://github.com/MesserLab/SLiM/pull/590\n\t\tadd comprehensive tests for spatial interaction kernel calculations; includes SIMD vs scalar consistency tests, C++ level tests, and script-level tests, https://github.com/MesserLab/SLiM/pull/592\n\t\tadd SIMD acceleration for trig functions (sin(), cos(), tan(), asin(), acos(), atan(), atan2()), power functions (^ opperator, pow, SpatialMap.pow()), https://github.com/MesserLab/SLiM/pull/595\n\t\tadd SIMD acceleration to SpatialMap.smooth() for 2-6x speedup, https://github.com/MesserLab/SLiM/pull/599\n\tfix #593, Student's T distribution had a sign error in the SpatialKernel method tdist(), thanks to Andy Kern, https://github.com/MesserLab/SLiM/issues/591\n\tupdate citations listed by citation()\n\tCI workflow for calculating code coverage with Codecov, thanks to Andy Kern, https://github.com/MesserLab/SLiM/pull/601\n\tfix #594, the pedigreeID and haplosomePedigreeID properties should be accessible (without other predigree-tracking features) in tree-seq models, even without pedigree tracking being enabled\n\tfix #584, a way to generate a random 64-bit integer is needed; added new rdunif64(integer$ n) function for this purpose\n\tshift over to Release 1 of the Total-Random fork of the PCG random number generator (better maintained), found at https://github.com/Total-Random/pcg-cpp/releases/tag/v1.0\n\tfix #602, (float)rdirichlet(integer$ n, numeric alpha) function to Eidos for Dirichlet distribution draws\n\tfix #610, distribution draws behave inconsistently with out-of-range parameters\n\t\trlnorm() accepted SD < 0 and returned a value; it should error, as rnorm() does (R returns NAN in the SD < 0 case, but erroring is more consistent with Eidos policies)\n\t\trexp() returned values for rate < 0; this should also error, consistent with Eidos policies\n\tadd zygosityOfMutations([No<Mutation> mutations = NULL], [integer$ hemizygousValue = 1], [integer$ haploidValue = 1]) for assessing zygosity (see also mutationsFromHaplosomes())\n\tpolicy change: the nucleotide and nucleotideValue properties of Substitution are now read-only (I think it was a bug that they were ever read-write...?)\n\tchange rects drawn by the Plot method rects() to have mitered corners, not bevelled\n\tfix #564, initializeMutationRateFromFile() needs a `sex` parameter\n\tfix #570, setMigrationRates() should make it easier to stop all migration (done in multitrait to avoid the annoying doc conflicts)\n\t\tspecifically, this entails two changes:\n\t\t\tallow a singleton migration rate value, applied for all subpops given\n\t\t\tallow the destination subpop to be given as a source, iff all rates supplied are 0.0, to stop all migration: allSubpops.setMigrationRates(allSubpops, 0.0)\n\tfix #567, plot windows can have their aspect ratio distorted due to screen size and other constraints\n\textend the Eidos identical() function to allow comparison of more than two parameters; e.g., (logical$)identical(* x, * y, ...)\n\tpolicy change: mean(integer(0)) or mean(float(0)) now returns NAN rather than NULL, to match R; I just noticed this, and NAN does seem better\n\tfix #612, Haplosome needs a mutationCount property\n\tfix #621, add a Laplace distribution function, rlaplace()\n\tfix a bug (a regression, introduced in SLiM 3.7!) in printing of large float values; \".0\" is sometimes shown erroneously\n\tfix #598: in Xcode and Qt Creator, force AVX2 and FMA on for x86_64 builds (true since 2013), and NEON on for ARM64 builds (true since forever); this is pretty safe, and makes SIMD/SLEEF work even without the CMake magic for them\n\nversion 5.1 (Eidos version 4.1):\n\tadd recipe 16.11, life-long monogamous mating\n\tadd the ability to suppress the header line of a LogFile, with a new [logical$ header = T] parameter to createLogFile() (#516), and adding [Nl$ header = NULL] for setFilePath() (#516)\n\tadd [string$ sex = \"*\"] parameter to initializeRecombinationRateFromFile(), passed through to initializeRecombinationRate(); fixing an oversight (#524)\n\twrite \"chromosomes\" and \"this_chromosome\" keys out to provenance as well as metadata (#520)\n\tfix an annoying autoindent cursor position bug that I suspect is a Qt 6 regression in QPlainTextEdit\n\tadd a define of TSK_TRACE_ERRORS in Xcode for slim and SLiMguiLegacy, in DEBUG only, for easier tskit debugging; break on _tsk_trace_error()\n\tfix a regression that caused the sourceSubpop pseudo-parameter to be NULL in modifyChild() callbacks in all cases; add tests, improve documentation (#522)\n\tadd chromosomeSubposition property to Haplosome, providing whether the haplosome is index 0 or 1 within its individual, within the set of haplosomes for its associated chromosome\n\tadd a (numeric)sign(numeric x) function that returns the sign (-1, 0, 1) of each element\n\tcalcFST() with a windowed range (start/end) would error; was missing a unit test (#548)\n\tcalcSFS() with an integer (non-NULL) binCount would error in multi-chromosome models if mutations from multiple chromosomes (or NULL) were given\n\tsurvival() callback that moves individuals did not correctly update has_null_haplosomes_, leading to a crash or a DEBUG raise (#549)\n\tcalcMeanFroh() did not focus on the specified chromosome correctly, in multi-species models, and thus produced incorrect results (#545)\n\tadd infinite loop checking in Eidos; add [logical$ checkInfiniteLoops = T] option to initializeSLiMOptions() to disable checking for infinite loops in Eidos\n\tfix #539, crash reading malformed population file\n\tfix #535, allow transparency in plots: added [float alpha = 1.0] to Plot methods abline(), lines(), points(), and text() (required to be singleton for lines())\n\tfix #547, mutation trajectories plot is confusing in the way it starts collecting data at the time it is opened\n\tfix #534, support uniparentally-transmitted chromosomes in hermaphrodite populations\n\tadd new Plot legendTitleEntry() method for making a title line in a plot legend\n\tclick-drag in the SLiMgui script view's line number area now drag-selects whole lines\n\tfix #550, add filter() function to Eidos, which is essentially a subset of R's filter(): (float)filter(numeric x, float filter, [lif$ outside = F])\n\tpartial fix for #530, add function (numeric$)tr(numeric x) to obtain the trace of a square matrix\n\tpartial fix for #530, add function (numeric)outerProduct(numeric x, numeric y) to obtain the outer product of vectors x and y\n\tpartial fix for #530, add function (numeric$)det(numeric x) to obtain the determinant of a square matrix\n\tpartial fix for #530, add function (float)inverse(numeric x) to obtain the inverse of a square non-singular matrix\n\tpartial fix for #530, add function (numeric)matrixPow(numeric x, integer$ power) to raise a matrix to an integer power\n\tpartial fix for #530, extend cor() and cov() to support correlation/covariance between the columns of a matrix (or matrices), as in R\n\t\tpolicy change: cov(x, y), cor(x, y), var(x), and sd(x) with x and/or y of length 1 now returns NAN (used to return NULL);\n\t\t\tthis is because you can't make a matrix containing NULLs, and Eidos doesn't have NA (which is what R uses in this case)\n\tadd Duplicate command to the Edit command, command-D, useful for code editing; change Show Debugging Output to shift-command-D\n\tadd \"Show SLiMgui Color Scales\" command to the Help menu in SLiMgui\n\tfix #553, an off-by-one bug in initializeRecombinationRateFromFile(); breaks backward compatibility, by fixing this bug\n\tadd image() method to Plot to add a SpatialMap or Image to a plot: (void)image(object$ image, numeric$ x1, numeric$ x2, numeric$ y1, numeric$ y2, [logical$ flipped = F], [float$ alpha = 1.0])\n\tadd matrix() method to Plot to add a matrix-based image to a plot: (void)matrix(numeric matrix, numeric$ x1, numeric$ x2, numeric$ y1, numeric$ y2, [logical$ flipped = F], [Nif valueRange = NULL], [Ns$ colors = NULL], [float$ alpha = 1.0])\n\tfix #538, check for unique SLiM ids only for alive individuals when loading a tree sequence\n\tfix #533, memory smasher in Haplosome method nucleotides(format=\"char\"); besides causing random crashes, this also caused this method to return incorrect results\n\tfix #527, add calcLD_D() and calcLD_Rsquared() popgen functions, contributed by Vitor Sudbrack\n\tfix apparently new STL check that double comparators for std::sort() must induce a strict weak ordering, including with NAN values; self-tests started raising\n\tfix #558, add new ways of subsetting matrices/arrays with A[B], or assigning into subsets of matrices/arrays with A[B] = ... : with a conformable logical matrix/array, or with an integer matrix that selects elements of the target\n\tadd asVector() method to strip off dimension attributes; this can be done with c() or x[] also, but it's nice to have the function, since R has it...\n\tfix #526, add a calcDxy() popgen utility function to SLiM that calculates Nei's Dxy genetic divergence statistic, contributed by Vitor Sudbrack\n\tfix #529, extend calcFST() to support multiple chromosomes\n\textend subsetMutations() to support subsetting mutations belonging to more than one chromosome\n\tfix #560, add recipe 14.16 \"Visualizing linkage disequilibrium\" to demonstrate the new calcLD_D() and calcLD_Rsquared() functions\n\nversion 5.0 (Eidos version 4.0):\n\tmulti-chromosome transition:\n\t--- main changes to existing APIs:\n\t\t\tclass Genome -> class Haplosome\n\t\t\tHaplosome class (from Genome class):\n\t\t\t\tproperty genomeType -> removed in favor of `chromosome.type`\n\t\t\t\tproperty isNullGenome -> isNullHaplosome\n\t\t\t\tproperty genomePedigreeID -> haplosomePedigreeID\n\t\t\t\tmethod mutationCountsInGenomes -> mutationCountsInHaplosomes\n\t\t\t\tmethod mutationFrequenciesInGenomes -> mutationFrequenciesInHaplosomes\n\t\t\tSubpopulation class:\n\t\t\t\tproperty genomes -> haplosomes\n\t\t\t\tproperty genomesNonNull -> haplosomesNonNull\n\t\t\tIndividual class:\n\t\t\t\tproperty genomes -> haplosomes\n\t\t\t\tproperty genomesNonNull -> haplosomesNonNull\n\t\t\t\tproperty genome1 -> haploidGenome1\n\t\t\t\tproperty genome2 -> haploidGenome2\n\t\t\tSpecies class:\n\t\t\t\tproperty chromosome: now usable only in single-chromosome models\n\t\t\t\tproperty chromosomeType -> removed in favor of `chromosome.type`\n\t\t\tMutationType class:\n\t\t\t\tproperty haploidDominanceCoeff -> hemizygousDominanceCoeff (applies only facing a null haplosome, not in \"true\" haploid chromosomes!)\n\t\t\tmutation() callbacks:\n\t\t\t\tpseudo-parameter genome -> haplosome\n\t\t\trecombination() callbacks:\n\t\t\t\tpseudo-parameter genome1 -> haplosome1\n\t\t\t\tpseudo-parameter genome2 -> haplosome2\n\t\t\tparameter name changes: calcFST(), calcPairHeterozygosity(), calcHeterozygosity(), calcWattersonsTheta(), calcInbreedingLoad(), calcPi(), calcTajimasD()\n\t\t\tparameter name changes: addEmpty(), addRecombinant()\n\t--- main additions to APIs:\n\t\t\t(object<Chromosome>$)initializeChromosome(integer$ id, [Ni$ length = NULL], [string$ type = \"A\"], [Ns$ symbol = NULL], [Ns$ name = NULL], [integer$ mutationRuns = 0])\n\t\t\tinitializeSex(): should now allow, and default to, NULL which should be used for all new models; \"A\" / \"X\" / \"Y\" should still be allowed for backward compatibility\n\t\t\tHaplosome class:\n\t\t\t\tproperty: chromosome => (object<Chromosome>$)\n\t\t\tChromosome class:\n\t\t\t\tproperty id => (integer$)\n\t\t\t\tproperty length => (integer$)\n\t\t\t\tproperty type => (string$)\n\t\t\t\tproperty symbol => (string$)\n\t\t\t\tproperty name <-> (string$)\n\t\t\tSpecies class:\n\t\t\t\tproperty chromosomes => (object<Chromosome>)\n\t\t\t\tproperty sexChromosomes => (object<Chromosome>)\n\t\t\t\tmethod: (object<Chromosome>)chromosomesOfType(string$ type)\n\t\t\t\tmethod: (object<Chromosome>)chromosomesWithIDs(integer ids)\n\t\t\t\tmethod: (object<Chromosome>)chromosomesWithSymbols(string symbols)\n\t\t\tIndividual class:\n\t\t\t\tmethod: (object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome> chromosomes = NULL], [Ni index = NULL], [logical$ includeNulls = T])\n\t\t\tMutation class:\n\t\t\t\tproperty: chromosome => (object<Chromosome>$)\n\t\t\tSubpopulation class:\n\t\t\t\tmethod: (object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome> chromosomes = NULL], [Ni index = NULL], [logical$ includeNulls = T])\n\t\t\t\tmethod: (object<Individual>)addMultiRecombinant(object<Dictionary>$ pattern, [Nfs$ sex = NULL], [No<Individual>$ parent1 = NULL],\n\t\t\t\t\t\t\t[No<Individual>$ parent2 = NULL], [logical$ randomizeStrands = F], [integer$ count = 1], [logical$ defer = F])\n\t--- policy changes:\n\t\t\tpolicy change: the old \"haplosome type\" (A/X/Y) in the genome metadata is now a chromosome type (different) in the haplosome metadata\n\t\t\tpolicy change: similarly, haplosome type A/X/Y in SLiM output (e.g., outputFull()) is now a chromosome type (different)\n\t\t\tpolicy change: initialization order is a bit stricter; initializeSex() with \"X\" or \"Y\" must come earlier, before calls that would define an implicit \"A\" chromosome\n\t\t\tpolicy change: the 1D SFS graph and haplotype plot no longer depend upon the current chromosome range selection; that was weird, and doesn't work well in multichrom\n\t\t\tpolicy change: the \"remove fixed mutations\" stage of the WF tick cycle is now after \"offspring become parents\" (no user-visible difference except WF tick cycle diagram)\n\t\t\tpolicy change: mutationRuns= for initializeSLiMOptions() has been changed to [l$ doMutationRunExperiments=T]; pass mutationRuns= to initializeChromosome() instead\n\t\t\tpolicy change (slight): the haplosome1Null and haplosome2Null parameters to addEmpty() now apply only to type \"A\" chromosomes, causing a minor break in backward compatibility\n\t\t\tpolicy change: randomizeStrands must now usually be explicitly specified for both addRecombinant() and addMultiRecombinant();\n\t\t\t\tthe default is now NULL, and NULL errors so that T or F must be explicitly given unless it does not matter (i.e., there is no recombination)\n\t\t\tpolicy change: fix #487, changing TSK_SIMPLIFY_KEEP_UNARY to TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS for retainCoalescentOnly=F (a change in simplification behavior)\n\t\t\tpolicy change: color variables on Individual now exist only under SLiMgui; at the command line there is now no memory backing them, so they cannot be used as scratch space\n\t--- tree-sequence recording changes:\n\t\t\tshift to a tree sequence for each chromosome, sharing the node, individual, and population tables across all tree sequences; new TreeSeqInfo struct for per-chromosome state\n\t\t\tremembered_haplosomes_ is now remembered_nodes_; it retains nodes that are shared across the tree sequences, and that can represent multiple haplosomes\n\t\t\tHaplosome no longer keeps its tskit node id; the individual keeps two tskit node ids for first and second position, used across all chromosomes in the shared node table\n\t\t\tadded a list of chromosomes to the top-level metadata (`chromosomes`), changed the top-level schema to describe this (optional) list\n\t\t\tadded a description of the focal chromosome to the top-level metadata (`this_chromosome`), changed the top-level schema to describe this (required) key\n\t\t\tchanged Genome metadata to Haplosome metadata, removed chromosome type, identical for all haplosomes of a given position in an individual\n\t\t\t\tthe way the is_null flags for haplosomes is handled is completely reworked and rather complex, of necessity; see comments in the code\n\t\t\trelative to original multichrom design, changed node metadata from `is_null` to `is_vacant` to reflect semantic shift; now it indicates non-null (0) versus unused/null (1); changed schema\n\t\t\tbumped .trees version number to 0.9\n\t\t\ttreeSeqOutput() writes a single .trees file for single-chromosome models (the existing behavior), but now creates a \"trees archive\" directory with .trees files inside for multichrom models\n\t\t\twhen saving a trees archive, [l$ overwriteDirectory=F] now controls whether an existing directory that looks like a trees archive will be overwritten (dangerous!)\n\t--- input/output formats and methods:\n\t\t\tthe default symbol for implicit chromosomes are \"A\", \"X\", or \"Y\", so output formats don't change for legacy models\n\t\t\tfix built-in mutation/substitution output methods for multiple chromosomes:\n\t\t\t\tSpecies method outputMutations(): in models with >1 chromosome, this now outputs the chromosome symbol after the position\n\t\t\t\tSpecies method outputFixedMutations(): in models with >1 chromosome, this now outputs the chromosome symbol after the position\n\t\t\tfix built-in MS input/output methods for multiple chromosomes:\n\t\t\t\tHaplosome method outputMS(): check that all haplosomes belong to a single chromosome, output MS based on that\n\t\t\t\tSubpopulation method outputMSSample(): add a [Niso<Chromosome>$ chromosome = NULL] parameter to identify the chromosome to sample with\n\t\t\t\tHaplosome method readFromMS(): check that all haplosomes belong to a single chromosome, input MS based on that\n\t\t\tfix built-in SLiM-format partial input/output methods for multiple chromosomes:\n\t\t\t\tHaplosome method output(): check that all haplosomes belong to a single chromosome; output the chromosome symbol in the header if multi-chrom\n\t\t\t\tSubpopulation method outputSample(): check that all haplosomes belong to a single chromosome\n\t\t\tfix built-in VCF input/output methods for multiple chromosomes:\n\t\t\t\tHaplosome method outputVCF(): check that all haplosomes belong to a single chromosome; pairs haplosomes as appropriate\n\t\t\t\tSubpopulation method outputVCFSample(): check that all haplosomes belong to a single chromosome; use chromosome symbols for the CHROM column\n\t\t\t\tadd [l$ groupAsIndividuals = T] parameter; if F, each haplosome is emitted as a haploid call rather than forming diploids, regardless of the chromosome's ploidy\n\t\t\t\tHaplosome_Class::ExecuteMethod_readFromVCF(): require VCF data that is single-chromosome, as with output\n\t\t\tfix built-in SLiM-format full input/output methods for multiple chromosomes:\n\t\t\t\tSpecies method outputFull(): allow multi-chromosome output with a new sectioned format, for both text and binary\n\t\t\t\tSpecies method readFromPopulationFile(): support reading multi-chromosome output, for both text and binary\n\t\t\t\tpolicy change: readFromPopulationFile() breaks backward compatibility with old file formats, for both text and binary; too much has changed\n\t\t\tchange file format codes for class Haplosome from GS/GM/GV to HS/HM/HV, matching the rename from Genome to Haplosome\n\t\t\tadd support for writing/reading Individual tag values in outputFull(), readFromPopulationFile()\n\t\t\tadd Individual output method +outputIndividuals(), for writing out a sample of individuals in SLiM format with optional metadata\n\t\t\tadd Individual output method +outputIndividualsToVCF(), for writing out a sample of individuals in VCF format with optional metadata\n\t\t\tadd recipe 8.3.6, output from multi-chromosome models\n\t\t\tadd Individual method readIndividualsFromVCF(), allowing reading of multi-chromosome data from VCF into a vector of individuals\n\t\t\tfix a bug in the neutral-sim tracking logic in readFromVCF() that I don't think anybody ever actually hit (reading a non-neutral mutation for a neutral mutation type)\n\t\t\trename the Haplosome method readFromVCF() to readHaplosomesFromVCF(), and readFromMS() to readHaplosomesFromMS(), for naming consistency; add SLiMgui autofix; revise recipe 18.12 for this rename\n\t\t\trename Haplosome methods output(), outputMS(), and outputVCF() to outputHaplosomes(), outputHaplosomesToMS(), and outputHaplosomesToVCF(), to parallel the new Individual output methods\n\t\t\textend outputFull() to support saving out substitutions, in a table at the end in the same format as outputFixedMutations()\n\t\t\tchange outputFull() individualTags parameter to objectTags, persist tags for individual, mutation, substitution, haplosome, subpopulation, and chromosome\n\t\t\textend readFromPopulationFile() to support restoring substitutions and tag values, but only for output in binary format; parsing text is too annoying\n\t\t\tadd [l$ objectTags=F] flag to outputIndividuals(), outputHaplosomes(), outputFixedMutations(), and outputMutations(), mirroring the work done for outputFull()\n\t--- other multi-chromosome related changes:\n\t\t\tadd autofixes in SLiMgui for the above API changes\n\t\t\trevise recipes for new terminology/APIs\n\t\t\tadd multichromosome display to SLiMgui\n\t\t\tadd a \"chromosome display\" window where you can view all the chromosomes simultaneously\n\t\t\timproved the accuracy of mutation run experiments, and the quality of the output generated by them, and extended them to be per-chromosome\n\t\t\textend subsetMutations() (on Species) to allow the chromosome to also be specified\n\t\t\tfor addSubpop(), haploid=T now requests specifically that type \"A\" chromosomes be made with their second haplosome null (for haplodiploidy, and backward compatibility)\n\t\t\tremove the SLiMguiLegacy haplotype plot; it would need to be fixed, and is no longer used by anybody (the one in SLiMgui remains, of course)\n\t\t\tremove the SLiMguiLegacy chromosome view OpenGL code; again, it would need to be fixed, and maintaining it is an unnecessary headache\n\t\t\tadd templating of GenerateIndividualX() for speed, as was done before for the MungeIndividualX() and HaplosomeX() methods, for speed\n\t\t\timplement addMultiRecombinant() for complete control over reproduction in multi-chromosome models\n\t\t\textend addRecombinant() and addMultiRecombinant() to allow NULL as a breaks vector with two strands, meaning \"draw breakpoints for me\", to avoid needing drawBreakpoints() in most cases\n\t\t\t\tthis new code path also allows gene conversion including heteroduplex mismatch repair and gBGC to work with addRecombinant() and addMultiRecombinant()\n\t\t\t\talso change to allow a recombination rate to be set for haploid chromosomes; this is potentially useful with addRecombinant() etc.\n\t\t\tadd addPatternForClone(), addPatternForCross(), addPatternForNull(), and addPatternForRecombinant() methods to Species for use with addMultiRecombinant()\n\t\t\tadd recipe 15.22, \"Complex multi-chromosome inheritance with addMultiRecombinant()\", to illustrate addMultiRecombinant()\n\t\t\tmodified recipes 15.14 and 15.21 to illustrate that NULL can now be passed to addRecombinant() for breaks to get automatic breakpoint generation\n\t\t\tallow the user to retain Chromosome objects with defineConstant()\n\t\t\tnew PAR (pseudo-autosomal region) recipe for section 15.23, replacing the old recipe in section 14.5 (which will be moved to SLiM-Extras for posterity)\n\t\t\tnew recipe 9.11 (Ne estimation) with a new multichrom-aware version of function estimateNe_Heterozygosity() that requires the chromosome to be supplied\n\t\t\trecombination() callbacks can now be optionally declared with a chromosome specifier (id or symbol), to apply to just one chromosome\n\t\t\t\tregisterRecombinationCallback() now takes an optional chromosome parameter to specify that focal chromosome (breaking backward API compatibility)\n\t\t\tfix up the calc...() functions for multiple chromosomes, and to be robust to the case of zero mutations (existing at all, or within the supplied haplosomes), and to improve error-checking and documentation\n\t\t\tadd a [Niso<Chromosome]$ chromosome] parameter to relatedness(), to allow relatedness to be assessed for any model chromosome; extended to all chromosome types\n\t\t\tadd mutationsFromHaplosomes() method, deprecate uniqueMutationsOfType()\n\t\t\toptimize mutrun experiment timing for reproduction and fitness calculation in single-chromosome models; no need for per-haplosome timings in that case!\n\t\t\taccelerate haplosome accessors on Individual: haploidGenome[1|2], haploidGenome[1|2]NonNull, haplosomes, haplosomesNonNull\n\t\n\tnon-multichrom changes:\n\t\tfix the wiring for calcPi() and calcTajimasD() to call the correct code; they were broken in SLiM 4.3\n\t\tadd a \"page guide at column\" pref to SLiMgui, for those trying to lay out code to a maximum width\n\t\tfix a SLiMgui bug where an error panel would not be visible because it was obscured by a floating window above it, appearing to lock up the whole app\n\t\tfixed a long-standing SLiMgui bug involving mutation frequencies and mutation run reuse when a subset of the subpopulations are selected in the GUI\n\t\t\tas part of this, (1) cleaned up and improved the SLIM_CLEAR_HAPLOSOMES debugging code, (2) separated SLiMgui's refcounting more completely from\n\t\t\tSLiM's, and (3) fixed unreleased bugs in mutationFrequencies()/mutationCounts()/mutationFrequenciesInHaplosomes()/mutationCountsInHaplosomes()\n\t\tcleaned up the confusion around Dictionary vs. DictionaryBase; methods/functions can now use Dictionary in their signature without problems\n\t\tfix a bug in treeSeqMetadata(); if no metadata was found, it would return object<Dictionary>(0), not an empty Dictionary object (and it leaked)\n\t\trenamed recipe 15.10 to \"Recording a pedigree and following a pedigree in a nonWF model\" so it is clearer what it does\n\t\tsplit chapter 15 (nonWF models) into two chapters, involving a great deal of renumbering, reorganizing, and rewriting\n\t\tdisable defer=T for all nonWF reproduction methods; it now does the same thing as defer=F (and is documented as having that possibility)\n\t\tadd setValuesVectorized() method to EidosDictionaryUnretained, to set values 1:1 from a source vector into dictionary entries of objects; like vectorized property assignment, but for setValue()\n\t\tfix error position tracking for errors inside user-defined functions, and in most nested situations\n\t\tadd \"absorbing\" boundary condition option for deviatePositions(), returning a vector of individuals to be killed because they moved out of bounds\n\t\tadd new Subpopulation method deviatePositionsWithMap(), similar to deviatePositions() but adding a spatial map that defines inside/outside bounds\n\t\tdisable OpenGL by default on Windows; the user can turn it on in the prefs; just too many people experiencing broken drawing and being confused\n\t\tadd a color chart and a plot symbols chart to the SLiMgui Help menu's list of quick-reference charts it can show\n\t\tattempt to fix SLiMgui window visibility issues -- miniaturized windows not becoming visible, off-screen windows remaining offscreen, etc.\n\t\tadd calcSFS() function to the popgen utility functions suite, add recipe 9.12 to demonstrate it\n\t\tadd recipe 17.19, \"Modeling indirect competition mediated by resource availability\", demonstrating Sam's resource-explicit approach\n\t\tadd calcMeanFroh() function to the popgen utility functions suite, add recipe 14.15 to demonstrate it\n\t\textend deferred tick scheduling to allow scheduling to occur within a single tick, as long as it is for a later tick cycle stage\n\t\tinvestigated and diagnosed a break in backward compatibility: models involving the Y use the MT RNG differently (less), and thus diverge from SLiM 4.3\n\t\tadd rztpois() function to Eidos, to draw from a zero-truncated Poisson distribution\n\t\textend initializeGenomicElement() to allow NULL,NULL for start,end, making it very easy to configure a single chromosome-length genomic element\n\t\t\ttweak recipes 8.3.3, 8.3.4, 8.3.5, 8.3.6, 8.3.7, 16.3, 16.9, and 16.10 to show off this new functionality, since it's now the nicest way to handle this situation\n\t\tadd initializeRecombinationRateFromFile() and initializeMutationRateFromFile() built-in functions; tweak recipe 8.2.2 to utilize it\n\tbug fixes:\n\t\tfix #481, add a substitutionsOfType() method to Species, parallel to mutationsOfType()\n\t\tfix #473, that tree-seq scripts with a subtle timing error in the addition of a new mutation would not generate a good error message from SLiM\n\t\tfix #488, non-UTF-8 encoding causes poor error\n\t\tfix #476, external editing causes SLiMgui to get confused\n\t\tfix #479, CLI progress bar would be a nice option; this is now -p[rogress]\n\t\tfix #478, record resource usage information in the tree sequence provenance; now we also print user/sys CPU usage for -t[ime], since we now have the information\n\t\tfix #494, adding a -c / -check command-line option to check the syntax of the input script\n\t\tfix #496, calling addCustomColumn() or addMeanSDColumns() inside a for loop passing the loop index variable for custom= does bad things\n\t\t\talso, we now require an object value for the context parameter to belong to a class that is under retain-release, since this is a long-term reference and could cause a crash otherwise\n\t\tfix a bug with reloading pedigree IDs after outputFull(), using readFromPopulationFile()\n\nversion 4.3 (Eidos version 3.3):\n\tfixed a bug in calcWattersonsTheta(): the value calculated would be incorrect if a window (start/end) was specified\n\tadded TOC I and TOC II to the PDF index of the SLiM manual; removed the bottom-of-page links section, which made search difficult\n\tadd subpopulationsWithNames() method to Community, to facilitate being able to use user-defined names for subpops\n\tfix bugs in some graphs in SLiMgui that could cause incorrect display or a crash in various circumstances\n\tsend debug output to the main window as well as the debug output tab, to avoid important messages getting lost\n\tadd a label next to the Jump button that shows the declaration of the script block containing the selection; clicking it runs the Jump menu\n\tsort recipes by correct numerical order, in both the Recipes menu and the Find Recipe panel, on all platforms\n\tupdate Robin Hood Hashing to 3.11.5 to get some minor fixes\n\tupdate zlib from 1.2.13 to 1.3.1 to get some minor fixes\n\tsome fixes under the hood to make filesystem paths on Windows, using \\ instead of /, be better understood by Eidos\n\tfix an occasional crash in sampleIndividuals() due to an off-by-one error in buffer sizing\n\tfurther extend tick range expressions, for scheduling events/callbacks, to allow the use of constants that are not defined until later in a run (variable-length burn-in, etc.)\n\t\tadd recipe 17.6 II, to illustrate this new capability\n\timprove recording of subpopulations in the tree-sequence recording population table (#447)\n\tadd calcPi() and calcTajimasD() functions thanks to Nick Bailey\n\textend deviatePositions(), pointDeviated(), sampleNearbyPoint(), and sampleImprovedNearbyPoint() to allow vectorization with a different spatial kernel for each iteration\n\tfix a line-ending bug in readFile(); a CRLF file from Windows, read on macOS/Linux, would not strip the CR off the ends of the lines\n\tshift to supporting Qt6 and C++17 to build SLiMgui; Qt5 with C++11 is still supported\n\t\tfor macOS, Qt6 is now the supported platform for macOS 11/12/13/14; Qt5 should only be used on macOS 10.15\n\t\tfor Windows, Qt6 is now the supported platform for Windows 10 (1809 or later) and Windows 11\n\t\tfor Linux, Qt6 is now the supported platform for Red Hat 8.6/8.8/9.2, openSUSE 15.5, and Ubuntu 22.04 among others\n\t\tthese recommendations are based on Qt6's recommended platforms; earlier platforms should use Qt5\n\t\tfor more details see https://doc.qt.io/qt-6/linux.html, https://doc.qt.io/qt-6/windows.html, https://doc.qt.io/qt-6/macos.html\n\t\tbuilding with CMake will now default to Qt6 if CMake can find it, and fall back to Qt5 otherwise; should be automatic\n\tadd a \"Use OpenGL for fast display\" checkbox in the Preferences panel, making it possible to disable OpenGL when it doesn't work well (#462)\n\tadd genomicElementForPosition() and hasGenomicElementForPosition() methods on Chromosome\n\tpolicy change: genomicElements property is now in sorted order (not in order of declaration)\n\tadd a \"Copy as HTML\" command to copy script with syntax coloring and such\n\nversion 4.2.2 (Eidos version 3.2.2):\n\tfix SLiMgui crash with code completion\n\tfix spurious VCF reading error (number of calls not equal to number of samples) due to incorrect usage of eof()\n\nversion 4.2.1 (Eidos version 3.2.1):\n\tfix an issue in Linux release/installer builds with FORTIFY_SOURCE=3 (resulting in a \"buffer overflow\" error in self-test and in treeSeqOutput())\n\tfix a crash in BorrowShuffleBuffer(), introduced debugging a different problem; occurs when (a) a nonWF model has (b) a subpop of size 0 (c) at reproduction() time (d) before ever having a non-zero size\n\nversion 4.2 (Eidos version 3.2):\n\tfix for #418, a crash involving null genomes in nonWF (has_null_genomes_ was not set correctly by addCloned() or takeMigrants() when putting a null genome into a subpop that previously had none)\n\tbig changes to Eidos under the hood - removal of the singleton/vector distinction and EidosValue subclasses, add constness flag, differentiate casting vs. non-casting accesses, etc.\n\tpolicy change: float indices are no longer legal for subsetting, indices must be integer (or a logical vector, as usual); this was inherited from R and is a bad idea for Eidos\n\tpolicy change: assignment into object properties must match the type of the property; no more promotion to integer/float from lower types\n\tadd some internal magic to accelerate statements of the form \"x = c(x,y)\" by appending y onto the end of x directly\n\toptimize mapValue() / spatialMapValue() - 6x speedup for large-point-vector 2D case, with spatial bounds [0,1] in both dimensions, and no interpolation\n\toptimize strength() and interactionDistance() in the case where exerters != NULL; had a very bad algorithm, now O(N) instead of O(NM) where N is # exerters, M is # interactors for the focal receiver\n\tbroaden the for loop syntax in Eidos to allow multiple 'in' clauses, such as \"for (i in 1:5, j in 6:10) ...\"\n\t\tas a side effect, for loop index variables are now constants until the loop has finished\n\t\tto demonstrate the new syntax, recipes 10.5, 14.7, and 19.7 have been modified to use it\n\tfix #422: readFromPopulationFile() for .trees files in SLiM 4.1 hits a MUCH higher peak memory usage in some cases, due to over-copying of mutation runs\n\tadd deviatePositions() method to Subpopulation for even faster offspring positioning than with pointDeviated(); revise recipes 16.3 and 16.8 to use it\n\tadd basic custom plotting capabilities to SLiMgui, through the slimgui object, with new methods createPlot(), lines(), points(), and text(); revise recipes 13.5 and 14.7 to demonstrate this capability\n\tadd SLiMgui plotting of data from LogFile output, through a context menu in the debug output window; revise recipes 4.2.5 and 15.16 (text only, not code) to demonstrate this capability\n\tsplit out the new plotting functionality into a new class, Plot, available only in SLiMgui\n\tadd support for legends in the SLiMgui plotting code with addLegend(), legendLineEntry(), legendPointEntry(), and legendSwatchEntry()\n\tadd logFileData() method to the SLiMgui class to allow access to logged data, which is useful for live plotting in SLiMgui\n\tconvert recipe 15.17 over to SLiMgui live plotting, to illustrate addLegend(), logFileData(), abline(), etc.\n\tadd new serialize() mode, \"pretty\", for pretty-printed Dictionary output\n\timprovements to axis scaling, tick labels, axis labels, data range, etc., with some impact on built-in plots, but mostly for custom plots at this point\n\tadd axis() method to Plot, for fine-scale control over axis tick marks and labels\n\tsplit the \"squashed stabilizing selection\" recipe out from section 13.6 to make a new section 13.7, utilizing lots of live SLiMgui plotting for advanced visualization\n\tadd support for external editors (#423): changes made externally will now result in a panel offering to reload from disk, or (if a pref is set) automatic reloading as long as there is no conflict\n\tadd multispecies tick cycle diagrams to the Help menu in QtSLiM\n\tfix Sachin's scoped assignment bug (#430): x=x+1 would do the wrong thing in a local scope where x is defined as a global variable; it would increment the global instead of making a new local\n\textend SLiM script parsing to allow expressions for event/callback timing, evaluated at the end of initialize() callbacks; these may depend upon global constants, and even call functions\n\t\tevents and callbacks may now be scheduled for a non-consecutive set of ticks, not just a range; for example, seq() or c() may be used to construct the times at which a script block runs\n\t\tas a part of this work, rescheduleScriptBlock() no longer makes copies of the script block when non-consecutive ticks are requested; a single script block can now be scheduled non-consecutively\n\t\tupdate recipe 17.4 to use this new facility instead of rescheduleScriptBlock(), and add recipe 4.1.10 demonstrating defining constants for parameters and using them for tick scheduling; also update manual sections 20.2 and 26.1 for this\n\tmake the Dictionary constructor allow a non-singleton string vector, so the (JSON) result of readFile() can be passed directly to it\n\trevised recipes 16.6, 16.7, 16.8, 16.9, 16.10, and 16.11 to use new APIs and conventions (mapValue(), mapColor(), uppercasing defined constants)\n\trequire the symbol name passed to defineConstant() / defineGlobal() to be a valid Eidos identifier\n\tfix a bug that would cause failures to write buffered compressed data from writeFile(), only in SLiMgui; these failures were not reported to the user well (only through SLiMgui's stderr)\n\trecipe 14.7 is a ground-up rewrite, to show the utility of using marker mutations to track true local ancestry, including live plotting in SLiMgui\n\tadd estimatedLastTick() method to Community; useful for custom plotting where you want to know the span of the model up front, to set an axis range, for example\n\tadjusted recipe 5.3.1 to use zero-based subpopulation ids, simplifying the logic; the workshop uses this recipe and it was a common source of confusion\n\t\nversion 4.1 (Eidos version 3.1):\n\tfix a minor bug with autofix when opening multiple .slim documents at once in SLiMgui\n\tfix recipe 17.10 to set the time unit, to avoid the timescale warning from tskit\n\tadd \"-fno-math-errno\" in Other C++ Flags to improve performance and help with SIMD vectorization; not set for C, only C++, so this does not affect the GSL\n\t\terrno is presently used in C++ only with functions that are not affected by -fno-math-errno, like chdir() and strtoll() and such, so there is no sacrifice here at all\n\tsplit reproduction in nonWF models into a two-stage process of reproduction for all species, then merging for all species, to allow multispecies interactions to be used; no consequence for single-species models\n\tadd a new build flag: if -D BUILD_NATIVE=ON is set, -march=native is passed to the compiler and a native build, usable only on the build machine itself, is produced for better optimization\n\tadd a new build flag: if -D BUILD_LTO=ON is set, link-time optimization is enabled (if the compilers say they support it), for better optimization; if the build then fails, don't use it\n\tfix a major performance issue for nearestNeighbors(), nearestNeighborsOfPoint(), and subsetIndividuals() with very large subpopulation size\n\tmemory usage debugging improvements: add a \"vm\" option to the usage() function, add a usage() method to Community\n\tswitch from Quickselect to std::nth_element() for choosing medians when building the k-d tree; might break backward reproducibility in some edge cases\n\timprove performance of reading text SLiM-format population files, as produced by outputFull()\n\tmove minimum system requirement up to 10.13 (the oldest SDK supported by Xcode 14.2); the command-line tools should still run on older systems\n\tclean up some old usage that is now flagged by Xcode (sprintf to snprintf, deprecated Cocoa API, old build-numbering scripts in the project)\n\tadvance copyrights to 2023\n\tadd the ability to generate profiles at the command line as well as in SLiMgui, making it possible to profile SLiM when running parallel\n\t\tto turn this on in CMake, add \"-DPROFILE=ON\" to the CMake command line\n\t\tto turn this on in Xcode, set \"-DSLIMPROFILING=1\" in \"Other C Flags\" in each target you want to enable it in (not at the project level!)\n\textend the Eidos Dictionary class (but not DataFrame) to allow integer keys, making it more of a general \"associative array\" class that can represent ragged arrays and similar structures\n\t\tas a side effect, \"slim\" type dictionary serialization now *always* quotes string keys (policy change), to distinguish, e.g., \"10\" (string) from 10 (integer) in serialized output\n\textend the Eidos Dictionary class (and DataFrame) to allow objects of all classes to be added; dictionaries containing objects that are not under retain-release just can't be kept long-term\n\timprove InteractionType performance for certain queries, especially drawByStrength() with fixed interaction strength\n\tbug fix: drawByStrength() would return at most N individuals, where N is the size of the exerter subpop; but this is incorrect since draws are with replacement\n\tbug fix: neighborCount() and interactingNeighborCount() would return float(0) instead of integer(0) in certain circumstances, totalOfNeighborStrengths() would return integer(0) instead of float(0)\n\tadd recipe 14.16, \"modeling biallelic loci in script\" (complementing recipes 14.15 I and 14.15 II, which show how to do it with built-in mutations and a mutation() callback)\n\tdisallow multiple log files at the same path, since this is a common mistake and there's no clear use for it\n\tbug fix: problem with reading in JSON that contains an \"object\" (i.e., a dictionary) inside the top-level object\n\tupdate the zlib code in eidos_zlib to version 1.2.13 (13 Oct 2022), fixing some issues (see zlib ChangeLog file)\n\tchange to DWARF, not DWARF with dSYM, even for Release builds; I don't use the dSYM file to reverse-symbolicate crash reports, so it just slows down my Release builds (but turning it off is unusual, so I'm noting it here)\n\tadd an optimized case for sample() with replacement, when using a weights vector; orders of magnitude speedup for large tasks\n\tshift GitHub Actions for macOS to macos-11 and macos-12; macos-10.15 stopped working in early May 2023, deprecated\n\tadd an optional parameter to initializeGeneConversion(), [l$ redrawLengthsOnFailure = F], to avoid failures to lay out tracts in some models; no behavior change by default\n\tadd an optional parameter, [integer$ count = 1], to addCrossed(), addSelfed(), addCloned(), addRecombinant(), and addEmpty() to produce multiple offspring in one call\n\t\tthis entails a policy change: if no children are generated (due to rejection by modifyChild(), in particular), object<Individual>(0) is returned, not NULL\n\tadd a method -(integer)compactIndices(void) to Dictionary, to compact result dictionaries down to their non-empty values with sequential keys\n\tadd a new recipe, 17.11, on changing the tree-sequence simplification interval\n\tfix a bug with the Species methods mutationCounts() / mutationFrequences(), only for multispecies models; counts/frequencies would be zero for some species\n\t\tthis did not occur when running under SLiMgui (different code path), but always happened at the command line\n\tadd rank() function to Eidos (https://github.com/MesserLab/SLiM/issues/379); identical to R except that logical and string are not supported, and \"random\" is not supported; can be added later as needed\n\tbug fix: #361, more than 2 billion mutations overflows without a good error message\n\tbug fix: #365, problems loading a tree sequence; what I fixed is to catch the uncaught raise from std::stoll() in Species::DerivedStatesFromAscii()\n\tbug fix in pyslim to announce: https://github.com/tskit-dev/pyslim/issues/307\n\tfeature request: #378, add font bigger (command +) and font smaller (command -) menu items and shortcuts, so the user doesn't have to open the prefs window; note that with command = the shift key is needed\n\t\tthis meant removal of the shortcuts for prettyprint script and reformat script, since they conflicted (well, prettyprint conflicted); probably nobody cares\n\trevised recipe 17.3 to show how to persist tag values from a simulation in the tree-sequence metadata\n\tadd five logical tag properties to Individual, tagL0 - tagL4, to hold user-defined values of type logical\n\tadd parent1 and parent2 parameters to addRecombinant() so that parental pedigreeIDs can be tracked properly if desired\n\tadd sharedParentCount() method, a simplified version of relatedness() using only parent pedigree IDs to find full sibs (2) and haf-sibs (1)\n\tsplit SpatialMap out into its own Eidos class\n\t\tmake -defineSpatialMap() return an o<SpatialMap>$ object that can be used independently\n\t\tmake SpatialMap know the spatial bounds that it is aligned to; all uses of a given SpatialMap must use the same spatial bounds!  if a subpop changes its bounds, it checks the bounds of the spatial maps it is using\n\t\tmake SpatialMap know its name; it is now an intrinsic property of the map, used primarily for SLiMgui display, and must be unique within each subpopulation\n\t\tadd a constructor for SpatialMap that duplicates the spatial map object, with a new name\n\t\tallow a given SpatialMap to be retained long-term (e.g., with defineConstant() / defineGlobal())\n\t\tallow a given SpatialMap to be set on more than one subpopulation, with a new method addSpatialMap(); also removeSpatialMap() to take one out, and a spatialMaps property to get the maps currently on a subpop\n\t\tadd utility methods directly on SpatialMap for the things subpop already does – mapValue(), mapColor(), mapImage() – and deprecate the Subpopulation APIs (except spatialMapValue(), which remains useful and undeprecated, and can now take a SpatialMap object)\n\t\tadd a changeValues() method on SpatialMap to change the grid values of an existing spatial map\n\t\tadd various properties on SpatialMap: gridDimensions, interpolate, name, spatialBounds, spatiality, tag\n\tadd interpolate() to SpatialMap, to increase the resolution of a spatial map by interpolating new values\n\tadd smooth() to SpatialMap, to smooth/blur a map; internally, add the SpatialKernel class (not user-visible)\n\tadd add(), multiply(), subtract(), divide(), power(), exp(), range(), and gridValues() methods to SpatialMap\n\tadd sampleNearbyPoint() and sampleImprovedNearbyPoint() to SpatialMap, for searching habitat and such\n\tadd a t-distribution option for SpatialKernel, to provide a fat-tailed distribution that behaves better than Cauchy\n\tadd a Subpopulation method pointDeviated() that can deviate points using a kernel and enforce boundary conditions in one call\n\ttweak WF reproduction, addCrossed(), addSelfed(), addCloned(), and addRecombinant() to give the new offspring the same spatial position as the first parent, allowing efficient positioning with pointDeviated() in the typical usage case\n\tpolicy change: type 'f' kernels now require a finite maxDistance, since the alternative doesn't really make sense (note that type 'l' already required a finite maxDistance)\n\tnew option in the Individuals view for spatial models, to display the underlying grid points of the spatial map\n\tadd changeColors(), blend(), and rescale() methods to SpatialMap; extend changeValues() so it can take a SpatialMap as its parameter\n\tadd Laplace DFE for MutationType, type \"p\"; contributed by Nick O'Brien\n\textend sampleIndividuals() and subsetIndividuals() to support constraining by tagL0 - tagL4\n\t\tpolicy change: if tag is specified (non-NULL), the tag property must now have a defined value on all individuals; previously this was not checked, and individuals with an undefined tag value were simply excluded\n\tadd [logical$ randomizeStrands = F] flag to addRecombinant; if T, strand1/strand2 and strand3/strand4 will be randomized for each offspring generated\n\tadd InteractionType method setConstraints(), generalizing sex-specificity with a whole raft of other possible constraints on receivers and/or exerters; interally, now keep two k-d trees, one constrained, one not\n\t\tfixed a bug in passing: drawByStrength() and nearestInteractingNeighbors() were not applying sex-specificity to receivers, for the returnDict=T case (never released publicly)\n\t\tfixed a bug in passing: partial sex-specificity (receivers but not exerters, or exerters but not receivers) was not applied flexibly in multispecies models where one species is sexual and one is not\n\timplement 2D bicubic interpolation with periodic boundaries for the interpolate() method\n\tupdate from tskit C_1.0 to C_1.1.2, fixing a memory leak on load of a .trees file, and presumably other things also\n\tadd testConstraints() method to InteractionType, to test whether a set of individuals satisfy constraints or not\n\tadd clang-tidy support in CMake (for internal development), do a pass over eidos and core\n\tadd/modify recipes for new spatial modeling features: new 15.3 V on pointDeviated(); new 15.14 on SpatialMap, interpolate(), smooth(), and sampleNearbyPoint(); new 16.12 on interaction constraints and other stuff\n\tmodify recipes to demonstrate the use of tagL0: 10.4.2, 12.1, 12.5, 14.2 II, 16.17, 16.24\n\tmodify recipes that use addRecombinant() to use randomizeStrands=T where appropriate: 16.17, 16.25\n\tadd lowerTri(), upperTri(), and diag(); thanks to Nick O'Brien (@nobrien97) for this contribution\n\tmodify recipes to use count= parameter to addCrossed() etc., where appropriate: 16.3, 16.23\n\tadd xy, xz, yz, and xyz properties to Individual that allow joint access to the x/y/z properties, for easier spatiality operations in complex spatial models (and to support some unit testing additions)\n\tfixed a variety of memory leaks and extended the unit testing for leaks considerably; should be pretty clean in its memory usage now\n\tswitch chapters 15 and 16 (nonWF and spatial models) and reorganize/renumber to rationalize the manual organization; many recipe numbers changed\n\tspeed up findInterval() by using binary search instead of linear search - O(log n) instead of O(n) to find the interval for one element, with n being the number of intervals (i.e., the length of vec)\n\nversion 4.0.1 (Eidos version 3.0.1):\n\tfix the documentation for the timeUnit parameter of initializeTreeSeq(), which had not been updated for SLiM 4's policy change that the default is now \"ticks\" in all cases\n\tfix a bug that would bite tree-seq models that reloaded with readFromPopulationFile(); such models could trigger an internal error, or leak memory\n\tfix LogFile bug with an absolute filesystem path on Windows\n\tfix error incorrectly raised for treeSeqRememberIndividuals() with a zero-length individuals vector\n\tfix the error position reported for assignment into a non-existent property; this fixes a bug in SLiMgui's autofix feature, as a side effect (with, e.g., \"sim.generation = 5\")\n\trevise recipe 6.1.2 (reading a recombination map from a file) to use readCSV() instead of readFile()\n\textend the subset() method of DataFrame to accept NULL for rows/cols, to take entire columns or entire rows respectively, for usability\n\textend readCSV() to allow sep=\"\", meaning that the separator is \"whitespace\", as in R\n\tadd a stringRepresentation() method on Object, to provide the same string representation printed by print()\n\timprove memory usage for Individual, down to 192 bytes from 232 bytes, by compactifying the color information for SLiMgui and rearranging ivars to minimize wasted space\n\tthe color property on Individual no longer guarantees that the value read equals the value set; when a color is set, it is now converted to RGB, so named colors do not round-trip\n\tadd a meanParentAge property, to make calculating generation length simpler; unavailable in WF models (like age), 0 for parentless individuals\n\tadd DataFrame asMatrix() method to convert a DataFrame into a matrix, if all columns are the same type/class\n\tmodify recipe 16.12 II to use asMatrix() to read the mating and death files more elegantly\n\nversion 4.0 (Eidos version 3.0):\n\tfix deprecated pyslim API issues in recipes 17.2, 17.4, 17.5, 17.7, 17.8, 17.10, 18.13:\n\t\tuse tskit.load() instead of pyslim.load(), pyslim.recapitate() instead of ts.recapitate(), ts.metadata['SLiM']['generation'] instead of ts.slim_generation\n\tadd a second recipe to section 16.19 (range expansion in a stepping-stone model), showing how to solve the same migration problem with a survival() callback\n\tfix a crash (rather than an error) when calling removeMutations() on a null genome in some situations\n\tsplit SLiMSim into two new classes: Species and Community\n\tmoved to Community: properties logFiles, generationStage, verbosity; it also has properties tick and tag\n\tmoved to Community: methods createLogFile(), register[X]Event(), deregisterScriptBlock(), rescheduleScriptBlock(), outputUsage(); also has its own simulationFinished()\n\tchange generations to ticks across almost all APIs; the basic unit of time is now called a tick, \"generation\" is a species-specific concept\n\tremove the inSLiMgui property of SLiMSim (deprecated since SLiM 3.2.1)\n\tremove vestiges of the xDominanceCoeff parameter to initializeSex() and the dominanceCoeffX property of SLiMSim (removed originally in SLiM 3.7)\n\tchange GO (generation of origin) to TO (tick of origin) in VCF output (should be able to read both annotations)\n\taddNewMutation() and addNewDrawnMutation() have had their originGeneration parameter removed (first made redundant in SLiM 3.5)\n\toriginGeneration property of Mutation and Substitution renamed to originTick; fixationGeneration property of Substitution renamed to fixationTick\n\tgeneration parameter to recalculateFitness() renamed to tick\n\tgenerations parameter to rescheduleScriptBlock() renamed to ticks\n\tnew addTick() method added to LogFile\n\tnew output formats include both the tick and cycle, for outputFull(), outputMutations(), outputFixedMutations()\n\ttop-level tree-sequence metadata produced by outputTreeSeq() now includes both the tick (\"tick\") and generation (\"generation\")\n\ttree-sequence metadata for mutations has changed the sense of \"slim_time\" to be in ticks, not generations\n\ttree-sequence metadata for individuals has changed the sense of \"SLIM_INDIVIDUAL_METADATA_MIGRATED\" to indicate migration in the last tick, not the last generation\n\tadd Generation textfield below the Tick textfield in SLiMgui & SLiMguiLegacy\n\tadd name and description properties to Species; these are the species name as declared in script and a user-controlled description string; they get persisted in tree-seq top-level metadata\n\tincrement the tree-seq file version from 0.7 to 0.8\n\tincrement version to 4.0 - usually this is not done until it's time to roll the release, but since we're on a branch, it is useful for testing purposes\n\tLogFile methods addGeneration(), addPopulationSexRatio(), and addPopulationSize() now take [No<Species>$ species = NULL]; if not supplied, it will default to a singleton species if possible\n\tSpecies now supports simulationFinished(), but only in the single-species case; in multispecies models call community.simulationFinished() instead\n\tmake \"early()\" required; the default block type has been a source of confusion and is worse now with the multispecies syntax\n\tadd optional \"species <identifier>\" and \"ticks <identifier>\" syntax to the SLiM top-level syntax to modify block declarations\n\tmake the Object Tables window in SLiMgui display all objects, across all species\n\tadd initializeSpecies() function to set species-specific options in explicit-species models: [i$ tickModulo = 1], [i$ tickPhase = 1], and [Ns$ avatar = NULL], for now\n\tSLiMgui now displays avatars in the Object Tables window\n\tadd allSpecies, allGenomicElementTypes, allInteractionTypes, allMutationTypes, allScriptBlocks, allSubpopulations properties to Community\n\tgraph windows (and haplotype plots) are now associated with the focal species at their time of creation, and display the species avatar as a badge\n\tadd a species \"tab bar\" in SLiMguiLegacy and QtSLiM to choose which species is the focal display species (population view, chromosome view, new graph windows)\n\tadd id property to Species\n\tadd lookup by id on Community for subpopulations, mutation types, genomic element types, interaction types, script blocks, and species with xWithIDs() methods\n\tadd species property to Chromosome, GenomicElementType, InteractionType, MutationType, Subpopulation\n\tadd active property and skipTick() method to Species, start using ticksModulo/ticksPhase to actually control species activation\n\tadd 'all' as a reserved species name, add the 'ticks all' syntax for event declarations and make it required in explicit-species models\n\tadd [No<Species>$ ticksSpec = NULL] to registerXEvent() so created event blocks can have a ticks specifier; add speciesSpec and tickSpec properties to SLiMEidosBlock\n\tdocumentation/manual revisions for all of the above\n\tremove now-obsolete pseudo-parameters from callbacks (breaking backward compatibility in 4.0; not really multispecies-related):\n\t\tfitness(), reproduction(), mateChoice(): removed genome1, genome2 (kept these in recombination() callbacks since they are not redundant, indicating the initial copy strand)\n\t\tmodifyChild(): removed childGenome1, childGenome2, childIsFemale, parent1Genome1, parent1Genome2, parent2Genome1, parent2Genome2\n\t\trevised recipes in reaction to these changes: 10.3.1 I/II, 11.3, 12.2 I/II, 12.3, 13.1, 14.5, 16.13, 16.14, 16.16, 16.17, 18.8\n\tadd WF/nonWF generation cycle images to QtSLiM, under the Help menu, for quick reference\n\tadd a findInterval() function to Eidos\n\tchange calcFST() from \"average of ratios\" to \"ratio of averages\", following current best practice; this breaks backward compatibility for users of this function, but hopefully in a good way\n\tadd autocorrect smarts to SLiMgui for common changes needed to migrate to SLiM 4\n\tswitch InteractionType from using a semi-permanent sparse array to using a transient sparse vector, providing multispecies flexibility:\n\t\tadd \"species all initialize()\" for non-species-specific initialization, move initializeInteractionType() to be non-species-specific, remove the `species` property from InteractionType\n\t\tmake it required, in multispecies models, to declare interaction() callbacks as \"species all interaction()\"; they are always active, and are not associated with any one species\n\t\tmove registerInteractionCallback() from Species to Community, since interaction() callbacks are now non-species-specific\n\t\tchange InteractionType APIs to be more explicit about receiver vs. exerter, allow an exerter subpop to be specified, etc.; new APIs:\n\t\t\t– (float)clippedIntegral(No<Individual> receivers) - note this method now uses saved positions from evaluate(), and thus requires evaluation\n\t\t\t– (float)distance(object<Individual>$ receiver, [No<Individual> exerters = NULL]) - receiver must now be singleton (matching interactionDistance())\n\t\t\t– (float)distanceFromPoint(float point, object<Individual> exerters) - renamed from distanceToPoint(), parameters switched places for consistency\n\t\t\t– (object<Individual>)drawByStrength(object<Individual>$ receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL]) - \"receiver\", added exerterSubpop\n\t\t\t– (integer)interactingNeighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL]) - changed individuals to receivers, added exerterSubpop, require all receivers in one subpop\n\t\t\t– (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL]) - no change\n\t\t\t– (float)localPopulationDensity(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL]) - added exerterSubpop\n\t\t\t– (object<Individual>)nearestInteractingNeighbors(object<Individual>$ receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL]) - \"receiver\", added exerterSubpop\n\t\t\t– (object<Individual>)nearestNeighbors(object<Individual>$ receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL]) - renamed individual to receiver, added exerterSubpop\n\t\t\t– (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ exerterSubpop, [integer$ count = 1]) - parameters switched\n\t\t\t– (float)strength(object<Individual>$ receiver, [No<Individual> exerters = NULL]) - no change\n\t\t\t– (float)totalOfNeighborStrengths(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL]) - added exerterSubpop\n\t\tchange InteractionType::evaluate() API: (void)evaluate(io<Subpopulation> subpops) - `subpops` now required, remove `immediate`\n\t\tremove the `subpop` pseudo-parameter from interaction() callbacks; receiver.subpop and exerter.subpop should now be used, and are not always the same\n\t\trevised recipes for these changes (for evaluate() now requiring subpops, in all cases; no other changes needed): 15.2, 15.3 I/II/III/IV, 15.4, 15.5, 15.6, 15.7, 15.8, 15.9, 15.10, 15.11, 15.12, 16.10, 16.11, 16.18\n\t\tnote that these changes break backward compatibility for most models, and break backward reproducibility for many (due to distances not being rounded off from double to float in some code paths now)\n\tmove initializeSLiMModelType() to be non-species-specific (i.e., must be in \"species all initialize()\"), so it is shared and doesn't need to be repeated\n\tadd parameter color to initializeSpecies(), and property color to Species; add property avatar to Species; tweak avatar to be [s$=\"\"] not [Ns$=NULL], the empty string can be the default\n\tadd \"Multispecies Population Size ~ Time\" graph to SLiMgui\n\tshift initialization requirements to allow \"no-genetics\" species to omit all of their genetic setup (mutation and recombination rates, mutation types, genomic element types, genomic elements)\n\tobsolete the term \"generation\" in favor of \"cycle\", \"generation cycle\" in favor of \"tick cycle\"; user-visible API changes:\n\t\tSpecies.generation -> .cycle, Community.generationStage -> .cycleStage\n\t\tchange the \"generation\" metadata key in the tree sequence top-level scheme to \"cycle\"\n\t\tLogFile.addGeneration() -> .addCycle(), LogFile.addGenerationStage() -> .addCycleStage()\n\t\tchange the column names produced by LogFile from \"generation\" and \"gen_stage\" to \"cycle\" and \"cycle_stage\"\n\t\trevise recipes to use the new properties and methods, have correct comments, etc.\n\tadd recipes 19.1, 19.2, 19.3, 19.4, 19.5, 19.6, 19.7: new multispecies recipes!\n\tadd neighborCount() and neighborCountOfPoint() methods to fill out the InteractionType API\n\tmodify recipe 18.14 to unique down nucleotide-based mutations regardless of their mutation type (mutation() rather than mutation(m1))\n\tadd recipe 18.15, showing how to unique down to the ancestral state when that is desirable\n\tadd an \"all\" tab to the species bar, to see all species simultaneously in the UI\n\tadd a [No$ subpopMap = NULL] parameter to readFromPopulationFile() to allow remapping of subpopulation ids on load, for .trees\n\tadd a \"Scheduling\" tab in the output viewer that shows tick/cycle/event/callback scheduling in chronological order\n\trelax the prohibition on calling cachedFitness() from late() in a WF model; it is now allowed IF recalculateFitness() has been called first\n\tfix a bug that caused malformed metadata for (a) models where a subpop was removed, when (b) those subpops had a larger SLiM id than other subpops (and were thus at the end of the population table)\n\toptimizations for several cases of sample() and sampleIndividuals() in the case of multiple draws without replacement\n\tadd calcInbreedingLoad() function, courtesy of Chris Kyriazis\n\tadd [logical$ randomizeCallbacks = T] to initializeSLiMOptions() to turn of randomization of the order individuals are processed with callbacks; T by default, breaks backward reproducibility unless set to F\n\tadd new section 14.15 recipes: biallelic models showing how to use mutation() callbacks, unique down, and handle back-mutation\n\tadd \"Focus on Script\" and \"Focus on Console\" keyboard shortcuts for keyboard warriors\n\trevise Python recipes to match current usage: 17.2, 17.4 II, 17.5 II, 17.7 II, 17.8 I, 17.8 III, 17.9 I, 17.10 II, 18.13 III\n\tadd species color lines in the script editor in SLiMgui, in multispecies mode\n\trelax call timing restrictions to allow species to operate upon each other within callbacks more broadly\n\tadd recipe 19.8: Within-host reproduction in a host–pathogen model\n\tremove the `active` property of Species, at least for now; I decided that the existence of this might paint me into a corner with respect to possible extensions to the skipTick() mechanism\n\tmerge in tskit C API 1.0 final\n\trelax unnecessary restrictions on reading, writing, addSubpop(), addSubpopSplit(), treeSeqRememberIndividuals(), treeSeqSimplify(), etc. being done in first() events\n\tadd willAutolog() method to LogFile to find out whether it will log automatically at the end of the current tick\n\tadd addSuppliedColumn() and setSuppliedValue() methods to LogFile, to support columns that are supplied their value by script, rather than generating them\n\tremove the removeConstants parameter from rm(); it is no longer possible to remove defined constants, use defineGlobal() instead if you want to change a global value\n\tadd killIndividuals() method on Species, for nonWF models only, to kill a given vector of individuals, immediately removing them from their subpopulations\n\tbug fix: add mutation frequency/count invalidation in more spots: addSubpop()/addSubpopSplit(), setSubpopulationSize(0) (WF), removeSubpopulation(), killIndividuals(), takeMigrants()\n\t\tthe results from sim.mutationFrequencies() / sim.mutationCounts() could be incorrect after one of those calls, for a complete tick cycle (test: test_freqCountChange_*.slim)\n\t\tSLiM's internal tally never produced incorrect fixation/loss, so the bug should manifest only in script, only when those methods are used (test: test_fixloss_*.slim)\n\t\tit could also result in (harmless) incorrect display of frequencies in SLiMgui at the end of a tick in which a subpopulation was removed (test: test_subpopRemoved_*.slim)\n\tfitness() callback redesign (breaks in backward compatibility):\n\t\tchange fitness() callbacks to be called mutationEffect() callbacks\n\t\tchange relFitness to effect, inside mutationEffect() callbacks\n\t\tchange fitness(NULL) callbacks to be called fitnessEffect() callbacks\n\t\tsplit registerFitnessCallback() into registerMutationEffectCallback() and registerFitnessEffectCallback()\n\tadd display of the Git SHA-1 hash in slim and SLiMgui, to aid in debugging; works for builds under cmake and qmake, not under Xcode\n\tadd a \"progress indicator\" in SLiMgui, in the Tick counter lineedit, that shows the progress towards the last tick the model will execute (assuming it doesn't stop early)\n\tshift recipes 16.5, 16.19, and 19.8 to use killIndividuals(), for pedagogical purposes\n\nversion 3.7.1 (Eidos version 2.7.1):\n\tfix a problem with the python recipe for recipe 18.13\n\tfix printf format specifier on Windows that was causing issues with old compilers on conda\n\tfix spurious \"subpopulation p0 has already been used\" errors in certain circumstances (#274), which was biting stdpopsim\n\tfix a crashing bug with treeSeqOutput() due to an incorrectly sized malloc buffer\n\tget rid of a spurious self-test error that happened occasionally due to changed to relatedness(); the test itself was wrong (#269)\n\tfix the appearance of SLiMgui profile output when in dark mode (#270)\n\tadvance copyrights to 2022\n\tfix recipes 17.8 and 17.9 to use sim_ancestry() instead of simulate()\n\nversion 3.7 (Eidos version 2.7)\n\tchange to allow .trees files to contain unreferenced empty subpops, to allow ancestral use of subpops that are now empty (see #168)\n\tdisallow reuse of subpopulation ids if they have gone into the tree-sequence tables, to prevent collisions\n\tchange so that entries for unused subpops are not modified in population tables loaded from a tree sequence (PR #172)\n\tadd a [format='slim'] parameter to Dictionary.serialize(), adding support for JSON serialization with the 'json' format specifier (note the JSON serialization format changed slightly due to bug fixes)\n\tadd a Dictionary(string$ jsonString) constructor for creating a Dictionary from a JSON serialization\n\tadd an assert() function to easily assert that a condition is true\n\tadd string manipulation functions: strcontains(), strfind(), strprefix(), strsuffix() for string substring searching\n\tadd graph menu items to the Simulation menu in QtSLiM, as used to exist in the old SLiMgui; left out accidentally\n\tadd SLiMSim method individualsWithPedigreeIDs() for fast lookup by pedigree ID, for keeping track of long-term interactions\n\tfix functions/methods that take Subpopulation/MutationType/SLiMEidosBlock to also accept an integer id, as most functions/methods already do:\n\t\tcalcVA(), rescheduleScriptBlock(), individualsWithPedigreeIDs(), mutationCounts(), mutationFrequencies(), nearestNeighborsOfPoint(), evaluate()\n\tfix JSON parsing bugs (singleton string value, illegal values)\n\tadd first() events at the start of the generation cycle\n\tadd survival() callbacks governing mortality in nonWF models\n\tmodify Eidos grammar for function declarations slightly, to allow a unary minus preceding a numeric default argument value\n\tswitch from Subpopulation-level object pools for genome/individual to Population-level object pools; get rid of a lot of ugly code as a result, particularly in takeMigrants()\n\tminor policy change: removeMutations() will no longer warn when called from a late() event in nonWF, or an early() event in WF, *if* it was asked to create a substitution\n\tpolicy change: source() now raises an error if the file path it is given does not exist\n\tadd [logical$ chdir = F] argument to source(), mirroring R's parameter of the same name, to make include-style usage of source() simpler (#190)\n\tadd the ability to relocate an individual with a survival() callback, to enable sperm storage and other such models where life continues after death\n\tadd recipe 16.22, sperm storage with a survival() callback\n\trevise recipe 16.12 to use a survival() callback\n\tadd recipe 16.23, tracking separate sexes in script nonWF style\n\tfix InteractionType to allow > 2 billion interactions in a model (switch from uint32_t to uint64_t)\n\tadd an \"action button\" at the bottom of the haplotype plot window, like that in graph windows\n\tadd checks for malloc/calloc/realloc failures, for clusters that make allocations fail when the process is at its memory limit\n\tfix a small bug involved duplicate derived states getting recorded by addNewDrawnMutation() when multiple mutations are added at the same position\n\tupdated to tskit C_0.99.14 (big metadata bug fix)\n\tupdated to unversioned tskit code to get improved consistency checking stuff quickly; will update to a tagged version when one comes out\n\tadd a concept of deprecated APIs in Eidos, to allow properties/methods to be documented as deprecated but not auto-completed\n\tnow perform fuller consistency checks (mutation/node time mismatches) every generation in DEBUG, and also now after simplification in DEBUG\n\tchange addRecombinant() to use (NULL, NULL, NULL) as a signal to create a null genome, rather than an empty genome without new mutations; this better reflects the existing semantics (breaks backward compatibility)\n\tadd genomesNonNull property to Subpopulation and Individual, returning those genomes of the subpop/individual that are not null genomes, for easier management of models that contain null genomes\n\tadd flags to addEmpty() allowing the user to request that either or both genomes ought to be null rather than just empty\n\tadd isHaploid=F flag to addSubpop()\n\tremove the dominanceCoeffX property of SLiMSim and the xDominanceCoeff parameter to initializeSex() (breaks backward compatibility)\n\tadd a new haploidDominanceCoeff property to MutationType to take its place with more flexibility and generality\n\trevise recipes as needed (16.13, 16.14 - the nonWF haploid recipes) to adjust for the above changes\n\textend outputFull(), readFromPopulationFile(), and .trees I/O to support null genomes and haploids\n\tallow readFromPopulationFile() with a .trees file even when tree-seq recording is not enabled\n\tadd an rnbinom() function to draw from a negative binomial distribution\n\tadd -write(s$ filePath) method to Image, to write an Image as a PNG file\n\tadd -spatialMapImage() method to Subpopulation to let you get an image for a spatial map\n\tadd tempdir() function to Eidos for better cross-platform support; revise recipes that use /tmp to use this (9.2, 9.3, 9.6.2, 17.3 I, 17.3 II)\n\tadd sysinfo() function to Eidos for better cross-platform support\n\tadd grep() function to Eidos for regular expression matching\n\tadd DataFrame class to Eidos (a subclass of Dictionary for representing data tables), with:\n\t\tproperties: colnames, dim, ncol, nrow\n\t\tmethods: cbind(), rbind(), subset(), subsetColumns(), subsetRows()\n\t\tother features: prints as a data table rather than a dictionary\n\tadd \"csv\" and \"tsv\" options to the Dictionary method serialize(), for generating CSV/TSV content (note serialize() now returns string, not string$)\n\tadd readCSV() function that reads a CSV (or TSV) file and returns a DataFrame\n\tmodify Dictionary method getRowValues() to make it useful as a contrast to DataFrame.subsetRows(), by allowing ragged rows, matrix/array elements; add [drop=F]; these changes are backward-compatible\n\tchange Eidos output of float values slightly; 1.0 now outputs as \"1.0\", not \"1\", to show that it is a float; seems better, breaks backward compatibility in a minor way\n\treplace recipe 14.4 (modeling inversions), incorporating changes from Vince Buffalo, Peter Ralph, & Andy Kern that fix several problems (see new discussion in the manual)\n\tadd the ability to create a new grayscale Image from a 2D matrix of values, the inverse of the integerK / floatK properties, as Image(numeric matrix); RGB may be added later if needed\n\tkeep a hash table from pedigree ID to individual table row, to speed up remembering of additional individuals\n \tadd parent pedigree ids to individual metadata (.trees file version increment); add pedigree-based info to the parent column of the individuals table\n\tadd summarizeIndividuals() to create vectors/matrices/arrays, and thereby spatial maps, that summarize a set of individuals\n\tadd recipe 15.13 showing how to use summarizeIndividuals() to make a spatial map (for density-dependent fecundity)\n\tfix the reproductiveOutput property so that it doesn't increment (or, in fact, decrements back down!) if a child is rejected by modifyChild()\n\tadd clippedIntegral() method to calculate the integral of an interaction function clipped to the spatial bounds of focal individuals\n\tadd localPopulationDensity() method to divide total strengths by clipped integrals to provide weighted local density values\n\trevise recipe 16.11 to use localPopulationDensity()\n\tupdate to robin hood hashing version 3.11.3 to get a few nice fixes and speed improvements\n\tfix a floating-point roundoff issue that would cause the frequency of fixed mutations, from mutationFrequencies(), to sometimes differ very slightly from 1.0\n\tadd recipe 16.24, haplodiploidy\n\tmodify recipe 16.15 (WF models implemented as nonWF models); there are now two recipes, the second one showing how to implement fitness-based mating success\n\tadd support for Markdown in the Jump menu (_italic_, *italic*, __bold__, **bold**; only in section header items, not in script block comments (Qt doesn't allow within-item formatting)\n\t\talso headers: # a lot larger (H1), ## a little larger (H2), ### default size (H3), #### a little smaller (H4), ##### medium-small (H5), ###### a lot smaller (H6)) (note the space after the hashes is required!)\n\tadd \"unified\" display mode in SLiMgui's individuals view\n\tWindows port, thanks to Russell Dinnage!  see manual for install instructions, etc.\n\tfix recipe 5.4 II (jump menu annotations with the Gravel model) to work with the new Markdown support added\n\tpolicy change: the same subpop identifier, such as p1, may not be reused in a model; this was already true for tree-seq, now it is enforced for all models for consistency (breaks backward compatibility)\n\tadd name and description properties to Subpopulation; persist them in treeseq metadata in the population table; switch the population table metadata schema from binary to JSON so we can add `name` and `description` in a way tskit and others can read\n\tupgrade the debugging output window: now with tabs for every output stream including LogFile and writeFile()\n\tfix relatedness() to handle overlapping generations, multiple parentage, etc, correctly; the version of relatedness() in SLiM 3.6 should not be used\n\tredesign the UI for the chromosome view and individuals view, to provide \"action buttons\" for more user-visible configurability\n\tadd treeSeqMetadata() function to get the metadata from a .trees file, as a Dictionary, without reading in the tree sequence\n\tupdated to tskit 0.99.15 to try out C API 1.0 prerelease stuff\n\tadd [Ns$ timeUnit=NULL] parameter to initializeTreeSeq() to set the name of the tree-sequence recording time unit\n\nversion 3.6 (build 2784; Eidos version 2.6):\n\tupdate to JSON for Modern C++ version 3.9.1\n\tadd metadata= parameter to treeSeqOutput(), to support user-generated metadata on the tree sequence\n\tmake ampersands show up in the Jump menu properly in SLiMgui\n\tfix tab stops in SLiMgui\n\tadd an F-distribution drawing function, rf(), following R, by request\n\tfix bug with source() that produced a warning about paste() semantics, and an incorrect sourced script string\n\tfix segfault-causing bug in Eidos argument processing for certain recursive calling patterns\n\tfix SLiMgui to not accept rich text pastes\n\tenable multiple selection in the Find Recipe panel\n\trevise recipes to avoid outputFull() when it takes a long time (Qt is slow processing big output dumps)\n\tadd a [permanent=T] optional flag to treeSeqRememberIndividuals() to allow for individuals to be \"retained\" rather than \"remembered\", thanks to Yan Wong\n\tadd [retainCoalescentOnly=T] flag for initializeTreeSeq() to modify simplification to keep more retained nodes than it otherwise would\n\tadd a generationStage property to SLiMSim to access the current generation cycle stage\n\timprove command-line processing – add -h/-help option, accept -- prefix\n\tadd a precision property to LogFile to govern the floating-point precision of its output (for other types of output, format() can often be used to get a specific output precision)\n\tchange SLiMgui (QtSLiM) to open .py recipes in the browser, for a better overall user experience\n\tmake SLiMgui on macOS not quit on the last window closing, following standard macOS user interface guidelines; requires Qt 5.15.2 due to Qt bugs\n\tSLiMgui: fix syntax coloring bug (keywords not colored properly)\n\tSLiMgui: fix missing color boxes in the help to show WF/nonWF/nuc properties/methods\n\tadd dark mode support for SLiMgui, for both macOS (tied to the OS setting) and Linux (with a checkbox in the prefs)\n\tupdate to tskit 0.99.10 to gain some new simplify() functionality\n\tfix a bug causing a spurious error about mismatching dominance coefficients in readFromPopulationFile() with very large dominance coefficient values\n\tmake <- an illegal token in Eidos, to guard against users who are used to R accidentally doing \"a <- b;\", which would otherwise be a comparison, \"a < -b;\", and would silently do nothing\n\tthe status bar in SLiMgui now resizes vertically to show wrapped content when necessary (long function/method signatures)\n\textend Eidos to allow all Unicode characters beyond 7-bit ASCII in identifiers, including accented characters, Chinese characters, and emoji\n\tfix argument processing bug (crash) for function/method calls with more than 256 arguments\n\tfix bugs with LogFile - writing zero-length compressed data gave an error, SLiMgui messed up the directory the log file was saved to\n\tadd \"debug points\" for runtime debugging of models in SLiMgui; new debugging output window, menu items, buttons, etc.\n\tswitch from QTextEdit to QPlainTextEdit for better performance (no user-visible change apart from SLiMgui performance on large amounts of output)\n\tadd support for an \"error stream\" in Eidos, in addition to the standard output stream; add [error=F] argument to cat(), catn(), print(), str() to support this\n\tfix a bug with the reproductive output tracking for an individual being incorrect after the individual is moved with takeMigrants()\n\tfix a serious bug with takeMigrants() that could lead to corruption/crashes, if a variable holding Individual objects was kept across the call and used again\n\tadd verbosity property to SLiMSim, to get/set the verbosity level\n\tfix memory leak of subpopulations after removeSubppulation() is called in WF models; could also cause an error, \"ERROR (Population::TallyMutationReferences): (internal error) tally != total genome count\"\n\tbump the .trees file version to reflect the change in sense for the individual flags (SLIM_TSK_INDIVIDUAL_RETAINED instead of SLIM_TSK_INDIVIDUAL_FIRST_GEN); no user-visible consequence\n\tfix bug causing output from nested events/callbacks/functions to be emitted in the wrong (non-chronological) order in some cases\n\tadd a debugIndent() function to Eidos, providing the current indentation string for use in producing error output that matches the indentation of debug points\n\tadd recipe 16.21, \"Dynamic population structure in nonWF models\"\n\textend Dictionary with getRowValues() and appendKeysAndValuesFrom() methods to enable dataframe-like usage patterns with it\n\textend Dictionary() constructor to allow it to be passed key-value pairs to set, or a Dictionary to copy\n\textend Dictionary with an identicalContents() method to test for equality of Dictionary objects (containing the identical keys and values)\n\nversion 3.5 (build 2663; Eidos version 2.5):\n\tadded build instructions for Windows WSL, thanks to Bernard Kim (no code change)\n\tfix some issues with recipes 13.5 and 14.8 (involving live plotting in R) with platform-dependent paths, lack of PDF viewing support in QtSLiM, etc.\n\tfix bug with precedence for operator ^, which needs to be higher than unary - to follow standard mathematical convention (GitHub #99)\n\tadd a tabulate() function to Eidos, more or less parallel to that in R\n\tspeed up match() for large x vectors, using unordered_map; goes from O(N*M) to O(N+M)\n\tadd a quantile() function to Eidos, parallel to R's default \"type 7\" quantile function\n\tadd new tests for the treatment of NANs, fix bugs with treatment of NANs in:\n\t\tsort(), order(), setUnion(), setIntersection(), setDifference(), setSymmetricDifference(), dbeta(), dgamma(), dmvnorm(), rmvnorm(), identical(), match(), unique(), min(), max(), range(), pmin(), pmax(), operators >=, <=, ==, !=\n\t\tthe sort() behavior now sorts NANs to the end of the vector; this is equivalent to R's with na.last=T set (which is not R's default!)\n\t\tcomparison operators now obey the IEEE rules for unorderability of NAN; if x is NAN, x<y, x>y, x<=y, x>=y, x==y are all F, x!=y is T\n\tdisallow adding mutations with addNewMutation() / addNewDrawnMutation() / addMutations() to individuals of age > 0 prevent tree sequence inconsistencies; see issue #102\n\textend codonsToAminoAcids() to be able to return integer codes for the amino acids, if passed long=0\n\tadd population and subpopulation fitness distribution plots to QtSLiM\n\trevise recipe 5.4 (Gravel model) thanks to Chase W. Nelson\n\tadd 1D and 2D SFS plots to QtSLiM, along with a 2D frequency spectrum plot\n\timprove plots in QtSLiM, particularly PDF generation\n\tadd colors() function to Eidos, providing several new color palettes including Turbo and Viridis\n\tintegrate tskit 0.3.0 into SLiM, allowing more efficient tree sequence simplification (due to faster sorting) and new metadata schema support for interoperability\n\trename SLiMgui to SLiMguiLegacy\n\trename QtSLiM to SLiMgui, including cmake and qmake build targets and flags (BUILD_SLIMGUI=ON instead of BUILD_QTSLIM=ON, SLiMgui target instead of QtSLiM)\n\trevise recipes 13.5 and 14.8 to generate PNG images, not PDF, since the new SLiMgui requires that\n\tadd Age Distribution graph to QtSLiM\n\tadd Population Size ~ Time graph to QtSLiM\n\tmake the Step button step continuously when held down, in QtSLiM\n\tmake \"generation play\" (entering a new generation in the generation counter textfield) use the Play button, and be stoppable\n\tadd tree sequence simplification to SLiMgui/QtSLiM profiles\n\tremove the first generation flag from SLiM .trees files, switch to the new simplify algorithm that preserves ancestors that are referenced\n\textend mutation() callbacks to allow returning an existing mutation\n\tpolicy change: mutation positions, when generating a gamete, are now uniqued – breaks backward reproducibility for almost all models\n\tadd subsetMutations() method on SLiMSim for fast lookup of specific mutations\n\tadd new recipe 18.14: \"modeling identity by state (IBS): uniquing new mutations down with a mutation() callback\"\n\tadd new recipe 10.6 II - Varying the dominance coefficient among mutations II\n\tpolicy change: originGeneration can no longer be used as scratch; it must be set to the current generation when a mutation is created\n\tpolicy change: pedigree tracking is now always enabled, and the keepPedigrees flag to initializeSLiMOptions() does nothing - REVERTED\n\tadd line numbers and highlighting of the current line in SLiMgui, controllable in the preferences\n\tadd \"Jump to Line...\" menu item under Edit > Find (command-L) in SLiMgui\n\tallow multiple copies of the same graph type to be opened in SLiMgui\n\tupdate tree-seq recipes for new tskit/pyslim APIs: 17.2, 17.4, 17.5, 17.7, 17.9, 18.13\n\timplement pre-processing of function/method argument lists (optimization), and extend function/method signature syntax to allow arguments following an ellipsis (the named argument syntax must be used to assign them)\n\textend paste() and paste0() to take multiple arguments, with new signatures (string$)paste(..., [string$ sep = \" \"]) and (string$)paste0(...), to encourage avoidance of the evil paste(c(...)) pattern\n\t\tnote this change is not completely backward-compatible; if you were passing in a sep= argument to paste() without the named argument syntax, you need to add sep=\n\tupdate recipes 4.2.5, 13.5, 14.8, and 16.12 (I) to use the new paste()/paste0() syntax – use \"sep=\" explicitly, avoid paste(c(...))\n\tadd individual pedigree IDs to outputFull() for both text and binary formats if pedigreeIDs=T is specified, read/use them in readFromPopulationFile()\n\tadd a \"jump to event/callback\" button to QtSLiM\n\toptimize sample() for the full shuffle case, and for better performance with large N; optimize sampleIndividuals() a bit for simple cases; may break backward compatibility for users of sample()\n\tadd support for doxygen-style /** and /// comments that get used in the \"jump to\" popup as section headers\n\tdarken the QtSLiM app icon while a model is running\n\tadd relayout option to prettyprinting in SLiMgui, with option-click/alt-click of the prettyprint button\n\tadd autosave option (off by default) to SLiMgui\n\tshow colored function/method signatures in the SLiMgui status bar\n\tshow elapsed CPU time, segregating mutations, and number of substitutions in the SLiMgui status bar\n\tmake it possible to retain a Mutation object long term with defineConstant() / setValue(), with a revamp of object memory management under the hood (putting Mutation under retain/release)\n\t\tsubtle behavior change: the reported frequency of a mutation that is removed with substitute=T used to be 0.0, now it is 1.0 (which seems more correct)\n\tadd isFixed and isSegregating properties to Mutation to help diagnose the state of a mutation that has been retained long-term\n\tadd recipe 9.9, \"Keeping a reference to a sweep mutation\"\n\tadd recipe 9.10, \"Tracking the fate of background mutations\"\n\tadd Image class to Eidos, based on lodepng\n\textend Dictionary with allKeys, addKeysAndValuesFrom(), clearKeysAndValues()\n\tmake superclass relationships explicit and documented; make Chromosome, SLiMEidosBlock, and SLiMgui inherit from EidosDictionaryUnretained\n\tmove doc for setValue()/getValue() to the Eidos manual, remove all the duplicated doc for it in SLiM\n\tshow superclasses in the doc browser, with a hyperlink\n\tchange defineSpatialMap() to require a matrix (except in the 1D case), removing the gridSize parameter (breaking backward compatibility!), and reading the matrix in the right order (so it looks the same in SLiMgui as in the console)\n\trevise recipes 15.10 and 15.11 to adjust to the changes in defineSpatialMap() (and fix a very small bug with the spatial bounds)\n\tput Chromosome under retain/release (subclassing EidosDictionaryRetained) so it can be kept long-term\n\tadd a \"showSymbolTables=F\" option for ls() that, if T, shows the whole chain of symbol tables that are defined, mostly for debugging purposes\n\tchange scoping rules so that variables in the global scope are visible inside user-defined functions and callbacks, like global constants\n\tadd a defineGlobal() function, parallel to defineConstant(), to assign a variable into the global scope\n\tadd \"Robin Hood Hashing\" to use in place of std::unordered_map in time-critical spots: match(), Dictionary, Genome bulk operations, MutationRun split/join, EidosTypeTable symbols, tree-seq simplification and individual table management, MS output\n\tadd a flushFile() function to Eidos to flush buffered content from writeFile()\n\tadd LogFile class for logging data to a CSV/TSV file, plus method createLogFile() and property logFiles on SLiMSim\n\tpolicy change: errors during writeFile() are now errors, not warnings\n\tadded files to support Bryce Carson's new Fedora package installer\n\tadd serialize() method to Dictionary, make Dictionary -allKeys be in sorted order\n\tadd mutationCountsInGenomes() and mutationFrequenciesInGenomes() methods for getting counts/frequencies within any sample of genomes\n\tadd a calcFST() function to SLiM to provide easy FST calculations; revise recipe 11.1 to use the new function\n\tadd a functionSource() function in Eidos to allow the user to see the Eidos source code for functions that are implemented in Eidos\n\tadd a calcVA() function to SLiM to calculate additive genetic variance for quantitative traints\n\tadded arm64 build for Apple Silicon\n\tadd a calcPairHeterozygosity(), calcHeterozygosity(), calcWattersonsTheta() functions to SLiM, add optional windowing to calcFST()\n\trevise recipe 14.1 to use calcHeterozygosity() instead of using custom code\n\tadd reproductiveOutput (Individual) and lifetimeReproductiveOutput (Subpopulation) properties to track individual reproductive output\n\tadd a new recipe 4.2.5, \"Automatic logging with LogFile\" (the old one became 4.2.6)\n\tadd a new recipe 16.19, \"Range expansion in a stepping-stone model\"\n\tadd a new recipe 16.20, \"Logistic population growth with the Beverton–Holt model\"\n\tadd lifetime reproductive output plot to QtSLiM; change the reproductive output logging to separate by sex, add lifetimeReproductiveOutputM and lifetimeReproductiveOutputF properties to cover that\n\tminor bugfix for recipe 14.7; use L instead of L-1 for chromosome length\n\tback out the earlier (9/4/2020) change making pedigree tracking always on, because the performance hit was too large; so the keepPedigrees flag to initializeSLiMOptions() now does something again\n\tput the reproductiveOutput/lifetimeReproductiveOutput properties under keepPedigrees=T, be more strict about requiring keepPedigrees=T to see/access any pedigree information at the user level\n\nversion 3.4 (build 2438; Eidos version 2.4):\n\tfix a subtle bug in which mutation IDs used by mutations read in from a .trees file could be re-used, producing a conflict, if the mutations were not ancestral to any extant genome -- biting you if you wrote a .trees file out again at the end\n\tadd qnorm() function in Eidos; thanks to Vince Buffalo for the PR\n\tadd SHA-256 code, output of a script hash to .trees files with the parameters/model_hash subkey, and an option to omit provenance output of the full script in outputTreeSeq() with includeModel=F; increment .trees file_version to \"0.4\"\n\tfix a crash in haplotype plotting when the number of genomes is large\n\tfix display bug with haplotype display on retina displays\n\tadd recipe 16.18: a spatial epidemiological S-I-R model\n\tnew versions of recipes 9.5.2 and 9.5.3 to fix a bug involving fitness calculations with multiple mutational lineages for a single sweep; see https://groups.google.com/d/msg/slim-discuss/DW-QqzoZLgg/NCusXvBqBAAJ\n\textended writeFile() and writeTempFile() to support writing .gz compressed files with compress=T, added zlib 1.2.11 to the project\n\tadd dbeta(), dexp(), and dgamma() functions to Eidos to provide probability density functions for those distributions\n\textended the compress=T option for writeFile() to support append=T as well, with internal buffering for performance\n\tadd QtSLiM to project!\n\tfix a bug that failed to catch an overflow in the tree-sequence tables for a large model\n\nversion 3.3.2 (build 2158; Eidos version 2.3.2):\n\tadd recipe 5.2.4 (joining subpopulations)\n\textend recipe 5.4 (the Gravel model) to show output from a vector of genomes sampled from multiple subpops\n\tfix a bug in recipe 13.4 (introduced in SLiM 3.3) that caused the environmental noise not to be included in the phenotypic values used for fitness calculations\n\tadd an optional <level> argument for the command-line option -l/-long, to provide the level of verbosity desired (default level is 2; defaults to 1 if -l/-long is not used)\n\tadd recipe 16.17 (meiotic drive)\n\tadd recipes for section 13.6 (a variety of fitness functions)\n\tspeed up AddIndividualsToTable(), eliminating a bottleneck for large models with multiple subpopulations\n\tspeed up outputMutations(), which was very slow if a large number of mutations were requested for output\n\tprotect methods in InteractionType against being passed new juveniles that have not yet been added to the subpopulation\n\toptimize the sample size 1 case in sampleIndividuals() when criteria are specified (min/max age, etc.)\n\tadd SLiMgui launch check for needed fonts\n\tfix a bug in AddNewDrawnMutation()/AddNewMutation() if a non-singleton vector of positions is given in unsorted order: the genome order is incorrect!\n\ttweak the default nonWF model to find a mate with \"subpop.sampleIndividuals(1)\" not \"p1.sampleIndividuals(1)\", for generality\n\ttweaks to allow distribution under conda-forge\n\tincrease the precision of MS output from 7 decimal places to 10, to accommodate larger chromosomes with precise positions\n\nversion 3.3.1 (build 2116; Eidos version 2.3.1):\n\tfix SLiMgui crashing bug involving (a) a type \"s\" mutation type with (b) a fixed color set for it\n\tprotect against a non-existent or non-writeable /tmp directory, which apparently some systems have\n\tfix crash in SLiMgui due to inaccessible properties\n\tfix bug involving (a) genomic elements specified out of sorted order, AND (b) a non-uniform mutation rate map; some genomic elements can end up not generating any mutations at all (present since SLiM 2.5)\n\tadd an option to clock() to select the clock type (\"cpu\" or \"monotonic\", for now); add the same option to executeLambda()\n\tfix a VCF output bug: blank lines in nucleotide-based output when a back-mutation is suppressed by simplifyNucleotides=T\n\tadd a wait=T optional parameter to system(), allowing wait=F (or a & at the end of the command line) to execute a system command in the background\n\tenable access to pedigree IDs whenever they are valid (i.e., when tree-sequence recording is enabled, as well as when pedigree tracking is enabled), and add them to VCF output when available\n\tadd an \"individual\" property to Genome that provides the individual to which a given genome belongs\n\tfix a crash with clonal nucleotide-based models using a custom mutation matrix\n\tshift temporary files used by -eidosTest and -slimTest into a randomly named subfolder, where necessary to prevent conflicts with other users\n\tchange recipes that set a new seed to use 2^62 rather than 2^32, to avoid repeated sequences\n\tfix memory allocation issue with more than 2^26 individuals\n\tfix crash when trying to use an InteractionType after takeMigrants() has made its cached data invalid\n\tfix crash when a call to takeMigrants() tries to migrate the same individual twice (i.e., the migrants vector is not uniqued)\n\tfix signatures shown in SLiMgui for callbacks that have return values\n\tfix problems with the variable browser caused by inaccessible properties\n\nversion 3.3 (build 2062; Eidos version 2.3):\n\tfix bug resulting in incorrect sex ratio (all males!) in sexual nonWF models when saved to a population file (either binary or text)\n\tadd nucleotideBased flag to initializeSLiMOptions()\n\tadd a NucleotideArray class to keep compact nucleotide sequences (2 bits per nucleotide)\n\tadd initializeAncestralSequence() function\n\tadd Chromosome.ancestralNucleotides() method\n\tadd randomSequence() function\n\tadd nucleotideBased property\n\tadd nucleotideCount(), nucleotideFrequency() functions\n\tadd codonsToAminoAcids(), nucleotidesToCodons() functions\n\tadd initializeMutationTypeNuc() and nucleotideBased property on MutationType\n\tadd mutationMatrix to initializeGenomicElementType()\n\tadd mutationMatrix property and setMutationMatrix() method to GenomicElementType\n\tadd Mutation support for nucleotides: nucleotide, nucleotideValue, ditto for Substitution\n\tadd nucleotide argument to addNewMutation() and addNewDrawnMutation()\n\tadd nucleotides() method to Genome\n\tadd mmJukesCantor() and mmKimura() mutational models\n\timplement sequence-based mutation\n\tadd mm16To256() function to expand a single-nucleotide mutation matrix into a trinucleotide mutation matrix\n\tdisable initializeMutationRate() and related API in nucleotide-based models\n\tupdate the ancestral nucleotide sequence upon fixation\n\tadd hotspot map support: initializeHotspotMap(), setHotspotMap(), and associated properties\n\tadd output of nucleotides to outputMutations(), outputFixedMutations(), and other output methods\n\tadd nucleotidesToCodons() function\n\trevamp the recombination model for the new gene conversion design\n\tgeneConversionFraction property removed, geneConversionEnabled / geneConversionNonCrossoverFraction / geneConversionSimpleConversionFraction / geneConversionGCBias added\n\tremove gcStarts / gcEnds from the recombination() callback specification\n\tremove old nucleotide and biased gene conversion recipes\n\tfix recipe 6.1.3 (gene conversion)\n\tadd setGeneConversion() method on Chromosome to change the gene conversion parameters dynamically\n\tadd recipes for chapter 17 (17.1 - 17.10)\n\tadd recording of nucleotides and ancestral sequence in tree-sequence recording\n\tincrementing .trees file version to 0.3\n\tfix input/output of ASCII trees files\n\tfix a bug with ASCII output of non-nuc models with outputFull() that prevented completely verbatim reloading (float precision issue)\n\tadd nucleotide support for readFromPopulationFile() with a text SLiM output file from outputFull() in a nucleotide-based model; nucleotides and ancestral seq restored correctly\n\tadd writing and reading of binary files with outputFull() and readFromPopulationFile() in nucleotide-based models\n\tadd heteroduplex mismatch repair, biased gene conversion, and add recipe 17.11\n\tadd readFromVCF() for reading from VCF files, readFromMS() for reading from MS files\n\tspeed up output of MS format for large models\n\tadd setAncestralNucleotides() method to Chromosome\n\tadd recipe 17.12, demonstrating loading from an empirical VCF file\n\tdisable link-time optimization (LTO) since it is causing build issues for some people\n\tfix a bug with the time base of WF models when a .trees is loaded in an early() event; a parent/child timestamp conflict could result\n\tadd simplificationInterval parameter to initializeTreeSeq() (breaking backward compatibility, for those not using named arguments for checkCoalescence / runCrosschecks)\n\tvectorize initializeGenomicElement(), fix recipe 17.7 to use it\n\tmake pedigree ID properties inaccessible when pedigree recording has not been enabled, to prevent confusion\n\tmake tag/tagF properties inaccessible when they have not been previously set, eliminating this class of bugs\n\tin WF models, enforce that subpopulation total fitness must be finite, to catch overflows\n\tfix minor code completion bug involving completing off of language keywords, like trying to complete \"for\" to \"format=\" in ancestralNucleotides()\n\trevise recipe 9.3.2, remove recipe 9.4.2, revise recipe 9.4.4, revise recipes 11.1, 11.2\n\trenumber recipes to make room for new chapter 13, move existing QTL recipes into chapter 13, add new recipe 13.2 to better introduce QTL model concepts\n\trevise recipes 13.3, 13.4, 13.5, 14.4, 14.5; add recipe 6.1.4 (multiple chromosomes), add recipe 12.5 (tracking separate sexes in script)\n\tremove recipe 14.6 (forcing a pedigree in a WF model)\n\trevise recipes 14.7, 15.3, 15.4, 15.5, 15.6, 15.7, 15.8, 15.9, 15.10, 15.11, 15.12\n\tadd recipe 9.6 (varying dominance coefficients)\n\tfix a bug that would produce incorrect results from mutationCounts() / mutationFrequencies() in early() events in nonWF models (not including the newly generated offspring)\n\tfix compile issues on Xcode 10.2, upgrade to JSON for Modern C++ version 3.6.1 (from 3.1.2)\n\tupdate GSL code to version 2.5  (no user-visible impact)\n\tchange mmJukesCantor() to take alpha, not mu, for consistency; revise recipes and doc\n\trevise recipe 14.9, 16.2, 16.9, 16.10, 16.11, 16.12, 16.13\n\tfix bug in mmKimura() mutation matrix (never released publicly)\n\tfix bug in outputMS() and outputMSSample() with filterMonomorphic=T (not the default) that could result in incorrect output, or in a crash\n\tfix uninitialized value bug with InteractionsData (never seen in the wild, probably inconsequential)\n\tfix symbol table double-dealloc bug (never seen in the wild, probably inconsequential)\n\tfix a possible misaligned pointer access when loading .trees files (never seen in the wild, only a problem on non-Intel architectures like ARM, might not even be a bug)\n\tfix an edge-case crasher in tree-seq models (never seen in the wild, perhaps only occurs when crosschecks are enabled)\n\tadd ancestral sequence to memory usage stats\n\tadd drawSelectionCoefficient() method to MutationType\n\trevise recipes 7.3, 7.4, 10.5.1 to eliminate unnecessary asInteger() calls\n\tconvert some float-type parameters to numeric-type: initializeTreeSeq(simplificationRatio), randomNucleotides(basis), spatialMapColor(value), defineSpatialMap(values, valueRange), setSpatialBounds()\n\thighlight matches in the Find Recipe panel\n\tthe selected display mutation types now apply to substitutions as well as mutations\n\tvectorize spatialMapValue() and revise recipe 15.11 to use it\n\toptimize sample() with weights, revise recipe 11.2 (splitting it into version I and II)\n\tcorrect recipe 16.15, which did not match the manual\n\toptimize operator subset [] with a singleton integer argument, since that is the common case\n\tfix an ordering problem with the remembered genomes after loading a .trees file (didn't match the order in the individuals table)\n\tmerge in kastore C_1.1.0 (67c5a6af4b85ea263e5cab854d94b691949e88ae) and tskit post-0.1.5 (3d16a36f8e54ac01a86f182dc73103bd07badf3e)\n\tadd mutation() callbacks and registerMutationCallback()\n\tmake nucleotide/nucleotideValue properties on Mutation writeable\n\tfix some leaks\n\trevise recipes 9.6 and 13.5 to use mutation() callbacks\n\tswitch Chromosome to keeping pointers to GenomicElement, fixing a potential crash (which I don't think anyone ever hit)\n\tmake initializeGenomicElement() return the new element, following the pattern of the other initialize...() functions\n\tadd GenomicElement pseudo-parameter element to mutation() callback API\n\tswitch Population from a subclass of std::map to containing a std::map of subpopulations (no user-visible effect)\n\tadd recipe 14.14 (Visualizing ancestry and admixture with mutation() callbacks)\n\tadd fileExists() function to Eidos\n\tfix bug resulting in incorrect results from max() with (1) integer type, and (2) at least one singleton argument that is neither 0 nor 1\n\tswitch to \"hardened runtime\" in preparation for Apple's notarization procedure\n\timprove self-tests\n\tfix bug in matrix multiplication with type float\n\tadd recipe 18.13 (Tree-sequence recording and nucleotide-based models)\n\n3.2.1 (build 1897; Eidos version 2.2.1):\n\tadd support for the slim command-line tool to read its script from stdin instead of from a supplied input script file\n\tfix bug that would bite models calling deregisterScriptBlock() more than once, leading to an incorrect event list in some cases\n\tadd recipe 15.15 (Implementing a Wright–Fisher model with a nonWF model)\n\tfix a bug resulting in incorrect values for the pedigreeGrandparentIDs property of Individual; they were correct internally, but returned incorrectly\n\tadd a drawBreakpoints() method on Chromosome to allow models to draw breakpoints using SLiM's logic\n\tadd recipe 15.16 (Alternation of generations)\n\tadd support for \"make install\" with cmake (see the README.md / README.html for instructions), thanks to Peter Ralph\n\tadd support for link-time optimization (LTO) on platforms that support it, thanks to Kevin Thornton\n\tadd an rbeta() function to Eidos for draws from the beta distribution\n\tadd a pnorm() function to Eidos for a cumulative distribution function for the normal distribution\n\tfix .trees file loading to check that the chromosome length matches, avoiding weird problems downstream\n\tfix a SLiMgui crash when displaying a large number of genomic element types\n\tadd a SLiMgui class and slimgui global instance, available only when running under SLiMgui, that provides some useful control options\n\tdeprecate the inSLiMgui property of SLiMSim; use 'if (exists(\"slimgui\")) ...' instead; revised recipes 13.11 and 13.17 for this change\n\tadd SLiMgui.openDocument() and SLiMgui.pauseExecution() methods, and SLiMgui.pid property, to SLiMgui class; revised recipes 13.11 and 13.17 to use openDocument()\n\tadd Subpopulation.configureDisplay() method, inserted a new recipe 5.3.4 to provide an example of using it\n\tfix a code completion hiccup with return/else/do/in\n\timprove error-reporting for command-line defines\n\tfix an uncaught raise optimizing illegal numeric constants\n\tupdate citations listed by citation()\n\timprove recipes (10.2, 10.3, 10.6.2, 16.3) that call setSeed(getSeed() + 1) to do setSeed(rdunif(1, 0, asInteger(2^32) - 1)); Matthew Hartfield pointed out the potential replicate correlation issue\n\tmove back deployment target from OS X 10.11 to OS X 10.10 thanks to Deploymate\n\tfix a bug involving calling setValue() inside a for loop, and similar setValue() scenarios involving a changing value\n\n3.2 (build 1859; Eidos version 2.2):\n\tfix a bug that could result in incorrect parent2, parent2Genome1, and parent2Genome2 values in modifyChild() callbacks in clonal models; should not impact correct model code\n\tfix incorrect values for isCloning / isSelfing in modifyChild() callbacks in nonWF models using addCloned() / addSelfed()\n\tfix incorrect modifyChild() callback source in nonWF models using addCloned(), addCrossed(), and addSelfed(); they were getting the list of callbacks from the target subpopulation\n\tfix crash in addEmpty() that nobody noticed because nobody uses it\n\tadd a new addRecombinant() method that allows easier modeling of haploids, horizontal gene transfer, and pre-planned recombination breakpoints\n\tadd recipe 15.13 (modeling clonal haploids in nonWF models with addRecombinant())\n\tadd recipe 15.14 (modeling clonal haploid bacteria with horizontal gene transfer)\n\tadd rgeom() function to Eidos for draws from a geometric distribution\n\toptimization of property & method dispatch (signature lookup, specifically), using lookup tables instead of hash tables\n\tadd outputUsage() method to dump memory usage of a simulation, incorporate this information into SLiMgui profile reports\n\tadd a button in SLiMgui to change the current working directory, correctly track the cwd when multiple SLiMgui windows are open, across recycles, etc.\n\tadd Find Recipe... panel in SLiMgui\n\tmodify asString(NULL) to return \"NULL\", and the string-concatenation operator + to use \"NULL\" when NULL is concatenated; cat() and catn() still produce no output for NULL\n\tscheduling a callback/event into the past now results in an error\n\tadd a parameter to outputMS() and outputMSSample() to allow only sites that are polymorphic within the sample to be output: filterMonomorphic=T\n\tfix code completion in SLiMgui after return, in, else, and do\n\tmake code completion much smarter; iTr now completes to initializeTreeSeq(), wf to writeFile(), etc.\n\tfix recipe 11.1 issue with calcFST() function returning NAN if any mutations are either (a) missing from both subpops, or (b) fixed in both subpops\n\tfix issues with passing NAN as a color component to the Eidos color-translation functions\n\tmake SLiMgui's \"graph population visualization\" migration rates in nonWF models reflect juvenile migration due to a non-parental destination subpop for addX()\n\tadd a print=T flag to version() so scripts can switch on the Eidos or SLiM version number without generating unwanted output\n\tvectorized the exists() function so a vector of symbol names can be check for existence\n\tvectorize the Eidos color-manipulation functions, using matrix arguments/returns: color2rgb(), hsv2rgb(), rgb2hsv(), rgb2color()\n\tadd new color palette functions: heatColors(), rainbow(), terrainColors(), and cmColors()\n\tfix big performance issue for nonWF models as they build up genetic diversity, due to the wrong mutation frequency tallying code path being used\n\tfix bug EidosSymbolTable buffer overrun in ContainsSymbol() and related methods; this will bite models that define a very large number of symbols (e.g., some nucleotide models)\n\tmake Eidos and SLiM more robust to NAN being passed in to various functions (rpois() hang, in particular)\n\tfix corrupted spatial location data for some individuals (mostly, maybe only?, first-gen individuals) in .trees files\n\tadd a usage() function to get the current or peak memory usage of the process\n\n3.1 (build 1817; Eidos version 2.1):\n\tdmvnorm() function added to Eidos, parallel to dnorm() but for multivariate Gaussian distributions\n\tadd JSON for Modern C++ (https://github.com/nlohmann/json) version 3.1.2 to SLiM for .trees provenance generation/parsing\n\textend SLiM's .trees file provenance info (tskit schema stuff, script text, seed, parameters, os environment, file_version==0.2)\n\tfixed a inefficient bottleneck in recipe 13.4 (reading MS format files)\n\tgreatly increase the performance and memory usage of the InteractionType spatial engine for big models (add sparse array for caching pairwise interactions)\n\t\tthis breaks backward reproducibility in some models, because distances/strengths are now internally rounded to float instead of double\n\tadd interactionDistance() method to InteractionType, returning INF as the distance for non-interacting pairs (including self-self distance)\n\tadd nearestInteractingNeighbors() method to InteractionType, excluding non-interacting pairs from the returned set of neighbors\n\tadd interactingNeighborCount() method to InteractionType, to get a count without getting identities\n\tchanged the semantics of strength(); the first argument must now be a singleton individual, and it returns strengths exerted upon that individual (old semantics were ill-defined and broken for non-reciprocal interactions)\n\trememberIndividuals() now actually remembers individuals in the tree sequence, as well as (what it did before) their associated nodes\n\tfix issues with genome recycling and subpop initialization, which could result in nodes in .trees files being marked as null genomes incorrectly and could cause memory usage to increase without bound\n\tbug fix: incorrect neutral dynamics for WF models with no non-neutral muttypes, no fitness() callbacks, but using fitnessScaling to modify fitness\n\tadded remembering of the initial generation, to enable recapitation\n\tchange .trees files to have rebased times on write, to simplify pyslim and reduce user error\n\tadd a warning for spatial interaction types with no max distance\n\tadd recipe 13.19, biased gene conversion\n\tadd recipe 16.10, recapitation\n\tfix coalescence checking to work even when individuals are remembered\n\n3.0 (build 1750; Eidos version 2.0):\n\tadd initializeSLiMModelType() function to choose SLiM's model type (WF or nonWF, at present), and modelType property on SLiMSim to access it\n\tdisable setSubpopulationSize(), setCloningRate(), setSelfingRate(), setSexRatio(), .cloningRate, .selfingRate, .sexRatio in nonWF models\n\tdisable addSubpopSplit(), setMigrationRates(), .immigrantSubpopFractions, .immigrantSubpopIDs in nonWF models\n\tmake definition of mateChoice() callbacks illegal in nonWF mode, including by registerMateChoiceCallback()\n\tadd age property to Individual, for nonWF models\n\tadd removeSubpopulation(), takeMigrants(), addCloned(), addSelfed(), addCrossed(), addEmpty() methods for use in nonWF models\n\tadd support for reproduction() callbacks, including adding registerReproductionCallback()\n\tmake convertToSubstitution default to F in nonWF models, since all non-neutral mutation types influence fitness and thus survival\n\tadd outputFull() ages=T parameter to control output of age information in nonWF models; does nothing in WF models; also modify readFromPopulationFile()\n\tswitch to using pointers for genomes and individuals\n\timplement the nonWF generation cycle\n\tadd sampleIndividuals() and subsetIndividuals() methods on Subpopulation for faster fetching of mates, etc.\n\tadd fitnessScaling property to Subpopulation and Individual, to alter fitness values per individual or per-subpop without fitness(NULL) callbacks\n\toptimizations: EidosSymbolTable improvements, constant caching, callback processing, argument processing, RNG optimizations, inlining, WF parent/child swap efficiency, fitnessScaling work\n\tadd hooks for tree sequence recording\n\timprove accelerated property get/set to be more vectorized\n\tadd support for accelerated method implementations, accelerate a few core methods\n\tspeed up SLiMSim::mutationsOfType(), SLiMSim::countOfMutationsOfType(), Genome::containsMutations(), SLiMSim::mutationCounts(), SLiMSim::mutationFrequencies(), Genome::mutationsOfType()\n\tswitch to dispatch of properties and methods using std::unordered_map to look up the signature\n\tmiscellaneous other optimizations: \"1/relFitness\" fitness() callbacks, property return checks, symbol table crossover, std::unordered_map vs. std::map, dynamic_cast<> usage, unnecessary IsNull() calls\n\tadd a \"New (nonWF)\" menu item to SLiMgui for quick creation of new nonWF models\n\tmake WF-only and nonWF-only API visibly tagged (with colored boxes) in the SLiMgui help window\n\tadd seqLen() function to Eidos, like seq_len() in R\n\tadd nonWF recipes\n\tfix InteractionType bug with periodic boundaries and totalOfNeighborStrengths() / strength()\n\tfix bug where a gene conversion rate of exactly 1.0 would be treated as 0.0\n\tfix bug with paste of code from a source with unconventional line endings\n\tadd support for a logical argument to mean(), and increase the accuracy of mean() for very large integer vectors by trying to avoid floating-point overflow issues\n\tfix bug that allowed cachedFitness() to be called from a late() event, returning garbage values\n\tfix recipe 13.1, which called cachedFitness() during a late() event, which should have been illegal (and now is illegal)\n\tadd recipe 13.3 III, mortality-based fitness using fitnessScaling\n\tfix a crash when calling setSubpopulationSize(0) (or removeSubpopulation()) twice on the same subpop\n\tfix searches in the help for strings that return more than one identical hit, such as \"tag\"; such searches were only displaying one of the multiple hits\n\tdisplay the emergent selfing rate, cloning rate, and sex ratio in SLiMgui for nonWF models\n\tmake the population visualization graph work better with nonWF models (using fitness values without density scaling, display emergent migration rates)\n\tmake the fitness over time graph display fitness without density scaling, as in other aspects of SLiMgui's presentation of fitness\n\tfix a crash with the fitness over time graph when the simulation became invalid (due to a stop() call or other error)\n\tfix a rare crash on quit from SLiMgui\n\tfix a crash due to stack overflow with large population sizes (only when callbacks are involved in offspring generation)\n\tadd new tree seq stuff: initializeTreeSeq(), treeSeqSimplify(), treeSeqRememberIndividuals(), treeSeqOutput()\n\tadd getwd() / setwd() functions to Eidos\n\tadd var(), cov(), cor() statistics functions to Eidos for variance, covariance, and (Pearson) correlation\n\tchange Eidos to not automatically assume return values based upon the value of the last statement; that makes it confusing/hard to define a function that returns void\n\tpolicy change: property/method accesses on zero-length vectors now raise unless the return type of the property/method is unambiguous\n\t\"void\" is now an actual value type in Eidos, although it can only be used as a return type for functions/methods; this improves type-safety\n\tfix recipes: 13.2 (mateChoice() callback with no explicit return), 13.9 (sapply() with no value), 11.2 (cachedFitness() from a late() event)\n\tadd rcauchy() for Cauchy distribution draws, and a \"c\" Cauchy interaction function option for InteractionType\n\tfix a display bug in SLiMgui on Retina displays\n\textend spatial point-processing methods (pointInBounds(), point[Periodic/Reflected/Stopped/Uniform], setSpatialPosition()) to be vectorized\n\tadd bounds-checking for MutationType DFE parameters and InteractionType IF parameters\n\tdisplay interaction types in the tableview drawer in SLiMgui, with a hover preview of the interaction function, as with mutation types\n\tfix the incorrect actual recombination rate for requested recombination rates close to 0.5, impose a <= 0.5 requirement on recombination rates, add related recipe 13.18\n\timprove options for display of subpopulations in the population view (control-click or right-click for menu)\n\tadd genome1 and genome2 properties on Individual to make getting just the first or second genomes of a vector of individuals simpler, in e.g. haploid models\n\tadd removeMutations(NULL) option that removes all of the mutations from the target genome, for e.g. haploid models; not allowed to be used with substitute=T\n\trevise recipe 13.13 (modeling haploids) to use genome2 and removeMutations(NULL), making is much faster and simpler\n\tmake the default working directory be ~/Desktop when running in SLiMgui; makes no sense for it to be the folder the app is in\n\tincrease maximum chromosome length from 1e9 to 1e15 (breaks reproducibility from a given seed, due to new MT64 RNG)\n\tfix rdunif() to be able to generate uniform draws in the full 64-bit range, using the new MT64 RNG; optimize rdunif() and rbinom() for the simple coin-flip case (breaks backward output compatibility)\n\tfix a crash in SLiMgui when displaying a haplotype plot (including in the chromosome view) in a model with null genomes, such as an X or Y model\n\textend containsMarkerMutation() with a [returnMutation=F] argument so the found mutation can be obtained\n\tcode completion can now supply argument names when in a function/method call\n\tadd suppressWarnings() function in Eidos\n\tfix issue with dropped model output just before a simulation terminated due to an error\n\tadd treeSeqCoalesced() and a checkCoalescence parameter for initializeTreeSeq(), to perform runtime checking for coalescence\n\tadd getValue() / setValue() functionality to Substitution, make values carry over from Mutation objects when they fix\n\tadd tree-seq recipes to SLiMgui\n\tadd a \"migrant\" property to Individual that is true if the individual has migrated in this generation, add \"migrant\" argument to sampleIndividuals() & subsetIndividuals()\n\tadd a timeUnit parameter to initializeTreeSeq() to allow the time unit to be set by the user; make it \"generations\" for WF and \"ticks\" for nonWF, by default\n\tadd recipe 9.11, effective population size versus census population size\n\n2.6 (build 1292; Eidos version 1.6):\n\tmake addNewMutation() and addNewDrawnMutation() vectorized, for much higher performance when adding many mutations in bulk; note policy change that requested mutations are returned whether added or not\n\tadd positionsOfMutationsOfType() method to Genome for speed of models that need that\n\textend the integer() function to be able to construct vectors of 0 and 1 at specified positions (sort of the opposite of which())\n\trevise recipe 13.9 to use new vectorized addNewMutation(), as well as the new positionsOfMutationsOfType() and integer()\n\tfix possible incorrect frequency/count info immediately after using addMutations() or removeMutations() (but not addNewMutation()/addNewDrawnMutation()) – the changes would not be reflected in freqs/counts immediately\n\tfix a display bug with added (or removed) mutations in SLiMgui\n\tadd \"Copy as Paragraph\", remove \"Paste and Match Style\", in SLiMgui and EidosScribe\n\tfix to only highlight errors in SLiMgui if the script has not changed since the last recycle (otherwise character positions are unreliable)\n\tfix a bug causing the wrong help text to appear for \"id\" properties on some classes in the help panel in SLiMgui\n\tadd haplotype snapshot plot (create from the Graph pop-up menu or the Simulation menu)\n\tadd haplotype display option for the chromosome view (control-click and select from context menu)\n\textended recipe 13.5 to show the new haplotype display options\n\tmake so the chromosome view can display a subset (but more than one) of the mutation types defined\n\tmake so displaying a subset of mutation types works when in haplotype display mode too\n\tperiodic boundary conditions: added periodicity parameter for initializeSLiMOptions(), periodicity property on SLiMSim, pointPeriodic() method on Subpopulation\n\t\tnote policy change: new parameter inserted in initializeSLiMOptions()\n\tadd recipe 14.12, demonstrating periodic spatial boundaries\n\tadd display of mutation type DFEs as tooltips in the info drawer\n\tadd rdunif(), a function for generating draws from a discrete uniform distribution\n\tadd tips in SLiMgui for the chromosome haplotype display mode, script prettyprinting, and DFE visualization in the mutation type table\n\tadd recipe 13.15 showing how to implement microsatellites\n\tadd recipe 13.16 showing how to implement transposable elements\n\tfix static analyzer issues, including minor bug fixes for _InitializePopulationFromBinaryFile() and a leak in haplotype plotting\n\tfix a bug in doCall() that would fail to get the return value from user-defined functions\n\tfix type-interpreter crashes with malformed function declarations\n\tfix a refcounting bug that would bite users running more than one simulations at the same time in SLiMgui\n\tswitch to shared_ptr for call signatures, to fix a leak with user-defined functions\n\timprove recipe 13.12 (modeling nucleotides) and optimize SLiM to make it run faster\n\tadd the ability to automatically select only non-neutral mutation types for display in the chromosome view\n\tfix a bug (never released) in pure neutral tracking with addNewMutation(), and optimize pure neutral tracking some more\n\tadd ability to change the number of bins in the frequency spectrum plot\n\toptimize EidosValue internals by using malloced buffers instead of std::vector, avoiding zero-initialization and capacity-checking\n\tfix a bug (never released) in ConcatenateEidosValues() with logical vectors that would cause incorrect results in some post-2.5 GitHub versions\n\tfix a bug (never released) in the new integer() two-value filling code added post-2.5\n\toptimize method dispatch in Eidos to gather results more efficiently, with benefits for script-intensive models\n\tadd support for matrices and arrays in Eidos; new functions matrix(), array(), nrow(), ncol(), dim(), t(), cbind(), rbind(), matrixMult(), drop()\n\tchanged the output format from str() and x.str() to be more R-like\n\tchanged apply() to return a matrix or array in some cases; could break backward compatibility in rare cases\n\tpolicy change: assignment into a subset of a property is no longer legal in Eidos (e.g. x.foo[1:3] = rvalue), because it is conceptually flawed (not an lvalue)\n\tupdate the GSL code in Eidos to GSL version 2.4 and pulled in gsl_ran_multivariate_gaussian(), gsl_linalg_cholesky_decomp1(), and dependencies (no user-visible impact)\n\tadd rmvnorm() for drawing from a multivariate distribution\n\tmake version() return version numbers to the caller\n\textend defineSpatialMap() to allow the map values to be specified as a matrix/array\n\tinternal policy change: properties are no longer allowed to return NULL or be set to NULL, and must raise instead if they cannot provide a value\n\tpolicy change: Chromosome properties that used to return NULL when inapplicable now raise (mutation rate map and recombination rate map properties)\n\tchange property semantics: singleton properties accessed on a matrix/array now mirror the dimensional structure of the target, like a unary operator\n\trename apply() to sapply() to match R, add a simplify= parameter to govern the result's dimensionality\n\tadd new apply() function to apply a lambda to margins of a matrix or array, as in R\n\tfix recipes to use sapply() instead of apply(), following the new function names, and to run in more reasonable time (for testing of them)\n\trescale the color scheme for recombination and mutation rate maps in SLiMgui to handle a wider range(1e-6 to 1e-9), and make the mutation rate display with a more purple hue (compared to blue for recombination rate)\n\tadd recipe 13.17 showing a two-trait QTL-based phenotypic model with pleiotropy and nutational correlation, plus live R-based plotting\n\n2.5 (build 1204; Eidos version 1.5):\n\tadd a check for completeness of the help information compared to class definitions, and add doc for a few missing items\n\tchange the getValue()/setValue() implementation to be more memory-efficient when not used (but a little slower and less memory-efficient when used)\n\tMutation now supports getValue()/setValue() for greater extensibility\n\tadd script prettyprinting facility to SLiMgui\n\tenhance pmax() and pmin() to allow a singleton vector to be paired with a longer vector\n\tenhance max(), min(), and range() to allow any number of arguments of any length\n\tenhance seq() to support an optional length parameter\n\tenhance any() and all() to allow any number of arguments of any length\n\tadd a ternary conditional operator, ? else, to the Eidos language\n\tadd a sumExact() function for exact summation of floating point numbers\n\timproved numerical accuracy for complex recombination maps\n\tadd ability to supply a mutation rate map instead of just an overall rate; removed the mutationRate property of Chromosome\n\tadd display of the mutation rate map in SLiMgui with the R button\n\tadd support for /* */ block comments to Eidos\n\tfix Context-defined functions so SLiMgui works with them better (showing the function prototype even after an error)\n\tfix a bug in InteractionType that would produce incorrect results for interactions if individuals had exactly identical coordinates\n\tspeed up mateChoice() callbacks that select just a subset of all possible mates\n\tadd a preserveOrder flag to the unique() function in Eidos to allow O(n log n) performance to be requested when order does not matter\n\trename function(), method(), and property() to functionSignature(), methodSignature(), and propertySignature() respectively\n\trename argument \"function\" for doCall() to \"functionName\"\n\tadd support for user-defined functions in Eidos and SLiM\n\tadd a source() function to read in and execute a source file\n\trevise recipe 11.1 to fix the FST calculation code and encapsulate it into a reusable function\n\tadd menu item in SLiMgui to open the SLiM-Extras repository on GitHub\n\tfix a major bug preventing new mutations from being introduced during clonal reproduction (existing in 2.4, 2.4.1, and 2.4.2)\n\tadd recipe 13.13, illustrating how to make a simple haploid model\n\tadd recipe 13.14, showing how to use variation in the mutation rate along the chromosome to model varying functional density\n\tfix recipe 5.3.3, which had recipe 5.3.2's code in its file\n\n2.4.2 (build 1167 on branch mutid_bug_242; Eidos version 1.4.2):\n\tfix for incorrect output due to non-unique mutation IDs\n\n2.4.1 (build 1166; Eidos version 1.4.1):\n\tfix a crash (or possible bad simulation data) involving stale subpopulation pointers in genomes in multi-subpop models\n\n2.4 (build 1163; Eidos version 1.4):\n\tadd a system() function to call out to Unix to run commands\n\tadd a tooltip showing the frames per second for the play speed slider, and tweak the play speed metrics\n\tadd PDF viewing capability to SLiMgui for R plotting integration\n\tadd a writeTempFile() Eidos function for creating randomly named unique temporary files\n\tadding inSLiMgui property to SLiMSim\n\tadd recipe 13.11, live plotting with R using system()\n\taddition of catn() function, identical to cat() but with a newline appended to the output\n\taddition of paste0() function, identical to paste() but with no separator\n\tadd -rescheduleScriptBlock() method to SLiMSim\n\tadd ability to display only one mutation type in the chromosome view, through a context menu (added a tip on this)\n\tadd a top/bottom splitter in the SLiMgui main window\n\timplement mutation runs inside Genome for better performance\n\tadd a new option in initializeSLiMOptions() to control the number of mutation runs, if desired (usually unnecessary)\n\toptimize crossover mutation code with improved code flow and expanded case treatments\n\toptimize fitness calculations by caching fitness effects of mutations\n\toptimization: switch to MutationIndex instead of Mutation *\n\toptimization: keep mutation refcounts in a separate buffer\n\tadded -l / -long command line option for long (i.e. verbose) output\n\tadd font size preference to SLiMgui, for presentations etc.\n\toptimization of simulations in which all mutations have no direct fitness effects, particularly QTL-based models\n\tadd sumOfMutationsOfType() method to Individual and Genome for fast totalling of additive QTLs in QTL-based models\n\toptimize script block handling for sims with many script blocks, to decrease callback overhead\n\trewrite QTL-based recipes to use sumOfMutationsOfType()\n\tadded a preventIncidentalSelfing option to initializeSLiMOptions(), to prevent incidental selfing in hermaphroditic models\n\tadd profiling (performance monitoring) in SLiMgui\n\tadd alternative displays for the population view, selectable with right-click / control-click\n\tupgraded to GSL version 2.3 and pulled in gsl_cdf_tdist_Q() and dependencies (no user-visible impact whatsoever)\n\tadded mutation run experiments\n\tadding ttest() function for performing t-tests\n\toptimize fitness calculations using non-neutral mutation caches\n\tspeed up pure neutral models by shifting from gsl_ran_discrete() to eidos_random_int() to choose mates\n\tfix an Eidos bug when doing a for loop on a seqAlong() vector of a zero length parameter, like \"for (i in seqAlong(q)) ...\" where q is zero-length (probably nobody cares)\n\tadd recipe 9.5, Changing selection coefficients with setSelectionCoeff()\n\tadd performance metrics related to mutations and mutation runs to SLiMgui's profile reports\n\tadd setValue() / getValue() capability to MutationType, GenomicElementType, and InteractionType\n\tscripted (type \"s\") DFEs in MutationType now have access to all SLiM constants\n\tadd mutationStackGroup property to MutationType and expand the mutation stacking algorithm accordingly\n\tfix for a potentially serious bug in the Eidos function setDifference() (no impact if you do not use that function)\n\tNOTE: this version changed model output in some cases because of a float/double change in fitness calculations\n\tNOTE: this version changed model output for pure neutral models because of a change in the random numbers used to choose mates\n\n2.3 (build 1052; Eidos version 1.3):\n\tadded x, y, and z properties to Individual for tracking spatial location\n\tadd continuousSpace parameter to initializeSLiMOptions() to allow simulations to register as using continuous space\n\tmake SLiMgui display subpopulations spatially when continuous space is enabled\n\tfix autocompletion bug with simulation symbols\n\tfix an omitted case in Eidos subsetting (which raised an exception)\n\toptimize ifelse() and operator ! in Eidos\n\tchange mateChoice() policy for all-zero return to be equivalent to returning float(0) – reject the first parent\n\toptimization for mean() in Eidos\n\tadd InteractionType class, initializeInteractionType(), and spatial queries\n\tfix copy so syntax coloring gets copied to the clipboard again\n\tadd setSpatialPosition() method to Individual\n\tadd spatialBounds, pointInBounds(), pointReflected(), pointStopped(), pointUniform(), and setSpatialBounds() to Subpopulation\n\tadd chapter 14 recipes\n\tadd chapter headers inside the Recipes menu\n\tadd support for interaction() callbacks\n\tmake the mutation-type argument for fitness() callbacks allow NULL, to allow non-mutation-based fitness callbacks\n\trewrite recipes 13.1, 13.3, 13.10, 14.2, 14.3, 14.4, and 14.5 to use global fitness callbacks instead of marker mutations\n\tallow mateChoice() callbacks to return a singleton Individual that is the chosen mate\n\trewrite recipe 11.2 to return a singleton Individual from its mateChoice() callback\n\tbroaden spatiality of InteractionType to allow \"y\", \"z\", \"xz\", \"yz\"\n\timplement the sex-segregation feature of InteractionType\n\timplement the reciprocality feature of InteractionType, change default for reciprocality to F\n\tadding unevaluate() to allow interactions to be reused with fresh calculations within a generation\n\tfix a code completion bug when the simulation is invalid\n\tfirst passes at recipes 14.6, 14.7, 14.8, and 14.9\n\tmove color-related code from SLiM to Eidos, add new color-conversion functions to Eidos\n\tadd support for spatial maps: defineSpatialMap(), spatialMapValue(), spatialMapColor()\n\tadd recipes 14.10 and 14.11\n\tadd support for output of positional information in outputFull(), and reading of positional information in readFromPopulationFile()\n\tpolicy change: readFromPopulationFile() no longer has the side effect of recalculating fitness values, and warns if called at a time other than a late() event\n\tremove the Import Population... command in SLiMgui, which no longer fits into the fitness-calculation model of SLiM\n\tadd tests for interactions and spatiality, tweak interfaces and requirements\n\n2.2.1 (build 992; Eidos version 1.2.1):\n\tadded recipe to demonstrate forcing a pedigree during mating (recipe 13.7)\n\tadded recipe to show suppression of baseline hermaphroditic selfing (recipe 12.4)\n\tadded recipe for estimating model parameters with ABC (recipe 13.8)\n\tadded tagF property to Individual\n\tfix code completion key binding problem on OS X 10.12\n\tadd recipe for true local ancestry tracking (recipe 13.9)\n\tfix a bug preventing negative constant definitions at the command line\n\tgeneralize command-line defines to allow arbitrary expressions\n\tadd order() function to obtain indices for sorting\n\tadd recipe for heritability with quantitative genetics (recipe 13.10)\n\tadd properties (color, colorSubstitution) to allow custom coloring of individuals, genomic element types, and mutation types in SLiMgui\n\tadd recipe for custom coloring in SLiMgui (recipe 7.4)\n\tadd/modify tests to improve code coverage\n\taccelerate bulk setting of some common read-write SLiM properties (up to a 3x speedup for test cases)\n\tswitch SLiMgui over to a full document-based model (.slim files, save, revert, etc.)\n\thighlight the recycle button green when changes have been made to the script since the last recycle\n\tmake multiple calls to initializeRecombinationRate() illegal, to prevent misunderstandings about how to make complex recombination maps\n\tspeed up syntax coloring for large files\n\tfix hang during mate choice when all individuals are fitness <= 0.0\n\n2.2 (build 955; Eidos version 1.2):\n\tadded recombination() callback for individual-level recombination modifications\n\tadd containsMarkerMutation() method to Genome\n\tadd example recipe for recombination() callbacks, section 13.5\n\tfix so final output from stop(), etc., gets to the output stream\n\tadded clock() function to Eidos for CPU time usage monitoring\n\timprove tick labels in SLiMgui chromosome view\n\tbounce the SLiMgui icon once when a run completes, for notification of the user\n\tadd MutationRun class for storing shared runs of mutations (performance enhancement)\n\tadd a tips/tricks window visible at startup, and make some items for it\n\tconverted the chromosome view to draw with OpenGL (performance enhancement)\n\tadd setValue()/getValue() dictionary capabilities to SLiMSim, Subpopulation, and Individual\n\trevise recipe 11.1 to use setValue()/getValue()\n\tadd -d[efine] command-line argument for slim, to allow Eidos constants to be defined on the command line\n\tNOTE: this version changed model output in many cases because the order of drawing mutations and breakpoints changed\n\n2.1.1 (build 924; Eidos version 1.1.1):\n\tfix segfault with very large recombination maps (thanks Martin Petr)\n\tfix some bad interactions between having sex enabled and using mateChoice()/modifyChild() callbacks (thanks Nathan Oakes)\n\tfix a crash involving accessing the individuals of a subpop after changing the subpop size (caching bug) (thanks to Melissa Hubisz)\n\tsort MS output by position (fix to regression; thanks Alexandre Harris)\n\tadd -mutationCounts method on SLiMSim, parallel to -mutationFrequencies\n\n2.1 (build 907; Eidos version 1.1):\n\tImprove the fitness~time plot (display of subpopulation fitnesses, point/line plotting option)\n\tFix for minor code-completion and status line bugs\n\tAdd infinite loop prevention for mateChoice() and modifyChild() callbacks\n\tAdd \"replace\" parameter to outputSample() and outputMSSample() – BREAKS BACKWARD COMPATIBILITY\n\tAdd outputVCFSample()\n\tFix a bug in Genome's -containsMutations() method that caused it to produce incorrect results if its argument was a non-singleton vector\n\tAdd an Individual class to SLiM, and an \"individuals\" property to Subpopulation\n\tAdd type Individual parameters to SLiM callbacks as needed\n\tAdd a unique index and a tag to Mutation and Substitution\n\tAdded mutation id to output formats and load code, so it is preserved across save/load\n\tThe readFromPopulationFile() method of SLiMSim now sets the generation as a side effect\n\tChange Eidos class methods to also work as non-multicast class methods (receiving the vector of objects as an operand)\n\tAdded size() class method in Eidos\n\tMake code completion smart about functions like sample() that return the same type/class they are passed\n\tAdded sex property to Individual\n\tAdded file output to outputMutations() and outputFixedMutations()\n\tAdded deleteFile() function to Eidos\n\tImprove display of very narrow recombination regions and genomic elements\n\tAdded DFE type 's' for user-defined scripts that generate selection coefficients\n\tAdd script/output show/hide menu command for SLiMgui\n\tAdd support for sex-specific recombination rates/maps\n\tAdd runtime memory overflow checking, disabled with -x command-line flag\n\tChange addNewMutation() and addNewDrawnMutation() to be class methods – BREAKS BACKWARD COMPATIBILITY\n\tAccelerated vectorized property access for singleton properties\n\tAdd \"Open Recipe\" menu in SLiMgui's File menu, for fast recipe access\n\tAdd default arguments and named arguments to Eidos function/method dispatch\n\tSplit ExecuteFunctionCall() into separate functions (no user-visible consequence)\n\tAdd file output and append options to all output methods\n\tAdd createDirectory() function to Eidos\n\tAdd automatic pedigree tracking to the Individual class\n\tAdd new initializeSLiMOptions() initialization function\n\tAdd uniqueMutations property and uniqueMutationsOfType() method to Individual\n\tNOTE: this version changed model output in many cases, for reasons I haven't bothered to retrace\n\n2.0.4 (build 833; Eidos version 1.0.4)\n\tFix issue with interleaving of output from SLiM versus Eidos\n\tFix for a code completion bug with if() statements\n\n2.0.3 (build 828; Eidos version 1.0.3):\n\tGreatly improved code completion facilities\n\tFix for build problem on Ubuntu\n\n2.0.2 (build 824; Eidos version 1.0.2):\n\tAdded beep() function to Eidos\n\tAdded setMutationType() method on Mutation\n\tAdded binary option for outputFull()\n\tAdded return of saved generation in readFromPopulationFile()\n\n2.0.1 (build 815; Eidos version 1.0.1):\n\tAdded format() to Eidos\n\tFixed performance issues in SLiMgui with a very large number of subpopulations\n\n2.0 (build 811; Eidos version 1.0):\n\tVersion history starts.\n"
  },
  {
    "path": "cmake/AboutTheseModules.cmake",
    "content": "# - Dummy module containing information about these modules for the HELP file\n# This file documents a snapshot of the cmake-modules available from\n# http://github.com/rpavlik/cmake-modules/\n# The latest version of these modules can always be found there.\n# Additionally, you can find instructions on how to integrate these modules\n# into your own project either in the README.markdown file in this directory,\n# or on the GitHub page listed above (scroll to the bottom to see the README\n# rendered attractively).\n#\n# In short: Modules of the form \"FindSomeName.cmake\" are considered to be\n# \"find modules\", and are intended to be used indirectly by calling find_package,\n# not by calling include.  Thus, you'll want to do something like:\n#  find_package(SomeName)\n# They define a number of variables allowing you to use whatever software\n# they search for, such as include directories and libraries. A few also\n# define some functions for your use.\n#\n# All other modules provide functionality, either immediately upon including\n# them, or by defining functions that perform some task of varying utility\n# that you can use any time after including them. Note that if a module\n# has the filename, for example, cmake/BoostTestTargets.cmake, you only\n# need to call:\n#  include(BoostTestTargets)\n#\n# For more information, see the documentation for individual modules, the\n# cmake-modules github page, and/or the upstream CMake documentation at\n# http://www.cmake.org/cmake/help/cmake-2-8-docs.html\n#\n#\n# Copyright 2009-2010, Iowa State University\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n# SPDX-License-Identifier: BSL-1.0\n\n"
  },
  {
    "path": "cmake/GetGitRevisionDescription.cmake",
    "content": "# - Returns a version string from Git\n#\n# These functions force a re-configure on each git commit so that you can\n# trust the values of the variables in your build system.\n#\n#  get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])\n#\n# Returns the refspec and sha hash of the current head revision\n#\n#  git_describe(<var> [<additional arguments to git describe> ...])\n#\n# Returns the results of git describe on the source tree, and adjusting\n# the output so that it tests false if an error occurs.\n#\n#  git_describe_working_tree(<var> [<additional arguments to git describe> ...])\n#\n# Returns the results of git describe on the working tree (--dirty option),\n# and adjusting the output so that it tests false if an error occurs.\n#\n#  git_get_exact_tag(<var> [<additional arguments to git describe> ...])\n#\n# Returns the results of git describe --exact-match on the source tree,\n# and adjusting the output so that it tests false if there was no exact\n# matching tag.\n#\n#  git_local_changes(<var>)\n#\n# Returns either \"CLEAN\" or \"DIRTY\" with respect to uncommitted changes.\n# Uses the return code of \"git diff-index --quiet HEAD --\".\n# Does not regard untracked files.\n#\n# Requires CMake 2.6 or newer (uses the 'function' command)\n#\n# Original Author:\n# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>\n# http://academic.cleardefinition.com\n#\n# Copyright 2009-2013, Iowa State University.\n# Copyright 2013-2020, Ryan Pavlik\n# Copyright 2013-2020, Contributors\n# SPDX-License-Identifier: BSL-1.0\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n\nif(__get_git_revision_description)\n    return()\nendif()\nset(__get_git_revision_description YES)\n\n# We must run the following at \"include\" time, not at function call time,\n# to find the path to this module rather than the path to a calling list file\nget_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)\n\n# Function _git_find_closest_git_dir finds the next closest .git directory\n# that is part of any directory in the path defined by _start_dir.\n# The result is returned in the parent scope variable whose name is passed\n# as variable _git_dir_var. If no .git directory can be found, the\n# function returns an empty string via _git_dir_var.\n#\n# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and\n# neither foo nor bar contain a file/directory .git. This wil return\n# C:/bla/.git\n#\nfunction(_git_find_closest_git_dir _start_dir _git_dir_var)\n    set(cur_dir \"${_start_dir}\")\n    set(git_dir \"${_start_dir}/.git\")\n    while(NOT EXISTS \"${git_dir}\")\n        # .git dir not found, search parent directories\n        set(git_previous_parent \"${cur_dir}\")\n        get_filename_component(cur_dir \"${cur_dir}\" DIRECTORY)\n        if(cur_dir STREQUAL git_previous_parent)\n            # We have reached the root directory, we are not in git\n            set(${_git_dir_var}\n                \"\"\n                PARENT_SCOPE)\n            return()\n        endif()\n        set(git_dir \"${cur_dir}/.git\")\n    endwhile()\n    set(${_git_dir_var}\n        \"${git_dir}\"\n        PARENT_SCOPE)\nendfunction()\n\nfunction(get_git_head_revision _refspecvar _hashvar)\n    _git_find_closest_git_dir(\"${CMAKE_CURRENT_SOURCE_DIR}\" GIT_DIR)\n\n    if(\"${ARGN}\" STREQUAL \"ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR\")\n        set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)\n    else()\n        set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)\n    endif()\n    if(NOT \"${GIT_DIR}\" STREQUAL \"\")\n        file(RELATIVE_PATH _relative_to_source_dir \"${CMAKE_SOURCE_DIR}\"\n             \"${GIT_DIR}\")\n        if(\"${_relative_to_source_dir}\" MATCHES \"[.][.]\" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)\n            # We've gone above the CMake root dir.\n            set(GIT_DIR \"\")\n        endif()\n    endif()\n    if(\"${GIT_DIR}\" STREQUAL \"\")\n        set(${_refspecvar}\n            \"GITDIR-NOTFOUND\"\n            PARENT_SCOPE)\n        set(${_hashvar}\n            \"GITDIR-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n\n    # Check if the current source dir is a git submodule or a worktree.\n    # In both cases .git is a file instead of a directory.\n    #\n    if(NOT IS_DIRECTORY ${GIT_DIR})\n        # The following git command will return a non empty string that\n        # points to the super project working tree if the current\n        # source dir is inside a git submodule.\n        # Otherwise the command will return an empty string.\n        #\n        execute_process(\n            COMMAND \"${GIT_EXECUTABLE}\" rev-parse\n                    --show-superproject-working-tree\n            WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"\n            OUTPUT_VARIABLE out\n            ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\n        if(NOT \"${out}\" STREQUAL \"\")\n            # If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule\n            file(READ ${GIT_DIR} submodule)\n            string(REGEX REPLACE \"gitdir: (.*)$\" \"\\\\1\" GIT_DIR_RELATIVE\n                                 ${submodule})\n            string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)\n            get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)\n            get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}\n                                   ABSOLUTE)\n            set(HEAD_SOURCE_FILE \"${GIT_DIR}/HEAD\")\n        else()\n            # GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree\n            file(READ ${GIT_DIR} worktree_ref)\n            # The .git directory contains a path to the worktree information directory\n            # inside the parent git repo of the worktree.\n            #\n            string(REGEX REPLACE \"gitdir: (.*)$\" \"\\\\1\" git_worktree_dir\n                                 ${worktree_ref})\n            string(STRIP ${git_worktree_dir} git_worktree_dir)\n            _git_find_closest_git_dir(\"${git_worktree_dir}\" GIT_DIR)\n            set(HEAD_SOURCE_FILE \"${git_worktree_dir}/HEAD\")\n        endif()\n    else()\n        set(HEAD_SOURCE_FILE \"${GIT_DIR}/HEAD\")\n    endif()\n    set(GIT_DATA \"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data\")\n    if(NOT EXISTS \"${GIT_DATA}\")\n        file(MAKE_DIRECTORY \"${GIT_DATA}\")\n    endif()\n\n    if(NOT EXISTS \"${HEAD_SOURCE_FILE}\")\n        return()\n    endif()\n    set(HEAD_FILE \"${GIT_DATA}/HEAD\")\n    configure_file(\"${HEAD_SOURCE_FILE}\" \"${HEAD_FILE}\" COPYONLY)\n\n    configure_file(\"${_gitdescmoddir}/GetGitRevisionDescription.cmake.in\"\n                   \"${GIT_DATA}/grabRef.cmake\" @ONLY)\n    include(\"${GIT_DATA}/grabRef.cmake\")\n\n    set(${_refspecvar}\n        \"${HEAD_REF}\"\n        PARENT_SCOPE)\n    set(${_hashvar}\n        \"${HEAD_HASH}\"\n        PARENT_SCOPE)\nendfunction()\n\nfunction(git_describe _var)\n    if(NOT GIT_FOUND)\n        find_package(Git QUIET)\n    endif()\n    get_git_head_revision(refspec hash)\n    if(NOT GIT_FOUND)\n        set(${_var}\n            \"GIT-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n    if(NOT hash)\n        set(${_var}\n            \"HEAD-HASH-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n\n    # TODO sanitize\n    #if((${ARGN}\" MATCHES \"&&\") OR\n    #\t(ARGN MATCHES \"||\") OR\n    #\t(ARGN MATCHES \"\\\\;\"))\n    #\tmessage(\"Please report the following error to the project!\")\n    #\tmessage(FATAL_ERROR \"Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}\")\n    #endif()\n\n    #message(STATUS \"Arguments to execute_process: ${ARGN}\")\n\n    execute_process(\n        COMMAND \"${GIT_EXECUTABLE}\" describe --tags --always ${hash} ${ARGN}\n        WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"\n        RESULT_VARIABLE res\n        OUTPUT_VARIABLE out\n        ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if(NOT res EQUAL 0)\n        set(out \"${out}-${res}-NOTFOUND\")\n    endif()\n\n    set(${_var}\n        \"${out}\"\n        PARENT_SCOPE)\nendfunction()\n\nfunction(git_describe_working_tree _var)\n    if(NOT GIT_FOUND)\n        find_package(Git QUIET)\n    endif()\n    if(NOT GIT_FOUND)\n        set(${_var}\n            \"GIT-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n\n    execute_process(\n        COMMAND \"${GIT_EXECUTABLE}\" describe --dirty ${ARGN}\n        WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"\n        RESULT_VARIABLE res\n        OUTPUT_VARIABLE out\n        ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if(NOT res EQUAL 0)\n        set(out \"${out}-${res}-NOTFOUND\")\n    endif()\n\n    set(${_var}\n        \"${out}\"\n        PARENT_SCOPE)\nendfunction()\n\nfunction(git_get_exact_tag _var)\n    git_describe(out --exact-match ${ARGN})\n    set(${_var}\n        \"${out}\"\n        PARENT_SCOPE)\nendfunction()\n\nfunction(git_local_changes _var)\n    if(NOT GIT_FOUND)\n        find_package(Git QUIET)\n    endif()\n    get_git_head_revision(refspec hash)\n    if(NOT GIT_FOUND)\n        set(${_var}\n            \"GIT-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n    if(NOT hash)\n        set(${_var}\n            \"HEAD-HASH-NOTFOUND\"\n            PARENT_SCOPE)\n        return()\n    endif()\n\n    execute_process(\n        COMMAND \"${GIT_EXECUTABLE}\" diff-index --quiet HEAD --\n        WORKING_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}\"\n        RESULT_VARIABLE res\n        OUTPUT_VARIABLE out\n        ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\n    if(res EQUAL 0)\n        set(${_var}\n            \"CLEAN\"\n            PARENT_SCOPE)\n    else()\n        set(${_var}\n            \"DIRTY\"\n            PARENT_SCOPE)\n    endif()\nendfunction()\n"
  },
  {
    "path": "cmake/GetGitRevisionDescription.cmake.in",
    "content": "#\n# Internal file for GetGitRevisionDescription.cmake\n#\n# Requires CMake 2.6 or newer (uses the 'function' command)\n#\n# Original Author:\n# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>\n# http://academic.cleardefinition.com\n# Iowa State University HCI Graduate Program/VRAC\n#\n# Copyright 2009-2012, Iowa State University\n# Copyright 2011-2015, Contributors\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n# SPDX-License-Identifier: BSL-1.0\n\nset(HEAD_HASH)\n\nfile(READ \"@HEAD_FILE@\" HEAD_CONTENTS LIMIT 1024)\n\nstring(STRIP \"${HEAD_CONTENTS}\" HEAD_CONTENTS)\nif(HEAD_CONTENTS MATCHES \"ref\")\n\t# named branch\n\tstring(REPLACE \"ref: \" \"\" HEAD_REF \"${HEAD_CONTENTS}\")\n\tif(EXISTS \"@GIT_DIR@/${HEAD_REF}\")\n\t\tconfigure_file(\"@GIT_DIR@/${HEAD_REF}\" \"@GIT_DATA@/head-ref\" COPYONLY)\n\telse()\n\t\tconfigure_file(\"@GIT_DIR@/packed-refs\" \"@GIT_DATA@/packed-refs\" COPYONLY)\n\t\tfile(READ \"@GIT_DATA@/packed-refs\" PACKED_REFS)\n\t\tif(${PACKED_REFS} MATCHES \"([0-9a-z]*) ${HEAD_REF}\")\n\t\t\tset(HEAD_HASH \"${CMAKE_MATCH_1}\")\n\t\tendif()\n\tendif()\nelse()\n\t# detached HEAD\n\tconfigure_file(\"@GIT_DIR@/HEAD\" \"@GIT_DATA@/head-ref\" COPYONLY)\nendif()\n\nif(NOT HEAD_HASH)\n\tfile(READ \"@GIT_DATA@/head-ref\" HEAD_HASH LIMIT 1024)\n\tstring(STRIP \"${HEAD_HASH}\" HEAD_HASH)\nendif()\n"
  },
  {
    "path": "cmake/GitSHA1.cpp.in",
    "content": "// For setting up the Git commit SHA-1 as a global\n// This is used when building under CMake\n\n#define GIT_SHA1 \"@GIT_SHA1@\"\n\nextern const char g_GIT_SHA1[];\n\nconst char g_GIT_SHA1[] = GIT_SHA1;\n"
  },
  {
    "path": "cmake/GitSHA1.h",
    "content": "// For setting up the Git commit SHA-1 as a global\n// See ../cmake/_README.txt\n\nextern const char g_GIT_SHA1[];\n"
  },
  {
    "path": "cmake/GitSHA1_Xcode.cpp",
    "content": "// For setting up the Git commit SHA-1 as a global\n// This is used when building under Xcode\n\nextern const char g_GIT_SHA1[];\n\nconst char g_GIT_SHA1[] = \"unknown (not defined under Xcode)\";\n"
  },
  {
    "path": "cmake/GitSHA1_qmake.cpp",
    "content": "// For setting up the Git commit SHA-1 as a global\n// This is used when building under qmake\n\nextern const char g_GIT_SHA1[];\n\n#ifdef GIT_SHA1\nconst char g_GIT_SHA1[] = GIT_SHA1;\n#else\n#warning No GIT_SHA1 definition supplied by qmake; check QtSLiM.pro\nconst char g_GIT_SHA1[] = \"unknown (qmake has not defined GIT_SHA1)\";\n#endif\n"
  },
  {
    "path": "cmake/LICENSE_1_0.txt",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "cmake/README.markdown",
    "content": "# Ryan's CMake Modules Collection\n\nRyan A. Pavlik, Ph.D.\n\n<ryan.pavlik@gmail.com> <abiryan@ryand.net>\n<http://academic.cleardefinition.com>\n\n<!--\nCopyright 2009-2014, Iowa State University\nCopyright 2014-2017, Sensics, Inc.\nCopyright 2018-2020, Collabora, Ltd.\nCopyright 2009-2020, Ryan A. Pavlik\nCopyright 2011-2020, Contributors\n\nSPDX-License-Identifier: BSL-1.0\n-->\n\n## Introduction\n\nThis is a collection of CMake modules that I've produced during the course\nof a variety of software development.  There are a number of find modules,\nespecially for virtual reality and physical simulation packages, some utility\nmodules of more general interest, and some patches or workarounds for\n(very old versions of) CMake itself.\n\nEach module is generally documented, and depending on how busy I was\nwhen I created it, the documentation can be fairly complete.\n\nBy now, it also includes contributions both from open-source projects I work on,\nas well as friendly strangers on the Internet contributing their modules. I am\nvery grateful for improvements/fixes/pull requests! As usual, contributions to\nfiles are assumed to be under the same license as they were offered to you\n(incoming == outgoing), and any new files must have proper copyright and SPDX\nlicense identifer headers.\n\n## How to Integrate\n\nHow would you like to use these? Some of the modules, particularly older ones,\nhave a number of internal dependencies, and thus would be best placed wholesale\ninto a `cmake` subdirectory of your project source. Otherwise, you may consider\njust picking the subset you prefer into such a `cmake` subdirectory.\n\n### All Modules\n\nIf you use Git, try installing [git-subtree][1] (included by default on\nGit for Windows and perhaps for your Linux distro, especially post-1.9.1), so\nyou can easily use this repository for subtree merges, updating simply.\n\nFor the initial checkout:\n\n```sh\ncd yourprojectdir\n\ngit subtree add --squash --prefix=cmake https://github.com/rpavlik/cmake-modules.git main\n```\n\nFor updates:\n\n```sh\ncd yourprojectdir\n\ngit subtree pull --squash --prefix=cmake https://github.com/rpavlik/cmake-modules.git main\n```\n\nIf you originally installed this by just copying the files, you'll sadly have to\ndelete the directory, commit that, then do the `git subtree add`. Annoying, but\nI don't know a workaround. (Alternately you can use the method described below,\nfor the \"subset of modules\", to update.)\n\nIf you use some other version control, you can export a copy of this directory\nwithout the git metadata by calling:\n\n```sh\n./export-to-directory.sh ../yourprojectdir/cmake\n```\n\nYou might also consider exporting to a temp directory and merging changes, since\nthis will not overwrite by default.  You can pass -f to overwrite existing files.\n\n### Just a few modules\n\nMany newer modules don't have any or many internal dependencies. You can review\nthem to look for any `include(` statements or other things that increase the\nfiles used (e.g. `configure_file(`, `file(READ`, `file(GENERATE`), and make sure\nyou copy those too.\n\nIf this is how you originally started using these modules, then running the\nfollowing from within a clone of this repo will automatically update any files.\n**Be sure you have committed any local changes in your project first to avoid\npotentially losing work!**\n\n```sh\n./update-modules.sh ../yourprojectdir/cmake/\n```\n\nNote that the script is not smart enough to know about changed dependent\nscripts/files, nor about scripts with matching names but not originating in this\nproject (it just looks at file names/paths), so manually review the diff before\ncommitting in your project.\n\n## How to Use\n\nAt the minimum, all you have to do is add a line like this near the top\nof your root CMakeLists.txt file (but not before your `project()` call):\n\n```cmake\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake\")\n```\n\nYou might also want the extra automatic features/fixes included with the\nmodules, for that, just add another line following the first one:\n\n```cmake\ninclude(UseBackportedModules)\n```\n\nFor more information on individual modules, look at the files themselves: they\nshould all start with a comment.\n\n## Licenses\n\nThe modules that I wrote myself are all subject to this license:\n\n> Copyright 2009-2014, Iowa State University.\n> or Copyright 2014-2017, Sensics, Inc.,\n> or Copyright 2018-2020, Collabora, Ltd.,\n> or Copyright 2009-2020, Ryan A. Pavlik\n>\n> Distributed under the Boost Software License, Version 1.0.\n>\n> (See accompanying file `LICENSE_1_0.txt` or copy at\n> <http://www.boost.org/LICENSE_1_0.txt>)\n\nModules based on those included with CMake are under the OSI-approved BSD\nlicense, which is included in each of those modules. A few other modules are\nmodified from other sources - when in doubt, look at the `.cmake` file - each\nfile has correct licensing information.\n\nIf you'd like to contribute, that would be great! Just make sure to include\nthe license boilerplate in your module, and send a pull request.\n\n## Important License Note\n\nIf you find this file inside of another project, rather at the top-level\ndirectory, you're in a separate project that is making use of these modules.\nThat separate project can (and probably does) have its own license specifics.\n\n[1]: https://github.com/git/git/tree/master/contrib/subtree  \"Git Subtree upstream\"\n"
  },
  {
    "path": "cmake/_README.txt",
    "content": "This folder contains a small subset of the files in:\n\nhttps://github.com/rpavlik/cmake-modules\n\nSpecifically:\n\n./LICENSE_1_0.txt\n./README.markdown\n./AboutTheseModules.cmake\n./GetGitRevisionDescription.cmake\n./GetGitRevisionDescription.cmake.in\n\nThese are distributed under the BSL 1.0 license: ./LICENSE_1_0.txt.\nNote that the BSL 1.0 is compatible with SLiM's license, allowing\nincorporation of these files.  See README.markdown for more info.\nThanks to Ryan A. Pavlik for these very useful modules!\n\n----------------------------------------------------------\n\nThe purpose of including these is to allow the current Git commit\nSHA1 to be shown in QtSLiM and slim's about info, making it easier\nto identify the version of SLiM being used.  See:\n\nhttps://stackoverflow.com/a/4318642/2752221\n\nfor details on how this is done in CMake.\n\nUnder qmake, we have a similar but inferior strategy at present\nbased upon https://stackoverflow.com/a/66315563/2752221 that sets\na define in QtSLiM.pro and sets a C global in GitSHA1_qmake.cpp.\nIt updates only when qmake is run, so the hash shown in SLiMgui\ncan be out of date; BEWARE.  It is intended chiefly for tagging\nbuilds done by the various installers.\n\nUnder Xcode we have no similar scheme, and GitSHA1_Xcode.cpp sets\nup a dummy string that indicates the hash is unknown.\n\nThanks to Bryce Carson for setting me on the trail with a link\nto rpavlik's repo!\n\nBenjamin C. Haller\n2 August 2022\n"
  },
  {
    "path": "cmake/toolchain-mingw64.cmake",
    "content": "# CMake toolchain file for cross-compiling SLiM to Windows using MinGW-w64\n#\n# NOTE: This file is only needed for cross-compiling to Windows from Linux.\n# It is NOT used for normal builds on Linux, macOS, or native Windows (MSYS2).\n#\n# Usage:\n#   mkdir build_win64 && cd build_win64\n#   cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-mingw64.cmake\n#   make -j10 slim eidos\n#\n# Prerequisites:\n#   sudo apt-get install mingw-w64\n#\n# Added by Andrew Kern on 2025-12-14\n# \n\nset(CMAKE_SYSTEM_NAME Windows)\nset(CMAKE_SYSTEM_PROCESSOR x86_64)\n\n# Specify the cross compilers\nset(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)\nset(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)\nset(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)\n\n# Where to find the target environment\nset(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)\n\n# Search for programs in the host environment\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n\n# Search for libraries and headers in the target environment\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n"
  },
  {
    "path": "codecov.yml",
    "content": "coverage:\n  status:\n    project:\n      default:\n        # Allow coverage to drop by up to 1% before failing\n        threshold: 1%\n    patch:\n      default:\n        # Don't require new code to have specific coverage\n        informational: true\n\ncomment:\n  # Post coverage comment on PRs\n  layout: \"reach,diff,flags,files\"\n  behavior: default\n  require_changes: false\n"
  },
  {
    "path": "core/chromosome.cpp",
    "content": "//\n//  chromosome.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"chromosome.h\"\n#include \"eidos_rng.h\"\n#include \"slim_globals.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"individual.h\"\n#include \"subpopulation.h\"\n\n#include <iostream>\n#include <fstream>\n#include <algorithm>\n#include <string>\n#include <cmath>\n#include <utility>\n#include <tuple>\n\n\n// This struct is used to represent a constant-mutation-rate subrange of a genomic element; it is used internally by Chromosome.\n// It is private to Chromosome, and is not exposed in Eidos in any way; it just assists with the drawing of new mutations.\nstruct GESubrange\n{\npublic:\n\tGenomicElement *genomic_element_ptr_;\t\t\t// pointer to the genomic element that contains this subrange\n\tslim_position_t start_position_;\t\t\t\t// the start position of the subrange\n\tslim_position_t end_position_;\t\t\t\t\t// the end position of the subrange\n\t\n\tGESubrange(GenomicElement *p_genomic_element_ptr, slim_position_t p_start_position, slim_position_t p_end_position);\n};\n\ninline __attribute__((always_inline)) GESubrange::GESubrange(GenomicElement *p_genomic_element_ptr, slim_position_t p_start_position, slim_position_t p_end_position) :\n\tgenomic_element_ptr_(p_genomic_element_ptr), start_position_(p_start_position), end_position_(p_end_position)\n{\n}\n\n\n#pragma mark -\n#pragma mark Chromosome\n#pragma mark -\n\nChromosome::Chromosome(Species &p_species, ChromosomeType p_type, int64_t p_id, std::string p_symbol, slim_chromosome_index_t p_index, int p_preferred_mutcount) :\n\tid_(p_id),\n\tsymbol_(p_symbol),\n\tname_(),\n\tindex_(p_index),\n\ttype_(p_type),\n\t\n\texp_neg_overall_mutation_rate_H_(0.0), exp_neg_overall_mutation_rate_M_(0.0), exp_neg_overall_mutation_rate_F_(0.0),\n\texp_neg_overall_recombination_rate_H_(0.0), exp_neg_overall_recombination_rate_M_(0.0), exp_neg_overall_recombination_rate_F_(0.0), \n\t\n#ifndef USE_GSL_POISSON\n\tprobability_both_0_H_(0.0), probability_both_0_OR_mut_0_break_non0_H_(0.0), probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_H_(0.0),\n\tprobability_both_0_M_(0.0), probability_both_0_OR_mut_0_break_non0_M_(0.0), probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_(0.0),\n\tprobability_both_0_F_(0.0), probability_both_0_OR_mut_0_break_non0_F_(0.0), probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_(0.0), \n#endif\n\n\thaplosome_pool_(p_species.population_.species_haplosome_pool_),\n\tpreferred_mutrun_count_(p_preferred_mutcount),\n\tx_experiments_enabled_(false),\n\tcommunity_(p_species.community_),\n\tspecies_(p_species),\n\tlast_position_(0),\n\textent_immutable_(false),\n\toverall_mutation_rate_H_(0.0), overall_mutation_rate_M_(0.0), overall_mutation_rate_F_(0.0),\n\toverall_mutation_rate_H_userlevel_(0.0), overall_mutation_rate_M_userlevel_(0.0), overall_mutation_rate_F_userlevel_(0.0),\n\toverall_recombination_rate_H_(0.0), overall_recombination_rate_M_(0.0), overall_recombination_rate_F_(0.0),\n\toverall_recombination_rate_H_userlevel_(0.0), overall_recombination_rate_M_userlevel_(0.0), overall_recombination_rate_F_userlevel_(0.0),\n\tusing_DSB_model_(false), non_crossover_fraction_(0.0), gene_conversion_avg_length_(0.0), gene_conversion_inv_half_length_(0.0), simple_conversion_fraction_(0.0), mismatch_repair_bias_(0.0),\n\tlast_position_mutrun_(0)\n{\n\t// If the user has said \"no mutation run experiments\" in initializeSLiMOptions(), then a count of zero\n\t// supplied here is interpreted as a count of 1, and experiments will thus not be conducted.\n\tif (!species_.UserWantsMutrunExperiments() && (preferred_mutrun_count_ == 0))\n\t\tpreferred_mutrun_count_ = 1;\n\t\n\t// Set up the default color for fixed mutations in SLiMgui\n\tcolor_sub_ = \"#3333FF\";\n\tif (!color_sub_.empty())\n\t\tEidos_GetColorComponents(color_sub_, &color_sub_red_, &color_sub_green_, &color_sub_blue_);\n\t\n\t// depending on the type of chromosome, cache some properties for quick reference\n\tswitch (type_)\n\t{\n\t\tcase ChromosomeType::kA_DiploidAutosome:\t\t\t\t// type \"A\"\n\t\t\tintrinsic_ploidy_ = 2;\n\t\t\talways_uses_null_haplosomes_ = false;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = false;\n\t\t\ttype_string_ = gStr_A;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// type \"H\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = false;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_H;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kX_XSexChromosome:\t\t\t\t\t// type \"X\"\n\t\t\tintrinsic_ploidy_ = 2;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = true;\n\t\t\tdefaults_to_zero_recombination_ = false;\n\t\t\ttype_string_ = gStr_X;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kY_YSexChromosome:\t\t\t\t\t// type \"Y\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = true;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_Y;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\t\t\t\t\t// type \"Z\"\n\t\t\tintrinsic_ploidy_ = 2;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = true;\n\t\t\tdefaults_to_zero_recombination_ = false;\n\t\t\ttype_string_ = gStr_Z;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kW_WSexChromosome:\t\t\t\t\t// type \"W\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = true;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_W;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\t\t// type \"HF\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = false;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_HF;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\t\t\t\t// type \"FL\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_FL;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\t\t\t// type \"HM\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = false;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_HM;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\t\t\t\t// type \"ML\"\n\t\t\tintrinsic_ploidy_ = 1;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_ML;\n\t\t\tbreak;\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// type \"H-\"\n\t\t\tintrinsic_ploidy_ = 2;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = false;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr_H_;\t\t// \"H-\"\n\t\t\tbreak;\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\t\t// type \"-Y\"\n\t\t\tintrinsic_ploidy_ = 2;\n\t\t\talways_uses_null_haplosomes_ = true;\n\t\t\tis_sex_chromosome_ = true;\n\t\t\tdefaults_to_zero_recombination_ = true;\n\t\t\ttype_string_ = gStr__Y;\t\t// \"-Y\"\n\t\t\tbreak;\n\t}\n}\n\nChromosome::~Chromosome(void)\n{\n\t//EIDOS_ERRSTREAM << \"Chromosome::~Chromosome\" << std::endl;\n\t\n\tif (lookup_mutation_H_)\n\t\tgsl_ran_discrete_free(lookup_mutation_H_);\n\t\n\tif (lookup_mutation_M_)\n\t\tgsl_ran_discrete_free(lookup_mutation_M_);\n\t\n\tif (lookup_mutation_F_)\n\t\tgsl_ran_discrete_free(lookup_mutation_F_);\n\t\n\tif (lookup_recombination_H_)\n\t\tgsl_ran_discrete_free(lookup_recombination_H_);\n\t\n\tif (lookup_recombination_M_)\n\t\tgsl_ran_discrete_free(lookup_recombination_M_);\n\t\n\tif (lookup_recombination_F_)\n\t\tgsl_ran_discrete_free(lookup_recombination_F_);\n\t\n\t// Dispose of any nucleotide sequence\n\tdelete ancestral_seq_buffer_;\n\tancestral_seq_buffer_ = nullptr;\n\t\n\t// Dispose of all genomic elements, which we own\n\tfor (GenomicElement *element : genomic_elements_)\n\t\tdelete element;\n\t\n\t// dispose of haplosomes within our junkyards\n\tfor (Haplosome *haplosome : haplosomes_junkyard_nonnull)\n\t{\n\t\thaplosome->~Haplosome();\n\t\thaplosome_pool_.DisposeChunk(const_cast<Haplosome *>(haplosome));\n\t}\n\thaplosomes_junkyard_nonnull.clear();\n\t\n\tfor (Haplosome *haplosome : haplosomes_junkyard_null)\n\t{\n\t\thaplosome->~Haplosome();\n\t\thaplosome_pool_.DisposeChunk(const_cast<Haplosome *>(haplosome));\n\t}\n\thaplosomes_junkyard_null.clear();\n\t\n\t// Dispose of all mutation run contexts\n#ifndef _OPENMP\n\tdelete mutation_run_context_SINGLE_.allocation_pool_;\n#else\n\tfor (size_t threadnum = 0; threadnum < mutation_run_context_PERTHREAD.size(); ++threadnum)\n\t{\n\t\tomp_destroy_lock(&mutation_run_context_PERTHREAD[threadnum]->allocation_pool_lock_);\n\t\tdelete mutation_run_context_PERTHREAD[threadnum]->allocation_pool_;\n\t\tdelete mutation_run_context_PERTHREAD[threadnum];\n\t}\n\tmutation_run_context_PERTHREAD.clear();\n#endif\n\t\n\t// Dispose of mutation run experiment data\n\tif (x_experiments_enabled_)\n\t{\n\t\tif (x_current_runtimes_)\n\t\t\tfree(x_current_runtimes_);\n\t\tx_current_runtimes_ = nullptr;\n\t\t\n\t\tif (x_previous_runtimes_)\n\t\t\tfree(x_previous_runtimes_);\n\t\tx_previous_runtimes_ = nullptr;\n\t}\n}\n\nvoid Chromosome::CreateNucleotideMutationRateMap(void)\n{\n\t// In Species::CacheNucleotideMatrices() we find the maximum sequence-based mutation rate requested.  Absent a\n\t// hotspot map, this is the overall rate at which we need to generate mutations everywhere along the chromosome,\n\t// because any particular spot could have the nucleotide sequence that leads to that maximum rate; we don't want\n\t// to have to calculate the mutation rate map every time the sequence changes, so instead we use rejection\n\t// sampling.  With a hotspot map, the mutation rate map is the product of the hotspot map and the maximum\n\t// sequence-based rate.  Note that we could get more tricky here – even without a hotspot map we could vary\n\t// the mutation rate map based upon the genomic elements in the chromosome, since different genomic elements\n\t// may have different maximum sequence-based mutation rates.  We do not do that right now, to keep the model\n\t// simple.\n\t\n\t// Note that in nucleotide-based models we completely hide the existence of the mutation rate map from the user;\n\t// all the user sees are the mutationMatrix parameters to initializeGenomicElementType() and the hotspot map\n\t// defined by initializeHotspotMap().  We still use the standard mutation rate map machinery under the hood,\n\t// though.  So this method is, in a sense, an internal call to initializeMutationRate() that sets up the right\n\t// rate map to achieve what the user has requested through other APIs.\n\t\n\tdouble max_nucleotide_mut_rate = species_.MaxNucleotideMutationRate();\n\t\n\tstd::vector<slim_position_t> &hotspot_end_positions_H = hotspot_end_positions_H_;\n\tstd::vector<slim_position_t> &hotspot_end_positions_M = hotspot_end_positions_M_;\n\tstd::vector<slim_position_t> &hotspot_end_positions_F = hotspot_end_positions_F_;\n\tstd::vector<double> &hotspot_multipliers_H = hotspot_multipliers_H_;\n\tstd::vector<double> &hotspot_multipliers_M = hotspot_multipliers_M_;\n\tstd::vector<double> &hotspot_multipliers_F = hotspot_multipliers_F_;\n\t\n\tstd::vector<slim_position_t> &mut_positions_H = mutation_end_positions_H_;\n\tstd::vector<slim_position_t> &mut_positions_M = mutation_end_positions_M_;\n\tstd::vector<slim_position_t> &mut_positions_F = mutation_end_positions_F_;\n\tstd::vector<double> &mut_rates_H = mutation_rates_H_;\n\tstd::vector<double> &mut_rates_M = mutation_rates_M_;\n\tstd::vector<double> &mut_rates_F = mutation_rates_F_;\n\t\n\t// clear the mutation map; there may be old cruft in there, if we're called by setHotspotMap() for example\n\tmut_positions_H.resize(0);\n\tmut_positions_M.resize(0);\n\tmut_positions_F.resize(0);\n\tmut_rates_H.resize(0);\n\tmut_rates_M.resize(0);\n\tmut_rates_F.resize(0);\n\t\n\tif ((hotspot_multipliers_M.size() > 0) && (hotspot_multipliers_F.size() > 0))\n\t{\n\t\t// two sex-specific hotspot maps\n\t\tfor (double multiplier_M : hotspot_multipliers_M)\n\t\t{\n\t\t\tdouble rate = max_nucleotide_mut_rate * multiplier_M;\n\t\t\t\n\t\t\tif (rate > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CreateNucleotideMutationRateMap): the maximum mutation rate in nucleotide-based models is 1.0.\" << EidosTerminate();\n\t\t\t\n\t\t\tmut_rates_M.emplace_back(rate);\n\t\t}\n\t\tfor (double multiplier_F : hotspot_multipliers_F)\n\t\t{\n\t\t\tdouble rate = max_nucleotide_mut_rate * multiplier_F;\n\t\t\t\n\t\t\tif (rate > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CreateNucleotideMutationRateMap): the maximum mutation rate in nucleotide-based models is 1.0.\" << EidosTerminate();\n\t\t\t\n\t\t\tmut_rates_F.emplace_back(rate);\n\t\t}\n\t\t\n\t\tmut_positions_M = hotspot_end_positions_M;\n\t\tmut_positions_F = hotspot_end_positions_F;\n\t}\n\telse if (hotspot_multipliers_H.size() > 0)\n\t{\n\t\t// one hotspot map\n\t\tfor (double multiplier_H : hotspot_multipliers_H)\n\t\t{\n\t\t\tdouble rate = max_nucleotide_mut_rate * multiplier_H;\n\t\t\t\n\t\t\tif (rate > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CreateNucleotideMutationRateMap): the maximum mutation rate in nucleotide-based models is 1.0.\" << EidosTerminate();\n\t\t\t\n\t\t\tmut_rates_H.emplace_back(rate);\n\t\t}\n\t\t\n\t\tmut_positions_H = hotspot_end_positions_H;\n\t}\n\telse\n\t{\n\t\t// No hotspot map specified at all; use a rate of 1.0 across the chromosome with an inferred length\n\t\tif (max_nucleotide_mut_rate > 1.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CreateNucleotideMutationRateMap): the maximum mutation rate in nucleotide-based models is 1.0.\" << EidosTerminate();\n\t\t\n\t\tmut_rates_H.emplace_back(max_nucleotide_mut_rate);\n\t\t//mut_positions_H.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\t\n\tcommunity_.chromosome_changed_ = true;\n}\n\n// initialize the random lookup tables used by Chromosome to draw mutation and recombination events\nvoid Chromosome::InitializeDraws(void)\n{\n\t// If we are in the special case of having no genetics, do some simple initialization and return.\n\t// This leaves us in an unusual state, with nullptr for recombination/mutation rate maps and a\n\t// last_position_ of -1; this state is not normally achievable, and might cause special problems.\n\tif (!species_.HasGenetics())\n\t{\n\t\tsingle_recombination_map_ = true;\n\t\tsingle_mutation_map_ = true;\n\t\t\n\t\tlast_position_ = -1;\n\t\textent_immutable_ = false;\n\t\t\n\t\tif (hotspot_multipliers_H_.size() == 0)\n\t\t\thotspot_multipliers_H_.emplace_back(1.0);\n\t\tif (hotspot_end_positions_H_.size() == 0)\n\t\t\thotspot_end_positions_H_.emplace_back(-1);\n\t\t\n\t\tif (mutation_rates_H_.size() == 0)\n\t\t\tmutation_rates_H_.emplace_back(1.0);\n\t\tif (mutation_end_positions_H_.size() == 0)\n\t\t\tmutation_end_positions_H_.emplace_back(-1);\n\t\t\n\t\tlookup_mutation_H_ = nullptr;\n\t\toverall_mutation_rate_M_userlevel_ = overall_mutation_rate_F_userlevel_ = overall_mutation_rate_H_userlevel_ = 0.0;\n\t\toverall_mutation_rate_M_ = overall_mutation_rate_F_ = overall_mutation_rate_H_ = 0.0;\n\t\texp_neg_overall_mutation_rate_M_ = exp_neg_overall_mutation_rate_F_ = exp_neg_overall_mutation_rate_H_ = 1.0;\n\t\t\n\t\tif (recombination_rates_H_.size() == 0)\n\t\t\trecombination_rates_H_.emplace_back(1.0);\n\t\tif (recombination_end_positions_H_.size() == 0)\n\t\t\trecombination_end_positions_H_.emplace_back(-1);\n\t\t\n\t\tlookup_recombination_H_ = nullptr;\n\t\tany_recombination_rates_05_ = false;\n\t\toverall_recombination_rate_M_userlevel_ = overall_recombination_rate_F_userlevel_ = overall_recombination_rate_H_userlevel_ = 0.0;\n\t\toverall_recombination_rate_M_ = overall_recombination_rate_F_ = overall_recombination_rate_H_ = 0.0;\n\t\texp_neg_overall_recombination_rate_M_ = exp_neg_overall_recombination_rate_F_ = exp_neg_overall_recombination_rate_H_ = 1.0;\n\t\t\n#ifndef USE_GSL_POISSON\n\t\t_InitializeJointProbabilities(overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_H_, probability_both_0_OR_mut_0_break_non0_H_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_H_);\n\t\t\n#endif\n\t\t\n\t\treturn;\n\t}\n\t\n\tif (genomic_elements_.size() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): empty chromosome.\" << EidosTerminate();\n\t\n\t// BCH 8/28/2024: we now sort the genomic elements here; we need them to be sorted later on anyway\n\t// I avoided doing this before because it changed the behavior, but it is hard to imagine anybody caring\n\t// Since elements must be non-overlapping, we only need to sort by start position\n\tstd::sort(genomic_elements_.begin(), genomic_elements_.end(),\n\t\t\t  [](GenomicElement *e1, GenomicElement *e2) { return e1->start_position_ < e2->start_position_; });\n\t\n\t// determine which case we are working with: separate recombination maps for the sexes, or one map\n\tauto rec_rates_H_size = recombination_rates_H_.size();\n\tauto rec_rates_M_size = recombination_rates_M_.size();\n\tauto rec_rates_F_size = recombination_rates_F_.size();\n\t\n\tif ((rec_rates_H_size > 0) && (rec_rates_M_size == 0) && (rec_rates_F_size == 0))\n\t\tsingle_recombination_map_ = true;\n\telse if ((rec_rates_H_size == 0) && (rec_rates_M_size > 0) && (rec_rates_F_size > 0))\n\t\tsingle_recombination_map_ = false;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): (internal error) unclear whether we have separate recombination maps or not, or recombination rate not specified.\" << EidosTerminate();\n\t\n\t// determine which case we are working with: separate mutation maps for the sexes, or one map\n\tauto mut_rates_H_size = mutation_rates_H_.size();\n\tauto mut_rates_M_size = mutation_rates_M_.size();\n\tauto mut_rates_F_size = mutation_rates_F_.size();\n\t\n\tif ((mut_rates_H_size > 0) && (mut_rates_M_size == 0) && (mut_rates_F_size == 0))\n\t\tsingle_mutation_map_ = true;\n\telse if ((mut_rates_H_size == 0) && (mut_rates_M_size > 0) && (mut_rates_F_size > 0))\n\t\tsingle_mutation_map_ = false;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): (internal error) unclear whether we have separate mutation maps or not, or mutation rate not specified.\" << EidosTerminate();\n\t\n\t// Calculate the last chromosome base position from our genomic elements, mutation and recombination maps\n\t// the end of the last genomic element may be before the end of the chromosome; the end of mutation and\n\t// recombination maps all need to agree, though, if they have been supplied.  Checks that the maps do\n\t// not end before the end of the chromosome will be done in _InitializeOne...Map().\n\t// BCH 9/20/2024: A chromosome declared explicitly with initializeChromosome() has an immutable length\n\tif (!extent_immutable_)\n\t{\n\t\tlast_position_ = 0;\n\t\t\n\t\tfor (GenomicElement *genomic_element : genomic_elements_)\n\t\t{ \n\t\t\tif (genomic_element->end_position_ > last_position_)\n\t\t\t\tlast_position_ = genomic_element->end_position_;\n\t\t}\n\t\t\n\t\tif (single_mutation_map_)\n\t\t{\n\t\t\tif (mutation_end_positions_H_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(mutation_end_positions_H_.begin(), mutation_end_positions_H_.end())));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (mutation_end_positions_M_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(mutation_end_positions_M_.begin(), mutation_end_positions_M_.end())));\n\t\t\tif (mutation_end_positions_F_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(mutation_end_positions_F_.begin(), mutation_end_positions_F_.end())));\n\t\t}\n\t\t\n\t\tif (single_recombination_map_)\n\t\t{\n\t\t\tif (recombination_end_positions_H_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(recombination_end_positions_H_.begin(), recombination_end_positions_H_.end())));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (recombination_end_positions_M_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(recombination_end_positions_M_.begin(), recombination_end_positions_M_.end())));\n\t\t\tif (recombination_end_positions_F_.size())\n\t\t\t\tlast_position_ = std::max(last_position_, *(std::max_element(recombination_end_positions_F_.begin(), recombination_end_positions_F_.end())));\n\t\t}\n\t\t\n\t\textent_immutable_ = true;\n\t}\n\t\n\t// Patch the hotspot end vector if it is empty; see setHotspotMap() and initializeHotspotMap().\n\t// Basically, the length of the chromosome might not have been known yet when the user set the map.\n\t// This is done for the mutation rate maps in _InitializeOneMutationMap(); we do it here for the hotspot map.\n\t// Here we also fill in a rate of 1.0 if no rate was supplied\n\tif ((hotspot_multipliers_H_.size() == 0) && (hotspot_multipliers_M_.size() == 0) && (hotspot_multipliers_F_.size() == 0))\n\t\thotspot_multipliers_H_.emplace_back(1.0);\n\tif ((hotspot_end_positions_H_.size() == 0) && (hotspot_multipliers_H_.size() == 1))\n\t\thotspot_end_positions_H_.emplace_back(last_position_);\n\tif ((hotspot_end_positions_M_.size() == 0) && (hotspot_multipliers_M_.size() == 1))\n\t\thotspot_end_positions_M_.emplace_back(last_position_);\n\tif ((hotspot_end_positions_F_.size() == 0) && (hotspot_multipliers_F_.size() == 1))\n\t\thotspot_end_positions_F_.emplace_back(last_position_);\n\t\n\t// Now remake our mutation map info, which we delegate to _InitializeOneMutationMap()\n\tif (single_mutation_map_)\n\t{\n\t\t_InitializeOneMutationMap(lookup_mutation_H_, mutation_end_positions_H_, mutation_rates_H_, overall_mutation_rate_H_userlevel_, overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_, mutation_subranges_H_);\n\t\t\n\t\t// Copy the H rates into the M and F ivars, so that they can be used by DrawMutationAndBreakpointCounts() if needed\n\t\toverall_mutation_rate_M_userlevel_ = overall_mutation_rate_F_userlevel_ = overall_mutation_rate_H_userlevel_;\n\t\toverall_mutation_rate_M_ = overall_mutation_rate_F_ = overall_mutation_rate_H_;\n\t\texp_neg_overall_mutation_rate_M_ = exp_neg_overall_mutation_rate_F_ = exp_neg_overall_mutation_rate_H_;\n\t}\n\telse\n\t{\n\t\t_InitializeOneMutationMap(lookup_mutation_M_, mutation_end_positions_M_, mutation_rates_M_, overall_mutation_rate_M_userlevel_, overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_, mutation_subranges_M_);\n\t\t_InitializeOneMutationMap(lookup_mutation_F_, mutation_end_positions_F_, mutation_rates_F_, overall_mutation_rate_F_userlevel_, overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_, mutation_subranges_F_);\n\t}\n\t\n\t// Now remake our recombination map info, which we delegate to _InitializeOneRecombinationMap()\n\tany_recombination_rates_05_ = false;\n\t\n\tif (single_recombination_map_)\n\t{\n\t\t_InitializeOneRecombinationMap(lookup_recombination_H_, recombination_end_positions_H_, recombination_rates_H_, overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_, overall_recombination_rate_H_userlevel_);\n\t\t\n\t\t// Copy the H rates into the M and F ivars, so that they can be used by DrawMutationAndBreakpointCounts() if needed\n\t\toverall_recombination_rate_M_ = overall_recombination_rate_F_ = overall_recombination_rate_H_;\n\t\texp_neg_overall_recombination_rate_M_ = exp_neg_overall_recombination_rate_F_ = exp_neg_overall_recombination_rate_H_;\n\t\toverall_recombination_rate_M_userlevel_ = overall_recombination_rate_F_userlevel_ = overall_recombination_rate_H_userlevel_;\n\t}\n\telse\n\t{\n\t\t_InitializeOneRecombinationMap(lookup_recombination_M_, recombination_end_positions_M_, recombination_rates_M_, overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_, overall_recombination_rate_M_userlevel_);\n\t\t_InitializeOneRecombinationMap(lookup_recombination_F_, recombination_end_positions_F_, recombination_rates_F_, overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_, overall_recombination_rate_F_userlevel_);\n\t}\n\t\n#ifndef USE_GSL_POISSON\n\t// Calculate joint mutation/recombination probabilities for the H/M/F cases\n\tif (single_mutation_map_ && single_recombination_map_)\n\t{\n\t\t_InitializeJointProbabilities(overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_H_, probability_both_0_OR_mut_0_break_non0_H_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_H_);\n\t}\n\telse if (single_mutation_map_ && !single_recombination_map_)\n\t{\n\t\t_InitializeJointProbabilities(overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_M_, probability_both_0_OR_mut_0_break_non0_M_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_);\n\t\t\n\t\t_InitializeJointProbabilities(overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_F_, probability_both_0_OR_mut_0_break_non0_F_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_);\n\t}\n\telse if (!single_mutation_map_ && single_recombination_map_)\n\t{\n\t\t_InitializeJointProbabilities(overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_M_, probability_both_0_OR_mut_0_break_non0_M_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_);\n\t\t\n\t\t_InitializeJointProbabilities(overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_F_, probability_both_0_OR_mut_0_break_non0_F_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_);\n\t}\n\telse if (!single_mutation_map_ && !single_recombination_map_)\n\t{\n\t\t_InitializeJointProbabilities(overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_M_, probability_both_0_OR_mut_0_break_non0_M_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_);\n\t\t\n\t\t_InitializeJointProbabilities(overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_,\n\t\t\t\t\t\t\t\t\t  overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_,\n\t\t\t\t\t\t\t\t\t  probability_both_0_F_, probability_both_0_OR_mut_0_break_non0_F_, probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_);\n\t}\n#endif\n}\n\n#ifndef USE_GSL_POISSON\nvoid Chromosome::_InitializeJointProbabilities(double p_overall_mutation_rate, double p_exp_neg_overall_mutation_rate,\n\t\t\t\t\t\t\t\t\t\t\t   double p_overall_recombination_rate, double p_exp_neg_overall_recombination_rate,\n\t\t\t\t\t\t\t\t\t\t\t   double &p_both_0, double &p_both_0_OR_mut_0_break_non0, double &p_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0)\n{\n\t// precalculate probabilities for Poisson draws of mutation count and breakpoint count\n\tdouble prob_mutation_0 = Eidos_FastRandomPoisson_PRECALCULATE(p_overall_mutation_rate);\t\t\t// exp(-mu); can be 0 due to underflow\n\tdouble prob_breakpoint_0 = Eidos_FastRandomPoisson_PRECALCULATE(p_overall_recombination_rate);\t// exp(-mu); can be 0 due to underflow\n\t\n\t// this is a validity check on the previous calculation of the exp_neg rates\n\tif ((p_exp_neg_overall_mutation_rate != prob_mutation_0) || (p_exp_neg_overall_recombination_rate != prob_breakpoint_0))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::_InitializeJointProbabilities): zero-probability does not match previous calculation.\" << EidosTerminate();\n\t\n\tdouble prob_mutation_not_0 = 1.0 - prob_mutation_0;\n\tdouble prob_breakpoint_not_0 = 1.0 - prob_breakpoint_0;\n\tdouble prob_both_0 = prob_mutation_0 * prob_breakpoint_0;\n\tdouble prob_mutation_0_breakpoint_not_0 = prob_mutation_0 * prob_breakpoint_not_0;\n\tdouble prob_mutation_not_0_breakpoint_0 = prob_mutation_not_0 * prob_breakpoint_0;\n\t\n\t//\tstd::cout << \"element_mutation_rate_ == \" << element_mutation_rate_ << std::endl;\n\t//\tstd::cout << \"prob_mutation_0 == \" << prob_mutation_0 << std::endl;\n\t//\tstd::cout << \"prob_breakpoint_0 == \" << prob_breakpoint_0 << std::endl;\n\t//\tstd::cout << \"prob_mutation_not_0 == \" << prob_mutation_not_0 << std::endl;\n\t//\tstd::cout << \"prob_breakpoint_not_0 == \" << prob_breakpoint_not_0 << std::endl;\n\t//\tstd::cout << \"prob_both_0 == \" << prob_both_0 << std::endl;\n\t//\tstd::cout << \"prob_mutation_0_breakpoint_not_0 == \" << prob_mutation_0_breakpoint_not_0 << std::endl;\n\t//\tstd::cout << \"prob_mutation_not_0_breakpoint_0 == \" << prob_mutation_not_0_breakpoint_0 << std::endl;\n\t\n\tp_both_0 = prob_both_0;\n\tp_both_0_OR_mut_0_break_non0 = prob_both_0 + prob_mutation_0_breakpoint_not_0;\n\tp_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0 = prob_both_0 + (prob_mutation_0_breakpoint_not_0 + prob_mutation_not_0_breakpoint_0);\n}\n#endif\n\nvoid Chromosome::ChooseMutationRunLayout(void)\n{\n\t// We now have a final last position, so we can calculate our mutation run layout\n\t\n\tif (species_.HasGenetics())\n\t{\n#ifdef _OPENMP\n\t\t// When running multi-threaded, we prefer the base number of mutruns to equal the number of threads\n\t\t// This allows us to subdivide responsibility along the haplosome equally among threads\n\t\tmutrun_count_base_ = gEidosMaxThreads;\n\t\tmutrun_count_multiplier_ = 1;\n\t\t\n\t\t// However, the shortest any mutrun can be is one base position, so with a short chromosome, the\n\t\t// number of mutruns gets clipped to the number of base positions (and not all threads will be used)\n\t\tif (mutrun_count_base_ > (last_position_ + 1))\n\t\t\tmutrun_count_base_ = (int32_t)(last_position_ + 1);\n#else\n\t\t// When running single-threaded, the base number of mutruns is always 1\n\t\tmutrun_count_base_ = 1;\n\t\tmutrun_count_multiplier_ = 1;\n#endif\n\t\t\n\t\tif (preferred_mutrun_count_ != 0)\n\t\t{\n\t\t\t// The user has given us a mutation run count, so use that count and divide the chromosome evenly\n\t\t\tif (preferred_mutrun_count_ < 1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChooseMutationRunLayout): there must be at least one mutation run per haplosome.\" << EidosTerminate();\n\t\t\t\n\t\t\t// If the preferred number of mutation runs is actually larger than the number of discrete positions,\n\t\t\t// it gets clipped.  No warning is emitted; this is pretty obvious, and the verbose output line suffices\n\t\t\tif (preferred_mutrun_count_ > (last_position_ + 1))\n\t\t\t\tpreferred_mutrun_count_ = (int32_t)(last_position_ + 1);\n\t\t\t\n\t\t\t// Similarly, we clip silently at SLIM_MUTRUN_MAXIMUM_COUNT; larger values are not presently allowed,\n\t\t\t// although the code is general and does not actually have a hard limit on the number of mutruns\n\t\t\tif (preferred_mutrun_count_ > SLIM_MUTRUN_MAXIMUM_COUNT)\n\t\t\t\tpreferred_mutrun_count_ = SLIM_MUTRUN_MAXIMUM_COUNT;\n\t\t\t\n#ifdef _OPENMP\n\t\t\t// When running multithreaded, we have some additional restrictions to try to keep the number of mutation runs\n\t\t\t// aligned with the number of threads; but we also want to allow the user to use fewer mutruns/threads\n\t\t\tif (((preferred_mutrun_count_ % gEidosMaxThreads) == 0) ||\t// if it is an exact multiple of the number of threads\n\t\t\t\t(preferred_mutrun_count_ < gEidosMaxThreads))\t\t\t\t// or, less than the number of threads\n\t\t\t\t;\t\t\t\t\t\t\t\t\t\t\t\t\t// then it is fine\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChooseMutationRunLayout): when multithreaded, if the number of mutation runs is specified it must be a multiple of the number of threads, or it must be less than the number of threads (clipped mutationRuns count is \" << preferred_mutrun_count_ << \", thread count is \" << gEidosMaxThreads << \").\" << EidosTerminate();\n#endif\n\t\t\t\n\t\t\tif (preferred_mutrun_count_ == gEidosMaxThreads)\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\t\t{\n\t\t\t\t// We have preferred_mutrun_count_ mutrun sections, each containing 1 mutation run; this is really the same as the next case\n\t\t\t\tmutrun_count_base_ = preferred_mutrun_count_;\n\t\t\t\tmutrun_count_multiplier_ = 1;\n\t\t\t}\n\t\t\telse if ((preferred_mutrun_count_ % gEidosMaxThreads) == 0)\n\t\t\t{\n\t\t\t\t// We have gEidosMaxThreads mutrun sections, each containing (preferred_mutrun_count_ / gEidosMaxThreads) mutation runs\n\t\t\t\tmutrun_count_base_ = gEidosMaxThreads;\n\t\t\t\tmutrun_count_multiplier_ = preferred_mutrun_count_ / gEidosMaxThreads;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The number of threads does not equal gEidosMaxThreads, so we have preferred_mutrun_count_ mutruns sections, each containing 1 mutrun\n\t\t\t\tmutrun_count_base_ = preferred_mutrun_count_;\n\t\t\t\tmutrun_count_multiplier_ = 1;\n\t\t\t}\n\t\t\t\n\t\t\tmutrun_count_ = mutrun_count_base_ * mutrun_count_multiplier_;\n\t\t\tmutrun_length_ = (slim_position_t)ceil((last_position_ + 1) / (double)mutrun_count_);\n\t\t\t\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << std::endl << \"// Override mutation run count = \" << mutrun_count_ << \", run length = \" << mutrun_length_ << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The user has not supplied a count, so we will conduct experiments to find the best count;\n\t\t\t// for simplicity we will just always start with a single run, since that is often best anyway,\n\t\t\t// unless we're running multithreaded; then we start with one run per thread, generally\n\t\t\tmutrun_count_ = mutrun_count_base_ * mutrun_count_multiplier_;\n\t\t\tmutrun_length_ = (slim_position_t)ceil((last_position_ + 1) / (double)mutrun_count_);\n\t\t\t\n\t\t\t// When we are running experiments, the mutation run length needs to be a power of two so that it can be divided evenly,\n\t\t\t// potentially a fairly large number of times.  We impose a maximum mutrun count of SLIM_MUTRUN_MAXIMUM_COUNT, so\n\t\t\t// actually it needs to just be an exact multiple of SLIM_MUTRUN_MAXIMUM_COUNT, not an exact power of two.\n\t\t\tmutrun_length_ = (slim_position_t)round(ceil(mutrun_length_ / (double)SLIM_MUTRUN_MAXIMUM_COUNT) * SLIM_MUTRUN_MAXIMUM_COUNT);\n\t\t\t\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << std::endl << \"// Initial mutation run count = \" << mutrun_count_ << \", run length = \" << mutrun_length_ << std::endl;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// No-genetics species use null haplosomes, and have no mutruns\n\t\tmutrun_count_base_ = 0;\n\t\tmutrun_count_multiplier_ = 1;\n\t\tmutrun_count_ = 0;\n\t\tmutrun_length_ = 0;\n\t}\n\t\n\tlast_position_mutrun_ = mutrun_count_ * mutrun_length_ - 1;\n\t\n\t// Consistency check\n\tif (((mutrun_length_ < 1) && species_.HasGenetics()) || (mutrun_count_ * mutrun_length_ <= last_position_) || (last_position_mutrun_ < last_position_))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChooseMutationRunLayout): (internal error) math error in mutation run calculations.\" << EidosTerminate();\n}\n\n// initialize one recombination map, used internally by InitializeDraws() to avoid code duplication\nvoid Chromosome::_InitializeOneRecombinationMap(gsl_ran_discrete_t *&p_lookup, std::vector<slim_position_t> &p_end_positions, std::vector<double> &p_rates, double &p_overall_rate, double &p_exp_neg_overall_rate, double &p_overall_rate_userlevel)\n{\n\t// Patch the recombination interval end vector if it is empty; see setRecombinationRate() and initializeRecombinationRate().\n\t// Basically, the length of the chromosome might not have been known yet when the user set the rate.\n\tif (p_end_positions.size() == 0)\n\t{\n\t\t// patching can only be done when a single uniform rate is specified\n\t\tif (p_rates.size() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): recombination endpoints not specified.\" << EidosTerminate();\n\t\t\n\t\tp_end_positions.emplace_back(last_position_);\n\t}\n\t\n\tif (p_end_positions[p_rates.size() - 1] < last_position_)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): recombination endpoints do not cover the full chromosome.\" << EidosTerminate();\n\t\n\t// BCH 11 April 2018: Fixing this code to use Peter Ralph's reparameterization that corrects for the way we use these rates\n\t// downstream.  So the rates we are passed in p_rates are from the user, and they represent \"ancestry breakpoint\" rates: the\n\t// desired probability of a crossover from one base to the next.  Downstream, when we actually generate breakpoints, we will\n\t// draw the number of breakpoints from a Poisson distribution with the overall rate of p_overall_rate that we sum up here,\n\t// then we will draw the location of each breakpoint from the p_lookup table we build here, and then we will sort and unique\n\t// those breakpoints so that we only ever have one breakpoint, at most, between any two bases.  That uniquing is the key step\n\t// that drives this reparameterization.  We need to choose a reparameterized lambda value for the Poisson draw such that the\n\t// probability P[Poisson(lambda) >= 1] == rate.  Simply using lambda=rate is a good approximation when rate is small, but when\n\t// rate is larger than 0.01 it starts to break down, and when rate is 0.5 it is quite inaccurate; P[Poisson(0.5) >= 1] ~= 0.39.\n\t// So we reparameterize according to the formula:\n\t//\n\t//\t\tlambda = -log(1 - p)\n\t//\n\t// where p is the probability requested by the user and lambda is the expected mean used for the Poisson draw to ensure that\n\t// P[Poisson(lambda) >= 1] == p.  Note that this formula blows up for p >= 1, and gets numerically unstable as it approaches\n\t// that limit; the lambda values chosen will become very large.  Since values above 0.5 are unbiological anyway, we do not\n\t// allow them; all recombination rates must be <= 0.5 in SLiM, as of this change.  0.5 represents complete independence;\n\t// we do not allow \"anti-linkage\" at present since it seems to be unbiological.  If somebody argues with us on that, we could\n\t// extend the limit up to, say, 0.9 without things blowing up badly, but 1.0 is out of the question.\n\t//\n\t// Here we also calculate the overall recombination rate in reparameterized units, which is what we actually use to draw\n\t// breakpoints, *and* the overall recombination rate in non-reparameterized units (as in SLiM 2.x and before), which is what\n\t// we report to the user if they ask for it (representing the expected number of crossovers along the chromosome).  The\n\t// reparameterized overall recombination rate is the expected number of breakpoints we will generate *before* uniquing,\n\t// which has no meaning for the user.\n\tstd::vector<double> reparameterized_rates;\n\t\n\treparameterized_rates.reserve(p_rates.size());\n\t\n\tfor (double user_rate : p_rates)\n\t{\n\t\t// this bounds check should have been done already externally to us, but no harm in making sure...\n\t\tif ((user_rate < 0.0) || (user_rate > 0.5))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): all recombination rates in SLiM must be in [0.0, 0.5].\" << EidosTerminate();\n\t\t\n#if 1\n\t\t// This is the new recombination-rate paradigm that compensates for uniquing of breakpoints, etc.\n\t\t\n\t\t// keep track of whether any recombination rates in the model are 0.5; if so, gene conversion needs to exclude those positions\n\t\tif (user_rate == 0.5)\n\t\t\tany_recombination_rates_05_ = true;\n\t\t\n\t\treparameterized_rates.emplace_back(-log(1.0 - user_rate));\n\t\t\n\t\t/*\n\t\t A good model to test that the recombination rate observed is actually the crossover rate requested:\n\t\t\n\t\tinitialize() {\n\t\t   defineConstant(\"L\", 10);\t\t// 10 breakpoint positions, so 11 bases\n\t\t   defineConstant(\"N\", 1000);\t\t// 1000 diploids\n\t\t\n\t\t   initializeMutationRate(0);\n\t\t   initializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\t   initializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t   initializeGenomicElement(g1, 0, L);\n\t\t   initializeRecombinationRate(0.5);\n\t\t}\n\t\t1 early() {\n\t\t   sim.addSubpop(\"p1\", N);\n\t\t   sim.tag = 0;\n\t\t}\n\t\trecombination() {\n\t\t   sim.tag = sim.tag + size(unique(breakpoints));\n\t\t   return F;\n\t\t}\n\t\t10000 late() {\n\t\t   print(sim.tag / (10000 * N * 2 * L));\n\t\t}\n\n\t\t */\n#else\n\t\t// This is the old recombination-rate paradigm, which should be used only for testing output compatibility in tests\n#warning old recombination-rate paradigm enabled!\n\t\t\n\t\treparameterized_rates.emplace_back(user_rate);\n#endif\n\t}\n\t\n\t// Calculate the overall recombination rate and the lookup table for breakpoints\n\tstd::vector<double> B(reparameterized_rates.size());\n\tstd::vector<double> B_userlevel(reparameterized_rates.size());\n\t\n\tB_userlevel[0] = p_rates[0] * static_cast<double>(p_end_positions[0]);\n\tB[0] = reparameterized_rates[0] * static_cast<double>(p_end_positions[0]);\t// No +1 here, because the position to the left of the first base is not a valid recombination position.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// So a 1-base model (position 0 to 0) has an end of 0, and thus an overall rate of 0.  This means that\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// gsl_ran_discrete_preproc() is given an interval with rate 0, but that seems OK.  BCH 4 April 2016\n\tfor (unsigned int i = 1; i < reparameterized_rates.size(); i++)\n\t{\n\t\tdouble length = static_cast<double>(p_end_positions[i] - p_end_positions[i - 1]);\n\t\t\n\t\tB_userlevel[i] = p_rates[i] * length;\n\t\tB[i] = reparameterized_rates[i] * length;\n\t}\n\t\n\tp_overall_rate_userlevel = Eidos_ExactSum(B_userlevel.data(), p_rates.size());\n\tp_overall_rate = Eidos_ExactSum(B.data(), reparameterized_rates.size());\n\t\n\t// All the recombination machinery below uses the reparameterized rates\n#ifndef USE_GSL_POISSON\n\tp_exp_neg_overall_rate = Eidos_FastRandomPoisson_PRECALCULATE(p_overall_rate);\t\t\t\t// exp(-mu); can be 0 due to underflow\n#endif\n\t\n\tif (p_lookup)\n\t\tgsl_ran_discrete_free(p_lookup);\n\t\n\tp_lookup = gsl_ran_discrete_preproc(reparameterized_rates.size(), B.data());\n}\n\n// initialize one mutation map, used internally by InitializeDraws() to avoid code duplication\nvoid Chromosome::_InitializeOneMutationMap(gsl_ran_discrete_t *&p_lookup, std::vector<slim_position_t> &p_end_positions, std::vector<double> &p_rates, double &p_requested_overall_rate, double &p_overall_rate, double &p_exp_neg_overall_rate, std::vector<GESubrange> &p_subranges)\n{\n\t// Patch the mutation interval end vector if it is empty; see setMutationRate() and initializeMutationRate().\n\t// Basically, the length of the chromosome might not have been known yet when the user set the rate.\n\tif (p_end_positions.size() == 0)\n\t{\n\t\t// patching can only be done when a single uniform rate is specified\n\t\tif (p_rates.size() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): mutation rate endpoints not specified.\" << EidosTerminate();\n\t\t\n\t\tp_end_positions.emplace_back(last_position_);\n\t}\n\t\n\tif (p_end_positions[p_rates.size() - 1] < last_position_)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): mutation rate endpoints do not cover the full chromosome.\" << EidosTerminate();\n\t\n\t// Calculate the overall mutation rate and the lookup table for mutation events.  This is more complicated than\n\t// for recombination maps, because the mutation rate map needs to be intersected with the genomic element map\n\t// such that all areas outside of any genomic element have a rate of 0.  In the end we need (i) a vector of\n\t// constant-rate subregions that do not span genomic element boundaries, (ii) a lookup table to go from the\n\t// index of a constant-rate subregion to the index of the containing genomic element, and (iii) a lookup table\n\t// to go from the index of a constant-rate subregion to the first base position and length of the subregion.\n\t// In effect, each of these subregions is sort of the new equivalent of a genomic element; we intersect the\n\t// mutation rate map with the genomic element map to create a list of new genomic elements of constant mut rate.\n\t// The class we use to represent these constant-rate subregions is GESubrange, declared in chromosome.h.\n\tp_subranges.clear();\n\t\n\t// We need to work with a *sorted* genomic elements vector here.  BCH 8/28/2024: That is now guaranteed.\n\t\n\t// This code deals in two different currencies: *requested* mutation rates and *adjusted* mutation rates.\n\t// This stems from the fact that, beginning in SLiM 3.5, we unique mutation positions as we're generating\n\t// gametes.  This uniquing means that some drawn positions may be filtered out, resulting in a realized\n\t// mutation rate that is lower than the requested rate (see section 22.2.3 in the manual for discussion).\n\t// We want to compensate for this effect, so that the realized rate is equal to the requested rate.  To do\n\t// that, we calculate adjusted rates that, after uniquing, will result in the requested rate.  However, we\n\t// want to hide this implementation detail from the user; the rate they see in Eidos from Chromosome should\n\t// be the same as the rate they requested originally, not the adjusted rate.  So we do calculations with\n\t// both, so that we can satisfy that requirement.  The adjustment is done piecewise, so that the adjusted\n\t// rate for each GESubrange is correct.  If we have a nucleotide-based matation matrix that leads to some\n\t// rejection sampling, that will be based on the ratios of the original rates, but it will be done *after*\n\t// positions have been drawn and uniqued, so that should also be correct, I think.  BCH 5 Sep. 2020\n\tstd::vector<double> A;\t// a vector of requested subrange weights\n\tstd::vector<double> B;\t// a vector of adjusted subrange weights\n\tunsigned int mutrange_index = 0;\n\tslim_position_t end_of_previous_mutrange = -1;\n\t\n\tfor (GenomicElement *ge_ptr : genomic_elements_)\n\t{\n\t\tGenomicElement &ge = *ge_ptr;\n\t\t\n\t\tfor ( ; mutrange_index < p_rates.size(); mutrange_index++)\n\t\t{\n\t\t\tslim_position_t end_of_mutrange = p_end_positions[mutrange_index];\n\t\t\t\n\t\t\tif (end_of_mutrange < ge.start_position_)\n\t\t\t{\n\t\t\t\t// This mutrange falls entirely before the current genomic element, so it is discarded by falling through\n\t\t\t}\n\t\t\telse if (end_of_previous_mutrange + 1 > ge.end_position_)\n\t\t\t{\n\t\t\t\t// This mutrange falls entirely after the current genomic element, so we need to move to the next genomic element\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This mutrange at least partially intersects the current genomic element, so we need to make a new GESubrange\n\t\t\t\tslim_position_t subrange_start = std::max(end_of_previous_mutrange + 1, ge.start_position_);\n\t\t\t\tslim_position_t subrange_end = std::min(end_of_mutrange, ge.end_position_);\n\t\t\t\tslim_position_t subrange_length = subrange_end - subrange_start + 1;\n\t\t\t\tdouble requested_rate = p_rates[mutrange_index];\n\t\t\t\t\n\t\t\t\tif (requested_rate >= 1.0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitializeDraws): requested mutation rate is >= 1.0.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tdouble adjusted_rate = -log1p(-requested_rate);\n\t\t\t\tdouble requested_subrange_weight = requested_rate * subrange_length;\n\t\t\t\tdouble adjusted_subrange_weight = adjusted_rate * subrange_length;\n\t\t\t\t\n\t\t\t\tA.emplace_back(requested_subrange_weight);\n\t\t\t\tB.emplace_back(adjusted_subrange_weight);\n\t\t\t\tp_subranges.emplace_back(&ge, subrange_start, subrange_end);\n\t\t\t\t\n\t\t\t\t// Now we need to decide whether to advance the genomic element or not; advancing mutrange_index here is not needed\n\t\t\t\tif (end_of_mutrange >= ge.end_position_)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tend_of_previous_mutrange = end_of_mutrange;\n\t\t}\n\t}\n\t\n\tp_requested_overall_rate = Eidos_ExactSum(A.data(), A.size());\n\tp_overall_rate = Eidos_ExactSum(B.data(), B.size());\n\t\n#ifndef USE_GSL_POISSON\n\tp_exp_neg_overall_rate = Eidos_FastRandomPoisson_PRECALCULATE(p_overall_rate);\t\t\t\t// exp(-mu); can be 0 due to underflow\n#endif\n\t\n\tif (p_lookup)\n\t\tgsl_ran_discrete_free(p_lookup);\n\t\n\tp_lookup = gsl_ran_discrete_preproc(B.size(), B.data());\n}\n\n// prints an error message and exits\nvoid Chromosome::MutationMapConfigError(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (Chromosome::MutationMapConfigError): (internal error) an error occurred in the configuration of mutation maps.\" << EidosTerminate();\n}\nvoid Chromosome::RecombinationMapConfigError(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (Chromosome::RecombinationMapConfigError): (internal error) an error occurred in the configuration of recombination maps.\" << EidosTerminate();\n}\n\nint Chromosome::DrawSortedUniquedMutationPositions(int p_count, IndividualSex p_sex, std::vector<std::pair<slim_position_t, GenomicElement *>> &p_positions)\n{\n\t// BCH 1 September 2020: This method generates a vector of positions, sorted and uniqued for the caller.  This avoid various issues\n\t// with two mutations occurring at the same position in the same gamete.  For example, nucleotide states in the tree-seq tables could\n\t// end up in a state that would normally be illegal, such as an A->G mutation followed by a G->G mutation, because SLiM's code wouldn't\n\t// understand that the second mutation occurred on the background of the first; it would think that both mutations were A->G, erroneously.\n\t// This also messed up uniquing of mutations with a mutation() callback in SLiM 3.5; you might want all mutations representing a given\n\t// nucleotide at a given position to share the same mutation object (IBS instead of IBD), but if two mutations occurred at the same\n\t// position in the same gamete, the first might be accepted, and then second – which should unique down to the first – would also be\n\t// accepted.  The right fix seems to be to unique the drawn mutation positions before creating mutations, avoiding all these issues;\n\t// multiple mutations at the same position in the same gamete seems unbiological anyway.\n\tgsl_ran_discrete_t *lookup;\n\tconst std::vector<GESubrange> *subranges;\n\t\n\tif (single_mutation_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\tlookup = lookup_mutation_H_;\n\t\tsubranges = &mutation_subranges_H_;\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\tlookup = lookup_mutation_M_;\n\t\t\tsubranges = &mutation_subranges_M_;\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\tlookup = lookup_mutation_F_;\n\t\t\tsubranges = &mutation_subranges_F_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tMutationMapConfigError();\n\t\t}\n\t}\n\t\n\t// draw all the positions, and keep track of the genomic element type for each\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tfor (int i = 0; i < p_count; ++i)\n\t{\n\t\tint mut_subrange_index = static_cast<int>(gsl_ran_discrete(rng_gsl, lookup));\n\t\tconst GESubrange &subrange = (*subranges)[mut_subrange_index];\n\t\tGenomicElement *source_element = subrange.genomic_element_ptr_;\n\t\t\n\t\t// Draw the position along the chromosome for the mutation, within the genomic element\n\t\tslim_position_t position = subrange.start_position_ + static_cast<slim_position_t>(Eidos_rng_interval_uint64(rng_64, subrange.end_position_ - subrange.start_position_ + 1));\n\t\t\n\t\tp_positions.emplace_back(position, source_element);\n\t}\n\t\n\t// sort and unique by position; 1 and 2 mutations are particularly common, so try to speed those up\n\tif (p_count > 1)\n\t{\n\t\tif (p_count == 2)\n\t\t{\n\t\t\tif (p_positions[0].first > p_positions[1].first)\n\t\t\t\tstd::swap(p_positions[0], p_positions[1]);\n\t\t\telse if (p_positions[0].first == p_positions[1].first)\n\t\t\t\tp_positions.resize(1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::sort(p_positions.begin(), p_positions.end(), [](const std::pair<slim_position_t, GenomicElement *> &p1, const std::pair<slim_position_t, GenomicElement *> &p2) { return p1.first < p2.first; });\n\t\t\tauto unique_iter = std::unique(p_positions.begin(), p_positions.end(), [](const std::pair<slim_position_t, GenomicElement *> &p1, const std::pair<slim_position_t, GenomicElement *> &p2) { return p1.first == p2.first; });\n\t\t\tp_positions.resize(std::distance(p_positions.begin(), unique_iter));\n\t\t}\n\t}\n\t\n\treturn (int)p_positions.size();\n}\n\n// draw a new mutation, based on the genomic element types present and their mutational proclivities\nMutationIndex Chromosome::DrawNewMutation(std::pair<slim_position_t, GenomicElement *> &p_position, slim_objectid_t p_subpop_index, slim_tick_t p_tick) const\n{\n\tconst GenomicElement &source_element = *(p_position.second);\n\tconst GenomicElementType &genomic_element_type = *(source_element.genomic_element_type_ptr_);\n\tMutationType *mutation_type_ptr = genomic_element_type.DrawMutationType();\n\t\n\tdouble selection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\n\t// NOTE THAT THE STACKING POLICY IS NOT ENFORCED HERE, SINCE WE DO NOT KNOW WHAT HAPLOSOME WE WILL BE INSERTED INTO!  THIS IS THE CALLER'S RESPONSIBILITY!\n\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\n\t// A nucleotide value of -1 is always used here; in nucleotide-based models this gets patched later, but that is sequence-dependent and background-dependent\n\tMutation *mutation = gSLiM_Mutation_Block + new_mut_index;\n\t\n\tnew (mutation) Mutation(mutation_type_ptr, index_, p_position.first, selection_coeff, p_subpop_index, p_tick, -1);\n\t\n\t// addition to the main registry and the muttype registries will happen if the new mutation clears the stacking policy\n\t\n\treturn new_mut_index;\n}\n\n// apply mutation() to a generated mutation; we might return nullptr (proposed mutation rejected), the original proposed mutation (it was accepted), or a replacement Mutation *\nMutation *Chromosome::ApplyMutationCallbacks(Mutation *p_mut, Haplosome *p_haplosome, GenomicElement *p_genomic_element, int8_t p_original_nucleotide, std::vector<SLiMEidosBlock*> &p_mutation_callbacks) const\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyMutationCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tslim_objectid_t mutation_type_id = p_mut->mutation_type_ptr_->mutation_type_id_;\n\t\n\t// note the focal child during the callback, so we can prevent illegal operations during the callback\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosMutationCallback;\n\t\n\tbool mutation_accepted = true, mutation_replaced = false;\n\t\n\tfor (SLiMEidosBlock *mutation_callback : p_mutation_callbacks)\n\t{\n\t\tif (mutation_callback->block_active_)\n\t\t{\n\t\t\tslim_objectid_t callback_mutation_type_id = mutation_callback->mutation_type_id_;\n\t\t\t\n\t\t\tif ((callback_mutation_type_id == -1) || (callback_mutation_type_id == mutation_type_id))\n\t\t\t{\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t// SLiMgui debugging point\n\t\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\t\n\t\t\t\t{\n\t\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\t\tEidosToken *decl_token = mutation_callback->root_node_->token_;\n\t\t\t\t\t\n\t\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t\t{\n\t\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG mutation(\";\n\t\t\t\t\t\tif ((mutation_callback->mutation_type_id_ != -1) && (mutation_callback->subpopulation_id_ != -1))\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"m\" << mutation_callback->mutation_type_id_ << \", p\" << mutation_callback->subpopulation_id_;\n\t\t\t\t\t\telse if (mutation_callback->mutation_type_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"m\" << mutation_callback->mutation_type_id_;\n\t\t\t\t\t\telse if (mutation_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"NULL, p\" << mutation_callback->subpopulation_id_;\n\t\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutation_callback->block_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << mutation_callback->block_id_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\t\tindenter.indent();\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t\t\n\t\t\t\t// The callback is active and matches the mutation type id of the mutation, so we need to execute it\n\t\t\t\t// This code is similar to Population::ExecuteScript, but we set up an additional symbol table, and we use the return value\n\t\t\t\tEidosValue_Object local_mut(p_mut, gSLiM_Mutation_Class);\n\t\t\t\tEidosValue_Int local_originalNuc(p_original_nucleotide);\n\t\t\t\t\n\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t{\n\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\tEidosInterpreter interpreter(mutation_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (mutation_callback->contains_self_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(mutation_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\n\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\tif (mutation_callback->contains_mut_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_mut.StackAllocated();\t\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_mut, EidosValue_SP(&local_mut));\n\t\t\t\t\t}\n\t\t\t\t\tif (mutation_callback->contains_parent_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_parent, p_haplosome->OwningIndividual()->CachedEidosValue());\n\t\t\t\t\tif (mutation_callback->contains_haplosome_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_haplosome, p_haplosome->CachedEidosValue());\n\t\t\t\t\tif (mutation_callback->contains_element_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_element, p_genomic_element->CachedEidosValue());\n\t\t\t\t\tif (mutation_callback->contains_subpop_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, p_haplosome->OwningIndividual()->subpopulation_->SymbolTableEntry().second);\n\t\t\t\t\tif (mutation_callback->contains_originalNuc_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_originalNuc.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_originalNuc, EidosValue_SP(&local_originalNuc));\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton logical, T if the mutation is accepted, F if it is rejected, or a Mutation object\n\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(mutation_callback->script_);\n\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\tEidosValueType resultType = result->Type();\n\t\t\t\t\t\tint resultCount = result->Count();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((resultType == EidosValueType::kValueLogical) && (resultCount == 1))\n\t\t\t\t\t\t{\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tmutation_accepted = result->LogicalData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tmutation_accepted = ((EidosValue_Logical *)result)->data()[0];\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ((resultType == EidosValueType::kValueObject) && (((EidosValue_Object *)result)->Class() == gSLiM_Mutation_Class) && (resultCount == 1))\n\t\t\t\t\t\t{\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tMutation *replacementMutation = (Mutation *)result->ObjectData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tMutation *replacementMutation = (Mutation *)((EidosValue_Object *)result)->data()[0];\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (replacementMutation == p_mut)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// returning the proposed mutation is the same as accepting it\n\t\t\t\t\t\t\t\tmutation_accepted = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// First, check that the mutation fits the requirements: position, mutation type, nucleotide; we are already set up for the mutation type and can't change in\n\t\t\t\t\t\t\t\t// mid-stream (would we switch to running mutation() callbacks for the new type??), and we have already chosen the nucleotide for consistency with the background\n\t\t\t\t\t\t\t\t// BCH 3 September 2020: A thread on slim-discuss (https://groups.google.com/forum/#!topic/slim-discuss/ALnZrzIroKY) has convinced me that it would be useful\n\t\t\t\t\t\t\t\t// to be able to return a replacement mutation of a different mutation type, so that you can generate mutations of a single type up front and multifurcate that\n\t\t\t\t\t\t\t\t// generation process into multiple mutation types on the other side (perhaps with different dominance coefficients, for example).  So I have relaxed the\n\t\t\t\t\t\t\t\t// mutation type requirement here.  If the mutation type is changed in the replacement, we switch to running callbacks for the new mutation type, but we do not\n\t\t\t\t\t\t\t\t// go back to the beginning; we're running callbacks in the order they were declared, and just switching which type we're running, mid-stream.\n\t\t\t\t\t\t\t\t// BCH 4 September 2020: Peter has persuaded me to relax the nucleotide restriction as well.  If the user changes the nucleotide, it may produce surprising\n\t\t\t\t\t\t\t\t// results (a mutation that doesn't change the nucleotide, like G->G, or a deviation from requested mutation-matrix probabilities), but that's the user's\n\t\t\t\t\t\t\t\t// responsibility to deal with; it can be a useful thing to do, Peter thinks.\n\t\t\t\t\t\t\t\tif (replacementMutation->position_ != p_mut->position_)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ApplyMutationCallbacks): a replacement mutation from a mutation() callback must match the position of the proposed mutation.\" << EidosTerminate(mutation_callback->identifier_token_);\n\t\t\t\t\t\t\t\tif ((replacementMutation->state_ == MutationState::kRemovedWithSubstitution) || (replacementMutation->state_ == MutationState::kFixedAndSubstituted))\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ApplyMutationCallbacks): a replacement mutation from a mutation() callback cannot be fixed/substituted.\" << EidosTerminate(mutation_callback->identifier_token_);\n\t\t\t\t\t\t\t\tif (replacementMutation->mutation_type_ptr_ != p_mut->mutation_type_ptr_)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t//EIDOS_TERMINATION << \"ERROR (Chromosome::ApplyMutationCallbacks): a replacement mutation from a mutation() callback must match the mutation type of the proposed mutation.\" << EidosTerminate(mutation_callback->identifier_token_);\n\t\t\t\t\t\t\t\t\tmutation_type_id = p_mut->mutation_type_ptr_->mutation_type_id_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t//if (replacementMutation->nucleotide_ != p_mut->nucleotide_)\n\t\t\t\t\t\t\t\t//\tEIDOS_TERMINATION << \"ERROR (Chromosome::ApplyMutationCallbacks): a replacement mutation from a mutation() callback must match the nucleotide of the proposed mutation.\" << EidosTerminate(mutation_callback->identifier_token_);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// It fits the bill, so replace the original proposed mutation with this new mutation; note we don't fix local_mut, it's about to go out of scope anyway\n\t\t\t\t\t\t\t\tp_mut = replacementMutation;\n\t\t\t\t\t\t\t\tmutation_replaced = true;\n\t\t\t\t\t\t\t\tmutation_accepted = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ApplyMutationCallbacks): mutation() callbacks must provide a return value that is either a singleton logical or a singleton Mutation object.\" << EidosTerminate(mutation_callback->identifier_token_);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!mutation_accepted)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// If a replacement mutation has been accepted at this point, we now check that it is not already present in the background haplosome; if it is present, the mutation is a no-op (implemented as a rejection)\n\tif (mutation_replaced && mutation_accepted)\n\t{\n\t\tif (p_haplosome->contains_mutation(p_mut))\n\t\t\tmutation_accepted = false;\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMutationCallback)]);\n#endif\n\t\n\treturn (mutation_accepted ? p_mut : nullptr);\n}\n\n// draw a new mutation with reference to the genomic background upon which it is occurring, for nucleotide-based models and/or mutation() callbacks\nMutationIndex Chromosome::DrawNewMutationExtended(std::pair<slim_position_t, GenomicElement *> &p_position, slim_objectid_t p_subpop_index, slim_tick_t p_tick, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, slim_position_t *p_breakpoints, int p_breakpoints_count, std::vector<SLiMEidosBlock*> *p_mutation_callbacks) const\n{\n\tslim_position_t position = p_position.first;\n\tGenomicElement &source_element = *(p_position.second);\n\tconst GenomicElementType &genomic_element_type = *(source_element.genomic_element_type_ptr_);\n\t\n\t// Determine which parental haplosome the mutation will be atop (so we can get the genetic context for it)\n\tbool on_first_haplosome = true;\n\t\n\tif (p_breakpoints)\n\t{\n\t\tfor (int break_index = 0; break_index < p_breakpoints_count; ++break_index)\n\t\t{\n\t\t\tif (p_breakpoints[break_index] > position)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\ton_first_haplosome = !on_first_haplosome;\n\t\t}\n\t}\n\t\n\tHaplosome *background_haplosome = (on_first_haplosome ? parent_haplosome_1 : parent_haplosome_2);\n\t\n\t// Determine whether the mutation will be created at all, and if it is, what nucleotide to use\n\tint8_t original_nucleotide = -1, nucleotide = -1;\n\t\n\tif (genomic_element_type.mutation_matrix_)\n\t{\n\t\tEidosValue_Float *mm = genomic_element_type.mutation_matrix_.get();\n\t\tint mm_count = mm->Count();\n\t\t\n\t\tif (mm_count == 16)\n\t\t{\n\t\t\t// The mutation matrix only cares about the single-nucleotide context; figure it out\n\t\t\tHaplosomeWalker walker(background_haplosome);\n\t\t\t\n\t\t\twalker.MoveToPosition(position);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= position is guaranteed by MoveToPosition()\n\t\t\t\tif (pos == position)\n\t\t\t\t{\n\t\t\t\t\tint8_t mut_nuc = mut->nucleotide_;\n\t\t\t\t\t\n\t\t\t\t\tif (mut_nuc != -1)\n\t\t\t\t\t\toriginal_nucleotide = mut_nuc;\n\t\t\t\t\t\n\t\t\t\t\twalker.NextMutation();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// No mutation is present at the position, so the background comes from the ancestral sequence\n\t\t\tif (original_nucleotide == -1)\n\t\t\t\toriginal_nucleotide = (int8_t)ancestral_seq_buffer_->NucleotideAtIndex(position);\n\t\t\t\n\t\t\t// OK, now we know the background nucleotide; determine the mutation rates to derived nucleotides\n\t\t\tdouble *nuc_thresholds = genomic_element_type.mm_thresholds + (size_t)original_nucleotide * 4;\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\n\t\t\tif (draw < nuc_thresholds[0])\t\tnucleotide = 0;\n\t\t\telse if (draw < nuc_thresholds[1])\tnucleotide = 1;\n\t\t\telse if (draw < nuc_thresholds[2])\tnucleotide = 2;\n\t\t\telse if (draw < nuc_thresholds[3])\tnucleotide = 3;\n\t\t\telse {\n\t\t\t\t// The mutation is an excess mutation, the result of an overall mutation rate on this genetic background\n\t\t\t\t// that is less than the maximum overall mutation rate for any genetic background; it should be discarded,\n\t\t\t\t// as if this mutation event never occurred at all.  We signal this by returning -1.\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\telse if (mm_count == 256)\n\t\t{\n\t\t\t// The mutation matrix cares about the trinucleotide context; figure it out\n\t\t\tint8_t background_nuc1 = -1, background_nuc3 = -1;\n\t\t\tHaplosomeWalker walker(background_haplosome);\n\t\t\t\n\t\t\twalker.MoveToPosition(position - 1);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= position - 1 is guaranteed by MoveToPosition()\n\t\t\t\tif (pos == position - 1)\n\t\t\t\t{\n\t\t\t\t\tint8_t mut_nuc = mut->nucleotide_;\n\t\t\t\t\t\n\t\t\t\t\tif (mut_nuc != -1)\n\t\t\t\t\t\tbackground_nuc1 = mut_nuc;\n\t\t\t\t\t\n\t\t\t\t\twalker.NextMutation();\n\t\t\t\t}\n\t\t\t\telse if (pos == position)\n\t\t\t\t{\n\t\t\t\t\tint8_t mut_nuc = mut->nucleotide_;\n\t\t\t\t\t\n\t\t\t\t\tif (mut_nuc != -1)\n\t\t\t\t\t\toriginal_nucleotide = mut_nuc;\n\t\t\t\t\t\n\t\t\t\t\twalker.NextMutation();\n\t\t\t\t}\n\t\t\t\telse if (pos == position + 1)\n\t\t\t\t{\n\t\t\t\t\tint8_t mut_nuc = mut->nucleotide_;\n\t\t\t\t\t\n\t\t\t\t\tif (mut_nuc != -1)\n\t\t\t\t\t\tbackground_nuc3 = mut_nuc;\n\t\t\t\t\t\n\t\t\t\t\twalker.NextMutation();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// No mutation is present at the position, so the background comes from the ancestral sequence\n\t\t\t// If a base in the trinucleotide is off the end of the chromosome, we assume it is an A; that is arbitrary,\n\t\t\t// but should avoid skewed rates associated with the dynamics of C/G in certain sequences (like CpG)\n\t\t\tif (background_nuc1 == -1)\n\t\t\t\tbackground_nuc1 = ((position == 0) ? 0 : (int8_t)ancestral_seq_buffer_->NucleotideAtIndex(position - 1));\n\t\t\tif (original_nucleotide == -1)\n\t\t\t\toriginal_nucleotide = (int8_t)ancestral_seq_buffer_->NucleotideAtIndex(position);\n\t\t\tif (background_nuc3 == -1)\n\t\t\t\tbackground_nuc3 = ((position == last_position_) ? 0 : (int8_t)ancestral_seq_buffer_->NucleotideAtIndex(position + 1));\n\t\t\t\n\t\t\t// OK, now we know the background nucleotide; determine the mutation rates to derived nucleotides\n\t\t\tint trinuc = ((int)background_nuc1) * 16 + ((int)original_nucleotide) * 4 + (int)background_nuc3;\n\t\t\tdouble *nuc_thresholds = genomic_element_type.mm_thresholds + (size_t)trinuc * 4;\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\n\t\t\tif (draw < nuc_thresholds[0])\t\tnucleotide = 0;\n\t\t\telse if (draw < nuc_thresholds[1])\tnucleotide = 1;\n\t\t\telse if (draw < nuc_thresholds[2])\tnucleotide = 2;\n\t\t\telse if (draw < nuc_thresholds[3])\tnucleotide = 3;\n\t\t\telse {\n\t\t\t\t// The mutation is an excess mutation, the result of an overall mutation rate on this genetic background\n\t\t\t\t// that is less than the maximum overall mutation rate for any genetic background; it should be discarded,\n\t\t\t\t// as if this mutation event never occurred at all.  We signal this by returning -1.\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawNewMutationExtended): (internal error) unexpected mutation matrix size.\" << EidosTerminate();\n\t}\n\t\n\t// Draw mutation type and selection coefficient, and create the new mutation\n\tMutationType *mutation_type_ptr = genomic_element_type.DrawMutationType();\n\t\n\tdouble selection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\n\t// NOTE THAT THE STACKING POLICY IS NOT ENFORCED HERE!  THIS IS THE CALLER'S RESPONSIBILITY!\n\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\tMutation *mutation = gSLiM_Mutation_Block + new_mut_index;\n\t\n\tnew (mutation) Mutation(mutation_type_ptr, index_, position, selection_coeff, p_subpop_index, p_tick, nucleotide);\n\t\n\t// Call mutation() callbacks if there are any\n\tif (p_mutation_callbacks)\n\t{\n\t\tMutation *post_callback_mut = ApplyMutationCallbacks(gSLiM_Mutation_Block + new_mut_index, background_haplosome, &source_element, original_nucleotide, *p_mutation_callbacks);\n\t\t\n\t\t// If the callback didn't return the proposed mutation, it will not be used; dispose of it\n\t\tif (post_callback_mut != mutation)\n\t\t{\n\t\t\t//std::cout << \"proposed mutation not used, disposing...\" << std::endl;\n\t\t\tmutation->Release();\n\t\t}\n\t\t\n\t\t// If it returned nullptr, the mutation event was rejected\n\t\tif (post_callback_mut == nullptr)\n\t\t{\n\t\t\t//std::cout << \"mutation rejected...\" << std::endl;\n\t\t\treturn -1;\n\t\t}\n\t\t\n\t\t// Otherwise, we will request the addition of whatever mutation it returned (which might be the proposed mutation).\n\t\t// Note that if an existing mutation was returned, ApplyMutationCallbacks() guarantees that it is not already present in the background haplosome.\n\t\tMutationIndex post_callback_mut_index = post_callback_mut->BlockIndex();\n\t\t\n\t\tif (new_mut_index != post_callback_mut_index)\n\t\t{\n\t\t\t//std::cout << \"replacing mutation!\" << std::endl;\n\t\t\tnew_mut_index = post_callback_mut_index;\n\t\t}\n\t}\n\t\n\t// addition to the main registry and the muttype registries will happen if the new mutation clears the stacking policy\n\t\n\treturn new_mut_index;\n}\n\n// draw a set of uniqued breakpoints according to the \"crossover breakpoint\" model and run them through recombination() callbacks, returning the final usable set\nvoid Chromosome::_DrawCrossoverBreakpoints(IndividualSex p_parent_sex, const int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers) const\n{\n\t// BEWARE! Chromosome::DrawDSBBreakpoints() below must be altered in parallel with this method!\n#if DEBUG\n\tif (using_DSB_model_)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawCrossoverBreakpoints): (internal error) this method should not be called when the DSB recombination model is being used.\" << EidosTerminate();\n#endif\n\t\n\tgsl_ran_discrete_t *lookup;\n\tconst std::vector<slim_position_t> *end_positions;\n\t\n\tif (single_recombination_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\tlookup = lookup_recombination_H_;\n\t\tend_positions = &recombination_end_positions_H_;\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_parent_sex == IndividualSex::kMale)\n\t\t{\n\t\t\tlookup = lookup_recombination_M_;\n\t\t\tend_positions = &recombination_end_positions_M_;\n\t\t}\n\t\telse if (p_parent_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\tlookup = lookup_recombination_F_;\n\t\t\tend_positions = &recombination_end_positions_F_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRecombinationMapConfigError();\n\t\t}\n\t}\n\t\n\t// draw recombination breakpoints\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tfor (int i = 0; i < p_num_breakpoints; i++)\n\t{\n\t\tslim_position_t breakpoint = 0;\n\t\tint recombination_interval = static_cast<int>(gsl_ran_discrete(rng_gsl, lookup));\n\t\t\n\t\t// choose a breakpoint anywhere in the chosen recombination interval with equal probability\n\t\t\n\t\t// BCH 4 April 2016: Added +1 to positions in the first interval.  We do not want to generate a recombination breakpoint\n\t\t// to the left of the 0th base, and the code in InitializeDraws() above explicitly omits that position from its calculation\n\t\t// of the overall recombination rate.  Using recombination_end_positions_[recombination_interval] here for the first\n\t\t// interval means that we use one less breakpoint position than usual; conceptually, the previous breakpoint ended at -1,\n\t\t// so it ought to be recombination_end_positions_[recombination_interval]+1, but we do not add one there, in order to\n\t\t// use one fewer positions.  We then shift all the positions to the right one, with the +1 that is added here, thereby\n\t\t// making the position that was omitted be the position to the left of the 0th base.\n\t\t//\n\t\t// I also added +1 in the formula for regions after the 0th.  In general, we want a recombination interval to own all the\n\t\t// positions to the left of its enclosed bases, up to and including the position to the left of the final base given as the\n\t\t// end position of the interval.  The next interval's first owned recombination position is therefore to the left of the\n\t\t// base that is one position to the right of the end of the preceding interval.  So we have to add one to the position\n\t\t// given by recombination_end_positions_[recombination_interval - 1], at minimum.  Since Eidos_rng_interval_uint64() returns\n\t\t// a zero-based random number, that means we need a +1 here as well.\n\t\t//\n\t\t// The key fact here is that a recombination breakpoint position of 1 means \"break to the left of the base at position 1\" –\n\t\t// the breakpoint falls between bases, to the left of the base at the specified number.  This is a consequence of the logic\n\t\t// in the crossover-mutation code, which copies mutations as long as their position is *less than* the position of the next\n\t\t// breakpoint.  When their position is *equal*, the breakpoint gets serviced by switching strands.  That logic causes the\n\t\t// breakpoints to fall to the left of their designated base.\n\t\t//\n\t\t// Note that Eidos_rng_interval_uint64() crashes (well, aborts fatally) if passed 0 for n.  We need to guarantee that that doesn't\n\t\t// happen, and we don't want to waste time checking for that condition here.  For a 1-base model, we are guaranteed that\n\t\t// the overall recombination rate will be zero, by the logic in InitializeDraws(), and so we should not be called in the\n\t\t// first place.  For longer chromosomes that start with a 1-base recombination interval, the rate calculated by\n\t\t// InitializeDraws() for the first interval should be 0, so gsl_ran_discrete() should never return the first interval to\n\t\t// us here.  For all other recombination intervals, the math of pos[x]-pos[x-1] should always result in a value >0,\n\t\t// since we guarantee that recombination end positions are in strictly ascending order.  So we should never crash.  :->\n\t\t\n\t\tif (recombination_interval == 0)\n\t\t\tbreakpoint = static_cast<slim_position_t>(Eidos_rng_interval_uint64(rng_64, (*end_positions)[recombination_interval]) + 1);\n\t\telse\n\t\t\tbreakpoint = (*end_positions)[recombination_interval - 1] + 1 + static_cast<slim_position_t>(Eidos_rng_interval_uint64(rng_64, (*end_positions)[recombination_interval] - (*end_positions)[recombination_interval - 1]));\n\t\t\n\t\tp_crossovers.emplace_back(breakpoint);\n\t}\n\t\n\t// sort and unique\n\tif (p_num_breakpoints > 2)\n\t{\n\t\tstd::sort(p_crossovers.begin(), p_crossovers.end());\n\t\tp_crossovers.erase(std::unique(p_crossovers.begin(), p_crossovers.end()), p_crossovers.end());\n\t}\n\telse if (p_num_breakpoints == 2)\n\t{\n\t\t// do our own dumb inline sort/unique if we have just two elements, to avoid the calls above\n\t\t// I didn't actually test this to confirm that it's faster, but models that generate many\n\t\t// breakpoints will generally hit the case above anyway, and models that generate few will\n\t\t// suffer only the additional (num_breakpoints == 2) test before falling through...\n\t\tslim_position_t bp1 = p_crossovers[0];\n\t\tslim_position_t bp2 = p_crossovers[1];\n\t\t\n\t\tif (bp1 > bp2)\n\t\t\tstd::swap(p_crossovers[0], p_crossovers[1]);\n\t\telse if (bp1 == bp2)\n\t\t\tp_crossovers.resize(1);\n\t}\n}\n\n// draw a set of uniqued breakpoints according to the \"double-stranded break\" model and run them through recombination() callbacks, returning the final usable set\n// the information returned here also includes a list of heteroduplex regions where mismatches between the two parental strands will need to be resolved\nvoid Chromosome::_DrawDSBBreakpoints(IndividualSex p_parent_sex, const int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers, std::vector<slim_position_t> &p_heteroduplex) const\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Chromosome::DrawDSBBreakpoints(): usage of statics, probably many other issues\");\n\t\n\t// BEWARE! Chromosome::DrawCrossoverBreakpoints() above must be altered in parallel with this method!\n#if DEBUG\n\tif (!using_DSB_model_)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawDSBBreakpoints): (internal error) this method should not be called when the crossover breakpoints recombination model is being used.\" << EidosTerminate();\n#endif\n\t\n\tgsl_ran_discrete_t *lookup;\n\tconst std::vector<slim_position_t> *end_positions;\n\tconst std::vector<double> *rates;\n\t\n\tif (single_recombination_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\tlookup = lookup_recombination_H_;\n\t\tend_positions = &recombination_end_positions_H_;\n\t\trates = &recombination_rates_H_;\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_parent_sex == IndividualSex::kMale)\n\t\t{\n\t\t\tlookup = lookup_recombination_M_;\n\t\t\tend_positions = &recombination_end_positions_M_;\n\t\t\trates = &recombination_rates_M_;\n\t\t}\n\t\telse if (p_parent_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\tlookup = lookup_recombination_F_;\n\t\t\tend_positions = &recombination_end_positions_F_;\n\t\t\trates = &recombination_rates_F_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRecombinationMapConfigError();\n\t\t}\n\t}\n\t\n\t// Draw extents and crossover/noncrossover and simple/complex decisions for p_num_breakpoints DSBs; we may not end up using all\n\t// of them, if the uniquing step reduces the set of DSBs, but we don't want to redraw these things if we have to loop back due\n\t// to a collision, because such redrawing would be liable to produce bias towards shorter extents.  (Redrawing the crossover/\n\t// noncrossover and simple/complex decisions would probably be harmless, but it is simpler to just make all decisions up front.)\n\tint try_count = 0;\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tstatic std::vector<std::tuple<slim_position_t, slim_position_t, bool, bool>> dsb_infos;\t// using a static prevents reallocation\n\t\n\t// If the redrawLengthsOnFailure parameter to initializeGeneConversion() is T, we jump back here on layout failure\n\t// Note that we also redraw noncrossover and simple, on this code path; that shouldn't matter since they are independent of layout\ngenerateDSBsRedrawingLengths:\n\t\n\tdsb_infos.resize(0);\n\t\n\tif (gene_conversion_avg_length_ < 2.0)\n\t{\n\t\tfor (int i = 0; i < p_num_breakpoints; i++)\n\t\t{\n\t\t\t// If the gene conversion tract mean length is < 2.0, gsl_ran_geometric() will blow up, and we should treat the tract length as zero\n\t\t\tbool noncrossover = (Eidos_rng_uniform_doubleCO(rng_64) <= non_crossover_fraction_);\t\t\t// tuple position 2\n\t\t\tbool simple = (Eidos_rng_uniform_doubleCO(rng_64) <= simple_conversion_fraction_);\t\t\t// tuple position 3\n\t\t\t\n\t\t\tdsb_infos.emplace_back(0, 0, noncrossover, simple);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int i = 0; i < p_num_breakpoints; i++)\n\t\t{\n\t\t\tslim_position_t extent1 = gsl_ran_geometric(rng_gsl, gene_conversion_inv_half_length_);\t\t// tuple position 0\n\t\t\tslim_position_t extent2 = gsl_ran_geometric(rng_gsl, gene_conversion_inv_half_length_);\t\t// tuple position 1\n\t\t\tbool noncrossover = (Eidos_rng_uniform_doubleCO(rng_64) <= non_crossover_fraction_);\t\t\t// tuple position 2\n\t\t\tbool simple = (Eidos_rng_uniform_doubleCO(rng_64) <= simple_conversion_fraction_);\t\t\t// tuple position 3\n\t\t\t\n\t\t\tdsb_infos.emplace_back(extent1, extent2, noncrossover, simple);\n\t\t}\n\t}\n\t\n\t// If the redrawLengthsOnFailure parameter to initializeGeneConversion() is F, we jump back here on layout failure\ngenerateDSBsWithoutRedrawingLengths:\n\t\n\tif (++try_count > 100)\n\t{\n\t\t// Note this block handles failure for both redraw_lengths_on_failure_ cases\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawDSBBreakpoints): non-overlapping recombination regions could not be achieved in 100 tries; terminating.  The recombination rate and/or mean gene conversion tract length may be too high.\";\n\t\tif (!redraw_lengths_on_failure_)\n\t\t\tEIDOS_TERMINATION << \"  You might wish to pass redrawLengthsOnFailure=T to initializeGeneConversion() to make gene conversion tract layout more robust.\";\n\t\tEIDOS_TERMINATION << EidosTerminate();\n\t}\n\t\n\t// First draw DSB points; dsb_points contains positions and a flag for whether the breakpoint is at a rate=0.5 position\n\tstatic std::vector<std::pair<slim_position_t, bool>> dsb_points;\t// using a static prevents reallocation\n\tdsb_points.resize(0);\n\t\n\tfor (int i = 0; i < p_num_breakpoints; i++)\n\t{\n\t\tslim_position_t breakpoint = 0;\n\t\tint recombination_interval = static_cast<int>(gsl_ran_discrete(rng_gsl, lookup));\n\t\t\n\t\tif (recombination_interval == 0)\n\t\t\tbreakpoint = static_cast<slim_position_t>(Eidos_rng_interval_uint64(rng_64, (*end_positions)[recombination_interval]) + 1);\n\t\telse\n\t\t\tbreakpoint = (*end_positions)[recombination_interval - 1] + 1 + static_cast<slim_position_t>(Eidos_rng_interval_uint64(rng_64, (*end_positions)[recombination_interval] - (*end_positions)[recombination_interval - 1]));\n\t\t\n\t\tif ((*rates)[recombination_interval] == 0.5)\n\t\t\tdsb_points.emplace_back(breakpoint, true);\n\t\telse\n\t\t\tdsb_points.emplace_back(breakpoint, false);\n\t}\n\t\n\t// Sort and unique the resulting DSB vector\n\tif (p_num_breakpoints > 1)\n\t{\n\t\tstd::sort(dsb_points.begin(), dsb_points.end());\t\t// sorts by the first element of the pair\n\t\tdsb_points.erase(std::unique(dsb_points.begin(), dsb_points.end()), dsb_points.end());\n\t}\n\t\n\t// Assemble lists of crossover breakpoints and heteroduplex regions, starting from a clean slate\n\tint final_num_breakpoints = (int)dsb_points.size();\n\tslim_position_t last_position_used = -1;\n\t\n\tp_crossovers.resize(0);\n\tp_heteroduplex.resize(0);\n\t\n\tfor (int i = 0; i < final_num_breakpoints; i++)\n\t{\n\t\tstd::pair<slim_position_t, bool> &dsb_pair = dsb_points[i];\n\t\tstd::tuple<slim_position_t, slim_position_t, bool, bool> &dsb_info = dsb_infos[i];\n\t\tslim_position_t dsb_point = dsb_pair.first;\n\t\t\n\t\tif (dsb_pair.second)\n\t\t{\n\t\t\t// This DSB is at a rate=0.5 point, so we do not generate a gene conversion tract; it just translates directly to a crossover breakpoint\n\t\t\t// Note that we do NOT check non_crossover_fraction_ here; it does not apply to rate=0.5 positions, since they cannot undergo gene conversion\n\t\t\tif (dsb_point <= last_position_used)\n\t\t\t{\n\t\t\t\tif (redraw_lengths_on_failure_)\n\t\t\t\t\tgoto generateDSBsRedrawingLengths;\n\t\t\t\telse\n\t\t\t\t\tgoto generateDSBsWithoutRedrawingLengths;\n\t\t\t}\n\t\t\t\n\t\t\tp_crossovers.emplace_back(dsb_point);\n\t\t\tlast_position_used = dsb_point;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This DSB is not at a rate=0.5 point, so we generate a gene conversion tract around it\n\t\t\tslim_position_t tract_start = dsb_point - std::get<0>(dsb_info);\n\t\t\tslim_position_t tract_end = SLiMClampToPositionType(dsb_point + std::get<1>(dsb_info));\n\t\t\t\n\t\t\t// We do not want to allow GC tracts to extend all the way to the chromosome beginning or end\n\t\t\t// This is partly because biologically it seems weird, and partly because a breakpoint at position 0 breaks tree-seq recording\n\t\t\tif ((tract_start <= 0) || (tract_end > last_position_) || (tract_start <= last_position_used))\n\t\t\t{\n\t\t\t\tif (redraw_lengths_on_failure_)\n\t\t\t\t\tgoto generateDSBsRedrawingLengths;\n\t\t\t\telse\n\t\t\t\t\tgoto generateDSBsWithoutRedrawingLengths;\n\t\t\t}\n\t\t\t\n\t\t\tif (tract_start == tract_end)\n\t\t\t{\n\t\t\t\t// gene conversion tract of zero length, so no tract after all, but we do use non_crossover here\n\t\t\t\tif (!std::get<2>(dsb_info))\n\t\t\t\t\tp_crossovers.emplace_back(tract_start);\n\t\t\t\tlast_position_used = tract_start;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// gene conversion tract of non-zero length, so generate the tract\n\t\t\t\tp_crossovers.emplace_back(tract_start);\n\t\t\t\tif (std::get<2>(dsb_info))\n\t\t\t\t\tp_crossovers.emplace_back(tract_end);\n\t\t\t\tlast_position_used = tract_end;\n\t\t\t\t\n\t\t\t\t// decide if it is a simple or a complex tract\n\t\t\t\tif (!std::get<3>(dsb_info))\n\t\t\t\t{\n\t\t\t\t\t// complex gene conversion tract; we need to save it in the list of heteroduplex regions\n\t\t\t\t\tp_heteroduplex.emplace_back(tract_start);\n\t\t\t\t\tp_heteroduplex.emplace_back(tract_end - 1);\t// heteroduplex positions are base positions, so the last position is to the left of the GC tract end\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// This high-level function is the funnel for drawing breakpoints.  It delegates down to DrawDSBBreakpoints()\n// or DrawCrossoverBreakpoints(), handles recombination() callbacks, and returns a sorted, uniqued vector.\n// You can supply it with a number of breakpoints to draw, or pass -1 to have it draw the number for you.\n// If the caller can handle complex gene conversion tracts, they should pass a vector for those to be placed\n// in.  If not, pass nullptr, and this method will raise if complex gene conversion tracts are in use.  For\n// addRecombinant() and addMultiRecombinant(), this method allows the parent to be different from the\n// haplosomes that are supplied; the parent individual is used to look up the haplosomes if they are passed\n// as nullptr.  The haplosomes are used only if recombination() callbacks are in effect.  The parent\n// is also used to look up the sex, for sex-specific recombination rates.\nvoid Chromosome::DrawBreakpoints(Individual *p_parent, Haplosome *p_haplosome1, Haplosome *p_haplosome2, int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers, std::vector<slim_position_t> *p_heteroduplex, const char *p_caller_name)\n{\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", recombination breakpoints cannot be drawn for a species with no genetics.\" << EidosTerminate();\n\t\n\tif (!p_heteroduplex && using_DSB_model_ && (simple_conversion_fraction_ != 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", complex gene conversion tracts cannot be active since there is no provision for handling heteroduplex regions.\" << EidosTerminate();\n\t\n\t// look up parent information; note that if parent is nullptr, we do not run recombination() callbacks!\n\t// the parent is a required pseudo-parameter for the recombination() callback\n\tIndividualSex parent_sex = IndividualSex::kUnspecified;\n\tstd::vector<SLiMEidosBlock*> recombination_callbacks;\n\tSubpopulation *parent_subpop = nullptr;\n\t\n\tif (p_parent)\n\t{\n\t\tparent_sex = p_parent->sex_;\n\t\tparent_subpop = p_parent->subpopulation_;\n\t\trecombination_callbacks = species_.CallbackBlocksMatching(community_.Tick(), SLiMEidosBlockType::SLiMEidosRecombinationCallback, -1, -1, parent_subpop->subpopulation_id_, id_);\n\t\t\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif (&p_parent->subpopulation_->species_ != &species_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", the parent, if supplied, must belong to the same species as the target chromosome.\" << EidosTerminate();\n\t}\n\telse\t// !p_parent\n\t{\n\t\t// In a sexual model with sex-specific recombination maps, we need to know the parent we're\n\t\t// generating breakpoints for; in other situations it is optional, but recombination()\n\t\t// breakpoints will not be called if parent is NULL.\n\t\tif (!single_recombination_map_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", a parent must be supplied since sex-specific recombination maps are in use (to determine which map to use, from the sex of the parent).\" << EidosTerminate();\n\t}\n\t\n\t// look up haplosome information, used only for the recombination() callback\n\tif ((!p_haplosome1 && p_haplosome2) || (!p_haplosome2 && p_haplosome1))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): (internal error) in \" << p_caller_name << \", haplosomes must either be supplied or not supplied.\" << EidosTerminate();\n\t\n\tif (p_haplosome1)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif ((&p_haplosome1->OwningIndividual()->subpopulation_->species_ != &species_) ||\n\t\t\t(&p_haplosome2->OwningIndividual()->subpopulation_->species_ != &species_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", parental haplosomes must belong to the same species as the target chromosome.\" << EidosTerminate();\n\t\t\n\t\tif ((p_haplosome1->chromosome_index_ != index_) || (p_haplosome2->chromosome_index_ != index_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", parental haplosomes must belong to the target chromosome.\" << EidosTerminate();\n\t\t\n\t\t// Note that if haplosomes were passed in but p_parent is nullptr, we do NOT attempt to infer a parent\n\t\t// subpopulation in order to get recombination() callbacks from it.  In the general case that would\n\t\t// not work, since the two haplosomes might belong to different subpopulations; and if we can't do it\n\t\t// in general, we shouldn't try to do it at all.  If you want recombination() callbacks, pass p_parent.\n\t}\n\telse if (p_parent)\n\t{\n\t\t// Get the indices of the haplosomes associated with this chromosome.  Note that the first/last indices\n\t\t// might be the same, if this is a haploid chromosome.  That is OK here.  The user is allowed to set a\n\t\t// recombination rate on a haploid chromosome and generate breakpoints for it; what they do with that\n\t\t// information is up to them.  (They might use them in an addRecombinant() or addMultiRecombinant() call,\n\t\t// for example.)  In that case, of a haploid chromosome, the same single parent haplosome will be passed\n\t\t// twice to recombination() callbacks; that seems better than not defining one of the pseudo-parameters.\n\t\tint first_haplosome_index = species_.FirstHaplosomeIndices()[index_];\n\t\tint last_haplosome_index = species_.LastHaplosomeIndices()[index_];\n\t\t\n\t\t// Note that for calling recombination() callbacks below, we treat the parent's first haplosome as the\n\t\t// initial copy strand.  If a distinction needs to be made, pass the haplosomes in to this method.\n\t\tp_haplosome1 = p_parent->haplosomes_[first_haplosome_index];\n\t\tp_haplosome2 = p_parent->haplosomes_[last_haplosome_index];\n\t}\n\t\n\t// Draw the number of breakpoints, if it was not supplied\n\tif (p_num_breakpoints == -1)\n\t\tp_num_breakpoints = DrawBreakpointCount(parent_sex);\n\t\n\tif ((p_num_breakpoints < 0) || (p_num_breakpoints > 1000000L))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): in \" << p_caller_name << \", the number of recombination breakpoints must be in [0, 1000000].\" << EidosTerminate();\n\t\n#if DEBUG\n\tif (p_crossovers.size())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): (internal error) in \" << p_caller_name << \", p_crossovers was not supplied empty.\" << EidosTerminate();\n#endif\n\t\n\t// draw the breakpoints based on the recombination rate map, and sort and unique the result\n\tif (p_num_breakpoints)\n\t{\n\t\tif (using_DSB_model_)\n\t\t{\n\t\t\tif (p_heteroduplex)\n\t\t\t{\n\t\t\t\t// p_heteroduplex is not nullptr, so the caller intends to use it for something\n\t\t\t\t_DrawDSBBreakpoints(parent_sex, p_num_breakpoints, p_crossovers, *p_heteroduplex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// p_heteroduplex is nullptr, so we need to pass in our own vector; it is not actually used\n\t\t\t\t// in this case anyway, since simple_conversion_fraction_ must be 1.0 (as checked above)\n\t\t\t\tstd::vector<slim_position_t> heteroduplex;\n\t\t\t\t\n\t\t\t\t_DrawDSBBreakpoints(parent_sex, p_num_breakpoints, p_crossovers, heteroduplex);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_DrawCrossoverBreakpoints(parent_sex, p_num_breakpoints, p_crossovers);\n\t\t}\n\t\t\n\t\t// p_crossovers is sorted and uniqued at this point\n\t\t\n\t\tif (recombination_callbacks.size())\n\t\t{\n\t\t\t// a non-zero number of breakpoints, with recombination callbacks\n\t\t\tbool breaks_changed = species_.population_.ApplyRecombinationCallbacks(p_parent, p_haplosome1, p_haplosome2, p_crossovers, recombination_callbacks);\n\t\t\t\n\t\t\t// we only sort/unique if the breakpoints have changed, since they were sorted/uniqued before\n\t\t\tif (breaks_changed && (p_crossovers.size() > 1))\n\t\t\t{\n\t\t\t\tstd::sort(p_crossovers.begin(), p_crossovers.end());\n\t\t\t\tp_crossovers.erase(unique(p_crossovers.begin(), p_crossovers.end()), p_crossovers.end());\n\t\t\t}\n\t\t}\n\t}\n\telse if (recombination_callbacks.size())\n\t{\n\t\t// zero breakpoints from the SLiM core, but we have recombination() callbacks\n\t\tspecies_.population_.ApplyRecombinationCallbacks(p_parent, p_haplosome1, p_haplosome2, p_crossovers, recombination_callbacks);\n\t\t\n\t\tif (p_crossovers.size() > 1)\n\t\t{\n\t\t\tstd::sort(p_crossovers.begin(), p_crossovers.end());\n\t\t\tp_crossovers.erase(unique(p_crossovers.begin(), p_crossovers.end()), p_crossovers.end());\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no breakpoints, no gene conversion, no recombination() callbacks\n\t}\n\t\n\t// values in p_crossovers and p_heteroduplex are returned to the caller\n\t// p_crossovers is guaranteed to be sorted and uniqued, which we check here\n\t// we also check that no position is less than zero or beyond the chromosome end\n#if DEBUG\n\tslim_position_t previous_value = -1;\n\tslim_position_t last_chrom_position = last_position_;\n\t\n\tfor (slim_position_t value : p_crossovers)\n\t{\n\t\tif (value <= previous_value)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): (internal error) breakpoints vector is not sorted/uniqued.\" << EidosTerminate();\n\t\tif (value > last_chrom_position)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::DrawBreakpoints): (internal error) breakpoints vector goes beyond the chromosome end.\" << EidosTerminate();\n\t\t\n\t\tprevious_value = value;\n\t}\n#endif\n}\n\nsize_t Chromosome::MemoryUsageForMutationMaps(void)\n{\n\tsize_t usage = 0;\n\t\n\tusage = (mutation_rates_H_.size() + mutation_rates_M_.size() + mutation_rates_F_.size()) * sizeof(double);\n\tusage += (mutation_end_positions_H_.size() + mutation_end_positions_M_.size() + mutation_end_positions_F_.size()) * sizeof(slim_position_t);\n\tusage += (mutation_subranges_H_.size() + mutation_subranges_M_.size() + mutation_subranges_F_.size()) * sizeof(GESubrange);\n\tusage += (hotspot_multipliers_H_.size() + hotspot_multipliers_M_.size() + hotspot_multipliers_F_.size()) * sizeof(double);\n\tusage += (hotspot_end_positions_H_.size() + hotspot_end_positions_M_.size() + hotspot_end_positions_F_.size()) * sizeof(slim_position_t);\n\t\n\tif (lookup_mutation_H_)\n\t\tusage += lookup_mutation_H_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_mutation_M_)\n\t\tusage += lookup_mutation_M_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_mutation_F_)\n\t\tusage += lookup_mutation_F_->K * (sizeof(size_t) + sizeof(double));\n\t\n\treturn usage;\n}\n\nsize_t Chromosome::MemoryUsageForRecombinationMaps(void)\n{\n\tsize_t usage = 0;\n\t\n\tusage = (recombination_rates_H_.size() + recombination_rates_M_.size() + recombination_rates_F_.size()) * sizeof(double);\n\tusage += (recombination_end_positions_H_.size() + recombination_end_positions_M_.size() + recombination_end_positions_F_.size()) * sizeof(slim_position_t);\n\t\n\tif (lookup_recombination_H_)\n\t\tusage += lookup_recombination_H_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_recombination_M_)\n\t\tusage += lookup_recombination_M_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_recombination_F_)\n\t\tusage += lookup_recombination_F_->K * (sizeof(size_t) + sizeof(double));\n\t\n\treturn usage;\n}\n\nsize_t Chromosome::MemoryUsageForAncestralSequence(void)\n{\n\tsize_t usage = 0;\n\t\n\tif (ancestral_seq_buffer_)\n\t{\n\t\tstd::size_t length = ancestral_seq_buffer_->size();\n\t\t\n\t\tusage += ((length + 31) / 32) * sizeof(uint64_t);\n\t}\n\t\n\treturn usage;\n}\n\nvoid Chromosome::SetUpMutationRunContexts(void)\n{\n\t// Make an EidosObjectPool to allocate mutation runs from; this is for memory locality, so make it nice and big\n#ifndef _OPENMP\n\tmutation_run_context_SINGLE_.allocation_pool_ = new EidosObjectPool(\"EidosObjectPool(MutationRun)\", sizeof(MutationRun), 65536);\n#else\n\t//std::cout << \"***** Initializing \" << gEidosMaxThreads << \" independent MutationRunContexts\" << std::endl;\n\t\n\t// Make per-thread MutationRunContexts; the number of threads that we set up for here is NOT gEidosMaxThreads,\n\t// but rather, the \"base\" number of mutation runs per haplosome chosen by Chromosome.  The chromosome is divided\n\t// into that many chunks along its length (or a multiple thereof), and there is one thread per \"base\" chunk.\n\tmutation_run_context_COUNT_ = mutrun_count_base_;\n\tmutation_run_context_PERTHREAD.resize(mutation_run_context_COUNT_);\n\t\n\tif (mutation_run_context_COUNT_ > 0)\n\t{\n\t\t// Check that each RNG was initialized by a different thread, as intended below;\n\t\t// this is not required, but it improves memory locality throughout the run\n\t\tbool threadObserved[mutation_run_context_COUNT_];\n\t\t\n#pragma omp parallel default(none) shared(mutation_run_context_PERTHREAD, threadObserved) num_threads(mutation_run_context_COUNT_)\n\t\t{\n\t\t\t// Each thread allocates and initializes its own MutationRunContext, for \"first touch\" optimization\n\t\t\tint threadnum = omp_get_thread_num();\n\t\t\t\n\t\t\tmutation_run_context_PERTHREAD[threadnum] = new MutationRunContext();\n\t\t\tmutation_run_context_PERTHREAD[threadnum]->allocation_pool_ = new EidosObjectPool(\"EidosObjectPool(MutationRun)\", sizeof(MutationRun), 65536);\n\t\t\tomp_init_lock(&mutation_run_context_PERTHREAD[threadnum]->allocation_pool_lock_);\n\t\t\tthreadObserved[threadnum] = true;\n\t\t}\t// end omp parallel\n\t\t\n\t\tfor (int threadnum = 0; threadnum < mutation_run_context_COUNT_; ++threadnum)\n\t\t\tif (!threadObserved[threadnum])\n\t\t\t\tstd::cerr << \"WARNING: parallel MutationRunContexts were not correctly initialized on their corresponding threads; this may cause slower simulation.\" << std::endl;\n\t}\n#endif\t// end _OPENMP\n}\n\n// These get called if a null haplosome is requested but the null junkyard is empty, or if a non-null haplosome is requested\n// but the non-null junkyard is empty; so we know that the primary junkyard for the request cannot service the request.\n// If the other junkyard has a haplosome, we want to repurpose it; this prevents one junkyard from filling up with an\n// ever-growing number of haplosomes while requests to the other junkyard create new haplosomes (which can happen because\n// haplosomes can be transmogrified between null and non-null after creation).  We create a new haplosome only if both\n// junkyards are empty.\n\nHaplosome *Chromosome::_NewHaplosome_NULL(Individual *p_individual)\n{\n\t// this does not set chromosome_subposition_; use NewHaplosome_NULL()\n\tif (haplosomes_junkyard_nonnull.size())\n\t{\n\t\tHaplosome *back = haplosomes_junkyard_nonnull.back();\n\t\thaplosomes_junkyard_nonnull.pop_back();\n\t\t\n\t\t// got a non-null haplosome, need to repurpose it to be a null haplosome\n\t\tback->ReinitializeHaplosomeToNull(p_individual);\n\t\t\n\t\treturn back;\n\t}\n\t\n\treturn new (haplosome_pool_.AllocateChunk()) Haplosome(Haplosome::NullHaplosome{}, p_individual, this);\n}\n\nHaplosome *Chromosome::_NewHaplosome_NONNULL(Individual *p_individual)\n{\n\t// this does not set chromosome_subposition_; use NewHaplosome_NONNULL()\n\tif (haplosomes_junkyard_null.size())\n\t{\n\t\tHaplosome *back = haplosomes_junkyard_null.back();\n\t\thaplosomes_junkyard_null.pop_back();\n\t\t\n\t\t// got a null haplosome, need to repurpose it to be a non-null haplosome cleared to nullptr\n\t\tback->ReinitializeHaplosomeToNonNull(p_individual, this);\n\t\t\n\t\treturn back;\n\t}\n\t\n\treturn new (haplosome_pool_.AllocateChunk()) Haplosome(Haplosome::NonNullHaplosome{}, p_individual, this);\n}\n\n\n\n//\n// Mutation run experiments\n//\n#pragma mark -\n#pragma mark Mutation run experiments\n#pragma mark -\n\nvoid Chromosome::InitiateMutationRunExperiments(void)\n{\n\tif (preferred_mutrun_count_ != 0)\n\t{\n\t\t// If the user supplied a count, go with that and don't run experiments\n\t\tx_experiments_enabled_ = false;\n\t\t\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// Mutation run experiments disabled since a mutation run count was supplied\" << std::endl;\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\tif (mutrun_length_ <= SLIM_MUTRUN_MAXIMUM_COUNT)\n\t{\n\t\t// If the chromosome length is too short, go with that and don't run experiments;\n\t\t// we want to guarantee that with SLIM_MUTRUN_MAXIMUM_COUNT runs each mutrun is at\n\t\t// least one mutation in length, so the code doesn't break down\n\t\tx_experiments_enabled_ = false;\n\t\t\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// Mutation run experiments disabled since the chromosome is very short\" << std::endl;\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\t\n\tx_experiments_enabled_ = true;\n\tspecies_.DoingMutrunExperimentsForChromosome();\n\t\n\tx_experiment_count_ = 0;\n\t\n\tx_current_mutcount_ = mutrun_count_;\n\tx_current_runtimes_ = (double *)malloc(SLIM_MUTRUN_EXPERIMENT_LENGTH * sizeof(double));\n\tx_current_buflen_ = 0;\n\t\n\tx_previous_mutcount_ = 0;\t\t\t// marks that no previous experiment has been done\n\tx_previous_runtimes_ = (double *)malloc(SLIM_MUTRUN_EXPERIMENT_LENGTH * sizeof(double));\n\tx_previous_buflen_ = 0;\n\t\n\tif (!x_current_runtimes_ || !x_previous_runtimes_)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::InitiateMutationRunExperiments): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tx_continuing_trend_ = false;\n\t\n\tx_stasis_limit_ = 5;\t\t\t\t// once we reach stasis, we will conduct 5 stasis experiments before exploring again\n\tx_stasis_alpha_ = 0.01;\t\t\t\t// initially, we use an alpha of 0.01 to break out of stasis due to a change in mean\n\tx_stasis_counter_ = 0;\n\tx_prev1_stasis_mutcount_ = 0;\t\t// we have never reached stasis before, so we have no memory of it\n\tx_prev2_stasis_mutcount_ = 0;\t\t// we have never reached stasis before, so we have no memory of it\n\t\n\tif (SLiM_verbosity_level >= 2)\n\t{\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\tSLIM_OUTSTREAM << \"// Mutation run experiments started\" << std::endl;\n\t}\n}\n\nvoid Chromosome::ZeroMutationRunExperimentClock(void)\n{\n\tif (x_experiments_enabled_)\n\t{\n\t\tif (x_within_measurement_period_)\n\t\t\tstd::cerr << \"WARNING: ZeroMutationRunExperimentClock() called when the measurement period is already begun!\" << std::endl;\n\t\t\n\t\tif (x_total_gen_clocks_ != 0)\n\t\t{\n\t\t\t// Clocks should only get logged in the interval within which they are used; if there are leftover counts\n\t\t\t// at this point, somebody is logging counts that are not getting used in the total.  Warn once.\n\t\t\tif (!community_.warned_experiment_run_clocks_)\n\t\t\t{\n\t\t\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Chromosome::PrepareForCycle(): usage of statics\");\n\t\t\t\t\n\t\t\t\tstd::cerr << \"WARNING: mutation run experiment clocks were logged outside of the measurement interval!\" << std::endl;\n\t\t\t\tcommunity_.warned_experiment_run_clocks_ = true;\n\t\t\t}\n\t\t\t\n\t\t\tx_total_gen_clocks_ = 0;\n\t\t}\n\t\t\n\t\tx_within_measurement_period_ = true;\n\t\t\n#if MUTRUN_EXPERIMENT_TIMING_OUTPUT\n\t\tstd::cout << \"tick \" << community_.Tick() << \", chromosome \" << id_ << \": starting timing\" << std::endl;\n#endif\n\t}\n}\n\nvoid Chromosome::FinishMutationRunExperimentTiming(void)\n{\n\tif (x_experiments_enabled_)\n\t{\n\t\tif (!x_within_measurement_period_)\n\t\t\tstd::cerr << \"WARNING: FinishMutationRunExperimentTiming() called when the measurement period has not begun!\" << std::endl;\n\t\t\n#if MUTRUN_EXPERIMENT_TIMING_OUTPUT\n\t\tstd::cout << \"tick \" << community_.Tick() << \", chromosome \" << id_ << \": ending timing with total count == \" << x_total_gen_clocks_ << \" (\" << Eidos_ElapsedProfileTime(x_total_gen_clocks_) << \" seconds)\" << std::endl;\n#endif\n\t\t\n\t\t// We only run mutrun experiments in ticks when our species in active; when inactive, any\n\t\t// clocks accumulated will simply be discarded unused, since they are not representative\n\t\tif (species_.Active())\n\t\t\tMaintainMutationRunExperiments(Eidos_ElapsedProfileTime(x_total_gen_clocks_));\n\t\t\n\t\tx_total_gen_clocks_ = 0;\n\t\tx_within_measurement_period_ = false;\n\t}\n}\n\nvoid Chromosome::TransitionToNewExperimentAgainstCurrentExperiment(int32_t p_new_mutrun_count)\n{\n\t// Save off the old experiment\n\tx_previous_mutcount_ = x_current_mutcount_;\n\tstd::swap(x_current_runtimes_, x_previous_runtimes_);\n\tx_previous_buflen_ = x_current_buflen_;\n\t\n\t// Set up the next experiment\n\tx_current_mutcount_ = p_new_mutrun_count;\n\tx_current_buflen_ = 0;\n}\n\nvoid Chromosome::TransitionToNewExperimentAgainstPreviousExperiment(int32_t p_new_mutrun_count)\n{\n\t// Set up the next experiment\n\tx_current_mutcount_ = p_new_mutrun_count;\n\tx_current_buflen_ = 0;\n}\n\nvoid Chromosome::EnterStasisForMutationRunExperiments(void)\n{\n\tif ((x_current_mutcount_ == x_prev1_stasis_mutcount_) || (x_current_mutcount_ == x_prev2_stasis_mutcount_))\n\t{\n\t\t// One of our recent trips to stasis was at the same count, so we broke stasis incorrectly; get stricter.\n\t\t// The purpose for keeping two previous counts is to detect when we are ping-ponging between two values\n\t\t// that produce virtually identical performance; we want to detect that and just settle on one of them.\n\t\tx_stasis_alpha_ *= 0.5;\n\t\tx_stasis_limit_ *= 2;\n\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t\tSLIM_OUTSTREAM << \"// Remembered previous stasis at \" << x_current_mutcount_ << \", strengthening stasis criteria\" << std::endl;\n#endif\n\t}\n\telse\n\t{\n\t\t// Our previous trips to stasis were at a different number of mutation runs, so reset our stasis parameters\n\t\tx_stasis_limit_ = 5;\n\t\tx_stasis_alpha_ = 0.01;\n\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t\tSLIM_OUTSTREAM << \"// No memory of previous stasis at \" << x_current_mutcount_ << \", resetting stasis criteria\" << std::endl;\n#endif\n\t}\n\t\n\tx_stasis_counter_ = 1;\n\tx_continuing_trend_ = false;\n\t\n\t// Preserve a memory of the last two *different* mutcounts we entered stasis on.  Only forget the old value\n\t// in x_prev2_stasis_mutcount_ if x_prev1_stasis_mutcount_ is about to get a new and different value.\n\t// This makes the anti-ping-pong mechanism described above effective even if we ping-pong irregularly.\n\tif (x_prev1_stasis_mutcount_ != x_current_mutcount_)\n\t\tx_prev2_stasis_mutcount_ = x_prev1_stasis_mutcount_;\n\tx_prev1_stasis_mutcount_ = x_current_mutcount_;\n\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\tif (SLiM_verbosity_level >= 2)\n\t\tSLIM_OUTSTREAM << \"// ****** ENTERING STASIS AT \" << x_current_mutcount_ << \" : x_stasis_limit_ = \" << x_stasis_limit_ << \", x_stasis_alpha_ = \" << x_stasis_alpha_ << std::endl;\n#endif\n}\n\nvoid Chromosome::MaintainMutationRunExperiments(double p_last_gen_runtime)\n{\n\t// Log the last cycle time into our buffer\n\tif (x_current_buflen_ >= SLIM_MUTRUN_EXPERIMENT_LENGTH)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::MaintainMutationRunExperiments): Buffer overrun, failure to reset after completion of an experiment.\" << EidosTerminate();\n\t\n\tx_current_runtimes_[x_current_buflen_] = p_last_gen_runtime;\n\t\n\t// Remember the history of the mutation run count\n\tx_mutcount_history_.emplace_back(x_current_mutcount_);\n\t\n\t// If the current experiment is not over, continue running it\n\t++x_current_buflen_;\n\t\n\tdouble current_mean = 0.0, previous_mean = 0.0, p = 0.0;\n\t\n\tif ((x_current_buflen_ == 10) && (x_current_mutcount_ != x_previous_mutcount_) && (x_previous_mutcount_ != 0))\n\t{\n\t\t// We want to be able to cut an experiment short if it is clearly a disaster.  So if we're not in stasis, and\n\t\t// we've run for 10 cycles, and the experiment mean is already different from the baseline at alpha 0.01,\n\t\t// and the experiment mean is worse than the baseline mean (if it is better, we want to continue collecting),\n\t\t// let's short-circuit the rest of the experiment and bail – like early termination of a medical trial.\n\t\tp = Eidos_TTest_TwoSampleWelch(x_current_runtimes_, x_current_buflen_, x_previous_runtimes_, x_previous_buflen_, &current_mean, &previous_mean);\n\t\tx_experiment_count_++;\n\t\t\n\t\tif ((p < 0.01) && (current_mean > previous_mean))\n\t\t{\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\t\tSLIM_OUTSTREAM << \"// \" << cycle_ << \" : Early t-test yielded HIGHLY SIGNIFICANT p of \" << p << \" with negative results; terminating early.\" << std::endl;\n\t\t\t}\n#endif\n\t\t\t\n\t\t\tgoto early_ttest_passed;\n\t\t}\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\telse if (SLiM_verbosity_level >= 2)\n\t\t{\n\t\t\tif (p >= 0.01)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\t\tSLIM_OUTSTREAM << \"// \" << cycle_ << \" : Early t-test yielded not highly significant p of \" << p << \"; continuing.\" << std::endl;\n\t\t\t}\n\t\t\telse if (current_mean > previous_mean)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\t\tSLIM_OUTSTREAM << \"// \" << cycle_ << \" : Early t-test yielded highly significant p of \" << p << \" with positive results; continuing data collection.\" << std::endl;\n\t\t\t}\n\t\t}\n#endif\n\t}\n\t\n\tif (x_current_buflen_ < SLIM_MUTRUN_EXPERIMENT_LENGTH)\n\t\treturn;\n\t\n\tif (x_previous_mutcount_ == 0)\n\t{\n\t\t// FINISHED OUR FIRST EXPERIMENT; move on to the next experiment, which is always double the number of mutruns\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : First mutation run experiment completed with mutrun count \" << x_current_mutcount_ << \"; will now try \" << (x_current_mutcount_ * 2) << std::endl;\n\t\t}\n#endif\n\t\t\n\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_ * 2);\n\t}\n\telse\n\t{\n\t\t// If we've just finished the second stasis experiment, run another stasis experiment before trying to draw any\n\t\t// conclusions.  We often enter stasis with one cycle's worth of data that was actually collected quite a\n\t\t// while ago, because we did exploration in both directions first.  This can lead to breaking out of stasis\n\t\t// immediately after entering, because we're comparing apples and oranges.  So we avoid doing that here.\n\t\tif ((x_stasis_counter_ <= 1) && (x_current_mutcount_ == x_previous_mutcount_))\n\t\t{\n\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_);\n\t\t\t++x_stasis_counter_;\n\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\t\tSLIM_OUTSTREAM << \"// \" << cycle_ << \" : Mutation run experiment completed (second stasis cycle, no tests conducted)\" << std::endl;\n\t\t\t}\n#endif\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// Otherwise, get a result from a t-test and decide what to do\n\t\tp = Eidos_TTest_TwoSampleWelch(x_current_runtimes_, x_current_buflen_, x_previous_runtimes_, x_previous_buflen_, &current_mean, &previous_mean);\n\t\tx_experiment_count_++;\n\t\t\n\tearly_ttest_passed:\n\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\tif (SLiM_verbosity_level >= 2)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// \" << cycle_ << \" : Mutation run experiment completed:\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//    mean == \" << current_mean << \" for \" << x_current_mutcount_ << \" mutruns (\" << x_current_buflen_ << \" data points)\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//    mean == \" << previous_mean << \" for \" << x_previous_mutcount_ << \" mutruns (\" << x_previous_buflen_ << \" data points)\" << std::endl;\n\t\t}\n#endif\n\t\t\n\t\tif (x_current_mutcount_ == x_previous_mutcount_)\t// are we in stasis?\n\t\t{\n\t\t\t//\n\t\t\t// FINISHED A STASIS EXPERIMENT; unless we have changed at alpha = 0.01 we stay put\n\t\t\t//\n\t\t\tbool means_different_stasis = (p < x_stasis_alpha_);\n\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << \"//    p == \" << p << \" : \" << (means_different_stasis ? \"SIGNIFICANT DIFFERENCE\" : \"no significant difference\") << \" at stasis alpha \" << x_stasis_alpha_ << std::endl;\n#endif\n\t\t\t\n\t\t\tif (means_different_stasis)\n\t\t\t{\n\t\t\t\t// OK, it looks like something has changed about our scenario, so we should come out of stasis and re-test.\n\t\t\t\t// We don't have any information about the new state of affairs, so we have no directional preference.\n\t\t\t\t// Let's try a larger number of mutation runs first, since haplosomes tend to fill up, unless we're at the max.\n\t\t\t\tif (x_current_mutcount_ * 2 > SLIM_MUTRUN_MAXIMUM_COUNT)\n\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_ / 2);\n\t\t\t\telse\n\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_ * 2);\n\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : Stasis mean changed, EXITING STASIS and trying new mutcount of \" << x_current_mutcount_ << std::endl;\n#endif\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We seem to be in a constant scenario.  Increment our stasis counter and see if we have reached our stasis limit\n\t\t\t\tif (++x_stasis_counter_ >= x_stasis_limit_)\n\t\t\t\t{\n\t\t\t\t\t// We reached the stasis limit, so we will try an experiment even though we don't seem to have changed;\n\t\t\t\t\t// as before, we try more mutation runs first, since increasing genetic complexity is typical\n\t\t\t\t\tif (x_current_mutcount_ * 2 > SLIM_MUTRUN_MAXIMUM_COUNT)\n\t\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_ / 2);\n\t\t\t\t\telse\n\t\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_ * 2);\n\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : Stasis limit reached, EXITING STASIS and trying new mutcount of \" << x_current_mutcount_ << std::endl;\n#endif\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We have not yet reached the stasis limit, so run another stasis experiment.\n\t\t\t\t\t// In this case we don't do a transition; we want to continue comparing against the original experiment\n\t\t\t\t\t// data so that if stasis slowly drift away from us, we eventually detect that as a change in stasis.\n\t\t\t\t\tx_current_buflen_ = 0;\n\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\tSLIM_OUTSTREAM << \"//    \" << cycle_ << \" : Stasis limit not reached (\" << x_stasis_counter_ << \" of \" << x_stasis_limit_ << \"), running another stasis experiment at \" << x_current_mutcount_ << std::endl;\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//\n\t\t\t// FINISHED A NON-STASIS EXPERIMENT; trying a move toward more/fewer mutruns\n\t\t\t//\n\t\t\tdouble alpha = 0.05;\n\t\t\tbool means_different_05 = (p < alpha);\n\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << \"//    p == \" << p << \" : \" << (means_different_05 ? \"SIGNIFICANT DIFFERENCE\" : \"no significant difference\") << \" at alpha \" << alpha << std::endl;\n#endif\n\t\t\t\n\t\t\tint32_t trend_next = (x_current_mutcount_ < x_previous_mutcount_) ? (x_current_mutcount_ / 2) : (x_current_mutcount_ * 2);\n\t\t\tint32_t trend_limit = (x_current_mutcount_ < x_previous_mutcount_) ? mutrun_count_base_ : SLIM_MUTRUN_MAXIMUM_COUNT;\t// for single-threaded, mutrun_count_base_ == 1\n\t\t\t\n\t\t\tif ((current_mean < previous_mean) || (!means_different_05 && (x_current_mutcount_ < x_previous_mutcount_)))\n\t\t\t{\n\t\t\t\t// We enter this case under two different conditions.  The first is that the new mean is better\n\t\t\t\t// than the old mean; whether that is significant or not, we want to continue in the same direction\n\t\t\t\t// with a new experiment, which is what we do here.  The other case is if the new mean is worse\n\t\t\t\t// than the old mean, but the difference is non-significant *and* we're trending toward fewer\n\t\t\t\t// mutation runs.  We treat that the same way: continue with a new experiment in the same direction.\n\t\t\t\t// But if the new mean is worse that the old mean and we're trending toward more mutation runs,\n\t\t\t\t// we do NOT follow this case, because an inconclusive but negative increasing trend pushes up our\n\t\t\t\t// peak memory usage and can be quite inefficient, and usually we just jump back down anyway.\n\t\t\t\t// BCH 8/14/2023: The if() below is intended to diagnose if trend_next will go beyond trend_limit,\n\t\t\t\t// and is thus not a legal move.  Just testing (x_current_mutcount_ == trend_limit) used to suffice,\n\t\t\t\t// because the base count was always a power of 2.  Now that is no longer true, and so we can, e.g.,\n\t\t\t\t// be at 768 and thinking about doubling to 1536.  We test for going beyond SLIM_MUTRUN_MAXIMUM_COUNT\n\t\t\t\t// explicitly now, to address that case.  Going too low is still effectively prevented, since we\n\t\t\t\t// will always reach the base count exactly before going below it.\n\t\t\t\tif ((x_current_mutcount_ == trend_limit) || (trend_next > SLIM_MUTRUN_MAXIMUM_COUNT))\n\t\t\t\t{\n\t\t\t\t\tif (current_mean < previous_mean)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Can't go beyond the trend limit (1 or SLIM_MUTRUN_MAXIMUM_COUNT), so we're done; ****** ENTER STASIS\n\t\t\t\t\t\t// We keep the current experiment as the first stasis experiment.\n\t\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(x_current_mutcount_);\n\t\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ****** \" << cycle_ << \" : Experiment \" << (means_different_05 ? \"successful\" : \"inconclusive but positive\") << \" at \" << x_previous_mutcount_ << \", nowhere left to go; entering stasis at \" << x_current_mutcount_ << \".\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tEnterStasisForMutationRunExperiments();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The means are not significantly different, and the current experiment is worse than the\n\t\t\t\t\t\t// previous one, and we can't go beyond the trend limit, so we're done; ****** ENTER STASIS\n\t\t\t\t\t\t// We keep the previous experiment as the first stasis experiment.\n\t\t\t\t\t\tTransitionToNewExperimentAgainstPreviousExperiment(x_previous_mutcount_);\n\t\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ****** \" << cycle_ << \" : Experiment \" << (means_different_05 ? \"failed\" : \"inconclusive but negative\") << \" at \" << x_previous_mutcount_ << \", nowhere left to go; entering stasis at \" << x_current_mutcount_ << \".\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tEnterStasisForMutationRunExperiments();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (current_mean < previous_mean)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Even if the difference is not significant, we appear to be moving in a beneficial direction,\n\t\t\t\t\t\t// so we will run the next experiment against the current experiment's results\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : Experiment \" << (means_different_05 ? \"successful\" : \"inconclusive but positive\") << \" at \" << x_current_mutcount_ << \" (against \" << x_previous_mutcount_ << \"), continuing trend with \" << trend_next << \" (against \" << x_current_mutcount_ << \")\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tTransitionToNewExperimentAgainstCurrentExperiment(trend_next);\n\t\t\t\t\t\tx_continuing_trend_ = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The difference is not significant, but we might be moving in a bad direction, and a series\n\t\t\t\t\t\t// of such moves, each non-significant against the previous experiment, can lead us way down\n\t\t\t\t\t\t// the garden path.  To make sure that doesn't happen, we run successive inconclusive experiments\n\t\t\t\t\t\t// against whichever preceding experiment had the lowest mean.\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : Experiment inconclusive but negative at \" << x_current_mutcount_ << \" (against \" << x_previous_mutcount_ << \"), checking \" << trend_next << \" (against \" << x_previous_mutcount_ << \")\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tTransitionToNewExperimentAgainstPreviousExperiment(trend_next);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The old mean was better, and either the difference is significant or the trend is toward more mutation\n\t\t\t\t// runs, so we want to give up on this trend and go back\n\t\t\t\tif (x_continuing_trend_)\n\t\t\t\t{\n\t\t\t\t\t// We already tried a step on the opposite side of the old position, so the old position appears ideal; ****** ENTER STASIS.\n\t\t\t\t\t// We throw away the current, failed experiment and keep the last experiment at the previous position as the first stasis experiment.\n\t\t\t\t\tTransitionToNewExperimentAgainstPreviousExperiment(x_previous_mutcount_);\n\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ****** \" << cycle_ << \" : Experiment failed, already tried opposite side, so \" << x_current_mutcount_ << \" appears optimal; entering stasis at \" << x_current_mutcount_ << \".\" << std::endl;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tEnterStasisForMutationRunExperiments();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We have not tried a step on the opposite side of the old position; let's return to our old position,\n\t\t\t\t\t// which we know is better than the position we just ran an experiment at, and then advance onward to\n\t\t\t\t\t// run an experiment at the next position in that reversed trend direction.\n\t\t\t\t\tint32_t new_mutcount = ((x_current_mutcount_ > x_previous_mutcount_) ? (x_previous_mutcount_ / 2) : (x_previous_mutcount_ * 2));\n\t\t\t\t\t\n\t\t\t\t\tif ((x_previous_mutcount_ == mutrun_count_base_) || (x_previous_mutcount_ == SLIM_MUTRUN_MAXIMUM_COUNT) ||\n\t\t\t\t\t\t(new_mutcount < mutrun_count_base_) || (new_mutcount > SLIM_MUTRUN_MAXIMUM_COUNT))\n\t\t\t\t\t{\n\t\t\t\t\t\t// can't jump over the previous mutcount, so we enter stasis at it\n\t\t\t\t\t\tTransitionToNewExperimentAgainstPreviousExperiment(x_previous_mutcount_);\n\t\t\t\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ****** \" << cycle_ << \" : Experiment failed, opposite side blocked so \" << x_current_mutcount_ << \" appears optimal; entering stasis at \" << x_current_mutcount_ << \".\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tEnterStasisForMutationRunExperiments();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\t\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\t\t\t\tSLIM_OUTSTREAM << \"// ** \" << cycle_ << \" : Experiment failed at \" << x_current_mutcount_ << \", opposite side untried, reversing trend back to \" << new_mutcount << \" (against \" << x_previous_mutcount_ << \")\" << std::endl;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tTransitionToNewExperimentAgainstPreviousExperiment(new_mutcount);\n\t\t\t\t\t\tx_continuing_trend_ = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Promulgate the new mutation run count\n\tif (x_current_mutcount_ != mutrun_count_)\n\t{\n\t\t// Fix all haplosomes.  We could do this by brute force, by making completely new mutation runs for every\n\t\t// existing haplosome and then calling Population::UniqueMutationRuns(), but that would be inefficient,\n\t\t// and would also cause a huge memory usage spike.  Instead, we want to preserve existing redundancy.\n\t\t\n\t\twhile (x_current_mutcount_ > mutrun_count_)\n\t\t{\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tstd::clock_t start_clock = std::clock();\n#endif\n\t\t\t\n\t\t\tif (x_current_mutcount_ > SLIM_MUTRUN_MAXIMUM_COUNT)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::MaintainMutationRunExperiments): (internal error) splitting mutation runs to beyond SLIM_MUTRUN_MAXIMUM_COUNT (x_current_mutcount_ == \" << x_current_mutcount_ << \").\" << EidosTerminate();\n\t\t\t\n\t\t\t// We are splitting existing runs in two, so make a map from old mutrun index to new pair of\n\t\t\t// mutrun indices; every time we encounter the same old index we will substitute the same pair.\n\t\t\tspecies_.population_.SplitMutationRunsForChromosome(mutrun_count_ * 2, this);\n\t\t\t\n\t\t\t// Fix the chromosome values\n\t\t\tmutrun_count_multiplier_ *= 2;\n\t\t\tmutrun_count_ *= 2;\n\t\t\tmutrun_length_ /= 2;\n\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << \"// ++ Splitting to achieve new mutation run count of \" << mutrun_count_ << \" took \" << ((std::clock() - start_clock) / (double)CLOCKS_PER_SEC) << \" seconds\" << std::endl;\n#endif\n\t\t\t\n#if DEBUG\n\t\tcommunity_.AllSpecies_CheckIntegrity();\n#endif\n\t\t}\n\t\t\n\t\twhile (x_current_mutcount_ < mutrun_count_)\n\t\t{\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tstd::clock_t start_clock = std::clock();\n#endif\n\t\t\t\n\t\t\tif (mutrun_count_multiplier_ % 2 != 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::MaintainMutationRunExperiments): (internal error) joining mutation runs to beyond mutrun_count_base_ (mutrun_count_base_ == \" << mutrun_count_base_ << \", x_current_mutcount_ == \" << x_current_mutcount_ << \").\" << EidosTerminate();\n\t\t\t\n\t\t\t// We are joining existing runs together, so make a map from old mutrun index pairs to a new\n\t\t\t// index; every time we encounter the same pair of indices we will substitute the same index.\n\t\t\tspecies_.population_.JoinMutationRunsForChromosome(mutrun_count_ / 2, this);\n\t\t\t\n\t\t\t// Fix the chromosome values\n\t\t\tmutrun_count_multiplier_ /= 2;\n\t\t\tmutrun_count_ /= 2;\n\t\t\tmutrun_length_ *= 2;\n\t\t\t\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t\t\tif (SLiM_verbosity_level >= 2)\n\t\t\t\tSLIM_OUTSTREAM << \"// ++ Joining to achieve new mutation run count of \" << mutrun_count_ << \" took \" << ((std::clock() - start_clock) / (double)CLOCKS_PER_SEC) << \" seconds\" << std::endl;\n#endif\n\t\t}\n\t\t\n\t\tif (mutrun_count_ != x_current_mutcount_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::MaintainMutationRunExperiments): Failed to transition to new mutation run count\" << x_current_mutcount_ << \".\" << EidosTerminate();\n\t\t\n#if DEBUG\n\t\tcommunity_.AllSpecies_CheckIntegrity();\n#endif\n\t}\n}\n\nvoid Chromosome::PrintMutationRunExperimentSummary(void)\n{\n#if MUTRUN_EXPERIMENT_OUTPUT\n\t// Print a full mutation run count history if MUTRUN_EXPERIMENT_OUTPUT is enabled\n\tif (x_experiments_enabled_)\n\t{\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\tSLIM_OUTSTREAM << \"// Chromosome \" << id_ << \" mutrun count history:\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"// mutrun_history <- c(\";\n\t\t\n\t\tbool first_count = true;\n\t\t\n\t\tfor (int32_t count : x_mutcount_history_)\n\t\t{\n\t\t\tif (first_count)\n\t\t\t\tfirst_count = false;\n\t\t\telse\n\t\t\t\tSLIM_OUTSTREAM << \", \";\n\t\t\t\n\t\t\tSLIM_OUTSTREAM << count;\n\t\t}\n\t\t\n\t\tSLIM_OUTSTREAM << \")\" << std::endl << std::endl;\n\t}\n#endif\n\t\n\t// If verbose output is enabled and we've been running mutation run experiments,\n\t// figure out the modal mutation run count and print that, for the user's benefit.\n\tif (x_experiments_enabled_)\n\t{\n\t\tint modal_index, modal_tally;\n\t\tint power_tallies[20];\t// we only go up to 1024 mutruns right now, but this gives us some headroom\n\t\t\n\t\tfor (int i = 0; i < 20; ++i)\t\t// NOLINT(*-loop-convert) : parallel to the loop below\n\t\t\tpower_tallies[i] = 0;\n\t\t\n\t\tfor (int32_t count : x_mutcount_history_)\n\t\t{\n\t\t\tint32_t power = (int32_t)round(log2(count));\n\t\t\t\n\t\t\tpower_tallies[power]++;\n\t\t}\n\t\t\n\t\tmodal_index = -1;\n\t\tmodal_tally = -1;\n\t\t\n\t\tfor (int i = 0; i < 20; ++i)\n\t\t\tif (power_tallies[i] > modal_tally)\n\t\t\t{\n\t\t\t\tmodal_tally = power_tallies[i];\n\t\t\t\tmodal_index = i;\n\t\t\t}\n\t\t\n\t\tint modal_count = (int)round(pow(2.0, modal_index));\n\t\tdouble modal_fraction = power_tallies[modal_index] / (double)(x_mutcount_history_.size());\n\t\t\n\t\tSLIM_OUTSTREAM << \"// Chromosome \" << id_ << \": \" << modal_count << \" (\" << (modal_fraction * 100) << \"% of cycles, \" << x_experiment_count_ << \" experiments)\" << std::endl;\n\t}\n}\n\n\n//\n// Eidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\n// These are private helper methods that error if we are still in initialize() callbacks\n// Most properties and all methods on Chromosome should be protected by these calls to prevent bugs\nvoid Chromosome::CheckPartialInitializationForProperty(EidosGlobalStringID p_property_id)\n{\n\tif (community_.Tick() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CheckPartialInitializationForProperty): Chromosome property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" cannot be accessed until initialize() callbacks are complete; the chromosome object is not yet fully initialized.\" << EidosTerminate();\n}\nvoid Chromosome::CheckPartialInitializationForMethod(EidosGlobalStringID p_method_id)\n{\n\tif (community_.Tick() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::CheckPartialInitializationForProperty): Chromosome method \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() cannot be called until initialize() callbacks are complete; the chromosome object is not yet fully initialized.\" << EidosTerminate();\n}\n\nconst EidosClass *Chromosome::Class(void) const\n{\n\treturn gSLiM_Chromosome_Class;\n}\n\nvoid Chromosome::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << symbol_ << \">\";\n}\n\nEidosValue_SP Chromosome::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_genomicElements:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElement_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (GenomicElement *genomic_element : genomic_elements_)\n\t\t\t\tvec->push_object_element_NORR(genomic_element);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_id:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(id_));\n\t\t}\n\t\tcase gID_isSexChromosome:\n\t\t{\n\t\t\treturn is_sex_chromosome_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\t}\n\t\tcase gID_intrinsicPloidy:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(intrinsic_ploidy_));\n\t\t}\n\t\tcase gID_lastPosition:\n\t\t{\n\t\t\tif (!extent_immutable_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property lastPosition is not yet defined, since the length of the target chromosome has not yet been determined; you could provide a specified length to initializeChromosome(), or avoid requesting the chromosome's lastPosition until the chromosome's initialization has been finalized (after the execution of initialize() callbacks).\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(last_position_));\n\t\t}\n\t\tcase gEidosID_length:\n\t\t{\n\t\t\tif (!extent_immutable_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property lastPosition is not yet defined, since the length of the target chromosome has not yet been determined; you could provide a specified length to initializeChromosome(), or avoid requesting the chromosome's length until the chromosome's initialization has been finalized (after the execution of initialize() callbacks).\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(last_position_ + 1));\n\t\t}\n\t\tcase gID_species:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(&species_, gSLiM_Species_Class));\n\t\t}\n\t\tcase gID_symbol:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(symbol_));\n\t\t}\n\t\tcase gEidosID_type:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(type_string_));\n\t\t}\n\t\t\t\n\t\tcase gID_hotspotEndPositions:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositions is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (!single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositions is not defined since sex-specific hotspot maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(hotspot_end_positions_H_));\n\t\t}\n\t\tcase gID_hotspotEndPositionsM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositionsM is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositionsM is not defined since sex-specific hotspot maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(hotspot_end_positions_M_));\n\t\t}\n\t\tcase gID_hotspotEndPositionsF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositionsF is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotEndPositionsF is not defined since sex-specific hotspot maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(hotspot_end_positions_F_));\n\t\t}\n\t\t\t\n\t\tcase gID_hotspotMultipliers:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliers is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (!single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliers is not defined since sex-specific hotspot maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(hotspot_multipliers_H_));\n\t\t}\n\t\tcase gID_hotspotMultipliersM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliersM is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliersM is not defined since sex-specific hotspot maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(hotspot_multipliers_M_));\n\t\t}\n\t\tcase gID_hotspotMultipliersF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliersF is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property hotspotMultipliersF is not defined since sex-specific hotspot maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(hotspot_multipliers_F_));\n\t\t}\n\t\t\t\n\t\tcase gID_mutationEndPositions:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositions is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (!single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositions is not defined since sex-specific mutation rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_end_positions_H_));\n\t\t}\n\t\tcase gID_mutationEndPositionsM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositionsM is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositionsM is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_end_positions_M_));\n\t\t}\n\t\tcase gID_mutationEndPositionsF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositionsF is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationEndPositionsF is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_end_positions_F_));\n\t\t}\n\t\t\t\n\t\tcase gID_mutationRates:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRates is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (!single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRates is not defined since sex-specific mutation rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mutation_rates_H_));\n\t\t}\n\t\tcase gID_mutationRatesM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRatesM is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRatesM is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mutation_rates_M_));\n\t\t}\n\t\tcase gID_mutationRatesF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRatesF is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property mutationRatesF is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mutation_rates_F_));\n\t\t}\n\t\t\t\n\t\tcase gID_overallMutationRate:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRate is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (!single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRate is not defined since sex-specific mutation rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_mutation_rate_H_userlevel_));\n\t\t}\n\t\tcase gID_overallMutationRateM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRateM is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRateM is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_mutation_rate_M_userlevel_));\n\t\t}\n\t\tcase gID_overallMutationRateF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (species_.IsNucleotideBased())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRateF is not defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\tif (single_mutation_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallMutationRateF is not defined since sex-specific mutation rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_mutation_rate_F_userlevel_));\n\t\t}\n\t\t\t\n\t\tcase gID_overallRecombinationRate:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallRecombinationRate is not defined since sex-specific recombination rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_recombination_rate_H_userlevel_));\n\t\t}\n\t\tcase gID_overallRecombinationRateM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallRecombinationRateM is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_recombination_rate_M_userlevel_));\n\t\t}\n\t\tcase gID_overallRecombinationRateF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property overallRecombinationRateF is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(overall_recombination_rate_F_userlevel_));\n\t\t}\n\t\t\t\n\t\tcase gID_recombinationEndPositions:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationEndPositions is not defined since sex-specific recombination rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(recombination_end_positions_H_));\n\t\t}\n\t\tcase gID_recombinationEndPositionsM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationEndPositionsM is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(recombination_end_positions_M_));\n\t\t}\n\t\tcase gID_recombinationEndPositionsF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationEndPositionsF is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(recombination_end_positions_F_));\n\t\t}\n\t\t\t\n\t\tcase gID_recombinationRates:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationRates is not defined since sex-specific recombination rate maps have been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(recombination_rates_H_));\n\t\t}\n\t\tcase gID_recombinationRatesM:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationRatesM is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(recombination_rates_M_));\n\t\t}\n\t\tcase gID_recombinationRatesF:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (single_recombination_map_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property recombinationRatesF is not defined since sex-specific recombination rate maps have not been defined.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(recombination_rates_F_));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_colorSubstitution:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(color_sub_));\n\t\t}\n\t\tcase gID_geneConversionEnabled:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\treturn using_DSB_model_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\t}\n\t\tcase gID_geneConversionGCBias:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!using_DSB_model_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property geneConversionGCBias is not defined since the DSB recombination model is not being used.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mismatch_repair_bias_));\n\t\t}\n\t\tcase gID_geneConversionNonCrossoverFraction:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!using_DSB_model_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property geneConversionNonCrossoverFraction is not defined since the DSB recombination model is not being used.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(non_crossover_fraction_));\n\t\t}\n\t\tcase gID_geneConversionMeanLength:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!using_DSB_model_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property geneConversionMeanLength is not defined since the DSB recombination model is not being used.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(gene_conversion_avg_length_));\n\t\t}\n\t\tcase gID_geneConversionSimpleConversionFraction:\n\t\t{\n\t\t\tCheckPartialInitializationForProperty(p_property_id);\n\t\t\t\n\t\t\tif (!using_DSB_model_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property geneConversionSimpleConversionFraction is not defined since the DSB recombination model is not being used.\" << EidosTerminate();\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(simple_conversion_fraction_));\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name_));\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::GetProperty): property tag accessed on chromosome before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid Chromosome::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_colorSubstitution:\n\t\t{\n\t\t\tcolor_sub_ = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\tif (!color_sub_.empty())\n\t\t\t\tEidos_GetColorComponents(color_sub_, &color_sub_red_, &color_sub_green_, &color_sub_blue_);\n\t\t\treturn;\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\tname_ = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t}\n}\n\nEidosValue_SP Chromosome::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_ancestralNucleotides:\t\t\treturn ExecuteMethod_ancestralNucleotides(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_genomicElementForPosition:\t\treturn ExecuteMethod_genomicElementForPosition(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_hasGenomicElementForPosition:\treturn ExecuteMethod_hasGenomicElementForPosition(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setAncestralNucleotides:\t\treturn ExecuteMethod_setAncestralNucleotides(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setGeneConversion:\t\t\t\treturn ExecuteMethod_setGeneConversion(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setHotspotMap:\t\t\t\t\treturn ExecuteMethod_setHotspotMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setMutationRate:\t\t\t\treturn ExecuteMethod_setMutationRate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setRecombinationRate:\t\t\treturn ExecuteMethod_setRecombinationRate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_drawBreakpoints:\t\t\t\treturn ExecuteMethod_drawBreakpoints(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (is)ancestralNucleotides([Ni$ start = NULL], [Ni$ end = NULL], [s$ format = \"string\"])\n//\nEidosValue_SP Chromosome::ExecuteMethod_ancestralNucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\t// The ancestral sequence is actually kept by Species, so go get it\n\tif (!species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_ancestralNucleotides): ancestralNucleotides() may only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tNucleotideArray *sequence = AncestralSequence();\n\tEidosValue *start_value = p_arguments[0].get();\n\tEidosValue *end_value = p_arguments[1].get();\n\t\n\tint64_t start = (start_value->Type() == EidosValueType::kValueNULL) ? 0 : start_value->IntAtIndex_NOCAST(0, nullptr);\n\tint64_t end = (end_value->Type() == EidosValueType::kValueNULL) ? last_position_ : end_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((start < 0) || (end < 0) || (start > last_position_) || (end > last_position_) || (start > end))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_ancestralNucleotides): start and end must be within the chromosome's extent, and start must be <= end.\" << EidosTerminate();\n\tif (((std::size_t)start >= sequence->size()) || ((std::size_t)end >= sequence->size()))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_ancestralNucleotides): (internal error) start and end must be within the ancestral sequence's length.\" << EidosTerminate();\n\t\n\tint64_t length = end - start + 1;\n\t\n\tif (length > INT_MAX)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_ancestralNucleotides): the returned vector would exceed the maximum vector length in Eidos.\" << EidosTerminate();\n\t\n\tEidosValue_String *format_value = (EidosValue_String *)p_arguments[2].get();\n\tconst std::string &format = format_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (format == \"codon\")\n\t\treturn sequence->NucleotidesAsCodonVector(start, end, /* p_force_vector */ false);\n\tif (format == \"string\")\n\t\treturn sequence->NucleotidesAsStringSingleton(start, end);\n\tif (format == \"integer\")\n\t\treturn sequence->NucleotidesAsIntegerVector(start, end);\n\tif (format == \"char\")\n\t\treturn sequence->NucleotidesAsStringVector(start, end);\n\t\n\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_ancestralNucleotides): parameter format must be either 'string', 'char', 'integer', or 'codon'.\" << EidosTerminate();\n}\n\n//\t*********************\t– (integer)drawBreakpoints([No<Individual>$ parent = NULL], [Ni$ n = NULL])\n//\nEidosValue_SP Chromosome::ExecuteMethod_drawBreakpoints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tEidosValue *parent_value = p_arguments[0].get();\n\tEidosValue *n_value = p_arguments[1].get();\n\t\n\tIndividual *parent = nullptr;\n\t\n\tif (parent_value->Type() != EidosValueType::kValueNULL)\n\t\tparent = (Individual *)parent_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tint num_breakpoints = -1;\t// means \"draw them for us\"\n\t\n\tif (n_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((n < 0) || (n > 1000000L))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_drawBreakpoints): drawBreakpoints() requires 0 <= n <= 1000000.\" << EidosTerminate();\n\t\t\n\t\tnum_breakpoints = (int)n;\n\t}\n\t\n\tstd::vector<slim_position_t> all_breakpoints;\n\t\n\t// Note that for calling recombination() callbacks below, we always treat the parent's first haplosome as\n\t// the initial copy strand.  This is documented; it is perhaps a weakness of the API here, but if we\n\t// randomly chose an initial copy strand it would not be used downstream, so.\n\t// FIXME an idea: a new parameter, [l$ randomizeStrands = F], could be added that, if true, would\n\t// put a breakpoint at 0 half of the time, regardless of recombination rate, so the initial copy\n\t// strand is randomized for anyone using the generated breakpoints.  This solves the problem, a\n\t// little bit clunkily.  The main client of this method is users of addRecombinant(), though, and\n\t// it now has its own randomizeStrands flag, so maybe this change is unnecessary?\n\t\n\tDrawBreakpoints(parent, /* p_haplosome1 */ nullptr, /* p_haplosome2 */ nullptr, num_breakpoints,\n\t\t\t\t\tall_breakpoints, /* p_heteroduplex */ nullptr, \"drawBreakpoints()\");\n\t\n\tif (all_breakpoints.size() == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\telse\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(all_breakpoints));\n}\n\nGenomicElement *Chromosome::ElementForPosition(slim_position_t pos)\n{\n\tauto element_iter = std::lower_bound(genomic_elements_.begin(), genomic_elements_.end(), pos,\n\t\t[](const GenomicElement *e, slim_position_t position) { return e->end_position_ < position; });\n\t\n\tif (element_iter == genomic_elements_.end())\n\t\treturn nullptr;\n\t\n\tGenomicElement *element = *element_iter;\n\t\n\tif (element->start_position_ > pos)\n\t\treturn nullptr;\n\t\n\treturn element;\n}\n\n//\t*********************\t(object<GenomicElement>)genomicElementForPosition(integer positions)\n//\nEidosValue_SP Chromosome::ExecuteMethod_genomicElementForPosition(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tEidosValue *positions_value = p_arguments[0].get();\n\tint positions_count = positions_value->Count();\n\tEidosValue_Object_SP obj_result_SP = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElement_Class));\n\tEidosValue_Object *obj_result = obj_result_SP->reserve(positions_count);\n\tconst int64_t *positions_data = positions_value->IntData();\n\t\n\tfor (int pos_index = 0; pos_index < positions_count; ++pos_index)\n\t{\n\t\tint64_t pos = positions_data[pos_index];\n\t\tGenomicElement *element = ElementForPosition(pos);\n\t\t\n\t\tif (element)\n\t\t\tobj_result->push_object_element_no_check_NORR(element);\n\t}\n\t\n\treturn obj_result_SP;\n}\n\n//\t*********************\t(logical)hasGenomicElementForPosition(integer positions)\n//\nEidosValue_SP Chromosome::ExecuteMethod_hasGenomicElementForPosition(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tEidosValue *positions_value = p_arguments[0].get();\n\tint positions_count = positions_value->Count();\n\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\tEidosValue_Logical *logical_result = logical_result_SP->reserve(positions_count);\n\tconst int64_t *positions_data = positions_value->IntData();\n\t\n\tfor (int pos_index = 0; pos_index < positions_count; ++pos_index)\n\t{\n\t\tint64_t pos = positions_data[pos_index];\n\t\tlogical_result->push_logical_no_check(ElementForPosition(pos) ? true : false);\n\t}\n\t\n\treturn logical_result_SP;\n}\n\n//\t*********************\t(integer$)setAncestralNucleotides(is sequence)\n//\nEidosValue_SP Chromosome::ExecuteMethod_setAncestralNucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tEidosValue *sequence_value = p_arguments[0].get();\n\t\n\tif (!species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): initializeAncestralNucleotides() may be only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tEidosValueType sequence_value_type = sequence_value->Type();\n\tint sequence_value_count = sequence_value->Count();\n\t\n\tif (sequence_value_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): initializeAncestralNucleotides() requires a sequence of length >= 1.\" << EidosTerminate();\n\t\n\tif (ancestral_seq_buffer_)\n\t{\n\t\tdelete ancestral_seq_buffer_;\n\t\tancestral_seq_buffer_ = nullptr;\n\t}\n\t\n\tif (sequence_value_type == EidosValueType::kValueInt)\n\t{\n\t\t// A vector of integers has been provided, where ACGT == 0123\n\t\tconst int64_t *int_data = sequence_value->IntData();\n\t\t\n\t\tancestral_seq_buffer_ = new NucleotideArray(sequence_value_count, int_data);\n\t}\n\telse if (sequence_value_type == EidosValueType::kValueString)\n\t{\n\t\tif (sequence_value_count != 1)\n\t\t{\n\t\t\t// A vector of characters has been provided, which must all be \"A\" / \"C\" / \"G\" / \"T\"\n\t\t\tconst std::string *string_data = sequence_value->StringData();\n\t\t\t\n\t\t\tancestral_seq_buffer_ = new NucleotideArray(sequence_value_count, string_data);\n\t\t}\n\t\telse\t// sequence_value_count == 1\n\t\t{\n\t\t\tconst std::string &sequence_string = sequence_value->StringData()[0];\n\t\t\tbool contains_only_nuc = true;\n\t\t\t\n\t\t\t// OK, we do a weird thing here.  We want to try to construct a NucleotideArray\n\t\t\t// from sequence_string, which throws with EIDOS_TERMINATION if it fails, but\n\t\t\t// we want to actually catch that exception even if we're running at the\n\t\t\t// command line, where EIDOS_TERMINATION normally calls exit().  So we actually\n\t\t\t// play around with the error-handling state to make it do what we want it to do.\n\t\t\t// This is very naughty and should be redesigned, but right now I'm not seeing\n\t\t\t// the right redesign strategy, so... hacking it for now.  Parallel code is at\n\t\t\t// Species::ExecuteContextFunction_initializeAncestralNucleotides()\n\t\t\tbool save_gEidosTerminateThrows = gEidosTerminateThrows;\n\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tancestral_seq_buffer_ = new NucleotideArray(sequence_string.length(), sequence_string.c_str());\n\t\t\t} catch (...) {\n\t\t\t\tcontains_only_nuc = false;\n\t\t\t\t\n\t\t\t\t// clean up the error state since we don't want this throw to be reported\n\t\t\t\tgEidosTermination.clear();\n\t\t\t\tgEidosTermination.str(\"\");\n\t\t\t}\n\t\t\t\n\t\t\tgEidosTerminateThrows = save_gEidosTerminateThrows;\n\t\t\t\n\t\t\tif (!contains_only_nuc)\n\t\t\t{\n\t\t\t\t// A singleton string has been provided that contains characters other than ACGT; we will interpret it as a filesystem path for a FASTA file\n\t\t\t\tstd::string file_path = Eidos_ResolvedPath(sequence_string);\n\t\t\t\tstd::ifstream file_stream(file_path.c_str());\n\t\t\t\t\n\t\t\t\tif (!file_stream.is_open())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): the file at path \" << sequence_string << \" could not be opened or does not exist.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tbool started_sequence = false;\n\t\t\t\tstd::string line, fasta_sequence;\n\t\t\t\t\n\t\t\t\twhile (getline(file_stream, line))\n\t\t\t\t{\n\t\t\t\t\t// skippable lines are blank or start with a '>' or ';'\n\t\t\t\t\t// we skip over them if they're at the start of the file; once we start a sequence, they terminate the sequence\n\t\t\t\t\tbool skippable = ((line.length() == 0) || (line[0] == '>') || (line[0] == ';'));\n\t\t\t\t\t\n\t\t\t\t\tif (!started_sequence && skippable)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (skippable)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// otherwise, append the nucleotides from this line, removing a \\r if one is present at the end of the line\n\t\t\t\t\tif (line.back() == '\\r')\n\t\t\t\t\t\tline.pop_back();\n\t\t\t\t\t\n\t\t\t\t\tfasta_sequence.append(line);\n\t\t\t\t\tstarted_sequence = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (file_stream.bad())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): a filesystem error occurred while reading the file at path \" << sequence_string << \".\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (fasta_sequence.length() == 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): no FASTA sequence found in \" << sequence_string << \".\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tancestral_seq_buffer_ = new NucleotideArray(fasta_sequence.length(), fasta_sequence.c_str());\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): (internal error) unrecognized sequence type.\" << EidosTerminate();\n\t}\n\t\n\t// check that the length of the new sequence matches the chromosome length\n\tif (ancestral_seq_buffer_->size() != (std::size_t)(last_position_ + 1))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setAncestralNucleotides): The chromosome length (\" << last_position_ + 1 << \" base\" << (last_position_ + 1 != 1 ? \"s\" : \"\") << \") does not match the ancestral sequence length (\" << ancestral_seq_buffer_->size() << \" base\" << (ancestral_seq_buffer_->size() != 1 ? \"s\" : \"\") << \").\" << EidosTerminate();\n\t\n\t// debugging\n\t//std::cout << \"ancestral sequence set: \" << *ancestral_seq_buffer_ << std::endl;\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(ancestral_seq_buffer_->size()));\n}\n\n//\t*********************\t– (void)setGeneConversion(numeric$ nonCrossoverFraction, numeric$ meanLength, numeric$ simpleConversionFraction, [numeric$ bias = 0])\n//\nEidosValue_SP Chromosome::ExecuteMethod_setGeneConversion(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() may not be called for a species with no genetics.\" << EidosTerminate();\n\t\n\tEidosValue *nonCrossoverFraction_value = p_arguments[0].get();\n\tEidosValue *meanLength_value = p_arguments[1].get();\n\tEidosValue *simpleConversionFraction_value = p_arguments[2].get();\n\tEidosValue *bias_value = p_arguments[3].get();\n\t\n\tdouble non_crossover_fraction = nonCrossoverFraction_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble gene_conversion_avg_length = meanLength_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble simple_conversion_fraction = simpleConversionFraction_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble bias = bias_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((non_crossover_fraction < 0.0) || (non_crossover_fraction > 1.0) || std::isnan(non_crossover_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() nonCrossoverFraction must be between 0.0 and 1.0 inclusive (\" << EidosStringForFloat(non_crossover_fraction) << \" supplied).\" << EidosTerminate();\n\tif ((gene_conversion_avg_length < 0.0) || std::isnan(gene_conversion_avg_length))\t\t// intentionally no upper bound\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() meanLength must be >= 0.0 (\" << EidosStringForFloat(gene_conversion_avg_length) << \" supplied).\" << EidosTerminate();\n\tif ((simple_conversion_fraction < 0.0) || (simple_conversion_fraction > 1.0) || std::isnan(simple_conversion_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() simpleConversionFraction must be between 0.0 and 1.0 inclusive (\" << EidosStringForFloat(simple_conversion_fraction) << \" supplied).\" << EidosTerminate();\n\tif ((bias < -1.0) || (bias > 1.0) || std::isnan(bias))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() bias must be between -1.0 and 1.0 inclusive (\" << EidosStringForFloat(bias) << \" supplied).\" << EidosTerminate();\n\tif ((bias != 0.0) && !species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setGeneConversion): setGeneConversion() bias must be 0.0 in non-nucleotide-based models.\" << EidosTerminate();\n\t\n\tusing_DSB_model_ = true;\n\tnon_crossover_fraction_ = non_crossover_fraction;\n\tgene_conversion_avg_length_ = gene_conversion_avg_length;\n\tgene_conversion_inv_half_length_ = 1.0 / (gene_conversion_avg_length / 2.0);\n\tsimple_conversion_fraction_ = simple_conversion_fraction;\n\tmismatch_repair_bias_ = bias;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setHotspotMap(numeric multipliers, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Chromosome::ExecuteMethod_setHotspotMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() may not be called for a species with no genetics.\" << EidosTerminate();\n\tif (!species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() may only be called in nucleotide-based models (use setMutationRate() to vary the mutation rate along the chromosome).\" << EidosTerminate();\n\t\n\tEidosValue *multipliers_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\t\n\tint multipliers_count = multipliers_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex = IndividualSex::kUnspecified;\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state\n\tif (((requested_sex == IndividualSex::kUnspecified) && !single_mutation_map_) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && single_mutation_map_))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? hotspot_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? hotspot_end_positions_M_ : hotspot_end_positions_F_));\n\tstd::vector<double> &multipliers = ((requested_sex == IndividualSex::kUnspecified) ? hotspot_multipliers_H_ : \n\t\t\t\t\t\t\t ((requested_sex == IndividualSex::kMale) ? hotspot_multipliers_M_ : hotspot_multipliers_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// ends is missing/NULL\n\t\tif (multipliers_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() requires multipliers to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values\n\t\tif ((multiplier < 0.0) || !std::isfinite(multiplier))\t\t// intentionally no upper bound\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() multiplier \" << EidosStringForFloat(multiplier) << \" out of range; multipliers must be >= 0.\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\tmultipliers.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\tmultipliers.emplace_back(multiplier);\n\t\tpositions.emplace_back(last_position_);\n\t}\n\telse\n\t{\n\t\t// ends is supplied\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != multipliers_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() requires ends and multipliers to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (mutation_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((multiplier < 0.0) || !std::isfinite(multiplier))\t\t// intentionally no upper bound\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() multiplier \" << multiplier << \" out of range; multipliers must be >= 0.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// The stake here is that the last position in the chromosome is not allowed to change after the chromosome is\n\t\t// constructed.  When we call InitializeDraws() below, we recalculate the last position – and we must come up\n\t\t// with the same answer that we got before, otherwise our last_position_ cache is invalid.\n\t\tint64_t new_last_position = ends_value->IntAtIndex_NOCAST(end_count - 1, nullptr);\n\t\t\n\t\tif (new_last_position != last_position_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setHotspotMap): setHotspotMap() end \" << new_last_position << \" noncompliant; the last interval must end at the last position of the chromosome (\" << last_position_ << \").\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\tmultipliers.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\tmultipliers.emplace_back(multiplier);\n\t\t\tpositions.emplace_back(mutation_end_position);\n\t\t}\n\t}\n\t\n\tCreateNucleotideMutationRateMap();\n\tInitializeDraws();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setMutationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Chromosome::ExecuteMethod_setMutationRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() may not be called for a species with no genetics.\" << EidosTerminate();\n\tif (species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() may not be called in nucleotide-based models (use setHotspotMap() to vary the mutation rate along the chromosome).\" << EidosTerminate();\n\t\n\tEidosValue *rates_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\t\n\tint rate_count = rates_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex = IndividualSex::kUnspecified;\n\t\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state\n\tif (((requested_sex == IndividualSex::kUnspecified) && !single_mutation_map_) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && single_mutation_map_))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? mutation_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? mutation_end_positions_M_ : mutation_end_positions_F_));\n\tstd::vector<double> &rates = ((requested_sex == IndividualSex::kUnspecified) ? mutation_rates_H_ : \n\t\t\t\t\t\t\t ((requested_sex == IndividualSex::kMale) ? mutation_rates_M_ : mutation_rates_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// ends is missing/NULL\n\t\tif (rate_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() requires rates to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values\n\t\tif ((mutation_rate < 0.0) || !std::isfinite(mutation_rate))\t\t// intentionally no upper bound\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() rate \" << EidosStringForFloat(mutation_rate) << \" out of range; rates must be >= 0.\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\trates.emplace_back(mutation_rate);\n\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\telse\n\t{\n\t\t// ends is supplied\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != rate_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() requires ends and rates to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (mutation_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((mutation_rate < 0.0) || !std::isfinite(mutation_rate))\t\t// intentionally no upper bound\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() rate \" << EidosStringForFloat(mutation_rate) << \" out of range; rates must be >= 0.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// The stake here is that the last position in the chromosome is not allowed to change after the chromosome is\n\t\t// constructed.  When we call InitializeDraws() below, we recalculate the last position – and we must come up\n\t\t// with the same answer that we got before, otherwise our last_position_ cache is invalid.\n\t\tint64_t new_last_position = ends_value->IntAtIndex_NOCAST(end_count - 1, nullptr);\n\t\t\n\t\tif (new_last_position != last_position_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setMutationRate): setMutationRate() end \" << new_last_position << \" noncompliant; the last interval must end at the last position of the chromosome (\" << last_position_ << \").\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\trates.emplace_back(mutation_rate);\n\t\t\tpositions.emplace_back(mutation_end_position);\n\t\t}\n\t}\n\t\n\tInitializeDraws();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setRecombinationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Chromosome::ExecuteMethod_setRecombinationRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tCheckPartialInitializationForMethod(p_method_id);\n\t\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() may not be called for a species with no genetics.\" << EidosTerminate();\n\t\n\tEidosValue *rates_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\t\n\tint rate_count = rates_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex = IndividualSex::kUnspecified;\n\t\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state\n\tif (((requested_sex == IndividualSex::kUnspecified) && !single_recombination_map_) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && single_recombination_map_))\n\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? recombination_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? recombination_end_positions_M_ : recombination_end_positions_F_));\n\tstd::vector<double> &rates = ((requested_sex == IndividualSex::kUnspecified) ? recombination_rates_H_ : \n\t\t\t\t\t\t\t ((requested_sex == IndividualSex::kMale) ? recombination_rates_M_ : recombination_rates_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// ends is missing/NULL\n\t\tif (rate_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() requires rates to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values\n\t\tif ((recombination_rate < 0.0) || (recombination_rate > 0.5) || std::isnan(recombination_rate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() rate \" << recombination_rate << \" out of range; rates must be in [0.0, 0.5].\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\trates.emplace_back(recombination_rate);\n\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\telse\n\t{\n\t\t// ends is supplied\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != rate_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() requires ends and rates to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t recombination_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (recombination_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((recombination_rate < 0.0) || (recombination_rate > 0.5) || std::isnan(recombination_rate))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() rate \" << recombination_rate << \" out of range; rates must be in [0.0, 0.5].\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// The stake here is that the last position in the chromosome is not allowed to change after the chromosome is\n\t\t// constructed.  When we call InitializeDraws() below, we recalculate the last position – and we must come up\n\t\t// with the same answer that we got before.\n\t\tint64_t new_last_position = ends_value->IntAtIndex_NOCAST(end_count - 1, nullptr);\n\t\t\n\t\tif (new_last_position != last_position_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ExecuteMethod_setRecombinationRate): setRecombinationRate() rate \" << new_last_position << \" noncompliant; the last interval must end at the last position of the chromosome (\" << last_position_ << \").\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.resize(0);\n\t\tpositions.resize(0);\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t recombination_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\trates.emplace_back(recombination_rate);\n\t\t\tpositions.emplace_back(recombination_end_position);\n\t\t}\n\t}\n\t\n\tInitializeDraws();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tChromosome_Class\n//\n#pragma mark -\n#pragma mark Chromosome_Class\n#pragma mark -\n\nEidosClass *gSLiM_Chromosome_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Chromosome_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Chromosome_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_genomicElements,\t\t\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_GenomicElement_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_isSexChromosome,\t\t\t\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_intrinsicPloidy,\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_lastPosition,\t\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_length,\t\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotEndPositions,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotEndPositionsM,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotEndPositionsF,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotMultipliers,\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotMultipliersM,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hotspotMultipliersF,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationEndPositions,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationEndPositionsM,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationEndPositionsF,\t\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationRates,\t\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationRatesM,\t\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationRatesF,\t\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_name,\t\t\t\t\t\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallMutationRate,\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallMutationRateM,\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallMutationRateF,\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallRecombinationRate,\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallRecombinationRateM,\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_overallRecombinationRateF,\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationEndPositions,\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationEndPositionsM,\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationEndPositionsF,\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationRates,\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationRatesM,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_recombinationRatesF,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_species,\t\t\t\t\t\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_symbol,\t\t\t\t\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_geneConversionEnabled,\t\t\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_geneConversionGCBias,\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_geneConversionNonCrossoverFraction,\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_geneConversionMeanLength,\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_geneConversionSimpleConversionFraction,\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_type,\t\t\t\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_colorSubstitution,\t\t\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Chromosome_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Chromosome_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_ancestralNucleotides, kEidosValueMaskInt | kEidosValueMaskString))->AddInt_OSN(gEidosStr_start, gStaticEidosValueNULL)->AddInt_OSN(gEidosStr_end, gStaticEidosValueNULL)->AddString_OS(\"format\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"string\"))));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_drawBreakpoints, kEidosValueMaskInt))->AddObject_OSN(\"parent\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddInt_OSN(\"n\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_genomicElementForPosition, kEidosValueMaskObject, gSLiM_GenomicElement_Class))->AddInt(\"positions\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_hasGenomicElementForPosition, kEidosValueMaskLogical))->AddInt(\"positions\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setAncestralNucleotides, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddIntString(\"sequence\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setGeneConversion, kEidosValueMaskVOID))->AddNumeric_S(\"nonCrossoverFraction\")->AddNumeric_S(\"meanLength\")->AddNumeric_S(\"simpleConversionFraction\")->AddNumeric_OS(\"bias\", gStaticEidosValue_Integer0));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setHotspotMap, kEidosValueMaskVOID))->AddNumeric(\"multipliers\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setMutationRate, kEidosValueMaskVOID))->AddNumeric(\"rates\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setRecombinationRate, kEidosValueMaskVOID))->AddNumeric(\"rates\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/chromosome.h",
    "content": "//\n//  chromosome.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Chromosome represents an entire chromosome.  Only the portions of the chromosome that are relevant to the simulation are\n explicitly modeled, so in practice, a chromosome is a vector of genomic elements defined by the input file.  A chromosome also has\n a length, an overall mutation rate, an overall recombination rate, and parameters related to gene conversion.\n \n */\n\n#ifndef __SLiM__chromosome__\n#define __SLiM__chromosome__\n\n\n#include <vector>\n#include <map>\n\n#include \"mutation.h\"\n#include \"mutation_type.h\"\n#include \"genomic_element.h\"\n#include \"genomic_element_type.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_value.h\"\n\nstruct GESubrange;\nclass Haplosome;\nclass Species;\nclass Individual;\n\n\nextern EidosClass *gSLiM_Chromosome_Class;\n\n\nclass Chromosome : public EidosDictionaryRetained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\t\n\tint64_t id_;\n\tstd::string symbol_;\n\tstd::string name_;\n\tslim_chromosome_index_t index_;\n\tChromosomeType type_;\n\t\n\t// cached properties of the chromosome that depend upon its type\n\tint intrinsic_ploidy_;\t\t\t\t\t\t\t\t\t// 1 or 2; the number of haplosomes kept for the chromosome\n\tbool always_uses_null_haplosomes_;\t\t\t\t\t\t// true for types that *always* involve null haplosomes\n\tbool is_sex_chromosome_;\t\t\t\t\t\t\t\t// true for types X, Y, Z, W, and -Y\n\tbool defaults_to_zero_recombination_;\t\t\t\t\t// false only for types A, X, and Z, which are truly diploid\n\tstd::string type_string_;\t\t\t\t\t\t\t\t// a string like \"A\", \"X\", etc. for the type\n\t\n\t// This vector contains all the genomic elements for this chromosome.  It is in sorted order once initialization is complete.\n\tstd::vector<GenomicElement *> genomic_elements_;\t\t// OWNED POINTERS: genomic elements belong to the chromosome\n\t\n\t// We now allow different recombination maps for males and females, optionally.  Unfortunately, this means we have a bit of an\n\t// explosion of state involved with recombination.  We now have _H, _M, and _F versions of many ivars.  The _M and _F versions\n\t// are used if sex is enabled and different recombination maps have been specified for males versus females.  The _H version\n\t// is used in all other cases – when sex is not enabled (i.e., hermaphrodites), and when separate maps have not been specified.\n\t// This flag indicates which option has been chosen; after initialize() time this cannot be changed.\n\tbool single_recombination_map_ = true;\n\t\n\t// The same is now true for mutation rate maps as well; we now have _H, _M, and _F versions of those, just as with recombination\n\t// maps.  This flag indicates which option has been chosen; after initialize() time this cannot be changed.\n\tbool single_mutation_map_ = true;\n\t\n\tgsl_ran_discrete_t *lookup_mutation_H_ = nullptr;\t\t// OWNED POINTER: lookup table for drawing mutations\n\tgsl_ran_discrete_t *lookup_mutation_M_ = nullptr;\n\tgsl_ran_discrete_t *lookup_mutation_F_ = nullptr;\n\t\n\tgsl_ran_discrete_t *lookup_recombination_H_ = nullptr;\t// OWNED POINTER: lookup table for drawing recombination breakpoints\n\tgsl_ran_discrete_t *lookup_recombination_M_ = nullptr;\n\tgsl_ran_discrete_t *lookup_recombination_F_ = nullptr;\n\t\n\t// caches to speed up Poisson draws in CrossoverMutation()\n\tdouble exp_neg_overall_mutation_rate_H_;\t\t\t\n\tdouble exp_neg_overall_mutation_rate_M_;\n\tdouble exp_neg_overall_mutation_rate_F_;\n\t\n\tdouble exp_neg_overall_recombination_rate_H_;\t\t\t\n\tdouble exp_neg_overall_recombination_rate_M_;\n\tdouble exp_neg_overall_recombination_rate_F_;\n\t\n#ifndef USE_GSL_POISSON\n\t// joint probabilities, used to accelerate drawing a mutation count and breakpoint count jointly\n\tdouble probability_both_0_H_;\n\tdouble probability_both_0_OR_mut_0_break_non0_H_;\n\tdouble probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_H_;\n\t\n\tdouble probability_both_0_M_;\n\tdouble probability_both_0_OR_mut_0_break_non0_M_;\n\tdouble probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_;\n\t\n\tdouble probability_both_0_F_;\n\tdouble probability_both_0_OR_mut_0_break_non0_F_;\n\tdouble probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_;\n#endif\n\t\n\t// GESubrange vectors used to facilitate new mutation generation – draw a subrange, then draw a position inside the subrange\n\tstd::vector<GESubrange> mutation_subranges_H_;\n\tstd::vector<GESubrange> mutation_subranges_M_;\n\tstd::vector<GESubrange> mutation_subranges_F_;\n\t\n\t// This object pool for haplosomes is owned by Species; we have a reference to it just for efficiency\n\tEidosObjectPool &haplosome_pool_;\t\t\t\t// NOT OWNED: a pool out of which haplosomes are allocated, for within-species locality\n\t\n\t// These haplosome junkyards, on the other hand, belong to us; each Chromosome keeps its own junkyards in which objects\n\t// are guaranteed to have the correct chromosome index already set up, and the correct chromosome mutrun configuration\n\tstd::vector<Haplosome *> haplosomes_junkyard_nonnull;\t// OWNED: non-null haplosomes go here when we're done with them, for reuse\n\tstd::vector<Haplosome *> haplosomes_junkyard_null;\t\t// OWNED: null haplosomes go here when we're done with them, for reuse\n\t\n\tHaplosome *_NewHaplosome_NULL(Individual *p_individual);\t\t// internal use only; does not set chromosome_subposition_\n\tHaplosome *_NewHaplosome_NONNULL(Individual *p_individual);\t\t// internal use only; does not set chromosome_subposition_\n\t\n\t// Chromosome now keeps two MutationRunPools, one for freed MutationRun objects and one for in-use MutationRun objects,\n\t// as well as an object pool out of which completely new MutationRuns are allocated, all bundled in a MutationRunContext.\n\t// When running multithreaded, each of these becomes a vector of per-thread objects, so we can alloc/free runs in parallel code.\n\t// This stuff is not set up until after initialize() callbacks; nobody should be using MutationRuns before then.\n#ifndef _OPENMP\n\tMutationRunContext mutation_run_context_SINGLE_;\n#else\n\tint mutation_run_context_COUNT_ = 0;\t\t\t\t\t\t\t\t\t\t\t// the number of PERTHREAD contexts\n\tstd::vector<MutationRunContext *> mutation_run_context_PERTHREAD;\n#endif\n\t\n\t// Mutation run optimization.  The ivars here are used only internally by Species; the canonical reference regarding the\n\t// number and length of mutation runs is kept by Chromosome (for the simulation) and by Haplosome (for each haplosome object).\n\t// If Species decides to change the number of mutation runs, it will update those canonical repositories accordingly.\n\t// A prefix of x_ is used on all mutation run experiment ivars, to avoid confusion.\n\tint preferred_mutrun_count_ = 0;\t\t\t// preferred mutation run length (from the user); 0 represents no preference\n\t\n#define SLIM_MUTRUN_EXPERIMENT_LENGTH\t50\t\t// kind of based on how large a sample size is needed to detect important differences fairly reliably by t-test\n#define SLIM_MUTRUN_MAXIMUM_COUNT\t\t1024\t// the most mutation runs we will ever use; hard to imagine that any model will want more than this\n\t\n\tbool x_experiments_enabled_;\t\t\t\t// if false, no experiments are run and no cycle runtimes are recorded\n\tint32_t x_experiment_count_;\t\t\t\t// a counter of the number of experiments we've run (the number of t-tests we've conducted)\n\t\n\tint32_t x_current_mutcount_;\t\t\t\t// the number of mutation runs we're currently using\n\tdouble *x_current_runtimes_;\t\t\t\t// cycle runtimes recorded at this mutcount (SLIM_MUTRUN_EXPERIMENT_MAXLENGTH length)\n\tint x_current_buflen_;\t\t\t\t\t\t// the number of runtimes in the current_mutcount_runtimes_ buffer\n\t\n\tint32_t x_previous_mutcount_;\t\t\t\t// the number of mutation runs we previously used\n\tdouble *x_previous_runtimes_;\t\t\t\t// cycle runtimes recorded at that mutcount (SLIM_MUTRUN_EXPERIMENT_MAXLENGTH length)\n\tint x_previous_buflen_;\t\t\t\t\t\t// the number of runtimes in the previous_mutcount_runtimes_ buffer\n\t\n\tbool x_continuing_trend_;\t\t\t\t\t// if true, the current experiment continues a trend, such that the opposite trend can be excluded\n\t\n\tint64_t x_stasis_limit_;\t\t\t\t\t// how many stasis experiments we're running between change experiments; gets longer over time\n\tdouble x_stasis_alpha_;\t\t\t\t\t\t// the alpha threshold at which we decide that stasis has been broken; gets smaller over time\n\tint64_t x_stasis_counter_;\t\t\t\t\t// how many stasis experiments we have run so far\n\tint32_t x_prev1_stasis_mutcount_;\t\t\t// the number of mutation runs we settled on when we reached stasis last time\n\tint32_t x_prev2_stasis_mutcount_;\t\t\t// the number of mutation runs we settled on when we reached stasis the time before last\n\t\n\tstd::vector<int32_t> x_mutcount_history_;\t// a record of the mutation run count used in each cycle\n\t\n\teidos_profile_t x_current_clock_ = 0;\t\t// the clock for timing current being done\n\tbool x_clock_running_ = false;\n\tbool x_within_measurement_period_ = false;\n\t\n\teidos_profile_t x_total_gen_clocks_ = 0;\t// a counter of clocks accumulated for the current cycle's runtime (across measured code blocks)\n\t\t\t\t\t\t\t\t\t\t\t\t// look at StartMutationRunExperimentClock() usage to see which blocks are measured\n\t\n\t// Mutation run experiments\n\tvoid TransitionToNewExperimentAgainstCurrentExperiment(int32_t p_new_mutrun_count);\n\tvoid TransitionToNewExperimentAgainstPreviousExperiment(int32_t p_new_mutrun_count);\n\tvoid EnterStasisForMutationRunExperiments(void);\n\tvoid MaintainMutationRunExperiments(double p_last_gen_runtime);\n\t\n\t// Erroring during partial initialization\n\tvoid CheckPartialInitializationForProperty(EidosGlobalStringID p_property_id);\n\tvoid CheckPartialInitializationForMethod(EidosGlobalStringID p_method_id);\n\t\npublic:\n\t\n\tCommunity &community_;\n\tSpecies &species_;\n\t\n\t// the total haplosome count depends on the chromosome; it will be different for an autosome versus a sex chromosome, for example\n\tslim_refcount_t total_haplosome_count_ = 0;\t\t\t\t// the number of non-null haplosomes in the population; a fixed mutation has this count\n#ifdef SLIMGUI\n\tslim_refcount_t gui_total_haplosome_count_ = 0;\t\t\t// the number of non-null haplosomes in the selected subpopulations in SLiMgui\n#endif\n\t\n\tslim_refcount_t tallied_haplosome_count_ = 0;\t\t\t// the total non-null haplosomes counted for this chromosome in the last tally\n\t\n\t// mutation and recombination machinery\n\tstd::vector<slim_position_t> mutation_end_positions_H_;\t\t// end positions of each defined mutation region (BEFORE intersection with GEs)\n\tstd::vector<slim_position_t> mutation_end_positions_M_;\n\tstd::vector<slim_position_t> mutation_end_positions_F_;\n\t\n\tstd::vector<double> mutation_rates_H_;\t\t\t\t\t\t// mutation rates, in events per base pair (BEFORE intersection with GEs)\n\tstd::vector<double> mutation_rates_M_;\n\tstd::vector<double> mutation_rates_F_;\n\t\n\tstd::vector<slim_position_t> recombination_end_positions_H_;\t// end positions of each defined recombination region\n\tstd::vector<slim_position_t> recombination_end_positions_M_;\n\tstd::vector<slim_position_t> recombination_end_positions_F_;\n\t\n\tstd::vector<double> recombination_rates_H_;\t\t\t\t\t// recombination rates, in probability of crossover per base pair (user-specified)\n\tstd::vector<double> recombination_rates_M_;\n\tstd::vector<double> recombination_rates_F_;\n\t\n\tbool any_recombination_rates_05_ = false;\t\t\t\t// set to T if any recombination rate is 0.5; those are excluded from gene conversion\n\t\n\tslim_position_t last_position_;\t\t\t\t\t\t\t// last valid position\n\tbool extent_immutable_;\t\t\t\t\t\t\t\t\t// can the chromosome endpoint still be changed?\n\t\n\tdouble overall_mutation_rate_H_;\t\t\t\t\t\t// overall mutation rate (AFTER intersection with GEs)\n\tdouble overall_mutation_rate_M_;\t\t\t\t\t\t// overall mutation rate\n\tdouble overall_mutation_rate_F_;\t\t\t\t\t\t// overall mutation rate\n\t\n\tdouble overall_mutation_rate_H_userlevel_;\t\t\t\t// requested (un-adjusted) overall mutation rate (AFTER intersection with GEs)\n\tdouble overall_mutation_rate_M_userlevel_;\t\t\t\t// requested (un-adjusted) overall mutation rate\n\tdouble overall_mutation_rate_F_userlevel_;\t\t\t\t// requested (un-adjusted) overall mutation rate\n\t\n\tdouble overall_recombination_rate_H_;\t\t\t\t\t// overall recombination rate (reparameterized; see _InitializeOneRecombinationMap)\n\tdouble overall_recombination_rate_M_;\t\t\t\t\t// overall recombination rate (reparameterized; see _InitializeOneRecombinationMap)\n\tdouble overall_recombination_rate_F_;\t\t\t\t\t// overall recombination rate (reparameterized; see _InitializeOneRecombinationMap)\n\t\n\tdouble overall_recombination_rate_H_userlevel_;\t\t\t// overall recombination rate (unreparameterized; see _InitializeOneRecombinationMap)\n\tdouble overall_recombination_rate_M_userlevel_;\t\t\t// overall recombination rate (unreparameterized; see _InitializeOneRecombinationMap)\n\tdouble overall_recombination_rate_F_userlevel_;\t\t\t// overall recombination rate (unreparameterized; see _InitializeOneRecombinationMap)\n\t\n\tbool using_DSB_model_;\t\t\t\t\t\t\t\t\t// if true, we are using the DSB recombination model, involving the variables below\n\tdouble non_crossover_fraction_;\t\t\t\t\t\t\t// fraction of DSBs that do not result in crossover\n\tdouble gene_conversion_avg_length_;\t\t\t\t\t\t// average gene conversion stretch length\n\tdouble gene_conversion_inv_half_length_;\t\t\t\t// 1.0 / (gene_conversion_avg_length_ / 2.0), used for geometric draws\n\tdouble simple_conversion_fraction_;\t\t\t\t\t\t// fraction of gene conversion tracts that are \"simple\" (no heteroduplex mismatche repair)\n\tdouble mismatch_repair_bias_;\t\t\t\t\t\t\t// GC bias in heteroduplex mismatch repair in complex gene conversion tracts\n\tbool redraw_lengths_on_failure_;\t\t\t\t\t\t// if T, we redraw lengths, not only positions, if tract layout fails\n\t\n\tint32_t mutrun_count_base_;\t\t\t\t\t\t\t\t// minimum number of mutruns used (number of threads, typically); can be multiplied by a factor\n\tint32_t mutrun_count_multiplier_;\t\t\t\t\t\t// the current factor by which mutrun_count_base_ is multiplied; a power of two in [1, 1024]\n\tint32_t mutrun_count_;\t\t\t\t\t\t\t\t\t// the number of mutation runs being used for all haplosomes: base x multiplier\n\tslim_position_t mutrun_length_;\t\t\t\t\t\t\t// the length, in base pairs, of each mutation run; the last run might not use its full length\n\tslim_position_t last_position_mutrun_;\t\t\t\t\t// (mutrun_count_ * mutrun_length_ - 1), for complete coverage in crossover-mutation\n\t\n\tstd::string color_sub_;\t\t\t\t\t\t\t\t\t\t// color to use for substitutions by default (in SLiMgui)\n\tfloat color_sub_red_, color_sub_green_, color_sub_blue_;\t// cached color components from color_sub_; should always be in sync\n\t\n\t// nucleotide-based models\n\tNucleotideArray *ancestral_seq_buffer_ = nullptr;\n\tstd::vector<slim_position_t> hotspot_end_positions_H_;\t\t// end positions of each defined hotspot region (BEFORE intersection with GEs)\n\tstd::vector<slim_position_t> hotspot_end_positions_M_;\n\tstd::vector<slim_position_t> hotspot_end_positions_F_;\n\tstd::vector<double> hotspot_multipliers_H_;\t\t\t\t\t// hotspot multipliers (BEFORE intersection with GEs)\n\tstd::vector<double> hotspot_multipliers_M_;\n\tstd::vector<double> hotspot_multipliers_F_;\n\t\n\t// private scratch space for the use of Population::RemoveAllFixedMutations()\n\tstd::vector<MutationIndex> fixed_mutation_accumulator_;\n\t\n\tint8_t scratch_;\t\t\t\t\t\t\t\t\t// temporary scratch space for use by algorithms; regard as volatile outside your own code block\n\t\n\t// a user-defined tag value\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\n\t// PROFILING : Chromosome keeps track of some additional profile information that is per-chromosome\n#if (SLIMPROFILING == 1)\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tstd::vector<int32_t> profile_mutcount_history_;\t\t\t\t\t\t\t\t\t// a record of the mutation run count used in each cycle\n\tint64_t profile_mutation_total_usage_ = 0;\t\t\t\t\t\t\t\t\t\t// how many (non-unique) mutations were used by mutation runs, summed across cycles\n\tint64_t profile_nonneutral_mutation_total_ = 0;\t\t\t\t\t\t\t\t\t// of profile_mutation_total_usage_, how many were deemed to be nonneutral\n\tint64_t profile_mutrun_total_usage_ = 0;\t\t\t\t\t\t\t\t\t\t// how many (non-unique) mutruns were used by haplosomes, summed across cycles\n\tint64_t profile_unique_mutrun_total_ = 0;\t\t\t\t\t\t\t\t\t\t// of profile_mutrun_total_usage_, how many unique mutruns existed, summed across cycles\n\tint64_t profile_mutrun_nonneutral_recache_total_ = 0;\t\t\t\t\t\t\t// of profile_unique_mutrun_total_, how many mutruns regenerated their nonneutral cache\n#endif\t// SLIM_USE_NONNEUTRAL_CACHES\n#endif\t// (SLIMPROFILING == 1)\n\t\n\tChromosome(const Chromosome&) = delete;\t\t\t\t\t\t\t\t\t// no copying\n\tChromosome& operator=(const Chromosome&) = delete;\t\t\t\t\t\t// no copying\n\tChromosome(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t// no null constructor\n\t\n\texplicit Chromosome(Species &p_species, ChromosomeType p_type, int64_t p_id, std::string p_symbol, slim_chromosome_index_t p_index, int p_preferred_mutcount);\n\t~Chromosome(void);\n\t\n\tinline __attribute__((always_inline)) int64_t ID(void) const\t{ return id_; }\n\tinline __attribute__((always_inline)) const std::string &Symbol(void) const\t{ return symbol_; }\n\tinline __attribute__((always_inline)) slim_chromosome_index_t Index(void) const { return index_; }\n\tinline __attribute__((always_inline)) ChromosomeType Type(void) const { return type_; }\n\tinline __attribute__((always_inline)) const std::string &Name(void) const { return name_; }\n\tinline __attribute__((always_inline)) void SetName(const std::string &p_name) { name_ = p_name; }\n\t\n\tinline __attribute__((always_inline)) int IntrinsicPloidy(void) const { return intrinsic_ploidy_; }\n\tinline __attribute__((always_inline)) bool AlwaysUsesNullHaplosomes(void) const { return always_uses_null_haplosomes_; }\n\tinline __attribute__((always_inline)) bool IsSexChromosome(void) const { return is_sex_chromosome_; }\n\tinline __attribute__((always_inline)) bool DefaultsToZeroRecombination(void) const { return defaults_to_zero_recombination_; }\n\tinline __attribute__((always_inline)) const std::string &TypeString(void) const { return type_string_; }\n\t\n\tinline __attribute__((always_inline)) std::vector<GenomicElement *> &GenomicElements(void)\t\t\t{ return genomic_elements_; }\n\tinline __attribute__((always_inline)) const std::vector<GenomicElement *> &GenomicElements(void) const\t\t\t{ return genomic_elements_; }\n\tinline __attribute__((always_inline)) NucleotideArray *AncestralSequence(void) const\t\t\t\t\t\t{ return ancestral_seq_buffer_; }\n\t\n\t// initialize the random lookup tables used by Chromosome to draw mutation and recombination events\n\tvoid CreateNucleotideMutationRateMap(void);\n\tvoid InitializeDraws(void);\n\tvoid _InitializeOneRecombinationMap(gsl_ran_discrete_t *&p_lookup, std::vector<slim_position_t> &p_end_positions, std::vector<double> &p_rates, double &p_overall_rate, double &p_exp_neg_overall_rate, double &p_overall_rate_userlevel);\n\tvoid _InitializeOneMutationMap(gsl_ran_discrete_t *&p_lookup, std::vector<slim_position_t> &p_end_positions, std::vector<double> &p_rates, double &p_requested_overall_rate, double &p_overall_rate, double &p_exp_neg_overall_rate, std::vector<GESubrange> &p_subranges);\n\tvoid ChooseMutationRunLayout(void);\n\t\n\tinline bool UsingSingleRecombinationMap(void) const { return single_recombination_map_; }\n\tinline bool UsingSingleMutationMap(void) const { return single_mutation_map_; }\n\tinline size_t GenomicElementCount(void) const { return genomic_elements_.size(); }\n\t\n\t// draw the number of mutations that occur, based on the overall mutation rate\n\tint DrawMutationCount(IndividualSex p_sex) const;\n\t\n\t// draw a vector of mutation positions (and the corresponding GenomicElementType objects), which is sorted and uniqued for the caller\n\tint DrawSortedUniquedMutationPositions(int p_count, IndividualSex p_sex, std::vector<std::pair<slim_position_t, GenomicElement *>> &p_positions);\n\t\n\t// draw a new mutation, based on the genomic element types present and their mutational proclivities\n\tMutationIndex DrawNewMutation(std::pair<slim_position_t, GenomicElement *> &p_position, slim_objectid_t p_subpop_index, slim_tick_t p_tick) const;\n\t\n\t// draw a new mutation with reference to the genomic background upon which it is occurring, for nucleotide-based models and/or mutation() callbacks\n\tMutation *ApplyMutationCallbacks(Mutation *p_mut, Haplosome *p_haplosome, GenomicElement *p_genomic_element, int8_t p_original_nucleotide, std::vector<SLiMEidosBlock*> &p_mutation_callbacks) const;\n\tMutationIndex DrawNewMutationExtended(std::pair<slim_position_t, GenomicElement *> &p_position, slim_objectid_t p_subpop_index, slim_tick_t p_tick, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, slim_position_t *p_breakpoints, int p_breakpoints_count, std::vector<SLiMEidosBlock*> *p_mutation_callbacks) const;\n\t\n\t// draw the number of breakpoints that occur, based on the overall recombination rate\n\tint DrawBreakpointCount(IndividualSex p_sex) const;\n\t\n\t// choose a set of recombination breakpoints, based on recomb. intervals, overall recomb. rate, and gene\n\t// conversion parameters; DrawBreakpoints() is the high-level funnel that most callers should use, whereas\n\t// the low-level functions do not handle recombination() callbacks and other niceties\n\tvoid _DrawCrossoverBreakpoints(IndividualSex p_parent_sex, const int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers) const;\n\tvoid _DrawDSBBreakpoints(IndividualSex p_parent_sex, const int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers, std::vector<slim_position_t> &p_heteroduplex) const;\n\tvoid DrawBreakpoints(Individual *p_parent, Haplosome *p_haplosome1, Haplosome *p_haplosome2, int p_num_breakpoints, std::vector<slim_position_t> &p_crossovers, std::vector<slim_position_t> *p_heteroduplex, const char *p_caller_name);\n\t\n#ifndef USE_GSL_POISSON\n\t// draw both the mutation count and breakpoint count, using a single Poisson draw for speed\n\tvoid DrawMutationAndBreakpointCounts(IndividualSex p_sex, int *p_mut_count, int *p_break_count) const;\n\t\n\t// initialize the joint probabilities used by DrawMutationAndBreakpointCounts()\n\tvoid _InitializeJointProbabilities(double p_overall_mutation_rate, double p_exp_neg_overall_mutation_rate,\n\t\t\t\t\t\t\t\t\t\t\t\t   double p_overall_recombination_rate, double p_exp_neg_overall_recombination_rate,\n\t\t\t\t\t\t\t\t\t\t\t\t   double &p_both_0, double &p_both_0_OR_mut_0_break_non0, double &p_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0);\n#endif\n\t\n\t// looking up genomic elements quickly, by binary search\n\tGenomicElement *ElementForPosition(slim_position_t pos);\n\t\n\t// internal methods for throwing errors from inline functions when assumptions about the configuration of maps are violated\n\tvoid MutationMapConfigError(void) const __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\tvoid RecombinationMapConfigError(void) const __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsageForMutationMaps(void);\n\tsize_t MemoryUsageForRecombinationMaps(void);\n\tsize_t MemoryUsageForAncestralSequence(void);\n\t\n\t// Make a null haplosome, which is associated with an individual, but has no associated chromosome, or\n\t// make a non-null haplosome, which is associated with an individual and has an associated chromosome\n\tHaplosome *NewHaplosome_NULL(Individual *p_individual, uint8_t p_chromosome_subposition);\n\tHaplosome *NewHaplosome_NONNULL(Individual *p_individual, uint8_t p_chromosome_subposition);\n\tvoid FreeHaplosome(Haplosome *p_haplosome);\n\t\n\tconst std::vector<Haplosome *> &HaplosomesJunkyardNonnull(void) { return haplosomes_junkyard_nonnull; }\n\tconst std::vector<Haplosome *> &HaplosomesJunkyardNull(void) { return haplosomes_junkyard_null; }\n\n\t// Mutation run contexts: each chromosome keeps per-thread \"contexts\" out of which mutation runs get allocated, and\n\t// into which they get freed.  This eliminates between-thread locking when working with mutation runs.\n\tvoid SetUpMutationRunContexts(void);\n\t\n#ifndef _OPENMP\n\tinline int ChromosomeMutationRunContextCount(void) { return 1; }\n\tinline __attribute__((always_inline)) MutationRunContext &ChromosomeMutationRunContextForThread(__attribute__((unused)) int p_thread_num)\n\t{\n#if DEBUG\n\t\tif (p_thread_num != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChromosomeMutationRunContextForThread): (internal error) p_thread_num out of range.\" << EidosTerminate();\n#endif\n\t\treturn mutation_run_context_SINGLE_;\n\t}\n\tinline __attribute__((always_inline)) MutationRunContext &ChromosomeMutationRunContextForMutationRunIndex(__attribute__((unused)) slim_mutrun_index_t p_mutrun_index)\n\t{\n#if DEBUG\n\t\tif ((p_mutrun_index < 0) || (p_mutrun_index >= mutrun_count_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChromosomeMutationRunContextForMutationRunIndex): (internal error) p_mutrun_index out of range.\" << EidosTerminate();\n#endif\n\t\treturn mutation_run_context_SINGLE_;\n\t}\n#else\n\tinline int ChromosomeMutationRunContextCount(void) { return mutation_run_context_COUNT_; }\n\tinline __attribute__((always_inline)) MutationRunContext &ChromosomeMutationRunContextForThread(int p_thread_num)\n\t{\n#if DEBUG\n\t\tif ((p_thread_num < 0) || (p_thread_num >= mutation_run_context_COUNT_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChromosomeMutationRunContextForThread): (internal error) p_thread_num out of range.\" << EidosTerminate();\n#endif\n\t\treturn *(mutation_run_context_PERTHREAD[p_thread_num]);\n\t}\n\tinline __attribute__((always_inline)) MutationRunContext &ChromosomeMutationRunContextForMutationRunIndex(__attribute__((unused)) slim_mutrun_index_t p_mutrun_index)\n\t{\n#if DEBUG\n\t\tif ((p_mutrun_index < 0) || (p_mutrun_index >= mutrun_count_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Chromosome::ChromosomeMutationRunContextForMutationRunIndex): (internal error) p_mutrun_index out of range.\" << EidosTerminate();\n#endif\n\t\t// The range of the haplosome that each thread is responsible for does not change across\n\t\t// splits/joins; one mutrun becomes two, or two become one, owned by the same thread\n\t\tint thread_num = (int)(p_mutrun_index / mutrun_count_multiplier_);\n\t\treturn *(mutation_run_context_PERTHREAD[thread_num]);\n\t}\n#endif\n\t\n\t// Mutation run experiments\n\tvoid InitiateMutationRunExperiments(void);\n\tvoid ZeroMutationRunExperimentClock(void);\n\tvoid FinishMutationRunExperimentTiming(void);\n\tvoid PrintMutationRunExperimentSummary(void);\n\tinline __attribute__((always_inline)) bool MutationRunExperimentsEnabled(void) { return x_experiments_enabled_; }\n\t\n\t// Mutation run experiment timing.  We use these methods to accumulate clocks taken in critical sections of the code.\n\t// Note that this design does NOT include time taken in first()/early()/late() events; since script blocks can do very\n\t// different work from one cycle to the next, this seems best, although it does mean that the impact of the number\n\t// of mutation runs on the execution time of Eidos events is not measured.\n\tinline __attribute__((always_inline)) void StartMutationRunExperimentClock(void)\n\t{\n\t\tif (x_experiments_enabled_)\n\t\t{\n#if DEBUG\n\t\t\tif (x_clock_running_)\n\t\t\t\tstd::cerr << \"WARNING: mutation run experiment clock was started when already running!\";\n\t\t\tif (!x_within_measurement_period_)\n\t\t\t\tstd::cerr << \"WARNING: mutation run experiment clock started outside the measurement period!\";\n#endif\n\t\t\tx_clock_running_ = true;\n\t\t\tx_current_clock_ = Eidos_BenchmarkTime();\n\t\t}\n\t}\n\t\n\tinline __attribute__((always_inline)) void StopMutationRunExperimentClock(__attribute__((unused)) const char *p_caller_name)\n\t{\n\t\tif (x_experiments_enabled_)\n\t\t{\n\t\t\teidos_profile_t end_clock = Eidos_BenchmarkTime();\n\t\t\t\n#if DEBUG\n\t\t\tif (!x_clock_running_)\n\t\t\t\tstd::cerr << \"WARNING: mutation run experiment clock was stopped when not running!\";\n\t\t\tif (!x_within_measurement_period_)\n\t\t\t\tstd::cerr << \"WARNING: mutation run experiment clock stopped outside the measurement period!\";\n#endif\n\t\t\t\n#if MUTRUN_EXPERIMENT_TIMING_OUTPUT\n\t\t\t// this log generates an unreasonable amount of output and is not usually desirable\n\t\t\t//std::cout << \"   tick \" << community_.Tick() << \", chromosome \" << id_ << \": mutrun experiment clock for \" << p_caller_name << \" count == \" << (end_clock - x_current_clock_) << std::endl;\n#endif\n\t\t\t\n\t\t\tx_clock_running_ = false;\n\t\t\tx_total_gen_clocks_ += (end_clock - x_current_clock_);\n\t\t\tx_current_clock_ = 0;\n\t\t}\n\t}\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_ancestralNucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_genomicElementForPosition(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_hasGenomicElementForPosition(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setAncestralNucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setGeneConversion(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setHotspotMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setMutationRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setRecombinationRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_drawBreakpoints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\n// draw the number of mutations that occur, based on the overall mutation rate\ninline __attribute__((always_inline)) int Chromosome::DrawMutationCount(IndividualSex p_sex) const\n{\n#ifdef USE_GSL_POISSON\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (single_mutation_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\treturn gsl_ran_poisson(rng, overall_mutation_rate_H_);\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\treturn gsl_ran_poisson(rng, overall_mutation_rate_M_);\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\treturn gsl_ran_poisson(rng, overall_mutation_rate_F_);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tMutationMapConfigError();\n\t\t}\n\t}\n#else\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\n\tif (single_mutation_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\treturn Eidos_FastRandomPoisson(rng_state, overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_);\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\treturn Eidos_FastRandomPoisson(rng_state, overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_);\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\treturn Eidos_FastRandomPoisson(rng_state, overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tMutationMapConfigError();\n\t\t}\n\t}\n#endif\n}\n\n// draw the number of breakpoints that occur, based on the overall recombination rate\ninline __attribute__((always_inline)) int Chromosome::DrawBreakpointCount(IndividualSex p_sex) const\n{\n#ifdef USE_GSL_POISSON\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (single_recombination_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\treturn gsl_ran_poisson(rng, overall_recombination_rate_H_);\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\treturn gsl_ran_poisson(rng, overall_recombination_rate_M_);\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\treturn gsl_ran_poisson(rng, overall_recombination_rate_F_);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRecombinationMapConfigError();\n\t\t}\n\t}\n#else\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\n\tif (single_recombination_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled\n\t\treturn Eidos_FastRandomPoisson(rng_state, overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_);\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\treturn Eidos_FastRandomPoisson(rng_state, overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_);\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\treturn Eidos_FastRandomPoisson(rng_state, overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRecombinationMapConfigError();\n\t\t}\n\t}\n#endif\n}\n\n#ifndef USE_GSL_POISSON\n// determine both the mutation count and the breakpoint count with (usually) a single RNG draw\n// this method relies on Eidos_FastRandomPoisson_NONZERO() and cannot be called when USE_GSL_POISSON is defined\ninline __attribute__((always_inline)) void Chromosome::DrawMutationAndBreakpointCounts(IndividualSex p_sex, int *p_mut_count, int *p_break_count) const\n{\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\tdouble u = Eidos_rng_uniform_doubleCO(rng_64);\n\t\n\tif (single_recombination_map_ && single_mutation_map_)\n\t{\n\t\t// With a single map, we don't care what sex we are passed; same map for all, and sex may be enabled or disabled.\n\t\t// We use the _H_ variants of all ivars in this case, which are all that is set up.\n\t\tif (u <= probability_both_0_H_)\n\t\t{\n\t\t\t*p_mut_count = 0;\n\t\t\t*p_break_count = 0;\n\t\t}\n\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_H_)\n\t\t{\n\t\t\t*p_mut_count = 0;\n\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_);\n\t\t}\n\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_H_)\n\t\t{\n\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_);\n\t\t\t*p_break_count = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_H_, exp_neg_overall_mutation_rate_H_);\n\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_H_, exp_neg_overall_recombination_rate_H_);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// With sex-specific maps, we treat males and females separately, and the individual we're given better be one of the two.\n\t\t// We use the _M_ and _F_ variants in this case; either the mutation map or the recombination map might be non-sex-specific,\n\t\t// so the _H_ variants were originally set up, but InitializeDraws() copies them into the _M_ and _F_ variants for us\n\t\t// so that we don't have to worry about finding the correct variant for each subcase of single/double maps.\n\t\tif (p_sex == IndividualSex::kMale)\n\t\t{\n\t\t\tif (u <= probability_both_0_M_)\n\t\t\t{\n\t\t\t\t*p_mut_count = 0;\n\t\t\t\t*p_break_count = 0;\n\t\t\t}\n\t\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_M_)\n\t\t\t{\n\t\t\t\t*p_mut_count = 0;\n\t\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_);\n\t\t\t}\n\t\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_M_)\n\t\t\t{\n\t\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_);\n\t\t\t\t*p_break_count = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_M_, exp_neg_overall_mutation_rate_M_);\n\t\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_M_, exp_neg_overall_recombination_rate_M_);\n\t\t\t}\n\t\t}\n\t\telse if (p_sex == IndividualSex::kFemale)\n\t\t{\n\t\t\tif (u <= probability_both_0_F_)\n\t\t\t{\n\t\t\t\t*p_mut_count = 0;\n\t\t\t\t*p_break_count = 0;\n\t\t\t}\n\t\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_F_)\n\t\t\t{\n\t\t\t\t*p_mut_count = 0;\n\t\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_);\n\t\t\t}\n\t\t\telse if (u <= probability_both_0_OR_mut_0_break_non0_OR_mut_non0_break_0_F_)\n\t\t\t{\n\t\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_);\n\t\t\t\t*p_break_count = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*p_mut_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_mutation_rate_F_, exp_neg_overall_mutation_rate_F_);\n\t\t\t\t*p_break_count = Eidos_FastRandomPoisson_NONZERO(rng_state, overall_recombination_rate_F_, exp_neg_overall_recombination_rate_F_);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRecombinationMapConfigError();\n\t\t}\n\t}\n}\n#endif\n\n// defer this include until now, to resolve mutual dependencies\n#include \"haplosome.h\"\n\ninline __attribute__((always_inline)) Haplosome *Chromosome::NewHaplosome_NULL(Individual *p_individual, uint8_t p_chromosome_subposition)\n{\n\tif (haplosomes_junkyard_null.size())\n\t{\n\t\tHaplosome *back = haplosomes_junkyard_null.back();\n\t\thaplosomes_junkyard_null.pop_back();\n\t\t\n\t\t//back->chromosome_index_ = index_;\t\t// guaranteed already set\n\t\tback->chromosome_subposition_ = p_chromosome_subposition;\n\t\tback->individual_ = p_individual;\n\t\treturn back;\n\t}\n\t\n\tHaplosome *hap = _NewHaplosome_NULL(p_individual);\n\thap->chromosome_subposition_ = p_chromosome_subposition;\n\treturn hap;\n}\n\ninline __attribute__((always_inline)) Haplosome *Chromosome::NewHaplosome_NONNULL(Individual *p_individual, uint8_t p_chromosome_subposition)\n{\n\tif (haplosomes_junkyard_nonnull.size())\n\t{\n\t\tHaplosome *back = haplosomes_junkyard_nonnull.back();\n\t\thaplosomes_junkyard_nonnull.pop_back();\n\t\t\n\t\t// Conceptually, we want to call ReinitializeHaplosomeNoClear() to set the haplosome up with the\n\t\t// current type, mutrun setup, etc.  But we know that the haplosome is nonnull, and that we\n\t\t// want it to be nonnull, so we can do less work than ReinitializeHaplosomeNoClear(), inline.\n\t\tif (back->mutrun_count_ != mutrun_count_)\n\t\t{\n\t\t\t// the number of mutruns has changed; need to reallocate\n\t\t\tif (back->mutruns_ != back->run_buffer_)\n\t\t\t\tfree(back->mutruns_);\n\t\t\t\n\t\t\tback->mutrun_count_ = mutrun_count_;\n\t\t\tback->mutrun_length_ = mutrun_length_;\n\t\t\t\n\t\t\tif (mutrun_count_ <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t\t{\n\t\t\t\tback->mutruns_ = back->run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\tEIDOS_BZERO(back->run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\tback->mutruns_ = (const MutationRun **)calloc(mutrun_count_, sizeof(const MutationRun *));\n#else\n\t\t\t\tback->mutruns_ = (const MutationRun **)malloc(mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t// the number of mutruns is unchanged, but we need to zero out the reused buffer here\n\t\t\tEIDOS_BZERO(back->mutruns_, mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t\t\n\t\t//back->chromosome_index_ = index_;\t\t// guaranteed already set\n\t\tback->chromosome_subposition_ = p_chromosome_subposition;\n\t\tback->individual_ = p_individual;\n\t\treturn back;\n\t}\n\t\n\tHaplosome *hap = _NewHaplosome_NONNULL(p_individual);\n\thap->chromosome_subposition_ = p_chromosome_subposition;\n\treturn hap;\n}\n\n// Frees a haplosome object (puts it in one of the junkyards); we do not clear the mutrun buffer, so it must be cleared when reused!\ninline __attribute__((always_inline)) void Chromosome::FreeHaplosome(Haplosome *p_haplosome)\n{\n#if DEBUG\n\tp_haplosome->individual_ = nullptr;\t\t// crash if anybody tries to use this pointer after the free\n#endif\n#if SLIM_CLEAR_HAPLOSOMES\n\tp_haplosome->clear_to_nullptr();\n#endif\n\t\n\t// somebody needs to reset the tag value of reused haplosomes; it might as well be us\n\t// this used to be done by Individual::Individual(), which got passed the individual's haplosomes\n\t// FIXME: this should only get cleared, in bulk, based on a flag, like individual tag values; big waste of time;\n\t// FIXME: see s_any_haplosome_tag_set_, we are already doing this in SwapChildAndParentHaplosomes() for WF\n\tp_haplosome->tag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\n\tif (p_haplosome->IsNull())\n\t\thaplosomes_junkyard_null.emplace_back(p_haplosome);\n\telse\n\t\thaplosomes_junkyard_nonnull.emplace_back(p_haplosome);\n}\n\n\nclass Chromosome_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tChromosome_Class(const Chromosome_Class &p_original) = delete;\t// no copy-construct\n\tChromosome_Class& operator=(const Chromosome_Class&) = delete;\t// no copying\n\tinline Chromosome_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__chromosome__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/community.cpp",
    "content": "//\n//  community.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 2/28/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"community.h\"\n#include \"species.h\"\n#include \"slim_functions.h\"\n#include \"eidos_test.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_ast_node.h\"\n#include \"individual.h\"\n#include \"polymorphism.h\"\n#include \"subpopulation.h\"\n#include \"interaction_type.h\"\n#include \"log_file.h\"\n\n#include <iostream>\n#include <iomanip>\n#include <fstream>\n#include <stdexcept>\n#include <algorithm>\n#include <typeinfo>\n#include <memory>\n#include <string>\n#include <map>\n#include <utility>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <unordered_set>\n#include <unordered_map>\n#include <float.h>\n#include <ctime>\n#include <limits>\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\n#endif\n\n//TREE SEQUENCE\n#include <stdio.h>\n#include <stdlib.h>\n#include \"json.hpp\"\n#include <sys/utsname.h>\n\n//TREE SEQUENCE\n//INCLUDE MSPRIME.H FOR THE CROSSCHECK CODE; NEEDS TO BE MOVED TO TSKIT\n// the tskit header is not designed to be included from C++, so we have to protect it...\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include \"kastore.h\"\n#include \"../treerec/tskit/trees.h\"\n#include \"../treerec/tskit/tables.h\"\n#include \"../treerec/tskit/genotypes.h\"\n#include \"../treerec/tskit/text_input.h\"\n#ifdef __cplusplus\n}\n#endif\n\n\n#pragma mark -\n#pragma mark Community\n#pragma mark -\n\nCommunity::Community(void) : self_symbol_(gID_community, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Community_Class)))\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\t// BCH 3/16/2022: We used to allocate the Species object here, as the first thing we did.  In SLiM 4 there can\n\t// be multiple species and they can have names other than \"sim\", so we delay species creation until parse time.\n\t\n\t// set up the symbol tables we will use for global variables and constants; note that the global variables table\n\t// lives *above* the context constants table, which is fine since they cannot define the same symbol anyway\n\t// this satisfies Eidos, which expects the child of the intrinsic constants table to be the global variables table\n\tsimulation_globals_ = new EidosSymbolTable(EidosSymbolTableType::kGlobalVariablesTable, gEidosConstantsSymbolTable);\n\tsimulation_constants_ = new EidosSymbolTable(EidosSymbolTableType::kContextConstantsTable, simulation_globals_);\n\t\n\t// set up the function map with the base Eidos functions plus zero-gen functions, since we're in an initial state\n\tsimulation_functions_ = *EidosInterpreter::BuiltInFunctionMap();\n\tAddZeroTickFunctionsToMap(simulation_functions_);\n\tAddSLiMFunctionsToMap(simulation_functions_);\n\t\n\t// reading from the input file is deferred to InitializeFromFile() to make raise-handling simpler - finish construction\n\t\n\t// BCH 3/21/2025: Note that tick_ == -1 at this point, now, so we can differentiate construction from initialize()\n\t// It gets set to 0 in Community::FinishInitialization(), when we finish with the construction phase.\n}\n\nCommunity::~Community(void)\n{\n\t//EIDOS_ERRSTREAM << \"Community::~Community\" << std::endl;\n\t\n\t// our log file registry retains all log files\n\tfor (LogFile *log_file : log_file_registry_)\n\t\tlog_file->Release();\n\tlog_file_registry_.clear();\n\t\n\tall_mutation_types_.clear();\n\tall_genomic_element_types_.clear();\n\t\n\tfor (auto interaction_type : interaction_types_)\n\t\tdelete interaction_type.second;\n\tinteraction_types_.clear();\n\t\n\tdelete simulation_globals_;\n\tsimulation_globals_ = nullptr;\n\t\n\tdelete simulation_constants_;\n\tsimulation_constants_ = nullptr;\n\t\n\tsimulation_functions_.clear();\n\t\n\tfor (auto script_block : script_blocks_)\n\t\tdelete script_block;\n\tscript_blocks_.clear();\n\t\n\t// All the script blocks that refer to the script are now gone\n\tdelete script_;\n\tscript_ = nullptr;\n\t\n\t// delete the Species last, after everything that might refer to Species state is gone\n\tfor (Species *species : all_species_)\n\t\tdelete species;\n}\n\nvoid Community::InitializeRNGFromSeed(unsigned long int *p_override_seed_ptr)\n{\n\t// track the random number seed given, if there is one\n\tunsigned long int rng_seed = (p_override_seed_ptr ? *p_override_seed_ptr : Eidos_GenerateRNGSeed());\n\t\n\tEidos_SetRNGSeed(rng_seed);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_OUTSTREAM << \"// Initial random seed:\\n\" << rng_seed << \"\\n\" << std::endl;\n\t\n\t// remember the original seed for .trees provenance\n\toriginal_seed_ = rng_seed;\n}\n\nvoid Community::InitializeFromFile(std::istream &p_infile)\n{\n\tp_infile.clear();\n\tp_infile.seekg(0, std::fstream::beg);\n\t\n\t// Reset error position indicators used by SLiMgui\n\tClearErrorPosition();\n\t\n\t// Read in the file; going through stringstream is fast...\n\tstd::stringstream buffer;\n\t\n\tbuffer << p_infile.rdbuf();\n\t\n\t// Tokenize and parse\n\t// BCH 5/1/2019: Note that this script_ variable may leak if tokenization/parsing raises below, because this method\n\t// is called while the Community constructor is still in progress, so the destructor is not called to clean up.  But\n\t// we can't actually clean up this variable, because it is used by SLiMAssertScriptRaise() to diagnose where the raise\n\t// occurred in the user's script; we'd have to redesign that code to fix this leak.  So be it.  It's not a large leak.\n\tscript_ = new SLiMEidosScript(buffer.str());\n\t\n\t// Set up top-level error-reporting info\n\tgEidosErrorContext.currentScript = script_;\n\t\n\tscript_->Tokenize();\n\tscript_->ParseSLiMFileToAST();\n\t\n\tconst EidosASTNode *root_node = script_->AST();\n\t\n\t// BCH 3/16/2022: The logic here used to be quite simple: loop over the parsed AST and make script blocks.  In SLiM 4\n\t// the top-level file structure is more complicated, because of species and ticks specifiers that can modify the\n\t// declared blocks.  Rather than making those part of the EidosASTNodes for the blocks themselves (which already have\n\t// a very complex internal structure), I have chosen to make them separate top-level nodes that modify the meaning\n\t// of the SLiMEidosBlock node that follows them.  That makes doing the parse, validating the file structure, creating\n\t// the species objects, and then creating the script blocks fairly complex.  That complexity is handled here.  Since\n\t// the logic here is rather complex, I have put in redundant checks to try to make sure nothing falls between the\n\t// cracks.  Errors that start with \"(internal error)\" should never be hit, as usual; those error cases ought to be\n\t// caught by earlier checks, unless I have missed a possible code path.\n\t\n\t// Assess the top-level structure and enforce semantics that can be enforced before knowing species names/declarations\n\t// Species are declared with initialize() callbacks of the form \"species <identifier> initialize()\"\n\tbool pending_species_spec = false, pending_ticks_spec = false;\n\tstd::string pending_spec_species_name;\n\tstd::vector<std::string> explicit_species_decl_names;\t\t// names from \"species <name> initialize()\" declarations\n\tint implied_species_decl_count = 0;\t\t\t\t\t\t\t// number of \"initialize()\" seen without \"species <name>\"\n\t\n\tfor (EidosASTNode *script_block_node : root_node->children_)\n\t{\n\t\tif (script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\t// If we already have a pending specifier then we now have two specifiers in a row\n\t\t\tif (pending_species_spec)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): a species specifier must be followed by a callback declaration.\" << EidosTerminate(script_block_node->token_);\n\t\t\tif (pending_ticks_spec)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): a ticks specifier must be followed by an event declaration.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\n\t\t\tif (script_block_node->children_.size() == 1)\n\t\t\t{\n\t\t\t\tpending_spec_species_name = script_block_node->children_[0]->token_->token_string_;\n\t\t\t\t\n\t\t\t\tif (script_block_node->token_->token_string_.compare(gStr_species) == 0)\n\t\t\t\t{\n\t\t\t\t\t//std::cout << \"species specifier seen: \" << pending_spec_species_name << std::endl;\n\t\t\t\t\tpending_species_spec = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (script_block_node->token_->token_string_.compare(gStr_ticks) == 0)\n\t\t\t\t{\n\t\t\t\t\t//std::cout << \"ticks specifier seen: \" << pending_spec_species_name << std::endl;\n\t\t\t\t\tpending_ticks_spec = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): unexpected top-level token \" << script_block_node->token_->token_string_ << \".\" << EidosTerminate(script_block_node->token_);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSLiMEidosBlockType type = SLiMEidosBlock::BlockTypeForRootNode(script_block_node);\n\t\t\t\n\t\t\tif (type == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t{\n\t\t\t\tif (pending_species_spec || pending_ticks_spec)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): user-defined functions may not be preceded by a species or ticks specifier.\" << EidosTerminate(script_block_node->token_);\n\t\t\t}\n\t\t\telse if ((type == SLiMEidosBlockType::SLiMEidosEventFirst) || (type == SLiMEidosBlockType::SLiMEidosEventEarly) || (type == SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t\t{\n\t\t\t\tif (pending_species_spec)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): event declarations may not be preceded by a species specifier; use a ticks specifier to designate an event as running only in the ticks when a particular species is active.\" << EidosTerminate(script_block_node->token_);\n\t\t\t}\n\t\t\telse if (type != SLiMEidosBlockType::SLiMEidosNoBlockType)\t// callbacks\n\t\t\t{\n\t\t\t\tif (pending_ticks_spec)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): callback declarations may not be preceded by a ticks specifier; use a species specifier to designate a callback as being associated with a particular species.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\t\n\t\t\t\tif (type == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t\t\t\t{\n\t\t\t\t\tif (pending_species_spec)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We have an explicit species declaration, \"species <name> initialize()\", so this is a multispecies model\n\t\t\t\t\t\tif (implied_species_decl_count > 0)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): an initialize() callback without a species specifier has previously been seen, so this is a single-species script, and therefore species specifiers are illegal.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// You can have multiple initialize() callbacks for a given species, but we want to tally the name just once; could use std::set instead but we want ordering\n\t\t\t\t\t\t// Note that `species all` is logged as a species name here; we will handle it separately below\n\t\t\t\t\t\tif (std::find(explicit_species_decl_names.begin(), explicit_species_decl_names.end(), pending_spec_species_name) == explicit_species_decl_names.end())\n\t\t\t\t\t\t\texplicit_species_decl_names.push_back(pending_spec_species_name);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// We have an implicit species declaration, \"initialize()\", so this is a single-species model\n\t\t\t\t\t\tif (explicit_species_decl_names.size() > 0)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): an initialize() callback with a species specifier has previously been seen, so this is a multi-species script, and therefore species specifiers are required.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\timplied_species_decl_count++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (type == SLiMEidosBlockType::SLiMEidosInteractionCallback)\n\t\t\t\t{\n\t\t\t\t\tif (pending_species_spec && (pending_spec_species_name != \"all\"))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): interaction() callbacks must be declared with 'species all' in multispecies models; they are never species-specific.\" << EidosTerminate(script_block_node->children_[0]->token_);\n\t\t\t\t}\n\t\t\t\telse\t// all other callback types\n\t\t\t\t{\n\t\t\t\t\tif (pending_species_spec && (pending_spec_species_name == \"all\"))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): \" << type << \" callbacks may not be declared with 'species all'; they are always species-specific.\" << EidosTerminate(script_block_node->children_[0]->token_);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t//std::cout << \"script block seen of type \" << type << std::endl;\n\t\t\t\n\t\t\tpending_species_spec = false;\n\t\t\tpending_ticks_spec = false;\n\t\t}\n\t}\n\t\n\t// Create species objects for each declared species, or \"sim\" if there was only an implied species declaration\n\tif ((implied_species_decl_count > 0) && (explicit_species_decl_names.size() > 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) all initialize() callbacks must either (1) be preceded by a species specifier, for multi-species models, or (2) not be preceded by a species specifier, for single-species models.\" << EidosTerminate(nullptr);\n\tif ((implied_species_decl_count == 0) && (explicit_species_decl_names.size() == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): no initialize() callback found; at least one initialize() callback is required in all SLiM scripts.\" << EidosTerminate(nullptr);\n\tif ((explicit_species_decl_names.size() == 1) && (explicit_species_decl_names[0] == \"all\"))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): no species-specific initialize() callback found; at least one species-specific initialize() callback is required in all SLiM scripts.\" << EidosTerminate(nullptr);\n\t\n\tif (implied_species_decl_count > 0)\n\t{\n\t\t// This is the single-species case; create a species named \"sim\"\n\t\tall_species_.push_back(new Species(*this, 0, gStr_sim));\n\t\t\n\t\tis_explicit_species_ = false;\n\t}\n\telse\n\t{\n\t\t// This is the multi-species case; create a species for each explicit declaration except `species all`\n\t\tint species_id = 0;\n\t\t\n\t\tfor (std::string &species_name : explicit_species_decl_names)\n\t\t\tif (species_name != \"all\")\n\t\t\t\tall_species_.push_back(new Species(*this, species_id++, species_name));\n\t\t\n\t\tis_explicit_species_ = true;\n\t}\n\t\n\t// Extract SLiMEidosBlocks from the parse tree\n\tSpecies *last_species_spec = nullptr, *last_ticks_spec = nullptr;\n\tbool last_spec_is_ticks_all = false;\t// \"ticks all\" is a special syntax; there is no species named \"all\" so it must be tracked with a separate flag\n\tbool last_spec_is_species_all = false;\t// \"species all\" is a special syntax; there is no species named \"all\" so it must be tracked with a separate flag\n\t\n\tfor (EidosASTNode *script_block_node : root_node->children_)\n\t{\n\t\tif ((script_block_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (script_block_node->children_.size() == 1))\n\t\t{\n\t\t\t// A \"species <identifier>\" or \"ticks <identifier>\" specification is present; remember what it specified\n\t\t\tEidosASTNode *child = script_block_node->children_[0];\n\t\t\tconst std::string &species_name = child->token_->token_string_;\n\t\t\tbool species_is_all = (species_name.compare(\"all\") == 0);\n\t\t\tSpecies *species = (species_is_all ? nullptr : SpeciesWithName(species_name));\n\t\t\t\n\t\t\tif (!species && !species_is_all)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): undeclared species name \" << species_name << \"; species must be explicitly declared with a species <name> specifier on an initialize() block.\" << EidosTerminate(child->token_);\n\t\t\t\n\t\t\tif (script_block_node->token_->token_string_.compare(gStr_species) == 0)\n\t\t\t{\n\t\t\t\tif (!is_explicit_species_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): no species have been explicitly declared, so species specifiers should not be used.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\t\n\t\t\t\tlast_species_spec = species;\n\t\t\t\tlast_spec_is_species_all = species_is_all;\n\t\t\t}\n\t\t\telse if (script_block_node->token_->token_string_.compare(gStr_ticks) == 0)\n\t\t\t{\n\t\t\t\tif (!is_explicit_species_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): no species have been explicitly declared, so ticks specifiers should not be used.\" << EidosTerminate(script_block_node->token_);\n\t\t\t\t\n\t\t\t\tlast_ticks_spec = species;\n\t\t\t\tlast_spec_is_ticks_all = species_is_all;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_block_node);\n\t\t\t\n\t\t\tif (new_script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t{\n\t\t\t\t// User-defined functions may not have a species or ticks specifier preceding them; this was already checked above\n\t\t\t\tif (last_species_spec || last_ticks_spec || last_spec_is_ticks_all || last_spec_is_species_all)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) user-defined functions may not be preceded by a species or ticks specifier.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t}\n\t\t\telse if ((new_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventFirst) ||\n\t\t\t\t(new_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventEarly) ||\n\t\t\t\t(new_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t\t{\n\t\t\t\t// Events may have a ticks specifier, but not a species specifier, preceding them; this was already checked above\n\t\t\t\tif (last_species_spec || last_spec_is_species_all)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) event declarations may not be preceded by a species specifier.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t{\n\t\t\t\t\tSpecies *block_ticks = last_ticks_spec;\n\t\t\t\t\t\n\t\t\t\t\tif (!block_ticks && !last_spec_is_ticks_all)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): when species names have been explicitly declared (such as in multispecies models), every event must be preceded by a ticks specifier of the form 'ticks <species-name>'; if you want an event to run in every tick, specify 'ticks all'.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\t\n\t\t\t\t\tnew_script_block->ticks_spec_ = block_ticks;\t// nullptr for \"ticks all\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnew_script_block->ticks_spec_ = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Callbacks of all types may not be preceded by a ticks specifier; this was already checked above\n\t\t\t\tif (last_ticks_spec || last_spec_is_ticks_all)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) callback declarations may not be preceded by a ticks specifier.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\n\t\t\t\t// Callbacks of all types may not be preceded by a species specifier in single-species models; this was already checked above\n\t\t\t\tif (!is_explicit_species_ && (last_species_spec || last_spec_is_species_all))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) callback declarations may not be preceded by a species specifier in single-species models.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\n\t\t\t\t// Callbacks of all types must be preceded by a species specifier in multispecies models\n\t\t\t\tif (is_explicit_species_ && !(last_species_spec || last_spec_is_species_all))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): when species names have been explicitly declared (as in multispecies models), every callback must be preceded by a species specifier of the form 'species <species-name>'; for non-species-specific initialize() and interaction() callbacks, specify 'species all'.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\n\t\t\t\tSpecies *block_species = (is_explicit_species_ ? last_species_spec : all_species_[0]);\t// nullptr for `species all`\n\t\t\t\t\n\t\t\t\tif (new_script_block->type_ == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t\t\t\t{\n\t\t\t\t\t// In multispecies models, initialize() callbacks may be `species all` or `species name`; no action needed\n\t\t\t\t}\n\t\t\t\telse if (new_script_block->type_ == SLiMEidosBlockType::SLiMEidosInteractionCallback)\n\t\t\t\t{\n\t\t\t\t\t// interaction() callbacks must be \"species all\"; this was already checked above\n\t\t\t\t\tif (is_explicit_species_ && block_species)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) interaction() callbacks in multispecies models must be declared with 'species all'; they are never species-specific.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t\t\n\t\t\t\t\t// In single-species models, the above default needs correction\n\t\t\t\t\tif (!is_explicit_species_)\n\t\t\t\t\t\tblock_species = nullptr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Other callback types may not be `species all`; this was already checked above\n\t\t\t\t\tif (last_spec_is_species_all)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::InitializeFromFile): (internal error) \" << new_script_block->type_ << \" callbacks may not be declared with 'species all'; they are always species-specific.\" << EidosTerminate(new_script_block->root_node_->token_);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tnew_script_block->species_spec_ = block_species;\n\t\t\t}\n\t\t\t\n\t\t\tAddScriptBlock(new_script_block, nullptr, new_script_block->root_node_->children_[0]->token_);\n\t\t\t\n\t\t\tlast_species_spec = nullptr;\n\t\t\tlast_ticks_spec = nullptr;\n\t\t\tlast_spec_is_ticks_all = false;\n\t\t\tlast_spec_is_species_all = false;\n\t\t}\n\t}\n\t\n\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\tClearErrorContext();\n}\n\nvoid Community::FinishInitialization(void)\n{\n\t// BCH 7/19/2024: At the very end of initialization of the Community, after script blocks\n\t// have been parsed, command-line constants have been defined, etc., we evaluate tick\n\t// ranges for script blocks for the first time.  Anything that doesn't involve\n\t// defined constants, or involves constants defined on the command line, can already\n\t// be evaluated at this time, which makes the appearance of things in SLiMgui cleaner.\n\tif (!all_tick_ranges_evaluated_)\n\t{\n\t\t// Set up top-level error-reporting info\n\t\tgEidosErrorContext.currentScript = script_;\n\t\t\n\t\t// Do the tick range evaluation work\n\t\tEvaluateScriptBlockTickRanges();\n\t\t\n\t\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\t\tClearErrorContext();\n\t}\n\t\n\t// We have been in the \"construction\" phase, with tick_ == -1 as set in the header.\n\t// Now we're done with construction, and set the tick counter to 0 for \"initialization\".\n\ttick_ = 0;\n}\n\nvoid Community::ValidateScriptBlockCaches(void)\n{\n#if DEBUG_BLOCK_REG_DEREG\n\tstd::cout << \"Tick \" << tick_ << \": ValidateScriptBlockCaches() called...\" << std::endl;\n#endif\n\t\n\tif (!script_block_types_cached_)\n\t{\n\t\tcached_first_events_.clear();\n\t\tcached_early_events_.clear();\n\t\tcached_late_events_.clear();\n\t\tcached_initialize_callbacks_.clear();\n\t\tcached_mutationEffect_callbacks_.clear();\n\t\tcached_fitnessEffect_callbacks_onetick_.clear();\n\t\tcached_fitnessEffect_callbacks_multitick_.clear();\n\t\tcached_interaction_callbacks_.clear();\n\t\tcached_matechoice_callbacks_.clear();\n\t\tcached_modifychild_callbacks_.clear();\n\t\tcached_recombination_callbacks_.clear();\n\t\tcached_mutation_callbacks_.clear();\n\t\tcached_survival_callbacks_.clear();\n\t\tcached_reproduction_callbacks_.clear();\n\t\tcached_userdef_functions_.clear();\n\t\t\n\t\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\t\n#if DEBUG_BLOCK_REG_DEREG\n\t\tstd::cout << \"   ValidateScriptBlockCaches() recaching, AllScriptBlocks() is:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n#endif\n\t\t\n\t\tfor (auto script_block : script_blocks)\n\t\t{\n\t\t\t// only blocks that have been scheduled are eligible; others have to wait until the next call to EvaluateScriptBlockTickRanges()\n\t\t\tif (!script_block->tick_range_evaluated_)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tswitch (script_block->type_)\n\t\t\t{\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tcached_first_events_.emplace_back(script_block);\t\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tcached_early_events_.emplace_back(script_block);\t\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tcached_late_events_.emplace_back(script_block);\t\t\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tcached_initialize_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tcached_mutationEffect_callbacks_.emplace_back(script_block);\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\n\t\t\t\t{\n\t\t\t\t\t// Note fitnessEffect() callbacks are not order-dependent, so we don't have to preserve their order\n\t\t\t\t\t// of declaration the way we do with other types of callbacks.  This allows us to be very efficient\n\t\t\t\t\t// in how we look them up, which is good since sometimes we have a very large number of them.\n\t\t\t\t\t// We put those that are registered for just a single tick in a separate vector, which we sort\n\t\t\t\t\t// by tick, allowing us to look them up quickly\n\t\t\t\t\tif (script_block->tick_range_is_sequence_ && (script_block->tick_start_ == script_block->tick_end_))\n\t\t\t\t\t{\n\t\t\t\t\t\tcached_fitnessEffect_callbacks_onetick_.emplace(script_block->tick_start_, script_block);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcached_fitnessEffect_callbacks_multitick_.emplace_back(script_block);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tcached_interaction_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\tcached_matechoice_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tcached_modifychild_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tcached_recombination_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tcached_mutation_callbacks_.emplace_back(script_block);\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\tcached_survival_callbacks_.emplace_back(script_block);\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\tcached_reproduction_callbacks_.emplace_back(script_block);\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\tcached_userdef_functions_.emplace_back(script_block);\t\t\tbreak;\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\tbreak;\t// never hit\n\t\t\t}\n\t\t}\n\t\t\n\t\tscript_block_types_cached_ = true;\n\t\t\n#if DEBUG_BLOCK_REG_DEREG\n\t\tstd::cout << \"   ValidateScriptBlockCaches() recached, late() events cached are:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : cached_late_events_)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n#endif\n\t}\n}\n\nstd::vector<SLiMEidosBlock*> Community::ScriptBlocksMatching(slim_tick_t p_tick, SLiMEidosBlockType p_event_type, slim_objectid_t p_mutation_type_id, slim_objectid_t p_interaction_type_id, slim_objectid_t p_subpopulation_id, int64_t p_chromosome_id, Species *p_species)\n{\n\tif (!script_block_types_cached_)\n\t\tValidateScriptBlockCaches();\n\t\n\tstd::vector<SLiMEidosBlock*> *block_list = nullptr;\n\t\n\tswitch (p_event_type)\n\t{\n\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tblock_list = &cached_first_events_;\t\t\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tblock_list = &cached_early_events_;\t\t\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tblock_list = &cached_late_events_;\t\t\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tblock_list = &cached_initialize_callbacks_;\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tblock_list = &cached_mutationEffect_callbacks_;\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tblock_list = &cached_fitnessEffect_callbacks_multitick_;\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tblock_list = &cached_interaction_callbacks_;\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\tblock_list = &cached_matechoice_callbacks_;\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tblock_list = &cached_modifychild_callbacks_;\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tblock_list = &cached_recombination_callbacks_;\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tblock_list = &cached_mutation_callbacks_;\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\tblock_list = &cached_survival_callbacks_;\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\tblock_list = &cached_reproduction_callbacks_;\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\tblock_list = &cached_userdef_functions_;\t\t\t\t\tbreak;\n\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\tbreak;\t// never hit\n\t}\n\t\n\tstd::vector<SLiMEidosBlock*> matches;\n\t\n\tfor (SLiMEidosBlock *script_block : *block_list)\n\t{\n#if DEBUG_TICK_RANGES\n\t\t// all the blocks here should have an evaluated tick range\n\t\tif (!script_block->tick_range_evaluated_)\n\t\t{\n\t\t\tstd::cout << \"### unscheduled block seen in ScriptBlocksMatching()\" << std::endl;\n\t\t\tcontinue;\n\t\t}\n#endif\n\t\t\n\t\t// check that the tick is in range\n\t\tif (script_block->tick_range_is_sequence_)\n\t\t{\n\t\t\tif ((p_tick < script_block->tick_start_) || (p_tick > script_block->tick_end_))\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (script_block->tick_set_.find(p_tick) == script_block->tick_set_.end())\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// check that the script type matches (event, callback, etc.) - now guaranteed by the caching mechanism\n\t\t//if (script_block->type_ != p_event_type)\n\t\t//\tcontinue;\n\t\t\n\t\t// check that the mutation type id matches, if requested\n\t\tif (p_mutation_type_id != -1)\n\t\t{\n\t\t\tslim_objectid_t mutation_type_id = script_block->mutation_type_id_;\n\t\t\t\n\t\t\tif ((mutation_type_id != -1) && (p_mutation_type_id != mutation_type_id))\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// check that the interaction type id matches, if requested\n\t\tif (p_interaction_type_id != -1)\n\t\t{\n\t\t\tslim_objectid_t interaction_type_id = script_block->interaction_type_id_;\n\t\t\t\n\t\t\tif ((interaction_type_id != -1) && (p_interaction_type_id != interaction_type_id))\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// check that the subpopulation id matches, if requested\n\t\tif (p_subpopulation_id != -1)\n\t\t{\n\t\t\tslim_objectid_t subpopulation_id = script_block->subpopulation_id_;\n\t\t\t\n\t\t\tif ((subpopulation_id != -1) && (p_subpopulation_id != subpopulation_id))\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// check that the chromosome id matches, if requested\n\t\tif (p_chromosome_id != -1)\n\t\t{\n\t\t\tint64_t chromosome_id = script_block->chromosome_id_;\n\t\t\t\n\t\t\tif ((chromosome_id != -1) && (p_chromosome_id != chromosome_id))\n\t\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// check that the species matches; this check is always on, nullptr means check that the species is nullptr\n\t\tif (p_species != script_block->species_spec_)\n\t\t\tcontinue;\n\t\t\n\t\t// OK, everything matches, so we want to return this script block\n\t\tmatches.emplace_back(script_block);\n\t}\n\t\n\t// add in any single-tick fitnessEffect() callbacks\n\tif (p_event_type == SLiMEidosBlockType::SLiMEidosFitnessEffectCallback)\n\t{\n\t\tauto find_range = cached_fitnessEffect_callbacks_onetick_.equal_range(p_tick);\n\t\tauto find_start = find_range.first;\n\t\tauto find_end = find_range.second;\n\t\t\n\t\tfor (auto block_iter = find_start; block_iter != find_end; ++block_iter)\n\t\t{\n\t\t\tSLiMEidosBlock *script_block = block_iter->second;\n\t\t\t\n\t\t\t// check that the subpopulation id matches, if requested\n\t\t\tif (p_subpopulation_id != -1)\n\t\t\t{\n\t\t\t\tslim_objectid_t subpopulation_id = script_block->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((subpopulation_id != -1) && (p_subpopulation_id != subpopulation_id))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// check that the species matches; this check is always on, nullptr means check that the species is nullptr\n\t\t\tif (p_species != script_block->species_spec_)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\t// OK, everything matches, so we want to return this script block\n\t\t\tmatches.emplace_back(script_block);\n\t\t}\n\t}\n\t\n\treturn matches;\n}\n\nstd::vector<SLiMEidosBlock*> &Community::AllScriptBlocks()\n{\n\treturn script_blocks_;\n}\n\nstd::vector<SLiMEidosBlock*> Community::AllScriptBlocksForSpecies(Species *p_species)\n{\n\tstd::vector<SLiMEidosBlock*> species_blocks;\n\t\n\tfor (SLiMEidosBlock *block : script_blocks_)\n\t\tif (block->species_spec_ == p_species)\n\t\t\tspecies_blocks.push_back(block);\n\t\n\treturn species_blocks;\n}\n\nvoid Community::OptimizeScriptBlock(SLiMEidosBlock *p_script_block)\n{\n\t// The goal here is to look for specific structures in callbacks that we are able to optimize by short-circuiting\n\t// the callback interpretation entirely and replacing it with equivalent C++ code.  This is extremely messy, so\n\t// we're not going to do this for very many cases, but sometimes it is worth it.\n\tif (!p_script_block->has_cached_optimization_)\n\t{\n\t\tif (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosFitnessEffectCallback)\n\t\t{\n\t\t\tconst EidosASTNode *base_node = p_script_block->compound_statement_node_;\n\t\t\t\n\t\t\tif ((base_node->token_->token_type_ == EidosTokenType::kTokenLBrace) && (base_node->children_.size() == 1))\n\t\t\t{\n\t\t\t\tbool opt_dnorm1_candidate = true;\n\t\t\t\tconst EidosASTNode *expr_node = base_node->children_[0];\n\t\t\t\t\n\t\t\t\t// we must have an intervening \"return\", which we jump down through\n\t\t\t\tif ((expr_node->token_->token_type_ == EidosTokenType::kTokenReturn) && (expr_node->children_.size() == 1))\n\t\t\t\t{\n\t\t\t\t\texpr_node = expr_node->children_[0];\n\t\t\t\t\t\n\t\t\t\t\t// parse an optional constant at the beginning, like 1.0 + ...\n\t\t\t\t\tdouble added_constant = NAN;\n\t\t\t\t\t\n\t\t\t\t\tif ((expr_node->token_->token_type_ == EidosTokenType::kTokenPlus) && (expr_node->children_.size() == 2))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosASTNode *constant_node = expr_node->children_[0];\n\t\t\t\t\t\tconst EidosASTNode *rhs_node = expr_node->children_[1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (constant_node->HasCachedNumericValue())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tadded_constant = constant_node->CachedNumericValue();\n\t\t\t\t\t\t\texpr_node = rhs_node;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tadded_constant = 0.0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// parse an optional divisor at the end, ... / div\n\t\t\t\t\tdouble denominator = NAN;\n\t\t\t\t\t\n\t\t\t\t\tif ((expr_node->token_->token_type_ == EidosTokenType::kTokenDiv) && (expr_node->children_.size() == 2))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosASTNode *numerator_node = expr_node->children_[0];\n\t\t\t\t\t\tconst EidosASTNode *denominator_node = expr_node->children_[1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (denominator_node->HasCachedNumericValue())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdenominator = denominator_node->CachedNumericValue();\n\t\t\t\t\t\t\texpr_node = numerator_node;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tdenominator = 1.0;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// parse the dnorm() function call\n\t\t\t\t\tif (opt_dnorm1_candidate && (expr_node->token_->token_type_ == EidosTokenType::kTokenLParen) && (expr_node->children_.size() >= 2))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosASTNode *call_node = expr_node->children_[0];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((call_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (call_node->token_->token_string_ == \"dnorm\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint child_count = (int)expr_node->children_.size();\n\t\t\t\t\t\t\tconst EidosASTNode *x_node = expr_node->children_[1];\n\t\t\t\t\t\t\tconst EidosASTNode *mean_node = (child_count >= 3) ? expr_node->children_[2] : nullptr;\n\t\t\t\t\t\t\tconst EidosASTNode *sd_node = (child_count >= 4) ? expr_node->children_[3] : nullptr;\n\t\t\t\t\t\t\tdouble mean_value = 0.0, sd_value = 1.0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// resolve named arguments\n\t\t\t\t\t\t\tif ((x_node->token_->token_type_ == EidosTokenType::kTokenAssign) && (x_node->children_.size() == 2))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst EidosASTNode *name_node = x_node->children_[0];\n\t\t\t\t\t\t\t\tconst EidosASTNode *value_node = x_node->children_[1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((name_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (name_node->token_->token_string_ == \"x\"))\n\t\t\t\t\t\t\t\t\tx_node = value_node;\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (mean_node && (mean_node->token_->token_type_ == EidosTokenType::kTokenAssign) && (mean_node->children_.size() == 2))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst EidosASTNode *name_node = mean_node->children_[0];\n\t\t\t\t\t\t\t\tconst EidosASTNode *value_node = mean_node->children_[1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((name_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (name_node->token_->token_string_ == \"mean\"))\n\t\t\t\t\t\t\t\t\tmean_node = value_node;\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (sd_node && (sd_node->token_->token_type_ == EidosTokenType::kTokenAssign) && (sd_node->children_.size() == 2))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst EidosASTNode *name_node = sd_node->children_[0];\n\t\t\t\t\t\t\t\tconst EidosASTNode *value_node = sd_node->children_[1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((name_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (name_node->token_->token_string_ == \"sd\"))\n\t\t\t\t\t\t\t\t\tsd_node = value_node;\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// the mean and sd parameters of dnorm can be omitted in the below calls, but if they are given, get their values\n\t\t\t\t\t\t\tif (mean_node)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (mean_node->HasCachedNumericValue())\n\t\t\t\t\t\t\t\t\tmean_value = mean_node->CachedNumericValue();\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (sd_node)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (sd_node->HasCachedNumericValue())\n\t\t\t\t\t\t\t\t\tsd_value = sd_node->CachedNumericValue();\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\topt_dnorm1_candidate = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// parse the x argument to dnorm, which can take several different forms\n\t\t\t\t\t\t\tif (opt_dnorm1_candidate)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ((x_node->token_->token_type_ == EidosTokenType::kTokenMinus) && (x_node->children_.size() == 2) && (mean_value == 0.0))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *lhs_node = x_node->children_[0];\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *rhs_node = x_node->children_[1];\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *dot_node = nullptr, *constant_node = nullptr;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (lhs_node->token_->token_type_ == EidosTokenType::kTokenDot)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tdot_node = lhs_node;\n\t\t\t\t\t\t\t\t\t\tconstant_node = rhs_node;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (rhs_node->token_->token_type_ == EidosTokenType::kTokenDot)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tdot_node = rhs_node;\n\t\t\t\t\t\t\t\t\t\tconstant_node = lhs_node;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (dot_node && constant_node && (dot_node->children_.size() == 2) && constant_node->HasCachedNumericValue())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tconst EidosASTNode *var_node = dot_node->children_[0];\n\t\t\t\t\t\t\t\t\t\tconst EidosASTNode *prop_node = dot_node->children_[1];\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tmean_value = constant_node->CachedNumericValue();\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif ((var_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (var_node->token_->token_string_ == \"individual\")\n\t\t\t\t\t\t\t\t\t\t\t&& (prop_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (prop_node->token_->token_string_ == \"tagF\"))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(individual.tagF - A, 0.0, B) / C; }\n\t\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(individual.tagF - A, 0.0, B); }\n\t\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(A - individual.tagF, 0.0, B) / C; }\n\t\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(A - individual.tagF, 0.0, B); }\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->has_cached_optimization_ = true;\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->has_cached_opt_dnorm1_ = true;\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_A_ = mean_value;\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_B_ = sd_value;\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_C_ = denominator;\n\t\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_D_ = added_constant;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if ((x_node->token_->token_type_ == EidosTokenType::kTokenDot) && (x_node->children_.size() == 2))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *var_node = x_node->children_[0];\n\t\t\t\t\t\t\t\t\tconst EidosASTNode *prop_node = x_node->children_[1];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif ((var_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (var_node->token_->token_string_ == \"individual\")\n\t\t\t\t\t\t\t\t\t\t&& (prop_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (prop_node->token_->token_string_ == \"tagF\"))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(individual.tagF, A, B) / C; }\n\t\t\t\t\t\t\t\t\t\t// callback of the form { return D + dnorm(individual.tagF, A, B); }\n\t\t\t\t\t\t\t\t\t\tp_script_block->has_cached_optimization_ = true;\n\t\t\t\t\t\t\t\t\t\tp_script_block->has_cached_opt_dnorm1_ = true;\n\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_A_ = mean_value;\n\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_B_ = sd_value;\n\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_C_ = denominator;\n\t\t\t\t\t\t\t\t\t\tp_script_block->cached_opt_D_ = added_constant;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n//\t\t\tif (p_script_block->has_cached_optimization_)\n//\t\t\t\tstd::cout << \"optimized:\" << std::endl << \"   \" << base_node->token_->token_string_ << std::endl;\n//\t\t\telse\n//\t\t\t\tstd::cout << \"NOT OPTIMIZED:\" << std::endl << \"   \" << base_node->token_->token_string_ << std::endl;\n\t\t}\n\t\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosMutationEffectCallback)\n\t\t{\n\t\t\tconst EidosASTNode *base_node = p_script_block->compound_statement_node_;\n\t\t\t\n\t\t\tif ((base_node->token_->token_type_ == EidosTokenType::kTokenLBrace) && (base_node->children_.size() == 1))\n\t\t\t{\n\t\t\t\tconst EidosASTNode *expr_node = base_node->children_[0];\n\t\t\t\t\n\t\t\t\t// we must have an intervening \"return\", which we jump down through\n\t\t\t\tif ((expr_node->token_->token_type_ == EidosTokenType::kTokenReturn) && (expr_node->children_.size() == 1))\n\t\t\t\t{\n\t\t\t\t\texpr_node = expr_node->children_[0];\n\t\t\t\t\t\n\t\t\t\t\tif ((expr_node->token_->token_type_ == EidosTokenType::kTokenDiv) && (expr_node->children_.size() == 2))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosASTNode *numerator_node = expr_node->children_[0];\n\t\t\t\t\t\tconst EidosASTNode *denominator_node = expr_node->children_[1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (numerator_node->HasCachedNumericValue())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble numerator = numerator_node->CachedNumericValue();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((denominator_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (denominator_node->token_->token_string_ == \"effect\"))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// callback of the form { return A/effect; }\n\t\t\t\t\t\t\t\tp_script_block->has_cached_optimization_ = true;\n\t\t\t\t\t\t\t\tp_script_block->has_cached_opt_reciprocal = true;\n\t\t\t\t\t\t\t\tp_script_block->cached_opt_A_ = numerator;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n//\t\t\tif (p_script_block->has_cached_optimization_)\n//\t\t\t\tstd::cout << \"optimized:\" << std::endl << \"   \" << base_node->token_->token_string_ << std::endl;\n//\t\t\telse\n//\t\t\t\tstd::cout << \"NOT OPTIMIZED:\" << std::endl << \"   \" << base_node->token_->token_string_ << std::endl;\n\t\t}\n\t}\n}\n\nvoid Community::AddScriptBlock(SLiMEidosBlock *p_script_block, EidosInterpreter *p_interpreter, const EidosToken *p_error_token)\n{\n\tscript_blocks_.emplace_back(p_script_block);\n\t\n\tp_script_block->TokenizeAndParse();\t// can raise\n\t\n\t// Check for the presence/absence of a species specifier, as required by the block type\n\tif (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosNoBlockType)\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) attempted add of a script block of type SLiMEidosNoBlockType.\" << EidosTerminate(p_error_token);\n\t}\n\telse if ((p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventFirst) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventEarly) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventLate) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction))\n\t{\n\t\tif (p_script_block->species_spec_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for an event or user-defined function has a species set.\" << EidosTerminate(p_error_token);\n\t}\n\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t{\n\t\t// with explicit species, initialize() callbacks may be species-specific or not, both are allowed; without explicit species, they must be species-specific (to `sim`)\n\t\tif (!is_explicit_species_ && !p_script_block->species_spec_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for an initialize() callback in a single-species model has no species set.\" << EidosTerminate(p_error_token);\n\t}\n\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosInteractionCallback)\n\t{\n\t\t// interaction() callbacks are always non-species-specific\n\t\tif (p_script_block->species_spec_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for an interaction() callback has a species set.\" << EidosTerminate(p_error_token);\n\t}\n\telse if (!p_script_block->species_spec_)\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a callback has no species set.\" << EidosTerminate(p_error_token);\n\t}\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (p_script_block->species_spec_)\n\t{\n\t\tbool species_has_initialized = (p_script_block->species_spec_->Cycle() >= 1);\n\t\t\n\t\tif (p_script_block->mutation_type_id_ >= 0)\n\t\t{\n\t\t\t// if the mutation type exists now, we check that it belongs to the specified species\n\t\t\tMutationType *muttype = MutationTypeWithID(p_script_block->mutation_type_id_);\n\t\t\t\n\t\t\tif (species_has_initialized && !muttype)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): script block is specific to a mutation type id (\" << p_script_block->mutation_type_id_ << \") that does not exist.\" << EidosTerminate(p_error_token);\n\t\t\t\n\t\t\tif (muttype && (&muttype->species_ != p_script_block->species_spec_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): script block is specific to a mutation type id (\" << p_script_block->mutation_type_id_ << \") that belongs to a different species.\" << EidosTerminate(p_error_token);\n\t\t}\n\t\t\n\t\tif (p_script_block->subpopulation_id_ >= 0)\n\t\t{\n\t\t\t// if the subpopulation exists now, we check that it belongs to the specified species\n\t\t\tSubpopulation *subpop = SubpopulationWithID(p_script_block->subpopulation_id_);\n\t\t\t\n\t\t\t// cannot error out if the subpopulation does not exist, since subpopulations are dynamic\n\t\t\t\n\t\t\tif (subpop && (&subpop->species_ != p_script_block->species_spec_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): script block is specific to a subpopulation id (\" << p_script_block->subpopulation_id_ << \") that belongs to a different species.\" << EidosTerminate(p_error_token);\n\t\t}\n\t\t\n\t\tif (p_script_block->interaction_type_id_ >= 0)\n\t\t{\n\t\t\t// interaction() callbacks may not have a specified species\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block with interaction_type_id_ set has a specified species.\" << EidosTerminate(p_error_token);\n\t\t}\n\t\t\n\t\tif (p_script_block->sex_specificity_ != IndividualSex::kUnspecified)\n\t\t{\n\t\t\t// if the species has been initialized, we check that it is sexual if necessary\n\t\t\tif (p_script_block->type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-reproduction() callback has sex_specificity_ set.\" << EidosTerminate(p_error_token);\n\t\t\t\n\t\t\tif (species_has_initialized && !p_script_block->species_spec_->SexEnabled())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a reproduction() callback has sex_specificity_ set, but the specified species is not sexual.\" << EidosTerminate(p_error_token);\n\t\t}\n\t}\n\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosInteractionCallback)\n\t{\n\t\t// interaction() callbacks are weird; they are callbacks that are non-species-specific, so they must be checked separately\n\t\tif (p_script_block->mutation_type_id_ != -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for an interaction() callback has mutation_type_id_ set.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tif (p_script_block->sex_specificity_ != IndividualSex::kUnspecified)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for an interaction() callback has sex_specificity_ set.\" << EidosTerminate(p_error_token);\n\t}\n\telse\n\t{\n\t\t// At this point we have an event, a user-defined function, or a non-species-specific initialize() callback, and no other specifier should be set\n\t\tif (p_script_block->mutation_type_id_ != -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-callback or initialize() callback has mutation_type_id_ set.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tif (p_script_block->subpopulation_id_ != -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-callback or initialize() callback has subpopulation_id_ set.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tif (p_script_block->chromosome_id_ != -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-callback or initialize() callback has chromosome_id_ set.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tif (p_script_block->interaction_type_id_ != -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-callback or initialize() callback has interaction_type_id_ set.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tif (p_script_block->sex_specificity_ != IndividualSex::kUnspecified)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): (internal error) script block for a non-callback or initialize() callback has sex_specificity_ set.\" << EidosTerminate(p_error_token);\n\t}\n\t\n\t// The script block passed tokenization and parsing, so it is reasonably well-formed.  Now we check for cases we optimize.\n\tOptimizeScriptBlock(p_script_block);\n\t\n\t// Define the symbol for the script block, if any\n\tif (p_script_block->block_id_ != -1)\n\t{\n\t\tEidosSymbolTableEntry &symbol_entry = p_script_block->ScriptBlockSymbolTableEntry();\n\t\tEidosGlobalStringID symbol_id = symbol_entry.first;\n\t\t\n\t\tif ((simulation_constants_->ContainsSymbol(symbol_id)) || (p_interpreter && p_interpreter->SymbolTable().ContainsSymbol(symbol_id)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AddScriptBlock): script block symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate(p_error_token);\n\t\t\n\t\tsimulation_constants_->InitializeConstantSymbolEntry(symbol_entry);\n\t}\n\t\n\t// Notify the various interested parties that the script blocks have changed\n\tlast_script_block_tick_cached_ = false;\n\tscript_block_types_cached_ = false;\n\tscripts_changed_ = true;\n\t\n#if DEBUG_BLOCK_REG_DEREG\n\tstd::cout << \"Tick \" << tick_ << \": AddScriptBlock() just added a block, script_blocks_ is:\" << std::endl;\n\tfor (SLiMEidosBlock *script_block : script_blocks_)\n\t{\n\t\tstd::cout << \"      \";\n\t\tscript_block->Print(std::cout);\n\t\tstd::cout << std::endl;\n\t}\n#endif\n\t\n#ifdef SLIMGUI\n\tif (p_interpreter)\t\t// not when initializing the community from script\n\t{\n\t\tgSLiMScheduling << \"\\t\\tnew script block registered: \";\n\t\tp_script_block->PrintDeclaration(gSLiMScheduling, this);\n\t\tgSLiMScheduling << std::endl;\n\t}\n#endif\n}\n\nvoid Community::DeregisterScheduledScriptBlocks(void)\n{\n\t// If we have blocks scheduled for deregistration, we sweep through and deregister them at the end of each stage of each tick.\n\t// This happens at a time when script blocks are not executing, so that we're guaranteed not to leave hanging pointers that could\n\t// cause a crash; it also guarantees that script blocks are applied consistently across each cycle stage.  A single block\n\t// might be scheduled for deregistration more than once, but should only occur in script_blocks_ once, so we have to be careful\n\t// with our deallocations here; we deallocate a block only when we find it in script_blocks_.\n#if DEBUG_BLOCK_REG_DEREG\n\tif (scheduled_deregistrations_.size())\n\t{\n\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledScriptBlocks() planning to remove:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : scheduled_deregistrations_)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n#endif\n\t\n\tfor (SLiMEidosBlock *block_to_dereg : scheduled_deregistrations_)\n\t{\n\t\tauto script_block_position = std::find(script_blocks_.begin(), script_blocks_.end(), block_to_dereg);\n\t\t\n\t\tif (script_block_position != script_blocks_.end())\n\t\t{\n#if DEBUG_BLOCK_REG_DEREG\n\t\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledScriptBlocks() removing block:\" << std::endl;\n\t\t\tstd::cout << \"   \";\n\t\t\tblock_to_dereg->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n#endif\n\t\t\t\n\t\t\t// Remove the symbol for it first\n\t\t\tif (block_to_dereg->block_id_ != -1)\n\t\t\t\tsimulation_constants_->RemoveConstantForSymbol(block_to_dereg->ScriptBlockSymbolTableEntry().first);\n\t\t\t\n\t\t\t// Then remove it from our script block list and deallocate it\n\t\t\tscript_blocks_.erase(script_block_position);\n\t\t\tlast_script_block_tick_cached_ = false;\n\t\t\tscript_block_types_cached_ = false;\n\t\t\tscripts_changed_ = true;\n\t\t\tdelete block_to_dereg;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::DeregisterScheduledScriptBlocks): (internal error) couldn't find block for deregistration.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n#if DEBUG_BLOCK_REG_DEREG\n\tif (scheduled_deregistrations_.size())\n\t{\n\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledScriptBlocks() after removal:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : script_blocks_)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n#endif\n\t\n\tscheduled_deregistrations_.resize(0);\n}\n\nvoid Community::DeregisterScheduledInteractionBlocks(void)\n{\n\t// Identical to DeregisterScheduledScriptBlocks() above, but for the interaction() dereg list; see deregisterScriptBlock()\n#if DEBUG_BLOCK_REG_DEREG\n\tif (scheduled_interaction_deregs_.size())\n\t{\n\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledInteractionBlocks() planning to remove:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : scheduled_interaction_deregs_)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n#endif\n\t\n\tfor (SLiMEidosBlock *block_to_dereg : scheduled_interaction_deregs_)\n\t{\n\t\tauto script_block_position = std::find(script_blocks_.begin(), script_blocks_.end(), block_to_dereg);\n\t\t\n\t\tif (script_block_position != script_blocks_.end())\n\t\t{\n#if DEBUG_BLOCK_REG_DEREG\n\t\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledInteractionBlocks() removing block:\" << std::endl;\n\t\t\tstd::cout << \"   \";\n\t\t\tblock_to_dereg->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n#endif\n\t\t\t\n\t\t\t// Remove the symbol for it first\n\t\t\tif (block_to_dereg->block_id_ != -1)\n\t\t\t\tsimulation_constants_->RemoveConstantForSymbol(block_to_dereg->ScriptBlockSymbolTableEntry().first);\n\t\t\t\n\t\t\t// Then remove it from our script block list and deallocate it\n\t\t\tscript_blocks_.erase(script_block_position);\n\t\t\tlast_script_block_tick_cached_ = false;\n\t\t\tscript_block_types_cached_ = false;\n\t\t\tscripts_changed_ = true;\n\t\t\tdelete block_to_dereg;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::DeregisterScheduledInteractionBlocks): (internal error) couldn't find block for deregistration.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n#if DEBUG_BLOCK_REG_DEREG\n\tif (scheduled_interaction_deregs_.size())\n\t{\n\t\tstd::cout << \"Tick \" << tick_ << \": DeregisterScheduledInteractionBlocks() after removal:\" << std::endl;\n\t\tfor (SLiMEidosBlock *script_block : script_blocks_)\n\t\t{\n\t\t\tstd::cout << \"      \";\n\t\t\tscript_block->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n#endif\n\t\n\tscheduled_interaction_deregs_.resize(0);\n}\n\nvoid Community::ExecuteFunctionDefinitionBlock(SLiMEidosBlock *p_script_block)\n{\n\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &SymbolTable());\n\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\n\tEidosInterpreter interpreter(p_script_block->root_node_->children_[0], client_symbols, simulation_functions_, this, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t, check_infinite_loops_\n#endif\n\t);\n\t\n\ttry\n\t{\n\t\t// Interpret the script; the result from the interpretation is not used for anything\n\t\tEidosValue_SP result = interpreter.EvaluateInternalBlock(p_script_block->script_);\n\t}\n\tcatch (...)\n\t{\n\t\tthrow;\n\t}\n}\n\nbool Community::SubpopulationIDInUse(slim_objectid_t p_subpop_id)\n{\n\t// This method returns whether a subpop ID is conceptually \"in use\": whether it is being used, has ever\n\t// been used, or is reserved for use in some way by, by any SLiM species or by any tree sequence.\n\t\n\t// First check our own data structures; we now do not allow reuse of subpop ids, even disjoint in time\n\tfor (Species *species : all_species_)\n\t\tif (species->used_subpop_ids_.find(p_subpop_id) != species->used_subpop_ids_.end())\n\t\t\treturn true;\n\t\n\t// Then have each species check for a conflict with its tree-sequence population table\n\tfor (Species *species : all_species_)\n\t\tif (species->_SubpopulationIDInUse(p_subpop_id))\n\t\t\treturn true;\n\t\n\treturn false;\n}\n\nbool Community::SubpopulationNameInUse(const std::string &p_subpop_name)\n{\n\t// This method returns whether a subpop name is conceptually \"in use\": whether it is being used, has ever\n\t// been used, or is reserved for use in some way by, by any SLiM species or by any tree sequence.\n\t\n\t// First check our own data structures; we now do not allow reuse of subpop names, even disjoint in time\n\tfor (Species *species : all_species_)\n\t\tif (species->used_subpop_names_.count(p_subpop_name))\n\t\t\treturn true;\n\t\n\t// The tree-sequence population table does not keep names for populations, so no conflicts can occur\n\t\n\treturn false;\n}\n\nSubpopulation *Community::SubpopulationWithID(slim_objectid_t p_subpop_id)\n{\n\tfor (Species *species : all_species_)\n\t{\n\t\tSubpopulation *found_subpop = species->SubpopulationWithID(p_subpop_id);\n\t\t\n\t\tif (found_subpop)\n\t\t\treturn found_subpop;\n\t}\n\t\n\treturn nullptr;\n}\n\nSubpopulation *Community::SubpopulationWithName(const std::string &p_subpop_name)\n{\n\tfor (Species *species : all_species_)\n\t{\n\t\tSubpopulation *found_subpop = species->SubpopulationWithName(p_subpop_name);\n\t\t\n\t\tif (found_subpop)\n\t\t\treturn found_subpop;\n\t}\n\t\n\treturn nullptr;\n}\n\nMutationType *Community::MutationTypeWithID(slim_objectid_t p_muttype_id)\n{\n\tfor (Species *species : all_species_)\n\t{\n\t\tMutationType *found_muttype = species->MutationTypeWithID(p_muttype_id);\n\t\t\n\t\tif (found_muttype)\n\t\t\treturn found_muttype;\n\t}\n\t\n\treturn nullptr;\n}\n\nGenomicElementType *Community::GenomicElementTypeWithID(slim_objectid_t p_getype_id)\n{\n\tfor (Species *species : all_species_)\n\t{\n\t\tGenomicElementType *found_getype = species->GenomicElementTypeWithID(p_getype_id);\n\t\t\n\t\tif (found_getype)\n\t\t\treturn found_getype;\n\t}\n\t\n\treturn nullptr;\n}\n\nSLiMEidosBlock *Community::ScriptBlockWithID(slim_objectid_t p_script_block_id)\n{\n\tfor (SLiMEidosBlock *block : script_blocks_)\n\t\tif (block->block_id_ == p_script_block_id)\n\t\t\treturn block;\n\t\n\treturn nullptr;\n}\n\nSpecies *Community::SpeciesWithID(slim_objectid_t p_species_id)\n{\n\t// Species IDs are just indices into all_species_\n\tif ((p_species_id < 0) || (p_species_id >= (slim_objectid_t)all_species_.size()))\n\t\treturn nullptr;\n\t\n\treturn all_species_[p_species_id];\n}\n\nSpecies *Community::SpeciesWithName(const std::string &species_name)\n{\n\tfor (Species *species : all_species_)\n\t{\n\t\tif (species->name_ == species_name)\n\t\t\treturn species;\n\t}\n\t\n\treturn nullptr;\n}\n\nvoid Community::InvalidateInteractionsForSpecies(Species *p_invalid_species)\n{\n\tfor (auto iter : interaction_types_)\n\t\titer.second->InvalidateForSpecies(p_invalid_species);\n}\n\nvoid Community::InvalidateInteractionsForSubpopulation(Subpopulation *p_invalid_subpop)\n{\n\tfor (auto iter : interaction_types_)\n\t\titer.second->InvalidateForSubpopulation(p_invalid_subpop);\n}\n\nSpecies *Community::SpeciesForIndividualsVector(const Individual * const *individuals, int value_count)\n{\n\tif (value_count == 0)\n\t\treturn nullptr;\n\t\n\tSpecies *consensus_species = &individuals[0]->subpopulation_->species_;\n\t\n\tif (consensus_species->community_.all_species_.size() == 1)\t// with only one species, all objects must be in this species\n\t\treturn consensus_species;\n\t\n\tfor (int value_index = 1; value_index < value_count; ++value_index)\n\t{\n\t\tSpecies *species = &individuals[value_index]->subpopulation_->species_;\n\t\t\n\t\tif (species != consensus_species)\n\t\t\treturn nullptr;\n\t}\n\t\n\treturn consensus_species;\n}\n\nSpecies *Community::SpeciesForIndividuals(EidosValue *value)\n{\n\tif (value->Type() != EidosValueType::kValueObject)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForIndividuals): (internal error) value is not of type object.\" << EidosTerminate();\n\t\n\tEidosValue_Object *object_value = (EidosValue_Object *)value;\n\t\n\tint value_count = object_value->Count();\n\t\n\tif (value_count == 0)\t// allow an empty vector that is not of class Individual, to allow object() to pass our checks\n\t\treturn nullptr;\n\t\n\tif (object_value->Class() != gSLiM_Individual_Class)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForIndividuals): (internal error) value is not of class Individual.\" << EidosTerminate();\n\t\n\tif (value_count == 1)\n\t\treturn &((Individual *)object_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_->species_;\n\t\n\tEidosValue_Object *object_vector_value = (EidosValue_Object *)object_value;\n\tconst Individual * const *individuals = (Individual **)object_vector_value->data();\n\t\n\treturn Community::SpeciesForIndividualsVector(individuals, value_count);\n}\n\nSpecies *Community::SpeciesForHaplosomesVector(const Haplosome * const *haplosomes, int value_count)\n{\n\tif (value_count == 0)\n\t\treturn nullptr;\n\t\n\tSpecies *consensus_species = &haplosomes[0]->OwningIndividual()->subpopulation_->species_;\n\t\n\tif (consensus_species->community_.all_species_.size() == 1)\t// with only one species, all objects must be in this species\n\t\treturn consensus_species;\n\t\n\tfor (int value_index = 1; value_index < value_count; ++value_index)\n\t{\n\t\tconst Species *species = &haplosomes[value_index]->OwningIndividual()->subpopulation_->species_;\n\t\t\n\t\tif (species != consensus_species)\n\t\t\treturn nullptr;\n\t}\n\t\n\treturn consensus_species;\n}\n\nSpecies *Community::SpeciesForHaplosomes(EidosValue *value)\n{\n\tif (value->Type() != EidosValueType::kValueObject)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForHaplosomes): (internal error) value is not of type object.\" << EidosTerminate();\n\t\n\tEidosValue_Object *object_value = (EidosValue_Object *)value;\n\t\n\tint value_count = object_value->Count();\n\t\n\tif (value_count == 0)\t// allow an empty vector that is not of class Individual, to allow object() to pass our checks\n\t\treturn nullptr;\n\t\n\tif (object_value->Class() != gSLiM_Haplosome_Class)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForHaplosomes): (internal error) value is not of class Haplosome.\" << EidosTerminate();\n\t\n\tif (value_count == 1)\n\t\treturn &((Haplosome *)object_value->ObjectElementAtIndex_NOCAST(0, nullptr))->OwningIndividual()->subpopulation_->species_;\n\t\n\tEidosValue_Object *object_vector_value = (EidosValue_Object *)object_value;\n\tconst Haplosome * const *haplosomes = (Haplosome **)object_vector_value->data();\n\t\n\treturn Community::SpeciesForHaplosomesVector(haplosomes, value_count);\n}\n\nSpecies *Community::SpeciesForMutationsVector(const Mutation * const *mutations, int value_count)\n{\n\tif (value_count == 0)\n\t\treturn nullptr;\n\t\n\tSpecies *consensus_species = &mutations[0]->mutation_type_ptr_->species_;\n\t\n\tif (consensus_species->community_.all_species_.size() == 1)\t// with only one species, all objects must be in this species\n\t\treturn consensus_species;\n\t\n\tfor (int value_index = 1; value_index < value_count; ++value_index)\n\t{\n\t\tSpecies *species = &mutations[value_index]->mutation_type_ptr_->species_;\n\t\t\n\t\tif (species != consensus_species)\n\t\t\treturn nullptr;\n\t}\n\t\n\treturn consensus_species;\n}\n\nSpecies *Community::SpeciesForMutations(EidosValue *value)\n{\n\tif (value->Type() != EidosValueType::kValueObject)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForMutations): (internal error) value is not of type object.\" << EidosTerminate();\n\t\n\tEidosValue_Object *object_value = (EidosValue_Object *)value;\n\t\n\tint value_count = object_value->Count();\n\t\n\tif (value_count == 0)\t// allow an empty vector that is not of class Individual, to allow object() to pass our checks\n\t\treturn nullptr;\n\t\n\tif (object_value->Class() != gSLiM_Mutation_Class)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SpeciesForMutations): (internal error) value is not of class Mutation.\" << EidosTerminate();\n\t\n\tif (value_count == 1)\n\t\treturn &((Mutation *)object_value->ObjectElementAtIndex_NOCAST(0, nullptr))->mutation_type_ptr_->species_;\n\t\n\tEidosValue_Object *object_vector_value = (EidosValue_Object *)object_value;\n\tconst Mutation * const *mutations = (Mutation **)object_vector_value->data();\n\t\n\treturn Community::SpeciesForMutationsVector(mutations, value_count);\n}\n\nEidosValue_SP Community::_EvaluateTickRangeNode(const EidosASTNode *p_node, std::string &p_error_string)\n{\n\t// We have a tick range expression that we need to execute, and it should return an integer value to us.\n\t// This is basically a lambda call, so the code here is parallel to the executeLambda() code in many ways.\n\t// Additional semantic restrictions are imposed by Community::EvaluateScriptBlockTickRanges().\n\t\n\t// We consider the tick range to be the union of the ranges of all of the tokens it comprises.\n\t// We don't need to do any error-handling in try/catch since we are not creating a new error-handling\n\t// scope (the way executing a lambda or a script block does).\n\t\n\t// Unusually, we want to allow only global constants to be used in tick range expressions;\n\t// anything else (context constants like community and sim, global variables, etc.) will\n\t// potentially change value, and thus imply that the tick range is dynamically based on\n\t// current simulation state, which is not true.  There is still a hole here, in that a\n\t// global constant might refer to a Dictionary, and the tick range could reference a\n\t// value in that Dictionary that changes dynamically; but that is contrived, and the user\n\t// will soon discover that it doesn't work, and I'm not going to worry about it.  Better\n\t// would be to have a real concept in Eidos of constant expressions, and require one here.\n\t\n\t// BCH 7/19/2024: This method can now return nullptr, beware!  It does so if evaluating the\n\t// tick range node raises, specifically with an \"undefined identifier\" warning.  It is then\n\t// assumed that that is a global constant that will be defined later, and so we return\n\t// nullptr to indicate \"not ready yet, try again later\".  That particular error is not\n\t// reported to the user, since it is not, in fact, an error in this context.  Other raises\n\t// will not be caught here and will continue upwards and be reported.\n\t\n\tEidosSymbolTable *client_symbols = nullptr;\n\t\n\t{\n\t\tclient_symbols = &SymbolTable();\n\t\t\n\t\twhile (client_symbols &&\n\t\t\t   (client_symbols->TableType() != EidosSymbolTableType::kEidosDefinedConstantsTable) &&\n\t\t\t   (client_symbols->TableType() != EidosSymbolTableType::kEidosIntrinsicConstantsTable))\n\t\t\tclient_symbols = client_symbols->ChainSymbolTable();\n\t\t\n\t\tif (!client_symbols)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::_EvaluateTickRangeNode): (internal error) couldn't find the defined constants or intrinsic constants symbol tables.\" << EidosTerminate(nullptr);\n\t\t\n\t\t//std::cout << std::endl << \"Community::_EvaluateTickRangeNode() client_symbols:\" << std::endl;\n\t\t//client_symbols->PrintSymbolTableChain(std::cout);\n\t}\n\t\n\tEidosFunctionMap &function_map = FunctionMap();\n\tEidosInterpreter interpreter(p_node, *client_symbols, function_map, this, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t, check_infinite_loops_\n#endif\n\t\t);\n\tEidosValue_SP result_SP;\n\t\n\t// BCH 7/19/2024: Here we enable the use of a special exception, SLiMUndefinedIdentifierException,\n\t// when an identifier is undefined inside the tick range expression.  This allows us to catch that\n\t// specific exception type and handle it.  This is gross but effective!  I think it works in every\n\t// case but x[Y] where x is defined but y is undefined; that will still raise.  Nobody will notice\n\t// that they can't defer that specific expression type.  :->  SLiMUndefinedIdentifierException is\n\t// raised by _GetValue_SpecialRaise(), a special EidosSymbolTable method that is used to fetch\n\t// symbol table values in EidosInterpreter::Evaluate_Identifier() only when a special flag is set\n\t// enabling this mode of operation.  We set that flag with SetUseCustomUndefinedIdentifierRaise().\n\t// This rather convoluted design is necessary because Eidos normally does not necessarily throw for\n\t// errors at all; when running on the command line, it simply logs the error and exits.  So we\n\t// needed a special flag to change that behavior to throwing a custom exception in all cases, to\n\t// make the interpreter tolerant at runtime of this specific case.\n\t// BCH 3/21/2025: Broadening this mechanism to also encompass a raise due to an undefined function\n\t// name, only when tick == -1 (during construction).  We get called by FinishInitialization(), at\n\t// which point user-defined functions have not yet been parsed, and we want to fail silently and\n\t// try again later if a tick range expression depends on a user-defined function.  The evaluation\n\t// should succeed after initialize().  See https://github.com/MesserLab/SLiM/issues/495.  Note that\n\t// we do not protect against an undefined function name in doCall(), only in direct function calls.\n\t// I'm not sure there's a really solid reason for that choice, it's just what I decided to do.\n\tinterpreter.SetUseCustomUndefinedIdentifierRaise(true);\n\tif (tick_ == -1)\n\t\tinterpreter.SetUseCustomUndefinedFunctionRaise(true);\n\t\n\ttry\n\t{\n\t\tresult_SP = interpreter.FastEvaluateNode(p_node);\n\t}\n\tcatch (SLiMUndefinedIdentifierException &e)\n\t{\n\t\t// for undefined identifiers, cache the name of the undefined constant and return nullptr\n\t\tp_error_string = e.what();\n\t\treturn EidosValue_SP();\n\t}\n\tcatch (SLiMUndefinedFunctionException &e)\n\t{\n\t\t// for undefined functions, we don't need to remember the name; just return nullptr\n\t\treturn EidosValue_SP();\n\t}\n\t\n\t// no need to set the \"custom undefined...\" flags back, it's a local interpreter anyway\n\t\n\tp_error_string = \"\";\t// no execution error, so clear out any cached error string present\n\t\n\tEidosValueType result_type = result_SP->Type();\n\t\n\tif (result_type != EidosValueType::kValueInt)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::_EvaluateTickRangeNode): tick range expressions must evaluate to an integer value.\" << EidosTerminate(p_node->ErrorPositionForNodeAndChildren());\n\t\n\tint result_count = result_SP->Count();\n\tconst int64_t *int_data = result_SP->IntData();\n\t\n\tfor (int index = 0; index < result_count; ++index)\n\t{\n\t\tint64_t result_element = int_data[index];\n\t\t\n\t\tif ((result_element < 1) || (result_element > SLIM_MAX_TICK))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::_EvaluateTickRangeNode): the tick expression \" << p_node->token_->token_string_ << \" contains an element that is out of range (\" << result_element << \").\" << EidosTerminate(p_node->ErrorPositionForNodeAndChildren());\n\t}\n\t\n\treturn result_SP;\n}\n\nSLiMCycleStage Community::CycleStageForScriptBlockType(SLiMEidosBlockType p_block_type)\n{\n\t// Figure out what cycle stage the rescheduled block executes in; this is annoying, but necessary for the new scheduling check call\n\tSLiMCycleStage stage = SLiMCycleStage::kStagePostCycle;\t// unused below, just here to silence a warning\n\t\n\t// NOLINTBEGIN(*-branch-clone) : multiple internal tick stages map to the same user-level stage\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\tswitch (p_block_type)\n\t\t{\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tstage = SLiMCycleStage::kWFStage0ExecuteFirstScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tstage = SLiMCycleStage::kWFStage1ExecuteEarlyScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tstage = SLiMCycleStage::kWFStage5ExecuteLateScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tstage = SLiMCycleStage::kStagePreCycle; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tstage = SLiMCycleStage::kWFStage6CalculateFitness; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tstage = SLiMCycleStage::kWFStage6CalculateFitness; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tstage = SLiMCycleStage::kWFStage7AdvanceTickCounter; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\tstage = SLiMCycleStage::kWFStage2GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tstage = SLiMCycleStage::kWFStage2GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tstage = SLiMCycleStage::kWFStage2GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tstage = SLiMCycleStage::kWFStage2GenerateOffspring; break;\n\t\t\t\n\t\t\t// script block types that are not allowed in WF models, or have no cycle stage\n\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\n\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\n\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\n\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::CycleStageForScriptBlockType): (internal error) CycleStageForScriptBlockType() cannot be called on this type of script block.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch (p_block_type)\n\t\t{\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tstage = SLiMCycleStage::kNonWFStage0ExecuteFirstScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tstage = SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tstage = SLiMCycleStage::kNonWFStage6ExecuteLateScripts; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tstage = SLiMCycleStage::kStagePreCycle; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tstage = SLiMCycleStage::kNonWFStage3CalculateFitness; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tstage = SLiMCycleStage::kNonWFStage3CalculateFitness; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tstage = SLiMCycleStage::kNonWFStage7AdvanceTickCounter; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tstage = SLiMCycleStage::kNonWFStage1GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tstage = SLiMCycleStage::kNonWFStage1GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tstage = SLiMCycleStage::kNonWFStage1GenerateOffspring; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\tstage = SLiMCycleStage::kNonWFStage4SurvivalSelection; break;\n\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\tstage = SLiMCycleStage::kNonWFStage1GenerateOffspring; break;\n\t\t\t\n\t\t\t// script block types that are not allowed in nonWF models, or have no cycle stage\n\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\n\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\n\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::CycleStageForScriptBlockType): (internal error) CycleStageForScriptBlockType() cannot be called on this type of script block.\" << EidosTerminate();\n\t\t}\n\t}\n\t// NOLINTEND(*-branch-clone)\n\t\n\treturn stage;\n}\n\nbool Community::IsPastOrPresent(slim_tick_t p_block_tick, SLiMEidosBlockType p_block_type)\n{\n\t// This checks whether the given tick, for the given script block type, would be past or present (true)\n\t// versus future (false).  If the tick is less than the current tick, then it is clearly past; if it is\n\t// greater. it is clearly future.  The tricky part is if it is equal; then we have to look at the tick\n\t// cycle stage and determine whether, within the current tick, it is past/present or future.  See also\n\t// Community::CheckScheduling() for a very similar piece of code, different only in how it handles the\n\t// problem.\n\t\n\t// Note that these timing calculations are really just an approximation in some cases.  For example,\n\t// a fitnessEffect() callback normally runs during fitness calculation, and that is what this code and\n\t// Community::CycleStageForScriptBlockType() above assume; but fitness calculation can occur at other\n\t// times too.  If the user defines a new constant in a first() event that activates a fitnessEffect()\n\t// callback in the current tick, and then immediately recalculates fitness, the callback might not be\n\t// used in the calculation -- although in fact I think it would be, given the design of the code.  The\n\t// point being that there is not an exact 1-to-1 correspondence between script block types and cycle\n\t// stages, in reality, and so this timing check is just an approximation.\n\t\n\tif (p_block_tick < tick_)\n\t\treturn true;\n\t\n\tif (p_block_tick == tick_)\n\t{\n\t\tSLiMCycleStage block_cycle_stage = CycleStageForScriptBlockType(p_block_type);\n\t\t\n\t\tif (block_cycle_stage <= cycle_stage_)\n\t\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\nvoid Community::EvaluateScriptBlockTickRanges()\n{\n\tif (all_tick_ranges_evaluated_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): (internal error) EvaluateScriptBlockTickRanges() called unexpectedly.\" << EidosTerminate(nullptr);\n\t\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\n\t// Evaluate tick range expressions to determine the start and end tick for each block\n\t// Assume all succeed in evaluating, until one fails\n\tall_tick_ranges_evaluated_ = true;\n\t\n\tbool any_scheduling_change = false;\t\t// set to true if anything actually gets scheduled\n\t\n\tfor (auto script_block : script_blocks)\n\t{\n\t\tif ((script_block->type_ != SLiMEidosBlockType::SLiMEidosInitializeCallback) &&\n\t\t\t!script_block->tick_range_evaluated_)\n\t\t{\n\t\t\tconst EidosASTNode *start_tick_node = script_block->start_tick_node_;\n\t\t\tconst EidosASTNode *colon_node = script_block->colon_node_;\n\t\t\tconst EidosASTNode *end_tick_node = script_block->end_tick_node_;\n\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\tstd::cout << \"script block \" << *script_block << \" (\" << script_block << \"):\";\n\t\t\t\n\t\t\tstd::cout << \"\\n  start tick expression:\";\n\t\t\tif (start_tick_node)\n\t\t\t\tstart_tick_node->PrintTreeWithIndent(std::cout, 2);\n\t\t\telse\n\t\t\t\tstd::cout << \"\\n    -- none --\";\n\t\t\t\n\t\t\tif (colon_node)\n\t\t\t\tstd::cout << \"\\n  colon node present\";\n\t\t\t\n\t\t\tstd::cout << \"\\n  end tick expression:\";\n\t\t\tif (end_tick_node)\n\t\t\t\tend_tick_node->PrintTreeWithIndent(std::cout, 2);\n\t\t\telse\n\t\t\t\tstd::cout << \"\\n    -- none --\";\n\t\t\t\n\t\t\tstd::cout << std::endl;\n#endif\n\t\t\t\n\t\t\tif (start_tick_node && colon_node && end_tick_node)\n\t\t\t{\n\t\t\t\t// e.g., 5:10 -- both expressions must evaluate to singletons, AND both must be \"primary\"/\"postfix\".  That means they must be a simple\n\t\t\t\t// number or identifier, a dot-expression (property access), a bracket-expression (subset), a paren-expression (function or method call),\n\t\t\t\t// or an expression that was grouped by parentheses.  The last one is tricky, because the parser doesn't generate a node representing\n\t\t\t\t// the grouping parentheses; instead, for this work, I added a flag, was_parenthesized_, that is set on a node if it was originally\n\t\t\t\t// inside grouping parentheses.  This flag gets the information we need out of the parser.  This requirement exists in the first place\n\t\t\t\t// so that X:Y range expressions don't violate the normal Eidos precedence rules for operator :.  Basically, X and Y both have to be\n\t\t\t\t// higher precedence than operator :, so that X:Y and (X):(Y) mean the same thing.  That is what our restrictions guarantee.\n\t\t\t\t// See Parse_SLiMEidosBlock() for more comments on this rather complicated problem, which is rooted in wanting to allow the X: and :Y\n\t\t\t\t// range syntaxes, as well as wanting to avoid user errors with the (surprising) operator : precedence rules.\n\t\t\t\tEidosTokenType start_type = start_tick_node->token_->token_type_;\n\t\t\t\tEidosTokenType end_type = end_tick_node->token_->token_type_;\n\t\t\t\t\n\t\t\t\tif ((start_type != EidosTokenType::kTokenNumber) && (start_type != EidosTokenType::kTokenIdentifier) &&\n\t\t\t\t\t(start_type != EidosTokenType::kTokenDot) && (start_type != EidosTokenType::kTokenLBracket) &&\n\t\t\t\t\t(start_type != EidosTokenType::kTokenLParen) && !start_tick_node->was_parenthesized_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start and end tick expressions must both be simple expressions (numbers, identifiers, expressions inside parentheses, and similar) when a tick range, X:Y, is used; this avoids precedence issues with the sequence operator, ':'.  To avoid this error, use parentheses to group the start and end tick expressions to make the precedence explicit.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tif ((end_type != EidosTokenType::kTokenNumber) && (end_type != EidosTokenType::kTokenIdentifier) &&\n\t\t\t\t\t(end_type != EidosTokenType::kTokenDot) && (end_type != EidosTokenType::kTokenLBracket) &&\n\t\t\t\t\t(end_type != EidosTokenType::kTokenLParen) && !end_tick_node->was_parenthesized_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start and end tick expressions must both be simple expressions (numbers, identifiers, expressions inside parentheses, and similar) when a tick range, X:Y, is used; this avoids precedence issues with the sequence operator, ':'.  To avoid this error, use parentheses to group the left and right sides to make the precedence explicit.\" << EidosTerminate(end_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tEidosValue_SP start_expr_value = _EvaluateTickRangeNode(start_tick_node, script_block->unevaluated_error_string_);\n\t\t\t\t\n\t\t\t\tif (!start_expr_value)\n\t\t\t\t{\n\t\t\t\t\tall_tick_ranges_evaluated_ = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEidosValue_SP end_expr_value = _EvaluateTickRangeNode(end_tick_node, script_block->unevaluated_error_string_);\n\t\t\t\t\n\t\t\t\tif (!end_expr_value)\n\t\t\t\t{\n\t\t\t\t\tall_tick_ranges_evaluated_ = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (start_expr_value->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start and end tick expressions must both evaluate to a singleton integer when a tick range, X:Y, is used.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tif (end_expr_value->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start and end tick expressions must both evaluate to a singleton integer when a tick range, X:Y, is used.\" << EidosTerminate(end_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\tscript_block->tick_range_is_sequence_ = true;\n\t\t\t\tscript_block->tick_start_ = (slim_tick_t)start_expr_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\tscript_block->tick_end_ = (slim_tick_t)end_expr_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\n\t\t\t\tif (script_block->tick_end_ < script_block->tick_start_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the end tick expression \" << end_tick_node->token_->token_string_ << \" evaluated to be less than the start tick expression \" << start_tick_node->token_->token_string_ << \" (\" << script_block->tick_end_ << \" < \" << script_block->tick_start_ << \").\" << EidosTerminate(end_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\t// With a specified start tick, it is an error for that start tick\n\t\t\t\t// to be past/present, since a fire of the event will be missed\n\t\t\t\tif (IsPastOrPresent(script_block->tick_start_, script_block->type_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start tick expression \" << start_tick_node->token_->token_string_ << \" evaluated to \" << script_block->tick_start_ << \", which is past/present; the current tick is \" << tick_ << \".  This means that the event will not be able to execute in one or more of its scheduled ticks, which is an error.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\tstd::cout << \"  tick range \" << script_block->tick_start_ << \" to \" << script_block->tick_end_ << std::endl;\n#endif\n\t\t\t}\n\t\t\telse if (start_tick_node && colon_node)\n\t\t\t{\n\t\t\t\t// e.g., 5: -- the start expression must evaluate to a singleton\n\t\t\t\tEidosValue_SP start_expr_value = _EvaluateTickRangeNode(start_tick_node, script_block->unevaluated_error_string_);\n\t\t\t\t\n\t\t\t\tif (!start_expr_value)\n\t\t\t\t{\n\t\t\t\t\tall_tick_ranges_evaluated_ = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (start_expr_value->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start tick expression must evaluate to a singleton integer when a tick range, X:, is used.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\tscript_block->tick_range_is_sequence_ = true;\n\t\t\t\tscript_block->tick_start_ = (slim_tick_t)start_expr_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\tscript_block->tick_end_ = SLIM_MAX_TICK + 1;\n\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\n\t\t\t\t// With a specified start tick, it is an error for that start tick\n\t\t\t\t// to be past/present, since a fire of the event will be missed\n\t\t\t\tif (IsPastOrPresent(script_block->tick_start_, script_block->type_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the start tick expression \" << start_tick_node->token_->token_string_ << \" evaluated to \" << script_block->tick_start_ << \", which is past/present; the current tick is \" << tick_ << \".  This means that the event will not be able to execute in one or more of its scheduled ticks, which is an error.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\tstd::cout << \"  tick range \" << script_block->tick_start_ << \" to end.\" << std::endl;\n#endif\n\t\t\t}\n\t\t\telse if (colon_node && end_tick_node)\n\t\t\t{\n\t\t\t\t// e.g., :5 -- the end expression must evaluate to a singleton\n\t\t\t\tEidosValue_SP end_expr_value = _EvaluateTickRangeNode(end_tick_node, script_block->unevaluated_error_string_);\n\t\t\t\t\n\t\t\t\tif (!end_expr_value)\n\t\t\t\t{\n\t\t\t\t\tall_tick_ranges_evaluated_ = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (end_expr_value->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the end tick expression must evaluate to a singleton integer when a tick range, :X, is used.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\tscript_block->tick_range_is_sequence_ = true;\n\t\t\t\tscript_block->tick_start_ = 1;\n\t\t\t\tscript_block->tick_end_ = (slim_tick_t)end_expr_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\n\t\t\t\t// With an implied start, it is an error for that start tick\n\t\t\t\t// to be past/present, since a fire of the event will be missed\n\t\t\t\tif (tick_ > 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): with an implied start tick at the start of model execution, the event has missed one or more of its scheduled ticks, which is an error.\" << EidosTerminate(colon_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\tstd::cout << \"  tick range beginning to \" << script_block->tick_end_ << \".\" << std::endl;\n#endif\n\t\t\t}\n\t\t\telse if (start_tick_node && !colon_node)\n\t\t\t{\n\t\t\t\t// e.g., 5 -- in this case, the expression may evaluate to a non-singleton integer value, like \"seq(1, 100, by=2)\"\n\t\t\t\tEidosValue_SP expr_value = _EvaluateTickRangeNode(start_tick_node, script_block->unevaluated_error_string_);\n\t\t\t\t\n\t\t\t\tif (!expr_value)\n\t\t\t\t{\n\t\t\t\t\tall_tick_ranges_evaluated_ = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tconst int64_t *expr_data = expr_value->IntData();\n\t\t\t\tint expr_count = expr_value->Count();\n\t\t\t\t\n\t\t\t\tif (expr_count == 0)\n\t\t\t\t{\n\t\t\t\t\t// set to run in no ticks; we do this with an empty set\n\t\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\t\tscript_block->tick_range_is_sequence_ = false;\n\t\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\t\tany_scheduling_change = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// if it is a singleton, or a consecutive range, we detect that and handle it efficiently\n\t\t\t\t\tbool is_sequential = true;\n\t\t\t\t\tint64_t first_value = expr_data[0];\n\t\t\t\t\tint64_t prev_value = first_value;\n\t\t\t\t\t\n\t\t\t\t\tfor (int index = 1; index < expr_count; ++index)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t value = expr_data[index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value != prev_value + 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tis_sequential = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tprev_value = value;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (is_sequential)\n\t\t\t\t\t{\n\t\t\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\t\t\tscript_block->tick_range_is_sequence_ = true;\n\t\t\t\t\t\tscript_block->tick_start_ = (slim_tick_t)first_value;\n\t\t\t\t\t\tscript_block->tick_end_ = (slim_tick_t)prev_value;\n\t\t\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// With a specified start tick, it is an error for that start tick\n\t\t\t\t\t\t// to be past/present, since a fire of the event will be missed\n\t\t\t\t\t\tif (IsPastOrPresent(script_block->tick_start_, script_block->type_))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (script_block->tick_start_ == script_block->tick_end_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the tick range expression \" << start_tick_node->token_->token_string_ << \" evaluated to tick \" << script_block->tick_start_ << \", which is past/present; the current tick is \" << tick_ << \".  This means that the event will not be able to execute in its scheduled tick, which is an error.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the tick range expression \" << start_tick_node->token_->token_string_ << \" evaluated to begin in tick \" << script_block->tick_start_ << \", which is past/present; the current tick is \" << tick_ << \".  This means that the event will not be able to execute in one or more of its scheduled ticks, which is an error.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\t\t\tstd::cout << \"  tick range \" << script_block->tick_start_ << \" to \" << script_block->tick_end_ << std::endl;\n#endif\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (expr_count > 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): for efficiency reasons, a non-sequential tick range expression may not contain more than 1,000,000 values; use rescheduleScriptBlock() if you really need to do this, but be aware that it may not perform well.  Often a better solution is to use a sequential range, and test an additional criterion inside the event or callback body.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\t\t\n\t\t\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\t\t\tscript_block->tick_range_is_sequence_ = false;\n\t\t\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::unordered_set<slim_tick_t> &tick_set = script_block->tick_set_;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttick_set.clear();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int index = 0; index < expr_count; ++index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_tick_t tick = (slim_tick_t)expr_data[index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (tick_set.find(tick) == tick_set.end())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttick_set.emplace(tick);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// With a non-sequential range, it is an error for any tick\n\t\t\t\t\t\t\t\t// to be past/present, since a fire of the event will be missed\n\t\t\t\t\t\t\t\tif (IsPastOrPresent(tick, script_block->type_))\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): the tick range expression \" << start_tick_node->token_->token_string_ << \" evaluated to include tick \" << tick << \", which is past/present; the current tick is \" << tick_ << \".  This means that the event will not be able to execute in one or more of its scheduled ticks, which is an error.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): a non-sequential tick range expression may not contain duplicate elements (\" << tick << \" is duplicated).  Use unique() to remove duplicates if desired.\" << EidosTerminate(start_tick_node->ErrorPositionForNodeAndChildren());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\t\t\tstd::cout << \"  non-sequential tick range (\" << tick_set.size() << \" elements).\" << std::endl;\n#endif\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (!start_tick_node && !colon_node && !end_tick_node)\n\t\t\t{\n\t\t\t\t// no tick specifier -- active in every tick\n\t\t\t\t// since there is no dependency on an expression, this will always be evaluated immediately\n\t\t\t\tscript_block->tick_range_evaluated_ = true;\n\t\t\t\tscript_block->tick_range_is_sequence_ = true;\n\t\t\t\tscript_block->tick_start_ = -1;\n\t\t\t\tscript_block->tick_end_ = SLIM_MAX_TICK + 1;\n\t\t\t\tscript_block->tick_set_.clear();\n\t\t\t\tany_scheduling_change = true;\n\t\t\t\t\n#if DEBUG_TICK_RANGES\n\t\t\t\tstd::cout << \"  tick range is every tick.\" << std::endl;\n#endif\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::EvaluateScriptBlockTickRanges): (internal error) unhandled tick range case.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (any_scheduling_change)\n\t{\n\t\t// Notify the various interested parties that the script blocks have changed\n\t\tlast_script_block_tick_cached_ = false;\n\t\tscript_block_types_cached_ = false;\n\t\tscripts_changed_ = true;\n\t}\n\t\n\t// We are now open for business\n}\n\nvoid Community::FlagUnevaluatedScriptBlockTickRanges()\n{\n\t// This is called at execution end, to error if any script blocks did not execute because their\n\t// tick range could not be evaluated; this depends on script_block->unevaluated_error_string_\n\t// being set up by _EvaluateTickRangeNode(), based on the error message string set up in\n\t// SLiMUndefinedIdentifierException by EidosSymbolTable::_GetValue_SpecialRaise().\n\tif (all_tick_ranges_evaluated_)\n\t\treturn;\n\t\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\n\tfor (auto script_block : script_blocks)\n\t{\n\t\tif ((script_block->type_ != SLiMEidosBlockType::SLiMEidosInitializeCallback) &&\n\t\t\t!script_block->tick_range_evaluated_)\n\t\t{\n\t\t\tif (!script_block->unevaluated_error_string_.length())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::FlagUnevaluatedScriptBlockTickRanges): (internal error) An internal error occurred regarding script block scheduling. Please report this error.\" << EidosTerminate(script_block->root_node_->ErrorPositionForNodeAndChildren());\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::FlagUnevaluatedScriptBlockTickRanges): At simulation end, this script block had never been executed because its tick range could never be evaluated.  This was due to a reference to a global constant, \" << script_block->unevaluated_error_string_ << \", that was never defined. (Note that variables, including global variables, are not visible in tick range expressions and cannot be used; only global constants may be used.)\\n\\nIf the non-execution of this script block is intentional, you can avoid this error by calling deregisterScriptBlock() to deregister the block before the simulation ends.\" << EidosTerminate(script_block->root_node_->ErrorPositionForNodeAndChildren());\n\t\t}\n\t}\n}\n\nslim_tick_t Community::FirstTick(void)\n{\n\tslim_tick_t first_tick = SLIM_MAX_TICK + 1;\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\n\t// Figure out our first tick; it is the earliest tick in which an Eidos event is set up to run,\n\t// since an Eidos event that adds a subpopulation is necessary to get things started\n\tfor (auto script_block : script_blocks)\n\t{\n\t\tif ((script_block->type_ == SLiMEidosBlockType::SLiMEidosEventFirst) ||\n\t\t\t(script_block->type_ == SLiMEidosBlockType::SLiMEidosEventEarly) ||\n\t\t\t(script_block->type_ == SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t{\n\t\t\tif (script_block->tick_range_is_sequence_)\n\t\t\t{\n\t\t\t\tif ((script_block->tick_start_ < first_tick) && (script_block->tick_start_ >= 1))\n\t\t\t\t\tfirst_tick = script_block->tick_start_;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (const auto &tick : script_block->tick_set_)\n\t\t\t\t{\n\t\t\t\t\tif ((tick < first_tick) && (tick >= 1))\n\t\t\t\t\t\tfirst_tick = tick;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn first_tick;\n}\n\nslim_tick_t Community::EstimatedLastTick(void)\n{\n\t// return our cached value if we have one\n\tif (last_script_block_tick_cached_)\n\t\treturn last_script_block_tick_;\n\t\n\t// otherwise, fill the cache\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\tslim_tick_t last_tick = 1;\n\t\n\t// The estimate is derived from the last tick in which an Eidos block is registered.\n\t// Any block type works, since the simulation could plausibly be stopped within a callback.\n\t// However, blocks that do not specify an end tick don't count.\n\tfor (auto script_block : script_blocks)\n\t{\n\t\tif (script_block->tick_range_is_sequence_)\n\t\t{\n\t\t\tif ((script_block->tick_end_ > last_tick) && (script_block->tick_end_ <= SLIM_MAX_TICK))\n\t\t\t\tlast_tick = script_block->tick_end_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (const auto &tick : script_block->tick_set_)\n\t\t\t\tif ((tick > last_tick) && (tick <= SLIM_MAX_TICK))\n\t\t\t\t\tlast_tick = tick;\n\t\t}\n\t}\n\t\n\tlast_script_block_tick_ = last_tick;\n\tlast_script_block_tick_cached_ = true;\n\t\n\treturn last_script_block_tick_;\n}\n\nvoid Community::SetModelType(SLiMModelType p_new_type)\n{\n\tif (model_type_set_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SetModelType): (internal error) the model has already been declared.\" << EidosTerminate();\n\t\n\tmodel_type_set_ = true;\n\tmodel_type_ = p_new_type;\n\t\n\t// propagate the model type decision downward to ensure consistency\n\tfor (Species *species : all_species_)\n\t{\n\t\tspecies->model_type_ = model_type_;\n\t\tspecies->population_.model_type_ = model_type_;\n\t}\n}\n\nvoid Community::SetTick(slim_tick_t p_new_tick)\n{\n\ttick_ = p_new_tick;\n\t\n\t// The tree sequence tick increments when generating offspring occurs, not at the ends of ticks as delineated by SLiM.\n\t// This prevents the tree sequence code from seeing two \"generations\" with the same value for the tick counter.\n\tif (((model_type_ == SLiMModelType::kModelTypeWF) && (CycleStage() < SLiMCycleStage::kWFStage2GenerateOffspring)) ||\n\t\t((model_type_ == SLiMModelType::kModelTypeNonWF) && (CycleStage() < SLiMCycleStage::kNonWFStage1GenerateOffspring)))\n\t\ttree_seq_tick_ = tick_ - 1;\n\telse\n\t\ttree_seq_tick_ = tick_;\n\t\n\ttree_seq_tick_offset_ = 0;\n}\n\n// This function is called by both SLiM and SLiMgui to run a tick.  In SLiM, it simply calls _RunOneTick(),\n// with no exception handling; in that scenario exceptions should not be thrown, since EidosTerminate() will log an\n// error and then call exit().  In SLiMgui, EidosTerminate() will raise an exception, and it will be caught right\n// here and converted to an \"invalid simulation\" state (simulation_valid_ == false), which will be noticed by SLiMgui\n// and will cause error reporting to occur based upon the error-tracking variables set.\nbool Community::RunOneTick(void)\n{\n#ifdef SLIMGUI\n\tif (simulation_valid_)\n\t{\n\t\ttry\n\t\t{\n#endif\n\t\t\treturn _RunOneTick();\n#ifdef SLIMGUI\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tsimulation_valid_ = false;\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\tClearErrorContext();\n#endif\n\t\n\treturn false;\n}\n\n// This function is called only by the SLiM self-testing machinery.  It has no exception handling; raises will\n// blow through to the catch block in the test harness so that they can be handled there.\nbool Community::_RunOneTick(void)\n{\n\t// ******************************************************************\n\t//\n\t// Stage 0: Pre-cycle bookkeeping\n\t//\n\tcycle_stage_ = SLiMCycleStage::kStagePreCycle;\n\t\n\t// Define the current script around each cycle execution, for error reporting\n\tgEidosErrorContext.currentScript = script_;\n\t\n\t// Activate all species at the beginning of the tick, according their modulo/phase\n\tif (tick_ == 0)\n\t{\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"# initialize() callbacks executing:\" << std::endl;\n#endif\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->SetActive(true);\n\t}\n\telse\n\t{\n\t\tfor (Species *species : all_species_)\n\t\t{\n\t\t\tslim_tick_t phase = species->TickPhase();\n\t\t\t\n\t\t\tif (tick_ >= phase)\n\t\t\t{\n\t\t\t\tslim_tick_t modulo = species->TickModulo();\n\t\t\t\t\n\t\t\t\tif ((modulo == 1) || ((tick_ - phase) % modulo == 0))\n\t\t\t\t{\n\t\t\t\t\tspecies->SetActive(true);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tspecies->SetActive(false);\n\t\t}\n\t\t\n\t\t\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"# tick \" << tick_ << \": \";\n\t\tbool first_species = true;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t{\n\t\t\tif (!first_species)\n\t\t\t\tgSLiMScheduling << \", \";\n\t\t\t\n\t\t\tif (species->Active())\n\t\t\t\tgSLiMScheduling << \"species \" << species->name_ << \" active (cycle \" << species->cycle_ << \")\";\n\t\t\telse\n\t\t\t\tgSLiMScheduling << \"species \" << species->name_ << \" INACTIVE\";\n\t\t\t\n\t\t\tfirst_species = false;\n\t\t}\n\t\t\n\t\tgSLiMScheduling << std::endl;\n#endif\n\t}\n\t\n\t// Activate registered script blocks at the beginning of the tick, unless the block's species/ticks specifier refers to an inactive species\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\n\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t{\n\t\tif ((!script_block->species_spec_ || script_block->species_spec_->Active()) && (!script_block->ticks_spec_ || script_block->ticks_spec_->Active()))\n\t\t{\n\t\t\tscript_block->block_active_ = -1;\t\t\t// block is active this tick\n\t\t}\n\t\telse\n\t\t{\n\t\t\tscript_block->block_active_ = 0;\t\t\t// block is inactive this tick\n\t\t\t\n\t\t\t// Check for deactivation causing a block not to execute at all; we consider this an error since it is almost certainly not what the user wants\n\t\t\tif (script_block->tick_range_evaluated_)\n\t\t\t\tif ((script_block->tick_range_is_sequence_ && (script_block->tick_start_ == script_block->tick_end_) && (script_block->tick_start_ == tick_)) ||\n\t\t\t\t(!script_block->tick_range_is_sequence_ && (script_block->tick_set_.size() == 1) && (script_block->tick_set_.find(tick_) == script_block->tick_set_.begin())))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::_RunOneTick): A script block that is scheduled to execute only in a single tick (tick \" << tick_ << \") was deactivated in that tick due to a 'species' or 'ticks' specifier in its declaration; the script block will thus not execute at all.\" << EidosTerminate(script_block->identifier_token_);\n\t\t}\n\t}\n\t\n\t// Execute either initialize() callbacks (for tick 0) or the full cycle\n\tif (tick_ == 0)\n\t{\n\t\tAllSpecies_RunInitializeCallbacks();\n\t\tCheckLongTermBoundary();\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->PrepareForCycle();\n\t\t\n\t\t// Non-zero ticks are handled by separate functions for WF and nonWF models\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\treturn _RunOneTickWF();\n\t\telse\n\t\t\treturn _RunOneTickNonWF();\n\t}\n}\n\nvoid Community::AllSpecies_RunInitializeCallbacks(void)\n{\n\t// The zero tick is handled here by shared code, since it is the same for WF and nonWF models\n\t\n\t// execute user-defined function blocks first; no need to profile this, it's just the definitions not the executions\n\tstd::vector<SLiMEidosBlock*> function_blocks = ScriptBlocksMatching(-1, SLiMEidosBlockType::SLiMEidosUserDefinedFunction, -1, -1, -1, -1, nullptr);\n\t\n\tfor (auto script_block : function_blocks)\n\t\tExecuteFunctionDefinitionBlock(script_block);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_OUTSTREAM << \"// RunInitializeCallbacks():\" << std::endl;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\t// execute non-species-specific (`species all`) initialize() callbacks first\n\tactive_species_ = nullptr;\n\tRunInitializeCallbacks();\n\t\n\t// execute initialize() callbacks for each species, in species declaration order\n\tfor (Species *species : all_species_)\n\t{\n\t\tactive_species_ = species;\n\t\tactive_species_->RunInitializeCallbacks();\n\t\tactive_species_ = nullptr;\n\t}\n\t\n\tDeregisterScheduledScriptBlocks();\n\t\n\t// compile results from initialization into our overall state\n\tfor (Species *species : all_species_)\n\t{\n\t\tconst std::map<slim_objectid_t,MutationType*> &muttypes = species->MutationTypes();\n\t\tconst std::map<slim_objectid_t,GenomicElementType*> &getypes = species->GenomicElementTypes();\n\t\t\n\t\tall_mutation_types_.insert(muttypes.begin(), muttypes.end());\n\t\tall_genomic_element_types_.insert(getypes.begin(), getypes.end());\n\t}\n\t\n\t// set up global symbols for all species, and for ourselves\n\tfor (Species *species : all_species_)\n\t{\n\t\tEidosSymbolTableEntry &symbol_entry = species->SymbolTableEntry();\n\t\tEidosGlobalStringID symbol_id = symbol_entry.first;\n\t\tstd::string symbol_string = EidosStringRegistry::StringForGlobalStringID(symbol_id);\n\t\t\n\t\tif (simulation_constants_->ContainsSymbol(symbol_id))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_RunInitializeCallbacks): A species with name '\" << symbol_string << \"' cannot be defined because that name is already in use.\" << EidosTerminate();\n\t\tif (!Eidos_GoodSymbolForDefine(symbol_string) && (symbol_string != \"sim\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_RunInitializeCallbacks): A species with name '\" << symbol_string << \"' cannot be defined because the symbol '\" << symbol_string << \"' is reserved.\" << EidosTerminate();\n\t\t\n\t\tsimulation_constants_->InitializeConstantSymbolEntry(symbol_entry);\n\t}\n\t\n\tsimulation_constants_->InitializeConstantSymbolEntry(SymbolTableEntry());\n\t\n\t// we're done with the initialization tick, so remove the zero-tick functions\n\tRemoveZeroTickFunctionsFromMap(simulation_functions_);\n\t\n\t// BCH 3/6/2024: Here is where we now determine the tick ranges for script blocks; we now\n\t// do this in a deferred fashion to allow tick ranges to contain constant expressions.\n\t// It needs to be done before the call to FirstTick() below so tick ranges are valid.\n\t// Nobody should call FirstTick() or EstimatedLastTick() before this point!\n\t// BCH 7/19/2024: Note that we will try again in each tick, if some expressions can't be\n\t// evaluated right away; but that won't figure into the first tick calculated here.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\t// determine the first tick and emit our start log\n\ttick_start_ = FirstTick();\t// SLIM_MAX_TICK + 1 if it can't find a first block\n\t\n\tif (tick_start_ == SLIM_MAX_TICK + 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_RunInitializeCallbacks): No Eidos event found to start the simulation.\" << EidosTerminate();\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_OUTSTREAM << \"\\n// Starting run at tick <start>:\\n\" << tick_start_ << \" \" << \"\\n\" << std::endl;\n\t\n\t// start at the beginning; note that tree_seq_tick_ will not equal tick_ until after reproduction\n\tSetTick(tick_start_);\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[0]);\n#endif\n\t\n\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\tClearErrorContext();\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tif (gEidosProfilingClientCount)\n\t\tCollectSLiMguiMemoryUsageProfileInfo();\n#endif\n}\n\nvoid Community::RunInitializeCallbacks(void)\n{\n\t// zero out the initialization check counts\n\tnum_interaction_types_ = 0;\n\tnum_modeltype_declarations_ = 0;\n\t\n\t// execute `species all` initialize() callbacks, which should always have a tick of 0 set\n\tstd::vector<SLiMEidosBlock*> init_blocks = ScriptBlocksMatching(0, SLiMEidosBlockType::SLiMEidosInitializeCallback, -1, -1, -1, -1, nullptr);\n\t\n\tfor (auto script_block : init_blocks)\n\t\tExecuteEidosEvent(script_block);\n\t\n\t// check for complete initialization\n\t\n\t// In multispecies models, we are responsible for finalizing the model type decision at the end of our initialization\n\t// In single-species models, the Species will do this after its init instead; see Species::RunInitializeCallbacks().\n\tif (is_explicit_species_)\n\t{\n\t\t// We default to WF, but here we explicitly declare our model type so everybody knows the default was not changed\n\t\t// This cements the choice of WF if a `species all` callback does not declare a model type explicitly\n\t\tif (num_modeltype_declarations_ == 0)\n\t\t\tSetModelType(SLiMModelType::kModelTypeWF);\n\t}\n}\n\n// execute a script event in the population; the script is assumed to be due to trigger\nvoid Community::ExecuteEidosEvent(SLiMEidosBlock *p_script_block)\n{\n\tif (!p_script_block->block_active_)\n\t\treturn;\n\t\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tEidosDebugPointIndent indenter;\n\t\n\t{\n\t\tEidosInterpreterDebugPointsSet *debug_points = DebugPoints();\n\t\tEidosToken *decl_token = p_script_block->root_node_->token_;\n\t\t\n\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t{\n\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG \";\n\t\t\t\n\t\t\tif (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventFirst)\n\t\t\t\tSLIM_ERRSTREAM << \"first()\";\n\t\t\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventEarly)\n\t\t\t\tSLIM_ERRSTREAM << \"early()\";\n\t\t\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventLate)\n\t\t\t\tSLIM_ERRSTREAM << \"late()\";\n\t\t\telse if (p_script_block->type_ == SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t\t\t\tSLIM_ERRSTREAM << \"initialize()\";\n\t\t\telse\n\t\t\t\tSLIM_ERRSTREAM << \"???\";\n\t\t\t\n\t\t\tif (p_script_block->block_id_ != -1)\n\t\t\t\tSLIM_ERRSTREAM << \" s\" << p_script_block->block_id_;\n\t\t\t\n\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << DebugPointInfo() << \")\" << std::endl;\n\t\t\tindenter.indent();\n\t\t}\n\t}\n#endif\n\t\n#ifdef SLIMGUI\n\tif ((p_script_block->type_ == SLiMEidosBlockType::SLiMEidosInitializeCallback) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventFirst) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventEarly) ||\n\t\t(p_script_block->type_ == SLiMEidosBlockType::SLiMEidosEventLate))\n\t{\n\t\t// These four types of script blocks log out to the scheduling stream when executed in SLiMgui\n\t\tgSLiMScheduling << \"\\tevent: \";\n\t\tp_script_block->PrintDeclaration(gSLiMScheduling, this);\n\t\tgSLiMScheduling << std::endl;\n\t}\n#endif\n\t\n\tSLiMEidosBlockType old_executing_block_type = executing_block_type_;\n\texecuting_block_type_ = p_script_block->type_;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &SymbolTable());\n\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\tEidosFunctionMap &function_map = FunctionMap();\n\t\n\tEidosInterpreter interpreter(p_script_block->compound_statement_node_, client_symbols, function_map, this, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t, check_infinite_loops_\n#endif\n\t\t);\n\t\n\tif (p_script_block->contains_self_)\n\t\tcallback_symbols.InitializeConstantSymbolEntry(p_script_block->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\n\ttry\n\t{\n\t\t// Interpret the script; the result from the interpretation is not used for anything and must be void\n\t\tEidosValue_SP result = interpreter.EvaluateInternalBlock(p_script_block->script_);\n\t\t\n\t\tif (result->Type() != EidosValueType::kValueVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteEidosEvent): \" << p_script_block->type_ << \" callbacks must not return a value; use a \\\"return;\\\" statement to explicitly return void if desired.\" << EidosTerminate(p_script_block->identifier_token_);\n\t}\n\tcatch (...)\n\t{\n\t\tthrow;\n\t}\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(profile_callback_totals_[(int)executing_block_type_]);\n#endif\n\t\n\texecuting_block_type_ = old_executing_block_type;\n}\n\nvoid Community::AllSpecies_CheckIntegrity(void)\n{\n#if DEBUG\n\t// Check the integrity of all the information in the individuals and haplosomes of the parental population\n\tfor (Species *species : all_species_)\n\t\tspecies->Species_CheckIntegrity();\n#endif\n\t\n#if DEBUG\n\t// Check for species consistency across all of the objects in each species\n\tfor (size_t species_index = 0; species_index < all_species_.size(); ++species_index)\n\t{\n\t\tSpecies *species = all_species_[species_index];\n\t\t\n\t\tif (&species->community_ != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) species->community_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tif (species->model_type_ != model_type_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) species->model_type_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tif (species->species_id_ != (int)species_index)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) species->species_id_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\t\tsize_t chromosomes_count = chromosomes.size();\n\t\t\n\t\tfor (size_t chromosome_index = 0; chromosome_index < chromosomes_count; chromosome_index++)\n\t\t{\n\t\t\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\t\t\n\t\t\tif (&chromosome->species_ != species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) chromosome->species_ mismatch.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (&chromosome->community_ != this)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) chromosome->community_ mismatch.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tPopulation &population = species->population_;\n\t\tconst std::map<slim_objectid_t,MutationType*> &muttypes = species->MutationTypes();\n\t\tconst std::map<slim_objectid_t,GenomicElementType*> &getypes = species->GenomicElementTypes();\n\t\t\n\t\tif (&population.species_ != species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) population.species_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tfor (auto const &subpop_iter : population.subpops_)\n\t\t\tif (&subpop_iter.second->species_ != species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) subpopulation->species_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tfor (auto const &muttype_iter : muttypes)\n\t\t\tif (&muttype_iter.second->species_ != species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) muttype->species_ mismatch.\" << EidosTerminate();\n\t\t\n\t\tfor (auto const &getype_iter : getypes)\n\t\t\tif (&getype_iter.second->species_ != species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) getype->species_ mismatch.\" << EidosTerminate();\n\t}\n#endif\n\t\n#if DEBUG\n#if DEBUG_LESS_INTENSIVE\n\t// These tests are extremely intensive, so sometimes it's useful to dial them down...\n\tif ((Tick() % 10) != 5)\n\t\treturn;\n#endif\n\t\n\t// Check the integrity of the mutation registry; all MutationIndex values should be in range\n\tfor (Species *species : all_species_)\n\t{\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = species->population_.MutationRegistry(&registry_size);\n\t\tstd::vector<MutationIndex> indices;\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutationIndex mutation_index = registry[registry_index];\n\t\t\t\n\t\t\tif ((mutation_index < 0) || (mutation_index >= gSLiM_Mutation_Block_Capacity))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) mutation index \" << mutation_index << \" out of the mutation block.\" << EidosTerminate();\n\t\t\t\n\t\t\tindices.push_back(mutation_index);\n\t\t}\n\t\t\n\t\tsize_t original_size = indices.size();\n\t\t\n\t\tstd::sort(indices.begin(), indices.end());\n\t\tindices.resize(static_cast<size_t>(std::distance(indices.begin(), std::unique(indices.begin(), indices.end()))));\n\t\t\n\t\tif (indices.size() != original_size)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::AllSpecies_CheckIntegrity): (internal error) duplicate mutation index in the mutation registry (size difference \" << (original_size - indices.size()) << \").\" << EidosTerminate();\n\t}\n#endif\n}\n\nvoid Community::AllSpecies_PurgeRemovedObjects(void)\n{\n\t// Purge removed subpopulations and killed individuals in all subpopulations.  This doesn't have\n\t// to happen at any particular frequency, really, but it frees up memory, and it also allows\n\t// frequency/count tallying to use MutationRun refcounts to run faster, so we do it after every\n\t// stage of the tick cycle in nonWF models.  In WF models, individuals can't be killed so that\n\t// is a non-issue, and removal of subpops is generally infrequent, so we purge removed subpops\n\t// with PurgeRemovedSubpopulations() only in Population::SwapGenerations().\n\tfor (Species *species : all_species_)\n\t{\n\t\tspecies->EmptyGraveyard();\t\t// needs to be done first; uses subpopulation references\n\t\tspecies->population_.PurgeRemovedSubpopulations();\n\t}\n}\n\n//\n//\t\t_RunOneTickWF() : runs all the stages for one cycle of a WF model\n//\nbool Community::_RunOneTickWF(void)\n{\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tif (gEidosProfilingClientCount)\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->CollectMutationProfileInfo();\n#endif\n#endif\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 0: Execute first() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage0ExecuteFirstScripts;\n\t\tstd::vector<SLiMEidosBlock*> first_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventFirst, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : first_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[1]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 1: Execute early() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage1ExecuteEarlyScripts;\n\t\tstd::vector<SLiMEidosBlock*> early_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventEarly, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : early_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[2]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 2: Generate offspring: evolve all subpopulations\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->CheckMutationStackPolicy();\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage2GenerateOffspring;\n\t\t\n\t\t// increment the tree-sequence tick immediately, since we are now going to make a new generation of individuals\n\t\ttree_seq_tick_++;\n\t\ttree_seq_tick_offset_ = 0;\n\t\t// note that tick_ is incremented later!\n\t\t\n\t\t// first all species generate offspring\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\toffspring generation: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->WF_GenerateOffspring();\n\t\t\t\tspecies->has_recalculated_fitness_ = false;\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\t// then all species switch generations; this prevents access to the child generation of one species while another is still generating offspring\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->WF_SwitchToChildGeneration();\n\t\t\n\t\t// invalidate interactions, now that the generation they were valid for has disappeared\n\t\t// BCH 5 Oct. 2024: this moved upward slightly in the tick cycle; used to happen in \"remove fixed mutations\"\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tInvalidateInteractionsForSpecies(species);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n\t\t// Deregister any interaction() callbacks that have been scheduled for deregistration, since it is now safe to do so\n\t\t// BCH 5 Oct. 2024: this moved upward slightly in the tick cycle; used to happen in \"remove fixed mutations\"\n\t\tDeregisterScheduledInteractionBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[3]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 3: Swap generations\n\t//\n\t// BCH 10/5/2024: Note this stage swapped positions with \"remove fixed mutations\" as part of\n\t// the multispecies work; I do not expect that change to have any user-visible fallout\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage3SwapGenerations;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->WF_SwapGenerations();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[4]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 4: Remove fixed mutations and associated tasks\n\t//\n\t// BCH 10/5/2024: Note this stage swapped positions with \"swap generations\" as part of\n\t// the multispecies work; I do not expect that change to have any user-visible fallout\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage4RemoveFixedMutations;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->MaintainMutationRegistry();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[5]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 5: Execute late() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage5ExecuteLateScripts;\n\t\tstd::vector<SLiMEidosBlock*> late_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventLate, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : late_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[6]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 6: Calculate fitness values for the new parental generation\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage6CalculateFitness;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\tfitness recalculation: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->RecalculateFitness();\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n\t\t// Maintain our mutation run experiments; we want this overhead to appear within the stage 6 profile\n\t\t// FIXME wait, why should this overhead appear in the fitness recalculation step??\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->FinishMutationRunExperimentTimings();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[7]);\n#endif\n\t\t\n#ifdef SLIMGUI\n\t\t// Let SLiMgui survey the population for mean fitness and such, if it is our target\n\t\t// We do this outside of profiling and mutation run experiments, since SLiMgui overhead should not affect those\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->population_.SurveyPopulation();\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 7: Advance the tick counter and do end-cycle tasks\n\t//\n\t{\n\t\tcycle_stage_ = SLiMCycleStage::kWFStage7AdvanceTickCounter;\n\t\t\n#ifdef SLIMGUI\n\t\t// re-tally for SLiMgui; this tallies into separate counters, uses the selected subpops, etc.\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->HasGenetics())\n\t\t\t\tspecies->population_.TallyMutationReferencesAcrossPopulation_SLiMgui();\n#endif\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->MaintainTreeSequence();\n\t\t\n\t\t// LogFile output\n\t\tfor (LogFile *log_file : log_file_registry_)\n\t\t\tlog_file->TickEndCallout();\n\t\t\n\t\t// BCH 7/19/2024: At the end of each tick we again try to determine the tick ranges\n\t\t// for script blocks; we now do this in a deferred fashion to allow tick ranges to\n\t\t// contain constant expressions, including expressions involving constants that only\n\t\t// get defined later in the run.  We do it at tick end so the result is immediately\n\t\t// visible in SLiMgui.  It must be done before the tick counter increments, and\n\t\t// before the call to EstimatedLastTick() below.\n\t\tif (!all_tick_ranges_evaluated_)\n\t\t\tEvaluateScriptBlockTickRanges();\n\t\t\n\t\t// Advance the tick and cycle counters (note that tree_seq_tick_ was incremented earlier!)\n\t\ttick_++;\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->AdvanceCycleCounter();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tif (gEidosProfilingClientCount)\n\t\t\tCollectSLiMguiMemoryUsageProfileInfo();\n#endif\n\t\t\n\t\t// Decide whether the simulation is over.  We need to call EstimatedLastTick() every time; we can't\n\t\t// cache it, because it can change based upon changes in script registration / deregistration.\n\t\tbool result;\n\t\t\n\t\tif (sim_declared_finished_)\n\t\t\tresult = false;\n\t\telse\n\t\t\tresult = (tick_ <= EstimatedLastTick());\n\t\t\n\t\tif (!result)\n\t\t\tSimulationHasFinished();\n\t\t\n\t\t// Use a special cycle stage for the interstitial space between ticks, when Eidos console input runs\n\t\tcycle_stage_ = SLiMCycleStage::kStagePostCycle;\n\t\t\n\t\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\t\tClearErrorContext();\n\t\t\n\t\treturn result;\n\t}\n}\n\n//\n//\t\t_RunOneTickNonWF() : runs all the stages for one cycle of a nonWF model\n//\nbool Community::_RunOneTickNonWF(void)\n{\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tif (gEidosProfilingClientCount)\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->CollectMutationProfileInfo();\n#endif\n#endif\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 0: Execute first() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage0ExecuteFirstScripts;\n\t\tstd::vector<SLiMEidosBlock*> first_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventFirst, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : first_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[1]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 1: Generate offspring: call reproduction() callbacks\n\t//\n\t{\n\t\t// increment the tree-seq tick at the start of reproduction; note that in first() events it is one less than tick_!\n\t\ttree_seq_tick_++;\n\t\ttree_seq_tick_offset_ = 0;\n\n#if defined(SLIMGUI)\n\t\t// zero out offspring counts used for SLiMgui's display\n\t\tfor (Species *species : all_species_)\n\t\t{\n\t\t\tif (species->species_active_)\n\t\t\t{\n\t\t\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : species->population_.subpops_)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\t\n\t\t\t\t\tsubpop->gui_offspring_cloned_M_ = 0;\n\t\t\t\t\tsubpop->gui_offspring_cloned_F_ = 0;\n\t\t\t\t\tsubpop->gui_offspring_selfed_ = 0;\n\t\t\t\t\tsubpop->gui_offspring_crossed_ = 0;\n\t\t\t\t\tsubpop->gui_offspring_empty_ = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// zero out migration counts used for SLiMgui's display\n\t\t\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : species->population_.subpops_)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\t\n\t\t\t\t\tsubpop->gui_premigration_size_ = subpop->parent_subpop_size_;\n\t\t\t\t\tsubpop->gui_migrants_.clear();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->CheckMutationStackPolicy();\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage1GenerateOffspring;\n\t\t\n\t\t// BCH 28 September 2022: Offspring generation in nonWF models is now done in two passes: first all species generate\n\t\t// their offspring, then all species merge their offspring.  This allows multispecies interactions to remain valid\n\t\t// through the whole reproduction process.  In effect, reproduction is now kind of two separate tick cycle stages,\n\t\t// but this is not emphasized since it only makes a difference to multispecies models; conceptually it is one stage.\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\toffspring generation: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->nonWF_GenerateOffspring();\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\tmerge offspring: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->nonWF_MergeOffspring();\n\t\t\t\tspecies->has_recalculated_fitness_ = false;\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\t// Deregister any interaction() callbacks that have been scheduled for deregistration, since it is now safe to do so\n\t\tDeregisterScheduledInteractionBlocks();\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[2]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 2: Execute early() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts;\n\t\tstd::vector<SLiMEidosBlock*> early_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventEarly, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : early_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[3]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 3: Calculate fitness values for the new population\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage3CalculateFitness;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\tfitness recalculation: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->RecalculateFitness();\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n\t\t// Invalidate interactions, now that the cycle they were valid for is disappearing\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tInvalidateInteractionsForSpecies(species);\n\t\t\n\t\t// Deregister any interaction() callbacks that have been scheduled for deregistration, since it is now safe to do so\n\t\tDeregisterScheduledInteractionBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[4]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 4: Viability/survival selection\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage4SurvivalSelection;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t{\n\t\t\t\texecuting_species_ = species;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tif (is_explicit_species_)\n\t\t\t\t\tgSLiMScheduling << \"\\tviability/survival: species \" << species->name_ << std::endl;\n#endif\n\t\t\t\tspecies->nonWF_ViabilitySurvival();\n\t\t\t\t\n\t\t\t\texecuting_species_ = nullptr;\n\t\t\t}\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[5]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 5: Remove fixed mutations and associated tasks\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage5RemoveFixedMutations;\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->MaintainMutationRegistry();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[6]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 6: Execute late() script events for the current cycle\n\t//\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage6ExecuteLateScripts;\n\t\tstd::vector<SLiMEidosBlock*> late_blocks = ScriptBlocksMatching(tick_, SLiMEidosBlockType::SLiMEidosEventLate, -1, -1, -1, -1, nullptr);\n\t\t\n\t\tfor (auto script_block : late_blocks)\n\t\t\tExecuteEidosEvent(script_block);\n\t\t\n\t\t// the stage is done, so deregister script blocks as requested\n\t\tDeregisterScheduledScriptBlocks();\n\t\t\n\t\t// Maintain our mutation run experiments; we want this overhead to appear within the stage 6 profile\n\t\t// FIXME wait, why should this overhead appear in late() events??\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->FinishMutationRunExperimentTimings();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(profile_stage_totals_[7]);\n#endif\n\t}\n\t\n\t// BCH 4/8/2025: Now we check between tick cycle stages, to allow deferred scheduling within one tick.\n\tif (!all_tick_ranges_evaluated_)\n\t\tEvaluateScriptBlockTickRanges();\n\t\n\tCheckLongTermBoundary();\n\tAllSpecies_PurgeRemovedObjects();\n\tAllSpecies_CheckIntegrity();\n\t\n\t\n\t// ******************************************************************\n\t//\n\t// Stage 7: Advance the tick counter and do end-cycle tasks\n\t//\n\t{\n\t\tcycle_stage_ = SLiMCycleStage::kNonWFStage7AdvanceTickCounter;\n\t\t\n#ifdef SLIMGUI\n\t\t// Let SLiMgui survey the population for mean fitness and such, if it is our target\n\t\t// We do this outside of profiling and mutation run experiments, since SLiMgui overhead should not affect those\n\t\tfor (Species *species : all_species_)\n\t\t\tspecies->population_.SurveyPopulation();\n#endif\n\t\t\n#ifdef SLIMGUI\n\t\t// re-tally for SLiMgui; this tallies into separate counters, uses the selected subpops, etc.\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->HasGenetics())\n\t\t\t\tspecies->population_.TallyMutationReferencesAcrossPopulation_SLiMgui();\n#endif\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->MaintainTreeSequence();\n\t\t\n\t\t// LogFile output\n\t\tfor (LogFile *log_file : log_file_registry_)\n\t\t\tlog_file->TickEndCallout();\n\t\t\n\t\t// BCH 7/19/2024: At the end of each tick we again try to determine the tick ranges\n\t\t// for script blocks; we now do this in a deferred fashion to allow tick ranges to\n\t\t// contain constant expressions, including expressions involving constants that only\n\t\t// get defined later in the run.  We do it at tick end so the result is immediately\n\t\t// visible in SLiMgui.  It must be done before the tick counter increments, and\n\t\t// before the call to EstimatedLastTick() below.\n\t\tif (!all_tick_ranges_evaluated_)\n\t\t\tEvaluateScriptBlockTickRanges();\n\t\t\n\t\t// Advance the tick counter (note that tree_seq_tick_ is incremented after first() events in the next tick!)\n\t\ttick_++;\n\t\tfor (Species *species : all_species_)\n\t\t\tif (species->Active())\n\t\t\t\tspecies->AdvanceCycleCounter();\n\t\t\n\t\tfor (Species *species : all_species_)\n\t\t{\n\t\t\tif (species->Active())\n\t\t\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : species->population_.subpops_)\n\t\t\t\t\tsubpop_pair.second->IncrementIndividualAges();\n\t\t}\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tif (gEidosProfilingClientCount)\n\t\t\tCollectSLiMguiMemoryUsageProfileInfo();\n#endif\n\t\t\n\t\t// Decide whether the simulation is over.  We need to call EstimatedLastTick() every time; we can't\n\t\t// cache it, because it can change based upon changes in script registration / deregistration.\n\t\tbool result;\n\t\t\n\t\tif (sim_declared_finished_)\n\t\t\tresult = false;\n\t\telse\n\t\t\tresult = (tick_ <= EstimatedLastTick());\n\t\t\n\t\tif (!result)\n\t\t\tSimulationHasFinished();\n\t\t\n\t\t// Use a special cycle stage for the interstitial space between ticks, when Eidos console input runs\n\t\tcycle_stage_ = SLiMCycleStage::kStagePostCycle;\n\t\t\n\t\t// Zero out error-reporting info so raises elsewhere don't get attributed to this script\n\t\tClearErrorContext();\n\t\t\n\t\treturn result;\n\t}\n}\n\nvoid Community::SimulationHasFinished(void)\n{\n\t// This is an opportunity for final calculation/output when a simulation finishes\n\tfor (Species *species : all_species_)\n\t\tspecies->SimulationHasFinished();\n\t\n\t// Error on any script blocks that never got scheduled\n\tFlagUnevaluatedScriptBlockTickRanges();\n}\n\nvoid Community::TabulateSLiMMemoryUsage_Community(SLiMMemoryUsage_Community *p_usage, EidosSymbolTable *p_current_symbols)\n{\n\tEIDOS_BZERO(p_usage, sizeof(SLiMMemoryUsage_Community));\n\t\n\t// Community usage\n\tp_usage->communityObjects_count = 1;\n\tp_usage->communityObjects = p_usage->communityObjects_count * sizeof(Community);\n\t\n\t// Mutation global buffers\n\tp_usage->mutationRefcountBuffer = SLiMMemoryUsageForMutationRefcounts();\n\tp_usage->mutationUnusedPoolSpace = SLiMMemoryUsageForFreeMutations();\t\t// note that in SLiMgui everybody shares this\n\t\n\t// InteractionType\n\t{\n\t\tp_usage->interactionTypeObjects_count = interaction_types_.size();\n\t\tp_usage->interactionTypeObjects = sizeof(InteractionType) * p_usage->interactionTypeObjects_count;\n\t\t\n\t\tfor (auto iter : interaction_types_)\n\t\t{\n\t\t\tp_usage->interactionTypeKDTrees += iter.second->MemoryUsageForKDTrees();\n\t\t\tp_usage->interactionTypePositionCaches += iter.second->MemoryUsageForPositions();\n\t\t}\n\t\t\n\t\tp_usage->interactionTypeSparseVectorPool += InteractionType::MemoryUsageForSparseVectorPool();\n\t}\n\t\n\t// Eidos usage\n\tp_usage->eidosASTNodePool = gEidosASTNodePool->MemoryUsageForAllNodes();\n\tp_usage->eidosSymbolTablePool = MemoryUsageForSymbolTables(p_current_symbols);\n\tp_usage->eidosValuePool = gEidosValuePool->MemoryUsageForAllNodes();\n\t\n\tfor (auto const &filebuf_pair : gEidosBufferedZipAppendData)\n\t\tp_usage->fileBuffers += filebuf_pair.second.capacity();\n\t\n\t// Total\n\tSumUpMemoryUsage_Community(*p_usage);\n}\n\n#if (SLIMPROFILING == 1)\n// PROFILING\nvoid Community::StartProfiling(void)\n{\n\tgEidosProfilingClientCount++;\n\t\n\t// prepare for profiling by measuring profile block overhead and lag\n\tEidos_PrepareForProfiling();\n\t\n\t// initialize counters\n\tprofile_elapsed_CPU_clock = 0;\n\tprofile_elapsed_wall_clock = 0;\n\tprofile_start_tick = Tick();\n\t\n\t// call this first, purely for its side effect of emptying out any pending profile counts\n\t// note that the accumulators governed by this method get zeroed out down below\n\tfor (Species *focal_species : all_species_)\n\t\tfocal_species->CollectMutationProfileInfo();\n\t\n\t// zero out profile counts for cycle stages\n\tfor (int i = 0; i < 9; ++i)\n\t\tprofile_stage_totals_[i] = 0;\n\t\n\t// zero out profile counts for callback types (note SLiMEidosUserDefinedFunction is excluded; that is not a category we profile)\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosEventFirst)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosEventEarly)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosEventLate)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosInitializeCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMutationEffectCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosFitnessEffectCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosInteractionCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosModifyChildCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosRecombinationCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMutationCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosReproductionCallback)] = 0;\n\tprofile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosSurvivalCallback)] = 0;\n\t\n\t// zero out profile counts for script blocks; dynamic scripts will be zeroed on construction\n\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\n\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\tif (script_block->type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\t// exclude user-defined functions; not user-visible as blocks\n\t\t\tscript_block->root_node_->ZeroProfileTotals();\n\t\n\t// zero out profile counts for all user-defined functions\n\tEidosFunctionMap &function_map = FunctionMap();\n\t\n\tfor (auto functionPairIter = function_map.begin(); functionPairIter != function_map.end(); ++functionPairIter)\n\t{\n\t\tconst EidosFunctionSignature *signature = functionPairIter->second.get();\n\t\t\n\t\tif (signature->body_script_ && signature->user_defined_)\n\t\t\tsignature->body_script_->AST()->ZeroProfileTotals();\n\t}\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t// zero out mutation run metrics that are collected by CollectMutationProfileInfo()\n\tfor (Species *focal_species : all_species_)\n\t{\n\t\tfocal_species->profile_nonneutral_regime_history_.clear();\n\t\tfocal_species->profile_max_mutation_index_ = 0;\n\t\t\n\t\tfor (Chromosome *focal_chromosome : focal_species->Chromosomes())\n\t\t{\n\t\t\tfocal_chromosome->profile_mutcount_history_.clear();\n\t\t\tfocal_chromosome->profile_mutation_total_usage_ = 0;\n\t\t\tfocal_chromosome->profile_nonneutral_mutation_total_ = 0;\n\t\t\tfocal_chromosome->profile_mutrun_total_usage_ = 0;\n\t\t\tfocal_chromosome->profile_unique_mutrun_total_ = 0;\n\t\t\tfocal_chromosome->profile_mutrun_nonneutral_recache_total_ = 0;\n\t\t}\n\t}\n#endif\n\t\n\t// zero out memory usage metrics\n\tEIDOS_BZERO(&profile_last_memory_usage_Community, sizeof(SLiMMemoryUsage_Community));\n\tEIDOS_BZERO(&profile_total_memory_usage_Community, sizeof(SLiMMemoryUsage_Community));\n\tEIDOS_BZERO(&profile_last_memory_usage_AllSpecies, sizeof(SLiMMemoryUsage_Species));\n\tEIDOS_BZERO(&profile_total_memory_usage_AllSpecies, sizeof(SLiMMemoryUsage_Species));\n\ttotal_memory_tallies_ = 0;\n\t\n\ttime(&profile_start_date);\n\tprofile_start_clock = std::chrono::steady_clock::now();\n}\n\nvoid Community::StopProfiling(void)\n{\n\ttime(&profile_end_date);\n\tprofile_end_clock = std::chrono::steady_clock::now();\n\tprofile_end_tick = Tick();\n\t\n\tgEidosProfilingClientCount--;\n}\n\nvoid Community::CollectSLiMguiMemoryUsageProfileInfo(void)\n{\n\t// Gather the data\n\tEIDOS_BZERO(&profile_last_memory_usage_AllSpecies, sizeof(SLiMMemoryUsage_Species));\n\t\n\tTabulateSLiMMemoryUsage_Community(&profile_last_memory_usage_Community, nullptr);\n\t\n\tfor (Species *species : all_species_)\n\t{\n\t\tspecies->TabulateSLiMMemoryUsage_Species(&species->profile_last_memory_usage_Species);\n\t\t\n\t\t// Add this tick's usage for this species into its single-species accumulator\n\t\tAccumulateMemoryUsageIntoTotal_Species(species->profile_last_memory_usage_Species, species->profile_total_memory_usage_Species);\n\t\t\n\t\t// Add this tick's usage for this species into this tick's overall species accumulator\n\t\tAccumulateMemoryUsageIntoTotal_Species(species->profile_last_memory_usage_Species, profile_last_memory_usage_AllSpecies);\n\t}\n\t\n\t// Add this tick's data into our top-level accumulators\n\tAccumulateMemoryUsageIntoTotal_Community(profile_last_memory_usage_Community, profile_total_memory_usage_Community);\n\tAccumulateMemoryUsageIntoTotal_Species(profile_last_memory_usage_AllSpecies, profile_total_memory_usage_AllSpecies);\n\t\n\t// Increment our accumulator count; we divide by this to get averages\n\ttotal_memory_tallies_++;\n}\n#endif\n\n#ifdef SLIMGUI\nvoid Community::FileWriteNotification(const std::string &p_file_path, std::vector<std::string> &&p_lines, bool p_append)\n{\n\tauto buffer_iter = std::find(file_write_paths_.begin(), file_write_paths_.end(), p_file_path);\n\t\n\tif (buffer_iter == file_write_paths_.end())\n\t{\n\t\t// No existing buffer for this path, so make a new one; this does not mean the file is new!\n\t\tfile_write_paths_.emplace_back(p_file_path);\n\t\tfile_write_buffers_.emplace_back(std::move(p_lines));\n\t\tfile_write_appends_.emplace_back(p_append);\n\t}\n\telse\n\t{\n\t\t// Use the existing buffer for this path\n\t\tsize_t buffer_index = std::distance(file_write_paths_.begin(), buffer_iter);\n\t\tstd::vector<std::string> &buffer = file_write_buffers_[buffer_index];\n\t\t\n\t\tif (!p_append)\n\t\t\tbuffer.clear();\n\t\t\n\t\tfor (std::string &line : p_lines)\n\t\t\tbuffer.emplace_back(std::move(line));\n\t\t\n\t\t// Note the append flag; the vector here is always parallel to the main vector\n\t\tfile_write_appends_[buffer_index] = p_append;\n\t}\n}\n#endif\n\nvoid Community::AllSpecies_TSXC_Enable(void)\n{\n\t// This is called by command-line slim if a -TSXC command-line option is supplied; the point of this is to allow\n\t// tree-sequence recording to be turned on, with mutation recording and runtime crosschecks, with a simple\n\t// command-line flag, so that my existing test suite can be crosschecked easily.  The -TSXC flag is not public.\n\tfor (Species *species : all_species_)\n\t\tspecies->TSXC_Enable();\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_ERRSTREAM << \"// ********** Turning on tree-sequence recording with crosschecks (-TSXC).\" << std::endl << std::endl;\n}\n\nvoid Community::AllSpecies_TSF_Enable(void)\n{\n    // This is called by command-line slim if a -TSF command-line option is supplied; the point of this is to allow\n    // tree-sequence recording to be turned on, with mutation recording but without runtime crosschecks, with a simple\n    // command-line flag, so that my existing test suite can be tested with tree-seq easily.  -TSF is not public.\n\tfor (Species *species : all_species_)\n\t\tspecies->TSF_Enable();\n    \n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_ERRSTREAM << \"// ********** Turning on tree-sequence recording without crosschecks (-TSF).\" << std::endl << std::endl;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/community.h",
    "content": "//\n//  community.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/28/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n SLiM encapsulates an ecological community - a multispecies simulation run - as a Community object, containing Species objects\n representing species in the simulated community.\n \n */\n\n#ifndef __SLiM__community__\n#define __SLiM__community__\n\n\n#include <vector>\n#include <chrono>\n\n#include \"species.h\"\n#include \"slim_globals.h\"\n#include \"eidos_script.h\"\n#include \"eidos_value.h\"\n#include \"eidos_functions.h\"\n#include \"slim_eidos_block.h\"\n\n\nclass EidosInterpreter;\nclass Individual;\nclass LogFile;\n\n#ifdef SLIMGUI\n// Forward declaration of EidosInterpreterDebugPointsSet; see eidos_interpreter.cpp\nstruct EidosInterpreterDebugPointsSet_struct;\ntypedef EidosInterpreterDebugPointsSet_struct EidosInterpreterDebugPointsSet;\n#endif\n\nextern EidosClass *gSLiM_Community_Class;\n\n\n#pragma mark -\n#pragma mark Community\n#pragma mark -\n\nclass Community : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\t// the way we handle script blocks is complicated and is private even against SLiMgui\n\t\n\tSLiMEidosScript *script_;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// OWNED POINTER: the whole input file script\n\tstd::vector<SLiMEidosBlock*> script_blocks_;\t\t\t\t\t\t\t\t\t// OWNED POINTERS: script blocks, both from the input file script and programmatic\n\tstd::vector<SLiMEidosBlock*> scheduled_deregistrations_;\t\t\t\t\t\t// NOT OWNED: blocks in script_blocks_ that are scheduled for deregistration\n\tstd::vector<SLiMEidosBlock*> scheduled_interaction_deregs_;\t\t\t\t\t\t// NOT OWNED: interaction() callbacks in script_blocks_ that are scheduled for deregistration\n\t\n\t// a cache of the last tick for the simulation, for speed\n\tbool all_tick_ranges_evaluated_ = false;\t\t\t\t\t\t\t\t\t\t// false until all tick ranges have been determined\n\tbool last_script_block_tick_cached_ = false;\n\tslim_tick_t last_script_block_tick_;\t\t\t\t\t\t\t\t\t\t\t// the last tick in which a bounded script block is scheduled to run\n\t\n\t// scripts blocks prearranged for fast lookup; these are all stored in script_blocks_ as well\n\tbool script_block_types_cached_ = false;\n\tstd::vector<SLiMEidosBlock*> cached_first_events_;\n\tstd::vector<SLiMEidosBlock*> cached_early_events_;\n\tstd::vector<SLiMEidosBlock*> cached_late_events_;\n\tstd::vector<SLiMEidosBlock*> cached_initialize_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_mutationEffect_callbacks_;\n\tstd::unordered_multimap<slim_tick_t, SLiMEidosBlock*> cached_fitnessEffect_callbacks_onetick_;\t// see ValidateScriptBlockCaches() for details\n\tstd::vector<SLiMEidosBlock*> cached_fitnessEffect_callbacks_multitick_;\n\tstd::vector<SLiMEidosBlock*> cached_interaction_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_matechoice_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_modifychild_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_recombination_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_mutation_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_survival_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_reproduction_callbacks_;\n\tstd::vector<SLiMEidosBlock*> cached_userdef_functions_;\n\t\n#ifdef SLIMGUI\n\tEidosInterpreterDebugPointsSet *debug_points_ = nullptr;\t\t\t\t\t\t// NOT OWNED; line numbers for all lines with debugging points set\n#endif\n\t\n\t// these maps compile the objects from all species into a single sorted list for presentation in the UI etc.\n\tstd::map<slim_objectid_t,MutationType*> all_mutation_types_;\t\t\t\t\t// NOT OWNED: each species owns its own mutation types\n\tstd::map<slim_objectid_t,GenomicElementType*> all_genomic_element_types_;\t\t// NOT OWNED: each species owns its own genomic element types\n\t\n\tstd::map<slim_objectid_t,InteractionType*> interaction_types_;\t\t\t\t\t// OWNED POINTERS: this map is the owner of all allocated InteractionType objects\n\t\n\tint num_interaction_types_;\n\tint num_modeltype_declarations_;\n\t\n#ifdef SLIMGUI\npublic:\n\tbool simulation_valid_ = true;\t\t\t\t\t\t\t\t\t\t\t\t\t// set to false if a terminating condition is encountered while running in SLiMgui\n#else\nprivate:\n#endif\n\t\n\tstd::vector<Species *>all_species_;\t\t\t\t\t\t\t\t\t\t\t\t// a vector of the species being simulated, in declaration order\n\tSpecies *active_species_ = nullptr;\t\t\t\t\t\t\t\t\t\t\t\t// the species presently executing; currently used only for initialize() callback dispatch\n\t\n\tEidosSymbolTable *simulation_globals_ = nullptr;\t\t\t\t\t\t\t\t// A symbol table of global variables, typically empty; the parent of simulation_constants_\n\tEidosSymbolTable *simulation_constants_ = nullptr;\t\t\t\t\t\t\t\t// A symbol table of constants defined by SLiM (p1, g1, m1, s1, etc.)\n\tEidosFunctionMap simulation_functions_;\t\t\t\t\t\t\t\t\t\t\t// A map of all defined functions in the simulation\n\t\n\t// these ivars track top-level simulation state: the tick, cycle stage, etc.\n\tslim_tick_t tick_start_ = 0;\t\t\t\t\t\t\t\t\t\t\t\t\t// the first tick number for which the simulation will run\n\tslim_tick_t tick_ = -1;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// the current tick reached in simulation\n\tEidosValue_SP cached_value_tick_;\t\t\t\t\t\t\t\t\t\t\t\t// a cached value for tick_; invalidates automatically when used\n\t\n\tSLiMCycleStage cycle_stage_ = SLiMCycleStage::kStagePreCycle;\t\t\t\t\t// the within-cycle stage currently being executed\n\tbool sim_declared_finished_ = false;\t\t\t\t\t\t\t\t\t\t\t// a flag set by Community.simulationFinished() to halt the sim at the end of the current tick\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t\t\t\t\t\t\t\t// for fast setup of the symbol table\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t\t\t\t\t\t// a user-defined tag value\n\t\n\t// LogFile registry, for logging data out to a file\n\tstd::vector<LogFile *> log_file_registry_;\t\t\t\t\t\t\t\t\t\t// OWNED POINTERS (under retain/release)\n\t\npublic:\n\t\n\tbool is_explicit_species_ = false;\t\t\t\t\t\t\t\t\t\t\t\t// true if we have explicit species declarations (even if only one, even if named \"sim\")\n\t\n\tbool model_type_set_ = false;\t\t\t\t\t\t\t\t\t\t\t\t\t// true if the model type has been set, either explicitly or implicitly\n\tSLiMModelType model_type_ = SLiMModelType::kModelTypeWF;\t\t\t\t\t\t// the overall model type: WF or nonWF, at present; affects many other things!\n\t\n\t// warning flags; used to issue warnings only once per run of the simulation\n\tbool warned_early_mutation_add_ = false;\n\tbool warned_early_mutation_remove_ = false;\n\tbool warned_early_output_ = false;\n\tbool warned_early_read_ = false;\n\tbool warned_no_max_distance_ = false;\n\tbool warned_readFromVCF_mutIDs_unused_ = false;\n\tbool warned_no_ancestry_read_ = false;\n\tbool warned_experiment_run_clocks_ = false;\n\tbool warned_spatial_map_color_deprecated_ = false;\n\tbool warned_spatial_map_image_deprecated_ = false;\n\t\n\t// checking for infinite loops, configurable with initializeSLiMOptions()\n#ifdef SLIMGUI\n\tbool check_infinite_loops_ = true;\n#endif\n\t\n\t// these ivars are set around callbacks so we know what type of callback we're in, to prevent illegal operations during callbacks\n\t// to make them easier to find, such checks should always be marked with a comment: // TIMING RESTRICTION\n\tSLiMEidosBlockType executing_block_type_ = SLiMEidosBlockType::SLiMEidosNoBlockType;\t// the innermost callback type we're executing now\n\tSpecies *executing_species_ = nullptr;\t\t\t\t\t\t\t\t\t\t\t\t\t// the species executing in the tick cycle right now\n\tIndividual *focal_modification_child_;\t\t\t\t\t// set during a modifyChild() callback to indicate the child being modified\n\t\n\t// change flags; used only by SLiMgui, to know that something has changed and a UI update is needed; start as true to provoke an initial display\n\tbool interaction_types_changed_ = true;\n\tbool mutation_types_changed_ = true;\n\tbool genomic_element_types_changed_ = true;\n\tbool chromosome_changed_ = true;\n\tbool scripts_changed_ = true;\n\t\n\t// provenance-related stuff: remembering the seed and command-line args\n\tunsigned long int original_seed_;\t\t\t\t\t\t\t\t\t\t\t\t// the initial seed value, from the user via the -s CLI option, or auto-generated\n\tstd::vector<std::string> cli_params_;\t\t\t\t\t\t\t\t\t\t\t// CLI parameters; an empty vector when run in SLiMgui, at least for now\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING : Community now keeps track of overall profiling variables\n\ttime_t profile_start_date;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// resolution of seconds, easy to convert to a date string\n\ttime_t profile_end_date;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// resolution of seconds, easy to convert to a date string\n\tstd::chrono::steady_clock::time_point profile_start_clock;\t\t\t\t\t\t// sub-second resolution, good for elapsed time\n\tstd::chrono::steady_clock::time_point profile_end_clock;\t\t\t\t\t\t// sub-second resolution, good for elapsed time\n\tstd::clock_t profile_elapsed_CPU_clock;\t\t\t\t\t\t\t\t\t\t\t// elapsed CPU time inside SLiM\n\teidos_profile_t profile_elapsed_wall_clock;\t\t\t\t\t\t\t\t\t\t// elapsed wall time inside SLiM\n\tslim_tick_t profile_start_tick;\t\t\t\t\t\t\t\t\t\t\t\t\t// the SLiM tick when profiling started\n\tslim_tick_t profile_end_tick;\t\t\t\t\t\t\t\t\t\t\t\t\t// the SLiM tick when profiling ended\n\t\n\t// PROFILING : Community keeps track of script timing counts\n\teidos_profile_t profile_stage_totals_[9];\t\t\t\t\t\t\t\t\t\t// profiling clocks; index 0 is initialize(), the rest follow sequentially; [8] is TS simplification\n\teidos_profile_t profile_callback_totals_[13];\t\t\t\t\t\t\t\t\t// profiling clocks; these follow SLiMEidosBlockType, except no SLiMEidosUserDefinedFunction\n\t\n\t// PROFILING : Community keeps track of its memory usage profile info (as does Species)\n\tSLiMMemoryUsage_Community profile_last_memory_usage_Community;\n\tSLiMMemoryUsage_Community profile_total_memory_usage_Community;\n\tSLiMMemoryUsage_Species profile_last_memory_usage_AllSpecies;\n\tSLiMMemoryUsage_Species profile_total_memory_usage_AllSpecies;\n\tint64_t total_memory_tallies_;\t\t// this is the total number of accumulations, for both Community and all Species under it\n#endif\t// (SLIMPROFILING == 1)\n\t\n\tCommunity(const Community&) = delete;\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tCommunity& operator=(const Community&) = delete;\t\t\t\t\t\t\t\t// no copying\n\texplicit Community(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// construct a Community; call InitializeFromFile() next\n\t~Community(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\tvoid InitializeFromFile(std::istream &p_infile);\t\t\t\t\t\t\t\t// parse an input file; call after construction\n\tvoid InitializeRNGFromSeed(unsigned long int *p_override_seed_ptr);\t\t\t\t// call after InitializeFromFile(), generally\n\tvoid FinishInitialization(void);\t\t\t\t\t\t\t\t\t\t\t\t// call last, after InitializeRNGFromSeed()\n\t\n\tvoid TabulateSLiMMemoryUsage_Community(SLiMMemoryUsage_Community *p_usage, EidosSymbolTable *p_current_symbols);\t\t// used by outputUsage() and SLiMgui profiling\n\t\n\t// Managing script blocks; these two methods should be used as a matched pair, bracketing each cycle stage that calls out to script\n\tvoid ValidateScriptBlockCaches(void);\n\tstd::vector<SLiMEidosBlock*> ScriptBlocksMatching(slim_tick_t p_tick, SLiMEidosBlockType p_event_type, slim_objectid_t p_mutation_type_id, slim_objectid_t p_interaction_type_id, slim_objectid_t p_subpopulation_id, int64_t p_chromosome_id, Species *p_species);\n\tstd::vector<SLiMEidosBlock*> &AllScriptBlocks();\n\tstd::vector<SLiMEidosBlock*> AllScriptBlocksForSpecies(Species *p_species);\n\tvoid OptimizeScriptBlock(SLiMEidosBlock *p_script_block);\n\tvoid AddScriptBlock(SLiMEidosBlock *p_script_block, EidosInterpreter *p_interpreter, const EidosToken *p_error_token);\n\tvoid DeregisterScheduledScriptBlocks(void);\n\tvoid DeregisterScheduledInteractionBlocks(void);\n\tvoid ExecuteFunctionDefinitionBlock(SLiMEidosBlock *p_script_block);\t\t\t// execute a SLiMEidosBlock that defines a function\n\tvoid CheckScheduling(slim_tick_t p_target_tick, SLiMCycleStage p_target_stage);\n\t\n\t// Managing resources shared across the community\n\tbool SubpopulationIDInUse(slim_objectid_t p_subpop_id);\t\t\t\t\t\t\t// not whether a SLiM subpop with this ID currently exists, but whether the ID is \"in use\"\n\tbool SubpopulationNameInUse(const std::string &p_subpop_name);\t\t\t\t\t// not whether a SLiM subpop with this name currently exists, but whether the name is \"in use\"\n\t\n\tSubpopulation *SubpopulationWithID(slim_objectid_t p_subpop_id);\n\tSubpopulation *SubpopulationWithName(const std::string &p_subpop_name);\n\tMutationType *MutationTypeWithID(slim_objectid_t p_muttype_id);\n\tGenomicElementType *GenomicElementTypeWithID(slim_objectid_t p_getype_id);\n\tSLiMEidosBlock *ScriptBlockWithID(slim_objectid_t p_script_block_id);\n\tSpecies *SpeciesWithID(slim_objectid_t p_species_id);\n\t\n\tSpecies *SpeciesWithName(const std::string &species_name);\n\t\n\tinline InteractionType *InteractionTypeWithID(slim_objectid_t p_inttype_id) {\n\t\tauto id_iter = interaction_types_.find(p_inttype_id);\n\t\treturn (id_iter == interaction_types_.end()) ? nullptr : id_iter->second;\n\t}\n\t\n\tinline __attribute__((always_inline)) const std::map<slim_objectid_t,MutationType*> &AllMutationTypes(void) const\t\t\t{ return all_mutation_types_; }\n\tinline __attribute__((always_inline)) const std::map<slim_objectid_t,GenomicElementType*> &AllGenomicElementTypes(void)\t\t{ return all_genomic_element_types_; }\n\tinline __attribute__((always_inline)) const std::map<slim_objectid_t,InteractionType*> &AllInteractionTypes(void)\t\t\t{ return interaction_types_; }\n\t\n\tvoid InvalidateInteractionsForSpecies(Species *p_invalid_species);\n\tvoid InvalidateInteractionsForSubpopulation(Subpopulation *p_invalid_subpop);\n\t\n\t// Checking for species identity; these return nullptr if the objects do not all belong to the same species\n\t// Calls to these methods, and other such species checks, should be labeled SPECIES CONSISTENCY CHECK to make them easier to find\n\tstatic Species *SpeciesForIndividualsVector(const Individual * const *individuals, int value_count);\n\tstatic Species *SpeciesForIndividuals(EidosValue *value);\n\t\n\tstatic Species *SpeciesForHaplosomesVector(const Haplosome * const *haplosomes, int value_count);\n\tstatic Species *SpeciesForHaplosomes(EidosValue *value);\n\t\n\tstatic Species *SpeciesForMutationsVector(const Mutation * const *mutations, int value_count);\n\tstatic Species *SpeciesForMutations(EidosValue *value);\n\t\n\t// Running ticks\n\tbool RunOneTick(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// run one tick and advance the tick count; returns false if finished\n\tbool _RunOneTick(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// does the work of RunOneTick(), with no try/catch\n\tvoid ExecuteEidosEvent(SLiMEidosBlock *p_script_block);\n\tvoid AllSpecies_RunInitializeCallbacks(void);\t\t\t\t\t\t\t\t\t// run initialize() callbacks and check for complete initialization\n\tvoid RunInitializeCallbacks(void);\t\t\t\t\t\t\t\t\t\t\t\t// run `species all` initialize() callbacks\n\tvoid AllSpecies_CheckIntegrity(void);\n\tvoid AllSpecies_PurgeRemovedObjects(void);\n\t\n\tbool _RunOneTickWF(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// called by _RunOneTick() to run a tick (WF models)\n\tbool _RunOneTickNonWF(void);\t\t\t\t\t\t\t\t\t\t\t\t\t// called by _RunOneTick() to run a tick (nonWF models)\n\t\n\tEidosValue_SP _EvaluateTickRangeNode(const EidosASTNode *p_node, std::string &p_error_string);\t// evaluate a node that represents a tick range expression\n\tSLiMCycleStage CycleStageForScriptBlockType(SLiMEidosBlockType p_block_type);\t// look up the cycle stage a block executes in\n\tbool IsPastOrPresent(slim_tick_t p_block_tick, SLiMEidosBlockType p_block_type); // is the given tick/cycle stage past/present (true) or future (false)?\n\tvoid EvaluateScriptBlockTickRanges(void);\t\t\t\t\t\t\t\t\t\t// evaluate tick range expressions to find when a block is scheduled\n\tvoid FlagUnevaluatedScriptBlockTickRanges(void);\t\t\t\t\t\t\t\t// error for script blocks whose tick range is unevaluated\n\tslim_tick_t FirstTick(void);\t\t\t\t\t\t\t\t\t\t\t\t\t// derived from the first tick in which an Eidos block is registered\n\tslim_tick_t EstimatedLastTick(void);\t\t\t\t\t\t\t\t\t\t\t// derived from the last tick in which an Eidos block is registered\n\tvoid SimulationHasFinished(void);\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tvoid StartProfiling(void);\n\tvoid StopProfiling(void);\n\t\n\tvoid CollectSLiMguiMemoryUsageProfileInfo(void);\n#endif\n\t\n\t// accessors\n\tinline __attribute__((always_inline)) const std::vector<Species *> &AllSpecies(void)\t\t\t\t\t\t\t\t\t{ return all_species_; }\n\tinline __attribute__((always_inline)) EidosSymbolTable &SymbolTable(void) const\t\t\t\t\t\t\t\t\t\t\t{ return *simulation_constants_; }\n\tinline __attribute__((always_inline)) EidosFunctionMap &FunctionMap(void)\t\t\t\t\t\t\t\t\t\t\t\t{ return simulation_functions_; }\n\t\n\tinline __attribute__((always_inline)) SLiMModelType ModelType(void) const\t\t\t\t\t\t\t\t\t\t\t\t{ return model_type_; }\n\tvoid SetModelType(SLiMModelType p_new_type);\n\t\n\tinline __attribute__((always_inline)) slim_tick_t Tick(void) const\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ return tick_; }\n\tvoid SetTick(slim_tick_t p_new_tick);\n\t\n\tinline __attribute__((always_inline)) SLiMCycleStage CycleStage(void) const\t\t\t\t\t\t\t\t\t\t\t\t{ return cycle_stage_; }\n\t\n\tinline __attribute__((always_inline)) SLiMEidosScript *Script(void) { return script_; }\n\tinline __attribute__((always_inline)) std::string ScriptString(void) { return script_->String(); }\n\t\n\t\n\t// ***********************************  Support for debugging points in SLiMgui\n#ifdef SLIMGUI\n\t// Set the debug points to be used; note that a copy is *not* made, the caller guarantees the lifetime of the passed object\n\tinline void SetDebugPoints(EidosInterpreterDebugPointsSet *p_debug_points) { debug_points_ = p_debug_points; }\n\tvirtual EidosInterpreterDebugPointsSet *DebugPoints(void) override { return debug_points_; }\n\tvirtual std::string DebugPointInfo(void) override { return std::string(\", tick \") + std::to_string(tick_); };\n#endif\n\t\n\t// ***********************************  Support for file observing notifications in SLiMgui\n#ifdef SLIMGUI\n\tvirtual void FileWriteNotification(const std::string &p_file_path, std::vector<std::string> &&p_lines, bool p_append) override;\n\t\n\tstd::vector<std::string> file_write_paths_;\t\t\t\t\t\t// full file paths for the file writes we have seen, in order of occurrence\n    std::vector<std::vector<std::string>> file_write_buffers_;\t\t// remembered file write lines, keyed by the full file path; read by SLiMgui\n    std::vector<uint8_t> file_write_appends_;\t\t\t\t\t\t// a parallel map just keeping a bool flag: true == append, false == overwrite\n#endif\n\n\t// TREE SEQUENCE RECORDING\n#pragma mark -\n#pragma mark treeseq recording ivars\n#pragma mark -\n\t\n\t// Most tree-seq stuff belongs to Species, but the tick clock is synchronized across the community, and command-line flags are managed here\n\t\n\tvoid AllSpecies_TSXC_Enable(void);          // forces tree-seq with crosschecks on for all species; called by the undocumented -TSXC option\n\tvoid AllSpecies_TSF_Enable(void);           // forces tree-seq without crosschecks on for all species; called by the undocumented -TSF option\n\t\n\tslim_tick_t tree_seq_tick_ = 0;\t\t\t\t// the tick for the tree sequence code, incremented after generating offspring\n\t\t\t\t\t\t\t\t\t\t\t\t// this is needed since addSubpop() in an early() event makes one gen, and then the offspring\n\t\t\t\t\t\t\t\t\t\t\t\t// arrive in the same tick according to SLiM, which confuses the tree-seq code\n\t\t\t\t\t\t\t\t\t\t\t\t// BCH 5/13/2021: We now increment this after first() events in nonWF models, too\n\tdouble tree_seq_tick_offset_ = 0;\t\t\t// this is a fractional offset added to tree_seq_tick_; this is needed to make successive calls\n\t\t\t\t\t\t\t\t\t\t\t\t// to addSubpopSplit() arrive at successively later times; see Population::AddSubpopulationSplit()\n\tstd::string treeseq_time_unit_;\t\t\t\t// set in initializeTreeSeq(), written out to .trees; has no effect on the simulation, just user data\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; };\n\t\n\tvirtual EidosValue_SP ContextDefinedFunctionDispatch(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\tEidosSymbolTable *SymbolsFromBaseSymbols(EidosSymbolTable *p_base_symbols);\t\t\t\t// derive a symbol table, adding our own symbols if needed\n\t\n\tstatic const std::vector<EidosFunctionSignature_CSP> *ZeroTickFunctionSignatures(void);\t\t// all zero-tick functions\n\tstatic void AddZeroTickFunctionsToMap(EidosFunctionMap &p_map);\n\tstatic void RemoveZeroTickFunctionsFromMap(EidosFunctionMap &p_map);\n\t\n\tstatic const std::vector<EidosFunctionSignature_CSP> *SLiMFunctionSignatures(void);\t\t// all non-zero-tick functions\n\tstatic void AddSLiMFunctionsToMap(EidosFunctionMap &p_map);\n\t\n\tEidosValue_SP ExecuteContextFunction_initializeSLiMModelType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeInteractionType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\tEidosValue_SP ExecuteMethod_createLogFile(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_estimatedLastTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_deregisterScriptBlock(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_genomicElementTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_interactionTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mutationTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_scriptBlocksWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_speciesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subpopulationsWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subpopulationsWithNames(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_outputUsage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerFirstEarlyLateEvent(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerInteractionCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_rescheduleScriptBlock(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_simulationFinished(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_usage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass Community_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tCommunity_Class(const Community_Class &p_original) = delete;\t// no copy-construct\n\tCommunity_Class& operator=(const Community_Class&) = delete;\t// no copying\n\tinline Community_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__community__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/community_eidos.cpp",
    "content": "//\n//  community_eidos.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 2/28/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"community.h\"\n\n#include \"haplosome.h\"\n#include \"individual.h\"\n#include \"subpopulation.h\"\n#include \"polymorphism.h\"\n#include \"interaction_type.h\"\n#include \"log_file.h\"\n\n#include <iostream>\n#include <iomanip>\n#include <fstream>\n#include <string>\n#include <utility>\n#include <algorithm>\n#include <vector>\n#include <cmath>\n#include <ctime>\n#include <unordered_map>\n#include <unordered_set>\n#include <limits>\n\n\nstatic std::string PrintBytes(size_t p_bytes)\n{\n\tstd::ostringstream sstream;\n\t\n\tsstream << p_bytes << \" bytes\";\n\t\n\tif (p_bytes > 1024.0 * 1024.0 * 1024.0 * 1024.0)\n\t\tsstream << \" (\" << (p_bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)) << \" TB\" << \")\";\n\telse if (p_bytes > 1024.0 * 1024.0 * 1024.0)\n\t\tsstream << \" (\" << (p_bytes / (1024.0 * 1024.0 * 1024.0)) << \" GB\" << \")\";\n\telse if (p_bytes > 1024.0 * 1024.0)\n\t\tsstream << \" (\" << (p_bytes / (1024.0 * 1024.0)) << \" MB\" << \")\";\n\telse if (p_bytes > 1024)\n\t\tsstream << \" (\" << (p_bytes / 1024.0) << \" K\" << \")\";\n\t\n\treturn sstream.str();\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nEidosValue_SP Community::ContextDefinedFunctionDispatch(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused(p_interpreter)\n\t\n\t// we only define initialize...() functions; so we must be in an initialize() callback\n\tif (tick_ != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ContextDefinedFunctionDispatch): the function \" << p_function_name << \"() may only be called in an initialize() callback.\" << EidosTerminate();\n\t\n\t// Non-species-specific initialization\n\tif (p_function_name.compare(gStr_initializeSLiMModelType) == 0)\t\t\t\treturn this->ExecuteContextFunction_initializeSLiMModelType(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeInteractionType) == 0)\t\treturn this->ExecuteContextFunction_initializeInteractionType(p_function_name, p_arguments, p_interpreter);\n\t\n\t// Species-specific initialization\n\tif (!active_species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ContextDefinedFunctionDispatch): no active species in context-defined function dispatch; \" << p_function_name << \"() must be called from a species-specific initialize() callback.\" << EidosTerminate();\n\t\n\tif (p_function_name.compare(gStr_initializeAncestralNucleotides) == 0)\t\treturn active_species_->ExecuteContextFunction_initializeAncestralNucleotides(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeGenomicElement) == 0)\t\treturn active_species_->ExecuteContextFunction_initializeGenomicElement(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeGenomicElementType) == 0)\treturn active_species_->ExecuteContextFunction_initializeGenomicElementType(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeMutationType) == 0)\t\t\treturn active_species_->ExecuteContextFunction_initializeMutationType(p_function_name, p_arguments, p_interpreter);\t\t\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\telse if (p_function_name.compare(gStr_initializeMutationTypeNuc) == 0)\t\treturn active_species_->ExecuteContextFunction_initializeMutationType(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeRecombinationRate) == 0)\treturn active_species_->ExecuteContextFunction_initializeRecombinationRate(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeChromosome) == 0)\t\t\treturn active_species_->ExecuteContextFunction_initializeChromosome(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeGeneConversion) == 0)\t\treturn active_species_->ExecuteContextFunction_initializeGeneConversion(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeMutationRate) == 0)\t\t\treturn active_species_->ExecuteContextFunction_initializeMutationRate(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeHotspotMap) == 0)\t\t\treturn active_species_->ExecuteContextFunction_initializeHotspotMap(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeSex) == 0)\t\t\t\t\treturn active_species_->ExecuteContextFunction_initializeSex(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeSLiMOptions) == 0)\t\t\treturn active_species_->ExecuteContextFunction_initializeSLiMOptions(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeSpecies) == 0)\t\t\t\treturn active_species_->ExecuteContextFunction_initializeSpecies(p_function_name, p_arguments, p_interpreter);\n\telse if (p_function_name.compare(gStr_initializeTreeSeq) == 0)\t\t\t\treturn active_species_->ExecuteContextFunction_initializeTreeSeq(p_function_name, p_arguments, p_interpreter);\n\t\n\tEIDOS_TERMINATION << \"ERROR (Community::ContextDefinedFunctionDispatch): the function \" << p_function_name << \"() is not implemented by Community.\" << EidosTerminate();\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *Community::ZeroTickFunctionSignatures(void)\n{\n\t// Allocate our own EidosFunctionSignature objects\n\tstatic std::vector<EidosFunctionSignature_CSP> sim_0_signatures_;\n\t\n\tif (!sim_0_signatures_.size())\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Community::ZeroTickFunctionSignatures(): not warmed up\");\n\t\t\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeAncestralNucleotides, nullptr, kEidosValueMaskInt | kEidosValueMaskSingleton, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddIntString(\"sequence\"));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeGenomicElement, nullptr, kEidosValueMaskObject, gSLiM_GenomicElement_Class, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddIntObject(\"genomicElementType\", gSLiM_GenomicElementType_Class)->AddInt_ON(\"start\", gStaticEidosValueNULL)->AddInt_ON(\"end\", gStaticEidosValueNULL));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeGenomicElementType, nullptr, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_GenomicElementType_Class, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddIntString_S(\"id\")->AddIntObject(\"mutationTypes\", gSLiM_MutationType_Class)->AddNumeric(\"proportions\")->AddFloat_ON(\"mutationMatrix\", gStaticEidosValueNULL));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeInteractionType, nullptr, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_InteractionType_Class, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddIntString_S(\"id\")->AddString_S(gStr_spatiality)->AddLogical_OS(gStr_reciprocal, gStaticEidosValue_LogicalF)->AddNumeric_OS(gStr_maxDistance, gStaticEidosValue_FloatINF)->AddString_OS(gStr_sexSegregation, gStaticEidosValue_StringDoubleAsterisk));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeMutationType, nullptr, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_MutationType_Class, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddIntString_S(\"id\")->AddNumeric_S(\"dominanceCoeff\")->AddString_S(\"distributionType\")->AddEllipsis());\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeMutationTypeNuc, nullptr, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_MutationType_Class, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddIntString_S(\"id\")->AddNumeric_S(\"dominanceCoeff\")->AddString_S(\"distributionType\")->AddEllipsis());\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeRecombinationRate, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddNumeric(\"rates\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeChromosome, nullptr, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Chromosome_Class, \"SLiM\"))->AddInt_S(\"id\")->AddInt_OSN(\"length\", gStaticEidosValueNULL)->AddString_OS(\"type\", gStaticEidosValue_StringA)->AddString_OSN(\"symbol\", gStaticEidosValueNULL)->AddString_OSN(\"name\", gStaticEidosValueNULL)->AddInt_OS(\"mutationRuns\", gStaticEidosValue_Integer0));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeGeneConversion, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddNumeric_S(\"nonCrossoverFraction\")->AddNumeric_S(\"meanLength\")->AddNumeric_S(\"simpleConversionFraction\")->AddNumeric_OS(\"bias\", gStaticEidosValue_Integer0)->AddLogical_OS(\"redrawLengthsOnFailure\", gStaticEidosValue_LogicalF));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeMutationRate, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddNumeric(\"rates\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeHotspotMap, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddNumeric(\"multipliers\")->AddInt_ON(\"ends\", gStaticEidosValueNULL)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeSex, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t\t->AddString_OSN(\"chromosomeType\", gStaticEidosValueNULL));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeSLiMOptions, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddLogical_OS(\"keepPedigrees\", gStaticEidosValue_LogicalF)->AddString_OS(\"dimensionality\", gStaticEidosValue_StringEmpty)->AddString_OS(\"periodicity\", gStaticEidosValue_StringEmpty)->AddLogical_OS(\"doMutationRunExperiments\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"preventIncidentalSelfing\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"nucleotideBased\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"randomizeCallbacks\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"checkInfiniteLoops\", gStaticEidosValue_LogicalT));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeSpecies, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddInt_OS(\"tickModulo\", gStaticEidosValue_Integer1)->AddInt_OS(\"tickPhase\", gStaticEidosValue_Integer1)->AddString_OS(gStr_avatar, gStaticEidosValue_StringEmpty)->AddString_OS(\"color\", gStaticEidosValue_StringEmpty));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeTreeSeq, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddLogical_OS(\"recordMutations\", gStaticEidosValue_LogicalT)->AddNumeric_OSN(\"simplificationRatio\", gStaticEidosValueNULL)->AddInt_OSN(\"simplificationInterval\", gStaticEidosValueNULL)->AddLogical_OS(\"checkCoalescence\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"runCrosschecks\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"retainCoalescentOnly\", gStaticEidosValue_LogicalT)->AddString_OSN(\"timeUnit\", gStaticEidosValueNULL));\n\t\tsim_0_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_initializeSLiMModelType, nullptr, kEidosValueMaskVOID, \"SLiM\"))\n\t\t\t\t\t\t\t\t\t   ->AddString_S(\"modelType\"));\n\t}\n\t\n\treturn &sim_0_signatures_;\n}\n\nvoid Community::AddZeroTickFunctionsToMap(EidosFunctionMap &p_map)\n{\n\tconst std::vector<EidosFunctionSignature_CSP> *signatures = ZeroTickFunctionSignatures();\n\t\n\tif (signatures)\n\t{\n\t\tfor (const EidosFunctionSignature_CSP &signature : *signatures)\n\t\t\tp_map.emplace(signature->call_name_, signature);\n\t}\n}\n\nvoid Community::RemoveZeroTickFunctionsFromMap(EidosFunctionMap &p_map)\n{\n\tconst std::vector<EidosFunctionSignature_CSP> *signatures = ZeroTickFunctionSignatures();\n\t\n\tif (signatures)\n\t{\n\t\tfor (const EidosFunctionSignature_CSP &signature : *signatures)\n\t\t\tp_map.erase(signature->call_name_);\n\t}\n}\n\nvoid Community::AddSLiMFunctionsToMap(EidosFunctionMap &p_map)\n{\n\tconst std::vector<EidosFunctionSignature_CSP> *signatures = SLiMFunctionSignatures();\n\t\n\tif (signatures)\n\t{\n\t\tfor (const EidosFunctionSignature_CSP &signature : *signatures)\n\t\t\tp_map.emplace(signature->call_name_, signature);\n\t}\n}\n\nEidosSymbolTable *Community::SymbolsFromBaseSymbols(EidosSymbolTable *p_base_symbols)\n{\n\t// Since we keep our own symbol table long-term, this function does not actually re-derive a new table, but just returns the cached table\n\tif (p_base_symbols != gEidosConstantsSymbolTable)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::SymbolsFromBaseSymbols): (internal error) SLiM requires that its parent symbol table be the standard Eidos symbol table.\" << EidosTerminate();\n\t\n\treturn simulation_constants_;\n}\n\n//\t*********************\t(void)initializeSLiMModelType(string$ modelType)\n//\nEidosValue_SP Community::ExecuteContextFunction_initializeSLiMModelType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_interpreter)\n\tEidosValue *arg_modelType_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_modeltype_declarations_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeSLiMModelType): initializeSLiMModelType() may be called only once.\" << EidosTerminate();\n\t\n\tif (is_explicit_species_ && active_species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeSLiMModelType): in multispecies models, initializeSLiMModelType() may only be called from a non-species-specific (`species all`) initialize() callback.\" << EidosTerminate();\n\t\n\tif ((num_interaction_types_ > 0) ||\n\t\t(active_species_ &&\n\t\t active_species_->HasDoneAnyInitialization()))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeSLiMModelType): initializeSLiMModelType() must be called before all other initialization functions.\" << EidosTerminate();\n\t\n\t{\n\t\t// string$ modelType\n\t\tstd::string model_type = arg_modelType_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (model_type == \"WF\")\n\t\t\tSetModelType(SLiMModelType::kModelTypeWF);\n\t\telse if (model_type == \"nonWF\")\n\t\t\tSetModelType(SLiMModelType::kModelTypeNonWF);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeSLiMModelType): in initializeSLiMModelType(), legal values for parameter modelType are only 'WF' or 'nonWF'.\" << EidosTerminate();\n\t}\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeSLiMModelType(\";\n\t\t\n\t\t// modelType\n\t\toutput_stream << \"modelType = \";\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF) output_stream << \"'WF'\";\n\t\telse if (model_type_ == SLiMModelType::kModelTypeNonWF) output_stream << \"'nonWF'\";\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_modeltype_declarations_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(object<InteractionType>$)initializeInteractionType(is$ id, string$ spatiality, [logical$ reciprocal = F], [numeric$ maxDistance = INF], [string$ sexSegregation = \"**\"])\n//\nEidosValue_SP Community::ExecuteContextFunction_initializeInteractionType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *spatiality_value = p_arguments[1].get();\n\tEidosValue *reciprocal_value = p_arguments[2].get();\n\tEidosValue *maxDistance_value = p_arguments[3].get();\n\tEidosValue *sexSegregation_value = p_arguments[4].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (is_explicit_species_ && active_species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeInteractionType): in multispecies models, initializeInteractionType() may only be called from a non-species-specific (`species all`) initialize() callback.\" << EidosTerminate();\n\t\n\tslim_objectid_t map_identifier = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 'i');\n\tstd::string spatiality_string = spatiality_value->StringAtIndex_NOCAST(0, nullptr);\n\tbool reciprocal = reciprocal_value->LogicalAtIndex_NOCAST(0, nullptr);\t\t// UNUSED\n\tdouble max_distance = maxDistance_value->NumericAtIndex_NOCAST(0, nullptr);\n\tstd::string sex_string = sexSegregation_value->StringAtIndex_NOCAST(0, nullptr);\n\tIndividualSex receiver_sex = IndividualSex::kUnspecified, exerter_sex = IndividualSex::kUnspecified;\n\t\n\tif (InteractionTypeWithID(map_identifier))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeInteractionType): initializeInteractionType() interaction type m\" << map_identifier << \" already defined.\" << EidosTerminate();\n\t\n\tif (sex_string == \"**\")\t\t\t{ receiver_sex = IndividualSex::kUnspecified;\texerter_sex = IndividualSex::kUnspecified;\t}\n\telse if (sex_string == \"*M\")\t{ receiver_sex = IndividualSex::kUnspecified;\texerter_sex = IndividualSex::kMale;\t\t\t}\n\telse if (sex_string == \"*F\")\t{ receiver_sex = IndividualSex::kUnspecified;\texerter_sex = IndividualSex::kFemale;\t\t}\n\telse if (sex_string == \"M*\")\t{ receiver_sex = IndividualSex::kMale;\t\t\texerter_sex = IndividualSex::kUnspecified;\t}\n\telse if (sex_string == \"MM\")\t{ receiver_sex = IndividualSex::kMale;\t\t\texerter_sex = IndividualSex::kMale;\t\t\t}\n\telse if (sex_string == \"MF\")\t{ receiver_sex = IndividualSex::kMale;\t\t\texerter_sex = IndividualSex::kFemale;\t\t}\n\telse if (sex_string == \"F*\")\t{ receiver_sex = IndividualSex::kFemale;\t\texerter_sex = IndividualSex::kUnspecified;\t}\n\telse if (sex_string == \"FM\")\t{ receiver_sex = IndividualSex::kFemale;\t\texerter_sex = IndividualSex::kMale;\t\t\t}\n\telse if (sex_string == \"FF\")\t{ receiver_sex = IndividualSex::kFemale;\t\texerter_sex = IndividualSex::kFemale;\t\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeInteractionType): initializeInteractionType() unsupported sexSegregation value (must be '**', '*M', '*F', 'M*', 'MM', 'MF', 'F*', 'FM', or 'FF').\" << EidosTerminate();\n\t\n\tInteractionType *new_interaction_type = new InteractionType(*this, map_identifier, spatiality_string, reciprocal, max_distance, receiver_sex, exerter_sex);\n\t\n\tinteraction_types_.emplace(map_identifier, new_interaction_type);\n\tinteraction_types_changed_ = true;\n\t\n\t// define a new Eidos variable to refer to the new mutation type\n\tEidosSymbolTableEntry &symbol_entry = new_interaction_type->SymbolTableEntry();\n\t\n\tif (p_interpreter.SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteContextFunction_initializeInteractionType): initializeInteractionType() symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\n\tSymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeInteractionType(\" << map_identifier << \", \\\"\" << spatiality_string << \"\\\"\";\n\t\t\n\t\tif (reciprocal == true)\n\t\t\toutput_stream << \", reciprocal=T\";\n\t\t\n\t\tif (!std::isinf(max_distance))\n\t\t\toutput_stream << \", maxDistance=\" << max_distance;\n\t\t\n\t\tif (sex_string != \"**\")\n\t\t\toutput_stream << \", sexSegregation=\\\"\" << sex_string << \"\\\"\";\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_interaction_types_++;\n\treturn symbol_entry.second;\n}\n\nconst EidosClass *Community::Class(void) const\n{\n\treturn gSLiM_Community_Class;\n}\n\nvoid Community::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP Community::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_allGenomicElementTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElementType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto getype : all_genomic_element_types_)\n\t\t\t\tvec->push_object_element_NORR(getype.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_allInteractionTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_InteractionType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto inttype : interaction_types_)\n\t\t\t\tvec->push_object_element_NORR(inttype.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_allMutationTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto muttype : all_mutation_types_)\n\t\t\t\tvec->push_object_element_NORR(muttype.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_allScriptBlocks:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_SLiMEidosBlock_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = AllScriptBlocks();\n\t\t\t\n\t\t\tfor (auto script_block : script_blocks)\n\t\t\t\tif (script_block->type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\t\t// exclude function blocks; not user-visible\n\t\t\t\t\tvec->push_object_element_NORR(script_block);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_allSpecies:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Species_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto species : all_species_)\n\t\t\t\tvec->push_object_element_NORR(species);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_allSubpopulations:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Subpopulation_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto species : all_species_)\n\t\t\t\tfor (auto pop : species->population_.subpops_)\n\t\t\t\t\tvec->push_object_element_NORR(pop.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_logFiles:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_LogFile_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n            for (LogFile *logfile : log_file_registry_)\n\t\t\t\tvec->push_object_element_RR(logfile);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_modelType:\n\t\t{\n\t\t\tstatic EidosValue_SP static_model_type_string_WF;\n\t\t\tstatic EidosValue_SP static_model_type_string_nonWF;\n\t\t\t\n#pragma omp critical (GetProperty_modelType_cache)\n\t\t\t{\n\t\t\t\tif (!static_model_type_string_WF)\n\t\t\t\t{\n\t\t\t\t\tstatic_model_type_string_WF = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"WF\"));\n\t\t\t\t\tstatic_model_type_string_nonWF = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"nonWF\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tswitch (model_type_)\n\t\t\t{\n\t\t\t\tcase SLiMModelType::kModelTypeWF:\t\treturn static_model_type_string_WF;\n\t\t\t\tcase SLiMModelType::kModelTypeNonWF:\treturn static_model_type_string_nonWF;\n\t\t\t\tdefault:\t\t\t\t\t\t\t\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_tick:\n\t\t{\n\t\t\tif (cached_value_tick_ && (cached_value_tick_->IntData()[0] != tick_))\n\t\t\t\tcached_value_tick_.reset();\n\t\t\tif (!cached_value_tick_)\n\t\t\t\tcached_value_tick_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tick_));\n\t\t\treturn cached_value_tick_;\n\t\t}\n\t\tcase gID_cycleStage:\n\t\t{\n\t\t\tSLiMCycleStage cycle_stage = CycleStage();\n\t\t\tstd::string cycle_stage_str = StringForSLiMCycleStage(cycle_stage);\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(cycle_stage_str));\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::GetProperty): property tag accessed on simulation object before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\tcase gID_verbosity:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(SLiM_verbosity_level));\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid Community::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_tick:\n\t\t{\n\t\t\tint64_t value = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\tslim_tick_t old_tick = tick_;\n\t\t\tslim_tick_t new_tick = SLiMCastToTickTypeOrRaise(value);\n\t\t\t\n\t\t\tSetTick(new_tick);\n\t\t\t\n\t\t\t// Setting the tick into the future is generally harmless; the simulation logic is designed to handle that anyway, since\n\t\t\t// that happens every tick.  Setting the tick into the past is a bit tricker, since some things that have already\n\t\t\t// occurred need to be invalidated.  In particular, historical data cached by SLiMgui needs to be fixed.  Note that here we\n\t\t\t// do NOT remove Substitutions that are in the future, or otherwise try to backtrack the actual simulation state.  If the user\n\t\t\t// actually restores a past state with readFromPopulationFile(), all that kind of stuff will be reset; but if all they do is\n\t\t\t// set the tick counter back, the model state is unchanged, substitutions are still fixed, etc.  This means that the\n\t\t\t// simulation code needs to be robust to the possibility that some records, e.g. for Substitutions, may appear to be about\n\t\t\t// events in the future.  But usually users will only set the tick back if they also call readFromPopulationFile().\n\t\t\tif (tick_ < old_tick)\n\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t// Fix fitness histories for SLiMgui.  Note that mutation_loss_times_ and mutation_fixation_times_ are not fixable, since\n\t\t\t\t// their entries are not separated out by tick, so we just leave them as is, containing information about\n\t\t\t\t// alternative futures of the model.\n\t\t\t\tfor (Species *species : all_species_)\n\t\t\t\t{\n\t\t\t\t\tfor (auto history_record_iter : species->population_.fitness_histories_)\n\t\t\t\t\t{\n\t\t\t\t\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\t\t\t\tdouble *history = history_record.history_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (history)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint old_last_valid_history_index = std::max(0, old_tick - 2);\t\t// if tick==2, tick 1 was the last valid entry, and it is at index 0\n\t\t\t\t\t\t\tint new_last_valid_history_index = std::max(0, tick_ - 2);\t\t// ditto\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// make sure that we don't overrun the end of the buffer\n\t\t\t\t\t\t\tif (old_last_valid_history_index > history_record.history_length_ - 1)\n\t\t\t\t\t\t\t\told_last_valid_history_index = history_record.history_length_ - 1;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int entry_index = new_last_valid_history_index + 1; entry_index <= old_last_valid_history_index; ++entry_index)\n\t\t\t\t\t\t\t\thistory[entry_index] = NAN;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (auto history_record_iter : species->population_.subpop_size_histories_)\n\t\t\t\t\t{\n\t\t\t\t\t\tSubpopSizeHistory &history_record = history_record_iter.second;\n\t\t\t\t\t\tslim_popsize_t *history = history_record.history_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (history)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint old_last_valid_history_index = std::max(0, old_tick - 2);\t\t// if tick==2, tick 1 was the last valid entry, and it is at index 0\n\t\t\t\t\t\t\tint new_last_valid_history_index = std::max(0, tick_ - 2);\t\t// ditto\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// make sure that we don't overrun the end of the buffer\n\t\t\t\t\t\t\tif (old_last_valid_history_index > history_record.history_length_ - 1)\n\t\t\t\t\t\t\t\told_last_valid_history_index = history_record.history_length_ - 1;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int entry_index = new_last_valid_history_index + 1; entry_index <= old_last_valid_history_index; ++entry_index)\n\t\t\t\t\t\t\t\thistory[entry_index] = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_verbosity:\n\t\t{\n\t\t\tint64_t value = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tSLiM_verbosity_level = value;\t// at the command line we bounds-check this, but here I see no need\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t}\n}\n\nEidosValue_SP Community::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_createLogFile:\t\t\t\t\treturn ExecuteMethod_createLogFile(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_estimatedLastTick:\t\t\t\treturn ExecuteMethod_estimatedLastTick(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_deregisterScriptBlock:\t\t\treturn ExecuteMethod_deregisterScriptBlock(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_genomicElementTypesWithIDs:\treturn ExecuteMethod_genomicElementTypesWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_interactionTypesWithIDs:\t\treturn ExecuteMethod_interactionTypesWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mutationTypesWithIDs:\t\t\treturn ExecuteMethod_mutationTypesWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_scriptBlocksWithIDs:\t\t\treturn ExecuteMethod_scriptBlocksWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_speciesWithIDs:\t\t\t\treturn ExecuteMethod_speciesWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_subpopulationsWithIDs:\t\t\treturn ExecuteMethod_subpopulationsWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_subpopulationsWithNames:\t\treturn ExecuteMethod_subpopulationsWithNames(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_outputUsage:\t\t\t\t\treturn ExecuteMethod_outputUsage(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerFirstEvent:\n\t\tcase gID_registerEarlyEvent:\n\t\tcase gID_registerLateEvent:\t\t\t\treturn ExecuteMethod_registerFirstEarlyLateEvent(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerInteractionCallback:\treturn ExecuteMethod_registerInteractionCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_rescheduleScriptBlock:\t\t\treturn ExecuteMethod_rescheduleScriptBlock(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_simulationFinished:\t\t\treturn ExecuteMethod_simulationFinished(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_usage:\t\t\t\t\treturn ExecuteMethod_usage(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (object<LogFile>$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = \",\"], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL], [logical$ header = T])\nEidosValue_SP Community::ExecuteMethod_createLogFile(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *filePath_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue *initialContents_value = p_arguments[1].get();\n\tEidosValue *append_value = p_arguments[2].get();\n\tEidosValue *compress_value = p_arguments[3].get();\n\tEidosValue_String *sep_value = (EidosValue_String *)p_arguments[4].get();\n\tEidosValue *logInterval_value = p_arguments[5].get();\n\tEidosValue *flushInterval_value = p_arguments[6].get();\n\tEidosValue *header_value = p_arguments[7].get();\n\t\n\t// process parameters\n\tconst std::string &filePath = filePath_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tstd::vector<const std::string *> initialContents;\n\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool do_compress = compress_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tconst std::string &sep = sep_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tbool autologging = false, explicitFlushing = false;\n\tint64_t logInterval = 0, flushInterval = 0;\n\tbool emit_header = header_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (initialContents_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tEidosValue_String *ic_string_value = (EidosValue_String *)initialContents_value;\n\t\tint ic_count = initialContents_value->Count();\n\t\t\n\t\tfor (int ic_index = 0; ic_index < ic_count; ++ic_index)\n\t\t\tinitialContents.emplace_back(&ic_string_value->StringRefAtIndex_NOCAST(ic_index, nullptr));\n\t}\n\t\n\tif (logInterval_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL turns off autologging\n\t\tautologging = false;\n\t\tlogInterval = 0;\n\t}\n\telse\n\t{\n\t\tautologging = true;\n\t\tlogInterval = logInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\tif (flushInterval_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL requests our automatic flushing behavior\n\t\texplicitFlushing = false;\n\t\tflushInterval = 0;\n\t}\n\telse\n\t{\n\t\texplicitFlushing = true;\n\t\tflushInterval = flushInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\t// Create the LogFile object\n\tLogFile *logfile = new LogFile(*this);\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(logfile, gSLiM_LogFile_Class));\n\t\n\t// Add it to our registry; it has a retain count from new that we will take over at this point\n\tlog_file_registry_.emplace_back(logfile);\n\t\n\t// Configure it\n\tlogfile->SetLogInterval(autologging, logInterval);\n\tlogfile->SetFlushInterval(explicitFlushing, flushInterval);\n\tlogfile->ConfigureFile(filePath, initialContents, append, emit_header, do_compress, sep);\n\t\n\t// Check for duplicate LogFiles using the same path; this is a common error so I'm making it illegal\n\tconst std::string &resolved_path = logfile->ResolvedFilePath();\n\t\n\tfor (LogFile *existing_log_file : log_file_registry_)\n\t{\n\t\tif (existing_log_file != logfile)\n\t\t{\n\t\t\tconst std::string &existing_path = existing_log_file->ResolvedFilePath();\n\t\t\t\n\t\t\tif (resolved_path == existing_path)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_createLogFile): createLogFile() cannot create a new log file at \" << resolved_path << \" because an existing log file is already using that path.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (integer$)estimatedLastTick(void)\n//\nEidosValue_SP Community::ExecuteMethod_estimatedLastTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tslim_tick_t last_tick = EstimatedLastTick();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(last_tick));\n}\n\n//\t*********************\t- (void)deregisterScriptBlock(io<SLiMEidosBlock> scriptBlocks)\n//\nEidosValue_SP Community::ExecuteMethod_deregisterScriptBlock(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *scriptBlocks_value = p_arguments[0].get();\n\t\n\tint block_count = scriptBlocks_value->Count();\n\t\n\t// We just schedule the blocks for deregistration; we do not deregister them immediately, because that would leave stale pointers lying around\n\tfor (int block_index = 0; block_index < block_count; ++block_index)\n\t{\n\t\tSLiMEidosBlock *block = SLiM_ExtractSLiMEidosBlockFromEidosValue_io(scriptBlocks_value, block_index, this, nullptr, \"deregisterScriptBlock()\");\t// agnostic to species\n\t\t\n\t\tif (block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t{\n\t\t\t// this should never be hit, because the user should have no way to get a reference to a function block\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_deregisterScriptBlock): (internal error) deregisterScriptBlock() cannot be called on user-defined function script blocks.\" << EidosTerminate();\n\t\t}\n\t\telse if (block->type_ == SLiMEidosBlockType::SLiMEidosInteractionCallback)\n\t\t{\n\t\t\t// interaction() callbacks have to work differently, because they can be called at any time after an\n\t\t\t// interaction has been evaluated, up until the interaction is invalidated; we can't make pointers\n\t\t\t// to interaction() callbacks go stale except at that specific point in the cycle\n\t\t\tif (std::find(scheduled_interaction_deregs_.begin(), scheduled_interaction_deregs_.end(), block) != scheduled_interaction_deregs_.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_deregisterScriptBlock): deregisterScriptBlock() called twice on the same script block.\" << EidosTerminate();\n\t\t\t\n\t\t\tscheduled_interaction_deregs_.emplace_back(block);\n\t\t\t\n#if DEBUG_BLOCK_REG_DEREG\n\t\t\tstd::cout << \"deregisterScriptBlock() called for block:\" << std::endl;\n\t\t\tstd::cout << \"   \";\n\t\t\tblock->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n#endif\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// all other script blocks go on the main list and get cleared out at the end of each cycle stage\n\t\t\tif (std::find(scheduled_deregistrations_.begin(), scheduled_deregistrations_.end(), block) != scheduled_deregistrations_.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_deregisterScriptBlock): deregisterScriptBlock() called twice on the same script block.\" << EidosTerminate();\n\t\t\t\n\t\t\tscheduled_deregistrations_.emplace_back(block);\n\t\t\t\n#if DEBUG_BLOCK_REG_DEREG\n\t\t\tstd::cout << \"deregisterScriptBlock() called for block:\" << std::endl;\n\t\t\tstd::cout << \"   \";\n\t\t\tblock->Print(std::cout);\n\t\t\tstd::cout << std::endl;\n#endif\n\t\t}\n\t\t\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"\\t\\tderegisterScriptBlock() called for block: \";\n\t\tblock->PrintDeclaration(gSLiMScheduling, this);\n\t\tgSLiMScheduling << std::endl;\n#endif\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (object<GenomicElementType>)genomicElementTypesWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_genomicElementTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElementType_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tGenomicElementType *object = GenomicElementTypeWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_genomicElementTypesWithIDs): genomicElementTypesWithIDs() did not find a genomic element type with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<InteractionType>)interactionTypesWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_interactionTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_InteractionType_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tInteractionType *object = InteractionTypeWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_interactionTypesWithIDs): interactionTypesWithIDs() did not find an interaction type with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<MutationType>)mutationTypesWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_mutationTypesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tMutationType *object = MutationTypeWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_mutationTypesWithIDs): mutationTypesWithIDs() did not find a mutation type with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>)scriptBlocksWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_scriptBlocksWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_SLiMEidosBlock_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tSLiMEidosBlock *object = ScriptBlockWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_scriptBlocksWithIDs): scriptBlocksWithIDs() did not find a script block with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<Species>)speciesWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_speciesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Species_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tSpecies *object = SpeciesWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_speciesWithIDs): speciesWithIDs() did not find a species with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<Subpopulation>)subpopulationsWithIDs(integer ids)\n//\nEidosValue_SP Community::ExecuteMethod_subpopulationsWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Subpopulation_Class))->resize_no_initialize_RR(ids_count);\n\t\n\tfor (int id_index = 0; id_index < ids_count; id_index++)\n\t{\n\t\tslim_objectid_t id = SLiMCastToObjectidTypeOrRaise(ids_data[id_index]);\n\t\tSubpopulation *object = SubpopulationWithID(id);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_subpopulationsWithIDs): subpopulationsWithIDs() did not find a subpopulation with id \" << id << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, id_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<Subpopulation>)subpopulationsWithNames(string names)\n//\nEidosValue_SP Community::ExecuteMethod_subpopulationsWithNames(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *names_value = p_arguments[0].get();\n\tint names_count = names_value->Count();\n\tconst std::string *names_data = names_value->StringData();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Subpopulation_Class))->resize_no_initialize_RR(names_count);\n\t\n\tfor (int name_index = 0; name_index < names_count; name_index++)\n\t{\n\t\tconst std::string &name = names_data[name_index];\n\t\tSubpopulation *object = SubpopulationWithName(name);\n\t\t\n\t\tif (!object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_subpopulationsWithNames): subpopulationsWithNames() did not find a subpopulation with name \" << name << \".\" << EidosTerminate();\n\t\t\n\t\tvec->set_object_element_no_check_NORR(object, name_index);\n\t}\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (void)outputUsage(void)\n//\nEidosValue_SP Community::ExecuteMethod_outputUsage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BEWARE: See also the -usage() method, which must be maintained in parallel with this\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\t// Save flags/precision and set to precision 1\n\tstd::ostream &out = p_interpreter.ExecutionOutputStream();\n\tstd::ios_base::fmtflags oldflags = out.flags();\n\tstd::streamsize oldprecision = out.precision();\n\tout << std::fixed << std::setprecision(1);\n\t\n\t// Tally up usage across the simulation\n\tSLiMMemoryUsage_Community usage_community;\n\tSLiMMemoryUsage_Species usage_all_species;\n\t\n\tEIDOS_BZERO(&usage_all_species, sizeof(SLiMMemoryUsage_Species));\n\t\n\tTabulateSLiMMemoryUsage_Community(&usage_community, &p_interpreter.SymbolTable());\n\t\n\tfor (Species *species : all_species_)\n\t{\n\t\tSLiMMemoryUsage_Species usage_one_species;\n\t\t\n\t\tspecies->TabulateSLiMMemoryUsage_Species(&usage_one_species);\n\t\tAccumulateMemoryUsageIntoTotal_Species(usage_one_species, usage_all_species);\n\t}\n\t\n\t// Print header\n\tout << \"Memory usage summary:\" << std::endl;\n\t\n\t// Chromosome\n\tout << \"   Chromosome objects(\" << usage_all_species.chromosomeObjects_count << \"): \" << PrintBytes(usage_all_species.chromosomeObjects) << std::endl;\n\tout << \"      Mutation rate maps: \" << PrintBytes(usage_all_species.chromosomeMutationRateMaps) << std::endl;\n\tout << \"      Recombination rate maps: \" << PrintBytes(usage_all_species.chromosomeRecombinationRateMaps) << std::endl;\n\tout << \"      Ancestral nucleotides: \" << PrintBytes(usage_all_species.chromosomeAncestralSequence) << std::endl;\n\t\n\t// Haplosome\n\tout << \"   Haplosome objects (\" << usage_all_species.haplosomeObjects_count << \"): \" << PrintBytes(usage_all_species.haplosomeObjects) << std::endl;\n\tout << \"      External MutationRun* buffers: \" << PrintBytes(usage_all_species.haplosomeExternalBuffers) << std::endl;\n\tout << \"      Unused pool space: \" << PrintBytes(usage_all_species.haplosomeUnusedPoolSpace) << std::endl;\n\tout << \"      Unused pool buffers: \" << PrintBytes(usage_all_species.haplosomeUnusedPoolBuffers) << std::endl;\n\t\n\t// GenomicElement\n\tout << \"   GenomicElement objects (\" << usage_all_species.genomicElementObjects_count << \"): \" << PrintBytes(usage_all_species.genomicElementObjects) << std::endl;\n\t\n\t// GenomicElementType\n\tout << \"   GenomicElementType objects (\" << usage_all_species.genomicElementTypeObjects_count << \"): \" << PrintBytes(usage_all_species.genomicElementTypeObjects) << std::endl;\n\t\n\t// Individual\n\tout << \"   Individual objects (\" << usage_all_species.individualObjects_count << \"): \" << PrintBytes(usage_all_species.individualObjects) << std::endl;\n\tout << \"      External Haplosome* buffers: \" << PrintBytes(usage_all_species.individualHaplosomeVectors) << std::endl;\n\tout << \"      Individuals awaiting reuse: \" << PrintBytes(usage_all_species.individualJunkyardAndHaplosomes) << std::endl;\n\tout << \"      Unused pool space: \" << PrintBytes(usage_all_species.individualUnusedPoolSpace) << std::endl;\n\t\n\t// InteractionType\n\tout << \"   InteractionType objects (\" << usage_community.interactionTypeObjects_count << \"): \" << PrintBytes(usage_community.interactionTypeObjects) << std::endl;\n\t\n\tif (usage_community.interactionTypeObjects_count)\n\t{\n\t\tout << \"      k-d trees: \" << PrintBytes(usage_community.interactionTypeKDTrees) << std::endl;\n\t\tout << \"      Position caches: \" << PrintBytes(usage_community.interactionTypePositionCaches) << std::endl;\n\t\tout << \"      Sparse vector pool: \" << PrintBytes(usage_community.interactionTypeSparseVectorPool) << std::endl;\n\t}\n\t\n\t// Mutation\n\tout << \"   Mutation objects (\" << usage_all_species.mutationObjects_count << \"): \" << PrintBytes(usage_all_species.mutationObjects) << std::endl;\n\tout << \"      Refcount buffer: \" << PrintBytes(usage_community.mutationRefcountBuffer) << std::endl;\n\tout << \"      Unused pool space: \" << PrintBytes(usage_community.mutationUnusedPoolSpace) << std::endl;\n\t\n\t// MutationRun\n\tout << \"   MutationRun objects (\" << usage_all_species.mutationRunObjects_count << \"): \" << PrintBytes(usage_all_species.mutationRunObjects) << std::endl;\n\tout << \"      External MutationIndex buffers: \" << PrintBytes(usage_all_species.mutationRunExternalBuffers) << std::endl;\n\tout << \"      Nonneutral mutation caches: \" << PrintBytes(usage_all_species.mutationRunNonneutralCaches) << std::endl;\n\tout << \"      Unused pool space: \" << PrintBytes(usage_all_species.mutationRunUnusedPoolSpace) << std::endl;\n\tout << \"      Unused pool buffers: \" << PrintBytes(usage_all_species.mutationRunUnusedPoolBuffers) << std::endl;\n\t\n\t// MutationType\n\tout << \"   MutationType objects (\" << usage_all_species.mutationTypeObjects_count << \"): \" << PrintBytes(usage_all_species.mutationTypeObjects) << std::endl;\n\t\n\t// Species (including the Population object)\n\tout << \"   Species objects: \" << PrintBytes(usage_all_species.speciesObjects) << std::endl;\n\tout << \"      Tree-sequence tables: \" << PrintBytes(usage_all_species.speciesTreeSeqTables) << std::endl;\n\t\n\t// Subpopulation\n\tout << \"   Subpopulation objects (\" << usage_all_species.subpopulationObjects_count << \"): \" << PrintBytes(usage_all_species.subpopulationObjects) << std::endl;\n\tout << \"      Fitness caches: \" << PrintBytes(usage_all_species.subpopulationFitnessCaches) << std::endl;\n\tout << \"      Parent tables: \" << PrintBytes(usage_all_species.subpopulationParentTables) << std::endl;\n\tout << \"      Spatial maps: \" << PrintBytes(usage_all_species.subpopulationSpatialMaps) << std::endl;\n\t\n\tif (usage_all_species.subpopulationSpatialMapsDisplay)\n\t\tout << \"      Spatial map display (SLiMgui): \" << PrintBytes(usage_all_species.subpopulationSpatialMapsDisplay) << std::endl;\n\t\n\t// Substitution\n\tout << \"   Substitution objects (\" << usage_all_species.substitutionObjects_count << \"): \" << PrintBytes(usage_all_species.substitutionObjects) << std::endl;\n\t\n\t// Eidos usage\n\tout << \"   Eidos: \" << std::endl;\n\tout << \"      EidosASTNode pool: \" << PrintBytes(usage_community.eidosASTNodePool) << std::endl;\n\tout << \"      EidosSymbolTable pool: \" << PrintBytes(usage_community.eidosSymbolTablePool) << std::endl;\n\tout << \"      EidosValue pool: \" << PrintBytes(usage_community.eidosValuePool) << std::endl;\n\tout << \"      File buffers: \" << PrintBytes(usage_community.fileBuffers) << std::endl;\n\t\n\tout << \"   # Total accounted for: \" << PrintBytes(usage_community.totalMemoryUsage + usage_all_species.totalMemoryUsage) << std::endl;\n\tout << std::endl;\n\t\n\t// Restore flags/precision\n\tout.flags(oldflags);\n\tout.precision(oldprecision);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\nvoid Community::CheckScheduling(slim_tick_t p_target_tick, SLiMCycleStage p_target_stage)\n{\n\t// See also Community::IsPastOrPresent() for essentially the same logic, but handling\n\t// the timing problem in a different way.\n\tif (p_target_tick < tick_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::CheckScheduling): event/callback scheduled for a past tick would not run.\" << EidosTerminate();\n\tif ((p_target_tick == tick_) && (p_target_stage < cycle_stage_))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::CheckScheduling): event/callback scheduled for the current tick, but for a past cycle stage, would not run.\" << EidosTerminate();\n\tif ((p_target_tick == tick_) && (p_target_stage == cycle_stage_))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::CheckScheduling): event/callback scheduled for the current tick, but for the currently executing cycle stage, would not run.\" << EidosTerminate();\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerFirstEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL], [No<Species>$ ticksSpec = NULL])\n//\t*********************\t– (object<SLiMEidosBlock>$)registerEarlyEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL], [No<Species>$ ticksSpec = NULL])\n//\t*********************\t– (object<SLiMEidosBlock>$)registerLateEvent(Nis$ id, string$ source, [Ni$ start = NULL], [Ni$ end = NULL], [No<Species>$ ticksSpec = NULL])\n//\nEidosValue_SP Community::ExecuteMethod_registerFirstEarlyLateEvent(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *start_value = p_arguments[2].get();\n\tEidosValue *end_value = p_arguments[3].get();\n\tEidosValue *ticksSpec_value = p_arguments[4].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if the id is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tSLiMEidosBlockType target_type;\n\t\n\tif (p_method_id == gID_registerFirstEvent)\n\t\ttarget_type = SLiMEidosBlockType::SLiMEidosEventFirst;\n\telse if (p_method_id == gID_registerEarlyEvent)\n\t\ttarget_type = SLiMEidosBlockType::SLiMEidosEventEarly;\n\telse if (p_method_id == gID_registerLateEvent)\n\t\ttarget_type = SLiMEidosBlockType::SLiMEidosEventLate;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_registerFirstEarlyLateEvent): (internal error) unrecognized p_method_id.\" << EidosTerminate();\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_registerFirstEarlyLateEvent): register\" << ((p_method_id == gID_registerFirstEvent) ? \"First\" : ((p_method_id == gID_registerEarlyEvent) ? \"Early\" : \"Late\")) << \"Event() requires start <= end.\" << EidosTerminate();\n\t\n\tSLiMCycleStage target_stage;\n\t\n\tif (target_type == SLiMEidosBlockType::SLiMEidosEventFirst)\n\t\ttarget_stage = (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage0ExecuteFirstScripts : SLiMCycleStage::kNonWFStage0ExecuteFirstScripts;\n\telse if (target_type == SLiMEidosBlockType::SLiMEidosEventEarly)\n\t\ttarget_stage = (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage1ExecuteEarlyScripts : SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts;\n\telse if (target_type == SLiMEidosBlockType::SLiMEidosEventLate)\n\t\ttarget_stage = (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage5ExecuteLateScripts : SLiMCycleStage::kNonWFStage6ExecuteLateScripts;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_registerFirstEarlyLateEvent): (internal error) unrecognized target_type.\" << EidosTerminate();\n\t\n\tSpecies *ticksSpec = ((ticksSpec_value->Type() != EidosValueType::kValueNULL) ? (Species *)ticksSpec_value->ObjectElementAtIndex_NOCAST(0, nullptr) : nullptr);\n\t\n\tif (ticksSpec && !is_explicit_species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_registerFirstEarlyLateEvent): ticksSpec must be NULL in models without explicit species declarations.\" << EidosTerminate();\n\t\n\tCheckScheduling(start_tick, target_stage);\n\t\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, target_type, start_tick, end_tick, nullptr, ticksSpec);\n\t\n\tAddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerInteractionCallback(Nis$ id, string$ source, io<InteractionType>$ intType, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Community::ExecuteMethod_registerInteractionCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *intType_value = p_arguments[2].get();\n\tEidosValue *subpop_value = p_arguments[3].get();\n\tEidosValue *start_value = p_arguments[4].get();\n\tEidosValue *end_value = p_arguments[5].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if the id is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t int_type_id = (intType_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(intType_value->IntAtIndex_NOCAST(0, nullptr)) : ((InteractionType *)intType_value->ObjectElementAtIndex_NOCAST(0, nullptr))->interaction_type_id_;\n\tslim_objectid_t subpop_id = -1;\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_registerInteractionCallback): registerInteractionCallback() requires start <= end.\" << EidosTerminate();\n\t\n\tCheckScheduling(start_tick, (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage7AdvanceTickCounter : SLiMCycleStage::kNonWFStage7AdvanceTickCounter);\n\t\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, SLiMEidosBlockType::SLiMEidosInteractionCallback, start_tick, end_tick, nullptr, nullptr);\n\t\n\tnew_script_block->interaction_type_id_ = int_type_id;\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tAddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>)rescheduleScriptBlock(io<SLiMEidosBlock>$ block, [Ni$ start = NULL], [Ni$ end = NULL], [Ni ticks = NULL])\n//\nEidosValue_SP Community::ExecuteMethod_rescheduleScriptBlock(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *block_value = (EidosValue_Object *)p_arguments[0].get();\n\tEidosValue *start_value = p_arguments[1].get();\n\tEidosValue *end_value = p_arguments[2].get();\n\tEidosValue *ticks_value = p_arguments[3].get();\n\t\n\tSLiMEidosBlock *block = SLiM_ExtractSLiMEidosBlockFromEidosValue_io(block_value, 0, this, nullptr, \"rescheduleScriptBlock()\");\t// agnostic to species\n\tbool start_null = (start_value->Type() == EidosValueType::kValueNULL);\n\tbool end_null = (end_value->Type() == EidosValueType::kValueNULL);\n\tbool ticks_null = (ticks_value->Type() == EidosValueType::kValueNULL);\n\t\n\tif (block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t{\n\t\t// this should never be hit, because the user should have no way to get a reference to a function block\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_rescheduleScriptBlock): (internal error) rescheduleScriptBlock() cannot be called on user-defined function script blocks.\" << EidosTerminate();\n\t}\n\t\n\tSLiMCycleStage stage = CycleStageForScriptBlockType(block->type_);\n\t\n\tif ((!start_null || !end_null) && ticks_null)\n\t{\n\t\t// start/end case; this is simple\n\t\t\n\t\tslim_tick_t start = (start_null ? 1 : SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)));\n\t\tslim_tick_t end = (end_null ? SLIM_MAX_TICK + 1 : SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)));\n\t\t\n\t\tif (start > end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_rescheduleScriptBlock): rescheduleScriptBlock() requires start <= end.\" << EidosTerminate();\n\t\t\n\t\tCheckScheduling(start, stage);\n\t\t\n\t\tblock->tick_range_evaluated_ = true;\n\t\tblock->tick_range_is_sequence_ = true;\n\t\tblock->tick_start_ = start;\n\t\tblock->tick_end_ = end;\n\t\tblock->tick_set_.clear();\n\t\t\n\t\tlast_script_block_tick_cached_ = false;\n\t\tscript_block_types_cached_ = false;\n\t\tscripts_changed_ = true;\n\t\t\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"\\t\\trescheduleScriptBlock() called (with start \" << start << \", end \" << end << \") for block: \";\n\t\tblock->PrintDeclaration(gSLiMScheduling, this);\n\t\tgSLiMScheduling << std::endl;\n#endif\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(block, gSLiM_SLiMEidosBlock_Class));\n\t}\n\telse if (!ticks_null && (start_null && end_null))\n\t{\n\t\t// ticks case; we no longer schedule multiple blocks, we use ticks_set_ with the focal block\n\t\t\n\t\t// first, fetch the ticks and make sure they are in bounds\n\t\tint tick_count = ticks_value->Count();\n\t\tconst int64_t *ticks_data = ticks_value->IntData();\n\t\t\n\t\tif (tick_count == 0)\n\t\t{\n\t\t\t// set to run in no ticks; we do this with an empty set\n\t\t\tblock->tick_range_evaluated_ = true;\n\t\t\tblock->tick_range_is_sequence_ = false;\n\t\t\tblock->tick_set_.clear();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// if it is a singleton, or a consecutive range, we detect that and handle it efficiently\n\t\t\t// we don't try to detect consecutive ranges that have been scrambled, since we'd have to sort;\n\t\t\t// I don't want this algorithm to be O(N log N), since we might get called with a very large vector\n\t\t\tbool is_sequential = true;\n\t\t\tint64_t first_value = ticks_data[0];\n\t\t\tint64_t prev_value = first_value;\n\t\t\t\n\t\t\tfor (int index = 1; index < tick_count; ++index)\n\t\t\t{\n\t\t\t\tint64_t tick_64 = ticks_data[index];\n\t\t\t\t\n\t\t\t\tif ((tick_64 < 1) || (tick_64 > SLIM_MAX_TICK))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_rescheduleScriptBlock): tick value out of range (\" << tick_64 << \").\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (tick_64 != prev_value + 1)\n\t\t\t\t{\n\t\t\t\t\tis_sequential = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tprev_value = tick_64;\n\t\t\t}\n\t\t\t\n\t\t\tif (is_sequential)\n\t\t\t{\n\t\t\t\tblock->tick_range_evaluated_ = true;\n\t\t\t\tblock->tick_range_is_sequence_ = true;\n\t\t\t\tblock->tick_start_ = (slim_tick_t)first_value;\n\t\t\t\tblock->tick_end_ = (slim_tick_t)prev_value;\n\t\t\t\tblock->tick_set_.clear();\n\t\t\t\t\n\t\t\t\tCheckScheduling(block->tick_start_, stage);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::unordered_set<slim_tick_t> &set = block->tick_set_;\n\t\t\t\tslim_tick_t min_tick = SLIM_MAX_TICK;\n\t\t\t\t\n\t\t\t\tblock->tick_range_evaluated_ = true;\n\t\t\t\tblock->tick_range_is_sequence_ = false;\n\t\t\t\tset.clear();\n\t\t\t\t\n\t\t\t\tfor (int tick_index = 0; tick_index < tick_count; ++tick_index)\n\t\t\t\t{\n\t\t\t\t\tslim_tick_t tick = (slim_tick_t)ticks_data[tick_index];\n\t\t\t\t\t\n\t\t\t\t\tif (set.find(tick) != set.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_rescheduleScriptBlock): rescheduleScriptBlock() requires that the tick vector contain unique values; the same tick cannot be used twice.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (tick < min_tick)\n\t\t\t\t\t\tmin_tick = tick;\n\t\t\t\t\t\n\t\t\t\t\tset.emplace(tick);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tCheckScheduling(min_tick, stage);\t// if the minimum tick is OK, they are all OK\n\t\t\t}\n\t\t}\n\t\t\n\t\tlast_script_block_tick_cached_ = false;\n\t\tscript_block_types_cached_ = false;\n\t\tscripts_changed_ = true;\n\t\t\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"\\t\\trescheduleScriptBlock() called (with a ticks schedule) for block: \";\n\t\tblock->PrintDeclaration(gSLiMScheduling, this);\n\t\tgSLiMScheduling << std::endl;\n#endif\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(block, gSLiM_SLiMEidosBlock_Class));\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Community::ExecuteMethod_rescheduleScriptBlock): rescheduleScriptBlock() requires that either start/end or ticks be supplied, but not both.\" << EidosTerminate();\n\t}\n}\n\n//\t*********************\t- (void)simulationFinished(void)\n//\nEidosValue_SP Community::ExecuteMethod_simulationFinished(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t// Note that Species::ExecuteMethod_simulationFinished() calls this method to forward simulationFinished() on to us!\n\t// This means that we need to have an identical Eidos method signature, etc., so the forwarding goes smoothly.\n\t\n#ifdef SLIMGUI\n\tgSLiMScheduling << \"\\t\\tsimulationFinished() called\" << std::endl;\n#endif\n\t\n\tsim_declared_finished_ = true;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (float$)usage(void)\n//\nEidosValue_SP Community::ExecuteMethod_usage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BEWARE: See also the -outputUsage() method, which must be maintained in parallel with this\n\t\n\t// Tally up usage across the simulation\n\tSLiMMemoryUsage_Community usage_community;\n\tSLiMMemoryUsage_Species usage_all_species;\n\t\n\tEIDOS_BZERO(&usage_all_species, sizeof(SLiMMemoryUsage_Species));\n\t\n\tTabulateSLiMMemoryUsage_Community(&usage_community, &p_interpreter.SymbolTable());\n\t\n\tfor (Species *species : all_species_)\n\t{\n\t\tSLiMMemoryUsage_Species usage_one_species;\n\t\t\n\t\tspecies->TabulateSLiMMemoryUsage_Species(&usage_one_species);\n\t\tAccumulateMemoryUsageIntoTotal_Species(usage_one_species, usage_all_species);\n\t}\n\t\n\tsize_t usage = usage_community.totalMemoryUsage + usage_all_species.totalMemoryUsage;\n\tdouble usage_MB = usage / (1024.0 * 1024.0);\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(usage_MB));\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tCommunity_Class\n//\n#pragma mark -\n#pragma mark Community_Class\n#pragma mark -\n\nEidosClass *gSLiM_Community_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Community_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Community_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allGenomicElementTypes,\ttrue,\tkEidosValueMaskObject, gSLiM_GenomicElementType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allInteractionTypes,\ttrue,\tkEidosValueMaskObject, gSLiM_InteractionType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allMutationTypes,\t\ttrue,\tkEidosValueMaskObject, gSLiM_MutationType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allScriptBlocks,\t\ttrue,\tkEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allSpecies,\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_allSubpopulations,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Subpopulation_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_logFiles,\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_LogFile_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_modelType,\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tick,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_cycleStage,\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_verbosity,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Community_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Community_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_createLogFile, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_LogFile_Class))->AddString_S(gEidosStr_filePath)->AddString_ON(\"initialContents\", gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"compress\", gStaticEidosValue_LogicalF)->AddString_OS(\"sep\", gStaticEidosValue_StringComma)->AddInt_OSN(\"logInterval\", gStaticEidosValueNULL)->AddInt_OSN(\"flushInterval\", gStaticEidosValueNULL)->AddLogical_OS(\"header\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_estimatedLastTick, kEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_deregisterScriptBlock, kEidosValueMaskVOID))->AddIntObject(\"scriptBlocks\", gSLiM_SLiMEidosBlock_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_genomicElementTypesWithIDs, kEidosValueMaskObject, gSLiM_GenomicElementType_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_interactionTypesWithIDs, kEidosValueMaskObject, gSLiM_InteractionType_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationTypesWithIDs, kEidosValueMaskObject, gSLiM_MutationType_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputUsage, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerFirstEvent, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddObject_OSN(\"ticksSpec\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerEarlyEvent, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddObject_OSN(\"ticksSpec\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerLateEvent, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddObject_OSN(\"ticksSpec\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerInteractionCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_S(\"intType\", gSLiM_InteractionType_Class)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_rescheduleScriptBlock, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntObject_S(\"block\", gSLiM_SLiMEidosBlock_Class)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddInt_ON(\"ticks\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_scriptBlocksWithIDs, kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_simulationFinished, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_speciesWithIDs, kEidosValueMaskObject, gSLiM_Species_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_subpopulationsWithIDs, kEidosValueMaskObject, gSLiM_Subpopulation_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_subpopulationsWithNames, kEidosValueMaskObject, gSLiM_Subpopulation_Class))->AddString(\"names\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_usage, kEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n"
  },
  {
    "path": "core/core.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2019-07-10T21:52:57\n#\n#-------------------------------------------------\n\nQT       -= core gui\n\nTEMPLATE = lib\nCONFIG += staticlib\n\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\n# BCH 4/8/2026: I force AVX2 and FMA on for x86_64 builds (true since 2013), and NEON on for ARM64 builds\n# (true since forever), without the compiler capability testing done in CMakeFlags.txt.  This is a hack;\n# if it breaks things for an end user they can build with CMake instead or disable these defines.  Note\n# that building in Qt Creator is not the primary supported build method for SLiM, and is probably mostly\n# used only by me; I just want this on for development.  See https://github.com/MesserLab/SLiM/issues/598.\n# Note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro.\nmessage(\"Target architecture is: $${QMAKE_TARGET.arch}\")\n\nQMAKE_CFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\nQMAKE_CXXFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\n\nQMAKE_CFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\nQMAKE_CXXFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\n\nQMAKE_CFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\nQMAKE_CXXFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\n\n\n# Set up to build QtSLiM; note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro\nDEFINES += EIDOS_GUI\nDEFINES += SLIMGUI=1\n\nCONFIG -= qt\nCONFIG += c++11\nCONFIG += c11\nQMAKE_CFLAGS += -std=c11\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\nQMAKE_CXXFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CXXFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CXXFLAGS += -Wno-unknown-pragmas -Wno-attributes -Wno-unused-parameter\n}\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n# eidos library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../eidos/release/ -leidos\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../eidos/debug/ -leidos\nelse:unix: LIBS += -L$$OUT_PWD/../eidos/ -leidos\nINCLUDEPATH += $$PWD/../eidos\nDEPENDPATH += $$PWD/../eidos\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/release/libeidos.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/debug/libeidos.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/release/eidos.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos/debug/eidos.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../eidos/libeidos.a\n\n# gsl library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../gsl/release/ -lgsl\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../gsl/debug/ -lgsl\nelse:unix: LIBS += -L$$OUT_PWD/../gsl/ -lgsl\nINCLUDEPATH += $$PWD/../gsl $$PWD/../gsl/blas $$PWD/../gsl/block $$PWD/../gsl/cblas $$PWD/../gsl/cdf\nINCLUDEPATH += $$PWD/../gsl/complex $$PWD/../gsl/err $$PWD/../gsl/interpolation $$PWD/../gsl/linalg $$PWD/../gsl/matrix\nINCLUDEPATH += $$PWD/../gsl/permutation $$PWD/../gsl/randist $$PWD/../gsl/rng $$PWD/../gsl/specfunc $$PWD/../gsl/sys\nINCLUDEPATH += $$PWD/../gsl/vector\nDEPENDPATH += $$PWD/../gsl\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/libgsl.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/libgsl.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/gsl.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/gsl.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../gsl/libgsl.a\n\n# tskit library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../treerec/tskit/release/ -ltskit\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../treerec/tskit/debug/ -ltskit\nelse:unix: LIBS += -L$$OUT_PWD/../treerec/tskit/ -ltskit\nINCLUDEPATH += $$PWD/../treerec/tskit $$PWD/../treerec $$PWD/../treerec/tskit/kastore\nDEPENDPATH += $$PWD/../treerec/tskit\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/release/libtskit.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/debug/libtskit.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/release/tskit.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/debug/tskit.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../treerec/tskit/libtskit.a\n\n\nSOURCES += \\\n    chromosome.cpp \\\n    community.cpp \\\n    community_eidos.cpp \\\n    genomic_element_type.cpp \\\n    genomic_element.cpp \\\n    haplosome.cpp \\\n    individual.cpp \\\n    interaction_type.cpp \\\n    log_file.cpp \\\n    mutation_run.cpp \\\n    mutation_type.cpp \\\n    mutation.cpp \\\n    polymorphism.cpp \\\n    population.cpp \\\n    slim_eidos_block.cpp \\\n    slim_functions.cpp \\\n    slim_globals.cpp \\\n    slim_test.cpp \\\n    slim_test_core.cpp \\\n    slim_test_genetics.cpp \\\n    slim_test_other.cpp \\\n    sparse_vector.cpp \\\n    spatial_kernel.cpp \\\n    spatial_map.cpp \\\n    species.cpp \\\n    species_eidos.cpp \\\n    subpopulation.cpp \\\n    substitution.cpp\n\nHEADERS += \\\n    chromosome.h \\\n    community.h \\\n    genomic_element_type.h \\\n    genomic_element.h \\\n    haplosome.h \\\n    individual.h \\\n    interaction_type.h \\\n    log_file.h \\\n    mutation_run.h \\\n    mutation_type.h \\\n    mutation.h \\\n    polymorphism.h \\\n    population.h \\\n    slim_eidos_block.h \\\n    slim_functions.h \\\n    slim_globals.h \\\n    slim_test.h \\\n    sparse_vector.h \\\n    spatial_kernel.h \\\n    spatial_map.h \\\n    species.h \\\n    subpopulation.h \\\n    substitution.h\n"
  },
  {
    "path": "core/genomic_element.cpp",
    "content": "//\n//  genomic_element.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"genomic_element.h\"\n#include \"slim_globals.h\"\n#include \"species.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#include <algorithm>\n#include <string>\n#include <vector>\n\n\n#pragma mark -\n#pragma mark GenomicElement\n#pragma mark -\n\n\nGenomicElement::GenomicElement(GenomicElementType *p_genomic_element_type_ptr, slim_position_t p_start_position, slim_position_t p_end_position) :\n\tgenomic_element_type_ptr_(p_genomic_element_type_ptr), start_position_(p_start_position), end_position_(p_end_position)\n{\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const GenomicElement &p_genomic_element)\n{\n\tp_outstream << \"GenomicElement{genomic_element_type_ g\" << p_genomic_element.genomic_element_type_ptr_->genomic_element_type_id_ << \", start_position_ \" << p_genomic_element.start_position_ << \", end_position_ \" << p_genomic_element.end_position_ << \"}\";\n\t\n\treturn p_outstream;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nvoid GenomicElement::GenerateCachedEidosValue(void)\n{\n\t// Note that this cache cannot be invalidated as long as a symbol table might exist that this value has been placed into\n\tself_value_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_GenomicElement_Class));\n}\n\nconst EidosClass *GenomicElement::Class(void) const\n{\n\treturn gSLiM_GenomicElement_Class;\n}\n\nvoid GenomicElement::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP GenomicElement::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_genomicElementType:\t// ACCELERATED\n\t\t\treturn genomic_element_type_ptr_->SymbolTableEntry().second;\n\t\tcase gID_startPosition:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(start_position_));\n\t\tcase gID_endPosition:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(end_position_));\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_tag:\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElement::GetProperty): property tag accessed on genomic element before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *GenomicElement::GetProperty_Accelerated_startPosition(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElement *value = (GenomicElement *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->start_position_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *GenomicElement::GetProperty_Accelerated_endPosition(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElement *value = (GenomicElement *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->end_position_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *GenomicElement::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElement *value = (GenomicElement *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElement::GetProperty_Accelerated_tag): property tag accessed on genomic element before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *GenomicElement::GetProperty_Accelerated_genomicElementType(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElementType_Class))->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElement *value = (GenomicElement *)(p_values[value_index]);\n\t\t\n\t\tobject_result->set_object_element_no_check_NORR(value->genomic_element_type_ptr_, value_index);\n\t}\n\t\n\treturn object_result;\n}\n\nvoid GenomicElement::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP GenomicElement::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_setGenomicElementType: return ExecuteMethod_setGenomicElementType(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (void)setGenomicElementType(io<GenomicElementType>$ genomicElementType)\n//\nEidosValue_SP GenomicElement::ExecuteMethod_setGenomicElementType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *genomicElementType_value = p_arguments[0].get();\n\tSpecies &species = genomic_element_type_ptr_->species_;\n\tGenomicElementType *getype_ptr = SLiM_ExtractGenomicElementTypeFromEidosValue_io(genomicElementType_value, 0, &species.community_, &species, \"setGenomicElementType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\tgenomic_element_type_ptr_ = getype_ptr;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tGenomicElement_Class\n//\n#pragma mark -\n#pragma mark GenomicElement_Class\n#pragma mark -\n\nEidosClass *gSLiM_GenomicElement_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *GenomicElement_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"GenomicElement_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_genomicElementType,\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_GenomicElementType_Class))->DeclareAcceleratedGet(GenomicElement::GetProperty_Accelerated_genomicElementType));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_startPosition,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(GenomicElement::GetProperty_Accelerated_startPosition));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_endPosition,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(GenomicElement::GetProperty_Accelerated_endPosition));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(GenomicElement::GetProperty_Accelerated_tag));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *GenomicElement_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"GenomicElement_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setGenomicElementType, kEidosValueMaskVOID))->AddIntObject_S(\"genomicElementType\", gSLiM_GenomicElementType_Class));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/genomic_element.h",
    "content": "//\n//  genomic_element.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class GenomicElement represents a portion of a chromosome with particular properties.  A genomic element is defined by its type,\n which might represent introns versus extrons for example, and the start and end positions of the element on the chromosome.\n \n */\n\n#ifndef __SLiM__genomic_element__\n#define __SLiM__genomic_element__\n\n\n#include <iostream>\n\n#include \"genomic_element_type.h\"\n#include \"eidos_value.h\"\n\n\nextern EidosClass *gSLiM_GenomicElement_Class;\n\n\nclass GenomicElement : public EidosObject\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosObject super;\n\npublic:\n\t\n\tEidosValue_SP self_value_;\t\t\t\t\t\t\t\t// cached EidosValue object for speed\n\t\n\tGenomicElementType *genomic_element_type_ptr_;\t\t\t// pointer to the type of genomic element this is\n\tslim_position_t start_position_;\t\t\t\t\t\t// the start position of the element\n\tslim_position_t end_position_;\t\t\t\t\t\t\t// the end position of the element\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t// a user-defined tag value\n\t\n\tGenomicElement(const GenomicElement &p_original) = delete;\t\t\t\t\t\t// no copying\n\tGenomicElement& operator= (const GenomicElement &p_original) = delete;\t\t\t// no copying\n\tGenomicElement(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t// no null constructor\n\t\n\tGenomicElement(GenomicElementType *p_genomic_element_type_ptr, slim_position_t p_start_position, slim_position_t p_end_position);\n\t\n\t//\n\t// Eidos support\n\t//\n\tvoid GenerateCachedEidosValue(void);\n\tinline __attribute__((always_inline)) EidosValue_SP CachedEidosValue(void) { if (!self_value_) GenerateCachedEidosValue(); return self_value_; };\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_setGenomicElementType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_startPosition(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_endPosition(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_genomicElementType(EidosObject **p_values, size_t p_values_size);\n};\n\n// support stream output of GenomicElement, for debugging\nstd::ostream &operator<<(std::ostream &p_outstream, const GenomicElement &p_genomic_element);\n\nclass GenomicElement_Class : public EidosClass\n{\nprivate:\n\ttypedef EidosClass super;\n\npublic:\n\tGenomicElement_Class(const GenomicElement_Class &p_original) = delete;\t// no copy-construct\n\tGenomicElement_Class& operator=(const GenomicElement_Class&) = delete;\t// no copying\n\tinline GenomicElement_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__genomic_element__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/genomic_element_type.cpp",
    "content": "//\n//  genomic_element_type.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"genomic_element_type.h\"\n#include \"slim_globals.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"mutation_type.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#include <algorithm>\n#include <string>\n#include <utility>\n\n\n#pragma mark -\n#pragma mark GenomicElementType\n#pragma mark -\n\nGenomicElementType::GenomicElementType(Species &p_species, slim_objectid_t p_genomic_element_type_id, std::vector<MutationType*> p_mutation_type_ptrs, std::vector<double> p_mutation_fractions) :\n\tself_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('g', p_genomic_element_type_id)), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_GenomicElementType_Class))),\n\tspecies_(p_species), genomic_element_type_id_(p_genomic_element_type_id), mutation_type_ptrs_(std::move(p_mutation_type_ptrs)), mutation_fractions_(std::move(p_mutation_fractions)), mutation_matrix_(nullptr)\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\tInitializeDraws();\n}\n\nGenomicElementType::~GenomicElementType(void)\n{\n\t//EIDOS_ERRSTREAM << \"GenomicElementType::~GenomicElementType\" << std::endl;\n\t\n\tif (lookup_mutation_type_)\n\t{\n\t\tgsl_ran_discrete_free(lookup_mutation_type_);\n\t\tlookup_mutation_type_ = nullptr;\n\t}\n\t\n\tif (mm_thresholds)\n\t{\n\t\tfree(mm_thresholds);\n\t\tmm_thresholds = nullptr;\n\t}\n}\n\nvoid GenomicElementType::InitializeDraws(void)\n{\n\tsize_t mutation_type_count = mutation_type_ptrs_.size();\n\t\n\tif (mutation_type_count != mutation_fractions_.size())\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::InitializeDraws): mutation types and fractions have different sizes.\" << EidosTerminate();\n\t\n\tif (lookup_mutation_type_)\n\t{\n\t\tgsl_ran_discrete_free(lookup_mutation_type_);\n\t\tlookup_mutation_type_ = nullptr;\n\t}\n\t\n\t// We allow an empty mutation type vector initially, because people might want to add mutation types in script.\n\t// However, if DrawMutationType() is called and our vector is still empty, that will be an error.\n\tif (mutation_type_count)\n\t{\n\t\t// Prepare to randomly draw mutation types\n\t\tstd::vector<double> A(mutation_type_count);\n\t\tbool nonzero_seen = false;\n\t\t\n\t\tfor (unsigned int i = 0; i < mutation_type_count; i++)\n\t\t{\n\t\t\tdouble fraction = mutation_fractions_[i];\n\t\t\t\n\t\t\tif (fraction > 0.0)\n\t\t\t\tnonzero_seen = true;\n\t\t\t\n\t\t\tA[i] = fraction;\n\t\t}\n\t\t\n\t\t// A mutation type vector with all zero proportions is treated the same as an empty vector: we allow it\n\t\t// on the assumption that it will be fixed later, but if it isn't, that will be an error.\n\t\tif (nonzero_seen)\n\t\t\tlookup_mutation_type_ = gsl_ran_discrete_preproc(mutation_type_count, A.data());\n\t}\n}\n\nMutationType *GenomicElementType::DrawMutationType(void) const\n{\n\tif (!lookup_mutation_type_)\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::DrawMutationType): empty mutation type vector for genomic element type.\" << EidosTerminate();\n\t\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\treturn mutation_type_ptrs_[gsl_ran_discrete(rng_gsl, lookup_mutation_type_)];\n}\n\nvoid GenomicElementType::SetNucleotideMutationMatrix(const EidosValue_Float_SP &p_mutation_matrix)\n{\n\tmutation_matrix_ = p_mutation_matrix;\n\t\n\t// integrity checks\n\tif (mutation_matrix_->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires mutationMatrix to be a 4x4 or 64x4 matrix.\" << EidosTerminate();\n\t\n\tconst int64_t *dims = mutation_matrix_->Dimensions();\n\t\n\tif ((dims[0] == 4) && (dims[1] == 4))\n\t{\n\t\t// This is the 4x4 matrix case, providing rates for each original nucleotide (rows) to each derived nucleotide (cols)\n\t\t\n\t\t// check for zeros in the necessary positions\n\t\tstatic int required_zeros_4x4[4] = {0, 5, 10, 15};\n\t\t\n\t\tfor (int required_zeros : required_zeros_4x4)\n\t\t\tif (mutation_matrix_->FloatAtIndex_NOCAST(required_zeros, nullptr) != 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): the mutationMatrix must contain 0.0 for all entries that correspond to a nucleotide mutating to itself.\" << EidosTerminate();\n\t\t\n\t\t// check that each row sums to <= 1.0; in fact this has to be <= 1.0 even when multiplied by the hotspot map, but this is a preliminary sanity check\n\t\t// check also for no negative values, and for all values being finite\n\t\tfor (int row = 0; row < 4; ++row)\n\t\t{\n\t\t\tdouble row_1 = mutation_matrix_->FloatAtIndex_NOCAST(row, nullptr);\n\t\t\tdouble row_2 = mutation_matrix_->FloatAtIndex_NOCAST(row + 4, nullptr);\n\t\t\tdouble row_3 = mutation_matrix_->FloatAtIndex_NOCAST(row + 8, nullptr);\n\t\t\tdouble row_4 = mutation_matrix_->FloatAtIndex_NOCAST(row + 12, nullptr);\n\t\t\t\n\t\t\tif ((row_1 < 0.0) || (row_2 < 0.0) || (row_3 < 0.0) || (row_4 < 0.0) ||\n\t\t\t\t!std::isfinite(row_1) || !std::isfinite(row_2) || !std::isfinite(row_3) || !std::isfinite(row_4))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires all mutation matrix values to be finite and >= 0.0.\" << EidosTerminate();\n\t\t\tif (row_1 + row_2 + row_3 + row_4 > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires the sum of each mutation matrix row (the total probability of mutating for the given nucleotide or trinucleotide) to be <= 1.0.\" << EidosTerminate();\n\t\t}\n\t}\n\telse if ((dims[0] == 64) && (dims[1] == 4))\n\t{\n\t\t// This is the 64x4 matrix case, providing rates for each original trinucleotide (rows) to each derived nucleotide (cols)\n\t\t\n\t\t// check for zeros in the necessary positions\n\t\tstatic int required_zeros_64x4[64] = {0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51, 68, 69, 70, 71, 84, 85, 86, 87, 100, 101, 102, 103, 116, 117, 118, 119, 136, 137, 138, 139, 152, 153, 154, 155, 168, 169, 170, 171, 184, 185, 186, 187, 204, 205, 206, 207, 220, 221, 222, 223, 236, 237, 238, 239, 252, 253, 254, 255};\n\t\t\n\t\tfor (int required_zeros : required_zeros_64x4)\n\t\t\tif (mutation_matrix_->FloatAtIndex_NOCAST(required_zeros, nullptr) != 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): the mutationMatrix must contain 0.0 for all entries that correspond to a nucleotide mutating to itself.\" << EidosTerminate();\n\t\t\n\t\t// check that each row sums to <= 1.0; in fact this has to be <= 1.0 even when multiplied by the hotspot map, but this is a preliminary sanity check\n\t\t// check also for no negative values\n\t\tfor (int row = 0; row < 64; ++row)\n\t\t{\n\t\t\tdouble row_1 = mutation_matrix_->FloatAtIndex_NOCAST(row, nullptr);\n\t\t\tdouble row_2 = mutation_matrix_->FloatAtIndex_NOCAST(row + 64, nullptr);\n\t\t\tdouble row_3 = mutation_matrix_->FloatAtIndex_NOCAST(row + 128, nullptr);\n\t\t\tdouble row_4 = mutation_matrix_->FloatAtIndex_NOCAST(row + 192, nullptr);\n\t\t\t\n\t\t\tif ((row_1 < 0.0) || (row_2 < 0.0) || (row_3 < 0.0) || (row_4 < 0.0) ||\n\t\t\t\t!std::isfinite(row_1) || !std::isfinite(row_2) || !std::isfinite(row_3) || !std::isfinite(row_4))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires all mutation matrix values to be finite and >= 0.0.\" << EidosTerminate();\n\t\t\tif (row_1 + row_2 + row_3 + row_4 > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires the sum of each mutation matrix row (the total probability of mutating for the given nucleotide or trinucleotide) to be <= 1.0.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::SetNucleotideMutationMatrix): initializeGenomicElementType() requires mutationMatrix to be a 4x4 or 64x4 matrix.\" << EidosTerminate();\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const GenomicElementType &p_genomic_element_type)\n{\n\tp_outstream << \"GenomicElementType{mutation_types_ \";\n\t\n\tif (p_genomic_element_type.mutation_type_ptrs_.size() == 0)\n\t{\n\t\tp_outstream << \"*\";\n\t}\n\telse\n\t{\n\t\tp_outstream << \"<\";\n\t\t\n\t\tfor (unsigned int i = 0; i < p_genomic_element_type.mutation_type_ptrs_.size(); ++i)\n\t\t{\n\t\t\tp_outstream << p_genomic_element_type.mutation_type_ptrs_[i]->mutation_type_id_;\n\t\t\t\n\t\t\tif (i < p_genomic_element_type.mutation_type_ptrs_.size() - 1)\n\t\t\t\tp_outstream << \" \";\n\t\t}\n\t\t\n\t\tp_outstream << \">\";\n\t}\n\t\n\tp_outstream << \", mutation_fractions_ \";\n\t\n\tif (p_genomic_element_type.mutation_fractions_.size() == 0)\n\t{\n\t\tp_outstream << \"*\";\n\t}\n\telse\n\t{\n\t\tp_outstream << \"<\";\n\t\t\n\t\tfor (unsigned int i = 0; i < p_genomic_element_type.mutation_fractions_.size(); ++i)\n\t\t{\n\t\t\tp_outstream << p_genomic_element_type.mutation_fractions_[i];\n\t\t\t\n\t\t\tif (i < p_genomic_element_type.mutation_fractions_.size() - 1)\n\t\t\t\tp_outstream << \" \";\n\t\t}\n\t\t\n\t\tp_outstream << \">\";\n\t}\n\n\tp_outstream << \"}\";\n\t\n\treturn p_outstream;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *GenomicElementType::Class(void) const\n{\n\treturn gSLiM_GenomicElementType_Class;\n}\n\nvoid GenomicElementType::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<g\" << genomic_element_type_id_ << \">\";\n}\n\nEidosValue_SP GenomicElementType::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_id:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!cached_value_getype_id_)\n\t\t\t\tcached_value_getype_id_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(genomic_element_type_id_));\n\t\t\treturn cached_value_getype_id_;\n\t\t}\n\t\tcase gID_mutationTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto mut_type : mutation_type_ptrs_)\n\t\t\t\tvec->push_object_element_NORR(mut_type);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_mutationFractions:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mutation_fractions_));\n\t\t}\n\t\tcase gID_mutationMatrix:\n\t\t{\n\t\t\tif (!mutation_matrix_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::GetProperty): property mutationMatrix is only defined in nucleotide-based models.\" << EidosTerminate();\n\t\t\treturn mutation_matrix_;\n\t\t}\n\t\tcase gID_species:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(&species_, gSLiM_Species_Class));\n\t\t}\n\t\t\n\t\t\t// variables\n\t\tcase gEidosID_color:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(color_));\n\t\tcase gID_tag:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::GetProperty): property tag accessed on genomic element type before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *GenomicElementType::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElementType *value = (GenomicElementType *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->genomic_element_type_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *GenomicElementType::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tGenomicElementType *value = (GenomicElementType *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::GetProperty): property tag accessed on genomic element type before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nvoid GenomicElementType::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tswitch (p_property_id)\n\t{\n\t\tcase gEidosID_color:\n\t\t{\n\t\t\tcolor_ = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\tif (!color_.empty())\n\t\t\t\tEidos_GetColorComponents(color_, &color_red_, &color_green_, &color_blue_);\n\t\t\t\n\t\t\t// tweak a flag to make SLiMgui update\n\t\t\tspecies_.community_.genomic_element_types_changed_ = true;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP GenomicElementType::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_setMutationFractions:\treturn ExecuteMethod_setMutationFractions(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setMutationMatrix:\t\treturn ExecuteMethod_setMutationMatrix(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (void)setMutationFractions(io<MutationType> mutationTypes, numeric proportions)\n//\nEidosValue_SP GenomicElementType::ExecuteMethod_setMutationFractions(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutationTypes_value = p_arguments[0].get();\n\tEidosValue *proportions_value = p_arguments[1].get();\n\t\n\tint mut_type_id_count = mutationTypes_value->Count();\n\tint proportion_count = proportions_value->Count();\n\t\n\tif (mut_type_id_count != proportion_count)\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::ExecuteMethod_setMutationFractions): setMutationFractions() requires the sizes of mutationTypes and proportions to be equal.\" << EidosTerminate();\n\t\n\tstd::vector<MutationType*> mutation_types;\n\tstd::vector<double> mutation_fractions;\n\t\n\tfor (int mut_type_index = 0; mut_type_index < mut_type_id_count; ++mut_type_index)\n\t{ \n\t\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutationTypes_value, mut_type_index, &species_.community_, &species_, \"setMutationFractions()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\tdouble proportion = proportions_value->NumericAtIndex_NOCAST(mut_type_index, nullptr);\n\t\t\n\t\tif ((proportion < 0) || !std::isfinite(proportion))\t\t// == 0 is allowed but must be fixed before the simulation executes; see InitializeDraws()\n\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::ExecuteMethod_setMutationFractions): setMutationFractions() proportions must be greater than or equal to zero (\" << EidosStringForFloat(proportion) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\tif (std::find(mutation_types.begin(), mutation_types.end(), mutation_type_ptr) != mutation_types.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::ExecuteMethod_setMutationFractions): setMutationFractions() mutation type m\" << mutation_type_ptr->mutation_type_id_ << \" used more than once.\" << EidosTerminate();\n\t\t\n\t\tmutation_types.emplace_back(mutation_type_ptr);\n\t\tmutation_fractions.emplace_back(proportion);\n\t\t\n\t\t// check whether we are now using a mutation type that is non-neutral; check and set pure_neutral_\n\t\tif ((mutation_type_ptr->dfe_type_ != DFEType::kFixed) || (mutation_type_ptr->dfe_parameters_[0] != 0.0))\n\t\t\tspecies_.pure_neutral_ = false;\n\t}\n\t\n\t// Everything seems to be in order, so replace our mutation info with the new info\n\tmutation_type_ptrs_ = mutation_types;\n\tmutation_fractions_ = mutation_fractions;\n\t\n\t// Reinitialize our mutation type lookup based on the new info\n\tInitializeDraws();\n\t\n\t// Notify interested parties of the change\n\tspecies_.community_.genomic_element_types_changed_ = true;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setMutationMatrix(float mutationMatrix)\n//\nEidosValue_SP GenomicElementType::ExecuteMethod_setMutationMatrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (!species_.IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (GenomicElementType::ExecuteMethod_setMutationMatrix): setMutationMatrix() may only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tEidosValue *mutationMatrix_value = p_arguments[0].get();\n\t\n\tSetNucleotideMutationMatrix(EidosValue_Float_SP((EidosValue_Float *)(mutationMatrix_value)));\n\t\n\t// the change to the mutation matrix means everything downstream has to be recached\n\tspecies_.MaxNucleotideMutationRateChanged();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tGenomicElementType_Class\n//\n#pragma mark -\n#pragma mark GenomicElementType_Class\n#pragma mark -\n\nEidosClass *gSLiM_GenomicElementType_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *GenomicElementType_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"GenomicElementType_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(GenomicElementType::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationTypes,\t\ttrue,\tkEidosValueMaskObject, gSLiM_MutationType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationFractions,\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationMatrix,\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_species,\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(GenomicElementType::GetProperty_Accelerated_tag));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_color,\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *GenomicElementType_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"GenomicElementType_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setMutationFractions, kEidosValueMaskVOID))->AddIntObject(\"mutationTypes\", gSLiM_MutationType_Class)->AddNumeric(\"proportions\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setMutationMatrix, kEidosValueMaskVOID))->AddFloat(\"mutationMatrix\"));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/genomic_element_type.h",
    "content": "//\n//  genomic_element_type.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class GenomicElementType represents a possible type of genomic element, defined by the types of mutations the element undergoes,\n and the relative fractions of each of those mutation types.  Exons and introns might be represented by different genomic element types,\n for example, and might have different types of mutations (exons undergo adaptive mutations while introns do not, perhaps).  At present,\n these mutational dynamics are the only defining characteristics of genomic elements.\n \n */\n\n#ifndef __SLiM__genomic_element_type__\n#define __SLiM__genomic_element_type__\n\n\n#include <vector>\n#include <iostream>\n\n#include \"slim_globals.h\"\n#include \"eidos_rng.h\"\n#include \"mutation_type.h\"\n#include \"eidos_value.h\"\n\nclass Species;\n\n\nextern EidosClass *gSLiM_GenomicElementType_Class;\n\n\nclass GenomicElementType : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\t\n\tgsl_ran_discrete_t *lookup_mutation_type_ = nullptr;\t\t\t\t// OWNED POINTER: a lookup table for getting a mutation type for this genomic element\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t\t\t\t\t// for fast setup of the symbol table\n\t\npublic:\n\t\n\tSpecies &species_;\n\t\n\tslim_objectid_t genomic_element_type_id_;\t\t\t\t\t\t\t// the id by which this genomic element type is indexed in the chromosome\n\tEidosValue_SP cached_value_getype_id_;\t\t\t\t\t\t\t\t// a cached value for genomic_element_type_id_; reset() if that changes\n\t\n\tstd::vector<MutationType*> mutation_type_ptrs_;\t\t\t\t\t\t// mutation types identifiers in this element\n\tstd::vector<double> mutation_fractions_;\t\t\t\t\t\t\t// relative fractions of each mutation type\n\t\n\tstd::string color_;\t\t\t\t\t\t\t\t\t\t\t\t\t// color to use when displayed (in SLiMgui)\n\tfloat color_red_, color_green_, color_blue_;\t\t\t\t\t\t// cached color components from color_; should always be in sync\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t\t\t// a user-defined tag value\n\t\n\tEidosValue_Float_SP mutation_matrix_;\t\t\t\t\t\t\t\t// in nucleotide-based models only, the 4x4 or 64x4 float mutation matrix\n\tdouble *mm_thresholds = nullptr;\t\t\t\t\t\t\t\t\t// mutation matrix threshold values for determining derived nucleotides; cached in CacheNucleotideMatrices()\n\t\n\tGenomicElementType(const GenomicElementType&) = delete;\t\t\t\t// no copying\n\tGenomicElementType& operator=(const GenomicElementType&) = delete;\t// no copying\n\tGenomicElementType(void) = delete;\t\t\t\t\t\t\t\t\t// no null construction\n\tGenomicElementType(Species &p_species, slim_objectid_t p_genomic_element_type_id, std::vector<MutationType*> p_mutation_type_ptrs, std::vector<double> p_mutation_fractions);\n\t~GenomicElementType(void);\n\t\n\tvoid InitializeDraws(void);\t\t\t\t\t\t\t\t\t// reinitialize our mutation-type lookup after changing our mutation type or proportions\n\tMutationType *DrawMutationType(void) const;\t\t\t\t\t// draw a mutation type from the distribution for this genomic element type\n\t\n\tvoid SetNucleotideMutationMatrix(const EidosValue_Float_SP &p_mutation_matrix);\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; }\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_setMutationFractions(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setMutationMatrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n};\n\n// support stream output of GenomicElementType, for debugging\nstd::ostream &operator<<(std::ostream &p_outstream, const GenomicElementType &p_genomic_element_type);\n\nclass GenomicElementType_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tGenomicElementType_Class(const GenomicElementType_Class &p_original) = delete;\t// no copy-construct\n\tGenomicElementType_Class& operator=(const GenomicElementType_Class&) = delete;\t// no copying\n\tinline GenomicElementType_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__genomic_element_type__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/haplosome.cpp",
    "content": "//\n//  haplosome.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"haplosome.h\"\n#include \"slim_globals.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"polymorphism.h\"\n#include \"subpopulation.h\"\n#include \"eidos_sorting.h\"\n\n#include <algorithm>\n#include <string>\n#include <iostream>\n#include <fstream>\n#include <iomanip>\n#include <map>\n#include <utility>\n\n\n#pragma mark -\n#pragma mark Haplosome\n#pragma mark -\n\n// Static class variables in support of Haplosome's bulk operation optimization; see Haplosome::WillModifyRunForBulkOperation()\nint64_t Haplosome::s_bulk_operation_id_ = 0;\nslim_mutrun_index_t Haplosome::s_bulk_operation_mutrun_index_ = -1;\nSLiMBulkOperationHashTable Haplosome::s_bulk_operation_runs_;\n\n\nHaplosome::~Haplosome(void)\n{\n\tif (mutruns_ != run_buffer_)\n\t\tfree(mutruns_);\n\tmutruns_ = nullptr;\n\t\n\tmutrun_count_ = 0;\n}\n\nChromosome *Haplosome::AssociatedChromosome(void) const\n{\n\treturn individual_->subpopulation_->species_.Chromosomes()[chromosome_index_];\n}\n\n// prints an error message, a stacktrace, and exits; called only for DEBUG\nvoid Haplosome::NullHaplosomeAccessError(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (Haplosome::NullHaplosomeAccessError): (internal error) a null haplosome was accessed.\" << EidosTerminate();\n}\n\nMutationRun *Haplosome::WillModifyRun(slim_mutrun_index_t p_run_index, MutationRunContext &p_mutrun_context)\n{\n#if DEBUG\n\tif (p_run_index >= mutrun_count_)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRun): (internal error) attempt to modify an out-of-index run.\" << EidosTerminate();\n#endif\n\t\n\t// This method used to support in-place modification for mutruns with a use count of 1,\n\t// saving the new mutation run allocation; this is now done only in WillModifyRun_UNSHARED().\n\t// See the header comment for more information.\n\tconst MutationRun *original_run = mutruns_[p_run_index];\n\tMutationRun *new_run = MutationRun::NewMutationRun(p_mutrun_context);\t// take from shared pool of used objects\n\t\n\tnew_run->copy_from_run(*original_run);\n\tmutruns_[p_run_index] = new_run;\n\t\n\t// We return a non-const pointer to the caller, giving them permission to modify this new run\n\treturn new_run;\n}\n\nMutationRun *Haplosome::WillModifyRun_UNSHARED(slim_mutrun_index_t p_run_index, MutationRunContext &p_mutrun_context)\n{\n#if DEBUG\n\tif (p_run_index >= mutrun_count_)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRun_UNSHARED): (internal error) attempt to modify an out-of-index run.\" << EidosTerminate();\n#endif\n\t\n\t// This method avoids the new mutation run allocation, unless the mutation run is empty.\n\t// This is based on a guarantee from the caller that the run is unshared (unless it is empty).\n\t// See the header comment for more information.\n\tconst MutationRun *original_run = mutruns_[p_run_index];\n\t\n\tif (original_run->size() == 0)\n\t{\n\t\tMutationRun *new_run = MutationRun::NewMutationRun(p_mutrun_context);\t// take from shared pool of used objects\n\t\t\n\t\tnew_run->copy_from_run(*original_run);\n\t\tmutruns_[p_run_index] = new_run;\n\t\t\n\t\t// We return a non-const pointer to the caller, giving them permission to modify this new run\n\t\treturn new_run;\n\t}\n\telse\n\t{\n\t\t// We have been guaranteed by the caller that this mutation run is unshared, so we can cast away the const\n\t\tMutationRun *unlocked_run = const_cast<MutationRun *>(original_run);\n\t\t\n\t\tunlocked_run->will_modify_run();\t// in-place modification of runs requires notification, for cache invalidation\n\t\t\n\t\t// We return a non-const pointer to the caller, giving them permission to modify this run\n\t\treturn unlocked_run;\n\t}\n}\n\nvoid Haplosome::BulkOperationStart(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome::BulkOperationStart(): s_bulk_operation_id_\");\n\t\n\tif (s_bulk_operation_id_ != 0)\n\t{\n\t\t//EIDOS_TERMINATION << \"ERROR (Haplosome::BulkOperationStart): (internal error) unmatched bulk operation start.\" << EidosTerminate();\n\t\t\n\t\t// It would be nice to be able to throw an exception here, but in the present design, the\n\t\t// bulk operation info can get messed up if the bulk operation throws an exception that\n\t\t// blows through the call to Haplosome::BulkOperationEnd().\n\t\t// Note this warning is not suppressed by gEidosSuppressWarnings; that is deliberate\n\t\tstd::cout << \"WARNING (Haplosome::BulkOperationStart): (internal error) unmatched bulk operation start.\" << std::endl;\n\t\t\n\t\t// For now, we assume that the end call got blown through, and we close out the old operation.\n\t\tHaplosome::BulkOperationEnd(s_bulk_operation_id_, s_bulk_operation_mutrun_index_);\n\t}\n\t\n\ts_bulk_operation_id_ = p_operation_id;\n\ts_bulk_operation_mutrun_index_ = p_mutrun_index;\n}\n\nMutationRun *Haplosome::WillModifyRunForBulkOperation(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index, MutationRunContext &p_mutrun_context)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome::WillModifyRunForBulkOperation(): s_bulk_operation_id_\");\n\t\n\tif (p_mutrun_index != s_bulk_operation_mutrun_index_)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRunForBulkOperation): (internal error) incorrect run index during bulk operation.\" << EidosTerminate();\n\tif (p_mutrun_index >= mutrun_count_)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRunForBulkOperation): (internal error) attempt to modify an out-of-index run.\" << EidosTerminate();\n\t\n#if 0\n#warning Haplosome::WillModifyRunForBulkOperation disabled...\n\t// The trivial version of this function just calls WillModifyRun(),\n\t// requesting that the caller perform the operation\n\treturn WillModifyRun(p_run_index);\n#else\n\t// The interesting version remembers the operation in progress, using the ID, and\n\t// tracks original/final MutationRun pointers, returning nullptr if an original is matched.\n\tconst MutationRun *original_run = mutruns_[p_mutrun_index];\n\t\n\tif (p_operation_id != s_bulk_operation_id_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRunForBulkOperation): (internal error) missing bulk operation start.\" << EidosTerminate();\n\t\n\tauto found_run_pair = s_bulk_operation_runs_.find(original_run);\n\t\n\tif (found_run_pair == s_bulk_operation_runs_.end())\n\t{\n\t\t// This MutationRun is not in the map, so we need to set up a new entry\n\t\tMutationRun *product_run = MutationRun::NewMutationRun(p_mutrun_context);\n\t\t\n\t\tproduct_run->copy_from_run(*original_run);\n\t\tmutruns_[p_mutrun_index] = product_run;\n\t\t\n\t\ttry {\n\t\t\ts_bulk_operation_runs_.emplace(original_run, product_run);\n\t\t} catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillModifyRunForBulkOperation): (internal error) SLiM encountered a raise from an internal hash table; please report this.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t//std::cout << \"WillModifyRunForBulkOperation() created product for \" << original_run << std::endl;\n\t\t\n\t\treturn product_run;\n\t}\n\telse\n\t{\n\t\t// This MutationRun is in the map, so we can just reuse it to redo the operation\n\t\tmutruns_[p_mutrun_index] = found_run_pair->second;\n\t\t\n\t\t//std::cout << \"   WillModifyRunForBulkOperation() substituted known product for \" << original_run << std::endl;\n\t\t\n\t\treturn nullptr;\n\t}\n#endif\n}\n\nvoid Haplosome::BulkOperationEnd(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome::BulkOperationEnd(): s_bulk_operation_id_\");\n\t\n\tif ((p_operation_id == s_bulk_operation_id_) && (p_mutrun_index == s_bulk_operation_mutrun_index_))\n\t{\n\t\ts_bulk_operation_runs_.clear();\n\t\ts_bulk_operation_id_ = 0;\n\t\ts_bulk_operation_mutrun_index_ = -1;\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::BulkOperationEnd): (internal error) unmatched bulk operation end.\" << EidosTerminate();\n\t}\n}\n\nvoid Haplosome::TallyHaplosomeReferences_Checkback(slim_refcount_t *p_mutrun_ref_tally, slim_refcount_t *p_mutrun_tally, int64_t p_operation_id)\n{\n#if DEBUG\n\tif (mutrun_count_ == 0)\n\t\tNullHaplosomeAccessError();\n#endif\n\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t{\n\t\tif (mutruns_[run_index]->operation_id_ != p_operation_id)\n\t\t{\n\t\t\t(*p_mutrun_ref_tally) += mutruns_[run_index]->use_count();\n\t\t\t(*p_mutrun_tally)++;\n\t\t\tmutruns_[run_index]->operation_id_ = p_operation_id;\n\t\t}\n\t}\n}\n\nvoid Haplosome::MakeNull(void)\n{\n\tif (mutrun_count_)\n\t{\n\t\tif (mutruns_ != run_buffer_)\n\t\t\tfree(mutruns_);\n\t\tmutruns_ = nullptr;\n\t\t\n\t\tmutrun_count_ = 0;\n\t\tmutrun_length_ = 0;\n\t}\n}\n\nvoid Haplosome::ReinitializeHaplosomeToNull(Individual *individual)\n{\n\t// Transmogrify a haplosome (which might be null or non-null) into a null haplosome\n\tindividual_ = individual;\n\t\n\tif (mutrun_count_)\n\t{\n\t\t// was a non-null haplosome, needs to become null\n\t\tif (mutruns_ != run_buffer_)\n\t\t\tfree(mutruns_);\n\t\tmutruns_ = nullptr;\n\t\t\n\t\t// chromosome_index_ remains untouched; we still belong to the same chromosome\n\t\tmutrun_count_ = 0;\n\t\tmutrun_length_ = 0;\n\t}\n}\n\nvoid Haplosome::ReinitializeHaplosomeToNonNull(Individual *individual, Chromosome *p_chromosome)\n{\n\t// Transmogrify a haplosome (which might be null or non-null) into a non-null haplosome with a specific configuration\n\tindividual_ = individual;\n\t\n#if DEBUG\n\t// We should always be reinitializing a haplosome that already belongs to the chromosome;\n\t// the only reason the chromosome is passed in is that it knows the mutrun configuration.\n\tif (chromosome_index_ != p_chromosome->Index())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ReinitializeHaplosomeToNonNull): (internal error) incorrect chromosome index.\" << EidosTerminate();\n#endif\n\t\n\tif (mutrun_count_ == 0)\n\t{\n\t\t// was a null haplosome, needs to become not null\n\t\tmutrun_count_ = p_chromosome->mutrun_count_;\n\t\tmutrun_length_ = p_chromosome->mutrun_length_;\n\t\t\n\t\tif (mutrun_count_ <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t{\n\t\t\tmutruns_ = run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tEIDOS_BZERO(run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t\telse\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tmutruns_ = (const MutationRun **)calloc(mutrun_count_, sizeof(const MutationRun *));\n#else\n\t\t\tmutruns_ = (const MutationRun **)malloc(mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t}\n\telse if (mutrun_count_ != p_chromosome->mutrun_count_)\n\t{\n\t\t// the number of mutruns has changed; need to reallocate\n\t\tif (mutruns_ != run_buffer_)\n\t\t\tfree(mutruns_);\n\t\t\n\t\tmutrun_count_ = p_chromosome->mutrun_count_;\n\t\tmutrun_length_ = p_chromosome->mutrun_length_;\n\t\t\n\t\tif (mutrun_count_ <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t{\n\t\t\tmutruns_ = run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tEIDOS_BZERO(run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t\telse\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tmutruns_ = (const MutationRun **)calloc(mutrun_count_, sizeof(const MutationRun *));\n#else\n\t\t\tmutruns_ = (const MutationRun **)malloc(mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t}\n\telse\n\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t// the number of mutruns has not changed; need to zero out\n\t\tEIDOS_BZERO(mutruns_, mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t}\n}\n\nvoid Haplosome::record_derived_states(Species *p_species) const\n{\n\t// This is called by Species::RecordAllDerivedStatesFromSLiM() to record all the derived states present\n\t// in a given haplosome that was just created by readFromPopulationFile() or some similar situation.  It should\n\t// make calls to record the derived state at each position in the haplosome that has any mutation.\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome::record_derived_states(): usage of statics\");\n\n\tstatic std::vector<Mutation *> record_vec;\n\t\n\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t{\n\t\tconst MutationRun *mutrun = mutruns_[run_index];\n\t\tint mutrun_size = mutrun->size();\n\t\tslim_position_t last_pos = -1;\n\t\t\n\t\t//record_vec.resize(0);\t// should always be left clear by the code below\n\t\t\n\t\tfor (int mut_index = 0; mut_index < mutrun_size; ++mut_index)\n\t\t{\n\t\t\tMutationIndex mutation_index = (*mutrun)[mut_index];\n\t\t\tMutation *mutation = mut_block_ptr + mutation_index;\n\t\t\tslim_position_t mutation_pos = mutation->position_;\n\t\t\t\n\t\t\tif (mutation_pos != last_pos)\n\t\t\t{\n\t\t\t\t// New position, so we finish the previous derived-state block...\n\t\t\t\tif (last_pos != -1)\n\t\t\t\t{\n\t\t\t\t\tp_species->RecordNewDerivedState(this, last_pos, record_vec);\n\t\t\t\t\trecord_vec.resize(0);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// ...and start a new derived-state block\n\t\t\t\tlast_pos = mutation_pos;\n\t\t\t}\n\t\t\t\n\t\t\trecord_vec.emplace_back(mutation);\n\t\t}\n\t\t\n\t\t// record the last derived block, if any\n\t\tif (last_pos != -1)\n\t\t{\n\t\t\tp_species->RecordNewDerivedState(this, last_pos, record_vec);\n\t\t\trecord_vec.resize(0);\n\t\t}\n\t}\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nvoid Haplosome::GenerateCachedEidosValue(void)\n{\n\t// Note that this cache cannot be invalidated as long as a symbol table might exist that this value has been placed into\n\tself_value_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Haplosome_Class));\n}\n\nconst EidosClass *Haplosome::Class(void) const\n{\n\treturn gSLiM_Haplosome_Class;\n}\n\nvoid Haplosome::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\";\n\t\n\tp_ostream << AssociatedChromosome()->Type();\n\t\n\tif (mutrun_count_ == 0)\n\t\tp_ostream << \":null>\";\n\telse\n\t\tp_ostream << \":\" << mutation_count() << \">\";\n}\n\nEidosValue_SP Haplosome::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_chromosome:\n\t\t{\n\t\t\t// We reach our chromosome through our individual; note this prevents standalone haplosome objects\n\t\t\tChromosome *chromosome = AssociatedChromosome();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(chromosome, gSLiM_Chromosome_Class));\n\t\t}\n\t\tcase gID_chromosomeSubposition:\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(chromosome_subposition_));\n\t\t}\n\t\tcase gID_haplosomePedigreeID:\t\t// ACCELERATED\n\t\t{\n\t\t\tSpecies &species = individual_->subpopulation_->species_;\n\t\t\t\n\t\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): property haplosomePedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(haplosome_id_));\n\t\t}\n\t\tcase gID_individual:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(individual_, gSLiM_Individual_Class));\n\t\t}\n\t\tcase gID_isNullHaplosome:\t\t// ACCELERATED\n\t\t\treturn ((mutrun_count_ == 0) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_mutationCount:\n\t\t{\n\t\t\tif (IsDeferred())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\t\t\n\t\t\tint mut_count = mutation_count();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mut_count));\n\t\t}\n\t\tcase gID_mutations:\n\t\t{\n\t\t\tif (IsDeferred())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\t\t\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\tint mut_count = mutation_count();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(mut_count);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\tint set_index = 0;\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = mutruns_[run_index];\n\t\t\t\tconst MutationIndex *mut_start_ptr = mutrun->begin_pointer_const();\n\t\t\t\tconst MutationIndex *mut_end_ptr = mutrun->end_pointer_const();\n\t\t\t\t\n\t\t\t\tfor (const MutationIndex *mut_ptr = mut_start_ptr; mut_ptr < mut_end_ptr; ++mut_ptr)\n\t\t\t\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + *mut_ptr, set_index++);\n\t\t\t}\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): property tag accessed on haplosome before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *Haplosome::GetProperty_Accelerated_haplosomePedigreeID(EidosObject **p_values, size_t p_values_size)\n{\n\tSpecies *consensus_species = Community::SpeciesForHaplosomesVector((Haplosome **)p_values, (int)p_values_size);\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tif (p_values_size == 0)\n\t\treturn int_result;\n\t\n\tif (consensus_species)\n\t{\n\t\t// check that pedigrees are enabled, once\n\t\tSpecies &species = ((Haplosome *)(p_values[0]))->individual_->subpopulation_->species_;\n\t\t\t\n\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): property haplosomePedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tHaplosome *value = (Haplosome *)(p_values[value_index]);\n\t\t\t\n\t\t\tint_result->set_int_no_check(value->haplosome_id_, value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// we have a mix of species, so we need to check that pedigree IDs are available for each individual\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tHaplosome *value = (Haplosome *)(p_values[value_index]);\n\t\t\tSpecies &species = value->individual_->subpopulation_->species_;\n\t\t\t\n\t\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): property haplosomePedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tint_result->set_int_no_check(value->haplosome_id_, value_index);\n\t\t}\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Haplosome::GetProperty_Accelerated_chromosomeSubposition(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tHaplosome *value = (Haplosome *)(p_values[value_index]);\n\t\tint64_t subposition_value = (uint64_t)(value->chromosome_subposition_);\n\t\t\n\t\tint_result->set_int_no_check(subposition_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Haplosome::GetProperty_Accelerated_isNullHaplosome(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tHaplosome *value = (Haplosome *)(p_values[value_index]);\n\t\t\n\t\tlogical_result->set_logical_no_check(value->mutrun_count_ == 0, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Haplosome::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tHaplosome *value = (Haplosome *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::GetProperty): property tag accessed on haplosome before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nvoid Haplosome::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\tIndividual::s_any_haplosome_tag_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nvoid Haplosome::SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tIndividual::s_any_haplosome_tag_set_ = true;\n\t\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Haplosome *)(p_values[value_index]))->tag_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Haplosome *)(p_values[value_index]))->tag_value_ = source_data[value_index];\n\t}\n}\n\nEidosValue_SP Haplosome::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\t//case gID_containsMarkerMutation:\t\treturn ExecuteMethod_Accelerated_containsMarkerMutation(p_method_id, p_arguments, p_interpreter);\n\t\t//case gID_containsMutations:\t\t\treturn ExecuteMethod_Accelerated_containsMutations(p_method_id, p_arguments, p_interpreter);\n\t\t//case gID_countOfMutationsOfType:\t\treturn ExecuteMethod_Accelerated_countOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mutationsOfType:\t\t\t\treturn ExecuteMethod_mutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_nucleotides:\t\t\t\t\treturn ExecuteMethod_nucleotides(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_positionsOfMutationsOfType:\treturn ExecuteMethod_positionsOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_sumOfMutationsOfType:\t\t\treturn ExecuteMethod_sumOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (Nlo<Mutation>$)containsMarkerMutation(io<MutationType>$ mutType, integer$ position, [returnMutation$ = F])\n//\nEidosValue_SP Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\tEidosValue *position_value = p_arguments[1].get();\n\tEidosValue *returnMutation_value = p_arguments[2].get();\n\t\n\tif (p_elements_size)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tSpecies *haplosomes_species = Community::SpeciesForHaplosomesVector((Haplosome **)p_elements, (int)p_elements_size);\n\t\t\n\t\tif (!haplosomes_species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation): containsMarkerMutation() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\t\n\t\thaplosomes_species->population_.CheckForDeferralInHaplosomesVector((Haplosome **)p_elements, p_elements_size, \"Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation\");\n\t\t\n\t\tSpecies &species = *haplosomes_species;\n\t\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"containsMarkerMutation()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\tslim_position_t marker_position = SLiMCastToPositionTypeOrRaise(position_value->IntAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\teidos_logical_t returnMutation = returnMutation_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (p_elements_size == 1)\n\t\t{\n\t\t\t// separate singleton case to return gStaticEidosValue_LogicalT / gStaticEidosValue_LogicalF\n\t\t\tHaplosome *element = (Haplosome *)(p_elements[0]);\n\t\t\t\n\t\t\tif (!element->IsNull())\n\t\t\t{\n\t\t\t\tChromosome *chromosome = element->AssociatedChromosome();\n\t\t\t\tslim_position_t last_position = chromosome->last_position_;\n\t\t\t\t\n\t\t\t\tif (marker_position > last_position)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation): containsMarkerMutation() position \" << marker_position << \" is past the end of the chromosome for the haplosome.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tMutation *mut = element->mutation_with_type_and_position(mutation_type_ptr, marker_position, last_position);\n\t\t\t\t\n\t\t\t\tif (returnMutation == false)\n\t\t\t\t\treturn (mut ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\telse\n\t\t\t\t\treturn (mut ? EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(mut, gSLiM_Mutation_Class)) : (EidosValue_SP)gStaticEidosValueNULL);\n\t\t\t}\n\t\t}\n\t\telse if (returnMutation == false)\n\t\t{\n\t\t\t// We will return a logical vector, T/F for each target haplosome; parallelized\n\t\t\tEidosValue_Logical *result_logical_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_elements_size);\n\t\t\tbool null_haplosome_seen = false;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CONTAINS_MARKER_MUT);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(p_elements_size) firstprivate(p_elements, mutation_type_ptr, marker_position, last_position, result_logical_vec) reduction(||: null_haplosome_seen) if(p_elements_size >= EIDOS_OMPMIN_CONTAINS_MARKER_MUT) num_threads(thread_count)\n\t\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t\t{\n\t\t\t\tHaplosome *element = (Haplosome *)(p_elements[element_index]);\n\t\t\t\t\n\t\t\t\tif (element->IsNull())\n\t\t\t\t{\n\t\t\t\t\tnull_haplosome_seen = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tChromosome *chromosome = element->AssociatedChromosome();\n\t\t\t\tslim_position_t last_position = chromosome->last_position_;\n\t\t\t\t\n\t\t\t\tif (marker_position > last_position)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation): containsMarkerMutation() position \" << marker_position << \" is past the end of the chromosome for the haplosome.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tMutation *mut = element->mutation_with_type_and_position(mutation_type_ptr, marker_position, last_position);\n\t\t\t\t\n\t\t\t\tresult_logical_vec->set_logical_no_check(mut != nullptr, element_index);\n\t\t\t}\n\t\t\t\n\t\t\tif (!null_haplosome_seen)\n\t\t\t\treturn EidosValue_SP(result_logical_vec);\n\t\t}\n\t\telse // (returnMutation == true)\n\t\t{\n\t\t\t// We will return an object<Mutation> vector, one Mutation (or NULL) for each target haplosome; not parallelized, for now\n\t\t\tEidosValue_Object *result_obj_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->reserve(p_elements_size);\n\t\t\tbool null_haplosome_seen = false;\n\t\t\t\n\t\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t\t{\n\t\t\t\tHaplosome *element = (Haplosome *)(p_elements[element_index]);\n\t\t\t\t\n\t\t\t\tif (element->IsNull())\n\t\t\t\t{\n\t\t\t\t\tnull_haplosome_seen = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tChromosome *chromosome = element->AssociatedChromosome();\n\t\t\t\tslim_position_t last_position = chromosome->last_position_;\n\t\t\t\t\n\t\t\t\tif (marker_position > last_position)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation): containsMarkerMutation() position \" << marker_position << \" is past the end of the chromosome for the haplosome.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tMutation *mut = element->mutation_with_type_and_position(mutation_type_ptr, marker_position, last_position);\n\t\t\t\t\n\t\t\t\tif (mut)\n\t\t\t\t\tresult_obj_vec->push_object_element_RR(mut);\n\t\t\t}\n\t\t\t\n\t\t\tif (!null_haplosome_seen)\n\t\t\t\treturn EidosValue_SP(result_obj_vec);\n\t\t}\n\t\t\n\t\t// we drop through to here when a null haplosome is encountered\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation): containsMarkerMutation() cannot be called on a null haplosome.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\treturn gStaticEidosValue_Logical_ZeroVec;\n\t}\n}\n\n//\t*********************\t- (logical)containsMutations(object<Mutation> mutations)\n//\nEidosValue_SP Haplosome::ExecuteMethod_Accelerated_containsMutations(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (p_elements_size)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tSpecies *haplosomes_species = Community::SpeciesForHaplosomesVector((Haplosome **)p_elements, (int)p_elements_size);\n\t\t\n\t\tif (!haplosomes_species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\t\n\t\thaplosomes_species->population_.CheckForDeferralInHaplosomesVector((Haplosome **)p_elements, p_elements_size, \"Haplosome::ExecuteMethod_Accelerated_containsMutations\");\n\t\t\n\t\tEidosValue *mutations_value = p_arguments[0].get();\n\t\tint mutations_count = mutations_value->Count();\n\t\t\n\t\tif (mutations_count > 0)\n\t\t{\n\t\t\tSpecies *mutations_species = Community::SpeciesForMutations(mutations_value);\n\t\t\t\n\t\t\tif (mutations_species != haplosomes_species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() requires that all mutations belong to the same species as the target haplosomes.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif ((mutations_count == 1) && (p_elements_size == 1))\n\t\t{\n\t\t\t// We want to be smart enough to return gStaticEidosValue_LogicalT or gStaticEidosValue_LogicalF in the singleton/singleton case\n\t\t\tMutation *mut = (Mutation *)(mutations_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\t\tHaplosome *element = (Haplosome *)(p_elements[0]);\n\t\t\t\n\t\t\tif (element->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 11/24/2024: I've gone back and forth on whether it should be an error to ask whether a mutation\n\t\t\t// associated with chromosome A is in a haplosome associated with chromosome B.  For now I'm going to\n\t\t\t// say it is an error, and that can be relaxed later if it becomes clear that it is too strict.  It\n\t\t\t// does seem like it is a question that indicates a fundamental logic flaw, like asking whether a\n\t\t\t// mutation that belongs to species A is in a haplosome that belongs to species B.\n\t\t\tif (mut->chromosome_index_ != element->chromosome_index_)\n\t\t\t{\n\t\t\t\t//return gStaticEidosValue_LogicalF;\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() requires that all mutations are associated with the same chromosome as the target haplosomes.  (If this requirement makes life difficult, it could be relaxed if necessary; but it seems useful for catching logic errors.  Note that the containsMutations() method of Individual does not have this restriction.)\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tbool contained = element->contains_mutation(mut);\n\t\t\t\n\t\t\treturn (contained ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_elements_size * mutations_count);\n\t\t\tEidosValue_SP result(logical_result);\n\t\t\tint64_t result_index = 0;\n\t\t\t\n\t\t\tEidosObject * const *mutations_data = mutations_value->ObjectData();\n\t\t\t\n\t\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t\t{\n\t\t\t\tHaplosome *element = (Haplosome *)(p_elements[element_index]);\n\t\t\t\t\n\t\t\t\tif (element->IsNull())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tMutation *mut = (Mutation *)mutations_data[value_index];\n\t\t\t\t\t\n\t\t\t\t\t// BCH 11/24/2024: I've gone back and forth on whether it should be an error to ask whether a mutation\n\t\t\t\t\t// associated with chromosome A is in a haplosome associated with chromosome B.  For now I'm going to\n\t\t\t\t\t// say it is an error, and that can be relaxed later if it becomes clear that it is too strict.  It\n\t\t\t\t\t// does seem like it is a question that indicates a fundamental logic flaw, like asking whether a\n\t\t\t\t\t// mutation that belongs to species A is in a haplosome that belongs to species B.\n\t\t\t\t\tif (mut->chromosome_index_ != element->chromosome_index_)\n\t\t\t\t\t{\n\t\t\t\t\t\t//logical_result->set_logical_no_check(false, result_index++);\n\t\t\t\t\t\t//continue;\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_containsMutations): containsMutations() requires that all mutations are associated with the same chromosome as the target haplosomes.  (If this requirement makes life difficult, it could be relaxed if necessary; but it seems useful for catching logic errors.  Note that the containsMutations() method of Individual does not have this restriction.)\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tbool contained = element->contains_mutation(mut);\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(contained, result_index++);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t}\n\telse\n\t{\n\t\treturn gStaticEidosValue_Logical_ZeroVec;\n\t}\n}\n\n//\t*********************\t- (integer$)countOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Haplosome::ExecuteMethod_Accelerated_countOfMutationsOfType(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (p_elements_size == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForHaplosomesVector((Haplosome **)p_elements, (int)p_elements_size);\n\t\n\tif (species == nullptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_countOfMutationsOfType): countOfMutationsOfType() requires that mutType belongs to the same species as the target individual.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInHaplosomesVector((Haplosome **)p_elements, p_elements_size, \"Haplosome::ExecuteMethod_Accelerated_countOfMutationsOfType\");\n\t\n\tEidosValue *mutType_value = p_arguments[0].get();\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species->community_, species, \"countOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Count the number of mutations of the given type\n\tconst int32_t mutrun_count = ((Haplosome *)(p_elements[0]))->mutrun_count_;\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tEidosValue_Int *integer_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_elements_size);\n\tbool saw_error = false;\n\t\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE);\n#pragma omp parallel for schedule(dynamic, 1) default(none) shared(p_elements_size) firstprivate(p_elements, mut_block_ptr, mutation_type_ptr, integer_result, mutrun_count) reduction(||: saw_error) if(p_elements_size >= EIDOS_OMPMIN_G_COUNT_OF_MUTS_OF_TYPE) num_threads(thread_count)\n\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t{\n\t\tHaplosome *element = (Haplosome *)(p_elements[element_index]);\n\t\t\n\t\tif (element->IsNull())\n\t\t{\n\t\t\tsaw_error = true;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tint match_count = 0;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = element->mutruns_[run_index];\n\t\t\tint mut_count = mutrun->size();\n\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\n\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\tif ((mut_block_ptr + mut_ptr[mut_index])->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t++match_count;\n\t\t}\n\t\t\n\t\tinteger_result->set_int_no_check(match_count, element_index);\n\t}\n\t\n\tif (saw_error)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_Accelerated_countOfMutationsOfType): countOfMutationsOfType() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\n\treturn EidosValue_SP(integer_result);\n}\n\n//\t*********************\t- (object<Mutation>)mutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Haplosome::ExecuteMethod_mutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tif (IsDeferred())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_mutationsOfType): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\tif (IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_mutationsOfType): mutationsOfType() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\n\tSpecies &species = individual_->subpopulation_->species_;\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"mutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// We want to return a singleton if we can, but we also want to avoid scanning through all our mutations twice.\n\t// We do this by not creating a vector until we see the second match; with one match, we make a singleton.\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tMutation *first_match = nullptr;\n\tEidosValue_Object *vec = nullptr;\n\tEidosValue_SP result_SP;\n\tint run_index;\n\t\n\tfor (run_index = 0; run_index < mutrun_count_; ++run_index)\n\t{\n\t\tconst MutationRun *mutrun = mutruns_[run_index];\n\t\tint mut_count = mutrun->size();\n\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\n\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t{\n\t\t\tMutation *mut = (mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\n\t\t\tif (mut->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t{\n\t\t\t\tif (!vec)\n\t\t\t\t{\n\t\t\t\t\tif (!first_match)\n\t\t\t\t\t\tfirst_match = mut;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\t\t\t\tresult_SP = EidosValue_SP(vec);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvec->push_object_element_RR(first_match);\n\t\t\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t\t\t\tfirst_match = nullptr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Now return the appropriate return value\n\tif (first_match)\n\t{\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(first_match, gSLiM_Mutation_Class));\n\t}\n\telse\n\t{\n\t\tif (!vec)\n\t\t{\n\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\tresult_SP = EidosValue_SP(vec);\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t\t\n\t}\n}\n\n//\t*********************\t– (is)nucleotides([Ni$ start = NULL], [Ni$ end = NULL], [s$ format = \"string\"])\n//\nEidosValue_SP Haplosome::ExecuteMethod_nucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (IsDeferred())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\n\tSpecies *species = &individual_->subpopulation_->species_;\n\tChromosome *chromosome = AssociatedChromosome();\n\tslim_position_t last_position = chromosome->last_position_;\n\t\n\tif (!species->IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): nucleotides() may only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tNucleotideArray *sequence = chromosome->AncestralSequence();\n\tEidosValue *start_value = p_arguments[0].get();\n\tEidosValue *end_value = p_arguments[1].get();\n\t\n\tint64_t start = (start_value->Type() == EidosValueType::kValueNULL) ? 0 : start_value->IntAtIndex_NOCAST(0, nullptr);\n\tint64_t end = (end_value->Type() == EidosValueType::kValueNULL) ? last_position : end_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((start < 0) || (end < 0) || (start > last_position) || (end > last_position) || (start > end))\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): start and end must be within the chromosome's extent, and start must be <= end.\" << EidosTerminate();\n\tif (((std::size_t)start >= sequence->size()) || ((std::size_t)end >= sequence->size()))\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): (internal error) start and end must be within the ancestral sequence's length.\" << EidosTerminate();\n\t\n\tint64_t length = end - start + 1;\n\t\n\tif (length > INT_MAX)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): the returned vector would exceed the maximum vector length in Eidos.\" << EidosTerminate();\n\t\n\tEidosValue_String *format_value = (EidosValue_String *)p_arguments[2].get();\n\tconst std::string &format = format_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (format == \"codon\")\n\t{\n\t\tEidosValue_SP codon_value = sequence->NucleotidesAsCodonVector(start, end, /* p_force_vector */ true);\n\t\t\n\t\t// patch the sequence with nucleotide mutations\n\t\t// no singleton case; we force a vector return from NucleotidesAsCodonVector() for simplicity\n\t\tint64_t *int_vec = ((EidosValue_Int *)(codon_value.get()))->data_mutable();\n\t\tHaplosomeWalker walker(this);\n\t\t\n\t\twalker.MoveToPosition(start);\n\t\t\n\t\twhile (!walker.Finished())\n\t\t{\n\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\n\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\tif (pos > end)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\n\t\t\tif (nuc != -1)\n\t\t\t{\n\t\t\t\t// We have a nucleotide-based mutation within the sequence range.  We need to get the current codon value,\n\t\t\t\t// deconstruct it into nucleotides, replace the overlaid nucleotide, reconstruct the codon value, and put\n\t\t\t\t// it back into the codon vector.\n\t\t\t\tint64_t codon_index = (pos - start) / 3;\n\t\t\t\tint codon_offset = (pos - start) % 3;\n\t\t\t\tint codon = (int)int_vec[codon_index];\n\t\t\t\t\n\t\t\t\tif (codon_offset == 0)\n\t\t\t\t{\n\t\t\t\t\tcodon = codon & 0x0F;\n\t\t\t\t\tcodon |= (nuc * 16);\n\t\t\t\t}\n\t\t\t\telse if (codon_offset == 1)\n\t\t\t\t{\n\t\t\t\t\tcodon = codon & 0x33;\n\t\t\t\t\tcodon |= (nuc * 4);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcodon = codon & 0x3C;\n\t\t\t\t\tcodon |= nuc;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_vec[codon_index] = codon;\n\t\t\t}\n\t\t\t\n\t\t\twalker.NextMutation();\n\t\t}\n\t\t\n\t\treturn codon_value;\n\t}\n\telse if (format == \"string\")\n\t{\n\t\tEidosValue_SP string_value = sequence->NucleotidesAsStringSingleton(start, end);\n\t\t\n\t\t// patch the sequence with nucleotide mutations\n\t\tif (start == end)\n\t\t{\n\t\t\t// singleton case: replace string_value entirely\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t{\n\t\t\t\t\tif (nuc == 0)\t\t\tstring_value = gStaticEidosValue_StringA;\n\t\t\t\t\telse if (nuc == 1)\t\tstring_value = gStaticEidosValue_StringC;\n\t\t\t\t\telse if (nuc == 2)\t\tstring_value = gStaticEidosValue_StringG;\n\t\t\t\t\telse /* (nuc == 3) */\tstring_value = gStaticEidosValue_StringT;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// vector case: replace the appropriate character in string_value\n\t\t\tstd::string &string_string = ((EidosValue_String *)(string_value.get()))->StringData_Mutable()[0];\n\t\t\tchar *string_ptr = &string_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t\tstring_ptr[pos - start] = gSLiM_Nucleotides[nuc];\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn string_value;\n\t}\n\telse if (format == \"integer\")\n\t{\n\t\tEidosValue_SP integer_value = sequence->NucleotidesAsIntegerVector(start, end);\n\t\t\n\t\t// patch the sequence with nucleotide mutations\n\t\tif (start == end)\n\t\t{\n\t\t\t// singleton case: replace integer_value entirely\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t{\n\t\t\t\t\tif (nuc == 0)\t\t\tinteger_value = gStaticEidosValue_Integer0;\n\t\t\t\t\telse if (nuc == 1)\t\tinteger_value = gStaticEidosValue_Integer1;\n\t\t\t\t\telse if (nuc == 2)\t\tinteger_value = gStaticEidosValue_Integer2;\n\t\t\t\t\telse /* (nuc == 3) */\tinteger_value = gStaticEidosValue_Integer3;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// vector case: replace the appropriate element in integer_value\n\t\t\tint64_t *int_vec = ((EidosValue_Int *)(integer_value.get()))->data_mutable();\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t\tint_vec[pos-start] = (int)nuc;\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn integer_value;\n\t}\n\telse if (format == \"char\")\n\t{\n\t\tEidosValue_SP char_value = sequence->NucleotidesAsStringVector(start, end);\n\t\t\n\t\t// patch the sequence with nucleotide mutations\n\t\tif (start == end)\n\t\t{\n\t\t\t// singleton case: replace char_value entirely\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t{\n\t\t\t\t\tif (nuc == 0)\t\t\tchar_value = gStaticEidosValue_StringA;\n\t\t\t\t\telse if (nuc == 1)\t\tchar_value = gStaticEidosValue_StringC;\n\t\t\t\t\telse if (nuc == 2)\t\tchar_value = gStaticEidosValue_StringG;\n\t\t\t\t\telse /* (nuc == 3) */\tchar_value = gStaticEidosValue_StringT;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// vector case: replace the appropriate element in char_value\n\t\t\tstd::string *char_vec = char_value->StringData_Mutable();\n\t\t\tHaplosomeWalker walker(this);\n\t\t\t\n\t\t\twalker.MoveToPosition(start);\n\t\t\t\n\t\t\twhile (!walker.Finished())\n\t\t\t{\n\t\t\t\tMutation *mut = walker.CurrentMutation();\n\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// pos >= start is guaranteed by MoveToPosition()\n\t\t\t\tif (pos > end)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint8_t nuc = mut->nucleotide_;\n\t\t\t\t\n\t\t\t\tif (nuc != -1)\n\t\t\t\t\tchar_vec[pos - start] = gSLiM_Nucleotides[nuc];\n\t\t\t\t\n\t\t\t\twalker.NextMutation();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn char_value;\n\t}\n\t\n\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_nucleotides): parameter format must be either 'string', 'char', 'integer', or 'codon'.\" << EidosTerminate();\n}\n\n//\t*********************\t- (integer)positionsOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Haplosome::ExecuteMethod_positionsOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tif (IsDeferred())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_positionsOfMutationsOfType): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\tif (IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_positionsOfMutationsOfType): positionsOfMutationsOfType() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\n\tSpecies &species = individual_->subpopulation_->species_;\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"positionsOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Return the positions of mutations of the given type\n\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t{\n\t\tconst MutationRun *mutrun = mutruns_[run_index];\n\t\tint mut_count = mutrun->size();\n\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\n\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t{\n\t\t\tMutation *mutation = mut_block_ptr + mut_ptr[mut_index];\n\t\t\t\n\t\t\tif (mutation->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\tint_result->push_int(mutation->position_);\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(int_result);\n}\n\n//\t*********************\t- (integer$)sumOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Haplosome::ExecuteMethod_sumOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tif (IsDeferred())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_sumOfMutationsOfType): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\tif (IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::ExecuteMethod_sumOfMutationsOfType): sumOfMutationsOfType() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\n\tSpecies &species = individual_->subpopulation_->species_;\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"sumOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Sum the selection coefficients of mutations of the given type\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tdouble selcoeff_sum = 0.0;\n\tint mutrun_count = mutrun_count_;\n\t\n\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t{\n\t\tconst MutationRun *mutrun = mutruns_[run_index];\n\t\tint haplosome1_count = mutrun->size();\n\t\tconst MutationIndex *haplosome_ptr = mutrun->begin_pointer_const();\n\t\t\n\t\tfor (int mut_index = 0; mut_index < haplosome1_count; ++mut_index)\n\t\t{\n\t\t\tMutation *mut_ptr = mut_block_ptr + haplosome_ptr[mut_index];\n\t\t\t\n\t\t\tif (mut_ptr->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\tselcoeff_sum += mut_ptr->selection_coeff_;\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(selcoeff_sum));\n}\n\n// print the sample represented by haplosomes, using SLiM's own format\nvoid Haplosome::PrintHaplosomes_SLiM(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, bool p_output_object_tags)\n{\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tslim_popsize_t sample_size = (slim_popsize_t)p_haplosomes.size();\n\t\n\t// get the polymorphisms within the sample\n\tPolymorphismMap polymorphisms;\n\t\n\tfor (slim_popsize_t s = 0; s < sample_size; s++)\n\t{\n\t\tHaplosome &haplosome = *p_haplosomes[s];\n\t\t\n\t\tif (haplosome.IsNull())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_SLiM): cannot output null haplosomes.\" << EidosTerminate();\n\t\t\n\t\tfor (int run_index = 0; run_index < haplosome.mutrun_count_; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\tint mut_count = mutrun->size();\n\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\n\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t}\n\t}\n\t\n\t// print the sample's polymorphisms; NOTE the output format changed due to the addition of mutation_id_, BCH 11 June 2016\n\t// NOTE the output format changed due to the addition of the nucleotide, BCH 2 March 2019\n\tp_out << \"Mutations:\"  << std::endl;\n\t\n\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms)\n\t{\n\t\tif (p_output_object_tags)\n\t\t\tpolymorphism_pair.second.Print_ID_Tag(p_out);\n\t\telse\n\t\t\tpolymorphism_pair.second.Print_ID(p_out);\n\t}\n\t\n\t// print the sample's haplosomes\n\tp_out << \"Haplosomes:\" << std::endl;\n\t\n\tfor (slim_popsize_t j = 0; j < sample_size; j++)\t\t\t\t\t\t\t\t\t\t\t\t\t\t// go through all haplosomes\n\t{\n\t\tHaplosome &haplosome = *p_haplosomes[j];\n\t\tIndividual *individual = haplosome.individual_;\n\t\t\n\t\tif (!individual)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_SLiM): (internal error) missing individual for haplosome.\" << EidosTerminate();\n\t\t\n\t\tslim_popsize_t index = individual->index_;\n\t\t\n\t\tif (index == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_SLiM): haplosomes being output must be visible in a subpopulation (i.e., may not belong to new juveniles).\" << EidosTerminate();\n\t\t\n\t\tSubpopulation *subpop = individual->subpopulation_;\n\t\t\n\t\tif (!subpop)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_SLiM): (internal error) missing subpopulation for individual.\" << EidosTerminate();\n\t\t\n\t\t// BCH 2/9/2025: For SLiM 5, we now print the subpopulation id and the\n\t\t// individual index for the haplosome, telling the user where each\n\t\t// haplosome came from; probably not useful, but more useful than before\n\t\tp_out << 'p' << subpop->subpopulation_id_ << \":i\" << index;\n\t\t\n\t\tif (p_output_object_tags)\n\t\t{\n\t\t\tif (haplosome.tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tp_out << \" ?\";\n\t\t\telse\n\t\t\t\tp_out << ' ' << haplosome.tag_value_;\n\t\t}\n\t\t\n\t\tfor (int run_index = 0; run_index < haplosome.mutrun_count_; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\tint mut_count = mutrun->size();\n\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\n\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t{\n\t\t\t\tslim_polymorphismid_t polymorphism_id = FindMutationInPolymorphismMap(polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t\n\t\t\t\tif (polymorphism_id == -1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_SLiM): (internal error) polymorphism not found.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tp_out << \" \" << polymorphism_id;\n\t\t\t}\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t}\n}\n\n// print the sample represented by haplosomes, using \"ms\" format\nvoid Haplosome::PrintHaplosomes_MS(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, const Chromosome &p_chromosome, bool p_filter_monomorphic)\n{\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tslim_popsize_t sample_size = (slim_popsize_t)p_haplosomes.size();\n\t\n\t// BCH 7 Nov. 2016: sort the polymorphisms by position since that is the expected sort\n\t// order in MS output.  In other types of output, sorting by the mutation id seems to\n\t// be fine.\n\tstd::vector<Polymorphism> sorted_polymorphisms;\n\t\n\t{\n\t\t// get the polymorphisms within the sample\n\t\tPolymorphismMap polymorphisms;\n\t\t\n\t\tfor (slim_popsize_t s = 0; s < sample_size; s++)\n\t\t{\n\t\t\tHaplosome &haplosome = *p_haplosomes[s];\n\t\t\t\n\t\t\tif (haplosome.IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_MS): cannot output null haplosomes.\" << EidosTerminate();\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < haplosome.mutrun_count_; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\n\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms)\n\t\t\tsorted_polymorphisms.emplace_back(polymorphism_pair.second);\n\t\t\n\t\tstd::sort(sorted_polymorphisms.begin(), sorted_polymorphisms.end());\n\t}\n\t\n\t// if requested, remove polymorphisms that are not polymorphic within the sample\n\tif (p_filter_monomorphic)\n\t{\n\t\tstd::vector<Polymorphism> filtered_polymorphisms;\n\t\t\n\t\tfor (Polymorphism &p : sorted_polymorphisms)\n\t\t\tif (p.prevalence_ != sample_size)\n\t\t\t\tfiltered_polymorphisms.emplace_back(p);\n\t\t\n\t\tstd::swap(sorted_polymorphisms, filtered_polymorphisms);\n\t}\n\t\n\t// make a hash table that looks up the genotype string position from a mutation pointer\n#if EIDOS_ROBIN_HOOD_HASHING\n\trobin_hood::unordered_flat_map<const Mutation*, int> genotype_string_positions;\n\t//typedef robin_hood::pair<const Mutation*, int> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\tstd::unordered_map<const Mutation*, int> genotype_string_positions;\n\t//typedef std::pair<const Mutation*, int> MAP_PAIR;\n#endif\n\tint genotype_string_position = 0;\n\t\n\ttry {\n\t\tfor (const Polymorphism &polymorphism : sorted_polymorphisms) \n\t\t\tgenotype_string_positions.emplace(polymorphism.mutation_ptr_, genotype_string_position++);\n\t} catch (...) {\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_MS): (internal error) SLiM encountered a raise from an internal hash table; please report this.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// print header\n\tp_out << \"//\" << std::endl << \"segsites: \" << sorted_polymorphisms.size() << std::endl;\n\t\n\t// print the sample's positions\n\tif (sorted_polymorphisms.size() > 0)\n\t{\n\t\t// Save flags/precision\n\t\tstd::ios_base::fmtflags oldflags = p_out.flags();\n\t\tstd::streamsize oldprecision = p_out.precision();\n\t\t\n\t\tp_out << std::fixed << std::setprecision(15);\t// BCH 26 Jan. 2020: increasing this from 7 to 10, so longer chromosomes work; maybe this should be a parameter?\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// BCH 23 July 2020: increasing from 10 to 15, which is the limit of double-precision floats anyway\n\t\t\n\t\t// Output positions\n\t\tp_out << \"positions:\";\n\t\t\n\t\tfor (const Polymorphism &polymorphism : sorted_polymorphisms) \n\t\t\tp_out << \" \" << static_cast<double>(polymorphism.mutation_ptr_->position_) / p_chromosome.last_position_;\t// this prints positions as being in the interval [0,1], which Philipp decided was the best policy\n\t\t\n\t\tp_out << std::endl;\n\t\t\n\t\t// Restore flags/precision\n\t\tp_out.flags(oldflags);\n\t\tp_out.precision(oldprecision);\n\t}\n\t\n\t// print the sample's genotypes\n\tfor (slim_popsize_t j = 0; j < sample_size; j++)\t\t\t\t\t\t\t\t\t\t\t\t\t\t// go through all individuals\n\t{\n\t\tHaplosome &haplosome = *p_haplosomes[j];\n\t\tstd::string genotype(sorted_polymorphisms.size(), '0'); // fill with 0s\n\t\t\n\t\tfor (int run_index = 0; run_index < haplosome.mutrun_count_; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\tint mut_count = mutrun->size();\n\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\n\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t{\n\t\t\t\tconst Mutation *mutation = mut_block_ptr + mut_ptr[mut_index];\n\t\t\t\tauto found_position = genotype_string_positions.find(mutation);\n\t\t\t\t\n\t\t\t\t// BCH 4/24/2019: when p_filter_monomorphic is true, mutations in a given haplosome may not exist in the position map\n\t\t\t\tif (found_position != genotype_string_positions.end())\n\t\t\t\t\tgenotype.replace(found_position->second, 1, \"1\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tp_out << genotype << std::endl;\n\t}\n}\n\ninline void EmitHaplosomeCall_Nuc_Simplify(std::ostream &p_out, const Haplosome &haplosome, std::vector<Polymorphism *> &nuc_based, slim_position_t mut_position, int *allele_index_for_nuc)\n{\n\t// Find and emit the nuc-based mut contained by this haplosome, if any.  If more than one nuc-based mut is contained, it is an error.\n\tint contained_mut_index = -1;\n\t\n\tfor (int muts_index = 0; muts_index < (int)nuc_based.size(); ++muts_index)\n\t{\n\t\tconst Mutation *mutation = nuc_based[muts_index]->mutation_ptr_;\n\t\t\n\t\tif (haplosome.contains_mutation(mutation))\n\t\t{\n\t\t\tif (contained_mut_index == -1)\n\t\t\t\tcontained_mut_index = muts_index;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EmitHaplosomeCall_Nuc): more than one nucleotide-based mutation encountered at the same position (\" << mut_position << \") in the same haplosome; the nucleotide cannot be called.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tif (contained_mut_index == -1)\n\t\tp_out << '0';\n\telse\n\t\tp_out << allele_index_for_nuc[nuc_based[contained_mut_index]->mutation_ptr_->nucleotide_];\n}\n\ninline void EmitHaplosomeCall_Nuc(std::ostream &p_out, const Haplosome &haplosome, std::vector<Polymorphism *> &nuc_based, slim_position_t mut_position)\n{\n\t// Find and emit the nuc-based mut contained by this haplosome, if any.  If more than one nuc-based mut is contained, it is an error.\n\tint contained_mut_index = -1;\n\t\n\tfor (int muts_index = 0; muts_index < (int)nuc_based.size(); ++muts_index)\n\t{\n\t\tconst Mutation *mutation = nuc_based[muts_index]->mutation_ptr_;\n\t\t\n\t\tif (haplosome.contains_mutation(mutation))\n\t\t{\n\t\t\tif (contained_mut_index == -1)\n\t\t\t\tcontained_mut_index = muts_index;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EmitHaplosomeCall_Nuc): more than one nucleotide-based mutation encountered at the same position (\" << mut_position << \") in the same haplosome; the nucleotide cannot be called.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tif (contained_mut_index == -1)\n\t\tp_out << '0';\n\telse\n\t\tp_out << (contained_mut_index + 1);\n}\n\n// print the sample represented by haplosomes, using \"vcf\" format\n// the haplosomes will all belong to a single chromosome, p_chromosome, and may include null haplosomes\n// depending on the intrinsic ploidy of p_chromosome the calls will be diploid or haploid; if diploid,\n// calls where one of a pair of haplosomes is null will be emitted as a haploid call; if all haplosomes\n// for a given individual are null, the call emitted will be \"~\".\nvoid Haplosome::PrintHaplosomes_VCF(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, const Chromosome &p_chromosome, bool p_groupAsIndividuals, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs)\n{\n\tSpecies &species = p_chromosome.species_;\n\tbool nucleotide_based = species.IsNucleotideBased();\n\tbool pedigrees_enabled = species.PedigreesEnabledByUser();\n\tslim_popsize_t haplosome_count = (slim_popsize_t)p_haplosomes.size();\n\tslim_popsize_t individual_count;\n\t\n\t// get information about the chromosome we're writing, which determines whether an \"individual\" in the VCF is one haplosome or two\n\tChromosomeType chromosome_type = p_chromosome.Type();\n\tint intrinsic_ploidy = p_chromosome.IntrinsicPloidy();\n\t\n\tif (!p_groupAsIndividuals)\n\t\tintrinsic_ploidy = 1;\t// if groupAsIndividuals is false, we just act as though the chromosome is haploid\n\t\n\tif (intrinsic_ploidy == 2)\n\t{\n\t\tif (haplosome_count % 2 == 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::PrintHaplosomes_VCF): Haplosome vector must be an even length for chromosome type \\\"\" << chromosome_type << \"\\\", since haplosomes are paired into individuals.\" << EidosTerminate();\n\t\t\n\t\tindividual_count = haplosome_count / 2;\n\t}\n\telse\n\t{\n\t\tindividual_count = haplosome_count;\n\t}\n\t\n\t// print the VCF header\n\tp_out << \"##fileformat=VCFv4.2\" << std::endl;\n\t\n\t{\n\t\ttime_t rawtime;\n\t\tstruct tm timeinfo;\n\t\tchar buffer[25];\t// should never be more than 10, in fact, plus a null\n\t\t\n\t\ttime(&rawtime);\n\t\tlocaltime_r(&rawtime, &timeinfo);\n\t\tstrftime(buffer, 25, \"%Y%m%d\", &timeinfo);\n\t\t\n\t\tp_out << \"##fileDate=\" << std::string(buffer) << std::endl;\n\t}\n\t\n\tp_out << \"##source=SLiM\" << std::endl;\n\t\n\t// BCH 10 July 2019: output haplosome pedigree IDs, if available, for all of the haplosomes being output.\n\t// It would be nice to be able to output individual pedigree IDs, but since we are working with a\n\t// vector of haplosomes there is no guarantee that the pairs of haplosomes here come from the same individuals.\n\tif (pedigrees_enabled && (haplosome_count > 0))\n\t{\n\t\tp_out << \"##slimHaplosomePedigreeIDs=\";\n\t\t\n\t\tfor (slim_popsize_t haplosome_index = 0; haplosome_index < haplosome_count; haplosome_index++)\n\t\t{\n\t\t\tif (haplosome_index > 0)\n\t\t\t\tp_out << \",\";\n\t\t\tp_out << p_haplosomes[haplosome_index]->haplosome_id_;\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t}\n\t\n\t// BCH 6 March 2019: Note that all of the INFO fields that provide per-mutation information have been\n\t// changed from a Number of 1 to a Number of ., since in nucleotide-based models we can call more than\n\t// one allele in a single call line (unlike in non-nucleotide-based models).\n\tp_out << \"##INFO=<ID=MID,Number=.,Type=Integer,Description=\\\"Mutation ID in SLiM\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=S,Number=.,Type=Float,Description=\\\"Selection Coefficient\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=DOM,Number=.,Type=Float,Description=\\\"Dominance\\\">\" << std::endl;\n\t// Note that at present we do not output the hemizygous dominance coefficient; too edge\n\tp_out << \"##INFO=<ID=PO,Number=.,Type=Integer,Description=\\\"Population of Origin\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=TO,Number=.,Type=Integer,Description=\\\"Tick of Origin\\\">\" << std::endl;\t\t\t// changed to ticks for 4.0, and changed \"GO\" to \"TO\"\n\tp_out << \"##INFO=<ID=MT,Number=.,Type=Integer,Description=\\\"Mutation Type\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=AC,Number=.,Type=Integer,Description=\\\"Allele Count\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=DP,Number=1,Type=Integer,Description=\\\"Total Depth\\\">\" << std::endl;\n\tif (p_output_multiallelics && !nucleotide_based)\n\t\tp_out << \"##INFO=<ID=MULTIALLELIC,Number=0,Type=Flag,Description=\\\"Multiallelic\\\">\" << std::endl;\n\tif (nucleotide_based)\n\t\tp_out << \"##INFO=<ID=AA,Number=1,Type=String,Description=\\\"Ancestral Allele\\\">\" << std::endl;\n\tif (p_output_nonnucs && nucleotide_based)\n\t\tp_out << \"##INFO=<ID=NONNUC,Number=0,Type=Flag,Description=\\\"Non-nucleotide-based\\\">\" << std::endl;\n\tp_out << \"##FORMAT=<ID=GT,Number=1,Type=String,Description=\\\"Genotype\\\">\" << std::endl;\n\tp_out << \"##contig=<ID=1,URL=https://github.com/MesserLab/SLiM>\" << std::endl;\n\tp_out << \"#CHROM\\tPOS\\tID\\tREF\\tALT\\tQUAL\\tFILTER\\tINFO\\tFORMAT\";\n\t\n\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\tp_out << \"\\ti\" << individual_index;\n\tp_out << std::endl;\n\t\n\tHaplosome::_PrintVCF(p_out, (const Haplosome **)p_haplosomes.data(), haplosome_count, p_chromosome, p_groupAsIndividuals, p_simplify_nucs, p_output_nonnucs, p_output_multiallelics);\n}\n\nvoid Haplosome::_PrintVCF(std::ostream &p_out, const Haplosome **p_haplosomes, int64_t p_haplosomes_count, const Chromosome &p_chromosome, bool p_groupAsIndividuals, bool p_simplify_nucs, bool p_output_nonnucs, bool p_output_multiallelics)\n{\n\tChromosomeType chromosome_type = p_chromosome.Type();\n\tint intrinsic_ploidy = p_chromosome.IntrinsicPloidy();\n\tSpecies &species = p_chromosome.species_;\n\tbool nucleotide_based = species.IsNucleotideBased();\n\tNucleotideArray *ancestral_seq = p_chromosome.AncestralSequence();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint64_t individual_count;\n\t\n\t// if groupAsIndividuals is false, we just act as though the chromosome is haploid\n\t// this option is not available for Individual::PrintIndividuals_VCF() since it doesn't\n\t// make sense for individual-based output, only single-chromosome haplosome-based output\n\tif (!p_groupAsIndividuals)\n\t\tintrinsic_ploidy = 1;\n\t\n\tif (intrinsic_ploidy == 2)\n\t{\n\t\tif (p_haplosomes_count % 2 == 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::_PrintVCF): Haplosome vector must be an even length for chromosome type \\\"\" << chromosome_type << \"\\\", since haplosomes are paired into individuals.\" << EidosTerminate();\n\t\t\n\t\tindividual_count = p_haplosomes_count / 2;\n\t}\n\telse\n\t{\n\t\tindividual_count = p_haplosomes_count;\n\t}\n\t\n\t// get the polymorphisms within the sample\n\tPolymorphismMap polymorphisms;\n\t\n\tfor (slim_popsize_t haplosome_index = 0; haplosome_index < p_haplosomes_count; haplosome_index++)\n\t{\n\t\tconst Haplosome &haplosome = *p_haplosomes[haplosome_index];\n\t\t\n\t\tif (!haplosome.IsNull())\n\t\t{\n\t\t\tfor (int run_index = 0; run_index < haplosome.mutrun_count_; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = haplosome.mutruns_[run_index];\n\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\n\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// We want to output polymorphisms sorted by position (starting in SLiM 3.3), to facilitate\n\t// calling all of the nucleotide mutations at a given position with a single call line.\n\tstd::vector<Polymorphism> sorted_polymorphisms;\n\t\n\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms)\n\t\tsorted_polymorphisms.emplace_back(polymorphism_pair.second);\n\t\n\tstd::sort(sorted_polymorphisms.begin(), sorted_polymorphisms.end());\n\t\n\t// Print a line for each mutation.  Note that we do NOT treat multiple mutations at the same position at being different alleles,\n\t// output on the same line.  This is because a single individual can carry more than one mutation at the same position, so it is\n\t// not really a question of different alleles; if there are N mutations at a given position, there are 2^N possible \"alleles\",\n\t// which is just silly to try to wedge into VCF format.  So instead, we output each mutation as a separate line, and we tag lines\n\t// for positions that carry more than one mutation with the MULTIALLELIC flag so they can be filtered out if they bother the user.\n\t// BCH 6 March 2019: The above comment remains true in non-nucleotide-based models.  In nucleotide-based models, the nucleotide-\n\t// based mutations at a given position are all output as a single call line, and then any non-nucleotide-based mutations are\n\t// emitted as separated call lines after that that are marked NONNUC (unless p_output_nonnucs is false, in which case they are\n\t// simply suppressed).\n\tfor (auto polyiter = sorted_polymorphisms.begin(); polyiter != sorted_polymorphisms.end(); )\n\t{\n\t\t// Assemble vectors of all the nuc-based and non-nuc-based mutations at this position; we will emit them all at once\n\t\tstd::vector<Polymorphism *> nuc_based, nonnuc_based;\n\t\tslim_position_t mut_position = polyiter->mutation_ptr_->position_;\n\t\t\n\t\twhile (true)\n\t\t{\n\t\t\t// Eat polymorphism entries in sorted_polymorphisms as long as they're at the same position, until the end\n\t\t\tPolymorphism &polymorphism = *polyiter;\n\t\t\tconst Mutation *mutation = polyiter->mutation_ptr_;\n\t\t\t\n\t\t\tif (mutation->position_ == mut_position)\n\t\t\t{\n\t\t\t\tif (mutation->mutation_type_ptr_->nucleotide_based_)\n\t\t\t\t\tnuc_based.emplace_back(&polymorphism);\n\t\t\t\telse\n\t\t\t\t\tnonnuc_based.emplace_back(&polymorphism);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// Next polymorphism\n\t\t\tpolyiter++;\n\t\t\tif (polyiter == sorted_polymorphisms.end())\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Emit the nucleotide-based mutations at this position as a single call line\n\t\tif (nucleotide_based && (nuc_based.size() > 0))\n\t\t{\n\t\t\t// Get the ancestral nucleotide at this position; this will be index 0\n\t\t\t// Indices 1..n will be used for the corresponding mutations in nonnuc_based\n\t\t\t// Note that this means it is \n\t\t\tint ancestral_nuc_index = ancestral_seq->NucleotideAtIndex(mut_position);\t\t// 0..3 for ACGT\n\t\t\t\n\t\t\t// Emit a single call line for all of the nucleotide-based mutations\n\t\t\t\n\t\t\tif (p_simplify_nucs)\n\t\t\t{\n\t\t\t\t// We are requested to simplify the nucleotide state; any mutations with the ancestral nucleotide will be considered part of the\n\t\t\t\t// ancestral state, and any mutations with matching nucleotide will be lumped together; SLiM state will not be emitted\n\t\t\t\t// We tally up the total prevalence of each nucleotide, ignoring the ancestral nucleotide.\n\t\t\t\tslim_refcount_t total_prevalence[4] = {0, 0, 0, 0};\n\t\t\t\tint allele_index_for_nuc[4] = {-1, -1 -1, -1};\n\t\t\t\t\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tint derived_nuc_index = (unsigned char)polymorphism->mutation_ptr_->nucleotide_;\n\t\t\t\t\t\n\t\t\t\t\tif (derived_nuc_index != ancestral_nuc_index)\n\t\t\t\t\t\ttotal_prevalence[derived_nuc_index] += polymorphism->prevalence_;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Assign genotype call indexes for the four nucleotides, based upon which ones have prevalence > 0\n\t\t\t\tallele_index_for_nuc[ancestral_nuc_index] = 0;\t// emit 0 for any mutations with a back-mutation\n\t\t\t\t\n\t\t\t\tint next_allele_index = 1;\t// 0 is ancestral\n\t\t\t\tfor (int nuc_index = 0; nuc_index < 4; ++nuc_index)\n\t\t\t\t{\n\t\t\t\t\tif (total_prevalence[nuc_index] > 0)\n\t\t\t\t\t\tallele_index_for_nuc[nuc_index] = next_allele_index++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If the only segregating alleles are back-mutations, we don't need to emit this call line at all\n\t\t\t\tif (total_prevalence[0] + total_prevalence[1] + total_prevalence[2] + total_prevalence[3] != 0)\n\t\t\t\t{\n\t\t\t\t\t// emit CHROM (\"1\"), POS, ID (\".\")\n\t\t\t\t\t// BCH 2/3/2025: we now emit the chromosome's symbol in the CHROM field, introducing a minor\n\t\t\t\t\t// backward compatibility break; it used to be \"1\" by default, now it is \"A\" by default, but\n\t\t\t\t\t// this is easy to fix by calling initializeChromosome() explicitly and supplying symbol=\"1\"\n\t\t\t\t\tp_out << p_chromosome.Symbol() << \"\\t\" << (mut_position + 1) << \"\\t.\\t\";\t\t\t// +1 because VCF uses 1-based positions\n\t\t\t\t\t\n\t\t\t\t\t// emit REF (\"A\" etc.)\n\t\t\t\t\tp_out << gSLiM_Nucleotides[ancestral_nuc_index];\n\t\t\t\t\tp_out << \"\\t\";\n\t\t\t\t\t\n\t\t\t\t\t// emit ALT (\"T\" etc.)\n\t\t\t\t\tbool firstEmitted = true;\n\t\t\t\t\tfor (int nuc_index=0; nuc_index < 4; ++nuc_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (total_prevalence[nuc_index] > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!firstEmitted)\n\t\t\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\t\t\tfirstEmitted = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tp_out << gSLiM_Nucleotides[nuc_index];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// emit QUAL (1000), FILTER (PASS)\n\t\t\t\t\tp_out << \"\\t1000\\tPASS\\t\";\n\t\t\t\t\t\n\t\t\t\t\t// emit the INFO fields and the Genotype marker; note mutation-specific fields are omitted since we are aggregating\n\t\t\t\t\tp_out << \"AC=\";\n\t\t\t\t\tfirstEmitted = true;\n\t\t\t\t\tfor (int nuc_prevalence : total_prevalence)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nuc_prevalence > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!firstEmitted)\n\t\t\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\t\t\tfirstEmitted = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tp_out << nuc_prevalence;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tp_out << \";DP=1000;\";\n\t\t\t\t\tp_out << \"AA=\" << gSLiM_Nucleotides[ancestral_nuc_index];\n\t\t\t\t\t\n\t\t\t\t\tp_out << \"\\tGT\";\n\t\t\t\t\t\n\t\t\t\t\t// emit the individual calls\n\t\t\t\t\tif (intrinsic_ploidy == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// intrinsically haploid chromosome; one haplosome per individual\n\t\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst Haplosome &haplosome = *p_haplosomes[individual_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// BCH 2/4/2025: If the haplosome is null, we now emit a \"~\" character\n\t\t\t\t\t\t\tif (haplosome.IsNull()) {\n\t\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haploid call\n\t\t\t\t\t\t\tp_out << '\\t';\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEmitHaplosomeCall_Nuc_Simplify(p_out, haplosome, nuc_based, mut_position, allele_index_for_nuc);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// intrinsically diploid chromosome; two haplosomes per individual\n\t\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst Haplosome &haplosome1 = *p_haplosomes[(size_t)individual_index * 2];\n\t\t\t\t\t\t\tconst Haplosome &haplosome2 = *p_haplosomes[(size_t)individual_index * 2 + 1];\n\t\t\t\t\t\t\tbool haplosome1_null = haplosome1.IsNull(), haplosome2_null = haplosome2.IsNull();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// BCH 2/4/2025: If both haplosomes are null, we now emit a \"~\" character\n\t\t\t\t\t\t\tif (haplosome1_null && haplosome2_null) {\n\t\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// diploid call unless hemizygous, producing a haploid call (and losing which haplosome was null)\n\t\t\t\t\t\t\tp_out << '\\t';\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!haplosome1_null)\n\t\t\t\t\t\t\t\tEmitHaplosomeCall_Nuc_Simplify(p_out, haplosome1, nuc_based, mut_position, allele_index_for_nuc);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!haplosome1_null && !haplosome2_null)\t// emit a separator for a diploid call\n\t\t\t\t\t\t\t\tp_out << '|';\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!haplosome2_null)\n\t\t\t\t\t\t\t\tEmitHaplosomeCall_Nuc_Simplify(p_out, haplosome2, nuc_based, mut_position, allele_index_for_nuc);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tp_out << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// emit CHROM (\"1\"), POS, ID (\".\")\n\t\t\t\t// BCH 2/3/2025: we now emit the chromosome's symbol in the CHROM field, introducing a minor\n\t\t\t\t// backward compatibility break; it used to be \"1\" by default, now it is \"A\" by default, but\n\t\t\t\t// this is easy to fix by calling initializeChromosome() explicitly and supplying symbol=\"1\"\n\t\t\t\tp_out << p_chromosome.Symbol() << \"\\t\" << (mut_position + 1) << \"\\t.\\t\";\t\t\t// +1 because VCF uses 1-based positions\n\t\t\t\t\n\t\t\t\t// emit REF (\"A\" etc.)\n\t\t\t\tp_out << gSLiM_Nucleotides[ancestral_nuc_index];\n\t\t\t\tp_out << \"\\t\";\n\t\t\t\t\n\t\t\t\t// emit ALT (\"T\" etc.)\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << gSLiM_Nucleotides[polymorphism->mutation_ptr_->nucleotide_];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// emit QUAL (1000), FILTER (PASS)\n\t\t\t\tp_out << \"\\t1000\\tPASS\\t\";\n\t\t\t\t\n\t\t\t\t// emit the INFO fields and the Genotype marker\n\t\t\t\tp_out << \"MID=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->mutation_id_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"S=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->selection_coeff_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"DOM=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->mutation_type_ptr_->dominance_coeff_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"PO=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->subpop_index_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"TO=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->origin_tick_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"MT=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->mutation_ptr_->mutation_type_ptr_->mutation_type_id_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"AC=\";\n\t\t\t\tfor (Polymorphism *polymorphism : nuc_based)\n\t\t\t\t{\n\t\t\t\t\tif (polymorphism != nuc_based.front())\n\t\t\t\t\t\tp_out << ',';\n\t\t\t\t\tp_out << polymorphism->prevalence_;\n\t\t\t\t}\n\t\t\t\tp_out << \";\";\n\t\t\t\t\n\t\t\t\tp_out << \"DP=1000;\";\n\t\t\t\t\n\t\t\t\tp_out << \"AA=\" << gSLiM_Nucleotides[ancestral_nuc_index];\n\t\t\t\t\n\t\t\t\tp_out << \"\\tGT\";\n\t\t\t\t\n\t\t\t\t// emit the individual calls\n\t\t\t\tif (intrinsic_ploidy == 1)\n\t\t\t\t{\n\t\t\t\t\t// intrinsically haploid chromosome; one haplosome per individual\n\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Haplosome &haplosome = *p_haplosomes[individual_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\t// BCH 2/4/2025: If the haplosome is null, we now emit a \"~\" character\n\t\t\t\t\t\tif (haplosome.IsNull()) {\n\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haploid call\n\t\t\t\t\t\tp_out << '\\t';\n\t\t\t\t\t\t\n\t\t\t\t\t\tEmitHaplosomeCall_Nuc(p_out, haplosome, nuc_based, mut_position);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// intrinsically diploid chromosome; two haplosomes per individual\n\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst Haplosome &haplosome1 = *p_haplosomes[(size_t)individual_index * 2];\n\t\t\t\t\t\tconst Haplosome &haplosome2 = *p_haplosomes[(size_t)individual_index * 2 + 1];\n\t\t\t\t\t\tbool haplosome1_null = haplosome1.IsNull(), haplosome2_null = haplosome2.IsNull();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// BCH 2/4/2025: If both haplosomes are null, we now emit a \"~\" character\n\t\t\t\t\t\tif (haplosome1_null && haplosome2_null) {\n\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// diploid call unless hemizygous, producing a haploid call (and losing which haplosome was null)\n\t\t\t\t\t\tp_out << '\\t';\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome1.IsNull())\n\t\t\t\t\t\t\tEmitHaplosomeCall_Nuc(p_out, haplosome1, nuc_based, mut_position);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome1_null && !haplosome2_null)\t// emit a separator for a diploid call\n\t\t\t\t\t\t\tp_out << '|';\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome2.IsNull())\n\t\t\t\t\t\t\tEmitHaplosomeCall_Nuc(p_out, haplosome2, nuc_based, mut_position);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tp_out << std::endl;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Emit the non-nucleotide-based mutations at this position as individual call lines, each as an A->T mutation\n\t\t// We do this if outputNonnucleotides==T, or if we are non-nucleotide-based (in which case outputNonnucleotides is ignored)\n\t\tif (p_output_nonnucs || !nucleotide_based)\n\t\t{\n\t\t\tfor (Polymorphism *polymorphism : nonnuc_based)\n\t\t\t{\n\t\t\t\tconst Mutation *mutation = polymorphism->mutation_ptr_;\n\t\t\t\t\n\t\t\t\t// Count the mutations at the given position to determine if we are multiallelic\n\t\t\t\tint allele_count = (int)nonnuc_based.size();\n\t\t\t\t\n\t\t\t\t// Output this mutation if (1) we are outputting multiallelics in a non-nuc-based model, or (2) we are a nuc-based model (regardless of allele count), or (3) it is not multiallelic\n\t\t\t\tif (p_output_multiallelics || nucleotide_based || (allele_count == 1))\n\t\t\t\t{\n\t\t\t\t\t// emit CHROM (\"1\"), POS, ID (\".\"), REF (\"A\"), and ALT (\"T\")\n\t\t\t\t\t// BCH 2/3/2025: we now emit the chromosome's symbol in the CHROM field, introducing a minor\n\t\t\t\t\t// backward compatibility break; it used to be \"1\" by default, now it is \"A\" by default, but\n\t\t\t\t\t// this is easy to fix by calling initializeChromosome() explicitly and supplying symbol=\"1\"\n\t\t\t\t\tp_out << p_chromosome.Symbol() << \"\\t\" << (mut_position + 1) << \"\\t.\\tA\\tT\";\t\t\t// +1 because VCF uses 1-based positions\n\t\t\t\t\t\n\t\t\t\t\t// emit QUAL (1000), FILTER (PASS)\n\t\t\t\t\tp_out << \"\\t1000\\tPASS\\t\";\n\t\t\t\t\t\n\t\t\t\t\t// emit the INFO fields and the Genotype marker\n\t\t\t\t\tp_out << \"MID=\" << mutation->mutation_id_ << \";\";\n\t\t\t\t\tp_out << \"S=\" << mutation->selection_coeff_ << \";\";\n\t\t\t\t\tp_out << \"DOM=\" << mutation->mutation_type_ptr_->dominance_coeff_ << \";\";\n\t\t\t\t\tp_out << \"PO=\" << mutation->subpop_index_ << \";\";\n\t\t\t\t\tp_out << \"TO=\" << mutation->origin_tick_ << \";\";\n\t\t\t\t\tp_out << \"MT=\" << mutation->mutation_type_ptr_->mutation_type_id_ << \";\";\n\t\t\t\t\tp_out << \"AC=\" << polymorphism->prevalence_ << \";\";\n\t\t\t\t\tp_out << \"DP=1000\";\n\t\t\t\t\t\n\t\t\t\t\tif (!nucleotide_based && (allele_count > 1))\t// output MULTIALLELIC flags only in non-nuc-based models\n\t\t\t\t\t\tp_out << \";MULTIALLELIC\";\n\t\t\t\t\tif (nucleotide_based && p_output_nonnucs)\n\t\t\t\t\t\tp_out << \";NONNUC\";\n\t\t\t\t\t\n\t\t\t\t\tp_out << \"\\tGT\";\n\t\t\t\t\t\n\t\t\t\t\t// emit the individual calls\n\t\t\t\t\tif (intrinsic_ploidy == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst Haplosome &haplosome = *p_haplosomes[individual_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// BCH 2/4/2025: If the haplosome is null, we now emit a \"~\" character\n\t\t\t\t\t\t\tif (haplosome.IsNull()) {\n\t\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haploid call\n\t\t\t\t\t\t\tp_out << (haplosome.contains_mutation(mutation) ? \"\\t1\" : \"\\t0\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst Haplosome &haplosome1 = *p_haplosomes[(size_t)individual_index * 2];\n\t\t\t\t\t\t\tconst Haplosome &haplosome2 = *p_haplosomes[(size_t)individual_index * 2 + 1];\n\t\t\t\t\t\t\tbool haplosome1_null = haplosome1.IsNull(), haplosome2_null = haplosome2.IsNull();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// BCH 2/4/2025: If both haplosomes are null, we now emit a \"~\" character\n\t\t\t\t\t\t\tif (haplosome1_null && haplosome2_null) {\n\t\t\t\t\t\t\t\tp_out << \"\\t~\";\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (haplosome1_null)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// hemizygous; we emit this as haploid (losing which haplosome was null)\n\t\t\t\t\t\t\t\tp_out << (haplosome2.contains_mutation(mutation) ? \"\\t1\" : \"\\t0\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (haplosome2_null)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// hemizygous; we emit this as haploid (losing which haplosome was null)\n\t\t\t\t\t\t\t\tp_out << (haplosome1.contains_mutation(mutation) ? \"\\t1\" : \"\\t0\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbool haplosome1_has_mut = haplosome1.contains_mutation(mutation);\n\t\t\t\t\t\t\t\tbool haplosome2_has_mut = haplosome2.contains_mutation(mutation);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (haplosome1_has_mut && haplosome2_has_mut)\tp_out << \"\\t1|1\";\n\t\t\t\t\t\t\t\telse if (haplosome1_has_mut)\t\t\t\t\tp_out << \"\\t1|0\";\n\t\t\t\t\t\t\t\telse if (haplosome2_has_mut)\t\t\t\t\tp_out << \"\\t0|1\";\n\t\t\t\t\t\t\t\telse\t\t\t\t\t\t\t\t\t\t\tp_out << \"\\t0|0\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tp_out << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// polyiter already points to the mutation at the next position, or to end(), so we don't advance it here\n\t}\n}\n\nsize_t Haplosome::MemoryUsageForMutrunBuffers(void)\n{\n\tif (mutruns_ == run_buffer_)\n\t\treturn 0;\n\telse\n\t\treturn mutrun_count_ * sizeof(MutationRun *);\n}\n\n\n//\n//\tHaplosome_Class\n//\n#pragma mark -\n#pragma mark Haplosome_Class\n#pragma mark -\n\nEidosClass *gSLiM_Haplosome_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Haplosome_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Haplosome_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosome,\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosomeSubposition,\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Haplosome::GetProperty_Accelerated_chromosomeSubposition));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haplosomePedigreeID,true,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Haplosome::GetProperty_Accelerated_haplosomePedigreeID));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_individual,\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Individual_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_isNullHaplosome,\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Haplosome::GetProperty_Accelerated_isNullHaplosome));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationCount,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutations,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Mutation_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Haplosome::GetProperty_Accelerated_tag)->DeclareAcceleratedSet(Haplosome::SetProperty_Accelerated_tag));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Haplosome_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Haplosome_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_addMutations, kEidosValueMaskVOID))->AddObject(\"mutations\", gSLiM_Mutation_Class));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_addNewDrawnMutation, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject(\"mutationType\", gSLiM_MutationType_Class)->AddInt(\"position\")->AddIntObject_ON(\"originSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddIntString_ON(\"nucleotide\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_addNewMutation, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject(\"mutationType\", gSLiM_MutationType_Class)->AddNumeric(\"selectionCoeff\")->AddInt(\"position\")->AddIntObject_ON(\"originSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddIntString_ON(\"nucleotide\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_containsMarkerMutation, kEidosValueMaskLogical | kEidosValueMaskSingleton | kEidosValueMaskNULL | kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class)->AddInt_S(\"position\")->AddLogical_OS(\"returnMutation\", gStaticEidosValue_LogicalF))->DeclareAcceleratedImp(Haplosome::ExecuteMethod_Accelerated_containsMarkerMutation));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_containsMutations, kEidosValueMaskLogical))->AddObject(\"mutations\", gSLiM_Mutation_Class))->DeclareAcceleratedImp(Haplosome::ExecuteMethod_Accelerated_containsMutations));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_countOfMutationsOfType, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class))->DeclareAcceleratedImp(Haplosome::ExecuteMethod_Accelerated_countOfMutationsOfType));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_positionsOfMutationsOfType, kEidosValueMaskInt))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_mutationCountsInHaplosomes, kEidosValueMaskInt))->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_mutationFrequenciesInHaplosomes, kEidosValueMaskFloat))->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationsOfType, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_nucleotides, kEidosValueMaskInt | kEidosValueMaskString))->AddInt_OSN(gEidosStr_start, gStaticEidosValueNULL)->AddInt_OSN(gEidosStr_end, gStaticEidosValueNULL)->AddString_OS(\"format\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"string\"))));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_readHaplosomesFromMS, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddString_S(gEidosStr_filePath)->AddIntObject_S(\"mutationType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_readHaplosomesFromVCF, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddString_S(gEidosStr_filePath)->AddIntObject_OSN(\"mutationType\", gSLiM_MutationType_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_removeMutations, kEidosValueMaskVOID))->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddLogical_OS(\"substitute\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_outputHaplosomesToMS, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"filterMonomorphic\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_outputHaplosomesToVCF, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"outputMultiallelics\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"simplifyNucleotides\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"outputNonnucleotides\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"groupAsIndividuals\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_outputHaplosomes, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"objectTags\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sumOfMutationsOfType, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nEidosValue_SP Haplosome_Class::ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_addMutations:\t\t\t\t\treturn ExecuteMethod_addMutations(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_addNewDrawnMutation:\n\t\tcase gID_addNewMutation:\t\t\t\treturn ExecuteMethod_addNewMutation(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_mutationCountsInHaplosomes:\n\t\tcase gID_mutationFrequenciesInHaplosomes:\treturn ExecuteMethod_mutationFreqsCountsInHaplosomes(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_outputHaplosomes:\n\t\tcase gID_outputHaplosomesToMS:\n\t\tcase gID_outputHaplosomesToVCF:\t\t\treturn ExecuteMethod_outputX(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_readHaplosomesFromMS:\t\t\treturn ExecuteMethod_readHaplosomesFromMS(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_readHaplosomesFromVCF:\t\t\treturn ExecuteMethod_readHaplosomesFromVCF(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_removeMutations:\t\t\t\treturn ExecuteMethod_removeMutations(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteClassMethod(p_method_id, p_target, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t+ (void)addMutations(object mutations)\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_addMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\tEidosValue *mutations_value = p_arguments[0].get();\n\t\n\t// FIXME this method should be optimized for large-scale bulk addition in the same\n\t// way that addNewMutation() and addNewDrawnMutation() now are.  BCH 29 Oct 2017\n\t\n\tint target_size = p_target->Count();\n\t\n\tif (target_size == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForHaplosomes(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): \" << \"addMutations() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_addMutations\");\n\t\n\tCommunity &community = species->community_;\n\t\n\t// All haplosomes must belong to the same chromosome, and all mutations being added must belong to that chromosome too.\n\t// It's important that a mismatch result in an error; attempts to add mutations to chromosomes inconsistently should be flagged.\n\tint mutations_count = mutations_value->Count();\n\tMutation * const *mutations = (Mutation * const *)mutations_value->ObjectData();\n\tHaplosome * const *targets = (Haplosome * const *)p_target->ObjectData();\n\tHaplosome *haplosome_0 = targets[0];\n\tslim_chromosome_index_t chromosome_index = haplosome_0->chromosome_index_;\n\t\n\tif (species->Chromosomes().size() > 1)\n\t{\n\t\t// We have to check for consistency if there's more than one chromosome\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\tif (targets[haplosome_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): \" << \"addMutations() requires that all target haplosomes are associated with the same chromosome.\" << EidosTerminate();\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t\tif (mutations[value_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): \" << \"addMutations() requires that all mutations to be added are associated with the same chromosome as the target haplosomes.\" << EidosTerminate();\n\t}\n\t\n\tChromosome *chromosome = species->Chromosomes()[chromosome_index];\n\t\n\t// use the 0th haplosome in the target to find out what the mutation run length is, so we can calculate run indices\n\tslim_position_t mutrun_length = haplosome_0->mutrun_length_;\n\t\n\t// check that the individuals that mutations are being added to have age == 0, in nonWF models, to prevent tree sequence inconsistencies (see issue #102)\n\tif ((community.ModelType() == SLiMModelType::kModelTypeNonWF) && species->RecordingTreeSequence())\n\t{\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\tIndividual *target_individual = target_haplosome->OwningIndividual();\n\t\t\t\n\t\t\tif (target_individual->age_ > 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): \" << \"addMutations() cannot add mutations to individuals of age > 0 when tree-sequence recording is enabled, to prevent internal inconsistencies.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// check for other semantic issues\n\tPopulation &pop = species->population_;\n\t\n\tspecies->CheckMutationStackPolicy();\n\t\n\t// TIMING RESTRICTION\n\tif (!community.warned_early_mutation_add_)\n\t{\n\t\tif ((community.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Haplosome_Class::ExecuteMethod_addMutations): addMutations() should probably not be called from a first() or early() event in a WF model; the added mutation(s) will not influence fitness values during offspring generation.\" << std::endl;\n\t\t\t\tcommunity.warned_early_mutation_add_ = true;\n\t\t\t}\n\t\t}\n\t\t// Note that there is no equivalent problem in nonWF models, because fitness values are used for survival,\n\t\t// not reproduction, and there is no event stage in the tick cycle that splits fitness from survival.\n\t}\n\t\n\t// TIMING RESTRICTION\n\tif (community.executing_species_ == species)\n\t{\n\t\tif (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosModifyChildCallback)\n\t\t{\n\t\t\t// Check that we're not inside a modifyChild() callback, or if we are, that the only haplosomes being modified belong to the new child.\n\t\t\t// This prevents problems with retracting the proposed child when tree-sequence recording is enabled; other extraneous changes must\n\t\t\t// not be backed out, and it's hard to separate, e.g., what's a child-related new mutation from an extraneously added new mutation.\n\t\t\t// Note that the other Haplosome methods that add/remove mutations perform the same check, and should be maintained in parallel.\n\t\t\tIndividual *focal_modification_child = community.focal_modification_child_;\n\t\t\t\n\t\t\tif (focal_modification_child)\n\t\t\t{\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (target_haplosome->individual_ != focal_modification_child)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() cannot be called on the currently executing species from within a modifyChild() callback to modify any haplosomes except those of the focal child being generated.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosRecombinationCallback) ||\n\t\t\t\t (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosMutationCallback))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() cannot be called on the currently executing species from within a recombination() or mutation() callback.\" << EidosTerminate();\n\t}\n\t\n\t// check that the same haplosome is not included more than once as a target, which we don't allow; we use patch_pointer as scratch\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t{\n\t\tHaplosome *target_haplosome = targets[target_index];\n\t\t\n\t\tif (target_haplosome->IsNull())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\t\n\t\ttarget_haplosome->scratch_ = 1;\n\t}\n\t\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t{\n\t\tHaplosome *target_haplosome = targets[target_index];\n\t\t\n\t\tif (target_haplosome->scratch_ != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() cannot be called on the same haplosome more than once (you must eliminate duplicates in the target vector).\" << EidosTerminate();\n\t\t\n\t\ttarget_haplosome->scratch_ = 0;\n\t}\n\t\n\t// Construct a vector of mutations to add that is sorted by position\n\tstd::vector<Mutation *> mutations_to_add;\n\t\n\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t{\n\t\tMutation *mut_to_add = mutations[value_index];\n\t\t\n\t\tif ((mut_to_add->state_ == MutationState::kFixedAndSubstituted) ||\n\t\t\t(mut_to_add->state_ == MutationState::kRemovedWithSubstitution))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() cannot add a mutation that has already been fixed/substituted.\" << EidosTerminate();\n\t\t\n\t\tmutations_to_add.emplace_back(mut_to_add);\n\t}\n\t\n\tstd::sort(mutations_to_add.begin(), mutations_to_add.end(), [ ](Mutation *i1, Mutation *i2) {return i1->position_ < i2->position_;});\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (mutations_count > 0)\n\t{\n\t\tSpecies *mutations_species = Community::SpeciesForMutations(mutations_value);\n\t\t\n\t\tif (mutations_species != species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addMutations): addMutations() requires that all mutations belong to the same species as the target haplosomes.\" << EidosTerminate();\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\t// First, pre-plan the positions of new tree-seq derived states in anticipation of doing the addition.  We have to check\n\t// whether the mutation being added is already present, to avoid recording a new derived state identical to the old one state.\n\t// The algorithm used here, with HaplosomeWalker, depends upon the fact that we just sorted the mutations to add by position.\n\t// However, we do still have to think about multiple muts being added at the same position, and existing stacked mutations.\n\tbool recording_tree_sequence_mutations = species->RecordingTreeSequenceMutations();\n\tstd::vector<std::pair<Haplosome *, std::vector<slim_position_t>>> new_derived_state_positions;\n\t\n\tif (recording_tree_sequence_mutations)\n\t{\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\tHaplosomeWalker walker(target_haplosome);\n\t\t\tslim_position_t last_added_pos = -1;\n\t\t\t\n\t\t\tfor (Mutation *mut : mutations_to_add)\n\t\t\t{\n\t\t\t\tslim_position_t mut_pos = mut->position_;\n\t\t\t\t\n\t\t\t\t// We don't care about other mutations at an already recorded position; move on\n\t\t\t\tif (mut_pos == last_added_pos)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// Advance the walker until it is at or after the mutation's position\n\t\t\t\twhile (!walker.Finished())\n\t\t\t\t{\n\t\t\t\t\tif (walker.Position() >= mut_pos)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\twalker.NextMutation();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If walker is finished, or is now after the mutation's position, drop through to add this position\n\t\t\t\tif (!walker.Finished() && (walker.Position() == mut_pos))\n\t\t\t\t{\n\t\t\t\t\t// If the mutation is already present, somewhere at this position, then we don't need to record it\n\t\t\t\t\tif (walker.MutationIsStackedAtCurrentPosition(mut))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// The mutation is not already present, so we need to record it; drop through to the addition code\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// we have decided that the new derived state at this position will need to be recorded, so note that\n\t\t\t\tif (last_added_pos == -1)\n\t\t\t\t{\n\t\t\t\t\t// no pair entry in new_derived_state_positions yet, so make a new pair entry for this haplosome\n\t\t\t\t\tnew_derived_state_positions.emplace_back(target_haplosome, std::vector<slim_position_t>(1, mut_pos));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we have an existing pair entry for this haplosome, so add this position to its position vector\n\t\t\t\t\tstd::pair<Haplosome *, std::vector<slim_position_t>> &haplosome_entry = new_derived_state_positions.back();\n\t\t\t\t\tstd::vector<slim_position_t> &haplosome_list = haplosome_entry.second;\n\t\t\t\t\t\n\t\t\t\t\thaplosome_list.emplace_back(mut_pos);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlast_added_pos = mut_pos;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Now handle the mutations to add, broken into bulk operations according to the mutation run they fall into\n\tslim_mutrun_index_t last_handled_mutrun_index = -1;\n\t\n\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t{\n\t\tMutation *next_mutation = mutations_to_add[value_index];\n\t\tconst slim_position_t pos = next_mutation->position_;\n\t\tslim_mutrun_index_t mutrun_index = (slim_mutrun_index_t)(pos / mutrun_length);\n\t\t\n\t\tif (mutrun_index <= last_handled_mutrun_index)\n\t\t\tcontinue;\n\t\t\n\t\t// We have not yet processed this mutation run; do this mutation run index as a bulk operation\n\t\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\t\n\t\tHaplosome::BulkOperationStart(operation_id, mutrun_index);\n\t\t\n\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(mutrun_index);\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\t\n\t\t\t// See if WillModifyRunForBulkOperation() can short-circuit the operation for us\n\t\t\tMutationRun *target_run = target_haplosome->WillModifyRunForBulkOperation(operation_id, mutrun_index, mutrun_context);\n\t\t\t\n\t\t\tif (target_run)\n\t\t\t{\n\t\t\t\tfor (int mut_index = value_index; mut_index < mutations_count; ++mut_index)\n\t\t\t\t{\n\t\t\t\t\tMutation *mut_to_add = mutations_to_add[mut_index];\n\t\t\t\t\tconst slim_position_t add_pos = mut_to_add->position_;\n\t\t\t\t\t\n\t\t\t\t\t// since we're in sorted order by position, as soon as we leave the current mutation run we're done\n\t\t\t\t\tif (add_pos / mutrun_length != mutrun_index)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (target_run->enforce_stack_policy_for_addition(mut_to_add->position_, mut_to_add->mutation_type_ptr_))\n\t\t\t\t\t{\n\t\t\t\t\t\ttarget_run->insert_sorted_mutation_if_unique(mut_to_add->BlockIndex());\n\t\t\t\t\t\t\n\t\t\t\t\t\t// No need to add the mutation to the registry; how would the user ever get a Mutation that was not already in it?\n\t\t\t\t\t\t// Similarly, no need to check and set pure_neutral_ and all_pure_neutral_DFE_; the mutation is already in the system\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tHaplosome::BulkOperationEnd(operation_id, mutrun_index);\n\t\t\n\t\t// now we have handled all mutations at this index (and all previous indices)\n\t\tlast_handled_mutrun_index = mutrun_index;\n\t\t\n\t\t// invalidate cached mutation refcounts; refcounts have changed\n\t\tpop.InvalidateMutationReferencesCache();\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\t// Now that all the bulk operations are done, record all the new derived states.  BCH 6/12/2021: Note that if a mutation to be added\n\t// was rejected by stacking policy 'f' above, it will still get recorded here with a new derived state, which will be identical to the\n\t// previous derived state.  This is maybe a bug, but nobody has complained and it looks hard to fix.  People don't use policy 'f' much.\n\tif (recording_tree_sequence_mutations)\n\t{\n\t\tfor (std::pair<Haplosome *, std::vector<slim_position_t>> &haplosome_pair : new_derived_state_positions)\n\t\t{\n\t\t\tHaplosome *target_haplosome = haplosome_pair.first;\n\t\t\tstd::vector<slim_position_t> &haplosome_positions = haplosome_pair.second;\n\t\t\t\n\t\t\tfor (slim_position_t position : haplosome_positions)\n\t\t\t\tspecies->RecordNewDerivedState(target_haplosome, position, *target_haplosome->derived_mutation_ids_at_position(position));\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t+ (object<Mutation>)addNewDrawnMutation(io<MutationType> mutationType, integer position, [Nio<Subpopulation> originSubpop = NULL], [Nis nucleotide = NULL])\n//\t*********************\t+ (object<Mutation>)addNewMutation(io<MutationType> mutationType, numeric selectionCoeff, integer position, [Nio<Subpopulation> originSubpop = NULL], [Nis nucleotide = NULL])\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_addNewMutation(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\t\n#ifdef __clang_analyzer__\n\tassert(((p_method_id == gID_addNewDrawnMutation) && (p_arguments.size() == 5)) || ((p_method_id == gID_addNewMutation) && (p_arguments.size() == 6)));\n#endif\n\t\n\tEidosValue *arg_muttype = p_arguments[0].get();\n\tEidosValue *arg_selcoeff = (p_method_id == gID_addNewDrawnMutation ? nullptr : p_arguments[1].get());\n\tEidosValue *arg_position = (p_method_id == gID_addNewDrawnMutation ? p_arguments[1].get() : p_arguments[2].get());\n\tEidosValue *arg_origin_subpop = (p_method_id == gID_addNewDrawnMutation ? p_arguments[2].get() : p_arguments[3].get());\n\tEidosValue *arg_nucleotide = (p_method_id == gID_addNewDrawnMutation ? p_arguments[3].get() : p_arguments[4].get());\n\t\n\tint target_size = p_target->Count();\n\t\n\tif (target_size == 0)\n\t\treturn gStaticEidosValueNULLInvisible;\t// this is almost an error condition, since a mutation was expected to be added and none was\n\t\n\tstd::string method_name = EidosStringRegistry::StringForGlobalStringID(p_method_id);\n\tmethod_name.append(\"()\");\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForHaplosomes(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_addNewMutation\");\n\t\n\tCommunity &community = species->community_;\n\t\n\t// All haplosomes must belong to the same chromosome.  It's important that a mismatch result in an error;\n\t// attempts to add mutations to chromosomes inconsistently should be flagged.\n\tHaplosome * const *targets = (Haplosome * const *)p_target->ObjectData();\n\tHaplosome *haplosome_0 = targets[0];\n\tslim_chromosome_index_t chromosome_index = haplosome_0->chromosome_index_;\n\t\n\tif (species->Chromosomes().size() > 1)\n\t{\n\t\t// We have to check for consistency if there's more than one chromosome\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\tif (targets[haplosome_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires that all target haplosomes are associated with the same chromosome.\" << EidosTerminate();\n\t}\n\t\n\tChromosome *chromosome = species->Chromosomes()[chromosome_index];\n\t\n\t// get the 0th haplosome in the target to find out what the mutation run length is, so we can calculate run indices\n\tint mutrun_count = haplosome_0->mutrun_count_;\n\tslim_position_t mutrun_length = haplosome_0->mutrun_length_;\n\t\n\t// check that the individuals that mutations are being added to have age == 0, in nonWF models, to prevent tree sequence inconsistencies (see issue #102)\n\tif ((community.ModelType() == SLiMModelType::kModelTypeNonWF) && species->RecordingTreeSequence())\n\t{\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\tIndividual *target_individual = target_haplosome->OwningIndividual();\n\t\t\t\n\t\t\tif (target_individual->age_ > 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" cannot add mutations to individuals of age > 0 when tree-sequence recording is enabled, to prevent internal inconsistencies.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// check for other semantic issues\n\tPopulation &pop = species->population_;\n\tbool nucleotide_based = species->IsNucleotideBased();\n\t\n\tif (!nucleotide_based && (arg_nucleotide->Type() != EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires nucleotide to be NULL in non-nucleotide-based models.\" << EidosTerminate();\n\t\n\tspecies->CheckMutationStackPolicy();\n\t\n\t// TIMING RESTRICTION\n\tif (!community.warned_early_mutation_add_)\n\t{\n\t\tif ((community.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" should probably not be called from a first() or early() event in a WF model; the added mutation will not influence fitness values during offspring generation.\" << std::endl;\n\t\t\t\tcommunity.warned_early_mutation_add_ = true;\n\t\t\t}\n\t\t}\n\t\t// Note that there is no equivalent problem in nonWF models, because fitness values are used for survival,\n\t\t// not reproduction, and there is no event stage in the tick cycle that splits fitness from survival.\n\t}\n\t\n\t// TIMING RESTRICTION\n\tif (community.executing_species_ == species)\n\t{\n\t\tif (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosModifyChildCallback)\n\t\t{\n\t\t\t// Check that we're not inside a modifyChild() callback, or if we are, that the only haplosomes being modified belong to the new child.\n\t\t\t// This prevents problems with retracting the proposed child when tree-sequence recording is enabled; other extraneous changes must\n\t\t\t// not be backed out, and it's hard to separate, e.g., what's a child-related new mutation from an extraneously added new mutation.\n\t\t\t// Note that the other Haplosome methods that add/remove mutations perform the same check, and should be maintained in parallel.\n\t\t\tIndividual *focal_modification_child = community.focal_modification_child_;\n\t\t\t\n\t\t\tif (focal_modification_child)\n\t\t\t{\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *target_haplosome = targets[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (target_haplosome->individual_ != focal_modification_child)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" cannot be called on the currently executing species from within a modifyChild() callback to modify any haplosomes except those of the focal child being generated.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosRecombinationCallback) ||\n\t\t\t\t (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosMutationCallback))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" cannot be called on the currently executing species from within a recombination() or mutation() callback.\" << EidosTerminate();\n\t}\n\t\n\t// position and originSubpop can now be either singletons or vectors of matching length or NULL; check them all\n\tint muttype_count = arg_muttype->Count();\n\tint selcoeff_count = (arg_selcoeff ? arg_selcoeff->Count() : 0);\n\tint position_count = arg_position->Count();\n\tint origin_subpop_count = arg_origin_subpop->Count();\n\tint nucleotide_count = arg_nucleotide->Count();\n\t\n\tif (arg_origin_subpop->Type() == EidosValueType::kValueNULL)\n\t\torigin_subpop_count = 1;\n\tif (arg_nucleotide->Type() == EidosValueType::kValueNULL)\n\t\tnucleotide_count = 1;\n\t\n\tint count_to_add = std::max({muttype_count, selcoeff_count, position_count, origin_subpop_count, nucleotide_count});\n\t\n\tif (((muttype_count != 1) && (muttype_count != count_to_add)) ||\n\t\t(arg_selcoeff && (selcoeff_count != 1) && (selcoeff_count != count_to_add)) ||\n\t\t((position_count != 1) && (position_count != count_to_add)) ||\n\t\t((origin_subpop_count != 1) && (origin_subpop_count != count_to_add)) ||\n\t\t((nucleotide_count != 1) && (nucleotide_count != count_to_add)))\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires that mutationType, \" << ((p_method_id == gID_addNewMutation) ? \"selectionCoeff, \" : \"\") << \"position, originSubpop, and nucleotide be either (1) singleton, or (2) equal in length to the other non-singleton argument(s), or (3) NULL, for originSubpop and nucleotide.\" << EidosTerminate();\n\t\n\tEidosValue_Object_SP retval(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\n\tif (count_to_add == 0)\n\t\treturn retval;\n\t\n\t// before proceeding, let's check that all positions supplied are valid, so we don't need to worry about it below\n\t// would be better not to call IntAtIndex_NOCAST() multiple times for the same position, but that will not be the majority of our time anyway...\n\tslim_position_t last_position = chromosome->last_position_;\n\t\n\tfor (int position_index = 0; position_index < position_count; ++position_index)\n\t{\n\t\tslim_position_t position = SLiMCastToPositionTypeOrRaise(arg_position->IntAtIndex_NOCAST(position_index, nullptr));\n\t\t\n\t\tif (position > last_position)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" position \" << position << \" is past the end of the chromosome.\" << EidosTerminate();\n\t}\n\t\n\t// similarly, check nucleotide values for validity\n\tuint8_t *nucleotide_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\n\tif (arg_nucleotide->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// If nucleotide is NULL, all mutation types supplied must be non-nucleotide-based\n\t\tfor (int muttype_index = 0; muttype_index < muttype_count; ++muttype_index)\n\t\t{\n\t\t\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(arg_muttype, muttype_index, &community, species, method_name.c_str());\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\n\t\t\tif (mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires nucleotide to be non-NULL when nucleotide-based mutation types are used.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// If nucleotide is non-NULL, all mutation types supplied must be nucleotide-based\n\t\tfor (int muttype_index = 0; muttype_index < muttype_count; ++muttype_index)\n\t\t{\n\t\t\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(arg_muttype, muttype_index, &community, species, method_name.c_str());\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\n\t\t\tif (!mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires nucleotide to be NULL when non-nucleotide-based mutation types are used.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// And then nucleotide values must also be within bounds\n\t\tif (arg_nucleotide->Type() == EidosValueType::kValueInt)\n\t\t{\n\t\t\tfor (int nucleotide_index = 0; nucleotide_index < nucleotide_count; ++nucleotide_index)\n\t\t\t{\n\t\t\t\tint64_t nuc_int = arg_nucleotide->IntAtIndex_NOCAST(nucleotide_index, nullptr);\n\t\t\t\t\n\t\t\t\tif ((nuc_int < 0) || (nuc_int > 3))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires integer nucleotide values to be in [0,3].\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\telse if (arg_nucleotide->Type() == EidosValueType::kValueString)\n\t\t{\n\t\t\tfor (int nucleotide_index = 0; nucleotide_index < nucleotide_count; ++nucleotide_index)\n\t\t\t{\n\t\t\t\tuint8_t nuc = nucleotide_lookup[(unsigned char)(arg_nucleotide->StringAtIndex_NOCAST(nucleotide_index, nullptr)[0])];\n\t\t\t\t\n\t\t\t\tif (nuc > 3)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires string nucleotide values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// check that the same haplosome is not included more than once as a target, which we don't allow; we use patch_pointer as scratch\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t{\n\t\tHaplosome *target_haplosome = targets[target_index];\n\t\t\n\t\tif (target_haplosome->IsNull())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" cannot be called on a null haplosome.\" << EidosTerminate();\n\t\t\n\t\ttarget_haplosome->scratch_ = 1;\n\t}\n\t\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t{\n\t\tHaplosome *target_haplosome = targets[target_index];\n\t\t\n\t\tif (target_haplosome->scratch_ != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" cannot be called on the same haplosome more than once (you must eliminate duplicates in the target vector).\" << EidosTerminate();\n\t\t\n\t\ttarget_haplosome->scratch_ = 0;\n\t}\n\t\n\t// each bulk operation is performed on a single mutation run, so we need to figure out which runs we're influencing\n\tstd::vector<slim_mutrun_index_t> mutrun_indexes;\n\t\n\tif (mutrun_count == 1)\n\t{\n\t\t// if we have just a single mutrun, we can avoid the sorting and uniquing; all valid positions are in mutrun 0\n\t\tmutrun_indexes.emplace_back(0);\n\t}\n\telse\n\t{\n\t\tfor (int pos_index = 0; pos_index < position_count; ++pos_index)\n\t\t{\n\t\t\tslim_position_t position = SLiMCastToPositionTypeOrRaise(arg_position->IntAtIndex_NOCAST(pos_index, nullptr));\n\t\t\tmutrun_indexes.emplace_back((slim_mutrun_index_t)(position / mutrun_length));\n\t\t}\n\t\t\n\t\tstd::sort(mutrun_indexes.begin(), mutrun_indexes.end());\n\t\tmutrun_indexes.resize(std::distance(mutrun_indexes.begin(), std::unique(mutrun_indexes.begin(), mutrun_indexes.end())));\n\t}\n\t\n\t// for the singleton case for each of the parameters, get all the info\n\tMutationType *singleton_mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(arg_muttype, 0, &community, species, method_name.c_str());\t\t// SPECIES CONSISTENCY CHECK\n\t\n\tdouble singleton_selection_coeff = (arg_selcoeff ? arg_selcoeff->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\t\n\tslim_position_t singleton_position = SLiMCastToPositionTypeOrRaise(arg_position->IntAtIndex_NOCAST(0, nullptr));\n\t\n\tslim_tick_t origin_tick = community.Tick();\n\t\n\tslim_objectid_t singleton_origin_subpop_id;\n\t\n\tif (arg_origin_subpop->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tsingleton_origin_subpop_id = -1;\n\t\t\n\t\t// We set the origin subpopulation based on the first haplosome in the target\n\t\tif (target_size >= 1)\n\t\t{\n\t\t\tHaplosome *first_target = targets[0];\n\t\t\tsingleton_origin_subpop_id = first_target->individual_->subpopulation_->subpopulation_id_;\n\t\t}\n\t}\n\telse if (arg_origin_subpop->Type() == EidosValueType::kValueInt)\n\t{\n\t\tsingleton_origin_subpop_id = SLiMCastToObjectidTypeOrRaise(arg_origin_subpop->IntAtIndex_NOCAST(0, nullptr));\n\t}\n\telse\n\t{\n\t\tSubpopulation *origin_subpop = ((Subpopulation *)(arg_origin_subpop->ObjectElementAtIndex_NOCAST(0, nullptr)));\n\t\t\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif (&origin_subpop->species_ != species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_addNewMutation): \" << method_name << \" requires that originSubpop belong to the same species as the target haplosomes.\" << EidosTerminate();\n\t\t\n\t\tsingleton_origin_subpop_id = origin_subpop->subpopulation_id_;\n\t}\n\t\n\tint64_t singleton_nucleotide;\n\t\n\tif (arg_nucleotide->Type() == EidosValueType::kValueNULL)\n\t\tsingleton_nucleotide = -1;\n\telse if (arg_nucleotide->Type() == EidosValueType::kValueInt)\n\t\tsingleton_nucleotide = arg_nucleotide->IntAtIndex_NOCAST(0, nullptr);\n\telse\n\t\tsingleton_nucleotide = nucleotide_lookup[(unsigned char)(arg_nucleotide->StringAtIndex_NOCAST(0, nullptr)[0])];\n\t\n\t// ok, now loop to add the mutations in a single bulk operation per mutation run\n\tbool recording_tree_sequence_mutations = species->RecordingTreeSequenceMutations();\n\t\n\tfor (slim_mutrun_index_t mutrun_index : mutrun_indexes)\n\t{\n\t\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\tstd::vector<MutationIndex> mutations_to_add;\n\t\t\n\t\t// Before starting the bulk operation for this mutation run, construct all of the mutations and add them all to the registry, etc.\n\t\t// It is possible that some mutations will not actually be added to any haplosome, due to stacking; they will be cleared from the\n\t\t// registry as lost mutations in the next cycle.  All mutations are returned to the user, whether actually added or not.\n\t\tMutationType *mutation_type_ptr = singleton_mutation_type_ptr;\n\t\tdouble selection_coeff = singleton_selection_coeff;\n\t\tslim_position_t position = singleton_position;\n\t\tslim_objectid_t origin_subpop_id = singleton_origin_subpop_id;\n\t\tint64_t nucleotide = singleton_nucleotide;\n\t\t\n\t\tfor (int mut_parameter_index = 0; mut_parameter_index < count_to_add; ++mut_parameter_index)\n\t\t{\n\t\t\tif (position_count != 1)\n\t\t\t\tposition = SLiMCastToPositionTypeOrRaise(arg_position->IntAtIndex_NOCAST(mut_parameter_index, nullptr));\n\t\t\t\n\t\t\t// check that this mutation will be added to this mutation run\n\t\t\tif (position / mutrun_length == mutrun_index)\n\t\t\t{\n\t\t\t\tif (muttype_count != 1)\n\t\t\t\t\tmutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(arg_muttype, mut_parameter_index, &community, species, method_name.c_str());\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\t\n\t\t\t\tif (selcoeff_count != 1)\n\t\t\t\t{\n\t\t\t\t\tif (arg_selcoeff)\n\t\t\t\t\t\tselection_coeff = arg_selcoeff->NumericAtIndex_NOCAST(mut_parameter_index, nullptr);\n\t\t\t\t\telse\n\t\t\t\t\t\tselection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (origin_subpop_count != 1)\n\t\t\t\t{\n\t\t\t\t\tif (arg_origin_subpop->Type() == EidosValueType::kValueInt)\n\t\t\t\t\t\torigin_subpop_id = SLiMCastToObjectidTypeOrRaise(arg_origin_subpop->IntAtIndex_NOCAST(mut_parameter_index, nullptr));\n\t\t\t\t\telse\n\t\t\t\t\t\torigin_subpop_id = ((Subpopulation *)(arg_origin_subpop->ObjectElementAtIndex_NOCAST(mut_parameter_index, nullptr)))->subpopulation_id_;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (nucleotide_count != 1)\n\t\t\t\t{\n\t\t\t\t\t// Already checked for validity above\n\t\t\t\t\tif (arg_nucleotide->Type() == EidosValueType::kValueInt)\n\t\t\t\t\t\tnucleotide = arg_nucleotide->IntAtIndex_NOCAST(mut_parameter_index, nullptr);\n\t\t\t\t\telse\n\t\t\t\t\t\tnucleotide = nucleotide_lookup[(unsigned char)(arg_nucleotide->StringAtIndex_NOCAST(mut_parameter_index, nullptr)[0])];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\t\t\n\t\t\t\tMutation *new_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_type_ptr, chromosome->Index(), position, selection_coeff, origin_subpop_id, origin_tick, (int8_t)nucleotide);\n\t\t\t\t\n\t\t\t\t// This mutation type might not be used by any genomic element type (i.e. might not already be vetted), so we need to check and set pure_neutral_\n\t\t\t\t// The selection coefficient might have been supplied by the user (i.e., not be from the mutation type's DFE), so we set all_pure_neutral_DFE_ also\n\t\t\t\tif (selection_coeff != 0.0)\n\t\t\t\t{\n\t\t\t\t\tspecies->pure_neutral_ = false;\n\t\t\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// add to the registry, return value, haplosome, etc.\n\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\tpop.MutationRegistryAdd(new_mut);\n\t\t\t\tretval->push_object_element_RR(new_mut);\n\t\t\t\tmutations_to_add.emplace_back(new_mut_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// BCH 18 January 2020: If a vector of positions was provided, mutations_to_add might be out of sorted\n\t\t// order, which is expected below by clear_set_and_merge(), so we sort here\n\t\tif ((position_count != 1) && (mutations_to_add.size() > 1))\n\t\t{\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\t\n\t\t\tstd::sort(mutations_to_add.begin(), mutations_to_add.end(), [mut_block_ptr](MutationIndex i1, MutationIndex i2) {return (mut_block_ptr + i1)->position_ < (mut_block_ptr + i2)->position_;});\n\t\t}\n\t\t\n\t\t// Now start the bulk operation and add mutations_to_add to every target haplosome\n\t\tHaplosome::BulkOperationStart(operation_id, mutrun_index);\n\t\t\n\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(mutrun_index);\n\t\t\n\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets[target_index];\n\t\t\t\n\t\t\t// See if WillModifyRunForBulkOperation() can short-circuit the operation for us\n\t\t\tconst MutationRun *original_run = target_haplosome->mutruns_[mutrun_index];\n\t\t\tMutationRun *modifiable_mutrun = target_haplosome->WillModifyRunForBulkOperation(operation_id, mutrun_index, mutrun_context);\n\t\t\t\n\t\t\tif (modifiable_mutrun)\n\t\t\t{\n\t\t\t\t// We merge the original run (which has not yet been freed!) and mutations_to_add into modifiable_mutrun\n\t\t\t\tmodifiable_mutrun->clear_set_and_merge(*original_run, mutations_to_add);\n\t\t\t}\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t// whether WillModifyRunForBulkOperation() short-circuited the addition or not, we need to notify the tree seq code\n\t\t\t// BCH 6/12/2021: We only need to record a derived state once per position, even if there were multiple adds at that position.\n\t\t\t// This prevents redundant derived states from being recorded; see discussion in https://github.com/MesserLab/SLiM/issues/195\n\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t{\n\t\t\t\tMutationIndex *muts = mutations_to_add.data();\n\t\t\t\tMutationIndex *muts_end = muts + mutations_to_add.size();\n\t\t\t\tslim_position_t previous_position = -1;\n\t\t\t\t\n\t\t\t\twhile (muts != muts_end)\n\t\t\t\t{\n\t\t\t\t\tMutation *mut = gSLiM_Mutation_Block + *(muts++);\n\t\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\t\n\t\t\t\t\tif (pos != previous_position)\n\t\t\t\t\t{\n\t\t\t\t\t\tspecies->RecordNewDerivedState(target_haplosome, pos, *target_haplosome->derived_mutation_ids_at_position(pos));\n\t\t\t\t\t\tprevious_position = pos;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tHaplosome::BulkOperationEnd(operation_id, mutrun_index);\n\t\t\n\t\t// invalidate cached mutation refcounts; refcounts have changed\n\t\tpop.InvalidateMutationReferencesCache();\n\t}\n\t\n\treturn retval;\n}\n\n//\t*********************\t+ (float)mutationFrequenciesInHaplosomes([No<Mutation> mutations = NULL])\n//\t*********************\t+ (integer)mutationCountsInHaplosomes([No<Mutation> mutations = NULL])\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutations_value = p_arguments[0].get();\n\t\n\t// get our target vector, handle the zero-length case, and do a pre-check for null haplosomes so we don't have to worry about it later on\n\tslim_refcount_t target_size = (slim_refcount_t)p_target->Count();\n\t\n\tif (target_size == 0)\n\t{\n\t\t// With a zero-length target, frequencies are undefined so it is an error; to keep life simple, we make it an error for counts too\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() cannot calculate counts/frequencies in a zero-length Haplosome vector (divide by zero).\" << EidosTerminate();\n\t}\n\t\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes(): usage of statics\");\n\t\n\tHaplosome * const *target_data = (Haplosome * const *)p_target->ObjectData();\n\t\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\tif (target_data[target_index]->IsNull())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() cannot be called on a null haplosome.\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForHaplosomesVector(target_data, target_size);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requires that all target haplosomes belong to a single species.\" << EidosTerminate();\n\t\n\tif (mutations_value->Count() >= 1)\n\t{\n\t\tSpecies *mut_species = Community::SpeciesForMutations(mutations_value);\n\t\t\n\t\tif (mut_species != species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requires that all mutations belong to the same species as the target haplosomes.\" << EidosTerminate();\n\t}\n\t\n\t// Note that we allow the haplosomes and mutations to be associated with more than one chromosome here;\n\t// you can pass a mix, and for each mutation you get its frequency in the haplosomes for its chromosome.\n\t// If you pass NULL, all mutations are used, which can be confusing in the multi-chromosome case if you\n\t// passed a vector of haplosomes that are all for a specific chromosome.  In that case, you shouldn't\n\t// pass NULL for mutations, but rather use sim.subsetMutations() to get the mutations for your focal\n\t// chromosome, probably.\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_mutationFreqsCountsInHaplosomes\");\n\t\n\tPopulation &population = species->population_;\n\t\n\t// Have the Population tally for the target haplosomes\n\tpopulation.TallyMutationReferencesAcrossHaplosomes(target_data, target_size);\n\t\n\t// Use the back-end code in Population to do the counting; TallyMutationReferencesAcrossHaplosomes()\n\t// should have set the total haplosome count correctly for the given haplosome sample.  Note that a\n\t// sample of mutations can be passed that belongs to a variety of different chromosomes; in this case,\n\t// each chromosome's total haplosome count should reflect the number of haplosomes in the sample\n\t// that belong to that chromosome, so the frequencies should be correct in that sense.\n\tif (p_method_id == gID_mutationFrequenciesInHaplosomes)\n\t\treturn population.Eidos_FrequenciesForTalliedMutations(mutations_value);\n\telse\n\t\treturn population.Eidos_CountsForTalliedMutations(mutations_value);\n}\n\n//\t*********************\t+ (void)outputHaplosomes([Ns$ filePath = NULL], [logical$ append=F], [logical$ objectTags = F])\n//\t*********************\t+ (void)outputHaplosomesToMS([Ns$ filePath = NULL], [logical$ append=F], [logical$ filterMonomorphic = F])\n//\t*********************\t+ (void)outputHaplosomesToVCF([Ns$ filePath = NULL], [logical$ outputMultiallelics = T], [logical$ append=F], [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T], [logical$ groupAsIndividuals = T])\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_outputX(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *outputMultiallelics_value = ((p_method_id == gID_outputHaplosomesToVCF) ? p_arguments[1].get() : nullptr);\n\tEidosValue *append_value = ((p_method_id == gID_outputHaplosomesToVCF) ? p_arguments[2].get() : p_arguments[1].get());\n\tEidosValue *filterMonomorphic_value = ((p_method_id == gID_outputHaplosomesToMS) ? p_arguments[2].get() : nullptr);\n\tEidosValue *simplifyNucleotides_value = ((p_method_id == gID_outputHaplosomesToVCF) ? p_arguments[3].get() : nullptr);\n\tEidosValue *outputNonnucleotides_value = ((p_method_id == gID_outputHaplosomesToVCF) ? p_arguments[4].get() : nullptr);\n\tEidosValue *groupAsIndividuals_value = ((p_method_id == gID_outputHaplosomesToVCF) ? p_arguments[5].get() : nullptr);\n\tEidosValue *objectTags_value = ((p_method_id == gID_outputHaplosomes) ? p_arguments[2].get() : nullptr);\n\t\n\t// default to outputting multiallelic positions (used by VCF output only)\n\tbool output_multiallelics = true;\n\t\n\tif (p_method_id == gID_outputHaplosomesToVCF)\n\t\toutput_multiallelics = outputMultiallelics_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool simplify_nucs = false;\n\t\n\tif (p_method_id == gID_outputHaplosomesToVCF)\n\t\tsimplify_nucs = simplifyNucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool output_nonnucs = true;\n\t\n\tif (p_method_id == gID_outputHaplosomesToVCF)\n\t\toutput_nonnucs = outputNonnucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool group_as_individuals = true;\n\t\n\tif (p_method_id == gID_outputHaplosomesToVCF)\n\t\tgroup_as_individuals = groupAsIndividuals_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// figure out if we're filtering out mutations that are monomorphic within the sample (MS output only)\n\tbool filter_monomorphic = false;\n\t\n\tif (p_method_id == gID_outputHaplosomesToMS)\n\t\tfilter_monomorphic = filterMonomorphic_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool output_object_tags = (objectTags_value ? objectTags_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\t\n\t// Get all the haplosomes we're sampling from p_target; they must all be in the same species, which we determine here\n\t// We require at least one haplosome because otherwise we can't determine the species\n\tint sample_size = p_target->Count();\n\tstd::vector<Haplosome *> haplosomes;\n\t\n\tif (sample_size <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_outputX): output of a zero-length haplosome vector is illegal; at least one haplosome is required for output.\" << EidosTerminate();\n\t\n\tHaplosome **target_haplosomes = (Haplosome **)p_target->ObjectData();\n\tSpecies *species = &target_haplosomes[0]->individual_->subpopulation_->species_;\n\t\n\tfor (int index = 0; index < sample_size; ++index)\n\t{\n\t\tHaplosome *haplosome = target_haplosomes[index];\n\t\tSpecies *haplosome_species = &haplosome->individual_->subpopulation_->species_;\n\t\t\n\t\tif (species != haplosome_species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_outputX): all haplosomes for output must belong to the same species.\" << EidosTerminate();\n\t\t\n\t\thaplosomes.emplace_back(haplosome);\n\t}\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_outputX\");\n\n\tCommunity &community = species->community_;\n\t\n\t// We infer the chromosome from the haplosomes, and in a multi-chrom species all the haplosomes must belong to it.\n\tslim_chromosome_index_t chromosome_index = haplosomes[0]->chromosome_index_;\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tfor (Haplosome *haplosome : haplosomes)\n\t\t\tif (haplosome->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_outputX): all haplosomes for output must be associated with the same chromosome.\" << EidosTerminate();\n\t}\n\t\n\t// Now handle stream/file output and dispatch to the actual print method\n\tif (filePath_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\t// If filePath is NULL, output to our output stream\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\t// For the output stream, we put out a descriptive SLiM-style header for all output types\n\t\t// BCH 2/2/2025: added the cycle count here after the tick; it was already documented as being here!\n\t\t// BCH 2/2/2025: added the chromosome symbol in the header; it is redundant for SLiM-format output,\n\t\t// but useful for MS and VCF; I decided to put it in all three for consistency across formats\n\t\t// BCH 2/7/2025: changed GS/GM/GV to HS/HM/HV, for the genome -> haplosome transition\n\t\toutput_stream << \"#OUT: \" << community.Tick() << \" \" << species->Cycle() << \" H\";\n\t\t\n\t\tif (p_method_id == gID_outputHaplosomes)\n\t\t\toutput_stream << \"S\";\n\t\telse if (p_method_id == gID_outputHaplosomesToMS)\n\t\t\toutput_stream << \"M\";\n\t\telse if (p_method_id == gID_outputHaplosomesToVCF)\n\t\t\toutput_stream << \"V\";\n\t\t\n\t\toutput_stream << \" \" << sample_size;\n\t\t\n\t\tif (chromosomes.size() > 1)\n\t\t{\n\t\t\toutput_stream << \" \" << chromosome->Type();\t\t\t\t\t\t// chromosome type, with >1 chromosome\n\t\t\toutput_stream << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\t\t\t// chromosome symbol, with >1 chromosome\n\t\t}\n\t\t\n\t\toutput_stream << std::endl;\n\t\t\n\t\t// Call out to print the actual sample\n\t\tif (p_method_id == gID_outputHaplosomes)\n\t\t\tHaplosome::PrintHaplosomes_SLiM(output_stream, haplosomes, output_object_tags);\n\t\telse if (p_method_id == gID_outputHaplosomesToMS)\n\t\t\tHaplosome::PrintHaplosomes_MS(output_stream, haplosomes, *chromosome, filter_monomorphic);\n\t\telse if (p_method_id == gID_outputHaplosomesToVCF)\n\t\t\tHaplosome::PrintHaplosomes_VCF(output_stream, haplosomes, *chromosome, group_as_individuals, output_multiallelics, simplify_nucs, output_nonnucs);\n\t}\n\telse\n\t{\n\t\t// Otherwise, output to filePath\n\t\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\tstd::ofstream outfile;\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\t\n\t\tif (outfile.is_open())\n\t\t{\n\t\t\tswitch (p_method_id)\n\t\t\t{\n\t\t\t\tcase gID_outputHaplosomes:\n\t\t\t\t\t// For file output, we put out the descriptive SLiM-style header only for SLiM-format output\n\t\t\t\t\t// BCH 2/2/2025: added the cycle count here after the tick; it was already documented as being here!\n\t\t\t\t\t// BCH 2/2/2025: added the chromosome symbol in the header; it is redundant for SLiM-format output,\n\t\t\t\t\t// but useful for MS and VCF; I decided to put it in all three for consistency across formats\n\t\t\t\t\t// BCH 2/7/2025: changed GS/GM/GV to HS/HM/HV, for the genome -> haplosome transition\n\t\t\t\t\toutfile << \"#OUT: \" << community.Tick() << \" \" << species->Cycle() << \" HS \" << sample_size;\n\t\t\t\t\t\n\t\t\t\t\tif (chromosomes.size() > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\toutfile << \" \" << chromosome->Type();\t\t\t\t\t\t// chromosome type, with >1 chromosome\n\t\t\t\t\t\toutfile << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\t\t\t// chromosome symbol, with >1 chromosome\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\toutfile << \" \" << outfile_path << std::endl;\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::PrintHaplosomes_SLiM(outfile, haplosomes, output_object_tags);\n\t\t\t\t\tbreak;\n\t\t\t\tcase gID_outputHaplosomesToMS:\n\t\t\t\t\tHaplosome::PrintHaplosomes_MS(outfile, haplosomes, *chromosome, filter_monomorphic);\n\t\t\t\t\tbreak;\n\t\t\t\tcase gID_outputHaplosomesToVCF:\n\t\t\t\t\tHaplosome::PrintHaplosomes_VCF(outfile, haplosomes, *chromosome, group_as_individuals, output_multiallelics, simplify_nucs, output_nonnucs);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_outputX): (internal error) unhandled case.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\toutfile.close(); \n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_outputX): could not open \" << outfile_path << \".\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t+ (o<Mutation>)readHaplosomesFromMS(s$ filePath = NULL, io<MutationType> mutationType)\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_readHaplosomesFromMS(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_interpreter)\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome_Class::ExecuteMethod_readHaplosomesFromMS(): SLiM global state read\");\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *mutationType_value = p_arguments[1].get();\n\t\n\tCommunity &community = SLiM_GetCommunityFromInterpreter(p_interpreter);\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n\tMutationType *mutation_type_ptr = nullptr;\n\t\n\tif (mutationType_value->Type() != EidosValueType::kValueNULL)\n\t\tmutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutationType_value, 0, &community, nullptr, \"ExecuteMethod_readHaplosomesFromMS()\");\t// this dictates the focal species\n\t\n\tif (!mutation_type_ptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): mutation type not found.\" << EidosTerminate();\n\t\n\t// Get the species of interest from the mutation type; we will check that all target haplosomes belong to it below\n\tSpecies &species = mutation_type_ptr->species_;\n\tPopulation &pop = species.population_;\n\tbool recording_mutations = species.RecordingTreeSequenceMutations();\n\tbool nucleotide_based = species.IsNucleotideBased();\n\tint target_size = p_target->Count();\n\t\n\tif (target_size <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): readHaplosomesFromMS() requires at least one target haplosome.\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *target_species = Community::SpeciesForHaplosomes(p_target);\n\t\n\tif (target_species != &species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): readHaplosomesFromMS() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\n\tspecies.population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_readHaplosomesFromMS\");\n\t\n\t// For MS input, we need to know the chromosome to calculate positions from the normalized interval [0, 1].\n\t// We infer it from the haplosomes, and in a multi-chromosome species all the haplosomes must belong to it.\n\tHaplosome * const *targets_data = (Haplosome * const *)p_target->ObjectData();\n\tslim_chromosome_index_t chromosome_index = targets_data[0]->chromosome_index_;\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\tif (targets_data[haplosome_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): for readHaplosomesFromMS(), all target haplosomes must be associated with the same chromosome.\" << EidosTerminate();\n\t}\n\t\n\tslim_position_t last_position = chromosome->last_position_;\n\t\n\t// Parse the whole input file and retain the information from it\n\tstd::ifstream infile(file_path);\n\t\n\tif (!infile)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): could not read file at path \" << file_path << \".\" << EidosTerminate();\n\t\n\tstd::string line, sub;\n\tint parse_state = 0;\n\tint segsites = -1;\n\tstd::vector<slim_position_t> positions;\n\tstd::vector<std::string> calls;\n\t\n\twhile (!infile.eof())\n\t{\n\t\tgetline(infile, line);\n\t\t\n\t\tif ((line.length() == 0) || (line.find(\"//\") == 0))\n\t\t\tcontinue;\n\t\t\n\t\tswitch (parse_state)\n\t\t{\n\t\t\tcase 0:\n\t\t\t{\n\t\t\t\t// Expecting \"segsites: x\"\n\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\n\t\t\t\tiss >> sub;\n\t\t\t\tif (sub != \"segsites:\")\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): expecting 'segsites:', found '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (!(iss >> sub))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): missing segsites value.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tint64_t segsites_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\t\t\n\t\t\t\tif ((segsites_long <= 0) || (segsites_long > 1000000))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): readMS() requires segsites in (0,1000000].\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tsegsites = (int)segsites_long;\n\t\t\t\t\n\t\t\t\tif (iss >> sub)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): malformed segsites line; additional content after segsites value.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tparse_state = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\t// Expecting \"positions: a b c...\"\n\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\n\t\t\t\tiss >> sub;\n\t\t\t\tif (sub != \"positions:\")\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): expecting 'positions:', found '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tfor (int pos_index = 0; pos_index < segsites; ++pos_index)\n\t\t\t\t{\n\t\t\t\t\tif (!(iss >> sub))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): missing positions value.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tdouble pos_double = EidosInterpreter::FloatForString(sub, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tif ((pos_double < 0.0) || (pos_double > 1.0))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): readMS() requires positions in [0,1].\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// BCH 26 Jan. 2020: There is a little subtlety here.  This equation, round(pos * L), provides\n\t\t\t\t\t// the exact inverse of what outputHaplosomesToMS() / outputMSSample() do, so it should exactly recover\n\t\t\t\t\t// positions written out by SLiM in MS format (modulo numerical error).  However, it results\n\t\t\t\t\t// in half as much \"mutational density\" at positions 0 and L as at other positions, if the\n\t\t\t\t\t// positions are uniformly distributed in [0,1] rather than originating in SLiM.  In that case,\n\t\t\t\t\t// min(floor(pos*(L+1)), L) would be better.  Maybe this choice ought to be an optional logical\n\t\t\t\t\t// parameter to readHaplosomesFromMS(), but nobody has complained yet, so I'm ignoring it for now; if\n\t\t\t\t\t// you expect to get exact discrete base positions you shouldn't be using MS format anyway...\n\t\t\t\t\tpositions.emplace_back((slim_position_t)round(pos_double * last_position));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (iss >> sub)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): malformed positions line; additional content after last expected position.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tparse_state = 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t// Expecting \"001010011001101111010...\" of length segsites\n\t\t\t\tif (line.find_first_not_of(\"01\") != std::string::npos)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): call lines must be composed entirely of 0 and 1.\" << EidosTerminate();\n\t\t\t\tif ((int)line.length() != segsites)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): call lines must be equal in length to the segsites value.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tcalls.emplace_back(line);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): (internal error) unhandled case.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tinfile.close();\n\t\n\tif ((int)calls.size() != target_size)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): target haplosome vector has size \" << target_size << \" but \" << calls.size() << \" call lines found.\" << EidosTerminate();\n\t\n\t// Instantiate the mutations; NOTE THAT THE STACKING POLICY IS NOT CHECKED HERE, AS THIS IS NOT CONSIDERED THE ADDITION OF A MUTATION!\n\tstd::vector<MutationIndex> mutation_indices;\n\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\n\tfor (int mut_index = 0; mut_index < segsites; ++mut_index)\n\t{\n\t\tslim_position_t position = positions[mut_index];\n\t\tdouble selection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\tslim_objectid_t subpop_index = -1;\n\t\tslim_tick_t origin_tick = community.Tick();\n\t\tint8_t nucleotide = -1;\n\t\t\n\t\tif (nucleotide_based && mutation_type_ptr->nucleotide_based_)\n\t\t{\n\t\t\t// select a nucleotide that is different from the ancestral state at this position\n\t\t\tint8_t ancestral = (int8_t)chromosome->AncestralSequence()->NucleotideAtIndex(position);\n\t\t\t\n\t\t\tnucleotide = (int8_t)Eidos_rng_interval_uint32(rng_32, 3);\t// 0, 1, 2\n\t\t\t\n\t\t\tif (nucleotide == ancestral)\n\t\t\t\tnucleotide++;\n\t\t}\n\t\t\n\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\n\t\tMutation *new_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_type_ptr, chromosome->Index(), position, selection_coeff, subpop_index, origin_tick, nucleotide);\n\t\t\n\t\t// This mutation type might not be used by any genomic element type (i.e. might not already be vetted), so we need to check and set pure_neutral_\n\t\tif (selection_coeff != 0.0)\n\t\t{\n\t\t\tspecies.pure_neutral_ = false;\n\t\t\t\n\t\t\t// the selection coefficient was drawn from the mutation type's DFE, so there is no need to set all_pure_neutral_DFE_\n\t\t\t//mutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t}\n\t\t\n\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\tpop.MutationRegistryAdd(new_mut);\n\t\tmutation_indices.emplace_back(new_mut_index);\n\t}\n\t\n\t// Sort the mutations by position so we can add them in order, and make an \"order\" vector for accessing calls in the sorted order\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tstd::vector<int64_t> order_vec = EidosSortIndexes(positions);\n\t\n\tstd::sort(mutation_indices.begin(), mutation_indices.end(), [mut_block_ptr](MutationIndex i1, MutationIndex i2) {return (mut_block_ptr + i1)->position_ < (mut_block_ptr + i2)->position_;});\n\t\n\t// Add the mutations to the target haplosomes, recording a new derived state with each addition\n#ifndef _OPENMP\n\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\t\n\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t{\n\t\tHaplosome *haplosome = targets_data[haplosome_index];\n\t\t\n\t\tif (haplosome->IsNull())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromMS): readHaplosomesFromMS() does not allow null haplosomes in the target haplosome vector.\" << EidosTerminate();\n\t\t\n\t\tbool haplosome_started_empty = (haplosome->mutation_count() == 0);\n\t\tslim_position_t mutrun_length = haplosome->mutrun_length_;\n\t\tslim_mutrun_index_t current_run_index = -1;\n\t\tMutationRun *current_mutrun = nullptr;\n\t\tstd::string &haplosome_string = calls[haplosome_index];\n\t\t\n\t\tfor (int segsite_index = 0; segsite_index < segsites; ++segsite_index)\n\t\t{\n\t\t\tint64_t call_index = order_vec[segsite_index];\n\t\t\tchar call = haplosome_string[call_index];\n\t\t\t\n\t\t\tif (call == '1')\n\t\t\t{\n\t\t\t\tMutationIndex mut_index = mutation_indices[segsite_index];\n\t\t\t\tMutation *mut = mut_block_ptr + mut_index;\n\t\t\t\tslim_position_t mut_pos = mut->position_;\n\t\t\t\tslim_mutrun_index_t mut_mutrun_index = (slim_mutrun_index_t)(mut_pos / mutrun_length);\n\t\t\t\t\n\t\t\t\tif (mut_mutrun_index != current_run_index)\n\t\t\t\t{\n#ifdef _OPENMP\n\t\t\t\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\t\t\t\tMutationRunContext &mutrun_context = species.ChromosomeMutationRunContextForMutationRunIndex(mut_mutrun_index);\n#endif\n\t\t\t\t\t\n\t\t\t\t\tcurrent_run_index = mut_mutrun_index;\n\t\t\t\t\t\n\t\t\t\t\t// We use WillModifyRun() because these are existing haplosomes we didn't create, and their runs may be shared; we have\n\t\t\t\t\t// no way to tell.  We avoid making excessive mutation run copies by calling this only once per mutrun per haplosome.\n\t\t\t\t\tcurrent_mutrun = haplosome->WillModifyRun(mut_mutrun_index, mutrun_context);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If the haplosome started empty, we can add mutations to the end with emplace_back(); if it did not, then they need to be inserted\n\t\t\t\tif (haplosome_started_empty)\n\t\t\t\t\tcurrent_mutrun->emplace_back(mut_index);\n\t\t\t\telse\n\t\t\t\t\tcurrent_mutrun->insert_sorted_mutation(mut_index);\n\t\t\t\t\n\t\t\t\tif (recording_mutations)\n\t\t\t\t\tspecies.RecordNewDerivedState(haplosome, mut_pos, *haplosome->derived_mutation_ids_at_position(mut_pos));\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Return the instantiated mutations\n\tint mutation_count = (int)mutation_indices.size();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(mutation_count);\n\t\n\tfor (int mut_index = 0; mut_index < mutation_count; ++mut_index)\n\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + mutation_indices[mut_index], mut_index);\n\t\n\treturn EidosValue_Object_SP(vec);\n}\n\n//\t*********************\t+ (o<Mutation>)readHaplosomesFromVCF(s$ filePath = NULL, [Nio<MutationType> mutationType = NULL])\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_interpreter)\n\t// BEWARE: This method shares a great deal of code with Individual_Class::ExecuteMethod_readIndividualsFromVCF().  Maintain in parallel.\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF(): SLiM global state read\");\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *mutationType_value = p_arguments[1].get();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (p_target->Count() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): \" << \"readHaplosomesFromVCF() requires a target Haplosome vector of length 1 or more, so that the species of the target can be determined.\" << EidosTerminate();\n\t\n\tSpecies *species = Community::SpeciesForHaplosomes(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): \" << \"readHaplosomesFromVCF() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF\");\n\t\n\t// All haplosomes must belong to the same chromosome, and in multichrom models the CHROM field must match its symbol\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\tbool model_is_multi_chromosome = (chromosomes.size() > 1);\n\tHaplosome * const *targets_data = (Haplosome * const *)p_target->ObjectData();\n\tint target_size = p_target->Count();\n\tHaplosome *haplosome_0 = targets_data[0];\n\tslim_chromosome_index_t chromosome_index = haplosome_0->chromosome_index_;\n\tChromosome *chromosome = chromosomes[chromosome_index];\n\tstd::string chromosome_symbol = chromosome->Symbol();\n\t\n\tif (species->Chromosomes().size() > 1)\n\t{\n\t\t// We have to check for consistency if there's more than one chromosome\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\tif (targets_data[haplosome_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): \" << \"readHaplosomesFromVCF() requires that all target haplosomes are associated with the same chromosome.\" << EidosTerminate();\n\t}\n\t\n\tCommunity &community = species->community_;\n\tPopulation &pop = species->population_;\n\tslim_position_t last_position = chromosome->last_position_;\n\tbool recording_mutations = species->RecordingTreeSequenceMutations();\n\tbool nucleotide_based = species->IsNucleotideBased();\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n\tMutationType *default_mutation_type_ptr = nullptr;\n\t\n\tif (mutationType_value->Type() != EidosValueType::kValueNULL)\n\t\tdefault_mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutationType_value, 0, &community, species, \"readHaplosomesFromVCF()\");\t\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Parse the whole input file and retain the information from it\n\tstd::ifstream infile(file_path);\n\t\n\tif (!infile)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): could not read file at path \" << file_path << \".\" << EidosTerminate();\n\t\n\tstd::string line, sub;\n\tint parse_state = 0;\n\tint sample_id_count = 0;\n\tbool info_MID_defined = false, info_S_defined = false, info_DOM_defined = false, info_PO_defined = false;\n\tbool info_GO_defined = false, info_TO_defined = false, info_MT_defined = false, /*info_AA_defined = false,*/ info_NONNUC_defined = false;\n\tstd::vector<std::pair<slim_position_t, std::string>> call_lines;\n\t\n\twhile (!infile.eof())\n\t{\n\t\tgetline(infile, line);\n\t\t\n\t\tswitch (parse_state)\n\t\t{\n\t\t\tcase 0:\n\t\t\t{\n\t\t\t\t// In header, parsing ## lines, until we get to the #CHROM line; the point of this is that we only want to interpret\n\t\t\t\t// INFO fields like MID, S, etc. as having their SLiM-specific meaning if their SLiM-specific definition is present\n\t\t\t\tif (line.compare(0, 2, \"##\") == 0)\n\t\t\t\t{\n\t\t\t\t\tif (line == \"##INFO=<ID=MID,Number=.,Type=Integer,Description=\\\"Mutation ID in SLiM\\\">\")\tinfo_MID_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=S,Number=.,Type=Float,Description=\\\"Selection Coefficient\\\">\")\t\tinfo_S_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=DOM,Number=.,Type=Float,Description=\\\"Dominance\\\">\")\t\t\t\tinfo_DOM_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=PO,Number=.,Type=Integer,Description=\\\"Population of Origin\\\">\")\tinfo_PO_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=GO,Number=.,Type=Integer,Description=\\\"Generation of Origin\\\">\")\tinfo_GO_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=TO,Number=.,Type=Integer,Description=\\\"Tick of Origin\\\">\")\t\t\tinfo_TO_defined = true;\t\t// SLiM 4 emits TO (tick) instead of GO (generation)\n\t\t\t\t\tif (line == \"##INFO=<ID=MT,Number=.,Type=Integer,Description=\\\"Mutation Type\\\">\")\t\t\tinfo_MT_defined = true;\n\t\t\t\t\t/*if (line == \"##INFO=<ID=AA,Number=1,Type=String,Description=\\\"Ancestral Allele\\\">\")\t\t\tinfo_AA_defined = true;*/\t\t// this one is standard, so we don't require this definition\n\t\t\t\t\tif (line == \"##INFO=<ID=NONNUC,Number=0,Type=Flag,Description=\\\"Non-nucleotide-based\\\">\")\tinfo_NONNUC_defined = true;\n\t\t\t\t}\n\t\t\t\telse if (line.compare(0, 1, \"#\") == 0)\n\t\t\t\t{\n\t\t\t\t\tstatic const char *header_fields[9] = {\"CHROM\", \"POS\", \"ID\", \"REF\", \"ALT\", \"QUAL\", \"FILTER\", \"INFO\", \"FORMAT\"};\n\t\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\t\n\t\t\t\t\tiss.get();\t// eat the initial #\n\t\t\t\t\t\n\t\t\t\t\t// verify that the expected standard columns are present\n\t\t\t\t\tfor (const char *header_field : header_fields)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!(iss >> sub))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): missing VCF header '\" << header_field << \"'.\" << EidosTerminate();\n\t\t\t\t\t\tif (sub != header_field)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): expected VCF header '\" << header_field << \"', saw '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// the remaining columns are sample IDs; we don't care what they are, we just count them\n\t\t\t\t\twhile (iss >> sub)\n\t\t\t\t\t\tsample_id_count++;\n\t\t\t\t\t\n\t\t\t\t\t// now the remainder of the file should be call lines\n\t\t\t\t\tparse_state = 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): unexpected line in VCF header: '\" << line << \"'.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\t// In call lines, fields are separated by tabs, and could theoretically contain spaces; here we just read a whole line,\n\t\t\t\t// extract the position field for the mutation, and save the line indexed by its mutation's position for later handling\n\t\t\t\tif (line.length() == 0)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\n\t\t\t\tstd::getline(iss, sub, '\\t');\t// CHROM\n\t\t\t\t\n\t\t\t\tif (model_is_multi_chromosome)\n\t\t\t\t{\n\t\t\t\t\t// in multi-chromosome models the CHROM value must match the associated chromosome of the haplosomes\n\t\t\t\t\tif (sub != chromosome_symbol)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): the CHROM field's value (\\\"\" << sub << \"\\\") in a call line does not match the symbol (\\\"\" << chromosome_symbol << \"\\\") for the focal chromosome with which the target haplosomes are associated.  In multi-chromosome models, the CHROM field is required to match the chromosome symbol to prevent bugs.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// in single-chromosome models the CHROM value must be consistent across the whole file, but need not match\n\t\t\t\t\tif (call_lines.size() == 0)\n\t\t\t\t\t\tchromosome_symbol = sub;\t// first call line's CHROM symbol gets remembered\n\t\t\t\t\telse if (sub != chromosome_symbol)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): the CHROM field's value (\\\"\" << sub << \"\\\") in a call line does not match the initial CHROM field's value (\\\"\" << chromosome_symbol << \"\\\").  In single-chromosome models, the CHROM field is required to have a single consistent value across all call lines to prevent bugs.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tstd::getline(iss, sub, '\\t');\t// POS\n\t\t\t\t\n\t\t\t\tint64_t pos = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr) - 1;\t\t// -1 because VCF uses 1-based positions\n\t\t\t\t\n\t\t\t\tif ((pos < 0) || (pos > last_position))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file POS value \" << pos << \" out of range.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tcall_lines.emplace_back(pos, line);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): (internal error) unhandled case.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tinfile.close();\n\t\n\t// sort the call lines by position, so that we can add them to empty haplosomes efficiently\n\tstd::sort(call_lines.begin(), call_lines.end(), [ ](const std::pair<slim_position_t, std::string> &l1, const std::pair<slim_position_t, std::string> &l2) {return l1.first < l2.first;});\n\t\n\t// cache target haplosomes and determine whether they are initially empty, in which case we can do fast mutation addition with emplace_back()\n\tstd::vector<Haplosome *> targets;\n\tstd::vector<slim_mutrun_index_t> target_last_mutrun_modified;\n\tstd::vector<MutationRun *> target_last_mutrun;\n\tbool all_target_haplosomes_started_empty = true;\n\t\n\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t{\n\t\tHaplosome *haplosome = targets_data[haplosome_index];\n\t\t\n\t\t// null haplosomes are silently excluded from the target list, for convenience\n\t\tif (!haplosome->IsNull())\n\t\t{\n\t\t\tif (haplosome->mutation_count() != 0)\n\t\t\t\tall_target_haplosomes_started_empty = false;\n\t\t\t\n\t\t\ttargets.emplace_back(haplosome);\n\t\t\ttarget_last_mutrun_modified.emplace_back(-1);\n\t\t\ttarget_last_mutrun.emplace_back(nullptr);\n\t\t}\n\t}\n\t\n\ttarget_size = (int)targets.size();\t// adjust for possible exclusion of null haplosomes\n\t\n\t// parse all the call lines, instantiate their mutations, and add the mutations to the target haplosomes\n#ifndef _OPENMP\n\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\tstd::vector<MutationIndex> mutation_indices;\n\tbool has_initial_mutations = (gSLiM_next_mutation_id != 0);\n\t\n\tfor (std::pair<slim_position_t, std::string> &call_line : call_lines)\n\t{\n\t\tslim_position_t mut_position = call_line.first;\n\t\tstd::istringstream iss(call_line.second);\n\t\tstd::string ref_str, alt_str, info_str;\n\t\t\n\t\tstd::getline(iss, sub, '\\t');\t\t// CHROM; don't care (already checked it above)\n\t\tstd::getline(iss, sub, '\\t');\t\t// POS; already fetched\n\t\tstd::getline(iss, sub, '\\t');\t\t// ID; don't care\n\t\tstd::getline(iss, ref_str, '\\t');\t// REF\n\t\tstd::getline(iss, alt_str, '\\t');\t// ALT\n\t\tstd::getline(iss, sub, '\\t');\t\t// QUAL; don't care\n\t\tstd::getline(iss, sub, '\\t');\t\t// FILTER; don't care\n\t\tstd::getline(iss, info_str, '\\t');\t// INFO\n\t\tstd::getline(iss, sub, '\\t');\t\t// FORMAT; don't care (GT must be first, according to the standard; we don't check)\n\t\t\n\t\t// parse/validate the REF nucleotide\n\t\tint8_t ref_nuc;\n\t\t\n\t\tif (ref_str == \"A\")\t\t\tref_nuc = 0;\n\t\telse if (ref_str == \"C\")\tref_nuc = 1;\n\t\telse if (ref_str == \"G\")\tref_nuc = 2;\n\t\telse if (ref_str == \"T\")\tref_nuc = 3;\n\t\telse\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file REF value must be A/C/G/T.\" << EidosTerminate();\n\t\t\n\t\t// parse/validate the ALT nucleotides\n\t\tstd::vector<std::string> alt_substrs = Eidos_string_split(alt_str, \",\");\n\t\tstd::vector<int8_t> alt_nucs;\n\t\t\n\t\tfor (std::string &alt_substr : alt_substrs)\n\t\t{\n\t\t\tif (alt_substr == \"A\")\t\t\talt_nucs.emplace_back(0);\n\t\t\telse if (alt_substr == \"C\")\t\talt_nucs.emplace_back(1);\n\t\t\telse if (alt_substr == \"G\")\t\talt_nucs.emplace_back(2);\n\t\t\telse if (alt_substr == \"T\")\t\talt_nucs.emplace_back(3);\n\t\t\telse\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file ALT value must be A/C/G/T.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tstd::size_t alt_allele_count = alt_nucs.size();\n\t\t\n\t\t// parse/validate the INFO fields that we recognize\n\t\tstd::vector<std::string> info_substrs = Eidos_string_split(info_str, \";\");\n\t\tstd::vector<slim_mutationid_t> info_mutids;\n\t\tstd::vector<double> info_selcoeffs;\n\t\tstd::vector<double> info_domcoeffs;\n\t\tstd::vector<slim_objectid_t> info_poporigin;\n\t\tstd::vector<slim_tick_t> info_tickorigin;\n\t\tstd::vector<slim_objectid_t> info_muttype;\n\t\tint8_t info_ancestral_nuc = -1;\n\t\tbool info_is_nonnuc = false;\n\t\t\n\t\tfor (std::string &info_substr : info_substrs)\n\t\t{\n\t\t\tif (info_MID_defined && (info_substr.compare(0, 4, \"MID=\") == 0))\t\t// Mutation ID\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(4), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_mutids.emplace_back((slim_mutationid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t\n\t\t\t\tif (info_mutids.size() && has_initial_mutations)\n\t\t\t\t{\n\t\t\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!community.warned_readFromVCF_mutIDs_unused_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): readHaplosomesFromVCF(): the VCF file specifies mutation IDs with the MID field, but some mutation IDs have already been used so uniqueness cannot be guaranteed.  Use of mutation IDs is therefore disabled; mutations will not receive the mutation ID requested in the file.  To fix this warning, remove the MID field from the VCF file before reading.  To get readHaplosomesFromVCF() to use the specified mutation IDs, load the VCF file into a model that has never simulated a mutation, and has therefore not used any mutation IDs.\" << std::endl;\n\t\t\t\t\t\t\tcommunity.warned_readFromVCF_mutIDs_unused_ = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// disable use of MID for this read\n\t\t\t\t\tinfo_MID_defined = false;\n\t\t\t\t\tinfo_mutids.clear();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (info_S_defined && (info_substr.compare(0, 2, \"S=\") == 0))\t\t// Selection Coefficient\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(2), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_selcoeffs.emplace_back(EidosInterpreter::FloatForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (info_DOM_defined && (info_substr.compare(0, 4, \"DOM=\") == 0))\t// Dominance Coefficient\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(4), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_domcoeffs.emplace_back(EidosInterpreter::FloatForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (info_PO_defined && (info_substr.compare(0, 3, \"PO=\") == 0))\t// Population of Origin\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_poporigin.emplace_back((slim_objectid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (info_TO_defined && (info_substr.compare(0, 3, \"TO=\") == 0))\t// Tick of Origin\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_tickorigin.emplace_back((slim_tick_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (info_GO_defined && (info_substr.compare(0, 3, \"GO=\") == 0))\t// Generation of Origin - emitted by SLiM 3, treated as TO here\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_tickorigin.emplace_back((slim_tick_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (info_MT_defined && (info_substr.compare(0, 3, \"MT=\") == 0))\t// Mutation Type\n\t\t\t{\n\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\n\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\tinfo_muttype.emplace_back((slim_objectid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t}\n\t\t\telse if (/* info_AA_defined && */ (info_substr.compare(0, 3, \"AA=\") == 0))\t// Ancestral Allele; definition not required since it is a standard field\n\t\t\t{\n\t\t\t\tstd::string aa_str = info_substr.substr(3);\n\t\t\t\t\n\t\t\t\tif (aa_str == \"A\")\t\t\tinfo_ancestral_nuc = 0;\n\t\t\t\telse if (aa_str == \"C\")\t\tinfo_ancestral_nuc = 1;\n\t\t\t\telse if (aa_str == \"G\")\t\tinfo_ancestral_nuc = 2;\n\t\t\t\telse if (aa_str == \"T\")\t\tinfo_ancestral_nuc = 3;\n\t\t\t\telse\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file AA value must be A/C/G/T.\" << EidosTerminate();\n\t\t\t}\n\t\t\telse if (info_NONNUC_defined && (info_substr == \"NONNUC\"))\t\t\t\t// Non-nucleotide-based\n\t\t\t{\n\t\t\t\tinfo_is_nonnuc = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ((info_mutids.size() != 0) && (info_mutids.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for MID field.\" << EidosTerminate();\n\t\t\tif ((info_selcoeffs.size() != 0) && (info_selcoeffs.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for S field.\" << EidosTerminate();\n\t\t\tif ((info_domcoeffs.size() != 0) && (info_domcoeffs.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for DOM field.\" << EidosTerminate();\n\t\t\tif ((info_poporigin.size() != 0) && (info_poporigin.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for PO field.\" << EidosTerminate();\n\t\t\tif ((info_tickorigin.size() != 0) && (info_tickorigin.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for GO or TO field.\" << EidosTerminate();\n\t\t\tif ((info_muttype.size() != 0) && (info_muttype.size() != alt_allele_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file unexpected value count for MT field.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// read the genotype data for each sample id, which might be diploid or haploid, and might have data beyond GT\n\t\tstd::vector<int> genotype_calls;\n\t\t\n\t\tfor (int sample_index = 0; sample_index < sample_id_count; ++sample_index)\n\t\t{\n\t\t\tif (iss.eof())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file call line ended unexpectedly before the last sample.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::getline(iss, sub, '\\t');\n\t\t\t\n\t\t\t// extract just the GT field if others are present\n\t\t\tstd::size_t colon_pos = sub.find_first_of(':');\n\t\t\t\n\t\t\tif (colon_pos != std::string::npos)\n\t\t\t\tsub = sub.substr(0, colon_pos);\n\t\t\t\n\t\t\t// separate haploid calls that are joined by | or /; this is the hotspot of the whole method, so we try to be efficient here\n\t\t\tbool call_handled = false;\n\t\t\t\n\t\t\tif ((sub.length() == 3) && ((sub[1] == '|') || (sub[1] == '/')))\n\t\t\t{\n\t\t\t\t// diploid, both single-digit\n\t\t\t\tchar sub_ch1 = sub[0];\n\t\t\t\tchar sub_ch2 = sub[2];\n\t\t\t\t\n\t\t\t\tif ((sub_ch1 >= '0') && (sub_ch1 <= '9') && (sub_ch2 >= '0') && (sub_ch2 <= '9'))\n\t\t\t\t{\n\t\t\t\t\tint genotype_call1 = (int)(sub_ch1 - '0');\n\t\t\t\t\tint genotype_call2 = (int)(sub_ch2 - '0');\n\t\t\t\t\t\n\t\t\t\t\tif ((genotype_call1 < 0) || (genotype_call1 > (int)alt_allele_count) || (genotype_call2 < 0) || (genotype_call2 > (int)alt_allele_count))\t// 0 is REF, 1..n are ALT alleles\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file call out of range (does not correspond to a REF or ALT allele in the call line).\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tgenotype_calls.emplace_back(genotype_call1);\n\t\t\t\t\tgenotype_calls.emplace_back(genotype_call2);\n\t\t\t\t\tcall_handled = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (sub.length() == 1)\n\t\t\t{\n\t\t\t\tchar sub_ch = sub[0];\n\t\t\t\t\n\t\t\t\tif (sub_ch == '~')\n\t\t\t\t{\n\t\t\t\t\t// If the call is ~, a tilde, it indicates that no genetic information is present\n\t\t\t\t\t// (this is the case for a female if we're reading Y-chromosome data, for example).\n\t\t\t\t\t// We do not add anything to genotype_calls; it is as if this call does not exist.\n\t\t\t\t\t// Note that this is not part of the VCF standard; it had to be invented for SLiM.\n\t\t\t\t\tcall_handled = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// haploid, single-digit\n\t\t\t\t\tif ((sub_ch >= '0') && (sub_ch <= '9'))\n\t\t\t\t\t{\n\t\t\t\t\t\tint genotype_call = (int)(sub_ch - '0');\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((genotype_call < 0) || (genotype_call > (int)alt_allele_count))\t// 0 is REF, 1..n are ALT alleles\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file call out of range (does not correspond to a REF or ALT allele in the call line).\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tgenotype_calls.emplace_back(genotype_call);\n\t\t\t\t\t\tcall_handled = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!call_handled)\n\t\t\t{\n\t\t\t\tstd::vector<std::string> genotype_substrs;\n\t\t\t\t\n\t\t\t\tif (sub.find('|') != std::string::npos)\n\t\t\t\t\tgenotype_substrs = Eidos_string_split(sub, \"|\");\t// phased\n\t\t\t\telse if (sub.find('/') != std::string::npos)\n\t\t\t\t\tgenotype_substrs = Eidos_string_split(sub, \"/\");\t// unphased; we don't worry about that\n\t\t\t\telse\n\t\t\t\t\tgenotype_substrs.emplace_back(sub);\t\t\t\t\t// haploid, presumably\n\t\t\t\t\n\t\t\t\tif ((genotype_substrs.size() < 1) || (genotype_substrs.size() > 2))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file genotype calls must be diploid or haploid; \" << genotype_substrs.size() << \" calls found in one sample.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// extract the calls' integer values, validate them, and keep them; we don't care which call was in which sample, we just preserve their order\n\t\t\t\tfor (std::string &genotype_substr : genotype_substrs)\n\t\t\t\t{\n\t\t\t\t\tstd::size_t genotype_call = EidosInterpreter::NonnegativeIntegerForString(genotype_substr, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tif (/*(genotype_call < 0) ||*/ (genotype_call > alt_allele_count))\t// 0 is REF, 1..n are ALT alleles\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file call out of range (does not correspond to a REF or ALT allele in the call line).\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tgenotype_calls.emplace_back((int)genotype_call);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!iss.eof())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file call line has unexpected entries following the last sample.\" << EidosTerminate();\n\t\tif ((int)genotype_calls.size() != target_size)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): target haplosome vector has size \" << target_size << \" but \" << genotype_calls.size() << \" calls were found in one call line.\" << EidosTerminate();\n\t\t\n\t\t// We have one call for each non-null target haplosome, so the requirement for this function is met.\n\t\t// Note that there is no checking that a ~ matches the position of a null haplosome in the target\n\t\t// vector; we have no concept of \"individuals\", we just match haplosomes to calls for each line.\n\t\t// The Individual version of readHaplosomesFromVCF() can be smarter, since it understands individuals.\n\t\t\n\t\t// instantiate the mutations involved in this call line; the REF allele represents no mutation, ALT alleles are each separate mutations\n\t\tstd::vector<MutationIndex> alt_allele_mut_indices;\n\t\t\n\t\tfor (std::size_t alt_allele_index = 0; alt_allele_index < alt_allele_count; ++alt_allele_index)\n\t\t{\n\t\t\t// figure out the mutation type; if specified with MT, look it up, otherwise use the default supplied\n\t\t\tMutationType *mutation_type_ptr = default_mutation_type_ptr;\n\t\t\t\n\t\t\tif (info_muttype.size() > 0)\n\t\t\t{\n\t\t\t\tslim_objectid_t mutation_type_id = info_muttype[alt_allele_index];\n                \n                mutation_type_ptr = species->MutationTypeWithID(mutation_type_id);\n\t\t\t\t\n\t\t\t\tif (!mutation_type_ptr)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file MT field references a mutation type m\" << mutation_type_id << \" that is not defined.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tif (!mutation_type_ptr)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file MT field missing, but no default mutation type was supplied in the mutationType parameter.\" << EidosTerminate();\n\t\t\t\n\t\t\t// check the dominance coefficient of DOM against that of the mutation type\n\t\t\tif (info_domcoeffs.size() > 0)\n\t\t\t{\n\t\t\t\tif (std::abs(info_domcoeffs[alt_allele_index] - mutation_type_ptr->dominance_coeff_) > 0.0001)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): VCF file DOM field specifies a dominance coefficient \" << info_domcoeffs[alt_allele_index] << \" that differs from the mutation type's dominance coefficient of \" << mutation_type_ptr->dominance_coeff_ << \".\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\t// get the selection coefficient from S, or draw one\n\t\t\tdouble selection_coeff;\n\t\t\t\n\t\t\tif (info_selcoeffs.size() > 0)\n\t\t\t\tselection_coeff = info_selcoeffs[alt_allele_index];\n\t\t\telse\n\t\t\t\tselection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\t\t\n\t\t\t// get the subpop index from PO, or set to -1; no bounds checking on this\n\t\t\tslim_objectid_t subpop_index = -1;\n\t\t\t\n\t\t\tif (info_poporigin.size() > 0)\n\t\t\t\tsubpop_index = info_poporigin[alt_allele_index];\n\t\t\t\n\t\t\t// get the origin tick from gO, or set to the current tick; no bounds checking on this\n\t\t\tslim_tick_t origin_tick;\n\t\t\t\n\t\t\tif (info_tickorigin.size() > 0)\n\t\t\t\torigin_tick = info_tickorigin[alt_allele_index];\n\t\t\telse\n\t\t\t\torigin_tick = community.Tick();\n\t\t\t\n\t\t\t// figure out the nucleotide and do nucleotide-related checks\n\t\t\tint8_t alt_allele_nuc = alt_nucs[alt_allele_index];\t\t// must be defined, in all cases, but might be ignored\n\t\t\tint8_t nucleotide;\n\t\t\t\n\t\t\tif (nucleotide_based)\n\t\t\t{\n\t\t\t\tif (info_NONNUC_defined)\n\t\t\t\t{\n\t\t\t\t\t// We are reading a SLiM-generated VCF file that uses NONNUC to designate non-nucleotide-based mutations\n\t\t\t\t\tif (info_is_nonnuc)\n\t\t\t\t\t{\n\t\t\t\t\t\t// This call line is marked NONNUC, so there is no associated nucleotide; check against the mutation type\n\t\t\t\t\t\tif (mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): a mutation marked NONNUC cannot use a nucleotide-based mutation type.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tnucleotide = -1;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// This call line is not marked NONNUC, so it represents nucleotide-based alleles\n\t\t\t\t\t\tif (!mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): a nucleotide-based mutation cannot use a non-nucleotide-based mutation type.\" << EidosTerminate();\n\t\t\t\t\t\tif (ref_nuc != info_ancestral_nuc)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): the REF nucleotide does not match the AA nucleotide.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tint8_t ancestral = (int8_t)chromosome->AncestralSequence()->NucleotideAtIndex(mut_position);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (ancestral != ref_nuc)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): the REF/AA nucleotide does not match the ancestral nucleotide at the same position; a matching ancestral nucleotide sequence must be set prior to calling readHaplosomesFromVCF().\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tnucleotide = alt_allele_nuc;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We are reading a generic VCF file that does not use NONNUC, so we follow the mutation type's lead; if it is nucleotide-based, we use the nucleotide specified\n\t\t\t\t\tif (mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation type is nucleotide-based, so use the nucleotide specified; in this case we ignore REF and AA, however\n\t\t\t\t\t\tnucleotide = alt_allele_nuc;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation type is non-nucleotide-based, so we ignore the nucleotide supplied, as well as REF/AA\n\t\t\t\t\t\tnucleotide = -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We are a non-nucleotide-based model, so NONNUC should not be defined; we do not understand nucleotides and will ignore them\n\t\t\t\tif (info_NONNUC_defined)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF): cannot read a VCF file generated by a nucleotide-based model into a non-nucleotide-based model.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tnucleotide = -1;\n\t\t\t}\n\t\t\t\n\t\t\t// instantiate the mutation with the values decided upon\n\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\tMutation *new_mut;\n\t\t\t\n\t\t\tif (info_mutids.size() > 0)\n\t\t\t{\n\t\t\t\t// a mutation ID was supplied; we use it blindly, having checked above that we are in the case where this is legal\n\t\t\t\tslim_mutationid_t mut_mutid = info_mutids[alt_allele_index];\n\t\t\t\t\n\t\t\t\tnew_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mut_mutid, mutation_type_ptr, chromosome->Index(), mut_position, selection_coeff, subpop_index, origin_tick, nucleotide);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// no mutation ID supplied, so use whatever is next\n\t\t\t\tnew_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_type_ptr, chromosome->Index(), mut_position, selection_coeff, subpop_index, origin_tick, nucleotide);\n\t\t\t}\n\t\t\t\n\t\t\t// This mutation type might not be used by any genomic element type (i.e. might not already be vetted), so we need to check and set pure_neutral_\n\t\t\t// The selection coefficient might have been supplied by the user (i.e., not be from the mutation type's DFE), so we set all_pure_neutral_DFE_ also\n\t\t\tif (selection_coeff != 0.0)\n\t\t\t{\n\t\t\t\tspecies->pure_neutral_ = false;\n\t\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t\t}\n\t\t\t\n\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\tpop.MutationRegistryAdd(new_mut);\n\t\t\talt_allele_mut_indices.emplace_back(new_mut_index);\n\t\t\tmutation_indices.emplace_back(new_mut_index);\n\t\t}\n\t\t\n\t\t// add the mutations to the appropriate haplosomes and record the new derived states\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tint call = genotype_calls[haplosome_index];\n\t\t\t\n\t\t\tif (call != 0)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = targets[haplosome_index];\n\t\t\t\tslim_mutrun_index_t &haplosome_last_mutrun_modified = target_last_mutrun_modified[haplosome_index];\n\t\t\t\tMutationRun *&haplosome_last_mutrun = target_last_mutrun[haplosome_index];\n\t\t\t\tslim_position_t mutrun_length = haplosome->mutrun_length_;\n\t\t\t\tMutationIndex mut_index = alt_allele_mut_indices[call - 1];\n\t\t\t\tslim_mutrun_index_t mut_mutrun_index = (slim_mutrun_index_t)(mut_position / mutrun_length);\n\t\t\t\t\n\t\t\t\tif (mut_mutrun_index != haplosome_last_mutrun_modified)\n\t\t\t\t{\n#ifdef _OPENMP\n\t\t\t\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\t\t\t\tMutationRunContext &mutrun_context = species->ChromosomeMutationRunContextForMutationRunIndex(mut_mutrun_index);\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// We use WillModifyRun() because these are existing haplosomes we didn't create, and their runs may be shared; we have\n\t\t\t\t\t// no way to tell.  We avoid making excessive mutation run copies by calling this only once per mutrun per haplosome.\n\t\t\t\t\thaplosome_last_mutrun = haplosome->WillModifyRun(mut_mutrun_index, mutrun_context);\n\t\t\t\t\thaplosome_last_mutrun_modified = mut_mutrun_index;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If the haplosome started empty, we can add mutations to the end with emplace_back(); if it did not, then they need to be inserted\n\t\t\t\tif (all_target_haplosomes_started_empty)\n\t\t\t\t\thaplosome_last_mutrun->emplace_back(mut_index);\n\t\t\t\telse\n\t\t\t\t\thaplosome_last_mutrun->insert_sorted_mutation(mut_index);\n\t\t\t\t\n\t\t\t\tif (recording_mutations)\n\t\t\t\t\tspecies->RecordNewDerivedState(haplosome, mut_position, *haplosome->derived_mutation_ids_at_position(mut_position));\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Return the instantiated mutations\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint mutation_count = (int)mutation_indices.size();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(mutation_count);\n\t\n\tfor (int mut_index = 0; mut_index < mutation_count; ++mut_index)\n\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + mutation_indices[mut_index], mut_index);\n\t\n\treturn EidosValue_Object_SP(vec);\n}\n\n//\t*********************\t+ (void)removeMutations([No<Mutation> mutations = NULL], [logical$ substitute = F])\n//\nEidosValue_SP Haplosome_Class::ExecuteMethod_removeMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\tEidosValue *mutations_value = p_arguments[0].get();\n\tEidosValue *substitute_value = p_arguments[1].get();\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint target_size = p_target->Count();\n\t\n\tif (target_size == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForHaplosomes(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() requires that all target haplosomes belong to the same species.\" << EidosTerminate();\n\t\n\t// All haplosomes must belong to the same chromosome, and all mutations being added must belong to that chromosome too.\n\t// It's important that a mismatch result in an error; attempts to add mutations to chromosomes inconsistently should be flagged.\n\tint mutations_count = mutations_value->Count();\n\tHaplosome * const *targets_data = (Haplosome * const *)p_target->ObjectData();\n\tHaplosome *haplosome_0 = targets_data[0];\n\tslim_chromosome_index_t chromosome_index = haplosome_0->chromosome_index_;\n\t\n\tif (species->Chromosomes().size() > 1)\n\t{\n\t\t// We have to check for consistency if there's more than one chromosome\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\tif (targets_data[haplosome_index]->chromosome_index_ != chromosome_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() requires that all target haplosomes are associated with the same chromosome.\" << EidosTerminate();\n\t\t\n\t\tif (mutations_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tMutation * const *mutations = (Mutation * const *)mutations_value->ObjectData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t\t\tif (mutations[value_index]->chromosome_index_ != chromosome_index)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() requires that all mutations to be removed are associated with the same chromosome as the target haplosomes.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tChromosome *chromosome = species->Chromosomes()[chromosome_index];\n\t\n\tspecies->population_.CheckForDeferralInHaplosomes(p_target, \"Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF\");\n\t\n\tCommunity &community = species->community_;\n\tPopulation &pop = species->population_;\n\tslim_tick_t tick = community.Tick();\n\tbool create_substitutions = substitute_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool recording_tree_sequence_mutations = species->RecordingTreeSequenceMutations();\n\tbool any_nonneutral_removed = false;\n\t\n\t// Use the 0th haplosome in the target to find out what the mutation run length is, so we can calculate run indices\n\tslim_position_t mutrun_length = haplosome_0->mutrun_length_;\n\t\n\t// TIMING RESTRICTION\n\tif (community.executing_species_ == species)\n\t{\n\t\tif (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosModifyChildCallback)\n\t\t{\n\t\t\t// Check that we're not inside a modifyChild() callback, or if we are, that the only haplosomes being modified belong to the new child.\n\t\t\t// This prevents problems with retracting the proposed child when tree-sequence recording is enabled; other extraneous changes must\n\t\t\t// not be backed out, and it's hard to separate, e.g., what's a child-related new mutation from an extraneously added new mutation.\n\t\t\t// Note that the other Haplosome methods that add/remove mutations perform the same check, and should be maintained in parallel.\n\t\t\tIndividual *focal_modification_child = community.focal_modification_child_;\n\t\t\t\n\t\t\tif (focal_modification_child)\n\t\t\t{\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *target_haplosome = targets_data[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (target_haplosome->individual_ != focal_modification_child)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on the currently executing species from within a modifyChild() callback to modify any haplosomes except those of the focal child being generated.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// This is actually only a problem when tree recording is on, but for consistency we outlaw it in all cases.  When a substitution\n\t\t\t// is created, it is added to the derived state of every haplosome, which is a side effect that can't be retracted if the modifyChild()\n\t\t\t// callback rejects the proposed child, so it has to be prohibited up front.  Anyway it would be a very strange thing to do.\n\t\t\tif (create_substitutions)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on the currently executing species from within a modifyChild() callback to create a substitution, because that would have side effects on haplosomes other than those of the focal child being generated.\" << EidosTerminate();\n\t\t}\n\t\telse if ((community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosRecombinationCallback) ||\n\t\t\t\t (community.executing_block_type_ == SLiMEidosBlockType::SLiMEidosMutationCallback))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on the currently executing species from within a recombination() or mutation() callback.\" << EidosTerminate();\n\t}\n\t\n\tif (mutations_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// This is the \"remove all mutations\" case, for which we have no vector of mutations to remove.  In this case we do the tree\n\t\t// sequence recording first, since we can add new empty derived states just at the locations where mutations presently exist.\n\t\t// Then we just go through and clear out the target haplosomes.\n\t\tif (create_substitutions)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): in removeMutations() substitute may not be T if mutations is NULL; an explicit vector of mutations to be substituted must be supplied.\" << EidosTerminate();\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (recording_tree_sequence_mutations)\n\t\t{\n\t\t\tconst std::vector<Mutation *> empty_mut_vector;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t{\n\t\t\t\tHaplosome *target_haplosome = targets_data[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (target_haplosome->IsNull())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on a null haplosome.  This error may be due to a break in backward compatibility in SLiM 3.7 involving addRecombinant() with haploid models; if that seems likely, please see the release notes.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tfor (HaplosomeWalker target_walker(target_haplosome); !target_walker.Finished(); target_walker.NextMutation())\n\t\t\t\t{\n\t\t\t\t\tMutation *mut = target_walker.CurrentMutation();\n\t\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\t\n\t\t\t\t\tspecies->RecordNewDerivedState(target_haplosome, pos, empty_mut_vector);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Fetch haplosome pointers and check for null haplosomes up front\n\t\tstd::vector<Haplosome *>target_haplosomes;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *target_haplosome = targets_data[haplosome_index];\n\t\t\t\n\t\t\tif (target_haplosome->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on a null haplosome.  This error may be due to a break in backward compatibility in SLiM 3.7 involving addRecombinant() with haploid models; if that seems likely, please see the release notes.\" << EidosTerminate();\n\t\t\t\n\t\t\ttarget_haplosomes.push_back(target_haplosome);\n\t\t}\n\t\t\n\t\t// Now remove all mutations; we don't use bulk operations here because it is simpler to just set them all to the same empty run\n\t\t// BCH 8/12/2021: fixing this code to only reset mutation runs if they presently contain a mutation; do nothing for empty mutruns\n\t\t// This avoids a bunch of mutrun thrash in haploid models that remove all mutations from the second haplosome in modifyChild(), etc.\n\t\tint mutrun_count = haplosome_0->mutrun_count_;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tMutationRun *shared_empty_run = nullptr;\t// different shared empty run for each mutrun index\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t{\n\t\t\t\tHaplosome *target_haplosome = target_haplosomes[haplosome_index];\n\t\t\t\tconst MutationRun *mutrun = target_haplosome->mutruns_[run_index];\n\t\t\t\t\n\t\t\t\tif (mutrun->size())\n\t\t\t\t{\n\t\t\t\t\t// Allocate the shared empty run lazily, since we might not need it (if we're removing mutations from haplosomes that are empty already)\n\t\t\t\t\tif (!shared_empty_run)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\t\t\tshared_empty_run = MutationRun::NewMutationRun(mutrun_context);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttarget_haplosome->mutruns_[run_index] = shared_empty_run;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// invalidate cached mutation refcounts; refcounts have changed\n\t\tpop.InvalidateMutationReferencesCache();\n\t\t\n\t\t// in this code path we just assume that nonneutral mutations might have been removed\n\t\tany_nonneutral_removed = true;\n\t}\n\telse\n\t{\n\t\t// If the user is creating substitutions for mutations, we now check for consistency at the end of the cycle, so that\n\t\t// we don't have a mutation still segregating while a substitution for it has also been created; see CheckMutationRegistry()\n\t\t// BCH 9/24/2021: Note that we cannot do the opposite check: checking that we only substitute a mutation when it has, in fact,\n\t\t// fixed.  We can't do that because there are models, such as the PAR (pseudo-autosomal region) recipe, that have different\n\t\t// fixation frequences for different parts of the haplosome because multiple chromosomes of different ploidy are being simulated.\n\t\t// Until we support multiple chromosomes more intrinsically, and can do that properly, substitution at less than frequency\n\t\t// 1.0 must be supported.  Note that this also means that we have to record new derived states here, because in some cases\n\t\t// (those same cases), the derived state for some haplosomes will have changed; if we do multiple chromosomes properly some day,\n\t\t// the recording of new derived states can probably be removed here, since no genetic state will have changed.\n\t\tif (create_substitutions)\n\t\t\tpop.SetMutationRegistryNeedsCheck();\n\t\t\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif (mutations_count)\n\t\t{\n\t\t\tSpecies *mutations_species = Community::SpeciesForMutations(mutations_value);\n\t\t\t\n\t\t\tif (mutations_species != species)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() requires that all mutations belong to the same species as the target haplosomes.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// Construct a vector of mutations to remove that is sorted by position\n\t\tstd::vector<Mutation *> mutations_to_remove;\n\t\tMutation * const *mutations_data = (Mutation * const *)mutations_value->ObjectData();\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t{\n\t\t\tMutation *mut = mutations_data[value_index];\n\t\t\t\n\t\t\tif (mut->state_ != MutationState::kInRegistry)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot remove mutations that are not currently segregating (i.e., have either been fixed/substituted or lost).\" << EidosTerminate();\n\t\t\t\n\t\t\tif (create_substitutions)\n\t\t\t\tmut->state_ = MutationState::kRemovedWithSubstitution;\t\t// mark removed/substituted mutations with a special state so they get handled correctly later\n\t\t\t\n\t\t\tmutations_to_remove.emplace_back(mut);\n\t\t\t\n\t\t\tif (mut->selection_coeff_ != 0.0)\n\t\t\t\tany_nonneutral_removed = true;\n\t\t}\n\t\t\n\t\tstd::sort(mutations_to_remove.begin(), mutations_to_remove.end(), [ ](Mutation *i1, Mutation *i2) {return i1->position_ < i2->position_;});\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\t// First, pre-plan the positions of new tree-seq derived states in anticipation of doing the removal.  We have to check\n\t\t// whether the mutation being added is already absent, to avoid recording a new derived state identical to the old one state.\n\t\t// The algorithm used here, with HaplosomeWalker, depends upon the fact that we just sorted the mutations to add by position.\n\t\t// However, we do still have to think about multiple muts being removed from the same position, and existing stacked mutations.\n\t\t// Note that when we are not creating substitutions, the haplosomes that possess a given mutation are the ones that change; but\n\t\t// when we are creating substitutions, the haplosomes that do *not* possess a given mutation are the ones that change, because\n\t\t// they gain the substitutuon, whereas the other haplosomes lose the mutation and gain the substitution, and are thus unchanged.\n\t\tstd::vector<std::pair<Haplosome *, std::vector<slim_position_t>>> new_derived_state_positions;\n\t\t\n\t\tif (recording_tree_sequence_mutations)\n\t\t{\n\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t{\n\t\t\t\tHaplosome *target_haplosome = targets_data[haplosome_index];\n\t\t\t\tHaplosomeWalker walker(target_haplosome);\n\t\t\t\tslim_position_t last_added_pos = -1;\n\t\t\t\t\n\t\t\t\tfor (Mutation *mut : mutations_to_remove)\n\t\t\t\t{\n\t\t\t\t\tslim_position_t mut_pos = mut->position_;\n\t\t\t\t\t\n\t\t\t\t\t// We don't care about other mutations at an already recorded position; move on\n\t\t\t\t\tif (mut_pos == last_added_pos)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// Advance the walker until it is at or after the mutation's position\n\t\t\t\t\twhile (!walker.Finished())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (walker.Position() >= mut_pos)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\twalker.NextMutation();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// If the derived state won't change for this position, then we don't need to record it; whether the\n\t\t\t\t\t// state will change depends upon whether the mutation is present, and whether we're substituting\n\t\t\t\t\tbool mutation_present = !walker.Finished() && (walker.Position() == mut_pos) && walker.MutationIsStackedAtCurrentPosition(mut);\n\t\t\t\t\t\n\t\t\t\t\tif ((create_substitutions && mutation_present) || (!create_substitutions && !mutation_present))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\t// we have decided that the new derived state at this position will need to be recorded, so note that\n\t\t\t\t\tif (last_added_pos == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// no pair entry in new_derived_state_positions yet, so make a new pair entry for this haplosome\n\t\t\t\t\t\tnew_derived_state_positions.emplace_back(target_haplosome, std::vector<slim_position_t>(1, mut_pos));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// we have an existing pair entry for this haplosome, so add this position to its position vector\n\t\t\t\t\t\tstd::pair<Haplosome *, std::vector<slim_position_t>> &haplosome_entry = new_derived_state_positions.back();\n\t\t\t\t\t\tstd::vector<slim_position_t> &haplosome_list = haplosome_entry.second;\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_list.emplace_back(mut_pos);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlast_added_pos = mut_pos;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Create substitutions for the mutations being removed, if requested.\n\t\t// Note we don't test for the mutations actually being fixed; that is the caller's responsibility to manage.\n\t\tif (create_substitutions)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t\t{\n\t\t\t\tMutation *mut = mutations_data[value_index];\n\t\t\t\tSubstitution *sub = new Substitution(*mut, tick);\n\t\t\t\t\n\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t// When doing tree recording, we additionally keep all fixed mutations (their ids) in a multimap indexed by their position\n\t\t\t\t// This allows us to find all the fixed mutations at a given position quickly and easily, for calculating derived states\n\t\t\t\tif (species->RecordingTreeSequence())\n\t\t\t\t\tpop.treeseq_substitutions_map_.emplace(mut->position_, sub);\n\t\t\t\t\n\t\t\t\tpop.substitutions_.emplace_back(sub);\n\t\t\t}\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t// When doing tree recording, if a given mutation is converted to a substitution by script, it may not be contained in some\n\t\t\t// haplosomes, but at the moment it fixes it is then considered to belong to the derived state of every non-null haplosome.  We\n\t\t\t// therefore need to go through all of the non-target haplosomes and record their new derived states at all positions\n\t\t\t// containing a new substitution.  If they already had a copy of the mutation, and didn't have it removed here, that is\n\t\t\t// pretty weird, but in practice it just means that their derived state will contain that mutation id twice – once for the\n\t\t\t// segregating mutation they still contain, and once for the new substitution.  We don't check for that case, but it should\n\t\t\t// just work automatically.\n\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t{\n\t\t\t\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\t\t\t\t\n\t\t\t\t// Mark all non-null haplosomes in the simulation that are not among the target haplosomes\n\t\t\t\tfor (auto subpop_pair : species->population_.subpops_)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\t\n\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *haplosome = ind->haplosomes_[haplosome_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\thaplosome->scratch_ = (haplosome->IsNull() ? 0 : 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t\t\ttargets_data[haplosome_index]->scratch_ = 0;\n\t\t\t\t\n\t\t\t\t// Figure out the unique chromosome positions that have changed (the uniqued set of mutation positions)\n\t\t\t\tstd::vector<slim_position_t> unique_positions;\n\t\t\t\tslim_position_t last_pos = -1;\n\t\t\t\t\n\t\t\t\tfor (Mutation *mut : mutations_to_remove)\n\t\t\t\t{\n\t\t\t\t\tslim_position_t pos = mut->position_;\n\t\t\t\t\t\n\t\t\t\t\tif (pos != last_pos)\n\t\t\t\t\t{\n\t\t\t\t\t\tunique_positions.emplace_back(pos);\n\t\t\t\t\t\tlast_pos = pos;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Loop through those haplosomes and log the new derived state at each (unique) position\n\t\t\t\tfor (auto subpop_pair : species->population_.subpops_)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\t\n\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *haplosome = ind->haplosomes_[haplosome_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (haplosome->scratch_ == 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (slim_position_t position : unique_positions)\n\t\t\t\t\t\t\t\t\tspecies->RecordNewDerivedState(haplosome, position, *haplosome->derived_mutation_ids_at_position(position));\n\t\t\t\t\t\t\t\thaplosome->scratch_ = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Now handle the mutations to remove, broken into bulk operations according to the mutation run they fall into\n\t\tslim_mutrun_index_t last_handled_mutrun_index = -1;\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t{\n\t\t\tMutation *next_mutation = mutations_to_remove[value_index];\n\t\t\tconst slim_position_t pos = next_mutation->position_;\n\t\t\tslim_mutrun_index_t mutrun_index = (slim_mutrun_index_t)(pos / mutrun_length);\n\t\t\t\n\t\t\tif (mutrun_index <= last_handled_mutrun_index)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\t// We have not yet processed this mutation run; do this mutation run index as a bulk operation\n\t\t\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\t\t\n\t\t\tHaplosome::BulkOperationStart(operation_id, mutrun_index);\n\t\t\t\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(mutrun_index);\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < target_size; ++haplosome_index)\n\t\t\t{\n\t\t\t\tHaplosome *target_haplosome = targets_data[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (target_haplosome->IsNull())\n\t\t\t\t{\n\t\t\t\t\tHaplosome::BulkOperationEnd(operation_id, mutrun_index);\t// clean up for SLiMgui\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() cannot be called on a null haplosome.  This error may be due to a break in backward compatibility in SLiM 3.7 involving addRecombinant() with haploid models; if that seems likely, please see the release notes.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// See if WillModifyRunForBulkOperation() can short-circuit the operation for us\n\t\t\t\tMutationRun *mutrun = target_haplosome->WillModifyRunForBulkOperation(operation_id, mutrun_index, mutrun_context);\n\t\t\t\t\n\t\t\t\tif (mutrun)\n\t\t\t\t{\n\t\t\t\t\t// Remove the specified mutations; see RemoveFixedMutations for the origins of this code\n\t\t\t\t\tMutationIndex *haplosome_iter = mutrun->begin_pointer();\n\t\t\t\t\tMutationIndex *haplosome_backfill_iter = mutrun->begin_pointer();\n\t\t\t\t\tMutationIndex *haplosome_max = mutrun->end_pointer();\n\t\t\t\t\t\n\t\t\t\t\t// haplosome_iter advances through the mutation list; for each entry it hits, the entry is either removed (skip it) or not removed (copy it backward to the backfill pointer)\n\t\t\t\t\twhile (haplosome_iter != haplosome_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex candidate_mutation = *haplosome_iter;\n\t\t\t\t\t\tconst slim_position_t candidate_pos = (mut_block_ptr + candidate_mutation)->position_;\n\t\t\t\t\t\tbool should_remove = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = value_index; mut_index < mutations_count; ++mut_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *mut_to_remove = mutations_to_remove[mut_index];\n\t\t\t\t\t\t\tMutationIndex mut_to_remove_index = mut_to_remove->BlockIndex();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mut_to_remove_index == candidate_mutation)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tshould_remove = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// since we're in sorted order by position, as soon as we pass the candidate we're done\n\t\t\t\t\t\t\tif (mut_to_remove->position_ > candidate_pos)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (should_remove)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Removed mutation; we want to omit it, so we just advance our pointer\n\t\t\t\t\t\t\t++haplosome_iter;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Unremoved mutation; we want to keep it, so we copy it backward and advance our backfill pointer as well as haplosome_iter\n\t\t\t\t\t\t\tif (haplosome_backfill_iter != haplosome_iter)\n\t\t\t\t\t\t\t\t*haplosome_backfill_iter = *haplosome_iter;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t++haplosome_backfill_iter;\n\t\t\t\t\t\t\t++haplosome_iter;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// excess mutations at the end have been copied back already; we just adjust mutation_count_ and forget about them\n\t\t\t\t\tmutrun->set_size(mutrun->size() - (int)(haplosome_iter - haplosome_backfill_iter));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tHaplosome::BulkOperationEnd(operation_id, mutrun_index);\n\t\t\t\n\t\t\t// now we have handled all mutations at this index (and all previous indices)\n\t\t\tlast_handled_mutrun_index = mutrun_index;\n\t\t\t\n\t\t\t// invalidate cached mutation refcounts; refcounts have changed\n\t\t\tpop.InvalidateMutationReferencesCache();\n\t\t}\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\t// Now that all the bulk operations are done, record all the new derived states\n\t\tif (recording_tree_sequence_mutations)\n\t\t{\n\t\t\tfor (std::pair<Haplosome *, std::vector<slim_position_t>> &haplosome_pair : new_derived_state_positions)\n\t\t\t{\n\t\t\t\tHaplosome *target_haplosome = haplosome_pair.first;\n\t\t\t\tstd::vector<slim_position_t> &haplosome_positions = haplosome_pair.second;\n\t\t\t\t\n\t\t\t\tfor (slim_position_t position : haplosome_positions)\n\t\t\t\t\tspecies->RecordNewDerivedState(target_haplosome, position, *target_haplosome->derived_mutation_ids_at_position(position));\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// TIMING RESTRICTION\n\t// issue a warning if removeMutations() was called at a questionable time, but only if the mutations removed were non-neutral\n\t// BCH: added the !create_substitutions check; if a substitution is being created, then it can be assumed that the mutation is fixed\n\t// in the model and is thus deemed by the model to make no difference to fitness outcomes (mutations that matter to fitness outcomes\n\t// should not be removed when they fix anyway).  This is maybe not absolutely 100% clear, but models that handle their own fixation,\n\t// like haploid models and haplodiploid models, should not have to see/suppress this warning.\n\tif (any_nonneutral_removed && !create_substitutions && !community.warned_early_mutation_remove_)\n\t{\n\t\tif ((community.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Haplosome_Class::ExecuteMethod_removeMutations): removeMutations() should probably not be called from a first() or early() event in a WF model; the removed mutation(s) will still influence fitness values during offspring generation.\" << std::endl;\n\t\t\t\tcommunity.warned_early_mutation_remove_ = true;\n\t\t\t}\n\t\t}\n\t\t// Note that there is no equivalent problem in nonWF models, because fitness values are used for survival,\n\t\t// not reproduction, and there is no event stage in the tick cycle that splits fitness from survival.\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tHaplosomeWalker\n//\n#pragma mark -\n#pragma mark HaplosomeWalker\n#pragma mark -\n\nvoid HaplosomeWalker::NextMutation(void)\n{\n\t// the !mutrun_ptr_ is actually not necessary, but ASAN wants it to be here...\n\tif (!mutrun_ptr_ || (++mutrun_ptr_ >= mutrun_end_))\n\t{\n\t\t// finished the current mutation, so move to the next until we find a mutation\n\t\tdo\n\t\t{\n\t\t\tif (++mutrun_index_ >= haplosome_->mutrun_count_)\n\t\t\t{\n\t\t\t\t// finished all mutation runs, so we're done\n\t\t\t\tmutation_ = nullptr;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tconst MutationRun *mutrun = haplosome_->mutruns_[mutrun_index_];\n\t\t\tmutrun_ptr_ = mutrun->begin_pointer_const();\n\t\t\tmutrun_end_ = mutrun->end_pointer_const();\n\t\t}\n\t\twhile (mutrun_ptr_ == mutrun_end_);\n\t}\n\t\n\tmutation_ = gSLiM_Mutation_Block + *mutrun_ptr_;\n}\n\nvoid HaplosomeWalker::MoveToPosition(slim_position_t p_position)\n{\n\t// Move the the first mutation that is at or after the given position.  Using this to move to a\n\t// given position is more efficient than iteratively advancing mutation by mutation, because\n\t// we can (1) go to the correct mutation run directly, and (2) do a binary search inside the\n\t// mutation run for the correct position.\n\tHaplosome *haplosome = haplosome_;\n\t\n\t// start at the mutrun dictated by the position we are moving to; positions < 0 start at 0\n\tmutrun_index_ = (int32_t)(p_position / haplosome->mutrun_length_);\n\tif (mutrun_index_ < 0)\n\t\tmutrun_index_ = 0;\n\t\n\twhile (true)\n\t{\n\t\t// if the mutrun is past the end of the last mutrun, we're done\n\t\tif (mutrun_index_ >= haplosome->mutrun_count_)\n\t\t{\n\t\t\tmutation_ = nullptr;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// get the information on the mutrun\n\t\tconst MutationRun *mutrun = haplosome->mutruns_[mutrun_index_];\n\t\tmutrun_ptr_ = mutrun->begin_pointer_const();\n\t\tmutrun_end_ = mutrun->end_pointer_const();\n\t\t\n\t\t// if the mutrun is empty, we will need to move to the next mutrun to find a mutation\n\t\tif (mutrun_ptr_ == mutrun_end_)\n\t\t\tmutrun_index_++;\n\t\telse\n\t\t\tbreak;\n\t}\n\t\n\t// if the mutation found is at or after the requested position, we are already done\n\tmutation_ = gSLiM_Mutation_Block + *mutrun_ptr_;\n\t\n\tif (mutation_->position_ >= p_position)\n\t\treturn;\n\t\n\t// otherwise, we are in the correct mutrun for the position, but the requested position\n\t// still lies ahead of us, so we have to advance until we reach or pass the position\n\t// FIXME should do a binary search inside the mutation run instead\n\tdo\n\t\tNextMutation();\n\twhile (!Finished() && (Position() < p_position));\n}\n\nbool HaplosomeWalker::MutationIsStackedAtCurrentPosition(Mutation *p_search_mut)\n{\n\t// We have reached some chromosome position (presumptively the *first mutation* at that position,\n\t// which we do not check here), and the caller wants to know if a given mutation, which is\n\t// located at that position, is contained in this haplosome.  This requires that we look ahead\n\t// through all of the mutations at the current position, since they are not sorted.  We are\n\t// guaranteed to stay inside the current mutation run, though, so this lookahead is simple.\n\tif (Finished())\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::MutationIsStackedAtCurrentPosition): (internal error) MutationIsStackedAtCurrentPosition() called on a finished walker.\" << EidosTerminate();\n\tif (!p_search_mut)\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::MutationIsStackedAtCurrentPosition): (internal error) MutationIsStackedAtCurrentPosition() called with a nullptr mutation to search for.\" << EidosTerminate();\n\t\n\tslim_position_t pos = mutation_->position_;\n\t\n\tif (p_search_mut->position_ != pos)\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::MutationIsStackedAtCurrentPosition): (internal error) MutationIsStackedAtCurrentPosition() called with a mutation that is not at the current walker position.\" << EidosTerminate();\n\t\n\tfor (const MutationIndex *search_ptr_ = mutrun_ptr_; search_ptr_ != mutrun_end_; ++search_ptr_)\n\t{\n\t\tMutationIndex mutindex = *search_ptr_;\n\t\tMutation *mut = gSLiM_Mutation_Block + mutindex;\n\t\t\n\t\tif (mut == p_search_mut)\n\t\t\treturn true;\n\t\tif (mut->position_ != pos)\n\t\t\tbreak;\n\t}\n\t\n\treturn false;\n}\n\nbool HaplosomeWalker::IdenticalAtCurrentPositionTo(HaplosomeWalker &p_other_walker)\n{\n\tif (Finished())\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::IdenticalAtCurrentPositionTo): (internal error) IdenticalAtCurrentPositionTo() called on a finished walker.\" << EidosTerminate();\n\tif (p_other_walker.Finished())\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::IdenticalAtCurrentPositionTo): (internal error) IdenticalAtCurrentPositionTo() called on a finished walker.\" << EidosTerminate();\n\tif (Position() != p_other_walker.Position())\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::IdenticalAtCurrentPositionTo): (internal error) IdenticalAtCurrentPositionTo() called with walkers at different positions.\" << EidosTerminate();\n\t\n\t// If the two walkers are using the same mutation run, they are identical by definition\n\tif (mutrun_ptr_ == p_other_walker.mutrun_ptr_)\n\t\treturn true;\n\t\n\t// If their current mutation differs, then the positions are not identical\n\tif (mutation_ != p_other_walker.mutation_)\n\t\treturn false;\n\t\n\t// Scan forward as long as we are still within the same position\n\tslim_position_t pos = mutation_->position_;\n\tconst MutationIndex *search_ptr_1 = mutrun_ptr_ + 1;\n\tconst MutationIndex *search_ptr_2 = p_other_walker.mutrun_ptr_ + 1;\n\t\n\tdo\n\t{\n\t\tMutation *mut_1 = (search_ptr_1 != mutrun_end_) ? (gSLiM_Mutation_Block + *search_ptr_1) : nullptr;\n\t\tMutation *mut_2 = (search_ptr_2 != p_other_walker.mutrun_end_) ? (gSLiM_Mutation_Block + *search_ptr_2) : nullptr;\n\t\tbool has_mut_at_position_1 = (mut_1) ? (mut_1->position_ == pos) : false;\n\t\tbool has_mut_at_position_2 = (mut_2) ? (mut_2->position_ == pos) : false;\n\t\t\n\t\t// If we have left the current position for both, simultaneously, then the positions are identical\n\t\tif (!has_mut_at_position_1 && !has_mut_at_position_2)\n\t\t\treturn true;\n\t\t\n\t\t// If we left the current position for one but not for the other, then the positions differ\n\t\tif (!has_mut_at_position_1 || !has_mut_at_position_2)\n\t\t\treturn false;\n\t\t\n\t\t// We are still within the current position in both, so if the mutations we reached differ then the positions differ\n\t\tif (mut_1 != mut_2)\n\t\t\treturn false;\n\t\t\n\t\t// Otherwise we saw identical mutations at the position, and we should continue scanning\n\t\t++search_ptr_1;\n\t\t++search_ptr_2;\n\t}\n\twhile (true);\n}\n\nint8_t HaplosomeWalker::NucleotideAtCurrentPosition(void)\n{\n\tif (Finished())\n\t\tEIDOS_TERMINATION << \"ERROR (HaplosomeWalker::NucleotideAtCurrentPosition): (internal error) NucleotideAtCurrentPosition() called on a finished walker.\" << EidosTerminate();\n\t\n\t// First check the mutation we're at, since we already have it\n\tint8_t nuc = mutation_->nucleotide_;\n\t\n\tif (nuc != -1)\n\t\treturn nuc;\n\t\n\t// Then scan forward as long as we are still within the same position\n\tslim_position_t pos = mutation_->position_;\n\t\n\tfor (const MutationIndex *search_ptr_ = mutrun_ptr_ + 1; search_ptr_ != mutrun_end_; ++search_ptr_)\n\t{\n\t\tMutationIndex mutindex = *search_ptr_;\n\t\tMutation *mut = gSLiM_Mutation_Block + mutindex;\n\t\t\n\t\tif (mut->position_ != pos)\n\t\t\treturn -1;\n\t\t\n\t\tnuc = mut->nucleotide_;\n\t\t\n\t\tif (nuc != -1)\n\t\t\treturn nuc;\n\t}\n\t\n\treturn -1;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/haplosome.h",
    "content": "//\n//  haplosome.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Haplosome represents a particular haplosome, defined as a vector of mutations.  Each individual in the simulation has a haplosome,\n which determines that individual's fitness (from the fitness effects of all of the mutations possessed).\n \n */\n\n// This include is up here because I had to jump through some hoops to break a #include loop between this and chromosome.h;\n// forward declaration wasn't enough, because both classes have inline methods that need the other type's definition.\n#include \"chromosome.h\"\n\n#ifndef __SLiM__haplosome__\n#define __SLiM__haplosome__\n\n\n#include \"mutation.h\"\n#include \"slim_globals.h\"\n#include \"eidos_value.h\"\n#include \"mutation_run.h\"\n\n#include <vector>\n#include <string.h>\n#include <unordered_map>\n\n//TREE SEQUENCE\n//INCLUDE JEROME's TABLES API\n#include \"../treerec/tskit/tables.h\"\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\ntypedef robin_hood::unordered_flat_map<const MutationRun*, const MutationRun*> SLiMBulkOperationHashTable;\ntypedef robin_hood::pair<const MutationRun*, const MutationRun*> SLiMBulkOperationPair;\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_map>\ntypedef std::unordered_map<const MutationRun*, const MutationRun*> SLiMBulkOperationHashTable;\ntypedef std::pair<const MutationRun*, const MutationRun*> SLiMBulkOperationPair;\n#endif\n\n\nclass Species;\nclass Population;\nclass Subpopulation;\nclass Individual;\nclass Individual_Class;\nclass HaplosomeWalker;\n\n\nextern EidosClass *gSLiM_Haplosome_Class;\n\n\n// Haplosome now keeps an array of MutationRun objects, and those objects actually hold the mutations of the haplosome.  This design\n// allows multiple Haplosome objects to share the same runs of mutations, for speed in copying runs during offspring generation.\n// The number of runs can be determined at runtime, ideally as a function of the chromosome length, mutation rate, and recombination\n// rate; the goal is to make it so runs are short enough that events inside them are relatively rare (allowing them to be copied\n// often during reproduction), but long enough that they contain enough mutations to make all this machinery worthwhile; if they\n// are usually empty then we're actually doing more work than we were before!\n\n// Each haplosome knows the number of runs and the run length, but it is the same for every haplosome in a given simulation.  The whole\n// simulation can be scaled up or down by splitting or joining mutation runs; this is done by the mutation-run experiment code.\n\n// The array of runs is malloced; since this is two mallocs per individual, this should not be unacceptable overhead, and it avoids\n// hard-coding of a maximum number of runs, wasting memory on unused pointers, etc.  For null haplosomes the runs pointer is nullptr,\n// so if we screw up our null haplosome checks we will get a hard crash, which is not a bad thing.\n\n// BCH 4/19/2023: Note that Haplosome's MutationRun objects are now handled using const pointers.  This reflects the fact that, in\n// general, MutationRuns in a Haplosome may be shared with other Haplosomes, and so should not be modified.  The underlying objects are\n// not const, in fact, they are just handled through const pointers to enforce immutability once they are added to a haplosome.  This\n// means that there are certain places in the code where we cast away the constness, when we know that a MutationRun is not, in\n// fact, shared by more than one haplosome; but in general we do not do that, because if the run is shared then modifying it is unsafe.\n// See mutation_run.h for further comments on this scheme, which replaces a previous scheme based on the refcounts of the runs.\n\n// BCH 5 May 2017: Well, it turns out that allocating the array of runs is in fact substantial overhead in some cases, so let's try\n// to avoid it.  We can keep an internal buffer of mutation run pointers, which we can use as long as we are within the buffer size.\n// Using a size of 1 for now, since larger sizes increase memory usage substantially for some models, and also slow us down somehow.\n// BCH 22 April 2023: I tried removing this internal buffer, to see if it is really worthwhile.  It is.  I think having the pointer\n// to the MutationRun in the same memory block really helps a lot with memory locality.\n#define SLIM_HAPLOSOME_MUTRUN_BUFSIZE 1\n\n\nclass Haplosome : public EidosObject\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosObject super;\n\nprivate:\n\tEidosValue_SP self_value_;\t\t\t\t\t\t\t\t\t\t// cached EidosValue object for speed\n\t\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\t\n\tslim_chromosome_index_t /* uint8_t */ chromosome_index_;\t\t// the index of this haplosome's chromosome\n\tuint8_t chromosome_subposition_;\t\t\t\t\t\t\t\t// 0 for the first haplosome for the chromosome, 1 for the second\n\tint8_t scratch_;\t\t\t\t\t\t\t\t\t\t\t\t// temporary scratch space that can be used locally in algorithms\n\t// 1 BYTE UNUSED HERE!\n\t\n\tint32_t mutrun_count_;\t\t\t\t\t\t\t\t\t\t\t// number of runs being used; 0 for a null haplosome, otherwise >= 1\n\tslim_position_t mutrun_length_;\t\t\t\t\t\t\t\t\t// the length, in base pairs, of each run; the last run may not use its full length\n\tconst MutationRun *run_buffer_[SLIM_HAPLOSOME_MUTRUN_BUFSIZE];\t// an internal buffer used to avoid allocation and memory nonlocality for simple models\n\tconst MutationRun **mutruns_;\t\t\t\t\t\t\t\t\t// mutation runs; nullptr if a null haplosome OR an empty haplosome\n\t\n\tIndividual *individual_;\t\t\t\t\t\t\t\t\t\t// NOT OWNED: the Individual this haplosome belongs to\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t\t// a user-defined tag value\n\t\n\t// TREE SEQUENCE RECORDING\n\tslim_haplosomeid_t haplosome_id_;\t// a unique id assigned by SLiM, as a side effect of pedigree recording, that never changes\n\t\t\t\t\t\t\t\t\t\t// note this is shared by all haplosomes at the same position (1st/2nd) in the same individual\n\t\n\t// Bulk operation optimization; see WillModifyRunForBulkOperation().  The idea is to keep track of changes to MutationRun\n\t// objects in a bulk operation, and short-circuit the operation for all haplosomes with the same initial MutationRun (since\n\t// the bulk operation will produce the same product MutationRun given the same initial MutationRun).  Note this is shared by all species.\n\tstatic int64_t s_bulk_operation_id_;\n\tstatic slim_mutrun_index_t s_bulk_operation_mutrun_index_;\n\tstatic SLiMBulkOperationHashTable s_bulk_operation_runs_;\n\t\npublic:\n\t\n\tHaplosome(const Haplosome &p_original) = delete;\n\tHaplosome& operator= (const Haplosome &p_original) = delete;\n\t\n\t// tags to indicate construction of a null vs. non-null haplosome, since the constructors take the same arguments\n\t// see https://stackoverflow.com/a/46775828/2752221 for this very nice solution with zero runtime overhead (no if)\n\tstruct NullHaplosome final {};\n\tstruct NonNullHaplosome final {};\n\t\n\t// make a null haplosome; the Haplosome::NullHaplosome{} parameter is just a tag to select this constructor\n\t// this constructor is for internal use only, and does not set chromosome_subposition_; use NewHaplosome_NULL()\n\tinline Haplosome(NullHaplosome, Individual *p_individual, Chromosome *p_chromosome) :\n\t\tchromosome_index_(p_chromosome->Index()), mutrun_count_(0), mutrun_length_(0), mutruns_(nullptr), individual_(p_individual), haplosome_id_(-1)\n\t{\n\t};\n\t\n\t// make a non-null haplosome; the Haplosome::NonNullHaplosome{} parameter is just a tag to select this constructor\n\t// this constructor is for internal use only, and does not set chromosome_subposition_; use NewHaplosome_NONNULL()\n\tinline Haplosome(NonNullHaplosome, Individual *p_individual, Chromosome *p_chromosome) :\n\t\tchromosome_index_(p_chromosome->Index()), mutrun_count_(p_chromosome->mutrun_count_), mutrun_length_(p_chromosome->mutrun_length_), individual_(p_individual), haplosome_id_(-1)\n\t{\n\t\tif (mutrun_count_ <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t{\n\t\t\tmutruns_ = run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tEIDOS_BZERO(run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t\telse\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\tmutruns_ = (const MutationRun **)calloc(mutrun_count_, sizeof(const MutationRun *));\n#else\n\t\t\tmutruns_ = (const MutationRun **)malloc(mutrun_count_ * sizeof(const MutationRun *));\n#endif\n\t\t}\n\t};\n\t\n\t~Haplosome(void);\n\t\n\tinline __attribute__((always_inline)) slim_haplosomeid_t HaplosomeID(void)\t\t\t\t{ return haplosome_id_; }\n\tinline __attribute__((always_inline)) void SetHaplosomeID(slim_haplosomeid_t p_new_id)\t{ haplosome_id_ = p_new_id; }\t// should basically never be called\n\tinline __attribute__((always_inline)) Individual *OwningIndividual(void)\t\t\t\t{ return individual_; }\n\tinline __attribute__((always_inline)) const Individual *OwningIndividual(void) const \t{ return individual_; }\n\tChromosome *AssociatedChromosome(void) const;\n\tinline __attribute__((always_inline)) slim_position_t MutrunLength(void) const\t\t\t{ return mutrun_length_; }\n\t\n\tvoid NullHaplosomeAccessError(void) const __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\t\t// prints an error message, a stacktrace, and exits; called only for DEBUG\n\t\n\tinline __attribute__((always_inline)) bool IsNull(void) const\t\t\t\t\t\t\t\t\t// returns true if the haplosome is a null (placeholder) haplosome, false otherwise\n\t{\n\t\treturn (mutrun_count_ == 0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// null haplosomes have a mutrun count of 0\n\t}\n\tinline __attribute__((always_inline)) bool IsDeferred(void) const\t\t\t\t\t\t\t\t// returns true if the haplosome is deferred haplosome (not yet generated), false otherwise\n\t{\n\t\treturn ((mutrun_count_ != 0) && mutruns_ && !mutruns_[0]);\t\t\t\t\t\t\t\t\t\t// when deferred, non-null haplosomes have a non-zero mutrun count but are cleared to nullptr\n\t}\n\t\n\tvoid MakeNull(void) __attribute__((cold));\t// transform into a null haplosome\n\t\n\t// used to re-initialize haplosomes to a new state, reusing them for efficiency\n\tvoid ReinitializeHaplosomeToNull(Individual *individual);\n\tvoid ReinitializeHaplosomeToNonNull(Individual *individual, Chromosome *p_chromosome);\n\t\n#if DEBUG\n\tstatic void DebugCheckStructureMatch(Haplosome *hapA, Haplosome *hapB, Chromosome *p_chromosome)\n\t{\n\t\t// This does a consistency check that two haplosomes (parent and child) match each other and,\n\t\t// if they are non-null, the expectated mutrun count/length passed in (from a chromosome)\n\t\t// It is used in the WF \"munge\" methods that munge an existing individual into a new child\n\t\tif ((hapA->IsNull() != hapB->IsNull()) || (!hapA->IsNull() &&\n\t\t\t((hapA->mutrun_count_ != p_chromosome->mutrun_count_) || (hapA->mutrun_length_ != p_chromosome->mutrun_length_) ||\n\t\t\t(hapB->mutrun_count_ != p_chromosome->mutrun_count_) || (hapB->mutrun_length_ != p_chromosome->mutrun_length_))))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::CheckStructureMatch): (internal error) haplosome structure does not match!\" << EidosTerminate();\n\t}\n\tstatic void DebugCheckStructureMatch(Haplosome *hapA, Haplosome *hapB, Haplosome *hapC, Chromosome *p_chromosome)\n\t{\n\t\t// This does a consistency check that two haplosomes (parent and child) match each other and,\n\t\t// if they are non-null, the expectated mutrun count/length passed in (from a chromosome)\n\t\t// It is used in the WF \"munge\" methods that munge an existing individual into a new child\n\t\tif (((hapA->IsNull() != hapB->IsNull()) || (hapA->IsNull() != hapC->IsNull())) || (!hapA->IsNull() &&\n\t\t\t((hapA->mutrun_count_ != p_chromosome->mutrun_count_) || (hapA->mutrun_length_ != p_chromosome->mutrun_length_) ||\n\t\t\t (hapB->mutrun_count_ != p_chromosome->mutrun_count_) || (hapB->mutrun_length_ != p_chromosome->mutrun_length_) ||\n\t\t\t (hapC->mutrun_count_ != p_chromosome->mutrun_count_) || (hapC->mutrun_length_ != p_chromosome->mutrun_length_))))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::CheckStructureMatch): (internal error) haplosome structure does not match!\" << EidosTerminate();\n\t}\n#else\n\tstatic inline void DebugCheckStructureMatch(Haplosome *, Haplosome *, Chromosome *) {}\n\tstatic inline void DebugCheckStructureMatch(Haplosome *, Haplosome *, Haplosome *, Chromosome *) {}\n#endif\n\t\n\t// This should be called before starting to define a mutation run from scratch, as the crossover-mutation code does.  It will\n\t// discard the current MutationRun and start over from scratch with a unique, new MutationRun which is returned by the call.\n\t// Note that there is a _LOCKED version of this below, which locks around the use of the allocation pool.\n\tinline MutationRun *WillCreateRun(int p_run_index, MutationRunContext &p_mutrun_context)\n\t{\n#if DEBUG\n\t\tif (p_run_index < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillCreateRun): (internal error) attempt to create a negative-index run.\" << EidosTerminate();\n\t\tif (p_run_index >= mutrun_count_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillCreateRun): (internal error) attempt to create an out-of-index run.\" << EidosTerminate();\n#endif\n\t\t\n\t\tMutationRun *new_run = MutationRun::NewMutationRun(p_mutrun_context);\t// take from shared pool of used objects\n\t\t\n\t\tmutruns_[p_run_index] = new_run;\n\t\treturn new_run;\n\t}\n\t\n\tinline MutationRun *WillCreateRun_LOCKED(int p_run_index, MutationRunContext &p_mutrun_context)\n\t{\n#if DEBUG\n\t\tif (p_run_index < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillCreateRun_LOCKED): (internal error) attempt to create a negative-index run.\" << EidosTerminate();\n\t\tif (p_run_index >= mutrun_count_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::WillCreateRun_LOCKED): (internal error) attempt to create an out-of-index run.\" << EidosTerminate();\n#endif\n\t\t\n\t\tMutationRun *new_run = MutationRun::NewMutationRun_LOCKED(p_mutrun_context);\t// take from shared pool of used objects\n\t\t\n\t\tmutruns_[p_run_index] = new_run;\n\t\treturn new_run;\n\t}\n\t\n\t\n\t// This should be called before modifying the run at a given index.  It will replicate the run to produce a single-referenced copy,\n\t// thus guaranteeing that the run can be modified legally.  The _UNSHARED version avoids making that copy unless the run is empty,\n\t// based on a guarantee from the caller that the run is already single-referenced unless it is empty; this variant is used in code\n\t// that loads new genetic data into initially empty haplosomes.  WillModifyRun() used to test the use count of the run to see whether\n\t// a copy was needed or not, but that is no longer possible in the new mutation run design where use counts are only valid after tallying.\n\tMutationRun *WillModifyRun(slim_mutrun_index_t p_run_index, MutationRunContext &p_mutrun_context);\n\tMutationRun *WillModifyRun_UNSHARED(slim_mutrun_index_t p_run_index, MutationRunContext &p_mutrun_context);\n\t\n\t// This is an alternate version of WillModifyRun().  It labels the upcoming modification as being the result of a bulk operation\n\t// being applied across multiple haplosomes, such that identical input haplosomes will produce identical output haplosomes, such as adding\n\t// the same mutation to all target haplosomes.  It returns T if the caller needs to actually perform the operation on this haplosome,\n\t// or F if this call performed the run for the caller (because the operation had already been performed on an identical haplosome).\n\t// The goal is that haplosomes that share the same mutation run should continue to share the same mutation run after being processed\n\t// by a bulk operation using this method.  A bit strange, but potentially important for efficiency.  Note that this method knows\n\t// nothing about the operation being performed; it just plays around with MutationRun pointers, recognizing when the runs are\n\t// identical.  The first call for a new operation ID will always return a pointer, and the caller will then perform the operation;\n\t// subsequent calls for haplosomes with the same starting MutationRun will substitute the same final MutationRun and return nullptr.\n\tstatic void BulkOperationStart(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index);\n\tMutationRun *WillModifyRunForBulkOperation(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index, MutationRunContext &p_mutrun_context);\n\tstatic void BulkOperationEnd(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index);\n\t\n\t// Remove all mutations in p_haplosome that have a state_ of MutationState::kFixedAndSubstituted, indicating that they have fixed\n\tvoid RemoveFixedMutations(int64_t p_operation_id, slim_mutrun_index_t p_mutrun_index)\n\t{\n#if DEBUG\n\t\tif (mutrun_count_ == 0)\n\t\t\tNullHaplosomeAccessError();\n#endif\n\t\t// Remove all fixed mutations from the given mutation run index.  Note that we cast away the const on our\n\t\t// mutation runs here.  This method is called only when fixed mutations are being removed from *all* haplosomes,\n\t\t// so the fact that it modifies other haplosomes that share this mutation run is a feature, not a bug.  See\n\t\t// Population::RemoveAllFixedMutations() for further context on this.\n\t\tMutationRun *mutrun = const_cast<MutationRun *>(mutruns_[p_mutrun_index]);\n\t\t\n\t\tmutrun->RemoveFixedMutations(p_operation_id);\n\t}\n\t\n\t// TallyHaplosomeReferences_Checkback() counts up the total MutationRun references, using their usage counts, as a checkback\n\tvoid TallyHaplosomeReferences_Checkback(slim_refcount_t *p_mutrun_ref_tally, slim_refcount_t *p_mutrun_tally, int64_t p_operation_id);\n\t\n\tinline __attribute__((always_inline)) int mutation_count(void) const\t// used to be called size(); renamed to avoid confusion with MutationRun::size() and break code using the wrong method\n\t{\n#if DEBUG\n\t\tif (mutrun_count_ == 0)\n\t\t\tNullHaplosomeAccessError();\n#endif\n\t\tif (mutrun_count_ == 1)\n\t\t{\n\t\t\treturn run_buffer_[0]->size();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint mut_count = 0;\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t\t\t\tmut_count += mutruns_[run_index]->size();\n\t\t\t\n\t\t\treturn mut_count;\n\t\t}\n\t}\n\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t// BCH 10/15/2024: clearing haplosomes to nullptr is no longer required; it just slows us down.\n\tinline __attribute__((always_inline)) void clear_to_nullptr(void)\n\t{\n\t\t// It is legal to call this method on null haplosomes, for speed/simplicity; it does no harm\n\t\tEIDOS_BZERO(mutruns_, mutrun_count_ * sizeof(const MutationRun *));\n\t}\n\t\n\tinline void check_cleared_to_nullptr(void)\n\t{\n\t\t// It is legal to call this method on null haplosomes, for speed/simplicity; it does no harm\n\t\tfor (int run_index = 0; run_index < mutrun_count_; ++run_index)\n\t\t\tif (mutruns_[run_index])\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::check_cleared_to_nullptr): (internal error) haplosome should be cleared but is not.\" << EidosTerminate();\n\t}\n#endif\n\t\n\tinline __attribute__((always_inline)) bool contains_mutation(const Mutation *p_mut) const\n\t{\n#if DEBUG\n\t\tif (mutrun_count_ == 0)\n\t\t\tNullHaplosomeAccessError();\n#endif\n\t\treturn mutruns_[p_mut->position_ / mutrun_length_]->contains_mutation(p_mut);\n\t}\n\t\n\tinline __attribute__((always_inline)) Mutation *mutation_with_type_and_position(MutationType *p_mut_type, slim_position_t p_position, slim_position_t p_last_position)\n\t{\n#if DEBUG\n\t\tif (mutrun_count_ == 0)\n\t\t\tNullHaplosomeAccessError();\n#endif\n\t\treturn mutruns_[p_position / mutrun_length_]->mutation_with_type_and_position(p_mut_type, p_position, p_last_position);\n\t}\n\t\n\tinline void copy_from_haplosome(const Haplosome &p_source_haplosome)\n\t{\n\t\tif (p_source_haplosome.IsNull())\n\t\t{\n\t\t\t// p_original is a null haplosome, so make ourselves null too, if we aren't already\n\t\t\tMakeNull();\n\t\t}\n\t\telse\n\t\t{\n#if DEBUG\n\t\t\tif (mutrun_count_ == 0)\n\t\t\t\tNullHaplosomeAccessError();\n#endif\n#if DEBUG\n\t\t\tif ((mutrun_count_ != p_source_haplosome.mutrun_count_) || (mutrun_length_ != p_source_haplosome.mutrun_length_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Haplosome::copy_from_haplosome): (internal error) assignment from haplosome with different count/length.\" << EidosTerminate();\n#endif\n\t\t\t\n\t\t\tif (mutrun_count_ == 1)\n\t\t\t{\n\t\t\t\t// This optimization does seem to make a significant difference...\n\t\t\t\trun_buffer_[0] = p_source_haplosome.mutruns_[0];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmemcpy(mutruns_, p_source_haplosome.mutruns_, mutrun_count_ * sizeof(const MutationRun *));\n\t\t\t}\n\t\t}\n\t\t\n\t\t// DO NOT copy the subpop pointer!  That is not part of the genetic state of the haplosome,\n\t\t// it's a back-pointer to the Subpopulation that owns this haplosome, and never changes!\n\t\t// subpop_ = p_source_haplosome.subpop_;\n\t}\n\t\n\tinline const std::vector<Mutation *> *derived_mutation_ids_at_position(slim_position_t p_position) const\n\t{\n\t\tslim_mutrun_index_t run_index = (slim_mutrun_index_t)(p_position / mutrun_length_);\n\t\t\n\t\treturn mutruns_[run_index]->derived_mutation_ids_at_position(p_position);\n\t}\n\t\n\tvoid record_derived_states(Species *p_species) const;\n\t\n\t// print the sample represented by haplosomes, using SLiM's own format\n\tstatic void PrintHaplosomes_SLiM(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, bool p_output_object_tags);\n\t\n\t// print the sample represented by haplosomes, using \"ms\" format\n\tstatic void PrintHaplosomes_MS(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, const Chromosome &p_chromosome, bool p_filter_monomorphic);\n\t\n\t// print the sample represented by haplosomes, using \"vcf\" format\n\tstatic void PrintHaplosomes_VCF(std::ostream &p_out, std::vector<Haplosome *> &p_haplosomes, const Chromosome &p_chromosome, bool groupAsIndividuals, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs);\n\tstatic void _PrintVCF(std::ostream &p_out, const Haplosome **p_haplosomes, int64_t p_haplosomes_count, const Chromosome &p_chromosome, bool p_groupAsIndividuals, bool p_simplify_nucs, bool p_output_nonnucs, bool p_output_multiallelics);\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsageForMutrunBuffers(void);\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tvoid GenerateCachedEidosValue(void);\n\tinline __attribute__((always_inline)) EidosValue_SP CachedEidosValue(void) { if (!self_value_) GenerateCachedEidosValue(); return self_value_; };\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_containsMarkerMutation(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_containsMutations(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_countOfMutationsOfType(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_nucleotides(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_positionsOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_sumOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_haplosomePedigreeID(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_chromosomeSubposition(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_isNullHaplosome(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\t\n\t// Accelerated property writing; see class EidosObject for comments on this mechanism\n\tstatic void SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\t\n\tfriend class Haplosome_Class;\n\t\n\t\n\t// With the new mutation run structure, the simplest course of action is to just let some SLiM classes delve\n\t// in Haplosome directly; we really don't want to get into trying to define an iterator that loops over mutation\n\t// runs, etc., transparently and pretends that a haplosome is just a single bag of mutations.\n\t// FIXME well, now we do in fact have the HaplosomeWalker iterator class below, which works nicely, so some\n\t// of the code that messes around inside Haplosome's internals can probably be switched over to using it...\n\tfriend Species;\n\tfriend Population;\n\tfriend Subpopulation;\n\tfriend Chromosome;\n\tfriend Individual;\n\tfriend Individual_Class;\n\tfriend HaplosomeWalker;\n};\n\nclass Haplosome_Class : public EidosClass\n{\nprivate:\n\ttypedef EidosClass super;\n\npublic:\n\tHaplosome_Class(const Haplosome_Class &p_original) = delete;\t// no copy-construct\n\tHaplosome_Class& operator=(const Haplosome_Class&) = delete;\t// no copying\n\tinline Haplosome_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\t\n\tvirtual EidosValue_SP ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const override;\n\tEidosValue_SP ExecuteMethod_addMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_addNewMutation(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_mutationFreqsCountsInHaplosomes(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_outputX(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_readHaplosomesFromMS(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_readHaplosomesFromVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_removeMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n};\n\n// This class allows clients of Haplosome to walk the mutations inside a haplosome without needing to know about MutationRun.\nclass HaplosomeWalker\n{\nprivate:\n\tHaplosome *haplosome_;\t\t\t\t\t\t// the haplosome being walked\n\tint32_t mutrun_index_;\t\t\t\t\t\t// the mutation run index we're presently traversing\n\tconst MutationIndex *mutrun_ptr_;\t\t\t// a pointer to the current element in the mutation run\n\tconst MutationIndex *mutrun_end_;\t\t\t// an end pointer for the mutation run\n\tMutation *mutation_;\t\t\t\t\t\t// the current mutation pointer, or nullptr if we have reached the end of the haplosome\n\t\npublic:\n\tHaplosomeWalker(void) = delete;\n\tHaplosomeWalker(const HaplosomeWalker &p_original) = default;\n\tHaplosomeWalker& operator= (const HaplosomeWalker &p_original) = default;\n\t\n\tinline HaplosomeWalker(Haplosome *p_haplosome) : haplosome_(p_haplosome), mutrun_index_(-1), mutrun_ptr_(nullptr), mutrun_end_(nullptr), mutation_(nullptr) { NextMutation(); };\n\tHaplosomeWalker(HaplosomeWalker&&) = default;\n\tinline ~HaplosomeWalker(void) {};\n\t\n\tinline Haplosome *WalkerHaplosome(void) { return haplosome_; }\n\tinline Mutation *CurrentMutation(void) { return mutation_; }\n\tinline bool Finished(void) { return (mutation_ == nullptr); }\n\tinline slim_position_t Position(void) { return mutation_->position_; }\t\t// must be sure the walker is not finished!\n\t\n\tvoid NextMutation(void);\n\tvoid MoveToPosition(slim_position_t p_position);\n\tbool MutationIsStackedAtCurrentPosition(Mutation *p_search_mut);\t// scans for the given mutation in any slot at the current position\n\tbool IdenticalAtCurrentPositionTo(HaplosomeWalker &p_other_walker);\t// compares stacked mutations between walkers (reordered is not identical)\n\tint8_t NucleotideAtCurrentPosition(void);\n};\n\n\n#endif /* defined(__SLiM__haplosome__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/individual.cpp",
    "content": "//\n//  individual.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 6/10/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"individual.h\"\n#include \"subpopulation.h\"\n#include \"species.h\"\n#include \"community.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_call_signature.h\"\n#include \"polymorphism.h\"\n\n#include <string>\n#include <algorithm>\n#include <vector>\n#include <cmath>\n#include <fstream>\n#include <utility>\n\n\n#pragma mark -\n#pragma mark Individual\n#pragma mark -\n\n// A global counter used to assign all Individual objects a unique ID\nslim_pedigreeid_t gSLiM_next_pedigree_id = 0;\n\n// Static member bools that track whether any individual has ever sustained a particular type of change\nbool Individual::s_any_individual_color_set_ = false;\nbool Individual::s_any_individual_dictionary_set_ = false;\nbool Individual::s_any_individual_tag_set_ = false;\nbool Individual::s_any_individual_tagF_set_ = false;\nbool Individual::s_any_individual_tagL_set_ = false;\nbool Individual::s_any_haplosome_tag_set_ = false;\nbool Individual::s_any_individual_fitness_scaling_set_ = false;\n\n\n// individual first, haplosomes later; this is the new multichrom paradigm\n// BCH 10/12/2024: Note that this will rarely be called after simulation startup; see NewSubpopIndividual()\nIndividual::Individual(Subpopulation *p_subpopulation, slim_popsize_t p_individual_index, IndividualSex p_sex, slim_age_t p_age, double p_fitness, float p_mean_parent_age) :\n#ifdef SLIMGUI\n\tcolor_set_(false),\n#endif\n\tmean_parent_age_(p_mean_parent_age), pedigree_id_(-1), pedigree_p1_(-1), pedigree_p2_(-1),\n\tpedigree_g1_(-1), pedigree_g2_(-1), pedigree_g3_(-1), pedigree_g4_(-1), reproductive_output_(0),\n\tsex_(p_sex), migrant_(false), killed_(false), cached_fitness_UNSAFE_(p_fitness),\n#ifdef SLIMGUI\n\tcached_unscaled_fitness_(p_fitness),\n#endif\n\tage_(p_age), index_(p_individual_index), subpopulation_(p_subpopulation)\n{\n\t// Set up our haplosomes with nullptr values initially.  If we have 0/1/2 haplosomes total, we use our\n\t// internal buffer for speed; avoid malloc/free entirely, and even more important, get the memory\n\t// locality of having the haplosome pointers right inside the individual itself.  Otherwise, we alloc\n\t// an external buffer, which entails fetching a new cache line to go through the indirection.\n\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\n\tif (haplosome_count_per_individual <= 2)\n\t{\n\t\thapbuffer_[0] = nullptr;\n\t\thapbuffer_[1] = nullptr;\n\t\thaplosomes_ = hapbuffer_;\n\t}\n\telse\n\t{\n\t\thaplosomes_ = (Haplosome **)calloc(haplosome_count_per_individual, sizeof(Haplosome *));\n\t}\n\t\n\t// Initialize tag values to the \"unset\" value\n\ttag_value_ = SLIM_TAG_UNSET_VALUE;\n\ttagF_value_ = SLIM_TAGF_UNSET_VALUE;\n\ttagL0_set_ = false;\n\ttagL1_set_ = false;\n\ttagL2_set_ = false;\n\ttagL3_set_ = false;\n\ttagL4_set_ = false;\n\t\n\t// Initialize x/y/z to 0.0, only when leak-checking (they show up as used before initialized in Valgrind)\n#if SLIM_LEAK_CHECKING\n\tspatial_x_ = 0.0;\n\tspatial_y_ = 0.0;\n\tspatial_z_ = 0.0;\n#endif\n}\n\nIndividual::~Individual(void)\n{\n\t// BCH 10/6/2024: Individual now owns the haplosomes inside it (a policy change for multichrom)\n\t// BCH 10/12/2024: Note that this might no longer be called except at simulation end; see FreeSubpopIndividual()\n\tSubpopulation *subpop = subpopulation_;\n\t\n\t// The subpopulation_ pointer is set to nullptr when an individual is placed in individuals_junkyard_;\n\t// in that case, its haplosomes have already been freed, so this loop does not need to run.\n\tif (subpopulation_)\n\t{\n\t\tconst std::vector<Chromosome *> &chromosome_for_haplosome_index = subpopulation_->species_.ChromosomesForHaplosomeIndices();\n\t\tint haplosome_count_per_individual = subpop->HaplosomeCountPerIndividual();\n\t\tHaplosome **haplosomes = haplosomes_;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\n\t\t\t// haplosome pointers can be nullptr, if an individual has already freed its haplosome objects;\n\t\t\t// this happens when an individual is placed in individuals_junkyard_, in particular\n\t\t\tif (haplosome)\n\t\t\t{\n\t\t\t\tChromosome *chromosome = chromosome_for_haplosome_index[haplosome_index];\n\t\t\t\t\n\t\t\t\tchromosome->FreeHaplosome(haplosome);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (haplosomes_ != hapbuffer_)\n\t\tfree(haplosomes_);\n\t\n#if DEBUG\n\thaplosomes_ = nullptr;\n#endif\n}\n\n#if DEBUG\nvoid Individual::AddHaplosomeAtIndex(Haplosome *p_haplosome, int p_index)\n{\n\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\n\tif ((p_index < 0) || (p_index >= haplosome_count_per_individual))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::AddHaplosomeAtIndex): (internal error) haplosome index \" << p_index << \" out of range.\" << EidosTerminate();\n\t\n\t// in DEBUG haplosomes_ should be zero-filled; when not in DEBUG, it may not be!\n\tif (haplosomes_[p_index])\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::AddHaplosomeAtIndex): (internal error) haplosome index \" << p_index << \" already filled.\" << EidosTerminate();\n\t\n\t// the haplosome should already know that it belongs to the individual; this method just makes the individual aware of that\n\tif (p_haplosome->individual_ != this)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::AddHaplosomeAtIndex): (internal error) haplosome individual_ pointer not set up.\" << EidosTerminate();\n\t\n\thaplosomes_[p_index] = p_haplosome;\n}\n#endif\n\nvoid Individual::AppendHaplosomesForChromosomes(EidosValue_Object *vec, std::vector<slim_chromosome_index_t> &chromosome_indices, int64_t index, bool includeNulls)\n{\n\tSpecies &species = subpopulation_->species_;\n\t\n\tfor (slim_chromosome_index_t chromosome_index : chromosome_indices)\n\t{\n\t\tChromosome *chromosome = species.Chromosomes()[chromosome_index];\n\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome_index];\n\t\t\n\t\tswitch (chromosome->Type())\n\t\t{\n\t\t\t\t// diploid chromosome types, where we will use index if supplied\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\tif ((index == -1) || (index == 0))\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes_[first_haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (includeNulls || !haplosome->IsNull())\n\t\t\t\t\t\tvec->push_object_element_NORR(haplosome);\n\t\t\t\t}\n\t\t\t\tif ((index == -1) || (index == 1))\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes_[first_haplosome_index+1];\n\t\t\t\t\t\n\t\t\t\t\tif (includeNulls || !haplosome->IsNull())\n\t\t\t\t\t\tvec->push_object_element_NORR(haplosome);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// haploid chromosome types, where index is ignored\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// the null is just ignored by this code\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes_[first_haplosome_index];\n\t\t\t\t\n\t\t\t\tif (includeNulls || !haplosome->IsNull())\n\t\t\t\t\tvec->push_object_element_NORR(haplosome);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// haploid chromosome types with a null haplosome first; index is ignored\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes_[first_haplosome_index+1];\t// the (possibly) non-null haplosome\n\t\t\t\t\n\t\t\t\tif (includeNulls || !haplosome->IsNull())\n\t\t\t\t\tvec->push_object_element_NORR(haplosome);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic inline bool _InPedigree(slim_pedigreeid_t A, slim_pedigreeid_t A_P1, slim_pedigreeid_t A_P2, slim_pedigreeid_t A_G1, slim_pedigreeid_t A_G2, slim_pedigreeid_t A_G3, slim_pedigreeid_t A_G4, slim_pedigreeid_t B)\n{\n\tif (B == -1)\n\t\treturn false;\n\t\n\tif ((A == B) || (A_P1 == B) || (A_P2 == B) || (A_G1 == B) || (A_G2 == B) || (A_G3 == B) || (A_G4 == B))\n\t\treturn true;\n\t\n\treturn false;\n}\n\nstatic double _Relatedness(slim_pedigreeid_t A, slim_pedigreeid_t A_P1, slim_pedigreeid_t A_P2, slim_pedigreeid_t A_G1, slim_pedigreeid_t A_G2, slim_pedigreeid_t A_G3, slim_pedigreeid_t A_G4,\n\t\t\t\t\t\t   slim_pedigreeid_t B, slim_pedigreeid_t B_P1, slim_pedigreeid_t B_P2, slim_pedigreeid_t B_G1, slim_pedigreeid_t B_G2, slim_pedigreeid_t B_G3, slim_pedigreeid_t B_G4)\n{\n\tif ((A == -1) || (B == -1))\n\t{\n\t\t// Unknown pedigree IDs do not match anybody\n\t\treturn 0.0;\n\t}\n\telse if (A == B)\n\t{\n\t\t// An individual matches itself with relatedness 1.0\n\t\treturn 1.0;\n\t}\n\telse {\n\t\tdouble out = 0.0;\n\t\t\n\t\tif (_InPedigree(B, B_P1, B_P2, B_G1, B_G2, B_G3, B_G4, A))\t\t// if A is in B...\n\t\t{\n\t\t\tout += _Relatedness(A, A_P1, A_P2, A_G1, A_G2, A_G3, A_G4, B_P1, B_G1, B_G2, -1, -1, -1, -1) / 2.0;\n\t\t\tout += _Relatedness(A, A_P1, A_P2, A_G1, A_G2, A_G3, A_G4, B_P2, B_G3, B_G4, -1, -1, -1, -1) / 2.0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tout += _Relatedness(A_P1, A_G1, A_G2, -1, -1, -1, -1, B, B_P1, B_P2, B_G1, B_G2, B_G3, B_G4) / 2.0;\n\t\t\tout += _Relatedness(A_P2, A_G3, A_G4, -1, -1, -1, -1, B, B_P1, B_P2, B_G1, B_G2, B_G3, B_G4) / 2.0;\n\t\t}\n\t\t\n\t\treturn out;\n\t}\n}\n\ndouble Individual::_Relatedness(slim_pedigreeid_t A, slim_pedigreeid_t A_P1, slim_pedigreeid_t A_P2, slim_pedigreeid_t A_G1, slim_pedigreeid_t A_G2, slim_pedigreeid_t A_G3, slim_pedigreeid_t A_G4,\n\t\t\t\t\t\t\t\tslim_pedigreeid_t B, slim_pedigreeid_t B_P1, slim_pedigreeid_t B_P2, slim_pedigreeid_t B_G1, slim_pedigreeid_t B_G2, slim_pedigreeid_t B_G3, slim_pedigreeid_t B_G4,\n\t\t\t\t\t\t\t\tIndividualSex A_sex, IndividualSex B_sex, ChromosomeType p_chromosome_type)\n{\n\t// This version of _Relatedness() corrects for the sex chromosome case.  It should be regarded as the top-level internal API here.\n\t// This is separate from RelatednessToIndividual(), and implemented as a static member function, for unit testing; we want an\n\t// API that unit tests can call without needing to actually have a constructed Individual object.\n\t\n\t// Correct for sex-chromosome simulations; the only individuals that count are those that pass on the sex chromosome to the\n\t// child.  We can do that here since we know that the first parent of a given individual is female and the second is male.\n\t// If individuals are cloning, then both parents will be the same sex as the offspring, in fact, but we still want to\n\t// treat it the same I think (?).  For example, a male offspring from biparental mating inherits an X from its female\n\t// parent only; a male offspring from cloning still inherits only one sex chromosome from its parent, so the same correction\n\t// seems appropriate still.\n\t\n#if DEBUG\n\tif ((p_chromosome_type != ChromosomeType::kA_DiploidAutosome) && ((A_sex == IndividualSex::kHermaphrodite) || (B_sex == IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::_Relatedness): (internal error) hermaphrodites cannot exist when modeling a sex chromosome\" << EidosTerminate();\n\tif (((A_sex == IndividualSex::kHermaphrodite) && (B_sex != IndividualSex::kHermaphrodite)) || ((A_sex != IndividualSex::kHermaphrodite) && (B_sex == IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::_Relatedness): (internal error) hermaphrodites cannot coexist with males and females\" << EidosTerminate();\n\tif (((A_sex == IndividualSex::kMale) && (B_P1 == A) && (B_P1 != B_P2)) ||\n\t\t((B_sex == IndividualSex::kMale) && (A_P1 == B) && (A_P1 != A_P2)) ||\n\t\t((A_sex == IndividualSex::kFemale) && (B_P2 == A) && (B_P2 != B_P1)) ||\n\t\t((B_sex == IndividualSex::kFemale) && (A_P2 == B) && (A_P2 != A_P1)))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::_Relatedness): (internal error) a male was indicated as a first parent, or a female as second parent, without clonality\" << EidosTerminate();\n#endif\n\t\n\tswitch (p_chromosome_type)\n\t{\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t{\n\t\t\t// No intervention needed (we assume that inheritance was normal, without null haplosomes)\n\t\t\t// For \"H\", recombination is possible if there are two parents, so this is the same as \"A\"\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t{\n\t\t\t// For \"H-\", the second parent should always match the first (by cloning), but we make sure of it\n\t\t\tB_P1 = A_P1;\n\t\t\tB_P2 = A_P2;\n\t\t\tB_G1 = A_G1;\n\t\t\tB_G2 = A_G2;\n\t\t\tB_G3 = A_G3;\n\t\t\tB_G4 = A_G4;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t{\n\t\t\t// Whichever sex A is, its second parent (A_P2) is male and so its male parent (A_G4) gave A_P2 a Y, not an X\n\t\t\tA_G4 = A_G3;\n\t\t\t\n\t\t\tif (A_sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// If A is male, its second parent (male) gave it a Y, not an X\n\t\t\t\tA_P2 = A_P1;\n\t\t\t\tA_G3 = A_G1;\n\t\t\t\tA_G4 = A_G2;\n\t\t\t}\n\t\t\t\n\t\t\t// Whichever sex B is, its second parent (B_P2) is male and so its male parent (B_G4) gave B_P2 a Y, not an X\n\t\t\tB_G4 = B_G3;\n\t\t\t\n\t\t\tif (B_sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// If B is male, its second parent (male) gave it a Y, not an X\n\t\t\t\tB_P2 = B_P1;\n\t\t\t\tB_G3 = B_G1;\n\t\t\t\tB_G4 = B_G2;\n\t\t\t}\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\t// When modeling the Y, females have no relatedness to anybody else except themselves, defined as 1.0 for consistency\n\t\t\tif ((A_sex == IndividualSex::kFemale) || (B_sex == IndividualSex::kFemale))\n\t\t\t{\n\t\t\t\tif (A == B)\n\t\t\t\t\treturn 1.0;\n\t\t\t\treturn 0.0;\n\t\t\t}\n\t\t\t\n\t\t\t// The female parents (A_P1 and B_P1) and their parents, and female grandparents (A_G3 and B_G3), do not contribute\n\t\t\tA_G3 = A_G4;\n\t\t\tA_P1 = A_P2;\n\t\t\tA_G1 = A_G3;\n\t\t\tA_G2 = A_G4;\n\t\t\t\n\t\t\tB_G3 = B_G4;\n\t\t\tB_P1 = B_P2;\n\t\t\tB_G1 = B_G3;\n\t\t\tB_G2 = B_G4;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t{\n\t\t\t// inherited from the male parent, so only the male (second) parents count\n\t\t\t// BCH 27 August 2025: Note that HM is now legal in non-sexual models; \"male\" just means \"second\"\n\t\t\tA_G3 = A_G4;\n\t\t\tA_P1 = A_P2;\n\t\t\tA_G1 = A_G3;\n\t\t\tA_G2 = A_G4;\n\t\t\t\n\t\t\tB_G3 = B_G4;\n\t\t\tB_P1 = B_P2;\n\t\t\tB_G1 = B_G3;\n\t\t\tB_G2 = B_G4;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t{\n\t\t\t// Whichever sex A is, its first parent (A_P1) is female and so its female parent (A_G1) gave A_P1 a W, not a Z\n\t\t\tA_G1 = A_G2;\n\t\t\t\n\t\t\tif (A_sex == IndividualSex::kFemale)\n\t\t\t{\n\t\t\t\t// If A is female, its first parent (female) gave it a W, not a Z\n\t\t\t\tA_P1 = A_P2;\n\t\t\t\tA_G1 = A_G3;\n\t\t\t\tA_G2 = A_G4;\n\t\t\t}\n\t\t\t\n\t\t\t// Whichever sex B is, its first parent (B_P1) is female and so its female parent (B_G1) gave B_P1 a W, not a Z\n\t\t\tB_G1 = B_G2;\n\t\t\t\n\t\t\tif (B_sex == IndividualSex::kFemale)\n\t\t\t{\n\t\t\t\t// If B is female, its first parent (female) gave it a W, not a Z\n\t\t\t\tB_P1 = B_P2;\n\t\t\t\tB_G1 = B_G3;\n\t\t\t\tB_G2 = B_G4;\n\t\t\t}\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t{\n\t\t\t// When modeling the W, males have no relatedness to anybody else except themselves, defined as 1.0 for consistency\n\t\t\tif ((A_sex == IndividualSex::kMale) || (B_sex == IndividualSex::kMale))\n\t\t\t{\n\t\t\t\tif (A == B)\n\t\t\t\t\treturn 1.0;\n\t\t\t\treturn 0.0;\n\t\t\t}\n\t\t\t\n\t\t\t// The male parents (A_P2 and B_P2) and their parents, and male grandparents (A_G2 and B_G2), do not contribute\n\t\t\tA_G2 = A_G1;\n\t\t\tA_P2 = A_P1;\n\t\t\tA_G3 = A_G1;\n\t\t\tA_G4 = A_G2;\n\t\t\t\n\t\t\tB_G2 = B_G1;\n\t\t\tB_P2 = B_P1;\n\t\t\tB_G3 = B_G1;\n\t\t\tB_G4 = B_G2;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t{\n\t\t\t// inherited from the female parent, so only the female (first) parents count\n\t\t\t// BCH 27 August 2025: Note that HF is now legal in non-sexual models; \"female\" just means \"first\"\n\t\t\tA_G2 = A_G1;\n\t\t\tA_P2 = A_P1;\n\t\t\tA_G3 = A_G1;\n\t\t\tA_G4 = A_G2;\n\t\t\t\n\t\t\tB_G2 = B_G1;\n\t\t\tB_P2 = B_P1;\n\t\t\tB_G3 = B_G1;\n\t\t\tB_G4 = B_G2;\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn ::_Relatedness(A, A_P1, A_P2, A_G1, A_G2, A_G3, A_G4, B, B_P1, B_P2, B_G1, B_G2, B_G3, B_G4);\n}\n\ndouble Individual::RelatednessToIndividual(Individual &p_ind, ChromosomeType p_chromosome_type)\n{\n\t// So, the goal is to calculate A and B's relatedness, given pedigree IDs for themselves and (perhaps) for their parents and\n\t// grandparents.  Note that a pedigree ID of -1 means \"no information\"; for a given cycle, information should either be\n\t// available for everybody, or for nobody (the latter occurs when that cycle is prior to the start of forward simulation).\n\t// So we have these ancestry trees:\n\t//\n\t//         G1  G2 G3  G4     G5  G6 G7  G8\n\t//          \\  /   \\  /       \\  /   \\  /\n\t//           P1     P2         P3     P4\n\t//            \\     /           \\     /\n\t//             \\   /             \\   /\n\t//              \\ /               \\ /\n\t//               A                 B\n\t//\n\t// If A and B are same individual, the relatedness is 1.0.  Otherwise, we need to determine the amount of consanguinity between\n\t// A and B.  If A is a parent of B (P3 or P4), their relatedness is 0.5; if A is a grandparent of B (G5/G6/G7/G8), then their\n\t// relatedness is 0.25.  A could also appear in B's tree more than once, but A cannot be its own parent.  So if A==P3, then A\n\t// cannot also be G5 or G6, and indeed, we do not need to look at G5 or G6 at all; the fact that A==P3 tells us everything we\n\t// we need to know about that half of B's tree, with a contribution of 0.5.  But it could *additionally* be true that A==P4,\n\t// giving another 0.5 for 1.0 total; or that A==G7, for 0.25; or that A==G8, for 0.25; for that A==G7 *and* A==G8, for 0.5,\n\t// making 1.0 total.  Basically, whenever you see A at a given position you do not need to look further upward from that node,\n\t// but you must still look at other nodes.  To do this properly, recursion is the simplest approach; this algorithm is thanks\n\t// to Peter Ralph.\n\t//\n\tIndividual &indA = *this, &indB = p_ind;\n\t\n\tslim_pedigreeid_t A = indA.pedigree_id_;\n\tslim_pedigreeid_t A_P1 = indA.pedigree_p1_;\n\tslim_pedigreeid_t A_P2 = indA.pedigree_p2_;\n\tslim_pedigreeid_t A_G1 = indA.pedigree_g1_;\n\tslim_pedigreeid_t A_G2 = indA.pedigree_g2_;\n\tslim_pedigreeid_t A_G3 = indA.pedigree_g3_;\n\tslim_pedigreeid_t A_G4 = indA.pedigree_g4_;\n\tslim_pedigreeid_t B = indB.pedigree_id_;\n\tslim_pedigreeid_t B_P1 = indB.pedigree_p1_;\n\tslim_pedigreeid_t B_P2 = indB.pedigree_p2_;\n\tslim_pedigreeid_t B_G1 = indB.pedigree_g1_;\n\tslim_pedigreeid_t B_G2 = indB.pedigree_g2_;\n\tslim_pedigreeid_t B_G3 = indB.pedigree_g3_;\n\tslim_pedigreeid_t B_G4 = indB.pedigree_g4_;\n\t\n\treturn _Relatedness(A, A_P1, A_P2, A_G1, A_G2, A_G3, A_G4, B, B_P1, B_P2, B_G1, B_G2, B_G3, B_G4, indA.sex_, indB.sex_, p_chromosome_type);\n}\n\nint Individual::_SharedParentCount(slim_pedigreeid_t X_P1, slim_pedigreeid_t X_P2, slim_pedigreeid_t Y_P1, slim_pedigreeid_t Y_P2)\n{\n\t// This is the top-level internal API here.  It is separate from RelatednessToIndividual(), and\n\t// implemented as a static member function, for unit testing; we want an\n\t// API that unit tests can call without needing to actually have a constructed Individual object.\n\t\n\t// If one individual is missing parent information, return 0\n\tif ((X_P1 == -1) || (X_P2 == -1) || (Y_P1 == -1) || (Y_P2 == -1))\n\t\treturn 0;\n\t\n\t// If both parents match, in one way or another, then they must be full siblings\n\tif ((X_P1 == Y_P1) && (X_P2 == Y_P2))\n\t\treturn 2;\n\tif ((X_P1 == Y_P2) && (X_P2 == Y_P1))\n\t\treturn 2;\n\t\n\t// Otherwise, if one parent matches, they must be half siblings\n\tif ((X_P1 == Y_P1) || (X_P1 == Y_P2) || (X_P2 == Y_P1) || (X_P2 == Y_P2))\n\t\treturn 1;\n\t\n\t// Otherwise, they are not siblings\n\treturn 0;\n}\n\nint Individual::SharedParentCountWithIndividual(Individual &p_ind)\n{\n\t// This is much simpler than Individual::RelatednessToIndividual(); we just want the shared parent count.  That is\n\t// defined, for two individuals X and Y with parents in {A, B, C, D}, as:\n\t//\n\t//\tAB CD -> 0 (no shared parents)\n\t//\tAB CC -> 0 (no shared parents)\n\t//\tAB AC -> 1 (half siblings)\n\t//\tAB AA -> 1 (half siblings)\n\t//\tAA AB -> 1 (half siblings)\n\t//\tAB AB -> 2 (full siblings)\n\t//\tAB BA -> 2 (full siblings)\n\t//\tAA AA -> 2 (full siblings)\n\t//\n\t// If X is itself a parent of Y, or vice versa, that is irrelevant for this method; we are not measuring\n\t// consanguinity here.\n\t//\n\tIndividual &indX = *this, &indY = p_ind;\n\t\n\tslim_pedigreeid_t X_P1 = indX.pedigree_p1_;\n\tslim_pedigreeid_t X_P2 = indX.pedigree_p2_;\n\tslim_pedigreeid_t Y_P1 = indY.pedigree_p1_;\n\tslim_pedigreeid_t Y_P2 = indY.pedigree_p2_;\n\t\n\treturn _SharedParentCount(X_P1, X_P2, Y_P1, Y_P2);\n}\n\n// print a vector of individuals, with all mutations and all haplosomes, to a stream\n// this takes a focal chromosome; if nullptr, data from all chromosomes is printed\nvoid Individual::PrintIndividuals_SLiM(std::ostream &p_out, const Individual **p_individuals, int64_t p_individuals_count, Species &species, bool p_output_spatial_positions, bool p_output_ages, bool p_output_ancestral_nucs, bool p_output_pedigree_ids, bool p_output_object_tags, bool p_output_substitutions, Chromosome *p_focal_chromosome)\n{\n\tPopulation &population = species.population_;\n\tCommunity &community = species.community_;\n\t\n\tif (population.child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::PrintIndividuals_SLiM): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n#if DO_MEMORY_CHECKS\n\t// This method can burn a huge amount of memory and get us killed, if we have a maximum memory usage.  It's nice to\n\t// try to check for that and terminate with a proper error message, to help the user diagnose the problem.\n\tint mem_check_counter = 0, mem_check_mod = 100;\n\t\n\tif (eidos_do_memory_checks)\n\t\tEidos_CheckRSSAgainstMax(\"Individual::PrintIndividuals_SLiM\", \"(The memory usage was already out of bounds on entry.)\");\n#endif\n\t\n\t// this method now handles outputFull() as well as outputIndividuals()\n\tbool output_full_population = (p_individuals == nullptr);\n\t\n\tif (output_full_population)\n\t{\n\t\t// We need to set up an individuals vector that contains all individuals, so we can share code below\n\t\tint64_t total_population_size = 0;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\t\n\t\t\ttotal_population_size += subpop_size;\n\t\t}\n\t\t\n\t\tp_individuals = (const Individual **)malloc(total_population_size * sizeof(Individual *));\n\t\tp_individuals_count = total_population_size;\n\t\t\n\t\tconst Individual **ind_buffer_ptr = p_individuals;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\t\n\t\t\tfor (slim_popsize_t i = 0; i < subpop_size; i++)\t\t\t\t// go through all children\n\t\t\t\t*(ind_buffer_ptr++) = subpop->parent_individuals_[i];\n\t\t}\n\t}\n\t\n\t// write the #OUT line\n\tp_out << \"#OUT: \" << community.Tick() << \" \" << species.Cycle() << (output_full_population ? \" A\" : \" IS\") << std::endl;\n\t\n\t// Figure out spatial position output.  If it was not requested, then we don't do it, and that's fine.  If it\n\t// was requested, then we output the number of spatial dimensions we're configured for (which might be zero).\n\tint spatial_output_count = (p_output_spatial_positions ? species.SpatialDimensionality() : 0);\n\t\n\t// Figure out age output.  If it was not requested, don't do it; if it was requested, do it if we use a nonWF model.\n\tint age_output_count = (p_output_ages && (species.model_type_ == SLiMModelType::kModelTypeNonWF)) ? 1 : 0;\n\t\n\t// Starting in SLiM 2.3, we output a version indicator at the top of the file so we can decode different\n\t// versions, etc.  Starting in SLiM 5, the version number is again synced with PrintAllBinary() (skipping\n\t// over 7 directly to 8), and the crazy four-way version number scheme that encoded flags is gone. See\n\t// PrintAllBinary() for the version history; but with version 8 we break backward compatibility anyway.\n\tp_out << \"Version: 8\" << std::endl;\n\t\n\t// Starting with version 8 (SLiM 5.0), we write out some flags; this information used to be incorporated into\n\t// the version number, which was gross.  Now we write out flags for all optional output that is enabled.\n\t// Reading code can assume that if a flag is not present, that output is not present.\n\tbool has_nucleotides = species.IsNucleotideBased();\n\tbool output_ancestral_nucs = has_nucleotides && p_output_ancestral_nucs;\n\t\n\tp_out << \"Flags:\";\n\tif (spatial_output_count)\t\tp_out << \" SPACE=\" << spatial_output_count;\n\tif (age_output_count)\t\t\tp_out << \" AGES\";\n\tif (p_output_pedigree_ids)\t\tp_out << \" PEDIGREES\";\n\tif (has_nucleotides)\t\t\tp_out << \" NUC\";\n\tif (output_ancestral_nucs)\t\tp_out << \" ANC_SEQ\";\n\tif (p_output_object_tags)\t\tp_out << \" OBJECT_TAGS\";\n\tif (p_output_substitutions)\t\tp_out << \" SUBSTITUTIONS\";\n\tp_out << std::endl;\n\t\n\t// Output populations first, for outputFull() only\n\tif (output_full_population)\n\t{\n\t\tp_out << \"Populations:\" << std::endl;\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\tdouble subpop_sex_ratio;\n\t\t\t\n\t\t\tif (species.model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\t{\n\t\t\t\tsubpop_sex_ratio = subpop->parent_sex_ratio_;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We want to output empty (but not removed) subpops, so we use a sex ratio of 0.0 to prevent div by 0\n\t\t\t\tif (subpop->parent_subpop_size_ == 0)\n\t\t\t\t\tsubpop_sex_ratio = 0.0;\n\t\t\t\telse\n\t\t\t\t\tsubpop_sex_ratio = 1.0 - (subpop->parent_first_male_index_ / (double)subpop->parent_subpop_size_);\n\t\t\t}\n\t\t\t\n\t\t\tp_out << \"p\" << subpop_pair.first << \" \" << subpop_size;\n\t\t\t\n\t\t\t// SEX ONLY\n\t\t\tif (subpop->sex_enabled_)\n\t\t\t\tp_out << \" S \" << subpop_sex_ratio;\n\t\t\telse\n\t\t\t\tp_out << \" H\";\n\t\t\t\n\t\t\tif (p_output_object_tags)\n\t\t\t{\n\t\t\t\tif (subpop->tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\t\t\t\tp_out << \" ?\";\n\t\t\t\telse\n\t\t\t\t\tp_out << ' ' << subpop->tag_value_;\n\t\t\t}\n\t\t\t\n\t\t\tp_out << std::endl;\n\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\tif (eidos_do_memory_checks)\n\t\t\t{\n\t\t\t\tmem_check_counter++;\n\t\t\t\t\n\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t\tEidos_CheckRSSAgainstMax(\"Individual::PrintIndividuals_SLiM\", \"(Out of memory while outputting population list.)\");\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\t// print all individuals; this used to come after the Mutations: section, but now mutations are per-chromosome,\n\t// whereas the list of individuals is invariant across all of the chromosomes printed, and so must come before\n\tp_out << \"Individuals:\" << std::endl;\n\t\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Individual::PrintIndividuals_SLiM(): usage of statics\");\n\tstatic char double_buf[40];\n\t\n\tfor (int64_t individual_index = 0; individual_index < p_individuals_count; ++individual_index)\n\t{\n\t\tconst Individual &individual = *(p_individuals[individual_index]);\n\t\tSubpopulation *subpop = individual.subpopulation_;\n\t\tslim_popsize_t index_in_subpop = individual.index_;\n\t\t\n\t\tif (!subpop || (index_in_subpop == -1))\n\t\t{\n\t\t\tif (output_full_population)\n\t\t\t\tfree(p_individuals);\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::PrintIndividuals_SLiM): target individuals must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tp_out << \"p\" << subpop->subpopulation_id_ << \":i\" << index_in_subpop;\t\t\t\t\t\t// individual identifier\n\t\t\n\t\t// BCH 9/13/2020: adding individual pedigree IDs, for SLiM 3.5, format version 5/6\n\t\tif (p_output_pedigree_ids)\n\t\t\tp_out << \" \" << individual.PedigreeID();\n\t\t\n\t\tp_out << ' ' << individual.sex_;\n\t\t\n\t\t// BCH 2/5/2025: Before version 8, we emitted haplosome identifiers here, like \"p1:16\" and\n\t\t// \"p1:17\", but now that we have multiple chromosomes that really isn't helpful; removing\n\t\t// them.  In the Haplosomes section we will now just identify the individual; that suffices.\n\t\t\n\t\t// output spatial position if requested; BCH 22 March 2019 switch to full precision for this, for accurate reloading\n\t\tif (spatial_output_count)\n\t\t{\n\t\t\tif (spatial_output_count >= 1)\n\t\t\t{\n\t\t\t\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_DBL_DIGS, individual.spatial_x_);\t\t// necessary precision for non-lossiness\n\t\t\t\tp_out << \" \" << double_buf;\n\t\t\t}\n\t\t\tif (spatial_output_count >= 2)\n\t\t\t{\n\t\t\t\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_DBL_DIGS, individual.spatial_y_);\t\t// necessary precision for non-lossiness\n\t\t\t\tp_out << \" \" << double_buf;\n\t\t\t}\n\t\t\tif (spatial_output_count >= 3)\n\t\t\t{\n\t\t\t\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_DBL_DIGS, individual.spatial_z_);\t\t// necessary precision for non-lossiness\n\t\t\t\tp_out << \" \" << double_buf;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// output ages if requested\n\t\tif (age_output_count)\n\t\t\tp_out << \" \" << individual.age_;\n\t\t\n\t\t// output individual tags if requested\n\t\tif (p_output_object_tags)\n\t\t{\n\t\t\tif (individual.tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tp_out << \" ?\";\n\t\t\telse\n\t\t\t\tp_out << ' ' << individual.tag_value_;\n\t\t\t\n\t\t\tif (individual.tagF_value_ == SLIM_TAGF_UNSET_VALUE)\n\t\t\t\tp_out << \" ?\";\n\t\t\telse\n\t\t\t{\n\t\t\t\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_DBL_DIGS, individual.tagF_value_);\t\t// necessary precision for non-lossiness\n\t\t\t\tp_out << \" \" << double_buf;\n\t\t\t}\n\t\t\t\n\t\t\tif (individual.tagL0_set_)\n\t\t\t\tp_out << ' ' << (individual.tagL0_value_ ? 'T' : 'F');\n\t\t\telse\n\t\t\t\tp_out << \" ?\";\n\t\t\t\n\t\t\tif (individual.tagL1_set_)\n\t\t\t\tp_out << ' ' << (individual.tagL1_value_ ? 'T' : 'F');\n\t\t\telse\n\t\t\t\tp_out << \" ?\";\n\t\t\t\n\t\t\tif (individual.tagL2_set_)\n\t\t\t\tp_out << ' ' << (individual.tagL2_value_ ? 'T' : 'F');\n\t\t\telse\n\t\t\t\tp_out << \" ?\";\n\t\t\t\n\t\t\tif (individual.tagL3_set_)\n\t\t\t\tp_out << ' ' << (individual.tagL3_value_ ? 'T' : 'F');\n\t\t\telse\n\t\t\t\tp_out << \" ?\";\n\t\t\t\n\t\t\tif (individual.tagL4_set_)\n\t\t\t\tp_out << ' ' << (individual.tagL4_value_ ? 'T' : 'F');\n\t\t\telse\n\t\t\t\tp_out << \" ?\";\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t\t\n#if DO_MEMORY_CHECKS\n\t\tif (eidos_do_memory_checks)\n\t\t{\n\t\t\tmem_check_counter++;\n\t\t\t\n\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\tEidos_CheckRSSAgainstMax(\"Population::PrintAll\", \"(Out of memory while printing individuals.)\");\n\t\t}\n#endif\n\t}\n\t\n\t// Loop over chromosomes and output data for each\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\t// if we have a focal chromosome, skip all the other chromosomes\n\t\tif (p_focal_chromosome && (chromosome != p_focal_chromosome))\n\t\t\tcontinue;\n\t\t\n\t\t// write information about the chromosome; note that we write the chromosome symbol, but PrintAllBinary() does not\n\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\n\t\tp_out << \"Chromosome: \" << (uint32_t)chromosome_index << \" \" << chromosome->Type() << \" \" << chromosome->ID() << \" \" << chromosome->last_position_ << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\n\t\t\n\t\tif (p_output_object_tags)\n\t\t{\n\t\t\tif (chromosome->tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tp_out << \" ?\";\n\t\t\telse\n\t\t\t\tp_out << ' ' << chromosome->tag_value_;\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t\t\n\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species.LastHaplosomeIndices()[chromosome_index];\n\t\tPolymorphismMap polymorphisms;\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\t// add all polymorphisms for this chromosome\n\t\tfor (int64_t individual_index = 0; individual_index < p_individuals_count; ++individual_index)\n\t\t{\n\t\t\tconst Individual *ind = p_individuals[individual_index];\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t}\n\t\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\t\tif (eidos_do_memory_checks)\n\t\t\t\t{\n\t\t\t\t\tmem_check_counter++;\n\t\t\t\t\t\n\t\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t\t\tEidos_CheckRSSAgainstMax(\"Population::PrintAll\", \"(Out of memory while assembling polymorphisms.)\");\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t}\n\t\t\n\t\t// print all polymorphisms\n\t\tp_out << \"Mutations:\"  << std::endl;\n\t\t\n\t\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms)\n\t\t{\n\t\t\t// NOTE this added mutation_id_, BCH 11 June 2016\n\t\t\t// NOTE the output format changed due to the addition of the nucleotide, BCH 2 March 2019\n\t\t\tif (p_output_object_tags)\n\t\t\t\tpolymorphism_pair.second.Print_ID_Tag(p_out);\n\t\t\telse\n\t\t\t\tpolymorphism_pair.second.Print_ID(p_out);\n\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\tif (eidos_do_memory_checks)\n\t\t\t{\n\t\t\t\tmem_check_counter++;\n\t\t\t\t\n\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t\tEidos_CheckRSSAgainstMax(\"Population::PrintAll\", \"(Out of memory while printing polymorphisms.)\");\n\t\t\t}\n#endif\n\t\t}\n\t\t\n\t\t// print all haplosomes\n\t\tp_out << \"Haplosomes:\" << std::endl;\n\t\t\n\t\tfor (int64_t individual_index = 0; individual_index < p_individuals_count; ++individual_index)\n\t\t{\n\t\t\tconst Individual *ind = p_individuals[individual_index];\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\t// i used to be the haplosome index, now it is the individual index; we will have one or\n\t\t\t\t// two lines with this individual index, depending on the intrinsic ploidy of the chromosome\n\t\t\t\t// since we changed from a haplosome index to an individual index, we now emit an \"i\",\n\t\t\t\t// just follow the same convention as the Individuals section\n\t\t\t\tp_out << \"p\" << ind->subpopulation_->subpopulation_id_ << \":i\" << ind->index_;\n\t\t\t\t\n\t\t\t\tif (p_output_object_tags)\n\t\t\t\t{\n\t\t\t\t\tif (haplosome->tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\t\t\t\t\tp_out << \" ?\";\n\t\t\t\t\telse\n\t\t\t\t\t\tp_out << ' ' << haplosome->tag_value_;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t{\n\t\t\t\t\tp_out << \" <null>\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_polymorphismid_t polymorphism_id = FindMutationInPolymorphismMap(polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (polymorphism_id == -1)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintAll): (internal error) polymorphism not found.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tp_out << \" \" << polymorphism_id;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tp_out << std::endl;\n\t\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\t\tif (eidos_do_memory_checks)\n\t\t\t\t{\n\t\t\t\t\tmem_check_counter++;\n\t\t\t\t\t\n\t\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t\t\tEidos_CheckRSSAgainstMax(\"Population::PrintAll\", \"(Out of memory while printing haplosomes.)\");\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t}\n\t\t\n\t\t// print ancestral sequence\n\t\tif (output_ancestral_nucs)\n\t\t{\n\t\t\tp_out << \"Ancestral sequence:\" << std::endl;\n\t\t\tp_out << *(chromosome->AncestralSequence());\n\t\t\t\n\t\t\t// operator<< above ends with a newline; here we add another, which the read code\n\t\t\t// can use to recognize that the nucleotide sequence has ended, even without an EOF\n\t\t\tp_out << std::endl;\n\t\t}\n\t}\n\t\n\t// Output substitutions at the end if requested; see Species::ExecuteMethod_outputFixedMutations()\n\tif (output_full_population && p_output_substitutions)\n\t{\n\t\tp_out << \"Substitutions:\" << std::endl;\n\t\t\n\t\tstd::vector<Substitution*> &subs = population.substitutions_;\n\t\t\n\t\tfor (unsigned int i = 0; i < subs.size(); i++)\n\t\t{\n\t\t\tp_out << i << \" \";\n\t\t\t\n\t\t\tif (p_output_object_tags)\n\t\t\t\tsubs[i]->PrintForSLiMOutput_Tag(p_out);\n\t\t\telse\n\t\t\t\tsubs[i]->PrintForSLiMOutput(p_out);\n\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\tif (eidos_do_memory_checks)\n\t\t\t{\n\t\t\t\tmem_check_counter++;\n\t\t\t\t\n\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t\tEidos_CheckRSSAgainstMax(\"Species::ExecuteMethod_outputFixedMutations\", \"(outputFixedMutations(): Out of memory while outputting substitution objects.)\");\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\t// if we malloced a buffer of individuals above, free it now\n\tif (output_full_population)\n\t\tfree(p_individuals);\n}\n\nvoid Individual::PrintIndividuals_VCF(std::ostream &p_out, const Individual **p_individuals, int64_t p_individuals_count, Species &p_species, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs, Chromosome *p_focal_chromosome)\n{\n\tconst std::vector<Chromosome *> &chromosomes = p_species.Chromosomes();\n\tbool nucleotide_based = p_species.IsNucleotideBased();\n\tbool pedigrees_enabled = p_species.PedigreesEnabledByUser();\n\t\n\t// print the VCF header\n\tp_out << \"##fileformat=VCFv4.2\" << std::endl;\n\t\n\t{\n\t\ttime_t rawtime;\n\t\tstruct tm timeinfo;\n\t\tchar buffer[25];\t// should never be more than 10, in fact, plus a null\n\t\t\n\t\ttime(&rawtime);\n\t\tlocaltime_r(&rawtime, &timeinfo);\n\t\tstrftime(buffer, 25, \"%Y%m%d\", &timeinfo);\n\t\t\n\t\tp_out << \"##fileDate=\" << std::string(buffer) << std::endl;\n\t}\n\t\n\tp_out << \"##source=SLiM\" << std::endl;\n\t\n\t// BCH 2/11/2025: Unlike Haplosome::PrintHaplosomes_VCF(), we can print individual pedigree IDs,\n\t// since we are working with a vector of individuals, not a vector of haplosomes.\n\tif (pedigrees_enabled && (p_individuals_count > 0))\n\t{\n\t\tp_out << \"##slimIndividualPedigreeIDs=\";\n\t\t\n\t\tfor (int64_t individual_index = 0; individual_index < p_individuals_count; ++individual_index)\n\t\t{\n\t\t\tif (individual_index > 0)\n\t\t\t\tp_out << \",\";\n\t\t\tp_out << p_individuals[individual_index]->pedigree_id_;\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t}\n\t\n\t// BCH 6 March 2019: Note that all of the INFO fields that provide per-mutation information have been\n\t// changed from a Number of 1 to a Number of ., since in nucleotide-based models we can call more than\n\t// one allele in a single call line (unlike in non-nucleotide-based models).\n\tp_out << \"##INFO=<ID=MID,Number=.,Type=Integer,Description=\\\"Mutation ID in SLiM\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=S,Number=.,Type=Float,Description=\\\"Selection Coefficient\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=DOM,Number=.,Type=Float,Description=\\\"Dominance\\\">\" << std::endl;\n\t// Note that at present we do not output the hemizygous dominance coefficient; too edge\n\tp_out << \"##INFO=<ID=PO,Number=.,Type=Integer,Description=\\\"Population of Origin\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=TO,Number=.,Type=Integer,Description=\\\"Tick of Origin\\\">\" << std::endl;\t\t\t// changed to ticks for 4.0, and changed \"GO\" to \"TO\"\n\tp_out << \"##INFO=<ID=MT,Number=.,Type=Integer,Description=\\\"Mutation Type\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=AC,Number=.,Type=Integer,Description=\\\"Allele Count\\\">\" << std::endl;\n\tp_out << \"##INFO=<ID=DP,Number=1,Type=Integer,Description=\\\"Total Depth\\\">\" << std::endl;\n\tif (p_output_multiallelics && !nucleotide_based)\n\t\tp_out << \"##INFO=<ID=MULTIALLELIC,Number=0,Type=Flag,Description=\\\"Multiallelic\\\">\" << std::endl;\n\tif (nucleotide_based)\n\t\tp_out << \"##INFO=<ID=AA,Number=1,Type=String,Description=\\\"Ancestral Allele\\\">\" << std::endl;\n\tif (p_output_nonnucs && nucleotide_based)\n\t\tp_out << \"##INFO=<ID=NONNUC,Number=0,Type=Flag,Description=\\\"Non-nucleotide-based\\\">\" << std::endl;\n\tp_out << \"##FORMAT=<ID=GT,Number=1,Type=String,Description=\\\"Genotype\\\">\" << std::endl;\n\tp_out << \"##contig=<ID=1,URL=https://github.com/MesserLab/SLiM>\" << std::endl;\n\tp_out << \"#CHROM\\tPOS\\tID\\tREF\\tALT\\tQUAL\\tFILTER\\tINFO\\tFORMAT\";\n\t\n\t// When printing individual identifiers, we print the actual identifiers like p1:i17,\n\t// unlike Population::PrintSample_VCF() and Haplosome_Class::ExecuteMethod_outputX()\n\tfor (slim_popsize_t individual_index = 0; individual_index < p_individuals_count; individual_index++)\n\t{\n\t\tconst Individual &ind = *p_individuals[individual_index];\n\t\tslim_popsize_t index_in_subpop = ind.index_;\n\t\tSubpopulation *subpop = ind.subpopulation_;\n\t\t\n\t\tif (!subpop || (index_in_subpop == -1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::PrintIndividuals_VCF): target individuals must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\t\n\t\tp_out << \"\\tp\" << subpop->subpopulation_id_ << \":i\" << index_in_subpop;\n\t}\n\tp_out << std::endl;\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tif (p_focal_chromosome && (chromosome != p_focal_chromosome))\n\t\t\tcontinue;\n\t\t\n\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\tint intrinsic_ploidy = chromosome->IntrinsicPloidy();\n\t\tint first_haplosome_index_ = p_species.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index_ = p_species.LastHaplosomeIndices()[chromosome_index];\n\t\tint64_t haplosome_count = p_individuals_count * intrinsic_ploidy;\n\t\t\n\t\t// assemble a vector of haplosomes, allowing us to share code with Haplosome::PrintHaplosomes_VCF()\n\t\tconst Haplosome **haplosomes_buffer = (const Haplosome **)malloc(haplosome_count * sizeof(Haplosome *));\n\t\tint64_t haplosome_buffer_index = 0;\n\t\t\n\t\tfor (int64_t individual_index = 0; individual_index < p_individuals_count; ++individual_index)\n\t\t{\n\t\t\tconst Individual &ind = *p_individuals[individual_index];\n\t\t\t\n\t\t\tfor (slim_popsize_t i = first_haplosome_index_; i <= last_haplosome_index_; i++)\n\t\t\t\thaplosomes_buffer[haplosome_buffer_index++] = ind.haplosomes_[i];\n\t\t}\n\t\t\n\t\tHaplosome::_PrintVCF(p_out, haplosomes_buffer, haplosome_count, *chromosome,\n\t\t\t\t\t\t\t /* p_groupAsIndividuals*/ true,\n\t\t\t\t\t\t\t p_simplify_nucs,\n\t\t\t\t\t\t\t p_output_nonnucs,\n\t\t\t\t\t\t\t p_output_multiallelics);\n\t}\n}\n\n\n//\n// Eidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nvoid Individual::GenerateCachedEidosValue(void)\n{\n\t// Note that this cache cannot be invalidated as long as a symbol table might exist that this value has been placed into\n\tself_value_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Individual_Class));\n}\n\nconst EidosClass *Individual::Class(void) const\n{\n\treturn gSLiM_Individual_Class;\n}\n\nvoid Individual::Print(std::ostream &p_ostream) const\n{\n\tif (killed_)\n\t\tp_ostream << Class()->ClassNameForDisplay() << \"<KILLED>\";\n\telse\n\t\tp_ostream << Class()->ClassNameForDisplay() << \"<p\" << subpopulation_->subpopulation_id_ << \":i\" << index_ << \">\";\n}\n\nEidosValue_SP Individual::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_subpopulation:\t\t// ACCELERATED\n\t\t{\n\t\t\tif (killed_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property subpopulation is not available for individuals that have been killed; they have no subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(subpopulation_, gSLiM_Subpopulation_Class));\n\t\t}\n\t\tcase gID_index:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(index_));\n\t\t}\n\t\tcase gID_haplosomes:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->resize_no_initialize(haplosome_count_per_individual);\n\t\t\tHaplosome **haplosomes = haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tvec->set_object_element_no_check_NORR(haplosome, haplosome_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_haplosomesNonNull:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(haplosome_count_per_individual);\n\t\t\tHaplosome **haplosomes = haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_haploidGenome1:\t\t\t// ACCELERATED\n\t\tcase gID_haploidGenome1NonNull:\t\t// ACCELERATED\n\t\t\t/*\n\t\t\t A vector of all Haplosome objects associated with this individual that are attributed to its first parent (the female parent, in sexual models).  This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.  The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in initializeChromosome().  For chromosomes with two associated haplosomes (types \"A\", \"X\", \"Z\", \"H-\", and \"-Y\"), the first haplosome is assumed to be from the first parent, and is thus included, whereas the second haplosome is assumed to be from the second parent and is thus not included.  For chromosomes with one associated haplosome that is inherited from the female parent in one way or another (types \"W\", \"HF\", and \"FL\"), that haplosome is always included.  For type \"H\", the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is included.  Other chromosome types (\"Y\", \"HM\", \"ML\") are never included.  See also the haploidGenome1NonNull property and the haplosomesForChromosomes() method.\n\t\t\t */\n\t\t{\n\t\t\tbool allowNullHaplosomes = (p_property_id == gID_haploidGenome1);\n\t\t\t\n\t\t\t// the semantics of this property assume that the individual was generated by a biparental cross\n\t\t\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(haplosome_count_per_individual);\n\t\t\tHaplosome **haplosomes = haplosomes_;\n\t\t\tint haplosome_index = 0;\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : subpopulation_->species_.Chromosomes())\n\t\t\t{\n\t\t\t\tswitch (chromosome->Type())\n\t\t\t\t{\n\t\t\t\t\t\t// chromosomes that have two haplosomes, the first of which is from the first parent\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (allowNullHaplosomes || !haplosome->IsNull())\n\t\t\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so included\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (allowNullHaplosomes || !haplosome->IsNull())\n\t\t\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_haploidGenome2:\t\t\t// ACCELERATED\n\t\tcase gID_haploidGenome2NonNull:\t\t// ACCELERATED\n\t\t\t/*\n\t\t\t A vector of all Haplosome objects associated with this individual that are attributed to its second parent (the male parent, in sexual models).  This method assumes the individual was generated by the typical method for each chromosome type, as explained below; it does not trace back the true ancestry of each haplosome.  The semantics of this are more obvious for some chromosome types than others, depending on the inheritance pattern of the chromosome as described in initializeChromosome().  For chromosomes with two associated haplosomes (types \"A\", \"X\", \"Z\", \"H-\", and\"-Y\"), the second haplosome is assumed to be from the second parent, and is thus included, whereas the first haplosome is assumed to be from the first parent and is thus not included.  For chromosomes with one associated haplosome that is inherited from the male parent in one way or another (types \"Y\", \"HM\", and \"ML\"), that haplosome is always included.  For type \"H\", the single haplosome is assumed to have come from the first parent (since clonal inheritance is the common case), and so is not included.  Other chromosome types (\"W\", \"HF\", \"FL\") are never included.  See also the haploidGenome2NonNull property and the haplosomesForChromosomes() method.\n\t\t\t */\n\t\t{\n\t\t\tbool allowNullHaplosomes = (p_property_id == gID_haploidGenome2);\n\t\t\t\n\t\t\t// the semantics of this property assume that the individual was generated by a biparental cross\n\t\t\tint haplosome_count_per_individual = subpopulation_->HaplosomeCountPerIndividual();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(haplosome_count_per_individual);\n\t\t\tHaplosome **haplosomes = haplosomes_;\n\t\t\tint haplosome_index = 0;\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : subpopulation_->species_.Chromosomes())\n\t\t\t{\n\t\t\t\tswitch (chromosome->Type())\n\t\t\t\t{\n\t\t\t\t\t\t// chromosomes that have two haplosomes, the second of which is from the second parent\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index+1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (allowNullHaplosomes || !haplosome->IsNull())\n\t\t\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so skipped\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (allowNullHaplosomes || !haplosome->IsNull())\n\t\t\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_sex:\n\t\t{\n\t\t\tstatic EidosValue_SP static_sex_string_H;\n\t\t\tstatic EidosValue_SP static_sex_string_F;\n\t\t\tstatic EidosValue_SP static_sex_string_M;\n\t\t\tstatic EidosValue_SP static_sex_string_O;\n\t\t\t\n#pragma omp critical (GetProperty_sex_cache)\n\t\t\t{\n\t\t\t\tif (!static_sex_string_H)\n\t\t\t\t{\n\t\t\t\t\tstatic_sex_string_H = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"H\"));\n\t\t\t\t\tstatic_sex_string_F = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"F\"));\n\t\t\t\t\tstatic_sex_string_M = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"M\"));\n\t\t\t\t\tstatic_sex_string_O = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"?\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tswitch (sex_)\n\t\t\t{\n\t\t\t\tcase IndividualSex::kHermaphrodite:\treturn static_sex_string_H;\n\t\t\t\tcase IndividualSex::kFemale:\t\treturn static_sex_string_F;\n\t\t\t\tcase IndividualSex::kMale:\t\t\treturn static_sex_string_M;\n\t\t\t\tdefault:\t\t\t\t\t\t\treturn static_sex_string_O;\n\t\t\t}\n\t\t}\n\t\tcase gID_age:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (age_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property age is not available in WF models.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(age_));\n\t\t}\n\t\tcase gID_meanParentAge:\n\t\t{\n\t\t\tif (mean_parent_age_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property meanParentAge is not available in WF models.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(mean_parent_age_));\n\t\t}\n\t\tcase gID_pedigreeID:\t\t// ACCELERATED\n\t\t{\n\t\t\tSpecies &species = subpopulation_->species_;\n\t\t\t\n\t\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property pedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(pedigree_id_));\n\t\t}\n\t\tcase gID_pedigreeParentIDs:\n\t\t{\n\t\t\tif (!subpopulation_->species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property pedigreeParentIDs is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tEidosValue_Int *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(2);\n\t\t\t\n\t\t\tvec->set_int_no_check(pedigree_p1_, 0);\n\t\t\tvec->set_int_no_check(pedigree_p2_, 1);\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_pedigreeGrandparentIDs:\n\t\t{\n\t\t\tif (!subpopulation_->species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property pedigreeGrandparentIDs is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tEidosValue_Int *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(4);\n\t\t\t\n\t\t\tvec->set_int_no_check(pedigree_g1_, 0);\n\t\t\tvec->set_int_no_check(pedigree_g2_, 1);\n\t\t\tvec->set_int_no_check(pedigree_g3_, 2);\n\t\t\tvec->set_int_no_check(pedigree_g4_, 3);\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_reproductiveOutput:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!subpopulation_->species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property reproductiveOutput is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(reproductive_output_));\n\t\t}\n\t\tcase gID_spatialPosition:\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tSpecies &species = subpopulation_->species_;\n\t\t\t\n\t\t\tswitch (species.SpatialDimensionality())\n\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): position cannot be accessed in non-spatial simulations.\" << EidosTerminate();\n\t\t\t\tcase 1:\n\t\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(spatial_x_));\n\t\t\t\tcase 2:\n\t\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{spatial_x_, spatial_y_});\n\t\t\t\tcase 3:\n\t\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{spatial_x_, spatial_y_, spatial_z_});\n\t\t\t\tdefault:\n\t\t\t\t\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_uniqueMutations:\n\t\t{\n\t\t\tSpecies &species = subpopulation_->species_;\n\t\t\tint haplosome_count_per_individual = species.HaplosomeCountPerIndividual();\n\t\t\tint total_mutation_count = 0;\n\t\t\t\n\t\t\tsubpopulation_->population_.CheckForDeferralInHaplosomesVector(haplosomes_, haplosome_count_per_individual, \"Individual::GetProperty\");\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\ttotal_mutation_count += haplosome->mutation_count();\n\t\t\t}\n\t\t\t\n\t\t\t// We reserve a vector large enough to hold all the mutations from all haplosomes; probably usually overkill, but it does little harm\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tif (total_mutation_count == 0)\n\t\t\t\treturn result_SP;\n\t\t\t\n\t\t\tvec->reserve(total_mutation_count);\n\t\t\t\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : species.Chromosomes())\n\t\t\t{\n\t\t\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome->Index()];\n\t\t\t\tint last_haplosome_index = species.LastHaplosomeIndices()[chromosome->Index()];\n\t\t\t\t\n\t\t\t\tif (first_haplosome_index == last_haplosome_index)\n\t\t\t\t{\n\t\t\t\t\t// haploid chromosomes contain unique mutations by definition; add them all\n\t\t\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome1->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun1 = haplosome1->mutruns_[run_index];\n\t\t\t\t\t\t\tint g1_size = mutrun1->size();\n\t\t\t\t\t\t\tint g1_index = 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutationIndex mut = (*mutrun1)[g1_index++];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + mut);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// diploid chromosomes require uniquing logic\n\t\t\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\t\t\tHaplosome *haplosome2 = haplosomes_[last_haplosome_index];\n\t\t\t\t\tint haplosome1_size = (haplosome1->IsNull() ? 0 : haplosome1->mutation_count());\n\t\t\t\t\tint haplosome2_size = (haplosome2->IsNull() ? 0 : haplosome2->mutation_count());\n\t\t\t\t\t\n\t\t\t\t\tif (haplosome1_size + haplosome2_size > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = (haplosome1_size ? haplosome1->mutrun_count_ : haplosome2->mutrun_count_);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We want to interleave mutations from the two haplosomes, keeping only the uniqued mutations.  For a given position, we take mutations\n\t\t\t\t\t\t\t// from g1 first, and then look at the mutations in g2 at the same position and add them if they are not in g1.\n\t\t\t\t\t\t\tconst MutationRun *mutrun1 = (haplosome1_size ? haplosome1->mutruns_[run_index] : nullptr);\n\t\t\t\t\t\t\tconst MutationRun *mutrun2 = (haplosome2_size ? haplosome2->mutruns_[run_index] : nullptr);\n\t\t\t\t\t\t\tint g1_size = (mutrun1 ? mutrun1->size() : 0);\n\t\t\t\t\t\t\tint g2_size = (mutrun2 ? mutrun2->size() : 0);\n\t\t\t\t\t\t\tint g1_index = 0, g2_index = 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (g1_size && g2_size)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Get the position of the mutations at g1_index and g2_index\n\t\t\t\t\t\t\t\tMutationIndex g1_mut = (*mutrun1)[g1_index], g2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\t\t\tslim_position_t pos1 = (mut_block_ptr + g1_mut)->position_, pos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Process mutations as long as both haplosomes still have mutations left in them\n\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (pos1 < pos2)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + g1_mut);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// Move to the next mutation in g1\n\t\t\t\t\t\t\t\t\t\tif (++g1_index >= g1_size)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tg1_mut = (*mutrun1)[g1_index];\n\t\t\t\t\t\t\t\t\t\tpos1 = (mut_block_ptr + g1_mut)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (pos1 > pos2)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + g2_mut);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// Move to the next mutation in g2\n\t\t\t\t\t\t\t\t\t\tif (++g2_index >= g2_size)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\tg2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\t\t\t\t\tpos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// pos1 == pos2; copy mutations from g1 until we are done with this position, then handle g2\n\t\t\t\t\t\t\t\t\t\tslim_position_t focal_pos = pos1;\n\t\t\t\t\t\t\t\t\t\tint first_index = g1_index;\n\t\t\t\t\t\t\t\t\t\tbool done = false;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\twhile (pos1 == focal_pos)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + g1_mut);\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t// Move to the next mutation in g1\n\t\t\t\t\t\t\t\t\t\t\tif (++g1_index >= g1_size)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tg1_mut = (*mutrun1)[g1_index];\n\t\t\t\t\t\t\t\t\t\t\tpos1 = (mut_block_ptr + g1_mut)->position_;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// Note that we may be done with g1 here, so be careful\n\t\t\t\t\t\t\t\t\t\tint last_index_plus_one = g1_index;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\twhile (pos2 == focal_pos)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tint check_index;\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\tfor (check_index = first_index; check_index < last_index_plus_one; ++check_index)\n\t\t\t\t\t\t\t\t\t\t\t\tif ((*mutrun1)[check_index] == g2_mut)\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t// If the check indicates that g2_mut is not in g1, we copy it over\n\t\t\t\t\t\t\t\t\t\t\tif (check_index == last_index_plus_one)\n\t\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + g2_mut);\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t// Move to the next mutation in g2\n\t\t\t\t\t\t\t\t\t\t\tif (++g2_index >= g2_size)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tg2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\t\t\t\t\t\tpos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// Note that we may be done with both g1 and/or g2 here; if so, done will be set and we will break out\n\t\t\t\t\t\t\t\t\t\tif (done)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twhile (true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Finish off any tail ends, which must be unique and sorted already\n\t\t\t\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + (*mutrun1)[g1_index++]);\n\t\t\t\t\t\t\twhile (g2_index < g2_size)\n\t\t\t\t\t\t\t\tvec->push_object_element_no_check_RR(mut_block_ptr + (*mutrun2)[g2_index++]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gEidosID_color:\n\t\t{\n\t\t\t// as of SLiM 4.0.1, we construct a color string from the RGB values, which will\n\t\t\t// not necessarily be what the user set, but will represent the same color\n#ifdef SLIMGUI\n\t\t\tif (!color_set_)\n\t\t\t\treturn gStaticEidosValue_StringEmpty;\n\t\t\t\n\t\t\tchar hex_chars[8];\n\t\t\t\n\t\t\tEidos_GetColorString(colorR_, colorG_, colorB_, hex_chars);\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(std::string(hex_chars)));\n#else\n\t\t\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\t\t\treturn gStaticEidosValue_StringEmpty;\n#endif\n\t\t}\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tag accessed on individual before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\tcase gID_tagF:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tdouble tagF_value = tagF_value_;\n\t\t\t\n\t\t\tif (tagF_value == SLIM_TAGF_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagF accessed on individual before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(tagF_value));\n\t\t}\n\t\tcase gID_tagL0:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!tagL0_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL0 accessed on individual before being set.\" << EidosTerminate();\n\t\t\treturn (tagL0_value_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_tagL1:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!tagL1_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL1 accessed on individual before being set.\" << EidosTerminate();\n\t\t\treturn (tagL1_value_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_tagL2:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!tagL2_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL2 accessed on individual before being set.\" << EidosTerminate();\n\t\t\treturn (tagL2_value_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_tagL3:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!tagL3_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL3 accessed on individual before being set.\" << EidosTerminate();\n\t\t\treturn (tagL3_value_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_tagL4:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!tagL4_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL4 accessed on individual before being set.\" << EidosTerminate();\n\t\t\treturn (tagL4_value_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_migrant:\t\t\t// ACCELERATED\n\t\t{\n\t\t\treturn (migrant_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_fitnessScaling:\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(fitness_scaling_));\n\t\t}\n\t\tcase gEidosID_x:\t\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(spatial_x_));\n\t\t}\n\t\tcase gEidosID_y:\t\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(spatial_y_));\n\t\t}\n\t\tcase gEidosID_z:\t\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(spatial_z_));\n\t\t}\n\t\t\t\n\t\t\t// These properties are presently undocumented, used for testing purposes, but maybe they are useful to others?\n\t\t\t// They provide x/y/z as pairs or a triplet, whether the model is spatial or not, regardless of dimensionality\n\t\tcase gEidosID_xy:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float({spatial_x_, spatial_y_}));\n\t\t}\n\t\tcase gEidosID_xz:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float({spatial_x_, spatial_z_}));\n\t\t}\n\t\tcase gEidosID_yz:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float({spatial_y_, spatial_z_}));\n\t\t}\n\t\tcase gEidosID_xyz:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float({spatial_x_, spatial_y_, spatial_z_}));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *Individual::GetProperty_Accelerated_index(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->index_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_pedigreeID(EidosObject **p_values, size_t p_values_size)\n{\n\tSpecies *consensus_species = Community::SpeciesForIndividualsVector((Individual **)p_values, (int)p_values_size);\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tif (p_values_size == 0)\n\t\treturn int_result;\n\t\n\tif (consensus_species)\n\t{\n\t\t// check that pedigree IDs are enabled, once\n\t\tSpecies &species = ((Individual *)(p_values[0]))->subpopulation_->species_;\n\t\t\n\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property pedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\n\t\t\tint_result->set_int_no_check(value->pedigree_id_, value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// we have a mix of species, so we need to check that pedigree IDs are available for each individual\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\tSpecies &species = value->subpopulation_->species_;\n\t\t\t\n\t\t\tif (!species.PedigreesEnabledByUser() && !species.RecordingTreeSequence())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property pedigreeID is not available because neither pedigree recording nor tree-sequence recording has been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tint_result->set_int_no_check(value->pedigree_id_, value_index);\n\t\t}\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tag accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_age(EidosObject **p_values, size_t p_values_size)\n{\n\tif ((p_values_size > 0) && (((Individual *)(p_values[0]))->subpopulation_->community_.ModelType() == SLiMModelType::kModelTypeWF))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property age is not available in WF models.\" << EidosTerminate();\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->age_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_reproductiveOutput(EidosObject **p_values, size_t p_values_size)\n{\n\tif ((p_values_size > 0) && !((Individual *)(p_values[0]))->subpopulation_->species_.PedigreesEnabledByUser())\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property reproductiveOutput is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->reproductive_output_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagF(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\tdouble tagF_value = value->tagF_value_;\n\t\t\n\t\tif (tagF_value == SLIM_TAGF_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagF accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tfloat_result->set_float_no_check(tagF_value, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagL0(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (!value->tagL0_set_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL0 accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tlogical_result->set_logical_no_check(value->tagL0_value_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagL1(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (!value->tagL1_set_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL1 accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tlogical_result->set_logical_no_check(value->tagL1_value_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagL2(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (!value->tagL2_set_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL2 accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tlogical_result->set_logical_no_check(value->tagL2_value_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagL3(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (!value->tagL3_set_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL3 accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tlogical_result->set_logical_no_check(value->tagL3_value_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_tagL4(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (!value->tagL4_set_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property tagL4 accessed on individual before being set.\" << EidosTerminate();\n\t\t\n\t\tlogical_result->set_logical_no_check(value->tagL4_value_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_migrant(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tlogical_result->set_logical_no_check(value->migrant_, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->fitness_scaling_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_x(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->spatial_x_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_y(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->spatial_y_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_z(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->spatial_z_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_spatialPosition(EidosObject **p_values, size_t p_values_size)\n{\n\tSpecies *consensus_species = Community::SpeciesForIndividualsVector((Individual **)p_values, (int)p_values_size);\n\tEidosValue_Float *float_result;\n\t\n\tif (consensus_species)\n\t{\n\t\t// All individuals belong to the same species (common case), so we have the same dimensionality for all\n\t\tint dimensionality = consensus_species->SpatialDimensionality();\n\t\t\n\t\tif (dimensionality == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): position cannot be accessed in non-spatial simulations.\" << EidosTerminate();\n\t\t\n\t\tfloat_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size * dimensionality);\n\t\t\n\t\tif (dimensionality == 1)\n\t\t{\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_x_, value_index);\n\t\t\t}\n\t\t}\n\t\telse if (dimensionality == 2)\n\t\t{\n\t\t\tsize_t result_index = 0;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_x_, result_index++);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_y_, result_index++);\n\t\t\t}\n\t\t}\n\t\telse // dimensionality == 3\n\t\t{\n\t\t\tsize_t result_index = 0;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_x_, result_index++);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_y_, result_index++);\n\t\t\t\tfloat_result->set_float_no_check(value->spatial_z_, result_index++);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Mixed-species group, so we have to figure out the dimensionality for each individual separately\n\t\t// FIXME: Do we really want to allow this?  seems crazy - how would the user actually use this?\n\t\tfloat_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\tSpecies &species = value->subpopulation_->species_;\n\t\t\t\n\t\t\tswitch (species.SpatialDimensionality())\n\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): position cannot be accessed in non-spatial simulations.\" << EidosTerminate();\n\t\t\t\tcase 1:\n\t\t\t\t\tfloat_result->push_float(value->spatial_x_);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tfloat_result->push_float(value->spatial_x_);\n\t\t\t\t\tfloat_result->push_float(value->spatial_y_);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tfloat_result->push_float(value->spatial_x_);\n\t\t\t\t\tfloat_result->push_float(value->spatial_y_);\n\t\t\t\t\tfloat_result->push_float(value->spatial_z_);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_subpopulation(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Subpopulation_Class))->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\n\t\tif (value->killed_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty): property subpopulation is not available for individuals that have been killed; they have no subpopulation.\" << EidosTerminate();\n\t\t\n\t\tobject_result->set_object_element_no_check_NORR(value->subpopulation_, value_index);\n\t}\n\t\n\treturn object_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haploidGenome1(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\t\n\tif (chromosomes.size() != 1)\n\t\treturn nullptr;\t\t// defer to GetProperty(); multiple chromosomes need to be looped through\n\t\n\tChromosome *chromosome = chromosomes[0];\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tswitch (chromosome->Type())\n\t{\n\t\t\t// chromosomes that have two haplosomes, the first of which is from the first parent\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t{\n\t\t\tobject_result->resize_no_initialize(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\t\n\t\t\t\tobject_result->set_object_element_no_check_NORR(value->haplosomes_[0], value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so included\n\t\t{\n\t\t\tobject_result->resize_no_initialize(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\t\n\t\t\t\tobject_result->set_object_element_no_check_NORR(value->haplosomes_[0], value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\treturn object_result;\t// zero-length return\n\t\t}\n\t}\n\t\n\t// some compilers warn if this is not here, even though the switch above handles all ChromosomeType values\n\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty_Accelerated_haploidGenome1): (internal error) chromosome type not handled.\" << EidosTerminate();\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haploidGenome1NonNull(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\t\n\tif (chromosomes.size() != 1)\n\t\treturn nullptr;\t\t// defer to GetProperty(); multiple chromosomes need to be looped through\n\t\n\tChromosome *chromosome = chromosomes[0];\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tswitch (chromosome->Type())\n\t{\n\t\t\t// chromosomes that have two haplosomes, the first of which is from the first parent\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t{\n\t\t\tobject_result->reserve(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tHaplosome *haplosome = value->haplosomes_[0];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tobject_result->push_object_element_no_check_NORR(haplosome);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so included\n\t\t{\n\t\t\tobject_result->reserve(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tHaplosome *haplosome = value->haplosomes_[0];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tobject_result->push_object_element_no_check_NORR(haplosome);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\treturn object_result;\t// zero-length return\n\t\t}\n\t}\n\t\n\t// some compilers warn if this is not here, even though the switch above handles all ChromosomeType values\n\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty_Accelerated_haploidGenome1NonNull): (internal error) chromosome type not handled.\" << EidosTerminate();\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haploidGenome2(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\t\n\tif (chromosomes.size() != 1)\n\t\treturn nullptr;\t\t// defer to GetProperty(); multiple chromosomes need to be looped through\n\t\n\tChromosome *chromosome = chromosomes[0];\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tswitch (chromosome->Type())\n\t{\n\t\t\t// chromosomes that have two haplosomes, the first of which is from the first parent\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t{\n\t\t\tobject_result->resize_no_initialize(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\t\n\t\t\t\tobject_result->set_object_element_no_check_NORR(value->haplosomes_[1], value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so included\n\t\t{\n\t\t\treturn object_result;\t// zero-length return\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\tobject_result->resize_no_initialize(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\t\n\t\t\t\tobject_result->set_object_element_no_check_NORR(value->haplosomes_[0], value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t}\n\t\n\t// some compilers warn if this is not here, even though the switch above handles all ChromosomeType values\n\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty_Accelerated_haploidGenome2): (internal error) chromosome type not handled.\" << EidosTerminate();\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haploidGenome2NonNull(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\t\n\tif (chromosomes.size() != 1)\n\t\treturn nullptr;\t\t// defer to GetProperty(); multiple chromosomes need to be looped through\n\t\n\tChromosome *chromosome = chromosomes[0];\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tswitch (chromosome->Type())\n\t{\n\t\t\t// chromosomes that have two haplosomes, the first of which is from the first parent\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\t// assumed to follow the same pattern\n\t\t{\n\t\t\tobject_result->reserve(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tHaplosome *haplosome = value->haplosomes_[1];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tobject_result->push_object_element_no_check_NORR(haplosome);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the female parent\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\t// assumed to follow the same pattern, so included\n\t\t{\n\t\t\treturn object_result;\t// zero-length return\n\t\t}\n\t\t\t// chromosomes that have one haplosome, from the male parent\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\tobject_result->reserve(p_values_size);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\t\t\tHaplosome *haplosome = value->haplosomes_[0];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tobject_result->push_object_element_no_check_NORR(haplosome);\n\t\t\t}\n\t\t\t\n\t\t\treturn object_result;\n\t\t}\n\t}\n\t\n\t// some compilers warn if this is not here, even though the switch above handles all ChromosomeType values\n\tEIDOS_TERMINATION << \"ERROR (Individual::GetProperty_Accelerated_haploidGenome2NonNull): (internal error) chromosome type not handled.\" << EidosTerminate();\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haplosomes(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->resize_no_initialize(p_values_size * haplosome_count_per_individual);\n\tsize_t result_index = 0;\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\tHaplosome **haplosomes = value->haplosomes_;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\n\t\t\tobject_result->set_object_element_no_check_NORR(haplosome, result_index++);\n\t\t}\n\t}\n\t\n\treturn object_result;\n}\n\nEidosValue *Individual::GetProperty_Accelerated_haplosomesNonNull(EidosObject **p_values, size_t p_values_size)\n{\n\tconst Individual **individuals_buffer = (const Individual **)p_values;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(individuals_buffer, (int)p_values_size);\n\t\n\tif (!species)\n\t\treturn nullptr;\t\t// defer to GetProperty(); different species will have different chromosomes\n\t\n\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(p_values_size * haplosome_count_per_individual);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tIndividual *value = (Individual *)(p_values[value_index]);\n\t\tHaplosome **haplosomes = value->haplosomes_;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t\tobject_result->push_object_element_no_check_NORR(haplosome);\n\t\t}\n\t}\n\t\n\treturn object_result;\n}\n\nvoid Individual::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gEidosID_color:\t\t// ACCELERATED\n\t\t{\n#ifdef SLIMGUI\n\t\t\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\t\t\tconst std::string &color_string = ((EidosValue_String &)p_value).StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (color_string.empty())\n\t\t\t{\n\t\t\t\tcolor_set_ = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidos_GetColorComponents(color_string, &colorR_, &colorG_, &colorB_);\n\t\t\t\tcolor_set_ = true;\n\t\t\t\ts_any_individual_color_set_ = true;\t\t// keep track of the fact that an individual's color has been set\n\t\t\t}\n#endif\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\ts_any_individual_tag_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagF:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\ttagF_value_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\ts_any_individual_tagF_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagL0:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\ttagL0_set_ = true;\n\t\t\ttagL0_value_ = value;\n\t\t\ts_any_individual_tagL_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagL1:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\ttagL1_set_ = true;\n\t\t\ttagL1_value_ = value;\n\t\t\ts_any_individual_tagL_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagL2:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\ttagL2_set_ = true;\n\t\t\ttagL2_value_ = value;\n\t\t\ts_any_individual_tagL_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagL3:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\ttagL3_set_ = true;\n\t\t\ttagL3_value_ = value;\n\t\t\ts_any_individual_tagL_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tagL4:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\ttagL4_set_ = true;\n\t\t\ttagL4_value_ = value;\n\t\t\ts_any_individual_tagL_set_ = true;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_fitnessScaling:\t// ACCELERATED\n\t\t{\n\t\t\tfitness_scaling_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tIndividual::s_any_individual_fitness_scaling_set_ = true;\n\t\t\t\n\t\t\tif ((fitness_scaling_ < 0.0) || (std::isnan(fitness_scaling_)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::SetProperty): property fitnessScaling must be >= 0.0.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase gEidosID_x:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tspatial_x_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\treturn;\n\t\t}\n\t\tcase gEidosID_y:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tspatial_y_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\treturn;\n\t\t}\n\t\tcase gEidosID_z:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tspatial_z_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\treturn;\n\t\t}\n\t\tcase gID_age:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_age_t value = SLiMCastToAgeTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\tage_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tag_set_ = true;\n\t\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->tag_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->tag_value_ = source_data[value_index];\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagF(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagF_set_ = true;\n\t\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->tagF_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->tagF_value_ = source_data[value_index];\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagL0(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagL_set_ = true;\n\t\n\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = source_data[0];\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL0_set_ = true;\n\t\t\tindividual->tagL0_value_ = source_value;\n\t\t}\n\t}\n\telse\n\t{\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL0_set_ = true;\n\t\t\tindividual->tagL0_value_ = source_data[value_index];\n\t\t}\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagL1(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagL_set_ = true;\n\t\n\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = source_data[0];\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL1_set_ = true;\n\t\t\tindividual->tagL1_value_ = source_value;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL1_set_ = true;\n\t\t\tindividual->tagL1_value_ = source_data[value_index];\n\t\t}\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagL2(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagL_set_ = true;\n\t\n\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = source_data[0];\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL2_set_ = true;\n\t\t\tindividual->tagL2_value_ = source_value;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL2_set_ = true;\n\t\t\tindividual->tagL2_value_ = source_data[value_index];\n\t\t}\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagL3(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagL_set_ = true;\n\t\n\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = source_data[0];\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL3_set_ = true;\n\t\t\tindividual->tagL3_value_ = source_value;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL3_set_ = true;\n\t\t\tindividual->tagL3_value_ = source_data[value_index];\n\t\t}\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_tagL4(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\ts_any_individual_tagL_set_ = true;\n\t\n\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = source_data[0];\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL4_set_ = true;\n\t\t\tindividual->tagL4_value_ = source_value;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\n\t\t\tindividual->tagL4_set_ = true;\n\t\t\tindividual->tagL4_value_ = source_data[value_index];\n\t\t}\n\t}\n}\n\nbool Individual::_SetFitnessScaling_1(double source_value, EidosObject **p_values, size_t p_values_size)\n{\n\tif ((source_value < 0.0) || (std::isnan(source_value)))\n\t\treturn true;\n\t\n\t// Note that parallelization here only helps on machines with very high memory bandwidth,\n\t// because this loop spends all of its time writing to memory.  It also introduces a\n\t// potential race condition if the same Individual is referenced more than once in\n\t// p_values; that is considered a bug in the user's script, and we could check for it\n\t// in DEBUG mode if we wanted to.\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_FITNESS_SCALE_1);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(p_values_size) firstprivate(p_values, source_value) if(parallel:p_values_size >= EIDOS_OMPMIN_SET_FITNESS_SCALE_1) num_threads(thread_count)\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t((Individual *)(p_values[value_index]))->fitness_scaling_ = source_value;\n\t\n\treturn false;\n}\n\nbool Individual::_SetFitnessScaling_N(const double *source_data, EidosObject **p_values, size_t p_values_size)\n{\n\tbool saw_error = false;\t// deferred raises for OpenMP compliance\n\t\n\t// Note that parallelization here only helps on machines with very high memory bandwidth,\n\t// because this loop spends all of its time writing to memory.  It also introduces a\n\t// potential race condition if the same Individual is referenced more than once in\n\t// p_values; that is considered a bug in the user's script, and we could check for it\n\t// in DEBUG mode if we wanted to.\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_FITNESS_SCALE_2);\n#pragma omp parallel for schedule(static) default(none) shared(p_values_size) firstprivate(p_values, source_data) reduction(||: saw_error) if(p_values_size >= EIDOS_OMPMIN_SET_FITNESS_SCALE_2) num_threads(thread_count)\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tdouble source_value = source_data[value_index];\n\t\t\n\t\tif ((source_value < 0.0) || (std::isnan(source_value)))\n\t\t\tsaw_error = true;\n\t\t\n\t\t((Individual *)(p_values[value_index]))->fitness_scaling_ = source_value;\n\t}\n\t\n\treturn saw_error;\n}\n\nvoid Individual::SetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tIndividual::s_any_individual_fitness_scaling_set_ = true;\n\tbool needs_raise = false;\n\t\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tneeds_raise = _SetFitnessScaling_1(source_value, p_values, p_values_size);\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tneeds_raise = _SetFitnessScaling_N(source_data, p_values, p_values_size);\n\t}\n\t\n\tif (needs_raise)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::SetProperty_Accelerated_fitnessScaling): property fitnessScaling must be >= 0.0.\" << EidosTerminate();\n}\n\nvoid Individual::SetProperty_Accelerated_x(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_x_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_x_ = source_data[value_index];\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_y(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_y_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_y_ = source_data[value_index];\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_z(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_z_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->spatial_z_ = source_data[value_index];\n\t}\n}\n\nvoid Individual::SetProperty_Accelerated_color(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n#pragma unused (p_values, p_values_size, p_source, p_source_size)\n#ifdef SLIMGUI\n\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\tif (p_source_size == 1)\n\t{\n\t\tconst std::string &source_value = ((EidosValue_String &)p_source).StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (source_value.empty())\n\t\t{\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t\t((Individual *)(p_values[value_index]))->color_set_ = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint8_t color_red, color_green, color_blue;\n\t\t\t\n\t\t\tEidos_GetColorComponents(source_value, &color_red, &color_green, &color_blue);\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\t\t\n\t\t\t\tindividual->colorR_ = color_red;\n\t\t\t\tindividual->colorG_ = color_green;\n\t\t\t\tindividual->colorB_ = color_blue;\n\t\t\t\tindividual->color_set_ = true;\n\t\t\t}\n\t\t\t\n\t\t\ts_any_individual_color_set_ = true;\t\t// keep track of the fact that an individual's color has been set\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst std::string *source_data = p_source.StringData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tIndividual *individual = ((Individual *)(p_values[value_index]));\n\t\t\tconst std::string &source_value = source_data[value_index];\n\t\t\t\n\t\t\tif (source_value.empty())\n\t\t\t{\n\t\t\t\tindividual->color_set_ = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidos_GetColorComponents(source_value, &individual->colorR_, &individual->colorG_, &individual->colorB_);\n\t\t\t\tindividual->color_set_ = true;\n\t\t\t\ts_any_individual_color_set_ = true;\t\t// keep track of the fact that an individual's color has been set\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\nvoid Individual::SetProperty_Accelerated_age(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\tslim_age_t source_age = SLiMCastToAgeTypeOrRaise(source_value);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->age_ = source_age;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Individual *)(p_values[value_index]))->age_ = SLiMCastToAgeTypeOrRaise(source_data[value_index]);\n\t}\n}\n\nEidosValue_SP Individual::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_containsMutations:\t\t\treturn ExecuteMethod_containsMutations(p_method_id, p_arguments, p_interpreter);\n\t\t//case gID_countOfMutationsOfType:\treturn ExecuteMethod_Accelerated_countOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_haplosomesForChromosomes:\treturn ExecuteMethod_haplosomesForChromosomes(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_relatedness:\t\t\t\treturn ExecuteMethod_relatedness(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_sharedParentCount:\t\t\treturn ExecuteMethod_sharedParentCount(p_method_id, p_arguments, p_interpreter);\n\t\t//case gID_sumOfMutationsOfType:\treturn ExecuteMethod_Accelerated_sumOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_uniqueMutationsOfType:\t\treturn ExecuteMethod_uniqueMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mutationsFromHaplosomes:\treturn ExecuteMethod_mutationsFromHaplosomes(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\t// In a sense, we here \"subclass\" EidosDictionaryUnretained to override setValue(); we set a flag remembering that\n\t\t\t// an individual's dictionary has been modified, and then we call \"super\" for the usual behavior.\n\t\t\tif (p_method_id == gEidosID_setValue)\n\t\t\t\ts_any_individual_dictionary_set_ = true;\n\t\t\t\n\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t\t}\n\t}\n}\n\n//\t*********************\t- (logical)containsMutations(object<Mutation> mutations)\n//\nEidosValue_SP Individual::ExecuteMethod_containsMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tint haplosome_count_per_individual = subpopulation_->species_.HaplosomeCountPerIndividual();\n\n\tsubpopulation_->population_.CheckForDeferralInHaplosomesVector(haplosomes_, haplosome_count_per_individual, \"Individual::ExecuteMethod_containsMutations\");\n\t\n\tEidosValue *mutations_value = p_arguments[0].get();\n\tint mutations_count = mutations_value->Count();\n\t\n\tif (mutations_count == 0)\n\t\treturn gStaticEidosValue_Logical_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForMutations(mutations_value);\n\t\n\tif (species != &subpopulation_->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_containsMutations): containsMutations() requires that all mutations belong to the same species as the target individual.\" << EidosTerminate();\n\t\n\tif (mutations_count == 1)\n\t{\n\t\t// treat the singleton case separately to return gStaticEidosValue_LogicalT / gStaticEidosValue_LogicalF\n\t\tMutation *mut = (Mutation *)(mutations_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\tslim_chromosome_index_t mut_chrom_index = mut->chromosome_index_;\n\t\tint first_haplosome_index = species->FirstHaplosomeIndices()[mut_chrom_index];\n\t\tint last_haplosome_index = species->LastHaplosomeIndices()[mut_chrom_index];\n\t\t\n\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes_[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull() && haplosome->contains_mutation(mut))\n\t\t\t\treturn gStaticEidosValue_LogicalT;\n\t\t}\n\t\t\n\t\treturn gStaticEidosValue_LogicalF;\n\t}\n\telse\n\t{\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(mutations_count);\n\t\tMutation * const *mutations = (Mutation * const *)mutations_value->ObjectData();\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t{\n\t\t\tMutation *mut = mutations[value_index];\n\t\t\tslim_chromosome_index_t mut_chrom_index = mut->chromosome_index_;\n\t\t\tint first_haplosome_index = species->FirstHaplosomeIndices()[mut_chrom_index];\n\t\t\tint last_haplosome_index = species->LastHaplosomeIndices()[mut_chrom_index];\n\t\t\t\n\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; ++haplosome_index)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull() && haplosome->contains_mutation(mut))\n\t\t\t\t{\n\t\t\t\t\tlogical_result->set_logical_no_check(true, value_index);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(false, value_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(logical_result);\n\t}\n}\n\n//\t*********************\t- (integer$)countOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Individual::ExecuteMethod_Accelerated_countOfMutationsOfType(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (p_elements_size == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector((Individual **)p_elements, (int)p_elements_size);\n\t\n\tif (species == nullptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_Accelerated_countOfMutationsOfType): countOfMutationsOfType() requires that mutType belongs to the same species as the target individual.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInIndividualsVector((Individual **)p_elements, p_elements_size, \"Individual::ExecuteMethod_Accelerated_countOfMutationsOfType\");\n\t\n\tEidosValue *mutType_value = p_arguments[0].get();\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species->community_, species, \"countOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Count the number of mutations of the given type\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tEidosValue_Int *integer_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_elements_size);\n\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\t\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE);\n#pragma omp parallel for schedule(dynamic, 1) default(none) shared(p_elements_size) firstprivate(p_elements, mut_block_ptr, mutation_type_ptr, integer_result) if(p_elements_size >= EIDOS_OMPMIN_I_COUNT_OF_MUTS_OF_TYPE) num_threads(thread_count)\n\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t{\n\t\tIndividual *element = (Individual *)(p_elements[element_index]);\n\t\tint match_count = 0;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = element->haplosomes_[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t{\n\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\tint haplosome1_count = mutrun->size();\n\t\t\t\t\tconst MutationIndex *haplosome1_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (int mut_index = 0; mut_index < haplosome1_count; ++mut_index)\n\t\t\t\t\t\tif ((mut_block_ptr + haplosome1_ptr[mut_index])->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\t\t++match_count;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tinteger_result->set_int_no_check(match_count, element_index);\n\t}\n\t\n\treturn EidosValue_SP(integer_result);\n}\n\n//\t*********************\t- (object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome> chromosomes = NULL], [Ni$ index = NULL], [logical$ includeNulls = T])\n//\nEidosValue_SP Individual::ExecuteMethod_haplosomesForChromosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosomes_value = p_arguments[0].get();\n\tEidosValue *index_value = p_arguments[1].get();\n\tEidosValue *includeNulls_value = p_arguments[2].get();\n\t\n\t// assemble a vector of chromosome indices we're fetching\n\tSpecies &species = subpopulation_->species_;\n\tstd::vector<slim_chromosome_index_t> chromosome_indices;\n\t\n\tspecies.GetChromosomeIndicesFromEidosValue(chromosome_indices, chromosomes_value);\n\t\n\t// get index and includeNulls\n\tint64_t index = -1;\t// for NULL\n\t\n\tif (index_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tindex = index_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((index != 0) && (index != 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_haplosomesForChromosomes): haplosomesForChromosomes() requires that index is 0, 1, or NULL.\" << EidosTerminate();\n\t}\n\t\n\tbool includeNulls = includeNulls_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// fetch the requested haplosomes\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tAppendHaplosomesForChromosomes(vec, chromosome_indices, index, includeNulls);\n\t\n\treturn EidosValue_SP(vec);\n}\n\t\n//\t*********************\t- (float)relatedness(object<Individual> individuals, [Niso<Chromosome>$ chromosome = NULL])\n//\nEidosValue_SP Individual::ExecuteMethod_relatedness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tEidosValue *chromosome_value = p_arguments[1].get();\n\tint individuals_count = individuals_value->Count();\n\t\n\tif (individuals_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(individuals_value);\n\t\n\tif (species != &subpopulation_->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_relatedness): relatedness() requires that all individuals belong to the same species as the target individual.\" << EidosTerminate();\n\t\n\tChromosome *chromosome = species->GetChromosomeFromEidosValue(chromosome_value);\n\t\n\tif (!chromosome)\n\t{\n\t\tif (species->Chromosomes().size() == 1)\n\t\t\tchromosome = species->Chromosomes()[0];\n\t\telse if (species->Chromosomes().size() > 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_relatedness): relatedness() requires the chromosome to be specified in multi-chromosome models.\" << EidosTerminate();\n\t}\n\t\n\t// in a no-genetics model, the chromosome parameter must be NULL, so chromosome will be nullptr, and we assume type \"A\"\n\tChromosomeType chromosome_type = (chromosome ? chromosome->Type() : ChromosomeType::kA_DiploidAutosome);\n\t\n\tbool pedigree_tracking_enabled = subpopulation_->species_.PedigreesEnabledByUser();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(individuals_count);\n\tIndividual * const *individuals_data = (Individual * const *)individuals_value->ObjectData();\n\t\n\tif (pedigree_tracking_enabled)\n\t{\n\t\t// this parallelizes the case of one_individual.relatedness(many_individuals)\n\t\t// it would be nice to also parallelize the case of many_individuals.relatedness(one_individual); that would require accelerating this method\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RELATEDNESS);\n#pragma omp parallel for schedule(dynamic, 128) default(none) shared(individuals_count, individuals_data) firstprivate(float_result) if(individuals_count >= EIDOS_OMPMIN_RELATEDNESS) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < individuals_count; ++value_index)\n\t\t{\n\t\t\tIndividual *ind = individuals_data[value_index];\n\t\t\tdouble relatedness = RelatednessToIndividual(*ind, chromosome_type);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(relatedness, value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int value_index = 0; value_index < individuals_count; ++value_index)\n\t\t{\n\t\t\tIndividual *ind = individuals_data[value_index];\n\t\t\tdouble relatedness = (ind == this) ? 1.0 : 0.0;\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(relatedness, value_index);\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (integer)sharedParentCount(o<Individual> individuals)\n//\nEidosValue_SP Individual::ExecuteMethod_sharedParentCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tint individuals_count = individuals_value->Count();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (individuals_count > 0)\n\t{\n\t\tSpecies *species = Community::SpeciesForIndividuals(individuals_value);\n\t\t\n\t\tif (species != &subpopulation_->species_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_sharedParentCount): sharedParentCount() requires that all individuals belong to the same species as the target individual.\" << EidosTerminate();\n\t}\n\t\n\tbool pedigree_tracking_enabled = subpopulation_->species_.PedigreesEnabledByUser();\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(individuals_count);\n\tIndividual * const *individuals = (Individual * const *)individuals_value->ObjectData();\n\t\n\tif (pedigree_tracking_enabled)\n\t{\n\t\t// FIXME needs parallelization, see relatedness()\n\t\tfor (int value_index = 0; value_index < individuals_count; ++value_index)\n\t\t{\n\t\t\tIndividual *ind = individuals[value_index];\n\t\t\tint shared_count = SharedParentCountWithIndividual(*ind);\n\t\t\t\n\t\t\tint_result->set_int_no_check(shared_count, value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int value_index = 0; value_index < individuals_count; ++value_index)\n\t\t{\n\t\t\tIndividual *ind = individuals[value_index];\n\t\t\tint shared_count = (ind == this) ? 2.0 : 0.0;\n\t\t\t\n\t\t\tint_result->set_int_no_check(shared_count, value_index);\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(int_result);\n}\n\n//\t*********************\t- (integer$)sumOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Individual::ExecuteMethod_Accelerated_sumOfMutationsOfType(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (p_elements_size == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector((Individual **)p_elements, (int)p_elements_size);\n\t\n\tif (species == nullptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_Accelerated_sumOfMutationsOfType): sumOfMutationsOfType() requires that mutType belongs to the same species as the target individual.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInIndividualsVector((Individual **)p_elements, p_elements_size, \"Individual::ExecuteMethod_Accelerated_sumOfMutationsOfType\");\n\t\n\tEidosValue *mutType_value = p_arguments[0].get();\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species->community_, species, \"sumOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Sum the selection coefficients of mutations of the given type\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_elements_size);\n\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\t\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE);\n#pragma omp parallel for schedule(dynamic, 1) default(none) shared(p_elements_size) firstprivate(p_elements, mut_block_ptr, mutation_type_ptr, float_result) if(p_elements_size >= EIDOS_OMPMIN_SUM_OF_MUTS_OF_TYPE) num_threads(thread_count)\n\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t{\n\t\tIndividual *element = (Individual *)(p_elements[element_index]);\n\t\tdouble selcoeff_sum = 0.0;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = element->haplosomes_[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t{\n\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\tint haplosome1_count = mutrun->size();\n\t\t\t\t\tconst MutationIndex *haplosome1_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (int mut_index = 0; mut_index < haplosome1_count; ++mut_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutation *mut_ptr = mut_block_ptr + haplosome1_ptr[mut_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mut_ptr->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\t\tselcoeff_sum += mut_ptr->selection_coeff_;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfloat_result->set_float_no_check(selcoeff_sum, element_index);\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (object<Mutation>)uniqueMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Individual::ExecuteMethod_uniqueMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// NOTE: this method has been deprecated in favor of mutationsFromHaplosomes()\n\tint haplosome_count_per_individual = subpopulation_->species_.HaplosomeCountPerIndividual();\n\n\tsubpopulation_->population_.CheckForDeferralInHaplosomesVector(haplosomes_, haplosome_count_per_individual, \"Individual::ExecuteMethod_uniqueMutationsOfType\");\n\t\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tSpecies &species = subpopulation_->species_;\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"uniqueMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// This code is adapted from uniqueMutations and follows its logic closely\n\t\n\t// We try to reserve a vector large enough to hold all the mutations; probably usually overkill, but it does little harm\n\t// Note that since we do not *always* reserve, we have to use push_object_element() below to check for space\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\tbool only_haploid_haplosomes = true;\n\tsize_t vec_reserve_size = 0;\n\t\n\tfor (Chromosome *chromosome : species.Chromosomes())\n\t{\n\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome->Index()];\n\t\tint last_haplosome_index = species.LastHaplosomeIndices()[chromosome->Index()];\n\t\t\n\t\tif (first_haplosome_index == last_haplosome_index)\n\t\t{\n\t\t\t// haploid chromosomes contain unique mutations by definition; add them all\n\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome1->IsNull())\n\t\t\t\tvec_reserve_size += haplosome1->mutation_count();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// diploid chromsomes where one is empty/null also contain unique mutations by definition\n\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *haplosome2 = haplosomes_[last_haplosome_index];\n\t\t\tint haplosome1_size = (haplosome1->IsNull() ? 0 : haplosome1->mutation_count());\n\t\t\tint haplosome2_size = (haplosome2->IsNull() ? 0 : haplosome2->mutation_count());\n\t\t\t\n\t\t\tif (haplosome1_size == 0)\n\t\t\t{\n\t\t\t\tvec_reserve_size += haplosome2_size;\n\t\t\t}\n\t\t\telse if (haplosome2_size == 0)\n\t\t\t{\n\t\t\t\tvec_reserve_size += haplosome1_size;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvec_reserve_size += (haplosome1_size + haplosome2_size);\n\t\t\t\tonly_haploid_haplosomes = false;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (vec_reserve_size == 0)\n\t\treturn result_SP;\n\t\n\tif (only_haploid_haplosomes || (vec_reserve_size < 100))\t// an arbitrary limit, but we don't want to make something *too* unnecessarily big...\n\t\tvec->reserve(vec_reserve_size);\t\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tfor (Chromosome *chromosome : species.Chromosomes())\n\t{\n\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome->Index()];\n\t\tint last_haplosome_index = species.LastHaplosomeIndices()[chromosome->Index()];\n\t\t\n\t\tif (first_haplosome_index == last_haplosome_index)\n\t\t{\n\t\t\t// haploid chromosomes contain unique mutations by definition; add them all\n\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome1->IsNull())\n\t\t\t{\n\t\t\t\tint mutrun_count = haplosome1->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun1 = haplosome1->mutruns_[run_index];\n\t\t\t\t\tint g1_size = mutrun1->size();\n\t\t\t\t\tint g1_index = 0;\n\t\t\t\t\t\n\t\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut = (*mutrun1)[g1_index++];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + mut);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// diploid chromosomes require uniquing logic\n\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *haplosome2 = haplosomes_[last_haplosome_index];\n\t\t\tint haplosome1_size = (haplosome1->IsNull() ? 0 : haplosome1->mutation_count());\n\t\t\tint haplosome2_size = (haplosome2->IsNull() ? 0 : haplosome2->mutation_count());\n\t\t\tint mutrun_count = (haplosome1_size ? haplosome1->mutrun_count_ : haplosome2->mutrun_count_);\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t{\n\t\t\t\t// We want to interleave mutations from the two haplosomes, keeping only the uniqued mutations.  For a given position, we take mutations\n\t\t\t\t// from g1 first, and then look at the mutations in g2 at the same position and add them if they are not in g1.\n\t\t\t\tconst MutationRun *mutrun1 = (haplosome1_size ? haplosome1->mutruns_[run_index] : nullptr);\n\t\t\t\tconst MutationRun *mutrun2 = (haplosome2_size ? haplosome2->mutruns_[run_index] : nullptr);\n\t\t\t\tint g1_size = (mutrun1 ? mutrun1->size() : 0);\n\t\t\t\tint g2_size = (mutrun2 ? mutrun2->size() : 0);\n\t\t\t\tint g1_index = 0, g2_index = 0;\n\t\t\t\t\n\t\t\t\tif (g1_size && g2_size)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex g1_mut = (*mutrun1)[g1_index], g2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\n\t\t\t\t\t// At this point, we need to loop forward in g1 and g2 until we have found mutations of the right type in both\n\t\t\t\t\twhile ((mut_block_ptr + g1_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (++g1_index >= g1_size)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tg1_mut = (*mutrun1)[g1_index];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\twhile ((mut_block_ptr + g2_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (++g2_index >= g2_size)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tg2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif ((g1_index < g1_size) && (g2_index < g2_size))\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_position_t pos1 = (mut_block_ptr + g1_mut)->position_;\n\t\t\t\t\t\tslim_position_t pos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Process mutations as long as both haplosomes still have mutations left in them\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Now we have mutations of the right type, so we can start working with them by position\n\t\t\t\t\t\t\tif (pos1 < pos2)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + g1_mut);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Move to the next mutation in g1\n\t\t\t\t\t\t\tloopback1:\n\t\t\t\t\t\t\t\tif (++g1_index >= g1_size)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tg1_mut = (*mutrun1)[g1_index];\n\t\t\t\t\t\t\t\tif ((mut_block_ptr + g1_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t\t\t\t\tgoto loopback1;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tpos1 = (mut_block_ptr + g1_mut)->position_;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (pos1 > pos2)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + g2_mut);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Move to the next mutation in g2\n\t\t\t\t\t\t\tloopback2:\n\t\t\t\t\t\t\t\tif (++g2_index >= g2_size)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tg2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\t\t\tif ((mut_block_ptr + g2_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t\t\t\t\tgoto loopback2;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tpos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// pos1 == pos2; copy mutations from g1 until we are done with this position, then handle g2\n\t\t\t\t\t\t\t\tslim_position_t focal_pos = pos1;\n\t\t\t\t\t\t\t\tint first_index = g1_index;\n\t\t\t\t\t\t\t\tbool done = false;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twhile (pos1 == focal_pos)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + g1_mut);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// Move to the next mutation in g1\n\t\t\t\t\t\t\t\tloopback3:\n\t\t\t\t\t\t\t\t\tif (++g1_index >= g1_size)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tg1_mut = (*mutrun1)[g1_index];\n\t\t\t\t\t\t\t\t\tif ((mut_block_ptr + g1_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t\t\t\t\t\tgoto loopback3;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tpos1 = (mut_block_ptr + g1_mut)->position_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Note that we may be done with g1 here, so be careful\n\t\t\t\t\t\t\t\tint last_index_plus_one = g1_index;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twhile (pos2 == focal_pos)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tint check_index;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tfor (check_index = first_index; check_index < last_index_plus_one; ++check_index)\n\t\t\t\t\t\t\t\t\t\tif ((*mutrun1)[check_index] == g2_mut)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// If the check indicates that g2_mut is not in g1, we copy it over\n\t\t\t\t\t\t\t\t\tif (check_index == last_index_plus_one)\n\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + g2_mut);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// Move to the next mutation in g2\n\t\t\t\t\t\t\t\tloopback4:\n\t\t\t\t\t\t\t\t\tif (++g2_index >= g2_size)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tg2_mut = (*mutrun2)[g2_index];\n\t\t\t\t\t\t\t\t\tif ((mut_block_ptr + g2_mut)->mutation_type_ptr_ != mutation_type_ptr)\n\t\t\t\t\t\t\t\t\t\tgoto loopback4;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tpos2 = (mut_block_ptr + g2_mut)->position_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Note that we may be done with both g1 and/or g2 here; if so, done will be set and we will break out\n\t\t\t\t\t\t\t\tif (done)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Finish off any tail ends, which must be unique and sorted already\n\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex mut = (*mutrun1)[g1_index++];\n\t\t\t\t\t\n\t\t\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + mut);\n\t\t\t\t}\n\t\t\t\twhile (g2_index < g2_size)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex mut = (*mutrun2)[g2_index++];\n\t\t\t\t\t\n\t\t\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + mut);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n\t/*\n\t A SLiM model to test the above code:\n\t \n\t initialize() {\n\t initializeMutationRate(1e-5);\n\t initializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t initializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\t initializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\t initializeGenomicElementType(\"g1\", c(m1, m2, m3), c(1.0, 1.0, 1.0));\n\t initializeGenomicElement(g1, 0, 99999);\n\t initializeRecombinationRate(1e-8);\n\t }\n\t 1 early() {\n\t sim.addSubpop(\"p1\", 500);\n\t }\n\t 1:20000 late() {\n\t for (i in p1.individuals)\n\t {\n\t // check m1\n\t um1 = i.uniqueMutationsOfType(m1);\n\t um2 = sortBy(unique(i.haplosomes.mutationsOfType(m1)), \"position\");\n\t \n\t if (!identical(um1.position, um2.position))\n\t {\n\t print(\"Mismatch for m1!\");\n\t print(um1.position);\n\t print(um2.position);\n\t }\n\t }\n\t }\n\t */\n}\n\n//\t*********************\t- (object<Mutation>)mutationsFromHaplosomes(string$ category, [Nio<MutationType>$ mutType = NULL], [Niso<Chromosome> chromosomes = NULL])\n//\nEidosValue_SP Individual::ExecuteMethod_mutationsFromHaplosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *category_value = p_arguments[0].get();\n\tEidosValue *mutType_value = p_arguments[1].get();\n\tEidosValue *chromosomes_value = p_arguments[2].get();\n\t\n\tSpecies &species = subpopulation_->species_;\n\t\n\t// parse category\n\ttypedef enum _SLiMMutationFilteringCategory {\n\t\tkFilterUnique,\n\t\tkFilterHomozygous,\n\t\tkFilterHeterozygous,\n\t\tkFilterHemizygous,\n\t\tkFilterAll\n\t} SLiMMutationFilteringCategory;\n\t\n\tSLiMMutationFilteringCategory category;\n\tstd::string category_string = category_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (category_string == \"unique\")\t\t\tcategory = SLiMMutationFilteringCategory::kFilterUnique;\n\telse if (category_string == \"homozygous\")\tcategory = SLiMMutationFilteringCategory::kFilterHomozygous;\n\telse if (category_string == \"heterozygous\")\tcategory = SLiMMutationFilteringCategory::kFilterHeterozygous;\n\telse if (category_string == \"hemizygous\")\tcategory = SLiMMutationFilteringCategory::kFilterHemizygous;\n\telse if (category_string == \"all\")\t\t\tcategory = SLiMMutationFilteringCategory::kFilterAll;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_mutationsFromHaplosomes): mutationsFromHaplosomes() requires that category is 'unique', 'homozygous', 'heterozygous', 'hemizygous', or 'all'.\" << EidosTerminate();\n\t\n\t// parse mutType\n\tMutationType *mutation_type_ptr = nullptr;\t// used if mutType_value is NULL, to indicate applicability to all mutation types\n\t\n\tif (mutType_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tmutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"mutationsFromHaplosomes()\");\t\t// SPECIES CONSISTENCY CHECK\n\t}\n\t\n\t// parse chromosomes\n\tstd::vector<slim_chromosome_index_t> chromosome_indices;\n\t\n\tspecies.GetChromosomeIndicesFromEidosValue(chromosome_indices, chromosomes_value);\n\t\n\t// loop through the chromosomes\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tfor (slim_chromosome_index_t chromosome_index : chromosome_indices)\n\t{\n\t\tChromosome *chromosome = species.Chromosomes()[chromosome_index];\n\t\tint first_haplosome_index = species.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species.LastHaplosomeIndices()[chromosome_index];\n\t\t\n\t\tif (chromosome->IntrinsicPloidy() == 1)\n\t\t{\n\t\t\t// the chromosome is intrinsically haploid; add its mutations if category applies\n\t\t\tif ((category != SLiMMutationFilteringCategory::kFilterUnique) &&\n\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterHomozygous) &&\n\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterAll))\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tHaplosome *haplosome = haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (haplosome->IsNull())\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\n\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun1 = haplosome->mutruns_[run_index];\n\t\t\t\tint g1_size = mutrun1->size();\n\t\t\t\tint g1_index = 0;\n\t\t\t\t\n\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex mut_index = (*mutrun1)[g1_index++];\n\t\t\t\t\t\n\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + mut_index)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + mut_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// the chromosome is intrinsically diploid\n\t\t\tHaplosome *haplosome1 = haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *haplosome2 = haplosomes_[last_haplosome_index];\n\t\t\t\n\t\t\tif (haplosome1->IsNull() && haplosome2->IsNull())\n\t\t\t{\n\t\t\t\t// both haplosomes are null; skip this chromosome\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (haplosome1->IsNull() || haplosome2->IsNull())\n\t\t\t{\n\t\t\t\t// exactly one haplosome is null; hemizygous case\n\t\t\t\tif ((category != SLiMMutationFilteringCategory::kFilterUnique) &&\n\t\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterHemizygous) &&\n\t\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterAll))\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tHaplosome *haplosome = haplosome1->IsNull() ? haplosome2 : haplosome1;\n\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun1 = haplosome->mutruns_[run_index];\n\t\t\t\t\tint g1_size = mutrun1->size();\n\t\t\t\t\tint g1_index = 0;\n\t\t\t\t\t\n\t\t\t\t\twhile (g1_index < g1_size)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex mut_index = (*mutrun1)[g1_index++];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + mut_index)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + mut_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// two non-null haplosomes; run through them in synchrony\n\t\t\t\t// this code is adapted from Subpopulation::_Fitness_DiploidChromosome()\n\t\t\t\tif ((category != SLiMMutationFilteringCategory::kFilterUnique) &&\n\t\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterHomozygous) &&\n\t\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterHeterozygous) &&\n\t\t\t\t\t(category != SLiMMutationFilteringCategory::kFilterAll))\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// set flags that we can quickly check for whether we are pushing particular mutations or not\n\t\t\t\tbool push_homozygous = ((category == SLiMMutationFilteringCategory::kFilterHomozygous) ||\n\t\t\t\t\t\t\t\t\t\t(category == SLiMMutationFilteringCategory::kFilterUnique) ||\n\t\t\t\t\t\t\t\t\t\t(category == SLiMMutationFilteringCategory::kFilterAll));\n\t\t\t\tbool push_heterozygous = ((category == SLiMMutationFilteringCategory::kFilterHeterozygous) ||\n\t\t\t\t\t\t\t\t\t\t  (category == SLiMMutationFilteringCategory::kFilterUnique) ||\n\t\t\t\t\t\t\t\t\t\t  (category == SLiMMutationFilteringCategory::kFilterAll));\n\t\t\t\t\n\t\t\t\t// both haplosomes are being modeled, so we need to scan through and figure out which mutations are heterozygous and which are homozygous\n\t\t\t\tconst int32_t mutrun_count = haplosome1->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun1 = haplosome1->mutruns_[run_index];\n\t\t\t\t\tconst MutationRun *mutrun2 = haplosome2->mutruns_[run_index];\n\t\t\t\t\t\n\t\t\t\t\t// Read directly from the MutationRun buffers\n\t\t\t\t\tconst MutationIndex *haplosome1_iter = mutrun1->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *haplosome2_iter = mutrun2->begin_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tconst MutationIndex *haplosome1_max = mutrun1->end_pointer_const();\n\t\t\t\t\tconst MutationIndex *haplosome2_max = mutrun2->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\t// first, handle the situation before either haplosome iterator has reached the end of its haplosome, for simplicity/speed\n\t\t\t\t\tif (haplosome1_iter != haplosome1_max && haplosome2_iter != haplosome2_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter, haplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\tslim_position_t haplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_, haplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (haplosome1_iter_position < haplosome2_iter_position)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Process a mutation in haplosome1 since it is leading\n\t\t\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome1_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome1_mutindex);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (haplosome1_iter_position > haplosome2_iter_position)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Process a mutation in haplosome2 since it is leading\n\t\t\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome2_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome2_mutindex);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Look for homozygosity: haplosome1_iter_position == haplosome2_iter_position\n\t\t\t\t\t\t\t\tslim_position_t position = haplosome1_iter_position;\n\t\t\t\t\t\t\t\tconst MutationIndex *haplosome1_start = haplosome1_iter;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// advance through haplosome1 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst MutationIndex *haplosome2_matchscan = haplosome2_iter; \n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// advance through haplosome2 with haplosome2_matchscan, looking for a match for the current mutation in haplosome1, to determine whether we are homozygous or not\n\t\t\t\t\t\t\t\t\twhile (haplosome2_matchscan != haplosome2_max && (mut_block_ptr + *haplosome2_matchscan)->position_ == position)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (haplosome1_mutindex == *haplosome2_matchscan)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// a homozygous match was found\n\t\t\t\t\t\t\t\t\t\t\tif (push_homozygous)\n\t\t\t\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome1_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome1_mutindex);\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t// push a second copy only if we're doing category \"all\"\n\t\t\t\t\t\t\t\t\t\t\tif (category == SLiMMutationFilteringCategory::kFilterAll)\n\t\t\t\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome1_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome1_mutindex);\n\t\t\t\t\t\t\t\t\t\t\tgoto homozygousExit1;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\thaplosome2_matchscan++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// no match was found, so we are heterozygous\n\t\t\t\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome1_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome1_mutindex);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thomozygousExit1:\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} while (haplosome1_iter_position == position);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// advance through haplosome2 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst MutationIndex *haplosome1_matchscan = haplosome1_start; \n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// advance through haplosome1 with haplosome1_matchscan, looking for a match for the current mutation in haplosome2, to determine whether we are homozygous or not\n\t\t\t\t\t\t\t\t\twhile (haplosome1_matchscan != haplosome1_max && (mut_block_ptr + *haplosome1_matchscan)->position_ == position)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (haplosome2_mutindex == *haplosome1_matchscan)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// a homozygous match was found; we know this match was already found by the haplosome1 loop above\n\t\t\t\t\t\t\t\t\t\t\tgoto homozygousExit2;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\thaplosome1_matchscan++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// no match was found, so we are heterozygous; we multiply our fitness by the selection coefficient and the dominance coefficient\n\t\t\t\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome2_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome2_mutindex);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thomozygousExit2:\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome2_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} while (haplosome2_iter_position == position);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// break out if either haplosome has reached its end\n\t\t\t\t\t\t\t\tif (haplosome1_iter == haplosome1_max || haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} while (true);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// one or the other haplosome has now reached its end, so now we just need to handle the remaining mutations in the unfinished haplosome\n#if DEBUG\n\t\t\t\t\tassert(!(haplosome1_iter != haplosome1_max && haplosome2_iter != haplosome2_max));\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// if haplosome1 is unfinished, finish it\n\t\t\t\t\twhile (haplosome1_iter != haplosome1_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome1_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome1_mutindex);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if haplosome2 is unfinished, finish it\n\t\t\t\t\twhile (haplosome2_iter != haplosome2_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex haplosome2_mutindex = *haplosome2_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (push_heterozygous)\n\t\t\t\t\t\t\tif (!mutation_type_ptr || ((mut_block_ptr + haplosome2_mutindex)->mutation_type_ptr_ == mutation_type_ptr))\n\t\t\t\t\t\t\t\tvec->push_object_element_RR(mut_block_ptr + haplosome2_mutindex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tIndividual_Class\n//\n#pragma mark -\n#pragma mark Individual_Class\n#pragma mark -\n\nEidosClass *gSLiM_Individual_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Individual_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Individual_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_subpopulation,\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Subpopulation_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_subpopulation));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_index,\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_index));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haplosomes,\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haplosomes));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haplosomesNonNull,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haplosomesNonNull));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haploidGenome1,\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haploidGenome1));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haploidGenome2,\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haploidGenome2));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haploidGenome1NonNull,\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haploidGenome1NonNull));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haploidGenome2NonNull,\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_haploidGenome2NonNull));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_sex,\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tag)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tag));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagF,\t\t\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagF)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagF));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagL0,\t\t\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagL0)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagL0));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagL1,\t\t\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagL1)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagL1));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagL2,\t\t\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagL2)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagL2));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagL3,\t\t\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagL3)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagL3));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tagL4,\t\t\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_tagL4)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_tagL4));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_migrant,\t\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_migrant));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_fitnessScaling,\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_fitnessScaling)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_fitnessScaling));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_x,\t\t\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_x)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_x));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_y,\t\t\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_y)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_y));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_z,\t\t\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_z)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_z));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_xy,\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_xz,\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_yz,\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_xyz,\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_age,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_age)->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_age));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_meanParentAge,\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_pedigreeID,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_pedigreeID));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_pedigreeParentIDs,\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_pedigreeGrandparentIDs,\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_reproductiveOutput,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_reproductiveOutput));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatialPosition,\t\ttrue,\tkEidosValueMaskFloat))->DeclareAcceleratedGet(Individual::GetProperty_Accelerated_spatialPosition));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_uniqueMutations,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Mutation_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_color,\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton))->DeclareAcceleratedSet(Individual::SetProperty_Accelerated_color));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Individual_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Individual_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_containsMutations, kEidosValueMaskLogical))->AddObject(\"mutations\", gSLiM_Mutation_Class));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_countOfMutationsOfType, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class))->DeclareAcceleratedImp(Individual::ExecuteMethod_Accelerated_countOfMutationsOfType));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_relatedness, kEidosValueMaskFloat))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_haplosomesForChromosomes, kEidosValueMaskObject, gSLiM_Haplosome_Class))->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional, \"chromosomes\", gSLiM_Chromosome_Class, gStaticEidosValueNULL)->AddInt_OSN(\"index\", gStaticEidosValueNULL)->AddLogical_OS(\"includeNulls\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sharedParentCount, kEidosValueMaskInt))->AddObject(\"individuals\", gSLiM_Individual_Class));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sumOfMutationsOfType, kEidosValueMaskFloat | kEidosValueMaskSingleton))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class))->DeclareAcceleratedImp(Individual::ExecuteMethod_Accelerated_sumOfMutationsOfType));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_uniqueMutationsOfType, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class)->MarkDeprecated());\n\t\tmethods->emplace_back(((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_zygosityOfMutations, kEidosValueMaskInt))->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OS(\"hemizygousValue\", gStaticEidosValue_Integer1)->AddInt_OS(\"haploidValue\", gStaticEidosValue_Integer1)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationsFromHaplosomes, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddString_S(\"category\")->AddIntObject_OSN(\"mutType\", gSLiM_MutationType_Class, gStaticEidosValueNULL)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional, \"chromosomes\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\t\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_outputIndividuals, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL)->AddLogical_OS(\"spatialPositions\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"ages\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"ancestralNucleotides\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"pedigreeIDs\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"objectTags\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_outputIndividualsToVCF, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL)->AddLogical_OS(\"outputMultiallelics\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"simplifyNucleotides\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"outputNonnucleotides\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_readIndividualsFromVCF, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddString_S(gEidosStr_filePath)->AddIntObject_OSN(\"mutationType\", gSLiM_MutationType_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gStr_setSpatialPosition, kEidosValueMaskVOID))->AddFloat(\"position\"));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nEidosValue_SP Individual_Class::ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_outputIndividuals:\t\t\treturn ExecuteMethod_outputIndividuals(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_outputIndividualsToVCF:\treturn ExecuteMethod_outputIndividualsToVCF(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_readIndividualsFromVCF:\treturn ExecuteMethod_readIndividualsFromVCF(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_setSpatialPosition:\t\treturn ExecuteMethod_setSpatialPosition(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gID_zygosityOfMutations:\t\treturn ExecuteMethod_zygosityOfMutations(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tdefault:\n\t\t{\n\t\t\t// In a sense, we here \"subclass\" EidosDictionaryUnretained_Class to override setValuesVectorized(); we set a flag remembering that\n\t\t\t// an individual's dictionary has been modified, and then we call \"super\" for the usual behavior.\n\t\t\tif (p_method_id == gEidosID_setValuesVectorized)\n\t\t\t\tIndividual::s_any_individual_dictionary_set_ = true;\n\t\t\t\n\t\t\treturn super::ExecuteClassMethod(p_method_id, p_target, p_arguments, p_interpreter);\n\t\t}\n\t}\n}\n\n//\t*********************\t+ (void)outputIndividuals([Ns$ filePath = NULL], [logical$ append=F], [Niso<Chromosome>$ chromosome = NULL], [logical$ spatialPositions = T], [logical$ ages = T], [logical$ ancestralNucleotides = F], [logical$ pedigreeIDs = F], [logical$ objectTags = F])\n//\nEidosValue_SP Individual_Class::ExecuteMethod_outputIndividuals(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *append_value = p_arguments[1].get();\n\tEidosValue *chromosome_value = p_arguments[2].get();\n\tEidosValue *spatialPositions_value = p_arguments[3].get();\n\tEidosValue *ages_value = p_arguments[4].get();\n\tEidosValue *ancestralNucleotides_value = p_arguments[5].get();\n\tEidosValue *pedigreeIDs_value = p_arguments[6].get();\n\tEidosValue *objectTags_value = p_arguments[7].get();\n\t\n\t// here we need to require at least one target individual,\n\t// do a species consistency check and get the species/community,\n\t// and get the vector of individuals that we will pass in\n\t// (from the raw data of the EidosValue, no need to copy; but add const)\n\tint individuals_count = p_target->Count();\n\t\n\tif (individuals_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() cannot be called on a zero-length target vector; at least one individual is required.\" << EidosTerminate();\n\t\n\tconst Individual **individuals_buffer = (const Individual **)p_target->ObjectData();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() requires that all individuals belong to the same species.\" << EidosTerminate();\n\t\n\tCommunity &community = species->community_;\n\t\n\t// TIMING RESTRICTION\n\tif (!community.warned_early_output_)\n\t{\n\t\tif ((community.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tChromosome *chromosome = species->GetChromosomeFromEidosValue(chromosome_value);\t// NULL returns nullptr\n\t\n\tbool output_spatial_positions = spatialPositions_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_ages = ages_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_ancestral_nucs = ancestralNucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_pedigree_ids = pedigreeIDs_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_object_tags = objectTags_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (output_pedigree_ids && !species->PedigreesEnabledByUser())\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() cannot output pedigree IDs, because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\n\tif (filePath_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\tIndividual::PrintIndividuals_SLiM(output_stream, individuals_buffer, individuals_count, *species, output_spatial_positions, output_ages, output_ancestral_nucs, output_pedigree_ids, output_object_tags, /* p_output_substitutions */ false, chromosome);\n\t}\n\telse\n\t{\n\t\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\tstd::ofstream outfile;\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\t\n\t\tif (outfile.is_open())\n\t\t{\n\t\t\tIndividual::PrintIndividuals_SLiM(outfile, individuals_buffer, individuals_count, *species, output_spatial_positions, output_ages, output_ancestral_nucs, output_pedigree_ids, output_object_tags, /* p_output_substitutions */ false, chromosome);\n\t\t\t\n\t\t\toutfile.close(); \n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() could not open \" << outfile_path << \".\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t+ (void)outputIndividualsToVCF([Ns$ filePath = NULL], [logical$ append = F], [Niso<Chromosome>$ chromosome = NULL], [logical$ outputMultiallelics = T], [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T])\n//\nEidosValue_SP Individual_Class::ExecuteMethod_outputIndividualsToVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *append_value = p_arguments[1].get();\n\tEidosValue *chromosome_value = p_arguments[2].get();\n\tEidosValue *outputMultiallelics_value = p_arguments[3].get();\n\tEidosValue *simplifyNucleotides_value = p_arguments[4].get();\n\tEidosValue *outputNonnucleotides_value = p_arguments[5].get();\n\t\n\t// here we need to require at least one target individual,\n\t// do a species consistency check and get the species/community,\n\t// and get the vector of individuals that we will pass in\n\t// (from the raw data of the EidosValue, no need to copy; but add const)\n\tint individuals_count = p_target->Count();\n\t\n\tif (individuals_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividualsToVCF): outputIndividualsToVCF() cannot be called on a zero-length target vector; at least one individual is required.\" << EidosTerminate();\n\t\n\tconst Individual **individuals_buffer = (const Individual **)p_target->ObjectData();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividualsToVCF): outputIndividualsToVCF() requires that all individuals belong to the same species.\" << EidosTerminate();\n\t\n\tCommunity &community = species->community_;\n\t\n\t// TIMING RESTRICTION\n\tif (!community.warned_early_output_)\n\t{\n\t\tif ((community.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Individual_Class::ExecuteMethod_outputIndividualsToVCF): outputIndividualsToVCF() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tChromosome *chromosome = species->GetChromosomeFromEidosValue(chromosome_value);\t// NULL returns nullptr\n\t\n\tbool output_multiallelics = outputMultiallelics_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool simplify_nucs = simplifyNucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_nonnucs = outputNonnucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (filePath_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\t// write the #OUT line, for file output only\n\t\toutput_stream << \"#OUT: \" << community.Tick() << \" \" << species->Cycle() << \" IS\" << std::endl;\n\t\t\n\t\tIndividual::PrintIndividuals_VCF(output_stream, individuals_buffer, individuals_count, *species, output_multiallelics, simplify_nucs, output_nonnucs, chromosome);\n\t}\n\telse\n\t{\n\t\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\tstd::ofstream outfile;\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\t\n\t\tif (outfile.is_open())\n\t\t{\n\t\t\tIndividual::PrintIndividuals_VCF(outfile, individuals_buffer, individuals_count, *species, output_multiallelics, simplify_nucs, output_nonnucs, chromosome);\n\t\t\t\n\t\t\toutfile.close(); \n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_outputIndividuals): outputIndividuals() could not open \" << outfile_path << \".\" << EidosTerminate();\n\t\t}\n\t}\n\treturn gStaticEidosValueVOID;\n}\n\n// this is to avoid copy-pasting the same addition code repeatedly; it is gross, but should get inlined\ninline __attribute__((always_inline)) static void\n_AddCallToHaplosome(int call, Haplosome *haplosome, slim_mutrun_index_t &haplosome_last_mutrun_modified, MutationRun *&haplosome_last_mutrun,\n\t\t\t\t\tstd::vector<MutationIndex> &alt_allele_mut_indices, slim_position_t mut_position, Species *species, MutationRunContext *mutrun_context,\n\t\t\t\t\tbool all_target_haplosomes_started_empty, bool recording_mutations)\n{\n\tif (call == 0)\n\t\treturn;\n\t\n\tslim_position_t mutrun_length = haplosome->MutrunLength();\n\tMutationIndex mut_index = alt_allele_mut_indices[call - 1];\n\tslim_mutrun_index_t mut_mutrun_index = (slim_mutrun_index_t)(mut_position / mutrun_length);\n\t\n\tif (mut_mutrun_index != haplosome_last_mutrun_modified)\n\t{\n#ifdef _OPENMP\n\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\tmutrun_context = &species->ChromosomeMutationRunContextForMutationRunIndex(mut_mutrun_index);\n#endif\n\t\t\n\t\t// We use WillModifyRun() because these are existing haplosomes we didn't create, and their runs may be shared; we have\n\t\t// no way to tell.  We avoid making excessive mutation run copies by calling this only once per mutrun per haplosome.\n\t\thaplosome_last_mutrun = haplosome->WillModifyRun(mut_mutrun_index, *mutrun_context);\n\t\thaplosome_last_mutrun_modified = mut_mutrun_index;\n\t}\n\t\n\t// If the haplosome started empty, we can add mutations to the end with emplace_back(); if it did not, then they need to be inserted\n\tif (all_target_haplosomes_started_empty)\n\t\thaplosome_last_mutrun->emplace_back(mut_index);\n\telse\n\t\thaplosome_last_mutrun->insert_sorted_mutation(mut_index);\n\t\n\tif (recording_mutations)\n\t\tspecies->RecordNewDerivedState(haplosome, mut_position, *haplosome->derived_mutation_ids_at_position(mut_position));\n}\n\n//\t*********************\t+ (o<Mutation>)readIndividualsFromVCF(s$ filePath = NULL, [Nio<MutationType> mutationType = NULL])\n//\nEidosValue_SP Individual_Class::ExecuteMethod_readIndividualsFromVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_interpreter)\n\t// BEWARE: This method shares a great deal of code with Haplosome_Class::ExecuteMethod_readHaplosomesFromVCF().  Maintain in parallel.\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Individual_Class::ExecuteMethod_readIndividualsFromVCF(): SLiM global state read\");\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *mutationType_value = p_arguments[1].get();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (p_target->Count() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): \" << \"readIndividualsFromVCF() requires a target Individual vector of length 1 or more, so that the species of the target can be determined.\" << EidosTerminate();\n\t\n\tSpecies *species = Community::SpeciesForIndividuals(p_target);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): \" << \"readIndividualsFromVCF() requires that all target individuals belong to the same species.\" << EidosTerminate();\n\t\n\tIndividual * const *individuals_data = (Individual * const *)p_target->ObjectData();\n\tint individuals_size = p_target->Count();\n\t\n\tspecies->population_.CheckForDeferralInIndividualsVector(individuals_data, individuals_size, \"Individual_Class::ExecuteMethod_readIndividualsFromVCF\");\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\tbool model_is_multi_chromosome = (chromosomes.size() > 1);\n\tstd::string chromosome_symbol;\t\t// used in single-chromosome models to check consistency\n\t\n\tCommunity &community = species->community_;\n\tPopulation &pop = species->population_;\n\tbool recording_mutations = species->RecordingTreeSequenceMutations();\n\tbool nucleotide_based = species->IsNucleotideBased();\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n\tbool has_initial_mutations = (gSLiM_next_mutation_id != 0);\n\tMutationType *default_mutation_type_ptr = nullptr;\n\t\n\tif (mutationType_value->Type() != EidosValueType::kValueNULL)\n\t\tdefault_mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutationType_value, 0, &community, species, \"readIndividualsFromVCF()\");\t\t\t// SPECIES CONSISTENCY CHECK\n\t\n\t// Parse the whole input file and retain the information from it\n\tstd::ifstream infile(file_path);\n\t\n\tif (!infile)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): could not read file at path \" << file_path << \".\" << EidosTerminate();\n\t\n\tstd::string line, sub;\n\tint parse_state = 0;\n\tint sample_id_count = 0;\n\tbool info_MID_defined = false, info_S_defined = false, info_DOM_defined = false, info_PO_defined = false;\n\tbool info_GO_defined = false, info_TO_defined = false, info_MT_defined = false, /*info_AA_defined = false,*/ info_NONNUC_defined = false;\n\t\n\t// This data structure keeps call lines that we read for each chromosome.  They could arrive from the file\n\t// in any order; with this we store them by chromosome, and then indexed by their mutation position.\n\tstd::vector<std::vector<std::pair<slim_position_t, std::string>>> call_lines_per_chromosome;\n\t\n\tcall_lines_per_chromosome.resize(chromosomes.size());\t// make an empty call_lines vector for each chromosome\n\t\n\twhile (!infile.eof())\n\t{\n\t\tgetline(infile, line);\n\t\t\n\t\tswitch (parse_state)\n\t\t{\n\t\t\tcase 0:\n\t\t\t{\n\t\t\t\t// In header, parsing ## lines, until we get to the #CHROM line; the point of this is that we only want to interpret\n\t\t\t\t// INFO fields like MID, S, etc. as having their SLiM-specific meaning if their SLiM-specific definition is present\n\t\t\t\tif (line.compare(0, 2, \"##\") == 0)\n\t\t\t\t{\n\t\t\t\t\tif (line == \"##INFO=<ID=MID,Number=.,Type=Integer,Description=\\\"Mutation ID in SLiM\\\">\")\tinfo_MID_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=S,Number=.,Type=Float,Description=\\\"Selection Coefficient\\\">\")\t\tinfo_S_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=DOM,Number=.,Type=Float,Description=\\\"Dominance\\\">\")\t\t\t\tinfo_DOM_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=PO,Number=.,Type=Integer,Description=\\\"Population of Origin\\\">\")\tinfo_PO_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=GO,Number=.,Type=Integer,Description=\\\"Generation of Origin\\\">\")\tinfo_GO_defined = true;\n\t\t\t\t\tif (line == \"##INFO=<ID=TO,Number=.,Type=Integer,Description=\\\"Tick of Origin\\\">\")\t\t\tinfo_TO_defined = true;\t\t// SLiM 4 emits TO (tick) instead of GO (generation)\n\t\t\t\t\tif (line == \"##INFO=<ID=MT,Number=.,Type=Integer,Description=\\\"Mutation Type\\\">\")\t\t\tinfo_MT_defined = true;\n\t\t\t\t\t/*if (line == \"##INFO=<ID=AA,Number=1,Type=String,Description=\\\"Ancestral Allele\\\">\")\t\t\tinfo_AA_defined = true;*/\t\t// this one is standard, so we don't require this definition\n\t\t\t\t\tif (line == \"##INFO=<ID=NONNUC,Number=0,Type=Flag,Description=\\\"Non-nucleotide-based\\\">\")\tinfo_NONNUC_defined = true;\n\t\t\t\t}\n\t\t\t\telse if (line.compare(0, 1, \"#\") == 0)\n\t\t\t\t{\n\t\t\t\t\tstatic const char *header_fields[9] = {\"CHROM\", \"POS\", \"ID\", \"REF\", \"ALT\", \"QUAL\", \"FILTER\", \"INFO\", \"FORMAT\"};\n\t\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\t\n\t\t\t\t\tiss.get();\t// eat the initial #\n\t\t\t\t\t\n\t\t\t\t\t// verify that the expected standard columns are present\n\t\t\t\t\tfor (const char *header_field : header_fields)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!(iss >> sub))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): missing VCF header '\" << header_field << \"'.\" << EidosTerminate();\n\t\t\t\t\t\tif (sub != header_field)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): expected VCF header '\" << header_field << \"', saw '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// the remaining columns are sample IDs; we don't care what they are, we just count them\n\t\t\t\t\twhile (iss >> sub)\n\t\t\t\t\t\tsample_id_count++;\n\t\t\t\t\t\n\t\t\t\t\tif (sample_id_count != individuals_size)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): there are \" << sample_id_count << \" samples in the VCF file, but \" << individuals_size << \" target individuals; the number of target individuals must match the number of VCF samples.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// now the remainder of the file should be call lines\n\t\t\t\t\tparse_state = 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): unexpected line in VCF header: '\" << line << \"'.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\t// In call lines, fields are separated by tabs, and could theoretically contain spaces; here we just read a whole line,\n\t\t\t\t// extract the position field for the mutation, and save the line indexed by its mutation's position for later handling\n\t\t\t\tif (line.length() == 0)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tstd::istringstream iss(line);\n\t\t\t\t\n\t\t\t\tstd::getline(iss, sub, '\\t');\t// CHROM\n\t\t\t\t\n\t\t\t\tChromosome *chromosome_for_call = species->ChromosomeFromSymbol(sub);\n\t\t\t\t\n\t\t\t\tif (model_is_multi_chromosome)\n\t\t\t\t{\n\t\t\t\t\t// in multi-chromosome models the CHROM value must match match a chromosome in the model\n\t\t\t\t\tif (!chromosome_for_call)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): the CHROM field's value (\\\"\" << sub << \"\\\") in a call line does not match any chromosome symbol for the focal species with which the target individuals are associated.  In multi-chromosome models, the CHROM field is required to match a chromosome symbol to prevent bugs.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// in single-chromosome models the CHROM value must be consistent across the whole file, but need not match\n\t\t\t\t\tif (chromosome_symbol.length() == 0)\n\t\t\t\t\t\tchromosome_symbol = sub;\t// first call line's CHROM symbol gets remembered\n\t\t\t\t\telse if (sub != chromosome_symbol)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): the CHROM field's value (\\\"\" << sub << \"\\\") in a call line does not match the initial CHROM field's value (\\\"\" << chromosome_symbol << \"\\\").  In single-chromosome models, the CHROM field is required to have a single consistent value across all call lines to prevent bugs.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (!chromosome_for_call)\n\t\t\t\t\t\tchromosome_for_call = chromosomes[0];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tslim_chromosome_index_t chromosome_index = chromosome_for_call->Index();\n\t\t\t\tslim_position_t last_position = chromosome_for_call->last_position_;\n\t\t\t\t\n\t\t\t\tstd::getline(iss, sub, '\\t');\t// POS\n\t\t\t\t\n\t\t\t\tint64_t pos = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr) - 1;\t\t// -1 because VCF uses 1-based positions\n\t\t\t\t\n\t\t\t\tif ((pos < 0) || (pos > last_position))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file POS value \" << pos << \" out of range.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tstd::vector<std::pair<slim_position_t, std::string>> &call_lines = call_lines_per_chromosome[chromosome_index];\n\t\t\t\t\n\t\t\t\tcall_lines.emplace_back(pos, line);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): (internal error) unhandled case.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tinfile.close();\n\t\n\t// We will keep track of all mutations added, to all chromosomes, and return them as a vector\n\tstd::vector<MutationIndex> mutation_indices;\n\t\n\t// Loop over the call lines for each chromosome, and handle chromosomes one by one\n\t// FIXME: from here downwards could probably be parallelized\n\tfor (size_t chromosome_index = 0; chromosome_index < chromosomes.size(); ++chromosome_index)\n\t{\n\t\tstd::vector<std::pair<slim_position_t, std::string>> &call_lines = call_lines_per_chromosome[chromosome_index];\n\t\t\n\t\tif (call_lines.size() == 0)\n\t\t\tcontinue;\n\t\t\n\t\tChromosome *chromosome = species->Chromosomes()[chromosome_index];\n\t\tint first_haplosome_index = species->FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species->LastHaplosomeIndices()[chromosome_index];\n\t\tint intrinsic_ploidy = (last_haplosome_index - first_haplosome_index) + 1;\n\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t// sort call_lines by position, so that we can add them to empty haplosomes efficiently\n\t\tstd::sort(call_lines.begin(), call_lines.end(), [ ](const std::pair<slim_position_t, std::string> &l1, const std::pair<slim_position_t, std::string> &l2) {return l1.first < l2.first;});\n\t\t\n\t\t// cache target haplosomes and determine whether they are initially empty, in which case we can do fast mutation addition with emplace_back()\n\t\t// NOTE that unlike readHaplosomesFromVCF(), we do not exclude null haplosomes here!\n\t\tstd::vector<Haplosome *> haplosomes;\n\t\tstd::vector<slim_mutrun_index_t> haplosomes_last_mutrun_modified;\n\t\tstd::vector<MutationRun *> haplosomes_last_mutrun;\n\t\tbool all_target_haplosomes_started_empty = true;\n\t\t\n\t\tfor (int individuals_index = 0; individuals_index < individuals_size; ++individuals_index)\n\t\t{\n\t\t\tIndividual *ind = individuals_data[individuals_index];\n\t\t\t\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = ind->haplosomes_[first_haplosome_index];\n\t\t\t\t\n\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t{\n\t\t\t\t\thaplosomes.emplace_back(nullptr);\n\t\t\t\t\thaplosomes_last_mutrun_modified.emplace_back(-1);\n\t\t\t\t\thaplosomes_last_mutrun.emplace_back(nullptr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (haplosome->mutation_count() != 0)\n\t\t\t\t\t\tall_target_haplosomes_started_empty = false;\n\t\t\t\t\t\n\t\t\t\t\thaplosomes.emplace_back(haplosome);\n\t\t\t\t\thaplosomes_last_mutrun_modified.emplace_back(-1);\n\t\t\t\t\thaplosomes_last_mutrun.emplace_back(nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (intrinsic_ploidy == 2)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = ind->haplosomes_[last_haplosome_index];\n\t\t\t\t\n\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t{\n\t\t\t\t\thaplosomes.emplace_back(nullptr);\n\t\t\t\t\thaplosomes_last_mutrun_modified.emplace_back(-1);\n\t\t\t\t\thaplosomes_last_mutrun.emplace_back(nullptr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (haplosome->mutation_count() != 0)\n\t\t\t\t\t\tall_target_haplosomes_started_empty = false;\n\t\t\t\t\t\n\t\t\t\t\thaplosomes.emplace_back(haplosome);\n\t\t\t\t\thaplosomes_last_mutrun_modified.emplace_back(-1);\n\t\t\t\t\thaplosomes_last_mutrun.emplace_back(nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// parse all the call lines, instantiate their mutations, and add the mutations to the target haplosomes\n#ifndef _OPENMP\n\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\t\t\n\t\tfor (std::pair<slim_position_t, std::string> &call_line : call_lines)\n\t\t{\n\t\t\tslim_position_t mut_position = call_line.first;\n\t\t\tstd::istringstream iss(call_line.second);\n\t\t\tstd::string ref_str, alt_str, info_str;\n\t\t\t\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// CHROM; don't care (already checked it above)\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// POS; already fetched\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// ID; don't care\n\t\t\tstd::getline(iss, ref_str, '\\t');\t// REF\n\t\t\tstd::getline(iss, alt_str, '\\t');\t// ALT\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// QUAL; don't care\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// FILTER; don't care\n\t\t\tstd::getline(iss, info_str, '\\t');\t// INFO\n\t\t\tstd::getline(iss, sub, '\\t');\t\t// FORMAT; don't care (GT must be first, according to the standard; we don't check)\n\t\t\t\n\t\t\t// parse/validate the REF nucleotide\n\t\t\tint8_t ref_nuc;\n\t\t\t\n\t\t\tif (ref_str == \"A\")\t\t\tref_nuc = 0;\n\t\t\telse if (ref_str == \"C\")\tref_nuc = 1;\n\t\t\telse if (ref_str == \"G\")\tref_nuc = 2;\n\t\t\telse if (ref_str == \"T\")\tref_nuc = 3;\n\t\t\telse\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file REF value must be A/C/G/T.\" << EidosTerminate();\n\t\t\t\n\t\t\t// parse/validate the ALT nucleotides\n\t\t\tstd::vector<std::string> alt_substrs = Eidos_string_split(alt_str, \",\");\n\t\t\tstd::vector<int8_t> alt_nucs;\n\t\t\t\n\t\t\tfor (std::string &alt_substr : alt_substrs)\n\t\t\t{\n\t\t\t\tif (alt_substr == \"A\")\t\t\talt_nucs.emplace_back(0);\n\t\t\t\telse if (alt_substr == \"C\")\t\talt_nucs.emplace_back(1);\n\t\t\t\telse if (alt_substr == \"G\")\t\talt_nucs.emplace_back(2);\n\t\t\t\telse if (alt_substr == \"T\")\t\talt_nucs.emplace_back(3);\n\t\t\t\telse\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file ALT value must be A/C/G/T.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tsize_t alt_allele_count = alt_nucs.size();\n\t\t\t\n\t\t\t// parse/validate the INFO fields that we recognize\n\t\t\tstd::vector<std::string> info_substrs = Eidos_string_split(info_str, \";\");\n\t\t\tstd::vector<slim_mutationid_t> info_mutids;\n\t\t\tstd::vector<double> info_selcoeffs;\n\t\t\tstd::vector<double> info_domcoeffs;\n\t\t\tstd::vector<slim_objectid_t> info_poporigin;\n\t\t\tstd::vector<slim_tick_t> info_tickorigin;\n\t\t\tstd::vector<slim_objectid_t> info_muttype;\n\t\t\tint8_t info_ancestral_nuc = -1;\n\t\t\tbool info_is_nonnuc = false;\n\t\t\t\n\t\t\tfor (std::string &info_substr : info_substrs)\n\t\t\t{\n\t\t\t\tif (info_MID_defined && (info_substr.compare(0, 4, \"MID=\") == 0))\t\t// Mutation ID\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(4), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_mutids.emplace_back((slim_mutationid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t\t\n\t\t\t\t\tif (info_mutids.size() && has_initial_mutations)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!community.warned_readFromVCF_mutIDs_unused_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Individual_Class::ExecuteMethod_readIndividualsFromVCF): readIndividualsFromVCF(): the VCF file specifies mutation IDs with the MID field, but some mutation IDs have already been used so uniqueness cannot be guaranteed.  Use of mutation IDs is therefore disabled; mutations will not receive the mutation ID requested in the file.  To fix this warning, remove the MID field from the VCF file before reading.  To get readIndividualsFromVCF() to use the specified mutation IDs, load the VCF file into a model that has never simulated a mutation, and has therefore not used any mutation IDs.\" << std::endl;\n\t\t\t\t\t\t\t\tcommunity.warned_readFromVCF_mutIDs_unused_ = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// disable use of MID for this read\n\t\t\t\t\t\tinfo_MID_defined = false;\n\t\t\t\t\t\tinfo_mutids.resize(0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (info_S_defined && (info_substr.compare(0, 2, \"S=\") == 0))\t\t// Selection Coefficient\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(2), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_selcoeffs.emplace_back(EidosInterpreter::FloatForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (info_DOM_defined && (info_substr.compare(0, 4, \"DOM=\") == 0))\t// Dominance Coefficient\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(4), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_domcoeffs.emplace_back(EidosInterpreter::FloatForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (info_PO_defined && (info_substr.compare(0, 3, \"PO=\") == 0))\t// Population of Origin\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_poporigin.emplace_back((slim_objectid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (info_TO_defined && (info_substr.compare(0, 3, \"TO=\") == 0))\t// Tick of Origin\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_tickorigin.emplace_back((slim_tick_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (info_GO_defined && (info_substr.compare(0, 3, \"GO=\") == 0))\t// Generation of Origin - emitted by SLiM 3, treated as TO here\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_tickorigin.emplace_back((slim_tick_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (info_MT_defined && (info_substr.compare(0, 3, \"MT=\") == 0))\t// Mutation Type\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> value_substrs = Eidos_string_split(info_substr.substr(3), \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &value_substr : value_substrs)\n\t\t\t\t\t\tinfo_muttype.emplace_back((slim_objectid_t)EidosInterpreter::NonnegativeIntegerForString(value_substr, nullptr));\n\t\t\t\t}\n\t\t\t\telse if (/* info_AA_defined && */ (info_substr.compare(0, 3, \"AA=\") == 0))\t// Ancestral Allele; definition not required since it is a standard field\n\t\t\t\t{\n\t\t\t\t\tstd::string aa_str = info_substr.substr(3);\n\t\t\t\t\t\n\t\t\t\t\tif (aa_str == \"A\")\t\t\tinfo_ancestral_nuc = 0;\n\t\t\t\t\telse if (aa_str == \"C\")\t\tinfo_ancestral_nuc = 1;\n\t\t\t\t\telse if (aa_str == \"G\")\t\tinfo_ancestral_nuc = 2;\n\t\t\t\t\telse if (aa_str == \"T\")\t\tinfo_ancestral_nuc = 3;\n\t\t\t\t\telse\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file AA value must be A/C/G/T.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\telse if (info_NONNUC_defined && (info_substr == \"NONNUC\"))\t\t\t\t// Non-nucleotide-based\n\t\t\t\t{\n\t\t\t\t\tinfo_is_nonnuc = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ((info_mutids.size() != 0) && (info_mutids.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for MID field.\" << EidosTerminate();\n\t\t\t\tif ((info_selcoeffs.size() != 0) && (info_selcoeffs.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for S field.\" << EidosTerminate();\n\t\t\t\tif ((info_domcoeffs.size() != 0) && (info_domcoeffs.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for DOM field.\" << EidosTerminate();\n\t\t\t\tif ((info_poporigin.size() != 0) && (info_poporigin.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for PO field.\" << EidosTerminate();\n\t\t\t\tif ((info_tickorigin.size() != 0) && (info_tickorigin.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for GO or TO field.\" << EidosTerminate();\n\t\t\t\tif ((info_muttype.size() != 0) && (info_muttype.size() != alt_allele_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file unexpected value count for MT field.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\t// instantiate the mutations involved in this call line; the REF allele represents no mutation, ALT alleles are each separate mutations\n\t\t\tstd::vector<MutationIndex> alt_allele_mut_indices;\n\t\t\t\n\t\t\tfor (std::size_t alt_allele_index = 0; alt_allele_index < alt_allele_count; ++alt_allele_index)\n\t\t\t{\n\t\t\t\t// figure out the mutation type; if specified with MT, look it up, otherwise use the default supplied\n\t\t\t\tMutationType *mutation_type_ptr = default_mutation_type_ptr;\n\t\t\t\t\n\t\t\t\tif (info_muttype.size() > 0)\n\t\t\t\t{\n\t\t\t\t\tslim_objectid_t mutation_type_id = info_muttype[alt_allele_index];\n\t\t\t\t\t\n\t\t\t\t\tmutation_type_ptr = species->MutationTypeWithID(mutation_type_id);\n\t\t\t\t\t\n\t\t\t\t\tif (!mutation_type_ptr)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file MT field references a mutation type m\" << mutation_type_id << \" that is not defined.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!mutation_type_ptr)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file MT field missing, but no default mutation type was supplied in the mutationType parameter.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// check the dominance coefficient of DOM against that of the mutation type\n\t\t\t\tif (info_domcoeffs.size() > 0)\n\t\t\t\t{\n\t\t\t\t\tif (std::abs(info_domcoeffs[alt_allele_index] - mutation_type_ptr->dominance_coeff_) > 0.0001)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file DOM field specifies a dominance coefficient \" << info_domcoeffs[alt_allele_index] << \" that differs from the mutation type's dominance coefficient of \" << mutation_type_ptr->dominance_coeff_ << \".\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// get the selection coefficient from S, or draw one\n\t\t\t\tdouble selection_coeff;\n\t\t\t\t\n\t\t\t\tif (info_selcoeffs.size() > 0)\n\t\t\t\t\tselection_coeff = info_selcoeffs[alt_allele_index];\n\t\t\t\telse\n\t\t\t\t\tselection_coeff = mutation_type_ptr->DrawSelectionCoefficient();\n\t\t\t\t\n\t\t\t\t// get the subpop index from PO, or set to -1; no bounds checking on this\n\t\t\t\tslim_objectid_t subpop_index = -1;\n\t\t\t\t\n\t\t\t\tif (info_poporigin.size() > 0)\n\t\t\t\t\tsubpop_index = info_poporigin[alt_allele_index];\n\t\t\t\t\n\t\t\t\t// get the origin tick from gO, or set to the current tick; no bounds checking on this\n\t\t\t\tslim_tick_t origin_tick;\n\t\t\t\t\n\t\t\t\tif (info_tickorigin.size() > 0)\n\t\t\t\t\torigin_tick = info_tickorigin[alt_allele_index];\n\t\t\t\telse\n\t\t\t\t\torigin_tick = community.Tick();\n\t\t\t\t\n\t\t\t\t// figure out the nucleotide and do nucleotide-related checks\n\t\t\t\tint8_t alt_allele_nuc = alt_nucs[alt_allele_index];\t\t// must be defined, in all cases, but might be ignored\n\t\t\t\tint8_t nucleotide;\n\t\t\t\t\n\t\t\t\tif (nucleotide_based)\n\t\t\t\t{\n\t\t\t\t\tif (info_NONNUC_defined)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We are reading a SLiM-generated VCF file that uses NONNUC to designate non-nucleotide-based mutations\n\t\t\t\t\t\tif (info_is_nonnuc)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This call line is marked NONNUC, so there is no associated nucleotide; check against the mutation type\n\t\t\t\t\t\t\tif (mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a mutation marked NONNUC cannot use a nucleotide-based mutation type.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnucleotide = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// This call line is not marked NONNUC, so it represents nucleotide-based alleles\n\t\t\t\t\t\t\tif (!mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a nucleotide-based mutation cannot use a non-nucleotide-based mutation type.\" << EidosTerminate();\n\t\t\t\t\t\t\tif (ref_nuc != info_ancestral_nuc)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): the REF nucleotide does not match the AA nucleotide.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tint8_t ancestral = (int8_t)chromosome->AncestralSequence()->NucleotideAtIndex(mut_position);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (ancestral != ref_nuc)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): the REF/AA nucleotide does not match the ancestral nucleotide at the same position; a matching ancestral nucleotide sequence must be set prior to calling readIndividualsFromVCF().\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnucleotide = alt_allele_nuc;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// We are reading a generic VCF file that does not use NONNUC, so we follow the mutation type's lead; if it is nucleotide-based, we use the nucleotide specified\n\t\t\t\t\t\tif (mutation_type_ptr->nucleotide_based_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation type is nucleotide-based, so use the nucleotide specified; in this case we ignore REF and AA, however\n\t\t\t\t\t\t\tnucleotide = alt_allele_nuc;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation type is non-nucleotide-based, so we ignore the nucleotide supplied, as well as REF/AA\n\t\t\t\t\t\t\tnucleotide = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We are a non-nucleotide-based model, so NONNUC should not be defined; we do not understand nucleotides and will ignore them\n\t\t\t\t\tif (info_NONNUC_defined)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): cannot read a VCF file generated by a nucleotide-based model into a non-nucleotide-based model.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tnucleotide = -1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// instantiate the mutation with the values decided upon\n\t\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\t\tMutation *new_mut;\n\t\t\t\t\n\t\t\t\tif (info_mutids.size() > 0)\n\t\t\t\t{\n\t\t\t\t\t// a mutation ID was supplied; we use it blindly, having checked above that we are in the case where this is legal\n\t\t\t\t\tslim_mutationid_t mut_mutid = info_mutids[alt_allele_index];\n\t\t\t\t\t\n\t\t\t\t\tnew_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mut_mutid, mutation_type_ptr, chromosome->Index(), mut_position, selection_coeff, subpop_index, origin_tick, nucleotide);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// no mutation ID supplied, so use whatever is next\n\t\t\t\t\tnew_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_type_ptr, chromosome->Index(), mut_position, selection_coeff, subpop_index, origin_tick, nucleotide);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// This mutation type might not be used by any genomic element type (i.e. might not already be vetted), so we need to check and set pure_neutral_\n\t\t\t\tif (selection_coeff != 0.0)\n\t\t\t\t{\n\t\t\t\t\tspecies->pure_neutral_ = false;\n\t\t\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\t\tpop.MutationRegistryAdd(new_mut);\n\t\t\t\talt_allele_mut_indices.emplace_back(new_mut_index);\n\t\t\t\tmutation_indices.emplace_back(new_mut_index);\n\t\t\t}\n\t\t\t\n\t\t\t// read the genotype data for each sample id, which might be diploid or haploid, and might have data beyond GT\n\t\t\t// NOTE: unlike readHaplosomesFromVCF(), we place the mutations directly into the haplosomes, rather than using a genotype_calls vector\n\t\t\tint haplosomes_index = 0;\n\t\t\t\n\t\t\tfor (int sample_index = 0; sample_index < sample_id_count; ++sample_index)\n\t\t\t{\n\t\t\t\tif (iss.eof())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file call line ended unexpectedly before the last sample.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tstd::getline(iss, sub, '\\t');\n\t\t\t\t\n\t\t\t\t// extract just the GT field if others are present\n\t\t\t\tstd::size_t colon_pos = sub.find_first_of(':');\n\t\t\t\t\n\t\t\t\tif (colon_pos != std::string::npos)\n\t\t\t\t\tsub = sub.substr(0, colon_pos);\n\t\t\t\t\n\t\t\t\t// separate haploid calls that are joined by | or /; this is the hotspot of the whole method, so we try to be efficient here\n\t\t\t\tbool call_handled = false;\n\t\t\t\tint genotype_call1 = -1;\n\t\t\t\tint genotype_call2 = -1;\n\t\t\t\t\n\t\t\t\tif ((sub.length() == 3) && ((sub[1] == '|') || (sub[1] == '/')))\n\t\t\t\t{\n\t\t\t\t\t// diploid, both single-digit\n\t\t\t\t\tchar sub_ch1 = sub[0];\n\t\t\t\t\tchar sub_ch2 = sub[2];\n\t\t\t\t\t\n\t\t\t\t\tif ((sub_ch1 >= '0') && (sub_ch1 <= '9') && (sub_ch2 >= '0') && (sub_ch2 <= '9'))\n\t\t\t\t\t{\n\t\t\t\t\t\tgenotype_call1 = (int)(sub_ch1 - '0');\n\t\t\t\t\t\tgenotype_call2 = (int)(sub_ch2 - '0');\n\t\t\t\t\t\t\n\t\t\t\t\t\tcall_handled = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (sub.length() == 1)\n\t\t\t\t{\n\t\t\t\t\tchar sub_ch = sub[0];\n\t\t\t\t\t\n\t\t\t\t\tif (sub_ch == '~')\n\t\t\t\t\t{\n\t\t\t\t\t\t// If the call is ~, a tilde, it indicates that no genetic information is present\n\t\t\t\t\t\t// (this is the case for a female if we're reading Y-chromosome data, for example).\n\t\t\t\t\t\t// We leave genotype_call1 and genotype_call2 as -1, indicating no call for either.\n\t\t\t\t\t\t// Note that this is not part of the VCF standard; it had to be invented for SLiM.\n\t\t\t\t\t\tcall_handled = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// haploid, single-digit; note we always place this in genotype_call1\n\t\t\t\t\t\tif ((sub_ch >= '0') && (sub_ch <= '9'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgenotype_call1 = (int)(sub_ch - '0');\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcall_handled = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!call_handled)\n\t\t\t\t{\n\t\t\t\t\tstd::vector<std::string> genotype_substrs;\n\t\t\t\t\t\n\t\t\t\t\tif (sub.find('|') != std::string::npos)\n\t\t\t\t\t\tgenotype_substrs = Eidos_string_split(sub, \"|\");\t// phased\n\t\t\t\t\telse if (sub.find('/') != std::string::npos)\n\t\t\t\t\t\tgenotype_substrs = Eidos_string_split(sub, \"/\");\t// unphased; we don't worry about that\n\t\t\t\t\telse\n\t\t\t\t\t\tgenotype_substrs.emplace_back(sub);\t\t\t\t\t// haploid, presumably\n\t\t\t\t\t\n\t\t\t\t\tif (genotype_substrs.size() == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\t// diploid\n\t\t\t\t\t\tgenotype_call1 = (int)EidosInterpreter::NonnegativeIntegerForString(genotype_substrs[0], nullptr);\n\t\t\t\t\t\tgenotype_call2 = (int)EidosInterpreter::NonnegativeIntegerForString(genotype_substrs[1], nullptr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (genotype_substrs.size() == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// haploid; note we always place this in genotype_call1\n\t\t\t\t\t\tgenotype_call1 = (int)EidosInterpreter::NonnegativeIntegerForString(genotype_substrs[0], nullptr);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file genotype calls must be diploid or haploid; \" << genotype_substrs.size() << \" calls found in one sample.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ((genotype_call1 > (int)alt_allele_count) || (genotype_call2 > (int)alt_allele_count))\t// 0 is REF, 1..n are ALT alleles\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file call out of range (does not correspond to a REF or ALT allele in the call line).\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif ((genotype_call2 != -1) && (intrinsic_ploidy == 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a diploid call was seen ('\" << sub << \"') but the focal chromosome for the call (with symbol '\" << chromosome->Symbol() << \"') is intrinsically haploid.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// add the mutations to the appropriate haplosomes and record the new derived states\n\t\t\t\t// this uses the cached haplosome state we set up above, for efficient addition:\n\t\t\t\t//\n\t\t\t\t//std::vector<Haplosome *> haplosomes;\n\t\t\t\t//std::vector<slim_mutrun_index_t> haplosomes_last_mutrun_modified;\n\t\t\t\t//std::vector<MutationRun *> haplosome_last_mutrun;\n\t\t\t\t//\n\t\t\t\t// remember that haplosomes has nullptr for any null haplosomes, to catch bugs!\n\t\t\t\t\n\t\t\t\tif (genotype_call1 == -1)\n\t\t\t\t{\n\t\t\t\t\tif (genotype_call2 == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Neither call is present; this occurs with the ~ call, which in not VCF standard\n\t\t\t\t\t\t// We check that both haplosomes are null; a non-null haplosome should be called\n\t\t\t\t\t\t// as not having any mutation with 0, not ~.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// We do, however, allow a ~ call for chromosome type 'A' or 'H', and transmogrify\n\t\t\t\t\t\t// any existing non-null haplosome to null, as long as it is empty.  We do not want\n\t\t\t\t\t\t// to allow that for other chromosome types, since it would require changing the sex.\n\t\t\t\t\t\tif (intrinsic_ploidy == 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *haplosome1 = haplosomes[haplosomes_index];\n\t\t\t\t\t\t\tHaplosome *haplosome2 = haplosomes[haplosomes_index + 1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (haplosome1 || haplosome2)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (chromosome_type == ChromosomeType::kA_DiploidAutosome)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (haplosome1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (haplosome1->mutation_count())\n\t\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a call of '~' was used for a haplosome that already contains mutations, and thus cannot be made into a null haplosome; use a call of 0, not ~, if the haplosome is not intended to be a null haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t\thaplosome1->MakeNull();\n\t\t\t\t\t\t\t\t\t\thaplosome1->OwningIndividual()->subpopulation_->has_null_haplosomes_ = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (haplosome2)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (haplosome2->mutation_count())\n\t\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a call of '~' was used for a haplosome that already contains mutations, and thus cannot be made into a null haplosome; use a call of 0, not ~, if the haplosome is not intended to be a null haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t\thaplosome2->MakeNull();\n\t\t\t\t\t\t\t\t\t\thaplosome2->OwningIndividual()->subpopulation_->has_null_haplosomes_ = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a call of '~' was used for an individual that has a non-null haplosome; that is not legal.\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we don't need to do anything; no mutations to add\n\t\t\t\t\t\t\thaplosomes_index += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *haplosome1 = haplosomes[haplosomes_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (haplosome1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (chromosome_type == ChromosomeType::kH_HaploidAutosome)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (haplosome1->mutation_count())\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a call of '~' was used for a haplosome that already contains mutations, and thus cannot be made into a null haplosome; use a call of 0, not ~, if the haplosome is not intended to be a null haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\thaplosome1->MakeNull();\n\t\t\t\t\t\t\t\t\thaplosome1->OwningIndividual()->subpopulation_->has_null_haplosomes_ = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a call of '~' was used for an individual that has a non-null haplosome; that is not legal.\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we don't need to do anything; no mutations to add\n\t\t\t\t\t\t\thaplosomes_index++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): (internal error) call for position 2 with no call for position 1; that should not occur in the present design.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (genotype_call2 == -1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Haploid call; this could be for an intrinsically haploid chromosome, or\n\t\t\t\t\t\t// could be indicating that one haplosome of an intrinsically diploid\n\t\t\t\t\t\t// chromosome is null.  For now, we require the null haplosome state to\n\t\t\t\t\t\t// already be set up.\n\t\t\t\t\t\tif (intrinsic_ploidy == 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (haplosomes[haplosomes_index])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Here, for chromosome type \"A\" we transmogrify the second haplosome into a\n\t\t\t\t\t\t\t\t// null haplosome as long as it is empty, rather than throwing an error.\n\t\t\t\t\t\t\t\t// The choice to do this to the *second* haplosome is kind of arbitrary; all\n\t\t\t\t\t\t\t\t// we know is that we've got a haploid call for a diploid chromosome.  Since\n\t\t\t\t\t\t\t\t// there is no indication in the call syntax, we assume the second haplosome\n\t\t\t\t\t\t\t\t// is the one intended to be null.  We could extend the syntax of VCF again\n\t\t\t\t\t\t\t\t// here, like 1|~ versus ~|1 indicating the position of the null, but that\n\t\t\t\t\t\t\t\t// feels like overkill at this time.  BCH 3/6/2025.\n\t\t\t\t\t\t\t\tif (haplosomes[haplosomes_index + 1])\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (chromosome_type == ChromosomeType::kA_DiploidAutosome)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHaplosome *implied_null_haplosome = haplosomes[haplosomes_index + 1];\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (implied_null_haplosome->mutation_count())\n\t\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a haploid call implies that an individual's second haplosome for a diploid chromosome is null, but that haplosome already contains mutations, and thus cannot be made into a null haplosome; use a diploid call, if neither haplosome is intended to be a null haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t\timplied_null_haplosome->MakeNull();\n\t\t\t\t\t\t\t\t\t\timplied_null_haplosome->OwningIndividual()->subpopulation_->has_null_haplosomes_ = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a haploid call is present for an individual that has two non-null haplosomes for the focal chromosome (which is not of type 'A'); that is not legal.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// add the called mutation to the haplosome at haplosomes_index\n\t\t\t\t\t\t\t\t_AddCallToHaplosome(genotype_call1, haplosomes[haplosomes_index], haplosomes_last_mutrun_modified[haplosomes_index], haplosomes_last_mutrun[haplosomes_index],\n\t\t\t\t\t\t\t\t\t\t\t\t\talt_allele_mut_indices, mut_position, species, &mutrun_context,\n\t\t\t\t\t\t\t\t\t\t\t\t\tall_target_haplosomes_started_empty, recording_mutations);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (haplosomes[haplosomes_index + 1])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// add the called mutation to the haplosome at haplosomes_index + 1\n\t\t\t\t\t\t\t\t_AddCallToHaplosome(genotype_call1, haplosomes[haplosomes_index + 1], haplosomes_last_mutrun_modified[haplosomes_index + 1], haplosomes_last_mutrun[haplosomes_index + 1],\n\t\t\t\t\t\t\t\t\t\t\t\t\talt_allele_mut_indices, mut_position, species, &mutrun_context,\n\t\t\t\t\t\t\t\t\t\t\t\t\tall_target_haplosomes_started_empty, recording_mutations);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a haploid call is present for an individual that has no non-null haplosome for the focal chromosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\thaplosomes_index += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\t// intrinsic_ploidy == 1\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (haplosomes[haplosomes_index])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// add the called mutation to the haplosome at haplosomes_index\n\t\t\t\t\t\t\t\t_AddCallToHaplosome(genotype_call1, haplosomes[haplosomes_index], haplosomes_last_mutrun_modified[haplosomes_index], haplosomes_last_mutrun[haplosomes_index],\n\t\t\t\t\t\t\t\t\t\t\t\t\talt_allele_mut_indices, mut_position, species, &mutrun_context,\n\t\t\t\t\t\t\t\t\t\t\t\t\tall_target_haplosomes_started_empty, recording_mutations);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a haploid call is present for an individual that has no non-null haplosome for the focal chromosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\thaplosomes_index++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Diploid call; must be for an intrinsically diploid chromosome, with no\n\t\t\t\t\t\t// null haplosomes present in the individual.\n\t\t\t\t\t\tif (intrinsic_ploidy == 1)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a diploid call is present for an intrinsically haploid focal chromosome.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// add the first called mutation to the haplosome at haplosomes_index\n\t\t\t\t\t\tif (haplosomes[haplosomes_index])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_AddCallToHaplosome(genotype_call1, haplosomes[haplosomes_index], haplosomes_last_mutrun_modified[haplosomes_index], haplosomes_last_mutrun[haplosomes_index],\n\t\t\t\t\t\t\t\t\t\t\t\talt_allele_mut_indices, mut_position, species, &mutrun_context,\n\t\t\t\t\t\t\t\t\t\t\t\tall_target_haplosomes_started_empty, recording_mutations);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a diploid call is present for an individual that has a null haplosome for the focal chromosome.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosomes_index++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// add the second called mutation to the haplosome at haplosomes_index\n\t\t\t\t\t\tif (haplosomes[haplosomes_index])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_AddCallToHaplosome(genotype_call2, haplosomes[haplosomes_index], haplosomes_last_mutrun_modified[haplosomes_index], haplosomes_last_mutrun[haplosomes_index],\n\t\t\t\t\t\t\t\t\t\t\t\talt_allele_mut_indices, mut_position, species, &mutrun_context,\n\t\t\t\t\t\t\t\t\t\t\t\tall_target_haplosomes_started_empty, recording_mutations);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): a diploid call is present for an individual that has a null haplosome for the focal chromosome.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosomes_index++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!iss.eof())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_readIndividualsFromVCF): VCF file call line has unexpected entries following the last sample.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// Return the instantiated mutations\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint mutation_count = (int)mutation_indices.size();\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(mutation_count);\n\t\n\tfor (int mut_index = 0; mut_index < mutation_count; ++mut_index)\n\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + mutation_indices[mut_index], mut_index);\n\t\n\treturn EidosValue_Object_SP(vec);\n}\n\n//\t*********************\t– (void)setSpatialPosition(float position)\n//\nEidosValue_SP Individual_Class::ExecuteMethod_setSpatialPosition(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *position_value = p_arguments[0].get();\n\tint dimensionality = 0;\n\tint value_count = position_value->Count();\n\tint target_size = p_target->Count();\n\t\n\t// Determine the spatiality of the individuals involved, and make sure it is the same for all\n\tif (target_size >= 1)\n\t{\n\t\tIndividual * const *targets = (Individual * const *)(p_target->ObjectData());\n\t\t\n\t\tdimensionality = targets[0]->subpopulation_->species_.SpatialDimensionality();\n\t\t\n\t\tfor (int target_index = 1; target_index < target_size; ++target_index)\n\t\t{\n\t\t\tIndividual *target = targets[target_index];\n\t\t\t\n\t\t\tif (target->subpopulation_->species_.SpatialDimensionality() != dimensionality)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): setSpatialPosition() requires that all individuals in the target vector have the same spatial dimensionality.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tif ((target_size > 0) && (dimensionality == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): setSpatialPosition() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\tif ((dimensionality < 0) || (dimensionality > 3))\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t\n\tif (value_count < dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): setSpatialPosition() requires at least as many coordinates as the spatial dimensionality of the simulation.\" << EidosTerminate();\n\t\n\tif (value_count == dimensionality)\n\t{\n\t\t// One point is being set across all targets\n\t\tif (target_size >= 1)\n\t\t{\n\t\t\t// Vector target case, one point\n\t\t\tIndividual * const *targets = (Individual * const *)(p_target->ObjectData());\n\t\t\t\n\t\t\tswitch (dimensionality)\n\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t{\n\t\t\t\t\tdouble x = position_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_1_1D);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(target_size) firstprivate(targets, x) if(target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_1_1D) num_threads(thread_count)\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = x;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 2:\n\t\t\t\t{\n\t\t\t\t\tdouble x = position_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\tdouble y = position_value->FloatAtIndex_NOCAST(1, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_1_2D);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(target_size) firstprivate(targets, x, y) if(target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_1_2D) num_threads(thread_count)\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = x;\n\t\t\t\t\t\ttarget->spatial_y_ = y;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 3:\n\t\t\t\t{\n\t\t\t\t\tdouble x = position_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\tdouble y = position_value->FloatAtIndex_NOCAST(1, nullptr);\n\t\t\t\t\tdouble z = position_value->FloatAtIndex_NOCAST(2, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_1_3D);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(target_size) firstprivate(targets, x, y, z) if(target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_1_3D) num_threads(thread_count)\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = x;\n\t\t\t\t\t\ttarget->spatial_y_ = y;\n\t\t\t\t\t\ttarget->spatial_z_ = z;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): (internal error) dimensionality out of range.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\telse if (value_count == dimensionality * target_size)\n\t{\n\t\t// Vector target case, one point per target (so the point vector has to be non-singleton too)\n\t\tIndividual * const *targets = (Individual * const *)(p_target->ObjectData());\n\t\tconst double *positions = position_value->FloatData();\n\t\t\n#ifdef _OPENMP\n\t\tif (((dimensionality == 1) && (target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_2_1D)) ||\n\t\t\t((dimensionality == 2) && (target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_2_2D)) ||\n\t\t\t((dimensionality == 3) && (target_size >= EIDOS_OMPMIN_SET_SPATIAL_POS_2_3D)))\n\t\t{\n\t\t\tswitch (dimensionality)\n\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t{\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_2_1D);\n#pragma omp parallel for schedule(static) default(none) shared(target_size) firstprivate(targets, positions) num_threads(thread_count) // if(EIDOS_OMPMIN_SET_SPATIAL_POS_2_1D) is above\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\ttargets[target_index]->spatial_x_ = positions[target_index];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 2:\n\t\t\t\t{\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_2_2D);\n#pragma omp parallel for schedule(static) default(none) shared(target_size) firstprivate(targets, positions) num_threads(thread_count) // if(EIDOS_OMPMIN_SET_SPATIAL_POS_2_2D) is above\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\tconst double *target_pos = positions + target_index * 2;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttarget->spatial_x_ = target_pos[0];\n\t\t\t\t\t\ttarget->spatial_y_ = target_pos[1];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 3:\n\t\t\t\t{\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SET_SPATIAL_POS_2_3D);\n#pragma omp parallel for schedule(static) default(none) shared(target_size) firstprivate(targets, positions) num_threads(thread_count) // if(EIDOS_OMPMIN_SET_SPATIAL_POS_2_3D) is above\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\tconst double *target_pos = positions + target_index * 3;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttarget->spatial_x_ = target_pos[0];\n\t\t\t\t\t\ttarget->spatial_y_ = target_pos[1];\n\t\t\t\t\t\ttarget->spatial_z_ = target_pos[2];\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else\n#endif\n\t\t{\n\t\t\tswitch (dimensionality)\n\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t{\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = *(positions++);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 2:\n\t\t\t\t{\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = *(positions++);\n\t\t\t\t\t\ttarget->spatial_y_ = *(positions++);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 3:\n\t\t\t\t{\n\t\t\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tIndividual *target = targets[target_index];\n\t\t\t\t\t\ttarget->spatial_x_ = *(positions++);\n\t\t\t\t\t\ttarget->spatial_y_ = *(positions++);\n\t\t\t\t\t\ttarget->spatial_z_ = *(positions++);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): (internal error) dimensionality out of range.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_setSpatialPosition): setSpatialPosition() requires the position parameter to contain either one point, or one point per individual (where each point has a number of coordinates equal to the spatial dimensionality of the simulation).\" << EidosTerminate();\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\t\n\n//\t*********************\t+ (integer)zygosityOfMutations([No<Mutation> mutations = NULL], [integer$ hemizygousValue = 1], [integer$ haploidValue = 1])\n//\nEidosValue_SP Individual_Class::ExecuteMethod_zygosityOfMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tIndividual **target_individuals = (Individual **)p_target->data();\n\tint target_size = p_target->Count();\n\t\n\tif (target_size == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividualsVector(target_individuals, target_size);\n\t\n\tif (species == nullptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_zygosityOfMutations): zygosityOfMutations() requires that all target individuals belong to the same species.\" << EidosTerminate();\n\t\n\tspecies->population_.CheckForDeferralInIndividualsVector(target_individuals, target_size, \"Individual_Class::ExecuteMethod_zygosityOfMutations\");\n\t\n\tconst std::vector<Chromosome *> &chromosomes = species->Chromosomes();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tEidosValue *mutations_value = p_arguments[0].get();\n\tEidosValue *hemizygousValue_value = p_arguments[1].get();\n\tEidosValue *haploidValue_value = p_arguments[2].get();\n\t\n\tint64_t hemizygousValue = hemizygousValue_value->IntAtIndex_NOCAST(0, nullptr);\n\tint64_t haploidValue = haploidValue_value->IntAtIndex_NOCAST(0, nullptr);\n\tstd::vector<Mutation *> focalMutations;\n\t\n\tif (mutations_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// When assessing all mutations, we assume that all chromosomes need to be scanned\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = species->population_.MutationRegistry(&registry_size);\n\t\t\n\t\tfocalMutations.resize(registry_size);\n\t\t\n\t\tMutation **focalMutations_data = focalMutations.data();\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tfocalMutations_data[registry_index] = mut;\n\t\t}\n\t\t\n\t\t// mark a scratch value inside all chromosomes; 1 indicates the chromosome is active\n\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\tchromosome->scratch_ = 1;\n\t}\n\telse\n\t{\n\t\t// When assessing a vector of mutations, we first determine which chromosomes we need to scan\n\t\t// In this case we also need to check that all mutations belong to the same species as the individuals\n\t\tif (Community::SpeciesForMutations(mutations_value) != species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual_Class::ExecuteMethod_zygosityOfMutations): zygosityOfMutations() requires that all mutations belong to the same species as the target individuals.\" << EidosTerminate();\n\t\t\n\t\t// zero out the scratch_ for all chromosomes; 0 indicates the chromosome is not active\n\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\tchromosome->scratch_ = 0;\n\t\t\n\t\tMutation **mutations_data = (Mutation **)mutations_value->ObjectData();\n\t\tint mutations_count = mutations_value->Count();\n\t\t\n\t\tfocalMutations.resize(mutations_count);\n\t\t\n\t\tMutation **focalMutations_data = focalMutations.data();\n\t\t\n\t\tfor (int mutations_index = 0; mutations_index < mutations_count; ++mutations_index)\n\t\t{\n\t\t\tMutation *mut = mutations_data[mutations_index];\n\t\t\t\n\t\t\tfocalMutations_data[mutations_index] = mut;\n\t\t\t\n\t\t\t// mark a scratch value inside the associated chromosome; 1 indicates the chromosome is active\n\t\t\tchromosomes[mut->chromosome_index_]->scratch_ = 1;\n\t\t}\n\t}\n\t\n\tif (focalMutations.size() == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// allocate the result vector\n\tEidosValue_Int *integer_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(focalMutations.size() * target_size);\n\tint64_t *integer_result_data = integer_result->data_mutable();\n\t\n\t// tabulate the results for each individuals\n\tconst uint8_t PRESENT_HETEROZYGOUS = 1;\n\tconst uint8_t PRESENT_HOMOZYGOUS = 2;\n\tconst uint8_t PRESENT_HEMIZYGOUS = 3;\n\tconst uint8_t PRESENT_HAPLOID = 4;\n\t\n\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t{\n\t\tIndividual *individual = target_individuals[target_index];\n\t\t\n\t\t// first we zero out our zygosity counters; note that if this is parallelized, it will need separate scratch space for each thread\n\t\tfor (Mutation *mut : focalMutations)\n\t\t\tmut->scratch_ = 0;\n\t\t\n\t\t// loop over the active chromosomes\n\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t{\n\t\t\tif (chromosome->scratch_ == 0)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tunsigned int chromosome_index = chromosome->Index();\n\t\t\t\n\t\t\tif (chromosome->IntrinsicPloidy() == 2)\n\t\t\t{\n\t\t\t\t// intrinsically diploid case\n\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[species->FirstHaplosomeIndices()[chromosome_index]];\n\t\t\t\tHaplosome *haplosome2 = individual->haplosomes_[species->LastHaplosomeIndices()[chromosome_index]];\n\t\t\t\tbool haplosome1_isnull = haplosome1->IsNull();\n\t\t\t\tbool haplosome2_isnull = haplosome2->IsNull();\n\t\t\t\t\n\t\t\t\tif (haplosome1_isnull && haplosome2_isnull)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tif (haplosome1_isnull || haplosome2_isnull)\n\t\t\t\t{\n\t\t\t\t\t// hemizygous case\n\t\t\t\t\tHaplosome *haplosome = (haplosome1_isnull ? haplosome2 : haplosome1);\n\t\t\t\t\tconst int32_t mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *haplosome_max = mutrun->end_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (haplosome_iter != haplosome_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex haplosome_mutation = *haplosome_iter++;\n\t\t\t\t\t\t\tMutation *mutation = (mut_block_ptr + haplosome_mutation);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmutation->scratch_ = PRESENT_HEMIZYGOUS;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// diploid case\n\t\t\t\t\tconst int32_t mutrun_count = haplosome1->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun1 = haplosome1->mutruns_[run_index];\n\t\t\t\t\t\tconst MutationRun *mutrun2 = haplosome2->mutruns_[run_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst MutationIndex *haplosome1_iter = mutrun1->begin_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *haplosome2_iter = mutrun2->begin_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst MutationIndex *haplosome1_max = mutrun1->end_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *haplosome2_max = mutrun2->end_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((haplosome1_iter != haplosome1_max) && (haplosome2_iter != haplosome2_max))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter, haplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\tslim_position_t haplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_, haplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (haplosome1_iter_position < haplosome2_iter_position)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Process a mutation in haplosome1 since it is leading\n\t\t\t\t\t\t\t\t\t(mut_block_ptr + haplosome1_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (haplosome1_iter_position > haplosome2_iter_position)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Process a mutation in haplosome2 since it is leading\n\t\t\t\t\t\t\t\t\t(mut_block_ptr + haplosome2_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Look for homozygosity: haplosome1_iter_position == haplosome2_iter_position\n\t\t\t\t\t\t\t\t\tslim_position_t position = haplosome1_iter_position;\n\t\t\t\t\t\t\t\t\tconst MutationIndex *haplosome1_start = haplosome1_iter;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// advance through haplosome1 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tconst MutationIndex *haplosome2_matchscan = haplosome2_iter; \n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// advance through haplosome2 with haplosome2_matchscan, looking for a match for the current mutation in haplosome1, to determine whether we are homozygous or not\n\t\t\t\t\t\t\t\t\t\twhile (haplosome2_matchscan != haplosome2_max && (mut_block_ptr + *haplosome2_matchscan)->position_ == position)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (haplosome1_mutindex == *haplosome2_matchscan)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t// a match was found, so we record a homozygous state\n\t\t\t\t\t\t\t\t\t\t\t\t(mut_block_ptr + haplosome1_mutindex)->scratch_ = PRESENT_HOMOZYGOUS;\n\t\t\t\t\t\t\t\t\t\t\t\tgoto homozygousExit1;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\thaplosome2_matchscan++;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// no match was found, so we are heterozygous\n\t\t\t\t\t\t\t\t\t\t(mut_block_ptr + haplosome1_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\thomozygousExit1:\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} while (haplosome1_iter_position == position);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// advance through haplosome2 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tconst MutationIndex *haplosome1_matchscan = haplosome1_start; \n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// advance through haplosome1 with haplosome1_matchscan, looking for a match for the current mutation in haplosome2, to determine whether we are homozygous or not\n\t\t\t\t\t\t\t\t\t\twhile ((haplosome1_matchscan != haplosome1_max) && ((mut_block_ptr + *haplosome1_matchscan)->position_ == position))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (haplosome2_mutindex == *haplosome1_matchscan)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t// a match was found; we know this match was already found by the haplosome1 loop above\n\t\t\t\t\t\t\t\t\t\t\t\tgoto homozygousExit2;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\thaplosome1_matchscan++;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// no match was found, so we are heterozygous\n\t\t\t\t\t\t\t\t\t\t(mut_block_ptr + haplosome2_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\thomozygousExit2:\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} while (haplosome2_iter_position == position);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// break out if either haplosome has reached its end\n\t\t\t\t\t\t\t\t\tif (haplosome1_iter == haplosome1_max || haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} while (true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// one or the other haplosome has now reached its end, so now we just need to handle the remaining mutations in the unfinished haplosome\n#if DEBUG\n\t\t\t\t\t\tassert(!(haplosome1_iter != haplosome1_max && haplosome2_iter != haplosome2_max));\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if haplosome1 is unfinished, finish it\n\t\t\t\t\t\twhile (haplosome1_iter != haplosome1_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter++;\n\t\t\t\t\t\t\t(mut_block_ptr + haplosome1_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if haplosome2 is unfinished, finish it\n\t\t\t\t\t\twhile (haplosome2_iter != haplosome2_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex haplosome2_mutindex = *haplosome2_iter++;\n\t\t\t\t\t\t\t(mut_block_ptr + haplosome2_mutindex)->scratch_ = PRESENT_HETEROZYGOUS;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// intrinsically haploid case\n\t\t\t\tHaplosome *haplosome = individual->haplosomes_[species->FirstHaplosomeIndices()[chromosome_index]];\n\t\t\t\t\n\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// haploid case\n\t\t\t\tconst int32_t mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *haplosome_max = mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\twhile (haplosome_iter != haplosome_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex haplosome_mutation = *haplosome_iter++;\n\t\t\t\t\t\tMutation *mutation = (mut_block_ptr + haplosome_mutation);\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutation->scratch_ = PRESENT_HAPLOID;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// then run through the mutations again and transfer counts (zygosity) to the result matrix\n\t\tint64_t *result_column_ptr = integer_result_data + focalMutations.size() * target_index;\n\t\t\n\t\tif ((hemizygousValue == 1) && (haploidValue == 1))\n\t\t{\n\t\t\t// simple occurrence counts\n\t\t\tfor (Mutation *mut : focalMutations)\n\t\t\t{\n\t\t\t\tint8_t scratch_value = mut->scratch_;\n\t\t\t\t\n\t\t\t\t// an occurrence count of 0 or 2 is unambiguous in the way it is recorded\n\t\t\t\t// other occurrence counts all translate to a zygosity of 1\n\t\t\t\tif ((scratch_value == 0) || (scratch_value == 2))\n\t\t\t\t\t*(result_column_ptr++) = scratch_value;\n\t\t\t\telse\n\t\t\t\t\t*(result_column_ptr++) = 1;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// not simple occurrence counts\n\t\t\tfor (Mutation *mut : focalMutations)\n\t\t\t{\n\t\t\t\tint8_t scratch_value = mut->scratch_;\n\t\t\t\t\n\t\t\t\t// an occurrence count of 0 or 2 is unambiguous in the way it is recorded\n\t\t\t\tif ((scratch_value == 0) || (scratch_value == 2))\n\t\t\t\t{\n\t\t\t\t\t*(result_column_ptr++) = scratch_value;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// other occurrence counts need to be translated to the correct result value\n\t\t\t\tif (scratch_value == PRESENT_HEMIZYGOUS)\n\t\t\t\t\t*(result_column_ptr++) = hemizygousValue;\n\t\t\t\telse if (scratch_value == PRESENT_HAPLOID)\n\t\t\t\t\t*(result_column_ptr++) = haploidValue;\n\t\t\t\telse\n\t\t\t\t\t*(result_column_ptr++) = 1;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// set the dimensionality of the result matrix\n\tconst int64_t dim_buf[2] = {(int64_t)focalMutations.size(), target_size};\n\t\n\tinteger_result->SetDimensions(2, dim_buf);\n\t\n\treturn EidosValue_SP(integer_result);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/individual.h",
    "content": "//\n//  individual.h\n//  SLiM\n//\n//  Created by Ben Haller on 6/10/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Individual is a simple placeholder for individual simulated organisms.  It is not used by SLiM's core engine at all;\n it is provided solely for scripting convenience, as a bag containing the two haplosomes associated with an individual.  This\n makes it easy to sample a subpopulation's individuals, rather than its haplosomes; to determine whether individuals have a given\n mutation on either of their haplosomes; and other similar tasks.\n \n Individuals are kept by Subpopulation, and have the same lifetime as the Subpopulation to which they belong.  Since they do not\n actually contain any information specific to a particular individual – just an index in the Subpopulation's haplosomes vector –\n they do not get deallocated and reallocated between cycles; the same object continues to represent individual #17 of the\n subpopulation for as long as that subpopulation exists.  This is safe because of the way that objects cannot live across code\n block boundaries in SLiM.  The tag values of particular Individual objects will persist between cycles, even though the\n individual that is conceptually represented has changed, but that is fine since those values are officially undefined until set.\n \n */\n\n#ifndef __SLiM__individual__\n#define __SLiM__individual__\n\n\n#include \"haplosome.h\"\n\n\nclass Subpopulation;\n\nextern EidosClass *gSLiM_Individual_Class;\n\n// A global counter used to assign all Individual objects a unique ID.  Note this is shared by all species.\nextern slim_pedigreeid_t gSLiM_next_pedigree_id;\t\t\t// use SLiM_GetNextPedigreeID() instead, for THREAD_SAFETY_IN_ACTIVE_PARALLEL()\n\ninline slim_pedigreeid_t SLiM_GetNextPedigreeID(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"SLiM_GetNextPedigreeID(): gSLiM_next_pedigree_id change\");\n\treturn gSLiM_next_pedigree_id++;\n}\n\ninline slim_pedigreeid_t SLiM_GetNextPedigreeID_Block(int p_block_size)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"SLiM_GetNextPedigreeID_Block(): gSLiM_next_pedigree_id change\");\n\tslim_pedigreeid_t block_base = gSLiM_next_pedigree_id;\n\t\n\tgSLiM_next_pedigree_id += p_block_size;\n\t\n\treturn block_base;\n}\n\nclass Individual : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\t\n\tEidosValue_SP self_value_;\t\t\t\t\t\t// cached EidosValue object for speed\n\t\n#ifdef SLIMGUI\n\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\tuint8_t color_set_;\t\t\t\t\t\t\t\t// set to true if the color for the individual has been set\n\tuint8_t colorR_, colorG_, colorB_;\t\t\t\t// cached color components from the color property\n#endif\n\t\n\t// Pedigree-tracking ivars.  These are -1 if unknown, otherwise assigned sequentially from 0 counting upward.  They\n\t// uniquely identify individuals within the simulation, so that relatedness of individuals can be assessed.  They can\n\t// be accessed through the read-only pedigree properties.  These are only maintained if sim->pedigrees_enabled_ is on.\n\t// If these are maintained, haplosome pedigree IDs are also maintained in parallel; see haplosome.h.\n\tfloat mean_parent_age_;\t\t\t\t// the mean age of this individual's parents; 0 if parentless, -1 in WF models\n\tslim_pedigreeid_t pedigree_id_;\t\t// the id of this individual\n\tslim_pedigreeid_t pedigree_p1_;\t\t// the id of parent 1\n\tslim_pedigreeid_t pedigree_p2_;\t\t// the id of parent 2\n\tslim_pedigreeid_t pedigree_g1_;\t\t// the id of grandparent 1\n\tslim_pedigreeid_t pedigree_g2_;\t\t// the id of grandparent 2\n\tslim_pedigreeid_t pedigree_g3_;\t\t// the id of grandparent 3\n\tslim_pedigreeid_t pedigree_g4_;\t\t// the id of grandparent 4\n\tint32_t reproductive_output_;\t\t// the number of offspring for which this individual has been a parent, so far\n\t\n\t// This holds the base tskit id used for haplosomes (nodes) belonging to this individual.  If the haplosome is\n\t// in 1st position (the first for its chromosome), its node id is tsk_node_id_base_; if it is in 2nd position\n\t// (the second for its chromosome), its node id is tsk_node_id_base_ + 1.  Since this is the same for all\n\t// haplosomes for a given individual, we store it here for space efficiency.  This is set up by the method\n\t// SetCurrentNewIndividual(), which creates the two new entries in the shared node table that are used by all\n\t// haplosomes for the individual.\n\ttsk_id_t /* int32_t */ tsk_node_id_base_;\n\t\npublic:\n\t\n\t// BCH 6 April 2017: making these ivars public; lots of other classes want to access them, but writing\n\t// accessors for them seems excessively complicated / slow, and friending the whole class is too invasive.\n\t// Basically I think of the Individual class as just being a struct-like bag in some aspects.\n\t\n\tuint8_t scratch_;\t\t\t\t\t// available for use by algorithms\n\tIndividualSex sex_;\t\t\t\t\t// must correspond to our position in the Subpopulation vector we live in\n\tunsigned int migrant_ : 1;\t\t\t// T if the individual has migrated in the current cycle, F otherwise\n\tunsigned int killed_ : 1;\t\t\t// T if the individual has been killed by killIndividuals(), F otherwise\n\t\n\t// note there are 4 bits free here for other logical flags\n\t\n\tunsigned tagL0_set_ : 1;\t\t\t// T if tagL0 has been set by the user\n\tunsigned tagL0_value_ : 1;\t\t\t// a user-defined tag value of logical type\n\tunsigned tagL1_set_ : 1;\t\t\t// T if tagL1 has been set by the user\n\tunsigned tagL1_value_ : 1;\t\t\t// a user-defined tag value of logical type\n\tunsigned tagL2_set_ : 1;\t\t\t// T if tagL2 has been set by the user\n\tunsigned tagL2_value_ : 1;\t\t\t// a user-defined tag value of logical type\n\tunsigned tagL3_set_ : 1;\t\t\t// T if tagL3 has been set by the user\n\tunsigned tagL3_value_ : 1;\t\t\t// a user-defined tag value of logical type\n\tunsigned tagL4_set_ : 1;\t\t\t// T if tagL4 has been set by the user\n\tunsigned tagL4_value_ : 1;\t\t\t// a user-defined tag value of logical type\n\t\n\tslim_usertag_t tag_value_;\t\t\t// a user-defined tag value of integer type\n\tdouble tagF_value_;\t\t\t\t\t// a user-defined tag value of float type\n\t\n\tdouble fitness_scaling_ = 1.0;\t\t// the fitnessScaling property value\n\tdouble cached_fitness_UNSAFE_;\t\t// the last calculated fitness value for this individual; NaN for new offspring, 1.0 for new subpops\n\t\t\t\t\t\t\t\t\t\t// this is marked UNSAFE because Subpopulation's individual_cached_fitness_OVERRIDE_ flag can override\n\t\t\t\t\t\t\t\t\t\t// this value in neutral models; that flag must be checked before using this cached value\n#ifdef SLIMGUI\n\tdouble cached_unscaled_fitness_;\t// the last calculated fitness value for this individual, WITHOUT subpop fitnessScaling; used only in\n\t\t\t\t\t\t\t\t\t\t// in SLiMgui, which wants to exclude that scaling because it usually represents density-dependence\n\t\t\t\t\t\t\t\t\t\t// that confuses interpretation; note that individual_cached_fitness_OVERRIDE_ is not relevant to this\n#endif\n\t\n\tHaplosome *hapbuffer_[2];\t\t\t// *(hapbuffer_[2]), an internal buffer used to avoid allocation and increase memory nonlocality\n\tHaplosome **haplosomes_;\t\t\t// OWNED haplosomes; can point to hapbuffer_ or to an external malloced block\n\tslim_age_t age_;\t\t\t\t\t// nonWF only: the age of the individual, in cycles; -1 in WF models\n\t\n\tslim_popsize_t index_;\t\t\t\t// the individual index in that subpop (0-based, and not multiplied by 2)\n\tSubpopulation *subpopulation_;\t\t// the subpop to which we belong; cannot be a reference because it changes on migration!\n\t\n\t// Continuous space ivars.  These are effectively free tag values of type float, unless they are used by interactions.\n\tdouble spatial_x_, spatial_y_, spatial_z_;\n\t\n\t//\n\t//\tThis class should not be copied, in general, but the default copy constructor cannot be entirely\n\t//\tdisabled, because we want to keep instances of this class inside STL containers.  We therefore\n\t//\toverride it to log whenever it is called, to reduce the risk of unintentional copying.\n\t//\n\tIndividual(const Individual &p_original) = delete;\n\tIndividual& operator= (const Individual &p_original) = delete;\t\t\t\t\t\t// no copy construction\n\tIndividual(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tIndividual(Subpopulation *p_subpopulation, slim_popsize_t p_individual_index, IndividualSex p_sex, slim_age_t p_age, double p_fitness, float p_mean_parent_age);\n\tvirtual ~Individual(void) override;\n\t\n\tinline __attribute__((always_inline)) void ClearColor(void) {\n#ifdef SLIMGUI\n\t\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\t\tcolor_set_ = false;\n#endif\n\t}\n\t\n\t// This sets the receiver up as a new individual, with a newly assigned pedigree id, and gets\n\t// parental and grandparental information from the supplied parents.\n\tinline __attribute__((always_inline)) void TrackParentage_Biparental(slim_pedigreeid_t p_pedigree_id, Individual &p_parent1, Individual &p_parent2)\n\t{\n\t\tpedigree_id_ = p_pedigree_id;\n\t\t\n\t\t// haplosome_id_ for all haplosomes should be set to (p_pedigree_id * 2) or (p_pedigree_id * 2 + 1)\n\t\t// that used to be done here, but with multiple chromosomes we do it when the haplosomes are made\n\t\t\n\t\tpedigree_p1_ = p_parent1.pedigree_id_;\n\t\tpedigree_p2_ = p_parent2.pedigree_id_;\n\t\t\n\t\tpedigree_g1_ = p_parent1.pedigree_p1_;\n\t\tpedigree_g2_ = p_parent1.pedigree_p2_;\n\t\tpedigree_g3_ = p_parent2.pedigree_p1_;\n\t\tpedigree_g4_ = p_parent2.pedigree_p2_;\n\t\t\n#pragma omp critical (ReproductiveOutput)\n\t\t{\n\t\t\tp_parent1.reproductive_output_++;\n\t\t\tp_parent2.reproductive_output_++;\n\t\t}\n\t}\n\t\n\tinline __attribute__((always_inline)) void RevokeParentage_Biparental(Individual &p_parent1, Individual &p_parent2)\n\t{\n\t\t// note this does not need to be in #pragma omp critical (ReproductiveOutput) because it never gets hit when parallel\n\t\t// that is because it only happens when modifyChild() rejects a child, and that does not happen when parallel\n\t\tp_parent1.reproductive_output_--;\n\t\tp_parent2.reproductive_output_--;\n\t}\n\t\n\tinline __attribute__((always_inline)) void TrackParentage_Uniparental(slim_pedigreeid_t p_pedigree_id, Individual &p_parent)\n\t{\n\t\tpedigree_id_ = p_pedigree_id;\n\t\t\n\t\t// haplosome_id_ for all haplosomes should be set to (p_pedigree_id * 2) or (p_pedigree_id * 2 + 1)\n\t\t// that used to be done here, but with multiple chromosomes we do it when the haplosomes are made\n\t\t\n\t\tpedigree_p1_ = p_parent.pedigree_id_;\n\t\tpedigree_p2_ = p_parent.pedigree_id_;\n\t\t\n\t\tpedigree_g1_ = p_parent.pedigree_p1_;\n\t\tpedigree_g2_ = p_parent.pedigree_p2_;\n\t\tpedigree_g3_ = p_parent.pedigree_p1_;\n\t\tpedigree_g4_ = p_parent.pedigree_p2_;\n\t\t\n#pragma omp critical (ReproductiveOutput)\n\t\t{\n\t\t\tp_parent.reproductive_output_ += 2;\n\t\t}\n\t}\n\t\n\tinline __attribute__((always_inline)) void RevokeParentage_Uniparental(Individual &p_parent)\n\t{\n\t\t// note this does not need to be in #pragma omp critical (ReproductiveOutput) because it never gets hit when parallel\n\t\t// that is because it only happens when modifyChild() rejects a child, and that does not happen when parallel\n\t\tp_parent.reproductive_output_ -= 2;\n\t}\n\t\n\t// This alternative to TrackParentage() is used when the parents are not known, as in\n\t// addEmpty() and addRecombined(); the unset ivars are set to -1 by the Individual constructor\n\tinline __attribute__((always_inline)) void TrackParentage_Parentless(slim_pedigreeid_t p_pedigree_id)\n\t{\n\t\tpedigree_id_ = p_pedigree_id;\n\t\t\n\t\t// haplosome_id_ for all haplosomes should be set to (p_pedigree_id * 2) or (p_pedigree_id * 2 + 1)\n\t\t// that used to be done here, but with multiple chromosomes we do it when the haplosomes are made\n\t}\n\t\n\tinline __attribute__((always_inline)) void RevokeParentage_Parentless()\n\t{\n\t\t// just for parallel design, no parentage to revoke\n\t}\n\t\n\t// In the new multichromosome design, the individual is created with nullptr values for its haplosomes,\n\t// and then this method is used to add each new haplosome object after it is generated\n#if DEBUG\n\tvoid AddHaplosomeAtIndex(Haplosome *p_haplosome, int p_index);\n#else\n\tinline __attribute__((always_inline)) void AddHaplosomeAtIndex(Haplosome *p_haplosome, int p_index)\n\t{\n\t\thaplosomes_[p_index] = p_haplosome;\n\t}\n#endif\n\t\n\t// Fetch specific haplosomes; used by haplosomesForChromosomes()\n\tvoid AppendHaplosomesForChromosomes(EidosValue_Object *vec, std::vector<slim_chromosome_index_t> &chromosome_indices, int64_t index, bool includeNulls);\n\t\n\t// Relatedness using pedigree data.  Most clients will use RelatednessToIndividual() and SharedParentCountWithIndividual;\n\t// _Relatedness() and _SharedParentCount() are internal API made public for unit testing.\n\tdouble RelatednessToIndividual(Individual &p_ind, ChromosomeType p_chromosome_type);\n\tstatic double _Relatedness(slim_pedigreeid_t A, slim_pedigreeid_t A_P1, slim_pedigreeid_t A_P2, slim_pedigreeid_t A_G1, slim_pedigreeid_t A_G2, slim_pedigreeid_t A_G3, slim_pedigreeid_t A_G4,\n\t\t\t\t\t\t\t   slim_pedigreeid_t B, slim_pedigreeid_t B_P1, slim_pedigreeid_t B_P2, slim_pedigreeid_t B_G1, slim_pedigreeid_t B_G2, slim_pedigreeid_t B_G3, slim_pedigreeid_t B_G4,\n\t\t\t\t\t\t\t   IndividualSex A_sex, IndividualSex B_sex, ChromosomeType p_chromosome_type);\n\t\n\tint SharedParentCountWithIndividual(Individual &p_ind);\n\tstatic int _SharedParentCount(slim_pedigreeid_t X_P1, slim_pedigreeid_t X_P2, slim_pedigreeid_t Y_P1, slim_pedigreeid_t Y_P2);\n\t\n\tinline __attribute__((always_inline)) slim_pedigreeid_t PedigreeID() const\t\t\t\t{ return pedigree_id_; }\n\tinline __attribute__((always_inline)) void SetPedigreeID(slim_pedigreeid_t p_new_id)\t{ pedigree_id_ = p_new_id; }\t// should basically never be called\n\tinline __attribute__((always_inline)) slim_pedigreeid_t Parent1PedigreeID() const\t\t{ return pedigree_p1_; }\n\tinline __attribute__((always_inline)) slim_pedigreeid_t Parent2PedigreeID() const\t\t{ return pedigree_p2_; }\n\tinline __attribute__((always_inline)) void SetParentPedigreeID(slim_pedigreeid_t p1_new_id, slim_pedigreeid_t p2_new_id)\t\t{ pedigree_p1_ = p1_new_id; pedigree_p2_ = p2_new_id; }\t// also?\n\tinline __attribute__((always_inline)) int32_t ReproductiveOutput()\t\t\t\t{ return reproductive_output_; }\n\t\n\t// Each individual reserves two consecutive nodes in the node table; these get/set the base tskit id for that 2-node block\n\tinline __attribute__((always_inline)) tsk_id_t TskitNodeIdBase(void) const { return tsk_node_id_base_; }\n\tinline __attribute__((always_inline)) void SetTskitNodeIdBase(tsk_id_t p_id) { tsk_node_id_base_ = p_id; }\n\t\n\t// Spatial position inheritance from a parent; should be called in every code path that generates an offspring from a parent\n\tinline __attribute__((always_inline)) void InheritSpatialPosition(int p_dimensionality, Individual *p_parent) {\n\t\tif (p_dimensionality > 0)\n\t\t{\n\t\t\tswitch (p_dimensionality)\n\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t\tspatial_x_ = p_parent->spatial_x_;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tspatial_x_ = p_parent->spatial_x_;\n\t\t\t\t\tspatial_y_ = p_parent->spatial_y_;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tspatial_x_ = p_parent->spatial_x_;\n\t\t\t\t\tspatial_y_ = p_parent->spatial_y_;\n\t\t\t\t\tspatial_z_ = p_parent->spatial_z_;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Individual-level output methods; used by outputIndividuals() and outputIndividualsToVCF()\n\tstatic void PrintIndividuals_SLiM(std::ostream &p_out, const Individual **p_individuals, int64_t p_individuals_count, Species &p_species, bool p_output_spatial_positions, bool p_output_ages, bool p_output_ancestral_nucs, bool p_output_pedigree_ids, bool p_output_object_tags, bool p_output_substitutions, Chromosome *p_focal_chromosome);\n\tstatic void PrintIndividuals_VCF(std::ostream &p_out, const Individual **p_individuals, int64_t p_individuals_count, Species &p_species, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs, Chromosome *p_focal_chromosome);\n\t\n\t//\n\t// Eidos support\n\t//\n\tvoid GenerateCachedEidosValue(void);\n\tinline __attribute__((always_inline)) EidosValue_SP CachedEidosValue(void) { if (!self_value_) GenerateCachedEidosValue(); return self_value_; };\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_containsMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_countOfMutationsOfType(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_haplosomesForChromosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_relatedness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_sharedParentCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_sumOfMutationsOfType(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_uniqueMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mutationsFromHaplosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_index(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_pedigreeID(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagL0(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagL1(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagL2(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagL3(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagL4(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_age(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_reproductiveOutput(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tagF(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_migrant(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_x(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_y(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_z(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_spatialPosition(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_subpopulation(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haploidGenome1(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haploidGenome1NonNull(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haploidGenome2(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haploidGenome2NonNull(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haplosomes(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_haplosomesNonNull(EidosObject **p_values, size_t p_values_size);\n\t\n\t// Accelerated property writing; see class EidosObject for comments on this mechanism\n\tstatic void SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagF(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagL0(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagL1(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagL2(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagL3(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tagL4(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic bool _SetFitnessScaling_1(double source_value, EidosObject **p_values, size_t p_values_size);\n\tstatic bool _SetFitnessScaling_N(const double *source_data, EidosObject **p_values, size_t p_values_size);\n\tstatic void SetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_x(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_y(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_z(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_age(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_color(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\t\n\t// These flags are used to minimize the work done by Subpopulation::SwapChildAndParentHaplosomes(); it only needs to\n\t// reset colors or dictionaries if they have ever been touched by the model.  These flags are set and never cleared.\n\t// BCH 5/24/2022: Note that these globals are shared across species, so if one species uses a given facility, all\n\t// species will suffer the associated speed penalty for it.  This is a bit unfortunate, but keeps the design simple.\n\tstatic bool s_any_individual_color_set_;\n\tstatic bool s_any_individual_dictionary_set_;\n\tstatic bool s_any_individual_tag_set_;\n\tstatic bool s_any_individual_tagF_set_;\n\tstatic bool s_any_individual_tagL_set_;\n\tstatic bool s_any_haplosome_tag_set_;\n\tstatic bool s_any_individual_fitness_scaling_set_;\n\t\n\t// for Subpopulation::ExecuteMethod_takeMigrants()\n\tfriend Subpopulation;\n};\n\nclass Individual_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tIndividual_Class(const Individual_Class &p_original) = delete;\t// no copy-construct\n\tIndividual_Class& operator=(const Individual_Class&) = delete;\t// no copying\n\tinline Individual_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\t\n\tvirtual EidosValue_SP ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const override;\n\tEidosValue_SP ExecuteMethod_outputIndividuals(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_outputIndividualsToVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_readIndividualsFromVCF(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_setSpatialPosition(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_zygosityOfMutations(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n};\n\n\n#endif /* defined(__SLiM__individual__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/interaction_type.cpp",
    "content": "//\n//  interaction_type.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 2/25/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"interaction_type.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"slim_eidos_block.h\"\n#include \"subpopulation.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"slim_globals.h\"\n#include \"sparse_vector.h\"\n#include \"eidos_simd.h\"\n\n#include <utility>\n#include <algorithm>\n#include <cmath>\n#include <limits>\n\n\n#pragma mark -\n#pragma mark InteractionType\n#pragma mark -\n\n// The SparseVector pool structure depends on whether we are built single-threaded or multi-threaded; see interaction_type.h\n#ifdef _OPENMP\n\nstd::vector<std::vector<SparseVector *>> InteractionType::s_freed_sparse_vectors_PERTHREAD;\n#if DEBUG\nstd::vector<int> InteractionType::s_sparse_vector_count_PERTHREAD;\n#endif\n\n#else\n\nstd::vector<SparseVector *> InteractionType::s_freed_sparse_vectors_SINGLE;\n#if DEBUG\nint InteractionType::s_sparse_vector_count_SINGLE = 0;\n#endif\n\n#endif\n\nvoid InteractionType::_WarmUp(void)\n{\n\t// Called by InteractionType_Class::InteractionType_Class() when it is created during warmup\n\tstatic bool beenHere = false;\n\t\n\tif (!beenHere) {\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"InteractionType::_WarmUp(): not warmed up\");\n\t\t\n#ifdef _OPENMP\n\t\t// set up per-thread sparse vector pools to avoid lock contention\n\t\ts_freed_sparse_vectors_PERTHREAD.resize(gEidosMaxThreads);\n\t\t#if DEBUG\n\t\ts_sparse_vector_count_PERTHREAD.resize(gEidosMaxThreads, 0);\n\t\t#endif\n#endif\n\t\t\n\t\tbeenHere = true;\n\t}\n}\n\nInteractionType::InteractionType(Community &p_community, slim_objectid_t p_interaction_type_id, std::string p_spatiality_string, bool p_reciprocal, double p_max_distance, IndividualSex p_receiver_sex, IndividualSex p_exerter_sex) :\n\tself_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('i', p_interaction_type_id)),\n\t\t\t EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_InteractionType_Class))),\n\tspatiality_string_(std::move(p_spatiality_string)), reciprocal_(p_reciprocal), max_distance_(p_max_distance), max_distance_sq_(p_max_distance * p_max_distance), if_type_(SpatialKernelType::kFixed), if_param1_(1.0), if_param2_(0.0),\n\tcommunity_(p_community), interaction_type_id_(p_interaction_type_id)\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\t// Figure out our spatiality, which is the number of spatial dimensions we actively use for distances\n\tif (spatiality_string_ == \"\")\t\t\t{ spatiality_ = 0; required_dimensionality_ = 0; }\n\telse if (spatiality_string_ == \"x\")\t\t{ spatiality_ = 1; required_dimensionality_ = 1; }\n\telse if (spatiality_string_ == \"y\")\t\t{ spatiality_ = 1; required_dimensionality_ = 2; }\n\telse if (spatiality_string_ == \"z\")\t\t{ spatiality_ = 1; required_dimensionality_ = 3; }\n\telse if (spatiality_string_ == \"xy\")\t{ spatiality_ = 2; required_dimensionality_ = 2; }\n\telse if (spatiality_string_ == \"xz\")\t{ spatiality_ = 2; required_dimensionality_ = 3; }\t\t// NOLINT(*-branch-clone) : intentional branch clone\n\telse if (spatiality_string_ == \"yz\")\t{ spatiality_ = 2; required_dimensionality_ = 3; }\n\telse if (spatiality_string_ == \"xyz\")\t{ spatiality_ = 3; required_dimensionality_ = 3; }\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::InteractionType): initializeInteractionType() spatiality '\" << spatiality_string_ << \"' must be '', 'x', 'y', 'z', 'xy', 'xz', 'yz', or 'xyz'.\" << EidosTerminate();\n\t\n\t// In the single-species case, we want to do some checks up front for backward compatibility/reproducibility;\n\t// in the multispecies case these must be deferred to evaluate() time, since they are specific to one evaluated species\n\tSpecies *single_species = (community_.is_explicit_species_ ? nullptr : community_.AllSpecies()[0]);\n\t\n\tif (single_species)\n\t\tif (required_dimensionality_ > single_species->SpatialDimensionality())\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::InteractionType): initializeInteractionType() spatiality cannot utilize spatial dimensions beyond those set in initializeSLiMOptions().\" << EidosTerminate();\n\t\n\tif (max_distance_ < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::InteractionType): initializeInteractionType() maxDistance must be >= 0.0.\" << EidosTerminate();\n\tif ((required_dimensionality_ == 0) && (!std::isinf(max_distance_) || (max_distance_ < 0.0)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::InteractionType): initializeInteractionType() maxDistance must be INF for non-spatial interactions.\" << EidosTerminate();\n\t\n\t// sex-segregation can be configured here, for historical reasons; see setConstraints() for all other constraint setting\n\tif ((p_receiver_sex != IndividualSex::kUnspecified) || (p_exerter_sex != IndividualSex::kUnspecified))\n\t{\n\t\tif (single_species && !single_species->SexEnabled())\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::InteractionType): initializeInteractionType() sexSegregation value other than '**' are unsupported in non-sexual simulations.\" << EidosTerminate();\n\t\t\n\t\tif (p_receiver_sex != IndividualSex::kUnspecified)\n\t\t{\n\t\t\treceiver_constraints_.sex_ = p_receiver_sex;\n\t\t\treceiver_constraints_.has_constraints_ = true;\n\t\t}\n\t\t\n\t\tif (p_exerter_sex != IndividualSex::kUnspecified)\n\t\t{\n\t\t\texerter_constraints_.sex_ = p_exerter_sex;\n\t\t\texerter_constraints_.has_constraints_ = true;\n\t\t}\n\t}\n\t\n\tif ((required_dimensionality_ > 0) && std::isinf(max_distance_))\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t{\n\t\t\tif (!community_.warned_no_max_distance_)\n\t\t\t{\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Community::ExecuteContextFunction_initializeInteractionType): initializeInteractionType() called to configure a spatial interaction type with no maximum distance; this may result in very poor performance.\" << std::endl;\n\t\t\t\tcommunity_.warned_no_max_distance_ = true;\n\t\t\t}\n\t\t}\n\t}\n}\n\nInteractionType::~InteractionType(void)\n{\n\tif (clipped_integral_)\n\t{\n\t\tfree(clipped_integral_);\n\t\tclipped_integral_ = nullptr;\n\t}\n}\n\nvoid InteractionType::EvaluateSubpopulation(Subpopulation *p_subpop)\n{\n\tif (p_subpop->has_been_removed_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EvaluateSubpopulation): you cannot evaluate an InteractionType for a subpopulation that has been removed.\" << EidosTerminate();\n\n\t// We evaluate for receiver and exerter subpopulations, so that all interaction evaluation state (except for\n\t// interaction() callbacks) is frozen at the same time.  Evaluate is necessary because the k-d trees are built\n\t// once and used to serve many queries, typically, and so they must be built based upon a fixed state snapshot.\n\tSpecies &species = p_subpop->species_;\n\tslim_objectid_t subpop_id = p_subpop->subpopulation_id_;\n\tslim_popsize_t subpop_size = p_subpop->parent_subpop_size_;\n\tIndividual **subpop_individuals = p_subpop->parent_individuals_.data();\n\t\n\t// Check that the subpopulation is compatible with the configuration of this interaction type\n\t// At this stage, we don't know whether it will be used as a receiver, exerter, or both\n\tCheckSpeciesCompatibility_Generic(p_subpop->species_);\n\t\n\t// Find/create a data object for this exerter\n\tauto data_iter = data_.find(subpop_id);\n\tInteractionsData *subpop_data;\n\t\n\tif (data_iter == data_.end())\n\t{\n\t\t// No entry in our map table for this subpop_id, so we need to make a new entry\n\t\tsubpop_data = &(data_.emplace(subpop_id, InteractionsData(subpop_size, p_subpop->parent_first_male_index_)).first->second);\n\t}\n\telse\n\t{\n\t\t// There is an existing entry, so we need to rehabilitate that entry by recycling its elements safely\n\t\tsubpop_data = &(data_iter->second);\n\t\t\n\t\tsubpop_data->individual_count_ = subpop_size;\n\t\tsubpop_data->first_male_index_ = p_subpop->parent_first_male_index_;\n\t\t\n\t\t// Ensure that other parts of the subpop data block are correctly reset to the same state that Invalidate()\n\t\t// uses; normally this has already been done by Initialize(), but not necessarily.\n\t\t// FIXME we could keep the positions array allocated; we would then need a flag indicating whether it's valid.\n\t\tif (subpop_data->positions_)\n\t\t{\n\t\t\tfree(subpop_data->positions_);\n\t\t\tsubpop_data->positions_ = nullptr;\n\t\t}\n\t\t\n\t\t// Free both k-d trees, keeping in mind that the two might share their memory.  FIXME we could keep the\n\t\t// k-d tree buffers around and reuse them; we would then need a flag indicating whether they're valid.\n\t\tif (subpop_data->kd_nodes_ALL_ == subpop_data->kd_nodes_EXERTERS_)\n\t\t\tsubpop_data->kd_nodes_EXERTERS_ = nullptr;\n\t\t\n\t\tif (subpop_data->kd_nodes_ALL_)\n\t\t{\n\t\t\tfree(subpop_data->kd_nodes_ALL_);\n\t\t\tsubpop_data->kd_nodes_ALL_ = nullptr;\n\t\t}\n\t\t\n\t\tif (subpop_data->kd_nodes_EXERTERS_)\n\t\t{\n\t\t\tfree(subpop_data->kd_nodes_EXERTERS_);\n\t\t\tsubpop_data->kd_nodes_EXERTERS_ = nullptr;\n\t\t}\n\t\t\n\t\tsubpop_data->kd_root_ALL_ = nullptr;\n\t\tsubpop_data->kd_node_count_ALL_ = 0;\n\t\t\n\t\tsubpop_data->kd_root_EXERTERS_ = nullptr;\n\t\tsubpop_data->kd_node_count_EXERTERS_ = 0;\n\t\t\n\t\t// Free the interaction() callbacks that were cached\n\t\tsubpop_data->evaluation_interaction_callbacks_.resize(0);\n\t}\n\t\n\t// At this point, positions_ is guaranteed to be nullptr, as are the k-d tree buffers.\n\t// Now we mark ourselves evaluated and fill in buffers as needed.\n\tsubpop_data->evaluated_ = true;\n\t\n\t// At a minimum, fetch positional data from the subpopulation; this is guaranteed to be present (for spatiality > 0)\n\tif (spatiality_ > 0)\n\t{\n\t\tdouble *positions = (double *)malloc((size_t)subpop_size * SLIM_MAX_DIMENSIONALITY * sizeof(double));\n\t\tif (!positions)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EvaluateSubpopulation): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tsubpop_data->positions_ = positions;\n\t\t\n\t\tint ind_index = 0;\n\t\tIndividual **individual = subpop_individuals;\n\t\tdouble *ind_positions = positions;\n\t\t\n\t\t// IMPORTANT: This is the only place in InteractionType's code where the spatial position of the individuals is\n\t\t// accessed.  We cache all positions here, and then use the cache everywhere else.  This means that except for\n\t\t// here, we can treat \"x\", \"y\", and \"z\" identically as 1D spatiality, \"xy\", \"xz\", and \"yz\" identically as 2D\n\t\t// spatiality, and of course \"xyz\" as 3D spatiality.  We do that by storing the cached position information in\n\t\t// the same slots regardless of which original coordinates it represents.  This also means that this is the\n\t\t// only place in the code where spatiality_string_ should be used (apart from the property accessor); everywhere\n\t\t// else, spatiality_ should suffice.  Be careful to keep following this convention, and the different spatiality\n\t\t// values will just automatically work.\n\t\tbool out_of_bounds_seen = false;\n\t\t\n\t\tif (spatiality_string_ == \"x\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(&subpop_data->periodic_x_, nullptr, nullptr);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_x1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_x_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord_bound = subpop_data->bounds_x1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord = (*individual)->spatial_x_;\n\t\t\t\t\t\n\t\t\t\t\tif ((coord < 0.0) || (coord > coord_bound))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"y\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(nullptr, &subpop_data->periodic_x_, nullptr);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_y1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_y_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord_bound = subpop_data->bounds_x1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord = (*individual)->spatial_y_;\n\t\t\t\t\t\n\t\t\t\t\tif ((coord < 0.0) || (coord > coord_bound))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"z\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(nullptr, nullptr, &subpop_data->periodic_x_);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_z1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_z_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord_bound = subpop_data->bounds_x1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord = (*individual)->spatial_z_;\n\t\t\t\t\t\n\t\t\t\t\tif ((coord < 0.0) || (coord > coord_bound))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"xy\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(&subpop_data->periodic_x_, &subpop_data->periodic_y_, nullptr);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_x1_;\n\t\t\tsubpop_data->bounds_y1_ = p_subpop->bounds_y1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_ && !subpop_data->periodic_y_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_x_;\n\t\t\t\t\tind_positions[1] = (*individual)->spatial_y_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord1_bound = subpop_data->bounds_x1_;\n\t\t\t\tdouble coord2_bound = subpop_data->bounds_y1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord1 = (*individual)->spatial_x_;\n\t\t\t\t\tdouble coord2 = (*individual)->spatial_y_;\n\t\t\t\t\t\n\t\t\t\t\tif ((subpop_data->periodic_x_ && ((coord1 < 0.0) || (coord1 > coord1_bound))) ||\n\t\t\t\t\t\t(subpop_data->periodic_y_ && ((coord2 < 0.0) || (coord2 > coord2_bound))))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord1;\n\t\t\t\t\tind_positions[1] = coord2;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"xz\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(&subpop_data->periodic_x_, nullptr, &subpop_data->periodic_y_);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_x1_;\n\t\t\tsubpop_data->bounds_y1_ = p_subpop->bounds_z1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_ && !subpop_data->periodic_y_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_x_;\n\t\t\t\t\tind_positions[1] = (*individual)->spatial_z_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord1_bound = subpop_data->bounds_x1_;\n\t\t\t\tdouble coord2_bound = subpop_data->bounds_y1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord1 = (*individual)->spatial_x_;\n\t\t\t\t\tdouble coord2 = (*individual)->spatial_z_;\n\t\t\t\t\t\n\t\t\t\t\tif ((subpop_data->periodic_x_ && ((coord1 < 0.0) || (coord1 > coord1_bound))) ||\n\t\t\t\t\t\t(subpop_data->periodic_y_ && ((coord2 < 0.0) || (coord2 > coord2_bound))))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord1;\n\t\t\t\t\tind_positions[1] = coord2;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"yz\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(nullptr, &subpop_data->periodic_x_, &subpop_data->periodic_y_);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_y1_;\n\t\t\tsubpop_data->bounds_y1_ = p_subpop->bounds_z1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_ && !subpop_data->periodic_y_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_y_;\n\t\t\t\t\tind_positions[1] = (*individual)->spatial_z_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord1_bound = subpop_data->bounds_x1_;\n\t\t\t\tdouble coord2_bound = subpop_data->bounds_y1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord1 = (*individual)->spatial_y_;\n\t\t\t\t\tdouble coord2 = (*individual)->spatial_z_;\n\t\t\t\t\t\n\t\t\t\t\tif ((subpop_data->periodic_x_ && ((coord1 < 0.0) || (coord1 > coord1_bound))) ||\n\t\t\t\t\t\t(subpop_data->periodic_y_ && ((coord2 < 0.0) || (coord2 > coord2_bound))))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord1;\n\t\t\t\t\tind_positions[1] = coord2;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"xyz\")\n\t\t{\n\t\t\tspecies.SpatialPeriodicity(&subpop_data->periodic_x_, &subpop_data->periodic_y_, &subpop_data->periodic_z_);\n\t\t\tsubpop_data->bounds_x1_ = p_subpop->bounds_x1_;\n\t\t\tsubpop_data->bounds_y1_ = p_subpop->bounds_y1_;\n\t\t\tsubpop_data->bounds_z1_ = p_subpop->bounds_z1_;\n\t\t\t\n\t\t\tif (!subpop_data->periodic_x_ && !subpop_data->periodic_y_ && !subpop_data->periodic_z_)\n\t\t\t{\n\t\t\t\t// fast loop for the non-periodic case\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tind_positions[0] = (*individual)->spatial_x_;\n\t\t\t\t\tind_positions[1] = (*individual)->spatial_y_;\n\t\t\t\t\tind_positions[2] = (*individual)->spatial_z_;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// bounds-check individual coordinates when periodic\n\t\t\t\tdouble coord1_bound = subpop_data->bounds_x1_;\n\t\t\t\tdouble coord2_bound = subpop_data->bounds_y1_;\n\t\t\t\tdouble coord3_bound = subpop_data->bounds_z1_;\n\t\t\t\t\n\t\t\t\twhile (ind_index < subpop_size)\n\t\t\t\t{\n\t\t\t\t\tdouble coord1 = (*individual)->spatial_x_;\n\t\t\t\t\tdouble coord2 = (*individual)->spatial_y_;\n\t\t\t\t\tdouble coord3 = (*individual)->spatial_z_;\n\t\t\t\t\t\n\t\t\t\t\tif ((subpop_data->periodic_x_ && ((coord1 < 0.0) || (coord1 > coord1_bound))) ||\n\t\t\t\t\t\t(subpop_data->periodic_y_ && ((coord2 < 0.0) || (coord2 > coord2_bound))) ||\n\t\t\t\t\t\t(subpop_data->periodic_z_ && ((coord3 < 0.0) || (coord3 > coord3_bound))))\n\t\t\t\t\t\tout_of_bounds_seen = true;\n\t\t\t\t\t\n\t\t\t\t\tind_positions[0] = coord1;\n\t\t\t\t\tind_positions[1] = coord2;\n\t\t\t\t\tind_positions[2] = coord3;\n\t\t\t\t\t++ind_index; ++individual; ind_positions += SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EvaluateSubpopulation): (internal error) illegal spatiality string value\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (out_of_bounds_seen)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EvaluateSubpopulation): an individual position was seen that is out of bounds for a periodic spatial dimension; positions within periodic bounds are required by InteractionType since the underlying spatial engine's integrity depends upon them.  The use of pointPeriodic() is recommended to enforce periodic boundaries.\" << EidosTerminate();\n\t}\n\t\n\t// Check that our maximum interactions distance does not violate the assumptions of periodic boundaries;\n\t// an individual cannot interact with the same individual more than once, through wrapping around.\n\tif ((subpop_data->periodic_x_ && (subpop_data->bounds_x1_ <= max_distance_ * 2.0)) ||\n\t\t(subpop_data->periodic_y_ && (subpop_data->bounds_y1_ <= max_distance_ * 2.0)) ||\n\t\t(subpop_data->periodic_z_ && (subpop_data->bounds_z1_ <= max_distance_ * 2.0)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EvaluateSubpopulation): maximum interaction distance is greater than or equal to half of the spatial extent of a periodic spatial dimension, which would allow an individual to participate in more than one interaction with a single individual.  When periodic boundaries are used, the maximum interaction distance of interaction types involving periodic dimensions must be less than half of the spatial extent of those dimensions.\" << EidosTerminate();\n\t\n\t// Cache the interaction() callbacks applicable at this moment, for the given subpopulation and this interaction type.\n\t// Note that interaction() callbacks are non-species-specific, so we fetch from the Community with species nullptr.\n\t// Callbacks used depend upon the exerter subpopulation, so this is snapping the callbacks for subpop as exerters;\n\t// the subpopulation of receivers does not influence the choice of which callbacks are used.\n\tsubpop_data->evaluation_interaction_callbacks_ = community_.ScriptBlocksMatching(community_.Tick(), SLiMEidosBlockType::SLiMEidosInteractionCallback, -1, interaction_type_id_, subpop_id, -1, nullptr);\n\t\n\t// Note that we do not create the k-d tree here.  Non-spatial models will never have a k-d tree; spatial models may or\n\t// may not need one, depending upon what methods are called by the client, which may vary cycle by cycle.\n\t// Also, receiver subpopulations need to be evaluated too, but (if used only for receivers) will not require a k-d tree.\n\t// Methods that need the k-d tree must therefore call EnsureKDTreePresent() prior to using it.\n\t\n\t// BCH 10/1/2023: For SLiM 4.1 this policy is now altered slightly.  If non-sex exerter constraints are set, we need to cache\n\t// the EXERTER k-d tree nodes here, because those constraints need to be applied to the state of individuals at snapshot\n\t// time.  We do not build the tree, just cache its nodes so it knows which individuals it contains.  This is potentially\n\t// a little bit wasteful, if a subpopulation that is evaluated is used only for receivers, not for exerters; that is\n\t// a fairly uncommon usage pattern, and the overhead of caching the nodes is pretty minimal -- O(N) to cache, versus\n\t// O(N log N) to build the tree, and the constant factor for both operations is small.\n\tif ((spatiality_ > 0) && (exerter_constraints_.has_nonsex_constraints_))\n\t{\n\t\t// There is one little hitch.  CacheKDTreeNodes() will call CheckIndividualNonSexConstraints(), and that\n\t\t// method will raise if an exerter constraint exists for a tag/tagL value but a candidate individual\n\t\t// doesn't have that tag/tagL value defined.  If the k-d tree is actually going to be used to find exerters,\n\t\t// then that raise is appropriate; an exerter has an unset tag/tagL and so the constraint cannot be applied.\n\t\t// BUT if the k-d tree is only going to be used to find receivers, or perhaps not at all, then the raise is\n\t\t// not appropriate and needs to be suppressed.  SO, here we pre-test for it, and set a flag remembering that\n\t\t// \"this subpop_data cannot be used to find exerters, because their state is non-compliant with the exerter\n\t\t// constraints\".  We check that flag in EnsureKDTreePresent_EXERTERS() and raise there, when we are certain\n\t\t// that the tree is actually being used.\n\t\tfor (int i = 0; i < subpop_size; ++i)\n\t\t{\n\t\t\tIndividual *ind = subpop_individuals[i];\n\t\t\t\n\t\t\tif (!_PrecheckIndividualNonSexConstraints(ind, exerter_constraints_))\n\t\t\t{\n\t\t\t\t// The k-d tree for this subpopulation will not get cached, because of an unset tag/tagL; if the\n\t\t\t\t// user tries to use this subpop as an exerter subpop, EnsureKDTreePresent_EXERTERS() will raise,\n\t\t\t\t// but if the user does not try to do that, there is no problem.\n\t\t\t\tsubpop_data->kd_constraints_raise_EXERTERS_ = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// OK, it's safe to proceed with caching the exerter k-d tree; nobody will raise.\n\t\tCacheKDTreeNodes(p_subpop, *subpop_data, /* p_apply_exerter_constraints */ true, &subpop_data->kd_nodes_EXERTERS_, &subpop_data->kd_root_EXERTERS_, &subpop_data->kd_node_count_EXERTERS_);\n\t}\n\t\n\t// Note that receiver constraints are evaluated at query time, not here.  This means that they are applied to the\n\t// state of the receiver at query time, whereas exerter constraints are applied to the state of the exerter at\n\t// evaluate() time.  This discrepancy is intentional and documented.  The alternative would be to go through the\n\t// subpop here, at evaluate() time, and cache receiver eligibility for the whole subpopulation.  That would be\n\t// made more complex by the fact that receivers might have undefined tag values that are needed to apply the\n\t// constraints, but - as above for exerters - the raise from that condition must be suppressed until the individual\n\t// is actually used as a receiver in a query.  Doing that would be even more complex than for exerters, and the\n\t// performance penalty would be much larger than for exerters.\n}\n\nbool InteractionType::AnyEvaluated(void)\n{\n\tfor (auto &data_iter : data_)\n\t{\n\t\tInteractionsData &data = data_iter.second;\n\t\t\n\t\tif (data.evaluated_)\n\t\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\nvoid InteractionType::_InvalidateData(InteractionsData &data)\n{\n\tdata.evaluated_ = false;\n\t\n\tif (data.positions_)\n\t{\n\t\tfree(data.positions_);\n\t\tdata.positions_ = nullptr;\n\t}\n\t\n\t// keep in mind that the two k-d trees may share their memory\n\tif (data.kd_nodes_ALL_ == data.kd_nodes_EXERTERS_)\n\t\tdata.kd_nodes_EXERTERS_ = nullptr;\n\t\n\tif (data.kd_nodes_ALL_)\n\t{\n\t\tfree(data.kd_nodes_ALL_);\n\t\tdata.kd_nodes_ALL_ = nullptr;\n\t}\n\t\n\tif (data.kd_nodes_EXERTERS_)\n\t{\n\t\tfree(data.kd_nodes_EXERTERS_);\n\t\tdata.kd_nodes_EXERTERS_ = nullptr;\n\t}\n\t\n\tdata.kd_root_ALL_ = nullptr;\n\tdata.kd_node_count_ALL_ = 0;\n\t\n\tdata.kd_root_EXERTERS_ = nullptr;\n\tdata.kd_node_count_EXERTERS_ = 0;\n\t\n\tdata.evaluation_interaction_callbacks_.resize(0);\n}\n\nvoid InteractionType::Invalidate(void)\n{\n\t// Called by SLiM when the old generation goes away; should invalidate all evaluation.  We avoid actually freeing the\n\t// big blocks if possible, though, since that can incur large overhead from madvise() – see header comments.  We do free\n\t// the positional data and the k-d tree, though, in an attempt to make fatal errors occur if somebody doesn't manage\n\t// the buffers and evaluated state correctly.  They should be smaller, and thus not trigger madvise(), anyway.\n\tfor (auto &data_iter : data_)\n\t\t_InvalidateData(data_iter.second);\n}\n\nvoid InteractionType::InvalidateForSpecies(Species *p_invalid_species)\n{\n\t// This is like Invalidate(), but invalidates only data associated with a given species\n\tfor (auto &data_iter : data_)\n\t{\n\t\tslim_objectid_t subpop_id = data_iter.first;\n\t\tSubpopulation *subpop = community_.SubpopulationWithID(subpop_id);\n\t\t\n\t\tif (subpop)\n\t\t{\n\t\t\tSpecies *species = &subpop->species_;\n\t\t\t\n\t\t\tif (species == p_invalid_species)\n\t\t\t\t_InvalidateData(data_iter.second);\n\t\t}\n\t}\n}\n\nvoid InteractionType::InvalidateForSubpopulation(Subpopulation *p_invalid_subpop)\n{\n\t// This is like Invalidate(), but invalidates only data associated with a given subpop\n\tfor (auto &data_iter : data_)\n\t{\n\t\tslim_objectid_t subpop_id = data_iter.first;\n\t\tSubpopulation *subpop = community_.SubpopulationWithID(subpop_id);\n\t\t\n\t\tif (subpop == p_invalid_subpop)\n\t\t\t_InvalidateData(data_iter.second);\n\t}\n}\n\nvoid InteractionType::CheckSpeciesCompatibility_Generic(Species &species)\n{\n\t// This checks that a given subpop (unknown whether receiver or exerter) is compatible with this interaction type\n\tif (required_dimensionality_ > species.SpatialDimensionality())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpeciesCompatibility_Generic): the exerter or receiver species has insufficient dimensionality to be used with this interaction type.\" << EidosTerminate();\n\t\n\t// For this \"generic\" case we do not check sex constraints at all.  This is useful partly when we don't know\n\t// whether the species will act as receiver or exerter, and partly when we specifically don't want to check\n\t// sex constraints, for queries like nearestNeighbors() that do not use constraints.\n}\n\nvoid InteractionType::CheckSpeciesCompatibility_Receiver(Species &species)\n{\n\t// This checks that a given receiver subpop is compatible with this interaction type\n\tif (required_dimensionality_ > species.SpatialDimensionality())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpeciesCompatibility_Receiver): the receiver species has insufficient dimensionality to be used with this interaction type.\" << EidosTerminate();\n\t\n\t// If there is a sex constraint for receivers, then the receiver species must be sexual\n\tif ((receiver_constraints_.sex_ != IndividualSex::kUnspecified) && !species.SexEnabled())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpeciesCompatibility_Receiver): a sex constraint exists for receivers, but the receiver species is non-sexual.\" << EidosTerminate();\n}\n\nvoid InteractionType::CheckSpeciesCompatibility_Exerter(Species &species)\n{\n\t// This checks that a given exerter subpop is compatible with this interaction type\n\tif (required_dimensionality_ > species.SpatialDimensionality())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpeciesCompatibility_Exerter): the exerter species has insufficient dimensionality to be used with this interaction type.\" << EidosTerminate();\n\t\n\t// If there is a sex constraint for receivers, then the receiver species must be sexual\n\tif ((exerter_constraints_.sex_ != IndividualSex::kUnspecified) && !species.SexEnabled())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpeciesCompatibility_Exerter): a sex constraint exists for exerters, but the exerter species is non-sexual.\" << EidosTerminate();\n}\n\nvoid InteractionType::CheckSpatialCompatibility(Subpopulation *receiver_subpop, Subpopulation *exerter_subpop)\n{\n\t// This checks that two subpops can legally interact with each other; it should always be guaranteed before a query is served\n\tif (receiver_subpop == exerter_subpop)\n\t\treturn;\n\t\n\t// Check for identical dimensionality\n\tint dimensionality_ex = exerter_subpop->species_.SpatialDimensionality();\n\tint dimensionality_re = receiver_subpop->species_.SpatialDimensionality();\n\t\n\tif (dimensionality_ex != dimensionality_re)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpatialCompatibility): the exerter and receiver subpopulations have different dimensionalities.\" << EidosTerminate();\n\t\n\t// Check for identical periodicity\n\tbool periodic_ex_x, periodic_ex_y, periodic_ex_z;\n\tbool periodic_re_x, periodic_re_y, periodic_re_z;\n\t\n\texerter_subpop->species_.SpatialPeriodicity(&periodic_ex_x, &periodic_ex_y, &periodic_ex_z);\n\treceiver_subpop->species_.SpatialPeriodicity(&periodic_re_x, &periodic_re_y, &periodic_re_z);\n\t\n\tif ((periodic_ex_x != periodic_re_x) || (periodic_ex_y != periodic_re_y) || (periodic_ex_z != periodic_re_z))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpatialCompatibility): the exerter and receiver subpopulations have different periodicities.\" << EidosTerminate();\n\t\n\t// Check for identical bounds, required only when the dimension in question is periodic\n\t// For non-periodic dimensions it is assumed that the bounds, even if they don't match, exist in the same coordinate system\n\tif (periodic_ex_x && ((exerter_subpop->bounds_x0_ != receiver_subpop->bounds_x0_) || (exerter_subpop->bounds_x1_ != receiver_subpop->bounds_x1_)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpatialCompatibility): the exerter and receiver subpopulations have different periodic x boundaries.\" << EidosTerminate();\n\t\n\tif (periodic_ex_y && ((exerter_subpop->bounds_y0_ != receiver_subpop->bounds_y0_) || (exerter_subpop->bounds_y1_ != receiver_subpop->bounds_y1_)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpatialCompatibility): the exerter and receiver subpopulations have different periodic y boundaries.\" << EidosTerminate();\n\t\n\tif (periodic_ex_z && ((exerter_subpop->bounds_z0_ != receiver_subpop->bounds_z0_) || (exerter_subpop->bounds_z1_ != receiver_subpop->bounds_z1_)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckSpatialCompatibility): the exerter and receiver subpopulations have different periodic z boundaries.\" << EidosTerminate();\n}\n\ndouble InteractionType::CalculateDistance(double *p_position1, double *p_position2)\n{\n#ifndef __clang_analyzer__\n\tif (spatiality_ == 1)\n\t{\n\t\treturn fabs(p_position1[0] - p_position2[0]);\n\t}\n\telse if (spatiality_ == 2)\n\t{\n\t\tdouble distance_x = (p_position1[0] - p_position2[0]);\n\t\tdouble distance_y = (p_position1[1] - p_position2[1]);\n\t\t\n\t\treturn sqrt(distance_x * distance_x + distance_y * distance_y);\n\t}\n\telse if (spatiality_ == 3)\n\t{\n\t\tdouble distance_x = (p_position1[0] - p_position2[0]);\n\t\tdouble distance_y = (p_position1[1] - p_position2[1]);\n\t\tdouble distance_z = (p_position1[2] - p_position2[2]);\n\t\t\n\t\treturn sqrt(distance_x * distance_x + distance_y * distance_y + distance_z * distance_z);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CalculateDistance): (internal error) calculation of distances requires that the interaction be spatial.\" << EidosTerminate();\n#else\n\treturn 0.0;\n#endif\n}\n\n// Calculate a distance including effects of periodicity.  This can always be called instead of\n// CalculateDistance(), it is just a little slower since it has to check the periodicity flags.\ndouble InteractionType::CalculateDistanceWithPeriodicity(double *p_position1, double *p_position2, InteractionsData &p_subpop_data)\n{\n\tif (spatiality_ == 1)\n\t{\n\t\tif (p_subpop_data.periodic_x_)\n\t\t{\n\t\t\tdouble x1 = p_position1[0], x2 = p_position2[0], d1, d2;\n\t\t\t\n\t\t\tif (x1 < x2)\t{ d1 = x2 - x1; d2 = (x1 + p_subpop_data.bounds_x1_) - x2; }\n\t\t\telse\t\t\t{ d1 = x1 - x2; d2 = (x2 + p_subpop_data.bounds_x1_) - x1; }\n\t\t\t\n\t\t\treturn std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn fabs(p_position1[0] - p_position2[0]);\n\t\t}\n\t}\n\telse if (spatiality_ == 2)\n\t{\n\t\tdouble distance_x, distance_y;\n\t\t\n\t\tif (p_subpop_data.periodic_x_)\n\t\t{\n\t\t\tdouble x1 = p_position1[0], x2 = p_position2[0], d1, d2;\n\t\t\t\n\t\t\tif (x1 < x2)\t{ d1 = x2 - x1; d2 = (x1 + p_subpop_data.bounds_x1_) - x2; }\n\t\t\telse\t\t\t{ d1 = x1 - x2; d2 = (x2 + p_subpop_data.bounds_x1_) - x1; }\n\t\t\t\n\t\t\tdistance_x = std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdistance_x = p_position1[0] - p_position2[0];\n\t\t}\n\t\t\n\t\tif (p_subpop_data.periodic_y_)\n\t\t{\n\t\t\tdouble y1 = p_position1[1], y2 = p_position2[1], d1, d2;\n\t\t\t\n\t\t\tif (y1 < y2)\t{ d1 = y2 - y1; d2 = (y1 + p_subpop_data.bounds_y1_) - y2; }\n\t\t\telse\t\t\t{ d1 = y1 - y2; d2 = (y2 + p_subpop_data.bounds_y1_) - y1; }\n\t\t\t\n\t\t\tdistance_y = std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdistance_y = p_position1[1] - p_position2[1];\n\t\t}\n\t\t\n\t\treturn sqrt(distance_x * distance_x + distance_y * distance_y);\n\t}\n\telse if (spatiality_ == 3)\n\t{\n\t\tdouble distance_x, distance_y, distance_z;\n\t\t\n\t\tif (p_subpop_data.periodic_x_)\n\t\t{\n\t\t\tdouble x1 = p_position1[0], x2 = p_position2[0], d1, d2;\n\t\t\t\n\t\t\tif (x1 < x2)\t{ d1 = x2 - x1; d2 = (x1 + p_subpop_data.bounds_x1_) - x2; }\n\t\t\telse\t\t\t{ d1 = x1 - x2; d2 = (x2 + p_subpop_data.bounds_x1_) - x1; }\n\t\t\t\n\t\t\tdistance_x = std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdistance_x = p_position1[0] - p_position2[0];\n\t\t}\n\t\t\n\t\tif (p_subpop_data.periodic_y_)\n\t\t{\n\t\t\tdouble y1 = p_position1[1], y2 = p_position2[1], d1, d2;\n\t\t\t\n\t\t\tif (y1 < y2)\t{ d1 = y2 - y1; d2 = (y1 + p_subpop_data.bounds_y1_) - y2; }\n\t\t\telse\t\t\t{ d1 = y1 - y2; d2 = (y2 + p_subpop_data.bounds_y1_) - y1; }\n\t\t\t\n\t\t\tdistance_y = std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdistance_y = p_position1[1] - p_position2[1];\n\t\t}\n\t\t\n\t\tif (p_subpop_data.periodic_z_)\n\t\t{\n\t\t\tdouble z1 = p_position1[2], z2 = p_position2[2], d1, d2;\n\t\t\t\n\t\t\tif (z1 < z2)\t{ d1 = z2 - z1; d2 = (z1 + p_subpop_data.bounds_z1_) - z2; }\n\t\t\telse\t\t\t{ d1 = z1 - z2; d2 = (z2 + p_subpop_data.bounds_z1_) - z1; }\n\t\t\t\n\t\t\tdistance_z = std::min(d1, d2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdistance_z = p_position1[2] - p_position2[2];\n\t\t}\n\t\t\n\t\treturn sqrt(distance_x * distance_x + distance_y * distance_y + distance_z * distance_z);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CalculateDistanceWithPeriodicity): (internal error) calculation of distances requires that the interaction be spatial.\" << EidosTerminate();\n}\n\ndouble InteractionType::CalculateStrengthNoCallbacks(double p_distance)\n{\n\t// CAUTION: This method should only be called when p_distance <= max_distance_ (or is NAN).\n\t// It is the caller's responsibility to do that filtering, for performance reasons!\n\t// The caller is also responsible for guaranteeing that this is not a self-interaction,\n\t// and that it is not ruled out by sex-selectivity.\n\t// SEE ALSO: Kernel::DensityForDistance(), which is parallel to this\n\tswitch (if_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t\treturn (if_param1_);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// fmax\n\t\tcase SpatialKernelType::kLinear:\n\t\t\treturn (if_param1_ * (1.0 - p_distance / max_distance_));\t\t\t\t\t\t\t\t\t// fmax * (1 − d/dmax)\n\t\tcase SpatialKernelType::kExponential:\n\t\t\treturn (if_param1_ * exp(-if_param2_ * p_distance));\t\t\t\t\t\t\t\t\t\t// fmax * exp(−λd)\n\t\tcase SpatialKernelType::kNormal:\n\t\t\treturn (if_param1_ * exp(-(p_distance * p_distance) / n_2param2sq_));\t\t\t\t\t\t// fmax * exp(−d^2/2σ^2)\n\t\tcase SpatialKernelType::kCauchy:\n\t\t{\n\t\t\tdouble temp = p_distance / if_param2_;\n\t\t\treturn (if_param1_ / (1.0 + temp * temp));\t\t\t\t\t\t\t\t\t\t\t\t\t// fmax / (1+(d/λ)^2)\n\t\t}\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t\treturn SpatialKernel::tdist(p_distance, if_param1_, if_param2_, if_param3_);\t\t\t\t// fmax / (1+(d/t)^2/n)^(−(ν+1)/2)\n\t}\n\tEIDOS_TERMINATION << \"ERROR (InteractionType::CalculateStrengthNoCallbacks): (internal error) unexpected SpatialKernelType.\" << EidosTerminate();\n}\n\ndouble InteractionType::CalculateStrengthWithCallbacks(double p_distance, Individual *p_receiver, Individual *p_exerter, std::vector<SLiMEidosBlock*> &p_interaction_callbacks)\n{\n\t// CAUTION: This method should only be called when p_distance <= max_distance_ (or is NAN).\n\t// It is the caller's responsibility to do that filtering, for performance reasons!\n\t// The caller is also responsible for guaranteeing that this is not a self-interaction,\n\t// and that it is not ruled out by sex-selectivity.\n\tdouble strength = CalculateStrengthNoCallbacks(p_distance);\n\t\n\tstrength = ApplyInteractionCallbacks(p_receiver, p_exerter, strength, p_distance, p_interaction_callbacks);\n\t\n\treturn strength;\n}\n\n// the number of grid cells along one side of the 1D/2D/3D clipped_integral_ buffer; probably best to be a power of two\n// we want to make this big enough that we don't need to interpolate; picking the closest value is within ~0.25% for 1024\n// at this size, clipped_integral_ takes 8 MB, which is quite acceptable, and the temp buffer takes about the same\nstatic const int64_t clipped_integral_size = 1024;\n\nvoid InteractionType::CacheClippedIntegral_1D(void)\n{\n\tif (clipped_integral_valid_ && clipped_integral_)\n\t\treturn;\n\t\n\tif (clipped_integral_)\n\t{\n\t\tfree(clipped_integral_);\n\t\tclipped_integral_ = nullptr;\n\t}\n\t\n\tif (!std::isfinite(max_distance_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CacheClippedIntegral_1D): clippedIntegral() requires that the maxDistance of the interaction be finite; integrals out to infinity cannot be computed numerically.\" << EidosTerminate();\n\t\n\t// First, build a temporary buffer holding interaction function values for distances from a focal individual.\n\t// This is a 1D matrix of values, with the focal individual positioned at the very end of it, sitting on\n\t// the grid position at (0, 0).  Distances used here are in [0, max_distance_], except that they are the\n\t// distance from the edge grid position (where the focal individual is) to the *center* of each cell (each value)\n\t// in the grid, so in fact the distances represent a slightly narrower range of values than [0, max_distance_].\n\tint64_t dts_quadrant = clipped_integral_size - 1;\t// -1 because this is the count of cells between grid lines\n\tdouble *distance_to_strength = (double *)calloc(dts_quadrant, sizeof(double));\n\tdouble dts_sum = 0.0;\n\t\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t{\n\t\tdouble cx = x + 0.5;\t\t\t\t\t\t\t\t\t\t// center of the interval starting at x\n\t\tdouble distance = (cx / dts_quadrant) * max_distance_;\t\t// x distance from the focal individual\n\t\t\n\t\tif (distance <= max_distance_)\t\t\t\t\t\t\t\t// if not, calloc() provides 0.0\n\t\t{\n\t\t\tdouble strength = CalculateStrengthNoCallbacks(distance);\n\t\t\t\n\t\t\tdistance_to_strength[x] = strength;\n\t\t\tdts_sum += strength;\n\t\t}\n\t}\n\t\n#if 0\n\t// debug output of distance_to_strength\n\tstd::cout << \"distance_to_strength :\" << std::endl;\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t\tprintf(\"%.6f \", distance_to_strength[x]);\n\tstd::cout << std::endl;\n#endif\n\t\n\t// Now we build clipped_integral_ itself.  It is one larger than distance_to_strength in each dimension,\n\t// providing the integral for distances (dx) from the focal individual to the nearest edge in each\n\t// dimension.  Each value in it is a sum of strengths from a linear subset of distance_to_strength:\n\t// the strengths that would be inside the spatial bounds, for the given (dx).  The value at (0)\n\t// is exactly the sum of distance_to_strength, representing the integral for an individual that is\n\t// positioned at the edge of the space.  At (clipped_integral_size - 1) is the value for an individual\n\t// exactly (max_distance_), or further, from the nearest edge; it is 2x the sum of the entirety of\n\t// distance_to_strength.  Note that clipped_integral_ is dts_quadrant+1 values in length, because each\n\t// value of clipped_integral_ is conceptually positioned at the *grid position* between the intervals\n\t// of distance_to_strength; its values represent focal individual positions, which fall on the grid\n\t// positions of distance_to_strength.\n\tclipped_integral_ = (double *)calloc(clipped_integral_size, sizeof(double));\n\t\n\t// fill the first row/column so we have previously computed values to work with below\n\tclipped_integral_[0] = dts_sum;\n\t\n\tfor (int64_t x = 1; x < clipped_integral_size; ++x)\n\t{\n\t\t// start with a previously computed value\n\t\tdouble integral = clipped_integral_[x - 1];\n\t\t\n\t\t// add the next value\n\t\tintegral += distance_to_strength[x - 1];\n\t\t\n\t\tclipped_integral_[x] = integral;\n\t}\n\t\n#if 0\n\t// debug output of clipped_integral_\n\tstd::cout << \"clipped_integral_ (point 1) :\" << std::endl;\n\tfor (int64_t x = 0; x < clipped_integral_size; ++x)\n\t\tprintf(\"%.6f \", clipped_integral_[x]);\n\tstd::cout << std::endl;\n#endif\n\t\n\t// rescale clipped_integral_ by the size of each grid cell: of the area covered by the grid\n\t// (max_distance_ x max_distance_), the subarea comprised by one cell (1/dts_quadrant^2) of that\n\t// we do this as a post-pass mostly for debugging purposes, so that the steps above can be\n\t// verified to be working correctly in themselves before complicating matters by rescaling\n\tint64_t grid_count = clipped_integral_size;\n\tdouble normalization = (1.0 / dts_quadrant) * max_distance_;\n\t\n\tfor (int64_t index = 0; index < grid_count; ++index)\n\t\tclipped_integral_[index] *= normalization;\n\t\n#if 0\n\t// debug output of clipped_integral_\n\tstd::cout << \"clipped_integral_ (point 2) :\" << std::endl;\n\tfor (int64_t x = 0; x < clipped_integral_size; ++x)\n\t\tprintf(\"%.6f \", clipped_integral_[x]);\n\tstd::cout << std::endl;\n#endif\n\t\n\tfree(distance_to_strength);\n\t\n\tclipped_integral_valid_ = true;\n}\n\nvoid InteractionType::CacheClippedIntegral_2D(void)\n{\n\tif (clipped_integral_valid_ && clipped_integral_)\n\t\treturn;\n\t\n\t//double start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC, end_time;\n\t\n\tif (clipped_integral_)\n\t{\n\t\tfree(clipped_integral_);\n\t\tclipped_integral_ = nullptr;\n\t}\n\t\n\tif (!std::isfinite(max_distance_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CacheClippedIntegral_2D): clippedIntegral() requires that the maxDistance of the interaction be finite; integrals out to infinity cannot be computed numerically.\" << EidosTerminate();\n\t\n\t// First, build a temporary buffer holding interaction function values for distances from a focal individual.\n\t// This is a 2D matrix of values, with the focal individual positioned at the very corner of it, sitting on\n\t// the grid lines that form the outside corner around the value at (0, 0).  Distances used here are in\n\t// [0, max_distance_], except that they are the distance from the corner grid intersection (where the focal\n\t// individual is) to the *center* of each cell (each value) in the grid, so in fact the distances represent\n\t// a slightly narrower range of values than [0, max_distance_].\n\tint64_t dts_quadrant = clipped_integral_size - 1;\t// -1 because this is the count of cells between grid lines\n\tdouble *distance_to_strength = (double *)calloc(dts_quadrant * dts_quadrant, sizeof(double));\n\t\n\t//std::cout << \"distance_to_strength size == \" << ((dts_quadrant * dts_quadrant * sizeof(double)) / (1024.0 * 1024.0)) << \"MB\" << std::endl << std::endl;\n\t\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t{\n\t\tfor (int64_t y = x; y < dts_quadrant; ++y)\n\t\t{\n\t\t\tdouble cx = x + 0.5, cy = y + 0.5;\t\t\t\t\t\t\t// center of the grid cell (x, y)\n\t\t\tdouble dx = (cx / dts_quadrant) * max_distance_;\t\t\t// x distance from the focal individual\n\t\t\tdouble dy = (cy / dts_quadrant) * max_distance_;\t\t\t// y distance from the focal individual\n\t\t\tdouble distance = sqrt(dx * dx + dy * dy);\t\t\t\t\t// distance from the focal individual\n\t\t\t\n\t\t\tif (distance <= max_distance_)\t\t\t\t\t\t\t\t// if not, calloc() provides 0.0\n\t\t\t{\n\t\t\t\tdouble strength = CalculateStrengthNoCallbacks(distance);\n\t\t\t\t\n\t\t\t\tdistance_to_strength[x + y * dts_quadrant] = strength;\n\t\t\t\tdistance_to_strength[y + x * dts_quadrant] = strength;\n\t\t\t}\n\t\t}\n\t}\n\t\n#if 0\n\t// debug output of distance_to_strength\n\tstd::cout << \"distance_to_strength :\" << std::endl;\n\tfor (int64_t y = 0; y < dts_quadrant; ++y)\n\t{\n\t\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t\t{\n\t\t\tprintf(\"%.6f \", distance_to_strength[x + y * dts_quadrant]);\n\t\t}\n\t\tstd::cout << std::endl;\n\t}\n\tstd::cout << std::endl;\n#endif\n\t\n\t// Now do preparatory summations to get a vector of cumulative column sums across distance_to_strength.\n\t// The first element of this vector is the sum of values from the first column of distance_to_strength.\n\t// The second element of this vector is that, *plus* the sum of the second column.  And so forth, such\n\t// that the last element of this vector of the sum of the entirety of distance_to_strength.  This will\n\t// allow us to work more efficiently below.  Since building clipped_integral_ the brute force way is\n\t// an O(N^4) algorithm (NxN values, each a sum of NxN values from distance_to_strength), this kind of\n\t// work will be important if we try to build a large clipped_integral_ buffer.\n\tdouble *dts_cumsums = (double *)malloc(dts_quadrant * sizeof(double));\n\tdouble *dts_colsums = (double *)malloc(dts_quadrant * sizeof(double));\n\tdouble total = 0.0;\n\t\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t{\n\t\tdouble colsum = 0.0;\n\t\t\n\t\tfor (int64_t y = 0; y < dts_quadrant; ++y)\n\t\t\tcolsum += distance_to_strength[x + y * dts_quadrant];\n\t\t\n\t\tdts_colsums[x] = colsum;\n\t\t\n\t\ttotal += colsum;\n\t\tdts_cumsums[x] = total;\n\t}\n\t\n#if 0\n\t// debug output of dts_colsums\n\tstd::cout << \"dts_colsums :\" << std::endl;\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t\tprintf(\"%.6f \", dts_colsums[x]);\n\tstd::cout << std::endl << std::endl;\n\t\n\t// debug output of dts_cumsums\n\tstd::cout << \"dts_cumsums :\" << std::endl;\n\tfor (int64_t x = 0; x < dts_quadrant; ++x)\n\t\tprintf(\"%.6f \", dts_cumsums[x]);\n\tstd::cout << std::endl << std::endl;\n#endif\n\t\n\t// Now we build clipped_integral_ itself.  It is one larger than distance_to_strength in each dimension,\n\t// providing the integral for distances (dx, dy) from the focal individual to the nearest edge in each\n\t// dimension.  Each value in it is a sum of strengths from a rectangular subset of distance_to_strength:\n\t// the strengths that would be inside the spatial bounds, for the given (dx, dy).  The value at (0, 0)\n\t// is exactly the sum of distance_to_strength, representing the integral for an individual that is\n\t// positioned at the corner of the space.  At (clipped_integral_size - 1, clipped_integral_size - 1) is\n\t// the value for an individual exactly (max_distance_, max_distance_), or further, from the nearest\n\t// corner; it is 4x the sum of the entirety of distance_to_strength.  Each side of clipped_integral_ is\n\t// dts_quadrant+1 values in length, because each value of clipped_integral_ is conceptually positioned\n\t// at the *intersection of grid lines* between the cells of distance_to_strength; its values represent\n\t// focal individual positions, which fall on the grid lines of distance_to_strength.\n\tclipped_integral_ = (double *)calloc(clipped_integral_size * clipped_integral_size, sizeof(double));\n\t\n\t//std::cout << \"clipped_integral_ size == \" << ((clipped_integral_size * clipped_integral_size * sizeof(double)) / (1024.0 * 1024.0)) << \"MB\" << std::endl << std::endl;\n\t\n\t// fill the first row/column so we have previously computed values to work with below\n\tfor (int64_t x = 0; x < clipped_integral_size; ++x)\n\t{\n\t\tdouble integral = dts_cumsums[dts_quadrant - 1];\t// full quadrant\n\t\t\n\t\tif (x > 0)\n\t\t\tintegral += dts_cumsums[x - 1];\t\t\t\t\t// additional columns\n\t\t\n\t\tclipped_integral_[x + 0 * clipped_integral_size] = integral;\n\t\tclipped_integral_[0 + x * clipped_integral_size] = integral;\n\t}\n\t\n\tfor (int64_t y = 1; y < clipped_integral_size; ++y)\n\t{\n\t\t// start with a previously computed value\n\t\tdouble integral = clipped_integral_[y + (y - 1) * clipped_integral_size];\n\t\t\n\t\t// add in previous values in the same row in this quadrant\n\t\tfor (int64_t x = 1; x < y; ++x)\n\t\t\tintegral += distance_to_strength[(x - 1) + (y - 1) * dts_quadrant];\n\t\t\n\t\t// now fill new values in this row\n\t\tfor (int64_t x = y; x < clipped_integral_size; ++x)\n\t\t{\n\t\t\t// add in the full row in the other quadrant\n\t\t\tintegral += dts_colsums[x - 1];\n\t\t\t\n\t\t\t// add in previous values in the same column in this quadrant; when x==y these were already in the previously computed value\n\t\t\tif (x > y)\n\t\t\t{\n\t\t\t\tfor (int64_t yr = 1; yr < y; ++yr)\n\t\t\t\t\tintegral += distance_to_strength[(x - 1) + (yr - 1) * dts_quadrant];\n\t\t\t}\n\t\t\t\n\t\t\t// add in the one new value for this new column in this row\n\t\t\tintegral += distance_to_strength[(x - 1) + (y - 1) * dts_quadrant];\n\t\t\t\n\t\t\tclipped_integral_[x + y * clipped_integral_size] = integral;\n\t\t\tclipped_integral_[y + x * clipped_integral_size] = integral;\n\t\t}\n\t}\n\t\n#if 0\n\t// debug output of clipped_integral_\n\tstd::cout << \"clipped_integral_ (point 1) :\" << std::endl;\n\tfor (int64_t y = 0; y < clipped_integral_size; ++y)\n\t{\n\t\tfor (int64_t x = 0; x < clipped_integral_size; ++x)\n\t\t{\n\t\t\tprintf(\"%.6f \", clipped_integral_[x + y * clipped_integral_size]);\n\t\t}\n\t\tstd::cout << std::endl;\n\t}\n\tstd::cout << std::endl;\n#endif\n\t\n\t// rescale clipped_integral_ by the size of each grid cell: of the area covered by the grid\n\t// (max_distance_ x max_distance_), the subarea comprised by one cell (1/dts_quadrant^2) of that\n\t// we do this as a post-pass mostly for debugging purposes, so that the steps above can be\n\t// verified to be working correctly in themselves before complicating matters by rescaling\n\tint64_t grid_count = clipped_integral_size * clipped_integral_size;\n\tdouble normalization = (1.0 / (dts_quadrant * dts_quadrant)) * (max_distance_ * max_distance_);\n\t\n\tfor (int64_t index = 0; index < grid_count; ++index)\n\t\tclipped_integral_[index] *= normalization;\n\t\n#if 0\n\t// debug output of clipped_integral_\n\tstd::cout << \"clipped_integral_ (point 2) :\" << std::endl;\n\tfor (int64_t y = 0; y < clipped_integral_size; ++y)\n\t{\n\t\tfor (int64_t x = 0; x < clipped_integral_size; ++x)\n\t\t{\n\t\t\tprintf(\"%.6f \", clipped_integral_[x + y * clipped_integral_size]);\n\t\t}\n\t\tstd::cout << std::endl;\n\t}\n\tstd::cout << std::endl;\n#endif\n\t\n\tfree(distance_to_strength);\n\tfree(dts_cumsums);\n\tfree(dts_colsums);\n\t\n\tclipped_integral_valid_ = true;\n\t\n\t// for 1024x1024 this takes ~0.5 seconds, so ouch, but it generally only needs to be done once\n\t// note that the step commented \"Now we build clipped_integral_ itself\" is where 90% of the time here is spent\n\t//end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t//std::cout << \"InteractionType::CacheClippedIntegral_2D() time == \" << (end_time - start_time) << std::endl;\n}\n\ndouble InteractionType::ClippedIntegral_1D(double indDistanceA1, double indDistanceA2, bool periodic_x)\n{\n\tif (periodic_x)\n\t{\n\t\tindDistanceA1 = max_distance_;\n\t\tindDistanceA2 = max_distance_;\n\t}\n\t\n\tif ((indDistanceA1 < max_distance_) && (indDistanceA2 < max_distance_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ClippedIntegral_1D): clippedIntegral() requires that the maximum interaction distance be less than half of the spatial bounds extent, for non-periodic boundaries, such that the interaction function cannot be clipped on both sides.\" << EidosTerminate();\n\t\n\tdouble indDistanceA = std::min(std::min(indDistanceA1, indDistanceA2), max_distance_) / max_distance_;\n\t\n\tif (indDistanceA < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ClippedIntegral_1D): clippedIntegral() requires that receivers lie within the spatial bounds of their subpopulation.\" << EidosTerminate();\n\t\n\tint coordA = (int)round(indDistanceA * (clipped_integral_size - 1));\n\t\n\t//std::cout << \"indDistanceA == \" << indDistanceA << \" : coordA == \" << coordA << \" : \" << clipped_integral_[coordA] << std::endl;\n\t\n\treturn clipped_integral_[coordA];\n}\n\ndouble InteractionType::ClippedIntegral_2D(double indDistanceA1, double indDistanceA2, double indDistanceB1, double indDistanceB2, bool periodic_x, bool periodic_y)\n{\n\tif (periodic_x)\n\t{\n\t\tindDistanceA1 = max_distance_;\n\t\tindDistanceA2 = max_distance_;\n\t}\n\tif (periodic_y)\n\t{\n\t\tindDistanceB1 = max_distance_;\n\t\tindDistanceB2 = max_distance_;\n\t}\n\t\n\tif (((indDistanceA1 < max_distance_) && (indDistanceA2 < max_distance_)) || ((indDistanceB1 < max_distance_) && (indDistanceB2 < max_distance_)))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ClippedIntegral_2D): clippedIntegral() requires that the maximum interaction distance be less than half of the spatial bounds extent, for non-periodic boundaries, such that the interaction function cannot be clipped on both sides.\" << EidosTerminate();\n\t\n\tdouble indDistanceA = std::min(std::min(indDistanceA1, indDistanceA2), max_distance_) / max_distance_;\n\tdouble indDistanceB = std::min(std::min(indDistanceB1, indDistanceB2), max_distance_) / max_distance_;\n\t\n\tif ((indDistanceA < 0.0) || (indDistanceB < 0.0))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ClippedIntegral_2D): clippedIntegral() requires that receivers lie within the spatial bounds of their subpopulation.\" << EidosTerminate();\n\t\n\tint coordA = (int)round(indDistanceA * (clipped_integral_size - 1));\n\tint coordB = (int)round(indDistanceB * (clipped_integral_size - 1));\n\t\n\t//std::cout << \"indDistanceA == \" << indDistanceA << \", indDistanceB == \" << indDistanceB << \" : coordA == \" << coordA << \", coordB == \" << coordB << \" : \" << clipped_integral_[coordA + coordB * clipped_integral_size] << std::endl;\n\t\n\treturn clipped_integral_[coordA + coordB * clipped_integral_size];\n}\n\ndouble InteractionType::ApplyInteractionCallbacks(Individual *p_receiver, Individual *p_exerter, double p_strength, double p_distance, std::vector<SLiMEidosBlock*> &p_interaction_callbacks)\n{\n\t// This uses THREAD_SAFETY_IN_ACTIVE_PARALLEL() instead of THREAD_SAFETY_IN_ANY_PARALLEL() because it does get\n\t// called from inactive (i.e., 1-thread) parallel regions, so that we don't have to special-case code paths\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"InteractionType::ApplyInteractionCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosInteractionCallback;\n\t\n\tfor (SLiMEidosBlock *interaction_callback : p_interaction_callbacks)\n\t{\n\t\tif (interaction_callback->block_active_)\n\t\t{\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = interaction_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG interaction(i\" << interaction_callback->interaction_type_id_;\n\t\t\t\t\tif (interaction_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \", p\" << interaction_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (interaction_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << interaction_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// The callback is active and matches our interaction type id, so we need to execute it\n\t\t\tconst EidosASTNode *compound_statement_node = interaction_callback->compound_statement_node_;\n\t\t\t\n\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t{\n\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\", so we can short-circuit it completely\n\t\t\t\tEidosValue *result = compound_statement_node->cached_return_value_.get();\n\t\t\t\t\n\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ApplyInteractionCallbacks): interaction() callbacks must provide a float singleton return value.\" << EidosTerminate(interaction_callback->identifier_token_);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// this checks the value type at runtime\n\t\t\t\tp_strength = result->FloatData()[0];\n#else\n\t\t\t\t// unsafe cast for speed\n\t\t\t\tp_strength = ((EidosValue_Float *)result)->data()[0];\n#endif\n\t\t\t\t\n\t\t\t\t// the cached value is owned by the tree, so we do not dispose of it\n\t\t\t\t// there is also no script output to handle\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// local variables for the callback parameters that we might need to allocate here, and thus need to free below\n\t\t\t\tEidosValue_Float local_distance(p_distance);\n\t\t\t\tEidosValue_Float local_strength(p_strength);\n\t\t\t\t\n\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t{\n\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\tEidosInterpreter interpreter(interaction_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (interaction_callback->contains_self_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(interaction_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\n\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\tif (interaction_callback->contains_distance_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_distance.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_distance, EidosValue_SP(&local_distance));\n\t\t\t\t\t}\n\t\t\t\t\tif (interaction_callback->contains_strength_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_strength.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_strength, EidosValue_SP(&local_strength));\n\t\t\t\t\t}\n\t\t\t\t\tif (interaction_callback->contains_receiver_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_receiver, p_receiver->CachedEidosValue());\n\t\t\t\t\tif (interaction_callback->contains_exerter_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_exerter, p_exerter->CachedEidosValue());\n\t\t\t\t\t\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton double used as a new fitness value\n\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(interaction_callback->script_);\n\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ApplyInteractionCallbacks): interaction() callbacks must provide a float singleton return value.\" << EidosTerminate(interaction_callback->identifier_token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\tp_strength = result->FloatData()[0];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (std::isnan(p_strength) || std::isinf(p_strength) || (p_strength < 0.0))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ApplyInteractionCallbacks): interaction() callbacks must return a finite value >= 0.0.\" << EidosTerminate(interaction_callback->identifier_token_);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosInteractionCallback)]);\n#endif\n\t\n\treturn p_strength;\n}\n\nsize_t InteractionType::MemoryUsageForKDTrees(void)\n{\n\tsize_t usage = 0;\n\t\n\t// this may be an underestimate, since we overallocate in some cases (exerter constraints)\n\tfor (auto &iter : data_)\n\t{\n\t\tconst InteractionsData &data = iter.second;\n\t\tusage += sizeof(SLiM_kdNode) * data.kd_node_count_ALL_;\n\t\tusage += sizeof(SLiM_kdNode) * data.kd_node_count_EXERTERS_;\n\t}\n\t\n\treturn usage;\n}\n\nsize_t InteractionType::MemoryUsageForPositions(void)\n{\n\tsize_t usage = 0;\n\t\n\tfor (auto &iter : data_)\n\t{\n\t\tconst InteractionsData &data = iter.second;\n\t\tusage += sizeof(double) * data.individual_count_;\n\t}\n\t\n\treturn usage;\n}\n\nsize_t InteractionType::MemoryUsageForSparseVectorPool(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"InteractionType::MemoryUsageForSparseVectorPool(): s_freed_sparse_vectors_\");\n\t\n\tsize_t usage = 0;\n\t\n#ifdef _OPENMP\n\t// When running multithreaded, count all pools\n\tfor (auto &pool : s_freed_sparse_vectors_PERTHREAD)\n\t{\n\t\tusage += sizeof(std::vector<SparseVector *>);\n\t\tusage += pool.size() * sizeof(SparseVector);\n\t\t\n\t\tfor (SparseVector *free_sv : pool)\n\t\t\tusage += free_sv->MemoryUsage();\n\t}\n#else\n\tusage = s_freed_sparse_vectors_SINGLE.size() * sizeof(SparseVector);\n\t\n\tfor (SparseVector *free_sv : s_freed_sparse_vectors_SINGLE)\n\t\tusage += free_sv->MemoryUsage();\n#endif\n\t\n\treturn usage;\n}\n\n\n#pragma mark -\n#pragma mark k-d tree construction\n#pragma mark -\n\n// This k-d tree code is patterned after the C code at RosettaCode.org : https://rosettacode.org/wiki/K-d_tree#C\n// It uses a Quickselect-style algorithm to select medians to produce a balanced tree\n// Each spatiality case is coded separately, for maximum speed, but they are very parallel\n\n// Some of the code below is separated by phase.  The k-d tree cycles through phase (x, y, z) as you descend,\n// and rather than passing phase as a parameter, the code has been factored into phase-specific functions\n// that are mutually recursive, for speed.  It's not a huge win, but it does help a little.\n\n// BCH 14 August 2017: NOTE that I have found that the RosettaCode.org C example code was incorrect, which\n// is disappointing.  It tried to check for duplicates of the median and terminate early, but its logic for\n// doing so was flawed and resulted in a bad tree that produced incorrect results.  This code now follows\n// the logic of the pseudocode at Wikipedia (https://en.wikipedia.org/wiki/Quickselect), which seems correct.\n// Ironically, the incorrect logic of the RosettaCode version only produced incorrect results when there\n// were duplicated values in the coordinate vector.\n\ninline __attribute__((always_inline)) void swap(SLiM_kdNode *p_x, SLiM_kdNode *p_y) noexcept\n{\n\tstd::swap(p_x->x, p_y->x);\n\tstd::swap(p_x->individual_index_, p_y->individual_index_);\n}\n\n// find median for phase 0 (x)\nSLiM_kdNode *InteractionType::FindMedian_p0(SLiM_kdNode *start, SLiM_kdNode *end)\n{\n\t// BCH 12/11/2022: This used to use Quickselect, but we encounterested issues with this hitting\n\t// its O(n^2) worst case.  Now we use the STL std::nth_element(), which seems to do better.\n\tSLiM_kdNode *mid = start + (end - start) / 2;\n\tstd::nth_element(start, mid, end, [](const SLiM_kdNode &i1, const SLiM_kdNode &i2) { return i1.x[0] < i2.x[0]; });\n\treturn mid;\n}\n\n// find median for phase 1 (y)\nSLiM_kdNode *InteractionType::FindMedian_p1(SLiM_kdNode *start, SLiM_kdNode *end)\n{\n\t// BCH 12/11/2022: This used to use Quickselect, but we encounterested issues with this hitting\n\t// its O(n^2) worst case.  Now we use the STL std::nth_element(), which seems to do better.\n\tSLiM_kdNode *mid = start + (end - start) / 2;\n\tstd::nth_element(start, mid, end, [](const SLiM_kdNode &i1, const SLiM_kdNode &i2) { return i1.x[1] < i2.x[1]; });\n\treturn mid;\n}\n\n// find median for phase 2 (z)\nSLiM_kdNode *InteractionType::FindMedian_p2(SLiM_kdNode *start, SLiM_kdNode *end)\n{\n\t// BCH 12/11/2022: This used to use Quickselect, but we encounterested issues with this hitting\n\t// its O(n^2) worst case.  Now we use the STL std::nth_element(), which seems to do better.\n\tSLiM_kdNode *mid = start + (end - start) / 2;\n\tstd::nth_element(start, mid, end, [](const SLiM_kdNode &i1, const SLiM_kdNode &i2) { return i1.x[2] < i2.x[2]; });\n\treturn mid;\n}\n\n// make k-d tree recursively for the 1D case for phase 0 (x)\nSLiM_kdNode *InteractionType::MakeKDTree1_p0(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p0(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree1_p0(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree1_p0(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\n// make k-d tree recursively for the 2D case for phase 0 (x)\nSLiM_kdNode *InteractionType::MakeKDTree2_p0(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p0(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree2_p1(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree2_p1(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\n// make k-d tree recursively for the 2D case for phase 1 (y)\nSLiM_kdNode *InteractionType::MakeKDTree2_p1(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p1(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree2_p0(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree2_p0(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\n// make k-d tree recursively for the 3D case for phase 0 (x)\nSLiM_kdNode *InteractionType::MakeKDTree3_p0(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p0(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree3_p1(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree3_p1(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\n// make k-d tree recursively for the 3D case for phase 1 (y)\nSLiM_kdNode *InteractionType::MakeKDTree3_p1(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p1(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree3_p2(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree3_p2(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\n// make k-d tree recursively for the 3D case for phase 2 (z)\nSLiM_kdNode *InteractionType::MakeKDTree3_p2(SLiM_kdNode *t, int len)\n{\n\tSLiM_kdNode *n = ((len == 1) ? t : FindMedian_p2(t, t + len));\n\t\n\tif (n)\n\t{\n\t\tint left_len = (int)(n - t);\n\t\tn->left  = (left_len ? MakeKDTree3_p0(t, left_len) : 0);\n\t\t\n\t\tint right_len = (int)(t + len - (n + 1));\n\t\tn->right = (right_len ? MakeKDTree3_p0(n + 1, right_len) : 0);\n\t}\n\treturn n;\n}\n\nvoid InteractionType::CacheKDTreeNodes(Subpopulation *subpop, InteractionsData &p_subpop_data, bool p_apply_exerter_constraints, SLiM_kdNode **kd_nodes_ptr, SLiM_kdNode **kd_root_ptr, slim_popsize_t *kd_node_count_ptr)\n{\n\tIndividual **subpop_individuals = subpop->parent_individuals_.data();\n\tint individual_count = p_subpop_data.individual_count_;\n\tint first_individual_index, last_individual_index;\n\t\n\t// Calculate modified indices into the population, based on exerter sex-specificity.  This lets us skip over\n\t// individuals that are disqualified by the exerter sex-specificity constraints without even looking at them.\n\tif (p_apply_exerter_constraints && (exerter_constraints_.sex_ == IndividualSex::kMale))\n\t{\n\t\tfirst_individual_index = p_subpop_data.first_male_index_;\n\t\tlast_individual_index = individual_count - 1;\n\t}\n\telse if (p_apply_exerter_constraints && (exerter_constraints_.sex_ == IndividualSex::kFemale))\n\t{\n\t\tfirst_individual_index = 0;\n\t\tlast_individual_index = p_subpop_data.first_male_index_ - 1;\n\t}\n\telse\n\t{\n\t\tfirst_individual_index = 0;\n\t\tlast_individual_index = individual_count - 1;\n\t}\n\t\n\t// Allocate the chosen number of nodes\n\tint max_node_count = last_individual_index - first_individual_index + 1;\n\tSLiM_kdNode *nodes = (SLiM_kdNode *)calloc(max_node_count, sizeof(SLiM_kdNode));\n\tif (!nodes)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CacheKDTreeNodes): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t// Fill the nodes with their initial data; start assuming the non-periodic base case, split into spatiality cases for speed\n\tint actual_node_count = 0;\n\t\n\tswitch (spatiality_)\n\t{\n\t\tcase 1:\n\t\t\tif (p_apply_exerter_constraints && exerter_constraints_.has_nonsex_constraints_)\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = subpop_individuals[i];\n\t\t\t\t\t\n\t\t\t\t\tif (CheckIndividualNonSexConstraints(ind, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\t\n\t\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\t\tactual_node_count++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\n\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\tactual_node_count++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tif (p_apply_exerter_constraints && exerter_constraints_.has_nonsex_constraints_)\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = subpop_individuals[i];\n\t\t\t\t\t\n\t\t\t\t\tif (CheckIndividualNonSexConstraints(ind, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\t\n\t\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\t\tnode->x[1] = position_data[1];\n\t\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\t\tactual_node_count++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\n\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\tnode->x[1] = position_data[1];\n\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\tactual_node_count++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tif (p_apply_exerter_constraints && exerter_constraints_.has_nonsex_constraints_)\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = subpop_individuals[i];\n\t\t\t\t\t\n\t\t\t\t\tif (CheckIndividualNonSexConstraints(ind, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\t\n\t\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\t\tnode->x[1] = position_data[1];\n\t\t\t\t\t\tnode->x[2] = position_data[2];\n\t\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\t\tactual_node_count++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int i = first_individual_index; i <= last_individual_index; ++i)\n\t\t\t\t{\n\t\t\t\t\tSLiM_kdNode *node = nodes + actual_node_count;\n\t\t\t\t\tdouble *position_data = p_subpop_data.positions_ + (size_t)i * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\t\n\t\t\t\t\tnode->x[0] = position_data[0];\n\t\t\t\t\tnode->x[1] = position_data[1];\n\t\t\t\t\tnode->x[2] = position_data[2];\n\t\t\t\t\tnode->individual_index_ = i;\n\t\t\t\t\tactual_node_count++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::CacheKDTreeNodes): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Note that replication of nodes for the periodic case is done in BuildKDTree(),\n\t// to save work when the k-d tree is not actually used for exerters\n\t\n\t// Write out the final constructed k-d tree to our parameters\n\t*kd_nodes_ptr = nodes;\n\t*kd_root_ptr = nullptr;\n\t*kd_node_count_ptr = actual_node_count;\n}\n\nvoid InteractionType::BuildKDTree(InteractionsData &p_subpop_data, SLiM_kdNode **kd_nodes_ptr, SLiM_kdNode **kd_root_ptr, slim_popsize_t *kd_node_count_ptr)\n{\n\t// If we have any periodic dimensions, we need to replicate our nodes spatially\n\t// Note that exerter constraints have already been applied\n\tint periodicity_multiplier = (p_subpop_data.periodic_x_ ? 3 : 1) * (p_subpop_data.periodic_y_ ? 3 : 1) * (p_subpop_data.periodic_z_ ? 3 : 1);\n\t\n\tif (periodicity_multiplier > 1)\n\t{\n\t\tSLiM_kdNode *nodes = *kd_nodes_ptr;\n\t\tint actual_node_count = *kd_node_count_ptr;\n\t\tint max_node_count = actual_node_count * periodicity_multiplier;\n\t\t\n\t\tnodes = (SLiM_kdNode *)realloc(nodes, max_node_count * sizeof(SLiM_kdNode));\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\tif (!nodes)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::BuildKDTree): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// We want periodicity_multiplier replicates; 3 or 9 or 27.  The central replicate is the base replicate, which we have\n\t\t// already created at replicate index 0 in the nodes buffer.  So we want to make the remaining replicates at the remaining\n\t\t// indices.  Each replicate gets offsets from the base position; to make that work easily, we calculate a modified index\n\t\t// that places the base replicate at the center of the buffer (even though it is really at position 0).\n\t\tint replicate_index_of_center = periodicity_multiplier / 2;\t\t// rounds down to nearest integer; 3 -> 1, 9 -> 4, 27 -> 13\n\t\t\n\t\tfor (int replicate = 1; replicate < periodicity_multiplier; ++replicate)\n\t\t{\n\t\t\tint replicate_quadrant_index = (replicate <= replicate_index_of_center) ? (replicate - 1) : replicate;\n\t\t\tSLiM_kdNode *replicate_nodes = nodes + (size_t)replicate * actual_node_count;\n\t\t\tdouble x_offset = 0, y_offset = 0, z_offset = 0;\n\t\t\t\n\t\t\t// Determine the correct offsets for this replicate of the individual position data;\n\t\t\t// maybe there is a smarter way to do this, but whatever\n\t\t\tint replication_dim_1 = (replicate_quadrant_index % 3) - 1;\n\t\t\tint replication_dim_2 = ((replicate_quadrant_index / 3) % 3) - 1;\n\t\t\tint replication_dim_3 = (replicate_quadrant_index / 9) - 1;\n\t\t\t\n\t\t\tif (p_subpop_data.periodic_x_)\n\t\t\t{\n\t\t\t\tx_offset = p_subpop_data.bounds_x1_ * replication_dim_1;\n\t\t\t\t\n\t\t\t\tif (p_subpop_data.periodic_y_)\n\t\t\t\t{\n\t\t\t\t\ty_offset = p_subpop_data.bounds_y1_ * replication_dim_2;\n\t\t\t\t\t\n\t\t\t\t\tif (p_subpop_data.periodic_z_)\n\t\t\t\t\t\tz_offset = p_subpop_data.bounds_z1_ * replication_dim_3;\n\t\t\t\t}\n\t\t\t\telse if (p_subpop_data.periodic_z_)\n\t\t\t\t{\n\t\t\t\t\tz_offset = p_subpop_data.bounds_z1_ * replication_dim_2;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (p_subpop_data.periodic_y_)\n\t\t\t{\n\t\t\t\ty_offset = p_subpop_data.bounds_y1_ * replication_dim_1;\n\t\t\t\t\n\t\t\t\tif (p_subpop_data.periodic_z_)\n\t\t\t\t\tz_offset = p_subpop_data.bounds_z1_ * replication_dim_2;\n\t\t\t}\n\t\t\telse if (p_subpop_data.periodic_z_)\n\t\t\t{\n\t\t\t\tz_offset = p_subpop_data.bounds_z1_ * replication_dim_1;\n\t\t\t}\n\t\t\t\n\t\t\t// Now that we have our offsets, copy the data for the replicate\n\t\t\tswitch (spatiality_)\n\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t\tfor (int i = 0; i < actual_node_count; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *original_node = nodes + i;\n\t\t\t\t\t\tSLiM_kdNode *replicate_node = replicate_nodes + i;\n\t\t\t\t\t\t\n\t\t\t\t\t\treplicate_node->x[0] = original_node->x[0] + x_offset;\n\t\t\t\t\t\treplicate_node->individual_index_ = original_node->individual_index_;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tfor (int i = 0; i < actual_node_count; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *original_node = nodes + i;\n\t\t\t\t\t\tSLiM_kdNode *replicate_node = replicate_nodes + i;\n\t\t\t\t\t\t\n\t\t\t\t\t\treplicate_node->x[0] = original_node->x[0] + x_offset;\n\t\t\t\t\t\treplicate_node->x[1] = original_node->x[1] + y_offset;\n\t\t\t\t\t\treplicate_node->individual_index_ = original_node->individual_index_;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tfor (int i = 0; i < actual_node_count; ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tSLiM_kdNode *original_node = nodes + i;\n\t\t\t\t\t\tSLiM_kdNode *replicate_node = replicate_nodes + i;\n\t\t\t\t\t\t\n\t\t\t\t\t\treplicate_node->x[0] = original_node->x[0] + x_offset;\n\t\t\t\t\t\treplicate_node->x[1] = original_node->x[1] + y_offset;\n\t\t\t\t\t\treplicate_node->x[2] = original_node->x[2] + z_offset;\n\t\t\t\t\t\treplicate_node->individual_index_ = original_node->individual_index_;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::BuildKDTree): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t\t\n\t\tactual_node_count *= periodicity_multiplier;\n\t\t\n\t\t// Write out the final constructed k-d tree to our parameters\n\t\t*kd_nodes_ptr = nodes;\n\t\t*kd_node_count_ptr = actual_node_count;\n\t}\n\t\n\tif (*kd_node_count_ptr == 0)\n\t{\n\t\t// Usually a root pointer of nullptr indicates that the tree hasn't been built, but it is\n\t\t// also used if the tree contains no nodes and thus has no root.\n\t\t*kd_root_ptr = nullptr;\n\t}\n\telse\n\t{\n\t\t// Now call out to recursively construct the tree\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: *kd_root_ptr = MakeKDTree1_p0(*kd_nodes_ptr, *kd_node_count_ptr);\tbreak;\n\t\t\tcase 2: *kd_root_ptr = MakeKDTree2_p0(*kd_nodes_ptr, *kd_node_count_ptr);\tbreak;\n\t\t\tcase 3: *kd_root_ptr = MakeKDTree3_p0(*kd_nodes_ptr, *kd_node_count_ptr);\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::BuildKDTree): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// Check the tree for correctness; for now I will leave this enabled in the DEBUG case,\n\t\t// because a bug was found in the k-d tree code in 2.4.1 that would have been caught by this.\n\t\t// Eventually, when it is clear that this code is robust, this check can be disabled.\n#if DEBUG\n\t\tint total_tree_count = 0;\n\t\t\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: total_tree_count = CheckKDTree1_p0(*kd_root_ptr);\tbreak;\n\t\t\tcase 2: total_tree_count = CheckKDTree2_p0(*kd_root_ptr);\tbreak;\n\t\t\tcase 3: total_tree_count = CheckKDTree3_p0(*kd_root_ptr);\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::BuildKDTree): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tif (total_tree_count != *kd_node_count_ptr)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::BuildKDTree): (internal error) the k-d tree count \" << total_tree_count << \" does not match the allocated node count\" << *kd_node_count_ptr << \".\" << EidosTerminate();\n#endif\n\t}\n}\n\nSLiM_kdNode *InteractionType::EnsureKDTreePresent_ALL(Subpopulation *subpop, InteractionsData &p_subpop_data)\n{\n\tif (!p_subpop_data.evaluated_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_ALL): (internal error) the interaction has not been evaluated.\" << EidosTerminate();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_ALL): (internal error) a k-d tree cannot be constructed for non-spatial interactions.\" << EidosTerminate();\n\t\n\tif (!p_subpop_data.kd_nodes_ALL_)\n\t\tCacheKDTreeNodes(subpop, p_subpop_data, /* p_apply_exerter_constraints */ false, &p_subpop_data.kd_nodes_ALL_, &p_subpop_data.kd_root_ALL_, &p_subpop_data.kd_node_count_ALL_);\n\t\n\tif (!p_subpop_data.kd_root_ALL_ && (p_subpop_data.kd_node_count_ALL_ > 0))\n\t\tBuildKDTree(p_subpop_data, &p_subpop_data.kd_nodes_ALL_, &p_subpop_data.kd_root_ALL_, &p_subpop_data.kd_node_count_ALL_);\n\t\n\treturn p_subpop_data.kd_root_ALL_;\t\t// note that this will return nullptr if the k-d tree has zero entries!\n}\n\nSLiM_kdNode *InteractionType::EnsureKDTreePresent_EXERTERS(Subpopulation *subpop, InteractionsData &p_subpop_data)\n{\n\tif (!p_subpop_data.evaluated_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_EXERTERS): (internal error) the interaction has not been evaluated.\" << EidosTerminate();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_EXERTERS): (internal error) a k-d tree cannot be constructed for non-spatial interactions.\" << EidosTerminate();\n\t\n\tif (!p_subpop_data.kd_nodes_EXERTERS_)\n\t{\n\t\t// If there are no exerter constraints, then the ALL tree should be the same as the EXERTERS tree; there's no reason to make both.\n\t\t// So at this point, if there are no exerter constraints, we first force the ALL tree to be constructed, and then we just leech on to it.\n\t\tif (!exerter_constraints_.has_constraints_)\n\t\t{\n\t\t\tEnsureKDTreePresent_ALL(subpop, p_subpop_data);\n\t\t\t\n\t\t\tp_subpop_data.kd_nodes_EXERTERS_ = p_subpop_data.kd_nodes_ALL_;\n\t\t\tp_subpop_data.kd_root_EXERTERS_ = p_subpop_data.kd_root_ALL_;\n\t\t\tp_subpop_data.kd_node_count_EXERTERS_ = p_subpop_data.kd_node_count_ALL_;\n\t\t\t\n\t\t\treturn p_subpop_data.kd_root_EXERTERS_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If our flag is set that there was a constraint precondition violation earlier, then we cannot build an exerters\n\t\t\t// tree, and instead need to show a user-visible error.  See EvaluateSubpopulation() for discussion.\n\t\t\tif (p_subpop_data.kd_constraints_raise_EXERTERS_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_EXERTERS): a tag, tagL0, tagL1, tagL2, tagL3, or tagL4 constraint is set for exerters, but the corresponding property is undefined (has not been set) for a candidate exerter being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\t// If there are non-sex exerter constraints, the k-d tree will be cached at evaluate() time.  This code path is\n\t\t\t// therefore only hit when there are no non-sex exerter constraints (but there is an exerter sex constraint).\n\t\t\t// Let's check that assertion, to make sure we don't have a logic error anywhere, since it is important for us\n\t\t\t// to cache the exerter k-d tree at evaluate() time if non-sex constraints are present.\n\t\t\tif (exerter_constraints_.has_nonsex_constraints_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::EnsureKDTreePresent_EXERTERS): (internal error) an internal error in the exerter k-d tree caching logic has occurred; please report this error.\" << EidosTerminate();\n\t\t\t\n\t\t\tCacheKDTreeNodes(subpop, p_subpop_data, /* p_apply_exerter_constraints */ true, &p_subpop_data.kd_nodes_EXERTERS_, &p_subpop_data.kd_root_EXERTERS_, &p_subpop_data.kd_node_count_EXERTERS_);\n\t\t}\n\t}\n\t\n\tif (!p_subpop_data.kd_root_EXERTERS_ && (p_subpop_data.kd_node_count_EXERTERS_ > 0))\n\t\tBuildKDTree(p_subpop_data, &p_subpop_data.kd_nodes_EXERTERS_, &p_subpop_data.kd_root_EXERTERS_, &p_subpop_data.kd_node_count_EXERTERS_);\n\t\n\treturn p_subpop_data.kd_root_EXERTERS_;\t\t// note that this will return nullptr if the k-d tree has zero entries!\n}\n\n\n#pragma mark -\n#pragma mark k-d tree consistency checking\n#pragma mark -\n\n// The general strategy is: the _pX() functions check that they are indeed a median node for all of the\n// nodes underneath the given node, for the coordinate of the given polarity.  They do this by calling\n// the pX_r() method on their left and right subtree, with their own coordinate; it recurses over the\n// subtrees.  The pX() method then makes a call on each subtree to have it check itself.  Each pX()\n// method call returns the total number of nodes found in itself and its subtrees.\n\nint InteractionType::CheckKDTree1_p0(SLiM_kdNode *t)\n{\n\tdouble split = t->x[0];\n\t\n\tif (t->left) CheckKDTree1_p0_r(t->left, split, true);\n\tif (t->right) CheckKDTree1_p0_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree1_p0(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree1_p0(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree1_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[0];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree1_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree1_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree1_p0_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree1_p0_r(t->right, split, isLeftSubtree);\n}\n\nint InteractionType::CheckKDTree2_p0(SLiM_kdNode *t)\n{\n\tdouble split = t->x[0];\n\t\n\tif (t->left) CheckKDTree2_p0_r(t->left, split, true);\n\tif (t->right) CheckKDTree2_p0_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree2_p1(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree2_p1(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree2_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[0];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree2_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree2_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree2_p0_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree2_p0_r(t->right, split, isLeftSubtree);\n}\n\nint InteractionType::CheckKDTree2_p1(SLiM_kdNode *t)\n{\n\tdouble split = t->x[1];\n\t\n\tif (t->left) CheckKDTree2_p1_r(t->left, split, true);\n\tif (t->right) CheckKDTree2_p1_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree2_p0(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree2_p0(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree2_p1_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[1];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree2_p1_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree2_p1_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree2_p1_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree2_p1_r(t->right, split, isLeftSubtree);\n}\n\nint InteractionType::CheckKDTree3_p0(SLiM_kdNode *t)\n{\n\tdouble split = t->x[0];\n\t\n\tif (t->left) CheckKDTree3_p0_r(t->left, split, true);\n\tif (t->right) CheckKDTree3_p0_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree3_p1(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree3_p1(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree3_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[0];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p0_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree3_p0_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree3_p0_r(t->right, split, isLeftSubtree);\n}\n\nint InteractionType::CheckKDTree3_p1(SLiM_kdNode *t)\n{\n\tdouble split = t->x[1];\n\t\n\tif (t->left) CheckKDTree3_p1_r(t->left, split, true);\n\tif (t->right) CheckKDTree3_p1_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree3_p2(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree3_p2(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree3_p1_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[1];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p1_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p1_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree3_p1_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree3_p1_r(t->right, split, isLeftSubtree);\n}\n\nint InteractionType::CheckKDTree3_p2(SLiM_kdNode *t)\n{\n\tdouble split = t->x[2];\n\t\n\tif (t->left) CheckKDTree3_p2_r(t->left, split, true);\n\tif (t->right) CheckKDTree3_p2_r(t->right, split, false);\n\t\n\tint left_count = t->left ? CheckKDTree3_p0(t->left) : 0;\n\tint right_count = t->right ? CheckKDTree3_p0(t->right) : 0;\n\t\n\treturn left_count + right_count + 1;\n}\n\nvoid InteractionType::CheckKDTree3_p2_r(SLiM_kdNode *t, double split, bool isLeftSubtree)\n{\n\tdouble x = t->x[2];\n\t\n\tif (isLeftSubtree) {\n\t\tif (x > split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p2_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t} else {\n\t\tif (x < split)\tEIDOS_TERMINATION << \"ERROR (InteractionType::CheckKDTree3_p2_r): (internal error) the k-d tree is not correctly sorted.\" << EidosTerminate();\n\t}\n\tif (t->left) CheckKDTree3_p2_r(t->left, split, isLeftSubtree);\n\tif (t->right) CheckKDTree3_p2_r(t->right, split, isLeftSubtree);\n}\n\n\n#pragma mark -\n#pragma mark sparse vector building\n#pragma mark -\n\ninline __attribute__((always_inline)) double dist_sq1(SLiM_kdNode *a, double *b)\n{\n#ifndef __clang_analyzer__\n\tdouble t = a->x[0] - b[0];\n\t\n\treturn t * t;\n#else\n\treturn 0.0;\n#endif\n}\n\ninline __attribute__((always_inline)) double dist_sq2(SLiM_kdNode *a, double *b)\n{\n#ifndef __clang_analyzer__\n\tdouble t, d;\n\t\n\tt = a->x[0] - b[0];\n\td = t * t;\n\t\n\tt = a->x[1] - b[1];\n\td += t * t;\n\t\n\treturn d;\n#else\n\treturn 0.0;\n#endif\n}\n\ninline __attribute__((always_inline)) double dist_sq3(SLiM_kdNode *a, double *b)\n{\n#ifndef __clang_analyzer__\n\tdouble t, d;\n\t\n\tt = a->x[0] - b[0];\n\td = t * t;\n\t\n\tt = a->x[1] - b[1];\n\td += t * t;\n\t\n\tt = a->x[2] - b[2];\n\td += t * t;\n\t\n\treturn d;\n#else\n\treturn 0.0;\n#endif\n}\n\n// add neighbors to the sparse vector in 1D\nvoid InteractionType::BuildSV_Presences_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector)\n{\n\tdouble d = dist_sq1(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[0] - nd[0];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryPresence(root->individual_index_);\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_1(root->left, nd, p_focal_individual_index, p_sparse_vector);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_1(root->right, nd, p_focal_individual_index, p_sparse_vector);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_1(root->right, nd, p_focal_individual_index, p_sparse_vector);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_1(root->left, nd, p_focal_individual_index, p_sparse_vector);\n\t}\n}\n\n// add neighbors to the sparse vector in 2D\nvoid InteractionType::BuildSV_Presences_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryPresence(root->individual_index_);\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbors to the sparse vector in 3D\nvoid InteractionType::BuildSV_Presences_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq3(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryPresence(root->individual_index_);\n\t\n\tif (++p_phase >= 3) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_3(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_3(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Presences_3(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Presences_3(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbors to the sparse vector in 1D\nvoid InteractionType::BuildSV_Distances_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector)\n{\n\tdouble d = dist_sq1(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[0] - nd[0];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryDistance(root->individual_index_, (sv_value_t)sqrt(d));\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_1(root->left, nd, p_focal_individual_index, p_sparse_vector);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_1(root->right, nd, p_focal_individual_index, p_sparse_vector);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_1(root->right, nd, p_focal_individual_index, p_sparse_vector);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_1(root->left, nd, p_focal_individual_index, p_sparse_vector);\n\t}\n}\n\n// add neighbors to the sparse vector in 2D\nvoid InteractionType::BuildSV_Distances_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryDistance(root->individual_index_, (sv_value_t)sqrt(d));\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbors to the sparse vector in 3D\nvoid InteractionType::BuildSV_Distances_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq3(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_sparse_vector->AddEntryDistance(root->individual_index_, (sv_value_t)sqrt(d));\n\t\n\tif (++p_phase >= 3) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_3(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_3(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tBuildSV_Distances_3(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tBuildSV_Distances_3(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"f\" (SpatialKernelType::kFixed : fixed) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_f_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\t//d = sqrt(d);\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)if_param1_);\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_f_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_f_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_f_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_f_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"l\" (SpatialKernelType::kLinear : linear) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_l_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\td = sqrt(d);\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)(if_param1_ * (1.0 - d / max_distance_)));\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_l_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_l_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_l_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_l_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"e\" (SpatialKernelType::kExponential : exponential) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_e_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\td = sqrt(d);\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)(if_param1_ * exp(-if_param2_ * d)));\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_e_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_e_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_e_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_e_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"n\" (SpatialKernelType::kNormal : normal/Gaussian) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_n_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\t//d = sqrt(d);\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)(if_param1_ * exp(-d / n_2param2sq_)));\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_n_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_n_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_n_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_n_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"c\" (SpatialKernelType::kCauchy : Cauchy) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_c_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\tdouble temp = sqrt(d) / if_param2_;\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)(if_param1_ / (1.0 + temp * temp)));\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_c_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_c_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_c_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_c_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\n// add neighbor strengths of type \"t\" (SpatialKernelType::kStudentsT : Student's t) to the sparse vector in 2D\nvoid InteractionType::BuildSV_Strengths_t_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t{\n\t\td = sqrt(d);\n\t\tp_sparse_vector->AddEntryStrength(root->individual_index_, (sv_value_t)SpatialKernel::tdist(d, if_param1_, if_param2_, if_param3_));\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\tif (dx > 0) {\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_t_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_t_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t} else {\n\t\tif (root->right)\t\t\t\tBuildSV_Strengths_t_2(root->right, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t\tif (dx2 > max_distance_sq_)\t\treturn;\n\t\tif (root->left)\t\t\t\t\tBuildSV_Strengths_t_2(root->left, nd, p_focal_individual_index, p_sparse_vector, p_phase);\n\t}\n}\n\nbool InteractionType::_CheckIndividualNonSexConstraints(Individual *p_individual, InteractionConstraints &p_constraints)\n{\n\t// we do not check p_constraints.has_nonsex_constraints_; this should only be called when a constraint exists\n\t// BEWARE: this checks for tag/tagL values being defined, as needed, and raises if they aren't\n\t\n\tif (p_constraints.tag_ != SLIM_TAG_UNSET_VALUE)\n\t{\n\t\tslim_usertag_t tag_value = p_individual->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tag constraint is set for the interaction type, but the tag property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\n\t\tif (p_constraints.tag_ != tag_value)\n\t\t\treturn false;\n\t}\n\tif ((p_constraints.min_age_ != -1) && (p_constraints.min_age_ > p_individual->age_))\n\t\treturn false;\n\tif ((p_constraints.max_age_ != -1) && (p_constraints.max_age_ < p_individual->age_))\n\t\treturn false;\n\tif ((p_constraints.migrant_ != -1) && (p_constraints.migrant_ != p_individual->migrant_))\n\t\treturn false;\n\t\n\tif (p_constraints.has_tagL_constraints_)\n\t{\n\t\tif (p_constraints.tagL0_ != -1)\n\t\t{\n\t\t\tif (!p_individual->tagL0_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tagL0 constraint is set for the interaction type, but the tagL0 property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (p_constraints.tagL0_ != p_individual->tagL0_value_)\n\t\t\t\treturn false;\n\t\t}\n\t\tif (p_constraints.tagL1_ != -1)\n\t\t{\n\t\t\tif (!p_individual->tagL1_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tagL1 constraint is set for the interaction type, but the tagL1 property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (p_constraints.tagL1_ != p_individual->tagL1_value_)\n\t\t\t\treturn false;\n\t\t}\n\t\tif (p_constraints.tagL2_ != -1)\n\t\t{\n\t\t\tif (!p_individual->tagL2_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tagL2 constraint is set for the interaction type, but the tagL2 property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (p_constraints.tagL2_ != p_individual->tagL2_value_)\n\t\t\t\treturn false;\n\t\t}\n\t\tif (p_constraints.tagL3_ != -1)\n\t\t{\n\t\t\tif (!p_individual->tagL3_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tagL3 constraint is set for the interaction type, but the tagL3 property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (p_constraints.tagL3_ != p_individual->tagL3_value_)\n\t\t\t\treturn false;\n\t\t}\n\t\tif (p_constraints.tagL4_ != -1)\n\t\t{\n\t\t\tif (!p_individual->tagL4_set_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::_CheckIndividualNonSexConstraints): a tagL4 constraint is set for the interaction type, but the tagL4 property is undefined (has not been set) for an individual being queried.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (p_constraints.tagL4_ != p_individual->tagL4_value_)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\t\n\treturn true;\n}\n\nbool InteractionType::_PrecheckIndividualNonSexConstraints(Individual *p_individual, InteractionConstraints &p_constraints)\n{\n\t// This is similar to _CheckIndividualNonSexConstraints(), but it does not actually check the constraints.\n\t// Instead, it checks that the constraints *can* be checked, without raising.  If a tag/tagL value that is\n\t// needed to do the constraint check is missing, this method returns false; otherwise it returns true,\n\t// meaning \"it is safe to check constraints\".  See EvaluateSubpopulation() for discussion.\n\tif ((p_constraints.tag_ != SLIM_TAG_UNSET_VALUE) && (p_individual->tag_value_ == SLIM_TAG_UNSET_VALUE))\n\t\treturn false;\n\t\n\tif (p_constraints.has_tagL_constraints_)\n\t{\n\t\tif ((p_constraints.tagL0_ != -1) && !p_individual->tagL0_set_)\n\t\t\t\treturn false;\n\t\tif ((p_constraints.tagL1_ != -1) && !p_individual->tagL1_set_)\n\t\t\t\treturn false;\n\t\tif ((p_constraints.tagL2_ != -1) && !p_individual->tagL2_set_)\n\t\t\t\treturn false;\n\t\tif ((p_constraints.tagL3_ != -1) && !p_individual->tagL3_set_)\n\t\t\t\treturn false;\n\t\tif ((p_constraints.tagL4_ != -1) && !p_individual->tagL4_set_)\n\t\t\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\nvoid InteractionType::FillSparseVectorForReceiverPresences(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, __attribute__((__unused__)) bool constraints_active)\n{\n#if DEBUG\n\t// The caller should guarantee that the receiver and exerter species are compatible with the interaction\n\tif (constraints_active)\n\t{\n\t\tCheckSpeciesCompatibility_Receiver(receiver->subpopulation_->species_);\n\t\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\t}\n\telse\n\t{\n\t\tCheckSpeciesCompatibility_Generic(receiver->subpopulation_->species_);\n\t\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\t}\n\t\n\t// SparseVector relies on the k-d tree, so this is an error for now\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverPresences): (internal error) request for k-d tree information from a non-spatial interaction.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver and exerter subpops are compatible in spatial structure\n\tCheckSpatialCompatibility(receiver->subpopulation_, exerter_subpop);\n\t\n\t// The caller should ensure that this method is never called for a receiver that cannot receive interactions\n\tif (constraints_active && !CheckIndividualConstraints(receiver, receiver_constraints_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverPresences): (internal error) the receiver is disqualified by the current receiver constraints.\" << EidosTerminate();\n\t\n\t// The caller should be handing us a sparse vector set up for distance data\n\tif (sv->DataType() != SparseVectorDataType::kPresences)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverPresences): (internal error) the sparse vector is not configured for presences.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver is not a new juvenile, because they need to have a saved position\n\tif (receiver->index_ < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverPresences): (internal error) the receiver is a new juvenile.\" << EidosTerminate();\n#endif\n\t\n\t// if the root is nullptr, the tree is empty and we have no results\n\tif (kd_root)\n\t{\n\t\t// Figure out what index in the exerter subpopulation, if any, needs to be excluded so self-interaction is zero\n\t\tslim_popsize_t excluded_index = (exerter_subpop == receiver->subpopulation_) ? receiver->index_ : -1;\n\t\t\n\t\t// Without a specified exerter sex, we can add each exerter with no sex test\n\t\tif (spatiality_ == 2)\t\tBuildSV_Presences_2(kd_root, receiver_position, excluded_index, sv, 0);\n\t\telse if (spatiality_ == 1)\tBuildSV_Presences_1(kd_root, receiver_position, excluded_index, sv);\n\t\telse if (spatiality_ == 3)\tBuildSV_Presences_3(kd_root, receiver_position, excluded_index, sv, 0);\n\t}\n\t\n\t// After building the sparse vector above, we mark it finished\n\tsv->Finished();\n}\n\nvoid InteractionType::FillSparseVectorForReceiverDistances(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, __attribute__((__unused__)) bool constraints_active)\n{\n#if DEBUG\n\t// The caller should guarantee that the receiver and exerter species are compatible with the interaction\n\tif (constraints_active)\n\t{\n\t\tCheckSpeciesCompatibility_Receiver(receiver->subpopulation_->species_);\n\t\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\t}\n\telse\n\t{\n\t\tCheckSpeciesCompatibility_Generic(receiver->subpopulation_->species_);\n\t\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\t}\n\t\n\t// Non-spatial interactions do not have a concept of distance, so this is an error\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverDistances): (internal error) request for distances from a non-spatial interaction.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver and exerter subpops are compatible in spatial structure\n\tCheckSpatialCompatibility(receiver->subpopulation_, exerter_subpop);\n\t\n\t// The caller should ensure that this method is never called for a receiver that cannot receive interactions\n\tif (constraints_active && !CheckIndividualConstraints(receiver, receiver_constraints_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverDistances): (internal error) the receiver is disqualified by the current receiver constraints.\" << EidosTerminate();\n\t\n\t// The caller should be handing us a sparse vector set up for distance data\n\tif (sv->DataType() != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverDistances): (internal error) the sparse vector is not configured for distances.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver is not a new juvenile, because they need to have a saved position\n\tif (receiver->index_ < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverDistances): (internal error) the receiver is a new juvenile.\" << EidosTerminate();\n#endif\n\t\n\t// if the root is nullptr, the tree is empty and we have no results\n\tif (kd_root)\n\t{\n\t\t// Figure out what index in the exerter subpopulation, if any, needs to be excluded so self-interaction is zero\n\t\tslim_popsize_t excluded_index = (exerter_subpop == receiver->subpopulation_) ? receiver->index_ : -1;\n\t\t\n\t\tif (spatiality_ == 2)\t\tBuildSV_Distances_2(kd_root, receiver_position, excluded_index, sv, 0);\n\t\telse if (spatiality_ == 1)\tBuildSV_Distances_1(kd_root, receiver_position, excluded_index, sv);\n\t\telse if (spatiality_ == 3)\tBuildSV_Distances_3(kd_root, receiver_position, excluded_index, sv, 0);\n\t}\n\t\n\t// After building the sparse vector above, we mark it finished\n\tsv->Finished();\n}\n\nvoid InteractionType::FillSparseVectorForPointDistances(SparseVector *sv, double *position, __attribute__((__unused__)) Subpopulation *exerter_subpop, SLiM_kdNode *kd_root)\n{\n\t// This is a special version of FillSparseVectorForReceiverDistances() used for nearestNeighborsOfPoint().\n\t// It searches for neighbors of a point, without using a receiver, just a point.\n#if DEBUG\n\t// The caller should guarantee that the exerter species is compatible with the interaction\n\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\t\n\t// Non-spatial interactions do not have a concept of distance, so this is an error\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForPointDistances): (internal error) request for distances from a non-spatial interaction.\" << EidosTerminate();\n\t\n\t// The caller should be handing us a sparse vector set up for distance data\n\tif (sv->DataType() != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForPointDistances): (internal error) the sparse vector is not configured for distances.\" << EidosTerminate();\n#endif\n\t\n\t// if the root is nullptr, the tree is empty and we have no results\n\tif (kd_root)\n\t{\n\t\tif (spatiality_ == 2)\t\tBuildSV_Distances_2(kd_root, position, -1, sv, 0);\n\t\telse if (spatiality_ == 1)\tBuildSV_Distances_1(kd_root, position, -1, sv);\n\t\telse if (spatiality_ == 3)\tBuildSV_Distances_3(kd_root, position, -1, sv, 0);\n\t}\n\t\n\t// After building the sparse vector above, we mark it finished\n\tsv->Finished();\n}\n\nvoid InteractionType::FillSparseVectorForReceiverStrengths(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, std::vector<SLiMEidosBlock*> &interaction_callbacks)\n{\n#if DEBUG\n\t// The caller should guarantee that the receiver and exerter species are compatible with the interaction\n\tCheckSpeciesCompatibility_Receiver(receiver->subpopulation_->species_);\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\t\n\t// Non-spatial interactions are not handled by this method (they must be handled separately by logic in the caller), so this is an error\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) request for strengths from a non-spatial interaction.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver and exerter subpops are compatible in spatial structure\n\tCheckSpatialCompatibility(receiver->subpopulation_, exerter_subpop);\n\t\n\t// The caller should ensure that this method is never called for a receiver that cannot receive interactions\n\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) the receiver is disqualified by the current receiver constraints.\" << EidosTerminate();\n\t\n\t// The caller should be handing us a sparse vector set up for strength data\n\tif (sv->DataType() != SparseVectorDataType::kStrengths)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) the sparse vector is not configured for strengths.\" << EidosTerminate();\n\t\n\t// The caller should guarantee that the receiver is not a new juvenile, because they need to have a saved position\n\tif (receiver->index_ < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) the receiver is a new juvenile.\" << EidosTerminate();\n#endif\n\t\n\t// if the root is nullptr, the tree is empty and we have no results\n\tif (kd_root)\n\t{\n\t\t// Figure out what index in the exerter subpopulation, if any, needs to be excluded so self-interaction is zero\n\t\tslim_popsize_t excluded_index = (exerter_subpop == receiver->subpopulation_) ? receiver->index_ : -1;\n\t\t\n\t\t// We special-case Fixed kernel builds directly to strength values here, for efficiency,\n\t\t// with no callbacks and spatiality \"xy\". Other kernels use the two-pass path below\n\t\t// which enables SIMD optimizations for Exponential and Normal kernels.\n\t\t// ADK 12/16/2025: changed to only use special-case path for Fixed kernel\n\t\tif ((interaction_callbacks.size() == 0) && (spatiality_ == 2) && (if_type_ == SpatialKernelType::kFixed))\n\t\t{\n\t\t\tsv->SetDataType(SparseVectorDataType::kStrengths);\n\t\t\tBuildSV_Strengths_f_2(kd_root, receiver_position, excluded_index, sv, 0);\n\t\t\tsv->Finished();\n\t\t\treturn;\n\t\t}\n\n\t\t// ADK 12/16/2025: The original switch below handled all kernel types in the special-case\n\t\t// single-pass path. Now only Fixed uses the special path above; other kernels fall\n\t\t// through to the two-pass distance-then-transform path, enabling SIMD optimizations.\n#if 0\n\t\tif ((interaction_callbacks.size() == 0) && (spatiality_ == 2))\n\t\t{\n\t\t\tsv->SetDataType(SparseVectorDataType::kStrengths);\n\n\t\t\tswitch (if_type_)\n\t\t\t{\n\t\t\t\tcase SpatialKernelType::kFixed:\t\t\tBuildSV_Strengths_f_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tcase SpatialKernelType::kLinear:\t\tBuildSV_Strengths_l_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tcase SpatialKernelType::kExponential:\tBuildSV_Strengths_e_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tcase SpatialKernelType::kNormal:\t\tBuildSV_Strengths_n_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tcase SpatialKernelType::kCauchy:\t\tBuildSV_Strengths_c_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tcase SpatialKernelType::kStudentsT:\t\tBuildSV_Strengths_t_2(kd_root, receiver_position, excluded_index, sv, 0); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) unoptimized SpatialKernelType value.\" << EidosTerminate();\n\t\t\t}\n\n\t\t\tsv->Finished();\n\t\t\treturn;\n\t\t}\n#endif\n\n\t\t// Set up to build distances first; this is an internal implementation detail, so we require the sparse vector set up for strengths above\n\t\tsv->SetDataType(SparseVectorDataType::kDistances);\n\t\t\n\t\tif (spatiality_ == 2)\t\tBuildSV_Distances_2(kd_root, receiver_position, excluded_index, sv, 0);\n\t\telse if (spatiality_ == 1)\tBuildSV_Distances_1(kd_root, receiver_position, excluded_index, sv);\n\t\telse if (spatiality_ == 3)\tBuildSV_Distances_3(kd_root, receiver_position, excluded_index, sv, 0);\n\t}\n\t\n\t// After building the sparse vector above, we mark it finished\n\tsv->Finished();\n\t\n\t// Now we scan through the pre-existing sparse vector for interacting pairs,\n\t// and transform distances into interaction strength values calculated for each.\n\tuint32_t nnz, *columns;\n\tsv_value_t *values;\n\t\n\tsv->Distances(&nnz, &columns, &values);\n\t\n\tif (interaction_callbacks.size() == 0)\n\t{\n\t\t// No callbacks; strength calculations come from the interaction function only\n\t\t\n\t\t// CalculateStrengthNoCallbacks() is basically inlined here, moved outside the loop; see that function for comments\n\t\tswitch (if_type_)\n\t\t{\n\t\t\tcase SpatialKernelType::kFixed:\n\t\t\t{\n\t\t\t\tfor (uint32_t col_iter = 0; col_iter < nnz; ++col_iter)\n\t\t\t\t\tvalues[col_iter] = (sv_value_t)if_param1_;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SpatialKernelType::kLinear:\n\t\t\t{\n\t\t\t\t// Use SIMD-optimized kernel: fmax = if_param1_, max_distance = max_distance_\n\t\t\t\tEidos_SIMD::linear_kernel_float32(values, nnz, (float)if_param1_, (float)max_distance_);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SpatialKernelType::kExponential:\n\t\t\t{\n\t\t\t\t// SIMD-accelerated exponential kernel: strength = fmax * exp(-lambda * distance)\n\t\t\t\tEidos_SIMD::exp_kernel_float32(values, nnz, (float)if_param1_, (float)if_param2_);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SpatialKernelType::kNormal:\n\t\t\t{\n\t\t\t\t// SIMD-accelerated Gaussian kernel: strength = fmax * exp(-d^2 / 2sigma^2)\n\t\t\t\tEidos_SIMD::normal_kernel_float32(values, nnz, (float)if_param1_, (float)n_2param2sq_);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SpatialKernelType::kCauchy:\n\t\t\t{\n\t\t\t\t// Use SIMD-optimized kernel: fmax = if_param1_, lambda = if_param2_\n\t\t\t\tEidos_SIMD::cauchy_kernel_float32(values, nnz, (float)if_param1_, (float)if_param2_);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase SpatialKernelType::kStudentsT:\n\t\t\t{\n\t\t\t\t// Use SIMD-optimized kernel: fmax = if_param1_, nu = if_param2_, tau = if_param3_\n\t\t\t\tEidos_SIMD::tdist_kernel_float32(values, nnz, (float)if_param1_, (float)if_param2_, (float)if_param3_);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// should never be hit, but this is the base case\n\t\t\t\tfor (uint32_t col_iter = 0; col_iter < nnz; ++col_iter)\n\t\t\t\t{\n\t\t\t\t\tsv_value_t distance = values[col_iter];\n\t\t\t\t\t\n\t\t\t\t\tvalues[col_iter] = (sv_value_t)CalculateStrengthNoCallbacks(distance);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FillSparseVectorForReceiverStrengths): (internal error) unimplemented SpatialKernelType case.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Callbacks; strength calculations need to include callback effects\n\t\t// BEWARE: With callbacks, this method can raise arbitrarily, so the caller needs\n\t\t// to be prepared for that, particularly if they are running parallel!\n\t\tIndividual **subpop_individuals = exerter_subpop->parent_individuals_.data();\n\t\t\n\t\tfor (uint32_t col_iter = 0; col_iter < nnz; ++col_iter)\n\t\t{\n\t\t\tuint32_t col = columns[col_iter];\n\t\t\tsv_value_t distance = values[col_iter];\n\t\t\t\n\t\t\tvalues[col_iter] = (sv_value_t)CalculateStrengthWithCallbacks(distance, receiver, subpop_individuals[col], interaction_callbacks);\n\t\t}\n\t}\n\t\n\t// We have transformed distances into strengths in the sparse vector's values_ buffer\n\tsv->SetDataType(SparseVectorDataType::kStrengths);\n}\n\n\n#pragma mark -\n#pragma mark k-d tree neighbor searches\n#pragma mark -\n\n// count neighbors in 1D\nint InteractionType::CountNeighbors_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index)\n{\n\tint neighborCount = 0;\n\tdouble d = dist_sq1(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[0] - nd[0];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tneighborCount++;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_1(root->left, nd, p_focal_individual_index);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_1(root->right, nd, p_focal_individual_index);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_1(root->right, nd, p_focal_individual_index);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_1(root->left, nd, p_focal_individual_index);\n\t}\n\t\n\treturn neighborCount;\n}\n\n// count neighbors in 2D\nint InteractionType::CountNeighbors_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_phase)\n{\n\tint neighborCount = 0;\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tneighborCount++;\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_2(root->left, nd, p_focal_individual_index, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_2(root->right, nd, p_focal_individual_index, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_2(root->right, nd, p_focal_individual_index, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_2(root->left, nd, p_focal_individual_index, p_phase);\n\t}\n\t\n\treturn neighborCount;\n}\n\n// count neighbors in 3D\nint InteractionType::CountNeighbors_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_phase)\n{\n\tint neighborCount = 0;\n\tdouble d = dist_sq3(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tneighborCount++;\n\t\n\tif (++p_phase >= 3) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_3(root->left, nd, p_focal_individual_index, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_3(root->right, nd, p_focal_individual_index, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tneighborCount += CountNeighbors_3(root->right, nd, p_focal_individual_index, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return neighborCount;\n\t\t\n\t\tif (root->left)\n\t\t\tneighborCount += CountNeighbors_3(root->left, nd, p_focal_individual_index, p_phase);\n\t}\n\t\n\treturn neighborCount;\n}\n\n// find the one best neighbor in 1D\nvoid InteractionType::FindNeighbors1_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist)\n{\n\tdouble d = dist_sq1(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[0] - nd[0];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((!*best || d < *best_dist) && (root->individual_index_ != p_focal_individual_index)) {\n\t\t*best_dist = d;\n\t\t*best = root;\n\t}\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighbors1_1(root->left, nd, p_focal_individual_index, best, best_dist);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighbors1_1(root->right, nd, p_focal_individual_index, best, best_dist);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighbors1_1(root->right, nd, p_focal_individual_index, best, best_dist);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighbors1_1(root->left, nd, p_focal_individual_index, best, best_dist);\n\t}\n}\n\n// find the one best neighbor in 2D\nvoid InteractionType::FindNeighbors1_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((!*best || d < *best_dist) && (root->individual_index_ != p_focal_individual_index)) {\n\t\t*best_dist = d;\n\t\t*best = root;\n\t}\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighbors1_2(root->left, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighbors1_2(root->right, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighbors1_2(root->right, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighbors1_2(root->left, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t}\n}\n\n// find the one best neighbor in 3D\nvoid InteractionType::FindNeighbors1_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist, int p_phase)\n{\n\tdouble d = dist_sq3(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((!*best || d < *best_dist) && (root->individual_index_ != p_focal_individual_index)) {\n\t\t*best_dist = d;\n\t\t*best = root;\n\t}\n\t\n\tif (++p_phase >= 3) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighbors1_3(root->left, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighbors1_3(root->right, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighbors1_3(root->right, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t\t\n\t\tif (dx2 >= *best_dist) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighbors1_3(root->left, nd, p_focal_individual_index, best, best_dist, p_phase);\n\t}\n}\n\n// find all neighbors in 1D\nvoid InteractionType::FindNeighborsA_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals)\n{\n\tdouble d = dist_sq1(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[0] - nd[0];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_result_vec.push_object_element_capcheck_NORR(p_individuals[root->individual_index_]);\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighborsA_1(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighborsA_1(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighborsA_1(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighborsA_1(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals);\n\t}\n}\n\n// find all neighbors in 2D\nvoid InteractionType::FindNeighborsA_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals, int p_phase)\n{\n\tdouble d = dist_sq2(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_result_vec.push_object_element_capcheck_NORR(p_individuals[root->individual_index_]);\n\t\n\tif (++p_phase >= 2) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighborsA_2(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighborsA_2(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighborsA_2(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighborsA_2(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t}\n}\n\n// find all neighbors in 3D\nvoid InteractionType::FindNeighborsA_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals, int p_phase)\n{\n\tdouble d = dist_sq3(root, nd);\n#ifndef __clang_analyzer__\n\tdouble dx = root->x[p_phase] - nd[p_phase];\n#else\n\tdouble dx = 0.0;\n#endif\n\tdouble dx2 = dx * dx;\n\t\n\tif ((d <= max_distance_sq_) && (root->individual_index_ != p_focal_individual_index))\n\t\tp_result_vec.push_object_element_capcheck_NORR(p_individuals[root->individual_index_]);\n\t\n\tif (++p_phase >= 3) p_phase = 0;\n\t\n\tif (dx > 0)\n\t{\n\t\tif (root->left)\n\t\t\tFindNeighborsA_3(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->right)\n\t\t\tFindNeighborsA_3(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t}\n\telse\n\t{\n\t\tif (root->right)\n\t\t\tFindNeighborsA_3(root->right, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t\t\n\t\tif (dx2 > max_distance_sq_) return;\n\t\t\n\t\tif (root->left)\n\t\t\tFindNeighborsA_3(root->left, nd, p_focal_individual_index, p_result_vec, p_individuals, p_phase);\n\t}\n}\n\n// BCH 5/24/2023: Here used to reside FindNeighborsN_1(), FindNeighborsN_2(), and FindNeighborsN_3(),\n// used for finding a particular number of neighbors (N), greater than 1 and less than all, in 1D / 2D / 3D.\n// They were not thread-safe, and were replaced by FillSparseVectorForReceiverDistances_ALL_NEIGHBORS();\n// now (11/2/2023) that has turned into FillSparseVectorForReceiverDistances() using kd_root_ALL_, below.\n\nvoid InteractionType::FindNeighbors(Subpopulation *p_subpop, SLiM_kdNode *kd_root, slim_popsize_t kd_node_count, double *p_point, int p_count, EidosValue_Object &p_result_vec, Individual *p_excluded_individual, bool constraints_active)\n{\n\t// If this method is passed kd_root_ALL_, from EnsureKDTreePresent_ALL(), it finds all neighbors, regardless\n\t// of exerter constraints.  If it is passed kd_root_EXERTERS_, from EnsureKDTreePresent_EXERTERS(), it finds\n\t// only neighbors that satisfy the exerter constraints.\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FindNeighbors): (internal error) neighbors cannot be found for non-spatial interactions.\" << EidosTerminate();\n\t\n\t// If zero neighbors are requested, or if the k-d tree root is nullptr (no nodes), return an empty result\n\t// BCH 11/2/2023: returning an empty result for !kd_root is a change in behavior; we used to throw an exception.\n\tif (!kd_root || (p_count == 0))\n\t\treturn;\n\t\n\t// Exclude the focal individual if and only if it is in the exerter subpopulation\n\tslim_popsize_t focal_individual_index;\n\t\n\tif (p_excluded_individual && (p_excluded_individual->subpopulation_ == p_subpop))\n\t\tfocal_individual_index = p_excluded_individual->index_;\n\telse\n\t\tfocal_individual_index = -1;\n\t\n\tif (p_count == 1)\n\t{\n\t\t// Finding a single nearest neighbor is special-cased, and does not enforce the max distance; we do that after\n\t\tSLiM_kdNode *best = nullptr;\n\t\tdouble best_dist = 0.0;\n\t\t\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: FindNeighbors1_1(kd_root, p_point, focal_individual_index, &best, &best_dist);\t\tbreak;\n\t\t\tcase 2: FindNeighbors1_2(kd_root, p_point, focal_individual_index, &best, &best_dist, 0);\tbreak;\n\t\t\tcase 3: FindNeighbors1_3(kd_root, p_point, focal_individual_index, &best, &best_dist, 0);\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FindNeighbors): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tif (best && (best_dist <= max_distance_sq_))\n\t\t{\n\t\t\tIndividual *best_individual = p_subpop->parent_individuals_[best->individual_index_];\n\t\t\t\n\t\t\tp_result_vec.push_object_element_NORR(best_individual);\n\t\t}\n\t}\n\telse if (p_count >= kd_node_count)\t// can't do (kd_node_count - 1), because the focal individual might not be among the nodes in the k-d tree\n\t{\n\t\t// Finding all neighbors within the interaction distance is special-cased\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: FindNeighborsA_1(kd_root, p_point, focal_individual_index, p_result_vec, p_subpop->parent_individuals_);\t\tbreak;\n\t\t\tcase 2: FindNeighborsA_2(kd_root, p_point, focal_individual_index, p_result_vec, p_subpop->parent_individuals_, 0);\t\tbreak;\n\t\t\tcase 3: FindNeighborsA_3(kd_root, p_point, focal_individual_index, p_result_vec, p_subpop->parent_individuals_, 0);\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::FindNeighbors): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Finding multiple neighbors is the slower general case; we use SparseVector to get all neighbors\n\t\t// (we would have to look at all of them anyway), and then sort them and return the top N\n\t\t// BCH 5/24/2023: This replaces the old algorithm using FindNeighborsN_X(), which was not thread-safe\n\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(p_subpop, SparseVectorDataType::kDistances);\n\t\t\n\t\ttry {\n\t\t\tif (p_excluded_individual)\n\t\t\t\tFillSparseVectorForReceiverDistances(sv, p_excluded_individual, p_point, p_subpop, kd_root, constraints_active);\n\t\t\telse\n\t\t\t\tFillSparseVectorForPointDistances(sv, p_point, p_subpop, kd_root);\n\t\t\t\n\t\t\tuint32_t nnz;\n\t\t\tconst uint32_t *columns;\n\t\t\tconst sv_value_t *distances;\n\t\t\t\n\t\t\tdistances = sv->Distances(&nnz, &columns);\n\t\t\t\n\t\t\tstd::vector<std::pair<uint32_t, sv_value_t>> neighbors;\n\t\t\t\n\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\tneighbors.emplace_back(col_index, distances[col_index]);\n\t\t\t\n\t\t\tstd::sort(neighbors.begin(), neighbors.end(), [](const std::pair<uint32_t, sv_value_t> &l, const std::pair<uint32_t, sv_value_t> &r) {\n\t\t\t\treturn l.second < r.second;\n\t\t\t});\n\t\t\t\n\t\t\tstd::vector<Individual *> &exerters = p_subpop->parent_individuals_;\n\t\t\t\n\t\t\t// the client requested p_count items, but we may have fewer\n\t\t\tif (p_count > (int)nnz)\n\t\t\t\tp_count = (int)nnz;\n\t\t\t\n\t\t\tfor (int neighbor_index = 0; neighbor_index < p_count; ++neighbor_index)\n\t\t\t{\n\t\t\t\tIndividual *exerter = exerters[columns[neighbors[neighbor_index].first]];\n\t\t\t\t\n\t\t\t\tp_result_vec.push_object_element_capcheck_NORR(exerter);\n\t\t\t}\n\t\t} catch (...) {\n\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\tInteractionType::FreeSparseVector(sv);\n\t}\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *InteractionType::Class(void) const\n{\n\treturn gSLiM_InteractionType_Class;\n}\n\nvoid InteractionType::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<i\" << interaction_type_id_ << \">\";\n}\n\nEidosValue_SP InteractionType::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_id:\t\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!cached_value_inttype_id_)\n\t\t\t\tcached_value_inttype_id_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(interaction_type_id_));\n\t\t\treturn cached_value_inttype_id_;\n\t\t}\n\t\tcase gID_reciprocal:\n\t\t{\n\t\t\treturn (reciprocal_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_sexSegregation:\n\t\t{\n\t\t\tstd::string sex_segregation_string;\n\t\t\t\n\t\t\tswitch (receiver_constraints_.sex_)\n\t\t\t{\n\t\t\t\tcase IndividualSex::kFemale:\tsex_segregation_string += \"F\"; break;\n\t\t\t\tcase IndividualSex::kMale:\t\tsex_segregation_string += \"M\"; break;\n\t\t\t\tdefault:\t\t\t\t\t\tsex_segregation_string += \"*\"; break;\n\t\t\t}\n\t\t\t\n\t\t\tswitch (exerter_constraints_.sex_)\n\t\t\t{\n\t\t\t\tcase IndividualSex::kFemale:\tsex_segregation_string += \"F\"; break;\n\t\t\t\tcase IndividualSex::kMale:\t\tsex_segregation_string += \"M\"; break;\n\t\t\t\tdefault:\t\t\t\t\t\tsex_segregation_string += \"*\"; break;\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(sex_segregation_string));\n\t\t}\n\t\tcase gID_spatiality:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(spatiality_string_));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_maxDistance:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(max_distance_));\n\t\tcase gID_tag:\t\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::GetProperty): property tag accessed on interaction type before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *InteractionType::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tInteractionType *value = (InteractionType *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->interaction_type_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *InteractionType::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tInteractionType *value = (InteractionType *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::GetProperty_Accelerated_tag): property tag accessed on interaction type before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nvoid InteractionType::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_maxDistance:\n\t\t{\n\t\t\tif (AnyEvaluated())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::SetProperty): maxDistance cannot be changed while the interaction is being evaluated; call unevaluate() first, or set maxDistance prior to evaluation of the interaction.\" << EidosTerminate();\n\t\t\t\n\t\t\tmax_distance_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tmax_distance_sq_ = max_distance_ * max_distance_;\n\t\t\t\n\t\t\tif (max_distance_ < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::SetProperty): the maximum interaction distance must be greater than or equal to zero.\" << EidosTerminate();\n\t\t\tif ((if_type_ == SpatialKernelType::kLinear) && (std::isinf(max_distance_) || (max_distance_ <= 0.0)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::SetProperty): the maximum interaction distance must be finite and greater than zero when interaction type 'l' has been chosen.\" << EidosTerminate();\n\t\t\t\n\t\t\t// tweak a flag to make SLiMgui update\n\t\t\tcommunity_.interaction_types_changed_ = true;\n\t\t\t\n\t\t\t// changing max_distance_ invalidates the cached clipped_integral_ buffer; we don't deallocate it, just invalidate it\n\t\t\tclipped_integral_valid_ = false;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP InteractionType::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_clippedIntegral:\t\t\treturn ExecuteMethod_clippedIntegral(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_distance:\t\t\t\t\treturn ExecuteMethod_distance(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_distanceFromPoint:\t\t\treturn ExecuteMethod_distanceFromPoint(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_drawByStrength:\t\t\treturn ExecuteMethod_drawByStrength(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_evaluate:\t\t\t\t\treturn ExecuteMethod_evaluate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_interactingNeighborCount:\treturn ExecuteMethod_interactingNeighborCount(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_localPopulationDensity:\treturn ExecuteMethod_localPopulationDensity(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_interactionDistance:\t\treturn ExecuteMethod_interactionDistance(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_nearestInteractingNeighbors:\treturn ExecuteMethod_nearestInteractingNeighbors(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_nearestNeighbors:\t\t\treturn ExecuteMethod_nearestNeighbors(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_nearestNeighborsOfPoint:\treturn ExecuteMethod_nearestNeighborsOfPoint(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_neighborCount:\t\t\t\treturn ExecuteMethod_neighborCount(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_neighborCountOfPoint:\t\treturn ExecuteMethod_neighborCountOfPoint(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setConstraints:\t\t\treturn ExecuteMethod_setConstraints(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setInteractionFunction:\treturn ExecuteMethod_setInteractionFunction(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_strength:\t\t\t\t\treturn ExecuteMethod_strength(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_testConstraints:\t\t\treturn ExecuteMethod_testConstraints(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_totalOfNeighborStrengths:\treturn ExecuteMethod_totalOfNeighborStrengths(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_unevaluate:\t\t\t\treturn ExecuteMethod_unevaluate(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\nstatic inline __attribute__((always_inline)) InteractionsData &InteractionsDataForSubpop(std::map<slim_objectid_t, InteractionsData> &data_, Subpopulation *subpop)\n{\n\tslim_objectid_t subpop_id = subpop->subpopulation_id_;\n\tauto subpop_data_iter = data_.find(subpop_id);\n\t\n\tif ((subpop_data_iter == data_.end()) || !subpop_data_iter->second.evaluated_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionsDataForSubpop): the interaction must be evaluated for the receiver and exerter subpopulations, by calling evaluate(), before any queries.\" << EidosTerminate();\n\t\n\treturn subpop_data_iter->second;\n}\n\n//\n//\t*********************\t– (float)clippedIntegral(No<Individual> receivers)\nEidosValue_SP InteractionType::ExecuteMethod_clippedIntegral(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *receivers_value = p_arguments[0].get();\n\tint receivers_count = receivers_value->Count();\n\t// BEWARE: ExecuteMethod_localPopulationDensity() assumes that its API matches that of ExecuteMethod_clippedIntegral()!\n\t// If any arguments are added here, its code will need to change because that assumption will then be violated!\n\t// In fact localPopulationDensity() has an additional argument now, but it does not need that argument to be handled\n\t// by clippedIntegral(), so this dependency still works.\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_clippedIntegral): clippedIntegral() has no meaning for non-spatial interactions.\" << EidosTerminate();\n\tif (spatiality_ == 3)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_clippedIntegral): clippedIntegral() has not been implemented for the 'xyz' case yet.  If you need this functionality, please file a GitHub issue.\" << EidosTerminate();\n\t\n\tif (spatiality_ == 1)\n\t\tCacheClippedIntegral_1D();\n\telse if (spatiality_ == 2)\n\t\tCacheClippedIntegral_2D();\n\telse // (spatiality_ == 3)\n\t{\n\t\t;\t// FIXME the big obstacle here is that a 1024x1024x1024 array of precalculated values is way too large, so interpolation is probably needed\n\t}\n\t\n\t// Note that clippedIntegral() ignores sex-specificity; every individual is in an \"interaction field\", which\n\t// clippedIntegral() measures, even if some individuals cannot actually feel any interactions exerted by others.\n\t// This policy means that clippedIntegral() never returns zero, avoiding divide-by-zero issues.\n\t\n\t// NULL means \"what's the integral for a receiver that is not near any edge?\"\n\tif (receivers_count == 0)\n\t{\n\t\tif (receivers_value->Type() == EidosValueType::kValueNULL)\n\t\t{\n\t\t\tdouble integral;\n\t\t\t\n\t\t\tif (spatiality_ == 1)\n\t\t\t\tintegral = ClippedIntegral_1D(max_distance_, max_distance_, false);\n\t\t\telse if (spatiality_ == 2)\n\t\t\t\tintegral = ClippedIntegral_2D(max_distance_, max_distance_, max_distance_, max_distance_, false, false);\n\t\t\telse // (spatiality_ == 3)\n\t\t\t\tintegral = 0.0;\t\t\t// FIXME\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(integral));\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\t}\n\t}\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(receivers_value);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_clippedIntegral): clippedIntegral() requires that all receivers belong to the same species.\" << EidosTerminate();\n\t\n\tCheckSpeciesCompatibility_Generic(*species);\n\t\n\tbool periodic_x, periodic_y, periodic_z;\n\t\n\tspecies->SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\n\t// We have a singleton or vector of receivers; we'd like to treat them both in the same way, so we set up for that here\n\t// We do not try to create a singleton return value when passed a singleton receiver; too complicated to optimize for that here\n\tconst Individual * const *receivers_data = (Individual * const *)receivers_value->ObjectData();\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receivers_data[0]->subpopulation_);\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(receivers_count);\n\n\t// Now treat cases according to spatiality\n\tbool saw_error1 = false, saw_error2 = false;\n\t\n\tif (spatiality_ == 1)\n\t{\n\t\tif (spatiality_string_ == \"x\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_1S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_x) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, periodic_x);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, periodic_x);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"y\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_1S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_y) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_y0_, subpop->bounds_y1_ - indA, periodic_y);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_y0_, subpop->bounds_y1_ - indA, periodic_y);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t\telse // (spatiality_string_ == \"z\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_1S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_z) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_z0_, subpop->bounds_z1_ - indA, periodic_z);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_1D(indA - subpop->bounds_z0_, subpop->bounds_z1_ - indA, periodic_z);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t}\n\telse if (spatiality_ == 2)\n\t{\n\t\tif (spatiality_string_ == \"xy\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_2S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_x, periodic_y) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble indB = receiver_position[1];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, indB - subpop->bounds_y0_, subpop->bounds_y1_ - indB, periodic_x, periodic_y);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, indB - subpop->bounds_y0_, subpop->bounds_y1_ - indB, periodic_x, periodic_y);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t\telse if (spatiality_string_ == \"xz\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_2S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_x, periodic_z) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble indB = receiver_position[1];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, indB - subpop->bounds_z0_, subpop->bounds_z1_ - indB, periodic_x, periodic_z);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_x0_, subpop->bounds_x1_ - indA, indB - subpop->bounds_z0_, subpop->bounds_z1_ - indB, periodic_x, periodic_z);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t\telse // (spatiality_string_ == \"yz\")\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CLIPPEDINTEGRAL_2S);\n#pragma omp parallel for schedule(static) default(none) shared(receivers_count, receiver_subpop_data) firstprivate(receivers_data, float_result, periodic_y, periodic_z) reduction(||: saw_error1) reduction(||: saw_error2) if(receivers_count >= EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tconst Individual *receiver = receivers_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\tSubpopulation *subpop = receiver->subpopulation_;\n\t\t\t\tdouble indA = receiver_position[0];\n\t\t\t\tdouble indB = receiver_position[1];\n\t\t\t\tdouble integral;\n\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\ttry {\n\t\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_y0_, subpop->bounds_y1_ - indA, indB - subpop->bounds_z0_, subpop->bounds_z1_ - indB, periodic_y, periodic_z);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n#else\n\t\t\t\tintegral = ClippedIntegral_2D(indA - subpop->bounds_y0_, subpop->bounds_y1_ - indA, indB - subpop->bounds_z0_, subpop->bounds_z1_ - indB, periodic_y, periodic_z);\n#endif\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(integral, receiver_index);\n\t\t\t}\n\t\t}\n\t}\n\telse // (spatiality_ == 3)\n\t{\n\t\t// FIXME\n\t}\n\t\n\t// deferred raises, for OpenMP compatibility\n\tif (saw_error1)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_clippedIntegral): clippedIntegral() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\tif (saw_error2)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_clippedIntegral): an exception was caught inside a parallel region.\" << EidosTerminate();\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\n//\t*********************\t– (float)distance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\nEidosValue_SP InteractionType::ExecuteMethod_distance(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *exerters_value = p_arguments[1].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distance): distance() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\tIndividual *receiver = (Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\n\tif (receiver_index_in_subpop < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distance): distance() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\n\tSubpopulation *receiver_subpop = receiver->subpopulation_;\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Generic(receiver_species);\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\n\t// figure out the exerter subpopulation and get info on it\n\tbool exerters_value_NULL = (exerters_value->Type() == EidosValueType::kValueNULL);\n\tint exerters_count = exerters_value->Count();\n\t\n\tif ((exerters_count == 0) && !exerters_value_NULL)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tSubpopulation *exerter_subpop = (exerters_value_NULL ? receiver_subpop : ((Individual *)exerters_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_);\n\t\n\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tdouble *exerter_position_data = exerter_subpop_data.positions_;\n\tbool periodicity_enabled = (exerter_subpop_data.periodic_x_ || exerter_subpop_data.periodic_y_ || exerter_subpop_data.periodic_z_);\n\t\n\tif (exerters_value_NULL)\n\t{\n\t\t// NULL means return distances from receiver (which must be singleton) to all individuals in its subpopulation\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerter_subpop_size);\n\t\t\n\t\tif (periodicity_enabled)\n\t\t{\n\t\t\tfor (int exerter_index = 0; exerter_index < exerter_subpop_size; ++exerter_index)\n\t\t\t{\n\t\t\t\tdouble distance = CalculateDistanceWithPeriodicity(receiver_position, exerter_position_data + (size_t)exerter_index * SLIM_MAX_DIMENSIONALITY, exerter_subpop_data);\n\t\t\t\t\n\t\t\t\tresult_vec->set_float_no_check(distance, exerter_index);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (int exerter_index = 0; exerter_index < exerter_subpop_size; ++exerter_index)\n\t\t\t{\n\t\t\t\tdouble distance = CalculateDistance(receiver_position, exerter_position_data + (size_t)exerter_index * SLIM_MAX_DIMENSIONALITY);\n\t\t\t\t\n\t\t\t\tresult_vec->set_float_no_check(distance, exerter_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n\telse\n\t{\n\t\t// Otherwise, individuals1 is singleton, and individuals2 is any length, so we loop over individuals2\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\tIndividual * const *exerters_data = (Individual * const *)exerters_value->ObjectData();\n\t\t\n\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t{\n\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distance): distance() requires that all exerters be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\n\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distance): distance() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\n\t\t\tdouble distance;\n\t\t\t\n\t\t\tif (periodicity_enabled)\n\t\t\t\tdistance = CalculateDistanceWithPeriodicity(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY, exerter_subpop_data);\n\t\t\telse\n\t\t\t\tdistance = CalculateDistance(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY);\n\t\t\t\n\t\t\tresult_vec->set_float_no_check(distance, exerter_index);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n}\n\n//\t*********************\t– (float)distanceFromPoint(float point, object<Individual> exerters)\n//\nEidosValue_SP InteractionType::ExecuteMethod_distanceFromPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\tEidosValue *exerters_value = p_arguments[1].get();\n\tint exerters_count = exerters_value->Count();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that the interaction be spatial.\" << EidosTerminate();\n\tif (point_value->Count() != spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that point is of length equal to the interaction spatiality.\" << EidosTerminate();\n\t\n\tif (exerters_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// Get the point's coordinates into a double[]\n\tdouble point_data[SLIM_MAX_DIMENSIONALITY];\n\t\n#ifdef __clang_analyzer__\n\t// The static analyzer does not understand some things, so we tell it here\n\tpoint_data[0] = 0;\n\tpoint_data[1] = 0;\n\tpoint_data[2] = 0;\n#endif\n\t\n\tfor (int point_index = 0; point_index < spatiality_; ++point_index)\n\t\tpoint_data[point_index] = point_value->FloatAtIndex_NOCAST(point_index, nullptr);\n\t\n\t// exerters_value is guaranteed to be of length >= 1; let's get the info on it\n\tIndividual * const *exerters_data = (Individual * const *)exerters_value->ObjectData();\n\tIndividual *exerter_first = (Individual *)exerters_data[0];\n\tSubpopulation *exerter_subpop = exerter_first->subpopulation_;\n\tSpecies &exerter_species = exerter_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Generic(exerter_species);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tdouble *exerter_position_data = exerter_subpop_data.positions_;\n\tbool periodicity_enabled = (exerter_subpop_data.periodic_x_ || exerter_subpop_data.periodic_y_ || exerter_subpop_data.periodic_z_);\n\t\n\t// If we're using periodic boundaries, the point supplied has to be within bounds in the periodic dimensions; points outside periodic bounds make no sense\n\tif (periodicity_enabled)\n\t{\n\t\tif ((exerter_subpop_data.periodic_x_ && ((point_data[0] < 0.0) || (point_data[0] > exerter_subpop_data.bounds_x1_))) ||\n\t\t\t(exerter_subpop_data.periodic_y_ && ((point_data[1] < 0.0) || (point_data[1] > exerter_subpop_data.bounds_y1_))) ||\n\t\t\t(exerter_subpop_data.periodic_z_ && ((point_data[2] < 0.0) || (point_data[2] > exerter_subpop_data.bounds_z1_))))\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that coordinates for periodic spatial dimensions fall inside spatial bounaries; use pointPeriodic() to ensure this if necessary.\" << EidosTerminate();\n\t}\n\t\n\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\n\tif (periodicity_enabled)\n\t{\n\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t{\n\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that all exerters be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\n\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\n\t\t\tdouble *ind_position = exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\n\t\t\tresult_vec->set_float_no_check(CalculateDistanceWithPeriodicity(ind_position, point_data, exerter_subpop_data), exerter_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t{\n\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that all exerters be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\n\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_distanceFromPoint): distanceFromPoint() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\n\t\t\tdouble *ind_position = exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\n\t\t\tresult_vec->set_float_no_check(CalculateDistance(ind_position, point_data), exerter_index);\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result_vec);\n}\n\n// a helper function for ExecuteMethod_drawByStrength() that does the draws using a vector of weights\nstatic void DrawByWeights(int draw_count, const double *weights, int n_weights, double weight_total, std::vector<int> &draw_indices)\n{\n\t// Draw individuals; we do this using either the GSL or linear search, depending on the query size\n\t// This choice is somewhat problematic.  I empirically determined at what query size the GSL started\n\t// to pay off despite the overhead of setup with gsl_ran_discrete_preproc().  However, I did that for\n\t// a particular subpopulation size; and the crossover point might also depend upon the distribution\n\t// of strength values in the subpopulation.  I'm not going to worry about this too much, though; it\n\t// is not really answerable in general, and a crossover of 50 seems reasonable.  For small counts,\n\t// linear search won't take that long anyway, and there must be a limit >= 1 where linear is faster\n\t// than the GSL; and for large counts the GSL is surely a win.  Trying to figure out exactly where\n\t// the crossover is in all cases would be overkill; my testing indicates the performance difference\n\t// between the two methods is not really that large anyway.\n\tif (weight_total > 0.0)\n\t{\n\t\tif (draw_count > 50)\t\t// the empirically determined crossover point in performance\n\t\t{\n\t\t\t// Use gsl_ran_discrete() to do the drawing\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tgsl_ran_discrete_t *gsl_lookup = gsl_ran_discrete_preproc(n_weights, weights);\n\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < draw_count; ++draw_index)\n\t\t\t{\n\t\t\t\tint hit_index = (int)gsl_ran_discrete(rng_gsl, gsl_lookup);\n\t\t\t\t\n\t\t\t\tdraw_indices.emplace_back(hit_index);\n\t\t\t}\n\t\t\t\n\t\t\tgsl_ran_discrete_free(gsl_lookup);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Use linear search to do the drawing\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < draw_count; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble the_rose_in_the_teeth = Eidos_rng_uniform_doubleCO(rng_64) * weight_total;\n\t\t\t\tdouble cumulative_weight = 0.0;\n\t\t\t\tint hit_index;\n\t\t\t\t\n\t\t\t\tfor (hit_index = 0; hit_index < n_weights; ++hit_index)\n\t\t\t\t{\n\t\t\t\t\tdouble weight = weights[hit_index];\n\t\t\t\t\t\n\t\t\t\t\tcumulative_weight += weight;\n\t\t\t\t\t\n\t\t\t\t\tif (the_rose_in_the_teeth <= cumulative_weight)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We might overrun the end, due to roundoff error; if so, attribute it to the first non-zero weight entry\n\t\t\t\tif (hit_index >= n_weights)\n\t\t\t\t{\n\t\t\t\t\tfor (hit_index = 0; hit_index < n_weights; ++hit_index)\n\t\t\t\t\t\tif (weights[hit_index] > 0.0)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (hit_index >= n_weights)\n\t\t\t\t\t\thit_index = 0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdraw_indices.emplace_back(hit_index);\n\t\t\t}\n\t\t}\n\t}\n}\n\n//\t*********************\t– (object)drawByStrength(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n//\nEidosValue_SP InteractionType::ExecuteMethod_drawByStrength(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *count_value = p_arguments[1].get();\n\tEidosValue *exerterSubpop_value = p_arguments[2].get();\n\tEidosValue *returnDict_value = p_arguments[3].get();\n\t\n\teidos_logical_t returnDict = returnDict_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tSubpopulation *receiver_subpop = nullptr;\n\t\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (receiver_value->Count() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() requires that the receiver is singleton when returnDict is F; if you want to process multiple receivers in a single call, pass returnDict=T.\" << EidosTerminate();\n\t\t\n\t\tIndividual *receiver = (Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\treceiver_subpop = receiver->subpopulation_;\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object vectors of Individual objects\n\t\tif (receiver_value->Count() == 0)\n\t\t{\n\t\t\t// With no receivers, return an empty Dictionary\n\t\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\t\t\n\t\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_drawByStrength()\");\n\t\t\t\n\t\t\t// objectElement is now retained by result_SP, so we can release it\n\t\t\tdictionary->Release();\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\n\t\treceiver_subpop = ((Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_;\n\t}\n\t\n\t// shared logic for both cases\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_species);\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\n\t// Check the count; note that we do NOT clamp count to exerter_subpop_size, since draws are done with replacement!\n\tint64_t count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() requires count >= 0.\" << EidosTerminate();\n\t\n\tbool has_interaction_callbacks = (exerter_subpop_data.evaluation_interaction_callbacks_.size() != 0);\n\tbool optimize_fixed_interaction_strengths = (!has_interaction_callbacks && (if_type_ == SpatialKernelType::kFixed));\n\t\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (count == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\t\tIndividual *receiver = (Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\n\t\t// Check constraints for the receiver; if the individual is disqualified, no draws can occur and the return is empty\n\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\tif (spatiality_ == 0)\n\t\t{\n\t\t\t// Non-spatial case; no distances used.  We have to worry about exerter constraints; they are not handled for us.\n\t\t\t// BCH 5/14/2023: We call ApplyInteractionCallbacks() below, so if this code ever goes parallel it\n\t\t\t// should stay single-threaded if/when any interaction() callbacks are present!\n\t\t\tslim_popsize_t receiver_index = ((exerter_subpop == receiver->subpopulation_) && (receiver->index_ >= 0) ? receiver->index_ : -1);\n\t\t\tstd::vector<SLiMEidosBlock*> &callbacks = exerter_subpop_data.evaluation_interaction_callbacks_;\n\t\t\t\n\t\t\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\tdouble total_interaction_strength = 0.0;\n\t\t\tstd::vector<double> cached_strength;\n\t\t\tstd::vector<Individual *> &exerters = exerter_subpop->parent_individuals_;\n\t\t\t\n\t\t\tfor (slim_popsize_t exerter_index_in_subpop = 0; exerter_index_in_subpop < exerter_subpop_size; ++exerter_index_in_subpop)\n\t\t\t{\n\t\t\t\tIndividual *exerter = exerters[exerter_index_in_subpop];\n\t\t\t\tdouble strength = 0;\n\t\t\t\t\n\t\t\t\tif ((exerter_index_in_subpop != receiver_index) && CheckIndividualConstraints(exerter, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\tstrength = ApplyInteractionCallbacks(receiver, exerter, if_param1_, NAN, callbacks);\t// hard-coding interaction function \"f\" (SpatialKernelType::kFixed), which is required\n\t\t\t\t\n\t\t\t\ttotal_interaction_strength += strength;\n\t\t\t\tcached_strength.emplace_back(strength);\n\t\t\t}\n\t\t\t\n\t\t\tif (total_interaction_strength > 0.0)\n\t\t\t{\n\t\t\t\tstd::vector<int> strength_indices;\n\t\t\t\t\n\t\t\t\tresult_vec->resize_no_initialize(count);\n\t\t\t\tDrawByWeights((int)count, cached_strength.data(), exerter_subpop_size, total_interaction_strength, strength_indices);\n\t\t\t\t\n\t\t\t\tfor (size_t result_index = 0; result_index < strength_indices.size(); ++result_index)\n\t\t\t\t{\n\t\t\t\t\tint strength_index = strength_indices[result_index];\n\t\t\t\t\tIndividual *chosen_individual = exerters[strength_index];\n\t\t\t\t\t\n\t\t\t\t\tresult_vec->set_object_element_no_check_NORR(chosen_individual, result_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Spatial case; we use the k-d tree to get strengths for all neighbors.\n\t\t\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\t\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\tEidosValue_SP result_vec_SP(result_vec);\n\t\t\t\n\t\t\t// If there are no exerters satisfying constraints, short-circuit\n\t\t\tif (!kd_root_EXERTERS)\n\t\t\t\treturn result_vec_SP;\n\t\t\t\n\t\t\tif (optimize_fixed_interaction_strengths)\n\t\t\t{\n\t\t\t\t// Optimized case: fixed interaction strength, no callbacks, so we can do uniform draws using presences only\n\t\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kPresences);\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tFillSparseVectorForReceiverPresences(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, /* constraints_active */ true);\n\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\tconst uint32_t *columns;\n\t\t\t\t\t\n\t\t\t\t\tsv->Presences(&nnz, &columns);\n\t\t\t\t\t\n\t\t\t\t\tif (nnz > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::vector<Individual *> &exerters = exerter_subpop->parent_individuals_;\n\t\t\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_vec->resize_no_initialize(count);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t result_index = 0; result_index < count; ++result_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint presence_index = Eidos_rng_interval_uint32(rng_32, nnz);\t// equal probability for each exerter\n\t\t\t\t\t\t\tuint32_t exerter_index = columns[presence_index];\n\t\t\t\t\t\t\tIndividual *chosen_individual = exerters[exerter_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tresult_vec->set_object_element_no_check_NORR(chosen_individual, result_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (...) {\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\treturn result_vec_SP;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case, getting strengths and doing weighted draws\n\t\t\t\t// BCH 5/14/2023: The call to FillSparseVectorForReceiverStrengths() means we run interaction() callbacks,\n\t\t\t\t// so if this code is ever parallelized, it should stay single-threaded when callbacks are enabled.\n\t\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\n\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\tconst uint32_t *columns;\n\t\t\t\t\tconst sv_value_t *strengths;\n\t\t\t\t\tstd::vector<double> double_strengths;\t// needed by DrawByWeights() for gsl_ran_discrete_preproc()\n\t\t\t\t\t\n\t\t\t\t\tstrengths = sv->Strengths(&nnz, &columns);\n\t\t\t\t\t\n\t\t\t\t\t// Total the interaction strengths, and gather a vector of strengths as doubles\n\t\t\t\t\tdouble total_interaction_strength = 0.0;\n\t\t\t\t\t\n\t\t\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tsv_value_t strength = strengths[col_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\ttotal_interaction_strength += strength;\n\t\t\t\t\t\tdouble_strengths.emplace_back((double)strength);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Draw individuals\n\t\t\t\t\tif (total_interaction_strength > 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::vector<int> strength_indices;\n\t\t\t\t\t\tstd::vector<Individual *> &exerters = exerter_subpop->parent_individuals_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_vec->resize_no_initialize(count);\n\t\t\t\t\t\tDrawByWeights((int)count, double_strengths.data(), nnz, total_interaction_strength, strength_indices);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (size_t result_index = 0; result_index < strength_indices.size(); ++result_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint strength_index = strength_indices[result_index];\n\t\t\t\t\t\t\tIndividual *chosen_individual = exerters[columns[strength_index]];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tresult_vec->set_object_element_no_check_NORR(chosen_individual, result_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (...) {\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\treturn result_vec_SP;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object vectors of Individual objects\n\t\t// We start by making a Dictionary with an empty Individual vector for each receiver\n\t\tif (spatiality_ == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() supports returning a Dictionary of results, with returnDict=T, only in the spatial case.\" << EidosTerminate();\n\t\t\n\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\tint receivers_count = receiver_value->Count();\n\t\tEidosValue_Object **result_vectors = (EidosValue_Object **)malloc(receivers_count * sizeof(EidosValue_Object *));\n\t\t\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tEidosValue_Object *empty_individuals_vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class);\n\t\t\t\n\t\t\tdictionary->SetKeyValue_IntegerKeys(receiver_index, EidosValue_SP(empty_individuals_vec));\n\t\t\tresult_vectors[receiver_index] = empty_individuals_vec;\n\t\t}\n\t\t\n\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_drawByStrength()\");\n\t\t\n\t\t// objectElement is now retained by result_SP, so we can release it\n\t\tdictionary->Release();\n\t\t\n\t\tif ((count > 0) && (exerter_subpop_size > 0))\t// BCH 5/24/2023: if the exerter subpop is empty, no individuals are drawn; short-circuit\n\t\t{\n\t\t\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\t\t\n\t\t\t// If there are no exerters satisfying constraints, short-circuit\n\t\t\tif (!kd_root_EXERTERS)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\treturn result_SP;\n\t\t\t}\n\t\t\t\n\t\t\tbool saw_error_1 = false, saw_error_2 = false, saw_error_3 = false, saw_error_4 = false;\n\t\t\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\t\tIndividual * const *receiver_data = (Individual * const *)receiver_value->ObjectData();\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_DRAWBYSTRENGTH);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(gEidos_RNG_PERTHREAD, receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_EXERTERS, optimize_fixed_interaction_strengths) firstprivate(receiver_data, result_vectors, count, exerter_subpop_size) reduction(||: saw_error_1) reduction(||: saw_error_2) reduction(||: saw_error_3) reduction(||: saw_error_4) if(!has_interaction_callbacks && (receivers_count >= EIDOS_OMPMIN_DRAWBYSTRENGTH)) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tIndividual *receiver = (Individual *)receiver_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Check constraints for the receiver; if the individual is disqualified, there are no candidates to draw from\n\t\t\t\ttry {\n\t\t\t\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises; protected\n\t\t\t\t\t\tcontinue;\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error_4 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\n\t\t\t\tEidosValue_Object *result_vec = result_vectors[receiver_index];\n\t\t\t\t\n\t\t\t\tif (optimize_fixed_interaction_strengths)\n\t\t\t\t{\n\t\t\t\t\t// Optimized case: fixed interaction strength, no callbacks, so we can do uniform draws using presences only\n\t\t\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kPresences);\n\t\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tFillSparseVectorForReceiverPresences(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, /* constraints_active */ true);\n\t\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\t\tconst uint32_t *columns;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsv->Presences(&nnz, &columns);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (nnz > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::vector<Individual *> &exerters = exerter_subpop->parent_individuals_;\n\t\t\t\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tresult_vec->resize_no_initialize(count);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int64_t result_index = 0; result_index < count; ++result_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint presence_index = Eidos_rng_interval_uint32(rng_32, nnz);\t// equal probability for each exerter\n\t\t\t\t\t\t\t\tuint32_t exerter_index = columns[presence_index];\n\t\t\t\t\t\t\t\tIndividual *chosen_individual = exerters[exerter_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tresult_vec->set_object_element_no_check_NORR(chosen_individual, result_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (...) {\n\t\t\t\t\t\tsaw_error_3 = true;\n\t\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// General case, getting strengths and doing weighted draws\n\t\t\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\t\t\t\n\t\t\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\t\t\ttry {\n\t\t\t\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\t\t// protected from running interaction() callbacks in parallel, above\n\t\t\t\t\t} catch (...) {\n\t\t\t\t\t\tsaw_error_3 = true;\n\t\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\tconst uint32_t *columns;\n\t\t\t\t\tconst sv_value_t *strengths;\n\t\t\t\t\tstd::vector<double> double_strengths;\t// needed by DrawByWeights() for gsl_ran_discrete_preproc()\n\t\t\t\t\t\n\t\t\t\t\tstrengths = sv->Strengths(&nnz, &columns);\n\t\t\t\t\t\n\t\t\t\t\t// Total the interaction strengths, and gather a vector of strengths as doubles\n\t\t\t\t\tdouble total_interaction_strength = 0.0;\n\t\t\t\t\t\n\t\t\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tsv_value_t strength = strengths[col_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\ttotal_interaction_strength += strength;\n\t\t\t\t\t\tdouble_strengths.emplace_back((double)strength);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Draw individuals\n\t\t\t\t\tif (total_interaction_strength > 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::vector<int> strength_indices;\n\t\t\t\t\t\tstd::vector<Individual *> &exerters = exerter_subpop->parent_individuals_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_vec->resize_no_initialize(count);\n\t\t\t\t\t\tDrawByWeights((int)count, double_strengths.data(), nnz, total_interaction_strength, strength_indices);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (size_t result_index = 0; result_index < strength_indices.size(); ++result_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint strength_index = strength_indices[result_index];\n\t\t\t\t\t\t\tIndividual *chosen_individual = exerters[columns[strength_index]];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tresult_vec->set_object_element_no_check_NORR(chosen_individual, result_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// deferred raises, for OpenMP compatibility\n\t\t\tif (saw_error_1)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\t}\n\t\t\tif (saw_error_2)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\t\t}\n\t\t\tif (saw_error_3)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): an exception was caught inside a parallel region.\" << EidosTerminate();\n\t\t\t}\n\t\t\tif (saw_error_4)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_drawByStrength): drawByStrength() tested a tag or tagL constraint, but a receiver's value for that property was not defined (had not been set).\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(result_vectors);\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t- (void)evaluate(io<Subpopulation> subpops)\n//\nEidosValue_SP InteractionType::ExecuteMethod_evaluate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *subpops_value = p_arguments[0].get();\n\t\n\t// TIMING RESTRICTION\n\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage2GenerateOffspring) ||\n\t\t(community_.CycleStage() == SLiMCycleStage::kNonWFStage1GenerateOffspring) ||\n\t\t(community_.CycleStage() == SLiMCycleStage::kNonWFStage4SurvivalSelection))\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_evaluate): evaluate() may not be called during the offspring generation or viability/survival cycle stages.\" << EidosTerminate();\n\t\n\t// Get the requested subpops\n\tint requested_subpop_count = subpops_value->Count();\n\t\t\n\tfor (int requested_subpop_index = 0; requested_subpop_index < requested_subpop_count; ++requested_subpop_index)\n\t\tEvaluateSubpopulation(SLiM_ExtractSubpopulationFromEidosValue_io(subpops_value, requested_subpop_index, &community_, nullptr, \"evaluate()\"));\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (integer)interactingNeighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_interactingNeighborCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BCH 11/2/2023: Note that this method is now almost identical to ExecuteMethod_neighborCount()\n\tEidosValue *receivers_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\tint receivers_count = receivers_value->Count();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactingNeighborCount): interactingNeighborCount() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\tif (receivers_count == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *receiver_subpop = ((Individual *)receivers_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_;\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_subpop->species_);\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\n\t// If there are no exerters satisfying constraints, short-circuit\n\tif (!kd_root_EXERTERS)\n\t{\n\t\t// If the exerter subpop is empty then all count values for the receivers are zero\n\t\tif (receivers_count == 1)\n\t\t{\n\t\t\treturn gStaticEidosValue_Integer0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Int *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(receivers_count);\n\t\t\t\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t\tresult_vec->set_int_no_check(0, receiver_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t}\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\tIndividual * const *receivers_data = (Individual * const *)receivers_value->ObjectData();\n\t\n\tif (receivers_count == 1)\n\t{\n\t\t// Just one value, so we can return a singleton and skip some work\n\t\tIndividual *receiver = (Individual *)receivers_data[0];\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactingNeighborCount): interactingNeighborCount() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\n\t\t// Check constraints for the receiver; if the individual is disqualified, the count is zero\n\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\t\treturn gStaticEidosValue_Integer0;\n\t\t\n\t\t// Find the neighbors\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tslim_popsize_t focal_individual_index = (exerter_subpop == receiver_subpop) ? receiver_index_in_subpop : -1;\n\t\tint neighborCount;\n\t\t\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: neighborCount = CountNeighbors_1(kd_root_EXERTERS, receiver_position, focal_individual_index);\t\t\tbreak;\n\t\t\tcase 2: neighborCount = CountNeighbors_2(kd_root_EXERTERS, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\tcase 3: neighborCount = CountNeighbors_3(kd_root_EXERTERS, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\tdefault: neighborCount = 0; break;\t// unsupported value\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(neighborCount));\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(receivers_count);\n\t\tbool saw_error_1 = false, saw_error_2 = false, saw_error_3 = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_INTNEIGHCOUNT);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_EXERTERS) firstprivate(receivers_data, result_vec) reduction(||: saw_error_1) reduction(||: saw_error_2) reduction(||: saw_error_3) if(receivers_count >= EIDOS_OMPMIN_INTNEIGHCOUNT) num_threads(thread_count)\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tIndividual *receiver = receivers_data[receiver_index];\n\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\n\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t{\n\t\t\t\tsaw_error_1 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t{\n\t\t\t\tsaw_error_2 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check constraints for the receiver; if the individual is disqualified, the count is zero\n\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\ttry {\n\t\t\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises; protected\n\t\t\t\t{\n\t\t\t\t\tresult_vec->set_int_no_check(0, receiver_index);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\tsaw_error_3 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Find the neighbors\n\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\tslim_popsize_t focal_individual_index = (exerter_subpop == receiver_subpop) ? receiver_index_in_subpop : -1;\n\t\t\tint neighborCount;\n\t\t\t\n\t\t\tswitch (spatiality_)\n\t\t\t{\n\t\t\t\tcase 1: neighborCount = CountNeighbors_1(kd_root_EXERTERS, receiver_position, focal_individual_index);\t\t\tbreak;\n\t\t\t\tcase 2: neighborCount = CountNeighbors_2(kd_root_EXERTERS, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\t\tcase 3: neighborCount = CountNeighbors_3(kd_root_EXERTERS, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\t\tdefault: neighborCount = 0; break;\t// unsupported value\n\t\t\t}\n\t\t\t\n\t\t\tresult_vec->set_int_no_check(neighborCount, receiver_index);\n\t\t}\n\t\t\n\t\t// deferred raises, for OpenMP compatibility\n\t\tif (saw_error_1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactingNeighborCount): interactingNeighborCount() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\tif (saw_error_2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactingNeighborCount): interactingNeighborCount() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\tif (saw_error_3)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactingNeighborCount): interactingNeighborCount() tested a tag or tagL constraint, but a receiver's value for that property was not defined (had not been set).\" << EidosTerminate();\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (float)localPopulationDensity(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_localPopulationDensity(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *receivers_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\tint receivers_count = receivers_value->Count();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() requires that the interaction be spatial.\" << EidosTerminate();\n\tif (spatiality_ == 3)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() does not support the 'xyz' case yet.  If you need this functionality, please file a GitHub issue.\" << EidosTerminate();\n\t\n\tif (receivers_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// receivers_value is guaranteed to have at least one value\n\tIndividual * const *receivers_data = (Individual * const *)receivers_value->ObjectData();\n\tIndividual *first_receiver = receivers_data[0];\n\tSubpopulation *receiver_subpop = first_receiver->subpopulation_;\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_subpop->species_);\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tif (receiver_subpop != exerter_subpop)\n\t\tif ((receiver_subpop->bounds_x0_ != exerter_subpop->bounds_x0_) || (receiver_subpop->bounds_x1_ != exerter_subpop->bounds_x1_) ||\n\t\t\t(receiver_subpop->bounds_y0_ != exerter_subpop->bounds_y0_) || (receiver_subpop->bounds_y1_ != exerter_subpop->bounds_y1_) ||\n\t\t\t(receiver_subpop->bounds_z0_ != exerter_subpop->bounds_z0_) || (receiver_subpop->bounds_z1_ != exerter_subpop->bounds_z1_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() requires that the receiver and exerter subpopulations have identical bounds.\" << EidosTerminate();\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\n\t// If there are no exerters satisfying constraints, short-circuit\n\tif (!kd_root_EXERTERS)\n\t{\n\t\t// If the exerter subpop is empty then all density values for the receivers are zero (note that we\n\t\t// already handled the case of receivers_count == 0 above, so the receiver is not in the exerter subpop)\n\t\tif (receivers_count == 1)\n\t\t{\n\t\t\treturn gStaticEidosValue_Float0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(receivers_count);\n\t\t\t\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t\tresult_vec->set_float_no_check(0, receiver_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t}\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\n\tdouble strength_for_zero_distance = CalculateStrengthNoCallbacks(0.0);\t// probably always if_param1_, but let's not hard-code that...\n\tbool has_interaction_callbacks = (exerter_subpop_data.evaluation_interaction_callbacks_.size() != 0);\n\t\n\tif (has_interaction_callbacks)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() does not allow interaction() callbacks, since they cannot be integrated to compute density.\" << EidosTerminate();\n\t\n\t// Subcontract to ExecuteMethod_clippedIntegral(); this handles all the spatiality crap for us\n\t// note that we pass our own parameters through to clippedIntegral()!  So our APIs need to be the same!\n\t// Actually, we now have an extra parameter, exerterSubpop(), compared to clippedIntegral(); but we\n\t// do not need it to use that parameter (because we require identical bounds above), so it's OK.\n\tEidosValue_SP clipped_integrals_SP = ExecuteMethod_clippedIntegral(p_method_id, p_arguments, p_interpreter);\n\tEidosValue *clipped_integrals = clipped_integrals_SP.get();\n\tconst double *clipped_integrals_data = clipped_integrals->FloatData();\n\t\n\t// Decide whether we can use our optimized case below\n\tbool optimize_fixed_interaction_strengths = (!has_interaction_callbacks && (if_type_ == SpatialKernelType::kFixed));\n\t\n\tif (receivers_count == 1)\n\t{\n\t\t// Just one value, so we can return a singleton and skip some work\n\t\tslim_popsize_t receiver_index_in_subpop = first_receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\n\t\t// Check constraints for the receiver; if the individual is disqualified, the local density of interacters is zero\n\t\tif (!CheckIndividualConstraints(first_receiver, receiver_constraints_))\t\t// potentially raises\n\t\t\treturn gStaticEidosValue_Float0;\n\t\t\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tdouble total_strength;\n\t\t\n\t\tif (optimize_fixed_interaction_strengths)\n\t\t{\n\t\t\t// Optimized case for fixed interaction strength and no callbacks\n\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kPresences);\n\t\t\t\n\t\t\ttry {\n\t\t\t\tFillSparseVectorForReceiverPresences(sv, first_receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, /* constraints_active */ true);\n\t\t\t\t\n\t\t\t\tuint32_t nnz;\n\t\t\t\tsv->Presences(&nnz);\n\t\t\t\t\n\t\t\t\ttotal_strength = nnz * if_param1_;\n\t\t\t} catch (...) {\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\tthrow;\n\t\t\t}\n\t\t\t\n\t\t\tFreeSparseVector(sv);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// General case, totalling strengths\n\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\t\n\t\t\ttry {\n\t\t\t\tFillSparseVectorForReceiverStrengths(sv, first_receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\t\t// singleton case, not parallel\n\t\t\t\t\n\t\t\t\t// Get the sparse vector data\n\t\t\t\tuint32_t nnz;\n\t\t\t\tconst sv_value_t *strengths;\n\t\t\t\t\n\t\t\t\tstrengths = sv->Strengths(&nnz);\n\t\t\t\t\n\t\t\t\t// Total the interaction strengths\n\t\t\t\ttotal_strength = 0.0;\n\t\t\t\t\n\t\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t\ttotal_strength += strengths[col_index];\n\t\t\t} catch (...) {\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\tthrow;\n\t\t\t}\n\t\t\t\n\t\t\tFreeSparseVector(sv);\n\t\t}\n\t\t\n\t\t// Add the interaction strength for the focal individual to the focal point, since it counts for density\n\t\tif (receiver_subpop == exerter_subpop)\n\t\t\ttotal_strength += strength_for_zero_distance;\n\t\t\n\t\t// Divide by the corresponding clipped integral to get density\n\t\ttotal_strength /= clipped_integrals->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(total_strength));\n\t}\n\telse\n\t{\n\t\t// Loop over the requested individuals and get the totals\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(receivers_count);\n\t\tbool saw_error_1 = false, saw_error_2 = false, saw_error_3 = false, saw_error_4 = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_LOCALPOPDENSITY);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_EXERTERS, strength_for_zero_distance, clipped_integrals_data, optimize_fixed_interaction_strengths) firstprivate(receivers_data, result_vec) reduction(||: saw_error_1) reduction(||: saw_error_2) reduction(||: saw_error_3) reduction(||: saw_error_4) if(!has_interaction_callbacks && (receivers_count >= EIDOS_OMPMIN_LOCALPOPDENSITY)) num_threads(thread_count)\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tIndividual *receiver = receivers_data[receiver_index];\n\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\n\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t{\n\t\t\t\tsaw_error_1 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t{\n\t\t\t\tsaw_error_2 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check constraints for the receiver; if the individual is disqualified, the local density of interacters is zero\n\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\ttry {\n\t\t\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises; protected\n\t\t\t\t{\n\t\t\t\t\tresult_vec->set_float_no_check(0, receiver_index);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\tsaw_error_3 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\tdouble total_strength;\n\t\t\tSparseVector *sv;\n\t\t\t\n\t\t\tif (optimize_fixed_interaction_strengths)\n\t\t\t{\n\t\t\t\t// Optimized case for fixed interaction strength and no callbacks\n\t\t\t\tsv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kPresences);\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tFillSparseVectorForReceiverPresences(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, /* constraints_active */ true);\n\t\t\t\t\t\n\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\tsv->Presences(&nnz);\n\t\t\t\t\ttotal_strength = nnz * if_param1_;\n\t\t\t\t} catch (...) {\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\tsaw_error_4 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case, totalling strengths\n\t\t\t\tsv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\t\t// we do not allow interaction() callbacks, so this should not raise\n\t\t\t\t\t\n\t\t\t\t\t// Get the sparse vector data\n\t\t\t\t\tuint32_t nnz;\n\t\t\t\t\tconst sv_value_t *strengths;\n\t\t\t\t\t\n\t\t\t\t\tstrengths = sv->Strengths(&nnz);\n\t\t\t\t\t\n\t\t\t\t\t// Total the interaction strengths\n\t\t\t\t\ttotal_strength = 0.0;\n\t\t\t\t\t\n\t\t\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t\t\ttotal_strength += strengths[col_index];\n\t\t\t\t} catch (...) {\n\t\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\t\tsaw_error_4 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Add the interaction strength for the focal individual to the focal point, since it counts for density\n\t\t\tif (receiver_subpop == exerter_subpop)\n\t\t\t\ttotal_strength += strength_for_zero_distance;\n\t\t\t\n\t\t\t// Divide by the corresponding clipped integral to get density\n\t\t\ttotal_strength /= clipped_integrals_data[receiver_index];\n\t\t\tresult_vec->set_float_no_check(total_strength, receiver_index);\n\t\t\t\n\t\t\tFreeSparseVector(sv);\n\t\t}\n\t\t\n\t\t// deferred raises, for OpenMP compatibility\n\t\tif (saw_error_1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\tif (saw_error_2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\tif (saw_error_3)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): localPopulationDensity() tested a tag or tagL constraint, but a receiver's value for that property was not defined (had not been set).\" << EidosTerminate();\n\t\tif (saw_error_4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_localPopulationDensity): an exception was caught inside a parallel region.\" << EidosTerminate();\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n}\n\n//\n//\t*********************\t– (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\nEidosValue_SP InteractionType::ExecuteMethod_interactionDistance(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *exerters_value = p_arguments[1].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactionDistance): interactionDistance() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\tIndividual *receiver = (Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\n\tif (receiver_index_in_subpop < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactionDistance): interactionDistance() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\n\tSubpopulation *receiver_subpop = receiver->subpopulation_;\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_species);\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\n\t// figure out the exerter subpopulation and get info on it\n\tbool exerters_value_NULL = (exerters_value->Type() == EidosValueType::kValueNULL);\n\tint exerters_count = exerters_value->Count();\n\t\n\tif ((exerters_count == 0) && !exerters_value_NULL)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tSubpopulation *exerter_subpop = (exerters_value_NULL ? receiver_subpop : ((Individual *)exerters_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_);\n\t\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\n\t// set up our return value\n\tif (exerters_value_NULL)\n\t\texerters_count = exerter_subpop_size;\n\t\n\t// Check constraints the receiver; if the individual is disqualified, the distance to each exerter is infinity\n\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\tgoto returnAllInfinity;\n\t\n\tif (exerters_value_NULL)\n\t{\n\t\t// NULL means return distances from individuals1 (which must be singleton) to all individuals in the subpopulation\n\t\t// We initialize the return vector to INFINITY, and fill in non-infinite values from the sparse vector\n\t\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\t\n\t\t// If the k-d tree has no qualifying exerters, we return all infinity\n\t\tif (!kd_root_EXERTERS)\n\t\t\tgoto returnAllInfinity;\n\t\t\n\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kDistances);\n\t\tuint32_t nnz;\n\t\tconst uint32_t *columns;\n\t\tconst sv_value_t *distances;\n\t\t\n\t\ttry {\n\t\t\tFillSparseVectorForReceiverDistances(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, /* constraints_active */ true);\n\t\t\tdistances = sv->Distances(&nnz, &columns);\n\t\t\t\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\t\tEidosValue_SP result_SP(result_vec);\n\t\t\tdouble *result_ptr = result_vec->data_mutable();\n\t\t\t\n\t\t\tfor (int exerter_index = 0; exerter_index < exerter_subpop_size; ++exerter_index)\n\t\t\t\t*(result_ptr + exerter_index) = INFINITY;\n\t\t\t\n\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t*(result_ptr + columns[col_index]) = distances[col_index];\n\t\t\t\n\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\treturn result_SP;\n\t\t} catch (...) {\n\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\tthrow;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Otherwise, receiver is singleton, and exerters is any length, so we loop over exerters\n\t\t// To avoid searching through sparse vector results for each exerter, we calculate distances\n\t\t// ourselves for each receiver-exerter pair, which is a bit complicated - we need to worry\n\t\t// about constraints, self-interactions, max distance, callbacks, etc., which SparseVector\n\t\t// handles for most client code.\n\t\tIndividual * const *exerters_data = (Individual * const *)exerters_value->ObjectData();\n\t\tdouble *exerter_position_data = exerter_subpop_data.positions_;\n\t\tbool periodicity_enabled = (exerter_subpop_data.periodic_x_ || exerter_subpop_data.periodic_y_ || exerter_subpop_data.periodic_z_);\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\tEidosValue_SP result_SP(result_vec);\n\t\t\n\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t{\n\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactionDistance): interactionDistance() requires that all exerters be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\n\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_interactionDistance): interactionDistance() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((exerter == receiver) || !CheckIndividualConstraints(exerter, exerter_constraints_))\n\t\t\t{\n\t\t\t\t// self-interactions and constraints result in an interaction distance of INF\n\t\t\t\tresult_vec->set_float_no_check(INFINITY, exerter_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdouble distance;\n\t\t\t\t\n\t\t\t\tif (periodicity_enabled)\n\t\t\t\t\tdistance = CalculateDistanceWithPeriodicity(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY, exerter_subpop_data);\n\t\t\t\telse\n\t\t\t\t\tdistance = CalculateDistance(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY);\n\t\t\t\t\n\t\t\t\tif (distance > max_distance_)\n\t\t\t\t{\n\t\t\t\t\t// interactions beyond the maximum interaction distance also produce INF\n\t\t\t\t\tresult_vec->set_float_no_check(INFINITY, exerter_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult_vec->set_float_no_check(distance, exerter_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\treturnAllInfinity:\n\t{\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\tEidosValue_SP result_SP(result_vec);\n\t\tdouble *result_ptr = result_vec->data_mutable();\n\t\t\n\t\tfor (int exerter_index = 0; exerter_index < exerter_subpop_size; ++exerter_index)\n\t\t\t*(result_ptr + exerter_index) = INFINITY;\n\t\t\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t– (object)nearestInteractingNeighbors(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n//\nEidosValue_SP InteractionType::ExecuteMethod_nearestInteractingNeighbors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BCH 11/2/2023: Note that this method is now almost identical to ExecuteMethod_nearestNeighbors()\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *count_value = p_arguments[1].get();\n\tEidosValue *exerterSubpop_value = p_arguments[2].get();\n\tEidosValue *returnDict_value = p_arguments[3].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\teidos_logical_t returnDict = returnDict_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tSubpopulation *receiver_subpop = nullptr;\n\tIndividual * const *receiver_data = (Individual * const *)receiver_value->ObjectData();\n\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (receiver_value->Count() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires that the receiver is singleton when returnDict is F; if you want to process multiple receivers in a single call, pass returnDict=T.\" << EidosTerminate();\n\t\t\n\t\tIndividual *receiver = receiver_data[0];\n\t\t\n\t\treceiver_subpop = receiver->subpopulation_;\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object with vectors of Individual objects\n\t\tif (receiver_value->Count() == 0)\n\t\t{\n\t\t\t// With no receivers, return an empty Dictionary\n\t\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\t\t\n\t\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_nearestInteractingNeighbors()\");\n\t\t\t\n\t\t\t// objectElement is now retained by result_SP, so we can release it\n\t\t\tdictionary->Release();\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\n\t\treceiver_subpop = receiver_data[0]->subpopulation_;\n\t}\n\t\n\t// shared logic for both cases\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_species);\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\t// Check the count\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tint64_t count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires count >= 0.\" << EidosTerminate();\n\t\n\tif (count > exerter_subpop_size)\n\t\tcount = exerter_subpop_size;\n\t\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (count == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\t\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\t\tIndividual *receiver = receiver_data[0];\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\n\t\t// Check constraints for the receiver; if the individual is disqualified, there are no interacting neighbors\n\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\t// Find the neighbors\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\t\n\t\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\tif (count < exerter_subpop_size)\t\t// reserve only if we are finding fewer than every possible neighbor\n\t\t\tresult_vec->reserve((int)count);\n\t\t\n\t\tFindNeighbors(exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.kd_node_count_EXERTERS_, receiver_position, (int)count, *result_vec, receiver, /* constraints_active */ true);\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object vectors of Individual objects\n\t\t// We start by making a Dictionary with an empty Individual vector for each receiver\n\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\tint receivers_count = receiver_value->Count();\n\t\tEidosValue_Object **result_vectors = (EidosValue_Object **)malloc(receivers_count * sizeof(EidosValue_Object *));\n\t\t\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tEidosValue_Object *empty_individuals_vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class);\n\t\t\t\n\t\t\tdictionary->SetKeyValue_IntegerKeys(receiver_index, EidosValue_SP(empty_individuals_vec));\n\t\t\tresult_vectors[receiver_index] = empty_individuals_vec;\n\t\t}\n\t\t\n\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_nearestInteractingNeighbors()\");\n\t\t\n\t\t// objectElement is now retained by result_SP, so we can release it\n\t\tdictionary->Release();\n\t\t\n\t\tif (count > 0)\n\t\t{\n\t\t\tbool saw_error_1 = false, saw_error_2 = false, saw_error_3 = false;\n\t\t\t\n\t\t\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\t\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_NEARESTINTNEIGH);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_EXERTERS) firstprivate(receiver_data, result_vectors, count, exerter_subpop_size) reduction(||: saw_error_1) reduction(||: saw_error_2) reduction(||: saw_error_3) if(receivers_count >= EIDOS_OMPMIN_NEARESTINTNEIGH) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tIndividual *receiver = receiver_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Check constraints for the receiver; if the individual is disqualified, there are no interacting neighbors\n\t\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\t\ttry {\n\t\t\t\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises; protected\n\t\t\t\t\t\tcontinue;\n\t\t\t\t} catch (...) {\n\t\t\t\t\tsaw_error_3 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\n\t\t\t\tEidosValue_Object *result_vec = result_vectors[receiver_index];\n\t\t\t\t\n\t\t\t\tif (count < exerter_subpop_size)\t\t// reserve only if we are finding fewer than every possible neighbor\n\t\t\t\t\tresult_vec->reserve((int)count);\n\t\t\t\t\n\t\t\t\tFindNeighbors(exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.kd_node_count_EXERTERS_, receiver_position, (int)count, *result_vec, receiver, /* constraints_active */ true);\n\t\t\t}\n\t\t\t\n\t\t\t// deferred raises, for OpenMP compatibility\n\t\t\tif (saw_error_1)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\t}\n\t\t\tif (saw_error_2)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\t\t}\n\t\t\tif (saw_error_3)\n\t\t\t{\n\t\t\t\tfree(result_vectors);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestInteractingNeighbors): nearestInteractingNeighbors() tested a tag or tagL constraint, but a receiver's value for that property was not defined (had not been set).\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(result_vectors);\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t– (object)nearestNeighbors(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n//\nEidosValue_SP InteractionType::ExecuteMethod_nearestNeighbors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BCH 11/2/2023: Note that this method is now almost identical to ExecuteMethod_nearestInteractingNeighbors()\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *count_value = p_arguments[1].get();\n\tEidosValue *exerterSubpop_value = p_arguments[2].get();\n\tEidosValue *returnDict_value = p_arguments[3].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\teidos_logical_t returnDict = returnDict_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tSubpopulation *receiver_subpop = nullptr;\n\tIndividual * const *receiver_data = (Individual * const *)receiver_value->ObjectData();\n\t\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (receiver_value->Count() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires that the receiver is singleton when returnDict is F; if you want to process multiple receivers in a single call, pass returnDict=T.\" << EidosTerminate();\n\t\t\n\t\tIndividual *receiver = receiver_data[0];\n\t\t\n\t\treceiver_subpop = receiver->subpopulation_;\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object with vectors of Individual objects\n\t\tif (receiver_value->Count() == 0)\n\t\t{\n\t\t\t// With no receivers, return an empty Dictionary\n\t\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\t\t\n\t\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_nearestNeighbors()\");\n\t\t\t\n\t\t\t// objectElement is now retained by result_SP, so we can release it\n\t\t\tdictionary->Release();\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\n\t\treceiver_subpop = receiver_data[0]->subpopulation_;\n\t}\n\t\n\t// shared logic for both cases\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Generic(receiver_species);\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\t// Check the count\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tint64_t count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires count >= 0.\" << EidosTerminate();\n\t\n\tif (count > exerter_subpop_size)\n\t\tcount = exerter_subpop_size;\n\t\n\tif (!returnDict)\n\t{\n\t\t// This is the single-threaded, single-receiver case; it returns a vector of Individual objects\n\t\tif (count == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\t\tIndividual *receiver = receiver_data[0];\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\n\t\t// Find the neighbors\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\tSLiM_kdNode *kd_root_ALL = EnsureKDTreePresent_ALL(exerter_subpop, exerter_subpop_data);\n\t\t\n\t\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\n\t\tif (count < exerter_subpop_size)\t\t// reserve only if we are finding fewer than every possible neighbor\n\t\t\tresult_vec->reserve((int)count);\n\t\t\n\t\tFindNeighbors(exerter_subpop, kd_root_ALL, exerter_subpop_data.kd_node_count_ALL_, receiver_position, (int)count, *result_vec, receiver, /* constraints_active */ false);\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n\telse\n\t{\n\t\t// This is the multi-threaded, multi-receiver case; it returns a Dictionary object vectors of Individual objects\n\t\t// We start by making a Dictionary with an empty Individual vector for each receiver\n\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\tint receivers_count = receiver_value->Count();\n\t\tEidosValue_Object **result_vectors = (EidosValue_Object **)malloc(receivers_count * sizeof(EidosValue_Object *));\n\t\t\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tEidosValue_Object *empty_individuals_vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class);\n\t\t\t\n\t\t\tdictionary->SetKeyValue_IntegerKeys(receiver_index, EidosValue_SP(empty_individuals_vec));\n\t\t\tresult_vectors[receiver_index] = empty_individuals_vec;\n\t\t}\n\t\t\n\t\tdictionary->ContentsChanged(\"InteractionType::ExecuteMethod_nearestNeighbors()\");\n\t\t\n\t\t// objectElement is now retained by result_SP, so we can release it\n\t\tdictionary->Release();\n\t\t\n\t\tif (count > 0)\n\t\t{\n\t\t\tbool saw_error_1 = false, saw_error_2 = false;\n\t\t\t\n\t\t\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\t\tSLiM_kdNode *kd_root_ALL = EnsureKDTreePresent_ALL(exerter_subpop, exerter_subpop_data);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_NEARESTNEIGH);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_ALL) firstprivate(receiver_data, result_vectors, count, exerter_subpop_size) reduction(||: saw_error_1) reduction(||: saw_error_2) if(receivers_count >= EIDOS_OMPMIN_NEARESTNEIGH) num_threads(thread_count)\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t{\n\t\t\t\tIndividual *receiver = receiver_data[receiver_index];\n\t\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\t\n\t\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t\t{\n\t\t\t\t\tsaw_error_2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\t\t\n\t\t\t\tEidosValue_Object *result_vec = result_vectors[receiver_index];\n\t\t\t\t\n\t\t\t\tif (count < exerter_subpop_size)\t\t// reserve only if we are finding fewer than every possible neighbor\n\t\t\t\t\tresult_vec->reserve((int)count);\n\t\t\t\t\n\t\t\t\tFindNeighbors(exerter_subpop, kd_root_ALL, exerter_subpop_data.kd_node_count_ALL_, receiver_position, (int)count, *result_vec, receiver, /* constraints_active */ false);\n\t\t\t}\n\t\t\t\n\t\t\t// deferred raises, for OpenMP compatibility\n\t\t\tif (saw_error_1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\t\tif (saw_error_2)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighbors): nearestNeighbors() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tfree(result_vectors);\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t– (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ exerterSubpop, [integer$ count = 1])\n//\nEidosValue_SP InteractionType::ExecuteMethod_nearestNeighborsOfPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\tEidosValue *count_value = p_arguments[2].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighborsOfPoint): nearestNeighborsOfPoint() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\t// Check the subpop\n\tSubpopulation *exerter_subpop = SLiM_ExtractSubpopulationFromEidosValue_io(exerterSubpop_value, 0, &community_, nullptr, \"nearestNeighborsOfPoint()\");\n\tSpecies &exerter_species = exerter_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Generic(exerter_species);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_ALL = EnsureKDTreePresent_ALL(exerter_subpop, exerter_subpop_data);\n\t\n\t// Check the point\n\tif (point_value->Count() != spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighborsOfPoint): nearestNeighborsOfPoint() requires that point is of length equal to the interaction spatiality.\" << EidosTerminate();\n\t\n\tdouble point_array[SLIM_MAX_DIMENSIONALITY];\n\t\n\tfor (int point_index = 0; point_index < spatiality_; ++point_index)\n\t\tpoint_array[point_index] = point_value->FloatAtIndex_NOCAST(point_index, nullptr);\n\t\n\t// Check the count\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tint64_t count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_nearestNeighborsOfPoint): nearestNeighborsOfPoint() requires count >= 0.\" << EidosTerminate();\n\t\n\tif (count > exerter_subpop_data.kd_node_count_ALL_)\n\t\tcount = exerter_subpop_data.kd_node_count_ALL_;\n\t\n\tif (count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\t// Find the neighbors\n\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\tif (count < exerter_subpop_size)\t\t// reserve only if we are finding fewer than every possible neighbor\n\t\tresult_vec->reserve((int)count);\n\t\n\tFindNeighbors(exerter_subpop, kd_root_ALL, exerter_subpop_data.kd_node_count_ALL_, point_array, (int)count, *result_vec, nullptr, /* constraints_active */ false);\n\t\n\treturn EidosValue_SP(result_vec);\n}\n\n//\t*********************\t– (integer)neighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_neighborCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// BCH 11/2/2023: Note that this method is now almost identical to ExecuteMethod_interactingNeighborCount()\n\tEidosValue *receivers_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\tint receivers_count = receivers_value->Count();\n\tIndividual * const *receivers_data = (Individual * const *)receivers_value->ObjectData();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCount): neighborCount() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\tif (receivers_count == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tSubpopulation *receiver_subpop = receivers_data[0]->subpopulation_;\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Generic(receiver_subpop->species_);\n\tCheckSpeciesCompatibility_Generic(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_ALL = EnsureKDTreePresent_ALL(exerter_subpop, exerter_subpop_data);\n\t\n\t// If there are no individuals in the tree, short-circuit\n\tif (!kd_root_ALL)\n\t{\n\t\t// If the exerter subpop is empty then all count values for the receivers are zero\n\t\tif (receivers_count == 1)\n\t\t{\n\t\t\treturn gStaticEidosValue_Integer0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Int *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(receivers_count);\n\t\t\t\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t\tresult_vec->set_int_no_check(0, receiver_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t}\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\n\tif (receivers_count == 1)\n\t{\n\t\t// Just one value, so we can return a singleton and skip some work\n\t\tIndividual *receiver = receivers_data[0];\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCount): neighborCount() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\n\t\t// Find the neighbors\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tslim_popsize_t focal_individual_index = (exerter_subpop == receiver_subpop) ? receiver_index_in_subpop : -1;\n\t\tint neighborCount;\n\t\t\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1: neighborCount = CountNeighbors_1(kd_root_ALL, receiver_position, focal_individual_index);\t\t\tbreak;\n\t\t\tcase 2: neighborCount = CountNeighbors_2(kd_root_ALL, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\tcase 3: neighborCount = CountNeighbors_3(kd_root_ALL, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\tdefault: neighborCount = 0; break;\t// unsupported value\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(neighborCount));\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(receivers_count);\n\t\tbool saw_error_1 = false, saw_error_2 = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_NEIGHCOUNT);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_ALL) firstprivate(receivers_data, result_vec) reduction(||: saw_error_1) reduction(||: saw_error_2) if(receivers_count >= EIDOS_OMPMIN_NEIGHCOUNT) num_threads(thread_count)\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tIndividual *receiver = receivers_data[receiver_index];\n\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\n\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t{\n\t\t\t\tsaw_error_1 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t{\n\t\t\t\tsaw_error_2 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Find the neighbors\n\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\tslim_popsize_t focal_individual_index = (exerter_subpop == receiver_subpop) ? receiver_index_in_subpop : -1;\n\t\t\tint neighborCount;\n\t\t\t\n\t\t\tswitch (spatiality_)\n\t\t\t{\n\t\t\t\tcase 1: neighborCount = CountNeighbors_1(kd_root_ALL, receiver_position, focal_individual_index);\t\t\tbreak;\n\t\t\t\tcase 2: neighborCount = CountNeighbors_2(kd_root_ALL, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\t\tcase 3: neighborCount = CountNeighbors_3(kd_root_ALL, receiver_position, focal_individual_index, 0);\t\tbreak;\n\t\t\t\tdefault: neighborCount = 0; break;\t// unsupported value\n\t\t\t}\n\t\t\t\n\t\t\tresult_vec->set_int_no_check(neighborCount, receiver_index);\n\t\t}\n\t\t\n\t\t// deferred raises, for OpenMP compatibility\n\t\tif (saw_error_1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCount): neighborCount() requires receivers to be visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\tif (saw_error_2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCount): neighborCount() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\t\n\t\treturn EidosValue_SP(result_vec);\n\t}\n}\n\n//\t*********************\t– (integer$)neighborCountOfPoint(float point, io<Subpopulation>$ exerterSubpop)\n//\nEidosValue_SP InteractionType::ExecuteMethod_neighborCountOfPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCountOfPoint): neighborCountOfPoint() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\t// Check the subpop\n\tSubpopulation *exerter_subpop = SLiM_ExtractSubpopulationFromEidosValue_io(exerterSubpop_value, 0, &community_, nullptr, \"nearestNeighborsOfPoint()\");\n\tSpecies &exerter_species = exerter_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Generic(exerter_species);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_ALL = EnsureKDTreePresent_ALL(exerter_subpop, exerter_subpop_data);\n\n\tif (!kd_root_ALL)\n\t\treturn gStaticEidosValue_Integer0;\n\t\n\t// Check the point\n\tif (point_value->Count() != spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCountOfPoint): neighborCountOfPoint() requires that point is of length equal to the interaction spatiality.\" << EidosTerminate();\n\t\n\tdouble point_array[SLIM_MAX_DIMENSIONALITY];\n\t\n\tfor (int point_index = 0; point_index < spatiality_; ++point_index)\n\t\tpoint_array[point_index] = point_value->FloatAtIndex_NOCAST(point_index, nullptr);\n\t\n\t// Find the neighbors\n\tint neighborCount;\n\t\n\tswitch (spatiality_)\n\t{\n\t\tcase 1: neighborCount = CountNeighbors_1(kd_root_ALL, point_array, -1);\t\t\tbreak;\n\t\tcase 2: neighborCount = CountNeighbors_2(kd_root_ALL, point_array, -1, 0);\t\tbreak;\n\t\tcase 3: neighborCount = CountNeighbors_3(kd_root_ALL, point_array, -1, 0);\t\tbreak;\n\t\tdefault: EIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_neighborCountOfPoint): (internal error) unsupported spatiality\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(neighborCount));\n}\n\n//\t*********************\t- (void)setConstraints(string$ who, [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL],\n//\t\t\t\t\t\t\t\t\t\t\t\t\t[Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_setConstraints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tif (AnyEvaluated())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() cannot be called while the interaction is being evaluated; call unevaluate() first, or call setConstraints() prior to evaluation of the interaction.\" << EidosTerminate();\n\t\n\tEidosValue *who_value = p_arguments[0].get();\n\tstd::string who = who_value->StringAtIndex_NOCAST(0, nullptr);\n\tbool set_receiver_constraints = false;\n\tbool set_exerter_constraints = false;\n\t\n\tif (who == \"receiver\")\n\t{\n\t\tset_receiver_constraints = true;\n\t}\n\telse if (who == \"exerter\")\n\t{\n\t\tset_exerter_constraints = true;\n\t}\n\telse if (who == \"both\")\n\t{\n\t\tset_receiver_constraints = true;\n\t\tset_exerter_constraints = true;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() requires the parameter who to be one of 'receiver', 'exerter', or 'both'.\" << EidosTerminate();\n\t\n\t// do two passes, one for receiver constraints, one for exerter constraints\n\tfor (int i = 0; i <= 1; ++i)\n\t{\n\t\tInteractionConstraints *constraints = nullptr;\n\t\t\n\t\tif (i == 0)\n\t\t{\n\t\t\tif (!set_receiver_constraints)\n\t\t\t\tcontinue;\n\t\t\tconstraints = &receiver_constraints_;\n\t\t}\n\t\tif (i == 1)\n\t\t{\n\t\t\tif (!set_exerter_constraints)\n\t\t\t\tcontinue;\n\t\t\tconstraints = &exerter_constraints_;\n\t\t}\n\t\t\n\t\t// first turn off all constraints\n\t\tconstraints->has_constraints_ = false;\n\t\tconstraints->sex_ = IndividualSex::kUnspecified;\n\t\tconstraints->has_nonsex_constraints_ = false;\n\t\tconstraints->tag_ = SLIM_TAG_UNSET_VALUE;\n\t\tconstraints->min_age_ = -1;\n\t\tconstraints->max_age_ = -1;\n\t\tconstraints->migrant_ = -1;\n\t\tconstraints->has_tagL_constraints_ = false;\n\t\tconstraints->tagL0_ = -1;\n\t\tconstraints->tagL1_ = -1;\n\t\tconstraints->tagL2_ = -1;\n\t\tconstraints->tagL3_ = -1;\n\t\tconstraints->tagL4_ = -1;\n\t\t\n\t\t// then turn on constraints as requested\n\t\tEidosValue *sex_value = p_arguments[1].get();\n\t\tif (sex_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tstd::string sex = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\tif (sex == \"M\")\t\t\t{ constraints->sex_ = IndividualSex::kMale; constraints->has_constraints_ = true; }\n\t\t\telse if (sex == \"F\")\t{ constraints->sex_ = IndividualSex::kFemale; constraints->has_constraints_ = true; }\n\t\t\telse if (sex == \"*\")\tconstraints->sex_ = IndividualSex::kUnspecified;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() requires the parameter sex to be 'M', 'F', or '*'.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tEidosValue *tag_value = p_arguments[2].get();\n\t\tif (tag_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tslim_usertag_t tag = tag_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tag_ = tag;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *minAge_value = p_arguments[3].get();\n\t\tif (minAge_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tif (community_.ModelType() == SLiMModelType::kModelTypeWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() cannot set a minAge constraint in a WF model (since the WF model is of non-overlapping generations).\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_age_t minAge = SLiMCastToAgeTypeOrRaise(minAge_value->IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\tif ((minAge <= 0) || (minAge > 100000))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() requires the parameter minAge to be >= 0 and <= 100000.\" << EidosTerminate();\n\t\t\t\n\t\t\tconstraints->min_age_ = minAge;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *maxAge_value = p_arguments[4].get();\n\t\tif (maxAge_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tif (community_.ModelType() == SLiMModelType::kModelTypeWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() cannot set a maxAge constraint in a WF model (since the WF model is of non-overlapping generations).\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_age_t maxAge = SLiMCastToAgeTypeOrRaise(maxAge_value->IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\tif ((maxAge <= 0) || (maxAge > 100000))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() requires the parameter maxAge to be >= 0 and <= 100000.\" << EidosTerminate();\n\t\t\t\n\t\t\tconstraints->max_age_ = maxAge;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t}\n\t\t\n\t\tif ((constraints->min_age_ != -1) && (constraints->max_age_ != -1) && (constraints->min_age_ > constraints->max_age_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setConstraints): setConstraints() requires minAge <= maxAge.\" << EidosTerminate();\n\t\t\n\t\tEidosValue *migrant_value = p_arguments[5].get();\n\t\tif (migrant_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t migrant = migrant_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->migrant_ = migrant;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *tagL0_value = p_arguments[6].get();\n\t\tif (tagL0_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t tagL0 = tagL0_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tagL0_ = tagL0;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t\tconstraints->has_tagL_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *tagL1_value = p_arguments[7].get();\n\t\tif (tagL1_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t tagL1 = tagL1_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tagL1_ = tagL1;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t\tconstraints->has_tagL_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *tagL2_value = p_arguments[8].get();\n\t\tif (tagL2_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t tagL2 = tagL2_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tagL2_ = tagL2;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t\tconstraints->has_tagL_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *tagL3_value = p_arguments[9].get();\n\t\tif (tagL3_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t tagL3 = tagL3_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tagL3_ = tagL3;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t\tconstraints->has_tagL_constraints_ = true;\n\t\t}\n\t\t\n\t\tEidosValue *tagL4_value = p_arguments[10].get();\n\t\tif (tagL4_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\teidos_logical_t tagL4 = tagL4_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconstraints->tagL4_ = tagL4;\n\t\t\tconstraints->has_constraints_ = true;\n\t\t\tconstraints->has_nonsex_constraints_ = true;\n\t\t\tconstraints->has_tagL_constraints_ = true;\n\t\t}\n\t}\n\t\n\t// mark that interaction types changed, so they get redisplayed in SLiMgui\n\tcommunity_.interaction_types_changed_ = true;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setInteractionFunction(string$ functionType, ...)\n//\nEidosValue_SP InteractionType::ExecuteMethod_setInteractionFunction(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tif (AnyEvaluated())\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setInteractionFunction): setInteractionFunction() cannot be called while the interaction is being evaluated; call unevaluate() first, or call setInteractionFunction() prior to evaluation of the interaction.\" << EidosTerminate();\n\t\n\t// SpatialKernel parses and bounds-checks our arguments for us\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(spatiality_, max_distance_, p_arguments, 0, /* p_expect_max_density */ true, &k_type, &k_param_count);\n\t\n\tif (kernel_count != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_setInteractionFunction): setInteractionFunction() requires a single kernel; all kernel definition arguments must be singletons.\" << EidosTerminate();\n\t\n\tSpatialKernel kernel(spatiality_, max_distance_, p_arguments, 0, 0, /* p_expect_max_density */ true, k_type, k_param_count);\n\t\n\t// Everything seems to be in order, so replace our IF info with the new info\n\t// FIXME we could consider actually keeping an internal SpatialKernel instance permanently\n\tif_type_ = kernel.kernel_type_;\n\tif_param1_ = kernel.kernel_param1_;\n\tif_param2_ = kernel.kernel_param2_;\n\tif_param3_ = kernel.kernel_param3_;\n\tn_2param2sq_ = kernel.n_2param2sq_;\n\t\n\t// mark that interaction types changed, so they get redisplayed in SLiMgui\n\tcommunity_.interaction_types_changed_ = true;\n\t\n\t// changing the interaction function invalidates the cached clipped_integral_ buffer; we don't deallocate it, just invalidate it\n\tclipped_integral_valid_ = false;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (float)strength(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_strength(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *receiver_value = p_arguments[0].get();\n\tEidosValue *exerters_value = p_arguments[1].get();\n\t\n\t// receiver_value is guaranteed to be singleton; let's get the info on it\n\tIndividual *receiver = (Individual *)receiver_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\n\tif (receiver_index_in_subpop < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_strength): strength() requires that the receiver is visible in a subpopulation (i.e., not a new juvenile).\" << EidosTerminate();\n\t\n\tSubpopulation *receiver_subpop = receiver->subpopulation_;\n\tSpecies &receiver_species = receiver_subpop->species_;\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_species);\n\t\n\t// figure out the exerter subpopulation and get info on it\n\tbool exerters_value_NULL = (exerters_value->Type() == EidosValueType::kValueNULL);\n\tint exerters_count = exerters_value->Count();\n\t\n\tif ((exerters_count == 0) && !exerters_value_NULL)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tSubpopulation *exerter_subpop = (exerters_value_NULL ? receiver_subpop : ((Individual *)exerters_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_);\n\t\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tslim_popsize_t exerter_subpop_size = exerter_subpop->parent_subpop_size_;\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\t\n\tif (exerters_value_NULL)\n\t\texerters_count = exerter_subpop_size;\n\t\n\t// Check constraints for the receiver; if the individual is disqualified, the strength to each exerter is zero\n\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\tgoto returnAllZero;\n\t\n\tif (spatiality_)\n\t{\n\t\t// Spatial case; we use the k-d tree to get strengths for all neighbors.\n\t\t// BCH 5/14/2023: The call to FillSparseVectorForReceiverStrengths() means we run interaction() callbacks,\n\t\t// so if this code is ever parallelized, it should stay single-threaded when callbacks are enabled.\n\t\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\n\t\tstd::vector<SLiMEidosBlock*> &interaction_callbacks = exerter_subpop_data.evaluation_interaction_callbacks_;\n\t\tbool has_interaction_callbacks = (interaction_callbacks.size() > 0);\n\t\t\n\t\tif (exerters_value_NULL)\n\t\t{\n\t\t\t// NULL means return distances from individuals1 (which must be singleton) to all individuals in the subpopulation\n\t\t\t// We initialize the return vector to 0, and fill in non-zero values from the sparse vector\n\t\t\tSLiM_kdNode *kd_root_EXERTERS = (spatiality_ ? EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data) : nullptr);\n\t\t\t\n\t\t\t// If the k-d tree has no qualifying exerters, we return all zeros\n\t\t\tif (!kd_root_EXERTERS)\n\t\t\t\tgoto returnAllZero;\n\t\t\t\n\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\tuint32_t nnz;\n\t\t\tconst uint32_t *columns;\n\t\t\tconst sv_value_t *strengths;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, interaction_callbacks);\n\t\t\t\tstrengths = sv->Strengths(&nnz, &columns);\n\t\t\t\t\n\t\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\t\t\tEidosValue_SP result_SP(result_vec);\n\t\t\t\tdouble *result_ptr = result_vec->data_mutable();\n\t\t\t\t\n\t\t\t\tEIDOS_BZERO(result_ptr, exerter_subpop_size * sizeof(double));\n\t\t\t\t\n\t\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\t\t*(result_ptr + columns[col_index]) = strengths[col_index];\n\t\t\t\t\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\treturn result_SP;\n\t\t\t} catch (...) {\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\tthrow;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, receiver is singleton, and exerters_value is any length, so we loop over exerters\n\t\t\t// To avoid searching through sparse vector results for each exerter, we calculate distances and\n\t\t\t// strengths ourselves for each receiver-exerter pair, which is a bit complicated - we need to\n\t\t\t// worry about constraints, self-interactions, max distance, callbacks, etc., which SparseVector\n\t\t\t// handles for most client code.\n\t\t\tIndividual * const *exerters_data = (Individual * const *)exerters_value->ObjectData();\n\t\t\tdouble *exerter_position_data = exerter_subpop_data.positions_;\n\t\t\tbool periodicity_enabled = (exerter_subpop_data.periodic_x_ || exerter_subpop_data.periodic_y_ || exerter_subpop_data.periodic_z_);\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\t\tEidosValue_SP result_SP(result_vec);\n\t\t\t\n\t\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t\t{\n\t\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\t\n\t\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_strength): strength() requires that all exerters be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\t\n\t\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_strength): strength() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif ((exerter == receiver) || !CheckIndividualConstraints(exerter, exerter_constraints_))\n\t\t\t\t{\n\t\t\t\t\t// self-interactions and constraints result in an interaction strength of 0.0\n\t\t\t\t\tresult_vec->set_float_no_check(0.0, exerter_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdouble distance;\n\t\t\t\t\t\n\t\t\t\t\tif (periodicity_enabled)\n\t\t\t\t\t\tdistance = CalculateDistanceWithPeriodicity(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY, exerter_subpop_data);\n\t\t\t\t\telse\n\t\t\t\t\t\tdistance = CalculateDistance(receiver_position, exerter_position_data + (size_t)exerter_index_in_subpop * SLIM_MAX_DIMENSIONALITY);\n\t\t\t\t\t\n\t\t\t\t\tif (distance > max_distance_)\n\t\t\t\t\t{\n\t\t\t\t\t\t// interactions beyond the maximum interaction distance also produce 0.0\n\t\t\t\t\t\tresult_vec->set_float_no_check(0.0, exerter_index);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble strength;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (has_interaction_callbacks)\n\t\t\t\t\t\t\tstrength = CalculateStrengthWithCallbacks(distance, receiver, exerter, interaction_callbacks);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tstrength = CalculateStrengthNoCallbacks(distance);\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_vec->set_float_no_check(strength, exerter_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Non-spatial case; no distances used.  We have to worry about exerter constraints; they are not handled for us.\n\t\t// BCH 5/14/2023: We call ApplyInteractionCallbacks() below, so if this code ever goes parallel it\n\t\t// should stay single-threaded if/when any interaction() callbacks are present!\n\t\tslim_popsize_t receiver_index = ((exerter_subpop == receiver->subpopulation_) && (receiver->index_ >= 0) ? receiver->index_ : -1);\n\t\tstd::vector<SLiMEidosBlock*> &callbacks = exerter_subpop_data.evaluation_interaction_callbacks_;\n\t\t\n\t\tif (exerters_value->Type() == EidosValueType::kValueNULL)\n\t\t{\n\t\t\t// NULL means return strengths to individuals1 (which must be singleton) from all individuals in the subpopulation\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerter_subpop_size);\n\t\t\t\n\t\t\tfor (int exerter_index = 0; exerter_index < exerter_subpop_size; ++exerter_index)\n\t\t\t{\n\t\t\t\tdouble strength = 0;\n\t\t\t\t\n\t\t\t\tif (exerter_index != receiver_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *exerter = exerter_subpop->parent_individuals_[exerter_index];\n\t\t\t\t\t\n\t\t\t\t\tif (CheckIndividualConstraints(exerter, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\t\tstrength = ApplyInteractionCallbacks(receiver, exerter, if_param1_, NAN, callbacks);\t// hard-coding interaction function \"f\" (SpatialKernelType::kFixed), which is required\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_vec->set_float_no_check(strength, exerter_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, individuals1 is singleton, and exerters_value is any length, so we loop over exerters_value\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\t\tIndividual * const *exerters_data = (Individual * const *)exerters_value->ObjectData();\n\t\t\t\n\t\t\tfor (int exerter_index = 0; exerter_index < exerters_count; ++exerter_index)\n\t\t\t{\n\t\t\t\tIndividual *exerter = exerters_data[exerter_index];\n\t\t\t\t\n\t\t\t\tif (exerter_subpop != exerter->subpopulation_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_strength): strength() requires that all individuals be in the same subpopulation.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tslim_popsize_t exerter_index_in_subpop = exerter->index_;\n\t\t\t\t\n\t\t\t\tif (exerter_index_in_subpop < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_strength): strength() requires that exerters are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tdouble strength = 0;\n\t\t\t\t\n\t\t\t\tif ((exerter_index_in_subpop != receiver_index) && CheckIndividualConstraints(exerter, exerter_constraints_))\t\t// potentially raises\n\t\t\t\t\tstrength = ApplyInteractionCallbacks(receiver, exerter, if_param1_, NAN, callbacks);\t// hard-coding interaction function \"f\" (SpatialKernelType::kFixed), which is required\n\t\t\t\t\n\t\t\t\tresult_vec->set_float_no_check(strength, exerter_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t}\n\t\n\treturnAllZero:\n\t{\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(exerters_count);\n\t\tEidosValue_SP result_SP(result_vec);\n\t\t\n\t\tEIDOS_BZERO(result_vec->data_mutable(), exerter_subpop_size * sizeof(double));\n\t\t\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t– (lo<Individual>)testConstraints(object<Individual> individuals, string$ constraints, [logical$ returnIndividuals = F])\n//\nEidosValue_SP InteractionType::ExecuteMethod_testConstraints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tEidosValue_String *constraints_value = (EidosValue_String *)p_arguments[1].get();\n\tEidosValue *returnIndividuals_value = p_arguments[2].get();\n\t\n\tint individuals_count = individuals_value->Count();\n\tIndividual * const *individuals_data = (Individual * const *)individuals_value->ObjectData();\n\t\n\tconst std::string &constraints_str = constraints_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tInteractionConstraints *constraints;\n\t\n\tif (constraints_str == \"receiver\")\n\t\tconstraints = &receiver_constraints_;\n\telse if (constraints_str == \"exerter\")\n\t\tconstraints = &exerter_constraints_;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_testConstraints): testConstraints() requires that parameter constraints be 'receiver' or 'exerter'.\" << EidosTerminate();\n\t\n\tbool returnIndividuals = returnIndividuals_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (individuals_count == 1)\n\t{\n\t\t// singleton case\n\t\tIndividual *ind = individuals_data[0];\n\t\t\n\t\tif (CheckIndividualConstraints(ind, *constraints))\n\t\t{\n\t\t\tif (returnIndividuals)\n\t\t\t\treturn p_arguments[0];\t// return the individual as it was passed in\n\t\t\telse\n\t\t\t\treturn gStaticEidosValue_LogicalT;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (returnIndividuals)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\telse\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// non-singleton case\n\t\tif (returnIndividuals)\n\t\t{\n\t\t\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\t\n\t\t\tfor (int index = 0; index < individuals_count; ++index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals_data[index];\n\t\t\t\t\n\t\t\t\tif (CheckIndividualConstraints(ind, *constraints))\n\t\t\t\t\tresult_vec->push_object_element_NORR(ind);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Logical *result_vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Logical();\n\t\t\tresult_vec->resize_no_initialize(individuals_count);\n\t\t\t\n\t\t\tfor (int index = 0; index < individuals_count; ++index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals_data[index];\n\t\t\t\tbool satisfied = CheckIndividualConstraints(ind, *constraints);\n\t\t\t\t\n\t\t\t\tresult_vec->set_logical_no_check(satisfied, index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_Logical_SP(result_vec);\n\t\t}\n\t}\n}\n\n//\t*********************\t– (float)totalOfNeighborStrengths(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n//\nEidosValue_SP InteractionType::ExecuteMethod_totalOfNeighborStrengths(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *receivers_value = p_arguments[0].get();\n\tEidosValue *exerterSubpop_value = p_arguments[1].get();\n\tint receivers_count = receivers_value->Count();\n\t\n\tif (spatiality_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): totalOfNeighborStrengths() requires that the interaction be spatial.\" << EidosTerminate();\n\t\n\tif (receivers_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// the exerter subpopulation defaults to the same subpop as the receivers\n\tIndividual * const *receivers_data = (Individual * const *)receivers_value->ObjectData();\n\tSubpopulation *receiver_subpop = receivers_data[0]->subpopulation_;\n\tSubpopulation *exerter_subpop = ((exerterSubpop_value->Type() == EidosValueType::kValueNULL) ? receiver_subpop : (Subpopulation *)exerterSubpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\n\tCheckSpeciesCompatibility_Receiver(receiver_subpop->species_);\n\tCheckSpeciesCompatibility_Exerter(exerter_subpop->species_);\n\tCheckSpatialCompatibility(receiver_subpop, exerter_subpop);\n\t\n\tInteractionsData &exerter_subpop_data = InteractionsDataForSubpop(data_, exerter_subpop);\n\tSLiM_kdNode *kd_root_EXERTERS = EnsureKDTreePresent_EXERTERS(exerter_subpop, exerter_subpop_data);\n\t\n\t// If there are no exerters satisfying constraints, short-circuit\n\tif (!kd_root_EXERTERS)\n\t{\n\t\t// If the exerter subpop is empty then all strength totals for the receivers are zero\n\t\tif (receivers_count == 1)\n\t\t{\n\t\t\treturn gStaticEidosValue_Float0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(receivers_count);\n\t\t\t\n\t\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t\t\tresult_vec->set_float_no_check(0, receiver_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(result_vec);\n\t\t}\n\t}\n\t\n\tInteractionsData &receiver_subpop_data = InteractionsDataForSubpop(data_, receiver_subpop);\n\t\n\tif (receivers_count == 1)\n\t{\n\t\t// Just one value, so we can return a singleton and skip some work\n\t\tIndividual *receiver = receivers_data[0];\n\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\n\t\tif (receiver_index_in_subpop < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): totalOfNeighborStrengths() requires that receivers are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\t\n\t\t// Check sex-specificity for the receiver; if the individual is disqualified, the total is zero\n\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises\n\t\t\treturn gStaticEidosValue_Float0;\n\t\t\n\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\n\t\ttry {\n\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\t\t// singleton case, not parallel\n\t\t} catch (...) {\n\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\t// Get the sparse vector data\n\t\tuint32_t nnz;\n\t\tconst sv_value_t *strengths;\n\t\t\n\t\tstrengths = sv->Strengths(&nnz);\n\t\t\n\t\t// Total the interaction strengths\n\t\tdouble total_strength = 0.0;\n\t\t\n\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\ttotal_strength += strengths[col_index];\n\t\t\n\t\tInteractionType::FreeSparseVector(sv);\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(total_strength));\n\t}\n\telse\n\t{\n\t\t// Loop over the requested individuals and get the totals\n\t\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(receivers_count);\n\t\tEidosValue_SP result_SP(result_vec);\n#ifdef _OPENMP\n\t\tbool has_interaction_callbacks = (exerter_subpop_data.evaluation_interaction_callbacks_.size() != 0);\n#endif\n\t\tbool saw_error_1 = false, saw_error_2 = false, saw_error_3 = false, saw_error_4 = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_TOTNEIGHSTRENGTH);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(receivers_count, receiver_subpop, exerter_subpop, receiver_subpop_data, exerter_subpop_data, kd_root_EXERTERS) firstprivate(receivers_data, result_vec) reduction(||: saw_error_1) reduction(||: saw_error_2) reduction(||: saw_error_3) reduction(||: saw_error_4) if(!has_interaction_callbacks && (receivers_count >= EIDOS_OMPMIN_TOTNEIGHSTRENGTH)) num_threads(thread_count)\n\t\tfor (int receiver_index = 0; receiver_index < receivers_count; ++receiver_index)\n\t\t{\n\t\t\tIndividual *receiver = receivers_data[receiver_index];\n\t\t\tslim_popsize_t receiver_index_in_subpop = receiver->index_;\n\t\t\t\n\t\t\tif (receiver_index_in_subpop < 0)\n\t\t\t{\n\t\t\t\tsaw_error_1 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// SPECIES CONSISTENCY CHECK\n\t\t\tif (receiver_subpop != receiver->subpopulation_)\n\t\t\t{\n\t\t\t\tsaw_error_2 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Check constraints for the receiver; if the individual is disqualified, the total is zero\n\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\ttry {\n\t\t\t\tif (!CheckIndividualConstraints(receiver, receiver_constraints_))\t\t// potentially raises; protected\n\t\t\t\t{\n\t\t\t\t\tresult_vec->set_float_no_check(0, receiver_index);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\tsaw_error_4 = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tdouble *receiver_position = receiver_subpop_data.positions_ + (size_t)receiver_index_in_subpop * SLIM_MAX_DIMENSIONALITY;\n\t\t\tSparseVector *sv = InteractionType::NewSparseVectorForExerterSubpop(exerter_subpop, SparseVectorDataType::kStrengths);\n\t\t\t\n\t\t\t// Under OpenMP, raises can't go past the end of the parallel region; handle things the same way when not under OpenMP for simplicity\n\t\t\ttry {\n\t\t\t\tFillSparseVectorForReceiverStrengths(sv, receiver, receiver_position, exerter_subpop, kd_root_EXERTERS, exerter_subpop_data.evaluation_interaction_callbacks_);\t\t// protected from running interaction() callbacks in parallel, above\n\t\t\t} catch (...) {\n\t\t\t\tsaw_error_3 = true;\n\t\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// Get the sparse vector data\n\t\t\tuint32_t nnz;\n\t\t\tconst sv_value_t *strengths;\n\t\t\t\n\t\t\tstrengths = sv->Strengths(&nnz);\n\t\t\t\n\t\t\t// Total the interaction strengths\n\t\t\tdouble total_strength = 0.0;\n\t\t\t\n\t\t\tfor (uint32_t col_index = 0; col_index < nnz; ++col_index)\n\t\t\t\ttotal_strength += strengths[col_index];\n\t\t\t\n\t\t\tresult_vec->set_float_no_check(total_strength, receiver_index);\n\t\t\tInteractionType::FreeSparseVector(sv);\n\t\t}\n\t\t\n\t\t// deferred raises, for OpenMP compatibility\n\t\tif (saw_error_1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): totalOfNeighborStrengths() requires that receivers are visible in a subpopulation (i.e., not new juveniles).\" << EidosTerminate();\n\t\tif (saw_error_2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): totalOfNeighborStrengths() requires that all receivers be in the same subpopulation.\" << EidosTerminate();\n\t\tif (saw_error_3)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): an exception was caught inside a parallel region.\" << EidosTerminate();\n\t\tif (saw_error_4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (InteractionType::ExecuteMethod_totalOfNeighborStrengths): totalOfNeighborStrengths() tested a tag or tagL constraint, but a receiver's value for that property was not defined (had not been set).\" << EidosTerminate();\n\t\t\n\t\treturn result_SP;\n\t}\n}\n\n//\t*********************\t– (void)unevaluate(void)\n//\nEidosValue_SP InteractionType::ExecuteMethod_unevaluate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tInvalidate();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tInteractionType_Class\n//\n#pragma mark -\n#pragma mark InteractionType_Class\n#pragma mark -\n\nEidosClass *gSLiM_InteractionType_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *InteractionType_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"InteractionType_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(InteractionType::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_reciprocal,\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_sexSegregation,\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatiality,\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_maxDistance,\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(InteractionType::GetProperty_Accelerated_tag));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *InteractionType_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"InteractionType_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_clippedIntegral, kEidosValueMaskFloat))->AddObject_N(\"receivers\", gSLiM_Individual_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_distance, kEidosValueMaskFloat))->AddObject_S(\"receiver\", gSLiM_Individual_Class)->AddObject_ON(\"exerters\", gSLiM_Individual_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_distanceFromPoint, kEidosValueMaskFloat))->AddFloat(\"point\")->AddObject(\"exerters\", gSLiM_Individual_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_drawByStrength, kEidosValueMaskObject, nullptr))->AddObject(\"receiver\", gSLiM_Individual_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddLogical_OS(\"returnDict\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_evaluate, kEidosValueMaskVOID))->AddIntObject(\"subpops\", gSLiM_Subpopulation_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_interactingNeighborCount, kEidosValueMaskInt))->AddObject(\"receivers\", gSLiM_Individual_Class)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_localPopulationDensity, kEidosValueMaskFloat))->AddObject(\"receivers\", gSLiM_Individual_Class)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_interactionDistance, kEidosValueMaskFloat))->AddObject_S(\"receiver\", gSLiM_Individual_Class)->AddObject_ON(\"exerters\", gSLiM_Individual_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_nearestInteractingNeighbors, kEidosValueMaskObject, nullptr))->AddObject(\"receiver\", gSLiM_Individual_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddLogical_OS(\"returnDict\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_nearestNeighbors, kEidosValueMaskObject, nullptr))->AddObject(\"receiver\", gSLiM_Individual_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddLogical_OS(\"returnDict\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_nearestNeighborsOfPoint, kEidosValueMaskObject, gSLiM_Individual_Class))->AddFloat(\"point\")->AddIntObject_S(\"exerterSubpop\", gSLiM_Subpopulation_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_neighborCount, kEidosValueMaskInt))->AddObject(\"receivers\", gSLiM_Individual_Class)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_neighborCountOfPoint, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddFloat(\"point\")->AddIntObject_S(\"exerterSubpop\", gSLiM_Subpopulation_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setConstraints, kEidosValueMaskVOID))->AddString_S(\"who\")->AddString_OSN(\"sex\", gStaticEidosValueNULL)->AddInt_OSN(\"tag\", gStaticEidosValueNULL)->AddInt_OSN(\"minAge\", gStaticEidosValueNULL)->AddInt_OSN(\"maxAge\", gStaticEidosValueNULL)->AddLogical_OSN(\"migrant\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL0\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL1\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL2\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL3\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL4\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setInteractionFunction, kEidosValueMaskVOID))->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_strength, kEidosValueMaskFloat))->AddObject_S(\"receiver\", gSLiM_Individual_Class)->AddObject_ON(\"exerters\", gSLiM_Individual_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_testConstraints, kEidosValueMaskLogical | kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddString_S(\"constraints\")->AddLogical_OS(\"returnIndividuals\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_totalOfNeighborStrengths, kEidosValueMaskFloat))->AddObject(\"receivers\", gSLiM_Individual_Class)->AddObject_OSN(\"exerterSubpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_unevaluate, kEidosValueMaskVOID)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n//\n//\t_InteractionsData\n//\n#pragma mark -\n#pragma mark _InteractionsData\n#pragma mark -\n\n_InteractionsData::_InteractionsData(_InteractionsData&& p_source) noexcept\n{\n\tevaluated_ = p_source.evaluated_;\n\tevaluation_interaction_callbacks_.swap(p_source.evaluation_interaction_callbacks_);\n\tindividual_count_ = p_source.individual_count_;\n\tfirst_male_index_ = p_source.first_male_index_;\n\tperiodic_x_ = p_source.periodic_x_;\n\tperiodic_y_ = p_source.periodic_y_;\n\tperiodic_z_ = p_source.periodic_z_;\n\tbounds_x1_ = p_source.bounds_x1_;\n\tbounds_y1_ = p_source.bounds_y1_;\n\tbounds_z1_ = p_source.bounds_z1_;\n\tpositions_ = p_source.positions_;\n\tkd_nodes_ALL_ = p_source.kd_nodes_ALL_;\n\tkd_root_ALL_ = p_source.kd_root_ALL_;\n\tkd_node_count_ALL_ = p_source.kd_node_count_ALL_;\n\tkd_nodes_EXERTERS_ = p_source.kd_nodes_EXERTERS_;\n\tkd_root_EXERTERS_ = p_source.kd_root_EXERTERS_;\n\tkd_node_count_EXERTERS_ = p_source.kd_node_count_EXERTERS_;\n\t\n\tp_source.evaluated_ = false;\n\tp_source.evaluation_interaction_callbacks_.resize(0);\n\tp_source.individual_count_ = 0;\n\tp_source.first_male_index_ = 0;\n\tp_source.periodic_x_ = false;\n\tp_source.periodic_y_ = false;\n\tp_source.periodic_z_ = false;\n\tp_source.bounds_x1_ = 0.0;\n\tp_source.bounds_y1_ = 0.0;\n\tp_source.bounds_z1_ = 0.0;\n\tp_source.positions_ = nullptr;\n\tp_source.kd_nodes_ALL_ = nullptr;\n\tp_source.kd_root_ALL_ = nullptr;\n\tp_source.kd_node_count_ALL_ = 0;\n\tp_source.kd_nodes_EXERTERS_ = nullptr;\n\tp_source.kd_root_EXERTERS_ = nullptr;\n\tp_source.kd_node_count_EXERTERS_ = 0;\n}\n\n_InteractionsData& _InteractionsData::operator=(_InteractionsData&& p_source) noexcept\n{\n\tif (this != &p_source)  \n\t{\n\t\tif (positions_)\n\t\t\tfree(positions_);\n\t\t\n\t\t// keep in mind that the two k-d trees may share their memory\n\t\tif (kd_nodes_ALL_ == kd_nodes_EXERTERS_)\n\t\t\tkd_nodes_EXERTERS_ = nullptr;\n\t\tif (kd_nodes_ALL_)\n\t\t\tfree(kd_nodes_ALL_);\n\t\tif (kd_nodes_EXERTERS_)\n\t\t\tfree(kd_nodes_EXERTERS_);\n\t\t\n\t\tevaluated_ = p_source.evaluated_;\n\t\tevaluation_interaction_callbacks_.swap(p_source.evaluation_interaction_callbacks_);\n\t\tindividual_count_ = p_source.individual_count_;\n\t\tfirst_male_index_ = p_source.first_male_index_;\n\t\tperiodic_x_ = p_source.periodic_x_;\n\t\tperiodic_y_ = p_source.periodic_y_;\n\t\tperiodic_z_ = p_source.periodic_z_;\n\t\tbounds_x1_ = p_source.bounds_x1_;\n\t\tbounds_y1_ = p_source.bounds_y1_;\n\t\tbounds_z1_ = p_source.bounds_z1_;\n\t\tpositions_ = p_source.positions_;\n\t\tkd_nodes_ALL_ = p_source.kd_nodes_ALL_;\n\t\tkd_root_ALL_ = p_source.kd_root_ALL_;\n\t\tkd_node_count_ALL_ = p_source.kd_node_count_ALL_;\n\t\tkd_nodes_EXERTERS_ = p_source.kd_nodes_EXERTERS_;\n\t\tkd_root_EXERTERS_ = p_source.kd_root_EXERTERS_;\n\t\tkd_node_count_EXERTERS_ = p_source.kd_node_count_EXERTERS_;\n\t\t\n\t\tp_source.evaluated_ = false;\n\t\tp_source.evaluation_interaction_callbacks_.resize(0);\n\t\tp_source.individual_count_ = 0;\n\t\tp_source.first_male_index_ = 0;\n\t\tp_source.periodic_x_ = false;\n\t\tp_source.periodic_y_ = false;\n\t\tp_source.periodic_z_ = false;\n\t\tp_source.bounds_x1_ = 0.0;\n\t\tp_source.bounds_y1_ = 0.0;\n\t\tp_source.bounds_z1_ = 0.0;\n\t\tp_source.positions_ = nullptr;\n\t\tp_source.kd_nodes_ALL_ = nullptr;\n\t\tp_source.kd_root_ALL_ = nullptr;\n\t\tp_source.kd_node_count_ALL_ = 0;\n\t\tp_source.kd_nodes_EXERTERS_ = nullptr;\n\t\tp_source.kd_root_EXERTERS_ = nullptr;\n\t\tp_source.kd_node_count_EXERTERS_ = 0;\n\t}\n\t\n\treturn *this;\n}\n\n_InteractionsData::_InteractionsData(void)\n{\n}\n\n_InteractionsData::_InteractionsData(slim_popsize_t p_individual_count, slim_popsize_t p_first_male_index) : individual_count_(p_individual_count), first_male_index_(p_first_male_index)\n{\n}\n\n_InteractionsData::~_InteractionsData(void)\n{\n\tif (positions_)\n\t{\n\t\tfree(positions_);\n\t\tpositions_ = nullptr;\n\t}\n\t\n\t// keep in mind that the two k-d trees may share their memory\n\tif (kd_nodes_ALL_ == kd_nodes_EXERTERS_)\n\t\tkd_nodes_EXERTERS_ = nullptr;\n\t\n\tif (kd_nodes_ALL_)\n\t{\n\t\tfree(kd_nodes_ALL_);\n\t\tkd_nodes_ALL_ = nullptr;\n\t}\n\t\n\tif (kd_nodes_EXERTERS_)\n\t{\n\t\tfree(kd_nodes_EXERTERS_);\n\t\tkd_nodes_EXERTERS_ = nullptr;\n\t}\n\t\n\tkd_root_ALL_ = nullptr;\n\tkd_node_count_ALL_ = 0;\n\t\n\tkd_root_EXERTERS_ = nullptr;\n\tkd_node_count_EXERTERS_ = 0;\n\t\n\t// Unnecessary since it's about to be destroyed anyway\n\t//evaluation_interaction_callbacks_.resize(0);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/interaction_type.h",
    "content": "//\n//  interaction_type.h\n//  SLiM\n//\n//  Created by Ben Haller on 2/25/17.\n//  Copyright (c) 2017-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class InteractionType represents a type of interaction defined in the input file, such as spatial competition, phenotype-based\n resource competition, or spatial mating preference.  A particular interaction is defined by a spatiality (x, xy, xyz, or none), a\n maximum distance threshold, and callbacks that map from distance to interaction strength (while also perhaps involving genetic and\n environmental factors that modify the interaction).\n \n */\n\n#ifndef __SLiM__interaction_type__\n#define __SLiM__interaction_type__\n\n\n#include <vector>\n#include <string>\n#include <map>\n\n#include \"eidos_value.h\"\n#include \"eidos_symbol_table.h\"\n#include \"slim_globals.h\"\n#include \"slim_eidos_block.h\"\n#include \"sparse_vector.h\"\n#include \"subpopulation.h\"\n#include \"spatial_kernel.h\"\n\n\nclass Species;\nclass Subpopulation;\nclass Individual;\nclass InteractionType_Class;\n\n\nextern EidosClass *gSLiM_InteractionType_Class;\n\n\n// This class uses an internal implementation of kd-trees for fast nearest-neighbor finding.  We use the same data structure to\n// save computed distances and interaction strengths.  A value of NaN is used as a placeholder to indicate that a given value\n// has not yet been calculated, and we fill the data structure in lazily.  We keep one such data structure per evaluated\n// subpopulation; if a subpopulation is not evaluated there is no overhead.\n#define SLIM_MAX_DIMENSIONALITY\t\t3\n\nstruct _SLiM_kdNode\n{\n\tdouble x[SLIM_MAX_DIMENSIONALITY];\t\t// the coordinates of the individual\n\tslim_popsize_t individual_index_;\t\t// the index of the individual in its subpopulation, and into positions_\n\tstruct _SLiM_kdNode *left;\t\t\t\t// the index of the KDNode for the left side\n\tstruct _SLiM_kdNode *right;\t\t\t\t// the index of the KDNode for the right side\n};\ntypedef struct _SLiM_kdNode SLiM_kdNode;\n\nstruct _InteractionsData\n{\n\t// This flag is true when the interaction has been evaluated.  What that means in practice is that allocated blocks below\n\t// are in sync with the state of the population.  Interactions automatically become un-evaluated at the end of each offspring\n\t// generation phase, when the parental generation that they are based upon expires.  They then need to be re-evaluated,\n\t// which re-synchronizes their state with the state of the new parental generation.  If an interaction is marked as unevaluated,\n\t// it may still have allocated blocks, and their size will be indicated by individual_count_; but individual_count_ may no\n\t// longer have anything to do with the subpopulation for this InteractionsData block.  The intent of this design is to allow\n\t// us to avoid freeing and mallocing large blocks; we want to allocate them once and keep them for the lifetime of the model,\n\t// unless the subpopulation size changes (which forces a reallocation).  This is important because these blocks can be so large\n\t// that they are considered \"large blocks\" by malloc, triggering some very slow processing such as madvise() that is to be\n\t// avoided at all costs.\n\tbool evaluated_ = false;\n\tstd::vector<SLiMEidosBlock*> evaluation_interaction_callbacks_;\n\t\n\tslim_popsize_t individual_count_ = 0;\t// the number of individuals managed; this will be equal to the size of the corresponding subpopulation\n\tslim_popsize_t first_male_index_ = 0;\t// from the subpopulation's value; needed for sex-segregation handling\n\t\n\tbool periodic_x_ = false;\t\t\t\t\t// true if this spatial coordinate is periodic, from the evaluated Species\n\tbool periodic_y_ = false;\t\t\t\t\t// these are in terms of the InteractionType's spatiality, not the simulation's dimensionality!\n\tbool periodic_z_ = false;\n\t\n\tdouble bounds_x1_ = 0.0, bounds_y1_ = 0.0, bounds_z1_ = 0.0;\t// copied from the Subpopulation; the zero-bound in each dimension is guaranteed to be zero *if* the dimension is periodic\n\t\n\t// individual_count_ * SLIM_MAX_DIMENSIONALITY entries, holding coordinate positions for all subpop individuals regardless of constraints\n\tdouble *positions_ = nullptr;\n\t\n\t// BCH 10/31/2023: We now have two separate k-d trees, one containing all individuals (ALL) and one containing only individuals\n\t// that satisfy the exerter constraints of the interaction type (EXERTERS).  Each is constructed on demand, so probably most models\n\t// will only trigger the construction of one or the other; but models that exercise both facilities will now have ~2x the memory usage\n\t// for the k-d tree(s).  That is not typically a ton of memory anyway.  Note that receiver constraints are checked at query time,\n\t// whereas sex-specificity for exerters is checked at k-d tree construction time.  Individuals that do not satisfy the exerter\n\t// constraints are omitted from the EXERTERS k-d tree, and are thus never found/returned.  If no exerter constraints are present,\n\t// the EXERTERS k-d tree will share the same malloced blocks as the ALL k-d tree -- they will be the same tree.\n\t//\n\t// If a given kd_nodes_ pointer is nullptr, the tree has not yet been cached by CacheKDTreeNodes().  If that pointer is non-nullptr\n\t// but the kd_root_ pointer is nullptr, the tree has been cached, but it has not yet been built, OR the k-d tree has zero nodes\n\t// (i.e., is empty); the kd_node_count_ value can be used to distinguish these cases.  If the kd_root_ pointer is also non-nullptr,\n\t// the tree is built and ready to use.  This is all checked by the EnsureKDTreePresent_X() methods, which should always be called to\n\t// get the pointer to a k-d tree root; the pointers below should never be accessed directly by clients of the trees.\n\t\n\t// This k-d tree contains ALL subpop individuals regardless of constraints; it finds \"neighbors\", whether interacting or not\n\tSLiM_kdNode *kd_nodes_ALL_ = nullptr;\t\t// individual_count_ entries, holding the nodes of the k-d tree\n\tSLiM_kdNode *kd_root_ALL_ = nullptr;\t\t// the root of the k-d tree\n\tslim_popsize_t kd_node_count_ALL_ = 0;\t\t// the number of entries in the k-d tree; may be a multiple of individual_count_ due to periodicity\n\t\n\t// This k-d tree contains only individuals satisfying the EXERTERS constraints; it finds \"exerters\" or \"interacting neighbors\"\n\tSLiM_kdNode *kd_nodes_EXERTERS_ = nullptr;\t\t// up to individual_count_ entries, holding the nodes of the k-d tree\n\tSLiM_kdNode *kd_root_EXERTERS_ = nullptr;\t\t// the root of the k-d tree\n\tslim_popsize_t kd_node_count_EXERTERS_ = 0;\t\t// the number of entries in the k-d tree; may be greater than individual_count_ due to periodicity\n\tbool kd_constraints_raise_EXERTERS_ = false;\t// an exerter tree cannot be constructed due to constraints; see EvaluateSubpopulation() for discussion\n\t\n\t_InteractionsData(const _InteractionsData&) = delete;\t\t\t\t\t// no copying\n\t_InteractionsData& operator=(const _InteractionsData&) = delete;\t\t// no copying\n\t_InteractionsData(_InteractionsData&&) noexcept;\t\t\t\t\t\t// move constructor, for std::map compatibility\n\t_InteractionsData& operator=(_InteractionsData&&) noexcept;\t\t\t\t// move assignment, for std::map compatibility\n\t_InteractionsData(void);\t\t\t\t\t\t\t\t\t\t\t\t// null construction, for std::map compatibility\n\t\n\t_InteractionsData(slim_popsize_t p_individual_count, slim_popsize_t p_first_male_index);\n\t~_InteractionsData(void);\n};\ntypedef struct _InteractionsData InteractionsData;\n\n\n// This structure expresses constraints present for exerters or receivers; see the\n// setConstraints() method for details.\ntypedef struct _InteractionConstraints {\n\tbool has_constraints_ = false;\t\t\t\t\t\t\t// true if any constraints at all are present\n\t\n\tIndividualSex sex_ = IndividualSex::kUnspecified;\t\t// IndividualSex::kUnspecified if unspecified\n\t\n\tbool has_nonsex_constraints_ = false;\t\t\t\t\t// true if any non-sex constraints are present\n\t\n\tslim_usertag_t tag_ = SLIM_TAG_UNSET_VALUE;\t\t\t\t// SLIM_TAG_UNSET_VALUE if unspecified\n\tslim_age_t min_age_ = -1, max_age_ = -1;\t\t\t\t// -1 if unspecified; >= 0 otherwise\n\tint8_t migrant_ = -1;\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n\t\n\tbool has_tagL_constraints_ = false;\t\t\t\t\t\t// true if tagLX constraints are present\n\tint8_t tagL0_ = -1;\t\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n\tint8_t tagL1_ = -1;\t\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n\tint8_t tagL2_ = -1;\t\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n\tint8_t tagL3_ = -1;\t\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n\tint8_t tagL4_ = -1;\t\t\t\t\t\t\t\t\t\t// -1 if unspecified; 0 or 1 otherwise\n} InteractionConstraints;\n\n\nclass InteractionType : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\n\tstatic void _WarmUp(void);\t\t\t\t\t// called internally at startup, do not call\n\tfriend InteractionType_Class;\t\t\t\t// so it can call _WarmUp() for us\n\t\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t// for fast setup of the symbol table\n\t\n\tstd::string spatiality_string_;\t\t\t\t// can be \"x\", \"y\", \"z\", \"xy\", \"xz\", \"yz\", or \"xyz\"; this determines spatiality_\n\tint required_dimensionality_;\t\t\t\t// the dimensionality required of all exerter/receiver subpops by our spatiality\n\tint spatiality_;\t\t\t\t\t\t\t// 0=none, 1=1D (x/y/z), 2=2D (xy/xz/yz), 3=3D (xyz)\n\tbool reciprocal_;\t\t\t\t\t\t\t// if true, interaction strengths A->B == B->A; NOW UNUSED\n\tdouble max_distance_;\t\t\t\t\t\t// the maximum distance, beyond which interaction strength is assumed to be zero\n\tdouble max_distance_sq_;\t\t\t\t\t// the maximum distance squared, cached for speed\n\t\n\tInteractionConstraints receiver_constraints_;\t// constraints on who can be a receiver\n\tInteractionConstraints exerter_constraints_;\t// constraints on who can be an exerter\n\tstatic bool _CheckIndividualNonSexConstraints(Individual *p_individual, InteractionConstraints &p_constraints);\n\tstatic bool _PrecheckIndividualNonSexConstraints(Individual *p_individual, InteractionConstraints &p_constraints);\n\t\n\tstatic inline __attribute__((always_inline)) bool CheckIndividualNonSexConstraints(Individual *p_individual, InteractionConstraints &p_constraints)\n\t{\n\t\tif (p_constraints.has_nonsex_constraints_)\n\t\t\treturn _CheckIndividualNonSexConstraints(p_individual, p_constraints);\n\t\treturn true;\n\t}\n\t\n\tstatic inline __attribute__((always_inline)) bool CheckIndividualConstraints(Individual *p_individual, InteractionConstraints &p_constraints)\n\t{\n\t\tif (p_constraints.has_constraints_)\n\t\t{\n\t\t\tif ((p_constraints.sex_ != IndividualSex::kUnspecified) && (p_constraints.sex_ != p_individual->sex_))\n\t\t\t\treturn false;\n\t\t\tif (p_constraints.has_nonsex_constraints_)\n\t\t\t\treturn _CheckIndividualNonSexConstraints(p_individual, p_constraints);\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t// a user-defined tag value\n\t\n\tSpatialKernelType if_type_;\t\t\t\t\t// the interaction function (IF) to use\n\tdouble if_param1_, if_param2_, if_param3_;\t// the parameters for that IF (not all of which may be used)\n\tdouble n_2param2sq_;\t\t\t\t\t\t// for type \"n\", precalculated == 2.0 * if_param2_ * if_param2_\n\t\n\tstd::map<slim_objectid_t, InteractionsData> data_;\t\t// cached data for the interaction, for each \"exerter\" subpopulation\n\t\n\tvoid _InvalidateData(InteractionsData &data);\n\t\n\tvoid CheckSpeciesCompatibility_Generic(Species &species);\n\tvoid CheckSpeciesCompatibility_Receiver(Species &species);\n\tvoid CheckSpeciesCompatibility_Exerter(Species &species);\n\tvoid CheckSpatialCompatibility(Subpopulation *receiver_subpop, Subpopulation *exerter_subpop);\n\t\n\tdouble CalculateDistance(double *p_position1, double *p_position2);\n\tdouble CalculateDistanceWithPeriodicity(double *p_position1, double *p_position2, InteractionsData &p_subpop_data);\n\t\n\tdouble CalculateStrengthNoCallbacks(double p_distance);\n\tdouble CalculateStrengthWithCallbacks(double p_distance, Individual *p_receiver, Individual *p_exerter, std::vector<SLiMEidosBlock*> &p_interaction_callbacks);\n\t\n\tSLiM_kdNode *FindMedian_p0(SLiM_kdNode *start, SLiM_kdNode *end);\n\tSLiM_kdNode *FindMedian_p1(SLiM_kdNode *start, SLiM_kdNode *end);\n\tSLiM_kdNode *FindMedian_p2(SLiM_kdNode *start, SLiM_kdNode *end);\n\tSLiM_kdNode *MakeKDTree1_p0(SLiM_kdNode *t, int len);\n\tSLiM_kdNode *MakeKDTree2_p0(SLiM_kdNode *t, int len);\n\tSLiM_kdNode *MakeKDTree2_p1(SLiM_kdNode *t, int len);\n\tSLiM_kdNode *MakeKDTree3_p0(SLiM_kdNode *t, int len);\n\tSLiM_kdNode *MakeKDTree3_p1(SLiM_kdNode *t, int len);\n\tSLiM_kdNode *MakeKDTree3_p2(SLiM_kdNode *t, int len);\n\t\n\t// Setting up the k-d trees now proceeds in several steps.  CacheKDTreeNodes() allocates the k-d tree buffers and copies positions and indices in, but does not\n\t// set up the left/right pointers -- it doesn't actually make the tree.  It is called at evaluate() time to set up the EXERTERS tree if exerter constraints\n\t// are set up, so that those constraints get applied to the state of the model at snapshot time.  For all other cases, it is called on demand when the tree\n\t// is needed.  BuildKDTree() takes the structure set up by CacheKDTreeNodes() and actually builds the tree structure recursively; it is called on demand when\n\t// the tree is needed.  EnsureKDTreePresent_ALL() and EnsureKDTreePresent_EXERTERS() are called when the corresponding k-d tree is actually needed, and it\n\t// triggers caching and building of the tree as needed.  They return a pointer to the tree root, which is all that is needed to use the tree for queries.\n\t// BEWARE!  Note that the EnsureKDTreePresent_X() methods will return nullptr if the requested tree contains zero nodes!  This needs to be checked!\n\tvoid CacheKDTreeNodes(Subpopulation *subpop, InteractionsData &p_subpop_data, bool p_apply_exerter_constraints, SLiM_kdNode **kd_nodes_ptr, SLiM_kdNode **kd_root_ptr, slim_popsize_t *kd_node_count_ptr);\n\tvoid BuildKDTree(InteractionsData &p_subpop_data, SLiM_kdNode **kd_nodes_ptr, SLiM_kdNode **kd_root_ptr, slim_popsize_t *kd_node_count_ptr);\n\tSLiM_kdNode *EnsureKDTreePresent_ALL(Subpopulation *subpop, InteractionsData &p_subpop_data);\n\tSLiM_kdNode *EnsureKDTreePresent_EXERTERS(Subpopulation *subpop, InteractionsData &p_subpop_data);\n\t\n\tint CheckKDTree1_p0(SLiM_kdNode *t);\n\tvoid CheckKDTree1_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\tint CheckKDTree2_p0(SLiM_kdNode *t);\n\tvoid CheckKDTree2_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\tint CheckKDTree2_p1(SLiM_kdNode *t);\n\tvoid CheckKDTree2_p1_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\tint CheckKDTree3_p0(SLiM_kdNode *t);\n\tvoid CheckKDTree3_p0_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\tint CheckKDTree3_p1(SLiM_kdNode *t);\n\tvoid CheckKDTree3_p1_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\tint CheckKDTree3_p2(SLiM_kdNode *t);\n\tvoid CheckKDTree3_p2_r(SLiM_kdNode *t, double split, bool isLeftSubtree);\n\t\n\tvoid BuildSV_Presences_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector);\n\tvoid BuildSV_Presences_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Presences_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\t\n\tvoid BuildSV_Distances_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector);\n\tvoid BuildSV_Distances_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Distances_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\t\n\tvoid BuildSV_Strengths_f_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Strengths_l_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Strengths_e_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Strengths_n_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Strengths_c_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\tvoid BuildSV_Strengths_t_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SparseVector *p_sparse_vector, int p_phase);\n\t\n\tint CountNeighbors_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index);\n\tint CountNeighbors_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_phase);\n\tint CountNeighbors_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_phase);\n\t\n\tvoid FindNeighbors1_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist);\n\tvoid FindNeighbors1_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist, int p_phase);\n\tvoid FindNeighbors1_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, SLiM_kdNode **best, double *best_dist, int p_phase);\n\tvoid FindNeighborsA_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals);\n\tvoid FindNeighborsA_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals, int p_phase);\n\tvoid FindNeighborsA_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, EidosValue_Object &p_result_vec, std::vector<Individual *> &p_individuals, int p_phase);\n\tvoid FindNeighborsN_1(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_count, SLiM_kdNode **best, double *best_dist);\n\tvoid FindNeighborsN_2(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_count, SLiM_kdNode **best, double *best_dist, int p_phase);\n\tvoid FindNeighborsN_3(SLiM_kdNode *root, double *nd, slim_popsize_t p_focal_individual_index, int p_count, SLiM_kdNode **best, double *best_dist, int p_phase);\n\tvoid FindNeighbors(Subpopulation *p_subpop, SLiM_kdNode *kd_root, slim_popsize_t kd_node_count, double *p_point, int p_count, EidosValue_Object &p_result_vec, Individual *p_excluded_individual, bool constraints_active);\n\t\n\t// this is a malloced 1D/2D/3D buffer, depending on our spatiality, that contains clipped integral values\n\t// for distances, for a focal individual, from 0 to max_distance_ to the nearest edge in each dimension\n\t// it is a cache that can be invalidated, without being deallocated, by setting the cached flag to false\n\tdouble *clipped_integral_ = nullptr;\n\tbool clipped_integral_valid_ = false;\n\t\n\t// A pool of unused SparseVector objects so that, once equilibrated, there is no alloc/realloc activity.  Note this is shared by all species.\n\t// When built multithreaded, we have per-thread sparse vector pools to avoid lock contention, but single-thread there is one pool.\n\t// At present we only use one SparseVector object per pool, but this design will allow new code to access multiple SparseVectors\n\t// simultaneously if that becomes useful for more complex functionality.  The overhead of the pools should be quite small.\n#ifdef _OPENMP\n\tstatic std::vector<std::vector<SparseVector *>> s_freed_sparse_vectors_PERTHREAD;\n\t#if DEBUG\n\tstatic std::vector<int> s_sparse_vector_count_PERTHREAD;\n\t#endif\n#else\n\tstatic std::vector<SparseVector *> s_freed_sparse_vectors_SINGLE;\n\t#if DEBUG\n\tstatic int s_sparse_vector_count_SINGLE;\n\t#endif\n#endif\n\t\n\tstatic inline __attribute__((always_inline)) SparseVector *NewSparseVectorForExerterSubpop(Subpopulation *exerter_subpop, SparseVectorDataType data_type)\n\t{\n\t\t// Return a recycled SparseVector object, or create a new one if we have no recycled objects left.\n\t\t// Objects in the free list are not in a reuseable state yet, and must be reset; see FreeSparseVector() below.\n\t\tSparseVector *sv;\n\t\t\n#ifdef _OPENMP\n\t\t// When running multithreaded, look up the per-thread SparseVector pool to use, and then use the single-threaded variable names\n\t\tint threadnum = omp_get_thread_num();\n\t\tstd::vector<SparseVector *> &s_freed_sparse_vectors_SINGLE = s_freed_sparse_vectors_PERTHREAD[threadnum];\n\t\t#if DEBUG\n\t\tint &s_sparse_vector_count_SINGLE = s_sparse_vector_count_PERTHREAD[threadnum];\n\t\t#endif\n#endif\n\t\t\n\t\tif (s_freed_sparse_vectors_SINGLE.size())\n\t\t{\n\t\t\tsv = s_freed_sparse_vectors_SINGLE.back();\n\t\t\ts_freed_sparse_vectors_SINGLE.pop_back();\n\t\t\t\n\t\t\tsv->Reset(exerter_subpop->parent_subpop_size_, data_type);\n\t\t}\n\t\telse\n\t\t{\n#if DEBUG\n\t\t\tif (++s_sparse_vector_count_SINGLE > 1)\n\t\t\t\tstd::cout << \"new SparseVector(), s_sparse_vector_count_ == \" << s_sparse_vector_count_SINGLE << \"...\" << std::endl;\n#endif\n\t\t\t\n\t\t\tsv = new SparseVector(exerter_subpop->parent_subpop_size_);\n\t\t\tsv->SetDataType(data_type);\n\t\t}\n\t\t\n\t\treturn sv;\n\t}\n\t\n\tstatic inline __attribute__((always_inline)) void FreeSparseVector(SparseVector *sv)\n\t{\n#ifdef _OPENMP\n\t\t// When running multithreaded, look up the per-thread SparseVector pool to use, and then use the single-threaded variable names\n\t\tint threadnum = omp_get_thread_num();\n\t\tstd::vector<SparseVector *> &s_freed_sparse_vectors_SINGLE = s_freed_sparse_vectors_PERTHREAD[threadnum];\n\t\t#if DEBUG\n\t\tint &s_sparse_vector_count_SINGLE = s_sparse_vector_count_PERTHREAD[threadnum];\n\t\t#endif\n#endif\n\t\t\n\t\t// We return mutation runs to the free list without resetting them, because we do not know the ncols\n\t\t// value for their next usage.  They would hang on to their internal buffers for reuse.\n\t\ts_freed_sparse_vectors_SINGLE.emplace_back(sv);\n\t\t\n#if DEBUG\n\t\ts_sparse_vector_count_SINGLE--;\n#endif\n\t}\n\t\n\tvoid FillSparseVectorForReceiverPresences(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, bool constraints_active);\n\tvoid FillSparseVectorForReceiverDistances(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, bool constraints_active);\n\tvoid FillSparseVectorForPointDistances(SparseVector *sv, double *position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root);\n\tvoid FillSparseVectorForReceiverStrengths(SparseVector *sv, Individual *receiver, double *receiver_position, Subpopulation *exerter_subpop, SLiM_kdNode *kd_root, std::vector<SLiMEidosBlock*> &interaction_callbacks);\n\t\npublic:\n\t\n\tCommunity &community_;\t\t\t\t\t\t// we know the community, but we have no focal species\n\t\n\tslim_objectid_t interaction_type_id_;\t\t// the id by which this interaction type is indexed in the chromosome\n\tEidosValue_SP cached_value_inttype_id_;\t\t// a cached value for interaction_type_id_; reset() if that changes\n\t\n\t\n\tInteractionType(const InteractionType&) = delete;\t\t\t\t\t// no copying\n\tInteractionType& operator=(const InteractionType&) = delete;\t\t// no copying\n\tInteractionType(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\tInteractionType(Community &p_community, slim_objectid_t p_interaction_type_id, std::string p_spatiality_string, bool p_reciprocal, double p_max_distance, IndividualSex p_receiver_sex, IndividualSex p_exerter_sex);\n\t~InteractionType(void);\n\t\n\tvoid EvaluateSubpopulation(Subpopulation *p_subpop);\n\tbool AnyEvaluated(void);\n\tvoid Invalidate(void);\n\tvoid InvalidateForSpecies(Species *p_invalid_species);\n\tvoid InvalidateForSubpopulation(Subpopulation *p_invalid_subpop);\n\t\n\tvoid CacheClippedIntegral_1D(void);\n\tvoid CacheClippedIntegral_2D(void);\n\tdouble ClippedIntegral_1D(double indDistanceA1, double indDistanceA2, bool periodic_x);\n\tdouble ClippedIntegral_2D(double indDistanceA1, double indDistanceA2, double indDistanceB1, double indDistanceB2, bool periodic_x, bool periodic_y);\n\t\n\t// apply interaction() callbacks to an interaction strength; the return value is the final interaction strength\n\tdouble ApplyInteractionCallbacks(Individual *p_receiver, Individual *p_exerter, double p_strength, double p_distance, std::vector<SLiMEidosBlock*> &p_interaction_callbacks);\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsageForKDTrees(void);\n\tsize_t MemoryUsageForPositions(void);\n\tstatic size_t MemoryUsageForSparseVectorPool(void);\n\t\n\tstatic inline void DeleteSparseVectorFreeList(void)\n\t{\n\t\t// This is not normally used by SLiM, but it is used in the SLiM test code in order to prevent sparse vectors\n\t\t// that are allocated in one test from carrying over to later tests (which makes leak debugging a pain).\n\t\t\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"InteractionType::DeleteSparseVectorFreeList(): s_freed_sparse_vectors_ change\");\n\t\t\n#ifdef _OPENMP\n\t\t// When running multithreaded, free all pools\n\t\tfor (auto &pool : s_freed_sparse_vectors_PERTHREAD)\n\t\t{\n\t\t\tfor (auto sv : pool)\n\t\t\t\tdelete (sv);\n\t\t\t\n\t\t\tpool.resize(0);\n\t\t}\n\t\t\n\t\t#if DEBUG\n\t\tfor (int &count : s_sparse_vector_count_PERTHREAD)\n\t\t\tcount = 0;\n\t\t#endif\n#else\n\t\tfor (auto sv : s_freed_sparse_vectors_SINGLE)\n\t\t\tdelete (sv);\n\t\t\n\t\ts_freed_sparse_vectors_SINGLE.resize(0);\n\t\t#if DEBUG\n\t\ts_sparse_vector_count_SINGLE = 0;\n\t\t#endif\n#endif\n\t}\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; }\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_clippedIntegral(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_distance(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_distanceFromPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_drawByStrength(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_evaluate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_interactingNeighborCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_localPopulationDensity(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_interactionDistance(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_nearestInteractingNeighbors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_nearestNeighbors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_nearestNeighborsOfPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_neighborCount(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_neighborCountOfPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setConstraints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setInteractionFunction(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_strength(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_testConstraints(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_totalOfNeighborStrengths(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_unevaluate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n};\n\nclass InteractionType_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tInteractionType_Class(const InteractionType_Class &p_original) = delete;\t// no copy-construct\n\tInteractionType_Class& operator=(const InteractionType_Class&) = delete;\t// no copying\n\tinline InteractionType_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { InteractionType::_WarmUp(); }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* __SLiM__interaction_type__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/log_file.cpp",
    "content": "//\n//  log_file.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 11/2/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"log_file.h\"\n\n#include <utility>\n#include <algorithm>\n#include <vector>\n#include <iomanip>\n\n#include \"slim_globals.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"subpopulation.h\"\n\n\n//\n//\tLogFile\n//\n#pragma mark -\n#pragma mark LogFile\n#pragma mark -\n\nLogFile::LogFile(Community &p_community) : community_(p_community)\n{\n}\n\nLogFile::~LogFile(void)\n{\n}\n\nvoid LogFile::Raise_UsesStringKeys(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (LogFile::Raise_UsesStringKeys): cannot use an integer key with the target LogFile object; LogFile always uses string keys.\" << EidosTerminate(nullptr);\n}\n\nvoid LogFile::ConfigureFile(const std::string &p_filePath, std::vector<const std::string *> &p_initialContents, bool p_append, bool p_emitHeader, bool p_compress, const std::string &p_sep)\n{\n\tuser_file_path_ = p_filePath;\n\t\n\t// correct the user-visible path to end in \".gz\" if it doesn't already\n\tif (p_compress && !Eidos_string_hasSuffix(user_file_path_, \".gz\"))\n\t\tuser_file_path_.append(\".gz\");\n\t\n\t// Resolve a ~ at the start of the path, and get a canonical absolute path\n\tresolved_file_path_ = Eidos_AbsolutePath(user_file_path_);\n\t\n\tcompress_ = p_compress;\n\tsep_ = p_sep;\n\temit_header_ = p_emitHeader;\n\t\n\t// We always open the file for writing (or appending) synchronously and write out the initial contents, if any\n\tEidos_WriteToFile(resolved_file_path_, p_initialContents, p_append, p_compress, EidosFileFlush::kForceFlush);\n}\n\nvoid LogFile::SetLogInterval(bool p_autologging_enabled, int64_t p_logInterval)\n{\n\tif (p_autologging_enabled && (p_logInterval < 1))\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::SetLogInterval): the log interval must be >= 1 (or NULL, to disable automatic logging).\" << EidosTerminate();\n\t\n\tautologging_enabled_ = p_autologging_enabled;\n\tlog_interval_ = p_autologging_enabled ? p_logInterval : 0;\n\tautolog_start_ = community_.Tick();\n}\n\nvoid LogFile::SetFlushInterval(bool p_explicit_flushing, int64_t p_flushInterval)\n{\n\tif (p_explicit_flushing && (p_flushInterval < 1))\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::SetFlushInterval): the flush interval must be >= 1 (or NULL, to request the default flushing behavior).\" << EidosTerminate();\n\t\n\texplicit_flushing_ = p_explicit_flushing;\n\tflush_interval_ = p_flushInterval;\n}\n\nEidosValue_SP LogFile::_GeneratedValue_Cycle(const LogFileGeneratorInfo &p_generator_info)\n{\n\tconst std::vector<Species *> &all_species = community_.AllSpecies();\n\tSpecies *species = all_species[p_generator_info.objectid_];\n\tslim_tick_t cycle = species->Cycle();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(cycle));\n}\n\nEidosValue_SP LogFile::_GeneratedValue_CycleStage(const LogFileGeneratorInfo &p_generator_info)\n{\n#pragma unused(p_generator_info)\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\tstd::string stage_string = StringForSLiMCycleStage(cycle_stage);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(stage_string));\n}\n\nEidosValue_SP LogFile::_GeneratedValue_PopulationSexRatio(const LogFileGeneratorInfo &p_generator_info)\n{\n\tconst std::vector<Species *> &all_species = community_.AllSpecies();\n\tSpecies *species = all_species[p_generator_info.objectid_];\n\t\n\tif (species->SexEnabled())\n\t{\n\t\tslim_popsize_t total_individuals = 0, total_males = 0;\n\t\t\n\t\tfor (auto &subpop_iter : species->population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_iter.second;\n\t\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\tslim_popsize_t first_male_index = subpop->parent_first_male_index_;\n\t\t\t\n\t\t\ttotal_individuals += subpop_size;\n\t\t\ttotal_males += (subpop_size - first_male_index);\n\t\t}\n\t\t\n\t\tdouble sex_ratio = (total_individuals == 0) ? 0.0 : (total_males / (double)total_individuals);\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sex_ratio));\n\t}\n\telse\n\t{\n\t\t// no dictionary entry, which will produce NULL\n\t\treturn gStaticEidosValueNULL;\n\t}\n}\n\nEidosValue_SP LogFile::_GeneratedValue_PopulationSize(const LogFileGeneratorInfo &p_generator_info)\n{\n#pragma unused(p_generator_info)\n\tconst std::vector<Species *> &all_species = community_.AllSpecies();\n\tSpecies *species = all_species[p_generator_info.objectid_];\n\tslim_popsize_t total_individuals = 0;\n\t\n\tfor (auto &subpop_iter : species->population_.subpops_)\n\t\ttotal_individuals += (subpop_iter.second)->parent_subpop_size_;\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(total_individuals));\n}\n\nEidosValue_SP LogFile::_GeneratedValue_SubpopulationSexRatio(const LogFileGeneratorInfo &p_generator_info)\n{\n\tSubpopulation *subpop = community_.SubpopulationWithID(p_generator_info.objectid_);\n\t\n\tif (subpop && subpop->species_.SexEnabled())\n\t{\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\tslim_popsize_t first_male_index = subpop->parent_first_male_index_;\n\t\tdouble sex_ratio = (subpop_size == 0) ? 0.0 : ((subpop_size - first_male_index) / (double)subpop_size);\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sex_ratio));\n\t}\n\telse\n\t{\n\t\t// no dictionary entry, which will produce NULL\n\t\treturn gStaticEidosValueNULL;\n\t}\n}\n\nEidosValue_SP LogFile::_GeneratedValue_SubpopulationSize(const LogFileGeneratorInfo &p_generator_info)\n{\n\tSubpopulation *subpop = community_.SubpopulationWithID(p_generator_info.objectid_);\n\t\n\tif (subpop)\n\t{\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(subpop_size));\n\t}\n\telse\n\t{\n\t\t// no dictionary entry, which will produce NULL\n\t\treturn gStaticEidosValueNULL;\n\t}\n}\n\nEidosValue_SP LogFile::_GeneratedValue_Tick(const LogFileGeneratorInfo &p_generator_info)\n{\n#pragma unused(p_generator_info)\n\tslim_tick_t tick = community_.Tick();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tick));\n}\n\nEidosValue_SP LogFile::_GeneratedValue_CustomScript(const LogFileGeneratorInfo &p_generator_info)\n{\n\t// See, e.g., Subpopulation::ApplyFitnessEffectCallbacks() for comments on running scripts\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"LogFile::_GeneratedValue_CustomScript(): running Eidos lambda\");\n\t\n\tEidosScript *generator_script = p_generator_info.script_;\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, generator_script};\n\t\n\tEidosValue_SP result_SP;\n\t\n\ttry\n\t{\n\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\tEidosInterpreter interpreter(*generator_script, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t);\n\t\t\n\t\t// BCH 11/7/2025: note this symbol is now protected in SLiM_ConfigureContext()\n\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_context, p_generator_info.context_);\n\t\t\n\t\tresult_SP = interpreter.EvaluateInterpreterBlock(false, true);\t// do not print output, return the last statement value\n\t\t\n\t\tif (result_SP->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::_GeneratedValue_CustomScript): a LogFile generator script for addCustomColumn() may not return type object.\" << EidosTerminate(nullptr);\n\t\tif ((result_SP->Type() != EidosValueType::kValueNULL) && (result_SP->Count() != 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::_GeneratedValue_CustomScript): a LogFile generator script for addCustomColumn() must return a singleton value, or NULL.\" << EidosTerminate(nullptr);\n\t}\n\tcatch (...)\n\t{\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"_GeneratedValue_CustomScript()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\tgEidosErrorContext = error_context_save;\n\t\n\treturn result_SP;\n}\n\nvoid LogFile::_GeneratedValues_CustomMeanAndSD(const LogFileGeneratorInfo &p_generator_info, EidosValue_SP *p_generated_value_1, EidosValue_SP *p_generated_value_2)\n{\n\t// See, e.g., Subpopulation::ApplyFitnessEffectCallbacks() for comments on running scripts\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"LogFile::_GeneratedValues_CustomMeanAndSD(): running Eidos lambda\");\n\t\n\tEidosScript *generator_script = p_generator_info.script_;\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, generator_script};\n\t\n\tEidosValue_SP result_SP;\n\t\n\ttry\n\t{\n\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\tEidosInterpreter interpreter(*generator_script, client_symbols, function_map, nullptr, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t);\n\t\t\n\t\t// BCH 11/7/2025: note this symbol is now protected in SLiM_ConfigureContext()\n\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_context, p_generator_info.context_);\n\t\t\n\t\tresult_SP = interpreter.EvaluateInterpreterBlock(false, true);\t// do not print output, return the last statement value\n\t\t\n\t\tif ((result_SP->Type() != EidosValueType::kValueInt) && (result_SP->Type() != EidosValueType::kValueFloat) && (result_SP->Type() != EidosValueType::kValueNULL))\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::_GeneratedValues_CustomMeanAndSD): a LogFile generator script for addMeanSDColumns() must return a vector of type integer or float, or NULL.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (result_SP->Count() == 0)\n\t\t{\n\t\t\t// A zero-length result vector, including NULL, will write out NA for mean and sd\n\t\t\t*p_generated_value_1 = gStaticEidosValueNULL;\n\t\t\t*p_generated_value_2 = gStaticEidosValueNULL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// A non-zero result vector gets evaluated for its mean and sd (sd==NA if length 1)\n\t\t\t// We just use eidos_functions here, since it does exactly what we want anyway\n\t\t\tstd::vector<EidosValue_SP> argument_vec;\n\t\t\t\n\t\t\targument_vec.emplace_back(result_SP);\n\t\t\t\n\t\t\tif (result_SP->Count() == 1)\n\t\t\t{\n\t\t\t\t*p_generated_value_1 = Eidos_ExecuteFunction_mean(argument_vec, interpreter);\n\t\t\t\t*p_generated_value_2 = gStaticEidosValueNULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*p_generated_value_1 = Eidos_ExecuteFunction_mean(argument_vec, interpreter);\n\t\t\t\t*p_generated_value_2 = Eidos_ExecuteFunction_sd(argument_vec, interpreter);\n\t\t\t}\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"_GeneratedValues_CustomMeanAndSD()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\tgEidosErrorContext = error_context_save;\n}\n\nvoid LogFile::_OutputValue(std::ostringstream &p_out, EidosValue *p_value)\n{\n\tEidosValueType type = p_value->Type();\n\t\n\tif (type == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL gets logged as NA; mixes paradigms a bit, but seems useful\n\t\tp_out << \"NA\";\n\t}\n\telse\n\t{\n\t\t// Use EidosValue to write the value.  However, we want to control the precision of float output.\n\t\t// Note that this is not thread-safe.\n\t\tint old_precision = gEidosFloatOutputPrecision;\n\t\tgEidosFloatOutputPrecision = float_precision_;\n\t\t\n\t\tp_out << *p_value;\t\t\t// FIXME this doesn't handle string quoting well at present\n\t\t\n\t\tgEidosFloatOutputPrecision = old_precision;\n\t}\n}\n\nvoid LogFile::AppendNewRow(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"LogFile::AppendNewRow(): filesystem write\");\n\t\n\t// Guarantee that we are in the parent generation for all generators, so they don't need to worry\n\tconst std::vector<Species *> &all_species = community_.AllSpecies();\n\t\n\tfor (Species *species : all_species)\n\t\tif (species->population_.child_generation_valid_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::AppendNewRow): (internal error) generating logfile entry with child generation active!\" << EidosTerminate();\n\t\n\tstd::vector<const std::string *> line_vec;\n\tstd::string header_line;\n\tstd::string row_line;\n\t\n\t// Gather all generators into our Dictionary\n\tRemoveAllKeys();\n\t\n\t// Generate the header row if needed\n\tif (!header_logged_)\n\t{\n\t\t// skip emitting the header line if the user has requested that\n\t\tif (emit_header_)\n\t\t{\n\t\t\tstd::ostringstream ss;\n\t\t\tbool first_column = true;\n\t\t\t\n#ifdef SLIMGUI\n\t\t\tstd::vector<std::string> gui_line;\n#endif\n\t\t\t\n\t\t\tfor (const std::string &column_name : column_names_)\n\t\t\t{\n\t\t\t\tif (!first_column)\n\t\t\t\t\tss << sep_;\n\t\t\t\tfirst_column = false;\n\t\t\t\tss << column_name;\n\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\tstd::ostringstream gui_ss;\n\t\t\t\tgui_ss << column_name;\n\t\t\t\tgui_line.emplace_back(gui_ss.str());\n#endif\n\t\t\t}\n\t\t\t\n\t\t\theader_line = ss.str();\n\t\t\tline_vec.emplace_back(&header_line);\n\t\t\t\n#ifdef SLIMGUI\n\t\t\temitted_lines_.emplace_back(std::move(gui_line));\n#endif\n\t\t}\n\t\t\n\t\t// Having emitted the header line, we lock ourselves to prevent inconsistencies in the emitted table\n\t\theader_logged_ = true;\n\t}\n\t\n\t// Generate the text of the row from the Dictionary entries\n\t{\n\t\tstd::ostringstream ss;\n\t\tint column_index = 0;\n\t\t\n#ifdef SLIMGUI\n\t\tstd::vector<std::string> gui_line;\n#endif\n\t\t\n\t\tfor (const LogFileGeneratorInfo &generator : generator_info_)\n\t\t{\n\t\t\tEidosValue_SP generated_value;\n\t\t\t\n\t\t\tswitch (generator.type_)\n\t\t\t{\n\t\t\t\tcase LogFileGeneratorType::kGenerator_Cycle:\n\t\t\t\t\tgenerated_value = _GeneratedValue_Cycle(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_CycleStage:\n\t\t\t\t\tgenerated_value = _GeneratedValue_CycleStage(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_PopulationSexRatio:\n\t\t\t\t\tgenerated_value = _GeneratedValue_PopulationSexRatio(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_PopulationSize:\n\t\t\t\t\tgenerated_value = _GeneratedValue_PopulationSize(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_SubpopulationSexRatio:\n\t\t\t\t\tgenerated_value = _GeneratedValue_SubpopulationSexRatio(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_SubpopulationSize:\n\t\t\t\t\tgenerated_value = _GeneratedValue_SubpopulationSize(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_Tick:\n\t\t\t\t\tgenerated_value = _GeneratedValue_Tick(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_CustomScript:\n\t\t\t\t\tgenerated_value = _GeneratedValue_CustomScript(generator);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LogFileGeneratorType::kGenerator_CustomMeanAndSD:\n\t\t\t\t{\n\t\t\t\t\t// This requires special-casing because it generates two columns\n\t\t\t\t\tEidosValue_SP generated_value_1, generated_value_2;\n\t\t\t\t\t\n\t\t\t\t\t_GeneratedValues_CustomMeanAndSD(generator, &generated_value_1, &generated_value_2);\n\t\t\t\t\t\n\t\t\t\t\t// emit generated_value_1\n\t\t\t\t\tif (column_index != 0)\n\t\t\t\t\t\tss << sep_;\n\t\t\t\t\t\n\t\t\t\t\t_OutputValue(ss, generated_value_1.get());\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tstd::ostringstream gui_ss;\n\t\t\t\t\t_OutputValue(gui_ss, generated_value_1.get());\n\t\t\t\t\tgui_line.emplace_back(gui_ss.str());\n#endif\n\t\t\t\t\t\n\t\t\t\t\tif (generated_value_1->Type() != EidosValueType::kValueNULL)\n\t\t\t\t\t\tSetKeyValue_StringKeys(column_names_[column_index], std::move(generated_value_1));\n\t\t\t\t\t\n\t\t\t\t\tcolumn_index++;\n\t\t\t\t\t\n\t\t\t\t\t// let the code below emit generated_value_2\n\t\t\t\t\tgenerated_value = generated_value_2;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase LogFileGeneratorType::kGenerator_SuppliedColumn:\n\t\t\t\t\tgenerated_value = supplied_values_.GetValueForKey_StringKeys(column_names_[column_index]);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// Emit the generated value and add it to our Dictionary state\n\t\t\tif (column_index != 0)\n\t\t\t\tss << sep_;\n\t\t\t\n\t\t\t_OutputValue(ss, generated_value.get());\n\t\t\t\n#ifdef SLIMGUI\n\t\t\tstd::ostringstream gui_ss;\n\t\t\t_OutputValue(gui_ss, generated_value.get());\n\t\t\tgui_line.emplace_back(gui_ss.str());\n#endif\n\t\t\t\n\t\t\tif (generated_value->Type() != EidosValueType::kValueNULL)\n\t\t\t\tSetKeyValue_StringKeys(column_names_[column_index], std::move(generated_value));\n\t\t\t\n\t\t\tcolumn_index++;\n\t\t}\n\t\t\n\t\trow_line = ss.str();\n\t\tline_vec.emplace_back(&row_line);\n\t\t\n#ifdef SLIMGUI\n\t\temitted_lines_.emplace_back(std::move(gui_line));\n#endif\n\t}\n\t\n\tsupplied_values_.RemoveAllKeys();\n\t\n\tContentsChanged(\"LogFile::AppendNewRow()\");\n\t\n\t// Write out the row\n\tEidosFileFlush flush = EidosFileFlush::kDefaultFlush;\n\t\n\tif (explicit_flushing_)\n\t{\n\t\tunflushed_row_count_++;\n\t\t\n\t\tif (unflushed_row_count_ >= flush_interval_)\n\t\t{\n\t\t\tflush = EidosFileFlush::kForceFlush;\n\t\t\tunflushed_row_count_ = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tflush = EidosFileFlush::kNoFlush;\n\t\t}\n\t}\n\t\n\tEidos_WriteToFile(resolved_file_path_, line_vec, true, compress_, flush);\n}\n\nvoid LogFile::TickEndCallout(void)\n{\n\tif (autologging_enabled_)\n\t{\n\t\tslim_tick_t tick = community_.Tick();\n\t\t\n\t\tif ((tick - autolog_start_) % log_interval_ == 0)\n\t\t\tAppendNewRow();\n\t}\n}\n\nstd::vector<std::string> LogFile::SortedKeys_StringKeys(void) const\n{\n\t// We want to return the column names in order, so we have to override EidosDictionaryUnretained here\n\t// Our column_names_ vector should correspond to EidosDictionaryUnretained's state, just with a fixed order\n\tstd::vector<std::string> string_keys;\n\t\n\tif (header_logged_)\n\t{\n\t\tfor (const std::string &column_name : column_names_)\n\t\t\tstring_keys.push_back(column_name);\n\t}\n\t\n\treturn string_keys;\n}\n\nconst EidosClass *LogFile::Class(void) const\n{\n\treturn gSLiM_LogFile_Class;\n}\n\nvoid LogFile::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << user_file_path_ << \">\";\n}\n\nEidosValue_SP LogFile::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\t//case gEidosID_allKeys:\t// not technically overridden here, but we override AllKeys() to provide new behavior\n\t\tcase gEidosID_filePath:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(user_file_path_));\n\t\tcase gID_logInterval:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(log_interval_));\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_precision:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(float_precision_));\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::GetProperty): property tag accessed on simulation object before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid LogFile::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_precision:\n\t\t{\n\t\t\tint64_t value = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((value < 1) || (value > 22))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::SetProperty): property precision must be in [1,22].\" << EidosTerminate();\n\t\t\t\n\t\t\tfloat_precision_ = (int)value;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP LogFile::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\t\t// our own methods\n\t\tcase gID_addCustomColumn:\t\t\t\treturn ExecuteMethod_addCustomColumn(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addCycle:\t\t\t\t\t\treturn ExecuteMethod_addCycle(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addCycleStage:\t\t\t\t\treturn ExecuteMethod_addCycleStage(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addMeanSDColumns:\t\t\t\treturn ExecuteMethod_addMeanSDColumns(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addPopulationSexRatio:\t\t\treturn ExecuteMethod_addPopulationSexRatio(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addPopulationSize:\t\t\t\treturn ExecuteMethod_addPopulationSize(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSubpopulationSexRatio:\t\treturn ExecuteMethod_addSubpopulationSexRatio(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSubpopulationSize:\t\t\treturn ExecuteMethod_addSubpopulationSize(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSuppliedColumn:\t\t\t\treturn ExecuteMethod_addSuppliedColumn(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addTick:\t\t\t\t\t\treturn ExecuteMethod_addTick(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_flush:\t\t\t\t\t\t\treturn ExecuteMethod_flush(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_logRow:\t\t\t\t\t\treturn ExecuteMethod_logRow(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setLogInterval:\t\t\t\treturn ExecuteMethod_setLogInterval(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setFilePath:\t\t\t\t\treturn ExecuteMethod_setFilePath(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setSuppliedValue:\t\t\t\treturn ExecuteMethod_setSuppliedValue(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_willAutolog:\t\t\t\t\treturn ExecuteMethod_willAutolog(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\t\t// overrides from Dictionary\n\t\tcase gEidosID_addKeysAndValuesFrom:\t\treturn ExecuteMethod_addKeysAndValuesFrom(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_appendKeysAndValuesFrom:\treturn ExecuteMethod_appendKeysAndValuesFrom(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_clearKeysAndValues:\t\treturn ExecuteMethod_clearKeysAndValues(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_setValue:\t\t\t\t\treturn ExecuteMethod_setValue(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\nvoid LogFile::RaiseForLockedHeader(const std::string &p_caller_name)\n{\n\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): this LogFile has already emitted its header line, so new data generators cannot be added.\" << EidosTerminate(nullptr);\n}\n\n//\t*********************\t- (void)addCustomColumn(string$ columnName, string$ source, [* context = NULL])\nEidosValue_SP LogFile::ExecuteMethod_addCustomColumn(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addCustomColumn\");\n\t\n\tEidosValue_String *columnName_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_String *source_value = (EidosValue_String *)p_arguments[1].get();\n\tEidosValue_SP context_value = p_arguments[2];\n\t\n\tconst std::string &column_name = columnName_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tconst std::string &source = source_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\t// See, e.g., Subpopulation::ApplyFitnessEffectCallbacks() for comments on parsing/running script blocks\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\tEidosScript *source_script = new EidosScript(source);\n\t\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, source_script};\n\t\n\ttry {\n\t\tsource_script->Tokenize();\n\t\tsource_script->ParseInterpreterBlockToAST(false);\n\t}\n\tcatch (...)\n\t{\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\tgEidosErrorContext = error_context_save;\n\t\t\tTranslateErrorContextToUserScript(\"ExecuteMethod_addCustomColumn()\");\n\t\t}\n\t\t\n\t\tdelete source_script;\n\t\tsource_script = nullptr;\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_addCustomColumn): tokenize/parse error in script for addCustomColumn().\" << EidosTerminate();\n\t}\n\t\n\tgEidosErrorContext = error_context_save;\n\t\n\t// Check contextValue for validity and make a copy of it.  Copying is needed to\n\t// ensure that the value is not changed underneath us externally, for example\n\t// by a for loop; see https://github.com/MesserLab/SLiM/issues/496.\n\tif (context_value->Type() == EidosValueType::kValueObject)\n\t{\n\t\tEidosValue_Object *context_object = (EidosValue_Object *)context_value.get();\n\t\t\n\t\tif (!context_object->Class()->UsesRetainRelease())\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_addCustomColumn): the context parameter to addCustomColumn() cannot be an object of a class that is not under retain-release, since the lifetime of such objects cannot be guaranteed.  See the documentation for addCustomColumn() for discussion of this limitation.\" << EidosTerminate();\n\t}\n\t\n\tcontext_value = context_value->CopyValues();\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_CustomScript, source_script, -1, std::move(context_value));\n\tcolumn_names_.emplace_back(column_name);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addCycle([No<Species>$ species])\nEidosValue_SP LogFile::ExecuteMethod_addCycle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addCycle\");\n\t\n\t// Figure out the species to log; if species is NULL, check for a singleton species to default to\n\tEidosValue *species_value = p_arguments[0].get();\n\tSpecies *species = SLiM_ExtractSpeciesFromEidosValue_No(species_value, 0, &SLiM_GetCommunityFromInterpreter(p_interpreter), \"addCycle()\");\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_Cycle, nullptr, species->species_id_, EidosValue_SP());\n\t\n\t// column name is \"cycle\" in single-species models; append the species name in multispecies models\n\tstd::string col_name = \"cycle\";\n\t\n\tif (community_.is_explicit_species_)\n\t{\n\t\tcol_name.append(\"_\");\n\t\tcol_name.append(species->name_);\n\t}\n\t\n\tcolumn_names_.emplace_back(col_name);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addCycleStage()\nEidosValue_SP LogFile::ExecuteMethod_addCycleStage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addCycleStage\");\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_CycleStage, nullptr, -1, EidosValue_SP());\n\tcolumn_names_.emplace_back(\"cycle_stage\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addMeanSDColumns(string$ columnName, string$ source, [* context = NULL])\nEidosValue_SP LogFile::ExecuteMethod_addMeanSDColumns(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addMeanSDColumns\");\n\t\n\tEidosValue_String *columnName_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_String *source_value = (EidosValue_String *)p_arguments[1].get();\n\tEidosValue_SP context_value = p_arguments[2];\n\t\n\tconst std::string &column_name = columnName_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tconst std::string &source = source_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\tEidosScript *source_script = new EidosScript(source);\n\t\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, source_script};\n\t\n\ttry {\n\t\tsource_script->Tokenize();\n\t\tsource_script->ParseInterpreterBlockToAST(false);\n\t}\n\tcatch (...)\n\t{\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\tgEidosErrorContext = error_context_save;\n\t\t\tTranslateErrorContextToUserScript(\"ExecuteMethod_addMeanSDColumns()\");\n\t\t}\n\t\t\n\t\tdelete source_script;\n\t\tsource_script = nullptr;\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_addMeanSDColumns): tokenize/parse error in script for addMeanSDColumns().\" << EidosTerminate();\n\t}\n\t\n\tgEidosErrorContext = error_context_save;\n\t\n\t// Check contextValue for validity and make a copy of it.  Copying is needed to\n\t// ensure that the value is not changed underneath us externally, for example\n\t// by a for loop; see https://github.com/MesserLab/SLiM/issues/496.\n\tif (context_value->Type() == EidosValueType::kValueObject)\n\t{\n\t\tEidosValue_Object *context_object = (EidosValue_Object *)context_value.get();\n\t\t\n\t\tif (!context_object->Class()->UsesRetainRelease())\n\t\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_addMeanSDColumns): the context parameter to addMeanSDColumns() cannot be an object of a class that is not under retain-release, since the lifetime of such objects cannot be guaranteed.  See the documentation for addCustomColumn() for discussion of this limitation.\" << EidosTerminate();\n\t}\n\t\n\tcontext_value = context_value->CopyValues();\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_CustomMeanAndSD, source_script, -1, std::move(context_value));\n\tcolumn_names_.emplace_back(column_name + \"_mean\");\n\tcolumn_names_.emplace_back(column_name + \"_sd\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addPopulationSexRatio([No<Species>$ species])\nEidosValue_SP LogFile::ExecuteMethod_addPopulationSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addPopulationSexRatio\");\n\t\n\t// Figure out the species to log; if species is NULL, check for a singleton species to default to\n\tEidosValue *species_value = p_arguments[0].get();\n\tSpecies *species = SLiM_ExtractSpeciesFromEidosValue_No(species_value, 0, &SLiM_GetCommunityFromInterpreter(p_interpreter), \"addPopulationSexRatio()\");\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_PopulationSexRatio, nullptr, species->species_id_, EidosValue_SP());\n\n\t// column name is \"sex_ratio\" in single-species models; append the species name in multispecies models\n\tstd::string col_name = \"sex_ratio\";\n\t\n\tif (community_.is_explicit_species_)\n\t{\n\t\tcol_name.append(\"_\");\n\t\tcol_name.append(species->name_);\n\t}\n\t\n\tcolumn_names_.emplace_back(col_name);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addPopulationSize([No<Species>$ species])\nEidosValue_SP LogFile::ExecuteMethod_addPopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addPopulationSize\");\n\t\n\t// Figure out the species to log; if species is NULL, check for a singleton species to default to\n\tEidosValue *species_value = p_arguments[0].get();\n\tSpecies *species = SLiM_ExtractSpeciesFromEidosValue_No(species_value, 0, &SLiM_GetCommunityFromInterpreter(p_interpreter), \"addPopulationSize()\");\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_PopulationSize, nullptr, species->species_id_, EidosValue_SP());\n\t\n\t// column name is \"num_individuals\" in single-species models; append the species name in multispecies models\n\tstd::string col_name = \"num_individuals\";\n\t\n\tif (community_.is_explicit_species_)\n\t{\n\t\tcol_name.append(\"_\");\n\t\tcol_name.append(species->name_);\n\t}\n\t\n\tcolumn_names_.emplace_back(col_name);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addSubpopulationSexRatio(io<Subpopulation>$ subpop)\nEidosValue_SP LogFile::ExecuteMethod_addSubpopulationSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addSubpopulationSexRatio\");\n\t\n\t// Extract the subpopulation id; we allow reference to nonexistent subpopulations, which is unusual, so there's no function to use\n\tEidosValue *subpop_value = p_arguments[0].get();\n\tslim_objectid_t subpop_id;\n\t\n\tif (subpop_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tsubpop_id = SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr));\n\t}\n\telse\n\t{\n\t\tSubpopulation *subpop = (Subpopulation *)(subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tsubpop_id = subpop->subpopulation_id_;\n\t}\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_SubpopulationSexRatio, nullptr, subpop_id, EidosValue_SP());\n\tcolumn_names_.emplace_back(SLiMEidosScript::IDStringWithPrefix('p', subpop_id) + \"_sex_ratio\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addSubpopulationSize(io<Subpopulation>$ subpop)\nEidosValue_SP LogFile::ExecuteMethod_addSubpopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addSubpopulationSize\");\n\t\n\t// Extract the subpopulation id; we allow reference to nonexistent subpopulations, which is unusual, so there's no function to use\n\tEidosValue *subpop_value = p_arguments[0].get();\n\tslim_objectid_t subpop_id;\n\t\n\tif (subpop_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tsubpop_id = SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr));\n\t}\n\telse\n\t{\n\t\tSubpopulation *subpop = (Subpopulation *)(subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tsubpop_id = subpop->subpopulation_id_;\n\t}\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_SubpopulationSize, nullptr, subpop_id, EidosValue_SP());\n\tcolumn_names_.emplace_back(SLiMEidosScript::IDStringWithPrefix('p', subpop_id) + \"_num_individuals\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addSuppliedColumn(string$ columnName)\nEidosValue_SP LogFile::ExecuteMethod_addSuppliedColumn(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addSuppliedColumn\");\n\t\n\tEidosValue_String *columnName_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &column_name = columnName_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_SuppliedColumn, nullptr, -1, EidosValue_SP());\n\tcolumn_names_.emplace_back(column_name);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)addTick()\nEidosValue_SP LogFile::ExecuteMethod_addTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (header_logged_)\n\t\tRaiseForLockedHeader(\"LogFile::ExecuteMethod_addTick\");\n\t\n\tgenerator_info_.emplace_back(LogFileGeneratorType::kGenerator_Tick, nullptr, -1, EidosValue_SP());\n\t\n\tcolumn_names_.emplace_back(\"tick\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)flush(void)\nEidosValue_SP LogFile::ExecuteMethod_flush(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidos_FlushFile(resolved_file_path_);\n\tunflushed_row_count_ = 0;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)logRow(void)\nEidosValue_SP LogFile::ExecuteMethod_logRow(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tAppendNewRow();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setLogInterval([Ni$ logInterval = NULL])\nEidosValue_SP LogFile::ExecuteMethod_setLogInterval(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *logInterval_value = p_arguments[0].get();\n\tbool autologging = false;\n\tint64_t logInterval = 0;\n\t\n\tif (logInterval_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL turns off autologging\n\t\tautologging = false;\n\t\tlogInterval = 0;\n\t}\n\telse\n\t{\n\t\tautologging = true;\n\t\tlogInterval = logInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\tSetLogInterval(autologging, logInterval);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setFilePath(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [Nl$ compress = NULL], [Ns$ sep = NULL], [Nl$ header = NULL])\nEidosValue_SP LogFile::ExecuteMethod_setFilePath(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue_String *filePath_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue *initialContents_value = p_arguments[1].get();\n\tEidosValue *append_value = p_arguments[2].get();\n\tEidosValue *compress_value = p_arguments[3].get();\n\tEidosValue_String *sep_value = (EidosValue_String *)p_arguments[4].get();\n\tEidosValue *header_value = p_arguments[5].get();\n\t\n\t// BCH 5/23/2025: The documentation has always said \"Any rows that have been buffered but not flushed\n\t// will be written to the previous file first, as if flush() had been called.\"  It looks to me like\n\t// that was not happening.  It seems best to just be explicit about it here, and maybe this fixes a bug.\n\t// Note that in the present design, flushing only affects compressed output; without compression, output\n\t// is always flushed immediately.  See Eidos_WriteToFile().\n\tEidos_FlushFile(resolved_file_path_);\n\tunflushed_row_count_ = 0;\n\t\n\t// Note that the parameters and their interpretation is different from Community::ExecuteMethod_createLogFile();\n\t// in particular, NULL here means \"keep the existing value\"\n\tconst std::string &filePath = filePath_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tstd::vector<const std::string *> initialContents;\n\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool do_compress = compress_;\n\tstd::string sep = sep_;\n\tbool emit_header = emit_header_;\n\t\n\tif (initialContents_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tEidosValue_String *ic_string_value = (EidosValue_String *)initialContents_value;\n\t\tint ic_count = initialContents_value->Count();\n\t\t\n\t\tfor (int ic_index = 0; ic_index < ic_count; ++ic_index)\n\t\t\tinitialContents.emplace_back(&ic_string_value->StringRefAtIndex_NOCAST(ic_index, nullptr));\n\t}\n\t\n\tif (compress_value->Type() != EidosValueType::kValueNULL)\n\t\tdo_compress = compress_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sep_value->Type() != EidosValueType::kValueNULL)\n\t\tsep = sep_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (header_value->Type() != EidosValueType::kValueNULL)\n\t\temit_header = header_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tConfigureFile(filePath, initialContents, append, emit_header, do_compress, sep);\n\t\n\t// BCH 5/23/2025: I think there was probably a bug here before, that a new header line wouldn't be\n\t// emitted into the new target file when using this method. By setting header_logged_ back to false,\n\t// we not only cause a new header line to be emitted, but also again allow changes to the columns;\n\t// I think that's OK, since we're going to a new file, why not?\n\theader_logged_ = false;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setSuppliedValue(string$ columnName, +$ value)\nEidosValue_SP LogFile::ExecuteMethod_setSuppliedValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue_String *columnName_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_SP value = p_arguments[1];\n\t\n\tconst std::string &column_name = columnName_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\t// check that the column name exists and is a supplied column\n\tauto col_iter = std::find(column_names_.begin(), column_names_.end(), column_name);\n\t\n\tif (col_iter == column_names_.end())\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_setSuppliedValue): column name \" << column_name << \" is not a column in the LogFile.\" << EidosTerminate();\n\t\n\tsize_t col_index = std::distance(column_names_.begin(), col_iter);\n\t\n\tLogFileGeneratorInfo &generator = generator_info_[col_index];\n\t\n\tif (generator.type_ != LogFileGeneratorType::kGenerator_SuppliedColumn)\n\t\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_setSuppliedValue): column name \" << column_name << \" is not a supplied column; use addSuppliedColumn() to create a column whose value can be supplied to LogFile.\" << EidosTerminate();\n\t\n\t// remember the supplied value\n\tsupplied_values_.SetKeyValue_StringKeys(column_name, std::move(value));\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (logical$)willAutolog(void)\nEidosValue_SP LogFile::ExecuteMethod_willAutolog(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tbool will_autolog = false;\n\t\n\tif (autologging_enabled_)\n\t{\n\t\tslim_tick_t tick = community_.Tick();\n\t\t\n\t\tif ((tick - autolog_start_) % log_interval_ == 0)\n\t\t\twill_autolog = true;\n\t}\n\t\n\treturn (will_autolog ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n}\n\nEidosValue_SP LogFile::ExecuteMethod_addKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_addKeysAndValuesFrom): LogFile manages its dictionary entries; they cannot be modified by the user.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP LogFile::ExecuteMethod_appendKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_appendKeysAndValuesFrom): LogFile manages its dictionary entries; they cannot be modified by the user.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP LogFile::ExecuteMethod_clearKeysAndValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_clearKeysAndValues): LogFile manages its dictionary entries; they cannot be modified by the user.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP LogFile::ExecuteMethod_setValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_setValue): LogFile manages its dictionary entries; they cannot be modified by the user.\" << EidosTerminate(nullptr);\n}\n\n\n//\n//\tLogFile_Class\n//\n#pragma mark -\n#pragma mark LogFile_Class\n#pragma mark -\n\nEidosClass *gSLiM_LogFile_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *LogFile_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"LogFile_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_filePath,\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_logInterval,\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_precision,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *LogFile_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"LogFile_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\t// our own methods\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addCustomColumn, kEidosValueMaskVOID))->AddString_S(\"columnName\")->AddString_S(gEidosStr_source)->AddAny_O(\"context\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addCycle, kEidosValueMaskVOID))->AddObject_OSN(\"species\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addCycleStage, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addMeanSDColumns, kEidosValueMaskVOID))->AddString_S(\"columnName\")->AddString_S(gEidosStr_source)->AddAny_O(\"context\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPopulationSexRatio, kEidosValueMaskVOID))->AddObject_OSN(\"species\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPopulationSize, kEidosValueMaskVOID))->AddObject_OSN(\"species\", gSLiM_Species_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSubpopulationSexRatio, kEidosValueMaskVOID))->AddIntObject_S(gStr_subpop, gSLiM_Subpopulation_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSubpopulationSize, kEidosValueMaskVOID))->AddIntObject_S(gStr_subpop, gSLiM_Subpopulation_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSuppliedColumn, kEidosValueMaskVOID))->AddString_S(\"columnName\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addTick, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_flush, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_logRow, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setLogInterval, kEidosValueMaskVOID))->AddInt_OSN(\"logInterval\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setFilePath, kEidosValueMaskVOID))->AddString_S(gEidosStr_filePath)->AddString_ON(\"initialContents\", gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OSN(\"compress\", gStaticEidosValueNULL)->AddString_OSN(\"sep\", gStaticEidosValueNULL)->AddLogical_OSN(\"header\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSuppliedValue, kEidosValueMaskVOID))->AddString_S(\"columnName\")->AddAnyBase_S(\"value\")));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_willAutolog, kEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\t\n\t\t// overrides of Dictionary methods; these should not be declared again, to avoid a duplicate in the methods table\n\t\t//methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_addKeysAndValuesFrom, kEidosValueMaskVOID))->AddObject_S(gEidosStr_source, gEidosDictionaryUnretained_Class));\n\t\t//methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_appendKeysAndValuesFrom, kEidosValueMaskVOID))->AddObject(gEidosStr_source, gEidosDictionaryUnretained_Class));\n\t\t//methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_clearKeysAndValues, kEidosValueMaskVOID)));\n\t\t//methods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_setValue, kEidosValueMaskVOID))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, \"key\", nullptr)->AddAny(\"value\")));\n\t\t\n\t\t//methods->emplace_back(((EidosInstanceMethodSignature *)(new EidosClassMethodSignature(gEidosStr_setValuesVectorized, kEidosValueMaskVOID))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, \"key\", nullptr)->AddAny(\"value\")));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nEidosValue_SP LogFile_Class::ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_setValuesVectorized:\treturn ExecuteMethod_setValuesVectorized(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\treturn super::ExecuteClassMethod(p_method_id, p_target, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t+ (void)setValuesVectorized(is$ key, * values)\n//\nEidosValue_SP LogFile_Class::ExecuteMethod_setValuesVectorized(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (LogFile::ExecuteMethod_setValuesVectorized): LogFile manages its dictionary entries; they cannot be modified by the user.\" << EidosTerminate(nullptr);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/log_file.h",
    "content": "//\n//  log_file.h\n//  SLiM\n//\n//  Created by Ben Haller on 11/2/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef log_file_h\n#define log_file_h\n\n#include \"eidos_value.h\"\n#include \"slim_globals.h\"\n\n#include <string>\n#include <sstream>\n\nclass Community;\n\n\nextern EidosClass *gSLiM_LogFile_Class;\n\n\n// Built-in and custom generator types that are presently supported\nenum class LogFileGeneratorType\n{\n\tkGenerator_Cycle,\n\tkGenerator_CycleStage,\n\tkGenerator_PopulationSexRatio,\n\tkGenerator_PopulationSize,\n\tkGenerator_SubpopulationSexRatio,\n\tkGenerator_SubpopulationSize,\n\tkGenerator_Tick,\n\tkGenerator_CustomScript,\n\tkGenerator_CustomMeanAndSD,\t\t\t// results in two columns!\n\tkGenerator_SuppliedColumn\n};\n\nstruct LogFileGeneratorInfo\n{\n\tLogFileGeneratorType type_;\t\t\t// the generator's type, as above\n\tEidosScript *script_;\t\t\t\t// a script to execute to generate the data, or nullptr\n\tslim_objectid_t objectid_;\t\t\t// the identifier for whatever object type might be relevant, or -1\n\tEidosValue_SP context_;\t\t\t\t// the context value for the generator, if any\n\t\n\tLogFileGeneratorInfo(LogFileGeneratorType p_type, EidosScript *p_script, slim_objectid_t p_objectid, EidosValue_SP p_context) : type_(p_type), script_(p_script), objectid_(p_objectid), context_(p_context) {};\n};\n\n\nclass LogFile : public EidosDictionaryRetained\n{\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\nprotected:\n\tvirtual void Raise_UsesStringKeys() const override __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\t\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\tCommunity &community_;\t\t\t\t\t\t\t\t\t\t// UNOWNED POINTER: the community we're working with\n\t\n\tstd::string user_file_path_;\t\t\t\t\t\t\t\t// the one given by the user to us\n\tstd::string resolved_file_path_;\t\t\t\t\t\t\t// the path we use internally, which must be an absolute path\n\t\n\tbool emit_header_ = true;\t\t\t\t\t\t\t\t\t// true if we are supposed to emit a header line at the start\n\tbool header_logged_ = false;\t\t\t\t\t\t\t\t// true if the header has been written out (in which case our generators are locked)\n\t\n\tbool compress_;\n\tstd::string sep_;\t\t\t\t\t\t\t\t\t\t\t// the separator string between values, such as \",\" or \"\\t\"\n\tint float_precision_ = 6;\t\t\t\t\t\t\t\t\t// the precision of output of float values\n\t\n\tbool autologging_enabled_ = false;\t\t\t\t\t\t\t// an overall flag to enable/disable automatic logging\n\tint64_t log_interval_ = 0;\t\t\t\t\t\t\t\t\t// tick interval for automatic logging\n\tslim_tick_t autolog_start_ = 0;\t\t\t\t\t\t\t\t// the first tick in which autologging occurred\n\t\n\tbool explicit_flushing_ = false;\t\t\t\t\t\t\t// an overall flag to enable/disable flushing by number of rows\n\tint64_t flush_interval_ = 0;\t\t\t\t\t\t\t\t// the maximum number of logged rows before we flush\n\tint64_t unflushed_row_count_ = 0;\t\t\t\t\t\t\t// a running counter since the last flush\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t// a user-defined tag value\n\t\n\t// Generators; these generate the data in the log file\n\tstd::vector<LogFileGeneratorInfo> generator_info_;\n\t\n\t// Columns; note that one generator can generate more than one column!\n\tstd::vector<std::string> column_names_;\n\t\n\t// A dictionary of supplied values, for kGenerator_SuppliedColumn\n\tEidosDictionaryUnretained supplied_values_;\n\t\n#ifdef SLIMGUI\n\t// For SLiMgui, LogFile keeps a record of all of the output it generates, which SLiMgui pulls out of it\n\tstd::vector<std::vector<std::string>> emitted_lines_;\n#endif\n\t\n\tvoid RaiseForLockedHeader(const std::string &p_caller_name);\n\t\n\tEidosValue_SP _GeneratedValue_Cycle(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_CycleStage(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_PopulationSexRatio(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_PopulationSize(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_SubpopulationSexRatio(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_SubpopulationSize(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_Tick(const LogFileGeneratorInfo &p_generator_info);\n\tEidosValue_SP _GeneratedValue_CustomScript(const LogFileGeneratorInfo &p_generator_info);\n\tvoid _GeneratedValues_CustomMeanAndSD(const LogFileGeneratorInfo &p_generator_info, EidosValue_SP *p_generated_value_1, EidosValue_SP *p_generated_value_2);\n\t\n\tvoid _OutputValue(std::ostringstream &ss, EidosValue *value);\n\t\npublic:\n\tLogFile(const LogFile &p_original) = delete;\t// no copy-construct\n\tLogFile& operator=(const LogFile&) = delete;\t// no copying\n\t\n\texplicit LogFile(Community &p_community);\n\tvirtual ~LogFile(void) override;\n\t\n\tvoid ConfigureFile(const std::string &p_filePath, std::vector<const std::string *> &p_initialContents, bool p_append, bool p_emitHeader, bool p_compress, const std::string &p_sep);\n\tvoid SetLogInterval(bool p_autologging_enabled, int64_t p_logInterval);\n\tvoid SetFlushInterval(bool p_explicit_flushing, int64_t p_flushInterval);\n\t\n\tvoid AppendNewRow(void);\n\tvoid TickEndCallout(void);\n\t\n\tinline const std::string &UserFilePath(void) const { return user_file_path_; }\n\tinline const std::string &ResolvedFilePath(void) const { return resolved_file_path_; }\n\t\n\tvirtual std::vector<std::string> SortedKeys_StringKeys(void) const override;\t// provide keys in column order\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\t// Our own methods\n\tEidosValue_SP ExecuteMethod_addCustomColumn(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addCycle(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addCycleStage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addMeanSDColumns(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addPopulationSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addPopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSubpopulationSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSubpopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSuppliedColumn(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_flush(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_logRow(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setLogInterval(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setFilePath(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setSuppliedValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_willAutolog(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Overrides of Dictionary methods, since we have a special Dictionary behavior\n\tEidosValue_SP ExecuteMethod_addKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_appendKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_clearKeysAndValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass LogFile_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tLogFile_Class(const LogFile_Class &p_original) = delete;\t// no copy-construct\n\tLogFile_Class& operator=(const LogFile_Class &) = delete;\t// no copying\n\tinline LogFile_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\t\n\t// Overrides of Dictionary methods, since we have a special Dictionary behavior\n\tvirtual EidosValue_SP ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const override;\n\tEidosValue_SP ExecuteMethod_setValuesVectorized(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n};\n\n\n#endif /* log_file_h */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/main.cpp",
    "content": "//\n//  main.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/12/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This file defines main() and related functions that initiate and run a SLiM simulation.\n \n */\n\n\n#include <iostream>\n#include <iomanip>\n#include <ios>\n#include <fstream>\n#include <sstream>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <ctime>\n#include <chrono>\n#include <algorithm>\n#include <sys/stat.h>\n\n#include \"community.h\"\n#include \"species.h\"\n#include \"eidos_globals.h\"\n#include \"slim_globals.h\"\n#include \"eidos_test.h\"\n#include \"slim_test.h\"\n#include \"eidos_symbol_table.h\"\n#include \"interaction_type.h\"\n#include \"eidos_rng.h\"\n\n// Get our Git commit SHA-1, as C string \"g_GIT_SHA1\"\n#include \"../cmake/GitSHA1.h\"\n\n\nstatic void PrintUsageAndDie(bool p_print_header, bool p_print_full_usage)\n{\n\tif (p_print_header)\n\t{\n\t\tSLIM_OUTSTREAM << \"SLiM version \" << SLIM_VERSION_STRING << \", built \" << __DATE__ << \" \" __TIME__ << \".\" << std::endl;\n\t\t\n\t\tif (strcmp(g_GIT_SHA1, \"GITDIR-NOTFOUND\") == 0)\n\t\t\tSLIM_OUTSTREAM << \"Git commit SHA-1: unknown (built from a non-Git source archive)\" << std::endl;\n\t\telse\n\t\t\tSLIM_OUTSTREAM << \"Git commit SHA-1: \" << std::string(g_GIT_SHA1) << std::endl;\n\t\t\n#ifdef DEBUG\n\t\tSLIM_OUTSTREAM << \"This is a DEBUG build of SLiM.\" << std::endl;\n#else\n\t\tSLIM_OUTSTREAM << \"This is a RELEASE build of SLiM.\" << std::endl;\n#endif\n#ifdef _OPENMP\n\t\tSLIM_OUTSTREAM << \"This is a PARALLEL (MULTI-THREADED) build of SLiM.\" << std::endl;\n#else\n\t\tSLIM_OUTSTREAM << \"This is a NON-PARALLEL (SINGLE-THREADED) build of SLiM.\" << std::endl;\n#endif\n#if (SLIMPROFILING == 1)\n\t\tSLIM_OUTSTREAM << \"This is a PROFILING build of SLiM.\" << std::endl;\n#endif\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"SLiM is a product of the Messer Lab, http://messerlab.org/\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"Copyright 2013-2026 Benjamin C. Haller.  All rights reserved.\" << std::endl << std::endl;\n\t\tSLIM_OUTSTREAM << \"By Benjamin C. Haller, http://benhaller.com/, and Philipp Messer.\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"---------------------------------------------------------------------------------\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"SLiM home page: http://messerlab.org/slim/\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"slim-announce mailing list: https://groups.google.com/d/forum/slim-announce\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"slim-discuss mailing list: https://groups.google.com/d/forum/slim-discuss\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"---------------------------------------------------------------------------------\" << std::endl << std::endl;\n\n\t\tSLIM_OUTSTREAM << \"SLiM is free software: you can redistribute it and/or modify it under the terms\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"of the GNU General Public License as published by the Free Software Foundation,\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"either version 3 of the License, or (at your option) any later version.\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"SLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"PURPOSE.  See the GNU General Public License for more details.\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"You should have received a copy of the GNU General Public License along with\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"SLiM.  If not, see <http://www.gnu.org/licenses/>.\" << std::endl << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"---------------------------------------------------------------------------------\" << std::endl << std::endl;\n\t}\n\t\n\tSLIM_OUTSTREAM << \"usage: slim -v[ersion] | -u[sage] | -h[elp] | -testEidos | -testSLiM |\" << std::endl;\n\tSLIM_OUTSTREAM << \"   [-l[ong] [<l>]] [-s[eed] <seed>] [-t[ime]] [-m[em]] [-M[emhist]] [-x]\" << std::endl;\n\tSLIM_OUTSTREAM << \"   [-d[efine] <def>] [-c[heck]] [-p[rogress]] \";\n#ifdef _OPENMP\n\t// Some flags are visible only for a parallel build\n\t// FIXME: these might not fit on the same line as other things\n\tSLIM_OUTSTREAM << \"[-maxThreads <n>] [-perTaskThreads \\\"x\\\"] \";\n#endif\n#if (SLIMPROFILING == 1)\n\t// Some flags are visible only for a profile build\n\tSLIM_OUTSTREAM << \"[<profile-flags>] \";\n#endif\n\tSLIM_OUTSTREAM << \"[<script file>]\" << std::endl;\n\t\n\tif (p_print_full_usage)\n\t{\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -v[ersion]         : print SLiM's version information\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -u[sage]           : print command-line usage help\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -h[elp]            : print full help information\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -testEidos | -te   : run built-in self-diagnostic tests of Eidos\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -testSLiM | -ts    : run built-in self-diagnostic tests of SLiM\" << std::endl;\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -l[ong] [<l>]      : long (i.e., verbose) output of level <l> (default 2)\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -s[eed] <seed>     : supply an initial random number seed for SLiM\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -t[ime]            : print SLiM's total execution time (in user clock time)\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -m[em]             : print SLiM's peak memory usage\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -M[emhist]         : print a histogram of SLiM's memory usage\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -p[rogress]        : show a progress bar in the terminal as SLiM runs\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -x                 : disable SLiM's runtime safety/consistency checks\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -d[efine] <def>    : define an Eidos constant, such as \\\"mu=1e-7\\\"\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -c[heck]           : check the input script's syntax, without executing it\" << std::endl;\n#ifdef _OPENMP\n\t\t// Some flags are visible only for a parallel build\n\t\tSLIM_OUTSTREAM << \"   -maxThreads <n>    : set the maximum number of threads used\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -perTaskThreads \\\"x\\\": set per-task thread counts to named set \\\"x\\\"\" << std::endl;\n#endif\n#if (SLIMPROFILING == 1)\n\t\tSLIM_OUTSTREAM << \"   \" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   <profile-flags>:\" << std::endl;\n\t\t\n\t\tSLIM_OUTSTREAM << \"   -profileStart <n>  : set the first tick to profile\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -profileEnd <n>    : set the last tick to profile\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   -profileOut <path> : set a path for profiling output (default profile.html)\" << std::endl;\n\t\tSLIM_OUTSTREAM << \"   \" << std::endl;\n#endif\n\t\tSLIM_OUTSTREAM << \"   <script file>      : the input script file (stdin may be used instead)\" << std::endl;\n\t}\n\t\n\tif (p_print_header || p_print_full_usage)\n\t\tSLIM_OUTSTREAM << std::endl;\n\t\n\texit(EXIT_SUCCESS);\n}\n\n#if SLIM_LEAK_CHECKING\nstatic void clean_up_leak_false_positives(void)\n{\n\t// This does a little cleanup that helps Valgrind to understand that some things have not been leaked.\n\t// I think perhaps unordered_map keeps values in an unaligned manner that Valgrind doesn't see as pointers.\n\tInteractionType::DeleteSparseVectorFreeList();\n\tFreeSymbolTablePool();\n\tif (gEidos_RNG_Initialized)\n\t\tEidos_FreeRNG();\n}\n#endif\n\nstatic void test_exit(int test_result)\n{\n#if SLIM_LEAK_CHECKING\n\tclean_up_leak_false_positives();\n\t\n\t// sleep() to give time to assess leaks at the command line\n\tstd::cout << \"\\nSLEEPING\" << std::endl;\n\tsleep(60);\n#endif\n\t\n\texit(test_result);\n}\n\nint main(int argc, char *argv[])\t// FIXME: clang-tidy flags this with bugprone-exception-escape, which is probably true\n{\n\t// parse command-line arguments\n\tunsigned long int override_seed = 0;\t\t\t\t\t// this is the type used for seeds in the GSL\n\tunsigned long int *override_seed_ptr = nullptr;\t\t\t// by default, a seed is generated or supplied in the input file\n\tconst char *input_file = nullptr;\n\tbool keep_time = false, keep_mem = false, keep_mem_hist = false, skip_checks = false;\n\tbool tree_seq_checks = false, tree_seq_force = false, show_progress = false, check_script = false;\n\tstd::vector<std::string> defined_constants;\n\t\n#ifdef _OPENMP\n\tlong max_thread_count = omp_get_max_threads();\n\tbool changed_max_thread_count = false;\n\tstd::string per_task_thread_count_set_name = \"\";\t\t// default per-task thread counts\n#endif\n\t\n#if (SLIMPROFILING == 1)\n\tslim_tick_t profile_start_tick = 0;\n\tslim_tick_t profile_end_tick = INT32_MAX;\n\tstd::string profile_output_path = \"slim_profile.html\";\n#endif\n\t\n\t// Test the thread-safety check; enable this #if to confirm that this macro is working\n\t// Note the macro only does its runtime check for a DEBUG build with _OPENMP defined!\n#if 0\n#pragma omp parallel\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"TEST\");\n\t}\n#endif\n\t\n\t// command-line SLiM generally terminates rather than throwing\n\tgEidosTerminateThrows = false;\n\t\n\t// \"slim\" with no arguments prints usage, *unless* stdin is not a tty, in which case we're running the stdin script\n\tif ((argc == 1) && isatty(fileno(stdin)))\n\t\tPrintUsageAndDie(true, false);\n\t\n\tfor (int arg_index = 1; arg_index < argc; ++arg_index)\n\t{\n\t\tconst char *arg = argv[arg_index];\n\t\t\n\t\t// -long or -l [<l>]: switches to long (i.e. verbose) output, with an optional integer level specifier\n\t\tif (strcmp(arg, \"--long\") == 0 || strcmp(arg, \"-long\") == 0 || strcmp(arg, \"-l\") == 0)\n\t\t{\n\t\t\tif (arg_index + 1 == argc)\n\t\t\t{\n\t\t\t\t// -l[ong] is the last command-line argument, so there is no level; default to 2\n\t\t\t\tSLiM_verbosity_level = 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// there is another argument following; if it is an integer, we eat it\n\t\t\t\tconst char *s = argv[arg_index + 1];\n\t\t\t\tbool is_digits = true;\n\t\t\t\t\n\t\t\t\twhile (*s) {\n\t\t\t\t\tif (isdigit(*s++) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tis_digits = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!is_digits)\n\t\t\t\t{\n\t\t\t\t\t// the argument contains non-digit characters, so assume it is not intended for us\n\t\t\t\t\tSLiM_verbosity_level = 2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terrno = 0;\n\t\t\t\t\tlong verbosity = strtol(argv[arg_index + 1], NULL, 10);\n\t\t\t\t\t\n\t\t\t\t\tif (errno)\n\t\t\t\t\t{\n\t\t\t\t\t\t// the argument did not parse as an integer, so assume it is not intended for us\n\t\t\t\t\t\tSLiM_verbosity_level = 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// the argument parsed as an integer, so it is used to set the verbosity level\n\t\t\t\t\t\tif ((verbosity < 0) || (verbosity > 2))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"Verbosity level supplied to -l[ong] must be 0, 1, or 2.\" << std::endl;\n\t\t\t\t\t\t\texit(EXIT_FAILURE);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLiM_verbosity_level = verbosity;\n\t\t\t\t\t\targ_index++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// SLIM_OUTSTREAM << \"// ********** Verbosity level set to \" << SLiM_verbosity_level << std::endl << std::endl;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -seed <x> or -s <x>: override the default seed with the supplied seed value\n\t\tif (strcmp(arg, \"--seed\") == 0 || strcmp(arg, \"-seed\") == 0 || strcmp(arg, \"-s\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\toverride_seed = strtol(argv[arg_index], NULL, 10);\n\t\t\toverride_seed_ptr = &override_seed;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -time or -t: take a time measurement and output it at the end of execution\n\t\tif (strcmp(arg, \"--time\") == 0 || strcmp(arg, \"-time\") == 0 || strcmp(arg, \"-t\") == 0)\n\t\t{\n\t\t\tkeep_time = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -mem or -m: take a peak memory usage measurement and output it at the end of execution\n\t\tif (strcmp(arg, \"--mem\") == 0 || strcmp(arg, \"-mem\") == 0 || strcmp(arg, \"-m\") == 0)\n\t\t{\n\t\t\tkeep_mem = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -mem or -m: take a peak memory usage measurement and output it at the end of execution\n\t\tif (strcmp(arg, \"--Memhist\") == 0 || strcmp(arg, \"-Memhist\") == 0 || strcmp(arg, \"-M\") == 0)\n\t\t{\n\t\t\tkeep_mem = true;\t\t// implied by this\n\t\t\tkeep_mem_hist = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -progress or -p: show a progress bar as the model runs\n\t\tif (strcmp(arg, \"--progress\") == 0 || strcmp(arg, \"-progress\") == 0 || strcmp(arg, \"-p\") == 0)\n\t\t{\n\t\t\tshow_progress = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -x: skip runtime checks for greater speed, or to avoid them if they are causing problems\n\t\tif (strcmp(arg, \"-x\") == 0)\n\t\t{\n\t\t\tskip_checks = true;\n\t\t\teidos_do_memory_checks = false;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -version or -v: print version information\n\t\tif (strcmp(arg, \"--version\") == 0 || strcmp(arg, \"-version\") == 0 || strcmp(arg, \"-v\") == 0)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << \"SLiM version \" << SLIM_VERSION_STRING << \", built \" << __DATE__ << \" \" __TIME__ << std::endl;\n\t\t\t\n\t\t\tif (strcmp(g_GIT_SHA1, \"GITDIR-NOTFOUND\") == 0)\n\t\t\t\tSLIM_OUTSTREAM << \"Git commit SHA-1: unknown (built from a non-Git source archive)\" << std::endl;\n\t\t\telse\n\t\t\t\tSLIM_OUTSTREAM << \"Git commit SHA-1: \" << std::string(g_GIT_SHA1) << std::endl;\n\t\t\t\n\t\t\texit(EXIT_SUCCESS);\n\t\t}\n\t\t\n\t\t// -testEidos or -te: run Eidos tests and quit\n\t\tif (strcmp(arg, \"--testEidos\") == 0 || strcmp(arg, \"-testEidos\") == 0 || strcmp(arg, \"-te\") == 0)\n\t\t{\n#ifdef _OPENMP\n\t\t\tEidos_WarmUpOpenMP(&SLIM_ERRSTREAM, changed_max_thread_count, (int)max_thread_count, true, /* max per-task thread counts */ \"maxThreads\");\n#endif\n\t\t\tEidos_WarmUp();\n\t\t\t\n\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\tint test_result = RunEidosTests();\n\t\t\t\n\t\t\tEidos_FlushFiles();\n\t\t\ttest_exit(test_result);\n\t\t}\n\t\t\n\t\t// -testSLiM or -ts: run SLiM tests and quit\n\t\tif (strcmp(arg, \"--testSLiM\") == 0 || strcmp(arg, \"-testSLiM\") == 0 || strcmp(arg, \"-ts\") == 0)\n\t\t{\n#ifdef _OPENMP\n\t\t\tEidos_WarmUpOpenMP(&SLIM_ERRSTREAM, changed_max_thread_count, (int)max_thread_count, true, /* max per-task thread counts */ \"maxThreads\");\n#endif\n\t\t\tSLiM_ConfigureContext();\n\t\t\tEidos_WarmUp();\n\t\t\tSLiM_WarmUp();\n\t\t\t\n\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\tint test_result = RunSLiMTests();\n\t\t\t\n\t\t\tEidos_FlushFiles();\n\t\t\ttest_exit(test_result);\n\t\t}\n\t\t\n\t\t// -usage or -u: print usage information\n\t\tif (strcmp(arg, \"--usage\") == 0 || strcmp(arg, \"-usage\") == 0 || strcmp(arg, \"-u\") == 0 || strcmp(arg, \"-?\") == 0)\n\t\t\tPrintUsageAndDie(false, true);\n\t\t\n\t\t// -usage or -u: print full help information\n\t\tif (strcmp(arg, \"--help\") == 0 || strcmp(arg, \"-help\") == 0 || strcmp(arg, \"-h\") == 0)\n\t\t\tPrintUsageAndDie(true, true);\n\t\t\n\t\t// -define or -d: define Eidos constants\n\t\tif (strcmp(arg, \"--define\") == 0 || strcmp(arg, \"-define\") == 0 || strcmp(arg, \"-d\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\tdefined_constants.emplace_back(argv[arg_index]);\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -check or -c: check the supplied script without executing it\n\t\tif (strcmp(arg, \"--check\") == 0 || strcmp(arg, \"-check\") == 0 || strcmp(arg, \"-c\") == 0)\n\t\t{\n\t\t\tcheck_script = true;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -maxThreads <x>: set the maximum number of OpenMP threads that will be used\n\t\tif (strcmp(arg, \"-maxThreads\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\tlong count = strtol(argv[arg_index], NULL, 10);\n\t\t\t\n#ifdef _OPENMP\n\t\t\tmax_thread_count = count;\n\t\t\tchanged_max_thread_count = true;\n\t\t\t\n\t\t\tif ((max_thread_count < 1) || (max_thread_count > EIDOS_OMP_MAX_THREADS))\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << \"The -maxThreads command-line option enforces a range of [1, \" << EIDOS_OMP_MAX_THREADS << \"].\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tcontinue;\n#else\n\t\t\tif (count != 1)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << \"The -maxThreads command-line option only allows a value of 1 when not running a PARALLEL build.\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\tcontinue;\n#endif\n\t\t}\n\t\t\n\t\t// -perTaskThreads \"x\": set the per-task thread counts to be used in OpenMP to a named set \"x\"\n\t\tif (strcmp(arg, \"-perTaskThreads\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n#ifdef _OPENMP\n\t\t\t// We just take the name as given; testing against known values will be done later\n\t\t\t// This command-line argument is ignored completely when not parallel\n\t\t\tper_task_thread_count_set_name = std::string(argv[arg_index]);\n#endif\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n#if (SLIMPROFILING == 1)\n\t\tif (strcmp(arg, \"-profileStart\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\tlong tick = strtol(argv[arg_index], NULL, 10);\n\t\t\t\n\t\t\tif ((tick < 0) || (tick > INT32_MAX))\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << \"The -profileStart command-line option enforces a range of [0, 2000000000].\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tprofile_start_tick = (slim_tick_t)tick;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (strcmp(arg, \"-profileEnd\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\tlong tick = strtol(argv[arg_index], NULL, 10);\n\t\t\t\n\t\t\tif ((tick < 0) || (tick > INT32_MAX))\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << \"The -profileEnd command-line option enforces a range of [0, 2000000000].\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tprofile_end_tick = (slim_tick_t)tick;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (strcmp(arg, \"-profileOut\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie(false, true);\n\t\t\t\n\t\t\tstd::string path = std::string(argv[arg_index]);\n\t\t\t\n\t\t\tif (path.length() == 0)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << \"The -profileOut command-line option requires a non-zero-length filesystem path.\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tprofile_output_path = path;\n\t\t\tcontinue;\n\t\t}\n#endif\n\t\t\n        // -TSXC is an undocumented command-line flag that turns on tree-sequence recording and runtime crosschecks\n        if (strcmp(arg, \"-TSXC\") == 0)\n        {\n            tree_seq_checks = true;\n            continue;\n        }\n        \n        // -TSF is an undocumented command-line flag that turns on tree-sequence recording without runtime crosschecks\n        if (strcmp(arg, \"-TSF\") == 0)\n        {\n            tree_seq_force = true;\n            continue;\n        }\n        \n\t\t// this is the fall-through, which should be the input file, and should be the last argument given\n\t\tif ((arg_index + 1 != argc) || strncmp(arg, \"-\", 1) == 0)\n\t\t{\n\t\t\tSLIM_ERRSTREAM << \"Unrecognized command-line argument: \" << arg << std::endl << std::endl;\n\t\t\t\n\t\t\tPrintUsageAndDie(false, true);\n\t\t}\n\t\t\n\t\tinput_file = argv[arg_index];\n\t}\n\t\n\t// check that we got what we need; if no file was supplied, then stdin must not be a tty (i.e., must be a pipe, etc.)\n\tif (!input_file && isatty(fileno(stdin)))\n\t\tPrintUsageAndDie(false, true);\n\t\n\t// for -check / -c, we suppress output other than the result of the check\n\tif (check_script)\n\t{\n\t\tSLiM_verbosity_level = 0;\n\t\tkeep_time = false;\n\t\tkeep_mem = false;\n\t\tkeep_mem_hist = false;\n\t\tskip_checks = false;\n\t\ttree_seq_checks = false;\n\t\ttree_seq_force = false;\n\t\tshow_progress = false;\n\t}\n\t\n\t// announce if we are running a debug build, are skipping runtime checks, etc.\n#if DEBUG\n\tif (SLiM_verbosity_level >= 1)\n\t\tSLIM_ERRSTREAM << \"// ********** DEBUG defined - you are not using a release build of SLiM\" << std::endl << std::endl;\n#endif\n\t\n#ifdef _OPENMP\n\tEidos_WarmUpOpenMP((SLiM_verbosity_level >= 1) ? &SLIM_ERRSTREAM : nullptr, changed_max_thread_count, (int)max_thread_count, true, per_task_thread_count_set_name);\n#endif\n\t\n\tif (SLiM_verbosity_level >= 2)\n\t\tSLIM_ERRSTREAM << \"// ********** The -l[ong] command-line option has enabled verbose output (level \" << SLiM_verbosity_level << \")\" << std::endl << std::endl;\n\t\n\tif (skip_checks && (SLiM_verbosity_level >= 1))\n\t\tSLIM_ERRSTREAM << \"// ********** The -x command-line option has disabled some runtime checks\" << std::endl << std::endl;\n\t\n\t// emit defined constants in verbose mode\n\tif (defined_constants.size() && (SLiM_verbosity_level >= 2))\n\t{\n\t\tfor (std::string &constant : defined_constants)\n\t\t\tstd::cout << \"-d[efine]: \" << constant << std::endl;\n\t\tstd::cout << std::endl;\n\t}\n\t\n\t// keep time (we do this whether or not the -time flag was passed)\n\tstd::clock_t begin_cpu = std::clock();\n\t\n\t// keep memory usage information, if asked to\n\tsize_t *mem_record = nullptr;\n\tint mem_record_index = 0;\n\tint mem_record_capacity = 0;\n\tsize_t initial_mem_usage = 0;\n\tsize_t peak_mem_usage = 0;\n\t\n\tif (keep_mem_hist)\n\t{\n\t\tmem_record_capacity = 16384;\n\t\tmem_record = (size_t *)malloc(mem_record_capacity * sizeof(size_t));\n\t\tif (!mem_record)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): allocation failed; you may need to raise the memory limit for SLiM.\" << std::endl;\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\t}\n\t\n\tif (keep_mem)\n\t{\n\t\t// note we subtract the size of our memory-tracking buffer, here and below\n\t\tinitial_mem_usage = Eidos_GetCurrentRSS() - mem_record_capacity * sizeof(size_t);\n\t}\n\t\n\t// run the simulation\n\tSLiM_ConfigureContext();\n\tEidos_WarmUp();\n\tSLiM_WarmUp();\n\t\n\tCommunity *community = nullptr;\n\tstd::string model_name;\n\t\n\tif (!input_file)\n\t{\n\t\t// no input file supplied; either the user forgot (if stdin is a tty) or they're piping a script into stdin\n\t\t// we checked for the tty case above, so here we assume stdin will supply the script\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(std::cin);\n\t\tmodel_name = \"stdin\";\n\t}\n\telse\n\t{\n\t\t// BCH 1/18/2020: check that input_file is a valid path to a file that we can access before opening it\n\t\t{\n\t\t\tFILE *fp = fopen(input_file, \"r\");\n\t\t\t\n\t\t\tif (!fp)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): could not open input file: \" << input_file << \".\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tstruct stat fileInfo;\n\t\t\tint retval = fstat(fileno(fp), &fileInfo);\n\t\t\t\n\t\t\tif (retval != 0)\n\t\t\t{\n\t\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): could not access input file: \" << input_file << \".\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\t// BCH 30 March 2020: adding S_ISFIFO() as a permitted file type here, to re-enable redirection of input\n\t\t\tif (!S_ISREG(fileInfo.st_mode) && !S_ISFIFO(fileInfo.st_mode))\n\t\t\t{\n\t\t\t\tfclose(fp);\n\t\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): input file \" << input_file << \" is not a regular file (it might be a directory or other special file).\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\tfclose(fp);\n\t\t}\n\t\t\n\t\t// input file supplied; open it and use it\n\t\tstd::ifstream infile(input_file);\n\t\t\n\t\tif (!infile.is_open())\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): could not open input file: \" << input_file << \".\" << std::endl;\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\t\t\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(infile);\n\t\tmodel_name = Eidos_LastPathComponent(std::string(input_file));\n\t}\n\t\n\tif (check_script)\n\t{\n\t\t// We survived loading the script above, so apparently it checks out OK.\n\t\tstd::cout << \"// ********** Check successful; no errors found.\" << std::endl;\n\t\treturn EXIT_SUCCESS;\n\t}\n\t\n\tif (keep_mem_hist)\n\t\tmem_record[mem_record_index++] = Eidos_GetCurrentRSS() - mem_record_capacity * sizeof(size_t);\n\t\n\tif (community)\n\t{\n\t\tcommunity->InitializeRNGFromSeed(override_seed_ptr);\n\t\t\n\t\tEidos_DefineConstantsFromCommandLine(defined_constants);\t// do this after the RNG has been set up\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argc; ++arg_index)\n\t\tcommunity->cli_params_.emplace_back(argv[arg_index]);\n\t\t\n\t\tcommunity->FinishInitialization();\n\t\t\n\t\tif (tree_seq_checks)\n\t\t\tcommunity->AllSpecies_TSXC_Enable();\n        if (tree_seq_force && !tree_seq_checks)\n\t\t\tcommunity->AllSpecies_TSF_Enable();\n\t\t\n#if DO_MEMORY_CHECKS\n\t\t// We check memory usage at the end of every 10 ticks, to be able to provide the user with a decent error message\n\t\t// if the maximum memory limit is exceeded.  Every 10 ticks is a compromise; these checks do take a little time.\n\t\t// Even with a model that runs through ticks very quickly, though, checking every 10 makes little difference.\n\t\t// Models in which the ticks take longer will see no measurable difference in runtime at all.  Note that these\n\t\t// checks can be disabled with the -x command-line option.\n\t\tint mem_check_counter = 0, mem_check_mod = 10;\n#endif\n\t\t\n\t\t// decide whether or not we're showing progress; we show it only if we have a tty (i.e. a terminal window)\n\t\t// it'd be nice if we could show progress in a terminal window even when our output has been redirected, but\n\t\t// I don't know how we'd do that -- how do we write to the terminal if stdout and stderr are redirected??\n\t\tif (show_progress)\n\t\t{\n\t\t\tif (isatty(fileno(stdout)))\n\t\t\t\tEidos_StartProgress(&std::cout);\n\t\t\telse if (isatty(fileno(stderr)))\n\t\t\t\tEidos_StartProgress(&std::cerr);\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::cerr << \"### Not showing progress, since neither stdout nor stderr is a tty.\" << std::endl << std::endl;\n\t\t\t\tshow_progress = false;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Run the simulation to its natural end\n#if (SLIMPROFILING == 1)\n\t\tbool profiling_started = false;\n\t\tbool wrote_profile_report = false;\n#endif\n\t\t\n\t\twhile (true)\n\t\t{\n\t\t\tbool tick_result;\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\tif (!profiling_started && (community->Tick() == profile_start_tick))\n\t\t\t{\n\t\t\t\tcommunity->StartProfiling();\n\t\t\t\tprofiling_started = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (profiling_started)\n\t\t\t{\n\t\t\t\tstd::clock_t startCPUClock = std::clock();\n\t\t\t\tSLIM_PROFILE_BLOCK_START();\n\t\t\t\t\n\t\t\t\ttick_result = community->RunOneTick();\n\t\t\t\t\n\t\t\t\tSLIM_PROFILE_BLOCK_END(community->profile_elapsed_wall_clock);\n\t\t\t\tstd::clock_t endCPUClock = std::clock();\n\t\t\t\t\n\t\t\t\tcommunity->profile_elapsed_CPU_clock += (endCPUClock - startCPUClock);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttick_result = community->RunOneTick();\n\t\t\t}\n\t\t\t\n\t\t\tif (profiling_started && ((!tick_result) || (community->Tick() == profile_end_tick)))\n\t\t\t{\n\t\t\t\tcommunity->StopProfiling();\n\t\t\t\tprofiling_started = false;\n\t\t\t\t\n\t\t\t\tWriteProfileResults(profile_output_path, model_name, community);\n\t\t\t\twrote_profile_report = true;\n\t\t\t\t\n\t\t\t\t// terminate at the end of this tick, since the goal was to produce a profile\n\t\t\t\ttick_result = false;\n\t\t\t}\n#else\n\t\t\ttick_result = community->RunOneTick();\n#endif\n\t\t\t\n\t\t\tif (!tick_result)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tif (show_progress)\n\t\t\t{\n\t\t\t\tslim_tick_t current_tick = community->Tick();\n\t\t\t\tslim_tick_t last_tick = community->EstimatedLastTick();\n\t\t\t\tslim_tick_t progress_step;\n\t\t\t\t\n\t\t\t\tif (last_tick <= 1000)\n\t\t\t\t\tprogress_step = 1;\n\t\t\t\telse if (last_tick <= 10000)\n\t\t\t\t\tprogress_step = 10;\n\t\t\t\telse\n\t\t\t\t\tprogress_step = 100;\t// the maximum value, just so our updates are reasonably frequent\n\t\t\t\t\n\t\t\t\t// We write out a line, as long as we are past initialize(), on any of three conditions:\n\t\t\t\t// it's tick 1, it is a multiple of progress_step ticks, or the progress line got erased\n\t\t\t\tif ((current_tick >= 1) && ((current_tick == 1) || (current_tick % progress_step == 0) || (Eidos_ProgressLength() == 0)))\n\t\t\t\t{\n\t\t\t\t\tdouble progress_fraction = (current_tick - 1) / (double)(last_tick - 1);\n\t\t\t\t\tconst int bar_length = 30;\n\t\t\t\t\tint filled_count = std::max(0, std::min((int)round(bar_length * progress_fraction), bar_length));\n\t\t\t\t\tint empty_count = bar_length - filled_count;\n\t\t\t\t\tstd::string filled_str = std::string(filled_count, '#');\n\t\t\t\t\tstd::string empty_str = std::string(empty_count, ' ');\n\t\t\t\t\tstd::ostringstream out_line;\n\t\t\t\t\t\n\t\t\t\t\t// decided not to use std::setw(3) to put the percentage in a fixed-width field\n\t\t\t\t\tout_line << \" [\" << filled_str << empty_str << \"] : \" << std::setprecision(0) << std::fixed << (progress_fraction * 100) << \"% (tick \" << current_tick << \" of \" << community->EstimatedLastTick() << \")\";\n\t\t\t\t\t\n\t\t\t\t\tEidos_WriteProgress(out_line.str());\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (keep_mem_hist)\n\t\t\t{\n\t\t\t\tif (mem_record_index == mem_record_capacity)\n\t\t\t\t{\n\t\t\t\t\tmem_record_capacity <<= 1;\n\t\t\t\t\tmem_record = (size_t *)realloc(mem_record, mem_record_capacity * sizeof(size_t));\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\t\t\t\tif (!mem_record)\n\t\t\t\t\t{\n\t\t\t\t\t\tSLIM_OUTSTREAM << std::endl << \"ERROR (main): allocation failed; you may need to raise the memory limit for SLiM.\" << std::endl;\n\t\t\t\t\t\texit(EXIT_FAILURE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmem_record[mem_record_index++] = Eidos_GetCurrentRSS() - mem_record_capacity * sizeof(size_t);\n\t\t\t}\n\t\t\t\n#if DO_MEMORY_CHECKS\n\t\t\tif (eidos_do_memory_checks)\n\t\t\t{\n\t\t\t\tmem_check_counter++;\n\t\t\t\t\n\t\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\t{\n\t\t\t\t\t// Check memory usage at the end of the ticks, so we can print a decent error message\n\t\t\t\t\tstd::ostringstream message;\n\t\t\t\t\t\n\t\t\t\t\tmessage << \"(Limit exceeded at end of tick \" << community->Tick() << \".)\" << std::endl;\n\t\t\t\t\t\n\t\t\t\t\tEidos_CheckRSSAgainstMax(\"main()\", message.str());\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t}\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// We write the profile report path at end, so it doesn't get lost in the middle of the output\n\t\tif (wrote_profile_report)\n\t\t{\n\t\t\tstd::cerr << std::endl << \"// profiled from tick \" << community->profile_start_tick << \" to \" << community->profile_end_tick << std::endl;\n\t\t\tstd::cerr << \"// wrote profile results to \" << profile_output_path << std::endl << std::endl;\n\t\t}\n#endif\n\t\t\n\t\t// clean up; but most of this is an unnecessary waste of time in the command-line context\n\t\tEidos_FlushFiles();\n\t\t\n#if SLIM_LEAK_CHECKING\n\t\tdelete community;\n\t\tcommunity = nullptr;\n\t\tclean_up_leak_false_positives();\n\t\t\n\t\t// sleep() to give time to assess leaks at the command line\n\t\tstd::cout << \"\\nSLEEPING\" << std::endl;\n\t\tsleep(60);\n#endif\n\t}\n\t\n\t// end timing and print elapsed time\n\tif (keep_time)\n\t{\n\t\tstd::clock_t end_cpu = std::clock();\n\t\tdouble cpu_time_secs = static_cast<double>(end_cpu - begin_cpu) / CLOCKS_PER_SEC;\n\t\tdouble user_time, sys_time;\n\t\t\n\t\tEidos_GetUserSysTime(&user_time, &sys_time);\n\t\t\n\t\tSLIM_ERRSTREAM << \"// ********** CPU time used: \" << cpu_time_secs << std::endl;\n\t\tif (user_time > 0.0)\n\t\t\tSLIM_ERRSTREAM << \"// ********** User CPU time: \" << user_time << std::endl;\n\t\tif (sys_time > 0.0)\n\t\t\tSLIM_ERRSTREAM << \"// ********** System CPU time: \" << sys_time << std::endl;\n\t\tSLIM_ERRSTREAM << \"// ********** Wall time used: \" << Eidos_WallTimeSeconds() << std::endl;\n\t}\n\t\n\tif (gEidosBenchmarkType != EidosBenchmarkType::kNone)\n\t{\n\t\tSLIM_ERRSTREAM << \"// ********** Benchmark time: \" << Eidos_ElapsedProfileTime(gEidosBenchmarkAccumulator) << std::endl;\n\t}\n\t\n\t// print memory usage stats\n\tif (keep_mem)\n\t{\n\t\tpeak_mem_usage = Eidos_GetPeakRSS();\n\t\t\n\t\tSLIM_ERRSTREAM << \"// ********** Initial memory usage: \" << initial_mem_usage << \" bytes (\" << initial_mem_usage / 1024.0 << \"K, \" << initial_mem_usage / (1024.0 * 1024) << \"MB)\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"// ********** Peak memory usage: \" << peak_mem_usage << \" bytes (\" << peak_mem_usage / 1024.0 << \"K, \" << peak_mem_usage / (1024.0 * 1024) << \"MB)\" << std::endl;\n\t}\n\t\n\tif (keep_mem_hist)\n\t{\n\t\tSLIM_ERRSTREAM << \"// ********** Memory usage history (execute in R for a plot): \" << std::endl;\n\t\tSLIM_ERRSTREAM << \"memhist <- c(\" << std::endl;\n\t\tfor (int hist_index = 0; hist_index < mem_record_index; ++hist_index)\n\t\t{\n\t\t\tSLIM_ERRSTREAM << \"   \" << mem_record[hist_index];\n\t\t\tif (hist_index < mem_record_index - 1)\n\t\t\t\tSLIM_ERRSTREAM << \",\";\n\t\t\tSLIM_ERRSTREAM << std::endl;\n\t\t}\n\t\tSLIM_ERRSTREAM << \")\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"initial_mem <- \" << initial_mem_usage << std::endl;\n\t\tSLIM_ERRSTREAM << \"peak_mem <- \" << peak_mem_usage << std::endl;\n\t\tSLIM_ERRSTREAM << \"#scale <- 1; scale_tag <- \\\"bytes\\\"\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"#scale <- 1024; scale_tag <- \\\"K\\\"\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"scale <- 1024 * 1024; scale_tag <- \\\"MB\\\"\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"#scale <- 1024 * 1024 * 1024; scale_tag <- \\\"GB\\\"\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"plot(memhist / scale, type=\\\"l\\\", ylab=paste0(\\\"Memory usage (\\\", scale_tag, \\\")\\\"), xlab=\\\"Tick (start)\\\", ylim=c(0,peak_mem/scale), lwd=4)\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"abline(h=peak_mem/scale, col=\\\"red\\\")\" << std::endl;\n\t\tSLIM_ERRSTREAM << \"abline(h=initial_mem/scale, col=\\\"blue\\\")\" << std::endl;\n\t\t\n\t\tfree(mem_record);\n\t}\n\t\n\treturn EXIT_SUCCESS;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation.cpp",
    "content": "//\n//  mutation.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"mutation.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"species.h\"\n\n#include <algorithm>\n#include <string>\n#include <vector>\n#include <cstdint>\n#include <csignal>\n\n\n// All Mutation objects get allocated out of a single shared block, for speed; see SLiM_WarmUp()\n// Note this is shared by all species; the mutations for every species come out of the same shared block.\nMutation *gSLiM_Mutation_Block = nullptr;\nMutationIndex gSLiM_Mutation_Block_Capacity = 0;\nMutationIndex gSLiM_Mutation_FreeIndex = -1;\nMutationIndex gSLiM_Mutation_Block_LastUsedIndex = -1;\n\n#ifdef DEBUG_LOCKS_ENABLED\nEidosDebugLock gSLiM_Mutation_LOCK(\"gSLiM_Mutation_LOCK\");\n#endif\n\nslim_refcount_t *gSLiM_Mutation_Refcounts = nullptr;\n\n#define SLIM_MUTATION_BLOCK_INITIAL_SIZE\t16384\t\t// makes for about a 1 MB block; not unreasonable\t\t// NOLINT(*-macro-to-enum) : this is fine\n\nextern std::vector<EidosValue_Object *> gEidosValue_Object_Mutation_Registry;\t// this is in Eidos; see SLiM_IncreaseMutationBlockCapacity()\n\nvoid SLiM_CreateMutationBlock(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SLiM_CreateMutationBlock(): gSLiM_Mutation_Block address change\");\n\t\n\t// first allocate the block; no need to zero the memory\n\tgSLiM_Mutation_Block_Capacity = SLIM_MUTATION_BLOCK_INITIAL_SIZE;\n\tgSLiM_Mutation_Block = (Mutation *)malloc(gSLiM_Mutation_Block_Capacity * sizeof(Mutation));\n\tgSLiM_Mutation_Refcounts = (slim_refcount_t *)malloc(gSLiM_Mutation_Block_Capacity * sizeof(slim_refcount_t));\n\t\n\tif (!gSLiM_Mutation_Block || !gSLiM_Mutation_Refcounts)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_CreateMutationBlock): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t//std::cout << \"Allocating initial mutation block, \" << SLIM_MUTATION_BLOCK_INITIAL_SIZE * sizeof(Mutation) << \" bytes (sizeof(Mutation) == \" << sizeof(Mutation) << \")\" << std::endl;\n\t\n\t// now we need to set up our free list inside the block; initially all blocks are free\n\tfor (MutationIndex i = 0; i < gSLiM_Mutation_Block_Capacity - 1; ++i)\n\t\t*(MutationIndex *)(gSLiM_Mutation_Block + i) = i + 1;\n\t\n\t*(MutationIndex *)(gSLiM_Mutation_Block + gSLiM_Mutation_Block_Capacity - 1) = -1;\n\t\n\t// now that the block is set up, we can start the free list\n\tgSLiM_Mutation_FreeIndex = 0;\n}\n\nvoid SLiM_IncreaseMutationBlockCapacity(void)\n{\n\t// We do not use a THREAD_SAFETY macro here because this needs to be checked in release builds also;\n\t// we are not able to completely protect against this occurring at runtime, and it corrupts the run.\n\t// It's OK for this to be called when we're inside an inactive parallel region; there is then no\n\t// race condition.  When a parallel region is active, even inside a critical region, reallocating\n\t// the mutation block has the potential for a race with other threads.\n\tif (omp_in_parallel())\n\t{\n\t\tstd::cerr << \"ERROR (SLiM_IncreaseMutationBlockCapacity): (internal error) SLiM_IncreaseMutationBlockCapacity() was called to reallocate gSLiM_Mutation_Block inside a parallel section.  If you see this message, you need to increase the pre-allocation margin for your simulation, because it is generating such an unexpectedly large number of new mutations.  Please contact the SLiM developers for guidance on how to do this.\" << std::endl;\n\t\traise(SIGTRAP);\n\t}\n\t\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.start_critical(1);\n#endif\n\t\n\tif (!gSLiM_Mutation_Block)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_IncreaseMutationBlockCapacity): (internal error) called before SLiM_CreateMutationBlock().\" << EidosTerminate();\n\t\n\t// We need to expand the size of our Mutation block.  This has the consequence of invalidating\n\t// every Mutation * in the program.  In general that is fine; we are careful to only keep\n\t// pointers to Mutation temporarily, and for long-term reference we use MutationIndex.  The\n\t// exception to this is EidosValue_Object; the user can put references to mutations into\n\t// variables that need to remain valid across reallocs like this.  We therefore have to hunt\n\t// down every EidosValue_Object that contains Mutations, and fix the pointer inside each of\n\t// them.  Because in SLiMgui all of the running simulations share a single Mutation block at\n\t// the moment, in SLiMgui this patching has to occur across all of the simulations, not just\n\t// the one that made this call.  Yes, this is very gross.  This is why pointers are evil.  :->\n\t\n\t// First let's do our realloc.  We just need to note the change in value for the pointer.\n\t// For now we will just double in size; we don't want to waste too much memory, but we\n\t// don't want to have to realloc too often, either.\n\t// BCH 11 May 2020: the realloc of gSLiM_Mutation_Block is technically problematic, because\n\t// Mutation is non-trivially copyable according to C++.  But it is safe, so I cast to void*\n\t// in the hopes that that will make the warning go away.\n\tstd::uintptr_t old_mutation_block = reinterpret_cast<std::uintptr_t>(gSLiM_Mutation_Block);\n\tMutationIndex old_block_capacity = gSLiM_Mutation_Block_Capacity;\n\t\n\t//std::cout << \"old capacity: \" << old_block_capacity << std::endl;\n\t\n\t// BCH 25 July 2023: check for increasing our block beyond the maximum size of 2^31 mutations.\n\t// See https://github.com/MesserLab/SLiM/issues/361.  Note that the initial size should be\n\t// a power of 2, so that we actually reach the maximum; see SLIM_MUTATION_BLOCK_INITIAL_SIZE.\n\t// In other words, we expect to be at exactly 0x0000000040000000UL here, and thus to double\n\t// to 0x0000000080000000UL, which is a capacity of 2^31, which is the limit of int32_t.\n\tif ((size_t)old_block_capacity > 0x0000000040000000UL)\t// >2^30 means >2^31 when doubled\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_IncreaseMutationBlockCapacity): too many mutations; there is a limit of 2^31 (2147483648) segregating mutations in SLiM.\" << EidosTerminate(nullptr);\n\t\n\tgSLiM_Mutation_Block_Capacity *= 2;\n\tgSLiM_Mutation_Block = (Mutation *)realloc((void*)gSLiM_Mutation_Block, gSLiM_Mutation_Block_Capacity * sizeof(Mutation));\t\t\t\t\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\tgSLiM_Mutation_Refcounts = (slim_refcount_t *)realloc(gSLiM_Mutation_Refcounts, gSLiM_Mutation_Block_Capacity * sizeof(slim_refcount_t));\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\n\tif (!gSLiM_Mutation_Block || !gSLiM_Mutation_Refcounts)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_IncreaseMutationBlockCapacity): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t//std::cout << \"new capacity: \" << gSLiM_Mutation_Block_Capacity << std::endl;\n\t\n\tstd::uintptr_t new_mutation_block = reinterpret_cast<std::uintptr_t>(gSLiM_Mutation_Block);\n\t\n\t// Set up the free list to extend into the new portion of the buffer.  If we are called when\n\t// gSLiM_Mutation_FreeIndex != -1, the free list will start with the new region.\n\tfor (MutationIndex i = old_block_capacity; i < gSLiM_Mutation_Block_Capacity - 1; ++i)\n\t\t*(MutationIndex *)(gSLiM_Mutation_Block + i) = i + 1;\n\t\n\t*(MutationIndex *)(gSLiM_Mutation_Block + gSLiM_Mutation_Block_Capacity - 1) = gSLiM_Mutation_FreeIndex;\n\t\n\tgSLiM_Mutation_FreeIndex = old_block_capacity;\n\t\n\t// Now we go out and fix Mutation * references in EidosValue_Object in all symbol tables\n\tif (new_mutation_block != old_mutation_block)\n\t{\n\t\t// This may be excessively cautious, but I want to avoid subtracting these uintptr_t values\n\t\t// to produce a negative number; that seems unwise and possibly platform-dependent.\n\t\tif (old_mutation_block > new_mutation_block)\n\t\t{\n\t\t\tstd::uintptr_t ptr_diff = old_mutation_block - new_mutation_block;\n\t\t\t\n\t\t\tfor (EidosValue_Object *mutation_value : gEidosValue_Object_Mutation_Registry)\n\t\t\t\tmutation_value->PatchPointersBySubtracting(ptr_diff);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::uintptr_t ptr_diff = new_mutation_block - old_mutation_block;\n\t\t\t\n\t\t\tfor (EidosValue_Object *mutation_value : gEidosValue_Object_Mutation_Registry)\n\t\t\t\tmutation_value->PatchPointersByAdding(ptr_diff);\n\t\t}\n\t}\n\t\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.end_critical();\n#endif\n}\n\nvoid SLiM_ZeroRefcountBlock(MutationRun &p_mutation_registry, bool p_registry_only)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SLiM_ZeroRefcountBlock(): gSLiM_Mutation_Block change\");\n\t\n#ifdef SLIMGUI\n\t// BCH 11/25/2017: This code path needs to be used in SLiMgui to avoid modifying the refcounts\n\t// for mutations in other simulations sharing the mutation block.\n\tp_registry_only = true;\n#endif\n\t\n\tif (p_registry_only)\n\t{\n\t\t// This code path zeros out refcounts just for the mutations currently in use in the registry.\n\t\t// It is thus minimal, but probably quite a bit slower than just zeroing out the whole thing.\n\t\t// BCH 6/8/2023: This is necessary in SLiMgui, as noted above, but also in multispecies sims\n\t\t// so that one species does not step on the toes of another species.\n\t\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\t\tconst MutationIndex *registry_iter = p_mutation_registry.begin_pointer_const();\n\t\tconst MutationIndex *registry_iter_end = p_mutation_registry.end_pointer_const();\n\t\t\n\t\twhile (registry_iter != registry_iter_end)\n\t\t\t*(refcount_block_ptr + (*registry_iter++)) = 0;\n\t}\n\telse\n\t{\n\t\t// Zero out the whole thing with EIDOS_BZERO(), without worrying about which bits are in use.\n\t\t// This hits more memory, but avoids having to read the registry, and should write whole cache lines.\n\t\tEIDOS_BZERO(gSLiM_Mutation_Refcounts, (gSLiM_Mutation_Block_LastUsedIndex + 1) * sizeof(slim_refcount_t));\n\t}\n}\n\nsize_t SLiMMemoryUsageForMutationBlock(void)\n{\n\treturn gSLiM_Mutation_Block_Capacity * sizeof(Mutation);\n}\n\nsize_t SLiMMemoryUsageForFreeMutations(void)\n{\n\tsize_t mut_count = 0;\n\tMutationIndex nextFreeBlock = gSLiM_Mutation_FreeIndex;\n\t\n\twhile (nextFreeBlock != -1)\n\t{\n\t\tmut_count++;\n\t\tnextFreeBlock = *(MutationIndex *)(gSLiM_Mutation_Block + nextFreeBlock);\n\t}\n\t\n\treturn mut_count * sizeof(Mutation);\n}\n\nsize_t SLiMMemoryUsageForMutationRefcounts(void)\n{\n\treturn gSLiM_Mutation_Block_Capacity * sizeof(slim_refcount_t);\n}\n\n\n#pragma mark -\n#pragma mark Mutation\n#pragma mark -\n\n// A global counter used to assign all Mutation objects a unique ID\nslim_mutationid_t gSLiM_next_mutation_id = 0;\n\nMutation::Mutation(MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, int8_t p_nucleotide) :\nmutation_type_ptr_(p_mutation_type_ptr), position_(p_position), selection_coeff_(static_cast<slim_selcoeff_t>(p_selection_coeff)), subpop_index_(p_subpop_index), origin_tick_(p_tick), chromosome_index_(p_chromosome_index), state_(MutationState::kNewMutation), nucleotide_(p_nucleotide), mutation_id_(gSLiM_next_mutation_id++)\n{\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.start_critical(2);\n#endif\n\t\n\t// initialize the tag to the \"unset\" value\n\ttag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\n\t// cache values used by the fitness calculation code for speed; see header\n\tcached_one_plus_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + selection_coeff_);\n\tcached_one_plus_dom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->dominance_coeff_ * selection_coeff_);\n\tcached_one_plus_hemizygousdom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->hemizygous_dominance_coeff_ * selection_coeff_);\n\t\n\t// zero out our refcount, which is now kept in a separate buffer\n\tgSLiM_Mutation_Refcounts[BlockIndex()] = 0;\n\t\n#if DEBUG_MUTATIONS\n\tstd::cout << \"Mutation constructed: \" << this << std::endl;\n#endif\n\t\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.end_critical();\n#endif\n\t\n#if 0\n\t// Dump the memory layout of a Mutation object.  Note this code needs to be synced tightly with the header, since C++ has no real introspection.\n\tstatic bool been_here = false;\n\t\n#pragma omp critical (Mutation_layout_dump)\n\t{\n\t\tif (!been_here)\n\t\t{\n\t\t\tchar *ptr_base = (char *)this;\n\t\t\tchar *ptr_mutation_type_ptr_ = (char *)&(this->mutation_type_ptr_);\n\t\t\tchar *ptr_position_ = (char *)&(this->position_);\n\t\t\tchar *ptr_selection_coeff_ = (char *)&(this->selection_coeff_);\n\t\t\tchar *ptr_subpop_index_ = (char *)&(this->subpop_index_);\n\t\t\tchar *ptr_origin_tick_ = (char *)&(this->origin_tick_);\n\t\t\tchar *ptr_state_ = (char *)&(this->state_);\n\t\t\tchar *ptr_nucleotide_ = (char *)&(this->nucleotide_);\n\t\t\tchar *ptr_scratch_ = (char *)&(this->scratch_);\n\t\t\tchar *ptr_mutation_id_ = (char *)&(this->mutation_id_);\n\t\t\tchar *ptr_tag_value_ = (char *)&(this->tag_value_);\n\t\t\tchar *ptr_cached_one_plus_sel_ = (char *)&(this->cached_one_plus_sel_);\n\t\t\tchar *ptr_cached_one_plus_dom_sel_ = (char *)&(this->cached_one_plus_dom_sel_);\n\t\t\tchar *ptr_cached_one_plus_haploiddom_sel_ = (char *)&(this->cached_one_plus_haploiddom_sel_);\n\t\t\t\n\t\t\tstd::cout << \"Class Mutation memory layout (sizeof(Mutation) == \" << sizeof(Mutation) << \") :\" << std::endl << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_mutation_type_ptr_ - ptr_base) << \" (\" << sizeof(MutationType *) << \" bytes): MutationType *mutation_type_ptr_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_position_ - ptr_base) << \" (\" << sizeof(slim_position_t) << \" bytes): const slim_position_t position_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_selection_coeff_ - ptr_base) << \" (\" << sizeof(slim_selcoeff_t) << \" bytes): slim_selcoeff_t selection_coeff_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_subpop_index_ - ptr_base) << \" (\" << sizeof(slim_objectid_t) << \" bytes): slim_objectid_t subpop_index_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_origin_tick_ - ptr_base) << \" (\" << sizeof(slim_tick_t) << \" bytes): const slim_tick_t origin_tick_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_state_ - ptr_base) << \" (\" << sizeof(int8_t) << \" bytes): const int8_t state_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_nucleotide_ - ptr_base) << \" (\" << sizeof(int8_t) << \" bytes): const int8_t nucleotide_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_scratch_ - ptr_base) << \" (\" << sizeof(int8_t) << \" bytes): const int8_t scratch_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_mutation_id_ - ptr_base) << \" (\" << sizeof(slim_mutationid_t) << \" bytes): const slim_mutationid_t mutation_id_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_tag_value_ - ptr_base) << \" (\" << sizeof(slim_usertag_t) << \" bytes): slim_usertag_t tag_value_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_cached_one_plus_sel_ - ptr_base) << \" (\" << sizeof(slim_selcoeff_t) << \" bytes): slim_selcoeff_t cached_one_plus_sel_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_cached_one_plus_dom_sel_ - ptr_base) << \" (\" << sizeof(slim_selcoeff_t) << \" bytes): slim_selcoeff_t cached_one_plus_dom_sel_\" << std::endl;\n\t\t\tstd::cout << \"   \" << (ptr_cached_one_plus_haploiddom_sel_ - ptr_base) << \" (\" << sizeof(slim_selcoeff_t) << \" bytes): slim_selcoeff_t cached_one_plus_haploiddom_sel_\" << std::endl;\n\t\t\tstd::cout << std::endl;\n\t\t\t\n\t\t\tbeen_here = true;\n\t\t}\n\t}\n#endif\n}\n\nMutation::Mutation(slim_mutationid_t p_mutation_id, MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, int8_t p_nucleotide) :\nmutation_type_ptr_(p_mutation_type_ptr), position_(p_position), selection_coeff_(static_cast<slim_selcoeff_t>(p_selection_coeff)), subpop_index_(p_subpop_index), origin_tick_(p_tick), chromosome_index_(p_chromosome_index), state_(MutationState::kNewMutation), nucleotide_(p_nucleotide), mutation_id_(p_mutation_id)\n{\n\t// initialize the tag to the \"unset\" value\n\ttag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\n\t// cache values used by the fitness calculation code for speed; see header\n\tcached_one_plus_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + selection_coeff_);\n\tcached_one_plus_dom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->dominance_coeff_ * selection_coeff_);\n\tcached_one_plus_hemizygousdom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->hemizygous_dominance_coeff_ * selection_coeff_);\n\t\n\t// zero out our refcount, which is now kept in a separate buffer\n\tgSLiM_Mutation_Refcounts[BlockIndex()] = 0;\n\t\n#if DEBUG_MUTATIONS\n\tstd::cout << \"Mutation constructed: \" << this << std::endl;\n#endif\n\t\n\t// Since a mutation id was supplied by the caller, we need to ensure that subsequent mutation ids generated do not collide\n\t// This constructor (unline the other Mutation() constructor above) is presently never called multithreaded,\n\t// so we just enforce that here.  If that changes, it should start using the debug lock to detect races, as above.\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Mutation::Mutation(): gSLiM_next_mutation_id change\");\n\t\n\tif (gSLiM_next_mutation_id <= mutation_id_)\n\t\tgSLiM_next_mutation_id = mutation_id_ + 1;\n}\n\nvoid Mutation::SelfDelete(void)\n{\n\t// This is called when our retain count reaches zero\n\t// We destruct ourselves and return our memory to our shared pool\n\tMutationIndex mutation_index = BlockIndex();\n\t\n\tthis->~Mutation();\n\tSLiM_DisposeMutationToBlock(mutation_index);\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const Mutation &p_mutation)\n{\n\tp_outstream << \"Mutation{mutation_type_ \" << p_mutation.mutation_type_ptr_->mutation_type_id_ << \", position_ \" << p_mutation.position_ << \", selection_coeff_ \" << p_mutation.selection_coeff_ << \", subpop_index_ \" << p_mutation.subpop_index_ << \", origin_tick_ \" << p_mutation.origin_tick_;\n\t\n\treturn p_outstream;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *Mutation::Class(void) const\n{\n\treturn gSLiM_Mutation_Class;\n}\n\nvoid Mutation::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << mutation_id_ << \":\" << selection_coeff_ << \">\";\n}\n\nEidosValue_SP Mutation::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_chromosome:\n\t\t{\n\t\t\tSpecies &species = mutation_type_ptr_->species_;\n\t\t\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\t\tChromosome *chromosome = chromosomes[chromosome_index_];\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(chromosome, gSLiM_Chromosome_Class));\n\t\t}\n\t\tcase gID_id:\t\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_id_));\n\t\tcase gID_isFixed:\t\t\t// ACCELERATED\n\t\t\treturn (((state_ == MutationState::kFixedAndSubstituted) || (state_ == MutationState::kRemovedWithSubstitution)) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_isSegregating:\t\t// ACCELERATED\n\t\t\treturn ((state_ == MutationState::kInRegistry) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_mutationType:\t\t// ACCELERATED\n\t\t\treturn mutation_type_ptr_->SymbolTableEntry().second;\n\t\tcase gID_originTick:\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(origin_tick_));\n\t\tcase gID_position:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(position_));\n\t\tcase gID_selectionCoeff:\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(selection_coeff_));\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_nucleotide:\t\t// ACCELERATED\n\t\t{\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty): property nucleotide is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\t\n\t\t\tswitch (nucleotide_)\n\t\t\t{\n\t\t\t\tcase 0:\treturn gStaticEidosValue_StringA;\n\t\t\t\tcase 1:\treturn gStaticEidosValue_StringC;\n\t\t\t\tcase 2:\treturn gStaticEidosValue_StringG;\n\t\t\t\tcase 3:\treturn gStaticEidosValue_StringT;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty): (internal error) unrecognized value for nucleotide_.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\tcase gID_nucleotideValue:\t// ACCELERATED\n\t\t{\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty): property nucleotideValue is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\t\n\t\t\tswitch (nucleotide_)\n\t\t\t{\n\t\t\t\tcase 0:\treturn gStaticEidosValue_Integer0;\n\t\t\t\tcase 1:\treturn gStaticEidosValue_Integer1;\n\t\t\t\tcase 2:\treturn gStaticEidosValue_Integer2;\n\t\t\t\tcase 3:\treturn gStaticEidosValue_Integer3;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty): (internal error) unrecognized value for nucleotide_.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\tcase gID_subpopID:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(subpop_index_));\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty): property tag accessed on mutation before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->mutation_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_isFixed(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tlogical_result->set_logical_no_check((value->state_ == MutationState::kFixedAndSubstituted) || (value->state_ == MutationState::kRemovedWithSubstitution), value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_isSegregating(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tlogical_result->set_logical_no_check(value->state_ == MutationState::kInRegistry, value_index);\n\t}\n\t\n\treturn logical_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_nucleotide(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\tint8_t nucleotide = value->nucleotide_;\n\t\t\n\t\tif (nucleotide == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty_Accelerated_nucleotide): property nucleotide is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\n\t\tif (nucleotide == 0)\n\t\t\tstring_result->PushString(gStr_A);\n\t\telse if (nucleotide == 1)\n\t\t\tstring_result->PushString(gStr_C);\n\t\telse if (nucleotide == 2)\n\t\t\tstring_result->PushString(gStr_G);\n\t\telse if (nucleotide == 3)\n\t\t\tstring_result->PushString(gStr_T);\n\t}\n\t\n\treturn string_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_nucleotideValue(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\tint8_t nucleotide = value->nucleotide_;\n\t\t\n\t\tif (nucleotide == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty_Accelerated_nucleotideValue): property nucleotideValue is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(nucleotide, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_originTick(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->origin_tick_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_position(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->position_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->subpop_index_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::GetProperty_Accelerated_tag): property tag accessed on mutation before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_selectionCoeff(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->selection_coeff_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Mutation::GetProperty_Accelerated_mutationType(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class))->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutation *value = (Mutation *)(p_values[value_index]);\n\t\t\n\t\tobject_result->set_object_element_no_check_NORR(value->mutation_type_ptr_, value_index);\n\t}\n\t\n\treturn object_result;\n}\n\nvoid Mutation::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_nucleotide:\n\t\t{\n\t\t\tconst std::string &nucleotide = ((EidosValue_String &)p_value).StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::SetProperty): property nucleotide is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (nucleotide == gStr_A)\t\tnucleotide_ = 0;\n\t\t\telse if (nucleotide == gStr_C)\tnucleotide_ = 1;\n\t\t\telse if (nucleotide == gStr_G)\tnucleotide_ = 2;\n\t\t\telse if (nucleotide == gStr_T)\tnucleotide_ = 3;\n\t\t\telse EIDOS_TERMINATION << \"ERROR (Mutation::SetProperty): property nucleotide may only be set to 'A', 'C', 'G', or 'T'.\" << EidosTerminate();\n\t\t\treturn;\n\t\t}\n\t\tcase gID_nucleotideValue:\n\t\t{\n\t\t\tint64_t nucleotide = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::SetProperty): property nucleotideValue is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\tif ((nucleotide < 0) || (nucleotide > 3))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Mutation::SetProperty): property nucleotideValue may only be set to 0 (A), 1 (C), 2 (G), or 3 (T).\" << EidosTerminate();\n\t\t\t\n\t\t\tnucleotide_ = (int8_t)nucleotide;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_subpopID:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_objectid_t value = SLiMCastToObjectidTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\tsubpop_index_ = value;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nvoid Mutation::SetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Mutation *)(p_values[value_index]))->subpop_index_ = SLiMCastToObjectidTypeOrRaise(source_value);\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Mutation *)(p_values[value_index]))->subpop_index_ = SLiMCastToObjectidTypeOrRaise(source_data[value_index]);\n\t}\n}\n\nvoid Mutation::SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Mutation *)(p_values[value_index]))->tag_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Mutation *)(p_values[value_index]))->tag_value_ = source_data[value_index];\n\t}\n}\n\nEidosValue_SP Mutation::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_setSelectionCoeff:\treturn ExecuteMethod_setSelectionCoeff(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setMutationType:\treturn ExecuteMethod_setMutationType(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (void)setSelectionCoeff(float$ selectionCoeff)\n//\nEidosValue_SP Mutation::ExecuteMethod_setSelectionCoeff(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *selectionCoeff_value = p_arguments[0].get();\n\t\n\tdouble value = selectionCoeff_value->FloatAtIndex_NOCAST(0, nullptr);\n\tslim_selcoeff_t old_coeff = selection_coeff_;\n\t\n\tselection_coeff_ = static_cast<slim_selcoeff_t>(value);\n\t// intentionally no lower or upper bound; -1.0 is lethal, but DFEs may generate smaller values, and we don't want to prevent or bowdlerize that\n\t// also, the dominance coefficient modifies the selection coefficient, so values < -1 are in fact meaningfully different\n\t\n\t// since this selection coefficient came from the user, check and set pure_neutral_ and all_pure_neutral_DFE_\n\tif (selection_coeff_ != 0.0)\n\t{\n\t\tSpecies &species = mutation_type_ptr_->species_;\n\t\t\n\t\tspecies.pure_neutral_ = false;\t\t\t\t\t\t\t// let the sim know that it is no longer a pure-neutral simulation\n\t\tmutation_type_ptr_->all_pure_neutral_DFE_ = false;\t// let the mutation type for this mutation know that it is no longer pure neutral\n\t\t\n\t\t// If a selection coefficient has changed from zero to non-zero, or vice versa, MutationRun's nonneutral mutation caches need revalidation\n\t\tif (old_coeff == 0.0)\n\t\t{\n\t\t\tspecies.nonneutral_change_counter_++;\n\t\t}\n\t}\n\telse if (old_coeff != 0.0)\t// && (selection_coeff_ == 0.0) implied by the \"else\"\n\t{\n\t\tSpecies &species = mutation_type_ptr_->species_;\n\t\t\n\t\t// If a selection coefficient has changed from zero to non-zero, or vice versa, MutationRun's nonneutral mutation caches need revalidation\n\t\tspecies.nonneutral_change_counter_++;\n\t}\n\t\n\t// cache values used by the fitness calculation code for speed; see header\n\tcached_one_plus_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + selection_coeff_);\n\tcached_one_plus_dom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->dominance_coeff_ * selection_coeff_);\n\tcached_one_plus_hemizygousdom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->hemizygous_dominance_coeff_ * selection_coeff_);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)setMutationType(io<MutationType>$ mutType)\n//\nEidosValue_SP Mutation::ExecuteMethod_setMutationType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\tSpecies &species = mutation_type_ptr_->species_;\n\t\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &species.community_, &species, \"setMutationType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\tif (mutation_type_ptr->nucleotide_based_ != mutation_type_ptr_->nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Mutation::ExecuteMethod_setMutationType): setMutationType() does not allow a mutation to be changed from nucleotide-based to non-nucleotide-based or vice versa.\" << EidosTerminate();\n\t\n\t// We take just the mutation type pointer; if the user wants a new selection coefficient, they can do that themselves\n\tmutation_type_ptr_ = mutation_type_ptr;\n\t\n\t// If we are non-neutral, make sure the mutation type knows it is now also non-neutral\n\tif (selection_coeff_ != 0.0)\n\t\tmutation_type_ptr_->all_pure_neutral_DFE_ = false;\n\t\n\t// cache values used by the fitness calculation code for speed; see header\n\tcached_one_plus_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + selection_coeff_);\n\tcached_one_plus_dom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->dominance_coeff_ * selection_coeff_);\n\tcached_one_plus_hemizygousdom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + mutation_type_ptr_->hemizygous_dominance_coeff_ * selection_coeff_);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tMutation_Class\n//\n#pragma mark -\n#pragma mark Mutation_Class\n#pragma mark -\n\nEidosClass *gSLiM_Mutation_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Mutation_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Mutation_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosome,\t\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_isFixed,\t\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_isFixed));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_isSegregating,\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_isSegregating));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationType,\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_MutationType_Class))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_mutationType));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotide,\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_nucleotide));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotideValue,\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_nucleotideValue));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_originTick,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_originTick));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_position,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_position));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_selectionCoeff,\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_selectionCoeff));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_subpopID,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_subpopID)->DeclareAcceleratedSet(Mutation::SetProperty_Accelerated_subpopID));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Mutation::GetProperty_Accelerated_tag)->DeclareAcceleratedSet(Mutation::SetProperty_Accelerated_tag));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Mutation_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Mutation_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSelectionCoeff, kEidosValueMaskVOID))->AddFloat_S(\"selectionCoeff\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setMutationType, kEidosValueMaskVOID))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation.h",
    "content": "//\n//  mutation.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Mutation represents a single mutation, defined by its type, its position on the chromosome, and its selection coefficient.\n Mutations are also tagged with the subpopulation and tick in which they arose.\n \n */\n\n#ifndef __SLiM__mutation__\n#define __SLiM__mutation__\n\n\n#include <iostream>\n\n#include \"slim_globals.h\"\n#include \"eidos_value.h\"\n\nclass MutationType;\n\n\nextern EidosClass *gSLiM_Mutation_Class;\n\n// A global counter used to assign all Mutation objects a unique ID\nextern slim_mutationid_t gSLiM_next_mutation_id;\n\n// A MutationIndex is an index into gSLiM_Mutation_Block (see below); it is used as, in effect, a Mutation *, but is 32-bit.\n// Note that type int32_t is used instead of uint32_t so that -1 can be used as a \"null pointer\"; perhaps UINT32_MAX would be\n// better, but on the other hand using int32_t has the virtue that if we run out of room we will probably crash hard rather\n// than perhaps just silently overrunning gSLiM_Mutation_Block with mysterious memory corruption bugs that are hard to catch.\n// For small simulations, defining this as int16_t instead can produce a substantial speedup (as much as 25%), but there are no\n// safeguards in the code to check for running out of indices, so doing that is quite dangerous at present.  A way to make\n// simulations switch from 16-bit to 32-bit at runtime, to get that speedup when possible, would be nice but in practice is very\n// difficult to code since MutationRun's internal buffer of MutationIndex is accessible and used directly by many clients.\ntypedef int32_t MutationIndex;\n\n// forward declaration of Mutation block allocation; see bottom of header\nclass Mutation;\nextern Mutation *gSLiM_Mutation_Block;\nextern MutationIndex gSLiM_Mutation_Block_Capacity;\n\n\ntypedef enum {\n\tkNewMutation = 0,\t\t\t// the state after new Mutation()\n\tkInRegistry,\t\t\t\t// segregating in the simulation\n\tkRemovedWithSubstitution,\t// removed by removeMutations(substitute=T); transitional from kInRegistry to kFixedAndSubstituted\n\tkFixedAndSubstituted,\t\t// fixed and turned into a Substitution object\n\tkLostAndRemoved\t\t\t\t// lost and removed from the simulation\n} MutationState;\n\nclass Mutation : public EidosDictionaryRetained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\npublic:\n\t\n\tMutationType *mutation_type_ptr_;\t\t\t\t\t// mutation type identifier\n\tconst slim_position_t position_;\t\t\t\t\t// position on the chromosome\n\tslim_selcoeff_t selection_coeff_;\t\t\t\t\t// selection coefficient – not const because it may be changed in script\n\tslim_objectid_t subpop_index_;\t\t\t\t\t\t// subpopulation in which mutation arose (or a user-defined tag value!)\n\tconst slim_tick_t origin_tick_;\t\t\t\t\t\t// tick in which the mutation arose\n\tslim_chromosome_index_t chromosome_index_;\t\t\t// the (uint8_t) index of this mutation's chromosome\n\tint8_t state_;\t\t\t\t\t\t\t\t\t\t// see MutationState above\n\tint8_t nucleotide_;\t\t\t\t\t\t\t\t\t// the nucleotide being kept: A=0, C=1, G=2, T=3.  -1 is used to indicate non-nucleotide-based.\n\tint8_t scratch_;\t\t\t\t\t\t\t\t\t// temporary scratch space for use by algorithms; regard as volatile outside your own code block\n\tconst slim_mutationid_t mutation_id_;\t\t\t\t// a unique id for each mutation, used to track mutations\n\tslim_usertag_t tag_value_;\t\t\t\t\t\t\t// a user-defined tag value\n\t\n#ifdef SLIMGUI\n\tmutable slim_refcount_t gui_reference_count_;\t\t\t// a count of the number of occurrences of this mutation within the selected subpopulations in SLiMgui, valid at cycle end\n\tmutable slim_refcount_t gui_scratch_reference_count_;\t// an additional refcount used for temporary tallies by SLiMgui, valid only when explicitly updated\n#endif\n\t\n\t// We cache values used in the fitness calculation code, for speed.  These are the final fitness effects of this mutation\n\t// when it is homozygous or heterozygous, respectively.  These values are clamped to a minimum of 0.0, so that multiplying\n\t// by them cannot cause the fitness of the individual to go below 0.0, avoiding slow tests in the core fitness loop.  These\n\t// values use slim_selcoeff_t for speed; roundoff should not be a concern, since such differences would be inconsequential.\n\tslim_selcoeff_t cached_one_plus_sel_;\t\t\t\t// a cached value for (1 + selection_coeff_), clamped to 0.0 minimum\n\tslim_selcoeff_t cached_one_plus_dom_sel_;\t\t\t// a cached value for (1 + dominance_coeff * selection_coeff_), clamped to 0.0 minimum\n\tslim_selcoeff_t cached_one_plus_hemizygousdom_sel_;\t// a cached value for (1 + hemizygous_dominance_coeff_ * selection_coeff_), clamped to 0.0 minimum\n\t// NOTE THERE ARE 4 BYTES FREE IN THE CLASS LAYOUT HERE; see Mutation::Mutation() and Mutation layout.graffle\n\t\n#if DEBUG\n\tmutable slim_refcount_t refcount_CHECK_;\t\t\t\t\t// scratch space for checking of parallel refcounting\n#endif\n\t\n\tMutation(const Mutation&) = delete;\t\t\t\t\t// no copying\n\tMutation& operator=(const Mutation&) = delete;\t\t// no copying\n\tMutation(void) = delete;\t\t\t\t\t\t\t// no null construction; Mutation is an immutable class\n\tMutation(MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, int8_t p_nucleotide);\n\tMutation(slim_mutationid_t p_mutation_id, MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, int8_t p_nucleotide);\n\t\n\t// a destructor is needed now that we inherit from EidosDictionaryRetained; we want it to be as minimal as possible, though, and inline\n#if DEBUG_MUTATIONS\n\tinline virtual ~Mutation(void) override\n\t{\n\t\tstd::cout << \"Mutation destructed: \" << this << std::endl;\n\t}\n#else\n\tinline virtual ~Mutation(void) override { }\n#endif\n\t\n\tvirtual void SelfDelete(void) override;\n\t\n\tinline __attribute__((always_inline)) MutationIndex BlockIndex(void) const\t\t\t{ return (MutationIndex)(this - gSLiM_Mutation_Block); }\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_setSelectionCoeff(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setMutationType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_isFixed(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_isSegregating(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_nucleotide(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_nucleotideValue(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_originTick(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_position(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_selectionCoeff(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_mutationType(EidosObject **p_values, size_t p_values_size);\n\t\n\t// Accelerated property writing; see class EidosObject for comments on this mechanism\n\tstatic void SetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n};\n\n// true if M1 has an earlier (smaller) position than M2\ninline __attribute__((always_inline)) bool operator<(const Mutation &p_mutation1, const Mutation &p_mutation2)\n{\n\treturn (p_mutation1.position_ < p_mutation2.position_);\n}\n\n// like operator< but with pointers; used for sort() among other things\n// this is kept in terms of Mutation * so callers can cache gSLiM_Mutation_Block locally\ninline __attribute__((always_inline)) bool CompareMutations(const Mutation *p_mutation1, const Mutation *p_mutation2)\n{\n\treturn (p_mutation1->position_ < p_mutation2->position_);\n}\n\n// support stream output of Mutation, for debugging\nstd::ostream &operator<<(std::ostream &p_outstream, const Mutation &p_mutation);\n\nclass Mutation_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tMutation_Class(const Mutation_Class &p_original) = delete;\t// no copy-construct\n\tMutation_Class& operator=(const Mutation_Class&) = delete;\t// no copying\n\tinline Mutation_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n//\n//\t\tMutation block allocation\n//\n\n// All Mutation objects get allocated out of a single shared pool, for speed.  We do not use EidosObjectPool for this\n// any more, because we need the allocation to be out of a single contiguous block of memory that we realloc as needed,\n// allowing Mutation objects to be referred to using 32-bit indexes into this contiguous block.  So we have a custom\n// pool, declared here and implemented in mutation.cpp.  Note that this is a global, to make it easy for users of\n// MutationIndex to look up mutations without needing to track down a pointer to the mutation block from the sim.  This\n// means that in SLiMgui a single block will be used for all mutations in all simulations; that should be harmless.\nclass MutationRun;\n\nextern Mutation *gSLiM_Mutation_Block;\nextern MutationIndex gSLiM_Mutation_FreeIndex;\nextern MutationIndex gSLiM_Mutation_Block_LastUsedIndex;\n\n#ifdef DEBUG_LOCKS_ENABLED\n// We do not arbitrate access to the mutation block with a lock; instead, we expect that clients\n// will manage their own multithreading issues.  In DEBUG mode we check for incorrect uses (races).\n// We use this lock to check.  Any failure to acquire the lock indicates a race.\nextern EidosDebugLock gSLiM_Mutation_LOCK;\n#endif\n\nextern slim_refcount_t *gSLiM_Mutation_Refcounts;\t// an auxiliary buffer, parallel to gSLiM_Mutation_Block, to increase memory cache efficiency\n\t\t\t\t\t\t\t\t\t\t\t\t\t// note that I tried keeping the fitness cache values and positions in separate buffers too, not a win\nvoid SLiM_CreateMutationBlock(void);\nvoid SLiM_IncreaseMutationBlockCapacity(void);\nvoid SLiM_ZeroRefcountBlock(MutationRun &p_mutation_registry, bool p_registry_only);\nsize_t SLiMMemoryUsageForMutationBlock(void);\nsize_t SLiMMemoryUsageForFreeMutations(void);\nsize_t SLiMMemoryUsageForMutationRefcounts(void);\n\ninline __attribute__((always_inline)) MutationIndex SLiM_NewMutationFromBlock(void)\n{\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.start_critical(0);\n#endif\n\t\n\tif (gSLiM_Mutation_FreeIndex == -1)\n\t\tSLiM_IncreaseMutationBlockCapacity();\n\t\n\tMutationIndex result = gSLiM_Mutation_FreeIndex;\n\t\n\tgSLiM_Mutation_FreeIndex = *(MutationIndex *)(gSLiM_Mutation_Block + result);\n\t\n\tif (gSLiM_Mutation_Block_LastUsedIndex < result)\n\t\tgSLiM_Mutation_Block_LastUsedIndex = result;\n\t\n#ifdef DEBUG_LOCKS_ENABLED\n\tgSLiM_Mutation_LOCK.end_critical();\n#endif\n\t\n\treturn result;\t// no need to zero out the memory, we are just an allocater, not a constructor\n}\n\ninline __attribute__((always_inline)) void SLiM_DisposeMutationToBlock(MutationIndex p_mutation_index)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"SLiM_DisposeMutationToBlock(): gSLiM_Mutation_Block change\");\n\t\n\tvoid *mut_ptr = gSLiM_Mutation_Block + p_mutation_index;\n\t\n\t*(MutationIndex *)mut_ptr = gSLiM_Mutation_FreeIndex;\n\tgSLiM_Mutation_FreeIndex = p_mutation_index;\n}\n\n\n#endif /* defined(__SLiM__mutation__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation_run.cpp",
    "content": "//\n//  mutation_run.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 11/29/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"mutation_run.h\"\n\n#include <vector>\n\n\n// For doing bulk operations across all MutationRun objects; see header\nint64_t MutationRun::sOperationID = 0;\n\n\nMutationRun::MutationRun(void)\n#ifdef DEBUG_LOCKS_ENABLED\n\t: mutrun_use_count_LOCK(\"mutrun_use_count_LOCK\")\n#endif\n{\n\t// give it some initial capacity\n\tmutation_capacity_ = SLIM_MUTRUN_INITIAL_CAPACITY;\n\tmutations_ = (MutationIndex *)malloc(mutation_capacity_ * sizeof(MutationIndex));\n\tif (!mutations_)\n\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::MutationRun): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n}\n\nMutationRun::~MutationRun(void)\n{\n\tfree(mutations_);\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tif (nonneutral_mutations_)\n\t\tfree(nonneutral_mutations_);\n#endif\n}\n\n#if 0\n// linear search\nbool MutationRun::contains_mutation(const Mutation *p_mut) const\n{\n\tMutationIndex mutation_index = p_mut->BlockIndex();\n\tconst MutationIndex *position = begin_pointer_const();\n\tconst MutationIndex *end_position = end_pointer_const();\n\t\n\tfor (; position != end_position; ++position)\n\t\tif (*position == mutation_index)\n\t\t\treturn true;\n\t\n\treturn false;\n}\n#else\n// binary search\nbool MutationRun::contains_mutation(const Mutation *p_mut) const\n{\n\tMutationIndex mutation_index = p_mut->BlockIndex();\n\tslim_position_t position = p_mut->position_;\n\tint mut_count = size();\n\tconst MutationIndex *mut_ptr = begin_pointer_const();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint mut_index;\n\t\n\t{\n\t\t// Find the requested position by binary search\n\t\tslim_position_t mut_pos;\n\t\t\n\t\t{\n\t\t\tint L = 0, R = mut_count - 1;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (L > R)\n\t\t\t\t\treturn false;\n\t\t\t\t\n\t\t\t\tmut_index = (L + R) >> 1;\t// overflow-safe because base positions have a max of 1000000000L\n\t\t\t\tmut_pos = (mut_block_ptr + mut_ptr[mut_index])->position_;\n\t\t\t\t\n\t\t\t\tif (mut_pos < position)\n\t\t\t\t{\n\t\t\t\t\tL = mut_index + 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mut_pos > position)\n\t\t\t\t{\n\t\t\t\t\tR = mut_index - 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// mut_pos == p_position\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\twhile (true);\n\t\t}\n\t\t\n\t\t// The mutation at mut_index is at p_position, but it may not be the only such\n\t\t// We check it first, then we check before it scanning backwards, and check after it scanning forwards\n\t\tif (mut_ptr[mut_index] == mutation_index)\n\t\t\treturn true;\n\t}\n\t\n\t// backward & forward scan are shared by both code paths\n\t{\n\t\tslim_position_t back_scan = mut_index;\n\t\t\n\t\twhile (back_scan > 0)\n\t\t{\n\t\t\tconst MutationIndex scan_mut_index = mut_ptr[--back_scan];\n\t\t\t\n\t\t\tif ((mut_block_ptr + scan_mut_index)->position_ != position)\n\t\t\t\tbreak;\n\t\t\tif (scan_mut_index == mutation_index)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\t\n\t{\n\t\tslim_position_t forward_scan = mut_index;\n\t\t\n\t\twhile (forward_scan < mut_count - 1)\n\t\t{\n\t\t\tconst MutationIndex scan_mut_index = mut_ptr[++forward_scan];\n\t\t\t\n\t\t\tif ((mut_block_ptr + scan_mut_index)->position_ != position)\n\t\t\t\tbreak;\n\t\t\tif (scan_mut_index == mutation_index)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\t\n\treturn false;\n}\n#endif\n\nMutation *MutationRun::mutation_with_type_and_position(MutationType *p_mut_type, slim_position_t p_position, slim_position_t p_last_position) const\n{\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint mut_count = size();\n\tconst MutationIndex *mut_ptr = begin_pointer_const();\n\tint mut_index;\n\t\n\tif (p_position == 0)\n\t{\n\t\t// The marker is supposed to be at position 0.  This is a very common case, so we special-case it\n\t\t// to avoid an inefficient binary search.  Instead, we just look at the beginning.\n\t\tif (mut_count == 0)\n\t\t\treturn nullptr;\n\t\t\n\t\tif ((mut_block_ptr + mut_ptr[0])->position_ > 0)\n\t\t\treturn nullptr;\n\t\t\n\t\tif ((mut_block_ptr + mut_ptr[0])->mutation_type_ptr_ == p_mut_type)\n\t\t\treturn (mut_block_ptr + mut_ptr[0]);\n\t\t\n\t\tmut_index = 0;\t// drop through to forward scan\n\t}\n\telse if (p_position == p_last_position)\n\t{\n\t\t// The marker is supposed to be at the very end of the chromosome.  This is also a common case,\n\t\t// so we special-case it by starting at the last mutation in the haplosome.\n\t\tif (mut_count == 0)\n\t\t\treturn nullptr;\n\t\t\n\t\tmut_index = mut_count - 1;\n\t\t\n\t\tif ((mut_block_ptr + mut_ptr[mut_index])->position_ < p_last_position)\n\t\t\treturn nullptr;\n\t\t\n\t\tif ((mut_block_ptr + mut_ptr[mut_index])->mutation_type_ptr_ == p_mut_type)\n\t\t\treturn (mut_block_ptr + mut_ptr[mut_index]);\n\t\t\n\t\t// drop through to backward scan\n\t}\n\telse\n\t{\n\t\t// Find the requested position by binary search\n\t\tslim_position_t mut_pos;\n\t\t\n\t\t{\n\t\t\tint L = 0, R = mut_count - 1;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (L > R)\n\t\t\t\t\treturn nullptr;\n\t\t\t\t\n\t\t\t\tmut_index = (L + R) >> 1;\t// overflow-safe because base positions have a max of 1000000000L\n\t\t\t\tmut_pos = (mut_block_ptr + mut_ptr[mut_index])->position_;\n\t\t\t\t\n\t\t\t\tif (mut_pos < p_position)\n\t\t\t\t{\n\t\t\t\t\tL = mut_index + 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mut_pos > p_position)\n\t\t\t\t{\n\t\t\t\t\tR = mut_index - 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// mut_pos == p_position\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\twhile (true);\n\t\t}\n\t\t\n\t\t// The mutation at mut_index is at p_position, but it may not be the only such\n\t\t// We check it first, then we check before it scanning backwards, and check after it scanning forwards\n\t\tif ((mut_block_ptr + mut_ptr[mut_index])->mutation_type_ptr_ == p_mut_type)\n\t\t\treturn (mut_block_ptr + mut_ptr[mut_index]);\n\t}\n\t\n\t// backward & forward scan are shared by both code paths\n\t{\n\t\tslim_position_t back_scan = mut_index;\n\t\t\n\t\twhile (back_scan > 0)\n\t\t{\n\t\t\tconst MutationIndex scan_mut_index = mut_ptr[--back_scan];\n\t\t\t\n\t\t\tif ((mut_block_ptr + scan_mut_index)->position_ != p_position)\n\t\t\t\tbreak;\n\t\t\tif ((mut_block_ptr + scan_mut_index)->mutation_type_ptr_ == p_mut_type)\n\t\t\t\treturn (mut_block_ptr + scan_mut_index);\n\t\t}\n\t}\n\t\n\t{\n\t\tslim_position_t forward_scan = mut_index;\n\t\t\n\t\twhile (forward_scan < mut_count - 1)\n\t\t{\n\t\t\tconst MutationIndex scan_mut_index = mut_ptr[++forward_scan];\n\t\t\t\n\t\t\tif ((mut_block_ptr + scan_mut_index)->position_ != p_position)\n\t\t\t\tbreak;\n\t\t\tif ((mut_block_ptr + scan_mut_index)->mutation_type_ptr_ == p_mut_type)\n\t\t\t\treturn (mut_block_ptr + scan_mut_index);\n\t\t}\n\t}\n\t\n\treturn nullptr;\n}\n\nconst std::vector<Mutation *> *MutationRun::derived_mutation_ids_at_position(slim_position_t p_position) const\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"MutationRun::derived_mutation_ids_at_position(): usage of statics\");\n\t\n\tstatic std::vector<Mutation *> return_vec;\n\t\n\t// First clear out whatever might be left over from last time\n\treturn_vec.resize(0);\n\t\n\t// Then fill in all the mutation IDs at the given position.  We search backward from the end since usually we are called\n\t// when a new mutation has just been added to the end; this will be slow for addNew[Drawn]Mutation() and removeMutations(),\n\t// but fast for the other cases, such as new SLiM-generated mutations, which are much more common.\n\tconst MutationIndex *begin_ptr = begin_pointer_const();\n\tconst MutationIndex *end_ptr = end_pointer_const();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tfor (const MutationIndex *mut_ptr = end_ptr - 1; mut_ptr >= begin_ptr; --mut_ptr)\n\t{\n\t\tMutation *mut = mut_block_ptr + *mut_ptr;\n\t\tslim_position_t mut_position = mut->position_;\n\t\t\n\t\tif (mut_position == p_position)\n\t\t\treturn_vec.emplace_back(mut);\n\t\telse if (mut_position < p_position)\n\t\t\tbreak;\n\t}\n\t\n\treturn &return_vec;\n}\n\nvoid MutationRun::_RemoveFixedMutations(void)\n{\n\t// Mutations that have fixed, and are thus targeted for removal, have had their state_ set to kFixedAndSubstituted.\n\t// That is done only when convertToSubstitution == T, so we don't need to check that flag here.\n\t\n\t// We don't use begin_pointer() / end_pointer() here, because we actually want to modify the MutationRun even\n\t// though it is shared by multiple Haplosomes; this is an exceptional case, so we go around our safeguards.\n\tMutationIndex *haplosome_iter = mutations_;\n\tMutationIndex *haplosome_backfill_iter = nullptr;\n\tMutationIndex *haplosome_max = mutations_ + mutation_count_;\n\tMutation *mutation_block_ptr = gSLiM_Mutation_Block;\n\t\n\t// haplosome_iter advances through the mutation list; for each entry it hits, the entry is either fixed (skip it) or not fixed\n\t// (copy it backward to the backfill pointer).  We do this with two successive loops; the first knows that no mutation has\n\t// yet been skipped, whereas the second knows that at least one mutation has been.\n\twhile (haplosome_iter != haplosome_max)\n\t{\n\t\tif ((mutation_block_ptr + (*haplosome_iter++))->state_ != MutationState::kFixedAndSubstituted)\n\t\t\tcontinue;\n\t\t\n\t\t// Fixed mutation; we want to omit it, so we skip it in haplosome_backfill_iter and transition to the second loop\n\t\thaplosome_backfill_iter = haplosome_iter - 1;\n\t\tbreak;\n\t}\n\t\n#ifdef __clang_analyzer__\n\t// the static analyzer doesn't understand the way the loop above drops through to the loop below\n\t// this assert is not always true, but it is true whenever (haplosome_iter != haplosome_max) at this point\n\tassert(haplosome_backfill_iter);\n#endif\n\t\n\twhile (haplosome_iter != haplosome_max)\n\t{\n\t\tMutationIndex mutation_index = *haplosome_iter;\n\t\t\n\t\tif ((mutation_block_ptr + mutation_index)->state_ != MutationState::kFixedAndSubstituted)\n\t\t{\n\t\t\t// Unfixed mutation; we want to keep it, so we copy it backward and advance our backfill pointer as well as haplosome_iter\n\t\t\t*haplosome_backfill_iter = mutation_index;\n\t\t\t\n\t\t\t++haplosome_backfill_iter;\n\t\t\t++haplosome_iter;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Fixed mutation; we want to omit it, so we just advance our pointer\n\t\t\t++haplosome_iter;\n\t\t}\n\t}\n\t\n\t// excess mutations at the end have been copied back already; we just adjust mutation_count_ and forget about them\n\tif (haplosome_backfill_iter != nullptr)\n\t{\n\t\tmutation_count_ -= (haplosome_iter - haplosome_backfill_iter);\n\t\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\t// invalidate the nonneutral mutation cache\n\t\tnonneutral_mutations_count_ = -1;\n#endif\n\t}\n}\n\nbool MutationRun::_EnforceStackPolicyForAddition(slim_position_t p_position, MutationStackPolicy p_policy, int64_t p_stack_group)\n{\n\tMutationIndex *begin_ptr = begin_pointer();\n\tMutationIndex *end_ptr = end_pointer();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tif (p_policy == MutationStackPolicy::kKeepFirst)\n\t{\n\t\t// If the first mutation occurring at a site is kept, then we need to check for an existing mutation of this stacking group\n\t\t// We scan in reverse order, because usually we're adding mutations on the end with emplace_back()\n\t\tfor (MutationIndex *mut_ptr = end_ptr - 1; mut_ptr >= begin_ptr; --mut_ptr)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + *mut_ptr;\n\t\t\tslim_position_t mut_position = mut->position_;\n\t\t\t\n\t\t\tif ((mut_position == p_position) && (mut->mutation_type_ptr_->stack_group_ == p_stack_group))\n\t\t\t\treturn false;\n\t\t\telse if (mut_position < p_position)\n\t\t\t\treturn true;\n\t\t}\n\t\t\n\t\treturn true;\n\t}\n\telse if (p_policy == MutationStackPolicy::kKeepLast)\n\t{\n\t\t// If the last mutation occurring at a site is kept, then we need to check for existing mutations of this type\n\t\t// We scan in reverse order, because usually we're adding mutations on the end with emplace_back()\n\t\tMutationIndex *first_match_ptr = nullptr;\n\t\t\n\t\tfor (MutationIndex *mut_ptr = end_ptr - 1; mut_ptr >= begin_ptr; --mut_ptr)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + *mut_ptr;\n\t\t\tslim_position_t mut_position = mut->position_;\n\t\t\t\n\t\t\tif ((mut_position == p_position) && (mut->mutation_type_ptr_->stack_group_ == p_stack_group))\n\t\t\t\tfirst_match_ptr = mut_ptr;\t// set repeatedly as we scan backwards, until we exit\n\t\t\telse if (mut_position < p_position)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// If we found any, we now scan forward and remove them, in anticipation of the new mutation being added\n\t\tif (first_match_ptr)\n\t\t{\n\t\t\tMutationIndex *replace_ptr = first_match_ptr;\t// replace at the first match position\n\t\t\tMutationIndex *mut_ptr = first_match_ptr + 1;\t// we know the initial position needs removal, so start at the next\n\t\t\t\n\t\t\tfor ( ; mut_ptr < end_ptr; ++mut_ptr)\n\t\t\t{\n\t\t\t\tMutationIndex mut_index = *mut_ptr;\n\t\t\t\tMutation *mut = mut_block_ptr + mut_index;\n\t\t\t\tslim_position_t mut_position = mut->position_;\n\t\t\t\t\n\t\t\t\tif ((mut_position == p_position) && (mut->mutation_type_ptr_->stack_group_ == p_stack_group))\n\t\t\t\t{\n\t\t\t\t\t// The current scan position is a mutation that needs to be removed, so scan forward to skip copying it backward\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// The current scan position is a valid mutation, so we copy it backwards\n\t\t\t\t\t*(replace_ptr++) = mut_index;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// excess mutations at the end have been copied back already; we just adjust mutation_count_ and forget about them\n\t\t\tset_size(size() - (int)(mut_ptr - replace_ptr));\n\t\t}\n\t\t\n\t\treturn true;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::_EnforceStackPolicyForAddition): (internal error) invalid policy.\" << EidosTerminate();\n}\n\nvoid MutationRun::split_run(MutationRun **p_first_half, MutationRun **p_second_half, slim_position_t p_split_first_position, MutationRunContext &p_mutrun_context) const\n{\n\tMutationRun *first_half = NewMutationRun(p_mutrun_context);\n\tMutationRun *second_half = NewMutationRun(p_mutrun_context);\n\tint32_t second_half_start;\n\t\n\tfor (second_half_start = 0; second_half_start < mutation_count_; ++second_half_start)\n\t\tif ((gSLiM_Mutation_Block + mutations_[second_half_start])->position_ >= p_split_first_position)\n\t\t\tbreak;\n\t\n\tif (second_half_start > 0)\n\t\tfirst_half->emplace_back_bulk(mutations_, second_half_start);\n\t\n\tif (second_half_start < mutation_count_)\n\t\tsecond_half->emplace_back_bulk(mutations_ + second_half_start, mutation_count_ - second_half_start);\n\t\n\t*p_first_half = first_half;\n\t*p_second_half = second_half;\n}\n\n\n#if SLIM_USE_NONNEUTRAL_CACHES\n\nvoid MutationRun::cache_nonneutral_mutations_REGIME_1() const\n{\n\t//\n\t//\tRegime 1 means there are no mutationEffect() callbacks at all, so neutrality can be assessed\n\t//\tsimply by looking at selection_coeff_ != 0.0.  The mutation type is irrelevant.\n\t//\n\tzero_out_nonneutral_buffer();\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\t// loop through mutations and copy the non-neutral ones into our buffer, resizing as needed\n\tfor (int32_t bufindex = 0; bufindex < mutation_count_; ++bufindex)\n\t{\n\t\tMutationIndex mutindex = mutations_[bufindex];\n\t\t\n\t\tif ((mut_block_ptr + mutindex)->selection_coeff_ != 0.0)\n\t\t\tadd_to_nonneutral_buffer(mutindex);\n\t}\n}\n\nvoid MutationRun::cache_nonneutral_mutations_REGIME_2() const\n{\n\t//\n\t//\tRegime 2 means the only mutationEffect() callbacks are (a) constant-effect, (b) neutral (i.e.,\n\t//\tmake their mutation type become neutral), and (c) global (i.e. apply to all subpopulations).\n\t//\tHere neutrality is assessed by first consulting the set_neutral_by_global_active_callback\n\t//\tflag of MutationType, which is set up by RecalculateFitness() for us.  If that is true,\n\t//\tthe mutation is neutral; if false, selection_coeff_ is reliable.  Note the code below uses\n\t//\tthe exact way that the C operator && works to implement this order of checks.\n\t//\n\tzero_out_nonneutral_buffer();\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\t// loop through mutations and copy the non-neutral ones into our buffer, resizing as needed\n\tfor (int32_t bufindex = 0; bufindex < mutation_count_; ++bufindex)\n\t{\n\t\tMutationIndex mutindex = mutations_[bufindex];\n\t\tMutation *mutptr = mut_block_ptr + mutindex;\n\t\t\n\t\t// The result of && is not order-dependent, but the first condition is checked first.\n\t\t// I expect many mutations would fail the first test (thus short-circuiting), whereas\n\t\t// few would fail the second test (i.e. actually be 0.0) in a QTL model.\n\t\tif ((!mutptr->mutation_type_ptr_->set_neutral_by_global_active_callback_) && (mutptr->selection_coeff_ != 0.0))\n\t\t\tadd_to_nonneutral_buffer(mutindex);\n\t}\n}\n\nvoid MutationRun::cache_nonneutral_mutations_REGIME_3() const\n{\n\t//\n\t//\tRegime 3 means that there are mutationEffect() callbacks beyond the constant neutral global\n\t//\tcallbacks of regime 2, so if a mutation's muttype is subject to any mutationEffect() callbacks\n\t//\tat all, whether active or not, that mutation must be considered to be non-neutral (because\n\t//\ta rogue callback could enable/disable other callbacks).  This is determined by consulting\n\t//\tthe subject_to_mutationEffect_callback flag of MutationType, set up by RecalculateFitness()\n\t//\tfor us.  If that flag is not set, then the selection_coeff_ is reliable as usual.\n\t//\n\tzero_out_nonneutral_buffer();\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\t// loop through mutations and copy the non-neutral ones into our buffer, resizing as needed\n\tfor (int32_t bufindex = 0; bufindex < mutation_count_; ++bufindex)\n\t{\n\t\tMutationIndex mutindex = mutations_[bufindex];\n\t\tMutation *mutptr = mut_block_ptr + mutindex;\n\t\t\n\t\t// The result of || is not order-dependent, but the first condition is checked first.\n\t\t// I have reordered this to put the fast test first; or I'm guessing it's the fast test.\n\t\tif ((mutptr->selection_coeff_ != 0.0) || (mutptr->mutation_type_ptr_->subject_to_mutationEffect_callback_))\n\t\t\tadd_to_nonneutral_buffer(mutindex);\n\t}\n}\n\nvoid MutationRun::check_nonneutral_mutation_cache() const\n{\n\tif (!nonneutral_mutations_)\n\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::check_nonneutral_mutation_cache): (internal error) cache not allocated.\" << EidosTerminate();\n\tif (nonneutral_mutations_count_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::check_nonneutral_mutation_cache): (internal error) unvalidated cache.\" << EidosTerminate();\n\tif (nonneutral_mutations_count_ > nonneutral_mutation_capacity_)\n\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::check_nonneutral_mutation_cache): (internal error) cache size exceeds cache capacity.\" << EidosTerminate();\n\t\n\t// Check for correctness in regime 1.  Now that we have three regimes, this isn't really worth maintaining;\n\t// it really just replicates the above logic exactly, so it is not a very effective cross-check.\n\t\n\t/*\n\tint32_t cache_index = 0;\n\t\n\tfor (int32_t bufindex = 0; bufindex < mutation_count_; ++bufindex)\n\t{\n\t\tMutationIndex mutindex = mutations_[bufindex];\n\t\tMutation *mutptr = gSLiM_Mutation_Block + mutindex;\n\t\t\n\t\tif (mutptr->selection_coeff_ != 0.0)\n\t\t\tif (*(nonneutral_mutations_ + cache_index++) != mutindex)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::check_nonneutral_mutation_cache_REGIME_1): (internal error) unsynchronized cache.\" << EidosTerminate();\n\t}\n\t */\n}\n\n#endif\n\n// Shorthand for clear(), then copy_from_run(p_mutations_to_set), then insert_sorted_mutation() on every\n// mutation in p_mutations_to_add, with checks with enforce_stack_policy_for_addition().  The point of\n// this is speed: like HaplosomeCloned(), we can merge the new mutations in much faster if we do it in\n// bulk.  Note that p_mutations_to_set and p_mutations_to_add must both be sorted by position.\nvoid MutationRun::clear_set_and_merge(const MutationRun &p_mutations_to_set, std::vector<MutationIndex> &p_mutations_to_add)\n{\n\t// first, clear all mutations out of the receiver\n\tclear();\n\t\n\t// handle the cases with no mutations in one or the other given run, so we can assume >= 1 mutations below\n\tint mut_to_set_count = p_mutations_to_set.size();\n\tint mut_to_add_count = (int)p_mutations_to_add.size();\n\t\n\tif (mut_to_add_count == 0)\n\t{\n\t\tcopy_from_run(p_mutations_to_set);\n\t\treturn;\n\t}\n\t\n\tif (mut_to_set_count == 0)\n\t{\n\t\tcopy_from_vector(p_mutations_to_add);\n\t\treturn;\n\t}\n\t\n\t// assume that all mutations will be added, and adjust capacity accordingly\n\tif (mut_to_set_count + mut_to_add_count > mutation_capacity_)\n\t{\n\t\t// See emplace_back for comments on our capacity policy\n\t\tdo\n\t\t{\n\t\t\tif (mutation_capacity_ < 32)\n\t\t\t\tmutation_capacity_ <<= 1;\t\t// double the number of pointers we can hold\n\t\t\telse\n\t\t\t\tmutation_capacity_ += 16;\n\t\t}\n\t\twhile (mut_to_set_count + mut_to_add_count > mutation_capacity_);\n\t\t\n\t\tmutations_ = (MutationIndex *)realloc(mutations_, mutation_capacity_ * sizeof(MutationIndex));\n\t\tif (!mutations_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::clear_set_and_merge): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// then interleave mutations together, effectively setting p_mutations_to_set and then adding in p_mutations_to_add\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tconst MutationIndex *mutation_iter\t\t= p_mutations_to_add.data();\n\tconst MutationIndex *mutation_iter_max\t= mutation_iter + p_mutations_to_add.size();\n\tMutationIndex mutation_iter_mutation_index = *mutation_iter;\n\tslim_position_t mutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\n\tconst MutationIndex *parent_iter\t\t= p_mutations_to_set.begin_pointer_const();\n\tconst MutationIndex *parent_iter_max\t= p_mutations_to_set.end_pointer_const();\n\tMutationIndex parent_iter_mutation_index = *parent_iter;\n\tslim_position_t parent_iter_pos = (mut_block_ptr + parent_iter_mutation_index)->position_;\n\t\n\t// this loop runs while we are still interleaving mutations from both sources\n\tdo\n\t{\n\t\tif (parent_iter_pos <= mutation_iter_pos)\n\t\t{\n\t\t\t// we have a parent mutation that comes first, so copy it\n\t\t\templace_back(*parent_iter);\n\t\t\t\n\t\t\tparent_iter++;\n\t\t\tif (parent_iter == parent_iter_max)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tparent_iter_mutation_index = *parent_iter;\n\t\t\tparent_iter_pos = (mut_block_ptr + parent_iter_mutation_index)->position_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we have a new mutation to add, which we know is not already present; check the stacking policy\n\t\t\tif (enforce_stack_policy_for_addition(mutation_iter_pos, (mut_block_ptr + mutation_iter_mutation_index)->mutation_type_ptr_))\n\t\t\t\templace_back(mutation_iter_mutation_index);\n\t\t\t\n\t\t\tmutation_iter++;\n\t\t\tif (mutation_iter == mutation_iter_max)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t}\n\t}\n\twhile (true);\n\t\n\t// one source is exhausted, but there are still mutations left in the other source\n\twhile (parent_iter != parent_iter_max)\n\t{\n\t\templace_back(*parent_iter);\n\t\tparent_iter++;\n\t}\n\t\n\twhile (mutation_iter != mutation_iter_max)\n\t{\n\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\n\t\tif (enforce_stack_policy_for_addition(mutation_iter_pos, (mut_block_ptr + mutation_iter_mutation_index)->mutation_type_ptr_))\n\t\t\templace_back(mutation_iter_mutation_index);\n\t\t\n\t\tmutation_iter++;\n\t}\n}\n\nsize_t MutationRun::MemoryUsageForMutationIndexBuffers(void) const\n{\n\treturn mutation_capacity_ * sizeof(MutationIndex);\n}\n\nsize_t MutationRun::MemoryUsageForNonneutralCaches(void) const\n{\n\treturn nonneutral_mutation_capacity_ * sizeof(MutationIndex);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation_run.h",
    "content": "//\n//  mutation_run.h\n//  SLiM\n//\n//  Created by Ben Haller on 11/29/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class MutationRun represents a run of mutations inside a haplosome.  It is used internally by Haplosome; it is not visible to Eidos\n code in SLiM, since the Haplosome class hides it behind a simplified API.  Most clients of Haplosome should strive to use the Haplosome\n APIs directly; it would be nice if MutationRun could be kept as a private implementation detail in most (all?) cases.\n \n */\n\n#ifndef __SLiM__mutation_run__\n#define __SLiM__mutation_run__\n\n\n#include \"mutation.h\"\n#include \"slim_globals.h\"\n#include \"eidos_intrusive_ptr.h\"\n#include \"eidos_object_pool.h\"\n\n#ifdef _OPENMP\n#include \"eidos_openmp.h\"\n#endif\n\n#include <string.h>\n#include <assert.h>\n\n\nclass MutationRun;\n\n\n// We keep a per-species pool of freed mutation runs, and a per-species pool of in-use mutation runs.  These are kept by the\n// Species; see species.h.  When running multithreaded, there is one such pool per thread (per species), allowing all\n// mutation run allocation and free operations to be done without locks (except locks done by new/malloc, but once a sufficiently\n// large pool of MutationRun objects has been established for each thread those should no longer occur).  A MutationRunPool\n// object is a vector of pointers to const MutationRun objects; a linked-list design was tried, but was slower.  We also\n// use EidosObjectPool to allocate MutationRun objects now, with one pool per thread; this gives us better memory locality\n// for the MutationRuns being used by each thread.\ntypedef std::vector<const MutationRun *> MutationRunPool;\n\n// This struct groups together all the objects for one context in which MutationRuns are allocated and used.  There is one\n// such context per thread for each chromosome in the model -- a multiplicity of contexts, for locality and encapsulation.\ntypedef struct MutationRunContext {\n\tMutationRunPool freed_pool_;\t\t\t\t\t\t// MutationRun objects that have been allocated, but are not in use\n\tMutationRunPool in_use_pool_;\t\t\t\t\t\t// MutationRun objects currently in use by the simulation\n\t\n\tEidosObjectPool *allocation_pool_ = nullptr;\t\t// out of which brand-new MutationRun objects are ultimately allocated\n#ifdef _OPENMP\n\tomp_lock_t allocation_pool_lock_;\t\t\t\t\t// must be used when accessing allocation pools across parallel threads\n#endif\n} MutationRunContext;\n\n\n// BCH 4/19/2023: We want MutationRuns to be able to be shared between Haplosomes; that's the whole point, leveraging shared\n// haplohype blocks to reduce redundant processing.  We also need to modify MutationRun objects, particularly when they are\n// first created, adding the mutations that they contain.  These goals are somewhat in opposition, because once a MutationRun\n// is shared by more than one Haplosome it needs to be immutable, in general, otherwise changes to it (intended for one Haplosome)\n// will change it for the other Haplosomes that share it, too.  We used to enforce that with the refcount of the MutationRun;\n// if a run's refcount was 1, it was used by only a single Haplosome and could be modified.  That was not actually used in many\n// places, though; it was not an important optimization, because usually code that modified the haplosome sequence made new\n// mutation runs anyway.  Now that we're shifting away from refcounts (towards explicit usage tallies that are only valid\n// at a particular point in the tick cycle), I'm getting rid of this refcount-based locking mechanism.  Instead, the fact\n// that mutation runs should not be modified after they are initially created will be enforced by using const pointers in\n// most places in the code.  When a new run is created, you get a non-const pointer and can modify it as you wish; once you\n// put it into a Haplosome, it becomes a const pointer and should not be modified, in general.  In some spots we cast away the\n// constness; this is legal because the underlying object was not declared const, so the const pointer is just an additional\n// constraint we imposed upon ourselves.  https://www.ibm.com/docs/en/zos/2.3.0?topic=expressions-const-cast-operator-c-only\n\n\n// Initial capacity for new MutationRun objects; this is a balance between high memory usage for simulations that don't have\n// many mutations, versus excessive reallocs for other simulations before they get up to equilibrium.  Set by guessing.\n#define SLIM_MUTRUN_INITIAL_CAPACITY\t16\n\n\n// If defined as 1, MutationRun will keep a side cache of the non-neutral mutations occuring inside it.  This can greatly accelerate\n// fitness calculations, but does consume additional memory, and is not always advantageous.  Define to 0 to disable this feature.\n// I'm not sure how long I will maintain the ability to disable these caches; the overhead is quite small, so I think it would be OK\n// to just make this always be on.  At present this flag is mostly useful for testing purposes.\n#define SLIM_USE_NONNEUTRAL_CACHES\t1\n\n\nclass MutationRun\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\t\n\t// MutationRun has a marking mechanism to let us loop through all haplosomes and perform an operation on each MutationRun once.\n\t// This counter is used to do that; a client wishing to perform such an operation should increment the counter and then use it\n\t// in conjuction with operation_id_ below.  Note this is shared by all species.\n\tstatic int64_t sOperationID;\t\t\t\t\t\t\t\t// use MutationRun::GetNextOperationID() to access this\n\nprivate:\n\n\t// MutationRun used to have an internal buffer that it could use to hold mutation pointers, to decrease malloc overhead when\n\t// making new MutationRun objects.  We now reuse MutationRun objects, without freeing their MutationIndex buffer, so the malloc\n\t// overhead equilibrates and then goes away.  Removing the internal buffer saves space and simplifies the logic.  BCH 4/16/2023\n\t\n\tMutationIndex *mutations_;\t\t\t\t\t\t\t\t\t// OWNED POINTER: a pointer to an array of MutationIndex\n\tint32_t mutation_count_ = 0;\t\t\t\t\t\t\t\t// the number of entries presently in mutations_\n\tint32_t mutation_capacity_;\t\t\t\t\t\t\t\t\t// the capacity of mutations_\n\t\n\tmutable uint32_t use_count_ = 0;\t\t\t\t\t\t\t// the usage count for this run across all haplosomes that are tallied\n#ifdef DEBUG_LOCKS_ENABLED\n\tmutable EidosDebugLock mutrun_use_count_LOCK;\n#endif\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\n\t// Non-neutral mutation caching.  This is a somewhat complex scheme designed to speed up fitness calculations.\n\t// The idea is that the mutation run can cache, once, a list of all of the non-neutral mutations it contains,\n\t// and then the fitness code can refer to that cached list from then on, saving a huge amount of looping over\n\t// neutral mutations in many simulations.  This simple idea is complicated by a few factors.  First of all, if\n\t// the mutation run changes, the cache needs to be invalidated.  Second, if the external information that the\n\t// cache relies upon changes, the cache needs to be invalidated.  That external information consists of (a) the\n\t// selection coefficients of mutations, and (b) the existence and state of mutationEffect() callbacks.  There\n\t// are three separate regimes in which these caches are used:\n\t//\n\t//\t1. No mutationEffect() callbacks defined.  Here caches depend solely upon mutation selection coefficients,\n\t//\t\tand can be carried forward through cycles with impunity.  If any mutation's selcoeff is changed between\n\t//\t\tzero and non-zero, a global flag in Species (nonneutral_change_counter_) marks all caches as invalid.\n\t//\n\t//\t2. Only constant-effect neutral callbacks are defined: \"return 0.0;\".  RecalculateFitness() runs through\n\t//\t\tmutation types and callbacks, and figures this state out and sets a flag in each mutation type as to\n\t//\t\twhether it is effectively neutral, after considering these constant-effect callbacks, or not.  This\n\t//\t\tstate changes in every cycle, so caches cannot be carried forward from cycle to cycle\n\t//\t\tin this regime unless the state of the callbacks, with respect to making mutation types neutral, is\n\t//\t\tunchanged.  If RecalculateFitness() detects a callback change, it sets the global all-invalid flag.\n\t//\n\t//\t3. At least one non-constant callback is defined.  RecalculateFitness() figures this out, and if this is\n\t//\t\tthe case, the non-neutral cache must include all mutations for which their muttype has a callback\n\t//\t\tdefined at all, whether constant or not, neutral or not, active or not, because the callback regime\n\t//\t\titself could change unpredictably.  These caches cannot be carried forward unless the state of the\n\t//\t\tcallbacks, with respect to which mutation types are influenced by them, is unchanged.  If a callback\n\t//\t\tchange is detected by RecalculateFitness(), it sets the global all-invalid flag.\n\t//\n\t//\t(FIXME) One could imagine inserting a regime between 2 and 3 that would allow a mix of constant and\n\t//\t\tnon-constant callbacks, as long as the non-constant callbacks were \"well-behaved\" – no use of the\n\t//\t\tactive property, no executeLambda, etc. – so that SLiM could know that the constant callbacks would\n\t//\t\tapply if they were active.  This could be pretty useful for models that have a mix of QTLs (using\n\t//\t\ta constant neutral callbacks) and other loci that are governed by mutationEffect() callbacks.  This\n\t//\t\tstrikes me as an edge case, though; mostly models are either QTL models or non-QTL models, I think.\n\t//\n\t// When models switch between one regime and another, they generally need to recache, since the criteria\n\t// for inclusion in the cache differs from regime to regime.  This is handled by RecalculateFitness().\n\t// The last regime used (for the previous cycle) is remembered in sim.last_nonneutral_regime_.\n\t//\n\t// Mutation runs are considered to be immutable in SLiM if they are referred to by more than one haplosome.\n\t// If they are referred to only once, however, they can be changed.  What that occurs, their nonneutral\n\t// cache must be invalidated.  This means that any code that calls use_count() on a mutrun, and modifies it\n\t// if the count is 1, must also invalidate the nonneutral cache.  This is done automatically by the existing\n\t// methods – in particular, MutationRun::will_modify_run(), which should be a funnel for all such code.\n\t// Newly created mutation runs are also routinely modified on the (valid) assumption that they are referred\n\t// to by only one haplosome (or no haplosomes at all, more likely); this is fine since they don't have a nonneutral\n\t// cache yet anyway.\n\t//\n\t// These caches are only used for mutation runs that are accessed by the FitnessOfParentWithHaplosomeIndices...()\n\t// suite of methods; pure neutral models and non-chromosome-dependent models will never touch these caches\n\t// and the buffer will never be allocated.\n\t//\n\t// BCH 4/19/2023: Note that this stuff is all related to caching, so it is mutable even for immutable objects.\n\t\n\tmutable int32_t nonneutral_change_validation_ = 0;\t\t\t// compared to sim.nonneutral_change_counter_ to detect changes\n\t\n\tmutable int32_t nonneutral_mutation_capacity_ = 0;\t\t\t// the capacity of nonneutral_mutations_\n\tmutable int32_t nonneutral_mutations_count_ = -1;\t\t\t// the number of entries currently used; -1 indicates an invalid cache\n\tmutable MutationIndex *nonneutral_mutations_ = nullptr;\t\t// OWNED POINTER: a pointer to MutationIndex for non-neutral mutations\n\t\n#if (SLIMPROFILING == 1)\n// PROFILING\n\tmutable bool recached_run_ = false;\t\t\t\t\t\t\t// so SLiMgui can count how many nonneutral caches get recached each tick\n#endif\t// (SLIMPROFILING == 1)\n\t\n#endif\t// SLIM_USE_NONNEUTRAL_CACHES\n\t\npublic:\n\t\n\tmutable int64_t operation_id_ = 0;\t\t// used to mark the MutationRun objects that have been handled by a global operation\n\t\n#if DEBUG\n\tmutable uint32_t use_count_CHECK_ = 0;\t// a checkback for use_count_\n#endif\n\t\n\tstatic inline slim_pedigreeid_t GetNextOperationID(void)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"GetNextOperationID(): MutationRun::sOperationID change\");\n\t\t\n\t\treturn ++(MutationRun::sOperationID);\n\t}\n\t\n\t// Allocation and disposal of MutationRun objects should go through these funnels.  The point of this architecture\n\t// is to re-use the instances completely.  We don't use EidosObjectPool here because it would construct/destruct the\n\t// objects, and we actually don't want that; we want the buffers in used MutationRun objects to stay allocated, for\n\t// greater speed.  We are constantly creating new runs, adding mutations in to them, and then throwing them away; once\n\t// the pool of freed runs settles into a steady state, that process can go on with no memory allocs or reallocs at all.\n\t// Note this is shared by all species; a mutation run may be used in one species and then reused in another.\n\t// Note that there is a _LOCKED version of this below, which locks around the use of the allocation pool.\n\tstatic inline __attribute__((always_inline)) MutationRun *NewMutationRun(MutationRunContext &p_mutrun_context)\n\t{\n\t\tMutationRunPool &free_pool = p_mutrun_context.freed_pool_;\n\t\t\n\t\tif (free_pool.size())\n\t\t{\n\t\t\t// We assume that the object from the free pool is in a reuseable state; see FreeMutationRun() below.\n\t\t\tconst MutationRun *new_run = free_pool.back();\n\t\t\t\n\t\t\t// remove our new run from the free pool\n\t\t\tfree_pool.pop_back();\n\t\t\t\n\t\t\t// add our new run to the inuse pool\n\t\t\tp_mutrun_context.in_use_pool_.push_back(new_run);\n\t\t\t\n\t\t\t// objects in the free pool are unused, so we can cast away the constness of the pointer here to explicitly\n\t\t\t// give the caller permission to modify this new run (see comment at the header top about this).\n\t\t\treturn const_cast<MutationRun *>(new_run);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No free run to reuse, so we have to make a new one.  We now allocate MutationRun objects out of a\n\t\t\t// per-species (and per-thread) EidosObjectPool.  This is not for allocation speed, since at equilibrium\n\t\t\t// we expect new MutationRuns to be coming from p_free_pool.  Rather, it is for memory locality; we want\n\t\t\t// all the MutationRuns we're using (or that one thread is using) to be clustered together in memory.\n\t\t\tMutationRun *new_run = new (p_mutrun_context.allocation_pool_->AllocateChunk()) MutationRun();\n\n\t\t\t// add our new run to the inuse pool\n\t\t\tp_mutrun_context.in_use_pool_.push_back(new_run);\n\t\t\t\n\t\t\treturn new_run;\n\t\t}\n\t}\n\t\n\tstatic inline __attribute__((always_inline)) MutationRun *NewMutationRun_LOCKED(MutationRunContext &p_mutrun_context)\n\t{\n\t\t// This version of NewMutationRun() locks around the access to the allocation pool and the inuse/free lists.\n\t\t// This allows NewMutationRun() to be called from thread A using thread B's allocation pool, which is exactly\n\t\t// what we do in the parallel reproduction code (since a given thread generates an entire offspring).  If you\n\t\t// are in a non-parallel region, or each thread is using only its own MutationRunContext, this is unnecessary.\n#ifdef _OPENMP\n\t\tomp_set_lock(&p_mutrun_context.allocation_pool_lock_);\n#endif\n\t\t\n\t\tMutationRunPool &free_pool = p_mutrun_context.freed_pool_;\n\t\t\n\t\tif (free_pool.size())\n\t\t{\n\t\t\t// We assume that the object from the free pool is in a reuseable state; see FreeMutationRun() below.\n\t\t\tconst MutationRun *new_run = free_pool.back();\n\t\t\t\n\t\t\t// remove our new run from the free pool\n\t\t\tfree_pool.pop_back();\n\t\t\t\n\t\t\t// add our new run to the inuse pool\n\t\t\tp_mutrun_context.in_use_pool_.push_back(new_run);\n\t\t\t\n#ifdef _OPENMP\n\t\t\tomp_unset_lock(&p_mutrun_context.allocation_pool_lock_);\n#endif\n\t\t\t\n\t\t\t// objects in the free pool are unused, so we can cast away the constness of the pointer here to explicitly\n\t\t\t// give the caller permission to modify this new run (see comment at the header top about this).\n\t\t\treturn const_cast<MutationRun *>(new_run);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No free run to reuse, so we have to make a new one.  We now allocate MutationRun objects out of a\n\t\t\t// per-species (and per-thread) EidosObjectPool.  This is not for allocation speed, since at equilibrium\n\t\t\t// we expect new MutationRuns to be coming from p_free_pool.  Rather, it is for memory locality; we want\n\t\t\t// all the MutationRuns we're using (or that one thread is using) to be clustered together in memory.\n\t\t\tMutationRun *new_run = new (p_mutrun_context.allocation_pool_->AllocateChunk()) MutationRun();\n\n\t\t\t// add our new run to the inuse pool\n\t\t\tp_mutrun_context.in_use_pool_.push_back(new_run);\n\t\t\t\n#ifdef _OPENMP\n\t\t\tomp_unset_lock(&p_mutrun_context.allocation_pool_lock_);\n#endif\n\t\t\t\n\t\t\treturn new_run;\n\t\t}\n\t}\n\t\n\tstatic inline __attribute__((always_inline)) void FreeMutationRun(const MutationRun *p_run, MutationRunContext &p_mutrun_context)\n\t{\n\t\t// NOTE THAT THE CALLER IS RESPONSIBLE FOR REMOVING THE MUTRUN FROM THE INUSE POOL!!!\n\t\t// We return mutation runs to the free list in a valid, reuseable state.  We do not free its buffers;\n\t\t// avoiding that free/alloc thrash is one of the big wins of recycling mutation run objects, in fact.\n\t\t// We are given a pointer to a const MutationRun, but the fact that we're freeing it means it is\n\t\t// unused by Haplosomes, and so we can cast away the const (see comment at the header top about this).\n\t\tMutationRun *freed_run = const_cast<MutationRun *>(p_run);\n\t\t\n\t\tfreed_run->mutation_count_ = 0;\t\t\t\t\t\t// empty the mutation buffer\n\t\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\tfreed_run->nonneutral_mutations_count_ = -1;\t\t// mark the non-neutral mutation cache as invalid\n#endif\n\t\t\n\t\t// add our new run to the free pool\n\t\tp_mutrun_context.freed_pool_.push_back(freed_run);\n\t}\n\t\n\tstatic inline void DeleteMutationRunContextContents(MutationRunContext &p_mutrun_context)\n\t{\n\t\t// This is not normally used by SLiM, but it is used in the SLiM test code in order to prevent mutation runs\n\t\t// that are allocated in one test from carrying over to later tests (which makes leak debugging a pain).\n\t\tEidosObjectPool *allocation_pool = p_mutrun_context.allocation_pool_;\n\t\tMutationRunPool &free_pool = p_mutrun_context.freed_pool_;\n\t\tMutationRunPool &in_use_pool = p_mutrun_context.in_use_pool_;\n\t\t\n\t\tfor (const MutationRun *freed_run : free_pool)\n\t\t{\n\t\t\tfreed_run->~MutationRun();\n\t\t\tallocation_pool->DisposeChunk(const_cast<MutationRun *>(freed_run));\n\t\t}\n\t\t\n\t\tfor (const MutationRun *inuse_run : in_use_pool)\n\t\t{\n\t\t\tinuse_run->~MutationRun();\n\t\t\tallocation_pool->DisposeChunk(const_cast<MutationRun *>(inuse_run));\n\t\t}\n\t\t\n\t\tfree_pool.resize(0);\n\t\tin_use_pool.resize(0);\n\t}\n\t\n\tMutationRun(const MutationRun&) = delete;\t\t\t\t\t// no copying\n\tMutationRun& operator=(const MutationRun&) = delete;\t\t// no copying\n\t\n\tMutationRun(void);\t\t\t\t\t\t\t\t\t\t\t// constructed empty\n\t~MutationRun(void);\n\t\n\t// MutationRun tallies its use count, as a way to do fast mutation count/frequency tallies.  Access to\n\t// this use count is exclusive, in principle, but the design of the tallying code ought to avoid the\n\t// necessity of locking.  We use EidosDebugLock here to catch race conditions in DEBUG builds.\n\tinline __attribute__((always_inline)) uint32_t use_count(void) const {\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.start_critical(0);\n#endif\n\t\tuint32_t count = use_count_;\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.end_critical();\n#endif\n\t\treturn count;\n\t}\n\tinline __attribute__((always_inline)) void zero_use_count(void) const {\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.start_critical(1);\n#endif\n\t\tuse_count_ = 0;\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.end_critical();\n#endif\n\t}\n\tinline __attribute__((always_inline)) void increment_use_count(void) const {\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.start_critical(2);\n#endif\n\t\tuse_count_++;\n#ifdef DEBUG_LOCKS_ENABLED\n\t\tmutrun_use_count_LOCK.end_critical();\n#endif\n\t}\n\t\n\tinline __attribute__((always_inline)) void will_modify_run(void) {\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\tnonneutral_mutations_count_ = -1;\t\t// invalidate the nonneutral cache since the run is changing\n#endif\n\t}\n\t\n\tinline __attribute__((always_inline)) MutationIndex const & operator[] (int p_index) const {\t// [] returns a reference to a pointer to Mutation; this is the const-pointer variant\n\t\treturn mutations_[p_index];\n\t}\n\t\n\tinline __attribute__((always_inline)) MutationIndex& operator[] (int p_index) {\t\t\t\t// [] returns a reference to a pointer to Mutation; this is the non-const-pointer variant\n\t\treturn mutations_[p_index];\n\t}\n\t\n\tinline __attribute__((always_inline)) int size(void) const {\n\t\treturn mutation_count_;\n\t}\n\t\n\tinline __attribute__((always_inline)) void set_size(int p_size) {\n\t\tmutation_count_ = p_size;\n\t}\n\t\n\tinline __attribute__((always_inline)) void clear(void)\n\t{\n\t\tmutation_count_ = 0;\n\t}\n\t\n\tbool contains_mutation(const Mutation *p_mut) const;\n\t\n\tMutation *mutation_with_type_and_position(MutationType *p_mut_type, slim_position_t p_position, slim_position_t p_last_position) const;\n\t\n\tinline __attribute__((always_inline)) void pop_back(void)\n\t{\n\t\tif (mutation_count_ > 0)\t// the standard says that popping an empty vector results in undefined behavior; this seems reasonable\n\t\t\t--mutation_count_;\n\t}\n\t\n\tinline __attribute__((always_inline)) void emplace_back(MutationIndex p_mutation_index)\n\t{\n\t\tif (mutation_count_ == mutation_capacity_)\n\t\t{\n\t\t\t// Up to a point, we want to double our capacity each time we have to realloc.  Beyond a certain point, that starts to\n\t\t\t// use a whole lot of memory, so we start expanding at a linear rate instead of a geometric rate.  This policy is based\n\t\t\t// on guesswork; the optimal policy would depend strongly on the particular details of the simulation being run.  The\n\t\t\t// goal, though, is twofold: (1) to avoid excessive reallocations early on, and (2) to avoid the peak memory usage,\n\t\t\t// when all haplosomes have grown to their stable equilibrium size, being drastically higher than necessary.  The policy\n\t\t\t// chosen here is intended to try to achieve both of those goals.  The size sequence we follow now is:\n\t\t\t//\n\t\t\t//\t16 (initial size)\n\t\t\t//\t32 (2x)\n\t\t\t//\t48 (+16)\n\t\t\t//\t64 (+16)\n\t\t\t//\t80 (+16)\n\t\t\t//\t...\n\t\t\t\n\t\t\tif (mutation_capacity_ < 32)\n\t\t\t\tmutation_capacity_ <<= 1;\t\t// double the number of pointers we can hold\n\t\t\telse\n\t\t\t\tmutation_capacity_ += 16;\n\t\t\t\n\t\t\tmutations_ = (MutationIndex *)realloc(mutations_, mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::emplace_back): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// Now we are guaranteed to have enough memory, so copy the pointer in\n\t\t*(mutations_ + mutation_count_) = p_mutation_index;\n\t\t++mutation_count_;\n\t}\n\t\n\tinline void emplace_back_bulk(const MutationIndex *p_mutation_indices, int32_t p_copy_count)\n\t{\n\t\tif (mutation_count_ + p_copy_count > mutation_capacity_)\n\t\t{\n\t\t\t// See emplace_back for comments on our capacity policy\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (mutation_capacity_ < 32)\n\t\t\t\t\tmutation_capacity_ <<= 1;\t\t// double the number of pointers we can hold\n\t\t\t\telse\n\t\t\t\t\tmutation_capacity_ += 16;\n\t\t\t}\n\t\t\twhile (mutation_count_ + p_copy_count > mutation_capacity_);\n\t\t\t\n\t\t\tmutations_ = (MutationIndex *)realloc(mutations_, mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::emplace_back_bulk): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// Now we are guaranteed to have enough memory, so copy the pointers in\n\t\tmemcpy(mutations_ + mutation_count_, p_mutation_indices, p_copy_count * sizeof(MutationIndex));\n\t\tmutation_count_ += p_copy_count;\n\t}\n\t\n\tinline void insert_sorted_mutation(MutationIndex p_mutation_index)\n\t{\n\t\t// first push it back on the end, which deals with capacity/locking issues\n\t\templace_back(p_mutation_index);\n\t\t\n\t\t// if it was our first element, then we're done; this would work anyway, but since it is extremely common let's short-circuit it\n\t\tif (mutation_count_ == 1)\n\t\t\treturn;\n\t\t\n\t\t// then find the proper position for it\n\t\tMutation *mut_ptr_to_insert = gSLiM_Mutation_Block + p_mutation_index;\n\t\tMutationIndex *sort_position = begin_pointer();\n\t\tconst MutationIndex *end_position = end_pointer_const() - 1;\t\t// the position of the newly added element\n\t\t\n\t\tfor ( ; sort_position != end_position; ++sort_position)\n\t\t\tif (CompareMutations(mut_ptr_to_insert, gSLiM_Mutation_Block + *sort_position))\t// if (p_mutation->position_ < (*sort_position)->position_)\n\t\t\t\tbreak;\n\t\t\n\t\t// if we got all the way to the end, then the mutation belongs at the end, so we're done\n\t\tif (sort_position == end_position)\n\t\t\treturn;\n\t\t\n\t\t// the new mutation has a position less than that at sort_position, so we need to move everybody upward\n\t\tmemmove(sort_position + 1, sort_position, (char *)end_position - (char *)sort_position);\n\t\t\n\t\t// finally, put the mutation where it belongs\n\t\t*sort_position = p_mutation_index;\n\t}\n\n\t/*\n\t This version of insert_sorted_mutation() searches for the insertion point from the end\n\t instead of the beginning.  I investigated that, but ultimately decided on a different\n\t course of action, and this change seems unnecessary and destabilizing; I don't think\n\t it would benefit any of the users of this method, on average.  Keeping the code for\n\t posterity.  BCH 29 October 2017\n\t \n\tinline void insert_sorted_mutation(MutationIndex p_mutation_index)\n\t{\n\t\t// first push it back on the end, which deals with capacity/locking issues\n\t\templace_back(p_mutation_index);\n\t\t\n\t\t// if it was our first element, then we're done; this would work anyway, but since it is extremely common let's short-circuit it\n\t\tif (mutation_count_ == 1)\n\t\t\treturn;\n\t\t\n\t\t// then find the proper position for it; mutations are often added in ascending order, so let's search backwards\n\t\tMutation *mut_ptr_to_insert = gSLiM_Mutation_Block + p_mutation_index;\n\t\tMutationIndex *sort_position = end_pointer() - 2;\t\t\t\t// the position back one from the newly added element (at end-1)\n\t\tconst MutationIndex *end_position = begin_pointer_const() - 1;\t// the position back one from the start of the mutation run\n\t\t\n\t\t// check for the mutation actually belonging at the end, for the quick return and simple completion design\n\t\tif (!CompareMutations(mut_ptr_to_insert, gSLiM_Mutation_Block + *sort_position))\t// if (p_mutation->position_ >= (*sort_position)->position_)\n\t\t\treturn;\n\t\t\n\t\t// ok, it doesn't belong at the end; start searching at end_pointer() - 3, which might not exist (might ==end_position)\n\t\t--sort_position;\n\t\t\n\t\tfor ( ; sort_position != end_position; --sort_position)\n\t\t\tif (!CompareMutations(mut_ptr_to_insert, gSLiM_Mutation_Block + *sort_position))\t// if (p_mutation->position_ >= (*sort_position)->position_)\n\t\t\t\tbreak;\n\t\t\n\t\t// ok, it belongs right *after* sort_position; the mutation at sort_position should stay, so skip ahead one\n\t\t++sort_position;\n\t\t\n\t\t// the new mutation has a position less than that at sort_position, so we need to move everybody upward\n\t\tmemmove(sort_position + 1, sort_position, (char *)(end_pointer_const() - 1) - (char *)sort_position);\n\t\t\n\t\t// finally, put the mutation where it belongs\n\t\t*sort_position = p_mutation_index;\n\t}*/\n\t\n\tinline void insert_sorted_mutation_if_unique(MutationIndex p_mutation_index)\n\t{\n\t\t// first push it back on the end, which deals with capacity/locking issues\n\t\templace_back(p_mutation_index);\n\t\t\n\t\t// if it was our first element, then we're done; this would work anyway, but since it is extremely common let's short-circuit it\n\t\tif (mutation_count_ == 1)\n\t\t\treturn;\n\t\t\n\t\t// then find the proper position for it\n\t\tMutation *mut_ptr_to_insert = gSLiM_Mutation_Block + p_mutation_index;\n\t\tMutationIndex *sort_position = begin_pointer();\n\t\tconst MutationIndex *end_position = end_pointer_const() - 1;\t\t// the position of the newly added element\n\t\t\n\t\tfor ( ; sort_position != end_position; ++sort_position)\n\t\t{\n\t\t\tif (CompareMutations(mut_ptr_to_insert, gSLiM_Mutation_Block + *sort_position))\t// if (p_mutation->position_ < (*sort_position)->position_)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (p_mutation_index == *sort_position)\n\t\t\t{\n\t\t\t\t// We are only supposed to insert the mutation if it is unique, and apparently it is not; discard it off the end\n\t\t\t\t--mutation_count_;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if we got all the way to the end, then the mutation belongs at the end, so we're done\n\t\tif (sort_position == end_position)\n\t\t\treturn;\n\t\t\n\t\t// the new mutation has a position less than that at sort_position, so we need to move everybody upward\n\t\tmemmove(sort_position + 1, sort_position, (char *)end_position - (char *)sort_position);\n\t\t\n\t\t// finally, put the mutation where it belongs\n\t\t*sort_position = p_mutation_index;\n\t}\n\t\n\tbool _EnforceStackPolicyForAddition(slim_position_t p_position, MutationStackPolicy p_policy, int64_t p_stack_group);\n\tinline __attribute__((always_inline)) bool enforce_stack_policy_for_addition(slim_position_t p_position, MutationType *p_mut_type_ptr);\t// below\n\t\n\tinline __attribute__((always_inline)) void copy_from_run(const MutationRun &p_source_run)\n\t{\n\t\tint source_mutation_count = p_source_run.mutation_count_;\n\t\t\n\t\t// first we need to ensure that we have sufficient capacity\n\t\tif (source_mutation_count > mutation_capacity_)\n\t\t{\n\t\t\tmutation_capacity_ = p_source_run.mutation_capacity_;\t\t// just use the same capacity as the source\n\t\t\t\n\t\t\tmutations_ = (MutationIndex *)realloc(mutations_, mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::copy_from_run): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// then copy all pointers from the source to ourselves\n\t\tmemcpy(mutations_, p_source_run.mutations_, source_mutation_count * sizeof(MutationIndex));\n\t\tmutation_count_ = source_mutation_count;\n\t}\n\t\n\tinline __attribute__((always_inline)) void copy_from_vector(const std::vector<MutationIndex> &p_source_vector)\n\t{\n\t\tint source_mutation_count = (int)p_source_vector.size();\n\t\t\n\t\t// first we need to ensure that we have sufficient capacity\n\t\tif (source_mutation_count > mutation_capacity_)\n\t\t{\n\t\t\tmutation_capacity_ = source_mutation_count;\t\t// just use the same capacity as the source size\n\t\t\t\n\t\t\tmutations_ = (MutationIndex *)realloc(mutations_, mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::copy_from_vector): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// then copy all pointers from the source to ourselves\n\t\tmemcpy(mutations_, p_source_vector.data(), source_mutation_count * sizeof(MutationIndex));\n\t\tmutation_count_ = source_mutation_count;\n\t}\n\t\n\t// Shorthand for clear(), then copy_from_run(p_mutations_to_set), then insert_sorted_mutation() on every\n\t// mutation in p_mutations_to_add, with checks with enforce_stack_policy_for_addition().  The point of\n\t// this is speed: like HaplosomeCloned(), we can merge the new mutations in much faster if we do it in\n\t// bulk.  Note that p_mutations_to_set and p_mutations_to_add must both be sorted by position, and it\n\t// must be guaranteed that none of the mutations in the two given runs are the same.\n\tvoid clear_set_and_merge(const MutationRun &p_mutations_to_set, std::vector<MutationIndex> &p_mutations_to_add);\n\t\n\t// This is used by the tree sequence recording code to get the full derived state at a given position.\n\t// Note that the vector returned is cached internally and reused with each call, for speed.\n\tconst std::vector<Mutation *> *derived_mutation_ids_at_position(slim_position_t p_position) const;\n\t\n\tinline __attribute__((always_inline)) const MutationIndex *begin_pointer_const(void) const\n\t{\n\t\treturn mutations_;\n\t}\n\t\n\tinline __attribute__((always_inline)) const MutationIndex *end_pointer_const(void) const\n\t{\n\t\treturn mutations_ + mutation_count_;\n\t}\n\t\n\tinline __attribute__((always_inline)) MutationIndex *begin_pointer(void)\n\t{\n\t\treturn mutations_;\n\t}\n\t\n\tinline __attribute__((always_inline)) MutationIndex *end_pointer(void)\n\t{\n\t\treturn mutations_ + mutation_count_;\n\t}\n\t\n\tvoid _RemoveFixedMutations(void);\n\tinline __attribute__((always_inline)) void RemoveFixedMutations(int64_t p_operation_id)\n\t{\n\t\tif (operation_id_ != p_operation_id)\n\t\t{\n\t\t\toperation_id_ = p_operation_id;\n\t\t\t\n\t\t\t_RemoveFixedMutations();\n\t\t}\n\t}\n\t\n\t// Hash and comparison functions used by UniqueMutationRuns() to unique mutation runs\n\tinline __attribute__((always_inline)) int64_t Hash(void) const\n\t{\n\t\tuint64_t hash = mutation_count_;\n\t\t\n\t\t// Hash mutation pointers together with the mutation count; we use every 4th mutation pointer for 4x speed,\n\t\t// and it doesn't seem to produce too many hash collisions, at least for the models I've tried.  Actually,\n\t\t// early on when chromosomes are nearly empty collisions are common (where using mut_index++ gives us zero\n\t\t// collisions in pretty much all cases), but at that stage Identical() is fast so it's OK.  At equilibrium\n\t\t// when chromosomes are more full collisions are much less common, so we avoid Identical() when it is slow.\n\t\tfor (int mut_index = 0; mut_index < mutation_count_; mut_index += 4)\n\t\t{\n\t\t\t// this hash function is a stab in the dark based upon the sdbm algorithm here: http://www.cse.yorku.ca/~oz/hash.html\n\t\t\thash = (uint64_t)mutations_[mut_index] + (hash << 6) + (hash << 16) - hash;\n\t\t}\n\t\t\n\t\treturn hash;\n\t}\n\t\n\tinline __attribute__((always_inline)) bool Identical(const MutationRun &p_run) const\n\t{\n\t\tif (mutation_count_ != p_run.mutation_count_)\n\t\t\treturn false;\n\t\t\n\t\tif (memcmp(mutations_, p_run.mutations_, mutation_count_ * sizeof(MutationIndex)) != 0)\n\t\t\treturn false;\n\t\t\n\t\treturn true;\n\t}\n\t\n\t// splitting mutation runs\n\tvoid split_run(MutationRun **p_first_half, MutationRun **p_second_half, slim_position_t p_split_first_position, MutationRunContext &p_mutrun_context) const;\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t// caching non-neutral mutations; see above for comments about the \"regime\" etc.\n\t\n\tinline __attribute__((always_inline)) void zero_out_nonneutral_buffer(void) const\n\t{\n\t\tif (!nonneutral_mutations_)\n\t\t{\n\t\t\t// If we don't have a buffer allocated yet, follow the same rules as for the main mutation buffer\n\t\t\tnonneutral_mutation_capacity_ = SLIM_MUTRUN_INITIAL_CAPACITY;\n\t\t\tnonneutral_mutations_ = (MutationIndex *)malloc(nonneutral_mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!nonneutral_mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::zero_out_nonneutral_buffer): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// empty out the current buffer contents\n\t\tnonneutral_mutations_count_ = 0;\n\t}\n\t\n\tinline __attribute__((always_inline)) void add_to_nonneutral_buffer(MutationIndex p_mutation_index) const\n\t{\n\t\t// This is basically the emplace_back() code, but for the nonneutral buffer\n\t\tif (nonneutral_mutations_count_ == nonneutral_mutation_capacity_)\n\t\t{\n#ifdef __clang_analyzer__\n\t\t\tassert(nonneutral_mutation_capacity_ > 0);\n#endif\n\t\t\t\n\t\t\tif (nonneutral_mutation_capacity_ < 32)\n\t\t\t\tnonneutral_mutation_capacity_ <<= 1;\t\t// double the number of pointers we can hold\n\t\t\telse\n\t\t\t\tnonneutral_mutation_capacity_ += 16;\n\t\t\t\n\t\t\tnonneutral_mutations_ = (MutationIndex *)realloc(nonneutral_mutations_, nonneutral_mutation_capacity_ * sizeof(MutationIndex));\n\t\t\tif (!nonneutral_mutations_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationRun::add_to_nonneutral_buffer): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t*(nonneutral_mutations_ + nonneutral_mutations_count_) = p_mutation_index;\n\t\t++nonneutral_mutations_count_;\n\t}\n\t\n\tvoid cache_nonneutral_mutations_REGIME_1() const;\n\tvoid cache_nonneutral_mutations_REGIME_2() const;\n\tvoid cache_nonneutral_mutations_REGIME_3() const;\n\t\n\tvoid check_nonneutral_mutation_cache() const;\n\t\n\tinline __attribute__((always_inline)) void beginend_nonneutral_pointers(const MutationIndex **p_mutptr_iter, const MutationIndex **p_mutptr_max, int32_t p_nonneutral_change_counter, int32_t p_nonneutral_regime) const\n\t{\n\t\tif ((nonneutral_change_validation_ != p_nonneutral_change_counter) || (nonneutral_mutations_count_ == -1))\n\t\t{\n\t\t\t// When running parallel, all nonneutral caches must be validated\n\t\t\t// ahead of time; see Subpopulation::FixNonNeutralCaches_OMP()\n\t\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"beginend_nonneutral_pointers()\");\n\t\t\t\n\t\t\t// If the nonneutral change counter has changed since we last validated, or our cache is invalid for other\n\t\t\t// reasons (most notably being a new mutation run that has not yet cached), validate it immediately\n\t\t\tnonneutral_change_validation_ = p_nonneutral_change_counter;\n\t\t\t\n\t\t\tswitch (p_nonneutral_regime)\n\t\t\t{\n\t\t\t\tcase 1: cache_nonneutral_mutations_REGIME_1(); break;\n\t\t\t\tcase 2: cache_nonneutral_mutations_REGIME_2(); break;\n\t\t\t\tcase 3: cache_nonneutral_mutations_REGIME_3(); break;\n\t\t\t}\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\trecached_run_ = true;\n#endif\n\t\t}\n\t\t\n#if DEBUG\n\t\tcheck_nonneutral_mutation_cache();\n#endif\n\t\t\n\t\t// Return the requested pointers to allow the caller to iterate over the nonneutral mutation buffer\n\t\t*p_mutptr_iter = nonneutral_mutations_;\n\t\t*p_mutptr_max = nonneutral_mutations_ + nonneutral_mutations_count_;\n\t}\n\t\n#ifdef _OPENMP\n\t// This is used by Subpopulation::FixNonNeutralCaches_OMP() to validate\n\t// these caches; it starts a new task if the nonneutral cache is invalid\n\t// This method is called from within a \"single\" construct.\n\tinline __attribute__((always_inline)) void validate_nonneutral_cache(int32_t p_nonneutral_change_counter, int32_t p_nonneutral_regime) const\n\t{\n\t\tif ((nonneutral_change_validation_ != p_nonneutral_change_counter) || (nonneutral_mutations_count_ == -1))\n\t\t{\n\t\t\t// If the nonneutral change counter has changed since we last validated, or our cache is invalid for other\n\t\t\t// reasons (most notably being a new mutation run that has not yet cached), validate it with an OpenMP task\n\t\t\t// We set up these variables to prevent ourselves from seeing the cache as invalid again\n\t\t\tnonneutral_change_validation_ = p_nonneutral_change_counter;\n\t\t\tnonneutral_mutations_count_ = 0;\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\trecached_run_ = true;\n#endif\n\t\t\t\n\t\t\t// I tried splitting the below code out into its own non-inline method,\n\t\t\t// but that seemed to trigger a compiler bug, so here we are.\n#pragma omp task\n\t\t\t{\n\t\t\t\tswitch (p_nonneutral_regime)\n\t\t\t\t{\n\t\t\t\t\tcase 1: cache_nonneutral_mutations_REGIME_1(); break;\n\t\t\t\t\tcase 2: cache_nonneutral_mutations_REGIME_2(); break;\n\t\t\t\t\tcase 3: cache_nonneutral_mutations_REGIME_3(); break;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tinline __attribute__((always_inline)) void tally_nonneutral_mutations(int64_t *p_mutation_count, int64_t *p_nonneutral_count, int64_t *p_recached_count) const\n\t{\n\t\t*p_mutation_count += mutation_count_;\n\t\t\n\t\tif (nonneutral_mutations_count_ != -1)\n\t\t\t*p_nonneutral_count += nonneutral_mutations_count_;\n\t\t\n\t\tif (recached_run_)\n\t\t{\n\t\t\t(*p_recached_count)++;\n\t\t\trecached_run_ = false;\n\t\t}\n\t}\n#endif\t// (SLIMPROFILING == 1)\n\t\n#endif\t// SLIM_USE_NONNEUTRAL_CACHES\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsageForMutationIndexBuffers(void) const;\n\tsize_t MemoryUsageForNonneutralCaches(void) const;\n};\n\n// We need MutationType below, but we can't include it at top because it requires MutationRun to be defined...\n#include \"mutation_type.h\"\n\ninline __attribute__((always_inline)) bool MutationRun::enforce_stack_policy_for_addition(slim_position_t p_position, MutationType *p_mut_type_ptr)\n{\n\tMutationStackPolicy policy = p_mut_type_ptr->stack_policy_;\n\t\n\tif (policy == MutationStackPolicy::kStack)\n\t{\n\t\t// If mutations are allowed to stack (the default), then we have no work to do and the new mutation is always added\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Otherwise, a relatively complicated check is needed, so we call out to a non-inline function\n\t\treturn _EnforceStackPolicyForAddition(p_position, policy, p_mut_type_ptr->stack_group_);\n\t}\n}\n\n#endif /* __SLiM__mutation_run__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation_type.cpp",
    "content": "//\n//  mutation_type.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"mutation_type.h\"\n#include \"eidos_rng.h\"\n#include \"slim_globals.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"slim_eidos_block.h\"\n#include \"species.h\"\n#include \"community.h\"\n\n#include <iostream>\n#include <sstream>\n#include <algorithm>\n#include <utility>\n\n\n// stream output for enumerations\nstd::ostream& operator<<(std::ostream& p_out, DFEType p_dfe_type)\n{\n\tswitch (p_dfe_type)\n\t{\n\t\tcase DFEType::kFixed:\t\t\tp_out << gStr_f;\t\tbreak;\n\t\tcase DFEType::kGamma:\t\t\tp_out << gStr_g;\t\tbreak;\n\t\tcase DFEType::kExponential:\t\tp_out << gStr_e;\t\tbreak;\n\t\tcase DFEType::kNormal:\t\t\tp_out << gEidosStr_n;\tbreak;\n\t\tcase DFEType::kWeibull:\t\t\tp_out << gStr_w;\t\tbreak;\n\t\tcase DFEType::kLaplace:\t\t\tp_out << gStr_p;\t\tbreak;\n\t\tcase DFEType::kScript:\t\t\tp_out << gEidosStr_s;\tbreak;\n\t}\n\t\n\treturn p_out;\n}\n\n\n#pragma mark -\n#pragma mark MutationType\n#pragma mark -\n\n#ifdef SLIMGUI\nMutationType::MutationType(Species &p_species, slim_objectid_t p_mutation_type_id, double p_dominance_coeff, bool p_nuc_based, DFEType p_dfe_type, std::vector<double> p_dfe_parameters, std::vector<std::string> p_dfe_strings, int p_mutation_type_index) :\n#else\nMutationType::MutationType(Species &p_species, slim_objectid_t p_mutation_type_id, double p_dominance_coeff, bool p_nuc_based, DFEType p_dfe_type, std::vector<double> p_dfe_parameters, std::vector<std::string> p_dfe_strings) :\n#endif\nself_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('m', p_mutation_type_id)), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_MutationType_Class))),\n\tspecies_(p_species), mutation_type_id_(p_mutation_type_id), dominance_coeff_(static_cast<slim_selcoeff_t>(p_dominance_coeff)), hemizygous_dominance_coeff_(1.0), dfe_type_(p_dfe_type), dfe_parameters_(std::move(p_dfe_parameters)), dfe_strings_(std::move(p_dfe_strings)), nucleotide_based_(p_nuc_based), convert_to_substitution_(false), stack_policy_(MutationStackPolicy::kStack), stack_group_(p_mutation_type_id), cached_dfe_script_(nullptr)\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t, muttype_registry_call_count_(0), keeping_muttype_registry_(false)\n#endif\n#ifdef SLIMGUI\n\t, mutation_type_index_(p_mutation_type_index)\n#endif\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\t// In WF models, convertToSubstitution defaults to T; in nonWF models it defaults to F as specified above\n\tif (species_.community_.ModelType() == SLiMModelType::kModelTypeWF)\n\t\tconvert_to_substitution_ = true;\n\t\n\tif ((dfe_parameters_.size() == 0) && (dfe_strings_.size() == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (MutationType::MutationType): invalid mutation type parameters.\" << EidosTerminate();\n\t// intentionally no bounds checks for DFE parameters; the count of DFE parameters is checked prior to construction\n\t// intentionally no bounds check for dominance_coeff_\n\t\n\t// determine whether this mutation type is initially pure neutral; note that this flag will be\n\t// cleared if any mutation of this type has its selection coefficient changed\n\t// note also that we do not set Species.pure_neutral_ here; we wait until this muttype is used\n\tall_pure_neutral_DFE_ = ((dfe_type_ == DFEType::kFixed) && (dfe_parameters_[0] == 0.0));\n\t\n\t// Nucleotide-based mutations use a special stacking group, -1, and always use stacking policy \"l\"\n\tif (p_nuc_based)\n\t{\n\t\tstack_policy_ = MutationStackPolicy::kKeepLast;\n\t\tstack_group_ = -1;\n\t}\n\t\n\t// The fact that we have been created means that stacking policy has changed and needs to be checked\n\tspecies_.MutationStackPolicyChanged();\n}\n\nMutationType::~MutationType(void)\n{\n\tdelete cached_dfe_script_;\n\tcached_dfe_script_ = nullptr;\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\tif (keeping_muttype_registry_)\n\t{\n\t\tmuttype_registry_.clear();\n\t\tkeeping_muttype_registry_ = false;\n\t}\n#endif\n}\n\nvoid MutationType::ParseDFEParameters(std::string &p_dfe_type_string, const EidosValue_SP *const p_arguments, int p_argument_count, DFEType *p_dfe_type, std::vector<double> *p_dfe_parameters, std::vector<std::string> *p_dfe_strings)\n{\n\t// First we figure out the DFE type from p_dfe_type_string, and set up expectations based on that\n\tint expected_dfe_param_count = 0;\n\tbool params_are_numeric = true;\n\t\n\tif (p_dfe_type_string.compare(gStr_f) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kFixed;\n\t\texpected_dfe_param_count = 1;\n\t}\n\telse if (p_dfe_type_string.compare(gStr_g) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kGamma;\n\t\texpected_dfe_param_count = 2;\n\t}\n\telse if (p_dfe_type_string.compare(gStr_e) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kExponential;\n\t\texpected_dfe_param_count = 1;\n\t}\n\telse if (p_dfe_type_string.compare(gEidosStr_n) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kNormal;\n\t\texpected_dfe_param_count = 2;\n\t}\n\telse if (p_dfe_type_string.compare(gStr_w) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kWeibull;\n\t\texpected_dfe_param_count = 2;\n\t}\n\telse if (p_dfe_type_string.compare(gStr_p) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kLaplace;\n\t\texpected_dfe_param_count = 2;\n\t}\n\telse if (p_dfe_type_string.compare(gEidosStr_s) == 0)\n\t{\n\t\t*p_dfe_type = DFEType::kScript;\n\t\texpected_dfe_param_count = 1;\n\t\tparams_are_numeric = false;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): distribution type '\" << p_dfe_type_string << \"' must be 'f', 'g', 'e', 'n', 'w', or 's'.\" << EidosTerminate();\n\t\n\tif (p_argument_count != expected_dfe_param_count)\n\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): distribution type '\" << *p_dfe_type << \"' requires exactly \" << expected_dfe_param_count << \" DFE parameter\" << (expected_dfe_param_count == 1 ? \"\" : \"s\") << \".\" << EidosTerminate();\n\t\n\t// Next we extract the parameter values, checking their types in accordance with params_are_numeric\n\tp_dfe_parameters->clear();\n\tp_dfe_strings->clear();\n\t\n\tfor (int dfe_param_index = 0; dfe_param_index < expected_dfe_param_count; ++dfe_param_index)\n\t{\n\t\tEidosValue *dfe_param_value = p_arguments[dfe_param_index].get();\n\t\tEidosValueType dfe_param_type = dfe_param_value->Type();\n\t\t\n\t\tif (params_are_numeric)\n\t\t{\n\t\t\tif ((dfe_param_type != EidosValueType::kValueFloat) && (dfe_param_type != EidosValueType::kValueInt))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): the parameters for a DFE of type '\" << *p_dfe_type << \"' must be of type numeric (integer or float).\" << EidosTerminate();\n\t\t\t\n\t\t\tp_dfe_parameters->emplace_back(dfe_param_value->NumericAtIndex_NOCAST(0, nullptr));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dfe_param_type != EidosValueType::kValueString)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): the parameters for a DFE of type '\" << *p_dfe_type << \"' must be of type string.\" << EidosTerminate();\n\t\t\t\n\t\t\tp_dfe_strings->emplace_back(dfe_param_value->StringAtIndex_NOCAST(0, nullptr));\n\t\t}\n\t}\n\t\n\t// Finally, we bounds-check the DFE parameters in the cases where there is a hard bound\n\tswitch (*p_dfe_type)\n\t{\n\t\tcase DFEType::kFixed:\n\t\t\t// no limits on fixed DFEs; we could check that s >= -1, but that assumes that the selection coefficients are being used as selection coefficients\n\t\t\tbreak;\n\t\tcase DFEType::kGamma:\n\t\t\t// mean is unrestricted, shape parameter must be >0 (officially mean > 0, but we allow mean <= 0 and the GSL handles it)\n\t\t\tif ((*p_dfe_parameters)[1] <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): a DFE of type 'g' must have a shape parameter > 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase DFEType::kExponential:\n\t\t\t// no limits on exponential DFEs (officially scale > 0, but we allow scale <= 0 and the GSL handles it)\n\t\t\tbreak;\n\t\tcase DFEType::kNormal:\n\t\t\t// mean is unrestricted, sd parameter must be >= 0\n\t\t\tif ((*p_dfe_parameters)[1] < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): a DFE of type 'n' must have a standard deviation parameter >= 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase DFEType::kWeibull:\n\t\t\t// scale and shape must both be > 0\n\t\t\tif ((*p_dfe_parameters)[0] <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): a DFE of type 'w' must have a scale parameter > 0.\" << EidosTerminate();\n\t\t\tif ((*p_dfe_parameters)[1] <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): a DFE of type 'w' must have a shape parameter > 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase DFEType::kLaplace:\n\t\t\t// mean is unrestricted, scale parameter must be > 0\n\t\t\tif ((*p_dfe_parameters)[1] <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::ParseDFEParameters): a DFE of type 'p' must have a scale parameter > 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase DFEType::kScript:\n\t\t\t// no limits on script here; the script is checked when it gets tokenized/parsed/executed\n\t\t\tbreak;\n\t}\n}\n\ndouble MutationType::DrawSelectionCoefficient(void) const\n{\n\t// BCH 11/11/2022: Note that EIDOS_GSL_RNG(omp_get_thread_num()) can take a little bit of time when running\n\t// parallel.  We don't want to pass the RNG in, though, because that would slow down the single-threaded\n\t// case, where the EIDOS_GSL_RNG(omp_get_thread_num()) call basically compiles away to a global var access.\n\t// So here and in similar places, we fetch the RNG rather than passing it in to keep single-threaded fast.\n\tswitch (dfe_type_)\n\t{\n\t\tcase DFEType::kFixed:\t\t\treturn dfe_parameters_[0];\n\t\t\t\n\t\tcase DFEType::kGamma:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\treturn gsl_ran_gamma(rng_gsl, dfe_parameters_[1], dfe_parameters_[0] / dfe_parameters_[1]);\n\t\t}\n\t\t\t\n\t\tcase DFEType::kExponential:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\treturn gsl_ran_exponential(rng_gsl, dfe_parameters_[0]);\n\t\t}\n\t\t\t\n\t\tcase DFEType::kNormal:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\treturn gsl_ran_gaussian(rng_gsl, dfe_parameters_[1]) + dfe_parameters_[0];\n\t\t}\n\t\t\t\n\t\tcase DFEType::kWeibull:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\treturn gsl_ran_weibull(rng_gsl, dfe_parameters_[0], dfe_parameters_[1]);\n\t\t}\n\t\t\t\n\t\tcase DFEType::kLaplace:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\treturn gsl_ran_laplace(rng_gsl, dfe_parameters_[1]) + dfe_parameters_[0];\n\t\t}\n\t\t\t\n\t\tcase DFEType::kScript:\n\t\t{\n\t\t\t// We have a script string that we need to execute, and it will return a float or integer to us.  This\n\t\t\t// is basically a lambda call, so the code here is parallel to the executeLambda() code in many ways.\n\t\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t\t// When running multi-threaded, this code is not re-entrant because it runs an Eidos interpreter.  We use\n\t\t\t// EidosDebugLock to enforce that.  In addition, it can raise, so the caller must be prepared for that.\n\t\t\tstatic EidosDebugLock DrawSelectionCoefficient_InterpreterLock(\"DrawSelectionCoefficient_InterpreterLock\");\n\t\t\t\n\t\t\tDrawSelectionCoefficient_InterpreterLock.start_critical(0);\n#endif\n\t\t\t\n\t\t\tdouble sel_coeff;\n\t\t\t\n\t\t\t// Errors in lambdas should be reported for the lambda script, not for the calling script,\n\t\t\t// if possible.  In the GUI this does not work well, however; there, errors should be\n\t\t\t// reported as occurring in the call to executeLambda().  Here we save off the current\n\t\t\t// error context and set up the error context for reporting errors inside the lambda,\n\t\t\t// in case that is possible; see how exceptions are handled below.\n\t\t\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\t\t\n\t\t\t// We try to do tokenization and parsing once per script, by caching the script\n\t\t\tif (!cached_dfe_script_)\n\t\t\t{\n\t\t\t\tstd::string script_string = dfe_strings_[0];\n\t\t\t\tcached_dfe_script_ = new EidosScript(script_string);\n\t\t\t\t\n\t\t\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, cached_dfe_script_};\n\t\t\t\t\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tcached_dfe_script_->Tokenize();\n\t\t\t\t\tcached_dfe_script_->ParseInterpreterBlockToAST(false);\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tif (gEidosTerminateThrows)\n\t\t\t\t\t{\n\t\t\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\t\t\tTranslateErrorContextToUserScript(\"DrawSelectionCoefficient()\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tdelete cached_dfe_script_;\n\t\t\t\t\tcached_dfe_script_ = nullptr;\n\t\t\t\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t\t\t\tDrawSelectionCoefficient_InterpreterLock.end_critical();\n#endif\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::DrawSelectionCoefficient): tokenize/parse error in type 's' DFE callback script.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Execute inside try/catch so we can handle errors well\n\t\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, cached_dfe_script_};\n\t\t\t\n\t\t\ttry\n\t\t\t{\n\t\t\t\tCommunity &community = species_.community_;\n\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &community.SymbolTable());\n\t\t\t\tEidosFunctionMap &function_map = community.FunctionMap();\n\t\t\t\tEidosInterpreter interpreter(*cached_dfe_script_, client_symbols, function_map, &community, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t, community.check_infinite_loops_\n#endif\n\t\t\t\t\t);\n\t\t\t\t\n\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInterpreterBlock(false, true);\t// do not print output, return the last statement value\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\tEidosValueType result_type = result->Type();\n\t\t\t\tint result_count = result->Count();\n\t\t\t\t\n\t\t\t\tif ((result_type == EidosValueType::kValueFloat) && (result_count == 1))\n\t\t\t\t\tsel_coeff = result->FloatData()[0];\n\t\t\t\telse if ((result_type == EidosValueType::kValueInt) && (result_count == 1))\n\t\t\t\t\tsel_coeff = result->IntData()[0];\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::DrawSelectionCoefficient): type 's' DFE callbacks must provide a singleton float or integer return value.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\t// If exceptions throw, then we want to set up the error information to highlight the\n\t\t\t\t// executeLambda() that failed, since we can't highlight the actual error.  (If exceptions\n\t\t\t\t// don't throw, this catch block will never be hit; exit() will already have been called\n\t\t\t\t// and the error will have been reported from the context of the lambda script string.)\n\t\t\t\tif (gEidosTerminateThrows)\n\t\t\t\t{\n\t\t\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t\t\t{\n\t\t\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\t\t\tTranslateErrorContextToUserScript(\"DrawSelectionCoefficient()\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t\t\tDrawSelectionCoefficient_InterpreterLock.end_critical();\n#endif\n\t\t\t\t\n\t\t\t\tthrow;\n\t\t\t}\n\t\t\t\n\t\t\t// Restore the normal error context in the event that no exception occurring within the lambda\n\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t\tDrawSelectionCoefficient_InterpreterLock.end_critical();\n#endif\n\t\t\t\n\t\t\treturn sel_coeff;\n\t\t}\n\t}\n\tEIDOS_TERMINATION << \"ERROR (MutationType::DrawSelectionCoefficient): (internal error) unexpected dfe_type_ value.\" << EidosTerminate();\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const MutationType &p_mutation_type)\n{\n\tp_outstream << \"MutationType{dominance_coeff_ \" << p_mutation_type.dominance_coeff_ << \", dfe_type_ '\" << p_mutation_type.dfe_type_ << \"', dfe_parameters_ <\";\n\t\n\tif (p_mutation_type.dfe_parameters_.size() > 0)\n\t{\n\t\tfor (unsigned int i = 0; i < p_mutation_type.dfe_parameters_.size(); ++i)\n\t\t{\n\t\t\tp_outstream << p_mutation_type.dfe_parameters_[i];\n\t\t\t\n\t\t\tif (i < p_mutation_type.dfe_parameters_.size() - 1)\n\t\t\t\tp_outstream << \" \";\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (unsigned int i = 0; i < p_mutation_type.dfe_strings_.size(); ++i)\n\t\t{\n\t\t\tp_outstream << \"\\\"\" << p_mutation_type.dfe_strings_[i] << \"\\\"\";\n\t\t\t\n\t\t\tif (i < p_mutation_type.dfe_strings_.size() - 1)\n\t\t\t\tp_outstream << \" \";\n\t\t}\n\t}\n\t\n\tp_outstream << \">}\";\n\t\n\treturn p_outstream;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *MutationType::Class(void) const\n{\n\treturn gSLiM_MutationType_Class;\n}\n\nvoid MutationType::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<m\" << mutation_type_id_ << \">\";\n}\n\nEidosValue_SP MutationType::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_id:\t\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!cached_value_muttype_id_)\n\t\t\t\tcached_value_muttype_id_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_type_id_));\n\t\t\treturn cached_value_muttype_id_;\n\t\t}\n\t\tcase gID_distributionType:\n\t\t{\n\t\t\tstatic EidosValue_SP static_dfe_string_f;\n\t\t\tstatic EidosValue_SP static_dfe_string_g;\n\t\t\tstatic EidosValue_SP static_dfe_string_e;\n\t\t\tstatic EidosValue_SP static_dfe_string_n;\n\t\t\tstatic EidosValue_SP static_dfe_string_w;\n\t\t\tstatic EidosValue_SP static_dfe_string_p;\n\t\t\tstatic EidosValue_SP static_dfe_string_s;\n\t\t\t\n#pragma omp critical (GetProperty_distributionType_cache)\n\t\t\t{\n\t\t\t\tif (!static_dfe_string_f)\n\t\t\t\t{\n\t\t\t\t\tstatic_dfe_string_f = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_f));\n\t\t\t\t\tstatic_dfe_string_g = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_g));\n\t\t\t\t\tstatic_dfe_string_e = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_e));\n\t\t\t\t\tstatic_dfe_string_n = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_n));\n\t\t\t\t\tstatic_dfe_string_w = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_w));\n\t\t\t\t\tstatic_dfe_string_p = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_p));\n\t\t\t\t\tstatic_dfe_string_s = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_s));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tswitch (dfe_type_)\n\t\t\t{\n\t\t\t\tcase DFEType::kFixed:\t\t\treturn static_dfe_string_f;\n\t\t\t\tcase DFEType::kGamma:\t\t\treturn static_dfe_string_g;\n\t\t\t\tcase DFEType::kExponential:\t\treturn static_dfe_string_e;\n\t\t\t\tcase DFEType::kNormal:\t\t\treturn static_dfe_string_n;\n\t\t\t\tcase DFEType::kWeibull:\t\t\treturn static_dfe_string_w;\n\t\t\t\tcase DFEType::kLaplace:\t\t\treturn static_dfe_string_p;\n\t\t\t\tcase DFEType::kScript:\t\t\treturn static_dfe_string_s;\n\t\t\t\tdefault:\t\t\t\t\t\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_distributionParams:\n\t\t{\n\t\t\tif (dfe_parameters_.size() > 0)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(dfe_parameters_));\n\t\t\telse\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(dfe_strings_));\n\t\t}\n\t\tcase gID_species:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(&species_, gSLiM_Species_Class));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gEidosID_color:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(color_));\n\t\tcase gID_colorSubstitution:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(color_sub_));\n\t\tcase gID_convertToSubstitution:\n\t\t\treturn (convert_to_substitution_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_dominanceCoeff:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(dominance_coeff_));\n\t\tcase gID_hemizygousDominanceCoeff:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(hemizygous_dominance_coeff_));\n\t\tcase gID_mutationStackGroup:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(stack_group_));\n\t\tcase gID_nucleotideBased:\n\t\t\treturn (nucleotide_based_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_mutationStackPolicy:\n\t\t{\n\t\t\tstatic EidosValue_SP static_policy_string_s;\n\t\t\tstatic EidosValue_SP static_policy_string_f;\n\t\t\tstatic EidosValue_SP static_policy_string_l;\n\t\t\t\n#pragma omp critical (GetProperty_mutationStackPolicy_cache)\n\t\t\t{\n\t\t\t\tif (!static_policy_string_s)\n\t\t\t\t{\n\t\t\t\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"MutationType::GetProperty(): usage of statics\");\n\t\t\t\t\t\n\t\t\t\t\tstatic_policy_string_s = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_s));\n\t\t\t\t\tstatic_policy_string_f = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_f));\n\t\t\t\t\tstatic_policy_string_l = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_l));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tswitch (stack_policy_)\n\t\t\t{\n\t\t\t\tcase MutationStackPolicy::kStack:\t\treturn static_policy_string_s;\n\t\t\t\tcase MutationStackPolicy::kKeepFirst:\treturn static_policy_string_f;\n\t\t\t\tcase MutationStackPolicy::kKeepLast:\treturn static_policy_string_l;\n\t\t\t\tdefault:\t\t\t\t\t\t\t\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_tag:\t\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::GetProperty): property tag accessed on mutation type before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *MutationType::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutationType *value = (MutationType *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->mutation_type_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *MutationType::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutationType *value = (MutationType *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::GetProperty_Accelerated_tag): property tag accessed on mutation type before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *MutationType::GetProperty_Accelerated_dominanceCoeff(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tMutationType *value = (MutationType *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->dominance_coeff_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nvoid MutationType::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gEidosID_color:\n\t\t{\n\t\t\tcolor_ = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\tif (!color_.empty())\n\t\t\t\tEidos_GetColorComponents(color_, &color_red_, &color_green_, &color_blue_);\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_colorSubstitution:\n\t\t{\n\t\t\tcolor_sub_ = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\tif (!color_sub_.empty())\n\t\t\t\tEidos_GetColorComponents(color_sub_, &color_sub_red_, &color_sub_green_, &color_sub_blue_);\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_convertToSubstitution:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tconvert_to_substitution_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_dominanceCoeff:\n\t\t{\n\t\t\tdouble value = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tdominance_coeff_ = static_cast<slim_selcoeff_t>(value);\t\t// intentionally no bounds check\n\t\t\t\n\t\t\t// Changing the dominance coefficient means that the cached fitness effects of all mutations using this type\n\t\t\t// become invalid.  We set a flag here to indicate that values that depend on us need to be recached.\n\t\t\tspecies_.any_dominance_coeff_changed_ = true;\n\t\t\tspecies_.community_.mutation_types_changed_ = true;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_hemizygousDominanceCoeff:\n\t\t{\n\t\t\tdouble value = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\themizygous_dominance_coeff_ = static_cast<slim_selcoeff_t>(value);\t\t// intentionally no bounds check\n\t\t\t\n\t\t\t// Changing the hemizygous dominance coefficient means that the cached fitness effects of all mutations using this type\n\t\t\t// become invalid.  We set a flag here to indicate that values that depend on us need to be recached.\n\t\t\tspecies_.any_dominance_coeff_changed_ = true;\n\t\t\tspecies_.community_.mutation_types_changed_ = true;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_mutationStackGroup:\n\t\t{\n\t\t\tint64_t new_group = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (nucleotide_based_ && (new_group != -1))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::SetProperty): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" must be -1 for nucleotide-based mutation types.\" << EidosTerminate();\n\t\t\t\n\t\t\tstack_group_ = new_group;\n\t\t\t\n\t\t\tspecies_.MutationStackPolicyChanged();\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_mutationStackPolicy:\n\t\t{\n\t\t\tstd::string value = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (nucleotide_based_ && (value != gStr_l))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::SetProperty): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" must be 'l' for nucleotide-based mutation types.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (value.compare(gEidosStr_s) == 0)\n\t\t\t\tstack_policy_ = MutationStackPolicy::kStack;\n\t\t\telse if (value.compare(gStr_f) == 0)\n\t\t\t\tstack_policy_ = MutationStackPolicy::kKeepFirst;\n\t\t\telse if (value.compare(gStr_l) == 0)\n\t\t\t\tstack_policy_ = MutationStackPolicy::kKeepLast;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (MutationType::SetProperty): new value for property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" must be 's', 'f', or 'l'.\" << EidosTerminate();\n\t\t\t\n\t\t\tspecies_.MutationStackPolicyChanged();\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nvoid MutationType::SetProperty_Accelerated_convertToSubstitution(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\teidos_logical_t source_value = p_source.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((MutationType *)(p_values[value_index]))->convert_to_substitution_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst eidos_logical_t *source_data = p_source.LogicalData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((MutationType *)(p_values[value_index]))->convert_to_substitution_ = source_data[value_index];\n\t}\n}\n\nvoid MutationType::SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((MutationType *)(p_values[value_index]))->tag_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((MutationType *)(p_values[value_index]))->tag_value_ = source_data[value_index];\n\t}\n}\n\nEidosValue_SP MutationType::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_drawSelectionCoefficient:\treturn ExecuteMethod_drawSelectionCoefficient(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setDistribution:\t\t\treturn ExecuteMethod_setDistribution(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (float)drawSelectionCoefficient([integer$ n = 1])\n//\nEidosValue_SP MutationType::ExecuteMethod_drawSelectionCoefficient(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_SP result_SP(nullptr);\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (ExecuteMethod_drawSelectionCoefficient): drawSelectionCoefficient() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\tfloat_result->set_float_no_check(DrawSelectionCoefficient(), draw_index);\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (void)setDistribution(string$ distributionType, ...)\n//\nEidosValue_SP MutationType::ExecuteMethod_setDistribution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *distributionType_value = p_arguments[0].get();\n\tstd::string dfe_type_string = distributionType_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\t// Parse the DFE type and parameters, and do various sanity checks\n\tDFEType dfe_type;\n\tstd::vector<double> dfe_parameters;\n\tstd::vector<std::string> dfe_strings;\n\t\n\tMutationType::ParseDFEParameters(dfe_type_string, p_arguments.data() + 1, (int)p_arguments.size() - 1, &dfe_type, &dfe_parameters, &dfe_strings);\n\t\n\t// keep track of whether we have ever seen a type 's' (scripted) DFE; if so, we switch to a slower case when evolving\n\tif (dfe_type == DFEType::kScript)\n\t\tspecies_.type_s_dfes_present_ = true;\n\t\n\t// Everything seems to be in order, so replace our distribution info with the new info\n\tdfe_type_ = dfe_type;\n\tdfe_parameters_ = dfe_parameters;\n\tdfe_strings_ = dfe_strings;\n\t\n\t// mark that mutation types changed, so they get redisplayed in SLiMgui\n\tspecies_.community_.mutation_types_changed_ = true;\n\t\n\t// check whether we are now using a DFE type that is non-neutral; check and set pure_neutral_ and all_pure_neutral_DFE_\n\tif ((dfe_type_ != DFEType::kFixed) || (dfe_parameters_[0] != 0.0))\n\t{\n\t\tspecies_.pure_neutral_ = false;\n\t\tall_pure_neutral_DFE_ = false;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tMutationType_Class\n//\n#pragma mark -\n#pragma mark MutationType_Class\n#pragma mark -\n\nEidosClass *gSLiM_MutationType_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *MutationType_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"MutationType_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(MutationType::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_convertToSubstitution,\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->DeclareAcceleratedSet(MutationType::SetProperty_Accelerated_convertToSubstitution));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_distributionType,\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_distributionParams,\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskString)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_dominanceCoeff,\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(MutationType::GetProperty_Accelerated_dominanceCoeff));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_hemizygousDominanceCoeff,\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationStackGroup,\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationStackPolicy,\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotideBased,\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_species,\t\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(MutationType::GetProperty_Accelerated_tag)->DeclareAcceleratedSet(MutationType::SetProperty_Accelerated_tag));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_color,\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_colorSubstitution,\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *MutationType_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"MutationType_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_drawSelectionCoefficient, kEidosValueMaskFloat))->AddInt_OS(\"n\", gStaticEidosValue_Integer1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setDistribution, kEidosValueMaskVOID))->AddString_S(\"distributionType\")->AddEllipsis());\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/mutation_type.h",
    "content": "//\n//  mutation_type.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class MutationType represents a type of mutation defined in the input file, such as a synonymous mutation or an adaptive mutation.\n A particular mutation type is defined by its distribution of fitness effects (DFE) and its dominance coefficient.  Once a mutation type\n is defined, a draw from its DFE can be generated to determine the selection coefficient of a particular mutation of that type.\n \n */\n\n// This include is up here because I had to jump through some hoops to break a #include loop between this and mutation_run.h;\n// forward declaration wasn't enough, because MutationType includes a MutationRun inside itself now, and mutation_run.h defines\n// an inline function that uses MutationType in a concrete fashion, so the mutual dependency was harder to break.\n#include \"mutation_run.h\"\n\n#ifndef __SLiM__mutation_type__\n#define __SLiM__mutation_type__\n\n\n#include <vector>\n#include <string>\n#include \"eidos_value.h\"\n#include \"eidos_symbol_table.h\"\n#include \"slim_globals.h\"\n\nclass Species;\n\n\nextern EidosClass *gSLiM_MutationType_Class;\n\n\n// This enumeration represents a type of distribution of fitness effects (DFE) that a mutation type can draw from\nenum class DFEType : char {\n\tkFixed = 0,\n\tkGamma,\n\tkExponential,\n\tkNormal,\n\tkWeibull,\n\tkLaplace,\n\tkScript\n};\n\nstd::ostream& operator<<(std::ostream& p_out, DFEType p_dfe_type);\n\n\t\nclass MutationType : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t\t\t// for fast setup of the symbol table\n\npublic:\n\t\n\t// a mutation type is specified by the DFE and the dominance coefficient\n\t//\n\t// DFE options: f: fixed (s) \n\t//              e: exponential (mean s)\n\t//              g: gamma distribution (mean s,shape)\n\t//\n\t// examples: synonymous, nonsynonymous, adaptive, etc.\n\t\n\tSpecies &species_;\n\t\n\tslim_objectid_t mutation_type_id_;\t\t\t// the id by which this mutation type is indexed in the chromosome\n\tEidosValue_SP cached_value_muttype_id_;\t\t// a cached value for mutation_type_id_; reset() if that changes\n\t\n\tslim_selcoeff_t dominance_coeff_;\t\t\t// dominance coefficient (h)\n\tslim_selcoeff_t hemizygous_dominance_coeff_;\t// dominance coefficient (h) used when one haplosome is null\n\t\n\tDFEType dfe_type_;\t\t\t\t\t\t\t// distribution of fitness effects (DFE) type (f: fixed, g: gamma, e: exponential, n: normal, w: Weibull)\n\tstd::vector<double> dfe_parameters_;\t\t// DFE parameters, of type double (originally float or integer type)\n\tstd::vector<std::string> dfe_strings_;\t\t// DFE parameters, of type std::string (originally string type)\n\t\n\tbool nucleotide_based_;\t\t\t\t\t\t// if true, the mutation type is nucleotide-based (i.e. mutations keep associated nucleotides)\n\t\n\tbool convert_to_substitution_;\t\t\t\t// if true (the default in WF models), mutations of this type are converted to substitutions\n\tMutationStackPolicy stack_policy_;\t\t\t// the mutation stacking policy; see above (kStack is the default)\n\tint64_t stack_group_;\t\t\t\t\t\t// the mutation stacking group this mutation type is in (== mutation_type_id_ is default)\n\t\n\tstd::string color_;\t\t\t\t\t\t\t\t\t\t\t// color to use when displayed (in SLiMgui), when segregating\n\tfloat color_red_, color_green_, color_blue_;\t\t\t\t// cached color components from color_; should always be in sync\n\tstd::string color_sub_;\t\t\t\t\t\t\t\t\t\t// color to use when displayed (in SLiMgui), when fixed\n\tfloat color_sub_red_, color_sub_green_, color_sub_blue_;\t// cached color components from color_sub_; should always be in sync\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t// a user-defined tag value\n\n\tmutable EidosScript *cached_dfe_script_;\t// used by DFE type 's' to hold a cached script for the DFE\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t// MutationType now has the ability to (optionally) keep a registry of all extant mutations of its type in the simulation,\n\t// separate from the main registry kept by Population.  This allows much faster response to Species::mutationsOfType()\n\t// and Species::countOfMutationsOfType(), because the muttype's registry can be consulted rather than doing a full scan of\n\t// main registry.  However, there is obviously overhead associated with adding/removing mutations from another registry, so\n\t// this feature is only turned on if there is demand: when more than one call per tick is made to Species::mutationsOfType()\n\t// or Species::countOfMutationsOfType() for a given muttype.  From then on, that muttype will track its own registry.  Obviously\n\t// this heuristic could be refined, perhaps with a way to stop tracking if it no longer seems to be used.\n\tmutable int muttype_registry_call_count_;\n\tmutable bool keeping_muttype_registry_;\n\tMutationRun muttype_registry_;\n#endif\n\t\n\t// For optimizing the fitness calculation code, the exact situation for each mutation type is of great interest: does it have\n\t// a neutral DFE, and if so has any mutation of that type had its selection coefficient changed to be non-zero, are mutations\n\t// of this type made neutral by a constant callback like \"return 1.0;\", and so forth.  Different parts of the code need to\n\t// know slightly different things, so we have several different flags of this sort.\n\t\n\t// all_pure_neutral_DFE_ is true if the DFE is \"f\" 0.0.  It is cleared if any mutation of this type has its selection coefficient\n\t// changed, so it can be used as a reliable indicator that mutations of a given mutation type are actually neutral – except for\n\t// the effects of mutationEffect() callbacks, which might make them non-neutral in a given tick / subpopulation.\n\tmutable bool all_pure_neutral_DFE_;\n\t\n\t// is_pure_neutral_now_ is set up by Subpopulation::UpdateFitness(), and is valid only inside a given UpdateFitness() call.\n\t// If set, it indicates that the mutation type is currently pure neutral – either because all_pure_neutral_DFE_ is set and the\n\t// mutation type cannot be influenced by any callbacks in the current subpopulation / tick, or because an active callback\n\t// actually sets the mutation type to be a constant value of 1.0 in this subpopulation / tick.  Mutations for which this\n\t// flag is set can be safely elided from fitness calculations altogether; the flag will not be set if other active callbacks\n\t// could mess things up for the mutation type by, e.g., deactivating the neutral-making callback.  If this flag is set for all\n\t// muttypes, chromosome-based fitness calculations will be skipped altogether for this tick.\n\tmutable bool is_pure_neutral_now_;\n\t\n\t// set_neutral_by_global_active_callback_ is set by RecalculateFitness() if the muttype is made neutral by a constant callback\n\t// (i.e., return 1.0) that is global (i.e., applies to all subpops) and active.  This flag should be consulted only when the\n\t// \"nonneutral regime\" (i.e., sim.last_nonneutral_regime_) is 2 (constant neutral mutationEffect() callbacks only); it is not\n\t// valid in other scenarios, so it should be used with extreme caution.\n\tmutable bool set_neutral_by_global_active_callback_ = false;\n\tmutable bool previous_set_neutral_by_global_active_callback_;\t// the previous value; scratch space for RecalculateFitness()\n\t\n\t// subject_to_mutationEffect_callback_ is set by RecalculateFitness() if the muttype is currently influenced by a callback in any subpop.\n\t// Mutations with this flag set are considered to be non-neutral, since their fitness value is unpredictable; mutations without\n\t// this flag set, on the other hand, are not influenced by any callback (active or inactive), so their selcoeff may be consulted.\n\t// This flag is valid only when the \"nonneutral regime\" (i.e., sim.last_nonneutral_regime_) is 3 (non-constant or non-neutral\n\t// callbacks present); it is not valid in other scenarios, so it should be used with extreme caution.\n\tmutable bool subject_to_mutationEffect_callback_ = false;\n\tmutable bool previous_subject_to_mutationEffect_callback_;\t\t\t\t// the previous value; scratch space for RecalculateFitness()\n\t\n#ifdef SLIMGUI\n\tint mutation_type_index_;\t\t\t\t\t// a zero-based index for this mutation type, used by SLiMgui to bin data by mutation type\n\tbool mutation_type_displayed_;\t\t\t\t// a flag used by SLiMgui to indicate whether this mutation type is being displayed in the chromosome view\n#endif\n\t\n\tMutationType(const MutationType&) = delete;\t\t\t\t\t// no copying\n\tMutationType& operator=(const MutationType&) = delete;\t\t// no copying\n\tMutationType(void) = delete;\t\t\t\t\t\t\t\t// no null construction\n#ifdef SLIMGUI\n\tMutationType(Species &p_species, slim_objectid_t p_mutation_type_id, double p_dominance_coeff, bool p_nuc_based, DFEType p_dfe_type, std::vector<double> p_dfe_parameters, std::vector<std::string> p_dfe_strings, int p_mutation_type_index);\n#else\n\tMutationType(Species &p_species, slim_objectid_t p_mutation_type_id, double p_dominance_coeff, bool p_nuc_based, DFEType p_dfe_type, std::vector<double> p_dfe_parameters, std::vector<std::string> p_dfe_strings);\n#endif\n\t~MutationType(void);\n\t\n\tstatic void ParseDFEParameters(std::string &p_dfe_type_string, const EidosValue_SP *const p_arguments, int p_argument_count,\n\t\t\t\t\t\t\t\t   DFEType *p_dfe_type, std::vector<double> *p_dfe_parameters, std::vector<std::string> *p_dfe_strings);\n\t\n\tdouble DrawSelectionCoefficient(void) const;\t\t\t\t\t// draw a selection coefficient from this mutation type's DFE\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; }\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_drawSelectionCoefficient(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setDistribution(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_dominanceCoeff(EidosObject **p_values, size_t p_values_size);\n\t\n\tstatic void SetProperty_Accelerated_convertToSubstitution(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n};\n\n// support stream output of MutationType, for debugging\nstd::ostream &operator<<(std::ostream &p_outstream, const MutationType &p_mutation_type);\n\nclass MutationType_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tMutationType_Class(const MutationType_Class &p_original) = delete;\t// no copy-construct\n\tMutationType_Class& operator=(const MutationType_Class&) = delete;\t// no copying\n\tinline MutationType_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__mutation_type__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/polymorphism.cpp",
    "content": "//\n//  polymorphism.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"polymorphism.h\"\n#include \"species.h\"\n\n#include <fstream>\n#include <map>\n#include <utility>\n#include <vector>\n\n\nPolymorphism::Polymorphism(slim_polymorphismid_t p_polymorphism_id, const Mutation *p_mutation_ptr, slim_refcount_t p_prevalence) :\n\tpolymorphism_id_(p_polymorphism_id), mutation_ptr_(p_mutation_ptr), prevalence_(p_prevalence)\n{\n}\n\nvoid Polymorphism::Print_ID_Tag(std::ostream &p_out) const\n{\n\t// BCH 4/6/2025: This is a copy of Print_ID() with output of\n\t// mutation_ptr_->tag_value_ added at the end\n\t\n\t// Added mutation_ptr_->mutation_id_ to this output, BCH 11 June 2016\n\t// Switched to full-precision output of selcoeff and domcoeff, for accurate reloading; BCH 22 March 2019\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Polymorphism::Print_ID_Tag(): usage of statics\");\n\t\n\tstatic char double_buf[40];\n\t\n\tp_out << polymorphism_id_ << \" \" << mutation_ptr_->mutation_id_ << \" \" << \"m\" << mutation_ptr_->mutation_type_ptr_->mutation_type_id_ << \" \" << mutation_ptr_->position_ << \" \";\n\t\n\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_FLT_DIGS, mutation_ptr_->selection_coeff_);\t\t// necessary precision for non-lossiness\n\tp_out << double_buf;\n\t\n\tp_out << \" \";\n\t\n\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_FLT_DIGS, mutation_ptr_->mutation_type_ptr_->dominance_coeff_);\t\t// necessary precision for non-lossiness\n\tp_out << double_buf;\n\t\n\tp_out << \" p\" << mutation_ptr_->subpop_index_ << \" \" << mutation_ptr_->origin_tick_ << \" \" << prevalence_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_ptr_->mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[mutation_ptr_->nucleotide_];\n\t\n\t// output the tag value, or '?' or the tag is not defined\n\tslim_usertag_t tag = mutation_ptr_->tag_value_;\n\t\n\tif (tag == SLIM_TAG_UNSET_VALUE)\n\t\tp_out << ' ' << '?';\n\telse\n\t\tp_out << ' ' << tag;\n\t\n\tp_out << std::endl;\n}\n\nvoid Polymorphism::Print_ID(std::ostream &p_out) const\n{\n\t// Added mutation_ptr_->mutation_id_ to this output, BCH 11 June 2016\n\t// Switched to full-precision output of selcoeff and domcoeff, for accurate reloading; BCH 22 March 2019\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Polymorphism::Print_ID(): usage of statics\");\n\t\n\tstatic char double_buf[40];\n\t\n\tp_out << polymorphism_id_ << \" \" << mutation_ptr_->mutation_id_ << \" \" << \"m\" << mutation_ptr_->mutation_type_ptr_->mutation_type_id_ << \" \" << mutation_ptr_->position_ << \" \";\n\t\n\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_FLT_DIGS, mutation_ptr_->selection_coeff_);\t\t// necessary precision for non-lossiness\n\tp_out << double_buf;\n\t\n\tp_out << \" \";\n\t\n\tsnprintf(double_buf, 40, \"%.*g\", EIDOS_FLT_DIGS, mutation_ptr_->mutation_type_ptr_->dominance_coeff_);\t\t// necessary precision for non-lossiness\n\tp_out << double_buf;\n\t\n\tp_out << \" p\" << mutation_ptr_->subpop_index_ << \" \" << mutation_ptr_->origin_tick_ << \" \" << prevalence_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_ptr_->mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[mutation_ptr_->nucleotide_];\n\t\n\tp_out << std::endl;\n}\n\nvoid Polymorphism::Print_NoID_Tag(std::ostream &p_out) const\n{\n\t// Added mutation_ptr_->mutation_id_ to this output, BCH 11 June 2016\n\t// Note that Print_ID() now outputs selcoeff and domcoeff in full precision, whereas here we do not; BCH 22 March 2019\n\tp_out << mutation_ptr_->mutation_id_ << \" \" << \"m\" << mutation_ptr_->mutation_type_ptr_->mutation_type_id_ << \" \" << mutation_ptr_->position_;\n\t\n\t// BCH 2/2/2025: Note that in multi-chrom models, this method now prints the chromosome symbol after the position\n\t// For brevity and backward compatibility, the chromosome symbol is not printed in single-chromosome models\n\tSpecies &species = mutation_ptr_->mutation_type_ptr_->species_;\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tChromosome *chromosome = chromosomes[mutation_ptr_->chromosome_index_];\n\t\t\n\t\tp_out << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\n\t}\n\t\n\t// and then the remainder of the output line\n\tp_out << \" \" << mutation_ptr_->selection_coeff_ << \" \" << mutation_ptr_->mutation_type_ptr_->dominance_coeff_ << \" p\" << mutation_ptr_->subpop_index_ << \" \" << mutation_ptr_->origin_tick_ << \" \" << prevalence_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_ptr_->mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[mutation_ptr_->nucleotide_];\n\t\n\t// output the tag value, or '?' or the tag is not defined\n\tslim_usertag_t tag = mutation_ptr_->tag_value_;\n\t\n\tif (tag == SLIM_TAG_UNSET_VALUE)\n\t\tp_out << ' ' << '?';\n\telse\n\t\tp_out << ' ' << tag;\n\t\n\tp_out << std::endl;\n}\n\nvoid Polymorphism::Print_NoID(std::ostream &p_out) const\n{\n\t// Added mutation_ptr_->mutation_id_ to this output, BCH 11 June 2016\n\t// Note that Print_ID() now outputs selcoeff and domcoeff in full precision, whereas here we do not; BCH 22 March 2019\n\tp_out << mutation_ptr_->mutation_id_ << \" \" << \"m\" << mutation_ptr_->mutation_type_ptr_->mutation_type_id_ << \" \" << mutation_ptr_->position_;\n\t\n\t// BCH 2/2/2025: Note that in multi-chrom models, this method now prints the chromosome symbol after the position\n\t// For brevity and backward compatibility, the chromosome symbol is not printed in single-chromosome models\n\tSpecies &species = mutation_ptr_->mutation_type_ptr_->species_;\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tChromosome *chromosome = chromosomes[mutation_ptr_->chromosome_index_];\n\t\t\n\t\tp_out << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\n\t}\n\t\n\t// and then the remainder of the output line\n\tp_out << \" \" << mutation_ptr_->selection_coeff_ << \" \" << mutation_ptr_->mutation_type_ptr_->dominance_coeff_ << \" p\" << mutation_ptr_->subpop_index_ << \" \" << mutation_ptr_->origin_tick_ << \" \" << prevalence_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_ptr_->mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[mutation_ptr_->nucleotide_];\n\t\n\tp_out << std::endl;\n}\n\n// find p_mutation in p_polymorphisms and return its id\nslim_polymorphismid_t FindMutationInPolymorphismMap(const PolymorphismMap &p_polymorphisms, const Mutation *p_mutation)\n{\n\tauto poly_iter = p_polymorphisms.find(p_mutation->mutation_id_);\n\t\n\tif (poly_iter == p_polymorphisms.end())\n\t\treturn -1;\t\t\t\t\t\t\t\t// a flag indicating a failed lookup\n\t\n\treturn poly_iter->second.polymorphism_id_;\n}\n\n// if mutation p_mutation is present in p_polymorphisms increase its prevalence, otherwise add it\nvoid AddMutationToPolymorphismMap(PolymorphismMap *p_polymorphisms, const Mutation *p_mutation)\n{\n\tauto poly_iter = p_polymorphisms->find(p_mutation->mutation_id_);\n\t\n\tif (poly_iter == p_polymorphisms->end())\n\t{\n\t\t// the mutation was not found, so add it to p_polymorphisms with a unique index counting up from 0\n\t\tauto polymorphisms_size = p_polymorphisms->size();\n\t\t\n\t\tif (polymorphisms_size > INT32_MAX)\n\t\t\tEIDOS_TERMINATION << \"ERROR (AddMutationToPolymorphismMap): (internal error) polymorphism_id does not fit in int32_t.\" << EidosTerminate();\n\t\t\n\t\tslim_polymorphismid_t polymorphism_id = static_cast<slim_polymorphismid_t>(polymorphisms_size);\n\t\tPolymorphism new_polymorphism = Polymorphism(polymorphism_id, p_mutation, 1);\n\t\t\n\t\tp_polymorphisms->emplace(p_mutation->mutation_id_, new_polymorphism);\n\t}\n\telse\n\t{\n\t\tpoly_iter->second.prevalence_++;\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/polymorphism.h",
    "content": "//\n//  polymorphism.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Polymorphism represents a polymorphism within a population.  It is not used in the simulation dynamics; it is only used\n for the purpose of collating statistics about a simulation for output.\n \n */\n\n#ifndef __SLiM__polymorphism__\n#define __SLiM__polymorphism__\n\n\n#include <iostream>\n\n#include \"chromosome.h\"\n\n\nclass Polymorphism;\n\n// This used to be a multimap that indexed by position, allowing collisions.  Now it is a std::map that indexes by mutation_id_,\n// which avoids any possibility of collisions, making the code simpler and faster.  BCH 11 June 2016\ntypedef std::map<const slim_mutationid_t,Polymorphism> PolymorphismMap;\ntypedef std::pair<const slim_mutationid_t,Polymorphism> PolymorphismPair;\n\n\nclass Polymorphism\n{\n\t// This class allows copying by design\n\t\npublic:\n\t\n\tslim_polymorphismid_t polymorphism_id_;\t\t// a unique identifier for the polymorphism, starting at 0; this is used instead of the\n\t\t\t\t\t\t\t\t\t\t\t\t// mutation's mutation_id_ because it compresses the range, allowing smaller output files\n\tconst Mutation *mutation_ptr_;\t\t\t\t// the mutation represented\n\tslim_refcount_t prevalence_;\t\t\t\t// prevalence\n\t\n\tPolymorphism(void) = delete;\t\t\t\t// no null construction\n\tPolymorphism(slim_polymorphismid_t p_polymorphism_id, const Mutation *p_mutation_ptr, slim_refcount_t p_prevalence);\n\t\n\tvoid Print_ID_Tag(std::ostream &p_out) const;\t\t\t// includes polymorphism_id_ and tag\n\tvoid Print_ID(std::ostream &p_out) const;\t\t\t// includes polymorphism_id_ at the beginning\n\tvoid Print_NoID_Tag(std::ostream &p_out) const;\t// does not include polymorphism_id_, but includes tag\n\tvoid Print_NoID(std::ostream &p_out) const;\t// does not include polymorphism_id_\n\t\n\tfriend bool operator<(const Polymorphism& p_l, const Polymorphism& p_r)\n\t{\n\t\treturn p_l.mutation_ptr_->position_ < p_r.mutation_ptr_->position_; // keep the same order\n\t}\n};\n\n\n// find p_mutation in p_polymorphisms and return its polymorphism_id_\nslim_polymorphismid_t FindMutationInPolymorphismMap(const PolymorphismMap &p_polymorphisms, const Mutation *p_mutation);\n\n// if mutation p_mutation is present in p_polymorphisms increase its prevalence, otherwise add it\nvoid AddMutationToPolymorphismMap(PolymorphismMap *p_polymorphisms, const Mutation *p_mutation);\n\n\n#endif /* defined(__SLiM__polymorphism__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/population.cpp",
    "content": "//\n//  population.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"population.h\"\n\n#include <fstream>\n#include <iomanip>\n#include <algorithm>\n#include <cmath>\n#include <utility>\n#include <unordered_map>\n#include <ctime>\n\n#include \"community.h\"\n#include \"species.h\"\n#include \"slim_globals.h\"\n#include \"eidos_script.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_symbol_table.h\"\n#include \"polymorphism.h\"\n#include \"subpopulation.h\"\n#include \"interaction_type.h\"\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_map>\n#endif\n\n\n// the initial capacities for the haplosome and individual pools here are just guesses at balancing low default memory usage, maximizing locality, and minimization of additional allocs\nPopulation::Population(Species &p_species) : model_type_(p_species.model_type_), community_(p_species.community_), species_(p_species), species_haplosome_pool_(p_species.species_haplosome_pool_), species_individual_pool_(p_species.species_individual_pool_)\n{\n}\n\nPopulation::~Population(void)\n{\n\tRemoveAllSubpopulationInfo();\n\t\n#ifdef SLIMGUI\n\t// release malloced storage for SLiMgui statistics collection\n\tfor (auto history_record_iter : fitness_histories_)\n\t{\n\t\tFitnessHistory &history_record = history_record_iter.second;\n\t\t\n\t\tif (history_record.history_)\n\t\t{\n\t\t\tfree(history_record.history_);\n\t\t\thistory_record.history_ = nullptr;\n\t\t\thistory_record.history_length_ = 0;\n\t\t}\n\t}\n    \n    for (auto history_record_iter : subpop_size_histories_)\n\t{\n\t\tSubpopSizeHistory &history_record = history_record_iter.second;\n\t\t\n\t\tif (history_record.history_)\n\t\t{\n\t\t\tfree(history_record.history_);\n\t\t\thistory_record.history_ = nullptr;\n\t\t\thistory_record.history_length_ = 0;\n\t\t}\n\t}\n#endif\n\t\n\t// dispose of any freed subpops\n\tPurgeRemovedSubpopulations();\n\t\n\t// dispose of individuals within our junkyard\n\tfor (Individual *individual : species_individuals_junkyard_)\n\t{\n\t\tindividual->~Individual();\n\t\tspecies_individual_pool_.DisposeChunk(const_cast<Individual *>(individual));\n\t}\n\tspecies_individuals_junkyard_.clear();\n}\n\nvoid Population::RemoveAllSubpopulationInfo(void)\n{\n    // BEWARE: do not access sim_ in this method!  This is called from\n    // Population::~Population(), at which point sim_ no longer exists!\n    \n\t// Free all subpopulations and then clear out our subpopulation list\n\tfor (auto subpopulation : subpops_)\n\t\tdelete subpopulation.second;\n\t\n\tsubpops_.clear();\n\t\n\t// Free all substitutions and clear out the substitution vector\n\tfor (auto substitution : substitutions_)\n\t\tsubstitution->Release();\n\t\n\tsubstitutions_.resize(0);\n\ttreeseq_substitutions_map_.clear();\n\t\n\t// The malloced storage of the mutation registry will be freed when it is destroyed, but it\n\t// does not know that the Mutation pointers inside it are owned, so we need to release them.\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint registry_size;\n\tconst MutationIndex *registry_iter = MutationRegistry(&registry_size);\n\tconst MutationIndex *registry_iter_end = registry_iter + registry_size;\n\t\n\tfor (; registry_iter != registry_iter_end; ++registry_iter)\n\t\t(mut_block_ptr + *registry_iter)->Release();\n\t\n\tmutation_registry_.clear();\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t// If we're keeping any separate registries inside mutation types, clear those now as well\n    // NOTE: The access of sim_ here is permissible because it will not happen after sim_ has been\n    // destructed, due to the clearing of keeping_muttype_registries_ at the end of this block.\n    // This block will execute when this method is called directly by Species::~Species(), and\n    // then it will not execute again when this method is called by Population::~Population().\n    // This design could probably stand to get cleaned up.  FIXME\n\tif (keeping_muttype_registries_)\n\t{\n\t\tfor (auto muttype_iter : species_.MutationTypes())\n\t\t{\n\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\n\t\t\tif (muttype->keeping_muttype_registry_)\n\t\t\t{\n\t\t\t\tmuttype->muttype_registry_.clear();\n\t\t\t\tmuttype->keeping_muttype_registry_ = false;\n\t\t\t}\n\t\t}\n\t\t\n\t\tkeeping_muttype_registries_ = false;\n\t}\n#endif\n\t\n#ifdef SLIMGUI\n\t// release malloced storage for SLiMgui statistics collection\n\tif (mutation_loss_times_)\n\t{\n\t\tfree(mutation_loss_times_);\n\t\tmutation_loss_times_ = nullptr;\n\t\tmutation_loss_tick_slots_ = 0;\n\t}\n\tif (mutation_fixation_times_)\n\t{\n\t\tfree(mutation_fixation_times_);\n\t\tmutation_fixation_times_ = nullptr;\n\t\tmutation_fixation_tick_slots_ = 0;\n\t}\n\t// Don't throw away the fitness history; it is perfectly valid even if the population has just been changed completely.  It happened.\n\t// If the read is followed by setting the cycle backward, individual fitness history entries will be invalidated in response.\n//\tif (fitness_history_)\n//\t{\n//\t\tfree(fitness_history_);\n//\t\tfitness_history_ = nullptr;\n//\t\tfitness_history_length_ = 0;\n//\t}\n#endif\n}\n\n// add new empty subpopulation p_subpop_id of size p_subpop_size\nSubpopulation *Population::AddSubpopulation(slim_objectid_t p_subpop_id, slim_popsize_t p_subpop_size, double p_initial_sex_ratio, bool p_haploid) \n{ \n\tif (community_.SubpopulationIDInUse(p_subpop_id))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulation): subpopulation p\" << p_subpop_id << \" has been used already, and cannot be used again (to prevent conflicts).\" << EidosTerminate();\n\tif ((p_subpop_size < 1) && (model_type_ == SLiMModelType::kModelTypeWF))\t// allowed in nonWF models\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulation): subpopulation p\" << p_subpop_id << \" empty.\" << EidosTerminate();\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulation): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n\t// make and add the new subpopulation\n\tSubpopulation *new_subpop = nullptr;\n\t\n\tif (species_.SexEnabled())\n\t\tnew_subpop = new Subpopulation(*this, p_subpop_id, p_subpop_size, true, p_initial_sex_ratio, p_haploid);\t// SEX ONLY\n\telse\n\t\tnew_subpop = new Subpopulation(*this, p_subpop_id, p_subpop_size, true, p_haploid);\n\t\n#ifdef SLIMGUI\n\t// When running under SLiMgui, we need to decide whether this subpopulation comes in selected or not.  We can't defer that\n\t// to SLiMgui's next update, because then mutation tallies are not kept properly up to date, resulting in a bad GUI refresh.\n\t// The rule is: if all currently existing subpops are selected, then the new subpop comes in selected as well.\n    bool gui_all_selected = true;\n    \n    for (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n        if (!subpop_pair.second->gui_selected_)\n        {\n            gui_all_selected = false;\n            break;\n        }\n    \n    new_subpop->gui_selected_ = gui_all_selected;\n#endif\n\t\n\tsubpops_.emplace(p_subpop_id, new_subpop);\n\tspecies_.used_subpop_ids_.emplace(p_subpop_id, new_subpop->name_);\n\t\n\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\tInvalidateMutationReferencesCache();\n\t\n\treturn new_subpop;\n}\n\n// WF only:\n// add new subpopulation p_subpop_id of size p_subpop_size individuals drawn from source subpopulation p_source_subpop_id\nSubpopulation *Population::AddSubpopulationSplit(slim_objectid_t p_subpop_id, Subpopulation &p_source_subpop, slim_popsize_t p_subpop_size, double p_initial_sex_ratio)\n{\n\tif (community_.SubpopulationIDInUse(p_subpop_id))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulationSplit): subpopulation p\" << p_subpop_id << \" has been used already, and cannot be used again (to prevent conflicts).\" << EidosTerminate();\n\tif (p_subpop_size < 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulationSplit): subpopulation p\" << p_subpop_id << \" empty.\" << EidosTerminate();\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AddSubpopulationSplit): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n\t// make and add the new subpopulation; note that we tell Subpopulation::Subpopulation() not to record tree-seq information\n\tSubpopulation *new_subpop = nullptr;\n \n\tif (species_.SexEnabled())\n\t\tnew_subpop = new Subpopulation(*this, p_subpop_id, p_subpop_size, false, p_initial_sex_ratio, false);\t// SEX ONLY\n\telse\n\t\tnew_subpop = new Subpopulation(*this, p_subpop_id, p_subpop_size, false, false);\n\t\n#ifdef SLIMGUI\n\t// When running under SLiMgui, we need to decide whether this subpopulation comes in selected or not.  We can't defer that\n\t// to SLiMgui's next update, because then mutation tallies are not kept properly up to date, resulting in a bad GUI refresh.\n\t// The rule is: if all currently existing subpops are selected, then the new subpop comes in selected as well.\n    bool gui_all_selected = true;\n    \n    for (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n        if (!subpop_pair.second->gui_selected_)\n        {\n            gui_all_selected = false;\n            break;\n        }\n    \n    new_subpop->gui_selected_ = gui_all_selected;\n#endif\n\t\n\tsubpops_.emplace(p_subpop_id, new_subpop);\n\tspecies_.used_subpop_ids_.emplace(p_subpop_id, new_subpop->name_);\n\t\n\t// then draw parents from the source population according to fitness, obeying the new subpop's sex ratio\n\tSubpopulation &subpop = *new_subpop;\n\tbool recording_tree_sequence = species_.RecordingTreeSequence();\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (recording_tree_sequence)\n\t{\n\t\t// OK, so, this is gross.  The user can call addSubpopSplit(), and the new individuals created as a side effect need to\n\t\t// arrive in the tree-seq tables stamped with a later time than their parents, but as far as SLiM is concerned they\n\t\t// were created at the same time as the parents; they exist at the same point in time, and it's WF, therefore they\n\t\t// were created at the same time, Q.E.D.  So to get the tree-seq code not to object, we add a small offset to the\n\t\t// tick counter.  Since addSubpopSplit() could be called multiple times in sequence, splitting a new subpop off\n\t\t// from each previous one in a linear fashion, each call to addSubpopSplit() needs to increase this offset slightly.\n\t\t// The offset is reset to zero each time the tree sequence's tick counter advances.  This is similar to the timing\n\t\t// problem that made us create tree_seq_tick_ in the first place, due to children arriving in the same SLiM tick as\n\t\t// their parents, but at least that only happens once per tick in a predictable fashion.\n\t\tspecies_.AboutToSplitSubpop();\n\t}\n\t\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\n\tfor (slim_popsize_t parent_index = 0; parent_index < subpop.parent_subpop_size_; parent_index++)\n\t{\n\t\t// draw individual from p_source_subpop and assign to be a parent in subpop\n\t\t// BCH 4/25/2018: we have to tree-seq record the new individuals and haplosomes here, with the correct parent information\n\t\t// Peter observes that biologically, it might make sense for each new haplosome in the split subpop to actually be a\n\t\t// clone of the original haplosome in the sense that it has the same parent as the original haplosomes, with the same\n\t\t// recombination breakpoints, etc.  But that would be quite hard to implement, especially since the parent in question\n\t\t// might have been simplified away already, and that script could have modified the original, and so forth.  Having\n\t\t// the new haplosome just inherit exactly from the original seems reasonable enough; for practical purposes it shouldn't\n\t\t// matter.\n\t\tslim_popsize_t migrant_index;\n\t\t\n\t\tif (species_.SexEnabled())\n\t\t{\n\t\t\tif (parent_index < subpop.parent_first_male_index_)\n\t\t\t\tmigrant_index = p_source_subpop.DrawFemaleParentUsingFitness(rng_state);\n\t\t\telse\n\t\t\t\tmigrant_index = p_source_subpop.DrawMaleParentUsingFitness(rng_state);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmigrant_index = p_source_subpop.DrawParentUsingFitness(rng_state);\n\t\t}\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (recording_tree_sequence)\n\t\t\tspecies_.SetCurrentNewIndividual(subpop.parent_individuals_[parent_index]);\n\t\t\n\t\tHaplosome **source_individual_haplosomes = p_source_subpop.parent_individuals_[migrant_index]->haplosomes_;\n\t\tHaplosome **dest_individual_haplosomes = subpop.parent_individuals_[parent_index]->haplosomes_;\n\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *source_haplosome = source_individual_haplosomes[haplosome_index];\n\t\t\tHaplosome *dest_haplosome = dest_individual_haplosomes[haplosome_index];\n\t\t\t\n\t\t\tdest_haplosome->copy_from_haplosome(*source_haplosome);\t// transmogrifies to null if needed\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (source_haplosome->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(dest_haplosome);\n\t\t\t\telse\n\t\t\t\t\tspecies_.RecordNewHaplosome(nullptr, 0, dest_haplosome, source_haplosome, nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\tInvalidateMutationReferencesCache();\n\t\n\t// UpdateFitness() is not called here - all fitnesses are kept as equal.  This is because the parents were drawn from the source subpopulation according\n\t// to their fitness already; fitness has already been applied.  If UpdateFitness() were called, fitness would be double-applied in this cycle.\n\t\n\treturn new_subpop;\n}\n\n// WF only:\n// set size of subpopulation p_subpop_id to p_subpop_size\nvoid Population::SetSize(Subpopulation &p_subpop, slim_popsize_t p_subpop_size)\n{\n\t// SetSize() can only be called when the child generation has not yet been generated.  It sets the size on the child generation,\n\t// and then that size takes effect when the children are generated from the parents in EvolveSubpopulation().\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::SetSize): called when the child generation was valid.\" << EidosTerminate();\n\t\n\tif (p_subpop_size == 0) // remove subpopulation p_subpop_id\n\t{\n\t\tslim_objectid_t subpop_id = p_subpop.subpopulation_id_;\n\t\t\n\t\t// only remove if we have not already removed\n\t\tif (subpops_.count(subpop_id))\n\t\t{\n\t\t\t// Note that we don't free the subpopulation here, because there may be live references to it; instead we keep it to the end of the cycle and then free it\n\t\t\t// First we remove the symbol for the subpop\n\t\t\tcommunity_.SymbolTable().RemoveConstantForSymbol(p_subpop.SymbolTableEntry().first);\n\t\t\t\n\t\t\t// Then we immediately remove the subpop from our list of subpops\n\t\t\tsubpops_.erase(subpop_id);\n\t\t\t\n\t\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\t\tsubpop_pair.second->migrant_fractions_.erase(subpop_id);\n\t\t\t\n\t\t\t// remember the subpop for later disposal\n\t\t\tremoved_subpops_.emplace_back(&p_subpop);\n\t\t\t\n\t\t\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\t\t\tInvalidateMutationReferencesCache();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// After we change the subpop size, we need to generate new children haplosomes to fit the new requirements\n\t\tp_subpop.child_subpop_size_ = p_subpop_size;\n\t\tp_subpop.GenerateChildrenToFitWF();\n\t}\n}\n\n// nonWF only:\n// remove subpopulation p_subpop_id from the model entirely\nvoid Population::RemoveSubpopulation(Subpopulation &p_subpop)\n{\n\tslim_objectid_t subpop_id = p_subpop.subpopulation_id_;\n\t\n\t// only remove if we have not already removed\n\tif (subpops_.count(subpop_id))\n\t{\n\t\t// Note that we don't free the subpopulation here, because there may be live references to it; instead we keep it to the end of the cycle and then free it\n\t\tcommunity_.InvalidateInteractionsForSubpopulation(&p_subpop);\n\t\t\n\t\t// First we remove the symbol for the subpop\n\t\tcommunity_.SymbolTable().RemoveConstantForSymbol(p_subpop.SymbolTableEntry().first);\n\t\t\n\t\t// Then we immediately remove the subpop from our list of subpops\n\t\tsubpops_.erase(subpop_id);\n\t\t\n\t\t// remember the subpop for later disposal\n\t\tremoved_subpops_.emplace_back(&p_subpop);\n\t\t\n\t\t// and let it know that it is invalid\n\t\tp_subpop.has_been_removed_ = true;\n\t\t\n\t\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\t\tInvalidateMutationReferencesCache();\n\t}\n}\n\n// nonWF only:\n// move individuals as requested by survival() callbacks\nvoid Population::ResolveSurvivalPhaseMovement(void)\n{\n\t// So, we have a survival() callback that has requested that some individuals move during the viability/survival phase.\n\t// We want to handle this as efficiently as we can; we could have many individuals moving between subpops in arbitrary\n\t// ways.  We will remove all moving individuals from their current subpops in a single pass, and then add them to their\n\t// new subpops in a single pass.  If just one individual is moving, this will be inefficient since the algorithm is O(N)\n\t// in the number of individuals, but I think it makes sense to optimize for the many-moving case for now.\n\tbool sex_enabled = species_.SexEnabled();\n\t\n\t// mark all individuals in all subpops as not-moving\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\tfor (Individual *individual : (subpop_pair.second)->parent_individuals_)\n\t\t\tindividual->scratch_ = 0;\n\t\n\t// mark moving individuals in all subpops as moving\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\tfor (Individual *individual : (subpop_pair.second)->nonWF_survival_moved_individuals_)\n\t\t\tindividual->scratch_ = 1;\n\t\n\t// loop through subpops and remove all individuals that are leaving, compacting downwards; similar to Subpopulation::ViabilitySurvival()\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{ \n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\tIndividual **individual_data = subpop->parent_individuals_.data();\n\t\tint remaining_individual_index = 0;\n\t\tint females_leaving = 0;\n\t\tbool individuals_leaving = false;\n\t\t\n\t\tfor (int individual_index = 0; individual_index < subpop->parent_subpop_size_; ++individual_index)\n\t\t{\n\t\t\tIndividual *individual = individual_data[individual_index];\n\t\t\tbool remaining = (individual->scratch_ == 0);\n\t\t\t\n\t\t\tif (remaining)\n\t\t\t{\n\t\t\t\t// individuals that remain get copied down to the next available slot\n\t\t\t\tif (remaining_individual_index != individual_index)\n\t\t\t\t{\n\t\t\t\t\tindividual_data[remaining_individual_index] = individual;\n\t\t\t\t\t\n\t\t\t\t\t// fix the individual's index_\n\t\t\t\t\tindividual_data[remaining_individual_index]->index_ = remaining_individual_index;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tremaining_individual_index++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// individuals that do not remain get tallied and removed at the end\n\t\t\t\tif (sex_enabled && (individual->sex_ == IndividualSex::kFemale))\n\t\t\t\t\tfemales_leaving++;\n\t\t\t\t\n\t\t\t\tindividuals_leaving = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Then fix our bookkeeping for the first male index, subpop size, caches, etc.\n\t\tif (individuals_leaving)\n\t\t{\n\t\t\tsubpop->parent_subpop_size_ = remaining_individual_index;\n\t\t\t\n\t\t\tif (sex_enabled)\n\t\t\t\tsubpop->parent_first_male_index_ -= females_leaving;\n\t\t\t\n\t\t\tsubpop->parent_individuals_.resize(subpop->parent_subpop_size_);\n\t\t\t\n\t\t\tsubpop->cached_parent_individuals_value_.reset();\n\t\t}\n\t}\n\t\n\t// loop through subpops and append individuals that are arriving; we do this using Subpopulation::MergeReproductionOffspring()\n\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{ \n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\n\t\tsubpop->nonWF_offspring_individuals_.swap(subpop->nonWF_survival_moved_individuals_);\n\t\t\n\t\tfor (Individual *individual : subpop->nonWF_offspring_individuals_)\n\t\t{\n#if defined(SLIMGUI)\n\t\t\t// tally this as an incoming migrant for SLiMgui\n\t\t\t++subpop->gui_migrants_[individual->subpopulation_->subpopulation_id_];\n#endif\n\t\t\t\n\t\t\t// has_null_haplosomes_ needs to reflect the presence of null haplosomes\n\t\t\tif (!subpop->has_null_haplosomes_ && individual->subpopulation_->has_null_haplosomes_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = individual->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tsubpop->has_null_haplosomes_ = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tindividual->subpopulation_ = subpop;\n\t\t\tindividual->migrant_ = true;\n\t\t}\n\t\t\n\t\tsubpop->MergeReproductionOffspring();\n\t}\n\t\n\t// Invalidate interactions; we just do this for all subpops, for now, rather than trying to\n\t// selectively invalidate only the subpops involved in the migrations that occurred\n\tcommunity_.InvalidateInteractionsForSpecies(&species_);\n}\n\nvoid Population::PurgeRemovedSubpopulations(void)\n{\n\tif (removed_subpops_.size())\n\t{\n\t\tfor (auto removed_subpop : removed_subpops_)\n\t\t\tdelete removed_subpop;\n\t\t\n\t\tremoved_subpops_.resize(0);\n\t}\n}\n\n#if DEFER_BROKEN\n// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n// and needs to be remade anew once things have settled down.\nvoid Population::CheckForDeferralInHaplosomesVector(Haplosome **p_haplosomes, size_t p_elements_size, const std::string &p_caller)\n{\n\tif (HasDeferredHaplosomes())\n\t{\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t{\n\t\t\tHaplosome *haplosome = p_haplosomes[element_index];\n\t\t\t\n\t\t\tif (haplosome->IsDeferred())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller << \"): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid Population::CheckForDeferralInHaplosomes(EidosValue_Object *p_haplosomes, const std::string &p_caller)\n{\n\tif (HasDeferredHaplosomes())\n\t{\n\t\tint element_count = p_haplosomes->Count();\n\t\tEidosObject * const *haplosomes_data = p_haplosomes->ObjectData();\n\t\t\n\t\tfor (int element_index = 0; element_index < element_count; ++element_index)\n\t\t{\n\t\t\tHaplosome *haplosome = (Haplosome *)haplosomes_data[element_index];\n\t\t\t\n\t\t\tif (haplosome->IsDeferred())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller << \"): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid Population::CheckForDeferralInIndividualsVector(Individual * const *p_individuals, size_t p_elements_size, const std::string &p_caller)\n{\n\tif (HasDeferredHaplosomes())\n\t{\n\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t{\n\t\t\tIndividual *ind = p_individuals[element_index];\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (haplosome->IsDeferred())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller << \"): the mutations of deferred haplosomes cannot be accessed.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n}\n#endif\n\n// nonWF only:\n#if DEFER_BROKEN\n// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n// and needs to be remade anew once things have settled down.\n// This method uses the old reproduction methods, which have been removed from the code base; it needs a complete rework\nvoid Population::DoDeferredReproduction(void)\n{\n\tsize_t deferred_count_nonrecombinant = deferred_reproduction_nonrecombinant_.size();\n\tsize_t deferred_count_recombinant = deferred_reproduction_recombinant_.size();\n\tsize_t deferred_count_total = deferred_count_nonrecombinant + deferred_count_recombinant;\n\t\n\tif (deferred_count_total == 0)\n\t\treturn;\n\t\n\t// before going parallel, we need to ensure that we have enough capacity in the\n\t// mutation block; we can't expand it while parallel, due to race conditions\n\t// see Population::EvolveSubpopulation() for the equivalent WF code\n#ifdef _OPENMP\n\tdo {\n\t\tint registry_size;\n\t\tMutationRegistry(&registry_size);\n\t\tsize_t est_mutation_block_slots_remaining_PRE = gSLiM_Mutation_Block_Capacity - registry_size;\n\t\tdouble overall_mutation_rate = std::max(species_.chromosome_->overall_mutation_rate_F_, species_.chromosome_->overall_mutation_rate_M_);\t// already multiplied by L\n\t\tsize_t est_slots_needed = (size_t)ceil(2 * deferred_count_total * overall_mutation_rate);\t// 2 because diploid, in the worst case\n\t\t\n\t\tsize_t ten_times_demand = 10 * est_slots_needed;\n\t\t\n\t\tif (est_mutation_block_slots_remaining_PRE <= ten_times_demand)\n\t\t{\n\t\t\tSLiM_IncreaseMutationBlockCapacity();\n\t\t\test_mutation_block_slots_remaining_PRE = gSLiM_Mutation_Block_Capacity - registry_size;\n\t\t\t\n\t\t\t//std::cerr << \"Tick \" << community_.Tick() << \": DOUBLED CAPACITY ***********************************\" << std::endl;\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t} while (true);\n#endif\n\t\n\t// now generate the haplosomes of the deferred offspring in parallel\n\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_DEFERRED_REPRO);\n\t\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_DEFERRED_REPRO);\n#pragma omp parallel for schedule(dynamic, 1) default(none) shared(deferred_count_nonrecombinant) if(deferred_count_nonrecombinant >= EIDOS_OMPMIN_DEFERRED_REPRO) num_threads(thread_count)\n\tfor (size_t deferred_index = 0; deferred_index < deferred_count_nonrecombinant; ++deferred_index)\n\t{\n\t\tSLiM_DeferredReproduction_NonRecombinant &deferred_rec = deferred_reproduction_nonrecombinant_[deferred_index];\n\t\t\n\t\tif ((deferred_rec.type_ == SLiM_DeferredReproductionType::kCrossoverMutation) || (deferred_rec.type_ == SLiM_DeferredReproductionType::kSelfed))\n\t\t{\n\t\t\tDoCrossoverMutation(deferred_rec.parent1_->subpopulation_, *deferred_rec.child_haplosome_1_, deferred_rec.parent1_->index_, deferred_rec.child_sex_, deferred_rec.parent1_->sex_, nullptr, nullptr);\n\t\t\t\n\t\t\tDoCrossoverMutation(deferred_rec.parent2_->subpopulation_, *deferred_rec.child_haplosome_2_, deferred_rec.parent2_->index_, deferred_rec.child_sex_, deferred_rec.parent2_->sex_, nullptr, nullptr);\n\t\t}\n\t\telse if (deferred_rec.type_ == SLiM_DeferredReproductionType::kClonal)\n\t\t{\n#warning the use of haplosomes_[0] and haplosomes_[1] here needs to be updated for multichrom\n\t\t\tDoClonalMutation(deferred_rec.parent1_->subpopulation_, *deferred_rec.child_haplosome_1_, *deferred_rec.parent1_->haplosomes_[0], deferred_rec.child_sex_, nullptr);\n\t\t\t\n\t\t\tDoClonalMutation(deferred_rec.parent1_->subpopulation_, *deferred_rec.child_haplosome_2_, *deferred_rec.parent1_->haplosomes_[1], deferred_rec.child_sex_, nullptr);\n\t\t}\n\t}\n\t\n\t//EIDOS_THREAD_COUNT(gEidos_OMP_threads_DEFERRED_REPRO);\t// this loop shares the same key\n#pragma omp parallel for schedule(dynamic, 1) default(none) shared(deferred_count_recombinant) if(deferred_count_recombinant >= EIDOS_OMPMIN_DEFERRED_REPRO) num_threads(thread_count)\n\tfor (size_t deferred_index = 0; deferred_index < deferred_count_recombinant; ++deferred_index)\n\t{\n\t\tSLiM_DeferredReproduction_Recombinant &deferred_rec = deferred_reproduction_recombinant_[deferred_index];\n\t\t\n\t\tif (deferred_rec.strand2_ == nullptr)\n\t\t{\n\t\t\tDoClonalMutation(deferred_rec.mutorigin_subpop_, *deferred_rec.child_haplosome_, *deferred_rec.strand1_, deferred_rec.sex_, nullptr);\n\t\t}\n\t\telse if (deferred_rec.type_ == SLiM_DeferredReproductionType::kRecombinant)\n\t\t{\n\t\t\tDoRecombinantMutation(deferred_rec.mutorigin_subpop_, *deferred_rec.child_haplosome_, deferred_rec.strand1_, deferred_rec.strand2_, deferred_rec.sex_, deferred_rec.break_vec_, nullptr);\n\t\t}\n\t}\n\t\n\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_DEFERRED_REPRO);\n\t\n\t// Clear the deferred reproduction queue\n\tdeferred_reproduction_nonrecombinant_.resize(0);\n\tdeferred_reproduction_recombinant_.resize(0);\n}\n#endif\n\n// WF only:\n// set fraction p_migrant_fraction of p_subpop_id that originates as migrants from p_source_subpop_id per cycle  \nvoid Population::SetMigration(Subpopulation &p_subpop, slim_objectid_t p_source_subpop_id, double p_migrant_fraction) \n{ \n\tif (subpops_.count(p_source_subpop_id) == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::SetMigration): no subpopulation p\" << p_source_subpop_id << \".\" << EidosTerminate();\n\tif ((p_migrant_fraction < 0.0) || (p_migrant_fraction > 1.0) || std::isnan(p_migrant_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::SetMigration): migration fraction has to be within [0,1] (\" << EidosStringForFloat(p_migrant_fraction) << \" supplied).\" << EidosTerminate();\n\t\n\tif (p_subpop.migrant_fractions_.count(p_source_subpop_id) != 0)\n\t\tp_subpop.migrant_fractions_.erase(p_source_subpop_id);\n\t\n\tif (p_migrant_fraction > 0.0)\t// BCH 4 March 2015: Added this if so we don't put a 0.0 migration rate into the table; harmless but looks bad in SLiMgui...\n\t\tp_subpop.migrant_fractions_.emplace(p_source_subpop_id, p_migrant_fraction); \n}\n\n// WF only:\n// apply mateChoice() callbacks to a mating event with a chosen first parent; the return is the second parent index, or -1 to force a redraw\nslim_popsize_t Population::ApplyMateChoiceCallbacks(slim_popsize_t p_parent1_index, Subpopulation *p_subpop, Subpopulation *p_source_subpop, std::vector<SLiMEidosBlock*> &p_mate_choice_callbacks)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyMateChoiceCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n\t\n\t// We start out using standard weights taken from the source subpopulation.  If, when we are done handling callbacks, we are still\n\t// using those standard weights, then we can do a draw using our fast lookup tables.  Otherwise, we will do a draw the hard way.\n\tbool sex_enabled = p_subpop->sex_enabled_;\n\tdouble *standard_weights = (sex_enabled ? p_source_subpop->cached_male_fitness_ : p_source_subpop->cached_parental_fitness_);\n\tdouble *current_weights = standard_weights;\n\tslim_popsize_t weights_length = p_source_subpop->cached_fitness_size_;\n\tbool weights_modified = false;\n\tIndividual *chosen_mate = nullptr;\t\t\t// callbacks can return an Individual instead of a weights vector, held here\n\tbool weights_reflect_chosen_mate = false;\t// if T, a weights vector has been created with a 1 for the chosen mate, to pass to the next callback\n\tSLiMEidosBlock *last_interventionist_mate_choice_callback = nullptr;\n\t\n\tfor (SLiMEidosBlock *mate_choice_callback : p_mate_choice_callbacks)\n\t{\n\t\tif (mate_choice_callback->block_active_)\n\t\t{\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = mate_choice_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG mateChoice(\";\n\t\t\t\t\tif (mate_choice_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << mate_choice_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (mate_choice_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << mate_choice_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// local variables for the callback parameters that we might need to allocate here, and thus need to free below\n\t\t\tEidosValue_SP local_weights_ptr;\n\t\t\tbool redraw_mating = false;\n\t\t\t\n\t\t\tif (chosen_mate && !weights_reflect_chosen_mate && mate_choice_callback->contains_weights_)\n\t\t\t{\n\t\t\t\t// A previous callback said it wanted a specific individual to be the mate.  We now need to make a weights vector\n\t\t\t\t// to represent that, since we have another callback that wants an incoming weights vector.\n\t\t\t\tif (!weights_modified)\n\t\t\t\t{\n\t\t\t\t\tcurrent_weights = (double *)malloc(sizeof(double) * weights_length);\t// allocate a new weights vector\n\t\t\t\t\tif (!current_weights)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\tweights_modified = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_BZERO(current_weights, sizeof(double) * weights_length);\n\t\t\t\tcurrent_weights[chosen_mate->index_] = 1.0;\n\t\t\t\t\n\t\t\t\tweights_reflect_chosen_mate = true;\n\t\t\t}\n\t\t\t\n\t\t\t// The callback is active, so we need to execute it; we start a block here to manage the lifetime of the symbol table\n\t\t\t{\n\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\tEidosInterpreter interpreter(mate_choice_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t);\n\t\t\t\t\n\t\t\t\tif (mate_choice_callback->contains_self_)\n\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(mate_choice_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\n\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\tif (mate_choice_callback->contains_individual_)\n\t\t\t\t{\n\t\t\t\t\tIndividual *parent1 = p_source_subpop->parent_individuals_[p_parent1_index];\n\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, parent1->CachedEidosValue());\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (mate_choice_callback->contains_subpop_)\n\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, p_subpop->SymbolTableEntry().second);\n\t\t\t\t\n\t\t\t\tif (mate_choice_callback->contains_sourceSubpop_)\n\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_sourceSubpop, p_source_subpop->SymbolTableEntry().second);\n\t\t\t\t\n\t\t\t\tif (mate_choice_callback->contains_weights_)\n\t\t\t\t{\n\t\t\t\t\tlocal_weights_ptr = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(current_weights, weights_length));\n\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gEidosID_weights, local_weights_ptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t// Interpret the script; the result from the interpretation can be one of several things, so this is a bit complicated\n\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(mate_choice_callback->script_);\n\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\tEidosValueType result_type = result->Type();\n\t\t\t\t\t\n\t\t\t\t\tif (result_type == EidosValueType::kValueVOID)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): mateChoice() callbacks must explicitly return a value.\" << EidosTerminate(mate_choice_callback->identifier_token_);\n\t\t\t\t\telse if (result_type == EidosValueType::kValueNULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// NULL indicates that the mateChoice() callback did not wish to alter the weights, so we do nothing\n\t\t\t\t\t}\n\t\t\t\t\telse if (result_type == EidosValueType::kValueObject)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A singleton vector of type Individual may be returned to choose a specific mate\n\t\t\t\t\t\tif ((result->Count() == 1) && (((EidosValue_Object *)result)->Class() == gSLiM_Individual_Class))\n\t\t\t\t\t\t{\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tchosen_mate = (Individual *)result->ObjectData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tchosen_mate = (Individual *)((EidosValue_Object *)result)->data()[0];\n#endif\n\t\t\t\t\t\t\tweights_reflect_chosen_mate = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// remember this callback for error attribution below\n\t\t\t\t\t\t\tlast_interventionist_mate_choice_callback = mate_choice_callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): invalid return value for mateChoice() callback.\" << EidosTerminate(mate_choice_callback->identifier_token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (result_type == EidosValueType::kValueFloat)\n\t\t\t\t\t{\n\t\t\t\t\t\tint result_count = result->Count();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (result_count == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// a return of float(0) indicates that there is no acceptable mate for the first parent; the first parent must be redrawn\n\t\t\t\t\t\t\tredraw_mating = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (result_count == weights_length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// if we used to have a specific chosen mate, we don't any more\n\t\t\t\t\t\t\tchosen_mate = nullptr;\n\t\t\t\t\t\t\tweights_reflect_chosen_mate = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// a non-zero float vector must match the size of the source subpop, and provides a new set of weights for us to use\n\t\t\t\t\t\t\tif (!weights_modified)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcurrent_weights = (double *)malloc(sizeof(double) * weights_length);\t// allocate a new weights vector\n\t\t\t\t\t\t\t\tif (!current_weights)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\tweights_modified = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// use FloatData() to get the values, copy them with memcpy()\n\t\t\t\t\t\t\tmemcpy(current_weights, result->FloatData(), sizeof(double) * weights_length);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// remember this callback for error attribution below\n\t\t\t\t\t\t\tlast_interventionist_mate_choice_callback = mate_choice_callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): invalid return value for mateChoice() callback.\" << EidosTerminate(mate_choice_callback->identifier_token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): invalid return value for mateChoice() callback.\" << EidosTerminate(mate_choice_callback->identifier_token_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// If this callback told us not to generate the child, we do not call the rest of the callback chain; we're done\n\t\t\tif (redraw_mating)\n\t\t\t{\n\t\t\t\tif (weights_modified)\n\t\t\t\t\tfree(current_weights);\n\t\t\t\t\n\t\t\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t\t// PROFILING\n\t\t\t\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)]);\n#endif\n\t\t\t\t\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// If we have a specific chosen mate, then we don't need to draw, but we do need to check the sex of the proposed mate\n\tif (chosen_mate)\n\t{\n\t\tslim_popsize_t drawn_parent = chosen_mate->index_;\n\t\t\n\t\tif (weights_modified)\n\t\t\tfree(current_weights);\n\t\t\n\t\tif (sex_enabled)\n\t\t{\n\t\t\tif (drawn_parent < p_source_subpop->parent_first_male_index_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): second parent chosen by mateChoice() callback is female.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t}\n\t\t\n\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)]);\n#endif\n\t\t\n\t\treturn drawn_parent;\n\t}\n\t\n\t// If a callback supplied a different set of weights, we need to use those weights to draw a male parent\n\tif (weights_modified)\n\t{\n\t\tslim_popsize_t drawn_parent = -1;\n\t\tdouble weights_sum = 0;\n\t\tint positive_count = 0;\n\t\t\n\t\t// first we assess the weights vector: get its sum, bounds-check it, etc.\n\t\tfor (slim_popsize_t weight_index = 0; weight_index < weights_length; ++weight_index)\n\t\t{\n\t\t\tdouble x = current_weights[weight_index];\n\t\t\t\n\t\t\tif (!std::isfinite(x))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): weight returned by mateChoice() callback is not finite.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t\t\n\t\t\tif (x > 0.0)\n\t\t\t{\n\t\t\t\tpositive_count++;\n\t\t\t\tweights_sum += x;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (x < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): weight returned by mateChoice() callback is less than 0.0.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t}\n\t\t\n\t\tif (weights_sum <= 0.0)\n\t\t{\n\t\t\t// We used to consider this an error; now we consider it to represent the first parent having no acceptable choice, so we\n\t\t\t// re-draw.  Returning float(0) is essentially equivalent, except that it short-circuits the whole mateChoice() callback\n\t\t\t// chain, whereas returning a vector of 0 values can be modified by a downstream mateChoice() callback.  Usually that is\n\t\t\t// not an important distinction.  Returning float(0) is faster in principle, but if one is already constructing a vector\n\t\t\t// of weights that can simply end up being all zero, then this path is much easier.  BCH 5 March 2017\n\t\t\t//EIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): weights returned by mateChoice() callback sum to 0.0 or less.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t\tfree(current_weights);\n\t\t\t\n\t\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)]);\n#endif\n\t\t\t\n\t\t\treturn -1;\n\t\t}\n\t\t\n\t\t// then we draw from the weights vector\n\t\tif (positive_count == 1)\n\t\t{\n\t\t\t// there is only a single positive value, so the callback has chosen a parent for us; we just need to locate it\n\t\t\t// we could have noted it above, but I don't want to slow down that loop, since many positive weights is the likely case\n\t\t\tfor (slim_popsize_t weight_index = 0; weight_index < weights_length; ++weight_index)\n\t\t\t\tif (current_weights[weight_index] > 0.0)\n\t\t\t\t{\n\t\t\t\t\tdrawn_parent = weight_index;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (positive_count <= weights_length / 4)\t// the threshold here is a guess\n\t\t{\n\t\t\t// there are just a few positive values, so try to be faster about scanning for them by checking for zero first\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble the_rose_in_the_teeth = Eidos_rng_uniform_doubleOO(rng_64) * weights_sum;\n\t\t\tdouble bachelor_sum = 0.0;\n\t\t\t\n\t\t\tfor (slim_popsize_t weight_index = 0; weight_index < weights_length; ++weight_index)\n\t\t\t{\n\t\t\t\tdouble weight = current_weights[weight_index];\n\t\t\t\t\n\t\t\t\tif (weight > 0.0)\n\t\t\t\t{\n\t\t\t\t\tbachelor_sum += weight;\n\t\t\t\t\t\n\t\t\t\t\tif (the_rose_in_the_teeth <= bachelor_sum)\n\t\t\t\t\t{\n\t\t\t\t\t\tdrawn_parent = weight_index;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// there are many positive values, so we need to do a uniform draw and see who gets the rose\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble the_rose_in_the_teeth = Eidos_rng_uniform_doubleOO(rng_64) * weights_sum;\n\t\t\tdouble bachelor_sum = 0.0;\n\t\t\t\n\t\t\tfor (slim_popsize_t weight_index = 0; weight_index < weights_length; ++weight_index)\n\t\t\t{\n\t\t\t\tbachelor_sum += current_weights[weight_index];\n\t\t\t\t\n\t\t\t\tif (the_rose_in_the_teeth <= bachelor_sum)\n\t\t\t\t{\n\t\t\t\t\tdrawn_parent = weight_index;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// we should always have a chosen parent at this point\n\t\tif (drawn_parent == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): failed to choose a mate.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t\n\t\tfree(current_weights);\n\t\t\n\t\tif (sex_enabled)\n\t\t{\n\t\t\tif (drawn_parent < p_source_subpop->parent_first_male_index_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyMateChoiceCallbacks): second parent chosen by mateChoice() callback is female.\" << EidosTerminate(last_interventionist_mate_choice_callback->identifier_token_);\n\t\t}\n\t\t\n\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)]);\n#endif\n\t\t\n\t\treturn drawn_parent;\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMateChoiceCallback)]);\n#endif\n\t\n\t// The standard behavior, with no active callbacks, is to draw a male parent using the standard fitness values\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\n\treturn (sex_enabled ? p_source_subpop->DrawMaleParentUsingFitness(rng_state) : p_source_subpop->DrawParentUsingFitness(rng_state));\n}\n\n// apply modifyChild() callbacks to a generated child; a return of false means \"do not use this child, generate a new one\"\nbool Population::ApplyModifyChildCallbacks(Individual *p_child, Individual *p_parent1, Individual *p_parent2, bool p_is_selfing, bool p_is_cloning, Subpopulation *p_target_subpop, Subpopulation *p_source_subpop, std::vector<SLiMEidosBlock*> &p_modify_child_callbacks)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyModifyChildCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\t// note the focal child during the callback, so we can prevent illegal operations during the callback\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n\tcommunity_.focal_modification_child_ = p_child;\n\t\n\tfor (SLiMEidosBlock *modify_child_callback : p_modify_child_callbacks)\n\t{\n\t\tif (modify_child_callback->block_active_)\n\t\t{\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = modify_child_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG modifyChild(\";\n\t\t\t\t\tif (modify_child_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << modify_child_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (modify_child_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << modify_child_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// The callback is active, so we need to execute it\n\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\tEidosInterpreter interpreter(modify_child_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_self_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(modify_child_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\n\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\tif (modify_child_callback->contains_child_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_child, p_child->CachedEidosValue());\n\t\t\t\n\t\t\tif (modify_child_callback->contains_parent1_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_parent1, p_parent1 ? p_parent1->CachedEidosValue() : (EidosValue_SP)gStaticEidosValueNULL);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_isSelfing_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_isSelfing, p_is_selfing ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_isCloning_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_isCloning, p_is_cloning ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_parent2_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_parent2, p_parent2 ? p_parent2->CachedEidosValue() : (EidosValue_SP)gStaticEidosValueNULL);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_subpop_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, p_target_subpop->SymbolTableEntry().second);\n\t\t\t\n\t\t\tif (modify_child_callback->contains_sourceSubpop_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_sourceSubpop, p_source_subpop ? p_source_subpop->SymbolTableEntry().second : (EidosValue_SP)gStaticEidosValueNULL);\n\t\t\t\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton double used as a new fitness value\n\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(modify_child_callback->script_);\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tif ((result->Type() != EidosValueType::kValueLogical) || (result->Count() != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyModifyChildCallbacks): modifyChild() callbacks must provide a logical singleton return value.\" << EidosTerminate(modify_child_callback->identifier_token_);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// this checks the value type at runtime\n\t\t\t\teidos_logical_t generate_child = result->LogicalData()[0];\n#else\n\t\t\t\t// unsafe cast for speed\n\t\t\t\teidos_logical_t generate_child = ((EidosValue_Logical *)result)->data()[0];\n#endif\n\t\t\t\t\n\t\t\t\t// If this callback told us not to generate the child, we do not call the rest of the callback chain; we're done\n\t\t\t\tif (!generate_child)\n\t\t\t\t{\n\t\t\t\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\t\t\t\tcommunity_.focal_modification_child_ = nullptr;\n\t\t\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t\t\t// PROFILING\n\t\t\t\t\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosModifyChildCallback)]);\n#endif\n\t\t\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tthrow;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\tcommunity_.focal_modification_child_ = nullptr;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosModifyChildCallback)]);\n#endif\n\t\n\treturn true;\n}\n\n// WF only:\n// generate children for subpopulation p_subpop_id, drawing from all source populations, handling crossover and mutation\nvoid Population::EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice_callbacks_present, bool p_modify_child_callbacks_present, bool p_recombination_callbacks_present, bool p_mutation_callbacks_present, bool p_type_s_dfe_present)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::EvolveSubpopulation(): usage of statics, probably many other issues\");\n\t\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\tEidosRNG_32_bit &rng_32 = rng_state->pcg32_rng_;\n\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\tgsl_rng *rng_gsl = &rng_state->gsl_rng_;\t\t// for use outside of parallel blocks\n\t\n\t// determine the templated version of the Munge...() methods that we will call out to for reproduction\n\t// this is an optimization technique that lets us optimize away unused cruft at compile time\n\t// some relevant posts that were helpful in figuring out the correct syntax:\n\t// \thttp://goodliffe.blogspot.com/2011/07/c-declaring-pointer-to-template-method.html\n\t// \thttps://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file\n\t// \thttps://stackoverflow.com/questions/22275786/change-boolean-flags-into-template-arguments\n\t// and a Godbolt experiment I did to confirm that this really works: https://godbolt.org/z/Mva4Kbhrd\n\tbool pedigrees_enabled = species_.PedigreesEnabled();\n\tbool recording_tree_sequence = species_.RecordingTreeSequence();\n\tbool has_munge_callback = (p_modify_child_callbacks_present || p_recombination_callbacks_present || p_mutation_callbacks_present);\n\tbool is_spatial = (species_.SpatialDimensionality() >= 1);\n\tbool mutrun_exp_timing_per_individual = species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() > 1);\n\t\n\tbool (Subpopulation::*MungeIndividualCrossed_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\tbool (Subpopulation::*MungeIndividualSelfed_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\tbool (Subpopulation::*MungeIndividualCloned_TEMPLATED)(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\t\n\tif (mutrun_exp_timing_per_individual)\n\t{\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\t// has any of the callbacks that the Munge...() methods care about; this can be refined later\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, true, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, true, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, true, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, true, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, false, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, false, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, false, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, true, false, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, true, false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, true, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, true, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, true, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, true, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, true, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, false, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, false, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, false, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<true, false, false, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<true, false, false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<true, false, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, true, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, true, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, true, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, true, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, false, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, false, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, false, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, true, false, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, true, false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, true, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, true, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, true, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, true, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, true, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_munge_callback)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, false, true, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, false, true, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, false, false, true>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed<false, false, false, false, false>;\n\t\t\t\t\t\tMungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed<false, false, false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned<false, false, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// refine the above choice with a custom version of optimizations for simple \"A\" and \"H\" cases\n\tif (!mutrun_exp_timing_per_individual && !has_munge_callback && (species_.Chromosomes().size() == 1))\n\t{\n\t\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t\n\t\tif (chromosome_type == ChromosomeType::kA_DiploidAutosome)\n\t\t{\n\t\t\tif (pedigrees_enabled)\n\t\t\t{\n\t\t\t\tif (recording_tree_sequence)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<true, true, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<true, true, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<true, false, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<true, false, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (recording_tree_sequence)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<false, true, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<false, true, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<false, false, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_A<false, false, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_A<false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_A<false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (chromosome_type == ChromosomeType::kH_HaploidAutosome)\n\t\t{\n\t\t\tif (pedigrees_enabled)\n\t\t\t{\n\t\t\t\tif (recording_tree_sequence)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<true, true, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<true, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<true, true, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<true, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<true, false, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<true, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<true, false, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<true, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (recording_tree_sequence)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<false, true, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<false, true, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<false, true, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<false, true, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<false, false, true>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<false, false, true>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tMungeIndividualCrossed_TEMPLATED = &Subpopulation::MungeIndividualCrossed_1CH_H<false, false, false>;\n\t\t\t\t\t\t//MungeIndividualSelfed_TEMPLATED = &Subpopulation::MungeIndividualSelfed_1CH_H<false, false, false>;\n\t\t\t\t\t\tMungeIndividualCloned_TEMPLATED = &Subpopulation::MungeIndividualCloned_1CH_H<false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tbool prevent_incidental_selfing = species_.PreventIncidentalSelfing();\n\tbool sex_enabled = p_subpop.sex_enabled_;\n\tslim_popsize_t total_children = p_subpop.child_subpop_size_;\n\t\n\t// set up to draw migrants; this works the same in the sex and asex cases, and for males / females / hermaphrodites\n\t// the way the code is now structured, \"migrant\" really includes everybody; we are a migrant source subpop for ourselves\n\tint migrant_source_count = static_cast<int>(p_subpop.migrant_fractions_.size());\n\tdouble migration_rates[migrant_source_count + 1];\n\tSubpopulation *migration_sources[migrant_source_count + 1];\n\tunsigned int num_migrants[migrant_source_count + 1];\t\t\t// used by client code below; type constrained by gsl_ran_multinomial()\n\t\n\tif (migrant_source_count > 0)\n\t{\n\t\tdouble migration_rate_sum = 0.0;\n\t\tint pop_count = 0;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,double> &fractions_pair : p_subpop.migrant_fractions_)\n\t\t{\n\t\t\tslim_objectid_t migrant_source_id = fractions_pair.first;\n            Subpopulation *migrant_source = species_.SubpopulationWithID(migrant_source_id);\n\t\t\t\n\t\t\tif (!migrant_source)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): no migrant source subpopulation p\" << migrant_source_id << \".\" << EidosTerminate();\n\t\t\t\n\t\t\tmigration_rates[pop_count] = fractions_pair.second;\n\t\t\tmigration_sources[pop_count] = migrant_source;\n\t\t\tmigration_rate_sum += fractions_pair.second;\n\t\t\tpop_count++;\n\t\t}\n\t\t\n\t\tif (migration_rate_sum <= 1.0)\n\t\t{\n\t\t\t// the remaining fraction is within-subpopulation mating\n\t\t\tmigration_rates[pop_count] = 1.0 - migration_rate_sum;\n\t\t\tmigration_sources[pop_count] = &p_subpop;\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): too many migrants in subpopulation p\" << p_subpop.subpopulation_id_ << \"; migration fractions must sum to <= 1.0.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\tmigration_rates[0] = 1.0;\n\t\tmigration_sources[0] = &p_subpop;\n\t}\n\t\n\t// SEX ONLY: the sex and asex cases share code but work a bit differently; the sex cases generates females and then males in\n\t// separate passes, and selfing is disabled in the sex case.  This block sets up for the sex case to diverge in these ways.\n\tslim_popsize_t total_female_children = 0, total_male_children = 0;\n\tint number_of_sexes = 1;\n\t\n\tif (sex_enabled)\n\t{\n\t\tdouble sex_ratio = p_subpop.child_sex_ratio_;\n\t\t\n\t\ttotal_male_children = static_cast<slim_popsize_t>(lround(total_children * sex_ratio));\t\t// sex ratio is defined as proportion male; round in favor of males, arbitrarily\n\t\ttotal_female_children = total_children - total_male_children;\n\t\tnumber_of_sexes = 2;\n\t\t\n\t\tif (total_male_children <= 0 || total_female_children <= 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): sex ratio \" << sex_ratio << \" results in a unisexual child population.\" << EidosTerminate();\n\t}\n\t\n\t// Mutrun experiment timing can be per-individual, per-chromosome, but that entails a lot of timing overhead.\n\t// To avoid that overhead, in single-chromosome models we just time across the whole round of reproduction\n\t// instead.  Note that in this case we chose a template above for the Munge...() methods that does not time.\n\t// FIXME 4/14/2025: It remains true that in multi-chrom models the timing overhead will be very high.  There\n\t// are various ways that could potentially be cut down.  (a) not measure in every tick, (b) stop measuring\n\t// once you've settled down into stasis, (c) measure a subset of all reproductions.  This should be done in\n\t// future, but we're out of time for now.\n\tif (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))\n\t\tspecies_.Chromosomes()[0]->StartMutationRunExperimentClock();\n\t\n\tif (p_mate_choice_callbacks_present || p_modify_child_callbacks_present || p_recombination_callbacks_present || p_mutation_callbacks_present || p_type_s_dfe_present)\n\t{\n\t\t// CALLBACKS PRESENT: We need to generate offspring in a randomized order.  This way the callbacks are presented with potential offspring\n\t\t// a random order, and so it is much easier to write a callback that runs for less than the full offspring generation phase (influencing a\n\t\t// limited number of mating events, for example).  So in this code branch, we prepare an overall plan for migration and sex, and then execute\n\t\t// that plan in an order randomized with Eidos_ran_shuffle_uint32().  BCH 28 September 2016: When sex is enabled, we want to generate male and female\n\t\t// offspring in shuffled order.  However, the vector of child individuals is organized into females first, then males, so we need to fill that\n\t\t// vector in an unshuffled order or we end up trying to generate a male offspring into a female slot, or vice versa.  See the usage of\n\t\t// child_index_F, child_index_M, and child_index in the shuffle cases below.\n\t\t\n\t\tif (migrant_source_count == 0)\n\t\t{\n\t\t\t// CALLBACKS, NO MIGRATION: Here we are drawing all offspring from the local pool, so we can optimize a lot.  We only need to shuffle\n\t\t\t// the order in which males and females are generated, if we're running with sex, selfing, or cloning; if not, we actually don't need\n\t\t\t// to shuffle at all, because no aspect of the mating algorithm is predetermined.\n\t\t\tslim_popsize_t child_count = 0;\t// counter over all subpop_size_ children\n\t\t\tSubpopulation &source_subpop = p_subpop;\n\t\t\tdouble selfing_fraction = source_subpop.selfing_fraction_;\n\t\t\tdouble cloning_fraction = source_subpop.female_clone_fraction_;\n\t\t\t\n\t\t\t// figure out our callback situation for this source subpop; callbacks come from the source, not the destination\n\t\t\t// we used to get other callbacks here too, but that is no longer necessary; the Munge...() methods handle it\n\t\t\tstd::vector<SLiMEidosBlock*> *mate_choice_callbacks = nullptr;\n\t\t\t\n\t\t\tif (p_mate_choice_callbacks_present && source_subpop.registered_mate_choice_callbacks_.size())\n\t\t\t\tmate_choice_callbacks = &source_subpop.registered_mate_choice_callbacks_;\n\t\t\t\n\t\t\tif (sex_enabled || (selfing_fraction > 0.0) || (cloning_fraction > 0.0))\n\t\t\t{\n\t\t\t\t// We have either sex, selfing, or cloning as attributes of each individual child, so we need to pre-plan and shuffle.\n\t\t\t\t\n\t\t\t\t// BCH 13 March 2018: We were allocating a buffer for the pre-plan on the stack, and that was overflowing the stack when\n\t\t\t\t// we had a large number of children; changing to using a static allocated buffer that we reuse.  Note the buffer here is\n\t\t\t\t// separate from the one below, and uses a different struct type, despite the similarity.\n\t\t\t\ttypedef struct\n\t\t\t\t{\n\t\t\t\t\tIndividualSex planned_sex;\n\t\t\t\t\tuint8_t planned_cloned;\n\t\t\t\t\tuint8_t planned_selfed;\n\t\t\t\t} offspring_plan_no_source;\n\t\t\t\t\n\t\t\t\tstatic offspring_plan_no_source *planned_offspring = nullptr;\n\t\t\t\tstatic int64_t planned_offspring_alloc_size = 0;\n\t\t\t\t\n\t\t\t\tif (planned_offspring_alloc_size < total_children)\n\t\t\t\t{\n\t\t\t\t\tplanned_offspring = (offspring_plan_no_source *)realloc(planned_offspring, total_children * sizeof(offspring_plan_no_source));\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\t\t\t\tif (!planned_offspring)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\tplanned_offspring_alloc_size = total_children;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (int sex_index = 0; sex_index < number_of_sexes; ++sex_index)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t total_children_of_sex;\n\t\t\t\t\tIndividualSex child_sex;\n\t\t\t\t\t\n\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t{\n\t\t\t\t\t\ttotal_children_of_sex = ((sex_index == 0) ? total_female_children : total_male_children);\n\t\t\t\t\t\tchild_sex = ((sex_index == 0) ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttotal_children_of_sex = total_children;\n\t\t\t\t\t\tchild_sex = IndividualSex::kHermaphrodite;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tslim_popsize_t migrants_to_generate = total_children_of_sex;\n\t\t\t\t\t\n\t\t\t\t\tif (migrants_to_generate > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// figure out how many from this source subpop are the result of selfing and/or cloning\n\t\t\t\t\t\tslim_popsize_t number_to_self = 0, number_to_clone = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (selfing_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (cloning_fraction > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdouble fractions[3] = {selfing_fraction, cloning_fraction, 1.0 - (selfing_fraction + cloning_fraction)};\n\t\t\t\t\t\t\t\tunsigned int counts[3] = {0, 0, 0};\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (fractions[2] < 0.0)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): selfingRate + cloningRate > 1.0; cannot generate offspring satisfying constraints.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tgsl_ran_multinomial(rng_gsl, 3, (unsigned int)migrants_to_generate, fractions, counts);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(counts[0]);\n\t\t\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(counts[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, selfing_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (cloning_fraction > 0)\n\t\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, cloning_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t\t\n\t\t\t\t\t\t// generate all selfed, cloned, and autogamous offspring in one shared loop\n\t\t\t\t\t\tslim_popsize_t migrant_count = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (migrant_count < migrants_to_generate)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toffspring_plan_no_source *offspring_plan_ptr = planned_offspring + child_count;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\toffspring_plan_ptr->planned_sex = child_sex;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (number_to_clone > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = true;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = false;\n\t\t\t\t\t\t\t\t--number_to_clone;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (number_to_self > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = false;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = true;\n\t\t\t\t\t\t\t\t--number_to_self;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = false;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// change all our counters\n\t\t\t\t\t\t\tmigrant_count++;\n\t\t\t\t\t\t\tchild_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEidos_ran_shuffle_uint32(rng_32, planned_offspring, total_children);\n\t\t\t\t\n\t\t\t\t// Now we can run through our plan vector and generate each planned child in order.\n\t\t\t\tslim_popsize_t child_index_F = 0, child_index_M = total_female_children, child_index;\n\t\t\t\t\n\t\t\t\tfor (child_count = 0; child_count < total_children; ++child_count)\n\t\t\t\t{\n\t\t\t\t\t// Get the plan for this offspring from our shuffled plan vector\n\t\t\t\t\toffspring_plan_no_source *offspring_plan_ptr = planned_offspring + child_count;\n\t\t\t\t\t\n\t\t\t\t\tIndividualSex child_sex = offspring_plan_ptr->planned_sex;\n\t\t\t\t\tbool selfed, cloned;\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\t\t// Find the appropriate index for the child we are generating; we need to put males and females in the right spots\n\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (child_sex == IndividualSex::kFemale)\n\t\t\t\t\t\t\tchild_index = child_index_F++;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tchild_index = child_index_M++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tchild_index = child_count;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// We loop back to here to retry child generation if a mateChoice() or modifyChild() callback causes our first attempt at\n\t\t\t\t\t// child generation to fail.  The first time we generate a given child index, we follow our plan; subsequent times, we\n\t\t\t\t\t// draw selfed and cloned randomly based on the probabilities set for the source subpop.  This allows the callbacks to\n\t\t\t\t\t// actually influence the proportion selfed/cloned, through e.g. lethal epistatic interactions or failed mate search.\n\t\t\t\tretryChild:\n\t\t\t\t\t\n\t\t\t\t\tif (num_tries > 1000000)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): failed to generate child after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (num_tries == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// first mating event, so follow our original plan for this offspring\n\t\t\t\t\t\t// note we could draw self/cloned as below even for the first try; this code path is just more efficient,\n\t\t\t\t\t\t// since it avoids a gsl_ran_uniform() for each child, in favor of one gsl_ran_multinomial() above\n\t\t\t\t\t\tselfed = offspring_plan_ptr->planned_selfed;\n\t\t\t\t\t\tcloned = offspring_plan_ptr->planned_cloned;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// a whole new mating event, so we draw selfed/cloned based on the source subpop's probabilities\n\t\t\t\t\t\tselfed = false;\n\t\t\t\t\t\tcloned = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (selfing_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (cloning_fraction > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (draw < selfing_fraction)\t\t\t\t\t\t\tselfed = true;\n\t\t\t\t\t\t\t\telse if (draw < selfing_fraction + cloning_fraction)\tcloned = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (draw < selfing_fraction)\t\t\t\t\t\t\tselfed = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (cloning_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (draw < cloning_fraction)\t\t\t\t\t\t\t\tcloned = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we do not redraw the sex of the child, however, because that is predetermined; we need to hit our target ratio\n\t\t\t\t\t\t// we could trade our planned sex for a randomly chosen planned sex from the remaining children to generate, but\n\t\t\t\t\t\t// that gets a little complicated because of selfing, and I'm having trouble imagining a scenario where it matters\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tbool child_accepted;\n\t\t\t\t\t\n\t\t\t\t\tif (cloned)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_popsize_t parent1;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\tparent1 = (child_sex == IndividualSex::kFemale) ? source_subpop.DrawFemaleParentUsingFitness(rng_state) : source_subpop.DrawMaleParentUsingFitness(rng_state);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\t\n\t\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\t\tnew_child->migrant_ = false;\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualCloned_TEMPLATED)(new_child, individual_pid, source_subpop.parent_individuals_[parent1]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_popsize_t parent1;\n\n\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\tparent1 = source_subpop.DrawFemaleParentUsingFitness(rng_state);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (selfed)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\t\t\tnew_child->migrant_ = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualSelfed_TEMPLATED)(new_child, individual_pid, source_subpop.parent_individuals_[parent1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_popsize_t parent2;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (!mate_choice_callbacks)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tparent2 = source_subpop.DrawMaleParentUsingFitness(rng_state);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\t\tparent2 = source_subpop.DrawParentUsingFitness(rng_state);\t// selfing possible!\n\t\t\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\tparent2 = ApplyMateChoiceCallbacks(parent1, &p_subpop, &source_subpop, *mate_choice_callbacks);\n\t\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (parent2 == -1)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The mateChoice() callbacks rejected parent1 altogether, so we need to choose a new parent1 and start over\n\t\t\t\t\t\t\t\t\tnum_tries++;\n\t\t\t\t\t\t\t\t\tgoto retryChild;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\t\t\tnew_child->migrant_ = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, individual_pid, source_subpop.parent_individuals_[parent1], source_subpop.parent_individuals_[parent2], child_sex);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (!child_accepted)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The modifyChild() callbacks suppressed the child altogether; this is juvenile migrant mortality, basically, so\n\t\t\t\t\t\t// we need to even change the source subpop for our next attempt.  In this case, however, we have no migration.\n\t\t\t\t\t\tnum_tries++;\n\t\t\t\t\t\tgoto retryChild;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// CALLBACKS, NO MIGRATION, NO SEX, NO SELFING, NO CLONING: so we don't need to preplan or shuffle, each child is generated in the same exact way.\n\t\t\t\tint num_tries = 0;\n\t\t\t\t\n\t\t\t\twhile (child_count < total_children)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t parent1, parent2;\n\t\t\t\t\t\n\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\n\t\t\t\t\tif (!mate_choice_callbacks)\n\t\t\t\t\t{\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t\tparent2 = source_subpop.DrawParentUsingFitness(rng_state);\t// selfing possible!\n\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (true)\t// loop while parent2 == -1, indicating a request for a new first parent\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\tparent2 = ApplyMateChoiceCallbacks(parent1, &p_subpop, &source_subpop, *mate_choice_callbacks);\n\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (parent2 != -1)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// parent1 was rejected by the callbacks, so we need to redraw a new parent1\n\t\t\t\t\t\t\tnum_tries++;\n\t\t\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (num_tries > 1000000)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): failed to generate child after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\n\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_count];\n\t\t\t\t\tnew_child->migrant_ = false;\n\t\t\t\t\t\n\t\t\t\t\tbool child_accepted = (p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, individual_pid, source_subpop.parent_individuals_[parent1], source_subpop.parent_individuals_[parent2], IndividualSex::kHermaphrodite);\n\t\t\t\t\t\n\t\t\t\t\tif (!child_accepted)\n\t\t\t\t\t{\n\t\t\t\t\t\tnum_tries++;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (num_tries > 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): failed to generate child after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if the child was accepted, change all our counters to start afresh\n\t\t\t\t\tchild_count++;\n\t\t\t\t\tnum_tries = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// CALLBACKS WITH MIGRATION: Here we need to shuffle the migration source subpops, as well as the offspring sex.  This makes things so\n\t\t\t// different that it is worth treating it as an entirely separate case; it is far less optimizable than the case without migration.\n\t\t\t// Note that this is pretty much the general case of this whole method; all the other cases are optimized sub-cases of this code!\n\t\t\tslim_popsize_t child_count = 0;\t// counter over all subpop_size_ children\n\t\t\t\n\t\t\t// Pre-plan and shuffle.\n\t\t\t\n\t\t\t// BCH 13 March 2018: We were allocating a buffer for the pre-plan on the stack, and that was overflowing the stack when\n\t\t\t// we had a large number of children; changing to using a static allocated buffer that we reuse.  Note the buffer here is\n\t\t\t// separate from the one below, and uses a different struct type, despite the similarity.\n\t\t\ttypedef struct\n\t\t\t{\n\t\t\t\tSubpopulation *planned_source;\n\t\t\t\tIndividualSex planned_sex;\n\t\t\t\tuint8_t planned_cloned;\n\t\t\t\tuint8_t planned_selfed;\n\t\t\t} offspring_plan_with_source;\n\t\t\t\n\t\t\tstatic offspring_plan_with_source *planned_offspring = nullptr;\n\t\t\tstatic int64_t planned_offspring_alloc_size = 0;\n\t\t\t\n\t\t\tif (planned_offspring_alloc_size < total_children)\n\t\t\t{\n\t\t\t\tplanned_offspring = (offspring_plan_with_source *)realloc(planned_offspring, total_children * sizeof(offspring_plan_with_source));\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\t\t\tif (!planned_offspring)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\tplanned_offspring_alloc_size = total_children;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int sex_index = 0; sex_index < number_of_sexes; ++sex_index)\n\t\t\t{\n\t\t\t\tslim_popsize_t total_children_of_sex;\n\t\t\t\tIndividualSex child_sex;\n\t\t\t\t\n\t\t\t\tif (sex_enabled)\n\t\t\t\t{\n\t\t\t\t\ttotal_children_of_sex = ((sex_index == 0) ? total_female_children : total_male_children);\n\t\t\t\t\tchild_sex = ((sex_index == 0) ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttotal_children_of_sex = total_children;\n\t\t\t\t\tchild_sex = IndividualSex::kHermaphrodite;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// draw the number of individuals from the migrant source subpops, and from ourselves, for the current sex\n\t\t\t\tif (migrant_source_count == 0)\n\t\t\t\t\tnum_migrants[0] = (unsigned int)total_children_of_sex;\n\t\t\t\telse\n\t\t\t\t\tgsl_ran_multinomial(rng_gsl, migrant_source_count + 1, (unsigned int)total_children_of_sex, migration_rates, num_migrants);\n\t\t\t\t\n\t\t\t\t// loop over all source subpops, including ourselves\n\t\t\t\tfor (int pop_count = 0; pop_count < migrant_source_count + 1; ++pop_count)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t migrants_to_generate = static_cast<slim_popsize_t>(num_migrants[pop_count]);\n\t\t\t\t\t\n\t\t\t\t\tif (migrants_to_generate > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tSubpopulation &source_subpop = *(migration_sources[pop_count]);\n\t\t\t\t\t\tdouble selfing_fraction = sex_enabled ? 0.0 : source_subpop.selfing_fraction_;\n\t\t\t\t\t\tdouble cloning_fraction = (sex_index == 0) ? source_subpop.female_clone_fraction_ : source_subpop.male_clone_fraction_;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// figure out how many from this source subpop are the result of selfing and/or cloning\n\t\t\t\t\t\tslim_popsize_t number_to_self = 0, number_to_clone = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (selfing_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (cloning_fraction > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdouble fractions[3] = {selfing_fraction, cloning_fraction, 1.0 - (selfing_fraction + cloning_fraction)};\n\t\t\t\t\t\t\t\tunsigned int counts[3] = {0, 0, 0};\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (fractions[2] < 0.0)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): selfingRate + cloningRate > 1.0; cannot generate offspring satisfying constraints.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tgsl_ran_multinomial(rng_gsl, 3, (unsigned int)migrants_to_generate, fractions, counts);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(counts[0]);\n\t\t\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(counts[1]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, selfing_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (cloning_fraction > 0)\n\t\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, cloning_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t\t\n\t\t\t\t\t\t// generate all selfed, cloned, and autogamous offspring in one shared loop\n\t\t\t\t\t\tslim_popsize_t migrant_count = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (migrant_count < migrants_to_generate)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toffspring_plan_with_source *offspring_plan_ptr = planned_offspring + child_count;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\toffspring_plan_ptr->planned_source = &source_subpop;\n\t\t\t\t\t\t\toffspring_plan_ptr->planned_sex = child_sex;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (number_to_clone > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = true;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = false;\n\t\t\t\t\t\t\t\t--number_to_clone;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (number_to_self > 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = false;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = true;\n\t\t\t\t\t\t\t\t--number_to_self;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_cloned = false;\n\t\t\t\t\t\t\t\toffspring_plan_ptr->planned_selfed = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// change all our counters\n\t\t\t\t\t\t\tmigrant_count++;\n\t\t\t\t\t\t\tchild_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tEidos_ran_shuffle_uint32(rng_32, planned_offspring, total_children);\n\t\t\t\n\t\t\t// Now we can run through our plan vector and generate each planned child in order.\n\t\t\tslim_popsize_t child_index_F = 0, child_index_M = total_female_children, child_index;\n\t\t\t\n\t\t\tfor (child_count = 0; child_count < total_children; ++child_count)\n\t\t\t{\n\t\t\t\t// Get the plan for this offspring from our shuffled plan vector\n\t\t\t\toffspring_plan_with_source *offspring_plan_ptr = planned_offspring + child_count;\n\t\t\t\t\n\t\t\t\tSubpopulation *source_subpop = offspring_plan_ptr->planned_source;\n\t\t\t\tIndividualSex child_sex = offspring_plan_ptr->planned_sex;\n\t\t\t\tbool selfed, cloned;\n\t\t\t\tint num_tries = 0;\n\t\t\t\t\n\t\t\t\t// Find the appropriate index for the child we are generating; we need to put males and females in the right spots\n\t\t\t\tif (sex_enabled)\n\t\t\t\t{\n\t\t\t\t\tif (child_sex == IndividualSex::kFemale)\n\t\t\t\t\t\tchild_index = child_index_F++;\n\t\t\t\t\telse\n\t\t\t\t\t\tchild_index = child_index_M++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tchild_index = child_count;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We loop back to here to retry child generation if a modifyChild() callback causes our first attempt at\n\t\t\t\t// child generation to fail.  The first time we generate a given child index, we follow our plan; subsequent times, we\n\t\t\t\t// draw selfed and cloned randomly based on the probabilities set for the source subpop.  This allows the callbacks to\n\t\t\t\t// actually influence the proportion selfed/cloned, through e.g. lethal epistatic interactions or failed mate search.\n\t\t\tretryWithNewSourceSubpop:\n\t\t\t\t\n\t\t\t\t// figure out our callback situation for this source subpop; callbacks come from the source, not the destination\n\t\t\t\t// we used to get other callbacks here too, but that is no longer necessary; the Munge...() methods handle it\n\t\t\t\tstd::vector<SLiMEidosBlock*> *mate_choice_callbacks = nullptr;\n\t\t\t\t\n\t\t\t\tif (source_subpop->registered_mate_choice_callbacks_.size())\n\t\t\t\t\tmate_choice_callbacks = &source_subpop->registered_mate_choice_callbacks_;\n\t\t\t\t\n\t\t\t\t// Similar to retryWithNewSourceSubpop: but assumes that the subpop remains unchanged; used after a failed mateChoice()\n\t\t\t\t// callback, which rejects parent1 but does not cause a redraw of the source subpop.\n\t\t\tretryWithSameSourceSubpop:\n\t\t\t\t\n\t\t\t\tif (num_tries > 1000000)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): failed to generate child after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (num_tries == 0)\n\t\t\t\t{\n\t\t\t\t\t// first mating event, so follow our original plan for this offspring\n\t\t\t\t\t// note we could draw self/cloned as below even for the first try; this code path is just more efficient,\n\t\t\t\t\t// since it avoids a gsl_ran_uniform() for each child, in favor of one gsl_ran_multinomial() above\n\t\t\t\t\tselfed = offspring_plan_ptr->planned_selfed;\n\t\t\t\t\tcloned = offspring_plan_ptr->planned_cloned;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// a whole new mating event, so we draw selfed/cloned based on the source subpop's probabilities\n\t\t\t\t\tdouble selfing_fraction = sex_enabled ? 0.0 : source_subpop->selfing_fraction_;\n\t\t\t\t\tdouble cloning_fraction = (child_sex != IndividualSex::kMale) ? source_subpop->female_clone_fraction_ : source_subpop->male_clone_fraction_;\n\t\t\t\t\t\n\t\t\t\t\tselfed = false;\n\t\t\t\t\tcloned = false;\n\t\t\t\t\t\n\t\t\t\t\tif (selfing_fraction > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cloning_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (draw < selfing_fraction)\t\t\t\t\t\t\tselfed = true;\n\t\t\t\t\t\t\telse if (draw < selfing_fraction + cloning_fraction)\tcloned = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (draw < selfing_fraction)\t\t\t\t\t\t\tselfed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (cloning_fraction > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (draw < cloning_fraction)\t\t\t\t\t\t\t\tcloned = true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// we do not redraw the sex of the child, however, because that is predetermined; we need to hit our target ratio\n\t\t\t\t\t// we could trade our planned sex for a randomly chosen planned sex from the remaining children to generate, but\n\t\t\t\t\t// that gets a little complicated because of selfing, and I'm having trouble imagining a scenario where it matters\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbool child_accepted;\n\t\t\t\t\n\t\t\t\tif (cloned)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t parent1;\n\t\t\t\t\t\n\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\tparent1 = (child_sex == IndividualSex::kFemale) ? source_subpop->DrawFemaleParentUsingFitness(rng_state) : source_subpop->DrawMaleParentUsingFitness(rng_state);\n\t\t\t\t\telse\n\t\t\t\t\t\tparent1 = source_subpop->DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\n\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\n\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\tnew_child->migrant_ = (source_subpop != &p_subpop);\n\t\t\t\t\t\n\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualCloned_TEMPLATED)(new_child, individual_pid, source_subpop->parent_individuals_[parent1]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t parent1;\n\t\t\t\t\t\n\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\tparent1 = source_subpop->DrawFemaleParentUsingFitness(rng_state);\n\t\t\t\t\telse\n\t\t\t\t\t\tparent1 = source_subpop->DrawParentUsingFitness(rng_state);\n\t\t\t\t\t\n\t\t\t\t\tif (selfed)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\t\tnew_child->migrant_ = (source_subpop != &p_subpop);\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualSelfed_TEMPLATED)(new_child, individual_pid, source_subpop->parent_individuals_[parent1]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_popsize_t parent2;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!mate_choice_callbacks)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tparent2 = source_subpop->DrawMaleParentUsingFitness(rng_state);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\tparent2 = source_subpop->DrawParentUsingFitness(rng_state);\t// selfing possible!\n\t\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\tparent2 = ApplyMateChoiceCallbacks(parent1, &p_subpop, source_subpop, *mate_choice_callbacks);\n\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (parent2 == -1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// The mateChoice() callbacks rejected parent1 altogether, so we need to choose a new parent1 and start over\n\t\t\t\t\t\t\t\tnum_tries++;\n\t\t\t\t\t\t\t\tgoto retryWithSameSourceSubpop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[child_index];\n\t\t\t\t\t\tnew_child->migrant_ = (source_subpop != &p_subpop);\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_accepted = (p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, individual_pid, source_subpop->parent_individuals_[parent1], source_subpop->parent_individuals_[parent2], child_sex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!child_accepted)\n\t\t\t\t{\n\t\t\t\t\t// The modifyChild() callbacks suppressed the child altogether; this is juvenile migrant mortality, basically, so\n\t\t\t\t\t// we need to even change the source subpop for our next attempt, so that differential mortality between different\n\t\t\t\t\t// migration sources leads to differential representation in the offspring generation – more offspring from the\n\t\t\t\t\t// subpop that is more successful at contributing migrants.\n\t\t\t\t\tgsl_ran_multinomial(rng_gsl, migrant_source_count + 1, 1, migration_rates, num_migrants);\n\t\t\t\t\t\n\t\t\t\t\tfor (int pop_count = 0; pop_count < migrant_source_count + 1; ++pop_count)\n\t\t\t\t\t\tif (num_migrants[pop_count] > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsource_subpop = migration_sources[pop_count];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tnum_tries++;\n\t\t\t\t\tgoto retryWithNewSourceSubpop;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// NO CALLBACKS PRESENT: offspring can be generated in a fixed (i.e. predetermined) order.  This is substantially faster, since it avoids\n\t\t// some setup overhead, including the Eidos_ran_shuffle() call.  All code that accesses individuals within a subpopulation needs to be aware of\n\t\t// the fact that the individuals might be in a non-random order, because of this code path.  BEWARE!\n\t\t\n\t\t// In some cases the code below parallelizes, when we're running multithreaded.  The main condition, already satisfied simply by virtue of\n\t\t// being in this code path, is that there are no callbacks enabled, of any type, that influence the process of reproduction.  This is because\n\t\t// we can't run Eidos code in parallel, at least for now.  At the moment, the DSB recombination model is also not allowed; it hasn't been tested.\n#ifdef _OPENMP\n\t\tbool can_parallelize = true;\n\t\t\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t\tif (chromosome.using_DSB_model_)\n\t\t\t{\n\t\t\t\tcan_parallelize = false;\n\t\t\t\tbreak;\n\t\t\t}\n#endif\n\t\t\n\t\t// We loop to generate females first (sex_index == 0) and males second (sex_index == 1).\n\t\t// In nonsexual simulations number_of_sexes == 1 and this loops just once.\n\t\tslim_popsize_t child_count = 0;\t// counter over all subpop_size_ children\n\t\t\n\t\tfor (int sex_index = 0; sex_index < number_of_sexes; ++sex_index)\n\t\t{\n\t\t\tslim_popsize_t total_children_of_sex;\n\t\t\tIndividualSex child_sex;\n\t\t\t\n\t\t\tif (sex_enabled)\n\t\t\t{\n\t\t\t\ttotal_children_of_sex = ((sex_index == 0) ? total_female_children : total_male_children);\n\t\t\t\tchild_sex = ((sex_index == 0) ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttotal_children_of_sex = total_children;\n\t\t\t\tchild_sex = IndividualSex::kHermaphrodite;\n\t\t\t}\n\t\t\t\n\t\t\t// draw the number of individuals from the migrant source subpops, and from ourselves, for the current sex\n\t\t\tif (migrant_source_count == 0)\n\t\t\t\tnum_migrants[0] = (unsigned int)total_children_of_sex;\n\t\t\telse\n\t\t\t\tgsl_ran_multinomial(rng_gsl, migrant_source_count + 1, (unsigned int)total_children_of_sex, migration_rates, num_migrants);\n\t\t\t\n\t\t\t// loop over all source subpops, including ourselves\n\t\t\tfor (int pop_count = 0; pop_count < migrant_source_count + 1; ++pop_count)\n\t\t\t{\n\t\t\t\tslim_popsize_t migrants_to_generate = static_cast<slim_popsize_t>(num_migrants[pop_count]);\n\t\t\t\t\n\t\t\t\tif (migrants_to_generate > 0)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation &source_subpop = *(migration_sources[pop_count]);\n\t\t\t\t\tdouble selfing_fraction = sex_enabled ? 0.0 : source_subpop.selfing_fraction_;\n\t\t\t\t\tdouble cloning_fraction = (sex_index == 0) ? source_subpop.female_clone_fraction_ : source_subpop.male_clone_fraction_;\n\t\t\t\t\t\n\t\t\t\t\t// figure out how many from this source subpop are the result of selfing and/or cloning\n\t\t\t\t\tslim_popsize_t number_to_self = 0, number_to_clone = 0;\n\t\t\t\t\t\n\t\t\t\t\tif (selfing_fraction > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cloning_fraction > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble fractions[3] = {selfing_fraction, cloning_fraction, 1.0 - (selfing_fraction + cloning_fraction)};\n\t\t\t\t\t\t\tunsigned int counts[3] = {0, 0, 0};\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (fractions[2] < 0.0)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::EvolveSubpopulation): selfingRate + cloningRate > 1.0; cannot generate offspring satisfying constraints.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgsl_ran_multinomial(rng_gsl, 3, (unsigned int)migrants_to_generate, fractions, counts);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(counts[0]);\n\t\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(counts[1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tnumber_to_self = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, selfing_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t}\n\t\t\t\t\telse if (cloning_fraction > 0)\n\t\t\t\t\t\tnumber_to_clone = static_cast<slim_popsize_t>(gsl_ran_binomial(rng_gsl, cloning_fraction, (unsigned int)migrants_to_generate));\n\t\t\t\t\t\n\t\t\t\t\t// We get a whole block of pedigree IDs to use in the loop below, avoiding race conditions / locking\n\t\t\t\t\t// We are also going to use Individual objects from a block starting at base_child_count\n\t\t\t\t\tslim_pedigreeid_t base_pedigree_id = SLiM_GetNextPedigreeID_Block(migrants_to_generate);\n\t\t\t\t\tslim_popsize_t base_child_count = child_count;\n\t\t\t\t\t\n\t\t\t\t\t// We need to make sure we have adequate capacity in the global mutation block for new mutations before we go parallel;\n\t\t\t\t\t// if SLiM_IncreaseMutationBlockCapacity() is called while parallel, it is a fatal error.  So we make a guess at how\n\t\t\t\t\t// much free space we will need, and preallocate here as needed, regardless of will_parallelize; no reason not to.\n#ifdef _OPENMP\n\t\t\t\t\tbool will_parallelize = can_parallelize && (migrants_to_generate >= EIDOS_OMPMIN_WF_REPRO);\n\t\t\t\t\tsize_t est_mutation_block_slots_remaining_PRE = 0;\n\t\t\t\t\t//size_t actual_mutation_block_slots_remaining_PRE = 0;\n\t\t\t\t\tdouble overall_mutation_rate = 0;\n\t\t\t\t\tsize_t est_slots_needed = 0;\n\t\t\t\t\t\n\t\t\t\t\t{\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\tint registry_size;\n\t\t\t\t\t\t\tMutationRegistry(&registry_size);\n\t\t\t\t\t\t\test_mutation_block_slots_remaining_PRE = gSLiM_Mutation_Block_Capacity - registry_size;\n\t\t\t\t\t\t\t//actual_mutation_block_slots_remaining_PRE = SLiMMemoryUsageForFreeMutations() / sizeof(Mutation);\n\t\t\t\t\t\t\toverall_mutation_rate = std::max(species_.chromosome_->overall_mutation_rate_F_, species_.chromosome_->overall_mutation_rate_M_);\t// already multiplied by L\n\t\t\t\t\t\t\test_slots_needed = (size_t)ceil(2 * migrants_to_generate * overall_mutation_rate);\t// 2 because diploid, in the worst case\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tsize_t ten_times_demand = 10 * est_slots_needed;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (est_mutation_block_slots_remaining_PRE <= ten_times_demand)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSLiM_IncreaseMutationBlockCapacity();\n\t\t\t\t\t\t\t\test_mutation_block_slots_remaining_PRE = gSLiM_Mutation_Block_Capacity - registry_size;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t//std::cerr << \"Tick \" << community_.Tick() << \": DOUBLED CAPACITY ***********************************\" << std::endl;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} while (true);\n\t\t\t\t\t\t\n\t\t\t\t\t\t//std::cerr << \"Tick \" << community_.Tick() << \":\" << std::endl;\n\t\t\t\t\t\t//std::cerr << \"   before reproduction, \" << actual_mutation_block_slots_remaining_PRE << \" actual slots remaining (\" << est_mutation_block_slots_remaining_PRE << \" estimated)\" << std::endl;\n\t\t\t\t\t\t//std::cerr << \"   demand for new mutations estimated at \" << est_slots_needed << \" (\" << migrants_to_generate << \" offspring, E(muts) == \" << overall_mutation_rate << \")\" << std::endl;\n\t\t\t\t\t}\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// generate all selfed, cloned, and autogamous offspring in one shared loop\n\t\t\t\t\tif ((number_to_self == 0) && (number_to_clone == 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t// a simple loop for the base case with no selfing, no cloning, and no callbacks; we split into two cases by sex_enabled for maximal speed\n\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_WF_REPRO);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, migrants_to_generate, base_child_count, base_pedigree_id, pedigrees_enabled, p_subpop, source_subpop, child_sex, prevent_incidental_selfing) if(will_parallelize) num_threads(thread_count)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidos_RNG_State *parallel_rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\t\t\t\t\t\n#pragma omp for schedule(dynamic, 1)\n\t\t\t\t\t\t\t\tfor (slim_popsize_t migrant_count = 0; migrant_count < migrants_to_generate; migrant_count++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent1 = source_subpop.DrawFemaleParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent2 = source_subpop.DrawMaleParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tslim_popsize_t this_child_index = base_child_count + migrant_count;\n\t\t\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[this_child_index];\n\t\t\t\t\t\t\t\t\tnew_child->migrant_ = (&source_subpop != &p_subpop);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, base_pedigree_id + migrant_count, source_subpop.parent_individuals_[parent1], source_subpop.parent_individuals_[parent2], child_sex);\n\t\t\t\t\t\t\t\t\tnew_child->migrant_ = (&source_subpop != &p_subpop);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tchild_count += migrants_to_generate;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_WF_REPRO);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, migrants_to_generate, base_child_count, base_pedigree_id, pedigrees_enabled, p_subpop, source_subpop, child_sex, prevent_incidental_selfing) if(will_parallelize) num_threads(thread_count)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidos_RNG_State *parallel_rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\t\t\t\t\t\n#pragma omp for schedule(dynamic, 1)\n\t\t\t\t\t\t\t\tfor (slim_popsize_t migrant_count = 0; migrant_count < migrants_to_generate; migrant_count++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent1 = source_subpop.DrawParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent2;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\t\tparent2 = source_subpop.DrawParentUsingFitness(parallel_rng_state);\t// note this does not prohibit selfing!\n\t\t\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tslim_popsize_t this_child_index = base_child_count + migrant_count;\n\t\t\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[this_child_index];\n\t\t\t\t\t\t\t\t\tnew_child->migrant_ = (&source_subpop != &p_subpop);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, base_pedigree_id + migrant_count, source_subpop.parent_individuals_[parent1], source_subpop.parent_individuals_[parent2], child_sex);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tchild_count += migrants_to_generate;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// the full loop with support for selfing/cloning (but no callbacks, since we're in that overall branch)\n\t\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_WF_REPRO);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, migrants_to_generate, number_to_clone, number_to_self, base_child_count, base_pedigree_id, pedigrees_enabled, p_subpop, source_subpop, sex_enabled, child_sex, recording_tree_sequence, prevent_incidental_selfing) if(will_parallelize) num_threads(thread_count)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidos_RNG_State *parallel_rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\t\t\t\t\n#pragma omp for schedule(dynamic, 1)\n\t\t\t\t\t\t\tfor (slim_popsize_t migrant_count = 0; migrant_count < migrants_to_generate; migrant_count++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (migrant_count < number_to_clone)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent1;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t\t\t\tparent1 = (child_sex == IndividualSex::kFemale) ? source_subpop.DrawFemaleParentUsingFitness(parallel_rng_state) : source_subpop.DrawMaleParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tslim_popsize_t this_child_index = base_child_count + migrant_count;\n\t\t\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[this_child_index];\n\t\t\t\t\t\t\t\t\tnew_child->migrant_ = (&source_subpop != &p_subpop);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t(p_subpop.*MungeIndividualCloned_TEMPLATED)(new_child, base_pedigree_id + migrant_count, source_subpop.parent_individuals_[parent1]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_popsize_t parent1;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t\t\t\tparent1 = source_subpop.DrawFemaleParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tparent1 = source_subpop.DrawParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tslim_popsize_t this_child_index = base_child_count + migrant_count;\n\t\t\t\t\t\t\t\t\tIndividual *new_child = p_subpop.child_individuals_[this_child_index];\n\t\t\t\t\t\t\t\t\tnew_child->migrant_ = (&source_subpop != &p_subpop);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (migrant_count < number_to_clone + number_to_self)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t(p_subpop.*MungeIndividualSelfed_TEMPLATED)(new_child, base_pedigree_id + migrant_count, source_subpop.parent_individuals_[parent1]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tslim_popsize_t parent2;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tparent2 = source_subpop.DrawMaleParentUsingFitness(parallel_rng_state);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t\t\t\t\t\tparent2 = source_subpop.DrawParentUsingFitness(parallel_rng_state);\t// selfing possible!\n\t\t\t\t\t\t\t\t\t\t\twhile (prevent_incidental_selfing && (parent2 == parent1));\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t(p_subpop.*MungeIndividualCrossed_TEMPLATED)(new_child, base_pedigree_id + migrant_count, source_subpop.parent_individuals_[parent1], source_subpop.parent_individuals_[parent2], child_sex);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_WF_REPRO);\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_count += migrants_to_generate;\n\t\t\t\t\t}\n\t\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\t\t//if (will_parallelize)\n\t\t\t\t\t//{\n\t\t\t\t\t//\tsize_t actual_mutation_block_slots_remaining_POST = SLiMMemoryUsageForFreeMutations() / sizeof(Mutation);\n\t\t\t\t\t//\t\n\t\t\t\t\t//\tstd::cerr << \"   after reproduction, \" << actual_mutation_block_slots_remaining_POST << \" actual slots remaining\" << std::endl;\n\t\t\t\t\t//\tstd::cerr << \"   actual demand for new mutations was \" << (actual_mutation_block_slots_remaining_PRE - actual_mutation_block_slots_remaining_POST) << \" (\" << est_slots_needed << \" was estimated)\" << std::endl;\n\t\t\t\t\t//}\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Mutrun experiment timing can be per-individual, per-chromosome, but that entails a lot of timing overhead.\n\t// To avoid that overhead, in single-chromosome models we just time across the whole round of reproduction\n\t// instead.  Note that in this case we chose a template above for the Munge...() methods that does not time.\n\tif (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))\n\t\tspecies_.Chromosomes()[0]->StopMutationRunExperimentClock(\"EvolveSubpopulation()\");\n}\n\n// apply recombination() callbacks to a generated child; a return of true means breakpoints were changed\nbool Population::ApplyRecombinationCallbacks(Individual *p_parent, Haplosome *p_haplosome1, Haplosome *p_haplosome2, std::vector<slim_position_t> &p_crossovers, std::vector<SLiMEidosBlock*> &p_recombination_callbacks)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyRecombinationCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\t// note the focal child during the callback, so we can prevent illegal operations during the callback\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n\t\n\tbool crossovers_changed = false;\n\tEidosValue_SP local_crossovers_ptr;\n\t\n\tfor (SLiMEidosBlock *recombination_callback : p_recombination_callbacks)\n\t{\n\t\tif (recombination_callback->block_active_)\n\t\t{\n\t\t\tif (recombination_callback->chromosome_id_ != -1)\n\t\t\t{\n\t\t\t\t// check that this callback applies to the focal chromosome\n\t\t\t\tint64_t focal_chromosome_id = p_haplosome1->AssociatedChromosome()->ID();\n\t\t\t\t\n\t\t\t\tif (recombination_callback->chromosome_id_ != focal_chromosome_id)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = recombination_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG recombination(\";\n\t\t\t\t\tif (recombination_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << recombination_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (recombination_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << recombination_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// The callback is active, so we need to execute it\n\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\tEidosInterpreter interpreter(recombination_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t);\n\t\t\t\n\t\t\tif (recombination_callback->contains_self_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(recombination_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\n\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\tif (recombination_callback->contains_individual_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, p_parent->CachedEidosValue());\n\t\t\tif (recombination_callback->contains_haplosome1_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_haplosome1, p_haplosome1->CachedEidosValue());\n\t\t\tif (recombination_callback->contains_haplosome2_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_haplosome2, p_haplosome2->CachedEidosValue());\n\t\t\tif (recombination_callback->contains_subpop_)\n\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, p_parent->subpopulation_->SymbolTableEntry().second);\n\t\t\t\n\t\t\t// All the variable entries for the crossovers and gene conversion start/end points\n\t\t\tif (recombination_callback->contains_breakpoints_)\n\t\t\t{\n\t\t\t\tif (!local_crossovers_ptr)\n\t\t\t\t\tlocal_crossovers_ptr = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(p_crossovers));\n\t\t\t\tclient_symbols.SetValueForSymbolNoCopy(gID_breakpoints, local_crossovers_ptr);\n\t\t\t}\n\t\t\t\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton logical, T if breakpoints have been changed, F otherwise\n\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(recombination_callback->script_);\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tif ((result->Type() != EidosValueType::kValueLogical) || (result->Count() != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyRecombinationCallbacks): recombination() callbacks must provide a logical singleton return value.\" << EidosTerminate(recombination_callback->identifier_token_);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// this checks the value type at runtime\n\t\t\t\teidos_logical_t breakpoints_changed = result->LogicalData()[0];\n#else\n\t\t\t\t// unsafe cast for speed\n\t\t\t\teidos_logical_t breakpoints_changed = ((EidosValue_Logical *)result)->data()[0];\n#endif\n\t\t\t\t\n\t\t\t\t// If the callback says that breakpoints were changed, check for an actual change in value for the variables referenced by the callback\n\t\t\t\tif (breakpoints_changed)\n\t\t\t\t{\n\t\t\t\t\tif (recombination_callback->contains_breakpoints_)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_SP new_crossovers = client_symbols.GetValueOrRaiseForSymbol(gID_breakpoints);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_crossovers != local_crossovers_ptr)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (new_crossovers->Type() != EidosValueType::kValueInt)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::ApplyRecombinationCallbacks): recombination() callbacks must provide output values (breakpoints) of type integer.\" << EidosTerminate(recombination_callback->identifier_token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnew_crossovers.swap(local_crossovers_ptr);\n\t\t\t\t\t\t\tcrossovers_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tthrow;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Read out the final values of breakpoint vectors that changed\n\tbool breakpoints_changed = false;\n\t\n\tif (crossovers_changed)\n\t{\n\t\tint count = local_crossovers_ptr->Count();\n\t\t\n\t\tp_crossovers.resize(count);\t\t// zero-fills only new entries at the margin, so is minimally wasteful\n\t\t\n\t\tconst int64_t *new_crossover_data = local_crossovers_ptr->IntData();\n\t\tslim_position_t *p_crossovers_data = p_crossovers.data();\n\t\t\n\t\tfor (int value_index = 0; value_index < count; ++value_index)\n\t\t\tp_crossovers_data[value_index] = (slim_position_t)new_crossover_data[value_index];\n\t\t\n\t\tbreakpoints_changed = true;\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosRecombinationCallback)]);\n#endif\n\t\n\treturn breakpoints_changed;\n}\n\n// generate a child haplosome from parental haplosomes, with recombination, gene conversion, and mutation\ntemplate <const bool f_treeseq, const bool f_callbacks>\nvoid Population::HaplosomeCrossed(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks)\n{\n#if DEBUG\n\t// This method is designed to run in parallel, but only if no callbacks are enabled\n\tif (p_recombination_callbacks || p_mutation_callbacks)\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::HaplosomeCrossed(): recombination and mutation callbacks are not allowed when executing in parallel\");\n\t\n\tif (!p_child_haplosome.individual_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): (internal error) individual_ pointer for child haplosome not set.\" << EidosTerminate();\n\t\n\t// BCH 9/20/2024: With the multichomosome redesign, the child and parent haplosome indices must always match; we are generating a\n\t// new offspring haplosome from parental haplosomes of the exact same chromosome (not just the same chomosome type).\n\tslim_chromosome_index_t chromosome_index = p_child_haplosome.chromosome_index_;\n\tslim_chromosome_index_t parent1_chromosome_index = parent_haplosome_1->chromosome_index_;\n\tslim_chromosome_index_t parent2_chromosome_index = parent_haplosome_2->chromosome_index_;\n\t\n\tif ((parent1_chromosome_index != chromosome_index) || (parent2_chromosome_index != chromosome_index))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): (internal error) mismatch between parent and child chromosomes (child chromosome index == \" << chromosome_index << \", parent 1 == \" << parent1_chromosome_index << \", parent 2 == \" << parent2_chromosome_index << \").\" << EidosTerminate();\n\t\n\tif (p_child_haplosome.IsNull() || parent_haplosome_1->IsNull() || parent_haplosome_2->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): (internal error) null haplosomes cannot be passed to HaplosomeCrossed().\" << EidosTerminate();\n\t\n\tHaplosome::DebugCheckStructureMatch(parent_haplosome_1, parent_haplosome_2, &p_child_haplosome, &p_chromosome);\n#endif\n#if SLIM_CLEAR_HAPLOSOMES\n\t// start with a clean slate in the child haplosome; we now expect child haplosomes to be cleared for us\n\tp_child_haplosome.check_cleared_to_nullptr();\n#endif\n\t\n\t// swap strands in half of cases to assure random assortment (or in all cases, if use_only_strand_1 == true, meaning that crossover cannot occur)\n\tbool do_swap = true;\t\t\t\t// if true, we are to swap the parental strands at the beginning 50% of the time\n\t\n\tif (do_swap)\n\t{\n\t\tif (Eidos_RandomBool(EIDOS_STATE_RNG(omp_get_thread_num())))\n\t\t\tstd::swap(parent_haplosome_1, parent_haplosome_2);\n\t}\n\t\n\t// some behaviors -- which callbacks to use, which recombination/mutation rate to use, subpop of origin for mutations, etc. --\n\t// depend upon characteristics of the first parent, so we fetch the necessary properties here\n\tIndividual *parent_individual = parent_haplosome_1->individual_;\n\tSubpopulation *source_subpop = parent_individual->subpopulation_;\n\tIndividualSex parent_sex = parent_individual->sex_;\n\t\n\t// determine how many mutations and breakpoints we have\n\tint num_mutations, num_breakpoints;\n\t\n#if defined(__GNUC__) && !defined(__clang__)\n\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\tstatic thread_local std::vector<slim_position_t> all_breakpoints;\n#else\n\tstatic std::vector<slim_position_t> all_breakpoints;\t// avoid buffer reallocs, etc.; we are guaranteed not to be re-entrant by the addX() methods\n#pragma omp threadprivate (all_breakpoints)\n#endif\n\t\n\tall_breakpoints.resize(0);\n\t\n\tstd::vector<slim_position_t> heteroduplex;\t\t\t\t// a vector of heteroduplex starts/ends, used only with complex gene conversion tracts\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// this is not static since we don't want to call resize(0) every time for a rare edge case\n\t\n\t{\n#ifdef USE_GSL_POISSON\n\t\t// When using the GSL's poisson draw, we have to draw the mutation count and breakpoint count separately;\n\t\t// the DrawMutationAndBreakpointCounts() method does not support USE_GSL_POISSON\n\t\tnum_mutations = chromosome.DrawMutationCount(p_parent_sex);\n\t\tnum_breakpoints = chromosome.DrawBreakpointCount(p_parent_sex);\n#else\n\t\t// get both the number of mutations and the number of breakpoints here; this allows us to draw both jointly, super fast!\n\t\tp_chromosome.DrawMutationAndBreakpointCounts(parent_sex, &num_mutations, &num_breakpoints);\n#endif\n\t\t\n\t\t//std::cout << num_mutations << \" mutations, \" << num_breakpoints << \" breakpoints\" << std::endl;\n\t\t\n\t\t// draw the breakpoints based on the recombination rate map, and sort and unique the result\n\t\t// we don't use Chromosome::DrawBreakpoints(), for speed, but this code mirrors it\n\t\tif (num_breakpoints)\n\t\t{\n\t\t\tif (p_chromosome.using_DSB_model_)\n\t\t\t\tp_chromosome._DrawDSBBreakpoints(parent_sex, num_breakpoints, all_breakpoints, heteroduplex);\n\t\t\telse\n\t\t\t\tp_chromosome._DrawCrossoverBreakpoints(parent_sex, num_breakpoints, all_breakpoints);\n\t\t\t\n\t\t\t// all_breakpoints is sorted and uniqued at this point\n\t\t\t\n\t\t\tif (f_callbacks && p_recombination_callbacks)\n\t\t\t{\n\t\t\t\t// a non-zero number of breakpoints, with recombination callbacks\n\t\t\t\tif (p_chromosome.using_DSB_model_ && (p_chromosome.simple_conversion_fraction_ != 1.0))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): recombination() callbacks may not be used when complex gene conversion tracts are in use, since recombination() callbacks have no support for heteroduplex regions.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tbool breaks_changed = ApplyRecombinationCallbacks(parent_individual, parent_haplosome_1, parent_haplosome_2, all_breakpoints, *p_recombination_callbacks);\n\t\t\t\tnum_breakpoints = (int)all_breakpoints.size();\n\t\t\t\t\n\t\t\t\t// we only sort/unique if the breakpoints have changed, since they were sorted/uniqued before\n\t\t\t\tif (breaks_changed && (num_breakpoints > 1))\n\t\t\t\t{\n\t\t\t\t\tstd::sort(all_breakpoints.begin(), all_breakpoints.end());\n\t\t\t\t\tall_breakpoints.erase(unique(all_breakpoints.begin(), all_breakpoints.end()), all_breakpoints.end());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// a non-zero number of breakpoints, without recombination callbacks\n\t\t\t}\n\t\t}\n\t\telse if (f_callbacks && p_recombination_callbacks)\n\t\t{\n\t\t\t// zero breakpoints from the SLiM core, but we have recombination() callbacks\n\t\t\tif (p_chromosome.using_DSB_model_ && (p_chromosome.simple_conversion_fraction_ != 1.0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): recombination() callbacks may not be used when complex gene conversion tracts are in use, since recombination() callbacks have no support for heteroduplex regions.\" << EidosTerminate();\n\t\t\t\n\t\t\tApplyRecombinationCallbacks(parent_individual, parent_haplosome_1, parent_haplosome_2, all_breakpoints, *p_recombination_callbacks);\n\t\t\tnum_breakpoints = (int)all_breakpoints.size();\n\t\t\t\n\t\t\tif (num_breakpoints > 1)\n\t\t\t{\n\t\t\t\tstd::sort(all_breakpoints.begin(), all_breakpoints.end());\n\t\t\t\tall_breakpoints.erase(unique(all_breakpoints.begin(), all_breakpoints.end()), all_breakpoints.end());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// no breakpoints or DSBs, no recombination() callbacks\n\t\t}\n\t}\n\t\n\t// we need a defined end breakpoint, so we add it now\n\tall_breakpoints.emplace_back(p_chromosome.last_position_mutrun_ + 10);\n\t\n\t// A leading zero in the breakpoints vector switches copy strands before copying begins.\n\t// We want to handle that up front, primarily because we don't want to record it in treeseq.\n\t// We only need to do this once, since the breakpoints vector is sorted/uniqued here.\n\t// For efficiency, we switch to a head pointer here; DO NOT USE all_breakpoints HEREAFTER!\n\tslim_position_t *breakpoints_ptr = all_breakpoints.data();\n\tint breakpoints_count = (int)all_breakpoints.size();\n\t\n\tif (*breakpoints_ptr == 0)\t// guaranteed to exist since we added an element above\n\t{\n\t\tbreakpoints_ptr++;\n\t\tbreakpoints_count--;\n\t\tstd::swap(parent_haplosome_1, parent_haplosome_2);\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\tbool recording_tree_sequence = f_treeseq;\n\tbool recording_tree_sequence_mutations = f_treeseq && species_.RecordingTreeSequenceMutations();\n\t\n\tif (recording_tree_sequence)\n\t{\n#pragma omp critical (TreeSeqNewHaplosome)\n\t\t{\n\t\t\tspecies_.RecordNewHaplosome(breakpoints_ptr, breakpoints_count, &p_child_haplosome, parent_haplosome_1, parent_haplosome_2);\n\t\t}\n\t}\n\t\n\t// mutations are usually rare, so let's streamline the case where none occur\n\tif (num_mutations == 0)\n\t{\n\t\tif (num_breakpoints == 0)\n\t\t{\n\t\t\t//\n\t\t\t// no mutations and no crossovers, so the child haplosome is just a copy of the parental haplosome\n\t\t\t//\n\t\t\t\n\t\t\tp_child_haplosome.copy_from_haplosome(*parent_haplosome_1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//\n\t\t\t// no mutations, but we do have crossovers, so we just need to interleave the two parental haplosomes\n\t\t\t//\n\t\t\t\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\tHaplosome *parent_haplosome = parent_haplosome_1;\n\t\t\tslim_position_t mutrun_length = p_child_haplosome.mutrun_length_;\n\t\t\tint mutrun_count = p_child_haplosome.mutrun_count_;\n\t\t\tint first_uncompleted_mutrun = 0;\n\t\t\t\n\t\t\tfor (int break_index = 0; break_index < breakpoints_count; break_index++)\n\t\t\t{\n\t\t\t\tslim_position_t breakpoint = breakpoints_ptr[break_index];\n\t\t\t\tslim_mutrun_index_t break_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\n\t\t\t\t// Copy over mutation runs until we arrive at the run in which the breakpoint occurs\n\t\t\t\twhile (break_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t{\n\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\n\t\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now we are supposed to process a breakpoint in first_uncompleted_mutrun; check whether that means we're done\n\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// The break occurs to the left of the base position of the breakpoint; check whether that is between runs\n\t\t\t\tif (breakpoint > break_mutrun_index * mutrun_length)\n\t\t\t\t{\n\t\t\t\t\t// The breakpoint occurs *inside* the run, so process the run by copying mutations and switching strands\n\t\t\t\t\tint this_mutrun_index = first_uncompleted_mutrun;\n\t\t\t\t\tconst MutationIndex *parent1_iter\t\t= parent_haplosome_1->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *parent2_iter\t\t= parent_haplosome_2->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *parent1_iter_max\t= parent_haplosome_1->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\t\tconst MutationIndex *parent2_iter_max\t= parent_haplosome_2->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\t\tconst MutationIndex *parent_iter\t\t= parent1_iter;\n\t\t\t\t\tconst MutationIndex *parent_iter_max\t= parent1_iter_max;\n\t\t\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(this_mutrun_index);\n\t\t\t\t\tMutationRun *child_mutrun = p_child_haplosome.WillCreateRun_LOCKED(this_mutrun_index, mutrun_context_LOCKED);\n\t\t\t\t\t\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n\t\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((mut_block_ptr + current_mutation)->position_ >= breakpoint)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have now handled the current breakpoint, so move on to the next breakpoint; advance the enclosing for loop here\n\t\t\t\t\t\tbreak_index++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if the next breakpoint is outside this mutation run, then finish the run and break out\n\t\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tbreak_index--;\t// the outer loop will want to handle the current breakpoint again at the mutation-run level\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// We have completed this run\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// The breakpoint occurs *between* runs, so just switch parent strands and the breakpoint is handled\n\t\t\t\t\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// we have at least one new mutation, so set up for that case (which splits into two cases below)\n\t\t\n\t\t// Generate all of the mutation positions as a separate stage, because we need to unique them.  See DrawSortedUniquedMutationPositions.\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#else\n\t\tstatic std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#pragma omp threadprivate (mut_positions)\n#endif\n\t\t\n\t\tmut_positions.resize(0);\n\t\t\n\t\tnum_mutations = p_chromosome.DrawSortedUniquedMutationPositions(num_mutations, parent_sex, mut_positions);\n\t\t\n\t\t// Create vector with the mutations to be added\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<MutationIndex> mutations_to_add;\n#else\n\t\tstatic std::vector<MutationIndex> mutations_to_add;\n#pragma omp threadprivate (mutations_to_add)\n#endif\n\t\t\n\t\tmutations_to_add.resize(0);\n\t\t\n#ifdef _OPENMP\n\t\tbool saw_error_in_critical = false;\n#endif\n\t\t\n\t\t// BCH 7/29/2023: I tried making a simple code path here that generated the new MutationIndex values in a critical region and then\n\t\t// did all the rest of the work outside the critical region.  It wasn't a noticeable win; mutation generation just isn't that\n\t\t// central of a bottleneck.  If you're making so many mutations that contention for this critical region matters, you're probably\n\t\t// completely bogged down in recombination and mutation registry maintenance.  Not worth the added code complexity.\n#pragma omp critical (MutationAlloc)\n\t\t{\n\t\t\ttry {\n\t\t\t\tif (species_.IsNucleotideBased() || (f_callbacks && p_mutation_callbacks))\n\t\t\t\t{\n\t\t\t\t\t// In nucleotide-based models, p_chromosome.DrawNewMutationExtended() will return new mutations to us with nucleotide_ set correctly.\n\t\t\t\t\t// To do that, and to adjust mutation rates correctly, it needs to know which parental haplosome the mutation occurred on the\n\t\t\t\t\t// background of, so that it can get the original nucleotide or trinucleotide context.  This code path is also used if mutation()\n\t\t\t\t\t// callbacks are enabled, since that also wants to be able to see the context of the mutation.\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutationExtended(mut_positions[k], source_subpop->subpopulation_id_, community_.Tick(), parent_haplosome_1, parent_haplosome_2, breakpoints_ptr, breakpoints_count, p_mutation_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutation != -1)\n\t\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// see further comments below, in the non-nucleotide case; they apply here as well\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// In non-nucleotide-based models, p_chromosome.DrawNewMutation() will return new mutations to us with nucleotide_ == -1\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutation(mut_positions[k], source_subpop->subpopulation_id_, community_.Tick());\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// no need to worry about pure_neutral_ or all_pure_neutral_DFE_ here; the mutation is drawn from a registered genomic element type\n\t\t\t\t\t\t// we can't handle the stacking policy here, since we don't yet know what the context of the new mutation will be; we do it below\n\t\t\t\t\t\t// we add the new mutation to the registry below, if the stacking policy says the mutation can actually be added\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\t// DrawNewMutation() / DrawNewMutationExtended() can raise, but it is (presumably) rare; we can leak mutations here\n\t\t\t\t// It occurs primarily with type 's' DFEs; an error in the user's script can cause a raise through here.\n#ifdef _OPENMP\n\t\t\t\tsaw_error_in_critical = true;\t\t// can't throw from a critical region, even when not inside a parallel region!\n#else\n\t\t\t\tthrow;\n#endif\n\t\t\t}\n\t\t}\t// end #pragma omp critical (MutationAlloc)\n\t\t\n#ifdef _OPENMP\n\t\tif (saw_error_in_critical)\n\t\t{\n\t\t\t// Note that the previous error message is still in gEidosTermination, so we just tack an addendum onto it and re-raise, in effect\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): An exception was caught inside a critical region.\" << EidosTerminate();\n\t\t}\n#endif\n\t\t\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tconst MutationIndex *mutation_iter\t\t= mutations_to_add.data();\n\t\tconst MutationIndex *mutation_iter_max\t= mutation_iter + mutations_to_add.size();\n\t\t\n\t\tMutationIndex mutation_iter_mutation_index;\n\t\tslim_position_t mutation_iter_pos;\n\t\t\n\t\tif (mutation_iter != mutation_iter_max) {\n\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t} else {\n\t\t\tmutation_iter_mutation_index = -1;\n\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t}\n\t\t\n\t\tslim_position_t mutrun_length = p_child_haplosome.mutrun_length_;\n\t\tint mutrun_count = p_child_haplosome.mutrun_count_;\n\t\tslim_mutrun_index_t mutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\n\t\tHaplosome *parent_haplosome = parent_haplosome_1;\n\t\tint first_uncompleted_mutrun = 0;\n\t\t\n\t\tif (num_breakpoints == 0)\n\t\t{\n\t\t\t//\n\t\t\t// mutations without breakpoints; we have to be careful here not to touch the second strand, because it could be null\n\t\t\t//\n\t\t\t\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\t// Copy over mutation runs until we arrive at the run in which the mutation occurs\n\t\t\t\twhile (mutation_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t{\n\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\n\t\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// The mutation occurs *inside* the run, so process the run by copying mutations\n\t\t\t\tint this_mutrun_index = first_uncompleted_mutrun;\n\t\t\t\tconst MutationIndex *parent_iter\t\t= parent_haplosome->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent_iter_max\t= parent_haplosome->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(this_mutrun_index);\n\t\t\t\tMutationRun *child_mutrun = p_child_haplosome.WillCreateRun_LOCKED(this_mutrun_index, mutrun_context_LOCKED);\n\t\t\t\t\n\t\t\t\t// add any additional new mutations that occur before the end of the mutation run; there is at least one\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// add any parental mutations that occur before or at the next new mutation's position\n\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\tslim_position_t current_mutation_pos = (mut_block_ptr + current_mutation)->position_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_mutation_pos > mutation_iter_pos)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// add the new mutation, which might overlap with the last added old mutation\n\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t}\n\t\t\t\twhile (mutation_mutrun_index == this_mutrun_index);\n\t\t\t\t\n\t\t\t\t// finish up any parental mutations that come after the last new mutation in the mutation run\n\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\n\t\t\t\t// We have completed this run\n\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\n\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//\n\t\t\t// mutations and crossovers; this is the most complex case\n\t\t\t//\n\t\t\t\n\t\t\tint break_index = 0;\n\t\t\tslim_position_t breakpoint = breakpoints_ptr[break_index];\n\t\t\tslim_mutrun_index_t break_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\n\t\t\twhile (true)\t// loop over breakpoints until we have handled the last one, which comes at the end\n\t\t\t{\n\t\t\t\tif (mutation_mutrun_index < break_mutrun_index)\n\t\t\t\t{\n\t\t\t\t\t// Copy over mutation runs until we arrive at the run in which the mutation occurs\n\t\t\t\t\twhile (mutation_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t\t{\n\t\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// We can't be done, since we have a mutation waiting to be placed, so we don't need to check\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Mutations can't occur between mutation runs the way breakpoints can, so we don't need to check that either\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Copy over mutation runs until we arrive at the run in which the breakpoint occurs\n\t\t\t\t\twhile (break_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t\t{\n\t\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Now we are supposed to process a breakpoint in first_uncompleted_mutrun; check whether that means we're done\n\t\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// If the breakpoint occurs *between* runs, just switch parent strands and the breakpoint is handled\n\t\t\t\t\tif (breakpoint == break_mutrun_index * mutrun_length)\n\t\t\t\t\t{\n\t\t\t\t\t\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// go to next breakpoint; this advances the for loop\n\t\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\t\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The event occurs *inside* the run, so process the run by copying mutations and switching strands\n\t\t\t\tint this_mutrun_index = first_uncompleted_mutrun;\n\t\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(this_mutrun_index);\n\t\t\t\tMutationRun *child_mutrun = p_child_haplosome.WillCreateRun_LOCKED(this_mutrun_index, mutrun_context_LOCKED);\n\t\t\t\tconst MutationIndex *parent1_iter\t\t= parent_haplosome_1->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent1_iter_max\t= parent_haplosome_1->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\tconst MutationIndex *parent_iter\t\t= parent1_iter;\n\t\t\t\tconst MutationIndex *parent_iter_max\t= parent1_iter_max;\n\t\t\t\t\n\t\t\t\tif (break_mutrun_index == this_mutrun_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationIndex *parent2_iter\t\t= parent_haplosome_2->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *parent2_iter_max\t= parent_haplosome_2->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tif (mutation_mutrun_index == this_mutrun_index)\n\t\t\t\t\t{\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// =====  this_mutrun_index has both breakpoint(s) and new mutation(s); this is the really nasty case\n\t\t\t\t\t\t//\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\t\tslim_position_t current_mutation_pos = (mut_block_ptr + current_mutation)->position_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (current_mutation_pos >= breakpoint)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// add any new mutations that occur before the parental mutation; we know the parental mutation is in this run, so these are too\n\t\t\t\t\t\t\t\twhile (mutation_iter_pos < current_mutation_pos)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// add any new mutations that occur before the breakpoint; for these we have to check that they fall within this mutation run\n\t\t\t\t\t\t\twhile ((mutation_iter_pos < breakpoint) && (mutation_mutrun_index == this_mutrun_index))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we have finished the parental mutation run; if the breakpoint we are now working toward lies beyond the end of the\n\t\t\t\t\t\t\t// current mutation run, then we have completed this run and can exit to the outer loop which will handle the rest\n\t\t\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t\t\t\tbreak;\t\t// the outer loop will want to handle this breakpoint again at the mutation-run level\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we have now handled the current breakpoint, so move on; if we just handled the last breakpoint, then we are done\n\t\t\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// We have completed this run\n\t\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// =====  this_mutrun_index has only breakpoint(s), no new mutations\n\t\t\t\t\t\t//\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((mut_block_ptr + current_mutation)->position_ >= breakpoint)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we have now handled the current breakpoint, so move on; if we just handled the last breakpoint, then we are done\n\t\t\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// if the next breakpoint is outside this mutation run, then finish the run and break out\n\t\t\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tbreak;\t// the outer loop will want to handle this breakpoint again at the mutation-run level\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// We have completed this run\n\t\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (mutation_mutrun_index == this_mutrun_index)\n\t\t\t\t{\n\t\t\t\t\t//\n\t\t\t\t\t// =====  this_mutrun_index has only new mutation(s), no breakpoints\n\t\t\t\t\t//\n\t\t\t\t\t\n\t\t\t\t\t// add any additional new mutations that occur before the end of the mutation run; there is at least one\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// add any parental mutations that occur before or at the next new mutation's position\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\tslim_position_t current_mutation_pos = (mut_block_ptr + current_mutation)->position_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_mutation_pos > mutation_iter_pos)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// add the new mutation, which might overlap with the last added old mutation\n\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t}\n\t\t\t\t\twhile (mutation_mutrun_index == this_mutrun_index);\n\t\t\t\t\t\n\t\t\t\t\t// finish up any parental mutations that come after the last new mutation in the mutation run\n\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\t\n\t\t\t\t\t// We have completed this run\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): (internal error) logic fail.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// debugging check\n#if 0\n\tfor (int i = 0; i < child_haplosome.mutrun_count_; ++i)\n\t\tif (child_haplosome.mutruns_[i].get() == nullptr)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCrossed): (internal error) null mutation run left at end of crossover-mutation.\" << EidosTerminate();\n#endif\n\t\n\tif (heteroduplex.size() > 0)\n\t\tDoHeteroduplexRepair(heteroduplex, breakpoints_ptr, breakpoints_count, parent_haplosome_1, parent_haplosome_2, &p_child_haplosome);\n}\n\ntemplate void Population::HaplosomeCrossed<false, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCrossed<false, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCrossed<true, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCrossed<true, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\n// generate a child haplosome from parental haplosomes, clonally with mutation\ntemplate <const bool f_treeseq, const bool f_callbacks>\nvoid Population::HaplosomeCloned(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks)\n{\n#if DEBUG\n\t// This method is designed to run in parallel, but only if no callbacks are enabled\n\tif (p_mutation_callbacks)\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::HaplosomeCloned(): mutation callbacks are not allowed when executing in parallel\");\n\t\n\tif (!p_child_haplosome.individual_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCloned): (internal error) individual_ pointer for child haplosome not set.\" << EidosTerminate();\n\t\n\t// BCH 9/20/2024: With the multichomosome redesign, the child and parent haplosome types must always match; we are generating a\n\t// new offspring haplosome clonally for a parental haplosome of the same type\n\tslim_chromosome_index_t chromosome_index = p_child_haplosome.chromosome_index_;\n\tslim_chromosome_index_t parent_chromosome_index = parent_haplosome->chromosome_index_;\n\t\n\tif (parent_chromosome_index != chromosome_index)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCloned): (internal error) mismatch between parent and child chromosomes (child chromosome index == \" << chromosome_index << \", parent == \" << parent_chromosome_index << \").\" << EidosTerminate();\n\t\n\tif (p_child_haplosome.IsNull() || parent_haplosome->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCloned): (internal error) null haplosomes cannot be passed to HaplosomeCloned().\" << EidosTerminate();\n\t\n\tHaplosome::DebugCheckStructureMatch(parent_haplosome, &p_child_haplosome, &p_chromosome);\n#endif\n#if SLIM_CLEAR_HAPLOSOMES\n\t// start with a clean slate in the child haplosome; we now expect child haplosomes to be cleared for us\n\tp_child_haplosome.check_cleared_to_nullptr();\n#endif\n\t\n\t// some behaviors -- which callbacks to use, which recombination/mutation rate to use, subpop of origin for mutations, etc. --\n\t// depend upon characteristics of the first parent, so we fetch the necessary properties here\n\tSubpopulation *source_subpop = parent_haplosome->individual_->subpopulation_;\n\tIndividualSex parent_sex = parent_haplosome->individual_->sex_;\n\n\t// determine how many mutations and breakpoints we have\n\tint num_mutations = p_chromosome.DrawMutationCount(parent_sex);\t// the parent sex is the same as the child sex\n\t\n\t// TREE SEQUENCE RECORDING\n\t// FIXME MULTICHROM separate critical region for each chromosome, too!\n\tbool recording_tree_sequence = f_treeseq;\n\tbool recording_tree_sequence_mutations = f_treeseq && species_.RecordingTreeSequenceMutations();\n\t\n\tif (recording_tree_sequence)\n\t{\n#pragma omp critical (TreeSeqNewHaplosome)\n\t\t{\n\t\t\tspecies_.RecordNewHaplosome(nullptr, 0, &p_child_haplosome, parent_haplosome, nullptr);\n\t\t}\n\t}\n\t\n\t// mutations are usually rare, so let's streamline the case where none occur\n\tif (num_mutations == 0)\n\t{\n\t\t// no mutations, so the child haplosome is just a copy of the parental haplosome\n\t\tp_child_haplosome.copy_from_haplosome(*parent_haplosome);\n\t}\n\telse\n\t{\n\t\t// Generate all of the mutation positions as a separate stage, because we need to unique them.  See DrawSortedUniquedMutationPositions.\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#else\n\t\tstatic std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#pragma omp threadprivate (mut_positions)\n#endif\n\t\t\n\t\tmut_positions.resize(0);\n\t\t\n\t\tnum_mutations = p_chromosome.DrawSortedUniquedMutationPositions(num_mutations, parent_sex, mut_positions);\n\t\t\n\t\t// Create vector with the mutations to be added\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<MutationIndex> mutations_to_add;\n#else\n\t\tstatic std::vector<MutationIndex> mutations_to_add;\n#pragma omp threadprivate (mutations_to_add)\n#endif\n\t\t\n\t\tmutations_to_add.resize(0);\n\t\t\n#ifdef _OPENMP\n\t\tbool saw_error_in_critical = false;\n#endif\n\t\t\n#pragma omp critical (MutationAlloc)\n\t\t{\n\t\t\ttry {\n\t\t\t\tif (species_.IsNucleotideBased() || (f_callbacks && p_mutation_callbacks))\n\t\t\t\t{\n\t\t\t\t\t// In nucleotide-based models, p_chromosome.DrawNewMutationExtended() will return new mutations to us with nucleotide_ set correctly.\n\t\t\t\t\t// To do that, and to adjust mutation rates correctly, it needs to know which parental haplosome the mutation occurred on the\n\t\t\t\t\t// background of, so that it can get the original nucleotide or trinucleotide context.  This code path is also used if mutation()\n\t\t\t\t\t// callbacks are enabled, since that also wants to be able to see the context of the mutation.\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutationExtended(mut_positions[k], source_subpop->subpopulation_id_, community_.Tick(), parent_haplosome, nullptr, nullptr, 0, p_mutation_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutation != -1)\n\t\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// see further comments below, in the non-nucleotide case; they apply here as well\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// In non-nucleotide-based models, chromosome.DrawNewMutation() will return new mutations to us with nucleotide_ == -1\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutation(mut_positions[k], source_subpop->subpopulation_id_, community_.Tick());\t// the parent sex is the same as the child sex\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// no need to worry about pure_neutral_ or all_pure_neutral_DFE_ here; the mutation is drawn from a registered genomic element type\n\t\t\t\t\t\t// we can't handle the stacking policy here, since we don't yet know what the context of the new mutation will be; we do it below\n\t\t\t\t\t\t// we add the new mutation to the registry below, if the stacking policy says the mutation can actually be added\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\t// DrawNewMutation() / DrawNewMutationExtended() can raise, but it is (presumably) rare; we can leak mutations here\n\t\t\t\t// It occurs primarily with type 's' DFEs; an error in the user's script can cause a raise through here.\n#ifdef _OPENMP\n\t\t\t\tsaw_error_in_critical = true;\t\t// can't throw from a critical region, even when not inside a parallel region!\n#else\n\t\t\t\tthrow;\n#endif\n\t\t\t}\n\t\t}\t// end #pragma omp critical (MutationAlloc)\n\t\t\n#ifdef _OPENMP\n\t\tif (saw_error_in_critical)\n\t\t{\n\t\t\t// Note that the previous error message is still in gEidosTermination, so we just tack an addendum onto it and re-raise, in effect\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeCloned): An exception was caught inside a critical region.\" << EidosTerminate();\n\t\t}\n#endif\n\t\t\n\t\t// if there are no mutations, the child haplosome is just a copy of the parental haplosome\n\t\t// this can happen with nucleotide-based models because -1 can be returned by DrawNewMutationExtended()\n\t\tif (mutations_to_add.size() == 0)\n\t\t{\n\t\t\tp_child_haplosome.copy_from_haplosome(*parent_haplosome);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// loop over mutation runs and either (1) copy the mutrun pointer from the parent, or (2) make a new mutrun by modifying that of the parent\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\tint mutrun_count = p_child_haplosome.mutrun_count_;\n\t\tslim_position_t mutrun_length = p_child_haplosome.mutrun_length_;\n\t\t\n\t\tconst MutationIndex *mutation_iter\t\t= mutations_to_add.data();\n\t\tconst MutationIndex *mutation_iter_max\t= mutation_iter + mutations_to_add.size();\n\t\tMutationIndex mutation_iter_mutation_index = *mutation_iter;\n\t\tslim_position_t mutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\tslim_mutrun_index_t mutation_iter_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tif (mutation_iter_mutrun_index > run_index)\n\t\t\t{\n\t\t\t\t// no mutations in this run, so just copy the run pointer\n\t\t\t\tp_child_haplosome.mutruns_[run_index] = parent_haplosome->mutruns_[run_index];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// interleave the parental haplosome with the new mutations\n\t\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\tMutationRun *child_run = p_child_haplosome.WillCreateRun_LOCKED(run_index, mutrun_context_LOCKED);\n\t\t\t\tconst MutationRun *parent_run = parent_haplosome->mutruns_[run_index];\n\t\t\t\tconst MutationIndex *parent_iter\t\t= parent_run->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent_iter_max\t= parent_run->end_pointer_const();\n\t\t\t\t\n\t\t\t\t// while there is at least one new mutation left to place in this run... (which we know is true when we first reach here)\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// while an old mutation in the parent is before or at the next new mutation...\n\t\t\t\t\twhile ((parent_iter != parent_iter_max) && ((mut_block_ptr + *parent_iter)->position_ <= mutation_iter_pos))\n\t\t\t\t\t{\n\t\t\t\t\t\t// we know the mutation is not already present, since mutations on the parent strand are already uniqued,\n\t\t\t\t\t\t// and new mutations are, by definition, new and thus cannot match the existing mutations\n\t\t\t\t\t\tchild_run->emplace_back(*parent_iter);\n\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// while a new mutation in this run is before the next old mutation in the parent... (which we know is true when we first reach here)\n\t\t\t\t\tslim_position_t parent_iter_pos = (parent_iter == parent_iter_max) ? (SLIM_INF_BASE_POSITION) : (mut_block_ptr + *parent_iter)->position_;\n\t\t\t\t\t\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// we know the mutation is not already present, since mutations on the parent strand are already uniqued,\n\t\t\t\t\t\t// and new mutations are, by definition, new and thus cannot match the existing mutations\n\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (child_run->enforce_stack_policy_for_addition(mutation_iter_pos, new_mut_type))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\tchild_run->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, mutation_iter_pos, *child_run->derived_mutation_ids_at_position(mutation_iter_pos));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// move to the next mutation\n\t\t\t\t\t\tmutation_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutation_iter == mutation_iter_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutation_iter_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we're out of new mutations for this run, transfer down to the simpler loop below\n\t\t\t\t\t\tif (mutation_iter_mutrun_index != run_index)\n\t\t\t\t\t\t\tgoto noNewMutationsLeft;\n\t\t\t\t\t}\n\t\t\t\t\twhile (mutation_iter_pos < parent_iter_pos);\n\t\t\t\t\t\n\t\t\t\t\t// at this point we know we have a new mutation to place in this run, but it falls after the next parental mutation, so we loop back\n\t\t\t\t}\n\t\t\t\twhile (true);\n\t\t\t\t\n\t\t\t\t// complete the mutation run after all new mutations within this run have been placed\n\t\t\tnoNewMutationsLeft:\n\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t{\n\t\t\t\t\tchild_run->emplace_back(*parent_iter);\n\t\t\t\t\tparent_iter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate void Population::HaplosomeCloned<false, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCloned<false, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCloned<true, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeCloned<true, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\n// generate a child haplosome from parental haplosomes, with recombination and mutation, and user-specified breakpoints\ntemplate <const bool f_treeseq, const bool f_callbacks>\nvoid Population::HaplosomeRecombined(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks)\n{\n#if DEBUG\n\t// This method is designed to run in parallel, but only if no callbacks are enabled\n\tif (p_mutation_callbacks)\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::HaplosomeRecombined(): recombination and mutation callbacks are not allowed when executing in parallel\");\n\t\n\tif (p_breakpoints.size() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) Called with an empty breakpoint array.\" << EidosTerminate();\n\t\n\tif (!parent_haplosome_1 || !parent_haplosome_2)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) Null haplosome pointer.\" << EidosTerminate();\n\t\n\tif (!p_child_haplosome.individual_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) individual_ pointer for child haplosome not set.\" << EidosTerminate();\n\t\n\t// BCH 9/20/2024: With the multichomosome redesign, the child and parent haplosome indices must always match; we are generating a\n\t// new offspring haplosome from parental haplosomes of the exact same chromosome (not just the same chomosome type).\n\tslim_chromosome_index_t chromosome_index = p_child_haplosome.chromosome_index_;\n\tslim_chromosome_index_t parent1_chromosome_index = parent_haplosome_1->chromosome_index_;\n\tslim_chromosome_index_t parent2_chromosome_index = parent_haplosome_2->chromosome_index_;\n\t\n\tif ((parent1_chromosome_index != chromosome_index) || (parent2_chromosome_index != chromosome_index))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) mismatch between parent and child chromosomes (child chromosome index == \" << chromosome_index << \", parent 1 == \" << parent1_chromosome_index << \", parent 2 == \" << parent2_chromosome_index << \").\" << EidosTerminate();\n\t\n\tif (p_child_haplosome.IsNull() || parent_haplosome_1->IsNull() || parent_haplosome_2->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) null haplosomes cannot be passed to HaplosomeRecombined().\" << EidosTerminate();\n\t\n\tHaplosome::DebugCheckStructureMatch(parent_haplosome_1, parent_haplosome_2, &p_child_haplosome, &p_chromosome);\n#endif\n#if SLIM_CLEAR_HAPLOSOMES\n\t// start with a clean slate in the child haplosome; we now expect child haplosomes to be cleared for us\n\tp_child_haplosome.check_cleared_to_nullptr();\n#endif\n\t\n\t// for addRecombinant() and addMultiRecombinant(), we use the destination subpop as the mutation origin\n\tSubpopulation *dest_subpop = p_child_haplosome.individual_->subpopulation_;\n\t\n\t// The parent sex is used for mutation generation; we might have sex-specific mutation\n\t// rates.  Which parent to use to determine the sex-specific mutation rate is ambiguous.\n\t// At present, the caller guarantees that the two parents are of the same sex, if sex-\n\t// specific mutation rates are in use, so we can just use parent_haplosome_1's sex.\n\tIndividualSex parent_sex = parent_haplosome_1->individual_->sex_;\n\t\n\t// determine how many mutations we have\n\tint num_mutations = p_chromosome.DrawMutationCount(parent_sex);\n\t\n\t// we need a defined end breakpoint, so we add it now; we don't want more than one, though,\n\t// and in some cases the caller might already have this breakpoint added, so we need to\n\t// check (that happens with multiple children in addRecombinant(), for example)\n\tif ((p_breakpoints.size() == 0) || (p_breakpoints.back() <= p_chromosome.last_position_mutrun_))\n\t\tp_breakpoints.emplace_back(p_chromosome.last_position_mutrun_ + 10);\n\t\n\t// A leading zero in the breakpoints vector switches copy strands before copying begins.\n\t// We want to handle that up front, primarily because we don't want to record it in treeseq.\n\t// We only need to do this once, since the breakpoints vector is sorted/uniqued here.\n\t// For efficiency, we switch to a head pointer here; DO NOT USE p_breakpoints HEREAFTER!\n\tslim_position_t *breakpoints_ptr = p_breakpoints.data();\n\tint breakpoints_count = (int)p_breakpoints.size();\n\t\n\tif (*breakpoints_ptr == 0)\t// guaranteed to exist since we added an element above\n\t{\n\t\tbreakpoints_ptr++;\n\t\tbreakpoints_count--;\n\t\tstd::swap(parent_haplosome_1, parent_haplosome_2);\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\tbool recording_tree_sequence = f_treeseq;\n\tbool recording_tree_sequence_mutations = f_treeseq && species_.RecordingTreeSequenceMutations();\n\t\n\tif (recording_tree_sequence)\n\t{\n#pragma omp critical (TreeSeqNewHaplosome)\n\t\t{\n\t\t\tspecies_.RecordNewHaplosome(breakpoints_ptr, breakpoints_count, &p_child_haplosome, parent_haplosome_1, parent_haplosome_2);\n\t\t}\n\t}\n\t\n\t// mutations are usually rare, so let's streamline the case where none occur\n\tif (num_mutations == 0)\n\t{\n\t\t//\n\t\t// no mutations, but we do have crossovers, so we just need to interleave the two parental haplosomes\n\t\t//\n\t\t\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tHaplosome *parent_haplosome = parent_haplosome_1;\n\t\tslim_position_t mutrun_length = p_child_haplosome.mutrun_length_;\n\t\tint mutrun_count = p_child_haplosome.mutrun_count_;\n\t\tint first_uncompleted_mutrun = 0;\n\t\t\n\t\tfor (int break_index = 0; break_index < breakpoints_count; break_index++)\n\t\t{\n\t\t\tslim_position_t breakpoint = breakpoints_ptr[break_index];\n\t\t\tslim_mutrun_index_t break_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\n\t\t\t// Copy over mutation runs until we arrive at the run in which the breakpoint occurs\n\t\t\twhile (break_mutrun_index > first_uncompleted_mutrun)\n\t\t\t{\n\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\n\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// Now we are supposed to process a breakpoint in first_uncompleted_mutrun; check whether that means we're done\n\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// The break occurs to the left of the base position of the breakpoint; check whether that is between runs\n\t\t\tif (breakpoint > break_mutrun_index * mutrun_length)\n\t\t\t{\n\t\t\t\t// The breakpoint occurs *inside* the run, so process the run by copying mutations and switching strands\n\t\t\t\tint this_mutrun_index = first_uncompleted_mutrun;\n\t\t\t\tconst MutationIndex *parent1_iter\t\t= parent_haplosome_1->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent2_iter\t\t= parent_haplosome_2->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent1_iter_max\t= parent_haplosome_1->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\tconst MutationIndex *parent2_iter_max\t= parent_haplosome_2->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\tconst MutationIndex *parent_iter\t\t= parent1_iter;\n\t\t\t\tconst MutationIndex *parent_iter_max\t= parent1_iter_max;\n\t\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(this_mutrun_index);\n\t\t\t\tMutationRun *child_mutrun = p_child_haplosome.WillCreateRun_LOCKED(this_mutrun_index, mutrun_context_LOCKED);\n\t\t\t\t\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((mut_block_ptr + current_mutation)->position_ >= breakpoint)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\n\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\n\t\t\t\t\t// we have now handled the current breakpoint, so move on to the next breakpoint; advance the enclosing for loop here\n\t\t\t\t\tbreak_index++;\n\t\t\t\t\t\n\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\n\t\t\t\t\t// if the next breakpoint is outside this mutation run, then finish the run and break out\n\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t{\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak_index--;\t// the outer loop will want to handle the current breakpoint again at the mutation-run level\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We have completed this run\n\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The breakpoint occurs *between* runs, so just switch parent strands and the breakpoint is handled\n\t\t\t\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// we have at least one new mutation, so set up for that case (which splits into two cases below)\n\t\t\n\t\t// Generate all of the mutation positions as a separate stage, because we need to unique them.  See DrawSortedUniquedMutationPositions.\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#else\n\t\tstatic std::vector<std::pair<slim_position_t, GenomicElement *>> mut_positions;\n#pragma omp threadprivate (mut_positions)\n#endif\n\t\t\n\t\tmut_positions.resize(0);\n\t\t\n\t\tnum_mutations = p_chromosome.DrawSortedUniquedMutationPositions(num_mutations, parent_sex, mut_positions);\n\t\t\n\t\t// Create vector with the mutations to be added\n#if defined(__GNUC__) && !defined(__clang__)\n\t\t// Work around GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27557\n\t\tstatic thread_local std::vector<MutationIndex> mutations_to_add;\n#else\n\t\tstatic std::vector<MutationIndex> mutations_to_add;\n#pragma omp threadprivate (mutations_to_add)\n#endif\n\t\t\n\t\tmutations_to_add.resize(0);\n\t\t\n#ifdef _OPENMP\n\t\tbool saw_error_in_critical = false;\n#endif\n\t\t\n#pragma omp critical (MutationAlloc)\n\t\t{\n\t\t\ttry {\n\t\t\t\tif (species_.IsNucleotideBased() || (f_callbacks && p_mutation_callbacks))\n\t\t\t\t{\n\t\t\t\t\t// In nucleotide-based models, p_chromosome.DrawNewMutationExtended() will return new mutations to us with nucleotide_ set correctly.\n\t\t\t\t\t// To do that, and to adjust mutation rates correctly, it needs to know which parental haplosome the mutation occurred on the\n\t\t\t\t\t// background of, so that it can get the original nucleotide or trinucleotide context.  This code path is also used if mutation()\n\t\t\t\t\t// callbacks are enabled, since that also wants to be able to see the context of the mutation.\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutationExtended(mut_positions[k], dest_subpop->subpopulation_id_, community_.Tick(), parent_haplosome_1, parent_haplosome_2, breakpoints_ptr, breakpoints_count, p_mutation_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutation != -1)\n\t\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// see further comments below, in the non-nucleotide case; they apply here as well\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// In non-nucleotide-based models, p_chromosome.DrawNewMutation() will return new mutations to us with nucleotide_ == -1\n\t\t\t\t\tfor (int k = 0; k < num_mutations; k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex new_mutation = p_chromosome.DrawNewMutation(mut_positions[k], dest_subpop->subpopulation_id_, community_.Tick());\n\t\t\t\t\t\t\n\t\t\t\t\t\tmutations_to_add.emplace_back(new_mutation);\t\t\t// positions are already sorted\n\t\t\t\t\t\t\n\t\t\t\t\t\t// no need to worry about pure_neutral_ or all_pure_neutral_DFE_ here; the mutation is drawn from a registered genomic element type\n\t\t\t\t\t\t// we can't handle the stacking policy here, since we don't yet know what the context of the new mutation will be; we do it below\n\t\t\t\t\t\t// we add the new mutation to the registry below, if the stacking policy says the mutation can actually be added\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (...) {\n\t\t\t\t// DrawNewMutation() / DrawNewMutationExtended() can raise, but it is (presumably) rare; we can leak mutations here\n\t\t\t\t// It occurs primarily with type 's' DFEs; an error in the user's script can cause a raise through here.\n#ifdef _OPENMP\n\t\t\t\tsaw_error_in_critical = true;\t\t// can't throw from a critical region, even when not inside a parallel region!\n#else\n\t\t\t\tthrow;\n#endif\n\t\t\t}\n\t\t}\t// end #pragma omp critical (MutationAlloc)\n\t\t\n#ifdef _OPENMP\n\t\tif (saw_error_in_critical)\n\t\t{\n\t\t\t// Note that the previous error message is still in gEidosTermination, so we just tack an addendum onto it and re-raise, in effect\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): An exception was caught inside a critical region.\" << EidosTerminate();\n\t\t}\n#endif\n\t\t\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tconst MutationIndex *mutation_iter\t\t= mutations_to_add.data();\n\t\tconst MutationIndex *mutation_iter_max\t= mutation_iter + mutations_to_add.size();\n\t\t\n\t\tMutationIndex mutation_iter_mutation_index;\n\t\tslim_position_t mutation_iter_pos;\n\t\t\n\t\tif (mutation_iter != mutation_iter_max) {\n\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t} else {\n\t\t\tmutation_iter_mutation_index = -1;\n\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t}\n\t\t\n\t\tslim_position_t mutrun_length = p_child_haplosome.mutrun_length_;\n\t\tint mutrun_count = p_child_haplosome.mutrun_count_;\n\t\tslim_mutrun_index_t mutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\n\t\tHaplosome *parent_haplosome = parent_haplosome_1;\n\t\tint first_uncompleted_mutrun = 0;\n\t\t\n\t\t//\n\t\t// mutations and crossovers; this is the most complex case\n\t\t//\n\t\tint break_index = 0;\n\t\tslim_position_t breakpoint = breakpoints_ptr[break_index];\n\t\tslim_mutrun_index_t break_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\n\t\twhile (true)\t// loop over breakpoints until we have handled the last one, which comes at the end\n\t\t{\n\t\t\tif (mutation_mutrun_index < break_mutrun_index)\n\t\t\t{\n\t\t\t\t// Copy over mutation runs until we arrive at the run in which the mutation occurs\n\t\t\t\twhile (mutation_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t{\n\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\n\t\t\t\t\t// We can't be done, since we have a mutation waiting to be placed, so we don't need to check\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Mutations can't occur between mutation runs the way breakpoints can, so we don't need to check that either\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Copy over mutation runs until we arrive at the run in which the breakpoint occurs\n\t\t\t\twhile (break_mutrun_index > first_uncompleted_mutrun)\n\t\t\t\t{\n\t\t\t\t\tp_child_haplosome.mutruns_[first_uncompleted_mutrun] = parent_haplosome->mutruns_[first_uncompleted_mutrun];\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t\t\n\t\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Now we are supposed to process a breakpoint in first_uncompleted_mutrun; check whether that means we're done\n\t\t\t\tif (first_uncompleted_mutrun >= mutrun_count)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// If the breakpoint occurs *between* runs, just switch parent strands and the breakpoint is handled\n\t\t\t\tif (breakpoint == break_mutrun_index * mutrun_length)\n\t\t\t\t{\n\t\t\t\t\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\n\t\t\t\t\t// go to next breakpoint; this advances the for loop\n\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// The event occurs *inside* the run, so process the run by copying mutations and switching strands\n\t\t\tint this_mutrun_index = first_uncompleted_mutrun;\n\t\t\tMutationRunContext &mutrun_context_LOCKED = p_chromosome.ChromosomeMutationRunContextForMutationRunIndex(this_mutrun_index);\n\t\t\tMutationRun *child_mutrun = p_child_haplosome.WillCreateRun_LOCKED(this_mutrun_index, mutrun_context_LOCKED);\n\t\t\tconst MutationIndex *parent1_iter\t\t= parent_haplosome_1->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\tconst MutationIndex *parent1_iter_max\t= parent_haplosome_1->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\tconst MutationIndex *parent_iter\t\t= parent1_iter;\n\t\t\tconst MutationIndex *parent_iter_max\t= parent1_iter_max;\n\t\t\t\n\t\t\tif (break_mutrun_index == this_mutrun_index)\n\t\t\t{\n\t\t\t\tconst MutationIndex *parent2_iter\t\t= parent_haplosome_2->mutruns_[this_mutrun_index]->begin_pointer_const();\n\t\t\t\tconst MutationIndex *parent2_iter_max\t= parent_haplosome_2->mutruns_[this_mutrun_index]->end_pointer_const();\n\t\t\t\t\n\t\t\t\tif (mutation_mutrun_index == this_mutrun_index)\n\t\t\t\t{\n\t\t\t\t\t//\n\t\t\t\t\t// =====  this_mutrun_index has both breakpoint(s) and new mutation(s); this is the really nasty case\n\t\t\t\t\t//\n\t\t\t\t\t\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n\t\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\tslim_position_t current_mutation_pos = (mut_block_ptr + current_mutation)->position_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_mutation_pos >= breakpoint)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// add any new mutations that occur before the parental mutation; we know the parental mutation is in this run, so these are too\n\t\t\t\t\t\t\twhile (mutation_iter_pos < current_mutation_pos)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// add any new mutations that occur before the breakpoint; for these we have to check that they fall within this mutation run\n\t\t\t\t\t\twhile ((mutation_iter_pos < breakpoint) && (mutation_mutrun_index == this_mutrun_index))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have finished the parental mutation run; if the breakpoint we are now working toward lies beyond the end of the\n\t\t\t\t\t\t// current mutation run, then we have completed this run and can exit to the outer loop which will handle the rest\n\t\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t\t\tbreak;\t\t// the outer loop will want to handle this breakpoint again at the mutation-run level\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have now handled the current breakpoint, so move on; if we just handled the last breakpoint, then we are done\n\t\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// We have completed this run\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//\n\t\t\t\t\t// =====  this_mutrun_index has only breakpoint(s), no new mutations\n\t\t\t\t\t//\n\t\t\t\t\t\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n\t\t\t\t\t\t// while there are still old mutations in the parent before the current breakpoint...\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((mut_block_ptr + current_mutation)->position_ >= breakpoint)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// add the old mutation; no need to check for a duplicate here since the parental haplosome is already duplicate-free\n\t\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have reached the breakpoint, so swap parents; we want the \"current strand\" variables to change, so no std::swap()\n\t\t\t\t\t\tparent1_iter = parent2_iter;\tparent1_iter_max = parent2_iter_max;\tparent_haplosome_1 = parent_haplosome_2;\n\t\t\t\t\t\tparent2_iter = parent_iter;\t\tparent2_iter_max = parent_iter_max;\t\tparent_haplosome_2 = parent_haplosome;\n\t\t\t\t\t\tparent_iter = parent1_iter;\t\tparent_iter_max = parent1_iter_max;\t\tparent_haplosome = parent_haplosome_1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// skip over anything in the new parent that occurs prior to the breakpoint; it was not the active strand\n\t\t\t\t\t\twhile (parent_iter != parent_iter_max && (mut_block_ptr + *parent_iter)->position_ < breakpoint)\n\t\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we have now handled the current breakpoint, so move on; if we just handled the last breakpoint, then we are done\n\t\t\t\t\t\tif (++break_index == breakpoints_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// otherwise, figure out the new breakpoint, and continue looping on the current mutation run, which needs to be finished\n\t\t\t\t\t\tbreakpoint = breakpoints_ptr[break_index];\n\t\t\t\t\t\tbreak_mutrun_index = (slim_mutrun_index_t)(breakpoint / mutrun_length);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if the next breakpoint is outside this mutation run, then finish the run and break out\n\t\t\t\t\t\tif (break_mutrun_index > this_mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tbreak;\t// the outer loop will want to handle this breakpoint again at the mutation-run level\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// if we just handled the last breakpoint, which is guaranteed to be at or beyond lastPosition+1, then we are done\n\t\t\t\t\tif (break_index == breakpoints_count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// We have completed this run\n\t\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (mutation_mutrun_index == this_mutrun_index)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// =====  this_mutrun_index has only new mutation(s), no breakpoints\n\t\t\t\t//\n\t\t\t\t\n\t\t\t\t// add any additional new mutations that occur before the end of the mutation run; there is at least one\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// add any parental mutations that occur before or at the next new mutation's position\n\t\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\t{\n\t\t\t\t\t\tMutationIndex current_mutation = *parent_iter;\n\t\t\t\t\t\tslim_position_t current_mutation_pos = (mut_block_ptr + current_mutation)->position_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_mutation_pos > mutation_iter_pos)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\tchild_mutrun->emplace_back(current_mutation);\n\t\t\t\t\t\tparent_iter++;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// add the new mutation, which might overlap with the last added old mutation\n\t\t\t\t\tMutation *new_mut = mut_block_ptr + mutation_iter_mutation_index;\n\t\t\t\t\tMutationType *new_mut_type = new_mut->mutation_type_ptr_;\n\t\t\t\t\t\n\t\t\t\t\tif (child_mutrun->enforce_stack_policy_for_addition(new_mut->position_, new_mut_type))\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation was passed by the stacking policy, so we can add it to the child haplosome and the registry\n\t\t\t\t\t\tchild_mutrun->emplace_back(mutation_iter_mutation_index);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mut->state_ != MutationState::kInRegistry)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t#pragma omp critical (MutationRegistryAdd)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutationRegistryAdd(new_mut);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\t\t\tif (recording_tree_sequence_mutations)\n\t\t\t\t\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tspecies_.RecordNewDerivedState(&p_child_haplosome, new_mut->position_, *child_mutrun->derived_mutation_ids_at_position(new_mut->position_));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (new_mut->state_ == MutationState::kNewMutation)\t// new and needs to be disposed of\n\t\t\t\t\t{\n\t\t\t\t\t\t// The mutation was rejected by the stacking policy, so we have to release it\n#pragma omp critical (MutationAlloc)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnew_mut->Release_PARALLEL();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (++mutation_iter != mutation_iter_max) {\n\t\t\t\t\t\tmutation_iter_mutation_index = *mutation_iter;\n\t\t\t\t\t\tmutation_iter_pos = (mut_block_ptr + mutation_iter_mutation_index)->position_;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmutation_iter_mutation_index = -1;\n\t\t\t\t\t\tmutation_iter_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmutation_mutrun_index = (slim_mutrun_index_t)(mutation_iter_pos / mutrun_length);\n\t\t\t\t}\n\t\t\t\twhile (mutation_mutrun_index == this_mutrun_index);\n\t\t\t\t\n\t\t\t\t// finish up any parental mutations that come after the last new mutation in the mutation run\n\t\t\t\twhile (parent_iter != parent_iter_max)\n\t\t\t\t\tchild_mutrun->emplace_back(*(parent_iter++));\n\t\t\t\t\n\t\t\t\t// We have completed this run\n\t\t\t\t++first_uncompleted_mutrun;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) logic fail.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// debugging check\n#if 0\n\tfor (int i = 0; i < child_haplosome.mutrun_count_; ++i)\n\t\tif (child_haplosome.mutruns_[i].get() == nullptr)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::HaplosomeRecombined): (internal error) null mutation run left at end of recombination-mutation.\" << EidosTerminate();\n#endif\n}\n\ntemplate void Population::HaplosomeRecombined<false, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeRecombined<false, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeRecombined<true, false>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\ntemplate void Population::HaplosomeRecombined<true, true>(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\nvoid Population::DoHeteroduplexRepair(std::vector<slim_position_t> &p_heteroduplex, slim_position_t *p_breakpoints, int p_breakpoints_count, Haplosome *p_parent_haplosome_1, Haplosome *p_parent_haplosome_2, Haplosome *p_child_haplosome)\n{\n#if DEBUG\n\tif (!p_child_haplosome->individual_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::DoHeteroduplexRepair): (internal error) The child haplosome must have an owning individual.\" << EidosTerminate();\n\tif ((p_parent_haplosome_1->chromosome_index_ != p_parent_haplosome_2->chromosome_index_) ||\n\t\t(p_parent_haplosome_1->chromosome_index_ != p_child_haplosome->chromosome_index_))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::DoHeteroduplexRepair): (internal error) The child haplosome and parent haplosomes must all have the same associated chromosome.\" << EidosTerminate();\n#endif\n\t\n\t// Heteroduplex mismatch repair handling: heteroduplex contains a set of start/end position\n\t// pairs, representing stretches of the offspring haplosome that result from \"complex\" gene\n\t// conversion tracts where the two homologous parental strands ended up paired, even though\n\t// their sequences do not necessarily match.  The code above designated one parental strand\n\t// as the ancestral strand, for purposes of generating the offspring haplosome and recording\n\t// ancestry with tree-sequence recording.  We now need to handle mismatch repair.  For each\n\t// heteroduplex stretch, we want to (1) determine which parental strand was considered to be\n\t// ancestral, (2) walk through the offspring haplosome and the non-ancestral strand looking for\n\t// mismatches (mutations in one that are not in the other), and (3) repair the mismatch\n\t// with equal probability of choosing either strand, unless we're in a nucleotide model and\n\t// biased gene conversion is enabled, in which case the choice will be influenced by the\n\t// GC bias.  In all cases, if the mismatch involves a newly introduced mutation we will\n\t// treat it identically to other mutations; mutations happen before heteroduplex repair,\n\t// although after gene conversion tracts get copied from the non-copy strand, and so they\n\t// can be reversed by heteroduplex repair.  This seems like the only clear/consistent policy\n\t// since new mutations could be stacked with other pre-existing mutations that should be\n\t// subject to heteroduplex repair.  Anyway this is such an edge case that our chosen policy\n\t// on it shouldn't matter for practical purposes.\n\tChromosome *chromosome = p_child_haplosome->AssociatedChromosome();\n\tdouble gBGC_coeff_scaled = (chromosome->mismatch_repair_bias_ + 1.0) / 2.0;\n\tbool repairs_biased = (species_.IsNucleotideBased() && (gBGC_coeff_scaled != 0.5));\n\tNucleotideArray *ancestral_sequence = (repairs_biased ? chromosome->AncestralSequence() : nullptr);\n\tint heteroduplex_tract_count = (int)(p_heteroduplex.size() / 2);\n\t\n\tif (heteroduplex_tract_count * 2 != (int)p_heteroduplex.size())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::DoHeteroduplexRepair): (internal error) The heteroduplex tract vector has an odd length.\" << EidosTerminate();\n\t\n\t// We accumulate vectors of all mutations to add to and to remove from the offspring haplosome,\n\t// and do all addition/removal in a single pass at the end of the process\n\tstd::vector<slim_position_t> repair_removals;\n\tstd::vector<Mutation*> repair_additions;\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\t\n\tfor (int heteroduplex_tract_index = 0; heteroduplex_tract_index < heteroduplex_tract_count; ++heteroduplex_tract_index)\n\t{\n\t\tslim_position_t tract_start = p_heteroduplex[(size_t)heteroduplex_tract_index * 2];\n\t\tslim_position_t tract_end = p_heteroduplex[(size_t)heteroduplex_tract_index * 2 + 1];\n\t\t\n\t\t// Determine which parental strand was the non-copy strand in this region, by scanning\n\t\t// the breakpoints vector; it must remain the non-copy strand throughout.\n\t\tbool copy_strand_is_1 = true;\n\t\t\n\t\tfor (int break_index = 0; break_index < p_breakpoints_count; ++break_index)\n\t\t{\n\t\t\tslim_position_t breakpoint = p_breakpoints[break_index];\n\t\t\t\n\t\t\tif (breakpoint <= tract_start)\n\t\t\t\tcopy_strand_is_1 = !copy_strand_is_1;\n\t\t\telse if (breakpoint > tract_end)\n\t\t\t\tbreak;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::DoHeteroduplexRepair): (internal error) The heteroduplex tract does not have a consistent copy strand.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tHaplosome *noncopy_haplosome = (copy_strand_is_1 ? p_parent_haplosome_2 : p_parent_haplosome_1);\n\t\t\n\t\t// Make haplosome walkers for the non-copy strand and the offspring strand, and move them\n\t\t// to the start of the heteroduplex tract region; we use SLIM_INF_BASE_POSITION to mean\n\t\t// \"past the end of the heteroduplex tract\" here\n\t\tHaplosomeWalker noncopy_walker(noncopy_haplosome);\n\t\tHaplosomeWalker offspring_walker(p_child_haplosome);\n\t\tslim_position_t noncopy_pos, offspring_pos;\n\t\t\n\t\tnoncopy_walker.MoveToPosition(tract_start);\n\t\toffspring_walker.MoveToPosition(tract_start);\n\t\t\n\t\tif (noncopy_walker.Finished()) noncopy_pos = SLIM_INF_BASE_POSITION;\n\t\telse {\n\t\t\tnoncopy_pos = noncopy_walker.Position();\n\t\t\tif (noncopy_pos > tract_end)\n\t\t\t\tnoncopy_pos = SLIM_INF_BASE_POSITION;\n\t\t}\n\t\tif (offspring_walker.Finished()) offspring_pos = SLIM_INF_BASE_POSITION;\n\t\telse {\n\t\t\toffspring_pos = offspring_walker.Position();\n\t\t\tif (offspring_pos > tract_end)\n\t\t\t\toffspring_pos = SLIM_INF_BASE_POSITION;\n\t\t}\n\t\t\n\t\t// Move the walkers forward in sync, looking for mismatches until both strands are done\n\t\twhile ((offspring_pos != SLIM_INF_BASE_POSITION) || (noncopy_pos != SLIM_INF_BASE_POSITION))\n\t\t{\n\t\t\tbool repair_toward_noncopy, advance_noncopy, advance_offspring;\n\t\t\tslim_position_t repair_pos;\n\t\t\t\n\t\t\tif (noncopy_pos < offspring_pos)\n\t\t\t{\n\t\t\t\t// A mutation exists on the non-copy strand where the offspring strand is empty;\n\t\t\t\t// this is a mismatch that needs to be repaired one way or the other\n\t\t\t\tif (repairs_biased)\n\t\t\t\t{\n\t\t\t\t\tint noncopy_nuc = noncopy_walker.NucleotideAtCurrentPosition();\t\t// NOLINT(*-signed-char-misuse) : intentional\n\t\t\t\t\t\n\t\t\t\t\t// The offspring nucleotide is ancestral; if the noncopy nuc is too, GC bias is irrelevant\n\t\t\t\t\tif (noncopy_nuc != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tint offspring_nuc = ancestral_sequence->NucleotideAtIndex(noncopy_pos);\n\t\t\t\t\t\tbool noncopy_nuc_AT = ((noncopy_nuc == 0) || (noncopy_nuc == 3));\n\t\t\t\t\t\tbool offspring_nuc_AT = ((offspring_nuc == 0) || (offspring_nuc == 3));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (noncopy_nuc_AT != offspring_nuc_AT)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// One nucleotide is A/T, the other is G/C, so GC bias is relevant here;\n\t\t\t\t\t\t\t// make a determination based on the assumption that the noncopy nucleotide is G/C\n\t\t\t\t\t\t\trepair_toward_noncopy = (Eidos_rng_uniform_doubleCO(rng_64) <= gBGC_coeff_scaled);\t// 1.0 means always repair toward GC\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// If the noncopy nucleotide is the A/T one, then our determination needs to be flipped\n\t\t\t\t\t\t\tif (noncopy_nuc_AT)\n\t\t\t\t\t\t\t\trepair_toward_noncopy = !repair_toward_noncopy;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgoto biasedRepair1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The default is unbiased repair; if we are biased we goto over this default\n\t\t\t\trepair_toward_noncopy = Eidos_RandomBool(rng_state);\n\t\t\t\t\n\t\t\tbiasedRepair1:\n\t\t\t\tadvance_noncopy = true;\n\t\t\t\tadvance_offspring = false;\n\t\t\t\trepair_pos = noncopy_pos;\n\t\t\t}\n\t\t\telse if (offspring_pos < noncopy_pos)\n\t\t\t{\n\t\t\t\t// A mutation exists on the offspring strand where the non-copy strand is empty;\n\t\t\t\t// this is a mismatch that needs to be repaired one way or the other\n\t\t\t\tif (repairs_biased)\n\t\t\t\t{\n\t\t\t\t\tint offspring_nuc = offspring_walker.NucleotideAtCurrentPosition();\t\t// NOLINT(*-signed-char-misuse) : intentional\n\t\t\t\t\t\n\t\t\t\t\t// The noncopy nucleotide is ancestral; if the offspring nuc is too, GC bias is irrelevant\n\t\t\t\t\tif (offspring_nuc != -1)\n\t\t\t\t\t{\n\t\t\t\t\t\tint noncopy_nuc = ancestral_sequence->NucleotideAtIndex(offspring_pos);\n\t\t\t\t\t\tbool noncopy_nuc_AT = ((noncopy_nuc == 0) || (noncopy_nuc == 3));\n\t\t\t\t\t\tbool offspring_nuc_AT = ((offspring_nuc == 0) || (offspring_nuc == 3));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (noncopy_nuc_AT != offspring_nuc_AT)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// One nucleotide is A/T, the other is G/C, so GC bias is relevant here;\n\t\t\t\t\t\t\t// make a determination based on the assumption that the noncopy nucleotide is G/C\n\t\t\t\t\t\t\trepair_toward_noncopy = (Eidos_rng_uniform_doubleCO(rng_64) <= gBGC_coeff_scaled);\t// 1.0 means always repair toward GC\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// If the noncopy nucleotide is the A/T one, then our determination needs to be flipped\n\t\t\t\t\t\t\tif (noncopy_nuc_AT)\n\t\t\t\t\t\t\t\trepair_toward_noncopy = !repair_toward_noncopy;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgoto biasedRepair2;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The default is unbiased repair; if we are biased we goto over this default\n\t\t\t\trepair_toward_noncopy = Eidos_RandomBool(rng_state);\n\t\t\t\t\n\t\t\tbiasedRepair2:\n\t\t\t\tadvance_noncopy = false;\n\t\t\t\tadvance_offspring = true;\n\t\t\t\trepair_pos = offspring_pos;\n\t\t\t}\n\t\t\telse if (offspring_walker.IdenticalAtCurrentPositionTo(noncopy_walker))\n\t\t\t{\n\t\t\t\t// The two walkers have identical state at this position, so there is no mismatch.\n\t\t\t\t// We consider identical stacks of mutations that are re-ordered with respect to\n\t\t\t\t// each other to be a mismatch, for simplicity; such re-ordered stacks should not\n\t\t\t\t// occur anyway unless the user is doing something really weird.\n\t\t\t\trepair_toward_noncopy = false;\n\t\t\t\tadvance_noncopy = true;\n\t\t\t\tadvance_offspring = true;\n\t\t\t\trepair_pos = offspring_pos;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The walkers are at the same position, and there is a mismatch.\n\t\t\t\tif (repairs_biased)\n\t\t\t\t{\n\t\t\t\t\tint noncopy_nuc = noncopy_walker.NucleotideAtCurrentPosition();\t\t\t// NOLINT(*-signed-char-misuse) : intentional\n\t\t\t\t\tint offspring_nuc = offspring_walker.NucleotideAtCurrentPosition();\t\t// NOLINT(*-signed-char-misuse) : intentional\n\t\t\t\t\t\n\t\t\t\t\t// If both nucleotides are ancestral, GC bias is irrelevant\n\t\t\t\t\tif ((noncopy_nuc != -1) || (offspring_nuc != -1))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (noncopy_nuc == -1) noncopy_nuc = ancestral_sequence->NucleotideAtIndex(offspring_pos);\n\t\t\t\t\t\tif (offspring_nuc == -1) offspring_nuc = ancestral_sequence->NucleotideAtIndex(offspring_pos);\n\t\t\t\t\t\t\n\t\t\t\t\t\tbool noncopy_nuc_AT = ((noncopy_nuc == 0) || (noncopy_nuc == 3));\n\t\t\t\t\t\tbool offspring_nuc_AT = ((offspring_nuc == 0) || (offspring_nuc == 3));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (noncopy_nuc_AT != offspring_nuc_AT)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// One nucleotide is A/T, the other is G/C, so GC bias is relevant here;\n\t\t\t\t\t\t\t// make a determination based on the assumption that the noncopy nucleotide is G/C\n\t\t\t\t\t\t\trepair_toward_noncopy = (Eidos_rng_uniform_doubleCO(rng_64) <= gBGC_coeff_scaled);\t// 1.0 means always repair toward GC\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// If the noncopy nucleotide is the A/T one, then our determination needs to be flipped\n\t\t\t\t\t\t\tif (noncopy_nuc_AT)\n\t\t\t\t\t\t\t\trepair_toward_noncopy = !repair_toward_noncopy;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgoto biasedRepair3;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The default is unbiased repair; if we are biased we goto over this default\n\t\t\t\trepair_toward_noncopy = Eidos_RandomBool(rng_state);\n\t\t\t\t\n\t\t\tbiasedRepair3:\n\t\t\t\tadvance_noncopy = true;\n\t\t\t\tadvance_offspring = true;\n\t\t\t\trepair_pos = offspring_pos;\n\t\t\t}\n\t\t\t\n\t\t\t// Move past the mismatch, marking mutations for copying if repair is toward the noncopy strand\n\t\t\tif (advance_noncopy)\n\t\t\t{\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (repair_toward_noncopy)\n\t\t\t\t\t\trepair_additions.emplace_back(noncopy_walker.CurrentMutation());\n\t\t\t\t\t\n\t\t\t\t\tnoncopy_walker.NextMutation();\n\t\t\t\t\tif (noncopy_walker.Finished())\n\t\t\t\t\t{\n\t\t\t\t\t\tnoncopy_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tnoncopy_pos = noncopy_walker.Position();\n\t\t\t\t\tif (noncopy_pos > repair_pos)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (noncopy_pos > tract_end)\n\t\t\t\t\t\t\tnoncopy_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (advance_offspring)\n\t\t\t{\n\t\t\t\tif (repair_toward_noncopy)\n\t\t\t\t\trepair_removals.emplace_back(repair_pos);\n\t\t\t\t\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\toffspring_walker.NextMutation();\n\t\t\t\t\tif (offspring_walker.Finished())\n\t\t\t\t\t{\n\t\t\t\t\t\toffspring_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\toffspring_pos = offspring_walker.Position();\n\t\t\t\t\tif (offspring_pos > repair_pos)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (offspring_pos > tract_end)\n\t\t\t\t\t\t\toffspring_pos = SLIM_INF_BASE_POSITION;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// We are done scanning; now we do all of the planned repairs.  Tree-sequence recording\n\t// needs to be kept apprised of all the changes made.  Note that in some cases a mutation\n\t// might have been newly added at a position, and then removed again by mismatch repair;\n\t// we will need to make sure that the recorded state is correct when that occurs.\n\t\n\tif ((repair_removals.size() > 0) || (repair_additions.size() > 0))\n\t{\n\t\t// We loop through the mutation runs in p_child_haplosome, and for each one, if there are\n\t\t// mutations to be added or removed we make a new mutation run and effect the changes\n\t\t// as we copy mutations over.  Mutruns without changes are left untouched.\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tslim_position_t mutrun_length = p_child_haplosome->mutrun_length_;\n\t\tslim_position_t mutrun_count = p_child_haplosome->mutrun_count_;\n\t\tstd::size_t removal_index = 0, addition_index = 0;\n\t\tslim_position_t next_removal_pos = (removal_index < repair_removals.size()) ? repair_removals[removal_index] : SLIM_INF_BASE_POSITION;\n\t\tslim_position_t next_addition_pos = (addition_index < repair_additions.size()) ? repair_additions[addition_index]->position_ : SLIM_INF_BASE_POSITION;\n\t\tslim_mutrun_index_t next_removal_mutrun_index = (slim_mutrun_index_t)(next_removal_pos / mutrun_length);\n\t\tslim_mutrun_index_t next_addition_mutrun_index = (slim_mutrun_index_t)(next_addition_pos / mutrun_length);\n\t\tslim_mutrun_index_t run_index = std::min(next_removal_mutrun_index, next_addition_mutrun_index);\n\t\t\n\t\twhile (run_index < mutrun_count)\n\t\t{\n\t\t\t// Now we will process *all* additions and removals for run_index\n\t\t\tMutationRunContext &mutrun_context_LOCKED = chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\tMutationRun *new_run = MutationRun::NewMutationRun_LOCKED(mutrun_context_LOCKED);\n\t\t\tconst MutationRun *old_run = p_child_haplosome->mutruns_[run_index];\n\t\t\tconst MutationIndex *old_run_iter\t\t= old_run->begin_pointer_const();\n\t\t\tconst MutationIndex *old_run_iter_max\t= old_run->end_pointer_const();\n\t\t\t\n\t\t\tfor ( ; old_run_iter != old_run_iter_max; ++old_run_iter)\n\t\t\t{\n\t\t\t\tMutationIndex old_run_mut_index = *old_run_iter;\n\t\t\t\tMutation *old_run_mut = mut_block_ptr + old_run_mut_index;\n\t\t\t\tslim_position_t old_run_mut_pos = old_run_mut->position_;\n\t\t\t\t\n\t\t\t\t// if we are past the current removal position, advance to the next, which should be at or after our position\n\t\t\t\tif (old_run_mut_pos > next_removal_pos)\n\t\t\t\t{\n\t\t\t\t\tremoval_index++;\n\t\t\t\t\tnext_removal_pos = (removal_index < repair_removals.size()) ? repair_removals[removal_index] : SLIM_INF_BASE_POSITION;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// if the current position is being removed, skip over this mutation; we may not be done with this removal position, however\n\t\t\t\tif (old_run_mut_pos == next_removal_pos)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// we will add the current mutation, but first we must add any addition mutations that come before it\n\t\t\t\twhile (next_addition_pos < old_run_mut_pos)\n\t\t\t\t{\n\t\t\t\t\tMutation *addition_mut = repair_additions[addition_index];\n\t\t\t\t\tMutationIndex addition_mut_index = (MutationIndex)(addition_mut - mut_block_ptr); // BlockIndex()\n\t\t\t\t\t\n\t\t\t\t\tnew_run->emplace_back(addition_mut_index);\n\t\t\t\t\t\n\t\t\t\t\taddition_index++;\n\t\t\t\t\tnext_addition_pos = (addition_index < repair_additions.size()) ? repair_additions[addition_index]->position_ : SLIM_INF_BASE_POSITION;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// add the current mutation, since it is not being removed\n\t\t\t\tnew_run->emplace_back(old_run_mut_index);\n\t\t\t}\n\t\t\t\n\t\t\t// update the mutrun indexes; we don't do this above to avoid lots of redundant division\n\t\t\tnext_removal_mutrun_index = (slim_mutrun_index_t)(next_removal_pos / mutrun_length);\n\t\t\tnext_addition_mutrun_index = (slim_mutrun_index_t)(next_addition_pos / mutrun_length);\n\t\t\t\n\t\t\t// if there are any removal positions left in this mutrun, they have been handled above\n\t\t\twhile (next_removal_mutrun_index == run_index)\n\t\t\t{\n\t\t\t\tremoval_index++;\n\t\t\t\tnext_removal_pos = (removal_index < repair_removals.size()) ? repair_removals[removal_index] : SLIM_INF_BASE_POSITION;\n\t\t\t\tnext_removal_mutrun_index = (slim_mutrun_index_t)(next_removal_pos / mutrun_length);\n\t\t\t}\n\t\t\t\n\t\t\t// if there are addition mutations left in this mutrun, they must go after the end of the old mutrun's mutations\n\t\t\twhile (next_addition_mutrun_index == run_index)\n\t\t\t{\n\t\t\t\tMutation *addition_mut = repair_additions[addition_index];\n\t\t\t\tMutationIndex addition_mut_index = (MutationIndex)(addition_mut - mut_block_ptr); // BlockIndex()\n\t\t\t\t\n\t\t\t\tnew_run->emplace_back(addition_mut_index);\n\t\t\t\t\n\t\t\t\taddition_index++;\n\t\t\t\tnext_addition_pos = (addition_index < repair_additions.size()) ? repair_additions[addition_index]->position_ : SLIM_INF_BASE_POSITION;\n\t\t\t\tnext_addition_mutrun_index = (slim_mutrun_index_t)(next_addition_pos / mutrun_length);\n\t\t\t}\n\t\t\t\n\t\t\t// replace the mutation run at run_index with the newly constructed run that has all additions and removals\n\t\t\tp_child_haplosome->mutruns_[run_index] = new_run;\n\t\t\t\n\t\t\t// go to the next run index that has changes\n\t\t\trun_index = std::min(next_removal_mutrun_index, next_addition_mutrun_index);\n\t\t}\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (species_.RecordingTreeSequenceMutations())\n\t{\n\t\t// We repurpose repair_removals here as a vector of all positions that changed due to heteroduplex repair.\n\t\t// We therefore add in the positions for each entry in repair_additions, then sort and unique.\n\t\tfor (Mutation *added_mut : repair_additions)\n\t\t\trepair_removals.emplace_back(added_mut->position_);\n\t\t\n\t\tstd::sort(repair_removals.begin(), repair_removals.end());\n\t\trepair_removals.erase(unique(repair_removals.begin(), repair_removals.end()), repair_removals.end());\n\t\t\n\t\t// Then we record the new derived state at every position that changed\n\t\tfor (slim_position_t changed_pos : repair_removals)\n\t\t{\n#pragma omp critical (TreeSeqNewDerivedState)\n\t\t\t{\n\t\t\t\tspecies_.RecordNewDerivedState(p_child_haplosome, changed_pos, *p_child_haplosome->derived_mutation_ids_at_position(changed_pos));\n\t\t\t}\n\t\t}\n\t}\n}\n\n#ifdef SLIMGUI\nvoid Population::RecordFitness(slim_tick_t p_history_index, slim_objectid_t p_subpop_id, double p_fitness_value)\n{\n\tFitnessHistory *history_rec_ptr = nullptr;\n\t\n\t// Find the existing history record, if it exists\n\tauto history_iter = fitness_histories_.find(p_subpop_id);\n\t\n\tif (history_iter != fitness_histories_.end())\n\t\thistory_rec_ptr = &(history_iter->second);\n\t\n\t// If not, create a new history record and add it to our vector\n\tif (!history_rec_ptr)\n\t{\n\t\tFitnessHistory history_record;\n\t\t\n\t\thistory_record.history_ = nullptr;\n\t\thistory_record.history_length_ = 0;\n\t\t\n\t\tauto emplace_rec = fitness_histories_.emplace(p_subpop_id, history_record);\n\t\t\n\t\tif (emplace_rec.second)\n\t\t\thistory_rec_ptr = &(emplace_rec.first->second);\n\t}\n\t\n\t// Assuming we now have a record, resize it as needed and insert the new value\n\tif (history_rec_ptr)\n\t{\n\t\tdouble *history = history_rec_ptr->history_;\n\t\tslim_tick_t history_length = history_rec_ptr->history_length_;\n\t\t\n\t\tif (p_history_index >= history_length)\n\t\t{\n\t\t\tslim_tick_t oldHistoryLength = history_length;\n\t\t\t\n\t\t\thistory_length = p_history_index + 1000;\t\t\t// give some elbow room for expansion\n\t\t\thistory = (double *)realloc(history, history_length * sizeof(double));\n\t\t\t\n\t\t\tfor (slim_tick_t i = oldHistoryLength; i < history_length; ++i)\n\t\t\t\thistory[i] = NAN;\n\t\t\t\n\t\t\t// Copy the new values back into the history record\n\t\t\thistory_rec_ptr->history_ = history;\n\t\t\thistory_rec_ptr->history_length_ = history_length;\n\t\t}\n\t\t\n\t\thistory[p_history_index] = p_fitness_value;\n\t}\n}\n\nvoid Population::RecordSubpopSize(slim_tick_t p_history_index, slim_objectid_t p_subpop_id, slim_popsize_t p_subpop_size)\n{\n    SubpopSizeHistory *history_rec_ptr = nullptr;\n\t\n\t// Find the existing history record, if it exists\n\tauto history_iter = subpop_size_histories_.find(p_subpop_id);\n\t\n\tif (history_iter != subpop_size_histories_.end())\n\t\thistory_rec_ptr = &(history_iter->second);\n\t\n\t// If not, create a new history record and add it to our vector\n\tif (!history_rec_ptr)\n\t{\n\t\tSubpopSizeHistory history_record;\n\t\t\n\t\thistory_record.history_ = nullptr;\n\t\thistory_record.history_length_ = 0;\n\t\t\n\t\tauto emplace_rec = subpop_size_histories_.emplace(p_subpop_id, history_record);\n\t\t\n\t\tif (emplace_rec.second)\n\t\t\thistory_rec_ptr = &(emplace_rec.first->second);\n\t}\n\t\n\t// Assuming we now have a record, resize it as needed and insert the new value\n\tif (history_rec_ptr)\n\t{\n\t\tslim_popsize_t *history = history_rec_ptr->history_;\n\t\tslim_tick_t history_length = history_rec_ptr->history_length_;\n\t\t\n\t\tif (p_history_index >= history_length)\n\t\t{\n\t\t\tslim_tick_t oldHistoryLength = history_length;\n\t\t\t\n\t\t\thistory_length = p_history_index + 1000;\t\t\t// give some elbow room for expansion\n\t\t\thistory = (slim_popsize_t *)realloc(history, history_length * sizeof(slim_popsize_t));\n\t\t\t\n\t\t\tfor (slim_tick_t i = oldHistoryLength; i < history_length; ++i)\n\t\t\t\thistory[i] = 0;\n\t\t\t\n\t\t\t// Copy the new values back into the history record\n\t\t\thistory_rec_ptr->history_ = history;\n\t\t\thistory_rec_ptr->history_length_ = history_length;\n\t\t}\n\t\t\n\t\thistory[p_history_index] = p_subpop_size;\n\t}\n}\n\n// This method is used to record population statistics that are kept per tick for SLiMgui\n#if defined(__clang__)\n__attribute__((no_sanitize(\"float-divide-by-zero\")))\n__attribute__((no_sanitize(\"integer-divide-by-zero\")))\n#endif\nvoid Population::SurveyPopulation(void)\n{\n\t// Calculate mean fitness for this tick\n\tdouble totalUnscaledFitness = 0.0;\n\tslim_popsize_t totalPopSize = 0;\n\tslim_tick_t historyIndex = community_.Tick() - 1;\t// zero-base: the first tick we put something in is tick 1, and we put it at index 0\n\t\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{ \n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\n\t\t// calculate the total fitness across the subpopulation; in nonWF models the population composition can change\n\t\t// late in the cycle, due to mortality and migration, so we postpone this assessment to the end of the tick\n\t\t// we use the fitness without subpop fitnessScaling, to present individual fitness without density effects\n\t\tdouble subpop_unscaled_total = 0;\n\t\t\n\t\tfor (Individual *individual : subpop->parent_individuals_)\n\t\t\tsubpop_unscaled_total += individual->cached_unscaled_fitness_;\n\t\t\n\t\ttotalUnscaledFitness += subpop_unscaled_total;\n\t\ttotalPopSize += subpop_size;\n\t\t\n\t\tdouble meanUnscaledFitness = subpop_unscaled_total / subpop_size;\n\t\t\n\t\t// Record for SLiMgui display\n\t\tsubpop->parental_mean_unscaled_fitness_ = meanUnscaledFitness;\n\t\tRecordFitness(historyIndex, subpop_pair.first, meanUnscaledFitness);\n\t\tRecordSubpopSize(historyIndex, subpop_pair.first, subpop_size);\n\t}\n\t\n\tRecordFitness(historyIndex, -1, totalUnscaledFitness / totalPopSize);\n\tRecordSubpopSize(historyIndex, -1, totalPopSize);\n}\n#endif\n\n#ifdef SLIMGUI\n// This method is used to tally up histogram metrics that are kept per mutation type for SLiMgui\nvoid Population::AddTallyForMutationTypeAndBinNumber(int p_mutation_type_index, int p_mutation_type_count, slim_tick_t p_bin_number, slim_tick_t **p_buffer, uint32_t *p_bufferBins)\n{\n\tslim_tick_t *buffer = *p_buffer;\n\tuint32_t bufferBins = *p_bufferBins;\n\t\n\t// A negative bin number can occur if the user is using the origin tick of mutations for their own purposes, as a tag field.  To protect against\n\t// crashing, we therefore clamp the bin number into [0, 1000000].  The upper bound is somewhat arbitrary, but we don't really want to allocate a larger\n\t// buffer than that anyway, and having values that large get clamped is not the end of the world, since these tallies are just for graphing.\n\tif (p_bin_number < 0)\n\t\tp_bin_number = 0;\n\tif (p_bin_number > 1000000)\n\t\tp_bin_number = 1000000;\n\t\n\tif (p_bin_number >= (int64_t)bufferBins)\n\t{\n\t\tint oldEntryCount = bufferBins * p_mutation_type_count;\n\t\t\n\t\tbufferBins = static_cast<uint32_t>(ceil((p_bin_number + 1) / 128.0) * 128.0);\t\t\t// give ourselves some headroom so we're not reallocating too often\n\t\tint newEntryCount = bufferBins * p_mutation_type_count;\n\t\t\n\t\tbuffer = (slim_tick_t *)realloc(buffer, newEntryCount * sizeof(slim_tick_t));\n\t\t\n\t\t// Zero out the new entries; the compiler should be smart enough to optimize this...\n\t\tfor (int i = oldEntryCount; i < newEntryCount; ++i)\n\t\t\tbuffer[i] = 0;\n\t\t\n\t\t// Since we reallocated the buffer, we need to set it back through our pointer parameters\n\t\t*p_buffer = buffer;\n\t\t*p_bufferBins = bufferBins;\n\t}\n\t\n\t// Add a tally to the appropriate bin\n\t(buffer[p_mutation_type_index + p_bin_number * p_mutation_type_count])++;\n}\n#endif\n\nvoid Population::ValidateMutationFitnessCaches(void)\n{\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint registry_size;\n\tconst MutationIndex *registry_iter = MutationRegistry(&registry_size);\n\tconst MutationIndex *registry_iter_end = registry_iter + registry_size;\n\t\n\twhile (registry_iter != registry_iter_end)\n\t{\n\t\tMutationIndex mut_index = (*registry_iter++);\n\t\tMutation *mut = mut_block_ptr + mut_index;\n\t\tslim_selcoeff_t sel_coeff = mut->selection_coeff_;\n\t\tslim_selcoeff_t dom_coeff = mut->mutation_type_ptr_->dominance_coeff_;\n\t\tslim_selcoeff_t hemizygous_dom_coeff = mut->mutation_type_ptr_->hemizygous_dominance_coeff_;\n\t\t\n\t\tmut->cached_one_plus_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + sel_coeff);\n\t\tmut->cached_one_plus_dom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + dom_coeff * sel_coeff);\n\t\tmut->cached_one_plus_hemizygousdom_sel_ = (slim_selcoeff_t)std::max(0.0, 1.0 + hemizygous_dom_coeff * sel_coeff);\n\t}\n}\n\nvoid Population::RecalculateFitness(slim_tick_t p_tick)\n{\n\t// calculate the fitnesses of the parents and make lookup tables; the main thing we do here is manage the mutationEffect() callbacks\n\t// as per the SLiM design spec, we get the list of callbacks once, and use that list throughout this stage, but we construct\n\t// subsets of it for each subpopulation, so that UpdateFitness() can just use the callback list as given to it\n\tstd::vector<SLiMEidosBlock*> mutationEffect_callbacks = species_.CallbackBlocksMatching(p_tick, SLiMEidosBlockType::SLiMEidosMutationEffectCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> fitnessEffect_callbacks = species_.CallbackBlocksMatching(p_tick, SLiMEidosBlockType::SLiMEidosFitnessEffectCallback, -1, -1, -1, -1);\n\tbool no_active_callbacks = true;\n\t\n\tfor (SLiMEidosBlock *callback : mutationEffect_callbacks)\n\t\tif (callback->block_active_)\n\t\t{\n\t\t\tno_active_callbacks = false;\n\t\t\tbreak;\n\t\t}\n\tif (no_active_callbacks)\n\t\tfor (SLiMEidosBlock *callback : fitnessEffect_callbacks)\n\t\t\tif (callback->block_active_)\n\t\t\t{\n\t\t\t\tno_active_callbacks = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\n\t// Figure out how we are going to handle MutationRun nonneutral mutation caches; see mutation_run.h.  We need to assess\n\t// the state of callbacks and decide which of the three \"regimes\" we are in, and then depending upon that and what\n\t// regime we were in in the previous generation, invalidate nonneutral caches or allow them to persist.\n\tconst std::map<slim_objectid_t,MutationType*> &mut_types = species_.MutationTypes();\n\tint32_t last_regime = species_.last_nonneutral_regime_;\n\tint32_t current_regime;\n\t\n\tif (no_active_callbacks)\n\t{\n\t\tcurrent_regime = 1;\n\t}\n\telse\n\t{\n\t\t// First, we want to save off the old values of our flags that govern nonneutral caching\n\t\tfor (auto muttype_iter : mut_types)\n\t\t{\n\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\n\t\t\tmuttype->previous_set_neutral_by_global_active_callback_ = muttype->set_neutral_by_global_active_callback_;\n\t\t\tmuttype->previous_subject_to_mutationEffect_callback_ = muttype->subject_to_mutationEffect_callback_;\n\t\t}\n\t\t\n\t\t// Then we assess which muttypes are being made globally neutral by a constant-value mutationEffect() callback\n\t\tbool all_active_callbacks_are_global_neutral_effects = true;\n\t\t\n\t\tfor (auto muttype_iter : mut_types)\n\t\t\t(muttype_iter.second)->set_neutral_by_global_active_callback_ = false;\n\t\t\n\t\tfor (SLiMEidosBlock *mutationEffect_callback : mutationEffect_callbacks)\n\t\t{\n\t\t\tif (mutationEffect_callback->block_active_)\n\t\t\t{\n\t\t\t\tif (mutationEffect_callback->subpopulation_id_ == -1)\n\t\t\t\t{\n\t\t\t\t\tconst EidosASTNode *compound_statement_node = mutationEffect_callback->compound_statement_node_;\n\t\t\t\t\t\n\t\t\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\"\n\t\t\t\t\t\tEidosValue *result = compound_statement_node->cached_return_value_.get();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((result->Type() == EidosValueType::kValueFloat) && (result->Count() == 1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (result->FloatData()[0] == 1.0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// the callback returns 1.0, so it makes the mutation types to which it applies become neutral\n\t\t\t\t\t\t\t\tslim_objectid_t mutation_type_id = mutationEffect_callback->mutation_type_id_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (mutation_type_id != -1)\n\t\t\t\t\t\t\t\t{\n                                    MutationType *found_muttype = species_.MutationTypeWithID(mutation_type_id);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (found_muttype)\n\t\t\t\t\t\t\t\t\t\tfound_muttype->set_neutral_by_global_active_callback_ = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// This is a constant neutral effect, so avoid dropping through to the flag set below\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// if we reach this point, we have an active callback that is not a\n\t\t\t\t// global constant neutral effect, so set our flag and break out\n\t\t\t\tall_active_callbacks_are_global_neutral_effects = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (all_active_callbacks_are_global_neutral_effects)\n\t\t{\n\t\t\t// The only active callbacks are global (i.e. not subpop-specific) constant-effect neutral callbacks,\n\t\t\t// so we will use the set_neutral_by_global_active_callback flag in the muttypes that we set up above.\n\t\t\t// When that flag is true, the mut is neutral; when it is false, consult the selection coefficient.\n\t\t\tcurrent_regime = 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have at least one active callback that is not a global constant-effect callback, so all\n\t\t\t// bets are off; any mutation of a muttype influenced by a callback must be considered non-neutral,\n\t\t\t// as governed by the flag set up below\n\t\t\tcurrent_regime = 3;\n\t\t\t\n\t\t\tfor (auto muttype_iter : mut_types)\n\t\t\t\t(muttype_iter.second)->subject_to_mutationEffect_callback_ = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *mutationEffect_callback : mutationEffect_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t mutation_type_id = mutationEffect_callback->mutation_type_id_;\n\t\t\t\t\n\t\t\t\tif (mutation_type_id != -1)\n\t\t\t\t{\n                    MutationType *found_muttype = species_.MutationTypeWithID(mutation_type_id);\n\t\t\t\t\t\n\t\t\t\t\tif (found_muttype)\n\t\t\t\t\t\tfound_muttype->subject_to_mutationEffect_callback_ = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// trigger a recache of nonneutral mutation lists for some regime transitions; see mutation_run.h\n\tif (last_regime == 0)\t\t\t\t\t\t\t\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\tspecies_.nonneutral_change_counter_++;\n\telse if ((current_regime == 1) && ((last_regime == 2) || (last_regime == 3)))\n\t\tspecies_.nonneutral_change_counter_++;\n\telse if (current_regime == 2)\n\t{\n\t\tif (last_regime != 2)\n\t\t\tspecies_.nonneutral_change_counter_++;\n\t\telse\n\t\t{\n\t\t\t// If we are in regime 2 this cycle and were last cycle as well, then if the way that\n\t\t\t// mutationEffect() callbacks are influencing mutation types is the same this cycle as it was last\n\t\t\t// cycle, we can actually carry over our nonneutral buffers.\n\t\t\tbool callback_state_identical = true;\n\t\t\t\n\t\t\tfor (auto muttype_iter : mut_types)\n\t\t\t{\n\t\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\t\n\t\t\t\tif (muttype->set_neutral_by_global_active_callback_ != muttype->previous_set_neutral_by_global_active_callback_)\n\t\t\t\t\tcallback_state_identical = false;\n\t\t\t}\n\t\t\t\n\t\t\tif (!callback_state_identical)\n\t\t\t\tspecies_.nonneutral_change_counter_++;\n\t\t}\n\t}\n\telse if (current_regime == 3)\n\t{\n\t\tif (last_regime != 3)\n\t\t\tspecies_.nonneutral_change_counter_++;\n\t\telse\n\t\t{\n\t\t\t// If we are in regime 3 this cycle and were last cycle as well, then if the way that\n\t\t\t// mutationEffect() callbacks are influencing mutation types is the same this cycle as it was last\n\t\t\t// cycle, we can actually carry over our nonneutral buffers.\n\t\t\tbool callback_state_identical = true;\n\t\t\t\n\t\t\tfor (auto muttype_iter : mut_types)\n\t\t\t{\n\t\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\t\n\t\t\t\tif (muttype->subject_to_mutationEffect_callback_ != muttype->previous_subject_to_mutationEffect_callback_)\n\t\t\t\t\tcallback_state_identical = false;\n\t\t\t}\n\t\t\t\n\t\t\tif (!callback_state_identical)\n\t\t\t\tspecies_.nonneutral_change_counter_++;\n\t\t}\n\t}\n\t\n\t// move forward to the regime we just chose; UpdateFitness() can consult this to get the current regime\n\tspecies_.last_nonneutral_regime_ = current_regime;\n\t\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\t// used for both mutationEffect() and fitnessEffect() for simplicity\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// FIXME this will get cleaned up when multiple phenotypes is done\n\t\n\tif (no_active_callbacks)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> no_callbacks;\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\tsubpop_pair.second->UpdateFitness(no_callbacks, no_callbacks);\n\t}\n\telse\n\t{\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tstd::vector<SLiMEidosBlock*> subpop_mutationEffect_callbacks;\n\t\t\tstd::vector<SLiMEidosBlock*> subpop_fitnessEffect_callbacks;\n\t\t\t\n\t\t\t// Get mutationEffect() and fitnessEffect() callbacks that apply to this subpopulation\n\t\t\tfor (SLiMEidosBlock *callback : mutationEffect_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop_mutationEffect_callbacks.emplace_back(callback);\n\t\t\t}\n\t\t\tfor (SLiMEidosBlock *callback : fitnessEffect_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop_fitnessEffect_callbacks.emplace_back(callback);\n\t\t\t}\n\t\t\t\n\t\t\t// Update fitness values, using the callbacks\n\t\t\tsubpop->UpdateFitness(subpop_mutationEffect_callbacks, subpop_fitnessEffect_callbacks);\n\t\t}\n\t}\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n\t// reset fitness_scaling_ to 1.0 on subpops and individuals\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\n\t\tsubpop->subpop_fitness_scaling_ = 1.0;\n\t\t\n\t\t// Reset fitness_scaling_ on individuals only if it has ever been changed\n\t\tif (Individual::s_any_individual_fitness_scaling_set_)\n\t\t{\n\t\t\tstd::vector<Individual *> &individuals = subpop->parent_individuals_;\n\t\t\t\n\t\t\tfor (Individual *individual : individuals)\n\t\t\t\tindividual->fitness_scaling_ = 1.0;\n\t\t}\n\t}\n}\n\n#if SLIM_CLEAR_HAPLOSOMES\n// WF only:\n// Clear all parental haplosomes to use nullptr for their mutation runs, so they are ready to reuse in the next tick\n// BCH 10/15/2024: This is now only enabled as a debugging setting; clearing haplosomes is no longer necessary.\nvoid Population::ClearParentalHaplosomes(void)\n{\n\tif (species_.HasGenetics())\n\t{\n\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_PARENTS_CLEAR);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PARENTS_CLEAR);\n#pragma omp parallel default(none) num_threads(thread_count)\n\t\t{\n\t\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->clear_to_nullptr();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// We have to clear out removed subpops, too, for as long as they stick around\n\t\t\tfor (Subpopulation *subpop : removed_subpops_)\n\t\t\t{\n#pragma omp for schedule(static)\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->clear_to_nullptr();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (Individual *ind : subpop->child_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->clear_to_nullptr();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_PARENTS_CLEAR);\n\t}\n}\n#endif\n\n// Scan through all mutation runs in the simulation and unique them\nvoid Population::UniqueMutationRuns(void)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::UniqueMutationRuns): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n#if SLIM_DEBUG_MUTATION_RUNS\n\tstd::clock_t begin = std::clock();\n#endif\n\tint64_t total_mutruns = 0, total_hash_collisions = 0, total_identical = 0, total_uniqued_away = 0, total_preexisting = 0, total_final = 0;\n\tint64_t operation_id = MutationRun::GetNextOperationID();\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tsize_t chromosome_count = chromosomes.size();\n\t\n\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_UNIQUE_MUTRUNS);\n\t\n\t// BCH 22 Oct. 2024: we want the top-level loop to be over mutation runs; we want to do the uniquing work\n\t// on a per-mutation-run basis.  However, mutation runs live inside haplosomes, which correspond to\n\t// chromosomes, and that correspondence is important; the mutation runs of two haplosomes that represent\n\t// the same chromosome need to be uniqued against each other, not independently.  So the new top-level\n\t// loop is over chromosomes, and then over mutruns and haplosomes that correspond to each chromosome.\n\t// FIXME: TO BE PARALLELIZED\n\tfor (size_t chromosome_index = 0; chromosome_index < chromosome_count; ++chromosome_index)\n\t{\n\t\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\tint first_haplosome_index = species_.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species_.LastHaplosomeIndices()[chromosome_index];\n\t\t\n\t\tint64_t count_mutruns = 0, count_hash_collisions = 0, count_identical = 0, count_uniqued_away = 0, count_preexisting = 0, count_final = 0;\n\t\tint mutrun_count_multiplier = chromosome->mutrun_count_multiplier_;\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n\t\tint mutrun_count = chromosome->mutrun_count_;\n\t\t\n\t\tif (mutrun_count_multiplier * mutrun_context_count != mutrun_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::UniqueMutationRuns): (internal error) mutation run subdivision is incorrect.\" << EidosTerminate();\n\t\t\n\t\t// Each mutation run index is now uniqued individually, because mutation runs cannot be used at more than one position.\n\t\t// This prevents empty mutation runs, in particular, from getting shared across positions, a necessary restriction.\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_UNIQUE_MUTRUNS);\n#pragma omp parallel for schedule(dynamic) default(none) shared(mutrun_count) firstprivate(operation_id) reduction(+: count_mutruns) reduction(+: count_hash_collisions) reduction(+: count_identical) reduction(+: count_uniqued_away) reduction(+: count_preexisting) reduction(+: count_final) num_threads(thread_count)\n\t\tfor (int mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t{\n\t\t\tstd::unordered_multimap<int64_t, const MutationRun *> runmap;\t// BCH 4/30/2023: switched to unordered, it is faster\n\t\t\t\n\t\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst MutationRun *mut_run = haplosome->mutruns_[mutrun_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mut_run)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbool first_sight_of_this_mutrun = false;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcount_mutruns++;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mut_run->operation_id_ != operation_id)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Mark each new run we encounter with the operation ID, to count the preexisting number of runs\n\t\t\t\t\t\t\t\tcount_preexisting++;\n\t\t\t\t\t\t\t\tmut_run->operation_id_ = operation_id;\n\t\t\t\t\t\t\t\tfirst_sight_of_this_mutrun = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Calculate a hash for this mutrun.  Note that we could store computed hashes into the runs above, so that\n\t\t\t\t\t\t\t// we only hash each pre-existing run once; but that would require an int64_t more storage per mutrun, and\n\t\t\t\t\t\t\t// the memory overhead doesn't presently seem worth the very slight performance gain it would usually provide\n\t\t\t\t\t\t\tint64_t hash = mut_run->Hash();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// See if we have any mutruns already defined with this hash.  Note that we actually want to do this search\n\t\t\t\t\t\t\t// even when first_sight_of_this_mutrun = true, because we want to find hash collisions, which may be other\n\t\t\t\t\t\t\t// runs that are identical to us despite being separate objects.  That is, in fact, kind of the point.\n\t\t\t\t\t\t\tauto range = runmap.equal_range(hash);\t\t// pair<Iter, Iter>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (range.first == range.second)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// No previous mutrun found with this hash, so add this mutrun to the multimap\n\t\t\t\t\t\t\t\trunmap.emplace(hash, mut_run);\n\t\t\t\t\t\t\t\tcount_final++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// There is at least one hit; first cycle through the hits and see if any of them are pointer-identical\n\t\t\t\t\t\t\t\tfor (auto hash_iter = range.first; hash_iter != range.second; ++hash_iter)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (mut_run == hash_iter->second)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tcount_identical++;\n\t\t\t\t\t\t\t\t\t\tgoto is_identical;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// OK, we have no pointer-identical matches; check for a duplicate using Identical()\n\t\t\t\t\t\t\t\tfor (auto hash_iter = range.first; hash_iter != range.second; ++hash_iter)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tconst MutationRun *hash_run = hash_iter->second;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (mut_run->Identical(*hash_run))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\thaplosome->mutruns_[mutrun_index] = hash_run;\n\t\t\t\t\t\t\t\t\t\tcount_identical++;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t// We will unique away all references to this mutrun, but we only want to count it once\n\t\t\t\t\t\t\t\t\t\tif (first_sight_of_this_mutrun)\n\t\t\t\t\t\t\t\t\t\t\tcount_uniqued_away++;\n\t\t\t\t\t\t\t\t\t\tgoto is_identical;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// If there was no identical match, then we have a hash collision; put it in the multimap\n\t\t\t\t\t\t\t\trunmap.emplace(hash, mut_run);\n\t\t\t\t\t\t\t\tcount_hash_collisions++;\n\t\t\t\t\t\t\t\tcount_final++;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tis_identical:\n\t\t\t\t\t\t\t\t;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\ttotal_mutruns += count_mutruns;\n\t\ttotal_hash_collisions += count_hash_collisions;\n\t\ttotal_identical += count_identical;\n\t\ttotal_uniqued_away += count_uniqued_away;\n\t\ttotal_preexisting += count_preexisting;\n\t\ttotal_final += count_final;\n\t}\n\t\n\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_UNIQUE_MUTRUNS);\n\t\n#if SLIM_DEBUG_MUTATION_RUNS\n\tstd::clock_t end = std::clock();\n\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\n\tstd::cout << \"UniqueMutationRuns(), tick \" << community_.Tick() << \": \\n   \" << total_mutruns << \" run pointers analyzed\\n   \" << total_preexisting << \" runs pre-existing\\n   \" << total_uniqued_away << \" duplicate runs discovered and uniqued away\\n   \" << (total_mutruns - total_identical) << \" final uniqued mutation runs\\n   \" << total_hash_collisions << \" hash collisions\\n   \" << time_spent << \" seconds elapsed\" << std::endl;\n#else\n    // get rid of unused variable warnings\n    (void)total_hash_collisions;\n    (void)total_mutruns;\n    (void)total_preexisting;\n    (void)total_uniqued_away;\n    (void)total_identical;\n#endif\n\t\n\tif (total_final != total_mutruns - total_identical)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::UniqueMutationRuns): (internal error) bookkeeping error in mutation run uniquing.\" << EidosTerminate();\n}\n\n#ifndef __clang_analyzer__\nvoid Population::SplitMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome)\n{\n\t// Note this method assumes that mutation run refcounts are correct; we enforce that here\n\tTallyMutationRunReferencesForPopulationForChromosome(p_chromosome);\n\t\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome->Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome->Index()];\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\t// fix the child haplosomes for the chromosome since they also need to be resized\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->child_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t old_mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t old_mutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\tint32_t new_mutrun_count = old_mutrun_count << 1;\n\t\t\t\t\t\tslim_position_t new_mutrun_length = old_mutrun_length >> 1;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (haplosome->mutruns_ != haplosome->run_buffer_)\n\t\t\t\t\t\t\tfree(haplosome->mutruns_);\n\t\t\t\t\t\thaplosome->mutruns_ = nullptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->mutrun_count_ = new_mutrun_count;\n\t\t\t\t\t\thaplosome->mutrun_length_ = new_mutrun_length;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutrun_count <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thaplosome->mutruns_ = haplosome->run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t\tEIDOS_BZERO(haplosome->run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)calloc(new_mutrun_count, sizeof(const MutationRun *));\n#else\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)malloc(new_mutrun_count * sizeof(const MutationRun *));\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we leave the haplosome cleared to nullptr, as expected by the WF code\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// make a map to keep track of which mutation runs split into which new runs\n#if EIDOS_ROBIN_HOOD_HASHING\n\trobin_hood::unordered_flat_map<const MutationRun *, std::pair<const MutationRun *, const MutationRun *>> split_map;\n    //typedef robin_hood::pair<const MutationRun *, std::pair<const MutationRun *, const MutationRun *>> SLiM_SPLIT_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\tstd::unordered_map<const MutationRun *, std::pair<const MutationRun *, const MutationRun *>> split_map;\n    //typedef std::pair<const MutationRun *, std::pair<const MutationRun *, const MutationRun *>> SLiM_SPLIT_PAIR;\n#endif\n\t\n\tint mutruns_buf_index;\n\tconst MutationRun **mutruns_buf = (const MutationRun **)calloc(p_new_mutrun_count, sizeof(const MutationRun *));\n\t\n\tif (!mutruns_buf)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::SplitMutationRuns): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttry {\n\t\t// for every subpop\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t old_mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t old_mutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\tint32_t new_mutrun_count = old_mutrun_count << 1;\n\t\t\t\t\t\tslim_position_t new_mutrun_length = old_mutrun_length >> 1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// for every mutation run, fill up mutrun_buf with entries\n\t\t\t\t\t\tmutruns_buf_index = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < old_mutrun_count; ++run_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mutrun->use_count() == 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// this mutrun is only referenced once, so we can just replace it without using the map\n\t\t\t\t\t\t\t\t// checking use_count() this way is only safe because we run directly after tallying!\n\t\t\t\t\t\t\t\tMutationRun *first_half, *second_half;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tmutrun->split_run(&first_half, &second_half, new_mutrun_length * (mutruns_buf_index + 1), mutrun_context);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = first_half;\n\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = second_half;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// this mutrun is referenced more than once, so we want to use our map\n\t\t\t\t\t\t\t\tauto found_entry = split_map.find(mutrun);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (found_entry != split_map.end())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// it was in the map already, so just use the values from the map\n\t\t\t\t\t\t\t\t\tstd::pair<const MutationRun *, const MutationRun *> &map_value = found_entry->second;\n\t\t\t\t\t\t\t\t\tconst MutationRun *first_half = map_value.first;\n\t\t\t\t\t\t\t\t\tconst MutationRun *second_half = map_value.second;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = first_half;\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = second_half;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// it was not in the map, so make the new runs, and insert them into the map\n\t\t\t\t\t\t\t\t\tMutationRun *first_half, *second_half;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutrun->split_run(&first_half, &second_half, new_mutrun_length * (mutruns_buf_index + 1), mutrun_context);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = first_half;\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = second_half;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tsplit_map.emplace(mutrun, std::pair<MutationRun *, MutationRun *>(first_half, second_half));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// now replace the runs in the haplosome with those in mutrun_buf\n\t\t\t\t\t\tif (haplosome->mutruns_ != haplosome->run_buffer_)\n\t\t\t\t\t\t\tfree(haplosome->mutruns_);\n\t\t\t\t\t\thaplosome->mutruns_ = nullptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->mutrun_count_ = new_mutrun_count;\n\t\t\t\t\t\thaplosome->mutrun_length_ = new_mutrun_length;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutrun_count <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t\t\t\t\t\thaplosome->mutruns_ = haplosome->run_buffer_;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)malloc(new_mutrun_count * sizeof(const MutationRun *));\t// not calloc() because overwritten below\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < new_mutrun_count; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index] = mutruns_buf[run_index];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (...) {\n\t\t// I think the emplace() call is the only thing above that is likely to raise, due e.g. to using a bad hash function...\n\t\tEIDOS_TERMINATION << \"ERROR (Population::SplitMutationRuns): (internal error) SLiM encountered a raise from an internal hash table; please report this.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (mutruns_buf)\n\t\tfree(mutruns_buf);\n}\n#else\n// the static analyzer has a lot of trouble understanding this method\nvoid Population::SplitMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome)\n{\n}\n#endif\n\n// define a hash function for std::pair<MutationRun *, MutationRun *> so we can use it in our hash table below\n// see https://stackoverflow.com/questions/32685540/c-unordered-map-with-pair-as-key-not-compiling\nstruct slim_pair_hash {\n\ttemplate <class T1, class T2>\n\tstd::size_t operator () (const std::pair<T1,T2> &p) const {\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\tauto h1 = robin_hood::hash<T1>{}(p.first);\n\t\tauto h2 = robin_hood::hash<T2>{}(p.second);\n#elif STD_UNORDERED_MAP_HASHING\n\t\tauto h1 = std::hash<T1>{}(p.first);\n\t\tauto h2 = std::hash<T2>{}(p.second);\n#endif\n\t\t\n\t\t// This is not a great hash function, but for our purposes it should actually be fine.\n\t\t// We don't expect identical pairs <A, A>, and if we have a pair <A, B> we don't\n\t\t// expect to get the reversed pair <B, A>, so this should not produce too many collisions.\n\t\t// If we do get collisions we could switch to MutationRun::Hash() instead, but it is\n\t\t// much slower, so this is probably better.\n\t\t//return h1 ^ h2;\n\t\t\n\t\t// BCH 8/12/2021: Actually, we do see identical pairs <A, A> in some cases, so the\n\t\t// above hash function is really not great – it produces 0 for all such cases.  Let's\n\t\t// try being just a little bit smarter, so that <A, A> produces a variety of values.\n\t\t// We lost the top bits of h1, but often they will be 0 anyway, or always the same,\n\t\t// since these are pointers and the high bits are the overall region of memory we're in.\n\t\treturn (h1 << 8) ^ h2;\n\t}\n};\n\n#ifndef __clang_analyzer__\nvoid Population::JoinMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome)\n{\n\t// Note this method assumes that mutation run refcounts are correct; we enforce that here\n\tTallyMutationRunReferencesForPopulationForChromosome(p_chromosome);\n\t\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome->Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome->Index()];\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\t// fix the child haplosomes for the chromosome since they also need to be resized\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->child_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t old_mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t old_mutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\tint32_t new_mutrun_count = old_mutrun_count >> 1;\n\t\t\t\t\t\tslim_position_t new_mutrun_length = old_mutrun_length << 1;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (haplosome->mutruns_ != haplosome->run_buffer_)\n\t\t\t\t\t\t\tfree(haplosome->mutruns_);\n\t\t\t\t\t\thaplosome->mutruns_ = nullptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->mutrun_count_ = new_mutrun_count;\n\t\t\t\t\t\thaplosome->mutrun_length_ = new_mutrun_length;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutrun_count <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thaplosome->mutruns_ = haplosome->run_buffer_;\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t\tEIDOS_BZERO(haplosome->run_buffer_, SLIM_HAPLOSOME_MUTRUN_BUFSIZE * sizeof(const MutationRun *));\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)calloc(new_mutrun_count, sizeof(const MutationRun *));\n#else\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)malloc(new_mutrun_count * sizeof(const MutationRun *));\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we leave the haplosome cleared to nullptr, as expected by the WF code\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// make a map to keep track of which mutation runs join into which new runs\n#if EIDOS_ROBIN_HOOD_HASHING\n\trobin_hood::unordered_flat_map<std::pair<const MutationRun *, const MutationRun *>, const MutationRun *, slim_pair_hash> join_map;\n    //typedef robin_hood::pair<std::pair<const MutationRun *, const MutationRun *>, const MutationRun *> SLiM_JOIN_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\tstd::unordered_map<std::pair<const MutationRun *, const MutationRun *>, const MutationRun *, slim_pair_hash> join_map;\n    //typedef std::pair<std::pair<const MutationRun *, const MutationRun *>, const MutationRun *> SLiM_JOIN_PAIR;\n#endif\n\tint mutruns_buf_index;\n\tconst MutationRun **mutruns_buf = (const MutationRun **)calloc(p_new_mutrun_count, sizeof(const MutationRun *));\n\t\n\tif (!mutruns_buf)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::JoinMutationRuns): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttry {\n\t\t// for every subpop\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t old_mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t old_mutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\tint32_t new_mutrun_count = old_mutrun_count >> 1;\n\t\t\t\t\t\tslim_position_t new_mutrun_length = old_mutrun_length << 1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// for every mutation run, fill up mutrun_buf with entries\n\t\t\t\t\t\tmutruns_buf_index = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < old_mutrun_count; run_index += 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun1 = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\tconst MutationRun *mutrun2 = haplosome->mutruns_[run_index + 1];\n\t\t\t\t\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((mutrun1->use_count() == 1) || (mutrun2->use_count() == 1))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// one of these mutruns is only referenced once, so we can just replace them without using the map\n\t\t\t\t\t\t\t\t// checking use_count() this way is only safe because we run directly after tallying!\n\t\t\t\t\t\t\t\tMutationRun *joined_run = MutationRun::NewMutationRun(mutrun_context);\t// take from shared pool of used objects\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tjoined_run->copy_from_run(*mutrun1);\n\t\t\t\t\t\t\t\tjoined_run->emplace_back_bulk(mutrun2->begin_pointer_const(), mutrun2->size());\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = joined_run;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// this mutrun is referenced more than once, so we want to use our map\n\t\t\t\t\t\t\t\tauto found_entry = join_map.find(std::pair<const MutationRun *, const MutationRun *>(mutrun1, mutrun2));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (found_entry != join_map.end())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// it was in the map already, so just use the values from the map\n\t\t\t\t\t\t\t\t\tconst MutationRun *map_value = found_entry->second;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = map_value;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// it was not in the map, so make the new runs, and insert them into the map\n\t\t\t\t\t\t\t\t\tMutationRun *joined_run = MutationRun::NewMutationRun(mutrun_context);\t// take from shared pool of used objects\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tjoined_run->copy_from_run(*mutrun1);\n\t\t\t\t\t\t\t\t\tjoined_run->emplace_back_bulk(mutrun2->begin_pointer_const(), mutrun2->size());\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutruns_buf[mutruns_buf_index++] = joined_run;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tjoin_map.emplace(std::pair<const MutationRun *, const MutationRun *>(mutrun1, mutrun2), joined_run);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// now replace the runs in the haplosome with those in mutrun_buf\n\t\t\t\t\t\tif (haplosome->mutruns_ != haplosome->run_buffer_)\n\t\t\t\t\t\t\tfree(haplosome->mutruns_);\n\t\t\t\t\t\thaplosome->mutruns_ = nullptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome->mutrun_count_ = new_mutrun_count;\n\t\t\t\t\t\thaplosome->mutrun_length_ = new_mutrun_length;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (new_mutrun_count <= SLIM_HAPLOSOME_MUTRUN_BUFSIZE)\n\t\t\t\t\t\t\thaplosome->mutruns_ = haplosome->run_buffer_;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosome->mutruns_ = (const MutationRun **)malloc(new_mutrun_count * sizeof(const MutationRun *));\t// not calloc() because overwritten below\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < new_mutrun_count; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index] = mutruns_buf[run_index];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch (...) {\n\t\t// I think the emplace() call is the only thing above that is likely to raise, due e.g. to using a bad hash function...\n\t\tEIDOS_TERMINATION << \"ERROR (Population::JoinMutationRuns): (internal error) SLiM encountered a raise from an internal hash table; please report this.\" << EidosTerminate(nullptr);\n\t}\n\n\tif (mutruns_buf)\n\t\tfree(mutruns_buf);\n}\n#else\n// the static analyzer has a lot of trouble understanding this method\nvoid Population::JoinMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome)\n{\n}\n#endif\n\n// Tally mutations and remove fixed/lost mutations\nvoid Population::MaintainMutationRegistry(void)\n{\n\tif ((model_type_ == SLiMModelType::kModelTypeWF) && child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MaintainMutationRegistry): (internal error) MaintainMutationRegistry() may only be called from the parent generation in WF models.\" << EidosTerminate();\n\t\n\t// go through all haplosomes and increment mutation reference counts; this updates total_haplosome_count_\n\t// this will call TallyMutationRunReferencesForPopulation() as a side effect unless it hits its cache\n\t{\n\t\tInvalidateMutationReferencesCache();\t// force a retally\n\t\t\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_MUT_TALLY);\n\t\tTallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ true);\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_MUT_TALLY);\n\t}\n\t\n\t// free unused mutation runs, relying upon the tally done above\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_MUTRUN_FREE);\n\t\tFreeUnusedMutationRuns();\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_MUTRUN_FREE);\n\t}\n\t\n\t// remove any mutations that have been eliminated or have fixed\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_MUT_FREE);\n\t\tRemoveAllFixedMutations();\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_MUT_FREE);\n\t}\n\t\n\t// check that the mutation registry does not have any \"zombies\" – mutations that have been removed and should no longer be there\n\t// also check for any mutations that are in the registry but do not have the state MutationState::kInRegistry\n#if DEBUG\n\tCheckMutationRegistry(true);\t// full check\n\tregistry_needs_consistency_check_ = false;\n#else\n\tif (registry_needs_consistency_check_)\n\t{\n\t\tCheckMutationRegistry(false);\t// check registry but not haplosomes\n\t\tregistry_needs_consistency_check_ = false;\n\t}\n#endif\n\t\n\t// debug output: assess mutation run usage patterns\n#if SLIM_DEBUG_MUTATION_RUNS\n\tAssessMutationRuns();\n#endif\n}\n\n// assess usage patterns of mutation runs across the simulation\nvoid Population::AssessMutationRuns(void)\n{\n\t// Note this method assumes that mutation run use counts are correct; it should be called immediately after tallying\n\t\n\tif ((model_type_ == SLiMModelType::kModelTypeWF) && child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::AssessMutationRuns): (internal error) AssessMutationRuns() may only be called from the parent generation in WF models.\" << EidosTerminate();\n\t\n\tslim_tick_t tick = community_.Tick();\n\t\n\tif (tick % 1000 == 0)\n\t{\n\t\tstd::cout << \"***** AssessMutationRuns(), tick \" << tick << \":\" << std::endl;\n\t\tstd::cout << \"   Mutation count: \" << mutation_registry_.size() << std::endl;\n\t\t\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t{\n\t\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\tint registry_size = 0, registry_count_in_chromosome = 0;\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\t\t\n\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t{\n\t\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\t\n\t\t\t\tif (mut->chromosome_index_ == chromosome_index)\n\t\t\t\t\tregistry_count_in_chromosome++;\n\t\t\t}\n\t\t\t\n\t\t\tint first_haplosome_index = species_.FirstHaplosomeIndices()[chromosome_index];\n\t\t\tint last_haplosome_index = species_.LastHaplosomeIndices()[chromosome_index];\n\t\t\tslim_refcount_t total_haplosome_count = 0, total_mutrun_count = 0, total_shared_mutrun_count = 0;\n\t\t\tint mutrun_count = 0, use_count_total = 0;\n\t\t\tslim_position_t mutrun_length = 0;\n\t\t\tint64_t mutation_total = 0;\n\t\t\t\n\t\t\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\t\t\n\t\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\t{\n\t\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\t\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\tmutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\t\tint mutrun_size = mutrun->size();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\ttotal_mutrun_count++;\n\t\t\t\t\t\t\t\tmutation_total += mutrun_size;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (mutrun->operation_id_ != operation_id)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_refcount_t use_count = (slim_refcount_t)mutrun->use_count();\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\ttotal_shared_mutrun_count++;\n\t\t\t\t\t\t\t\t\tuse_count_total += use_count;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmutrun->operation_id_ = operation_id;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttotal_haplosome_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstd::cout << \"   ========== Chromosome index \" << (unsigned int)(chromosome->Index()) << \", id \" << chromosome->ID() << \", symbol \" << chromosome->Symbol() << \" (length \" << (chromosome->last_position_ + 1) << \")\" << std::endl;\n\t\t\tstd::cout << \"   Mutation count in chromosome: \" << registry_count_in_chromosome << std::endl;\n\t\t\tstd::cout << \"   Haplosome count: \" << total_haplosome_count << \" (divided into \" << mutrun_count << \" mutation runs of length \" << mutrun_length << \")\" << std::endl;\n\t\t\t\n\t\t\tstd::cout << \"   Mutation run unshared: \" << total_mutrun_count;\n\t\t\tif (total_mutrun_count) std::cout << \" (containing \" << (mutation_total / (double)total_mutrun_count) << \" mutations on average)\";\n\t\t\tstd::cout << std::endl;\n\t\t\t\n\t\t\tstd::cout << \"   Mutation run actual: \" << total_shared_mutrun_count;\n\t\t\tif (total_shared_mutrun_count) std::cout << \" (mean use count \" << (use_count_total / (double)total_shared_mutrun_count) << \")\";\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n}\n\n// WF only:\n// step forward to the next generation: make the children become the parents\nvoid Population::SwapGenerations(void)\n{\n\t// record lifetime reproductive outputs for all parents before swapping, including in subpops being removed\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\tsubpop_pair.second->TallyLifetimeReproductiveOutput();\n\tfor (Subpopulation *subpop : removed_subpops_)\n\t\tsubpop->TallyLifetimeReproductiveOutput();\n\t\n\t// dispose of any freed subpops\n\tPurgeRemovedSubpopulations();\n\t\n\t// make children the new parents; each subpop flips its child_generation_valid_ flag at the end of this call\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\tsubpop_pair.second->SwapChildAndParentHaplosomes();\n\t\n\t// flip our flag to indicate that the good haplosomes are now in the parental generation, and the next child generation is ready to be produced\n\tchild_generation_valid_ = false;\n}\n\nvoid Population::TallyMutationRunReferencesForPopulationForChromosome(Chromosome *p_chromosome)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForPopulationForChromosome): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\tslim_refcount_t tallied_haplosome_count = 0;\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome->Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome->Index()];\n\tint mutrun_count_multiplier = p_chromosome->mutrun_count_multiplier_;\n\tint mutrun_context_count = p_chromosome->ChromosomeMutationRunContextCount();\n\t\n\tif (mutrun_count_multiplier * mutrun_context_count != p_chromosome->mutrun_count_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForPopulationForChromosome): (internal error) mutation run subdivision is incorrect.\" << EidosTerminate();\n\t\n\t// THIS PARALLEL REGION CANNOT HAVE AN IF()!  IT MUST ALWAYS EXECUTE PARALLEL!\n\t// the reduction() is a bit odd - every thread will generate the same value, and we just want that value,\n\t// but lastprivate() is not legal for parallel regions, for some reason, so we use reduction(max)\n#pragma omp parallel default(none) shared(mutrun_count_multiplier, mutrun_context_count, std::cerr) reduction(max: total_haplosome_count) num_threads(mutrun_context_count)\n\t{\n\t\t// this is initialized by OpenMP to the most negative number (reduction type max); we want zero instead!\n\t\ttallied_haplosome_count = 0;\n\t\t\n#ifdef _OPENMP\n\t\t// it is imperative that we run with the requested number of threads\n\t\tif (omp_get_num_threads() != mutrun_context_count)\n\t\t{\n\t\t\tstd::cerr << \"requested  \" << mutrun_context_count << \" threads but got \" << omp_get_num_threads() << std::endl;\n\t\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::TallyMutationRunReferencesForPopulationForChromosome(): incorrect thread count!\");\n\t\t}\n#endif\n\t\t\n\t\t// first, zero all use counts across all in-use MutationRun objects\n\t\t// each thread does its own zeroing, for its own MutationRunContext\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : mutrun_context.in_use_pool_)\n\t\t\t\tmutrun->zero_use_count();\n\t\t}\n\t\t\n\t\t// second, loop through all haplosomes in all subpops and tally the usage of their MutationRun objects\n\t\t// each thread handles only the range of mutation run indices that it is responsible for\n\t\tint first_mutrun_index = omp_get_thread_num() * mutrun_count_multiplier;\n\t\tint last_mutrun_index = first_mutrun_index + mutrun_count_multiplier - 1;\n\t\t\n\t\t// note this is NOT an OpenMP parallel for loop!  each encountering thread runs every iteration!\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tif (subpop->CouldContainNullHaplosomes())\n\t\t\t{\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttallied_haplosome_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// optimized case when null haplosomes do not exist in this subpop\n\t\t\t\t\n\t\t\t\tif (last_haplosome_index == first_haplosome_index + 1)\n\t\t\t\t{\n\t\t\t\t\t// optimize the simple diploid single-chromosome case\n\t\t\t\t\tif (first_haplosome_index == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// optimize the first-chromosome case\n\t\t\t\t\t\tif ((first_mutrun_index == last_mutrun_index) && (first_mutrun_index == 0))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// optimize the one-mutrun case (given first-chromosome as well)\n\t\t\t\t\t\t\t// this is the hotspot for simple one-chromosome diploid models; note that it\n\t\t\t\t\t\t\t// runs about twice as slowly as in 4.3, because we no longer have subpop_genomes\n\t\t\t\t\t\t\t// to loop through directly, so we have to gather haplosomes from individuals;\n\t\t\t\t\t\t\t// I don't see a way to recover that performance loss easily\n\t\t\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tind->haplosomes_[0]->mutruns_[0]->increment_use_count();\n\t\t\t\t\t\t\t\tind->haplosomes_[1]->mutruns_[0]->increment_use_count();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tHaplosome *haplosome0 = ind->haplosomes_[0];\n\t\t\t\t\t\t\t\tHaplosome *haplosome1 = ind->haplosomes_[1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thaplosome0->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\t\thaplosome1->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (first_mutrun_index == last_mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// optimize the one-mutrun case\n\t\t\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tind->haplosomes_[first_haplosome_index]->mutruns_[first_mutrun_index]->increment_use_count();\n\t\t\t\t\t\t\t\tind->haplosomes_[first_haplosome_index+1]->mutruns_[first_mutrun_index]->increment_use_count();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tHaplosome *haplosome0 = ind->haplosomes_[first_haplosome_index];\n\t\t\t\t\t\t\t\tHaplosome *haplosome1 = ind->haplosomes_[first_haplosome_index+1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thaplosome0->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\t\thaplosome1->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttallied_haplosome_count += (subpop->parent_individuals_.size() * (last_haplosome_index - first_haplosome_index + 1));\n\t\t\t}\n\t\t}\n\t}\n\t\n#if DEBUG\n\t// In debug builds we do a complete re-tally single-threaded, into a side counter, for a check-back\n\t{\n\t\tslim_refcount_t tallied_haplosome_count_CHECK = 0;\n\t\t\n\t\tfor (int threadnum = 0; threadnum < p_chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t inuse_pool_count = inuse_pool.size();\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < inuse_pool_count; ++pool_index)\n\t\t\t\tinuse_pool[pool_index]->use_count_CHECK_ = 0;\n\t\t}\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->use_count_CHECK_++;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttallied_haplosome_count_CHECK++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (tallied_haplosome_count_CHECK != tallied_haplosome_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForPopulationForChromosome): (internal error) tallied_haplosome_count_CHECK != tallied_haplosome_count (\" << tallied_haplosome_count_CHECK << \" != \" << tallied_haplosome_count << \").\" << EidosTerminate();\n\t\t\n\t\tfor (int threadnum = 0; threadnum < p_chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t inuse_pool_count = inuse_pool.size();\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < inuse_pool_count; ++pool_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = inuse_pool[pool_index];\n\t\t\t\t\n\t\t\t\tif (mutrun->use_count_CHECK_ != mutrun->use_count())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForPopulationForChromosome): (internal error) use_count_CHECK_ \" << mutrun->use_count_CHECK_ << \" != mutrun->use_count() \" << mutrun->use_count() << \".\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n#endif\n\t\n\t// if you want to then free the mutation runs that are unused, call FreeUnusedMutationRuns()\n\t\n\tp_chromosome->tallied_haplosome_count_ = tallied_haplosome_count;\n}\n\nvoid Population::TallyMutationRunReferencesForPopulation(bool p_clock_for_mutrun_experiments)\n{\n\t// Each chromosome is tallied separately, in the present design; this allows parallelization to work differently for each\n\tif (p_clock_for_mutrun_experiments)\n\t{\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t{\n\t\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\t\n\t\t\tTallyMutationRunReferencesForPopulationForChromosome(chromosome);\n\t\t\t\n\t\t\tchromosome->StopMutationRunExperimentClock(\"TallyMutationRunReferencesForPopulation()\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t\tTallyMutationRunReferencesForPopulationForChromosome(chromosome);\n\t}\n}\n\nvoid Population::TallyMutationRunReferencesForSubpopsForChromosome(std::vector<Subpopulation*> *p_subpops_to_tally, Chromosome *p_chromosome)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForSubpops): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\tslim_refcount_t tallied_haplosome_count = 0;\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome->Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome->Index()];\n\tint mutrun_count_multiplier = p_chromosome->mutrun_count_multiplier_;\n\tint mutrun_context_count = p_chromosome->ChromosomeMutationRunContextCount();\n\t\n\tif (mutrun_count_multiplier * mutrun_context_count != p_chromosome->mutrun_count_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForSubpops): (internal error) mutation run subdivision is incorrect.\" << EidosTerminate();\n\t\n\t// THIS PARALLEL REGION CANNOT HAVE AN IF()!  IT MUST ALWAYS EXECUTE PARALLEL!\n\t// the reduction() is a bit odd - every thread will generate the same value, and we just want that value,\n\t// but lastprivate() is not legal for parallel regions, for some reason, so we use reduction(max)\n#pragma omp parallel default(none) shared(mutrun_count_multiplier, mutrun_context_count, std::cerr, p_subpops_to_tally) reduction(max: total_haplosome_count) num_threads(mutrun_context_count)\n\t{\n\t\t// this is initialized by OpenMP to the most negative number (reduction type max); we want zero instead!\n\t\ttallied_haplosome_count = 0;\n\t\t\n#ifdef _OPENMP\n\t\t// it is imperative that we run with the requested number of threads\n\t\tif (omp_get_num_threads() != mutrun_context_count)\n\t\t{\n\t\t\tstd::cerr << \"requested  \" << mutrun_context_count << \" threads but got \" << omp_get_num_threads() << std::endl;\n\t\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::TallyMutationRunReferencesForSubpops(): incorrect thread count!\");\n\t\t}\n#endif\n\t\t\n\t\t// first, zero all use counts across all in-use MutationRun objects\n\t\t// each thread does its own zeroing, for its own MutationRunContext\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : mutrun_context.in_use_pool_)\n\t\t\t\tmutrun->zero_use_count();\n\t\t}\n\t\t\n\t\t// second, loop through all haplosomes in all subpops and tally the usage of their MutationRun objects\n\t\t// each thread handles only the range of mutation run indices that it is responsible for\n\t\tint first_mutrun_index = omp_get_thread_num() * mutrun_count_multiplier;\n\t\tint last_mutrun_index = first_mutrun_index + mutrun_count_multiplier - 1;\n\t\t\n\t\t// note this is NOT an OpenMP parallel for loop!  each encountering thread runs every iteration!\n\t\tfor (Subpopulation *subpop : *p_subpops_to_tally)\n\t\t{\n\t\t\tif (subpop->CouldContainNullHaplosomes())\n\t\t\t{\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttallied_haplosome_count++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// optimized case when null haplosomes do not exist in this subpop\n\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t{\n\t\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = first_mutrun_index; run_index <= last_mutrun_index; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->increment_use_count();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttallied_haplosome_count += subpop->parent_individuals_.size() * (last_haplosome_index - first_haplosome_index + 1);\n\t\t\t}\n\t\t}\n\t}\n\t\n#if DEBUG\n\t// In debug builds we do a complete re-tally single-threaded, into a side counter, for a check-back\n\t// The code for this is very similar to the code above, but it at least checks that optimizations above are correct...\n\t{\n\t\tslim_refcount_t tallied_haplosome_count_CHECK = 0;\n\t\t\n\t\tfor (int threadnum = 0; threadnum < p_chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t inuse_pool_count = inuse_pool.size();\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < inuse_pool_count; ++pool_index)\n\t\t\t\tinuse_pool[pool_index]->use_count_CHECK_ = 0;\n\t\t}\n\t\t\n\t\tfor (const Subpopulation *subpop : *p_subpops_to_tally)\n\t\t{\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->use_count_CHECK_++;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttallied_haplosome_count_CHECK++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (tallied_haplosome_count_CHECK != tallied_haplosome_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForSubpopsForChromosome): (internal error) tallied_haplosome_count_CHECK != tallied_haplosome_count (\" << tallied_haplosome_count_CHECK << \" != \" << tallied_haplosome_count << \").\" << EidosTerminate();\n\t\t\n\t\tfor (int threadnum = 0; threadnum < p_chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = p_chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t inuse_pool_count = inuse_pool.size();\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < inuse_pool_count; ++pool_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = inuse_pool[pool_index];\n\t\t\t\t\n\t\t\t\tif (mutrun->use_count_CHECK_ != mutrun->use_count())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationRunReferencesForSubpopsForChromosome): (internal error) use_count_CHECK_ \" << mutrun->use_count_CHECK_ << \" != mutrun->use_count() \" << mutrun->use_count() << \".\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n#endif\n\t\n\tp_chromosome->tallied_haplosome_count_ = tallied_haplosome_count;\n}\n\nvoid Population::TallyMutationRunReferencesForSubpops(std::vector<Subpopulation*> *p_subpops_to_tally)\n{\n\t// Each chromosome is tallied separately, in the present design; this allows parallelization to work differently for each\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\tTallyMutationRunReferencesForSubpopsForChromosome(p_subpops_to_tally, chromosome);\n}\n\nvoid Population::TallyMutationRunReferencesForHaplosomes(const Haplosome * const *haplosomes_ptr, slim_popsize_t haplosomes_count)\n{\n\t// FIXME parallelize this; unclear how, since the haplosomes might be scattered across chromosomes\n\t// could perhaps check for the haplosomes all belonging to one chromosome, and parallelize that\n\t// specific case, which is obvious, at least; probably that's the common case.\n\t\t\n\t// first, zero all chromosome tallies and all use counts across all in-use MutationRun objects\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tchromosome->tallied_haplosome_count_ = 0;\n\t\t\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n\t\t\n\t\tfor (int mutrun_context_index = 0; mutrun_context_index < mutrun_context_count; ++mutrun_context_index)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(mutrun_context_index);\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : mutrun_context.in_use_pool_)\n\t\t\t\tmutrun->zero_use_count();\n\t\t}\n\t}\n\t\n\t// second, loop through all haplosomes in all subpops and tally the usage of their MutationRun objects\n\tfor (slim_popsize_t haplosome_index = 0; haplosome_index < haplosomes_count; ++haplosome_index)\n\t{\n\t\tconst Haplosome *haplosome = haplosomes_ptr[haplosome_index];\n\t\t\n\t\tif (!haplosome->IsNull())\n\t\t{\n\t\t\tfor (int run_index = 0; run_index < haplosome->mutrun_count_; ++run_index)\n\t\t\t\thaplosome->mutruns_[run_index]->increment_use_count();\n\t\t\t\n\t\t\tChromosome *chromosome = species_.Chromosomes()[haplosome->chromosome_index_];\n\t\t\tchromosome->tallied_haplosome_count_++;\n\t\t}\n\t}\n}\n\nvoid Population::FreeUnusedMutationRuns(void)\n{\n\t// It is assumed by this method that mutation run tallies are up to date!\n\t// The caller must ensure that by calling TallyMutationRunReferencesForPopulation()!\n\t\n#if DEBUG\n\t// Check for usage of each mutation run we intend to free, to catch bugs in that area.\n\t// This is useful for debugging problems with mutation run freeing, such as the error\n\t// message \"a mutation run was used at more than one position\", which is a symptom\n\t// of a mutation being freed while it is still in use.\n\t\n\t// first set the use_count_CHECK_ of all mutation runs to zero\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n\t\t\n\t\tfor (int mutrun_context_index = 0; mutrun_context_index < mutrun_context_count; ++mutrun_context_index)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(mutrun_context_index);\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : mutrun_context.in_use_pool_)\n\t\t\t\tmutrun->use_count_CHECK_ = 0;\n\t\t}\n\t}\n\t\n\t// then go through all haplosomes of all individuals of all subpops, and increment their use count\n\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t{\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\thaplosome->mutruns_[run_index]->use_count_CHECK_++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// then check for mutruns with a use count of 0 (slated to be freed) but a non-zero check count (still in use)\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n\t\t\n\t\tfor (int mutrun_context_index = 0; mutrun_context_index < mutrun_context_count; ++mutrun_context_index)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(mutrun_context_index);\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : mutrun_context.in_use_pool_)\n\t\t\t\tif ((mutrun->use_count() == 0) && (mutrun->use_count_CHECK_ != 0))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::FreeUnusedMutationRuns): (internal error) use_count() is zero for mutrun with actual usage count \" << mutrun->use_count_CHECK_ << \"!\" << EidosTerminate();\n\t\t}\n\t}\n#endif\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// free all in-use MutationRun objects that are not actually in use (use count == 0)\n\t\t// each thread does its own checking and freeing, for its own MutationRunContext\n#ifdef _OPENMP\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n#endif\n\t\t\n#pragma omp parallel default(none) num_threads(mutrun_context_count)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t pool_count = inuse_pool.size();\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < pool_count; )\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = inuse_pool[pool_index];\n\t\t\t\t\n\t\t\t\tif (mutrun->use_count() == 0)\n\t\t\t\t{\n\t\t\t\t\t// First we remove the mutation run from the inuse pool by backfilling\n\t\t\t\t\tinuse_pool[pool_index] = inuse_pool.back();\n\t\t\t\t\tinuse_pool.pop_back();\n\t\t\t\t\t\n\t\t\t\t\t// Because we backfilled, we want to stay at this index, but the pool is one smaller\n\t\t\t\t\t// This is why we remove the run ourselves, instead of FreeMutationRun() doing it\n\t\t\t\t\t--pool_count;\n\t\t\t\t\t\n\t\t\t\t\t// Then we give the mutation run back to the free pool\n\t\t\t\t\tMutationRun::FreeMutationRun(mutrun, mutrun_context);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t++pool_index;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tchromosome->StopMutationRunExperimentClock(\"FreeUnusedMutationRuns()\");\n\t}\n}\n\n// count the number of non-null haplosomes in the population\nslim_refcount_t Population::_CountNonNullHaplosomesForChromosome(Chromosome *p_chromosome)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::_CountNonNullHaplosomesForChromosome): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\tslim_chromosome_index_t chromosome_index = p_chromosome->Index();\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[chromosome_index];\n\tslim_refcount_t total_haplosome_count = 0;\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\n\t\tif (subpop->CouldContainNullHaplosomes())\n\t\t{\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\ttotal_haplosome_count++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// optimized case when null haplosomes do not exist in this subpop\n\t\t\ttotal_haplosome_count += subpop->parent_individuals_.size() * (last_haplosome_index - first_haplosome_index + 1);\n\t\t}\n\t}\n\t\n\treturn total_haplosome_count;\n}\n\nvoid Population::InvalidateMutationReferencesCache(void)\n{\n\tlast_tallied_subpops_.resize(0);\n\tcached_tallies_valid_ = false;\n}\n\n// count the total number of times that each Mutation in the registry is referenced by the whole population\nvoid Population::TallyMutationReferencesAcrossPopulation(bool p_clock_for_mutrun_experiments)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationReferencesAcrossPopulation): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\t// Figure out whether the last tally was of the same thing, such that we can skip the work\n\t// For this code path (across population), last_tallied_subpops_ must be zero to hit the cache\n\tif (cached_tallies_valid_ && (last_tallied_subpops_.size() == 0))\n\t{\n\t\t// we hit the cache; we just return so the previously computed result is reused\n\t\t\n#if DEBUG\n#if DEBUG_LESS_INTENSIVE\n\t\t// These tests are extremely intensive, so sometimes it's useful to dial them down...\n\t\tif ((community_.Tick() % 97) != 5)\n\t\t\treturn;\n#endif\n\t\t\n\t\t// check that the cached haplosome count is correct; note that it includes only non-null haplosomes\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t{\n\t\t\tslim_refcount_t tallied_haplosome_count = _CountNonNullHaplosomesForChromosome(chromosome);\n\t\t\t\n\t\t\tif (tallied_haplosome_count != chromosome->tallied_haplosome_count_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationReferencesAcrossPopulation): (internal error) cached case hit incorrectly; tallied_haplosome_count_ is not correct.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// in DEBUG mode, do the complete check below as well; it should match, if the cache is valid\n\t\tgoto doDebugCheck;\n#endif\n\t\t\n\t\treturn;\n\t}\n\t\n\t// Tally mutation run usage first, and then leverage that to tally mutations\n\t// Note this sets up tallied_haplosome_count_ for all chromosomes\n\tTallyMutationRunReferencesForPopulation(p_clock_for_mutrun_experiments);\n\t\n\t// Give the core work to our fast worker method; this zeroes and then tallies\n\t_TallyMutationReferences_FAST_FromMutationRunUsage(p_clock_for_mutrun_experiments);\n\t\n#if DEBUG\ndoDebugCheck:\n\t{\n\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\tstd::vector<Haplosome *> haplosomes;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **ind_haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = ind_haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\thaplosomes.push_back(haplosome);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t_CheckMutationTallyAcrossHaplosomes(haplosomes.data(), (slim_popsize_t)haplosomes.size(), \"Population::TallyMutationReferencesAcrossPopulation()\");\n\t}\n#endif\n\t\n\t// set up the cache info\n\tlast_tallied_subpops_.resize(0);\n\tcached_tallies_valid_ = true;\n\t\n\t// When tallying the full population, we update total_haplosome_count_ as well, since we did the work\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\tchromosome->total_haplosome_count_ = chromosome->tallied_haplosome_count_;\n}\n\n#ifdef SLIMGUI\n// this tallies separately for SLiMgui, into private counters, across the selected subpopulations only\n// we pay a performance price for this in SLiMgui in the cases when the main tally is up to date and\n// would be accurate, but there have been too many bugs with trying to do both at the same time; if\n// there is going to be any smart caching behavior for SLiMgui, it needs to be in this code path only\nvoid Population::TallyMutationReferencesAcrossPopulation_SLiMgui(void)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationReferencesAcrossPopulation_SLiMgui): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\t// We're in SLiMgui, so we need to figure out how we're going to handle its refcounts, which are\n\t// separate from slim's since the user can select just a subset of subpopulations.\n\tbool slimgui_subpop_all_selected = true;\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\tif (!subpop_pair.second->gui_selected_)\n\t\t\tslimgui_subpop_all_selected = false;\n\t\n\tif (slimgui_subpop_all_selected)\n\t{\n\t\t// All subpopulations are selected in SLiMgui, so we can tally using MutationRun across\n\t\t// the whole population.  A tally from TallyMutationReferencesAcrossPopulation() will \n\t\t// thus be valid, and might even hit its cache.  We can subcontract to it to do the work.\n\t\tTallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t}\n\telse\n\t{\n\t\t// A subset of subpops are selected in SLiMgui, so we can tally using MutationRun across\n\t\t// those subpops with TallyMutationReferencesAcrossSubpopulations().\n\t\tstd::vector<Subpopulation *> subpops_to_tally;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t\t\tif (subpop_pair.second->gui_selected_)\n\t\t\t\tsubpops_to_tally.push_back(subpop_pair.second);\n\t\t\n\t\tTallyMutationReferencesAcrossSubpopulations(&subpops_to_tally);\n\t}\n\t\n\t// Then copy the tallied refcounts into our private refcounts\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\tint registry_size;\n\tconst MutationIndex *registry_iter = MutationRegistry(&registry_size);\n\tconst MutationIndex *registry_iter_end = registry_iter + registry_size;\n\t\n\twhile (registry_iter != registry_iter_end)\n\t{\n\t\tMutationIndex mut_index = *registry_iter;\n\t\tslim_refcount_t *refcount_ptr = refcount_block_ptr + mut_index;\n\t\tconst Mutation *mutation = mut_block_ptr + mut_index;\n\t\t\n\t\tmutation->gui_reference_count_ = *refcount_ptr;\n\t\tregistry_iter++;\n\t}\n\t\n\t// And update the SLiMgui total haplosome counts from the tally as well\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\tchromosome->gui_total_haplosome_count_ = chromosome->tallied_haplosome_count_;\n\t\n\t// There seems to be no need for a separate DEBUG check here, because the calls above to\n\t// TallyMutationReferencesAcrossPopulation() / TallyMutationReferencesAcrossSubpopulations()\n\t// already have their own DEBUG check code; we just copy the work they did for us.\n}\n#endif\n\nvoid Population::TallyMutationReferencesAcrossSubpopulations(std::vector<Subpopulation*> *p_subpops_to_tally)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::TallyMutationReferencesAcrossSubpopulations): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\t// When tallying just a subset of the subpops, we don't update total_haplosome_count_,\n\t// which applies only to population-wide tallies; but we do set tallied_haplosome_count_\n\t\n\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\t\n\t// We have two ways of tallying; here we decide which way to use.  We only loop through haplosomes\n\t// if we are tallying for a single subpopulation and it is small; otherwise, looping through\n\t// mutation runs is expected to be faster.  Tallying with mutruns would still work, just slower.\n\tbool tally_using_mutruns = true;\n\n\tif (p_subpops_to_tally->size() == 0)\t\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\ttally_using_mutruns = false;\n\telse if ((p_subpops_to_tally->size() == 1) && ((*p_subpops_to_tally)[0]->parent_individuals_.size() <= 5))\n\t\ttally_using_mutruns = false;\n\t\n\t// Figure out whether the last tally was of the same thing, such that we can skip the work\n\tif (cached_tallies_valid_ && last_tallied_subpops_.size() && (last_tallied_subpops_ == *p_subpops_to_tally))\n\t{\n\t\t// we hit the cache; we just return so the previously computed result is reused\n\t\t\n#if DEBUG\n\t\t// in DEBUG mode, do the complete check below as well; it should match, if the cache is valid\n\t\tgoto doDebugCheck;\n#endif\n\t\t\n\t\treturn;\n\t}\n\t\n\tif (tally_using_mutruns)\n\t{\n\t\t// FAST PATH: Tally mutation run usage first, and then leverage that to tally mutations\n\t\t// Note that this call sets up tallied_haplosome_count_ for all chromosomes\n\t\tTallyMutationRunReferencesForSubpops(p_subpops_to_tally);\n\t\t\n\t\t// Give the core work to our fast worker method; this zeroes and then tallies\n\t\t_TallyMutationReferences_FAST_FromMutationRunUsage(/* p_clock_for_mutrun_experiments */ false);\n\t}\n\telse\n\t{\n\t\t// SLOW PATH: Increment the refcounts through all pointers to Mutation in all haplosomes\n\t\tSLiM_ZeroRefcountBlock(mutation_registry_, /* p_registry_only */ community_.AllSpecies().size() > 1);\n\t\t\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t\tchromosome->tallied_haplosome_count_ = 0;\n\t\t\n\t\tfor (Subpopulation *subpop : *p_subpops_to_tally)\n\t\t{\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **ind_haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = ind_haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tChromosome *chromosome = species_.ChromosomesForHaplosomeIndices()[haplosome_index];\n\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\tconst MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n\t\t\t\t\t\t\t\t++(*(refcount_block_ptr + *haplosome_iter));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tchromosome->tallied_haplosome_count_++;\t// count only non-null haplosomes to determine fixation\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n#if DEBUG\ndoDebugCheck:\n\t{\n\t\tstd::vector<Haplosome *> haplosomes;\n\t\t\n\t\tfor (Subpopulation *subpop : *p_subpops_to_tally)\n\t\t{\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **ind_haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = ind_haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\thaplosomes.push_back(haplosome);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t_CheckMutationTallyAcrossHaplosomes(haplosomes.data(), (slim_popsize_t)haplosomes.size(), \"Population::TallyMutationReferencesAcrossSubpopulations()\");\n\t}\n#endif\n\t\n\t// set up the cache info\n\tlast_tallied_subpops_ = *p_subpops_to_tally;\n\tcached_tallies_valid_ = true;\n}\n\nvoid Population::TallyMutationReferencesAcrossHaplosomes(const Haplosome * const *haplosomes_ptr, slim_popsize_t haplosomes_count)\n{\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\t\n\t// We have two ways of tallying; here we decide which way to use.  We tally directly by\n\t// looping through haplosomes below a certain problem threshold, because there is some\n\t// overhead to tallying the mutation runs; it's not worth it for small problems.  The\n\t// threshold is a complete guess; in reality it will depend upon how much mutation run\n\t// sharing is present, how many mutations per run there are, and many other factors.\n\t// I put the threshold pretty low because if you do mutruns and you're wrong, you just\n\t// pay a small fixed overhead, but if you do haplosomes and you're wrong, it can hurt a lot.\n\tbool can_tally_using_mutruns = true;\n\t\n\tif (haplosomes_count <= 10)\n\t\tcan_tally_using_mutruns = false;\n\t\n\tif (can_tally_using_mutruns)\n\t{\n\t\t// FAST PATH: Tally mutation run usage first, and then leverage that to tally mutations\n\t\t// Note that this call sets up tallied_haplosome_count_ for all chromosomes\n\t\tTallyMutationRunReferencesForHaplosomes(haplosomes_ptr, haplosomes_count);\n\t\t\n\t\t// Give the core work to our fast worker method; this zeroes and then tallies\n\t\t_TallyMutationReferences_FAST_FromMutationRunUsage(/* p_clock_for_mutrun_experiments */ false);\n\t}\n\telse\n\t{\n\t\t// SLOW PATH: Increment the refcounts through all pointers to Mutation in all haplosomes\n\t\tSLiM_ZeroRefcountBlock(mutation_registry_, /* p_registry_only */ community_.AllSpecies().size() > 1);\n\t\t\n\t\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t\t\tchromosome->tallied_haplosome_count_ = 0;\n\t\t\n\t\tfor (slim_popsize_t i = 0; i < haplosomes_count; i++)\n\t\t{\n\t\t\tconst Haplosome *haplosome = haplosomes_ptr[i];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t{\n\t\t\t\tChromosome *chromosome = species_.Chromosomes()[haplosome->chromosome_index_];\n\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\tconst MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\n\t\t\t\t\tfor (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n\t\t\t\t\t\t++(*(refcount_block_ptr + *haplosome_iter));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tchromosome->tallied_haplosome_count_++;\t// count only non-null haplosomes to determine fixation\n\t\t\t}\n\t\t}\n\t}\n\t\n#if DEBUG\n\t_CheckMutationTallyAcrossHaplosomes(haplosomes_ptr, haplosomes_count, \"Population::TallyMutationReferencesAcrossHaplosomes()\");\n#endif\n\t\n\t// We have messed up any cached tallies, so mark the cache as invalid\n\tInvalidateMutationReferencesCache();\n}\n\n// This internal method tallies for all mutations across all mutation runs.  It does not do\n// the mutation run tallying itself, however; instead, the caller can tally mutation runs\n// across whatever set of subpops/haplosomes they wish, and then this method will provide\n// mutation tallies given that choice.\nvoid Population::_TallyMutationReferences_FAST_FromMutationRunUsage(bool p_clock_for_mutrun_experiments)\n{\n\t// first zero out the refcounts in all registered Mutation objects\n\tSLiM_ZeroRefcountBlock(mutation_registry_, /* p_registry_only */ community_.AllSpecies().size() > 1);\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tif (p_clock_for_mutrun_experiments)\n\t\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// each thread does its own tallying, for its own MutationRunContext\n#ifdef _OPENMP\n\t\tint mutrun_context_count = chromosome->ChromosomeMutationRunContextCount();\n#endif\n\t\t\n#pragma omp parallel default(none) shared(gSLiM_Mutation_Refcounts) num_threads(mutrun_context_count)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\n\t\t\tMutationRunPool &inuse_pool = mutrun_context.in_use_pool_;\n\t\t\tsize_t inuse_pool_count = inuse_pool.size();\n\t\t\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\t\t\t\n\t\t\tfor (size_t pool_index = 0; pool_index < inuse_pool_count; ++pool_index)\n\t\t\t{\n\t\t\t\tconst MutationRun *mutrun = inuse_pool[pool_index];\n\t\t\t\tconst slim_refcount_t use_count = (slim_refcount_t)mutrun->use_count();\n\t\t\t\t\n\t\t\t\t// Note that no locking or atomicity is needed here at all!  This is because\n\t\t\t\t// each thread is responsible for particular positions along the haplosome;\n\t\t\t\t// no other thread will be accessing this tally at the same time as us!\n\t\t\t\t// FIXME this is probably rife with false sharing, however; it would be useful\n\t\t\t\t// to put the refcounts for different mutations into different memory blocks\n\t\t\t\t// according to the thread that manages each mutation.\n\t\t\t\t\n\t\t\t\t// Try using __restrict__ pointers to help the compiler optimize here; unclear\n\t\t\t\t// whether this matters.  See https://github.com/MesserLab/SLiM/pull/596.\n\t\t\t\tconst MutationIndex * __restrict__ mutrun_iter = mutrun->begin_pointer_const();\n\t\t\t\tconst MutationIndex * const __restrict__ mutrun_end_iter = mutrun->end_pointer_const();\n\t\t\t\tslim_refcount_t * const __restrict__ refcounts = refcount_block_ptr;\n\t\t\t\t\n\t\t\t\t// I've gone back and forth on unrolling this loop.  This ought to be done\n\t\t\t\t// by the compiler, and the best unrolling strategy depends on the platform.\n\t\t\t\t// But the compiler doesn't seem to do it, for my macOS system at least, or\n\t\t\t\t// doesn't do it well; this increases speed by ~5% here.  I'm not sure if\n\t\t\t\t// clang is being dumb, or what, but it seems worthwhile.\n\t\t\t\t// BCH 12/23/2025: Andy Kern tried some changes to force the compiler to\n\t\t\t\t// unroll this loop for us; see https://github.com/MesserLab/SLiM/pull/596.\n\t\t\t\t// I backed out those changes in the end, because Clang was refusing to do it.\n\t\t\t\t// Until compilers get smarter, we apparently have to hand-unroll this.\n\t\t\t\twhile (mutrun_iter + 16 < mutrun_end_iter)\n\t\t\t\t{\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\twhile (mutrun_iter != mutrun_end_iter)\n\t\t\t\t\t*(refcounts + (*mutrun_iter++)) += use_count;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (p_clock_for_mutrun_experiments)\n\t\t\tchromosome->StopMutationRunExperimentClock(\"_TallyMutationReferences_FAST_FromMutationRunUsage()\");\n\t}\n}\n\n#if DEBUG\nvoid Population::_CheckMutationTallyAcrossHaplosomes(const Haplosome * const *haplosomes_ptr, slim_popsize_t haplosomes_count, std::string caller_name)\n{\n\t// This does a DEBUG check on the results of mutation reference tallying, done in several spots.\n\t// It should be called immediately after tallying, and passed a vector of the haplosomes tallied across.\n\tint registry_count;\n\tconst MutationIndex *registry_iter = MutationRegistry(&registry_count);\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\t// zero out all check refcounts\n\tfor (int registry_index = 0; registry_index < registry_count; ++registry_index)\n\t{\n\t\tconst Mutation *mut = mut_block_ptr + registry_iter[registry_index];\n\t\tmut->refcount_CHECK_ = 0;\n\t}\n\t\n\t// simply loop through all mutruns of all haplosomes given, and increment check refcounts\n\tfor (slim_popsize_t haplosome_index = 0; haplosome_index < haplosomes_count; ++haplosome_index)\n\t{\n\t\tconst Haplosome *haplosome = haplosomes_ptr[haplosome_index];\n\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\tconst MutationIndex *mutrun_iter = mutrun->begin_pointer_const();\n\t\t\tconst MutationIndex *mutrun_end_iter = mutrun->end_pointer_const();\n\t\t\t\n\t\t\tfor (; mutrun_iter != mutrun_end_iter; ++mutrun_iter)\n\t\t\t\t(mut_block_ptr + *mutrun_iter)->refcount_CHECK_++;\n\t\t}\n\t}\n\t\n\t// then loop through the registry and check that all check refcounts match tallied refcounts\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\t\n\tfor (int registry_index = 0; registry_index < registry_count; ++registry_index)\n\t{\n\t\tMutationIndex mut_blockindex = registry_iter[registry_index];\n\t\tconst Mutation *mut = mut_block_ptr + mut_blockindex;\n\t\t\n\t\tif (mut->state_ == MutationState::kInRegistry)\n\t\t{\n\t\t\tslim_refcount_t refcount_standard = *(refcount_block_ptr + mut_blockindex);\n\t\t\tslim_refcount_t refcount_checkback = mut->refcount_CHECK_;\n\t\t\t\n\t\t\tif (refcount_standard != refcount_checkback)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::_CheckMutationTallyAcrossHaplosomes): (internal error) mutation refcount \" << refcount_standard << \" != checkback \" << refcount_checkback << \" in \" << caller_name << \".\" << EidosTerminate();\n\t\t}\n\t}\n}\n#endif\n\nEidosValue_SP Population::Eidos_FrequenciesForTalliedMutations(EidosValue *mutations_value)\n{\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\tEidosValue_SP result_SP;\n\t\n\t// Fetch tallied haplosome counts for all chromosomes up front; these will be set up beforehand\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tstatic std::vector<double> tallied_haplosome_counts;\t\t// static to avoid alloc/dealloc\n\t\n\ttallied_haplosome_counts.resize(0);\n\ttallied_haplosome_counts.reserve(chromosomes.size());\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t\ttallied_haplosome_counts.push_back(chromosome->tallied_haplosome_count_);\n\t\n\t// BCH 10/3/2020: Note that we now have to worry about being asked for the frequency of mutations that are\n\t// not in the registry, and might be fixed or lost.  We handle this in the first major case below, where\n\t// a vector of mutations was given.  It could be a marginal issue in the second major case, where NULL was\n\t// passed for the mutation vector, because the registry can temporarily contain mutations in the state\n\t// MutationState::kRemovedWithSubstitution, immediately after removeMutations(substitute=T); if that is\n\t// a potential issue, registry_needs_consistency_check_ will be true, and we treat it specially.\n\t\n\tif (mutations_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\t// a vector of mutations was given, so loop through them and take their tallies\n\t\tint mutations_count = mutations_value->Count();\n\t\tEidosObject * const *mutations_data = mutations_value->ObjectData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(mutations_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t{\n\t\t\tMutation *mut = (Mutation *)mutations_data[value_index];\n\t\t\tint8_t mut_state = mut->state_;\n\t\t\tdouble freq;\n\t\t\t\n\t\t\tif (mut_state == MutationState::kInRegistry)\t\t\tfreq = *(refcount_block_ptr + mut->BlockIndex()) / tallied_haplosome_counts[mut->chromosome_index_];\n\t\t\telse if (mut_state == MutationState::kLostAndRemoved)\tfreq = 0.0;\n\t\t\telse\t\t\t\t\t\t\t\t\t\t\t\t\tfreq = 1.0;\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(freq, value_index);\n\t\t}\n\t}\n\telse if (MutationRegistryNeedsCheck())\n\t{\n\t\t// no mutation vector was given, so return all frequencies from the registry\n\t\t// this is the same as the case below, except MutationState::kRemovedWithSubstitution is possible\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\tMutation *mutation_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(registry_size);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; registry_index++)\n\t\t{\n\t\t\tMutationIndex mut_index = registry[registry_index];\n\t\t\tconst Mutation *mut = mutation_block_ptr + mut_index;\n\t\t\tdouble freq;\n\t\t\t\n\t\t\tif (mut->state_ == MutationState::kInRegistry)\t\t\tfreq = *(refcount_block_ptr + mut_index) / tallied_haplosome_counts[mut->chromosome_index_];\n\t\t\telse /* MutationState::kRemovedWithSubstitution */\t\tfreq = 1.0;\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(freq, registry_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no mutation vector was given, so return all frequencies from the registry\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\tMutation *mutation_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(registry_size);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; registry_index++)\n\t\t{\n\t\t\tMutationIndex mut_index = registry[registry_index];\n\t\t\tconst Mutation *mut = mutation_block_ptr + mut_index;\n\t\t\tfloat_result->set_float_no_check(*(refcount_block_ptr + registry[registry_index]) / tallied_haplosome_counts[mut->chromosome_index_], registry_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\nEidosValue_SP Population::Eidos_CountsForTalliedMutations(EidosValue *mutations_value)\n{\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\tEidosValue_SP result_SP;\n\t\n\t// Fetch total haplosome counts for all chromosomes up front; these will be set up beforehand\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tstatic std::vector<slim_refcount_t> tallied_haplosome_counts;\t\t// static to avoid alloc/dealloc\n\t\n\ttallied_haplosome_counts.resize(0);\n\ttallied_haplosome_counts.reserve(chromosomes.size());\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t\ttallied_haplosome_counts.push_back(chromosome->tallied_haplosome_count_);\n\t\n\t// BCH 10/3/2020: Note that we now have to worry about being asked for the frequency of mutations that are\n\t// not in the registry, and might be fixed or lost.  We handle this in the first major case below, where\n\t// a vector of mutations was given.  It could be a marginal issue in the second major case, where NULL was\n\t// passed for the mutation vector, because the registry can temporarily contain mutations in the state\n\t// MutationState::kRemovedWithSubstitution, immediately after removeMutations(substitute=T); if that is\n\t// a potential issue, registry_needs_consistency_check_ will be true, and we treat it specially.\n\t\n\tif (mutations_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\t// a vector of mutations was given, so loop through them and take their tallies\n\t\tint mutations_count = mutations_value->Count();\n\t\tEidosObject * const *mutations_data = mutations_value->ObjectData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(mutations_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < mutations_count; ++value_index)\n\t\t{\n\t\t\tMutation *mut = (Mutation *)mutations_data[value_index];\n\t\t\tint8_t mut_state = mut->state_;\n\t\t\tslim_refcount_t count;\n\t\t\t\n\t\t\tif (mut_state == MutationState::kInRegistry)\t\t\tcount = *(refcount_block_ptr + mut->BlockIndex());\n\t\t\telse if (mut_state == MutationState::kLostAndRemoved)\tcount = 0;\n\t\t\telse\t\t\t\t\t\t\t\t\t\t\t\t\tcount = tallied_haplosome_counts[mut->chromosome_index_];\n\t\t\t\n\t\t\tint_result->set_int_no_check(count, value_index);\n\t\t}\n\t}\n\telse if (MutationRegistryNeedsCheck())\n\t{\n\t\t// no mutation vector was given, so return all frequencies from the registry\n\t\t// this is the same as the case below, except MutationState::kRemovedWithSubstitution is possible\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\tMutation *mutation_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(registry_size);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; registry_index++)\n\t\t{\n\t\t\tMutationIndex mut_index = registry[registry_index];\n\t\t\tconst Mutation *mut = mutation_block_ptr + mut_index;\n\t\t\tslim_refcount_t count;\n\t\t\t\n\t\t\tif (mut->state_ == MutationState::kInRegistry)\t\tcount = *(refcount_block_ptr + mut_index);\n\t\t\telse /* MutationState::kRemovedWithSubstitution */\tcount = tallied_haplosome_counts[mut->chromosome_index_];\n\t\t\t\n\t\t\tint_result->set_int_no_check(count, registry_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no mutation vector was given, so return all frequencies from the registry\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(registry_size);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; registry_index++)\n\t\t\tint_result->set_int_no_check(*(refcount_block_ptr + registry[registry_index]), registry_index);\n\t}\n\t\n\treturn result_SP;\n}\n\n// handle negative fixation (remove from the registry) and positive fixation (convert to Substitution), using existing mutation reference counts\n// TallyMutationReferencesAcrossPopulation() must have cached tallies across the whole population before this is called, or it will malfunction!\nvoid Population::RemoveAllFixedMutations(void)\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::RemoveAllFixedMutations): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\t// We use a stack-local MutationRun object so it gets disposed of properly via RAII; non-optimal\n\t// from a performance perspective, since it will do reallocs to reach its needed size, but\n\t// since this method is only called once per cycle it shouldn't matter.\n\tMutationRun removed_mutation_accumulator;\n\t\n#ifdef SLIMGUI\n\tint mutation_type_count = static_cast<int>(species_.mutation_types_.size());\n#endif\n\t\n\t// Fetch total haplosome counts for all chromosomes up front; these will be set up beforehand\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tstatic std::vector<slim_refcount_t> total_haplosome_counts;\t\t// static to avoid alloc/dealloc\n\t\n\ttotal_haplosome_counts.resize(0);\n\ttotal_haplosome_counts.reserve(chromosomes.size());\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t\ttotal_haplosome_counts.push_back(chromosome->total_haplosome_count_);\n\t\n\t// remove Mutation objects that are no longer referenced, freeing them; avoid using an iterator since it would be invalidated\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\t{\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = MutationRegistry(&registry_size);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutationIndex mutation_index = registry[registry_index];\n\t\t\tslim_refcount_t reference_count = *(refcount_block_ptr + mutation_index);\n\t\t\tMutation *mutation = mut_block_ptr + mutation_index;\n\t\t\tbool remove_mutation = false;\n\t\t\t\n\t\t\tif (reference_count == 0)\n\t\t\t{\n\t\t\t\tif (mutation->state_ == MutationState::kRemovedWithSubstitution)\n\t\t\t\t{\n\t\t\t\t\t// a substitution object was already created by removeMutations() at the user's request;\n\t\t\t\t\t// the refcount is zero because the mutation was removed in script, but it was fixed/substituted\n\t\t\t\t\t// this code path is similar to the fixation code path below, but does not create a Substitution\n#if DEBUG_MUTATIONS\n\t\t\t\t\tstd::cout << \"Mutation fixed by script, already substituted: \" << mutation << std::endl;\n#endif\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t// If we're running under SLiMgui, make a note of the fixation time of the mutation\n\t\t\t\t\tslim_tick_t fixation_time = community_.Tick() - mutation->origin_tick_;\n\t\t\t\t\tint mutation_type_index = mutation->mutation_type_ptr_->mutation_type_index_;\n\t\t\t\t\t\n\t\t\t\t\tAddTallyForMutationTypeAndBinNumber(mutation_type_index, mutation_type_count, fixation_time / 10, &mutation_fixation_times_, &mutation_fixation_tick_slots_);\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// fix the refcount of record; we want user-substituted mutations to have a full refcount, not 0\n\t\t\t\t\t// actually, this doesn't work, because the denominator – what total_haplosome_count_ is – depends\n\t\t\t\t\t// on what the user asks; so now Species::ExecuteMethod_mutationFreqsCounts() handles this\n\t\t\t\t\t// the same issue would have bitten SLiM-substituted mutations if the population size changed\n\t\t\t\t\t//*(refcount_block_ptr + mutation_index) = total_haplosome_count_;\n\t\t\t\t\t\n\t\t\t\t\tmutation->state_ = MutationState::kFixedAndSubstituted;\t\t\t// marked in anticipation of removal below\n\t\t\t\t\tremove_mutation = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if DEBUG_MUTATIONS\n\t\t\t\t\tstd::cout << \"Mutation unreferenced, will remove: \" << mutation << std::endl;\n#endif\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t// If we're running under SLiMgui, make a note of the lifetime of the mutation\n\t\t\t\t\tslim_tick_t loss_time = community_.Tick() - mutation->origin_tick_;\n\t\t\t\t\tint mutation_type_index = mutation->mutation_type_ptr_->mutation_type_index_;\n\t\t\t\t\t\n\t\t\t\t\tAddTallyForMutationTypeAndBinNumber(mutation_type_index, mutation_type_count, loss_time / 10, &mutation_loss_times_, &mutation_loss_tick_slots_);\n#endif\n\t\t\t\t\t\n\t\t\t\t\tmutation->state_ = MutationState::kLostAndRemoved;\t\t\t// marked in anticipation of removal below\n\t\t\t\t\tremove_mutation = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (reference_count == total_haplosome_counts[mutation->chromosome_index_])\n\t\t\t{\n\t\t\t\tif (mutation->mutation_type_ptr_->convert_to_substitution_)\n\t\t\t\t{\n#if DEBUG_MUTATIONS\n\t\t\t\t\tstd::cout << \"Mutation fixed, will substitute: \" << mutation << std::endl;\n#endif\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t// If we're running under SLiMgui, make a note of the fixation time of the mutation\n\t\t\t\t\tslim_tick_t fixation_time = community_.Tick() - mutation->origin_tick_;\n\t\t\t\t\tint mutation_type_index = mutation->mutation_type_ptr_->mutation_type_index_;\n\t\t\t\t\t\n\t\t\t\t\tAddTallyForMutationTypeAndBinNumber(mutation_type_index, mutation_type_count, fixation_time / 10, &mutation_fixation_times_, &mutation_fixation_tick_slots_);\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// add the fixed mutation to a per-chromosome vector, to be converted to a Substitution object below\n\t\t\t\t\tchromosomes[mutation->chromosome_index_]->fixed_mutation_accumulator_.push_back(mutation_index);\n\t\t\t\t\t\n\t\t\t\t\tmutation->state_ = MutationState::kFixedAndSubstituted;\t\t\t// marked in anticipation of removal below\n\t\t\t\t\tremove_mutation = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (remove_mutation)\n\t\t\t{\n\t\t\t\t// We have an unreferenced mutation object, so we want to remove it quickly\n\t\t\t\tif (registry_index == registry_size - 1)\n\t\t\t\t{\n\t\t\t\t\tmutation_registry_.pop_back();\n\t\t\t\t\t\n\t\t\t\t\t--registry_size;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tMutationIndex last_mutation = mutation_registry_[registry_size - 1];\n\t\t\t\t\tmutation_registry_[registry_index] = last_mutation;\n\t\t\t\t\tmutation_registry_.pop_back();\n\t\t\t\t\t\n\t\t\t\t\t--registry_size;\n\t\t\t\t\t--registry_index;\t// revisit this index\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We can't delete the mutation yet, because we might need to make a Substitution object from it, so add it to a vector for deletion below\n\t\t\t\tremoved_mutation_accumulator.emplace_back(mutation_index);\n\t\t\t}\n\t\t}\n\t}\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t// remove fixed mutations from MutationType registries as well, if we've got any; this is simpler since\n\t// the main registry is in charge of all bookkeeping, substitution, removal, etc.\n\tif (keeping_muttype_registries_ && removed_mutation_accumulator.size())\n\t{\n\t\tfor (auto muttype_iter : species_.MutationTypes())\n\t\t{\n\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\t\n\t\t\tif (muttype->keeping_muttype_registry_)\n\t\t\t{\n\t\t\t\tMutationRun &registry = muttype->muttype_registry_;\n\t\t\t\tint registry_length = registry.size();\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < registry_length; ++i)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex mutation_index = registry[i];\n\t\t\t\t\tMutation *mutation = mut_block_ptr + mutation_index;\n\t\t\t\t\t\n\t\t\t\t\tif ((mutation->state_ == MutationState::kFixedAndSubstituted) || (mutation->state_ == MutationState::kLostAndRemoved))\n\t\t\t\t\t{\n\t\t\t\t\t\t// We have an unreferenced mutation object, so we want to remove it quickly\n\t\t\t\t\t\tif (i == registry_length - 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tregistry.pop_back();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t--registry_length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex last_mutation = registry[registry_length - 1];\n\t\t\t\t\t\t\tregistry[i] = last_mutation;\n\t\t\t\t\t\t\tregistry.pop_back();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t--registry_length;\n\t\t\t\t\t\t\t--i;\t// revisit this index\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n\t\n\t// replace fixed mutations with Substitution objects, one chromosome at a time\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tstd::vector<MutationIndex> &fixed_mutation_accumulator = chromosome->fixed_mutation_accumulator_;\n\t\tint fixed_mutation_accumulator_size = (int)fixed_mutation_accumulator.size();\n\t\t\n\t\tif (fixed_mutation_accumulator_size == 0)\n\t\t\tcontinue;\n\t\t\n\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\n\t\t//std::cout << \"Chromosome \" << chromosome_index << \": removing \" << fixed_mutation_accumulator.size() << \" fixed mutations...\" << std::endl;\n\t\t\n\t\t// We remove fixed mutations from each MutationRun just once; this is the operation ID we use for that\n\t\tint first_haplosome_index = species_.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species_.LastHaplosomeIndices()[chromosome_index];\n\t\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\t\t// subpopulations\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\t// Loop over the mutations to remove, and take advantage of our mutation runs by scanning\n\t\t\t\t\t\t// for removal only within the runs that contain a mutation to be removed.  If there is\n\t\t\t\t\t\t// more than one mutation to be removed within the same run, the second time around the\n\t\t\t\t\t\t// runs will no-op the scan using operation_id.  The whole rest of the haplosomes can be skipped.\n\t\t\t\t\t\tslim_position_t mutrun_length = haplosome->mutrun_length_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = 0; mut_index < fixed_mutation_accumulator_size; mut_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex mut_to_remove = fixed_mutation_accumulator[mut_index];\n\t\t\t\t\t\t\tMutation *mutation = (mut_block_ptr + mut_to_remove);\n\t\t\t\t\t\t\tslim_position_t mut_position = mutation->position_;\n\t\t\t\t\t\t\tslim_mutrun_index_t mutrun_index = (slim_mutrun_index_t)(mut_position / mutrun_length);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\thaplosome->RemoveFixedMutations(operation_id, mutrun_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tslim_tick_t tick = community_.Tick();\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (species_.RecordingTreeSequence())\n\t\t{\n\t\t\t// When doing tree recording, we additionally keep all fixed mutations (their ids) in a multimap indexed by their position\n\t\t\t// This allows us to find all the fixed mutations at a given position quickly and easily, for calculating derived states\n\t\t\tfor (int i = 0; i < fixed_mutation_accumulator_size; i++)\n\t\t\t{\n\t\t\t\tMutation *mut_to_remove = mut_block_ptr + fixed_mutation_accumulator[i];\n\t\t\t\tSubstitution *sub = new Substitution(*mut_to_remove, tick);\n\t\t\t\t\n\t\t\t\ttreeseq_substitutions_map_.emplace(mut_to_remove->position_, sub);\n\t\t\t\tsubstitutions_.emplace_back(sub);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// When not doing tree recording, we just create substitutions and keep them in a vector\n\t\t\tfor (int i = 0; i < fixed_mutation_accumulator_size; i++)\n\t\t\t{\n\t\t\t\tMutation *mut_to_remove = mut_block_ptr + fixed_mutation_accumulator[i];\n\t\t\t\tSubstitution *sub = new Substitution(*mut_to_remove, tick);\n\t\t\t\t\n\t\t\t\tsubstitutions_.emplace_back(sub);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Nucleotide-based models also need to modify the ancestral sequence when a mutation fixes\n\t\tif (species_.IsNucleotideBased())\n\t\t{\n\t\t\tNucleotideArray *ancestral_seq = chromosome->ancestral_seq_buffer_;\n\t\t\t\n\t\t\tfor (int i = 0; i < fixed_mutation_accumulator_size; i++)\n\t\t\t{\n\t\t\t\tMutation *mut_to_remove = mut_block_ptr + fixed_mutation_accumulator[i];\n\t\t\t\t\n\t\t\t\tif (mut_to_remove->mutation_type_ptr_->nucleotide_based_)\n\t\t\t\t\tancestral_seq->SetNucleotideAtIndex(mut_to_remove->position_, mut_to_remove->nucleotide_);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Clear the accumulator for reuse next tick\n\t\tfixed_mutation_accumulator.resize(0);\n\t}\n\t\n\t// now we can delete (or zombify) removed mutation objects\n\tif (removed_mutation_accumulator.size() > 0)\n\t{\n\t\tfor (int i = 0; i < removed_mutation_accumulator.size(); i++)\n\t\t{\n\t\t\tMutationIndex mutation = removed_mutation_accumulator[i];\n\t\t\t\n#if DEBUG_MUTATION_ZOMBIES\n\t\t\t// Note that this violates SLiM guarantees, as of SLiM 3.5, because mutations are allowed to be retained\n\t\t\t// long-term, so they are not necessarily invalid objects just because they're removed from the registry.\n\t\t\t// But this might be useful for catching tricky bugs, so I'm leaving it in.  BCH 10/2/2020\n\t\t\t(mut_block_ptr + mutation)->mutation_type_ptr_ = nullptr;\t// render lethal\n\t\t\t(mut_block_ptr + mutation)->reference_count_ = -1;\t\t\t// zombie\n#else\n\t\t\t// We no longer delete mutation objects; instead, we release them\n\t\t\t(mut_block_ptr + mutation)->Release();\n#endif\n\t\t}\n\t}\n}\n\nvoid Population::CheckMutationRegistry(bool p_check_haplosomes)\n{\n\tif ((model_type_ == SLiMModelType::kModelTypeWF) && child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::CheckMutationRegistry): (internal error) CheckMutationRegistry() may only be called from the parent generation in WF models.\" << EidosTerminate();\n\t\n\tMutation *mutation_block_ptr = gSLiM_Mutation_Block;\n#if DEBUG_MUTATION_ZOMBIES\n\tslim_refcount_t *refcount_block_ptr = gSLiM_Mutation_Refcounts;\n#endif\n\tint registry_size;\n\tconst MutationIndex *registry_iter = MutationRegistry(&registry_size);\n\tconst MutationIndex *registry_iter_end = registry_iter + registry_size;\n\t\n\t// First check that we don't have any zombies in our registry.  BCH 10/2/2020 as of SLiM 3.5 we now also check\n\t// for registered/segregating mutations that do not have state_ == MutationState::kInRegistry, and we now get\n\t// called in DEBUG mode all the time, and in non-DEBUG mode when removeMutations(substitute=T) has been used.\n\tfor (; registry_iter != registry_iter_end; ++registry_iter)\n\t{\n\t\tMutationIndex mut_index = *registry_iter;\n\t\t\n#if DEBUG_MUTATION_ZOMBIES\n\t\tif (*(refcount_block_ptr + mut_index) == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::CheckMutationRegistry): (internal error) zombie mutation found in registry with address \" << (*registry_iter) << EidosTerminate();\n#endif\n\t\t\n\t\tint8_t mut_state = (mutation_block_ptr + mut_index)->state_;\n\t\t\n\t\tif (mut_state != MutationState::kInRegistry)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::CheckMutationRegistry): A mutation was found in the mutation registry with a state other than MutationState::kInRegistry (\" << (int)mut_state << \").  This may be the result of calling removeMutations(substitute=T) without actually removing the mutation from all haplosomes.\" << EidosTerminate();\n\t}\n\t\n#if DEBUG_LESS_INTENSIVE\n\t// These tests are extremely intensive, so sometimes it's useful to dial them down...\n\tif ((community_.Tick() % 10) != 5)\n\t\treturn;\n#endif\n\t\n\tif (p_check_haplosomes)\n\t{\n\t\t// then check that we don't have any zombies in any haplosomes\n\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\t\t// subpopulations\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *haplosome_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (; haplosome_iter != haplosome_end_iter; ++haplosome_iter)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex mut_index = *haplosome_iter;\n\t\t\t\t\t\t\t\n#if DEBUG_MUTATION_ZOMBIES\n\t\t\t\t\t\t\tif (*(refcount_block_ptr + mut_index) == -1)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::CheckMutationRegistry): (internal error) zombie mutation found in haplosome with address \" << (*haplosome_iter) << EidosTerminate();\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tint8_t mut_state = (mutation_block_ptr + mut_index)->state_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mut_state != MutationState::kInRegistry)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::CheckMutationRegistry): A mutation was found in a haplosome with a state other than MutationState::kInRegistry (\" << (int)mut_state << \").  This may be the result of calling removeMutations(substitute=T) without actually removing the mutation from all haplosomes.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// print all mutations and all haplosomes to a stream in binary, for maximum reading speed\n// this is a binary version of Individual::PrintIndividuals_SLiM(), which is quite parallel\nvoid Population::PrintAllBinary(std::ostream &p_out, bool p_output_spatial_positions, bool p_output_ages, bool p_output_ancestral_nucs, bool p_output_pedigree_ids, bool p_output_object_tags, bool p_output_substitutions) const\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintAllBinary): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n\t// Figure out spatial position output.  If it was not requested, then we don't do it, and that's fine.  If it\n\t// was requested, then we output the number of spatial dimensions we're configured for (which might be zero).\n\tint32_t spatial_output_count = (int32_t)(p_output_spatial_positions ? species_.SpatialDimensionality() : 0);\n\t\n\t// Figure out age output.  If it was not requested, don't do it; if it was requested, do it if we use a nonWF model.\n\tint age_output_count = (p_output_ages && (model_type_ == SLiMModelType::kModelTypeNonWF)) ? 1 : 0;\n\t\n\t// Figure out pedigree ID output\n\tint pedigree_output_count = (p_output_pedigree_ids ? 1 : 0);\n\t\n\t// We will output nucleotides for all mutations, and an ancestral sequence at the end, if we are nucleotide-based.\n\tbool has_nucleotides = species_.IsNucleotideBased();\n\tbool output_ancestral_nucs = has_nucleotides && p_output_ancestral_nucs;\n\t\n\tint32_t section_end_tag = 0xFFFF0000;\n\t\n\t// Header section\n\t{\n\t\t// Write a 32-bit endianness tag\n\t\tint32_t endianness_tag = 0x12345678;\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&endianness_tag), sizeof endianness_tag);\n\t\t\n\t\t// Write a format version tag\n\t\tint32_t version_tag = 8;\t\t// version 2 started with SLiM 2.1\n\t\t\t\t\t\t\t\t\t\t// version 3 started with SLiM 2.3\n\t\t\t\t\t\t\t\t\t\t// version 4 started with SLiM 3.0, only when individual age is output\n\t\t\t\t\t\t\t\t\t\t// version 5 started with SLiM 3.3, adding a \"flags\" field and nucleotide support\n\t\t\t\t\t\t\t\t\t\t// version 6 started with SLiM 3.5, adding optional pedigree ID output with a new flag\n\t\t\t\t\t\t\t\t\t\t// version 7 started with SLiM 4.0, changing generation to ticks and adding cycle\n\t\t\t\t\t\t\t\t\t\t// version 8 started with SLiM 5.0, adding multiple chromosomes\n\t\tp_out.write(reinterpret_cast<char *>(&version_tag), sizeof version_tag);\n\t\t\n\t\t// Write the size of a double\n\t\tint32_t double_size = sizeof(double);\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&double_size), sizeof double_size);\n\t\t\n\t\t// Write a test double, to ensure the same format is used on the reading machine\n\t\tdouble double_test = 1234567890.0987654321;\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&double_test), sizeof double_test);\n\t\t\n\t\t// Write a \"flags\" field, new in SLiM 3.3; the bit values here are all changed/new in version 8\n\t\t{\n\t\t\tint64_t flags = 0;\n\t\t\t\n\t\t\tif (spatial_output_count)\t\tflags |= spatial_output_count;\t// takes 0x0001 and 0x0002\n\t\t\tif (age_output_count)\t\t\tflags |= 0x0004;\n\t\t\tif (pedigree_output_count)\t\tflags |= 0x0008;\n\t\t\tif (has_nucleotides)\t\t\tflags |= 0x0010;\n\t\t\tif (output_ancestral_nucs)\t\tflags |= 0x0020;\n\t\t\tif (p_output_object_tags)\t\tflags |= 0x0040;\n\t\t\tif (p_output_substitutions)\t\tflags |= 0x0080;\n\t\t\t\n\t\t\tp_out.write(reinterpret_cast<char *>(&flags), sizeof flags);\n\t\t}\n\t\t\n\t\t// Write the sizes of the various SLiM types\n\t\tint32_t slim_tick_t_size = sizeof(slim_tick_t);\n\t\tint32_t slim_position_t_size = sizeof(slim_position_t);\n\t\tint32_t slim_objectid_t_size = sizeof(slim_objectid_t);\n\t\tint32_t slim_popsize_t_size = sizeof(slim_popsize_t);\n\t\tint32_t slim_refcount_t_size = sizeof(slim_refcount_t);\n\t\tint32_t slim_selcoeff_t_size = sizeof(slim_selcoeff_t);\n\t\tint32_t slim_mutationid_t_size = sizeof(slim_mutationid_t);\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 2\n\t\tint32_t slim_polymorphismid_t_size = sizeof(slim_polymorphismid_t);\t\t\t\t\t\t\t\t\t\t\t// Added in version 2\n\t\tint32_t slim_age_t_size = sizeof(slim_age_t);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 6\n\t\tint32_t slim_pedigreeid_t_size = sizeof(slim_pedigreeid_t);\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 6\n\t\tint32_t slim_haplosomeid_t_size = sizeof(slim_haplosomeid_t);\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 6\n\t\tint32_t slim_usertag_t_size = sizeof(slim_usertag_t);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 8\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&slim_tick_t_size), sizeof slim_tick_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_position_t_size), sizeof slim_position_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_objectid_t_size), sizeof slim_objectid_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_popsize_t_size), sizeof slim_popsize_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_refcount_t_size), sizeof slim_refcount_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_selcoeff_t_size), sizeof slim_selcoeff_t_size);\n\t\tp_out.write(reinterpret_cast<char *>(&slim_mutationid_t_size), sizeof slim_mutationid_t_size);\t\t\t\t// Added in version 2\n\t\tp_out.write(reinterpret_cast<char *>(&slim_polymorphismid_t_size), sizeof slim_polymorphismid_t_size);\t\t// Added in version 2\n\t\tp_out.write(reinterpret_cast<char *>(&slim_age_t_size), sizeof slim_age_t_size);\t\t\t\t\t\t\t// Added in version 6\n\t\tp_out.write(reinterpret_cast<char *>(&slim_pedigreeid_t_size), sizeof slim_pedigreeid_t_size);\t\t\t\t// Added in version 6\n\t\tp_out.write(reinterpret_cast<char *>(&slim_haplosomeid_t_size), sizeof slim_haplosomeid_t_size);\t\t\t// Added in version 6\n\t\tp_out.write(reinterpret_cast<char *>(&slim_usertag_t_size), sizeof slim_usertag_t_size);\t\t\t\t\t// Added in version 8\n\t\t\n\t\t// Write the tick and cycle\n\t\tslim_tick_t tick = community_.Tick();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Changed from generation to tick in version 7\n\t\tslim_tick_t cycle = species_.Cycle();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 7\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&tick), sizeof tick);\n\t\tp_out.write(reinterpret_cast<char *>(&cycle), sizeof cycle);\n\t}\n\t\n\t// Write a tag indicating the section has ended\n\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\n\t// Populations section\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\n\t{\n\t\tconst Subpopulation *subpop = subpop_pair.second;\n\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\tdouble subpop_sex_ratio;\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tsubpop_sex_ratio = subpop->parent_sex_ratio_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (subpop->parent_subpop_size_ == 0)\n\t\t\t\tsubpop_sex_ratio = 0.0;\n\t\t\telse\n\t\t\t\tsubpop_sex_ratio = 1.0 - (subpop->parent_first_male_index_ / (double)subpop->parent_subpop_size_);\n\t\t}\n\t\t\n\t\t// Write a tag indicating we are starting a new subpopulation\n\t\tint32_t subpop_start_tag = 0xFFFF0001;\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&subpop_start_tag), sizeof subpop_start_tag);\n\t\t\n\t\t// Write the subpop identifier\n\t\tp_out.write(reinterpret_cast<char *>(&subpop_id), sizeof subpop_id);\n\t\t\n\t\t// Write the subpop size\n\t\tp_out.write(reinterpret_cast<char *>(&subpop_size), sizeof subpop_size);\n\t\t\n\t\t// Write a flag indicating whether this population has sexual or hermaphroditic\n\t\tint32_t sex_flag = (subpop->sex_enabled_ ? 1 : 0);\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&sex_flag), sizeof sex_flag);\n\t\t\n\t\t// Write the sex ratio; if we are not sexual, this will be garbage, but that is fine, we want a constant-length record\n\t\tp_out.write(reinterpret_cast<char *>(&subpop_sex_ratio), sizeof subpop_sex_ratio);\n\t\t\n\t\t// Write the tag if requested\n\t\tif (p_output_object_tags)\n\t\t\tp_out.write(reinterpret_cast<const char *>(&subpop->tag_value_), sizeof subpop->tag_value_);\n\t\t\n\t\t// now will come either a subpopulation start tag, or a section end tag\n\t}\n\t\n\t// Write a tag indicating the section has ended\n\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\n\t// Individuals section; this contains optional metadata about the individuals\n\t// This section is new with version 8; its information used to be embedded in the Haplosomes section, in binary\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\t\t\t// go through all subpopulations\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\n\t\tfor (slim_popsize_t individual_index = 0; individual_index < subpop_size; individual_index++)\t// go through all children\n\t\t{\n\t\t\tIndividual &individual = *(subpop->parent_individuals_[individual_index]);\n\t\t\t\n\t\t\t// Output individual sex\n\t\t\tp_out.write(reinterpret_cast<char *>(&individual.sex_), sizeof individual.sex_);\n\t\t\t\n\t\t\t// Output individual pedigree ID information.  Added in version 5.\n\t\t\tif (pedigree_output_count)\n\t\t\t{\n\t\t\t\tslim_pedigreeid_t pedigree_id = individual.PedigreeID();\n\t\t\t\t\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&pedigree_id), sizeof pedigree_id);\n\t\t\t}\n\t\t\t\n\t\t\t// Output individual spatial position information.  Added in version 3.\n\t\t\tif (spatial_output_count)\n\t\t\t{\n\t\t\t\tif (spatial_output_count >= 1)\n\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.spatial_x_), sizeof individual.spatial_x_);\n\t\t\t\tif (spatial_output_count >= 2)\n\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.spatial_y_), sizeof individual.spatial_y_);\n\t\t\t\tif (spatial_output_count >= 3)\n\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.spatial_z_), sizeof individual.spatial_z_);\n\t\t\t}\n\t\t\t\n\t\t\t// Output individual age information before the mutation list.  Added in version 4.\n\t\t\tif (age_output_count)\n\t\t\t{\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.age_), sizeof individual.age_);\n\t\t\t}\n\t\t\t\n\t\t\t// output object tags if requested\n\t\t\tif (p_output_object_tags)\n\t\t\t{\n\t\t\t\tchar T_value = 1, F_value = 0, UNDEF_value = 2;\n\t\t\t\t\n\t\t\t\t// for these two, we just write out undefined-tag values directly; they will read back in\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.tag_value_), sizeof individual.tag_value_);\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&individual.tagF_value_), sizeof individual.tagF_value_);\n\t\t\t\t\n\t\t\t\t// for the logical tags, we write out an undefined-tag value of 2\n\t\t\t\tif (individual.tagL0_set_)\n\t\t\t\t\tp_out.write(individual.tagL0_value_ ? &T_value : &F_value, sizeof T_value);\n\t\t\t\telse\n\t\t\t\t\tp_out.write(&UNDEF_value, sizeof UNDEF_value);\n\t\t\t\t\n\t\t\t\tif (individual.tagL1_set_)\n\t\t\t\t\tp_out.write(individual.tagL1_value_ ? &T_value : &F_value, sizeof T_value);\n\t\t\t\telse\n\t\t\t\t\tp_out.write(&UNDEF_value, sizeof UNDEF_value);\n\t\t\t\t\n\t\t\t\tif (individual.tagL2_set_)\n\t\t\t\t\tp_out.write(individual.tagL2_value_ ? &T_value : &F_value, sizeof T_value);\n\t\t\t\telse\n\t\t\t\t\tp_out.write(&UNDEF_value, sizeof UNDEF_value);\n\t\t\t\t\n\t\t\t\tif (individual.tagL3_set_)\n\t\t\t\t\tp_out.write(individual.tagL3_value_ ? &T_value : &F_value, sizeof T_value);\n\t\t\t\telse\n\t\t\t\t\tp_out.write(&UNDEF_value, sizeof UNDEF_value);\n\t\t\t\t\n\t\t\t\tif (individual.tagL4_set_)\n\t\t\t\t\tp_out.write(individual.tagL4_value_ ? &T_value : &F_value, sizeof T_value);\n\t\t\t\telse\n\t\t\t\t\tp_out.write(&UNDEF_value, sizeof UNDEF_value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Write a tag indicating the section has ended\n\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\n\t// BCH 2/5/2025: Now we write genetic data for each chromosome.  Each chromosome will get a section end tag.\n\t// Here we write out the chromosome count, so the reading code knows how many chromosome sections to expect.\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tint32_t chromosome_count = (int)chromosomes.size();\n\t\n\tp_out.write(reinterpret_cast<char *>(&chromosome_count), sizeof chromosome_count);\n\t\n\tfor (const Chromosome *chromosome : chromosomes)\n\t{\n\t\t// write information about the chromosome; we don't write the symbol, since strings are annoying,\n\t\t// so the chromosome symbol will not be validated on read, but I think that's fine\n\t\tint32_t chromosome_index = chromosome->Index();\n\t\tint32_t chromosome_type = (int32_t)chromosome->Type();\n\t\tint64_t chromosome_id = chromosome->ID();\n\t\tslim_position_t chromosome_lastpos = chromosome->last_position_;\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&chromosome_index), sizeof chromosome_index);\n\t\tp_out.write(reinterpret_cast<char *>(&chromosome_type), sizeof chromosome_type);\n\t\tp_out.write(reinterpret_cast<char *>(&chromosome_id), sizeof chromosome_id);\n\t\tp_out.write(reinterpret_cast<char *>(&chromosome_lastpos), sizeof chromosome_lastpos);\n\t\t\n\t\tif (p_output_object_tags)\n\t\t\tp_out.write(reinterpret_cast<const char *>(&chromosome->tag_value_), sizeof chromosome->tag_value_);\n\t\t\n\t\t// Find all polymorphisms\n\t\tint first_haplosome_index = species_.FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = species_.LastHaplosomeIndices()[chromosome_index];\n\t\tPolymorphismMap polymorphisms;\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\t\t\t// go through all subpopulations\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Write out the size of the mutation map, so we can allocate a vector rather than utilizing std::map when reading\n\t\tint32_t mutation_map_size = (int32_t)polymorphisms.size();\n\t\t\n\t\tp_out.write(reinterpret_cast<char *>(&mutation_map_size), sizeof mutation_map_size);\n\t\t\n\t\t// Mutations section\n\t\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms)\n\t\t{\n\t\t\tconst Polymorphism &polymorphism = polymorphism_pair.second;\n\t\t\tconst Mutation *mutation_ptr = polymorphism.mutation_ptr_;\n\t\t\tconst MutationType *mutation_type_ptr = mutation_ptr->mutation_type_ptr_;\n\t\t\t\n\t\t\tslim_polymorphismid_t polymorphism_id = polymorphism.polymorphism_id_;\n\t\t\tint64_t mutation_id = mutation_ptr->mutation_id_;\t\t\t\t\t\t\t\t\t\t\t\t\t// Added in version 2\n\t\t\tslim_objectid_t mutation_type_id = mutation_type_ptr->mutation_type_id_;\n\t\t\tslim_position_t position = mutation_ptr->position_;\n\t\t\tslim_selcoeff_t selection_coeff = mutation_ptr->selection_coeff_;\n\t\t\tslim_selcoeff_t dominance_coeff = mutation_type_ptr->dominance_coeff_;\n\t\t\t// BCH 9/22/2021: Note that mutation_type_ptr->hemizygous_dominance_coeff_ is not saved; too edge to be bothered...\n\t\t\tslim_objectid_t subpop_index = mutation_ptr->subpop_index_;\n\t\t\tslim_tick_t origin_tick = mutation_ptr->origin_tick_;\n\t\t\tslim_refcount_t prevalence = polymorphism.prevalence_;\n\t\t\tint8_t nucleotide = mutation_ptr->nucleotide_;\n\t\t\t\n\t\t\t// Write a tag indicating we are starting a new mutation\n\t\t\tint32_t mutation_start_tag = 0xFFFF0002;\n\t\t\t\n\t\t\tp_out.write(reinterpret_cast<char *>(&mutation_start_tag), sizeof mutation_start_tag);\n\t\t\t\n\t\t\t// Write the mutation data\n\t\t\tp_out.write(reinterpret_cast<char *>(&polymorphism_id), sizeof polymorphism_id);\n\t\t\tp_out.write(reinterpret_cast<char *>(&mutation_id), sizeof mutation_id);\t\t\t\t\t\t\t// Added in version 2\n\t\t\tp_out.write(reinterpret_cast<char *>(&mutation_type_id), sizeof mutation_type_id);\n\t\t\tp_out.write(reinterpret_cast<char *>(&position), sizeof position);\n\t\t\tp_out.write(reinterpret_cast<char *>(&selection_coeff), sizeof selection_coeff);\n\t\t\tp_out.write(reinterpret_cast<char *>(&dominance_coeff), sizeof dominance_coeff);\n\t\t\tp_out.write(reinterpret_cast<char *>(&subpop_index), sizeof subpop_index);\n\t\t\tp_out.write(reinterpret_cast<char *>(&origin_tick), sizeof origin_tick);\n\t\t\tp_out.write(reinterpret_cast<char *>(&prevalence), sizeof prevalence);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&nucleotide), sizeof nucleotide);\t\t\t\t\t\t\t// added in version 5\n\t\t\t\n\t\t\tif (p_output_object_tags)\n\t\t\t\tp_out.write(reinterpret_cast<const char *>(&mutation_ptr->tag_value_), sizeof mutation_ptr->tag_value_);\n\t\t\t\n\t\t\t// now will come either a mutation start tag, or a section end tag\n\t\t}\n\t\t\n\t\t// Write a tag indicating the section has ended\n\t\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\t\n\t\t// Haplosomes section\n\t\tbool use_16_bit = (mutation_map_size <= UINT16_MAX - 1);\t// 0xFFFF is reserved as the start of our various tags\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : subpops_)\t\t\t// go through all subpopulations\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tslim_objectid_t subpop_id = subpop_pair.first + 1;\t// + 1 so it doesn't ever collide with the section end tag\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tconst Haplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\t// Write out the haplosome header; start with the subpop id + 1 to guarantee that the first 32 bits are != section_end_tag\n\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&subpop_id), sizeof subpop_id);\t// + 1\n\t\t\t\t\t\n\t\t\t\t\tif (p_output_object_tags)\n\t\t\t\t\t\tp_out.write(reinterpret_cast<const char *>(&haplosome->tag_value_), sizeof haplosome->tag_value_);\n\t\t\t\t\t\n\t\t\t\t\t// Write out the mutation list\n\t\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\t// null haplosomes get a 32-bit flag value written instead of a mutation count\n\t\t\t\t\t\tint32_t null_haplosome_tag = 0xFFFF1000;\n\t\t\t\t\t\t\n\t\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&null_haplosome_tag), sizeof null_haplosome_tag);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// write a 32-bit mutation count\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint32_t total_mutations = haplosome->mutation_count();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&total_mutations), sizeof total_mutations);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (use_16_bit)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Write out 16-bit mutation tags\n\t\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_polymorphismid_t polymorphism_id = FindMutationInPolymorphismMap(polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (polymorphism_id == -1)\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintAllBinary): (internal error) polymorphism not found.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (polymorphism_id <= UINT16_MAX - 1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuint16_t id_16 = (uint16_t)polymorphism_id;\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&id_16), sizeof id_16);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintAllBinary): (internal error) mutation id out of 16-bit bounds.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Write out 32-bit mutation tags\n\t\t\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tslim_polymorphismid_t polymorphism_id = FindMutationInPolymorphismMap(polymorphisms, mut_block_ptr + mut_ptr[mut_index]);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (polymorphism_id == -1)\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintAllBinary): (internal error) polymorphism not found.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tp_out.write(reinterpret_cast<char *>(&polymorphism_id), sizeof polymorphism_id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// now will come either an individual index, or a section end tag\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Write a tag indicating the haplosomes section has ended\n\t\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\t\n\t\t// Ancestral sequence section, for nucleotide-based models, when requested\n\t\tif (output_ancestral_nucs)\n\t\t{\n\t\t\tchromosome->AncestralSequence()->WriteCompressedNucleotides(p_out);\n\t\t\t\n\t\t\t// Write a tag indicating the ancestral sequence section has ended\n\t\t\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t\t}\n\t}\n\t\n\t// New in SLiM 5, output substitutions if requested\n\tif (p_output_substitutions)\n\t{\n\t\tfor (const Substitution *substitution_ptr : substitutions_)\n\t\t{\n\t\t\tconst MutationType *mutation_type_ptr = substitution_ptr->mutation_type_ptr_;\n\t\t\tint64_t mutation_id = substitution_ptr->mutation_id_;\n\t\t\tslim_objectid_t mutation_type_id = mutation_type_ptr->mutation_type_id_;\n\t\t\tslim_position_t position = substitution_ptr->position_;\n\t\t\tslim_selcoeff_t selection_coeff = substitution_ptr->selection_coeff_;\n\t\t\tslim_selcoeff_t dominance_coeff = mutation_type_ptr->dominance_coeff_;\n\t\t\tslim_objectid_t subpop_index = substitution_ptr->subpop_index_;\n\t\t\tslim_tick_t origin_tick = substitution_ptr->origin_tick_;\n\t\t\tslim_tick_t fixation_tick = substitution_ptr->fixation_tick_;\n\t\t\tslim_chromosome_index_t chromosome_index = substitution_ptr->chromosome_index_;\n\t\t\tint8_t nucleotide = substitution_ptr->nucleotide_;\n\t\t\t\n\t\t\t// Write a tag indicating we are starting a new substitution\n\t\t\tint32_t substitution_start_tag = 0xFFFF0003;\n\t\t\t\n\t\t\tp_out.write(reinterpret_cast<char *>(&substitution_start_tag), sizeof substitution_start_tag);\n\t\t\t\n\t\t\t// Write the mutation data\n\t\t\tp_out.write(reinterpret_cast<char *>(&mutation_id), sizeof mutation_id);\n\t\t\tp_out.write(reinterpret_cast<char *>(&mutation_type_id), sizeof mutation_type_id);\n\t\t\tp_out.write(reinterpret_cast<char *>(&position), sizeof position);\n\t\t\tp_out.write(reinterpret_cast<char *>(&selection_coeff), sizeof selection_coeff);\n\t\t\tp_out.write(reinterpret_cast<char *>(&dominance_coeff), sizeof dominance_coeff);\n\t\t\tp_out.write(reinterpret_cast<char *>(&subpop_index), sizeof subpop_index);\n\t\t\tp_out.write(reinterpret_cast<char *>(&origin_tick), sizeof origin_tick);\n\t\t\tp_out.write(reinterpret_cast<char *>(&fixation_tick), sizeof fixation_tick);\n\t\t\tp_out.write(reinterpret_cast<char *>(&chromosome_index), sizeof chromosome_index);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t\tp_out.write(reinterpret_cast<char *>(&nucleotide), sizeof nucleotide);\n\t\t\tif (p_output_object_tags)\n\t\t\t\tp_out.write(reinterpret_cast<const char *>(&substitution_ptr->tag_value_), sizeof substitution_ptr->tag_value_);\n\t\t\t\n\t\t\t// now will come either a mutation start tag, or a section end tag\n\t\t}\n\t\t\n\t\t// Write a tag indicating the section has ended\n\t\tp_out.write(reinterpret_cast<char *>(&section_end_tag), sizeof section_end_tag);\n\t}\n}\n\n// print sample of p_sample_size haplosomes from subpopulation p_subpop_id\nvoid Population::PrintSample_SLiM(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome) const\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_SLiM): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\tstd::vector<Individual *> &subpop_individuals = p_subpop.parent_individuals_;\n\tstd::vector<Haplosome *> candidates;\n\t\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome.Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome.Index()];\n\t\n\tfor (Individual *ind : subpop_individuals)\n\t{\n\t\tif (p_subpop.sex_enabled_ && (p_requested_sex != IndividualSex::kUnspecified) && (ind->sex_ != p_requested_sex))\n\t\t\tcontinue;\n\t\t\n\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *haplosome = ind->haplosomes_[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t\tcandidates.push_back(haplosome);\n\t\t}\n\t}\n\t\n\tif (p_replace && (candidates.size() == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_SLiM): no eligible haplosomes for sampling with replacement.\" << EidosTerminate();\n\tif (!p_replace && ((slim_popsize_t)candidates.size() < p_sample_size))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_SLiM): not enough eligible haplosomes for sampling without replacement.\" << EidosTerminate();\n\t\n\t// assemble a sample (with or without replacement)\n\tstd::vector<Haplosome *> sample; \n\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\n\tfor (slim_popsize_t s = 0; s < p_sample_size; s++)\n\t{\n\t\t// select a random haplosome (not a random individual) by selecting a random candidate entry\n\t\tint candidate_index = static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, (uint32_t)candidates.size()));\n\t\t\n\t\tsample.emplace_back(candidates[candidate_index]);\n\t\t\n\t\t// If we're sampling without replacement, remove the index we have just taken; either we will use it or it is invalid\n\t\tif (!p_replace)\n\t\t{\n\t\t\tcandidates[candidate_index] = candidates.back();\n\t\t\tcandidates.pop_back();\n\t\t}\n\t}\n\t\n\t// print the sample using Haplosome's static member function\n\tHaplosome::PrintHaplosomes_SLiM(p_out, sample, /* p_output_object_tags */ false);\n}\n\n// print sample of p_sample_size haplosomes from subpopulation p_subpop_id, using \"ms\" format\nvoid Population::PrintSample_MS(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome, bool p_filter_monomorphic) const\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_MS): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n\tstd::vector<Individual *> &subpop_individuals = p_subpop.parent_individuals_;\n\tstd::vector<Haplosome *> candidates;\n\t\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome.Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome.Index()];\n\t\n\tfor (Individual *ind : subpop_individuals)\n\t{\n\t\tif (p_subpop.sex_enabled_ && (p_requested_sex != IndividualSex::kUnspecified) && (ind->sex_ != p_requested_sex))\n\t\t\tcontinue;\n\t\t\n\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; ++haplosome_index)\n\t\t{\n\t\t\tHaplosome *haplosome = ind->haplosomes_[haplosome_index];\n\t\t\t\n\t\t\tif (!haplosome->IsNull())\n\t\t\t\tcandidates.push_back(haplosome);\n\t\t}\n\t}\n\t\n\tif (p_replace && (candidates.size() == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_MS): no eligible haplosomes for sampling with replacement.\" << EidosTerminate();\n\tif (!p_replace && ((slim_popsize_t)candidates.size() < p_sample_size))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_MS): not enough eligible haplosomes for sampling without replacement.\" << EidosTerminate();\n\t\n\t// assemble a sample (with or without replacement)\n\tstd::vector<Haplosome *> sample; \n\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\n\tfor (slim_popsize_t s = 0; s < p_sample_size; s++)\n\t{\n\t\t// select a random haplosome (not a random individual) by selecting a random candidate entry\n\t\tint candidate_index = static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, (uint32_t)candidates.size()));\n\t\t\n\t\tsample.emplace_back(candidates[candidate_index]);\n\t\t\n\t\t// If we're sampling without replacement, remove the index we have just taken; either we will use it or it is invalid\n\t\tif (!p_replace)\n\t\t{\n\t\t\tcandidates[candidate_index] = candidates.back();\n\t\t\tcandidates.pop_back();\n\t\t}\n\t}\n\t\n\t// print the sample using Haplosome's static member function\n\tHaplosome::PrintHaplosomes_MS(p_out, sample, p_chromosome, p_filter_monomorphic);\n}\n\n// print sample of p_sample_size *individuals* (NOT haplosomes or genomes) from subpopulation p_subpop_id\nvoid Population::PrintSample_VCF(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs, bool p_group_as_individuals) const\n{\n\tif (child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_VCF): (internal error) called with child generation active!.\" << EidosTerminate();\n\t\n\tstd::vector<Individual *> &subpop_individuals = p_subpop.parent_individuals_;\n\tstd::vector<Individual *> candidates;\n\t\n\tfor (Individual *ind : subpop_individuals)\n\t{\n\t\tif (p_subpop.sex_enabled_ && (p_requested_sex != IndividualSex::kUnspecified) && (ind->sex_ != p_requested_sex))\n\t\t\tcontinue;\n\t\t\n\t\tcandidates.push_back(ind);\n\t}\n\t\n\tif (p_replace && (candidates.size() == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_VCF): no eligible individuals for sampling with replacement.\" << EidosTerminate();\n\tif (!p_replace && ((slim_popsize_t)candidates.size() < p_sample_size))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::PrintSample_VCF): not enough eligible individuals for sampling without replacement.\" << EidosTerminate();\n\t\n\t// assemble a sample (with or without replacement)\n\tstd::vector<Haplosome *> sample; \n\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\n\tint first_haplosome_index = species_.FirstHaplosomeIndices()[p_chromosome.Index()];\n\tint last_haplosome_index = species_.LastHaplosomeIndices()[p_chromosome.Index()];\n\t\n\tfor (slim_popsize_t s = 0; s < p_sample_size; s++)\n\t{\n\t\t// select a random individual (not a random haplosome) by selecting a random candidate entry\n\t\tint candidate_index = static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, (uint32_t)candidates.size()));\n\t\tIndividual *ind = candidates[candidate_index];\n\t\t\n\t\t// take all of its haplosomes for the chosen chromosome, including null haplosomes (needed as placeholders)\n\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; ++haplosome_index)\n\t\t\tsample.emplace_back(ind->haplosomes_[haplosome_index]);\n\t\t\n\t\t// If we're sampling without replacement, remove the index we have just taken; either we will use it or it is invalid\n\t\tif (!p_replace)\n\t\t{\n\t\t\tcandidates[candidate_index] = candidates.back();\n\t\t\tcandidates.pop_back();\n\t\t}\n\t}\n\t\n\t// print the sample using Haplosome's static member function\n\tHaplosome::PrintHaplosomes_VCF(p_out, sample, p_chromosome, p_group_as_individuals, p_output_multiallelics, p_simplify_nucs, p_output_nonnucs);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/population.h",
    "content": "//\n//  population.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Population represents the entire simulated population as a map of one or more subpopulations.  This class is where much\n of the simulation logic resides; the population is called to put events into effect, to evolve, and so forth.\n \n */\n\n#ifndef __SLiM__population__\n#define __SLiM__population__\n\n\n#include <vector>\n#include <map>\n#include <string>\n#include <unordered_map>\n\n#include \"slim_globals.h\"\n#include \"substitution.h\"\n#include \"chromosome.h\"\n#include \"slim_eidos_block.h\"\n#include \"mutation_run.h\"\n\n\nclass Community;\nclass Species;\nclass Subpopulation;\nclass Individual;\nclass Haplosome;\n\n\n#pragma mark -\n#pragma mark Deferred reproduction (mainly for multithreading)\n#pragma mark -\n\ntypedef enum class SLiM_DeferredReproductionType : uint8_t {\n\tkCrossoverMutation = 0,\n\tkClonal,\n\tkSelfed,\n\tkRecombinant\n} SLiM_DeferredReproductionType;\n\nclass SLiM_DeferredReproduction_NonRecombinant {\npublic:\n\tSLiM_DeferredReproductionType type_;\n\tIndividual *parent1_;\n\tIndividual *parent2_;\n\tHaplosome *child_haplosome_1_;\n\tHaplosome *child_haplosome_2_;\n\tIndividualSex child_sex_;\n\t\n\tSLiM_DeferredReproduction_NonRecombinant(SLiM_DeferredReproductionType p_type,\n\t\t\t\t\t\t\t  Individual *p_parent1,\n\t\t\t\t\t\t\t  Individual *p_parent2,\n\t\t\t\t\t\t\t  Haplosome *p_child_haplosome_1,\n\t\t\t\t\t\t\t  Haplosome *p_child_haplosome_2,\n\t\t\t\t\t\t\t  IndividualSex p_child_sex) :\n\t\ttype_(p_type), parent1_(p_parent1), parent2_(p_parent2), child_haplosome_1_(p_child_haplosome_1), child_haplosome_2_(p_child_haplosome_2), child_sex_(p_child_sex)\n\t{};\n};\n\nclass SLiM_DeferredReproduction_Recombinant {\npublic:\n\tSLiM_DeferredReproductionType type_;\n\tSubpopulation *mutorigin_subpop_;\n\tHaplosome *child_haplosome_;\n\tHaplosome *strand1_;\n\tHaplosome *strand2_;\n\tstd::vector<slim_position_t> break_vec_;\n\t\n\tSLiM_DeferredReproduction_Recombinant(SLiM_DeferredReproductionType p_type,\n\t\t\t\t\t\t\t  Subpopulation *p_mutorigin_subpop,\n\t\t\t\t\t\t\t  Haplosome *p_strand1,\n\t\t\t\t\t\t\t  Haplosome *p_strand2,\n\t\t\t\t\t\t\t  std::vector<slim_position_t> &p_break_vec,\n\t\t\t\t\t\t\t  Haplosome *p_child_haplosome) :\n\t\ttype_(p_type), mutorigin_subpop_(p_mutorigin_subpop), child_haplosome_(p_child_haplosome), strand1_(p_strand1), strand2_(p_strand2)\n\t{\n\t\tstd::swap(break_vec_, p_break_vec);\t\t// take ownership of the passed vector with std::swap(), to avoid copying\n\t};\n};\n\n\n#ifdef SLIMGUI\n// This struct is used to hold fitness values observed during a run, for display by GraphView_FitnessOverTime\n// The Population keeps the fitness histories for all the subpopulations, because subpops can come and go, but\n// we want to remember their histories and display them even after they're gone.\ntypedef struct FitnessHistory {\n\tdouble *history_ = nullptr;\t\t\t\t\t\t// mean fitness, recorded per tick; tick 1 goes at index 0\n\tslim_tick_t history_length_ = 0;\t\t\t\t// the number of entries in the history_ buffer\n} FitnessHistory;\n\n// This struct similarly holds observed subpopulation sizes observed during a run, for QtSLiMGraphView_PopSizeOverTime\ntypedef struct SubpopSizeHistory {\n    slim_popsize_t *history_ = nullptr;             // subpop size, recorded per tick; tick 1 goes at index 0\n\tslim_tick_t history_length_ = 0;\t\t\t\t// the number of entries in the history_ buffer\n} SubpopSizeHistory;\n#endif\n\n\nclass Population\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\n\tMutationRun mutation_registry_;\t\t\t\t\t\t\t// OWNED POINTERS: a registry of all mutations that have been added to this population\n\tbool registry_needs_consistency_check_ = false;\t\t\t// set this to run CheckMutationRegistry() at the end of the cycle\n\t\n\t// Cache info for TallyMutationReferences...(), along with Chromosome::cached_tally_haplosome_count_; see those functions\n\tbool cached_tallies_valid_ = false;\n\tstd::vector<Subpopulation*> last_tallied_subpops_;\t\t// NOT OWNED POINTERS\n\t\npublic:\n\t\n\tstd::map<slim_objectid_t,Subpopulation*> subpops_;\t\t// OWNED POINTERS\n\t\n\tSLiMModelType model_type_;\n\tCommunity &community_;\n\tSpecies &species_;\n\t\n\t// Object pools for individuals and haplosomes, kept species-wide\n\tEidosObjectPool &species_haplosome_pool_;\t\t\t\t\t// NOT OWNED; a pool out of which haplosomes are allocated, for within-species locality\n\tEidosObjectPool &species_individual_pool_;\t\t\t\t\t// NOT OWNED; a pool out of which individuals are allocated, for within-species locality\n\tstd::vector<Individual *> species_individuals_junkyard_;\t// individuals get put here when we're done with them, for fast reuse\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\tbool keeping_muttype_registries_ = false;\t\t\t\t// if true, at least one MutationType is also keeping its own registry\n\tbool any_muttype_call_count_used_ = false;\t\t\t\t// if true, a muttype's muttype_registry_call_count_ has been incremented\n#endif\n\t\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tstd::vector<SLiM_DeferredReproduction_NonRecombinant> deferred_reproduction_nonrecombinant_;\n\tstd::vector<SLiM_DeferredReproduction_Recombinant> deferred_reproduction_recombinant_;\n#endif\n\t\n\tstd::vector<Substitution*> substitutions_;\t\t\t\t// OWNED POINTERS: Substitution objects for all fixed mutations\n\tstd::unordered_multimap<slim_position_t, Substitution*> treeseq_substitutions_map_;\t// TREE SEQUENCE RECORDING; keeps all fixed mutations, hashed by position\n\n\tbool child_generation_valid_ = false;\t\t\t\t\t// WF only: this keeps track of whether children have been generated by EvolveSubpopulation() yet, or whether the parents are still in charge\n\t\n\tstd::vector<Subpopulation*> removed_subpops_;\t\t\t// OWNED POINTERS: Subpops which are set to size 0 (and thus removed) are kept here until the end of the cycle\n\t\n#ifdef SLIMGUI\n\t// information-gathering for various graphs in SLiMgui\n\tslim_tick_t *mutation_loss_times_ = nullptr;\t\t\t// histogram bins: {1 bin per mutation-type} for 10 ticks, realloced outward to add new tick bins as needed\n\tuint32_t mutation_loss_tick_slots_ = 0;\t\t\t\t\t// the number of tick-sized slots (with bins per mutation-type) presently allocated\n\t\n\tslim_tick_t *mutation_fixation_times_ = nullptr;\t\t// histogram bins: {1 bin per mutation-type} for 10 ticks, realloced outward to add new tick bins as needed\n\tuint32_t mutation_fixation_tick_slots_ = 0;\t\t\t\t// the number of tick-sized slots (with bins per mutation-type) presently allocated\n\t\n\tstd::map<slim_objectid_t,FitnessHistory> fitness_histories_;\t// fitness histories indexed by subpopulation id (or by -1, for the Population history)\n    std::map<slim_objectid_t,SubpopSizeHistory> subpop_size_histories_;\t// size histories indexed by subpopulation id (or by -1, for the Population history)\n#endif\n\t\n\tPopulation(const Population&) = delete;\t\t\t\t\t// no copying\n\tPopulation& operator=(const Population&) = delete;\t\t// no copying\n\tPopulation(void) = delete;\t\t\t\t\t\t\t\t// no default constructor\n\texplicit Population(Species &p_species);\t\t\t// our constructor: we must have a reference to our species, from which we get our community\n\t~Population(void);\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\t// add new empty subpopulation p_subpop_id of size p_subpop_size\n\tSubpopulation *AddSubpopulation(slim_objectid_t p_subpop_id, slim_popsize_t p_subpop_size, double p_initial_sex_ratio, bool p_haploid);\n\t\n\t// Mutation registry access\n\tinline const MutationIndex *MutationRegistry(int *registry_count)\n\t{\n\t\t*registry_count = mutation_registry_.size();\n\t\treturn mutation_registry_.begin_pointer_const();\n\t}\n\t\n\tinline void MutationRegistryAdd(Mutation *p_mutation)\n\t{\n#if DEBUG\n\t\tif ((p_mutation->state_ == MutationState::kInRegistry) ||\n\t\t\t(p_mutation->state_ == MutationState::kRemovedWithSubstitution) ||\n\t\t\t(p_mutation->state_ == MutationState::kFixedAndSubstituted))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MutationRegistryAdd): \" << \"(internal error) cannot add a mutation to the registry that is already in the registry, or has been fixed/substituted.\" << EidosTerminate();\n#endif\n\t\t\n\t\t// We could be adding a lost mutation back into the registry (from a mutation() callback), in which case it gets a retain\n\t\t// New mutations already have a retain count of 1, which we use (i.e., we take ownership of the mutation passed in to us)\n\t\tif (p_mutation->state_ != MutationState::kNewMutation)\n\t\t\tp_mutation->Retain();\n\t\t\n\t\tMutationIndex new_mut_index = p_mutation->BlockIndex();\n\t\tmutation_registry_.emplace_back(new_mut_index);\n\t\t\n\t\tp_mutation->state_ = MutationState::kInRegistry;\n\t\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t\tif (keeping_muttype_registries_)\n\t\t{\n\t\t\tMutationType *mutation_type_ptr = p_mutation->mutation_type_ptr_;\n\t\t\t\n\t\t\tif (mutation_type_ptr->keeping_muttype_registry_)\n\t\t\t{\n\t\t\t\t// This mutation type is also keeping its own private registry, so we need to add to that as well\n\t\t\t\tmutation_type_ptr->muttype_registry_.emplace_back(new_mut_index);\n\t\t\t}\n\t\t}\n#endif\n\t}\n\t\n\t// apply modifyChild() callbacks to a generated child; a return of false means \"do not use this child, generate a new one\"\n\tbool ApplyModifyChildCallbacks(Individual *p_child, Individual *p_parent1, Individual *p_parent2, bool p_is_selfing, bool p_is_cloning, Subpopulation *p_target_subpop, Subpopulation *p_source_subpop, std::vector<SLiMEidosBlock*> &p_modify_child_callbacks);\n\t\n\t// apply recombination() callbacks to a generated child; a return of true means the breakpoints were changed\n\t// note that in the general case (e.g., addRecombinant()), the haplosomes might not belong to the parent\n\tbool ApplyRecombinationCallbacks(Individual *p_parent, Haplosome *p_haplosome1, Haplosome *p_haplosome2, std::vector<slim_position_t> &p_crossovers, std::vector<SLiMEidosBlock*> &p_recombination_callbacks);\n\t\n\t// generate a child haplosome from parental haplosome(s), very directly -- no null haplosomes etc., just cross/clone/recombine\n\t// these methods are templated with variants for speed; see also MungeIndividualCrossed() etc.\n\ttemplate <const bool f_treeseq, const bool f_callbacks>\n\tvoid HaplosomeCrossed(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\t\n\ttemplate <const bool f_treeseq, const bool f_callbacks>\n\tvoid HaplosomeCloned(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\t\n\ttemplate <const bool f_treeseq, const bool f_callbacks>\n\tvoid HaplosomeRecombined(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks);\n\t\n\tvoid (Population::*HaplosomeCrossed_TEMPLATED)(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<SLiMEidosBlock*> *p_recombination_callbacks, std::vector<SLiMEidosBlock*> *p_mutation_callbacks) = nullptr;\n\tvoid (Population::*HaplosomeCloned_TEMPLATED)(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome, std::vector<SLiMEidosBlock*> *p_mutation_callbacks) = nullptr;\n\tvoid (Population::*HaplosomeRecombined_TEMPLATED)(Chromosome &p_chromosome, Haplosome &p_child_haplosome, Haplosome *parent_haplosome_1, Haplosome *parent_haplosome_2, std::vector<slim_position_t> &p_breakpoints, std::vector<SLiMEidosBlock*> *p_mutation_callbacks) = nullptr;\n\t\n\tvoid DoHeteroduplexRepair(std::vector<slim_position_t> &p_heteroduplex, slim_position_t *p_breakpoints, int p_breakpoints_count, Haplosome *p_parent_haplosome_1, Haplosome *p_parent_haplosome_2, Haplosome *p_child_haplosome);\n\t\n\t// generate offspring within a reproduction() callback using templated Subpopulation methods; these pointers get\n\t// set up at the beginning of each tick's reproduction() callback stage, and should not be used outside of it\n\tIndividual *(Subpopulation::*GenerateIndividualCrossed_TEMPLATED)(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex) = nullptr;\n\tIndividual *(Subpopulation::*GenerateIndividualSelfed_TEMPLATED)(Individual *p_parent) = nullptr;\n\tIndividual *(Subpopulation::*GenerateIndividualCloned_TEMPLATED)(Individual *p_parent) = nullptr;\n\n\t// An internal method that validates cached fitness values kept by Mutation objects\n\tvoid ValidateMutationFitnessCaches(void);\n\t\n\t// Recalculate all fitness values for the parental generation, including the use of mutationEffect() callbacks\n\tvoid RecalculateFitness(slim_tick_t p_tick);\n\t\n\t// Scan through all mutation runs in the simulation and unique them\n\tvoid UniqueMutationRuns(void);\n\t\n\t// Scan through all haplosomes and either split or join their mutation runs, to double or halve the number of runs per haplosome\n\tvoid SplitMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome);\n\tvoid JoinMutationRunsForChromosome(int32_t p_new_mutrun_count, Chromosome *p_chromosome);\n\t\n\t// Tally mutations and remove fixed/lost mutations\n\tvoid MaintainMutationRegistry(void);\n\t\n\t// Tally MutationRun usage and free unused MutationRuns.  Note that all of these tallying methods tally into\n\t// the same use_count_ counter kept by MutationRun, so a new tally wipes the results of the previous tally.\n\t// Also note that the mutation tallying methods below call these methods to tally mutation runs first, so\n\t// the mutation run tallies will be altered as a side effect of doing a mutation tally.  These methods all\n\t// place the number of non-null haplosomes that were tallied across into the tallied_haplosome_count_ value\n\t// of each chromosome involved in the tally.\n\tvoid TallyMutationRunReferencesForPopulationForChromosome(Chromosome *p_chromosome);\n\tvoid TallyMutationRunReferencesForPopulation(bool p_clock_for_mutrun_experiments);\n\tvoid TallyMutationRunReferencesForSubpopsForChromosome(std::vector<Subpopulation*> *p_subpops_to_tally, Chromosome *p_chromosome);\n\tvoid TallyMutationRunReferencesForSubpops(std::vector<Subpopulation*> *p_subpops_to_tally);\n\tvoid TallyMutationRunReferencesForHaplosomes(const Haplosome * const *haplosomes_ptr, slim_popsize_t haplosomes_count);\n\tvoid FreeUnusedMutationRuns(void);\t// depends upon a previous tally by TallyMutationRunReferencesForPopulation()!\n\t\n\t// Tally Mutation usage; these count the total number of times that each Mutation in the registry is referenced\n\t// by a population (or a set of subpopulations, or a set of haplosomes), putting the usage counts into the refcount\n\t// block kept by Mutation.  For the whole population, and for a set of subpops, cache info is maintained so the\n\t// tally can be reused when possible.  For a set of haplosomes, the result is not cached, and so the cache is\n\t// always invalidated.  The maximum number of references (the total number of non-null haplosomes tallied) is\n\t// always placed into the tallied_haplosome_count_ value for each chromosome involved in the tally.  When\n\t// tallying across all subpopulations, total_haplosome_count_ for each chromosome is also set to this same\n\t// value, which is the maximum possible number of references (i.e. fixation), as a side effect.  The cache\n\t// of tallies can be invalidated by calling InvalidateMutationReferencesCache().\n\tvoid InvalidateMutationReferencesCache(void);\n\n\tvoid TallyMutationReferencesAcrossPopulation(bool p_clock_for_mutrun_experiments);\n#ifdef SLIMGUI\n\tvoid TallyMutationReferencesAcrossPopulation_SLiMgui(void);\t\t// tallies selected subpops into SLiMgui-private counters\n#endif\n\tvoid TallyMutationReferencesAcrossSubpopulations(std::vector<Subpopulation*> *p_subpops_to_tally);\n\tvoid TallyMutationReferencesAcrossHaplosomes(const Haplosome * const *haplosomes, slim_popsize_t haplosomes_count);\n\t\n\tslim_refcount_t _CountNonNullHaplosomesForChromosome(Chromosome *p_chromosome);\n\tvoid _TallyMutationReferences_FAST_FromMutationRunUsage(bool p_clock_for_mutrun_experiments);\n#if DEBUG\n\tvoid _CheckMutationTallyAcrossHaplosomes(const Haplosome * const *haplosomes_ptr, slim_popsize_t haplosomes_count, std::string caller_name);\n#endif\n\t\n\t// Eidos back-end code that counts up tallied mutations, to be called after TallyMutationReferences...().\n\t// These methods correctly handle cases where the mutations are fixed, removed, substituted, lost, etc.,\n\t// to return the correct frequency/count values to the user as an EidosValue_SP.\n\tEidosValue_SP Eidos_FrequenciesForTalliedMutations(EidosValue *mutations_value);\n\tEidosValue_SP Eidos_CountsForTalliedMutations(EidosValue *mutations_value);\n\t\n\t// Handle negative fixation (remove from the registry) and positive fixation (convert to Substitution).\n\t// This uses reference counts from TallyMutationReferencesAcrossPopulation(), which must be called before this method.\n\tvoid RemoveAllFixedMutations(void);\n\t\n\t// check the registry for any bad entries (i.e. zombies, mutations with an incorrect state_)\n\tvoid CheckMutationRegistry(bool p_check_haplosomes);\n\tinline void SetMutationRegistryNeedsCheck(void) { registry_needs_consistency_check_ = true; }\n\tinline bool MutationRegistryNeedsCheck(void) { return registry_needs_consistency_check_; }\n\t\n\t// assess usage patterns of mutation runs across the simulation\n\tvoid AssessMutationRuns(void);\n\t\n\t//********** WF methods\n\t\n\t// add new subpopulation p_subpop_id of size p_subpop_size individuals drawn from source subpopulation p_source_subpop_id\n\tSubpopulation *AddSubpopulationSplit(slim_objectid_t p_subpop_id, Subpopulation &p_source_subpop, slim_popsize_t p_subpop_size, double p_initial_sex_ratio);\n\t\n\t// set size of subpopulation p_subpop_id to p_subpop_size\n\tvoid SetSize(Subpopulation &p_subpop, slim_popsize_t p_subpop_size);\n\t\n\t// set fraction p_migrant_fraction of p_subpop_id that originates as migrants from p_source_subpop_id per cycle  \n\tvoid SetMigration(Subpopulation &p_subpop, slim_objectid_t p_source_subpop_id, double p_migrant_fraction);\n\t\n\t// apply mateChoice() callbacks to a mating event with a chosen first parent; the return is the second parent index, or -1 to force a redraw\n\tslim_popsize_t ApplyMateChoiceCallbacks(slim_popsize_t p_parent1_index, Subpopulation *p_subpop, Subpopulation *p_source_subpop, std::vector<SLiMEidosBlock*> &p_mate_choice_callbacks);\n\t\n\t// generate children for subpopulation p_subpop_id, drawing from all source populations, handling crossover and mutation\n\tvoid EvolveSubpopulation(Subpopulation &p_subpop, bool p_mate_choice_callbacks_present, bool p_modify_child_callbacks_present, bool p_recombination_callbacks_present, bool p_mutation_callbacks_present, bool p_type_s_dfe_present);\n\t\n\t// step forward a generation: make the children become the parents\n\tvoid SwapGenerations(void);\n\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t// Clear all parental haplosomes to use nullptr for their mutation runs, so they are ready to reuse in the next tick\n\tvoid ClearParentalHaplosomes(void);\n#endif\n\t\n\t//********** nonWF methods\n\n\t// remove subpopulation p_subpop_id from the model entirely\n\tvoid RemoveSubpopulation(Subpopulation &p_subpop);\n\t\n\t// move individuals as requested by survival() callbacks\n\tvoid ResolveSurvivalPhaseMovement(void);\n\t\n\t// checks for deferred haplosomes in queue right now; allows optimization when none are present\n#if DEFER_BROKEN\n\tinline bool HasDeferredHaplosomes(void) { return ((deferred_reproduction_nonrecombinant_.size() > 0) || (deferred_reproduction_recombinant_.size() > 0)); }\n\tvoid CheckForDeferralInHaplosomesVector(Haplosome **p_haplosomes, size_t p_elements_size, const std::string &p_caller);\n\tvoid CheckForDeferralInHaplosomes(EidosValue_Object *p_haplosomes, const std::string &p_caller);\n\tvoid CheckForDeferralInIndividualsVector(Individual * const *p_individuals, size_t p_elements_size, const std::string &p_caller);\n#else\n\tinline bool HasDeferredHaplosomes(void) { return false; }\n\tinline void CheckForDeferralInHaplosomesVector(__attribute__ ((unused)) Haplosome **p_haplosomes, __attribute__ ((unused)) size_t p_elements_size, __attribute__ ((unused)) const std::string &p_caller) {}\n\tinline void CheckForDeferralInHaplosomes(__attribute__ ((unused)) EidosValue_Object *p_haplosomes, __attribute__ ((unused)) const std::string &p_caller) {}\n\tinline void CheckForDeferralInIndividualsVector(__attribute__ ((unused)) Individual * const *p_individuals, __attribute__ ((unused)) size_t p_elements_size, __attribute__ ((unused)) const std::string &p_caller) {}\n#endif\n\t\n#if DEFER_BROKEN\n\tvoid DoDeferredReproduction(void);\n#endif\n\t\n\t//********** methods for all models\n\t\n\tvoid PurgeRemovedSubpopulations(void);\n\n\t// print all mutations and all haplosomes to a stream\n\t// note that text output is now at Individual::PrintIndividuals_SLiM()\n\tvoid PrintAllBinary(std::ostream &p_out, bool p_output_spatial_positions, bool p_output_ages, bool p_output_ancestral_nucs, bool p_output_pedigree_ids, bool p_output_object_tags, bool p_output_substitutions) const;\n\t\n\t// print sample of p_sample_size haplosomes from subpopulation p_subpop_id, using SLiM's own format\n\tvoid PrintSample_SLiM(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome) const;\n\t\n\t// print sample of p_sample_size haplosomes from subpopulation p_subpop_id, using \"ms\" format\n\tvoid PrintSample_MS(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome, bool p_filter_monomorphic) const;\n\t\n\t// print sample of p_sample_size haplosomes from subpopulation p_subpop_id, using \"vcf\" format\n\tvoid PrintSample_VCF(std::ostream &p_out, Subpopulation &p_subpop, slim_popsize_t p_sample_size, bool p_replace, IndividualSex p_requested_sex, const Chromosome &p_chromosome, bool p_output_multiallelics, bool p_simplify_nucs, bool p_output_nonnucs, bool p_group_as_individuals) const;\n\t\n\t// remove subpopulations, purge all mutations and substitutions, etc.; called before InitializePopulationFrom[Text|Binary]File()\n\tvoid RemoveAllSubpopulationInfo(void);\n\t\n\t// additional methods for SLiMgui, for information-gathering support\n#ifdef SLIMGUI\n\tvoid RecordFitness(slim_tick_t p_history_index, slim_objectid_t p_subpop_id, double p_fitness_value);\n    void RecordSubpopSize(slim_tick_t p_history_index, slim_objectid_t p_subpop_id, slim_popsize_t p_subpop_size);\n\tvoid SurveyPopulation(void);\n\tvoid AddTallyForMutationTypeAndBinNumber(int p_mutation_type_index, int p_mutation_type_count, slim_tick_t p_bin_number, slim_tick_t **p_buffer, uint32_t *p_bufferBins);\n#endif\n};\n\n\n#endif /* defined(__SLiM__population__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_eidos_block.cpp",
    "content": "//\n//  slim_script_block.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 6/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n#include \"slim_eidos_block.h\"\n#include \"eidos_interpreter.h\"\n#include \"slim_globals.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_ast_node.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"interaction_type.h\"\n#include \"subpopulation.h\"\n\n#include \"errno.h\"\n#include \"string.h\"\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\nstd::ostream& operator<<(std::ostream& p_out, SLiMEidosBlockType p_block_type)\n{\n\tswitch (p_block_type)\n\t{\n\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tp_out << \"first()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tp_out << \"early()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tp_out << \"late()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tp_out << \"initialize()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tp_out << \"mutationEffect()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tp_out << \"fitnessEffect()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tp_out << \"interaction()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\tp_out << \"mateChoice()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tp_out << \"modifyChild()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tp_out << \"recombination()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tp_out << \"mutation()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\tp_out << \"survival()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\tp_out << \"reproduction()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\tp_out << \"function\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\tp_out << \"NO BLOCK\"; break;\n\t}\n\t\n\treturn p_out;\n}\n\nstatic inline bool SLiM_TokenIsCallbackIdentifier(EidosToken *token)\n{\n\tif (token->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\treturn false;\n\t\n\tif ((token->token_string_.compare(gStr_first) == 0) ||\n\t\t(token->token_string_.compare(gStr_early) == 0) ||\n\t\t(token->token_string_.compare(gStr_late) == 0) ||\n\t\t(token->token_string_.compare(gStr_initialize) == 0) ||\n\t\t(token->token_string_.compare(gStr_fitnessEffect) == 0) ||\n\t\t(token->token_string_.compare(gStr_mutationEffect) == 0) ||\n\t\t(token->token_string_.compare(gStr_mutation) == 0) ||\n\t\t(token->token_string_.compare(gStr_interaction) == 0) ||\n\t\t(token->token_string_.compare(gStr_mateChoice) == 0) ||\n\t\t(token->token_string_.compare(gStr_modifyChild) == 0) ||\n\t\t(token->token_string_.compare(gStr_recombination) == 0) ||\n\t\t(token->token_string_.compare(gStr_survival) == 0) ||\n\t\t(token->token_string_.compare(gStr_reproduction) == 0))\n\t\treturn true;\n\t\n\t// also return true for obsolete callbacks, to parse it correctly even though it's obsolete\n\tif (token->token_string_.compare(gStr_fitness) == 0)\n\t\treturn true;\n\t\n\treturn false;\n}\n\n\n//\n//\tSLiMEidosScript\n//\n#pragma mark -\n#pragma mark SLiMEidosScript\n#pragma mark -\n\nSLiMEidosScript::SLiMEidosScript(const std::string &p_script_string) : EidosScript(p_script_string, nullptr, 0, 0, 0)\n{\n}\n\nSLiMEidosScript::~SLiMEidosScript(void)\n{\n}\n\nEidosASTNode *SLiMEidosScript::Parse_SLiMFile(void)\n{\n\tEidosToken *virtual_token = new EidosToken(EidosTokenType::kTokenContextFile, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\n\tEidosASTNode *node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(virtual_token, true);\n\t\n\ttry\n\t{\n\t\t// We handle the grammar a bit differently than how it is printed in the railroad diagrams in the doc.\n\t\t// Parsing of the optional tick range is done in Parse_SLiMEidosBlock() since it ends up as children of that node.\n\t\twhile (current_token_type_ != EidosTokenType::kTokenEOF)\n\t\t{\n\t\t\t// For multispecies, we now look at the current token and handle it specially if it is \"species\" or \"ticks\".\n\t\t\tif ((current_token_type_ == EidosTokenType::kTokenIdentifier) && (current_token_->token_string_.compare(gStr_species) == 0))\n\t\t\t\tnode->AddChild(Parse_SpeciesSpecifier());\n\t\t\telse if ((current_token_type_ == EidosTokenType::kTokenIdentifier) && (current_token_->token_string_.compare(gStr_ticks) == 0))\n\t\t\t\tnode->AddChild(Parse_TicksSpecifier());\n\t\t\telse\n\t\t\t\tnode->AddChild(Parse_SLiMEidosBlock());\n\t\t}\n\t\t\n\t\tMatch(EidosTokenType::kTokenEOF, \"SLiM file\");\n\t}\n\tcatch (...)\n\t{\n\t\t// destroy the parse root and return it to the pool; the tree must be allocated out of gEidosASTNodePool!\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *SLiMEidosScript::Parse_SpeciesSpecifier(void)\n{\n\tEidosASTNode *node = nullptr, *species_name;\n\t\n\ttry {\n\t\t// This parses \"species identifier\" specifiers, creating a node with the species name as its child\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenIdentifier, \"species specifier\");\n\t\t\n\t\tspecies_name = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\tnode->AddChild(species_name);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\n\t\tMatch(EidosTokenType::kTokenIdentifier, \"species specifier\");\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *SLiMEidosScript::Parse_TicksSpecifier(void)\n{\n\tEidosASTNode *node = nullptr, *species_name;\n\t\n\ttry {\n\t\t// This parses \"ticks identifier\" specifiers, creating a node with the species name as its child\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenIdentifier, \"ticks specifier\");\n\t\t\n\t\tspecies_name = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\tnode->AddChild(species_name);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\n\t\tMatch(EidosTokenType::kTokenIdentifier, \"ticks specifier\");\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *SLiMEidosScript::Parse_SLiMEidosBlock(void)\n{\n\tEidosToken *virtual_token = new EidosToken(EidosTokenType::kTokenContextEidosBlock, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\n\tEidosASTNode *slim_script_block_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(virtual_token, true);\n\t\n\t// We handle the grammar a bit differently than how it is printed in the railroad diagrams in the doc.\n\t// We parse the slim_script_info section here, as part of the script block.\n\ttry\n\t{\n\t\t// Keep track of the beginning of the script block, to patch virtual_token below...\n\t\tconst int32_t token_start = current_token_->token_start_;\n\t\tconst int32_t token_UTF16_start = current_token_->token_UTF16_start_;\n\t\tconst int32_t token_line = current_token_->token_line_;\t// we use the line of our starting token\n\t\tEidosASTNode *compound_statement_node = nullptr;\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenFunction)\n\t\t{\n\t\t\t// Starting in SLiM 2.5, the user can declare their own functions at the top level in the SLiM file.\n\t\t\t// Since the SLiM input file is not an Eidos interpreter block, we have to handle that ourselves.\n\t\t\tEidosASTNode *function_node = Parse_FunctionDecl();\n\t\t\t\n\t\t\tif (function_node->children_.size() == 4)\n\t\t\t{\n\t\t\t\tcompound_statement_node = function_node->children_[3];\t// for the virtual token range below\n\t\t\t\t\n\t\t\t\tslim_script_block_node->AddChild(function_node);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The first element is an optional script identifier like s1; we check here that an identifier matches the\n\t\t\t// pattern sX before eating it, since an identifier here could also be a callback tag like \"mutationEffect\".\n\t\t\tif ((current_token_type_ == EidosTokenType::kTokenIdentifier) && SLiMEidosScript::StringIsIDWithPrefix(current_token_->token_string_, 's'))\n\t\t\t{\n\t\t\t\t// a script identifier like s1 is present; add it\n\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM script block\");\n\t\t\t}\n\t\t\t\n\t\t\t// Next comes an optional tick X, or a tick range X:Y, X:, or :Y (a lone : is not legal).\n\t\t\t// We don't parse this as if the : were an operator, since we have to allow for a missing start or end;\n\t\t\t// for this reason, we make the : into a node of its own, with no children, so X:Y, X:, and :Y are distinct.\n\t\t\t// SLiMEidosBlock::SLiMEidosBlock(EidosASTNode *p_root_node) handles this anomalous tree structure.\n\t\t\t//\n\t\t\t// BCH 3/6/2024: We now allow ticks specifiers with a complex structure such as N, N+10, N:(N+10),\n\t\t\t// (N+10):(N+20), and even things like 1:(L ? N+10 else N+20), etc.  Note that parentheses are needed\n\t\t\t// for the sequence expressions that involve complicated operands.  This is tricky.  As just mentioned,\n\t\t\t// we want to allow X: and :Y, so this is not a normal Eidos sequence-expression, and we can't parse it\n\t\t\t// as such.  We use special _NOSEQ parsing methods below to parse just X, the colon, and Y, without\n\t\t\t// allowing the colon to become a sequence-expression.  That means that \"N+10:N+20\" would parse as \"N+10\",\n\t\t\t// the colon, and \"N+20\", which might seem nice, and might even be what the user wants -- but it is\n\t\t\t// not how the operator precedence of the : operator normally works in Eidos, which would be N+(10:N)+20\n\t\t\t// instead.  To avoid confusion over this conflict, we require that if X and Y are both present (X:Y),\n\t\t\t// they must both be \"primary\" or \"postfix\" expressions -- a number, an identifier, a parenthesized expression,\n\t\t\t// function and method calls, etc., where the top-level operator node is higher precedence than the\n\t\t\t// sequence operator.  This way, X:Y always behaves as it does in Eidos, even though we are parsing it\n\t\t\t// in a different way, because we disallow all of the conflicting cases.  That check is done at evaluation\n\t\t\t// time; see EvaluateScriptBlockTickRanges().  Here we just do the parsing, using NOSEQ.\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenColon)\n\t\t\t{\n\t\t\t\t// The tick range starts with a colon; first eat that\n\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\tMatch(EidosTokenType::kTokenColon, \"SLiM script block\");\n\t\t\t\t\n\t\t\t\t// In this situation, we must have an end tick subexpression; a lone colon is not a legal tick specifier\n\t\t\t\tif (SLiM_TokenIsCallbackIdentifier(current_token_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; expected an integer expression for the tick range end.\" << EidosTerminate(current_token_);\n\t\t\t\t\n\t\t\t\t// BCH 3/6/2024: We used to require a number here:\n\t\t\t\t//\n\t\t\t\t//if (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t//\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t//\n\t\t\t\t// but now we allow any NOSEQ subexpression:\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *end_tick_expr = nullptr;\n\t\t\t\t\t\n\t\t\t\t\tend_tick_expr = Parse_ConditionalExpr_NOSEQ();\n\t\t\t\t\t\n\t\t\t\t\tslim_script_block_node->AddChild(end_tick_expr);\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; expected an integer expression for the tick range end.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\n\t\t\t\t\t// Introduce a bad node, since we're being error-tolerant\n\t\t\t\t\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (!SLiM_TokenIsCallbackIdentifier(current_token_))\n\t\t\t{\n\t\t\t\t// A start tick subexpression appears to be present; add it\n\t\t\t\t\n\t\t\t\t// We used to require a number here:\n\t\t\t\t//\n\t\t\t\t//if (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t//\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t//\n\t\t\t\t// but now we allow any NOSEQ subexpression:\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *start_tick_expr = nullptr;\n\t\t\t\t\t\n\t\t\t\t\tstart_tick_expr = Parse_ConditionalExpr_NOSEQ();\n\t\t\t\t\t\n\t\t\t\t\tslim_script_block_node->AddChild(start_tick_expr);\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; expected an integer expression for the tick range start.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\n\t\t\t\t\t// Introduce a bad node, since we're being error-tolerant\n\t\t\t\t\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// If a colon is present, we have a range, although it could be just X:\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenColon)\n\t\t\t\t{\n\t\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\tMatch(EidosTokenType::kTokenColon, \"SLiM script block\");\n\t\t\t\t\t\n\t\t\t\t\t// If an end tick subexpression is present, add it\n\t\t\t\t\tif (!SLiM_TokenIsCallbackIdentifier(current_token_))\n\t\t\t\t\t{\n\t\t\t\t\t\t// We used to require a number here:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t//if (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t\t\t//\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// but now we allow any NOSEQ subexpression:\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosASTNode *end_tick_expr = nullptr;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tend_tick_expr = Parse_ConditionalExpr_NOSEQ();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tslim_script_block_node->AddChild(end_tick_expr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (...)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; expected an integer expression for the tick range end.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Introduce a bad node, since we're being error-tolerant\n\t\t\t\t\t\t\tslim_script_block_node->AddChild(Parse_Constant());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Now we are to the point of parsing the actual slim_script_block\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tif (current_token_->token_string_.compare(gStr_first) == 0)\n\t\t\t\t{\n\t\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM first() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM first() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM first() event\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_early) == 0)\n\t\t\t\t{\n\t\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM early() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM early() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM early() event\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_late) == 0)\n\t\t\t\t{\n\t\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM late() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM late() event\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM late() event\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_initialize) == 0)\n\t\t\t\t{\n\t\t\t\t\tslim_script_block_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM initialize() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM initialize() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM initialize() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_fitnessEffect) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM fitnessEffect() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM fitnessEffect() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM fitnessEffect() callback\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM fitnessEffect() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_mutationEffect) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutationEffect() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM mutationEffect() callback\");\n\t\t\t\t\t\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A (required) mutation type id is present; add it\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutationEffect() callback\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; a mutation type id is required in mutationEffect() callback definitions.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"SLiM mutationEffect() callback\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutationEffect() callback\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; subpopulation id expected.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM mutationEffect() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_mutation) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutation() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM mutation() callback\");\n\t\t\t\t\t\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A (optional) mutation type id (or NULL) is present; add it\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutation() callback\");\n\t\t\t\t\t\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"SLiM mutation() callback\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mutation() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; subpopulation id expected.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM mutation() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_interaction) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM interaction() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM interaction() callback\");\n\t\t\t\t\t\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A (required) interaction type id is present; add it\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM interaction() callback\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; an interaction type id is required in interaction() callback definitions.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t{\n\t\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"SLiM interaction() callback\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM interaction() callback\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; subpopulation id expected.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM interaction() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_mateChoice) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mateChoice() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM mateChoice() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM mateChoice() callback\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM mateChoice() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_modifyChild) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM modifyChild() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM modifyChild() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM modifyChild() callback\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM modifyChild() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_recombination) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM recombination() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM recombination() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id (or NULL) is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM recombination() callback\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// A (optional) chromosome identifier (id or symbol, or NULL) is present; add it\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"SLiM recombination() callback\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenString)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenString, \"SLiM recombination() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenNumber, \"SLiM recombination() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM reproduction() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; chromosome-id (integer or string) or NULL expected.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM recombination() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_survival) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM survival() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM survival() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM survival() callback\");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM survival() callback\");\n\t\t\t\t}\n\t\t\t\telse if (current_token_->token_string_.compare(gStr_reproduction) == 0)\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *callback_info_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\tslim_script_block_node->AddChild(callback_info_node);\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM reproduction() callback\");\n\t\t\t\t\tMatch(EidosTokenType::kTokenLParen, \"SLiM reproduction() callback\");\n\t\t\t\t\t\n\t\t\t\t\t// A (optional) subpopulation id (or NULL) is present; add it\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM reproduction() callback\");\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// A (optional) sex string (or NULL) is present; add it\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"SLiM reproduction() callback\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenString)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenString, \"SLiM reproduction() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_));\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"SLiM reproduction() callback\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; sex of 'M' or 'F' expected.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Make a placeholder bad node, to be error-tolerant\n\t\t\t\t\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\t\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\t\t\t\tcallback_info_node->AddChild(bad_node);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"SLiM reproduction() callback\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected identifier \" << *current_token_ << \"; expected an event declaration (first, early, late), a callback declaration (initialize, fitnessEffect, interaction, mateChoice, modifyChild, mutation, mutationEffect, recombination, reproduction, or survival), or a function declaration.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\n\t\t\t\t\t// Consume the stray identifier, to be error-tolerant\n\t\t\t\t\tConsume();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): unexpected token \" << *current_token_ << \"; expected an event declaration (first, early, late), a callback declaration (initialize, fitnessEffect, interaction, mateChoice, modifyChild, mutation, mutationEffect, recombination, reproduction, or survival), or a function declaration.  Note that early() is no longer a default script block type that may be omitted; it must now be specified explicitly.\" << EidosTerminate(current_token_);\n\t\t\t\t\n\t\t\t\t// Consume the stray identifier, to be error-tolerant\n\t\t\t\tConsume();\n\t\t\t}\n\t\t\t\n\t\t\t// Regardless of what happened above, all Eidos blocks end with a compound statement, which is the last child of the node\n\t\t\tcompound_statement_node = Parse_CompoundStatement();\n\t\t\t\n\t\t\tslim_script_block_node->AddChild(compound_statement_node);\n\t\t}\n\t\t\n\t\t// Patch virtual_token to contain the range from beginning to end of the script block\n\t\tif (compound_statement_node)\n\t\t{\n\t\t\tconst int32_t token_end = compound_statement_node->token_->token_end_;\n\t\t\tconst int32_t token_UTF16_end = compound_statement_node->token_->token_UTF16_end_;\n\t\t\t\n\t\t\tstd::string &&token_string = script_string_.substr(token_start, token_end - token_start + 1);\n\t\t\t\n\t\t\tslim_script_block_node->ReplaceTokenWithToken(new EidosToken(slim_script_block_node->token_->token_type_, token_string, token_start, token_end, token_UTF16_start, token_UTF16_end, token_line));\n\t\t}\n\t\telse if (!parse_make_bad_nodes_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::Parse_SLiMEidosBlock): (internal error) missing compound_statement_node\" << EidosTerminate(current_token_);\n\n\t}\n\tcatch (...)\n\t{\n\t\tif (slim_script_block_node)\n\t\t{\n\t\t\tslim_script_block_node->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(slim_script_block_node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn slim_script_block_node;\n}\n\nvoid SLiMEidosScript::ParseSLiMFileToAST(bool p_make_bad_nodes)\n{\n\t// destroy the parse root and return it to the pool; the tree must be allocated out of gEidosASTNodePool!\n\tif (parse_root_)\n\t{\n\t\tparse_root_->~EidosASTNode();\n\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(parse_root_));\n\t\tparse_root_ = nullptr;\n\t}\n\t\n\t// set up parse state\n\tparse_index_ = 0;\n\tcurrent_token_ = &token_stream_.at(parse_index_);\t\t// should always have at least an EOF\n\tcurrent_token_type_ = current_token_->token_type_;\n\tparse_make_bad_nodes_ = p_make_bad_nodes;\n\t\n\t// parse a new AST from our start token\n\tparse_root_ = Parse_SLiMFile();\n\t\n\tparse_root_->OptimizeTree();\n\t\n\t// if logging of the AST is requested, do that\n\tif (gEidosLogAST)\n\t{\n\t\tstd::cout << \"AST : \\n\";\n\t\tthis->PrintAST(std::cout);\n\t}\n\t\n\tparse_make_bad_nodes_ = false;\n}\n\nbool SLiMEidosScript::StringIsIDWithPrefix(const std::string &p_identifier_string, char p_prefix_char)\n{\n\tconst char *id_cstr = p_identifier_string.c_str();\n\tsize_t id_cstr_len = strlen(id_cstr);\n\t\n\t// the criteria here are pretty loose, because we want SLiMEidosScript::ExtractIDFromStringWithPrefix to be\n\t// called and generate a raise if the string appears to be intended to be an ID but is malformed\n\t// however, we don't want to end up here with just any string that starts with the prefix character...\n\t\n\t// if the prefix character is not present, then it's not a match\n\tif ((id_cstr_len < 1) || (*id_cstr != p_prefix_char))\n\t\treturn false;\n\t\n\t// if there is at least one character following the prefix, those characters must all be numeric\n\tif (id_cstr_len > 1)\n\t{\n\t\tfor (unsigned int str_index = 1; str_index < id_cstr_len; ++str_index)\n\t\t\tif ((id_cstr[str_index] < '0') || (id_cstr[str_index] > '9'))\n\t\t\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\nslim_objectid_t SLiMEidosScript::ExtractIDFromStringWithPrefix(const std::string &p_identifier_string, char p_prefix_char, const EidosToken *p_blame_token)\n{\n\tconst char *id_cstr = p_identifier_string.c_str();\n\tsize_t id_cstr_len = strlen(id_cstr);\n\t\n\tif ((id_cstr_len < 1) || (*id_cstr != p_prefix_char))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::ExtractIDFromStringWithPrefix): an identifier prefix '\" << p_prefix_char << \"' was expected.\" << EidosTerminate(p_blame_token);\n\t\n\tfor (unsigned int str_index = 1; str_index < id_cstr_len; ++str_index)\n\t\tif ((id_cstr[str_index] < '0') || (id_cstr[str_index] > '9'))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::ExtractIDFromStringWithPrefix): the id after the '\" << p_prefix_char << \"' prefix must be a simple integer.\" << EidosTerminate(p_blame_token);\n\t\n\tif (id_cstr_len < 2)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::ExtractIDFromStringWithPrefix): an integer id was expected after the '\" << p_prefix_char << \"' prefix.\" << EidosTerminate(p_blame_token);\n\t\n\terrno = 0;\n\tchar *end_scan_char = nullptr;\n\tint64_t long_block_id = strtoll(id_cstr + 1, &end_scan_char, 10);\t// +1 to omit the prefix character\n\t\n\tif (errno || (end_scan_char == id_cstr + 1))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::ExtractIDFromStringWithPrefix): the identifier \" << p_identifier_string << \" was not parseable.\" << EidosTerminate(p_blame_token);\n\t\n\tif ((long_block_id < 0) || (long_block_id > SLIM_MAX_ID_VALUE))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosScript::ExtractIDFromStringWithPrefix): the identifier \" << p_identifier_string << \" was out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn static_cast<slim_objectid_t>(long_block_id);\t\t// range check is above, with a better message than SLiMCastToObjectidTypeOrRaise()\n}\n\n\n//\n//\tSLiMEidosBlock\n//\n#pragma mark -\n#pragma mark SLiMEidosBlock\n#pragma mark -\n\nSLiMEidosBlockType SLiMEidosBlock::BlockTypeForRootNode(EidosASTNode *p_root_node)\n{\n\t// Get the block type for a node without actually constructing the block.  This is parallel to the constructor code below,\n\t// and the two must be maintained in parallel when new callback types, etc., are added.  Note that we don't do any bounds-\n\t// or error-checking here; we just need to know the *intended* block type, if we can figure it out.\n\tconst std::vector<EidosASTNode *> &block_children = p_root_node->children_;\n\tint child_index = 0, n_children = (int)block_children.size();\n\t\n\tif ((n_children == 1) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenFunction))\n\t{\n\t\treturn SLiMEidosBlockType::SLiMEidosUserDefinedFunction;\n\t}\n\telse\n\t{\n\t\t// eat a string, for the script id, if present; an identifier token must follow the sX format to be taken as an id here, as in the parse code\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tEidosToken *script_id_token = block_children[child_index]->token_;\n\t\t\t\n\t\t\tif ((script_id_token->token_type_ == EidosTokenType::kTokenIdentifier) && SLiMEidosScript::StringIsIDWithPrefix(script_id_token->token_string_, 's'))\n\t\t\t\tchild_index++;\n\t\t}\n\t\t\n\t\t// eat the optional tick range, which could be X, X:Y, X:, or :Y\n\t\tif ((child_index < n_children) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenNumber))\n\t\t\t\tchild_index++;\n\t\tif ((child_index < n_children) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenColon))\n\t\t\t\tchild_index++;\n\t\tif ((child_index < n_children) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenNumber))\n\t\t\t\tchild_index++;\n\t\t\n\t\t// eat the callback info node, if present\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tconst EidosASTNode *callback_node = block_children[child_index];\n\t\t\tconst EidosToken *callback_token = callback_node->token_;\n\t\t\t\n\t\t\tif (callback_token->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tconst std::string &callback_name = callback_token->token_string_;\n\t\t\t\t\n\t\t\t\tif (callback_name.compare(gStr_first) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosEventFirst;\n\t\t\t\telse if (callback_name.compare(gStr_early) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosEventEarly;\n\t\t\t\telse if (callback_name.compare(gStr_late) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosEventLate;\n\t\t\t\telse if (callback_name.compare(gStr_initialize) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosInitializeCallback;\n\t\t\t\telse if (callback_name.compare(gStr_fitnessEffect) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosFitnessEffectCallback;\n\t\t\t\telse if (callback_name.compare(gStr_mutationEffect) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\n\t\t\t\telse if (callback_name.compare(gStr_mutation) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosMutationCallback;\n\t\t\t\telse if (callback_name.compare(gStr_interaction) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosInteractionCallback;\n\t\t\t\telse if (callback_name.compare(gStr_mateChoice) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n\t\t\t\telse if (callback_name.compare(gStr_modifyChild) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n\t\t\t\telse if (callback_name.compare(gStr_recombination) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n\t\t\t\telse if (callback_name.compare(gStr_survival) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosSurvivalCallback;\n\t\t\t\telse if (callback_name.compare(gStr_reproduction) == 0)\n\t\t\t\t\treturn SLiMEidosBlockType::SLiMEidosReproductionCallback;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn SLiMEidosBlockType::SLiMEidosNoBlockType;\n}\n\nSLiMEidosBlock::SLiMEidosBlock(EidosASTNode *p_root_node) :\n\tself_symbol_(gID_self, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMEidosBlock_Class))),\n\tscript_block_symbol_(gEidosID_none, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMEidosBlock_Class))),\n\troot_node_(p_root_node)\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\tscript_block_symbol_.second->MarkAsConstant();\n\t\n\t// NOTE: SLiMEidosBlock::BlockTypeForRootNode() above must be maintained in parallel with this method!\n\tconst std::vector<EidosASTNode *> &block_children = root_node_->children_;\n\tint child_index = 0, n_children = (int)block_children.size();\n\t\n\tblock_id_ = -1;\t// the default unless it is set below\n\t\n\tif ((n_children == 1) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenFunction))\n\t{\n\t\tEidosASTNode *function_decl_node = block_children[child_index];\n\t\t\n\t\tif (function_decl_node->children_.size() == 4)\n\t\t{\n\t\t\tcompound_statement_node_ = function_decl_node->children_[3];\n\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosUserDefinedFunction;\n\t\t\t\n\t\t\tchild_index++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): (internal error) unexpected child count in user-defined function declaration.\" << EidosTerminate(function_decl_node->token_);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// eat a string, for the script id, if present; an identifier token must follow the sX format to be taken as an id here, as in the parse code\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tEidosToken *script_id_token = block_children[child_index]->token_;\n\t\t\t\n\t\t\tif ((script_id_token->token_type_ == EidosTokenType::kTokenIdentifier) && SLiMEidosScript::StringIsIDWithPrefix(script_id_token->token_string_, 's'))\n\t\t\t{\n\t\t\t\tblock_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(script_id_token->token_string_, 's', script_id_token);\n\t\t\t\tchild_index++;\n\t\t\t\t\n\t\t\t\t// fix ID string for our symbol\n\t\t\t\tstd::string new_symbol_string = SLiMEidosScript::IDStringWithPrefix('s', block_id_);\n\t\t\t\tscript_block_symbol_.first = EidosStringRegistry::GlobalStringIDForString(new_symbol_string);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// eat the optional tick range, which could be X, X:Y, X:, or :Y\n\t\t// we don't need to syntax-check here since the parse already did\n\t\t// BCH 3/6/2024: Note that X and Y can now be expressions, not just numbers; we evaluate them later, in EvaluateScriptBlockTickRanges()\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tEidosToken *start_tick_token = block_children[child_index]->token_;\n\t\t\t\n\t\t\t// BCH 3/6/2024: We used to parse a number here, and get its value immediately:\n\t\t\t//\n\t\t\t//if (start_tick_token->token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t//{\n\t\t\t//\tint64_t long_start = EidosInterpreter::NonnegativeIntegerForString(start_tick_token->token_string_, start_tick_token);\n\t\t\t//\t\n\t\t\t//\t// We do our own range checking here so that we can highlight the bad token\n\t\t\t//\tif ((long_start < 1) || (long_start > SLIM_MAX_TICK))\n\t\t\t//\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): the start tick \" << start_tick_token->token_string_ << \" is out of range.\" << EidosTerminate(start_tick_token);\n\t\t\t//\t\n\t\t\t//\tstart_tick_ = SLiMCastToTickTypeOrRaise(long_start);\n\t\t\t//\tend_tick_ = start_tick_;\t\t\t// if a start is given, the default end is the same as the start\n\t\t\t//\tchild_index++;\n\t\t\t//}\n\t\t\t//\n\t\t\t// but now we allow any expression, and evaluate it later (as long as it is not a colon):\n\t\t\tif ((start_tick_token->token_type_ != EidosTokenType::kTokenColon) && !SLiM_TokenIsCallbackIdentifier(start_tick_token))\n\t\t\t{\n\t\t\t\tstart_tick_node_ = block_children[child_index];\n\t\t\t\tchild_index++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tEidosToken *colon_token = block_children[child_index]->token_;\n\t\t\t\n\t\t\t// we don't need to do anything here except move across the colon\n\t\t\tif (colon_token->token_type_ == EidosTokenType::kTokenColon)\n\t\t\t{\n\t\t\t\t// BCH 3/6/2024: Evaluation of tick ranges is now deferred\n\t\t\t\t//end_tick_ = SLIM_MAX_TICK + 1;\t// marker value for \"no endpoint specified\"; illegal for the user to specify this as a literal\n\t\t\t\tcolon_node_ = block_children[child_index];\n\t\t\t\tchild_index++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tEidosToken *end_tick_token = block_children[child_index]->token_;\n\t\t\t\n\t\t\t// BCH 3/6/2024: We used to parse a number here, and get its value immediately:\n\t\t\t//if (end_tick_token->token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t//{\n\t\t\t//\tint64_t long_end = EidosInterpreter::NonnegativeIntegerForString(end_tick_token->token_string_, end_tick_token);\n\t\t\t//\t\n\t\t\t//\t// We do our own range checking here so that we can highlight the bad token\n\t\t\t//\tif ((long_end < 1) || (long_end > SLIM_MAX_TICK))\n\t\t\t//\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): the end tick \" << end_tick_token->token_string_ << \" is out of range.\" << EidosTerminate(end_tick_token);\n\t\t\t//\tif (long_end < start_tick_)\n\t\t\t//\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): the end tick \" << end_tick_token->token_string_ << \" is less than the start tick.\" << EidosTerminate(end_tick_token);\n\t\t\t//\t\n\t\t\t//\tend_tick_ = SLiMCastToTickTypeOrRaise(long_end);\n\t\t\t//\tchild_index++;\n\t\t\t//}\n\t\t\t// but now we allow any constant expression, and evaluate it later:\n\t\t\tif (!SLiM_TokenIsCallbackIdentifier(end_tick_token))\n\t\t\t{\n\t\t\t\tend_tick_node_ = block_children[child_index];\n\t\t\t\tchild_index++;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// eat the callback info node, if present\n\t\tif (child_index < n_children)\n\t\t{\n\t\t\tconst EidosASTNode *callback_node = block_children[child_index];\n\t\t\tconst EidosToken *callback_token = callback_node->token_;\n\t\t\t\n\t\t\t// Note that except for initialize() callbacks, this method leaves tick_range_evaluated_ as false; the tick\n\t\t\t// range is defined by the node, and evaluation of that is deferred to when EvaluateScriptBlockTickRanges()\n\t\t\t// is called, as for example by Community::FinishInitialization().\n\t\t\t\n\t\t\tif (callback_token->token_type_ != EidosTokenType::kTokenLBrace)\n\t\t\t{\n\t\t\t\tEidosTokenType callback_type = callback_token->token_type_;\n\t\t\t\tconst std::string &callback_name = callback_token->token_string_;\n\t\t\t\tconst std::vector<EidosASTNode *> &callback_children = callback_node->children_;\n\t\t\t\tint n_callback_children = (int)callback_children.size();\n\t\t\t\t\n\t\t\t\tidentifier_token_ = callback_token;\t// remember our identifier token for easy access later\n\t\t\t\t\n\t\t\t\tif ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_first) == 0))\n\t\t\t\t{\n\t\t\t\t\tif (n_callback_children != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): first() event needs 0 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosEventFirst;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_early) == 0))\n\t\t\t\t{\n\t\t\t\t\tif (n_callback_children != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): early() event needs 0 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosEventEarly;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_late) == 0))\n\t\t\t\t{\n\t\t\t\t\tif (n_callback_children != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): late() event needs 0 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosEventLate;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_initialize) == 0))\n\t\t\t\t{\n\t\t\t\t\tif (n_callback_children != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): initialize() callback needs 0 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (start_tick_node_ || colon_node_ || end_tick_node_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): a tick range cannot be specified for an initialize() callback.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\ttick_range_evaluated_ = true;\n\t\t\t\t\ttick_range_is_sequence_ = true;\n\t\t\t\t\ttick_start_ = 0;\n\t\t\t\t\ttick_end_ = 0;\n\t\t\t\t\ttick_set_.clear();\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosInitializeCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_fitnessEffect) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): fitnessEffect() callback needs 0 or 1 parameter.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosFitnessEffectCallback;\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_mutationEffect) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 1) && (n_callback_children != 2))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): mutationEffect() callback needs 1 or 2 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tEidosToken *mutation_type_id_token = callback_children[0]->token_;\n\t\t\t\t\t\n\t\t\t\t\tmutation_type_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(mutation_type_id_token->token_string_, 'm', mutation_type_id_token);\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[1]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_mutation) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1) && (n_callback_children != 2))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): mutation() callback needs 0, 1, or 2 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children >= 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *mutation_type_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutation_type_id_token->token_string_ == gEidosStr_NULL)\n\t\t\t\t\t\t\tmutation_type_id_ = -1;\t// special placeholder that indicates a NULL mutation type identifier\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmutation_type_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(mutation_type_id_token->token_string_, 'm', mutation_type_id_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (n_callback_children == 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[1]->token_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosMutationCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_interaction) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 1) && (n_callback_children != 2))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): interaction() callback needs 1 or 2 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tEidosToken *interaction_type_id_token = callback_children[0]->token_;\n\t\t\t\t\t\n\t\t\t\t\tinteraction_type_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(interaction_type_id_token->token_string_, 'i', interaction_type_id_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[1]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosInteractionCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_mateChoice) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): mateChoice() callback needs 0 or 1 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_modifyChild) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): modifyChild() callback needs 0 or 1 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_recombination) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1) && (n_callback_children != 2))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): recombination() callback needs 0, 1, or 2 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children >= 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (subpop_id_token->token_string_ == gEidosStr_NULL)\n\t\t\t\t\t\t\tsubpopulation_id_ = -1;\t\t// not limited to one subpopulation\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children >= 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *chromosome_id_token = callback_children[1]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((chromosome_id_token->token_type_ == EidosTokenType::kTokenIdentifier) && (chromosome_id_token->token_string_ == gEidosStr_NULL))\n\t\t\t\t\t\t\tchromosome_id_ = -1;\t\t// not limited by chromosome\n\t\t\t\t\t\telse if (chromosome_id_token->token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t\t\t\tchromosome_id_ = EidosInterpreter::NonnegativeIntegerForString(chromosome_id_token->token_string_, chromosome_id_token);\n\t\t\t\t\t\telse if (chromosome_id_token->token_type_ == EidosTokenType::kTokenString)\n\t\t\t\t\t\t\tchromosome_symbol_ = chromosome_id_token->token_string_;\t// will be translated into chromosome_id_ in RunInitializeCallbacks()\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): recombination() callback needs a value for chromosome that is a non-negative integer, or NULL.\" << EidosTerminate(callback_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_survival) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): survival() callback needs 0 or 1 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosSurvivalCallback;\n\t\t\t\t}\n\t\t\t\telse if ((callback_type == EidosTokenType::kTokenIdentifier) && (callback_name.compare(gStr_reproduction) == 0))\n\t\t\t\t{\n\t\t\t\t\tif ((n_callback_children != 0) && (n_callback_children != 1) && (n_callback_children != 2))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): reproduction() callback needs 0, 1, or 2 parameters.\" << EidosTerminate(callback_token);\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children >= 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *subpop_id_token = callback_children[0]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (subpop_id_token->token_string_ == gEidosStr_NULL)\n\t\t\t\t\t\t\tsubpopulation_id_ = -1;\t\t// not limited to one subpopulation\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsubpopulation_id_ = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_token->token_string_, 'p', subpop_id_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (n_callback_children >= 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosToken *sex_token = callback_children[1]->token_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((sex_token->token_type_ == EidosTokenType::kTokenIdentifier) && (sex_token->token_string_ == gEidosStr_NULL))\n\t\t\t\t\t\t\tsex_specificity_ = IndividualSex::kUnspecified;\t\t// not limited by sex\n\t\t\t\t\t\telse if ((sex_token->token_type_ == EidosTokenType::kTokenString) && (sex_token->token_string_ == \"M\"))\n\t\t\t\t\t\t\tsex_specificity_ = IndividualSex::kMale;\n\t\t\t\t\t\telse if ((sex_token->token_type_ == EidosTokenType::kTokenString) && (sex_token->token_string_ == \"F\"))\n\t\t\t\t\t\t\tsex_specificity_ = IndividualSex::kFemale;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): reproduction() callback needs a value for sex of 'M', 'F', or NULL.\" << EidosTerminate(callback_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttype_ = SLiMEidosBlockType::SLiMEidosReproductionCallback;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): unknown callback type.\" << EidosTerminate(callback_token);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tchild_index++;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// eat the compound statement, which must be present\n\t\tif ((child_index < n_children) && (block_children[child_index]->token_->token_type_ == EidosTokenType::kTokenLBrace))\n\t\t{\n\t\t\tcompound_statement_node_ = block_children[child_index];\n\t\t\tchild_index++;\n\t\t}\n\t}\n\t\n\tif (!compound_statement_node_)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): no compound statement found for SLiMEidosBlock.\" << EidosTerminate(child_index > 0 ? block_children[child_index - 1]->token_ : nullptr);\n\t\n\tif (child_index != n_children)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SLiMEidosBlock): unexpected node in SLiMEidosBlock.\" << EidosTerminate(block_children[child_index]->token_);\n\t\n\tScanTreeForIdentifiersUsed();\n}\n\nSLiMEidosBlock::SLiMEidosBlock(slim_objectid_t p_id, const std::string &p_script_string, SLiMEidosBlockType p_type, slim_tick_t p_start, slim_tick_t p_end, Species *p_species_spec, Species *p_ticks_spec) :\n\tself_symbol_(gID_self, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMEidosBlock_Class))),\n\tscript_block_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('s', p_id)), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SLiMEidosBlock_Class))),\n\ttype_(p_type), block_id_(p_id), tick_range_evaluated_(true), tick_range_is_sequence_(true), tick_start_(p_start), tick_end_(p_end), species_spec_(p_species_spec), ticks_spec_(p_ticks_spec)\n{\n\t// this constructor is used by the various registerX() methods that register a new script block; they all take a start and end tick,\n\t// with no option to supply a vector of ticks instead, which is why there is no constructor here taking a vector of ticks\n\t\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\tscript_block_symbol_.second->MarkAsConstant();\n\t\n\t// since this constructor is for script blocks that are not derived from the user script, we use the corresponding EidosScript constructor\n\tscript_ = new EidosScript(p_script_string);\n\t\n\t// the caller should now call TokenizeAndParse() to complete initialization\n}\n\nSLiMEidosBlock::~SLiMEidosBlock(void)\n{\n\tdelete script_;\n}\n\nvoid SLiMEidosBlock::TokenizeAndParse(void)\n{\n\t// This should be called on script-based SLiMEidosBlocks immediately after construction;\n\t// it is separated out from the constructor for simplicity because it may raise.\n\tif (script_)\n\t{\n\t\tscript_->Tokenize();\n\t\tscript_->ParseInterpreterBlockToAST(false);\n\t\t\n\t\troot_node_ = script_->AST();\n\t\t\n\t\tif (root_node_->children_.size() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::TokenizeAndParse): script blocks must be compound statements.\" << EidosTerminate();\n\t\tif (root_node_->children_[0]->token_->token_type_ != EidosTokenType::kTokenLBrace)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::TokenizeAndParse): script blocks must be compound statements.\" << EidosTerminate();\n\t\t\n\t\tcompound_statement_node_ = root_node_->children_[0];\n\t\t\n\t\tScanTreeForIdentifiersUsed();\n\t}\n}\n\nvoid SLiMEidosBlock::_ScanNodeForIdentifiersUsed(const EidosASTNode *p_scan_node)\n{\n\t// recurse down the tree; determine our children, then ourselves\n\tfor (auto child : p_scan_node->children_)\n\t\t_ScanNodeForIdentifiersUsed(child);\n\t\n\tif (p_scan_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t{\n\t\tconst std::string &token_string = p_scan_node->token_->token_string_;\n\t\t\n\t\tif (token_string.compare(gEidosStr_apply) == 0)\t\t\t\t\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr_sapply) == 0)\t\t\t\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr_doCall) == 0)\t\t\t\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr_executeLambda) == 0)\t\t\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr__executeLambda_OUTER) == 0)\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr_ls) == 0)\t\t\t\t\t\tcontains_wildcard_ = true;\n\t\tif (token_string.compare(gEidosStr_rm) == 0)\t\t\t\t\t\tcontains_wildcard_ = true;\n\t\t\n\t\tif (token_string.compare(gStr_self) == 0)\t\t\t\tcontains_self_ = true;\n\t\t\n\t\tif (token_string.compare(gStr_mut) == 0)\t\t\t\tcontains_mut_ = true;\n\t\tif (token_string.compare(gStr_effect) == 0)\t\t\t\tcontains_effect_ = true;\n\t\tif (token_string.compare(gStr_individual) == 0)\t\t\tcontains_individual_ = true;\n\t\tif (token_string.compare(gStr_element) == 0)\t\t\tcontains_element_ = true;\n\t\tif (token_string.compare(gStr_haplosome) == 0)\t\t\tcontains_haplosome_ = true;\n\t\tif (token_string.compare(gStr_haplosome1) == 0)\t\t\tcontains_haplosome1_ = true;\n\t\tif (token_string.compare(gStr_haplosome2) == 0)\t\t\tcontains_haplosome2_ = true;\n\t\tif (token_string.compare(gStr_subpop) == 0)\t\t\t\tcontains_subpop_ = true;\n\t\tif (token_string.compare(gStr_homozygous) == 0)\t\t\tcontains_homozygous_ = true;\n\t\tif (token_string.compare(gStr_sourceSubpop) == 0)\t\tcontains_sourceSubpop_ = true;\n\t\tif (token_string.compare(gEidosStr_weights) == 0)\t\tcontains_weights_ = true;\n\t\tif (token_string.compare(gStr_child) == 0)\t\t\t\tcontains_child_ = true;\n\t\tif (token_string.compare(gStr_parent) == 0)\t\t\t\tcontains_parent_ = true;\n\t\tif (token_string.compare(gStr_parent1) == 0)\t\t\tcontains_parent1_ = true;\n\t\tif (token_string.compare(gStr_isCloning) == 0)\t\t\tcontains_isCloning_ = true;\n\t\tif (token_string.compare(gStr_isSelfing) == 0)\t\t\tcontains_isSelfing_ = true;\n\t\tif (token_string.compare(gStr_parent2) == 0)\t\t\tcontains_parent2_ = true;\n\t\tif (token_string.compare(gStr_breakpoints) == 0)\t\tcontains_breakpoints_ = true;\n\t\tif (token_string.compare(gStr_distance) == 0)\t\t\tcontains_distance_ = true;\n\t\tif (token_string.compare(gStr_strength) == 0)\t\t\tcontains_strength_ = true;\n\t\tif (token_string.compare(gStr_receiver) == 0)\t\t\tcontains_receiver_ = true;\n\t\tif (token_string.compare(gStr_exerter) == 0)\t\t\tcontains_exerter_ = true;\n\t\tif (token_string.compare(gStr_originalNuc) == 0)\t\tcontains_originalNuc_ = true;\n\t\tif (token_string.compare(gStr_surviving) == 0)\t\t\tcontains_surviving_ = true;\n\t\tif (token_string.compare(gStr_fitness) == 0)\t\t\tcontains_fitness_ = true;\n\t\tif (token_string.compare(gStr_draw) == 0)\t\t\t\tcontains_draw_ = true;\n\t}\n}\n\nvoid SLiMEidosBlock::ScanTreeForIdentifiersUsed(void)\n{\n\t_ScanNodeForIdentifiersUsed(compound_statement_node_);\n\t\n\t// If the script block contains a \"wildcard\" – an identifier that signifies that any other identifier could be accessed – then\n\t// we just set all of our \"contains_\" flags to T.  Any new flag that is added must be added here too!\n\tif (contains_wildcard_)\n\t{\n\t\tcontains_self_ = true;\n\t\tcontains_mut_ = true;\n\t\tcontains_effect_ = true;\n\t\tcontains_individual_ = true;\n\t\tcontains_element_ = true;\n\t\tcontains_haplosome_ = true;\n\t\tcontains_haplosome1_ = true;\n\t\tcontains_haplosome2_ = true;\n\t\tcontains_subpop_ = true;\n\t\tcontains_homozygous_ = true;\n\t\tcontains_sourceSubpop_ = true;\n\t\tcontains_weights_ = true;\n\t\tcontains_child_ = true;\n\t\tcontains_parent_ = true;\n\t\tcontains_parent1_ = true;\n\t\tcontains_isCloning_ = true;\n\t\tcontains_isSelfing_ = true;\n\t\tcontains_parent2_ = true;\n\t\tcontains_breakpoints_ = true;\n\t\tcontains_distance_ = true;\n\t\tcontains_strength_ = true;\n\t\tcontains_receiver_ = true;\n\t\tcontains_exerter_ = true;\n\t\tcontains_originalNuc_ = true;\n\t\tcontains_surviving_ = true;\n\t\tcontains_fitness_ = true;\n\t\tcontains_draw_ = true;\n\t}\n}\n\n#ifdef SLIMGUI\n// used by SLiMgui to generate the scheduling log's output\nvoid SLiMEidosBlock::PrintDeclaration(std::ostream& p_out, Community *p_community)\n{\n\tif (p_community->is_explicit_species_)\n\t{\n\t\tif ((type_ == SLiMEidosBlockType::SLiMEidosEventFirst) ||\n\t\t\t(type_ == SLiMEidosBlockType::SLiMEidosEventEarly) ||\n\t\t\t(type_ == SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t{\n\t\t\t// events have ticks specifiers\n\t\t\tif (ticks_spec_ == nullptr)\n\t\t\t\tgSLiMScheduling << \"ticks all \";\n\t\t\telse\n\t\t\t\tgSLiMScheduling << \"ticks \" << ticks_spec_->name_ << \" \";\n\t\t}\n\t\telse if (type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t{\n\t\t\t// callbacks have species specifiers\n\t\t\tif (species_spec_ == nullptr)\n\t\t\t\tgSLiMScheduling << \"species all \";\n\t\t\telse\n\t\t\t\tgSLiMScheduling << \"species \" << species_spec_->name_ << \" \";\n\t\t}\n\t}\n\t\n\tif (block_id_ != -1)\n\t\tgSLiMScheduling << \"s\" << block_id_ << \" \";\n\t\n\tif (type_ != SLiMEidosBlockType::SLiMEidosInitializeCallback)\n\t{\n\t\tif (!tick_range_is_sequence_)\n\t\t{\n\t\t\tgSLiMScheduling << \"? \";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (tick_start_ != -1)\n\t\t\t\tgSLiMScheduling << tick_start_;\n\t\t\tif (tick_end_ != tick_start_)\n\t\t\t{\n\t\t\t\tif ((tick_start_ != -1) || (tick_end_ != SLIM_MAX_TICK + 1))\n\t\t\t\t\tgSLiMScheduling << \":\";\n\t\t\t\tif (tick_end_ != SLIM_MAX_TICK + 1)\n\t\t\t\t\tgSLiMScheduling << tick_end_;\n\t\t\t}\n\t\t\tif ((tick_start_ != -1) || (tick_end_ != SLIM_MAX_TICK + 1))\n\t\t\t\tgSLiMScheduling << \" \";\n\t\t}\n\t}\n\t\n\tswitch (type_)\n\t{\n\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tp_out << \"first()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tp_out << \"early()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tp_out << \"late()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tp_out << \"initialize()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tp_out << \"fitnessEffect()\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\tp_out << \"function\"; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\tp_out << \"NO BLOCK\"; break;\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\n\t\t{\n\t\t\t// mutationEffect(<mutTypeId> [, <subpopId>])\n\t\t\tp_out << \"mutationEffect(m\" << mutation_type_id_;\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \", p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\n\t\t{\n\t\t\t// interaction(<intTypeId> [, <subpopId>])\n\t\t\tp_out << \"interaction(i\" << interaction_type_id_;\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \", p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\n\t\t{\n\t\t\t// mateChoice([<subpopId>])\n\t\t\tp_out << \"mateChoice(\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\n\t\t{\n\t\t\t// modifyChild([<subpopId>])\n\t\t\tp_out << \"modifyChild(\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\n\t\t{\n\t\t\t// recombination([<subpopId>])\n\t\t\tp_out << \"recombination(\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"p\" << subpopulation_id_;\n\t\t\telse if (chromosome_id_ != -1)\n\t\t\t\tp_out << \"NULL\";\n\t\t\tif (chromosome_id_ != -1)\n\t\t\t\tp_out << \", \\\"\" << chromosome_id_ << \"\\\"\";\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\n\t\t{\n\t\t\t// mutation([<mutTypeId> [, <subpopId>]])\n\t\t\tp_out << \"mutation(\";\n\t\t\tif (mutation_type_id_ != -1)\n\t\t\t\tp_out << \"m\" << mutation_type_id_;\n\t\t\telse if (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"NULL\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \", p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\n\t\t{\n\t\t\t// survival([<subpopId>])\n\t\t\tp_out << \"survival(\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"p\" << subpopulation_id_;\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\n\t\t{\n\t\t\t// reproduction([<subpopId> [, <sex>]])\n\t\t\tp_out << \"reproduction(\";\n\t\t\tif (subpopulation_id_ != -1)\n\t\t\t\tp_out << \"p\" << subpopulation_id_;\n\t\t\telse if (sex_specificity_ != IndividualSex::kUnspecified)\n\t\t\t\tp_out << \"NULL\";\n\t\t\tif (sex_specificity_ != IndividualSex::kUnspecified)\n\t\t\t\tp_out << \", \\\"\" << sex_specificity_ << \"\\\"\";\n\t\t\tp_out << \")\";\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tint32_t token_line = root_node_->token_->token_line_;\n\t\n\tif (token_line != -1)\n\t\tgSLiMScheduling << \" [line \" << (token_line + 1) << \"]\";\n}\n#endif\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *SLiMEidosBlock::Class(void) const\n{\n\treturn gSLiM_SLiMEidosBlock_Class;\n}\n\nvoid SLiMEidosBlock::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\";\n\t\n\tif (tick_range_is_sequence_)\n\t{\n\t\tp_ostream << \"? : \";\n\t}\n\telse\n\t{\n\t\tif (tick_start_ > 0)\n\t\t{\n\t\t\tp_ostream << tick_start_;\n\t\t\t\n\t\t\tif (tick_end_ != tick_start_)\n\t\t\t\tp_ostream << \":\" << tick_end_;\n\t\t\t\n\t\t\tp_ostream << \" : \";\n\t\t}\n\t}\n\t\n\tswitch (type_)\n\t{\n\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\tp_ostream << gStr_first; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\tp_ostream << gStr_early; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\tp_ostream << gStr_late; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\tp_ostream << gStr_initialize; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\tp_ostream << gStr_mutationEffect; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\tp_ostream << gStr_fitnessEffect; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\tp_ostream << gStr_interaction; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\tp_ostream << gStr_mateChoice; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\tp_ostream << gStr_modifyChild; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\tp_ostream << gStr_recombination; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\tp_ostream << gStr_mutation; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\tp_ostream << gStr_survival; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\tp_ostream << gStr_reproduction; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\tp_ostream << gEidosStr_function; break;\n\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType: \t\t\t\tbreak;\t// never hit\n\t}\n\t\n\tp_ostream << \">\";\n}\n\nEidosValue_SP SLiMEidosBlock::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_id:\n\t\t{\n\t\t\tif (!cached_value_block_id_)\n\t\t\t\tcached_value_block_id_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(block_id_));\n\t\t\treturn cached_value_block_id_;\n\t\t}\n\t\tcase gEidosID_start:\n\t\t{\n\t\t\tif (!tick_range_evaluated_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): the tick range for this script block has not yet been evaluated, so the start property is undefined.\" << EidosTerminate();\n\t\t\tif (!tick_range_is_sequence_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): this script block does not have a sequential tick range, so the start property is undefined.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tick_start_));\n\t\t}\n\t\tcase gEidosID_end:\n\t\t{\n\t\t\tif (!tick_range_evaluated_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): the tick range for this script block has not yet been evaluated, so the end property is undefined.\" << EidosTerminate();\n\t\t\tif (!tick_range_is_sequence_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): this script block does not have a sequential tick range, so the end property is undefined.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tick_end_));\n\t\t}\n\t\t\t// FIXME: could add a `ticks` property as well, which would return a vector of ticks for scheduling when tick_range_is_sequence_ is true... but is it needed?\n\t\tcase gEidosID_type:\n\t\t{\n\t\t\tswitch (type_)\n\t\t\t{\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventFirst:\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_first));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventEarly:\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_early));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosEventLate:\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_late));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInitializeCallback:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_initialize));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationEffectCallback:\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_mutationEffect));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosFitnessEffectCallback:\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_fitnessEffect));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosInteractionCallback:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_interaction));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMateChoiceCallback:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_mateChoice));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosModifyChildCallback:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_modifyChild));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosRecombinationCallback:\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_recombination));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosMutationCallback:\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_mutation));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosSurvivalCallback:\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_survival));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosReproductionCallback:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_reproduction));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosUserDefinedFunction:\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_function));\n\t\t\t\tcase SLiMEidosBlockType::SLiMEidosNoBlockType:\t\t\t\treturn gStaticEidosValue_StringAsterisk;\t// never hit\n\t\t\t}\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): (internal error) unrecognized value for type_.\" << EidosTerminate();\n\t\t}\n\t\tcase gEidosID_source:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(compound_statement_node_->token_->token_string_));\n\t\tcase gID_speciesSpec:\n\t\t{\n\t\t\t// With no species spec, we return an empty object vector of class Species; this is allowed since this is a read-only property\n\t\t\tif (species_spec_)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(species_spec_, gSLiM_Species_Class));\n\t\t\telse\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Species_Class));\n\t\t}\n\t\tcase gID_ticksSpec:\n\t\t{\n\t\t\t// With no ticks spec, we return an empty object vector of class Species; this is allowed since this is a read-only property\n\t\t\tif (ticks_spec_)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(ticks_spec_, gSLiM_Species_Class));\n\t\t\telse\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Species_Class));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_active:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(block_active_));\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::GetProperty): property tag accessed on script block before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid SLiMEidosBlock::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_active:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\t// cannot activate a block if it has been deactivated by its association with an inactive species\n\t\t\tif (value && ((species_spec_ && !species_spec_->Active()) || (ticks_spec_ && !ticks_spec_->Active())))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::SetProperty): property active cannot be used to activate a block that is inactive because of a 'species' or 'ticks' specifier in its declaration, or because it was deactivated by a call to skipTick().\" << EidosTerminate();\n\t\t\t\n\t\t\tblock_active_ = value;\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t}\n}\n\n\n//\n//\tSLiMEidosBlock_Class\n//\n#pragma mark -\n#pragma mark SLiMEidosBlock_Class\n#pragma mark -\n\nEidosClass *gSLiM_SLiMEidosBlock_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *SLiMEidosBlock_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SLiMEidosBlock_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_active,\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_start,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_end,\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_type,\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_source,\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_speciesSpec,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_ticksSpec,\t\ttrue,\tkEidosValueMaskObject, gSLiM_Species_Class)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\n\n//\n//\tSLiMTypeTable\n//\n#pragma mark -\n#pragma mark SLiMTypeTable\n#pragma mark -\n\nSLiMTypeTable::SLiMTypeTable(void) : EidosTypeTable()\n{\n}\n\nSLiMTypeTable::~SLiMTypeTable(void)\n{\n}\n\nbool SLiMTypeTable::ContainsSymbol(EidosGlobalStringID p_symbol_name) const\n{\n\tbool has_symbol = EidosTypeTable::ContainsSymbol(p_symbol_name);\n\t\n\tif (!has_symbol)\n\t{\n\t\t// If our superclass is not aware of the symbol, then we want to pretend it exists if it follows\n\t\t// one of the standard naming patterns pX, gX, mX, or sX; this lets the user complete off of\n\t\t// those roots even if the simulation is not aware of the existence of the variable.  See also\n\t\t// eidosConsoleWindowController:tokenStringIsSpecialIdentifier:\n\t\tconst std::string &token_string = EidosStringRegistry::StringForGlobalStringID(p_symbol_name);\n\t\tint len = (int)token_string.length();\n\t\t\n\t\tif (len >= 2)\n\t\t{\n\t\t\tchar first_ch = token_string[0];\n\t\t\t\n\t\t\tif ((first_ch == 'p') || (first_ch == 'g') || (first_ch == 'm') || (first_ch == 's') || (first_ch == 'i'))\n\t\t\t{\n\t\t\t\tfor (int ch_index = 1; ch_index < len; ++ch_index)\n\t\t\t\t{\n\t\t\t\t\tchar idx_ch = token_string[ch_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((idx_ch < '0') || (idx_ch > '9'))\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn false;\n\t}\n\t\n\treturn has_symbol;\n}\n\nEidosTypeSpecifier SLiMTypeTable::GetTypeForSymbol(EidosGlobalStringID p_symbol_name) const\n{\n\tEidosTypeSpecifier symbol_type = EidosTypeTable::GetTypeForSymbol(p_symbol_name);\n\t\n\tif (symbol_type.type_mask == kEidosValueMaskNone)\n\t{\n\t\t// If our superclass is not aware of the symbol, then we want to pretend it exists if it follows\n\t\t// one of the standard naming patterns pX, gX, mX, or sX; this lets the user complete off of\n\t\t// those roots even if the simulation is not aware of the existence of the variable.  See also\n\t\t// eidosConsoleWindowController:tokenStringIsSpecialIdentifier:\n\t\tconst std::string &token_string = EidosStringRegistry::StringForGlobalStringID(p_symbol_name);\n\t\tint len = (int)token_string.length();\n\t\t\n\t\tif (len >= 2)\n\t\t{\n\t\t\tchar first_ch = token_string[0];\n\t\t\t\n\t\t\tif ((first_ch == 'p') || (first_ch == 'g') || (first_ch == 'm') || (first_ch == 's') || (first_ch == 'i'))\n\t\t\t{\n\t\t\t\tfor (int ch_index = 1; ch_index < len; ++ch_index)\n\t\t\t\t{\n\t\t\t\t\tchar idx_ch = token_string[ch_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((idx_ch < '0') || (idx_ch > '9'))\n\t\t\t\t\t\treturn symbol_type;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tswitch(first_ch)\n\t\t\t\t{\n\t\t\t\t\tcase 'p': return EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Subpopulation_Class};\n\t\t\t\t\tcase 'g': return EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_Haplosome_Class};\n\t\t\t\t\tcase 'm': return EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_MutationType_Class};\n\t\t\t\t\tcase 's': return EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class};\n\t\t\t\t\tcase 'i': return EidosTypeSpecifier{kEidosValueMaskObject, gSLiM_InteractionType_Class};\n\t\t\t\t\tdefault: break;\t// never hit, given the if above\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn symbol_type;\n\t}\n\t\n\treturn symbol_type;\n}\n\n\n//\n//\tSLiMTypeInterpreter\n//\n#pragma mark -\n#pragma mark SLiMTypeInterpreter\n#pragma mark -\n\nSLiMTypeInterpreter::SLiMTypeInterpreter(const EidosScript &p_script, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types)\n\t: EidosTypeInterpreter(p_script, p_symbols, p_functions, p_call_types)\n{\n}\n\nSLiMTypeInterpreter::SLiMTypeInterpreter(const EidosASTNode *p_root_node_, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types)\n\t: EidosTypeInterpreter(p_root_node_, p_symbols, p_functions, p_call_types)\n{\n}\n\nSLiMTypeInterpreter::~SLiMTypeInterpreter(void)\n{\n}\n\nvoid SLiMTypeInterpreter::_SetTypeForISArgumentOfClass(const EidosASTNode *p_arg_node, char p_symbol_prefix, const EidosClass *p_type_class)\n{\n\tif (p_arg_node)\n\t{\n\t\tconst EidosToken *arg_token = p_arg_node->token_;\n\t\t\n\t\tif (arg_token->token_type_ == EidosTokenType::kTokenString)\n\t\t{\n\t\t\t// The argument can be a string, in which case it must start with p_symbol_prefix and then have 1+ numeric characters\n\t\t\tconst std::string &constant_name = arg_token->token_string_;\n\t\t\t\n\t\t\tif ((constant_name.length() >= 2) && (constant_name[0] == p_symbol_prefix))\n\t\t\t{\n\t\t\t\tbool all_numeric = true;\n\t\t\t\t\n\t\t\t\tfor (size_t idx = 1; idx < constant_name.length(); ++idx)\n\t\t\t\t\tif (!isdigit(constant_name[idx]))\n\t\t\t\t\t\tall_numeric = false;\n\t\t\t\t\n\t\t\t\tif (all_numeric)\n\t\t\t\t{\n\t\t\t\t\tEidosGlobalStringID constant_id = EidosStringRegistry::GlobalStringIDForString(constant_name);\n\t\t\t\t\t\n\t\t\t\t\tglobal_symbols_->SetTypeForSymbol(constant_id, EidosTypeSpecifier{kEidosValueMaskObject, p_type_class});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (arg_token->token_type_ == EidosTokenType::kTokenNumber)\n\t\t{\n\t\t\t// The argument can be numeric, in which case it must have a cached int value that is singleton and within bounds\n\t\t\tEidosValue *cached_value = p_arg_node->cached_literal_value_.get();\n\t\t\t\n\t\t\tif (cached_value && (cached_value->Type() == EidosValueType::kValueInt) && (cached_value->Count() == 1))\n\t\t\t{\n\t\t\t\tint64_t cached_int = cached_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\n\t\t\t\tif ((cached_int >= 0) && (cached_int <= SLIM_MAX_ID_VALUE))\n\t\t\t\t{\n\t\t\t\t\tEidosGlobalStringID constant_id = EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix(p_symbol_prefix, static_cast<slim_objectid_t>(cached_int)));\n\t\t\t\t\t\n\t\t\t\t\tglobal_symbols_->SetTypeForSymbol(constant_id, EidosTypeSpecifier{kEidosValueMaskObject, p_type_class});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nEidosTypeSpecifier SLiMTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(std::string const &p_function_name, const EidosFunctionSignature *p_function_signature, const std::vector<EidosASTNode *> &p_arguments)\n{\n\t// call super; this should always be called, since it type-evaluates all arguments as a side effect\n\tEidosTypeSpecifier ret = EidosTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(p_function_name, p_function_signature, p_arguments);\n\t\n\t// Create any symbols defined as a side effect of this call, which happens after argument type-evaluation.\n\t// In figuring this stuff out, we need to be careful about the fact that the p_arguments vector can contain nullptr\n\t// values if there were missing arguments, etc.; we try to be error-tolerant, so we allow cases that would raise\n\t// in EidosInterpreter.  _SetTypeForISArgumentOfClass() is safe to call with nullptr.\n\tint argument_count = (int)p_arguments.size();\n\t\n\tif ((p_function_name == \"initializeGenomicElementType\") && (argument_count >= 1))\n\t{\n\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 'g', gSLiM_GenomicElementType_Class);\n\t}\n\telse if (((p_function_name == \"initializeMutationType\") || (p_function_name == \"initializeMutationTypeNuc\")) && (argument_count >= 1))\n\t{\n\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 'm', gSLiM_MutationType_Class);\n\t}\n\telse if ((p_function_name == \"initializeInteractionType\") && (argument_count >= 1))\n\t{\n\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 'i', gSLiM_InteractionType_Class);\n\t}\n\t\n\treturn ret;\n}\n\nEidosTypeSpecifier SLiMTypeInterpreter::_TypeEvaluate_MethodCall_Internal(const EidosClass *p_target, const EidosMethodSignature *p_method_signature, const std::vector<EidosASTNode *> &p_arguments)\n{\n\t// call super; this should always be called, since it type-evaluates all arguments as a side effect\n\tEidosTypeSpecifier ret = EidosTypeInterpreter::_TypeEvaluate_MethodCall_Internal(p_target, p_method_signature, p_arguments);\n\t\n\t// Create any symbols defined as a side effect of this call, which happens after argument type-evaluation.\n\t// In figuring this stuff out, we need to be careful about the fact that the p_arguments vector can contain nullptr\n\t// values if there were missing arguments, etc.; we try to be error-tolerant, so we allow cases that would raise\n\t// in EidosInterpreter.  _SetTypeForISArgumentOfClass() is safe to call with nullptr.\n\tif (p_method_signature)\n\t{\n\t\tif (p_target == gSLiM_Community_Class)\n\t\t{\n\t\t\tint argument_count = (int)p_arguments.size();\n\t\t\t\n\t\t\tconst std::string &function_name = p_method_signature->call_name_;\n\t\t\t\n\t\t\tif (((function_name == \"registerFirstEvent\") ||\n\t\t\t\t (function_name == \"registerEarlyEvent\") ||\n\t\t\t\t (function_name == \"registerInteractionCallback\") ||\n\t\t\t\t (function_name == \"registerLateEvent\") ||\n\t\t\t\t (function_name == \"rescheduleScriptBlock\")) && (argument_count >= 1))\n\t\t\t{\n\t\t\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 's', gSLiM_SLiMEidosBlock_Class);\n\t\t\t}\n\t\t}\n\t\telse if (p_target == gSLiM_Species_Class)\n\t\t{\n\t\t\tint argument_count = (int)p_arguments.size();\n\t\t\t\n\t\t\tconst std::string &function_name = p_method_signature->call_name_;\n\t\t\t\n\t\t\tif (((function_name == \"addSubpop\") || (function_name == \"addSubpopSplit\")) && (argument_count >= 1))\n\t\t\t{\n\t\t\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 'p', gSLiM_Subpopulation_Class);\n\t\t\t}\n\t\t\tif (((function_name == \"registerFitnessEffectCallback\") ||\n\t\t\t\t (function_name == \"registerMutationEffectCallback\") ||\n\t\t\t\t (function_name == \"registerMateChoiceCallback\") ||\n\t\t\t\t (function_name == \"registerModifyChildCallback\") ||\n\t\t\t\t (function_name == \"registerRecombinationCallback\") ||\n\t\t\t\t (function_name == \"registerMutationCallback\") ||\n\t\t\t\t (function_name == \"registerSurvivalCallback\") ||\n\t\t\t\t (function_name == \"registerReproductionCallback\")) && (argument_count >= 1))\n\t\t\t{\n\t\t\t\t_SetTypeForISArgumentOfClass(p_arguments[0], 's', gSLiM_SLiMEidosBlock_Class);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn ret;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_eidos_block.h",
    "content": "//\n//  slim_script_block.h\n//  SLiM\n//\n//  Created by Ben Haller on 6/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class SLiMEidosBlock represents one script block defined in SLiM's input file, or programmatically via the methods on Species.\n A SLiMEidosBlock knows the tick range in which it is to run, has a reference to its AST so it can be executed, and various\n other state.\n \n */\n\n#ifndef __SLiM__slim_script_block__\n#define __SLiM__slim_script_block__\n\n#include \"slim_globals.h\"\n#include \"eidos_script.h\"\n#include \"eidos_value.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_type_table.h\"\n#include \"eidos_type_interpreter.h\"\n\n#include <unordered_set>\n\nclass Community;\n\n\nenum class SLiMEidosBlockType {\n\tSLiMEidosEventFirst = 0,\n\tSLiMEidosEventEarly,\n\tSLiMEidosEventLate,\n\t\n\tSLiMEidosInitializeCallback,\n\tSLiMEidosMutationEffectCallback,\n\tSLiMEidosFitnessEffectCallback,\n\tSLiMEidosInteractionCallback,\n\tSLiMEidosMateChoiceCallback,\n\tSLiMEidosModifyChildCallback,\n\tSLiMEidosRecombinationCallback,\n\tSLiMEidosMutationCallback,\n\tSLiMEidosReproductionCallback,\n\tSLiMEidosSurvivalCallback,\n\t\n\tSLiMEidosUserDefinedFunction,\n\t\n\tSLiMEidosNoBlockType = -1\t\t// not used as a type, only used to indicate \"no type\"\n};\n\nstd::ostream& operator<<(std::ostream& p_out, SLiMEidosBlockType p_block_type);\n\n\n#pragma mark -\n#pragma mark SLiMEidosScript\n#pragma mark -\n\nclass SLiMEidosScript : public EidosScript\n{\nprivate:\n\ttypedef EidosScript super;\n\npublic:\n\tSLiMEidosScript(const SLiMEidosScript&) = delete;\t\t\t\t\t\t\t// no copying\n\tSLiMEidosScript& operator=(const SLiMEidosScript&) = delete;\t\t\t\t// no copying\n\tSLiMEidosScript(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\texplicit SLiMEidosScript(const std::string &p_script_string);\n\t\n\tvirtual ~SLiMEidosScript(void);\n\t\n\tvoid ParseSLiMFileToAST(bool p_make_bad_nodes = false);\t\t\t\t\t\t// generate AST from token stream for a SLiM input file ( slim_script_block* EOF )\n\t\n\t// Top-level parse methods for SLiM input files\n\tEidosASTNode *Parse_SLiMFile(void);\n\tEidosASTNode *Parse_SpeciesSpecifier(void);\n\tEidosASTNode *Parse_TicksSpecifier(void);\n\tEidosASTNode *Parse_SLiMEidosBlock(void);\n\t\n\t// A utility method for extracting the numeric component of an identifier like 'p2', 's3', 'm17', or 'g5'\n\t// This raises if the expected character prefix is not present, or if anything but numeric digits are present, or if the ID is out of range\n\t// The token-based API uses the token for error tracking if an exception is raised; the string-based API just calls EidosTerminate(), and\n\t// thus inherits whatever error-tracking token information might have been previously set.\n\tstatic bool StringIsIDWithPrefix(const std::string &p_identifier_string, char p_prefix_char);\n\tstatic slim_objectid_t ExtractIDFromStringWithPrefix(const std::string &p_identifier_string, char p_prefix_char, const EidosToken *p_blame_token);\n\t\n\t// Returns a string of the form \"p1\", \"g7\", \"m17\", etc., from the type character and object identifier\n\tstatic inline std::string IDStringWithPrefix(char p_type_char, slim_objectid_t p_object_id)\n\t{\n\t\tstd::ostringstream idstring_stream;\n\t\t\n\t\tidstring_stream << p_type_char << p_object_id;\n\t\t\n\t\treturn idstring_stream.str();\n\t}\n};\n\n\n#pragma mark -\n#pragma mark SLiMEidosBlock\n#pragma mark -\n\nextern EidosClass *gSLiM_SLiMEidosBlock_Class;\n\n\nclass SLiMEidosBlock : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t// \"self\" : for fast setup of the symbol table\n\tEidosSymbolTableEntry script_block_symbol_;\t\t\t// \"sX\" : for fast setup of the symbol table\n\t\npublic:\n\t\n\tSLiMEidosBlockType type_ = SLiMEidosBlockType::SLiMEidosNoBlockType;\t// SLiM 4: this no longer defaults to early()\n\t\n\tslim_objectid_t block_id_ = -1;\t\t\t\t\t\t\t\t// the id of the block; -1 if no id was assigned (anonymous block)\n\tEidosValue_SP cached_value_block_id_;\t\t\t\t\t\t// a cached value for block_id_; reset() if that changes\n\t\n\t// BCH 3/6/2024: For deferred tick range evaluation, we now need to keep track of the tick range nodes in our AST.\n\t// These can represent <vector-expr>, <singleton-expr>:, :<singleton-expr>, or <singleton-expr>:<singleton-expr>,\n\t// or no tick range at all (all nullptr).  These are used at eval time; see EvaluateScriptBlockTickRanges(), which\n\t// uses these nodes to produce the tick range information below.  We do not use Robin Hood Hashing for tick_set_\n\t// because I'm concerned about the possibility of a long, regular sequence of values triggering the hash collision\n\t// case in it; better to take a small performance hit and be assured of total reliability, in this case.\n\tconst EidosASTNode *start_tick_node_ = nullptr;\t\t\t\t// NOT OWNED\n\tconst EidosASTNode *colon_node_ = nullptr;\t\t\t\t\t// NOT OWNED\n\tconst EidosASTNode *end_tick_node_ = nullptr;\t\t\t\t// NOT OWNED\n\t\n\tbool tick_range_evaluated_ = false;\t\t\t\t\t\t\t// if false, the start/end ticks are unknown because the tick range expression has not yet been evaluated\n\tstd::string unevaluated_error_string_;\t\t\t\t\t\t// contains the error message from the error that prevented evaluation, if any\n\tbool tick_range_is_sequence_ = true;\t\t\t\t\t\t// if true, tick_start_ and tick_end_ are used; if false, tick_set_ is used\n\tslim_tick_t tick_start_ = -1;\t\t\t\t\t\t\t\t// the first tick to which the block is limited\n\tslim_tick_t tick_end_ = SLIM_MAX_TICK + 1;\t\t\t\t\t// the last tick to which the block is limited\n\tstd::unordered_set<slim_tick_t> tick_set_;\t\t\t\t\t// a set of ticks to which the block is limited\n\t\n\t// other specifiers that limit when a block executes\n\tSpecies *species_spec_ = nullptr;\t\t\t\t\t\t\t// NOT OWNED: the species to which the block is limited; nullptr if not limited by this\n\tSpecies *ticks_spec_ = nullptr;\t\t\t\t\t\t\t\t// NOT OWNED: the species to which the block is synchronized (only active when that species is active)\n\tslim_objectid_t mutation_type_id_ = -1;\t\t\t\t\t\t// -1 if not limited by this\n\tslim_objectid_t subpopulation_id_ = -1;\t\t\t\t\t\t// -1 if not limited by this\n\tslim_objectid_t interaction_type_id_ = -1;\t\t\t\t\t// -1 if not limited by this\n\tIndividualSex sex_specificity_ = IndividualSex::kUnspecified;\t// IndividualSex::kUnspecified if not limited by this\n\tint64_t chromosome_id_ = -1;\t\t\t\t\t\t\t\t// -1 if not limited by this\n\tstd::string chromosome_symbol_;\t\t\t\t\t\t\t\t// if non-empty, converted into chromosome_id_ after initialize() callbacks\n\t\n\tEidosScript *script_ = nullptr;\t\t\t\t\t\t\t\t// OWNED: nullptr indicates that we are derived from the input file script\n\tconst EidosASTNode *root_node_ = nullptr;\t\t\t\t\t// NOT OWNED: the root node for the whole block, including its tick range and type nodes\n\tconst EidosASTNode *compound_statement_node_ = nullptr;\t\t// NOT OWNED: the node for the compound statement that constitutes the body of the block\n\tconst EidosToken *identifier_token_ = nullptr;\n\t\n\tslim_usertag_t block_active_ = -1;\t\t\t\t\t\t\t// the \"active\" property of the block: 0 if inactive, all other values are active\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t// a user-defined tag value\n\t\n\t// Flags indicating what identifiers this script block uses; identifiers that are not used do not need to be added.\n\tbool contains_wildcard_ = false;\t\t\t// \"apply\", \"sapply\", \"executeLambda\", \"_executeLambda_OUTER\", \"ls\", \"rm\"; all other contains_ flags will be T if this is T\n\tbool contains_self_ = false;\t\t\t\t// \"self\"\n\tbool contains_mut_ = false;\t\t\t\t\t// \"mut\" (mutationEffect/mutation callback parameter)\n\tbool contains_effect_ = false;\t\t\t\t// \"effect\" (mutationEffect callback parameter)\n\tbool contains_individual_ = false;\t\t\t// \"individual\" (fitnessEffect/mutationEffect/mateChoice/recombination/survival/reproduction callback parameter)\n\tbool contains_element_ = false;\t\t\t\t// \"element\" (mutation callback parameter)\n\tbool contains_haplosome_ = false;\t\t\t// \"haplosome\" (mutation callback parameter)\n\tbool contains_haplosome1_ = false;\t\t\t// \"haplosome1\" (recombination callback parameter)\n\tbool contains_haplosome2_ = false;\t\t\t// \"haplosome2\" (recombination callback parameter)\n\tbool contains_subpop_ = false;\t\t\t\t// \"subpop\" (fitnessEffect/mutationEffect/interaction/mateChoice/modifyChild/recombination/survival/reproduction/mutation callback parameter)\n\tbool contains_homozygous_ = false;\t\t\t// \"homozygous\" (mutationEffect callback parameter)\n\tbool contains_sourceSubpop_ = false;\t\t// \"sourceSubpop\" (mateChoice/modifyChild callback parameter)\n\tbool contains_weights_ = false;\t\t\t\t// \"weights\" (mateChoice callback parameter)\n\tbool contains_child_ = false;\t\t\t\t// \"child\" (modifyChild callback parameter)\n\tbool contains_parent_ = false;\t\t\t\t// \"parent\" (mutation callback parameter)\n\tbool contains_parent1_ = false;\t\t\t\t// \"parent1\" (modifyChild callback parameter)\n\tbool contains_isCloning_ = false;\t\t\t// \"isCloning\" (modifyChild callback parameter)\n\tbool contains_isSelfing_ = false;\t\t\t// \"isSelfing\" (modifyChild callback parameter)\n\tbool contains_parent2_ = false;\t\t\t\t// \"parent2\" (modifyChild callback parameter)\n\tbool contains_breakpoints_ = false;\t\t\t// \"breakpoints\" (recombination callback parameter)\n\tbool contains_distance_ = false;\t\t\t// \"distance\" (interaction callback parameter)\n\tbool contains_strength_ = false;\t\t\t// \"strength\" (interaction callback parameter)\n\tbool contains_receiver_ = false;\t\t\t// \"receiver\" (interaction callback parameter)\n\tbool contains_exerter_ = false;\t\t\t\t// \"exerter\" (interaction callback parameter)\n\tbool contains_originalNuc_ = false;\t\t\t// \"originalNuc\" (mutation callback parameter)\n\tbool contains_surviving_ = false;\t\t\t// \"surviving\" (survival callback parameter)\n\tbool contains_fitness_ = false;\t\t\t\t// \"fitness\" (survival callback parameter)\n\tbool contains_draw_ = false;\t\t\t\t// \"draw\" (survival callback parameter)\n\t\n\t// Special-case optimizations for particular common callback types.  If a callback can be substituted by C++ code,\n\t// has_cached_optimization_ will be true and the flags and values below will indicate exactly how to do so.\n\tbool has_cached_optimization_ = false;\n\tbool has_cached_opt_dnorm1_ = false;\n\tbool has_cached_opt_reciprocal = false;\n\tdouble cached_opt_A_ = 0.0;\n\tdouble cached_opt_B_ = 0.0;\n\tdouble cached_opt_C_ = 0.0;\n\tdouble cached_opt_D_ = 0.0;\n\t\n\t\n\tstatic SLiMEidosBlockType BlockTypeForRootNode(EidosASTNode *p_root_node);\t\t// get the block type for a node without actually constructing the block\n\t\n\tSLiMEidosBlock(const SLiMEidosBlock&) = delete;\t\t\t\t\t// no copying\n\tSLiMEidosBlock& operator=(const SLiMEidosBlock&) = delete;\t\t// no copying\n\tSLiMEidosBlock(void) = delete;\t\t\t\t\t\t\t\t\t// no default constructor\n\t\n\texplicit SLiMEidosBlock(EidosASTNode *p_root_node);\t\t\t\t// initialize from a SLiMEidosBlock root node from the input file; species gets set later\n\tSLiMEidosBlock(slim_objectid_t p_id, const std::string &p_script_string, SLiMEidosBlockType p_type, slim_tick_t p_start, slim_tick_t p_end, Species *p_species_spec, Species *p_ticks_spec);\t\t// initialize from a programmatic script\n\t~SLiMEidosBlock(void);\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\t// Tokenize and parse the script.  This should be called immediately after construction.  Raises on script errors.\n\tvoid TokenizeAndParse(void);\n\t\n\t// Scan the tree for optimization purposes, called by the constructors\n\tvoid _ScanNodeForIdentifiersUsed(const EidosASTNode *p_scan_node);\n\tvoid ScanTreeForIdentifiersUsed(void);\n\t\n\tvoid PrintDeclaration(std::ostream& p_out, Community *p_community);\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SelfSymbolTableEntry(void) { return self_symbol_; };\n\tEidosSymbolTableEntry &ScriptBlockSymbolTableEntry(void) { if (block_id_ != -1) return script_block_symbol_; else EIDOS_TERMINATION << \"ERROR (SLiMEidosBlock::ScriptBlockSymbolTableEntry): (internal error) no symbol table entry.\" << EidosTerminate(); };\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n};\n\nclass SLiMEidosBlock_Class : public EidosClass\n{\nprivate:\n\ttypedef EidosClass super;\n\npublic:\n\tSLiMEidosBlock_Class(const SLiMEidosBlock_Class &p_original) = delete;\t// no copy-construct\n\tSLiMEidosBlock_Class& operator=(const SLiMEidosBlock_Class&) = delete;\t// no copying\n\tinline SLiMEidosBlock_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n};\n\n\n#pragma mark -\n#pragma mark SLiMTypeTable\n#pragma mark -\n\nclass SLiMTypeTable : public EidosTypeTable\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosTypeTable super;\n\npublic:\n\t\n\tSLiMTypeTable(const SLiMTypeTable&) = delete;\t\t\t\t\t\t\t\t\t\t// no copying\n\tSLiMTypeTable& operator=(const SLiMTypeTable&) = delete;\t\t\t\t\t\t\t// no copying\n\texplicit SLiMTypeTable(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// standard constructor\n\tvirtual ~SLiMTypeTable(void) override;\n\t\n\t// Test for containing a value for a symbol\n\tvirtual bool ContainsSymbol(EidosGlobalStringID p_symbol_name) const override;\n\t\n\t// Get the type for a symbol\n\tvirtual EidosTypeSpecifier GetTypeForSymbol(EidosGlobalStringID p_symbol_name) const override;\n};\n\n\n#pragma mark -\n#pragma mark SLiMTypeInterpreter\n#pragma mark -\n\nclass SLiMTypeInterpreter : public EidosTypeInterpreter\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosTypeInterpreter super;\n\npublic:\n\t\n\tSLiMTypeInterpreter(const SLiMTypeInterpreter&) = delete;\t\t\t\t\t// no copying\n\tSLiMTypeInterpreter& operator=(const SLiMTypeInterpreter&) = delete;\t\t// no copying\n\tSLiMTypeInterpreter(void) = delete;\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\t\n\tSLiMTypeInterpreter(const EidosScript &p_script, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types);\t\t\t// we use the passed symbol table but do not own it\n\tSLiMTypeInterpreter(const EidosASTNode *p_root_node_, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types);\t\t// we use the passed symbol table but do not own it\n\t\n\tvirtual ~SLiMTypeInterpreter(void) override;\n\t\n\tvoid _SetTypeForISArgumentOfClass(const EidosASTNode *p_arg_node, char p_symbol_prefix, const EidosClass *p_type_class);\n\t\n\tvirtual EidosTypeSpecifier _TypeEvaluate_FunctionCall_Internal(std::string const &p_function_name, const EidosFunctionSignature *p_function_signature, const std::vector<EidosASTNode *> &p_arguments) override;\n\t\n\tvirtual EidosTypeSpecifier _TypeEvaluate_MethodCall_Internal(const EidosClass *p_target, const EidosMethodSignature *p_method_signature, const std::vector<EidosASTNode *> &p_arguments) override;\n};\n\n\n#endif /* defined(__SLiM__slim_script_block__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_functions.cpp",
    "content": "//\n//  slim_functions.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 2/15/19.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_functions.h\"\n#include \"slim_globals.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"subpopulation.h\"\n#include \"haplosome.h\"\n#include \"mutation.h\"\n#include \"mutation_type.h\"\n#include \"individual.h\"\n#include \"eidos_rng.h\"\n#include \"json.hpp\"\n\n#include <string>\n#include <vector>\n#include <limits>\n#include <algorithm>\n\n\nextern const char *gSLiMSourceCode_calcDxy;\nextern const char *gSLiMSourceCode_calcFST;\nextern const char *gSLiMSourceCode_calcVA;\nextern const char *gSLiMSourceCode_calcLD_D;\nextern const char *gSLiMSourceCode_calcLD_Rsquared;\nextern const char *gSLiMSourceCode_calcMeanFroh;\nextern const char *gSLiMSourceCode_calcPairHeterozygosity;\nextern const char *gSLiMSourceCode_calcHeterozygosity;\nextern const char *gSLiMSourceCode_calcWattersonsTheta;\nextern const char *gSLiMSourceCode_calcInbreedingLoad;\nextern const char *gSLiMSourceCode_calcPi;\nextern const char *gSLiMSourceCode_calcSFS;\nextern const char *gSLiMSourceCode_calcTajimasD;\n\nextern const char *gSLiMSourceCode_initializeMutationRateFromFile;\nextern const char *gSLiMSourceCode_initializeRecombinationRateFromFile;\n\n\nconst std::vector<EidosFunctionSignature_CSP> *Community::SLiMFunctionSignatures(void)\n{\n\t// Allocate our own EidosFunctionSignature objects\n\tstatic std::vector<EidosFunctionSignature_CSP> sim_func_signatures_;\n\t\n\tif (!sim_func_signatures_.size())\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Community::SLiMFunctionSignatures(): not warmed up\");\n\t\t\n\t\t// Nucleotide utilities\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"codonsToAminoAcids\", SLiM_ExecuteFunction_codonsToAminoAcids, kEidosValueMaskString | kEidosValueMaskInt, \"SLiM\"))->AddInt(\"codons\")->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"long\", nullptr, gStaticEidosValue_LogicalF)->AddLogical_OS(\"paste\", gStaticEidosValue_LogicalT));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"codonsToNucleotides\", SLiM_ExecuteFunction_codonsToNucleotides, kEidosValueMaskInt | kEidosValueMaskString, \"SLiM\"))->AddInt(\"codons\")->AddString_OS(\"format\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"string\"))));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"mm16To256\", SLiM_ExecuteFunction_mm16To256, kEidosValueMaskFloat, \"SLiM\"))->AddFloat(\"mutationMatrix16\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"mmJukesCantor\", SLiM_ExecuteFunction_mmJukesCantor, kEidosValueMaskFloat, \"SLiM\"))->AddFloat_S(\"alpha\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"mmKimura\", SLiM_ExecuteFunction_mmKimura, kEidosValueMaskFloat, \"SLiM\"))->AddFloat_S(\"alpha\")->AddFloat_S(\"beta\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"nucleotideCounts\", SLiM_ExecuteFunction_nucleotideCounts, kEidosValueMaskInt, \"SLiM\"))->AddIntString(\"sequence\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"nucleotideFrequencies\", SLiM_ExecuteFunction_nucleotideFrequencies, kEidosValueMaskFloat, \"SLiM\"))->AddIntString(\"sequence\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"nucleotidesToCodons\", SLiM_ExecuteFunction_nucleotidesToCodons, kEidosValueMaskInt, \"SLiM\"))->AddIntString(\"sequence\"));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"randomNucleotides\", SLiM_ExecuteFunction_randomNucleotides, kEidosValueMaskInt | kEidosValueMaskString, \"SLiM\"))->AddInt_S(\"length\")->AddNumeric_ON(\"basis\", gStaticEidosValueNULL)->AddString_OS(\"format\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"string\"))));\n\t\t\n\t\t// Population genetics utilities (implemented with Eidos code)\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcDxy\", gSLiMSourceCode_calcDxy, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes1\", gSLiM_Haplosome_Class)->AddObject(\"haplosomes2\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddLogical_OS(\"normalize\", gStaticEidosValue_LogicalF));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcFST\", gSLiMSourceCode_calcFST, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes1\", gSLiM_Haplosome_Class)->AddObject(\"haplosomes2\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcVA\", gSLiMSourceCode_calcVA, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcLD_D\", gSLiMSourceCode_calcLD_D, kEidosValueMaskFloat, \"SLiM\"))->AddObject_S(\"mut1\", gSLiM_Mutation_Class)->AddObject_ON(\"mut2\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddObject_ON(\"haplosomes\", gSLiM_Haplosome_Class, gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcLD_Rsquared\", gSLiMSourceCode_calcLD_Rsquared, kEidosValueMaskFloat, \"SLiM\"))->AddObject_S(\"mut1\", gSLiM_Mutation_Class)->AddObject_ON(\"mut2\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddObject_ON(\"haplosomes\", gSLiM_Haplosome_Class, gStaticEidosValueNULL)->AddLogical_OS(\"squared\", gStaticEidosValue_LogicalT));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcMeanFroh\", gSLiMSourceCode_calcMeanFroh, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddInt_OS(\"minimumLength\", EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(1000000)))->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcPairHeterozygosity\", gSLiMSourceCode_calcPairHeterozygosity, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject_S(\"haplosome1\", gSLiM_Haplosome_Class)->AddObject_S(\"haplosome2\", gSLiM_Haplosome_Class)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL)->AddLogical_OS(\"infiniteSites\", gStaticEidosValue_LogicalT));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcHeterozygosity\", gSLiMSourceCode_calcHeterozygosity, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcWattersonsTheta\", gSLiMSourceCode_calcWattersonsTheta, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcInbreedingLoad\", gSLiMSourceCode_calcInbreedingLoad, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes\", gSLiM_Haplosome_Class)->AddIntObject_OSN(\"mutType\", gSLiM_MutationType_Class, gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcPi\", gSLiMSourceCode_calcPi, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcSFS\", gSLiMSourceCode_calcSFS, kEidosValueMaskNumeric, \"SLiM\"))->AddInt_OSN(\"binCount\", gStaticEidosValueNULL)->AddObject_ON(\"haplosomes\", gSLiM_Haplosome_Class, gStaticEidosValueNULL)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddString_OS(\"metric\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"density\")))->AddLogical_OS(\"fold\", gStaticEidosValue_LogicalF));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"calcTajimasD\", gSLiMSourceCode_calcTajimasD, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\"))->AddObject(\"haplosomes\", gSLiM_Haplosome_Class)->AddObject_ON(\"muts\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\t\n\t\t// Other built-in SLiM functions\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"summarizeIndividuals\", SLiM_ExecuteFunction_summarizeIndividuals, kEidosValueMaskFloat, \"SLiM\"))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddInt(\"dim\")->AddNumeric(\"spatialBounds\")->AddString_S(\"operation\")->AddLogicalEquiv_OSN(\"empty\", gStaticEidosValue_Float0)->AddLogical_OS(\"perUnitArea\", gStaticEidosValue_LogicalF)->AddString_OSN(\"spatiality\", gStaticEidosValueNULL));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"treeSeqMetadata\", SLiM_ExecuteFunction_treeSeqMetadata, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class, \"SLiM\"))->AddString_S(\"filePath\")->AddLogical_OS(\"userData\", gStaticEidosValue_LogicalT));\n\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"initializeMutationRateFromFile\", gSLiMSourceCode_initializeMutationRateFromFile, kEidosValueMaskVOID, \"SLiM\"))->AddString_S(\"path\")->AddInt_S(\"lastPosition\")->AddFloat_OS(\"scale\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-8)))->AddString_OS(\"sep\", gStaticEidosValue_StringTab)->AddString_OS(\"dec\", gStaticEidosValue_StringPeriod)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"initializeRecombinationRateFromFile\", gSLiMSourceCode_initializeRecombinationRateFromFile, kEidosValueMaskVOID, \"SLiM\"))->AddString_S(\"path\")->AddInt_S(\"lastPosition\")->AddFloat_OS(\"scale\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-8)))->AddString_OS(\"sep\", gStaticEidosValue_StringTab)->AddString_OS(\"dec\", gStaticEidosValue_StringPeriod)->AddString_OS(\"sex\", gStaticEidosValue_StringAsterisk));\n\t\t\n\t\t// Internal SLiM functions\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"_startBenchmark\", SLiM_ExecuteFunction__startBenchmark, kEidosValueMaskVOID, \"SLiM\"))->AddString_S(gEidosStr_type));\n\t\tsim_func_signatures_.emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"_stopBenchmark\", SLiM_ExecuteFunction__stopBenchmark, kEidosValueMaskFloat | kEidosValueMaskSingleton, \"SLiM\")));\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tobject instantiation – add in constructors for SLiM classes that have them\n\t\t//\tsee also EidosInterpreter::BuiltInFunctions(), which this extends\n\t\t//\n\t\tconst std::vector<EidosFunctionSignature_CSP> *class_functions = gSLiM_SpatialMap_Class->Functions();\n\t\t\n\t\tsim_func_signatures_.insert(sim_func_signatures_.end(), class_functions->begin(), class_functions->end());\n\t}\n\t\n\treturn &sim_func_signatures_;\n}\n\n\n// ************************************************************************************\n//\n//\tpopulation genetics utilities\n//\n#pragma mark -\n#pragma mark Population genetics utilities\n#pragma mark -\n\n// These are implemented in Eidos, for transparency/modifiability.  These strings are globals mostly so the\n// formatting of the code looks nice in Xcode; they are used only by Community::SLiMFunctionSignatures().\n\n#pragma mark (float$)calcDxy(object<Haplosome> haplosomes1, object<Haplosome> haplosomes2, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL], [logical$ normalize = F])\nconst char *gSLiMSourceCode_calcDxy = \nR\"V0G0N({\n\tn1 = haplosomes1.length();\n\tn2 = haplosomes2.length();\n\tif (n1 == 0 | n2 == 0)\n\t\tstop(\"ERROR (calcDxy): haplosomes1 and haplosomes2 must both be non-empty.\");\n\t\n\tspecies = haplosomes1[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(c(haplosomes1, haplosomes2).individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcDxy): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcDxy): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes1[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(c(haplosomes1, haplosomes2).chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcDxy): all haplosomes must be associated with the same chromosome.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcDxy): all mutations must be associated with the same chromosome as the haplosomes.\");\n\t}\n\tlength = chromosome.length;\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcDxy): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcDxy): start and end must be within the bounds of the focal chromosome\");\n\t\tlength = end - start + 1;\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t}\n\telse if (isNULL(start) & isNULL(end))\n\t{\n\t\tstart = 0;\n\t\tend = chromosome.lastPosition;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcDxy): start and end must both be NULL or both be non-NULL.\");\n\t}\n\t\n\t// narrow down to mutations actually present in the haplosomes and not fixed\n\tp = c(haplosomes1, haplosomes2).mutationFrequenciesInHaplosomes(muts);\n\tmuts = muts[(p != 0.0) & (p != 1.0)];\n\tif (size(muts) == 0) // if there are no mutations segregating, Dxy = 0\n\t\treturn 0.0;\n\t\n\t// get the count of each mutation in the two sets of haplosomes\n\tdos1 = haplosomes1.mutationCountsInHaplosomes(muts);\n\tdos2 = haplosomes2.mutationCountsInHaplosomes(muts);\n\t\n\t// calculate counts for the \"empty\" positions (they are alleles too, even\n\t// though they don't have mutation objects in SLiM); note the implementation\n\t// assumes \"infinite sites\" by assuming that a given site contains only a\n\t// single SLiM mutation; if multiple SLiM mutations were present, the empty\n\t// count would need to account for all of them, but that is hard to do\n\tdos1_empty = size(haplosomes1) - dos1;\n\tdos2_empty = size(haplosomes2) - dos2;\n\t\n\tdos1 = c(dos1, dos1_empty);\n\tdos2 = c(dos2, dos2_empty);\n\t\n\t// \"presence of A in haplosomes1\" times \"absence of A in haplosomes2\" +\n\t//    \"presence of A in haplosomes2\" times \"absence of A in haplosomes1\"\n\tdiffs_per_site = dos1 * (n2 - dos2) + (n1 - dos1) * dos2;\n\tdiff = sum(diffs_per_site);\n\t\n\t// this estimates Dxy as defined by Nei, without normalization by length\n\tdxy = diff / 2.0 / n1 / n2;\n\t\n\tif (normalize)\n\t\treturn dxy / length;\n\telse\n\t\treturn dxy;\n})V0G0N\";\n\n#pragma mark (float$)calcFST(object<Haplosome> haplosomes1, object<Haplosome> haplosomes2, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\nconst char *gSLiMSourceCode_calcFST = \nR\"V0G0N({\n\tif ((haplosomes1.length() == 0) | (haplosomes2.length() == 0))\n\t\tstop(\"ERROR (calcFST): haplosomes1 and haplosomes2 must both be non-empty.\");\n\t\n\tspecies = haplosomes1[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(c(haplosomes1, haplosomes2).individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcFST): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcFST): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosomes = haplosomes1[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tchromosomes = sortBy(unique(haplosomes1.chromosome, preserveOrder=F), \"id\");\n\t\tchromosomes2 = sortBy(unique(haplosomes2.chromosome, preserveOrder=F), \"id\");\n\t\tif (!identical(chromosomes, chromosomes2))\n\t\t\tstop(\"ERROR (calcFST): both haplosomes must be associated with the same set of chromosomes.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(match(unique(muts.chromosome), chromosomes) == -1))\n\t\t\t\tstop(\"ERROR (calcFST): all mutations must be associated with the same chromosomes as the haplosomes.\");\n\t}\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosomes);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (chromosomes.length() > 1)\n\t\t\tstop(\"ERROR (calcFST): start/end cannot be specified with more than one chromosome.\");\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcFST): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= chromosomes.length))\n\t\t\tstop(\"ERROR (calcFST): start and end must be within the bounds of the focal chromosome\");\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcFST): start and end must both be NULL or both be non-NULL.\");\n\t}\n\t\n\t// do the calculation; if the FST is undefined, return NULL\n\tp1_p = haplosomes1.mutationFrequenciesInHaplosomes(muts);\n\tp2_p = haplosomes2.mutationFrequenciesInHaplosomes(muts);\n\tmean_p = (p1_p + p2_p) / 2.0;\n\tH_t = 2.0 * mean_p * (1.0 - mean_p);\n\tH_s = p1_p * (1.0 - p1_p) + p2_p * (1.0 - p2_p);\n\tmean_H_t = mean(H_t);\n\t\n\tif (isNULL(mean_H_t))\t// occurs if muts is zero-length\n\t\treturn NAN;\n\tif (mean_H_t == 0)\t\t// occurs if muts is not zero-length but all frequencies are zero\n\t\treturn NAN;\n\t\n\tfst = 1.0 - mean(H_s) / mean_H_t;\n\treturn fst;\n})V0G0N\";\n\n#pragma mark (float$)calcVA(object<Individual> individuals, io<MutationType>$ mutType)\nconst char *gSLiMSourceCode_calcVA = \nR\"V0G0N({\n\tif (individuals.length() < 2)\n\t\tstop(\"ERROR (calcVA): individuals must contain at least two elements.\");\n\t\n\t// look up an integer mutation type id from the community\n\tif (type(mutType) == \"integer\") {\n\t\tmutTypes = community.allMutationTypes;\n\t\tmutTypeForID = mutTypes[mutTypes.id == mutType];\n\t\tassert(length(mutTypeForID) == 1, \"calcVA() did not find a mutation type with id \" + mutType);\n\t\tmutType = mutTypeForID;\n\t}\n\t\n\t// the mutation type dictates the focal species\n\tspecies = mutType.species;\n\t\n\t// all individuals must belong to the focal species\n\tif (community.allSpecies.length() > 1)\n\t\tif (!all(individuals.subpopulation.species == species))\n\t\t\tstop(\"ERROR (calcVA): all individuals must belong to the same species as mutType.\");\n\t\n\treturn var(individuals.sumOfMutationsOfType(mutType));\n})V0G0N\";\n\n#pragma mark (float)calcLD_D(object<Mutation>$ mut1, [No<Mutation> mut2 = NULL], [No<Haplosome> haplosomes = NULL])\nconst char *gSLiMSourceCode_calcLD_D = \nR\"V0G0N({\n\t// check species\n\tspecies = mut1.mutationType.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (!isNULL(haplosomes))\n\t\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\t\tstop(\"ERROR (calcLD_D): all haplosomes must belong to the same species as mut1.\");\n\t\tif (!isNULL(mut2))\n\t\t\tif (any(mut2.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcLD_D): all mutations must belong to the same species as mut1.\");\n\t}\n\t\n\t// check chromosome\n\tchromosome = mut1.chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (!isNULL(haplosomes))\n\t\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcLD_D): all haplosomes must belong to the same chromosome as mut1.\");\n\t\tif (!isNULL(mut2))\n\t\t\tif (any(mut2.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcLD_D): all mutations must belong to the same chromosome as mut1.\");\n\t}\n\t\n\t// if mut2 is NULL, calculate across all mutations for the chromosome\n\tif (isNULL(mut2))\n\t\tmut2 = species.subsetMutations(chromosome=chromosome);\t// includes mut1\n\t\n\t// if haplosomes is NULL, calculate across all haplosomes for the chromosome\n\tif (isNULL(haplosomes))\n\t\thaplosomes = species.subpopulations.haplosomesForChromosomes(chromosome);\n\t\n\tif (size(haplosomes) == 0)\n\t\tstop(\"ERROR (calcLD_D): haplosomes must be non-empty.\");\n\t\n\t// get haplosomes that contain the first mutation\n\thaplosomes1 = haplosomes[haplosomes.containsMutations(mut1)];\n\t\n\tif (size(haplosomes1) == 0)\n\t\treturn rep(0.0, size(mut2)); // D=0 if either mutation is not present\n\t\n\t// calculate the frequency of haplosomes that contain both mutations\n\tp_12 = haplosomes1.mutationCountsInHaplosomes(mut2) / size(haplosomes);\n\t\n\t// calculate the frequency of each mutation across haplosomes\n\tp_1 = size(haplosomes1) / size(haplosomes);\n\tp_2 = haplosomes.mutationFrequenciesInHaplosomes(mut2);\n\treturn p_12 - p_1 * p_2;\n})V0G0N\";\n\n#pragma mark (float)calcLD_Rsquared(object<Mutation>$ mut1, [No<Mutation> mut2 = NULL], [No<Haplosome> haplosomes = NULL], [logical$ squared = T])\nconst char *gSLiMSourceCode_calcLD_Rsquared = \nR\"V0G0N({\n\t// check species\n\tspecies = mut1.mutationType.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (!isNULL(haplosomes))\n\t\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\t\tstop(\"ERROR (calcLD_Rsquared): all haplosomes must belong to the same species as mut1.\");\n\t\tif (!isNULL(mut2))\n\t\t\tif (any(mut2.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcLD_Rsquared): all mutations must belong to the same species as mut1.\");\n\t}\n\t\n\t// check chromosome\n\tchromosome = mut1.chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (!isNULL(haplosomes))\n\t\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcLD_Rsquared): all haplosomes must belong to the same chromosome as mut1.\");\n\t\tif (!isNULL(mut2))\n\t\t\tif (any(mut2.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcLD_Rsquared): all mutations must belong to the same chromosome as mut1.\");\n\t}\n\t\n\t// if mut2 is NULL, calculate across all mutations for the chromosome\n\tif (isNULL(mut2))\n\t\tmut2 = species.subsetMutations(chromosome=chromosome);\t// includes mut1\n\t\n\t// if haplosomes is NULL, calculate across all haplosomes for the chromosome\n\tif (isNULL(haplosomes))\n\t\thaplosomes = species.subpopulations.haplosomesForChromosomes(chromosome);\n\t\n\tif (size(haplosomes) == 0)\n\t\tstop(\"ERROR (calcLD_Rsquared): haplosomes must be non-empty.\");\n\t\n\t// get haplosomes that contain the first mutation\n\thaplosomes1 = haplosomes[haplosomes.containsMutations(mut1)];\n\t\n\tif (size(haplosomes1) == 0)\n\t\treturn rep(NAN, size(mut2)); // r^2 doesn't exist if either mutation is absent (0/0)\n\t\n\t// calculate the frequency of haplosomes that contain both mutations\n\tp_12 = haplosomes1.mutationCountsInHaplosomes(mut2) / size(haplosomes);\n\t\n\t// calculate the frequency of each mutation across haplosomes\n\tp_1 = size(haplosomes1) / size(haplosomes);\n\tp_2 = haplosomes.mutationFrequenciesInHaplosomes(mut2);\n\t\n\t// squared=T returns r^2 between 0 and 1\n\t// squared=F returns r between -1 and 1\n\tif (squared)\n\t\treturn (p_12 - p_1 * p_2)^2 / (p_1 * p_2 * (1.0 - p_1) * (1.0 - p_2));\n\telse\n\t\treturn (p_12 - p_1 * p_2) / sqrt(p_1 * p_2 * (1.0 - p_1) * (1.0 - p_2));\n})V0G0N\";\n\n#pragma mark (float$)calcMeanFroh(object<Individual> individuals, [integer$ minimumLength = 1e6], [Niso<Chromosome>$ chromosome = NULL])\nconst char *gSLiMSourceCode_calcMeanFroh = \nR\"V0G0N({\n\t// With zero individuals, we return NAN; it's good to be flexible on\n\t// this, so models don't error out on local extinction and such.\n\tif (length(individuals) == 0)\n\t\treturn NAN;\n\t\n\tspecies = individuals[0].subpopulation.species;\n\t\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(individuals.subpopulation.species != species))\n\t\tstop(\"ERROR (calcMeanFroh): calcMeanFroh() requires that all individuals belong to a single species.\");\n\t}\n\t\n\tif (minimumLength < 0)\n\t\tstop(\"ERROR (calcMeanFroh): calcMeanFroh() requires minimumLength >= 0 (\" + minimumLength + \" supplied).\");\n\t\n\t// get the chromosomes we will operate over\n\tif (isNULL(chromosome))\n\t{\n\t\tchromosomes = species.chromosomes;\n\t\tchromosomes = chromosomes[chromosomes.intrinsicPloidy == 2];\n\t}\n\telse\n\t{\n\t\tif (type(chromosome) == \"integer\")\n\t\t\tchromosome = species.chromosomesWithIDs(chromosome);\n\t\telse if (type(chromosome) == \"string\")\n\t\t\tchromosome = species.chromosomesWithSymbols(chromosome);\n\t\t\n\t\tif (chromosome.species != species)\n\t\t\tstop(\"ERROR (calcMeanFroh): calcMeanFroh() requires that chromosome belong to the same species as individual.\");\n\t\tif (chromosome.intrinsicPloidy != 2)\n\t\t\tstop(\"ERROR (calcMeanFroh): calcMeanFroh() requires that chromosome have intrinsic ploidy 2.\");\n\t\t\n\t\tchromosomes = chromosome;\n\t}\n\t\n\tif (chromosomes.length() == 0)\n\t\tstop(\"ERROR (calcMeanFroh): no chromosomes with intrinsic ploidy 2 in calcMeanFroh().\");\n\t\n\t// average over the individuals supplied; some might be skipped over,\n\t// if they have no diploid haplosomes (due to null haplosomes)\n\ttotal_individuals = 0;\n\ttotal_froh = 0;\n\t\n\tfor (individual in individuals)\n\t{\n\t\t// do the calculation\n\t\ttotal_chr_length = 0;\n\t\ttotal_roh_length = 0;\n\t\t\n\t\tfor (chr in chromosomes)\n\t\t{\n\t\t\t// get the haplosomes we will operate over, for the focal chromosome\n\t\t\thaplosomes = individual.haplosomesForChromosomes(chr, includeNulls=F);\n\t\t\t\n\t\t\tif (haplosomes.length() != 2)\n\t\t\t\tnext;\n\t\t\t\n\t\t\t// get the mutations that are heterozygous, for the focal chromosome\n\t\t\thet_pos = individual.mutationsFromHaplosomes(\"heterozygous\", chromosomes=chr).position;\n\t\t\thet_pos_1 = c(-1, het_pos);\n\t\t\thet_pos_2 = c(het_pos, chr.lastPosition + 1);\n\t\t\troh = (het_pos_2 - het_pos_1) - 1;\n\t\t\t\n\t\t\t// filter the ROH we found by the threshold length passed in\n\t\t\tif (minimumLength > 0)\n\t\t\t\troh = roh[roh >= minimumLength];\n\t\t\t\n\t\t\ttotal_roh_length = total_roh_length + sum(roh);\n\t\t\ttotal_chr_length = total_chr_length + chr.length;\n\t\t}\n\t\t\n\t\t// if total_chr_length is zero, the individual has no chromosome for which\n\t\t// it is actually diploid, so we can't calculate F_ROH; we skip it\n\t\tif (total_chr_length == 0)\n\t\t\tnext;\n\t\t\n\t\t// we calculate F_ROH as the total ROH lengths divided by the total length\n\t\t// we add that in to our running total, to average over the individuals\n\t\ttotal_froh = total_froh + (total_roh_length / total_chr_length);\n\t\ttotal_individuals = total_individuals + 1;\n\t}\n\t\n\t// if we got zero individuals that we could actually calculate F_ROH for, we\n\t// return NAN, because it seems like we want to be tolerant of this case;\n\t// the user can handle it as they wish\n\tif (total_individuals == 0)\n\t\treturn NAN;\n\t\n\t// return the average F_ROH across individuals it could be calculated for\n\treturn total_froh / total_individuals;\n})V0G0N\";\n\n#pragma mark (float$)calcPairHeterozygosity(object<Haplosome>$ haplosome1, object<Haplosome>$ haplosome2, [Ni$ start = NULL], [Ni$ end = NULL], [l$ infiniteSites = T])\nconst char *gSLiMSourceCode_calcPairHeterozygosity = \nR\"V0G0N({\n\tspecies = haplosome1.individual.subpopulation.species;\n\tif (haplosome2.individual.subpopulation.species != species)\n\t\tstop(\"ERROR (calcPairHeterozygosity): haplosome1 and haplosome2 must belong to the same species.\");\n\t\n\tchromosome = haplosome1.chromosome;\n\tif (haplosome2.chromosome != chromosome)\n\t\tstop(\"ERROR (calcPairHeterozygosity): haplosome1 and haplosome2 must belong to the same chromosome.\");\n\t\n\tmuts1 = haplosome1.mutations;\n\tmuts2 = haplosome2.mutations;\n\tlength = chromosome.length;\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcPairHeterozygosity): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcPairHeterozygosity): start and end must be within the bounds of the focal chromosome\");\n\t\tm1pos = muts1.position;\n\t\tm2pos = muts2.position;\n\t\tmuts1 = muts1[(m1pos >= start) & (m1pos <= end)];\n\t\tmuts2 = muts2[(m2pos >= start) & (m2pos <= end)];\n\t\tlength = end - start + 1;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcPairHeterozygosity): start and end must both be NULL or both be non-NULL.\");\n\t}\n\t\n\t// do the calculation\n\tunshared = setSymmetricDifference(muts1, muts2);\n\tif (!infiniteSites)\n\t\tunshared = unique(unshared.position, preserveOrder=F);\n\t\n\treturn size(unshared) / length;\n})V0G0N\";\n\n#pragma mark (float$)calcHeterozygosity(o<Haplosome> haplosomes, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\nconst char *gSLiMSourceCode_calcHeterozygosity = \nR\"V0G0N({\n\tif (haplosomes.length() == 0)\n\t\tstop(\"ERROR (calcHeterozygosity): haplosomes must be non-empty.\");\n\t\n\tspecies = haplosomes[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcHeterozygosity): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcHeterozygosity): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcHeterozygosity): all haplosomes must be associated with the same chromosome.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcHeterozygosity): all mutations must be associated with the same chromosome as the haplosomes.\");\n\t}\n\t\n\tlength = chromosome.length;\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcHeterozygosity): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcHeterozygosity): start and end must be within the bounds of the focal chromosome\");\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t\tlength = end - start + 1;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcHeterozygosity): start and end must both be NULL or both be non-NULL.\");\n\t}\n\n\t// do the calculation\n\tp = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\theterozygosity = 2 * sum(p * (1 - p)) / length;\n\treturn heterozygosity;\n})V0G0N\";\n\n#pragma mark (float$)calcWattersonsTheta(o<Haplosome> haplosomes, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\nconst char *gSLiMSourceCode_calcWattersonsTheta = \nR\"V0G0N({\n\tif (haplosomes.length() == 0)\n\t\tstop(\"ERROR (calcWattersonsTheta): haplosomes must be non-empty.\");\n\t\n\tspecies = haplosomes[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcWattersonsTheta): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcWattersonsTheta): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcWattersonsTheta): all haplosomes must be associated with the same chromosome.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcWattersonsTheta): all mutations must be associated with the same chromosome as the haplosomes.\");\n\t}\n\t\n\tlength = chromosome.length;\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcWattersonsTheta): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcWattersonsTheta): start and end must be within the bounds of the focal chromosome\");\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t\tlength = end - start + 1;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcWattersonsTheta): start and end must both be NULL or both be non-NULL.\");\n\t}\n\n\t// narrow down to the mutations that are actually present in the haplosomes and aren't fixed\n\tp = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\tmuts = muts[(p != 0.0) & (p != 1.0)];\n\n\t// do the calculation\n\tk = size(muts);\n\tn = haplosomes.size();\n\ta_n = sum(1 / 1:(n-1));\n\ttheta = (k / a_n) / length;\n\treturn theta;\n})V0G0N\";\n\n#pragma mark (float$)calcInbreedingLoad(object<Haplosome> haplosomes, [Nio<MutationType>$ mutType = NULL])\nconst char *gSLiMSourceCode_calcInbreedingLoad = \nR\"V0G0N({\n\t// look up an integer mutation type id from the community\n\tif (type(mutType) == \"integer\") {\n\t\tmutTypes = community.allMutationTypes;\n\t\tmutTypeForID = mutTypes[mutTypes.id == mutType];\n\t\tassert(length(mutTypeForID) == 1, \"calcInbreedingLoad() did not find a mutation type with id \" + mutType);\n\t\tmutType = mutTypeForID;\n\t}\n\t\n\tif (haplosomes.length() == 0)\n\t\tstop(\"ERROR (calcInbreedingLoad): haplosomes must be non-empty.\");\n\t\n\tspecies = haplosomes[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcInbreedingLoad): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(mutType))\n\t\t\tif (mutType.species != species)\n\t\t\t\tstop(\"ERROR (calcInbreedingLoad): mutType must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcInbreedingLoad): all haplosomes must be associated with the same chromosome.\");\n\t}\n\t\n\t// get the focal mutations and narrow down to those that are deleterious\n\tif (isNULL(mutType))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\telse\n\t\tmuts = species.subsetMutations(mutType=mutType, chromosome=chromosome);\n\t\n\tmuts = muts[muts.selectionCoeff < 0.0];\n\t\n\t// get frequencies and focus on those that are in the haplosomes\n\tq = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\tinHaplosomes = (q > 0);\n\t\n\tmuts = muts[inHaplosomes];\n\tq = q[inHaplosomes];\n\t\n\t// fetch selection coefficients; note that we use the negation of\n\t// SLiM's selection coefficient, following Morton et al. 1956's usage\n\ts = -muts.selectionCoeff;\n\t\n\t// replace s > 1.0 with s == 1.0; a mutation can't be more lethal\n\t// than lethal (this can happen when drawing from a gamma distribution)\n\ts[s > 1.0] = 1.0;\n\t\n\t// get h for each mutation; note that this will not work if changing\n\t// h using mutationEffect() callbacks or other scripted approaches\n\th = muts.mutationType.dominanceCoeff;\n\t\n\t// calculate number of haploid lethal equivalents (B or inbreeding load)\n\t// this equation is from Morton et al. 1956\n\treturn (sum(q*s) - sum(q^2*s) - 2*sum(q*(1-q)*s*h));\n})V0G0N\";\n\n#pragma mark (float$)calcPi(object<Haplosome> haplosomes, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\nconst char *gSLiMSourceCode_calcPi = \nR\"V0G0N({\n\tif (haplosomes.length() < 2)\n\t\tstop(\"ERROR (calcPi): haplosomes must contain at least two elements.\");\n\t\n\tspecies = haplosomes[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcPi): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcPi): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcPi): all haplosomes must be associated with the same chromosome.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcPi): all mutations must be associated with the same chromosome as the haplosomes.\");\n\t}\n\t\n\tlength = chromosome.length;\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcPi): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcPi): start and end must be within the bounds of the focal chromosome\");\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t\tlength = end - start + 1;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcPi): start and end must both be NULL or both be non-NULL.\");\n\t}\n\t\n\t// narrow down to the mutations that are actually present in the haplosomes and aren't fixed\n\tp = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\tmuts = muts[(p != 0.0) & (p != 1.0)];\n\t\n\t// do the calculation\n\t// obtain counts of variant sequences for all segregating sites\n\tvarCount = haplosomes.mutationCountsInHaplosomes(muts);\n\t// total count of sequences minus count of variant sequences equals count of invariant sequences\n\tinvarCount = haplosomes.size() - varCount;\n\t// count of pairwise differences per site is the product of counts of both alleles\n\t// (equation 1 in Korunes and Samuk 2021); this is then summed for all sites \n\tdiffs = sum(varCount * invarCount);\n\t// pi is the ratio of pairwise differences to number of possible combinations of the given sequences\n\tpi = diffs / ((haplosomes.size() * (haplosomes.size() - 1)) / 2);\n\t// pi is conventionally averaged per site (consistent with SLiM's calculation of Watterson's theta)\n\tavg_pi = pi / length;\n\treturn avg_pi;\n})V0G0N\";\n\n#pragma mark (numeric)calcSFS([Ni$ binCount = NULL], [No<Haplosome> haplosomes = NULL], [No<Mutation> muts = NULL], [string$ metric = \"density\"], [logical$ fold = F])\nconst char *gSLiMSourceCode_calcSFS = \nR\"V0G0N({\n\t// first determine the haplosomes and the species\n\tif (isNULL(haplosomes)) {\n\t\tif (community.allSpecies.length() != 1)\n\t\t\tstop(\"ERROR (): calcSFS() can only infer the value of haplosomes in a single-species model; otherwise, you need to supply the specific haplosomes to be used.\");\n\t\t\n\t\tspecies = community.allSpecies;\n\t\thaplosomes = sim.subpopulations.haplosomesNonNull;\n\t}\n\telse\n\t{\n\t\tif (haplosomes.length() == 0)\n\t\t\tstop(\"ERROR (calcSFS): haplosomes must be non-empty.\");\n\t\t\n\t\tspecies = haplosomes[0].individual.subpopulation.species;\n\t\t\n\t\tif (community.allSpecies.length() > 1)\n\t\t{\n\t\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\t\tstop(\"ERROR (calcSFS): all haplosomes must belong to the same species.\");\n\t\t}\n\t\t\n\t\t// exclude null haplosomes silently\n\t\thaplosomes = haplosomes[!haplosomes.isNullHaplosome];\n\t}\n\t\n\t// validate binCount\n\tif (!isNULL(binCount))\n\t\tif ((binCount <= 0) | (binCount > 100000))\n\t\t\t\tstop(\"ERROR (calcSFS): binCount must be in the range [1, 100000], or NULL.\");\n\t\n\t// if no haplosomes are supplied, we don't want to error (we want to work\n\t// even when called on an empty simulation, for ease of use), so we just\n\t// return zeros; note after this point haplosomes is guaranteed non-empty\n\tif (haplosomes.length() == 0)\n\t{\n\t\tif (isNULL(binCount))\n\t\t\t\treturn integer(0);\n\t\treturn float(binCount);\n\t}\n\t\n\t// a NULL binCount means: each haplosome is a sample, and bins should be\n\t// counts, not frequency bins; with N samples, we have bins for the counts\n\t// from 1 to N-1 (here we do 0 to N, we will remove the end bins downstream)\n\t// note for this mode we do require that all haplosomes belong to a single\n\t// chromosome; counts combined across different haplosomes are not valid\n\t// in the general case.\n\tbinsAreSampleCounts = F;\n\tif (isNULL(binCount))\n\t{\n\t\tchromosome = haplosomes[0].chromosome;\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcSFS): when binCount is NULL, all haplosomes must be associated with the same chromosome; counts should be within a single chromosome, since a different number of haplosomes could be present for different chromosomes.\");\n\t\t\n\t\tbinCount = haplosomes.length() + 1;\t\t// 0 to number of haplosomes\n\t\tbinsAreSampleCounts = T;\n\t}\n\t\n\t// apart from the case above, we do not need to require a single chromosome;\n\t// we work with all mutations in the model, even if the haplosomes supplied\n\t// belong to a single chromosome.  this works because mutations that are not\n\t// present in any of the supplied haplosomes will have a frequency of zero\n\t// (or NAN, if the mutation belongs to a different chromosome), and those\n\t// will be filtered out below.\n\tif (isNULL(muts))\n\t{\n\t\tmuts = species.mutations;\n\t}\n\telse\n\t{\n\t\tif (any(muts.chromosome.species != species))\n\t\t\tstop(\"ERROR (calcSFS): all mutations in muts must belong to the same species as the haplosomes; an SFS can be calculated only within a single species.\");\n\t}\n\t\n\tif (!binsAreSampleCounts)\n\t{\n\t\t// get the frequencies; note mutationFrequenciesInHaplosomes() is smart enough\n\t\t// to assess the frequency of each mutation only within the haplosomes that\n\t\t// are associated with the same chromosome as the mutation, so this should do\n\t\t// the right thing even in multichrom models.\n\t\tfreqs = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\t\t\n\t\t// filter out frequencies of zero or NAN; they should not influence the SFS.\n\t\tfreqs = freqs[freqs != 0.0];\n\t\tfreqs = freqs[isFinite(freqs)];\n\t\t\n\t\t// discretize the frequencies into the specified number of bins\n\t\tbins = pmin(asInteger(floor(freqs * binCount)), binCount - 1);\n\t\t\n\t\t// tabulate the number of mutations in each frequency bin to make a histogram\n\t\ttallies = tabulate(bins, maxbin=binCount-1);\n\t}\n\telse\n\t{\n\t\t// this is the \"binCount=NULL\" case, where each bin is an integer count\n\t\t// we handle this separately to avoid possible float numerical error\n\t\tcounts = haplosomes.mutationCountsInHaplosomes(muts);\n\t\t\n\t\t// filter out counts of zero; they should not influence the SFS.\n\t\tcounts = counts[counts != 0.0];\n\t\t\n\t\t// tabulate the number of mutations in each count bin to make a histogram\n\t\ttallies = tabulate(counts, maxbin=binCount-1);\n\t\t\n\t\t// unlike above (frequency bins), with count bins we discard the bottom\n\t\t// and top bins; count bins span [1, N-1]; the top bin might contain fixed\n\t\t// mutations in SLiM, but they are not empirically observable\n\t\tif (binsAreSampleCounts)\n\t\t\ttallies = tallies[1:(length(tallies)-2)];\n\t}\n\t\n\t// \"fold\" the SFS if requested, combining the first and last value, and on\n\t// to the center; this is often done empirically because you don't know\n\t// which allele is ancestral and which is derived.  the tricky thing is\n\t// what to do with the central bin, if there is an odd number of bins; we\n\t// add it to itself, but the central bin could be handled other ways too,\n\t// such as excluding that data point (which the user can do after).\n\tif (fold & (size(tallies) >= 2))\n\t{\n\t\tmidpoint = (length(tallies) - 1) / 2;\n\t\tleftSeq = asInteger(seq(from=0, to=midpoint));\n\t\trightSeq = asInteger(seq(from=length(tallies)-1, to=midpoint));\n\t\ttallies = tallies[leftSeq] + tallies[rightSeq];\n\t}\n\t\n\t// return either counts or densities, as requested; note that you can have\n\t// binsAreSampleCounts be T, and yet return density values, that is legal,\n\t// and just means that you want densities for singletons, doubletons, etc.\n\tif (metric == \"count\")\n\t\treturn tallies;\n\telse if (metric == \"density\")\n\t\treturn tallies / sum(tallies);\n\telse\n\t\tstop(\"ERROR (calcSFS): unrecognized value '\" + metric + \"' for parameter metric.\");\n})V0G0N\";\n\n#pragma mark (float$)calcTajimasD(object<Haplosome> haplosomes, [No<Mutation> muts = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\nconst char *gSLiMSourceCode_calcTajimasD = \nR\"V0G0N({\n\tif (haplosomes.length() < 4)\n\t\tstop(\"ERROR (calcTajimasD): haplosomes must contain at least four elements.\");\n\t\n\tspecies = haplosomes[0].individual.subpopulation.species;\n\tif (community.allSpecies.length() > 1)\n\t{\n\t\tif (any(haplosomes.individual.subpopulation.species != species))\n\t\t\tstop(\"ERROR (calcTajimasD): all haplosomes must belong to the same species.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.mutationType.species != species))\n\t\t\t\tstop(\"ERROR (calcTajimasD): all mutations must belong to the same species as the haplosomes.\");\n\t}\n\t\n\tchromosome = haplosomes[0].chromosome;\n\tif (species.chromosomes.length() > 1)\n\t{\n\t\tif (any(haplosomes.chromosome != chromosome))\n\t\t\tstop(\"ERROR (calcTajimasD): all haplosomes must be associated with the same chromosome.\");\n\t\tif (!isNULL(muts))\n\t\t\tif (any(muts.chromosome != chromosome))\n\t\t\t\tstop(\"ERROR (calcTajimasD): all mutations must be associated with the same chromosome as the haplosomes.\");\n\t}\n\t\n\tlength = chromosome.length;\n\t\n\tif (isNULL(muts))\n\t\tmuts = species.subsetMutations(chromosome=chromosome);\n\t\n\t// handle windowing\n\tif (!isNULL(start) & !isNULL(end))\n\t{\n\t\tif (start > end)\n\t\t\tstop(\"ERROR (calcTajimasD): start must be less than or equal to end.\");\n\t\tif ((start < 0) | (end >= length))\n\t\t\tstop(\"ERROR (calcTajimasD): start and end must be within the bounds of the focal chromosome\");\n\t\tmpos = muts.position;\n\t\tmuts = muts[(mpos >= start) & (mpos <= end)];\n\t\tlength = end - start + 1;\n\t}\n\telse if (!isNULL(start) | !isNULL(end))\n\t{\n\t\tstop(\"ERROR (calcTajimasD): start and end must both be NULL or both be non-NULL.\");\n\t}\n\t\n\t// narrow down to the mutations that are actually present in the haplosomes and aren't fixed\n\tp = haplosomes.mutationFrequenciesInHaplosomes(muts);\n\tmuts = muts[(p != 0.0) & (p != 1.0)];\n\t\n\t// do the calculation\n\t// Pi and Watterson's theta functions divide by sequence length so this must be undone in Tajima's D\n\t// Sequence length is constant (i.e. no missing data or indels) so this can be applied equally over both metrics\n\tdiff = (calcPi(haplosomes, muts, start, end) - calcWattersonsTheta(haplosomes, muts, start, end)) * length;\n\t// calculate standard deviation of covariance of pi and Watterson's theta\n\t// note that first 3 variables defined below are sufficient for Watterson's theta calculation as well,\n\t// although the calcWattersonsTheta() function is used above for proper interval handling and clarity \n\tk = size(muts);\n\tn = haplosomes.size();\n\ta_1 = sum(1 / 1:(n - 1));\n\ta_2 = sum(1 / (1:(n - 1)) ^ 2);\n\tb_1 = (n + 1) / (3 * (n - 1));\n\tb_2 = 2 * (n ^ 2 + n + 3) / (9 * n * (n - 1));\n\tc_1 = b_1 - 1 / a_1;\n\tc_2 = b_2 - (n + 2) / (a_1 * n) + a_2 / a_1 ^ 2;\n\te_1 = c_1 / a_1;\n\te_2 = c_2 / (a_1 ^ 2 + a_2);\n\tcovar = e_1 * k + e_2 * k * (k - 1);\n\tstdev = sqrt(covar);\n\ttajima_d = diff / stdev;\n\treturn tajima_d;\n})V0G0N\";\n\n\n// ************************************************************************************\n//\n//\tother built-in functions\n//\n#pragma mark -\n#pragma mark Other built-in functions\n#pragma mark -\n\n#pragma mark (void)initializeMutationRateFromFile(s$ path, i$ lastPosition, [f$ scale=1e-8], [s$ sep=\"\\t\"], [s$ dec=\".\"], [string$ sex = \"*\"])\nconst char *gSLiMSourceCode_initializeMutationRateFromFile = \nR\"V0G0N({\n\terrbase = \"ERROR (initializeMutationRateFromFile): \";\n\tudf = errbase + \"unexpected data format; the file cannot be read.\";\n\t\n\tif ((scale <= 0.0) | (scale > 1.0))\n\t\tstop(errbase + \"scale must be in (0.0, 1.0].\");\n\tif (!fileExists(path))\n\t\tstop(errbase + \"file not found at path '\" + path + \"'.\");\n\t\n\tmap = readCSV(path, colNames=c(\"ends\", \"rates\"), sep=sep, dec=dec);\n\tif (length(map) == 0)\n\t\tstop(udf);\n\tif (length(map.allKeys) != 2)\n\t\tstop(udf);\n\t\n\tends = map.getValue(\"ends\");\n\trates = map.getValue(\"rates\");\n\tif (!isInteger(ends) | !isFloat(rates) | (length(ends) == 0))\n\t\tstop(udf);\n\t\n\t// We expect the first column to be start positions, not end positions.\n\t// The first value in that column therefore tells us whether the data\n\t// is zero-based or one-based; we require one or the other.  There is\n\t// another -1 applied to the positions because we convert them from\n\t// start positions to end positions; each segment ends at the base\n\t// previous to the start of the next segment.\n\tbase = ends[0];\n\tif ((base != 0) & (base != 1))\n\t\tstop(errbase + \"the first position in the file must be 0 (for 0-based positions) or 1 (for 1-based positions).\");\n\t\n\tif (length(ends) == 1)\n\t\tends = lastPosition;\t\t// only the first start position is present\n\telse\n\t\tends = c(ends[1:(size(ends)-1)] - base - 1, lastPosition);\n\t\n\tinitializeMutationRate(rates * scale, ends, sex);\n})V0G0N\";\n\n#pragma mark (void)initializeRecombinationRateFromFile(s$ path, i$ lastPosition, [f$ scale=1e-8], [s$ sep=\"\\t\"], [s$ dec=\".\"], [string$ sex = \"*\"])\nconst char *gSLiMSourceCode_initializeRecombinationRateFromFile = \nR\"V0G0N({\n\terrbase = \"ERROR (initializeRecombinationRateFromFile): \";\n\tudf = errbase + \"unexpected data format; the file cannot be read.\";\n\t\n\tif ((scale <= 0.0) | (scale > 1.0))\n\t\tstop(errbase + \"scale must be in (0.0, 1.0].\");\n\tif (!fileExists(path))\n\t\tstop(errbase + \"file not found at path '\" + path + \"'.\");\n\t\n\tmap = readCSV(path, colNames=c(\"ends\", \"rates\"), sep=sep, dec=dec);\n\tif (length(map) == 0)\n\t\tstop(udf);\n\tif (length(map.allKeys) != 2)\n\t\tstop(udf);\n\t\n\tends = map.getValue(\"ends\");\n\trates = map.getValue(\"rates\");\n\tif (!isInteger(ends) | !isFloat(rates) | (length(ends) == 0))\n\t\tstop(udf);\n\t\n\t// We expect the first column to be start positions, not end positions.\n\t// The first value in that column therefore tells us whether the data\n\t// is zero-based or one-based; we require one or the other.  Unlike in\n\t// initializeMutationRateFromFile(), there is no shift to translate from\n\t// starts to ends; a start of 8 (beginning a rate to the right of pos 8)\n\t// is the same as an end of 8 (ending the previous rate to the left of\n\t// position 8); in-between positions are confusing.  See #553.\n\tbase = ends[0];\n\tif ((base != 0) & (base != 1))\n\t\tstop(errbase + \"the first position in the file must be 0 (for 0-based positions) or 1 (for 1-based positions).\");\n\t\n\tif (length(ends) == 1)\n\t\tends = lastPosition;\t\t// only the first start position is present\n\telse\n\t\tends = c(ends[1:(size(ends)-1)] - base, lastPosition);\n\t\n\tinitializeRecombinationRate(rates * scale, ends, sex);\n})V0G0N\";\n\n\n// ************************************************************************************\n//\n//\tcodon tables\n//\n#pragma mark -\n#pragma mark Codon tables\n#pragma mark -\n\nstatic std::string codon2aa_short[64] = {\n\t/* AAA */\t\"K\",\n\t/* AAC */\t\"N\",\n\t/* AAG */\t\"K\",\n\t/* AAT */\t\"N\",\n\t/* ACA */\t\"T\",\n\t/* ACC */\t\"T\",\n\t/* ACG */\t\"T\",\n\t/* ACT */\t\"T\",\n\t/* AGA */\t\"R\",\n\t/* AGC */\t\"S\",\n\t/* AGG */\t\"R\",\n\t/* AGT */\t\"S\",\n\t/* ATA */\t\"I\",\n\t/* ATC */\t\"I\",\n\t/* ATG */\t\"M\",\n\t/* ATT */\t\"I\",\n\t/* CAA */\t\"Q\",\n\t/* CAC */\t\"H\",\n\t/* CAG */\t\"Q\",\n\t/* CAT */\t\"H\",\n\t/* CCA */\t\"P\",\n\t/* CCC */\t\"P\",\n\t/* CCG */\t\"P\",\n\t/* CCT */\t\"P\",\n\t/* CGA */\t\"R\",\n\t/* CGC */\t\"R\",\n\t/* CGG */\t\"R\",\n\t/* CGT */\t\"R\",\n\t/* CTA */\t\"L\",\n\t/* CTC */\t\"L\",\n\t/* CTG */\t\"L\",\n\t/* CTT */\t\"L\",\n\t/* GAA */\t\"E\",\n\t/* GAC */\t\"D\",\n\t/* GAG */\t\"E\",\n\t/* GAT */\t\"D\",\n\t/* GCA */\t\"A\",\n\t/* GCC */\t\"A\",\n\t/* GCG */\t\"A\",\n\t/* GCT */\t\"A\",\n\t/* GGA */\t\"G\",\n\t/* GGC */\t\"G\",\n\t/* GGG */\t\"G\",\n\t/* GGT */\t\"G\",\n\t/* GTA */\t\"V\",\n\t/* GTC */\t\"V\",\n\t/* GTG */\t\"V\",\n\t/* GTT */\t\"V\",\n\t/* TAA */\t\"X\",\n\t/* TAC */\t\"Y\",\n\t/* TAG */\t\"X\",\n\t/* TAT */\t\"Y\",\n\t/* TCA */\t\"S\",\n\t/* TCC */\t\"S\",\n\t/* TCG */\t\"S\",\n\t/* TCT */\t\"S\",\n\t/* TGA */\t\"X\",\n\t/* TGC */\t\"C\",\n\t/* TGG */\t\"W\",\n\t/* TGT */\t\"C\",\n\t/* TTA */\t\"L\",\n\t/* TTC */\t\"F\",\n\t/* TTG */\t\"L\",\n\t/* TTT */\t\"F\"\n};\n\nstatic std::string codon2aa_long[64] = {\n\t/* AAA */\t\"Lys\",\n\t/* AAC */\t\"Asn\",\n\t/* AAG */\t\"Lys\",\n\t/* AAT */\t\"Asn\",\n\t/* ACA */\t\"Thr\",\n\t/* ACC */\t\"Thr\",\n\t/* ACG */\t\"Thr\",\n\t/* ACT */\t\"Thr\",\n\t/* AGA */\t\"Arg\",\n\t/* AGC */\t\"Ser\",\n\t/* AGG */\t\"Arg\",\n\t/* AGT */\t\"Ser\",\n\t/* ATA */\t\"Ile\",\n\t/* ATC */\t\"Ile\",\n\t/* ATG */\t\"Met\",\n\t/* ATT */\t\"Ile\",\n\t/* CAA */\t\"Gln\",\n\t/* CAC */\t\"His\",\n\t/* CAG */\t\"Gln\",\n\t/* CAT */\t\"His\",\n\t/* CCA */\t\"Pro\",\n\t/* CCC */\t\"Pro\",\n\t/* CCG */\t\"Pro\",\n\t/* CCT */\t\"Pro\",\n\t/* CGA */\t\"Arg\",\n\t/* CGC */\t\"Arg\",\n\t/* CGG */\t\"Arg\",\n\t/* CGT */\t\"Arg\",\n\t/* CTA */\t\"Leu\",\n\t/* CTC */\t\"Leu\",\n\t/* CTG */\t\"Leu\",\n\t/* CTT */\t\"Leu\",\n\t/* GAA */\t\"Glu\",\n\t/* GAC */\t\"Asp\",\n\t/* GAG */\t\"Glu\",\n\t/* GAT */\t\"Asp\",\n\t/* GCA */\t\"Ala\",\n\t/* GCC */\t\"Ala\",\n\t/* GCG */\t\"Ala\",\n\t/* GCT */\t\"Ala\",\n\t/* GGA */\t\"Gly\",\n\t/* GGC */\t\"Gly\",\n\t/* GGG */\t\"Gly\",\n\t/* GGT */\t\"Gly\",\n\t/* GTA */\t\"Val\",\n\t/* GTC */\t\"Val\",\n\t/* GTG */\t\"Val\",\n\t/* GTT */\t\"Val\",\n\t/* TAA */\t\"Ter\",\n\t/* TAC */\t\"Tyr\",\n\t/* TAG */\t\"Ter\",\n\t/* TAT */\t\"Tyr\",\n\t/* TCA */\t\"Ser\",\n\t/* TCC */\t\"Ser\",\n\t/* TCG */\t\"Ser\",\n\t/* TCT */\t\"Ser\",\n\t/* TGA */\t\"Ter\",\n\t/* TGC */\t\"Cys\",\n\t/* TGG */\t\"Trp\",\n\t/* TGT */\t\"Cys\",\n\t/* TTA */\t\"Leu\",\n\t/* TTC */\t\"Phe\",\n\t/* TTG */\t\"Leu\",\n\t/* TTT */\t\"Phe\"\n};\n\nstatic int codon2aa_int[64] = {\n\t/* AAA */\t12,\n\t/* AAC */\t3,\n\t/* AAG */\t12,\n\t/* AAT */\t3,\n\t/* ACA */\t17,\n\t/* ACC */\t17,\n\t/* ACG */\t17,\n\t/* ACT */\t17,\n\t/* AGA */\t2,\n\t/* AGC */\t16,\n\t/* AGG */\t2,\n\t/* AGT */\t16,\n\t/* ATA */\t10,\n\t/* ATC */\t10,\n\t/* ATG */\t13,\n\t/* ATT */\t10,\n\t/* CAA */\t6,\n\t/* CAC */\t9,\n\t/* CAG */\t6,\n\t/* CAT */\t9,\n\t/* CCA */\t15,\n\t/* CCC */\t15,\n\t/* CCG */\t15,\n\t/* CCT */\t15,\n\t/* CGA */\t2,\n\t/* CGC */\t2,\n\t/* CGG */\t2,\n\t/* CGT */\t2,\n\t/* CTA */\t11,\n\t/* CTC */\t11,\n\t/* CTG */\t11,\n\t/* CTT */\t11,\n\t/* GAA */\t7,\n\t/* GAC */\t4,\n\t/* GAG */\t7,\n\t/* GAT */\t4,\n\t/* GCA */\t1,\n\t/* GCC */\t1,\n\t/* GCG */\t1,\n\t/* GCT */\t1,\n\t/* GGA */\t8,\n\t/* GGC */\t8,\n\t/* GGG */\t8,\n\t/* GGT */\t8,\n\t/* GTA */\t20,\n\t/* GTC */\t20,\n\t/* GTG */\t20,\n\t/* GTT */\t20,\n\t/* TAA */\t0,\n\t/* TAC */\t19,\n\t/* TAG */\t0,\n\t/* TAT */\t19,\n\t/* TCA */\t16,\n\t/* TCC */\t16,\n\t/* TCG */\t16,\n\t/* TCT */\t16,\n\t/* TGA */\t0,\n\t/* TGC */\t5,\n\t/* TGG */\t18,\n\t/* TGT */\t5,\n\t/* TTA */\t11,\n\t/* TTC */\t14,\n\t/* TTG */\t11,\n\t/* TTT */\t14\n};\n\n\n// ************************************************************************************\n//\n//\tnucleotide utilities\n//\n#pragma mark -\n#pragma mark Nucleotide utilities\n#pragma mark -\n\n//\t(string)codonsToAminoAcids(integer codons, [li$ long = F], [l$ paste = T])\nEidosValue_SP SLiM_ExecuteFunction_codonsToAminoAcids(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *codons_value = p_arguments[0].get();\n\tEidosValue *long_value = p_arguments[1].get();\n\t\n\tint codons_length = codons_value->Count();\n\t\n\tbool integer_result = (long_value->Type() == EidosValueType::kValueInt);\n\teidos_logical_t long_strings = (integer_result ? false : long_value->LogicalAtIndex_NOCAST(0, nullptr));\n\t\n\tif (integer_result)\n\t{\n\t\tint64_t long_intval = long_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (long_intval != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires 'long' to be T, F, or 0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (codons_length == 1)\n\t{\n\t\tint64_t codon = codons_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((codon < 0) || (codon > 63))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires codons to be in [0, 63].\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (integer_result)\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(codon2aa_int[codon]));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::string &aa = (long_strings ? codon2aa_long[codon] : codon2aa_short[codon]);\n\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(aa));\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst int64_t *int_data = codons_value->IntData();\n\t\t\n\t\tif (integer_result)\n\t\t{\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(codons_length);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < codons_length; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t codon = int_data[value_index];\n\t\t\t\t\n\t\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires codons to be in [0, 63].\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(codon2aa_int[codon], value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(int_result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue *paste_value = p_arguments[2].get();\n\t\t\teidos_logical_t paste = paste_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (paste)\n\t\t\t{\n\t\t\t\tif (long_strings && (codons_length > 0))\n\t\t\t\t{\n\t\t\t\t\t// pasting: \"Aaa-Bbb-Ccc\"\n\t\t\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\t\t\t\tstd::string &aa_string = string_result->StringData_Mutable()[0];\n\t\t\t\t\t\n\t\t\t\t\taa_string.resize(codons_length * 4 - 1);\t// create space for all the amino acids we will generate, including hyphens\n\t\t\t\t\t\n\t\t\t\t\tchar *aa_string_ptr = &aa_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < codons_length; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t codon = int_data[value_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires codons to be in [0, 63].\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string &aa = codon2aa_long[codon];\n\t\t\t\t\t\tchar *codon_aa_ptr = &aa[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_index > 0)\n\t\t\t\t\t\t\t*(aa_string_ptr++) = '-';\n\t\t\t\t\t\t\n\t\t\t\t\t\t*(aa_string_ptr++) = codon_aa_ptr[0];\n\t\t\t\t\t\t*(aa_string_ptr++) = codon_aa_ptr[1];\n\t\t\t\t\t\t*(aa_string_ptr++) = codon_aa_ptr[2];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn EidosValue_SP(string_result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// pasting: \"ABC\"\n\t\t\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\t\t\t\tstd::string &aa_string = string_result->StringData_Mutable()[0];\n\t\t\t\t\t\n\t\t\t\t\taa_string.resize(codons_length);\t// create space for all the amino acids we will generate\n\t\t\t\t\t\n\t\t\t\t\tchar *aa_string_ptr = &aa_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < codons_length; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t codon = int_data[value_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires codons to be in [0, 63].\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string &aa = codon2aa_short[codon];\n\t\t\t\t\t\t\n\t\t\t\t\t\taa_string_ptr[value_index] = aa[0];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\treturn EidosValue_SP(string_result);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// no pasting: \"A\" \"C\" \"C\" or \"Aaa\" \"Bbb\" \"Ccc\"\n\t\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(codons_length);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < codons_length; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t codon = int_data[value_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToAminoAcids): function codonsToAminoAcids() requires codons to be in [0, 63].\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tstd::string &aa = (long_strings ? codon2aa_long[codon] : codon2aa_short[codon]);\n\t\t\t\t\t\n\t\t\t\t\tstring_result->PushString(aa);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn EidosValue_SP(string_result);\n\t\t\t}\n\t\t}\n\t}\n}\n\n//\t(integer)nucleotidesToCodons(is sequence)\nEidosValue_SP SLiM_ExecuteFunction_nucleotidesToCodons(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *sequence_value = p_arguments[0].get();\n\tEidosValueType sequence_type = sequence_value->Type();\n\tint64_t sequence_count = sequence_value->Count();\n\t\n\tif (sequence_count == 1)\n\t{\n\t\tif (sequence_type == EidosValueType::kValueString)\n\t\t{\n\t\t\t// singleton string case\n\t\t\tuint8_t *nuc_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\t\tconst std::string &string_ref = sequence_value->StringData()[0];\n\t\t\tint64_t length = (int64_t)string_ref.length();\n\t\t\t\n\t\t\tif (length % 3 != 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires the nucleotide sequence to be a multiple of three in length.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint64_t length_3 = length / 3;\n\t\t\t\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length_3);\n\t\t\t\n\t\t\tfor (int64_t value_index = 0; value_index < length_3; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t codon_base = value_index * 3;\n\t\t\t\t\n\t\t\t\tint nuc1 = nuc_lookup[(int)(unsigned char)(string_ref[codon_base])];\n\t\t\t\tint nuc2 = nuc_lookup[(int)(unsigned char)(string_ref[codon_base + 1])];\n\t\t\t\tint nuc3 = nuc_lookup[(int)(unsigned char)(string_ref[codon_base + 2])];\n\t\t\t\t\n\t\t\t\tif ((nuc1 > 3) || (nuc2 > 3) || (nuc3 > 3))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tint codon = nuc1 * 16 + nuc2 * 4 + nuc3;\t// 0..63\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(codon, value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(int_result);\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires the nucleotide sequence to be a multiple of three in length.\" << EidosTerminate(nullptr);\n\t}\n\telse\n\t{\n\t\tif (sequence_count % 3 != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires the nucleotide sequence to be a multiple of three in length.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint64_t length_3 = sequence_count / 3;\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length_3);\n\t\t\n\t\tif (sequence_type == EidosValueType::kValueString)\n\t\t{\n\t\t\t// string vector case\n\t\t\tuint8_t *nuc_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\t\tconst std::string *string_vec = sequence_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < length_3; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t codon_base = (size_t)value_index * 3;\n\t\t\t\t\n\t\t\t\tconst std::string &nucstring1 = string_vec[codon_base];\n\t\t\t\tconst std::string &nucstring2 = string_vec[codon_base + 1];\n\t\t\t\tconst std::string &nucstring3 = string_vec[codon_base + 2];\n\t\t\t\t\n\t\t\t\tif ((nucstring1.length() != 1) || (nucstring2.length() != 1) || (nucstring3.length() != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tint nuc1 = nuc_lookup[(int)(unsigned char)(nucstring1[0])];\n\t\t\t\tint nuc2 = nuc_lookup[(int)(unsigned char)(nucstring2[0])];\n\t\t\t\tint nuc3 = nuc_lookup[(int)(unsigned char)(nucstring3[0])];\n\t\t\t\t\n\t\t\t\tif ((nuc1 > 3) || (nuc2 > 3) || (nuc3 > 3))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tint codon = nuc1 * 16 + nuc2 * 4 + nuc3;\t// 0..63\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(codon, value_index);\n\t\t\t}\n\t\t}\n\t\telse // sequence_type == EidosValueType::kValueInt\n\t\t{\n\t\t\t// int vector case\n\t\t\tconst int64_t *int_data = sequence_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < length_3; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t codon_base = (size_t)value_index * 3;\n\t\t\t\t\n\t\t\t\tint64_t nuc1 = int_data[codon_base];\n\t\t\t\tint64_t nuc2 = int_data[codon_base + 1];\n\t\t\t\tint64_t nuc3 = int_data[codon_base + 2];\n\t\t\t\t\n\t\t\t\tif ((nuc1 < 0) || (nuc1 > 3) || (nuc2 < 0) || (nuc2 > 3) || (nuc3 < 0) || (nuc3 > 3))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_nucleotidesToCodons): function nucleotidesToCodons() requires integer sequence values to be in [0,3].\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tint64_t codon = nuc1 * 16 + nuc2 * 4 + nuc3;\t// 0..63\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(codon, value_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(int_result);\n\t}\n}\n\nstatic void CountNucleotides(EidosValue *sequence_value, int64_t *total_ACGT, const char *function_name)\n{\n\tEidosValueType sequence_type = sequence_value->Type();\n\tint sequence_count = sequence_value->Count();\n\t\n\tif (sequence_count == 1)\n\t{\n\t\t// Singleton case\n\t\tif (sequence_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tuint64_t nuc = sequence_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (nuc > 3)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_\" << function_name << \"): function \" << function_name << \"() requires integer sequence values to be in [0,3].\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\ttotal_ACGT[nuc]++;\n\t\t}\n\t\telse // sequence_type == EidosValueType::kValueString\n\t\t{\n\t\t\t// Note that this is different from the case below - a single string versus a vector of single characters\n\t\t\tuint8_t *nuc_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\t\tconst std::string &string_ref = sequence_value->StringData()[0];\n\t\t\tstd::size_t length = string_ref.length();\n\t\t\t\n\t\t\tfor (std::size_t i = 0; i < length; ++i)\n\t\t\t{\n\t\t\t\tchar nuc_char = string_ref[i];\n\t\t\t\tuint8_t nuc_index = nuc_lookup[(int)(unsigned char)(nuc_char)];\n\t\t\t\t\n\t\t\t\tif (nuc_index > 3)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_\" << function_name << \"): function \" << function_name << \"() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\ttotal_ACGT[nuc_index]++;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Vector case, optimized for speed\n\t\tif (sequence_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data = sequence_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < sequence_count; ++value_index)\n\t\t\t{\n\t\t\t\tuint64_t nuc = int_data[value_index];\n\t\t\t\t\n\t\t\t\tif (nuc > 3)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_\" << function_name << \"): function \" << function_name << \"() requires integer sequence values to be in [0,3].\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\ttotal_ACGT[nuc]++;\n\t\t\t}\n\t\t}\n\t\telse // sequence_type == EidosValueType::kValueString\n\t\t{\n\t\t\tuint8_t *nuc_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\t\tconst std::string *string_vec = sequence_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < sequence_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &nuc_string = string_vec[value_index];\n\t\t\t\t\n\t\t\t\tif (nuc_string.length() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_\" << function_name << \"): function \" << function_name << \"() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tchar nuc_char = nuc_string[0];\n\t\t\t\tuint8_t nuc_index = nuc_lookup[(int)(unsigned char)(nuc_char)];\n\t\t\t\t\n\t\t\t\tif (nuc_index > 3)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_\" << function_name << \"): function \" << function_name << \"() requires string sequence values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\ttotal_ACGT[nuc_index]++;\n\t\t\t}\n\t\t}\n\t}\n}\n\n//\t(float)mm16To256(float mutationMatrix16)\nEidosValue_SP SLiM_ExecuteFunction_mm16To256(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *mutationMatrix16_value = p_arguments[0].get();\n\t\n\tif (mutationMatrix16_value->Count() != 16)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mm16To256): function mm16To256() requires mutationMatrix16 to be of length 16.\" << EidosTerminate(nullptr);\n\tif ((mutationMatrix16_value->DimensionCount() != 2) || (mutationMatrix16_value->Dimensions()[0] != 4) || (mutationMatrix16_value->Dimensions()[1] != 4))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mm16To256): function mm16To256() requires mutationMatrix16 to be a 4x4 matrix.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(256);\n\t\n\tfor (int i = 0; i < 256; ++i)\n\t{\n\t\tint ancestral_nucleotide = ((i / 4) % 4);\n\t\tint derived_nucleotide = (i / 64);\n\t\tdouble value = mutationMatrix16_value->FloatAtIndex_NOCAST(ancestral_nucleotide + derived_nucleotide * 4, nullptr);\n\t\t\n\t\tfloat_result->set_float_no_check(value, i);\n\t}\n\t\n\tconst int64_t dims[2] = {64, 4};\n\tfloat_result->SetDimensions(2, dims);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t(float)mmJukesCantor(float$ alpha)\nEidosValue_SP SLiM_ExecuteFunction_mmJukesCantor(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *alpha_value = p_arguments[0].get();\n\tdouble alpha = alpha_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif (alpha < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mmJukesCantor): function mmJukesCantor() requires alpha >= 0.0.\" << EidosTerminate(nullptr);\n\tif (3 * alpha > 1.0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mmJukesCantor): function mmJukesCantor() requires 3 * alpha <= 1.0.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(16);\n\t\n\tfloat_result->set_float_no_check(0.0, 0);\n\tfloat_result->set_float_no_check(alpha, 1);\n\tfloat_result->set_float_no_check(alpha, 2);\n\tfloat_result->set_float_no_check(alpha, 3);\n\t\n\tfloat_result->set_float_no_check(alpha, 4);\n\tfloat_result->set_float_no_check(0.0, 5);\n\tfloat_result->set_float_no_check(alpha, 6);\n\tfloat_result->set_float_no_check(alpha, 7);\n\t\n\tfloat_result->set_float_no_check(alpha, 8);\n\tfloat_result->set_float_no_check(alpha, 9);\n\tfloat_result->set_float_no_check(0.0, 10);\n\tfloat_result->set_float_no_check(alpha, 11);\n\t\n\tfloat_result->set_float_no_check(alpha, 12);\n\tfloat_result->set_float_no_check(alpha, 13);\n\tfloat_result->set_float_no_check(alpha, 14);\n\tfloat_result->set_float_no_check(0.0, 15);\n\t\n\tconst int64_t dims[2] = {4, 4};\n\tfloat_result->SetDimensions(2, dims);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t(float)mmKimura(float$ alpha, float$ beta)\nEidosValue_SP SLiM_ExecuteFunction_mmKimura(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *alpha_value = p_arguments[0].get();\n\tEidosValue *beta_value = p_arguments[1].get();\n\t\n\tdouble alpha = alpha_value->FloatAtIndex_NOCAST(0, nullptr);\n\tdouble beta = beta_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((alpha < 0.0) || (alpha > 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mmKimura): function mmKimura() requires alpha to be in [0.0, 1.0].\" << EidosTerminate(nullptr);\n\tif ((beta < 0.0) || (beta > 0.5))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mmKimura): function mmKimura() requires beta to be in [0.0, 0.5].\" << EidosTerminate(nullptr);\n\tif (alpha + 2 * beta > 1.0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_mmKimura): function mmKimura() requires alpha + 2 * beta to be <= 1.0.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(16);\n\t\n\tfloat_result->set_float_no_check(0.0, 0);\n\tfloat_result->set_float_no_check(beta, 1);\n\tfloat_result->set_float_no_check(alpha, 2);\n\tfloat_result->set_float_no_check(beta, 3);\n\t\n\tfloat_result->set_float_no_check(beta, 4);\n\tfloat_result->set_float_no_check(0.0, 5);\n\tfloat_result->set_float_no_check(beta, 6);\n\tfloat_result->set_float_no_check(alpha, 7);\n\t\n\tfloat_result->set_float_no_check(alpha, 8);\n\tfloat_result->set_float_no_check(beta, 9);\n\tfloat_result->set_float_no_check(0.0, 10);\n\tfloat_result->set_float_no_check(beta, 11);\n\t\n\tfloat_result->set_float_no_check(beta, 12);\n\tfloat_result->set_float_no_check(alpha, 13);\n\tfloat_result->set_float_no_check(beta, 14);\n\tfloat_result->set_float_no_check(0.0, 15);\n\t\n\tconst int64_t dims[2] = {4, 4};\n\tfloat_result->SetDimensions(2, dims);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t(integer)nucleotideCounts(is sequence)\nEidosValue_SP SLiM_ExecuteFunction_nucleotideCounts(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *sequence_value = p_arguments[0].get();\n\tint64_t total_ACGT[4] = {0, 0, 0, 0};\n\t\n\tCountNucleotides(sequence_value, total_ACGT, \"nucleotideCounts\");\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(4);\n\t\n\tint_result->set_int_no_check(total_ACGT[0], 0);\n\tint_result->set_int_no_check(total_ACGT[1], 1);\n\tint_result->set_int_no_check(total_ACGT[2], 2);\n\tint_result->set_int_no_check(total_ACGT[3], 3);\n\t\n\treturn EidosValue_SP(int_result);\n}\n\n//\t(float)nucleotideFrequencies(is sequence)\nEidosValue_SP SLiM_ExecuteFunction_nucleotideFrequencies(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *sequence_value = p_arguments[0].get();\n\tint64_t total_ACGT[4] = {0, 0, 0, 0};\n\t\n\tCountNucleotides(sequence_value, total_ACGT, \"nucleotideFrequencies\");\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(4);\n\tdouble total = total_ACGT[0] + total_ACGT[1] + total_ACGT[2] + total_ACGT[3];\n\t\n\tfloat_result->set_float_no_check(total_ACGT[0] / total, 0);\n\tfloat_result->set_float_no_check(total_ACGT[1] / total, 1);\n\tfloat_result->set_float_no_check(total_ACGT[2] / total, 2);\n\tfloat_result->set_float_no_check(total_ACGT[3] / total, 3);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t(is)randomNucleotides(i$ length, [Nif basis = NULL], [s$ format = \"string\"])\nEidosValue_SP SLiM_ExecuteFunction_randomNucleotides(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tEidosValue *basis_value = p_arguments[1].get();\n\tEidosValue_String *format_value = (EidosValue_String *)p_arguments[2].get();\n\t\n\t// Get the sequence length to generate\n\tint64_t length = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((length < 0) || (length > 2000000000L))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_randomNucleotides): function randomNucleotides() requires length to be in [0, 2e9].\" << EidosTerminate(nullptr);\n\t\n\t// Figure out the probability threshold for each base\n\tdouble pA = 0.25, pC = 0.25, pG = 0.25, pT; // = 0.25;\t// not used below\n\t\n\tif (basis_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tif (basis_value->Count() != 4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_randomNucleotides): function randomNucleotides() requires basis to be either NULL, or an integer or float vector of length 4 (with relative probabilities for A/C/G/T).\" << EidosTerminate(nullptr);\n\t\t\n\t\tpA = basis_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\tpC = basis_value->NumericAtIndex_NOCAST(1, nullptr);\n\t\tpG = basis_value->NumericAtIndex_NOCAST(2, nullptr);\n\t\tpT = basis_value->NumericAtIndex_NOCAST(3, nullptr);\n\t\t\n\t\tif (!std::isfinite(pA) || !std::isfinite(pC) || !std::isfinite(pG) || !std::isfinite(pT) || (pA < 0.0) || (pC < 0.0) || (pG < 0.0) || (pT < 0.0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_randomNucleotides): function randomNucleotides() requires basis values to be finite and >= 0.0.\" << EidosTerminate(nullptr);\n\t\t\n\t\tdouble sum = pA + pC + pG + pT;\n\t\t\n\t\tif (sum <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_randomNucleotides): function randomNucleotides() requires at least one basis value to be > 0.0.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Normalize to probabilities\n\t\tpA = pA / sum;\n\t\tpC = pC / sum;\n\t\tpG = pG / sum;\n\t\t//pT = pT / sum;\t\t// not used below since it will end up as 1.0 below\n\t}\n\t\n\t// Convert probabilities to thresholds\n\t//pT += pA + pC + pG;\t\t// should be 1.0; not used\n\tpG += pA + pC;\n\tpC += pA;\n\t\n\t// Generate a result in the requested format\n\tconst std::string &format = format_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((format != \"string\") && (format != \"char\") && (format != \"integer\"))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_randomNucleotides): function randomNucleotides() requires a format of 'string', 'char', or 'integer'.\" << EidosTerminate();\n\t\n\tif (length == 0)\n\t{\n\t\tif (format == \"integer\")\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\telse\t\t\t\t\t\treturn gStaticEidosValue_String_ZeroVec;\n\t}\n\t\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tif (length == 1)\n\t{\n\t\t// Handle the singleton case separately for speed\n\t\tdouble runif = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\n\t\tif (format == \"integer\")\n\t\t{\n\t\t\tif (runif < pA)\t\t\treturn gStaticEidosValue_Integer0;\n\t\t\telse if (runif < pC)\treturn gStaticEidosValue_Integer1;\n\t\t\telse if (runif < pG)\treturn gStaticEidosValue_Integer2;\n\t\t\telse /* (runif < pT) */\treturn gStaticEidosValue_Integer3;\n\t\t}\n\t\telse\t// \"string\", \"char\"\n\t\t{\n\t\t\tif (runif < pA)\t\t\treturn gStaticEidosValue_StringA;\n\t\t\telse if (runif < pC)\treturn gStaticEidosValue_StringC;\n\t\t\telse if (runif < pG)\treturn gStaticEidosValue_StringG;\n\t\t\telse /* (runif < pT) */\treturn gStaticEidosValue_StringT;\n\t\t}\n\t}\n\t\n\tif (format == \"char\")\n\t{\n\t\t// return a vector of one-character strings, \"T\" \"A\" \"T\" \"A\"\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)length);\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t{\n\t\t\tdouble runif = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\n\t\t\tif (runif < pA)\t\t\tstring_result->PushString(gStr_A);\n\t\t\telse if (runif < pC)\tstring_result->PushString(gStr_C);\n\t\t\telse if (runif < pG)\tstring_result->PushString(gStr_G);\n\t\t\telse /* (runif < pT) */\tstring_result->PushString(gStr_T);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\telse if (format == \"integer\")\n\t{\n\t\t// return a vector of integers, 3 0 3 0\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length);\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t{\n\t\t\tdouble runif = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\n\t\t\tif (runif < pA)\t\t\tint_result->set_int_no_check(0, value_index);\n\t\t\telse if (runif < pC)\tint_result->set_int_no_check(1, value_index);\n\t\t\telse if (runif < pG)\tint_result->set_int_no_check(2, value_index);\n\t\t\telse /* (runif < pT) */\tint_result->set_int_no_check(3, value_index);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(int_result);\n\t}\n\telse if (format == \"string\")\n\t{\n\t\t// return a singleton string for the whole sequence, \"TATA\"; we munge the std::string inside the EidosValue to avoid memory copying, very naughty\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\tstd::string &nuc_string = string_result->StringData_Mutable()[0];\n\t\t\n\t\tnuc_string.resize(length);\t// create space for all the nucleotides we will generate\n\t\t\n\t\tchar *nuc_string_ptr = &nuc_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t{\n\t\t\tdouble runif = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\n\t\t\tif (runif < pA)\t\t\tnuc_string_ptr[value_index] = 'A';\n\t\t\telse if (runif < pC)\tnuc_string_ptr[value_index] = 'C';\n\t\t\telse if (runif < pG)\tnuc_string_ptr[value_index] = 'G';\n\t\t\telse /* (runif < pT) */\tnuc_string_ptr[value_index] = 'T';\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\t\n\t// CODE COVERAGE: This is dead code\n\treturn result_SP;\n}\n\n// (is)codonsToNucleotides(integer codons, [string$ format = \"string\"])\nEidosValue_SP SLiM_ExecuteFunction_codonsToNucleotides(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *codons_value = p_arguments[0].get();\n\tEidosValue_String *format_value = (EidosValue_String *)p_arguments[1].get();\n\t\n\tint codons_length = codons_value->Count();\n\tint length = codons_length * 3;\n\tconst std::string &format = format_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tconst int64_t *codons_data = codons_value->IntData();\n\t\n\tif (format == \"char\")\n\t{\n\t\t// return a vector of one-character strings, \"T\" \"A\" \"T\" \"A\" \"C\" \"G\"\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)length);\n\t\t\n\t\tfor (int codon_index = 0; codon_index < codons_length; ++codon_index)\n\t\t{\n\t\t\tint codon = (int)codons_data[codon_index];\n\t\t\t\n\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): function codonsToNucleotides() requires codon values to be in [0,63].\" << EidosTerminate();\n\t\t\t\n\t\t\tint nuc1 = codon >> 4;\n\t\t\tint nuc2 = (codon >> 2) & 0x03;\n\t\t\tint nuc3 = codon & 0x03;\n\t\t\t\n\t\t\tswitch (nuc1) {\n\t\t\t\tcase 0: string_result->PushString(gStr_A); break;\n\t\t\t\tcase 1: string_result->PushString(gStr_C); break;\n\t\t\t\tcase 2: string_result->PushString(gStr_G); break;\n\t\t\t\tcase 3: string_result->PushString(gStr_T); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): nucleotide value out of range.\" << EidosTerminate();\n\t\t\t}\n\t\t\tswitch (nuc2) {\n\t\t\t\tcase 0: string_result->PushString(gStr_A); break;\n\t\t\t\tcase 1: string_result->PushString(gStr_C); break;\n\t\t\t\tcase 2: string_result->PushString(gStr_G); break;\n\t\t\t\tcase 3: string_result->PushString(gStr_T); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): nucleotide value out of range.\" << EidosTerminate();\n\t\t\t}\n\t\t\tswitch (nuc3) {\n\t\t\t\tcase 0: string_result->PushString(gStr_A); break;\n\t\t\t\tcase 1: string_result->PushString(gStr_C); break;\n\t\t\t\tcase 2: string_result->PushString(gStr_G); break;\n\t\t\t\tcase 3: string_result->PushString(gStr_T); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): nucleotide value out of range.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\telse if (format == \"integer\")\n\t{\n\t\t// return a vector of integers, 3 0 3 0 1 2\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length);\n\t\t\n\t\tfor (int codon_index = 0; codon_index < codons_length; ++codon_index)\n\t\t{\n\t\t\tint codon = (int)codons_data[codon_index];\n\t\t\t\n\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): function codonsToNucleotides() requires codon values to be in [0,63].\" << EidosTerminate();\n\t\t\t\n\t\t\tint nuc1 = codon >> 4;\n\t\t\tint nuc2 = (codon >> 2) & 0x03;\n\t\t\tint nuc3 = codon & 0x03;\n\t\t\t\n\t\t\tint_result->set_int_no_check(nuc1, (size_t)codon_index * 3);\n\t\t\tint_result->set_int_no_check(nuc2, (size_t)codon_index * 3 + 1);\n\t\t\tint_result->set_int_no_check(nuc3, (size_t)codon_index * 3 + 2);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(int_result);\n\t}\n\telse if (format == \"string\")\n\t{\n\t\t// return a singleton string for the whole sequence, \"TATACG\"; we munge the std::string inside the EidosValue to avoid memory copying, very naughty\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\tstd::string &nuc_string = string_result->StringData_Mutable()[0];\n\t\t\n\t\tnuc_string.resize(length);\t// create space for all the nucleotides we will generate\n\t\t\n\t\tchar *nuc_string_ptr = &nuc_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\n\t\tfor (int codon_index = 0; codon_index < codons_length; ++codon_index)\n\t\t{\n\t\t\tint codon = (int)codons_data[codon_index];\n\t\t\t\n\t\t\tif ((codon < 0) || (codon > 63))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): function codonsToNucleotides() requires codon values to be in [0,63].\" << EidosTerminate();\n\t\t\t\n\t\t\tint nuc1 = codon >> 4;\n\t\t\tint nuc2 = (codon >> 2) & 0x03;\n\t\t\tint nuc3 = codon & 0x03;\n\t\t\t\n\t\t\tnuc_string_ptr[(size_t)codon_index * 3] = gSLiM_Nucleotides[nuc1];\n\t\t\tnuc_string_ptr[(size_t)codon_index * 3 + 1] = gSLiM_Nucleotides[nuc2];\n\t\t\tnuc_string_ptr[(size_t)codon_index * 3 + 2] = gSLiM_Nucleotides[nuc3];\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_codonsToNucleotides): function codonsToNucleotides() requires a format of 'string', 'char', or 'integer'.\" << EidosTerminate();\n\t}\n}\n\n\n// ************************************************************************************\n//\n//\tother functions\n//\n#pragma mark -\n#pragma mark Other functions\n#pragma mark -\n\nstatic inline int SummarizeGridIndex_1D(Individual *individual, int component0, double *spatialBounds, int64_t *dims, __attribute__((unused)) int64_t result_count)\n{\n\tdouble coord0 = (&(individual->spatial_x_))[component0];\n\t\n\tif ((coord0 < spatialBounds[0]) || (coord0 > spatialBounds[1]))\n\t\treturn -1;\t// a flag value that indicates \"individual out of bounds\"\n\t\n\t// figure out which grid cell this individual is in\n\tint grid0 = (int)round(((coord0 - spatialBounds[0]) / (spatialBounds[1] - spatialBounds[0])) * (dims[0] - 1));\n\t\n#if DEBUG\n\tif ((grid0 < 0) || (grid0 >= dims[0]))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid coordinates out of bounds.\" << EidosTerminate();\n#endif\n\t\n\tint grid_index = (int)grid0;\t// this is the index in tallies, result_data\n\t\n#if DEBUG\n\tif ((grid_index < 0) || (grid_index >= result_count))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid index out of bounds.\" << EidosTerminate();\n#endif\n\t\n\treturn grid_index;\n}\n\nstatic inline int SummarizeGridIndex_2D(Individual *individual, int component0, int component1, double *spatialBounds, int64_t *dims, __attribute__((unused)) int64_t result_count)\n{\n\tdouble coord0 = (&(individual->spatial_x_))[component0];\t// x, for \"xy\"\n\tdouble coord1 = (&(individual->spatial_x_))[component1];\t// y, for \"xy\"\n\t\n\tif ((coord0 < spatialBounds[0]) || (coord0 > spatialBounds[1]) || (coord1 < spatialBounds[2]) || (coord1 > spatialBounds[3]))\n\t\treturn -1;\t// a flag value that indicates \"individual out of bounds\"\n\t\n\t// figure out which grid cell this individual is in\n\tint grid0 = (int)round(((coord0 - spatialBounds[0]) / (spatialBounds[1] - spatialBounds[0])) * (dims[1] - 1));\t// x index, for \"xy\"\n\tint grid1 = (int)round(((coord1 - spatialBounds[2]) / (spatialBounds[3] - spatialBounds[2])) * (dims[0] - 1));\t// y index, for \"xy\"\n\t\n#if DEBUG\n\tif (((grid0 < 0) || (grid0 >= dims[1])) || ((grid1 < 0) || (grid1 >= dims[0])))\t\t// dims[0] is row count, dims[1] is col count\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid coordinates out of bounds.\" << EidosTerminate();\n#endif\n\t\n\tint grid_index = (int)(grid0 * dims[0] + dims[0] - 1 - grid1);\t// this is the index in tallies, result_data; x * row_count + y, by row, for \"xy\"\n\t\n#if DEBUG\n\tif ((grid_index < 0) || (grid_index >= result_count))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid index out of bounds.\" << EidosTerminate();\n#endif\n\t\n\treturn grid_index;\n}\n\nstatic inline int SummarizeGridIndex_3D(Individual *individual, int component0, int component1, int component2, double *spatialBounds, int64_t *dims, __attribute__((unused)) int64_t result_count)\n{\n\tdouble coord0 = (&(individual->spatial_x_))[component0];\t// x, for \"xyz\"\n\tdouble coord1 = (&(individual->spatial_x_))[component1];\t// y, for \"xyz\"\n\tdouble coord2 = (&(individual->spatial_x_))[component2];\t// z, for \"xyz\"\n\t\n\tif ((coord0 < spatialBounds[0]) || (coord0 > spatialBounds[1]) || (coord1 < spatialBounds[2]) || (coord1 > spatialBounds[3]) || (coord2 < spatialBounds[4]) || (coord2 > spatialBounds[5]))\n\t\treturn -1;\t// a flag value that indicates \"individual out of bounds\"\n\t\n\t// figure out which grid cell this individual is in\n\tint grid0 = (int)round(((coord0 - spatialBounds[0]) / (spatialBounds[1] - spatialBounds[0])) * (dims[1] - 1));\t// x index, for \"xyz\"\n\tint grid1 = (int)round(((coord1 - spatialBounds[2]) / (spatialBounds[3] - spatialBounds[2])) * (dims[0] - 1));\t// y index, for \"xyz\"\n\tint grid2 = (int)round(((coord2 - spatialBounds[4]) / (spatialBounds[5] - spatialBounds[4])) * (dims[2] - 1));\t// z index, for \"xyz\"\n\t\n#if DEBUG\n\tif (((grid0 < 0) || (grid0 >= dims[1])) || ((grid1 < 0) || (grid1 >= dims[0])) || ((grid2 < 0) || (grid2 >= dims[2])))\t\t// dims[0] is row count, dims[1] is col count\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid coordinates out of bounds.\" << EidosTerminate();\n#endif\n\t\n\tint grid_index = (int)(grid0 * dims[0] + dims[0] - 1 - grid1 + grid2 * dims[0] * dims[1]);\t// this is the index in tallies, result_data; x * row_count + y + z * cow_count * col_count, by row, for \"xy\"\n\t\n#if DEBUG\n\tif ((grid_index < 0) || (grid_index >= result_count))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) grid index out of bounds.\" << EidosTerminate();\n#endif\n\t\n\treturn grid_index;\n}\n\n// (float)summarizeIndividuals(o<Individual> individuals, integer dim, numeric spatialBounds, s$ operation, [Nlif$ empty = 0.0], [l$ perUnitArea = F], [Ns$ spatiality = NULL])\nEidosValue_SP SLiM_ExecuteFunction_summarizeIndividuals(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tEidosValue *dim_value = p_arguments[1].get();\n\tEidosValue *spatialBounds_value = p_arguments[2].get();\n\tEidosValue *operation_value = p_arguments[3].get();\n\tEidosValue *empty_value = p_arguments[4].get();\n\tEidosValue *perUnitArea_value = p_arguments[5].get();\n\tEidosValue *spatiality_value = p_arguments[6].get();\n\t\n\tif (p_interpreter.SymbolTable().SymbolDefinedAnywhere(gID_individuals))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() can't set up a local variable named 'individuals' because a symbol with that name is already defined.\" << EidosTerminate();\n\t\n\t// Get individuals vector; complicated as usual by singleton vs. vector\n\tint individuals_count = individuals_value->Count();\n\t\n\tif (individuals_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() cannot be called with a zero-length individuals vector, because the focal species, and thus the spatial dimensionality, cannot be determined.\" << EidosTerminate();\n\t\n\tIndividual **individuals_buffer = (Individual **)individuals_value->ObjectData();\n\t\n\t// This very weird code tests that the layout of ivars inside Individual is what we expect it to be below\n\t// We use the first individual in the buffer as a test subject, rather than nullptr, to make UBSan happy\n\tstatic bool beenHere = false;\n\t\n\tif (!beenHere)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"SLiM_ExecuteFunction_summarizeIndividuals(): usage of statics\");\n\t\t\n\t\tIndividual *test_ind_layout = individuals_buffer[0];\n\t\n\t\tif (((&(test_ind_layout->spatial_x_)) + 1 != (&(test_ind_layout->spatial_y_))) ||\n\t\t\t((&(test_ind_layout->spatial_x_)) + 2 != (&(test_ind_layout->spatial_z_))))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) Individual ivar layout unexpected.\" << EidosTerminate();\n\t\t\n\t\tbeenHere = true;\n\t}\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(individuals_value);\n\t\n\tif (!species)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() requires that all individuals belong to the same species.\" << EidosTerminate();\n\t\n\t// Get the model's dimensionality, which will be context for everything we do below\n\tCommunity &community = species->community_;\n\tint spatial_dimensionality = species->SpatialDimensionality();\n\t\n\tif (spatial_dimensionality <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() can only be called in spatial models, since it summarizes spatially-partitioned information.\" << EidosTerminate();\n\t\n\t// Get our spatiality and interpret it\n\tint spatiality, required_dimensionality;\n\tint component0 = -1, component1 = -1, component2 = -1;\n\t\n\tif (spatiality_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tspatiality = spatial_dimensionality;\n\t\trequired_dimensionality = spatial_dimensionality;\n\t\t\n\t\tif (spatiality >= 1)\n\t\t\tcomponent0 = 0;\n\t\tif (spatiality >= 2)\n\t\t\tcomponent1 = 1;\n\t\tif (spatiality >= 3)\n\t\t\tcomponent2 = 2;\n\t}\n\telse\n\t{\n\t\tstd::string spatiality_string = spatiality_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (spatiality_string.compare(gEidosStr_x) == 0)\t\t{ spatiality = 1; required_dimensionality = 1; component0 = 0; }\n\t\telse if (spatiality_string.compare(gEidosStr_y) == 0)\t{ spatiality = 1; required_dimensionality = 2; component0 = 1; }\n\t\telse if (spatiality_string.compare(gEidosStr_z) == 0)\t{ spatiality = 1; required_dimensionality = 3; component0 = 2; }\n\t\telse if (spatiality_string.compare(\"xy\") == 0)\t\t\t{ spatiality = 2; required_dimensionality = 2; component0 = 0; component1 = 1; }\n\t\telse if (spatiality_string.compare(\"xz\") == 0)\t\t\t{ spatiality = 2; required_dimensionality = 3; component0 = 0; component1 = 2; }\n\t\telse if (spatiality_string.compare(\"yz\") == 0)\t\t\t{ spatiality = 2; required_dimensionality = 3; component0 = 1; component1 = 2; }\n\t\telse if (spatiality_string.compare(\"xyz\") == 0)\t\t\t{ spatiality = 3; required_dimensionality = 3; component0 = 0; component1 = 1; component2 = 2; }\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() spatiality '\" << spatiality_string << \"' must be 'x', 'y', 'z', 'xy', 'xz', 'yz', or 'xyz'.\" << EidosTerminate();\n\t}\n\t\n\tif (required_dimensionality > spatial_dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() spatiality cannot utilize spatial dimensions beyond those set in initializeSLiMOptions().\" << EidosTerminate();\n\t\n\tif ((spatiality != 1) && (spatiality != 2) && (spatiality != 3))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) unexpected spatiality \" << spatiality << \".\" << EidosTerminate();\n\t\n\t// Get the spatial bounds and check that it matches the model dimensionality; note that we rearrange the order of the bounds vector here!\n\tint spatialBounds_count = spatialBounds_value->Count();\n\tdouble spatialBounds[6] = {-1, -1, -1, -1, -1, -1};\n\tbool invalid_bounds = false;\n\t\n\tif (spatialBounds_count != spatial_dimensionality * 2)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() spatialBounds is an unexpected length.  It must be supplied in the model's dimensionality (as from the spatialBounds property of a Subpopulation).\" << EidosTerminate();\n\t\n\tif (spatiality >= 1)\n\t{\n\t\tspatialBounds[0] = spatialBounds_value->NumericAtIndex_NOCAST(component0, nullptr);\n\t\tspatialBounds[1] = spatialBounds_value->NumericAtIndex_NOCAST(component0 + spatiality, nullptr);\n\t\tif (spatialBounds[0] >= spatialBounds[1])\n\t\t\tinvalid_bounds = true;\n\t}\n\tif (spatiality >= 2)\n\t{\n\t\tspatialBounds[2] = spatialBounds_value->NumericAtIndex_NOCAST(component1, nullptr);\n\t\tspatialBounds[3] = spatialBounds_value->NumericAtIndex_NOCAST(component1 + spatiality, nullptr);\n\t\tif (spatialBounds[2] >= spatialBounds[3])\n\t\t\tinvalid_bounds = true;\n\t}\n\tif (spatiality >= 3)\n\t{\n\t\tspatialBounds[4] = spatialBounds_value->NumericAtIndex_NOCAST(component2, nullptr);\n\t\tspatialBounds[5] = spatialBounds_value->NumericAtIndex_NOCAST(component2 + spatiality, nullptr);\n\t\tif (spatialBounds[4] >= spatialBounds[5])\n\t\t\tinvalid_bounds = true;\n\t}\n\t\n\tif (invalid_bounds)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() spatialBounds are invalid; it is required that x0 < x1, y0 < y1, and z0 < z1.\" << EidosTerminate();\n\t\n\t// Get the operation lambda string and the empty-cell value (NULL to execute the lambda for empty cells too)\n\tstd::string operation_string = operation_value->StringAtIndex_NOCAST(0, nullptr);\n\tbool uses_empty = (empty_value->Type() != EidosValueType::kValueNULL);\n\tdouble empty = uses_empty ? empty_value->FloatAtIndex_CAST(0, nullptr) : 0.0;\t// handles logical, integer, and float\n\t\n\t// Get the edgeScale value, which is used to postprocess vaues at the very end\n\tbool perUnitArea = perUnitArea_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (perUnitArea && std::isfinite(empty) && (empty != 0.0))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() requires that when perUnitArea is T, empty is F, 0, 0.0, INF, -INF, or NAN (so that the empty value does not get scaled, which presumably does not make sense).\" << EidosTerminate();\n\t\n\t// Get our dimensions, for our returned vector/matrix/array\n\tint dim_count = dim_value->Count();\n\t\n\tif (dim_count != spatiality)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() spatiality does not match the number of dimensions in dim; \" << spatiality << \" dimension(s) expected based on spatiality.\" << EidosTerminate();\n\t\n\tint64_t dims[3] = {0, 0, 0};\n\tint64_t result_count = 1;\n\t\n\tfor (int dim_index = 0; dim_index < dim_count; ++dim_index)\n\t{\n\t\tdims[dim_index] = dim_value->IntAtIndex_NOCAST(dim_index, nullptr);\n\t\t\n\t\tif ((dims[dim_index] < 2) || (dims[dim_index] > 10000))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): summarizeIndividuals() requires dimensions in dim to be in the range [2, 10000].\" << EidosTerminate();\n\t\t\n\t\tresult_count *= dims[dim_index];\n\t}\n\t\n\tif ((result_count <= 0) || (result_count >= INT32_MAX))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): (internal error) calculated size for returned vector (\" << result_count << \") is out of range for int32_t.\" << EidosTerminate();\n\t\n\t// Allocate our return value, set its dimensions, and get set up for using it\n\tEidosValue_Float *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(result_count);\n\tdouble *result_data = result_vec->data_mutable();\n\t\n\tif (dim_count > 1)\n\t\tresult_vec->SetDimensions(dim_count, dims);\n\t\n\t// Collect individuals into bins, then execute the operation on each bin\n\tstd::vector<std::vector<Individual *>> binned_individuals;\n\tbinned_individuals.resize(result_count);\n\t\n\tif (spatiality == 1)\n\t{\n\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t{\n\t\t\tIndividual *individual = individuals_buffer[individual_index];\n\t\t\tint grid_index = SummarizeGridIndex_1D(individual, component0, spatialBounds, dims, result_count);\n\t\t\tif (grid_index >= 0)\n\t\t\t\tbinned_individuals[grid_index].emplace_back(individual);\n\t\t}\n\t}\n\telse if (spatiality == 2)\n\t{\n\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t{\n\t\t\tIndividual *individual = individuals_buffer[individual_index];\n\t\t\tint grid_index = SummarizeGridIndex_2D(individual, component0, component1, spatialBounds, dims, result_count);\n\t\t\tif (grid_index >= 0)\n\t\t\t\tbinned_individuals[grid_index].emplace_back(individual);\n\t\t}\n\t}\n\telse // (spatiality == 3)\n\t{\n\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t{\n\t\t\tIndividual *individual = individuals_buffer[individual_index];\n\t\t\tint grid_index = SummarizeGridIndex_3D(individual, component0, component1, component2, spatialBounds, dims, result_count);\n\t\t\tif (grid_index >= 0)\n\t\t\t\tbinned_individuals[grid_index].emplace_back(individual);\n\t\t}\n\t}\n\t\n\t// Now we handle some special-case situations that we anticipate being common.  We have to have an *exact* match to use one of these.\n\t// I haven't implemented many of these for now, because actually this function is quite fast anyway; since the lambda gets called\n\t// only once per grid square, and then typically uses vectorized calls to do its work, it is actually quite an efficient design.\n\t// Even the optimizations here probably only pay off when the number of grid cells is very large and the number of individuals is small.\n\t// A better optimization would avoid building the binned_individuals vector at all, for simple cases like these where the result\n\t// could be accumulated directly into the result_data vector; but I'll wait until I see a model where this is a real hotspot.\n\tif (((operation_string == \"individuals.size();\") || (operation_string == \"individuals.length();\") || (operation_string == \"size(individuals);\") || (operation_string == \"length(individuals);\") || (operation_string == \"return individuals.size();\") || (operation_string == \"return individuals.length();\") || (operation_string == \"return size(individuals);\") || (operation_string == \"return length(individuals);\")) && (!uses_empty || (empty == 0.0)))\n\t{\n\t\t// simple abundance: a count of the individuals in each cell\n\t\tfor (int64_t bin_index = 0; bin_index < result_count; ++bin_index)\n\t\t{\n\t\t\tstd::vector<Individual *> &individuals = binned_individuals[bin_index];\n\t\t\t\n\t\t\tresult_data[bin_index] = individuals.size();\n\t\t}\n\t}\n\telse if ((((operation_string == \"1.0;\") || (operation_string == \"1;\") || (operation_string == \"T;\")) && uses_empty && (empty == 0.0)))\n\t{\n\t\t// simple presence/absence: 1.0 if individuals are present, 0.0 otherwise\n\t\tfor (int64_t bin_index = 0; bin_index < result_count; ++bin_index)\n\t\t{\n\t\t\tstd::vector<Individual *> &individuals = binned_individuals[bin_index];\n\t\t\t\n\t\t\tresult_data[bin_index] = ((individuals.size() == 0) ? 0.0 : 1.0);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// run the lambda on each bin, which does not depend upon the spatiality\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"SLiM_ExecuteFunction_summarizeIndividuals(): running Eidos lambda\");\n\t\t\n\t\tEidosValue_String *lambda_value_singleton = (EidosValue_String *)operation_value;\n\t\tEidosScript *script = lambda_value_singleton->CachedScript();\n\t\t\n\t\t// Errors in lambdas should be reported for the lambda script, not for the calling script,\n\t\t// if possible.  In the GUI this does not work well, however; there, errors should be\n\t\t// reported as occurring in the call to sapply().  Here we save off the current\n\t\t// error context and set up the error context for reporting errors inside the lambda,\n\t\t// in case that is possible; see how exceptions are handled below.\n\t\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\t\n\t\t// We try to do tokenization and parsing once per script, by caching the script inside the EidosValue_String_singleton instance\n\t\tif (!script)\n\t\t{\n\t\t\tscript = new EidosScript(operation_string);\n\t\t\t\n\t\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\t\t\n\t\t\ttry\n\t\t\t{\n\t\t\t\tscript->Tokenize();\n\t\t\t\tscript->ParseInterpreterBlockToAST(false);\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tif (gEidosTerminateThrows)\n\t\t\t\t{\n\t\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\t\tTranslateErrorContextToUserScript(\"SLiM_ExecuteFunction_summarizeIndividuals()\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdelete script;\n\t\t\t\t\n\t\t\t\tthrow;\n\t\t\t}\n\t\t\t\n\t\t\tif (lambda_value_singleton)\n\t\t\t\tlambda_value_singleton->SetCachedScript(script);\n\t\t}\n\t\t\n\t\t// Execute inside try/catch so we can handle errors well\n\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\t\n\t\tEidosValue_Object individuals_vec(gSLiM_Individual_Class);\n\t\tindividuals_vec.StackAllocated();\n\t\t\n\t\ttry\n\t\t{\n\t\t\tEidosSymbolTable &interpreter_symbols = p_interpreter.SymbolTable();\t\t\t\t\t\t// use our own symbol table\n\t\t\tEidosSymbolTable constants(EidosSymbolTableType::kContextConstantsTable, &interpreter_symbols);\n\t\t\tEidosSymbolTable symbols(EidosSymbolTableType::kLocalVariablesTable, &constants);\t// add a variables symbol table on top, shared across all invocations\n\t\t\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\t\t\t\t\t\t\t\t// use our own function map\n\t\t\tEidosInterpreter interpreter(*script, symbols, function_map, &community, p_interpreter.ExecutionOutputStream(), p_interpreter.ErrorOutputStream()\n#ifdef SLIMGUI\n\t\t\t\t, p_interpreter.check_infinite_loops_\n#endif\n\t\t\t\t);\n\t\t\t\n\t\t\t// We set up a \"constant\" value for `individuals` that refers to the stack-allocated object vector made above\n\t\t\t// For each grid cell we will munge the contents of that vector, without having to touch the symbol table again\n\t\t\t// BCH 11/7/2025: Note that we now check for conflicts with this symbol up at the top\n\t\t\tconstants.InitializeConstantSymbolEntry(gID_individuals, EidosValue_SP(&individuals_vec));\n\t\t\t\n\t\t\t// go through the individuals and tally them\n\t\t\tfor (int64_t bin_index = 0; bin_index < result_count; ++bin_index)\n\t\t\t{\n\t\t\t\tstd::vector<Individual *> &bin_individuals = binned_individuals[bin_index];\n\t\t\t\tsize_t bin_individuals_count = bin_individuals.size();\n\t\t\t\t\n\t\t\t\tif (uses_empty && (bin_individuals_count == 0))\n\t\t\t\t{\n\t\t\t\t\tresult_data[bin_index] = empty;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Set the variable \"individuals\" to the focal individuals.  We want to do this as efficiently as possible.\n\t\t\t\t\t// Best would be to swap() bin_individuals into individuals_vec, which maybe we will do eventually.  In the\n\t\t\t\t\t// meantime, we use clear() to release the old values in the vector, resize_no_initialize() to expand to the\n\t\t\t\t\t// needed capacity without initializing, and set_object_element_no_check_NORR() to put values into their\n\t\t\t\t\t// slots without any checks.  Note that Individual is not under retain/release, which simplifies things.\n\t\t\t\t\tIndividual **bin_individuals_data = bin_individuals.data();\n\t\t\t\t\t\n\t\t\t\t\tindividuals_vec.clear();\n\t\t\t\t\tindividuals_vec.resize_no_initialize(bin_individuals_count);\n\t\t\t\t\t\n\t\t\t\t\tfor (size_t index = 0; index < bin_individuals_count; ++index)\n\t\t\t\t\t\tindividuals_vec.set_object_element_no_check_NORR(bin_individuals_data[index], index);\n\t\t\t\t\t\n\t\t\t\t\t// Get the result.  BEWARE!  This calls causes re-entry into the Eidos interpreter, which is not usually\n\t\t\t\t\t// possible since Eidos does not support multithreaded usage.  This is therefore a key failure point for\n\t\t\t\t\t// bugs that would otherwise not manifest.\n\t\t\t\t\tEidosValue_SP &&return_value_SP = interpreter.EvaluateInterpreterBlock(false, true);\t\t// do not print output, return the last statement value\n\t\t\t\t\t\n\t\t\t\t\tif ((return_value_SP->Count() == 1) && ((return_value_SP->Type() == EidosValueType::kValueFloat) || (return_value_SP->Type() == EidosValueType::kValueInt) || (return_value_SP->Type() == EidosValueType::kValueLogical)))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult_data[bin_index] = return_value_SP->FloatAtIndex_CAST(0, nullptr);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_summarizeIndividuals): the lambda operation must return a singleton float, integer, or logical.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\t// If exceptions throw, then we want to set up the error information to highlight the\n\t\t\t// function call that failed, since we can't highlight the actual error.  (If exceptions\n\t\t\t// don't throw, this catch block will never be hit; exit() will already have been called\n\t\t\t// and the error will have been reported from the context of the lambda script string.)\n\t\t\tif (gEidosTerminateThrows)\n\t\t\t{\n\t\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t\t{\n\t\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\t\tTranslateErrorContextToUserScript(\"SLiM_ExecuteFunction_summarizeIndividuals()\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (!lambda_value_singleton)\n\t\t\t\tdelete script;\n\t\t\t\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\t// Restore the normal error context in the event that no exception occurring within the lambda\n\t\tgEidosErrorContext = error_context_save;\n\t\t\n\t\tif (!lambda_value_singleton)\n\t\t\tdelete script;\n\t}\n\t\n\t// rescale values if requested with perUnitArea; this post-processing code is shared with the lambda case\n\tif (perUnitArea)\n\t{\n\t\tif (spatiality == 1)\n\t\t{\n\t\t\t// first scale end values by the amount of area they contain relative to interior grid cells\n\t\t\t*(result_data) *= 2.0;\n\t\t\t*(result_data + dims[0] - 1) *= 2.0;\n\t\t\t\n\t\t\t// now divide each value by the area encompassed by an interior grid cell, which is a fraction of the total spatialBounds area\n\t\t\tdouble total_area = spatialBounds[1] - spatialBounds[0];\n\t\t\tdouble interior_cell_count = dims[0] - 1;\t\t\t\t\t\t\t\t// -1 because end cells combine to make one fewer cell\n\t\t\tdouble interior_cell_area = total_area / interior_cell_count;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tresult_data[value_index] /= interior_cell_area;\n\t\t}\n\t\telse if (spatiality == 2)\n\t\t{\n\t\t\t// first scale edge and corner values by the amount of area they contain relative to interior grid cells\n\t\t\t// note that these loops hit the corners twice, intentionally; they contain 1/4 the area of interior cells\n\t\t\tfor (int row = 0; row < dims[0]; row++)\n\t\t\t{\n\t\t\t\t*(result_data + row) *= 2.0;\n\t\t\t\t*(result_data + row + (dims[1] - 1) * dims[0]) *= 2.0;\n\t\t\t}\n\t\t\tfor (int col = 0; col < dims[1]; col++)\n\t\t\t{\n\t\t\t\t*(result_data + col * dims[0]) *= 2.0;\n\t\t\t\t*(result_data + (dims[0] - 1) + col * dims[0]) *= 2.0;\n\t\t\t}\n\t\t\t\n\t\t\t// now divide each value by the area encompassed by an interior grid cell, which is a fraction of the total spatialBounds area\n\t\t\tdouble total_area = (spatialBounds[1] - spatialBounds[0]) * (spatialBounds[3] - spatialBounds[2]);\t\t// width * height\n\t\t\tdouble interior_cell_count = (dims[0] - 1) * (dims[1] - 1);\t\t\t\t\t\t\t\t\t\t\t\t// -1 because edge/corner cells combine to make one fewer rows/columns\n\t\t\tdouble interior_cell_area = total_area / interior_cell_count;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tresult_data[value_index] /= interior_cell_area;\n\t\t}\n\t\telse if (spatiality == 3)\n\t\t{\n\t\t\t// first scale edge and corner values by the amount of area they contain relative to interior grid cells\n\t\t\t// note that this hits the corners three times, intentionally; they contain 1/8 the area of interior cells\n\t\t\t// we do this by scanning through the whole array; it's less efficient but the logic is much simpler\n\t\t\tfor (int row = 0; row < dims[0]; row++)\n\t\t\t{\n\t\t\t\tfor (int col = 0; col < dims[1]; col++)\n\t\t\t\t{\n\t\t\t\t\tfor (int plane = 0; plane < dims[2]; plane++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint extreme_row = ((row == 0) || (row == dims[0] - 1)) ? 1 : 0;\n\t\t\t\t\t\tint extreme_col = ((col == 0) || (col == dims[1] - 1)) ? 1 : 0;\n\t\t\t\t\t\tint extreme_plane = ((plane == 0) || (plane == dims[2] - 1)) ? 1 : 0;\n\t\t\t\t\t\tint extremity_sum = extreme_row + extreme_col + extreme_plane;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (extremity_sum == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble factor = 1.0 * (extreme_row ? 2.0 : 1.0) * (extreme_col ? 2.0 : 1.0) * (extreme_plane ? 2.0 : 1.0);\n\t\t\t\t\t\t\n\t\t\t\t\t\t*(result_data + row + col * dims[0] + plane * dims[0] * dims[1]) *= factor;\t// (dims[0] - 1 - row) not row, actually, but we can do it flipped, doesn't matter\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// now divide each value by the area encompassed by an interior grid cell, which is a fraction of the total spatialBounds area\n\t\t\tdouble total_area = (spatialBounds[1] - spatialBounds[0]) * (spatialBounds[3] - spatialBounds[2]) * (spatialBounds[5] - spatialBounds[4]);\t\t// width * height * depth\n\t\t\tdouble interior_cell_count = (dims[0] - 1) * (dims[1] - 1) * (dims[2] - 1);\t\t\t\t\t\t\t// -1 because edge/corner cells combine to make one fewer rows/columns\n\t\t\tdouble interior_cell_area = total_area / interior_cell_count;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tresult_data[value_index] /= interior_cell_area;\n\t\t}\n\t}\n\n\treturn EidosValue_SP(result_vec);\n}\n\n// (object<Dictionary>$)treeSeqMetadata(string$ filePath, [logical$ userData=T])\nEidosValue_SP SLiM_ExecuteFunction_treeSeqMetadata(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n\t\n\ttsk_table_collection_t temp_tables;\n\t\n\tint ret = tsk_table_collection_load(&temp_tables, file_path.c_str(), TSK_LOAD_SKIP_TABLES | TSK_LOAD_SKIP_REFERENCE_SEQUENCE);\n\tif (ret != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): tree-sequence file at \" << file_path << \" could not be read; error \" << ret << \" from tsk_table_collection_load().\" << EidosTerminate();\n\t\n\tif (temp_tables.metadata_schema_length == 0)\n\t{\n\t\ttsk_table_collection_free(&temp_tables);\n\t\t\n\t\t// With no schema, error out\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): no metadata schema present in file \" << file_path << \"; a JSON schema is required.\" << EidosTerminate();\n\t}\n\t\n\tif (temp_tables.metadata_length == 0)\n\t{\n\t\ttsk_table_collection_free(&temp_tables);\n\t\t\n\t\t// With no metadata, return an empty dictionary.  BCH 1/17/2025: prior to SLiM 5, this erroneously returned object<Dictionary>(0)\n\t\tEidosDictionaryRetained *objectElement = new EidosDictionaryRetained();\n\t\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDictionaryRetained_Class));\n\t\t\n\t\tobjectElement->Release();\t// retained by result_SP\n\t\treturn result_SP;\n\t}\n\t\n\tstd::string metadata_schema_string(temp_tables.metadata_schema, temp_tables.metadata_schema_length);\n\tnlohmann::json metadata_schema;\n\t\n\ttry {\n\t\tmetadata_schema = nlohmann::json::parse(metadata_schema_string);\n\t} catch (...) {\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the metadata schema must be a JSON string.\" << EidosTerminate();\n\t}\n\t\n\tstd::string codec = metadata_schema[\"codec\"];\n\t\n\tif (codec != \"json\")\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the metadata codec must be 'json'.\" << EidosTerminate();\n\t\n\tstd::string metadata_string(temp_tables.metadata, temp_tables.metadata_length);\n\tnlohmann::json metadata;\n\t\n\ttsk_table_collection_free(&temp_tables);\n\t\n\ttry {\n\t\tmetadata = nlohmann::json::parse(metadata_string);\n\t} catch (...) {\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the metadata must be a JSON string.\" << EidosTerminate();\n\t}\n\t\n\tEidosValue *userData_value = p_arguments[1].get();\n\tbool userData = userData_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (userData)\n\t{\n\t\tif (!metadata.contains(\"SLiM\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the user metadata was requested, but the top-level metadata does not contain a 'SLiM' key.\" << EidosTerminate();\n\t\t\n\t\tmetadata = metadata[\"SLiM\"];\n\t\tif (metadata.type() != nlohmann::json::value_t::object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the user metadata was requested, but the 'SLiM' key is not of type object.\" << EidosTerminate();\n\t\t\n\t\tif (!metadata.contains(\"user_metadata\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the user metadata was requested, but the 'SLiM' dictionary does not contain a 'user_metadata' key.\" << EidosTerminate();\n\t\t\n\t\tmetadata = metadata[\"user_metadata\"];\n\t\tif (metadata.type() != nlohmann::json::value_t::object)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction_treeSeqMetadata): the user metadata was requested, but the 'user_metadata' key is not of type object.\" << EidosTerminate();\n\t}\n\t\n\tEidosDictionaryRetained *objectElement = new EidosDictionaryRetained();\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDictionaryRetained_Class));\n\t\n\tobjectElement->Release();\t// retained by result_SP\n\tobjectElement->AddJSONFrom(metadata);\n\tobjectElement->ContentsChanged(\"treeSeqMetadata()\");\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_functions.h",
    "content": "//\n//  slim_functions.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/26/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef slim_functions_h\n#define slim_functions_h\n\n\n#include <stdio.h>\n\n#include \"eidos_value.h\"\n#include \"eidos_interpreter.h\"\n\n\n// SLiM built-in functions; the signatures for these are declared in Community::SLiMFunctionSignatures()\n\nEidosValue_SP SLiM_ExecuteFunction_codonsToAminoAcids(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_mm16To256(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_mmJukesCantor(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_mmKimura(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_nucleotideCounts(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_nucleotideFrequencies(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_nucleotidesToCodons(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_randomNucleotides(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_codonsToNucleotides(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\nEidosValue_SP SLiM_ExecuteFunction_summarizeIndividuals(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction_treeSeqMetadata(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n#endif /* slim_functions_h */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_globals.cpp",
    "content": "//\n//  slim_globals.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 1/4/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_globals.h\"\n\n#include \"chromosome.h\"\n#include \"individual.h\"\n#include \"interaction_type.h\"\n#include \"haplosome.h\"\n#include \"genomic_element.h\"\n#include \"genomic_element_type.h\"\n#include \"log_file.h\"\n#include \"mutation.h\"\n#include \"mutation_type.h\"\n#include \"slim_eidos_block.h\"\n#include \"community.h\"\n#include \"spatial_map.h\"\n#include \"species.h\"\n#include \"substitution.h\"\n#include \"subpopulation.h\"\n\n#include \"mutation_run.h\"\n\n#include <string>\n#include <vector>\n#include <cstdio>\n#include <fstream>\n#include <algorithm>\n\n#include \"json.hpp\"\n\n\n// Require 64-bit; apparently there are some issues on 32-bit, and nobody should be doing that anyway\nstatic_assert(sizeof(char *) == 8, \"SLiM must be built for 64-bit, not 32-bit.\");\n\n\nEidosValue_String_SP gStaticEidosValue_StringA;\nEidosValue_String_SP gStaticEidosValue_StringC;\nEidosValue_String_SP gStaticEidosValue_StringG;\nEidosValue_String_SP gStaticEidosValue_StringT;\n\nconst std::string gStr_strand1(\"strand1\");\nconst std::string gStr_strand2(\"strand2\");\nconst std::string gStr_breaks1(\"breaks1\");\nconst std::string gStr_strand3(\"strand3\");\nconst std::string gStr_strand4(\"strand4\");\nconst std::string gStr_breaks2(\"breaks2\");\n\nvoid SLiM_WarmUp(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SLiM_WarmUp(): illegal when parallel\");\n\t\n\tstatic bool been_here = false;\n\t\n\tif (!been_here)\n\t{\n\t\tbeen_here = true;\n\t\t\n\t\t// Create the global class objects for all SLiM Eidos classes, from superclass to subclass\n\t\t// This breaks encapsulation, kind of, but it needs to be done here, in order, so that superclass objects exist,\n\t\t// and so that the global string names for the classes have already been set up by C++'s static initialization\n\t\tgSLiM_Chromosome_Class =\t\t\tnew Chromosome_Class(\t\t\tgStr_Chromosome,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgSLiM_Individual_Class =\t\t\tnew Individual_Class(\t\t\tgEidosStr_Individual,\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_InteractionType_Class =\t\tnew InteractionType_Class(\t\tgStr_InteractionType,\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_Haplosome_Class =\t\t\t\tnew Haplosome_Class(\t\t\tgEidosStr_Haplosome,\t\tgEidosObject_Class);\n\t\tgSLiM_GenomicElement_Class =\t\tnew GenomicElement_Class(\t\tgStr_GenomicElement,\t\tgEidosObject_Class);\n\t\tgSLiM_GenomicElementType_Class =\tnew GenomicElementType_Class(\tgStr_GenomicElementType,\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_LogFile_Class =\t\t\t\tnew LogFile_Class(\t\t\t\tgStr_LogFile,\t\t\t\tgEidosDictionaryRetained_Class);\n\t\tgSLiM_Mutation_Class =\t\t\t\tnew Mutation_Class(\t\t\t\tgEidosStr_Mutation,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgSLiM_MutationType_Class =\t\t\tnew MutationType_Class(\t\t\tgStr_MutationType,\t\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_SLiMEidosBlock_Class =\t\tnew SLiMEidosBlock_Class(\t\tgStr_SLiMEidosBlock,\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_Community_Class =\t\t\t\tnew Community_Class(\t\t\tgStr_Community,\t\t\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_SpatialMap_Class =\t\t\tnew SpatialMap_Class(\t\t\tgStr_SpatialMap,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgSLiM_Species_Class =\t\t\t\tnew Species_Class(\t\t\t\tgStr_Species,\t\t\t\tgEidosDictionaryUnretained_Class);\n\t\tgSLiM_Substitution_Class =\t\t\tnew Substitution_Class(\t\t\tgStr_Substitution,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgSLiM_Subpopulation_Class =\t\t\tnew Subpopulation_Class(\t\tgStr_Subpopulation,\t\t\tgEidosDictionaryUnretained_Class);\n\t\t\n\t\t// Tell all registered classes to initialize their dispatch tables; doing this here saves a flag check later\n\t\t// Note that this can't be done in the EidosClass constructor because the vtable is not set up for the subclass yet\n\t\tfor (EidosClass *eidos_class : EidosClass::RegisteredClasses(true, true))\n\t\t\teidos_class->CacheDispatchTables();\n\t\t\n\t\t// Set up our shared pool for Mutation objects\n\t\tSLiM_CreateMutationBlock();\n\t\t\n\t\t// Make sure the Eidos context information has already been configured; this has to be done first thing,\n\t\t// so that any customizations to Eidos that SLiM introduces take effect before anything else happens\n\t\tif (gEidosContextVersion == 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) SLiM_ConfigureContext() was not called before SLiMWarmUp().\" << EidosTerminate();\n\t\t\n\t\t// Allocate global permanents\n\t\tgStaticEidosValue_StringA = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_A));\n\t\tgStaticEidosValue_StringC = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_C));\n\t\tgStaticEidosValue_StringG = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_G));\n\t\tgStaticEidosValue_StringT = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gStr_T));\n\t\t\n#if DO_MEMORY_CHECKS\n\t\t// Check for a memory limit and prepare for memory-limit testing\n\t\tEidos_CheckRSSAgainstMax(\"SLiM_WarmUp()\", \"This internal check should never fail!\");\n#endif\n\t\t\n\t\t//std::cout << \"sizeof(Individual) == \" << sizeof(Individual) << std::endl;\n\t\t//std::cout << \"sizeof(Mutation) == \" << sizeof(Mutation) << std::endl;\n\t\t\n\t\t//std::cout << \"sizeof(int) == \" << sizeof(int) << std::endl;\n\t\t//std::cout << \"sizeof(long) == \" << sizeof(long) << std::endl;\n\t\t//std::cout << \"sizeof(size_t) == \" << sizeof(size_t) << std::endl;\n\t\t\n\t\t// Test that our tskit metadata schemas are valid JSON, and print them out formatted for debugging purposes if desired\n\t\tnlohmann::json top_level_schema, edge_schema, site_schema, mutation_schema, node_schema, individual_schema, population_schema;\n\t\t\n\t\ttry {\n\t\t\ttop_level_schema = nlohmann::json::parse(gSLiM_tsk_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tif (gSLiM_tsk_edge_metadata_schema.length())\n\t\t\t\tedge_schema = nlohmann::json::parse(gSLiM_tsk_edge_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_edge_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tif (gSLiM_tsk_site_metadata_schema.length())\n\t\t\t\tsite_schema = nlohmann::json::parse(gSLiM_tsk_site_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_site_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tmutation_schema = nlohmann::json::parse(gSLiM_tsk_mutation_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_mutation_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tnode_schema = nlohmann::json::parse(gSLiM_tsk_node_metadata_schema_FORMAT);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_node_metadata_schema_FORMAT must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tindividual_schema = nlohmann::json::parse(gSLiM_tsk_individual_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_individual_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\ttry {\n\t\t\tpopulation_schema = nlohmann::json::parse(gSLiM_tsk_population_metadata_schema);\n\t\t}  catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_WarmUp): (internal error) gSLiM_tsk_population_metadata_schema must be a JSON string.\" << EidosTerminate();\n\t\t}\n\t\t\n#if 0\n#warning printing of JSON schemas should be disabled in a production build\n\t\tstd::cout << \"gSLiM_tsk_metadata_schema == \" << std::endl << top_level_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_edge_metadata_schema == \" << std::endl << edge_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_site_metadata_schema == \" << std::endl << site_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_mutation_metadata_schema == \" << std::endl << mutation_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_node_metadata_schema_FORMAT == \" << std::endl << node_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_individual_metadata_schema == \" << std::endl << individual_schema.dump(4) << std::endl << std::endl;\n\t\tstd::cout << \"gSLiM_tsk_population_metadata_schema == \" << std::endl << population_schema.dump(4) << std::endl << std::endl;\n#endif\n\t}\n}\n\n\n// ostringstreams for SLiM output; see the header for details\nstd::ostringstream gSLiMOut;\nstd::ostringstream gSLiMError;\n\n#ifdef SLIMGUI\nstd::ostringstream gSLiMScheduling;\n#endif\n\n\n#pragma mark -\n#pragma mark Types and max values\n#pragma mark -\n\n// Functions for casting from Eidos ints (int64_t) to SLiM int types safely\nvoid SLiM_RaiseTickRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaiseTickRangeError): value \" << p_long_value << \" for a tick index or duration is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaiseAgeRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaiseAgeRangeError): value \" << p_long_value << \" for an individual age is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaisePositionRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaisePositionRangeError): value \" << p_long_value << \" for a chromosome position or length is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaisePedigreeIDRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaisePedigreeIDRangeError): value \" << p_long_value << \" for an individual pedigree ID is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaiseObjectidRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaiseObjectidRangeError): value \" << p_long_value << \" for a SLiM object identifier value is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaisePopsizeRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaisePopsizeRangeError): value \" << p_long_value << \" for a subpopulation size, individual index, or haplosome index is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaiseUsertagRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaiseUsertagRangeError): value \" << p_long_value << \" for a user-supplied tag is out of range.\" << EidosTerminate();\n}\n\nvoid SLiM_RaisePolymorphismidRangeError(int64_t p_long_value)\n{\n\tEIDOS_TERMINATION << \"ERROR (SLiM_RaisePolymorphismidRangeError): value \" << p_long_value << \" for a polymorphism identifier is out of range.\" << EidosTerminate();\n}\n\nCommunity &SLiM_GetCommunityFromInterpreter(EidosInterpreter &p_interpreter)\n{\n#if DEBUG\n\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\tCommunity *community = dynamic_cast<Community *>(p_interpreter.Context());\n#else\n\tCommunity *community = (Community *)(p_interpreter.Context());\n#endif\n\t\n\tif (!community)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_GetCommunityFromInterpreter): (internal error) the community is not registered as the context pointer.\" << EidosTerminate();\n\t\n\treturn *community;\n}\n\nslim_objectid_t SLiM_ExtractObjectIDFromEidosValue_is(EidosValue *p_value, int p_index, char p_prefix_char)\n{\n\treturn (p_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(p_value->IntAtIndex_NOCAST(p_index, nullptr)) : SLiMEidosScript::ExtractIDFromStringWithPrefix(p_value->StringAtIndex_NOCAST(p_index, nullptr), p_prefix_char, nullptr);\n}\n\nMutationType *SLiM_ExtractMutationTypeFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name)\n{\n\tMutationType *found_muttype = nullptr;\n\t\n\tif (p_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tslim_objectid_t mutation_type_id = SLiMCastToObjectidTypeOrRaise(p_value->IntAtIndex_NOCAST(p_index, nullptr));\n\t\t\n\t\tif (p_species)\n\t\t{\n\t\t\t// Look in the species, if one was supplied\n\t\t\tfound_muttype = p_species->MutationTypeWithID(mutation_type_id);\n\t\t\t\n\t\t\tif (!found_muttype)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractMutationTypeFromEidosValue_io): \" << p_method_name << \" mutation type m\" << mutation_type_id << \" not defined in the focal species.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, look in all species in the community\n\t\t\tfor (Species *species : p_community->AllSpecies())\n\t\t\t{\n\t\t\t\tfound_muttype = species->MutationTypeWithID(mutation_type_id);\n\t\t\t\t\n\t\t\t\tif (found_muttype)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!found_muttype)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractMutationTypeFromEidosValue_io): \" << p_method_name << \" mutation type m\" << mutation_type_id << \" not defined.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n#if DEBUG\n\t\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\t\t// the class of the object here should be guaranteed by the caller anyway\n\t\tfound_muttype = dynamic_cast<MutationType *>(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#else\n\t\tfound_muttype = (MutationType *)(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#endif\n\t\t\n\t\tif (!found_muttype)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractMutationTypeFromEidosValue_io): (internal error) \" << p_method_name << \" was passed an object that is not a mutation type.\" << EidosTerminate();\n\t\t\n\t\tif (p_species && (&found_muttype->species_ != p_species))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractMutationTypeFromEidosValue_io): \" << p_method_name << \" mutation type m\" << found_muttype->mutation_type_id_ << \" not defined in the focal species.\" << EidosTerminate();\n\t}\n\t\n\treturn found_muttype;\n}\n\nGenomicElementType *SLiM_ExtractGenomicElementTypeFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name)\n{\n\tGenomicElementType *found_getype = nullptr;\n\t\n\tif (p_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tslim_objectid_t getype_id = SLiMCastToObjectidTypeOrRaise(p_value->IntAtIndex_NOCAST(p_index, nullptr));\n\t\t\n\t\tif (p_species)\n\t\t{\n\t\t\t// Look in the species, if one was supplied\n\t\t\tfound_getype = p_species->GenomicElementTypeWithID(getype_id);\n\t\t\t\n\t\t\tif (!found_getype)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractGenomicElementTypeFromEidosValue_io): \" << p_method_name << \" genomic element type g\" << getype_id << \" not defined in the focal species.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, look in all species in the community\n\t\t\tfor (Species *species : p_community->AllSpecies())\n\t\t\t{\n\t\t\t\tfound_getype = species->GenomicElementTypeWithID(getype_id);\n\t\t\t\t\n\t\t\t\tif (found_getype)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!found_getype)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractGenomicElementTypeFromEidosValue_io): \" << p_method_name << \" genomic element type g\" << getype_id << \" not defined.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n#if DEBUG\n\t\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\t\t// the class of the object here should be guaranteed by the caller anyway\n\t\tfound_getype = dynamic_cast<GenomicElementType *>(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#else\n\t\tfound_getype = (GenomicElementType *)(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#endif\n\t\t\n\t\tif (!found_getype)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractGenomicElementTypeFromEidosValue_io): (internal error) \" << p_method_name << \" was passed an object that is not a genomic element type.\" << EidosTerminate();\n\t\t\n\t\tif (p_species && (&found_getype->species_ != p_species))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractGenomicElementTypeFromEidosValue_io): \" << p_method_name << \" genomic element type g\" << found_getype->genomic_element_type_id_ << \" not defined in the focal species.\" << EidosTerminate();\n\t}\n\t\n\treturn found_getype;\n}\n\nSubpopulation *SLiM_ExtractSubpopulationFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name)\n{\n\tSubpopulation *found_subpop = nullptr;\n\t\n\tif (p_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tslim_objectid_t source_subpop_id = SLiMCastToObjectidTypeOrRaise(p_value->IntAtIndex_NOCAST(p_index, nullptr));\n\t\t\n\t\tif (p_species)\n\t\t{\n\t\t\t// Look in the species, if one was supplied\n\t\t\tfound_subpop = p_species->SubpopulationWithID(source_subpop_id);\n\t\t\t\n\t\t\tif (!found_subpop)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSubpopulationFromEidosValue_io): \" << p_method_name << \" subpopulation p\" << source_subpop_id << \" not defined in the focal species.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, look in all species in the community\n\t\t\tfor (Species *species : p_community->AllSpecies())\n\t\t\t{\n\t\t\t\tfound_subpop = species->SubpopulationWithID(source_subpop_id);\n\t\t\t\t\n\t\t\t\tif (found_subpop)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!found_subpop)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSubpopulationFromEidosValue_io): \" << p_method_name << \" subpopulation p\" << source_subpop_id << \" not defined.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n#if DEBUG\n\t\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\t\t// the class of the object here should be guaranteed by the caller anyway\n\t\tfound_subpop = dynamic_cast<Subpopulation *>(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#else\n\t\tfound_subpop = (Subpopulation *)(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#endif\n\t\t\n\t\tif (!found_subpop)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSubpopulationFromEidosValue_io): (internal error) \" << p_method_name << \" was passed an object that is not a subpopulation.\" << EidosTerminate();\n\t\t\n\t\tif (p_species && (&found_subpop->species_ != p_species))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSubpopulationFromEidosValue_io): \" << p_method_name << \" subpopulation p\" << found_subpop->subpopulation_id_ << \" not defined in the focal species.\" << EidosTerminate();\n\t}\n\t\n\treturn found_subpop;\n}\n\nSLiMEidosBlock *SLiM_ExtractSLiMEidosBlockFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name)\n{\n\tSLiMEidosBlock *found_block = nullptr;\n\t\n\tif (p_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tslim_objectid_t block_id = SLiMCastToObjectidTypeOrRaise(p_value->IntAtIndex_NOCAST(p_index, nullptr));\n\t\tstd::vector<SLiMEidosBlock*> &script_blocks = p_community->AllScriptBlocks();\n\t\t\n\t\tfor (SLiMEidosBlock *temp_found_block : script_blocks)\n\t\t\tif (temp_found_block->block_id_ == block_id)\n\t\t\t{\n\t\t\t\tfound_block = temp_found_block;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\n\t\tif (!found_block)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSLiMEidosBlockFromEidosValue_io): \" << p_method_name << \" SLiMEidosBlock s\" << block_id << \" not defined.\" << EidosTerminate();\n\t}\n\telse\n\t{\n#if DEBUG\n\t\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\t\t// the class of the object here should be guaranteed by the caller anyway\n\t\tfound_block = dynamic_cast<SLiMEidosBlock *>(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#else\n\t\tfound_block = (SLiMEidosBlock *)(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#endif\n\t\t\n\t\tif (!found_block)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSLiMEidosBlockFromEidosValue_io): (internal error) \" << p_method_name << \" was passed an object that is not a SLiMEidosBlock.\" << EidosTerminate();\n\t\t\n\t}\n\t\n\tif (p_species && (found_block->species_spec_ != p_species))\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSLiMEidosBlockFromEidosValue_io): \" << p_method_name << \" SLiMEidosBlock s\" << found_block->block_id_ << \" not defined in the focal species.\" << EidosTerminate();\n\t\n\treturn found_block;\n}\n\nSpecies *SLiM_ExtractSpeciesFromEidosValue_No(EidosValue *p_value, int p_index, Community *p_community, const char *p_method_name)\n{\n\tSpecies *found_species = nullptr;\n\t\n\tif (p_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tconst std::vector<Species *> &all_species = p_community->AllSpecies();\n\t\t\n\t\tif (all_species.size() == 1)\n\t\t\tfound_species = all_species[0];\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSpeciesFromEidosValue_No): \" << p_method_name << \" requires a species to be supplied in multispecies models.\" << EidosTerminate();\n\t}\n\telse\n\t{\n#if DEBUG\n\t\t// Use dynamic_cast<> only in DEBUG since it is hella slow\n\t\t// the class of the object here should be guaranteed by the caller anyway\n\t\tfound_species = dynamic_cast<Species *>(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#else\n\t\tfound_species = (Species *)(p_value->ObjectElementAtIndex_NOCAST(p_index, nullptr));\n#endif\n\t\t\n\t\tif (!found_species)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExtractSpeciesFromEidosValue_No): (internal error) \" << p_method_name << \" was passed an object that is not a Species.\" << EidosTerminate();\n\t}\n\t\n\treturn found_species;\n}\n\n\n#pragma mark -\n#pragma mark Memory management\n#pragma mark -\n\nvoid SumUpMemoryUsage_Species(SLiMMemoryUsage_Species &p_usage)\n{\n\tp_usage.totalMemoryUsage =\n\t\tp_usage.chromosomeObjects +\n\t\tp_usage.chromosomeMutationRateMaps +\n\t\tp_usage.chromosomeRecombinationRateMaps +\n\t\tp_usage.chromosomeAncestralSequence +\n\t\tp_usage.haplosomeObjects +\n\t\tp_usage.haplosomeExternalBuffers +\n\t\tp_usage.haplosomeUnusedPoolSpace +\n\t\tp_usage.haplosomeUnusedPoolBuffers +\n\t\tp_usage.genomicElementObjects +\n\t\tp_usage.genomicElementTypeObjects +\n\t\tp_usage.individualObjects +\n\t\tp_usage.individualJunkyardAndHaplosomes +\n\t\tp_usage.individualHaplosomeVectors +\n\t\tp_usage.individualUnusedPoolSpace +\n\t\tp_usage.mutationObjects +\n\t\tp_usage.mutationRunObjects +\n\t\tp_usage.mutationRunExternalBuffers +\n\t\tp_usage.mutationRunNonneutralCaches +\n\t\tp_usage.mutationRunUnusedPoolSpace +\n\t\tp_usage.mutationRunUnusedPoolBuffers +\n\t\tp_usage.mutationTypeObjects +\n\t\tp_usage.speciesObjects +\n\t\tp_usage.speciesTreeSeqTables +\n\t\tp_usage.subpopulationObjects +\n\t\tp_usage.subpopulationFitnessCaches +\n\t\tp_usage.subpopulationParentTables +\n\t\tp_usage.subpopulationSpatialMaps +\n\t\tp_usage.subpopulationSpatialMapsDisplay +\n\t\tp_usage.substitutionObjects;\n}\n\nvoid SumUpMemoryUsage_Community(SLiMMemoryUsage_Community &p_usage)\n{\n\tp_usage.totalMemoryUsage =\n\t\tp_usage.communityObjects +\n\t\tp_usage.mutationRefcountBuffer +\n\t\tp_usage.mutationUnusedPoolSpace +\n\t\tp_usage.interactionTypeObjects +\n\t\tp_usage.interactionTypeKDTrees +\n\t\tp_usage.interactionTypePositionCaches +\n\t\tp_usage.interactionTypeSparseVectorPool +\n\t\tp_usage.eidosASTNodePool +\n\t\tp_usage.eidosSymbolTablePool +\n\t\tp_usage.eidosValuePool + \n\t\tp_usage.fileBuffers;\n}\n\nvoid AccumulateMemoryUsageIntoTotal_Species(SLiMMemoryUsage_Species &p_usage, SLiMMemoryUsage_Species &p_total)\n{\n\t// p_total += p_usage;\n\t\n\tp_total.chromosomeObjects_count += p_usage.chromosomeObjects_count;\n\tp_total.chromosomeObjects += p_usage.chromosomeObjects;\n\tp_total.chromosomeMutationRateMaps += p_usage.chromosomeMutationRateMaps;\n\tp_total.chromosomeRecombinationRateMaps += p_usage.chromosomeRecombinationRateMaps;\n\tp_total.chromosomeAncestralSequence += p_usage.chromosomeAncestralSequence;\n\t\n\tp_total.haplosomeObjects_count += p_usage.haplosomeObjects_count;\n\tp_total.haplosomeObjects += p_usage.haplosomeObjects;\n\tp_total.haplosomeExternalBuffers += p_usage.haplosomeExternalBuffers;\n\tp_total.haplosomeUnusedPoolSpace += p_usage.haplosomeUnusedPoolSpace;\n\tp_total.haplosomeUnusedPoolBuffers += p_usage.haplosomeUnusedPoolBuffers;\n\t\n\tp_total.genomicElementObjects_count += p_usage.genomicElementObjects_count;\n\tp_total.genomicElementObjects += p_usage.genomicElementObjects;\n\t\n\tp_total.genomicElementTypeObjects_count += p_usage.genomicElementTypeObjects_count;\n\tp_total.genomicElementTypeObjects += p_usage.genomicElementTypeObjects;\n\t\n\tp_total.individualObjects_count += p_usage.individualObjects_count;\n\tp_total.individualObjects += p_usage.individualObjects;\n\tp_total.individualHaplosomeVectors += p_usage.individualHaplosomeVectors;\n\tp_total.individualJunkyardAndHaplosomes += p_usage.individualJunkyardAndHaplosomes;\n\tp_total.individualUnusedPoolSpace += p_usage.individualUnusedPoolSpace;\n\t\n\tp_total.mutationObjects_count += p_usage.mutationObjects_count;\n\tp_total.mutationObjects += p_usage.mutationObjects;\n\t\n\tp_total.mutationRunObjects_count += p_usage.mutationRunObjects_count;\n\tp_total.mutationRunObjects += p_usage.mutationRunObjects;\n\tp_total.mutationRunExternalBuffers += p_usage.mutationRunExternalBuffers;\n\tp_total.mutationRunNonneutralCaches += p_usage.mutationRunNonneutralCaches;\n\tp_total.mutationRunUnusedPoolSpace += p_usage.mutationRunUnusedPoolSpace;\n\tp_total.mutationRunUnusedPoolBuffers += p_usage.mutationRunUnusedPoolBuffers;\n\t\n\tp_total.mutationTypeObjects_count += p_usage.mutationTypeObjects_count;\n\tp_total.mutationTypeObjects += p_usage.mutationTypeObjects;\n\t\n\tp_total.speciesObjects_count += p_usage.speciesObjects_count;\n\tp_total.speciesObjects += p_usage.speciesObjects;\n\tp_total.speciesTreeSeqTables += p_usage.speciesTreeSeqTables;\n\t\n\tp_total.subpopulationObjects_count += p_usage.subpopulationObjects_count;\n\tp_total.subpopulationObjects += p_usage.subpopulationObjects;\n\tp_total.subpopulationFitnessCaches += p_usage.subpopulationFitnessCaches;\n\tp_total.subpopulationParentTables += p_usage.subpopulationParentTables;\n\tp_total.subpopulationSpatialMaps += p_usage.subpopulationSpatialMaps;\n\tp_total.subpopulationSpatialMapsDisplay += p_usage.subpopulationSpatialMapsDisplay;\n\t\n\tp_total.substitutionObjects_count += p_usage.substitutionObjects_count;\n\tp_total.substitutionObjects += p_usage.substitutionObjects;\n\t\n\tp_total.totalMemoryUsage += p_usage.totalMemoryUsage;\n}\n\nvoid AccumulateMemoryUsageIntoTotal_Community(SLiMMemoryUsage_Community &p_usage, SLiMMemoryUsage_Community &p_total)\n{\n\t// p_total += p_usage;\n\t\n\tp_total.communityObjects_count += p_usage.communityObjects_count;\n\tp_total.communityObjects += p_usage.communityObjects;\n\t\n\tp_total.mutationRefcountBuffer += p_usage.mutationRefcountBuffer;\n\tp_total.mutationUnusedPoolSpace += p_usage.mutationUnusedPoolSpace;\n\t\n\tp_total.interactionTypeObjects_count += p_usage.interactionTypeObjects_count;\n\tp_total.interactionTypeObjects += p_usage.interactionTypeObjects;\n\tp_total.interactionTypeKDTrees += p_usage.interactionTypeKDTrees;\n\tp_total.interactionTypePositionCaches += p_usage.interactionTypePositionCaches;\n\t\n\tp_total.interactionTypeSparseVectorPool += p_usage.interactionTypeSparseVectorPool;\n\t\n\tp_total.eidosASTNodePool += p_usage.eidosASTNodePool;\n\tp_total.eidosSymbolTablePool += p_usage.eidosSymbolTablePool;\n\tp_total.eidosValuePool += p_usage.eidosValuePool;\n\tp_total.fileBuffers += p_usage.fileBuffers;\n\t\n\tp_total.totalMemoryUsage += p_usage.totalMemoryUsage;\n}\n\n\n\n#pragma mark -\n#pragma mark Shared SLiM types and enumerations\n#pragma mark -\n\n// Verbosity, from the command-line option -l[ong]; defaults to 1 if -l[ong] is not used\nint64_t SLiM_verbosity_level = 1;\n\n// stream output for cycle stages\nstd::string StringForSLiMCycleStage(SLiMCycleStage p_stage)\n{\n\tswitch (p_stage)\n\t{\n\t\t// some of these are not user-visible\n\t\tcase SLiMCycleStage::kStagePreCycle: return \"begin\";\n\t\tcase SLiMCycleStage::kWFStage0ExecuteFirstScripts: return \"first\";\n\t\tcase SLiMCycleStage::kWFStage1ExecuteEarlyScripts: return \"early\";\n\t\tcase SLiMCycleStage::kWFStage2GenerateOffspring: return \"reproduction\";\n\t\tcase SLiMCycleStage::kWFStage3SwapGenerations: return \"swap\";\n\t\tcase SLiMCycleStage::kWFStage4RemoveFixedMutations: return \"tally\";\n\t\tcase SLiMCycleStage::kWFStage5ExecuteLateScripts: return \"late\";\n\t\tcase SLiMCycleStage::kWFStage6CalculateFitness: return \"fitness\";\n\t\tcase SLiMCycleStage::kWFStage7AdvanceTickCounter: return \"end\";\n\t\tcase SLiMCycleStage::kNonWFStage0ExecuteFirstScripts: return \"first\";\n\t\tcase SLiMCycleStage::kNonWFStage1GenerateOffspring: return \"reproduction\";\n\t\tcase SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts: return \"early\";\n\t\tcase SLiMCycleStage::kNonWFStage3CalculateFitness: return \"fitness\";\n\t\tcase SLiMCycleStage::kNonWFStage4SurvivalSelection: return \"survival\";\n\t\tcase SLiMCycleStage::kNonWFStage5RemoveFixedMutations: return \"tally\";\n\t\tcase SLiMCycleStage::kNonWFStage6ExecuteLateScripts: return \"late\";\n\t\tcase SLiMCycleStage::kNonWFStage7AdvanceTickCounter: return \"end\";\n\t\tcase SLiMCycleStage::kStagePostCycle: return \"console\";\n\t}\n\t\n\tEIDOS_TERMINATION << \"ERROR (StringForSLiMCycleStage): (internal) unrecognized cycle stage.\" << EidosTerminate();\n}\n\n// stream output for enumerations\nstd::string StringForChromosomeType(ChromosomeType p_chromosome_type)\n{\n\tswitch (p_chromosome_type)\n\t{\n\t\tcase ChromosomeType::kA_DiploidAutosome:\t\t\t\treturn gStr_A;\n\t\tcase ChromosomeType::kH_HaploidAutosome:\t\t\t\treturn gStr_H;\n\t\tcase ChromosomeType::kX_XSexChromosome:\t\t\t\t\treturn gStr_X;\n\t\tcase ChromosomeType::kY_YSexChromosome:\t\t\t\t\treturn gStr_Y;\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\t\t\t\t\treturn gStr_Z;\n\t\tcase ChromosomeType::kW_WSexChromosome:\t\t\t\t\treturn gStr_W;\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\t\treturn gStr_HF;\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\t\t\t\treturn gStr_FL;\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\t\t\treturn gStr_HM;\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\t\t\t\treturn gStr_ML;\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\treturn gStr_H_;\t\t// \"H-\"\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\t\treturn gStr__Y;\t\t// \"-Y\"\n\t}\n\tEIDOS_TERMINATION << \"ERROR (StringForChromosomeType): (internal error) unexpected p_chromosome_type value.\" << EidosTerminate();\n}\n\nChromosomeType ChromosomeTypeForString(std::string type)\n{\n\tif (type == gStr_A)\t\t\treturn ChromosomeType::kA_DiploidAutosome;\n\telse if (type == gStr_H)\treturn ChromosomeType::kH_HaploidAutosome;\n\telse if (type == gStr_X)\treturn ChromosomeType::kX_XSexChromosome;\n\telse if (type == gStr_Y)\treturn ChromosomeType::kY_YSexChromosome;\n\telse if (type == gStr_Z)\treturn ChromosomeType::kZ_ZSexChromosome;\n\telse if (type == gStr_W)\treturn ChromosomeType::kW_WSexChromosome;\n\telse if (type == gStr_HF)\treturn ChromosomeType::kHF_HaploidFemaleInherited;\n\telse if (type == gStr_FL)\treturn ChromosomeType::kFL_HaploidFemaleLine;\n\telse if (type == gStr_HM)\treturn ChromosomeType::kHM_HaploidMaleInherited;\n\telse if (type == gStr_ML)\treturn ChromosomeType::kML_HaploidMaleLine;\n\telse if (type == gStr_H_)\treturn ChromosomeType::kHNull_HaploidAutosomeWithNull;\n\telse if (type == gStr__Y)\treturn ChromosomeType::kNullY_YSexChromosomeWithNull;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (ChromosomeTypeForString): unrecognized chromosome type '\" << type << \"'.\" << EidosTerminate();\n}\n\nstd::ostream& operator<<(std::ostream& p_out, ChromosomeType p_chromosome_type)\n{\n\tp_out << StringForChromosomeType(p_chromosome_type);\n\treturn p_out;\n}\n\nstd::string StringForIndividualSex(IndividualSex p_sex)\n{\n\tswitch (p_sex)\n\t{\n\t\tcase IndividualSex::kUnspecified:\t\treturn \"*\";\n\t\tcase IndividualSex::kHermaphrodite:\t\treturn \"H\";\n\t\tcase IndividualSex::kFemale:\t\t\treturn \"F\";\t\t// SEX ONLY\n\t\tcase IndividualSex::kMale:\t\t\t\treturn \"M\";\t\t// SEX ONLY\n\t}\n\tEIDOS_TERMINATION << \"ERROR (StringForIndividualSex): (internal error) unexpected p_sex value.\" << EidosTerminate();\n}\n\nstd::ostream& operator<<(std::ostream& p_out, IndividualSex p_sex)\n{\n\tp_out << StringForIndividualSex(p_sex);\n\treturn p_out;\n}\n\nconst char gSLiM_Nucleotides[4] = {'A', 'C', 'G', 'T'};\n\n\n#pragma mark -\n#pragma mark NucleotideArray\n#pragma mark -\n\nNucleotideArray::NucleotideArray(std::size_t p_length, const int64_t *p_int_buffer) : length_(p_length)\n{\n\tbuffer_ = (uint64_t *)malloc(((length_ + 31) / 32) * sizeof(uint64_t));\n\tif (!buffer_)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\n\t// Eat 32 nucleotides at a time if we can\n\tstd::size_t index = 0, buf_index = 0;\n\t\n\tfor ( ; index < length_; index += 32)\n\t{\n\t\tuint64_t accumulator = 0;\n\t\t\n\t\tfor (std::size_t i = 0; i < 32; )\n\t\t{\n\t\t\tuint64_t nuc = (uint64_t)p_int_buffer[index + i];\n\t\t\t\n\t\t\tif (nuc > 3)\t// values < 0 will becomes > 3 after casting above\n\t\t\t{\n\t\t\t\tfree(buffer_);\n\t\t\t\tbuffer_ = nullptr;\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): integer nucleotide value \" << p_int_buffer[index + i] << \" must be 0 (A), 1 (C), 2 (G), or 3 (T).\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\taccumulator |= (nuc << (i * 2));\n\t\t\t\n\t\t\tif (index + ++i == length_)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tbuffer_[buf_index++] = accumulator;\n\t}\n}\n\nuint8_t *NucleotideArray::NucleotideCharToIntLookup(void)\n{\n\t// set up a lookup table for speed\n\tstatic uint8_t *nuc_lookup = nullptr;\n\t\n\tif (!nuc_lookup)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"NucleotideArray::NucleotideCharToIntLookup(): usage of statics\");\n\t\t\n\t\tnuc_lookup = (uint8_t *)malloc(256 * sizeof(uint8_t));\n\t\tif (!nuc_lookup)\n\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideCharToIntLookup): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\t\n\t\tfor (int i = 0; i < 256; ++i)\n\t\t\tnuc_lookup[i] = 4;\t// placeholder illegal value\n\t\t\n\t\tnuc_lookup[(int)('A')] = 0;\n\t\tnuc_lookup[(int)('C')] = 1;\n\t\tnuc_lookup[(int)('G')] = 2;\n\t\tnuc_lookup[(int)('T')] = 3;\n\t}\n\t\n\treturn nuc_lookup;\n}\n\nNucleotideArray::NucleotideArray(std::size_t p_length, const char *p_char_buffer) : length_(p_length)\n{\n\tuint8_t *nuc_lookup = NucleotideArray::NucleotideCharToIntLookup();\n\t\n\tbuffer_ = (uint64_t *)malloc(((length_ + 31) / 32) * sizeof(uint64_t));\n\tif (!buffer_)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\n\t// Eat 32 nucleotides at a time if we can\n\tstd::size_t index = 0, buf_index = 0;\n\t\n\tfor ( ; index < length_; index += 32)\n\t{\n\t\tuint64_t accumulator = 0;\n\t\t\n\t\tfor (std::size_t i = 0; i < 32; )\n\t\t{\n\t\t\tchar nuc_char = p_char_buffer[index + i];\n\t\t\tuint64_t nuc = nuc_lookup[(int)(unsigned char)(nuc_char)];\n\t\t\t\n\t\t\tif (nuc > 3)\n\t\t\t{\n\t\t\t\tfree(buffer_);\n\t\t\t\tbuffer_ = nullptr;\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): character nucleotide value '\" << nuc_char << \"' must be 'A', 'C', 'G', or 'T'.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\taccumulator |= (nuc << (i * 2));\n\t\t\t\n\t\t\tif (index + ++i == length_)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tbuffer_[buf_index++] = accumulator;\n\t}\n}\n\nNucleotideArray::NucleotideArray(std::size_t p_length, const std::string p_string_vector[]) : length_(p_length)\n{\n\tbuffer_ = (uint64_t *)malloc(((length_ + 31) / 32) * sizeof(uint64_t));\n\tif (!buffer_)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\n\t// Eat 32 nucleotides at a time if we can\n\tstd::size_t index = 0, buf_index = 0;\n\t\n\tfor ( ; index < length_; index += 32)\n\t{\n\t\tuint64_t accumulator = 0;\n\t\t\n\t\tfor (std::size_t i = 0; i < 32; )\n\t\t{\n\t\t\tconst std::string &nuc_string = p_string_vector[index + i];\n\t\t\tuint64_t nuc;\n\t\t\t\n\t\t\tif (nuc_string == gStr_A) nuc = 0;\n\t\t\telse if (nuc_string == gStr_C) nuc = 1;\n\t\t\telse if (nuc_string == gStr_G) nuc = 2;\n\t\t\telse if (nuc_string == gStr_T) nuc = 3;\n\t\t\telse\n\t\t\t{\n\t\t\t\tfree(buffer_);\n\t\t\t\tbuffer_ = nullptr;\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): string nucleotide character '\" << nuc_string << \"' must be 'A', 'C', 'G', or 'T'.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\taccumulator |= (nuc << (i * 2));\n\t\t\t\n\t\t\tif (index + ++i == length_)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tbuffer_[buf_index++] = accumulator;\n\t}\n}\n\nvoid NucleotideArray::SetNucleotideAtIndex(std::size_t p_index, uint64_t p_nuc)\n{\n\tif (p_nuc > 3)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::SetNucleotideAtIndex): integer nucleotide values must be 0 (A), 1 (C), 2 (G), or 3 (T).\" << EidosTerminate();\n\t\n\tuint64_t &chunk = buffer_[p_index / 32];\n\tint shift = ((p_index % 32) * 2);\n\tuint64_t mask = ((uint64_t)0x03) << shift;\n\tuint64_t nucbits = (uint64_t)p_nuc << shift;\n\t\n\tchunk = (chunk & ~mask) | nucbits;\n}\n\nEidosValue_SP NucleotideArray::NucleotidesAsIntegerVector(int64_t start, int64_t end)\n{\n\tint64_t length = end - start + 1;\n\t\n\tif (length == 1)\n\t{\n\t\tswitch (NucleotideAtIndex(start))\n\t\t{\n\t\t\tcase 0:\t\treturn gStaticEidosValue_Integer0;\n\t\t\tcase 1:\t\treturn gStaticEidosValue_Integer1;\n\t\t\tcase 2:\t\treturn gStaticEidosValue_Integer2;\n\t\t\tcase 3:\t\treturn gStaticEidosValue_Integer3;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotidesAsIntegerVector): nucleotide value out of range.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// return a vector of integers, 3 0 3 0\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length);\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t\tint_result->set_int_no_check(NucleotideAtIndex(start + value_index), value_index);\n\t\t\n\t\treturn EidosValue_SP(int_result);\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\nEidosValue_SP NucleotideArray::NucleotidesAsCodonVector(int64_t start, int64_t end, bool p_force_vector)\n{\n\tint64_t length = end - start + 1;\n\t\n\tif ((length == 3) && !p_force_vector)\n\t{\n\t\tint nuc1 = NucleotideAtIndex(start);\n\t\tint nuc2 = NucleotideAtIndex(start + 1);\n\t\tint nuc3 = NucleotideAtIndex(start + 2);\n\t\tint codon = nuc1 * 16 + nuc2 * 4 + nuc3;\t// 0..63\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(codon));\n\t}\n\telse\n\t{\n\t\t// return a vector of codons: nucleotide triplets compacted into a single integer value\n\t\tint64_t length_3 = length / 3;\n\t\t\n\t\tif (length % 3 != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotidesAsCodonVector): to obtain codons, the requested sequence length must be a multiple of 3.\" << EidosTerminate();\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)length_3);\n\t\t\n\t\tfor (int64_t value_index = 0; value_index < length_3; ++value_index)\n\t\t{\n\t\t\tint64_t codon_base = start + value_index * 3;\n\t\t\t\n\t\t\tint nuc1 = NucleotideAtIndex(codon_base);\n\t\t\tint nuc2 = NucleotideAtIndex(codon_base + 1);\n\t\t\tint nuc3 = NucleotideAtIndex(codon_base + 2);\n\t\t\tint codon = nuc1 * 16 + nuc2 * 4 + nuc3;\t// 0..63\n\t\t\t\n\t\t\tint_result->set_int_no_check(codon, value_index);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(int_result);\n\t}\n}\n\nEidosValue_SP NucleotideArray::NucleotidesAsStringVector(int64_t start, int64_t end)\n{\n\tint64_t length = end - start + 1;\n\t\n\tif (length == 1)\n\t{\n\t\tswitch (NucleotideAtIndex(start))\n\t\t{\n\t\t\tcase 0:\t\treturn gStaticEidosValue_StringA;\n\t\t\tcase 1:\t\treturn gStaticEidosValue_StringC;\n\t\t\tcase 2:\t\treturn gStaticEidosValue_StringG;\n\t\t\tcase 3:\t\treturn gStaticEidosValue_StringT;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotidesAsStringVector): nucleotide value out of range.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// return a vector of one-character strings, \"T\" \"A\" \"T\" \"A\"\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)length);\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t{\n\t\t\tswitch (NucleotideAtIndex(start + value_index))\n\t\t\t{\n\t\t\t\tcase 0:\t\tstring_result->PushString(gStr_A); break;\n\t\t\t\tcase 1:\t\tstring_result->PushString(gStr_C); break;\n\t\t\t\tcase 2:\t\tstring_result->PushString(gStr_G); break;\n\t\t\t\tcase 3:\t\tstring_result->PushString(gStr_T); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotidesAsStringVector): nucleotide value out of range.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\nEidosValue_SP NucleotideArray::NucleotidesAsStringSingleton(int64_t start, int64_t end)\n{\n\tint64_t length = end - start + 1;\n\t\n\tif (length == 1)\n\t{\n\t\tswitch (NucleotideAtIndex(start))\n\t\t{\n\t\t\tcase 0:\t\treturn gStaticEidosValue_StringA;\n\t\t\tcase 1:\t\treturn gStaticEidosValue_StringC;\n\t\t\tcase 2:\t\treturn gStaticEidosValue_StringG;\n\t\t\tcase 3:\t\treturn gStaticEidosValue_StringT;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotidesAsStringSingleton): nucleotide value out of range.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// return a singleton string for the whole sequence, \"TATA\"; we munge the std::string inside the EidosValue to avoid memory copying, very naughty\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\tstd::string &nuc_string = string_result->StringData_Mutable()[0];\n\t\t\n\t\tnuc_string.resize(length);\t// create space for all the nucleotides we will generate\n\t\t\n\t\tchar *nuc_string_ptr = &nuc_string[0];\t// data() returns a const pointer, but this is safe in C++11 and later\n\t\t\n\t\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\t\tnuc_string_ptr[value_index] = gSLiM_Nucleotides[NucleotideAtIndex(start + value_index)];\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\t\n\treturn gStaticEidosValueNULL;\n}\n\nvoid NucleotideArray::WriteNucleotidesToBuffer(char *buffer) const\n{\n\tfor (std::size_t index = 0; index < length_; ++index)\n\t\tbuffer[index] = gSLiM_Nucleotides[NucleotideAtIndex(index)];\n}\n\nvoid NucleotideArray::ReadNucleotidesFromBuffer(const char *buffer)\n{\n\tfor (std::size_t index = 0; index < length_; ++index)\n\t{\n\t\tchar nuc_char = buffer[index];\n\t\tuint64_t nuc_int;\n\t\t\n\t\tif (nuc_char == 'A')\t\tnuc_int = 0;\n\t\telse if (nuc_char == 'C')\tnuc_int = 1;\n\t\telse if (nuc_char == 'G')\tnuc_int = 2;\n\t\telse if (nuc_char == 'T')\tnuc_int = 3;\n\t\telse EIDOS_TERMINATION << \"ERROR (NucleotideArray::ReadNucleotidesFromBuffer): unexpected character '\" << nuc_char << \"' in nucleotide sequence.\" << EidosTerminate();\n\t\t\n\t\tSetNucleotideAtIndex(index, nuc_int);\n\t}\n}\n\nvoid NucleotideArray::WriteCompressedNucleotides(std::ostream &p_out) const\n{\n\t// First write out the size of the sequence, in nucleotides, as a 64-bit int\n\tint64_t ancestral_sequence_size = (int64_t)size();\n\t\n\tp_out.write(reinterpret_cast<char *>(&ancestral_sequence_size), sizeof ancestral_sequence_size);\n\t\n\t// Then write out the compressed nucleotides themselves\n\tstd::size_t size_bytes = ((ancestral_sequence_size + 31) / 32) * sizeof(uint64_t);\n\t\n\tp_out.write(reinterpret_cast<char *>(buffer_), size_bytes);\n}\n\nvoid NucleotideArray::ReadCompressedNucleotides(char **buffer, char *end)\n{\n\t// First read the size of the sequence, in nucleotides, as a 64-bit int\n\tint64_t ancestral_sequence_size;\n\t\n\tif ((*buffer) + sizeof(ancestral_sequence_size) > end)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::ReadCompressedNucleotides): out of buffer reading length.\" << EidosTerminate();\n\t\n\tancestral_sequence_size = *(int64_t *)*buffer;\n\t(*buffer) += sizeof(ancestral_sequence_size);\n\t\n\tif ((std::size_t)ancestral_sequence_size != size())\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::ReadCompressedNucleotides): ancestral sequence length does not match the sequence length being read.\" << EidosTerminate();\n\t\n\tstd::size_t size_bytes = ((ancestral_sequence_size + 31) / 32) * sizeof(uint64_t);\n\t\n\tif ((*buffer) + size_bytes > end)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::ReadCompressedNucleotides): out of buffer reading nucleotides.\" << EidosTerminate();\n\t\n\tmemcpy(buffer_, (*buffer), size_bytes);\n\t(*buffer) += size_bytes;\n}\n\nstd::ostream& operator<<(std::ostream& p_out, const NucleotideArray &p_nuc_array)\n{\n\t// Emit FASTA format with 70 bases per line\n\tstd::size_t index = 0;\n\tstd::string nuc_string;\n\t\n\t// Emit lines of length 70 first; presumably buffering in a string is faster than emitting one character at a time to the stream...\n\tnuc_string.resize(70);\n\t\n\twhile (index + 70 <= p_nuc_array.length_)\n\t{\n\t\tfor (int line_index = 0; line_index < 70; ++line_index)\n\t\t\tnuc_string[line_index] = gSLiM_Nucleotides[p_nuc_array.NucleotideAtIndex(index + line_index)];\n\t\t\n\t\tp_out << nuc_string << std::endl;\n\t\tindex += 70;\n\t}\n\t\n\t// Then emit a final line with any remaining nucleotides\n\tif (index < p_nuc_array.length_)\n\t{\n\t\tfor ( ; index < p_nuc_array.length_; ++index)\n\t\t{\n\t\t\tint nuc = p_nuc_array.NucleotideAtIndex(index);\n\t\t\t\n\t\t\tif (nuc == 0)\t\t\tp_out << 'A';\n\t\t\telse if (nuc == 1)\t\tp_out << 'C';\n\t\t\telse if (nuc == 2)\t\tp_out << 'G';\n\t\t\telse /*if (nuc == 3)*/\tp_out << 'T';\n\t\t}\n\t\t\n\t\tp_out << std::endl;\n\t}\n\t\n\treturn p_out;\n}\n\nstd::istream& operator>>(std::istream& p_in, NucleotideArray &p_nuc_array)\n{\n\t// read in nucleotides, skipping over newline characters; we expect to read exactly the right number of nucleotides\n\t// if we see two newline characters ('\\n', specifically) in a row, we take that as termination\n\tstd::size_t index = 0;\n\tbool just_saw_newline = false;\n\t\n\tdo\n\t{\n\t\tint nuc_char = p_in.get();\n\t\t\n\t\tif (nuc_char != EOF)\n\t\t{\n\t\t\t// for \\n, check for two in a row and terminate\n\t\t\tif (nuc_char == '\\n')\n\t\t\t{\n\t\t\t\tif (just_saw_newline)\n\t\t\t\t\tbreak;\n\t\t\t\tjust_saw_newline = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// for other whitespace, skip over it but don't reset just_saw_newline\n\t\t\tif ((nuc_char == '\\r') || (nuc_char == ' '))\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\t// any other character has to be a nucleotide; bounds-check and read it\n\t\t\tif (index >= p_nuc_array.length_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::operator>>): excess nucleotide sequence; the sequence length does not match the model.\" << EidosTerminate();\n\t\t\t\n\t\t\tuint64_t nuc_int;\n\t\t\t\n\t\t\tif (nuc_char == 'A')\t\tnuc_int = 0;\n\t\t\telse if (nuc_char == 'C')\tnuc_int = 1;\n\t\t\telse if (nuc_char == 'G')\tnuc_int = 2;\n\t\t\telse if (nuc_char == 'T')\tnuc_int = 3;\n\t\t\telse EIDOS_TERMINATION << \"ERROR (NucleotideArray::operator>>): unexpected character '\" << nuc_char << \"' in nucleotide sequence.\" << EidosTerminate();\n\t\t\t\n\t\t\tp_nuc_array.SetNucleotideAtIndex(index, nuc_int);\n\t\t\tjust_saw_newline = false;\n\t\t\tindex++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we got an EOF; terminate\n\t\t\tbreak;\n\t\t}\n\t}\n\twhile (true);\n\t\n\t// we have reached the end, either with an EOF or two newlines; see if it makes sense\n\tif (index != p_nuc_array.length_)\n\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::operator>>): premature end of nucleotide sequence; the sequence length does not match the model.\" << EidosTerminate();\n\t\n\treturn p_in;\n}\n\n\n#pragma mark -\n#pragma mark Global strings and IDs\n#pragma mark -\n\n// initialize...() functions defined by Species\nconst std::string &gStr_initializeAncestralNucleotides = EidosRegisteredString(\"initializeAncestralNucleotides\", gID_initializeAncestralNucleotides);\nconst std::string &gStr_initializeGenomicElement = EidosRegisteredString(\"initializeGenomicElement\", gID_initializeGenomicElement);\nconst std::string &gStr_initializeGenomicElementType = EidosRegisteredString(\"initializeGenomicElementType\", gID_initializeGenomicElementType);\nconst std::string &gStr_initializeMutationType = EidosRegisteredString(\"initializeMutationType\", gID_initializeMutationType);\nconst std::string &gStr_initializeMutationTypeNuc = EidosRegisteredString(\"initializeMutationTypeNuc\", gID_initializeMutationTypeNuc);\nconst std::string &gStr_initializeChromosome = EidosRegisteredString(\"initializeChromosome\", gID_initializeChromosome);\nconst std::string &gStr_initializeGeneConversion = EidosRegisteredString(\"initializeGeneConversion\", gID_initializeGeneConversion);\nconst std::string &gStr_initializeMutationRate = EidosRegisteredString(\"initializeMutationRate\", gID_initializeMutationRate);\nconst std::string &gStr_initializeHotspotMap = EidosRegisteredString(\"initializeHotspotMap\", gID_initializeHotspotMap);\nconst std::string &gStr_initializeRecombinationRate = EidosRegisteredString(\"initializeRecombinationRate\", gID_initializeRecombinationRate);\nconst std::string &gStr_initializeSex = EidosRegisteredString(\"initializeSex\", gID_initializeSex);\nconst std::string &gStr_initializeSLiMOptions = EidosRegisteredString(\"initializeSLiMOptions\", gID_initializeSLiMOptions);\nconst std::string &gStr_initializeSpecies = EidosRegisteredString(\"initializeSpecies\", gID_initializeSpecies);\nconst std::string &gStr_initializeTreeSeq = EidosRegisteredString(\"initializeTreeSeq\", gID_initializeTreeSeq);\nconst std::string &gStr_initializeSLiMModelType = EidosRegisteredString(\"initializeSLiMModelType\", gID_initializeSLiMModelType);\nconst std::string &gStr_initializeInteractionType = EidosRegisteredString(\"initializeInteractionType\", gID_initializeInteractionType);\n\n// mostly property names\nconst std::string &gStr_genomicElements = EidosRegisteredString(\"genomicElements\", gID_genomicElements);\nconst std::string &gStr_lastPosition = EidosRegisteredString(\"lastPosition\", gID_lastPosition);\nconst std::string &gStr_hotspotEndPositions = EidosRegisteredString(\"hotspotEndPositions\", gID_hotspotEndPositions);\nconst std::string &gStr_hotspotEndPositionsM = EidosRegisteredString(\"hotspotEndPositionsM\", gID_hotspotEndPositionsM);\nconst std::string &gStr_hotspotEndPositionsF = EidosRegisteredString(\"hotspotEndPositionsF\", gID_hotspotEndPositionsF);\nconst std::string &gStr_hotspotMultipliers = EidosRegisteredString(\"hotspotMultipliers\", gID_hotspotMultipliers);\nconst std::string &gStr_hotspotMultipliersM = EidosRegisteredString(\"hotspotMultipliersM\", gID_hotspotMultipliersM);\nconst std::string &gStr_hotspotMultipliersF = EidosRegisteredString(\"hotspotMultipliersF\", gID_hotspotMultipliersF);\nconst std::string &gStr_intrinsicPloidy = EidosRegisteredString(\"intrinsicPloidy\", gID_intrinsicPloidy);\nconst std::string &gStr_isSexChromosome = EidosRegisteredString(\"isSexChromosome\", gID_isSexChromosome);\nconst std::string &gStr_mutationEndPositions = EidosRegisteredString(\"mutationEndPositions\", gID_mutationEndPositions);\nconst std::string &gStr_mutationEndPositionsM = EidosRegisteredString(\"mutationEndPositionsM\", gID_mutationEndPositionsM);\nconst std::string &gStr_mutationEndPositionsF = EidosRegisteredString(\"mutationEndPositionsF\", gID_mutationEndPositionsF);\nconst std::string &gStr_mutationRates = EidosRegisteredString(\"mutationRates\", gID_mutationRates);\nconst std::string &gStr_mutationRatesM = EidosRegisteredString(\"mutationRatesM\", gID_mutationRatesM);\nconst std::string &gStr_mutationRatesF = EidosRegisteredString(\"mutationRatesF\", gID_mutationRatesF);\nconst std::string &gStr_overallMutationRate = EidosRegisteredString(\"overallMutationRate\", gID_overallMutationRate);\nconst std::string &gStr_overallMutationRateM = EidosRegisteredString(\"overallMutationRateM\", gID_overallMutationRateM);\nconst std::string &gStr_overallMutationRateF = EidosRegisteredString(\"overallMutationRateF\", gID_overallMutationRateF);\nconst std::string &gStr_overallRecombinationRate = EidosRegisteredString(\"overallRecombinationRate\", gID_overallRecombinationRate);\nconst std::string &gStr_overallRecombinationRateM = EidosRegisteredString(\"overallRecombinationRateM\", gID_overallRecombinationRateM);\nconst std::string &gStr_overallRecombinationRateF = EidosRegisteredString(\"overallRecombinationRateF\", gID_overallRecombinationRateF);\nconst std::string &gStr_recombinationEndPositions = EidosRegisteredString(\"recombinationEndPositions\", gID_recombinationEndPositions);\nconst std::string &gStr_recombinationEndPositionsM = EidosRegisteredString(\"recombinationEndPositionsM\", gID_recombinationEndPositionsM);\nconst std::string &gStr_recombinationEndPositionsF = EidosRegisteredString(\"recombinationEndPositionsF\", gID_recombinationEndPositionsF);\nconst std::string &gStr_recombinationRates = EidosRegisteredString(\"recombinationRates\", gID_recombinationRates);\nconst std::string &gStr_recombinationRatesM = EidosRegisteredString(\"recombinationRatesM\", gID_recombinationRatesM);\nconst std::string &gStr_recombinationRatesF = EidosRegisteredString(\"recombinationRatesF\", gID_recombinationRatesF);\nconst std::string &gStr_symbol = EidosRegisteredString(\"symbol\", gID_symbol);\nconst std::string &gStr_geneConversionEnabled = EidosRegisteredString(\"geneConversionEnabled\", gID_geneConversionEnabled);\nconst std::string &gStr_geneConversionGCBias = EidosRegisteredString(\"geneConversionGCBias\", gID_geneConversionGCBias);\nconst std::string &gStr_geneConversionNonCrossoverFraction = EidosRegisteredString(\"geneConversionNonCrossoverFraction\", gID_geneConversionNonCrossoverFraction);\nconst std::string &gStr_geneConversionMeanLength = EidosRegisteredString(\"geneConversionMeanLength\", gID_geneConversionMeanLength);\nconst std::string &gStr_geneConversionSimpleConversionFraction = EidosRegisteredString(\"geneConversionSimpleConversionFraction\", gID_geneConversionSimpleConversionFraction);\nconst std::string &gStr_chromosomeSubposition = EidosRegisteredString(\"chromosomeSubposition\", gID_chromosomeSubposition);\nconst std::string &gStr_isNullHaplosome = EidosRegisteredString(\"isNullHaplosome\", gID_isNullHaplosome);\nconst std::string &gStr_mutationCount = EidosRegisteredString(\"mutationCount\", gID_mutationCount);\nconst std::string &gStr_mutations = EidosRegisteredString(\"mutations\", gID_mutations);\nconst std::string &gStr_uniqueMutations = EidosRegisteredString(\"uniqueMutations\", gID_uniqueMutations);\nconst std::string &gStr_genomicElementType = EidosRegisteredString(\"genomicElementType\", gID_genomicElementType);\nconst std::string &gStr_startPosition = EidosRegisteredString(\"startPosition\", gID_startPosition);\nconst std::string &gStr_endPosition = EidosRegisteredString(\"endPosition\", gID_endPosition);\nconst std::string &gStr_id = EidosRegisteredString(\"id\", gID_id);\nconst std::string &gStr_mutationTypes = EidosRegisteredString(\"mutationTypes\", gID_mutationTypes);\nconst std::string &gStr_mutationFractions = EidosRegisteredString(\"mutationFractions\", gID_mutationFractions);\nconst std::string &gStr_mutationMatrix = EidosRegisteredString(\"mutationMatrix\", gID_mutationMatrix);\nconst std::string &gStr_isFixed = EidosRegisteredString(\"isFixed\", gID_isFixed);\nconst std::string &gStr_isSegregating = EidosRegisteredString(\"isSegregating\", gID_isSegregating);\nconst std::string &gStr_mutationType = EidosRegisteredString(\"mutationType\", gID_mutationType);\nconst std::string &gStr_nucleotide = EidosRegisteredString(\"nucleotide\", gID_nucleotide);\nconst std::string &gStr_nucleotideValue = EidosRegisteredString(\"nucleotideValue\", gID_nucleotideValue);\nconst std::string &gStr_originTick = EidosRegisteredString(\"originTick\", gID_originTick);\nconst std::string &gStr_position = EidosRegisteredString(\"position\", gID_position);\nconst std::string &gStr_selectionCoeff = EidosRegisteredString(\"selectionCoeff\", gID_selectionCoeff);\nconst std::string &gStr_subpopID = EidosRegisteredString(\"subpopID\", gID_subpopID);\nconst std::string &gStr_convertToSubstitution = EidosRegisteredString(\"convertToSubstitution\", gID_convertToSubstitution);\nconst std::string &gStr_distributionType = EidosRegisteredString(\"distributionType\", gID_distributionType);\nconst std::string &gStr_distributionParams = EidosRegisteredString(\"distributionParams\", gID_distributionParams);\nconst std::string &gStr_dominanceCoeff = EidosRegisteredString(\"dominanceCoeff\", gID_dominanceCoeff);\nconst std::string &gStr_hemizygousDominanceCoeff = EidosRegisteredString(\"hemizygousDominanceCoeff\", gID_hemizygousDominanceCoeff);\nconst std::string &gStr_mutationStackGroup = EidosRegisteredString(\"mutationStackGroup\", gID_mutationStackGroup);\nconst std::string &gStr_mutationStackPolicy = EidosRegisteredString(\"mutationStackPolicy\", gID_mutationStackPolicy);\n//const std::string &gStr_start = EidosRegisteredString(\"start\", gID_start);\n//const std::string &gStr_end = EidosRegisteredString(\"end\", gID_end);\n//const std::string &gStr_type = EidosRegisteredString(\"type\", gID_type);\n//const std::string &gStr_source = EidosRegisteredString(\"source\", gID_source);\nconst std::string &gStr_active = EidosRegisteredString(\"active\", gID_active);\nconst std::string &gStr_allGenomicElementTypes = EidosRegisteredString(\"allGenomicElementTypes\", gID_allGenomicElementTypes);\nconst std::string &gStr_allInteractionTypes = EidosRegisteredString(\"allInteractionTypes\", gID_allInteractionTypes);\nconst std::string &gStr_allMutationTypes = EidosRegisteredString(\"allMutationTypes\", gID_allMutationTypes);\nconst std::string &gStr_allScriptBlocks = EidosRegisteredString(\"allScriptBlocks\", gID_allScriptBlocks);\nconst std::string &gStr_allSpecies = EidosRegisteredString(\"allSpecies\", gID_allSpecies);\nconst std::string &gStr_allSubpopulations = EidosRegisteredString(\"allSubpopulations\", gID_allSubpopulations);\nconst std::string &gStr_chromosome = EidosRegisteredString(\"chromosome\", gID_chromosome);\nconst std::string &gStr_chromosomes = EidosRegisteredString(\"chromosomes\", gID_chromosomes);\nconst std::string &gStr_genomicElementTypes = EidosRegisteredString(\"genomicElementTypes\", gID_genomicElementTypes);\nconst std::string &gStr_lifetimeReproductiveOutput = EidosRegisteredString(\"lifetimeReproductiveOutput\", gID_lifetimeReproductiveOutput);\nconst std::string &gStr_lifetimeReproductiveOutputM = EidosRegisteredString(\"lifetimeReproductiveOutputM\", gID_lifetimeReproductiveOutputM);\nconst std::string &gStr_lifetimeReproductiveOutputF = EidosRegisteredString(\"lifetimeReproductiveOutputF\", gID_lifetimeReproductiveOutputF);\nconst std::string &gStr_modelType = EidosRegisteredString(\"modelType\", gID_modelType);\nconst std::string &gStr_nucleotideBased = EidosRegisteredString(\"nucleotideBased\", gID_nucleotideBased);\nconst std::string &gStr_scriptBlocks = EidosRegisteredString(\"scriptBlocks\", gID_scriptBlocks);\nconst std::string &gStr_sexChromosomes = EidosRegisteredString(\"sexChromosomes\", gID_sexChromosomes);\nconst std::string &gStr_sexEnabled = EidosRegisteredString(\"sexEnabled\", gID_sexEnabled);\nconst std::string &gStr_subpopulations = EidosRegisteredString(\"subpopulations\", gID_subpopulations);\nconst std::string &gStr_substitutions = EidosRegisteredString(\"substitutions\", gID_substitutions);\nconst std::string &gStr_tick = EidosRegisteredString(\"tick\", gID_tick);\nconst std::string &gStr_cycle = EidosRegisteredString(\"cycle\", gID_cycle);\nconst std::string &gStr_cycleStage = EidosRegisteredString(\"cycleStage\", gID_cycleStage);\nconst std::string &gStr_colorSubstitution = EidosRegisteredString(\"colorSubstitution\", gID_colorSubstitution);\nconst std::string &gStr_verbosity = EidosRegisteredString(\"verbosity\", gID_verbosity);\nconst std::string &gStr_tag = EidosRegisteredString(\"tag\", gID_tag);\nconst std::string &gStr_tagF = EidosRegisteredString(\"tagF\", gID_tagF);\nconst std::string &gStr_tagL0 = EidosRegisteredString(\"tagL0\", gID_tagL0);\nconst std::string &gStr_tagL1 = EidosRegisteredString(\"tagL1\", gID_tagL1);\nconst std::string &gStr_tagL2 = EidosRegisteredString(\"tagL2\", gID_tagL2);\nconst std::string &gStr_tagL3 = EidosRegisteredString(\"tagL3\", gID_tagL3);\nconst std::string &gStr_tagL4 = EidosRegisteredString(\"tagL4\", gID_tagL4);\nconst std::string &gStr_migrant = EidosRegisteredString(\"migrant\", gID_migrant);\nconst std::string &gStr_fitnessScaling = EidosRegisteredString(\"fitnessScaling\", gID_fitnessScaling);\nconst std::string &gStr_firstMaleIndex = EidosRegisteredString(\"firstMaleIndex\", gID_firstMaleIndex);\nconst std::string &gStr_haplosomes = EidosRegisteredString(\"haplosomes\", gID_haplosomes);\nconst std::string &gStr_haplosomesNonNull = EidosRegisteredString(\"haplosomesNonNull\", gID_haplosomesNonNull);\nconst std::string &gStr_haploidGenome1 = EidosRegisteredString(\"haploidGenome1\", gID_haploidGenome1);\nconst std::string &gStr_haploidGenome2 = EidosRegisteredString(\"haploidGenome2\", gID_haploidGenome2);\nconst std::string &gStr_haploidGenome1NonNull = EidosRegisteredString(\"haploidGenome1NonNull\", gID_haploidGenome1NonNull);\nconst std::string &gStr_haploidGenome2NonNull = EidosRegisteredString(\"haploidGenome2NonNull\", gID_haploidGenome2NonNull);\nconst std::string &gStr_sex = EidosRegisteredString(\"sex\", gID_sex);\nconst std::string &gStr_individuals = EidosRegisteredString(\"individuals\", gID_individuals);\nconst std::string &gStr_subpopulation = EidosRegisteredString(\"subpopulation\", gID_subpopulation);\nconst std::string &gStr_index = EidosRegisteredString(\"index\", gID_index);\nconst std::string &gStr_immigrantSubpopIDs = EidosRegisteredString(\"immigrantSubpopIDs\", gID_immigrantSubpopIDs);\nconst std::string &gStr_immigrantSubpopFractions = EidosRegisteredString(\"immigrantSubpopFractions\", gID_immigrantSubpopFractions);\nconst std::string &gStr_avatar = EidosRegisteredString(\"avatar\", gID_avatar);\nconst std::string &gStr_name = EidosRegisteredString(\"name\", gID_name);\nconst std::string &gStr_description = EidosRegisteredString(\"description\", gID_description);\nconst std::string &gStr_selfingRate = EidosRegisteredString(\"selfingRate\", gID_selfingRate);\nconst std::string &gStr_cloningRate = EidosRegisteredString(\"cloningRate\", gID_cloningRate);\nconst std::string &gStr_sexRatio = EidosRegisteredString(\"sexRatio\", gID_sexRatio);\nconst std::string &gStr_gridDimensions = EidosRegisteredString(\"gridDimensions\", gID_gridDimensions);\nconst std::string &gStr_interpolate = EidosRegisteredString(\"interpolate\", gID_interpolate);\nconst std::string &gStr_spatialBounds = EidosRegisteredString(\"spatialBounds\", gID_spatialBounds);\nconst std::string &gStr_spatialMaps = EidosRegisteredString(\"spatialMaps\", gID_spatialMaps);\nconst std::string &gStr_individualCount = EidosRegisteredString(\"individualCount\", gID_individualCount);\nconst std::string &gStr_fixationTick = EidosRegisteredString(\"fixationTick\", gID_fixationTick);\nconst std::string &gStr_age = EidosRegisteredString(\"age\", gID_age);\nconst std::string &gStr_meanParentAge = EidosRegisteredString(\"meanParentAge\", gID_meanParentAge);\nconst std::string &gStr_pedigreeID = EidosRegisteredString(\"pedigreeID\", gID_pedigreeID);\nconst std::string &gStr_pedigreeParentIDs = EidosRegisteredString(\"pedigreeParentIDs\", gID_pedigreeParentIDs);\nconst std::string &gStr_pedigreeGrandparentIDs = EidosRegisteredString(\"pedigreeGrandparentIDs\", gID_pedigreeGrandparentIDs);\nconst std::string &gStr_reproductiveOutput = EidosRegisteredString(\"reproductiveOutput\", gID_reproductiveOutput);\nconst std::string &gStr_haplosomePedigreeID = EidosRegisteredString(\"haplosomePedigreeID\", gID_haplosomePedigreeID);\nconst std::string &gStr_reciprocal = EidosRegisteredString(\"reciprocal\", gID_reciprocal);\nconst std::string &gStr_sexSegregation = EidosRegisteredString(\"sexSegregation\", gID_sexSegregation);\nconst std::string &gStr_dimensionality = EidosRegisteredString(\"dimensionality\", gID_dimensionality);\nconst std::string &gStr_periodicity = EidosRegisteredString(\"periodicity\", gID_periodicity);\nconst std::string &gStr_spatiality = EidosRegisteredString(\"spatiality\", gID_spatiality);\nconst std::string &gStr_spatialPosition = EidosRegisteredString(\"spatialPosition\", gID_spatialPosition);\nconst std::string &gStr_maxDistance = EidosRegisteredString(\"maxDistance\", gID_maxDistance);\n\n// mostly method names\nconst std::string &gStr_ancestralNucleotides = EidosRegisteredString(\"ancestralNucleotides\", gID_ancestralNucleotides);\nconst std::string &gStr_nucleotides = EidosRegisteredString(\"nucleotides\", gID_nucleotides);\nconst std::string &gStr_genomicElementForPosition = EidosRegisteredString(\"genomicElementForPosition\", gID_genomicElementForPosition);\nconst std::string &gStr_hasGenomicElementForPosition = EidosRegisteredString(\"hasGenomicElementForPosition\", gID_hasGenomicElementForPosition);\nconst std::string &gStr_setAncestralNucleotides = EidosRegisteredString(\"setAncestralNucleotides\", gID_setAncestralNucleotides);\nconst std::string &gStr_setGeneConversion = EidosRegisteredString(\"setGeneConversion\", gID_setGeneConversion);\nconst std::string &gStr_setHotspotMap = EidosRegisteredString(\"setHotspotMap\", gID_setHotspotMap);\nconst std::string &gStr_setMutationRate = EidosRegisteredString(\"setMutationRate\", gID_setMutationRate);\nconst std::string &gStr_setRecombinationRate = EidosRegisteredString(\"setRecombinationRate\", gID_setRecombinationRate);\nconst std::string &gStr_drawBreakpoints = EidosRegisteredString(\"drawBreakpoints\", gID_drawBreakpoints);\nconst std::string &gStr_addMutations = EidosRegisteredString(\"addMutations\", gID_addMutations);\nconst std::string &gStr_addNewDrawnMutation = EidosRegisteredString(\"addNewDrawnMutation\", gID_addNewDrawnMutation);\nconst std::string &gStr_addNewMutation = EidosRegisteredString(\"addNewMutation\", gID_addNewMutation);\nconst std::string &gStr_containsMutations = EidosRegisteredString(\"containsMutations\", gID_containsMutations);\nconst std::string &gStr_countOfMutationsOfType = EidosRegisteredString(\"countOfMutationsOfType\", gID_countOfMutationsOfType);\nconst std::string &gStr_positionsOfMutationsOfType = EidosRegisteredString(\"positionsOfMutationsOfType\", gID_positionsOfMutationsOfType);\nconst std::string &gStr_containsMarkerMutation = EidosRegisteredString(\"containsMarkerMutation\", gID_containsMarkerMutation);\nconst std::string &gStr_haplosomesForChromosomes = EidosRegisteredString(\"haplosomesForChromosomes\", gID_haplosomesForChromosomes);\nconst std::string &gStr_relatedness = EidosRegisteredString(\"relatedness\", gID_relatedness);\nconst std::string &gStr_sharedParentCount = EidosRegisteredString(\"sharedParentCount\", gID_sharedParentCount);\nconst std::string &gStr_mutationsOfType = EidosRegisteredString(\"mutationsOfType\", gID_mutationsOfType);\nconst std::string &gStr_outputIndividuals = EidosRegisteredString(\"outputIndividuals\", gID_outputIndividuals);\nconst std::string &gStr_outputIndividualsToVCF = EidosRegisteredString(\"outputIndividualsToVCF\", gID_outputIndividualsToVCF);\nconst std::string &gStr_readIndividualsFromVCF = EidosRegisteredString(\"readIndividualsFromVCF\", gID_readIndividualsFromVCF);\nconst std::string &gStr_setSpatialPosition = EidosRegisteredString(\"setSpatialPosition\", gID_setSpatialPosition);\nconst std::string &gStr_substitutionsOfType = EidosRegisteredString(\"substitutionsOfType\", gID_substitutionsOfType);\nconst std::string &gStr_sumOfMutationsOfType = EidosRegisteredString(\"sumOfMutationsOfType\", gID_sumOfMutationsOfType);\nconst std::string &gStr_uniqueMutationsOfType = EidosRegisteredString(\"uniqueMutationsOfType\", gID_uniqueMutationsOfType);\nconst std::string &gStr_zygosityOfMutations = EidosRegisteredString(\"zygosityOfMutations\", gID_zygosityOfMutations);\nconst std::string &gStr_mutationsFromHaplosomes = EidosRegisteredString(\"mutationsFromHaplosomes\", gID_mutationsFromHaplosomes);\nconst std::string &gStr_readHaplosomesFromMS = EidosRegisteredString(\"readHaplosomesFromMS\", gID_readHaplosomesFromMS);\nconst std::string &gStr_readHaplosomesFromVCF = EidosRegisteredString(\"readHaplosomesFromVCF\", gID_readHaplosomesFromVCF);\nconst std::string &gStr_removeMutations = EidosRegisteredString(\"removeMutations\", gID_removeMutations);\nconst std::string &gStr_setGenomicElementType = EidosRegisteredString(\"setGenomicElementType\", gID_setGenomicElementType);\nconst std::string &gStr_setMutationFractions = EidosRegisteredString(\"setMutationFractions\", gID_setMutationFractions);\nconst std::string &gStr_setMutationMatrix = EidosRegisteredString(\"setMutationMatrix\", gID_setMutationMatrix);\nconst std::string &gStr_setSelectionCoeff = EidosRegisteredString(\"setSelectionCoeff\", gID_setSelectionCoeff);\nconst std::string &gStr_setMutationType = EidosRegisteredString(\"setMutationType\", gID_setMutationType);\nconst std::string &gStr_drawSelectionCoefficient = EidosRegisteredString(\"drawSelectionCoefficient\", gID_drawSelectionCoefficient);\nconst std::string &gStr_setDistribution = EidosRegisteredString(\"setDistribution\", gID_setDistribution);\nconst std::string &gStr_addPatternForClone = EidosRegisteredString(\"addPatternForClone\", gID_addPatternForClone);\nconst std::string &gStr_addPatternForCross = EidosRegisteredString(\"addPatternForCross\", gID_addPatternForCross);\nconst std::string &gStr_addPatternForNull = EidosRegisteredString(\"addPatternForNull\", gID_addPatternForNull);\nconst std::string &gStr_addPatternForRecombinant = EidosRegisteredString(\"addPatternForRecombinant\", gID_addPatternForRecombinant);\nconst std::string &gStr_addSubpop = EidosRegisteredString(\"addSubpop\", gID_addSubpop);\nconst std::string &gStr_addSubpopSplit = EidosRegisteredString(\"addSubpopSplit\", gID_addSubpopSplit);\nconst std::string &gStr_chromosomesOfType = EidosRegisteredString(\"chromosomesOfType\", gID_chromosomesOfType);\nconst std::string &gStr_chromosomesWithIDs = EidosRegisteredString(\"chromosomesWithIDs\", gID_chromosomesWithIDs);\nconst std::string &gStr_chromosomesWithSymbols = EidosRegisteredString(\"chromosomesWithSymbols\", gID_chromosomesWithSymbols);\nconst std::string &gStr_estimatedLastTick = EidosRegisteredString(\"estimatedLastTick\", gID_estimatedLastTick);\nconst std::string &gStr_deregisterScriptBlock = EidosRegisteredString(\"deregisterScriptBlock\", gID_deregisterScriptBlock);\nconst std::string &gStr_genomicElementTypesWithIDs = EidosRegisteredString(\"genomicElementTypesWithIDs\", gID_genomicElementTypesWithIDs);\nconst std::string &gStr_interactionTypesWithIDs = EidosRegisteredString(\"interactionTypesWithIDs\", gID_interactionTypesWithIDs);\nconst std::string &gStr_mutationTypesWithIDs = EidosRegisteredString(\"mutationTypesWithIDs\", gID_mutationTypesWithIDs);\nconst std::string &gStr_scriptBlocksWithIDs = EidosRegisteredString(\"scriptBlocksWithIDs\", gID_scriptBlocksWithIDs);\nconst std::string &gStr_speciesWithIDs = EidosRegisteredString(\"speciesWithIDs\", gID_speciesWithIDs);\nconst std::string &gStr_subpopulationsWithIDs = EidosRegisteredString(\"subpopulationsWithIDs\", gID_subpopulationsWithIDs);\nconst std::string &gStr_subpopulationsWithNames = EidosRegisteredString(\"subpopulationsWithNames\", gID_subpopulationsWithNames);\nconst std::string &gStr_individualsWithPedigreeIDs = EidosRegisteredString(\"individualsWithPedigreeIDs\", gID_individualsWithPedigreeIDs);\nconst std::string &gStr_killIndividuals = EidosRegisteredString(\"killIndividuals\", gID_killIndividuals);\nconst std::string &gStr_mutationCounts = EidosRegisteredString(\"mutationCounts\", gID_mutationCounts);\nconst std::string &gStr_mutationCountsInHaplosomes = EidosRegisteredString(\"mutationCountsInHaplosomes\", gID_mutationCountsInHaplosomes);\nconst std::string &gStr_mutationFrequencies = EidosRegisteredString(\"mutationFrequencies\", gID_mutationFrequencies);\nconst std::string &gStr_mutationFrequenciesInHaplosomes = EidosRegisteredString(\"mutationFrequenciesInHaplosomes\", gID_mutationFrequenciesInHaplosomes);\n//const std::string &gStr_mutationsOfType = EidosRegisteredString(\"mutationsOfType\", gID_mutationsOfType);\n//const std::string &gStr_countOfMutationsOfType = EidosRegisteredString(\"countOfMutationsOfType\", gID_countOfMutationsOfType);\nconst std::string &gStr_outputFixedMutations = EidosRegisteredString(\"outputFixedMutations\", gID_outputFixedMutations);\nconst std::string &gStr_outputFull = EidosRegisteredString(\"outputFull\", gID_outputFull);\nconst std::string &gStr_outputMutations = EidosRegisteredString(\"outputMutations\", gID_outputMutations);\nconst std::string &gStr_outputUsage = EidosRegisteredString(\"outputUsage\", gID_outputUsage);\nconst std::string &gStr_readFromPopulationFile = EidosRegisteredString(\"readFromPopulationFile\", gID_readFromPopulationFile);\nconst std::string &gStr_recalculateFitness = EidosRegisteredString(\"recalculateFitness\", gID_recalculateFitness);\nconst std::string &gStr_registerFirstEvent = EidosRegisteredString(\"registerFirstEvent\", gID_registerFirstEvent);\nconst std::string &gStr_registerEarlyEvent = EidosRegisteredString(\"registerEarlyEvent\", gID_registerEarlyEvent);\nconst std::string &gStr_registerLateEvent = EidosRegisteredString(\"registerLateEvent\", gID_registerLateEvent);\nconst std::string &gStr_registerFitnessEffectCallback = EidosRegisteredString(\"registerFitnessEffectCallback\", gID_registerFitnessEffectCallback);\nconst std::string &gStr_registerInteractionCallback = EidosRegisteredString(\"registerInteractionCallback\", gID_registerInteractionCallback);\nconst std::string &gStr_registerMateChoiceCallback = EidosRegisteredString(\"registerMateChoiceCallback\", gID_registerMateChoiceCallback);\nconst std::string &gStr_registerModifyChildCallback = EidosRegisteredString(\"registerModifyChildCallback\", gID_registerModifyChildCallback);\nconst std::string &gStr_registerRecombinationCallback = EidosRegisteredString(\"registerRecombinationCallback\", gID_registerRecombinationCallback);\nconst std::string &gStr_registerMutationCallback = EidosRegisteredString(\"registerMutationCallback\", gID_registerMutationCallback);\nconst std::string &gStr_registerMutationEffectCallback = EidosRegisteredString(\"registerMutationEffectCallback\", gID_registerMutationEffectCallback);\nconst std::string &gStr_registerSurvivalCallback = EidosRegisteredString(\"registerSurvivalCallback\", gID_registerSurvivalCallback);\nconst std::string &gStr_registerReproductionCallback = EidosRegisteredString(\"registerReproductionCallback\", gID_registerReproductionCallback);\nconst std::string &gStr_rescheduleScriptBlock = EidosRegisteredString(\"rescheduleScriptBlock\", gID_rescheduleScriptBlock);\nconst std::string &gStr_simulationFinished = EidosRegisteredString(\"simulationFinished\", gID_simulationFinished);\nconst std::string &gStr_skipTick = EidosRegisteredString(\"skipTick\", gID_skipTick);\nconst std::string &gStr_subsetMutations = EidosRegisteredString(\"subsetMutations\", gID_subsetMutations);\nconst std::string &gStr_treeSeqCoalesced = EidosRegisteredString(\"treeSeqCoalesced\", gID_treeSeqCoalesced);\nconst std::string &gStr_treeSeqSimplify = EidosRegisteredString(\"treeSeqSimplify\", gID_treeSeqSimplify);\nconst std::string &gStr_treeSeqRememberIndividuals = EidosRegisteredString(\"treeSeqRememberIndividuals\", gID_treeSeqRememberIndividuals);\nconst std::string &gStr_treeSeqOutput = EidosRegisteredString(\"treeSeqOutput\", gID_treeSeqOutput);\nconst std::string &gStr__debug = EidosRegisteredString(\"_debug\", gID__debug);\nconst std::string &gStr_setMigrationRates = EidosRegisteredString(\"setMigrationRates\", gID_setMigrationRates);\nconst std::string &gStr_deviatePositions = EidosRegisteredString(\"deviatePositions\", gID_deviatePositions);\nconst std::string &gStr_deviatePositionsWithMap = EidosRegisteredString(\"deviatePositionsWithMap\", gID_deviatePositionsWithMap);\nconst std::string &gStr_pointDeviated = EidosRegisteredString(\"pointDeviated\", gID_pointDeviated);\nconst std::string &gStr_pointInBounds = EidosRegisteredString(\"pointInBounds\", gID_pointInBounds);\nconst std::string &gStr_pointReflected = EidosRegisteredString(\"pointReflected\", gID_pointReflected);\nconst std::string &gStr_pointStopped = EidosRegisteredString(\"pointStopped\", gID_pointStopped);\nconst std::string &gStr_pointPeriodic = EidosRegisteredString(\"pointPeriodic\", gID_pointPeriodic);\nconst std::string &gStr_pointUniform = EidosRegisteredString(\"pointUniform\", gID_pointUniform);\nconst std::string &gStr_pointUniformWithMap = EidosRegisteredString(\"pointUniformWithMap\", gID_pointUniformWithMap);\nconst std::string &gStr_setCloningRate = EidosRegisteredString(\"setCloningRate\", gID_setCloningRate);\nconst std::string &gStr_setSelfingRate = EidosRegisteredString(\"setSelfingRate\", gID_setSelfingRate);\nconst std::string &gStr_setSexRatio = EidosRegisteredString(\"setSexRatio\", gID_setSexRatio);\nconst std::string &gStr_setSpatialBounds = EidosRegisteredString(\"setSpatialBounds\", gID_setSpatialBounds);\nconst std::string &gStr_setSubpopulationSize = EidosRegisteredString(\"setSubpopulationSize\", gID_setSubpopulationSize);\nconst std::string &gStr_addCloned = EidosRegisteredString(\"addCloned\", gID_addCloned);\nconst std::string &gStr_addCrossed = EidosRegisteredString(\"addCrossed\", gID_addCrossed);\nconst std::string &gStr_addEmpty = EidosRegisteredString(\"addEmpty\", gID_addEmpty);\nconst std::string &gStr_addMultiRecombinant = EidosRegisteredString(\"addMultiRecombinant\", gID_addMultiRecombinant);\nconst std::string &gStr_addRecombinant = EidosRegisteredString(\"addRecombinant\", gID_addRecombinant);\nconst std::string &gStr_addSelfed = EidosRegisteredString(\"addSelfed\", gID_addSelfed);\nconst std::string &gStr_takeMigrants = EidosRegisteredString(\"takeMigrants\", gID_takeMigrants);\nconst std::string &gStr_removeSubpopulation = EidosRegisteredString(\"removeSubpopulation\", gID_removeSubpopulation);\nconst std::string &gStr_cachedFitness = EidosRegisteredString(\"cachedFitness\", gID_cachedFitness);\nconst std::string &gStr_sampleIndividuals = EidosRegisteredString(\"sampleIndividuals\", gID_sampleIndividuals);\nconst std::string &gStr_subsetIndividuals = EidosRegisteredString(\"subsetIndividuals\", gID_subsetIndividuals);\nconst std::string &gStr_defineSpatialMap = EidosRegisteredString(\"defineSpatialMap\", gID_defineSpatialMap);\nconst std::string &gStr_addSpatialMap = EidosRegisteredString(\"addSpatialMap\", gID_addSpatialMap);\nconst std::string &gStr_removeSpatialMap = EidosRegisteredString(\"removeSpatialMap\", gID_removeSpatialMap);\nconst std::string &gStr_spatialMapColor = EidosRegisteredString(\"spatialMapColor\", gID_spatialMapColor);\nconst std::string &gStr_spatialMapImage = EidosRegisteredString(\"spatialMapImage\", gID_spatialMapImage);\nconst std::string &gStr_spatialMapValue = EidosRegisteredString(\"spatialMapValue\", gID_spatialMapValue);\nconst std::string &gStr_add = EidosRegisteredString(\"add\", gID_add);\nconst std::string &gStr_blend = EidosRegisteredString(\"blend\", gID_blend);\nconst std::string &gStr_multiply = EidosRegisteredString(\"multiply\", gID_multiply);\nconst std::string &gStr_subtract = EidosRegisteredString(\"subtract\", gID_subtract);\nconst std::string &gStr_divide = EidosRegisteredString(\"divide\", gID_divide);\nconst std::string &gStr_power = EidosRegisteredString(\"power\", gID_power);\nconst std::string &gStr_exp = EidosRegisteredString(\"exp\", gID_exp);\nconst std::string &gStr_changeColors = EidosRegisteredString(\"changeColors\", gID_changeColors);\nconst std::string &gStr_changeValues = EidosRegisteredString(\"changeValues\", gID_changeValues);\nconst std::string &gStr_gridValues = EidosRegisteredString(\"gridValues\", gID_gridValues);\nconst std::string &gStr_mapColor = EidosRegisteredString(\"mapColor\", gID_mapColor);\nconst std::string &gStr_mapImage = EidosRegisteredString(\"mapImage\", gID_mapImage);\nconst std::string &gStr_mapValue = EidosRegisteredString(\"mapValue\", gID_mapValue);\nconst std::string &gStr_rescale = EidosRegisteredString(\"rescale\", gID_rescale);\nconst std::string &gStr_sampleImprovedNearbyPoint = EidosRegisteredString(\"sampleImprovedNearbyPoint\", gID_sampleImprovedNearbyPoint);\nconst std::string &gStr_sampleNearbyPoint = EidosRegisteredString(\"sampleNearbyPoint\", gID_sampleNearbyPoint);\nconst std::string &gStr_smooth = EidosRegisteredString(\"smooth\", gID_smooth);\nconst std::string &gStr_outputMSSample = EidosRegisteredString(\"outputMSSample\", gID_outputMSSample);\nconst std::string &gStr_outputVCFSample = EidosRegisteredString(\"outputVCFSample\", gID_outputVCFSample);\nconst std::string &gStr_outputSample = EidosRegisteredString(\"outputSample\", gID_outputSample);\nconst std::string &gStr_outputHaplosomesToMS = EidosRegisteredString(\"outputHaplosomesToMS\", gID_outputHaplosomesToMS);\nconst std::string &gStr_outputHaplosomesToVCF = EidosRegisteredString(\"outputHaplosomesToVCF\", gID_outputHaplosomesToVCF);\nconst std::string &gStr_outputHaplosomes = EidosRegisteredString(\"outputHaplosomes\", gID_outputHaplosomes);\nconst std::string &gStr_evaluate = EidosRegisteredString(\"evaluate\", gID_evaluate);\nconst std::string &gStr_distance = EidosRegisteredString(\"distance\", gID_distance);\nconst std::string &gStr_localPopulationDensity = EidosRegisteredString(\"localPopulationDensity\", gID_localPopulationDensity);\nconst std::string &gStr_interactionDistance = EidosRegisteredString(\"interactionDistance\", gID_interactionDistance);\nconst std::string &gStr_clippedIntegral = EidosRegisteredString(\"clippedIntegral\", gID_clippedIntegral);\nconst std::string &gStr_distanceFromPoint = EidosRegisteredString(\"distanceFromPoint\", gID_distanceFromPoint);\nconst std::string &gStr_nearestNeighbors = EidosRegisteredString(\"nearestNeighbors\", gID_nearestNeighbors);\nconst std::string &gStr_neighborCount = EidosRegisteredString(\"neighborCount\", gID_neighborCount);\nconst std::string &gStr_neighborCountOfPoint = EidosRegisteredString(\"neighborCountOfPoint\", gID_neighborCountOfPoint);\nconst std::string &gStr_nearestInteractingNeighbors = EidosRegisteredString(\"nearestInteractingNeighbors\", gID_nearestInteractingNeighbors);\nconst std::string &gStr_interactingNeighborCount = EidosRegisteredString(\"interactingNeighborCount\", gID_interactingNeighborCount);\nconst std::string &gStr_nearestNeighborsOfPoint = EidosRegisteredString(\"nearestNeighborsOfPoint\", gID_nearestNeighborsOfPoint);\nconst std::string &gStr_setConstraints = EidosRegisteredString(\"setConstraints\", gID_setConstraints);\nconst std::string &gStr_setInteractionFunction = EidosRegisteredString(\"setInteractionFunction\", gID_setInteractionFunction);\nconst std::string &gStr_strength = EidosRegisteredString(\"strength\", gID_strength);\nconst std::string &gStr_testConstraints = EidosRegisteredString(\"testConstraints\", gID_testConstraints);\nconst std::string &gStr_totalOfNeighborStrengths = EidosRegisteredString(\"totalOfNeighborStrengths\", gID_totalOfNeighborStrengths);\nconst std::string &gStr_unevaluate = EidosRegisteredString(\"unevaluate\", gID_unevaluate);\nconst std::string &gStr_drawByStrength = EidosRegisteredString(\"drawByStrength\", gID_drawByStrength);\n\n// mostly SLiM variable names used in callbacks and such\nconst std::string &gStr_community = EidosRegisteredString(\"community\", gID_community);\nconst std::string &gStr_sim = EidosRegisteredString(\"sim\", gID_sim);\nconst std::string &gStr_self = EidosRegisteredString(\"self\", gID_self);\nconst std::string &gStr_individual = EidosRegisteredString(\"individual\", gID_individual);\nconst std::string &gStr_element = EidosRegisteredString(\"element\", gID_element);\nconst std::string &gStr_haplosome = EidosRegisteredString(\"haplosome\", gID_haplosome);\nconst std::string &gStr_haplosome1 = EidosRegisteredString(\"haplosome1\", gID_haplosome1);\nconst std::string &gStr_haplosome2 = EidosRegisteredString(\"haplosome2\", gID_haplosome2);\nconst std::string &gStr_subpop = EidosRegisteredString(\"subpop\", gID_subpop);\nconst std::string &gStr_sourceSubpop = EidosRegisteredString(\"sourceSubpop\", gID_sourceSubpop);\n//const std::string &gStr_weights = EidosRegisteredString(\"weights\", gID_weights);\t\tnow gEidosStr_weights\nconst std::string &gStr_child = EidosRegisteredString(\"child\", gID_child);\nconst std::string &gStr_parent = EidosRegisteredString(\"parent\", gID_parent);\nconst std::string &gStr_parent1 = EidosRegisteredString(\"parent1\", gID_parent1);\nconst std::string &gStr_isCloning = EidosRegisteredString(\"isCloning\", gID_isCloning);\nconst std::string &gStr_isSelfing = EidosRegisteredString(\"isSelfing\", gID_isSelfing);\nconst std::string &gStr_parent2 = EidosRegisteredString(\"parent2\", gID_parent2);\nconst std::string &gStr_mut = EidosRegisteredString(\"mut\", gID_mut);\nconst std::string &gStr_effect = EidosRegisteredString(\"effect\", gID_effect);\nconst std::string &gStr_homozygous = EidosRegisteredString(\"homozygous\", gID_homozygous);\nconst std::string &gStr_breakpoints = EidosRegisteredString(\"breakpoints\", gID_breakpoints);\nconst std::string &gStr_receiver = EidosRegisteredString(\"receiver\", gID_receiver);\nconst std::string &gStr_exerter = EidosRegisteredString(\"exerter\", gID_exerter);\nconst std::string &gStr_originalNuc = EidosRegisteredString(\"originalNuc\", gID_originalNuc);\nconst std::string &gStr_fitness = EidosRegisteredString(\"fitness\", gID_fitness);\nconst std::string &gStr_surviving = EidosRegisteredString(\"surviving\", gID_surviving);\nconst std::string &gStr_draw = EidosRegisteredString(\"draw\", gID_draw);\n\n// SLiMgui instance name and methods\nconst std::string &gStr_slimgui = EidosRegisteredString(\"slimgui\", gID_slimgui);\nconst std::string &gStr_pid = EidosRegisteredString(\"pid\", gID_pid);\nconst std::string &gStr_configureDisplay = EidosRegisteredString(\"configureDisplay\", gID_configureDisplay);\nconst std::string &gStr_createPlot = EidosRegisteredString(\"createPlot\", gID_createPlot);\nconst std::string &gStr_logFileData = EidosRegisteredString(\"logFileData\", gID_logFileData);\nconst std::string &gStr_openDocument = EidosRegisteredString(\"openDocument\", gID_openDocument);\nconst std::string &gStr_pauseExecution = EidosRegisteredString(\"pauseExecution\", gID_pauseExecution);\nconst std::string &gStr_plotWithTitle = EidosRegisteredString(\"plotWithTitle\", gID_plotWithTitle);\n\n// Plot methods and properties\nconst std::string &gStr_abline = EidosRegisteredString(\"abline\", gID_abline);\nconst std::string &gStr_addLegend = EidosRegisteredString(\"addLegend\", gID_addLegend);\nconst std::string &gStr_axis = EidosRegisteredString(\"axis\", gID_axis);\nconst std::string &gStr_image = EidosRegisteredString(\"image\", gID_image);\nconst std::string &gStr_legendLineEntry = EidosRegisteredString(\"legendLineEntry\", gID_legendLineEntry);\nconst std::string &gStr_legendPointEntry = EidosRegisteredString(\"legendPointEntry\", gID_legendPointEntry);\nconst std::string &gStr_legendSwatchEntry = EidosRegisteredString(\"legendSwatchEntry\", gID_legendSwatchEntry);\nconst std::string &gStr_legendTitleEntry = EidosRegisteredString(\"legendTitleEntry\", gID_legendTitleEntry);\nconst std::string &gStr_lines = EidosRegisteredString(\"lines\", gID_lines);\nconst std::string &gStr_matrix = EidosRegisteredString(\"matrix\", gID_matrix);\nconst std::string &gStr_mtext = EidosRegisteredString(\"mtext\", gID_mtext);\nconst std::string &gStr_points = EidosRegisteredString(\"points\", gID_points);\nconst std::string &gStr_rects = EidosRegisteredString(\"rects\", gID_rects);\nconst std::string &gStr_segments = EidosRegisteredString(\"segments\", gID_segments);\nconst std::string &gStr_setBorderless = EidosRegisteredString(\"setBorderless\", gID_setBorderless);\nconst std::string &gStr_text = EidosRegisteredString(\"text\", gID_text);\nconst std::string &gStr_title = EidosRegisteredString(\"title\", gID_title);\n\n// mostly SLiM element types\nconst std::string &gStr_Chromosome = EidosRegisteredString(\"Chromosome\", gID_Chromosome);\n//const std::string &gStr_Haplosome = EidosRegisteredString(\"Haplosome\", gID_Haplosome);\t\t\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nconst std::string &gStr_GenomicElement = EidosRegisteredString(\"GenomicElement\", gID_GenomicElement);\nconst std::string &gStr_GenomicElementType = EidosRegisteredString(\"GenomicElementType\", gID_GenomicElementType);\n//const std::string &gStr_Mutation = EidosRegisteredString(\"Mutation\", gID_Mutation);\t\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nconst std::string &gStr_MutationType = EidosRegisteredString(\"MutationType\", gID_MutationType);\nconst std::string &gStr_SLiMEidosBlock = EidosRegisteredString(\"SLiMEidosBlock\", gID_SLiMEidosBlock);\nconst std::string &gStr_Community = EidosRegisteredString(\"Community\", gID_Community);\nconst std::string &gStr_SpatialMap = EidosRegisteredString(\"SpatialMap\", gID_SpatialMap);\nconst std::string &gStr_Species = EidosRegisteredString(\"Species\", gID_Species);\nconst std::string &gStr_Subpopulation = EidosRegisteredString(\"Subpopulation\", gID_Subpopulation);\n//const std::string &gStr_Individual = EidosRegisteredString(\"Individual\", gID_Individual);\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nconst std::string &gStr_Substitution = EidosRegisteredString(\"Substitution\", gID_Substitution);\nconst std::string &gStr_InteractionType = EidosRegisteredString(\"InteractionType\", gID_InteractionType);\nconst std::string &gStr_Plot = EidosRegisteredString(\"Plot\", gID_Plot);\nconst std::string &gStr_SLiMgui = EidosRegisteredString(\"SLiMgui\", gID_SLiMgui);\n\n// strings for LogFile\nconst std::string &gStr_createLogFile = EidosRegisteredString(\"createLogFile\", gID_createLogFile);\nconst std::string &gStr_logFiles = EidosRegisteredString(\"logFiles\", gID_logFiles);\nconst std::string &gStr_LogFile = EidosRegisteredString(\"LogFile\", gID_LogFile);\nconst std::string &gStr_logInterval = EidosRegisteredString(\"logInterval\", gID_logInterval);\nconst std::string &gStr_precision = EidosRegisteredString(\"precision\", gID_precision);\nconst std::string &gStr_addCustomColumn = EidosRegisteredString(\"addCustomColumn\", gID_addCustomColumn);\nconst std::string &gStr_addCycle = EidosRegisteredString(\"addCycle\", gID_addCycle);\nconst std::string &gStr_addCycleStage = EidosRegisteredString(\"addCycleStage\", gID_addCycleStage);\nconst std::string &gStr_addMeanSDColumns = EidosRegisteredString(\"addMeanSDColumns\", gID_addMeanSDColumns);\nconst std::string &gStr_addPopulationSexRatio = EidosRegisteredString(\"addPopulationSexRatio\", gID_addPopulationSexRatio);\nconst std::string &gStr_addPopulationSize = EidosRegisteredString(\"addPopulationSize\", gID_addPopulationSize);\nconst std::string &gStr_addSubpopulationSexRatio = EidosRegisteredString(\"addSubpopulationSexRatio\", gID_addSubpopulationSexRatio);\nconst std::string &gStr_addSubpopulationSize = EidosRegisteredString(\"addSubpopulationSize\", gID_addSubpopulationSize);\nconst std::string &gStr_addSuppliedColumn = EidosRegisteredString(\"addSuppliedColumn\", gID_addSuppliedColumn);\nconst std::string &gStr_addTick = EidosRegisteredString(\"addTick\", gID_addTick);\nconst std::string &gStr_flush = EidosRegisteredString(\"flush\", gID_flush);\nconst std::string &gStr_logRow = EidosRegisteredString(\"logRow\", gID_logRow);\nconst std::string &gStr_setLogInterval = EidosRegisteredString(\"setLogInterval\", gID_setLogInterval);\nconst std::string &gStr_setFilePath = EidosRegisteredString(\"setFilePath\", gID_setFilePath);\nconst std::string &gStr_setSuppliedValue = EidosRegisteredString(\"setSuppliedValue\", gID_setSuppliedValue);\nconst std::string &gStr_willAutolog = EidosRegisteredString(\"willAutolog\", gID_willAutolog);\nconst std::string &gStr_context = EidosRegisteredString(\"context\", gID_context);\n\n// mostly other fixed strings\nconst std::string gStr_A = \"A\";\t// these nucleotide strings are not registered, no need\nconst std::string gStr_C = \"C\";\nconst std::string gStr_G = \"G\";\nconst std::string gStr_T = \"T\";\nconst std::string gStr_H = \"H\";\t// these chromosome type strings (and \"A\" above) are not registered, no need\nconst std::string gStr_X = \"X\";\nconst std::string gStr_Y = \"Y\";\nconst std::string gStr_Z = \"Z\";\nconst std::string gStr_W = \"W\";\nconst std::string gStr_HF = \"HF\";\nconst std::string gStr_FL = \"FL\";\nconst std::string gStr_HM = \"HM\";\nconst std::string gStr_ML = \"ML\";\nconst std::string gStr_H_ = \"H-\";\nconst std::string gStr__Y = \"-Y\";\nconst std::string &gStr_f = EidosRegisteredString(\"f\", gID_f);\nconst std::string &gStr_g = EidosRegisteredString(\"g\", gID_g);\nconst std::string &gStr_e = EidosRegisteredString(\"e\", gID_e);\n//const std::string &gStr_n = EidosRegisteredString(\"n\", gID_n);\t\tnow gEidosStr_n\nconst std::string &gStr_w = EidosRegisteredString(\"w\", gID_w);\nconst std::string &gStr_l = EidosRegisteredString(\"l\", gID_l);\nconst std::string &gStr_p = EidosRegisteredString(\"p\", gID_p);\n//const std::string &gStr_s = EidosRegisteredString(\"s\", gID_s);\t\tnow gEidosStr_s\nconst std::string &gStr_species = EidosRegisteredString(\"species\", gID_species);\nconst std::string &gStr_ticks = EidosRegisteredString(\"ticks\", gID_ticks);\nconst std::string &gStr_speciesSpec = EidosRegisteredString(\"speciesSpec\", gID_speciesSpec);\nconst std::string &gStr_ticksSpec = EidosRegisteredString(\"ticksSpec\", gID_ticksSpec);\nconst std::string &gStr_first = EidosRegisteredString(\"first\", gID_first);\nconst std::string &gStr_early = EidosRegisteredString(\"early\", gID_early);\nconst std::string &gStr_late = EidosRegisteredString(\"late\", gID_late);\nconst std::string &gStr_initialize = EidosRegisteredString(\"initialize\", gID_initialize);\nconst std::string &gStr_fitnessEffect = EidosRegisteredString(\"fitnessEffect\", gID_fitnessEffect);\nconst std::string &gStr_mutationEffect = EidosRegisteredString(\"mutationEffect\", gID_mutationEffect);\nconst std::string &gStr_interaction = EidosRegisteredString(\"interaction\", gID_interaction);\nconst std::string &gStr_mateChoice = EidosRegisteredString(\"mateChoice\", gID_mateChoice);\nconst std::string &gStr_modifyChild = EidosRegisteredString(\"modifyChild\", gID_modifyChild);\nconst std::string &gStr_recombination = EidosRegisteredString(\"recombination\", gID_recombination);\nconst std::string &gStr_mutation = EidosRegisteredString(\"mutation\", gID_mutation);\nconst std::string &gStr_survival = EidosRegisteredString(\"survival\", gID_survival);\nconst std::string &gStr_reproduction = EidosRegisteredString(\"reproduction\", gID_reproduction);\n\n\nvoid SLiM_ConfigureContext(void)\n{\n\tstatic bool been_here = false;\n\t\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SLiM_ConfigureContext(): not warmed up\");\n\t\n\tif (!been_here)\n\t{\n\t\tbeen_here = true;\n\t\t\n\t\tgEidosContextVersion = SLIM_VERSION_FLOAT;\n\t\tgEidosContextVersionString = std::string(\"SLiM version \") + std::string(SLIM_VERSION_STRING);\n\t\tgEidosContextLicense = \"SLiM is free software: you can redistribute it and/or\\nmodify it under the terms of the GNU General Public\\nLicense as published by the Free Software Foundation,\\neither version 3 of the License, or (at your option)\\nany later version.\\n\\nSLiM is distributed in the hope that it will be\\nuseful, but WITHOUT ANY WARRANTY; without even the\\nimplied warranty of MERCHANTABILITY or FITNESS FOR\\nA PARTICULAR PURPOSE.  See the GNU General Public\\nLicense for more details.\\n\\nYou should have received a copy of the GNU General\\nPublic License along with SLiM.  If not, see\\n<http://www.gnu.org/licenses/>.\\n\";\n\t\tgEidosContextCitation = \"To cite SLiM in publications please use:\\n\\nHaller, B.C., Ralph, P.L., and Messer, P.W. (2026).\\nSLiM 5: Eco-evolutionary simulations across multiple\\nchromosomes and full genomes. Molecular Biology and\\nEvolution 43(1): msaf313.\\nDOI: https://doi.org/10.1093/molbev/msaf313\\n\\nFor papers using tree-sequence recording, please cite:\\n\\nHaller, B.C., Galloway, J., Kelleher, J., Messer, P.W.,\\n& Ralph, P.L. (2019). Tree‐sequence recording in SLiM\\nopens new horizons for forward‐time simulation of whole\\ngenomes. Molecular Ecology Resources 19(2), 552-566.\\nDOI: https://doi.org/10.1111/1755-0998.12968\\n\";\n\t\t\n\t\t// Make a list of symbols that are not allowed as global constants or variables, because they would\n\t\t// potentially conflict with pseudo-parameters or other facilities downstream.\n\t\tgEidosContextReservedSymbols.push_back(\"self\");\n\t\tgEidosContextReservedSymbols.push_back(\"community\");\n\t\tgEidosContextReservedSymbols.push_back(\"sim\");\n\t\tgEidosContextReservedSymbols.push_back(\"slimgui\");\n\t\tgEidosContextReservedSymbols.push_back(\"context\");\t\t// defined by LogFile\n\t\tgEidosContextReservedSymbols.push_back(\"distance\");\t\t// defined in ApplyInteractionCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"strength\");\t\t// defined in ApplyInteractionCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"receiver\");\t\t// defined in ApplyInteractionCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"exerter\");\t\t// defined in ApplyInteractionCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"mut\");\t\t\t// defined in ApplyMutationEffectCallbacks() etc.\n\t\tgEidosContextReservedSymbols.push_back(\"effect\");\t\t// defined in ApplyMutationEffectCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"individual\");\t// defined in ApplyMutationEffectCallbacks() etc.\n\t\tgEidosContextReservedSymbols.push_back(\"subpop\");\t\t// defined in ApplyMutationEffectCallbacks() etc.\n\t\tgEidosContextReservedSymbols.push_back(\"homozygous\");\t// defined in ApplyMutationEffectCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"fitness\");\t\t// defined in ApplySurvivalCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"draw\");\t\t\t// defined in ApplySurvivalCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"surviving\");\t// defined in ApplySurvivalCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"sourceSubpop\");\t// defined in ApplyMateChoiceCallbacks() etc.\n\t\tgEidosContextReservedSymbols.push_back(\"weights\");\t\t// defined in ApplyMateChoiceCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"child\");\t\t// defined in ApplyModifyChildCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"parent1\");\t\t// defined in ApplyModifyChildCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"isSelfing\");\t// defined in ApplyModifyChildCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"isCloning\");\t// defined in ApplyModifyChildCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"parent2\");\t\t// defined in ApplyModifyChildCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"haplosome1\");\t// defined in ApplyRecombinationCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"haplosome2\");\t// defined in ApplyRecombinationCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"parent\");\t\t// defined in ApplyMutationCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"haplosome\");\t// defined in ApplyMutationCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"element\");\t\t// defined in ApplyMutationCallbacks()\n\t\tgEidosContextReservedSymbols.push_back(\"originalNuc\");\t// defined in ApplyMutationCallbacks()\n\t}\n}\n\n\n// *************************************\n//\n//\tTSKIT/tree sequence tables related\n//\n#pragma mark -\n#pragma mark Tree sequences\n#pragma mark -\n\n// Metadata schemas:\n// These should be valid json strings, parseable by python's json.loads( )\n// and then turned into a valid metadata schema by tskit.MetadataSchema( ).\n// You can check these by doing, in python:\n// ```\n// t = ( <paste in everything below except final semicolon> )\n// d = json.loads(t)\n// m = tskit.MetadataSchema(d)\n// for e in d['examples']:\n//    m.encode_row(e)\n// ```\n// Furthermore, so that they match with the way python would do it,\n// we've produced these by doing :\n// ```\n// import pyslim\n// for ms in pyslim.slim_metadata_schemas:\n//   print(ms)\n//   print(str(pyslim.slim_metadata_schemas[ms]))\n// ```\n// See the pyslim code for readable versions of these.\n\n// For more info on schemas in tskit, see: https://tskit.dev/tskit/docs/stable/metadata.html#sec-metadata\n \n// BCH 11/7/2021: Since I have been needing to modify these here by hand, I have changed them into C++ raw string literals.\n// I have also added some code in SLiM_WarmUp() that checks that the metadata schemas are all valid JSON, and optionally prints them.\n// see https://stackoverflow.com/a/5460235/2752221\n\n// This is a useful JSON editor: https://jsoneditoronline.org/\n\n// BCH 12/9/2024: Added the new optional key `chromosomes`, providing an array of information about chromosomes (to support\n// multiple chromosomes), and the new required key `this_chromosome` specifying information about this file's chromosome.\nconst std::string gSLiM_tsk_metadata_schema =\nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"codec\":\"json\",\"examples\":[{\"SLiM\":{\"file_version\":\"0.9\",\"name\":\"fox\",\"description\":\"foxes on Catalina island\",\"cycle\":123,\"tick\":123,\"model_type\":\"WF\",\"this_chromosome\":{\"id\":1,\"index\":0,\"symbol\":\"1\",\"name\":\"autosome_1\",\"type\":\"A\"},\"chromosomes\":[{\"id\":1,\"symbol\":\"1\",\"name\":\"autosome_1\",\"type\":\"A\"},{\"id\":35,\"symbol\":\"MT\",\"name\":\"mtDNA\",\"type\":\"HF\"}],\"nucleotide_based\":false,\"separate_sexes\":true,\"spatial_dimensionality\":\"xy\",\"spatial_periodicity\":\"x\"}}],\"properties\":{\"SLiM\":{\"description\":\"Top-level metadata for a SLiM tree sequence, file format version 0.9\",\"properties\":{\"file_version\":{\"description\":\"The SLiM 'file format version' of this tree sequence.\",\"type\":\"string\"},\"name\":{\"description\":\"The SLiM species name represented by this tree sequence.\",\"type\":\"string\"},\"description\":{\"description\":\"A user-configurable description of the species represented by this tree sequence.\",\"type\":\"string\"},\"cycle\":{\"description\":\"The 'SLiM cycle' counter when this tree sequence was recorded.\",\"type\":\"integer\"},\"tick\":{\"description\":\"The 'SLiM tick' counter when this tree sequence was recorded.\",\"type\":\"integer\"},\"model_type\":{\"description\":\"The model type used for the last part of this simulation (WF or nonWF).\",\"enum\":[\"WF\",\"nonWF\"],\"type\":\"string\"},\"this_chromosome\":{\"description\":\"The chromosome represented by the tree sequence in this file.\",\"properties\":{\"id\":{\"description\":\"An integer identifier for the chromosome, unique within this set of tree sequences; often the chromosome number in the organism being represented, such as 1.\",\"type\":\"integer\"},\"index\":{\"description\":\"The (zero-based) index of this chromosome in the chromosomes metadata array (if present), which should match the information given here.\",\"type\":\"integer\"},\"symbol\":{\"description\":\"A short string symbol for the chromosome, unique within this set of tree sequences, such as \\\"1\\\" or \\\"MT\\\".\",\"type\":\"string\"},\"name\":{\"description\":\"A user-specified name for the chromosome, such as an accession identifier.\",\"type\":\"string\"},\"type\":{\"description\":\"The type of chromosome, as specified by SLiM.\",\"type\":\"string\"}},\"required\":[\"id\",\"index\",\"symbol\",\"type\"],\"type\":\"object\"},\"chromosomes\":{\"description\":\"The chromosomes represented by the collection of tree sequences, of which this tree sequence is one member.\",\"items\":{\"properties\":{\"id\":{\"description\":\"An integer identifier for the chromosome, unique within this set of tree sequences; often the chromosome number in the organism being represented, such as 1.\",\"type\":\"integer\"},\"symbol\":{\"description\":\"A short string symbol for the chromosome, unique within this set of tree sequences, such as \\\"1\\\" or \\\"MT\\\".\",\"type\":\"string\"},\"name\":{\"description\":\"A user-specified name for the chromosome, such as an accession identifier.\",\"type\":\"string\"},\"type\":{\"description\":\"The type of chromosome, as specified by SLiM.\",\"type\":\"string\"}},\"required\":[\"id\",\"symbol\",\"type\"],\"type\":\"object\"},\"type\":\"array\"},\"nucleotide_based\":{\"description\":\"Whether the simulation was nucleotide-based.\",\"type\":\"boolean\"},\"separate_sexes\":{\"description\":\"Whether the simulation had separate sexes.\",\"type\":\"boolean\"},\"spatial_dimensionality\":{\"description\":\"The spatial dimensionality of the simulation.\",\"enum\":[\"\",\"x\",\"xy\",\"xyz\"],\"type\":\"string\"},\"spatial_periodicity\":{\"description\":\"The spatial periodicity of the simulation.\",\"enum\":[\"\",\"x\",\"y\",\"z\",\"xy\",\"xz\",\"yz\",\"xyz\"],\"type\":\"string\"},\"stage\":{\"description\":\"The stage of the SLiM life cycle when this tree sequence was recorded.\",\"type\":\"string\"}},\"required\":[\"model_type\",\"tick\",\"file_version\",\"spatial_dimensionality\",\"spatial_periodicity\",\"this_chromosome\",\"separate_sexes\",\"nucleotide_based\"],\"type\":\"object\"}},\"required\":[\"SLiM\"],\"type\":\"object\"})V0G0N\";\n\nconst std::string gSLiM_tsk_edge_metadata_schema = \"\";\nconst std::string gSLiM_tsk_site_metadata_schema = \"\";\n\nconst std::string gSLiM_tsk_mutation_metadata_schema =\nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"additionalProperties\":false,\"codec\":\"struct\",\"description\":\"SLiM schema for mutation metadata.\",\"examples\":[{\"mutation_list\":[{\"mutation_type\":1,\"nucleotide\":3,\"selection_coeff\":-0.2,\"slim_time\":243,\"subpopulation\":0}]}],\"properties\":{\"mutation_list\":{\"items\":{\"additionalProperties\":false,\"properties\":{\"mutation_type\":{\"binaryFormat\":\"i\",\"description\":\"The index of this mutation's mutationType.\",\"index\":1,\"type\":\"integer\"},\"nucleotide\":{\"binaryFormat\":\"b\",\"description\":\"The nucleotide for this mutation (0=A , 1=C , 2=G, 3=T, or -1 for none)\",\"index\":5,\"type\":\"integer\"},\"selection_coeff\":{\"binaryFormat\":\"f\",\"description\":\"This mutation's selection coefficient.\",\"index\":2,\"type\":\"number\"},\"slim_time\":{\"binaryFormat\":\"i\",\"description\":\"The SLiM tick counter when this mutation occurred.\",\"index\":4,\"type\":\"integer\"},\"subpopulation\":{\"binaryFormat\":\"i\",\"description\":\"The ID of the subpopulation this mutation occurred in.\",\"index\":3,\"type\":\"integer\"}},\"required\":[\"mutation_type\",\"selection_coeff\",\"subpopulation\",\"slim_time\",\"nucleotide\"],\"type\":\"object\"},\"noLengthEncodingExhaustBuffer\":true,\"type\":\"array\"}},\"required\":[\"mutation_list\"],\"type\":\"object\"})V0G0N\";\n\n// BCH 12/10/2024: Removed the type field, and changed the treatment of is_vacant.  We have a\n// tricky problem here, which is that is_vacant is now variable-length and there is no count.\n// The number of byte (uint8_t) entries in is_vacant depends on the number of chromosomes in\n// the full set of tree sequences, because the node metadata has to contain flags (bits) for\n// every chromosome, not just for the chromosome represented by this file.  So we deduce the\n// length of is_vacant from that, but it is variable-length and has no count associated with\n// it in the metadata.  I think this is actually not allowed in JSON Schema, understandably.\n// To make this work, we have to write out a DIFFERENT VERSION OF THIS METADATA SCHEMA\n// depending on the number of bytes used.  In other words, if 7 bytes of is_vacant data are\n// needed (for 49-56 chromosomes), we'd write out a version of the schema that specifies\n// 7 bytes of is_vacant data using binaryFormat:7B.  This effectively puts the count into the\n// schema itself.  The number of bytes present can thus be inferred from the schema present\n// in the file, but also from the 'chromosomes' top-level metadata key; one bit is taken\n// for each chromosome, in order, regardless of their type, providing flags for one node\n// table entry for one haplosome of each chromosome.  (Remember, there are two node table\n// entries per individual; the first corresponds to haplosome 1, so its is_vacant data only\n// records is_vacant flags for haplosome 1 of each chromosome, and similarly for the second\n// node table entry corresponding to haplosome 2 of each chromosome.)  The variable name here\n// ends in \"_FORMAT\" because it is a format string containing `%d`, which must be replaced\n// by the correct byte count when it is used for output.  See SetCurrentNewIndividual() and\n// RecordNewHaplosome() for how this dynamic metadata structure is used in practice, and\n// WriteTreeSequenceMetadata() for where this schema format string is used.\n//\n// BCH 4/10/2025: Changing from binary format 's' to 'B', using the new support for fixed-\n// length arrays in tskit: https://github.com/tskit-dev/tskit/issues/3088.  This has been\n// released in tskit version Python 0.6.1.  The new syntax for declaring a fixed-length\n// array is: {\"type\": \"array\", \"length\": 3, \"items\": {\"type\":\"number\", \"binaryFormat\":\"B\"}}.\n// The length, 3 here, is encoded with \"%d\" and replaced at runtime with the correct count.\n// (The string replaced is \"%d\" *including* the quotes, because the format string needs to\n// itself be a legal JSON string in order to pass SLiM's own internal checks, so beware.)\nconst std::string gSLiM_tsk_node_metadata_schema_FORMAT =\nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"additionalProperties\":false,\"codec\":\"struct\",\"description\":\"SLiM schema for node metadata.\",\"examples\":[{\"is_vacant\":0,\"slim_id\":123}],\"properties\":{\"is_vacant\":{\"description\":\"A vector of byte (uint8_t) values, with each bit representing whether the node represents a vacant position, either unused or a null haplosome (1), or a non-null haplosome (0), in the corresponding chromosome. This field encodes vacancy for all of the chromosomes in the model, not just the chromosome represented in this file (so that the node table is identical across all chromosomes for a multi-chromosome model). Each chromosome receives one bit here; there are two node table entries per individual, used for the two haplosomes of every chromosome, so only one bit is needed in each entry (making two bits total per chromosome, across the two node table entries). The least significant bit of the first byte is used first (for one haplosome of the first chromosome); the most significant bit of the last byte is used last. The number of bytes present in this field is indicated by this schema's 'binaryFormat' field, which is variable (!), and can also be deduced from the number of chromosomes in the model as given in the top-level 'chromosomes' metadata key, which should always be present if this metadata is present.\",\"index\":1,\"items\":{\"binaryFormat\":\"B\",\"type\":\"number\"},\"length\":\"%d\",\"type\":\"array\"},\"slim_id\":{\"binaryFormat\":\"q\",\"description\":\"The 'pedigree ID' of the haplosomes associated with this node in SLiM.\",\"index\":0,\"type\":\"integer\"}},\"required\":[\"slim_id\",\"is_vacant\"],\"type\":[\"object\",\"null\"]})V0G0N\";\n\nconst std::string gSLiM_tsk_individual_metadata_schema =\nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"additionalProperties\":false,\"codec\":\"struct\",\"description\":\"SLiM schema for individual metadata.\",\"examples\":[{\"age\":-1,\"flags\":0,\"pedigree_id\":123,\"pedigree_p1\":12,\"pedigree_p2\":23,\"sex\":0,\"subpopulation\":0}],\"flags\":{\"SLIM_INDIVIDUAL_METADATA_MIGRATED\":{\"description\":\"Whether this individual was a migrant, either in the tick when the tree sequence was written out (if the individual was alive then), or in the tick of the last time they were Remembered (if not).\",\"value\":1}},\"properties\":{\"age\":{\"binaryFormat\":\"i\",\"description\":\"The age of this individual, either when the tree sequence was written out (if the individual was alive then), or the last time they were Remembered (if not).\",\"index\":4,\"type\":\"integer\"},\"flags\":{\"binaryFormat\":\"I\",\"description\":\"Other information about the individual: see 'flags'.\",\"index\":7,\"type\":\"integer\"},\"pedigree_id\":{\"binaryFormat\":\"q\",\"description\":\"The 'pedigree ID' of this individual in SLiM.\",\"index\":1,\"type\":\"integer\"},\"pedigree_p1\":{\"binaryFormat\":\"q\",\"description\":\"The 'pedigree ID' of this individual's first parent in SLiM.\",\"index\":2,\"type\":\"integer\"},\"pedigree_p2\":{\"binaryFormat\":\"q\",\"description\":\"The 'pedigree ID' of this individual's second parent in SLiM.\",\"index\":3,\"type\":\"integer\"},\"sex\":{\"binaryFormat\":\"i\",\"description\":\"The sex of the individual (0 for female, 1 for male, -1 for hermaphrodite).\",\"index\":6,\"type\":\"integer\"},\"subpopulation\":{\"binaryFormat\":\"i\",\"description\":\"The ID of the subpopulation the individual was part of, either when the tree sequence was written out (if the individual was alive then), or the last time they were Remembered (if not).\",\"index\":5,\"type\":\"integer\"}},\"required\":[\"pedigree_id\",\"pedigree_p1\",\"pedigree_p2\",\"age\",\"subpopulation\",\"sex\",\"flags\"],\"type\":\"object\"})V0G0N\";\n\n// This schema was obsoleted in SLiM 3.7; we now use a JSON schema for the population metadata (see below)\nconst std::string gSLiM_tsk_population_metadata_schema_PREJSON = \nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"additionalProperties\":false,\"codec\":\"struct\",\"description\":\"SLiM schema for population metadata.\",\"examples\":[{\"bounds_x0\":0.0,\"bounds_x1\":100.0,\"bounds_y0\":0.0,\"bounds_y1\":100.0,\"bounds_z0\":0.0,\"bounds_z1\":100.0,\"female_cloning_fraction\":0.25,\"male_cloning_fraction\":0.0,\"migration_records\":[{\"migration_rate\":0.9,\"source_subpop\":1},{\"migration_rate\":0.1,\"source_subpop\":2}],\"selfing_fraction\":0.5,\"sex_ratio\":0.5,\"slim_id\":2}],\"properties\":{\"bounds_x0\":{\"binaryFormat\":\"d\",\"description\":\"The minimum x-coordinate in this subpopulation.\",\"index\":6,\"type\":\"number\"},\"bounds_x1\":{\"binaryFormat\":\"d\",\"description\":\"The maximum x-coordinate in this subpopulation.\",\"index\":7,\"type\":\"number\"},\"bounds_y0\":{\"binaryFormat\":\"d\",\"description\":\"The minimum y-coordinate in this subpopulation.\",\"index\":8,\"type\":\"number\"},\"bounds_y1\":{\"binaryFormat\":\"d\",\"description\":\"The maximum y-coordinate in this subpopulation.\",\"index\":9,\"type\":\"number\"},\"bounds_z0\":{\"binaryFormat\":\"d\",\"description\":\"The minimum z-coordinate in this subpopulation.\",\"index\":10,\"type\":\"number\"},\"bounds_z1\":{\"binaryFormat\":\"d\",\"description\":\"The maximum z-coordinate in this subpopulation.\",\"index\":11,\"type\":\"number\"},\"female_cloning_fraction\":{\"binaryFormat\":\"d\",\"description\":\"The frequency with which females in this subpopulation reproduce clonally (for WF models).\",\"index\":3,\"type\":\"number\"},\"male_cloning_fraction\":{\"binaryFormat\":\"d\",\"description\":\"The frequency with which males in this subpopulation reproduce clonally (for WF models).\",\"index\":4,\"type\":\"number\"},\"migration_records\":{\"arrayLengthFormat\":\"I\",\"index\":13,\"items\":{\"additionalProperties\":false,\"properties\":{\"migration_rate\":{\"binaryFormat\":\"d\",\"description\":\"The fraction of children in this subpopulation that are composed of 'migrants' from the source subpopulation (in WF models).\",\"index\":2,\"type\":\"number\"},\"source_subpop\":{\"binaryFormat\":\"i\",\"description\":\"The ID of the subpopulation migrants come from (in WF models).\",\"index\":1,\"type\":\"integer\"}},\"required\":[\"source_subpop\",\"migration_rate\"],\"type\":\"object\"},\"type\":\"array\"},\"selfing_fraction\":{\"binaryFormat\":\"d\",\"description\":\"The frequency with which individuals in this subpopulation self (for WF models).\",\"index\":2,\"type\":\"number\"},\"sex_ratio\":{\"binaryFormat\":\"d\",\"description\":\"This subpopulation's sex ratio (for WF models).\",\"index\":5,\"type\":\"number\"},\"slim_id\":{\"binaryFormat\":\"i\",\"description\":\"The ID of this population in SLiM. Note that this is called a 'subpopulation' in SLiM.\",\"index\":1,\"type\":\"integer\"}},\"required\":[\"slim_id\",\"selfing_fraction\",\"female_cloning_fraction\",\"male_cloning_fraction\",\"sex_ratio\",\"bounds_x0\",\"bounds_x1\",\"bounds_y0\",\"bounds_y1\",\"bounds_z0\",\"bounds_z1\",\"migration_records\"],\"type\":[\"object\",\"null\"]})V0G0N\";\n\n// BCH 19 May 2022: removed the `required` status for the \"slim_id\" key for SLiM 4, to allow \"carryover\" metadata\n// to validate without errors (but for it to be considered SLiM metadata, \"slim_id\" must nevertheless be present).\n// This is a change from SLiM 3.7 (and before SLiM 3.7 we were pre-JSON), but we don't need to have the SLiM 3.7\n// schema in SLiM since we don't check/validate schemas anyway in SLiM; we will just write out this new schema in\n// SLiM 4, and on read we won't care whether the schema is the 3.7 or the 4.0 schema.\nconst std::string gSLiM_tsk_population_metadata_schema = \nR\"V0G0N({\"$schema\":\"http://json-schema.org/schema#\",\"additionalProperties\":true,\"codec\":\"json\",\"description\":\"SLiM schema for population metadata.\",\"examples\":[{\"bounds_x0\":0.0,\"bounds_x1\":100.0,\"bounds_y0\":0.0,\"bounds_y1\":100.0,\"female_cloning_fraction\":0.25,\"male_cloning_fraction\":0.0,\"migration_records\":[{\"migration_rate\":0.9,\"source_subpop\":1},{\"migration_rate\":0.1,\"source_subpop\":2}],\"name\":\"p2\",\"selfing_fraction\":0.5,\"sex_ratio\":0.5,\"slim_id\":2}],\"properties\":{\"bounds_x0\":{\"description\":\"The minimum x-coordinate in this subpopulation.\",\"type\":\"number\"},\"bounds_x1\":{\"description\":\"The maximum x-coordinate in this subpopulation.\",\"type\":\"number\"},\"bounds_y0\":{\"description\":\"The minimum y-coordinate in this subpopulation.\",\"type\":\"number\"},\"bounds_y1\":{\"description\":\"The maximum y-coordinate in this subpopulation.\",\"type\":\"number\"},\"bounds_z0\":{\"description\":\"The minimum z-coordinate in this subpopulation.\",\"type\":\"number\"},\"bounds_z1\":{\"description\":\"The maximum z-coordinate in this subpopulation.\",\"type\":\"number\"},\"description\":{\"description\":\"A description of this subpopulation.\",\"type\":\"string\"},\"female_cloning_fraction\":{\"description\":\"The frequency with which females in this subpopulation reproduce clonally (for WF models).\",\"type\":\"number\"},\"male_cloning_fraction\":{\"description\":\"The frequency with which males in this subpopulation reproduce clonally (for WF models).\",\"type\":\"number\"},\"migration_records\":{\"items\":{\"properties\":{\"migration_rate\":{\"description\":\"The fraction of children in this subpopulation that are composed of 'migrants' from the source subpopulation (in WF models).\",\"type\":\"number\"},\"source_subpop\":{\"description\":\"The ID of the subpopulation migrants come from (in WF models).\",\"type\":\"integer\"}},\"required\":[\"source_subpop\",\"migration_rate\"],\"type\":\"object\"},\"type\":\"array\"},\"name\":{\"description\":\"A human-readable name for this subpopulation.\",\"type\":\"string\"},\"selfing_fraction\":{\"description\":\"The frequency with which individuals in this subpopulation self (for WF models).\",\"type\":\"number\"},\"sex_ratio\":{\"description\":\"This subpopulation's sex ratio (for WF models).\",\"type\":\"number\"},\"slim_id\":{\"description\":\"The ID of this population in SLiM. Note that this is called a 'subpopulation' in SLiM.\",\"type\":\"integer\"}},\"required\":[],\"type\":[\"object\",\"null\"]})V0G0N\";\n\n\n// *************************************\n//\n//\tProfiling\n//\n#pragma mark -\n#pragma mark Profiling\n#pragma mark -\n\n#if (SLIMPROFILING == 1)\n//\n//\tSupport for profiling at the command line, and emitting the profile report in HTML\n//\tThis is very parallel to the profile reporting code in SLiMguiLegacy and QtSLiM,\n//\tbut without Cocoa or Qt, and emitting HTML instead of widget kit formats\n//\n\n#if DEBUG\n#error In order to obtain accurate timing information that is relevant to the actual runtime of a model, profiling requires that you are running a Release build of SLiM.\n#endif\n\nstatic std::string StringForByteCount(int64_t bytes)\n{\n\tchar buf[128];\t\t// used for printf-style formatted strings\n\t\n\tif (bytes > 512LL * 1024L * 1024L * 1024L)\n\t{\n\t\tsnprintf(buf, 128, \"%0.2f\", bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0));\n\t\treturn std::string(buf).append(\" TB\");\n\t}\n\telse if (bytes > 512L * 1024L * 1024L)\n\t{\n\t\tsnprintf(buf, 128, \"%0.2f\", bytes / (1024.0 * 1024.0 * 1024.0));\n\t\treturn std::string(buf).append(\" GB\");\n\t}\n\telse if (bytes > 512L * 1024L)\n\t{\n\t\tsnprintf(buf, 128, \"%0.2f\", bytes / (1024.0 * 1024.0));\n\t\treturn std::string(buf).append(\" MB\");\n\t}\n\telse if (bytes > 512L)\n\t{\n\t\tsnprintf(buf, 128, \"%0.2f\", bytes / (1024.0));\n\t\treturn std::string(buf).append(\" KB\");\n\t}\n\telse\n\t{\n\t\tsnprintf(buf, 128, \"%lld\", (long long int)bytes);\n\t\treturn std::string(buf).append(\" bytes\");\n\t}\n}\n\n#define SLIM_YELLOW_FRACTION 0.10\n#define SLIM_SATURATION 0.75\n\nstatic std::string SpanTagForColorFraction(double color_fraction)\n{\n\tdouble r, g, b;\n\tchar buf[256];\n\t\n\tif (color_fraction < SLIM_YELLOW_FRACTION)\n\t{\n\t\t// small fractions fall on a ramp from white (0.0) to yellow (SLIM_YELLOW_FRACTION)\n\t\tr = 1.0;\n\t\tg = 1.0;\n\t\tb = 1.0 - (color_fraction / SLIM_YELLOW_FRACTION) * SLIM_SATURATION;\n\t}\n\telse\n\t{\n\t\t// larger fractions ramp from yellow (SLIM_YELLOW_FRACTION) to red (1.0)\n\t\tr = 1.0;\n\t\tg = (1.0 - (color_fraction - SLIM_YELLOW_FRACTION) / (1.0 - SLIM_YELLOW_FRACTION));\n\t\tb = 0.0;\n\t}\n\t\n\tsnprintf(buf, 256, \"<span style='background-color:rgb(%d,%d,%d);'>\", (int)round(r * 255), (int)round(g * 255), (int)round(b * 255));\n\treturn std::string(buf);\n}\n\nstatic void _ColorScriptWithProfileCounts(const EidosASTNode *node, double elapsedTime, int32_t baseIndex, double *color_fractions)\n{\n\teidos_profile_t count = node->profile_total_;\n\t\n\tif (count > 0)\n\t{\n\t\tint32_t start = 0, end = 0;\n\t\t\n\t\tnode->FullUTF8Range(&start, &end);\n\t\t\n\t\tstart -= baseIndex;\n\t\tend -= baseIndex;\n\t\t\n\t\tdouble color_fraction = Eidos_ElapsedProfileTime(count) / elapsedTime;\n\t\t\n\t\tfor (int32_t pos = start; pos <= end; pos++)\n\t\t\tcolor_fractions[pos] = color_fraction;\n\t}\n\t\n\t// Then let child nodes color\n\tfor (const EidosASTNode *child : node->children_)\n\t\t_ColorScriptWithProfileCounts(child, elapsedTime, baseIndex, color_fractions);\n}\n\nstatic std::string ColorScriptWithProfileCounts(std::string script, const EidosASTNode *node, double elapsedTime, int32_t baseIndex)\n{\n\tconst char *script_data = script.data();\n\tsize_t script_len = script.length();\n\tdouble *color_fractions = (double *)calloc(script_len, sizeof(double));\n\t\n\t// Color our range, and all children's ranges recursively\n\t_ColorScriptWithProfileCounts(node, elapsedTime, baseIndex, color_fractions);\n\t\n\t// Assemble our result string\n\tstd::string result;\n\tdouble last_fraction = -1.0;\n\t\n\tfor (size_t pos = 0; pos < script_len; ++pos)\n\t{\n\t\t// change the color if necessary\n\t\tif (color_fractions[pos] != last_fraction)\n\t\t{\n\t\t\tif (pos > 0)\n\t\t\t\tresult.append(\"</span>\");\n\t\t\t\n\t\t\tlast_fraction = color_fractions[pos];\n\t\t\tresult.append(SpanTagForColorFraction(last_fraction));\n\t\t}\n\t\t\n\t\t// emit the character, escaped as needed\n\t\tchar ch = script_data[pos];\n\t\t\n\t\tif (ch == '&') result.append(\"&amp;\");\n\t\telse if (ch == '<') result.append(\"&lt;\");\n\t\telse if (ch == '>') result.append(\"&gt;\");\n\t\telse if (ch == '\\n') result.append(\"<BR>\\n\");\n\t\telse if (ch == '\\r') ;\n\t\telse if (ch == '\\t') result.append(\"&nbsp;&nbsp;&nbsp;\");\n\t\telse result.append(1, ch);\n\t}\n\t\n\tif (script_len > 0)\n\t\tresult.append(\"</span>\");\n\t\n\tfree(color_fractions);\n\treturn result;\n}\n\nstatic std::string ColoredSpanForByteCount(int64_t bytes, double total)\n{\n\tstd::string byteString = StringForByteCount(bytes);\n\tdouble fraction = bytes / total;\n\tstd::string spanTag = SpanTagForColorFraction(fraction);\n\t\n\tspanTag.append(byteString).append(\"</span>\");\n\treturn spanTag;\n}\n\nstatic std::string HTMLEncodeString(const std::string &data)\n{\n\t// This is used to escape characters that have a special meaning in HTML\n\tstd::string buffer;\n\tbuffer.reserve(data.size());\n\t\n\tfor (size_t pos = 0; pos != data.size(); ++pos)\n\t{\n\t\tswitch (data[pos])\n\t\t{\n\t\t\tcase '&':\tbuffer.append(\"&amp;\");       \t\t\tbreak;\n\t\t\tcase '<':\tbuffer.append(\"&lt;\");        \t\t\tbreak;\n\t\t\tcase '>':\tbuffer.append(\"&gt;\");        \t\t\tbreak;\n\t\t\tcase '\\n':\tbuffer.append(\"<BR>\\n\");\t\t\t\tbreak;\n\t\t\tcase '\\r':\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\tcase '\\t':\tbuffer.append(\"&nbsp;&nbsp;&nbsp;\");\tbreak;\n\t\t\tdefault:\tbuffer.append(&data[pos], 1); break;\t\t\t// note we specify UTF-8 encoding, so this works with everything\n\t\t}\n\t}\n\t\n\treturn buffer;\n}\n\nstatic std::string HTMLMakeSpacesNonBreaking(const char *data)\n{\n\t// This is used to convert spaces ni &nbsp;, to make the alignment and formatting work properly\n\tstd::string buffer;\n\tsize_t pos = 0;\n\t\n\twhile (true)\n\t{\n\t\tchar ch = data[pos];\n\t\t\n\t\tif (ch == 0)\t\t\t\tbreak;\n\t\telse if (data[pos] == ' ')\tbuffer.append(\"&nbsp;\");\n\t\telse\t\t\t\t\t\tbuffer.append(&data[pos], 1);\n\t\t\n\t\tpos++;\n\t}\n\t\n\treturn buffer;\n}\n\nvoid WriteProfileResults(std::string profile_output_path, std::string model_name, Community *community)\n{\n\tstd::string resolved_path = Eidos_ResolvedPath(profile_output_path);\n\tstd::ofstream fout(resolved_path);\n\tchar buf[256];\t\t// used for printf-style formatted strings\n\t\n\tif (!fout.is_open())\n\t\tEIDOS_TERMINATION << std::endl << \"ERROR (WriteProfileResults): Could not open profile output path \" << profile_output_path << EidosTerminate();\n\t\n\t//\n\t//\tHTML header\n\t//\n\t\n\tfout << \"<!DOCTYPE HTML PUBLIC \\\"-//W3C//DTD HTML 3.2//EN\\\">\" << \"\\n\";\n\tfout << \"<html>\" << \"\\n\";\n\tfout << \"<head>\" << \"\\n\";\n\tfout << \"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>\" << \"\\n\";\n\tfout << \"<meta http-equiv='Content-Style-Type' content='text/css'>\" << \"\\n\";\n\tfout << \"<title>Profile Report</title>\" << \"\\n\";\n\tfout << \"<meta name='Generator' content='SLiM'>\" << \"\\n\";\n\tfout << \"<style type='text/css'>\" << \"\\n\";\n\tfout << \"    body {font-family: Optima,sans-serif; font-size: 14;}\" << \"\\n\";\n\tfout << \"    h2 {margin-bottom: 0px;}\" << \"\\n\";\n\tfout << \"    h3 {margin-bottom: 0px;}\" << \"\\n\";\n\tfout << \"    p {margin-top: 5px;}\" << \"\\n\";\n\tfout << \"    tt {font-family: Menlo,monospace; font-size: 13;}\" << \"\\n\";\n\tfout << \"</style>\" << \"\\n\";\n\tfout << \"</head>\" << \"\\n\\n\";\n\tfout << \"<body>\" << \"\\n\";\n\t\n\t\n\t//\n\t//\tProfile header\n\t//\n\t\n\tdouble elapsedWallClockTime = (std::chrono::duration_cast<std::chrono::microseconds>(community->profile_end_clock - community->profile_start_clock).count()) / (double)1000000L;\n\tdouble elapsedCPUTimeInSLiM = community->profile_elapsed_CPU_clock / (double)CLOCKS_PER_SEC;\n\tdouble elapsedWallClockTimeInSLiM = Eidos_ElapsedProfileTime(community->profile_elapsed_wall_clock);\n\tslim_tick_t elapsedSLiMTicks = community->profile_end_tick - community->profile_start_tick;\n\t\n\tfout << \"<h2>Profile Report\" << \"</h2>\\n\";\n\tfout << \"<p>Model: \" << model_name << \"</p>\\n\\n\";\n\t\n\tstd::string start_date_string(ctime(&community->profile_start_date));\n\tstd::string end_date_string(ctime(&community->profile_end_date));\n\t\n\tstart_date_string.pop_back();\t\t// remove the trailing newline that ctime() annoyingly adds\n\tend_date_string.pop_back();\n\t\n\tfout << \"<p>Run start: \" << start_date_string << \"<BR>\\n\";\n\tfout << \"Run end: \" << end_date_string << \"</p>\\n\\n\";\n\t\n#ifdef _OPENMP\n\tfout << \"<p>Maximum parallel threads: \" << gEidosMaxThreads << \"</p>\\n\\n\";\n#endif\n\t\n\tsnprintf(buf, 256, \"%0.2f s\", elapsedWallClockTime);\n\tfout << \"<p>Elapsed wall clock time: \" << buf << \"<BR>\\n\";\n\t\n\tsnprintf(buf, 256, \"%0.2f s\", elapsedWallClockTimeInSLiM);\n\tfout << \"Elapsed wall clock time inside SLiM core (corrected): \" << buf << \"<BR>\\n\";\n\t\n\tsnprintf(buf, 256, \"%0.2f\", elapsedCPUTimeInSLiM);\n\tfout << \"Elapsed CPU time inside SLiM core (uncorrected): \" << buf << \" s\" << \"<BR>\\n\";\n\t\n\tfout << \"Elapsed ticks: \" << elapsedSLiMTicks << ((community->profile_start_tick == 0) ? \" (including initialize)\" : \"\") << \"</p>\\n\\n\";\n\t\n\t\n\tsnprintf(buf, 256, \"%0.2f ticks (%0.4g s)\", gEidos_ProfileOverheadTicks, gEidos_ProfileOverheadSeconds);\n\tfout << \"<p>Profile block external overhead: \" << buf << \"<BR>\\n\";\n\t\n\tsnprintf(buf, 256, \"%0.2f ticks (%0.4g s)\", gEidos_ProfileLagTicks, gEidos_ProfileLagSeconds);\n\tfout << \"Profile block internal lag: \" << buf << \"</p>\\n\\n\";\n\t\n\tsize_t total_usage = community->profile_total_memory_usage_Community.totalMemoryUsage + community->profile_total_memory_usage_AllSpecies.totalMemoryUsage;\n\tsize_t average_usage = total_usage / community->total_memory_tallies_;\n\tsize_t last_usage = community->profile_last_memory_usage_Community.totalMemoryUsage + community->profile_last_memory_usage_AllSpecies.totalMemoryUsage;\n\t\n\tfout << \"<p>Average tick SLiM memory use: \" << StringForByteCount(average_usage) << \"<BR>\\n\";\n\tfout << \"Final tick SLiM memory use: \" << StringForByteCount(last_usage) << \"</p>\\n\\n\";\n\t\n\t\n\t//\n\t//\tCycle stage breakdown\n\t//\n\t\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tbool isWF = (community->ModelType() == SLiMModelType::kModelTypeWF);\n\t\tdouble elapsedStage0Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[0]);\n\t\tdouble elapsedStage1Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[1]);\n\t\tdouble elapsedStage2Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[2]);\n\t\tdouble elapsedStage3Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[3]);\n\t\tdouble elapsedStage4Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[4]);\n\t\tdouble elapsedStage5Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[5]);\n\t\tdouble elapsedStage6Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[6]);\n\t\tdouble elapsedStage7Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[7]);\n\t\tdouble elapsedStage8Time = Eidos_ElapsedProfileTime(community->profile_stage_totals_[8]);\n\t\tdouble percentStage0 = (elapsedStage0Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage1 = (elapsedStage1Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage2 = (elapsedStage2Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage3 = (elapsedStage3Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage4 = (elapsedStage4Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage5 = (elapsedStage5Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage6 = (elapsedStage6Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage7 = (elapsedStage7Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percentStage8 = (elapsedStage8Time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage0Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage1Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage2Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage3Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage4Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage5Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage6Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage7Time));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedStage8Time));\n\t\t\n\t\tfout << \"<h3>Cycle stage breakdown\" << \"</h3>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage0Time, percentStage0);\n\t\tfout << \"<p>\" << HTMLMakeSpacesNonBreaking(buf) << \" : initialize() callback execution\" << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage1Time, percentStage1);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 0 - first() event execution\" : \" : stage 0 - first() event execution\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage2Time, percentStage2);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 1 - early() event execution\" : \" : stage 1 - offspring generation\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage3Time, percentStage3);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 2 - offspring generation\" : \" : stage 2 - early() event execution\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage4Time, percentStage4);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 3 - generation swap\" : \" : stage 3 - fitness calculation\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage5Time, percentStage5);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 4 - bookkeeping (fixed mutation removal, etc.)\" : \" : stage 4 - viability/survival selection\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage6Time, percentStage6);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 5 - late() event execution\" : \" : stage 5 - bookkeeping (fixed mutation removal, etc.)\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage7Time, percentStage7);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 6 - fitness calculation\" : \" : stage 6 - late() event execution\") << \"<BR>\\n\";\n\t\t\n\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%5.2f%%)</tt>\", fw, elapsedStage8Time, percentStage8);\n\t\tfout << HTMLMakeSpacesNonBreaking(buf) << (isWF ? \" : stage 7 - tree sequence auto-simplification\" : \" : stage 7 - tree sequence auto-simplification\") << \"</p>\\n\\n\";\n\t}\n\t\n\t\n\t//\n\t//\tCallback type breakdown\n\t//\n\t\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tdouble elapsedTime_first = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventFirst]);\n\t\tdouble elapsedTime_early = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventEarly]);\n\t\tdouble elapsedTime_late = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosEventLate]);\n\t\tdouble elapsedTime_initialize = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInitializeCallback]);\n\t\tdouble elapsedTime_mutationEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationEffectCallback]);\n\t\tdouble elapsedTime_fitnessEffect = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosFitnessEffectCallback]);\n\t\tdouble elapsedTime_interaction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosInteractionCallback]);\n\t\tdouble elapsedTime_matechoice = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMateChoiceCallback]);\n\t\tdouble elapsedTime_modifychild = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosModifyChildCallback]);\n\t\tdouble elapsedTime_recombination = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosRecombinationCallback]);\n\t\tdouble elapsedTime_mutation = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosMutationCallback]);\n\t\tdouble elapsedTime_reproduction = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosReproductionCallback]);\n\t\tdouble elapsedTime_survival = Eidos_ElapsedProfileTime(community->profile_callback_totals_[(int)SLiMEidosBlockType::SLiMEidosSurvivalCallback]);\n\t\tdouble percent_first = (elapsedTime_first / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_early = (elapsedTime_early / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_late = (elapsedTime_late / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_initialize = (elapsedTime_initialize / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitness = (elapsedTime_mutationEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_fitnessglobal = (elapsedTime_fitnessEffect / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_interaction = (elapsedTime_interaction / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_matechoice = (elapsedTime_matechoice / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_modifychild = (elapsedTime_modifychild / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_recombination = (elapsedTime_recombination / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_mutation = (elapsedTime_mutation / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_reproduction = (elapsedTime_reproduction / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tdouble percent_survival = (elapsedTime_survival / elapsedWallClockTimeInSLiM) * 100.0;\n\t\tint fw = 4, fw2 = 4;\n\t\t\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_first));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_early));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_late));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_initialize));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutationEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_fitnessEffect));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_interaction));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_matechoice));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_modifychild));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_recombination));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_mutation));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_reproduction));\n\t\tfw = std::max(fw, 3 + DisplayDigitsForIntegerPart(elapsedTime_survival));\n\t\t\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_first));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_early));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_late));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_initialize));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitness));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_fitnessglobal));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_interaction));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_matechoice));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_modifychild));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_recombination));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_mutation));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_reproduction));\n\t\tfw2 = std::max(fw2, 3 + DisplayDigitsForIntegerPart(percent_survival));\n\t\t\n\t\tfout << \"<h3>Callback type breakdown\" << \"</h3>\\n\";\n\t\t\n\t\t// Note these are out of numeric order, but in cycle stage order\n\t\tif (community->ModelType() == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_initialize, fw2, percent_initialize);\n\t\t\tfout << \"<p>\" << HTMLMakeSpacesNonBreaking(buf) << \" : initialize() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_first, fw2, percent_first);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : first() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_early, fw2, percent_early);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : early() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_matechoice, fw2, percent_matechoice);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : mateChoice() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_recombination, fw2, percent_recombination);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : recombination() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_mutation, fw2, percent_mutation);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : mutation() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_modifychild, fw2, percent_modifychild);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : modifyChild() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_late, fw2, percent_late);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : late() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_mutationEffect, fw2, percent_fitness);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : mutationEffect() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_fitnessEffect, fw2, percent_fitnessglobal);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : fitnessEffect() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_interaction, fw2, percent_interaction);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : interaction() callbacks\" << \"</p>\\n\\n\";\n\t\t\t\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_initialize, fw2, percent_initialize);\n\t\t\tfout << \"<p>\" << HTMLMakeSpacesNonBreaking(buf) << \" : initialize() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_first, fw2, percent_first);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : first() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_reproduction, fw2, percent_reproduction);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : reproduction() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_recombination, fw2, percent_recombination);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : recombination() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_mutation, fw2, percent_mutation);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : mutation() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_modifychild, fw2, percent_modifychild);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : modifyChild() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_early, fw2, percent_early);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : early() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_mutationEffect, fw2, percent_fitness);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : mutationEffect() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_fitnessEffect, fw2, percent_fitnessglobal);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : fitnessEffect() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_survival, fw2, percent_survival);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : survival() callbacks\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_late, fw2, percent_late);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : late() events\" << \"<BR>\\n\";\n\t\t\t\n\t\t\tsnprintf(buf, 256, \"<tt>%*.2f s (%*.2f%%)</tt>\", fw, elapsedTime_interaction, fw2, percent_interaction);\n\t\t\tfout << HTMLMakeSpacesNonBreaking(buf) << \" : interaction() callbacks\" << \"</p>\\n\\n\";\n\t\t}\n\t}\n\t\n\t\n\t//\n\t//\tScript block profiles\n\t//\n\t\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\t{\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\t\n\t\t\t// Convert the profile counts in all script blocks into self counts (excluding the counts of nodes below them)\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t\tif (script_block->type_ != SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\t\t// exclude function blocks; not user-visible\n\t\t\t\t\tscript_block->root_node_->ConvertProfileTotalsToSelfCounts();\n\t\t}\n\t\t\n\t\t{\n\t\t\tfout << \"<h3>Script block profiles (as a fraction of corrected wall clock time)\" << \"</h3>\\n\";\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tsnprintf(buf, 256, \"<p style='margin-bottom: 5px;'><tt>%0.2f s (%0.2f%%):</tt></p>\", total_block_time, percent_block_time);\n\t\t\t\t\tfout << buf << \"\\n\" << \"<p style='margin-top: 5px;'><tt>\";\n\t\t\t\t\tfout << ColorScriptWithProfileCounts(profile_root->token_->token_string_, profile_root, elapsedWallClockTimeInSLiM, profile_root->token_->token_start_) << \"</tt></p>\\n\\n\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t\tfout << \"<p><i>(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\" << \"</i></p>\\n\\n\";\n\t\t}\n\t\t\n\t\t{\n\t\t\tfout << \"<h3>Script block profiles (as a fraction of within-block wall clock time)\" << \"</h3>\\n\";\n\t\t\t\n\t\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community->AllScriptBlocks();\n\t\t\tbool hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *script_block : script_blocks)\n\t\t\t{\n\t\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosUserDefinedFunction)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tconst EidosASTNode *profile_root = script_block->root_node_;\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tsnprintf(buf, 256, \"<p style='margin-bottom: 5px;'><tt>%0.2f s (%0.2f%%):</tt></p>\", total_block_time, percent_block_time);\n\t\t\t\t\tfout << buf << \"\\n\" << \"<p style='margin-top: 5px;'><tt>\";\n\t\t\t\t\tfout << ColorScriptWithProfileCounts(profile_root->token_->token_string_, profile_root, total_block_time, profile_root->token_->token_start_) << \"</tt></p>\\n\\n\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t\tfout << \"<p><i>(blocks using < 0.01 s and < 0.01% of total wall clock time are not shown)\" << \"</i></p>\\n\\n\";\n\t\t}\n\t}\n\t\n\t\n\t//\n\t//\tUser-defined functions (if any)\n\t//\n\t\n\tif (elapsedWallClockTimeInSLiM > 0.0)\n\t{\n\t\tEidosFunctionMap &function_map = community->FunctionMap();\n\t\tstd::vector<const EidosFunctionSignature *> userDefinedFunctions;\n\t\t\n\t\tfor (auto functionPairIter = function_map.begin(); functionPairIter != function_map.end(); ++functionPairIter)\n\t\t{\n\t\t\tconst EidosFunctionSignature *signature = functionPairIter->second.get();\n\t\t\t\n\t\t\tif (signature->body_script_ && signature->user_defined_)\n\t\t\t{\n\t\t\t\tsignature->body_script_->AST()->ConvertProfileTotalsToSelfCounts();\n\t\t\t\tuserDefinedFunctions.emplace_back(signature);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\tfout << \"<h3>User-defined functions (as a fraction of corrected wall clock time)\" << \"</h3>\\n\";\n\t\t\t\n\t\t\tbool hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\t\n\t\t\t\t\tsnprintf(buf, 256, \"<p style='margin-bottom: 5px;'><tt>%0.2f s (%0.2f%%):</tt></p>\", total_block_time, percent_block_time);\n\t\t\t\t\tfout << buf << \"\\n\" << \"<p style='margin-top: 5px;'><tt>\" << HTMLEncodeString(signature_string) << \"<BR>\";\n\t\t\t\t\t\n\t\t\t\t\tfout << ColorScriptWithProfileCounts(profile_root->token_->token_string_, profile_root, elapsedWallClockTimeInSLiM, profile_root->token_->token_start_) << \"</tt></p>\\n\\n\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t\tfout << \"<p><i>(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\" << \"</i></p>\\n\\n\";\n\t\t}\n\t\t\n\t\tif (userDefinedFunctions.size())\n\t\t{\n\t\t\tfout << \"<h3>User-defined functions (as a fraction of within-block wall clock time)\" << \"</h3>\\n\";\n\t\t\t\n\t\t\tbool hiddenInconsequentialBlocks = false;\n\t\t\t\n\t\t\tfor (const EidosFunctionSignature *signature : userDefinedFunctions)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *profile_root = signature->body_script_->AST();\n\t\t\t\tdouble total_block_time = Eidos_ElapsedProfileTime(profile_root->TotalOfSelfCounts());\t// relies on ConvertProfileTotalsToSelfCounts() being called above!\n\t\t\t\tdouble percent_block_time = (total_block_time / elapsedWallClockTimeInSLiM) * 100.0;\n\t\t\t\t\n\t\t\t\tif ((total_block_time >= 0.01) || (percent_block_time >= 0.01))\n\t\t\t\t{\n\t\t\t\t\tconst std::string &&signature_string = signature->SignatureString();\n\t\t\t\t\t\n\t\t\t\t\tsnprintf(buf, 256, \"<p style='margin-bottom: 5px;'><tt>%0.2f s (%0.2f%%):</tt></p>\", total_block_time, percent_block_time);\n\t\t\t\t\tfout << buf << \"\\n\" << \"<p style='margin-top: 5px;'><tt>\" << HTMLEncodeString(signature_string) << \"<BR>\";\n\t\t\t\t\t\n\t\t\t\t\tfout << ColorScriptWithProfileCounts(profile_root->token_->token_string_, profile_root, total_block_time, profile_root->token_->token_start_) << \"</tt></p>\\n\\n\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thiddenInconsequentialBlocks = true;\n\t\t\t}\n\t\t\t\n\t\t\tif (hiddenInconsequentialBlocks)\n\t\t\t\tfout << \"<p><i>(functions using < 0.01 s and < 0.01% of total wall clock time are not shown)\" << \"</i></p>\\n\\n\";\n\t\t}\n\t}\n\t\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t//\n\t//\tMutationRun metrics, presented per Species\n\t//\n\tconst std::vector<Species *> &all_species = community->AllSpecies();\n\t\n\tfor (Species *focal_species : all_species)\n\t{\n\t\tfout << \"<h3>MutationRun usage\";\n\t\tif (all_species.size() > 1)\n\t\t\tfout << \" (\" << HTMLEncodeString(focal_species->avatar_) << \" \" << HTMLEncodeString(focal_species->name_) << \")\";\n\t\tfout << \"</h3>\\n\";\n\t\t\n\t\tif (!focal_species->HasGenetics())\n\t\t{\n\t\t\tfout << \"<p><i>(omitted for no-genetics species)\" << \"</i></p>\\n\";\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t{\n\t\t\tint64_t regime_tallies[3];\n\t\t\tint64_t regime_tallies_total = (int)focal_species->profile_nonneutral_regime_history_.size();\n\t\t\t\n\t\t\tfor (int regime = 0; regime < 3; ++regime)\n\t\t\t\tregime_tallies[regime] = 0;\n\t\t\t\n\t\t\tfor (int32_t regime : focal_species->profile_nonneutral_regime_history_)\n\t\t\t\tif ((regime >= 1) && (regime <= 3))\n\t\t\t\t\tregime_tallies[regime - 1]++;\n\t\t\t\telse\n\t\t\t\t\tregime_tallies_total--;\n\t\t\t\n\t\t\tfout << \"<p>\";\n\t\t\tbool first_line = true;\n\t\t\t\n\t\t\tfor (int regime = 0; regime < 3; ++regime)\n\t\t\t{\n\t\t\t\tif (!first_line)\n\t\t\t\t\tfout << \"<BR>\\n\";\n\t\t\t\tsnprintf(buf, 256, \"%6.2f%%\", (regime_tallies[regime] / (double)regime_tallies_total) * 100.0);\n\t\t\t\tfout << \"<tt>\" << HTMLMakeSpacesNonBreaking(buf) << \"</tt> of ticks : regime \" << (regime + 1) << \" (\" << (regime == 0 ? \"no mutationEffect() callbacks\" : (regime == 1 ? \"constant neutral mutationEffect() callbacks only\" : \"unpredictable mutationEffect() callbacks present\")) << \")\";\n\t\t\t\tfirst_line = false;\n\t\t\t}\n\t\t\t\n\t\t\tfout << \"</p>\\n\";\n\t\t}\n\t\t\n\t\tfout << \"<p><tt>\" << focal_species->profile_max_mutation_index_ << \"</tt> maximum simultaneous mutations</p>\\n\";\n\t\t\n\t\tconst std::vector<Chromosome *> &chromosomes = focal_species->Chromosomes();\n\t\t\n\t\tfor (Chromosome *focal_chromosome : chromosomes)\n\t\t{\n\t\t\tfout << \"<p><i>Chromosome \\\"\" << focal_chromosome->Symbol() << \"\\\":</i></p>\\n\";\n\t\t\t\n\t\t\t{\n\t\t\t\tint64_t power_tallies[20];\t// we only go up to 1024 mutruns right now, but this gives us some headroom\n\t\t\t\tint64_t power_tallies_total = (int)focal_chromosome->profile_mutcount_history_.size();\n\t\t\t\t\n\t\t\t\tfor (int power = 0; power < 20; ++power)\n\t\t\t\t\tpower_tallies[power] = 0;\n\t\t\t\t\n\t\t\t\tfor (int32_t count : focal_chromosome->profile_mutcount_history_)\n\t\t\t\t{\n\t\t\t\t\tint power = (int)round(log2(count));\n\t\t\t\t\t\n\t\t\t\t\tpower_tallies[power]++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfout << \"<p>\";\n\t\t\t\tbool first_line = true;\n\t\t\t\t\n\t\t\t\tfor (int power = 0; power < 20; ++power)\n\t\t\t\t{\n\t\t\t\t\tif (power_tallies[power] > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!first_line)\n\t\t\t\t\t\t\tfout << \"<BR>\\n\";\n\t\t\t\t\t\tsnprintf(buf, 256, \"%6.2f%%\", (power_tallies[power] / (double)power_tallies_total) * 100.0);\n\t\t\t\t\t\tfout << \"<tt>\" << HTMLMakeSpacesNonBreaking(buf) << \"</tt> of ticks : \" << ((int)(round(pow(2.0, power)))) << \" mutation runs per haplosome\";\n\t\t\t\t\t\tfirst_line = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfout << \"</p>\\n\";\n\t\t\t}\n\t\t\t\n\t\t\tfout << \"<p><tt>\" << focal_chromosome->profile_mutation_total_usage_ << \"</tt> mutations referenced, summed across all ticks<BR>\\n\";\n\t\t\tfout << \"<tt>\" << focal_chromosome->profile_nonneutral_mutation_total_ << \"</tt> mutations considered potentially nonneutral<BR>\\n\";\n\t\t\tsnprintf(buf, 256, \"%0.2f%%\", ((focal_chromosome->profile_mutation_total_usage_ - focal_chromosome->profile_nonneutral_mutation_total_) / (double)focal_chromosome->profile_mutation_total_usage_) * 100.0);\n\t\t\tfout << \"<tt>\" << buf << \"</tt> of mutations excluded from fitness calculations</p>\\n\";\n\t\t\t\n\t\t\tfout << \"<p><tt>\" << focal_chromosome->profile_mutrun_total_usage_ << \"</tt> mutation runs referenced, summed across all ticks<BR>\\n\";\n\t\t\tfout << \"<tt>\" << focal_chromosome->profile_unique_mutrun_total_ << \"</tt> unique mutation runs maintained among those<BR>\\n\";\n\t\t\tsnprintf(buf, 256, \"%6.2f%%\", (focal_chromosome->profile_mutrun_nonneutral_recache_total_ / (double)focal_chromosome->profile_unique_mutrun_total_) * 100.0);\n\t\t\tfout << \"<tt>\" << HTMLMakeSpacesNonBreaking(buf) << \"</tt> of mutation run nonneutral caches rebuilt per tick<BR>\\n\";\n\t\t\tsnprintf(buf, 256, \"%6.2f%%\", ((focal_chromosome->profile_mutrun_total_usage_ - focal_chromosome->profile_unique_mutrun_total_) / (double)focal_chromosome->profile_mutrun_total_usage_) * 100.0);\n\t\t\tfout << \"<tt>\" << HTMLMakeSpacesNonBreaking(buf) << \"</tt> of mutation runs shared among haplosomes</p>\\n\\n\";\n\t\t}\n\t}\n#endif\n\t\n\t//\n\t//\tMemory usage metrics\n\t//\n\t\n\t{\n\t\tfout << \"<h3>SLiM memory usage (average / final tick) \" << \"</h3>\\n\";\n\t\t\n\t\tSLiMMemoryUsage_Community &mem_tot_C = community->profile_total_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_tot_S = community->profile_total_memory_usage_AllSpecies;\n\t\tSLiMMemoryUsage_Community &mem_last_C = community->profile_last_memory_usage_Community;\n\t\tSLiMMemoryUsage_Species &mem_last_S = community->profile_last_memory_usage_AllSpecies;\n\t\tint64_t div = community->total_memory_tallies_;\n\t\tdouble ddiv = community->total_memory_tallies_;\n\t\tdouble average_total = (mem_tot_C.totalMemoryUsage + mem_tot_S.totalMemoryUsage) / ddiv;\n\t\tdouble final_total = mem_last_C.totalMemoryUsage + mem_last_S.totalMemoryUsage;\n\t\t\n\t\t// Chromosome\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.chromosomeObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.chromosomeObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.chromosomeObjects, final_total) << \"</tt> : Chromosome objects (\" << buf << \" / \" << mem_last_S.chromosomeObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.chromosomeMutationRateMaps / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.chromosomeMutationRateMaps, final_total) << \"</tt> : mutation rate maps<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.chromosomeRecombinationRateMaps / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.chromosomeRecombinationRateMaps, final_total) << \"</tt> : recombination rate maps<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.chromosomeAncestralSequence / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.chromosomeAncestralSequence, final_total) << \"</tt> : ancestral nucleotides</p>\\n\\n\";\n\t\t\n\t\t// Community\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_C.communityObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.communityObjects, final_total) << \"</tt> : Community object</p>\\n\\n\";\n\t\t\n\t\t// Haplosome\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.haplosomeObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.haplosomeObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.haplosomeObjects, final_total) << \"</tt> : Haplosome objects (\" << buf << \" / \" << mem_last_S.haplosomeObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.haplosomeExternalBuffers / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.haplosomeExternalBuffers, final_total) << \"</tt> : external MutationRun* buffers<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.haplosomeUnusedPoolSpace / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.haplosomeUnusedPoolSpace, final_total) << \"</tt> : unused pool space<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.haplosomeUnusedPoolBuffers / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.haplosomeUnusedPoolBuffers, final_total) << \"</tt> : unused pool buffers</p>\\n\\n\";\n\t\t\n\t\t// GenomicElement\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.genomicElementObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.genomicElementObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.genomicElementObjects, final_total) << \"</tt> : GenomicElement objects (\" << buf << \" / \" << mem_last_S.genomicElementObjects_count << \")</p>\\n\\n\";\n\t\t\n\t\t// GenomicElementType\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.genomicElementTypeObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.genomicElementTypeObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.genomicElementTypeObjects, final_total) << \"</tt> : GenomicElementType objects (\" << buf << \" / \" << mem_last_S.genomicElementTypeObjects_count << \")</p>\\n\\n\";\n\t\t\n\t\t// Individual\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.individualObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.individualObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.individualObjects, final_total) << \"</tt> : Individual objects (\" << buf << \" / \" << mem_last_S.individualObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.individualHaplosomeVectors / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.individualHaplosomeVectors, final_total) << \"</tt> : external Haplosome* buffers</p>\\n\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.individualJunkyardAndHaplosomes / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.individualJunkyardAndHaplosomes, final_total) << \"</tt> : individuals awaiting reuse</p>\\n\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.individualUnusedPoolSpace / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.individualUnusedPoolSpace, final_total) << \"</tt> : unused pool space</p>\\n\\n\";\n\t\t\n\t\t// InteractionType\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_C.interactionTypeObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_C.interactionTypeObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.interactionTypeObjects, final_total) << \"</tt> : InteractionType objects (\" << buf << \" / \" << mem_last_C.interactionTypeObjects_count << \")\";\n\t\t\n\t\tif (mem_tot_C.interactionTypeObjects_count || mem_last_C.interactionTypeObjects_count)\n\t\t{\n\t\t\tfout << \"<BR>\\n\";\t// finish previous line with <BR>\n\t\t\t\n\t\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.interactionTypeKDTrees / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.interactionTypeKDTrees, final_total) << \"</tt> : k-d trees<BR>\\n\";\n\t\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.interactionTypePositionCaches / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.interactionTypePositionCaches, final_total) << \"</tt> : position caches<BR>\\n\";\n\t\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.interactionTypeSparseVectorPool / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.interactionTypeSparseVectorPool, final_total) << \"</tt> : sparse arrays\";\n\t\t}\n\t\t\n\t\tfout << \"</p>\\n\\n\";\n\t\t\n\t\t// Mutation\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.mutationObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.mutationObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationObjects, final_total) << \"</tt> : Mutation objects (\" << buf << \" / \" << mem_last_S.mutationObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.mutationRefcountBuffer / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.mutationRefcountBuffer, final_total) << \"</tt> : refcount buffer<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.mutationUnusedPoolSpace / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.mutationUnusedPoolSpace, final_total) << \"</tt> : unused pool space</p>\\n\\n\";\n\t\t\n\t\t// MutationRun\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.mutationRunObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.mutationRunObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationRunObjects, final_total) << \"</tt> : MutationRun objects (\" << buf << \" / \" << mem_last_S.mutationRunObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.mutationRunExternalBuffers / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationRunExternalBuffers, final_total) << \"</tt> : external MutationIndex buffers<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.mutationRunNonneutralCaches / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationRunNonneutralCaches, final_total) << \"</tt> : nonneutral mutation caches<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.mutationRunUnusedPoolSpace / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationRunUnusedPoolSpace, final_total) << \"</tt> : unused pool space<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.mutationRunUnusedPoolBuffers / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationRunUnusedPoolBuffers, final_total) << \"</tt> : unused pool buffers</p>\\n\\n\";\n\t\t\n\t\t// MutationType\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.mutationTypeObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.mutationTypeObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.mutationTypeObjects, final_total) << \"</tt> : MutationType objects (\" << buf << \" / \" << mem_last_S.mutationTypeObjects_count << \")</p>\\n\\n\";\n\t\t\n\t\t// Species\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.speciesObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.speciesObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.speciesObjects, final_total) << \"</tt> : Species objects (\" << buf << \" / \" << mem_last_S.speciesObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.speciesTreeSeqTables / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.speciesTreeSeqTables, final_total) << \"</tt> : tree-sequence tables</p>\\n\\n\";\n\t\t\n\t\t// Subpopulation\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.subpopulationObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.subpopulationObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.subpopulationObjects, final_total) << \"</tt> : Subpopulation objects (\" << buf << \" / \" << mem_last_S.subpopulationObjects_count << \")<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.subpopulationFitnessCaches / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.subpopulationFitnessCaches, final_total) << \"</tt> : fitness caches<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.subpopulationParentTables / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.subpopulationParentTables, final_total) << \"</tt> : parent tables<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.subpopulationSpatialMaps / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.subpopulationSpatialMaps, final_total) << \"</tt> : spatial maps\";\n\t\t\n\t\tif (mem_tot_S.subpopulationSpatialMapsDisplay || mem_last_S.subpopulationSpatialMapsDisplay)\n\t\t{\n\t\t\tfout << \"<BR>\\n\";\t// finish previous line with <BR>\n\t\t\t\n\t\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_S.subpopulationSpatialMapsDisplay / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.subpopulationSpatialMapsDisplay, final_total) << \"</tt> : spatial map display (SLiMgui only)\";\n\t\t}\n\t\t\n\t\tfout << \"</p>\\n\\n\";\n\t\t\n\t\t// Substitution\n\t\tsnprintf(buf, 256, \"%0.2f\", mem_tot_S.substitutionObjects_count / ddiv);\n\t\tfout << \"<p><tt>\" << ColoredSpanForByteCount(mem_tot_S.substitutionObjects / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_S.substitutionObjects, final_total) << \"</tt> : Substitution objects (\" << buf << \" / \" << mem_last_S.substitutionObjects_count << \")</p>\\n\\n\";\n\t\t\n\t\t// Eidos\n\t\tfout << \"<p>Eidos:<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.eidosASTNodePool / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.eidosASTNodePool, final_total) << \"</tt> : EidosASTNode pool<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.eidosSymbolTablePool / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.eidosSymbolTablePool, final_total) << \"</tt> : EidosSymbolTable pool<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.eidosValuePool / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.eidosValuePool, final_total) << \"</tt> : EidosValue pool<BR>\\n\";\n\t\tfout << \"<tt>&nbsp;&nbsp;&nbsp;\" << ColoredSpanForByteCount(mem_tot_C.fileBuffers / div, average_total) << \"</tt> / <tt>\" << ColoredSpanForByteCount(mem_last_C.fileBuffers, final_total) << \"</tt> : File buffers</p>\\n\";\n\t}\n\t\n\t\n\t//\n\t//\tHTML footer\n\t//\n\t\n\tfout << \"</body>\" << \"\\n\";\n\tfout << \"</html>\" << std::endl;\n\t\n\tfout.close();\n\tif (!fout)\n\t\tEIDOS_TERMINATION << std::endl << \"ERROR (WriteProfileResults): Could not write to profile output path \" << profile_output_path << EidosTerminate();\n}\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_globals.h",
    "content": "//\n//  slim_globals.h\n//  SLiM\n//\n//  Created by Ben Haller on 1/4/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This file contains various enumerations and small helper classes that are used across SLiM.\n \n */\n\n#ifndef __SLiM__slim_globals__\n#define __SLiM__slim_globals__\n\n\n#include <stdio.h>\n#include <cstdint>\n\n#include \"eidos_globals.h\"\n#include \"eidos_value.h\"\n\nclass MutationType;\nclass Community;\nclass Species;\nclass EidosInterpreter;\nclass Population;\nclass GenomicElementType;\nclass Subpopulation;\nclass SLiMEidosBlock;\n\n\n// SLiM version: see also Info.plist and QtSLiM.pro\n#define SLIM_VERSION_STRING\t(\"5.2\")\n#define SLIM_VERSION_FLOAT\t(5.2)\n\n\n// This should be called once at startup to give SLiM an opportunity to initialize static state\nvoid SLiM_WarmUp(void);\n\n\n// *******************************************************************************************************************\n//\n//\tGlobal optimization flags\n//\n#pragma mark -\n#pragma mark Global optimization flags\n#pragma mark -\n\n// If defined, MutationType will keep its own registry of all mutations of that type, under certain circumstances.\n// See mutation_type.h for more information on this optimization.\n#define SLIM_KEEP_MUTTYPE_REGISTRIES\n\n\n// *******************************************************************************************************************\n//\n//\tOutput handling for SLiM\n//\n#pragma mark -\n#pragma mark Output handling\n#pragma mark -\n\n// Output from SLiM can work in one of two ways.  If gEidosTerminateThrows == 0, ordinary output goes to cout,\n// and error output goes to cerr.  The other mode has gEidosTerminateThrows == 1.  In that mode, we use global\n// ostringstreams to capture all output to both the output and error streams.  These streams should get emptied out after\n// every SLiM operation, so a single stream can be safely used by multiple SLiM instances (as long as we do not\n// multithread).  Note that Eidos output goes into its own output streams, which SLiM empties into the SLiM output streams.\n// Note also that termination output is handled separately, using EIDOS_TERMINATION.\nextern std::ostringstream gSLiMOut;\nextern std::ostringstream gSLiMError;\n#define SLIM_OUTSTREAM\t\t(gEidosTerminateThrows ? gSLiMOut : std::cout)\n#define SLIM_ERRSTREAM\t\t(gEidosTerminateThrows ? gSLiMError : std::cerr)\n\n#ifdef SLIMGUI\n// When running under SLiMgui, we can have additional output streams that do not exist when running at the command line\nextern std::ostringstream gSLiMScheduling;\t\t// information about scheduling in each tick\n#endif\n\n\n// *******************************************************************************************************************\n//\n//\tTypes and maximum values used by SLiM\n//\n#pragma mark -\n#pragma mark Types and max values\n#pragma mark -\n\n// This is the standard setup for SLiM: 32 bit ints for most values.  This is recommended.  This gives a maximum of\n// 1 billion for quantities such as object IDs, ticks, population sizes, and chromosome positions.  This is\n// comfortably under INT_MAX, which is a bit over 2 billion.  The goal is to try to avoid overflow bugs by keeping\n// a large amount of headroom, so that we are not at risk of simple calculations with these quantities overflowing.\n// Raising these limits to int64_t is reasonable if you need to run a larger simulation.  Lowering them to int16_t\n// is not recommended, and will likely buy you very little, because most of the memory usage in typical simulations\n// is in the arrays of mutation indices kept by Haplosome objects.\n// BCH 11 May 2018: changing slim_position_t to int64_t for SLiM 3; L <= 1e9 was a bit limiting.  We now enforce a\n// maximum position of 1e15.  INT64_MAX is almost 1e19, so this may seem arbitrary.  The reason is that we want to\n// interact well with code, such as the tree-sequence code, that keeps positions as doubles.  The IEEE standard for\n// double mandates 52 bits for the fractional part, which means that the ability to uniquely identify every integer\n// position breaks down a little bit shy of 1e16.  Thus we limit to 1e15, as a round limit with lots of headroom.\n\ntypedef int32_t\tslim_tick_t;\t\t\t// tick numbers, tick durations\ntypedef int32_t\tslim_age_t;\t\t\t\t// individual ages which may be from zero on up\ntypedef int64_t\tslim_position_t;\t\t// chromosome positions, lengths in base pairs\ntypedef uint8_t slim_chromosome_index_t;\t// the index of a chromosome within a species, in the order they were defined; in [0, 255]\ntypedef int64_t slim_mutrun_index_t;\t// indices of mutation runs within haplosomes; SLIM_INF_BASE_POSITION leads to very large values, thus 64-bit\ntypedef int32_t\tslim_objectid_t;\t\t// identifiers values for objects, like the \"5\" in p5, g5, m5, s5\ntypedef int32_t\tslim_popsize_t;\t\t\t// subpopulation sizes and indices, include haplosome indices\ntypedef int64_t slim_usertag_t;\t\t\t// user-provided \"tag\" values; also used for the \"active\" property, which is like tag\ntypedef int32_t slim_refcount_t;\t\t// mutation refcounts, counts of the number of occurrences of a mutation\ntypedef int64_t slim_mutationid_t;\t\t// identifiers for mutations, which require 64 bits since there can be so many\ntypedef int64_t slim_pedigreeid_t;\t\t// identifiers for pedigreed individuals; over many ticks in a large model maybe 64 bits?\ntypedef int64_t slim_haplosomeid_t;\t\t// identifiers for pedigreed haplosomes; not user-visible, used by the tree-recording code, pedigree_id*2 + [0/1]\ntypedef int32_t slim_polymorphismid_t;\t// identifiers for polymorphisms, which need only 32 bits since they are only segregating mutations\ntypedef float slim_selcoeff_t;\t\t\t// storage of selection coefficients in memory-tight classes; also dominance coefficients\n\n#define SLIM_MAX_TICK\t\t\t(1000000000L)\t// ticks range from 0 (init time) to this; SLIM_MAX_TICK + 1 is an \"infinite\" marker value\n#define SLIM_MAX_BASE_POSITION\t(1000000000000000L)\t// base positions in the chromosome can range from 0 to 1e15; see above\n#define SLIM_INF_BASE_POSITION\t(1100000000000000L)\t// used to represent a base position infinitely beyond the end of the chromosome\n#define SLIM_MAX_PEDIGREE_ID\t(1000000000000000000L)\t// pedigree IDs for individuals can range from 0 to 1e18 (~2^60)\n#define SLIM_MAX_ID_VALUE\t\t(1000000000L)\t// IDs for subpops, genomic elements, etc. can range from 0 to this\n#define SLIM_MAX_SUBPOP_SIZE\t(1000000000L)\t// subpopulations can range in size from 0 to this; haplosome indexes, up to Nx this\n#define SLIM_TAG_UNSET_VALUE\t(INT64_MIN)\t\t// for tags of type slim_usertag_t, the flag value for \"unset\"\n#define SLIM_TAGF_UNSET_VALUE\t(-DBL_MAX)\t\t// for tags of type double (i.e. tagF), the flag value for \"unset\"\n\n// Functions for casting from Eidos ints (int64_t) to SLiM int types safely; not needed for slim_refcount_t at present\nvoid SLiM_RaiseTickRangeError(int64_t p_long_value);\nvoid SLiM_RaiseAgeRangeError(int64_t p_long_value);\nvoid SLiM_RaisePositionRangeError(int64_t p_long_value);\nvoid SLiM_RaisePedigreeIDRangeError(int64_t p_long_value);\nvoid SLiM_RaiseObjectidRangeError(int64_t p_long_value);\nvoid SLiM_RaisePopsizeRangeError(int64_t p_long_value);\nvoid SLiM_RaiseUsertagRangeError(int64_t p_long_value);\nvoid SLiM_RaisePolymorphismidRangeError(int64_t p_long_value);\n\ninline __attribute__((always_inline)) slim_tick_t SLiMCastToTickTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 1) || (p_long_value > SLIM_MAX_TICK))\n\t\tSLiM_RaiseTickRangeError(p_long_value);\n\t\n\treturn static_cast<slim_tick_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_age_t SLiMCastToAgeTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > SLIM_MAX_TICK))\n\t\tSLiM_RaiseAgeRangeError(p_long_value);\n\t\n\treturn static_cast<slim_age_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_position_t SLiMCastToPositionTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > SLIM_MAX_BASE_POSITION))\n\t\tSLiM_RaisePositionRangeError(p_long_value);\n\t\n\treturn static_cast<slim_position_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_pedigreeid_t SLiMCastToPedigreeIDOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > SLIM_MAX_PEDIGREE_ID))\n\t\tSLiM_RaisePedigreeIDRangeError(p_long_value);\n\t\n\treturn static_cast<slim_pedigreeid_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_objectid_t SLiMCastToObjectidTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > SLIM_MAX_ID_VALUE))\n\t\tSLiM_RaiseObjectidRangeError(p_long_value);\n\t\n\treturn static_cast<slim_objectid_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_popsize_t SLiMCastToPopsizeTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > SLIM_MAX_SUBPOP_SIZE))\n\t\tSLiM_RaisePopsizeRangeError(p_long_value);\n\t\n\treturn static_cast<slim_popsize_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_usertag_t SLiMCastToUsertagTypeOrRaise(int64_t p_long_value)\n{\n\t// no range check at present since slim_usertag_t is in fact int64_t; it is in range by definition\n\t// SLiM_RaiseUsertagRangeError(long_value);\n\t\n\treturn static_cast<slim_usertag_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_polymorphismid_t SLiMCastToPolymorphismidTypeOrRaise(int64_t p_long_value)\n{\n\tif ((p_long_value < 0) || (p_long_value > INT32_MAX))\n\t\tSLiM_RaisePolymorphismidRangeError(p_long_value);\n\t\n\treturn static_cast<slim_polymorphismid_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_tick_t SLiMClampToTickType(int64_t p_long_value)\n{\n\tif (p_long_value < 1)\n\t\treturn 1;\n\tif (p_long_value > SLIM_MAX_TICK)\n\t\treturn SLIM_MAX_TICK;\n\treturn static_cast<slim_tick_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_position_t SLiMClampToPositionType(int64_t p_long_value)\n{\n\tif (p_long_value < 0)\n\t\treturn 0;\n\tif (p_long_value > SLIM_MAX_BASE_POSITION)\n\t\treturn SLIM_MAX_BASE_POSITION;\n\treturn static_cast<slim_position_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_objectid_t SLiMClampToObjectidType(int64_t p_long_value)\n{\n\tif (p_long_value < 0)\n\t\treturn 0;\n\tif (p_long_value > SLIM_MAX_ID_VALUE)\n\t\treturn SLIM_MAX_ID_VALUE;\n\treturn static_cast<slim_objectid_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_popsize_t SLiMClampToPopsizeType(int64_t p_long_value)\n{\n\tif (p_long_value < 0)\n\t\treturn 0;\n\tif (p_long_value > SLIM_MAX_SUBPOP_SIZE)\n\t\treturn SLIM_MAX_SUBPOP_SIZE;\n\treturn static_cast<slim_popsize_t>(p_long_value);\n}\n\ninline __attribute__((always_inline)) slim_usertag_t SLiMClampToUsertagType(int64_t p_long_value)\n{\n\t// no range check at present since slim_usertag_t is in fact int64_t; it is in range by definition\n\treturn static_cast<slim_usertag_t>(p_long_value);\n}\n\nCommunity &SLiM_GetCommunityFromInterpreter(EidosInterpreter &p_interpreter);\nslim_objectid_t SLiM_ExtractObjectIDFromEidosValue_is(EidosValue *p_value, int p_index, char p_prefix_char);\n\n// These take both a Community and a Species.  If the species is non-nullptr, the lookup is done in that species\n// and the community is not used (and may be nullptr).  If the species is nullptr, the lookup is in the community,\n// and an object in any species will be found.  So: supply a species if you want a species-specific search.\nMutationType *SLiM_ExtractMutationTypeFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name);\nGenomicElementType *SLiM_ExtractGenomicElementTypeFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name);\nSubpopulation *SLiM_ExtractSubpopulationFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name);\nSLiMEidosBlock *SLiM_ExtractSLiMEidosBlockFromEidosValue_io(EidosValue *p_value, int p_index, Community *p_community, Species *p_species, const char *p_method_name);\n\nSpecies *SLiM_ExtractSpeciesFromEidosValue_No(EidosValue *p_value, int p_index, Community *p_community, const char *p_method_name);\t\t// NULL tries for a single-species default\n\n// This template provides a function pointer that will delete a void* pointing to a given type.\n// It thus allows us to hold on to a void* pointing to a Qt object, for example, without building\n// against Qt; SLiMgui will give us the void* and a deleter pointer, which we can cache for it\n// and invalidate the cache, deleting the object, when appropriate without ever knowing its type.\ntemplate<typename T>\nvoid Eidos_Deleter(void *ptr) {\n\tdelete static_cast<T*>(ptr);\n}\n\n\n// *******************************************************************************************************************\n//\n//\tMemory management\n//\n#pragma mark -\n#pragma mark Memory management\n#pragma mark -\n\n/*\n \n Memory management in SLiM is a complex topic which I'll try to summarize here.  Classes that are visible in Eidos\n descend from EidosObject.  Most of these have their ownership and lifetime managed by the simulation; whenever an\n Individual dies, for example, the Individual object ceases to exist at that time, and is disposed of.  A subclass\n of EidosObject, EidosDictionaryRetained, provides optional retain/release style memory management for all objects\n visible in Eidos; Chromosome, Mutation, Substitution, and LogFile utilize this facility, and can therefore all be\n held onto long-term in Eidos with defineConstant() or setValue().  In either case, objects might be allocated out\n of several different pools: some objects are allocated with new, some out of EidosObjectPool.  EidosValue objects\n themselves (which can contain pointers to EidosObjects) are always allocated from a single global EidosObjectPool\n that is shared across the process, gEidosValuePool, and EidosASTNodes are similarly allocated from another global\n pool, gEidosASTNodePool.  Here are details on the memory management scheme for various SLiM classes (note that by\n \"never deleted\", this means not deleted within a run of a simulation; in SLiMgui they can be deleted):\n \n EidosValue : no base class; allocated from a shared pool, held under retain/release with Eidos_intrusive_ptr\n EidosObject : base class for all Eidos classes that are visible as objects in SLiM scripts\n EidosDictionaryUnretained : EidosObject subclass that provides dictionary-style key-value Eidos methods\n EidosDictionaryRetained : EidosDictionaryUnretained subclass that provides retain/release memory management\n \n GenomicElement : EidosObject subclass, allocated with new and never deleted\n SLiMgui : EidosDictionaryUnretained subclass, allocated with new and never deleted\n GenomicElementType : EidosDictionaryUnretained subclass, allocated with new and never deleted\n MutationType : EidosDictionaryUnretained subclass, allocated with new and never deleted\n InteractionType : EidosDictionaryUnretained subclass, allocated with new and never deleted\n Community : EidosDictionaryUnretained subclass, allocated with new and never deleted\n Species : EidosDictionaryUnretained subclass, allocated with new and never deleted\n SLiMEidosBlock : EidosObject subclass, dynamic lifetime with a deferred deletion scheme in Community\n \n MutationRun : no superclass, not visible in Eidos, shared by Haplosome, private pools for very efficient reuse\n Haplosome : EidosObject subclass, allocated out of an EidosObjectPool owned by its subpopulation\n Individual : EidosDictionaryUnretained subclass, allocated out of an EidosObjectPool owned by its subpopulation\n Subpopulation : EidosDictionaryUnretained subclass, allocated with new/delete\n \n Chromosome : EidosDictionaryRetained subclass, allocated with new/delete\n Substitution : EidosDictionaryRetained subclass, allocated with new/delete\n Mutation : EidosDictionaryRetained subclass, allocated out of a special global pool, gSLiM_Mutation_Block\n LogFile : EidosDictionaryRetained subclass, allocated with new/delete\n\n The dynamics of Mutation are unusual and require further discussion.  The global shared gSLiM_Mutation_Block pool\n is used instead of EidosObjectPool because all mutations must be allocated out of a single contiguous memory bloc\n in order to be indexable with MutationIndex (whereas EidosObjectPool dynamically creates new blocs).  This allows\n references to mutations in MutationRun to be done with 32-bit MutationIndexes rather than 64-bit pointers, giving\n better performance.  Mutation, as a subclass of EidosDictionaryRetained, is under retain/release, but the uses of\n Mutation inside SLiM's core do not cause retain/release activity, for efficiency; instead, the population keeps a\n \"registry\" of mutations that are currently segregating, and the registry holds a retain on all of those mutations\n on behalf of the entire SLiM core.  Normally, when a mutation is lost or fixes and gets removed from the registry\n that retain is released and the mutation is given back to the shared pool.  This only changes if a reference to a\n mutation is kept in an EidosValue, which will apply another retain; if that EidosValue is persistent, as a result\n of being kept by defineConstant() or setValue(), then when the registry releases the mutation the EidosValue will\n still have a retain and the mutation will live on, even though it is no longer referenced by the simulation.  The\n Mutation class now keeps an ivar, state_, that keeps track of whether a mutation is still in the registry, or has\n been lost or fixed.\n \n MutationRun is similarly complex.  It is not visible in Eidos, but a single MutationRun can be shared by multiple\n Haplosomes, so it keeps a refcount (updated each tick by tallying usage across haplosomes).  All MutationRuns are\n allocated out of a single pool per species.  When their refcount goes to zero they do not get destructed; instead\n they are returned to a per-species \"freed list\" while still in a constructed state, allowing extremely fast reuse\n since they are a central bottleneck in most SLiM models.\n \n In summary, there are two different retain/release schemes in SLiM, one run by Eidos_intrusive_ptr and one run by\n EidosDictionaryRetained.  Eidos_intrusive_ptr is a template-based solution that can be incorporated in class with\n the declaration of a counter and two friend functions, providing a very general solution.  In contrast, the class\n EidosDictionaryRetained provides a retain/release scheme that's tightly integrated into EidosValue's design, with\n explicit calls to retain/release instead of the automatic \"shared pointer\" design of Eidos_intrusive_ptr.\n \n Other SLiM Eidos objects could conceivably be brought under EidosDictionaryRetained, allowing them to be retained\n long-term like Mutation and Substitution.  However, this is tricky with objects that have a lifetime delimited by\n the simulation itself, like Subpopulation; it would be hard to keep a Subpopulation object alive beyond its usual\n lifetime while remaining useful and functional.  There is also a substantial speed penalty to being under retain/\n release; manipulating large vectors of Mutation objects in Eidos is now ~3x slower than it used to be.  The large\n advantages of being able to keep Mutation objects long-term seemed to justify this; no similar advantages seem to\n exist for the other SLiM classes that would justify this additional overhead.\n \n BCH 3/28/2023: Apropos of the previous paragraph, I looked into having the managed-lifetime objects that live for\n the whole simulation (Community, Species, GenomicElementType, MutationType, InteractionType, SLiMgui) behave like\n they're under retain-release (so they can be put into Dictionaries and defined as global constants and so forth),\n but it proved difficult and fragile.  There are two choices for this.  You could actually put these objects under\n retain-release, and design things so that at the end of the simulation they get a Release() call and that trigger\n causes their deallocation.  The problem with that is that retained references to them - even their self_symbol_ -\n make it so they don't actually get deallocated at the point in time that they should be, and so they leak.  A way\n to break retain cycles would be needed, but that's a very complex thing.  The other possible approach is for them\n to just pretend to be under retain-release, but to get forced to dealloc at the end of the simulation, regardless\n of their retain count.  The problem in this case is that Release() calls will come in for the objects after their\n deallocation; trying to prevent that by chasing down and clearing every retained reference before deallocation is\n a very complex thing too.  What is really needed is a weak-reference scheme where only the simulation's reference\n is strong, and all other references are weak and get cleared when the strong reference is released; but again, it\n is a very complex thing to implement.  In the end I decided it wasn't worth the time, effort, and complexity.\n \n BCH 5/24/2022: Adding a new note regarding memory policy in multispecies SLiM.  The above points still apply, but\n it is worth emphasizing that the shared global pools now apply across species.  Multiple species share a pool for\n Mutation objects, and a pool for MutationRun objects, in other words; they do not share their pools of Individual\n and Haplosome objects, however, as those are kept by the Population.  This is the simplest design; it seems to be\n fine.  It might provide greater memory locality benefits for each species to have its own pool, but that would be\n more than offset by the added complexity of having to walk up to the species to get the active pool.  This design\n means that mutaton indexes and gSLiM_next_mutation_id are shared across species; a given mutation index is unique\n not only within the species, but across species.  Similarly, the \"bulk operation\" facilities of MutationRun share\n globals used by all species, so a bulk operation can only be in progress for one species at a time.  Other shared\n globals include s_freed_sparse_vectors_ (which keeps freed SparseVector objects for reuse by InteractionType) and\n gSLiM_next_pedigree_id (which keeps the next pedigree ID to be used).  This implies that pedigree IDs are uniqued\n across species also, which in turn implies that haplosome IDs used in tree-sequence recording are uniqued as well\n given the invariant relationship between pedigree and haplosome IDs.\n \n */\n\n#define DEBUG_MUTATIONS\t\t\t\t0\t\t// turn on logging of mutation construction and destruction\n\n// Per-species memory usage assessment as done by Species::TabulateSLiMMemoryUsage_Species() is placed into this struct\ntypedef struct\n{\n\tint64_t chromosomeObjects_count;\n\tsize_t chromosomeObjects;\n\tsize_t chromosomeMutationRateMaps;\n\tsize_t chromosomeRecombinationRateMaps;\n\tsize_t chromosomeAncestralSequence;\n\t\n\tint64_t haplosomeObjects_count;\n\tsize_t haplosomeObjects;\n\tsize_t haplosomeExternalBuffers;\n\tsize_t haplosomeUnusedPoolSpace;\t\t\t\t// this pool is kept by Population, per-species\n\tsize_t haplosomeUnusedPoolBuffers;\n\t\n\tint64_t genomicElementObjects_count;\n\tsize_t genomicElementObjects;\n\t\n\tint64_t genomicElementTypeObjects_count;\n\tsize_t genomicElementTypeObjects;\n\t\n\tint64_t individualObjects_count;\n\tsize_t individualObjects;\n\tsize_t individualHaplosomeVectors;\n\tsize_t individualJunkyardAndHaplosomes;\n\tsize_t individualUnusedPoolSpace;\t\t\t// this pool is kept by Population, per-species\n\t\n\tint64_t mutationObjects_count;\n\tsize_t mutationObjects;\n\t\n\tint64_t mutationRunObjects_count;\n\tsize_t mutationRunObjects;\n\tsize_t mutationRunExternalBuffers;\n\tsize_t mutationRunNonneutralCaches;\n\tsize_t mutationRunUnusedPoolSpace;\t\t\t// this pool is kept by Species\n\tsize_t mutationRunUnusedPoolBuffers;\t\t// this pool is kept by Species\n\t\n\tint64_t mutationTypeObjects_count;\n\tsize_t mutationTypeObjects;\n\t\n\tint64_t speciesObjects_count;\n\tsize_t speciesObjects;\n\tsize_t speciesTreeSeqTables;\n\t\n\tint64_t subpopulationObjects_count;\n\tsize_t subpopulationObjects;\n\tsize_t subpopulationFitnessCaches;\n\tsize_t subpopulationParentTables;\n\tsize_t subpopulationSpatialMaps;\n\tsize_t subpopulationSpatialMapsDisplay;\n\t\n\tint64_t substitutionObjects_count;\n\tsize_t substitutionObjects;\n\t\n\tsize_t totalMemoryUsage;\n} SLiMMemoryUsage_Species;\n\n// Community-wide memory usage assessment as done by Community::TabulateSLiMMemoryUsage_Community() is placed into this struct\ntypedef struct\n{\n\tint64_t communityObjects_count;\n\tsize_t communityObjects;\n\t\n\tsize_t mutationRefcountBuffer;\t\t\t// this pool is kept globally by Mutation\n\tsize_t mutationUnusedPoolSpace;\t\t\t// this pool is kept globally by Mutation\n\t\n\tint64_t interactionTypeObjects_count;\t// InteractionType is kept by Community now\n\tsize_t interactionTypeObjects;\n\tsize_t interactionTypeKDTrees;\n\tsize_t interactionTypePositionCaches;\n\tsize_t interactionTypeSparseVectorPool;\t// This pool is kept globally by InteractionType\n\t\n\tsize_t eidosASTNodePool;\t\t\t\t// this pool is kept globally by Eidos\n\tsize_t eidosSymbolTablePool;\t\t\t// this pool is kept globally by EidosSymbolTable\n\tsize_t eidosValuePool;\t\t\t\t\t// this pool is kept globally by Eidos\n\tsize_t fileBuffers;\t\t\t\t\t\t// these buffers are kept globally by Eidos\n\t\n\tsize_t totalMemoryUsage;\n} SLiMMemoryUsage_Community;\n\nvoid SumUpMemoryUsage_Species(SLiMMemoryUsage_Species &p_usage);\nvoid SumUpMemoryUsage_Community(SLiMMemoryUsage_Community &p_usage);\n\nvoid AccumulateMemoryUsageIntoTotal_Species(SLiMMemoryUsage_Species &p_usage, SLiMMemoryUsage_Species &p_total);\nvoid AccumulateMemoryUsageIntoTotal_Community(SLiMMemoryUsage_Community &p_usage, SLiMMemoryUsage_Community &p_total);\n\n\n// *******************************************************************************************************************\n//\n//\tDebugging support\n//\n#pragma mark -\n#pragma mark Debugging support\n#pragma mark -\n\n// Debugging #defines that can be turned on\n#define DEBUG_MUTATION_ZOMBIES\t\t0\t\t// avoid destroying Mutation objects; keep them as zombies\n#define SLIM_DEBUG_MUTATION_RUNS\t0\t\t// turn on to get logging about mutation run uniquing and usage\n#define DEBUG_BLOCK_REG_DEREG\t\t0\t\t// turn on to get logging about script block registration/deregistration\n#define DEBUG_SHUFFLE_BUFFER\t\t1\t\t// debug memory overruns with the shuffle buffer\n#define DEBUG_TICK_RANGES\t\t\t0\t\t// debug tick range parsing and evaluation\n#define DEBUG_LESS_INTENSIVE\t\t0\t\t// decrease the frequency of some very intensive DEBUG checks\n\n\n// In SLiMgui we want to emit only a reasonably limited number of lines of input debugging; for big models, this output\n// can get rather excessive.  Outside of SLiMgui, though, we emit it all, because the user might need it for some reason.\n#ifdef SLIMGUI\n#define ABBREVIATE_DEBUG_INPUT\t1\n#else\n#define ABBREVIATE_DEBUG_INPUT\t0\n#endif\n\n// If 1, checks of current memory usage versus maximum allowed memory usage will be done in certain spots\n// where we are particularly likely to run out of memory, to provide the user with a better error message.\n// Note that even when this is 1, the user can disable some of these checks with -x.\n// Disable for Windows until Eidos_GetMaxRSS() issue fixed:\n#ifdef _WIN32\n#define DO_MEMORY_CHECKS\t0\n#else\n#define DO_MEMORY_CHECKS\t1\n#endif\n\n// If 1, and SLiM_verbosity_level >= 2, additional output will be generated regarding the mutation run count\n// experiments performed by Species.\n#define MUTRUN_EXPERIMENT_OUTPUT\t0\n\n// If 1, debug output will be generated for mutation run count experiment timing information\n#define MUTRUN_EXPERIMENT_TIMING_OUTPUT\t\t0\n\n// If 1, the MutationRun pointers inside Haplosome objects will be cleared to nullptr when the haplosome is\n// freed, or disposed of into a junkyard, or anything like that -- whenever it is no longer in use.  This\n// could be useful for debugging problems with dereferencing stale MutationRun pointers.  Otherwise it is\n// not necessary, and just slows SLiM down.\n#define SLIM_CLEAR_HAPLOSOMES\t0\n\n// Verbosity, from the command-line option -l[ong]; defaults to 1 if -l[ong] is not used\nextern int64_t SLiM_verbosity_level;\n\n\n// *******************************************************************************************************************\n//\n//\tShared SLiM types and enumerations\n//\n#pragma mark -\n#pragma mark Shared SLiM types and enumerations\n#pragma mark -\n\n// This enumeration represents the type of model: presently WF or nonWF\nenum class SLiMModelType\n{\n\tkModelTypeWF = 0,\t\t\t// a Wright-Fisher model: the original model type supported by SLiM\n\tkModelTypeNonWF\t\t\t\t// a non-Wright-Fisher model: a new model type that is more general\n};\n\nenum class SLiMCycleStage\n{\n\tkStagePreCycle = 0,\n\t\n\t// stages for WF models\n\tkWFStage0ExecuteFirstScripts = 1,\n\tkWFStage1ExecuteEarlyScripts,\n\tkWFStage2GenerateOffspring,\n\tkWFStage3SwapGenerations,\n\tkWFStage4RemoveFixedMutations,\n\tkWFStage5ExecuteLateScripts,\n\tkWFStage6CalculateFitness,\n\tkWFStage7AdvanceTickCounter,\n\t\n\t// stages for nonWF models\n\tkNonWFStage0ExecuteFirstScripts = 101,\n\tkNonWFStage1GenerateOffspring,\n\tkNonWFStage2ExecuteEarlyScripts,\n\tkNonWFStage3CalculateFitness,\n\tkNonWFStage4SurvivalSelection,\n\tkNonWFStage5RemoveFixedMutations,\n\tkNonWFStage6ExecuteLateScripts,\n\tkNonWFStage7AdvanceTickCounter,\n\t\n\t// end stage between ticks; things in the Eidos console happen here\n\tkStagePostCycle = 201,\n};\n\nstd::string StringForSLiMCycleStage(SLiMCycleStage p_stage);\n\n// This enumeration represents the type of a chromosome.  Note that the sex of an individual cannot always be inferred\n// from chromosomal state, and the user is allowed to play games with null haplosomes; the chromosomes follow the sex\n// of the individual, the sex of the individual does not follow the chromosomes.  See the initializeChromosome() doc.\nenum class ChromosomeType : uint8_t {\n\tkA_DiploidAutosome = 0,\n\tkH_HaploidAutosome,\n\tkX_XSexChromosome,\n\tkY_YSexChromosome,\n\tkZ_ZSexChromosome,\n\tkW_WSexChromosome,\n\tkHF_HaploidFemaleInherited,\n\tkFL_HaploidFemaleLine,\n\tkHM_HaploidMaleInherited,\n\tkML_HaploidMaleLine,\n\tkHNull_HaploidAutosomeWithNull,\n\tkNullY_YSexChromosomeWithNull\n};\n\nstd::string StringForChromosomeType(ChromosomeType p_chromosome_type);\nChromosomeType ChromosomeTypeForString(std::string type);\t\t\t\t// raises if no match\nstd::ostream& operator<<(std::ostream& p_out, ChromosomeType p_chromosome_type);\n\n\n// This enumeration represents the sex of an individual: hermaphrodite, female, or male.  It also includes an \"unspecified\"\n// value that is useful in situations where the code wants to say that it doesn't care what sex is present.\nenum class IndividualSex : int8_t\n{\n\tkUnspecified = -2,\n\tkHermaphrodite = -1,\n\tkFemale = 0,\n\tkMale = 1\n};\n\nstd::string StringForIndividualSex(IndividualSex p_sex);\nstd::ostream& operator<<(std::ostream& p_out, IndividualSex p_sex);\n\n\n// This enumeration represents the policy followed for multiple mutations at the same position.\n// Such \"stacked\" mutations can be allowed (the default), or the first or last mutation at the position can be kept.\nenum class MutationStackPolicy : char {\n\tkStack = 0,\n\tkKeepFirst,\n\tkKeepLast,\n};\n\nextern EidosValue_String_SP gStaticEidosValue_StringA;\nextern EidosValue_String_SP gStaticEidosValue_StringC;\nextern EidosValue_String_SP gStaticEidosValue_StringG;\nextern EidosValue_String_SP gStaticEidosValue_StringT;\n\nextern const char gSLiM_Nucleotides[4];\t\t// A, C, G, T\n\n\n// This enumeration represents possible boundary conditions supported by SLiM.  Note that \"absorbing\"\n// is not included here, because there is no SLiM API that supports absorbing boundaries.\nenum class BoundaryCondition : char {\n\tkNone = 0,\n\tkStopping,\n\tkReflecting,\n\tkReprising,\n\tkAbsorbing,\n\tkPeriodic\n};\n\n\n// *******************************************************************************************************************\n//\n//\tTSKIT/tree sequence tables related\n//\n#pragma mark -\n#pragma mark Tree sequences\n#pragma mark -\n\t\n#define SLIM_TSK_INDIVIDUAL_ALIVE       ((tsk_flags_t)(1 << 16))\n#define SLIM_TSK_INDIVIDUAL_REMEMBERED  ((tsk_flags_t)(1 << 17))\n#define SLIM_TSK_INDIVIDUAL_RETAINED    ((tsk_flags_t)(1 << 18))\n\nextern const std::string gSLiM_tsk_metadata_schema;\nextern const std::string gSLiM_tsk_edge_metadata_schema;\nextern const std::string gSLiM_tsk_site_metadata_schema;\nextern const std::string gSLiM_tsk_mutation_metadata_schema;\nextern const std::string gSLiM_tsk_node_metadata_schema_FORMAT;\nextern const std::string gSLiM_tsk_individual_metadata_schema;\nextern const std::string gSLiM_tsk_population_metadata_schema_PREJSON;\t\t// before SLiM 3.7\nextern const std::string gSLiM_tsk_population_metadata_schema;\n\n\n// *******************************************************************************************************************\n//\n//\tNucleotideArray\n//\n#pragma mark -\n#pragma mark NucleotideArray\n#pragma mark -\n\t\nclass NucleotideArray\n{\n\t// This is a very quick-and-dirty class for storing a nucleotide sequence compactly.  BCH 14 Feb. 2019\n\t\nprivate:\n\t// The length of the array, in nucleotides\n\tstd::size_t length_;\n\t\n\t// Nucleotides are stored as 2-bit unsigned quantities in uint64_t, where A=0, C=1, G=2, T=3.\n\t// The least-significant bits of each uint64_t are filled first.  Each uint64_t holds 32 nucleotides.\n\tuint64_t *buffer_;\n\t\npublic:\n\tNucleotideArray(const NucleotideArray&) = delete;\t\t\t\t// no copying\n\tNucleotideArray& operator=(const NucleotideArray&) = delete;\t// no copying\n\tNucleotideArray(void) = delete;\t\t\t\t\t\t\t\t\t// no null construction\n\tNucleotideArray(std::size_t p_length) : length_(p_length) {\n\t\tbuffer_ = (uint64_t *)malloc(((length_ + 31) / 32) * sizeof(uint64_t));\n\t\tif (!buffer_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (NucleotideArray::NucleotideArray): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t}\n\t~NucleotideArray(void) {\n\t\tif (buffer_) { free(buffer_); buffer_ = nullptr; }\n\t}\n\t\n\t// Constructors that take sequences.  These raise a C++ exception if the sequence data is invalid,\n\t// so that it can be caught and handled without involving the Eidos exception machinery.  These\n\t// should therefore generally be called from a try/catch block.\n\tNucleotideArray(std::size_t p_length, const int64_t *p_int_buffer);\n\tNucleotideArray(std::size_t p_length, const char *p_char_buffer);\n\tNucleotideArray(std::size_t p_length, const std::string p_string_vector[]);\n\t\n\tstd::size_t size() const { return length_; }\n\t\n\tinline int NucleotideAtIndex(std::size_t p_index) const {\n\t\tuint64_t chunk = buffer_[p_index / 32];\n\t\treturn (int)((chunk >> ((p_index % 32) * 2)) & 0x03);\n\t}\n\tvoid SetNucleotideAtIndex(std::size_t p_index, uint64_t p_nuc);\n\t\n\t// Write nucleotides to a char buffer; the buffer must be allocated with sufficient length\n\t// Read nucleotides from a char buffer; the buffer is assumed to be of appropriate length\n\tvoid WriteNucleotidesToBuffer(char *buffer) const;\n\tvoid ReadNucleotidesFromBuffer(const char *buffer);\n\t\n\t// Write compressed nucleotides to an ostream as a binary block, with a leading 64-bit size in nucleotides\n\t// Read compressed nucleotides from a buffer as a binary block, with a leading size, advancing the pointer\n\tvoid WriteCompressedNucleotides(std::ostream &p_out) const;\n\tvoid ReadCompressedNucleotides(char **buffer, char *end);\n\t\n\t// Write nucleotides into an EidosValue, in any of the supported formats\n\tEidosValue_SP NucleotidesAsIntegerVector(int64_t start, int64_t end);\n\tEidosValue_SP NucleotidesAsCodonVector(int64_t start, int64_t end, bool p_force_vector);\n\tEidosValue_SP NucleotidesAsStringVector(int64_t start, int64_t end);\n\tEidosValue_SP NucleotidesAsStringSingleton(int64_t start, int64_t end);\n\t\n\t// Read/write nucleotides to a stream; here FASTA format is used on output (with no header\n\t// produced, 70 characters per line), and on input (no header allowed, newlines removed)\n\tfriend std::ostream& operator<<(std::ostream& p_out, const NucleotideArray &p_nuc_array);\n\tfriend std::istream& operator>>(std::istream& p_in, NucleotideArray &p_nuc_array);\n\t\n\t// Provides a static lookup table for going from char ('A'/'C'/'G'/'T') to int (0/1/2/3; 4 for errors)\n\tstatic uint8_t *NucleotideCharToIntLookup(void);\n};\n\nstd::ostream& operator<<(std::ostream& p_out, const NucleotideArray &p_nuc_array);\n\n\n// *******************************************************************************************************************\n//\n//\tGlobal strings and IDs\n//\n#pragma mark -\n#pragma mark Global strings and IDs\n#pragma mark -\n\n//\n//\tAdditional global std::string objects.  See script_globals.h for details.\n//\n\n// first are ones with no corresponding ID; these are just std::string globals, not registered\nextern const std::string gStr_strand1;\nextern const std::string gStr_strand2;\nextern const std::string gStr_breaks1;\nextern const std::string gStr_strand3;\nextern const std::string gStr_strand4;\nextern const std::string gStr_breaks2;\n\nvoid SLiM_ConfigureContext(void);\n\nextern const std::string &gStr_initializeAncestralNucleotides;\nextern const std::string &gStr_initializeGenomicElement;\nextern const std::string &gStr_initializeGenomicElementType;\nextern const std::string &gStr_initializeMutationType;\nextern const std::string &gStr_initializeMutationTypeNuc;\nextern const std::string &gStr_initializeChromosome;\nextern const std::string &gStr_initializeGeneConversion;\nextern const std::string &gStr_initializeMutationRate;\nextern const std::string &gStr_initializeHotspotMap;\nextern const std::string &gStr_initializeRecombinationRate;\nextern const std::string &gStr_initializeSex;\nextern const std::string &gStr_initializeSLiMOptions;\nextern const std::string &gStr_initializeSpecies;\nextern const std::string &gStr_initializeTreeSeq;\nextern const std::string &gStr_initializeSLiMModelType;\nextern const std::string &gStr_initializeInteractionType;\n\nextern const std::string &gStr_genomicElements;\nextern const std::string &gStr_lastPosition;\nextern const std::string &gStr_hotspotEndPositions;\nextern const std::string &gStr_hotspotEndPositionsM;\nextern const std::string &gStr_hotspotEndPositionsF;\nextern const std::string &gStr_hotspotMultipliers;\nextern const std::string &gStr_hotspotMultipliersM;\nextern const std::string &gStr_hotspotMultipliersF;\nextern const std::string &gStr_intrinsicPloidy;\nextern const std::string &gStr_isSexChromosome;\nextern const std::string &gStr_mutationEndPositions;\nextern const std::string &gStr_mutationEndPositionsM;\nextern const std::string &gStr_mutationEndPositionsF;\nextern const std::string &gStr_mutationRates;\nextern const std::string &gStr_mutationRatesM;\nextern const std::string &gStr_mutationRatesF;\nextern const std::string &gStr_overallMutationRate;\nextern const std::string &gStr_overallMutationRateM;\nextern const std::string &gStr_overallMutationRateF;\nextern const std::string &gStr_overallRecombinationRate;\nextern const std::string &gStr_overallRecombinationRateM;\nextern const std::string &gStr_overallRecombinationRateF;\nextern const std::string &gStr_recombinationEndPositions;\nextern const std::string &gStr_recombinationEndPositionsM;\nextern const std::string &gStr_recombinationEndPositionsF;\nextern const std::string &gStr_recombinationRates;\nextern const std::string &gStr_recombinationRatesM;\nextern const std::string &gStr_recombinationRatesF;\nextern const std::string &gStr_symbol;\nextern const std::string &gStr_geneConversionEnabled;\nextern const std::string &gStr_geneConversionGCBias;\nextern const std::string &gStr_geneConversionNonCrossoverFraction;\nextern const std::string &gStr_geneConversionMeanLength;\nextern const std::string &gStr_geneConversionSimpleConversionFraction;\nextern const std::string &gStr_chromosomeSubposition;\nextern const std::string &gStr_isNullHaplosome;\nextern const std::string &gStr_mutationCount;\nextern const std::string &gStr_mutations;\nextern const std::string &gStr_uniqueMutations;\nextern const std::string &gStr_genomicElementType;\nextern const std::string &gStr_startPosition;\nextern const std::string &gStr_endPosition;\nextern const std::string &gStr_id;\nextern const std::string &gStr_mutationTypes;\nextern const std::string &gStr_mutationFractions;\nextern const std::string &gStr_mutationMatrix;\nextern const std::string &gStr_isFixed;\nextern const std::string &gStr_isSegregating;\nextern const std::string &gStr_mutationType;\nextern const std::string &gStr_nucleotide;\nextern const std::string &gStr_nucleotideValue;\nextern const std::string &gStr_originTick;\nextern const std::string &gStr_position;\nextern const std::string &gStr_selectionCoeff;\nextern const std::string &gStr_subpopID;\nextern const std::string &gStr_convertToSubstitution;\nextern const std::string &gStr_distributionType;\nextern const std::string &gStr_distributionParams;\nextern const std::string &gStr_dominanceCoeff;\nextern const std::string &gStr_hemizygousDominanceCoeff;\nextern const std::string &gStr_mutationStackGroup;\nextern const std::string &gStr_mutationStackPolicy;\n//extern const std::string &gStr_start;\t\tnow gEidosStr_start\n//extern const std::string &gStr_end;\t\tnow gEidosStr_end\n//extern const std::string &gStr_type;\t\tnow gEidosStr_type\n//extern const std::string &gStr_source;\t\tnow gEidosStr_source\nextern const std::string &gStr_active;\nextern const std::string &gStr_allGenomicElementTypes;\nextern const std::string &gStr_allInteractionTypes;\nextern const std::string &gStr_allMutationTypes;\nextern const std::string &gStr_allScriptBlocks;\nextern const std::string &gStr_allSpecies;\nextern const std::string &gStr_allSubpopulations;\nextern const std::string &gStr_chromosome;\nextern const std::string &gStr_chromosomes;\nextern const std::string &gStr_genomicElementTypes;\nextern const std::string &gStr_lifetimeReproductiveOutput;\nextern const std::string &gStr_lifetimeReproductiveOutputM;\nextern const std::string &gStr_lifetimeReproductiveOutputF;\nextern const std::string &gStr_modelType;\nextern const std::string &gStr_nucleotideBased;\nextern const std::string &gStr_scriptBlocks;\nextern const std::string &gStr_sexChromosomes;\nextern const std::string &gStr_sexEnabled;\nextern const std::string &gStr_subpopulations;\nextern const std::string &gStr_substitutions;\nextern const std::string &gStr_tick;\nextern const std::string &gStr_cycle;\nextern const std::string &gStr_cycleStage;\nextern const std::string &gStr_colorSubstitution;\nextern const std::string &gStr_verbosity;\nextern const std::string &gStr_tag;\nextern const std::string &gStr_tagF;\nextern const std::string &gStr_tagL0;\nextern const std::string &gStr_tagL1;\nextern const std::string &gStr_tagL2;\nextern const std::string &gStr_tagL3;\nextern const std::string &gStr_tagL4;\nextern const std::string &gStr_migrant;\nextern const std::string &gStr_fitnessScaling;\nextern const std::string &gStr_firstMaleIndex;\nextern const std::string &gStr_haplosomes;\nextern const std::string &gStr_haplosomesNonNull;\nextern const std::string &gStr_haploidGenome1;\nextern const std::string &gStr_haploidGenome2;\nextern const std::string &gStr_haploidGenome1NonNull;\nextern const std::string &gStr_haploidGenome2NonNull;\nextern const std::string &gStr_sex;\nextern const std::string &gStr_individuals;\nextern const std::string &gStr_subpopulation;\nextern const std::string &gStr_index;\nextern const std::string &gStr_immigrantSubpopIDs;\nextern const std::string &gStr_immigrantSubpopFractions;\nextern const std::string &gStr_avatar;\nextern const std::string &gStr_name;\nextern const std::string &gStr_description;\nextern const std::string &gStr_selfingRate;\nextern const std::string &gStr_cloningRate;\nextern const std::string &gStr_sexRatio;\nextern const std::string &gStr_gridDimensions;\nextern const std::string &gStr_interpolate;\nextern const std::string &gStr_spatialBounds;\nextern const std::string &gStr_spatialMaps;\nextern const std::string &gStr_individualCount;\nextern const std::string &gStr_fixationTick;\nextern const std::string &gStr_age;\nextern const std::string &gStr_meanParentAge;\nextern const std::string &gStr_pedigreeID;\nextern const std::string &gStr_pedigreeParentIDs;\nextern const std::string &gStr_pedigreeGrandparentIDs;\nextern const std::string &gStr_reproductiveOutput;\nextern const std::string &gStr_haplosomePedigreeID;\nextern const std::string &gStr_reciprocal;\nextern const std::string &gStr_sexSegregation;\nextern const std::string &gStr_dimensionality;\nextern const std::string &gStr_periodicity;\nextern const std::string &gStr_spatiality;\nextern const std::string &gStr_spatialPosition;\nextern const std::string &gStr_maxDistance;\n\nextern const std::string &gStr_ancestralNucleotides;\nextern const std::string &gStr_nucleotides;\nextern const std::string &gStr_genomicElementForPosition;\nextern const std::string &gStr_hasGenomicElementForPosition;\nextern const std::string &gStr_setAncestralNucleotides;\nextern const std::string &gStr_setGeneConversion;\nextern const std::string &gStr_setHotspotMap;\nextern const std::string &gStr_setMutationRate;\nextern const std::string &gStr_setRecombinationRate;\nextern const std::string &gStr_drawBreakpoints;\nextern const std::string &gStr_addMutations;\nextern const std::string &gStr_addNewDrawnMutation;\nextern const std::string &gStr_addNewMutation;\nextern const std::string &gStr_containsMutations;\nextern const std::string &gStr_countOfMutationsOfType;\nextern const std::string &gStr_positionsOfMutationsOfType;\nextern const std::string &gStr_containsMarkerMutation;\nextern const std::string &gStr_haplosomesForChromosomes;\nextern const std::string &gStr_relatedness;\nextern const std::string &gStr_sharedParentCount;\nextern const std::string &gStr_mutationsOfType;\nextern const std::string &gStr_outputIndividuals;\nextern const std::string &gStr_outputIndividualsToVCF;\nextern const std::string &gStr_readIndividualsFromVCF;\nextern const std::string &gStr_setSpatialPosition;\nextern const std::string &gStr_substitutionsOfType;\nextern const std::string &gStr_sumOfMutationsOfType;\nextern const std::string &gStr_uniqueMutationsOfType;\nextern const std::string &gStr_zygosityOfMutations;\nextern const std::string &gStr_mutationsFromHaplosomes;\nextern const std::string &gStr_readHaplosomesFromMS;\nextern const std::string &gStr_readHaplosomesFromVCF;\nextern const std::string &gStr_removeMutations;\nextern const std::string &gStr_setGenomicElementType;\nextern const std::string &gStr_setMutationFractions;\nextern const std::string &gStr_setMutationMatrix;\nextern const std::string &gStr_setSelectionCoeff;\nextern const std::string &gStr_setMutationType;\nextern const std::string &gStr_drawSelectionCoefficient;\nextern const std::string &gStr_setDistribution;\nextern const std::string &gStr_addPatternForClone;\nextern const std::string &gStr_addPatternForCross;\nextern const std::string &gStr_addPatternForNull;\nextern const std::string &gStr_addPatternForRecombinant;\nextern const std::string &gStr_addSubpop;\nextern const std::string &gStr_addSubpopSplit;\nextern const std::string &gStr_chromosomesOfType;\nextern const std::string &gStr_chromosomesWithIDs;\nextern const std::string &gStr_chromosomesWithSymbols;\nextern const std::string &gStr_estimatedLastTick;\nextern const std::string &gStr_deregisterScriptBlock;\nextern const std::string &gStr_genomicElementTypesWithIDs;\nextern const std::string &gStr_interactionTypesWithIDs;\nextern const std::string &gStr_mutationTypesWithIDs;\nextern const std::string &gStr_scriptBlocksWithIDs;\nextern const std::string &gStr_speciesWithIDs;\nextern const std::string &gStr_subpopulationsWithIDs;\nextern const std::string &gStr_subpopulationsWithNames;\nextern const std::string &gStr_individualsWithPedigreeIDs;\nextern const std::string &gStr_killIndividuals;\nextern const std::string &gStr_mutationCounts;\nextern const std::string &gStr_mutationCountsInHaplosomes;\nextern const std::string &gStr_mutationFrequencies;\nextern const std::string &gStr_mutationFrequenciesInHaplosomes;\n//extern const std::string &gStr_mutationsOfType;\n//extern const std::string &gStr_countOfMutationsOfType;\nextern const std::string &gStr_outputFixedMutations;\nextern const std::string &gStr_outputFull;\nextern const std::string &gStr_outputMutations;\nextern const std::string &gStr_outputUsage;\nextern const std::string &gStr_readFromPopulationFile;\nextern const std::string &gStr_recalculateFitness;\nextern const std::string &gStr_registerFirstEvent;\nextern const std::string &gStr_registerEarlyEvent;\nextern const std::string &gStr_registerLateEvent;\nextern const std::string &gStr_registerFitnessEffectCallback;\nextern const std::string &gStr_registerInteractionCallback;\nextern const std::string &gStr_registerMateChoiceCallback;\nextern const std::string &gStr_registerModifyChildCallback;\nextern const std::string &gStr_registerRecombinationCallback;\nextern const std::string &gStr_registerMutationCallback;\nextern const std::string &gStr_registerMutationEffectCallback;\nextern const std::string &gStr_registerSurvivalCallback;\nextern const std::string &gStr_registerReproductionCallback;\nextern const std::string &gStr_rescheduleScriptBlock;\nextern const std::string &gStr_simulationFinished;\nextern const std::string &gStr_skipTick;\nextern const std::string &gStr_subsetMutations;\nextern const std::string &gStr_treeSeqCoalesced;\nextern const std::string &gStr_treeSeqSimplify;\nextern const std::string &gStr_treeSeqRememberIndividuals;\nextern const std::string &gStr_treeSeqOutput;\nextern const std::string &gStr__debug;\t// internal\nextern const std::string &gStr_setMigrationRates;\nextern const std::string &gStr_deviatePositions;\nextern const std::string &gStr_deviatePositionsWithMap;\nextern const std::string &gStr_pointDeviated;\nextern const std::string &gStr_pointInBounds;\nextern const std::string &gStr_pointReflected;\nextern const std::string &gStr_pointStopped;\nextern const std::string &gStr_pointPeriodic;\nextern const std::string &gStr_pointUniform;\nextern const std::string &gStr_pointUniformWithMap;\nextern const std::string &gStr_setCloningRate;\nextern const std::string &gStr_setSelfingRate;\nextern const std::string &gStr_setSexRatio;\nextern const std::string &gStr_setSpatialBounds;\nextern const std::string &gStr_setSubpopulationSize;\nextern const std::string &gStr_addCloned;\nextern const std::string &gStr_addCrossed;\nextern const std::string &gStr_addEmpty;\nextern const std::string &gStr_addMultiRecombinant;\nextern const std::string &gStr_addRecombinant;\nextern const std::string &gStr_addSelfed;\nextern const std::string &gStr_takeMigrants;\nextern const std::string &gStr_removeSubpopulation;\nextern const std::string &gStr_cachedFitness;\nextern const std::string &gStr_sampleIndividuals;\nextern const std::string &gStr_subsetIndividuals;\nextern const std::string &gStr_defineSpatialMap;\nextern const std::string &gStr_addSpatialMap;\nextern const std::string &gStr_removeSpatialMap;\nextern const std::string &gStr_spatialMapColor;\nextern const std::string &gStr_spatialMapImage;\nextern const std::string &gStr_spatialMapValue;\nextern const std::string &gStr_add;\nextern const std::string &gStr_blend;\nextern const std::string &gStr_multiply;\nextern const std::string &gStr_divide;\nextern const std::string &gStr_subtract;\nextern const std::string &gStr_power;\nextern const std::string &gStr_exp;\nextern const std::string &gStr_changeColors;\nextern const std::string &gStr_changeValues;\nextern const std::string &gStr_gridValues;\nextern const std::string &gStr_mapColor;\nextern const std::string &gStr_mapImage;\nextern const std::string &gStr_mapValue;\nextern const std::string &gStr_rescale;\nextern const std::string &gStr_sampleImprovedNearbyPoint;\nextern const std::string &gStr_sampleNearbyPoint;\nextern const std::string &gStr_smooth;\nextern const std::string &gStr_outputMSSample;\nextern const std::string &gStr_outputVCFSample;\nextern const std::string &gStr_outputSample;\nextern const std::string &gStr_outputHaplosomesToMS;\nextern const std::string &gStr_outputHaplosomesToVCF;\nextern const std::string &gStr_outputHaplosomes;\nextern const std::string &gStr_evaluate;\nextern const std::string &gStr_distance;\nextern const std::string &gStr_localPopulationDensity;\nextern const std::string &gStr_interactionDistance;\nextern const std::string &gStr_clippedIntegral;\nextern const std::string &gStr_distanceFromPoint;\nextern const std::string &gStr_nearestNeighbors;\nextern const std::string &gStr_neighborCount;\nextern const std::string &gStr_neighborCountOfPoint;\nextern const std::string &gStr_nearestInteractingNeighbors;\nextern const std::string &gStr_interactingNeighborCount;\nextern const std::string &gStr_nearestNeighborsOfPoint;\nextern const std::string &gStr_setConstraints;\nextern const std::string &gStr_setInteractionFunction;\nextern const std::string &gStr_strength;\nextern const std::string &gStr_testConstraints;\nextern const std::string &gStr_totalOfNeighborStrengths;\nextern const std::string &gStr_unevaluate;\nextern const std::string &gStr_drawByStrength;\n\nextern const std::string &gStr_community;\nextern const std::string &gStr_sim;\nextern const std::string &gStr_self;\nextern const std::string &gStr_individual;\nextern const std::string &gStr_element;\nextern const std::string &gStr_haplosome;\nextern const std::string &gStr_haplosome1;\nextern const std::string &gStr_haplosome2;\nextern const std::string &gStr_subpop;\nextern const std::string &gStr_sourceSubpop;\n//extern const std::string &gStr_weights;\t\tnow gEidosStr_weights\nextern const std::string &gStr_child;\nextern const std::string &gStr_parent;\nextern const std::string &gStr_parent1;\nextern const std::string &gStr_isCloning;\nextern const std::string &gStr_isSelfing;\nextern const std::string &gStr_parent2;\nextern const std::string &gStr_mut;\nextern const std::string &gStr_effect;\nextern const std::string &gStr_homozygous;\nextern const std::string &gStr_breakpoints;\nextern const std::string &gStr_receiver;\nextern const std::string &gStr_exerter;\nextern const std::string &gStr_originalNuc;\nextern const std::string &gStr_fitness;\nextern const std::string &gStr_surviving;\nextern const std::string &gStr_draw;\n\nextern const std::string &gStr_slimgui;\nextern const std::string &gStr_pid;\nextern const std::string &gStr_configureDisplay;\nextern const std::string &gStr_createPlot;\nextern const std::string &gStr_logFileData;\nextern const std::string &gStr_openDocument;\nextern const std::string &gStr_pauseExecution;\nextern const std::string &gStr_plotWithTitle;\n\nextern const std::string &gStr_abline;\nextern const std::string &gStr_addLegend;\nextern const std::string &gStr_axis;\nextern const std::string &gStr_image;\nextern const std::string &gStr_legendLineEntry;\nextern const std::string &gStr_legendPointEntry;\nextern const std::string &gStr_legendSwatchEntry;\nextern const std::string &gStr_legendTitleEntry;\nextern const std::string &gStr_lines;\nextern const std::string &gStr_matrix;\nextern const std::string &gStr_mtext;\nextern const std::string &gStr_points;\nextern const std::string &gStr_rects;\nextern const std::string &gStr_segments;\nextern const std::string &gStr_setBorderless;\nextern const std::string &gStr_text;\nextern const std::string &gStr_title;\n\nextern const std::string &gStr_Chromosome;\n//extern const std::string &gStr_Haplosome;\t\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nextern const std::string &gStr_GenomicElement;\nextern const std::string &gStr_GenomicElementType;\n//extern const std::string &gStr_Mutation;\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nextern const std::string &gStr_MutationType;\nextern const std::string &gStr_SLiMEidosBlock;\nextern const std::string &gStr_Community;\nextern const std::string &gStr_SpatialMap;\nextern const std::string &gStr_Species;\nextern const std::string &gStr_Subpopulation;\n//extern const std::string &gStr_Individual;\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\nextern const std::string &gStr_Substitution;\nextern const std::string &gStr_InteractionType;\nextern const std::string &gStr_Plot;\nextern const std::string &gStr_SLiMgui;\n\nextern const std::string &gStr_createLogFile;\nextern const std::string &gStr_logFiles;\nextern const std::string &gStr_LogFile;\nextern const std::string &gStr_logInterval;\nextern const std::string &gStr_precision;\nextern const std::string &gStr_addCustomColumn;\nextern const std::string &gStr_addCycle;\nextern const std::string &gStr_addCycleStage;\nextern const std::string &gStr_addMeanSDColumns;\nextern const std::string &gStr_addPopulationSexRatio;\nextern const std::string &gStr_addPopulationSize;\nextern const std::string &gStr_addSubpopulationSexRatio;\nextern const std::string &gStr_addSubpopulationSize;\nextern const std::string &gStr_addSuppliedColumn;\nextern const std::string &gStr_addTick;\nextern const std::string &gStr_flush;\nextern const std::string &gStr_logRow;\nextern const std::string &gStr_setLogInterval;\nextern const std::string &gStr_setFilePath;\nextern const std::string &gStr_setSuppliedValue;\nextern const std::string &gStr_willAutolog;\nextern const std::string &gStr_context;\n\nextern const std::string gStr_A;\t// these nucleotide strings are not registered, no need\nextern const std::string gStr_C;\nextern const std::string gStr_G;\nextern const std::string gStr_T;\nextern const std::string gStr_H;\t// these chromosome type strings (and \"A\" above) are not registered, no need\nextern const std::string gStr_X;\nextern const std::string gStr_Y;\nextern const std::string gStr_Z;\nextern const std::string gStr_W;\nextern const std::string gStr_HF;\nextern const std::string gStr_FL;\nextern const std::string gStr_HM;\nextern const std::string gStr_ML;\nextern const std::string gStr_H_;\nextern const std::string gStr__Y;\nextern const std::string &gStr_f;\nextern const std::string &gStr_g;\nextern const std::string &gStr_e;\n//extern const std::string &gStr_n;\t\tnow gEidosStr_n\nextern const std::string &gStr_w;\nextern const std::string &gStr_l;\nextern const std::string &gStr_p;\n//extern const std::string &gStr_s;\t\tnow gEidosStr_s\nextern const std::string &gStr_species;\nextern const std::string &gStr_ticks;\nextern const std::string &gStr_speciesSpec;\nextern const std::string &gStr_ticksSpec;\nextern const std::string &gStr_first;\nextern const std::string &gStr_early;\nextern const std::string &gStr_late;\nextern const std::string &gStr_initialize;\nextern const std::string &gStr_fitnessEffect;\nextern const std::string &gStr_mutationEffect;\nextern const std::string &gStr_interaction;\nextern const std::string &gStr_mateChoice;\nextern const std::string &gStr_modifyChild;\nextern const std::string &gStr_mutation;\nextern const std::string &gStr_survival;\nextern const std::string &gStr_recombination;\nextern const std::string &gStr_reproduction;\n\n\nenum _SLiMGlobalStringID : int {\n\tgID_initializeAncestralNucleotides = gEidosID_LastEntry + 1,\n\tgID_initializeGenomicElement,\n\tgID_initializeGenomicElementType,\n\tgID_initializeMutationType,\n\tgID_initializeMutationTypeNuc,\n\tgID_initializeChromosome,\n\tgID_initializeGeneConversion,\n\tgID_initializeMutationRate,\n\tgID_initializeHotspotMap,\n\tgID_initializeRecombinationRate,\n\tgID_initializeSex,\n\tgID_initializeSLiMOptions,\n\tgID_initializeSpecies,\n\tgID_initializeTreeSeq,\n\tgID_initializeSLiMModelType,\n\tgID_initializeInteractionType,\n\t\n\tgID_genomicElements,\n\tgID_lastPosition,\n\tgID_hotspotEndPositions,\n\tgID_hotspotEndPositionsM,\n\tgID_hotspotEndPositionsF,\n\tgID_hotspotMultipliers,\n\tgID_hotspotMultipliersM,\n\tgID_hotspotMultipliersF,\n\tgID_intrinsicPloidy,\n\tgID_isSexChromosome,\n\tgID_mutationEndPositions,\n\tgID_mutationEndPositionsM,\n\tgID_mutationEndPositionsF,\n\tgID_mutationRates,\n\tgID_mutationRatesM,\n\tgID_mutationRatesF,\n\tgID_overallMutationRate,\n\tgID_overallMutationRateM,\n\tgID_overallMutationRateF,\n\tgID_overallRecombinationRate,\n\tgID_overallRecombinationRateM,\n\tgID_overallRecombinationRateF,\n\tgID_recombinationEndPositions,\n\tgID_recombinationEndPositionsM,\n\tgID_recombinationEndPositionsF,\n\tgID_recombinationRates,\n\tgID_recombinationRatesM,\n\tgID_recombinationRatesF,\n\tgID_symbol,\n\tgID_geneConversionEnabled,\n\tgID_geneConversionGCBias,\n\tgID_geneConversionNonCrossoverFraction,\n\tgID_geneConversionMeanLength,\n\tgID_geneConversionSimpleConversionFraction,\n\tgID_chromosomeSubposition,\n\tgID_isNullHaplosome,\n\tgID_mutationCount,\n\tgID_mutations,\n\tgID_uniqueMutations,\n\tgID_genomicElementType,\n\tgID_startPosition,\n\tgID_endPosition,\n\tgID_id,\n\tgID_mutationTypes,\n\tgID_mutationFractions,\n\tgID_mutationMatrix,\n\tgID_isFixed,\n\tgID_isSegregating,\n\tgID_mutationType,\n\tgID_nucleotide,\n\tgID_nucleotideValue,\n\tgID_originTick,\n\tgID_position,\n\tgID_selectionCoeff,\n\tgID_subpopID,\n\tgID_convertToSubstitution,\n\tgID_distributionType,\n\tgID_distributionParams,\n\tgID_dominanceCoeff,\n\tgID_hemizygousDominanceCoeff,\n\tgID_mutationStackGroup,\n\tgID_mutationStackPolicy,\n\t//gID_start,\tnow gEidosID_start\n\t//gID_end,\t\tnow gEidosID_end\n\t//gID_type,\t\tnow gEidosID_type\n\t//gID_source,\tnow gEidosID_source\n\tgID_active,\n\tgID_allGenomicElementTypes,\n\tgID_allInteractionTypes,\n\tgID_allMutationTypes,\n\tgID_allScriptBlocks,\n\tgID_allSpecies,\n\tgID_allSubpopulations,\n\tgID_chromosome,\n\tgID_chromosomes,\n\tgID_genomicElementTypes,\n\tgID_lifetimeReproductiveOutput,\n\tgID_lifetimeReproductiveOutputM,\n\tgID_lifetimeReproductiveOutputF,\n\tgID_modelType,\n\tgID_nucleotideBased,\n\tgID_scriptBlocks,\n\tgID_sexChromosomes,\n\tgID_sexEnabled,\n\tgID_subpopulations,\n\tgID_substitutions,\n\tgID_tick,\n\tgID_cycle,\n\tgID_cycleStage,\n\tgID_colorSubstitution,\n\tgID_verbosity,\n\tgID_tag,\n\tgID_tagF,\n\tgID_tagL0,\n\tgID_tagL1,\n\tgID_tagL2,\n\tgID_tagL3,\n\tgID_tagL4,\n\tgID_migrant,\n\tgID_fitnessScaling,\n\tgID_firstMaleIndex,\n\tgID_haplosomes,\n\tgID_haplosomesNonNull,\n\tgID_haploidGenome1,\n\tgID_haploidGenome2,\n\tgID_haploidGenome1NonNull,\n\tgID_haploidGenome2NonNull,\n\tgID_sex,\n\tgID_individuals,\n\tgID_subpopulation,\n\tgID_index,\n\tgID_immigrantSubpopIDs,\n\tgID_immigrantSubpopFractions,\n\tgID_avatar,\n\tgID_name,\n\tgID_description,\n\tgID_selfingRate,\n\tgID_cloningRate,\n\tgID_sexRatio,\n\tgID_gridDimensions,\n\tgID_interpolate,\n\tgID_spatialBounds,\n\tgID_spatialMaps,\n\tgID_individualCount,\n\tgID_fixationTick,\n\tgID_age,\n\tgID_meanParentAge,\n\tgID_pedigreeID,\n\tgID_pedigreeParentIDs,\n\tgID_pedigreeGrandparentIDs,\n\tgID_reproductiveOutput,\n\tgID_haplosomePedigreeID,\n\tgID_reciprocal,\n\tgID_sexSegregation,\n\tgID_dimensionality,\n\tgID_periodicity,\n\tgID_spatiality,\n\tgID_spatialPosition,\n\tgID_maxDistance,\n\t\n\tgID_ancestralNucleotides,\n\tgID_nucleotides,\n\tgID_genomicElementForPosition,\n\tgID_hasGenomicElementForPosition,\n\tgID_setAncestralNucleotides,\n\tgID_setGeneConversion,\n\tgID_setHotspotMap,\n\tgID_setMutationRate,\n\tgID_setRecombinationRate,\n\tgID_drawBreakpoints,\n\tgID_addMutations,\n\tgID_addNewDrawnMutation,\n\tgID_addNewMutation,\n\tgID_containsMutations,\n\tgID_countOfMutationsOfType,\n\tgID_positionsOfMutationsOfType,\n\tgID_containsMarkerMutation,\n\tgID_haplosomesForChromosomes,\n\tgID_relatedness,\n\tgID_sharedParentCount,\n\tgID_mutationsOfType,\n\tgID_outputIndividuals,\n\tgID_outputIndividualsToVCF,\n\tgID_readIndividualsFromVCF,\n\tgID_setSpatialPosition,\n\tgID_substitutionsOfType,\n\tgID_sumOfMutationsOfType,\n\tgID_uniqueMutationsOfType,\n\tgID_zygosityOfMutations,\n\tgID_mutationsFromHaplosomes,\n\tgID_readHaplosomesFromMS,\n\tgID_readHaplosomesFromVCF,\n\tgID_removeMutations,\n\tgID_setGenomicElementType,\n\tgID_setMutationFractions,\n\tgID_setMutationMatrix,\n\tgID_setSelectionCoeff,\n\tgID_setMutationType,\n\tgID_drawSelectionCoefficient,\n\tgID_setDistribution,\n\tgID_addPatternForClone,\n\tgID_addPatternForCross,\n\tgID_addPatternForNull,\n\tgID_addPatternForRecombinant,\n\tgID_addSubpop,\n\tgID_chromosomesOfType,\n\tgID_chromosomesWithIDs,\n\tgID_chromosomesWithSymbols,\n\tgID_addSubpopSplit,\n\tgID_estimatedLastTick,\n\tgID_deregisterScriptBlock,\n\tgID_genomicElementTypesWithIDs,\n\tgID_interactionTypesWithIDs,\n\tgID_mutationTypesWithIDs,\n\tgID_scriptBlocksWithIDs,\n\tgID_speciesWithIDs,\n\tgID_subpopulationsWithIDs,\n\tgID_subpopulationsWithNames,\n\tgID_individualsWithPedigreeIDs,\n\tgID_killIndividuals,\n\tgID_mutationCounts,\n\tgID_mutationCountsInHaplosomes,\n\tgID_mutationFrequencies,\n\tgID_mutationFrequenciesInHaplosomes,\n\t//gID_mutationsOfType,\n\t//gID_countOfMutationsOfType,\n\tgID_outputFixedMutations,\n\tgID_outputFull,\n\tgID_outputMutations,\n\tgID_outputUsage,\n\tgID_readFromPopulationFile,\n\tgID_recalculateFitness,\n\tgID_registerFirstEvent,\n\tgID_registerEarlyEvent,\n\tgID_registerLateEvent,\n\tgID_registerFitnessEffectCallback,\n\tgID_registerInteractionCallback,\n\tgID_registerMateChoiceCallback,\n\tgID_registerModifyChildCallback,\n\tgID_registerRecombinationCallback,\n\tgID_registerMutationCallback,\n\tgID_registerMutationEffectCallback,\n\tgID_registerSurvivalCallback,\n\tgID_registerReproductionCallback,\n\tgID_rescheduleScriptBlock,\n\tgID_simulationFinished,\n\tgID_skipTick,\n\tgID_subsetMutations,\n\tgID_treeSeqCoalesced,\n\tgID_treeSeqSimplify,\n\tgID_treeSeqRememberIndividuals,\n\tgID_treeSeqOutput,\n\tgID__debug,\t\t// internal\n\tgID_setMigrationRates,\n\tgID_deviatePositions,\n\tgID_deviatePositionsWithMap,\n\tgID_pointDeviated,\n\tgID_pointInBounds,\n\tgID_pointReflected,\n\tgID_pointStopped,\n\tgID_pointPeriodic,\n\tgID_pointUniform,\n\tgID_pointUniformWithMap,\n\tgID_setCloningRate,\n\tgID_setSelfingRate,\n\tgID_setSexRatio,\n\tgID_setSpatialBounds,\n\tgID_setSubpopulationSize,\n\tgID_addCloned,\n\tgID_addCrossed,\n\tgID_addEmpty,\n\tgID_addMultiRecombinant,\n\tgID_addRecombinant,\n\tgID_addSelfed,\n\tgID_takeMigrants,\n\tgID_removeSubpopulation,\n\tgID_cachedFitness,\n\tgID_sampleIndividuals,\n\tgID_subsetIndividuals,\n\tgID_defineSpatialMap,\n\tgID_addSpatialMap,\n\tgID_removeSpatialMap,\n\tgID_spatialMapColor,\n\tgID_spatialMapImage,\n\tgID_spatialMapValue,\n\tgID_add,\n\tgID_blend,\n\tgID_multiply,\n\tgID_subtract,\n\tgID_divide,\n\tgID_power,\n\tgID_exp,\n\tgID_changeColors,\n\tgID_changeValues,\n\tgID_gridValues,\n\tgID_mapColor,\n\tgID_mapImage,\n\tgID_mapValue,\n\tgID_rescale,\n\tgID_sampleImprovedNearbyPoint,\n\tgID_sampleNearbyPoint,\n\tgID_smooth,\n\tgID_outputMSSample,\n\tgID_outputVCFSample,\n\tgID_outputSample,\n\tgID_outputHaplosomesToMS,\n\tgID_outputHaplosomesToVCF,\n\tgID_outputHaplosomes,\n\tgID_evaluate,\n\tgID_distance,\n\tgID_localPopulationDensity,\n\tgID_interactionDistance,\n\tgID_clippedIntegral,\n\tgID_distanceFromPoint,\n\tgID_nearestNeighbors,\n\tgID_neighborCount,\n\tgID_neighborCountOfPoint,\n\tgID_nearestInteractingNeighbors,\n\tgID_interactingNeighborCount,\n\tgID_nearestNeighborsOfPoint,\n\tgID_setConstraints,\n\tgID_setInteractionFunction,\n\tgID_strength,\n\tgID_testConstraints,\n\tgID_totalOfNeighborStrengths,\n\tgID_unevaluate,\n\tgID_drawByStrength,\n\t\n\tgID_community,\n\tgID_sim,\n\tgID_self,\n\tgID_individual,\n\tgID_element,\n\tgID_haplosome,\n\tgID_haplosome1,\n\tgID_haplosome2,\n\tgID_subpop,\n\tgID_sourceSubpop,\n\t//gID_weights,\t\tnow gEidosID_weights\n\tgID_child,\n\tgID_parent,\n\tgID_parent1,\n\tgID_isCloning,\n\tgID_isSelfing,\n\tgID_parent2,\n\tgID_mut,\n\tgID_effect,\n\tgID_homozygous,\n\tgID_breakpoints,\n\tgID_receiver,\n\tgID_exerter,\n\tgID_originalNuc,\n\tgID_fitness,\n\tgID_surviving,\n\tgID_draw,\n\t\n\tgID_slimgui,\n\tgID_pid,\n\tgID_configureDisplay,\n\tgID_createPlot,\n\tgID_logFileData,\n\tgID_openDocument,\n\tgID_pauseExecution,\n\tgID_plotWithTitle,\n\t\n\tgID_abline,\n\tgID_addLegend,\n\tgID_axis,\n\tgID_image,\n\tgID_legendLineEntry,\n\tgID_legendPointEntry,\n\tgID_legendSwatchEntry,\n\tgID_legendTitleEntry,\n\tgID_lines,\n\tgID_matrix,\n\tgID_mtext,\n\tgID_points,\n\tgID_rects,\n\tgID_segments,\n\tgID_setBorderless,\n\tgID_text,\n\tgID_title,\n\t\n\tgID_Chromosome,\n\tgID_Haplosome,\n\tgID_GenomicElement,\n\tgID_GenomicElementType,\n\t//gID_Mutation,\t\t// in Eidos; see EidosValue_Object::EidosValue_Object()\n\tgID_MutationType,\n\tgID_SLiMEidosBlock,\n\tgID_Community,\n\tgID_SpatialMap,\n\tgID_Species,\n\tgID_Subpopulation,\n\tgID_Individual,\n\tgID_Substitution,\n\tgID_InteractionType,\n\tgID_Plot,\n\tgID_SLiMgui,\n\t\n\tgID_createLogFile,\n\tgID_logFiles,\n\tgID_LogFile,\n\tgID_logInterval,\n\tgID_precision,\n\tgID_addCustomColumn,\n\tgID_addCycle,\n\tgID_addCycleStage,\n\tgID_addMeanSDColumns,\n\tgID_addPopulationSexRatio,\n\tgID_addPopulationSize,\n\tgID_addSubpopulationSexRatio,\n\tgID_addSubpopulationSize,\n\tgID_addSuppliedColumn,\n\tgID_addTick,\n\tgID_flush,\n\tgID_logRow,\n\tgID_setLogInterval,\n\tgID_setFilePath,\n\tgID_setSuppliedValue,\n\tgID_willAutolog,\n\tgID_context,\n\t\n\tgID_f,\n\tgID_g,\n\tgID_e,\n\t// gID_n,\t\tnow gEidosID_n\n\tgID_w,\n\tgID_l,\n\tgID_p,\n\t//gID_s,\tnow gEidosID_s\n\tgID_species,\n\tgID_ticks,\n\tgID_speciesSpec,\n\tgID_ticksSpec,\n\tgID_first,\n\tgID_early,\n\tgID_late,\n\tgID_initialize,\n\tgID_fitnessEffect,\n\tgID_mutationEffect,\n\tgID_interaction,\n\tgID_mateChoice,\n\tgID_modifyChild,\n\tgID_recombination,\n\tgID_mutation,\n\tgID_survival,\n\tgID_reproduction,\n\t\n\tgID_LastSLiMEntry\t// must come last\n};\n\nstatic_assert((int)gID_LastSLiMEntry <= (int)gEidosID_LastContextEntry, \"the Context's last EidosGlobalStringID is greater than Eidos's upper limit\");\n\n\n// *******************************************************************************************************************\n//\n//\tProfiling\n//\n#pragma mark -\n#pragma mark Profiling\n#pragma mark -\n\n#if (SLIMPROFILING == 1)\nvoid WriteProfileResults(std::string profile_output_path, std::string model_name, Community *community);\n#endif\n\n\n#endif /* defined(__SLiM__slim_globals__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test.cpp",
    "content": "//\n//  slim_test.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/14/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_test.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"eidos_test.h\"\n#include \"individual.h\"\n#include \"mutation_run.h\"\n#include \"interaction_type.h\"\n\n#include <stdlib.h>\n#include <iostream>\n#include <string>\n#include <vector>\n#include <stdexcept>\n#include <unordered_map>\n#include <map>\n#include <utility>\n#include <ctime>\n\n\n// Keeping records of test success / failure\nstatic int gSLiMTestSuccessCount = 0;\nstatic int gSLiMTestFailureCount = 0;\n\n\n// Instantiates and runs the script, and prints an error if the result does not match expectations\nvoid SLiMAssertScriptSuccess(const std::string &p_script_string, int p_lineNumber)\n{\n\t{\n\tgSLiMTestFailureCount++;\t// assume failure; we will fix this at the end if we succeed\n\t\n\tCommunity *community = nullptr;\n\tstd::istringstream infile(p_script_string);\n\t\n\ttry {\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(infile);\n\t\tcommunity->InitializeRNGFromSeed(nullptr);\n\t\tcommunity->FinishInitialization();\n\t}\n\tcatch (...)\n\t{\n\t\tif (p_lineNumber != -1)\n\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during new Community(): \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\n\t\tClearErrorContext();\n\t\treturn;\n\t}\n\t\n\ttry {\n\t\twhile (community->_RunOneTick());\n\t}\n\tcatch (...)\n\t{\n\t\tif (community)\n\t\t\tfor (Species *species : community->AllSpecies())\n\t\t\t\tspecies->DeleteAllMutationRuns();\n\t\t\n\t\tdelete community;\n\t\tInteractionType::DeleteSparseVectorFreeList();\n\t\t\n\t\tif (p_lineNumber != -1)\n\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during RunOneTick(): \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\n\t\tClearErrorContext();\n\t\treturn;\n\t}\n\t\n\tif (community)\n\t\tfor (Species *species : community->AllSpecies())\n\t\t\tspecies->DeleteAllMutationRuns();\n\t\n\tdelete community;\n\tInteractionType::DeleteSparseVectorFreeList();\n\t\n\tgSLiMTestFailureCount--;\t// correct for our assumption of failure above\n\tgSLiMTestSuccessCount++;\n\t\n\t//std::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_SUCCESS_TAG << endl;\n\t\n\tClearErrorContext();\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\tstd::cerr << \"WARNING (SLiMAssertScriptSuccess): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\nvoid SLiMAssertScriptRaise(const std::string &p_script_string, const std::string &p_reason_snip, int p_lineNumber, bool p_expect_error_position, bool p_error_is_in_stop)\n{\n\t{\n\tCommunity *community = nullptr;\n\t\n\ttry {\n\t\tstd::istringstream infile(p_script_string);\n\t\t\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(infile);\n\t\tcommunity->InitializeRNGFromSeed(nullptr);\n\t\tcommunity->FinishInitialization();\n\t\t\n\t\twhile (community->_RunOneTick());\n\t\t\n\t\tgSLiMTestFailureCount++;\n\t\t\n\t\tif (p_lineNumber != -1)\n\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : no raise during SLiM execution (expected \\\"\" << p_reason_snip << \"\\\").\" << std::endl;\n\t}\n\tcatch (...)\n\t{\n\t\t// We need to call Eidos_GetTrimmedRaiseMessage() here to empty the error stringstream, even if we don't log the error\n\t\tstd::string raise_message = Eidos_GetTrimmedRaiseMessage();\n\t\t\n\t\tif (p_error_is_in_stop || (raise_message.find(\"stop() called\") == std::string::npos))\n\t\t{\n\t\t\tif (raise_message.find(p_reason_snip) != std::string::npos)\n\t\t\t{\n\t\t\t\tif ((gEidosErrorContext.errorPosition.characterStartOfError == -1) ||\n\t\t\t\t\t(gEidosErrorContext.errorPosition.characterEndOfError == -1))\n\t\t\t\t{\n\t\t\t\t\tif (!p_expect_error_position)\n\t\t\t\t\t{\n\t\t\t\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t//std::cerr << p_script_string << \" == (expected raise) : \" << EIDOS_OUTPUT_SUCCESS_TAG << \"\\n   \" << raise_message << endl;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (p_lineNumber != -1)\n\t\t\t\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise expected, but no error info set\" << std::endl;\n\t\t\t\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (!p_expect_error_position)\n\t\t\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_SUCCESS_TAG << \" : raise expected, and error info is set; but error info was not expected!\" << std::endl;\n\t\t\t\t\t\n\t\t\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\t\t\n\t\t\t\t\t//std::cerr << p_script_string << \" == (expected raise) : \" << EIDOS_OUTPUT_SUCCESS_TAG << \"\\n   \" << raise_message << endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\n\t\t\t\tif (p_lineNumber != -1)\n\t\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\t\n\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise message mismatch (expected \\\"\" << p_reason_snip << \"\\\").\" << std::endl;\n\t\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgSLiMTestFailureCount++;\n\t\t\t\n\t\t\tif (p_lineNumber != -1)\n\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\n\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : stop() reached (expected \\\"\" << p_reason_snip << \"\\\").\" << std::endl;\n\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t}\n\t\t\n\t\t// Error messages that say (internal error) should not be possible to trigger in script\n\t\tif (raise_message.find(\"(internal error)\") != std::string::npos)\n\t\t{\n\t\t\tstd::cerr << p_script_string << \" : error message contains (internal error) erroneously\" << std::endl;\n\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t}\n\t}\n\t\n\tif (community)\n\t\tfor (Species *species : community->AllSpecies())\n\t\t\tspecies->DeleteAllMutationRuns();\n\t\n\tdelete community;\n\tInteractionType::DeleteSparseVectorFreeList();\n\t\n\tClearErrorContext();\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\tstd::cerr << \"WARNING (SLiMAssertScriptRaise): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\nvoid SLiMAssertScriptStop(const std::string &p_script_string, int p_lineNumber)\n{\n\t{\n\tCommunity *community = nullptr;\n\t\n\ttry {\n\t\tstd::istringstream infile(p_script_string);\n\t\t\n\t\tcommunity = new Community();\n\t\tcommunity->InitializeFromFile(infile);\n\t\tcommunity->InitializeRNGFromSeed(nullptr);\n\t\tcommunity->FinishInitialization();\n\t\t\n\t\twhile (community->_RunOneTick());\n\t\t\n\t\tgSLiMTestFailureCount++;\n\t\t\n\t\tif (p_lineNumber != -1)\n\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : no raise during SLiM execution.\" << std::endl;\n\t}\n\tcatch (...)\n\t{\n\t\t// We need to call Eidos_GetTrimmedRaiseMessage() here to empty the error stringstream, even if we don't log the error\n\t\tstd::string raise_message = Eidos_GetTrimmedRaiseMessage();\n\t\t\n\t\tif (raise_message.find(\"stop() called\") == std::string::npos)\n\t\t{\n\t\t\tgSLiMTestFailureCount++;\n\t\t\t\n\t\t\tif (p_lineNumber != -1)\n\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\n\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : stop() not reached\" << std::endl;\n\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\n\t\t\tif ((gEidosErrorContext.errorPosition.characterStartOfError != -1) &&\n\t\t\t\t(gEidosErrorContext.errorPosition.characterEndOfError != -1))\n\t\t\t{\n\t\t\t\tEidos_LogScriptError(std::cerr, gEidosErrorContext);\n\t\t\t}\n\t\t\t\n\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\n\t\t\t//std::cerr << p_script_string << \" == (expected raise) \" << raise_message << \" : \" << EIDOS_OUTPUT_SUCCESS_TAG << endl;\n\t\t}\n\t}\n\t\n\tif (community)\n\t\tfor (Species *species : community->AllSpecies())\n\t\t\tspecies->DeleteAllMutationRuns();\n\t\n\tdelete community;\n\tInteractionType::DeleteSparseVectorFreeList();\n\t\n\tClearErrorContext();\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\tstd::cerr << \"WARNING (SLiMAssertScriptStop): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\nvoid SLiMAssertScriptRaisePosition(const std::string &p_script_string, const int p_bad_position, const char *p_reason_snip, int p_lineNumber)\n{\n\t{\n\t\tCommunity *community = nullptr;\n\t\t\n\t\ttry {\n\t\t\tstd::istringstream infile(p_script_string);\n\t\t\t\n\t\t\tcommunity = new Community();\n\t\t\tcommunity->InitializeFromFile(infile);\n\t\t\tcommunity->InitializeRNGFromSeed(nullptr);\n\t\t\tcommunity->FinishInitialization();\n\t\t\t\n\t\t\twhile (community->_RunOneTick());\n\t\t\t\n\t\t\tgSLiMTestFailureCount++;\n\t\t\t\n\t\t\tif (p_lineNumber != -1)\n\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\n\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : no raise during SLiM execution (expected \\\"\" << p_reason_snip << \"\\\").\" << std::endl;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\t// We need to call Eidos_GetTrimmedRaiseMessage() here to empty the error stringstream, even if we don't log the error\n\t\t\tstd::string raise_message = Eidos_GetTrimmedRaiseMessage();\n\t\t\t\n\t\t\tif (raise_message.find(p_reason_snip) != std::string::npos)\n\t\t\t{\n\t\t\t\tif ((gEidosErrorContext.errorPosition.characterStartOfError == -1) ||\n\t\t\t\t\t(gEidosErrorContext.errorPosition.characterEndOfError == -1))\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\t\n\t\t\t\t\tif (p_lineNumber != -1)\n\t\t\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\t\t\n\t\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise expected, but no error info set\" << std::endl;\n\t\t\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t\t}\n\t\t\t\telse if (gEidosErrorContext.errorPosition.characterStartOfError != p_bad_position)\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\t\n\t\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise expected, but error position unexpected (\" << gEidosErrorContext.errorPosition.characterStartOfError << \")\" << std::endl;\n\t\t\t\t\tstd::cerr << p_script_string << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\t\tEidos_LogScriptError(std::cerr, gEidosErrorContext);\n\t\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\t\t\n\t\t\t\t\t//std::cerr << p_script_string << \" == (expected raise) : \" << EIDOS_OUTPUT_SUCCESS_TAG << \"\\n   \" << raise_message << endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\n\t\t\t\tif (p_lineNumber != -1)\n\t\t\t\t\tstd::cerr << \"[\" << p_lineNumber << \"] \";\n\t\t\t\t\n\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise message mismatch (expected \\\"\" << p_reason_snip << \"\\\").\" << std::endl;\n\t\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t}\n\t\t\t\n\t\t\t// Error messages that say (internal error) should not be possible to trigger in script\n\t\t\tif (raise_message.find(\"(internal error)\") != std::string::npos)\n\t\t\t{\n\t\t\t\tstd::cerr << p_script_string << \" : error message contains (internal error) erroneously\" << std::endl;\n\t\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (community)\n\t\t\tfor (Species *species : community->AllSpecies())\n\t\t\t\tspecies->DeleteAllMutationRuns();\n\t\t\n\t\tdelete community;\n\t\tInteractionType::DeleteSparseVectorFreeList();\n\t\t\n\t\tClearErrorContext();\n\t\t\n\t\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\t\tstd::cerr << \"WARNING (SLiMAssertScriptRaise): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\n\n// Test subfunction prototypes\nstatic void _RunBasicTests(void);\nstatic void _RunSLiMTimingTests(void);\n\n\n// Test function shared strings\nstd::string gen1_setup(\"initialize() { initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } \");\nstd::string gen1_setup_sex(\"initialize() { initializeSex('X'); initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } \");\nstd::string gen2_stop(\" 2 early() { stop(); } \");\nstd::string gen1_setup_highmut_p1(\"initialize() { initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } \");\nstd::string gen1_setup_fixmut_p1(\"initialize() { initializeMutationRate(1e-4); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } 10 early() { sim.mutations[0].setSelectionCoeff(500.0); sim.recalculateFitness(); } \");\nstd::string gen1_setup_i1(\"initialize() { initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', ''); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { } \");\nstd::string gen1_setup_i1x(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'x'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); } \");\nstd::string gen1_setup_i1xPx(\"initialize() { initializeSLiMOptions(dimensionality='x', periodicity='x'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'x'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); } \");\nstd::string gen1_setup_i1xy(\"initialize() { initializeSLiMOptions(dimensionality='xy'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); p1.individuals.y = runif(10); } \");\nstd::string gen1_setup_i1xyPxy(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='xy'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); p1.individuals.y = runif(10); } \");\nstd::string gen1_setup_i1xyz(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xyz'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); p1.individuals.y = runif(10); p1.individuals.z = runif(10); } \");\nstd::string gen1_setup_i1xyzPxz(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xyz'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { p1.individuals.x = runif(10); p1.individuals.y = runif(10); p1.individuals.z = runif(10); } \");\nstd::string gen1_setup_p1(gen1_setup + \"1 early() { sim.addSubpop('p1', 10); } \");\nstd::string gen1_setup_p1_100(gen1_setup + \"1 early() { sim.addSubpop('p1', 100); } \");\nstd::string gen1_setup_sex_p1(gen1_setup_sex + \"1 early() { sim.addSubpop('p1', 10); } \");\nstd::string gen1_setup_sex_p1_100(gen1_setup_sex + \"1 early() { sim.addSubpop('p1', 100); } \");\nstd::string gen1_setup_p1p2p3(gen1_setup + \"1 early() { sim.addSubpop('p1', 10); sim.addSubpop('p2', 10); sim.addSubpop('p3', 10); } \");\nstd::string gen1_setup_p1p2p3_100(gen1_setup + \"1 early() { sim.addSubpop('p1', 100); sim.addSubpop('p2', 100); sim.addSubpop('p3', 100); } \");\n\nstd::string WF_prefix(\"initialize() { initializeSLiMModelType('WF'); } \");\nstd::string nonWF_prefix(\"initialize() { initializeSLiMModelType('nonWF'); } \");\n\nstd::string pedigrees_prefix(\"initialize() { initializeSLiMOptions(keepPedigrees=T); } \");\n\n\nint RunSLiMTests(void)\n{\n\t// This function should never be called when parallel, but individual tests are allowed to go parallel internally\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"RunSLiMTests(): illegal when parallel\");\n\t\n\t// Test SLiM.  The goal here is not really to test that the core code of SLiM is working properly – that simulations\n\t// work as they are intended to.  Such testing is beyond the scope of what we can do here.  Instead, the goal here\n\t// is to test all of the Eidos-related APIs in SLiM – to make sure that all properties, methods, and functions in\n\t// SLiM's Eidos interface work properly.  SLiM itself will get a little incidental testing along the way.\n\t\n\tif (!Eidos_TemporaryDirectoryExists())\n\t\tstd::cout << \"WARNING: This system does not appear to have a writeable temporary directory.  Filesystem tests are disabled, and functions such as writeTempFile() and system() that depend upon the existence of the temporary directory will raise an exception if called (and are therefore also not tested).  Other self-tests that rely on writing temporary files, such as of readCSV() and Image, will also be disabled.  If this is surprising, contact the system administrator for details.\" << std::endl;\n\t\n\t// We want to run the self-test inside a new temporary directory, to prevent collisions with other self-test runs\n\tstd::string prefix = Eidos_TemporaryDirectory() + \"slimTest_\";\n\tstd::string temp_path_template = prefix + \"XXXXXX\";\n\tchar *temp_path_cstr = strdup(temp_path_template.c_str());\n\t\n\tif (Eidos_mkstemps_directory(temp_path_cstr, 0) == 0)\n\t{\n\t\t//std::cout << \"Running SLiM self-tests in \" << temp_path_cstr << \" ...\" << std::endl;\n\t}\n\telse\n\t{\n\t\tstd::cout << \"A folder within the temporary directory could not be created; there may be a permissions problem with the temporary directory.  The self-test could not be run.\" << std::endl;\n\t\treturn 1;\n\t}\n\t\n\tstd::string temp_path(temp_path_cstr);\t// the final random path generated by Eidos_mkstemps_directory\n\tfree(temp_path_cstr);\n\t\n\t// Reset error counts\n\tgSLiMTestSuccessCount = 0;\n\tgSLiMTestFailureCount = 0;\n\t\n\t// Run tests\n\t_RunBasicTests();\n\t_RunErrorPositionTests();\n\t_RunRelatednessTests();\n\t_RunInitTests();\n\t_RunCommunityTests();\n\t_RunSpeciesTests(temp_path);\n\t_RunMutationTypeTests();\n\t_RunGenomicElementTypeTests();\n\t_RunGenomicElementTests();\n\t_RunChromosomeTests();\n\t_RunMutationTests();\n\t_RunHaplosomeTests(temp_path);\n\t_RunSubpopulationTests();\n\t_RunIndividualTests();\n\t_RunSubstitutionTests();\n\t_RunSLiMEidosBlockTests();\n\t_RunContinuousSpaceTests();\n\t_RunSpatialMapTests();\n\t_RunNonWFTests();\n\t_RunTreeSeqTests(temp_path);\n\t_RunNucleotideFunctionTests();\n\t_RunNucleotideMethodTests();\n\t_RunPopGenFunctionTests();\n\t_RunSLiMTimingTests();\n\t\n#ifdef _OPENMP\n\t_RunParallelSLiMTests();\n#endif\n\t\n\t_RunInteractionTypeTests();\t\t// many tests, time-consuming, so do this last\n\t\n\t// ************************************************************************************\n\t//\n\t//\tPrint a summary of test results\n\t//\n\tstd::cerr << std::endl;\n\tif (gSLiMTestFailureCount)\n\t\tstd::cerr << \"\" << EIDOS_OUTPUT_FAILURE_TAG << \" count: \" << gSLiMTestFailureCount << std::endl;\n\tstd::cerr << EIDOS_OUTPUT_SUCCESS_TAG << \" count: \" << gSLiMTestSuccessCount << std::endl;\n\tstd::cerr.flush();\n\t\n\t// Clear out the SLiM output streams post-test\n\tgSLiMOut.clear();\n\tgSLiMOut.str(\"\");\n\t\n\tgSLiMError.clear();\n\tgSLiMError.str(\"\");\n\t\n#ifdef SLIMGUI\n\tgSLiMScheduling.clear();\n\tgSLiMScheduling.str(\"\");\n#endif\n\t\n\t// return a standard Unix result code indicating success (0) or failure (1);\n\treturn (gSLiMTestFailureCount > 0) ? EXIT_FAILURE : EXIT_SUCCESS;\n}\n\n#pragma mark basic tests\nvoid _RunBasicTests(void)\n{\n\t// Note that the code here uses C++11 raw string literals, which Xcode's prettyprinting and autoindent code does not\n\t// presently understand.  The line/character positions for SLiMAssertScriptRaise() depend upon the indenting that\n\t// Xcode has chosen to give the Eidos scripts below.  Be careful, therefore, not to re-indent this code!\n\t\n\t// Test that a basic script works\n\tstd::string basic_script(R\"V0G0N(\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t initialize() {\n\t\t\t\t\t\t\t\t initializeMutationRate(1e-7);\n\t\t\t\t\t\t\t\t initializeMutationType('m1', 0.5, 'f', 0.0);\n\t\t\t\t\t\t\t\t initializeGenomicElementType('g1', m1, 1.0);\n\t\t\t\t\t\t\t\t initializeGenomicElement(g1, 0, 99999);\n\t\t\t\t\t\t\t\t initializeRecombinationRate(1e-8);\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t 1 early() { sim.addSubpop('p1', 500); }\n\t\t\t\t\t\t\t 5 late() { sim.outputFull(); }\n\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t )V0G0N\");\n\t\n\tSLiMAssertScriptSuccess(basic_script);\n\t\n\t\n\t// Test that stop() raises as it is supposed to\n\tstd::string stop_test(R\"V0G0N(\n\t\t\t\t\t\t  \n\t\t\t\t\t\t  initialize() {\n\t\t\t\t\t\t\t  initializeMutationRate(1e-7);\n\t\t\t\t\t\t\t  initializeMutationType('m1', 0.5, 'f', 0.0);\n\t\t\t\t\t\t\t  initializeGenomicElementType('g1', m1, 1.0);\n\t\t\t\t\t\t\t  initializeGenomicElement(g1, 0, 99999);\n\t\t\t\t\t\t\t  initializeRecombinationRate(1e-8);\n\t\t\t\t\t\t  }\n\t\t\t\t\t\t  1 early() { sim.addSubpop('p1', 500); }\n\t\t\t\t\t\t  3 early() { stop(); }\n\t\t\t\t\t\t  5 late() { sim.outputFull(); }\n\t\t\t\t\t\t  \n\t\t\t\t\t\t  )V0G0N\");\n\t\n\tSLiMAssertScriptStop(stop_test);\n\t\n\t// Test script registration\n\tSLiMAssertScriptStop(\"initialize() { stop(); } s1 early() {}\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { stop(); } s1 early() {} s1 early() {}\", \"already defined\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { stop(); } 1: early() {}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { stop(); } :1 early() {}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { stop(); } 1:10 early() {}\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { stop(); } : early() {}\", \"unexpected token\", __LINE__);\n\t\n\t// Test top-level structure parsing; this was adding for SLiM 4 due to the multispecies revisions\n\t// If these tests do not stop for other reasons, they produce a raise due to incorrect initialization, \"At least one mutation rate interval must be defined...\"\n\tSLiMAssertScriptStop(\"initialize() {} 1 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(0.0); } 1 early() {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(0.0); } initialize() {} 1 early() {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() {} initialize() {} ticks fox 1 early() {}\", \"undeclared species\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} initialize() {} species fox 1 early() {}\", \"preceded by a species\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} initialize() {} ticks fox mutationEffect(m1) {}\", \"preceded by a ticks\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} initialize() {} species fox mutationEffect(m1) {}\", \"undeclared species\", __LINE__);\n\tSLiMAssertScriptRaise(\"species all initialize() {} species fox initialize() { initializeRecombinationRate(0.0); } ticks all 1 early() {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species all initialize() {} species fox initialize() {} 1 early() {}\", \"preceded by a ticks\", __LINE__);\n\tSLiMAssertScriptRaise(\"species all initialize() {} ticks all 1 early() { stop(); }\", \"no species-specific initialize() callback found\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species fox initialize() {} initialize() {} 1 early() {}\", \"species specifiers are required\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} species fox initialize() {} 1 early() {}\", \"species specifiers are illegal\", __LINE__);\n\tSLiMAssertScriptRaise(\"species fox initialize() {} 1 early() { stop(); }\", \"must be preceded by a ticks specifier\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} ticks all 1 early() { stop(); }\", \"ticks specifiers should not be used\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {} species all 1 early() { stop(); }\", \"may not be preceded by a species specifier\", __LINE__);\n\tSLiMAssertScriptStop(\"species mouse initialize() {} species fox initialize() {} ticks all 1 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() { initializeRecombinationRate(0.0); } ticks all 1 early() {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() {} ticks bear 1 early() {}\", \"undeclared species\", __LINE__);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() { initializeRecombinationRate(0.0); } ticks fox 1 early() {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() {} species all mutationEffect(m1) {}\", \"mutationEffect() callbacks may not be declared with 'species all'\", __LINE__);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() {} species bear mutationEffect(m1) {}\", \"undeclared species\", __LINE__);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() { initializeRecombinationRate(0.0); } species fox mutationEffect(m1) {}\", \"mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species mouse initialize() {} species fox initialize() {} mutationEffect(m1) {}\", \"must be preceded\", __LINE__);\n\tSLiMAssertScriptRaise(\"species mouse species mouse\", \"must be followed by a callback\", __LINE__);\n\tSLiMAssertScriptRaise(\"ticks mouse ticks mouse\", \"must be followed by an event\", __LINE__);\n\tSLiMAssertScriptRaise(\"foo\", \"unexpected token\", __LINE__);\t\t\t\t\t// these three now read \"foo\" as a tick range, and then hit EOF\n\tSLiMAssertScriptRaise(\"species mouse foo\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(\"ticks mouse foo\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(\"species fox function (void)foo(void) {}\", \"may not be preceded\", __LINE__);\n\tSLiMAssertScriptRaise(\"ticks fox function (void)foo(void) {}\", \"may not be preceded\", __LINE__);\n\tSLiMAssertScriptRaise(\"species fox 1 early() {}\", \"may not be preceded\", __LINE__);\n\tSLiMAssertScriptRaise(\"ticks fox 1 early() {}\", \"no initialize() callback\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"species fox mutationEffect(m1) {}\", \"no initialize() callback\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"ticks fox mutationEffect(m1) {}\", \"may not be preceded\", __LINE__);\n\t\n\t// Test no-genetics scripts; we just want to confirm that they can run without any null haplosome errors, consistency check errors, etc., especially in DEBUG\n\t// BCH 9/20/2024: removing some tests here because it is no longer legal to declare a no-genetics model to be a model of the X or Y chromosome; that makes no sense\n\tSLiMAssertScriptRaise(\"initialize() {initializeTreeSeq();} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", \"cannot use tree-sequence recording\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() {initializeSLiMOptions(nucleotideBased=T);} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", \"cannot be nucleotide-based\", __LINE__, false);\n\tSLiMAssertScriptStop(\"initialize() {} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {} 1 early() {sim.addSubpop('p1', 10); p1.setCloningRate(0.5);} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {} 1 early() {sim.addSubpop('p1', 10); p1.setSelfingRate(0.5);} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSex('A');} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSex('A');} 1 early() {sim.addSubpop('p1', 10); p1.setCloningRate(0.5);} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {initializeSex('X');} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", \"one mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() {initializeSex('Y');} 1 early() {sim.addSubpop('p1', 10);} 5 late() {stop();}\", \"one mutation rate interval\", __LINE__, false);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');} reproduction() {subpop.addCrossed(individual, subpop.sampleIndividuals(1));} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');} reproduction() {subpop.addCloned(individual);} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');} reproduction() {subpop.addSelfed(individual);} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');} reproduction() {subpop.addEmpty();} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');initializeSex('A');} reproduction(NULL,'F') {subpop.addCrossed(individual, subpop.sampleIndividuals(1,sex='M'));} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');initializeSex('A');} reproduction() {subpop.addCloned(individual);} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {initializeSLiMModelType('nonWF');initializeSex('A');} reproduction() {subpop.addEmpty();} 1 early() {sim.addSubpop('p1', 20);} early() {p1.fitnessScaling = 20 / p1.individualCount;} 5 late() {stop();}\", __LINE__);\n\t\n\t// Test \"long-term boundary\" checks; note that Eidos has more complete checks in eidos_test_functions_other.cpp,\n\t// so here we are only testing specifically that SLiM catches long-term boundary violations correctly\n\tstd::string ltb1_script(R\"V0G0N(\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tinitialize() {\n\t\t\t\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\t\t\t\tinitializeMutationType('m1', 0.5, 'f', 0.0);\n\t\t\t\t\t\t\tinitializeGenomicElementType('g1', m1, 1.0);\n\t\t\t\t\t\t\tinitializeGenomicElement(g1, 0, 99999);\n\t\t\t\t\t\t\tinitializeRecombinationRate(1e-8);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t1 early() { sim.addSubpop('p1', 500); x = Dictionary('a', p1); }\n\t\t\t\t\t\t\t5 late() { sim.outputFull(); }\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t)V0G0N\");\n\t\n\tSLiMAssertScriptSuccess(ltb1_script);\t// x is scoped, so there is no long-term reference\n\t\n\tstd::string ltb2_script(R\"V0G0N(\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tinitialize() {\n\t\t\t\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\t\t\t\tinitializeMutationType('m1', 0.5, 'f', 0.0);\n\t\t\t\t\t\t\tinitializeGenomicElementType('g1', m1, 1.0);\n\t\t\t\t\t\t\tinitializeGenomicElement(g1, 0, 99999);\n\t\t\t\t\t\t\tinitializeRecombinationRate(1e-8);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t1 early() { sim.addSubpop('p1', 500); defineGlobal('x', Dictionary('a', p1)); }\n\t\t\t\t\t\t\t5 late() { sim.outputFull(); }\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t)V0G0N\");\n\t\n\tSLiMAssertScriptRaise(ltb2_script, \"long-term reference has been kept\", 0, false);\t// x is not scoped, so there is a long-term reference\n\t\n\tstd::string ltb3_script(R\"V0G0N(\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tinitialize() {\n\t\t\t\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\t\t\t\tinitializeMutationType('m1', 0.5, 'f', 0.0);\n\t\t\t\t\t\t\tinitializeGenomicElementType('g1', m1, 1.0);\n\t\t\t\t\t\t\tinitializeGenomicElement(g1, 0, 99999);\n\t\t\t\t\t\t\tinitializeRecombinationRate(1e-8);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t1 early() { sim.addSubpop('p1', 500); sim.setValue('x', Dictionary('a', p1)); }\n\t\t\t\t\t\t\t5 late() { sim.outputFull(); }\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t)V0G0N\");\n\t\n\tSLiMAssertScriptRaise(ltb3_script, \"long-term reference has been kept\", 0, false);\t// sim.getValue('x') is not scoped, so there is a long-term reference\n\t\n\t// Test protection against conflicts and shadowing involving global constants and variables\n\tSLiMAssertScriptSuccess(\"initialize() { defineConstant('foo', 17); } 1 early() { }\");\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('if', 17); } 1 early() { }\", \"identifier 'if' is reserved\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('PI', 17); } 1 early() { }\", \"identifier 'PI' is already defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('subpop', 17); } 1 early() { }\", \"identifier 'subpop' is reserved\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(\"species foo initialize() { } ticks all 1 early() { }\");\n\tSLiMAssertScriptSuccess(\"species sim initialize() { } ticks all 1 early() { }\");\n\tSLiMAssertScriptRaise(\"species if initialize() { } ticks all 1 early() { }\", \"unexpected token '<if>' in species specifier\", __LINE__);\n\tSLiMAssertScriptRaise(\"species PI initialize() { } ticks all 1 early() { }\", \"that name is already in use\", __LINE__, /* p_expect_error_position */ false);\n\tSLiMAssertScriptRaise(\"species subpop initialize() { } ticks all 1 early() { }\", \"the symbol 'subpop' is reserved\", __LINE__, /* p_expect_error_position */ false);\n\tSLiMAssertScriptRaise(\"species all initialize() { defineConstant('foo', 17); } species foo initialize() { } ticks all 1 early() { }\", \"that name is already in use\", __LINE__, /* p_expect_error_position */ false);\n\tSLiMAssertScriptRaise(\"species all initialize() { defineConstant('sim', 17); } species sim initialize() { } ticks all 1 early() { }\", \"identifier 'sim' is reserved\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(\"initialize() { initializeSLiMOptions(dimensionality='xy'); } 1 late() { sim.addSubpop('p1', 100); p1.individuals.setSpatialPosition(p1.pointUniform(100)); } late() { summarizeIndividuals(p1.individuals, c(10, 10), p1.spatialBounds, operation='individuals.size();', empty=0.0, perUnitArea=T); }\");\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xy'); defineConstant('individuals', 17); } 1 late() { sim.addSubpop('p1', 100); p1.individuals.setSpatialPosition(p1.pointUniform(100)); } late() { summarizeIndividuals(p1.individuals, c(10, 10), p1.spatialBounds, operation='individuals.size();', empty=0.0, perUnitArea=T); }\", \"can't set up a local variable named 'individuals'\", __LINE__);\n}\n\n#pragma mark error position tracking\nvoid _RunErrorPositionTests(void)\n{\n\t// test that errors are correctly located within the user's script (or their own script)\n\t// error tracking is very complicated (at least with the faulty design we have right now),\n\t// and so one of the tests here is known to fail and is commented out until things improve\n\t// note that the tests here are also in the folder \"error tracking tests\" in my tests folder\n\t\n\t// 1_early.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 36, \"undefined identifier foo\", __LINE__);\n\t\n\t// 2_modifyChild.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 500);\n\t\t}\n\t\tmodifyChild() {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 87, \"undefined identifier foo\", __LINE__);\n\t\n\t// 3_userDef_function.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tfn1();\n\t\t}\n\t\tfunction (void)fn1(void) {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 79, \"undefined identifier foo\", __LINE__);\n\t\n\t// 4_userDef_function_nested.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tfn1();\n\t\t}\n\t\tfunction (void)fn1(void) {\n\t\t\tfn2();\n\t\t}\n\t\tfunction (void)fn2(void) {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 122, \"undefined identifier foo\", __LINE__);\n\t\n\t// 5_lambda.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\texecuteLambda(\"foo;\");\n\t\t}\n\t)V0G0N\", 36, \"undefined identifier foo\", __LINE__);\n\t\n\t// 6_lambda_nested.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tfn1();\n\t\t}\n\t\tfunction (void)fn1(void) {\n\t\t\tfn2();\n\t\t}\n\t\tfunction (void)fn2(void) {\n\t\t\texecuteLambda(\"foo;\");\n\t\t}\n\t)V0G0N\", 122, \"undefined identifier foo\", __LINE__);\n\t\n\t// 7_tokenize_error.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\t$\n\t\t}\n\t)V0G0N\", 36, \"unexpected token '$'\", __LINE__);\n\t\n\t// 8_parse_error.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\t1 + ;\n\t\t}\n\t)V0G0N\", 40, \"unexpected token ';'\", __LINE__);\n\t\n\t// 9_triggered_callback.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 500);\n\t\t\tsim.recalculateFitness();\n\t\t}\n\t\tfitnessEffect() {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 118, \"undefined identifier foo\", __LINE__);\n\t\n\t// 10_triggered_callback_nested.slim\n\t\n\t// The error position is wrong for this test, for reasons that are well understood.\n\t// The error context is foo() when the error is raised,because callbacks don't set\n\t// up their own error context information, but rather rely on the assumption that\n\t// they are executed in the user script context (which is almost always true).\n\t// The error position is in the fitnessEffect() callback's coordinates, which are\n\t// user script coordinates, but the context is set to foo(), so the error position\n\t// gets translated to user space using the wrong offset.  I don't see an easy way\n\t// to fix this, or even to catch that it has happened.  BCH 3/12/2025\n\t\n\t/*SLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 500);\n\t\t\tfoo();\n\t\t}\n\t\tfunction (void)foo(void) {\n\t\t\tsim.recalculateFitness();\n\t\t}\n\t\tfitnessEffect() {\n\t\t\tfoo;\n\t\t}\n\t)V0G0N\", 118, \"undefined identifier foo\", __LINE__);*/\n\t\n\t// 11_userDef_lambda.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 500);\n\t\t\texecuteLambda(\"foo();\");\n\t\t}\n\t\tfunction (void)foo(void) {\n\t\t\tbar;\n\t\t}\n\t)V0G0N\", 126, \"undefined identifier bar\", __LINE__);\n\t\n\t// 12_builtin_function.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsum(\"a\");\n\t\t}\n\t)V0G0N\", 36, \"cannot be type string\", __LINE__);\n\t\n\t// 13_sapply_userDef_function.slim\n\tSLiMAssertScriptRaisePosition(R\"V0G0N(\n\t\tinitialize() {}\n\t\t1 early() {\n\t\t\tsapply(1:10, \"foo(applyValue);\");\n\t\t}\n\t\tfunction (void)foo(integer$ x) {\n\t\t\tbar;\n\t\t}\n\t)V0G0N\", 112, \"undefined identifier bar\", __LINE__);\n\t\n\t// there is a #14 and #15 in \"error tracking tests\", but they check that Unicode characters don't throw off\n\t// the error range, and I don't want to deal with putting them here because Unicode.\n}\n\n#pragma mark Individual relatedness tests\nvoid _RunRelatednessTests(void)\n{\n\t// This function tests the relatedness() function of Individual.  This can't be done easily in script, since setting up an exact pedigree\n\t// in a SLiM model is kind of a pain, and we want to test a bunch of different pedigrees here; it would just be too complex.  So we test\n\t// the internal API of the Individual class here instead, and verify that it produces the correct values; relatedness() uses that.\n\t\n\ttypedef struct pedigree_test_info_ {\n\t\tslim_pedigreeid_t A;\n\t\tslim_pedigreeid_t A_P1;\n\t\tslim_pedigreeid_t A_P2;\n\t\tslim_pedigreeid_t A_G1;\n\t\tslim_pedigreeid_t A_G2;\n\t\tslim_pedigreeid_t A_G3;\n\t\tslim_pedigreeid_t A_G4;\n\t\tslim_pedigreeid_t B;\n\t\tslim_pedigreeid_t B_P1;\n\t\tslim_pedigreeid_t B_P2;\n\t\tslim_pedigreeid_t B_G1;\n\t\tslim_pedigreeid_t B_G2;\n\t\tslim_pedigreeid_t B_G3;\n\t\tslim_pedigreeid_t B_G4;\n\t\tIndividualSex A_sex;\n\t\tIndividualSex B_sex;\n\t\tChromosomeType type;\n\t\tdouble expectedRelatedness;\n\t} pedigree_test_info;\n\t\n\tpedigree_test_info test_pedigrees[] = {\n\t\t// two individuals that are completely unrelated\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 12, 13, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// completely unrelated individuals with missing information\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ -1, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ -1, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ -1, -1, -1, -1, -1, -1, -1, /* B */ -1, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 8, 9, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.0},\n\t\t\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, -1, -1, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// the exact same individual\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 0, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 1.0},\n\t\t\n\t\t// products of cloning/selfing\n\t\t{/* A */ 0, 1, 1, 3, 4, 3, 4, /* B */ 0, 1, 1, 3, 4, 3, 4, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 1, 3, 4, 3, 4, /* B */ 7, 1, 1, 3, 4, 3, 4, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 1, 2, 2, 2, 2, /* B */ 0, 1, 1, 2, 2, 2, 2, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 1, 2, 2, 2, 2, /* B */ 7, 1, 1, 2, 2, 2, 2, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 1, 2, 2, 2, 2, /* B */ 1, 2, 2, 3, 3, 3, 3, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 1, 2, 2, 2, 2, /* B */ 2, 3, 3, 4, 4, 4, 4, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 1.0},\n\t\t\n\t\t// siblings\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 2, 3, 4, 5, 6, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// siblings with missing information\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, -1, -1, -1, -1, /* B */ 7, 1, 2, -1, -1, -1, -1, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// parent-child (hermaphroditic)\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, 0, 8, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, -1, -1, -1, -1, -1, -1, /* B */ 7, 8, 0, -1, -1, -1, -1, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t\n\t\t// mother-daughter\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// mother-son\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 1.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 0, 8, 1, 2, 9, 10, /* other */ IndividualSex::kFemale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// father-daughter\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kFemale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 0.0},\n\t\t\n\t\t// father-son\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.5},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.0},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 0, 9, 10, 1, 2, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kNullY_YSexChromosomeWithNull, /*expected */ 1.0},\n\t\t\n\t\t// half-siblings (hermaphroditic)\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 1, 8, 3, 4, 9, 10, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 2, 8, 5, 6, 9, 10, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 1, 9, 10, 3, 4, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 2, 9, 10, 5, 6, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t\n\t\t// cousins (hermaphroditic)\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 3, 4, 10, 11, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.125},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 3, 4, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.125},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 5, 6, 10, 11, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.125},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 10, 11, 5, 6, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.125},\n\t\t\n\t\t// grandchild-grandparent (hermaphroditic)\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 3, 7, 8, 9, 10, 11, 12, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 4, 7, 8, 9, 10, 11, 12, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 5, 7, 8, 9, 10, 11, 12, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 6, 7, 8, 9, 10, 11, 12, /* other */ IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, /*expected */ 0.25},\n\t\t\n\t\t// random spot-checks; obviously there is a huge variety of set-ups we could check...\n\t\t// male cousins sharing both of their maternal grandparents, modeling the X:\n\t\t{/* A */ 0, 1, 2, 3, 4, 5, 6, /* B */ 7, 8, 9, 3, 4, 10, 11, /* other */ IndividualSex::kMale, IndividualSex::kMale, ChromosomeType::kX_XSexChromosome, /*expected */ 0.5},\n\t\t\n\t\t/* end-of-array marker entry : DO NOT TOUCH */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, IndividualSex::kHermaphrodite, IndividualSex::kHermaphrodite, ChromosomeType::kA_DiploidAutosome, -1.0}\n\t};\n\t\n\t{\n\t\tpedigree_test_info *p = test_pedigrees;\n\t\t\n\t\tfor ( ; p->expectedRelatedness > -1.0; ++p)\n\t\t{\n\t\t\ttry {\n\t\t\t\tdouble rel = Individual::_Relatedness(p->A, p->A_P1, p->A_P2, p->A_G1, p->A_G2, p->A_G3, p->A_G4, p->B, p->B_P1, p->B_P2, p->B_G1, p->B_G2, p->B_G3, p->B_G4, p->A_sex, p->B_sex, p->type);\n\t\t\t\tdouble expected = p->expectedRelatedness;\n\t\t\t\t\n\t\t\t\tif (rel == expected)\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\t\t\n\t\t\t\t\t//std::cerr << \"relatedness test \" << EIDOS_OUTPUT_SUCCESS_TAG << \": test index \" << (p - test_pedigrees) << \" produced a relatedness of \" << rel << \" (as expected)\" << std::endl;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\t\n\t\t\t\t\tstd::cerr << \"relatedness test \" << EIDOS_OUTPUT_FAILURE_TAG << \": test index \" << (p - test_pedigrees) << \" produced a relatedness of \" << rel << \" (\" << expected << \" expected)\" << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tstd::cerr << \"relatedness test \" << EIDOS_OUTPUT_FAILURE_TAG << \": test index \" << (p - test_pedigrees) << \" raised an exception: \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// this output is useful for figuring out which entry is causing a problem, when it is located near the end\n\t//std::cerr << \"end-of-array index == \" << (p - test_pedigrees) << std::endl;\n\t\n\t// Run tests of SharedParentCount() as well, which is much simpler\n\ttypedef struct sharedparent_test_info_ {\n\t\tslim_pedigreeid_t X_P1;\n\t\tslim_pedigreeid_t X_P2;\n\t\tslim_pedigreeid_t Y_P1;\n\t\tslim_pedigreeid_t Y_P2;\n\t\tint expectedCount;\n\t} sharedparent_test_info;\n\t\n\tsharedparent_test_info test_sharedparent[] = {\n\t\t{/* X */ -1, -1, /* Y */ -1, -1, /*expected */ 0},\t\t// missing information\n\t\t{/* X */ 0, 1, /* Y */ 2, 3, /*expected */ 0},\n\t\t{/* X */ 0, 1, /* Y */ 2, 2, /*expected */ 0},\n\t\t{/* X */ 0, 1, /* Y */ 0, 2, /*expected */ 1},\n\t\t{/* X */ 0, 1, /* Y */ 0, 0, /*expected */ 1},\n\t\t{/* X */ 0, 0, /* Y */ 0, 1, /*expected */ 1},\n\t\t{/* X */ 0, 1, /* Y */ 0, 1, /*expected */ 2},\n\t\t{/* X */ 0, 1, /* Y */ 1, 0, /*expected */ 2},\n\t\t{/* X */ 0, 0, /* Y */ 0, 0, /*expected */ 2},\n\t\t/* end-of-array marker entry : DO NOT TOUCH */ {-1, -1, -1, -1, -1}\n\t};\n\t\n\t{\n\t\tsharedparent_test_info *p = test_sharedparent;\n\t\t\n\t\tfor ( ; p->expectedCount > -1; ++p)\n\t\t{\n\t\t\ttry {\n\t\t\t\tint count = Individual::_SharedParentCount(p->X_P1, p->X_P2, p->Y_P1, p->Y_P2);\n\t\t\t\tint expected = p->expectedCount;\n\t\t\t\t\n\t\t\t\tif (count == expected)\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestSuccessCount++;\n\t\t\t\t\t\n\t\t\t\t\t//std::cerr << \"sharedParentCount test \" << EIDOS_OUTPUT_SUCCESS_TAG << \": test index \" << (p - test_sharedparent) << \" produced a count of \" << count << \" (as expected)\" << std::endl;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tgSLiMTestFailureCount++;\n\t\t\t\t\t\n\t\t\t\t\tstd::cerr << \"sharedParentCount test \" << EIDOS_OUTPUT_FAILURE_TAG << \": test index \" << (p - test_sharedparent) << \" produced a count of \" << count << \" (\" << expected << \" expected)\" << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tstd::cerr << \"sharedParentCount test \" << EIDOS_OUTPUT_FAILURE_TAG << \": test index \" << (p - test_sharedparent) << \" raised an exception: \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#pragma mark SLiM timing tests\nvoid _RunSLiMTimingTests(void)\n{\n#if 0\n\t// Speed comparison of different signature lookup methods\n\t// the conclusion is that std::unordered_map is faster than std::map or the old switch()-based scheme\n\t{\n\t\tEidosGlobalStringID haplosome_properties[4] = {gID_haplosomeType, gID_isNullHaplosome, gID_mutations, gID_tag};\n\t\tstd::map<EidosGlobalStringID, const EidosPropertySignature *> haplosome_map;\n\t\tstd::unordered_map<EidosGlobalStringID, const EidosPropertySignature *> haplosome_unordered_map;\n\t\t\n\t\tfor (int i = 0; i < 4; ++i)\n\t\t\thaplosome_map.emplace(haplosome_properties[i], gSLiM_Haplosome_Class->_SignatureForProperty(haplosome_properties[i]));\n\t\t\n\t\tfor (int i = 0; i < 4; ++i)\n\t\t\thaplosome_unordered_map.emplace(haplosome_properties[i], gSLiM_Haplosome_Class->_SignatureForProperty(haplosome_properties[i]));\n\t\t\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = haplosome_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 4)];\n\t\t\t\t\n\t\t\t\ttotal += (int64_t)(gSLiM_Haplosome_Class->_SignatureForProperty(property_id));\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for Haplosome_Class::_SignatureForProperty() calls: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = haplosome_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 4)];\n\t\t\t\t\n\t\t\t\tauto found_iter = haplosome_map.find(property_id);\n\t\t\t\tif (found_iter != haplosome_map.end())\n\t\t\t\t{\n\t\t\t\t\tconst EidosPropertySignature *sig = found_iter->second;\n\t\t\t\t\ttotal += (int64_t)sig;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for haplosome_map calls: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = haplosome_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 4)];\n\t\t\t\t\n\t\t\t\tauto found_iter = haplosome_unordered_map.find(property_id);\n\t\t\t\tif (found_iter != haplosome_unordered_map.end())\n\t\t\t\t{\n\t\t\t\t\tconst EidosPropertySignature *sig = found_iter->second;\n\t\t\t\t\ttotal += (int64_t)sig;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for haplosome_unordered_map calls: \" << time_spent << std::endl << std::endl;\n\t\t}\n\t}\n\t\n\t{\n\t\tEidosGlobalStringID individual_properties[17] = {gID_subpopulation, gID_index, gID_haplosomes, gID_sex, gID_tag, gID_tagF, gID_fitnessScaling, gEidosID_x, gEidosID_y, gEidosID_z, gID_age, gID_pedigreeID, gID_pedigreeParentIDs, gID_pedigreeGrandparentIDs, gID_spatialPosition, gID_uniqueMutations, gEidosID_color};\n\t\tstd::map<EidosGlobalStringID, const EidosPropertySignature *> individual_map;\n\t\tstd::unordered_map<EidosGlobalStringID, const EidosPropertySignature *> individual_unordered_map;\n\t\t\n\t\tfor (int i = 0; i < 17; ++i)\n\t\t\tindividual_map.emplace(individual_properties[i], gSLiM_Individual_Class->_SignatureForProperty(individual_properties[i]));\n\t\t\n\t\tfor (int i = 0; i < 17; ++i)\n\t\t\tindividual_unordered_map.emplace(individual_properties[i], gSLiM_Individual_Class->_SignatureForProperty(individual_properties[i]));\n\t\t\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = individual_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 17)];\n\t\t\t\t\n\t\t\t\ttotal += (int64_t)(gSLiM_Individual_Class->_SignatureForProperty(property_id));\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for Individual_Class::_SignatureForProperty() calls: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = individual_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 17)];\n\t\t\t\t\n\t\t\t\tauto found_iter = individual_map.find(property_id);\n\t\t\t\tif (found_iter != individual_map.end())\n\t\t\t\t{\n\t\t\t\t\tconst EidosPropertySignature *sig = found_iter->second;\n\t\t\t\t\ttotal += (int64_t)sig;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for individual_map calls: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 100000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_id = individual_properties[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 17)];\n\t\t\t\t\n\t\t\t\tauto found_iter = individual_unordered_map.find(property_id);\n\t\t\t\tif (found_iter != individual_unordered_map.end())\n\t\t\t\t{\n\t\t\t\t\tconst EidosPropertySignature *sig = found_iter->second;\n\t\t\t\t\ttotal += (int64_t)sig;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for individual_unordered_map calls: \" << time_spent << std::endl << std::endl;\n\t\t}\n\t}\n#endif\n\t\n#if 0\n\t// Speed comparison between internal and internal symbols for EidosSymbolTable, for ContainsSymbol() checks\n\t// the conclusion is that an external table is significantly faster for failed checks (as when we have to\n\t// check the intrinsic symbols table for a name conflict before defining a new symbols), slightly faster for\n\t// successful checks (as when a random intrinsic symbol is used), but significantly slower for successful\n\t// checks against early symbols in the table (T and F, which are very commonly used).  We cache EidosValues\n\t// for the intrinsic constants in the tree during optimization, so the successful-lookup cases should not be\n\t// important; the failed-check case should be what matters.  Nevertheless, puzzingly, testing indicates that\n\t// switching the intrinsic constants table to use the external hash table hurts performance.  I'm not sure\n\t// why that is, but I have decided not to do that since it does not seem to be a win despite the results here.\n\t{\n\t\tEidosGlobalStringID symbol_ids[7] = {gEidosID_T, gEidosID_F, gEidosID_NULL, gEidosID_PI, gEidosID_E, gEidosID_INF, gEidosID_NAN};\n\t\tEidosSymbolTable internalTable(EidosSymbolTableType::kEidosIntrinsicConstantsTable, nullptr, false);\n\t\tEidosSymbolTable externalTable(EidosSymbolTableType::kEidosIntrinsicConstantsTable, nullptr, true);\n\t\t\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tbool contains_symbol = internalTable.ContainsSymbol(gEidosID_F);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for internalTable (F) checks: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tbool contains_symbol = externalTable.ContainsSymbol(gEidosID_F);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for externalTable (F) checks: \" << time_spent << std::endl << std::endl;\n\t\t}\n\t\t\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID variable_id = symbol_ids[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 7)];\n\t\t\t\t\n\t\t\t\tbool contains_symbol = internalTable.ContainsSymbol(variable_id);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for internalTable successful checks: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID variable_id = symbol_ids[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 7)];\n\t\t\t\t\n\t\t\t\tbool contains_symbol = externalTable.ContainsSymbol(variable_id);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for externalTable successful checks: \" << time_spent << std::endl << std::endl;\n\t\t}\n\t\t\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tbool contains_symbol = internalTable.ContainsSymbol(gEidosID_applyValue);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for internalTable failed checks: \" << time_spent << std::endl;\n\t\t}\n\t\t{\n\t\t\tstd::clock_t begin = std::clock();\n\t\t\tint64_t total = 0;\n\t\t\t\n\t\t\tfor (int64_t i = 0; i < 1000000000; i++)\n\t\t\t{\n\t\t\t\tbool contains_symbol = externalTable.ContainsSymbol(gEidosID_applyValue);\n\t\t\t\t\n\t\t\t\ttotal += (contains_symbol ? 1 : 2);\n\t\t\t}\n\t\t\t\n\t\t\tstd::clock_t end = std::clock();\n\t\t\tdouble time_spent = static_cast<double>(end - begin) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"Time for externalTable failed checks: \" << time_spent << std::endl << std::endl;\n\t\t}\n\t}\n#endif\n}\n\n#pragma mark SLiM timing tests\nextern void _RunParallelSLiMTests()\n{\n\t// Tests of parallelization of SLiM functions/methods/core code; see also eidos_test_parallel.h\n#ifdef _OPENMP\n\tconst std::string &parallelization_test_string =\n#include \"slim_test_parallel.h\"\n\t;\n\t{\n\t\tstd::vector<std::string> test_strings = Eidos_string_split(parallelization_test_string, \"// ***********************************************************************************************\");\n\t\t\n\t\t//for (int testidx = 0; testidx < 100; testidx++)\t// uncomment this for a more thorough stress test\n\t\t{\n\t\t\tfor (std::string &test_string : test_strings)\n\t\t\t{\n\t\t\t\t// Skip empty tests\n\t\t\t\tif (test_string.find(\"initialize()\") == std::string::npos)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t//std::chrono::steady_clock::time_point begin_ts = std::chrono::steady_clock::now();\n\t\t\t\t\n\t\t\t\t// Note that we ensure that we are using the maximum number of threads at start & end\n\t\t\t\t{\n\t\t\t\t\tgEidosNumThreads = gEidosMaxThreads;\n\t\t\t\t\tgEidosNumThreadsOverride = false;\n\t\t\t\t\tomp_set_num_threads(gEidosMaxThreads);\n\t\t\t\t\t\n\t\t\t\t\tSLiMAssertScriptSuccess(test_string);\n\t\t\t\t\t\n\t\t\t\t\tgEidosNumThreads = gEidosMaxThreads;\n\t\t\t\t\tgEidosNumThreadsOverride = false;\n\t\t\t\t\tomp_set_num_threads(gEidosMaxThreads);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t//std::chrono::steady_clock::time_point end_ts = std::chrono::steady_clock::now();\n\t\t\t\t//std::cout << \"parallel test took \" << std::chrono::duration<double>(end_ts - begin_ts).count() << \" seconds:\" << std::endl << test_string << std::endl << std::endl;\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test.h",
    "content": "//\n//  slim_test.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/14/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef __SLiM__slim_test__\n#define __SLiM__slim_test__\n\n#include <stdio.h>\n#include <string>\n\n\nint RunSLiMTests(void);\n\n\n// Helper functions for testing\nextern void SLiMAssertScriptSuccess(const std::string &p_script_string, int p_lineNumber = -1);\nextern void SLiMAssertScriptRaise(const std::string &p_script_string, const std::string &p_reason_snip, int p_lineNumber, bool p_expect_error_position = true, bool p_error_is_in_stop = false);\nextern void SLiMAssertScriptStop(const std::string &p_script_string, int p_lineNumber = -1);\n\nextern void SLiMAssertScriptRaisePosition(const std::string &p_script_string, const int p_bad_position, const char *p_reason_snip, int p_lineNumber);\n\n\n// Conceptually, all the slim_test_X.cpp stuff is a single source file, and all the details below are private.\n// It is split into multiple files to improve compile performance; the single source file took almost a minute to compile\n\n\n// Defined in various slim_test_X.cpp files\nextern void _RunInitTests(void);\nextern void _RunCommunityTests(void);\nextern void _RunSpeciesTests(const std::string &temp_path);\nextern void _RunMutationTypeTests(void);\nextern void _RunGenomicElementTypeTests(void);\nextern void _RunGenomicElementTests(void);\nextern void _RunChromosomeTests(void);\nextern void _RunMutationTests(void);\nextern void _RunHaplosomeTests(const std::string &temp_path);\nextern void _RunSubpopulationTests(void);\nextern void _RunIndividualTests(void);\nextern void _RunErrorPositionTests(void);\nextern void _RunRelatednessTests(void);\nextern void _RunInteractionTypeTests(void);\nextern void _RunSubstitutionTests(void);\nextern void _RunSLiMEidosBlockTests(void);\nextern void _RunContinuousSpaceTests(void);\nextern void _RunSpatialMapTests(void);\nextern void _RunNonWFTests(void);\nextern void _RunTreeSeqTests(const std::string &temp_path);\nextern void _RunNucleotideFunctionTests(void);\nextern void _RunNucleotideMethodTests(void);\nextern void _RunPopGenFunctionTests(void);\nextern void _RunParallelSLiMTests();\n\n// Test function shared strings\nextern std::string gen1_setup;\nextern std::string gen1_setup_sex;\nextern std::string gen2_stop;\nextern std::string gen1_setup_highmut_p1;\nextern std::string gen1_setup_fixmut_p1;\nextern std::string gen1_setup_i1;\nextern std::string gen1_setup_i1x;\nextern std::string gen1_setup_i1xPx;\nextern std::string gen1_setup_i1xy;\nextern std::string gen1_setup_i1xyPxy;\nextern std::string gen1_setup_i1xyz;\nextern std::string gen1_setup_i1xyzPxz;\nextern std::string gen1_setup_p1;\nextern std::string gen1_setup_p1_100;\nextern std::string gen1_setup_sex_p1;\nextern std::string gen1_setup_sex_p1_100;\nextern std::string gen1_setup_p1p2p3;\nextern std::string gen1_setup_p1p2p3_100;\nextern std::string WF_prefix;\nextern std::string nonWF_prefix;\nextern std::string pedigrees_prefix;\n\n\n#endif /* defined(__SLiM__slim_test__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test_core.cpp",
    "content": "//\n//  slim_test_core.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_test.h\"\n\n#include \"eidos_globals.h\"\n\n#include <string>\n\n\n#pragma mark initialize() tests\nvoid _RunInitTests(void)\n{\t\n\t// ************************************************************************************\n\t//\n\t//\tInitialization function tests\n\t//\n\t\n\t// Test (void)initializeGeneConversion(numeric$ conversionFraction, numeric$ meanLength)\n\tSLiMAssertScriptStop(\"initialize() { initializeGeneConversion(0.5, 10000000000000, 0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal; no max for meanLength\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(-0.001, 10000000000000, 0.0); stop(); }\", \"nonCrossoverFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(1.001, 10000000000000, 0.0); stop(); }\", \"nonCrossoverFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, -0.01, 0.0); stop(); }\", \"meanLength must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, 1000, -0.001); stop(); }\", \"simpleConversionFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, 1000, 1.001); stop(); }\", \"simpleConversionFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, 1000, 0.0, -1.001); stop(); }\", \"bias must be between -1.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, 1000, 0.0, 1.001); stop(); }\", \"bias must be between -1.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeGeneConversion(0.5, 1000, 0.0, 0.1); stop(); }\", \"must be 0.0 in non-nucleotide-based models\", __LINE__);\n\t\n\t// Test (object<MutationType>$)initializeMutationType(is$ id, numeric$ dominanceCoeff, string$ distributionType, ...)\n\tSLiMAssertScriptStop(\"initialize() { initializeMutationType('m1', 0.5, 'f', 0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeMutationType(1, 0.5, 'f', 0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType(-1, 0.5, 'f', 0.0); stop(); }\", \"identifier value is out of range\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('p2', 0.5, 'f', 0.0); stop(); }\", \"identifier prefix 'm' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('mm1', 0.5, 'f', 0.0); stop(); }\", \"must be a simple integer\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f'); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f', 0.0, 0.0); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'e', 0.0, 0.0); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'e', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'e', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'x', 0.0); stop(); }\", \"must be 'f', 'g', 'e', 'n', 'w', or 's'\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { x = initializeMutationType('m7', 0.5, 'f', 0.0); if (x == m7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { x = initializeMutationType(7, 0.5, 'f', 0.0); if (x == m7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { m7 = 15; initializeMutationType(7, 0.5, 'f', 0.0); stop(); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f', 0.0); initializeMutationType('m1', 0.5, 'f', 0.0); stop(); }\", \"already defined\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 3.1, 0.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'g', 3.1, -1.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'n', 3.1, -1.0); stop(); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 3.1, 0.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'p', 3.1, -1.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 0.0, 7.5); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', -1.0, 7.5); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 3.1, 0.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'w', 3.1, -7.5); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\t\n\t// Test (object<GenomicElementType>$)initializeGenomicElementType(is$ id, io<MutationType> mutationTypes, numeric proportions)\n\tstd::string define_m12(\" initializeMutationType('m1', 0.5, 'f', 0.0); initializeMutationType('m2', 0.5, 'f', 0.5); \");\n\t\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', object(), integer(0)); stop(); }\", __LINE__);\t\t\t// legal: genomic element with no mutations\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', integer(0), float(0)); stop(); }\", __LINE__);\t\t\t// legal: genomic element with no mutations\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2), c(0,0)); stop(); }\", __LINE__);\t\t\t\t// legal: genomic element with all zero proportions (must be fixed later...)\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2), 1:2); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType(1, c(m1,m2), 1:2); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', 1:2, 1:2); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2)); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2), 1); stop(); }\", \"requires the sizes\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2), c(-1,2)); stop(); }\", \"must be greater than or equal to zero\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', 2:3, 1:2); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(2,2), 1:2); stop(); }\", \"used more than once\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"x = initializeGenomicElementType('g7', c(m1,m2), 1:2); if (x == g7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_m12 + \"x = initializeGenomicElementType(7, c(m1,m2), 1:2); if (x == g7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"g7 = 17; initializeGenomicElementType(7, c(m1,m2), 1:2); stop(); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_m12 + \"initializeGenomicElementType('g1', c(m1,m2), 1:2); initializeGenomicElementType('g1', c(m1,m2), c(0,0)); stop(); }\", \"already defined\", __LINE__);\n\t\n\t// Test (void)initializeGenomicElement(io<GenomicElementType>$ genomicElementType, integer$ start, integer$ end)\n\tstd::string define_g1(define_m12 + \" initializeGenomicElementType('g1', c(m1,m2), 1:2); \");\n\t\n\tSLiMAssertScriptStop(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 0, 1000000000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_g1 + \"initializeGenomicElement(1, 0, 1000000000); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 0); stop(); }\", \"cannot be NULL separately\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(2, 0, 1000000000); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, -1, 1000000000); stop(); }\", \"out of range\", __LINE__);\n\t//SLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 0, 1000000001); stop(); }\", \"out of range\", __LINE__);\t\t// now legal!\n\tSLiMAssertScriptStop(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 0, 1000000000000000); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 0, 1000000000000001); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeGenomicElement(g1, 100, 99); stop(); }\", \"is less than start position\", __LINE__);\n\t\n\t// Test (void)initializeMutationRate(numeric$ rate)\n\tSLiMAssertScriptStop(\"initialize() { initializeMutationRate(0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationRate(-0.0000001); stop(); }\", \"requires rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationRate(10000000); stop(); }\", \"requires rates to be\", __LINE__);\t// no longer legal, in SLiM 3.5\n\t\n\t// Test (void)initializeRecombinationRate(numeric rates, [integer ends])\n\tSLiMAssertScriptStop(\"initialize() { initializeRecombinationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(-0.00001); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeRecombinationRate(0.5); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(0.6); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(10000); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, 0.1)); stop(); }\", \"requires rates to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(integer(0), integer(0)); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, 0.1), 1000); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, 0.1), 1:3); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, 0.1), c(2000, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, 0.1), c(1000, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeRecombinationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeRecombinationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(-0.00001); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeRecombinationRate(0.5); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(0.6); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(10000); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1)); stop(); }\", \"requires rates to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(integer(0), integer(0)); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1000); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1:3); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(2000, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(integer(0), integer(0), '*'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1000, '*'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1:3, '*'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(2000, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(integer(0), integer(0), 'M'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1000, 'M'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), 1:3, 'M'); stop(); }\", \"ends and rates to be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(2000, 1000), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 1000), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeRecombinationRate(c(0.0, -0.001), c(1000, 2000), 'M'); stop(); }\", \"requires rates to be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 2000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 2000, 'F'); stop(); } 1 early() {}\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 3000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 2000, 'F'); } 1 early() {}\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptStop(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 1000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 2000, 'F'); } 1 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 2000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 1999, 'F'); } 1 early() {}\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 2000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 2001, 'F'); } 1 early() { stop(); }\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 2000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), 'M'); initializeRecombinationRate(0.0, 2000, '*'); } 1 early() {}\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() {\" + define_g1 + \"initializeMutationRate(0.0); initializeGenomicElement(g1, 0, 2000); initializeSex('A'); initializeRecombinationRate(c(0.0, 0.1), c(1000, 2000), '*'); initializeRecombinationRate(0.0, 2000, 'F'); } 1 early() {}\", \"single map versus separate maps\", __LINE__);\n\t\n\t// Test (void)initializeSex(string$ chromosomeType)\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('X'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('Y'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('Z'); stop(); }\", \"requires a chromosomeType of\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSex('A'); initializeSex('A'); stop(); }\", \"may be called only once\", __LINE__);\n\t\n\t// Test (void)initializeSLiMModelType(string$ modelType)\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMModelType(); stop(); }\", \"missing required argument 'modelType'\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMModelType('WF'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMModelType('nonWF'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMModelType('foo'); stop(); }\", \"legal values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(); initializeSLiMModelType('WF'); stop(); }\", \"must be called before\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationRate(0.0); initializeSLiMModelType('WF'); stop(); }\", \"must be called before\", __LINE__);\n\t\n\t// Test (void)initializeSLiMOptions([logical$ keepPedigrees = F], [string$ dimensionality = \"\"], [string$ periodicity = \"\"], [integer$ mutationRuns = 0], [logical$ preventIncidentalSelfing = F])\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(F, ''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(T, ''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(F, 'xyz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(T, 'xyz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality=''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xy'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='', periodicity=''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x', periodicity=''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x', periodicity='x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity=''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='y'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='xy'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity=''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='y'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='z'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xy'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='yz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xyz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(preventIncidentalSelfing=F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(preventIncidentalSelfing=T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(keepPedigrees=NULL); stop(); }\", \"cannot be type NULL\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality=NULL); stop(); }\", \"cannot be type NULL\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(preventIncidentalSelfing=NULL); stop(); }\", \"cannot be type NULL\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='foo'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='y'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='z'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xz'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='yz'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='zyx'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='', periodicity='x'); stop(); }\", \"may not be set in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x', periodicity='y'); stop(); }\", \"cannot utilize spatial dimensions beyond\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x', periodicity='z'); stop(); }\", \"cannot utilize spatial dimensions beyond\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='z'); stop(); }\", \"cannot utilize spatial dimensions beyond\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='foo'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xzy'); stop(); }\", \"legal non-empty values\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(); initializeSLiMOptions(); stop(); }\", \"may be called only once\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationRate(0.0); initializeSLiMOptions(); stop(); }\", \"must be called before\", __LINE__);\n\t\n\t// Test (object<InteractionType>$)initializeInteractionType(is$ id, string$ spatiality, [logical$ reciprocal = F], [numeric$ maxDistance = INF], [string$ sexSegregation = \"**\"])\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(-1, ''); stop(); }\", \"identifier value is out of range\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeInteractionType(0, ''); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeInteractionType('i0', ''); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, 'x'); stop(); }\", \"spatial dimensions beyond those set\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType('i0', 'x'); stop(); }\", \"spatial dimensions beyond those set\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, 'w'); stop(); }\", \"spatiality 'w' must be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType('i0', 'w'); stop(); }\", \"spatiality 'w' must be\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeInteractionType(0, '', T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, '', T, 0.1); stop(); }\", \"must be INF for non-spatial interactions\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeInteractionType(0, '', T, INF, '**'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, '', T, INF, '*M'); stop(); }\", \"unsupported in non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, '**'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, '*M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, '*F'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'M*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'MM'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'MF'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'F*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'FM'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSex('A'); initializeInteractionType(0, '', T, INF, 'FF'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, '', T, INF, 'W*'); stop(); }\", \"unsupported sexSegregation value\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeInteractionType(0, '', T, INF, '*W'); stop(); }\", \"unsupported sexSegregation value\", __LINE__);\n\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'w'); stop(); }\", \"spatiality 'w' must be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType('i0', 'w'); stop(); }\", \"spatiality 'w' must be\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, '', T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, '', T, 0.1); stop(); }\", \"must be INF for non-spatial interactions\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, '', T, INF, '**'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, '', T, INF, '*M'); stop(); }\", \"unsupported in non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeSex('A'); initializeInteractionType(0, '', T, INF, '*M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, '', T, INF, 'W*'); stop(); }\", \"unsupported sexSegregation value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'y'); stop(); }\", \"spatial dimensions beyond those set\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', F, 0.1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', T, 0.1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', T, 0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', T, -0.1); stop(); }\", \"maxDistance must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeInteractionType(0, 'x', T, 0.1, '*M'); stop(); }\", \"unsupported in non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='x'); initializeSex('A'); initializeInteractionType(0, 'x', T, 0.1, '*M'); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'x'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'y'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'z'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'xy'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'yz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'xz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'xyz'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'w'); stop(); }\", \"spatiality 'w' must be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'yx'); stop(); }\", \"spatiality 'yx' must be\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeInteractionType(0, 'zyx'); stop(); }\", \"spatiality 'zyx' must be\", __LINE__);\n}\n\n#pragma mark Community tests\nvoid _RunCommunityTests(void)\n{\n\t// Note that _RunSpeciesTests() also does some Community tests, for historical reasons...\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { community.outputUsage(); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { community.usage(); } \" + gen2_stop, __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.allGenomicElementTypes, g1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (community.allInteractionTypes.size() == 0) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.allMutationTypes, m1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (community.allScriptBlocks.size() == 3) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.allSpecies, sim)) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.allSubpopulations, p1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (community.logFiles.size() == 0) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (community.tick == 2) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { community.tag = 10; if (community.tag == 10) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.genomicElementTypesWithIDs(1), g1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.genomicElementTypesWithIDs(2); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.genomicElementTypesWithIDs(c(2,3)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.genomicElementTypesWithIDs(c(1,1)), c(g1,g1))) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"2 early() { if (identical(community.interactionTypesWithIDs(1), i1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"2 early() { community.interactionTypesWithIDs(2); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"2 early() { community.interactionTypesWithIDs(c(2,3)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"2 early() { if (identical(community.interactionTypesWithIDs(c(1,1)), c(i1,i1))) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.mutationTypesWithIDs(1), m1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.mutationTypesWithIDs(2); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.mutationTypesWithIDs(c(2,3)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.mutationTypesWithIDs(c(1,1)), c(m1,m1))) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"s1 2 early() { if (identical(community.scriptBlocksWithIDs(1), self)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"s1 2 early() { community.scriptBlocksWithIDs(2); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"s1 2 early() { community.scriptBlocksWithIDs(c(2,3)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"s1 2 early() { if (identical(community.scriptBlocksWithIDs(c(1,1)), c(self,self))) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.speciesWithIDs(0), sim)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.speciesWithIDs(1); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.speciesWithIDs(c(1,2)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.speciesWithIDs(c(0,0)), c(sim,sim))) stop(); } \", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.subpopulationsWithIDs(1), p1)) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.subpopulationsWithIDs(2); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { community.subpopulationsWithIDs(c(2,3)); } \", \"did not find\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(community.subpopulationsWithIDs(c(1,1)), c(p1,p1))) stop(); } \", __LINE__);\n}\n\n#pragma mark Species tests\nvoid _RunSpeciesTests(const std::string &temp_path)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Species & Community\n\t//\n\t\n\t// Test sim properties\n\tSLiMAssertScriptStop(gen1_setup + \"1 first() { } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes; } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.chromosomes = sim.chromosomes; } \" + gen2_stop, \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.chromosomes.type == 'A') stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.chromosomes.type = 'A'; } \" + gen2_stop, \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { if (sim.chromosomes.type == 'X') stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { sim.chromosomes.type = 'X'; } \" + gen2_stop, \"read-only property\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.cycle; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.cycle = 7; } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { community.tick = 7; } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (community.cycleStage == 'early') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (community.cycleStage == 'early') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 late() { if (community.cycleStage == 'late') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"modifyChild(p1) { if (community.cycleStage == 'reproduction') stop(); } 2 early() {}\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"mutationEffect(m1) { if (community.cycleStage == 'fitness') stop(); } 100 early() {}\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { community.cycleStage = 'early'; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.genomicElementTypes == g1) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.genomicElementTypes = g1; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (community.modelType == 'WF') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { if (community.modelType == 'WF') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(WF_prefix + gen1_setup + \"1 early() { if (community.modelType == 'WF') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(WF_prefix + gen1_setup_sex + \"1 early() { if (community.modelType == 'WF') stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { community.modelType = 'foo'; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.mutationTypes == m1) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.mutationTypes = m1; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.mutations; } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.mutations = _Test(7); } \", \"cannot be object element type\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.scriptBlocks; } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.scriptBlocks = sim.scriptBlocks[0]; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { community.allScriptBlocks; } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { community.allScriptBlocks = community.allScriptBlocks[0]; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.sexEnabled == F) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { if (sim.sexEnabled == T) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (size(sim.subpopulations) == 0) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.subpopulations = _Test(7); } \", \"cannot be object element type\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (size(sim.substitutions) == 0) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.substitutions = _Test(7); } \", \"cannot be object element type\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.tag; } \", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { c(sim,sim).tag; } \", \"before being set\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.tag = -17; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.tag = -17; } 2 early() { if (sim.tag == -17) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { community.verbosity; } \", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { community.verbosity = -17; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { community.verbosity = -17; } 2 early() { if (community.verbosity == -17) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.dimensionality == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"1 early() { if (sim.dimensionality == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"1 early() { sim.dimensionality = 'x'; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (sim.dimensionality == 'x') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.periodicity == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"1 early() { if (sim.periodicity == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"1 early() { sim.periodicity = 'x'; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (sim.periodicity == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz + \"1 early() { if (sim.periodicity == 'xz') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (sim.id == 0) stop(); } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.id = 2; } \" + gen2_stop, \"read-only property\", __LINE__);\n\t\n\t// Test sim - (object<Subpopulation>)addSubpop(is$ subpopID, integer$ size, [float$ sexRatio])\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.addSubpop('p1', 10); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.addSubpop(1, 10); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.addSubpop('p1', 10, 0.5); } \" + gen2_stop, __LINE__);\t// default value\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.addSubpop(1, 10, 0.5); } \" + gen2_stop, __LINE__);\t// default value\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.addSubpop('p1', 10, 0.4); } \" + gen2_stop, \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.addSubpop(1, 10, 0.4); } \" + gen2_stop, \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { sim.addSubpop('p1', 10, 0.5); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { sim.addSubpop(1, 10, 0.5); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { x = sim.addSubpop('p7', 10); if (x == p7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { x = sim.addSubpop(7, 10); if (x == p7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { p7 = 17; sim.addSubpop('p7', 10); stop(); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.addSubpop('p7', 10); sim.addSubpop(7, 10); stop(); }\", \"used already\", __LINE__);\n\t\n\t// Test sim - (object<Subpopulation>)addSubpopSplit(is$ subpopID, integer$ size, io<Subpopulation>$ sourceSubpop, [float$ sexRatio])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit('p2', 10, p1); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit('p2', 10, 1); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 10, p1); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 10, 1); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 10, 7); } \" + gen2_stop, \"not defined\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit('p2', 10, p1, 0.5); } \" + gen2_stop, __LINE__);\t// default value\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 10, p1, 0.5); } \" + gen2_stop, __LINE__);\t// default value\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit('p2', 10, p1, 0.4); } \" + gen2_stop, \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 10, p1, 0.4); } \" + gen2_stop, \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { sim.addSubpopSplit('p2', 10, p1, 0.5); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { sim.addSubpopSplit(2, 10, p1, 0.5); } \" + gen2_stop, __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { x = sim.addSubpopSplit('p7', 10, p1); if (x == p7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { x = sim.addSubpopSplit(7, 10, p1); if (x == p7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p7 = 17; sim.addSubpopSplit('p7', 10, p1); stop(); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.addSubpopSplit('p7', 10, p1); sim.addSubpopSplit(7, 10, p1); stop(); }\", \"used already\", __LINE__);\n\t\n\t// Test sim - (void)deregisterScriptBlock(io<SLiMEidosBlock> scriptBlocks)\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(s1); } s1 2 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(1); } s1 2 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(object()); } s1 2 early() { stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// legal: deregister nothing\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(c(s1, s1)); } s1 2 early() { stop(); }\", \"same script block\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(c(1, 1)); } s1 2 early() { stop(); }\", \"same script block\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(s1); community.deregisterScriptBlock(s1); } s1 2 early() { stop(); }\", \"same script block\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(1); community.deregisterScriptBlock(1); } s1 2 early() { stop(); }\", \"same script block\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(c(s1, s2)); } s1 2 early() { stop(); } s2 3 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { community.deregisterScriptBlock(c(1, 2)); } s1 2 early() { stop(); } s2 3 early() { stop(); }\", __LINE__);\n\t\n\t// Test sim - (object<Individual>)individualsWithPedigreeIDs(integer pedigreeIDs, [Nio<Subpopulation> subpops = NULL])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.individualsWithPedigreeIDs(1); }\", \"when pedigree recording\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(integer(0)); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(100000); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(rep(100000, 1000)); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals[0]; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = sample(p1.individuals, 1000, replace=T); ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids); if (identical(i1, i2)) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.individualsWithPedigreeIDs(1, p1); }\", \"when pedigree recording\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(integer(0), p1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(100000, p1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(rep(100000, 1000), p1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals[0]; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, p1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, p1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = sample(p1.individuals, 1000, replace=T); ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, p1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.individualsWithPedigreeIDs(1, 1); }\", \"when pedigree recording\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { sim.individualsWithPedigreeIDs(1, 10); }\", \"p10 not defined\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(integer(0), 1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(100000, 1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"1 early() { i = sim.individualsWithPedigreeIDs(rep(100000, 1000), 1); if (identical(i, p1.individuals[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals[0]; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, 1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = p1.individuals; ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, 1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeSLiMOptions(keepPedigrees=T); }\" + gen1_setup_p1 + \"10 early() { i1 = sample(p1.individuals, 1000, replace=T); ids = i1.pedigreeID; i2 = sim.individualsWithPedigreeIDs(ids, 1); if (identical(i1, i2)) stop(); }\", __LINE__);\n\t\n\t// Test sim - (void)killIndividuals(object<Individual> individuals)\n\t// this is also done in the test script killIndividuals_test.slim, in Miscellaneous\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_p1_100 + \"2:10 first() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_p1_100 + \"2:10 early() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_p1_100 + \"2:10 late() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_sex_p1_100 + \"2:10 first() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_sex_p1_100 + \"2:10 early() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(nonWF_prefix + gen1_setup_sex_p1_100 + \"2:10 late() { p1.individuals.tag = 0; s = p1.sampleIndividuals(3); s.tag = 1; sim.killIndividuals(s); if (sum(p1.individuals.tag) != 0) stop(); }\", __LINE__);\n\t\n\t// Test sim - (float)mutationFrequencies(Nio<Subpopulation> subpops, [object<Mutation> mutations])\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(p1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(c(p1, p2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(NULL); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(sim.subpopulations); }\", __LINE__);\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(object()); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t// legal to specify an empty object vector\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(10); }\", \"p10 not defined\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(1:2); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(sim.subpopulations.id); }\", __LINE__);\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationFrequencies(integer(0)); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal to specify an empty integer vector\n\t\n\t// Test sim - (integer)mutationCounts(Nio<Subpopulation> subpops, [object<Mutation> mutations])\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(p1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(c(p1, p2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(NULL); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(sim.subpopulations); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(object()); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// legal to specify an empty object vector\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(10); }\", \"p10 not defined\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(1:2); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(sim.subpopulations.id); }\", __LINE__);\t\t\t\t\t\t\t\t\t// legal, requests population-wide frequencies\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 early() { sim.mutationCounts(integer(0)); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// legal to specify an empty integer vector\n\t\n\t// Test sim - (object<Mutation>)mutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { sim.mutationsOfType(m1); } \", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { sim.mutationsOfType(1); } \", __LINE__);\n\t\n\t// Test sim - (object<Mutation>)countOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { sim.countOfMutationsOfType(m1); } \", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { sim.countOfMutationsOfType(1); } \", __LINE__);\n\t\n\t// Test sim - (void)outputFixedMutations(void)\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFixedMutations(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFixedMutations(NULL); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFixedMutations('\" + temp_path + \"/slimOutputFixedTest.txt'); }\", __LINE__);\n\t\n\t// Test sim - (void)outputFull([string$ filePath])\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(NULL); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(spatialPositions=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(spatialPositions=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(ages=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(ages=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { sim.outputFull(spatialPositions=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { sim.outputFull(spatialPositions=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { sim.outputFull(ages=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { sim.outputFull(ages=F); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull(NULL, T); }\", \"cannot output in binary format\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull('\" + temp_path + \"/slimOutputFullTest.txt'); }\", __LINE__);\t\t\t\t\t\t\t\t// legal, output to file path; this test might work only on Un*x systems\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { sim.outputFull('\" + temp_path + \"/slimOutputFullTest.slimbinary', T); }\", __LINE__);\t\t\t\t\t\t// legal, output to file path; this test might work only on Un*x systems\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { p1.individuals.x = runif(10); sim.outputFull('\" + temp_path + \"/slimOutputFullTest_POSITIONS.txt'); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 late() { p1.individuals.x = runif(10); sim.outputFull('\" + temp_path + \"/slimOutputFullTest_POSITIONS.slimbinary', T); }\", __LINE__);\n\t}\n\t\n\t// Test sim - (void)outputMutations(object<Mutation> mutations)\n\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(sim.mutations); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t// legal; should have some mutations by gen 5\n\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(sim.mutations[0]); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal; output just one mutation\n\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(sim.mutations[integer(0)]); }\", __LINE__);\t\t\t\t\t\t\t\t// legal to specify an empty object vector\n\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(object()); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// legal to specify an empty object vector\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(NULL); }\", \"cannot be type NULL\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(sim.mutations, NULL); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t\tSLiMAssertScriptSuccess(gen1_setup_highmut_p1 + \"5 late() { sim.outputMutations(sim.mutations, '\" + temp_path + \"/slimOutputMutationsTest.txt'); }\", __LINE__);\n\t\n\t// Test sim - (void)readFromPopulationFile(string$ filePath)\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest.txt'); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// legal, read from file path; depends on the outputFull() test above\n\t\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest.slimbinary'); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal, read from file path; depends on the outputFull() test above\n\t\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest_POSITIONS.txt'); }\", \"spatial dimensionality of this model\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest_POSITIONS.slimbinary'); }\", \"output spatial dimensionality does not match\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest_POSITIONS.txt'); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest_POSITIONS.slimbinary'); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/notAFile.foo'); }\", \"does not exist or is empty\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest.txt'); if (size(sim.subpopulations) != 3) stop(); }\", __LINE__);\t\t\t// legal; should wipe previous state\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"1 early() { sim.readFromPopulationFile('\" + temp_path + \"/slimOutputFullTest.slimbinary'); if (size(sim.subpopulations) != 3) stop(); }\", __LINE__);\t// legal; should wipe previous state\n\t}\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerFirstEvent(Nis$ id, string$ source, [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(NULL, '{ stop(); }', 2, 2); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent('s1', '{ stop(); }', 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerFirstEvent('s1', '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerFirstEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(1, '{ stop(); }', 2, 2); community.registerFirstEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(1, '{ stop(); }', 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(1, '{ stop(); }', -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(1, '{ stop(); }', 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerFirstEvent(1, '{ $; }', 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerEarlyEvent(Nis$ id, string$ source, [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(NULL, '{ stop(); }', 2, 2); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent('s1', '{ stop(); }', 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerEarlyEvent('s1', '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerEarlyEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(1, '{ stop(); }', 2, 2); community.registerEarlyEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(1, '{ stop(); }', 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(1, '{ stop(); }', -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(1, '{ stop(); }', 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerEarlyEvent(1, '{ $; }', 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerLateEvent(Nis$ id, string$ source, [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { community.registerLateEvent(NULL, '{ stop(); }', 2, 2); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent('s1', '{ stop(); }', 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerLateEvent('s1', '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; community.registerLateEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent(1, '{ stop(); }', 2, 2); community.registerLateEvent(1, '{ stop(); }', 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent(1, '{ stop(); }', 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent(1, '{ stop(); }', -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent(1, '{ stop(); }', 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { community.registerLateEvent(1, '{ $; }', 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerFitnessEffectCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop], [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(NULL, '{ stop(); }', NULL, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(NULL, '{ stop(); }', p1, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(NULL, '{ stop(); }'); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback('s1', '{ stop(); }', NULL, 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { s1 = 7; sim.registerFitnessEffectCallback('s1', '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { s1 = 7; sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, 2, 2); sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(1, '{ stop(); }', NULL, 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerFitnessEffectCallback(1, '{ $; }', NULL, 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerMutationEffectCallback(Nis$ id, string$ source, io<MutationType>$ mutType, [Nio<Subpopulation>$ subpop], [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', 1, NULL, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', m1, NULL, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', 1, 1, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', m1, p1, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', 1); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }', m1); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(NULL, '{ stop(); }'); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback('s1', '{ stop(); }', m1, NULL, 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { s1 = 7; sim.registerMutationEffectCallback('s1', '{ stop(); }', m1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { s1 = 7; sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, 2, 2); sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(1, '{ stop(); }', m1, NULL, 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { sim.registerMutationEffectCallback(1, '{ $; }', m1, NULL, 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test community - (object<SLiMEidosBlock>)registerInteractionCallback(Nis$ id, string$ source, io<InteractionType>$ intType, [Nio<Subpopulation>$ subpop], [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', 1, NULL, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', i1, NULL, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', 1, 1, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', i1, p1, 5, 10); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', 1); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }', i1); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(NULL, '{ stop(); }'); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback('s1', '{ stop(); }', i1, NULL, 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { s1 = 7; community.registerInteractionCallback('s1', '{ stop(); }', i1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { s1 = 7; community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, 2, 2); community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(1, '{ stop(); }', i1, NULL, 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 early() { community.registerInteractionCallback(1, '{ $; }', i1, NULL, 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerMateChoiceCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop], [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }', NULL, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }', NULL, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }', 1, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }', p1, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }'); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ stop(); }'); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback('s1', '{ stop(); }', NULL, 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; sim.registerMateChoiceCallback('s1', '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, 2, 2); sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(1, '{ stop(); }', NULL, 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(1, '{ $; }', NULL, 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim - (object<SLiMEidosBlock>)registerModifyChildCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop], [integer$ start], [integer$ end])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }', NULL, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }', NULL, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }', 1, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }', p1, 2, 2); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }'); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL, '{ stop(); }'); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(NULL); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback('s1', '{ stop(); }', NULL, 2, 2); } s1 early() { }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; sim.registerModifyChildCallback('s1', '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1 = 7; sim.registerModifyChildCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(1, '{ stop(); }', NULL, 2, 2); sim.registerModifyChildCallback(1, '{ stop(); }', NULL, 2, 2); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(1, '{ stop(); }', NULL, 3, 2); }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(1, '{ stop(); }', NULL, -1, -1); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(1, '{ stop(); }', NULL, 0, 0); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.registerModifyChildCallback(1, '{ $; }', NULL, 2, 2); }\", \"unexpected token '$'\", __LINE__);\n\t\n\t// Test sim – (object<SLiMEidosBlock>)rescheduleScriptBlock(io<SLiMEidosBlock>$ block, [Ni$ start = NULL], [Ni$ end = NULL], [Ni ticks = NULL])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=10, end=9); stop(); } s1 10 early() { }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=integer(0)); stop(); } s1 10 early() { }\", __LINE__);\t// this is now legal\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=c(25, 25)); stop(); } s1 10 early() { }\", \"same tick cannot be used twice\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25, end=25, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25, end=NULL, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=NULL, end=25, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25, end=25); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25:29)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=NULL, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"for the currently executing\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"for the currently executing\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { b = community.rescheduleScriptBlock(s1, start=NULL, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"scheduled for a past tick\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { b = community.rescheduleScriptBlock(s1, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"scheduled for a past tick\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25, end=NULL); if (b.start == 25 & b.end == 1000000001) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, start=25); if (b.start == 25 & b.end == 1000000001) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=25); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=25:28); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25:28)) stop(); } s1 10 early() { }\", __LINE__);\n\t// these would use a `ticks` property now to check the scheduling, if that property existed; you'd also have sort-order issues though, would need to check the sorted order\n\t//SLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=c(25:28, 35)); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, c(25:28, 35))) stop(); } s1 10 early() { }\", __LINE__);\n\t//SLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(s1, ticks=c(13, 25:28)); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, c(13, 25:28))) stop(); } s1 10 early() { }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(2, start=10, end=9); stop(); } s1 10 early() { }\", \"s2 not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=10, end=9); stop(); } s1 10 early() { }\", \"requires start <= end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=integer(0)); stop(); } s1 10 early() { }\", __LINE__);\t// this is now legal\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=c(25, 25)); stop(); } s1 10 early() { }\", \"same tick cannot be used twice\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25, end=25, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25, end=NULL, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=NULL, end=25, ticks=25); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1); stop(); } s1 10 early() { }\", \"either start/end or ticks\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25, end=25); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25:29)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=NULL, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"for the currently executing\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"for the currently executing\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { b = community.rescheduleScriptBlock(1, start=NULL, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"scheduled for a past tick\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { b = community.rescheduleScriptBlock(1, end=29); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 1:29)) stop(); } s1 10 early() { }\", \"scheduled for a past tick\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25, end=NULL); if (b.start == 25 & b.end == 1000000001) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, start=25); if (b.start == 25 & b.end == 1000000001) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=25); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25)) stop(); } s1 10 early() { }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=25:28); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, 25:28)) stop(); } s1 10 early() { }\", __LINE__);\n\t// these would use a `ticks` property now to check the scheduling, if that property existed; you'd also have sort-order issues though, would need to check the sorted order\n\t//SLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=c(25:28, 35)); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, c(25:28, 35))) stop(); } s1 10 early() { }\", __LINE__);\n\t//SLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { b = community.rescheduleScriptBlock(1, ticks=c(13, 25:28)); r = sapply(b, 'applyValue.start:applyValue.end;'); if (identical(r, c(13, 25:28))) stop(); } s1 10 early() { }\", __LINE__);\n\t\n\t// Test Community - (object<LogFile>$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = \",\"], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL])\n\tif (Eidos_TemporaryDirectoryExists())\n\t\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"1 late() { path = '\" + temp_path + \"/slimLogFileTest.txt'; log = community.createLogFile(path, initialContents='# HEADER COMMENT', logInterval=1); log.addTick(); log.addCycle(); log.addSubpopulationSize(p1); } 10 late() { }\", __LINE__);\n\t\n\t// Test Community - (void)simulationFinished(void)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"11 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { community.simulationFinished(); } 11 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { sim.simulationFinished(); } 11 early() { stop(); }\", __LINE__);\n\t\n\t// Test sim - (object<Mutation>)subsetMutations([No<Mutation>$ exclude = NULL], [Nio<MutationType>$ mutationType = NULL], [Ni$ position = NULL], [Nis$ nucleotide = NULL], [Ni$ tag = NULL], [Ni$ id = NULL])\n\t// unusually, we do this with custom SLiM scripts that check the API stochastically, since it would be difficult\n\t// to test all the possible parameter combinations otherwise; we do a non-nucleotide test and a nucleotide test\n\tSLiMAssertScriptSuccess(R\"V0G0N(\n\tinitialize() {\n\t\tinitializeMutationRate(1e-2);\n\t\tinitializeMutationType('m1', 0.5, 'f', 0.0);\n\t\tinitializeMutationType('m2', 0.5, 'f', 0.0);\n\t\tinitializeGenomicElementType('g1', c(m1,m2), c(1,1));\n\t\tinitializeGenomicElement(g1, 0, 99);\n\t\tinitializeRecombinationRate(1e-8);\n\t\tm2.color=\"red\";\n\t}\n\t1 early() { sim.addSubpop('p1', 10); }\n\t50 early() {\n\t\tm=sim.mutations;\n\t\tm.tag=rdunif(m.size(), max=5);\n\t\tfor (i in 1:10000) {\n\t\t\tex=(runif(1)<0.8) ? NULL else sample(m,1);\n\t\t\tmt=(runif(1)<0.8) ? NULL else ((runif(1) < 0.5) ? m1 else m2);\n\t\t\tpos=(runif(1)<0.8) ? NULL else rdunif(1, max=99);\n\t\t\ttag=(runif(1)<0.8) ? NULL else rdunif(1, max=5);\n\t\t\tid=(runif(1)<0.8) ? NULL else sample(m.id, 1);\n\t\t\tmethod1=sim.subsetMutations(exclude=ex, mutType=mt, position=pos,\n\t\t\t\ttag=tag, id=id);\n\t\t\tmethod2=m;\n\t\t\tif (!isNULL(ex)) method2=method2[method2!=ex];\n\t\t\tif (!isNULL(mt)) method2=method2[method2.mutationType==mt];\n\t\t\tif (!isNULL(pos)) method2=method2[method2.position==pos];\n\t\t\tif (!isNULL(tag)) method2=method2[method2.tag==tag];\n\t\t\tif (!isNULL(id)) method2=method2[method2.id==id];\n\t\t\t\n\t\t\tif (!identical(method1,method2)) stop();\n\t\t}\n\t}\n\t)V0G0N\", __LINE__);\n\tSLiMAssertScriptSuccess(R\"V0G0N(\n\tinitialize() {\n\t\tinitializeSLiMOptions(nucleotideBased=T);\n\t\tinitializeAncestralNucleotides(randomNucleotides(100));\n\t\tinitializeMutationTypeNuc('m1', 0.5, 'f', 0.0);\n\t\tinitializeMutationTypeNuc('m2', 0.5, 'f', 0.0);\n\t\tinitializeGenomicElementType('g1', c(m1,m2), c(1,1), mmJukesCantor(1e-2 / 3));\n\t\tinitializeGenomicElement(g1, 0, 99);\n\t\tinitializeRecombinationRate(1e-8);\n\t\tm2.color=\"red\";\n\t}\n\t1 early() { sim.addSubpop('p1', 10); }\n\t50 early() {\n\t\tm=sim.mutations;\n\t\tm.tag=rdunif(m.size(), max=5);\n\t\tfor (i in 1:10000) {\n\t\t\tex=(runif(1)<0.8) ? NULL else sample(m,1);\n\t\t\tmt=(runif(1)<0.8) ? NULL else ((runif(1) < 0.5) ? m1 else m2);\n\t\t\tpos=(runif(1)<0.8) ? NULL else rdunif(1, max=99);\n\t\t\tnuc=(runif(1)<0.8) ? NULL else rdunif(1, max=3);\n\t\t\ttag=(runif(1)<0.8) ? NULL else rdunif(1, max=5);\n\t\t\tid=(runif(1)<0.8) ? NULL else sample(m.id, 1);\n\t\t\tmethod1=sim.subsetMutations(exclude=ex, mutType=mt, position=pos,\n\t\t\t\tnucleotide=nuc, tag=tag, id=id);\n\t\t\tmethod2=m;\n\t\t\tif (!isNULL(ex)) method2=method2[method2!=ex];\n\t\t\tif (!isNULL(mt)) method2=method2[method2.mutationType==mt];\n\t\t\tif (!isNULL(pos)) method2=method2[method2.position==pos];\n\t\t\tif (!isNULL(nuc)) method2=method2[method2.nucleotideValue==nuc];\n\t\t\tif (!isNULL(tag)) method2=method2[method2.tag==tag];\n\t\t\tif (!isNULL(id)) method2=method2[method2.id==id];\n\t\t\t\n\t\t\tif (!identical(method1,method2)) stop();\n\t\t}\n\t}\n\t)V0G0N\", __LINE__);\n\t\n\t// Test sim EidosDictionaryUnretained functionality: - (+)getValue(is$ key) and - (void)setValue(is$ key, + value)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.setValue('foo', 7:9); sim.setValue('bar', 'baz'); } 10 early() { if (identical(sim.getValue('foo'), 7:9) & identical(sim.getValue('bar'), 'baz')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.setValue('foo', 3:5); sim.setValue('foo', 'foobar'); } 10 early() { if (identical(sim.getValue('foo'), 'foobar')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { sim.setValue('foo', 3:5); sim.setValue('foo', NULL); } 10 early() { if (isNULL(sim.getValue('foo'))) stop(); }\", __LINE__);\n\t\n\t// Test mutation frequency/counts by cross-checking different methods against each other\n\t// this is a shortened version of SLiM_project/Miscellaneous/Testing/test_multichrom_freqs_counts.slim\n\t// it is best when run under DEBUG, since then SLiM's self-check code is also involved\n\tSLiMAssertScriptSuccess(R\"V0G0N(\n\tinitialize() {\n\t\tinitializeSex();\n\t\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.1);\n\t\tinitializeMutationType(\"m3\", 0.5, \"f\", -0.01);\n\t\tinitializeGenomicElementType(\"g1\", c(m1,m2,m3), c(100, 1, 10));\n\n\t\tids = 1:11;\n\t\tlengths = c(2e4, rep(1e4, 10));\n\t\ttypes = c(\"A\", \"A\", \"H\", \"X\", \"Y\", \"W\", \"Z\", \"HF\", \"FL\", \"HM\", \"ML\");\n\n\t\tfor (id in ids, length in lengths, type in types)\n\t\t{\n\t\t\tinitializeChromosome(id, length);\n\t\t\tinitializeMutationRate(1e-4);\n\t\t\tinitializeGenomicElement(g1, 0, length - 1);\n\t\t\tinitializeRecombinationRate(1e-4);\n\t\t}\n\t}\n\t1 early() {\n\t\tsim.addSubpop(\"p1\", 10);\n\t\tsim.addSubpop(\"p2\", 10);\n\t\tp1.setMigrationRates(p2, 0.001);\n\t\tp2.setMigrationRates(p1, 0.01);\n\t}\n\t85 early() {\n\t\tp1.setSubpopulationSize(30);\n\t\tp2.setSubpopulationSize(30);\n\t}\n\t90:100 late() {\n\t\tp1_haplosomes = p1.haplosomes;\n\t\tp2_haplosomes = p2.haplosomes;\n\t\tall_haplosomes = c(p1_haplosomes, p2_haplosomes);\n\t\thaplosome_subsample = sample(all_haplosomes, integerDiv(size(all_haplosomes), 4));\n\t\tall_muts = sim.mutations;\n\t\tsampled_muts = sample(sim.mutations, integerDiv(size(sim.mutations), 2));\n\n\t\t// check mutation counts first\n\t\tfor (iter in 1:2)\n\t\t{\n\t\t\tmuts_checked = ((iter == 1) ? NULL else sampled_muts);\n\n\t\t\tcounts_hapsample_1 = haplosome_subsample.mutationCountsInHaplosomes(muts_checked);\n\n\t\t\tcounts_p1_haplosomes = p1_haplosomes.mutationCountsInHaplosomes(muts_checked);\n\t\t\tcounts_p1_subpop = sim.mutationCounts(p1, muts_checked);\n\t\t\tif (!identical(counts_p1_haplosomes, counts_p1_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tcounts_hapsample_2 = haplosome_subsample.mutationCountsInHaplosomes(muts_checked);\n\t\t\tif (!identical(counts_hapsample_1, counts_hapsample_2))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tcounts_p2_haplosomes = p2_haplosomes.mutationCountsInHaplosomes(muts_checked);\n\t\t\tcounts_p2_subpop = sim.mutationCounts(p2, muts_checked);\n\t\t\tif (!identical(counts_p2_haplosomes, counts_p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tcounts_p1p1_haplosomes = c(p1_haplosomes, p2_haplosomes).mutationCountsInHaplosomes(muts_checked);\n\t\t\tcounts_p1p2_subpop = sim.mutationCounts(c(p1, p2), muts_checked);\n\t\t\tcounts_pop = sim.mutationCounts(NULL, muts_checked);\n\n\t\t\tif (!identical(counts_p1p1_haplosomes, counts_p1p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\t\t\tif (!identical(counts_pop, counts_p1p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\t\t\tif (!identical(counts_p1_haplosomes + counts_p2_haplosomes, counts_p1p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tcounts_hapsample_3 = haplosome_subsample.mutationCountsInHaplosomes(muts_checked);\n\t\t\tif (!identical(counts_hapsample_1, counts_hapsample_3))\n\t\t\t\tstop(\"iter == \" + iter);\n\t\t}\n\n\t\t// check mutation frequencies second\n\t\tfor (iter in 1:2)\n\t\t{\n\t\t\tmuts_checked = ((iter == 1) ? NULL else sampled_muts);\n\n\t\t\tfreqs_hapsample_1 = haplosome_subsample.mutationFrequenciesInHaplosomes(muts_checked);\n\n\t\t\tfreqs_p1_haplosomes = p1_haplosomes.mutationFrequenciesInHaplosomes(muts_checked);\n\t\t\tfreqs_p1_subpop = sim.mutationFrequencies(p1, muts_checked);\n\t\t\tif (!identical(freqs_p1_haplosomes, freqs_p1_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tfreqs_hapsample_2 = haplosome_subsample.mutationFrequenciesInHaplosomes(muts_checked);\n\t\t\tif (!identical(freqs_hapsample_1, freqs_hapsample_2))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tfreqs_p2_haplosomes = p2_haplosomes.mutationFrequenciesInHaplosomes(muts_checked);\n\t\t\tfreqs_p2_subpop = sim.mutationFrequencies(p2, muts_checked);\n\t\t\tif (!identical(freqs_p2_haplosomes, freqs_p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tfreqs_p1p1_haplosomes = c(p1_haplosomes, p2_haplosomes).mutationFrequenciesInHaplosomes(muts_checked);\n\t\t\tfreqs_p1p2_subpop = sim.mutationFrequencies(c(p1, p2), muts_checked);\n\t\t\tfreqs_pop = sim.mutationFrequencies(NULL, muts_checked);\n\n\t\t\tif (!identical(freqs_p1p1_haplosomes, freqs_p1p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\t\t\tif (!identical(freqs_pop, freqs_p1p2_subpop))\n\t\t\t\tstop(\"iter == \" + iter);\n\n\t\t\tfreqs_hapsample_3 = haplosome_subsample.mutationFrequenciesInHaplosomes(muts_checked);\n\t\t\tif (!identical(freqs_hapsample_1, freqs_hapsample_3))\n\t\t\t\tstop(\"iter == \" + iter);\n\t\t}\n\t}\n\t)V0G0N\", __LINE__);\n}\n\n#pragma mark Subpopulation tests\nvoid _RunSubpopulationTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Subpopulation\n\t//\n\t\n\t// Test Subpopulation properties\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.cloningRate == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.firstMaleIndex == p1.firstMaleIndex) stop(); }\", __LINE__);\t\t\t\t\t// legal but undefined value in non-sexual sims\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.haplosomes) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.haplosomesNonNull) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.individuals) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.id == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.immigrantSubpopFractions, float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.immigrantSubpopIDs, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.selfingRate == 0.0) stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// legal but always 0.0 in non-sexual sims\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.sexRatio == 0.0) stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// legal but always 0.0 in non-sexual sims\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.species, sim)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.individualCount == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { c(p1,p1).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.tag = 135; if (p1.tag == 135) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.fitnessScaling = 135.0; if (p1.fitnessScaling == 135.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.fitnessScaling = 0.0; if (p1.fitnessScaling == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.fitnessScaling = -0.01; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.fitnessScaling = NAN; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.name == 'p1') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.name = 'p1'; if (p1.name == 'p1') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.name = 'foo'; if (p1.name == 'foo') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.name = 'foo'; p1.name = 'bar'; if (p1.name == 'bar') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.name = 'p2'; }\", \"subpopulation symbol\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.name = 'foo'; p1.name = 'bar'; p1.name = 'foo'; }\", \"must be unique\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (p1.description == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.description = 'this is groovy'; if (p1.description == 'this is groovy') stop(); }\", __LINE__);\n\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.cloningRate = 0.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.firstMaleIndex = p1.firstMaleIndex; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes = p1.haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomesNonNull = p1.haplosomesNonNull[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.individuals = p1.individuals[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.id = 1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.immigrantSubpopFractions = 1.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.immigrantSubpopIDs = 1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.selfingRate = 0.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.sexRatio = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.species = sim; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.individualCount = 10; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (identical(p1.cloningRate, c(0.0,0.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.firstMaleIndex == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.haplosomes) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.haplosomesNonNull) == 15) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.individuals) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.id == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (identical(p1.immigrantSubpopFractions, float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (identical(p1.immigrantSubpopIDs, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.selfingRate == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.sexRatio == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (identical(p1.species, sim)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.individualCount == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { c(p1,p1).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.tag = 135; if (p1.tag == 135) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.fitnessScaling = 135.0; if (p1.fitnessScaling == 135.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.fitnessScaling = 0.0; if (p1.fitnessScaling == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.fitnessScaling = -0.01; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.fitnessScaling = NAN; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.name == 'p1') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.name = 'p1'; if (p1.name == 'p1') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.name = 'foo'; if (p1.name == 'foo') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.name = 'foo'; p1.name = 'bar'; if (p1.name == 'bar') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.name = 'p2'; }\", \"subpopulation symbol\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.name = 'foo'; p1.name = 'bar'; p1.name = 'foo'; }\", \"must be unique\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (p1.description == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.description = 'this is groovy'; if (p1.description == 'this is groovy') stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.cloningRate = 0.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.firstMaleIndex = p1.firstMaleIndex; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.haplosomes = p1.haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.haplosomesNonNull = p1.haplosomesNonNull[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.individuals = p1.individuals[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.id = 1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.immigrantSubpopFractions = 1.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.immigrantSubpopIDs = 1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.selfingRate = 0.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.sexRatio = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.species = sim; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.individualCount = 10; stop(); }\", \"read-only property\", __LINE__);\n\t\n\t// Test Subpopulation - (float)cachedFitness(Ni indices)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.cachedFitness(NULL), rep(1.0, 10))) stop(); }\", __LINE__);\t\t\t\t// legal (after subpop construction)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"2 early() { if (identical(p1.cachedFitness(NULL), rep(1.0, 10))) stop(); }\", __LINE__);\t\t\t\t// legal (after generating children)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.cachedFitness(0), 1.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.cachedFitness(0:3), rep(1.0, 4))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { identical(p1.cachedFitness(-1), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { identical(p1.cachedFitness(10), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { identical(p1.cachedFitness(c(-1,5)), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { identical(p1.cachedFitness(c(5,10)), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { identical(p1.cachedFitness(-1), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { identical(p1.cachedFitness(10), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { identical(p1.cachedFitness(c(-1,5)), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"2 early() { identical(p1.cachedFitness(c(5,10)), rep(1.0, 10)); stop(); }\", \"out of range\", __LINE__);\n\t\n\t// Test Subpopulation – (object<Individual>)sampleIndividuals(integer$ size, [logical$ replace = F], [No<Individual>$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(0)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(1)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(2)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(4)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, exclude=p1.individuals[2])) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2])) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, exclude=p1.individuals[2])) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, exclude=p1.individuals[2])) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2])) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2])) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2])) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2])) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.sampleIndividuals(-1); }\", \"requires a sample size\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.sampleIndividuals(15, replace=F); if (size(i) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.sampleIndividuals(1, sex='M'); }\", \"in non-sexual models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.sampleIndividuals(1, sex='W'); }\", \"unrecognized value for sex\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (p1.sampleIndividuals(3, replace=T, exclude=p1.individuals[5], sex='M', tag=1).size() == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (p1.sampleIndividuals(3, replace=F, exclude=p1.individuals[5], sex='M', tag=1).size() == 2) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(0, tag=1).tag, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(1, tag=1).tag, c(1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(2, tag=1).tag, c(1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(4, tag=1).tag, c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(0, exclude=p1.individuals[2], tag=1).tag, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(1, exclude=p1.individuals[2], tag=1).tag, c(1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(2, exclude=p1.individuals[2], tag=1).tag, c(1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(4, exclude=p1.individuals[2], tag=1).tag, c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(0, replace=T, tag=1).tag, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(1, replace=T, tag=1).tag, c(1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(2, replace=T, tag=1).tag, c(1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(4, replace=T, tag=1).tag, c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2], tag=1).tag, integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2], tag=1).tag, c(1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2], tag=1).tag, c(1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2], tag=1).tag, c(1,1,1,1))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, exclude=p1.individuals[2])) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2])) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, exclude=p1.individuals[2])) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, exclude=p1.individuals[2])) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2])) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2])) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2])) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2])) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, sex='M')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, sex='M')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, sex='M')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, sex='M')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, exclude=p1.individuals[2], sex='M')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2], sex='M')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, exclude=p1.individuals[2], sex='M')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, exclude=p1.individuals[2], sex='M')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, sex='M')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, sex='M')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, sex='M')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, sex='M')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2], sex='M')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2], sex='M')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2], sex='M')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2], sex='M')) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, sex='F')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, sex='F')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, sex='F')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, sex='F')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, exclude=p1.individuals[2], sex='F')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2], sex='F')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, exclude=p1.individuals[2], sex='F')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, exclude=p1.individuals[2], sex='F')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, sex='F')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, sex='F')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, sex='F')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, sex='F')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2], sex='F')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2], sex='F')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2], sex='F')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2], sex='F')) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, migrant=F)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, migrant=F)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, migrant=F)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, migrant=F)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, exclude=p1.individuals[2], migrant=F)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2], migrant=F)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, exclude=p1.individuals[2], migrant=F)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, exclude=p1.individuals[2], migrant=F)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, migrant=F)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, migrant=F)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, migrant=F)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, migrant=F)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, replace=T, exclude=p1.individuals[2], migrant=F)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, replace=T, exclude=p1.individuals[2], migrant=F)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(2, replace=T, exclude=p1.individuals[2], migrant=F)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(4, replace=T, exclude=p1.individuals[2], migrant=F)) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(0, migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.sampleIndividuals(1, exclude=p1.individuals[2], migrant=T)) == 0) stop(); }\", __LINE__);\n\t\n\t// Test Subpopulation – (object<Individual>)subsetIndividuals([No<Individual>$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.subsetIndividuals()) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2])) == 9) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.subsetIndividuals(sex='M'); }\", \"in non-sexual models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.subsetIndividuals(sex='W'); }\", \"unrecognized value for sex\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.subsetIndividuals(tag=1).tag, c(1,1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (identical(p1.subsetIndividuals(exclude=p1.individuals[3], tag=1).tag, c(1,1,1,1))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals()) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2])) == 9) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(sex='M')) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2], sex='M')) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(sex='F')) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2], sex='F')) == 4) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(migrant=F)) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2], migrant=F)) == 9) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { if (size(p1.subsetIndividuals(exclude=p1.individuals[2], migrant=T)) == 0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(sex='F', tag=1)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], sex='F', tag=1)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(sex='F', tag=0)) == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], sex='F', tag=0)) == 3) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(tag=1, migrant=F)) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], tag=1, migrant=F)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(tag=0, migrant=F)) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], tag=0, migrant=F)) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(tag=1, migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], tag=1, migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(tag=0, migrant=T)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.individuals.tag = rep(c(0,1),5); if (size(p1.subsetIndividuals(exclude=p1.individuals[3], tag=0, migrant=T)) == 0) stop(); }\", __LINE__);\n\t\n\t// Test Subpopulation - (void)outputMSSample(integer$ sampleSize, [logical$ replace], [string$ requestedSex], [Ns$ filePath = NULL], [logical$ append = F], [logical$ filterMonomorphic = F])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputMSSample(30, F); stop(); }\", \"not enough eligible haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, F, 'M'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, F, 'F'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputMSSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(30, F); stop(); }\", \"not enough eligible haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, F, 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, F, 'F'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputMSSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\t\n\t// Test Subpopulation - (void)outputSample(integer$ sampleSize, [logical$ replace], [string$ requestedSex])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputSample(30, F); stop(); }\", \"not enough eligible haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputSample(1, F, 'M'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputSample(1, F, 'F'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(30, F); stop(); }\", \"not enough eligible haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, F, 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, F, 'F'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\t\n\t// Test Subpopulation - (void)outputVCFSample(integer$ sampleSize, [logical$ replace], [string$ requestedSex], [logical$ outputMultiallelics)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(30, F); stop(); }\", \"not enough eligible individuals\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, F, 'M'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, F, 'F'); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, 'M', F); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, 'F', F); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, '*', F); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, 'M', T); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, 'F', T); stop(); }\", \"non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 late() { p1.outputVCFSample(5, F, '*', T); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(10); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(30); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(30, F); stop(); }\", \"not enough eligible individuals\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(30, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, F, 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, F, 'F'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, F, '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(1, F, 'Z'); stop(); }\", \"requested sex\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, 'M', F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, 'F', F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, '*', F); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, 'M', T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, 'F', T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 late() { p1.outputVCFSample(5, F, '*', T); stop(); }\", __LINE__);\n\t\n\t// Test Subpopulation - (void)setCloningRate(numeric rate)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setCloningRate(0.0); } 10 early() { if (p1.cloningRate == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setCloningRate(0.5); } 10 early() { if (p1.cloningRate == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setCloningRate(1.0); } 10 early() { if (p1.cloningRate == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setCloningRate(-0.001); stop(); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setCloningRate(1.001); stop(); }\", \"within [0,1]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(0.0); } 10 early() { if (identical(p1.cloningRate, c(0.0, 0.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(0.5); } 10 early() { if (identical(p1.cloningRate, c(0.5, 0.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(1.0); } 10 early() { if (identical(p1.cloningRate, c(1.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(-0.001); stop(); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(1.001); stop(); }\", \"within [0,1]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(c(0.0, 0.1)); } 10 early() { if (identical(p1.cloningRate, c(0.0, 0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(c(0.5, 0.1)); } 10 early() { if (identical(p1.cloningRate, c(0.5, 0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(c(1.0, 0.1)); } 10 early() { if (identical(p1.cloningRate, c(1.0, 0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(c(0.0, -0.001)); stop(); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setCloningRate(c(0.0, 1.001)); stop(); }\", \"within [0,1]\", __LINE__);\n\t\n\t// Test Subpopulation - (void)setMigrationRates(io<Subpopulation> sourceSubpops, numeric rates)\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(2, 0.1); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(3, 0.1); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), c(0.1, 0.1)); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(1, 0.1); } 10 early() { stop(); }\", \"self-referential\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(4, 0.1); } 10 early() { stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 1), c(0.1, 0.1)); } 10 early() { stop(); }\", \"self-referential\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 4), c(0.1, 0.1)); } 10 early() { stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 2), c(0.1, 0.1)); } 10 early() { stop(); }\", \"two rates set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(p2, p2), c(0.1, 0.1)); } 10 early() { stop(); }\", \"two rates set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), 0.1); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), float(0)); } 10 early() { stop(); }\", \"to be equal in size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), c(0.1, 0.1, 0.1)); } 10 early() { stop(); }\", \"to be equal in size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(2, c(0.1, 0.1)); } 10 early() { stop(); }\", \"to be equal in size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(2, -0.0001); } 10 early() { stop(); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(2, 1.0001); } 10 early() { stop(); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), 0.6); } 10 early() { stop(); }\", \"must sum to <= 1.0\", __LINE__, false);\t// raise is from EvolveSubpopulation(); we don't force constraints prematurely\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"1 early() { p1.setMigrationRates(c(2, 3), c(0.6, 0.6)); } 10 early() { stop(); }\", \"must sum to <= 1.0\", __LINE__, false);\t// raise is from EvolveSubpopulation(); we don't force constraints prematurely\n\t\n\t// Test Subpopulation - (void)setSelfingRate(numeric$ rate)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSelfingRate(0.0); } 10 early() { if (p1.selfingRate == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSelfingRate(0.5); } 10 early() { if (p1.selfingRate == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSelfingRate(1.0); } 10 early() { if (p1.selfingRate == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSelfingRate(-0.001); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSelfingRate(1.001); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setSelfingRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t// we permit this, since a rate of 0.0 makes sense even in sexual sims\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setSelfingRate(0.1); stop(); }\", \"cannot be called in sexual simulations\", __LINE__);\n\t\n\t// Test Subpopulation - (void)setSexRatio(float$ sexRatio)\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSexRatio(0.0); stop(); }\", \"cannot be called in asexual simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSexRatio(0.1); stop(); }\", \"cannot be called in asexual simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(0.0); } 10 early() { if (p1.sexRatio == 0.0) stop(); }\", \"produced no males\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(0.1); } 10 early() { if (p1.sexRatio == 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(0.5); } 10 early() { if (p1.sexRatio == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(0.9); } 10 early() { if (p1.sexRatio == 0.9) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(1.0); } 10 early() { if (p1.sexRatio == 1.0) stop(); }\", \"produced no females\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(-0.001); }\", \"within [0,1]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(1.001); }\", \"within [0,1]\", __LINE__);\n\t\n\t// Test Subpopulation - (void)setSubpopulationSize(integer$ size)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(0); if (p1.individualCount == 10) stop(); }\", \"undefined identifier\", __LINE__);\t\t// the symbol is undefined immediately\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { px=p1; p1.setSubpopulationSize(0); if (px.individualCount == 10) stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// does not take visible effect until generating children\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(0); } 2 early() { if (p1.individualCount == 0) stop(); }\", \"undefined identifier\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(20); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(20); if (p1.individualCount == 10) stop(); }\", __LINE__);\t\t\t\t\t// does not take visible effect until generating children\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(20); } 2 early() { if (p1.individualCount == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(-1); stop(); }\", \"out of range\", __LINE__);\n\t\n\t// Test Subpopulation EidosDictionaryUnretained functionality: - (+)getValue(is$ key) and - (void)setValue(is$ key, + value)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setValue('foo', 7:9); p1.setValue('bar', 'baz'); } 10 early() { if (identical(p1.getValue('foo'), 7:9) & identical(p1.getValue('bar'), 'baz')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setValue('foo', 3:5); p1.setValue('foo', 'foobar'); } 10 early() { if (identical(p1.getValue('foo'), 'foobar')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.setValue('foo', 3:5); p1.setValue('foo', NULL); } 10 early() { if (isNULL(p1.getValue('foo'))) stop(); }\", __LINE__);\n\t\n\t// Test spatial stuff including spatialBounds, setSpatialBounds(), pointInBounds(), pointPeriodic(), pointReflected(), pointStopped(), pointUniform()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(p1.spatialBounds, float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.spatialBounds = 0.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.setSpatialBounds(-2.0); stop(); }\", \"setSpatialBounds() cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.pointInBounds(-2.0); stop(); }\", \"pointInBounds() cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.pointPeriodic(-2.0); stop(); }\", \"pointPeriodic() cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.pointReflected(-2.0); stop(); }\", \"pointReflected() cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.pointStopped(-2.0); stop(); }\", \"pointStopped() cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.pointUniform(); stop(); }\", \"pointUniform() cannot be called in non-spatial simulations\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.pointInBounds(float(0)), logical(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.pointReflected(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.pointStopped(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 7.5)); if (identical(p1.pointPeriodic(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.pointUniform(0), float(0))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (identical(p1.spatialBounds, c(0.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.spatialBounds, c(-2.0, 7.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(-2.0); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 1.0, 1.0)); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(-2.1) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(-2.0) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(0.0) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(7.5) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(7.6) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (p1.pointInBounds(11.0, 0.0) == F) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-2.0, 7.5)); if (identical(p1.pointInBounds(c(11.0, 0.0)), c(F,T))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(-15.5) == -0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(-5.5) == -4.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(-5.0) == -5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(2.0) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(2.5) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(3.5) == 1.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(11.0) == -4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointReflected(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (identical(p1.pointReflected(c(-15.5, -5.5, 2.0, 3.5)), c(-0.5, -4.5, 2.0, 1.5))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(-15.5) == -5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(-5.5) == -5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(-5.0) == -5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(2.0) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(2.5) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(3.5) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(11.0) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointStopped(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (identical(p1.pointStopped(c(-15.5, -5.5, 2.0, 3.5)), c(-5.0, -5.0, 2.0, 2.5))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (size(p1.pointUniform()) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (size(p1.pointUniform(1)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (size(p1.pointUniform(5)) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointPeriodic(-15.5) == -0.5) stop(); }\", \"no periodic spatial dimension\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(-5.0, 2.5)); if (p1.pointPeriodic(-15.5) == -0.5) stop(); }\", \"requires min coordinates to be 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(-0.5) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(-5.5) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(2.0) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(2.5) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(3.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(11.0) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (p1.pointPeriodic(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { p1.setSpatialBounds(c(0.0, 2.5)); if (identical(p1.pointPeriodic(c(-0.5, -5.5, 0.0, 2.5, 3.5)), c(2.0, 2.0, 0.0, 2.5, 1.0))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.pointInBounds(float(0)), logical(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.pointReflected(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.pointStopped(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 7.5, 4.5)); if (identical(p1.pointPeriodic(float(0)), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.pointUniform(0), float(0))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { if (identical(p1.spatialBounds, c(0.0, 0.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.spatialBounds, c(-2.0, 1.5, 7.5, 4.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5)); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 0.0, 1.0, 1.0, 1.0)); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(-2.1, 2.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(-2.0, 2.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(0.0, 1.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(0.0, 1.5)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(0.0, 2.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(0.0, 4.5)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(0.0, 4.6)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(7.5, 2.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(7.6, 2.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (p1.pointInBounds(c(11.0, 0.0, 0.0)) == F) stop(); }\", \"exact multiple\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-2.0, 1.5, 7.5, 4.5)); if (identical(p1.pointInBounds(c(-2.1, 2.0, 7.5, 2.0)), c(F,T))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(-15.5, 11)), c(-0.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(-5.5, 11)), c(-4.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(-5.0, 11)), c(-5.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.0, 9.5)), c(2.0, 11.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.0, 10.5)), c(2.0, 10.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.0, 11)), c(2.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.0, 12.0)), c(2.0, 12.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.0, 13.25)), c(2.0, 10.75))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(2.5, 11)), c(2.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(3.5, 11)), c(1.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(11.0, 11)), c(-4.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(11.0, 0.0, 0.0)), c(-4.0, 11))) stop(); }\", \"exact multiple\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointReflected(c(-15.5, 11, 2.0, 13.25)), c(-0.5, 11, 2.0, 10.75))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(-15.5, 11)), c(-5.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(-5.5, 11)), c(-5.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(-5.0, 11)), c(-5.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.0, 9.5)), c(2.0, 10.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.0, 10.5)), c(2.0, 10.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.0, 11)), c(2.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.0, 12.0)), c(2.0, 12.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.0, 13.25)), c(2.0, 12.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(2.5, 11)), c(2.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(3.5, 11)), c(2.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(11.0, 11)), c(2.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(11.0, 0.0, 0.0)), c(-4.0, 11))) stop(); }\", \"exact multiple\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointStopped(c(-15.5, 11, 2.0, 13.25)), c(-5.0, 11, 2.0, 12.0))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (size(p1.pointUniform()) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (size(p1.pointUniform(1)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (size(p1.pointUniform(5)) == 10) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(-15.5, 0.0)), c(-0.5, 11))) stop(); }\", \"no periodic spatial dimension\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(-5.0, 10.5, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(-15.5, 0.0)), c(-0.5, 11))) stop(); }\", \"requires min coordinates to be 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(-0.5, 11)), c(2.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(-5.5, 11)), c(2.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(0.0, 11)), c(0.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(2.0, -1.5)), c(2.0, 10.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(2.0, 11)), c(2.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(2.0, 14.25)), c(2.0, 2.25))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(2.5, 11)), c(2.5, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(3.5, 11)), c(1.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(11.0, 11)), c(1.0, 11))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(11.0, 0.0, 0.0)), c(-4.0, 11))) stop(); }\", \"exact multiple\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 2.5, 12.0)); if (identical(p1.pointPeriodic(c(-0.5, 11, 2.0, -1.5)), c(2.0, 11, 2.0, 10.5))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { if (identical(p1.spatialBounds, c(0.0, 0.0, 0.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.setSpatialBounds(c(-2.0, -100, 10.0, 7.5, -99.5, 12.0)); if (identical(p1.spatialBounds, c(-2.0, -100, 10.0, 7.5, -99.5, 12.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.setSpatialBounds(-2.0); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 1.0, 1.0)); stop(); }\", \"requires twice as many coordinates\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_bounds(gen1_setup_i1xyz + \"1 early() { p1.setSpatialBounds(c(-10.0, 0.0, 10.0,    -9.0, 2.0, 13.0)); \");\n\tstd::string gen1_setup_i1xyzPxz_bounds(gen1_setup_i1xyzPxz + \"1 early() { p1.setSpatialBounds(c(0.0, 0.0, 0.0,    9.0, 2.0, 13.0)); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-10.1, 1.0, 11.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 1.0, 11.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-8.0, 1.0, 11.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, -1.0, 11.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 1.0, 11.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 3.0, 11.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 1.0, 9.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 1.0, 11.0)) == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(-9.5, 1.0, 14.0)) == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(11.0, 0.0) == F) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointInBounds(c(11.0, 0.0)) == F) stop(); }\", \"requires the length of point\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointInBounds(c(-10.1, 1.0, 11.0, -9.5, 1.0, 11.0)), c(F, T))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-10.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-8.0, 1.0, 11.0)), c(-10.0, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, -1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 2.5, 11.0)), c(-9.5, 1.5, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 1.0, 4.5)), c(-9.5, 1.0, 10.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-9.5, 1.0, 14.5)), c(-9.5, 1.0, 11.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointReflected(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointReflected(c(11.0, 0.0)) == -4.0) stop(); }\", \"requires the length of point\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointReflected(c(-10.5, -1.0, 4.5, -8.0, 2.5, 14.5)), c(-9.5, 1.0, 10.5, -10.0, 1.5, 11.5))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-10.5, 1.0, 11.0)), c(-10.0, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-8.0, 1.0, 11.0)), c(-9.0, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, -1.0, 11.0)), c(-9.5, 0.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 2.5, 11.0)), c(-9.5, 2.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 1.0, 4.5)), c(-9.5, 1.0, 10.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 1.0, 11.0)), c(-9.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-9.5, 1.0, 14.5)), c(-9.5, 1.0, 13.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointStopped(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_bounds + \"if (p1.pointStopped(c(11.0, 0.0)) == -4.0) stop(); }\", \"requires the length of point\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (identical(p1.pointStopped(c(-10.5, -1.0, 4.5, -8.0, 2.5, 14.5)), c(-10.0, 0.0, 10.0, -9.0, 2.0, 13.0))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (size(p1.pointUniform()) == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (size(p1.pointUniform(1)) == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_bounds + \"if (size(p1.pointUniform(5)) == 15) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-10.5, 1.0, 11.0)), c(7.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 1.0, 11.0)), c(8.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-8.0, 1.0, 11.0)), c(1.0, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, -1.0, 11.0)), c(8.5, -1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 1.0, 11.0)), c(8.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 2.5, 11.0)), c(8.5, 2.5, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 1.0, 4.5)), c(8.5, 1.0, 4.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 1.0, 11.0)), c(8.5, 1.0, 11.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-9.5, 1.0, 14.5)), c(8.5, 1.0, 1.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyzPxz_bounds + \"if (p1.pointPeriodic(11.0, 0.0) == -4.0) stop(); }\", \"too many arguments supplied\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyzPxz_bounds + \"if (p1.pointPeriodic(c(11.0, 0.0)) == -4.0) stop(); }\", \"requires the length of point\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyzPxz_bounds + \"if (identical(p1.pointPeriodic(c(-10.5, -1.0, 4.5, -8.0, 2.5, 14.5)), c(7.5, -1.0, 4.5, 1.0, 2.5, 1.5))) stop(); }\", __LINE__);\n\t\n\t// Test spatial stuff including defineSpatialMap(), spatialMapColor(), and spatialMapValue()\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', c(0.0, 1.0)); stop(); }\", \"spatial dimensions beyond those set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.spatialMapColor('m', 0.5); stop(); }\", \"could not find map\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.spatialMapValue('m', float(0)); stop(); }\", \"could not find map\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.spatialMapValue('m', 0.0); stop(); }\", \"could not find map\", __LINE__);\n\t\n\t// Test that permutations of defineSpatialMap() that include the old gridSize parameter get a helpful error message\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', gridSize=2, c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', NULL, c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, values=c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), interpolate=T); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), T); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), T, valueRange=c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), T, c(0.0, 1.0)); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), T, c(0.0, 1.0), colors=c('red','blue')); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.defineSpatialMap('map', 'x', 2, c(0.0, 1.0), T, c(0.0, 1.0), c('red','blue')); stop(); }\", \"changed in SLiM 3.5\", __LINE__);\n\t\n\t// a few tests supplying a matrix/array spatial map instead of a vector; no need to test spatialMapValue() etc. with these,\n\t// since it all funnels into the same map definition code anyway, so we just need to be sure the pre-funnel code is good...\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xy', matrix(1.0:4, nrow=2)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xy', matrix(1.0:9, nrow=3)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xy', matrix(1.0:6, nrow=2)); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(1.0:4, nrow=2)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(1.0:9, nrow=3)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(1.0:6, nrow=2)); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(1.0:8, c(2,2,2))); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(1.0:27, c(3,3,3))); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(1.0:12, c(2,3,2))); stop(); }\", __LINE__);\n\t\n\t// 1D sim with 1D x map\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', 'xy', c(0.0, 1.0)); stop(); }\", \"does not match the spatiality defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', 'xy', matrix(1.0:4, nrow=2)); stop(); }\", \"spatial dimensions beyond those set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', 'x', 0.0); stop(); }\", \"must be of size >= 2\", __LINE__);\n\t\n\tstd::string gen1_setup_i1x_mapNI(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', 'x', c(0.0, 1.0, 3.0), interpolate=F, valueRange=c(-5.0, 5.0), colors=c('black', 'white')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.2) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.3) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.7) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 0.8) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapColor('map', -5.0) == '#000000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapColor('map', -2.5) == '#404040') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapColor('map', 0.0001) == '#808080') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapColor('map', 2.5) == '#BFBFBF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapNI + \"if (p1.spatialMapColor('map', 5.0) == '#FFFFFF') stop(); }\", __LINE__);\n\t\n\tstd::string gen1_setup_i1x_mapI(gen1_setup_i1x + \"1 early() { p1.defineSpatialMap('map', 'x', c(0.0, 1.0, 3.0), interpolate=T, valueRange=c(-5.0, 5.0), colors=c('#FF003F', '#007F00', '#00FFFF')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 0.25) == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 0.75) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapColor('map', -5.0) == '#FF003F') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapColor('map', -2.5) == '#804020') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapColor('map', 0.0001) == '#007F00') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapColor('map', 2.5) == '#00BF80') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x_mapI + \"if (p1.spatialMapColor('map', 5.0) == '#00FFFF') stop(); }\", __LINE__);\n\t\n\t// 3D sim with 1D x map\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'x', 0.0); stop(); }\", \"must be of size >= 2\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapNIx(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'x', c(0.0, 1.0, 3.0), interpolate=F, valueRange=c(-5.0, 5.0), colors=c('black', 'white')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.2) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.3) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.7) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 0.8) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapColor('map', -5.0) == '#000000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapColor('map', -2.5) == '#404040') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapColor('map', 0.0001) == '#808080') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapColor('map', 2.5) == '#BFBFBF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIx + \"if (p1.spatialMapColor('map', 5.0) == '#FFFFFF') stop(); }\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapIx(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'x', c(0.0, 1.0, 3.0), interpolate=T, valueRange=c(-5.0, 5.0), colors=c('#FF003F', '#007F00', '#00FFFF')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 0.25) == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 0.75) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapColor('map', -5.0) == '#FF003F') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapColor('map', -2.5) == '#804020') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapColor('map', 0.0001) == '#007F00') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapColor('map', 2.5) == '#00BF80') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIx + \"if (p1.spatialMapColor('map', 5.0) == '#00FFFF') stop(); }\", __LINE__);\n\t\n\t// 3D sim with 1D z map\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'z', 0.0); stop(); }\", \"must be of size >= 2\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapNIz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'z', c(0.0, 1.0, 3.0), interpolate=F, valueRange=c(-5.0, 5.0), colors=c('black', 'white')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.2) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.3) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.7) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 0.8) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapColor('map', -5.0) == '#000000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapColor('map', -2.5) == '#404040') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapColor('map', 0.0001) == '#808080') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapColor('map', 2.5) == '#BFBFBF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIz + \"if (p1.spatialMapColor('map', 5.0) == '#FFFFFF') stop(); }\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapIz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'z', c(0.0, 1.0, 3.0), interpolate=T, valueRange=c(-5.0, 5.0), colors=c('#FF003F', '#007F00', '#00FFFF')); \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', -9.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 0.0) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 0.25) == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 0.5) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 0.75) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 1.0) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapValue('map', 9.0) == 3.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapColor('map', -5.0) == '#FF003F') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapColor('map', -2.5) == '#804020') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapColor('map', 0.0001) == '#007F00') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapColor('map', 2.5) == '#00BF80') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIz + \"if (p1.spatialMapColor('map', 5.0) == '#00FFFF') stop(); }\", __LINE__);\n\t\n\t// 3D sim with 2D xz map; note that these tests were designed with the old matrix interpretation, so now a transpose/flip is needed to make them match\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', 0.0); stop(); }\", \"does not match the spatiality defined for the map\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(0.0)); stop(); }\", \"must be of size >= 2\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapNIxz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(c(0.0, 1, 3, 5, 5, 5), ncol=3, byrow=T)[1:0,], interpolate=F, valueRange=c(-5.0, 5.0), colors=c('black', 'white')); \");\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_mapNIxz + \"p1.spatialMapValue('map', 0.0); stop(); }\", \"must match spatiality of map\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(-9.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.2, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.3, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.5, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.7, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.8, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(1.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(9.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(-9.0, 0.2)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.0, 0.2)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.2, 0.2)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.3, 0.2)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.5, 0.2)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.7, 0.2)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.8, 0.2)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(1.0, 0.2)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(9.0, 0.2)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(-9.0, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.0, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.2, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.3, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.5, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.7, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.8, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(1.0, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(9.0, 0.8)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(-9.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.2, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.3, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.5, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.7, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(0.8, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(1.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapValue('map', c(9.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapColor('map', -5.0) == '#000000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapColor('map', -2.5) == '#404040') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapColor('map', 0.0001) == '#808080') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapColor('map', 2.5) == '#BFBFBF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxz + \"if (p1.spatialMapColor('map', 5.0) == '#FFFFFF') stop(); }\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapIxz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xz', matrix(c(0.0, 1, 3, 5, 5, 5), ncol=3, byrow=T)[1:0,], interpolate=T, valueRange=c(-5.0, 5.0), colors=c('#FF003F', '#007F00', '#00FFFF')); \");\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_mapIxz + \"p1.spatialMapValue('map', 0.0); stop(); }\", \"must match spatiality of map\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(-9.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.25, 0.0)) == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.5, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.75, 0.0)) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(1.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(9.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(-9.0, 0.5)) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.0, 0.5)) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.25, 0.5)) == 2.75) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.5, 0.5)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.75, 0.5)) == 3.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(1.0, 0.5)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(9.0, 0.5)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(-9.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.25, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.5, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(0.75, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(1.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapValue('map', c(9.0, 1.0)) == 5.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapColor('map', -5.0) == '#FF003F') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapColor('map', -2.5) == '#804020') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapColor('map', 0.0001) == '#007F00') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapColor('map', 2.5) == '#00BF80') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxz + \"if (p1.spatialMapColor('map', 5.0) == '#00FFFF') stop(); }\", __LINE__);\n\t\n\t// 3D sim with 3D xyz map; note that these tests were designed with the old matrix interpretation, so now a transpose/flip is needed to make them match\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', '', float(0)); stop(); }\", \"spatiality '' must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', 0.0); stop(); }\", \"does not match the spatiality defined for the map\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(0.0, c(1,1,1))); stop(); }\", \"must be of size >= 2\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapNIxyz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(c(3.0, 0, 4, 1, 5, 2, 9, 6, 10, 7, 11, 8), c(2,3,2)), interpolate=F, valueRange=c(-5.0, 5.0), colors=c('black', 'white')); \");\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_mapNIxyz + \"p1.spatialMapValue('map', 0.0); stop(); }\", \"must match spatiality of map\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 0.0)) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.8, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.8, 0.0)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.8, 0.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 0.0)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 0.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 0.6)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 0.6)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 0.6)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.2, 0.6)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.2, 0.6)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.2, 0.6)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 0.6)) == 9.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 0.6)) == 10.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 0.6)) == 11.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 1.0)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 1.0)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 1.0)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.2, 1.0)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.2, 1.0)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.2, 1.0)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 1.0)) == 9.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 1.0)) == 10.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 1.0)) == 11.0) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapColor('map', -5.0) == '#000000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapColor('map', -2.5) == '#404040') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapColor('map', 0.0001) == '#808080') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapColor('map', 2.5) == '#BFBFBF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapNIxyz + \"if (p1.spatialMapColor('map', 5.0) == '#FFFFFF') stop(); }\", __LINE__);\n\t\n\tstd::string gen1_setup_i1xyz_mapIxyz(gen1_setup_i1xyz + \"1 early() { p1.defineSpatialMap('map', 'xyz', array(c(3.0, 0, 4, 1, 5, 2, 9, 6, 10, 7, 11, 8), c(2,3,2)), interpolate=T, valueRange=c(-5.0, 5.0), colors=c('#FF003F', '#007F00', '#00FFFF')); \");\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_mapIxyz + \"p1.spatialMapValue('map', 0.0); stop(); }\", \"must match spatiality of map\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 0.0)) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 0.0)) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 0.0)) == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.5, 0.0)) == 1.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.5, 0.0)) == 2.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.5, 0.0)) == 3.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 0.0)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 0.0)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 0.0)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 0.5)) == 3.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 0.5)) == 4.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 0.5)) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.5, 0.5)) == 4.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.5, 0.5)) == 5.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.5, 0.5)) == 6.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 0.5)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 0.5)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 0.5)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.0, 1.0)) == 6.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.0, 1.0)) == 7.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.0, 1.0)) == 8.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 0.5, 1.0)) == 7.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 0.5, 1.0)) == 8.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 0.5, 1.0)) == 9.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.0, 1.0, 1.0)) == 9.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(0.5, 1.0, 1.0)) == 10.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapValue('map', c(1.0, 1.0, 1.0)) == 11.0) stop(); }\", __LINE__);\n\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapColor('map', -5.0) == '#FF003F') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapColor('map', -2.5) == '#804020') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapColor('map', 0.0001) == '#007F00') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapColor('map', 2.5) == '#00BF80') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_mapIxyz + \"if (p1.spatialMapColor('map', 5.0) == '#00FFFF') stop(); }\", __LINE__);\n}\n\n#pragma mark Individual tests\nvoid _RunIndividualTests(void)\n{\t\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Individual\n\t//\n\t\n\t// Test Individual properties\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (all(i.color == '')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome1) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome2) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (size(i.haplosomes) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (size(i.haplosomesNonNull) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome1, i.haplosomes[0:9 * 2])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome2, i.haplosomes[0:9 * 2 + 1])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (all(i.index == (0:9))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (all(i.subpopulation == rep(p1, 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (all(i.sex == rep('H', 10))) stop(); }\", __LINE__);\n#ifdef SLIMGUI\n\t// the color property is only functional under SLiMgui now\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.color = 'red'; if (all(i.color == '#FF0000')) stop(); }\", __LINE__);\n#endif\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tag = 135; if (all(i.tag == 135)) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagF; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF = 135.0; if (all(i.tagF == 135.0)) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagL0; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL0; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL0 = T; if (all(i.tagL0 == T)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL0 = F; if (all(i.tagL0 == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL0 = rep(c(T,F),5); if (sum(i.tagL0) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagL1; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL1; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL1 = T; if (all(i.tagL1 == T)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL1 = F; if (all(i.tagL1 == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL1 = rep(c(T,F),5); if (sum(i.tagL1) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagL2; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL2; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL2 = T; if (all(i.tagL2 == T)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL2 = F; if (all(i.tagL2 == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL2 = rep(c(T,F),5); if (sum(i.tagL2) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagL3; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL3; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL3 = T; if (all(i.tagL3 == T)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL3 = F; if (all(i.tagL3 == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL3 = rep(c(T,F),5); if (sum(i.tagL3) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i[0].tagL4; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL4; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL4 = T; if (all(i.tagL4 == T)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL4 = F; if (all(i.tagL4 == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagL4 = rep(c(T,F),5); if (sum(i.tagL4) == 5) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (size(i.migrant) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; if (all(i.migrant == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = 135.0; if (all(i.fitnessScaling == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = 0.0; if (all(i.fitnessScaling == 0.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = -0.01; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = NAN; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = 135.0; if (all(i.x == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.y = 135.0; if (all(i.y == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.z = 135.0; if (all(i.z == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.uniqueMutations; stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.haploidGenome1 = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.haploidGenome2 = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.haplosomes = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.haplosomesNonNull = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.index = i[0].index; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.subpopulation = i[0].subpopulation; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.sex = i[0].sex; stop(); }\", \"read-only property\", __LINE__);\n\t//SLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.uniqueMutations = sim.mutations[0]; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (all(i.color == '')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome1) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome1NonNull) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome2) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haploidGenome2NonNull) == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haplosomes) == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.haplosomesNonNull) == 15) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome1, i.haplosomes[0:9 * 2])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome1NonNull, i.haplosomes[0:9 * 2])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome2, i.haplosomes[0:9 * 2 + 1])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (identical(i.haploidGenome2NonNull, i.haplosomes[0:4 * 2 + 1])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (all(i.index == (0:9))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (all(i.subpopulation == rep(p1, 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (all(i.sex == repEach(c('F','M'), 5))) stop(); }\", __LINE__);\n#ifdef SLIMGUI\n\t// the color property is only functional under SLiMgui now\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.color = 'red'; if (all(i.color == '#FF0000')) stop(); }\", __LINE__);\n#endif\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i[0].tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.tag = 135; if (all(i.tag == 135)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i[0].tagF; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.tagF; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.tagF = 135.0; if (all(i.tagF == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (size(i.migrant) == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; if (all(i.migrant == F)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = 135.0; if (all(i.fitnessScaling == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = 0.0; if (all(i.fitnessScaling == 0.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = -0.01; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = NAN; }\", \"must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.x = 135.0; if (all(i.x == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.y = 135.0; if (all(i.y == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.z = 135.0; if (all(i.z == 135.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 early() { i = p1.individuals; i.uniqueMutations; stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.haploidGenome1 = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.haploidGenome2 = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.haplosomes = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.haplosomesNonNull = i[0].haplosomes[0]; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.index = i[0].index; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.subpopulation = i[0].subpopulation; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"1 early() { i = p1.individuals; i.sex = i[0].sex; stop(); }\", \"read-only property\", __LINE__);\n\t//SLiMAssertScriptRaise(gen1_setup_sex_p1 + \"10 early() { i = p1.individuals; i.uniqueMutations = sim.mutations[0]; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = 0.5; if (identical(i.spatialPosition, rep(0.5, 10))) stop(); }\", \"position cannot be accessed\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.x = 0.5; if (identical(i.spatialPosition, rep(0.5, 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.x = 0.5; i.y = 0.6; if (identical(i.spatialPosition, rep(c(0.5, 0.6), 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.x = 0.5; i.y = 0.6; i.z = 0.7; if (identical(i.spatialPosition, rep(c(0.5, 0.6, 0.7), 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.spatialPosition = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.spatialPosition = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.spatialPosition = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.spatialPosition = 0.5; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.setSpatialPosition(0.5); stop(); }\", \"cannot be called in non-spatial simulations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(float(0)); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(0.5); if (identical(i[0].spatialPosition, 0.5)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(c(0.5, 0.6)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.setSpatialPosition(float(0)); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.setSpatialPosition(0.5); if (identical(i.spatialPosition, rep(0.5, 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.setSpatialPosition(c(0.5, 0.6)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i = p1.individuals; i.setSpatialPosition((1:10) / 10.0); if (identical(i.spatialPosition, (1:10) / 10.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(0.5); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(c(0.5, 0.6)); if (identical(i[0].spatialPosition, c(0.5, 0.6))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(c(0.5, 0.6, 0.7)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.setSpatialPosition(0.5); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.setSpatialPosition(c(0.5, 0.6)); if (identical(i.spatialPosition, rep(c(0.5, 0.6), 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.setSpatialPosition(c(0.5, 0.6, 0.7)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.setSpatialPosition(1.0:20); if (identical(i.spatialPosition, 1.0:20)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i = p1.individuals; i.setSpatialPosition(1.0:20); if (identical(i.y, (1.0:10)*2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(0.5); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(c(0.5, 0.6, 0.7)); if (identical(i[0].spatialPosition, c(0.5, 0.6, 0.7))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i[0].setSpatialPosition(c(0.5, 0.6, 0.7, 0.8)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.setSpatialPosition(0.5); }\", \"requires at least as many coordinates\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.setSpatialPosition(c(0.5, 0.6, 0.7)); if (identical(i.spatialPosition, rep(c(0.5, 0.6, 0.7), 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.setSpatialPosition(c(0.5, 0.6, 0.7, 0.8)); }\", \"position parameter to contain\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.setSpatialPosition(1.0:30); if (identical(i.spatialPosition, 1.0:30)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz + \"1 early() { i = p1.individuals; i.setSpatialPosition(1.0:30); if (identical(i.z, (1.0:10)*3)) stop(); }\", __LINE__);\n\t\n\t// Some specific testing for setting of accelerated properties\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tag = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tag = asInteger(seqAlong(i) % 2 == 0); if (all(i.tag == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tag = seqAlong(i); if (all(i.tag == seqAlong(i))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF = asFloat(seqAlong(i) % 2 == 0); if (all(i.tagF == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF = seqAlong(i); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.tagF = asFloat(seqAlong(i)); if (all(i.tagF == seqAlong(i))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = asFloat(seqAlong(i) % 2 == 0); if (all(i.fitnessScaling == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = seqAlong(i); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.fitnessScaling = asFloat(seqAlong(i)); if (all(i.fitnessScaling == seqAlong(i))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = asFloat(seqAlong(i) % 2 == 0); if (all(i.x == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = seqAlong(i); if (all(i.x == seqAlong(i))) stop(); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.x = asFloat(seqAlong(i)); if (all(i.x == seqAlong(i))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.y = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.y = asFloat(seqAlong(i) % 2 == 0); if (all(i.y == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.y = seqAlong(i); if (all(i.y == seqAlong(i))) stop(); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.y = asFloat(seqAlong(i)); if (all(i.y == seqAlong(i))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.z = (seqAlong(i) % 2 == 0); }\", \"cannot be type logical\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.z = asFloat(seqAlong(i) % 2 == 0); if (all(i.z == (seqAlong(i) % 2 == 0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.z = seqAlong(i); if (all(i.z == seqAlong(i))) stop(); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.z = asFloat(seqAlong(i)); if (all(i.z == seqAlong(i))) stop(); }\", __LINE__);\n#ifdef SLIMGUI\n\t// the color property is only functional under SLiMgui now\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals; i.color = format('#%.6X', seqAlong(i)); if (all(i.color == format('#%.6X', seqAlong(i)))) stop(); }\", __LINE__);\n#endif\n\t\n\t// Test Individual - (logical)containsMutations(object<Mutation> mutations)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.containsMutations(object()); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.containsMutations(sim.mutations); stop(); }\", __LINE__);\n\t\n\t// Test Individual - (integer$)countOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.countOfMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.countOfMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i[0:1].countOfMutationsOfType(1); stop(); }\", __LINE__);\n\t\n\t// Test Individual - (float$)sumOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.sumOfMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.sumOfMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i[0:1].sumOfMutationsOfType(1); stop(); }\", __LINE__);\n\t\n\t// Test Individual - (object<Mutation>)uniqueMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.uniqueMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i.uniqueMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { i = p1.individuals; i[0:1].uniqueMutationsOfType(1); stop(); }\", __LINE__);\n\t/*\n\t Positions are tested with identical() instead of the mutation vectors themselves, only because the sorted order of mutations\n\t at exactly the same position may differ; identical(um1, um2) will occasionally flag these as false positives.\n\t */\n\tSLiMAssertScriptSuccess(R\"V0G0N(\n\t\tinitialize() {\n\t\t\tinitializeMutationRate(1e-5);\n\t\t\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\t\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t\tinitializeGenomicElement(g1, 0, 99999);\n\t\t\tinitializeRecombinationRate(1e-8);\n\t\t}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 500);\n\t\t}\n\t\t1:200 late() {\n\t\t\tfor (i in p1.individuals) {\n\t\t\t\tum1 = i.uniqueMutations;\n\t\t\t\tum2 = sortBy(unique(i.haplosomes.mutations), \"position\");\n\t\t\t\tif (!identical(um1.position, um2.position))\n\t\t\t\t\tstop(\"Mismatch!\");\n\t\t\t}\n\t\t})V0G0N\");\n\t\n\t// Test optional pedigree stuff; note that relatedness can be higher than 0.5 due to inbreeding, even if preventIncidentalSelfing=T were set\n\t// see the model test_relatedness.slim (not in the GitHub repo) for more precise tests that relatedness() does the right calculations\n\tstd::string gen1_setup_norel(\"initialize() { initializeSLiMOptions(keepPedigrees=F); initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } \");\n\tstd::string gen1_setup_rel(\"initialize() { initializeSLiMOptions(keepPedigrees=T); initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } \");\n\tstd::string gen1_setup_rel_S(\"initialize() { initializeSLiMOptions(keepPedigrees=T); initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeSex('A'); } 1 early() { sim.addSubpop('p1', 10); } \");\n\t\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (all(p1.individuals.pedigreeID == -1)) stop(); }\", \"is not available\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (all(p1.individuals.pedigreeParentIDs == -1)) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (all(p1.individuals.pedigreeGrandparentIDs == -1)) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (all(p1.individuals.reproductiveOutput == 0)) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (p1.individuals[0].reproductiveOutput == 0) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (mean(p1.lifetimeReproductiveOutput) > 0) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (mean(p1.lifetimeReproductiveOutputM) > 0) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (mean(p1.lifetimeReproductiveOutputF) > 0) stop(); }\", \"has not been enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_rel + \"5 early() { if (mean(p1.lifetimeReproductiveOutputM) > 0) stop(); }\", \"separate sexes are not enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_rel + \"5 early() { if (mean(p1.lifetimeReproductiveOutputF) > 0) stop(); }\", \"separate sexes are not enabled\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_norel + \"5 early() { if (all(p1.individuals.haplosomes.haplosomePedigreeID == -1)) stop(); }\", \"is not available\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (p1.individuals[0].relatedness(p1.individuals[0]) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (p1.individuals[0].sharedParentCount(p1.individuals[0]) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (p1.individuals[0].relatedness(p1.individuals[1]) == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (p1.individuals[0].sharedParentCount(p1.individuals[1]) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (all(p1.individuals[0].relatedness(p1.individuals[1:9]) == 0.0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_norel + \"5 early() { if (all(p1.individuals[0].sharedParentCount(p1.individuals[1:9]) == 0)) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals.pedigreeID != -1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals.pedigreeParentIDs != -1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals.pedigreeGrandparentIDs != -1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals.reproductiveOutput == 0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (p1.individuals[0].reproductiveOutput == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (mean(p1.lifetimeReproductiveOutput) > 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel_S + \"5 early() { if (mean(p1.lifetimeReproductiveOutput) > 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel_S + \"5 early() { if (mean(p1.lifetimeReproductiveOutputM) > 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel_S + \"5 early() { if (mean(p1.lifetimeReproductiveOutputF) > 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals.haplosomes.haplosomePedigreeID != -1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (p1.individuals[0].relatedness(p1.individuals[0]) == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (p1.individuals[0].sharedParentCount(p1.individuals[0]) == 2) stop(); }\", __LINE__);\n\t// In certain inbreeding scenarios, which can happen by chance, relatedness of individuals can be 1.0 (maybe even higher?) so these tests are no good\n\t//SLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (p1.individuals[0].relatedness(p1.individuals[1]) < 1.0) stop(); }\", __LINE__);\n\t//SLiMAssertScriptStop(gen1_setup_rel + \"5 early() { if (all(p1.individuals[0].relatedness(p1.individuals[1:9]) < 1.0)) stop(); }\", __LINE__);\n\t\n\t// Test Individual EidosDictionaryUnretained functionality: - (+)getValue(is$ key) and - (void)setValue(is$ key, + value)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals[0]; i.setValue('foo', 7:9); i.setValue('bar', 'baz'); if (identical(i.getValue('foo'), 7:9) & identical(i.getValue('bar'), 'baz')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals[0]; i.setValue('foo', 3:5); i.setValue('foo', 'foobar'); if (identical(i.getValue('foo'), 'foobar')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { i = p1.individuals[0]; i.setValue('foo', 3:5); i.setValue('foo', NULL); if (isNULL(i.getValue('foo'))) stop(); }\", __LINE__);\n}\n\n#pragma mark SLiMEidosBlock tests\nvoid _RunSLiMEidosBlockTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: SLiMEidosBlock\n\t//\n\t\n\t// Test SLiMEidosBlock properties\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.active == -1) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.end == 4) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.id == 1) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.source == '{ sim = 10; }') stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.start == 2) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.type == 'early') stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.type == 'early') stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (s1.type == 'late') stop(); } s1 2:4 late() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { s1.active = 198; if (s1.active == 198) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.end = 4; stop(); } s1 2:4 early() { sim = 10; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.id = 1; stop(); } s1 2:4 early() { sim = 10; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.source = '{ sim = 10; }'; stop(); } s1 2:4 early() { sim = 10; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.start = 2; stop(); } s1 2:4 early() { sim = 10; } \", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.tag; } s1 2:4 early() { sim = 10; } \", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { c(s1,s1).tag; } s1 2:4 early() { sim = 10; } \", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { s1.tag = 219; if (s1.tag == 219) stop(); } s1 2:4 early() { sim = 10; } \", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { s1.type = 'event'; stop(); } s1 2:4 early() { sim = 10; } \", \"read-only property\", __LINE__);\n\t\n\t// No methods on SLiMEidosBlock\n\t\n\t// Test user-defined functions in SLiM; there is a huge amount more that could be tested, but these get tested by EidosScribe too,\n\t// so mostly we just need to make sure here that they get declared and defined properly in SLiM, and are callable.\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"function (i)A(i x) {return x*2;} 1 early() { if (A(2) == 4) stop(); } 10 early() {  } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"function (i)A(i x) {return B(x)+1;} function (i)B(i x) {return x*2;} 1 early() { if (A(2) == 5) stop(); } 10 early() {  } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"function (i)fac([i b=10]) { if (b <= 1) return 1; else return b*fac(b-1); } 1 early() { if (fac(5) == 120) stop(); } 10 early() {  } \", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"function (i)spsize(o<Subpopulation>$ sp) { return sp.individualCount; } 2 early() { if (spsize(p1) == 10) stop(); } 10 early() {  } \", __LINE__);\n\t\n\t// Test callbacks; we don't attempt to test their functionality here, just their declaration and the fact that they get called\n\t// Their actual functionality gets tested by the R test suite and the recipes; we want to probe error cases here, more\n\t// Things to be careful of: declaration syntax, return value types, special optimized cases, pseudo-parameter definitions\n\tstatic std::string gen1_setup_p1p2p3_nonWF(nonWF_prefix + \"initialize() { initializeSex(); initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); } \" + \"1 early() { sim.addSubpop('p1', 10); sim.addSubpop('p2', 10); sim.addSubpop('p3', 10); } \" + \"late() { sim.subpopulations.fitnessScaling = 20 / sim.subpopulations.individualCount; } \");\n\tstatic std::string gen1_setup_p1p2p3_nonWF_cross(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, 'F') { mate = subpop.sampleIndividuals(1, sex='M'); if (mate.size() == 1) subpop.addCrossed(individual, mate); } \");\n\tstatic std::string gen1_setup_p1p2p3_nonWF_clone(gen1_setup_p1p2p3_nonWF + \"reproduction() { subpop.addCloned(individual); } \");\n\t\n\t// fitnessEffect() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"fitnessEffect() { return 1.0; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"fitnessEffect() { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"fitnessEffect(p1) { return 1.0; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"fitnessEffect(p1) { stop(); } 100 early() { ; }\", __LINE__);\n\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"fitnessEffect(p4) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 fitnessEffect(p1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"fitnessEffect(m1) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"fitnessEffect(p1) { if (!isNULL(individual) & !isNULL(subpop)) return 1.0; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"fitnessEffect(p1) { if (!isNULL(individual) & !isNULL(subpop)) return 1.0; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"fitnessEffect(p1) { if (!isNULL(individual) & !isNULL(subpop)) return 1.0; } 100 early() { stop(); }\", __LINE__);\n\t\n\t// mutationEffect() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return effect; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutationEffect(m1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutationEffect(m1, p1) { return effect; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutationEffect(m1, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutationEffect(m2) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutationEffect(m2, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutationEffect(m1, p4) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mutationEffect(m1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mutationEffect(m1, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect() { stop(); } 100 early() { ; }\", \"mutation type id is required\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1, p1, p2) { stop(); } 100 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1, m1) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(p1) { stop(); } 100 early() { ; }\", \"identifier prefix 'm' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1, NULL) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { ; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return NULL; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return F; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return T; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return 1; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return 'a'; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { return mut; } 100 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; ; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return NULL; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return F; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return T; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return 1; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return 'a'; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutationEffect(m1) { mut; return mut; } 100 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutationEffect(m1) { if (!isNULL(mut) & !isNULL(homozygous) & !isNULL(effect) & !isNULL(individual) & !isNULL(subpop)) return effect; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"mutationEffect(m1) { if (!isNULL(mut) & !isNULL(homozygous) & !isNULL(effect) & !isNULL(individual) & !isNULL(subpop)) return effect; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"mutationEffect(m1) { if (!isNULL(mut) & !isNULL(homozygous) & !isNULL(effect) & !isNULL(individual) & !isNULL(subpop)) return effect; } 100 early() { stop(); }\", __LINE__);\n\t\n\t// mateChoice() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mateChoice() { return weights; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mateChoice() { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mateChoice(p1) { return weights; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mateChoice(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mateChoice(p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mateChoice(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(m1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1, p1) { stop(); } 10 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(NULL) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { ; } 10 early() { ; }\", \"must explicitly return a value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return F; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return T; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { return individual.haploidGenome1; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; ; } 10 early() { ; }\", \"must explicitly return a value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return F; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return T; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mateChoice(p1) { subpop; return individual.haploidGenome1; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mateChoice(p1) { if (!isNULL(individual) & !isNULL(subpop) & !isNULL(sourceSubpop) & !isNULL(weights)) return weights; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// modifyChild() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"modifyChild() { return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"modifyChild() { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"modifyChild(p1) { return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"modifyChild(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"modifyChild(p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 modifyChild(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(m1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1, p1) { stop(); } 10 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(NULL) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { return NULL; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { return child; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; return NULL; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"modifyChild(p1) { subpop; return child; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"modifyChild(p1) { if (!isNULL(child) & !isNULL(isCloning) & !isNULL(isSelfing) & !isNULL(parent1) & !isNULL(parent2) & !isNULL(subpop) & !isNULL(sourceSubpop)) return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"modifyChild(p1) { if (!isNULL(child) & !isNULL(isCloning) & !isNULL(isSelfing) & !isNULL(parent1) & !isNULL(parent2) & !isNULL(subpop) & isNULL(sourceSubpop)) return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"modifyChild(p1) { if (!isNULL(child) & !isNULL(isCloning) & !isNULL(isSelfing) & !isNULL(parent1) & !isNULL(parent2) & !isNULL(subpop) & !isNULL(sourceSubpop)) return T; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// recombination() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination() { return F; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination() { return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination() { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination(p1) { return F; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination(p1) { return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"recombination(p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 recombination(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(m1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1, p1) { stop(); } 10 early() { ; }\", \"needs a value for chromosome\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination(NULL) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { return NULL; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { return subpop; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; return NULL; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"recombination(p1) { subpop; return subpop; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"recombination(p1) { if (!isNULL(individual) & !isNULL(haplosome1) & !isNULL(haplosome2) & !isNULL(subpop) & !isNULL(breakpoints)) return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"recombination(p1) { if (!isNULL(individual) & !isNULL(haplosome1) & !isNULL(haplosome2) & !isNULL(subpop) & !isNULL(breakpoints)) return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"recombination(p1) { if (!isNULL(individual) & !isNULL(haplosome1) & !isNULL(haplosome2) & !isNULL(subpop) & !isNULL(breakpoints)) return T; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// interaction() callbacks\n\tstatic std::string gen1_setup_p1p2p3_i1(gen1_setup_p1p2p3 + \"initialize() { initializeInteractionType('i1', ''); } early() { i1.evaluate(sim.subpopulations); i1.strength(p1.individuals[0]); } \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return 1.0; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_i1 + \"interaction(i1) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_i1 + \"interaction(i1, p1) { return 1.0; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_i1 + \"interaction(i1, p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_i1 + \"interaction(i2) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_i1 + \"interaction(i2, p1) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_i1 + \"interaction(i1, p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(\"early() { s1.active = 0; } \" + gen1_setup_p1p2p3_i1 + \"s1 interaction(i1) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(\"early() { s1.active = 0; } \" + gen1_setup_p1p2p3_i1 + \"s1 interaction(i1, p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction() { stop(); } 10 early() { ; }\", \"interaction type id is required\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1, p1, p2) { stop(); } 10 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1, i1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(p1) { stop(); } 10 early() { ; }\", \"identifier prefix 'i' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1, NULL) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(NULL, i1) { stop(); } 10 early() { ; }\", \"identifier prefix 'i' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return NULL; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return F; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return T; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { return exerter; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; return F; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; return T; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_i1 + \"interaction(i1) { exerter; return exerter; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_i1 + \"interaction(i1) { if (!isNULL(distance) & !isNULL(strength) & !isNULL(exerter) & !isNULL(receiver)) return 1.0; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// reproduction() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction() { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction() { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1, 'F') { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1, 'F') { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, 'F') { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, 'F') { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1, NULL) { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1, NULL) { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, NULL) { subpop.addCloned(individual); } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, NULL) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_nonWF + \"reproduction(p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_nonWF + \"reproduction() { s1.active = 0; } s1 reproduction(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(m1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1, p1) { stop(); } 10 early() { ; }\", \"needs a value for sex\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(NULL, '*') { stop(); } 10 early() { ; }\", \"needs a value for sex\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return NULL; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return F; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return T; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return 1; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return 1.0; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return 'a'; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { return subpop; } 10 early() { ; }\", \"must return void\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return NULL; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return F; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return T; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return 1; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return 1.0; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return 'a'; } 10 early() { ; }\", \"must return void\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { subpop; return subpop; } 10 early() { ; }\", \"must return void\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF + \"reproduction(p1) { if (!isNULL(individual) & !isNULL(subpop)) subpop.addCloned(individual); else foo; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// mutation() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1) { return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1) { return mut; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation() { return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation() { return mut; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation() { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL) { return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL) { return mut; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1, p1) { return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1, p1) { return mut; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL, p1) { return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL, p1) { return mut; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(NULL, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutation(m2) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutation(m2, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutation(m1, p4) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"mutation(NULL, p4) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mutation(m1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mutation(m1, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3 + \"early() { s1.active = 0; } s1 mutation(NULL, p1) { stop(); } 100 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1, p1, p2) { stop(); } 100 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1, m1) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(p1) { stop(); } 100 early() { ; }\", \"identifier prefix 'm' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1, NULL) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(NULL, m1) { stop(); } 100 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { ; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { return NULL; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { return 1; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { return 1.0; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { return 'a'; } 100 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { mut; ; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { mut; return NULL; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { mut; return 1; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { mut; return 1.0; } 100 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3 + \"mutation(m1) { mut; return 'a'; } 100 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3 + \"mutation(m1) { if (!isNULL(mut) & !isNULL(haplosome) & !isNULL(element) & !isNULL(originalNuc) & !isNULL(parent) & !isNULL(subpop)) return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"mutation(m1) { if (!isNULL(mut) & !isNULL(haplosome) & !isNULL(element) & !isNULL(originalNuc) & !isNULL(parent) & !isNULL(subpop)) return T; } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"mutation(m1) { if (!isNULL(mut) & !isNULL(haplosome) & !isNULL(element) & !isNULL(originalNuc) & !isNULL(parent) & !isNULL(subpop)) return T; } 100 early() { stop(); }\", __LINE__);\n\t\n\t// survival() callbacks\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival() { return F; } 10 early() { if (p1.individualCount == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival() { return T; } 10 early() { if (p1.individualCount == 5120) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival() { return NULL; } 10 early() { stop(); }\", __LINE__);\n\t//SLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival() { if (subpop == p1) return p2; return NULL; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival() { stop(); } 10 early() { ; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return F; } 10 early() { if (p1.individualCount == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return T; } 10 early() { if (p1.individualCount == 5120) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return NULL; } 10 early() { stop(); }\", __LINE__);\n\t//SLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return p2; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_nonWF_clone + \"survival(p4) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptSuccess(gen1_setup_p1p2p3_nonWF_clone + \"early() { s1.active = 0; } s1 survival(p1) { stop(); } 10 early() { ; }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(m1) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1, p1) { stop(); } 10 early() { ; }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(NULL) { stop(); } 10 early() { ; }\", \"identifier prefix 'p' was expected\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { subpop; ; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { subpop; return 1; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { subpop; return 1.0; } 10 early() { ; }\", \"return value\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { subpop; return 'a'; } 10 early() { ; }\", \"return value\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_cross + \"survival(p1) { if (!isNULL(individual) & !isNULL(subpop) & !isNULL(surviving) & !isNULL(fitness) & !isNULL(draw)) return T; } 10 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1p2p3_nonWF_clone + \"survival(p1) { if (!isNULL(individual) & !isNULL(subpop) & !isNULL(surviving) & !isNULL(fitness) & !isNULL(draw)) return T; } 10 early() { stop(); }\", __LINE__);\n\t\n\t// Test tick range expressions\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} early() { if (community.tick == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} 1: early() { if (community.tick == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} :10 early() { if (community.tick == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} 2:5 early() { if (community.tick == 5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} 1 early() { if (community.tick == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} N+2 early() { if (community.tick == 7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} N+5: early() { if (community.tick == 10) stop(); } 20 early() {}\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} :N-1 early() { if (community.tick == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} (N+1):(N+4) early() { if (community.tick == 9) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} N*N early() { if (community.tick == 25) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} sum(1:3) early() { if (community.tick == 6) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} sum(1:3):7 early() { if (community.tick == 7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} seq(1, 10, by=3) early() { if (community.tick == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} seq(1, 10, by=3)*2 early() { if (community.tick == 20) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { defineConstant('N', 5); } 1 early() {} c(1, 5, 10) early() { if (community.tick == 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(\"initialize() { defineConstant('N', 5); } 1 early() {} integer(0) early() { stop(); } 10 early() {}\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} 1.5 early() { stop(); }\", \"must evaluate to an integer value\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} 1:1.5 early() { stop(); }\", \"must evaluate to an integer value\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} 'foo' early() { stop(); }\", \"must evaluate to an integer value\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} 2 5 early() { stop(); }\", \"expected an event declaration\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} : early() { stop(); }\", \"unexpected token\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} N+40:(N+50) early() { stop(); }\", \"must both be simple expressions\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} (N+40):N+50 early() { stop(); }\", \"must both be simple expressions\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} R early() { stop(); }\", \"global constant, R, that was never defined\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); defineGlobal('R', 5); } 1 early() {} R early() { stop(); }\", \"not visible in tick range expressions\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { defineConstant('N', 5); } 1 early() {} c(1, 5, 10, 5) early() { stop(); }\", \"duplicate elements\", __LINE__);\n\t\n\t// More advanced tick range expressions, involving deferral of the definition of the constant and such\n\t// First just a basic script with a deferred block:\n\tstd::string tickexpr1(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptStop(tickexpr1);\n\t\n\t// Then a second deferred block scheduled by the first:\n\tstd::string tickexpr2(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { defineConstant(\"TIME2\", 10); }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptStop(tickexpr2);\n\t\n\t// A deferred block scheduled into the past:\n\tstd::string tickexpr3(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { defineConstant(\"TIME2\", 4); }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptRaise(tickexpr3, \"past/present\", __LINE__);\n\t\n\t// A deferred block scheduled into the present, which is still illegal:\n\tstd::string tickexpr4(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { defineConstant(\"TIME2\", 5); }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptRaise(tickexpr4, \"past/present\", __LINE__);\n\t\n\t// A deferred block scheduled into the near future in the same tick, which should work:\n\tstd::string tickexpr4_1(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 first() { defineConstant(\"TIME2\", 5); }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptStop(tickexpr4_1);\n\t\n\tstd::string tickexpr4_2(R\"V0G0N(\n\t\tinitialize() { initializeSLiMModelType(\"nonWF\"); }\n\t\t1 first() { sim.addSubpop(\"p1\", 500); defineGlobal(\"COUNT\", 0); defineConstant(\"FOO\", 10); }\n\t\t1:FOO reproduction() {\n\t\t\tdefineGlobal(\"COUNT\", COUNT + 1);\n\t\t\tself.active = 0;\n\t\t}\n\t\t20 late() { if (COUNT == 10) stop(); }\n\t)V0G0N\");\n\tSLiMAssertScriptStop(tickexpr4_2);\n\t\n\t// A deferred block that never gets scheduled because global variables aren't used:\n\tstd::string tickexpr5(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { defineGlobal(\"TIME2\", 5); }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptRaise(tickexpr5, \"global constant, TIME2, that was never defined\", __LINE__);\n\t\n\t// A deferred block that never gets scheduled because the constant never gets set:\n\tstd::string tickexpr6(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { }\n\t\tTIME2 early() { stop(); }\n\t\t20 late() { }\n\t\t)V0G0N\");\n\tSLiMAssertScriptRaise(tickexpr6, \"global constant, TIME2, that was never defined\", __LINE__);\n\t\n\t// A deferred block that never gets scheduled, but is deregistered before the simulation ends, avoiding the error:\n\tstd::string tickexpr7(R\"V0G0N(\n\t\tinitialize() { defineConstant(\"TIME1\", 5); }\n\t\t1 early() { sim.addSubpop(\"p1\", 5); }\n\t\tTIME1 early() { }\n\t\ts1 TIME2 early() { stop(); }\n\t\t20 late() { community.deregisterScriptBlock(s1); }\n\t\t)V0G0N\");\n\tSLiMAssertScriptSuccess(tickexpr7);\n\t\n\t// Test tick range expressions involving a user-defined function (see https://github.com/MesserLab/SLiM/issues/495)\n\tstd::string tickexpr8(R\"V0G0N(\n\t\tinitialize() {\n\t\t}\n\t\tfunction (i) tock(i years) {\n\t\t\treturn (asInteger(years / 30));\n\t\t}\n\t\ttock(300) early() {\n\t\t\tstop('executed the scheduled event');\n\t\t}\n\t\t)V0G0N\");\n\tSLiMAssertScriptStop(tickexpr8);\n\t\n\tstd::string tickexpr9(R\"V0G0N(\n\t\tinitialize() {\n\t\t}\n\t\tfunction (i) tock(i years) {\n\t\t\treturn (asInteger(years / 30));\n\t\t}\n\t\ttuck(300) early() {\t\t// typo\n\t\t\tstop('executed the scheduled event');\n\t\t}\n\t\t)V0G0N\");\n\tSLiMAssertScriptRaise(tickexpr9, \"unrecognized function name tuck\", __LINE__);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test_genetics.cpp",
    "content": "//\n//  slim_test_genetics.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_test.h\"\n\n#include \"eidos_globals.h\"\n\n#include <string>\n\n\n#pragma mark MutationType tests\nvoid _RunMutationTypeTests(void)\n{\t\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: MutationType\n\t//\n\t\n\t// Test MutationType properties\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.color == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.colorSubstitution == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.convertToSubstitution == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.mutationStackGroup == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.mutationStackPolicy == 's') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.distributionParams == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.distributionType == 'f') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.dominanceCoeff == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (m1.id == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.color = ''; } 2 early() { if (m1.color == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.color = 'red'; } 2 early() { if (m1.color == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.color = '#FF0000'; } 2 early() { if (m1.color == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.colorSubstitution = ''; } 2 early() { if (m1.colorSubstitution == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.colorSubstitution = 'red'; } 2 early() { if (m1.colorSubstitution == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.colorSubstitution = '#FF0000'; } 2 early() { if (m1.colorSubstitution == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { c(m1,m1).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.tag = 17; } 2 early() { if (m1.tag == 17) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.convertToSubstitution = F; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.mutationStackGroup = -17; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.mutationStackPolicy = 's'; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.mutationStackPolicy = 'f'; }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.mutationStackPolicy = 'l'; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.mutationStackPolicy = 'z'; }\", \"property mutationStackPolicy must be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.distributionParams = 0.1; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.distributionType = 'g'; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.dominanceCoeff = 0.3; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.id = 2; }\", \"read-only property\", __LINE__);\n\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); c(m1,m2).mutationStackGroup = 3; c(m1,m2).mutationStackPolicy = 'f'; } 1 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); c(m1,m2).mutationStackGroup = 3; m1.mutationStackPolicy = 'f'; m2.mutationStackPolicy = 'l'; } 1 early() { stop(); }\", \"inconsistent mutationStackPolicy\", __LINE__, false);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); c(m1,m2).mutationStackGroup = 3; c(m1,m2).mutationStackPolicy = 'f'; } 1 early() { m2.mutationStackPolicy = 'l'; }\", \"inconsistent mutationStackPolicy\", __LINE__, false);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); m1.mutationStackPolicy = 'f'; m2.mutationStackPolicy = 'l'; } 1 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); m1.mutationStackPolicy = 'f'; m2.mutationStackPolicy = 'l'; } 1 early() { c(m1,m2).mutationStackGroup = 3; }\", \"inconsistent mutationStackPolicy\", __LINE__, false);\n\t\n\t// Test MutationType - (void)setDistribution(string$ distributionType, ...)\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('f', 2.2); if (m1.distributionType == 'f' & m1.distributionParams == 2.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, 7.5); if (m1.distributionType == 'g' & identical(m1.distributionParams, c(3.1, 7.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('e', -3); if (m1.distributionType == 'e' & m1.distributionParams == -3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, 7.5); if (m1.distributionType == 'n' & identical(m1.distributionParams, c(3.1, 7.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, 7.5); if (m1.distributionType == 'p' & identical(m1.distributionParams, c(3.1, 7.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, 7.5); if (m1.distributionType == 'w' & identical(m1.distributionParams, c(3.1, 7.5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('s', 'return 1;'); if (m1.distributionType == 's' & identical(m1.distributionParams, 'return 1;')) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('x', 1.5); stop(); }\", \"must be 'f', 'g', 'e', 'n', 'w', or 's'\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('f', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 'foo', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('e', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', 'foo', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 'foo', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 'foo', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('s', 3); stop(); }\", \"must be of type string\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('f', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', '1', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('e', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', '1', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', '1', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', '1', 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('s', 3.1); stop(); }\", \"must be of type string\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('f', T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', T, 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('e', T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', T, 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', T, 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', T, 7.5); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, T); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('s', T); stop(); }\", \"must be of type string\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, 0.0); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, -1.0); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, -1.0); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, 0.0); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, -1.0); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 0.0, 7.5); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', -1.0, 7.5); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, 0.0); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, -7.5); }\", \"must have a shape parameter > 0\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { m1.setDistribution('s', 'return foo;'); } 100 early() { stop(); }\", \"undefined identifier foo\", __LINE__, false);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { m1.setDistribution('s', 'x >< 5;'); } 100 early() { stop(); }\", \"tokenize/parse error in type 's' DFE callback script\", __LINE__, false);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"1 early() { m1.setDistribution('s', 'x $ 5;'); } 100 early() { stop(); }\", \"tokenize/parse error in type 's' DFE callback script\", __LINE__, false);\n\t\n\t// Test MutationType - (float)drawSelectionCoefficient([integer$ n = 1])\n\t// the parameters here are chosen so that these tests should fail extremely rarely\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('f', 2.2); if (m1.drawSelectionCoefficient() == 2.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('f', 2.2); if (identical(m1.drawSelectionCoefficient(10), rep(2.2, 10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, 7.5); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('g', 3.1, 7.5); if (abs(mean(m1.drawSelectionCoefficient(5000)) - 3.1) < 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('e', -3.0); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('e', -3.0); if (abs(mean(m1.drawSelectionCoefficient(30000)) + 3.0) < 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, 0.5); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('n', 3.1, 0.5); if (abs(mean(m1.drawSelectionCoefficient(2000)) - 3.1) < 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, 7.5); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('p', 3.1, 0.01); if (abs(mean(m1.drawSelectionCoefficient(2000)) - 3.1) < 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, 7.5); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('w', 3.1, 7.5); if (abs(mean(m1.drawSelectionCoefficient(2000)) - 2.910106) < 0.1) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup + \"1 early() { m1.setDistribution('s', 'rbinom(1, 4, 0.5);'); m1.drawSelectionCoefficient(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { m1.setDistribution('s', 'rbinom(1, 4, 0.5);'); if (abs(mean(m1.drawSelectionCoefficient(5000)) - 2.0) < 0.1) stop(); }\", __LINE__);\n}\n\n#pragma mark GenomicElementType tests\nvoid _RunGenomicElementTypeTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: GenomicElementType\n\t//\n\t\n\t// Test GenomicElementType properties\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (g1.color == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (g1.id == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { g1.id = 2; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (g1.mutationFractions == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (g1.mutationTypes == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.color = ''; } 2 early() { if (g1.color == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.color = 'red'; } 2 early() { if (g1.color == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.color = '#FF0000'; } 2 early() { if (g1.color == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { g1.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { c(g1,g1).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.tag = 17; } 2 early() { if (g1.tag == 17) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { g1.mutationFractions = 1.0; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { g1.mutationTypes = m1; }\", \"read-only property\", __LINE__);\n\t\n\t// Test GenomicElementType - (void)setMutationFractions(io<MutationType> mutationTypes, numeric proportions)\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.setMutationFractions(object(), integer(0)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.setMutationFractions(m1, 0.0); if (g1.mutationTypes == m1 & g1.mutationFractions == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.setMutationFractions(1, 0.0); if (g1.mutationTypes == m1 & g1.mutationFractions == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.setMutationFractions(m1, 0.3); if (g1.mutationTypes == m1 & g1.mutationFractions == 0.3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { g1.setMutationFractions(1, 0.3); if (g1.mutationTypes == m1 & g1.mutationFractions == 0.3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(m1,m2), c(0.3, 0.7)); if (identical(g1.mutationTypes, c(m1,m2)) & identical(g1.mutationFractions, c(0.3,0.7))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(1,2), c(0.3, 0.7)); if (identical(g1.mutationTypes, c(m1,m2)) & identical(g1.mutationFractions, c(0.3,0.7))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(m1,m2)); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(m1,m2), 0.3); stop(); }\", \"requires the sizes\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(m1,m2), c(-1, 2)); stop(); }\", \"must be greater than or equal to zero\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(2,3), c(1, 2)); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(m2,m2), c(1, 2)); stop(); }\", \"used more than once\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"initialize() { initializeMutationType('m2', 0.7, 'e', 0.5); } 1 early() { g1.setMutationFractions(c(2,2), c(1, 2)); stop(); }\", \"used more than once\", __LINE__);\n}\n\n#pragma mark GenomicElement tests\nvoid _RunGenomicElementTests(void)\n{\t\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: GenomicElement\n\t//\n\t\n\tstd::string gen1_setup_2ge(\"initialize() { initializeMutationRate(1e-7); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 999); initializeGenomicElement(g1, 1000, 99999); initializeRecombinationRate(1e-8); } \");\n\t\n\t// Test GenomicElement properties\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; if (ge.endPosition == 999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; if (ge.startPosition == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; if (ge.genomicElementType == g1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.tag = -12; if (ge.tag == -12) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.endPosition = 999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.startPosition = 0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.genomicElementType = g1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; if (ge.endPosition == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; if (ge.startPosition == 1000) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; if (ge.genomicElementType == g1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; ge.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; ge.tag = -17; if (ge.tag == -17) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; ge.endPosition = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; ge.startPosition = 1000; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[1]; ge.genomicElementType = g1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements; ge.tag; }\", \"before being set\", __LINE__);\n\t\n\t// Test GenomicElement - (void)setGenomicElementType(io<GenomicElementType>$ genomicElementType)\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.setGenomicElementType(g1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.setGenomicElementType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.setGenomicElementType(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.setGenomicElementType(object()); stop(); }\", \"must be a singleton\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"1 early() { ge = sim.chromosomes.genomicElements[0]; ge.setGenomicElementType(2); stop(); }\", \"not defined\", __LINE__);\n\t\n\t// Test GenomicElement position testing\n\tSLiMAssertScriptStop(gen1_setup_2ge + \"initialize() { initializeGenomicElement(g1, 100000, 100000); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"initialize() { initializeGenomicElement(g1, 99999, 100000); stop(); }\", \"overlaps existing genomic element\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_2ge + \"initialize() { initializeGenomicElement(g1, -2, -1); stop(); }\", \"chromosome position or length is out of range\", __LINE__);\n}\n\n#pragma mark Chromosome tests\nvoid _RunChromosomeTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Chromosome\n\t//\n\t\n\t// Test Chromosome properties\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.colorSubstitution == '#3333FF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionEnabled == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionGCBias == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionNonCrossoverFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionMeanLength == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionSimpleConversionFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.genomicElements[0].genomicElementType == g1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.lastPosition == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.overallRecombinationRate == 1e-8 * 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallRecombinationRateM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallRecombinationRateF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.recombinationEndPositions == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationEndPositionsM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationEndPositionsF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.recombinationRates == 1e-8) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationRatesM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationRatesF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.overallMutationRate == 1e-7 * 100000) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallMutationRateM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallMutationRateF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.mutationEndPositions == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationEndPositionsM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationEndPositionsF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; if (ch.mutationRates == 1e-7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationRatesM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationRatesF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = ''; if (ch.colorSubstitution == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = 'red'; if (ch.colorSubstitution == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = '#FF0000'; if (ch.colorSubstitution == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; c(ch,ch).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.tag = 3294; if (ch.tag == 3294) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.genomicElements = ch.genomicElements; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.lastPosition = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallMutationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.mutationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.colorSubstitution == '#3333FF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionEnabled == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionGCBias == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionNonCrossoverFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionMeanLength == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionSimpleConversionFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.genomicElements[0].genomicElementType == g1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.lastPosition == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.overallRecombinationRate == 1e-8 * 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallRecombinationRateM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallRecombinationRateF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.recombinationEndPositions == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationEndPositionsM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationEndPositionsF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.recombinationRates == 1e-8) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationRatesM)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationRatesF)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.overallMutationRate == 1e-7 * 100000) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallMutationRateM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallMutationRateF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.mutationEndPositions == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationEndPositionsM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationEndPositionsF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (ch.mutationRates == 1e-7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationRatesM)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationRatesF)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = ''; if (ch.colorSubstitution == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = 'red'; if (ch.colorSubstitution == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = '#FF0000'; if (ch.colorSubstitution == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; c(ch,ch).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.tag = 3294; if (ch.tag == 3294) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.genomicElements = ch.genomicElements; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.lastPosition = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallMutationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.mutationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\t\n\tstd::string gen1_setup_sex_2rates(\"initialize() { initializeSex('X'); initializeMutationRate(1e-7, sex='M'); initializeMutationRate(1e-8, sex='F'); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8, 99999, 'M'); initializeRecombinationRate(1e-7, 99999, 'F'); } \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.colorSubstitution == '#3333FF') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionEnabled == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionGCBias == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionNonCrossoverFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionMeanLength == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.geneConversionSimpleConversionFraction == 0.0) stop(); }\", \"not defined since the DSB\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.genomicElements[0].genomicElementType == g1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.lastPosition == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallRecombinationRate)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.overallRecombinationRateM == 1e-8 * 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.overallRecombinationRateF == 1e-7 * 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationEndPositions)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.recombinationEndPositionsM == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.recombinationEndPositionsF == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.recombinationRates)) stop(); }\", \"sex-specific recombination rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.recombinationRatesM == 1e-8) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.recombinationRatesF == 1e-7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.overallMutationRate)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.overallMutationRateM == 1e-7 * 100000) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.overallMutationRateF == 1e-8 * 100000) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationEndPositions)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.mutationEndPositionsM == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.mutationEndPositionsF == 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (isNULL(ch.mutationRates)) stop(); }\", \"sex-specific mutation rate maps\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.mutationRatesM == 1e-7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; if (ch.mutationRatesF == 1e-8) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = ''; if (ch.colorSubstitution == '') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = 'red'; if (ch.colorSubstitution == 'red') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.colorSubstitution = '#FF0000'; if (ch.colorSubstitution == '#FF0000') stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; c(ch,ch).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.tag = 3294; if (ch.tag == 3294) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.genomicElements = ch.genomicElements; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.lastPosition = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallRecombinationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.recombinationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallMutationRate = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateM = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.overallMutationRateF = 1e-2; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositions = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsM = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationEndPositionsF = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationRates = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationRatesM = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.mutationRatesF = 1e-8; stop(); }\", \"read-only property\", __LINE__);\n\t\n\t// Test Chromosome - (void)setMutationRate(numeric rates, [integer ends])\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(-0.00001); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(10000); stop(); }\", \"rate is >= 1.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1)); stop(); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0)); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"must be >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0), '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(-0.00001); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(10000); stop(); }\", \"rate is >= 1.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1)); stop(); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0)); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"must be >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0), '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"must be >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999, 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999, 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(0.0); stop(); }\", \"single map versus separate maps\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(-0.00001); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(10000); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(1000, 99999), 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.001), c(1000, 99999), 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(integer(0), integer(0), 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99999, 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), 99997:99999, 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 1000), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, 0.1), c(99999, 99999), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 99999), 'M'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 2000), 'M'); stop(); }\", \"must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setMutationRate(c(0.0, -0.001), c(1000, 100000), 'M'); stop(); }\", \"must be >= 0\", __LINE__);\n\t\n\t// Test Chromosome - (void)setRecombinationRate(numeric rates, [integer ends])\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(-0.00001); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.5); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.6); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(10000); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1)); stop(); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0)); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0), '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.0); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(-0.00001); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.5); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.6); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(10000); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1)); stop(); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0)); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0), '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999, 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999, 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000), 'M'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(0.0); stop(); }\", \"single map versus separate maps\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// legal: singleton rate, no end\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(); stop(); }\", \"missing required argument\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(-0.00001); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(10000); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000)); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999, '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999, '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000), '*'); stop(); }\", \"single map versus separate maps\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(1000, 99999), 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.001), c(1000, 99999), 'M'); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(integer(0), integer(0), 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99999, 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), 99997:99999, 'M'); stop(); }\", \"to be of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 1000), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, 0.1), c(99999, 99999), 'M'); stop(); }\", \"ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 99999), 'M'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 2000), 'M'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_sex_2rates + \"1 early() { ch = sim.chromosomes; ch.setRecombinationRate(c(0.0, -0.001), c(1000, 100000), 'M'); stop(); }\", \"rates must be in [0.0, 0.5]\", __LINE__);\n\t\n\t// initializeGeneConversion() tests\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75); } 1 early() { if (sim.chromosomes.geneConversionEnabled == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75); } 1 early() { if (sim.chromosomes.geneConversionNonCrossoverFraction == 0.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75); } 1 early() { if (sim.chromosomes.geneConversionMeanLength == 1234.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75); } 1 early() { if (sim.chromosomes.geneConversionSimpleConversionFraction == 0.75) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75); } 1 early() { if (sim.chromosomes.geneConversionGCBias == 0.0) stop(); }\", __LINE__);\n\t\n\t// setGeneConversion() tests\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75); if (sim.chromosomes.geneConversionEnabled == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75); if (sim.chromosomes.geneConversionNonCrossoverFraction == 0.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75); if (sim.chromosomes.geneConversionMeanLength == 1234.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75); if (sim.chromosomes.geneConversionSimpleConversionFraction == 0.75) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75); if (sim.chromosomes.geneConversionGCBias == 0.0) stop(); }\", __LINE__);\n\t\n\t// some basic tests of initializeChromosome(), especially length checks and length determination with and without a length of NULL\n\tstd::string short_init = \"initialize() { initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); \";\n\t\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1, length=1e4); initializeGenomicElement(g1, 0, 1e4); }\", \"extent of the chromosome\", __LINE__);\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1, length=1e4); initializeRecombinationRate(1e-7, 1e4); }\", \"extent of the chromosome\", __LINE__);\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1, length=1e4); initializeMutationRate(1e-7, 1e4); }\", \"extent of the chromosome\", __LINE__);\n\t\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1, length=1e4); initializeGenomicElement(g1, 0, 1e4-1); stop(); }\");\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1, length=1e4); initializeRecombinationRate(1e-7, 1e4-1); stop(); }\");\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1, length=1e4); initializeMutationRate(1e-7, 1e4-1); stop(); }\");\n\t\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e4-1); initializeMutationRate(1e-7, 1e4-1); } 1 early() { if (sim.chromosome.length == 1e4) stop(); }\");\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e4-1); initializeMutationRate(1e-7, 1e4-1); } 1 early() { if (sim.chromosome.lastPosition == 1e4-1) stop(); }\");\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e5-1); initializeRecombinationRate(1e-7, 1e5-1); initializeMutationRate(1e-7, 1e4-1); }\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e5-1); initializeRecombinationRate(1e-7, 1e4-1); initializeMutationRate(1e-7, 1e5-1); }\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e5-1); initializeMutationRate(1e-7, 1e5-1); } 1 early() { if (sim.chromosome.length == 1e5) stop(); }\");\n\tSLiMAssertScriptStop(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e5-1); initializeMutationRate(1e-7, 1e5-1); } 1 early() { if (sim.chromosome.lastPosition == 1e5-1) stop(); }\");\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e5-1); initializeMutationRate(1e-7, 1e4-1); }\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptRaise(short_init + \"initializeChromosome(1); initializeGenomicElement(g1, 0, 1e4-1); initializeRecombinationRate(1e-7, 1e4-1); initializeMutationRate(1e-7, 1e5-1); }\", \"do not cover the full chromosome\", __LINE__, false);\n}\n\n#pragma mark Mutation tests\nvoid _RunMutationTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Mutation\n\t//\n\t\n\t// Test Mutation properties\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; if (mut.mutationType == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; if ((mut.originTick >= 1) & (mut.originTick < 10)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; if ((mut.position >= 0) & (mut.position < 100000)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; if (mut.selectionCoeff == 0.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; if (mut.subpopID == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.mutationType = m1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.originTick = 1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.position = 0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.selectionCoeff = 0.1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.subpopID = 237; if (mut.subpopID == 237) stop(); }\", __LINE__);\t\t\t\t\t\t// legal; this field may be used as a user tag\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; c(mut,mut).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.tag = 278; if (mut.tag == 278) stop(); }\", __LINE__);\n\t\n\t// Test Mutation - (void)setMutationType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setMutationType(m1); if (mut.mutationType == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setMutationType(m1); if (mut.mutationType == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setMutationType(2); if (mut.mutationType == m1) stop(); }\", \"mutation type m2 not defined\", __LINE__);\n\t\n\t// Test Mutation - (void)setSelectionCoeff(float$ selectionCoeff)\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setSelectionCoeff(0.5); if (mut.selectionCoeff == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setSelectionCoeff(1); if (mut.selectionCoeff == 1) stop(); }\", \"cannot be type integer\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setSelectionCoeff(-500.0); if (mut.selectionCoeff == -500.0) stop(); }\", __LINE__);\t// legal; no lower bound\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.setSelectionCoeff(500.0); if (mut.selectionCoeff == 500.0) stop(); }\", __LINE__);\t\t// legal; no upper bound\n}\n\n#pragma mark Substitution tests\nvoid _RunSubstitutionTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Substitution\n\t//\n\t\n\t// Test Substitution properties\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { if (size(sim.substitutions) > 0) stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// check that our script generates substitutions fast enough\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; if (sub.fixationTick > 0 & sub.fixationTick <= 30) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; if (sub.mutationType == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; if (sub.originTick > 0 & sub.originTick <= 10) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; if (sub.position >= 0 & sub.position <= 99999) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { if (sum(sim.substitutions.selectionCoeff == 500.0) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; if (sub.subpopID == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.fixationTick = 10; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.mutationType = m1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.originTick = 10; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.position = 99999; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.selectionCoeff = 50.0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.subpopID = 237; if (sub.subpopID == 237) stop(); }\", __LINE__);\t\t\t\t\t\t// legal; this field may be used as a user tag\n}\n\n#pragma mark Haplosome tests\nvoid _RunHaplosomeTests(const std::string &temp_path)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: Haplosome\n\t//\n\t\n\t// Test Haplosome properties\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; if (gen.chromosome.type == 'A') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[c(0,1)]; if (identical(gen.chromosomeSubposition, c(0,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; if (gen.isNullHaplosome == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; if (gen.mutations[0].mutationType == m1) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; c(gen,gen).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.tag = 278; if (gen.tag == 278) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.chromosome.type = 'A'; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.chromosomeSubposition = 0; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.isNullHaplosome = F; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.mutations[0].mutationType = m1; stop(); }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { counts1 = sapply(p1.haplosomes, 'size(applyValue.mutations);'); counts2 = p1.haplosomes.mutationCount; if (identical(counts1, counts2)) stop(); }\");\n\t\n\t// Test Haplosome + (void)addMutations(object<Mutation> mutations)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.addMutations(object()); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.addMutations(gen.mutations[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.addMutations(p1.haplosomes[1].mutations[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; mut = p1.haplosomes[1].mutations[0]; gen.addMutations(rep(mut, 10)); if (sum(gen.mutations == mut) == 1) stop(); }\", __LINE__);\n\t\n\t// Test Haplosome + (object<Mutation>)addNewDrawnMutation(io<MutationType> mutationType, integer position, [Nio<Subpopulation> originSubpop])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, NULL); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, NULL, NULL); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000:5003, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000:5003, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000:5003); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(7, 5000, NULL); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, -1, 1); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 100000, 1); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, 237); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t// bad subpop, but this is legal to allow \"tagging\" of mutations\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(1, 5000, -1); stop(); }\", \"out of range\", __LINE__);\t\t\t\t\t// however, such tags must be within range\n\t\n\t// Test Haplosome + (object<Mutation>)addNewMutation(io<MutationType> mutationType, numeric selectionCoeff, integer position, [Nio<Subpopulation> originSubpop])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, NULL); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000:5000, p1); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000:5003, 0:3); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000:5003); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, (0:3)/10, 5000:5003); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, (0:3)/10, 5000:5003, 0:3); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(7, 0.1, 5000, 1); p1.haplosomes.addMutations(mut); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, -1, 1); p1.haplosomes.addMutations(mut); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 100000, 1); p1.haplosomes.addMutations(mut); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, 237); p1.haplosomes.addMutations(mut); stop(); }\", __LINE__);\t\t\t\t\t\t\t// bad subpop, but this is legal to allow \"tagging\" of mutations\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(1, 0.1, 5000, -1); p1.haplosomes.addMutations(mut); stop(); }\", \"out of range\", __LINE__);\t// however, such tags must be within range\n\t\n\t// Test Haplosome + (object<Mutation>)addNewDrawnMutation(io<MutationType> mutationType, integer position, [io<Subpopulation> originSubpop]) with new class method non-multiplex behavior\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000:5003, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000:5003, 0:3); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(m1, 5000:5003); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(7, 5000, 1); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, -1, 1); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 100000, 1); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, 237); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t// bad subpop, but this is legal to allow \"tagging\" of mutations\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewDrawnMutation(1, 5000, -1); stop(); }\", \"out of range\", __LINE__);\t\t\t\t\t// however, such tags must be within range\n\t\n\t// Test Haplosome + (object<Mutation>)addNewMutation(io<MutationType> mutationType, numeric selectionCoeff, integer position, [io<Subpopulation> originSubpop]) with new class method non-multiplex behavior\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000:5003, p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000:5003, 0:3); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, 0.1, 5000:5003); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, (0:3)/10, 5000:5003); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(m1, (0:3)/10, 5000:5003, 0:3); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(7, 0.1, 5000, 1); stop(); }\", \"not defined\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, -1, 1); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 100000, 1); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, 237); stop(); }\", __LINE__);\t\t\t\t\t\t\t// bad subpop, but this is legal to allow \"tagging\" of mutations\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes.addNewMutation(1, 0.1, 5000, -1); stop(); }\", \"out of range\", __LINE__);\t// however, such tags must be within range\n\t\n\t// Test Haplosome - (logical$)containsMarkerMutation(io<MutationType>$ mutType, integer$ position, [logical$ returnMutation = F])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, 1000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(1, 1000); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].containsMarkerMutation(1, 1000); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, -1); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, 1000000); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(10, 1000); stop(); }\", \"mutation type m10 not defined\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, 1000, returnMutation=T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(1, 1000, returnMutation=T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].containsMarkerMutation(1, 1000, returnMutation=T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, -1, returnMutation=T); stop(); }\", \"out of range\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(m1, 1000000, returnMutation=T); stop(); }\", \"past the end\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMarkerMutation(10, 1000, returnMutation=T); stop(); }\", \"mutation type m10 not defined\", __LINE__);\n\t\n\t// Test Haplosome - (logical)containsMutations(object<Mutation> mutations)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMutations(object()); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].containsMutations(sim.mutations); stop(); }\", __LINE__);\n\t\n\t// Test Haplosome - (integer$)countOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].countOfMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].countOfMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].countOfMutationsOfType(1); stop(); }\", __LINE__);\n\t\n\t// Test Haplosome + (float)mutationFrequenciesInHaplosomes([No<Mutation> mutations = NULL])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationFrequenciesInHaplosomes(); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationFrequenciesInHaplosomes(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationFrequenciesInHaplosomes(); if (identical(f, sim.mutationFrequencies(NULL))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationFrequenciesInHaplosomes(object()); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationFrequenciesInHaplosomes(object()); if (size(f) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationFrequenciesInHaplosomes(object()); if (size(f) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationFrequenciesInHaplosomes(sim.mutations); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationFrequenciesInHaplosomes(sim.mutations); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationFrequenciesInHaplosomes(sim.mutations); if (identical(f, sim.mutationFrequencies(NULL))) stop(); }\", __LINE__);\n\t\n\t// Test Haplosome + (integer)mutationCountsInHaplosomes([No<Mutation> mutations = NULL])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationCountsInHaplosomes(); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationCountsInHaplosomes(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationCountsInHaplosomes(); if (identical(f, sim.mutationCounts(NULL))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationCountsInHaplosomes(object()); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationCountsInHaplosomes(object()); if (size(f) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationCountsInHaplosomes(object()); if (size(f) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[integer(0)].mutationCountsInHaplosomes(sim.mutations); stop(); }\", \"zero-length Haplosome vector\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes[0].mutationCountsInHaplosomes(sim.mutations); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { f = p1.haplosomes.mutationCountsInHaplosomes(sim.mutations); if (identical(f, sim.mutationCounts(NULL))) stop(); }\", __LINE__);\n\t\n\t// Test Haplosome - (integer$)positionsOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].positionsOfMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].positionsOfMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].positionsOfMutationsOfType(1); stop(); }\", __LINE__);\n\t\n\t// Test Haplosome - (float$)sumOfMutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].sumOfMutationsOfType(m1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].sumOfMutationsOfType(1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].sumOfMutationsOfType(1); stop(); }\", __LINE__);\n\t\n\t// Test Haplosome - (object<Mutation>)mutationsOfType(io<MutationType>$ mutType)\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].mutationsOfType(m1); } \", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { p1.haplosomes[0].mutationsOfType(1); } \", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_p1 + \"10 early() { p1.haplosomes[0:1].mutationsOfType(1); } \", __LINE__);\n\t\n\t// Test Haplosome + (void)removeMutations(object<Mutation> mutations, [logical$ substitute])\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(mut); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(mut); gen.removeMutations(mut); stop(); }\", __LINE__);\t// legal to remove a mutation that is not present\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.removeMutations(object()); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.removeMutations(gen.mutations); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(mut, T); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(mut, T); gen.removeMutations(mut, T); stop(); }\", \"not currently segregating\", __LINE__);\t// not legal to remove a mutation that has been substituted\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; gen.removeMutations(object(), T); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.removeMutations(gen.mutations, T); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(); gen.removeMutations(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_highmut_p1 + \"10 early() { gen = p1.haplosomes[0]; gen.removeMutations(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.1, 5000); gen.removeMutations(NULL, T); }\", \"substitute may not be T if\", __LINE__);\n\t\n\t// Test Haplosome + (void)outputHaplosomesToMS([Ns$ filePath], [logical$ append = F], [logical$ filterMonomorphic = F])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 0, T).outputHaplosomesToMS(); stop(); }\", \"at least one haplosome is required\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomesToMS(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomesToMS(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomesToMS('\" + temp_path + \"/slimOutputMSTest2.txt'); stop(); }\", __LINE__);\n\t}\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomesToMS(NULL); stop(); }\", \"cannot output null haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes[!p1.haplosomes.isNullHaplosome], 100, T).outputHaplosomesToMS(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomesToMS('\" + temp_path + \"/slimOutputMSTest4.txt'); stop(); }\", \"cannot output null haplosomes\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes[!p1.haplosomes.isNullHaplosome], 100, T).outputHaplosomesToMS('\" + temp_path + \"/slimOutputMSTest5.txt'); stop(); }\", __LINE__);\n\t}\n\t\n\t// Test Haplosome + (void)outputHaplosomes([Ns$ filePath])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 0, T).outputHaplosomes(); stop(); }\", \"at least one haplosome is required\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomes(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomes(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomes('\" + temp_path + \"/slimOutputTest2.txt'); stop(); }\", __LINE__);\n\t}\n\t\n\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomes(NULL); stop(); }\", \"cannot output null haplosomes\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes[!p1.haplosomes.isNullHaplosome], 100, T).outputHaplosomes(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptRaise(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes, 100, T).outputHaplosomes('\" + temp_path + \"/slimOutputTest4.txt'); stop(); }\", \"cannot output null haplosomes\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.haplosomes[!p1.haplosomes.isNullHaplosome], 100, T).outputHaplosomes('\" + temp_path + \"/slimOutputTest5.txt'); stop(); }\", __LINE__);\n\t}\n\t\n\t// Test Haplosome + (void)outputHaplosomesToVCF([Ns$ filePath], [logical$ outputMultiallelics])\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 0, T).haplosomes.outputHaplosomesToVCF(); stop(); }\", \"at least one haplosome is required\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF('\" + temp_path + \"/slimOutputVCFTest2.txt'); stop(); }\", __LINE__);\n\t}\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF(NULL, F); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF('\" + temp_path + \"/slimOutputVCFTest4.txt', F); stop(); }\", __LINE__);\n\t}\n\t\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF(NULL); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF('\" + temp_path + \"/slimOutputVCFTest6.txt'); stop(); }\", __LINE__);\n\t}\n\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF(NULL, F); stop(); }\", __LINE__);\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_sex_p1 + \"10 late() { sample(p1.individuals, 100, T).haplosomes.outputHaplosomesToVCF('\" + temp_path + \"/slimOutputVCFTest8.txt', F); stop(); }\", __LINE__);\n\t}\n\t\n\t\n\t// BCH: This is just a temporary resting spot for these zygosityOfMutations() tests, which have been pulled back from the `multitrait` branch.\n\t\n\t// test the new zygosityOfMutations() method\n\t#pragma mark test_zygosity1\n\tstd::string test_zygosity1 =\t// simple one-chromosome diploid test\n\tR\"V0G0N(\n\t\tinitialize() {\n\t\t\tinitializeMutationRate(1e-7);\n\t\t\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.01);\n\t\t\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t\tinitializeGenomicElement(g1, 0, 9999999);\n\t\t\tinitializeRecombinationRate(1e-8);\n\t\t}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 10);\n\t\t}\n\t\t20 late() {\n\t\t\tinds = p1.individuals;\n\t\t\tmuts = sim.mutations;\n\t\t\t\n\t\t\t// calculate zygosity\n\t\t\tz = inds.zygosityOfMutations(NULL);\n\t\t\t\n\t\t\t// cross-check row sums: occurrence counts of each mutation\n\t\t\tmutCounts1 = rowSums(z);\n\t\t\tmutCounts2 = sim.mutationCounts(p1, NULL);\n\t\t\tif (!identical(mutCounts1, mutCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check column sums: the number of mutations per individual\n\t\t\tindCounts1 = colSums(z);\n\t\t\tindCounts2 = sapply(inds, \"applyValue.haplosomes.mutations.size();\");\n\t\t\tif (!identical(indCounts1, indCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check against a zygosity matrix from containsMutations()\n\t\t\tm = NULL;\n\t\t\tfor (ind in inds)\n\t\t\t{\n\t\t\t\tcounts_h0 = ind.haplosomes[0].containsMutations(muts);\n\t\t\t\tcounts_h1 = ind.haplosomes[1].containsMutations(muts);\n\t\t\t\tzygosity = asInteger(counts_h0) + asInteger(counts_h1);\n\t\t\t\tm = cbind(m, zygosity);\n\t\t\t}\n\t\t\tif (!identical(z, m))\n\t\t\t\tstop(\"zygosity matrices do not match\");\n\t\t}\n\t)V0G0N\";\n\t\n\tSLiMAssertScriptSuccess(test_zygosity1);\n\n\t#pragma mark test_zygosity2\n\tstd::string test_zygosity2 =\t// multiple chromosomes of different types\n\tR\"V0G0N(\n\t\tinitialize() {\n\t\t\tinitializeSex();\n\t\t\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.01);\n\t\t\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t\t\n\t\t\tids = 1:6;\n\t\t\tsymbols = c(1:3, \"X\", \"Y\", \"MT\");\n\t\t\tlengths = rdunif(6, 2e7, 4e7);\n\t\t\ttypes = c(rep(\"A\", 3), \"X\", \"Y\", \"H\");\n\t\t\t\n\t\t\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t\t\t{\n\t\t\t\tinitializeChromosome(id, length, type, symbol);\n\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\tinitializeRecombinationRate(1e-8);   // not used for the Y\n\t\t\t\tinitializeGenomicElement(g1);\n\t\t\t}\n\t\t}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 10);\n\t\t}\n\t\t20 late() {\n\t\t\tinds = p1.individuals;\n\t\t\tmuts = sim.mutations;\n\t\t\t\n\t\t\t// calculate zygosity\n\t\t\tz = inds.zygosityOfMutations(NULL);\n\t\t\t\n\t\t\t// cross-check row sums: occurrence counts of each mutation\n\t\t\tmutCounts1 = rowSums(z);\n\t\t\tmutCounts2 = sim.mutationCounts(p1, NULL);\n\t\t\tif (!identical(mutCounts1, mutCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check column sums: the number of mutations per individual\n\t\t\tindCounts1 = colSums(z);\n\t\t\tindCounts2 = sapply(inds, \"applyValue.haplosomesNonNull.mutations.size();\");\n\t\t\tif (!identical(indCounts1, indCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check against a zygosity matrix from containsMutations()\n\t\t\tm = NULL;\n\t\t\tfor (ind in inds)\n\t\t\t{\n\t\t\t\tzygosity = 0;\n\t\t\t\t\n\t\t\t\tfor (chromosome in sim.chromosomes)\n\t\t\t\t{\n\t\t\t\t\tchr_haplosomes = ind.haplosomesForChromosomes(chromosome, includeNulls=F);\n\t\t\t\t\t\n\t\t\t\t\tif (length(chr_haplosomes) == 0)\n\t\t\t\t\t\tnext;\n\t\t\t\t\t\n\t\t\t\t\tchr_muts_indices = which(muts.chromosome == chromosome);\n\t\t\t\t\tchr_muts = muts[chr_muts_indices];\n\t\t\t\t\t\n\t\t\t\t\tfor (hap in chr_haplosomes)\n\t\t\t\t\t{\n\t\t\t\t\t\tchr_muts_counts = hap.containsMutations(chr_muts);\n\t\t\t\t\t\tall_muts_counts = rep(0, length(muts));\n\t\t\t\t\t\tall_muts_counts[chr_muts_indices] = chr_muts_counts;\n\t\t\t\t\t\tzygosity = zygosity + all_muts_counts;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tm = cbind(m, zygosity);\n\t\t\t}\n\t\t\tif (!identical(z, m))\n\t\t\t\tstop(\"zygosity matrices do not match\");\n\t\t}\n\t)V0G0N\";\n\t\n\tSLiMAssertScriptSuccess(test_zygosity2);\n\n\t#pragma mark test_zygosity3\n\tstd::string test_zygosity3 =\t// same but passing mutations=mut explicitly, different code path\n\tR\"V0G0N(\n\t\tinitialize() {\n\t\t\tinitializeSex();\n\t\t\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.01);\n\t\t\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t\t\n\t\t\tids = 1:6;\n\t\t\tsymbols = c(1:3, \"X\", \"Y\", \"MT\");\n\t\t\tlengths = rdunif(6, 2e7, 4e7);\n\t\t\ttypes = c(rep(\"A\", 3), \"X\", \"Y\", \"H\");\n\t\t\t\n\t\t\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t\t\t{\n\t\t\t\tinitializeChromosome(id, length, type, symbol);\n\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\tinitializeRecombinationRate(1e-8);   // not used for the Y\n\t\t\t\tinitializeGenomicElement(g1);\n\t\t\t}\n\t\t}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 10);\n\t\t}\n\t\t20 late() {\n\t\t\tinds = p1.individuals;\n\t\t\tmuts = sim.mutations;\n\t\t\t\n\t\t\t// calculate zygosity\n\t\t\tz = inds.zygosityOfMutations(NULL);\n\t\t\t\n\t\t\t// cross-check row sums: occurrence counts of each mutation\n\t\t\tmutCounts1 = rowSums(z);\n\t\t\tmutCounts2 = sim.mutationCounts(p1, NULL);\n\t\t\tif (!identical(mutCounts1, mutCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check column sums: the number of mutations per individual\n\t\t\tindCounts1 = colSums(z);\n\t\t\tindCounts2 = sapply(inds, \"applyValue.haplosomesNonNull.mutations.size();\");\n\t\t\tif (!identical(indCounts1, indCounts2))\n\t\t\t\tstop(\"individual mutation counts do not match\");\n\t\t\t\n\t\t\t// cross-check against a zygosity matrix from containsMutations()\n\t\t\tm = NULL;\n\t\t\tfor (ind in inds)\n\t\t\t{\n\t\t\t\tzygosity = 0;\n\t\t\t\t\n\t\t\t\tfor (chromosome in sim.chromosomes)\n\t\t\t\t{\n\t\t\t\t\tchr_haplosomes = ind.haplosomesForChromosomes(chromosome, includeNulls=F);\n\t\t\t\t\t\n\t\t\t\t\tif (length(chr_haplosomes) == 0)\n\t\t\t\t\t\tnext;\n\t\t\t\t\t\n\t\t\t\t\tchr_muts_indices = which(muts.chromosome == chromosome);\n\t\t\t\t\tchr_muts = muts[chr_muts_indices];\n\t\t\t\t\t\n\t\t\t\t\tfor (hap in chr_haplosomes)\n\t\t\t\t\t{\n\t\t\t\t\t\tchr_muts_counts = hap.containsMutations(chr_muts);\n\t\t\t\t\t\tall_muts_counts = rep(0, length(muts));\n\t\t\t\t\t\tall_muts_counts[chr_muts_indices] = chr_muts_counts;\n\t\t\t\t\t\tzygosity = zygosity + all_muts_counts;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tm = cbind(m, zygosity);\n\t\t\t}\n\t\t\tif (!identical(z, m))\n\t\t\t\tstop(\"zygosity matrices do not match\");\n\t\t}\n\t)V0G0N\";\n\t\n\tSLiMAssertScriptSuccess(test_zygosity3);\n\t\n\t#pragma mark test_zygosity4\n\tstd::string test_zygosity4 =\t// test specified values for hemizygosity and haploidy\n\tR\"V0G0N(\n\t\tinitialize() {\n\t\t\tinitializeSex();\n\t\t\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.01);\n\t\t\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t\t\n\t\t\tids = 1:6;\n\t\t\tsymbols = c(1:3, \"X\", \"Y\", \"MT\");\n\t\t\tlengths = rdunif(6, 2e7, 4e7);\n\t\t\ttypes = c(rep(\"A\", 3), \"X\", \"Y\", \"H\");\n\t\t\t\n\t\t\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t\t\t{\n\t\t\t\tinitializeChromosome(id, length, type, symbol);\n\t\t\t\tinitializeMutationRate(1e-7);\n\t\t\t\tinitializeRecombinationRate(1e-8);   // not used for the Y\n\t\t\t\tinitializeGenomicElement(g1);\n\t\t\t}\n\t\t}\n\t\t1 early() {\n\t\t\tsim.addSubpop(\"p1\", 10);\n\t\t}\n\t\t20 late() {\n\t\t\tinds = p1.individuals;\n\t\t\tmuts = sample(sim.mutations, 1000, replace=T);\n\t\t\t\n\t\t\t// calculate zygosity\n\t\t\tz = inds.zygosityOfMutations(muts, hemizygousValue=3, haploidValue=4);\n\t\t\t\n\t\t\t// check that the correct values were used for each mutation\n\t\t\tfor (mut in muts, index in seqAlong(muts))\n\t\t\t{\n\t\t\t\tchr = mut.chromosome;\n\t\t\t\tcol = z[index,];\n\t\t\t\tu = sort(unique(col, preserveOrder=F));\n\t\t\t\tif (chr.type == \"A\")\n\t\t\t\t\texpected = c(0, 1, 2);\n\t\t\t\telse if (chr.type == \"X\")\n\t\t\t\t\texpected = c(0, 1, 2, 3);\n\t\t\t\telse if (chr.type == \"Y\")\n\t\t\t\t\texpected = c(0, 4);\n\t\t\t\telse if (chr.type == \"H\")\n\t\t\t\t\texpected = c(0, 4);\n\t\t\t\t\n\t\t\t\tif (any(match(u, expected) == -1))\n\t\t\t\t\tstop(\"for chromosome type \" + chr.type + \" expected (\" +\n\t\t\t\t\t\tpaste(expected, sep=\", \") + \") but saw (\" +\n\t\t\t\t\t\tpaste(u, sep=\", \") + \")\");\n\t\t\t}\n\t\t}\n\t)V0G0N\";\n\t\n\tSLiMAssertScriptSuccess(test_zygosity4);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test_other.cpp",
    "content": "//\n//  slim_test_other.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"slim_test.h\"\n\n#include \"eidos_globals.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_simd.h\"\n\n#include <string>\n#include <vector>\n#include <cstring>\n#include <cmath>\n\n\n#pragma mark InteractionType tests\nstatic void _RunInteractionTypeTests_Nonspatial(bool p_sex_enabled, const std::string &p_sex_segregation);\nstatic void _RunInteractionTypeTests_Spatial(const std::string &p_max_distance, bool p_sex_enabled, const std::string &p_sex_segregation);\nstatic void _RunInteractionTypeTests_LocalPopDensity(void);\nstatic void _RunSpatialKernelValueTests(void);\nstatic void _RunSpatialKernelSIMDTests(void);\n\nvoid _RunInteractionTypeTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tGen 1+ tests: InteractionType\n\t//\n\t\n\t// The goal here is to get good code coverage in interaction_type.cpp; with code of this complexity it's extremely difficult\n\t// to comprehensively test the actual functionality across all cases and code paths, but at least we can try to execute all\n\t// the major code paths and make sure we don't crash or anything.\n\t\n\t// Test InteractionType properties\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (i1.id == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (isInfinite(i1.maxDistance)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (i1.reciprocal == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (i1.sexSegregation == '**') stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { if (i1.spatiality == 'x') stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i1.id = 2; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i1.maxDistance = 0.5; if (i1.maxDistance == 0.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i1.reciprocal = F; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i1.sexSegregation = '**'; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i1.spatiality = 'x'; }\", \"read-only property\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { i1.tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1x + \"1 early() { c(i1,i1).tag; }\", \"before being set\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i1.tag = 17; } 2 early() { if (i1.tag == 17) stop(); }\", __LINE__);\n\t\n\t// Test clippedIntegral()\n\tSLiMAssertScriptRaise(gen1_setup_i1 + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", \"non-spatial interactions\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1x + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(p1.individuals[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xPx + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(p1.individuals[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xy + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(p1.individuals[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyPxy + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(p1.individuals[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz + \"1 early() { i1.maxDistance = 0.45; } late() { i1.evaluate(p1); i1.clippedIntegral(NULL); stop(); }\", \"not been implemented\", __LINE__);\n\t\n\t// Run tests in a variety of combinations\n\t_RunInteractionTypeTests_Nonspatial(false, \"**\");\n\t\n\t_RunInteractionTypeTests_Spatial(\" INF \", false, \"**\");\n\t_RunInteractionTypeTests_Spatial(\"999.0\", false, \"**\");\n\t\n\t_RunInteractionTypeTests_LocalPopDensity();\t\t// different enough to get its own call\n\n\t_RunSpatialKernelValueTests();\t\t\t\t\t// test numerical correctness of kernel calculations\n\t_RunSpatialKernelSIMDTests();\t\t\t\t\t// C++ level tests for SIMD kernel functions\n\n\tfor (int sex_seg_index = 0; sex_seg_index <= 8; ++sex_seg_index)\n\t{\n\t\t// For a full test, uncomment all cases below; that makes for a long test runtime, but it works.\n\t\t// Note that the tests are throttled down when sexSegregation != \"**\" anyway, because the results\n\t\t// will vary, and it's too much work to figure out the right answer for every test in every\n\t\t// combination; we just test for a crash or error.\n\t\tstd::string seg_str;\n\t\t\n\t\tswitch (sex_seg_index)\t\t// NOLINT(*-missing-default-case) : loop bounds\n\t\t{\n\t\t\tcase 0: seg_str = \"**\"; break;\n\t\t\tcase 1: seg_str = \"*M\"; break;\n\t\t\tcase 2: seg_str = \"*F\"; break;\n\t\t\tcase 3: seg_str = \"M*\"; break;\n\t\t\tcase 4: seg_str = \"MM\"; break;\n\t\t\tcase 5: seg_str = \"MF\"; break;\n\t\t\tcase 6: seg_str = \"F*\"; break;\n\t\t\tcase 7: seg_str = \"FM\"; break;\n\t\t\tcase 8: seg_str = \"FF\"; break;\n\t\t\tdefault: continue;\n\t\t}\n\t\t\n\t\t_RunInteractionTypeTests_Nonspatial(true, seg_str);\n\t\t\n\t\t_RunInteractionTypeTests_Spatial(\" INF \", true, seg_str);\n\t\t_RunInteractionTypeTests_Spatial(\"999.0\", true, seg_str);\n\t}\n}\n\nvoid _RunInteractionTypeTests_Nonspatial(bool p_sex_enabled, const std::string &p_sex_segregation)\n{\n\tstd::string sex_string = p_sex_enabled ? \"initializeSex('A'); \" : \"                    \";\n\tbool sex_seg_on = (p_sex_segregation != \"**\");\n\t\n\tstd::string gen1_setup_i1_pop(\"initialize() { initializeMutationRate(1e-5); \" + sex_string + \"initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', '', sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); } 1:10 late() { i1.evaluate(p1); i1.strength(p1.individuals[0]); } 1 late() { ind = p1.individuals; \");\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"i1.unevaluate(); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"i1.unevaluate(); i1.unevaluate(); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.distance(ind[0], ind[2]); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.interactionDistance(ind[0], ind[2]); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.distanceFromPoint(1.0, ind[0]); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"i1.drawByStrength(ind[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.nearestNeighbors(ind[8], 1); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.nearestInteractingNeighbors(ind[8], 1); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.interactingNeighborCount(ind[8]); stop(); }\", \"interaction be spatial\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.nearestNeighborsOfPoint(19.0, p1, 1); stop(); }\", \"interaction be spatial\", __LINE__);\n\t\n\tif (!sex_seg_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (i1.strength(ind[0], ind[2]) == 1.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5]), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5], NULL), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.strength(ind[0], ind[2]); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.strength(ind[5], NULL); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t}\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1_pop + \"i1.totalOfNeighborStrengths(ind[0]); stop(); }\", \"interaction be spatial\", __LINE__);\n}\n\nvoid _RunInteractionTypeTests_Spatial(const std::string &p_max_distance, bool p_sex_enabled, const std::string &p_sex_segregation)\n{\n\tstd::string sex_string = p_sex_enabled ? \"initializeSex('A'); \" : \"                    \";\n\tbool sex_seg_on = (p_sex_segregation != \"**\");\n\tbool max_dist_on = (p_max_distance != \" INF \");\t\t// the spaces make this the same width as \"999.0\", for error position checks\n\t\n\t// *** 1D\n\tfor (int i = 0; i < 3; ++i)\n\t{\n\t\tstd::string gen1_setup_i1x_pop;\n\t\tstd::string spatiality;\n\t\t\n\t\t// test spatiality 'x', 'y', and 'z'\n\t\tif (i == 0)\n\t\t{\n\t\t\tspatiality = \"x\";\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', '\" + spatiality + \"', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.\" + spatiality + \" = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse if (i == 1)\n\t\t{\n\t\t\tspatiality = \"y\";\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', '\" + spatiality + \"', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.\" + spatiality + \" = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tspatiality = \"z\";\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', '\" + spatiality + \"', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.\" + spatiality + \" = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)distance(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.distance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[2], ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (i1.distance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[8], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[5]), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distance(ind[5], NULL), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.interactionDistance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[0:1], ind[2]), c(11.0, 1.0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (i1.interactionDistance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, INF, 20, 15, 5))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[integer(0)], ind[8]), float(0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[5]), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[5], NULL), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// comprehensively testing all the different sex-seg cases is complicated, but we can at least test the two branches of the code against each other\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.interactionDistance(ind[5]), i1.interactionDistance(ind[5], NULL))) stop(); }\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)distanceFromPoint(float point, object<Individual> individuals1)\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.distanceFromPoint(1.0, ind[0]) == 11.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distanceFromPoint(1.0, ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (i1.distanceFromPoint(1.0:2.0, ind[0:1]) == 11.0) stop(); }\", \"point is of length equal to\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distanceFromPoint(5.0, ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.distanceFromPoint(8.0, ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)drawByStrength(object<Individual>$ individual, [integer$ count = 1])\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0]); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 50); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], -1); stop(); }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return strength * 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind, returnDict=T); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.drawByStrength(ind, returnDict=T); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (void)evaluate(io<Subpopulation> subpops)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.evaluate(); stop(); }\", \"required argument 'subpops'\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.evaluate(p1); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.evaluate(1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.evaluate(NULL); stop(); }\", \"cannot be type NULL\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.evaluate(10); stop(); }\", \"p10 not defined\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t\t// Test InteractionType – (integer)neighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\t// Test InteractionType – (integer$)neighborCountOfPoint(float point, io<Subpopulation>$ exerterSubpop)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighbors(ind[8], 1), ind[9])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(sortBy(i1.nearestNeighbors(ind[8], 3), 'index'), ind[c(6,7,9)])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.neighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) + 1 == i1.neighborCountOfPoint(ind[\" + std::to_string(ind_index) + \"].\" + spatiality + \", p1)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x_pop + \"nn = i1.nearestNeighbors(ind, 100, returnDict=T); nc = i1.neighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestInteractingNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t\t// Test InteractionType – (object<Individual>)interactingNeighborCount(object<Individual>$ individual, [integer$ count = 1])\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.interactingNeighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == sum(isFinite(i1.interactionDistance(ind[\" + std::to_string(ind_index) + \"])))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1x_pop + \"nn = i1.nearestInteractingNeighbors(ind, 100, returnDict=T); nc = i1.interactingNeighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\t\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.nearestInteractingNeighbors(ind, returnDict=T); stop(); } interaction(i1) { return 'foo'; }\", __LINE__);\t// doesn't raise because it doesn't use strengths\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.nearestInteractingNeighbors(ind, returnDict=T); stop(); } interaction(i1) { return 'foo'+'bar'; }\", __LINE__);\t// doesn't raise because it doesn't use strengths\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.interactingNeighborCount(ind); stop(); } interaction(i1) { return 'foo'; }\", __LINE__);\t// doesn't raise because it doesn't use strengths\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.interactingNeighborCount(ind); stop(); } interaction(i1) { return 'foo'+'bar'; }\", __LINE__);\t// doesn't raise because it doesn't use strengths\n\t\t}\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ subpop, [integer$ count = 1])\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(5.0, p1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(5.0, p1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(19.0, p1, 1), ind[8])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(19.0, p1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(5.0, 1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(5.0, 1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.nearestNeighborsOfPoint(19.0, 1, 1), ind[8])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(19.0, 1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(19.0, 10, 3), 'index'), ind[c(7,8,9)])) stop(); }\", \"p10 not defined\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (void)setInteractionFunction(string$ functionType, ...)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"while the interaction is being evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"functionType 'q' must be\", __LINE__);\n\t\tif (max_dist_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('f'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t}\n\t\telse\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\t\t\n\t\tif (!max_dist_on)\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, -1.0); stop(); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 0.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, -1.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (float)strength(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.strength(ind[0], ind[2]) == 1.0) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(1.0, 0.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5]), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], NULL), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.strength(ind[0], ind[2]); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.strength(ind[0], ind[2]); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.strength(ind[5], NULL); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.strength(ind[5], NULL); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)totalOfNeighborStrengths(object<Individual> individuals)\n\t\tif (!sex_seg_on)\t// cppcheck-suppress duplicateCondition\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(9.0, 9.0, 9.0))) stop(); }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind[0]); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind); stop(); } interaction(i1) { return 'foo'; }\", \"callbacks must provide\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind[0]); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.totalOfNeighborStrengths(ind); stop(); } interaction(i1) { return 'foo'+'bar'; }\", \"callbacks must provide\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (void)unevaluate(void)\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.unevaluate(); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.distance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.interactionDistance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.distanceFromPoint(1.0, ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.drawByStrength(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.nearestNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.nearestInteractingNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.interactingNeighborCount(ind[8]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.nearestNeighborsOfPoint(19.0, p1, 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.strength(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.unevaluate(); i1.totalOfNeighborStrengths(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t}\n\t\n\t// *** 2D\n\tfor (int i = 0; i < 6; ++i)\n\t{\n\t\tstd::string gen1_setup_i1xy_pop;\n\t\tbool use_first_coordinate = (i < 3);\n\t\tstd::string spatiality;\n\t\t\n\t\t// test spatiality 'xy' for x and y, 'xz' for x and z, and 'yz' for y and z \n\t\tif (i == 0)\n\t\t{\n\t\t\tspatiality = \"xy\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = 0.0; p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse if (i == 1)\n\t\t{\n\t\t\tspatiality = \"xz\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.z = 0.0; p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse if (i == 2)\n\t\t{\n\t\t\tspatiality = \"yz\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'yz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.z = 0.0; p1.individuals.x = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse if (i == 3)\n\t\t{\n\t\t\tspatiality = \"xy\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = 0.0; p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse if (i == 4)\n\t\t{\n\t\t\tspatiality = \"xz\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = 0.0; p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\telse // if (i == 5)\n\t\t{\n\t\t\tspatiality = \"yz\";\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'yz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = 0.0; p1.individuals.x = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)distance(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.distance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[2], ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (i1.distance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[5]), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distance(ind[5], NULL), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.interactionDistance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[0:1], ind[2]), c(11.0, 1.0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (i1.interactionDistance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, INF, 20, 15, 5))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[integer(0)], ind[8]), float(0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[5]), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[5], NULL), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// comprehensively testing all the different sex-seg cases is complicated, but we can at least test the two branches of the code against each other\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.interactionDistance(ind[5]), i1.interactionDistance(ind[5], NULL))) stop(); }\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)distanceFromPoint(float point, object<Individual> individuals1)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.distanceFromPoint(c(\" + (use_first_coordinate ? \"1.0, 0.0\" : \"0.0, 1.0\") + \"), ind[0]) == 11.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distanceFromPoint(c(\" + (use_first_coordinate ? \"1.0, 0.0\" : \"0.0, 1.0\") + \"), ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (i1.distanceFromPoint(1.0, ind[0:1]) == 11.0) stop(); }\", \"point is of length equal to\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distanceFromPoint(c(\" + (use_first_coordinate ? \"5.0, 0.0\" : \"0.0, 5.0\") + \"), ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.distanceFromPoint(c(\" + (use_first_coordinate ? \"8.0, 0.0\" : \"0.0, 8.0\") + \"), ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)drawByStrength(object<Individual>$ individual, [integer$ count = 1])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0]); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 50); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], -1); stop(); }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return strength * 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (void)evaluate(io<Subpopulation> subpops)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.evaluate(p1); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.evaluate(1); stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t\t// Test InteractionType – (integer)neighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\t// Test InteractionType – (integer$)neighborCountOfPoint(float point, io<Subpopulation>$ exerterSubpop)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighbors(ind[8], 1), ind[9])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(sortBy(i1.nearestNeighbors(ind[8], 3), 'index'), ind[c(6,7,9)])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.neighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) + 1 == i1.neighborCountOfPoint(ind[\" + std::to_string(ind_index) + \"].\" + spatiality + \", p1)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1xy_pop + \"nn = i1.nearestNeighbors(ind, 100, returnDict=T); nc = i1.neighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestInteractingNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t\t// Test InteractionType – (object<Individual>)interactingNeighborCount(object<Individual>$ individual, [integer$ count = 1])\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.interactingNeighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\t\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == sum(isFinite(i1.interactionDistance(ind[\" + std::to_string(ind_index) + \"])))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptSuccess(gen1_setup_i1xy_pop + \"nn = i1.nearestInteractingNeighbors(ind, 100, returnDict=T); nc = i1.interactingNeighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ subpop, [integer$ count = 1])\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0), p1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0), p1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(\" + (use_first_coordinate ? \"19.0, 0.0\" : \"0.0, 19.0\") + \"), p1, 1), ind[8])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(\" + (use_first_coordinate ? \"19.0, 0.0\" : \"0.0, 19.0\") + \"), p1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0), 1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0), 1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(\" + (use_first_coordinate ? \"19.0, 0.0\" : \"0.0, 19.0\") + \"), 1, 1), ind[8])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(\" + (use_first_coordinate ? \"19.0, 0.0\" : \"0.0, 19.0\") + \"), 1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (void)setInteractionFunction(string$ functionType, ...)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"while the interaction is being evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"functionType 'q' must be\", __LINE__);\n\t\tif (max_dist_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('f'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t}\n\t\telse\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\t\t\n\t\tif (!max_dist_on)\n\t\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, -1.0); stop(); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 0.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, -1.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\t\t\n\t\t// Test InteractionType – (float)strength(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\t\tif (!sex_seg_on)\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.strength(ind[0], ind[2]) == 1.0) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(1.0, 0.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5]), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], NULL), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (float)totalOfNeighborStrengths(object<Individual> individuals)\n\t\tif (!sex_seg_on)\t// cppcheck-suppress duplicateCondition\n\t\t{\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 9.0)) stop(); }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(9.0, 9.0, 9.0))) stop(); }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\t}\n\t\t\n\t\t// Test InteractionType – (void)unevaluate(void)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.unevaluate(); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.distance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.interactionDistance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.distanceFromPoint(c(1.0, 0.0), ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.drawByStrength(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.nearestNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.nearestInteractingNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.interactingNeighborCount(ind[8]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.nearestNeighborsOfPoint(19.0, p1, 1); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.strength(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xy_pop + \"i1.unevaluate(); i1.totalOfNeighborStrengths(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t}\n\t\n\t// *** 3D with y and z zero\n\tstd::string gen1_setup_i1xyz_pop(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xyz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = 0.0; p1.individuals.z = 0.0; i1.evaluate(p1); ind = p1.individuals; \");\n\t\n\t// Test InteractionType – (float)distance(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.distance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[2], ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (i1.distance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[5]), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distance(ind[5], NULL), c(15.0, 5, 4, 3, 2, 0, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\tif (!sex_seg_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.interactionDistance(ind[0], ind[2]) == 11.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[0:1], ind[2]), c(11.0, 1.0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[0], ind[2:3]), c(11.0, 12.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (i1.interactionDistance(ind[0:1], ind[2:3]) == 11.0) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[5], ind[c(0, 5, 9, 8, 1)]), c(15.0, INF, 20, 15, 5))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[integer(0)], ind[8]), float(0))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[5]), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[5], NULL), c(15.0, 5, 4, 3, 2, INF, 2, 3, 15, 20))) stop(); }\", __LINE__);\n\t}\n\telse\n\t{\n\t\t// comprehensively testing all the different sex-seg cases is complicated, but we can at least test the two branches of the code against each other\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.interactionDistance(ind[5]), i1.interactionDistance(ind[5], NULL))) stop(); }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (float)distanceFromPoint(float point, object<Individual> individuals1)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.distanceFromPoint(c(1.0, 0.0, 0.0), ind[0]) == 11.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distanceFromPoint(c(1.0, 0.0, 0.0), ind[0:1]), c(11.0, 1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (i1.distanceFromPoint(1.0, ind[0:1]) == 11.0) stop(); }\", \"point is of length equal to\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distanceFromPoint(c(5.0, 0.0, 0.0), ind[c(0, 5, 9, 8, 1)]), c(15.0, 0, 20, 15, 5))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.distanceFromPoint(c(8.0, 0.0, 0.0), ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)drawByStrength(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 50); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], -1); stop(); }\", \"requires count >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.drawByStrength(ind[0], 0), ind[integer(0)])) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.drawByStrength(ind[0], -1); stop(); } interaction(i1) { return strength * 2.0; }\", \"requires count >= 0\", __LINE__);\n\t\n\t// Test InteractionType – (void)evaluate(io<Subpopulation> subpops)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.evaluate(p1); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.evaluate(1); stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighbors(ind[8], 1), ind[9])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(sortBy(i1.nearestNeighbors(ind[8], 3), 'index'), ind[c(6,7,9)])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.neighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) + 1 == i1.neighborCountOfPoint(ind[\" + std::to_string(ind_index) + \"].xyz, p1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1xyz_pop + \"nn = i1.nearestNeighbors(ind, 100, returnDict=T); nc = i1.neighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestInteractingNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t// Test InteractionType – (object<Individual>)interactingNeighborCount(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestInteractingNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.interactingNeighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == sum(isFinite(i1.interactionDistance(ind[\" + std::to_string(ind_index) + \"])))) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1xyz_pop + \"nn = i1.nearestInteractingNeighbors(ind, 100, returnDict=T); nc = i1.interactingNeighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ subpop, [integer$ count = 1])\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0, 0.0), p1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0, 0.0), p1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(19.0, 0.0, 0.0), p1, 1), ind[8])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(19.0, 0.0, 0.0), p1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0, 0.0), 1, -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(5.0, 0.0, 0.0), 1, 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.nearestNeighborsOfPoint(c(19.0, 0.0, 0.0), 1, 1), ind[8])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(19.0, 0.0, 0.0), 1, 3), 'index'), ind[c(7,8,9)])) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (void)setInteractionFunction(string$ functionType, ...)\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"while the interaction is being evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('q', 10.0); i1.evaluate(p1); stop(); }\", \"functionType 'q' must be\", __LINE__);\n\tif (max_dist_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('f'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t}\n\telse\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\t\n\tif (!max_dist_on)\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", \"finite maximum interaction distance\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l'); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0, 2.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 2.0, 1.0); i1.evaluate(p1); stop(); }\", \"requires exactly\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, -1.0); stop(); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, 0.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('c', 5.0, -1.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\t\n\t// Test InteractionType – (float)strength(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\tif (!sex_seg_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.strength(ind[0], ind[2]) == 1.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(1.0, 0.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5]), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], NULL), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], ind[c(0, 5, 9, 8, 1)]), c(2.0, 0.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[1], ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (float)totalOfNeighborStrengths(object<Individual> individuals)\n\tif (!sex_seg_on)\t// cppcheck-suppress duplicateCondition\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 9.0)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 9.0)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 9.0)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(9.0, 9.0, 9.0))) stop(); }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[integer(0)]), float(0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[5]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[9]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"if (identical(i1.totalOfNeighborStrengths(ind[c(0, 5, 9)]), c(18.0, 18.0, 18.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (void)unevaluate(void)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.unevaluate(); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.distance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.interactionDistance(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.distanceFromPoint(c(1.0, 0.0, 0.0), ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.drawByStrength(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.nearestNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.nearestInteractingNeighbors(ind[8], 1); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.interactingNeighborCount(ind[8]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.nearestNeighborsOfPoint(19.0, p1, 1); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.strength(ind[0], ind[2]); stop(); }\", \"must be evaluated\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop + \"i1.unevaluate(); i1.totalOfNeighborStrengths(ind[0]); stop(); }\", \"must be evaluated\", __LINE__);\n\t\n\t// *** 3D with full 3D coordinates; we skip the error-testing here since it's the same as before\n\tstd::string gen1_setup_i1xyz_pop_full(\"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xyz', maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = c(12.0, 3, -2, 10, 8, 72, 0, -5, -13, 7); p1.individuals.z = c(0.0, 5, 9, -6, 6, -16, 2, 1, -1, 8); i1.evaluate(p1); ind = p1.individuals; \");\n\t\n\t// Test InteractionType – (float)distance(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.distance(ind[0], ind[2]) == sqrt(11^2 + 14^2 + 9^2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.distance(ind[2], ind[0:1]), c(sqrt(11^2 + 14^2 + 9^2), sqrt(1^2 + 5^2 + 4^2)))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.distance(ind[0], ind[2:3]), c(sqrt(11^2 + 14^2 + 9^2), sqrt(12^2 + 2^2 + 6^2)))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (all(i1.distance(ind[5]) - c(63.882705, 72.2979, 78.2112, 62.8728, 67.7052,  0.0, 74.2428, 78.9113, 87.6070, 72.1179) < 0.001)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (all(i1.distance(ind[5], NULL) - c(63.882705, 72.2979, 78.2112, 62.8728, 67.7052,  0.0, 74.2428, 78.9113, 87.6070, 72.1179) < 0.001)) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\tif (!sex_seg_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.interactionDistance(ind[0], ind[2]) - sqrt(11^2 + 14^2 + 9^2) < 0.001) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop_full + \"if (identical(i1.interactionDistance(ind[0:1], ind[2]), c(sqrt(11^2 + 14^2 + 9^2), sqrt(1^2 + 5^2 + 4^2)))) stop(); }\", \"must be a singleton\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (all(i1.interactionDistance(ind[0], ind[2:3]) - c(sqrt(11^2 + 14^2 + 9^2), sqrt(12^2 + 2^2 + 6^2)) < 0.001)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (all(i1.interactionDistance(ind[5])[c(0:4,6:9)] - c(63.882705, 72.2979, 78.2112, 62.8728, 67.7052, 74.2428, 78.9113, 87.6070, 72.1179) < 0.001)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (all(i1.interactionDistance(ind[5], NULL)[c(0:4,6:9)] - c(63.882705, 72.2979, 78.2112, 62.8728, 67.7052, 74.2428, 78.9113, 87.6070, 72.1179) < 0.001)) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (isInfinite(i1.interactionDistance(ind[5])[5])) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (isInfinite(i1.interactionDistance(ind[5], NULL)[5])) stop(); }\", __LINE__);\n\t}\n\telse\n\t{\n\t\t// comprehensively testing all the different sex-seg cases is complicated, but we can at least test the two branches of the code against each other\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.interactionDistance(ind[5]), i1.interactionDistance(ind[5], NULL))) stop(); }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (float)distanceFromPoint(float point, object<Individual> individuals1)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.distanceFromPoint(c(-7.0, 12.0, 4.0), ind[0]) == 5.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.distanceFromPoint(c(-7.0, 12.0, 4.0), ind[0:1]), c(5.0, sqrt(7^2 + 9^2 + 1^2)))) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)drawByStrength(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0]); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 50); stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0]); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 1); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.drawByStrength(ind[0], 50); stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\n\t// Test InteractionType – (void)evaluate(io<Subpopulation> subpops)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.evaluate(p1); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.evaluate(1); stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestNeighbors(ind[8], 1), ind[7])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(sortBy(i1.nearestNeighbors(ind[8], 3), 'index'), ind[c(6,7,9)])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.neighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (size(i1.nearestNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) + 1 == i1.neighborCountOfPoint(ind[\" + std::to_string(ind_index) + \"].xyz, p1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1xyz_pop_full + \"nn = i1.nearestNeighbors(ind, 100, returnDict=T); nc = i1.neighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestInteractingNeighbors(object<Individual>$ individual, [integer$ count = 1])\n\t// Test InteractionType – (object<Individual>)interactingNeighborCount(object<Individual>$ individual, [integer$ count = 1])\n\tSLiMAssertScriptRaise(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestInteractingNeighbors(ind[8], -1), ind[integer(0)])) stop(); }\", \"requires count >= 0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestInteractingNeighbors(ind[8], 0), ind[integer(0)])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == i1.interactingNeighborCount(ind[\" + std::to_string(ind_index) + \"])) stop(); }\", __LINE__);\n\tfor (int ind_index = 0; ind_index < 10; ++ind_index)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (size(i1.nearestInteractingNeighbors(ind[\" + std::to_string(ind_index) + \"], 100)) == sum(isFinite(i1.interactionDistance(ind[\" + std::to_string(ind_index) + \"])))) stop(); }\", __LINE__);\n\tSLiMAssertScriptSuccess(gen1_setup_i1xyz_pop_full + \"nn = i1.nearestInteractingNeighbors(ind, 100, returnDict=T); nc = i1.interactingNeighborCount(ind); for (i in 0:9) if (size(nn.getValue(i)) != nc[i]) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ subpop, [integer$ count = 1])\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestNeighborsOfPoint(c(-7.0, 12.0, 4.0), p1, 1), ind[0])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestNeighborsOfPoint(c(7.0, 3.0, 12.0), p1, 1), ind[2])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(19.0, -4.0, -2.0), p1, 3), 'index'), ind[c(6,7,8)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(7.0, 3.0, 12.0), p1, 3), 'index'), ind[c(1,2,4)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestNeighborsOfPoint(c(-7.0, 12.0, 4.0), 1, 1), ind[0])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.nearestNeighborsOfPoint(c(7.0, 3.0, 12.0), 1, 1), ind[2])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(19.0, -4.0, -2.0), 1, 3), 'index'), ind[c(6,7,8)])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(sortBy(i1.nearestNeighborsOfPoint(c(7.0, 3.0, 12.0), 1, 3), 'index'), ind[c(1,2,4)])) stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (void)setInteractionFunction(string$ functionType, ...)\n\tif (max_dist_on)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.setInteractionFunction('f', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('l', 5.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('e', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.maxDistance=1.0; i1.setInteractionFunction('n', 5.0, 1.0); i1.evaluate(p1); stop(); }\", __LINE__);\n\t\n\t// Test InteractionType – (float)strength(object<Individual> individuals1, [No<Individual> individuals2 = NULL])\n\tif (!sex_seg_on)\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.strength(ind[0], ind[2]) == 1.0) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[0], ind[2:3]), c(1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5]), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5], NULL), c(1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0))) stop(); }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (i1.strength(ind[0], ind[2]) == 2.0) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[0], ind[2:3]), c(2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5]), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.strength(ind[5], NULL), c(2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 2.0))) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (float)totalOfNeighborStrengths(object<Individual> individuals)\n\tif (!sex_seg_on)\t// cppcheck-suppress duplicateCondition\n\t{\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 9.0)) stop(); }\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"if (identical(i1.totalOfNeighborStrengths(ind[0]), 18.0)) stop(); } interaction(i1) { return strength * 2.0; }\", __LINE__);\n\t}\n\t\n\t// Test InteractionType – (void)unevaluate(void)\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.evaluate(p1); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_i1xyz_pop_full + \"i1.unevaluate(); i1.unevaluate(); stop(); }\", __LINE__);\n\t\n\t// *** Test all spatial queries with (1) empty receivers vector, (2) empty exerter subpop, (3) no qualified receivers, (4) no qualified exerters, all for (a) returnDict=F vs. (b) returnDict=T\n\t// We do this only for 2D at present; the logic is generally shared, for this level of functionality.  We use a nonWF model so we can have empty subpopulations; p1 has 10 male individuals,\n\t// p2 has 10 female individuals, and p3 is empty.  We randomize positions each time, unlike the tests above.  We don't look at results here at all; the goal is just to exercise the code paths\n\t// and make sure nothing crashes.\n\tfor (int periodic = 0; periodic <= 1; ++periodic)\n\t{\n\t\tif ((periodic == 1) && (!max_dist_on))\n\t\t\tcontinue;\n\t\t\n\t\tstd::string periodic_str = (periodic ? \", periodicity='xy'\" : \"\");\n\t\tstd::string max_distance = (periodic ? \" 0.45 \" : p_max_distance);\n\t\tstd::string gen1_setup_i1xy_edge_cases;\n\t\t\n\t\tif (p_sex_enabled)\n\t\t\tgen1_setup_i1xy_edge_cases = std::string(\"initialize() { initializeSLiMModelType('nonWF'); initializeSLiMOptions(dimensionality='xy'\" + periodic_str + \"); \" + sex_string + \"initializeInteractionType('i1', 'xy', maxDistance=\" + max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10, sexRatio=1.0); p1.individuals.setSpatialPosition(p1.pointUniform(10)); sim.addSubpop('p2', 10, sexRatio=0.0); p2.individuals.setSpatialPosition(p2.pointUniform(10)); sim.addSubpop('p3', 0); i1.evaluate(c(p1,p2,p3)); ind1 = p1.individuals; ind2 = p2.individuals; ind3 = p3.individuals; \");\n\t\telse\n\t\t\tgen1_setup_i1xy_edge_cases = std::string(\"initialize() { initializeSLiMModelType('nonWF'); initializeSLiMOptions(dimensionality='xy'\" + periodic_str + \"); initializeInteractionType('i1', 'xy', maxDistance=\" + max_distance + \"); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.setSpatialPosition(p1.pointUniform(10)); sim.addSubpop('p2', 10); p2.individuals.setSpatialPosition(p2.pointUniform(10)); sim.addSubpop('p3', 0); i1.evaluate(c(p1,p2,p3)); ind1 = p1.individuals; ind2 = p2.individuals; ind3 = p3.individuals; \");\n\t\t\n\t\t// (float)distance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.distance(ind1[0], ind2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.distance(ind1[0], ind3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (float)distanceFromPoint(float point, object<Individual> exerters)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.distanceFromPoint(ind1[0].xy, ind2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.distanceFromPoint(ind1[0].xy, ind3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (object)drawByStrength(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 0, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 1, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 100, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 0, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 1, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 100, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// drawByStrength(, returnDict=T)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind3, 1000, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0], 100, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.drawByStrength(ind1[0:1], 100, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (integer)interactingNeighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind3, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind1[0], p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind1[0:1], p2); stop(); }\", __LINE__);\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind3, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind1[0], p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactingNeighborCount(ind1[0:1], p3); stop(); }\", __LINE__);\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (float)interactionDistance(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactionDistance(ind1[0], ind2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.interactionDistance(ind1[0], ind3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (float)localPopulationDensity(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\t// we do all of these in a single model because of the large first-time overhead\n\t\tif (max_dist_on)\n\t\t{\n\t\t\tstd::string gen1_setup_i1xy_edge_cases_MAX;\t\t// clippedIntegral() requires a short maximum distance; we use 0.45\n\t\t\t\n\t\t\tif (p_sex_enabled)\n\t\t\t\tgen1_setup_i1xy_edge_cases_MAX = std::string(\"initialize() { initializeSLiMModelType('nonWF'); initializeSLiMOptions(dimensionality='xy'); \" + sex_string + \"initializeInteractionType('i1', 'xy', maxDistance=0.45, sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10, sexRatio=1.0); p1.individuals.setSpatialPosition(p1.pointUniform(10)); sim.addSubpop('p2', 10, sexRatio=0.0); p2.individuals.setSpatialPosition(p2.pointUniform(10)); sim.addSubpop('p3', 0); i1.evaluate(c(p1,p2,p3)); ind1 = p1.individuals; ind2 = p2.individuals; ind3 = p3.individuals; \");\n\t\t\telse\n\t\t\t\tgen1_setup_i1xy_edge_cases_MAX = std::string(\"initialize() { initializeSLiMModelType('nonWF'); initializeSLiMOptions(dimensionality='xy'); initializeInteractionType('i1', 'xy', maxDistance=0.45); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.setSpatialPosition(p1.pointUniform(10)); sim.addSubpop('p2', 10); p2.individuals.setSpatialPosition(p2.pointUniform(10)); sim.addSubpop('p3', 0); i1.evaluate(c(p1,p2,p3)); ind1 = p1.individuals; ind2 = p2.individuals; ind3 = p3.individuals; \");\n\t\t\t\n\t\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases_MAX + \"i1.localPopulationDensity(ind3, p2); \"\t\t\t\t\t\t\t\t\t\t\t// empty receiver\n\t\t\t\t\t\t\t\t + \"i1.localPopulationDensity(ind1[0], p2); \"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\t\t\t\t\t\t\t + \"i1.localPopulationDensity(ind1[0:1], p2); \"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\t\t\t\t\t\t\t + \"i1.localPopulationDensity(ind3, p3); \"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\t\t\t\t\t\t\t + \"i1.localPopulationDensity(ind1[0], p3); \"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\t\t\t\t\t\t + \"i1.localPopulationDensity(ind1[0:1], p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t}\n\t\t\n\t\t// (object)nearestInteractingNeighbors(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 0, p2); stop(); }\", __LINE__);\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 1, p2); stop(); }\", __LINE__);\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 100, p2); stop(); }\", __LINE__);\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 0, p3); stop(); }\", __LINE__);\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 1, p3); stop(); }\", __LINE__);\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 100, p3); stop(); }\", __LINE__);\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// nearestInteractingNeighbors(, returnDict=T)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 0, p2, returnDict=T); stop(); }\", __LINE__);\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 1, p2, returnDict=T); stop(); }\", __LINE__);\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 100, p2, returnDict=T); stop(); }\", __LINE__);\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 100, p2, returnDict=T); stop(); }\", __LINE__);\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind3, 1000, p3, returnDict=T); stop(); }\", __LINE__);\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 0, p3, returnDict=T); stop(); }\", __LINE__);\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 1, p3, returnDict=T); stop(); }\", __LINE__);\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0], 100, p3, returnDict=T); stop(); }\", __LINE__);\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestInteractingNeighbors(ind1[0:1], 100, p3, returnDict=T); stop(); }\", __LINE__);\t// empty exerter subpop\n\t\t\n\t\t// (object)nearestNeighbors(object<Individual> receiver, [integer$ count = 1], [No<Subpopulation>$ exerterSubpop = NULL], [logical$ returnDict = F])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 0, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 1, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 100, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 0, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 1, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 100, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// nearestNeighbors(, returnDict=T)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 0, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 1, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 100, p2, returnDict=T); stop(); }\", __LINE__);\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind3, 1000, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 0, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 1, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0], 100, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighbors(ind1[0:1], 100, p3, returnDict=T); stop(); }\", __LINE__);\t\t\t// empty exerter subpop\n\t\t\n\t\t// (object<Individual>)nearestNeighborsOfPoint(float point, io<Subpopulation>$ exerterSubpop, [integer$ count = 1])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=0); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=1); stop(); }\", __LINE__);\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=100); stop(); }\", __LINE__);\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=0); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=1); stop(); }\", __LINE__);\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.nearestNeighborsOfPoint(ind1[0].xy, p2, count=100); stop(); }\", __LINE__);\t\t\t// empty exerter subpop\n\t\t\n\t\t// (integer)neighborCount(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind3, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind1[0], p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind1[0:1], p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind3, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind1[0], p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCount(ind1[0:1], p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (integer$)neighborCountOfPoint(float point, io<Subpopulation>$ exerterSubpop)\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCountOfPoint(ind1[0].xy, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.neighborCountOfPoint(ind1[0].xy, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (float)strength(object<Individual>$ receiver, [No<Individual> exerters = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.strength(ind1[0], ind2); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.strength(ind1[0], ind3); stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t\t// empty exerter subpop\n\t\t\n\t\t// (float)totalOfNeighborStrengths(object<Individual> receivers, [No<Subpopulation>$ exerterSubpop = NULL])\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind3, p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty receiver\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind1[0], p2); stop(); }\", __LINE__);\t\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind1[0:1], p2); stop(); }\", __LINE__);\t\t\t\t\t\t// sex-segregation effects\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind3, p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty receiver, empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind1[0], p3); stop(); }\", __LINE__);\t\t\t\t\t\t\t// empty exerter subpop\n\t\tSLiMAssertScriptStop(gen1_setup_i1xy_edge_cases + \"i1.totalOfNeighborStrengths(ind1[0:1], p3); stop(); }\", __LINE__);\t\t\t\t\t\t// empty exerter subpop\n\t}\n}\n\nvoid _RunInteractionTypeTests_LocalPopDensity()\n{\n\t// Test InteractionType - localPopulationDensity()\n\t// FIXME for now we just make the calls, we don't test the results\n\t\n\t// *** 1D\n\tfor (int i = 0; i < 6; ++i)\n\t{\n\t\tstd::string gen1_setup_i1x_pop;\n\t\t\n\t\tif (i == 0)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'x', reciprocal=T, maxDistance=10.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 1)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'y', reciprocal=T, maxDistance=10.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 2)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'z', reciprocal=T, maxDistance=10.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t\n\t\t// go beyond type 'f', since that hits an optimized case\n\t\telse if (i == 3)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'x', reciprocal=T, maxDistance=10.0); i1.setInteractionFunction('l', 1.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 4)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'y', reciprocal=T, maxDistance=10.0); i1.setInteractionFunction('l', 1.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse // if (i == 5)\n\t\t\tgen1_setup_i1x_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'z', reciprocal=T, maxDistance=10.0); i1.setInteractionFunction('l', 1.0); } 1 early() { sim.addSubpop('p1', 10); p1.setSpatialBounds(c(-30, -30, -30, 30, 30, 30)); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = runif(10); p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[integer(0)]); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[0]); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[c(0, 5, 9)]); stop(); }\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[integer(0)]); stop(); } interaction(i1) { return 2.0; }\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[0]); stop(); } interaction(i1) { return 2.0; }\", \"interaction() callbacks\", __LINE__);\n\t\tSLiMAssertScriptRaise(gen1_setup_i1x_pop + \"i1.localPopulationDensity(ind[c(0, 5, 9)]); stop(); } interaction(i1) { return 2.0; }\", \"interaction() callbacks\", __LINE__);\n\t}\n\t/*\n\t// *** 2D\n\tfor (int i = 0; i < 6; ++i)\n\t{\n\t\tstd::string gen1_setup_i1xy_pop;\n\t\tbool use_first_coordinate = (i < 3);\n\t\t\n\t\tif (i == 0)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = 0.0; p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 1)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xz', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.x = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.z = 0.0; p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 2)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'yz', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.z = 0.0; p1.individuals.x = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 3)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xy', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.y = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = 0.0; p1.individuals.z = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse if (i == 4)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'xz', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.x = 0.0; p1.individuals.y = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\telse // if (i == 5)\n\t\t\tgen1_setup_i1xy_pop = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); \" + sex_string + \"initializeMutationRate(1e-5); initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeRecombinationRate(1e-8); initializeInteractionType('i1', 'yz', \" + reciprocal_string + \", maxDistance=\" + p_max_distance + \", sexSegregation='\" + p_sex_segregation + \"'); } 1 early() { sim.addSubpop('p1', 10); p1.individuals.z = c(-10.0, 0, 1, 2, 3, 5, 7, 8, 20, 25); p1.individuals.y = 0.0; p1.individuals.x = runif(10); i1.evaluate(p1); ind = p1.individuals; \";\n\t\t\n\t}\n\t*/\n\t\n\t// 3D is not supported by clippedIntegral() at the moment\n}\n\n#pragma mark Continuous space tests\nvoid _RunContinuousSpaceTests(void)\n{\n\t// Since these tests are so different from others – spatiality has to be enabled, interactions have to be set up,\n\t// etc. – I decided to put them in their own test function, rather than wedging them into the class tests above.\n\t// Tests of the basic functionality of properties and methods remain in the class tests, however.\n\t\n\t// BCH 10/5/2023: I'm not sure what I intended to go here!  This function was empty until now.  But now I've added\n\t// the tests below, which test inheritance of position and pointDeviated().  Here's the full model that we test\n\t// variants of:\n\t// BCH 3/22/2025: adding \"absorbing\" when using deviatePositions(), setting fitnessScaling to 0.0.\n\t\n\t/*\n\t initialize() {\n\t\t // periodic bounds enabled/disabled\n\t\t initializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\t\t \n\t\t // sex enabled/disabled\n\t\t initializeSex();\n\t }\n\t 1 early() {\n\t\t sim.addSubpop(\"p1\", 500);\n\t\t if (sim.periodicity == \"\")\n\t\t\t p1.setSpatialBounds(c(1.5, 3.8, 1.9, 6.2));\n\t\t else\n\t\t\t p1.setSpatialBounds(c(0.0, 0.0, 1.9, 6.2));\n\t\t p1.individuals.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\t\t \n\t\t // cloning and selfing enabled/disabled\n\t\t p1.setCloningRate(0.2);\n\t\t if (!sim.sexEnabled)\n\t\t\t p1.setSelfingRate(0.2);\n\t }\n\t early() {\n\t\t defineGlobal(\"PARENT_POS\", p1.individuals.spatialPosition);\n\t }\n\t // callback present/absent\n\t modifyChild() {\n\t\t if ((child.x != parent1.x) | (child.y != parent1.y))\n\t\t\t stop(\"child does not match parent!\");\n\t\t return T;\n\t }\n\t late() {\n\t\t inds = p1.individuals;\n\t\t pos = inds.spatialPosition;\n\t\t if (any(match(pos, PARENT_POS) == -1))\n\t\t\t stop(\"child does not match parent!\");\n\t\t \n\t\t // different boundary conditions and kernels\n\t\t inds.setSpatialPosition(p1.pointDeviated(inds.size(), pos, \"reprising\", INF, \"n\", 0.1));\n\t\t if (!all(p1.pointInBounds(inds.spatialPosition)))\n\t\t\t stop(\"position out of bounds!\");\n\t }\n\t 10 late() {}\n\t */\n\t\n\t// This exercises most cases in WF models, although it does not test the code path with migration.\n\t\n\tfor (int dimcount = 1; dimcount <= 3; ++dimcount)\n\t{\n\t\tfor (int sex_enabled = 0; sex_enabled <= 1; ++sex_enabled)\n\t\t{\n\t\t\tfor (int cloning_selfing = 0; cloning_selfing <= 1; ++cloning_selfing)\n\t\t\t{\n\t\t\t\tfor (int periodic = 0; periodic <= 1; ++periodic)\n\t\t\t\t{\n\t\t\t\t\tfor (int callbacks = 0; callbacks <= 1; ++callbacks)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int boundary = 0; boundary <= 4; boundary++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int kernel = 0; kernel <= 4; kernel++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (int use_deviate_positions = 0; use_deviate_positions <= 2; ++use_deviate_positions)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif ((boundary == 3) && (!periodic))\t\t// with periodic bounds, use only periodic boundary condition\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tif ((boundary != 3) && periodic)\t\t// with non-periodic bounds, do not use periodic boundary condition\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tif ((dimcount == 3) && (kernel == 4))\t// in 3D, do not use Student's t displacement; not implemented\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tif ((boundary == 4) && (use_deviate_positions == 0))\t// with absorbing boundaries, need to be using deviatePositions()\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tstd::string model_string = \"initialize() { \";\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='x', periodicity='x'); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='x'); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xy', periodicity='xy'); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xy'); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xyz', periodicity='xyz'); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xyz'); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (sex_enabled)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"initializeSex('A'); \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"} 1 early() { sim.addSubpop('p1', 500); \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 6.2)); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.8, 6.2)); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 0.0, 1.9, 6.2)); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.5, 1.8, 1.9, 6.2)); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 0.0, 0.0, 1.9, 6.2, 11.4)); \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.5, 1.8, 0.7, 1.9, 6.2, 11.4)); \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.individuals.setSpatialPosition(p1.pointUniform(p1.individualCount)); \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (cloning_selfing)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"p1.setCloningRate(0.2); if (!sim.sexEnabled) p1.setSelfingRate(0.2); \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"} early() { defineGlobal('PARENT_POS', p1.individuals.spatialPosition); } \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (callbacks)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"modifyChild() { if (child.x != parent1.x) stop('child does not match parent!'); return T; } \");\n\t\t\t\t\t\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"modifyChild() { if ((child.x != parent1.x) | (child.y != parent1.y)) stop('child does not match parent!'); return T; } \");\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"modifyChild() { if ((child.x != parent1.x) | (child.y != parent1.y) | (child.z != parent1.z)) stop('child does not match parent!'); return T; } \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"late() { inds = p1.individuals; pos = inds.spatialPosition; \");\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"if (any(match(pos, PARENT_POS) == -1)) stop('child does not match parent!'); \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (use_deviate_positions == 0)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"inds.setSpatialPosition(p1.pointDeviated(inds.size(), pos, \");\n\t\t\t\t\t\t\t\t\telse if (use_deviate_positions == 1)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"to_kill = p1.deviatePositions(NULL, \");\n\t\t\t\t\t\t\t\t\telse if (use_deviate_positions == 2)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"to_kill = p1.deviatePositions(inds, \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tswitch (boundary)\t\t\t\t\t// NOLINT(*-missing-default-case) : loop bounds\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tcase 0: model_string.append(\"'stopping'\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 1: model_string.append(\"'reflecting'\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 2: model_string.append(\"'reprising'\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 3: model_string.append(\"'periodic'\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 4: model_string.append(\"'absorbing'\"); break;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tswitch (kernel)\t\t\t\t\t\t// NOLINT(*-missing-default-case) : loop bounds\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tcase 0: model_string.append(\", 0.1, 'f')\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 1: model_string.append(\", 0.1, 'l')\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 2: model_string.append(\", INF, 'e', 10.0)\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 3: model_string.append(\", INF, 'n', 0.1)\"); break;\n\t\t\t\t\t\t\t\t\t\tcase 4: model_string.append(\", INF, 't', 2.0, 0.1)\"); break;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (use_deviate_positions == 0)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"); \");\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"; \");\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"to_kill.fitnessScaling = 0.0; \");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// no bounds-checking for 'absorbing'; the individuals are out of bounds but will be killed\n\t\t\t\t\t\t\t\t\tif (boundary != 4)\n\t\t\t\t\t\t\t\t\t\tmodel_string.append(\"if (!all(p1.pointInBounds(inds.spatialPosition))) stop('position out of bounds!'); \");\n\t\t\t\t\t\t\t\t\tmodel_string.append(\"} 10 late() {} \");\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tSLiMAssertScriptSuccess(model_string);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// For nonWF models we have a different test model.  This is simpler since there are not so many code paths to check.\n\t// Sex doesn't matter, callbacks present/absent doesn't matter, migration doesn't matter, cloning/selfing is tested\n\t// in every variant here:\n\t\n\t/*\n\t initialize() {\n\t\t initializeSLiMModelType(\"nonWF\");\n\t\t defineConstant(\"K\", 100);\t\n\t\t \n\t\t // periodic bounds enabled/disabled\n\t\t initializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n\t\t \n\t\t // need genetics so we can use addRecombinant()\n\t\t initializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\t\t initializeGenomicElementType(\"g1\", m1, 1.0);\n\t\t initializeGenomicElement(g1, 0, 99999);\n\t\t initializeMutationRate(1e-7);\n\t\t initializeRecombinationRate(1e-8);\n\t }\n\t reproduction() {\n\t\t mate = subpop.sampleIndividuals(1);\n\t\t o1 = subpop.addCrossed(individual, mate);\n\t\t o2 = subpop.addCloned(individual);\n\t\t o3 = subpop.addSelfed(individual);\n\t\t ig = sample(individual.haplosomes, 2, F);\n\t\t mg = sample(mate.haplosomes, 2, F);\n\t\t o4 = subpop.addRecombinant(ig[0], ig[1], sim.chromosomes.drawBreakpoints(),\n\t\t\t\t\t mg[0], mg[1], sim.chromosomes.drawBreakpoints(),\n\t\t\t\t\t parent1=individual, parent2=mate);\n\t\t for (o in c(o1, o2, o3, o4))\n\t\t\t if ((o.x != individual.x) | (o.y != individual.y))\n\t\t\t\t stop(\"child does not match parent!\");\n\t }\n\t 1 early() {\n\t\t sim.addSubpop(\"p1\", K);\n\t\t if (sim.periodicity == \"\")\n\t\t\t p1.setSpatialBounds(c(1.5, 3.8, 1.9, 6.2));\n\t\t else\n\t\t\t p1.setSpatialBounds(c(0.0, 0.0, 1.9, 6.2));\n\t\t p1.individuals.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\t }\n\t early() {\n\t\t inds = p1.individuals;\n\t\t pos = inds.spatialPosition;\n\t\t \n\t\t // different boundary conditions and kernels\n\t\t inds.setSpatialPosition(p1.pointDeviated(inds.size(), pos, \"reprising\", INF, \"n\", 0.1));\n\t\t if (!all(p1.pointInBounds(inds.spatialPosition)))\n\t\t\t stop(\"position out of bounds!\");\n\t\t \n\t\t p1.fitnessScaling = K / p1.individualCount;\n\t }\n\t 10 late() {}\n\t */\n\t\n\tfor (int dimcount = 1; dimcount <= 3; ++dimcount)\n\t{\n\t\tfor (int periodic = 0; periodic <= 1; ++periodic)\n\t\t{\n\t\t\tfor (int boundary = 0; boundary <= 3; boundary++)\n\t\t\t{\n\t\t\t\tfor (int kernel = 0; kernel <= 4; kernel++)\n\t\t\t\t{\n\t\t\t\t\tif ((boundary == 3) && (!periodic))\t\t// with periodic bounds, use only periodic boundary condition\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ((boundary != 3) && periodic)\t\t// with non-periodic bounds, do not use periodic boundary condition\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif ((dimcount == 3) && (kernel == 4))\t// in 3D, do not use Student's t displacement; not implemented\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\tstd::string model_string = \"initialize() { initializeSLiMModelType('nonWF'); defineConstant('K', 100); \";\n\t\t\t\t\t\n\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='x', periodicity='x'); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='x'); \");\n\t\t\t\t\t}\n\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xy', periodicity='xy'); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xy'); \");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xyz', periodicity='xyz'); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='xyz'); \");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); initializeGenomicElement(g1, 0, 99999); initializeMutationRate(1e-7); initializeRecombinationRate(1e-8); } \");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"reproduction() { mate = subpop.sampleIndividuals(1); o1 = subpop.addCrossed(individual, mate); o2 = subpop.addCloned(individual); o3 = subpop.addSelfed(individual); \");\n\t\t\t\t\tmodel_string.append(\"ig = sample(individual.haplosomes, 2, F); mg = sample(mate.haplosomes, 2, F); o4 = subpop.addRecombinant(ig[0], ig[1], sim.chromosomes.drawBreakpoints(), mg[0], mg[1], sim.chromosomes.drawBreakpoints(), parent1=individual, parent2=mate, randomizeStrands=T); \");\n\t\t\t\t\t\n\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t\tmodel_string.append(\"for (o in c(o1, o2, o3, o4)) if (o.x != individual.x) stop('child does not match parent!'); }\");\n\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t\tmodel_string.append(\"for (o in c(o1, o2, o3, o4)) if ((o.x != individual.x) | (o.y != individual.y)) stop('child does not match parent!'); }\");\n\t\t\t\t\telse\n\t\t\t\t\t\tmodel_string.append(\"for (o in c(o1, o2, o3, o4)) if ((o.x != individual.x) | (o.y != individual.y) | (o.z != individual.z)) stop('child does not match parent!'); }\");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"1 early() { sim.addSubpop('p1', K); \");\n\t\t\t\t\t\n\t\t\t\t\tif (dimcount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 6.2)); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.8, 6.2)); \");\n\t\t\t\t\t}\n\t\t\t\t\telse if (dimcount == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 0.0, 1.9, 6.2)); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.5, 1.8, 1.9, 6.2)); \");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (periodic)\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(0.0, 0.0, 0.0, 1.9, 6.2, 11.4)); \");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tmodel_string.append(\"p1.setSpatialBounds(c(1.5, 1.8, 0.7, 1.9, 6.2, 11.4)); \");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"p1.individuals.setSpatialPosition(p1.pointUniform(p1.individualCount)); }\");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"early() { inds = p1.individuals; pos = inds.spatialPosition; inds.setSpatialPosition(p1.pointDeviated(inds.size(), pos, \");\n\t\t\t\t\t\n\t\t\t\t\tswitch (boundary)\t\t\t\t\t// NOLINT(*-missing-default-case) : loop bounds\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 0: model_string.append(\"'stopping'\"); break;\n\t\t\t\t\t\tcase 1: model_string.append(\"'reflecting'\"); break;\n\t\t\t\t\t\tcase 2: model_string.append(\"'reprising'\"); break;\n\t\t\t\t\t\tcase 3: model_string.append(\"'periodic'\"); break;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tswitch (kernel)\t\t\t\t\t\t// NOLINT(*-missing-default-case) : loop bounds\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 0: model_string.append(\", 0.1, 'f')); \"); break;\n\t\t\t\t\t\tcase 1: model_string.append(\", 0.1, 'l')); \"); break;\n\t\t\t\t\t\tcase 2: model_string.append(\", INF, 'e', 10.0)); \"); break;\n\t\t\t\t\t\tcase 3: model_string.append(\", INF, 'n', 0.1)); \"); break;\n\t\t\t\t\t\tcase 4: model_string.append(\", INF, 't', 2.0, 0.1)); \"); break;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"if (!all(p1.pointInBounds(inds.spatialPosition))) stop('position out of bounds!'); \");\n\t\t\t\t\tmodel_string.append(\"p1.fitnessScaling = K / p1.individualCount; } 10 late() {} \");\n\t\t\t\t\t\n\t\t\t\t\tSLiMAssertScriptSuccess(model_string);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Test different kernel types - other tests generally use only type \"f\"\n\t// Test different constraints - note that sex-segregation gets tested elsewhere\n\tfor (int dimcount = 1; dimcount <= 3; ++dimcount)\n\t{\n\t\tstd::string dimensionality;\n\t\t\n\t\tif (dimcount == 1)\t\tdimensionality = \"x\";\n\t\telse if (dimcount == 2)\tdimensionality = \"xy\";\n\t\telse\t\t\t\t\tdimensionality = \"xyz\";\n\t\t\n\t\tfor (int constraints = 0; constraints <= 1; ++constraints)\n\t\t{\n\t\t\tfor (int periodic = 0; periodic <= 1; ++periodic)\n\t\t\t{\n\t\t\t\tfor (int kernel = 0; kernel <= 5; kernel++)\n\t\t\t\t{\n\t\t\t\t\tstd::string model_string = \"initialize() { initializeSLiMModelType('nonWF'); defineConstant('K', 100); \";\n\t\t\t\t\t\n\t\t\t\t\tif (periodic)\n\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='\" + dimensionality + \"', periodicity='\" + dimensionality + \"'); \");\n\t\t\t\t\telse\n\t\t\t\t\t\tmodel_string.append(\"initializeSLiMOptions(dimensionality='\" + dimensionality + \"'); \");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"initializeSex('A'); \");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"initializeInteractionType(1, '\" + dimensionality + \"', maxDistance=0.2); \");\n\t\t\t\t\t\n\t\t\t\t\tswitch (kernel)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 0: model_string.append(\"i1.setInteractionFunction('f', 1.0); \"); break;\n\t\t\t\t\t\tcase 1: model_string.append(\"i1.setInteractionFunction('l', 1.0); \"); break;\n\t\t\t\t\t\tcase 2: model_string.append(\"i1.setInteractionFunction('n', 1.0, 0.1); \"); break;\n\t\t\t\t\t\tcase 3: model_string.append(\"i1.setInteractionFunction('e', 1.0, 10.0); \"); break;\n\t\t\t\t\t\tcase 4: model_string.append(\"i1.setInteractionFunction('c', 1.0, 0.1); \"); break;\n\t\t\t\t\t\tcase 5: model_string.append(\"i1.setInteractionFunction('t', 1.0, 3.0, 0.1); \"); break;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (constraints)\n\t\t\t\t\t{\n\t\t\t\t\t\tmodel_string.append(\"i1.setConstraints('receiver', sex='M', tagL2=T); \");\n\t\t\t\t\t\tmodel_string.append(\"i1.setConstraints('exerter', sex='F', tagL2=F); \");\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"} 1 early() { sim.addSubpop(1, K); inds = p1.individuals; inds.setSpatialPosition(p1.pointUniform(1)); \");\n\t\t\t\t\t\n\t\t\t\t\tif (constraints)\n\t\t\t\t\t\tmodel_string.append(\"inds.tagL2 = (runif(K) < 0.5); \");\n\t\t\t\t\t\n\t\t\t\t\tmodel_string.append(\"i1.evaluate(p1); \");\n\t\t\t\t\tmodel_string.append(\"i1.drawByStrength(inds[0], 1, p1); \");\n\t\t\t\t\tmodel_string.append(\"i1.drawByStrength(inds[0], 1000, p1); \");\n\t\t\t\t\tmodel_string.append(\"i1.drawByStrength(inds, 1, p1, returnDict=T); \");\n\t\t\t\t\tmodel_string.append(\"}\");\n\t\t\t\t\t\n\t\t\t\t\tSLiMAssertScriptSuccess(model_string, __LINE__);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Test summarizeIndividuals() in a few simple ways\n\tfor (int dimcount = 1; dimcount <= 3; ++dimcount)\n\t{\n\t\tstd::string dimensionality;\n\t\tstd::string dim_str;\n\t\t\n\t\tif (dimcount == 1)\t\t{ dimensionality = \"x\"; dim_str = \"10\"; }\n\t\telse if (dimcount == 2)\t{ dimensionality = \"xy\"; dim_str = \"10, 10\"; }\n\t\telse\t\t\t\t\t{ dimensionality = \"xyz\"; dim_str = \"5, 5, 5\"; }\n\t\t\n\t\tfor (int operation = 0; operation <= 2; operation++)\n\t\t{\n\t\t\tstd::string model_string = \"initialize() { initializeSLiMOptions(dimensionality='\" + dimensionality + \"'); defineConstant('K', 1000); } \";\n\t\t\t\n\t\t\tmodel_string.append(\"1 late() { sim.addSubpop('p1', K); p1.individuals.setSpatialPosition(p1.pointUniform(K)); \");\n\t\t\tmodel_string.append(\"density = summarizeIndividuals(p1.individuals, c(\" + dim_str + \"), p1.spatialBounds, \");\n\t\t\t\n\t\t\tif (operation == 0)\n\t\t\t\tmodel_string.append(\"operation='1;', empty=0.0, perUnitArea=F); \");\n\t\t\telse if (operation == 1)\n\t\t\t\tmodel_string.append(\"operation='individuals.size();', empty=0.0, perUnitArea=T); \");\n\t\t\telse\n\t\t\t\tmodel_string.append(\"operation='2;', empty=0.0, perUnitArea=F); \");\n\t\t\t\n\t\t\tmodel_string.append(\"}\");\n\t\t\t\n\t\t\tSLiMAssertScriptSuccess(model_string, __LINE__);\n\t\t}\n\t}\n}\n\n#pragma mark Spatial map tests\nvoid _RunSpatialMapTests(void)\n{\n\tfor (int periodic = 0; periodic <= 1; ++periodic)\n\t{\n\t\t//\n\t\t//\t1D\n\t\t//\n\t\tstd::string prefix_1D;\n\t\t\n\t\tif (periodic == 0)\n\t\t\tprefix_1D = \"initialize() { initializeSLiMOptions(dimensionality='x'); } 1 early() { sim.addSubpop('p1', 10); mv1 = runif(11); mv2 = runif(11); m1 = p1.defineSpatialMap('map1', 'x', mv1); m2 = p1.defineSpatialMap('map2', 'x', mv2); \";\n\t\telse\n\t\t\tprefix_1D = \"initialize() { initializeSLiMOptions(dimensionality='x', periodicity='x'); } 1 early() { sim.addSubpop('p1', 10); mv1 = runif(11); mv2 = runif(11); m1 = p1.defineSpatialMap('map1', 'x', mv1); m2 = p1.defineSpatialMap('map2', 'x', mv2); \";\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"f1 = m1.gridValues(); f2 = m2.gridValues(); if (identical(mv1, f1) & identical(mv2, f2)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m3 = SpatialMap('map3', m1); f3 = m3.gridValues(); if (identical(mv1, f3)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.add(17.3); if (identical(mv1 + 17.3, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.add(mv2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.add(m2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(17.3, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(mv2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(m2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(17.3, 1.0); if (identical(rep(17.3, 11), m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(mv2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(m2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(17.3, 0.4); if (all(abs((mv1*0.6 + rep(17.3, 11)*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(mv2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.blend(m2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.multiply(0.25); if (identical(mv1 * 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.multiply(mv2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.multiply(m2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.subtract(0.25); if (identical(mv1 - 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.subtract(mv2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.subtract(m2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.divide(0.25); if (identical(mv1 / 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.divide(mv2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.divide(m2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.power(0.25); if (allClose(mv1 ^ 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.power(mv2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.power(m2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.exp(); if (allClose(exp(mv1), m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); m1.changeColors(c(0.5, 0.8), c('red', 'blue')); } \");\n\t\t\n\t\tSLiMAssertScriptRaise(prefix_1D + \"m1.changeValues(17.3); }\", \"must be of size >= 2\", __LINE__);\n\t\tSLiMAssertScriptStop(prefix_1D + \"mx = rep(17.3, 10); m1.changeValues(mx); if (identical(mx, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.changeValues(mv2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.changeValues(m2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.interpolate(3, 'nearest'); if (identical(m1.gridDimensions, 31)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.interpolate(3, 'linear'); if (identical(m1.gridDimensions, 31)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.interpolate(3, 'cubic'); if (identical(m1.gridDimensions, 31)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapColor(rnorm(50)); } \");\n\t\t\n\t\t/* mapImage() only generates 2D images\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.mapImage(centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.mapImage(centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=F, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=T, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.mapImage(10, 15, centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.mapImage(10, 15, centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=F, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=T, color=T); } \");\n\t\t \n\t\t SLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapImage('map1', centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapImage('map1', centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapImage('map1', 10, 15, centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapImage('map1', 10, 15, centers=T, color=F); } \");*/\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.mapValue(runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.mapValue(runif(1)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.mapValue(runif(10)); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapValue('map1', runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapValue('map1', runif(1)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"p1.spatialMapValue('map1', runif(10)); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"if (identical(range(mv1), m1.range()) & identical(range(mv2), m2.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.rescale(); if (identical(c(0.0, 1.0), m1.range())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_1D + \"m1.rescale(0.2, 1.7); if (identical(c(0.2, 1.7), m1.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleImprovedNearbyPoint(runif(10), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleImprovedNearbyPoint(runif(10), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleImprovedNearbyPoint(runif(10), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleImprovedNearbyPoint(runif(10), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleImprovedNearbyPoint(runif(10), 0.2, 't', 2, 0.1); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleNearbyPoint(runif(10), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleNearbyPoint(runif(10), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleNearbyPoint(runif(10), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleNearbyPoint(runif(10), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.sampleNearbyPoint(runif(10), 0.2, 't', 2, 0.1); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.1, 't', 2, 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 't', 2, 0.1); } \");\n\n\t\t// large kernel to test periodic boundary wrapping\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"m1.smooth(0.5, 'n', 0.2); } \");\n\n\t\tSLiMAssertScriptSuccess(prefix_1D + \"defineConstant('M1', m1); defineGlobal('M2', m2); } 2 early() { sim.addSubpop('p2', 10); p2.addSpatialMap(M1); p2.addSpatialMap(M2); } 3 early() { p1.removeSpatialMap('map1'); p2.removeSpatialMap(M2); } 4 early() { if (!identical(p1.spatialMaps, M2)) stop(); if (!identical(p2.spatialMaps, M1)) stop(); p2.removeSpatialMap('map1'); p1.removeSpatialMap(M2); }\");\n\n\t\t//\n\t\t//\t2D\n\t\t//\n\t\tstd::string prefix_2D;\n\t\t\n\t\tif (periodic == 0)\n\t\t\tprefix_2D = \"initialize() { initializeSLiMOptions(dimensionality='xy'); } 1 early() { sim.addSubpop('p1', 10); mv1 = matrix(runif(30), ncol=5); mv2 = matrix(runif(30), ncol=5); m1 = p1.defineSpatialMap('map1', 'xy', mv1); m2 = p1.defineSpatialMap('map2', 'xy', mv2); \";\n\t\telse\n\t\t\tprefix_2D = \"initialize() { initializeSLiMOptions(dimensionality='xy', periodicity='xy'); } 1 early() { sim.addSubpop('p1', 10); mv1 = matrix(runif(30), ncol=5); mv2 = matrix(runif(30), ncol=5); m1 = p1.defineSpatialMap('map1', 'xy', mv1); m2 = p1.defineSpatialMap('map2', 'xy', mv2); \";\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"f1 = m1.gridValues(); f2 = m2.gridValues(); if (identical(mv1, f1) & identical(mv2, f2)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m3 = SpatialMap('map3', m1); f3 = m3.gridValues(); if (identical(mv1, f3)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.add(17.3); if (identical(mv1 + 17.3, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.add(mv2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.add(m2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(17.3, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(mv2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(m2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(17.3, 1.0); if (identical(matrix(rep(17.3, 30), ncol=5), m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(mv2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(m2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(17.3, 0.4); if (all(abs((mv1*0.6 + matrix(rep(17.3, 30), ncol=5)*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(mv2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.blend(m2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.multiply(0.25); if (identical(mv1 * 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.multiply(mv2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.multiply(m2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.subtract(0.25); if (identical(mv1 - 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.subtract(mv2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.subtract(m2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.divide(0.25); if (identical(mv1 / 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.divide(mv2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.divide(m2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.power(0.25); if (allClose(mv1 ^ 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.power(mv2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.power(m2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.exp(); if (allClose(exp(mv1), m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); m1.changeColors(c(0.5, 0.8), c('red', 'blue')); } \");\n\t\t\n\t\tSLiMAssertScriptRaise(prefix_2D + \"m1.changeValues(17.3); }\", \"does not match the spatiality\", __LINE__);\n\t\tSLiMAssertScriptStop(prefix_2D + \"mx = matrix(rep(17.3, 30), ncol=5); m1.changeValues(mx); if (identical(mx, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.changeValues(mv2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.changeValues(m2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.interpolate(3, 'nearest'); if (identical(m1.gridDimensions, c(13, 16))) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.interpolate(3, 'linear'); if (identical(m1.gridDimensions, c(13, 16))) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.interpolate(3, 'cubic'); if (identical(m1.gridDimensions, c(13, 16))) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapColor(rnorm(50)); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapImage(centers=F, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapImage(centers=T, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=F, color=T); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=T, color=T); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapImage(10, 15, centers=F, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapImage(10, 15, centers=T, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=F, color=T); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=T, color=T); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapImage('map1', centers=F, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapImage('map1', centers=T, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapImage('map1', 10, 15, centers=F, color=F); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapImage('map1', 10, 15, centers=T, color=F); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapValue(runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapValue(runif(2)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.mapValue(runif(20)); } \");\n\t\tSLiMAssertScriptRaise(prefix_2D + \"m1.mapValue(runif(21)); } \", \"must match spatiality\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapValue('map1', runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapValue('map1', runif(2)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"p1.spatialMapValue('map1', runif(20)); } \");\n\t\tSLiMAssertScriptRaise(prefix_2D + \"p1.spatialMapValue('map1', runif(21)); } \", \"must match spatiality\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"if (identical(range(mv1), m1.range()) & identical(range(mv2), m2.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.rescale(); if (identical(c(0.0, 1.0), m1.range())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_2D + \"m1.rescale(0.2, 1.7); if (identical(c(0.2, 1.7), m1.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleImprovedNearbyPoint(runif(20), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleImprovedNearbyPoint(runif(20), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleImprovedNearbyPoint(runif(20), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleImprovedNearbyPoint(runif(20), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleImprovedNearbyPoint(runif(20), 0.2, 't', 2, 0.1); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleNearbyPoint(runif(20), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleNearbyPoint(runif(20), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleNearbyPoint(runif(20), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleNearbyPoint(runif(20), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.sampleNearbyPoint(runif(20), 0.2, 't', 2, 0.1); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.1, 't', 2, 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.interpolate(3, 'cubic'); m1.smooth(0.1, 't', 2, 0.1); } \");\n\n\t\t// large kernel to test periodic boundary wrapping\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"m1.smooth(0.5, 'n', 0.2); } \");\n\n\t\tSLiMAssertScriptSuccess(prefix_2D + \"defineConstant('M1', m1); defineGlobal('M2', m2); } 2 early() { sim.addSubpop('p2', 10); p2.addSpatialMap(M1); p2.addSpatialMap(M2); } 3 early() { p1.removeSpatialMap('map1'); p2.removeSpatialMap(M2); } 4 early() { if (!identical(p1.spatialMaps, M2)) stop(); if (!identical(p2.spatialMaps, M1)) stop(); p2.removeSpatialMap('map1'); p1.removeSpatialMap(M2); }\");\n\n\t\t//\n\t\t//\t3D\n\t\t//\n\t\tstd::string prefix_3D;\n\t\t\n\t\tif (periodic == 0)\n\t\t\tprefix_3D = \"initialize() { initializeSLiMOptions(dimensionality='xyz'); } 1 early() { sim.addSubpop('p1', 10); mv1 = array(runif(120), dim=c(6, 5, 4)); mv2 = array(runif(120), dim=c(6, 5, 4)); m1 = p1.defineSpatialMap('map1', 'xyz', mv1); m2 = p1.defineSpatialMap('map2', 'xyz', mv2); \";\n\t\telse\n\t\t\tprefix_3D = \"initialize() { initializeSLiMOptions(dimensionality='xyz', periodicity='xyz'); } 1 early() { sim.addSubpop('p1', 10); mv1 = array(runif(120), dim=c(6, 5, 4)); mv2 = array(runif(120), dim=c(6, 5, 4)); m1 = p1.defineSpatialMap('map1', 'xyz', mv1); m2 = p1.defineSpatialMap('map2', 'xyz', mv2); \";\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"f1 = m1.gridValues(); f2 = m2.gridValues(); if (identical(mv1, f1) & identical(mv2, f2)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m3 = SpatialMap('map3', m1); f3 = m3.gridValues(); if (identical(mv1, f3)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.add(17.3); if (identical(mv1 + 17.3, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.add(mv2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.add(m2); if (identical(mv1 + mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(17.3, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(mv2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(m2, 0.0); if (identical(mv1, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(17.3, 1.0); if (identical(array(rep(17.3, 120), dim=c(6, 5, 4)), m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(mv2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(m2, 1.0); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(17.3, 0.4); if (all(abs((mv1*0.6 + array(rep(17.3, 120), dim=c(6, 5, 4))*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(mv2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.blend(m2, 0.4); if (all(abs((mv1*0.6 + mv2*0.4) - m1.gridValues()) < 1e-15)) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.multiply(0.25); if (identical(mv1 * 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.multiply(mv2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.multiply(m2); if (identical(mv1 * mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.subtract(0.25); if (identical(mv1 - 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.subtract(mv2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.subtract(m2); if (identical(mv1 - mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.divide(0.25); if (identical(mv1 / 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.divide(mv2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.divide(m2); if (identical(mv1 / mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.power(0.25); if (allClose(mv1 ^ 0.25, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.power(mv2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.power(m2); if (allClose(mv1 ^ mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.exp(); if (allClose(exp(mv1), m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('black', 'white')); m1.changeColors(c(0.5, 0.8), c('red', 'blue')); } \");\n\t\t\n\t\tSLiMAssertScriptRaise(prefix_3D + \"m1.changeValues(17.3); }\", \"does not match the spatiality\", __LINE__);\n\t\tSLiMAssertScriptStop(prefix_3D + \"mx = array(rep(17.3, 120), dim=c(6, 5, 4)); m1.changeValues(mx); if (identical(mx, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.changeValues(mv2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.changeValues(m2); if (identical(mv2, m1.gridValues())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.interpolate(3, 'nearest'); if (identical(m1.gridDimensions, c(13, 16, 10))) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.interpolate(3, 'linear'); if (identical(m1.gridDimensions, c(13, 16, 10))) stop(); } \");\n\t\tSLiMAssertScriptRaise(prefix_3D + \"m1.interpolate(3, 'cubic'); if (identical(m1.gridDimensions, c(13, 16, 10))) stop(); } \", \"not currently supported for 3D\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapColor(rnorm(50)); } \");\n\t\t\n\t\t/* mapImage() only generates 2D images\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.mapImage(centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.mapImage(centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=F, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(centers=T, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.mapImage(10, 15, centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.mapImage(10, 15, centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=F, color=T); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"m1.changeColors(c(0.0, 1.0), c('red', 'black')); m1.mapImage(10, 15, centers=T, color=T); } \");\n\t\t \n\t\t SLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapImage('map1', centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapImage('map1', centers=T, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapImage('map1', 10, 15, centers=F, color=F); } \");\n\t\t SLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapImage('map1', 10, 15, centers=T, color=F); } \");*/\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.mapValue(runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.mapValue(runif(3)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.mapValue(runif(30)); } \");\n\t\tSLiMAssertScriptRaise(prefix_3D + \"m1.mapValue(runif(31)); } \", \"must match spatiality\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapValue('map1', runif(0)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapValue('map1', runif(3)); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"p1.spatialMapValue('map1', runif(30)); } \");\n\t\tSLiMAssertScriptRaise(prefix_3D + \"p1.spatialMapValue('map1', runif(31)); } \", \"must match spatiality\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"if (identical(range(mv1), m1.range()) & identical(range(mv2), m2.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.rescale(); if (identical(c(0.0, 1.0), m1.range())) stop(); } \");\n\t\tSLiMAssertScriptStop(prefix_3D + \"m1.rescale(0.2, 1.7); if (identical(c(0.2, 1.7), m1.range())) stop(); } \");\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleImprovedNearbyPoint(runif(30), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleImprovedNearbyPoint(runif(30), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleImprovedNearbyPoint(runif(30), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleImprovedNearbyPoint(runif(30), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptRaise(prefix_3D + \"m1.sampleImprovedNearbyPoint(runif(30), 0.2, 't', 3, 0.1); } \", \"kernel type not supported\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleNearbyPoint(runif(30), 0.2, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleNearbyPoint(runif(30), 0.2, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleNearbyPoint(runif(30), 0.2, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.sampleNearbyPoint(runif(30), 0.2, 'n', 0.1); } \");\n\t\tSLiMAssertScriptRaise(prefix_3D + \"m1.sampleNearbyPoint(runif(30), 0.2, 't', 3, 0.1); } \", \"kernel type not supported\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 'f'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.1, 't', 3, 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 'f'); } \");\t// linear not cubic, for 3D\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 'l'); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 'e', 10.0); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 'n', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 'c', 0.1); } \");\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.interpolate(3, 'linear'); m1.smooth(0.1, 't', 3, 0.1); } \");\n\n\t\t// large kernel to test periodic boundary wrapping\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"m1.smooth(0.5, 'n', 0.2); } \");\n\n\t\tSLiMAssertScriptSuccess(prefix_3D + \"defineConstant('M1', m1); defineGlobal('M2', m2); } 2 early() { sim.addSubpop('p2', 10); p2.addSpatialMap(M1); p2.addSpatialMap(M2); } 3 early() { p1.removeSpatialMap('map1'); p2.removeSpatialMap(M2); } 4 early() { if (!identical(p1.spatialMaps, M2)) stop(); if (!identical(p2.spatialMaps, M1)) stop(); p2.removeSpatialMap('map1'); p1.removeSpatialMap(M2); }\");\n\t}\n}\n\n#pragma mark nonWF model tests\nvoid _RunNonWFTests(void)\n{\n\t// Test properties and methods that should be disabled in nonWF mode\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.setSubpopulationSize(500); } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.cloningRate; } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.setCloningRate(0.5); } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.selfingRate; } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.setSelfingRate(0.5); } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_sex_p1 + \"1 early() { p1.sexRatio; } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_sex_p1 + \"1 early() { p1.setSexRatio(0.5); } \", \"not available in nonWF models\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { sim.addSubpopSplit(2, 100, p1); } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.immigrantSubpopFractions; } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.immigrantSubpopIDs; } \", \"not available in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.setMigrationRates(2, 0.1); } \", \"not available in nonWF models\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 mateChoice() { return T; } \", \"may not be defined in nonWF models\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { sim.registerMateChoiceCallback(NULL, '{ return T; } '); } \", \"not available in nonWF models\", __LINE__);\n\t\n\t// Test properties and methods that should be disabled in WF mode\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.individuals.age; } \", \"not available in WF models\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.removeSubpopulation(); stop(); }\", \"not available in WF models\", __LINE__);\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.takeMigrants(p1.individuals); stop(); }\", \"not available in WF models\", __LINE__);\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.addCloned(p1.individuals[0]); stop(); }\", \"not available in WF models\", __LINE__);\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.addCrossed(p1.individuals[0], p1.individuals[1]); stop(); }\", \"not available in WF models\", __LINE__);\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.addEmpty(); stop(); }\", \"not available in WF models\", __LINE__);\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 early() { p1.addSelfed(p1.individuals[0]); stop(); }\", \"not available in WF models\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(WF_prefix + gen1_setup_p1 + \"1 reproduction() { return; } \", \"may not be defined in WF models\", __LINE__);\n\t\n\t// Community.modelType\n\tSLiMAssertScriptStop(gen1_setup + \"1 early() { if (community.modelType == 'WF') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup + \"1 early() { if (community.modelType == 'nonWF') stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_sex + \"1 early() { if (community.modelType == 'nonWF') stop(); } \", __LINE__);\n\t\n\t// Individual.age\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.individuals.age; stop(); } \", __LINE__);\n\t\n\t// Individual.meanParentAge\n\tSLiMAssertScriptStop(nonWF_prefix + pedigrees_prefix + gen1_setup_p1 + \"1 early() { p1.individuals.meanParentAge; stop(); } \", __LINE__);\n\t\n\t// Subpopulation - (void)takeMigrants() and sampleIndividuals()\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 first() { s = c(p2,p3).sampleIndividuals(1); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 early() { s = c(p2,p3).sampleIndividuals(1); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 late() { s = c(p2,p3).sampleIndividuals(1); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 first() { s = c(p2,p3).sampleIndividuals(1, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 early() { s = c(p2,p3).sampleIndividuals(1, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 late() { s = c(p2,p3).sampleIndividuals(1, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 first() { s = c(p2,p3).sampleIndividuals(40); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 early() { s = c(p2,p3).sampleIndividuals(40); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 late() { s = c(p2,p3).sampleIndividuals(40); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 first() { s = c(p2,p3).sampleIndividuals(40, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 early() { s = c(p2,p3).sampleIndividuals(40, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1p2p3_100 + \"2:10 late() { s = c(p2,p3).sampleIndividuals(40, migrant=F); p1.takeMigrants(s); stop(); } \", __LINE__);\n\t\n\t// Subpopulation - (void)removeSubpopulation()\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.removeSubpopulation(); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.removeSubpopulation(); if (p1.individualCount == 10) stop(); }\", \"undefined identifier\", __LINE__);\t\t// the symbol is undefined immediately\n\tSLiMAssertScriptStop(nonWF_prefix + gen1_setup_p1 + \"1 early() { px=p1; p1.removeSubpopulation(); if (px.individualCount == 10) stop(); }\", __LINE__);\t\t\t\t\t\t\t\t\t// does not take visible effect until generating children\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"1 early() { p1.removeSubpopulation(); } 2 early() { if (p1.individualCount == 0) stop(); }\", \"undefined identifier\", __LINE__);\n\t\n\t// Test that deferred generation of offspring haplosomes does not cause vulnerabilities in properties/methods\n#if DEFER_BROKEN\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.uniqueMutations; }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_highmut_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.containsMutations(sim.mutations); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.countOfMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.sumOfMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.uniqueMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.mutations; }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_highmut_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.addMutations(sim.mutations); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.addNewDrawnMutation(m1, 10); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.addNewMutation(m1, 0.0, 10); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.containsMarkerMutation(m1, 10); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_highmut_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.containsMutations(sim.mutations); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.countOfMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.mutationCountsInHaplosomes(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.mutationFrequenciesInHaplosomes(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.mutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.nucleotides(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.outputHaplosomes(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.outputHaplosomesToMS(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.outputHaplosomesToVCF(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.positionsOfMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.readHaplosomesFromMS('foo', m1); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.readHaplosomesFromVCF('foo'); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.removeMutations(); }\", \"deferred haplosomes\", __LINE__);\n\tSLiMAssertScriptRaise(nonWF_prefix + gen1_setup_p1 + \"2 reproduction() { offspring = p1.addCloned(individual, defer=T); offspring.haplosomes.sumOfMutationsOfType(m1); }\", \"deferred haplosomes\", __LINE__);\n#endif\n}\n\n#pragma mark treeseq tests\nvoid _RunTreeSeqTests(const std::string &temp_path)\n{\n\t// initializeTreeSeq()\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=10.0, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=10.0, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=INF, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=INF, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=0.0, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=0.0, checkCoalescence=F, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=10.0, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=10.0, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=INF, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=INF, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=0.0, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=0.0, checkCoalescence=T, runCrosschecks=F); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=10.0, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=10.0, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=INF, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=INF, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=0.0, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=0.0, checkCoalescence=F, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=10.0, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=10.0, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=INF, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=INF, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=F, simplificationRatio=0.0, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(recordMutations=T, simplificationRatio=0.0, checkCoalescence=T, runCrosschecks=T); } \" + gen1_setup_p1 + \"100 early() { stop(); }\", __LINE__);\n\t\n\t// treeSeqCoalesced()\n\tSLiMAssertScriptRaise(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"1: early() { sim.treeSeqCoalesced(); } 100 early() { stop(); }\", \"coalescence checking is enabled\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(checkCoalescence=T); } \" + gen1_setup_p1 + \"1: early() { sim.treeSeqCoalesced(); } 100 early() { stop(); }\", __LINE__);\n\t\n\t// treeSeqSimplify()\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"50 early() { sim.treeSeqSimplify(); } 100 early() { stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"1: early() { sim.treeSeqSimplify(); } 100 early() { stop(); }\", __LINE__);\n\t\n\t// treeSeqRememberIndividuals()\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"50 early() { sim.treeSeqRememberIndividuals(p1.individuals[integer(0)]); } 100 early() { sim.treeSeqSimplify(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"50 early() { sim.treeSeqRememberIndividuals(p1.individuals); } 100 early() { sim.treeSeqSimplify(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"1: early() { sim.treeSeqRememberIndividuals(p1.individuals); } 100 early() { sim.treeSeqSimplify(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"50 early() { sim.treeSeqRememberIndividuals(p1.individuals, permanent=F); } 100 early() { sim.treeSeqSimplify(); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"1: early() { sim.treeSeqRememberIndividuals(p1.individuals, permanent=F); } 100 early() { sim.treeSeqSimplify(); stop(); }\", __LINE__);\n\t\n\t// treeSeqOutput()\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"100 early() { sim.treeSeqOutput('\" + temp_path + \"/SLiM_treeSeq_1.trees', simplify=F); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"100 early() { sim.treeSeqOutput('\" + temp_path + \"/SLiM_treeSeq_2.trees', simplify=T); stop(); }\", __LINE__);\n\t\t\n\t\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"100 early() { sim.treeSeqOutput('\" + temp_path + \"/SLiM_treeSeq_1.trees', simplify=F, includeModel=F); stop(); }\", __LINE__);\n\t\tSLiMAssertScriptStop(\"initialize() { initializeTreeSeq(); } \" + gen1_setup_p1 + \"100 early() { sim.treeSeqOutput('\" + temp_path + \"/SLiM_treeSeq_2.trees', simplify=T, includeModel=F); stop(); }\", __LINE__);\n\t}\n\t\n\t// test that RNG seeds are working as expected; the next test relies upon this\n\tSLiMAssertScriptSuccess(R\"V0G0N(\ninitialize() {\n\tdefineConstant('SEED', getSeed());\n\tx = runif(10); y = sample(1:1000, 5); z = rbeta(10, 0.5, 1.75);\n\t\n\tsetSeed(SEED+1);\n\ta1 = runif(10);\n\ta2 = sample(1:1000, 5);\n\ta3 = rbeta(10, 0.5, 1.75);\n\t\n\tsetSeed(SEED+1);\n\tb1 = runif(10);\n\tb2 = sample(1:1000, 5);\n\tb3 = rbeta(10, 0.5, 1.75);\n\t\n\tif (!identical(a1, b1))\n\t\tstop('64-bit generator is out of sync');\n\tif (!identical(a2, b2))\n\t\tstop('32-bit generator is out of sync');\n\tif (!identical(a3, b3))\n\t\tstop('gsl generator is out of sync');\n}\n1 early()\n{\n}\n)V0G0N\");\n\t\n\t// test remembering, saving, and loading with each chromosome type\n\t// this relies on being able to write to the temporary directory on the machine\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tstd::vector<std::string> chr_types = {\"A\", \"H\", \"X\", \"Y\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"H-\", \"-Y\"};\n\t\t\n\t\tfor (const std::string &chr_type : chr_types)\n\t\t{\n\t\t\tstd::string test_script = R\"V0G0N(\ninitialize() {\n\tdefineConstant(\"CHR_TYPE\", \"*****\");\n\tdefineConstant(\"SEED\", getSeed());\n\tdefineConstant(\"PATH\", tempdir() + \"slim_trees_test.trees\");\n\tinitializeTreeSeq(runCrosschecks=T);\n\tinitializeSex();\n\t\n\tinitializeChromosome(1, 10000, CHR_TYPE);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeGenomicElement(g1, 0, 9999);\n\tinitializeMutationRate(2e-5);\n\tinitializeRecombinationRate(2e-5);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 20);\n\t;;;;;\n\tsim.setValue(\"iter\", 0);\n}\n2: early() {\n\tind = sample(sim.subpopulations.individuals, 1);\n\tsim.treeSeqRememberIndividuals(ind);\n}\n100 late() {\n\tsim.treeSeqOutput(PATH);\n\tsetSeed(SEED + 1);\n}\n200 late() {\n\ts = sum(sim.mutationCounts(NULL) + sim.substitutions.size());\n\tif (sim.getValue(\"iter\") == 0)\n\t{\n\t\tsim.setValue(\"s\", s);\n\t\tsim.setValue(\"iter\", 1);\n\t\tsim.readFromPopulationFile(PATH);\n\t\tsetSeed(SEED + 1);\n\t}\n\telse\n\t{\n\t\tif (s != sim.getValue(\"s\"))\n\t\t\tstop(\"s value mismatch for chromosome type \" + CHR_TYPE + \"(\" + s + \" versus \" + sim.getValue(\"s\") + \"), SEED == \" + SEED + \".\");\n\t\telse\n\t\t\tcatn(\"s value match (\" + s + \") for chromosome type \" + CHR_TYPE);\n\t}\n}\n)V0G0N\";\n\t\t\t\n\t\t\t// put the chromosome type into the script\n\t\t\ttest_script.replace(test_script.find(\"*****\"), 5, chr_type);\n\t\t\t\n\t\t\t// \"H-\" requires cloning only, for now at least...\n\t\t\tif (chr_type == \"H-\")\n\t\t\t\ttest_script.replace(test_script.find(\";;;;;\"), 5, \"p1.setCloningRate(1.0);\");\n\t\t\t\n\t\t\tSLiMAssertScriptSuccess(test_script);\n\t\t}\n\t}\n}\n\n#pragma mark Nucleotide API tests\nvoid _RunNucleotideFunctionTests(void)\n{\n\t// nucleotidesToCodons()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotidesToCodons(string(0)), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotidesToCodons(integer(0)), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons('A'); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(0); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons('AA'); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c(0,0)); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('AAA') == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('A','A','A')) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,0,0)) == 0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('AAC') == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('A','A','C')) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,0,1)) == 1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('AAG') == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('A','A','G')) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,0,2)) == 2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('AAT') == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('A','A','T')) == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,0,3)) == 3) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('ACA') == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('A','C','A')) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,1,0)) == 4) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('CAA') == 16) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('C','A','A')) == 16) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(1,0,0)) == 16) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('TTT') == 63) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c('T','T','T')) == 63) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(3,3,3)) == 63) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons('AAAA') == 0) stop(); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { if (nucleotidesToCodons(c(0,0,0,0)) == 0) stop(); }\", \"multiple of three in length\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotidesToCodons('AAAAACAAGAATTTT'), c(0,1,2,3,63))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotidesToCodons(c('A','A','A','A','A','C','A','A','G','A','A','T','T','T','T')), c(0,1,2,3,63))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotidesToCodons(c(0,0,0,0,0,1,0,0,2,0,0,3,3,3,3)), c(0,1,2,3,63))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons('ADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c('A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c(0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c(0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons('AAAADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c('A','A','A','A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c(0,0,0,0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotidesToCodons(c(0,0,0,0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\t\n\t// codonsToAminoAcids()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=F, paste=T), '')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=T, paste=T), '')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=0, paste=T), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=F, paste=F), string(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=T, paste=F), string(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(integer(0), long=0, paste=F), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=F, paste=T), 'K')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=T, paste=T), 'Lys')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=0, paste=T), 12)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=F, paste=F), 'K')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=T, paste=F), 'Lys')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(0, long=0, paste=F), 12)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=F, paste=T), 'KNF')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=T, paste=T), 'Lys-Asn-Phe')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=0, paste=T), c(12, 3, 14))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=F, paste=F), c('K','N','F'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=T, paste=F), c('Lys', 'Asn', 'Phe'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToAminoAcids(c(0,1,63), long=0, paste=F), c(12, 3, 14))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=F, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=T, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=0, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=F, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=T, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(-1, long=0, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=F, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=T, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=0, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=F, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=T, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(64, long=0, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=F, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=T, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=0, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=F, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=T, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,-1), long=0, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=F, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=T, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=0, paste=T); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=F, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=T, paste=F); }\", \"requires codons to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToAminoAcids(c(0,64), long=0, paste=F); }\", \"requires codons to be\", __LINE__);\n\t\n\t// mm16To256()\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mm16To256(rep(0.0,15)); }\", \"to be of length 16\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mm16To256(rep(0.0,16)); }\", \"to be a 4x4 matrix\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mm16To256(matrix(rep(0.0,16), ncol=4)), matrix(rep(0.0,256),ncol=4))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mm16To256(matrix(rep(0.25,16), ncol=4)), matrix(rep(0.25,256),ncol=4))) stop(); }\", __LINE__);\n\t\n\t// mmJukesCantor()\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmJukesCantor(-0.1); }\", \"requires alpha >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmJukesCantor(0.35); }\", \"requires 3 * alpha <= 1.0\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mmJukesCantor(0.0), matrix(rep(0.0,16),ncol=4))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mmJukesCantor(0.25), matrix(c(0.0, 0.25, 0.25, 0.25, 0.25, 0.0, 0.25, 0.25, 0.25, 0.25, 0.0, 0.25, 0.25, 0.25, 0.25, 0.0),ncol=4))) stop(); }\", __LINE__);\n\t\n\t// mmKimura()\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmKimura(-0.1, 0.5); }\", \"requires alpha to be in\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmKimura(1.1, 0.5); }\", \"requires alpha to be in\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmKimura(0.5, -0.1); }\", \"requires beta to be in\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { mmKimura(0.5, 1.1); }\", \"requires beta to be in\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mmKimura(0.0, 0.0), matrix(rep(0.0,16),ncol=4))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(mmKimura(0.5, 0.25), matrix(c(0.0, 0.25, 0.5, 0.25, 0.25, 0.0, 0.25, 0.5, 0.5, 0.25, 0.0, 0.25, 0.25, 0.5, 0.25, 0.0),ncol=4))) stop(); }\", __LINE__);\n\t\n\t// nucleotideCounts()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(string(0)), c(0,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(integer(0)), c(0,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('A'), c(1,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('C'), c(0,1,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('G'), c(0,0,1,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('T'), c(0,0,0,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(0), c(1,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(1), c(0,1,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(2), c(0,0,1,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(3), c(0,0,0,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('ACGT'), c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(c('A','C','G','T')), c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(c(0,1,2,3)), c(1,1,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts('AACACGATCG'), c(4,3,2,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(c('A','A','C','A','C','G','A','T','C','G')), c(4,3,2,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideCounts(c(0,0,1,0,1,2,0,3,1,2)), c(4,3,2,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts('ADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c('A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c(0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c(0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts('AAAADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c('A','A','A','A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c(0,0,0,0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideCounts(c(0,0,0,0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\t\n\t// nucleotideFrequencies()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (all(isNAN(nucleotideFrequencies(string(0))))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (all(isNAN(nucleotideFrequencies(integer(0))))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('A'), c(1.0,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('C'), c(0,1.0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('G'), c(0,0,1.0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('T'), c(0,0,0,1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(0), c(1.0,0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(1), c(0,1.0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(2), c(0,0,1.0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(3), c(0,0,0,1.0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('ACGT'), c(0.25,0.25,0.25,0.25))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(c('A','C','G','T')), c(0.25,0.25,0.25,0.25))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(c(0,1,2,3)), c(0.25,0.25,0.25,0.25))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies('AACACGATCG'), c(0.4,0.3,0.2,0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(c('A','A','C','A','C','G','A','T','C','G')), c(0.4,0.3,0.2,0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(nucleotideFrequencies(c(0,0,1,0,1,2,0,3,1,2)), c(0.4,0.3,0.2,0.1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies('ADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c('A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c(0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c(0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies('AAAADA'); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c('A','A','A','A','D','A')); }\", \"requires string sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c(0,0,0,0,-1,0)); }\", \"requires integer sequence values\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { nucleotideFrequencies(c(0,0,0,0,4,0)); }\", \"requires integer sequence values\", __LINE__);\n\t\n\t// randomNucleotides()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(randomNucleotides(0, format='string'), string(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(randomNucleotides(0, format='char'), string(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(randomNucleotides(0, format='integer'), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, format='string'), 'A')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(1); if (identical(randomNucleotides(1, format='char'), 'C')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(2); if (identical(randomNucleotides(1, format='integer'), 1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(3); if (identical(randomNucleotides(10, format='string'), 'CAGGGTAGGA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(4); if (identical(randomNucleotides(10, format='char'), c('A','T','G','G','G','T','C','A','A','C'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(5); if (identical(randomNucleotides(10, format='integer'), c(0,3,0,1,0,0,3,2,0,2))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(1.0,0,0,0), format='string'), 'A')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(1.0,0,0,0), format='char'), 'A')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(1.0,0,0,0), format='integer'), 0)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,1.0,0,0), format='string'), 'C')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,1.0,0,0), format='char'), 'C')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,1.0,0,0), format='integer'), 1)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,1.0,0), format='string'), 'G')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,1.0,0), format='char'), 'G')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,1.0,0), format='integer'), 2)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,0,1.0), format='string'), 'T')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,0,1.0), format='char'), 'T')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(1, basis=c(0,0,0,1.0), format='integer'), 3)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(1.0,0,0,0), format='string'), 'AAAAAAAAAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(1.0,0,0,0), format='char'), rep('A',10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(1.0,0,0,0), format='integer'), rep(0,10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,1.0,0,0), format='string'), 'CCCCCCCCCC')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,1.0,0,0), format='char'), rep('C',10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,1.0,0,0), format='integer'), rep(1,10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,1.0,0), format='string'), 'GGGGGGGGGG')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,1.0,0), format='char'), rep('G',10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,1.0,0), format='integer'), rep(2,10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,0,1.0), format='string'), 'TTTTTTTTTT')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,0,1.0), format='char'), rep('T',10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(10, basis=c(0,0,0,1.0), format='integer'), rep(3,10))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(100, basis=c(10.0,1.0,2.0,3.0), format='string'), 'AAAAAAGAGAAAAAAGACAAAAAAACAAAAAAGAACAAAAATATAAAAGGTAAATCAAAAAAAATGAGAATAACGGAAAAAGATATAAAAAAAAAAATAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(100, basis=c(10.0,1.0,2.0,3.0), format='char'), c('A','A','A','A','A','A','G','A','G','A','A','A','A','A','A','G','A','C','A','A','A','A','A','A','A','C','A','A','A','A','A','A','G','A','A','C','A','A','A','A','A','T','A','T','A','A','A','A','G','G','T','A','A','A','T','C','A','A','A','A','A','A','A','A','T','G','A','G','A','A','T','A','A','C','G','G','A','A','A','A','A','G','A','T','A','T','A','A','A','A','A','A','A','A','A','A','A','T','A','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { setSeed(0); if (identical(randomNucleotides(100, basis=c(10.0,1.0,2.0,3.0), format='integer'), c(0,0,0,0,0,0,2,0,2,0,0,0,0,0,0,2,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,3,0,3,0,0,0,0,2,2,3,0,0,0,3,1,0,0,0,0,0,0,0,0,3,2,0,2,0,0,3,0,0,1,2,2,0,0,0,0,0,2,0,3,0,3,0,0,0,0,0,0,0,0,0,0,0,3,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(-1); }\", \"requires length to be in [0, 2e9]\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=3.0); }\", \"requires basis to be either\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=c(0.0,0.0,0.0,0.0)); }\", \"requires at least one basis value to be > 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=c(0.0,0.0,0.2,-0.1)); }\", \"requires basis values to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=c(0.0,0.0,0.2,INF)); }\", \"requires basis values to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=c(0.0,0.0,0.2,NAN)); }\", \"requires basis values to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { randomNucleotides(0, basis=c(0.0,0.0,0.2,0.0), format='foo'); }\", \"requires a format of\", __LINE__);\n\t\n\t// codonsToNucleotides()\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(integer(0), format='string'), '')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(integer(0), format='char'), string(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(integer(0), format='integer'), integer(0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0, format='string'), 'AAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(1, format='string'), 'AAC')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(2, format='string'), 'AAG')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(3, format='string'), 'AAT')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(4, format='string'), 'ACA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(8, format='string'), 'AGA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(12, format='string'), 'ATA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(16, format='string'), 'CAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(32, format='string'), 'GAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(48, format='string'), 'TAA')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(63, format='string'), 'TTT')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0, format='char'), c('A','A','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(1, format='char'), c('A','A','C'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(2, format='char'), c('A','A','G'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(3, format='char'), c('A','A','T'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(4, format='char'), c('A','C','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(8, format='char'), c('A','G','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(12, format='char'), c('A','T','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(16, format='char'), c('C','A','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(32, format='char'), c('G','A','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(48, format='char'), c('T','A','A'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(63, format='char'), c('T','T','T'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0, format='integer'), c(0,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(1, format='integer'), c(0,0,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(2, format='integer'), c(0,0,2))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(3, format='integer'), c(0,0,3))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(4, format='integer'), c(0,1,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(8, format='integer'), c(0,2,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(12, format='integer'), c(0,3,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(16, format='integer'), c(1,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(32, format='integer'), c(2,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(48, format='integer'), c(3,0,0))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(63, format='integer'), c(3,3,3))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0:5, format='string'), 'AAAAACAAGAATACAACC')) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0:5, format='char'), c('A','A','A','A','A','C','A','A','G','A','A','T','A','C','A','A','C','C'))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (identical(codonsToNucleotides(0:5, format='integer'), c(0,0,0,0,0,1,0,0,2,0,0,3,0,1,0,0,1,1))) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(-1, format='string'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(-1, format='char'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(-1, format='integer'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(64, format='string'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(64, format='char'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(64, format='integer'); }\", \"requires codon values to be\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { codonsToNucleotides(0, format='foo'); }\", \"requires a format of\", __LINE__);\n}\n\nvoid _RunNucleotideMethodTests(void)\n{\n\t// Test that various nucleotide-based APIs behave as they ought to when used in a non-nucleotide model\n\tSLiMAssertScriptRaise(\"initialize() { initializeAncestralNucleotides('ACGT'); } \", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeHotspotMap(1.0); } \", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationTypeNuc(1, 0.5, 'f', 0.0); } \", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mutationMatrix=mmJukesCantor(1e-7)); } \", \"to be NULL in non-nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotEndPositions; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotEndPositionsM; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotEndPositionsF; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotMultipliers; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotMultipliersM; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.hotspotMultipliersF; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.ancestralNucleotides(); }\", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { sim.chromosomes.setHotspotMap(1.0); }\", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { p1.haplosomes[0].nucleotides(); }\", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { g1.mutationMatrix; }\", \"only defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { g1.setMutationMatrix(mmJukesCantor(1e-7)); }\", \"only be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.nucleotide; }\", \"only defined for nucleotide-based mutations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_highmut_p1 + \"10 early() { mut = sim.mutations[0]; mut.nucleotideValue; }\", \"only defined for nucleotide-based mutations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.nucleotide; }\", \"only defined for nucleotide-based mutations\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_fixmut_p1 + \"30 early() { sub = sim.substitutions[0]; sub.nucleotideValue; }\", \"only defined for nucleotide-based mutations\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (sim.nucleotideBased == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(gen1_setup_p1 + \"1 early() { if (m1.nucleotideBased == F) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 5000, nucleotide='A'); stop(); }\", \"NULL in non-nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup_p1 + \"1 early() { gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.0, 5000, nucleotide='A'); stop(); }\", \"NULL in non-nucleotide-based models\", __LINE__);\n\t\n\t// Test that some APIs are correctly disabled in nucleotide-based models\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(nucleotideBased=T); initializeMutationRate(1e-7); } \", \"may not be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(\"initialize() { initializeSLiMOptions(nucleotideBased=T); initializeMutationTypeNuc(1, 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0); }\", \"non-NULL in nucleotide-based models\", __LINE__);\n\t\n\tstd::string nuc_model_start(\"initialize() { initializeSLiMOptions(nucleotideBased=T); \");\n\tstd::string nuc_model_init(nuc_model_start + \"initializeAncestralNucleotides(randomNucleotides(1e2)); initializeMutationTypeNuc(1, 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-7)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } \");\n\t\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationEndPositions; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationEndPositionsF; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationEndPositionsM; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationRates; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationRatesF; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.mutationRatesM; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.overallMutationRate; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.overallMutationRateF; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.overallMutationRateM; }\", \"not defined in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setMutationRate(1e-7); }\", \"may not be called in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop('p1', 10); gen = p1.haplosomes[0]; mut = gen.addNewDrawnMutation(m1, 50); }\", \"requires nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop('p1', 10); gen = p1.haplosomes[0]; mut = gen.addNewMutation(m1, 0.0, 50); }\", \"requires nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { m1.mutationStackGroup = 2; }\", \"for nucleotide-based mutation types\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { m1.mutationStackPolicy = 'f'; }\", \"for nucleotide-based mutation types\", __LINE__);\n\t\n\t// initializeAncestralNucleotides()\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(integer(0)); } \", \"requires a sequence of length >= 1\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(-1); } \", \"integer nucleotide value\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(4); } \", \"integer nucleotide value\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides('AACAGTACGTTACAGGTACAD'); } \", \"could not be opened or does not exist\", __LINE__);\t// file path!\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(c(0,-1,2)); } \", \"integer nucleotide value\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(c(0,4,2)); } \", \"integer nucleotide value\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeAncestralNucleotides(c('A','D','T')); } \", \"string nucleotide character\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"if (initializeAncestralNucleotides('A') == 1) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"if (initializeAncestralNucleotides(0) == 1) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"if (initializeAncestralNucleotides('ACGTACGT') == 8) stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"if (initializeAncestralNucleotides(c(0,1,2,3,0,1,2,3)) == 8) stop(); } \", __LINE__);\n\t\n\t// initializeHotspotMap()\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(float(0)); } \", \"to be a singleton\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(1.0, integer(0)); } \", \"of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(float(0), 1e2-1); } \", \"of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(float(0), integer(0)); } \", \"of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(1.0, sex='A'); } \", \"requested sex 'A' unsupported\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(1.0, sex='M'); } \", \"supplied in non-sexual simulation\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeSex('A'); initializeHotspotMap(1.0, sex='A'); } \", \"requested sex 'A' unsupported\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeSex('A'); initializeHotspotMap(1.0, sex='M'); initializeHotspotMap(1.0, sex='F'); initializeHotspotMap(1.0, sex='M'); } \", \"may be called only once\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(1.0); initializeHotspotMap(1.0); } \", \"may be called only once\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(c(1.0, 1.2)); } \", \"multipliers to be a singleton\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(-0.1); } \", \"multipliers to be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(0.1, c(10, 20)); } \", \"of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(c(1.0, 1.2), 10); } \", \"of equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(c(1.0, 1.2), c(20, 10)); } \", \"in strictly ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeHotspotMap(c(1.0, -1.2), c(10, 20)); } \", \"multipliers to be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeHotspotMap(c(1.0, 1.2), c(10, 20)); } 1 early() {}\", \"do not cover the full chromosome\", __LINE__, false);\n\tSLiMAssertScriptStop(nuc_model_start + \"initializeHotspotMap(2.0); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeHotspotMap(c(1.0, 1.2), c(10, 1e2-1)); } 1 early() { stop(); } \", __LINE__);\n\t\n\t// initializeMutationTypeNuc() (copied from initializeMutationType())\n\tSLiMAssertScriptStop(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f', 0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"initializeMutationTypeNuc(1, 0.5, 'f', 0.0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc(-1, 0.5, 'f', 0.0); stop(); }\", \"identifier value is out of range\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('p2', 0.5, 'f', 0.0); stop(); }\", \"identifier prefix 'm' was expected\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('mm1', 0.5, 'f', 0.0); stop(); }\", \"must be a simple integer\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f'); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f', 0.0, 0.0); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'e', 0.0, 0.0); stop(); }\", \"requires exactly 1 DFE parameter\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 0.0); stop(); }\", \"requires exactly 2 DFE parameters\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'e', 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 'foo', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 0.0, 'foo'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'e', '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', '1', 0.0); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 0.0, '1'); stop(); }\", \"must be of type numeric\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'x', 0.0); stop(); }\", \"must be 'f', 'g', 'e', 'n', 'w', or 's'\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"x = initializeMutationTypeNuc('m7', 0.5, 'f', 0.0); if (x == m7) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_start + \"x = initializeMutationTypeNuc(7, 0.5, 'f', 0.0); if (x == m7) stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"m7 = 15; initializeMutationTypeNuc(7, 0.5, 'f', 0.0); stop(); }\", \"already defined\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'f', 0.0); initializeMutationTypeNuc('m1', 0.5, 'f', 0.0); stop(); }\", \"already defined\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 3.1, 0.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'g', 3.1, -1.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'n', 3.1, -1.0); stop(); }\", \"must have a standard deviation parameter >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 3.1, 0.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'p', 3.1, -1.0); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 0.0, 7.5); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', -1.0, 7.5); stop(); }\", \"must have a scale parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 3.1, 0.0); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationTypeNuc('m1', 0.5, 'w', 3.1, -7.5); stop(); }\", \"must have a shape parameter > 0\", __LINE__);\n\t\n\t// initializeGenomicElementType()\n\tSLiMAssertScriptRaise(nuc_model_start + \"initializeMutationType('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mutationMatrix=mmJukesCantor(1e-7)); } \", \"requires all mutation types for\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0); } \", \"non-NULL in nucleotide-based models\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, float(0)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, rep(1.0, 16)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, rep(1.0, 256)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, matrix(rep(1.0, 16), ncol=2)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, matrix(rep(1.0, 256), ncol=2)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, matrix(rep(1.0, 16), ncol=4)); } \", \"must contain 0.0 for all\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, matrix(rep(1.0, 256), ncol=4)); } \", \"must contain 0.0 for all\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, mmJukesCantor(0.25)*2); } \", \"requires the sum of each mutation matrix row\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, mm16To256(mmJukesCantor(0.25))*2); } \", \"requires the sum of each mutation matrix row\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { mm = mmJukesCantor(0.25); mm[0,1] = -0.1; initializeGenomicElementType('g2', m1, 1.0, mm); } \", \"to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"initialize() { mm = mm16To256(mmJukesCantor(0.25)); mm[0,1] = -0.1; initializeGenomicElementType('g2', m1, 1.0, mm); } \", \"to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, mmJukesCantor(0.25)); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGenomicElementType('g2', m1, 1.0, mm16To256(mmJukesCantor(0.25))); stop(); } \", __LINE__);\n\t\n\t// hotspotEndPositions, hotspotEndPositionsM, hotspotEndPositionsF\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { if (sim.chromosomes.hotspotEndPositions == 1e2-1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeHotspotMap(2.0); } 1 early() { if (sim.chromosomes.hotspotEndPositions == 1e2-1) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeHotspotMap(c(1.0, 1.2), c(10, 1e2-1)); } 1 early() { if (identical(sim.chromosomes.hotspotEndPositions, c(10, 1e2-1))) stop(); }\", __LINE__);\n\t\n\t// hotspotMultipliers, hotspotMultipliersM, hotspotMultipliersF\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { if (sim.chromosomes.hotspotMultipliers == 1.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeHotspotMap(2.0); } 1 early() { if (sim.chromosomes.hotspotMultipliers == 2.0) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeHotspotMap(c(1.0, 1.2), c(10, 1e2-1)); } 1 early() { if (identical(sim.chromosomes.hotspotMultipliers, c(1.0, 1.2))) stop(); }\", __LINE__);\n\t\n\t// ancestralNucleotides()\n\tstd::string ances_setup_string = \"initialize() { initializeSLiMOptions(nucleotideBased=T); defineConstant('AS', randomNucleotides(1e2, format='string')); initializeAncestralNucleotides(AS); initializeMutationTypeNuc(1, 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-7)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } \";\n\tstd::string ances_setup_char = \"initialize() { initializeSLiMOptions(nucleotideBased=T); defineConstant('AS', randomNucleotides(1e2, format='char')); initializeAncestralNucleotides(AS); initializeMutationTypeNuc(1, 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-7)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } \";\n\tstd::string ances_setup_integer = \"initialize() { initializeSLiMOptions(nucleotideBased=T); defineConstant('AS', randomNucleotides(1e2, format='integer')); initializeAncestralNucleotides(AS); initializeMutationTypeNuc(1, 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-7)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } \";\n\t\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(format='string'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(end=49, format='string'), substr(AS, 0, 49))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=50, format='string'), substr(AS, 50, 99))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=25, end=69, format='string'), substr(AS, 25, 69))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(substr(AS, 10, 39)))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(format='char'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(end=49, format='char'), AS[0:49])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=50, format='char'), AS[50:99])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=25, end=69, format='char'), AS[25:69])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(AS[10:39]))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(format='integer'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(end=49, format='integer'), AS[0:49])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=50, format='integer'), AS[50:99])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=25, end=69, format='integer'), AS[25:69])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { if (identical(sim.chromosomes.ancestralNucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(AS[10:39]))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.chromosomes.ancestralNucleotides(start=-1, end=50, format='integer'); }\", \"within the chromosome's extent\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.chromosomes.ancestralNucleotides(start=50, end=100, format='integer'); }\", \"within the chromosome's extent\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.chromosomes.ancestralNucleotides(start=75, end=25, format='integer'); }\", \"start must be <= end\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.chromosomes.ancestralNucleotides(format='foo'); }\", \"format must be either\", __LINE__);\n\t\n\t// setHotspotMap()\n\tstd::string nuc_w_hotspot = nuc_model_init + \"initialize() { initializeHotspotMap(c(1.0, 1.2), c(10, 1e2-1)); } \";\n\t\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(float(0)); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(1.0, integer(0)); }\", \"equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(float(0), 1e2-1); }\", \"equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(float(0), integer(0)); }\", \"equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(1.0, sex='A'); }\", \"sex 'A' unsupported\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(1.0, sex='M'); }\", \"original configuration\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, 1.2)); }\", \"to be a singleton if\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(-0.1); }\", \"multipliers must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(0.1, c(10, 20)); }\", \"equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, 1.2), 10); }\", \"equal and nonzero size\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, 1.2), c(20, 10)); }\", \"strictly ascending order\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, -1.2), c(10, 20)); }\", \"multipliers must be >= 0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, 1.2), c(10, 20)); }\", \"must end at the last position\", __LINE__);\n\tSLiMAssertScriptStop(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(1.2); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_w_hotspot + \"1 early() { sim.chromosomes.setHotspotMap(c(1.0, 1.2), c(10, 1e2-1)); stop(); }\", __LINE__);\n\t\n\t// nucleotides()\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(format='string'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(end=49, format='string'), substr(AS, 0, 49))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=50, format='string'), substr(AS, 50, 99))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=25, end=69, format='string'), substr(AS, 25, 69))) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_string + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(substr(AS, 10, 39)))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(format='char'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(end=49, format='char'), AS[0:49])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=50, format='char'), AS[50:99])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=25, end=69, format='char'), AS[25:69])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_char + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(AS[10:39]))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(format='integer'), AS)) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(end=49, format='integer'), AS[0:49])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=50, format='integer'), AS[50:99])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=25, end=69, format='integer'), AS[25:69])) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); if (identical(p1.haplosomes[0].nucleotides(start=10, end=39, format='codon'), nucleotidesToCodons(AS[10:39]))) stop(); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].nucleotides(start=-1, end=50, format='integer'); }\", \"within the chromosome's extent\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].nucleotides(start=50, end=100, format='integer'); }\", \"within the chromosome's extent\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].nucleotides(start=75, end=25, format='integer'); }\", \"start must be <= end\", __LINE__);\n\tSLiMAssertScriptRaise(ances_setup_integer + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].nucleotides(format='foo'); }\", \"format must be either\", __LINE__);\n\t\n\t// mutationMatrix()\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { if (identical(g1.mutationMatrix, mmJukesCantor(1e-7))) stop(); }\", __LINE__);\n\t\n\t// setMutationMatrix()\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(NULL); } \", \"cannot be type NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(float(0)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(rep(1.0, 16)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(rep(1.0, 256)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(matrix(rep(1.0, 16), ncol=2)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(matrix(rep(1.0, 256), ncol=2)); } \", \"a 4x4 or 64x4 matrix\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(matrix(rep(1.0, 16), ncol=4)); } \", \"must contain 0.0 for all\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(matrix(rep(1.0, 256), ncol=4)); } \", \"must contain 0.0 for all\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(mmJukesCantor(0.25)*2); } \", \"requires the sum of each mutation matrix row\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { g1.setMutationMatrix(mm16To256(mmJukesCantor(0.25))*2); } \", \"requires the sum of each mutation matrix row\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { mm = mmJukesCantor(0.25); mm[0,1] = -0.1; g1.setMutationMatrix(mm); } \", \"to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { mm = mm16To256(mmJukesCantor(0.25)); mm[0,1] = -0.1; g1.setMutationMatrix(mm); } \", \"to be finite and >= 0.0\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { g1.setMutationMatrix(mmJukesCantor(0.25)); stop(); } \", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { g1.setMutationMatrix(mm16To256(mmJukesCantor(0.25))); stop(); } \", __LINE__);\n\t\n\t// nucleotide & nucleotideValue\n\tstd::string nuc_highmut(\"initialize() { initializeSLiMOptions(nucleotideBased=T); initializeAncestralNucleotides(randomNucleotides(1e2)); initializeMutationTypeNuc('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-2)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } \");\n\tstd::string nuc_fixmut(\"initialize() { initializeSLiMOptions(nucleotideBased=T); initializeAncestralNucleotides(randomNucleotides(1e2)); initializeMutationTypeNuc('m1', 0.5, 'f', 0.0); initializeGenomicElementType('g1', m1, 1.0, mmJukesCantor(1e-2)); initializeGenomicElement(g1, 0, 1e2-1); initializeRecombinationRate(1e-8); } 1 early() { sim.addSubpop('p1', 10); } 10 early() { sim.mutations[0].setSelectionCoeff(500.0); sim.recalculateFitness(); } \");\n\t\n\tSLiMAssertScriptStop(nuc_highmut + \"10 early() { mut = sim.mutations[0]; mut.nucleotide; stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_highmut + \"10 early() { mut = sim.mutations[0]; mut.nucleotideValue; stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_fixmut + \"30 early() { sub = sim.substitutions[0]; sub.nucleotide; stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_fixmut + \"30 early() { sub = sim.substitutions[0]; sub.nucleotideValue; stop(); }\", __LINE__);\n\t\n\t// addNewDrawnMutation()\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide=NULL); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide='D'); }\", \"string nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide=-1); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide=4); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide='A'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewDrawnMutation(m1, 10, nucleotide=0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=NULL); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=c('A','D','G','C')); }\", \"string nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=c(0,-1,2,3)); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=c(0,4,2,3)); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=c('A','C','G','T')); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewDrawnMutation(m1, 10, nucleotide=0:3); stop(); }\", __LINE__);\n\t\n\t// addNewMutation()\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide=NULL); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide='D'); }\", \"string nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide=-1); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide=4); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide='A'); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0].addNewMutation(m1, 0.5, 10, nucleotide=0); stop(); }\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=NULL); }\", \"nucleotide to be non-NULL\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=c('A','D','G','C')); }\", \"string nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=c(0,-1,2,3)); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=c(0,4,2,3)); }\", \"integer nucleotide values\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=c('A','C','G','T')); stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.addSubpop(1, 10); p1.haplosomes[0:3].addNewMutation(m1, 0.5, 10, nucleotide=0:3); stop(); }\", __LINE__);\n\t\n\t// Species.nucleotideBased\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { if (sim.nucleotideBased == T) stop(); }\", __LINE__);\n\t\n\t// MutationType.nucleotideBased\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { if (m1.nucleotideBased == T) stop(); }\", __LINE__);\n\t\n\t// initializeGeneConversion() tests using GC bias != 0\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75, -0.01); } 1 early() { if (sim.chromosomes.geneConversionEnabled == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75, -0.01); } 1 early() { if (sim.chromosomes.geneConversionNonCrossoverFraction == 0.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75, -0.01); } 1 early() { if (sim.chromosomes.geneConversionMeanLength == 1234.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75, -0.01); } 1 early() { if (sim.chromosomes.geneConversionSimpleConversionFraction == 0.75) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"initialize() { initializeGeneConversion(0.2, 1234.5, 0.75, -0.01); } 1 early() { if (sim.chromosomes.geneConversionGCBias == -0.01) stop(); }\", __LINE__);\n\t\n\t// Chromosome.setGeneConversion() tests using GC bias != 0\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75, -0.01); if (sim.chromosomes.geneConversionEnabled == T) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75, -0.01); if (sim.chromosomes.geneConversionNonCrossoverFraction == 0.2) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75, -0.01); if (sim.chromosomes.geneConversionMeanLength == 1234.5) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75, -0.01); if (sim.chromosomes.geneConversionSimpleConversionFraction == 0.75) stop(); }\", __LINE__);\n\tSLiMAssertScriptStop(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.2, 1234.5, 0.75, -0.01); if (sim.chromosomes.geneConversionGCBias == -0.01) stop(); }\", __LINE__);\n\t\n\t// Chromosome.setGeneConversion() bounds tests\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(-0.001, 10000000000000, 0.0); stop(); }\", \"nonCrossoverFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(1.001, 10000000000000, 0.0); stop(); }\", \"nonCrossoverFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.5, -0.01, 0.0); stop(); }\", \"meanLength must be >= 0.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.5, 1000, -0.001); stop(); }\", \"simpleConversionFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.5, 1000, 1.001); stop(); }\", \"simpleConversionFraction must be between 0.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.5, 1000, 0.0, -1.001); stop(); }\", \"bias must be between -1.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(nuc_model_init + \"1 early() { sim.chromosomes.setGeneConversion(0.5, 1000, 0.0, 1.001); stop(); }\", \"bias must be between -1.0 and 1.0\", __LINE__);\n\tSLiMAssertScriptRaise(gen1_setup + \"1 early() { sim.chromosomes.setGeneConversion(0.5, 1000, 0.0, 0.1); stop(); }\", \"must be 0.0 in non-nucleotide-based models\", __LINE__);\n}\n\n#pragma mark Population Genetics tests\n\nvoid _RunPopGenFunctionTests(void)\n{\n/*\n\tThese tests are based on the following test script:\n\t\ninitialize() {\n\tinitializeMutationType(\"m1\", 0.5, \"n\", 0.0, 0.001);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tchr = initializeChromosome(1, 5e5);\n\tinitializeMutationRate(1e-7);\n\tinitializeGenomicElement(g1, 0, 5e5-1);\n\tinitializeRecombinationRate(1e-8);\n\tdefineConstant(\"CHR1\", chr);\n\t\n\tchr = initializeChromosome(2, 1e6);\n\tinitializeMutationRate(1e-7);\n\tinitializeGenomicElement(g1, 0, 1e6-1);\n\tinitializeRecombinationRate(1e-8);\n\tdefineConstant(\"CHR2\", chr);\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\", 50);\n\tsim.addSubpop(\"p2\", 50);\n\tp1.setMigrationRates(p2, 0.01);\n\tp2.setMigrationRates(p1, 0.01);\n}\n\n1:2000 late() {\n\t// test calc...() functions; note that in tick 1 all haplosomes are empty by design\n\tcatn(\"Tick \" + community.tick + \" (\" + size(sim.mutations) + \" mutations segregating)\");\n\t\n\th0 = p1.haplosomes[integer(0)];\n\th_p1_ch1 = p1.haplosomesForChromosomes(1)[0];\n\th_p2_ch1 = p2.haplosomesForChromosomes(1)[0];\n\th_p1_ch2 = p1.haplosomesForChromosomes(2)[0];\n\th_p2_ch2 = p2.haplosomesForChromosomes(2)[0];\n\tmuts_ch1 = sim.subsetMutations(chromosome=1);\n\tmuts_ch2 = sim.subsetMutations(chromosome=2);\n\t\n\t//calcFST(h0, h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\t//calcFST(p1.haplosomes, p2.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch2);\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   FST(1h) == \" + calcFST(p1.haplosomesForChromosomes(1)[0], p2.haplosomesForChromosomes(1)[0]));\t// valid even with 1 haplosome each\n\tcatn(\"   FST(CHR1) == \" + calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1)));\n\tcatn(\"   FST(CHR2) == \" + calcFST(p1.haplosomesForChromosomes(2), p2.haplosomesForChromosomes(2)));\n\tcatn(\"   FST(CHR1, muts_ch1) == \" + calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch1));\n\t\n\t//calcHeterozygosity(h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\t//calcHeterozygosity(sim.subpopulations.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2);\t\t\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   het(1h) == \" + calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1)[0]));\t\t\t\t// valid even with 1 haplosome\n\tcatn(\"   het(CHR1) == \" + calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1)));\n\tcatn(\"   het(CHR2) == \" + calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(2)));\n\tcatn(\"   het(CHR1, muts_ch1) == \" + calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1));\n\t\n\t//calcVA(p1.individuals, 2);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// errors (can't find m2)\n\t//calcVA(p1.individuals[integer(0)], m1);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must contain at least 2 elements\n\t//calcVA(p1.individuals[0], m1);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must contain at least 2 elements\n\tcatn(\"   VA(2i) == \" + calcVA(p1.individuals[0:1], m1));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// valid with 2 individuals\n\tcatn(\"   VA(p1) == \" + calcVA(p1.individuals, m1));\n\tcatn(\"   VA(p2) == \" + calcVA(p2.individuals, 1));\n\tcatn(\"   VA(all) == \" + calcVA(sim.subpopulations.individuals, m1));\n\t\n\t//calcPairHeterozygosity(h_p1_ch1, h_p1_ch2);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   pairHet(CHR1) == \" + calcPairHeterozygosity(h_p1_ch1, h_p2_ch1));\n\tcatn(\"   pairHet(CHR2) == \" + calcPairHeterozygosity(h_p1_ch2, h_p2_ch2));\n\t\n\t//calcWattersonsTheta(h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\tcatn(\"   WatTh(1h) == \" + calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1)[0]));\t\t\t// valid even with 1 haplosome\n\t//calcWattersonsTheta(p1.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2);\t\t\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   WatTh(CHR1) == \" + calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1)));\n\tcatn(\"   WatTh(CHR2) == \" + calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(2)));\n\tcatn(\"   WatTh(CHR1, muts_ch1) == \" + calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1));\n\t\n\t//calcInbreedingLoad(h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\tcatn(\"   inbL(h1) == \" + calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1)[0]));\t\t\t// valid even with 1 haplosome\n\t//calcInbreedingLoad(sim.subpopulations.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), 2);\t\t\t\t\t\t\t\t\t\t\t// errors (can't find m2)\n\tcatn(\"   inbL(CHR1) == \" + calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1)));\n\tcatn(\"   inbL(CHR1) == \" + calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), 1));\n\tcatn(\"   inbL(CHR1) == \" + calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), m1));\n\tcatn(\"   inbL(CHR2) == \" + calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(2)));\n\t\n\t//calcPi(h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\t//calcPi(sim.subpopulations.haplosomesForChromosomes(1)[0]);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must contain at least 2 elements\n\tcatn(\"   pi(2h) == \" + calcPi(sim.subpopulations.haplosomesForChromosomes(1)[0:1]));\t\t\t\t\t\t\t// valid with 2 haplosomes\n\t//calcPi(p1.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcPi(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2);\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   pi(CHR1) == \" + calcPi(sim.subpopulations.haplosomesForChromosomes(1)));\n\tcatn(\"   pi(CHR2) == \" + calcPi(sim.subpopulations.haplosomesForChromosomes(2)));\n\tcatn(\"   pi(CHR1, muts_ch1) == \" + calcPi(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1));\n\t\n\t//calcTajimasD(h0);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// must be non-empty\n\t//catn(\"   TajD(1h) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0]));\t\t\t\t\t// must contain at least 4 elements\n\t//catn(\"   TajD(2h) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:1]));\t\t\t\t// must contain at least 4 elements\n\t//catn(\"   TajD(3h) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:2]));\t\t\t\t// must contain at least 4 elements\n\tcatn(\"   TajD(4h) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:3]));\t\t\t\t\t// valid with 4 haplosomes\n\t//calcTajimasD(p1.haplosomes);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\t//calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2);\t\t\t\t\t\t\t\t\t\t\t// multichrom error\n\tcatn(\"   TajD(CHR1) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)));\n\tcatn(\"   TajD(CHR2) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(2)));\n\tcatn(\"   TajD(CHR1, muts_ch1) == \" + calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1));\n}\n\n\tNote that this section only tests for correct bounds-checking and errors and such; we do not\n\tcheck for numerical correctness.  Doing that is tricky and not yet implemented.  FIXME\n */\n\t\n\tstd::string base_script = \"initialize() { initializeMutationType('m1', 0.5, 'n', 0.0, 0.001); initializeGenomicElementType('g1', m1, 1.0); chr = initializeChromosome(1, 5e5); initializeMutationRate(1e-7); initializeGenomicElement(g1, 0, 5e5-1); initializeRecombinationRate(1e-8); defineConstant('CHR1', chr); chr = initializeChromosome(2, 1e6); initializeMutationRate(1e-7); initializeGenomicElement(g1, 0, 1e6-1); initializeRecombinationRate(1e-8); defineConstant('CHR2', chr); } 1 late() { sim.addSubpop('p1', 50); sim.addSubpop('p2', 50); p1.setMigrationRates(p2, 0.01); p2.setMigrationRates(p1, 0.01); } 1:100 late() { h0 = p1.haplosomes[integer(0)]; h_p1_ch1 = p1.haplosomesForChromosomes(1)[0]; h_p2_ch1 = p2.haplosomesForChromosomes(1)[0]; h_p1_ch2 = p1.haplosomesForChromosomes(2)[0]; h_p2_ch2 = p2.haplosomesForChromosomes(2)[0]; muts_ch1 = sim.subsetMutations(chromosome=1); muts_ch2 = sim.subsetMutations(chromosome=2); \";\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcDxy(h0, h0); }\", \"must both be non-empty\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcDxy(p1.haplosomes, p2.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcDxy(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(1)[0], p2.haplosomesForChromosomes(1)[0]); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(2), p2.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(2), p2.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcDxy(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcFST(h0, h0); }\", \"must both be non-empty\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomes, p2.haplosomes); }\", __LINE__);\n\tSLiMAssertScriptRaise(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(2)); }\", \"same set of chromosomes\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(1)[0], p2.haplosomesForChromosomes(1)[0]); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(2), p2.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(2), p2.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcFST(p1.haplosomesForChromosomes(1), p2.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcHeterozygosity(h0); }\", \"haplosomes must be non-empty\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1)[0]); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcHeterozygosity(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcVA(p1.individuals, 2); }\", \"did not find a mutation type\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcVA(p1.individuals[integer(0)], m1); }\", \"at least two elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcVA(p1.individuals[0], m1); }\", \"at least two elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcVA(p1.individuals[0:1], m1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcVA(p1.individuals, m1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcVA(p2.individuals, 1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcVA(sim.subpopulations.individuals, m1); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcPairHeterozygosity(h_p1_ch1, h_p1_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch1, h_p2_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch2, h_p2_ch2); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch1, h_p2_ch1, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch2, h_p2_ch2, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch1, h_p2_ch1, infiniteSites=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch2, h_p2_ch2, infiniteSites=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch1, h_p2_ch1, 1e5, 2e5, infiniteSites=F); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPairHeterozygosity(h_p1_ch2, h_p2_ch2, 1e5, 2e5, infiniteSites=F); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcWattersonsTheta(h0); }\", \"haplosomes must be non-empty\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1)[0]); }\", __LINE__);\n\tSLiMAssertScriptRaise(base_script + \"calcWattersonsTheta(p1.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcWattersonsTheta(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcInbreedingLoad(h0); }\", \"haplosomes must be non-empty\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1)[0]); }\", __LINE__);\n\tSLiMAssertScriptRaise(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), 2); }\", \"did not find a mutation type\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), 1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(1), m1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcInbreedingLoad(sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcPi(h0); }\", \"haplosomes must contain at least two elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1)[0]); }\", \"haplosomes must contain at least two elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1)[0:1]); }\", __LINE__);\n\tSLiMAssertScriptRaise(base_script + \"calcPi(p1.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcPi(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(h0); }\", \"haplosomes must contain at least four elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0]); }\", \"haplosomes must contain at least four elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:1]); }\", \"haplosomes must contain at least four elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:2]); }\", \"haplosomes must contain at least four elements\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)[0:3]); }\", __LINE__);\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(p1.haplosomes); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptRaise(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), muts_ch2); }\", \"same chromosome\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(2), NULL, 1e5, 2e5); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcTajimasD(sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, 1e5, 2e5); }\", __LINE__);\n\t\n\t// (numeric)calcSFS([Ni$ binCount = NULL], [No<Haplosome> haplosomes = NULL], [No<Mutation> muts = NULL], [string$ metric = \"density\"], [logical$ fold = F])\n\tSLiMAssertScriptRaise(base_script + \"calcSFS(); }\", \"when binCount is NULL\", __LINE__, true, /* p_error_is_in_stop */ true);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(2)); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), muts_ch1); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), metric='count'); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(2), metric='count'); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, metric='count'); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), fold=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(2), fold=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, fold=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), metric='count', fold=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(2), metric='count', fold=T); }\", __LINE__);\n\tSLiMAssertScriptSuccess(base_script + \"calcSFS(10, sim.subpopulations.haplosomesForChromosomes(1), muts_ch1, metric='count', fold=T); }\", __LINE__);\n}\n\n#pragma mark Spatial kernel value tests\nvoid _RunSpatialKernelValueTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tTests for numerical correctness of spatial interaction kernel calculations\n\t//\n\t//\tThese tests verify that each kernel type produces correct strength values\n\t//\tfor known distances and parameters. This catches bugs in SIMD implementations\n\t//\tby comparing against expected values computed from the kernel formulas.\n\t//\n\n\t// Base setup: 1D spatial model with two individuals at known positions\n\t// Individual 0 at x=0.0, Individual 1 at x=0.5, so distance = 0.5\n\t// maxDistance = 1.0 for all tests\n\tstd::string kernel_test_setup =\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.5; \";  // distance = 0.5\n\n\t// Test Linear kernel: strength = fmax * (1 - d / max_distance)\n\t// fmax = 5.0, max_distance = 1.0, distance = 0.5\n\t// Expected: 5.0 * (1 - 0.5 / 1.0) = 5.0 * 0.5 = 2.5\n\tSLiMAssertScriptStop(kernel_test_setup +\n\t\t\"  i1.setInteractionFunction('l', 5.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 2.5)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Linear kernel at distance = 0 (should return fmax)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.0; \"  // distance = 0\n\t\t\"  i1.setInteractionFunction('l', 5.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 5.0)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Exponential kernel: strength = fmax * exp(-lambda * d)\n\t// fmax = 5.0, lambda = 2.0, distance = 0.5\n\t// Expected: 5.0 * exp(-2.0 * 0.5) = 5.0 * exp(-1.0) ≈ 1.8394\n\tSLiMAssertScriptStop(kernel_test_setup +\n\t\t\"  i1.setInteractionFunction('e', 5.0, 2.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  expected = 5.0 * exp(-2.0 * 0.5); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), expected)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Exponential kernel at distance = 0 (should return fmax)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.0; \"\n\t\t\"  i1.setInteractionFunction('e', 5.0, 2.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 5.0)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Normal (Gaussian) kernel: strength = fmax * exp(-d^2 / (2 * sigma^2))\n\t// fmax = 5.0, sigma = 0.5, distance = 0.5\n\t// Expected: 5.0 * exp(-0.25 / 0.5) = 5.0 * exp(-0.5) ≈ 3.0327\n\tSLiMAssertScriptStop(kernel_test_setup +\n\t\t\"  i1.setInteractionFunction('n', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  expected = 5.0 * exp(-0.5 * 0.5 / (2.0 * 0.5 * 0.5)); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), expected)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Normal kernel at distance = 0 (should return fmax)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.0; \"\n\t\t\"  i1.setInteractionFunction('n', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 5.0)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Cauchy kernel: strength = fmax / (1 + (d / lambda)^2)\n\t// fmax = 5.0, lambda = 0.5, distance = 0.5\n\t// Expected: 5.0 / (1 + (0.5/0.5)^2) = 5.0 / 2 = 2.5\n\tSLiMAssertScriptStop(kernel_test_setup +\n\t\t\"  i1.setInteractionFunction('c', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  expected = 5.0 / (1.0 + (0.5/0.5)^2); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), expected)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Cauchy kernel at distance = 0 (should return fmax)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.0; \"\n\t\t\"  i1.setInteractionFunction('c', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 5.0)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Student's T kernel: strength = fmax * pow(1 + (d/tau)^2 / nu, -(nu+1)/2)\n\t// Correct formula: strength decreases with distance as base > 1 and exponent < 0\n\t// fmax = 5.0, nu = 3.0, tau = 0.5, distance = 0.5\n\t// base = 1 + (0.5/0.5)^2 / 3 = 4/3, exponent = -(3+1)/2 = -2\n\t// Correct: 5.0 * (4/3)^(-2) = 5.0 * (9/16) = 2.8125\n\tSLiMAssertScriptStop(kernel_test_setup +\n\t\t\"  i1.setInteractionFunction('t', 5.0, 3.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  d_over_tau = 0.5 / 0.5; \"\n\t\t\"  base = 1.0 + d_over_tau^2 / 3.0; \"\n\t\t\"  expected = 5.0 * base^(-(3.0 + 1.0) / 2.0); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), expected)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test Student's T kernel at distance = 0 (should return fmax)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=1.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.0; \"\n\t\t\"  i1.setInteractionFunction('t', 5.0, 3.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), 5.0)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// =============================================================================\n\t// SIMD vs Scalar consistency tests\n\t// These tests compare the scalar path (i1.strength()) against the SIMD path\n\t// (i1.totalOfNeighborStrengths()) to ensure both implementations agree.\n\t// The scalar path uses CalculateStrengthNoCallbacks() in interaction_type.cpp\n\t// The SIMD path uses the *_kernel_float32() functions in eidos_simd.h\n\t// =============================================================================\n\n\t// Shared setup for 2D SIMD consistency tests\n\tstd::string simd_consistency_setup =\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='xy'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'xy', maxDistance=2.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; p1.individuals[0].y = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.5; p1.individuals[1].y = 0.0; \";\n\n\t// Linear kernel: SIMD (linear_kernel_float32) vs scalar consistency\n\tSLiMAssertScriptStop(simd_consistency_setup +\n\t\t\"  i1.setInteractionFunction('l', 5.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  scalar_strength = i1.strength(p1.individuals[0], p1.individuals[1]); \"\n\t\t\"  simd_strength = i1.totalOfNeighborStrengths(p1.individuals[0]); \"\n\t\t\"  if (allClose(scalar_strength, simd_strength)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Exponential kernel: SIMD (exp_kernel_float32) vs scalar consistency\n\tSLiMAssertScriptStop(simd_consistency_setup +\n\t\t\"  i1.setInteractionFunction('e', 5.0, 2.0); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  scalar_strength = i1.strength(p1.individuals[0], p1.individuals[1]); \"\n\t\t\"  simd_strength = i1.totalOfNeighborStrengths(p1.individuals[0]); \"\n\t\t\"  if (allClose(scalar_strength, simd_strength)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Normal kernel: SIMD (normal_kernel_float32) vs scalar consistency\n\tSLiMAssertScriptStop(simd_consistency_setup +\n\t\t\"  i1.setInteractionFunction('n', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  scalar_strength = i1.strength(p1.individuals[0], p1.individuals[1]); \"\n\t\t\"  simd_strength = i1.totalOfNeighborStrengths(p1.individuals[0]); \"\n\t\t\"  if (allClose(scalar_strength, simd_strength)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Cauchy kernel: SIMD (cauchy_kernel_float32) vs scalar consistency\n\tSLiMAssertScriptStop(simd_consistency_setup +\n\t\t\"  i1.setInteractionFunction('c', 5.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  scalar_strength = i1.strength(p1.individuals[0], p1.individuals[1]); \"\n\t\t\"  simd_strength = i1.totalOfNeighborStrengths(p1.individuals[0]); \"\n\t\t\"  if (allClose(scalar_strength, simd_strength)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Student's T kernel: SIMD (tdist_kernel_float32) vs scalar consistency\n\tSLiMAssertScriptStop(simd_consistency_setup +\n\t\t\"  i1.setInteractionFunction('t', 5.0, 3.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  scalar_strength = i1.strength(p1.individuals[0], p1.individuals[1]); \"\n\t\t\"  simd_strength = i1.totalOfNeighborStrengths(p1.individuals[0]); \"\n\t\t\"  if (allClose(scalar_strength, simd_strength)) stop(); \"\n\t\t\"}\", __LINE__);\n\n\t// Test with multiple individuals to exercise SIMD paths (need > 8 for AVX2)\n\t// Using Normal kernel with 20 individuals at various positions\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='x'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'x', maxDistance=2.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 20); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals.x = seq(0.0, 1.9, length=20); \"  // positions 0.0, 0.1, 0.2, ..., 1.9\n\t\t\"  i1.setInteractionFunction('n', 1.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  ind0 = p1.individuals[0]; \"  // at x = 0.0\n\t\t\"  ind10 = p1.individuals[10]; \"  // at x = 1.0, distance = 1.0 from ind0\n\t\t\"  expected = exp(-1.0^2 / (2.0 * 0.5^2)); \"  // exp(-2.0) ≈ 0.1353\n\t\t\"  if (allClose(i1.strength(ind0, ind10), expected)) stop();\"\n\t\t\"}\", __LINE__);\n\n\t// Test 2D spatial case (exercises different code path)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='xy'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'xy', maxDistance=2.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 2); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals[0].x = 0.0; p1.individuals[0].y = 0.0; \"\n\t\t\"  p1.individuals[1].x = 0.3; p1.individuals[1].y = 0.4; \"  // distance = 0.5\n\t\t\"  i1.setInteractionFunction('n', 1.0, 0.5); \"\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  expected = exp(-0.5^2 / (2.0 * 0.5^2)); \"  // exp(-0.5) ≈ 0.6065\n\t\t\"  if (allClose(i1.strength(p1.individuals[0], p1.individuals[1]), expected)) stop();\"\n\t\t\"}\", __LINE__);\n\n\t// Test 2D with many individuals (exercises 2D SIMD paths)\n\tSLiMAssertScriptStop(\n\t\t\"initialize() { \"\n\t\t\"  initializeSLiMOptions(dimensionality='xy'); \"\n\t\t\"  initializeMutationRate(0); \"\n\t\t\"  initializeMutationType('m1', 0.5, 'f', 0.0); \"\n\t\t\"  initializeGenomicElementType('g1', m1, 1.0); \"\n\t\t\"  initializeGenomicElement(g1, 0, 99999); \"\n\t\t\"  initializeRecombinationRate(0); \"\n\t\t\"  initializeInteractionType('i1', 'xy', maxDistance=5.0); \"\n\t\t\"} \"\n\t\t\"1 early() { sim.addSubpop('p1', 100); } \"\n\t\t\"1 late() { \"\n\t\t\"  p1.individuals.x = runif(100, 0, 4); \"\n\t\t\"  p1.individuals.y = runif(100, 0, 4); \"\n\t\t\"  i1.setInteractionFunction('e', 1.0, 1.0); \"  // Exponential\n\t\t\"  i1.evaluate(p1); \"\n\t\t\"  ind0 = p1.individuals[0]; \"\n\t\t\"  ind1 = p1.individuals[1]; \"\n\t\t\"  dist = sqrt((ind0.x - ind1.x)^2 + (ind0.y - ind1.y)^2); \"\n\t\t\"  expected = exp(-dist); \"\n\t\t\"  actual = i1.strength(ind0, ind1); \"\n\t\t\"  if (dist > 5.0) { if (actual == 0.0) stop(); } \"  // beyond maxDistance\n\t\t\"  else { if (allClose(actual, expected)) stop(); }\"\n\t\t\"}\", __LINE__);\n}\n\n#pragma mark Spatial kernel SIMD tests (C++ level)\nvoid _RunSpatialKernelSIMDTests(void)\n{\n\t// ************************************************************************************\n\t//\n\t//\tC++ level tests for spatial kernel SIMD functions\n\t//\n\t//\tThese tests directly call the SIMD kernel functions with random input data\n\t//\tand compare against scalar reference calculations. This provides thorough\n\t//\ttesting of the SIMD implementations with ~1000 values per kernel.\n\t//\n\n\tconst int test_count = 1000;\n\tconst float tolerance = 1e-5f;\n\tfloat distances[test_count];\n\tfloat simd_results[test_count];\n\n\t// Generate random distances in range [0, 2)\n\tgsl_rng *rng = gsl_rng_alloc(gsl_rng_taus2);\n\tgsl_rng_set(rng, 12345);  // fixed seed for reproducibility\n\n\tfor (int i = 0; i < test_count; i++)\n\t\tdistances[i] = (float)(gsl_rng_uniform(rng) * 2.0);\n\n\t// ***********************************************************************************************\n\t// Test linear_kernel_float32: strength = fmax * (1 - d / max_distance)\n\t{\n\t\tfloat fmax = 5.0f, max_distance = 2.0f;\n\t\tstd::memcpy(simd_results, distances, test_count * sizeof(float));\n\t\tEidos_SIMD::linear_kernel_float32(simd_results, test_count, fmax, max_distance);\n\n\t\tfor (int i = 0; i < test_count; i++)\n\t\t{\n\t\t\tfloat expected = fmax * (1.0f - distances[i] / max_distance);\n\t\t\tif (std::abs(simd_results[i] - expected) > tolerance)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (_RunSpatialKernelSIMDTests): linear_kernel_float32 mismatch at index \" << i << \": expected \" << expected << \", got \" << simd_results[i] << EidosTerminate();\n\t\t}\n\t}\n\n\t// ***********************************************************************************************\n\t// Test exp_kernel_float32: strength = fmax * exp(-lambda * d)\n\t{\n\t\tfloat fmax = 5.0f, lambda = 2.0f;\n\t\tstd::memcpy(simd_results, distances, test_count * sizeof(float));\n\t\tEidos_SIMD::exp_kernel_float32(simd_results, test_count, fmax, lambda);\n\n\t\tfor (int i = 0; i < test_count; i++)\n\t\t{\n\t\t\tfloat expected = fmax * std::exp(-lambda * distances[i]);\n\t\t\tif (std::abs(simd_results[i] - expected) > tolerance)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (_RunSpatialKernelSIMDTests): exp_kernel_float32 mismatch at index \" << i << \": expected \" << expected << \", got \" << simd_results[i] << EidosTerminate();\n\t\t}\n\t}\n\n\t// ***********************************************************************************************\n\t// Test normal_kernel_float32: strength = fmax * exp(-d^2 / two_sigma_sq)\n\t{\n\t\tfloat fmax = 5.0f, sigma = 0.5f;\n\t\tfloat two_sigma_sq = 2.0f * sigma * sigma;\n\t\tstd::memcpy(simd_results, distances, test_count * sizeof(float));\n\t\tEidos_SIMD::normal_kernel_float32(simd_results, test_count, fmax, two_sigma_sq);\n\n\t\tfor (int i = 0; i < test_count; i++)\n\t\t{\n\t\t\tfloat d = distances[i];\n\t\t\tfloat expected = fmax * std::exp(-(d * d) / two_sigma_sq);\n\t\t\tif (std::abs(simd_results[i] - expected) > tolerance)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (_RunSpatialKernelSIMDTests): normal_kernel_float32 mismatch at index \" << i << \": expected \" << expected << \", got \" << simd_results[i] << EidosTerminate();\n\t\t}\n\t}\n\n\t// ***********************************************************************************************\n\t// Test cauchy_kernel_float32: strength = fmax / (1 + (d/lambda)^2)\n\t{\n\t\tfloat fmax = 5.0f, lambda = 0.5f;\n\t\tstd::memcpy(simd_results, distances, test_count * sizeof(float));\n\t\tEidos_SIMD::cauchy_kernel_float32(simd_results, test_count, fmax, lambda);\n\n\t\tfor (int i = 0; i < test_count; i++)\n\t\t{\n\t\t\tfloat d_over_lambda = distances[i] / lambda;\n\t\t\tfloat expected = fmax / (1.0f + d_over_lambda * d_over_lambda);\n\t\t\tif (std::abs(simd_results[i] - expected) > tolerance)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (_RunSpatialKernelSIMDTests): cauchy_kernel_float32 mismatch at index \" << i << \": expected \" << expected << \", got \" << simd_results[i] << EidosTerminate();\n\t\t}\n\t}\n\n\t// ***********************************************************************************************\n\t// Test tdist_kernel_float32: strength = fmax * pow(1 + (d/tau)^2 / nu, -(nu+1)/2)\n\t{\n\t\tfloat fmax = 5.0f, nu = 3.0f, tau = 0.5f;\n\t\tstd::memcpy(simd_results, distances, test_count * sizeof(float));\n\t\tEidos_SIMD::tdist_kernel_float32(simd_results, test_count, fmax, nu, tau);\n\n\t\tfor (int i = 0; i < test_count; i++)\n\t\t{\n\t\t\tfloat d_over_tau = distances[i] / tau;\n\t\t\tfloat base = 1.0f + d_over_tau * d_over_tau / nu;\n\t\t\tfloat exponent = -(nu + 1.0f) / 2.0f;\n\t\t\tfloat expected = fmax * std::pow(base, exponent);\n\t\t\tif (std::abs(simd_results[i] - expected) > tolerance)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (_RunSpatialKernelSIMDTests): tdist_kernel_float32 mismatch at index \" << i << \": expected \" << expected << \", got \" << simd_results[i] << EidosTerminate();\n\t\t}\n\t}\n\n\tgsl_rng_free(rng);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/slim_test_parallel.h",
    "content": "R\"V0G0N(\n\n\n// This file is actually SLiM code!  It is run by _RunParallelSLiMTests() in slim_test.cpp.\n// The purpose of it is to test SLiM code when run in parallel against the same code run\n// single-threaded, to ensure that parallelization preserves results (to the extent possible).  The\n// reason to make this a separate file is mostly because otherwise Xcode's indenting algorithm gets\n// very confused.  Note this whole thing is one big C++ string literal.\n\n// Note that this test file gets subdivided and run in chunks; this improves error reporting.  See\n// _RunParallelSLiMTests() in slim_test.cpp.\n\n// ***********************************************************************************************\n\n// basic test, doesn't check anything, should always work\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n100 late() {\n}\n\n// ***********************************************************************************************\n\n// InteractionType -clippedIntegral() (1D x)\t\t\t\t// EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n\tinitializeInteractionType(1, \"x\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.clippedIntegral(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.clippedIntegral(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -clippedIntegral() (1D x) failed test\");\n}\n\n// ***********************************************************************************************\n\n// test InteractionType -clippedIntegral() (2D xy)\t\t\t// EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.clippedIntegral(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.clippedIntegral(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -clippedIntegral() (2D xy) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Haplosome -containsMarkerMutation()\t\t\t\t\t\t// EIDOS_OMPMIN_CONTAINS_MARKER_MUT\n\ninitialize() {\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);       // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.0, 0.2);  // QTLs\n\tm2.convertToSubstitution = F;\n\tinitializeGenomicElementType(\"g1\", c(m1, m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 9999999);\n\tinitializeRecombinationRate(1e-6);\n}\nmutationEffect(m2) { return 1.0; }\n1 early() { sim.addSubpop(\"p1\", 100); }\n199 late() {\n\tsim.chromosomes.setMutationRate(0.0);\n\tsim.chromosomes.setRecombinationRate(0.0);\n\tp1.setCloningRate(1.0);\n\tp1.setSubpopulationSize(100000);\n\t\n\t// choose a mutation near 0.5 frequency to search for\n\tmuts = sim.mutations;\n\tfreqs = sim.mutationFrequencies(NULL);\n\td_05 = abs(0.5 - freqs);\n\ti = whichMin(d_05);\n\tdefineGlobal(\"MUT\", muts[i]);\n}\n200 late() {\n haplosomes = sim.subpopulations.haplosomes;\n\n\ta = haplosomes.containsMarkerMutation(MUT.mutationType, MUT.position, returnMutation=F);\n\tparallelSetNumThreads(1);\n\tb = haplosomes.containsMarkerMutation(MUT.mutationType, MUT.position, returnMutation=F);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Haplosome -containsMarkerMutation() failed test\");\n}\n\n// ***********************************************************************************************\n\n// Haplosome -countOfMutationsOfType()\t\t\t\t\t// EIDOS_OMPMIN_G_COUNT_OF_MUTS_OF_TYPE\n\ninitialize() {\n\tinitializeMutationRate(1e-3);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.1, 0.5);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\ta = p1.individuals.haplosomes.countOfMutationsOfType(m2);\n\tparallelSetNumThreads(1);\n\tc = p1.individuals.haplosomes.countOfMutationsOfType(m2);\n\t\n\tif (!identical(a, c))\n\t\tstop(\"parallel Haplosome -countOfMutationsOfType() failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -countOfMutationsOfType()\t\t\t\t\t// EIDOS_OMPMIN_I_COUNT_OF_MUTS_OF_TYPE\n\ninitialize() {\n\tinitializeMutationRate(1e-3);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.1, 0.5);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\ta = p1.individuals.countOfMutationsOfType(m2);\n\tparallelSetNumThreads(1);\n\tc = p1.individuals.countOfMutationsOfType(m2);\n\t\n\tif (!identical(a, c))\n\t\tstop(\"parallel Individual -countOfMutationsOfType() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -drawByStrength()\t\t\t\t\t\t// EIDOS_OMPMIN_DRAWBYSTRENGTH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"f\", 1.0);\t\t\t// fixed interaction strength special case\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.drawByStrength(inds, returnDict=T);\n\tparallelSetNumThreads(1);\n\tb = i1.drawByStrength(inds, returnDict=T);\n\t\n\t// this test is stochastic, so we don't have a good way to test that it worked,\n\t// but at least we exercise the code path when running in parallel...\n}\n\n// ***********************************************************************************************\n\n// InteractionType -drawByStrength()\t\t\t\t\t\t// EIDOS_OMPMIN_DRAWBYSTRENGTH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\t\t// general case\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.drawByStrength(inds, returnDict=T);\n\tparallelSetNumThreads(1);\n\tb = i1.drawByStrength(inds, returnDict=T);\n\t\n\t// this test is stochastic, so we don't have a good way to test that it worked,\n\t// but at least we exercise the code path when running in parallel...\n}\n\n// ***********************************************************************************************\n\n// Species -individualsWithPedigreeIDs()\t\t\t\t\t// EIDOS_OMPMIN_INDS_W_PEDIGREE_IDS\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T);\n}\n1 early() { sim.addSubpop(\"p1\", 100000); }\n1 late() {\n\tinds = p1.individuals;\n\tpids = inds.pedigreeID;\n\tlookup = sample(pids, 100000, replace=T);\n\t\n\ta = sim.individualsWithPedigreeIDs(lookup);\n\tparallelSetNumThreads(1);\n\tb = sim.individualsWithPedigreeIDs(lookup);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Species -individualsWithPedigreeIDs() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -interactingNeighborCount()\t\t\t\t// EIDOS_OMPMIN_INTNEIGHCOUNT\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.interactingNeighborCount(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.interactingNeighborCount(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -interactingNeighborCount() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -localPopulationDensity()\t\t\t\t// EIDOS_OMPMIN_LOCALPOPDENSITY\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.localPopulationDensity(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.localPopulationDensity(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -localPopulationDensity() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestInteractingNeighbors()\t\t\t// EIDOS_OMPMIN_NEARESTINTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestInteractingNeighbors(inds, returnDict=T);\t\t// count=1 special-case\n\tparallelSetNumThreads(1);\n\tb = i1.nearestInteractingNeighbors(inds, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestInteractingNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestInteractingNeighbors()\t\t\t// EIDOS_OMPMIN_NEARESTINTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestInteractingNeighbors(inds, count=2, returnDict=T);\t// avoid the count=1 and count=N special-cases\n\tparallelSetNumThreads(1);\n\tb = i1.nearestInteractingNeighbors(inds, count=2, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestInteractingNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestInteractingNeighbors()\t\t\t// EIDOS_OMPMIN_NEARESTINTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestInteractingNeighbors(inds, count=1000, returnDict=T);\t// count=N special-case\n\tparallelSetNumThreads(1);\n\tb = i1.nearestInteractingNeighbors(inds, count=1000, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestInteractingNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestNeighbors()\t\t\t\t\t\t// EIDOS_OMPMIN_NEARESTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestNeighbors(inds, returnDict=T);\t\t// count=1 special-case\n\tparallelSetNumThreads(1);\n\tb = i1.nearestNeighbors(inds, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestNeighbors()\t\t\t\t\t\t// EIDOS_OMPMIN_NEARESTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestNeighbors(inds, count=2, returnDict=T);\t// avoid the count=1 and count=N special-cases\n\tparallelSetNumThreads(1);\n\tb = i1.nearestNeighbors(inds, count=2, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -nearestNeighbors()\t\t\t\t\t\t// EIDOS_OMPMIN_NEARESTNEIGH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.nearestNeighbors(inds, count=1000, returnDict=T);\t// count=N special-cases\n\tparallelSetNumThreads(1);\n\tb = i1.nearestNeighbors(inds, count=1000, returnDict=T);\n\t\n\tif (!a.identicalContents(b))\n\t\tstop(\"parallel InteractionType -nearestNeighbors() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -neighborCount()\t\t\t\t\t\t\t// EIDOS_OMPMIN_NEIGHCOUNT\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.neighborCount(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.neighborCount(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -neighborCount() failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointInBounds()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_IN_BOUNDS_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 100));\n\tpoints = runif(10000000 * 1, min=-20, max=120);\n\t\n\ta = p1.pointInBounds(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointInBounds(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointInBounds() (1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointInBounds()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_IN_BOUNDS_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tpoints = runif(10000000 * 2, min=-20, max=120);\n\t\n\ta = p1.pointInBounds(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointInBounds(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointInBounds() (2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointInBounds()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_IN_BOUNDS_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\tpoints = runif(10000000 * 3, min=-20, max=120);\n\t\n\ta = p1.pointInBounds(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointInBounds(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointInBounds() (3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointPeriodic()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_PERIODIC_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\", periodicity=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(0, 100));\n\tpoints = runif(10000000 * 1, min=-20, max=120);\n\t\n\ta = p1.pointPeriodic(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointPeriodic(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointPeriodic() (1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointPeriodic()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_PERIODIC_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\", periodicity=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(0, 0, 100, 100));\n\tpoints = runif(10000000 * 2, min=-20, max=120);\n\t\n\ta = p1.pointPeriodic(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointPeriodic(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointPeriodic() (2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointPeriodic()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_PERIODIC_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\", periodicity=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(0, 0, 0, 100, 100, 100));\n\tpoints = runif(10000000 * 3, min=-20, max=120);\n\t\n\ta = p1.pointPeriodic(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointPeriodic(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointPeriodic() (3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointReflected()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_REFLECTED_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 100));\n\tpoints = runif(10000000 * 1, min=-20, max=120);\n\t\n\ta = p1.pointReflected(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointReflected(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointReflected() (1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointReflected()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_REFLECTED_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tpoints = runif(10000000 * 2, min=-20, max=120);\n\t\n\ta = p1.pointReflected(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointReflected(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointReflected() (2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointReflected()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_REFLECTED_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\tpoints = runif(10000000 * 3, min=-20, max=120);\n\t\n\ta = p1.pointReflected(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointReflected(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointReflected() (3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointStopped()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_STOPPED_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 100));\n\tpoints = runif(10000000 * 1, min=-20, max=120);\n\t\n\ta = p1.pointStopped(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointStopped(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointStopped() (1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointStopped()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_STOPPED_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tpoints = runif(10000000 * 2, min=-20, max=120);\n\t\n\ta = p1.pointStopped(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointStopped(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointStopped() (2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointStopped()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_STOPPED_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\tpoints = runif(10000000 * 3, min=-20, max=120);\n\t\n\ta = p1.pointStopped(points);\n\tparallelSetNumThreads(1);\n\tb = p1.pointStopped(points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -pointStopped() (3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointUniform()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_UNIFORM_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 100));\n\t\n\ta = p1.pointUniform(10000000);\n\tparallelSetNumThreads(1);\n\tb = p1.pointUniform(10000000);\n\t\n\tif (abs(mean(a) - mean(b)) > 0.1)\n\t\tstop(\"parallel Subpopulation -pointUniform() (1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointUniform()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_UNIFORM_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\t\n\ta = p1.pointUniform(10000000);\n\tparallelSetNumThreads(1);\n\tb = p1.pointUniform(10000000);\n\t\n\tif (abs(mean(a) - mean(b)) > 0.1)\n\t\tstop(\"parallel Subpopulation -pointUniform() (2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -pointUniform()\t\t\t\t\t\t\t// EIDOS_OMPMIN_POINT_UNIFORM_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\t\n\ta = p1.pointUniform(10000000);\n\tparallelSetNumThreads(1);\n\tb = p1.pointUniform(10000000);\n\t\n\tif (abs(mean(a) - mean(b)) > 0.1)\n\t\tstop(\"parallel Subpopulation -pointUniform() (3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -relatedness()\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_RELATEDNESS\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n19 late() { p1.setSubpopulationSize(100000); }\n20 late() {\n\tinds = p1.individuals;\n\tfocalInd = inds[0];\n\t\n\ta = focalInd.relatedness(inds);\n\tparallelSetNumThreads(1);\n\tb = focalInd.relatedness(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -relatedness() failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -sampleIndividuals(replace=T)\t\t\t\t// EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_1\n\ninitialize() {\n}\n1 early() { sim.addSubpop(\"p1\", 100000); }\n1 late() {\n\ta = p1.sampleIndividuals(100000, replace=T);\n\tparallelSetNumThreads(1);\n\tb = p1.sampleIndividuals(100000, replace=T);\n\t\n\t// this test is stochastic, so we don't have a good way to test that it worked,\n\t// but at least we exercise the code path when running in parallel...\n\tif (size(a) != size(b))\n\t\tstop(\"parallel sampleIndividuals() 1 failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -sampleIndividuals(replace=T)\t\t\t\t// EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_2\n\ninitialize() {\n}\n1 early() { sim.addSubpop(\"p1\", 100000); }\n1 late() {\n\ta = p1.sampleIndividuals(100000, replace=T, migrant=F);\n\tparallelSetNumThreads(1);\n\tb = p1.sampleIndividuals(100000, replace=T, migrant=F);\n\t\n\t// this test is stochastic, so we don't have a good way to test that it worked,\n\t// but at least we exercise the code path when running in parallel...\n\tif (size(a) != size(b))\n\t\tstop(\"parallel sampleIndividuals() 2 failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual.fitnessScaling = float$\t\t\t\t\t\t// EIDOS_OMPMIN_SET_FITNESS_SCALE_1\n\ninitialize() {\n}\n1 early() { sim.addSubpop(\"p1\", 100000); }\n1 late() {\n\tinds = p1.individuals;\n\tinds.fitnessScaling = 1.17;\n\ta = inds.fitnessScaling;\n\tparallelSetNumThreads(1);\n\tinds.fitnessScaling = 1.0;\t\t// reset values\n\tinds.fitnessScaling = 1.17;\n\tb = inds.fitnessScaling;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel fitnessScaling = float$ failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual.fitnessScaling = float\t\t\t\t\t\t// EIDOS_OMPMIN_SET_FITNESS_SCALE_2\n\ninitialize() {\n}\n1 early() { sim.addSubpop(\"p1\", 100000); }\n1 late() {\n\tvalues = runif(100000);\n\tinds = p1.individuals;\n\tinds.fitnessScaling = values;\n\ta = inds.fitnessScaling;\n\tparallelSetNumThreads(1);\n\tinds.fitnessScaling = 1.0;\t\t// reset values\n\tinds.fitnessScaling = values;\n\tb = inds.fitnessScaling;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel fitnessScaling = float failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_1_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 100));\n\tpoint = p1.pointUniform(1);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(point);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(point);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (1 1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_1_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tpoint = p1.pointUniform(1);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(point);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(point);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (1 2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_1_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\tpoint = p1.pointUniform(1);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(point);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(point);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (1 3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_2_1D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"x\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 100));\n\tpoints = p1.pointUniform(p1.individualCount);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(points);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(points);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (2 1D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_2_2D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tpoints = p1.pointUniform(p1.individualCount);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(points);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(points);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (2 2D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -setSpatialPosition() \t\t\t\t\t\t// EIDOS_OMPMIN_SET_SPATIAL_POS_2_3D\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xyz\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 10, 100, 100, 100));\n\tpoints = p1.pointUniform(p1.individualCount);\n\tinds = p1.individuals;\n\t\n\tinds.setSpatialPosition(points);\n\ta = inds.spatialPosition;\n\tparallelSetNumThreads(1);\n\tinds.setSpatialPosition(points);\n\tb = inds.spatialPosition;\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Individual -setSpatialPosition() (2 3D) failed test\");\n}\n\n// ***********************************************************************************************\n\n// Subpopulation -spatialMapValue()\t\t\t\t\t\t\t// EIDOS_OMPMIN_SPATIAL_MAP_VALUE\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tmapValues = matrix(runif(100*100), nrow=100, ncol=100);\n\tp1.defineSpatialMap(\"map\", \"xy\", mapValues, interpolate=T);\n\tpoints = runif(10000000 * 2, min=-20, max=120);\n\t\n\ta = p1.spatialMapValue(\"map\", points);\n\tparallelSetNumThreads(1);\n\tb = p1.spatialMapValue(\"map\", points);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel Subpopulation -spatialMapValue() failed test\");\n}\n\n// ***********************************************************************************************\n\n// Individual -sumOfMutationsOfType()\t\t\t\t\t\t// EIDOS_OMPMIN_SUM_OF_MUTS_OF_TYPE\n\ninitialize() {\n\tinitializeMutationRate(1e-3);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"n\", 0.1, 0.5);\n\tinitializeGenomicElementType(\"g1\", c(m1,m2), c(1,1));\n\tinitializeGenomicElement(g1, 0, 999999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n}\n1 late() {\n\tb = p1.individuals.sumOfMutationsOfType(m2);\n\tparallelSetNumThreads(1);\n\td = p1.individuals.sumOfMutationsOfType(m2);\n\t\n\tif (!identical(b, d))\n\t\tstop(\"parallel Individual -sumOfMutationsOfType() failed test\");\n}\n\n// ***********************************************************************************************\n\n// InteractionType -totalOfNeighborStrengths()\t\t\t\t// EIDOS_OMPMIN_TOTNEIGHSTRENGTH\n\ninitialize() {\n\tinitializeSLiMOptions(dimensionality=\"xy\");\n\tinitializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=0.15);\n\ti1.setInteractionFunction(\"n\", 1.0, 0.05);\n}\n1 late() {\n\tsim.addSubpop(\"p1\", 1000000);\n\tp1.setSpatialBounds(c(10, 10, 100, 100));\n\tinds = p1.individuals;\n\tinds.setSpatialPosition(p1.pointUniform(p1.individualCount));\n\ti1.evaluate(p1);\n\t\n\ta = i1.totalOfNeighborStrengths(inds);\n\tparallelSetNumThreads(1);\n\tb = i1.totalOfNeighborStrengths(inds);\n\t\n\tif (!identical(a, b))\n\t\tstop(\"parallel InteractionType -totalOfNeighborStrengths() failed test\");\n}\n\n)V0G0N\"\n"
  },
  {
    "path": "core/sparse_vector.cpp",
    "content": "//\n//  sparse_vector.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 4/14/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"sparse_vector.h\"\n\n#include <ostream>\n#include <cmath>\n#include <string.h>\n\n#pragma mark -\n#pragma mark SparseVector\n#pragma mark -\n\nSparseVector::SparseVector(unsigned int p_ncols)\n{\n\tif (p_ncols == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::SparseVector): zero-size sparse vector.\" << EidosTerminate(nullptr);\n\t\n\tncols_ = p_ncols;\n\tnnz_ = 0;\n\tnnz_capacity_ = 1024;\n\tfinished_ = false;\n\tvalue_type_ = SparseVectorDataType::kNoData;\n\t\n\tcolumns_ = (uint32_t *)malloc(nnz_capacity_ * sizeof(uint32_t));\n\tvalues_ = (sv_value_t *)malloc(nnz_capacity_ * sizeof(sv_value_t));\n\t\n\tif (!columns_ || !values_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::SparseVector): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tResizeToFitMaxNNZ(ncols_);\n}\n\nSparseVector::~SparseVector(void)\n{\n\tncols_ = 0;\n\tnnz_ = 0;\n\tnnz_capacity_ = 0;\n\tfinished_ = false;\n\tvalue_type_ = SparseVectorDataType::kNoData;\n\t\n\tfree(columns_);\n\tcolumns_ = nullptr;\n\t\n\tfree(values_);\n\tvalues_ = nullptr;\n}\n\nvoid SparseVector::ResizeToFitMaxNNZ(uint32_t max_nnz)\n{\n\t// The design of SparseVector is that it always knows up front the maximum number of entries that can be added; it is\n\t// always the number of columns specified to its constructor or to Reset().  This method resizes the vector proactively\n\t// to make room for that maximum number of entries.  This allows us to add new entries without checking capacity.  For\n\t// models with a million individuals, this will cause our capacity to grow to a million entries, but that is trivial.\n\tif (max_nnz > nnz_capacity_)\n\t{\n\t\tdo\n\t\t\tnnz_capacity_ <<= 1;\n\t\twhile (max_nnz > nnz_capacity_);\n\t\t\n\t\tcolumns_ = (uint32_t *)realloc(columns_, nnz_capacity_ * sizeof(uint32_t));\n\t\tvalues_ = (sv_value_t *)realloc(values_, nnz_capacity_ * sizeof(sv_value_t));\n\t\t\n\t\tif (!columns_ || !values_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::ResizeToFitMaxNNZ): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t}\n}\n\nsize_t SparseVector::MemoryUsage(void)\n{\n\treturn (sizeof(uint32_t) + sizeof(sv_value_t)) * (nnz_capacity_);\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const SparseVector &p_vector)\n{\n\tp_outstream << \"SparseVector: \" << p_vector.ncols_ << \" columns\";\n\tif (!p_vector.finished_)\n\t\tp_outstream << \" (NOT FINISHED)\" << std::endl;\n\tp_outstream << std::endl;\n\t\n\tp_outstream << \"   ncols == \" << p_vector.ncols_ << std::endl;\n\tp_outstream << \"   nnz == \" << p_vector.nnz_ << std::endl;\n\tp_outstream << \"   nnz_capacity == \" << p_vector.nnz_capacity_ << std::endl;\n\t\n\tp_outstream << \"   columns == {\";\n\tfor (uint32_t nzi = 0; nzi < p_vector.nnz_; ++nzi)\n\t{\n\t\tif (nzi > 0)\n\t\t\tp_outstream << \", \";\n\t\tp_outstream << p_vector.columns_[nzi];\n\t}\n\tp_outstream << \"}\" << std::endl;\n\t\n\tp_outstream << \"   \";\n\t\n\tif (p_vector.value_type_ == SparseVectorDataType::kPresences)\t\t\tp_outstream << \"presences\";\n\telse if (p_vector.value_type_ == SparseVectorDataType::kDistances)\t\tp_outstream << \"distances\";\n\telse if (p_vector.value_type_ == SparseVectorDataType::kStrengths)\t\tp_outstream << \"strengths\";\n\telse\n\t{\n\t\tp_outstream << \"unknown values\" << std::endl;\n\t\treturn p_outstream;\n\t}\n\t\n\tp_outstream << \" == {\";\n\tfor (uint32_t nzi = 0; nzi < p_vector.nnz_; ++nzi)\n\t{\n\t\tif (nzi > 0)\n\t\t\tp_outstream << \", \";\n\t\tp_outstream << p_vector.values_[nzi];\n\t}\n\tp_outstream << \"}\" << std::endl;\n\t\n\treturn p_outstream;\n}\n"
  },
  {
    "path": "core/sparse_vector.h",
    "content": "//\n//  sparse_vector.h\n//  SLiM\n//\n//  Created by Ben Haller on 4/14/2022.\n//  Copyright (c) 2022-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef sparse_vector_h\n#define sparse_vector_h\n\n\n#include \"slim_globals.h\"\n\n#include <vector>\n\n\n/*\n This class provides a sparse vector of distance/strength pairs, for use by the InteractionType code.  Each sparse vector entry\n contains an interaction distance and strength, kept in separate buffers internally.  If a given interaction is not contained\n by the sparse vector (because it is beyond the maximum interaction distance), a distance of INFINITY will be returned, with a\n strength of 0.  A sparse vector contains all of the interaction values *felt* by a given individual (the \"receiver\"); each column\n represents the interactions *exerted* by particular individuals (the \"exerters\").  This way one can quickly read all of the\n interaction strengths felt by a focal receiver individual, which is the typical use case.\n */\n\n// This is the type used to store distances and strengths in SparseVector.  It is defined as float, in order both to cut\n// down on memory usage, and to maybe increase speed due to vectorization and less bytes going to/from memory.  These typedefs\n// can be changed to double if float's precision is problematic; everything should just work, although that is not tested.\ntypedef float sv_value_t;\n\n// This enum designates the type of value being stored by SparseVector.  It is used for consistency checking in DEBUG builds.\ntypedef enum {\n\tkNoData = 0,\n\tkPresences,\n\tkDistances,\n\tkStrengths\n} SparseVectorDataType;\n\nclass SparseVector\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\t// note that we do not sort by column within the row; we do a linear search for the column\n\t// usually we do not need to identify a particular column, we just want to look at all the values\n\tsv_value_t *values_;\t\t\t\t// a distance or strength value for each non-empty entry\n\tuint32_t *columns_;\t\t\t\t\t// the column indices for the non-empty values in each row\n\tSparseVectorDataType value_type_;\t// what kind of values we're storing\n\t\n\tuint32_t ncols_;\t\t\t\t\t// the number of columns; determined at construction time\n\tuint32_t nnz_;\t\t\t\t\t\t// the number of non-zero entries in the sparse vector\n\tuint32_t nnz_capacity_;\t\t\t\t// the number of non-zero entries allocated for at present\n\t\n\tbool finished_;\t\t\t\t\t\t// if true, Finished() has been called and the vector is ready to use\n\t\n\tvoid ResizeToFitMaxNNZ(uint32_t max_nnz);\n\t\npublic:\n\tSparseVector(const SparseVector&) = delete;\t\t\t\t\t// no copying\n\tSparseVector& operator=(const SparseVector&) = delete;\t\t// no copying\n\tSparseVector(void) = delete;\t\t\t\t\t\t\t\t// no null construction\n\tSparseVector(unsigned int p_ncols);\n\t~SparseVector(void);\n\t\n\tvoid Reset(unsigned int p_ncols, SparseVectorDataType data_type);\t\t// reset to new dimensions\n\t\n\t// Building a sparse vector has to be done in column order, one entry at a time, and then has to be Finished().\n\t// You can supply either distances or strengths; SparseVector does not store both simultaneously.  You should\n\t// declare in advance which type of value you intend to store; this is checked when building DEBUG.\n\tvoid AddEntryPresence(const uint32_t p_column);\n\tvoid AddEntryDistance(const uint32_t p_column, sv_value_t p_distance);\n\tvoid AddEntryStrength(const uint32_t p_column, sv_value_t p_strength);\n\tvoid Finished(void);\n\t\n\tinline __attribute__((always_inline)) bool IsFinished() const\t\t\t\t\t\t{ return finished_; };\n\tinline __attribute__((always_inline)) uint32_t ColumnCount() const\t\t\t\t\t{ return ncols_; };\n\t\n\tinline __attribute__((always_inline)) SparseVectorDataType DataType(void) const\t\t{ return value_type_; }\n\tinline __attribute__((always_inline)) void SetDataType(SparseVectorDataType type)\t{ value_type_ = type; }\n\t\n\t// Access to the sparse vector's data\n\tvoid Presences(uint32_t *p_nnz) const;\n\tvoid Presences(uint32_t *p_nnz, const uint32_t **p_columns) const;\n\t\n\tconst sv_value_t *Distances(uint32_t *p_nnz) const;\n\tconst sv_value_t *Distances(uint32_t *p_nnz, const uint32_t **p_columns) const;\n\tvoid Distances(uint32_t *p_nnz, uint32_t **p_columns, sv_value_t **p_distances);\t// non-const\n\t\n\tconst sv_value_t *Strengths(uint32_t *p_nnz) const;\n\tconst sv_value_t *Strengths(uint32_t *p_nnz, const uint32_t **p_columns) const;\n\tvoid Strengths(uint32_t *p_nnz, uint32_t **p_columns, sv_value_t **p_strengths);\t// non-const\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsage(void);\n\t\n\tfriend std::ostream &operator<<(std::ostream &p_outstream, const SparseVector &p_vector);\n};\n\ninline void SparseVector::Reset(unsigned int p_ncols, SparseVectorDataType data_type)\n{\n#if DEBUG\n\tif (p_ncols == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Reset): zero-size sparse vector.\" << EidosTerminate(nullptr);\n#endif\n\t\n\tncols_ = p_ncols;\n\tnnz_ = 0;\n\tfinished_ = false;\n\tvalue_type_ = data_type;\n\tResizeToFitMaxNNZ(ncols_);\n}\n\ninline void SparseVector::AddEntryPresence(const uint32_t p_column)\n{\n#if DEBUG\n\tif (finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryPresence): adding entry to sparse vector that is finished.\" << EidosTerminate(nullptr);\n\tif (p_column >= ncols_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryPresence): adding column beyond the end of the sparse vector.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kPresences)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryPresence): sparse vector is not specialized for presences.\" << EidosTerminate(nullptr);\n\tif (nnz_ >= nnz_capacity_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryPresence): insufficient capacity allocated.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// insert the new entry\n\tcolumns_[nnz_] = p_column;\n\tnnz_++;\n}\n\ninline void SparseVector::AddEntryDistance(const uint32_t p_column, sv_value_t p_distance)\n{\n#if DEBUG\n\tif (finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryDistance): adding entry to sparse vector that is finished.\" << EidosTerminate(nullptr);\n\tif (p_column >= ncols_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryDistance): adding column beyond the end of the sparse vector.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryDistance): sparse vector is not specialized for distances.\" << EidosTerminate(nullptr);\n\tif (nnz_ >= nnz_capacity_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryDistance): insufficient capacity allocated.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// insert the new entry\n\tcolumns_[nnz_] = p_column;\n\tvalues_[nnz_] = p_distance;\n\tnnz_++;\n}\n\ninline void SparseVector::AddEntryStrength(const uint32_t p_column, sv_value_t p_strength)\n{\n#if DEBUG\n\tif (finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryStrength): adding entry to sparse vector that is finished.\" << EidosTerminate(nullptr);\n\tif (p_column >= ncols_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryStrength): adding column beyond the end of the sparse vector.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kStrengths)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryStrength): sparse vector is not specialized for strengths.\" << EidosTerminate(nullptr);\n\tif (nnz_ >= nnz_capacity_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::AddEntryStrength): insufficient capacity allocated.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// insert the new entry\n\tcolumns_[nnz_] = p_column;\n\tvalues_[nnz_] = p_strength;\n\tnnz_++;\n}\n\ninline __attribute__((always_inline)) void SparseVector::Finished(void)\n{\n#if DEBUG\n\tif (finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Finished): finishing sparse vector that is already finished.\" << EidosTerminate(nullptr);\n#endif\n\t\n\tif (value_type_ == SparseVectorDataType::kNoData)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Finished): sparse vector was never specialized to presences, distances, or strengths.\" << EidosTerminate(nullptr);\n\t\n\tfinished_ = true;\n}\n\ninline void SparseVector::Presences(uint32_t *p_nnz) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Presences): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kPresences)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Presences): sparse vector is not specialized for presences.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n}\n\ninline void SparseVector::Presences(uint32_t *p_nnz, const uint32_t **p_columns) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Presences): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kPresences)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Presences): sparse vector is not specialized for presences.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\t*p_columns = columns_;\n}\n\ninline const sv_value_t *SparseVector::Distances(uint32_t *p_nnz) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not specialized for distances.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\treturn values_;\n}\n\ninline const sv_value_t *SparseVector::Distances(uint32_t *p_nnz, const uint32_t **p_columns) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not specialized for distances.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\t*p_columns = columns_;\n\treturn values_;\n}\n\ninline void SparseVector::Distances(uint32_t *p_nnz, uint32_t **p_columns, sv_value_t **p_distances)\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kDistances)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Distances): sparse vector is not specialized for distances.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\t*p_columns = columns_;\n\t*p_distances = values_;\n}\n\ninline const sv_value_t *SparseVector::Strengths(uint32_t *p_nnz) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kStrengths)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not specialized for strengths.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\treturn values_;\n}\n\ninline const sv_value_t *SparseVector::Strengths(uint32_t *p_nnz, const uint32_t **p_columns) const\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kStrengths)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not specialized for strengths.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\t*p_columns = columns_;\n\treturn values_;\n}\n\ninline void SparseVector::Strengths(uint32_t *p_nnz, uint32_t **p_columns, sv_value_t **p_strengths)\n{\n#if DEBUG\n\t// should be done building the vector\n\tif (!finished_)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not finished being built.\" << EidosTerminate(nullptr);\n\tif (value_type_ != SparseVectorDataType::kStrengths)\n\t\tEIDOS_TERMINATION << \"ERROR (SparseVector::Strengths): sparse vector is not specialized for strengths.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// return info; note that a non-null pointer is returned even if count==0\n\t*p_nnz = (uint32_t)nnz_;\t// cast should be safe, the number of entries is 32-bit\n\t*p_columns = columns_;\n\t*p_strengths = values_;\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const SparseVector &p_vector);\n\n\n#endif /* sparse_vector_h */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/spatial_kernel.cpp",
    "content": "//\n//  spatial_kernel.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 9/9/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"spatial_kernel.h\"\n#include \"eidos_value.h\"\n#include \"eidos_rng.h\"\n\n#include <string>\n#include <algorithm>\n\n\n// stream output for enumerations\nstd::ostream& operator<<(std::ostream& p_out, SpatialKernelType p_kernel_type)\n{\n\tswitch (p_kernel_type)\n\t{\n\t\tcase SpatialKernelType::kFixed:\t\t\tp_out << gStr_f;\t\tbreak;\n\t\tcase SpatialKernelType::kLinear:\t\tp_out << gStr_l;\t\tbreak;\n\t\tcase SpatialKernelType::kExponential:\tp_out << gStr_e;\t\tbreak;\n\t\tcase SpatialKernelType::kNormal:\t\tp_out << gEidosStr_n;\tbreak;\n\t\tcase SpatialKernelType::kCauchy:\t\tp_out << gEidosStr_c;\tbreak;\n\t\tcase SpatialKernelType::kStudentsT:\t\tp_out << gEidosStr_t;\tbreak;\n\t}\n\t\n\treturn p_out;\n}\n\n\n#pragma mark -\n#pragma mark SpatialKernel\n#pragma mark -\n\nint SpatialKernel::PreprocessArguments(int p_dimensionality, double p_maxDistance, const std::vector<EidosValue_SP> &p_arguments, int p_first_kernel_arg, bool p_expect_max_density, SpatialKernelType *p_kernel_type, int *p_k_param_count)\n{\n\t// This method pre-processes the kernel definition arguments, counting how many kernels are being defined,\n\t// and doing shared checks across all of the kernels being defined to save cycles in defining each one\n\tif ((p_dimensionality < 0) || (p_dimensionality > 3))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel dimensionality must be 0, 1, 2, or 3.\" << EidosTerminate();\n\tif (p_maxDistance <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel maxDistance must be greater than zero.\" << EidosTerminate();\n\t\n\t// Parse the arguments that define our kernel shape\n\tif (p_arguments[p_first_kernel_arg]->Type() != EidosValueType::kValueString)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): (internal error) functionType is not a string.\" << EidosTerminate();\n\t\n\tEidosValue_String *functionType_value = (EidosValue_String *)p_arguments[p_first_kernel_arg].get();\n\t\n\tif (functionType_value->Count() != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): (internal error) functionType must be a singleton string.\" << EidosTerminate();\n\t\n\tconst std::string &k_type_string = functionType_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tSpatialKernelType k_type;\n\tint expected_k_param_count = 0;\n\t\n\tif (k_type_string.compare(gStr_f) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kFixed;\n\t\texpected_k_param_count = (p_expect_max_density ? 1 : 0);\n\t\t\n\t\t// BCH 9/26/2023: Adding this restriction because it is required for the DrawDisplacement_SX() methods.\n\t\t// It makes sense – a kernel that doesn't fall off with distance at all shouldn't have infinite extent.\n\t\t// For totalOfNeighborStrengths(), for example, this would become simply a count of all interacting\n\t\t// individuals across the whole landscape - it is no longer really a spatial query at all.\n\t\tif ((p_dimensionality > 0) && std::isinf(p_maxDistance))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel type 'f' cannot be used unless a finite maximum interaction distance greater than zero has been set.\" << EidosTerminate();\n\t}\n\telse if (k_type_string.compare(gStr_l) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kLinear;\n\t\texpected_k_param_count = (p_expect_max_density ? 1 : 0);\n\t\t\n\t\tif (std::isinf(p_maxDistance))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel type 'l' cannot be used unless a finite maximum interaction distance greater than zero has been set.\" << EidosTerminate();\n\t}\n\telse if (k_type_string.compare(gStr_e) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kExponential;\n\t\texpected_k_param_count = (p_expect_max_density ? 2 : 1);\n\t}\n\telse if (k_type_string.compare(gEidosStr_n) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kNormal;\n\t\texpected_k_param_count = (p_expect_max_density ? 2 : 1);\n\t}\n\telse if (k_type_string.compare(gEidosStr_c) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kCauchy;\n\t\texpected_k_param_count = (p_expect_max_density ? 2 : 1);\n\t}\n\telse if (k_type_string.compare(gEidosStr_t) == 0)\n\t{\n\t\tk_type = SpatialKernelType::kStudentsT;\n\t\texpected_k_param_count = (p_expect_max_density ? 3 : 2);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel functionType '\" << k_type_string << \"' must be 'f', 'l', 'e', 'n', 'c', or 't'.\" << EidosTerminate();\n\t\n\tif ((p_dimensionality == 0) && (k_type != SpatialKernelType::kFixed))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel functionType 'f' is required for non-spatial interactions.\" << EidosTerminate();\n\t\n\tif ((int)p_arguments.size() - p_first_kernel_arg != 1 + expected_k_param_count)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): spatial kernel functionType '\" << k_type << \"' requires exactly \" << expected_k_param_count << \" kernel configuration parameter\" << (expected_k_param_count == 1 ? \"\" : \"s\") << \".\" << EidosTerminate();\n\t\n\t// This is the crux of this method: determining how many kernels the user is requesting that we should construct.\n\tint kernel_count = 1;\n\t\n\tfor (int k_param_index = 0; k_param_index < expected_k_param_count; ++k_param_index)\n\t{\n\t\tEidosValue *k_param_value = p_arguments[1 + k_param_index + p_first_kernel_arg].get();\n\t\tEidosValueType k_param_type = k_param_value->Type();\n\t\t\n\t\tif ((k_param_type != EidosValueType::kValueFloat) && (k_param_type != EidosValueType::kValueInt))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): the parameters for this spatial kernel type must be numeric (integer or float).\" << EidosTerminate();\n\t\t\n\t\tint k_param_count = k_param_value->Count();\n\t\t\n\t\tif (k_param_count != 1)\n\t\t{\n\t\t\tif (kernel_count == 1)\n\t\t\t{\n\t\t\t\t// the first time we see a non-1 value, we accept it as defining the kernel count\n\t\t\t\tkernel_count = k_param_count;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// subsequent times, it must match the kernel count we already inferred\n\t\t\t\tif (k_param_count != kernel_count)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::PreprocessArguments): an inconsistent number of kernels is defined; all kernel definition parameters must either be singleton, or have the same non-singleton count.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// OK, we're accepting this kernel definition; keep track of what we're doing\n\t// these values will get passed back in to the SpatialKernel constructor,\n\t// but we only need to figure them out once\n\t*p_kernel_type = k_type;\n\t*p_k_param_count = expected_k_param_count;\n\t\n\treturn kernel_count;\n}\n\nSpatialKernel::SpatialKernel(int p_dimensionality, double p_maxDistance, const std::vector<EidosValue_SP> &p_arguments, int p_first_kernel_arg, int p_kernel_arg_index, bool p_expect_max_density, SpatialKernelType p_kernel_type, int p_k_param_count) : dimensionality_(p_dimensionality), max_distance_(p_maxDistance), kernel_type_(p_kernel_type)\n{\n\t// This constructs a kernel from the arguments given, beginning at argument p_first_kernel_arg.\n\t// For example, take the smooth() method of SpatialKernel:\n\t//\n\t//\t- (void)smooth(float$ maxDistance, string$ functionType, ...)\n\t//\n\t// It parses out maxDistance and passes it to us; it then forwards its remaining\n\t// arguments, with p_first_kernel_arg == 1, to define the shape of the kernel it wants.\n\t// The ellipsis arguments are patterned after setInteractionFunction(); this class is\n\t// basically a grid-sampled version of the same style of kernel that InteractionType\n\t// uses, and indeed, InteractionType now uses SpatialKernel for some of its work.\n\t// If p_expect_max_density is true, a maximum kernel density is expected and the kernel\n\t// specification is as it is for setInteractionFunction(); if p_expect_max_density is\n\t// false, the maximum kernel density is not expected, as for the smooth() method of\n\t// SpatialMap.\n\t//\n\t// The grid sampling is based upon the spatial scale established by a given SpatialMap;\n\t// the max distance and other kernel parameters are in terms of that scale.\n\t\n\t// Note that SpatialKernel::PreprocessArguments() must be called prior to calling this,\n\t// to check the correctness of the arguments and count how many kernels are being made.\n\t\n\t// Parse kernel arguments; checks are done by SpatialKernel::PreprocessArguments().\n\t// Internally, we always have a max kernel density.  If one was not expected from the arguments,\n\t// we insert a value of 1.0 for the max kernel density.\n\tstd::vector<double> k_parameters;\n\t\n\tif (!p_expect_max_density)\n\t\tk_parameters.emplace_back(1.0);\n\t\n\tfor (int k_param_index = 0; k_param_index < p_k_param_count; ++k_param_index)\n\t{\n\t\tEidosValue *k_param_value = p_arguments[1 + k_param_index + p_first_kernel_arg].get();\n\t\t\n\t\t// each parameter can be either singleton, or a vector from which we use index p_kernel_arg_index\n\t\tif (k_param_value->Count() == 1)\n\t\t\tk_parameters.emplace_back(k_param_value->NumericAtIndex_NOCAST(0, nullptr));\n\t\telse\n\t\t\tk_parameters.emplace_back(k_param_value->NumericAtIndex_NOCAST(p_kernel_arg_index, nullptr));\n\t}\n\t\n\t// Bounds-check the IF parameters in the cases where there is a hard bound\n\t// NOLINTBEGIN(*-branch-clone) : intentional consecutive branches\n\tswitch (kernel_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t\t// no limits on fixed IFs; doesn't make much sense to use 0.0, but it's not illegal\n\t\t\tbreak;\n\t\tcase SpatialKernelType::kLinear:\n\t\t\t// no limits on linear IFs; doesn't make much sense to use 0.0, but it's not illegal\n\t\t\tbreak;\n\t\tcase SpatialKernelType::kExponential:\n\t\t\t// no limits on exponential IFs; a shape of 0.0 doesn't make much sense, but it's not illegal\n\t\t\tbreak;\n\t\tcase SpatialKernelType::kNormal:\n\t\t\t// no limits on the maximum strength (although 0.0 doesn't make much sense); sd must be >= 0\n\t\t\tif (k_parameters[1] < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::SpatialKernel): spatial kernel type 'n' must have a standard deviation parameter >= 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase SpatialKernelType::kCauchy:\n\t\t\t// no limits on the maximum strength (although 0.0 doesn't make much sense); scale must be > 0\n\t\t\tif (k_parameters[1] <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::SpatialKernel): spatial kernel type 'c' must have a scale parameter > 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t\t// nu can range from -inf to +inf but must be greater than the dimensionality minus one; scale (sigma) must be >= 0\n\t\t\tif (k_parameters[1] <= p_dimensionality - 1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::SpatialKernel): spatial kernel type 't' must have a degrees of freedom parameter that is greater than the kernel dimensionality minus one.\" << EidosTerminate();\n\t\t\tif (k_parameters[2] < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::SpatialKernel): spatial kernel type 't' must have a scale parameter >= 0.\" << EidosTerminate();\n\t\t\tbreak;\n\t}\n\t// NOLINTEND(*-branch-clone)\n\t\n\t// Everything seems to be in order, so replace our kernel info with the new info\n\tkernel_param1_ = ((k_parameters.size() >= 1) ? k_parameters[0] : 0.0);\n\tkernel_param2_ = ((k_parameters.size() >= 2) ? k_parameters[1] : 0.0);\n\tkernel_param3_ = ((k_parameters.size() >= 3) ? k_parameters[2] : 0.0);\n\tn_2param2sq_ = (kernel_type_ == SpatialKernelType::kNormal) ? (2.0 * kernel_param2_ * kernel_param2_) : 0.0;\n}\n\nSpatialKernel::~SpatialKernel(void)\n{\n\tif (values_)\n\t\tfree(values_);\n}\n\nvoid SpatialKernel::CalculateGridValues(SpatialMap &p_map)\n{\n\tif ((dimensionality_ < 1) || (dimensionality_ > 3))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::CalculateGridValues): grid values can only be calculated for kernels with dimensionality of 1, 2, or 3.\" << EidosTerminate(nullptr);\n\tif ((max_distance_ <= 0.0) || (!std::isfinite(max_distance_)))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::CalculateGridValues): grid values can only be calculated for kernels with a maxDistance that is positive and finite.\" << EidosTerminate(nullptr);\n\t\n\t// Derive our spatial scale from the given spatial map, which provides a correspondence between\n\t// spatial bounds and pixel sizes; after this, we do not use the SpatialMap, so these scales\n\t// could instead be passed in.\n\tdouble spatial_size_a = (p_map.bounds_a1_ - p_map.bounds_a0_);\n\tdouble spatial_size_b = (dimensionality_ >= 2) ? (p_map.bounds_b1_ - p_map.bounds_b0_) : 0.0;\n\tdouble spatial_size_c = (dimensionality_ >= 3) ? (p_map.bounds_c1_ - p_map.bounds_c0_) : 0.0;\n\t\n\tpixels_to_spatial_a_ = (spatial_size_a / (p_map.grid_size_[0] - 1));\n\tpixels_to_spatial_b_ = (dimensionality_ >= 2) ? (spatial_size_b / (p_map.grid_size_[1] - 1)) : 0.0;\n\tpixels_to_spatial_c_ = (dimensionality_ >= 3) ? (spatial_size_c / (p_map.grid_size_[2] - 1)) : 0.0;\n\t\n\tdim[0] = 0;\n\tdim[1] = 0;\n\tdim[2] = 0;\n\t\n\tint64_t values_size = 1;\n\t\n\tdouble pixelsize_d = (max_distance_ * 2) / pixels_to_spatial_a_;\t// convert spatial to pixels\n\tint64_t pixelsize = (int64_t)ceil(pixelsize_d);\n\tif (pixelsize % 2 == 0)\t\t\t\t\t\t\t\t\t\t\t// round up to an odd integer\n\t\tpixelsize++;\n\tdim[0] = pixelsize;\n\tvalues_size *= pixelsize;\n\t\n\tif (dimensionality_ >= 2)\n\t{\n\t\tpixelsize_d = (max_distance_ * 2) / pixels_to_spatial_b_;\t// convert spatial to pixels\n\t\tpixelsize = (int64_t)ceil(pixelsize_d);\n\t\tif (pixelsize % 2 == 0)\t\t\t\t\t\t\t\t\t\t// round up to an odd integer\n\t\t\tpixelsize++;\n\t\tdim[1] = pixelsize;\n\t\tvalues_size *= pixelsize;\n\t}\n\t\n\tif (dimensionality_ >= 3)\n\t{\n\t\tpixelsize_d = (max_distance_ * 2) / pixels_to_spatial_c_;\t// convert spatial to pixels\n\t\tpixelsize = (int64_t)ceil(pixelsize_d);\n\t\tif (pixelsize % 2 == 0)\t\t\t\t\t\t\t\t\t\t// round up to an odd integer\n\t\t\tpixelsize++;\n\t\tdim[2] = pixelsize;\n\t\tvalues_size *= pixelsize;\n\t}\n\t\n\t// Allocate our values buffer\n\tvalues_ = (double *)malloc(values_size * sizeof(double));\n\t\n\tif (!values_)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::CalculateGridValues): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t// Set our values\n\tswitch (dimensionality_)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tint64_t kernel_offset_a = dim[0] / 2;\t// rounds down\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int64_t a = 0; a < dim[0]; ++a)\n\t\t\t{\n\t\t\t\tdouble distance = (a - kernel_offset_a) * pixels_to_spatial_a_;\n\t\t\t\tdouble density = (distance > max_distance_) ? 0.0 : DensityForDistance(distance);\n\t\t\t\t\n\t\t\t\tvalues_[a] = density;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tint64_t kernel_offset_a = dim[0] / 2;\t// rounds down\n\t\t\tint64_t kernel_offset_b = dim[1] / 2;\t// rounds down\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int64_t a = 0; a < dim[0]; ++a)\n\t\t\t{\n\t\t\t\tdouble dist_a = (a - kernel_offset_a) * pixels_to_spatial_a_;\n\t\t\t\tdouble dist_a_sq = dist_a * dist_a;\n\t\t\t\t\n\t\t\t\tfor (int64_t b = 0; b < dim[1]; ++b)\n\t\t\t\t{\n\t\t\t\t\tdouble dist_b = (b - kernel_offset_b) * pixels_to_spatial_b_;\n\t\t\t\t\tdouble dist_b_sq = dist_b * dist_b;\n\t\t\t\t\tdouble distance = sqrt(dist_a_sq + dist_b_sq);\n\t\t\t\t\t\n\t\t\t\t\tdouble density = (distance > max_distance_) ? 0.0 : DensityForDistance(distance);\n\t\t\t\t\t\n\t\t\t\t\tvalues_[a + b * dim[0]] = density;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tint64_t kernel_offset_a = dim[0] / 2;\t// rounds down\n\t\t\tint64_t kernel_offset_b = dim[1] / 2;\t// rounds down\n\t\t\tint64_t kernel_offset_c = dim[2] / 2;\t// rounds down\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int64_t a = 0; a < dim[0]; ++a)\n\t\t\t{\n\t\t\t\tdouble dist_a = (a - kernel_offset_a) * pixels_to_spatial_a_;\n\t\t\t\tdouble dist_a_sq = dist_a * dist_a;\n\t\t\t\t\n\t\t\t\tfor (int64_t b = 0; b < dim[1]; ++b)\n\t\t\t\t{\n\t\t\t\t\tdouble dist_b = (b - kernel_offset_b) * pixels_to_spatial_b_;\n\t\t\t\t\tdouble dist_b_sq = dist_b * dist_b;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t c = 0; c < dim[2]; ++c)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble dist_c = (c - kernel_offset_c) * pixels_to_spatial_c_;\n\t\t\t\t\t\tdouble dist_c_sq = dist_c * dist_c;\n\t\t\t\t\t\tdouble distance = sqrt(dist_a_sq + dist_b_sq + dist_c_sq);\n\t\t\t\t\t\tdouble density = (distance > max_distance_) ? 0.0 : DensityForDistance(distance);\n\t\t\t\t\t\t\n\t\t\t\t\t\tvalues_[a + b * dim[0] + c * dim[0] * dim[1]] = density;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault: break;\n\t}\n}\n\ndouble SpatialKernel::DensityForDistance(double p_distance)\n{\n\t// SEE ALSO: InteractionType::CalculateStrengthNoCallbacks(), which is parallel to this\n\tswitch (kernel_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t\treturn (kernel_param1_);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// fmax\n\t\tcase SpatialKernelType::kLinear:\n\t\t\treturn (kernel_param1_ * (1.0 - p_distance / max_distance_));\t\t\t\t\t\t\t\t\t// fmax * (1 − d/dmax)\n\t\tcase SpatialKernelType::kExponential:\n\t\t\treturn (kernel_param1_ * exp(-kernel_param2_ * p_distance));\t\t\t\t\t\t\t\t\t\t// fmax * exp(−λd)\n\t\tcase SpatialKernelType::kNormal:\n\t\t\treturn (kernel_param1_ * exp(-(p_distance * p_distance) / n_2param2sq_));\t\t\t\t\t\t// fmax * exp(−d^2/2σ^2)\n\t\tcase SpatialKernelType::kCauchy:\n\t\t{\n\t\t\tdouble temp = p_distance / kernel_param2_;\n\t\t\treturn (kernel_param1_ / (1.0 + temp * temp));\t\t\t\t\t\t\t\t\t\t\t\t\t// fmax / (1+(d/λ)^2)\n\t\t}\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t\treturn SpatialKernel::tdist(p_distance, kernel_param1_, kernel_param2_, kernel_param3_);\t\t// fmax / (1+(d/t)^2/n)^(−(ν+1)/2)\n\t}\n\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::DensityForDistance): (internal error) unexpected SpatialKernelType value.\" << EidosTerminate();\n}\n\nvoid SpatialKernel::DrawDisplacement_S1(double *displacement)\n{\n\t// Draw a displacement from the kernel center, weighted by kernel density\n\t// Note that we could be going either plus or minus from the center\n\tswitch (kernel_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t{\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tdisplacement[0] = Eidos_rng_uniform_doubleCO(rng_64) * 2 * max_distance_ - max_distance_;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kLinear:\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\t\t\t\n\t\t\tdouble d = (1 - sqrt(Eidos_rng_uniform_doubleCO(rng_64))) * max_distance_;\n\t\t\t\n\t\t\tdisplacement[0] = (Eidos_RandomBool(rng_state) ? d : -d);\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kExponential:\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\tgsl_rng *rng_gsl = &rng_state->gsl_rng_;\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td = gsl_ran_exponential(rng_gsl, 1.0 / kernel_param2_);\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = (Eidos_RandomBool(rng_state) ? d : -d);\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kNormal:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = d;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td = gsl_ran_tdist(rng_gsl, kernel_param2_) * kernel_param3_;\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = d;\n\t\t\treturn;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t// Other distributions are of unclear utility, since draws may cluster at the max distance; this is\n\t\t\t// particularly bad for the Cauchy, because the area under it out to infinity is infinite for D>1\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::DrawDisplacement_S1): kernel type not supported.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid SpatialKernel::DrawDisplacement_S2(double *displacement)\n{\n\t// Draw a displacement from the kernel center, weighted by kernel density\n\t// Note that we could be going in any direction from the center\n\tswitch (kernel_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t{\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble theta = Eidos_rng_uniform_doubleCO(rng_64) * 2 * M_PI;\n\t\t\tdouble d = sqrt(Eidos_rng_uniform_doubleCO(rng_64)) * max_distance_;\n\t\t\tdisplacement[0] = cos(theta) * d;\n\t\t\tdisplacement[1] = sin(theta) * d;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kLinear:\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\tgsl_rng *rng_gsl = &rng_state->gsl_rng_;\n\t\t\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\t\t\tdouble theta = Eidos_rng_uniform_doubleCO(rng_64) * 2 * M_PI;\n\t\t\tdouble d = gsl_ran_beta(rng_gsl, 2.0, 2.0) * max_distance_;\n\t\t\tdisplacement[0] = cos(theta) * d;\n\t\t\tdisplacement[1] = sin(theta) * d;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kExponential:\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\tgsl_rng *rng_gsl = &rng_state->gsl_rng_;\n\t\t\tEidosRNG_64_bit &rng_64 = rng_state->pcg64_rng_;\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td = gsl_ran_gamma(rng_gsl, 2.0, 1.0 / kernel_param2_);\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdouble theta = Eidos_rng_uniform_doubleCO(rng_64) * 2 * M_PI;\n\t\t\t\n\t\t\tdisplacement[0] = cos(theta) * d;\n\t\t\tdisplacement[1] = sin(theta) * d;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kNormal:\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\tdouble d1, d2;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td1 = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t\td2 = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t} while (sqrt(d1*d1 + d2*d2) > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = d1;\n\t\t\tdisplacement[1] = d2;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t{\n\t\t\t// df (nu) is kernel_param2_, scale is kernel_param3_\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\tdouble x = 0.5 + abs(Eidos_rng_uniform_doubleCO(rng_64) - 0.5);\n\t\t\t\td = sqrt(std::max(0.0, kernel_param2_ * (pow(2.0 - 2.0 * x, -2.0 / (kernel_param2_ - 1.0)) - 1.0))) * kernel_param3_;\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdouble theta = Eidos_rng_uniform_doubleCO(rng_64) * 2 * M_PI;\n\t\t\t\n\t\t\tdisplacement[0] = cos(theta) * d;\n\t\t\tdisplacement[1] = sin(theta) * d;\n\t\t\treturn;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t// Other distributions are of unclear utility, since draws may cluster at the max distance; this is\n\t\t\t// particularly bad for the Cauchy, because the area under it out to infinity is infinite for D>1\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::DrawDisplacement_S2): kernel type not supported.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid SpatialKernel::DrawDisplacement_S3(double *displacement)\n{\n\t// Draw a displacement from the kernel center, weighted by kernel density\n\t// Note that we could be going in any direction from the center\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tswitch (kernel_type_)\n\t{\n\t\tcase SpatialKernelType::kFixed:\n\t\t{\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\tdouble dx = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dy = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dz = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble sphere_dist = sqrt(dx*dx + dy*dy + dz*dz);\n\t\t\tdouble d = pow(Eidos_rng_uniform_doubleCO(rng_64), 1/3.0) * max_distance_;\n\t\t\t\n\t\t\tdisplacement[0] = dx * d / sphere_dist;\n\t\t\tdisplacement[1] = dy * d / sphere_dist;\n\t\t\tdisplacement[2] = dz * d / sphere_dist;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kLinear:\n\t\t{\n\t\t\tdouble dx = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dy = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dz = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble sphere_dist = sqrt(dx*dx + dy*dy + dz*dz);\n\t\t\tdouble d = gsl_ran_beta(rng_gsl, 3.0, 2.0) * max_distance_;\n\t\t\t\n\t\t\tdisplacement[0] = dx * d / sphere_dist;\n\t\t\tdisplacement[1] = dy * d / sphere_dist;\n\t\t\tdisplacement[2] = dz * d / sphere_dist;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kExponential:\n\t\t{\n\t\t\tdouble dx = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dy = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble dz = gsl_ran_gaussian(rng_gsl, 1.0);\n\t\t\tdouble sphere_dist = sqrt(dx*dx + dy*dy + dz*dz);\n\t\t\tdouble d;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td = gsl_ran_gamma(rng_gsl, 3.0, 1.0 / kernel_param2_);\n\t\t\t} while (d > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = dx * d / sphere_dist;\n\t\t\tdisplacement[1] = dy * d / sphere_dist;\n\t\t\tdisplacement[2] = dz * d / sphere_dist;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kNormal:\n\t\t{\n\t\t\tdouble d1, d2, d3;\n\t\t\t\n\t\t\tdo {\n\t\t\t\td1 = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t\td2 = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t\td3 = gsl_ran_gaussian(rng_gsl, kernel_param2_);\n\t\t\t} while (sqrt(d1*d1 + d2*d2 + d3*d3) > max_distance_);\n\t\t\t\n\t\t\tdisplacement[0] = d1;\n\t\t\tdisplacement[1] = d2;\n\t\t\tdisplacement[2] = d3;\n\t\t\treturn;\n\t\t}\n\t\tcase SpatialKernelType::kStudentsT:\n\t\t\t// FIXME: punting for now.  Peter says: \"That involves an integral I don't know how to do. If you really want to do it, you could always do it numerically (even, pre-compute the values - it's just a 1D integral that we understand pretty well...)\"\n\t\tdefault:\n\t\t{\n\t\t\t// Other distributions are of unclear utility, since draws may cluster at the max distance; this is\n\t\t\t// particularly bad for the Cauchy, because the area under it out to infinity is infinite for D>1\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialKernel::DrawDisplacement_S3): kernel type not supported.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nstd::ostream& operator<<(std::ostream& p_out, SpatialKernel &p_kernel)\n{\n\tstd::cout << \"Kernel with dimensionality_ == \" << p_kernel.dimensionality_ << \":\" << std::endl;\n\tstd::cout << \"   max_distance_ == \" << p_kernel.max_distance_ << std::endl;\n\tstd::cout << \"   kernel_type_ == \\\"\" << p_kernel.kernel_type_ << \"\\\"\" << std::endl;\n\tstd::cout << \"   kernel_param1_ == \" << p_kernel.kernel_param1_ << std::endl;\n\tstd::cout << \"   kernel_param2_ == \" << p_kernel.kernel_param2_ << std::endl;\n\tstd::cout << \"   n_2param2sq_ == \" << p_kernel.n_2param2sq_ << std::endl;\n\tstd::cout << \"   dim[3] == {\" << p_kernel.dim[0] << \", \" << p_kernel.dim[1] << \", \" << p_kernel.dim[2] << \"}\" << std::endl;\n\t\n\tif (p_kernel.values_)\n\t{\n\t\tstd::cout << \"   pixels_to_spatial_a_ == \" << p_kernel.pixels_to_spatial_a_ << std::endl;\n\t\tstd::cout << \"   pixels_to_spatial_b_ == \" << p_kernel.pixels_to_spatial_b_ << std::endl;\n\t\tstd::cout << \"   pixels_to_spatial_c_ == \" << p_kernel.pixels_to_spatial_c_ << std::endl;\n\t}\n\t\n\tstd::cout << \"   values ==\";\n\t\n\tswitch (p_kernel.dimensionality_)\n\t{\n\t\tcase 1:\t\t\t\t\t\t\t\t\t\t// NOLINT(*-branch-clone) : intentional duplicate branches\n\t\t\t// unimplemented\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tfor (int b = 0; b < p_kernel.dim[1]; b++)\n\t\t\t{\n\t\t\t\tstd::cout << std::endl << \"      \";\n\t\t\t\t\n\t\t\t\tfor (int a = 0; a < p_kernel.dim[0]; a++)\n\t\t\t\t{\n\t\t\t\t\tstd::ostringstream os;\n\t\t\t\t\t\n\t\t\t\t\tos.precision(3);\n\t\t\t\t\tos << std::fixed;\n\t\t\t\t\tos << p_kernel.values_[a + b * p_kernel.dim[0]];\n\t\t\t\t\t\n\t\t\t\t\tstd::cout << os.str() << \" \";\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 3:\t\t\t\t\t\t\t\t\t\t// NOLINT(*-branch-clone) : intentional duplicate branches\n\t\t\t// unimplemented\n\t\t\tbreak;\n\t\tdefault: break;\n\t}\n\tstd::cout << std::endl;\n\t\n\treturn p_out;\n}\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/spatial_kernel.h",
    "content": "//\n//  spatial_kernel.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/9/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class SpatialKernel represents a spatial kernel of some shape.  It is used by both InteractionType and SpatialMap\n to represent the kernels they use internally.  It is not visible in Eidos, at least for now.\n \n */\n\n#ifndef __SLiM__spatial_kernel__\n#define __SLiM__spatial_kernel__\n\n#include <vector>\n#include <cstdint>\n\n#include \"eidos_value.h\"\n#include \"spatial_map.h\"\n\n\n// This enumeration represents a type of interaction function (IF) that an\n// interaction type can use to convert distances to interaction strengths\nenum class SpatialKernelType : char {\n\tkFixed = 0,\t\t// \"f\"\n\tkLinear,\t\t// \"l\"\n\tkExponential,\t// \"e\"\n\tkNormal,\t\t// \"n\"\n\tkCauchy,\t\t// \"c\"\n\tkStudentsT,\t\t// \"t\"\n};\n\nstd::ostream& operator<<(std::ostream& p_out, SpatialKernelType p_kernel_type);\n\n\n#pragma mark -\n#pragma mark SpatialKernel\n#pragma mark -\n\nclass SpatialKernel\n{\npublic:\n\t// core kernel definition\n\tint dimensionality_;\t\t\t// 1, 2, or 3: how many dimensions the kernel data is\n\tdouble max_distance_;\t\t\t// the maximum spatial distance out to which the kernel stretches\n\tdouble pixels_to_spatial_a_;\t// multiply by this to convert pixels to spatial scale for a\n\tdouble pixels_to_spatial_b_;\t// multiply by this to convert pixels to spatial scale for b\n\tdouble pixels_to_spatial_c_;\t// multiply by this to convert pixels to spatial scale for c\n\t\n\tSpatialKernelType kernel_type_;\t\t\t\t// the kernel type to use\n\tdouble kernel_param1_, kernel_param2_, kernel_param3_;\t// parameters for that kernel type (not all of which may be used)\n\tdouble n_2param2sq_;\t\t\t\t\t\t// for type \"n\", precalc 2.0 * kernel_param2_ * kernel_param2_\n\t\n\t// discrete grid values; set up only if CalculateGridValues() is called\n\tdouble *values_ = nullptr;\t\t// raw kernel pixel data, malloced\n\tint64_t dim[3] = {0, 0, 0};\t\t// pixel dimensions of values_ for 1, 2, or 3 axes\n\t\n\t// calculate t-distribution PDF values in our fashion, for which the function is normalized to a maximum value\n\t// we don't use the GSL for this, because it does two gamma-function calculations that we don't need (they normalize away)\n\tstatic inline double tdist(double x, double max, double nu, double tau) {\n\t\tdouble x_over_tau = x / tau;\n\t\treturn max * pow(1.0 + x_over_tau * x_over_tau / nu, -(nu + 1.0) / 2.0);\n\t};\n\t\npublic:\n\t// This static member function should be called before beginning to construct kernels from an argument list\n\t// When you then use the constructor below, all arguments must be the same, to avoid missing errors\n\tstatic int PreprocessArguments(int p_dimensionality, double p_maxDistance, const std::vector<EidosValue_SP> &p_arguments, int p_first_kernel_arg, bool p_expect_max_density, SpatialKernelType *p_kernel_type, int *p_k_param_count);\n\t\n\tSpatialKernel(const SpatialKernel&) = default;\t\t\t\t\t\t\t// can copy spatial kernels\n\tSpatialKernel& operator=(const SpatialKernel&) = delete;\t\t\t\t// no copying\n\tSpatialKernel(void) = delete;\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tSpatialKernel(int p_dimensionality, double p_maxDistance, const std::vector<EidosValue_SP> &p_arguments, int p_first_kernel_arg, int p_kernel_arg_index, bool p_expect_max_density, SpatialKernelType p_kernel_type, int p_k_param_count);\n\t~SpatialKernel(void);\n\t\n\tvoid CalculateGridValues(SpatialMap &p_map);\n\tdouble DensityForDistance(double p_distance);\n\tvoid DrawDisplacement_S1(double *displacement);\n\tvoid DrawDisplacement_S2(double *displacement);\n\tvoid DrawDisplacement_S3(double *displacement);\n\t\n\tfriend void SpatialMap::Convolve_S1(SpatialKernel &kernel);\n\tfriend void SpatialMap::Convolve_S2(SpatialKernel &kernel);\n\tfriend void SpatialMap::Convolve_S3(SpatialKernel &kernel);\n};\n\nstd::ostream& operator<<(std::ostream& p_out, SpatialKernel &p_kernel);\n\n\n#endif /* __SLiM__spatial_kernel__ */\n"
  },
  {
    "path": "core/spatial_map.cpp",
    "content": "//\n//  spatial_map.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 9/4/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"spatial_map.h\"\n#include \"spatial_kernel.h\"\n#include \"subpopulation.h\"\n#include \"eidos_class_Image.h\"\n#include \"eidos_simd.h\"\n\n#include \"gsl_math.h\"\n#include \"gsl_spline.h\"\n#include \"gsl_interp2d.h\"\n#include \"gsl_spline2d.h\"\n\n#include <utility>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\n// Clamp a standardized coordinate, which should be in [0,1], to [0,1].\n#define SLiMClampCoordinate(x) (((x) < 0.0) ? 0.0 : (((x) > 1.0) ? 1.0 : (x)))\n\n\n#pragma mark -\n#pragma mark SpatialMap\n#pragma mark -\n\nSpatialMap::SpatialMap(std::string p_name, std::string p_spatiality_string, Subpopulation *p_subpop, EidosValue *p_values, bool p_interpolate, EidosValue *p_value_range, EidosValue *p_colors) :\n\tname_(std::move(p_name)), tag_value_(SLIM_TAG_UNSET_VALUE), spatiality_string_(std::move(p_spatiality_string)), interpolate_(p_interpolate)\n{\n\t// The spatiality string determines what dimensionality we require for subpops using us; it must be large enough to\n\t// encompass our spatiality (\"xyz\" to encompass \"xz\", for example).  It also determines how many dimensions of map\n\t// data we contain, which is spatiality_ (1, 2, or 3), and which spatial boundary components we standardize to,\n\t// which is spatiality_type_ (just an integer representation of spatiality_string_, really).  Finally, it copies\n\t// over the relevant portions of the reference subpopulation's bounds for our spatiality.\n\tif (spatiality_string_.compare(gEidosStr_x) == 0) {\n\t\trequired_dimensionality_ = 1;\n\t\tspatiality_ = 1;\n\t\tspatiality_type_ = 1;\n\t\tp_subpop->species_.SpatialPeriodicity(&periodic_a_, nullptr, nullptr);\n\t\tperiodic_b_ = false;\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_x0_;\n\t\tbounds_a1_ = p_subpop->bounds_x1_;\n\t\tbounds_b0_ = 0;\n\t\tbounds_b1_ = 0;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(gEidosStr_y) == 0) {\n\t\trequired_dimensionality_ = 2;\n\t\tspatiality_ = 1;\n\t\tspatiality_type_ = 2;\n\t\tp_subpop->species_.SpatialPeriodicity(nullptr, &periodic_a_, nullptr);\n\t\tperiodic_b_ = false;\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_y0_;\n\t\tbounds_a1_ = p_subpop->bounds_y1_;\n\t\tbounds_b0_ = 0;\n\t\tbounds_b1_ = 0;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(gEidosStr_z) == 0) {\n\t\trequired_dimensionality_ = 3;\n\t\tspatiality_ = 1;\n\t\tspatiality_type_ = 3;\n\t\tp_subpop->species_.SpatialPeriodicity(nullptr, nullptr, &periodic_a_);\n\t\tperiodic_b_ = false;\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_z0_;\n\t\tbounds_a1_ = p_subpop->bounds_z1_;\n\t\tbounds_b0_ = 0;\n\t\tbounds_b1_ = 0;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(\"xy\") == 0) {\n\t\trequired_dimensionality_ = 2;\n\t\tspatiality_ = 2;\n\t\tspatiality_type_ = 4;\n\t\tp_subpop->species_.SpatialPeriodicity(&periodic_a_, &periodic_b_, nullptr);\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_x0_;\n\t\tbounds_a1_ = p_subpop->bounds_x1_;\n\t\tbounds_b0_ = p_subpop->bounds_y0_;\n\t\tbounds_b1_ = p_subpop->bounds_y1_;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(\"xz\") == 0) {\n\t\trequired_dimensionality_ = 3;\n\t\tspatiality_ = 2;\n\t\tspatiality_type_ = 5;\n\t\tp_subpop->species_.SpatialPeriodicity(&periodic_a_, nullptr, &periodic_b_);\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_x0_;\n\t\tbounds_a1_ = p_subpop->bounds_x1_;\n\t\tbounds_b0_ = p_subpop->bounds_z0_;\n\t\tbounds_b1_ = p_subpop->bounds_z1_;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(\"yz\") == 0) {\n\t\trequired_dimensionality_ = 3;\n\t\tspatiality_ = 2;\n\t\tspatiality_type_ = 6;\n\t\tp_subpop->species_.SpatialPeriodicity(nullptr, &periodic_a_, &periodic_b_);\n\t\tperiodic_c_ = false;\n\t\tbounds_a0_ = p_subpop->bounds_y0_;\n\t\tbounds_a1_ = p_subpop->bounds_y1_;\n\t\tbounds_b0_ = p_subpop->bounds_z0_;\n\t\tbounds_b1_ = p_subpop->bounds_z1_;\n\t\tbounds_c0_ = 0;\n\t\tbounds_c1_ = 0;\n\t}\n\telse if (spatiality_string_.compare(\"xyz\") == 0) {\n\t\trequired_dimensionality_ = 3;\n\t\tspatiality_ = 3;\n\t\tspatiality_type_ = 7;\n\t\tp_subpop->species_.SpatialPeriodicity(&periodic_a_, &periodic_b_, &periodic_c_);\n\t\tbounds_a0_ = p_subpop->bounds_x0_;\n\t\tbounds_a1_ = p_subpop->bounds_x1_;\n\t\tbounds_b0_ = p_subpop->bounds_y0_;\n\t\tbounds_b1_ = p_subpop->bounds_y1_;\n\t\tbounds_c0_ = p_subpop->bounds_z0_;\n\t\tbounds_c1_ = p_subpop->bounds_z1_;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::SpatialMap): defineSpatialMap() spatiality '\" << spatiality_string_ << \"' must be 'x', 'y', 'z', 'xy', 'xz', 'yz', or 'xyz'.\" << EidosTerminate();\n\t\n\tTakeValuesFromEidosValue(p_values, \"SpatialMap::SpatialMap\", \"defineSpatialMap()\");\n\tTakeColorsFromEidosValues(p_value_range, p_colors, \"SpatialMap::SpatialMap\", \"defineSpatialMap()\");\n}\n\nSpatialMap::SpatialMap(std::string p_name, SpatialMap &p_original) :\n\tname_(std::move(p_name)), tag_value_(SLIM_TAG_UNSET_VALUE), spatiality_string_(p_original.spatiality_string_), spatiality_(p_original.spatiality_), spatiality_type_(p_original.spatiality_type_), periodic_a_(p_original.periodic_a_), periodic_b_(p_original.periodic_b_), periodic_c_(p_original.periodic_c_), required_dimensionality_(p_original.required_dimensionality_), bounds_a0_(p_original.bounds_a0_), bounds_a1_(p_original.bounds_a1_), bounds_b0_(p_original.bounds_b0_), bounds_b1_(p_original.bounds_b1_), bounds_c0_(p_original.bounds_c0_), bounds_c1_(p_original.bounds_c1_), interpolate_(p_original.interpolate_), values_min_(p_original.values_min_), values_max_(p_original.values_max_), n_colors_(p_original.n_colors_), colors_min_(p_original.colors_min_), colors_max_(p_original.colors_max_)\n{\n\t// Note that this does not copy the information from EidosDictionaryRetained, and it leaves tag unset\n\t// This is intentional (that is very instance-specific state that should arguably not be copied)\n\t\n\t// Copy over our grid dimensions\n\tgrid_size_[0] = p_original.grid_size_[0];\n\tgrid_size_[1] = p_original.grid_size_[1];\n\tgrid_size_[2] = p_original.grid_size_[2];\n\tvalues_size_ = p_original.values_size_;\n\t\n\t// Copy over the map values\n\tvalues_ = (double *)malloc(values_size_ * sizeof(double));\n\tif (!values_)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::SpatialMap): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tmemcpy(values_, p_original.values_, values_size_ * sizeof(double));\n\t\n\t// Copy color mapping components\n\tif (n_colors_)\n\t{\n\t\tred_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\tgreen_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\tblue_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\t\n\t\tif (!red_components_ || !green_components_ || !blue_components_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::SpatialMap): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tmemcpy(red_components_, p_original.red_components_, n_colors_ * sizeof(float));\n\t\tmemcpy(green_components_, p_original.green_components_, n_colors_ * sizeof(float));\n\t\tmemcpy(blue_components_, p_original.blue_components_, n_colors_ * sizeof(float));\n\t}\n\telse\n\t{\n\t\tred_components_ = nullptr;\n\t\tgreen_components_ = nullptr;\n\t\tblue_components_ = nullptr;\n\t}\n}\n\nSpatialMap::~SpatialMap(void)\n{\n\tif (values_)\n\t\tfree(values_);\n\t\n\tif (red_components_)\n\t\tfree(red_components_);\n\tif (green_components_)\n\t\tfree(green_components_);\n\tif (blue_components_)\n\t\tfree(blue_components_);\n\t\n#if defined(SLIMGUI)\n\tif (display_buffer_)\n\t\tfree(display_buffer_);\n\t\n\tif (image_)\n\t{\n\t\tif (image_deleter_)\n\t\t\timage_deleter_(image_);\n\t\telse\n\t\t\tstd::cout << \"Missing SpatialMap image_deleter_; leaking memory\" << std::endl;\n\t}\n#endif\n}\n\nvoid SpatialMap::_ValuesChanged(void)\n{\n#if defined(SLIMGUI)\n\t// Force a display image recache in SLiMgui\n\tif (display_buffer_)\n\t{\n\t\tfree(display_buffer_);\n\t\tdisplay_buffer_ = nullptr;\n\t}\n\tif (image_)\n\t{\n\t\tif (image_deleter_)\n\t\t\timage_deleter_(image_);\n\t\telse\n\t\t\tstd::cout << \"Missing SpatialMap image_deleter_; leaking memory\" << std::endl;\n\t\t\n\t\timage_ = nullptr;\n\t\timage_deleter_ = nullptr;\n\t}\n#endif\n\t\n\t// Reassesses our minimum and maximum values\n\tvalues_min_ = values_max_ = values_[0];\n\t\n\t// FIXME: TO BE PARALLELIZED\n\tfor (int64_t values_index = 1; values_index < values_size_; ++values_index)\n\t{\n\t\tdouble value = values_[values_index];\n\t\t\n\t\tvalues_min_ = std::min(values_min_, value);\n\t\tvalues_max_ = std::max(values_max_, value);\n\t}\n\t\n\t// If we're using our default grayscale colors, realign to the new range\n\tif (n_colors_ == 0)\n\t{\n\t\tcolors_min_ = values_min_;\n\t\tcolors_max_ = values_max_;\n\t}\n\t\n\t// At least for now, we have a policy of no INF/NAN in spatial maps;\n\t// there is not a clear need for them, and this simplifies things\n\tif (!std::isfinite(values_min_) || !std::isfinite(values_max_))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::_ValuesChanged): non-finite values (infinities, NANs) are not allowed in SpatialMap.\" << EidosTerminate();\n}\n\nvoid SpatialMap::TakeColorsFromEidosValues(EidosValue *p_value_range, EidosValue *p_colors, const std::string &p_code_name, const std::string &p_eidos_name)\n{\n\t// Make our color map\n\tbool range_is_null = (p_value_range->Type() == EidosValueType::kValueNULL);\n\tbool colors_is_null = (p_colors->Type() == EidosValueType::kValueNULL);\n\t\n\tn_colors_ = 0;\n\t\n\tif (!range_is_null || !colors_is_null)\n\t{\n\t\tif (range_is_null || colors_is_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" valueRange and colors must either both be supplied, or neither supplied.\" << EidosTerminate();\n\t\t\n\t\tif (p_value_range->Count() != 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" valueRange must be exactly length 2 (giving the min and max value permitted).\" << EidosTerminate();\n\t\t\n\t\t// valueRange and colors were provided, so use them for coloring\n\t\tcolors_min_ = p_value_range->NumericAtIndex_NOCAST(0, nullptr);\n\t\tcolors_max_ = p_value_range->NumericAtIndex_NOCAST(1, nullptr);\n\t\t\n\t\tif (!std::isfinite(colors_min_) || !std::isfinite(colors_max_) || (colors_min_ > colors_max_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" valueRange must be finite, and min <= max is required.\" << EidosTerminate();\n\t\t\n\t\tn_colors_ = p_colors->Count();\n\t\t\n\t\tif (n_colors_ < 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" colors must be of length >= 2.\" << EidosTerminate();\n\t}\n\t\n\t// Allocate buffers to hold our color component vectors, if we were supplied with color info\n\tfree(red_components_);\n\tfree(green_components_);\n\tfree(blue_components_);\n\tred_components_ = nullptr;\n\tgreen_components_ = nullptr;\n\tblue_components_ = nullptr;\n\t\n\tif (n_colors_ > 0)\n\t{\n\t\tred_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\tgreen_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\tblue_components_ = (float *)malloc(n_colors_ * sizeof(float));\n\t\t\n\t\tif (!red_components_ || !green_components_ || !blue_components_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst std::string *colors_vec_ptr = p_colors->StringData();\n\t\t\n\t\tfor (int colors_index = 0; colors_index < n_colors_; ++colors_index)\n\t\t\tEidos_GetColorComponents(colors_vec_ptr[colors_index], red_components_ + colors_index, green_components_ + colors_index, blue_components_ + colors_index);\n\t}\n\t\n\t_ValuesChanged();\n}\n\nvoid SpatialMap::TakeValuesFromEidosValue(EidosValue *p_values, const std::string &p_code_name, const std::string &p_eidos_name)\n{\n\tint values_dimcount = p_values->DimensionCount();\n\tconst int64_t *values_dim = p_values->Dimensions();\n\t\n\tif (values_dimcount != spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" the dimensionality of the supplied vector/matrix/array does not match the spatiality defined for the map.\" << EidosTerminate();\n\t\n\tint dimension_index;\n\tvalues_size_ = 1;\n\t\n\tfor (dimension_index = 0; dimension_index < spatiality_; ++dimension_index)\n\t{\n\t\tint64_t dimension_size = (values_dimcount == 1) ? p_values->Count() : values_dim[dimension_index];\t// treat a vector as a 1D matrix\n\t\t\n\t\tif (dimension_size < 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" all dimensions of value must be of size >= 2.\" << EidosTerminate();\n\t\t\n\t\tgrid_size_[dimension_index] = dimension_size;\n\t\tvalues_size_ *= dimension_size;\n\t}\n\tfor ( ; dimension_index < 3; ++dimension_index)\n\t\tgrid_size_[dimension_index] = 0;\n\t\n\t// Matrices and arrays use dim[0] as the number of rows, and dim[1] as the number of cols; spatial maps do the opposite,\n\t// following standard image conventions (by row, not by column); we therefore need to swap grid_size_[0] and grid_size_[1]\n\tif (spatiality_ >= 2)\n\t\tstd::swap(grid_size_[0], grid_size_[1]);\n\t\n\t// Allocate a values buffer of the proper size\n\tfree(values_);\n\tvalues_ = nullptr;\n\t\n\tvalues_ = (double *)malloc(values_size_ * sizeof(double));\n\tif (!values_)\n\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t// Take the values we were passed in\n\tconst double *values_float_vec_ptr = (p_values->Type() == EidosValueType::kValueFloat) ? p_values->FloatData() : nullptr;\n\tconst int64_t *values_integer_vec_ptr = (p_values->Type() == EidosValueType::kValueInt) ? p_values->IntData() : nullptr;\n\t\n\tif (spatiality_ == 1)\n\t{\n\t\t// A vector was passed (since no matrix dimension here is allowed to have a size of 1), so no transpose/flip needed\n\t\t// The vector values will be read left to right, or bottom to top, following SLiM's Cartesian spatial coordinates\n\t\tif (values_float_vec_ptr)\n\t\t\tfor (int64_t values_index = 0; values_index < values_size_; ++values_index)\n\t\t\t\tvalues_[values_index] = *(values_float_vec_ptr++);\n\t\telse\n\t\t\tfor (int64_t values_index = 0; values_index < values_size_; ++values_index)\n\t\t\t\tvalues_[values_index] = *(values_integer_vec_ptr++);\n\t}\n\telse if (spatiality_ >= 2)\n\t{\n\t\t// A matrix/array was passed (it is no longer legal to pass a vector in the multidimensional case)\n\t\t// A transpose/flip is therefore needed, because matrices are stored by row and read top to bottom\n\t\tint64_t col_count = grid_size_[0];\t\t// note grid_size_ got swapped above\n\t\tint64_t row_count = grid_size_[1];\n\t\tint64_t plane_count = (spatiality_ == 3) ? grid_size_[2] : 1;\n\t\t\n\t\tif (values_float_vec_ptr)\n\t\t{\n\t\t\tfor (int64_t z = 0; z < plane_count; ++z)\n\t\t\t{\n\t\t\t\tint64_t plane_offset = z * (row_count * col_count);\n\t\t\t\t\n\t\t\t\tfor (int64_t x = 0; x < col_count; ++x)\n\t\t\t\t\tfor (int64_t y = 0; y < row_count; ++y)\n\t\t\t\t\t\tvalues_[plane_offset + x + (row_count - 1 - y) * col_count] = values_float_vec_ptr[plane_offset + y + x * row_count];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (int64_t z = 0; z < plane_count; ++z)\n\t\t\t{\n\t\t\t\tint64_t plane_offset = z * (row_count * col_count);\n\t\t\t\t\n\t\t\t\tfor (int64_t x = 0; x < col_count; ++x)\n\t\t\t\t\tfor (int64_t y = 0; y < row_count; ++y)\n\t\t\t\t\t\tvalues_[plane_offset + x + (row_count - 1 - y) * col_count] = values_integer_vec_ptr[plane_offset + y + x * row_count];\n\t\t\t}\n\t\t}\n\t}\n\t\n\t_ValuesChanged();\n\t\n\t// Note that we do not change the min/max or the color map; that is up to the caller, if they wish to do so\n}\n\nvoid SpatialMap::TakeOverMallocedValues(double *p_values, int64_t p_dimcount, int64_t *p_dimensions)\n{\n\tif (p_dimcount != spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::TakeOverMallocedValues): (internal error) the dimensionality of the supplied values does not match the spatiality defined for the map.\" << EidosTerminate();\n\t\n\tint dimension_index;\n\tvalues_size_ = 1;\n\t\n\tfor (dimension_index = 0; dimension_index < spatiality_; ++dimension_index)\n\t{\n\t\tint64_t dimension_size = p_dimensions[dimension_index];\n\t\t\n\t\tif (dimension_size < 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::TakeOverMallocedValues): (internal error) all dimensions of value must be of size >= 2.\" << EidosTerminate();\n\t\t\n\t\tgrid_size_[dimension_index] = dimension_size;\n\t\tvalues_size_ *= dimension_size;\n\t}\n\tfor ( ; dimension_index < 3; ++dimension_index)\n\t\tgrid_size_[dimension_index] = 0;\n\t\n\t// Take over the passed buffer\n\tfree(values_);\n\tvalues_ = p_values;\n\t\n\t_ValuesChanged();\n\t\n\t// Note that we do not change the min/max or the color map; that is up to the caller, if they wish to do so\n}\n\nbool SpatialMap::IsCompatibleWithSubpopulation(Subpopulation *p_subpop)\n{\n\t// This checks that spatiality/dimensionality and bounds are compatible between the spatial map and a given subpopulation\n\tint spatial_dimensionality = p_subpop->species_.SpatialDimensionality();\n\tbool subpop_periodic_x, subpop_periodic_y, subpop_periodic_z;\n\t\n\tp_subpop->species_.SpatialPeriodicity(&subpop_periodic_x, &subpop_periodic_y, &subpop_periodic_z);\n\t\n\tif (spatiality_type_ == 1) {\t\t\t// \"x\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_x0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_x1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_x))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 2) {\t\t// \"y\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_y0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_y1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_y))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 3) {\t\t// \"z\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_z0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_z1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_z))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 4) {\t\t// \"xy\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_x0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_x1_) ||\n\t\t\t(bounds_b0_ != p_subpop->bounds_y0_) ||\n\t\t\t(bounds_b1_ != p_subpop->bounds_y1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_x) ||\n\t\t\t(periodic_b_ != subpop_periodic_y))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 5) {\t\t// \"xz\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_x0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_x1_) ||\n\t\t\t(bounds_b0_ != p_subpop->bounds_z0_) ||\n\t\t\t(bounds_b1_ != p_subpop->bounds_z1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_x) ||\n\t\t\t(periodic_b_ != subpop_periodic_z))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 6) {\t\t// \"yz\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_y0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_y1_) ||\n\t\t\t(bounds_b0_ != p_subpop->bounds_z0_) ||\n\t\t\t(bounds_b1_ != p_subpop->bounds_z1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_y) ||\n\t\t\t(periodic_b_ != subpop_periodic_z))\n\t\t\treturn false;\n\t}\n\telse if (spatiality_type_ == 7) {\t\t// \"xyz\"\n\t\tif ((required_dimensionality_ > spatial_dimensionality) ||\n\t\t\t(bounds_a0_ != p_subpop->bounds_x0_) ||\n\t\t\t(bounds_a1_ != p_subpop->bounds_x1_) ||\n\t\t\t(bounds_b0_ != p_subpop->bounds_y0_) ||\n\t\t\t(bounds_b1_ != p_subpop->bounds_y1_) ||\n\t\t\t(bounds_c0_ != p_subpop->bounds_z0_) ||\n\t\t\t(bounds_c1_ != p_subpop->bounds_z1_) ||\n\t\t\t(periodic_a_ != subpop_periodic_x) ||\n\t\t\t(periodic_b_ != subpop_periodic_y) ||\n\t\t\t(periodic_c_ != subpop_periodic_z))\n\t\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\nbool SpatialMap::IsCompatibleWithMap(SpatialMap *p_map)\n{\n\t// This checks that spatiality/dimensionality/periodicity and bounds are compatible between the spatial map and a given spatial map\n\tif ((spatiality_ != p_map->spatiality_) || (spatiality_type_ != p_map->spatiality_type_))\n\t\treturn false;\n\tif ((periodic_a_ != p_map->periodic_a_) || (periodic_b_ != p_map->periodic_b_) || (periodic_c_ != p_map->periodic_c_))\n\t\treturn false;\n\t\n\tif ((bounds_a0_ != p_map->bounds_a0_) || (bounds_a1_ != p_map->bounds_a1_) || (grid_size_[0] != p_map->grid_size_[0]))\n\t\treturn false;\n\tif (spatiality_ >= 2)\n\t\tif ((bounds_b0_ != p_map->bounds_b0_) || (bounds_b1_ != p_map->bounds_b1_) || (grid_size_[1] != p_map->grid_size_[1]))\n\t\t\treturn false;\n\tif (spatiality_ >= 3)\n\t\tif ((bounds_c0_ != p_map->bounds_c0_) || (bounds_c1_ != p_map->bounds_c1_) || (grid_size_[2] != p_map->grid_size_[2]))\n\t\t\treturn false;\n\t\n\t// this one should never be true if the above were all false, but it's a safety check\n\tif (values_size_ != p_map->values_size_)\n\t\treturn false;\n\t\n\treturn true;\n}\n\nbool SpatialMap::IsCompatibleWithMapValues(SpatialMap *p_map)\n{\n\t// This checks that grid value dimensions are compatible between the spatial map and a given spatial map\n\tif (grid_size_[0] != p_map->grid_size_[0])\n\t\treturn false;\n\tif ((spatiality_ >= 2) && (grid_size_[1] != p_map->grid_size_[1]))\n\t\treturn false;\n\tif ((spatiality_ >= 3) && (grid_size_[2] != p_map->grid_size_[2]))\n\t\treturn false;\n\t\n\t// this one should never be true if the above were all false, but it's a safety check\n\tif (values_size_ != p_map->values_size_)\n\t\treturn false;\n\t\n\treturn true;\n}\n\nbool SpatialMap::IsCompatibleWithValue(EidosValue *p_value)\n{\n\t// This checks that the dimensions of a vector/matrix/array are compatible with the spatial map\n\tif (p_value->Count() != values_size_)\n\t\treturn false;\n\t\n\tif (p_value->DimensionCount() != spatiality_)\n\t\treturn false;\n\t\n\tconst int64_t *values_dim = p_value->Dimensions();\n\t\n\t// Matrices and arrays use dim[0] as the number of rows, and dim[1] as the number of cols; spatial maps do the opposite,\n\t// following standard image conventions (by row, not by column); we therefore need to swap grid_size_[0] and grid_size_[1]\n\tswitch (spatiality_)\n\t{\n\t\tcase 1:\n\t\t\treturn true;\n\t\tcase 2:\n\t\t\tif ((values_dim[0] != grid_size_[1]) || (values_dim[1] != grid_size_[0]))\n\t\t\t\treturn false;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tif ((values_dim[0] != grid_size_[1]) || (values_dim[1] != grid_size_[0]) || (values_dim[2] != grid_size_[2]))\n\t\t\t\treturn false;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::IsCompatibleWithValue): (internal error) spatiality_ out of range.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn true;\n}\n\ndouble SpatialMap::ValueAtPoint_S1(double *p_point)\n{\n\t// This looks up the value at point, which is in coordinates that have been normalized and clamped to [0,1]\n\t// Note that this does NOT handle periodicity; it is assumed that the point has already been brought in bounds\n\tassert (spatiality_ == 1);\n\t\n\tdouble x_fraction = p_point[0];\n\tint64_t xsize = grid_size_[0];\n\t\n\tif (interpolate_)\n\t{\n\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\tint x1_map = (int)floor(x_map);\n\t\tint x2_map = (int)ceil(x_map);\n\t\tdouble fraction_x2 = x_map - x1_map;\n\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\tdouble value_x1 = values_[x1_map] * fraction_x1;\n\t\tdouble value_x2 = values_[x2_map] * fraction_x2;\n\t\t\n\t\treturn value_x1 + value_x2;\n\t}\n\telse\n\t{\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\t\n\t\treturn values_[x_map];\n\t}\n}\n\ndouble SpatialMap::ValueAtPoint_S2(double *p_point)\n{\n\t// This looks up the value at point, which is in coordinates that have been normalized and clamped to [0,1]\n\t// Note that this does NOT handle periodicity; it is assumed that the point has already been brought in bounds\n\tassert (spatiality_ == 2);\n\t\n\tdouble x_fraction = p_point[0];\n\tdouble y_fraction = p_point[1];\n\tint64_t xsize = grid_size_[0];\n\tint64_t ysize = grid_size_[1];\n\t\n\tif (interpolate_)\n\t{\n\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\tdouble y_map = y_fraction * (ysize - 1);\n\t\tint x1_map = (int)floor(x_map);\n\t\tint y1_map = (int)floor(y_map);\n\t\tint x2_map = (int)ceil(x_map);\n\t\tint y2_map = (int)ceil(y_map);\n\t\tdouble fraction_x2 = x_map - x1_map;\n\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\tdouble fraction_y2 = y_map - y1_map;\n\t\tdouble fraction_y1 = 1.0 - fraction_y2;\n\t\tdouble value_x1_y1 = values_[x1_map + y1_map * xsize] * fraction_x1 * fraction_y1;\n\t\tdouble value_x2_y1 = values_[x2_map + y1_map * xsize] * fraction_x2 * fraction_y1;\n\t\tdouble value_x1_y2 = values_[x1_map + y2_map * xsize] * fraction_x1 * fraction_y2;\n\t\tdouble value_x2_y2 = values_[x2_map + y2_map * xsize] * fraction_x2 * fraction_y2;\n\t\t\n\t\treturn value_x1_y1 + value_x2_y1 + value_x1_y2 + value_x2_y2;\n\t}\n\telse\n\t{\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\tint y_map = (int)round(y_fraction * (ysize - 1));\n\t\t\n\t\treturn values_[x_map + y_map * xsize];\n\t}\n}\n\ndouble SpatialMap::ValueAtPoint_S3(double *p_point)\n{\n\t// This looks up the value at point, which is in coordinates that have been normalized and clamped to [0,1]\n\t// Note that this does NOT handle periodicity; it is assumed that the point has already been brought in bounds\n\tassert (spatiality_ == 3);\n\t\n\tdouble x_fraction = p_point[0];\n\tdouble y_fraction = p_point[1];\n\tdouble z_fraction = p_point[2];\n\tint64_t xsize = grid_size_[0];\n\tint64_t ysize = grid_size_[1];\n\tint64_t zsize = grid_size_[2];\n\t\n\tif (interpolate_)\n\t{\n\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\tdouble y_map = y_fraction * (ysize - 1);\n\t\tdouble z_map = z_fraction * (zsize - 1);\n\t\tint x1_map = (int)floor(x_map);\n\t\tint y1_map = (int)floor(y_map);\n\t\tint z1_map = (int)floor(z_map);\n\t\tint x2_map = (int)ceil(x_map);\n\t\tint y2_map = (int)ceil(y_map);\n\t\tint z2_map = (int)ceil(z_map);\n\t\tdouble fraction_x2 = x_map - x1_map;\n\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\tdouble fraction_y2 = y_map - y1_map;\n\t\tdouble fraction_y1 = 1.0 - fraction_y2;\n\t\tdouble fraction_z2 = z_map - z1_map;\n\t\tdouble fraction_z1 = 1.0 - fraction_z2;\n\t\tdouble value_x1_y1_z1 = values_[x1_map + y1_map * xsize + z1_map * xsize * ysize] * fraction_x1 * fraction_y1 * fraction_z1;\n\t\tdouble value_x2_y1_z1 = values_[x2_map + y1_map * xsize + z1_map * xsize * ysize] * fraction_x2 * fraction_y1 * fraction_z1;\n\t\tdouble value_x1_y2_z1 = values_[x1_map + y2_map * xsize + z1_map * xsize * ysize] * fraction_x1 * fraction_y2 * fraction_z1;\n\t\tdouble value_x2_y2_z1 = values_[x2_map + y2_map * xsize + z1_map * xsize * ysize] * fraction_x2 * fraction_y2 * fraction_z1;\n\t\tdouble value_x1_y1_z2 = values_[x1_map + y1_map * xsize + z2_map * xsize * ysize] * fraction_x1 * fraction_y1 * fraction_z2;\n\t\tdouble value_x2_y1_z2 = values_[x2_map + y1_map * xsize + z2_map * xsize * ysize] * fraction_x2 * fraction_y1 * fraction_z2;\n\t\tdouble value_x1_y2_z2 = values_[x1_map + y2_map * xsize + z2_map * xsize * ysize] * fraction_x1 * fraction_y2 * fraction_z2;\n\t\tdouble value_x2_y2_z2 = values_[x2_map + y2_map * xsize + z2_map * xsize * ysize] * fraction_x2 * fraction_y2 * fraction_z2;\n\t\t\n\t\treturn value_x1_y1_z1 + value_x2_y1_z1 + value_x1_y2_z1 + value_x2_y2_z1 + value_x1_y1_z2 + value_x2_y1_z2 + value_x1_y2_z2 + value_x2_y2_z2;\n\t}\n\telse\n\t{\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\tint y_map = (int)round(y_fraction * (ysize - 1));\n\t\tint z_map = (int)round(z_fraction * (zsize - 1));\n\t\t\n\t\treturn values_[x_map + y_map * xsize + z_map * xsize * ysize];\n\t}\n}\n\nvoid SpatialMap::ColorForValue(double p_value, double *p_rgb_ptr)\n{\n\tif (n_colors_ == 0)\n\t{\n\t\t// this is the case when a color table was not defined; here, min could equal max\n\t\t// in this case, all values in the map should fall in the interval [min_value_, max_value_]\n\t\tdouble value_fraction = ((colors_min_ < colors_max_) ? ((p_value - colors_min_) / (colors_max_ - colors_min_)) : 0.0);\n\t\tp_rgb_ptr[0] = value_fraction;\n\t\tp_rgb_ptr[1] = value_fraction;\n\t\tp_rgb_ptr[2] = value_fraction;\n\t}\n\telse\n\t{\n\t\t// this is the case when a color table was defined; here, min < max (BCH 10/20/2021: now, can be equal here too)\n\t\t// in this case, values in the map may fall outside the interval [min_value_, max_value_]\n\t\tdouble value_fraction = ((colors_min_ < colors_max_) ? ((p_value - colors_min_) / (colors_max_ - colors_min_)) : 0.0);\n\t\tdouble color_index = value_fraction * (n_colors_ - 1);\n\t\tint color_index_1 = (int)floor(color_index);\n\t\tint color_index_2 = (int)ceil(color_index);\n\t\t\n\t\tif (color_index_1 < 0) color_index_1 = 0;\n\t\tif (color_index_1 >= n_colors_) color_index_1 = n_colors_ - 1;\n\t\tif (color_index_2 < 0) color_index_2 = 0;\n\t\tif (color_index_2 >= n_colors_) color_index_2 = n_colors_ - 1;\n\t\t\n\t\tdouble color_2_weight = color_index - color_index_1;\n\t\tdouble color_1_weight = 1.0F - color_2_weight;\n\t\t\n\t\tdouble red1 = red_components_[color_index_1];\n\t\tdouble green1 = green_components_[color_index_1];\n\t\tdouble blue1 = blue_components_[color_index_1];\n\t\tdouble red2 = red_components_[color_index_2];\n\t\tdouble green2 = green_components_[color_index_2];\n\t\tdouble blue2 = blue_components_[color_index_2];\n\t\t\n\t\tp_rgb_ptr[0] = (red1 * color_1_weight + red2 * color_2_weight);\n\t\tp_rgb_ptr[1] = (green1 * color_1_weight + green2 * color_2_weight);\n\t\tp_rgb_ptr[2] = (blue1 * color_1_weight + blue2 * color_2_weight);\n\t}\n}\n\nvoid SpatialMap::ColorForValue(double p_value, float *p_rgb_ptr)\n{\n\tif (n_colors_ == 0)\n\t{\n\t\t// this is the case when a color table was not defined; here, min could equal max\n\t\t// in this case, all values in the map should fall in the interval [min_value_, max_value_]\n\t\tfloat value_fraction = (float)((colors_min_ < colors_max_) ? ((p_value - colors_min_) / (colors_max_ - colors_min_)) : 0.0);\n\t\tp_rgb_ptr[0] = value_fraction;\n\t\tp_rgb_ptr[1] = value_fraction;\n\t\tp_rgb_ptr[2] = value_fraction;\n\t}\n\telse\n\t{\n\t\t// this is the case when a color table was defined; here, min < max (BCH 10/20/2021: now, can be equal here too)\n\t\t// in this case, values in the map may fall outside the interval [min_value_, max_value_]\n\t\tdouble value_fraction = ((colors_min_ < colors_max_) ? ((p_value - colors_min_) / (colors_max_ - colors_min_)) : 0.0);\n\t\tdouble color_index = value_fraction * (n_colors_ - 1);\n\t\tint color_index_1 = (int)floor(color_index);\n\t\tint color_index_2 = (int)ceil(color_index);\n\t\t\n\t\tif (color_index_1 < 0) color_index_1 = 0;\n\t\tif (color_index_1 >= n_colors_) color_index_1 = n_colors_ - 1;\n\t\tif (color_index_2 < 0) color_index_2 = 0;\n\t\tif (color_index_2 >= n_colors_) color_index_2 = n_colors_ - 1;\n\t\t\n\t\tdouble color_2_weight = color_index - color_index_1;\n\t\tdouble color_1_weight = 1.0F - color_2_weight;\n\t\t\n\t\tdouble red1 = red_components_[color_index_1];\n\t\tdouble green1 = green_components_[color_index_1];\n\t\tdouble blue1 = blue_components_[color_index_1];\n\t\tdouble red2 = red_components_[color_index_2];\n\t\tdouble green2 = green_components_[color_index_2];\n\t\tdouble blue2 = blue_components_[color_index_2];\n\t\t\n\t\tp_rgb_ptr[0] = (float)(red1 * color_1_weight + red2 * color_2_weight);\n\t\tp_rgb_ptr[1] = (float)(green1 * color_1_weight + green2 * color_2_weight);\n\t\tp_rgb_ptr[2] = (float)(blue1 * color_1_weight + blue2 * color_2_weight);\n\t}\n}\n\n// SIMD-accelerated convolution for 1D spatial maps\n// Uses vectorized dot products with loop reordering for contiguous memory access\nvoid SpatialMap::Convolve_S1(SpatialKernel &kernel)\n{\n\tif (spatiality_ != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S1): (internal error) map spatiality 1 required.\" << EidosTerminate();\n\tif (kernel.dimensionality_ != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S1): (internal error) kernel dimensionality 1 required.\" << EidosTerminate();\n\t\n\tint64_t kernel_dim_a = kernel.dim[0];\n\t\n\tif ((kernel_dim_a < 1) || (kernel_dim_a % 2 == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S1): (internal error) kernel dimensions must be odd.\" << EidosTerminate();\n\t\n\tint64_t dim_a = grid_size_[0];\n\tdouble *new_values = (double *)malloc(dim_a * sizeof(double));\n\t\n\tif (!new_values)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S1): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint64_t kernel_a_offset = -(kernel_dim_a / 2);\n\tdouble *kernel_values = kernel.values_;\n\tdouble *new_values_ptr = new_values;\n\t\n\tfor (int64_t a = 0; a < dim_a; ++a)\n\t{\n\t\tdouble coverage = (!periodic_a_ && ((a == 0) || (a == dim_a - 1))) ? 0.5 : 1.0;\n\t\t\n\t\tdouble kernel_total = 0.0;\n\t\tdouble conv_total = 0.0;\n\t\t\n\t\t// Calculate valid kernel range for non-periodic boundaries\n\t\tint64_t kernel_a_first = 0;\n\t\tint64_t kernel_a_last = kernel_dim_a - 1;\n\t\t\n\t\tif (!periodic_a_)\n\t\t{\n\t\t\t// Clamp to valid range\n\t\t\tkernel_a_first = std::max((int64_t)0, -(a + kernel_a_offset));\n\t\t\tkernel_a_last = std::min(kernel_dim_a - 1, (dim_a - 1) - (a + kernel_a_offset));\n\t\t}\n\t\t\n\t\t// Non-periodic: clamping above guarantees bounds, use SIMD\n\t\tint64_t conv_a_first = a + kernel_a_first + kernel_a_offset;\n\t\t\n\t\tif (!periodic_a_)\n\t\t{\n\t\t\tint64_t count = kernel_a_last - kernel_a_first + 1;\n\t\t\tEidos_SIMD::convolve_dot_product_scaled_float64(\n\t\t\t\t&kernel_values[kernel_a_first],\n\t\t\t\t&values_[conv_a_first],\n\t\t\t\tcount, coverage,\n\t\t\t\tkernel_total, conv_total);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Handle periodic boundaries element by element\n\t\t\tfor (int64_t kernel_a = 0; kernel_a < kernel_dim_a; kernel_a++)\n\t\t\t{\n\t\t\t\tint64_t conv_a = a + kernel_a + kernel_a_offset;\n\t\t\t\t\n\t\t\t\t// Wrap around periodic boundaries if out of range\n\t\t\t\tif ((conv_a < 0) || (conv_a >= dim_a))\n\t\t\t\t{\n\t\t\t\t\twhile (conv_a < 0)\n\t\t\t\t\t\tconv_a += (dim_a - 1);\n\t\t\t\t\twhile (conv_a >= dim_a)\n\t\t\t\t\t\tconv_a -= (dim_a - 1);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble kernel_value = kernel_values[kernel_a] * coverage;\n\t\t\t\tdouble pixel_value = values_[conv_a];\n\t\t\t\t\n\t\t\t\tkernel_total += kernel_value;\n\t\t\t\tconv_total += kernel_value * pixel_value;\n\t\t\t}\n\t\t}\n\t\t\n\t\t*(new_values_ptr++) = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t}\n\t\n\tTakeOverMallocedValues(new_values, 1, grid_size_);\t// takes new_values from us\n}\n\n// SIMD-accelerated convolution for 2D spatial maps\n// Uses vectorized dot products with loop reordering for contiguous memory access\nvoid SpatialMap::Convolve_S2(SpatialKernel &kernel)\n{\n\tif (spatiality_ != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S2): (internal error) map spatiality 2 required.\" << EidosTerminate();\n\tif (kernel.dimensionality_ != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S2): (internal error) kernel dimensionality 2 required.\" << EidosTerminate();\n\t\n\tint64_t kernel_dim_a = kernel.dim[0];\n\tint64_t kernel_dim_b = kernel.dim[1];\n\t\n\tif ((kernel_dim_a < 1) || (kernel_dim_a % 2 == 0) ||\n\t\t(kernel_dim_b < 1) || (kernel_dim_b % 2 == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S2): (internal error) kernel dimensions must be odd.\" << EidosTerminate();\n\t\n\tint64_t dim_a = grid_size_[0], dim_b = grid_size_[1];\n\tdouble *new_values = (double *)malloc(dim_a * dim_b * sizeof(double));\n\t\n\tif (!new_values)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S2): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint64_t kernel_a_offset = -(kernel_dim_a / 2), kernel_b_offset = -(kernel_dim_b / 2);\n\tdouble *kernel_values = kernel.values_;\n\tdouble *new_values_ptr = new_values;\n\t\n\tif (!periodic_a_ && !periodic_b_)\n\t{\n\t\t// Optimized non-periodic case with SIMD\n\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t{\n\t\t\tdouble coverage_b = ((b == 0) || (b == dim_b - 1)) ? 0.5 : 1.0;\n\t\t\t\n\t\t\tint64_t kernel_b_first = std::max((int64_t)0, -(b + kernel_b_offset));\n\t\t\tint64_t kernel_b_last = std::min(kernel_dim_b - 1, (kernel_dim_b - 1) + (((dim_b - 1) - b) + kernel_b_offset));\n\t\t\t\n\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t{\n\t\t\t\tdouble coverage_a = ((a == 0) || (a == dim_a - 1)) ? 0.5 : 1.0;\n\t\t\t\tdouble coverage = coverage_a * coverage_b;\n\t\t\t\t\n\t\t\t\tint64_t kernel_a_first = std::max((int64_t)0, -(a + kernel_a_offset));\n\t\t\t\tint64_t kernel_a_last = std::min(kernel_dim_a - 1, (kernel_dim_a - 1) + (((dim_a - 1) - a) + kernel_a_offset));\n\t\t\t\t\n\t\t\t\tdouble kernel_total = 0.0;\n\t\t\t\tdouble conv_total = 0.0;\n\t\t\t\t\n\t\t\t\t// Loop over b first (outer), then vectorize over a (inner, contiguous)\n\t\t\t\tfor (int64_t kernel_b = kernel_b_first; kernel_b <= kernel_b_last; kernel_b++)\n\t\t\t\t{\n\t\t\t\t\tint64_t conv_b = b + kernel_b + kernel_b_offset;\n\t\t\t\t\tint64_t conv_a_start = a + kernel_a_first + kernel_a_offset;\n\t\t\t\t\tint64_t count = kernel_a_last - kernel_a_first + 1;\n\t\t\t\t\t\n\t\t\t\t\t// Use SIMD dot product for the contiguous a dimension\n\t\t\t\t\tEidos_SIMD::convolve_dot_product_scaled_float64(\n\t\t\t\t\t\t&kernel_values[kernel_a_first + kernel_b * kernel_dim_a],\n\t\t\t\t\t\t&values_[conv_a_start + conv_b * dim_a],\n\t\t\t\t\t\tcount, coverage,\n\t\t\t\t\t\tkernel_total, conv_total);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(new_values_ptr++) = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// General periodic case - element by element\n\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t{\n\t\t\tdouble coverage_b = (!periodic_b_ && ((b == 0) || (b == dim_b - 1))) ? 0.5 : 1.0;\n\t\t\t\n\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t{\n\t\t\t\tdouble coverage_a = (!periodic_a_ && ((a == 0) || (a == dim_a - 1))) ? 0.5 : 1.0;\n\t\t\t\tdouble coverage = coverage_a * coverage_b;\n\t\t\t\t\n\t\t\t\tdouble kernel_total = 0.0;\n\t\t\t\tdouble conv_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int64_t kernel_b = 0; kernel_b < kernel_dim_b; kernel_b++)\n\t\t\t\t{\n\t\t\t\t\tint64_t conv_b = b + kernel_b + kernel_b_offset;\n\t\t\t\t\t\n\t\t\t\t\tif ((conv_b < 0) || (conv_b >= dim_b))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!periodic_b_)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (conv_b < 0)\n\t\t\t\t\t\t\tconv_b += (dim_b - 1);\n\t\t\t\t\t\twhile (conv_b >= dim_b)\n\t\t\t\t\t\t\tconv_b -= (dim_b - 1);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t kernel_a = 0; kernel_a < kernel_dim_a; kernel_a++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t conv_a = a + kernel_a + kernel_a_offset;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((conv_a < 0) || (conv_a >= dim_a))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!periodic_a_)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\twhile (conv_a < 0)\n\t\t\t\t\t\t\t\tconv_a += (dim_a - 1);\n\t\t\t\t\t\t\twhile (conv_a >= dim_a)\n\t\t\t\t\t\t\t\tconv_a -= (dim_a - 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble kernel_value = kernel_values[kernel_a + kernel_b * kernel_dim_a] * coverage;\n\t\t\t\t\t\tdouble pixel_value = values_[conv_a + conv_b * dim_a];\n\t\t\t\t\t\t\n\t\t\t\t\t\tkernel_total += kernel_value;\n\t\t\t\t\t\tconv_total += kernel_value * pixel_value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(new_values_ptr++) = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t\t\t}\n\t\t}\n\t}\n\t\n#if 0\n\t// Check the values computed above by the optimized algorithm against the simple algorithm\n\t// test_smooth2D.slim is a test file that can be used with this validation code\n\t// NOTE: due to SIMD, results may differ slightly; needs tolerance check with allClose()\n\tnew_values_ptr = new_values;\n\t\n\tif (!periodic_a_ && !periodic_b_)\n\t{\n\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t{\n\t\t\tdouble coverage_b = (!periodic_b_ && ((b == 0) || (b == dim_b - 1))) ? 0.5 : 1.0;\n\t\t\t\n\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t{\n\t\t\t\tdouble coverage_a = (!periodic_a_ && ((a == 0) || (a == dim_a - 1))) ? 0.5 : 1.0;\n\t\t\t\tdouble coverage = coverage_a * coverage_b;\t\t\t\t\t// handles partial coverage at the edges of the spatial map\n\t\t\t\t\n\t\t\t\t// calculate the kernel's effect at point (a,b)\n\t\t\t\tdouble kernel_total = 0.0;\n\t\t\t\tdouble conv_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int64_t kernel_a = 0; kernel_a < kernel_dim_a; kernel_a++)\n\t\t\t\t{\n\t\t\t\t\tint64_t conv_a = a + kernel_a + kernel_a_offset;\n\t\t\t\t\t\n\t\t\t\t\t// handle bounds: either clip or wrap\n\t\t\t\t\tif ((conv_a < 0) || (conv_a >= dim_a))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t kernel_b = 0; kernel_b < kernel_dim_b; kernel_b++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t conv_b = b + kernel_b + kernel_b_offset;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// handle bounds: either clip or wrap\n\t\t\t\t\t\tif ((conv_b < 0) || (conv_b >= dim_b))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// this point is within bounds; add it in to the totals\n\t\t\t\t\t\tdouble kernel_value = kernel_values[kernel_a + kernel_b * kernel_dim_a] * coverage;\n\t\t\t\t\t\tdouble pixel_value = values_[conv_a + conv_b * dim_a];\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we keep a total of the kernel values that were within bounds, for this point\n\t\t\t\t\t\tkernel_total += kernel_value;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// and we keep a total of the convolution - kernel values times pixel values\n\t\t\t\t\t\tconv_total += kernel_value * pixel_value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdouble check_value = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t\t\t\tdouble calculated_value = *(new_values_ptr++);\n\t\t\t\t\n\t\t\t\tif (check_value != calculated_value)\n\t\t\t\t\tstd::cout << \"Convolve_S2 optimization mismatch: \" << check_value << \" versus \" << calculated_value << std::endl;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\t\n\tTakeOverMallocedValues(new_values, 2, grid_size_);\t// takes new_values from us\n}\n\n// SIMD-accelerated convolution for 3D spatial maps\n// Uses vectorized dot products with loop reordering for contiguous memory access\nvoid SpatialMap::Convolve_S3(SpatialKernel &kernel)\n{\n\tif (spatiality_ != 3)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S3): (internal error) map spatiality 3 required.\" << EidosTerminate();\n\tif (kernel.dimensionality_ != 3)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S3): (internal error) kernel dimensionality 3 required.\" << EidosTerminate();\n\t\n\tint64_t kernel_dim_a = kernel.dim[0];\n\tint64_t kernel_dim_b = kernel.dim[1];\n\tint64_t kernel_dim_c = kernel.dim[2];\n\t\n\tif ((kernel_dim_a < 1) || (kernel_dim_a % 2 == 0) ||\n\t\t(kernel_dim_b < 1) || (kernel_dim_b % 2 == 0) ||\n\t\t(kernel_dim_c < 1) || (kernel_dim_c % 2 == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S3): (internal error) kernel dimensions must be odd.\" << EidosTerminate();\n\t\n\tint64_t dim_a = grid_size_[0], dim_b = grid_size_[1], dim_c = grid_size_[2];\n\tdouble *new_values = (double *)malloc(dim_a * dim_b * dim_c * sizeof(double));\n\t\n\tif (!new_values)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::Convolve_S3): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint64_t kernel_a_offset = -(kernel_dim_a / 2), kernel_b_offset = -(kernel_dim_b / 2), kernel_c_offset = -(kernel_dim_c / 2);\n\tdouble *kernel_values = kernel.values_;\n\tdouble *new_values_ptr = new_values;\n\t\n\tif (!periodic_a_ && !periodic_b_ && !periodic_c_)\n\t{\n\t\t// Optimized non-periodic case with SIMD\n\t\tfor (int64_t c = 0; c < dim_c; ++c)\n\t\t{\n\t\t\tdouble coverage_c = ((c == 0) || (c == dim_c - 1)) ? 0.5 : 1.0;\n\t\t\t\n\t\t\tint64_t kernel_c_first = std::max((int64_t)0, -(c + kernel_c_offset));\n\t\t\tint64_t kernel_c_last = std::min(kernel_dim_c - 1, (kernel_dim_c - 1) + (((dim_c - 1) - c) + kernel_c_offset));\n\t\t\t\n\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t{\n\t\t\t\tdouble coverage_b = ((b == 0) || (b == dim_b - 1)) ? 0.5 : 1.0;\n\t\t\t\t\n\t\t\t\tint64_t kernel_b_first = std::max((int64_t)0, -(b + kernel_b_offset));\n\t\t\t\tint64_t kernel_b_last = std::min(kernel_dim_b - 1, (kernel_dim_b - 1) + (((dim_b - 1) - b) + kernel_b_offset));\n\t\t\t\t\n\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t{\n\t\t\t\t\tdouble coverage_a = ((a == 0) || (a == dim_a - 1)) ? 0.5 : 1.0;\n\t\t\t\t\tdouble coverage = coverage_a * coverage_b * coverage_c;\n\t\t\t\t\t\n\t\t\t\t\tint64_t kernel_a_first = std::max((int64_t)0, -(a + kernel_a_offset));\n\t\t\t\t\tint64_t kernel_a_last = std::min(kernel_dim_a - 1, (kernel_dim_a - 1) + (((dim_a - 1) - a) + kernel_a_offset));\n\t\t\t\t\t\n\t\t\t\t\tdouble kernel_total = 0.0;\n\t\t\t\t\tdouble conv_total = 0.0;\n\t\t\t\t\t\n\t\t\t\t\t// Loop over c and b (outer), then vectorize over a (inner, contiguous)\n\t\t\t\t\tfor (int64_t kernel_c = kernel_c_first; kernel_c <= kernel_c_last; kernel_c++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t conv_c = c + kernel_c + kernel_c_offset;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t kernel_b = kernel_b_first; kernel_b <= kernel_b_last; kernel_b++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint64_t conv_b = b + kernel_b + kernel_b_offset;\n\t\t\t\t\t\t\tint64_t conv_a_start = a + kernel_a_first + kernel_a_offset;\n\t\t\t\t\t\t\tint64_t count = kernel_a_last - kernel_a_first + 1;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Use SIMD dot product for the contiguous a dimension\n\t\t\t\t\t\t\tEidos_SIMD::convolve_dot_product_scaled_float64(\n\t\t\t\t\t\t\t\t&kernel_values[kernel_a_first + kernel_b * kernel_dim_a + kernel_c * kernel_dim_a * kernel_dim_b],\n\t\t\t\t\t\t\t\t&values_[conv_a_start + conv_b * dim_a + conv_c * dim_a * dim_b],\n\t\t\t\t\t\t\t\tcount, coverage,\n\t\t\t\t\t\t\t\tkernel_total, conv_total);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t*(new_values_ptr++) = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// General periodic case - element by element\n\t\tfor (int64_t c = 0; c < dim_c; ++c)\n\t\t{\n\t\t\tdouble coverage_c = (!periodic_c_ && ((c == 0) || (c == dim_c - 1))) ? 0.5 : 1.0;\n\t\t\t\n\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t{\n\t\t\t\tdouble coverage_b = (!periodic_b_ && ((b == 0) || (b == dim_b - 1))) ? 0.5 : 1.0;\n\t\t\t\t\n\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t{\n\t\t\t\t\tdouble coverage_a = (!periodic_a_ && ((a == 0) || (a == dim_a - 1))) ? 0.5 : 1.0;\n\t\t\t\t\tdouble coverage = coverage_a * coverage_b * coverage_c;\n\t\t\t\t\t\n\t\t\t\t\tdouble kernel_total = 0.0;\n\t\t\t\t\tdouble conv_total = 0.0;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t kernel_c = 0; kernel_c < kernel_dim_c; kernel_c++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t conv_c = c + kernel_c + kernel_c_offset;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((conv_c < 0) || (conv_c >= dim_c))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!periodic_c_)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\twhile (conv_c < 0)\n\t\t\t\t\t\t\t\tconv_c += (dim_c - 1);\n\t\t\t\t\t\t\twhile (conv_c >= dim_c)\n\t\t\t\t\t\t\t\tconv_c -= (dim_c - 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t kernel_b = 0; kernel_b < kernel_dim_b; kernel_b++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint64_t conv_b = b + kernel_b + kernel_b_offset;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((conv_b < 0) || (conv_b >= dim_b))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!periodic_b_)\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twhile (conv_b < 0)\n\t\t\t\t\t\t\t\t\tconv_b += (dim_b - 1);\n\t\t\t\t\t\t\t\twhile (conv_b >= dim_b)\n\t\t\t\t\t\t\t\t\tconv_b -= (dim_b - 1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int64_t kernel_a = 0; kernel_a < kernel_dim_a; kernel_a++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint64_t conv_a = a + kernel_a + kernel_a_offset;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((conv_a < 0) || (conv_a >= dim_a))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tif (!periodic_a_)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\twhile (conv_a < 0)\n\t\t\t\t\t\t\t\t\t\tconv_a += (dim_a - 1);\n\t\t\t\t\t\t\t\t\twhile (conv_a >= dim_a)\n\t\t\t\t\t\t\t\t\t\tconv_a -= (dim_a - 1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tdouble kernel_value = kernel_values[kernel_a + kernel_b * kernel_dim_a + kernel_c * kernel_dim_a * kernel_dim_b] * coverage;\n\t\t\t\t\t\t\t\tdouble pixel_value = values_[conv_a + conv_b * dim_a + conv_c * dim_a * dim_b];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tkernel_total += kernel_value;\n\t\t\t\t\t\t\t\tconv_total += kernel_value * pixel_value;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t*(new_values_ptr++) = ((kernel_total > 0) ? (conv_total / kernel_total) : 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tTakeOverMallocedValues(new_values, 3, grid_size_);\t// takes new_values from us\n}\n\nvoid SpatialMap::FillRGBBuffer(uint8_t *buffer, int64_t width, int64_t height, bool flipped, bool no_interpolation)\n{\n    // This method requires spatiality 2; we just return otherwise\n    if (spatiality_ != 2)\n        return;\n    \n    int64_t xsize = grid_size_[0];\n    int64_t ysize = grid_size_[1];\n    double *values = values_;\n    bool interpolate = interpolate_ && !no_interpolation;\t// no_interpolation==true forces interpolation off\n    \n\tif (interpolate)\n\t{\n\t\tfor (int yc = 0; yc < height; yc++)\n\t\t{\n\t\t\tdouble y_fraction = (flipped ? (((height - 1) - yc) + 0.5) / height : (yc + 0.5) / height);\t\t// pixel center\n\t\t\t\n\t\t\tfor (int xc = 0; xc < width; xc++)\n\t\t\t{\n\t\t\t\t// Look up the nearest map point and get its value; interpolate if requested\n\t\t\t\tdouble x_fraction = (xc + 0.5) / width;\t\t// pixel center\n\t\t\t\tdouble value;\n\t\t\t\t\n\t\t\t\t// interpolation\n\t\t\t\tdouble x_map = x_fraction * (xsize - 1);\n\t\t\t\tdouble y_map = y_fraction * (ysize - 1);\n\t\t\t\tint x1_map = static_cast<int>(floor(x_map));\n\t\t\t\tint y1_map = static_cast<int>(floor(y_map));\n\t\t\t\tint x2_map = static_cast<int>(ceil(x_map));\n\t\t\t\tint y2_map = static_cast<int>(ceil(y_map));\n\t\t\t\tdouble fraction_x2 = x_map - x1_map;\n\t\t\t\tdouble fraction_x1 = 1.0 - fraction_x2;\n\t\t\t\tdouble fraction_y2 = y_map - y1_map;\n\t\t\t\tdouble fraction_y1 = 1.0 - fraction_y2;\n\t\t\t\tdouble value_x1_y1 = values[x1_map + y1_map * xsize] * fraction_x1 * fraction_y1;\n\t\t\t\tdouble value_x2_y1 = values[x2_map + y1_map * xsize] * fraction_x2 * fraction_y1;\n\t\t\t\tdouble value_x1_y2 = values[x1_map + y2_map * xsize] * fraction_x1 * fraction_y2;\n\t\t\t\tdouble value_x2_y2 = values[x2_map + y2_map * xsize] * fraction_x2 * fraction_y2;\n\t\t\t\t\n\t\t\t\tvalue = value_x1_y1 + value_x2_y1 + value_x1_y2 + value_x2_y2;\n\t\t\t\t\n\t\t\t\t// Given the interpolated value, look up the color, interpolating that if necessary\n\t\t\t\tdouble rgb[3];\n\t\t\t\t\n\t\t\t\tColorForValue(value, rgb);\n\t\t\t\t\n\t\t\t\t// Write the color values to the buffer\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[0] * 255.0));\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[1] * 255.0));\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[2] * 255.0));\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (int yc = 0; yc < height; yc++)\n\t\t{\n\t\t\tdouble y_fraction = (flipped ? (((height - 1) - yc) + 0.5) / height : (yc + 0.5) / height);\t\t// pixel center\n\t\t\t\n\t\t\tfor (int xc = 0; xc < width; xc++)\n\t\t\t{\n\t\t\t\t// Look up the nearest map point and get its value; interpolate if requested\n\t\t\t\tdouble x_fraction = (xc + 0.5) / width;\t\t// pixel center\n\t\t\t\tdouble value;\n\t\t\t\t\n\t\t\t\t// no interpolation\n\t\t\t\tint x_map = (int)std::round(x_fraction * (xsize - 1));\n\t\t\t\tint y_map = (int)std::round(y_fraction * (ysize - 1));\n\t\t\t\t\n\t\t\t\tvalue = values[x_map + y_map * xsize];\n\t\t\t\t\n\t\t\t\t// Given the un-interpolated value, look up the color, interpolating that if necessary\n\t\t\t\tdouble rgb[3];\n\t\t\t\t\n\t\t\t\tColorForValue(value, rgb);\n\t\t\t\t\n\t\t\t\t// Write the color values to the buffer\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[0] * 255.0));\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[1] * 255.0));\n\t\t\t\t*(buffer++) = static_cast<uint8_t>(round(rgb[2] * 255.0));\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *SpatialMap::Class(void) const\n{\n\treturn gSLiM_SpatialMap_Class;\n}\n\nvoid SpatialMap::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\\'\" << name_ << \"\\'>\";\n}\n\nEidosValue_SP SpatialMap::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_gridDimensions:\n\t\t{\n\t\t\tswitch (spatiality_)\n\t\t\t{\n\t\t\t\tcase 1: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{grid_size_[0]});\n\t\t\t\tcase 2: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{grid_size_[0], grid_size_[1]});\n\t\t\t\tcase 3: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{grid_size_[0], grid_size_[1], grid_size_[2]});\n\t\t\t\tdefault:\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name_));\n\t\t}\n\t\tcase gID_spatialBounds:\n\t\t{\n\t\t\tswitch (spatiality_)\n\t\t\t{\n\t\t\t\tcase 1: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_a0_, bounds_a1_});\n\t\t\t\tcase 2: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_a0_, bounds_b0_, bounds_a1_, bounds_b1_});\n\t\t\t\tcase 3: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_a0_, bounds_b0_, bounds_c0_, bounds_a1_, bounds_b1_, bounds_c1_});\n\t\t\t\tdefault:\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_spatiality:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(spatiality_string_));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_interpolate:\n\t\t{\n\t\t\treturn (interpolate_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::GetProperty): property tag accessed on spatial map before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid SpatialMap::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_interpolate:\n\t\t{\n\t\t\teidos_logical_t value = p_value.LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tinterpolate_ = value;\n\t\t\t\n\t\t\t// We don't need to call _ValuesChanged(), just recache display\n#if defined(SLIMGUI)\n\t\t\t// Force a display image recache in SLiMgui\n\t\t\tif (display_buffer_)\n\t\t\t{\n\t\t\t\tfree(display_buffer_);\n\t\t\t\tdisplay_buffer_ = nullptr;\n\t\t\t}\n\t\t\t// image_ does not have interpolated data, so it is not invalidated here\n#endif\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP SpatialMap::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gID_add:\t\t\t\t\treturn ExecuteMethod_add(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_blend:\t\t\t\t\treturn ExecuteMethod_blend(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_multiply:\t\t\t\treturn ExecuteMethod_multiply(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_subtract:\t\t\t\treturn ExecuteMethod_subtract(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_divide:\t\t\t\treturn ExecuteMethod_divide(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_power:\t\t\t\t\treturn ExecuteMethod_power(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_exp:\t\t\t\t\treturn ExecuteMethod_exp(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_changeColors:\t\t\treturn ExecuteMethod_changeColors(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_changeValues:\t\t\treturn ExecuteMethod_changeValues(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_gridValues:\t\t\treturn ExecuteMethod_gridValues(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_interpolate:\t\t\treturn ExecuteMethod_interpolate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mapColor:\t\t\t\treturn ExecuteMethod_mapColor(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mapImage:\t\t\t\treturn ExecuteMethod_mapImage(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mapValue:\t\t\t\treturn ExecuteMethod_mapValue(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_range:\t\t\treturn ExecuteMethod_range(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_rescale:\t\t\t\treturn ExecuteMethod_rescale(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_sampleImprovedNearbyPoint:\t\treturn ExecuteMethod_sampleImprovedNearbyPoint(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_sampleNearbyPoint:\t\treturn ExecuteMethod_sampleNearbyPoint(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_smooth:\t\t\t\treturn ExecuteMethod_smooth(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (object<SpatialMap>)add(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_add(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_add): add() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_add\", \"add()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble add_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] += add_scalar;\n\t}\n\telse\n\t{\n\t\tSpatialMap *add_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *add_map_values = add_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(add_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_add): add() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] += add_map_values[i];\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)blend(ifo<SpatialMap> x, float$ xFraction)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_blend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *xFraction_value = p_arguments[1].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_blend): blend() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_add\", \"add()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tdouble xFraction = xFraction_value->FloatAtIndex_NOCAST(0, nullptr);\n\tdouble targetFraction = 1 - xFraction;\n\t\n\tif ((xFraction < 0.0) || (xFraction > 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_blend): blend() requires xFraction to be in [0.0, 1.0].\" << EidosTerminate();\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble blend_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] = blend_scalar * xFraction + values_[i] * targetFraction;\n\t}\n\telse\n\t{\n\t\tSpatialMap *blend_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *blend_map_values = blend_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(blend_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_blend): blend() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] = blend_map_values[i] * xFraction + values_[i] * targetFraction;\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)multiply(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_multiply(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_multiply): multiply() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_multiply\", \"multiply()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble multiply_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] *= multiply_scalar;\n\t}\n\telse\n\t{\n\t\tSpatialMap *multiply_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *multiply_map_values = multiply_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(multiply_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_multiply): multiply() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] *= multiply_map_values[i];\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)subtract(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_subtract(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_subtract): subtract() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_subtract\", \"subtract()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble subtract_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] -= subtract_scalar;\n\t}\n\telse\n\t{\n\t\tSpatialMap *subtract_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *subtract_map_values = subtract_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(subtract_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_subtract): subtract() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] -= subtract_map_values[i];\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)divide(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_divide(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_divide): divide() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_divide\", \"divide()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble divide_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] /= divide_scalar;\n\t}\n\telse\n\t{\n\t\tSpatialMap *divide_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *divide_map_values = divide_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(divide_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_divide): divide() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\t\tvalues_[i] /= divide_map_values[i];\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)power(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_power(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP spatialmap_temp;\n\t\n\tif (x_value->Count() > 1)\n\t{\n\t\tif (x_value->Type() == EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_power): power() requires x to be a singleton if it is of type object (i.e., a singleton SpatialMap).\" << EidosTerminate();\n\t\t\n\t\t// handle a vector/matrix/array parameter by converting it to a spatial map and then following that code path\n\t\tspatialmap_temp = _DeriveTemporarySpatialMapWithEidosValue(x_value, \"SpatialMap::ExecuteMethod_power\", \"power()\");\n\t\tx_value = spatialmap_temp.get();\n\t}\n\t\n\tif ((x_value->Type() == EidosValueType::kValueInt) || (x_value->Type() == EidosValueType::kValueFloat))\n\t{\n\t\tdouble power_scalar = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tEidos_SIMD::pow_float64_scalar_exp(values_, power_scalar, values_, values_size_);\n\t}\n\telse\n\t{\n\t\tSpatialMap *power_map = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tdouble *power_map_values = power_map->values_;\n\t\t\n\t\tif (!IsCompatibleWithMap(power_map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_power): power() requires the target SpatialMap to be compatible with the SpatialMap supplied in x (using the same spatiality and bounds, and having the same grid resolution).\" << EidosTerminate();\n\t\t\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tEidos_SIMD::pow_float64(values_, power_map_values, values_, values_size_);\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (object<SpatialMap>)exp(void)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_exp(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// FIXME: TO BE PARALLELIZED\n\tEidos_SIMD::exp_float64(values_, values_, values_size_);\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (void)changeColors([Nif valueRange = NULL], [Ns color = NULL])\n//\nEidosValue_SP SpatialMap::ExecuteMethod_changeColors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *value_range = p_arguments[0].get();\n\tEidosValue *colors = p_arguments[1].get();\n\t\n\tTakeColorsFromEidosValues(value_range, colors, \"SpatialMap::ExecuteMethod_changeColors\", \"changeColors()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)changeValues(ifo<SpatialMap> x)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_changeValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->Type() == EidosValueType::kValueObject)\n\t{\n\t\tif (x_value->Count() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_changeValues): changeValues() requires that if x is of type object, it must be a singleton SpatialMap.\" << EidosTerminate();\n\t\t\n\t\t// If passed a SpatialMap object, we copy its values directly\n\t\tSpatialMap *x = (SpatialMap *)x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (IsCompatibleWithMapValues(x))\n\t\t{\n\t\t\tmemcpy(values_, x->values_, values_size_ * sizeof(double));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgrid_size_[0] = x->grid_size_[0];\n\t\t\tgrid_size_[1] = x->grid_size_[1];\n\t\t\tgrid_size_[2] = x->grid_size_[2];\n\t\t\tvalues_size_ = x->values_size_;\n\t\t\tvalues_ = (double *)realloc(values_, values_size_ * sizeof(double));\n\t\t\tmemcpy(values_, x->values_, values_size_ * sizeof(double));\n\t\t}\n\t\t\n\t\t_ValuesChanged();\n\t}\n\telse\n\t{\n\t\tTakeValuesFromEidosValue(x_value, \"SpatialMap::ExecuteMethod_changeValues\", \"changeValues()\");\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (float)gridValues(void)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_gridValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(values_size_);\n\t\n\tif (spatiality_ == 1)\n\t{\n\t\t// Returning a vector for the 1D case is a simple copy\n\t\tfor (int i = 0; i < values_size_; ++i)\n\t\t\tfloat_result->set_float_no_check(values_[i], i);\n\t}\n\telse\n\t{\n\t\t// In the 2D and 3D cases, a transpose/flip is needed\n\t\tint64_t col_count = grid_size_[0];\t\t// note grid_size_ got swapped above\n\t\tint64_t row_count = grid_size_[1];\n\t\tint64_t plane_count = (spatiality_ == 3) ? grid_size_[2] : 1;\n\t\t\n\t\tfor (int64_t z = 0; z < plane_count; ++z)\n\t\t{\n\t\t\tint64_t plane_offset = z * (row_count * col_count);\n\t\t\t\n\t\t\tfor (int64_t x = 0; x < col_count; ++x)\n\t\t\t\tfor (int64_t y = 0; y < row_count; ++y)\n\t\t\t\t\tfloat_result->set_float_no_check(values_[plane_offset + x + (row_count - 1 - y) * col_count], plane_offset + y + x * row_count);\n\t\t}\n\t\t\n\t\tint64_t dims[3] = {grid_size_[1], grid_size_[0], grid_size_[2]};\n\t\tfloat_result->SetDimensions(spatiality_, dims);\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (object<SpatialMap>)interpolate(integer$ factor, [string$ method = \"linear\"])\n//\nEidosValue_SP SpatialMap::ExecuteMethod_interpolate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *factor_value = p_arguments[0].get();\n\tint64_t factor = factor_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\t// the upper limit here is arbitrary, but the goal is to prevent users from blowing up their memory usage unintentionally\n\tif ((factor < 2) || (factor > 10001))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): interpolate() requires factor to be in [2, 10001], rather arbitrarily.\" << EidosTerminate();\n\t\n\tEidosValue_String *method_value = (EidosValue_String *)p_arguments[1].get();\n\tconst std::string &method_string = method_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tint method;\n\t\n\tif (method_string == \"nearest\")\n\t\tmethod = 0;\n\telse if (method_string == \"linear\")\n\t\tmethod = 1;\n\telse if (method_string == \"cubic\")\n\t\tmethod = 2;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): interpolate() requires method to be 'nearest', 'linear', or 'cubic'.\" << EidosTerminate();\n\t\n\tif ((method == 0) || (method == 1))\n\t{\n\t\t// These methods are supported directly by ValueAtPoint_S1() / ValueAtPoint_S2() / ValueAtPoint_S3()\n\t\t\n\t\t// Temporarily force interpolation on\n\t\tbool old_interpolate = interpolate_;\n\t\tinterpolate_ = (method ? true : false);\n\t\t\n\t\t// Generate the new values and set them\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\tint64_t dim_a = (factor * (grid_size_[0] - 1)) + 1;\n\t\t\t\tdouble *new_values = (double *)malloc(dim_a * sizeof(double));\n\t\t\t\tdouble *new_values_ptr = new_values;\n\t\t\t\tdouble point_vec[1];\n\t\t\t\t\n\t\t\t\tif (!new_values)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t{\n\t\t\t\t\tpoint_vec[0] = a / (double)(dim_a - 1);\n\t\t\t\t\t\n\t\t\t\t\t*(new_values_ptr++) = ValueAtPoint_S1(point_vec);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTakeOverMallocedValues(new_values, 1, &dim_a);\t// takes new_values from us\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\tint64_t dim_a = (factor * (grid_size_[0] - 1)) + 1, dim_b = (factor * (grid_size_[1] - 1)) + 1;\n\t\t\t\tdouble *new_values = (double *)malloc(dim_a * dim_b * sizeof(double));\n\t\t\t\tdouble *new_values_ptr = new_values;\n\t\t\t\tdouble point_vec[2];\n\t\t\t\t\n\t\t\t\tif (!new_values)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t\t{\n\t\t\t\t\tpoint_vec[1] = b / (double)(dim_b - 1);\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t\t{\n\t\t\t\t\t\tpoint_vec[0] = a / (double)(dim_a - 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\t*(new_values_ptr++) = ValueAtPoint_S2(point_vec);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint64_t dims[2] = {dim_a, dim_b};\n\t\t\t\tTakeOverMallocedValues(new_values, 2, dims);\t// takes new_values from us\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\tint64_t dim_a = (factor * (grid_size_[0] - 1)) + 1, dim_b = (factor * (grid_size_[1] - 1)) + 1, dim_c = (factor * (grid_size_[2] - 1)) + 1;\n\t\t\t\tdouble *new_values = (double *)malloc(dim_a * dim_b * dim_c * sizeof(double));\n\t\t\t\tdouble *new_values_ptr = new_values;\n\t\t\t\tdouble point_vec[3];\n\t\t\t\t\n\t\t\t\tif (!new_values)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int64_t c = 0; c < dim_c; ++c)\n\t\t\t\t{\n\t\t\t\t\tpoint_vec[2] = c / (double)(dim_c - 1);\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t\t\t{\n\t\t\t\t\t\tpoint_vec[1] = b / (double)(dim_b - 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpoint_vec[0] = a / (double)(dim_a - 1);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t*(new_values_ptr++) = ValueAtPoint_S3(point_vec);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint64_t dims[3] = {dim_a, dim_b, dim_c};\n\t\t\t\tTakeOverMallocedValues(new_values, 3, dims);\t// takes new_values from us\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: break;\n\t\t}\n\t\t\n\t\t// Restore the user's interpolation value\n\t\tinterpolate_ = old_interpolate;\n\t}\n\telse\t// method == 3\n\t{\n\t\t// This is cubic/bicubic interpolation; we use the GSL to do this for us\n\t\t// Require all/nothing for periodicity\n\t\tif (((spatiality_ == 2) && (periodic_a_ != periodic_b_)) ||\n\t\t\t((spatiality_ == 3) && ((periodic_a_ != periodic_b_) || (periodic_a_ != periodic_c_))))\n\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): interpolate() currently requires the spatial map to be either entirely non-periodic, or entirely periodic, for 'cubic' interpolation.\" << EidosTerminate(nullptr);\n\t\t\n\t\tbool periodic = periodic_a_;\t// now guaranteed to apply to all dimensions\n\t\t\n\t\tswitch (spatiality_)\n\t\t{\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\t// cubic interpolation\n\t\t\t\tint64_t dim_a = (factor * (grid_size_[0] - 1)) + 1;\n\t\t\t\tdouble *new_values = (double *)malloc(dim_a * sizeof(double));\n\t\t\t\tdouble *x = (double *)malloc(grid_size_[0] * sizeof(double));\n\t\t\t\tdouble *y = (double *)malloc(grid_size_[0] * sizeof(double));\n\t\t\t\t\n\t\t\t\tif (!new_values || !x || !y)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// set up coordinates on our grid, not in user coordinates, for simplicity\n\t\t\t\tfor (int i = 0; i < grid_size_[0]; ++i)\n\t\t\t\t{\n\t\t\t\t\tx[i] = i;\n\t\t\t\t\ty[i] = values_[i];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgsl_interp_accel *acc = gsl_interp_accel_alloc();\n\t\t\t\tauto interpolation_type = periodic ? gsl_interp_cspline_periodic : gsl_interp_cspline;\n\t\t\t\tgsl_spline *spline = gsl_spline_alloc(interpolation_type, grid_size_[0]);\n\t\t\t\tdouble *new_values_ptr = new_values;\n\t\t\t\tdouble scale = 1.0 / factor;\n\t\t\t\t\n\t\t\t\tgsl_spline_init(spline, x, y, grid_size_[0]);\n\t\t\t\t\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t\t*(new_values_ptr++) = gsl_spline_eval(spline, a * scale, acc);\n\t\t\t\t\n\t\t\t\tgsl_spline_free(spline);\n\t\t\t\tgsl_interp_accel_free(acc);\n\t\t\t\tfree(x);\n\t\t\t\tfree(y);\n\t\t\t\t\n\t\t\t\tTakeOverMallocedValues(new_values, 1, &dim_a);\t// takes new_values from us\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\t// bicubic interpolation\n\t\t\t\tif ((grid_size_[0] < 4) || (grid_size_[1] < 4))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): bicubic interpolation requires a starting map with a grid size at least 4x4.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// the periodic boundaries case is similar to the non-periodic case, except that we perform\n\t\t\t\t// the (non-periodic) interpolation on an expanded grid with margins of 20 grid points on\n\t\t\t\t// all sides (20 comes from here: https://stackoverflow.com/a/25106574/2752221 as a suggested\n\t\t\t\t// margin to produce acceptably small error).  Then we use the central part of that grid,\n\t\t\t\t// minus the margins.\n\t\t\t\t\n\t\t\t\tint64_t margin = periodic ? 20 : 0;\n\t\t\t\tint64_t gs0_with_margins = grid_size_[0] + margin * 2;\n\t\t\t\tint64_t gs1_with_margins = grid_size_[1] + margin * 2;\n\t\t\t\t\n\t\t\t\t// dim_a and dim_b are the dimensions of the final grid we want, without margins; new_values is the final values\n\t\t\t\tint64_t dim_a = (factor * (grid_size_[0] - 1)) + 1, dim_b = (factor * (grid_size_[1] - 1)) + 1;\n\t\t\t\tdouble *new_values = (double *)malloc(dim_a * dim_b * sizeof(double));\n\t\t\t\t\n\t\t\t\t// x and y are the coordinates of the grid with margins; z is the original values to interpolate, with margins\n\t\t\t\tdouble *x = (double *)malloc(gs0_with_margins * sizeof(double));\n\t\t\t\tdouble *y = (double *)malloc(gs1_with_margins * sizeof(double));\n\t\t\t\tdouble *z = (double *)malloc(gs0_with_margins * gs1_with_margins * sizeof(double));\n\t\t\t\t\n\t\t\t\tif (!new_values || !x || !y || !z)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// set up coordinates on our grid with margins, not in user coordinates, for simplicity\n\t\t\t\tfor (int i = 0; i < gs0_with_margins; ++i)\n\t\t\t\t\tx[i] = i;\n\t\t\t\tfor (int i = 0; i < gs1_with_margins; ++i)\n\t\t\t\t\ty[i] = i;\n\t\t\t\t\n\t\t\t\tconst gsl_interp2d_type *T = gsl_interp2d_bicubic;\n\t\t\t\tgsl_spline2d *spline = gsl_spline2d_alloc(T, gs0_with_margins, gs1_with_margins);\n\t\t\t\tgsl_interp_accel *xacc = gsl_interp_accel_alloc();\n\t\t\t\tgsl_interp_accel *yacc = gsl_interp_accel_alloc();\n\t\t\t\tdouble *new_values_ptr = new_values;\n\t\t\t\tdouble scale = 1.0 / factor;\n\t\t\t\t\n\t\t\t\tif (!periodic)\n\t\t\t\t{\n\t\t\t\t\t// in the non-periodic case, there are no margins so we can use our grid values directly\n\t\t\t\t\t// the periodic case with margin==0 reduces to this, so this is just optimization\n\t\t\t\t\tfor (int64_t b = 0; b < gs1_with_margins; ++b)\n\t\t\t\t\t\tfor (int64_t a = 0; a < gs0_with_margins; ++a)\n\t\t\t\t\t\t\tgsl_spline2d_set(spline, z, a, b, values_[a + b * grid_size_[0]]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// in the periodic case, we have to add the margins, so there is some futzing around\n\t\t\t\t\t// note that we repeat (grid_size_[0] - 1) and (grid_size_[1] - 1) elements, because\n\t\t\t\t\t// the last column/row ought to be duplicates of the first column/row (we don't check)\n\t\t\t\t\t// the \"+ (grid_size_[1] - 1) * 10)\" term is to make things positive so % is not wonky\n\t\t\t\t\tfor (int64_t b = 0; b < gs1_with_margins; ++b)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t original_grid_b = (b - margin + (grid_size_[1] - 1) * 10) % (grid_size_[1] - 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t a = 0; a < gs0_with_margins; ++a)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint64_t original_grid_a = (a - margin + (grid_size_[0] - 1) * 10) % (grid_size_[0] - 1);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgsl_spline2d_set(spline, z, a, b, values_[original_grid_a + original_grid_b * grid_size_[0]]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgsl_spline2d_init(spline, x, y, z, gs0_with_margins, gs1_with_margins);\n\t\t\t\t\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tif (!periodic)\n\t\t\t\t{\n\t\t\t\t\t// in the non-periodic case, there are no margins so we can extract grid values directly\n\t\t\t\t\t// the periodic case with margin==0 reduces to this, so this is just optimization\n\t\t\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t\t\t\t*(new_values_ptr++) = gsl_spline2d_eval(spline, a * scale, b * scale, xacc, yacc);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// in the periodic case, we want to extract grid values from the central area, within the margins\n\t\t\t\t\t// recall that (factor-1) values are inserted between each grid value, so for interpolate() with\n\t\t\t\t\t// b==0 with margin==2 and factor==3, we want to start at 6: M**M**X, X is at position 6; when\n\t\t\t\t\t// non-periodic, margin==0 and so offset==0.\n\t\t\t\t\tint64_t offset = margin * factor;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t b = 0; b < dim_b; ++b)\n\t\t\t\t\t\tfor (int64_t a = 0; a < dim_a; ++a)\n\t\t\t\t\t\t\t*(new_values_ptr++) = gsl_spline2d_eval(spline, (a + offset) * scale, (b + offset) * scale, xacc, yacc);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgsl_spline2d_free(spline);\n\t\t\t\tgsl_interp_accel_free(xacc);\n\t\t\t\tgsl_interp_accel_free(yacc);\n\t\t\t\tfree(x);\n\t\t\t\tfree(y);\n\t\t\t\tfree(z);\n\t\t\t\t\n\t\t\t\tint64_t dims[2] = {dim_a, dim_b};\n\t\t\t\tTakeOverMallocedValues(new_values, 2, dims);\t// takes new_values from us\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\t// tricubic interpolation - not supported by the GSL\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_interpolate): cubic interpolation is not currently supported for 3D spatial maps; please open a feature request if you need this.\" << EidosTerminate(nullptr);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: break;\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (string)mapColor(numeric value)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_mapColor(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *values = p_arguments[0].get();\n\t\n\t// mapColor() does not utilize the default grayscale ramp; if the user wants color, they need to set up a color map\n\tif (n_colors_ == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_mapColor): mapColor() no color map defined for spatial map.\" << EidosTerminate();\n\t\n\tint value_count = values->Count();\n\tEidosValue_String *string_return = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(value_count);\n\tEidosValue_SP result_SP = EidosValue_SP(string_return);\n\t\n\tfor (slim_popsize_t value_index = 0; value_index < value_count; value_index++)\n\t{\n\t\tdouble value = values->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\tdouble rgb[3];\n\t\tchar hex_chars[8];\n\t\t\n\t\tColorForValue(value, rgb);\n\t\tEidos_GetColorString(rgb[0], rgb[1], rgb[2], hex_chars);\n\t\tstring_return->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(object<Image>$)mapImage([Ni$ width = NULL], [Ni$ height = NULL], [logical$ centers = F], [logical$ color = T])\n//\nEidosValue_SP SpatialMap::ExecuteMethod_mapImage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *width_value = p_arguments[0].get();\n\tEidosValue *height_value = p_arguments[1].get();\n\tEidosValue *centers_value = p_arguments[2].get();\n\tEidosValue *color_value = p_arguments[3].get();\n\t\n\tif (spatiality_ != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_mapImage): mapImage() can only generate an image for 2D spatial maps.\" << EidosTerminate();\n\t\n\tint64_t image_width = grid_size_[0], image_height = grid_size_[1];\n\t\n\tif (width_value->Type() != EidosValueType::kValueNULL)\n\t\timage_width = width_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (height_value->Type() != EidosValueType::kValueNULL)\n\t\timage_height = height_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((image_width <= 0) || (image_width > 100000) || (image_height <= 0) || (image_height > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_mapImage): mapImage() requires width and height values to be in [1, 100000].\" << EidosTerminate();\n\t\n\tbool color = color_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (color && (n_colors_ == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_mapImage): mapImage() requires a defined color map for the spatial map with color=T; use color=F to get a grayscale image, or define a color map in SpatialMap().\" << EidosTerminate();\n\t\n\tEidosImage *image = new EidosImage(image_width, image_height, !color);\n\tunsigned char * const data = image->Data();\n\tunsigned char *data_ptr = data;\n\tbool centers = centers_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (centers)\n\t{\n\t\t// grid lines are defined at [0, ..., 1] with (image_width + 1) values,\n\t\t// and [0, ..., 1] with (image_height + 1) values, and samples are\n\t\t// taken at the midpoints between the grid lines\n\t\tdouble point[2];\n\t\t\n\t\tfor (int y = 0; y < image_height; ++y)\n\t\t{\n\t\t\tpoint[1] = 1.0 - ((y + 0.5) / (double)image_height);  // (y/image_height + (y+1)/image_height) / 2\n\t\t\t\n\t\t\tfor (int x = 0; x < image_width; ++x)\n\t\t\t{\n\t\t\t\tpoint[0] = (x + 0.5) / (double)image_width;  // (x/image_width + (x+1)/image_width) / 2\n\t\t\t\t\n\t\t\t\tdouble map_value = ValueAtPoint_S2(point);\n\t\t\t\t\n\t\t\t\tif (color)\n\t\t\t\t{\n\t\t\t\t\tdouble rgb[3];\n\t\t\t\t\t\n\t\t\t\t\tColorForValue(map_value, rgb);\n\t\t\t\t\t\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[0], 0.0), 1.0) * 255.0);\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[1], 0.0), 1.0) * 255.0);\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[2], 0.0), 1.0) * 255.0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(map_value, 0.0), 1.0) * 255.0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// grid lines are defined at [0, ..., 1] with image_width values,\n\t\t// and [0, ..., 1] with image_height values, and samples are\n\t\t// taken at the grid lines\n\t\tdouble point[2];\n\t\t\n\t\tfor (int y = 0; y < image_height; ++y)\n\t\t{\n\t\t\tpoint[1] = 1.0 - (y / (double)(image_height - 1));\n\t\t\t\n\t\t\tfor (int x = 0; x < image_width; ++x)\n\t\t\t{\n\t\t\t\tpoint[0] = x / (double)(image_width - 1);\n\t\t\t\t\n\t\t\t\tdouble map_value = ValueAtPoint_S2(point);\n\t\t\t\t\n\t\t\t\tif (color)\n\t\t\t\t{\n\t\t\t\t\tdouble rgb[3];\n\t\t\t\t\t\n\t\t\t\t\tColorForValue(map_value, rgb);\n\t\t\t\t\t\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[0], 0.0), 1.0) * 255.0);\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[1], 0.0), 1.0) * 255.0);\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(rgb[2], 0.0), 1.0) * 255.0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t*(data_ptr++) = (unsigned char)round(std::min(std::max(map_value, 0.0), 1.0) * 255.0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tEidosValue_SP result_SP(EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(image, gEidosImage_Class)));\n\t\n\t// image is now retained by result_SP, so we can release it\n\timage->Release();\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (float)mapValue(float point)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_mapValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point = p_arguments[0].get();\n\t\n\t// Note that point is required to already be in terms of our spatiality; if we are an \"xz\" map, it must contain \"xz\" values\n\t// Also note that we clamp coordinates here, whether they are periodic or not; the caller should use pointPeriodic()\n\tif (point->Count() % spatiality_ != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_mapValue): mapValue() length of point must match spatiality of map \" << name_ << \", or be a multiple thereof.\" << EidosTerminate();\n\t\n\tint x_count = point->Count() / spatiality_;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tconst double *point_data = point->FloatData();\n\t\n\t// need to parallelize the three loops below separately now; disabling this parallelization for now\n\t//EIDOS_THREAD_COUNT(gEidos_OMP_threads_SPATIAL_MAP_VALUE);\n//#pragma omp parallel for schedule(static) default(none) shared(x_count) firstprivate(point_data, float_result) if(x_count >= EIDOS_OMPMIN_SPATIAL_MAP_VALUE) num_threads(thread_count)\n\t\n\t// It's very common for spatial bounds to be [0, 1] or [0, x] rather than the fully general case,\n\t// so we actually optimize all of the cases here\n\t\n\tswitch (spatiality_)\t// NOLINT(*-missing-default-case) : our spatiality is always in [1,3], and we can't throw from a parallel region\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tif (!interpolate_)\n\t\t\t{\n\t\t\t\t// without interpolation, use the inline version of ValueAtPoint_S1()\n\t\t\t\tif (bounds_a0_ == 0.0)\n\t\t\t\t{\n\t\t\t\t\tif (bounds_a1_ == 1.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_index]);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1_NOINTERPOLATE(a), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_index] / bounds_a1_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1_NOINTERPOLATE(a), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 1D case without interpolation\n\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble a = SLiMClampCoordinate((point_data[0 + value_index] - bounds_a0_) / (bounds_a1_ - bounds_a0_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1_NOINTERPOLATE(a), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (bounds_a0_ == 0.0)\n\t\t\t\t{\n\t\t\t\t\tif (bounds_a1_ == 1.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_index];\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_index] / bounds_a1_;\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 1D case\n\t\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble point_vec[1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble a = (point_data[0 + value_index] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S1(point_vec), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tif (!interpolate_)\n\t\t\t{\n\t\t\t\t// without interpolation, use the inline version of ValueAtPoint_S2()\n\t\t\t\tif ((bounds_a0_ == 0.0) && (bounds_b0_ == 0.0))\n\t\t\t\t{\n\t\t\t\t\tif ((bounds_a1_ == 1.0) && (bounds_b1_ == 1.0))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_offset]);\n\t\t\t\t\t\t\tdouble b = SLiMClampCoordinate(point_data[1 + value_offset]);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2_NOINTERPOLATE(a, b), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_offset] / bounds_a1_);\n\t\t\t\t\t\t\tdouble b = SLiMClampCoordinate(point_data[1 + value_offset] / bounds_b1_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2_NOINTERPOLATE(a, b), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 2D case without interpolation\n\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble a = SLiMClampCoordinate((point_data[0 + value_offset] - bounds_a0_) / (bounds_a1_ - bounds_a0_));\n\t\t\t\t\t\tdouble b = SLiMClampCoordinate((point_data[1 + value_offset] - bounds_b0_) / (bounds_b1_ - bounds_b0_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2_NOINTERPOLATE(a, b), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((bounds_a0_ == 0.0) && (bounds_b0_ == 0.0))\n\t\t\t\t{\n\t\t\t\t\tif ((bounds_a1_ == 1.0) && (bounds_b1_ == 1.0))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[2];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_offset];\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble b = point_data[1 + value_offset];\n\t\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[2];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_offset] / bounds_a1_;\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble b = point_data[1 + value_offset] / bounds_b1_;\n\t\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 2D case\n\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble point_vec[2];\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble a = (point_data[0 + value_offset] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble b = (point_data[1 + value_offset] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S2(point_vec), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tif (!interpolate_)\n\t\t\t{\n\t\t\t\t// without interpolation, use the inline version of ValueAtPoint_S3()\n\t\t\t\tif ((bounds_a0_ == 0.0) && (bounds_b0_ == 0.0) && (bounds_c0_ == 0.0))\n\t\t\t\t{\n\t\t\t\t\tif ((bounds_a1_ == 1.0) && (bounds_b1_ == 1.0) && (bounds_c1_ == 1.0))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_offset]);\n\t\t\t\t\t\t\tdouble b = SLiMClampCoordinate(point_data[1 + value_offset]);\n\t\t\t\t\t\t\tdouble c = SLiMClampCoordinate(point_data[2 + value_offset]);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3_NOINTERPOLATE(a, b, c), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble a = SLiMClampCoordinate(point_data[0 + value_offset] / bounds_a1_);\n\t\t\t\t\t\t\tdouble b = SLiMClampCoordinate(point_data[1 + value_offset] / bounds_b1_);\n\t\t\t\t\t\t\tdouble c = SLiMClampCoordinate(point_data[2 + value_offset] / bounds_c1_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3_NOINTERPOLATE(a, b, c), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 3D case without interpolation\n\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble a = SLiMClampCoordinate((point_data[0 + value_offset] - bounds_a0_) / (bounds_a1_ - bounds_a0_));\n\t\t\t\t\t\tdouble b = SLiMClampCoordinate((point_data[1 + value_offset] - bounds_b0_) / (bounds_b1_ - bounds_b0_));\n\t\t\t\t\t\tdouble c = SLiMClampCoordinate((point_data[2 + value_offset] - bounds_c0_) / (bounds_c1_ - bounds_c0_));\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3_NOINTERPOLATE(a, b, c), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((bounds_a0_ == 0.0) && (bounds_b0_ == 0.0) && (bounds_c0_ == 0.0))\n\t\t\t\t{\n\t\t\t\t\tif ((bounds_a1_ == 1.0) && (bounds_b1_ == 1.0) && (bounds_c1_ == 1.0))\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[3];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_offset];\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble b = point_data[1 + value_offset];\n\t\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble c = point_data[2 + value_offset];\n\t\t\t\t\t\t\tpoint_vec[2] = SLiMClampCoordinate(c);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble point_vec[3];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble a = point_data[0 + value_offset] / bounds_a1_;\n\t\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble b = point_data[1 + value_offset] / bounds_b1_;\n\t\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble c = point_data[2 + value_offset] / bounds_c1_;\n\t\t\t\t\t\t\tpoint_vec[2] = SLiMClampCoordinate(c);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3(point_vec), value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// full 3D case\n\t\t\t\t\tfor (int value_index = 0, value_offset = 0; value_index < x_count; ++value_index, value_offset += 3)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble point_vec[3];\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble a = (point_data[0 + value_offset] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\t\t\tpoint_vec[0] = SLiMClampCoordinate(a);\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble b = (point_data[1 + value_offset] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\t\t\t\tpoint_vec[1] = SLiMClampCoordinate(b);\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble c = (point_data[2 + value_offset] - bounds_c0_) / (bounds_c1_ - bounds_c0_);\n\t\t\t\t\t\tpoint_vec[2] = SLiMClampCoordinate(c);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result->set_float_no_check(ValueAtPoint_S3(point_vec), value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (float)range(void)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_range(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(2);\n\t\n\tfloat_result->set_float_no_check(values_min_, 0);\n\tfloat_result->set_float_no_check(values_max_, 1);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (object<SpatialMap>)rescale([numeric$ min = 0.0], [numeric$ max = 1.0])\n//\nEidosValue_SP SpatialMap::ExecuteMethod_rescale(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *min_value = p_arguments[0].get();\n\tEidosValue *max_value = p_arguments[1].get();\n\t\n\tdouble min = min_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble max = max_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tif (!std::isfinite(min) || !std::isfinite(max) || (min >= max))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_rescale): rescale() requires that min and max are finite, and that min < max.\" << EidosTerminate(nullptr);\n\t\n\tif (values_max_ == values_min_)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_rescale): rescale() requires that the current map values have a non-zero range width (i.e., a maximum value that is greater than the minimum value).\" << EidosTerminate(nullptr);\n\t\n\t// rescale from our current range [values_min_, values_max_] to the new range [min, max]\n\tdouble old_range_width = values_max_ - values_min_;\n\tdouble new_range_width = max - min;\n\t\n\t// FIXME: TO BE PARALLELIZED\n\tfor (int64_t i = 0; i < values_size_; ++i)\n\t\tvalues_[i] = ((values_[i] - values_min_) / old_range_width) * new_range_width + min;\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t- (float)sampleImprovedNearbyPoint(float point, float$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// Our arguments go to SpatialKernel::SpatialKernel(), which creates the kernel object that we use\n\tEidosValue *point_value = p_arguments[0].get();\n\tsize_t coordinate_count = point_value->Count();\n\t\n\tif (coordinate_count % spatiality_ != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint): sampleImprovedNearbyPoint() requires the length of point to be a multiple of the spatial map's spatiality (i.e., to contain complete points).\" << EidosTerminate(nullptr);\n\t\n\tint point_count = (int)(coordinate_count / spatiality_);\n\t\n\tif (point_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tEidosValue *maxDistance_value = p_arguments[1].get();\n\tdouble max_distance = maxDistance_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(spatiality_, max_distance, p_arguments, 2, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif ((kernel_count != 1) && (kernel_count != point_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleImprovedNearbyPoint): sampleImprovedNearbyPoint() requires that the number of spatial kernels defined (by the supplied kernel-definition arguments) either must be 1, or must equal the number of points being processed (\" << kernel_count << \" kernels defined; \" << (int)(point_count / spatiality_) << \" individuals processed).\" << EidosTerminate();\n\t\n\tSpatialKernel kernel0(spatiality_, max_distance, p_arguments, 2, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 2\n\t\n\tif (values_min_ < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint): sampleImprovedNearbyPoint() requires that all map values are non-negative.\" << EidosTerminate(nullptr);\n\t\n\t// Require all/nothing for periodicity\n\tif (((spatiality_ == 2) && (periodic_a_ != periodic_b_)) ||\n\t\t((spatiality_ == 3) && ((periodic_a_ != periodic_b_) || (periodic_a_ != periodic_c_))))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleImprovedNearbyPoint): sampleImprovedNearbyPoint() currently requires the spatial map to be either entirely non-periodic, or entirely periodic.\" << EidosTerminate(nullptr);\n\t\n\tbool periodic = periodic_a_;\t// now guaranteed to apply to all dimensions\n\t\n\tconst double *point_buf = point_value->FloatData();\n\tconst double *point_buf_ptr = point_buf;\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(coordinate_count);\n\tdouble *result_ptr = float_result->data_mutable();\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tif (spatiality_ == 1)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\t\n\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\tdouble displaced_point[1];\n\t\t\t\n\t\t\tif (periodic)\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\tkernel.DrawDisplacement_S1(displaced_point);\n\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tkernel.DrawDisplacement_S1(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t}\n\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_));\n\t\t\t}\n\t\t\t\n\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\tdouble rescaled_point[1], rescaled_displaced[1];\n\t\t\t\n\t\t\trescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\trescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\n\t\t\t// Metropolis-Hastings: move to the new point if it is better, otherwise stay with probability equal to ratio of map values\n\t\t\tdouble original_map_value = ValueAtPoint_S1(rescaled_point);\n\t\t\tdouble map_value = ValueAtPoint_S1(rescaled_displaced);\n\t\t\t\n\t\t\tif ((map_value > original_map_value) || (map_value > original_map_value * Eidos_rng_uniform_doubleCO(rng_64)))\n\t\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t\telse\n\t\t\t\t*(result_ptr++) = point_a;\n\t\t}\n\t}\n\telse if (spatiality_ == 2)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\tdouble point_b = *(point_buf_ptr)++;\n\t\t\t\n\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\tdouble displaced_point[2];\n\t\t\t\n\t\t\tif (periodic)\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\tkernel.DrawDisplacement_S2(displaced_point);\n\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[1] < 0.0)\n\t\t\t\t\tdisplaced_point[1] += bounds_b1_;\n\t\t\t\twhile (displaced_point[1] > bounds_b1_)\n\t\t\t\t\tdisplaced_point[1] -= bounds_b1_;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tkernel.DrawDisplacement_S2(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t}\n\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||\n\t\t\t\t\t   (displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_));\n\t\t\t}\n\t\t\t\n\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\tdouble rescaled_point[2], rescaled_displaced[2];\n\t\t\t\n\t\t\trescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\trescaled_point[1] = (point_b - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\trescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\trescaled_displaced[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\t\n\t\t\t// Metropolis-Hastings: move to the new point if it is better, otherwise stay with probability equal to ratio of map values\n\t\t\tdouble original_map_value = ValueAtPoint_S2(rescaled_point);\n\t\t\tdouble map_value = ValueAtPoint_S2(rescaled_displaced);\n\t\t\t\n\t\t\tif ((map_value > original_map_value) || (map_value > original_map_value * Eidos_rng_uniform_doubleCO(rng_64)))\n\t\t\t{\n\t\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t\t\t*(result_ptr++) = displaced_point[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*(result_ptr++) = point_a;\n\t\t\t\t*(result_ptr++) = point_b;\n\t\t\t}\n\t\t}\n\t}\n\telse // (spatiality_ == 3)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\tdouble point_b = *(point_buf_ptr)++;\n\t\t\tdouble point_c = *(point_buf_ptr)++;\n\t\t\t\n\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\tdouble displaced_point[3];\n\t\t\t\n\t\t\tif (periodic)\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\tkernel.DrawDisplacement_S3(displaced_point);\n\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\tdisplaced_point[2] += point_c;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[1] < 0.0)\n\t\t\t\t\tdisplaced_point[1] += bounds_b1_;\n\t\t\t\twhile (displaced_point[1] > bounds_b1_)\n\t\t\t\t\tdisplaced_point[1] -= bounds_b1_;\n\t\t\t\t\n\t\t\t\twhile (displaced_point[2] < 0.0)\n\t\t\t\t\tdisplaced_point[2] += bounds_c1_;\n\t\t\t\twhile (displaced_point[2] > bounds_c1_)\n\t\t\t\t\tdisplaced_point[2] -= bounds_c1_;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tkernel.DrawDisplacement_S3(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\tdisplaced_point[2] += point_c;\n\t\t\t\t}\n\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||\n\t\t\t\t\t   (displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_) ||\n\t\t\t\t\t   (displaced_point[2] < bounds_c0_) || (displaced_point[2] > bounds_c1_));\n\t\t\t}\n\t\t\t\n\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\tdouble rescaled_point[3], rescaled_displaced[3];\n\t\t\t\n\t\t\trescaled_point[0] = (point_a - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\trescaled_point[1] = (point_b - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\trescaled_point[2] = (point_c - bounds_c0_) / (bounds_c1_ - bounds_c0_);\n\t\t\trescaled_displaced[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\trescaled_displaced[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\trescaled_displaced[2] = (displaced_point[2] - bounds_c0_) / (bounds_c1_ - bounds_c0_);\n\t\t\t\n\t\t\t// Metropolis-Hastings: move to the new point if it is better, otherwise stay with probability equal to ratio of map values\n\t\t\tdouble original_map_value = ValueAtPoint_S3(rescaled_point);\n\t\t\tdouble map_value = ValueAtPoint_S3(rescaled_displaced);\n\t\t\t\n\t\t\tif ((map_value > original_map_value) || (map_value > original_map_value * Eidos_rng_uniform_doubleCO(rng_64)))\n\t\t\t{\n\t\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t\t\t*(result_ptr++) = displaced_point[1];\n\t\t\t\t*(result_ptr++) = displaced_point[2];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*(result_ptr++) = point_a;\n\t\t\t\t*(result_ptr++) = point_b;\n\t\t\t\t*(result_ptr++) = point_c;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (float)sampleNearbyPoint(float point, float$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_sampleNearbyPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// Our arguments go to SpatialKernel::SpatialKernel(), which creates the kernel object that we use\n\tEidosValue *point_value = p_arguments[0].get();\n\tsize_t coordinate_count = point_value->Count();\n\t\n\tif (coordinate_count % spatiality_ != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() requires the length of point to be a multiple of the spatial map's spatiality (i.e., to contain complete points).\" << EidosTerminate(nullptr);\n\t\n\tint point_count = (int)(coordinate_count / spatiality_);\n\t\n\tif (point_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tEidosValue *maxDistance_value = p_arguments[1].get();\n\tdouble max_distance = maxDistance_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(spatiality_, max_distance, p_arguments, 2, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif ((kernel_count != 1) && (kernel_count != point_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() requires that the number of spatial kernels defined (by the supplied kernel-definition arguments) either must be 1, or must equal the number of points being processed (\" << kernel_count << \" kernels defined; \" << (int)(point_count / spatiality_) << \" individuals processed).\" << EidosTerminate();\n\t\n\tSpatialKernel kernel0(spatiality_, max_distance, p_arguments, 2, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 2\n\t\n\t// Require all/nothing for periodicity\n\tif (((spatiality_ == 2) && (periodic_a_ != periodic_b_)) ||\n\t\t((spatiality_ == 3) && ((periodic_a_ != periodic_b_) || (periodic_a_ != periodic_c_))))\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() currently requires the spatial map to be either entirely non-periodic, or entirely periodic.\" << EidosTerminate(nullptr);\n\t\n\tbool periodic = periodic_a_;\t// now guaranteed to apply to all dimensions\n\t\n\tconst double *point_buf = point_value->FloatData();\n\tconst double *point_buf_ptr = point_buf;\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(coordinate_count);\n\tdouble *result_ptr = float_result->data_mutable();\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tif (spatiality_ == 1)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\tdouble displaced_point[1];\n\t\t\tdouble map_value;\n\t\t\tint num_tries = 0;\n\t\t\t\n\t\t\t// rejection sample to draw a displaced point from the product of the kernel times the map\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() failed to generate a successful nearby point by rejection sampling after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (periodic)\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\t\tkernel.DrawDisplacement_S1(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\tkernel.DrawDisplacement_S1(displaced_point);\n\t\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\t}\n\t\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\t\tdouble rescaled_point[1];\n\t\t\t\t\n\t\t\t\trescaled_point[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\tmap_value = ValueAtPoint_S1(rescaled_point);\n\t\t\t}\n\t\t\twhile (values_max_ * Eidos_rng_uniform_doubleCO(rng_64) > map_value);\n\t\t\t\n\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t}\n\t}\n\telse if (spatiality_ == 2)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\tdouble point_b = *(point_buf_ptr)++;\n\t\t\tdouble displaced_point[2];\n\t\t\tdouble map_value;\n\t\t\tint num_tries = 0;\n\t\t\t\n\t\t\t// rejection sample to draw a displaced point from the product of the kernel times the map\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() failed to generate a successful nearby point by rejection sampling after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (periodic)\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\t\tkernel.DrawDisplacement_S2(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[1] < 0.0)\n\t\t\t\t\t\tdisplaced_point[1] += bounds_b1_;\n\t\t\t\t\twhile (displaced_point[1] > bounds_b1_)\n\t\t\t\t\t\tdisplaced_point[1] -= bounds_b1_;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\tkernel.DrawDisplacement_S2(displaced_point);\n\t\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\t}\n\t\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||\n\t\t\t\t\t\t   (displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\t\tdouble rescaled_point[2];\n\t\t\t\t\n\t\t\t\trescaled_point[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\trescaled_point[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\t\tmap_value = ValueAtPoint_S2(rescaled_point);\n\t\t\t}\n\t\t\twhile (values_max_ * Eidos_rng_uniform_doubleCO(rng_64) > map_value);\n\t\t\t\n\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t\t*(result_ptr++) = displaced_point[1];\n\t\t}\n\t}\n\telse // (spatiality_ == 3)\n\t{\n\t\t// FIXME: TO BE PARALLELIZED\n\t\tfor (int point_index = 0; point_index < point_count; point_index++)\n\t\t{\n\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(spatiality_, max_distance, p_arguments, 2, point_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\tdouble point_a = *(point_buf_ptr)++;\n\t\t\tdouble point_b = *(point_buf_ptr)++;\n\t\t\tdouble point_c = *(point_buf_ptr)++;\n\t\t\tdouble displaced_point[3];\n\t\t\tdouble map_value;\n\t\t\tint num_tries = 0;\n\t\t\t\n\t\t\t// rejection sample to draw a displaced point from the product of the kernel times the map\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_sampleNearbyPoint): sampleNearbyPoint() failed to generate a successful nearby point by rejection sampling after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (periodic)\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, then enforce periodic boundaries\n\t\t\t\t\tkernel.DrawDisplacement_S3(displaced_point);\n\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\tdisplaced_point[2] += point_c;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[0] < 0.0)\n\t\t\t\t\t\tdisplaced_point[0] += bounds_a1_;\n\t\t\t\t\twhile (displaced_point[0] > bounds_a1_)\n\t\t\t\t\t\tdisplaced_point[0] -= bounds_a1_;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[1] < 0.0)\n\t\t\t\t\t\tdisplaced_point[1] += bounds_b1_;\n\t\t\t\t\twhile (displaced_point[1] > bounds_b1_)\n\t\t\t\t\t\tdisplaced_point[1] -= bounds_b1_;\n\t\t\t\t\t\n\t\t\t\t\twhile (displaced_point[2] < 0.0)\n\t\t\t\t\t\tdisplaced_point[2] += bounds_c1_;\n\t\t\t\t\twhile (displaced_point[2] > bounds_c1_)\n\t\t\t\t\t\tdisplaced_point[2] -= bounds_c1_;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// displace the point by a draw from the kernel, looping until the displaced point is in bounds\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\tkernel.DrawDisplacement_S3(displaced_point);\n\t\t\t\t\t\tdisplaced_point[0] += point_a;\n\t\t\t\t\t\tdisplaced_point[1] += point_b;\n\t\t\t\t\t\tdisplaced_point[2] += point_c;\n\t\t\t\t\t}\n\t\t\t\t\twhile ((displaced_point[0] < bounds_a0_) || (displaced_point[0] > bounds_a1_) ||\n\t\t\t\t\t\t   (displaced_point[1] < bounds_b0_) || (displaced_point[1] > bounds_b1_) ||\n\t\t\t\t\t\t   (displaced_point[2] < bounds_c0_) || (displaced_point[2] > bounds_c1_));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// we do most of our work in user-space coordinates; here we scale to [0, 1] for ValueAtPoint\n\t\t\t\tdouble rescaled_point[3];\n\t\t\t\t\n\t\t\t\trescaled_point[0] = (displaced_point[0] - bounds_a0_) / (bounds_a1_ - bounds_a0_);\n\t\t\t\trescaled_point[1] = (displaced_point[1] - bounds_b0_) / (bounds_b1_ - bounds_b0_);\n\t\t\t\trescaled_point[2] = (displaced_point[2] - bounds_c0_) / (bounds_c1_ - bounds_c0_);\n\t\t\t\tmap_value = ValueAtPoint_S3(rescaled_point);\n\t\t\t}\n\t\t\twhile (values_max_ * Eidos_rng_uniform_doubleCO(rng_64) > map_value);\n\t\t\t\n\t\t\t*(result_ptr++) = displaced_point[0];\n\t\t\t*(result_ptr++) = displaced_point[1];\n\t\t\t*(result_ptr++) = displaced_point[2];\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t- (object<SpatialMap>)smooth(float$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP SpatialMap::ExecuteMethod_smooth(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// Our arguments go to SpatialKernel::SpatialKernel(), which creates the kernel object that we use\n\tEidosValue *maxDistance_value = p_arguments[0].get();\n\tdouble max_distance = maxDistance_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\t// SpatialKernel parses and bounds-checks our arguments for us\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(spatiality_, max_distance, p_arguments, 1, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif (kernel_count != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_smooth): smooth() requires a single kernel; all kernel definition arguments must be singletons.\" << EidosTerminate();\n\t\n\tSpatialKernel kernel(spatiality_, max_distance, p_arguments, 1, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 1\n\t\n\t// Ask the kernel to create a discrete grid of values, at our spatial scale (we define the\n\t// relationship between spatial bounds and pixels, used by the kernel to make its grid)\n\tkernel.CalculateGridValues(*this);\n\t\n\t//std::cout << kernel << std::endl;\n\t\n\t// Generate the new spatial map values and set them into ourselves\n\tswitch (spatiality_)\n\t{\n\t\tcase 1:\n\t\t\tConvolve_S1(kernel);\tbreak;\n\t\tcase 2:\n\t\t\tConvolve_S2(kernel);\tbreak;\n\t\tcase 3:\n\t\t\tConvolve_S3(kernel);\tbreak;\n\t\t\t\n\t\tdefault:\t\t\t\t\tbreak;\n\t}\n\t\n\t_ValuesChanged();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_SpatialMap_Class));\n}\n\n\n//\n//\tObject instantiation\n//\n#pragma mark -\n#pragma mark Object instantiation\n#pragma mark -\n\n// called internally to create a temporary spatial map from a vector/matrix/array, to perform an operation\n// first it copies the target spatial map, to get things like bounds etc.; then it copies values in from p_argument\nEidosValue_SP SpatialMap::_DeriveTemporarySpatialMapWithEidosValue(EidosValue *p_argument, const std::string &p_code_name, const std::string &p_eidos_name)\n{\n\tif (!IsCompatibleWithValue(p_argument))\n\t\tEIDOS_TERMINATION << \"ERROR (\" << p_code_name << \"): \" << p_eidos_name << \" the dimensionality and grid dimensions of the supplied vector/matrix/array must match those of the target map (i.e., must be conformable).\" << EidosTerminate();\n\t\n\t// make a duplicate of this SpatialMap\n\tSpatialMap *objectElement = new SpatialMap(\"__tempmap__INTERNAL__\", *this);\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gSLiM_SpatialMap_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\t// copy in values from p_argument\n\tobjectElement->TakeValuesFromEidosValue(p_argument, \"SpatialMap::_DeriveTemporarySpatialMapWithEidosValue\", \"(internal error)\");\n\t\n\treturn result_SP;\n}\n\n\n//\t(object<SpatialMap>$)SpatialMap(...)\n//\t(object<SpatialMap>$)SpatialMap(string$ name, object<SpatialMap>$ map)\nstatic EidosValue_SP SLiM_Instantiate_SpatialMap(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_String *name_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &name = name_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tEidosValue *map_value = p_arguments[1].get();\n\tSpatialMap *map = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialMap *objectElement = new SpatialMap(name, *map);\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gSLiM_SpatialMap_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tSpatialMap_Class\n//\n#pragma mark -\n#pragma mark SpatialMap_Class\n#pragma mark -\n\nEidosClass *gSLiM_SpatialMap_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *SpatialMap_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SpatialMap_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_gridDimensions,\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_interpolate,\t\t\tfalse,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_name,\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatialBounds,\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatiality,\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *SpatialMap_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SpatialMap_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_add, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_blend, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class)->AddFloat_S(\"xFraction\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_multiply, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_subtract, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_divide, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_power, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_exp, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_changeColors, kEidosValueMaskVOID))->AddNumeric_ON(\"valueRange\", gStaticEidosValueNULL)->AddString_ON(\"colors\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_changeValues, kEidosValueMaskVOID))->AddArg(kEidosValueMaskNumeric | kEidosValueMaskObject, \"x\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_gridValues, kEidosValueMaskFloat)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_interpolate, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddInt_S(\"factor\")->AddString_OS(\"method\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"linear\"))));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mapColor, kEidosValueMaskString))->AddNumeric(\"value\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mapImage, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosImage_Class))->AddInt_OSN(gEidosStr_width, gStaticEidosValueNULL)->AddInt_OSN(gEidosStr_height, gStaticEidosValueNULL)->AddLogical_OS(\"centers\", gStaticEidosValue_LogicalF)->AddLogical_OS(gEidosStr_color, gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mapValue, kEidosValueMaskFloat))->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_range, kEidosValueMaskFloat)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_rescale, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddNumeric_OS(\"min\", gStaticEidosValue_Float0)->AddNumeric_OS(\"max\", gStaticEidosValue_Float1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sampleImprovedNearbyPoint, kEidosValueMaskFloat))->AddFloat(\"point\")->AddFloat_S(\"maxDistance\")->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sampleNearbyPoint, kEidosValueMaskFloat))->AddFloat(\"point\")->AddFloat_S(\"maxDistance\")->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_smooth, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddFloat_S(\"maxDistance\")->AddString_S(\"functionType\")->AddEllipsis());\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *SpatialMap_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"SpatialMap_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gStr_SpatialMap, SLiM_Instantiate_SpatialMap, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddString_S(\"name\")->AddObject_S(\"map\", gSLiM_SpatialMap_Class));\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "core/spatial_map.h",
    "content": "//\n//  spatial_map.h\n//  SLiM\n//\n//  Created by Ben Haller on 9/4/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class SpatialMap represents a map of spatial values that define a property, such as elevation, temperature,\n rainfall, habitability, food availability, or local carrying capacity, for a spatial landscape.  A spatial map\n can be a 1D, 2D, or 3D grid of values for points in space.  Besides being a sort of N-dimensional data structure\n structure to fill the void made by the lack of an array type in Eidos, it also manages interpolation, rescaling\n to fit the spatial bounds of the subpopulation, color mapping, and other miscellaneous issues.\n \n */\n\n#ifndef __SLiM__spatial_map__\n#define __SLiM__spatial_map__\n\n#include \"slim_globals.h\"\n#include \"eidos_value.h\"\n#include \"eidos_symbol_table.h\"\n#include \"eidos_class_Dictionary.h\"\n\nclass Subpopulation;\nclass SpatialKernel;\n\n\n#pragma mark -\n#pragma mark SpatialMap\n#pragma mark -\n\nextern EidosClass *gSLiM_SpatialMap_Class;\n\nclass SpatialMap : public EidosDictionaryRetained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\n\tvoid _ValuesChanged(void);\n\tEidosValue_SP _DeriveTemporarySpatialMapWithEidosValue(EidosValue *p_argument, const std::string &p_code_name, const std::string &p_eidos_name);\n\t\npublic:\n\t\n\tstd::string name_;\t\t\t\t\t// the name of the spatial map, used in SLiMgui and required to be unique\n\tslim_usertag_t tag_value_;\t\t\t// a user-defined tag value\n\t\n\tstd::string spatiality_string_;\t\t// \"x\", \"y\", \"z\", \"xy\", \"xz\", \"yz\", or \"xyz\": the spatial dimensions for the map\n\tint spatiality_;\t\t\t\t\t// 1, 2, or 3 for 1D, 2D, or 3D: the number of spatial dimensions\n\tint spatiality_type_;\t\t\t\t// 1==\"x\", 2==\"y\", 3==\"z\", 4==\"xy\", 5==\"yz\", 6==\"xz\", 7==\"xyz\"\n\tbool periodic_a_, periodic_b_, periodic_c_;\t\t// periodic boundary flags for spatiality dimensions a/b/c\n\t\n\tint required_dimensionality_;\t\t// 1, 2, or 3 for the dimensionality we require; enough to encompass spatiality_type_\n\t\n\tdouble bounds_a0_, bounds_a1_;\t\t// bounds in our first spatiality dimension\n\tdouble bounds_b0_, bounds_b1_;\t\t// bounds in our second spatiality dimension, if used\n\tdouble bounds_c0_, bounds_c1_;\t\t// bounds in our third spatiality dimension, if used\n\t\n\tint64_t grid_size_[3];\t\t\t\t// the number of points in the first, second, and third spatial dimensions\n\tint64_t values_size_;\t\t\t\t// the number of values in values_ (the product of grid_size_)\n\tdouble *values_ = nullptr;\t\t\t// OWNED POINTER: the values for the grid points\n\tbool interpolate_;\t\t\t\t\t// if true, the map will interpolate values; otherwise, nearest-neighbor\n\tdouble values_min_, values_max_;\t// min/max of values_; re-evaluated every time our data changes\n\t\n\tint n_colors_ = 0;\t\t\t\t\t\t// the number of color values given to map across the min/max value range\n\tdouble colors_min_, colors_max_;\t// min/max for our color gradient\n\tfloat *red_components_ = nullptr;\t// OWNED POINTER: red components, n_colors_ in size, from min to max value\n\tfloat *green_components_ = nullptr;\t// OWNED POINTER: green components, n_colors_ in size, from min to max value\n\tfloat *blue_components_ = nullptr;\t// OWNED POINTER: blue components, n_colors_ in size, from min to max value\n\t\n#if defined(SLIMGUI)\n\t// This cache is for SLiMgui's individuals display\n\tuint8_t *display_buffer_ = nullptr;\t// OWNED POINTER: used by SLiMgui, contains RGB values for pixels in the PopulationView\n\tint buffer_width_, buffer_height_;\t// the size of the buffer, in pixels, each of which is 3 x sizeof(uint8_t)\n    bool buffer_flipped_;               // true if flipped (for Qt display) false if not (for GL display)\n\t\n\t// This cache is for Plot's image() method; unlike the cache above, it is never interpolated\n\tvoid *image_ = nullptr;\t\t\t\t\t\t\t// OWNED POINTER: a QImage* used by Plot\n\tbool image_flipped_;\t\t\t\t\t\t\t// true if the cached image was flipped\n\tvoid (*image_deleter_)(void *ptr) = nullptr;\t// a deleter function for image_ since we don't reference Qt\n#endif\n\t\n\tSpatialMap(const SpatialMap&) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tSpatialMap& operator=(const SpatialMap&) = delete;\t\t\t\t\t\t\t\t\t\t// no copying\n\tSpatialMap(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tSpatialMap(std::string p_name, std::string p_spatiality_string, Subpopulation *p_subpop, EidosValue *p_values, bool p_interpolate, EidosValue *p_value_range, EidosValue *p_colors);\n\tSpatialMap(std::string p_name, SpatialMap &p_original);\n\t~SpatialMap(void);\n\t\n\tvoid TakeColorsFromEidosValues(EidosValue *p_value_range, EidosValue *p_colors, const std::string &p_code_name, const std::string &p_eidos_name);\n\tvoid TakeValuesFromEidosValue(EidosValue *p_values, const std::string &p_code_name, const std::string &p_eidos_name);\n\tvoid TakeOverMallocedValues(double *p_values, int64_t p_dimcount, int64_t *p_dimensions);\n\tbool IsCompatibleWithSubpopulation(Subpopulation *p_subpop);\n\tbool IsCompatibleWithMap(SpatialMap *p_map);\n\tbool IsCompatibleWithMapValues(SpatialMap *p_map);\n\tbool IsCompatibleWithValue(EidosValue *p_value);\n\t\n\tdouble ValueAtPoint_S1(double *p_point);\n\tdouble ValueAtPoint_S2(double *p_point);\n\tdouble ValueAtPoint_S3(double *p_point);\n\t\n\tinline double ValueAtPoint_S1_NOINTERPOLATE(double x_fraction)\n\t{\n\t\t// See ValueAtPoint_S1(); this is a fast inline version that assumes no interpolation\n\t\tint64_t xsize = grid_size_[0];\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\t\t\n\t\treturn values_[x_map];\n\t}\n\t\n\tinline double ValueAtPoint_S2_NOINTERPOLATE(double x_fraction, double y_fraction)\n\t{\n\t\t// See ValueAtPoint_S2(); this is a fast inline version that assumes no interpolation\n\t\tint64_t xsize = grid_size_[0];\n\t\tint64_t ysize = grid_size_[1];\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\tint y_map = (int)round(y_fraction * (ysize - 1));\n\t\t\n\t\treturn values_[x_map + y_map * xsize];\n\t}\n\t\n\tdouble ValueAtPoint_S3_NOINTERPOLATE(double x_fraction, double y_fraction, double z_fraction)\n\t{\n\t\t// See ValueAtPoint_S3(); this is a fast inline version that assumes no interpolation\n\t\tint64_t xsize = grid_size_[0];\n\t\tint64_t ysize = grid_size_[1];\n\t\tint64_t zsize = grid_size_[2];\n\t\tint x_map = (int)round(x_fraction * (xsize - 1));\n\t\tint y_map = (int)round(y_fraction * (ysize - 1));\n\t\tint z_map = (int)round(z_fraction * (zsize - 1));\n\t\t\n\t\treturn values_[x_map + y_map * xsize + z_map * xsize * ysize];\n\t}\n\t\n\tvoid ColorForValue(double p_value, double *p_rgb_ptr);\n\tvoid ColorForValue(double p_value, float *p_rgb_ptr);\n\t\n\tvoid Convolve_S1(SpatialKernel &kernel);\n\tvoid Convolve_S2(SpatialKernel &kernel);\n\tvoid Convolve_S3(SpatialKernel &kernel);\n\t\n\tvoid FillRGBBuffer(uint8_t *buffer, int64_t width, int64_t height, bool flipped, bool no_interpolation);\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_add(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_blend(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_multiply(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subtract(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_divide(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_power(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_exp(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_changeColors(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_changeValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_gridValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_interpolate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mapColor(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mapImage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mapValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_range(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_rescale(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_sampleImprovedNearbyPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_sampleNearbyPoint(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_smooth(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass SpatialMap_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tSpatialMap_Class(const SpatialMap_Class &p_original) = delete;\t// no copy-construct\n\tSpatialMap_Class& operator=(const SpatialMap_Class&) = delete;\t// no copying\n\tinline SpatialMap_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n};\n\n\n#endif /* __SLiM__spatial_map__ */\n"
  },
  {
    "path": "core/species.cpp",
    "content": "//\n//  species.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/26/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"species.h\"\n#include \"community.h\"\n#include \"slim_functions.h\"\n#include \"eidos_test.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_sorting.h\"\n#include \"individual.h\"\n#include \"polymorphism.h\"\n#include \"subpopulation.h\"\n#include \"interaction_type.h\"\n#include \"log_file.h\"\n\n#include <iostream>\n#include <iomanip>\n#include <fstream>\n#include <stdexcept>\n#include <algorithm>\n#include <typeinfo>\n#include <memory>\n#include <string>\n#include <utility>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <unordered_set>\n#include <unordered_map>\n#include <float.h>\n#include <ctime>\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\n#endif\n\n//TREE SEQUENCE\n#include <stdio.h>\n#include <stdlib.h>\n#include \"json.hpp\"\n#include <sys/utsname.h>\n#include <sys/stat.h>\n#include <dirent.h>\n\n//TREE SEQUENCE\n//INCLUDE MSPRIME.H FOR THE CROSSCHECK CODE; NEEDS TO BE MOVED TO TSKIT\n// the tskit header is not designed to be included from C++, so we have to protect it...\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include \"kastore.h\"\n#include \"../treerec/tskit/trees.h\"\n#include \"../treerec/tskit/tables.h\"\n#include \"../treerec/tskit/genotypes.h\"\n#include \"../treerec/tskit/text_input.h\"\n#ifdef __cplusplus\n}\n#endif\n\n\n// This is the version written to the provenance table of .trees files\nstatic const char *SLIM_TREES_FILE_VERSION_INITIAL __attribute__((unused)) = \"0.1\";\t\t// SLiM 3.0, before the Inidividual table, etc.; UNSUPPORTED\nstatic const char *SLIM_TREES_FILE_VERSION_PRENUC = \"0.2\";\t\t// before introduction of nucleotides\nstatic const char *SLIM_TREES_FILE_VERSION_POSTNUC = \"0.3\";\t\t// SLiM 3.3.x, with the added nucleotide field in MutationMetadataRec\nstatic const char *SLIM_TREES_FILE_VERSION_HASH = \"0.4\";\t\t// SLiM 3.4.x, with the new model_hash key in provenance\nstatic const char *SLIM_TREES_FILE_VERSION_META = \"0.5\";\t\t// SLiM 3.5.x onward, with information in metadata instead of provenance\nstatic const char *SLIM_TREES_FILE_VERSION_PREPARENT = \"0.6\";\t// SLiM 3.6.x onward, with SLIM_TSK_INDIVIDUAL_RETAINED instead of SLIM_TSK_INDIVIDUAL_FIRST_GEN\nstatic const char *SLIM_TREES_FILE_VERSION_PRESPECIES = \"0.7\";\t// SLiM 3.7.x onward, with parent pedigree IDs in the individuals table metadata\nstatic const char *SLIM_TREES_FILE_VERSION_SPECIES = \"0.8\";\t\t// SLiM 4.0.x onward, with species `name`/`description`, and `tick` in addition to `cycle`\nstatic const char *SLIM_TREES_FILE_VERSION = \"0.9\";\t\t\t\t// SLiM 5.0 onward, for multichrom (haplosomes not genomes, and `chromosomes` key)\n\n#pragma mark -\n#pragma mark Species\n#pragma mark -\n\nSpecies::Species(Community &p_community, slim_objectid_t p_species_id, const std::string &p_name) :\n\tself_symbol_(EidosStringRegistry::GlobalStringIDForString(p_name), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Species_Class))),\n\tspecies_haplosome_pool_(\"EidosObjectPool(Haplosome)\", sizeof(Haplosome), 16384), species_individual_pool_(\"EidosObjectPool(Individual)\", sizeof(Individual), 8192),\n    model_type_(p_community.model_type_), community_(p_community), population_(*this), name_(p_name), species_id_(p_species_id)\n{\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n#ifdef SLIMGUI\n\t// Pedigree recording is always enabled when running under SLiMgui, so that the various graphs all work\n\t// However, as with tree-sequence recording, the fact that it is enabled is not user-visible unless the user enables it\n\tpedigrees_enabled_ = true;\n\tpedigrees_enabled_by_SLiM_ = true;\n#endif\n\t\n\t// Make space for up to SLIM_MAX_CHROMOSOMES Chromosome objects, but don't make any for now\n\t// This prevents the storage underlying chromosomes_ from being reallocated\n\tchromosomes_.reserve(SLIM_MAX_CHROMOSOMES);\n}\n\nSpecies::~Species(void)\n{\n\t//EIDOS_ERRSTREAM << \"Species::~Species\" << std::endl;\n\t\n\t// There shouldn't be any individuals in the graveyard here, but just in case\n\tEmptyGraveyard();\t\t// needs to be done first; uses subpopulation references\n\t\n\tpopulation_.RemoveAllSubpopulationInfo();\n\tpopulation_.PurgeRemovedSubpopulations();\n\t\n\tDeleteAllMutationRuns();\n\t\n\tfor (auto mutation_type : mutation_types_)\n\t\tdelete mutation_type.second;\n\tfor (auto &element : mutation_types_)\n\t\telement.second = nullptr;\n\tmutation_types_.clear();\n\t\n\tfor (auto genomic_element_type : genomic_element_types_)\n\t\tdelete genomic_element_type.second;\n\tfor (auto &element : genomic_element_types_)\n\t\telement.second = nullptr;\n\tgenomic_element_types_.clear();\n\t\n\t// Free the shuffle buffer\n\tif (shuffle_buffer_)\n\t{\n\t\tfree(shuffle_buffer_);\n\t\tshuffle_buffer_ = nullptr;\n\t}\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (RecordingTreeSequence())\n\t\tFreeTreeSequence();\n\t\n\tif (hap_metadata_1F_) {\n\t\tfree(hap_metadata_1F_);\n\t\thap_metadata_1F_ = nullptr;\n\t}\n\tif (hap_metadata_1M_) {\n\t\tfree(hap_metadata_1M_);\n\t\thap_metadata_1M_ = nullptr;\n\t}\n\tif (hap_metadata_2F_) {\n\t\tfree(hap_metadata_2F_);\n\t\thap_metadata_2F_ = nullptr;\n\t}\n\tif (hap_metadata_2M_) {\n\t\tfree(hap_metadata_2M_);\n\t\thap_metadata_2M_ = nullptr;\n\t}\n\t\n\t// Let go of our chromosome objects.  This is tricky, because other objects deleted later might try to use\n\t// the chromosome objects after they're gone, leading to undefined behavior.  To make such bugs easier to\n\t// catch, we zero out pointers to chromosomes everywhere we keep them, so usage of them hopefully crashes.\n\tfor (Chromosome *chromosome : chromosomes_)\n\t\tchromosome->Release();\n\t\n\tstd::fill(chromosomes_.begin(), chromosomes_.end(), nullptr);\n\tchromosomes_.clear();\n\t\n\tfor (auto &element : chromosome_from_id_)\n\t\telement.second = nullptr;\n\tchromosome_from_id_.clear();\n\t\n\tfor (auto &element : chromosome_from_symbol_)\n\t\telement.second = nullptr;\n\tchromosome_from_symbol_.clear();\n\t\n\tstd::fill(chromosome_for_haplosome_index_.begin(), chromosome_for_haplosome_index_.end(), nullptr);\n\tchromosome_for_haplosome_index_.clear();\n}\n\nvoid Species::_MakeHaplosomeMetadataRecords(void)\n{\n\t// Set up our default metadata records for haplosomes, which are variable-length.  The default records\n\t// are used as the initial configuration of the nodes for new individuals; then, as haplosomes are\n\t// added to the new individual, the is_vacant_ bits get tweaked as needed in the recorded metadata, which\n\t// is a bit gross, but necessary; the node metadata is recorded before the haplosomes are created.\n\t// See HaplosomeMetadataRec for comments on this design.\n\t\n\t// First, calculate how many bytes we need\n\tsize_t bits_needed_for_is_vacant = chromosomes_.size();\t\t\t\t\t// each chromosome needs one bit per node table entry\n\thaplosome_metadata_size_ = sizeof(HaplosomeMetadataRec) - 1;\t\t\t// -1 to subtract out the is_vacant_[1] in the record\n\thaplosome_metadata_is_vacant_bytes_ = ((bits_needed_for_is_vacant + 7) / 8);\t// (x+7)/8 rounds up to the number of bytes\n\thaplosome_metadata_size_ += haplosome_metadata_is_vacant_bytes_;\n\t\n\t// Then allocate the buffers needed; the \"male\" versions are present only when sex is enabled\n\thap_metadata_1F_ = (HaplosomeMetadataRec *)calloc(haplosome_metadata_size_, 1);\n\thap_metadata_1M_ = (sex_enabled_ ? (HaplosomeMetadataRec *)calloc(haplosome_metadata_size_, 1) : nullptr);\n\thap_metadata_2F_ = (HaplosomeMetadataRec *)calloc(haplosome_metadata_size_, 1);\n\thap_metadata_2M_ = (sex_enabled_ ? (HaplosomeMetadataRec *)calloc(haplosome_metadata_size_, 1) : nullptr);\n\t\n\t// Then set the is_vacant_ bits for the default state for males and females; this is the state in which\n\t// all chromosomes that dictate the is_vacant_ state by sex have that dictated state, while all others\n\t// (types \"A\", \"H\", and \"H-\" only) are assumed to be non-null.  Any positions that are unused for a\n\t// given chromosome type (like the second position for type \"Y\") are given as 1 here, \"vacant\", by\n\t// definition; \"vacant\" is either \"unused\" or \"null haplosome\".  We go from least-significant bit\n\t// to most-significant bit, byte by byte, with each chromosome using two bits.  The less significant\n\t// of those two bits is is_vacant_ for haplosome 1 for that chromosome; the more significant of those\n\t// two bits is is_vacant_ for haplosome 2 for that chromosome.\n\tIndividualSex sex = IndividualSex::kFemale;\n\tHaplosomeMetadataRec *focal_metadata_1 = hap_metadata_1F_;\n\tHaplosomeMetadataRec *focal_metadata_2 = hap_metadata_2F_;\n\t\n\twhile (true)\n\t{\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\tbool haplosome_1_is_vacant = false, haplosome_2_is_vacant = false;\n\t\t\t\n\t\t\tswitch (chromosome->Type())\n\t\t\t{\n\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\thaplosome_1_is_vacant = false;\t\t\t\t\t\t\t\t// always present (by default)\n\t\t\t\t\thaplosome_2_is_vacant = false;\t\t\t\t\t\t\t\t// always present (by default)\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\thaplosome_1_is_vacant = false;\t\t\t\t\t\t\t\t// always present (by default)\n\t\t\t\t\thaplosome_2_is_vacant = true;\t\t\t\t\t\t\t\t// always unused\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\thaplosome_1_is_vacant = false;\t\t\t\t\t\t\t\t// always present\n\t\t\t\t\thaplosome_2_is_vacant = true;\t\t\t\t\t\t\t\t// always null\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\thaplosome_1_is_vacant = false;\t\t\t\t\t\t\t\t// always present\n\t\t\t\t\thaplosome_2_is_vacant = (sex == IndividualSex::kMale);\t\t// null in males\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\thaplosome_1_is_vacant = (sex == IndividualSex::kFemale);\t// null in females\n\t\t\t\t\thaplosome_2_is_vacant = true;\t\t\t\t\t\t\t\t// always unused\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\thaplosome_1_is_vacant = (sex == IndividualSex::kFemale);\t// null in females\n\t\t\t\t\thaplosome_2_is_vacant = false;\t\t\t\t\t\t\t\t// always present\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\thaplosome_1_is_vacant = (sex == IndividualSex::kMale);\t\t// null in males\n\t\t\t\t\thaplosome_2_is_vacant = true;\t\t\t\t\t\t\t\t// always unused\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\thaplosome_1_is_vacant = true;\t\t\t\t\t\t\t\t// always null\n\t\t\t\t\thaplosome_2_is_vacant = (sex == IndividualSex::kFemale);\t// null in females\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// set the appropriate bits in the focal metadata, which we know was cleared to zero initially\n\t\t\tint byte_index = chromosome_index / 8;\n\t\t\tint bit_shift = chromosome_index % 8;\n\t\t\t\n\t\t\tif (haplosome_1_is_vacant)\n\t\t\t\tfocal_metadata_1->is_vacant_[byte_index] |= (0x01 << bit_shift);\n\t\t\t\n\t\t\tif (haplosome_2_is_vacant)\n\t\t\t\tfocal_metadata_2->is_vacant_[byte_index] |= (0x01 << bit_shift);\n\t\t}\n\t\t\n\t\t// loop from female to male, then break out\n\t\tif (sex_enabled_ && (sex == IndividualSex::kFemale))\n\t\t{\n\t\t\tsex = IndividualSex::kMale;\n\t\t\tfocal_metadata_1 = hap_metadata_1M_;\n\t\t\tfocal_metadata_2 = hap_metadata_2M_;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\t\n//\tprintf(\"hap_metadata_1F_ == %.2X\\n\", hap_metadata_1F_->is_vacant_[0]);\n//\tprintf(\"hap_metadata_1M_ == %.2X\\n\", hap_metadata_1M_->is_vacant_[0]);\n//\tprintf(\"hap_metadata_2F_ == %.2X\\n\", hap_metadata_2F_->is_vacant_[0]);\n//\tprintf(\"hap_metadata_2M_ == %.2X\\n\", hap_metadata_2M_->is_vacant_[0]);\n}\n\nChromosome *Species::ChromosomeFromID(int64_t p_id)\n{\n\tauto iter = chromosome_from_id_.find(p_id);\n\t\n\tif (iter == chromosome_from_id_.end())\n\t\treturn nullptr;\n\t\n\treturn (*iter).second;\n}\n\nChromosome *Species::ChromosomeFromSymbol(const std::string &p_symbol)\n{\n\tauto iter = chromosome_from_symbol_.find(p_symbol);\n\t\n\tif (iter == chromosome_from_symbol_.end())\n\t\treturn nullptr;\n\t\n\treturn (*iter).second;\n}\n\nvoid Species::MakeImplicitChromosome(ChromosomeType p_type)\n{\n\tif (has_implicit_chromosome_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MakeImplicitChromosome): (internal error) implicit chromosome already exists.\" << EidosTerminate();\n\tif (num_chromosome_inits_ != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MakeImplicitChromosome): (internal error) explicit chromosome already exists.\" << EidosTerminate();\n\t\n\t// Only these three chromosome types are supported for an implicitly defined chromosome.  The symbols used\n\t// here match the symbols that were output for chromosome types in various built-in output methods prior to\n\t// SLiM 5, for backward compatibility.\n\tstd::string chromosome_symbol;\n\t\n\tif (p_type == ChromosomeType::kA_DiploidAutosome)\n\t\tchromosome_symbol = \"A\";\n\telse if (p_type == ChromosomeType::kX_XSexChromosome)\n\t\tchromosome_symbol = \"X\";\n\telse if (p_type == ChromosomeType::kNullY_YSexChromosomeWithNull)\n\t\tchromosome_symbol = \"Y\";\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MakeImplicitChromosome): (internal error) unsupported implicit chromosome type.\" << EidosTerminate();\n\t\n\t// Create an implicit Chromosome object with a retain on it from EidosDictionaryRetained::EidosDictionaryRetained()\n\tChromosome *chromosome = new Chromosome(*this, p_type, 1, chromosome_symbol, /* p_index */ 0, /* p_preferred_mutcount */ 0);\n\t\n\t// Add it to our registry; AddChromosome() takes its retain count\n\tAddChromosome(chromosome);\n\thas_implicit_chromosome_ = true;\n\thas_currently_initializing_chromosome_ = true;\n}\n\nChromosome *Species::CurrentlyInitializingChromosome(void)\n{\n\tif (!has_currently_initializing_chromosome_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CurrentlyInitializingChromosome): (internal error) no currently initializing chromosome exists; MakeImplicitChromosome() should be called first.\" << EidosTerminate();\n\tif (!has_implicit_chromosome_ && (num_chromosome_inits_ == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CurrentlyInitializingChromosome): (internal error) no currently initializing chromosome exists even though has_currently_initializing_chromosome_ is true.\" << EidosTerminate();\n\t\n\treturn chromosomes_.back();\n}\n\nvoid Species::AddChromosome(Chromosome *p_chromosome)\n{\n\tint64_t id = p_chromosome->ID();\n\tstd::string symbol = p_chromosome->Symbol();\n\t\n\t// this is the main registry, and owns the retain count on every chromosome; it takes the caller's retain here\n\tchromosomes_.push_back(p_chromosome);\n\t\n\t// these are secondary indices that do not keep a retain on the chromosomes\n\tchromosome_from_id_.emplace(id, p_chromosome);\n\tchromosome_from_symbol_.emplace(symbol, p_chromosome);\n\t\n\t// keep track of our haplosome configuration\n\tif (p_chromosome->IntrinsicPloidy() == 2)\n\t{\n\t\tchromosome_for_haplosome_index_.push_back(p_chromosome);\n\t\tchromosome_for_haplosome_index_.push_back(p_chromosome);\n\t\tchromosome_subindex_for_haplosome_index_.push_back(0);\n\t\tchromosome_subindex_for_haplosome_index_.push_back(1);\n\t\tfirst_haplosome_index_.push_back(haplosome_count_per_individual_);\n\t\tlast_haplosome_index_.push_back(haplosome_count_per_individual_ + 1);\n\t\thaplosome_count_per_individual_ += 2;\n\t}\n\telse // p_chromosome->IntrinsicPloidy() == 1\n\t{\n\t\tchromosome_for_haplosome_index_.push_back(p_chromosome);\n\t\tchromosome_subindex_for_haplosome_index_.push_back(0);\n\t\tfirst_haplosome_index_.push_back(haplosome_count_per_individual_);\n\t\tlast_haplosome_index_.push_back(haplosome_count_per_individual_);\n\t\thaplosome_count_per_individual_ += 1;\n\t}\n\t\n\t// keep track of whether we contain null haplosomes or not (for optimizations)\n\t// if addRecombinant(), addMultiRecombinant(), etc. places a null haplosome in 'A' or 'H', it will set\n\t// the has_null_haplosomes_ flag, which tracks this at a finer level of detail than the chromosome type\n\tif (p_chromosome->AlwaysUsesNullHaplosomes())\n\t\tchromosomes_use_null_haplosomes_ = true;\n}\n\nChromosome *Species::GetChromosomeFromEidosValue(EidosValue *chromosome_value)\n{\n\tEidosValueType chromosome_value_type = chromosome_value->Type();\n\tint chromosome_value_count = chromosome_value->Count();\n\t\n\t// NULL means \"no chromosome chosen\"; caller must be prepared for nullptr\n\tif (chromosome_value_type == EidosValueType::kValueNULL)\n\t\treturn nullptr;\n\t\n\tif (chromosome_value_count != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeFromEidosValue): (internal error) the chromosome parameter must be singleton.\" << EidosTerminate();\n\t\n\tswitch (chromosome_value_type)\n\t{\n\t\tcase EidosValueType::kValueInt:\n\t\t{\n\t\t\tint64_t id = chromosome_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tChromosome *chromosome = ChromosomeFromID(id);\n\t\t\t\n\t\t\tif (!chromosome)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeFromEidosValue): could not find a chromosome with the given id (\" << id << \") in the target species.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn chromosome;\n\t\t}\n\t\tcase EidosValueType::kValueString:\n\t\t{\n\t\t\tconst std::string &symbol = chromosome_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\tChromosome *chromosome = ChromosomeFromSymbol(symbol);\n\t\t\t\n\t\t\tif (!chromosome)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeFromEidosValue): could not find a chromosome with the given symbol (\" << symbol << \") in the target species.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn chromosome;\n\t\t}\n\t\tcase EidosValueType::kValueObject:\n\t\t{\n\t\t\tChromosome *chromosome = (Chromosome *)chromosome_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (&chromosome->species_ != this)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeFromEidosValue): the chromosome passed does not belong to the target species.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn chromosome;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeFromEidosValue): (internal error) unexpected type for parameter chromosome.\" << EidosTerminate();\n\t}\n}\n\nvoid Species::GetChromosomeIndicesFromEidosValue(std::vector<slim_chromosome_index_t> &chromosome_indices, EidosValue *chromosomes_value)\n{\n\tEidosValueType chromosomes_value_type = chromosomes_value->Type();\n\tint chromosomes_value_count = chromosomes_value->Count();\n\t\n\tswitch (chromosomes_value_type)\n\t{\n\t\t// NULL means \"all chromosomes\", unlike for GetChromosomeFromEidosValue()\n\t\tcase EidosValueType::kValueNULL:\n\t\t{\n\t\t\tfor (Chromosome *chromosome : Chromosomes())\n\t\t\t\tchromosome_indices.push_back(chromosome->Index());\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosValueType::kValueInt:\n\t\t{\n\t\t\tconst int64_t *ids_data = chromosomes_value->IntData();\n\t\t\t\n\t\t\tfor (int ids_index = 0; ids_index < chromosomes_value_count; ids_index++)\n\t\t\t{\n\t\t\t\tint64_t id = ids_data[ids_index];\n\t\t\t\tChromosome *chromosome = ChromosomeFromID(id);\n\t\t\t\t\n\t\t\t\tif (!chromosome)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeIndicesFromEidosValue): could not find a chromosome with the given id (\" << id << \") in the target species.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tchromosome_indices.push_back(chromosome->Index());\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosValueType::kValueString:\n\t\t{\n\t\t\tconst std::string *symbols_data = chromosomes_value->StringData();\n\t\t\t\n\t\t\tfor (int symbols_index = 0; symbols_index < chromosomes_value_count; symbols_index++)\n\t\t\t{\n\t\t\t\tconst std::string &symbol = symbols_data[symbols_index];\n\t\t\t\tChromosome *chromosome = ChromosomeFromSymbol(symbol);\n\t\t\t\t\n\t\t\t\tif (!chromosome)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeIndicesFromEidosValue): could not find a chromosome with the given symbol (\" << symbol << \") in the target species.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tchromosome_indices.push_back(chromosome->Index());\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosValueType::kValueObject:\n\t\t{\n\t\t\tChromosome * const *chromosomes_data = (Chromosome * const *)chromosomes_value->ObjectData();\n\t\t\t\n\t\t\tfor (int chromosome_index = 0; chromosome_index < chromosomes_value_count; ++chromosome_index)\n\t\t\t{\n\t\t\t\tChromosome *chromosome = chromosomes_data[chromosome_index];\n\t\t\t\t\n\t\t\t\tif (&chromosome->species_ != this)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeIndicesFromEidosValue): the chromosome passed does not belong to the target species.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tchromosome_indices.push_back(chromosome->Index());\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetChromosomeIndicesFromEidosValue): (internal error) unexpected type for parameter chromosome.\" << EidosTerminate();\n\t}\n}\n\n// get one line of input, sanitizing by removing comments and whitespace; used only by Species::InitializePopulationFromTextFile\nvoid GetInputLine(std::istream &p_input_file, std::string &p_line);\nvoid GetInputLine(std::istream &p_input_file, std::string &p_line)\n{\n\tgetline(p_input_file, p_line);\n\t\n\t// remove all after \"//\", the comment start sequence\n\t// BCH 16 Dec 2014: note this was \"/\" in SLiM 1.8 and earlier, changed to allow full filesystem paths to be specified.\n\tif (p_line.find(\"//\") != std::string::npos)\n\t\tp_line.erase(p_line.find(\"//\"));\n\t\n\t// remove leading and trailing whitespace (spaces and tabs)\n\tp_line.erase(0, p_line.find_first_not_of(\" \\t\"));\n\tp_line.erase(p_line.find_last_not_of(\" \\t\") + 1);\n}\n\nSLiMFileFormat Species::FormatOfPopulationFile(const std::string &p_file_string)\n{\n\tif (p_file_string.length())\n\t{\n\t\t// p_file should have had its trailing slash stripped already, and a leading ~ should have been resolved\n\t\t// we will check those assumptions here for safety...\n\t\tif (p_file_string[0] == '~')\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::FormatOfPopulationFile): (internal error) leading ~ in path was not resolved.\" << EidosTerminate();\n\t\tif (p_file_string.back() == '/')\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::FormatOfPopulationFile): (internal error) trailing / in path was not stripped.\" << EidosTerminate();\n\t\t\n\t\t// First determine if the path is for a file or a directory\n\t\tconst char *file_cstr = p_file_string.c_str();\n\t\tstruct stat statbuf;\n\t\t\n\t\tif (stat(file_cstr, &statbuf) != 0)\n\t\t\treturn SLiMFileFormat::kFileNotFound;\n\t\t\n\t\tif (S_ISDIR(statbuf.st_mode))\n\t\t{\n\t\t\t// The path is for a whole directory.  This used to be the code path for a directory-based tskit text\n\t\t\t// (i.e. non-binary) format, but we no longer support that.  This is now the code path for reading in\n\t\t\t// a multi-chromosome archive of .trees files, which live inside a directory.  If the directory does\n\t\t\t// not contain the expected .trees files, we'll discover that later on and raise.\n\t\t\treturn SLiMFileFormat::kFormatDirectory;\n\t\t}\n\t\telse if (S_ISREG(statbuf.st_mode))\n\t\t{\n\t\t\t// The path is for a file.  It could be a SLiM text file, SLiM binary file, or tskit binary file; we\n\t\t\t// determine which using the leading 4 bytes of the file.  This heuristic will need to be adjusted\n\t\t\t// if/when these file formats change (such as going off of HD5 in the tskit file format).\n\t\t\tstd::ifstream infile(file_cstr, std::ios::in | std::ios::binary);\n\t\t\t\n\t\t\tif (!infile.is_open() || infile.eof())\n\t\t\t\treturn SLiMFileFormat::kFileNotFound;\n\t\t\t\n\t\t\t// Determine the file length\n\t\t\tinfile.seekg(0, std::ios_base::end);\n\t\t\tstd::size_t file_size = infile.tellg();\n\t\t\t\n\t\t\t// Determine the file format\n\t\t\tif (file_size >= 4)\n\t\t\t{\n\t\t\t\tchar file_chars[4] = {0, 0, 0, 0};\n\t\t\t\tuint32_t file_endianness_tag = 0;\n\t\t\t\t\n\t\t\t\tinfile.seekg(0, std::ios_base::beg);\n\t\t\t\tinfile.read(&file_chars[0], 4);\n\t\t\t\t\n\t\t\t\tinfile.seekg(0, std::ios_base::beg);\n\t\t\t\tinfile.read(reinterpret_cast<char *>(&file_endianness_tag), sizeof file_endianness_tag);\n\t\t\t\t\n\t\t\t\tif ((file_chars[0] == '#') && (file_chars[1] == 'O') && (file_chars[2] == 'U') && (file_chars[3] == 'T'))\n\t\t\t\t\treturn SLiMFileFormat::kFormatSLiMText;\n\t\t\t\telse if (file_endianness_tag == 0x12345678)\n\t\t\t\t\treturn SLiMFileFormat::kFormatSLiMBinary;\n\t\t\t\telse if (file_endianness_tag == 0x46444889)\t\t\t// 'âHDF', the prefix for HDF5 files apparently; reinterpreted via endianness\n\t\t\t\t\treturn SLiMFileFormat::kFormatTskitBinary_HDF5;\n\t\t\t\telse if (file_endianness_tag == 0x53414B89)\t\t\t// 'âKAS', the prefix for kastore files apparently; reinterpreted via endianness\n\t\t\t\t\treturn SLiMFileFormat::kFormatTskitBinary_kastore;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn SLiMFileFormat::kFormatUnrecognized;\n}\n\nvoid Species::_CleanAllReferencesToSpecies(EidosInterpreter *p_interpreter)\n{\n\t// clear out all variables of type Subpopulation etc. from the symbol table; they will all be invalid momentarily\n\t// note that we do this not only in our constants table, but in the user's variables as well; we can leave no stone unturned\n\t// Note that we presently have no way of clearing out EidosScribe/SLiMgui references (the variable browser, in particular),\n\t// and so EidosConsoleWindowController has to do an ugly and only partly effective hack to work around this issue.\n\tif (p_interpreter)\n\t{\n\t\tEidosSymbolTable &symbols = p_interpreter->SymbolTable();\n\t\tstd::vector<std::string> all_symbols = symbols.AllSymbols();\n\t\tstd::vector<EidosGlobalStringID> symbols_to_remove;\n\t\t\n\t\tfor (const std::string &symbol_name : all_symbols)\n\t\t{\n\t\t\tEidosGlobalStringID symbol_ID = EidosStringRegistry::GlobalStringIDForString(symbol_name);\n\t\t\tEidosValue_SP symbol_value = symbols.GetValueOrRaiseForSymbol(symbol_ID);\n\t\t\t\n\t\t\tif (symbol_value->Type() == EidosValueType::kValueObject)\n\t\t\t{\n\t\t\t\tEidosValue_Object *symbol_object = (static_pointer_cast<EidosValue_Object>(symbol_value)).get();\n\t\t\t\tconst EidosClass *symbol_class = symbol_object->Class();\n\t\t\t\t\n\t\t\t\tif ((symbol_class == gSLiM_Subpopulation_Class) || (symbol_class == gSLiM_Haplosome_Class) || (symbol_class == gSLiM_Individual_Class) || (symbol_class == gSLiM_Mutation_Class) || (symbol_class == gSLiM_Substitution_Class))\n\t\t\t\t{\n\t\t\t\t\t// BCH 5/7/2022: For multispecies, we now have to be careful to clear out only state related to the target species!\n\t\t\t\t\t// This is truly disgusting, because it means we have to go down into the elements of the value to check their species\n\t\t\t\t\t// If *any* element of a value belongs to the target species, we remove the whole value (rather than editing out elements)\n\t\t\t\t\t// Unless/until we are able to let the user retain references to these objects beyond their natural lifetime, there is\n\t\t\t\t\t// just no alternative; the user may find it surprising that their local variable has disappeared, but... such is life\n\t\t\t\t\tbool refers_to_target_species = false;\n\t\t\t\t\t\n\t\t\t\t\tif (symbol_class == gSLiM_Subpopulation_Class)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < symbol_object->Count(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSubpopulation *element = (Subpopulation *)symbol_object->ObjectElementAtIndex_NOCAST(i, nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (&element->species_ == this)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trefers_to_target_species = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (symbol_class == gSLiM_Haplosome_Class)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < symbol_object->Count(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tHaplosome *element = (Haplosome *)symbol_object->ObjectElementAtIndex_NOCAST(i, nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (&element->individual_->subpopulation_->species_ == this)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trefers_to_target_species = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (symbol_class == gSLiM_Individual_Class)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < symbol_object->Count(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIndividual *element = (Individual *)symbol_object->ObjectElementAtIndex_NOCAST(i, nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (&element->subpopulation_->species_ == this)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trefers_to_target_species = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (symbol_class == gSLiM_Mutation_Class)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < symbol_object->Count(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *element = (Mutation *)symbol_object->ObjectElementAtIndex_NOCAST(i, nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (&element->mutation_type_ptr_->species_ == this)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trefers_to_target_species = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (symbol_class == gSLiM_Substitution_Class)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int i = 0; i < symbol_object->Count(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSubstitution *element = (Substitution *)symbol_object->ObjectElementAtIndex_NOCAST(i, nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (&element->mutation_type_ptr_->species_ == this)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trefers_to_target_species = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (refers_to_target_species)\n\t\t\t\t\t\tsymbols_to_remove.emplace_back(symbol_ID);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor (EidosGlobalStringID symbol_ID : symbols_to_remove)\n\t\t\tsymbols.RemoveConstantForSymbol(symbol_ID);\n\t}\n}\n\nslim_tick_t Species::InitializePopulationFromFile(const std::string &p_file_string, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_remap)\n{\n\tSLiMFileFormat file_format = FormatOfPopulationFile(p_file_string);\n\t\n\tif (file_format == SLiMFileFormat::kFileNotFound)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): initialization file does not exist or is empty.\" << EidosTerminate();\n\tif (file_format == SLiMFileFormat::kFormatUnrecognized)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): initialization file is invalid.\" << EidosTerminate();\n\t\n\t// readPopulationFromFile() should define a long-term boundary; the user shouldn't keep references to non-retain-release objects across it\n\tCheckLongTermBoundary();\n\t\n\t// start by cleaning out all variable/constant references to the species or any population object underneath it\n\t_CleanAllReferencesToSpecies(p_interpreter);\n\t\n\t// invalidate interactions, since any cached interaction data depends on the subpopulations and individuals\n\tcommunity_.InvalidateInteractionsForSpecies(this);\n\t\n\t// then we dispose of all existing subpopulations, mutations, etc.\n\tpopulation_.RemoveAllSubpopulationInfo();\n    \n    // Forget remembered subpop IDs and names since we are resetting our state.  We need to do this\n    // to add in subpopulations we will load after resetting; however, it does leave open a window\n    // for incorrect usage since ids/names that were used previously but are no longer extant will\n    // be forgotten as a side effect of reloading, and could then get reused.  This seems unlikely\n    // to arise in practice, and if it does it should produce a downstream error in Python if it\n    // matters, due to ambiguity of duplicated ids/names, so we won't worry about it here - we'd\n    // have to persist the list of known ids/names in metadata, which isn't worth the effort.\n\t// BCH 3/13/2022: Note that now in multispecies, we forget only the names/ids that we ourselves\n\t// have used; the other species in the community still remember and block their own usages.\n\tused_subpop_ids_.clear();\n\tused_subpop_names_.clear();\n\t\n\t// Read in the file.  The SLiM file-reading methods are not tree-sequence-aware, so we bracket them\n\t// with calls that fix the tree sequence recording state around them.  The treeSeq output methods\n\t// are of course treeSeq-aware, so we don't need to do that for them.\n    const char *file_cstr = p_file_string.c_str();\n\tslim_tick_t new_tick = 0;\n    \n\tif ((file_format == SLiMFileFormat::kFormatSLiMText) || (file_format == SLiMFileFormat::kFormatSLiMBinary))\n\t{\n\t\tif (p_subpop_remap.size() > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): the subpopMap parameter is currently supported only when reading .trees files; for other file types it must be NULL (or an empty Dictionary).\" << EidosTerminate();\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (RecordingTreeSequence())\n\t\t{\n\t\t\tFreeTreeSequence();\n\t\t\tAllocateTreeSequenceTables();\n\t\t\t\n\t\t\tif (!community_.warned_no_ancestry_read_ && !gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter->ErrorOutputStream() << \"#WARNING (Species::InitializePopulationFromFile): when tree-sequence recording is enabled, it is usually desirable to call readFromPopulationFile() with a tree-sequence file to provide ancestry; such a file can be produced with treeSeqOutput(), or from msprime/tskit in Python.\" << std::endl;\n\t\t\t\tcommunity_.warned_no_ancestry_read_ = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (file_format == SLiMFileFormat::kFormatSLiMText)\n\t\t\tnew_tick = _InitializePopulationFromTextFile(file_cstr, p_interpreter);\n\t\telse if (file_format == SLiMFileFormat::kFormatSLiMBinary)\n\t\t\tnew_tick = _InitializePopulationFromBinaryFile(file_cstr, p_interpreter);\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (RecordingTreeSequence())\n\t\t{\n\t\t\t// set up all of the mutations we just read in with the tree-seq recording code\n\t\t\tRecordAllDerivedStatesFromSLiM();\n\t\t\t\n\t\t\t// reset our tree-seq auto-simplification interval so we don't simplify immediately\n\t\t\tsimplify_elapsed_ = 0;\n\t\t\t\n\t\t\t// reset our last coalescence state; we don't know whether we're coalesced now or not\n\t\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t\t\ttsinfo.last_coalescence_state_ = false;\n\t\t}\n\t}\n\telse if (file_format == SLiMFileFormat::kFormatTskitBinary_kastore)\n\t{\n\t\tif (chromosomes_.size() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): the focal species defines \" << chromosomes_.size() << \" chromosomes.  A single-chromosome tree-sequence file cannot be read in for this species, because the number of chromosomes does not match.\" << EidosTerminate();\n\t\t\n\t\t// We have a single chromosome and a single-chromosome .trees file; we will validate downstream that the chromosome information matches\n\t\tnew_tick = _InitializePopulationFromTskitBinaryFile(file_cstr, p_interpreter, p_subpop_remap, *chromosomes_[0]);\n\t}\n\telse if (file_format == SLiMFileFormat::kFormatDirectory)\n\t{\n\t\t// Here we assume that a directory is a multi-chromosome .trees archive; we will check downstream\n\t\tnew_tick = _InitializePopulationFromTskitDirectory(p_file_string, p_interpreter, p_subpop_remap);\n\t}\n\telse if (file_format == SLiMFileFormat::kFormatTskitBinary_HDF5)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): msprime HDF5 binary files are not supported; that file format has been superseded by kastore.\" << EidosTerminate();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InitializePopulationFromFile): unrecognized format code.\" << EidosTerminate();\n\t\n\treturn new_tick;\n}\n\nslim_tick_t Species::_InitializePopulationFromTextFile(const char *p_file, EidosInterpreter *p_interpreter)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::_InitializePopulationFromTextFile(): SLiM global state read\");\n\t\n\tslim_tick_t file_tick, file_cycle;\n\tstd::string line, sub; \n\tstd::ifstream infile(p_file);\n\tint spatial_output_count = 0;\n\tint age_output_count = 0;\n\tbool has_individual_pedigree_IDs = false;\n\tbool has_nucleotides = false;\n\tbool output_ancestral_nucs = false;\n\t\n\tif (!infile.is_open())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): could not open initialization file.\" << EidosTerminate();\n\t\n\t// BCH 2/5/2025: I am removing code for reading file versions older than version 8 (SLiM 5.0); keeping\n\t// the legacy reading code working has been a headache and I want a clean break for multichrom\n\t\n\t// Parse the first line, to get the tick and cycle\n\t{\n\t\tGetInputLine(infile, line);\n\t\n\t\tstd::istringstream iss(line);\n\t\t\n\t\tiss >> sub;\t\t// #OUT:\n\t\t\n\t\tiss >> sub;\t\t// tick\n\t\tint64_t tick_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\tfile_tick = SLiMCastToTickTypeOrRaise(tick_long);\n\t\t\n\t\tiss >> sub;\t\t// cycle; this used to be the \"A\" file type tag, so we try to emit a good error message\n\t\t\n\t\tif (sub == \"A\")\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): reading of population files older than version 8 (SLiM 5.0) is no longer supported.\" << EidosTerminate();\n\t\t\n\t\tint64_t cycle_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\tfile_cycle = SLiMCastToTickTypeOrRaise(cycle_long);\n\t\t\n\t\tiss >> sub;\t\t// should be \"A\"\n\t\tif (sub != \"A\")\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): the file type identifier in the #OUT line should be 'A', but is '\" << sub << \"'.\" << EidosTerminate();\n\t}\n\t\n\t// As of SLiM 2.1, we change the generation as a side effect of loading; otherwise we can't correctly update our state here!\n\t// As of SLiM 3, we set the generation up here, before making any individuals, because we need it to be correct for the tree-seq recording code.\n\t// As of SLiM 4, we set both the tick and the cycle, which are both saved to the file for version 7 and after.\n\tcommunity_.SetTick(file_tick);\n\tSetCycle(file_cycle);\n\t\n\t// Read and ignore initial stuff until we hit the Populations section\n\tint64_t file_version = 0;\t// represents no version tag found\n\t\n\twhile (!infile.eof())\n\t{\n\t\tGetInputLine(infile, line);\n\t\t\n\t\t// Starting in SLiM 3, we handle a Version line if we see one in passing, and it is required below\n\t\tif (line.find(\"Version:\") != std::string::npos)\n\t\t{\n\t\t\tstd::istringstream iss(line);\n\t\t\t\n\t\t\tiss >> sub;\t\t// Version:\n\t\t\tiss >> sub;\t\t// version number\n\t\t\t\n\t\t\tfile_version = (int64_t)EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// Starting in SLiM 5, we handle a Flags line if we see one in passing, but it is not required\n\t\tif (line.find(\"Flags:\") != std::string::npos)\n\t\t{\n\t\t\tstd::istringstream iss(line);\n\t\t\t\n\t\t\tiss >> sub;\t\t// Flags:\n\t\t\t\n\t\t\twhile (iss >> sub)\n\t\t\t{\n\t\t\t\tif (sub == \"SPACE=0\")\n\t\t\t\t\tspatial_output_count = 0;\n\t\t\t\telse if (sub == \"SPACE=1\")\n\t\t\t\t\tspatial_output_count = 1;\n\t\t\t\telse if (sub == \"SPACE=2\")\n\t\t\t\t\tspatial_output_count = 2;\n\t\t\t\telse if (sub == \"SPACE=3\")\n\t\t\t\t\tspatial_output_count = 3;\n\t\t\t\telse if (sub == \"AGES\")\n\t\t\t\t\tage_output_count = 1;\n\t\t\t\telse if (sub == \"PEDIGREES\")\n\t\t\t\t\thas_individual_pedigree_IDs = true;\n\t\t\t\telse if (sub == \"NUC\")\n\t\t\t\t\thas_nucleotides = true;\n\t\t\t\telse if (sub == \"ANC_SEQ\")\n\t\t\t\t\toutput_ancestral_nucs = true;\n\t\t\t\telse if (sub == \"OBJECT_TAGS\")\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): readFromPopulationFile() does not support reading in object tags from text format; output of object tags should be turned off in outputFull(), or you should save in binary instead with binary=T.\" << EidosTerminate();\n\t\t\t\telse if (sub == \"SUBSTITUTIONS\")\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): readFromPopulationFile() does not support reading in substitutions from text format; output of substitutions should be turned off in outputFull(), or you should save in binary instead with binary=T.\" << EidosTerminate();\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): unrecognized flag in Flags line: '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (line.find(\"Populations\") != std::string::npos)\n\t\t\tbreak;\n\t}\n\t\n\t// validate the file version\n\tif (file_version <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): file version is missing or corrupted; reading of population files older than version 8 (SLiM 5.0) is no longer supported.\" << EidosTerminate();\n\tif (file_version < 8)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): file version \" << file_version << \" detected; reading of population files older than version 8 (SLiM 5.0) is no longer supported.\" << EidosTerminate();\n\tif (file_version != 8)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): unrecognized version (\" << file_version << \"); the last version recognized by this version of SLiM is 8 (this file may have been generated by a more recent version of SLiM).\" << EidosTerminate();\n\t\n\t// validate flags that were found (or not found)\n\tif ((spatial_output_count != 0) && (spatial_output_count != SpatialDimensionality()))\t// note that we allow spatial information to be missing\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): a non-zero spatial dimensionality of \" << spatial_output_count << \" is flagged, but the spatial dimensionality of this model is \" << SpatialDimensionality() << \"; that is inconsistent.\" << EidosTerminate();\n\t\n\tif (age_output_count && (model_type_ == SLiMModelType::kModelTypeWF))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): age information is present but the simulation is using a WF model; that is inconsistent.\" << EidosTerminate();\n\tif (!age_output_count && (model_type_ == SLiMModelType::kModelTypeNonWF))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): age information is not present but the simulation is using a nonWF model; age information must be included.\" << EidosTerminate();\n\t\n\tif (has_nucleotides && !IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): nucleotides are flagged as present in this file, but this is a non-nucleotide model; that is inconsistent.\" << EidosTerminate();\n\tif (!has_nucleotides && IsNucleotideBased())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): nucleotides are not flagged as present in this file, but this is a nucleotide model; that is inconsistent.\" << EidosTerminate();\n\tif (output_ancestral_nucs && !has_nucleotides)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): an ancestral sequence is flagged as present, but nucleotides are not flagged as present; that is inconsistent.\" << EidosTerminate();\n\t\n\t// Now we are in the Populations section; read and instantiate each population until we hit the Individuals section\n\twhile (!infile.eof())\n\t{ \n\t\tGetInputLine(infile, line);\n\t\t\n\t\tif (line.length() == 0)\n\t\t\tcontinue;\n\t\tif (line.find(\"Individuals\") != std::string::npos)\n\t\t\tbreak;\n\t\t\n\t\tstd::istringstream iss(line);\n\t\t\n\t\tiss >> sub;\n\t\tslim_objectid_t subpop_index = SLiMEidosScript::ExtractIDFromStringWithPrefix(sub, 'p', nullptr);\n\t\t\n\t\tiss >> sub;\n\t\tint64_t subpop_size_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\tslim_popsize_t subpop_size = SLiMCastToPopsizeTypeOrRaise(subpop_size_long);\n\t\t\n\t\t// SLiM 2.0 output format has <H | S <ratio>> here; if that is missing or \"H\" is given, the population is hermaphroditic and the ratio given is irrelevant\n\t\tdouble sex_ratio = 0.0;\n\t\t\n\t\tif (iss >> sub)\n\t\t{\n\t\t\tif (sub == \"S\")\n\t\t\t{\n\t\t\t\tiss >> sub;\n\t\t\t\tsex_ratio = EidosInterpreter::FloatForString(sub, nullptr);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Create the population population\n\t\tSubpopulation *new_subpop = population_.AddSubpopulation(subpop_index, subpop_size, sex_ratio, false);\n\t\t\n\t\t// define a new Eidos variable to refer to the new subpopulation\n\t\tEidosSymbolTableEntry &symbol_entry = new_subpop->SymbolTableEntry();\n\t\t\n\t\tif (p_interpreter && p_interpreter->SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): new subpopulation symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\t\n\t\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t}\n\t\n\t// Now we are in the Individuals section; handle spatial positions, etc. until we hit a Chromosome line\n\tconst std::vector<Chromosome *> &chromosomes = Chromosomes();\n\t\n\tif (has_individual_pedigree_IDs)\n\t\tgSLiM_next_pedigree_id = 0;\n\t\n\tif (line.find(\"Individuals\") != std::string::npos)\n\t{\n\t\twhile (!infile.eof()) \n\t\t{\n\t\t\tGetInputLine(infile, line);\n\t\t\t\n\t\t\tif (line.length() == 0)\n\t\t\t\tcontinue;\n\t\t\tif (line.find(\"Chromosome\") != std::string::npos)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tstd::istringstream iss(line);\n\t\t\t\n\t\t\tiss >> sub;\t\t// pX:iY – individual identifier\n\t\t\tstd::size_t pos = static_cast<int>(sub.find_first_of(':'));\n\t\t\t\n\t\t\tif (pos == std::string::npos)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): colon missing in individual specifier.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::string &&subpop_id_string = sub.substr(0, pos);\n\t\t\t\n\t\t\tslim_objectid_t subpop_id = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_string, 'p', nullptr);\n\t\t\tstd::string &&individual_index_string = sub.substr(pos + 1, std::string::npos);\n\t\t\t\n\t\t\tif (individual_index_string[0] != 'i')\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): reference to individual is malformed.\" << EidosTerminate();\n\t\t\t\n\t\t\tint64_t individual_index = EidosInterpreter::NonnegativeIntegerForString(individual_index_string.c_str() + 1, nullptr);\n\t\t\t\n\t\t\tSubpopulation *subpop = SubpopulationWithID(subpop_id);\n\t\t\t\n\t\t\tif (!subpop)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): referenced subpopulation p\" << subpop_id << \" not defined.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (individual_index >= subpop->parent_subpop_size_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): referenced individual i\" << individual_index << \" is out of range.\" << EidosTerminate();\n\t\t\t\n\t\t\tIndividual &individual = *subpop->parent_individuals_[individual_index];\n\t\t\t\n\t\t\tif (has_individual_pedigree_IDs)\n\t\t\t{\n\t\t\t\t// If pedigree IDs are present use them; if not, we'll get whatever the default IDs are from the subpop construction\n\t\t\t\tiss >> sub;\n\t\t\t\tint64_t pedigree_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\t\tslim_pedigreeid_t pedigree_id = SLiMCastToPedigreeIDOrRaise(pedigree_long);\n\t\t\t\t\n\t\t\t\tif (PedigreesEnabled())\n\t\t\t\t{\n\t\t\t\t\tindividual.SetPedigreeID(pedigree_id);\n\t\t\t\t\tgSLiM_next_pedigree_id = std::max(gSLiM_next_pedigree_id, pedigree_id + 1);\n\t\t\t\t\t\n\t\t\t\t\t// we need to fix the haplosome ids for all of the individual's haplosomes\n\t\t\t\t\tint haplosome_index = 0;\n\t\t\t\t\t\n\t\t\t\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\t\t\t{\n\t\t\t\t\t\tindividual.haplosomes_[haplosome_index++]->SetHaplosomeID(pedigree_id * 2);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (chromosome->IntrinsicPloidy() == 2)\n\t\t\t\t\t\t\tindividual.haplosomes_[haplosome_index++]->SetHaplosomeID(pedigree_id * 2 + 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbool sex_mismatch = false;\n\t\t\tiss >> sub;\t\t\t// individual sex identifier (F/M/H)\n\t\t\t\n\t\t\tif (sub == \"F\")\n\t\t\t{\n\t\t\t\tif (individual.sex_ != IndividualSex::kFemale)\n\t\t\t\t\tsex_mismatch = true;\n\t\t\t}\n\t\t\telse if (sub == \"M\")\n\t\t\t{\n\t\t\t\tif (individual.sex_ != IndividualSex::kMale)\n\t\t\t\t\tsex_mismatch = true;\n\t\t\t}\n\t\t\telse if (sub == \"H\")\n\t\t\t{\n\t\t\t\tif (individual.sex_ != IndividualSex::kHermaphrodite)\n\t\t\t\t\tsex_mismatch = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): unrecognized individual sex '\" << sub << \"'.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (sex_mismatch)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): the specified individual sex '\" << sub << \"' does not match the sex of the individual '\" << individual.sex_ << \"'.\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 2/5/2025: Before version 8, we emitted haplosome identifiers here, like \"p1:16\" and\n\t\t\t// \"p1:17\", but now that we have multiple chromosomes that really isn't helpful; removing\n\t\t\t// them.  In the Haplosomes section we will now just identify the individual; that suffices.\n\t\t\t\n\t\t\t// Parse the optional fields at the end of each individual line.  This is a bit tricky.\n\t\t\t// First we read all of the fields in, then we decide how to use them.\n\t\t\tstd::vector<std::string> opt_params;\n\t\t\tint expected_opt_param_count = spatial_output_count + age_output_count;\n\t\t\tint opt_param_index = 0;\n\t\t\t\n\t\t\twhile (iss >> sub)\n\t\t\t\topt_params.emplace_back(sub);\n\t\t\t\n\t\t\tif ((int)opt_params.size() != expected_opt_param_count)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): output file format does not contain the expected individual data, as specified by the Flags line.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (spatial_output_count)\n\t\t\t{\n\t\t\t\t// age information is present, in addition to the correct number of spatial positions\n\t\t\t\tif (spatial_output_count >= 1)\n\t\t\t\t\tindividual.spatial_x_ = EidosInterpreter::FloatForString(opt_params[opt_param_index++], nullptr);\t// spatial position x\n\t\t\t\tif (spatial_output_count >= 2)\n\t\t\t\t\tindividual.spatial_y_ = EidosInterpreter::FloatForString(opt_params[opt_param_index++], nullptr);\t// spatial position y\n\t\t\t\tif (spatial_output_count >= 3)\n\t\t\t\t\tindividual.spatial_z_ = EidosInterpreter::FloatForString(opt_params[opt_param_index++], nullptr);\t// spatial position z\n\t\t\t}\n\t\t\t\n\t\t\tif (age_output_count)\n\t\t\t{\n\t\t\t\tindividual.age_ = (slim_age_t)EidosInterpreter::NonnegativeIntegerForString(opt_params[opt_param_index++], nullptr);\t// age\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Now we loop over chromosomes; each starts with a Chromosome line and then contains subsections\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\t// we should currently have a Chromosome line that matches the current chromosome\n\t\tstd::istringstream chrom_iss(line);\n\t\t\n\t\tchrom_iss >> sub;\t// Chromosome:\n\t\t\n\t\t// chromosome index; chromosomes should be given in the same order as in the model\n\t\tchrom_iss >> sub;\n\t\tint64_t raw_chromosome_index = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\n\t\tif (raw_chromosome_index >= (int)chromosomes.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome index \" << raw_chromosome_index << \" out of range.\" << EidosTerminate();\n\t\t\n\t\tslim_chromosome_index_t chromosome_index = (slim_chromosome_index_t)raw_chromosome_index;\n\t\t\n\t\tif (chromosome_index != chromosome->Index())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome index \" << chromosome_index << \" does not match expected index \" << (unsigned int)(chromosome->Index()) << \".\" << EidosTerminate();\n\t\t\n\t\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\t\t//int last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\t\n\t\t// chromosome type\n\t\tchrom_iss >> sub;\n\t\tChromosomeType chromosome_type = ChromosomeTypeForString(sub);\n\t\t\n\t\tif (chromosome_type != chromosome->Type())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome type \" << chromosome_type << \" does not match expected index \" << chromosome->Type() << \".\" << EidosTerminate();\n\t\t\n\t\t// chromosome id\n\t\tchrom_iss >> sub;\n\t\tint64_t chromosome_id = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\n\t\tif (chromosome_id != chromosome->ID())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome id \" << chromosome_id << \" does not match expected id \" << chromosome->ID() << \".\" << EidosTerminate();\n\t\t\n\t\t// chromosome last position\n\t\tchrom_iss >> sub;\n\t\tint64_t chromosome_lastpos = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\n\t\tif (chromosome_lastpos != chromosome->last_position_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome last position \" << chromosome_lastpos << \" does not match expected last position \" << chromosome->last_position_ << \".\" << EidosTerminate();\n\t\t\n\t\t// chromosome symbol\n\t\tchrom_iss >> sub;\n\t\tstd::string quoted_symbol = '\\\"' + chromosome->Symbol() + '\\\"';\n\t\t\n\t\tif (sub != quoted_symbol)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): chromosome symbol \" << sub << \" does not match expected symbol \" << chromosome->Symbol() << \".\" << EidosTerminate();\n\t\t\n\t\tGetInputLine(infile, line);\n\t\tif (line.find(\"Mutations\") == std::string::npos)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): a Mutations section must follow each Chromosome line.\" << EidosTerminate();\n\t\t\n\t\t// Now we are in the Mutations section; read and instantiate all mutations and add them to our map and to the registry\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\trobin_hood::unordered_flat_map<slim_polymorphismid_t,MutationIndex> mutations;\n#elif STD_UNORDERED_MAP_HASHING\n\t\tstd::unordered_map<slim_polymorphismid_t,MutationIndex> mutations;\n#endif\n\t\t\n\t\twhile (!infile.eof()) \n\t\t{\n\t\t\tGetInputLine(infile, line);\n\t\t\t\n\t\t\tif (line.length() == 0)\n\t\t\t\tcontinue;\n\t\t\tif (line.find(\"Haplosomes\") != std::string::npos)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tstd::istringstream iss(line);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tint64_t polymorphismid_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\tslim_polymorphismid_t polymorphism_id = SLiMCastToPolymorphismidTypeOrRaise(polymorphismid_long);\n\t\t\t\n\t\t\t// Added in version 2 output, starting in SLiM 2.1\n\t\t\tiss >> sub;\n\t\t\tslim_mutationid_t mutation_id;\n\t\t\t\n\t\t\tif (sub[0] == 'm')\t// autodetect whether we are parsing version 1 or version 2 output\n\t\t\t{\n\t\t\t\tmutation_id = polymorphism_id;\t\t// when parsing version 1 output, we use the polymorphism id as the mutation id\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmutation_id = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\t\t\n\t\t\t\tiss >> sub;\t\t// queue up sub for mutation_type_id\n\t\t\t}\n\t\t\t\n\t\t\tslim_objectid_t mutation_type_id = SLiMEidosScript::ExtractIDFromStringWithPrefix(sub, 'm', nullptr);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tint64_t position_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\tslim_position_t position = SLiMCastToPositionTypeOrRaise(position_long);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tdouble selection_coeff = EidosInterpreter::FloatForString(sub, nullptr);\n\t\t\t\n\t\t\tiss >> sub;\t\t// dominance coefficient, which is given in the mutation type; we check below that the value read matches the mutation type\n\t\t\tdouble dominance_coeff = EidosInterpreter::FloatForString(sub, nullptr);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tslim_objectid_t subpop_index = SLiMEidosScript::ExtractIDFromStringWithPrefix(sub, 'p', nullptr);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tint64_t tick_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\tslim_tick_t tick = SLiMCastToTickTypeOrRaise(tick_long);\n\t\t\t\n\t\t\tiss >> sub;\t\t// prevalence, which we discard\n\t\t\t\n\t\t\tint8_t nucleotide = -1;\n\t\t\tif (iss && (iss >> sub))\n\t\t\t{\n\t\t\t\t// fetch the nucleotide field if it is present\n\t\t\t\tif (sub == \"A\") nucleotide = 0;\n\t\t\t\telse if (sub == \"C\") nucleotide = 1;\n\t\t\t\telse if (sub == \"G\") nucleotide = 2;\n\t\t\t\telse if (sub == \"T\") nucleotide = 3;\n\t\t\t\telse EIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): unrecognized value '\"<< sub << \"' in nucleotide field.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\t// look up the mutation type from its index\n\t\t\tMutationType *mutation_type_ptr = MutationTypeWithID(mutation_type_id);\n\t\t\t\n\t\t\tif (!mutation_type_ptr) \n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): mutation type m\"<< mutation_type_id << \" has not been defined for this species.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (!Eidos_ApproximatelyEqual(mutation_type_ptr->dominance_coeff_, dominance_coeff))\t// a reasonable tolerance to allow for I/O roundoff\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): mutation type m\"<< mutation_type_id << \" has dominance coefficient \" << mutation_type_ptr->dominance_coeff_ << \" that does not match the population file dominance coefficient of \" << dominance_coeff << \".\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 9/22/2021: Note that mutation_type_ptr->hemizygous_dominance_coeff_ is not saved, or checked here; too edge to be bothered...\n\t\t\t\n\t\t\tif ((nucleotide == -1) && mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): mutation type m\"<< mutation_type_id << \" is nucleotide-based, but a nucleotide value for a mutation of this type was not supplied.\" << EidosTerminate();\n\t\t\tif ((nucleotide != -1) && !mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): mutation type m\"<< mutation_type_id << \" is not nucleotide-based, but a nucleotide value for a mutation of this type was supplied.\" << EidosTerminate();\n\t\t\t\n\t\t\t// construct the new mutation; NOTE THAT THE STACKING POLICY IS NOT CHECKED HERE, AS THIS IS NOT CONSIDERED THE ADDITION OF A MUTATION!\n\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\t\n\t\t\tMutation *new_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_id, mutation_type_ptr, chromosome_index, position, selection_coeff, subpop_index, tick, nucleotide);\n\t\t\t\n\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\tmutations.emplace(polymorphism_id, new_mut_index);\n\t\t\tpopulation_.MutationRegistryAdd(new_mut);\n\t\t\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t\t\tif (population_.keeping_muttype_registries_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): (internal error) separate muttype registries set up during pop load.\" << EidosTerminate();\n#endif\n\t\t\t\n\t\t\t// all mutations seen here will be added to the simulation somewhere, so check and set pure_neutral_ and all_pure_neutral_DFE_\n\t\t\tif (selection_coeff != 0.0)\n\t\t\t{\n\t\t\t\tpure_neutral_ = false;\n\t\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpopulation_.InvalidateMutationReferencesCache();\n\t\t\n\t\t// Now we are in the Haplosomes section, which should take us to the end of the chromosome unless there is an Ancestral Sequence section\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n#ifndef _OPENMP\n\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\t\tslim_popsize_t previous_individual_index = -1;\t// detect the first/second haplosome for intrinsically diploid chromosomes\n\t\t\n\t\twhile (!infile.eof())\n\t\t{\n\t\t\tGetInputLine(infile, line);\n\t\t\t\n\t\t\tif (line.length() == 0)\n\t\t\t\tcontinue;\n\t\t\tif (line.find(\"Ancestral sequence\") != std::string::npos)\n\t\t\t\tbreak;\n\t\t\tif (line.find(\"Chromosome\") != std::string::npos)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tstd::istringstream iss(line);\n\t\t\t\n\t\t\tiss >> sub;\n\t\t\tstd::size_t pos = static_cast<int>(sub.find_first_of(':'));\n\t\t\t\n\t\t\tif (pos == std::string::npos)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): colon missing in individual specifier.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::string &&subpop_id_string = sub.substr(0, pos);\n\t\t\t\n\t\t\tslim_objectid_t subpop_id = SLiMEidosScript::ExtractIDFromStringWithPrefix(subpop_id_string, 'p', nullptr);\n\t\t\tstd::string &&individual_index_string = sub.substr(pos + 1, std::string::npos);\n\t\t\t\n\t\t\tif (individual_index_string[0] != 'i')\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): reference to individual is malformed.\" << EidosTerminate();\n\t\t\t\n\t\t\t// this used to be the haplosome index, now it is the individual index and we have to figure out the haplosome index\n\t\t\tint64_t individual_index_long = EidosInterpreter::NonnegativeIntegerForString(individual_index_string.c_str() + 1, nullptr);\n\t\t\t\n\t\t\tSubpopulation *subpop = SubpopulationWithID(subpop_id);\n\t\t\t\n\t\t\tif (!subpop)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): referenced subpopulation p\" << subpop_id << \" not defined.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (individual_index_long >= subpop->parent_subpop_size_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): referenced individual i\" << individual_index_long << \" is out of range.\" << EidosTerminate();\n\t\t\tslim_popsize_t individual_index = static_cast<slim_popsize_t>(individual_index_long);\n\t\t\t\n\t\t\t// detect when this is the second haplosome line for a given individual, and validate that\n\t\t\t// FIXME this code is brittle in various ways -- a second line might be needed but omitted, or a third line might be given\n\t\t\tbool is_individual_index_repeat = (individual_index == previous_individual_index);\n\t\t\t\n\t\t\tif (is_individual_index_repeat && (chromosome->IntrinsicPloidy() != 2))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): a second haplosome was specified for a chromosome that is intrinsically haploid.\" << EidosTerminate();\n\t\t\t\n\t\t\tprevious_individual_index = individual_index;\n\t\t\t\n\t\t\t// look up the individual and haplosome\n\t\t\tIndividual *ind = subpop->parent_individuals_[individual_index];\n\t\t\tint haplosome_index = first_haplosome_index + is_individual_index_repeat;\n\t\t\tHaplosome &haplosome = *(ind->haplosomes_[haplosome_index]);\n\t\t\t\n\t\t\tif (haplosome.chromosome_index_ != chromosome->Index())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): (internal error) haplosome does not belong to the focal chromosome.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (iss >> sub)\n\t\t\t{\n\t\t\t\t// BCH 2/5/2025: We instantiate null haplosomes only where expect them to be, based upon\n\t\t\t\t// the chromosome type.  For chromosome types 'A' and 'H', null haplosomes can occur anywhere;\n\t\t\t\t// when that happens, we transform the instantiated haplosome to a null haplosome if necessary.\n\t\t\t\t// AddSubpopulation() created the haplosomes above, before we knew which would be null.\n\t\t\t\tif (sub == \"<null>\")\n\t\t\t\t{\n\t\t\t\t\tif (!haplosome.IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((model_type_ == SLiMModelType::kModelTypeNonWF) && ((chromosome_type == ChromosomeType::kA_DiploidAutosome) || (chromosome_type == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thaplosome.MakeNull();\n\t\t\t\t\t\t\tsubpop->has_null_haplosomes_ = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): haplosome is specified as null, but the instantiated haplosome is non-null.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tcontinue;\t// this line is over\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (haplosome.IsNull())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): haplosome is specified as non-null, but the instantiated haplosome is null.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// drop through, and sub will be interpreted as a mutation id below\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tcontinue;\t// no mutations\n\t\t\t\t\n\t\t\tslim_position_t mutrun_length_ = haplosome.mutrun_length_;\n\t\t\tslim_mutrun_index_t current_mutrun_index = -1;\n\t\t\tMutationRun *current_mutrun = nullptr;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tint64_t polymorphismid_long = EidosInterpreter::NonnegativeIntegerForString(sub, nullptr);\n\t\t\t\tslim_polymorphismid_t polymorphism_id = SLiMCastToPolymorphismidTypeOrRaise(polymorphismid_long);\n\t\t\t\t\n\t\t\t\tauto found_mut_pair = mutations.find(polymorphism_id);\n\t\t\t\t\n\t\t\t\tif (found_mut_pair == mutations.end()) \n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): polymorphism \" << polymorphism_id << \" has not been defined.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tMutationIndex mutation = found_mut_pair->second;\n\t\t\t\tslim_mutrun_index_t mutrun_index = (slim_mutrun_index_t)((mut_block_ptr + mutation)->position_ / mutrun_length_);\n\t\t\t\t\n\t\t\t\tassert(mutrun_index != -1);\t\t// to clue in the static analyzer\n\t\t\t\t\n\t\t\t\tif (mutrun_index != current_mutrun_index)\n\t\t\t\t{\n#ifdef _OPENMP\n\t\t\t\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\t\t\t\tMutationRunContext &mutrun_context = chromosome.ChromosomeMutationRunContextForMutationRunIndex(mutrun_index);\n#endif\n\t\t\t\t\t\n\t\t\t\t\tcurrent_mutrun_index = mutrun_index;\n\t\t\t\t\t\n\t\t\t\t\t// We use WillModifyRun_UNSHARED() because we know that these runs are unshared (unless empty);\n\t\t\t\t\t// we created them empty, nobody has modified them but us, and we process each haplosome separately.\n\t\t\t\t\t// However, using WillModifyRun() would generally be fine since we hit this call only once\n\t\t\t\t\t// per mutrun per haplosome anyway, as long as the mutations are sorted by position.\n\t\t\t\t\tcurrent_mutrun = haplosome.WillModifyRun_UNSHARED(current_mutrun_index, mutrun_context);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcurrent_mutrun->emplace_back(mutation);\n\t\t\t}\n\t\t\twhile (iss >> sub);\n\t\t}\n\t\t\n\t\t// Now we are in the Ancestral sequence section, which should take us to the end of the chromosome\n\t\t// (or file).  Conveniently, NucleotideArray supports operator>> to read nucleotides until the EOF.\n\t\t// BCH 2/5/2025: that operator>> code now stops if it sees two newlines, also, which we rely on here\n\t\t// to recognize the end of the sequence and then begin a new Chromosome section.\n\t\tif (line.find(\"Ancestral sequence\") != std::string::npos)\n\t\t{\n\t\t\tinfile >> *(chromosome->AncestralSequence());\n\t\t}\n\t\telse if (output_ancestral_nucs)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTextFile): an ancestral sequence is flagged as present, but was not found.\" << EidosTerminate();\n\t}\n\t\n\t// It's a little unclear how we ought to clean up after ourselves, and this is a continuing source of bugs.  We could be loading\n\t// a new population in an early() event, in a late() event, or in between cycles in SLiMgui, e.g. in the Eidos console.\n\t// The safest avenue seems to be to just do all the bookkeeping we can think of: tally frequencies, calculate fitnesses, and\n\t// survey the population for SLiMgui.  This will lead to some of these actions being done at an unusual time in the cycle,\n\t// though, and will cause some things to be done unnecessarily (because they are not normally up-to-date at the current\n\t// cycle stage anyway) or done twice (which could be particularly problematic for mutationEffect() callbacks).  Nevertheless, this seems\n\t// like the best policy, at least until shown otherwise...  BCH 11 June 2016\n\t\n\t// BCH 5 April 2017: Well, it has been shown otherwise.  Now that interactions have been added, mutationEffect() callbacks often depend on\n\t// them, which means the interactions need to be evaluated, which means we can't evaluate fitness values yet; we need to give the\n\t// user's script a chance to evaluate the interactions.  This was always a problem, really; mutationEffect() callbacks might have needed\n\t// some external state to be set up that would be on the population state.  But now it is a glaring problem, and forces us to revise\n\t// our policy.  All we do now is unique mutation runs and retally mutrun/mutation counts.\n\t\n\t// Re-tally mutation references so we have accurate frequency counts for our new mutations\n\tpopulation_.UniqueMutationRuns();\n\tpopulation_.InvalidateMutationReferencesCache();\t// force a retally\n\tpopulation_.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t\n\treturn file_tick;\n}\n\n#ifndef __clang_analyzer__\nslim_tick_t Species::_InitializePopulationFromBinaryFile(const char *p_file, EidosInterpreter *p_interpreter)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::_InitializePopulationFromBinaryFile(): SLiM global state read\");\n\t\n\tstd::size_t file_size = 0;\n\tslim_tick_t file_tick, file_cycle;\n\t\n\t// options in the flags field\n\tint32_t spatial_output_count = 0;\n\tint age_output_count = 0;\n\tint pedigree_output_count = 0;\n\tbool has_nucleotides = false;\n\tbool has_ancestral_nucs = false;\n\tbool has_object_tags = false;\n\tbool has_substitutions = false;\n\t\n\t// Read file into buf\n\tstd::ifstream infile(p_file, std::ios::in | std::ios::binary);\n\t\n\tif (!infile.is_open() || infile.eof())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): could not open initialization file.\" << EidosTerminate();\n\t\n\t// Determine the file length\n\tinfile.seekg(0, std::ios_base::end);\n\tfile_size = infile.tellg();\n\t\n\t// Read in the entire file; we assume we have enough memory, for now\n\tstd::unique_ptr<char[]> raii_buf(new char[file_size]);\n\tchar *buf = raii_buf.get();\n\t\n\tif (!buf)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): could not allocate input buffer.\" << EidosTerminate();\n\t\n\tchar *buf_end = buf + file_size;\n\tchar *p = buf;\n\t\n\tinfile.seekg(0, std::ios_base::beg);\n\tinfile.read(buf, file_size);\n\t\n\t// Close the file; we will work only with our buffer from here on\n\t// Note that we use memcpy() to read values from the buffer, since it takes care of alignment issues\n\t// for us that otherwise bother the UndefinedBehaviorSanitizer.  On platforms that don't care about\n\t// alignment this should compile down to the same code; on platforms that do care, it avoids a crash.\n\tinfile.close();\n\t\n\tint32_t section_end_tag;\n\tint32_t file_version;\n\t\n\t// Header beginning, to check endianness and determine file version\n\t{\n\t\tint32_t endianness_tag, version_tag;\n\t\t\n\t\tif (p + sizeof(endianness_tag) + sizeof(version_tag) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF while reading header.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&endianness_tag, p, sizeof(endianness_tag));\n\t\tp += sizeof(endianness_tag);\n\t\t\n\t\tmemcpy(&version_tag, p, sizeof(version_tag));\n\t\tp += sizeof(version_tag);\n\t\t\n\t\tif (endianness_tag != 0x12345678)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): endianness mismatch.\" << EidosTerminate();\n\t\t\n\t\tfile_version = version_tag;\n\t\t\n\t\tif (file_version <= 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): file version is missing or corrupted; reading of population files older than version 8 (SLiM 5.0) is no longer supported.\" << EidosTerminate();\n\t\tif (file_version < 8)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): file version \" << file_version << \" detected; reading of population files older than version 8 (SLiM 5.0) is no longer supported.\" << EidosTerminate();\n\t\tif (file_version != 8)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unrecognized version (\" << file_version << \"); the last version recognized by this version of SLiM is 8 (this file may have been generated by a more recent version of SLiM).\" << EidosTerminate();\n\t}\n\t\n\t// Header section\n\t{\n\t\tint32_t double_size;\n\t\tdouble double_test;\n\t\tint64_t flags = 0;\n\t\tint32_t slim_tick_t_size, slim_position_t_size, slim_objectid_t_size, slim_popsize_t_size, slim_refcount_t_size, slim_selcoeff_t_size, slim_mutationid_t_size, slim_polymorphismid_t_size, slim_age_t_size, slim_pedigreeid_t_size, slim_haplosomeid_t_size, slim_usertag_t_size;\n\t\tint header_length = sizeof(double_size) + sizeof(double_test) + sizeof(flags) + sizeof(slim_tick_t_size) + sizeof(slim_position_t_size) + sizeof(slim_objectid_t_size) + sizeof(slim_popsize_t_size) + sizeof(slim_refcount_t_size) + sizeof(slim_selcoeff_t_size) + sizeof(slim_mutationid_t_size) + sizeof(slim_polymorphismid_t_size) + sizeof(slim_age_t_size) + sizeof(slim_pedigreeid_t_size) + sizeof(slim_haplosomeid_t_size) + sizeof(slim_usertag_t_size) + sizeof(file_tick) + sizeof(file_cycle) + sizeof(section_end_tag);\n\t\t\n\t\t// this is how to add more header tags in future versions\n\t\t//if (file_version >= 9)\n\t\t//\theader_length += sizeof(new_header_variable);\n\t\t\n\t\tif (p + header_length > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF while reading header.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&double_size, p, sizeof(double_size));\n\t\tp += sizeof(double_size);\n\t\t\n\t\tmemcpy(&double_test, p, sizeof(double_test));\n\t\tp += sizeof(double_test);\n\t\t\n\t\tmemcpy(&flags, p, sizeof(flags));\n\t\tp += sizeof(flags);\n\t\t\n\t\tif (flags & 0x0003) spatial_output_count = (flags & 0x03);\n\t\tif (flags & 0x0004) age_output_count = 1;\n\t\tif (flags & 0x0008) pedigree_output_count = 1;\n\t\tif (flags & 0x0010) has_nucleotides = true;\n\t\tif (flags & 0x0020) has_ancestral_nucs = true;\n\t\tif (flags & 0x0040) has_object_tags = true;\n\t\tif (flags & 0x0080) has_substitutions = true;\n\t\t\n\t\tmemcpy(&slim_tick_t_size, p, sizeof(slim_tick_t_size));\n\t\tp += sizeof(slim_tick_t_size);\n\t\t\n\t\tmemcpy(&slim_position_t_size, p, sizeof(slim_position_t_size));\n\t\tp += sizeof(slim_position_t_size);\n\t\t\n\t\tmemcpy(&slim_objectid_t_size, p, sizeof(slim_objectid_t_size));\n\t\tp += sizeof(slim_objectid_t_size);\n\t\t\n\t\tmemcpy(&slim_popsize_t_size, p, sizeof(slim_popsize_t_size));\n\t\tp += sizeof(slim_popsize_t_size);\n\t\t\n\t\tmemcpy(&slim_refcount_t_size, p, sizeof(slim_refcount_t_size));\n\t\tp += sizeof(slim_refcount_t_size);\n\t\t\n\t\tmemcpy(&slim_selcoeff_t_size, p, sizeof(slim_selcoeff_t_size));\n\t\tp += sizeof(slim_selcoeff_t_size);\n\t\t\n\t\tmemcpy(&slim_mutationid_t_size, p, sizeof(slim_mutationid_t_size));\n\t\tp += sizeof(slim_mutationid_t_size);\n\t\t\n\t\tmemcpy(&slim_polymorphismid_t_size, p, sizeof(slim_polymorphismid_t_size));\n\t\tp += sizeof(slim_polymorphismid_t_size);\n\t\t\n\t\tmemcpy(&slim_age_t_size, p, sizeof(slim_age_t_size));\n\t\tp += sizeof(slim_age_t_size);\n\t\t\n\t\tmemcpy(&slim_pedigreeid_t_size, p, sizeof(slim_pedigreeid_t_size));\n\t\tp += sizeof(slim_pedigreeid_t_size);\n\t\t\n\t\tmemcpy(&slim_haplosomeid_t_size, p, sizeof(slim_haplosomeid_t_size));\n\t\tp += sizeof(slim_haplosomeid_t_size);\n\t\t\n\t\tmemcpy(&slim_usertag_t_size, p, sizeof(slim_usertag_t_size));\n\t\tp += sizeof(slim_usertag_t_size);\n\t\t\n\t\tmemcpy(&file_tick, p, sizeof(file_tick));\n\t\tp += sizeof(file_tick);\n\t\t\n\t\tmemcpy(&file_cycle, p, sizeof(file_cycle));\n\t\tp += sizeof(file_cycle);\n\t\t\n\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\tp += sizeof(section_end_tag);\n\t\t\n\t\tif (double_size != sizeof(double))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): sizeof(double) mismatch.\" << EidosTerminate();\n\t\tif (double_test != 1234567890.0987654321)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): double format mismatch.\" << EidosTerminate();\n\t\t\n\t\tif ((spatial_output_count < 0) || (spatial_output_count > 3))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): spatial output count out of range.\" << EidosTerminate();\n\t\tif ((spatial_output_count > 0) && (spatial_output_count != spatial_dimensionality_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): output spatial dimensionality does not match that of the simulation.\" << EidosTerminate();\n\t\t\n\t\tif (age_output_count && (model_type_ == SLiMModelType::kModelTypeWF))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): age information is present but the simulation is using a WF model.\" << EidosTerminate();\n\t\tif (!age_output_count && (model_type_ == SLiMModelType::kModelTypeNonWF))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): age information is not present but the simulation is using a nonWF model; age information must be included.\" << EidosTerminate();\n\t\t\n\t\tif (has_nucleotides && !nucleotide_based_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): the output was generated by a nucleotide-based model, but the current model is not nucleotide-based.\" << EidosTerminate();\n\t\tif (!has_nucleotides && nucleotide_based_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): the output was generated by a non-nucleotide-based model, but the current model is nucleotide-based.\" << EidosTerminate();\n\t\tif (has_ancestral_nucs && !has_nucleotides)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): an ancestral sequence is flagged as present, but the current model is not nucleotide-based.\" << EidosTerminate();\n\t\t\n\t\tif ((slim_tick_t_size != sizeof(slim_tick_t)) ||\n\t\t\t(slim_position_t_size != sizeof(slim_position_t)) ||\n\t\t\t(slim_objectid_t_size != sizeof(slim_objectid_t)) ||\n\t\t\t(slim_popsize_t_size != sizeof(slim_popsize_t)) ||\n\t\t\t(slim_refcount_t_size != sizeof(slim_refcount_t)) ||\n\t\t\t(slim_selcoeff_t_size != sizeof(slim_selcoeff_t)) ||\n\t\t\t(slim_mutationid_t_size != sizeof(slim_mutationid_t)) ||\n\t\t\t(slim_polymorphismid_t_size != sizeof(slim_polymorphismid_t)) ||\n\t\t\t(slim_age_t_size != sizeof(slim_age_t)) ||\n\t\t\t(slim_pedigreeid_t_size != sizeof(slim_pedigreeid_t)) ||\n\t\t\t(slim_haplosomeid_t_size != sizeof(slim_haplosomeid_t)) ||\n\t\t\t(slim_usertag_t_size != sizeof(slim_usertag_t)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): SLiM datatype size mismatch.\" << EidosTerminate();\n\t\t\n\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after header.\" << EidosTerminate();\n\t}\n\t\n\t// As of SLiM 2.1, we change the generation as a side effect of loading; otherwise we can't correctly update our state here!\n\t// As of SLiM 3, we set the generation up here, before making any individuals, because we need it to be correct for the tree-seq recording code.\n\t// As of SLiM 4, we set both the tick and the cycle, which are both saved to the file for version 7 and after.\n\tcommunity_.SetTick(file_tick);\n\tSetCycle(file_cycle);\n\t\n\t// Populations section\n\twhile (true)\n\t{\n\t\tint32_t subpop_start_tag;\n\t\tslim_objectid_t subpop_id;\n\t\tslim_popsize_t subpop_size;\n\t\tint32_t sex_flag;\n\t\tdouble subpop_sex_ratio;\n\t\t\n\t\t// If there isn't enough buffer left to read a full subpop record, we assume we are done with this section\n\t\tif (p + sizeof(subpop_start_tag) + sizeof(subpop_id) + sizeof(subpop_size) + sizeof(sex_flag) + sizeof(subpop_sex_ratio) + (has_object_tags ? sizeof(slim_usertag_t) : 0) > buf_end)\n\t\t\tbreak;\n\t\t\n\t\t// If the first int32_t is not a subpop start tag, then we are done with this section\n\t\tmemcpy(&subpop_start_tag, p, sizeof(subpop_start_tag));\n\t\tif (subpop_start_tag != (int32_t)0xFFFF0001)\n\t\t\tbreak;\n\t\t\n\t\t// Otherwise, we have a subpop record; read in the rest of it\n\t\tp += sizeof(subpop_start_tag);\n\t\t\n\t\tmemcpy(&subpop_id, p, sizeof(subpop_id));\n\t\tp += sizeof(subpop_id);\n\t\t\n\t\tmemcpy(&subpop_size, p, sizeof(subpop_size));\n\t\tp += sizeof(subpop_size);\n\t\t\n\t\tmemcpy(&sex_flag, p, sizeof(sex_flag));\n\t\tp += sizeof(sex_flag);\n\t\t\n\t\tif (sex_flag != sex_enabled_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): sex vs. hermaphroditism mismatch between file and simulation.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&subpop_sex_ratio, p, sizeof(subpop_sex_ratio));\n\t\tp += sizeof(subpop_sex_ratio);\n\t\t\n\t\t// Create the population population\n\t\tSubpopulation *new_subpop = population_.AddSubpopulation(subpop_id, subpop_size, subpop_sex_ratio, false);\n\t\t\n\t\tif (has_object_tags)\n\t\t{\n\t\t\tmemcpy(&new_subpop->tag_value_, p, sizeof(new_subpop->tag_value_));\n\t\t\tp += sizeof(new_subpop->tag_value_);\n\t\t}\n\t\t\n\t\t// define a new Eidos variable to refer to the new subpopulation\n\t\tEidosSymbolTableEntry &symbol_entry = new_subpop->SymbolTableEntry();\n\t\t\n\t\tif (p_interpreter && p_interpreter->SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): new subpopulation symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\t\n\t\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t}\n\t\n\tif (p + sizeof(section_end_tag) > buf_end)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after subpopulations.\" << EidosTerminate();\n\telse\n\t{\n\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\tp += sizeof(section_end_tag);\n\t\t\n\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after subpopulations.\" << EidosTerminate();\n\t}\n\t\n\t// Individuals section\n\tconst std::vector<Chromosome *> &chromosomes = Chromosomes();\n\t\n\tif (pedigree_output_count)\n\t\tgSLiM_next_pedigree_id = 0;\n\t\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\tslim_popsize_t subpop_size = subpop->parent_subpop_size_;\n\t\t\n\t\tfor (slim_popsize_t individual_index = 0; individual_index < subpop_size; individual_index++)\t// go through all children\n\t\t{\n\t\t\t// If there isn't enough buffer left to read a full subpop record, we have an error\n\t\t\tif (p + sizeof(IndividualSex) + pedigree_output_count * sizeof(slim_pedigreeid_t) + spatial_output_count * sizeof(double) + age_output_count * sizeof(slim_age_t) + (has_object_tags ? sizeof(slim_usertag_t) + sizeof(double) + 5*sizeof(char) : 0) > buf_end)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF in individuals section.\" << EidosTerminate();\n\t\t\t\n\t\t\tIndividual &individual = *(subpop->parent_individuals_[individual_index]);\n\t\t\t\n\t\t\tmemcpy(&individual.sex_, p, sizeof(individual.sex_));\n\t\t\tp += sizeof(individual.sex_);\n\t\t\t\n\t\t\tif (pedigree_output_count)\n\t\t\t{\n\t\t\t\tif (PedigreesEnabled())\n\t\t\t\t{\n\t\t\t\t\tslim_pedigreeid_t pedigree_id;\n\t\t\t\t\t\n\t\t\t\t\tmemcpy(&pedigree_id, p, sizeof(pedigree_id));\n\t\t\t\t\t\n\t\t\t\t\tindividual.SetPedigreeID(pedigree_id);\n\t\t\t\t\tgSLiM_next_pedigree_id = std::max(gSLiM_next_pedigree_id, pedigree_id + 1);\n\t\t\t\t\t\n\t\t\t\t\t// we need to fix the haplosome ids for all of the individual's haplosomes\n\t\t\t\t\tint haplosome_index = 0;\n\t\t\t\t\t\n\t\t\t\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\t\t\t{\n\t\t\t\t\t\tindividual.haplosomes_[haplosome_index++]->SetHaplosomeID(pedigree_id * 2);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (chromosome->IntrinsicPloidy() == 2)\n\t\t\t\t\t\t\tindividual.haplosomes_[haplosome_index++]->SetHaplosomeID(pedigree_id * 2 + 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tp += sizeof(slim_pedigreeid_t);\n\t\t\t}\n\t\t\t\n\t\t\tif (spatial_output_count)\n\t\t\t{\n\t\t\t\tif (spatial_output_count >= 1)\n\t\t\t\t{\n\t\t\t\t\tmemcpy(&individual.spatial_x_, p, sizeof(individual.spatial_x_));\n\t\t\t\t\tp += sizeof(double);\n\t\t\t\t}\n\t\t\t\tif (spatial_output_count >= 2)\n\t\t\t\t{\n\t\t\t\t\tmemcpy(&individual.spatial_y_, p, sizeof(individual.spatial_y_));\n\t\t\t\t\tp += sizeof(double);\n\t\t\t\t}\n\t\t\t\tif (spatial_output_count >= 3)\n\t\t\t\t{\n\t\t\t\t\tmemcpy(&individual.spatial_z_, p, sizeof(individual.spatial_z_));\n\t\t\t\t\tp += sizeof(double);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (age_output_count)\n\t\t\t{\n\t\t\t\tmemcpy(&individual.age_, p, sizeof(individual.age_));\n\t\t\t\tp += sizeof(slim_age_t);\n\t\t\t}\n\t\t\t\n\t\t\tif (has_object_tags)\n\t\t\t{\n\t\t\t\tmemcpy(&individual.tag_value_, p, sizeof(individual.tag_value_));\n\t\t\t\tp += sizeof(tag_value_);\n\t\t\t\t\n\t\t\t\tmemcpy(&individual.tagF_value_, p, sizeof(individual.tagF_value_));\n\t\t\t\tp += sizeof(individual.tagF_value_);\n\t\t\t\t\n\t\t\t\t{\n\t\t\t\t\tchar tagL0_value;\n\t\t\t\t\tmemcpy(&tagL0_value, p, sizeof(tagL0_value));\n\t\t\t\t\tp += sizeof(char);\n\t\t\t\t\t\n\t\t\t\t\tif (tagL0_value == 0) { individual.tagL0_set_ = 1; individual.tagL0_value_ = 0; }\n\t\t\t\t\telse if (tagL0_value == 1) { individual.tagL0_set_ = 1; individual.tagL0_value_ = 1; }\n\t\t\t\t\telse { individual.tagL0_set_ = 0; }\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tchar tagL1_value;\n\t\t\t\t\tmemcpy(&tagL1_value, p, sizeof(tagL1_value));\n\t\t\t\t\tp += sizeof(char);\n\t\t\t\t\t\n\t\t\t\t\tif (tagL1_value == 0) { individual.tagL1_set_ = 1; individual.tagL1_value_ = 0; }\n\t\t\t\t\telse if (tagL1_value == 1) { individual.tagL1_set_ = 1; individual.tagL1_value_ = 1; }\n\t\t\t\t\telse { individual.tagL1_set_ = 0; }\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tchar tagL2_value;\n\t\t\t\t\tmemcpy(&tagL2_value, p, sizeof(tagL2_value));\n\t\t\t\t\tp += sizeof(char);\n\t\t\t\t\t\n\t\t\t\t\tif (tagL2_value == 0) { individual.tagL2_set_ = 1; individual.tagL2_value_ = 0; }\n\t\t\t\t\telse if (tagL2_value == 1) { individual.tagL2_set_ = 1; individual.tagL2_value_ = 1; }\n\t\t\t\t\telse { individual.tagL2_set_ = 0; }\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tchar tagL3_value;\n\t\t\t\t\tmemcpy(&tagL3_value, p, sizeof(tagL3_value));\n\t\t\t\t\tp += sizeof(char);\n\t\t\t\t\t\n\t\t\t\t\tif (tagL3_value == 0) { individual.tagL3_set_ = 1; individual.tagL3_value_ = 0; }\n\t\t\t\t\telse if (tagL3_value == 1) { individual.tagL3_set_ = 1; individual.tagL3_value_ = 1; }\n\t\t\t\t\telse { individual.tagL3_set_ = 0; }\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tchar tagL4_value;\n\t\t\t\t\tmemcpy(&tagL4_value, p, sizeof(tagL4_value));\n\t\t\t\t\tp += sizeof(char);\n\t\t\t\t\t\n\t\t\t\t\tif (tagL4_value == 0) { individual.tagL4_set_ = 1; individual.tagL4_value_ = 0; }\n\t\t\t\t\telse if (tagL4_value == 1) { individual.tagL4_set_ = 1; individual.tagL4_value_ = 1; }\n\t\t\t\t\telse { individual.tagL4_set_ = 0; }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (p + sizeof(section_end_tag) > buf_end)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after individuals.\" << EidosTerminate();\n\telse\n\t{\n\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\tp += sizeof(section_end_tag);\n\t\t\n\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after individuals.\" << EidosTerminate();\n\t}\n\t\n\t// Loop over the chromosomes.  Each chromosome gets a section end tag.  We begin with a chromosome count.\n\tint32_t chromosome_count;\n\t\n\tif (p + sizeof(chromosome_count) > buf_end)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF at chromosome count.\" << EidosTerminate();\n\telse\n\t{\n\t\tmemcpy(&chromosome_count, p, sizeof(chromosome_count));\n\t\tp += sizeof(chromosome_count);\n\t\t\n\t\tif (chromosome_count != (int)chromosomes.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): chromosome count does not match the model state.\" << EidosTerminate();\n\t}\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\t// Read and validate information about the chromosome\n\t\tint32_t raw_chromosome_index;\n\t\tint32_t raw_chromosome_type;\n\t\tint64_t chromosome_id;\n\t\tint64_t chromosome_lastpos;\n\t\tint32_t mutation_map_size;\n\t\t\n\t\tif (p + sizeof(raw_chromosome_index) + sizeof(raw_chromosome_type) + sizeof(chromosome_id) + sizeof(chromosome_lastpos) + (has_object_tags ? sizeof(slim_usertag_t) : 0) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF in chromosome information.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&raw_chromosome_index, p, sizeof(raw_chromosome_index));\n\t\tp += sizeof(raw_chromosome_index);\n\n\t\tif (raw_chromosome_index != chromosome->Index())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): chromosome index mismatch.\" << EidosTerminate();\n\t\t\n\t\tslim_chromosome_index_t chromosome_index = (slim_chromosome_index_t)raw_chromosome_index;\n\t\t\n\t\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\t\n\t\tmemcpy(&raw_chromosome_type, p, sizeof(raw_chromosome_type));\n\t\tp += sizeof(raw_chromosome_type);\n\t\t\n\t\tChromosomeType chromosome_type = (ChromosomeType)raw_chromosome_type;\n\t\t\n\t\tif (chromosome_type != chromosome->Type())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): chromosome type mismatch.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&chromosome_id, p, sizeof(chromosome_id));\n\t\tp += sizeof(chromosome_id);\n\t\t\n\t\tif (chromosome_id != chromosome->ID())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): chromosome id mismatch.\" << EidosTerminate();\n\t\t\n\t\tmemcpy(&chromosome_lastpos, p, sizeof(chromosome_lastpos));\n\t\tp += sizeof(chromosome_lastpos);\n\t\t\n\t\tif (chromosome_lastpos != chromosome->last_position_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): chromosome last position mismatch.\" << EidosTerminate();\n\t\t\n\t\tif (has_object_tags)\n\t\t{\n\t\t\tmemcpy(&chromosome->tag_value_, p, sizeof(chromosome->tag_value_));\n\t\t\tp += sizeof(chromosome->tag_value_);\n\t\t}\n\t\t\n\t\t// Read in the size of the mutation map, so we can allocate a vector rather than utilizing std::map\n\t\tif (p + sizeof(mutation_map_size) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF at mutation map size.\" << EidosTerminate();\n\t\telse\n\t\t{\n\t\t\tmemcpy(&mutation_map_size, p, sizeof(mutation_map_size));\n\t\t\tp += sizeof(mutation_map_size);\n\t\t}\n\t\t\n\t\t// Mutations section\n\t\tstd::unique_ptr<MutationIndex[]> raii_mutations(new MutationIndex[mutation_map_size]);\n\t\tMutationIndex *mutations = raii_mutations.get();\n\t\t\n\t\tif (!mutations)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): could not allocate mutations buffer.\" << EidosTerminate();\n\t\t\n\t\twhile (true)\n\t\t{\n\t\t\tint32_t mutation_start_tag;\n\t\t\tslim_polymorphismid_t polymorphism_id;\n\t\t\tslim_mutationid_t mutation_id;\n\t\t\tslim_objectid_t mutation_type_id;\n\t\t\tslim_position_t position;\n\t\t\tslim_selcoeff_t selection_coeff;\n\t\t\tslim_selcoeff_t dominance_coeff;\n\t\t\tslim_objectid_t subpop_index;\n\t\t\tslim_tick_t tick;\n\t\t\tslim_refcount_t prevalence;\n\t\t\tint8_t nucleotide = -1;\n\t\t\t\n\t\t\t// If there isn't enough buffer left to read a full mutation record, we assume we are done with this section\n\t\t\tint record_size = sizeof(mutation_start_tag) + sizeof(polymorphism_id) + sizeof(mutation_id) + sizeof(mutation_type_id) + sizeof(position) + sizeof(selection_coeff) + sizeof(dominance_coeff) + sizeof(subpop_index) + sizeof(tick) + sizeof(prevalence);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t\trecord_size += sizeof(nucleotide);\n\t\t\tif (has_object_tags)\n\t\t\t\trecord_size += sizeof(slim_usertag_t);\n\t\t\t\n\t\t\tif (p + record_size > buf_end)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// If the first int32_t is not a mutation start tag, then we are done with this section\n\t\t\tmemcpy(&mutation_start_tag, p, sizeof(mutation_start_tag));\n\t\t\tif (mutation_start_tag != (int32_t)0xFFFF0002)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Otherwise, we have a mutation record; read in the rest of it\n\t\t\tp += sizeof(mutation_start_tag);\n\t\t\t\n\t\t\tmemcpy(&polymorphism_id, p, sizeof(polymorphism_id));\n\t\t\tp += sizeof(polymorphism_id);\n\t\t\t\n\t\t\tmemcpy(&mutation_id, p, sizeof(mutation_id));\n\t\t\tp += sizeof(mutation_id);\n\t\t\t\n\t\t\tmemcpy(&mutation_type_id, p, sizeof(mutation_type_id));\n\t\t\tp += sizeof(mutation_type_id);\n\t\t\t\n\t\t\tmemcpy(&position, p, sizeof(position));\n\t\t\tp += sizeof(position);\n\t\t\t\n\t\t\tmemcpy(&selection_coeff, p, sizeof(selection_coeff));\n\t\t\tp += sizeof(selection_coeff);\n\t\t\t\n\t\t\tmemcpy(&dominance_coeff, p, sizeof(dominance_coeff));\n\t\t\tp += sizeof(dominance_coeff);\n\t\t\t\n\t\t\tmemcpy(&subpop_index, p, sizeof(subpop_index));\n\t\t\tp += sizeof(subpop_index);\n\t\t\t\n\t\t\tmemcpy(&tick, p, sizeof(tick));\n\t\t\tp += sizeof(tick);\n\t\t\t\n\t\t\tmemcpy(&prevalence, p, sizeof(prevalence));\n\t\t\t(void)prevalence;\t// we don't use the frequency when reading the pop data back in; let the static analyzer know that's OK\n\t\t\tp += sizeof(prevalence);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t{\n\t\t\t\tmemcpy(&nucleotide, p, sizeof(nucleotide));\n\t\t\t\tp += sizeof(nucleotide);\n\t\t\t}\n\t\t\t\n\t\t\t// look up the mutation type from its index\n\t\t\tMutationType *mutation_type_ptr = MutationTypeWithID(mutation_type_id);\n\t\t\t\n\t\t\tif (!mutation_type_ptr) \n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" has not been defined for this species.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (mutation_type_ptr->dominance_coeff_ != dominance_coeff)\t\t// no tolerance, unlike _InitializePopulationFromTextFile(); should match exactly here since we used binary\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" has dominance coefficient \" << mutation_type_ptr->dominance_coeff_ << \" that does not match the population file dominance coefficient of \" << dominance_coeff << \".\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 9/22/2021: Note that mutation_type_ptr->hemizygous_dominance_coeff_ is not saved, or checked here; too edge to be bothered...\n\t\t\t\n\t\t\tif ((nucleotide == -1) && mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" is nucleotide-based, but a nucleotide value for a mutation of this type was not supplied.\" << EidosTerminate();\n\t\t\tif ((nucleotide != -1) && !mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" is not nucleotide-based, but a nucleotide value for a mutation of this type was supplied.\" << EidosTerminate();\n\t\t\t\n\t\t\t// construct the new mutation; NOTE THAT THE STACKING POLICY IS NOT CHECKED HERE, AS THIS IS NOT CONSIDERED THE ADDITION OF A MUTATION!\n\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\t\n\t\t\tMutation *new_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_id, mutation_type_ptr, chromosome_index, position, selection_coeff, subpop_index, tick, nucleotide);\n\t\t\t\n\t\t\t// read the tag value, if present\n\t\t\tif (has_object_tags)\n\t\t\t{\n\t\t\t\tmemcpy(&new_mut->tag_value_, p, sizeof(slim_usertag_t));\n\t\t\t\tp += sizeof(slim_usertag_t);\n\t\t\t}\n\t\t\t\n\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\tmutations[polymorphism_id] = new_mut_index;\n\t\t\tpopulation_.MutationRegistryAdd(new_mut);\n\t\t\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t\t\tif (population_.keeping_muttype_registries_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): (internal error) separate muttype registries set up during pop load.\" << EidosTerminate();\n#endif\n\t\t\t\n\t\t\t// all mutations seen here will be added to the simulation somewhere, so check and set pure_neutral_ and all_pure_neutral_DFE_\n\t\t\tif (selection_coeff != 0.0)\n\t\t\t{\n\t\t\t\tpure_neutral_ = false;\n\t\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t\t}\n\t\t}\n\t\t\n\t\tpopulation_.InvalidateMutationReferencesCache();\n\t\t\n\t\tif (p + sizeof(section_end_tag) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after mutations.\" << EidosTerminate();\n\t\telse\n\t\t{\n\t\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\t\tp += sizeof(section_end_tag);\n\t\t\t\n\t\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after mutations.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// Haplosomes section\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tbool use_16_bit = (mutation_map_size <= UINT16_MAX - 1);\t// 0xFFFF is reserved as the start of our various tags\n\t\tstd::unique_ptr<MutationIndex[]> raii_haplosomebuf(new MutationIndex[mutation_map_size]);\t// allowing us to use emplace_back_bulk() for speed\n\t\tMutationIndex *haplosomebuf = raii_haplosomebuf.get();\n#ifndef _OPENMP\n\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome &haplosome = *haplosomes[haplosome_index];\n\t\t\t\t\tslim_objectid_t subpop_id;\n\t\t\t\t\tint32_t total_mutations;\n\t\t\t\t\t\n\t\t\t\t\t// If there isn't enough buffer left to read a full haplosome record, we have an error\n\t\t\t\t\tif (p + sizeof(subpop_id) + sizeof(total_mutations) + (has_object_tags ? sizeof(slim_usertag_t) : 0) > buf_end)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF in haplosome header.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tmemcpy(&subpop_id, p, sizeof(subpop_id));\n\t\t\t\t\tp += sizeof(subpop_id);\n\t\t\t\t\t\n\t\t\t\t\tif (subpop_id != subpop_pair.first + 1)\t\t// + 1 to avoid colliding with section_end_tag\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): subpop id mismatch.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (has_object_tags)\n\t\t\t\t\t{\n\t\t\t\t\t\tmemcpy(&haplosome.tag_value_, p, sizeof(slim_usertag_t));\n\t\t\t\t\t\tp += sizeof(slim_usertag_t);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tmemcpy(&total_mutations, p, sizeof(total_mutations));\n\t\t\t\t\tp += sizeof(total_mutations);\n\t\t\t\t\t\n\t\t\t\t\t// Check the null haplosome state\n\t\t\t\t\t// BCH 2/5/2025: We instantiate null haplosomes only where expect them to be, based upon\n\t\t\t\t\t// the chromosome type.  For chromosome types 'A' and 'H', null haplosomes can occur anywhere;\n\t\t\t\t\t// when that happens, we transform the instantiated haplosome to a null haplosome if necessary.\n\t\t\t\t\t// AddSubpopulation() created the haplosomes above, before we knew which would be null.\n\t\t\t\t\tif (total_mutations == (int32_t)0xFFFF1000)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!haplosome.IsNull())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((model_type_ == SLiMModelType::kModelTypeNonWF) && ((chromosome_type == ChromosomeType::kA_DiploidAutosome) || (chromosome_type == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thaplosome.MakeNull();\n\t\t\t\t\t\t\t\tsubpop->has_null_haplosomes_ = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): haplosome is specified as null, but the instantiated haplosome is non-null.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (haplosome.IsNull())\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): haplosome is specified as non-null, but the instantiated haplosome is null.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Read in the mutation list\n\t\t\t\t\t\tint32_t mutcount = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (use_16_bit)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// reading 16-bit mutation tags\n\t\t\t\t\t\t\tuint16_t mutation_id;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (p + sizeof(mutation_id) * total_mutations > buf_end)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF while reading haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (; mutcount < total_mutations; ++mutcount)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmemcpy(&mutation_id, p, sizeof(mutation_id));\n\t\t\t\t\t\t\t\tp += sizeof(mutation_id);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Add mutation to haplosome\n\t\t\t\t\t\t\t\tif (/*(mutation_id < 0) ||*/ (mutation_id >= mutation_map_size)) \n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation \" << mutation_id << \" has not been defined.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thaplosomebuf[mutcount] = mutations[mutation_id];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// reading 32-bit mutation tags\n\t\t\t\t\t\t\tint32_t mutation_id;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (p + sizeof(mutation_id) * total_mutations > buf_end)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF while reading haplosome.\" << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (; mutcount < total_mutations; ++mutcount)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmemcpy(&mutation_id, p, sizeof(mutation_id));\n\t\t\t\t\t\t\t\tp += sizeof(mutation_id);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// Add mutation to haplosome\n\t\t\t\t\t\t\t\tif ((mutation_id < 0) || (mutation_id >= mutation_map_size)) \n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation \" << mutation_id << \" has not been defined.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thaplosomebuf[mutcount] = mutations[mutation_id];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tslim_position_t mutrun_length_ = haplosome.mutrun_length_;\n\t\t\t\t\t\tslim_mutrun_index_t current_mutrun_index = -1;\n\t\t\t\t\t\tMutationRun *current_mutrun = nullptr;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mutcount; ++mut_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutationIndex mutation = haplosomebuf[mut_index];\n\t\t\t\t\t\t\tslim_mutrun_index_t mutrun_index = (slim_mutrun_index_t)((mut_block_ptr + mutation)->position_ / mutrun_length_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mutrun_index != current_mutrun_index)\n\t\t\t\t\t\t\t{\n#ifdef _OPENMP\n\t\t\t\t\t\t\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\t\t\t\t\t\t\tMutationRunContext &mutrun_context = chromosome.ChromosomeMutationRunContextForMutationRunIndex(mutrun_index);\n#endif\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcurrent_mutrun_index = mutrun_index;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// We use WillModifyRun_UNSHARED() because we know that these runs are unshared (unless empty);\n\t\t\t\t\t\t\t\t// we created them empty, nobody has modified them but us, and we process each haplosome separately.\n\t\t\t\t\t\t\t\t// However, using WillModifyRun() would generally be fine since we hit this call only once\n\t\t\t\t\t\t\t\t// per mutrun per haplosome anyway, as long as the mutations are sorted by position.\n\t\t\t\t\t\t\t\tcurrent_mutrun = haplosome.WillModifyRun_UNSHARED(current_mutrun_index, mutrun_context);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcurrent_mutrun->emplace_back(mutation);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (p + sizeof(section_end_tag) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after haplosomes.\" << EidosTerminate();\n\t\telse\n\t\t{\n\t\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\t\tp += sizeof(section_end_tag);\n\t\t\t\n\t\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after haplosomes.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// Ancestral sequence section, for nucleotide-based models\n\t\t// The ancestral sequence can be suppressed at save time, to decrease file size etc.  If it is missing,\n\t\t// we do not consider that an error at present.  This is a little weird – it's more useful to suppress\n\t\t// the ancestral sequence when writing text – but maybe the user really doesn't want it.  So do nothing.\n\t\tif (has_ancestral_nucs)\n\t\t{\n\t\t\tif (p + sizeof(int64_t) > buf_end)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): ancestral sequence was expected but is missing.\" << EidosTerminate();\n\t\t\t\n\t\t\tchromosome->AncestralSequence()->ReadCompressedNucleotides(&p, buf_end);\n\t\t\t\n\t\t\tif (p + sizeof(section_end_tag) > buf_end)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after ancestral sequence.\" << EidosTerminate();\n\t\t\telse\n\t\t\t{\n\t\t\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\t\t\tp += sizeof(section_end_tag);\n\t\t\t\t\n\t\t\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after ancestral sequence.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (has_substitutions)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tint32_t substitution_start_tag;\n\t\t\tslim_mutationid_t mutation_id;\n\t\t\tslim_objectid_t mutation_type_id;\n\t\t\tslim_position_t position;\n\t\t\tslim_selcoeff_t selection_coeff;\n\t\t\tslim_selcoeff_t dominance_coeff;\n\t\t\tslim_objectid_t subpop_index;\n\t\t\tslim_tick_t origin_tick;\n\t\t\tslim_tick_t fixation_tick;\n\t\t\tslim_chromosome_index_t chromosome_index;\n\t\t\tint8_t nucleotide = -1;\n\t\t\t\n\t\t\t// If there isn't enough buffer left to read a full mutation record, we assume we are done with this section\n\t\t\tint record_size = sizeof(substitution_start_tag) + sizeof(mutation_id) + sizeof(mutation_type_id) + sizeof(position) + sizeof(selection_coeff) + sizeof(dominance_coeff) + sizeof(subpop_index) + sizeof(origin_tick) + sizeof(fixation_tick) + sizeof(chromosome_index);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t\trecord_size += sizeof(nucleotide);\n\t\t\tif (has_object_tags)\n\t\t\t\trecord_size += sizeof(slim_usertag_t);\n\t\t\t\n\t\t\tif (p + record_size > buf_end)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// If the first int32_t is not a mutation start tag, then we are done with this section\n\t\t\tmemcpy(&substitution_start_tag, p, sizeof(substitution_start_tag));\n\t\t\tif (substitution_start_tag != (int32_t)0xFFFF0003)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Otherwise, we have a mutation record; read in the rest of it\n\t\t\tp += sizeof(substitution_start_tag);\n\t\t\t\n\t\t\tmemcpy(&mutation_id, p, sizeof(mutation_id));\n\t\t\tp += sizeof(mutation_id);\n\t\t\t\n\t\t\tmemcpy(&mutation_type_id, p, sizeof(mutation_type_id));\n\t\t\tp += sizeof(mutation_type_id);\n\t\t\t\n\t\t\tmemcpy(&position, p, sizeof(position));\n\t\t\tp += sizeof(position);\n\t\t\t\n\t\t\tmemcpy(&selection_coeff, p, sizeof(selection_coeff));\n\t\t\tp += sizeof(selection_coeff);\n\t\t\t\n\t\t\tmemcpy(&dominance_coeff, p, sizeof(dominance_coeff));\n\t\t\tp += sizeof(dominance_coeff);\n\t\t\t\n\t\t\tmemcpy(&subpop_index, p, sizeof(subpop_index));\n\t\t\tp += sizeof(subpop_index);\n\t\t\t\n\t\t\tmemcpy(&origin_tick, p, sizeof(origin_tick));\n\t\t\tp += sizeof(origin_tick);\n\t\t\t\n\t\t\tmemcpy(&fixation_tick, p, sizeof(fixation_tick));\n\t\t\tp += sizeof(fixation_tick);\n\t\t\t\n\t\t\tmemcpy(&chromosome_index, p, sizeof(chromosome_index));\n\t\t\t(void)chromosome_index;\n\t\t\tp += sizeof(chromosome_index);\n\t\t\t\n\t\t\tif (has_nucleotides)\n\t\t\t{\n\t\t\t\tmemcpy(&nucleotide, p, sizeof(nucleotide));\n\t\t\t\tp += sizeof(nucleotide);\n\t\t\t}\n\t\t\t\n\t\t\t// note the tag is read below, after the substitution is created\n\t\t\t\n\t\t\t// look up the mutation type from its index\n\t\t\tMutationType *mutation_type_ptr = MutationTypeWithID(mutation_type_id);\n\t\t\t\n\t\t\tif (!mutation_type_ptr) \n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" has not been defined for this species.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (mutation_type_ptr->dominance_coeff_ != dominance_coeff)\t\t// no tolerance, unlike _InitializePopulationFromTextFile(); should match exactly here since we used binary\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" has dominance coefficient \" << mutation_type_ptr->dominance_coeff_ << \" that does not match the population file dominance coefficient of \" << dominance_coeff << \".\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 9/22/2021: Note that mutation_type_ptr->hemizygous_dominance_coeff_ is not saved, or checked here; too edge to be bothered...\n\t\t\t\n\t\t\tif ((nucleotide == -1) && mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" is nucleotide-based, but a nucleotide value for a mutation of this type was not supplied.\" << EidosTerminate();\n\t\t\tif ((nucleotide != -1) && !mutation_type_ptr->nucleotide_based_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): mutation type m\" << mutation_type_id << \" is not nucleotide-based, but a nucleotide value for a mutation of this type was supplied.\" << EidosTerminate();\n\t\t\t\n\t\t\t// construct the new substitution\n\t\t\tSubstitution *new_substitution = new Substitution(mutation_id, mutation_type_ptr, chromosome_index, position, selection_coeff, subpop_index, origin_tick, fixation_tick, nucleotide);\n\t\t\t\n\t\t\t// read its tag, if requested\n\t\t\tif (has_object_tags)\n\t\t\t{\n\t\t\t\tmemcpy(&new_substitution->tag_value_, p, sizeof(slim_usertag_t));\n\t\t\t\tp += sizeof(slim_usertag_t);\n\t\t\t}\n\t\t\t\n\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t// When doing tree recording, we additionally keep all fixed mutations (their ids) in a multimap indexed by their position\n\t\t\t// This allows us to find all the fixed mutations at a given position quickly and easily, for calculating derived states\n\t\t\tif (RecordingTreeSequence())\n\t\t\t\tpopulation_.treeseq_substitutions_map_.emplace(new_substitution->position_, new_substitution);\n\t\t\t\n\t\t\tpopulation_.substitutions_.emplace_back(new_substitution);\n\t\t}\n\t\t\n\t\tif (p + sizeof(section_end_tag) > buf_end)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): unexpected EOF after mutations.\" << EidosTerminate();\n\t\telse\n\t\t{\n\t\t\tmemcpy(&section_end_tag, p, sizeof(section_end_tag));\n\t\t\tp += sizeof(section_end_tag);\n\t\t\t\n\t\t\tif (section_end_tag != (int32_t)0xFFFF0000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromBinaryFile): missing section end after mutations.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// It's a little unclear how we ought to clean up after ourselves, and this is a continuing source of bugs.  We could be loading\n\t// a new population in an early() event, in a late() event, or in between cycles in SLiMgui, e.g. in the Eidos console.\n\t// The safest avenue seems to be to just do all the bookkeeping we can think of: tally frequencies, calculate fitnesses, and\n\t// survey the population for SLiMgui.  This will lead to some of these actions being done at an unusual time in the cycle,\n\t// though, and will cause some things to be done unnecessarily (because they are not normally up-to-date at the current\n\t// cycle stage anyway) or done twice (which could be particularly problematic for mutationEffect() callbacks).  Nevertheless, this seems\n\t// like the best policy, at least until shown otherwise...  BCH 11 June 2016\n\t\n\t// BCH 5 April 2017: Well, it has been shown otherwise.  Now that interactions have been added, mutationEffect() callbacks often depend on\n\t// them, which means the interactions need to be evaluated, which means we can't evaluate fitness values yet; we need to give the\n\t// user's script a chance to evaluate the interactions.  This was always a problem, really; mutationEffect() callbacks might have needed\n\t// some external state to be set up that would be on the population state.  But now it is a glaring problem, and forces us to revise\n\t// our policy.  For backward compatibility, we will keep the old behavior if reading a file that is version 2 or earlier; a bit\n\t// weird, but probably nobody will ever even notice...\n\t\n\t// Re-tally mutation references so we have accurate frequency counts for our new mutations\n\tpopulation_.UniqueMutationRuns();\n\tpopulation_.InvalidateMutationReferencesCache();\t// force a retally\n\tpopulation_.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t\n\tif (file_version <= 2)\n\t{\n\t\t// Now that we have the info on everybody, update fitnesses so that we're ready to run the next cycle\n\t\t// used to be generation + 1; removing that 18 Feb 2016 BCH\n\t\t\n\t\tnonneutral_change_counter_++;\t\t\t// trigger unconditional nonneutral mutation caching inside UpdateFitness()\n\t\tlast_nonneutral_regime_ = 3;\t\t\t// this means \"unpredictable callbacks\", will trigger a recache next cycle\n\t\t\n\t\tfor (auto muttype_iter : mutation_types_)\n\t\t\t(muttype_iter.second)->subject_to_mutationEffect_callback_ = true;\t// we're not doing RecalculateFitness()'s work, so play it safe\n\t\t\n\t\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\t\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\t// used for both mutationEffect() and fitnessEffect() for simplicity\n\t\tcommunity_.executing_species_ = this;\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tstd::vector<SLiMEidosBlock*> mutationEffect_callbacks = CallbackBlocksMatching(community_.Tick(), SLiMEidosBlockType::SLiMEidosMutationEffectCallback, -1, -1, subpop_id, -1);\n\t\t\tstd::vector<SLiMEidosBlock*> fitnessEffect_callbacks = CallbackBlocksMatching(community_.Tick(), SLiMEidosBlockType::SLiMEidosFitnessEffectCallback, -1, -1, subpop_id, -1);\n\t\t\t\n\t\t\tsubpop->UpdateFitness(mutationEffect_callbacks, fitnessEffect_callbacks);\n\t\t}\n\t\t\n\t\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\tcommunity_.executing_species_ = nullptr;\n\t\t\n#ifdef SLIMGUI\n\t\t// Let SLiMgui survey the population for mean fitness and such, if it is our target\n\t\tpopulation_.SurveyPopulation();\n#endif\n\t}\n\t\n\treturn file_tick;\n}\n#else\n// the static analyzer has a lot of trouble understanding this method\nslim_tick_t Species::_InitializePopulationFromBinaryFile(const char *p_file, EidosInterpreter *p_interpreter)\n{\n\treturn 0;\n}\n#endif\n\nvoid Species::DeleteAllMutationRuns(void)\n{\n\t// This traverses the free and in-use MutationRun pools and frees them all\n\t// Note that the allocation pools themselves, and the MutationRunContexts, remain intact\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tfor (int threadnum = 0; threadnum < chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\tMutationRun::DeleteMutationRunContextContents(mutrun_context);\n\t\t}\n\t}\n}\n\nSubpopulation *Species::SubpopulationWithName(const std::string &p_subpop_name) {\n\tfor (auto subpop_iter : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_iter.second;\n\t\tif (subpop->name_ == p_subpop_name)\n\t\t\treturn subpop;\n\t}\n\treturn nullptr;\n}\n\n\n//\n// Running cycles\n//\n#pragma mark -\n#pragma mark Running cycles\n#pragma mark -\n\nstd::vector<SLiMEidosBlock*> Species::CallbackBlocksMatching(slim_tick_t p_tick, SLiMEidosBlockType p_event_type, slim_objectid_t p_mutation_type_id, slim_objectid_t p_interaction_type_id, slim_objectid_t p_subpopulation_id, int64_t p_chromosome_id)\n{\n\t// Callbacks are species-specific; this method calls up to the community, which manages script blocks,\n\t// but does a species-specific search.\n\treturn community_.ScriptBlocksMatching(p_tick, p_event_type, p_mutation_type_id, p_interaction_type_id, p_subpopulation_id, p_chromosome_id, this);\n}\n\nvoid Species::RunInitializeCallbacks(void)\n{\n\t// zero out the initialization check counts\n\tnum_species_inits_ = 0;\n\tnum_slimoptions_inits_ = 0;\n\tnum_mutation_type_inits_ = 0;\n\tnum_ge_type_inits_ = 0;\n\tnum_sex_inits_ = 0;\n\tnum_treeseq_inits_ = 0;\n\tnum_chromosome_inits_ = 0;\n\t\n\tnum_mutrate_inits_ = 0;\n\tnum_recrate_inits_ = 0;\n\tnum_genomic_element_inits_ = 0;\n\tnum_gene_conv_inits_ = 0;\n\tnum_ancseq_inits_ = 0;\n\tnum_hotmap_inits_ = 0;\n\t\n\thas_implicit_chromosome_ = false;\n\t\n\t// execute initialize() callbacks, which should always have a tick of 0 set\n\tstd::vector<SLiMEidosBlock*> init_blocks = CallbackBlocksMatching(0, SLiMEidosBlockType::SLiMEidosInitializeCallback, -1, -1, -1, -1);\n\t\n\tfor (auto script_block : init_blocks)\n\t\tcommunity_.ExecuteEidosEvent(script_block);\n\t\n\t//\n\t// check for complete initialization\n\t//\n\t\n\tif ((num_mutrate_inits_ == 0) && (num_mutation_type_inits_ == 0) && (num_ge_type_inits_ == 0) &&\n\t\t(num_genomic_element_inits_ == 0) && (num_recrate_inits_ == 0) && (num_gene_conv_inits_ == 0) &&\n\t\t(num_chromosome_inits_ == 0) && (!has_implicit_chromosome_))\n\t{\n\t\t// BCH 26 April 2022: In SLiM 4, as a special case, we allow *all* of the genetic structure boilerplate to be omitted.\n\t\t// This gives a species with no genetics, no mutations, no recombination, no declared chromosomes, and so forth.\n\t\t// In that case, here we set up the default empty genetic structure and pretend to have been initialized, so we have\n\t\t// little bits of several initialization functions excerpted here.  Note that the state achieved by this code path\n\t\t// cannot be achieved any other way; in particular, we have no genomic element types, no mutation types, and no\n\t\t// genomic elements; normally that is illegal, but we deliberately carve out this special case.\n\t\t// BCH 22 May 2022: No-genetics species cannot use tree-sequence recording or be nucleotide-based, for simplicity.\n\t\t// They always use null haplosomes, so any attempt to access their genetics is illegal.  They have no mutruns.\n\t\t// BCH 18 September 2024: They also cannot have any declared chromosomes, or do anything that would cause an\n\t\t// implicit chromosome to be defined.\n\t\t// BCH 10 October 2024: No-genetics models now have no Chromosome object at all\n\t\tif (recording_tree_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): no-genetics species cannot use tree-sequence recording; either add genetic initialization calls, or disable tree-sequence recording.\" << EidosTerminate();\n\t\tif (nucleotide_based_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): no-genetics species cannot be nucleotide-based; either add genetic initialization calls, or turn off nucleotides.\" << EidosTerminate();\n\t\t\n\t\thas_genetics_ = false;\n\t}\n\n\tif (has_genetics_ && (!has_implicit_chromosome_) && (num_chromosome_inits_ == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): (internal error) a chromosome has not been set up properly.\" << EidosTerminate();\n\tif (!has_genetics_ && (has_implicit_chromosome_ || (num_chromosome_inits_ > 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): (internal error) a chromosome was set up in a no-genetics model.\" << EidosTerminate();\n\t\n\t// From the initialization that has occurred, there should now be a currently initializing chromosome,\n\t// whether implicitly or explicitly defined.  We now close out its definition and check it for\n\t// correctness.  If this is a multichromosome model, this has already been done for the previous ones.\n\tif (has_genetics_)\n\t\tEndCurrentChromosome(/* starting_new_chromosome */ false);\n\t\n\t// set a default avatar string if one was not provided; these will be A, B, etc.\n\tif (avatar_.length() == 0)\n\t\tavatar_ = std::string(1, (char)('A' + species_id_));\n\t\n\tcommunity_.scripts_changed_ = true;\t\t// avatars changed, either here or with initializeSpecies(), so redisplay the script block table\n\t\n\t// In single-species models, we are responsible for finalizing the model type decision at the end of our initialization\n\t// In multispecies models, the Community will have already made this decision and propagated it down to us.\n\tif (!community_.is_explicit_species_)\n\t{\n\t\t// We default to WF, but here we explicitly declare our model type so everybody knows the default was not changed\n\t\t// This cements the choice of WF if the first species initialized does not declare a model type explicitly\n\t\tif (!community_.model_type_set_)\n\t\t\tcommunity_.SetModelType(SLiMModelType::kModelTypeWF);\n\t}\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> script_blocks = community_.AllScriptBlocksForSpecies(this);\n\t\t\n\t\tfor (auto script_block : script_blocks)\n\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosMateChoiceCallback)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): mateChoice() callbacks may not be defined in nonWF models.\" << EidosTerminate(script_block->identifier_token_);\n\t}\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> script_blocks = community_.AllScriptBlocksForSpecies(this);\n\t\t\n\t\tfor (auto script_block : script_blocks)\n\t\t{\n\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): reproduction() callbacks may not be defined in WF models.\" << EidosTerminate(script_block->identifier_token_);\n\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosSurvivalCallback)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): survival() callbacks may not be defined in WF models.\" << EidosTerminate(script_block->identifier_token_);\n\t\t}\n\t}\n\tif (!sex_enabled_)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> script_blocks = community_.AllScriptBlocksForSpecies(this);\n\t\t\n\t\tfor (auto script_block : script_blocks)\n\t\t\tif ((script_block->type_ == SLiMEidosBlockType::SLiMEidosReproductionCallback) && (script_block->sex_specificity_ != IndividualSex::kUnspecified))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): reproduction() callbacks may not be limited by sex in non-sexual models.\" << EidosTerminate(script_block->identifier_token_);\n\t}\n\t{\n\t\tstd::vector<SLiMEidosBlock*> script_blocks = community_.AllScriptBlocksForSpecies(this);\n\t\t\n\t\tfor (auto script_block : script_blocks)\n\t\t{\n\t\t\tif (script_block->type_ == SLiMEidosBlockType::SLiMEidosRecombinationCallback)\n\t\t\t{\n\t\t\t\tif (has_implicit_chromosome_ && ((script_block->chromosome_id_ != -1) || (script_block->chromosome_symbol_.length() > 0)))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): recombination() callbacks may only use a chromosome specifier in models with explicitly declared chromosomes.\" << EidosTerminate(script_block->identifier_token_);\n\t\t\t\t\n\t\t\t\tif (script_block->chromosome_symbol_.length() > 0)\n\t\t\t\t{\n\t\t\t\t\tChromosome *chrom = ChromosomeFromSymbol(script_block->chromosome_symbol_);\n\t\t\t\t\t\n\t\t\t\t\t// In general we allow callbacks to reference subpops, mutation types, etc. that do not exist,\n\t\t\t\t\t// giving the user broad latitude, but with string chromosome symbols a typo seems likely\n\t\t\t\t\tif (!chrom)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): recombination() callback declaration references a chromosome with symbol '\" << script_block->chromosome_symbol_ << \"' that has not been declared.\" << EidosTerminate(script_block->identifier_token_);\n\t\t\t\t\t\n\t\t\t\t\t// translate the symbol into an id, which is what ApplyRecombinationCallbacks() checks\n\t\t\t\t\tscript_block->chromosome_id_ = chrom->ID();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (nucleotide_based_)\n\t{\n\t\tif (num_ancseq_inits_ == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): Nucleotide-based models must provide an ancestral nucleotide sequence with initializeAncestralNucleotides().\" << EidosTerminate();\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\tif (!chromosome->ancestral_seq_buffer_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): (internal error) No ancestral sequence!\" << EidosTerminate();\n\t}\n\t\n\tCheckMutationStackPolicy();\n\t\n\t// In nucleotide-based models, process the mutationMatrix parameters for genomic element types to calculate the maximum mutation rate\n\tif (nucleotide_based_)\n\t\tCacheNucleotideMatrices();\n\t\n\t// initialize pre-allocated default Haplosome metadata records (HaplosomeMetadataRec) based on the chromosome configuration\n\t_MakeHaplosomeMetadataRecords();\n\t\n\t// initialize chromosomes\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\t// In nucleotide-based models, construct a mutation rate map\n\t\tif (nucleotide_based_)\n\t\t\tchromosome->CreateNucleotideMutationRateMap();\n\t\t\n\t\tchromosome->InitializeDraws();\n\t}\n\t\n\t// set up mutation runs for all chromosomes\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tchromosome->ChooseMutationRunLayout();\n\t\tchromosome->SetUpMutationRunContexts();\n\t}\n\t\n\t// Defining a neutral mutation type when tree-recording is on (with mutation recording) and the mutation rate is non-zero is legal, but causes a warning\n\t// I'm not sure this is a good idea, but maybe it will help people avoid doing dumb things; added at the suggestion of Peter Ralph...\n\t// BCH 26 Jan. 2020; refining the test here so it only logs if the neutral mutation type is used by a genomic element type\n\tif (recording_tree_ && recording_mutations_)\n\t{\n\t\tbool mut_rate_zero = true;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tfor (double rate : chromosome->mutation_rates_H_)\n\t\t\t\tif (rate != 0.0) { mut_rate_zero = false; break; }\n\t\t\tif (mut_rate_zero)\n\t\t\t\tfor (double rate : chromosome->mutation_rates_M_)\n\t\t\t\t\tif (rate != 0.0) { mut_rate_zero = false; break; }\n\t\t\tif (mut_rate_zero)\n\t\t\t\tfor (double rate : chromosome->mutation_rates_F_)\n\t\t\t\t\tif (rate != 0.0) { mut_rate_zero = false; break; }\n\t\t}\n\t\t\n\t\tif (!mut_rate_zero)\n\t\t{\n\t\t\tbool using_neutral_muttype = false;\n\t\t\t\n\t\t\tfor (auto getype_iter : genomic_element_types_)\n\t\t\t{\n\t\t\t\tGenomicElementType *getype = getype_iter.second;\n\t\t\t\t\n\t\t\t\tfor (auto muttype : getype->mutation_type_ptrs_)\n\t\t\t\t{\n\t\t\t\t\tif ((muttype->dfe_type_ == DFEType::kFixed) && (muttype->dfe_parameters_.size() == 1) && (muttype->dfe_parameters_[0] == 0.0))\n\t\t\t\t\t\tusing_neutral_muttype = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (using_neutral_muttype && !gEidosSuppressWarnings)\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::RunInitializeCallbacks): with tree-sequence recording enabled and a non-zero mutation rate, a neutral mutation type was defined and used; this is legal, but usually undesirable, since neutral mutations can be overlaid later using the tree-sequence information.\" << std::endl;\n\t\t}\n\t}\n\t\n\t// Ancestral sequence check; this has to wait until after the chromosome has been initialized\n\tif (nucleotide_based_)\n\t{\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\tif (chromosome->ancestral_seq_buffer_->size() != (std::size_t)(chromosome->last_position_ + 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RunInitializeCallbacks): The chromosome length (\" << chromosome->last_position_ + 1 << \" base\" << (chromosome->last_position_ + 1 != 1 ? \"s\" : \"\") << \") does not match the ancestral sequence length (\" << chromosome->ancestral_seq_buffer_->size() << \" base\" << (chromosome->ancestral_seq_buffer_->size() != 1 ? \"s\" : \"\") << \").\" << EidosTerminate();\n\t}\n\t\n\t// always start at cycle 1, regardless of what the starting tick value might be\n\tSetCycle(1);\n\t\n\t// kick off mutation run experiments, if needed\n\tfor (Chromosome *chromosome : chromosomes_)\n\t\tchromosome->InitiateMutationRunExperiments();\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (RecordingTreeSequence())\n\t\tAllocateTreeSequenceTables();\n}\n\nvoid Species::EndCurrentChromosome(bool starting_new_chromosome)\n{\n\t// Check for complete/correct initialization of the currently initializing chromosome.  The error messages emitted are tailored\n\t// to whether the user has an implicitly defined chromosome, or is explicitly defining chromosomes with initializeChromosome()\n\t// calls; we want to avoid confusion over the new vs. old paradigm of defining the chromosome.\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\tbool explicit_chromosome = (num_chromosome_inits_ > 0);\n\tstd::string chromosomeStr = (explicit_chromosome ? \"current chromosome\" : \"chromosome\");\n\tstd::string contextStr = (explicit_chromosome ? \"for the current chromosome\" : \"in an initialize() callback\");\n\tstd::string finalStr = ((explicit_chromosome && starting_new_chromosome) ? \"  The current chromosome's initialization must be completed before initialization of the next chromosome, with a new call to initializeChromosome(), can begin.\" : \"\");\n\t\n\tif (!nucleotide_based_ && (num_mutrate_inits_ == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  At least one mutation rate interval must be defined \" << contextStr << \" with initializeMutationRate(), although the rate given can be zero.\" << finalStr << EidosTerminate();\n\tif (nucleotide_based_ && (num_mutrate_inits_ > 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): initializeMutationRate() may not be called in nucleotide-based models (use initializeHotspotMap() to vary the mutation rate along the chromosome).\" << EidosTerminate();\n\t\n\tif ((num_mutation_type_inits_ == 0) && has_genetics_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): At least one mutation type must be defined in an initialize() callback with initializeMutationType() (or initializeMutationTypeNuc(), in nucleotide-based models).\" << EidosTerminate();\n\t\n\tif ((num_ge_type_inits_ == 0) && has_genetics_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): At least one genomic element type must be defined in an initialize() callback with initializeGenomicElementType().\" << EidosTerminate();\n\t\n\tif ((num_genomic_element_inits_ == 0) && has_genetics_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  At least one genomic element must be defined \" << contextStr << \" with initializeGenomicElement().\" << finalStr << EidosTerminate();\n\t\n\tif (num_recrate_inits_ == 0)\n\t{\n\t\tif (chromosome->DefaultsToZeroRecombination())\n\t\t{\n\t\t\t// For chromosomes that require zero recombination, we allow the\n\t\t\t// initializeRecombinationRate() call to be omitted for brevity.\n\t\t\t// Derived from ExecuteContextFunction_initializeRecombinationRate().\n\t\t\tstd::vector<slim_position_t> &positions = chromosome->recombination_end_positions_H_;\n\t\t\tstd::vector<double> &rates = chromosome->recombination_rates_H_;\n\t\t\trates.clear();\n\t\t\tpositions.clear();\n\t\t\t\n\t\t\trates.emplace_back(0.0);\n\t\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t\t\t\n\t\t\tnum_recrate_inits_++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  At least one recombination rate interval must be defined \" << contextStr << \" with initializeRecombinationRate(), although the rate given can be zero.\" << finalStr << EidosTerminate();\n\t\t}\n\t}\n\t\n\tif ((chromosome->recombination_rates_H_.size() != 0) && ((chromosome->recombination_rates_M_.size() != 0) || (chromosome->recombination_rates_F_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): Cannot define both sex-specific and sex-nonspecific recombination rates.\" << EidosTerminate();\n\t\n\tif (((chromosome->recombination_rates_M_.size() == 0) && (chromosome->recombination_rates_F_.size() != 0)) ||\n\t\t((chromosome->recombination_rates_M_.size() != 0) && (chromosome->recombination_rates_F_.size() == 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  Both sex-specific recombination rates must be defined, not just one (but one may be defined as zero).\" << finalStr << EidosTerminate();\n\t\n\t\n\tif ((chromosome->mutation_rates_H_.size() != 0) && ((chromosome->mutation_rates_M_.size() != 0) || (chromosome->mutation_rates_F_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): Cannot define both sex-specific and sex-nonspecific mutation rates.\" << EidosTerminate();\n\t\n\tif (((chromosome->mutation_rates_M_.size() == 0) && (chromosome->mutation_rates_F_.size() != 0)) ||\n\t\t((chromosome->mutation_rates_M_.size() != 0) && (chromosome->mutation_rates_F_.size() == 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  Both sex-specific mutation rates must be defined, not just one (but one may be defined as zero).\" << finalStr << EidosTerminate();\n\t\n\t\n\tif ((chromosome->hotspot_multipliers_H_.size() != 0) && ((chromosome->hotspot_multipliers_M_.size() != 0) || (chromosome->hotspot_multipliers_F_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): Cannot define both sex-specific and sex-nonspecific hotspot maps.\" << EidosTerminate();\n\t\n\tif (((chromosome->hotspot_multipliers_M_.size() == 0) && (chromosome->hotspot_multipliers_F_.size() != 0)) ||\n\t\t((chromosome->hotspot_multipliers_M_.size() != 0) && (chromosome->hotspot_multipliers_F_.size() == 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::EndCurrentChromosome): The initialization of the \" << chromosomeStr << \" is incomplete.  Both sex-specific hotspot maps must be defined, not just one (but one may be defined as 1.0).\" << finalStr << EidosTerminate();\n\t\n\thas_currently_initializing_chromosome_ = false;\n}\n\nbool Species::HasDoneAnyInitialization(void)\n{\n\t// This is used by Community to make sure that initializeModelType() executes before any other init\n\treturn ((num_mutation_type_inits_ > 0) || (num_mutrate_inits_ > 0) || (num_ge_type_inits_ > 0) || (num_genomic_element_inits_ > 0) || (num_recrate_inits_ > 0) || (num_gene_conv_inits_ > 0) || (num_sex_inits_ > 0) || (num_slimoptions_inits_ > 0) || (num_treeseq_inits_ > 0) || (num_ancseq_inits_ > 0) || (num_hotmap_inits_ > 0) || (num_species_inits_ > 0) || (num_chromosome_inits_ > 0) || has_implicit_chromosome_);\n}\n\nvoid Species::PrepareForCycle(void)\n{\n\t// Called by Community at the very start of each cycle, whether WF or nonWF (but not before initialize() callbacks)\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t\t// Optimization; see mutation_type.h for an explanation of what this counter is used for\n\t\tif (population_.any_muttype_call_count_used_)\n\t\t{\n\t\t\tfor (auto muttype_iter : mutation_types_)\n\t\t\t\t(muttype_iter.second)->muttype_registry_call_count_ = 0;\n\t\t\t\n\t\t\tpopulation_.any_muttype_call_count_used_ = false;\n\t\t}\n#endif\n\t\n\t// zero out clock accumulators for mutation run experiments; we will add to these as we do work later\n\tfor (Chromosome *chromosome : chromosomes_)\n\t\tchromosome->ZeroMutationRunExperimentClock();\n}\n\nvoid Species::MaintainMutationRegistry(void)\n{\n\tif (has_genetics_)\n\t{\n\t\tpopulation_.MaintainMutationRegistry();\n\t\t\n\t\t// Every hundredth cycle we unique mutation runs to optimize memory usage and efficiency.  The number 100 was\n\t\t// picked out of a hat – often enough to perhaps be useful in keeping SLiM slim, but infrequent enough that if it\n\t\t// is a time sink it won't impact the simulation too much.  This call is really quite fast, though – on the order\n\t\t// of 0.015 seconds for a pop of 10000 with a 1e5 chromosome and lots of mutations.  So although doing this every\n\t\t// cycle would seem like overkill – very few duplicates would be found per call – every 100 should be fine.\n\t\t// Anyway, if we start seeing this call in performance analysis, we should probably revisit this; the benefit is\n\t\t// likely to be pretty small for most simulations, so if the cost is significant then it may be a lose.\n\t\tif (cycle_ % 100 == 0)\n\t\t\tpopulation_.UniqueMutationRuns();\n\t}\n}\n\nvoid Species::RecalculateFitness(void)\n{\n\tpopulation_.RecalculateFitness(cycle_);\t// used to be cycle_ + 1 in the WF cycle; removing that 18 Feb 2016 BCH\n}\n\nvoid Species::MaintainTreeSequence(void)\n{\n\t// TREE SEQUENCE RECORDING\n\tif (recording_tree_)\n\t{\n#if DEBUG\n\t\t// check the integrity of the tree sequence in every cycle in Debug mode only\n\t\tCheckTreeSeqIntegrity();\n#endif\n\t\t\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tCheckAutoSimplification();\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(community_.profile_stage_totals_[8]);\n#endif\n\t\t\n\t\t// note that this causes simplification, so it will confuse the auto-simplification code\n\t\tif (running_treeseq_crosschecks_ && (cycle_ % treeseq_crosschecks_interval_ == 0))\n\t\t\tCrosscheckTreeSeqIntegrity();\n\t}\n}\n\nvoid Species::EmptyGraveyard(void)\n{\n\t// Individuals end up in graveyard_ due to killIndividuals(); they get disposed of here.\n\t// It's not necessary that FreeSubpopIndividual() be called on the correct subpopulation, really,\n\t// but that API is at the Subpopulation level instead of in Species for efficiency, so...\n\tfor (Individual *individual : graveyard_)\n\t\tindividual->subpopulation_->FreeSubpopIndividual(individual);\n\t\n\tgraveyard_.resize(0);\n}\n\nvoid Species::WF_GenerateOffspring(void)\n{\n\tslim_tick_t tick = community_.Tick();\n\tstd::vector<SLiMEidosBlock*> mate_choice_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosMateChoiceCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> modify_child_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosModifyChildCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> recombination_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosRecombinationCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> mutation_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosMutationCallback, -1, -1, -1, -1);\n\tbool mate_choice_callbacks_present = mate_choice_callbacks.size();\n\tbool modify_child_callbacks_present = modify_child_callbacks.size();\n\tbool recombination_callbacks_present = recombination_callbacks.size();\n\tbool mutation_callbacks_present = mutation_callbacks.size();\n\tbool no_active_callbacks = true;\n\t\n\t// a type 's' DFE needs to count as an active callback; it could activate other callbacks,\n\t// and in any case we need EvolveSubpopulation() to take the non-parallel code path\n\tif (type_s_dfes_present_)\n\t\tno_active_callbacks = false;\n\t\n\t// if there are no active callbacks of any type, we can pretend there are no callbacks at all\n\t// if there is a callback of any type, however, then inactive callbacks could become active\n\tif (mate_choice_callbacks_present || modify_child_callbacks_present || recombination_callbacks_present || mutation_callbacks_present)\n\t{\n\t\tif (no_active_callbacks)\n\t\t\tfor (SLiMEidosBlock *callback : mate_choice_callbacks)\n\t\t\t\tif (callback->block_active_)\n\t\t\t\t{\n\t\t\t\t\tno_active_callbacks = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\n\t\tif (no_active_callbacks)\n\t\t\tfor (SLiMEidosBlock *callback : modify_child_callbacks)\n\t\t\t\tif (callback->block_active_)\n\t\t\t\t{\n\t\t\t\t\tno_active_callbacks = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\n\t\tif (no_active_callbacks)\n\t\t\tfor (SLiMEidosBlock *callback : recombination_callbacks)\n\t\t\t\tif (callback->block_active_)\n\t\t\t\t{\n\t\t\t\t\tno_active_callbacks = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\n\t\tif (no_active_callbacks)\n\t\t\tfor (SLiMEidosBlock *callback : mutation_callbacks)\n\t\t\t\tif (callback->block_active_)\n\t\t\t\t{\n\t\t\t\t\tno_active_callbacks = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t}\n\t\n\tif (no_active_callbacks)\n\t{\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t\tpopulation_.EvolveSubpopulation(*subpop_pair.second, false, false, false, false, false);\n\t}\n\telse\n\t{\n\t\t// cache a list of callbacks registered for each subpop\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\t// Get mateChoice() callbacks that apply to this subpopulation\n\t\t\tsubpop->registered_mate_choice_callbacks_.resize(0);\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *callback : mate_choice_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop->registered_mate_choice_callbacks_.emplace_back(callback);\n\t\t\t}\n\t\t\t\n\t\t\t// Get modifyChild() callbacks that apply to this subpopulation\n\t\t\tsubpop->registered_modify_child_callbacks_.resize(0);\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *callback : modify_child_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop->registered_modify_child_callbacks_.emplace_back(callback);\n\t\t\t}\n\t\t\t\n\t\t\t// Get recombination() callbacks that apply to this subpopulation\n\t\t\tsubpop->registered_recombination_callbacks_.resize(0);\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *callback : recombination_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop->registered_recombination_callbacks_.emplace_back(callback);\n\t\t\t}\n\t\t\t\n\t\t\t// Get mutation() callbacks that apply to this subpopulation\n\t\t\tsubpop->registered_mutation_callbacks_.resize(0);\n\t\t\t\n\t\t\tfor (SLiMEidosBlock *callback : mutation_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop->registered_mutation_callbacks_.emplace_back(callback);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// then evolve each subpop\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t\tpopulation_.EvolveSubpopulation(*subpop_pair.second, mate_choice_callbacks_present, modify_child_callbacks_present, recombination_callbacks_present, mutation_callbacks_present, type_s_dfes_present_);\n\t}\n}\n\nvoid Species::WF_SwitchToChildGeneration(void)\n{\n\t// switch to the child generation; we don't want to do this until all callbacks have executed for all subpops\n\tpopulation_.child_generation_valid_ = true;\n\t\n\t// added 30 November 2016 so MutationRun refcounts reflect their usage count in the simulation\n\t// moved up to SLiMCycleStage::kWFStage2GenerateOffspring, 9 January 2018, so that the\n\t// population is in a standard state for CheckIndividualIntegrity() at the end of this stage\n\t// BCH 4/22/2023: this is no longer relevant in terms of accurate MutationRun refcounts, since\n\t// we no longer refcount those, but they still need to be zeroed out so they're ready for reuse\n\t// BCH 10/15/2024: I realized that clearing the haplosomes is no longer needed at all; we can\n\t// just remove our requirement that the haplosomes be cleared, and overwrite the stale pointers\n\t// when we reuse a haplosome.  I am relegating haplosome clearing to a debugging flag.\n#if SLIM_CLEAR_HAPLOSOMES\n\tpopulation_.ClearParentalHaplosomes();\n#endif\n}\n\nvoid Species::WF_SwapGenerations(void)\n{\n\tpopulation_.SwapGenerations();\n}\n\nvoid Species::nonWF_GenerateOffspring(void)\n{\n\tslim_tick_t tick = community_.Tick();\n\tstd::vector<SLiMEidosBlock*> reproduction_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosReproductionCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> modify_child_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosModifyChildCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> recombination_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosRecombinationCallback, -1, -1, -1, -1);\n\tstd::vector<SLiMEidosBlock*> mutation_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosMutationCallback, -1, -1, -1, -1);\n\t\n\t// choose templated variants for GenerateIndividualsX() methods of Subpopulation, called during reproduction() callbacks\n\t// this is an optimization technique that lets us optimize away unused cruft at compile time\n\t// some relevant posts that were helpful in figuring out the correct syntax:\n\t// \thttp://goodliffe.blogspot.com/2011/07/c-declaring-pointer-to-template-method.html\n\t// \thttps://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file\n\t// \thttps://stackoverflow.com/questions/22275786/change-boolean-flags-into-template-arguments\n\t// and a Godbolt experiment I did to confirm that this really works: https://godbolt.org/z/Mva4Kbhrd\n\t//\n\t// callbacks are \"on\" if they exist for any subpopulation, since nonWF allows parents to belong to any subpop\n\t// note this optimization depends upon the fact that none of these flags can change during one reproduction() stage!\n\tbool pedigrees_enabled = PedigreesEnabled();\n\tbool recording_tree_sequence = RecordingTreeSequence();\n\tbool has_reproduction_callbacks = ((reproduction_callbacks.size() > 0) || (modify_child_callbacks.size() > 0) || (recombination_callbacks.size() > 0) || (mutation_callbacks.size() > 0));\n\tbool is_spatial = (SpatialDimensionality() >= 1);\n\t\n\tif (DoingAnyMutationRunExperiments())\n\t{\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\t// has any of the callbacks that the GenerateIndividuals...() methods care about; this can be refined later\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, true, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, true, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, true, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<true, false, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<true, false, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<true, false, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, true, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, true, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, true, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (recording_tree_sequence)\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, true, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, true, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, true, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, true, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, true, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, true, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, true, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, true, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (has_reproduction_callbacks)\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, false, true, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, false, true, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, false, true, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, false, true, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (is_spatial)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, false, false, true>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, false, false, true>;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.GenerateIndividualCrossed_TEMPLATED = &Subpopulation::GenerateIndividualCrossed<false, false, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualSelfed_TEMPLATED = &Subpopulation::GenerateIndividualSelfed<false, false, false, false, false>;\n\t\t\t\t\t\tpopulation_.GenerateIndividualCloned_TEMPLATED = &Subpopulation::GenerateIndividualCloned<false, false, false, false, false>;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// similarly, choose templated variants for the HaplosomeCrossed()/HaplosomeCloned()/HaplosomeRecombined() methods of Population\n\tif (recording_tree_sequence)\n\t{\n\t\tif (has_reproduction_callbacks)\t// has any of the callbacks that the GenerateIndividuals...() methods care about; this can be refined later\n\t\t{\n\t\t\tpopulation_.HaplosomeCrossed_TEMPLATED = &Population::HaplosomeCrossed<true, true>;\n\t\t\tpopulation_.HaplosomeCloned_TEMPLATED = &Population::HaplosomeCloned<true, true>;\n\t\t\tpopulation_.HaplosomeRecombined_TEMPLATED = &Population::HaplosomeRecombined<true, true>;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpopulation_.HaplosomeCrossed_TEMPLATED = &Population::HaplosomeCrossed<true, false>;\n\t\t\tpopulation_.HaplosomeCloned_TEMPLATED = &Population::HaplosomeCloned<true, false>;\n\t\t\tpopulation_.HaplosomeRecombined_TEMPLATED = &Population::HaplosomeRecombined<true, false>;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (has_reproduction_callbacks)\n\t\t{\n\t\t\tpopulation_.HaplosomeCrossed_TEMPLATED = &Population::HaplosomeCrossed<false, true>;\n\t\t\tpopulation_.HaplosomeCloned_TEMPLATED = &Population::HaplosomeCloned<false, true>;\n\t\t\tpopulation_.HaplosomeRecombined_TEMPLATED = &Population::HaplosomeRecombined<false, true>;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpopulation_.HaplosomeCrossed_TEMPLATED = &Population::HaplosomeCrossed<false, false>;\n\t\t\tpopulation_.HaplosomeCloned_TEMPLATED = &Population::HaplosomeCloned<false, false>;\n\t\t\tpopulation_.HaplosomeRecombined_TEMPLATED = &Population::HaplosomeRecombined<false, false>;\n\t\t}\n\t}\n\t\n\t// cache a list of callbacks registered for each subpop\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t{\n\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\n\t\t// Get reproduction() callbacks that apply to this subpopulation\n\t\tsubpop->registered_reproduction_callbacks_.resize(0);\n\t\t\n\t\tfor (SLiMEidosBlock *callback : reproduction_callbacks)\n\t\t{\n\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\n\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\tsubpop->registered_reproduction_callbacks_.emplace_back(callback);\n\t\t}\n\t\t\n\t\t// Get modifyChild() callbacks that apply to this subpopulation\n\t\tsubpop->registered_modify_child_callbacks_.resize(0);\n\t\t\n\t\tfor (SLiMEidosBlock *callback : modify_child_callbacks)\n\t\t{\n\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\n\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\tsubpop->registered_modify_child_callbacks_.emplace_back(callback);\n\t\t}\n\t\t\n\t\t// Get recombination() callbacks that apply to this subpopulation\n\t\tsubpop->registered_recombination_callbacks_.resize(0);\n\t\t\n\t\tfor (SLiMEidosBlock *callback : recombination_callbacks)\n\t\t{\n\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\n\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\tsubpop->registered_recombination_callbacks_.emplace_back(callback);\n\t\t}\n\t\t\n\t\t// Get mutation() callbacks that apply to this subpopulation\n\t\tsubpop->registered_mutation_callbacks_.resize(0);\n\t\t\n\t\tfor (SLiMEidosBlock *callback : mutation_callbacks)\n\t\t{\n\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\n\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\tsubpop->registered_mutation_callbacks_.emplace_back(callback);\n\t\t}\n\t}\n\t\n\t// then evolve each subpop\n\tSLiMEidosBlockType old_executing_block_type = community_.executing_block_type_;\n\tcommunity_.executing_block_type_ = SLiMEidosBlockType::SLiMEidosReproductionCallback;\n\t\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\tsubpop_pair.second->ReproduceSubpopulation();\n\t\n\tcommunity_.executing_block_type_ = old_executing_block_type;\n\t\n\t// This completes the first half of the reproduction process; see Species::nonWF_MergeOffspring() for the second half\n}\n\nvoid Species::nonWF_MergeOffspring(void)\n{\n\t// Species::nonWF_GenerateOffspring() completed the first half of the reproduction process; this does the second half\n\t// This defers the merging of offspring until all species have reproduced, allowing multispecies interactions to remain valid\n\t\n\t// Invalidate interactions, now that the generation they were valid for is disappearing\n\tcommunity_.InvalidateInteractionsForSpecies(this);\n\t\n\t// then merge in the generated offspring; we don't want to do this until all callbacks have executed for all subpops\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\tsubpop_pair.second->MergeReproductionOffspring();\n\t\n\t// then generate any deferred haplosomes; note that the deferred offspring got merged in above already\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tpopulation_.DoDeferredReproduction();\n#endif\n\t\n\t// clear the \"migrant\" property on all individuals\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\tstd::vector<Individual *> &parents = subpop->parent_individuals_;\n\t\tsize_t parent_count = parents.size();\n\t\t\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_MIGRANT_CLEAR);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MIGRANT_CLEAR);\n#pragma omp parallel for schedule(static) default(none) shared(parent_count) firstprivate(parents)  if(parent_count >= EIDOS_OMPMIN_MIGRANT_CLEAR) num_threads(thread_count)\n\t\tfor (size_t parent_index = 0; parent_index < parent_count; ++parent_index)\n\t\t{\n\t\t\tparents[parent_index]->migrant_ = false;\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_MIGRANT_CLEAR);\n\t}\n\t\n\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\tpopulation_.InvalidateMutationReferencesCache();\n}\n\nvoid Species::nonWF_ViabilitySurvival(void)\n{\n\tslim_tick_t tick = community_.Tick();\n\tstd::vector<SLiMEidosBlock*> survival_callbacks = CallbackBlocksMatching(tick, SLiMEidosBlockType::SLiMEidosSurvivalCallback, -1, -1, -1, -1);\n\tbool survival_callbacks_present = survival_callbacks.size();\n\tbool no_active_callbacks = true;\n\t\n\t// if there are no active callbacks, we can pretend there are no callbacks at all\n\tif (survival_callbacks_present)\n\t{\n\t\tfor (SLiMEidosBlock *callback : survival_callbacks)\n\t\t\tif (callback->block_active_)\n\t\t\t{\n\t\t\t\tno_active_callbacks = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t}\n\t\n\tif (no_active_callbacks)\n\t{\n\t\t// Survival is simple viability selection without callbacks\n\t\tstd::vector<SLiMEidosBlock*> no_survival_callbacks;\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t\tsubpop_pair.second->ViabilitySurvival(no_survival_callbacks);\n\t}\n\telse\n\t{\n\t\t// Survival is governed by callbacks, per subpopulation\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tslim_objectid_t subpop_id = subpop_pair.first;\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tstd::vector<SLiMEidosBlock*> subpop_survival_callbacks;\n\t\t\t\n\t\t\t// Get survival callbacks that apply to this subpopulation\n\t\t\tfor (SLiMEidosBlock *callback : survival_callbacks)\n\t\t\t{\n\t\t\t\tslim_objectid_t callback_subpop_id = callback->subpopulation_id_;\n\t\t\t\t\n\t\t\t\tif ((callback_subpop_id == -1) || (callback_subpop_id == subpop_id))\n\t\t\t\t\tsubpop_survival_callbacks.emplace_back(callback);\n\t\t\t}\n\t\t\t\n\t\t\t// Handle survival, using the callbacks\n\t\t\tsubpop->ViabilitySurvival(subpop_survival_callbacks);\n\t\t}\n\t\t\n\t\t// Callbacks could have requested that individuals move rather than dying; check for that\n\t\tbool any_moved = false;\n\t\t\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tif ((subpop_pair.second)->nonWF_survival_moved_individuals_.size())\n\t\t\t{\n\t\t\t\tany_moved = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (any_moved)\n\t\t\tpopulation_.ResolveSurvivalPhaseMovement();\n\t}\n\t\n\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\tpopulation_.InvalidateMutationReferencesCache();\n}\n\nvoid Species::FinishMutationRunExperimentTimings(void)\n{\n\tfor (Chromosome *chromosome : chromosomes_)\n\t\tchromosome->FinishMutationRunExperimentTiming();\n}\n\nvoid Species::SetCycle(slim_tick_t p_new_cycle)\n{\n\tcycle_ = p_new_cycle;\n\t\n\t// Note that the tree sequence tick depends upon the tick, not the cycle,\n\t// so that it is is sync for all species in the community.\n}\n\nvoid Species::AdvanceCycleCounter(void)\n{\n\t// called by Community at the end of the cycle\n\tSetCycle(cycle_ + 1);\n}\n\nvoid Species::SimulationHasFinished(void)\n{\n\t// This is an opportunity for final calculation/output when a simulation finishes\n\t// This is called by Community::SimulationHasFinished() for each species\n\t\n\t// Print mutation run experiment results\n\tif (SLiM_verbosity_level >= 2)\n\t{\n\t\tint summary_count = 0;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\tsummary_count += chromosome->MutationRunExperimentsEnabled();\n\t\t\n\t\tif (summary_count > 0)\n\t\t{\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t\t\n\t\t\tSLIM_OUTSTREAM << \"// Mutation run experiment data:\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// For each chromosome that conducted experiments, the optimal\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// mutation run count is given, with the percentage of cycles\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// in which that number was used.  The number of mutation run\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// experiments conducted is also given; if that is small (less\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// than 200 or so), or if the percentage of cycles is close to\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// or below 50%, the optimal count may not be accurate, since\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// insufficient data was gathered.  In that case, you might\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// wish to conduct your own timing experiments using different\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// counts.  Profile output also has more detail on this data.\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//\" << std::endl;\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\t\tchromosome->PrintMutationRunExperimentSummary();\n\t\t\t\n\t\t\tSLIM_OUTSTREAM << \"//\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// It might (or might not) speed up your model to add:\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//    mutationRuns=X\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"//\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// to the initializeChromosome() call\" << (summary_count > 1 ? \"s\" : \"\") << \" in your initialize()\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// callback, where X is the optimal count for the chromosome.\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// (If your model does not call initializeChromosome(), you\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// would need to add \" << (summary_count > 1 ? \"those calls\" : \"that call\") <<\n\t\t\t\t\".)  Optimal \" << (summary_count > 1 ? \"counts\" : \"count\") << \" may change\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// if your model changes, or even if the model is just run on\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << \"// different hardware.  See the SLiM manual for more details.\" << std::endl;\n\t\t\tSLIM_OUTSTREAM << std::endl;\n\t\t}\n\t}\n}\n\nvoid Species::InferInheritanceForClone(Chromosome *chromosome, Individual *parent, IndividualSex sex, Haplosome **strand1, Haplosome **strand3, const char *caller_name)\n{\n#if DEBUG\n\tif (!chromosome || !parent || !strand1 || !strand3 || !caller_name)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForClone): (internal error) parameter is nullptr.\" << EidosTerminate();\n#endif\n\t\n\tChromosomeType chromosome_type = chromosome->Type();\n\tunsigned int chromosome_index = chromosome->Index();\n\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\n\t// validate the offspring's sex; note that we allow kHF_HaploidFemaleInherited and\n\t// kHM_HaploidMaleInherited to be inherited from the \"wrong\" sex, as does addCloned();\n\t// those inheritance patterns are for biparental crosses specifically\n\tIndividualSex parent_sex = parent->sex_;\n\t\n\tif (sex == IndividualSex::kUnspecified)\n\t\tsex = parent_sex;\n\t\n\tif (sex != parent_sex)\n\t\tif ((chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kY_YSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kW_WSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kFL_HaploidFemaleLine) ||\n\t\t\t(chromosome_type == ChromosomeType::kML_HaploidMaleLine) ||\n\t\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForClone): clonal inheritance inference for \" << caller_name << \" requires that sex match the sex of the parent for chromosome type '\" << chromosome_type << \"' (symbol '\" << chromosome->Symbol() << \"'), since the haplosome configuration of that chromosome type depends upon sex.  You can pass NULL for sex to match the parent automatically.\" << EidosTerminate();\n\t\n\t// all returned entries not set are NULL\n\t*strand1 = nullptr;\n\t*strand3 = nullptr;\n\t\n\t// for simplicity, we just test for a null haplosome and clone whatever is not null;\n\t// if the parent is legal, the offspring will be legal too, given the sex check above\n\tif (chromosome->IntrinsicPloidy() == 2)\n\t{\n\t\tHaplosome *hap1 = parent->haplosomes_[first_haplosome_index];\n\t\tHaplosome *hap2 = parent->haplosomes_[last_haplosome_index];\n\t\t\n\t\tif (!hap1->IsNull())\t*strand1 = hap1;\n\t\tif (!hap2->IsNull())\t*strand3 = hap2;\n\t}\n\telse\t// chromosome->IntrinsicPloidy() == 1\n\t{\t\t\n\t\tHaplosome *hap = parent->haplosomes_[first_haplosome_index];\n\t\t\n\t\tif (!hap->IsNull())\t\t*strand1 = hap;\n\t}\n}\n\nvoid Species::InferInheritanceForCross(Chromosome *chromosome, Individual *parent1, Individual *parent2, IndividualSex sex, Haplosome **strand1, Haplosome **strand2, Haplosome **strand3, Haplosome **strand4, const char *caller_name)\n{\n#if DEBUG\n\tif (!chromosome || !parent1 || !parent2 || !strand1 || !strand2 || !strand3 || !strand4 || !caller_name)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForCross): (internal error) parameter is nullptr.\" << EidosTerminate();\n#endif\n\t\n\tChromosomeType chromosome_type = chromosome->Type();\n\tunsigned int chromosome_index = chromosome->Index();\n\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\n\t// validate the offspring's sex; note that we allow kHF_HaploidFemaleInherited and\n\t// kHM_HaploidMaleInherited to be inherited from the \"wrong\" sex, as does addCloned();\n\t// those inheritance patterns are for biparental crosses specifically\n\tIndividualSex parent1_sex = parent1->sex_;\n\tIndividualSex parent2_sex = parent2->sex_;\n\t\n\tif (sex_enabled_ && ((parent1_sex != IndividualSex::kFemale) || (parent2_sex != IndividualSex::kMale)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForCross): \" << caller_name << \" requires that parent1 be female and parent2 male, in a sexual model.  If you require more flexibility than this, turn off separate sexes and track the sex of individuals yourself, or use addPatternForRecombinant() instead.\" << EidosTerminate();\n\t\n\tif (sex == IndividualSex::kUnspecified)\n\t\tif ((chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kY_YSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kW_WSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kFL_HaploidFemaleLine) ||\n\t\t\t(chromosome_type == ChromosomeType::kML_HaploidMaleLine) ||\n\t\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForCross): crossed inheritance inference for \" << caller_name << \" requires that sex is specified explicitly as 'M' or 'F' for chromosome type '\" << chromosome_type << \"' (symbol '\" << chromosome->Symbol() << \"'), since the haplosome configuration of that chromosome type depends upon sex.\" << EidosTerminate();\n\t\n\t// all returned entries not set are NULL\n\t*strand1 = nullptr;\n\t*strand2 = nullptr;\n\t*strand3 = nullptr;\n\t*strand4 = nullptr;\n\t\n\t// figure out the inheritance patterns, which are complex!\n\tswitch (chromosome_type)\n\t{\n\t\t\t// diploid types\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t{\n\t\t\t// we require all haplosomes non-null; if the user is playing games, they need to control them\n\t\t\tHaplosome *hap1 = parent1->haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *hap2 = parent1->haplosomes_[last_haplosome_index];\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *hap4 = parent2->haplosomes_[last_haplosome_index];\n\t\t\t\n\t\t\tif (hap1->IsNull() || hap2->IsNull() || hap3->IsNull() || hap4->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForCross): crossed inheritance inference for \" << caller_name << \" requires that all four parental strands are not null haplosomes for chromosome type 'A'), since the parental strands are supposed to be crossed.  Use addPatternForRecombinant() to control more complex inheritance patterns.\" << EidosTerminate();\n\t\t\t\n\t\t\t*strand1 = hap1;\n\t\t\t*strand2 = hap2;\n\t\t\t*strand3 = hap3;\n\t\t\t*strand4 = hap4;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t{\n\t\t\t// we require all haplosomes non-null; if the user is playing games, they need to control them\n\t\t\tHaplosome *hap1 = parent1->haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (hap1->IsNull() || hap3->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::InferInheritanceForCross): crossed inheritance inference for \" << caller_name << \" requires that both parental strands are not null haplosomes for chromosome type 'H'), since the strands from the two parents are supposed to be crossed.  Use addPatternForRecombinant() to control more complex inheritance patterns.\" << EidosTerminate();\n\t\t\t\n\t\t\t*strand1 = hap1;\n\t\t\t*strand2 = hap3;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t{\n\t\t\t// females are XX, males are X-\n\t\t\tHaplosome *hap1 = parent1->haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *hap2 = parent1->haplosomes_[last_haplosome_index];\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\t// hap4 is null\n\t\t\t\n\t\t\tif (sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// first offspring X is crossed from the female, second is null (a Y was inherited instead)\n\t\t\t\t*strand1 = hap1;\n\t\t\t\t*strand2 = hap2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// first offspring X is crossed from the female, second is clonal from the male\n\t\t\t\t*strand1 = hap1;\n\t\t\t\t*strand2 = hap2;\n\t\t\t\t*strand3 = hap3;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\t// females are -, males are Y\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// offspring Y is inherited from the male\n\t\t\t\t*strand1 = hap3;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t{\n\t\t\t// females are -Z, males are ZZ\n\t\t\tHaplosome *hap2 = parent1->haplosomes_[last_haplosome_index];\t// hap1 is null\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\n\t\t\tHaplosome *hap4 = parent2->haplosomes_[last_haplosome_index];\n\t\t\t\n\t\t\tif (sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// first offspring Z is clonal from the female, second is crossed from the male\n\t\t\t\t*strand1 = hap2;\n\t\t\t\t*strand3 = hap3;\n\t\t\t\t*strand4 = hap4;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// first offspring Z is null (a W was inherited instead), second is crossed from the male\n\t\t\t\t*strand3 = hap3;\n\t\t\t\t*strand4 = hap4;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t{\n\t\t\t// females are W, males are -\n\t\t\tHaplosome *hap1 = parent1->haplosomes_[first_haplosome_index];\n\t\t\t\n\t\t\tif (sex == IndividualSex::kFemale)\n\t\t\t{\n\t\t\t\t// offspring W is inherited from the female\n\t\t\t\t*strand1 = hap1;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t{\n\t\t\tHaplosome *hap1 = parent1->haplosomes_[first_haplosome_index];\n\t\t\t*strand1 = hap1;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t{\n\t\t\tHaplosome *hap3 = parent2->haplosomes_[first_haplosome_index];\n\t\t\t*strand1 = hap3;\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t{\n\t\t\t// females are --, males are -Y\n\t\t\tHaplosome *hap4 = parent2->haplosomes_[last_haplosome_index];\n\t\t\t\n\t\t\tif (sex == IndividualSex::kMale)\n\t\t\t{\n\t\t\t\t// offspring Y is inherited from the male, to the second offspring haplosome\n\t\t\t\t*strand3 = hap4;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): chromosome type 'H-' does not allow reproduction by biparental cross (only cloning); chromosome type 'H' provides greater flexibility for modeling haploids.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// this method always randomizes the initial copy strand; even if randomizeStrands=F is passed\n\t// to addMultiRecombinant(), inferred crosses should still behave like regular crosses\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\n\tif (*strand1 && *strand2 && Eidos_RandomBool(rng_state))\n\t\tstd::swap(*strand1, *strand2);\n\tif (*strand3 && *strand4 && Eidos_RandomBool(rng_state))\n\t\tstd::swap(*strand3, *strand4);\n}\n\nvoid Species::Species_CheckIntegrity(void)\n{\n#if DEBUG\n\t// Check for consistency in the chromosome setup first\n\tconst std::vector<Chromosome *> &chromosomes = Chromosomes();\n\tsize_t chromosomes_count = chromosomes.size();\n\tint haplosome_index = 0;\n\tbool null_haplosomes_used = false;\n\t\n\tif (has_genetics_ && (chromosomes_count == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) no chromosome present in genetic species.\" << EidosTerminate();\n\t\n\tfor (size_t chromosome_index = 0; chromosome_index < chromosomes_count; chromosome_index++)\n\t{\n\t\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t\n\t\tif (chromosome->Index() != chromosome_index)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) chromosome->Index() mismatch.\" << EidosTerminate();\n\t\t\n\t\tif (ChromosomeFromID(chromosome->ID()) != chromosome)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) chromosome->ID() lookup error.\" << EidosTerminate();\n\t\t\n\t\tif (ChromosomeFromSymbol(chromosome->Symbol()) != chromosome)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) chromosome->Symbol() lookup error.\" << EidosTerminate();\n\t\t\n\t\tif (!sex_enabled_ &&\n\t\t\t((chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t\t (chromosome_type == ChromosomeType::kY_YSexChromosome) ||\n\t\t\t (chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t\t (chromosome_type == ChromosomeType::kW_WSexChromosome) ||\n\t\t\t //(chromosome_type == ChromosomeType::kHF_HaploidFemaleInherited) ||\t\t// now allowing; see issue #534\n\t\t\t (chromosome_type == ChromosomeType::kFL_HaploidFemaleLine) ||\n\t\t\t //(chromosome_type == ChromosomeType::kHM_HaploidMaleInherited) ||\t\t\t// now allowing; see issue #534\n\t\t\t (chromosome_type == ChromosomeType::kML_HaploidMaleLine) ||\n\t\t\t (chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) chromosome type '\" << chromosome_type << \"' not allowed in non-sexual models.\" << EidosTerminate();\n\t\t\n\t\t// check haplosome indices\n\t\tint haplosome_count = chromosome->IntrinsicPloidy();\n\t\t\n\t\tif (first_haplosome_index_[chromosome_index] != haplosome_index)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) first_haplosome_index_ mismatch.\" << EidosTerminate();\n\t\tif (last_haplosome_index_[chromosome_index] != haplosome_index + haplosome_count - 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) last_haplosome_index_ mismatch.\" << EidosTerminate();\n\t\t\n\t\thaplosome_index += haplosome_count;\n\t\t\n\t\t// check null haplosome optimization\n\t\tif (chromosome->AlwaysUsesNullHaplosomes())\n\t\t\tnull_haplosomes_used = true;\n\t}\n\t\n\tif (haplosome_index != haplosome_count_per_individual_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) haplosome_count_per_individual_ does not match chromosomes.\" << EidosTerminate();\n\t\n\tif (null_haplosomes_used != chromosomes_use_null_haplosomes_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::Species_CheckIntegrity): (internal error) chromosomes_use_null_haplosomes_ mismatch.\" << EidosTerminate();\n#endif\n\t\n#if DEBUG\n\t// Then check each individual and its haplosomes\n\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\tsubpop_pair.second->CheckIndividualIntegrity();\n#endif\n}\n\nvoid Species::_CheckMutationStackPolicy(void)\n{\n\t// Check mutation stacking policy for consistency.  This is called periodically during the simulation.\n\t\n\t// First do a fast check for the standard case, that each mutation type is in its own stacking group\n\t// with an index equal to its mutation_type_id_.  Unless the user has configured stacking groups this\n\t// will verify the setup very quickly.\n\tbool stacking_nonstandard = false;\n\t\n\tfor (auto muttype_iter : mutation_types_)\n\t{\n\t\tMutationType *muttype = muttype_iter.second;\n\t\t\n\t\tif (muttype->stack_group_ != muttype->mutation_type_id_)\n\t\t{\n\t\t\tstacking_nonstandard = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tif (stacking_nonstandard)\n\t{\n\t\t// If there are N mutation types that participate in M stacking groups, the runtime of the code below\n\t\t// is approximately O(N*M), so it can take quite a long time with many distinct stacking groups.  It\n\t\t// could perhaps be made faster by first putting the mutation types into a data structure that sorted\n\t\t// them by stacking group; a std::map, or just sorting them by stacking group in a vector.  However,\n\t\t// I have yet to encounter a model that triggers this case badly (now that the nucleotide model has\n\t\t// been fixed to use a single mutation stacking group).\n\t\tstd::vector<int64_t> checked_groups;\n\t\t\n\t\tfor (auto muttype_iter : mutation_types_)\n\t\t{\n\t\t\tMutationType *muttype = muttype_iter.second;\n\t\t\tint64_t stack_group = muttype->stack_group_;\n\t\t\t\n\t\t\tif (std::find(checked_groups.begin(), checked_groups.end(), stack_group) == checked_groups.end())\n\t\t\t{\n\t\t\t\t// This stacking group has not been checked yet\n\t\t\t\tMutationStackPolicy stack_policy = muttype->stack_policy_;\n\t\t\t\t\n\t\t\t\tfor (auto muttype_iter2 : mutation_types_)\n\t\t\t\t{\n\t\t\t\t\tMutationType *muttype2 = muttype_iter2.second;\n\t\t\t\t\t\n\t\t\t\t\tif ((muttype2->stack_group_ == stack_group) && (muttype2->stack_policy_ != stack_policy))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_CheckMutationStackPolicy): inconsistent mutationStackPolicy values within one mutationStackGroup.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tchecked_groups.emplace_back(stack_group);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// we're good until the next change\n\tmutation_stack_policy_changed_ = false;\n}\n\nvoid Species::MaxNucleotideMutationRateChanged(void)\n{\n\tCacheNucleotideMatrices();\n\t\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tchromosome->CreateNucleotideMutationRateMap();\n\t\tchromosome->InitializeDraws();\n\t}\n}\n\nvoid Species::CacheNucleotideMatrices(void)\n{\n\t// Go through all genomic element types in a nucleotide-based model, analyze their mutation matrices,\n\t// and find the maximum mutation rate expressed by any genomic element type for any genomic background.\n\tmax_nucleotide_mut_rate_ = 0.0;\n\t\n\tfor (auto type_entry : genomic_element_types_)\n\t{\n\t\tGenomicElementType *ge_type = type_entry.second;\n\t\t\n\t\tif (ge_type->mm_thresholds)\n\t\t\tfree(ge_type->mm_thresholds);\n\t\t\n\t\tif (ge_type->mutation_matrix_)\n\t\t{\n\t\t\tEidosValue_Float *mm = ge_type->mutation_matrix_.get();\n\t\t\tconst double *mm_data = mm->data();\n\t\t\t\n\t\t\tif (mm->Count() == 16)\n\t\t\t{\n\t\t\t\tfor (int nuc = 0; nuc < 4; ++nuc)\n\t\t\t\t{\n\t\t\t\t\tdouble rateA = mm_data[nuc];\n\t\t\t\t\tdouble rateC = mm_data[nuc + 4];\n\t\t\t\t\tdouble rateG = mm_data[nuc + 8];\n\t\t\t\t\tdouble rateT = mm_data[nuc + 12];\n\t\t\t\t\tdouble total_rate = rateA + rateC + rateG + rateT;\n\t\t\t\t\t\n\t\t\t\t\tif (total_rate > max_nucleotide_mut_rate_)\n\t\t\t\t\t\tmax_nucleotide_mut_rate_ = total_rate;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (mm->Count() == 256)\n\t\t\t{\n\t\t\t\tfor (int trinuc = 0; trinuc < 64; ++trinuc)\n\t\t\t\t{\n\t\t\t\t\tdouble rateA = mm_data[trinuc];\n\t\t\t\t\tdouble rateC = mm_data[trinuc + 64];\n\t\t\t\t\tdouble rateG = mm_data[trinuc + 128];\n\t\t\t\t\tdouble rateT = mm_data[trinuc + 192];\n\t\t\t\t\tdouble total_rate = rateA + rateC + rateG + rateT;\n\t\t\t\t\t\n\t\t\t\t\tif (total_rate > max_nucleotide_mut_rate_)\n\t\t\t\t\t\tmax_nucleotide_mut_rate_ = total_rate;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CacheNucleotideMatrices): (internal error) unsupported mutation matrix size.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// Now go through the genomic element types again, and calculate normalized mutation rate\n\t// threshold values that will allow fast decisions on which derived nucleotide to create\n\tfor (auto type_entry : genomic_element_types_)\n\t{\n\t\tGenomicElementType *ge_type = type_entry.second;\n\t\t\n\t\tif (ge_type->mutation_matrix_)\n\t\t{\n\t\t\tEidosValue_Float *mm = ge_type->mutation_matrix_.get();\n\t\t\tconst double *mm_data = mm->data();\n\t\t\t\n\t\t\tif (mm->Count() == 16)\n\t\t\t{\n\t\t\t\tge_type->mm_thresholds = (double *)malloc(16 * sizeof(double));\n\t\t\t\tif (!ge_type->mm_thresholds)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CacheNucleotideMatrices): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tfor (int nuc = 0; nuc < 4; ++nuc)\n\t\t\t\t{\n\t\t\t\t\tdouble rateA = mm_data[nuc];\n\t\t\t\t\tdouble rateC = mm_data[nuc + 4];\n\t\t\t\t\tdouble rateG = mm_data[nuc + 8];\n\t\t\t\t\tdouble rateT = mm_data[nuc + 12];\n\t\t\t\t\tdouble total_rate = rateA + rateC + rateG + rateT;\n\t\t\t\t\tdouble fraction_of_max_rate = total_rate / max_nucleotide_mut_rate_;\n\t\t\t\t\tdouble *nuc_thresholds = ge_type->mm_thresholds + (size_t)nuc * 4;\n\t\t\t\t\t\n\t\t\t\t\tnuc_thresholds[0] = (rateA / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[1] = ((rateA + rateC) / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[2] = ((rateA + rateC + rateG) / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[3] = fraction_of_max_rate;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (mm->Count() == 256)\n\t\t\t{\n\t\t\t\tge_type->mm_thresholds = (double *)malloc(256 * sizeof(double));\n\t\t\t\tif (!ge_type->mm_thresholds)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CacheNucleotideMatrices): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tfor (int trinuc = 0; trinuc < 64; ++trinuc)\n\t\t\t\t{\n\t\t\t\t\tdouble rateA = mm_data[trinuc];\n\t\t\t\t\tdouble rateC = mm_data[trinuc + 64];\n\t\t\t\t\tdouble rateG = mm_data[trinuc + 128];\n\t\t\t\t\tdouble rateT = mm_data[trinuc + 192];\n\t\t\t\t\tdouble total_rate = rateA + rateC + rateG + rateT;\n\t\t\t\t\tdouble fraction_of_max_rate = total_rate / max_nucleotide_mut_rate_;\n\t\t\t\t\tdouble *nuc_thresholds = ge_type->mm_thresholds + (size_t)trinuc * 4;\n\t\t\t\t\t\n\t\t\t\t\tnuc_thresholds[0] = (rateA / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[1] = ((rateA + rateC) / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[2] = ((rateA + rateC + rateG) / total_rate) * fraction_of_max_rate;\n\t\t\t\t\tnuc_thresholds[3] = fraction_of_max_rate;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CacheNucleotideMatrices): (internal error) unsupported mutation matrix size.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid Species::TabulateSLiMMemoryUsage_Species(SLiMMemoryUsage_Species *p_usage)\n{\n\tEIDOS_BZERO(p_usage, sizeof(SLiMMemoryUsage_Species));\n\t\n\t// Gather haplosomes in preparation for the work below\n\tstd::vector<Haplosome *> all_haplosomes_in_use, all_haplosomes_not_in_use;\n\tsize_t haplosome_pool_usage = 0, individual_pool_usage = 0;\n\tint haplosome_count_per_individual = HaplosomeCountPerIndividual();\n\t\n\tfor (auto iter : population_.subpops_)\n\t{\n\t\tSubpopulation &subpop = *iter.second;\n\t\t\n\t\tfor (Individual *ind : subpop.parent_individuals_)\n\t\t{\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\tall_haplosomes_in_use.push_back(haplosomes[haplosome_index]);\n\t\t}\n\t\t\n\t\tfor (Individual *ind : subpop.child_individuals_)\n\t\t{\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\tall_haplosomes_in_use.push_back(haplosomes[haplosome_index]);\n\t\t}\n\t\t\n\t\tfor (Individual *ind : subpop.nonWF_offspring_individuals_)\n\t\t{\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\tall_haplosomes_in_use.push_back(haplosomes[haplosome_index]);\n\t\t}\n\t\t\n\t}\n\t\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tall_haplosomes_not_in_use.insert(all_haplosomes_not_in_use.end(), chromosome->HaplosomesJunkyardNonnull().begin(), chromosome->HaplosomesJunkyardNonnull().end());\n\t\tall_haplosomes_not_in_use.insert(all_haplosomes_not_in_use.end(), chromosome->HaplosomesJunkyardNull().begin(), chromosome->HaplosomesJunkyardNull().end());\n\t}\n\t\n\thaplosome_pool_usage = species_haplosome_pool_.MemoryUsageForAllNodes();\n\tindividual_pool_usage = species_individual_pool_.MemoryUsageForAllNodes();\n\t\n\t// Chromosome\n\t{\n\t\tp_usage->chromosomeObjects_count = chromosomes_.size();\n\t\tp_usage->chromosomeObjects = sizeof(Chromosome) * p_usage->chromosomeObjects_count;\n\t\tp_usage->chromosomeMutationRateMaps = 0;\n\t\tp_usage->chromosomeRecombinationRateMaps = 0;\n\t\tp_usage->chromosomeAncestralSequence = 0;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tp_usage->chromosomeMutationRateMaps += chromosome->MemoryUsageForMutationMaps();\n\t\t\tp_usage->chromosomeRecombinationRateMaps += chromosome->MemoryUsageForRecombinationMaps();\n\t\t\tp_usage->chromosomeAncestralSequence += chromosome->MemoryUsageForAncestralSequence();\n\t\t}\n\t}\n\t\n\t// Haplosome\n\t{\n\t\tp_usage->haplosomeObjects_count = all_haplosomes_in_use.size();\n\t\tp_usage->haplosomeObjects = sizeof(Haplosome) * p_usage->haplosomeObjects_count;\n\t\t\n\t\tfor (Haplosome *haplosome : all_haplosomes_in_use)\n\t\t\tp_usage->haplosomeExternalBuffers += haplosome->MemoryUsageForMutrunBuffers();\n\t\t\n\t\tp_usage->haplosomeUnusedPoolSpace = haplosome_pool_usage - p_usage->haplosomeObjects;\t// includes junkyard objects and unused space\n\t\t\n\t\tfor (Haplosome *haplosome : all_haplosomes_not_in_use)\n\t\t\tp_usage->haplosomeUnusedPoolBuffers += haplosome->MemoryUsageForMutrunBuffers();\n\t}\n\t\n\t// GenomicElement\n\t{\n\t\tp_usage->genomicElementObjects_count = 0;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\tp_usage->genomicElementObjects_count += chromosome->GenomicElementCount();\n\t\t\n\t\tp_usage->genomicElementObjects = sizeof(GenomicElement) * p_usage->genomicElementObjects_count;\n\t}\n\t\n\t// GenomicElementType\n\t{\n\t\tp_usage->genomicElementTypeObjects_count = genomic_element_types_.size();\n\t\tp_usage->genomicElementTypeObjects = sizeof(GenomicElementType) * p_usage->genomicElementTypeObjects_count;\n\t}\n\t\n\t// Individual\n\t{\n\t\tint64_t objectCount = 0;\n\t\t\n\t\tfor (auto iter : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation &subpop = *iter.second;\n\t\t\t\n\t\t\tobjectCount += subpop.parent_individuals_.size();\n\t\t\tobjectCount += subpop.child_individuals_.size();\n\t\t\tobjectCount += subpop.nonWF_offspring_individuals_.size();\n\t\t}\n\t\t\n\t\tp_usage->individualObjects_count = objectCount;\n\t\tp_usage->individualObjects = sizeof(Individual) * p_usage->individualObjects_count;\n\t\t\n\t\t// externally allocated haplosome buffers; don't count if the internal buffer (capacity 2) is in use\n\t\tif (haplosome_count_per_individual > 2)\n\t\t\tp_usage->individualHaplosomeVectors = p_usage->individualObjects_count * haplosome_count_per_individual * sizeof(Haplosome*);\n\t\t\n\t\t// individuals in the junkyard, awaiting reuse, including their haplosome buffers\n\t\tp_usage->individualJunkyardAndHaplosomes = sizeof(Individual) * population_.species_individuals_junkyard_.size();\n\t\tif (haplosome_count_per_individual > 2)\n\t\t\tp_usage->individualJunkyardAndHaplosomes = population_.species_individuals_junkyard_.size() * haplosome_count_per_individual * sizeof(Haplosome*);\n\t\t\n\t\t// unused pool space; this is memory for new individuals that has never been used, and has no haplosome buffers\n\t\tp_usage->individualUnusedPoolSpace = individual_pool_usage - p_usage->individualObjects;\n\t}\n\t\n\t// Mutation\n\t{\n\t\tint registry_size;\n\t\t\n\t\tpopulation_.MutationRegistry(&registry_size);\n\t\tp_usage->mutationObjects_count = (int64_t)registry_size;\n\t\tp_usage->mutationObjects = sizeof(Mutation) * registry_size;\n\t}\n\t\n\t// MutationRun\n\t{\n\t\t{\n\t\t\tint64_t mutrun_objectCount = 0;\n\t\t\tint64_t mutrun_externalBuffers = 0;\n\t\t\tint64_t mutrun_nonneutralCaches = 0;\n\t\t\t\n\t\t\t// each thread has its own inuse pool\n\t\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\t{\n\t\t\t\tfor (int threadnum = 0; threadnum < chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t\t\t{\n\t\t\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationRun *inuse_mutrun : mutrun_context.in_use_pool_)\n\t\t\t\t\t{\n\t\t\t\t\t\tmutrun_objectCount++;\n\t\t\t\t\t\tmutrun_externalBuffers += inuse_mutrun->MemoryUsageForMutationIndexBuffers();\n\t\t\t\t\t\tmutrun_nonneutralCaches += inuse_mutrun->MemoryUsageForNonneutralCaches();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tp_usage->mutationRunObjects_count = mutrun_objectCount;\n\t\t\tp_usage->mutationRunObjects = sizeof(MutationRun) * mutrun_objectCount;\n\t\t\t\n\t\t\tp_usage->mutationRunExternalBuffers = mutrun_externalBuffers;\n\t\t\tp_usage->mutationRunNonneutralCaches = mutrun_nonneutralCaches;\n\t\t}\n\t\t\n\t\t{\n\t\t\tint64_t mutrun_unusedCount = 0;\n\t\t\tint64_t mutrun_unusedBuffers = 0;\n\t\t\t\n\t\t\t// each thread has its own free pool\n\t\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\t{\n\t\t\t\tfor (int threadnum = 0; threadnum < chromosome->ChromosomeMutationRunContextCount(); ++threadnum)\n\t\t\t\t{\n\t\t\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(threadnum);\n\t\t\t\t\t\n\t\t\t\t\tfor (const MutationRun *free_mutrun : mutrun_context.freed_pool_)\n\t\t\t\t\t{\n\t\t\t\t\t\tmutrun_unusedCount++;\n\t\t\t\t\t\tmutrun_unusedBuffers += free_mutrun->MemoryUsageForMutationIndexBuffers();\n\t\t\t\t\t\tmutrun_unusedBuffers += free_mutrun->MemoryUsageForNonneutralCaches();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tp_usage->mutationRunUnusedPoolSpace = sizeof(MutationRun) * mutrun_unusedCount;\n\t\t\tp_usage->mutationRunExternalBuffers = mutrun_unusedBuffers;\n\t\t}\n\t}\n\t\n\t// MutationType\n\t{\n\t\tp_usage->mutationTypeObjects_count = mutation_types_.size();\n\t\tp_usage->mutationTypeObjects = sizeof(MutationType) * p_usage->mutationTypeObjects_count;\n\t}\n\t\n\t// Species (including the Population object)\n\t{\n\t\tp_usage->speciesObjects_count = 1;\n\t\tp_usage->speciesObjects = (sizeof(Species) - sizeof(Chromosome)) * p_usage->speciesObjects_count;\t// Chromosome is handled separately above\n\t\t\n\t\t// this now adds up usage across all table collections, avoiding overcounting of shared tables\n\t\tp_usage->speciesTreeSeqTables = 0;\n\t\tbool first = true;\n\t\t\n\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t{\n\t\t\tp_usage->speciesTreeSeqTables += MemoryUsageForTreeSeqInfo(tsinfo, /* p_count_shared_tables */ first);\n\t\t\tfirst = false;\n\t\t}\n\t}\n\t\n\t// Subpopulation\n\t{\n\t\tp_usage->subpopulationObjects_count = population_.subpops_.size();\n\t\tp_usage->subpopulationObjects = sizeof(Subpopulation) * p_usage->subpopulationObjects_count;\n\t\t\n\t\tfor (auto iter : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation &subpop = *iter.second;\n\t\t\t\n\t\t\tif (subpop.cached_parental_fitness_)\n\t\t\t\tp_usage->subpopulationFitnessCaches += subpop.cached_fitness_capacity_ * sizeof(double);\n\t\t\tif (subpop.cached_male_fitness_)\n\t\t\t\tp_usage->subpopulationFitnessCaches += subpop.cached_fitness_capacity_ * sizeof(double);\n\t\t\t\n\t\t\tp_usage->subpopulationParentTables += subpop.MemoryUsageForParentTables();\n\t\t\t\n\t\t\tfor (const auto &iter_map : subpop.spatial_maps_)\n\t\t\t{\n\t\t\t\tSpatialMap &map = *iter_map.second;\n\t\t\t\t\n\t\t\t\tif (map.values_)\n\t\t\t\t{\n\t\t\t\t\tif (map.spatiality_ == 1)\n\t\t\t\t\t\tp_usage->subpopulationSpatialMaps += map.grid_size_[0] * sizeof(double);\n\t\t\t\t\telse if (map.spatiality_ == 2)\n\t\t\t\t\t\tp_usage->subpopulationSpatialMaps += map.grid_size_[0] * map.grid_size_[1] * sizeof(double);\n\t\t\t\t\telse if (map.spatiality_ == 3)\n\t\t\t\t\t\tp_usage->subpopulationSpatialMaps += map.grid_size_[0] * map.grid_size_[1] * map.grid_size_[2] * sizeof(double);\n\t\t\t\t}\n\t\t\t\tif (map.red_components_)\n\t\t\t\t\tp_usage->subpopulationSpatialMaps += map.n_colors_ * sizeof(float) * 3;\n#if defined(SLIMGUI)\n\t\t\t\tif (map.display_buffer_)\n\t\t\t\t\tp_usage->subpopulationSpatialMapsDisplay += (size_t)map.buffer_width_ * (size_t)map.buffer_height_ * sizeof(uint8_t) * 3;\n\t\t\t\t\n\t\t\t\t// FIXME: the usage due to image_ should be added here\n#endif\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/*\n\t Subpopulation:\n\t \n\tgsl_ran_discrete_t *lookup_parent_ = nullptr;\t\t\t// OWNED POINTER: lookup table for drawing a parent based upon fitness\n\tgsl_ran_discrete_t *lookup_female_parent_ = nullptr;\t// OWNED POINTER: lookup table for drawing a female parent based upon fitness, SEX ONLY\n\tgsl_ran_discrete_t *lookup_male_parent_ = nullptr;\t\t// OWNED POINTER: lookup table for drawing a male parent based upon fitness, SEX ONLY\n\n\t */\n\t\n\t// Substitution\n\t{\n\t\tp_usage->substitutionObjects_count = population_.substitutions_.size();\n\t\tp_usage->substitutionObjects = sizeof(Substitution) * p_usage->substitutionObjects_count;\n\t}\n\t\n\t// missing: EidosCallSignature, EidosPropertySignature, EidosScript, EidosToken, function map, global strings and ids and maps, std::strings in various objects\n\t// that sort of overhead should be fairly constant, though, and should be dwarfed by the overhead of the objects above in bigger models\n\t\n\t// also missing: LogFile\n\t\n\tSumUpMemoryUsage_Species(*p_usage);\n}\n\nslim_popsize_t *Species::BorrowShuffleBuffer(slim_popsize_t p_buffer_size)\n{\n\tif (shuffle_buf_borrowed_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::BorrowShuffleBuffer): (internal error) shuffle buffer already borrowed.\" << EidosTerminate();\n\t\n#if DEBUG_SHUFFLE_BUFFER\n\t// guarantee allocation of a buffer, even with a requested size of 0, so we have a place to put our overrun barriers\n\tif ((p_buffer_size > shuffle_buf_capacity_) || !shuffle_buffer_)\n#else\n\tif (p_buffer_size > shuffle_buf_capacity_)\n#endif\n\t{\n\t\tif (shuffle_buffer_)\n\t\t\tfree(shuffle_buffer_);\n\t\tshuffle_buf_capacity_ = p_buffer_size * 2;\t\t// double capacity so we reallocate less often\n#if DEBUG_SHUFFLE_BUFFER\n\t\t// room for an extra value at the start and end\n\t\tshuffle_buffer_ = (slim_popsize_t *)malloc((shuffle_buf_capacity_ + 2) * sizeof(slim_popsize_t));\n#else\n\t\tshuffle_buffer_ = (slim_popsize_t *)malloc(shuffle_buf_capacity_ * sizeof(slim_popsize_t));\n#endif\n\t\tshuffle_buf_size_ = 0;\n\t\t\n\t\tif (!shuffle_buffer_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::BorrowShuffleBuffer): allocation failed (requested size \" << p_buffer_size << \" entries, allocation size \" << (shuffle_buf_capacity_ * sizeof(slim_popsize_t)) << \" bytes); you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t}\n\t\n#if DEBUG_SHUFFLE_BUFFER\n\t// put flag values in to detect an overrun\n\tslim_popsize_t *buffer_contents = shuffle_buffer_ + 1;\n\t\n\tshuffle_buffer_[0] = (slim_popsize_t)0xDEADD00D;\n\tshuffle_buffer_[p_buffer_size + 1] = (slim_popsize_t)0xDEADD00D;\n#else\n\tslim_popsize_t *buffer_contents = shuffle_buffer_;\n#endif\n\t\n\tif (shuffle_buf_is_enabled_)\n\t{\n\t\t// The shuffle buffer is enabled, so we need to reinitialize it with sequential values if it has\n\t\t// changed size (unnecessary if it has not changed size, since the values are just rearranged),\n\t\t// and then shuffle it into a new order.\n\t\t\n\t\tif (p_buffer_size != shuffle_buf_size_)\n\t\t{\n\t\t\tfor (slim_popsize_t i = 0; i < p_buffer_size; ++i)\n\t\t\t\tbuffer_contents[i] = i;\n\t\t\t\n\t\t\tshuffle_buf_size_ = p_buffer_size;\n\t\t}\n\t\t\n\t\tif (shuffle_buf_size_ > 0)\n\t\t{\n\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\tEidos_ran_shuffle_uint32(rng_32, buffer_contents, shuffle_buf_size_);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// The shuffle buffer is disabled, so we can assume that existing entries are already sequential,\n\t\t// and we only need to \"top off\" the buffer with new sequential values if it has grown.\n\t\tif (p_buffer_size > shuffle_buf_size_)\n\t\t{\n\t\t\tfor (slim_popsize_t i = shuffle_buf_size_; i < p_buffer_size; ++i)\n\t\t\t\tbuffer_contents[i] = i;\n\t\t\t\n\t\t\tshuffle_buf_size_ = p_buffer_size;\n\t\t}\n\t}\n\t\n#if DEBUG_SHUFFLE_BUFFER\n\t// check for correct setup of flag values; entries 1:shuffle_buf_size_ are used\n\tif (shuffle_buffer_[0] != (slim_popsize_t)0xDEADD00D)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::BorrowShuffleBuffer): (internal error) shuffle buffer overrun at start.\" << EidosTerminate();\n\tif (shuffle_buffer_[shuffle_buf_size_ + 1] != (slim_popsize_t)0xDEADD00D)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::BorrowShuffleBuffer): (internal error) shuffle buffer overrun at end.\" << EidosTerminate();\n#endif\n\t\n\tshuffle_buf_borrowed_ = true;\n\treturn buffer_contents;\n}\n\nvoid Species::ReturnShuffleBuffer(void)\n{\n\tif (!shuffle_buf_borrowed_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReturnShuffleBuffer): (internal error) shuffle buffer was not borrowed.\" << EidosTerminate();\n\t\n#if DEBUG_SHUFFLE_BUFFER\n\t// check for correct setup of flag values; entries 1:shuffle_buf_size_ are used\n\tif (shuffle_buffer_[0] != (slim_popsize_t)0xDEADD00D)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReturnShuffleBuffer): (internal error) shuffle buffer overrun at start.\" << EidosTerminate();\n\tif (shuffle_buffer_[shuffle_buf_size_ + 1] != (slim_popsize_t)0xDEADD00D)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReturnShuffleBuffer): (internal error) shuffle buffer overrun at end.\" << EidosTerminate();\n#endif\n\t\n\tshuffle_buf_borrowed_ = false;\n}\n\n#if (SLIMPROFILING == 1)\n// PROFILING\n#if SLIM_USE_NONNEUTRAL_CACHES\nvoid Species::CollectMutationProfileInfo(void)\n{\n\t// maintain our history of the nonneutral regime\n\tprofile_nonneutral_regime_history_.emplace_back(last_nonneutral_regime_);\n\t\n\t// track the maximum number of mutations in existence at one time\n\tint registry_size;\n\t\n\tpopulation_.MutationRegistry(&registry_size);\n\tprofile_max_mutation_index_ = std::max(profile_max_mutation_index_, (int64_t)registry_size);\n\t\n\t// tally per-chromosome information\n\tint64_t operation_id = MutationRun::GetNextOperationID();\n\t\n\tfor (Chromosome *chromosome : Chromosomes())\n\t{\n\t\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome->Index()];\n\t\tint last_haplosome_index = LastHaplosomeIndices()[chromosome->Index()];\n\t\t\n\t\t// maintain our history of the number of mutruns per haplosome\n\t\tchromosome->profile_mutcount_history_.emplace_back(chromosome->mutrun_count_);\n\t\t\n\t\t// tally up the number of mutation runs, mutation usage metrics, etc.\n\t\tfor (std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\tconst MutationRun **mutruns = haplosome->mutruns_;\n\t\t\t\t\tint32_t mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tchromosome->profile_mutrun_total_usage_ += mutrun_count;\n\t\t\t\t\t\n\t\t\t\t\tfor (int32_t mutrun_index = 0; mutrun_index < mutrun_count; ++mutrun_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = mutruns[mutrun_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutrun)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (mutrun->operation_id_ != operation_id)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tmutrun->operation_id_ = operation_id;\n\t\t\t\t\t\t\t\tchromosome->profile_unique_mutrun_total_++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// tally the total and nonneutral mutations\n\t\t\t\t\t\t\tmutrun->tally_nonneutral_mutations(&chromosome->profile_mutation_total_usage_,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   &chromosome->profile_nonneutral_mutation_total_,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   &chromosome->profile_mutrun_nonneutral_recache_total_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n#endif\n#endif\n\n\n//\n// TREE SEQUENCE RECORDING\n//\n#pragma mark -\n#pragma mark Tree sequence recording\n#pragma mark -\n\nvoid Species::AboutToSplitSubpop(void)\n{\n\t// see Population::AddSubpopulationSplit()\n\tcommunity_.tree_seq_tick_offset_ += 0.00001;\n}\n\nvoid Species::CopySharedTablesIn(tsk_table_collection_t &p_tables)\n{\n\t// This directly copies the shared tables (nodes, individuals, and populations) into the\n\t// table collection p_tables.  This means that p_tables will point to the same table\n\t// column buffers as the main table collection does, BUT will have its own separate row\n\t// counts for those buffers.  This is an extraordinarily dangerous state to be in; if\n\t// either table collection adds/removes rows from a shared table, the two collections\n\t// will get out of synch, and buffer overruns and other problems will soon follow.\n\t// As soon as possible, DisconnectCopiedSharedTables() should be called to undo this.\n#if DEBUG\n\tif (&p_tables == &treeseq_[0].tables_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CopySharedTablesIn): (internal error) trying to copy shared tables into the main table collection!\" << EidosTerminate();\n#endif\n\t\n\ttsk_table_collection_t &main_tables = treeseq_[0].tables_;\n\t\n\tp_tables.nodes = main_tables.nodes;\n\tp_tables.individuals = main_tables.individuals;\n\tp_tables.populations = main_tables.populations;\n}\n\nvoid Species::DisconnectCopiedSharedTables(tsk_table_collection_t &p_tables)\n{\n\t// This zeroes out copies of shared tables (nodes, individuals, and populations) set up\n\t// by CopySharedTablesIn().  Note that changes to shared column data will persist, but\n\t// changes to row counts will *not* persist; they get zeroed here.  Be careful!\n\t\n\t// The tskit example at https://github.com/tskit-dev/tskit/pull/2665/files only\n\t// disconnects at the end, in free_tables(), but that seems very dangerous; any\n\t// accidental use of a tskit API that modifies a copied table will make things\n\t// go out of sync.  Our design here means we have to copy in and then disconnect\n\t// around every operation that references the contents of a given table, but it seems\n\t// safer to me.\n#if DEBUG\n\tif (&p_tables == &treeseq_[0].tables_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::DisconnectCopiedSharedTables): (internal error) trying to disconnect the main table collection!\" << EidosTerminate();\n#endif\n\t\n\tEIDOS_BZERO(&p_tables.nodes, sizeof(p_tables.nodes));\n\tEIDOS_BZERO(&p_tables.individuals, sizeof(p_tables.individuals));\n\tEIDOS_BZERO(&p_tables.populations, sizeof(p_tables.populations));\n}\n\nvoid Species::handle_error(const std::string &msg, int err)\n{\n\tstd::cout << \"Error:\" << msg << \": \" << tsk_strerror(err) << std::endl;\n\tEIDOS_TERMINATION << msg << \": \" << tsk_strerror(err) << EidosTerminate();\n}\n\nvoid Species::ReorderIndividualTable(tsk_table_collection_t *p_tables, std::vector<int> p_individual_map, bool p_keep_unmapped)\n{\n\t// Modifies the tables in place so that individual number individual_map[k] becomes the k-th individual in the new tables.\n\t// Discard unmapped individuals unless p_keep_unmapped is true, in which case put them at the end.\n\tsize_t num_individuals = p_tables->individuals.num_rows;\n\tstd::vector<tsk_id_t> inverse_map(num_individuals, TSK_NULL);\n\t\n\tfor (tsk_id_t j = 0; (size_t)j < p_individual_map.size(); j++)\n\t\tinverse_map[p_individual_map[j]] = j;\n\t\n\t// If p_keep_unmapped is true, use the inverse table to add all unmapped individuals to the end of p_individual_map\n\tif (p_keep_unmapped)\n\t{\n\t\tfor (tsk_id_t j = 0; (size_t)j < inverse_map.size(); j++)\n\t\t{\n\t\t\tif (inverse_map[j] == TSK_NULL)\n\t\t\t{\n\t\t\t\tinverse_map[j] = (tsk_id_t)p_individual_map.size();\n\t\t\t\tp_individual_map.emplace_back(j);\n\t\t\t}\n\t\t}\n\t\tassert(p_individual_map.size() == p_tables->individuals.num_rows);\n\t}\n\t\n\t// Make a copy of p_tables->individuals, from which we will copy rows back to p_tables->individuals\n\ttsk_individual_table_t individuals_copy;\n\tint ret = tsk_individual_table_copy(&p_tables->individuals, &individuals_copy, 0);\n\tif (ret < 0) handle_error(\"reorder_individuals\", ret);\n\t\n\t// Clear p_tables->individuals and copy rows into it in the requested order\n\ttsk_individual_table_clear(&p_tables->individuals);\n\t\n\tfor (tsk_id_t k : p_individual_map)\n\t{\n\t\tassert((size_t) k < individuals_copy.num_rows);\n\t\t\n\t\tuint32_t flags = individuals_copy.flags[k];\n\t\tdouble *location = individuals_copy.location + individuals_copy.location_offset[k];\n\t\tsize_t location_length = individuals_copy.location_offset[k+1] - individuals_copy.location_offset[k];\n\t\tconst char *metadata = individuals_copy.metadata + individuals_copy.metadata_offset[k];\n\t\tsize_t metadata_length = individuals_copy.metadata_offset[k+1] - individuals_copy.metadata_offset[k];\n\t\t\n\t\tret = tsk_individual_table_add_row(&p_tables->individuals, flags, location, (tsk_size_t)location_length,\n                NULL, 0, // individual parents\n                metadata, (tsk_size_t)metadata_length);\n\t\tif (ret < 0) handle_error(\"tsk_individual_table_add_row\", ret);\n\t}\n\t\n\tassert(p_tables->individuals.num_rows == p_individual_map.size());\n\t\n\t// Free the contents of the individual table copy we made (but not the table itself, which is stack-allocated)\n\ttsk_individual_table_free(&individuals_copy);\n\t\n\t// Fix the individual indices in the nodes table to point to the new rows\n\tfor (size_t j = 0; j < p_tables->nodes.num_rows; j++)\n\t{\n\t\ttsk_id_t old_indiv = p_tables->nodes.individual[j];\n\t\t\n\t\tif (old_indiv >= 0)\n\t\t\tp_tables->nodes.individual[j] = inverse_map[old_indiv];\n\t}\n}\n\nvoid Species::AddParentsColumnForOutput(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash)\n{\n\t// Build a parents column in the individuals table for output, from the pedigree IDs in the metadata\n\t// We create the parents column and fill it with info.  Note that we always know the pedigree ID if a parent\n\t// existed, so a parent pedigree ID of -1 means \"there was no parent\", and should result in no parent table entry.\n\t// A parent pedigree ID that is not present in the individuals table translates to TSK_NULL, which means\n\t// \"this parent did exist, but was not put in the table, or was simplified away\".  We allocate two entries\n\t// per individual, which might be an overallocation but is unlikely to matter.\n\tsize_t num_rows = p_tables->individuals.num_rows;\n\tsize_t parents_buffer_size = num_rows * 2 * sizeof(tsk_id_t);\n\ttsk_id_t *parents_buffer = (tsk_id_t *)malloc(parents_buffer_size);\n\ttsk_size_t *parents_offset_buffer = (tsk_size_t *)malloc((p_tables->individuals.max_rows + 1) * sizeof(tsk_size_t));\t// +1 for the trailing length entry\n\t\n\tif (!parents_buffer || !parents_offset_buffer)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::AddParentsColumnForOutput): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttsk_id_t *parents_buffer_ptr = parents_buffer;\n\t\n\tfor (tsk_size_t individual_index = 0; individual_index < num_rows; individual_index++)\n\t{\n\t\ttsk_id_t tsk_individual = (tsk_id_t)individual_index;\n\t\tIndividualMetadataRec *metadata_rec = (IndividualMetadataRec *)(p_tables->individuals.metadata + p_tables->individuals.metadata_offset[tsk_individual]);\n\t\tslim_pedigreeid_t pedigree_p1 = metadata_rec->pedigree_p1_;\n\t\tslim_pedigreeid_t pedigree_p2 = metadata_rec->pedigree_p2_;\n\t\t\n\t\tparents_offset_buffer[individual_index] = parents_buffer_ptr - parents_buffer;\n\t\t\n\t\tif (pedigree_p1 != -1)\n\t\t{\n\t\t\tauto p1_iter = p_individuals_hash->find(pedigree_p1);\n\t\t\ttsk_id_t p1_tskid = (p1_iter == p_individuals_hash->end()) ? TSK_NULL : p1_iter->second;\n\t\t\t\n\t\t\t//std::cout << \"first parent pedigree ID \" << pedigree_p1 << \" is tskid \" << p1_tskid << std::endl;\n\t\t\t*(parents_buffer_ptr++) = p1_tskid;\n\t\t}\n\t\t\n\t\tif (pedigree_p2 != -1)\n\t\t{\n\t\t\tauto p2_iter = p_individuals_hash->find(pedigree_p2);\n\t\t\ttsk_id_t p2_tskid = (p2_iter == p_individuals_hash->end()) ? TSK_NULL : p2_iter->second;\n\t\t\t\n\t\t\t//std::cout << \"second parent pedigree ID \" << pedigree_p2 << \" is tskid \" << p2_tskid << std::endl;\n\t\t\t*(parents_buffer_ptr++) = p2_tskid;\n\t\t}\n\t}\n\t\n\tparents_offset_buffer[num_rows] = parents_buffer_ptr - parents_buffer;\n\t\n\t// Put the new parents buffers into the individuals table\n\tif (p_tables->individuals.parents)\n\t\tfree(p_tables->individuals.parents);\n\tp_tables->individuals.parents = parents_buffer;\n\t\n\tif (p_tables->individuals.parents_offset)\n\t\tfree(p_tables->individuals.parents_offset);\n\tp_tables->individuals.parents_offset = parents_offset_buffer;\n\t\n\tp_tables->individuals.parents_length = parents_buffer_ptr - parents_buffer;\n\tp_tables->individuals.max_parents_length = parents_buffer_size;\n}\n\nvoid Species::BuildTabledIndividualsHash(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash)\n{\n\t// Here we rebuild a hash table for fast lookup of individuals table rows.\n\t// The key is the pedigree ID, so we can look up tabled individuals quickly; the value\n\t// is the index of that pedigree ID in the list of tabled individuals.  This code\n\t// used to live in AddNewIndividualsToTable(), building a temporary table; now it can\n\t// rebuild a permanent table (tabled_individuals_hash_), or make a temporary table\n\t// for local use.\n\tp_individuals_hash->clear();\n\t\n\ttsk_size_t num_rows = p_tables->individuals.num_rows;\n\tchar *metadata_base = p_tables->individuals.metadata;\n\ttsk_size_t *metadata_offset = p_tables->individuals.metadata_offset;\n\t\n\tfor (tsk_size_t individual_index = 0; individual_index < num_rows; individual_index++)\n\t{\n\t\tIndividualMetadataRec *metadata_rec = (IndividualMetadataRec *)(metadata_base + metadata_offset[individual_index]);\n\t\tslim_pedigreeid_t pedigree_id = metadata_rec->pedigree_id_;\n\t\ttsk_id_t tsk_individual = (tsk_id_t)individual_index;\n\t\t\n\t\tp_individuals_hash->emplace(pedigree_id, tsk_individual);\n\t}\n}\n\nstruct edge_plus_time {\n\tdouble time;\n\ttsk_id_t parent, child;\n\tdouble left, right;\n};\n\n// This parallel sorter is basically a clone of _Eidos_ParallelQuicksort_ASCENDING() in eidos_sorting.inc\n// The only difference (and the only reason we can't use that code directly) is we want to inline our comparator\n#ifdef _OPENMP\nstatic void _Eidos_ParallelQuicksort_ASCENDING(edge_plus_time *values, int64_t lo, int64_t hi, int64_t fallthrough)\n{\n\tif (lo >= hi)\n\t\treturn;\n\t\n\tif (hi - lo + 1 <= fallthrough) {\n\t\t// fall through to sorting with std::sort() below our threshold size\n\t\tstd::sort(values + lo, values + hi + 1,\n\t\t\t[](const edge_plus_time &lhs, const edge_plus_time &rhs) {\n\t\t\t\tif (lhs.time == rhs.time) {\n\t\t\t\t\tif (lhs.parent == rhs.parent) {\n\t\t\t\t\t\tif (lhs.child == rhs.child) {\n\t\t\t\t\t\t\treturn lhs.left < rhs.left;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn lhs.child < rhs.child;\n\t\t\t\t\t}\n\t\t\t\t\treturn lhs.parent < rhs.parent;\n\t\t\t\t}\n\t\t\t\treturn lhs.time < rhs.time;\n\t\t\t});\n\t} else {\n\t\t// choose the middle of three pivots, in an attempt to avoid really bad pivots\n\t\tedge_plus_time &pivot1 = *(values + lo);\n\t\tedge_plus_time &pivot2 = *(values + hi);\n\t\tedge_plus_time &pivot3 = *(values + ((lo + hi) >> 1));\n\t\tedge_plus_time pivot;\n\t\t\n\t\t// we just use times to choose the middle pivot; pivots with the same time probably won't be very\n\t\t// different in their sorted position anyway, except pathological models that record vast numbers\n\t\t// of edges in very few ticks; for those, this will revert to random-ish pivot choice (not so bad?)\n\t\tif (pivot1.time > pivot2.time)\n\t\t{\n\t\t\tif (pivot2.time > pivot3.time)\t\tpivot = pivot2;\n\t\t\telse if (pivot1.time > pivot3.time)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\t\t\tpivot = pivot1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (pivot1.time > pivot3.time)\t\tpivot = pivot1;\n\t\t\telse if (pivot2.time > pivot3.time)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\t\t\tpivot = pivot2;\n\t\t}\n\t\t\n\t\t// note that std::partition is not guaranteed to leave the pivot value in position\n\t\t// we do a second partition to exclude all duplicate pivot values, which seems to be one standard strategy\n\t\t// this works particularly well when duplicate values are very common; it helps avoid O(n^2) performance\n\t\t// note the partition is not parallelized; that is apparently a difficult problem for parallel quicksort\n\t\tedge_plus_time *middle1 = std::partition(values + lo, values + hi + 1, [pivot](const edge_plus_time& em) {\n\t\t\t//return em < pivot;\n\t\t\tif (em.time == pivot.time) {\n\t\t\t\tif (em.parent == pivot.parent) {\n\t\t\t\t\tif (em.child == pivot.child) {\n\t\t\t\t\t\treturn em.left < pivot.left;\n\t\t\t\t\t}\n\t\t\t\t\treturn em.child < pivot.child;\n\t\t\t\t}\n\t\t\t\treturn em.parent < pivot.parent;\n\t\t\t}\n\t\t\treturn em.time < pivot.time;\n\t\t});\n\t\tedge_plus_time *middle2 = std::partition(middle1, values + hi + 1, [pivot](const edge_plus_time& em) {\n\t\t\t//return !(pivot < em);\n\t\t\tif (pivot.time == em.time) {\n\t\t\t\tif (pivot.parent == em.parent) {\n\t\t\t\t\tif (pivot.child == em.child) {\n\t\t\t\t\t\treturn !(pivot.left < em.left);\n\t\t\t\t\t}\n\t\t\t\t\treturn !(pivot.child < em.child);\n\t\t\t\t}\n\t\t\t\treturn !(pivot.parent < em.parent);\n\t\t\t}\n\t\t\treturn !(pivot.time < em.time);\n\t\t});\n\t\tint64_t mid1 = middle1 - values;\n\t\tint64_t mid2 = middle2 - values;\n\t\t#pragma omp task default(none) firstprivate(values, lo, mid1, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_ASCENDING(values, lo, mid1 - 1, fallthrough); }\t// Left branch\n\t\t#pragma omp task default(none) firstprivate(values, hi, mid2, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_ASCENDING(values, mid2, hi, fallthrough); }\t\t// Right branch\n\t}\n}\n#endif\n\nstatic int\nslim_sort_edges(tsk_table_sorter_t *sorter, tsk_size_t start)\n{\n\t// this is the same as slim_sort_edges_PARALLEL(), but the loops are not parallelized.\n\t// this is used for multi-chromosome models, since we then parallelize across chromosomes.\n\t// so this function can be run *inside* a parallel region, but does not make a parallel region.\n\t\n\tif (sorter->tables->edges.metadata_length != 0)\n\t\tthrow std::invalid_argument(\"the sorter does not currently handle edge metadata\");\n\tif (start != 0)\n\t\tthrow std::invalid_argument(\"the sorter requires start==0\");\n\t\n\tstd::size_t num_rows = static_cast<std::size_t>(sorter->tables->edges.num_rows);\n\t//std::cout << num_rows << \" edge table rows to be sorted\" << std::endl;\n\t\n\tedge_plus_time *temp_edge_data = (edge_plus_time *)malloc(num_rows * sizeof(edge_plus_time));\n\tif (!temp_edge_data)\n\t\tEIDOS_TERMINATION << \"ERROR (slim_sort_edges): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttsk_edge_table_t *edges = &sorter->tables->edges;\n\tdouble *node_times = sorter->tables->nodes.time;\n\t\n\t// pre-sort: assemble the temp_edge_data vector\n\tfor (tsk_size_t i = 0; i < num_rows; ++i)\n\t{\n\t\ttemp_edge_data[i] = edge_plus_time{ node_times[edges->parent[i]], edges->parent[i], edges->child[i], edges->left[i], edges->right[i] };\n\t}\n\t\n\t// sort with std::sort\n\tstd::sort(temp_edge_data, temp_edge_data + num_rows,\n\t\t\t  [](const edge_plus_time &lhs, const edge_plus_time &rhs) {\n\t\tif (lhs.time == rhs.time) {\n\t\t\tif (lhs.parent == rhs.parent) {\n\t\t\t\tif (lhs.child == rhs.child) {\n\t\t\t\t\treturn lhs.left < rhs.left;\n\t\t\t\t}\n\t\t\t\treturn lhs.child < rhs.child;\n\t\t\t}\n\t\t\treturn lhs.parent < rhs.parent;\n\t\t}\n\t\treturn lhs.time < rhs.time;\n\t});\n\t\n\t// post-sort: copy the sorted temp_edge_data vector back into the edge table\n\tfor (std::size_t i = 0; i < num_rows; ++i)\n\t{\n\t\tedges->left[i] = temp_edge_data[i].left;\n\t\tedges->right[i] = temp_edge_data[i].right;\n\t\tedges->parent[i] = temp_edge_data[i].parent;\n\t\tedges->child[i] = temp_edge_data[i].child;\n\t}\n\t\n\tfree(temp_edge_data);\n\t\n\treturn 0;\n}\n\n#ifdef _OPENMP\nstatic int\nslim_sort_edges_PARALLEL(tsk_table_sorter_t *sorter, tsk_size_t start)\n{\n\t// this is the same as slim_sort_edges(), but the loops are (potentially) parallelized.\n\t// this is used for single-chromosome models, to get some parallelization benefit.\n\t\n\tif (sorter->tables->edges.metadata_length != 0)\n\t\tthrow std::invalid_argument(\"the sorter does not currently handle edge metadata\");\n\tif (start != 0)\n\t\tthrow std::invalid_argument(\"the sorter requires start==0\");\n\t\n\tstd::size_t num_rows = static_cast<std::size_t>(sorter->tables->edges.num_rows);\n\t//std::cout << num_rows << \" edge table rows to be sorted\" << std::endl;\n\t\n\tedge_plus_time *temp_edge_data = (edge_plus_time *)malloc(num_rows * sizeof(edge_plus_time));\n\tif (!temp_edge_data)\n\t\tEIDOS_TERMINATION << \"ERROR (slim_sort_edges_PARALLEL): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttsk_edge_table_t *edges = &sorter->tables->edges;\n\tdouble *node_times = sorter->tables->nodes.time;\n\t\n\t// pre-sort: assemble the temp_edge_data vector\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SIMPLIFY_SORT_PRE);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SIMPLIFY_SORT_PRE);\n#pragma omp parallel for schedule(static) default(none) shared(num_rows, temp_edge_data, edges, node_times) if(num_rows >= EIDOS_OMPMIN_SIMPLIFY_SORT_PRE) num_threads(thread_count)\n\t\tfor (tsk_size_t i = 0; i < num_rows; ++i)\n\t\t{\n\t\t\ttemp_edge_data[i] = edge_plus_time{ node_times[edges->parent[i]], edges->parent[i], edges->child[i], edges->left[i], edges->right[i] };\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SIMPLIFY_SORT_PRE);\n\t}\n\t\n\t// sort with std::sort when not running parallel, or if the task is small;\n\t// sort in parallel for big tasks if we can; see Eidos_ParallelSort() which\n\t// this is patterned after, but we want the (faster) inlined comparator...\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SIMPLIFY_SORT);\n\t\t\n#ifdef _OPENMP\n\t\tif (num_rows >= EIDOS_OMPMIN_SIMPLIFY_SORT)\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SIMPLIFY_SORT);\n#pragma omp parallel default(none) shared(num_rows, temp_edge_data) num_threads(thread_count)\n\t\t\t{\n\t\t\t\t// We fall through to using std::sort when below a threshold interval size.\n\t\t\t\t// The larger the threshold, the less time we spend thrashing tasks on small\n\t\t\t\t// intervals, which is good; but it also sets a limit on how many threads we\n\t\t\t\t// we bring to bear on relatively small sorts, which is bad.  We try to\n\t\t\t\t// calculate the optimal fall-through heuristically here; basically we want\n\t\t\t\t// to subdivide with tasks enough that the workload is shared well, and then\n\t\t\t\t// do the rest of the work with std::sort().  The more threads there are,\n\t\t\t\t// the smaller we want to subdivide.\n\t\t\t\tint64_t fallthrough = num_rows / (EIDOS_FALLTHROUGH_FACTOR * omp_get_num_threads());\n\t\t\t\t\n\t\t\t\tif (fallthrough < 1000)\n\t\t\t\t\tfallthrough = 1000;\n\t\t\t\t\n#pragma omp single nowait\n\t\t\t\t{\n\t\t\t\t\t_Eidos_ParallelQuicksort_ASCENDING(temp_edge_data, 0, num_rows - 1, fallthrough);\n\t\t\t\t}\n\t\t\t} // End of parallel region\n\t\t\t\n\t\t\tgoto didParallelSort;\n\t\t}\n#endif\n\t\t\n\t\tstd::sort(temp_edge_data, temp_edge_data + num_rows,\n\t\t\t\t  [](const edge_plus_time &lhs, const edge_plus_time &rhs) {\n\t\t\tif (lhs.time == rhs.time) {\n\t\t\t\tif (lhs.parent == rhs.parent) {\n\t\t\t\t\tif (lhs.child == rhs.child) {\n\t\t\t\t\t\treturn lhs.left < rhs.left;\n\t\t\t\t\t}\n\t\t\t\t\treturn lhs.child < rhs.child;\n\t\t\t\t}\n\t\t\t\treturn lhs.parent < rhs.parent;\n\t\t\t}\n\t\t\treturn lhs.time < rhs.time;\n\t\t});\n\t\t\n#ifdef _OPENMP\n\t\t// If we did a parallel sort, we jump here to skip the single-threaded sort\n\tdidParallelSort:\n#endif\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SIMPLIFY_SORT);\n\t}\n\t\n\t// post-sort: copy the sorted temp_edge_data vector back into the edge table\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SIMPLIFY_SORT_POST);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SIMPLIFY_SORT_POST);\n#pragma omp parallel for schedule(static) default(none) shared(num_rows, temp_edge_data, edges) if(num_rows >= EIDOS_OMPMIN_SIMPLIFY_SORT_POST) num_threads(thread_count)\n\t\tfor (std::size_t i = 0; i < num_rows; ++i)\n\t\t{\n\t\t\tedges->left[i] = temp_edge_data[i].left;\n\t\t\tedges->right[i] = temp_edge_data[i].right;\n\t\t\tedges->parent[i] = temp_edge_data[i].parent;\n\t\t\tedges->child[i] = temp_edge_data[i].child;\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SIMPLIFY_SORT_POST);\n\t}\n\t\n\tfree(temp_edge_data);\n\t\n\treturn 0;\n}\n#endif\n\nvoid Species::_SimplifyTreeSequence(TreeSeqInfo &tsinfo, const std::vector<tsk_id_t> &samples)\n{\n\t// BEWARE!  This is an internal method, and should only be called from SimplifyAllTreeSequences()!\n\t// It assumes that a variety of things will be done by the caller, and those things are not optional!\n\t// With multiple chromosomes when running parallel, this will be called from inside a parallel region!\n\t\n\t// sort the table collection\n\t{\n\t\ttsk_flags_t flags = TSK_NO_CHECK_INTEGRITY;\n#if DEBUG\n\t\t// in DEBUG mode, we do a standard consistency check for tree-seq integrity after each simplify; unlike in\n\t\t// CheckTreeSeqIntegrity(), this does not need TSK_NO_CHECK_POPULATION_REFS since we have a valid population table\n\t\t// we don't need/want order checks for the tables, since we sort them here; if that doesn't do the right thing,\n\t\t// that would be a bug in tskit, and would be caught by their tests, presumably, so no point in wasting time on it...\n\t\tflags = 0;\n#endif\n\t\t\n#if 0\n\t\t// sort the tables using tsk_table_collection_sort() to get the default behavior\n\t\tint ret = tsk_table_collection_sort(&tsinfo.tables_, /* edge_start */ NULL, /* flags */ flags);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_sort\", ret);\n#else\n\t\t// sort the tables using our own custom edge sorter, for additional speed through inlining of the comparison function\n\t\t// see https://github.com/tskit-dev/tskit/pull/627, https://github.com/tskit-dev/tskit/pull/711\n\t\t// FIXME for additional speed we could perhaps be smart about only sorting the portions of the edge table\n\t\t// that need it, but the tricky thing is that all the old stuff has to be at the bottom of the table, not the top...\n\t\ttsk_table_sorter_t sorter;\n\t\tint ret = tsk_table_sorter_init(&sorter, &tsinfo.tables_, /* flags */ flags);\n\t\tif (ret != 0) handle_error(\"tsk_table_sorter_init\", ret);\n\t\t\n#ifdef _OPENMP\n\t\t// When running multithreaded, we can parallelize the sorting work.  We do so only for single-chromosome models,\n\t\t// however.  With multiple chromosomes we parallelize across chromosomes, allowing simplification in parallel too.\n\t\tif (chromosomes_.size() > 1)\n\t\t\tsorter.sort_edges = slim_sort_edges;\n\t\telse\n\t\t\tsorter.sort_edges = slim_sort_edges_PARALLEL;\n#else\n\t\tsorter.sort_edges = slim_sort_edges;\n#endif\t// _OPENMP\n\t\t\n\t\ttry {\n\t\t\tret = tsk_table_sorter_run(&sorter, NULL);\n\t\t} catch (std::exception &e) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_SimplifyTreeSequence): (internal error) exception raised during tsk_table_sorter_run(): \" << e.what() << \".\" << EidosTerminate();\n\t\t}\n\t\tif (ret != 0) handle_error(\"tsk_table_sorter_run\", ret);\n\t\t\n\t\ttsk_table_sorter_free(&sorter);\n\t\tif (ret != 0) handle_error(\"tsk_table_sorter_free\", ret);\n#endif\n\t}\n\t\n\t// remove redundant sites we added\n\t{\n\t\tint ret = tsk_table_collection_deduplicate_sites(&tsinfo.tables_, 0);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_deduplicate_sites\", ret);\n\t}\n\t\n\t// simplify\n\t{\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SIMPLIFY_CORE);\n\t\t\n\t\t// BCH 12/9/2024: Removing TSK_SIMPLIFY_FILTER_INDIVIDUALS here, because we now need to filter the individuals\n\t\t// table ourselves after simplifying all the tree sequences (perhaps in parallel); see SimplifyAllTreeSequences().\n\t\ttsk_flags_t flags = TSK_SIMPLIFY_FILTER_SITES | TSK_SIMPLIFY_KEEP_INPUT_ROOTS;\n\t\t\n\t\t// BCH 12/10/2024: This should still work, with our own node table filtering code.  As Jerome explains, \"simplify\n\t\t// will still keep the *edges* that are unary, and that's all that matters. The downstream filtering code you\n\t\t// have just looks to see what nodes have references, and filters out those that are not used in any edges.\"\n\t\t// BCH 3/13/2025: changing TSK_SIMPLIFY_KEEP_UNARY to TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS,\n\t\t// since it is the correct flag; see discussion in https://github.com/MesserLab/SLiM/issues/487\n\t\tif (!retain_coalescent_only_) flags |= TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS;\n\t\t\n\t\t// BCH 12/9/2024: These flags are added for multichromosome support; we want to simplify all the tree sequences\n\t\t// (perhaps in parallel), without touching the node table at all, and then we clean up the node table afterwards.\n\t\tflags |= TSK_SIMPLIFY_NO_FILTER_NODES | TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS;\n\t\t\n\t\tint ret = tsk_table_collection_simplify(&tsinfo.tables_, samples.data(), (tsk_size_t)samples.size(), flags, NULL);\n\t\tif (ret != 0) handle_error(\"tsk_table_collection_simplify\", ret);\n\t\t\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SIMPLIFY_CORE);\n\t}\n\t\n\t// note that we leave things in a partially completed state; the nodes and individuals tables still\n\t// need to be filtered!  that is the responsibility of the caller -- i.e., SimplifyAllTreeSequences().\n}\n\nvoid Species::SimplifyAllTreeSequences(void)\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::SimplifyAllTreeSequences): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// if we have no recorded nodes, there is nothing to simplify; note that the nodes table is shared\n\tif (treeseq_[0].tables_.nodes.num_rows == 0)\n\t\treturn;\n\t\n\tstd::vector<tsk_id_t> samples;\n\t\n\t// BCH 7/27/2019: We now build a hash table containing all of the entries of remembered_nodes_,\n\t// so that the find() operations in the loop below can be done in constant time instead of O(N) time.\n\t// We need to be able to find out the index of an entry, in remembered_nodes_, once we have found it;\n\t// that is what the mapped value provides, whereas the key value is the tsk_id_t we need to find below.\n\t// We do all this inside a block so the map gets deallocated as soon as possible, to minimize footprint.\n\t// BCH 12/9/2024: The point of all this kerfuffle with the lookup table is that an extant individual\n\t// might also be a remembered individual, and we don't want to put it into the samples vector twice,\n\t// I think; otherwise we could just throw the remembered nodes and extant individuals into `samples`\n\t// with no lookup table complication.\n\t{\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\trobin_hood::unordered_flat_map<tsk_id_t, uint32_t> remembered_nodes_lookup;\n\t\t//typedef robin_hood::pair<tsk_id_t, uint32_t> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\tstd::unordered_map<tsk_id_t, uint32_t> remembered_nodes_lookup;\n\t\t//typedef std::pair<tsk_id_t, uint32_t> MAP_PAIR;\n#endif\n\t\t\n\t\t// the remembered_nodes_ come first in the list of samples\n\t\tuint32_t index = 0;\n\t\t\n\t\tfor (tsk_id_t sample_id : remembered_nodes_)\n\t\t{\n\t\t\tsamples.emplace_back(sample_id);\n\t\t\tremembered_nodes_lookup.emplace(sample_id, index);\n\t\t\tindex++;\n\t\t}\n\t\t\n\t\t// and then come all the nodes of the extant individuals\n\t\tfor (auto subpop_iter : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_iter.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\t// all the haplosomes for an individual share the same two tskit node ids (shared node table)\n\t\t\t\t// since both nodes for an individual are always remembered together, we only need to do\n\t\t\t\t// one hash table lookup to determine whether this individual's haplosomes are remembered\n\t\t\t\ttsk_id_t tsk_node_id_base = ind->TskitNodeIdBase();\n\t\t\t\t\n\t\t\t\tauto iter = remembered_nodes_lookup.find(tsk_node_id_base);\n\t\t\t\tbool not_remembered = (iter == remembered_nodes_lookup.end());\n\t\t\t\t\n\t\t\t\tif (not_remembered)\n\t\t\t\t{\n\t\t\t\t\tsamples.emplace_back(tsk_node_id_base);\n\t\t\t\t\tsamples.emplace_back(tsk_node_id_base + 1);\n\t\t\t\t}\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// check that both of the individual's haplosomes are (or are not) remembered together\n\t\t\t\tauto iter_2 = remembered_nodes_lookup.find(tsk_node_id_base + 1);\n\t\t\t\tbool not_remembered_2 = (iter_2 == remembered_nodes_lookup.end());\n\t\t\t\t\n\t\t\t\tif (not_remembered != not_remembered_2)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::SimplifyAllTreeSequences): one node remembered, one node not!.\" << EidosTerminate(nullptr);\n#endif\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// the tables need to have a population table to be able to sort it; we make this in index 0's table\n\t// collection, and the other table collections will share it temporarily using CopySharedTablesIn()\n\ttsk_table_collection_t &main_tables = treeseq_[0].tables_;\n\t\n\tWritePopulationTable(&main_tables);\n\t\n\t// simplify all of the tree sequences\n\t// FIXME MULTICHROM: parallelize simplification here!\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\tTreeSeqInfo &chromosome_tsinfo = treeseq_[chromosome_index];\n\t\ttsk_table_collection_t &chromosome_tables = chromosome_tsinfo.tables_;\n\t\t\n\t\t// swap in the shared tables from the main tree sequence; we need them for simplify to work, but\n\t\t// simplify should not touch any of them, so it should be safe to simplify using them directly\n\t\tif (chromosome_index > 0)\n\t\t\tCopySharedTablesIn(chromosome_tables);\n\t\t\n\t\t// simplify\n\t\t_SimplifyTreeSequence(chromosome_tsinfo, samples);\n\t\t\n\t\t// swap out the shared tables immediately after; the filtering code below does not need the shared tables\n\t\tif (chromosome_index > 0)\n\t\t\tDisconnectCopiedSharedTables(chromosome_tables);\n\t}\n\t\n\t// the node table needs to be filtered now; we turned that off for simplification, so it could be parallelized.\n\t// this code is copied from https://github.com/tskit-dev/tskit/pull/2665/files (multichrom_wright_fisher.c)\n\tconst tsk_size_t num_nodes = main_tables.nodes.num_rows;\n\t\n\tif (num_nodes > 0)\n\t{\n\t\ttsk_size_t sample_count = (tsk_size_t)samples.size();\n\t\tint ret;\n\t\ttsk_bool_t *keep_nodes = (tsk_bool_t *)calloc(num_nodes, sizeof(tsk_bool_t));\t// note: cleared by calloc\n\t\ttsk_id_t *node_id_map = (tsk_id_t *)malloc(num_nodes * sizeof(tsk_id_t));\n\t\t\n\t\tif (!keep_nodes || !node_id_map)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::SimplifyAllTreeSequences): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// mark the nodes we want to keep: samples (including remembered nodes), plus all nodes referenced by edges\n\t\tfor (tsk_size_t j = 0; j < sample_count; j++)\n\t\t\tkeep_nodes[samples[j]] = true;\n\n\t\t// update the 'sample' flags on the nodes (which simplify didn't update because we used the NO_FILTER_NODES flag)\n\t\tfor (tsk_size_t j = 0; j < num_nodes; j++)\n\t\t\tmain_tables.nodes.flags[j] &= (~TSK_NODE_IS_SAMPLE);\n\t\t\n\t\tfor (tsk_size_t j = 0; j < sample_count; j++)\n\t\t\tmain_tables.nodes.flags[samples[j]] |= TSK_NODE_IS_SAMPLE;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\tTreeSeqInfo &chromosome_tsinfo = treeseq_[chromosome_index];\n\t\t\ttsk_table_collection_t &chromosome_tables = chromosome_tsinfo.tables_;\n\t\t\ttsk_id_t *edges_child = chromosome_tables.edges.child;\n\t\t\ttsk_id_t *edges_parent = chromosome_tables.edges.parent;\n\t\t\ttsk_size_t edges_num_rows = chromosome_tables.edges.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t k = 0; k < edges_num_rows; k++) {\n\t\t\t\tkeep_nodes[edges_child[k]] = true;\n\t\t\t\tkeep_nodes[edges_parent[k]] = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// tskit does the work for us and provides an index map\n\t\tret = tsk_node_table_keep_rows(&main_tables.nodes, keep_nodes, 0, node_id_map);\n\t\tif (ret < 0) handle_error(\"tsk_node_table_keep_rows\", ret);\n\t\t\n\t\t// remap node references\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\t\tTreeSeqInfo &chromosome_tsinfo = treeseq_[chromosome_index];\n\t\t\ttsk_table_collection_t &chromosome_tables = chromosome_tsinfo.tables_;\n\t\t\t\n\t\t\t// remap in the edges table\n\t\t\ttsk_id_t *edges_child = chromosome_tables.edges.child;\n\t\t\ttsk_id_t *edges_parent = chromosome_tables.edges.parent;\n\t\t\ttsk_size_t edges_num_rows = chromosome_tables.edges.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t k = 0; k < edges_num_rows; k++) {\n\t\t\t\tedges_child[k] = node_id_map[edges_child[k]];\n\t\t\t\tedges_parent[k] = node_id_map[edges_parent[k]];\n\t\t\t}\n\t\t\t\n\t\t\t// remap in the mutations table also; Jerome's example didn't have mutations so it didn't do this\n\t\t\ttsk_id_t *mutations_node = chromosome_tables.mutations.node;\n\t\t\ttsk_size_t mutations_num_rows = chromosome_tables.mutations.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t k = 0; k < mutations_num_rows; k++) {\n\t\t\t\ttsk_id_t remapped_id = node_id_map[mutations_node[k]];\n\t\t\t\t\n\t\t\t\t// Peter says: You might also think we need to loop through the mutation table to add nodes that are\n\t\t\t\t// referred to there to keep_nodes, but I don't think that's true - we should be able to assert\n\t\t\t\t// node_id_map[mutations_node[k]] >= 0. (it'll be -1 if the node has been removed).  So, doing that.\n\t\t\t\tassert(remapped_id >= 0);\n\t\t\t\t\n\t\t\t\tmutations_node[k] = remapped_id;\n\t\t\t}\n\t\t\t\n#if DEBUG\n\t\t\t// BCH 2/25/2025: We need to swap in the shared tables around the integrity check\n\t\t\tif (chromosome_index > 0)\n\t\t\t\tCopySharedTablesIn(chromosome_tables);\n\t\t\t\n\t\t\tret = tsk_table_collection_check_integrity(&chromosome_tables, 0);\n\t\t\tif (ret < 0) handle_error(\"SimplifyAllTreeSequences() tsk_table_collection_check_integrity after node remapping\", ret);\n\t\t\t\n\t\t\tif (chromosome_index > 0)\n\t\t\t\tDisconnectCopiedSharedTables(chromosome_tables);\n#endif\n\t\t}\n\t\t\n\t\t// update map of remembered_nodes_; with a single chromosome and a standard simplify,\n\t\t// they would now be the first n entries in the node table (and we used to assume that),\n\t\t// but now that is not guaranteed, and we need to remap them using node_id_map\n\t\tfor (tsk_id_t j = 0; j < (tsk_id_t)remembered_nodes_.size(); j++)\n\t\t\tremembered_nodes_[j] = node_id_map[samples[j]];\n\t\t\n\t\t// and update the tskit node id base for all extant individuals, similarly\n\t\tfor (auto subpop_iter : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_iter.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\t// all the haplosomes for an individual share the same two tskit node ids (shared node table)\n\t\t\t\t// we thus need to just remap the base id, and the second id should always remap with it\n\t\t\t\ttsk_id_t tsk_node_id_base = ind->TskitNodeIdBase();\n\t\t\t\ttsk_id_t remapped_base = node_id_map[tsk_node_id_base];\n\t\t\t\t\n\t\t\t\tind->SetTskitNodeIdBase(remapped_base);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// check that the second id did remap alongside the first id\n\t\t\t\tif (node_id_map[tsk_node_id_base + 1] != remapped_base + 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::SimplifyAllTreeSequences): node table filtering did not preserve order!\" << EidosTerminate(nullptr);\n#endif\n\t\t\t}\n\t\t}\n\t\t\n\t\tfree(keep_nodes);\n\t\tfree(node_id_map);\n\t}\n\t\n\t// the individual table needs to be filtered now; we no longer pass TSK_SIMPLIFY_FILTER_INDIVIDUALS for simplification,\n\t// so it could be parallelized.  The code here is based on the node table filtering above, mutatis mutandis\n\tconst tsk_size_t num_individuals = main_tables.individuals.num_rows;\n\t\n\tif (num_individuals > 0)\n\t{\n\t\tint ret;\n\t\ttsk_bool_t *keep_individuals = (tsk_bool_t *)calloc(num_individuals, sizeof(tsk_bool_t));\t// note: cleared by calloc\n\t\ttsk_id_t *individual_id_map = (tsk_id_t *)malloc(num_individuals * sizeof(tsk_id_t));\n\t\t\n\t\tif (!keep_individuals || !individual_id_map)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::SimplifyAllTreeSequences): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// mark the individuals we want to keep: all individuals referenced by nodes; note that the node table is shared,\n\t\t// so we only need to loop through that one shared node table that is kept by the main table collection\n\t\t{\n\t\t\ttsk_id_t *nodes_individual = main_tables.nodes.individual;\n\t\t\ttsk_size_t nodes_num_rows = main_tables.nodes.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t k = 0; k < nodes_num_rows; k++) {\n\t\t\t\ttsk_id_t individual_index = nodes_individual[k];\n\t\t\t\t\n\t\t\t\tif (individual_index != TSK_NULL)\n\t\t\t\t\tkeep_individuals[individual_index] = true;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// tskit does the work for us and provides an index map\n\t\tret = tsk_individual_table_keep_rows(&main_tables.individuals, keep_individuals, 0, individual_id_map);\n\t\tif (ret < 0) handle_error(\"tsk_individual_table_keep_rows\", ret);\n\t\t\n\t\t// remap individual references; again, this is a shared table so we only need to modify it for the main tables\n\t\t{\n\t\t\ttsk_id_t *nodes_individual = main_tables.nodes.individual;\n\t\t\ttsk_size_t nodes_num_rows = main_tables.nodes.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t k = 0; k < nodes_num_rows; k++) {\n\t\t\t\ttsk_id_t individual_index = nodes_individual[k];\n\t\t\t\t\n\t\t\t\tif (individual_index != TSK_NULL)\n\t\t\t\t\tnodes_individual[k] = individual_id_map[individual_index];\n\t\t\t}\n\t\t\t\n#if DEBUG\n\t\t\t// BCH 2/25/2025: We don't need to swap in the shared tables, because this call is only on main_tables\n\t\t\tret = tsk_table_collection_check_integrity(&main_tables, 0);\n\t\t\tif (ret < 0) handle_error(\"SimplifyAllTreeSequences() tsk_table_collection_check_integrity after individual remapping\", ret);\n#endif\n\t\t}\n\t\t\n\t\tfree(keep_individuals);\n\t\tfree(individual_id_map);\n\t\t\n\t\t// remake our hash table of pedigree ids to tsk_ids, since we have reordered the (shared) individuals table\n\t\tBuildTabledIndividualsHash(&main_tables, &tabled_individuals_hash_);\n\t}\n\t\n\t// note that simplify does not mess with the population table, at least with the flags we pass it,\n\t// so we don't need to filter it as we filtered the node and individual tables above\n\t\n\t// reset current position, used to rewind individuals that are rejected by modifyChild()\n\tRecordTablePosition();\n\t\n\t// and reset our elapsed time since last simplification, for auto-simplification\n\tsimplify_elapsed_ = 0;\n\t\n\t// as a side effect of simplification, update a \"model has coalesced\" flag that the user can consult, if requested\n\t// this could potentially be parallelized, but it's kind of a fringe feature, and not that slow...\n\tif (running_coalescence_checks_)\n\t{\n\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t{\n\t\t\t// BCH 2/25/2025: Copy shared tables in across the coalescence check\n\t\t\tif (tsinfo.chromosome_index_ != 0)\n\t\t\t\tCopySharedTablesIn(tsinfo.tables_);\n\t\t\t\n\t\t\tCheckCoalescenceAfterSimplification(tsinfo);\n\t\t\t\n\t\t\tif (tsinfo.chromosome_index_ != 0)\n\t\t\t\tDisconnectCopiedSharedTables(tsinfo.tables_);\n\t\t}\n\t}\n}\n\nvoid Species::CheckCoalescenceAfterSimplification(TreeSeqInfo &tsinfo)\n{\n#if DEBUG\n\tif (!recording_tree_ || !running_coalescence_checks_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CheckCoalescenceAfterSimplification): (internal error) coalescence check called with recording or checking off.\" << EidosTerminate();\n#endif\n\t\n\t// Note that this method assumes that tsinfo has had the shared tables copied in!\n\t\n\t// Copy the table collection, which will (if it is not the main table collection) have empty tables for\n\t// the shared node, individual, and population tables.  We copy *first*, because we don't want to make\n\t// a copy of the shared tables, we just want to share them at the pointer level.  (Jerome said at one\n\t// point that this copy is unnecessary since tsk_table_collection_build_index() does not modify the core\n\t// information in the table collection, but just adds some separate indices.  However, we also need to\n\t// add a population table, so really it is best to make a copy I think.)\n\ttsk_table_collection_t tables_copy;\n\tint ret;\n\t\n\tret = tsk_table_collection_copy(&tsinfo.tables_, &tables_copy, 0);\n\tif (ret < 0) handle_error(\"tsk_table_collection_copy\", ret);\n\t\n\t// If tsinfo is not the main table collection (which has the shared tables), copy the shared tables in now.\n\t// If it is the main table collection, it now has a deep copy of the population table, so it is fine.\n\tif (tsinfo.chromosome_index_ > 0)\n\t{\n\t\tCopySharedTablesIn(tables_copy);\n\t\t\n\t\t// Now we have a pointer-level copy of the main table collection's population table; if we modify it,\n\t\t// which we need to do, we would actually modify the original table in the main table collection,\n\t\t// which we don't want.  So now we make a deep copy of it that we can modify safely.  We own that\n\t\t// deep copy, and will free it at the end.\n\t\ttsk_population_table_t deep_copy_pop_table;\n\t\t\n\t\tret = tsk_population_table_copy(&tables_copy.populations, &deep_copy_pop_table, 0);\n\t\tif (ret < 0) handle_error(\"tsk_population_table_copy\", ret);\n\t\t\n\t\ttables_copy.populations = deep_copy_pop_table;\t\t// overwrite with the copy\n\t}\n\t\n\t// Our tables copy needs to have a population table now, since this is required to build a tree sequence.\n\t// We could build this once and reuse it across all the calls to this method for different chromosomes,\n\t// but I think's probably not worth the trouble; the overhead should be small.\n\tWritePopulationTable(&tables_copy);\n\t\n\t// Build an index (which does not modify the main tables) and make a tree sequence.\n\tret = tsk_table_collection_build_index(&tables_copy, 0);\n\tif (ret < 0) handle_error(\"tsk_table_collection_build_index\", ret);\n\t\n\ttsk_treeseq_t ts;\n\t\n\tret = tsk_treeseq_init(&ts, &tables_copy, 0);\n\tif (ret < 0) handle_error(\"tsk_treeseq_init\", ret);\n\t\n\t// Collect a vector of all extant haplosome node IDs belonging to the chromosome that tsinfo records\n\tint first_haplosome_index = FirstHaplosomeIndices()[tsinfo.chromosome_index_];\n\tint last_haplosome_index = LastHaplosomeIndices()[tsinfo.chromosome_index_];\n\tstd::vector<tsk_id_t> all_extant_nodes;\n\t\n\tfor (auto subpop_iter : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_iter.second;\n\t\t\n\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t{\n\t\t\t// all the haplosomes for an individual share the same two tskit node ids (shared node table)\n\t\t\t// we only want to trace back from haplosomes that are used by the focal chromosome, however;\n\t\t\t// and only from haplosomes that are non-null (a test which was missing before, a bug I think)\n\t\t\ttsk_id_t tsk_node_id_base = ind->TskitNodeIdBase();\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t{\n\t\t\t\t\t// the tskit node id for a haplosome is the base ID from the individual, plus 0 or 1\n\t\t\t\t\tall_extant_nodes.emplace_back(tsk_node_id_base + haplosome->chromosome_subposition_);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tint64_t extant_node_count = (int64_t)all_extant_nodes.size();\n\t\n\t// Iterate through the trees to check coalescence; this is a bit tricky because of keeping first-gen nodes and nodes\n\t// in remembered individuals.  We use the sparse tree's \"tracked samples\" feature, tracking extant individuals\n\t// only, to find out whether all extant individuals are under a single root (coalesced), or under multiple roots\n\t// (not coalesced).  Doing this requires a scan through all the roots at each site, which is very slow if we have\n\t// indeed coalesced, but if we are far from coalescence we will usually be able to determine that in the scan of the\n\t// first tree (because every site will probably be uncoalesced), which seems like the right performance trade-off.\n\ttsk_tree_t t;\n\tbool fully_coalesced = true;\n\t\n\ttsk_tree_init(&t, &ts, 0);\n\tif (ret < 0) handle_error(\"tsk_tree_init\", ret);\n\t\n\ttsk_tree_set_tracked_samples(&t, extant_node_count, all_extant_nodes.data());\n\tif (ret < 0) handle_error(\"tsk_tree_set_tracked_samples\", ret);\n\t\n\tret = tsk_tree_first(&t);\n\tif (ret < 0) handle_error(\"tsk_tree_first\", ret);\n\t\n\tfor (; (ret == 1) && fully_coalesced; ret = tsk_tree_next(&t))\n\t{\n#if 0\n\t\t// If we didn't keep first-generation lineages, or remember haplosomes, >1 root would mean not coalesced\n\t\tif (tsk_tree_get_num_roots(&t) > 1)\n\t\t{\n\t\t\tfully_coalesced = false;\n\t\t\tbreak;\n\t\t}\n#else\n\t\t// But we do have retained/remembered nodes in the tree, so we need to be smarter; nodes for the first gen\n\t\t// ancestors will always be present, giving >1 root in each tree even when we have coalesced, and the\n\t\t// remembered individuals may mean that more than one root node has children, too, even when we have\n\t\t// coalesced.  What we need to know is: how many roots are there that have >0 *extant* children?  This\n\t\t// is what we use the tracked samples for; they are extant individuals.\n\t\tfor (tsk_id_t root = tsk_tree_get_left_root(&t); root != TSK_NULL; root = t.right_sib[root])\n\t\t{\n\t\t\tint64_t num_tracked = t.num_tracked_samples[root];\n\t\t\t\n\t\t\tif ((num_tracked > 0) && (num_tracked < extant_node_count))\n\t\t\t{\n\t\t\t\tfully_coalesced = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n#endif\n\t}\n\tif (ret < 0) handle_error(\"tsk_tree_next\", ret);\n\t\n\tret = tsk_tree_free(&t);\n\tif (ret < 0) handle_error(\"tsk_tree_free\", ret);\n\t\n\tret = tsk_treeseq_free(&ts);\n\tif (ret < 0) handle_error(\"tsk_treeseq_free\", ret);\n\t\n\tif (tsinfo.chromosome_index_ > 0)\n\t{\n\t\t// we made a new deep copy of the population table above, so we need to free it before disconnecting\n\t\tret = tsk_population_table_free(&tables_copy.populations);\n\t\tif (ret < 0) handle_error(\"tsk_population_table_free\", ret);\n\t\t\n\t\t// now we can disconnect, zeroing out the other shared tables that we made pointer-level copies of\n\t\tDisconnectCopiedSharedTables(tables_copy);\n\t}\n\t\n\tret = tsk_table_collection_free(&tables_copy);\n\tif (ret < 0) handle_error(\"tsk_table_collection_free\", ret);\n\t\n\t//std::cout << \"tick \" << community->Tick() << \": fully_coalesced == \" << (fully_coalesced ? \"TRUE\" : \"false\") << std::endl;\n\ttsinfo.last_coalescence_state_ = fully_coalesced;\n}\n\nbool Species::_SubpopulationIDInUse(slim_objectid_t p_subpop_id)\n{\n\t// Called by Community::SubpopulationIDInUse(); do not call directly!\n\t\n\t// This checks the tree-sequence population table, if there is one. We'll\n\t// assume that *any* metadata means we can't use the subpop, which means we\n\t// won't clobber any existing metadata, although there might be subpops\n\t// with metadata not put in by SLiM.\n\tif (RecordingTreeSequence() && treeseq_.size())\n\t{\n\t\t// We only need to consult the first (shared) populations table\n\t\ttsk_population_table_t &shared_populations_table = treeseq_[0].tables_.populations;\n\t\t\n\t\tif (p_subpop_id < (int)shared_populations_table.num_rows) {\n\t\t\tint ret;\n\t\t\ttsk_population_t row;\n\n\t\t\tret = tsk_population_table_get_row(&shared_populations_table, p_subpop_id, &row);\n\t\t\tif (ret != 0) handle_error(\"tsk_population_table_get_row\", ret);\n\t\t\tif (row.metadata_length > 0) {\n\t\t\t\t// Check the metadata is not \"null\". It would maybe be better\n\t\t\t\t// to parse the metadata, though.\n\t\t\t\tif ((row.metadata_length != 4) || (strncmp(row.metadata, \"null\", 4) != 0)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn false;\n}\n\nvoid Species::RecordTablePosition(void)\n{\n\t// keep the current position in each table collection for rewinding if a proposed child is rejected\n\t// note that for freed tables (because of table sharing), this will record/restore a position of 0\n\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\ttsk_table_collection_record_num_rows(&tsinfo.tables_, &tsinfo.table_position_);\n}\n\nvoid Species::AllocateTreeSequenceTables(void)\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::AllocateTreeSequenceTables): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\tif (tables_initialized_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::AllocateTreeSequenceTables): (internal error) tree sequence tables already initialized.\" << EidosTerminate();\n\t\n\t// Set up the table collections before loading a saved population or starting a simulation\n\t// We have one TreeSeqInfo struct for each chromosome, and allocate and initialize them all here\n\ttreeseq_.resize(chromosomes_.size());\n\t\n\tbool first = true;\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tslim_chromosome_index_t index = chromosome->Index();\n\t\tTreeSeqInfo &tsinfo = treeseq_[index];\n\t\t\n\t\t//INITIALIZE NODE AND EDGE TABLES.\n\t\tint ret = tsk_table_collection_init(&tsinfo.tables_, TSK_TC_NO_EDGE_METADATA);\n\t\tif (ret != 0) handle_error(\"AllocateTreeSequenceTables()\", ret);\n\t\t\n\t\tif (!first)\n\t\t{\n\t\t\t// the node, individual, and population tables are shared; only the first TreeSeqInfo\n\t\t\t// contains them at most times, and the tables are shared with the others when needed\n\t\t\t// attempting to access these freed tables will probably crash, beware\n\t\t\ttsk_node_table_free(&tsinfo.tables_.nodes);\n\t\t\ttsk_individual_table_free(&tsinfo.tables_.individuals);\n\t\t\ttsk_population_table_free(&tsinfo.tables_.populations);\n\t\t}\n\t\t\n\t\ttsinfo.tables_.sequence_length = (double)chromosome->last_position_ + 1;\n\t\ttsinfo.chromosome_index_ = chromosome->Index();\n\t\ttsinfo.last_coalescence_state_ = false;\n\t\t\n\t\tfirst = false;\n\t}\n\t\n\tRecordTablePosition();\n\ttables_initialized_ = true;\n}\n\nvoid Species::SetCurrentNewIndividual(__attribute__((unused))Individual *p_individual)\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::SetCurrentNewIndividual): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// This is called by code where new individuals are created\n\t\n\t// Remember the new individual being defined; we don't need this right now,\n\t// but it seems to keep coming back, so I've kept the code for it...\n\t//current_new_individual_ = p_individual;\n\t\n\t// Remember the current table position so we can return to it later in RetractNewIndividual()\n\tRecordTablePosition();\n\t\n\t// Record the usage of the next two node table entries for this individual, for (up to) two\n\t// haplosomes in each tree sequence.  Some chromosomes will involve only one haplosome, because\n\t// they are haploid; and sometimes null haplosomes will mean that fewer (or none) of these\n\t// node table entries will actually be used.  That's OK; we want to use the same node table\n\t// entries for a given individual in every tree sequences, so we (in general) have to reserve\n\t// two entries in any case, and tskit will ignore the ones we don't use.  Note that this work\n\t// used to be done in RecordNewHaplosome(), but it needs to be done just once for each new\n\t// individual, whereas RecordNewHaplosome() has to record each new haplosome created.\n\t\n\t// Add haplosome nodes; we mark all nodes with TSK_NODE_IS_SAMPLE here because we have full\n\t// genealogical information on all of them (until simplify, which clears TSK_NODE_IS_SAMPLE\n\t// from nodes that are not kept in the sample).\n\tdouble time = (double) -1 * (community_.tree_seq_tick_ + community_.tree_seq_tick_offset_);\t// see Population::AddSubpopulationSplit() regarding tree_seq_tick_offset_\n\ttsk_flags_t flags = TSK_NODE_IS_SAMPLE;\n\ttsk_node_table_t &shared_node_table = treeseq_[0].tables_.nodes;\n\t\n\t// Figure out the metadata to use, which is a version of the default metadata.  We patch in\n\t// the correct haplosome pedigree IDs, directly into the default metadata records, so\n\t// this code is not thread-safe!  The design is this way because the size of HaplosomeMetadataRec\n\t// is determined dynamically at runtime, depending on the number of chromosomes in the model.\n\t// (If we want this to run in parallel across chromosomes eventually, we could keep separate\n\t// copies of the default haplosome metadata for each chromosome, to make this thread-safe...)\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL();\n\tstatic_assert(sizeof(HaplosomeMetadataRec) == 9, \"HaplosomeMetadataRec has changed size; this code probably needs to be updated\");\n\tHaplosomeMetadataRec *metadata1, *metadata2;\n\t\n\tif (p_individual->sex_ == IndividualSex::kMale)\n\t{\n\t\t// this case covers only males\n\t\tmetadata1 = hap_metadata_1M_;\n\t\tmetadata2 = hap_metadata_2M_;\n\t}\n\telse\n\t{\n\t\t// this case covers both females and hermaphrodites\n\t\tmetadata1 = hap_metadata_1F_;\n\t\tmetadata2 = hap_metadata_2F_;\n\t}\n\t\n\tmetadata1->haplosome_id_ = p_individual->PedigreeID() * 2;\n\tmetadata2->haplosome_id_ = p_individual->PedigreeID() * 2 + 1;\n\t\n\t// Make the node table entries, with default metadata for now\n\ttsk_id_t nodeTSKID1 = tsk_node_table_add_row(&shared_node_table, flags, time,\n\t\t\t\t\t\t\t\t\t\t\t\t (tsk_id_t)p_individual->subpopulation_->subpopulation_id_,\n\t\t\t\t\t\t\t\t\t\t\t\t TSK_NULL, (char *)metadata1, (tsk_size_t)haplosome_metadata_size_);\n\tif (nodeTSKID1 < 0) handle_error(\"tsk_node_table_add_row\", nodeTSKID1);\n\t\n\ttsk_id_t nodeTSKID2 = tsk_node_table_add_row(&shared_node_table, flags, time,\n\t\t\t\t\t\t\t\t\t\t\t\t (tsk_id_t)p_individual->subpopulation_->subpopulation_id_,\n\t\t\t\t\t\t\t\t\t\t\t\t TSK_NULL, (char *)metadata2, (tsk_size_t)haplosome_metadata_size_);\n\tif (nodeTSKID2 < 0) handle_error(\"tsk_node_table_add_row\", nodeTSKID2);\n\t\n\t// The individual remembers the tskid of the first node (which is the same across all haplosomes\n\t// in 1st position).  For haplosomes in 2nd position, it is first_tsk_node_id + 1.\n\tp_individual->SetTskitNodeIdBase(nodeTSKID1);\n\t\n\t// The haplosome metadata is presently all zero.  FinalizeCurrentNewIndividual() will clean it up.\n}\n\nvoid Species::RetractNewIndividual()\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RetractNewIndividual): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// This is called when a new child, introduced by SetCurrentNewIndividual(), gets rejected by a modifyChild()\n\t// callback.  We will have logged recombination breakpoints and new mutations into our tables, and now want\n\t// to back those changes out by re-setting the active row index for the tables.\n\t\n\t// We presently don't use current_new_individual_ any more, but I've kept\n\t// around the code since it seems to keep coming back...\n\t//current_new_individual_ = nullptr;\n\t\n\tsize_t trees_count = treeseq_.size();\n\t\n\tif (trees_count > 0)\n\t{\n\t\tTreeSeqInfo &tsinfo_0 = treeseq_[0];\n\t\t\n\t\t// BCH 12/1/2025: The base table collection can restore its bookmarked position directly;\n\t\t// that will reset the bookmarked positions in all of the shared tables as well.\n\t\ttsk_table_collection_truncate(&tsinfo_0.tables_, &tsinfo_0.table_position_);\n\t\t\n\t\t// BCH 12/1/2025: In the multichrom case we need to protect against a segfault inside\n\t\t// tsk_table_collection_truncate() for the secondary table collections.  This is because\n\t\t// they have NULL for their various column pointers, and tsk_table_collection_truncate()\n\t\t// accesses index 0 of every offset column to get the offset for row 0.  (It is always\n\t\t// for row 0 in the shared tables because they are zeroed out; their num_rows was zero\n\t\t// in RecordTablePosition().)  See https://github.com/MesserLab/SLiM/issues/579 for details.\n\t\t// BEWARE: This code will need updating if new shared tables are added, or new columns\n\t\t// are added within the existing shared table.  Any offset column that is accessed in the\n\t\t// ..._truncate() functions for the shared tables needs to be protected here.\n\t\ttsk_size_t zero_value = 0;\n\t\ttsk_size_t *pointer_to_zero_value = &zero_value;\n\t\t\n\t\tfor (size_t trees_index = 1; trees_index < trees_count; ++trees_index)\n\t\t{\n\t\t\tTreeSeqInfo &tsinfo_i = treeseq_[trees_index];\n\t\t\t\n#if DEBUG\n\t\t\t// This protection scheme relies upon the bookmarked row being zero for shared tables;\n\t\t\t// only the zeroth element of each offset column is set up by the hack here.\n\t\t\tif ((tsinfo_i.table_position_.nodes != 0) ||\n\t\t\t\t(tsinfo_i.table_position_.individuals != 0) ||\n\t\t\t\t(tsinfo_i.table_position_.populations != 0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RetractNewIndividual): (internal error) tree sequence bookmark for a shared table in a secondary table collection is non-zero.\" << EidosTerminate();\n#endif\n\t\t\t\n\t\t\ttsinfo_i.tables_.nodes.metadata_offset = pointer_to_zero_value;\n\t\t\ttsinfo_i.tables_.individuals.location_offset = pointer_to_zero_value;\n\t\t\ttsinfo_i.tables_.individuals.parents_offset = pointer_to_zero_value;\n\t\t\ttsinfo_i.tables_.individuals.metadata_offset = pointer_to_zero_value;\n\t\t\ttsinfo_i.tables_.populations.metadata_offset = pointer_to_zero_value;\n\t\t\t\n\t\t\ttsk_table_collection_truncate(&tsinfo_i.tables_, &tsinfo_i.table_position_);\n\t\t\t\n\t\t\ttsinfo_i.tables_.nodes.metadata_offset = NULL;\n\t\t\ttsinfo_i.tables_.individuals.location_offset = NULL;\n\t\t\ttsinfo_i.tables_.individuals.parents_offset = NULL;\n\t\t\ttsinfo_i.tables_.individuals.metadata_offset = NULL;\n\t\t\ttsinfo_i.tables_.populations.metadata_offset = NULL;\n\t\t}\n\t}\n\t\n\t// The above code boils down to this, which was the old code before #579 came along.\n\t// It is the same apart from the complicated protection against segfaults:\n\t//\n\t//\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t//\t\ttsk_table_collection_truncate(&tsinfo.tables_, &tsinfo.table_position_);\n}\n\nvoid Species::RecordNewHaplosome(slim_position_t *p_breakpoints, int p_breakpoints_count, Haplosome *p_new_haplosome, \n\t\tconst Haplosome *p_initial_parental_haplosome, const Haplosome *p_second_parental_haplosome)\n{\n\t// This method records a new non-null haplosome; see also RecordNewHaplosome_NULL().\n\t\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n\t\n\tif (!p_new_haplosome)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) p_new_haplosome is nullptr.\" << EidosTerminate();\n\tif (p_new_haplosome->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) p_new_haplosome is a null haplosome.\" << EidosTerminate();\n#endif\n\t\n\tslim_chromosome_index_t chromosome_index = p_new_haplosome->chromosome_index_;\n\tChromosome &chromosome = *chromosomes_[chromosome_index];\n\tTreeSeqInfo &tsinfo = treeseq_[chromosome_index];\n\t\n\t// This records information about an individual in the edge table.  BCH 12/6/2024: Note that recording the\n\t// new node table entries is now done by SetCurrentNewIndividual().  That method determines the tskit node\n\t// ids for the two haplosome positions of the individual, as tsk_node_id_base_ (+ 1).\n\t\n\t// Note that the breakpoints vector provided may (or may not) contain a breakpoint, as the final breakpoint\n\t// in the vector, that is past the end of the chromosome.  This is for bookkeeping in the crossover-mutation\n\t// code and should be ignored, as the code below does.  The breakpoints vector may be nullptr (indicating no\n\t// recombination), but if it exists it will be sorted in ascending order.\n\n\t// if there is no parent then no need to record edges\n\tif (!p_initial_parental_haplosome && !p_second_parental_haplosome)\n\t\treturn;\n\t\n\tassert(p_initial_parental_haplosome);\t// this cannot be nullptr if p_second_parental_haplosome is non-null, so now it is guaranteed non-null\n\t\n\t// get the TSK IDs for all the haplosomes involved; they are the tsk_node_id_base_ of the owning\n\t// individual, plus 0 or 1 depending on whether they are the first or second haplosome for their\n\t// associated chromosome\n\ttsk_id_t offspringTSKID, haplosome1TSKID, haplosome2TSKID;\n\t\n\toffspringTSKID = p_new_haplosome->OwningIndividual()->TskitNodeIdBase() + p_new_haplosome->chromosome_subposition_;\n\thaplosome1TSKID = p_initial_parental_haplosome->OwningIndividual()->TskitNodeIdBase() + p_initial_parental_haplosome->chromosome_subposition_;\n\tif (!p_second_parental_haplosome)\n\t\thaplosome2TSKID = haplosome1TSKID;\n\telse\n\t\thaplosome2TSKID = p_second_parental_haplosome->OwningIndividual()->TskitNodeIdBase() + p_second_parental_haplosome->chromosome_subposition_;\n\t\n\t// fix possible excess past-the-end breakpoint\n\tif (p_breakpoints_count && (p_breakpoints[p_breakpoints_count - 1] > chromosome.last_position_))\n\t\tp_breakpoints_count--;\n\t\n\t// add an edge for each interval between breakpoints\n\tdouble left = 0.0;\n\tdouble right;\n\tbool polarity = true;\n\t\n\tfor (int i = 0; i < p_breakpoints_count; i++)\n\t{\n\t\tright = p_breakpoints[i];\n\t\t\n\t\ttsk_id_t parent = (tsk_id_t) (polarity ? haplosome1TSKID : haplosome2TSKID);\n\t\tpolarity = !polarity;\n\t\t\n\t\t// Sometimes the user might add a breakpoint at 0, to flip the initial copy strand, as in the meiotic\n\t\t// drive recipe.  If they do that, a left==right breakpoint might make it in to here.  That would be\n\t\t// a bug in the caller.  This has never been seen in the wild, so I'll make it DEBUG only.  In non-\n\t\t// DEBUG runs the tree sequence will fail to pass integrity checks, with TSK_ERR_BAD_EDGE_INTERVAL.\n#if DEBUG\n\t\tif (left >= right)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) a left==right breakpoint was passed to RecordNewHaplosome().\" << EidosTerminate();\n#endif\n\t\t\n\t\tint ret = tsk_edge_table_add_row(&tsinfo.tables_.edges, left, right, parent, offspringTSKID, NULL, 0);\n\t\tif (ret < 0) handle_error(\"tsk_edge_table_add_row\", ret);\n\t\t\n\t\tleft = right;\n\t}\n\t\n\tright = (double)chromosome.last_position_+1;\n\ttsk_id_t parent = (tsk_id_t) (polarity ? haplosome1TSKID : haplosome2TSKID);\n\tint ret = tsk_edge_table_add_row(&tsinfo.tables_.edges, left, right, parent, offspringTSKID, NULL, 0);\n\tif (ret < 0) handle_error(\"tsk_edge_table_add_row\", ret);\n}\n\nvoid Species::RecordNewHaplosome_NULL(Haplosome *p_new_haplosome)\n{\n\t// This method records a new null haplosome (no edges to record); see also RecordNewHaplosome().\n\t\n\t// BCH 12/10/2024: With the new metadata scheme for haplosome, we also need to fix the is_vacant_ metadata if\n\t// the new haplosome is a null haplosome *and* it belongs to a chromosome type where that is notable.  In\n\t// the present design, that can only be chromosome types \"A\" and \"H\"; the other chromosome types do not\n\t// allow deviation from the default null-haplosome configuration.\n\t\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome_NULL): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n\t\n\tif (!p_new_haplosome)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) p_new_haplosome is nullptr.\" << EidosTerminate();\n\tif (!p_new_haplosome->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewHaplosome): (internal error) p_new_haplosome is not a null haplosome.\" << EidosTerminate();\n#endif\n\t\n\t{\n\t\tslim_chromosome_index_t chromosome_index = p_new_haplosome->chromosome_index_;\n\t\tChromosome &chromosome = *chromosomes_[chromosome_index];\n\t\tChromosomeType chromosome_type = chromosome.Type();\n\t\t\n\t\tif ((chromosome_type == ChromosomeType::kA_DiploidAutosome) || (chromosome_type == ChromosomeType::kH_HaploidAutosome))\n\t\t{\n\t\t\t// it is null and that was unexpected; we need to flip the corresponding is_vacant_ bit\n\t\t\t// each chromosome has two node table entries; entry 1 is for haplosome 1, entry 2 is\n\t\t\t// for haplosome 2, so there is only one bit per chromosome in a given is_vacant_ vector\n\t\t\ttsk_id_t offspringTSKID = p_new_haplosome->OwningIndividual()->TskitNodeIdBase() + p_new_haplosome->chromosome_subposition_;\n\t\t\ttsk_node_table_t &shared_node_table = treeseq_[0].tables_.nodes;\n\t\t\tHaplosomeMetadataRec *metadata = (HaplosomeMetadataRec *)(shared_node_table.metadata + shared_node_table.metadata_offset[offspringTSKID]);\n\t\t\tuint8_t *metadata_is_vacant = metadata->is_vacant_;\n\t\t\tint byte_index = chromosome_index / 8;\n\t\t\tint bit_shift = chromosome_index % 8;\n\t\t\t\n\t\t\tmetadata_is_vacant[byte_index] |= (0x01 << bit_shift);\n\t\t}\n\t}\n}\n\nvoid Species::RecordNewDerivedState(const Haplosome *p_haplosome, slim_position_t p_position, const std::vector<Mutation *> &p_derived_mutations)\n{\n#if DEBUG\n\tif (!recording_mutations_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewDerivedState): (internal error) tree sequence mutation recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// This records information in the Site and Mutation tables.\n\t// This is called whenever a new mutation is added to a haplosome.  Because\n\t// mutation stacking makes things complicated, this hook supplies not just\n\t// the new mutation, but the entire new derived state – all of the\n\t// mutations that exist at the given position in the given haplosome,\n\t// post-addition.  This derived state may involve the removal of some\n\t// ancestral mutations (or may not), in addition to the new mutation that\n\t// was added.  The new state is not even guaranteed to be different from\n\t// the ancestral state; because of the way new mutations are added in some\n\t// paths (with bulk operations) we may not know.  This method will also be\n\t// called when a mutation is removed from a given haplosome; if no mutations\n\t// remain at the given position, p_derived_mutations will be empty.  The\n\t// vector of mutations passed in here is reused internally, so this method\n\t// must not keep a pointer to it; any information that needs to be kept\n\t// from it must be copied out.  See treerec/implementation.md for more.\n\t\n\t// BCH 4/29/2018: Null haplosomes should never contain any mutations at all,\n\t// including fixed mutations; the simplest thing is to just disallow derived\n\t// states for them altogether.\n\tif (p_haplosome->IsNull())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewDerivedState): new derived states cannot be recorded for null haplosomes.\" << EidosTerminate();\n\t\n\ttsk_id_t haplosomeTSKID = p_haplosome->OwningIndividual()->TskitNodeIdBase() + p_haplosome->chromosome_subposition_;\n\tslim_chromosome_index_t index = p_haplosome->chromosome_index_;\n\tTreeSeqInfo &tsinfo = treeseq_[index];\n\n\t// Identify any previous mutations at this site in this haplosome, and add a new site.\n\t// This site may already exist, but we add it anyway, and deal with that in deduplicate_sites().\n\tdouble tsk_position = (double) p_position;\n\n\ttsk_id_t site_id = tsk_site_table_add_row(&tsinfo.tables_.sites, tsk_position, NULL, 0, NULL, 0);\n\tif (site_id < 0) handle_error(\"tsk_site_table_add_row\", site_id);\n\t\n\t// form derived state\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::RecordNewDerivedState(): usage of statics\");\n\t\n\tstatic std::vector<slim_mutationid_t> derived_mutation_ids;\n\tstatic std::vector<MutationMetadataRec> mutation_metadata;\n\tMutationMetadataRec metadata_rec;\n\t\n\tderived_mutation_ids.resize(0);\n\tmutation_metadata.resize(0);\n\tfor (Mutation *mutation : p_derived_mutations)\n\t{\n\t\tderived_mutation_ids.emplace_back(mutation->mutation_id_);\n\t\tMetadataForMutation(mutation, &metadata_rec);\n\t\tmutation_metadata.emplace_back(metadata_rec);\n\t}\n\t\n\t// find and incorporate any fixed mutations at this position, which exist in all new derived states but are not included by SLiM\n\t// BCH 5/14/2019: Note that this means that derived states will be recorded that look \"stacked\" even when those mutations would\n\t// not have stacked, by the stacking policy, had they occurred in the same haplosome at the same time.  So this is a bit weird.\n\t// For example, you can end up with a derived state that appears to show two nucleotides stacked at the same position; but one\n\t// fixed before the other one occurred, so they aren't stacked really, the new one just occurred on the ancestral background of\n\t// the old one.  Possibly we ought to do something different about this (and not record a stacked derived state), but that\n\t// would be a big change since it has implications for crosscheck, etc.  FIXME\n\tauto position_range_iter = population_.treeseq_substitutions_map_.equal_range(p_position);\n\t\n\tfor (auto position_iter = position_range_iter.first; position_iter != position_range_iter.second; ++position_iter)\n\t{\n\t\tSubstitution *substitution = position_iter->second;\n\t\t\n\t\tderived_mutation_ids.emplace_back(substitution->mutation_id_);\n\t\tMetadataForSubstitution(substitution, &metadata_rec);\n\t\tmutation_metadata.emplace_back(metadata_rec);\n\t}\n\t\n\t// check for time consistency, using the shared node table in treeseq_[0]; this used to be a DEBUG check, but\n\t// it turns out that it happens in real models, so it should be checked in release builds also; it occurs\n\t// when a new mutation is added to a subpop that just split off a new subpop, due to tree_seq_tick_offset_;\n\t// see https://github.com/MesserLab/SLiM/issues/473 for a model that reproduces the problem, and now raises.\n\tdouble time = -(double) (community_.tree_seq_tick_ + community_.tree_seq_tick_offset_);\t// see Population::AddSubpopulationSplit() regarding tree_seq_tick_offset_\n\tTreeSeqInfo &tsinfo0 = treeseq_[0];\n\t\n\tif (time < tsinfo0.tables_.nodes.time[haplosomeTSKID])\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordNewDerivedState): a mutation is being added with an invalid timestamp, greater than the time of the tree sequence node to which it belongs.  This can happen if you use addSubpopSplit() to split a new subpop from an old subpop, and then try to add a new mutation to the old subpop in the same tick.  That would imply that descendants of the old subpop ought to possess the new mutation -- but they don't, because the new subpop was already split off.  It therefore creates an inconsistency in the tree sequence.  Either add the new mutation prior to the split, or wait until the next tick to add the new mutation at a time that is clearly post-split.  (Details: invalid derived state recorded in tick \" << community_.Tick() << \", haplosome \" << haplosomeTSKID << \", id \" << p_haplosome->haplosome_id_ << \", with time \" << time << \" >= \" << tsinfo0.tables_.nodes.time[haplosomeTSKID] << \").\" << EidosTerminate();\n\t\n\t// add the mutation table row with the final derived state and metadata\n\tchar *derived_muts_bytes = (char *)(derived_mutation_ids.data());\n\tsize_t derived_state_length = derived_mutation_ids.size() * sizeof(slim_mutationid_t);\n\tchar *mutation_metadata_bytes = (char *)(mutation_metadata.data());\n\tsize_t mutation_metadata_length = mutation_metadata.size() * sizeof(MutationMetadataRec);\n\t\n\tint ret = tsk_mutation_table_add_row(&tsinfo.tables_.mutations, site_id, haplosomeTSKID, TSK_NULL, \n\t\t\t\t\ttime,\n\t\t\t\t\tderived_muts_bytes, (tsk_size_t)derived_state_length,\n\t\t\t\t\tmutation_metadata_bytes, (tsk_size_t)mutation_metadata_length);\n\tif (ret < 0) handle_error(\"tsk_mutation_table_add_row\", ret);\n}\n\nvoid Species::CheckAutoSimplification(void)\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CheckAutoSimplification): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// This is called at the end of each cycle, at an appropriate time to simplify.  This method decides\n\t// whether to simplify or not, based upon how long it has been since the last time we simplified.  Each\n\t// time we simplify, we ask whether we simplified too early, too late, or just the right time by comparing\n\t// the pre:post ratio of the tree recording table sizes to the desired pre:post ratio, simplification_ratio_,\n\t// as set up in initializeTreeSeq().  Note that a simplification_ratio_ value of INF means \"never simplify\n\t// automatically\"; we check for that up front.\n\t++simplify_elapsed_;\n\t\n\tif (simplification_interval_ != -1)\n\t{\n\t\t// BCH 4/5/2019: Adding support for a chosen simplification interval rather than a ratio.  A value of -1\n\t\t// means the simplification ratio is being used, as implemented below; any other value is a target interval.\n\t\tif ((simplify_elapsed_ >= 1) && (simplify_elapsed_ >= simplification_interval_))\n\t\t{\n\t\t\tSimplifyAllTreeSequences();\n\t\t}\n\t}\n\telse if (!std::isinf(simplification_ratio_))\n\t{\n\t\tif (simplify_elapsed_ >= simplify_interval_)\n\t\t{\n\t\t\t// We could, in principle, calculate actual memory used based on number of rows * sizeof(column), etc.,\n\t\t\t// but that seems like overkill; adding together the number of rows in all the tables should be a\n\t\t\t// reasonable proxy, and this whole thing is just a heuristic that needs to be tailored anyway.\n\t\t\t// Note that this overcounts the rows for shared tables, but since the ratio of old:new is what matters\n\t\t\t// for the decision below, it seems to me that that overcounting is unimportant, and simpler to code.\n\t\t\tuint64_t old_table_size = 0;\n\t\t\tuint64_t new_table_size = 0;\n\t\t\t\n\t\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t\t{\n\t\t\t\told_table_size += (uint64_t)tsinfo.tables_.nodes.num_rows;\n\t\t\t\told_table_size += (uint64_t)tsinfo.tables_.edges.num_rows;\n\t\t\t\told_table_size += (uint64_t)tsinfo.tables_.sites.num_rows;\n\t\t\t\told_table_size += (uint64_t)tsinfo.tables_.mutations.num_rows;\n\t\t\t}\n\t\t\t\n\t\t\tSimplifyAllTreeSequences();\n\t\t\t\t\n\t\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t\t{\n\t\t\t\tnew_table_size += (uint64_t)tsinfo.tables_.nodes.num_rows;\n\t\t\t\tnew_table_size += (uint64_t)tsinfo.tables_.edges.num_rows;\n\t\t\t\tnew_table_size += (uint64_t)tsinfo.tables_.sites.num_rows;\n\t\t\t\tnew_table_size += (uint64_t)tsinfo.tables_.mutations.num_rows;\n\t\t\t}\n\t\t\t\n\t\t\tdouble ratio = old_table_size / (double)new_table_size;\n\t\t\t\n\t\t\t//std::cout << \"auto-simplified in tick \" << community->Tick() << \"; old size \" << old_table_size << \", new size \" << new_table_size;\n\t\t\t//std::cout << \"; ratio \" << ratio << \", target \" << simplification_ratio_ << std::endl;\n\t\t\t//std::cout << \"old interval \" << simplify_interval_ << \", new interval \";\n\t\t\t\n\t\t\t// Adjust our automatic simplification interval based upon the observed change in storage space used.\n\t\t\t// Not sure if this is exactly what we want to do; this will hunt around a lot without settling on a value,\n\t\t\t// but that seems harmless.  The scaling factor of 1.2 is chosen somewhat arbitrarily; we want it to be\n\t\t\t// large enough that we will arrive at the optimum interval before too terribly long, but small enough\n\t\t\t// that we have some granularity, so that once we reach the optimum we don't fluctuate too much.\n\t\t\tif (ratio < simplification_ratio_)\n\t\t\t{\n\t\t\t\t// We simplified too soon; wait a little longer next time\n\t\t\t\tsimplify_interval_ *= 1.2;\n\t\t\t\t\n\t\t\t\t// Impose a maximum interval of 1000, so we don't get caught flat-footed if model demography changes\n\t\t\t\tif (simplify_interval_ > 1000.0)\n\t\t\t\t\tsimplify_interval_ = 1000.0;\n\t\t\t}\n\t\t\telse if (ratio > simplification_ratio_)\n\t\t\t{\n\t\t\t\t// We simplified too late; wait a little less long next time\n\t\t\t\tsimplify_interval_ /= 1.2;\n\t\t\t\t\n\t\t\t\t// Impose a minimum interval of 1.0, just to head off weird underflow issues\n\t\t\t\tif (simplify_interval_ < 1.0)\n\t\t\t\t\tsimplify_interval_ = 1.0;\n\t\t\t}\n\t\t\t\n\t\t\t//std::cout << simplify_interval_ << std::endl;\n\t\t}\n\t}\n}\n\nvoid Species::DerivedStatesFromAscii(tsk_table_collection_t *p_tables)\n{\n\t// This modifies p_tables in place, replacing the derived_state column of p_tables with a binary version.\n\ttsk_mutation_table_t mutations_copy;\n\tint ret = tsk_mutation_table_copy(&p_tables->mutations, &mutations_copy, 0);\n\tif (ret < 0) handle_error(\"derived_from_ascii\", ret);\n\t\n\t{\n\t\tconst char *derived_state = p_tables->mutations.derived_state;\n\t\ttsk_size_t *derived_state_offset = p_tables->mutations.derived_state_offset;\n\t\tstd::vector<slim_mutationid_t> binary_derived_state;\n\t\tstd::vector<tsk_size_t> binary_derived_state_offset;\n\t\tsize_t derived_state_total_part_count = 0;\n\t\t\n\t\tbinary_derived_state_offset.emplace_back(0);\n\t\t\n\t\ttry {\n\t\t\tfor (size_t j = 0; j < p_tables->mutations.num_rows; j++)\n\t\t\t{\n\t\t\t\tstd::string string_derived_state(derived_state + derived_state_offset[j], derived_state_offset[j+1] - derived_state_offset[j]);\n\t\t\t\t\n\t\t\t\tif (string_derived_state.size() == 0)\n\t\t\t\t{\n\t\t\t\t\t// nothing to do for an empty derived state\n\t\t\t\t}\n\t\t\t\telse if (string_derived_state.find(',') == std::string::npos)\n\t\t\t\t{\n\t\t\t\t\t// a single mutation can be handled more efficiently, and this is the common case so it's worth optimizing\n\t\t\t\t\tbinary_derived_state.emplace_back((slim_mutationid_t)std::stoll(string_derived_state));\n\t\t\t\t\tderived_state_total_part_count++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// stacked mutations require that the derived state be separated to parse it\n\t\t\t\t\tstd::vector<std::string> derived_state_parts = Eidos_string_split(string_derived_state, \",\");\n\t\t\t\t\t\n\t\t\t\t\tfor (std::string &derived_state_part : derived_state_parts)\n\t\t\t\t\t\tbinary_derived_state.emplace_back((slim_mutationid_t)std::stoll(derived_state_part));\n\t\t\t\t\t\n\t\t\t\t\tderived_state_total_part_count += derived_state_parts.size();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbinary_derived_state_offset.emplace_back((tsk_size_t)(derived_state_total_part_count * sizeof(slim_mutationid_t)));\n\t\t\t}\n\t\t} catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::DerivedStatesFromAscii): a mutation derived state was not convertible into an int64_t mutation id.  The tree-sequence data may not be annotated for SLiM, or may be corrupted.  If mutations were added in msprime, do you want to use the msprime.SLiMMutationModel?\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (binary_derived_state.size() == 0)\n\t\t\tbinary_derived_state.resize(1);\n\t\t\n\t\tret = tsk_mutation_table_set_columns(&p_tables->mutations,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.num_rows,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.site,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.node,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.parent,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.time,\n\t\t\t\t\t\t\t\t\t\t (char *)binary_derived_state.data(),\n\t\t\t\t\t\t\t\t\t\t binary_derived_state_offset.data(),\n\t\t\t\t\t\t\t\t\t\t mutations_copy.metadata,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.metadata_offset);\n\t\tif (ret < 0) handle_error(\"derived_from_ascii\", ret);\n\t}\n\t\n\ttsk_mutation_table_free(&mutations_copy);\n}\n\nvoid Species::DerivedStatesToAscii(tsk_table_collection_t *p_tables)\n{\n\t// This modifies p_tables in place, replacing the derived_state column of p_tables with an ASCII version.\n\ttsk_mutation_table_t mutations_copy;\n\tint ret = tsk_mutation_table_copy(&p_tables->mutations, &mutations_copy, 0);\n\tif (ret < 0) handle_error(\"derived_to_ascii\", ret);\n\t\n\t{\n\t\tconst char *derived_state = p_tables->mutations.derived_state;\n\t\ttsk_size_t *derived_state_offset = p_tables->mutations.derived_state_offset;\n\t\tstd::string text_derived_state;\n\t\tstd::vector<tsk_size_t> text_derived_state_offset;\n\t\t\n\t\ttext_derived_state_offset.emplace_back(0);\n\t\t\n\t\tfor (size_t j = 0; j < p_tables->mutations.num_rows; j++)\n\t\t{\n\t\t\tslim_mutationid_t *int_derived_state = (slim_mutationid_t *)(derived_state + derived_state_offset[j]);\n\t\t\tsize_t cur_derived_state_length = (derived_state_offset[j+1] - derived_state_offset[j])/sizeof(slim_mutationid_t);\n\t\t\t\n\t\t\tfor (size_t i = 0; i < cur_derived_state_length; i++)\n\t\t\t{\n\t\t\t\tif (i != 0) text_derived_state.append(\",\");\n\t\t\t\ttext_derived_state.append(std::to_string(int_derived_state[i]));\n\t\t\t}\n\t\t\ttext_derived_state_offset.emplace_back((tsk_size_t)text_derived_state.size());\n\t\t}\n\t\t\n\t\tret = tsk_mutation_table_set_columns(&p_tables->mutations,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.num_rows,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.site,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.node,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.parent,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.time,\n\t\t\t\t\t\t\t\t\t\t text_derived_state.c_str(),\n\t\t\t\t\t\t\t\t\t\t text_derived_state_offset.data(),\n\t\t\t\t\t\t\t\t\t\t mutations_copy.metadata,\n\t\t\t\t\t\t\t\t\t\t mutations_copy.metadata_offset);\n\t\tif (ret < 0) handle_error(\"derived_to_ascii\", ret);\n\t}\n\t\n\ttsk_mutation_table_free(&mutations_copy);\n}\n\nvoid Species::AddIndividualsToTable(Individual * const *p_individual, size_t p_num_individuals, tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash, tsk_flags_t p_flags)\n{\n\t// We use currently use this function in two ways, depending on p_flags:\n\t//  1. (SLIM_TSK_INDIVIDUAL_REMEMBERED) for individuals to be permanently\n\t//      remembered, or\n\t//  2. (SLIM_TSK_INDIVIDUAL_RETAINED) for individuals to be retained only while\n\t//      some of their genome (i.e. any of their nodes) exists in the tree sequence, or\n\t//  3. (SLIM_TSK_INDIVIDUAL_ALIVE) to output the final generation in the tree sequence.\n\t// So, in case (1) we set the REMEMBERED flag, in case (2) we set the RETAINED flag,\n\t// and in case (3) we set the ALIVE flag.\n\t// Note that this function can be called multiple times for the same set of\n\t// individuals. In the most extreme case, individuals who are remembered, then\n\t// permanently remembered but still alive when the tree sequence is written out will\n\t// have this method called on them three times, and they get all flags set.\n\t\n\t// Passing nullptr used to be allowed as a shorthand for \"use the internal tables\", but that is\n\t// no longer allowed since we now might have multiple internal table collections, per chromosome.\n\tif (p_tables == nullptr)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::AddIndividualsToTable): (internal error) p_tables is nullptr!\" << EidosTerminate();\n\t\n\t// loop over individuals and add entries to the individual table; if they are already\n\t// there, we just need to update their flags, metadata, location, etc.\n\tfor (size_t j = 0; j < p_num_individuals; j++)\n\t{\n\t\tIndividual *ind = p_individual[j];\n\t\tslim_pedigreeid_t ped_id = ind->PedigreeID();\n\n\t\tstd::vector<double> location;\n\t\tlocation.emplace_back(ind->spatial_x_);\n\t\tlocation.emplace_back(ind->spatial_y_);\n\t\tlocation.emplace_back(ind->spatial_z_);\n\t\t\n\t\tIndividualMetadataRec metadata_rec;\n\t\tMetadataForIndividual(ind, &metadata_rec);\n\t\t\n\t\t// do a fast lookup to see whether this individual is already in the individuals table\n\t\tauto ind_pos = p_individuals_hash->find(ped_id);\n\t\t\n\t\tif (ind_pos == p_individuals_hash->end()) {\n\t\t\t// This individual is not already in the tables.\n\t\t\ttsk_id_t tsk_individual = tsk_individual_table_add_row(&p_tables->individuals,\n\t\t\t\t\tp_flags, location.data(), (uint32_t)location.size(), \n                    NULL, 0, // individual parents\n\t\t\t\t\t(char *)&metadata_rec, (uint32_t)sizeof(IndividualMetadataRec));\n\t\t\tif (tsk_individual < 0) handle_error(\"tsk_individual_table_add_row\", tsk_individual);\n\t\t\t\n\t\t\t// Add the new individual to our hash table, for fast lookup as done above\n\t\t\tp_individuals_hash->emplace(ped_id, tsk_individual);\n\n\t\t\t// Update node table to have the individual's tskit id in its individual column\n\t\t\ttsk_id_t tsk_node_id_base = ind->TskitNodeIdBase();\n\t\t\t\n\t\t\tassert(tsk_node_id_base + 1 < (tsk_id_t) p_tables->nodes.num_rows);\t\t// base and base+1 must both be in range\n\t\t\tp_tables->nodes.individual[tsk_node_id_base] = tsk_individual;\n\t\t\tp_tables->nodes.individual[tsk_node_id_base + 1] = tsk_individual;\n\n\t\t\t// Update remembered nodes; there are just two entries, base and base+1, for all haplosomes\n\t\t\tif (p_flags & SLIM_TSK_INDIVIDUAL_REMEMBERED)\n\t\t\t{\n\t\t\t\tremembered_nodes_.emplace_back(tsk_node_id_base);\n\t\t\t\tremembered_nodes_.emplace_back(tsk_node_id_base + 1);\n\t\t\t}\n\t\t} else {\n\t\t\t// This individual is already there; we need to update the information.\n\t\t\ttsk_id_t tsk_individual =  ind_pos->second;\n\n\t\t\tassert(((size_t)tsk_individual < p_tables->individuals.num_rows)\n\t\t\t\t   && (location.size()\n\t\t\t\t\t   == (p_tables->individuals.location_offset[tsk_individual + 1]\n\t\t\t\t\t\t   - p_tables->individuals.location_offset[tsk_individual]))\n\t\t\t\t   && (sizeof(IndividualMetadataRec)\n\t\t\t\t\t   == (p_tables->individuals.metadata_offset[tsk_individual + 1]\n\t\t\t\t\t\t   - p_tables->individuals.metadata_offset[tsk_individual])));\n\t\t\t\n\t\t\t// It could have been previously inserted but not with the SLIM_TSK_INDIVIDUAL_REMEMBERED\n\t\t\t// flag: if so, it now needs adding to the list of remembered nodes\n\t\t\ttsk_id_t tsk_node_id_base = ind->TskitNodeIdBase();\n\t\t\t\n\t\t\tif (((p_tables->individuals.flags[tsk_individual] & SLIM_TSK_INDIVIDUAL_REMEMBERED) == 0)\n\t\t\t\t&& (p_flags & SLIM_TSK_INDIVIDUAL_REMEMBERED))\n\t\t\t{\n\t\t\t\tremembered_nodes_.emplace_back(tsk_node_id_base);\n\t\t\t\tremembered_nodes_.emplace_back(tsk_node_id_base + 1);\n\t\t\t}\n\n\t\t\tmemcpy(p_tables->individuals.location\n\t\t\t\t   + p_tables->individuals.location_offset[tsk_individual],\n\t\t\t\t   location.data(), location.size() * sizeof(double));\n\t\t\tmemcpy(p_tables->individuals.metadata\n\t\t\t\t\t+ p_tables->individuals.metadata_offset[tsk_individual],\n\t\t\t\t\t&metadata_rec, sizeof(IndividualMetadataRec));\n\t\t\tp_tables->individuals.flags[tsk_individual] |= p_flags;\n\t\t\t\n\t\t\t// Check node table\n\t\t\tassert(ind->TskitNodeIdBase() + 1 < (tsk_id_t) p_tables->nodes.num_rows);\t// base and base+1 must both be in range\n\t\t\t\n\t\t\t// BCH 4/29/2019: These asserts are, we think, not technically necessary – the code\n\t\t\t// would work even if they were violated.  But they're a nice invariant to guarantee,\n\t\t\t// and right now they are always true.\n\t\t\tassert(p_tables->nodes.individual[tsk_node_id_base] == (tsk_id_t)tsk_individual);\n\t\t\tassert(p_tables->nodes.individual[tsk_node_id_base + 1] == (tsk_id_t)tsk_individual);\n\t\t}\n\t}\n}\n\nvoid Species::AddLiveIndividualsToIndividualsTable(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash)\n{\n\t// add currently alive individuals to the individuals table, so they persist\n\t// through simplify and can be revived when loading saved state\n\tfor (auto subpop_iter : population_.subpops_)\n\t{\n\t\tAddIndividualsToTable(subpop_iter.second->parent_individuals_.data(), subpop_iter.second->parent_individuals_.size(), p_tables, p_individuals_hash, SLIM_TSK_INDIVIDUAL_ALIVE);\n\t}\n}\n\nvoid Species::FixAliveIndividuals(tsk_table_collection_t *p_tables)\n{\n\t// This clears the alive flags of the remaining entries; our internal tables never say \"alive\",\n\t// since that changes from cycle to cycle, so after loading saved state we want to strip\n\tfor (size_t j = 0; j < p_tables->individuals.num_rows; j++)\n\t\tp_tables->individuals.flags[j] &= (~SLIM_TSK_INDIVIDUAL_ALIVE);\n}\n\n// check whether population metadata is SLiM metadata or not, without raising; if it is, return the slim_id, >= 0, if not, return -1\n// see also Species::__PrepareSubpopulationsFromTables(), which does similar checks but raises if something is wrong\nstatic slim_objectid_t CheckSLiMPopulationMetadata(const char *p_metadata, size_t p_metadata_length)\n{\n\tstd::string metadata_string(p_metadata, p_metadata_length);\n\tnlohmann::json subpop_metadata;\n\t\n\ttry {\n\t\tsubpop_metadata = nlohmann::json::parse(metadata_string);\n\t} catch (...) {\n\t\treturn -1;\n\t}\n\n\tif (subpop_metadata.is_null())\n\t\treturn -1;\n\tif (!subpop_metadata.is_object())\n\t\treturn -1;\n\t\n\tif (!subpop_metadata.contains(\"slim_id\"))\n\t\treturn -1;\n\tif (!subpop_metadata[\"slim_id\"].is_number_integer())\n\t\treturn -1;\n\t\n\treturn subpop_metadata[\"slim_id\"].get<slim_objectid_t>();\n}\n\nvoid Species::WritePopulationTable(tsk_table_collection_t *p_tables)\n{\n\tint ret;\n\ttsk_id_t tsk_population_id = -1;\n\ttsk_population_table_t *population_table_copy;\n\tpopulation_table_copy = (tsk_population_table_t *)malloc(sizeof(tsk_population_table_t));\n\tif (!population_table_copy)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WritePopulationTable): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\tret = tsk_population_table_copy(&p_tables->populations, population_table_copy, 0);\n\tif (ret != 0) handle_error(\"WritePopulationTable tsk_population_table_copy()\", ret);\n\tret = tsk_population_table_clear(&p_tables->populations);\n\tif (ret != 0) handle_error(\"WritePopulationTable tsk_population_table_clear()\", ret);\n\n\t// figure out the last subpop id we need to write out to the table; this is the greatest value from (a) the number\n\t// of rows in the current population table (to carry over non-SLiM pop table entries we loaded in), (b) the subpop\n\t// references found in the node table, which might reference subpops that no longer exist, and (c) the subpop ids\n\t// found in our \"previously used\" information, whcih references every subpop id we have seen during execution.\n\tslim_objectid_t last_subpop_id = (slim_objectid_t)population_table_copy->num_rows - 1;\t// FIXME note this assumes the number of rows fits into 32 bits\n\tfor (size_t j = 0; j < p_tables->nodes.num_rows; j++)\n\t\tlast_subpop_id = std::max(last_subpop_id, p_tables->nodes.population[j]);\n\tfor (const auto &used_id_name : used_subpop_ids_)\n\t\tlast_subpop_id = std::max(last_subpop_id, used_id_name.first);\n\t\n\t// write out an entry for each subpop\n\tslim_objectid_t last_id_written = -1;\n\t\n\tfor (auto subpop_iter : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_iter.second;\n\t\tslim_objectid_t subpop_id = subpop->subpopulation_id_;\n\t\t\n\t\t// first, write out empty entries for unused subpop ids before this one; note metadata should always be JSON here,\n\t\t// binary metadata got translated to JSON by _InstantiateSLiMObjectsFromTables() on read\n\t\twhile (last_id_written < subpop_id - 1)\n\t\t{\n\t\t\tbool got_metadata = false;\n\t\t\tstd::string new_metadata_string(\"null\");\n\t\t\t\n\t\t\tif (++last_id_written < (slim_objectid_t) population_table_copy->num_rows)\n\t\t\t{\n\t\t\t\ttsk_population_t tsk_population_object;\n\t\t\t\tret = tsk_population_table_get_row(population_table_copy, last_id_written, &tsk_population_object);\n\t\t\t\tif (ret != 0) handle_error(\"WritePopulationTable tsk_population_table_get_row()\", ret);\n\t\t\t\t\n\t\t\t\tif (CheckSLiMPopulationMetadata(tsk_population_object.metadata, tsk_population_object.metadata_length) == -1)\n\t\t\t\t{\n\t\t\t\t\t// The metadata present, if any, is not SLiM metadata, so it should be carried over.\n\t\t\t\t\tnew_metadata_string = std::string(tsk_population_object.metadata, tsk_population_object.metadata_length);\n\t\t\t\t\tgot_metadata = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// SLiM metadata for non-extant subpops gets removed at write time for consistency.\n\t\t\t\t\t// See issue #317 for discussion.  However, we keep *names* from SLiM populations\n\t\t\t\t\t// that are found in the table and have been removed, because names provide a\n\t\t\t\t\t// useful way for the user to check that everything is as they expect,\n\t\t\t\t\t// lets them find particular populations without error-prone bookkeeping,\n\t\t\t\t\t// and is the basis for the more user-friendly interfaces in msprime\n\t\t\t\t\t// (e.g., it's important to have names when setting up a more complex model\n\t\t\t\t\t// to use in recapitation). At present, the only way that\n\t\t\t\t\t// entries can have SLiM metadata in the population table\n\t\t\t\t\t// but not correspond to extant populations is if the populations were present\n\t\t\t\t\t// in a tree sequence that was loaded in to SLiM but they were\n\t\t\t\t\t// subsequently removed.\n\t\t\t\t\tstd::string metadata_string(\n\t\t\t\t\t\t\ttsk_population_object.metadata,\n\t\t\t\t\t\t\ttsk_population_object.metadata_length);\n\t\t\t\t\tnlohmann::json old_metadata;\n\t\t\t\t\told_metadata = nlohmann::json::parse(metadata_string);\n\t\t\t\t\tif (old_metadata.contains(\"name\")) {\n\t\t\t\t\t\tnlohmann::json new_metadata = nlohmann::json::object();\n\t\t\t\t\t\tnew_metadata[\"name\"] = old_metadata[\"name\"];\n\t\t\t\t\t\tnew_metadata_string = new_metadata.dump();\n\t\t\t\t\t\tgot_metadata = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// BCH 7/20/2024: To fix #447, we have some new logic here.  If we didn't get any useful\n\t\t\t// metadata from the population table, we're on our own.  If we have previously seen a\n\t\t\t// subpop with this id at any point, we use the name we last saw for that id.\n\t\t\tif (!got_metadata)\n\t\t\t{\n\t\t\t\tauto used_id_name_iter = used_subpop_ids_.find(last_id_written);\n\t\t\t\t\n\t\t\t\tif (used_id_name_iter != used_subpop_ids_.end())\n\t\t\t\t{\n\t\t\t\t\tnlohmann::json new_metadata = nlohmann::json::object();\n\t\t\t\t\tnew_metadata[\"name\"] = (*used_id_name_iter).second;\n\t\t\t\t\tnew_metadata_string = new_metadata.dump();\n\t\t\t\t\t//got_metadata = true;\t// BCH 4/15/2025: value stored is never used; commenting out, I don't *think* this represents a bug, just an unnecessary store...\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// otherwise, we will use the \"null\" metadata we set as the default above,\n\t\t\t// producing a simple placeholder row that implies the id has never been used.\n\t\t\t\n\t\t\ttsk_population_id = tsk_population_table_add_row(\n\t\t\t\t\t&p_tables->populations,\n\t\t\t\t\tnew_metadata_string.data(),\n\t\t\t\t\tnew_metadata_string.length()\n\t\t\t);\n\t\t\tif (tsk_population_id < 0) handle_error(\"tsk_population_table_add_row\", tsk_population_id);\n\t\t\t\n\t\t\tassert(tsk_population_id == last_id_written);\n\t\t}\n\t\t\n\t\t// now we're at the slot for this subpopulation, so construct it and write it out\n\t\tnlohmann::json pop_metadata = nlohmann::json::object();\n\t\t\n\t\tpop_metadata[\"slim_id\"] = subpop->subpopulation_id_;\n\t\t\n\t\tif (spatial_dimensionality_ >= 1)\n\t\t{\n\t\t\tpop_metadata[\"bounds_x0\"] = subpop->bounds_x0_;\n\t\t\tpop_metadata[\"bounds_x1\"] = subpop->bounds_x1_;\n\t\t}\n\t\tif (spatial_dimensionality_ >= 2)\n\t\t{\n\t\t\tpop_metadata[\"bounds_y0\"] = subpop->bounds_y0_;\n\t\t\tpop_metadata[\"bounds_y1\"] = subpop->bounds_y1_;\n\t\t}\n\t\tif (spatial_dimensionality_ >= 3)\n\t\t{\n\t\t\tpop_metadata[\"bounds_z0\"] = subpop->bounds_z0_;\n\t\t\tpop_metadata[\"bounds_z1\"] = subpop->bounds_z1_;\n\t\t}\n\t\t\n\t\tpop_metadata[\"name\"] = subpop->name_;\n\t\tif (subpop->description_.length())\n\t\t\tpop_metadata[\"description\"] = subpop->description_;\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tif (subpop->selfing_fraction_ > 0.0)\n\t\t\t\tpop_metadata[\"selfing_fraction\"] = subpop->selfing_fraction_;\n\t\t\tif (subpop->female_clone_fraction_ > 0.0)\n\t\t\t\tpop_metadata[\"female_cloning_fraction\"] = subpop->female_clone_fraction_;\n\t\t\tif (subpop->male_clone_fraction_ > 0.0)\n\t\t\t\tpop_metadata[\"male_cloning_fraction\"] = subpop->male_clone_fraction_;\n\t\t\tif (subpop->parent_sex_ratio_ != 0.5)\n\t\t\t\tpop_metadata[\"sex_ratio\"] = subpop->parent_sex_ratio_;\n\t\t\t\n\t\t\tnlohmann::json migration_records = nlohmann::json::array();\n\t\t\t\n\t\t\tfor (std::pair<slim_objectid_t,double> migration_pair : subpop->migrant_fractions_)\n\t\t\t{\n\t\t\t\tnlohmann::json migration_record = nlohmann::json::object();\n\t\t\t\t\n\t\t\t\tmigration_record[\"source_subpop\"] = migration_pair.first;\n\t\t\t\tmigration_record[\"migration_rate\"] = migration_pair.second;\n\t\t\t\tmigration_records.emplace_back(std::move(migration_record));\n\t\t\t}\n\t\t\t\n\t\t\tpop_metadata[\"migration_records\"] = std::move(migration_records);\n\t\t}\n\t\t\n\t\tstd::string metadata_rec = pop_metadata.dump();\n\t\t\n\t\ttsk_population_id = tsk_population_table_add_row(&p_tables->populations, (char *)metadata_rec.c_str(), (uint32_t)metadata_rec.length());\n\t\tif (tsk_population_id < 0) handle_error(\"tsk_population_table_add_row\", tsk_population_id);\n\t\t\n\t\tlast_id_written++;\n\t\tassert(tsk_population_id == last_id_written);\n\t}\n\t\n\t// finally, write out entries for the rest of the table; entries are needed up to\n\t// largest_subpop_id_ because there could be ancestral nodes that reference them\n\twhile (last_id_written < (slim_objectid_t) last_subpop_id)\n\t{\n\t\tbool got_metadata = false;\n\t\tstd::string new_metadata_string(\"null\");\n\t\t\n\t\tif (++last_id_written < (slim_objectid_t) population_table_copy->num_rows)\n\t\t{\n\t\t\ttsk_population_t tsk_population_object;\n\t\t\ttsk_population_table_get_row(population_table_copy, last_id_written, &tsk_population_object);\n\t\t\tif (ret != 0) handle_error(\"WritePopulationTable tsk_population_table_get_row()\", ret);\n\t\t\t\n\t\t\tif (CheckSLiMPopulationMetadata(tsk_population_object.metadata, tsk_population_object.metadata_length) == -1)\n\t\t\t{\n\t\t\t\t// The metadata present, if any, is not SLiM metadata, so it should be carried over; note that\n\t\t\t\tnew_metadata_string = std::string(tsk_population_object.metadata, tsk_population_object.metadata_length);\n\t\t\t\tgot_metadata = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// As above, retain only names from SLiM metadata for non-extant subpops.\n\t\t\t\tstd::string metadata_string(\n\t\t\t\t\t\ttsk_population_object.metadata,\n\t\t\t\t\t\ttsk_population_object.metadata_length);\n\t\t\t\tnlohmann::json old_metadata;\n\t\t\t\told_metadata = nlohmann::json::parse(metadata_string);\n\t\t\t\tif (old_metadata.contains(\"name\")) {\n\t\t\t\t\tnlohmann::json new_metadata = nlohmann::json::object();\n\t\t\t\t\tnew_metadata[\"name\"] = old_metadata[\"name\"];\n\t\t\t\t\tnew_metadata_string = new_metadata.dump();\n\t\t\t\t\tgot_metadata = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// BCH 7/20/2024: To fix #447, we have some new logic here.  If we didn't get any useful\n\t\t// metadata from the population table, we're on our own.  If we have previously seen a\n\t\t// subpop with this id at any point, we use the name we last saw for that id.\n\t\tif (!got_metadata)\n\t\t{\n\t\t\tauto used_id_name_iter = used_subpop_ids_.find(last_id_written);\n\t\t\t\n\t\t\tif (used_id_name_iter != used_subpop_ids_.end())\n\t\t\t{\n\t\t\t\tnlohmann::json new_metadata = nlohmann::json::object();\n\t\t\t\tnew_metadata[\"name\"] = (*used_id_name_iter).second;\n\t\t\t\tnew_metadata_string = new_metadata.dump();\n\t\t\t\t//got_metadata = true;\t// BCH 4/15/2025: value stored is never used; commenting out, I don't *think* this represents a bug, just an unnecessary store...\n\t\t\t}\n\t\t}\n\t\t\n\t\ttsk_population_id = tsk_population_table_add_row(\n\t\t\t\t&p_tables->populations,\n\t\t\t\tnew_metadata_string.data(),\n\t\t\t\tnew_metadata_string.length()\n\t\t);\n\t\tif (tsk_population_id < 0) handle_error(\"tsk_population_table_add_row\", tsk_population_id);\n\t\t\n\t\tassert(tsk_population_id == last_id_written);\n\t}\n\t\n\tret = tsk_population_table_free(population_table_copy);\n\tif (ret != 0) handle_error(\"tsk_population_table_free\", ret);\n\tfree(population_table_copy);\n}\n\nvoid Species::WriteTreeSequenceMetadata(tsk_table_collection_t *p_tables, EidosDictionaryUnretained *p_metadata_dict, slim_chromosome_index_t p_chromosome_index)\n{\n\tint ret = 0;\n\n\t//////\n\t// Top-level (tree sequence) metadata:\n\t// In the future, we might need to *add* to the metadata *and also* the schema,\n\t// leaving other keys that might already be there.\n\t// But that's being a headache, so we're skipping it.\n\t\n\t// BCH 3/9/2025: This is now wrapped in try/catch because the JSON library might raise, especially if it dislikes\n\t// the model string we try to put in metadata for p_include_model; see https://github.com/MesserLab/SLiM/issues/488\n\tstd::string new_metadata_str;\n\t\n\ttry {\n\t\tnlohmann::json metadata;\n\t\t\n\t\t// Add user-defined metadata under the SLiM key, if it was supplied by the user\n\t\t// See https://github.com/MesserLab/SLiM/issues/122\n\t\tif (p_metadata_dict)\n\t\t{\n\t\t\tnlohmann::json user_metadata = p_metadata_dict->JSONRepresentation();\n\t\t\t\n\t\t\tmetadata[\"SLiM\"][\"user_metadata\"] = user_metadata;\n\t\t\t\n\t\t\t//std::cout << \"JSON metadata: \" << std::endl << user_metadata.dump(4) << std::endl;\n\t\t}\n\t\t\n\t\t// We could support per-chromosome top-level metadata, too, that would only be saved out\n\t\t// to that chromosome's file, but let's wait to see whether somebody asks for it...\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF) {\n\t\t\tmetadata[\"SLiM\"][\"model_type\"] = \"WF\";\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) {\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"first\";\n\t\t\t} else if (community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts) {\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"early\";\n\t\t\t} else {\n\t\t\t\tassert(community_.CycleStage() == SLiMCycleStage::kWFStage5ExecuteLateScripts);\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"late\";\n\t\t\t}\n\t\t} else {\n\t\t\tassert(model_type_ == SLiMModelType::kModelTypeNonWF);\n\t\t\tmetadata[\"SLiM\"][\"model_type\"] = \"nonWF\";\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) {\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"first\";\n\t\t\t} else if (community_.CycleStage() == SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) {\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"early\";\n\t\t\t} else {\n\t\t\t\tassert(community_.CycleStage() == SLiMCycleStage::kNonWFStage6ExecuteLateScripts);\n\t\t\t\tmetadata[\"SLiM\"][\"stage\"] = \"late\";\n\t\t\t}\n\t\t}\n\t\tmetadata[\"SLiM\"][\"cycle\"] = Cycle();\n\t\tmetadata[\"SLiM\"][\"tick\"] = community_.Tick();\n\t\tmetadata[\"SLiM\"][\"file_version\"] = SLIM_TREES_FILE_VERSION;\n\t\t\n\t\tmetadata[\"SLiM\"][\"name\"] = name_;\n\t\tif (description_.length())\n\t\t\tmetadata[\"SLiM\"][\"description\"] = description_;\n\t\t\n\t\tif (spatial_dimensionality_ == 0) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_dimensionality\"] = \"\";\n\t\t} else if (spatial_dimensionality_ == 1) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_dimensionality\"] = \"x\";\n\t\t} else if (spatial_dimensionality_ == 2) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_dimensionality\"] = \"xy\";\n\t\t} else {\n\t\t\tmetadata[\"SLiM\"][\"spatial_dimensionality\"] = \"xyz\";\n\t\t}\n\t\tif (periodic_x_ & periodic_y_ & periodic_z_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"xyz\";\n\t\t} else if (periodic_x_ & periodic_y_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"xy\";\n\t\t} else if (periodic_x_ & periodic_z_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"xz\";\n\t\t} else if (periodic_y_ & periodic_z_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"yz\";\n\t\t} else if (periodic_x_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"x\";\n\t\t} else if (periodic_y_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"y\";\n\t\t} else if (periodic_z_) {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"z\";\n\t\t} else {\n\t\t\tmetadata[\"SLiM\"][\"spatial_periodicity\"] = \"\";\n\t\t}\n\t\tmetadata[\"SLiM\"][\"separate_sexes\"] = sex_enabled_ ? true : false;\n\t\tmetadata[\"SLiM\"][\"nucleotide_based\"] = nucleotide_based_ ? true : false;\n\t\t\n\t\tmetadata[\"SLiM\"][\"chromosomes\"] = nlohmann::json::array();\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tnlohmann::json chromosome_info;\n\t\t\t\n\t\t\tchromosome_info[\"index\"] = chromosome->Index();\n\t\t\tchromosome_info[\"id\"] = chromosome->ID();\n\t\t\tchromosome_info[\"symbol\"] = chromosome->Symbol();\n\t\t\tif (chromosome->Name().length() > 0)\n\t\t\t\tchromosome_info[\"name\"] = chromosome->Name();\n\t\t\tchromosome_info[\"type\"] = StringForChromosomeType(chromosome->Type());\n\t\t\t\n\t\t\tmetadata[\"SLiM\"][\"chromosomes\"].push_back(chromosome_info);\n\t\t\t\n\t\t\tif (p_chromosome_index == chromosome->Index())\t\t// true for the chromosome being written\n\t\t\t{\n\t\t\t\t// write out all the same information again in a key called \"this_chromosome\"; this way the\n\t\t\t\t// user can trivially get the info for the chromosome represented by the file; note that a\n\t\t\t\t// no-genetics model will have a chromosomes key with an empty array, and no this_chromosome,\n\t\t\t\t// but a no-genetics model can't write a tree sequence anyway, so that is moot.\n\t\t\t\tmetadata[\"SLiM\"][\"this_chromosome\"] = chromosome_info;\n\t\t\t}\n\t\t}\n\t\t\n\t\tnew_metadata_str = metadata.dump();\n\t} catch (const std::exception &e) {\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequenceMetadata): a JSON string could not be generated for tree-sequence metadata due to an error: '\" << e.what() << \"'.\" << EidosTerminate();\n\t} catch (...) {\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequenceMetadata): a JSON string could not be generated for tree-sequence metadata due to an unknown error.\" << EidosTerminate();\n\t}\n\t\n\tret = tsk_table_collection_set_metadata(\n\t\t\tp_tables, new_metadata_str.c_str(), (tsk_size_t)new_metadata_str.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_table_collection_set_metadata\", ret);\n\n\t// As above, we maybe ought to edit the metadata schema adding our keys,\n\t// but then comparing tables is a headache; see tskit#763\n\tret = tsk_table_collection_set_metadata_schema(\n\t\t\tp_tables, gSLiM_tsk_metadata_schema.c_str(), (tsk_size_t)gSLiM_tsk_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_table_collection_set_metadata_schema\", ret);\n\n\t////////////\n\t// Set metadata schema on each table\n\tret = tsk_edge_table_set_metadata_schema(&p_tables->edges,\n\t\t\tgSLiM_tsk_edge_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)gSLiM_tsk_edge_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_edge_table_set_metadata_schema\", ret);\n\tret = tsk_site_table_set_metadata_schema(&p_tables->sites,\n\t\t\tgSLiM_tsk_site_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)gSLiM_tsk_site_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_site_table_set_metadata_schema\", ret);\n\tret = tsk_mutation_table_set_metadata_schema(&p_tables->mutations,\n\t\t\tgSLiM_tsk_mutation_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)gSLiM_tsk_mutation_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_mutation_table_set_metadata_schema\", ret);\n\tret = tsk_individual_table_set_metadata_schema(&p_tables->individuals,\n\t\t\tgSLiM_tsk_individual_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)gSLiM_tsk_individual_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_individual_table_set_metadata_schema\", ret);\n\tret = tsk_population_table_set_metadata_schema(&p_tables->populations,\n\t\t\tgSLiM_tsk_population_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)gSLiM_tsk_population_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_population_table_set_metadata_schema\", ret);\n\t\n\t// For the node table the schema we save out depends upon the number of\n\t// bits needed to represent the null haplosome structure of the model.\n\t// We allocate one bit per chromosome, in each node table entry (note\n\t// there are two entries per individual, so it ends up being two bits\n\t// of information per chromosome, across the two node table entries.)\n\t// See the big comment on gSLiM_tsk_node_metadata_schema_FORMAT.\n\tstd::string tsk_node_metadata_schema = gSLiM_tsk_node_metadata_schema_FORMAT;\n\tsize_t pos = tsk_node_metadata_schema.find(\"\\\"%d\\\"\");\n\tstd::string count_string = std::to_string(haplosome_metadata_is_vacant_bytes_);\n\t\n\tif (pos == std::string::npos)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequenceMetadata): (internal error) `%d` substring missing from gSLiM_tsk_node_metadata_schema_FORMAT.\" << EidosTerminate();\n\t\n\ttsk_node_metadata_schema.replace(pos, 4, count_string);\t\t// replace %d in the format string with the byte count\n\t\n\tret = tsk_node_table_set_metadata_schema(&p_tables->nodes,\n\t\t\ttsk_node_metadata_schema.c_str(),\n\t\t\t(tsk_size_t)tsk_node_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_node_table_set_metadata_schema\", ret);\n}\n\nvoid Species::WriteProvenanceTable(tsk_table_collection_t *p_tables, bool p_use_newlines, bool p_include_model, slim_chromosome_index_t p_chromosome_index)\n{\n\tint ret = 0;\n\ttime_t timer;\n\tsize_t timestamp_size = 64;\n\tchar buffer[timestamp_size];\n\tstruct tm* tm_info;\n\t// NOTE: since file version 0.5, we do *not* read information\n\t// back out of the provenance table, but get it from metadata instead.\n\t// But, we still want to record how the tree sequence was produced in\n\t// provenance, so the code remains much the same.\n\t\n\t// New provenance writing code, using the JSON for Modern C++ library (json.hpp); this is file_version 0.2 (and up)\n\t// BCH 3/9/2025: This is now wrapped in try/catch because the JSON library might raise, especially if it dislikes\n\t// the model string we try to put in metadata for p_include_model; see https://github.com/MesserLab/SLiM/issues/488\n\tstd::string provenance_str;\n\t\n\ttry {\n\t\tnlohmann::json j;\n\t\t\n\t\t// BCH 3/10/2024: Moving from schema version 1.0.0 to 1.1.0, which I believe shipped in tskit 0.5.9.\n\t\t// This adds the optional `resources` key.  See https://github.com/MesserLab/SLiM/issues/478.\n\t\tj[\"schema_version\"] = \"1.1.0\";\n\t\t\n\t\tstruct utsname name;\n\t\tret = uname(&name);\n\t\t\n\t\tif (ret == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteProvenanceTable): (internal error) uname() failed.\" << EidosTerminate();\n\t\t\n\t\tj[\"environment\"][\"os\"][\"version\"] = std::string(name.version);\n\t\tj[\"environment\"][\"os\"][\"node\"] = std::string(name.nodename);\n\t\tj[\"environment\"][\"os\"][\"release\"] = std::string(name.release);\n\t\tj[\"environment\"][\"os\"][\"system\"] = std::string(name.sysname);\n\t\tj[\"environment\"][\"os\"][\"machine\"] = std::string(name.machine);\n\t\t\n\t\tj[\"software\"][\"name\"] = \"SLiM\";\t\t// note this key was named \"program\" in provenance version 0.1\n\t\tj[\"software\"][\"version\"] = SLIM_VERSION_STRING;\n\t\t\n\t\tj[\"slim\"][\"file_version\"] = SLIM_TREES_FILE_VERSION;\t// see declaration of SLIM_TREES_FILE_VERSION for comments on prior versions\n\t\tj[\"slim\"][\"cycle\"] = Cycle();\n\t\tj[\"slim\"][\"tick\"] = community_.Tick();\n\t\tj[\"slim\"][\"name\"] = name_;\n\t\tif (description_.length())\n\t\t\tj[\"slim\"][\"description\"] = description_;\n\t\t//j[\"slim\"][\"remembered_node_count\"] = (long)remembered_nodes_.size();\t// no longer writing this key!\n\t\t\n\t\t// compute the SHA-256 hash of the script string\n\t\tconst std::string &scriptString = community_.ScriptString();\n\t\tconst char *script_chars = scriptString.c_str();\n\t\tuint8_t script_hash[32];\n\t\tchar script_hash_string[65];\n\t\t\n\t\tEidos_calc_sha_256(script_hash, script_chars, strlen(script_chars));\n\t\tEidos_hash_to_string(script_hash_string, script_hash);\n\t\t\n\t\tstd::string scriptHashString(script_hash_string);\n\t\t\n\t\t//std::cout << \"script hash: \" << scriptHashString << std::endl;\n\t\t\n\t\tj[\"parameters\"][\"command\"] = community_.cli_params_;\n\t\t\n\t\t// note high overlap with WriteTreeSequenceMetadata\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF) {\n\t\t\tj[\"parameters\"][\"model_type\"] = \"WF\";\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) {\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"first\";\n\t\t\t} else if (community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts) {\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"early\";\n\t\t\t} else {\n\t\t\t\tassert(community_.CycleStage() == SLiMCycleStage::kWFStage5ExecuteLateScripts);\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"late\";\n\t\t\t}\n\t\t} else {\n\t\t\tassert(model_type_ == SLiMModelType::kModelTypeNonWF);\n\t\t\tj[\"parameters\"][\"model_type\"] = \"nonWF\";\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) {\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"first\";\n\t\t\t} else if (community_.CycleStage() == SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) {\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"early\";\n\t\t\t} else {\n\t\t\t\tassert(community_.CycleStage() == SLiMCycleStage::kNonWFStage6ExecuteLateScripts);\n\t\t\t\tj[\"parameters\"][\"stage\"] = \"late\";\n\t\t\t}\n\t\t}\n\t\tif (spatial_dimensionality_ == 0) {\n\t\t\tj[\"parameters\"][\"spatial_dimensionality\"] = \"\";\n\t\t} else if (spatial_dimensionality_ == 1) {\n\t\t\tj[\"parameters\"][\"spatial_dimensionality\"] = \"x\";\n\t\t} else if (spatial_dimensionality_ == 2) {\n\t\t\tj[\"parameters\"][\"spatial_dimensionality\"] = \"xy\";\n\t\t} else {\n\t\t\tj[\"parameters\"][\"spatial_dimensionality\"] = \"xyz\";\n\t\t}\n\t\tif (periodic_x_ & periodic_y_ & periodic_z_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"xyz\";\n\t\t} else if (periodic_x_ & periodic_y_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"xy\";\n\t\t} else if (periodic_x_ & periodic_z_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"xz\";\n\t\t} else if (periodic_y_ & periodic_z_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"yz\";\n\t\t} else if (periodic_x_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"x\";\n\t\t} else if (periodic_y_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"y\";\n\t\t} else if (periodic_z_) {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"z\";\n\t\t} else {\n\t\t\tj[\"parameters\"][\"spatial_periodicity\"] = \"\";\n\t\t}\n\t\tj[\"parameters\"][\"separate_sexes\"] = sex_enabled_ ? true : false;\n\t\tj[\"parameters\"][\"nucleotide_based\"] = nucleotide_based_ ? true : false;\n\t\t\n\t\tj[\"parameters\"][\"chromosomes\"] = nlohmann::json::array();\n\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t{\n\t\t\tnlohmann::json chromosome_info;\n\t\t\t\n\t\t\tchromosome_info[\"index\"] = chromosome->Index();\n\t\t\tchromosome_info[\"id\"] = chromosome->ID();\n\t\t\tchromosome_info[\"symbol\"] = chromosome->Symbol();\n\t\t\tif (chromosome->Name().length() > 0)\n\t\t\t\tchromosome_info[\"name\"] = chromosome->Name();\n\t\t\tchromosome_info[\"type\"] = StringForChromosomeType(chromosome->Type());\n\t\t\t\n\t\t\tj[\"parameters\"][\"chromosomes\"].push_back(chromosome_info);\n\t\t\t\n\t\t\tif (p_chromosome_index == chromosome->Index())\t\t// true for the chromosome being written\n\t\t\t{\n\t\t\t\t// write out all the same information again in a key called \"this_chromosome\"; this way the\n\t\t\t\t// user can trivially get the info for the chromosome represented by the file; note that a\n\t\t\t\t// no-genetics model will have a chromosomes key with an empty array, and no this_chromosome,\n\t\t\t\t// but a no-genetics model can't write a tree sequence anyway, so that is moot.\n\t\t\t\tj[\"parameters\"][\"this_chromosome\"] = chromosome_info;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (p_include_model)\n\t\t\tj[\"parameters\"][\"model\"] = scriptString;\t\t\t\t// made model optional in file_version 0.4\n\t\tj[\"parameters\"][\"model_hash\"] = scriptHashString;\t\t\t// added model_hash in file_version 0.4\n\t\tj[\"parameters\"][\"seed\"] = community_.original_seed_;\n\t\t\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"16\"][\"name\"] = \"SLIM_TSK_INDIVIDUAL_ALIVE\";\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"16\"][\"description\"] = \"the individual was alive at the time the file was written\";\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"17\"][\"name\"] = \"SLIM_TSK_INDIVIDUAL_REMEMBERED\";\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"17\"][\"description\"] = \"the individual was requested by the user to be permanently remembered\";\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"18\"][\"name\"] = \"SLIM_TSK_INDIVIDUAL_RETAINED\";\n\t\tj[\"metadata\"][\"individuals\"][\"flags\"][\"18\"][\"description\"] = \"the individual was requested by the user to be retained only if its nodes continue to exist in the tree sequence\";\n\t\t\n\t\t// We save this information out only for runs at the command line.  This data might not be available on\n\t\t// all platforms; when it is unavailable, the key will be omitted.  We always have elapsed wall time.\n#ifndef SLIMGUI\n\t\tdouble user_time, sys_time;\n\t\tsize_t peak_RSS = Eidos_GetPeakRSS();\n\t\t\n\t\tEidos_GetUserSysTime(&user_time, &sys_time);\n\t\t\n\t\tj[\"resources\"][\"elapsed_time\"] = Eidos_WallTimeSeconds();\n\t\tif (user_time > 0.0)\n\t\t\tj[\"resources\"][\"user_time\"] = user_time;\n\t\tif (sys_time > 0.0)\n\t\t\tj[\"resources\"][\"sys_time\"] = sys_time;\n\t\tif (peak_RSS > 0)\n\t\t\tj[\"resources\"][\"max_memory\"] = peak_RSS;\n#endif\n\t\t\n\t\tif (p_use_newlines)\n\t\t\tprovenance_str = j.dump(4);\n\t\telse\n\t\t\tprovenance_str = j.dump();\n\t} catch (const std::exception &e) {\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteProvenanceTable): a JSON string could not be generated for tree-sequence provenance due to an error: '\" << e.what() << \"'.\" << EidosTerminate();\n\t} catch (...) {\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteProvenanceTable): a JSON string could not be generated for tree-sequence provenance due to an unknown error.\" << EidosTerminate();\n\t}\n\t\n\t//std::cout << \"Provenance output: \\n\" << provenance_str << std::endl;\n\t\n\ttime(&timer);\n\ttm_info = localtime(&timer);\n\tstrftime(buffer, timestamp_size, \"%Y-%m-%dT%H:%M:%S\", tm_info);\n\t\n\tret = tsk_provenance_table_add_row(&p_tables->provenances, buffer, (tsk_size_t)strlen(buffer), provenance_str.c_str(), (tsk_size_t)provenance_str.length());\n\tif (ret < 0) handle_error(\"tsk_provenance_table_add_row\", ret);\n}\n\nvoid Species::_MungeIsNullNodeMetadataToIndex0(TreeSeqInfo &p_treeseq, int original_chromosome_index)\n{\n\t// This shifts is_vacant metadata bits in the node table from an original index (the chromosome index\n\t// being loaded from a file) to a final index of 0 (destined for a single-chromosome model).  This\n\t// is done by allocating a whole new metadata buffer, because in the general case the size of the\n\t// metadata records might actually be changing -- if the file has more than one byte of is_vacant\n\t// information per record.  So we will make new metadata and replace the old.  The new metadata\n\t// buffer uses one byte of is_vacant data, always, since we're loading into a single-chromosome model.\n\t// Note that this means the metadata schema might change too!\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\ttsk_node_table_t &node_table = tables.nodes;\n\tHaplosomeMetadataRec *new_metadata_buffer = (HaplosomeMetadataRec *)calloc(node_table.num_rows, sizeof(HaplosomeMetadataRec));\n\t\n\t// these are for accessing the is_vacant bit in the original metadata\n\tint byte_index = original_chromosome_index / 8;\n\tint bit_shift = original_chromosome_index % 8;\n\t\n\tfor (tsk_size_t row = 0; row < node_table.num_rows; ++row)\n\t{\n\t\tsize_t node_metadata_length = node_table.metadata_offset[row + 1] - node_table.metadata_offset[row];\n\t\tsize_t expected_min_metadata_length = sizeof(HaplosomeMetadataRec) + byte_index;\t// 1 byte already counted in HaplosomeMetadataRec\n\t\t\n\t\t// check that the length is sufficient for the bits of original_index\n\t\tif (node_metadata_length < expected_min_metadata_length)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unexpected node metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tHaplosomeMetadataRec *node_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[row]);\n\t\tHaplosomeMetadataRec *new_metadata = new_metadata_buffer + row;\n\t\t\n\t\tnew_metadata->haplosome_id_ = node_metadata->haplosome_id_;\n\t\t\n\t\tif ((node_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01)\n\t\t\tnew_metadata->is_vacant_[0] = 0x01;\n\t}\n\t\n\t// Now change the offsets to the new offsets; we do not allocate a new buffer,\n\t// because we just need the same number of rows that we already have.\n\tfor (tsk_size_t row = 0; row <= node_table.num_rows; ++row)\n\t\tnode_table.metadata_offset[row] = row * sizeof(HaplosomeMetadataRec);\n\t\n\ttsk_safe_free(node_table.metadata);\n\t\n\tnode_table.metadata = (char *)new_metadata_buffer;\n\tnode_table.metadata_length = node_table.num_rows * sizeof(HaplosomeMetadataRec);\n\tnode_table.max_metadata_length = node_table.metadata_length;\n\t\n\t// need to fix the schema, because the number of bytes may have changed\n\tstd::string tsk_node_metadata_schema = gSLiM_tsk_node_metadata_schema_FORMAT;\n\tsize_t pos = tsk_node_metadata_schema.find(\"\\\"%d\\\"\");\n\tstd::string count_string = std::to_string(haplosome_metadata_is_vacant_bytes_);\n\t\n\tif (pos == std::string::npos)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_MungeIsNullNodeMetadataToIndex0): (internal error) `%d` substring missing from gSLiM_tsk_node_metadata_schema_FORMAT.\" << EidosTerminate();\n\t\n\ttsk_node_metadata_schema.replace(pos, 4, count_string);\t\t// replace %d in the format string with the byte count\n\t\n\tint ret = tsk_node_table_set_metadata_schema(&node_table,\n\t\t\t\t\t\t\t\t\t\t\t\t tsk_node_metadata_schema.c_str(),\n\t\t\t\t\t\t\t\t\t\t\t\t (tsk_size_t)tsk_node_metadata_schema.length());\n\tif (ret != 0)\n\t\thandle_error(\"tsk_node_table_set_metadata_schema\", ret);\n}\n\nvoid Species::ReadTreeSequenceMetadata(TreeSeqInfo &p_treeseq, slim_tick_t *p_tick, slim_tick_t *p_cycle, SLiMModelType *p_model_type, int *p_file_version)\n{\n\t// New provenance reading code, using the JSON for Modern C++ library (json.hpp); this\n\t// applies to file versions > 0.1.  The version 0.1 code was removed 24 Feb. 2025.\n\t\n\ttsk_table_collection_t &p_tables = p_treeseq.tables_;\n\tstd::string model_type_str;\n\tstd::string cycle_stage_str;\n\tlong long tick_ll, gen_ll;\n\tint this_chromosome_id;\n\tint this_chromosome_index;\n\tstd::string this_chromosome_symbol;\n\tstd::string this_chromosome_type;\n\tbool chomosomes_key_present = false;\n\t\n\ttry {\n\t\t////////////\n\t\t// Format 0.5 and later: using top-level metadata\n\t\t\n\t\t// Note: we *could* parse the metadata schema, but instead we'll just try parsing the metadata.\n\t\t// std::string metadata_schema_str(p_tables->metadata_schema, p_tables->metadata_schema_length);\n\t\t// nlohmann::json metadata_schema = nlohmann::json::parse(metadata_schema_str);\n\n\t\tstd::string metadata_str(p_tables.metadata, p_tables.metadata_length);\n\t\tauto metadata = nlohmann::json::parse(metadata_str);\n\t\t\n\t\t//std::cout << metadata.dump(4) << std::endl;\n\t\t\n\t\tif (!metadata[\"SLiM\"].contains(\"file_version\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the required metadata key 'file_version' is missing; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tauto file_version = metadata[\"SLiM\"][\"file_version\"];\n\t\t\n\t\tif ((file_version == SLIM_TREES_FILE_VERSION_PRENUC) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_POSTNUC) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_HASH) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_META) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_PREPARENT) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_PRESPECIES) ||\n\t\t\t(file_version == SLIM_TREES_FILE_VERSION_SPECIES))\n\t\t{\n\t\t\t// SLiM 5.0 breaks backward compatibility with earlier file versions\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the version of this file appears to be too old to be read, or the file is corrupted; you can try using pyslim to bring an old file version forward to the current version, or generate a new file with the current version of SLiM or pyslim.\" << EidosTerminate();\n\t\t}\n\t\telse if (file_version == SLIM_TREES_FILE_VERSION)\n\t\t{\n\t\t\t*p_file_version = 9;\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): this .trees file was generated by an unrecognized version of SLiM or pyslim (internal file version \" << file_version << \"); this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\t// We test for some keys if they are new or optional, but assume that others must be there, such as \"model_type\".\n\t\t// If we fetch a key and it is missing, nhlohmann::json raises and we end up in the provenance fallback code below.\n\t\t// That indicates that we're reading an old file version, which we no longer support in SLiM 5.\n\t\t// BCH 2/24/2025: I'm shifting towards testing for every key before fetching, in order to give better error messages.\n\t\tif (!metadata[\"SLiM\"].contains(\"model_type\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the required metadata key 'model_type' is missing; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tmodel_type_str = metadata[\"SLiM\"][\"model_type\"];\n\t\t\n\t\tif (!metadata[\"SLiM\"].contains(\"tick\"))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the required metadata key 'tick' is missing; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\ttick_ll = metadata[\"SLiM\"][\"tick\"];\n\t\t\n\t\t// \"cycle\" is optional and now defaults to the tick (it used to fall back to the old \"generation\" key)\n\t\tif (metadata[\"SLiM\"].contains(\"cycle\"))\n\t\t\tgen_ll = metadata[\"SLiM\"][\"cycle\"];\n\t\telse\n\t\t\tgen_ll = tick_ll;\n\t\t\n\t\t// \"stage\" is optional, and is used below only for validation; it provides an extra layer of safety\n\t\tif (metadata[\"SLiM\"].contains(\"stage\"))\n\t\t\tcycle_stage_str = metadata[\"SLiM\"][\"stage\"];\n\t\t\n\t\t/*if (metadata[\"SLiM\"].contains(\"name\"))\n\t\t{\n\t\t\t// If a species name is present, it must match our own name; can't load data across species, as a safety measure\n\t\t\t// If users find this annoying, it can be relaxed; nothing really depends on it\n\t\t\t// BCH 5/12/2022: OK, it is already annoying; disabling this check for now\n\t\t\tstd::string metadata_name = metadata[\"SLiM\"][\"name\"];\n\t\t\t\n\t\t\tif (metadata_name != name_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): this .trees file represents a species named \" << metadata_name << \", which does not match the name of the target species, \" << name_ << \"; species names must match.\" << EidosTerminate();\n\t\t}*/\n\t\t\n\t\tif (metadata[\"SLiM\"].contains(\"description\"))\n\t\t{\n\t\t\t// If a species description is present and non-empty, it replaces our own description\n\t\t\tstd::string metadata_description = metadata[\"SLiM\"][\"description\"];\n\t\t\t\n\t\t\tif (metadata_description.length())\n\t\t\t\tdescription_ = metadata_description;\n\t\t}\n\t\t\n\t\t// The \"this_chromosome\" key is required, as are the keys within it\n\t\tauto &this_chromosome_metadata = metadata[\"SLiM\"][\"this_chromosome\"];\n\t\t\n\t\tif (!this_chromosome_metadata.is_object())\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the 'this_chromosome' metadata key must be a JSON object.\" << std::endl;\n\t\tif (!this_chromosome_metadata.contains(\"id\"))\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'id' is missing from the 'this_chromosome' metadata entry.\" << std::endl;\n\t\tif (!this_chromosome_metadata.contains(\"index\"))\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'index' is missing from the 'this_chromosome' metadata entry.\" << std::endl;\n\t\tif (!this_chromosome_metadata.contains(\"symbol\"))\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'symbol' is missing from the 'this_chromosome' metadata entry.\" << std::endl;\n\t\tif (!this_chromosome_metadata.contains(\"type\"))\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'type' is missing from the 'this_chromosome' metadata entry.\" << std::endl;\n\t\t\n\t\tthis_chromosome_id = this_chromosome_metadata[\"id\"];\n\t\tthis_chromosome_index = this_chromosome_metadata[\"index\"];\n\t\tthis_chromosome_symbol = this_chromosome_metadata[\"symbol\"];\n\t\tthis_chromosome_type = this_chromosome_metadata[\"type\"];\n\t\t\n\t\t// The \"chromosomes\" key is optional, but if provided, it has to make sense\n\t\tif (metadata[\"SLiM\"].contains(\"chromosomes\"))\n\t\t{\n\t\t\tchomosomes_key_present = true;\n\t\t\t\n\t\t\t// We validate the whole \"chromosomes\" key against the whole model, to make sure everything is as expected\n\t\t\tauto &chromosomes_metadata = metadata[\"SLiM\"][\"chromosomes\"];\n\t\t\t\n\t\t\tif (!chromosomes_metadata.is_array())\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the 'chromosomes' metadata key must be an array.\" << std::endl;\n\t\t\tif (chromosomes_metadata.size() != Chromosomes().size())\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the number of entries in the 'chromosomes' metadata key does not match the number of chromosomes in the model.\" << std::endl;\n\t\t\t\n\t\t\tfor (std::size_t chromosomes_index = 0; chromosomes_index < Chromosomes().size(); ++chromosomes_index)\n\t\t\t{\n\t\t\t\tChromosome *chromosome = Chromosomes()[chromosomes_index];\n\t\t\t\tauto &one_chromosome_metadata = chromosomes_metadata[chromosomes_index];\n\t\t\t\t\n\t\t\t\tif (!one_chromosome_metadata.contains(\"id\"))\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'id' is missing from a 'chromosomes' metadata entry; if 'chromosomes' is provided at all, it must be complete.\" << std::endl;\n\t\t\t\tif (!one_chromosome_metadata.contains(\"symbol\"))\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'symbol' is missing from a 'chromosomes' metadata entry; if 'chromosomes' is provided at all, it must be complete.\" << std::endl;\n\t\t\t\tif (!one_chromosome_metadata.contains(\"type\"))\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the required metadata key 'type' is missing from a 'chromosomes' metadata entry; if 'chromosomes' is provided at all, it must be complete.\" << std::endl;\n\t\t\t\t\n\t\t\t\tint one_chromosome_id = one_chromosome_metadata[\"id\"];\n\t\t\t\tstd::string one_chromosome_symbol = one_chromosome_metadata[\"symbol\"];\n\t\t\t\tstd::string one_chromosome_type = one_chromosome_metadata[\"type\"];\n\t\t\t\t\n\t\t\t\tif (one_chromosome_id != chromosome->ID())\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the id for the entry at index \" << chromosomes_index << \" in the 'chromosomes' metadata key does not match the corresponding chromosome in the model.\" << std::endl;\n\t\t\t\tif (one_chromosome_symbol != chromosome->Symbol())\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the symbol for the entry at index \" << chromosomes_index << \" in the 'chromosomes' metadata key does not match the corresponding chromosome in the model.\" << std::endl;\n\t\t\t\tif (one_chromosome_type != chromosome->TypeString())\n\t\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the type for the entry at index \" << chromosomes_index << \" in the 'chromosomes' metadata key does not match the corresponding chromosome in the model.\" << std::endl;\n\t\t\t}\n\t\t}\n\t} catch (...) {\n\t\t///////////////////////\n\t\t// Previous formats: everything is in provenance\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the version of this file appears to be too old to be read, or the file is corrupted; you can try using pyslim to bring an old file version forward to the current version, or generate a new file with the current version of SLiM.\" << EidosTerminate();\n\t}\n\t\n\t// check the model type; at the moment we do not require the model type to match what we are running, but we issue a warning on a mismatch\n\tif (((model_type_str == \"WF\") && (model_type_ != SLiMModelType::kModelTypeWF)) ||\n\t\t((model_type_str == \"nonWF\") && (model_type_ != SLiMModelType::kModelTypeNonWF)))\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the model type of the .trees file (\" << model_type_str << \") does not match the current model type.\" << std::endl;\n\t}\n\t\n\tif (model_type_str == \"WF\")\n\t\t*p_model_type = SLiMModelType::kModelTypeWF;\n\telse if (model_type_str == \"nonWF\")\n\t\t*p_model_type = SLiMModelType::kModelTypeNonWF;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): unrecognized model type ('\" << model_type_str << \"'); this file cannot be read.\" << EidosTerminate();\n\t\n\t// bounds-check the cycle and tick\n\tif ((gen_ll < 1) || (gen_ll > SLIM_MAX_TICK))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): cycle value (\" << gen_ll << \") out of range; this file cannot be read.\" << EidosTerminate();\n\tif ((tick_ll < 1) || (tick_ll > SLIM_MAX_TICK))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): tick value (\" << tick_ll << \") out of range; this file cannot be read.\" << EidosTerminate();\n\t\n\t*p_tick = (slim_tick_t)tick_ll;\n\t*p_cycle = (slim_tick_t)gen_ll;\n\t\n\t// check the cycle stage for a match, warn on mismatch; this is new in SLiM 4, seems like a good idea\n\tif (cycle_stage_str.length())\n\t{\n\t\tif (cycle_stage_str == \"first\")\n\t\t{\n\t\t\tif ((community_.CycleStage() != SLiMCycleStage::kWFStage0ExecuteFirstScripts) &&\n\t\t\t\t(community_.CycleStage() != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts))\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the cycle stage of the .trees file ('first') does not match the current cycle stage.\" << std::endl;\n\t\t}\n\t\telse if (cycle_stage_str == \"early\")\n\t\t{\n\t\t\tif ((community_.CycleStage() != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) &&\n\t\t\t\t(community_.CycleStage() != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts))\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the cycle stage of the .trees file ('early') does not match the current cycle stage.\" << std::endl;\n\t\t}\n\t\telse if (cycle_stage_str == \"late\")\n\t\t{\n\t\t\tif ((community_.CycleStage() != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t\t\t(community_.CycleStage() != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\t\t\tSLIM_ERRSTREAM << \"#WARNING (Species::ReadTreeSequenceMetadata): the cycle stage of the .trees file ('late') does not match the current cycle stage.\" << std::endl;\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): a cycle stage is given in metadata, but its value ('\" << cycle_stage_str << \"') is unrecognized.\" << EidosTerminate();\n\t}\n\t\n\t// check the \"this_chromosome\" metadata information against the chromosome that p_treeseq says we're reading\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\t\n\tif (this_chromosome_id != chromosome->ID())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the chromosome id provided in the 'this_chromosome' key (\" << this_chromosome_id << \") does not match the id (\" << chromosome->ID() << \") of the corresponding chromosome in the model.\" << EidosTerminate();\n\tif (this_chromosome_type != chromosome->TypeString())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the chromosome type provided in the 'this_chromosome' key (\" << this_chromosome_type << \") does not match the type (\" << chromosome->TypeString() << \") of the corresponding chromosome in the model.\" << EidosTerminate();\n\tif (this_chromosome_symbol != chromosome->Symbol())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the chromosome symbol provided in the 'this_chromosome' key (\" << this_chromosome_symbol << \") does not match the symbol (\" << chromosome->Symbol() << \") of the corresponding chromosome in the model.\" << EidosTerminate();\n\t\n\t// Check the chromosome index; when loading a multi-chromosome set, we normally require indices to match\n\t// - one exception is that you can load a chromosome from any index into a single-chromosome model\n\t// - another exception is that, as a special nod to assembling a set of externally-generated (i.e., msprime)\n\t//   simulations into a multi-chromosome set, we allow the index to be 0 in \"this_chromosome\", if and only if\n\t//   the \"chromosomes\" key is not present; the file then represents a single chromosome that doesn't know\n\t//   that it's part of a larger set.\n\t// In both of these exceptional cases, we need to make sure that we look up bits in the is_vacant flags of\n\t// node metadata using the chromosome index stated in the file being loaded, NOT the chromosome index that the\n\t// data is being loaded into!  In the first case, we can simply munge the node table metadata right now, to\n\t// have the is_vacant bits in the position for index 0.  In the second case, it is much trickier because we\n\t// have a shared node table, and we need to fix the is_vacant bits in the shared table as well.\n\tif (this_chromosome_index != chromosome->Index())\n\t{\n\t\tif (Chromosomes().size() == 1)\n\t\t{\n\t\t\t// We are loading into a single-chromosome model.  We need to munge the incoming is_vacant \n\t\t\t// metadata to move is_vacant flags from the file's index down to index 0.\n\t\t\t_MungeIsNullNodeMetadataToIndex0(p_treeseq, this_chromosome_index);\n\t\t}\n\t\telse if ((this_chromosome_index == 0) && !chomosomes_key_present)\n\t\t{\n\t\t\t// We are loading a file that has is_vacant information at index 0, into a different index\n\t\t\t// in a multi-chromosome model.  This is allowed when chomosomes_key_present is false,\n\t\t\t// because this is the pattern we get from loading an msprime simulation in without\n\t\t\t// setting up all the multi-chrom metadata completely.  Doing this requires that we do more\n\t\t\t// complex munging, which is not yet supported.  In particular, we will need to modify the\n\t\t\t// shared node table, not just the node table being loaded; and we will need to in some way\n\t\t\t// manage the equality check between the shared node table and our node table, which would\n\t\t\t// fail since they will not match (due to the presence of other chromosomes).\n\t\t\t// FIXME MULTICHROM: I need a test case before I can do this; waiting for one from Peter.\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): (internal error) loading into a different chromosome index is not yet supported.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ReadTreeSequenceMetadata): the chromosome index provided in the 'this_chromosome' key (\" << this_chromosome_index << \") does not match the index (\" << (unsigned int)(chromosome->Index()) << \") of the corresponding chromosome in the model.\" << EidosTerminate();\n\t}\n}\n\nvoid Species::_CreateDirectoryForMultichromArchive(std::string resolved_user_path, bool p_overwrite_directory)\n{\n\t// Eidos_CreateDirectory() errors if the path already exists, but for WriteTreeSequence(),\n\t// we want to replace an existing directory (but not a file); it would be too annoying\n\t// if we didn't, for successive runs of the same model.  The archive is, in effect, one\n\t// file.  However, we want to be very careful in doing this, since it is dangerous!\n\tint resolved_user_path_length = (int)resolved_user_path.length();\n\tbool resolved_user_path_ends_in_slash = (resolved_user_path_length > 0) && (resolved_user_path[resolved_user_path_length-1] == '/');\n\t\n\tstruct stat file_info;\n\tbool path_exists = (stat(resolved_user_path.c_str(), &file_info) == 0);\n\t\n\tif (path_exists)\n\t{\n\t\tbool is_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\n\t\tif (is_directory)\n\t\t{\n\t\t\tif (!p_overwrite_directory)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path; you may pass overwriteDirectory=T to override this error and replace the existing directory, but note that this is quite a dangerous operation (treeSeqOutput() will still refuse to overwrite the existing directory if it contains any files besides .trees files, for additional safety).\" << EidosTerminate();\n\t\t\t\n\t\t\t// remove() requires that the directory be empty, so we need to remove all files inside it.\n\t\t\t// For safety, we first pass over all files and verify that they are not directories, and\n\t\t\t// that their filenames all end in .trees.  If there is any other cruft inside the directory,\n\t\t\t// we will refuse to delete it.\n\t\t\tDIR *dp = opendir(resolved_user_path.c_str());\n\t\t\t\n\t\t\tif (dp != NULL)\n\t\t\t{\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\terrno = 0;\n\t\t\t\t\tstruct dirent *ep = readdir(dp);\n\t\t\t\t\tint error = errno;\n\t\t\t\t\t\n\t\t\t\t\tif (!ep)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (error)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be read.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tstd::string interior_filename_base = ep->d_name;\n\t\t\t\t\t\n\t\t\t\t\tif ((interior_filename_base == \".\") || (interior_filename_base == \"..\"))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\tstd::string interior_filename = resolved_user_path + (resolved_user_path_ends_in_slash ? \"\" : \"/\") + interior_filename_base;\t\t// NOLINT(*-inefficient-string-concatenation) : this is fine\n\t\t\t\t\t\n\t\t\t\t\tbool file_exists = (stat(interior_filename.c_str(), &file_info) == 0);\n\t\t\t\t\t\n\t\t\t\t\tif (!file_exists)\n\t\t\t\t\t{\n\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be read.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tis_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\t\t\t\n\t\t\t\t\tif (is_directory)\n\t\t\t\t\t{\n\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and contains a subdirectory within it (\" << interior_filename_base << \"); overwriting the path is not safe.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\tif (!Eidos_string_hasSuffix(interior_filename, \".trees\") && (interior_filename_base != \".DS_Store\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and contains a file within it (\" << interior_filename_base << \") that is not a .trees file; overwriting the path is not safe.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t(void)closedir(dp);\n\t\t\t\t\n\t\t\t\t// OK, everything in the directory seems eligible for removal; let's try.  Note that the logic\n\t\t\t\t// below duplicates the logic above, to avoid race conditions in which the filesystem changes.\n\t\t\t\tdp = opendir(resolved_user_path.c_str());\n\t\t\t\t\n\t\t\t\tif (dp != NULL)\n\t\t\t\t{\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n\t\t\t\t\t\terrno = 0;\n\t\t\t\t\t\tstruct dirent *ep = readdir(dp);\n\t\t\t\t\t\tint error = errno;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!ep)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (error)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be read.\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string interior_filename_base = ep->d_name;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((interior_filename_base == \".\") || (interior_filename_base == \"..\"))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string interior_filename = resolved_user_path + (resolved_user_path_ends_in_slash ? \"\" : \"/\") + interior_filename_base;\t\t// NOLINT(*-inefficient-string-concatenation) : this is fine\n\t\t\t\t\t\t\n\t\t\t\t\t\tbool file_exists = (stat(interior_filename.c_str(), &file_info) == 0);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!file_exists)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be read.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tis_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (is_directory)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and contains a subdirectory within it (\" << interior_filename_base << \"); overwriting the path is not safe.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!Eidos_string_hasSuffix(interior_filename, \".trees\") && (interior_filename_base != \".DS_Store\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and contains a file within it (\" << interior_filename_base << \") that is not a .trees file; overwriting the path is not safe.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbool success = (remove(interior_filename.c_str()) == 0);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!success)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and contains a file within it (\" << interior_filename_base << \") that could not be removed.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be overwritten.\" << EidosTerminate();\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be overwritten.\" << EidosTerminate();\n\t\t\t\n\t\t\tbool success = (remove(resolved_user_path.c_str()) == 0);\n\t\t\t\n\t\t\tif (!success)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a directory already exists at that path and could not be removed.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because a file already exists at that path.\" << EidosTerminate();\n\t}\n\t\n\t// If we made it to here, there should no longer be a directory at resolved_user_path\n\tstd::string error_string;\n\tbool success = Eidos_CreateDirectory(resolved_user_path, &error_string);\n\t\n\t// Fatal error if we can't create the directory\n\tif (error_string.length())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", because of error: \" << error_string << \".\" << EidosTerminate();\n\telse if (!success)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): directory could not be created at path \" << resolved_user_path << \", for unknown reasons.\" << EidosTerminate();\n}\n\nvoid Species::WriteTreeSequence(std::string &p_recording_tree_path, bool p_simplify, bool p_include_model, EidosDictionaryUnretained *p_metadata_dict, bool p_overwrite_directory)\n{\n\tint ret = 0;\n\tbool is_multichrom = (chromosomes_.size() > 1);\n\t\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// If this is a single-chromosome species, then write out the single tree sequence to the path;\n\t// otherwise, create p_recording_tree_path as a directory, and write out to that directory\n\t// Standardize the path, resolving a leading ~ and maybe other things\n\tstd::string resolved_user_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(p_recording_tree_path));\n\t\n\tif (is_multichrom)\n\t{\n\t\t// For a multichromosome archive, we need to create the directory to hold it.  This call\n\t\t// will raise if there are any problems in doing so.\n\t\t_CreateDirectoryForMultichromArchive(resolved_user_path, p_overwrite_directory);\n\t}\n\t\n\t// Add a population (i.e., subpopulation) table to the table collection; subpopulation information\n\t// comes from the time of output.  This needs to happen before simplify/sort.  We write the population\n\t// table once, into treeseq_[0], and then share it into the other tree sequences below.  Note that\n\t// SimplifyAllTreeSequences() also writes the population table, so this call is redundant when\n\t// p_simplify is true, but I'm leaving it this way for redundancy, to prevent future bugs, and\n\t// because I'm not 100% certain that we didn't do it this way originally for a good reason.  :->\n\tWritePopulationTable(&treeseq_[0].tables_);\n\t\n\t// First we simplify, on the original table collection; we considered doing this on the copy,\n\t// but then the copy takes longer and the simplify's work is lost, and there doesn't seem to\n\t// be a compelling case for leaving the original tables unsimplified.  Note that Peter has done\n\t// a check that calling treeSeqOutput() in the middle of a run does not change the result, although\n\t// it *does* change the order of the rows; see https://github.com/MesserLab/SLiM/issues/209\n\tif (p_simplify)\n\t{\n\t\tSimplifyAllTreeSequences();\n\t}\n\t\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\tTreeSeqInfo &chromosome_tsinfo = treeseq_[chromosome_index];\n\t\ttsk_table_collection_t &chromosome_tables = chromosome_tsinfo.tables_;\n\t\t\n\t\t// Copy in the shared tables (node, individual, population) at this point, so the shared tables then get\n\t\t// copied below; we will be modifying the tables, and don't want our modification to go into the original\n\t\t// shared tables, which we are not allowed to change.\n\t\tif (chromosome_index > 0)\n\t\t\tCopySharedTablesIn(chromosome_tables);\n\t\t\n\t\t// Copy the table collection so that modifications we do for writing don't affect the original tables.\n\t\t// Note that there's a lot of work below to clean up the individuals table and node table for saving.\n\t\t// Those tables are shared.  We don't want to do this cleanup in the original tables, since that would\n\t\t// modify our recording state I guess; but I think this cleanup will be the same for every chromosome,\n\t\t// so technically we could do this work just once, I think (?), and share the processed tables across\n\t\t// all the chromosomes.  I've chosen not to pursue that idea, because I don't see a path to doing it\n\t\t// without increasing the high-water mark for the memory usage of this code, which is very important\n\t\t// to keep low.  Anyhow, maybe this is unimportant since it is only overhead at save time, and is\n\t\t// probably not a hotspot.\n\t\ttsk_table_collection_t output_tables;\n\t\tret = tsk_table_collection_copy(&chromosome_tables, &output_tables, 0);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_copy\", ret);\n\t\t\n\t\t// We can unshare the shared tables in the original table collection immediately, zeroing them out.\n\t\tif (chromosome_index > 0)\n\t\t\tDisconnectCopiedSharedTables(chromosome_tables);\n\t\t\n\t\t// Sort and deduplicate; we don't need to do this if we simplified above, since simplification does these steps\n\t\tif (!p_simplify)\n\t\t{\n\t\t\tint flags = TSK_NO_CHECK_INTEGRITY;\n#if DEBUG\n\t\t\tflags = 0;\n#endif\n\t\t\tret = tsk_table_collection_sort(&output_tables, /* edge_start */ NULL, /* flags */ flags);\n\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_sort\", ret);\n\t\t\t\n\t\t\t// Remove redundant sites we added\n\t\t\tret = tsk_table_collection_deduplicate_sites(&output_tables, 0);\n\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_deduplicate_sites\", ret);\n\t\t}\n\t\t\n\t\t// Add in the mutation.parent information; valid tree sequences need parents, but we don't keep them while running\n\t\tret = tsk_table_collection_build_index(&output_tables, 0);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_build_index\", ret);\n\t\tret = tsk_table_collection_compute_mutation_parents(&output_tables, TSK_NO_CHECK_INTEGRITY);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_compute_mutation_parents\", ret);\n\t\t\n\t\t{\n\t\t\t// Create a local hash table for pedigree IDs to individuals table indices.  If we simplified, that validated\n\t\t\t// tabled_individuals_hash_ as a side effect, so we can copy that as a base; otherwise, we make one from scratch.\n\t\t\t// Note that this hash table is used only for AddLiveIndividualsToIndividualsTable() below; after that we reorder\n\t\t\t// the individuals table, so we'll make another hash table for AddParentsColumnForOutput(), unfortunately.\n\t\t\tINDIVIDUALS_HASH local_individuals_lookup;\n\t\t\t\n\t\t\tif (p_simplify)\n\t\t\t\tlocal_individuals_lookup = tabled_individuals_hash_;\t\t// copies\n\t\t\telse\n\t\t\t\tBuildTabledIndividualsHash(&output_tables, &local_individuals_lookup);\n\t\t\t\n\t\t\t// Add information about the current cycle to the individual table; \n\t\t\t// this modifies \"remembered\" individuals, since information comes from the\n\t\t\t// time of output, not creation\n\t\t\tAddLiveIndividualsToIndividualsTable(&output_tables, &local_individuals_lookup);\n\t\t}\n\t\t\n\t\t// We need the individual table's order, for alive individuals, to match that of\n\t\t// SLiM so that when we read back in it doesn't cause a reordering as a side effect\n\t\t// all other individuals in the table will be retained, at the end\n\t\tstd::vector<int> individual_map;\n\t\t\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\t\n\t\t\tfor (Individual *individual : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\ttsk_id_t node_id = individual->TskitNodeIdBase();\n\t\t\t\ttsk_id_t ind_id = output_tables.nodes.individual[node_id];\n\t\t\t\t\n\t\t\t\tindividual_map.emplace_back(ind_id);\n\t\t\t}\n\t\t}\n\t\t\n\t\tReorderIndividualTable(&output_tables, individual_map, true);\n\t\t\n\t\t// Now that the table is reordered, we can build the parents column of the individuals table\n\t\t// This requires a new pedigree id to tskid lookup table, which we construct here.\n\t\t{\n\t\t\tINDIVIDUALS_HASH local_individuals_lookup;\n\t\t\t\n\t\t\tBuildTabledIndividualsHash(&output_tables, &local_individuals_lookup);\n\t\t\tAddParentsColumnForOutput(&output_tables, &local_individuals_lookup);\n\t\t}\n\t\t\n\t\t// Rebase the times in the nodes to be in tskit-land; see _InstantiateSLiMObjectsFromTables() for the inverse operation\n\t\t// BCH 4/4/2019: switched to using tree_seq_tick_ to avoid a parent/child timestamp conflict\n\t\t// This makes sense; as far as tree-seq recording is concerned, tree_seq_tick_ is the time counter\n\t\tslim_tick_t time_adjustment = community_.tree_seq_tick_;\n\t\t\n\t\tfor (size_t node_index = 0; node_index < output_tables.nodes.num_rows; ++node_index)\n\t\t\toutput_tables.nodes.time[node_index] += time_adjustment;\n\t\t\n\t\tfor (size_t mut_index = 0; mut_index < output_tables.mutations.num_rows; ++mut_index)\n\t\t\toutput_tables.mutations.time[mut_index] += time_adjustment;\n\t\t\n\t\t// Add a row to the Provenance table to record current state; text format does not allow newlines in the entry,\n\t\t// so we don't prettyprint the JSON when going to text, as a quick fix that avoids quoting the newlines etc.\n\t\tWriteProvenanceTable(&output_tables, /* p_use_newlines */ true, p_include_model, chromosome->Index());\n\t\t\n\t\t// Add top-level metadata and metadata schema\n\t\tWriteTreeSequenceMetadata(&output_tables, p_metadata_dict, chromosome->Index());\n\t\t\n\t\t// Set the simulation time unit, in case that is useful to someone.  This is set up in initializeTreeSeq().\n\t\tret = tsk_table_collection_set_time_units(&output_tables, community_.treeseq_time_unit_.c_str(), community_.treeseq_time_unit_.length());\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_set_time_units\", ret);\n\t\t\n\t\t// Write out the copied tables\n\t\t{\n\t\t\t// derived state data must be in ASCII (or unicode) on disk, according to tskit policy\n\t\t\tDerivedStatesToAscii(&output_tables);\n\t\t\t\n\t\t\t// In nucleotide-based models, put an ASCII representation of the reference sequence into the tables\n\t\t\tif (nucleotide_based_)\n\t\t\t{\n\t\t\t\tstd::size_t buflen = chromosome->AncestralSequence()->size();\n\t\t\t\tchar *buffer = (char *)malloc(buflen);\n\t\t\t\t\n\t\t\t\tif (!buffer)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::WriteTreeSequence): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tchromosome->AncestralSequence()->WriteNucleotidesToBuffer(buffer);\n\t\t\t\t\n\t\t\t\tret = tsk_reference_sequence_takeset_data(&output_tables.reference_sequence, buffer, buflen);\t\t// tskit now owns buffer\n\t\t\t\tif (ret < 0) handle_error(\"tsk_reference_sequence_takeset_data\", ret);\n\t\t\t}\n\t\t\t\n\t\t\t// With one chromosome, we write out to resolved_user_path directly; with more than one, we\n\t\t\t// created a directory at resolved_user_path above, and now we generate a generic filename\n\t\t\tstd::string output_path;\n\t\t\t\n\t\t\tif (chromosomes_.size() == 1)\n\t\t\t\toutput_path = resolved_user_path;\n\t\t\telse\n\t\t\t\toutput_path = resolved_user_path + \"/chromosome_\" + chromosome->Symbol() + \".trees\";\n\t\t\t\n\t\t\tret = tsk_table_collection_dump(&output_tables, output_path.c_str(), 0);\n\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_dump\", ret);\n\t\t}\n\t\t\n\t\t// Done with our tables copy\n\t\tret = tsk_table_collection_free(&output_tables);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_free\", ret);\n\t}\n}\n\n\nvoid Species::FreeTreeSequence()\n{\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::FreeTreeSequence): (internal error) FreeTreeSequence() called when tree-sequence recording is not enabled.\" << EidosTerminate();\n\t\n\tif (tables_initialized_)\n\t{\n\t\t// Free any tree-sequence recording stuff that has been allocated; called when Species is getting deallocated,\n\t\t// and also when we're wiping the slate clean with something like readFromPopulationFile().\n\t\tbool first = true;\n\t\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t\t{\n\t\t\t// the node, individual, and population tables are shared; avoid doing a double free\n\t\t\t// (I don't think any of the shared tables should be copied at this point anyway,\n\t\t\t// though; maybe there should be an assert here to that effect?)\n\t\t\tif (!first)\n\t\t\t\tDisconnectCopiedSharedTables(tsinfo.tables_);\n\t\t\t\n\t\t\ttsk_table_collection_free(&tsinfo.tables_);\n\t\t\tfirst = false;\n\t\t}\n\t\t\n\t\ttreeseq_.resize(0);\n\t\t\n\t\tremembered_nodes_.clear();\n\t\ttabled_individuals_hash_.clear();\n\t\ttables_initialized_ = false;\n\t}\n}\n\nvoid Species::RecordAllDerivedStatesFromSLiM(void)\n{\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::RecordAllDerivedStatesFromSLiM): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// This method does nothing but record mutations, so...\n\tif (!recording_mutations_)\n\t\treturn;\n\t\n\t// This is called when new tree sequence tables need to be built to correspond to the current state of SLiM, such as\n\t// after handling a readFromPopulationFile() call.  It is guaranteed by the caller of this method that any old tree\n\t// sequence recording stuff has been freed with a call to FreeTreeSequence(), and then a new recording session has\n\t// been initiated with AllocateTreeSequenceTables(); it might be good for this method to do a sanity check that all\n\t// of the recording tables are indeed allocated but empty, I guess.  Every extant individual and haplosome has been\n\t// recorded already, with calls to SetCurrentNewIndividual() and RecordNewHaplosome(), in the readPopulationFile()\n\t// code. Our job is just to record the mutations (\"derived states\") in the SLiM data into the tree sequence.  Note\n\t// that new mutations will not be added one at a time, when they are stacked; each block of stacked mutations in a\n\t// haplosome will be added with a single derived state call here.\n\tint haplosome_count_per_individual = HaplosomeCountPerIndividual();\n\t\n\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\n\t\tfor (Individual *individual : subpop->parent_individuals_)\n\t\t{\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = individual->haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\thaplosome->record_derived_states(this);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Species::MetadataForMutation(Mutation *p_mutation, MutationMetadataRec *p_metadata)\n{\n\tstatic_assert(sizeof(MutationMetadataRec) == 17, \"MutationMetadataRec has changed size; this code probably needs to be updated\");\n\t\n\tif (!p_mutation || !p_metadata)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MetadataForMutation): (internal error) bad parameters to MetadataForMutation().\" << EidosTerminate();\n\t\n\tp_metadata->mutation_type_id_ = p_mutation->mutation_type_ptr_->mutation_type_id_;\n\tp_metadata->selection_coeff_ = p_mutation->selection_coeff_;\n\tp_metadata->subpop_index_ = p_mutation->subpop_index_;\n\tp_metadata->origin_tick_ = p_mutation->origin_tick_;\n\tp_metadata->nucleotide_ = p_mutation->nucleotide_;\n}\n\nvoid Species::MetadataForSubstitution(Substitution *p_substitution, MutationMetadataRec *p_metadata)\n{\n\tstatic_assert(sizeof(MutationMetadataRec) == 17, \"MutationMetadataRec has changed size; this code probably needs to be updated\");\n\t\n\tif (!p_substitution || !p_metadata)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MetadataForSubstitution): (internal error) bad parameters to MetadataForSubstitution().\" << EidosTerminate();\n\t\n\tp_metadata->mutation_type_id_ = p_substitution->mutation_type_ptr_->mutation_type_id_;\n\tp_metadata->selection_coeff_ = p_substitution->selection_coeff_;\n\tp_metadata->subpop_index_ = p_substitution->subpop_index_;\n\tp_metadata->origin_tick_ = p_substitution->origin_tick_;\n\tp_metadata->nucleotide_ = p_substitution->nucleotide_;\n}\n\nvoid Species::MetadataForIndividual(Individual *p_individual, IndividualMetadataRec *p_metadata)\n{\n\tstatic_assert(sizeof(IndividualMetadataRec) == 40, \"IndividualMetadataRec has changed size; this code probably needs to be updated\");\n\t\n\tif (!p_individual || !p_metadata)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::MetadataForIndividual): (internal error) bad parameters to MetadataForIndividual().\" << EidosTerminate();\n\t\n\tp_metadata->pedigree_id_ = p_individual->PedigreeID();\n\tp_metadata->pedigree_p1_ = p_individual->Parent1PedigreeID();\n\tp_metadata->pedigree_p2_ = p_individual->Parent2PedigreeID();\n\tp_metadata->age_ = p_individual->age_;\n\tp_metadata->subpopulation_id_ = p_individual->subpopulation_->subpopulation_id_;\n\tp_metadata->sex_ = (int32_t)p_individual->sex_;\t\t// IndividualSex, but int32_t in the record\n\t\n\tp_metadata->flags_ = 0;\n\tif (p_individual->migrant_)\n\t\tp_metadata->flags_ |= SLIM_INDIVIDUAL_METADATA_MIGRATED;\n}\n\nvoid Species::CheckTreeSeqIntegrity(void)\n{\n\t// Here we call tskit to check the integrity of the tree-sequence tables themselves – not against\n\t// SLiM's parallel data structures (done in CrosscheckTreeSeqIntegrity()), just on their own.\n\tfor (TreeSeqInfo &tsinfo : treeseq_)\n\t{\n\t\t// BCH 2/25/2025: We need to share tables in, for chromosomes after the first\n\t\tif (tsinfo.chromosome_index_ > 0)\n\t\t\tCopySharedTablesIn(tsinfo.tables_);\n\t\t\n\t\tint ret = tsk_table_collection_check_integrity(&tsinfo.tables_, TSK_NO_CHECK_POPULATION_REFS);\n\t\tif (ret < 0) handle_error(\"tsk_table_collection_check_integrity()\", ret);\n\t\t\n\t\tif (tsinfo.chromosome_index_ > 0)\n\t\t\tDisconnectCopiedSharedTables(tsinfo.tables_);\n\t}\n}\n\nvoid Species::CrosscheckTreeSeqIntegrity(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Species::CrosscheckTreeSeqIntegrity(): illegal when parallel\");\n\t\n#if DEBUG\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) tree sequence recording method called with recording off.\" << EidosTerminate();\n#endif\n\t\n\t// first crosscheck the substitutions multimap against SLiM's substitutions vector\n\t{\n\t\tstd::vector<Substitution *> vector_subs = population_.substitutions_;\n\t\tstd::vector<Substitution *> multimap_subs;\n\t\t\n\t\tfor (auto entry : population_.treeseq_substitutions_map_)\n\t\t\tmultimap_subs.emplace_back(entry.second);\n\t\t\n\t\tstd::sort(vector_subs.begin(), vector_subs.end());\n\t\tstd::sort(multimap_subs.begin(), multimap_subs.end());\n\t\t\n\t\tif (vector_subs != multimap_subs)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) mismatch between SLiM substitutions and the treeseq substitution multimap.\" << EidosTerminate();\n\t}\n\t\n\t// crosscheck haplosomes and mutations one chromosome at a time\n\tfor (Chromosome *chromosome : chromosomes_)\n\t{\n\t\tint chromosome_index = chromosome->Index();\n\t\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\t\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\ttsk_table_collection_t &chromosome_tables = treeseq_[chromosome_index].tables_;\n\t\t\n\t\t// get all haplosomes from all subpopulations for the focal chromosome; we will cross-check them all simultaneously\n\t\tstatic std::vector<Haplosome *> haplosomes;\n\t\thaplosomes.resize(0);\n\t\t\n\t\tfor (auto pop_iter : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = pop_iter.second;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **ind_haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\thaplosomes.emplace_back(ind_haplosomes[haplosome_index]);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if we have no haplosomes to check, we return; we could check that the tree sequences are also empty, but we don't\n\t\tsize_t haplosome_count = haplosomes.size();\n\t\t\n\t\tif (haplosome_count == 0)\n\t\t\tcontinue;\n\t\t\n\t\t// check for correspondence between SLiM's haplosomes and the tree_seq's nodes, including their metadata\n\t\t// FIXME unimplemented\n\t\t\n\t\t// if we're recording mutations, we can check all of them\n\t\tif (recording_mutations_)\n\t\t{\n\t\t\t// prepare to walk all the haplosomes by making HaplosomeWalker objects for them all\n\t\t\tstatic std::vector<HaplosomeWalker> haplosome_walkers;\n\t\t\thaplosome_walkers.clear();\n\t\t\thaplosome_walkers.reserve(haplosome_count);\n\t\t\t\n\t\t\tfor (Haplosome *haplosome : haplosomes)\n\t\t\t\thaplosome_walkers.emplace_back(haplosome);\n\t\t\t\n\t\t\t// Copy in the shared tables (node, individual, population) at this point, so the shared tables then get\n\t\t\t// copied below; we will be modifying the tables, and don't want our modification to go into the original\n\t\t\t// shared tables, which we are not allowed to change.\n\t\t\tif (chromosome_index > 0)\n\t\t\t\tCopySharedTablesIn(chromosome_tables);\n\t\t\t\n\t\t\t// Copy the table collection so that modifications we do for crosscheck don't affect the original tables.\n\t\t\t// FIXME this could be stack-local rather than malloced; not making that change now to keep the diffs simpler\n\t\t\tint ret;\n\t\t\ttsk_table_collection_t *tables_copy;\n\t\t\t\n\t\t\ttables_copy = (tsk_table_collection_t *)malloc(sizeof(tsk_table_collection_t));\n\t\t\tif (!tables_copy)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tret = tsk_table_collection_copy(&chromosome_tables, tables_copy, 0);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_table_collection_copy()\", ret);\n\t\t\t\n\t\t\t// We can unshare the shared tables in the original table collection immediately, zeroing them out.\n\t\t\tif (chromosome_index > 0)\n\t\t\t\tDisconnectCopiedSharedTables(chromosome_tables);\n\t\t\t\n\t\t\t// our tables copy needs to have a population table now, since this is required to build a tree sequence\n\t\t\t// we could build this once and reuse it across all the calls to this method for different chromosomes,\n\t\t\t// but I think's probably not worth the trouble; the overhead should be small.\n\t\t\tWritePopulationTable(tables_copy);\n\t\t\t\n\t\t\t// simplify before making our tree_sequence object; the sort and deduplicate and compute parents are required for the crosscheck, whereas the simplify\n\t\t\t// could perhaps be removed, which would cause the iteration over variants to visit a bunch of stuff unrelated to the current individuals.\n\t\t\t// this code is adapted from Species::_SimplifyTreeSequence(), but we don't need to update the TSK map table or the table position,\n\t\t\t// and we simplify down to just the extant individuals since we can't cross-check older individuals anyway...\n\t\t\tif (tables_copy->nodes.num_rows != 0)\n\t\t\t{\n\t\t\t\tstd::vector<tsk_id_t> samples;\n\t\t\t\t\n\t\t\t\tfor (auto iter : population_.subpops_)\n\t\t\t\t{\n\t\t\t\t\tSubpopulation *subpop = iter.second;\n\t\t\t\t\t\n\t\t\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome **ind_haplosomes = ind->haplosomes_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t\t\t\t\tsamples.emplace_back(ind->TskitNodeIdBase() + ind_haplosomes[haplosome_index]->chromosome_subposition_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttsk_flags_t flags = TSK_NO_CHECK_INTEGRITY;\n#if DEBUG\n\t\t\t\tflags = 0;\n#endif\n\t\t\t\tret = tsk_table_collection_sort(tables_copy, /* edge_start */ NULL, /* flags */ flags);\n\t\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_sort\", ret);\n\t\t\t\t\n\t\t\t\tret = tsk_table_collection_deduplicate_sites(tables_copy, 0);\n\t\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_deduplicate_sites\", ret);\n\t\t\t\t\n\t\t\t\t// crosscheck is not going to be parallelized, so we use different flags for simplify here than in\n\t\t\t\t// Species::_SimplifyTreeSequence(); in particular, we let it filter nodes and individuals for us\n\t\t\t\t// BCH 3/13/2025: changing TSK_SIMPLIFY_KEEP_UNARY to TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS,\n\t\t\t\t// since it is the correct flag; see discussion in https://github.com/MesserLab/SLiM/issues/487\n\t\t\t\tflags = TSK_SIMPLIFY_FILTER_SITES | TSK_SIMPLIFY_FILTER_INDIVIDUALS | TSK_SIMPLIFY_KEEP_INPUT_ROOTS;\n\t\t\t\tif (!retain_coalescent_only_) flags |= TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS;\n\t\t\t\t\n\t\t\t\tret = tsk_table_collection_simplify(tables_copy, samples.data(), (tsk_size_t)samples.size(), flags, NULL);\n\t\t\t\tif (ret != 0) handle_error(\"tsk_table_collection_simplify\", ret);\n\t\t\t\t\n\t\t\t\t// must build indexes before compute mutation parents\n\t\t\t\tret = tsk_table_collection_build_index(tables_copy, 0);\n\t\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_build_index\", ret);\n\t\t\t\t\n\t\t\t\tret = tsk_table_collection_compute_mutation_parents(tables_copy, TSK_NO_CHECK_INTEGRITY);\n\t\t\t\tif (ret < 0) handle_error(\"tsk_table_collection_compute_mutation_parents\", ret);\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t// allocate and set up the tree_sequence object that contains all the tree sequences\n\t\t\ttsk_treeseq_t *ts;\n\t\t\t\n\t\t\tts = (tsk_treeseq_t *)malloc(sizeof(tsk_treeseq_t));\n\t\t\tif (!ts)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tret = tsk_treeseq_init(ts, tables_copy, TSK_TS_INIT_BUILD_INDEXES);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_treeseq_init()\", ret);\n\t\t\t\n\t\t\t// allocate and set up the variant object we'll update as we walk along the sequence\n\t\t\ttsk_variant_t variant;\n\t\t\t\n\t\t\tret = tsk_variant_init(\n\t\t\t\t\t\t\t\t   &variant, ts, NULL, 0, NULL, TSK_ISOLATED_NOT_MISSING);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_variant_init()\", ret);\n\t\t\t\n\t\t\t// crosscheck by looping through variants\n\t\t\tfor (tsk_size_t i = 0; i < ts->tables->sites.num_rows; i++)\n\t\t\t{\n\t\t\t\tret = tsk_variant_decode(&variant, (tsk_id_t)i, 0);\n\t\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_variant_decode()\", ret);\n\t\t\t\t\n\t\t\t\t// Check this variant against SLiM.  A variant represents a site at which a tracked mutation exists.\n\t\t\t\t// The tsk_variant_t will tell us all the allelic states involved at that site, what the alleles are, and which haplosomes\n\t\t\t\t// in the sample are using them.  We will then check that all the haplosomes that the variant claims to involve have\n\t\t\t\t// the allele the variant attributes to them, and that no haplosomes contain any alleles at the position that are not\n\t\t\t\t// described by the variant.  The variants are returned in sorted order by position, so we can keep pointers into\n\t\t\t\t// every extant haplosome's mutruns, advance those pointers a step at a time, and check that everything matches at every\n\t\t\t\t// step.  Keep in mind that some mutations may have been fixed (substituted) or lost.\n\t\t\t\tslim_position_t variant_pos_int = (slim_position_t)variant.site.position;\t\t// should be no loss of precision, fingers crossed\n\t\t\t\t\n\t\t\t\t// Get all the substitutions involved at this site, which should be present in every sample\n\t\t\t\tauto substitution_range_iter = population_.treeseq_substitutions_map_.equal_range(variant_pos_int);\n\t\t\t\tstatic std::vector<slim_mutationid_t> fixed_mutids;\n\t\t\t\t\n\t\t\t\tfixed_mutids.resize(0);\n\t\t\t\tfor (auto substitution_iter = substitution_range_iter.first; substitution_iter != substitution_range_iter.second; ++substitution_iter)\n\t\t\t\t\tfixed_mutids.emplace_back(substitution_iter->second->mutation_id_);\n\t\t\t\t\n\t\t\t\t// Check all the haplosomes against the variant's belief about this site\n\t\t\t\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosomeWalker &haplosome_walker = haplosome_walkers[haplosome_index];\n\t\t\t\t\tint32_t haplosome_variant = variant.genotypes[haplosome_index];\n\t\t\t\t\ttsk_size_t haplosome_allele_length = variant.allele_lengths[haplosome_variant];\n\t\t\t\t\t\n\t\t\t\t\tif (haplosome_allele_length % sizeof(slim_mutationid_t) != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) variant allele had length that was not a multiple of sizeof(slim_mutationid_t).\" << EidosTerminate();\n\t\t\t\t\thaplosome_allele_length /= sizeof(slim_mutationid_t);\n\t\t\t\t\t\n\t\t\t\t\t//std::cout << \"variant for haplosome: \" << (int)haplosome_variant << \" (allele length == \" << haplosome_allele_length << \")\" << std::endl;\n\t\t\t\t\t\n\t\t\t\t\t// BCH 4/29/2018: null haplosomes shouldn't ever contain any mutations, including fixed mutations\n\t\t\t\t\tif (haplosome_walker.WalkerHaplosome()->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (haplosome_allele_length == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) null haplosome has non-zero treeseq allele length \" << haplosome_allele_length << \".\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// (1) if the variant's allele is zero-length, we do nothing (if it incorrectly claims that a haplosome contains no\n\t\t\t\t\t// mutation, we'll catch that later)  (2) if the variant's allele is the length of one mutation id, we can simply\n\t\t\t\t\t// check that the next mutation in the haplosome in question exists and has the right mutation id; (3) if the variant's\n\t\t\t\t\t// allele has more than one mutation id, we have to check them all against all the mutations at the given position\n\t\t\t\t\t// in the haplosome in question, which is a bit annoying since the lists may not be in the same order.  Note that if\n\t\t\t\t\t// the variant is for a mutation that has fixed, it will not be present in the haplosome; we check for a substitution\n\t\t\t\t\t// with the right ID.\n\t\t\t\t\tslim_mutationid_t *haplosome_allele = (slim_mutationid_t *)variant.alleles[haplosome_variant];\n\t\t\t\t\t\n\t\t\t\t\tif (haplosome_allele_length == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If there are no fixed mutations at this site, we can continue; haplosomes that have a mutation at this site will\n\t\t\t\t\t\t// raise later when they realize they have been skipped over, so we don't have to check for that now...\n\t\t\t\t\t\tif (fixed_mutids.size() == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) the treeseq has 0 mutations at position \" << variant_pos_int << \", SLiM has \" << fixed_mutids.size() << \" fixed mutation(s).\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\telse if (haplosome_allele_length == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The tree has just one mutation at this site; this is the common case, so we try to handle it quickly\n\t\t\t\t\t\tslim_mutationid_t allele_mutid = *haplosome_allele;\n\t\t\t\t\t\tMutation *current_mut = haplosome_walker.CurrentMutation();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (current_mut)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tslim_position_t current_mut_pos = current_mut->position_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_mut_pos < variant_pos_int)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) haplosome mutation was not represented in trees (single case).\" << EidosTerminate();\n\t\t\t\t\t\t\tif (current_mut->position_ > variant_pos_int)\n\t\t\t\t\t\t\t\tcurrent_mut = nullptr;\t// not a candidate for this position, we'll see it again later\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!current_mut && (fixed_mutids.size() == 1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We have one fixed mutation and no segregating mutation, versus one mutation in the tree; crosscheck\n\t\t\t\t\t\t\tif (allele_mutid != fixed_mutids[0])\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) the treeseq has mutid \" << allele_mutid << \" at position \" << variant_pos_int << \", SLiM has a fixed mutation of id \" << fixed_mutids[0] << EidosTerminate();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcontinue;\t// the match was against a fixed mutation, so don't go to the next mutation\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (current_mut && (fixed_mutids.size() == 0))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We have one segregating mutation and no fixed mutation, versus one mutation in the tree; crosscheck\n\t\t\t\t\t\t\tif (allele_mutid != current_mut->mutation_id_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) the treeseq has mutid \" << allele_mutid << \" at position \" << variant_pos_int << \", SLiM has a segregating mutation of id \" << current_mut->mutation_id_ << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We have a count mismatch; there is one mutation in the tree, but we have !=1 in SLiM including substitutions\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) haplosome/allele size mismatch at position \" << variant_pos_int << \": the treeseq has 1 mutation of mutid \" << allele_mutid << \", SLiM has \" << (current_mut ? 1 : 0) << \" segregating and \" << fixed_mutids.size() << \" fixed mutation(s).\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_walker.NextMutation();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Check the next mutation to see if it's at this position as well, and is missing from the tree;\n\t\t\t\t\t\t// this would get caught downstream, but for debugging it is clearer to catch it here\n\t\t\t\t\t\tMutation *next_mut = haplosome_walker.CurrentMutation();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (next_mut && next_mut->position_ == variant_pos_int)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) the treeseq is missing a stacked mutation with mutid \" << next_mut->mutation_id_ << \" at position \" << variant_pos_int << \".\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t\telse // (haplosome_allele_length > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tstatic std::vector<slim_mutationid_t> allele_mutids;\n\t\t\t\t\t\tstatic std::vector<slim_mutationid_t> haplosome_mutids;\n\t\t\t\t\t\tallele_mutids.resize(0);\n\t\t\t\t\t\thaplosome_mutids.resize(0);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// tabulate all tree mutations\n\t\t\t\t\t\tfor (tsk_size_t mutid_index = 0; mutid_index < haplosome_allele_length; ++mutid_index)\n\t\t\t\t\t\t\tallele_mutids.emplace_back(haplosome_allele[mutid_index]);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// tabulate segregating SLiM mutations\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *current_mut = haplosome_walker.CurrentMutation();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (current_mut)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslim_position_t current_mut_pos = current_mut->position_;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (current_mut_pos < variant_pos_int)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) haplosome mutation was not represented in trees (bulk case).\" << EidosTerminate();\n\t\t\t\t\t\t\t\telse if (current_mut_pos == variant_pos_int)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thaplosome_mutids.emplace_back(current_mut->mutation_id_);\n\t\t\t\t\t\t\t\t\thaplosome_walker.NextMutation();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// tabulate fixed SLiM mutations\n\t\t\t\t\t\thaplosome_mutids.insert(haplosome_mutids.end(), fixed_mutids.begin(), fixed_mutids.end());\n\t\t\t\t\t\t\n\t\t\t\t\t\t// crosscheck, sorting so there is no order-dependency\n\t\t\t\t\t\tif (allele_mutids.size() != haplosome_mutids.size())\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) haplosome/allele size mismatch at position \" << variant_pos_int << \": the treeseq has \" << allele_mutids.size() << \" mutations, SLiM has \" << (haplosome_mutids.size() - fixed_mutids.size()) << \" segregating and \" << fixed_mutids.size() << \" fixed mutation(s).\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::sort(allele_mutids.begin(), allele_mutids.end());\n\t\t\t\t\t\tstd::sort(haplosome_mutids.begin(), haplosome_mutids.end());\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (tsk_size_t mutid_index = 0; mutid_index < haplosome_allele_length; ++mutid_index)\n\t\t\t\t\t\t\tif (allele_mutids[mutid_index] != haplosome_mutids[mutid_index])\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) haplosome/allele bulk mutid mismatch.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// we have finished all variants, so all the haplosomes we're tracking should be at their ends; any left-over mutations\n\t\t\t// should have been in the trees but weren't, so this is an error\n\t\t\tfor (size_t haplosome_index = 0; haplosome_index < haplosome_count; haplosome_index++)\n\t\t\t\tif (!haplosome_walkers[haplosome_index].Finished())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) mutations left in haplosome beyond those in tree.\" << EidosTerminate();\n\t\t\t\n\t\t\t// free\n\t\t\tret = tsk_variant_free(&variant);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_variant_free()\", ret);\n\t\t\t\n\t\t\tret = tsk_treeseq_free(ts);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_treeseq_free()\", ret);\n\t\t\tfree(ts);\n\t\t\t\n\t\t\tret = tsk_table_collection_free(tables_copy);\n\t\t\tif (ret != 0) handle_error(\"CrosscheckTreeSeqIntegrity tsk_table_collection_free()\", ret);\n\t\t\tfree(tables_copy);\n\t\t}\n\t}\n\t\n\t// check that tabled_individuals_hash_ is the right size and has all the right entries\n\tif (recording_tree_)\n\t{\n\t\ttsk_individual_table_t &shared_individuals_table = treeseq_[0].tables_.individuals;\n\t\t\n\t\tif (shared_individuals_table.num_rows != tabled_individuals_hash_.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) tabled_individuals_hash_ size (\" << tabled_individuals_hash_.size() << \") does not match the individuals table size (\" << shared_individuals_table.num_rows << \").\" << EidosTerminate();\n\t\t\n\t\tfor (tsk_size_t individual_index = 0; individual_index < shared_individuals_table.num_rows; individual_index++)\n\t\t{\n\t\t\ttsk_id_t tsk_individual = (tsk_id_t)individual_index;\n\t\t\tIndividualMetadataRec *metadata_rec = (IndividualMetadataRec *)(shared_individuals_table.metadata + shared_individuals_table.metadata_offset[tsk_individual]);\n\t\t\tslim_pedigreeid_t pedigree_id = metadata_rec->pedigree_id_;\n\t\t\tauto lookup = tabled_individuals_hash_.find(pedigree_id);\n\n\t\t\tif (lookup == tabled_individuals_hash_.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) missing entry for a pedigree id in tabled_individuals_hash_.\" << EidosTerminate();\n\n\t\t\ttsk_id_t lookup_tskid = lookup->second;\n\n\t\t\tif (tsk_individual != lookup_tskid)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::CrosscheckTreeSeqIntegrity): (internal error) incorrect entry for a pedigree id in tabled_individuals_hash_.\" << EidosTerminate();\n\t\t}\n\t}\n}\n\nvoid Species::__CheckPopulationMetadata(TreeSeqInfo &p_treeseq)\n{\n\t// check population table metadata\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tchar *pop_schema_ptr = tables.populations.metadata_schema;\n\ttsk_size_t pop_schema_len = tables.populations.metadata_schema_length;\n\tstd::string pop_schema(pop_schema_ptr, pop_schema_len);\n\t\n\tif (pop_schema == gSLiM_tsk_population_metadata_schema_PREJSON)\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): the population metadata schema is old; this version of the .trees format is no longer supported by SLiM.\" << EidosTerminate(nullptr);\n\t}\n\telse\n\t{\n\t\t// If it is not in the pre-JSON format, check that it is JSON; we don't accept binary non-JSON metadata.\n\t\t// This is necessary because we will carry this metadata over when we output a new population table on save;\n\t\t// this metadata must be compatible with our schema, which is a JSON schema.  Note that we do not check that\n\t\t// the schema exactly matches our current schema string, however; we are permissive about that, by design.\n\t\t// See https://github.com/MesserLab/SLiM/issues/169 for discussion about schema checking/compatibility.\n\t\tnlohmann::json pop_schema_json;\n\t\t\n\t\ttry {\n\t\t\tpop_schema_json = nlohmann::json::parse(pop_schema);\n\t\t} catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): the population metadata schema does not parse as a valid JSON string.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tif (pop_schema_json[\"codec\"] != \"json\")\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): the population metadata schema must be JSON.\" << EidosTerminate(nullptr);\n\t}\n}\n\n// We need a reverse hash to construct the remapped population table\n#if EIDOS_ROBIN_HOOD_HASHING\ntypedef robin_hood::unordered_flat_map<slim_objectid_t, int64_t> SUBPOP_REMAP_REVERSE_HASH;\n#elif STD_UNORDERED_MAP_HASHING\ntypedef std::unordered_map<slim_objectid_t, int64_t> SUBPOP_REMAP_REVERSE_HASH;\n#endif\n\nvoid Species::__RemapSubpopulationIDs(SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq, __attribute__ ((unused)) int p_file_version)\n{\n\t// If we have been given a remapping table, this method munges all of the data\n\t// and metadata in the treeseq tables to accomplish that remapping.  It is gross\n\t// to have to do this on the raw table data, but we need that data to be corrected\n\t// so that we can simulate forward from it.  Every subpop id referenced in the\n\t// tables must be remapped; if a map is given, it must remap everything.  We have\n\t// to check all metadata carefully, since this remap happens before other checks.\n\t// We handle both SLiM metadata and non-SLiM metadata correctly here if we can.\n\tif (p_subpop_map.size() > 0)\n\t{\n\t\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\t\tSUBPOP_REMAP_REVERSE_HASH subpop_reverse_hash;\t// from SLiM subpop id back to the table index read\n\t\tslim_objectid_t remapped_row_count = 0;\t\t\t// the number of rows we need in the remapped population table\n\t\tint ret = 0;\n\t\t\n\t\t// When remapping, we may encounter -1 as a subpopulation id.  This is actually TSK_NULL,\n\t\t// which is used in various contexts to represent \"unknown\" - as a source in the migration\n\t\t// table, as the subpop of origin for a mutation, etc.  Whenever we encounter such a\n\t\t// TSK_NULL, we just want to map it back to itself; so we will map -1 to -1.  This is\n\t\t// necessary because we raise when we see an unmapped subpopulation id.  We make a copy\n\t\t// of p_subpop_map so we don't modify the caller's map.\n\t\tSUBPOP_REMAP_HASH subpop_map = p_subpop_map;\n\t\t\n\t\tsubpop_map.emplace(-1, -1);\n\t\t\n\t\t// First we will scan the population table metadata to assess the situation\n\t\t{\n\t\t\ttsk_population_table_t &pop_table = tables.populations;\n\t\t\ttsk_size_t pop_count = pop_table.num_rows;\n\t\t\t\n\t\t\t// Start by checking that no remap entry references a population table index that is out of range\n\t\t\tif (pop_count == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): the population table is empty, and therefore cannot be remapped.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfor (auto &remap_entry : p_subpop_map)\n\t\t\t{\n\t\t\t\tint64_t table_index = remap_entry.first;\n\t\t\t\t//slim_objectid_t remapped_index = remap_entry.second;\n\t\t\t\t\n\t\t\t\t//std::cout << \"index \" << table_index << \" being remapped to \" << remapped_index << std::endl;\n\t\t\t\t\n\t\t\t\tif (table_index < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): (internal error) index \" << table_index << \" is out of range (less than zero).\" << EidosTerminate(nullptr);\n\t\t\t\tif (table_index >= (int64_t)pop_count)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): index \" << table_index << \" is out of range (last valid index \" << ((int64_t)pop_count - 1) << \").\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\t// OK, population table indices are in range; check the population table entry remappings one by one\n\t\t\tfor (tsk_size_t pop_index = 0; pop_index < pop_count; pop_index++)\n\t\t\t{\n\t\t\t\t// validate and parse metadata\n\t\t\t\tsize_t metadata_length = pop_table.metadata_offset[pop_index + 1] - pop_table.metadata_offset[pop_index];\n\t\t\t\t\n\t\t\t\tchar *metadata_char = pop_table.metadata + pop_table.metadata_offset[pop_index];\n\t\t\t\tstd::string metadata_string(metadata_char, metadata_length);\n\t\t\t\tnlohmann::json subpop_metadata;\n\t\t\t\tslim_objectid_t subpop_id = (slim_objectid_t)pop_index, remapped_id;\n\t\t\t\t\n\t\t\t\t// we require that metadata for every row be valid JSON; we have no way of\n\t\t\t\t// understanding, much less remapping, metadata in other (binary) formats\n\t\t\t\ttry {\n\t\t\t\t\tsubpop_metadata = nlohmann::json::parse(metadata_string);\n\t\t\t\t} catch (...) {\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata does not parse as a valid JSON string; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (subpop_metadata.is_null())\n\t\t\t\t{\n\t\t\t\t\t// 'null' rows in the population table correspond to unused subpop IDs\n\t\t\t\t\tauto remap_iter = subpop_map.find(subpop_id);\n\t\t\t\t\t\n\t\t\t\t\t// null lines are usually not remapped, so we don't require a remap here, but if\n\t\t\t\t\t// they are referenced by other data then they will have to be, so we allow it\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\tremapped_id = remap_iter->second;\n\t\t\t\t}\n\t\t\t\telse if (!subpop_metadata.is_object())\n\t\t\t\t{\n\t\t\t\t\t// if a row's metadata is not 'null', we require it to be a JSON \"object\"\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata does not parse as a JSON object; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\telse if (!subpop_metadata.contains(\"slim_id\"))\n\t\t\t\t{\n\t\t\t\t\t// this row has JSON metadata that does not have a \"slim_id\" key, so it is\n\t\t\t\t\t// not SLiM metadata; this is the \"carryover\" case and we will remap it\n\t\t\t\t\t// without any attempt to fix the contents of the metadata\n\t\t\t\t\t\n\t\t\t\t\t// since the metadata is not null, a remap is required; check for it and fetch it\n\t\t\t\t\tauto remap_iter = subpop_map.find(subpop_id);\n\t\t\t\t\t\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): subpopulation id \" << subpop_id << \" is used in the population table (for a non-SLiM 'carryover' subpopulation), but is not remapped in subpopMap.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tremapped_id = remap_iter->second;\n\t\t\t\t}\n\t\t\t\telse if (!subpop_metadata[\"slim_id\"].is_number_integer())\n\t\t\t\t{\n\t\t\t\t\t// if a row has JSON metadata with a \"slim_id\" key, its value must be an integer\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata key 'slim_id' is not the expected type (integer); this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// This row has JSON metadata with an integer \"slim_id\" key; it is\n\t\t\t\t\t// SLiM metadata so this row will end up being a SLiM subpopulation\n\t\t\t\t\t// and we will remap it and fix up its metadata\n\t\t\t\t\tslim_objectid_t slim_id = subpop_metadata[\"slim_id\"].get<slim_objectid_t>();\n\t\t\t\t\t\n\t\t\t\t\t// enforce the slim_id == index invariant here; removing this invariant would be\n\t\t\t\t\t// possible but would require a bunch of bookeeping and checks; see treerec/implementation.md\n                    // for more discussion of this\n\t\t\t\t\tif (slim_id != subpop_id)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata value for key 'slim_id' is not equal to the table index; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\t// since the metadata is not null, a remap is required; check for it and fetch it\n\t\t\t\t\tauto remap_iter = subpop_map.find(subpop_id);\n\t\t\t\t\t\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): subpopulation id \" << subpop_id << \" is used in the population table, but is not remapped in subpopMap.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tremapped_id = remap_iter->second;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// this remap seems good; do the associated bookkeeping\n\t\t\t\tif (remapped_id >= remapped_row_count)\n\t\t\t\t\tremapped_row_count = remapped_id + 1;\t// +1 so the count encompasses [0, remapped_id]\n\t\t\t\t\n\t\t\t\tsubpop_reverse_hash.emplace(std::pair<slim_objectid_t, int64_t>(remapped_id, subpop_id));\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Next we reorder the actual rows of the population table, using a copy of the table\n\t\t{\n\t\t\ttsk_id_t tsk_population_id;\n\t\t\ttsk_population_table_t *population_table_copy;\n\t\t\tpopulation_table_copy = (tsk_population_table_t *)malloc(sizeof(tsk_population_table_t));\n\t\t\tif (!population_table_copy)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\tret = tsk_population_table_copy(&tables.populations, population_table_copy, 0);\n\t\t\tif (ret != 0) handle_error(\"__RemapSubpopulationIDs tsk_population_table_copy()\", ret);\n\t\t\tret = tsk_population_table_clear(&tables.populations);\n\t\t\tif (ret != 0) handle_error(\"__RemapSubpopulationIDs tsk_population_table_clear()\", ret);\n\t\t\t\n\t\t\tfor (slim_objectid_t remapped_row_index = 0; remapped_row_index < remapped_row_count; ++remapped_row_index)\n\t\t\t{\n\t\t\t\tauto reverse_iter = subpop_reverse_hash.find(remapped_row_index);\n\t\t\t\t\n\t\t\t\tif (reverse_iter == subpop_reverse_hash.end())\n\t\t\t\t{\n\t\t\t\t\t// No remap hash entry for this row index, so it must be an empty row\n\t\t\t\t\ttsk_population_id = tsk_population_table_add_row(&tables.populations, \"null\", 4);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We have a remap entry; this could be an empty row, a SLiM subpop row, or a carryover row\n\t\t\t\t\ttsk_id_t original_row_index = (slim_objectid_t)reverse_iter->second;\n\t\t\t\t\tsize_t metadata_length = population_table_copy->metadata_offset[original_row_index + 1] - population_table_copy->metadata_offset[original_row_index];\n\t\t\t\t\tchar *metadata_char = population_table_copy->metadata + population_table_copy->metadata_offset[original_row_index];\n\t\t\t\t\tstd::string metadata_string(metadata_char, metadata_length);\n\t\t\t\t\tnlohmann::json subpop_metadata = nlohmann::json::parse(metadata_string);\n\t\t\t\t\t\n\t\t\t\t\tif (subpop_metadata.is_null())\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is a remap entry for this, but it is an empty row; no slim_id\n\t\t\t\t\t\ttsk_population_id = tsk_population_table_add_row(&tables.populations, \"null\", 4);\n\t\t\t\t\t}\n\t\t\t\t\telse if (!subpop_metadata.contains(\"slim_id\"))\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is a remap entry for this, with JSON metadata that has no slim_id;\n\t\t\t\t\t\t// this is carryover metadata, typically from msprime but who knows\n\t\t\t\t\t\t// We will remap msprime-style names like \"pop_0\", but *not* SLiM names like \"p0\"\n\t\t\t\t\t\t// We also permit the name to not be a string, in this code path, since\n\t\t\t\t\t\t// this metadata does not conform to our schema; we need to accept whatever it is\n\t\t\t\t\t\tstd::string msprime_name = std::string(\"pop_\").append(std::to_string(original_row_index));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (subpop_metadata.contains(\"name\") && subpop_metadata[\"name\"].is_string() && (subpop_metadata[\"name\"].get<std::string>() == msprime_name))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsubpop_metadata[\"name\"] = SLiMEidosScript::IDStringWithPrefix('p', remapped_row_index);\n\t\t\t\t\t\t\tmetadata_string = subpop_metadata.dump();\n\t\t\t\t\t\t\ttsk_population_id = tsk_population_table_add_row(&tables.populations, (char *)metadata_string.c_str(), (uint32_t)metadata_string.length());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttsk_population_id = tsk_population_table_add_row(&tables.populations, metadata_char, metadata_length);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is a remap entry for this, with JSON metadata that has a slim_id;\n\t\t\t\t\t\t// this is a SLiM subpop, so we need to re-generate the metadata to fix slim_id\n\t\t\t\t\t\tsubpop_metadata[\"slim_id\"] = remapped_row_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// We also need to fix the \"name\" metadata key when it equals the SLiM identifier\n\t\t\t\t\t\t// We fix msprime-style names like \"pop_0\" to the remapped \"pX\" name; see issue #173\n\t\t\t\t\t\tif (subpop_metadata.contains(\"name\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlohmann::json value = subpop_metadata[\"name\"];\n\t\t\t\t\t\t\tif (!value.is_string())\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata key 'name' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\tstd::string metadata_name = value.get<std::string>();\n\t\t\t\t\t\t\tstd::string id_name = SLiMEidosScript::IDStringWithPrefix('p', original_row_index);\n\t\t\t\t\t\t\tstd::string msprime_name = std::string(\"pop_\").append(std::to_string(original_row_index));\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((metadata_name == id_name) || (metadata_name == msprime_name))\n\t\t\t\t\t\t\t\tsubpop_metadata[\"name\"] = SLiMEidosScript::IDStringWithPrefix('p', remapped_row_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// And finally, if there are migration records (for WF models) we need to remap them\n\t\t\t\t\t\t// We check only what we need to check; __ConfigureSubpopulationsFromTables() does more\n\t\t\t\t\t\tsize_t migration_rec_count = 0;\n\t\t\t\t\t\tnlohmann::json migration_records;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (subpop_metadata.contains(\"migration_records\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlohmann::json value = subpop_metadata[\"migration_records\"];\n\t\t\t\t\t\t\tif (!value.is_array())\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata key 'migration_records' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\tmigration_records = value;\n\t\t\t\t\t\t\tmigration_rec_count = migration_records.size();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (migration_rec_count > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (size_t migration_index = 0; migration_index < migration_rec_count; ++migration_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnlohmann::json migration_rec = migration_records[migration_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (!migration_rec.is_object() || !migration_rec.contains(\"source_subpop\") || !migration_rec[\"source_subpop\"].is_number_integer())\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): population metadata migration record does not obey the metadata schema; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tslim_objectid_t old_subpop = migration_rec[\"source_subpop\"].get<slim_objectid_t>();\n\t\t\t\t\t\t\t\tauto remap_iter = subpop_map.find(old_subpop);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_subpop << \") used by the tree sequence data (migration record) was not remapped.\" << EidosTerminate();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tslim_objectid_t new_subpop = remap_iter->second;\n\t\t\t\t\t\t\t\tmigration_rec[\"source_subpop\"] = new_subpop;\n\t\t\t\t\t\t\t\tmigration_records[migration_index] = migration_rec;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tsubpop_metadata[\"migration_records\"] = migration_records;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// We've done all the necessary metadata tweaks; write it out\n\t\t\t\t\t\tmetadata_string = subpop_metadata.dump();\n\t\t\t\t\t\ttsk_population_id = tsk_population_table_add_row(&tables.populations, (char *)metadata_string.c_str(), (uint32_t)metadata_string.length());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check the tsk_population_id returned by tsk_population_table_add_row() above\n\t\t\t\tif (tsk_population_id < 0) handle_error(\"tsk_population_table_add_row\", tsk_population_id);\n\t\t\t\tassert(tsk_population_id == remapped_row_index);\n\t\t\t}\n\t\t\t\n\t\t\tret = tsk_population_table_free(population_table_copy);\n\t\t\tif (ret != 0) handle_error(\"tsk_population_table_free\", ret);\n\t\t\tfree(population_table_copy);\n\t\t}\n\t\t\n\t\t// BCH 30 May 2022: OK, now we deal with the other tables.  We have a few stakes here.  The metadata on those tables is\n\t\t// guaranteed to be SLiM metadata.  I am told that it is not correct to check the schemas for the tables against known SLiM\n\t\t// schemas; the incoming file has a SLiM file version on it, and that means that it is guaranteed by whoever made it to be\n\t\t// SLiM-compliant, and that means SLiM metadata throughout (except in the population table itself, where the fact that our\n\t\t// metadata is JSON means we can distinguish foreign metadata and carry it over intact, as in the code above; that is not\n\t\t// possible in other tables because the metadata is binary).  The only compliance check we do is that the length of each chunk\n\t\t// of metadata matches what we expect it to be (based upon SLiM's binary metadata formats and the file version); and if a\n\t\t// length doesn't match, we throw.  That is not really for the benefit of the caller, or to validate the incoming data; it is\n\t\t// only for our own debugging purposes, as an assert of what we already know is guaranteed to be true.  So, given this\n\t\t// understanding, we will now go into the tables and munge all of their metadata to refer to the remapped subpopulation ids.\n\t\t\n\t\t// Remap subpop_index_ in the mutation metadata, in place\n\t\t{\n\t\t\tstd::size_t metadata_rec_size = sizeof(MutationMetadataRec);\n\t\t\ttsk_mutation_table_t &mut_table = tables.mutations;\n\t\t\ttsk_size_t num_rows = mut_table.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t mut_index = 0; mut_index < num_rows; ++mut_index)\n\t\t\t{\n\t\t\t\tchar *metadata_bytes = mut_table.metadata + mut_table.metadata_offset[mut_index];\n\t\t\t\ttsk_size_t metadata_length = mut_table.metadata_offset[mut_index + 1] - mut_table.metadata_offset[mut_index];\n\t\t\t\t\n\t\t\t\tif (metadata_length % metadata_rec_size != 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): unexpected mutation metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tint stack_count = (int)(metadata_length / metadata_rec_size);\n\t\t\t\t\n\t\t\t\tfor (int stack_index = 0; stack_index < stack_count; ++stack_index)\n\t\t\t\t{\n\t\t\t\t\t// Here we have to deal with the metadata format\n\t\t\t\t\tMutationMetadataRec *metadata = (MutationMetadataRec *)metadata_bytes + stack_index;\n\t\t\t\t\tslim_objectid_t old_subpop = metadata->subpop_index_;\n\t\t\t\t\tauto remap_iter = subpop_map.find(old_subpop);\n\t\t\t\t\t\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_subpop << \") used by the tree sequence data (mutation metadata) was not remapped.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tmetadata->subpop_index_ = remap_iter->second;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Next we remap subpopulation_id_ in the individual metadata, in place\n\t\t{\n\t\t\ttsk_individual_table_t &ind_table = tables.individuals;\n\t\t\ttsk_size_t num_rows = ind_table.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t ind_index = 0; ind_index < num_rows; ++ind_index)\n\t\t\t{\n\t\t\t\tchar *metadata_bytes = ind_table.metadata + ind_table.metadata_offset[ind_index];\n\t\t\t\ttsk_size_t metadata_length = ind_table.metadata_offset[ind_index + 1] - ind_table.metadata_offset[ind_index];\n\t\t\t\t\n\t\t\t\tif (metadata_length != sizeof(IndividualMetadataRec))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): unexpected individual metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tIndividualMetadataRec *metadata = (IndividualMetadataRec *)metadata_bytes;\n\t\t\t\tslim_objectid_t old_subpop = metadata->subpopulation_id_;\n\t\t\t\tauto remap_iter = subpop_map.find(old_subpop);\n\t\t\t\t\n\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_subpop << \") used by the tree sequence data (individual metadata) was not remapped.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tmetadata->subpopulation_id_ = remap_iter->second;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Next we remap subpop ids in the population column of the node table, in place\n\t\t{\n\t\t\ttsk_node_table_t &node_table = tables.nodes;\n\t\t\ttsk_size_t num_rows = node_table.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t node_index = 0; node_index < num_rows; ++node_index)\n\t\t\t{\n\t\t\t\ttsk_id_t old_subpop = node_table.population[node_index];\n\t\t\t\tauto remap_iter = subpop_map.find(old_subpop);\n\t\t\t\t\n\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_subpop << \") used by the tree sequence data (node table) was not remapped.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tnode_table.population[node_index] = remap_iter->second;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// SLiM does not use the migration table, but we should remap it just\n\t\t// to keep the internal state of the tree sequence consistent\n\t\t{\n\t\t\ttsk_migration_table_t &migration_table = tables.migrations;\n\t\t\ttsk_size_t num_rows = migration_table.num_rows;\n\t\t\t\n\t\t\tfor (tsk_size_t node_index = 0; node_index < num_rows; ++node_index)\n\t\t\t{\n\t\t\t\t// remap source column\n\t\t\t\t{\n\t\t\t\t\ttsk_id_t old_source = migration_table.source[node_index];\n\t\t\t\t\tauto remap_iter = subpop_map.find(old_source);\n\t\t\t\t\t\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_source << \") used by the tree sequence data (migration table) was not remapped.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tmigration_table.source[node_index] = remap_iter->second;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// remap dest column\n\t\t\t\t{\n\t\t\t\t\ttsk_id_t old_dest = migration_table.dest[node_index];\n\t\t\t\t\tauto remap_iter = subpop_map.find(old_dest);\n\t\t\t\t\t\n\t\t\t\t\tif (remap_iter == subpop_map.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__RemapSubpopulationIDs): a subpopulation index (\" << old_dest << \") used by the tree sequence data (migration table) was not remapped.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tmigration_table.dest[node_index] = remap_iter->second;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntypedef struct ts_subpop_info {\n\tslim_popsize_t countMH_ = 0, countF_ = 0;\n\tstd::vector<IndividualSex> sex_;\n\tstd::vector<tsk_id_t> nodes_;\n\tstd::vector<slim_pedigreeid_t> pedigreeID_;\n\tstd::vector<slim_pedigreeid_t> pedigreeP1_;\n\tstd::vector<slim_pedigreeid_t> pedigreeP2_;\n\tstd::vector<slim_age_t> age_;\n\tstd::vector<double> spatial_x_;\n\tstd::vector<double> spatial_y_;\n\tstd::vector<double> spatial_z_;\n\tstd::vector<uint32_t> flags_;\n} ts_subpop_info;\n\nvoid Species::__PrepareSubpopulationsFromTables(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, TreeSeqInfo &p_treeseq)\n{\n\t// This reads the subpopulation table and creates ts_subpop_info records for the non-empty subpopulations\n\t// Doing this first allows us to check that individuals are going into subpopulations that we understand\n\t// The code here is duplicated to some extent in __ConfigureSubpopulationsFromTables(), which finalizes things\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\ttsk_population_table_t &pop_table = tables.populations;\n\ttsk_size_t pop_count = pop_table.num_rows;\n\t\n\tfor (tsk_size_t pop_index = 0; pop_index < pop_count; pop_index++)\n\t{\n\t\t// We want to allow \"carryover\" of metadata from other sources such as msprime, so we do not want to require\n\t\t// that metadata is SLiM metadata.  We only prepare to receive individuals in subpopulations with SLiM metadata,\n\t\t// though; other subpopulations must not contain any extant individuals.  See issue #318.\n\t\tsize_t metadata_length = pop_table.metadata_offset[pop_index + 1] - pop_table.metadata_offset[pop_index];\n\t\tchar *metadata_char = pop_table.metadata + pop_table.metadata_offset[pop_index];\n\t\tslim_objectid_t subpop_id = CheckSLiMPopulationMetadata(metadata_char, metadata_length);\n\t\t\n\t\t// -1 indicates that the metadata does not represent an extant SLiM subpopulation\n\t\tif (subpop_id == -1)\n\t\t\tcontinue;\n\t\t\n\t\t// bounds-check the subpop id; if a slim_id is present, we require it to be well-behaved\n\t\tif ((subpop_id < 0) || (subpop_id > SLIM_MAX_ID_VALUE))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__PrepareSubpopulationsFromTables): subpopulation id out of range (\" << subpop_id << \"); ids must be >= 0 and <= \" << SLIM_MAX_ID_VALUE << \".\" << EidosTerminate();\n\t\t\n\t\t// create the ts_subpop_info record for this subpop_id\n\t\tif (p_subpopInfoMap.find(subpop_id) != p_subpopInfoMap.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__PrepareSubpopulationsFromTables): subpopulation id (\" << subpop_id << \") occurred twice in the subpopulation table.\" << EidosTerminate();\n\t\tif (subpop_id != (int)pop_index)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__PrepareSubpopulationsFromTables): slim_id value \" << subpop_id << \" occurred at the wrong index in the subpopulation table; entries must be at their corresponding index.  This may result from simplification; if so, pass filter_populations=False to simplify().\" << EidosTerminate();\n\t\t\n\t\tp_subpopInfoMap.emplace(subpop_id, ts_subpop_info());\n\t}\n}\n\nvoid Species::__TabulateSubpopulationsFromTreeSequence(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, tsk_treeseq_t *p_ts, TreeSeqInfo &p_treeseq, SLiMModelType p_file_model_type)\n{\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\tChromosomeType chromosomeType = chromosome->Type();\n\tsize_t individual_count = p_ts->tables->individuals.num_rows;\n\t\n\tif (individual_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): loaded tree sequence files must contain a non-empty individuals table.\" << EidosTerminate();\n\t\n\ttsk_individual_t individual;\n\tint ret = 0;\n\t\n\tfor (size_t individual_index = 0; individual_index < individual_count; individual_index++)\n\t{\n\t\tret = tsk_treeseq_get_individual(p_ts, (tsk_id_t)individual_index, &individual);\n\t\tif (ret != 0) handle_error(\"__TabulateSubpopulationsFromTreeSequence tsk_treeseq_get_individual\", ret);\n\t\t\n\t\t// tabulate only individuals marked as being alive; everybody else in the table is irrelevant to us during load\n\t\tif (!(individual.flags & SLIM_TSK_INDIVIDUAL_ALIVE))\n\t\t\tcontinue;\n\t\t\n\t\t// fetch the metadata for this individual\n\t\tif (individual.metadata_length != sizeof(IndividualMetadataRec))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unexpected individual metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tIndividualMetadataRec *metadata = (IndividualMetadataRec *)(individual.metadata);\n\t\t\n\t\t// find the ts_subpop_info rec for this individual's subpop, created by __PrepareSubpopulationsFromTables()\n\t\tslim_objectid_t subpop_id = metadata->subpopulation_id_;\n\t\tauto subpop_info_iter = p_subpopInfoMap.find(subpop_id);\n\t\t\n\t\tif (subpop_info_iter == p_subpopInfoMap.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individual has a subpopulation id (\" << subpop_id << \") that is not described by the population table.\" << EidosTerminate();\n\t\t\n\t\tts_subpop_info &subpop_info = subpop_info_iter->second;\n\t\t\n\t\t// check and tabulate sex within each subpop\n\t\tIndividualSex sex = (IndividualSex)metadata->sex_;\t\t\t// IndividualSex, but int32_t in the record\n\t\t\n\t\tswitch (sex)\n\t\t{\n\t\t\tcase IndividualSex::kHermaphrodite:\n\t\t\t\tif (sex_enabled_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): hermaphrodites may not be loaded into a model in which sex is enabled.\" << EidosTerminate();\n\t\t\t\tsubpop_info.countMH_++;\n\t\t\t\tbreak;\n\t\t\tcase IndividualSex::kFemale:\n\t\t\t\tif (!sex_enabled_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): females may not be loaded into a model in which sex is not enabled.\" << EidosTerminate();\n\t\t\t\tsubpop_info.countF_++;\n\t\t\t\tbreak;\n\t\t\tcase IndividualSex::kMale:\n\t\t\t\tif (!sex_enabled_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): males may not be loaded into a model in which sex is not enabled.\" << EidosTerminate();\n\t\t\t\tsubpop_info.countMH_++;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unrecognized individual sex value \" << sex << \".\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tsubpop_info.sex_.emplace_back(sex);\n\t\t\n\t\t// check that the individual has exactly two nodes; we are always diploid in terms of nodes, regardless of the chromosome type\n\t\tif (individual.nodes_length != 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unexpected node count; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tsubpop_info.nodes_.emplace_back(individual.nodes[0]);\n\t\tsubpop_info.nodes_.emplace_back(individual.nodes[1]);\n\t\t\n\t\t// bounds-check and save off the pedigree ID, which we will use again; note that parent pedigree IDs are allowed to be -1\n\t\tif (metadata->pedigree_id_ < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individuals loaded must have pedigree IDs >= 0.\" << EidosTerminate();\n\t\tsubpop_info.pedigreeID_.push_back(metadata->pedigree_id_);\n\t\t\n\t\tif ((metadata->pedigree_p1_ < -1) || (metadata->pedigree_p2_ < -1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individuals loaded must have parent pedigree IDs >= -1.\" << EidosTerminate();\n\t\tsubpop_info.pedigreeP1_.push_back(metadata->pedigree_p1_);\n\t\tsubpop_info.pedigreeP2_.push_back(metadata->pedigree_p2_);\n\n\t\t// save off the flags for later use\n\t\tsubpop_info.flags_.push_back(metadata->flags_);\n\t\t\n\t\t// bounds-check ages; we cross-translate ages of 0 and -1 if the model type has been switched\n\t\tslim_age_t age = metadata->age_;\n\t\t\n\t\tif ((p_file_model_type == SLiMModelType::kModelTypeNonWF) && (model_type_ == SLiMModelType::kModelTypeWF) && (age == 0))\n\t\t\tage = -1;\n\t\tif ((p_file_model_type == SLiMModelType::kModelTypeWF) && (model_type_ == SLiMModelType::kModelTypeNonWF) && (age == -1))\n\t\t\tage = 0;\n\t\t\n\t\tif (((age < 0) || (age > SLIM_MAX_ID_VALUE)) && (model_type_ == SLiMModelType::kModelTypeNonWF))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individuals loaded into a nonWF model must have age values >= 0 and <= \" << SLIM_MAX_ID_VALUE << \".\" << EidosTerminate();\n\t\tif ((age != -1) && (model_type_ == SLiMModelType::kModelTypeWF))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individuals loaded into a WF model must have age values == -1.\" << EidosTerminate();\n\t\t\n\t\tsubpop_info.age_.emplace_back(age);\n\t\t\n\t\t// no bounds-checks for spatial position\n\t\tif (individual.location_length != 3)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unexpected individual location length; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tsubpop_info.spatial_x_.emplace_back(individual.location[0]);\n\t\tsubpop_info.spatial_y_.emplace_back(individual.location[1]);\n\t\tsubpop_info.spatial_z_.emplace_back(individual.location[2]);\n\t\t\n\t\t// check the referenced nodes; right now this is not essential for re-creating the saved state, but is just a crosscheck\n\t\t// here we crosscheck the node information against expected values from other places in the tables or the model\n\t\ttsk_node_table_t &node_table = tables.nodes;\n\t\ttsk_id_t node0 = individual.nodes[0];\n\t\ttsk_id_t node1 = individual.nodes[1];\n\t\t\n\t\tif (((node_table.flags[node0] & TSK_NODE_IS_SAMPLE) == 0) || ((node_table.flags[node1] & TSK_NODE_IS_SAMPLE) == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): nodes for individual are not in-sample; this file cannot be read.\" << EidosTerminate();\n\t\tif ((node_table.individual[node0] != individual.id) || (node_table.individual[node1] != individual.id))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): individual-node inconsistency; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tsize_t node0_metadata_length = node_table.metadata_offset[node0 + 1] - node_table.metadata_offset[node0];\n\t\tsize_t node1_metadata_length = node_table.metadata_offset[node1 + 1] - node_table.metadata_offset[node1];\n\t\t\n\t\tint byte_index = chromosome_index / 8;\n\t\tint bit_shift = chromosome_index % 8;\n\t\tsize_t expected_min_metadata_length = sizeof(HaplosomeMetadataRec) + byte_index;\t// 1 byte already counted in HaplosomeMetadataRec\n\t\t\n\t\t// check that the metadata is long enough to contain the is_vacant bit we will look at; we don't check\n\t\t// that it is exactly the length we expect here, just that it works for our local purposes\n\t\tif ((node0_metadata_length < expected_min_metadata_length) || (node1_metadata_length < expected_min_metadata_length))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): unexpected node metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tHaplosomeMetadataRec *node0_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node0]);\n\t\tHaplosomeMetadataRec *node1_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node1]);\n\t\t\n\t\tif ((node0_metadata->haplosome_id_ != metadata->pedigree_id_ * 2) || (node1_metadata->haplosome_id_ != metadata->pedigree_id_ * 2 + 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): haplosome id mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\t// check that the null-haplosome flags make sense with the chromosome type\n\t\tbool expected_is_vacant_0 = false, expected_is_vacant_1 = false;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = false;\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = (sex == IndividualSex::kMale) ? true : false;\t// null in males\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\texpected_is_vacant_0 = (sex == IndividualSex::kMale) ? false : true;\t// null in females\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\texpected_is_vacant_0 = (sex == IndividualSex::kMale) ? false : true;\t// null in females\n\t\t\t\texpected_is_vacant_1 = false;\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\texpected_is_vacant_0 = (sex == IndividualSex::kMale) ? true : false;\t// null in males\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\texpected_is_vacant_0 = (sex == IndividualSex::kMale) ? true : false;\t// null in males\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\texpected_is_vacant_0 = (sex == IndividualSex::kMale) ? false : true;\t// null in females\n\t\t\t\texpected_is_vacant_1 = true;\t// unused\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\texpected_is_vacant_0 = false;\n\t\t\t\texpected_is_vacant_1 = true;\t// null\n\t\t\t\tbreak;\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\texpected_is_vacant_0 = true;\t// null\n\t\t\t\texpected_is_vacant_1 = (sex == IndividualSex::kMale) ? false : true;\t// null in females\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// Null haplosomes are allowed to occur arbitrarily in nonWF models in chromosome types 'A' and 'H'\n\t\tbool node0_is_vacant = !!((node0_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\n\t\tif (node0_is_vacant != expected_is_vacant_0)\n\t\t{\n\t\t\tif ((model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): node is_vacant unexpected; this file cannot be read.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// We do not check the second haplosome's null flag if the chromosome type is intrinsically haploid\n\t\tif (chromosome->IntrinsicPloidy() == 2)\n\t\t{\n\t\t\tbool node1_is_vacant = !!((node1_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\t\n\t\t\tif (node1_is_vacant != expected_is_vacant_1)\n\t\t\t{\n\t\t\t\tif ((model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t;\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateSubpopulationsFromTreeSequence): node is_vacant unexpected; this file cannot be read.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Species::__CreateSubpopulationsFromTabulation(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, EidosInterpreter *p_interpreter, std::unordered_map<tsk_id_t, Haplosome *> &p_nodeToHaplosomeMap, TreeSeqInfo &p_treeseq)\n{\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\tChromosomeType chromosomeType = chromosome->Type();\n\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\n\t// We will keep track of all pedigree IDs used, and check at the end that they do not collide; faster than checking as we go\n\t// This could be done with a hash table, but I imagine that would be slower until the number of individuals becomes very large\n\t// Also, I'm a bit nervous about putting a large number of consecutive integers into a hash table, re: edge-case performance\n\tstd::vector<slim_pedigreeid_t> pedigree_id_check;\n\tstd::vector<slim_haplosomeid_t> haplosome_id_check;\n\t\n\tgSLiM_next_pedigree_id = 0;\n\t\n\tfor (auto subpop_info_iter : p_subpopInfoMap)\n\t{\n\t\tslim_objectid_t subpop_id = subpop_info_iter.first;\n\t\tts_subpop_info &subpop_info = subpop_info_iter.second;\n\t\tslim_popsize_t subpop_size = sex_enabled_ ? (subpop_info.countMH_ + subpop_info.countF_) : subpop_info.countMH_;\n\t\tdouble sex_ratio = sex_enabled_ ? (subpop_info.countMH_ / (double)subpop_size) : 0.5;\n\t\t\n\t\t// Create the new subpopulation – without recording it in the tree-seq tables\n\t\trecording_tree_ = false;\n\t\tSubpopulation *new_subpop = population_.AddSubpopulation(subpop_id, subpop_size, sex_ratio, false);\n\t\trecording_tree_ = true;\n\t\t\n\t\t// define a new Eidos variable to refer to the new subpopulation\n\t\tEidosSymbolTableEntry &symbol_entry = new_subpop->SymbolTableEntry();\n\t\t\n\t\tif (p_interpreter && p_interpreter->SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): new subpopulation symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\t\n\t\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\t\n\t\t// connect up the individuals and haplosomes in the new subpop with the tree-seq table entries\n\t\tint sex_count = sex_enabled_ ? 2 : 1;\n\t\t\n\t\tfor (int sex_index = 0; sex_index < sex_count; ++sex_index)\n\t\t{\n\t\t\tIndividualSex generating_sex = (sex_enabled_ ? (sex_index == 0 ? IndividualSex::kFemale : IndividualSex::kMale) : IndividualSex::kHermaphrodite);\n\t\t\tslim_popsize_t tabulation_size = (sex_enabled_ ? (sex_index == 0 ? subpop_info.countF_ : subpop_info.countMH_) : subpop_info.countMH_);\n\t\t\tslim_popsize_t start_index = (generating_sex == IndividualSex::kMale) ? new_subpop->parent_first_male_index_ : 0;\n\t\t\tslim_popsize_t last_index = (generating_sex == IndividualSex::kFemale) ? (new_subpop->parent_first_male_index_ - 1) : (new_subpop->parent_subpop_size_ - 1);\n\t\t\tslim_popsize_t sex_size = last_index - start_index + 1;\n\t\t\t\n\t\t\tif (tabulation_size != sex_size)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): (internal error) mismatch between tabulation size and subpop size.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t tabulation_index = -1;\n\t\t\t\n\t\t\tfor (slim_popsize_t ind_index = start_index; ind_index <= last_index; ++ind_index)\n\t\t\t{\n\t\t\t\t// scan for the next tabulation entry of the expected sex\n\t\t\t\tdo {\n\t\t\t\t\ttabulation_index++;\n\t\t\t\t\t\n\t\t\t\t\tif (tabulation_index >= subpop_size)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): (internal error) ran out of tabulated individuals.\" << EidosTerminate();\n\t\t\t\t} while (subpop_info.sex_[tabulation_index] != generating_sex);\n\t\t\t\t\n\t\t\t\tIndividual *individual = new_subpop->parent_individuals_[ind_index];\n\t\t\t\t\n\t\t\t\tif (individual->sex_ != generating_sex)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): (internal error) unexpected individual sex.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\ttsk_id_t node_id_0 = subpop_info.nodes_[(size_t)tabulation_index * 2];\n\t\t\t\ttsk_id_t node_id_1 = subpop_info.nodes_[(size_t)tabulation_index * 2 + 1];\n\t\t\t\t\n\t\t\t\tif (node_id_0 + 1 != node_id_1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): (internal error) node ids for individual are not adjacent.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tindividual->SetTskitNodeIdBase(node_id_0);\n\t\t\t\t\n\t\t\t\tslim_pedigreeid_t pedigree_id = subpop_info.pedigreeID_[tabulation_index];\n\t\t\t\tindividual->SetPedigreeID(pedigree_id);\n\t\t\t\tpedigree_id_check.emplace_back(pedigree_id);\t// we will test for collisions below\n\t\t\t\tgSLiM_next_pedigree_id = std::max(gSLiM_next_pedigree_id, pedigree_id + 1);\n\n\t\t\t\tindividual->SetParentPedigreeID(subpop_info.pedigreeP1_[tabulation_index], subpop_info.pedigreeP2_[tabulation_index]);\n\t\t\t\t\n\t\t\t\tuint32_t flags = subpop_info.flags_[tabulation_index];\n\t\t\t\tif (flags & SLIM_INDIVIDUAL_METADATA_MIGRATED)\n\t\t\t\t\tindividual->migrant_ = true;\n\t\t\t\t\n\t\t\t\tindividual->age_ = subpop_info.age_[tabulation_index];\n\t\t\t\tindividual->spatial_x_ = subpop_info.spatial_x_[tabulation_index];\n\t\t\t\tindividual->spatial_y_ = subpop_info.spatial_y_[tabulation_index];\n\t\t\t\tindividual->spatial_z_ = subpop_info.spatial_z_[tabulation_index];\n\t\t\t\t\n\t\t\t\tp_nodeToHaplosomeMap.emplace(node_id_0, individual->haplosomes_[first_haplosome_index]);\n\t\t\t\tslim_haplosomeid_t haplosome_id = pedigree_id * 2;\n\t\t\t\tindividual->haplosomes_[first_haplosome_index]->haplosome_id_ = haplosome_id;\n\t\t\t\thaplosome_id_check.emplace_back(haplosome_id);\t// we will test for collisions below\n\t\t\t\t\n\t\t\t\tif (last_haplosome_index != first_haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tp_nodeToHaplosomeMap.emplace(node_id_1, individual->haplosomes_[last_haplosome_index]);\n\t\t\t\t\thaplosome_id = pedigree_id * 2 + 1;\n\t\t\t\t\tindividual->haplosomes_[last_haplosome_index]->haplosome_id_ = haplosome_id;\n\t\t\t\t\thaplosome_id_check.emplace_back(haplosome_id);\t// we will test for collisions below\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check the referenced nodes; right now this is not essential for re-creating the saved state, but is just a crosscheck\n\t\t\t\t// here we crosscheck the node information against the realized values in the haplosomes of the individual\n\t\t\t\ttsk_node_table_t &node_table = tables.nodes;\n\t\t\t\tsize_t node0_metadata_length = node_table.metadata_offset[node_id_0 + 1] - node_table.metadata_offset[node_id_0];\n\t\t\t\tsize_t node1_metadata_length = node_table.metadata_offset[node_id_1 + 1] - node_table.metadata_offset[node_id_1];\n\t\t\t\t\n\t\t\t\tint byte_index = chromosome_index / 8;\n\t\t\t\tint bit_shift = chromosome_index % 8;\n\t\t\t\tsize_t expected_min_metadata_length = sizeof(HaplosomeMetadataRec) + byte_index;\t// 1 byte already counted in HaplosomeMetadataRec\n\t\t\t\t\n\t\t\t\t// check that the metadata is long enough to contain the is_vacant bit we will look at; we don't check\n\t\t\t\t// that it is exactly the length we expect here, just that it works for our local purposes\n\t\t\t\tif ((node0_metadata_length < expected_min_metadata_length) || (node1_metadata_length < expected_min_metadata_length))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): unexpected node metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tHaplosomeMetadataRec *node0_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node_id_0]);\n\t\t\t\tHaplosome *haplosome0 = individual->haplosomes_[first_haplosome_index];\n\t\t\t\t\n\t\t\t\tif (node0_metadata->haplosome_id_ != haplosome0->haplosome_id_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome id mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// Null haplosomes are allowed to occur arbitrarily in nonWF models in chromosome types 'A' and 'H'\n\t\t\t\tbool node0_is_vacant = !!((node0_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\t\t\n\t\t\t\tif (node0_is_vacant != haplosome0->IsNull())\n\t\t\t\t{\n\t\t\t\t\tif (node0_is_vacant && (model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome0->MakeNull();\n\t\t\t\t\t\tnew_subpop->has_null_haplosomes_ = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome null mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We do not check the second haplosome's state if the chromosome type is intrinsically haploid\n\t\t\t\tif (last_haplosome_index != first_haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tHaplosomeMetadataRec *node1_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node_id_1]);\n\t\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[last_haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (node1_metadata->haplosome_id_ != haplosome1->haplosome_id_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome id mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tbool node1_is_vacant = !!((node1_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\t\t\t\n\t\t\t\t\tif (node1_is_vacant != haplosome1->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (node1_is_vacant && (model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thaplosome1->MakeNull();\n\t\t\t\t\t\t\tnew_subpop->has_null_haplosomes_ = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome null mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Check for individual pedigree ID collisions by sorting and looking for duplicates\n\tstd::sort(pedigree_id_check.begin(), pedigree_id_check.end());\n\tconst auto duplicate = std::adjacent_find(pedigree_id_check.begin(), pedigree_id_check.end());\n\t\n\tif (duplicate != pedigree_id_check.end())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): the individual pedigree ID value \" << *duplicate << \" was used more than once; individual pedigree IDs must be unique.\" << EidosTerminate();\n}\n\nvoid Species::__CreateSubpopulationsFromTabulation_SECONDARY(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, __attribute__((unused)) EidosInterpreter *p_interpreter, std::unordered_map<tsk_id_t, Haplosome *> &p_nodeToHaplosomeMap, TreeSeqInfo &p_treeseq)\n{\n\t// NOTE: This version of __CreateSubpopulationsFromTabulation() validates subpopulations already created,\n\t// ensuring that they match those made by __CreateSubpopulationsFromTabulation() for the first chromosome\n\t// read.  BEWARE: These methods should be maintained in parallel!\n\t\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\tChromosomeType chromosomeType = chromosome->Type();\n\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\n\t// We do not check pedigree ids in this secondary pass; __CreateSubpopulationsFromTabulation() set them up.\n\t\n\tfor (auto subpop_info_iter : p_subpopInfoMap)\n\t{\n\t\tslim_objectid_t subpop_id = subpop_info_iter.first;\n\t\tts_subpop_info &subpop_info = subpop_info_iter.second;\n\t\tslim_popsize_t subpop_size = sex_enabled_ ? (subpop_info.countMH_ + subpop_info.countF_) : subpop_info.countMH_;\n\t\t\n\t\t// Get the existing subpopulation and check that its size and sex ratio match expectations.\n\t\tSubpopulation *new_subpop = SubpopulationWithID(subpop_id);\n\t\t\n\t\tif (new_subpop->parent_subpop_size_ != subpop_size)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): subpopulation size mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\n\t\tif (sex_enabled_ && (new_subpop->parent_first_male_index_ != subpop_info.countF_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): sex ratio mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\n\t\t// connect up the individuals and haplosomes in the new subpop with the tree-seq table entries\n\t\tint sex_count = sex_enabled_ ? 2 : 1;\n\t\t\n\t\tfor (int sex_index = 0; sex_index < sex_count; ++sex_index)\n\t\t{\n\t\t\tIndividualSex generating_sex = (sex_enabled_ ? (sex_index == 0 ? IndividualSex::kFemale : IndividualSex::kMale) : IndividualSex::kHermaphrodite);\n\t\t\tslim_popsize_t tabulation_size = (sex_enabled_ ? (sex_index == 0 ? subpop_info.countF_ : subpop_info.countMH_) : subpop_info.countMH_);\n\t\t\tslim_popsize_t start_index = (generating_sex == IndividualSex::kMale) ? new_subpop->parent_first_male_index_ : 0;\n\t\t\tslim_popsize_t last_index = (generating_sex == IndividualSex::kFemale) ? (new_subpop->parent_first_male_index_ - 1) : (new_subpop->parent_subpop_size_ - 1);\n\t\t\tslim_popsize_t sex_size = last_index - start_index + 1;\n\t\t\t\n\t\t\tif (tabulation_size != sex_size)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): (internal error) mismatch between tabulation size and subpop size.\" << EidosTerminate();\n\t\t\t\n\t\t\tslim_popsize_t tabulation_index = -1;\n\t\t\t\n\t\t\tfor (slim_popsize_t ind_index = start_index; ind_index <= last_index; ++ind_index)\n\t\t\t{\n\t\t\t\t// scan for the next tabulation entry of the expected sex\n\t\t\t\tdo {\n\t\t\t\t\ttabulation_index++;\n\t\t\t\t\t\n\t\t\t\t\tif (tabulation_index >= subpop_size)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): (internal error) ran out of tabulated individuals.\" << EidosTerminate();\n\t\t\t\t} while (subpop_info.sex_[tabulation_index] != generating_sex);\n\t\t\t\t\n\t\t\t\tIndividual *individual = new_subpop->parent_individuals_[ind_index];\n\t\t\t\t\n\t\t\t\tif (individual->sex_ != generating_sex)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): (internal error) unexpected individual sex.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\ttsk_id_t node_id_0 = subpop_info.nodes_[(size_t)tabulation_index * 2];\n\t\t\t\ttsk_id_t node_id_1 = subpop_info.nodes_[(size_t)tabulation_index * 2 + 1];\n\t\t\t\t\n\t\t\t\tif (node_id_0 + 1 != node_id_1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): (internal error) node ids for individual are not adjacent.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (individual->TskitNodeIdBase() != node_id_0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): tskit node id mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tslim_pedigreeid_t pedigree_id = subpop_info.pedigreeID_[tabulation_index];\n\t\t\t\t\n\t\t\t\tif (individual->PedigreeID() != pedigree_id)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): pedigree id mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\tif ((individual->Parent1PedigreeID() != subpop_info.pedigreeP1_[tabulation_index]) ||\n\t\t\t\t\t(individual->Parent2PedigreeID() != subpop_info.pedigreeP2_[tabulation_index]))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): parent pedigree id mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tuint32_t flags = subpop_info.flags_[tabulation_index];\n\t\t\t\tif ((flags & SLIM_INDIVIDUAL_METADATA_MIGRATED) && !individual->migrant_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): individual migrant flag mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (individual->age_ != subpop_info.age_[tabulation_index])\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): individual age mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\tif ((individual->spatial_x_ != subpop_info.spatial_x_[tabulation_index]) ||\n\t\t\t\t\t(individual->spatial_y_ != subpop_info.spatial_y_[tabulation_index]) ||\n\t\t\t\t\t(individual->spatial_z_ != subpop_info.spatial_z_[tabulation_index]))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): individual spatial position mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// the haplosomes we're setting up are different from the haplosomes previously set up,\n\t\t\t\t// so unlike the above code, we actually do work here, not just checkbacks\n\t\t\t\tp_nodeToHaplosomeMap.emplace(node_id_0, individual->haplosomes_[first_haplosome_index]);\n\t\t\t\tindividual->haplosomes_[first_haplosome_index]->haplosome_id_ = pedigree_id * 2;\n\t\t\t\t\n\t\t\t\tif (last_haplosome_index != first_haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tp_nodeToHaplosomeMap.emplace(node_id_1, individual->haplosomes_[last_haplosome_index]);\n\t\t\t\t\tindividual->haplosomes_[last_haplosome_index]->haplosome_id_ = pedigree_id * 2 + 1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check the referenced nodes; right now this is not essential for re-creating the saved state, but is just a crosscheck\n\t\t\t\t// here we crosscheck the node information against the realized values in the haplosomes of the individual\n\t\t\t\ttsk_node_table_t &node_table = tables.nodes;\n\t\t\t\tsize_t node0_metadata_length = node_table.metadata_offset[node_id_0 + 1] - node_table.metadata_offset[node_id_0];\n\t\t\t\tsize_t node1_metadata_length = node_table.metadata_offset[node_id_1 + 1] - node_table.metadata_offset[node_id_1];\n\t\t\t\t\n\t\t\t\tint byte_index = chromosome_index / 8;\n\t\t\t\tint bit_shift = chromosome_index % 8;\n\t\t\t\tsize_t expected_min_metadata_length = sizeof(HaplosomeMetadataRec) + byte_index;\t// 1 byte already counted in HaplosomeMetadataRec\n\t\t\t\t\n\t\t\t\t// check that the metadata is long enough to contain the is_vacant bit we will look at; we don't check\n\t\t\t\t// that it is exactly the length we expect here, just that it works for our local purposes\n\t\t\t\tif ((node0_metadata_length < expected_min_metadata_length) || (node1_metadata_length < expected_min_metadata_length))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation_SECONDARY): unexpected node metadata length; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tHaplosomeMetadataRec *node0_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node_id_0]);\n\t\t\t\tHaplosome *haplosome0 = individual->haplosomes_[first_haplosome_index];\n\t\t\t\t\n\t\t\t\tif (node0_metadata->haplosome_id_ != haplosome0->haplosome_id_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome id mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\t// Null haplosomes are allowed to occur arbitrarily in nonWF models in chromosome types 'A' and 'H'\n\t\t\t\tbool node0_is_vacant = !!((node0_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\t\t\n\t\t\t\tif (node0_is_vacant != haplosome0->IsNull())\n\t\t\t\t{\n\t\t\t\t\tif (node0_is_vacant && (model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t{\n\t\t\t\t\t\thaplosome0->MakeNull();\n\t\t\t\t\t\tnew_subpop->has_null_haplosomes_ = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome null mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We do not check the second haplosome's state if the chromosome type is intrinsically haploid\n\t\t\t\tif (last_haplosome_index != first_haplosome_index)\n\t\t\t\t{\n\t\t\t\t\tHaplosomeMetadataRec *node1_metadata = (HaplosomeMetadataRec *)(node_table.metadata + node_table.metadata_offset[node_id_1]);\n\t\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[last_haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (node1_metadata->haplosome_id_ != haplosome1->haplosome_id_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome id mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tbool node1_is_vacant = !!((node1_metadata->is_vacant_[byte_index] >> bit_shift) & 0x01);\n\t\t\t\t\t\n\t\t\t\t\tif (node1_is_vacant != haplosome1->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (node1_is_vacant && (model_type_ == SLiMModelType::kModelTypeNonWF) &&\n\t\t\t\t\t\t\t((chromosomeType == ChromosomeType::kA_DiploidAutosome) || (chromosomeType == ChromosomeType::kH_HaploidAutosome)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thaplosome1->MakeNull();\n\t\t\t\t\t\t\tnew_subpop->has_null_haplosomes_ = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateSubpopulationsFromTabulation): node-haplosome null mismatch; this file cannot be read.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Species::__ConfigureSubpopulationsFromTables(EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq)\n{\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\ttsk_population_table_t &pop_table = tables.populations;\n\ttsk_size_t pop_count = pop_table.num_rows;\n\t\n\tfor (tsk_size_t pop_index = 0; pop_index < pop_count; pop_index++)\n\t{\n\t\t// validate and parse metadata; get metadata values or fall back to default values\n\t\tsize_t metadata_length = pop_table.metadata_offset[pop_index + 1] - pop_table.metadata_offset[pop_index];\n\t\tchar *metadata_char = pop_table.metadata + pop_table.metadata_offset[pop_index];\n\t\tslim_objectid_t subpop_id = CheckSLiMPopulationMetadata(metadata_char, metadata_length);\n\t\t\n\t\t// -1 indicates that the metadata does not represent an extant SLiM subpopulation, so we\n\t\t// skip it entirely; this logic mirrors that in __PrepareSubpopulationsFromTables(), which has\n\t\t// already created a ts_subpop_info record for every SLiM-compliant subpopulation\n\t\tif (subpop_id == -1)\n\t\t\tcontinue;\n\t\t\n\t\t// otherwise, the metadata is valid and we proceed; this design means we parse the JSON twice, but whatever\n\t\tstd::string metadata_string(metadata_char, metadata_length);\n\t\tnlohmann::json subpop_metadata = nlohmann::json::parse(metadata_string);\n\n\t\t// Now we get to new work not done by __PrepareSubpopulationsFromTables()\n\t\tdouble metadata_selfing_fraction = 0.0;\n\t\tdouble metadata_female_clone_fraction = 0.0;\n\t\tdouble metadata_male_clone_fraction = 0.0;\n\t\tdouble metadata_sex_ratio = 0.5;\n\t\tdouble metadata_bounds_x0 = 0.0;\n\t\tdouble metadata_bounds_x1 = 1.0;\n\t\tdouble metadata_bounds_y0 = 0.0;\n\t\tdouble metadata_bounds_y1 = 1.0;\n\t\tdouble metadata_bounds_z0 = 0.0;\n\t\tdouble metadata_bounds_z1 = 1.0;\n\t\t\n\t\tif (subpop_metadata.contains(\"bounds_x0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_x0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_x0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_x0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_x1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_x1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_x1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_x1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_y0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_y0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_y0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_y0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_y1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_y1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_y1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_y1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_z0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_z0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_z0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_z0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_z1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_z1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'bounds_z1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_z1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"female_cloning_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"female_cloning_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'female_cloning_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_female_clone_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"male_cloning_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"male_cloning_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'male_cloning_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_male_clone_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"selfing_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"selfing_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'selfing_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_selfing_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"sex_ratio\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"sex_ratio\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'sex_ratio' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_sex_ratio = value.get<double>();\n\t\t}\n\t\t\n\t\tstd::string metadata_name = SLiMEidosScript::IDStringWithPrefix('p', subpop_id);\n\t\tstd::string metadata_description;\n\t\t\n\t\tif (subpop_metadata.contains(\"name\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"name\"];\n\t\t\tif (!value.is_string())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'name' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_name = value.get<std::string>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"description\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"description\"];\n\t\t\tif (!value.is_string())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'description' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_description = value.get<std::string>();\n\t\t}\n\t\t\n\t\tsize_t migration_rec_count = 0;\n\t\tnlohmann::json migration_records;\n\t\t\n\t\tif (subpop_metadata.contains(\"migration_records\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"migration_records\"];\n\t\t\tif (!value.is_array())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata key 'migration_records' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmigration_records = value;\n\t\t\tmigration_rec_count = migration_records.size();\n\t\t}\n\t\t\n\t\t// construct the subpopulation from the metadata values and other information we have decoded\n\t\tSubpopulation *subpop = SubpopulationWithID(subpop_id);\n\t\t\n\t\tif (!subpop)\n\t\t{\n\t\t\t// in a WF model it is an error to have a referenced subpop that is empty, so skip this subpop\n\t\t\t// we want to allow the population table to contain unreferenced empty subpops (for ancestral stuff)\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\t// In a nonWF model an empty subpop is legal, so create it without recording\n\t\t\trecording_tree_ = false;\n\t\t\tsubpop = population_.AddSubpopulation(subpop_id, 0, 0.5, false);\n\t\t\trecording_tree_ = true;\n\t\t\t\n\t\t\t// define a new Eidos variable to refer to the new subpopulation\n\t\t\tEidosSymbolTableEntry &symbol_entry = subpop->SymbolTableEntry();\n\t\t\t\n\t\t\tif (p_interpreter && p_interpreter->SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): new subpopulation symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here; this file cannot be read.\" << EidosTerminate();\n\t\t\t\n\t\t\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\t}\n\t\t\n\t\tsubpop->SetName(metadata_name);\n\t\tsubpop->description_ = metadata_description;\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tsubpop->selfing_fraction_ = metadata_selfing_fraction;\n\t\t\tsubpop->female_clone_fraction_ = metadata_female_clone_fraction;\n\t\t\tsubpop->male_clone_fraction_ = metadata_male_clone_fraction;\n\t\t\tsubpop->child_sex_ratio_ = metadata_sex_ratio;\n\t\t\t\n\t\t\tif (!sex_enabled_ && (subpop->female_clone_fraction_ != subpop->male_clone_fraction_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): cloning rate mismatch for non-sexual model; this file cannot be read.\" << EidosTerminate();\n\t\t\tif (sex_enabled_ && (subpop->selfing_fraction_ != 0.0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): selfing rate may be non-zero only for hermaphoditic models; this file cannot be read.\" << EidosTerminate();\n\t\t\tif ((subpop->female_clone_fraction_ < 0.0) || (subpop->female_clone_fraction_ > 1.0) ||\n\t\t\t\t(subpop->male_clone_fraction_ < 0.0) || (subpop->male_clone_fraction_ > 1.0) ||\n\t\t\t\t(subpop->selfing_fraction_ < 0.0) || (subpop->selfing_fraction_ > 1.0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): out-of-range value for cloning rate or selfing rate; this file cannot be read.\" << EidosTerminate();\n\t\t\tif (sex_enabled_ && ((subpop->child_sex_ratio_ < 0.0) || (subpop->child_sex_ratio_ > 1.0)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): out-of-range value for sex ratio; this file cannot be read.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tsubpop->bounds_x0_ = metadata_bounds_x0;\n\t\tsubpop->bounds_x1_ = metadata_bounds_x1;\n\t\tsubpop->bounds_y0_ = metadata_bounds_y0;\n\t\tsubpop->bounds_y1_ = metadata_bounds_y1;\n\t\tsubpop->bounds_z0_ = metadata_bounds_z0;\n\t\tsubpop->bounds_z1_ = metadata_bounds_z1;\n\t\t\n\t\tif (((spatial_dimensionality_ >= 1) && (subpop->bounds_x0_ >= subpop->bounds_x1_)) ||\n\t\t\t((spatial_dimensionality_ >= 2) && (subpop->bounds_y0_ >= subpop->bounds_y1_)) ||\n\t\t\t((spatial_dimensionality_ >= 3) && (subpop->bounds_z0_ >= subpop->bounds_z1_)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): unsorted spatial bounds; this file cannot be read.\" << EidosTerminate();\n\t\tif (((spatial_dimensionality_ >= 1) && periodic_x_ && (subpop->bounds_x0_ != 0.0)) ||\n\t\t\t((spatial_dimensionality_ >= 2) && periodic_y_ && (subpop->bounds_y0_ != 0.0)) ||\n\t\t\t((spatial_dimensionality_ >= 3) && periodic_z_ && (subpop->bounds_z0_ != 0.0)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): periodic bounds must have a minimum coordinate of 0.0; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tif ((model_type_ == SLiMModelType::kModelTypeNonWF) && (migration_rec_count > 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): migration rates cannot be provided in a nonWF model; this file cannot be read.\" << EidosTerminate();\n\t\t\n\t\tfor (size_t migration_index = 0; migration_index < migration_rec_count; ++migration_index)\n\t\t{\n\t\t\tnlohmann::json migration_rec = migration_records[migration_index];\n\t\t\t\n\t\t\tif (!migration_rec.is_object() || !migration_rec.contains(\"migration_rate\") || !migration_rec[\"migration_rate\"].is_number() || !migration_rec.contains(\"source_subpop\") || !migration_rec[\"source_subpop\"].is_number_integer())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): population metadata migration record does not obey the metadata schema; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tslim_objectid_t source_id = migration_rec[\"source_subpop\"].get<slim_objectid_t>();\n\t\t\tdouble rate = migration_rec[\"migration_rate\"].get<double>();\n\t\t\t\n\t\t\tif (source_id == subpop_id)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): self-referential migration record; this file cannot be read.\" << EidosTerminate();\n\t\t\tif (subpop->migrant_fractions_.find(source_id) != subpop->migrant_fractions_.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): duplicate migration record; this file cannot be read.\" << EidosTerminate();\n\t\t\tif ((rate < 0.0) || (rate > 1.0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables): out-of-range migration rate; this file cannot be read.\" << EidosTerminate();\n\t\t\t\n\t\t\tsubpop->migrant_fractions_.emplace(source_id, rate);\n\t\t}\n\t}\n}\n\nvoid Species::__ConfigureSubpopulationsFromTables_SECONDARY(__attribute__((unused)) EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq)\n{\n\t// NOTE: This version of __ConfigureSubpopulationsFromTables() validates the configuration already set up,\n\t// ensuring that it matches those made by __ConfigureSubpopulationsFromTables() for the first chromosome\n\t// read.  BEWARE: These methods should be maintained in parallel!\n\t\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\ttsk_population_table_t &pop_table = tables.populations;\n\ttsk_size_t pop_count = pop_table.num_rows;\n\t\n\tfor (tsk_size_t pop_index = 0; pop_index < pop_count; pop_index++)\n\t{\n\t\t// validate and parse metadata; get metadata values or fall back to default values\n\t\tsize_t metadata_length = pop_table.metadata_offset[pop_index + 1] - pop_table.metadata_offset[pop_index];\n\t\tchar *metadata_char = pop_table.metadata + pop_table.metadata_offset[pop_index];\n\t\tslim_objectid_t subpop_id = CheckSLiMPopulationMetadata(metadata_char, metadata_length);\n\t\t\n\t\t// -1 indicates that the metadata does not represent an extant SLiM subpopulation, so we\n\t\t// skip it entirely; this logic mirrors that in __PrepareSubpopulationsFromTables(), which has\n\t\t// already created a ts_subpop_info record for every SLiM-compliant subpopulation\n\t\tif (subpop_id == -1)\n\t\t\tcontinue;\n\t\t\n\t\t// otherwise, the metadata is valid and we proceed; this design means we parse the JSON twice, but whatever\n\t\tstd::string metadata_string(metadata_char, metadata_length);\n\t\tnlohmann::json subpop_metadata = nlohmann::json::parse(metadata_string);\n\n\t\t// Now we get to new work not done by __PrepareSubpopulationsFromTables()\n\t\tdouble metadata_selfing_fraction = 0.0;\n\t\tdouble metadata_female_clone_fraction = 0.0;\n\t\tdouble metadata_male_clone_fraction = 0.0;\n\t\tdouble metadata_sex_ratio = 0.5;\n\t\tdouble metadata_bounds_x0 = 0.0;\n\t\tdouble metadata_bounds_x1 = 1.0;\n\t\tdouble metadata_bounds_y0 = 0.0;\n\t\tdouble metadata_bounds_y1 = 1.0;\n\t\tdouble metadata_bounds_z0 = 0.0;\n\t\tdouble metadata_bounds_z1 = 1.0;\n\t\t\n\t\tif (subpop_metadata.contains(\"bounds_x0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_x0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_x0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_x0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_x1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_x1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_x1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_x1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_y0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_y0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_y0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_y0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_y1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_y1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_y1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_y1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_z0\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_z0\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_z0' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_z0 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"bounds_z1\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"bounds_z1\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'bounds_z1' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_bounds_z1 = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"female_cloning_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"female_cloning_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'female_cloning_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_female_clone_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"male_cloning_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"male_cloning_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'male_cloning_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_male_clone_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"selfing_fraction\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"selfing_fraction\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'selfing_fraction' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_selfing_fraction = value.get<double>();\n\t\t}\n\t\tif (subpop_metadata.contains(\"sex_ratio\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"sex_ratio\"];\n\t\t\tif (!value.is_number())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'sex_ratio' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_sex_ratio = value.get<double>();\n\t\t}\n\t\t\n\t\tstd::string metadata_name = SLiMEidosScript::IDStringWithPrefix('p', subpop_id);\n\t\t\n\t\tif (subpop_metadata.contains(\"name\"))\n\t\t{\n\t\t\tnlohmann::json value = subpop_metadata[\"name\"];\n\t\t\tif (!value.is_string())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): population metadata key 'name' is not the expected type; this file cannot be read.\" << EidosTerminate(nullptr);\n\t\t\tmetadata_name = value.get<std::string>();\n\t\t}\n\t\t\n\t\t// we skip the description; it does not get validated across chromosomes\n\t\t\n\t\t// migration does not get validated across chromosomes either, too annoying and marginal\n\t\t\n\t\t// validate the subpopulation from the metadata values and other information we have decoded\n\t\tSubpopulation *subpop = SubpopulationWithID(subpop_id);\n\t\t\n\t\tif (!subpop)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): a subpopulation (id \" << subpop_id << \") was not defined by the first .trees file read, but was referenced by a later .trees file; subpopulation structure must match exactly across chromosomes.\" << EidosTerminate();\n\t\t\n\t\tif (subpop->name_ != metadata_name)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): subpopulation name mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tif (subpop->selfing_fraction_ != metadata_selfing_fraction)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): selfing fraction mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\tif (subpop->female_clone_fraction_ != metadata_female_clone_fraction)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): female cloning fraction mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\tif (subpop->male_clone_fraction_ != metadata_male_clone_fraction)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): male cloning fraction mismatch between chromosomes read.\" << EidosTerminate();\n\t\t\tif (subpop->child_sex_ratio_ != metadata_sex_ratio)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): sex ratio mismatch between chromosomes read.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif ((subpop->bounds_x0_ != metadata_bounds_x0) ||\n\t\t\t(subpop->bounds_x1_ != metadata_bounds_x1) ||\n\t\t\t(subpop->bounds_y0_ != metadata_bounds_y0) ||\n\t\t\t(subpop->bounds_y1_ != metadata_bounds_y1) ||\n\t\t\t(subpop->bounds_z0_ != metadata_bounds_z0) ||\n\t\t\t(subpop->bounds_z1_ != metadata_bounds_z1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__ConfigureSubpopulationsFromTables_SECONDARY): spatial bounds mismatch between chromosomes read.\" << EidosTerminate();\n\t}\n}\n\ntypedef struct ts_mut_info {\n\tslim_position_t position;\n\tMutationMetadataRec metadata;\n\tslim_refcount_t ref_count;\n} ts_mut_info;\n\nvoid Species::__TabulateMutationsFromTables(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutMap, TreeSeqInfo &p_treeseq, __attribute__ ((unused)) int p_file_version)\n{\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tstd::size_t metadata_rec_size = sizeof(MutationMetadataRec);\n\ttsk_mutation_table_t &mut_table = tables.mutations;\n\ttsk_size_t mut_count = mut_table.num_rows;\n\t\n\tif ((mut_count > 0) && !recording_mutations_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): cannot load mutations when mutation recording is disabled.\" << EidosTerminate();\n\t\n\tfor (tsk_size_t mut_index = 0; mut_index < mut_count; ++mut_index)\n\t{\n\t\tconst char *derived_state_bytes = mut_table.derived_state + mut_table.derived_state_offset[mut_index];\n\t\ttsk_size_t derived_state_length = mut_table.derived_state_offset[mut_index + 1] - mut_table.derived_state_offset[mut_index];\n\t\tconst char *metadata_bytes = mut_table.metadata + mut_table.metadata_offset[mut_index];\n\t\ttsk_size_t metadata_length = mut_table.metadata_offset[mut_index + 1] - mut_table.metadata_offset[mut_index];\n\t\t\n\t\tif (derived_state_length % sizeof(slim_mutationid_t) != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): unexpected mutation derived state length; this file cannot be read.\" << EidosTerminate();\n\t\tif (metadata_length % metadata_rec_size != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): unexpected mutation metadata length; this file cannot be read.\" << EidosTerminate();\n\t\tif (derived_state_length / sizeof(slim_mutationid_t) != metadata_length / metadata_rec_size)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): (internal error) mutation metadata length does not match derived state length.\" << EidosTerminate();\n\t\t\n\t\tint stack_count = (int)(derived_state_length / sizeof(slim_mutationid_t));\n\t\tslim_mutationid_t *derived_state_vec = (slim_mutationid_t *)derived_state_bytes;\n\t\tconst void *metadata_vec = metadata_bytes;\t// either const MutationMetadataRec* or const MutationMetadataRec_PRENUC*\n\t\ttsk_id_t site_id = mut_table.site[mut_index];\n\t\tdouble position_double = tables.sites.position[site_id];\n\t\tdouble position_double_round = round(position_double);\n\t\t\n\t\tif (position_double_round != position_double)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): mutation positions must be whole numbers for importation into SLiM; fractional positions are not allowed.\" << EidosTerminate();\n\t\t\n\t\tslim_position_t position = (slim_position_t)position_double_round;\n\t\t\n\t\t// tabulate the mutations referenced by this entry, overwriting previous tabulations (last state wins)\n\t\tfor (int stack_index = 0; stack_index < stack_count; ++stack_index)\n\t\t{\n\t\t\tslim_mutationid_t mut_id = derived_state_vec[stack_index];\n\t\t\t\n\t\t\tauto mut_info_find = p_mutMap.find(mut_id);\n\t\t\tts_mut_info *mut_info;\n\t\t\t\n\t\t\tif (mut_info_find == p_mutMap.end())\n\t\t\t{\n\t\t\t\t// no entry already present; create one\n\t\t\t\tauto mut_info_insert = p_mutMap.emplace(mut_id, ts_mut_info());\n\t\t\t\tmut_info = &((mut_info_insert.first)->second);\n\t\t\t\t\n\t\t\t\tmut_info->position = position;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// entry already present; check that it refers to the same mutation, using its position (see https://github.com/MesserLab/SLiM/issues/179)\n\t\t\t\tmut_info = &(mut_info_find->second);\n\t\t\t\t\n\t\t\t\tif (mut_info->position != position)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TabulateMutationsFromTables): inconsistent mutation position observed reading tree sequence data; this may indicate that mutation IDs are not unique.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tMutationMetadataRec *metadata = (MutationMetadataRec *)metadata_vec + stack_index;\n\t\t\t\n\t\t\tmut_info->metadata = *metadata;\n\t\t}\n\t}\n}\n\nvoid Species::__TallyMutationReferencesWithTreeSequence(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutMap, std::unordered_map<tsk_id_t, Haplosome *> p_nodeToHaplosomeMap, tsk_treeseq_t *p_ts)\n{\n\t// allocate and set up the tsk_variant object we'll use to walk through sites\n\ttsk_variant_t *variant;\n\tvariant = (tsk_variant_t *)malloc(sizeof(tsk_variant_t));\n\tif (!variant)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::__TallyMutationReferencesWithTreeSequence): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint ret = tsk_variant_init(\n\t\t\tvariant, p_ts, NULL, 0, NULL, TSK_ISOLATED_NOT_MISSING);\n\tif (ret != 0) handle_error(\"__TallyMutationReferencesWithTreeSequence tsk_variant_init()\", ret);\n\t\n\t// set up a map from sample indices in the variant to Haplosome objects; the sample\n\t// may contain nodes that are ancestral and need to be excluded\n\tstd::vector<Haplosome *> indexToHaplosomeMap;\n\tsize_t sample_count = variant->num_samples;\n\t\n\tfor (size_t sample_index = 0; sample_index < sample_count; ++sample_index)\n\t{\n\t\ttsk_id_t sample_node_id = variant->samples[sample_index];\n\t\tauto sample_nodeToHaplosome_iter = p_nodeToHaplosomeMap.find(sample_node_id);\n\t\t\n\t\tif (sample_nodeToHaplosome_iter != p_nodeToHaplosomeMap.end())\n\t\t{\n\t\t\tindexToHaplosomeMap.emplace_back(sample_nodeToHaplosome_iter->second);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this sample is presumably not extant; no corresponding haplosome, so record nullptr\n\t\t\tindexToHaplosomeMap.emplace_back(nullptr);\n\t\t}\n\t}\n\t\n\t// add mutations to haplosomes by looping through variants\n\tfor (tsk_size_t i = 0; i < p_ts->tables->sites.num_rows; i++)\n\t{\n\t\tret = tsk_variant_decode(variant, (tsk_id_t)i, 0);\n\t\tif (ret < 0) handle_error(\"__TallyMutationReferencesWithTreeSequence tsk_variant_decode()\", ret);\n\t\t\n\t\t// We have a new variant; set it into SLiM.  A variant represents a site at which a tracked mutation exists.\n\t\t// The tsk_variant_t will tell us all the allelic states involved at that site, what the alleles are, and which haplosomes\n\t\t// in the sample are using them.  We want to find any mutations that are shared across all non-null haplosomes.\n\t\tfor (tsk_size_t allele_index = 0; allele_index < variant->num_alleles; ++allele_index)\n\t\t{\n\t\t\ttsk_size_t allele_length = variant->allele_lengths[allele_index];\n\t\t\t\n\t\t\tif (allele_length > 0)\n\t\t\t{\n\t\t\t\t// Calculate the number of extant haplosomes that reference this allele\n\t\t\t\tint32_t allele_refs = 0;\n\t\t\t\t\n\t\t\t\tfor (size_t sample_index = 0; sample_index < sample_count; sample_index++)\n\t\t\t\t\tif ((variant->genotypes[sample_index] == (int32_t)allele_index) && (indexToHaplosomeMap[sample_index] != nullptr))\n\t\t\t\t\t\tallele_refs++;\n\t\t\t\t\n\t\t\t\t// If that count is greater than zero (might be zero if only non-extant nodes reference the allele), tally it\n\t\t\t\tif (allele_refs)\n\t\t\t\t{\n\t\t\t\t\tif (allele_length % sizeof(slim_mutationid_t) != 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TallyMutationReferencesWithTreeSequence): (internal error) variant allele had length that was not a multiple of sizeof(slim_mutationid_t).\" << EidosTerminate();\n\t\t\t\t\tallele_length /= sizeof(slim_mutationid_t);\n\t\t\t\t\t\n\t\t\t\t\tslim_mutationid_t *allele = (slim_mutationid_t *)variant->alleles[allele_index];\n\t\t\t\t\t\n\t\t\t\t\tfor (tsk_size_t mutid_index = 0; mutid_index < allele_length; ++mutid_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_mutationid_t mut_id = allele[mutid_index];\n\t\t\t\t\t\tauto mut_info_iter = p_mutMap.find(mut_id);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mut_info_iter == p_mutMap.end())\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__TallyMutationReferencesWithTreeSequence): mutation id \" << mut_id << \" was referenced but does not exist.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Add allele_refs to the refcount for this mutation\n\t\t\t\t\t\tts_mut_info &mut_info = mut_info_iter->second;\n\t\t\t\t\t\t\n\t\t\t\t\t\tmut_info.ref_count += allele_refs;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// free\n\tret = tsk_variant_free(variant);\n\tif (ret != 0) handle_error(\"__TallyMutationReferencesWithTreeSequence tsk_variant_free()\", ret);\n\tfree(variant);\n}\n\nvoid Species::__CreateMutationsFromTabulation(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutInfoMap, std::unordered_map<slim_mutationid_t, MutationIndex> &p_mutIndexMap, TreeSeqInfo &p_treeseq)\n{\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tint first_haplosome_index = FirstHaplosomeIndices()[chromosome_index];\n\tint last_haplosome_index = LastHaplosomeIndices()[chromosome_index];\n\t\n\t// count the number of non-null haplosomes there are for the focal chromosome; this is the count that would represent fixation\n\tslim_refcount_t fixation_count = 0;\n\t\n\tfor (auto pop_iter : population_.subpops_)\n\t{\n\t\tSubpopulation *subpop = pop_iter.second;\n\t\t\n\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t{\n\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = first_haplosome_index; haplosome_index <= last_haplosome_index; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\tfixation_count++;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// instantiate mutations\n\tfor (auto mut_info_iter : p_mutInfoMap)\n\t{\n\t\tslim_mutationid_t mutation_id = mut_info_iter.first;\n\t\tts_mut_info &mut_info = mut_info_iter.second;\n\t\tMutationMetadataRec *metadata_ptr = &mut_info.metadata;\n\t\tMutationMetadataRec metadata;\n\t\tslim_position_t position = mut_info.position;\n\t\t\n\t\t// BCH 4 Feb 2020: bump the next mutation ID counter as needed here, so that this happens in all cases – even if\n\t\t// the mutation in the mutation table is fixed (so we will create a Substitution) or absent (so we will create\n\t\t// nothing).  Even in those cases, we have to ensure that we do not re-use the previously used mutation ID.\n\t\tif (gSLiM_next_mutation_id <= mutation_id)\n\t\t\tgSLiM_next_mutation_id = mutation_id + 1;\n\t\t\n\t\t// a mutation might not be referenced by any extant haplosome; it might be present in an ancestral node,\n\t\t// but have been lost in all descendants, in which case we do not need to instantiate it\n\t\tif (mut_info.ref_count == 0)\n\t\t\tcontinue;\n\t\t\n\t\t// BCH 4/25/2019: copy the metadata with memcpy(), avoiding a misaligned pointer access; this is needed because\n\t\t// sizeof(MutationMetadataRec) is odd, according to Xcode.  Actually I think this might be a bug in Xcode's runtime\n\t\t// checking, because MutationMetadataRec is defined as packed so the compiler should not use aligned reads for it...?\n\t\t// Anyway, it's a safe fix and will probably get optimized away by the compiler, so whatever...\n\t\tmemcpy(&metadata, metadata_ptr, sizeof(MutationMetadataRec));\n\t\t\n\t\t// look up the mutation type from its index\n\t\tMutationType *mutation_type_ptr = MutationTypeWithID(metadata.mutation_type_id_);\n\t\t\n\t\tif (!mutation_type_ptr) \n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateMutationsFromTabulation): mutation type m\" << metadata.mutation_type_id_ << \" has not been defined for this species.\" << EidosTerminate();\n\t\t\n\t\tif ((mut_info.ref_count == fixation_count) && (mutation_type_ptr->convert_to_substitution_))\n\t\t{\n\t\t\t// this mutation is fixed, and the muttype wants substitutions, so make a substitution\n\t\t\tSubstitution *sub = new Substitution(mutation_id, mutation_type_ptr, chromosome_index, position, metadata.selection_coeff_, metadata.subpop_index_, metadata.origin_tick_, community_.Tick(), metadata.nucleotide_);\n\t\t\t\n\t\t\tpopulation_.treeseq_substitutions_map_.emplace(position, sub);\n\t\t\tpopulation_.substitutions_.emplace_back(sub);\n\t\t\t\n\t\t\t// add -1 to our local map, so we know there's an entry but we also know it's a substitution\n\t\t\tp_mutIndexMap[mutation_id] = -1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// construct the new mutation; NOTE THAT THE STACKING POLICY IS NOT CHECKED HERE, AS THIS IS NOT CONSIDERED THE ADDITION OF A MUTATION!\n\t\t\tMutationIndex new_mut_index = SLiM_NewMutationFromBlock();\n\t\t\t\n\t\t\tMutation *new_mut = new (gSLiM_Mutation_Block + new_mut_index) Mutation(mutation_id, mutation_type_ptr, chromosome_index, position, metadata.selection_coeff_, metadata.subpop_index_, metadata.origin_tick_, metadata.nucleotide_);\n\t\t\t\n\t\t\t// add it to our local map, so we can find it when making haplosomes, and to the population's mutation registry\n\t\t\tp_mutIndexMap[mutation_id] = new_mut_index;\n\t\t\tpopulation_.MutationRegistryAdd(new_mut);\n\t\t\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t\t\tif (population_.keeping_muttype_registries_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__CreateMutationsFromTabulation): (internal error) separate muttype registries set up during pop load.\" << EidosTerminate();\n#endif\n\t\t}\n\t\t\n\t\t// all mutations seen here will be added to the simulation somewhere, so check and set pure_neutral_ and all_pure_neutral_DFE_\n\t\tif (metadata.selection_coeff_ != 0.0)\n\t\t{\n\t\t\tpure_neutral_ = false;\n\t\t\tmutation_type_ptr->all_pure_neutral_DFE_ = false;\n\t\t}\n\t}\n}\n\nvoid Species::__AddMutationsFromTreeSequenceToHaplosomes(std::unordered_map<slim_mutationid_t, MutationIndex> &p_mutIndexMap, std::unordered_map<tsk_id_t, Haplosome *> p_nodeToHaplosomeMap, tsk_treeseq_t *p_ts, TreeSeqInfo &p_treeseq)\n{\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\t\n\t// This code is based on Species::CrosscheckTreeSeqIntegrity(), but it can be much simpler.\n\t// We also don't need to sort/deduplicate/simplify; the tables read in should be simplified already.\n\tif (!recording_mutations_)\n\t\treturn;\n\t\n\t// allocate and set up the variant object we'll use to walk through sites\n\ttsk_variant_t *variant;\n\n\tvariant = (tsk_variant_t *)malloc(sizeof(tsk_variant_t));\n\tif (!variant)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::__AddMutationsFromTreeSequenceToHaplosomes): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint ret = tsk_variant_init(variant, p_ts, NULL, 0, NULL, TSK_ISOLATED_NOT_MISSING);\n\tif (ret != 0) handle_error(\"__AddMutationsFromTreeSequenceToHaplosomes tsk_variant_init()\", ret);\n\t\n\t// set up a map from sample indices in the variant to Haplosome objects; the sample\n\t// may contain nodes that are ancestral and need to be excluded\n\tstd::vector<Haplosome *> indexToHaplosomeMap;\n\tsize_t sample_count = variant->num_samples;\n\t\n\tfor (size_t sample_index = 0; sample_index < sample_count; ++sample_index)\n\t{\n\t\ttsk_id_t sample_node_id = variant->samples[sample_index];\n\t\tauto sample_nodeToHaplosome_iter = p_nodeToHaplosomeMap.find(sample_node_id);\n\t\t\n\t\tif (sample_nodeToHaplosome_iter != p_nodeToHaplosomeMap.end())\n\t\t{\n\t\t\t// we found a haplosome for this sample, so record it\n\t\t\tindexToHaplosomeMap.emplace_back(sample_nodeToHaplosome_iter->second);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this sample is presumably not extant; no corresponding haplosome, so record nullptr\n\t\t\tindexToHaplosomeMap.emplace_back(nullptr);\n\t\t}\n\t}\n\t\n\t// add mutations to haplosomes by looping through variants\n#ifndef _OPENMP\n\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(omp_get_thread_num());\t// when not parallel, we have only one MutationRunContext\n#endif\n\t\n\tfor (tsk_size_t i = 0; i < p_ts->tables->sites.num_rows; i++)\n\t{\n\t\tret = tsk_variant_decode(variant, (tsk_id_t)i, 0);\n\t\tif (ret < 0) handle_error(\"__AddMutationsFromTreeSequenceToHaplosomes tsk_variant_decode()\", ret);\n\t\t\n\t\t// We have a new variant; set it into SLiM.  A variant represents a site at which a tracked mutation exists.\n\t\t// The tsk_variant_t will tell us all the allelic states involved at that site, what the alleles are, and which haplosomes\n\t\t// in the sample are using them.  We will then set all the haplosomes that the variant claims to involve to have\n\t\t// the allele the variant attributes to them.  The variants are returned in sorted order by position, so we can\n\t\t// always add new mutations to the ends of haplosomes.\n\t\tslim_position_t variant_pos_int = (slim_position_t)variant->site.position;\n\t\t\n\t\tfor (size_t sample_index = 0; sample_index < sample_count; sample_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = indexToHaplosomeMap[sample_index];\n\t\t\t\n\t\t\tif (haplosome)\n\t\t\t{\n\t\t\t\tint32_t haplosome_variant = variant->genotypes[sample_index];\n\t\t\t\ttsk_size_t haplosome_allele_length = variant->allele_lengths[haplosome_variant];\n\t\t\t\t\n\t\t\t\tif (haplosome_allele_length % sizeof(slim_mutationid_t) != 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__AddMutationsFromTreeSequenceToHaplosomes): (internal error) variant allele had length that was not a multiple of sizeof(slim_mutationid_t).\" << EidosTerminate();\n\t\t\t\thaplosome_allele_length /= sizeof(slim_mutationid_t);\n\t\t\t\t\n\t\t\t\tif (haplosome_allele_length > 0)\n\t\t\t\t{\n\t\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__AddMutationsFromTreeSequenceToHaplosomes): (internal error) null haplosome has non-zero treeseq allele length \" << haplosome_allele_length << \".\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tslim_mutationid_t *haplosome_allele = (slim_mutationid_t *)variant->alleles[haplosome_variant];\n\t\t\t\t\tslim_mutrun_index_t run_index = (slim_mutrun_index_t)(variant_pos_int / haplosome->mutrun_length_);\n\t\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\t\t// When parallel, the MutationRunContext depends upon the position in the haplosome\n\t\t\t\t\tMutationRunContext &mutrun_context = ChromosomeMutationRunContextForMutationRunIndex(run_index);\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// We use WillModifyRun_UNSHARED() because we know that these runs are unshared (unless empty);\n\t\t\t\t\t// we created them empty, nobody has modified them but us, and we process each haplosome separately.\n\t\t\t\t\tMutationRun *mutrun = haplosome->WillModifyRun_UNSHARED(run_index, mutrun_context);\n\t\t\t\t\t\n\t\t\t\t\tfor (tsk_size_t mutid_index = 0; mutid_index < haplosome_allele_length; ++mutid_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_mutationid_t mut_id = haplosome_allele[mutid_index];\n\t\t\t\t\t\tauto mut_index_iter = p_mutIndexMap.find(mut_id);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mut_index_iter == p_mutIndexMap.end())\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::__AddMutationsFromTreeSequenceToHaplosomes): mutation id \" << mut_id << \" was referenced but does not exist.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Add the mutation to the haplosome unless it is fixed (mut_index == -1)\n\t\t\t\t\t\tMutationIndex mut_index = mut_index_iter->second;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mut_index != -1)\n\t\t\t\t\t\t\tmutrun->emplace_back(mut_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This sample has no corresponding haplosome.  This is generally because the individual it\n\t\t\t\t// belongs to it is not extant, I think.  It could maybe also be due to some kind of erroneous\n\t\t\t\t// bookkeeping.  I'm not sure exactly what that would look like, or how we'd differentiate the\n\t\t\t\t// error case from the ordinary case.  Punting on this until such time as it manifests in a bug.\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// free\n\tret = tsk_variant_free(variant);\n\tif (ret != 0) handle_error(\"__AddMutationsFromTreeSequenceToHaplosomes tsk_variant_free()\", ret);\n\tfree(variant);\n}\n\nvoid Species::__CheckNodePedigreeIDs(__attribute__((unused)) EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq)\n{\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\t\n\t// Make sure our next pedigree ID is safe; right now it only accounts for pedigree IDs used by individuals, but maybe there\n\t// could be nodes in the node table with haplosome pedigree IDs greater than those in use by individuals, in nonWF models.\n\t// See https://github.com/MesserLab/SLiM/pull/420 for an example model that does this very easily.\n\t\n\t// Previously, we checked for duplicate haplosome IDs here as well, just in case.\n    // __CreateSubpopulationsFromTabulation() does this in living individuals\n    // already; however, it was found to be overly restrictive, in situations\n    // involving merging of parallel simulations; see https://github.com/MesserLab/SLiM/issues/538\n\ttsk_node_table_t &node_table = tables.nodes;\n\ttsk_size_t node_count = node_table.num_rows;\n\t\n\tfor (tsk_size_t j = 0; (size_t)j < node_count; j++)\n\t{\n\t\ttsk_size_t offset1 = node_table.metadata_offset[j];\n\t\ttsk_size_t offset2 = node_table.metadata_offset[j + 1];\n\t\ttsk_size_t length = (offset2 - offset1);\n\t\t\n\t\t// allow nodes with other types of metadata; but if the metadata length metches ours, we have to assume it's ours\n\t\tif (length == sizeof(HaplosomeMetadataRec))\n\t\t{\n\t\t\t// get the metadata record and check the haplosome pedigree ID\n\t\t\tHaplosomeMetadataRec *metadata_rec = (HaplosomeMetadataRec *)(node_table.metadata + offset1);\n\t\t\tslim_pedigreeid_t pedigree_id = metadata_rec->haplosome_id_ / 2;\t\t\t// rounds down to integer\n\t\t\t\n\t\t\tif (pedigree_id >= gSLiM_next_pedigree_id)\n\t\t\t{\n\t\t\t\t// We tried issuing a warning here:\n\t\t\t\t//\n\t\t\t\t// p_interpreter->ErrorOutputStream() << \"#WARNING (Species::__CheckNodePedigreeIDs): in reading the tree sequence, a node was encountered with a haplosome pedigree ID that was (after division by 2) greater than the largest individual pedigree ID in the tree sequence.  This is not necessarily an error, but it is highly unusual, and could indicate that the tree sequence file is corrupted.  It may happen due to external manipulations of a tree sequence, or perhaps if an unsimplified tree sequence produced by SLiM is being loaded.\" << std::endl;\n\t\t\t\t//\n\t\t\t\t// It proved not useful.  It got hit if you remembered an individual and then killed it and ended the sim,\n\t\t\t\t// such that that individual's nodes were still in the table, but it was not-alive and was more recently\n\t\t\t\t// born than any alive individual.  An uncommon thing to do, but not unreasonable.  On the other hand, this\n\t\t\t\t// warning did not flag any actually pathological cases for anyone; and it was a very confusing warning!\n\t\t\t\t\n\t\t\t\tgSLiM_next_pedigree_id = pedigree_id + 1;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Species::_ReadAncestralSequence(const char *p_file, Chromosome &p_chromosome)\n{\n\tif (nucleotide_based_)\n\t{\n\t\tchar *buffer;\t\t\t\t// kastore needs to provide us with a memory location from which to read the data\n\t\tstd::size_t buffer_length;\t// kastore needs to provide us with the length, in bytes, of the buffer\n\t\tkastore_t store;\n\t\t\n\t\tint ret = kastore_open(&store, p_file, \"r\", 0);\n\t\tif (ret != 0) {\n\t\t\tkastore_close(&store);\n\t\t\thandle_error(\"kastore_open\", ret);\n\t\t}\n\t\t\n\t\tret = kastore_gets_uint8(&store, \"reference_sequence/data\", (uint8_t **)&buffer, &buffer_length);\n\t\t\n\t\t// SLiM 3.6 and earlier wrote out int8_t data, but now tskit writes uint8_t data; to be tolerant of the old type, if\n\t\t// we get a type mismatch, try again with int8_t.  Note that buffer points into kastore's data and need not be freed.\n\t\tif (ret == KAS_ERR_TYPE_MISMATCH)\n\t\t\tret = kastore_gets_int8(&store, \"reference_sequence/data\", (int8_t **)&buffer, &buffer_length);\n\t\t\n\t\tif (ret != 0)\n\t\t\tbuffer = NULL;\n\t\t\n\t\tif (!buffer)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitBinaryFile): this is a nucleotide-based model, but there is no reference nucleotide sequence.\" << EidosTerminate();\n\t\tif (buffer_length != p_chromosome.AncestralSequence()->size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitBinaryFile): the reference nucleotide sequence length does not match the model.\" << EidosTerminate();\n\t\t\n\t\tp_chromosome.AncestralSequence()->ReadNucleotidesFromBuffer(buffer);\n\t\t\n\t\t// buffer is owned by kastore and is freed by closing the store\n\t\tkastore_close(&store);\n\t}\n}\n\nstatic int table_memcmp(const void *__s1, const void *__s2, size_t __n)\n{\n\t// this is a helper function for comparing tskit table columns, because I'm not sure\n\t// whether all of the defined table columns are necessarily allocated or not...\n\t\n\t// first, return unequal if one pointer is nullptr and the other is not\n\tif ((__s1 && !__s2) || (!__s1 && __s2))\n\t\treturn 1;\n\t\n\t// if both are nullptr, return equal\n\tif (!__s1 && !__s2)\n\t\treturn 0;\n\t\n\t// finally, fall back to memcmp() with two valid pointers\n\treturn memcmp(__s1, __s2, __n);\n}\n\n// Note that tskit has tsk_node_table_equals(), tsk_individual_table_equals(), and tsk_population_table_equals().\n// However, those functions don't provide a *reason* for the difference, which I think it important to report\n// back to the user, so I'm keeping my versions.  The tskit folks don't intend to change this.\n// See https://github.com/tskit-dev/tskit/issues/3089#issuecomment-2687232143\nstatic void _CompareNodeTables(tsk_node_table_t &nodes0, tsk_node_table_t &nodes1);\nstatic void _CompareIndividualTables(tsk_individual_table_t &individuals0, tsk_individual_table_t &individuals1);\nstatic void _ComparePopulationTables(tsk_population_table_t &population0, tsk_population_table_t &population1);\n\nvoid _CompareNodeTables(tsk_node_table_t &nodes0, tsk_node_table_t &nodes1)\n{\n\t// This delves into the internals of tskit rather heinously...\n\tif (nodes0.num_rows != nodes1.num_rows)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (number of rows differs).\" << EidosTerminate();\n\t\n\tif (nodes0.metadata_length != nodes1.metadata_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (metadata length differs).\" << EidosTerminate();\n\t\n\tif (nodes0.metadata_schema_length != nodes1.metadata_schema_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (metadata schema length differs).\" << EidosTerminate();\n\t\n\ttsk_size_t num_rows = nodes0.num_rows;\n\t\n\tif (table_memcmp(nodes0.flags, nodes1.flags, num_rows * sizeof(tsk_flags_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (flags column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.time, nodes1.time, num_rows * sizeof(double)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (time column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.population, nodes1.population, num_rows * sizeof(tsk_id_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (population column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.individual, nodes1.individual, num_rows * sizeof(tsk_id_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (individual column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.metadata, nodes1.metadata, nodes0.metadata_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (metadata column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.metadata_offset, nodes1.metadata_offset, num_rows * sizeof(tsk_size_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (metadata_offset column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(nodes0.metadata_schema, nodes1.metadata_schema, nodes0.metadata_schema_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareNodeTables): node table mismatch between loaded chromosomes (metadata_schema column differs).\" << EidosTerminate();\n}\n\nvoid _CompareIndividualTables(tsk_individual_table_t &individuals0, tsk_individual_table_t &individuals1)\n{\n\t// This delves into the internals of tskit rather heinously...\n\tif (individuals0.num_rows != individuals1.num_rows)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (number of rows differs).\" << EidosTerminate();\n\t\n\tif (individuals0.location_length != individuals1.location_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (location length differs).\" << EidosTerminate();\n\t\n\tif (individuals0.parents_length != individuals1.parents_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (parents length differs).\" << EidosTerminate();\n\t\n\tif (individuals0.metadata_length != individuals1.metadata_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (metadata length differs).\" << EidosTerminate();\n\t\n\tif (individuals0.metadata_schema_length != individuals1.metadata_schema_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (metadata schema length differs).\" << EidosTerminate();\n\t\n\ttsk_size_t num_rows = individuals0.num_rows;\n\t\n\tif (table_memcmp(individuals0.flags, individuals1.flags, num_rows * sizeof(tsk_flags_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (flags column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.location, individuals1.location, individuals0.location_length * sizeof(double)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (location column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.location_offset, individuals1.location_offset, num_rows * sizeof(tsk_size_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (location_offset column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.parents, individuals1.parents, individuals0.parents_length * sizeof(tsk_id_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (parents column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.parents_offset, individuals1.parents_offset, num_rows * sizeof(tsk_size_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (parents_offset column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.metadata, individuals1.metadata, individuals0.metadata_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (metadata column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.metadata_offset, individuals1.metadata_offset, num_rows * sizeof(tsk_size_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (metadata_offset column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(individuals0.metadata_schema, individuals1.metadata_schema, individuals0.metadata_schema_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_CompareIndividualTables): individual table mismatch between loaded chromosomes (metadata_schema column differs).\" << EidosTerminate();\n}\n\nvoid _ComparePopulationTables(tsk_population_table_t &population0, tsk_population_table_t &population1)\n{\n\t// This delves into the internals of tskit rather heinously...\n\tif (population0.num_rows != population1.num_rows)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (number of rows differs).\" << EidosTerminate();\n\t\n\tif (population0.metadata_length != population1.metadata_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (metadata length differs).\" << EidosTerminate();\n\t\n\tif (population0.metadata_schema_length != population1.metadata_schema_length)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (metadata schema length differs).\" << EidosTerminate();\n\t\n\ttsk_size_t num_rows = population0.num_rows;\n\t\n\tif (table_memcmp(population0.metadata, population1.metadata, population0.metadata_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (metadata column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(population0.metadata_offset, population1.metadata_offset, num_rows * sizeof(tsk_size_t)) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (metadata_offset column differs).\" << EidosTerminate();\n\t\n\tif (table_memcmp(population0.metadata_schema, population1.metadata_schema, population0.metadata_schema_length) != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (_ComparePopulationTables): population table mismatch between loaded chromosomes (metadata_schema column differs).\" << EidosTerminate();\n}\n\nvoid Species::_InstantiateSLiMObjectsFromTables(EidosInterpreter *p_interpreter, slim_tick_t p_metadata_tick, slim_tick_t p_metadata_cycle, SLiMModelType p_file_model_type, int p_file_version, SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq)\n{\n\t// NOTE: This method handles the first (or only) chromosome being read in.  A parallel method,\n\t// _InstantiateSLiMObjectsFromTables_SECONDARY(), handles the second and onward.  The code is\n\t// quite similar, and should be maintained in parallel!\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\t\n\t// check the sequence length against the chromosome length\n\tif (tables.sequence_length != chromosome->last_position_ + 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): chromosome length in loaded population (\" << tables.sequence_length << \") does not match the configured chromosome length (\" << (chromosome->last_position_ + 1) << \").\" << EidosTerminate();\n\t\n\t// set the tick and cycle from the provenance data\n\tcommunity_.SetTick(p_metadata_tick);\n\tSetCycle(p_metadata_cycle);\n\t\n\t// rebase the times in the nodes to be in SLiM-land; see WriteTreeSequence for the inverse operation\n\t// BCH 4/4/2019: switched to using tree_seq_tick_ to avoid a parent/child timestamp conflict\n\t// This makes sense; as far as tree-seq recording is concerned, tree_seq_tick_ is the time counter\n\tslim_tick_t time_adjustment = community_.tree_seq_tick_;\n\t\n\tfor (size_t node_index = 0; node_index < tables.nodes.num_rows; ++node_index)\n\t\ttables.nodes.time[node_index] -= time_adjustment;\n\n\tfor (size_t mut_index = 0; mut_index < tables.mutations.num_rows; ++mut_index)\n\t\ttables.mutations.time[mut_index] -= time_adjustment;\n\t\n\t// check/rewrite the incoming tree-seq information in various ways\n\t__CheckPopulationMetadata(p_treeseq);\n\t__RemapSubpopulationIDs(p_subpop_map, p_treeseq, p_file_version);\n\t\n\t// allocate and set up the tree_sequence object\n\t// note that this tree sequence is based upon whatever sample the file was saved with, and may contain in-sample individuals\n\t// that are not presently alive, so we have to tread carefully; the actually alive individuals are flagged with \n\t// SLIM_TSK_INDIVIDUAL_ALIVE in the individuals table (there may also be remembered and retained individuals in there too)\n\ttsk_treeseq_t *ts;\n\tint ret = 0;\n\t\n\tts = (tsk_treeseq_t *)malloc(sizeof(tsk_treeseq_t));\n\tif (!ts)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tret = tsk_treeseq_init(ts, &tables, TSK_TS_INIT_BUILD_INDEXES);\n\tif (ret != 0) handle_error(\"_InstantiateSLiMObjectsFromTables tsk_treeseq_init()\", ret);\n\t\n\tstd::unordered_map<tsk_id_t, Haplosome *> nodeToHaplosomeMap;\n\t\n\t{\n\t\tstd::unordered_map<slim_objectid_t, ts_subpop_info> subpopInfoMap;\n\t\t\n\t\t__PrepareSubpopulationsFromTables(subpopInfoMap, p_treeseq);\n\t\t__TabulateSubpopulationsFromTreeSequence(subpopInfoMap, ts, p_treeseq, p_file_model_type);\n\t\t__CreateSubpopulationsFromTabulation(subpopInfoMap, p_interpreter, nodeToHaplosomeMap, p_treeseq);\n\t\t__ConfigureSubpopulationsFromTables(p_interpreter, p_treeseq);\n\t}\n\t\n\tstd::unordered_map<slim_mutationid_t, MutationIndex> mutIndexMap;\n\t\n\t{\n\t\tstd::unordered_map<slim_mutationid_t, ts_mut_info> mutInfoMap;\n\t\t\n\t\t__TabulateMutationsFromTables(mutInfoMap, p_treeseq, p_file_version);\n\t\t__TallyMutationReferencesWithTreeSequence(mutInfoMap, nodeToHaplosomeMap, ts);\n\t\t__CreateMutationsFromTabulation(mutInfoMap, mutIndexMap, p_treeseq);\n\t}\n\t\n\t__AddMutationsFromTreeSequenceToHaplosomes(mutIndexMap, nodeToHaplosomeMap, ts, p_treeseq);\n\t\n\tret = tsk_treeseq_free(ts);\n\tif (ret != 0) handle_error(\"_InstantiateSLiMObjectsFromTables tsk_treeseq_free()\", ret);\n\tfree(ts);\n\t\n\t// Reset our last coalescence state; we don't know whether we're coalesced now or not\n\tp_treeseq.last_coalescence_state_ = false;\n}\n\nvoid Species::_InstantiateSLiMObjectsFromTables_SECONDARY(EidosInterpreter *p_interpreter, slim_tick_t p_metadata_tick, slim_tick_t p_metadata_cycle, SLiMModelType p_file_model_type, int p_file_version, SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq)\n{\n\t// NOTE: _InstantiateSLiMObjectsFromTables() handles the first (or only) chromosome being read in.  This\n\t// method handles the second and onward.  The code is quite similar, and should be maintained in parallel!\n\t\n\t// NOTE: At this stage we have our own nodes/individuals/population tables!  We will remove them at the end.\n\ttsk_table_collection_t &tables = p_treeseq.tables_;\n\tslim_chromosome_index_t chromosome_index = p_treeseq.chromosome_index_;\n\tChromosome *chromosome = Chromosomes()[chromosome_index];\n\t\n\t// check the sequence length against the chromosome length\n\tif (tables.sequence_length != chromosome->last_position_ + 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables_SECONDARY): chromosome length in loaded population (\" << tables.sequence_length << \") does not match the configured chromosome length (\" << (chromosome->last_position_ + 1) << \").\" << EidosTerminate();\n\t\n\t// check the tick and cycle; this should already have been validated externally\n\tif ((community_.Tick() != p_metadata_tick) || (Cycle() != p_metadata_cycle))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables_SECONDARY): (internal error) tick or cycle mismatch.\" << EidosTerminate();\n\t\n\t// rebase the times in the nodes to be in SLiM-land; see WriteTreeSequence for the inverse operation\n\t// BCH 4/4/2019: switched to using tree_seq_tick_ to avoid a parent/child timestamp conflict\n\t// This makes sense; as far as tree-seq recording is concerned, tree_seq_tick_ is the time counter\n\tslim_tick_t time_adjustment = community_.tree_seq_tick_;\n\t\n\tfor (size_t node_index = 0; node_index < tables.nodes.num_rows; ++node_index)\n\t\ttables.nodes.time[node_index] -= time_adjustment;\n\t\n\tfor (size_t mut_index = 0; mut_index < tables.mutations.num_rows; ++mut_index)\n\t\ttables.mutations.time[mut_index] -= time_adjustment;\n\t\n\t// check/rewrite the incoming tree-seq information in various ways\n\t__CheckPopulationMetadata(p_treeseq);\n\t__RemapSubpopulationIDs(p_subpop_map, p_treeseq, p_file_version);\n\t\n\t// allocate and set up the tree_sequence object\n\t// note that this tree sequence is based upon whatever sample the file was saved with, and may contain in-sample individuals\n\t// that are not presently alive, so we have to tread carefully; the actually alive individuals are flagged with \n\t// SLIM_TSK_INDIVIDUAL_ALIVE in the individuals table (there may also be remembered and retained individuals in there too)\n\ttsk_treeseq_t *ts;\n\tint ret = 0;\n\t\n\tts = (tsk_treeseq_t *)malloc(sizeof(tsk_treeseq_t));\n\tif (!ts)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tret = tsk_treeseq_init(ts, &tables, TSK_TS_INIT_BUILD_INDEXES);\n\tif (ret != 0) handle_error(\"_InstantiateSLiMObjectsFromTables tsk_treeseq_init()\", ret);\n\t\n\tstd::unordered_map<tsk_id_t, Haplosome *> nodeToHaplosomeMap;\n\t\n\t{\n\t\tstd::unordered_map<slim_objectid_t, ts_subpop_info> subpopInfoMap;\n\t\t\n\t\t__PrepareSubpopulationsFromTables(subpopInfoMap, p_treeseq);\n\t\t__TabulateSubpopulationsFromTreeSequence(subpopInfoMap, ts, p_treeseq, p_file_model_type);\n\t\t__CreateSubpopulationsFromTabulation_SECONDARY(subpopInfoMap, p_interpreter, nodeToHaplosomeMap, p_treeseq);\n\t\t__ConfigureSubpopulationsFromTables_SECONDARY(p_interpreter, p_treeseq);\n\t}\n\t\n\tstd::unordered_map<slim_mutationid_t, MutationIndex> mutIndexMap;\n\t\n\t{\n\t\tstd::unordered_map<slim_mutationid_t, ts_mut_info> mutInfoMap;\n\t\t\n\t\t__TabulateMutationsFromTables(mutInfoMap, p_treeseq, p_file_version);\n\t\t__TallyMutationReferencesWithTreeSequence(mutInfoMap, nodeToHaplosomeMap, ts);\n\t\t__CreateMutationsFromTabulation(mutInfoMap, mutIndexMap, p_treeseq);\n\t}\n\t\n\t__AddMutationsFromTreeSequenceToHaplosomes(mutIndexMap, nodeToHaplosomeMap, ts, p_treeseq);\n\t\n\tret = tsk_treeseq_free(ts);\n\tif (ret != 0) handle_error(\"_InstantiateSLiMObjectsFromTables tsk_treeseq_free()\", ret);\n\tfree(ts);\n\t\n\t// At this point we have loaded in and processed tables that are normally shared, and that\n\t// *should* be identical to the tables that we share with the main table collection.  We\n\t// may have made some changes above, such as remapping subpopulation IDs and whatnot, but\n\t// those changes should be deterministic, so those tables should still be identical to the\n\t// main table collection.  We will compare, to validate.\n\t_CompareNodeTables(treeseq_[0].tables_.nodes, p_treeseq.tables_.nodes);\n\t_CompareIndividualTables(treeseq_[0].tables_.individuals, p_treeseq.tables_.individuals);\n\t_ComparePopulationTables(treeseq_[0].tables_.populations, p_treeseq.tables_.populations);\n\t\n\t// Now we can remove our table copies to free up the memory usage immediately.\n\ttsk_node_table_free(&p_treeseq.tables_.nodes);\n\ttsk_individual_table_free(&p_treeseq.tables_.individuals);\n\ttsk_population_table_free(&p_treeseq.tables_.populations);\n\t\n\t// Reset our last coalescence state; we don't know whether we're coalesced now or not\n\tp_treeseq.last_coalescence_state_ = false;\n}\n\nvoid Species::_PostInstantiationCleanup(EidosInterpreter *p_interpreter)\n{\n\t// We have read in one or a set of chromosomes, instantiated corresponding SLiM objects, and now need to\n\t// clean up after ourselves.  The shared tables in the table collection should now be disconnected; only\n\t// the main table collection is now complete, and our final cleanup will operate on that.\n\tTreeSeqInfo &treeSeqInfo = treeseq_[0];\n\ttsk_table_collection_t &tables = treeSeqInfo.tables_;\n\t\n\t// Ensure that the next pedigree ID used will not cause a collision with any existing nodes in the node table,\n\t// and that there are no duplicate node pedigree IDs in the input file (whether in use or not).\n\t__CheckNodePedigreeIDs(p_interpreter, treeSeqInfo);\n\t\n\t// Set up the remembered haplosomes by looking though the list of nodes and their individuals\n\tif (remembered_nodes_.size() != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InstantiateSLiMObjectsFromTables): (internal error) remembered_nodes_ is not empty.\" << EidosTerminate();\n\t\n\tfor (tsk_id_t j = 0; (size_t) j < tables.nodes.num_rows; j++)\n\t{\n\t\ttsk_id_t ind = tables.nodes.individual[j];\n\t\tif (ind >=0)\n\t\t{\n\t\t\tuint32_t flags = tables.individuals.flags[ind];\n\t\t\tif (flags & SLIM_TSK_INDIVIDUAL_REMEMBERED)\n\t\t\t\tremembered_nodes_.emplace_back(j);\n\t\t}\n\t}\n\tassert(remembered_nodes_.size() % 2 == 0);\n\t\n\t// Sort them to match the order of the individual table, so that they satisfy\n\t// the invariants asserted in Species::AddIndividualsToTable(); see the comments there\n\ttsk_id_t *nodes_table_individuals = tables.nodes.individual;\n\t\n\tstd::sort(remembered_nodes_.begin(), remembered_nodes_.end(), [nodes_table_individuals](tsk_id_t l, tsk_id_t r) {\n\t\ttsk_id_t l_ind = nodes_table_individuals[l];\n\t\ttsk_id_t r_ind = nodes_table_individuals[r];\n\t\tif (l_ind != r_ind)\n\t\t\treturn l_ind < r_ind;\n\t\treturn l < r;\n\t});\n\t\n\t// Clear ALIVE flags\n\tFixAliveIndividuals(&tables);\n\t\n\t// Remove individuals that are not remembered or retained\n\tstd::vector<tsk_id_t> individual_map;\n\tfor (tsk_id_t j = 0; (size_t) j < tables.individuals.num_rows; j++)\n\t{\n\t\tuint32_t flags = tables.individuals.flags[j];\n\t\tif (flags & (SLIM_TSK_INDIVIDUAL_REMEMBERED | SLIM_TSK_INDIVIDUAL_RETAINED))\n\t\t\tindividual_map.emplace_back(j);\n\t}\n\tReorderIndividualTable(&tables, individual_map, false);\n\tBuildTabledIndividualsHash(&tables, &tabled_individuals_hash_);\n\t\n\t// Re-tally mutation references so we have accurate frequency counts for our new mutations\n\tpopulation_.UniqueMutationRuns();\n\tpopulation_.InvalidateMutationReferencesCache();\t// force a retally\n\tpopulation_.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t\n\t// Do a crosscheck to ensure data integrity\n\t// BCH 10/16/2019: this crosscheck can take a significant amount of time; for a single load that is not a big deal,\n\t// but for models that reload many times (e.g., conditional on fixation), this overhead can add up to a substantial\n\t// fraction of total runtime.  That's crazy, especially since I've never seen this crosscheck fail except when\n\t// actively working on the tree-seq code.  So let's run it only the first load, and then assume loads are valid,\n\t// if we're running a Release build.  With a Debug build we still check on every load.\n#if DEBUG\n\tCheckTreeSeqIntegrity();\n\tCrosscheckTreeSeqIntegrity();\n#else\n\t{\n\t\tstatic bool been_here = false;\n\t\t\n\t\tif (!been_here) {\n\t\t\tbeen_here = true;\n\t\t\tCheckTreeSeqIntegrity();\n\t\t\tCrosscheckTreeSeqIntegrity();\n\t\t}\n\t}\n#endif\n\t\n\t// Simplification has just been done, in effect (assuming the tree sequence we loaded is simplified; we assume that\n\t// here, but if that is not true, no harm done really except that it might be a while before we simplify again)\n\tsimplify_elapsed_ = 0;\n\t\n\t// I'm not sure why we record the table position here; it is used only by RetractNewIndividual().\n\tRecordTablePosition();\n\t\n\ttables_initialized_ = true;\n}\n\nslim_tick_t Species::_InitializePopulationFromTskitBinaryFile(const char *p_file, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_map, Chromosome &p_chromosome)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::_InitializePopulationFromTskitBinaryFile(): SLiM global state read\");\n\t\n\t// BEWARE: _InitializePopulationFromTskitDirectory() has a modified version of this code.  Maintain in parallel!\n\t\n\t// note that we now allow this to be called without tree-seq on, just to load haplosomes/mutations from the .trees file\n\tint ret;\n\n\tif (recording_tree_)\n\t\tFreeTreeSequence();\n\t\n\t// if tree-seq is not enabled, we set recording_mutations_ to true temporarily, so mutations get loaded without a raise\n\t// we remember the state of recording_tree_, because it gets forced to true as a side effect of loading\n\tbool was_recording_tree = recording_tree_;\n\t\n\tif (!was_recording_tree)\n\t{\n\t\trecording_tree_ = true;\n\t\trecording_mutations_ = true;\n\t}\n\t\n\t// make a new TreeSeqInfo record in treeseq_ and set it up\n\ttreeseq_.resize(1);\n\t\n\tTreeSeqInfo &treeSeqInfo = treeseq_.back();\n\t\n\ttreeSeqInfo.chromosome_index_ = p_chromosome.Index();\n\ttreeSeqInfo.last_coalescence_state_ = false;\n\t\n\tret = tsk_table_collection_load(&treeSeqInfo.tables_, p_file, TSK_LOAD_SKIP_REFERENCE_SEQUENCE);\t// we load the ref seq ourselves; see below\n\tif (ret != 0) handle_error(\"tsk_table_collection_load\", ret);\n\t\n\t// BCH 4/25/2019: if indexes are present on tables_ we want to drop them; they are synced up\n\t// with the edge table, but we plan to modify the edge table so they will become invalid anyway, and\n\t// then they may cause a crash because of their unsynced-ness; see tskit issue #179\n\tret = tsk_table_collection_drop_index(&treeSeqInfo.tables_, 0);\n\tif (ret != 0) handle_error(\"tsk_table_collection_drop_index\", ret);\n\n\t// read in the tree sequence metadata first so we have file version information and check for SLiM compliance and such\n\tslim_tick_t metadata_tick;\n\tslim_tick_t metadata_cycle;\n\tSLiMModelType file_model_type;\n\tint file_version;\n\t\n\tReadTreeSequenceMetadata(treeSeqInfo, &metadata_tick, &metadata_cycle, &file_model_type, &file_version);\n\t\n\t// convert ASCII derived-state data, which is the required format on disk, back to our in-memory binary format\n\tDerivedStatesFromAscii(&treeSeqInfo.tables_);\n\t\n\t// in nucleotide-based models, read the ancestral sequence; we do this ourselves, directly from kastore, to avoid having\n\t// tskit make a full ASCII copy of the reference sequences from kastore into tables_; see tsk_table_collection_load() above\n\t_ReadAncestralSequence(p_file, p_chromosome);\n\t\n\t// make the corresponding SLiM objects\n\t_InstantiateSLiMObjectsFromTables(p_interpreter, metadata_tick, metadata_cycle, file_model_type, file_version, p_subpop_map, treeSeqInfo);\n\t\n\t// cleanup such as handling remembered haplosomes and the individuals table, mutation tallying, and integrity checks\n\t// this incorporates all of the post-load work that spans the whole set of chromosomes in the model\n\t_PostInstantiationCleanup(p_interpreter);\n\t\n\t// if tree-seq is not on, throw away the tree-seq data structures now that we're done loading SLiM state\n\tif (!was_recording_tree)\n\t{\n\t\tFreeTreeSequence();\n\t\trecording_tree_ = false;\n\t\trecording_mutations_ = false;\n\t}\n\t\n\treturn metadata_tick;\n}\n\nslim_tick_t Species::_InitializePopulationFromTskitDirectory(std::string p_directory, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_remap)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::_InitializePopulationFromTskitDirectory(): SLiM global state read\");\n\t\n\t// First, get the .trees files in the directory\n\tint directory_length = (int)p_directory.length();\n\tbool directory_ends_in_slash = (directory_length > 0) && (p_directory[directory_length-1] == '/');\n\tstruct stat file_info;\n\tDIR *dp = opendir(p_directory.c_str());\n\tstd::vector<std::string> trees_paths;\n\t\n\tif (dp != NULL)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\terrno = 0;\n\t\t\tstruct dirent *ep = readdir(dp);\n\t\t\tint error = errno;\n\t\t\t\n\t\t\tif (!ep)\n\t\t\t{\n\t\t\t\tif (error)\n\t\t\t\t{\n\t\t\t\t\t(void)closedir(dp);\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the directory at path \" << p_directory << \" could not be read.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tstd::string interior_filename_base = ep->d_name;\n\t\t\t\n\t\t\tif ((interior_filename_base == \".\") || (interior_filename_base == \"..\"))\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tstd::string interior_filename = p_directory + (directory_ends_in_slash ? \"\" : \"/\") + interior_filename_base;\t\t// NOLINT(*-inefficient-string-concatenation) : this is fine\n\t\t\t\n\t\t\tbool file_exists = (stat(interior_filename.c_str(), &file_info) == 0);\n\t\t\t\n\t\t\tif (!file_exists)\n\t\t\t{\n\t\t\t\t(void)closedir(dp);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the directory at path \" << p_directory << \" could not be read.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tbool is_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\t\n\t\t\tif (!is_directory && Eidos_string_hasSuffix(interior_filename, \".trees\"))\n\t\t\t\ttrees_paths.push_back(interior_filename);\n\t\t}\n\t\t\n\t\t(void)closedir(dp);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the directory at path \" << p_directory << \" could not be read.\" << EidosTerminate();\n\t\n\t// Second, confirm that the count is correct and the symbols match\n\tconst std::vector<Chromosome *> &chromosomes = Chromosomes();\n\t\n\tif (trees_paths.size() != chromosomes.size())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the directory at path \" << p_directory << \" contains \" << trees_paths.size() << \" .trees files, but the focal species defines \" << Chromosomes().size() << \" chromosomes.\" << EidosTerminate();\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tconst std::string &symbol = chromosome->Symbol();\n\t\tstd::string expected_filename = std::string(\"chromosome_\") + symbol + \".trees\";\n\t\tstd::string expected_path = p_directory + (directory_ends_in_slash ? \"\" : \"/\") + expected_filename;\n\t\t\n\t\tif (std::find(trees_paths.begin(), trees_paths.end(), expected_path) == trees_paths.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the directory at path \" << p_directory << \" contains \" << trees_paths.size() << \" does not contain a chromosome file named \" << expected_filename << \", which is expected based upon the chromosomes defined in the focal species.\" << EidosTerminate();\n\t}\n\t\n\t// OK, we appear to have a well-formed multichrom archive that we can load.  Now we will load the data for\n\t// each chromosome.  The code here follows the pattern of _InitializePopulationFromTskitBinaryFile(), but\n\t// has been modified accordingly.  See that method for comments.  BEWARE: Maintain in parallel!\n\tslim_tick_t metadata_tick = 0;\n\tslim_tick_t metadata_cycle = 0;\n\tSLiMModelType file_model_type = SLiMModelType::kModelTypeWF;\n\tint file_version = 0;\n\t\n\tif (recording_tree_)\n\t\tFreeTreeSequence();\n\t\n\tbool was_recording_tree = recording_tree_;\n\t\n\tif (!was_recording_tree)\n\t{\n\t\trecording_tree_ = true;\n\t\trecording_mutations_ = true;\n\t}\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tbool is_first_chromosome = (chromosome == chromosomes[0]);\n\t\tconst std::string &symbol = chromosome->Symbol();\n\t\tstd::string expected_filename = std::string(\"chromosome_\") + symbol + \".trees\";\n\t\tstd::string expected_path = p_directory + (directory_ends_in_slash ? \"\" : \"/\") + expected_filename;\n\t\t\n\t\ttreeseq_.resize(treeseq_.size() + 1);\n\t\tTreeSeqInfo &treeSeqInfo = treeseq_.back();\n\t\ttreeSeqInfo.chromosome_index_ = chromosome->Index();\n\t\ttreeSeqInfo.last_coalescence_state_ = false;\n\t\t\n\t\tint ret = tsk_table_collection_load(&treeSeqInfo.tables_, expected_path.c_str(), TSK_LOAD_SKIP_REFERENCE_SEQUENCE);\n\t\tif (ret != 0) handle_error(\"tsk_table_collection_load\", ret);\n\t\t\n\t\tret = tsk_table_collection_drop_index(&treeSeqInfo.tables_, 0);\n\t\tif (ret != 0) handle_error(\"tsk_table_collection_drop_index\", ret);\n\t\t\n\t\tslim_tick_t this_metadata_tick;\n\t\tslim_tick_t this_metadata_cycle;\n\t\tSLiMModelType this_file_model_type;\n\t\tint this_file_version;\n\t\t\n\t\tReadTreeSequenceMetadata(treeSeqInfo, &this_metadata_tick, &this_metadata_cycle, &this_file_model_type, &this_file_version);\n\t\t\n\t\tif (is_first_chromosome)\n\t\t{\n\t\t\tmetadata_tick = this_metadata_tick;\n\t\t\tmetadata_cycle = this_metadata_cycle;\n\t\t\tfile_model_type = this_file_model_type;\n\t\t\tfile_version = this_file_version;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (this_metadata_tick != metadata_tick)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the .trees files for chromosomes were saved in different ticks (\" << metadata_tick << \" versus \" << this_metadata_tick << \").  This must be consistent across all files.\" << EidosTerminate();\n\t\t\tif (this_metadata_cycle != metadata_cycle)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the .trees files for chromosomes were saved in different ticks (\" << metadata_cycle << \" versus \" << this_metadata_cycle << \").  This must be consistent across all files.\" << EidosTerminate();\n\t\t\tif (this_file_model_type != file_model_type)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the .trees files for chromosomes were saved from different model types (WF versus nonWF).  This must be consistent across all files.\" << EidosTerminate();\n\t\t\tif (this_file_version != file_version)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::_InitializePopulationFromTskitDirectory): the .trees files for chromosomes have different file versions (\" << file_version << \" versus \" << this_file_version << \").  This must be consistent across all files.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tDerivedStatesFromAscii(&treeSeqInfo.tables_);\n\t\t_ReadAncestralSequence(expected_path.c_str(), *chromosome);\n\t\t\n\t\t// The first chromosome uses _InstantiateSLiMObjectsFromTables() and creates the subpopulations, etc.,\n\t\t// as needed.  The remaining chromosomes use _InstantiateSLiMObjectsFromTables_SECONDARY(), which\n\t\t// checks against the population structure that was created; it should always match exactly.\n\t\tif (is_first_chromosome)\n\t\t\t_InstantiateSLiMObjectsFromTables(p_interpreter, metadata_tick, metadata_cycle, file_model_type, file_version, p_subpop_remap, treeSeqInfo);\n\t\telse\n\t\t\t_InstantiateSLiMObjectsFromTables_SECONDARY(p_interpreter, metadata_tick, metadata_cycle, file_model_type, file_version, p_subpop_remap, treeSeqInfo);\n\t}\n\t\n\t// cleanup such as handling remembered haplosomes and the individuals table, mutation tallying, and integrity checks\n\t// this incorporates all of the post-load work that spans the whole set of chromosomes in the model\n\t_PostInstantiationCleanup(p_interpreter);\n\t\n\tif (!was_recording_tree)\n\t{\n\t\tFreeTreeSequence();\n\t\trecording_tree_ = false;\n\t\trecording_mutations_ = false;\n\t}\n\t\n\treturn metadata_tick;\n}\n\nsize_t Species::MemoryUsageForTreeSeqInfo(TreeSeqInfo &p_tsinfo, bool p_count_shared_tables)\n{\n\ttsk_table_collection_t &t = p_tsinfo.tables_;\n\tsize_t usage = 0;\n\t\n\t// the individuals table, nodes table, and population table are shared\n\tif (p_count_shared_tables)\n\t{\n\t\tusage += sizeof(tsk_individual_table_t);\n\t\t\n\t\tif (t.individuals.flags)\n\t\t\tusage += t.individuals.max_rows * sizeof(uint32_t);\n\t\tif (t.individuals.location_offset)\n\t\t\tusage += t.individuals.max_rows * sizeof(tsk_size_t);\n\t\tif (t.individuals.parents_offset)\n\t\t\tusage += t.individuals.max_rows * sizeof(tsk_size_t);\n\t\tif (t.individuals.metadata_offset)\n\t\t\tusage += t.individuals.max_rows * sizeof(tsk_size_t);\n\t\t\n\t\tif (t.individuals.location)\n\t\t\tusage += t.individuals.max_location_length * sizeof(double);\n\t\tif (t.individuals.parents)\n\t\t\tusage += t.individuals.max_parents_length * sizeof(tsk_id_t);\n\t\tif (t.individuals.metadata)\n\t\t\tusage += t.individuals.max_metadata_length * sizeof(char);\n\t\t\n\t\tusage += sizeof(tsk_node_table_t);\n\t\t\n\t\tif (t.nodes.flags)\n\t\t\tusage += t.nodes.max_rows * sizeof(uint32_t);\n\t\tif (t.nodes.time)\n\t\t\tusage += t.nodes.max_rows * sizeof(double);\n\t\tif (t.nodes.population)\n\t\t\tusage += t.nodes.max_rows * sizeof(tsk_id_t);\n\t\tif (t.nodes.individual)\n\t\t\tusage += t.nodes.max_rows * sizeof(tsk_id_t);\n\t\tif (t.nodes.metadata_offset)\n\t\t\tusage += t.nodes.max_rows * sizeof(tsk_size_t);\n\t\t\n\t\tif (t.nodes.metadata)\n\t\t\tusage += t.nodes.max_metadata_length * sizeof(char);\n\t\t\n\t\tusage += sizeof(tsk_population_table_t);\n\t\t\n\t\tif (t.populations.metadata_offset)\n\t\t\tusage += t.populations.max_rows * sizeof(tsk_size_t);\n\t\t\n\t\tif (t.populations.metadata)\n\t\t\tusage += t.populations.max_metadata_length * sizeof(char);\n\t}\n\t\n\tusage += sizeof(tsk_edge_table_t);\n\t\n\tif (t.edges.left)\n\t\tusage += t.edges.max_rows * sizeof(double);\n\tif (t.edges.right)\n\t\tusage += t.edges.max_rows * sizeof(double);\n\tif (t.edges.parent)\n\t\tusage += t.edges.max_rows * sizeof(tsk_id_t);\n\tif (t.edges.child)\n\t\tusage += t.edges.max_rows * sizeof(tsk_id_t);\n\t\n\tusage += sizeof(tsk_migration_table_t);\n\t\n\tif (t.migrations.source)\n\t\tusage += t.migrations.max_rows * sizeof(tsk_id_t);\n\tif (t.migrations.dest)\n\t\tusage += t.migrations.max_rows * sizeof(tsk_id_t);\n\tif (t.migrations.node)\n\t\tusage += t.migrations.max_rows * sizeof(tsk_id_t);\n\tif (t.migrations.left)\n\t\tusage += t.migrations.max_rows * sizeof(double);\n\tif (t.migrations.right)\n\t\tusage += t.migrations.max_rows * sizeof(double);\n\tif (t.migrations.time)\n\t\tusage += t.migrations.max_rows * sizeof(double);\n\t\n\tusage += sizeof(tsk_site_table_t);\n\t\n\tif (t.sites.position)\n\t\tusage += t.sites.max_rows * sizeof(double);\n\tif (t.sites.ancestral_state_offset)\n\t\tusage += t.sites.max_rows * sizeof(tsk_size_t);\n\tif (t.sites.metadata_offset)\n\t\tusage += t.sites.max_rows * sizeof(tsk_size_t);\n\t\n\tif (t.sites.ancestral_state)\n\t\tusage += t.sites.max_ancestral_state_length * sizeof(char);\n\tif (t.sites.metadata)\n\t\tusage += t.sites.max_metadata_length * sizeof(char);\n\t\n\tusage += sizeof(tsk_mutation_table_t);\n\t\n\tif (t.mutations.node)\n\t\tusage += t.mutations.max_rows * sizeof(tsk_id_t);\n\tif (t.mutations.site)\n\t\tusage += t.mutations.max_rows * sizeof(tsk_id_t);\n\tif (t.mutations.parent)\n\t\tusage += t.mutations.max_rows * sizeof(tsk_id_t);\n\tif (t.mutations.derived_state_offset)\n\t\tusage += t.mutations.max_rows * sizeof(tsk_size_t);\n\tif (t.mutations.metadata_offset)\n\t\tusage += t.mutations.max_rows * sizeof(tsk_size_t);\n\t\n\tif (t.mutations.derived_state)\n\t\tusage += t.mutations.max_derived_state_length * sizeof(char);\n\tif (t.mutations.metadata)\n\t\tusage += t.mutations.max_metadata_length * sizeof(char);\n\t\n\tusage += sizeof(tsk_provenance_table_t);\n\t\n\tif (t.provenances.timestamp_offset)\n\t\tusage += t.provenances.max_rows * sizeof(tsk_size_t);\n\tif (t.provenances.record_offset)\n\t\tusage += t.provenances.max_rows * sizeof(tsk_size_t);\n\t\n\tif (t.provenances.timestamp)\n\t\tusage += t.provenances.max_timestamp_length * sizeof(char);\n\tif (t.provenances.record)\n\t\tusage += t.provenances.max_record_length * sizeof(char);\n\t\n\tusage += remembered_nodes_.size() * sizeof(tsk_id_t);\n\t\n\treturn usage;\n}\n\nvoid Species::TSXC_Enable(void)\n{\n\t// This is called by command-line slim if a -TSXC command-line option is supplied; the point of this is to allow\n\t// tree-sequence recording to be turned on, with mutation recording and runtime crosschecks, with a simple\n\t// command-line flag, so that my existing test suite can be crosschecked easily.  The -TSXC flag is not public.\n\trecording_tree_ = true;\n\trecording_mutations_ = true;\n\tsimplification_ratio_ = 10.0;\n\tsimplification_interval_ = -1;\t\t\t// this means \"use the ratio, not a fixed interval\"\n\tsimplify_interval_ = 20;\t\t\t\t// this is the initial simplification interval\n\trunning_coalescence_checks_ = false;\n\trunning_treeseq_crosschecks_ = true;\n\ttreeseq_crosschecks_interval_ = 50;\t\t// check every 50th cycle, otherwise it is just too slow\n\t\n\tpedigrees_enabled_ = true;\n\tpedigrees_enabled_by_SLiM_ = true;\n}\n\nvoid Species::TSF_Enable(void)\n{\n\t// This is called by command-line slim if a -TSF command-line option is supplied; the point of this is to allow\n\t// tree-sequence recording to be turned on, with mutation recording but without runtime crosschecks, with a simple\n\t// command-line flag, so that my existing test suite can be tested with tree-seq easily.  -TSF is not public.\n\trecording_tree_ = true;\n\trecording_mutations_ = true;\n\tsimplification_ratio_ = 10.0;\n\tsimplification_interval_ = -1;            // this means \"use the ratio, not a fixed interval\"\n\tsimplify_interval_ = 20;                // this is the initial simplification interval\n\trunning_coalescence_checks_ = false;\n\trunning_treeseq_crosschecks_ = false;\n\t\n\tpedigrees_enabled_ = true;\n\tpedigrees_enabled_by_SLiM_ = true;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/species.h",
    "content": "//\n//  species.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/26/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n SLiM encapsulates a simulation run as a Species object.  This allows a simulation to be stepped and controlled by a GUI.\n \n */\n\n#ifndef __SLiM__species__\n#define __SLiM__species__\n\n\n#include <vector>\n#include <map>\n#include <ctime>\n#include <unordered_set>\n\n#include \"slim_globals.h\"\n#include \"population.h\"\n#include \"chromosome.h\"\n#include \"eidos_value.h\"\n#include \"mutation_run.h\"\n\n//TREE SEQUENCE\n//INCLUDE JEROME's TABLES API\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include \"../treerec/tskit/trees.h\"\n#include \"../treerec/tskit/tables.h\"\n#include \"../treerec/tskit/text_input.h\"\n#ifdef __cplusplus\n}\n#endif\n\n\nclass Community;\nclass EidosInterpreter;\nclass Individual;\nclass MutationType;\nclass GenomicElementType;\nclass InteractionType;\nstruct ts_subpop_info;\nstruct ts_mut_info;\n\nextern EidosClass *gSLiM_Species_Class;\n\nenum class SLiMFileFormat\n{\n\tkFileNotFound = -1,\n\tkFormatUnrecognized = 0,\n\tkFormatSLiMText,\t\t\t\t// as saved by outputFull(filePath, binary=F)\n\tkFormatSLiMBinary,\t\t\t\t// as saved by outputFull(filePath, binary=T)\n\tkFormatTskitBinary_HDF5,\t\t// old file format, no longer supported\n\tkFormatTskitBinary_kastore,\t\t// as saved by treeSeqOutput(path)\n\tkFormatDirectory,\t\t\t\t// a directory, presumed to contain .trees files for multiple chromosomes\n};\n\n\n// We have a defined maximum number of chromosomes that we resize to immediately, so the chromosome vector never reallocs\n// There would be an upper limit of 256 anyway because Mutation uses uint8_t to keep the index of its chromosome\n#define SLIM_MAX_CHROMOSOMES\t256\n\n\n// TREE SEQUENCE RECORDING\n#pragma mark -\n#pragma mark treeseq recording metadata records\n#pragma mark -\n\n// These structs are used by the tree-rec code to record all metadata about an object that needs to be saved.\n// Note that this information is a snapshot taken at one point in time, and may become stale; be careful.\n// Changing these structs will break binary compatibility in our output files, and requires changes elsewhere.\n// Note that these structs are packed, and so accesses to them and within them may be unaligned; we assume\n// that is OK on the platforms we run on, so as to keep file sizes down.\n\ntypedef struct __attribute__((__packed__)) {\n\tslim_objectid_t mutation_type_id_;\t\t// 4 bytes (int32_t): the id of the mutation type the mutation belongs to\n\tslim_selcoeff_t selection_coeff_;\t\t// 4 bytes (float): the selection coefficient\n\tslim_objectid_t subpop_index_;\t\t\t// 4 bytes (int32_t): the id of the subpopulation in which the mutation arose\n\tslim_tick_t origin_tick_;\t\t\t\t// 4 bytes (int32_t): the tick in which the mutation arose\n\tint8_t nucleotide_;\t\t\t\t\t\t// 1 byte (int8_t): the nucleotide for the mutation (0='A', 1='C', 2='G', 3='T'), or -1\n} MutationMetadataRec;\n\ntypedef struct __attribute__((__packed__)) {\n\t// BCH 12/10/2024: This metadata record is becoming a bit complicated, for multichromosome SLiM, and is now actually variable-length.\n\t// The difficulty is that this metadata gets attached to nodes in the tree sequence, and in multichrom models the node table is\n\t// shared by all of the chromosome-specific tree sequences.  That implies that the haplosome metadata has to be the *same* for all\n\t// of the haplosomes that reference that node -- all the first haplosomes of an individual, or all the second haplosomes of an\n\t// individual.  We want to keep is_vacant_ state separately for each haplosome; within one individual, some haplosomes might be nulls,\n\t// other might not be, and we need to know the difference to correctly read/analyze a tree sequence.  To achieve this, each node's\n\t// metadata -- HaplosomeMetadataRec -- will record a *vector* of is_vacant_ bytes, each containing 8 bits, recording the is_vacant_\n\t// state for each of the haplosome slots represented by the node in its owning individual.  Note that haplosome slots for a given\n\t// node can actually have three states in an individual: \"real\", \"null\", or \"unused\".  \"Real\" would be the first haplosome for the\n\t// Y in a male; \"null\" would be the first haplosome for the Y in a female (a placeholder for the Y that could be there but is not);\n\t// and \"unused\" would be the *second* haplosome for the Y in either sex (because the Y is a haploid chromosome, and haplosomes for\n\t// the second position therefore do not exist -- but a node for that slot still exists, because we *always* make two nodes in the\n\t// tree sequence for each chromosome, to maintain the 1:2 individual_id:node_id invariant that we assume throughout the code).  The\n\t// flags in is_vacant_ differentiate between \"real\" and \"unused\"/\"null\"; the value for \"unused\" positions should indicate \"vacant\",\n\t// just as for \"null\" positions.  See Species::_MakeHaplosomeMetadataRecords() and elsewhere.\n\t//\n\tslim_haplosomeid_t haplosome_id_;\t\t// 8 bytes (int64_t): the SLiM haplosome ID for this haplosome, assigned by pedigree rec\n\t\t\t\t\t\t\t\t\t\t\t// \t\tnote that the ID is the same across all chromosomes in an individual!\n\tuint8_t is_vacant_[1];\t\t\t\t\t// 1 byte (8 bits, handled bitwise) -- but this field is actually variable-length, see above\n\t// BCH 12/6/2024: type_, the chromosome type for the haplosome, has moved to top-level metadata; it is constant across a tree sequence\n} HaplosomeMetadataRec;\n\ntypedef struct __attribute__((__packed__)) {\n\tslim_pedigreeid_t pedigree_id_;\t\t\t// 8 bytes (int64_t): the SLiM pedigree ID for this individual, assigned by pedigree rec\n\tslim_pedigreeid_t pedigree_p1_;\t\t\t// 8 bytes (int64_t): the SLiM pedigree ID for this individual's parent 1\n\tslim_pedigreeid_t pedigree_p2_;\t\t\t// 8 bytes (int64_t): the SLiM pedigree ID for this individual's parent 2\n\tslim_age_t age_;                        // 4 bytes (int32_t): the age of the individual (-1 for WF models)\n\tslim_objectid_t subpopulation_id_;      // 4 bytes (int32_t): the subpopulation the individual belongs to\n\tint32_t sex_;\t\t\t\t\t\t\t// 4 bytes (int32_t): the sex of the individual, as defined by the IndividualSex enum\n\tuint32_t flags_;\t\t\t\t\t\t// 4 bytes (uint32_t): assorted flags, see below\n} IndividualMetadataRec;\n\n#define SLIM_INDIVIDUAL_METADATA_MIGRATED\t0x01\t// set if the individual has migrated in this cycle\n\n// We double-check the size of these records to make sure we understand what they contain and how they're packed\nstatic_assert(sizeof(MutationMetadataRec) == 17, \"MutationMetadataRec is not 17 bytes!\");\nstatic_assert(sizeof(HaplosomeMetadataRec) == 9, \"HaplosomeMetadataRec is not 9 bytes!\");\t// but its size is dynamic at runtime\nstatic_assert(sizeof(IndividualMetadataRec) == 40, \"IndividualMetadataRec is not 40 bytes!\");\n\n// We check endianness on the platform we're building on; we assume little-endianness in our read/write code, I think.\n#if defined(__BYTE_ORDER__)\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#warning Reading and writing binary files with SLiM may produce non-standard results on this (big-endian) platform due to endianness\n#endif\n#endif\n\n\n#pragma mark -\n#pragma mark Species\n#pragma mark -\n\nclass Species : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\n#ifdef SLIMGUI\npublic:\n#else\nprivate:\n#endif\n\t\n\t// Species simulation state\n\tslim_tick_t cycle_ = 0;\t\t\t\t\t\t\t\t\t\t\t\t\t// the current cycle reached in simulation\n\tEidosValue_SP cached_value_cycle_;\t\t\t\t\t\t\t\t\t\t\t// a cached value for cycle_; invalidates automatically when used\n\t\n\tbool species_active_ = true;\t\t\t\t\t\t\t\t\t\t\t\t\t// the \"active\" property of the species\n\tslim_tick_t tick_modulo_ = 1;\t\t\t\t\t\t\t\t\t\t\t\t\t// the species is active every tick_modulo_ ticks\n\tslim_tick_t tick_phase_ = 1;\t\t\t\t\t\t\t\t\t\t\t\t\t// the species is first active in tick tick_phase_\n\t\n\tstd::string color_;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// color to use when displayed (in SLiMgui)\n\tfloat color_red_, color_green_, color_blue_;\t\t\t\t\t\t\t\t\t// cached color components from color_; should always be in sync\n\t\n\tbool has_genetics_ = true;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// false if the species has no mutation, no recombination, no muttypes/getypes, no genomic elements\n\t\n\t// for multiple chromosomes, we now have a vector of pointers to Chromosome objects,\n\t// as well as hash tables for quick lookup by id and symbol\n#if EIDOS_ROBIN_HOOD_HASHING\n\ttypedef robin_hood::unordered_flat_map<int64_t, Chromosome *> CHROMOSOME_ID_HASH;\n\ttypedef robin_hood::unordered_flat_map<std::string, Chromosome *> CHROMOSOME_SYMBOL_HASH;\n#elif STD_UNORDERED_MAP_HASHING\n\ttypedef std::unordered_map<int64_t, Chromosome *> CHROMOSOME_ID_HASH;\n\ttypedef std::unordered_map<std::string, Chromosome *> CHROMOSOME_SYMBOL_HASH;\n#endif\n\t\n\t// Chromosome state\n\tstd::vector<Chromosome *> chromosomes_;\t\t\t\t// OWNED (retained); all our chromosomes, in the order in which they were defined\n\tCHROMOSOME_ID_HASH chromosome_from_id_;\t\t\t\t// NOT OWNED; get a chromosome from a chromosome id quickly\n\tCHROMOSOME_SYMBOL_HASH chromosome_from_symbol_;\t\t// NOT OWNED; get a chromosome from a chromosome symbol quickly\n\t\n\tstd::vector<Chromosome *> chromosome_for_haplosome_index_;\t// NOT OWNED; of length haplosome_count_per_individual_\n\tstd::vector<uint8_t> chromosome_subindex_for_haplosome_index_;\t// 0 or 1, the first or second haplosome for the chromosome\n\tstd::vector<int> first_haplosome_index_;\t\t\t// the first index in haplosomes_ for a given chromosome (synced to chromosomes_)\n\tstd::vector<int> last_haplosome_index_;\t\t\t\t// the last index in haplosomes_ for a given chromosome (synced to chromosomes_)\n\tint haplosome_count_per_individual_ = 0;\t\t\t// the total number of haplosomes per individual, based on the chromosome types\n\tbool chromosomes_use_null_haplosomes_ = false;\t\t// set to true if our chromosome types use null haplosomes; check this with CouldContainNullHaplosomes()\n\t\n\t// std::map is used instead of std::unordered_map mostly for convenience, for sorted order in the UI; these are unlikely to be bottlenecks I think\n\tstd::map<slim_objectid_t,MutationType*> mutation_types_;\t\t\t\t\t\t// OWNED POINTERS: this map is the owner of all allocated MutationType objects\n\tstd::map<slim_objectid_t,GenomicElementType*> genomic_element_types_;\t\t\t// OWNED POINTERS: this map is the owner of all allocated GenomicElementType objects\n\t\n\tbool mutation_stack_policy_changed_ = true;\t\t\t\t\t\t\t\t\t\t// when set, the stacking policy settings need to be checked for consistency\n\t\n\t// SEX ONLY: sex-related instance variables\n\tbool sex_enabled_ = false;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// true if sex is tracked for individuals; if false, all individuals are hermaphroditic\n\t\n\t// private initialization methods\n#if EIDOS_ROBIN_HOOD_HASHING\n\ttypedef robin_hood::unordered_flat_map<int64_t, slim_objectid_t> SUBPOP_REMAP_HASH;\n #elif STD_UNORDERED_MAP_HASHING\n\ttypedef std::unordered_map<int64_t, slim_objectid_t> SUBPOP_REMAP_HASH;\n #endif\n\t\n\tSLiMFileFormat FormatOfPopulationFile(const std::string &p_file_string);\t\t// determine the format of a file/folder at the given path using leading bytes, etc.\n\tvoid _CleanAllReferencesToSpecies(EidosInterpreter *p_interpreter);\t\t\t\t// clean up in anticipation of loading new species state\n\tslim_tick_t InitializePopulationFromFile(const std::string &p_file_string, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_remap);\t// initialize the population from the file\n\tslim_tick_t _InitializePopulationFromTextFile(const char *p_file, EidosInterpreter *p_interpreter);\t\t\t\t// initialize the population from a SLiM text file\n\tslim_tick_t _InitializePopulationFromBinaryFile(const char *p_file, EidosInterpreter *p_interpreter);\t\t\t// initialize the population from a SLiM binary file\n\t\n\t// a \"temporary graveyard\" for keeping individuals that have been killed by killIndividuals(), until they can be freed\n\tstd::vector<Individual *> graveyard_;\n\t\n\t// pedigree tracking: off by default, optionally turned on at init time to enable calls to TrackParentage_X()\n\tbool pedigrees_enabled_ = false;\n\tbool pedigrees_enabled_by_user_ = false;\t\t// pedigree tracking was turned on by the user, which is user-visible\n\tbool pedigrees_enabled_by_SLiM_ = false;\t\t// pedigree tracking has been forced on by tree-seq recording or SLiMgui, which is not user-visible\n\t\n\t// continuous space support\n\tint spatial_dimensionality_ = 0;\n\tbool periodic_x_ = false;\n\tbool periodic_y_ = false;\n\tbool periodic_z_ = false;\n\t\n\t// preventing incidental selfing in hermaphroditic models\n\tbool prevent_incidental_selfing_ = false;\n\t\n\t// mutation run timing experiment configuration\n\tbool do_mutrun_experiments_ = true;\t\t\t\t// user-level flag in initializeSLiMOptions(); if false, experiments are never run\n\tbool doing_any_mutrun_experiments_ = false;\t\t// is any chromosome actually running mutation run timing experiments?\n\t\n\t// nucleotide-based models\n\tbool nucleotide_based_ = false;\n\t\n\tdouble max_nucleotide_mut_rate_;\t\t\t\t// the highest rate for any genetic background in any genomic element type\n\tvoid CacheNucleotideMatrices(void);\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t\t\t\t\t\t\t\t// for fast setup of the symbol table\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t\t\t\t\t\t\t\t// a user-defined tag value\n\t\n\t// Shuffle buffer.  This is a shared buffer of sequential values that can be used by client code to shuffle the order in which\n\t// operations are performed.  The buffer always contains [0, 1, ..., N-1] shuffled into a new random order with each request\n\t// if randomized callbacks are enabled (the default in SLiM 4), or [0, 1, ..., N-1] in sequence if they are disabled.\n\t// Never access these ivars directly; always use BorrowShuffleBuffer() and ReturnShuffleBuffer().\n\tslim_popsize_t *shuffle_buffer_ = nullptr;\n\tslim_popsize_t shuffle_buf_capacity_ = 0;\t// allocated capacity\n\tslim_popsize_t shuffle_buf_size_ = 0;\t\t// the number of entries actually usable\n\tbool shuffle_buf_borrowed_ = false;\t\t\t// a safeguard against re-entrancy\n\tbool shuffle_buf_is_enabled_ = true;\t\t// if false, the buffer is \"pass-through\" - just sequential integers\n\t\n\t//\n\t// Initialization completeness check counts; should be used only when running initialize() callbacks\n\t//\n\t\n\t// per-species initialization; zeroed by Species::RunInitializeCallbacks()\n\tint num_species_inits_;\t\t\t\t// number of calls to initializeSpecies()\n\tint num_slimoptions_inits_;\t\t\t// number of calls to initializeSLiMOptions()\n\tint num_mutation_type_inits_;\t\t// number of calls to initializeMutationType() and initializeMutationTypeNuc()\n\tint num_ge_type_inits_;\t\t\t\t// number of calls to initializeGenomicElementType()\n\tint num_sex_inits_;\t\t\t\t\t// SEX ONLY: number of calls to initializeSex()\n\tint num_treeseq_inits_;\t\t\t\t// number of calls to initializeTreeSeq()\n\tint num_chromosome_inits_;\t\t\t// number of calls to initializeChromosome()\n\tbool has_implicit_chromosome_;\t\t// true if the model implicitly defines a chromosome, with no initializeChromosome() call\n\tbool has_currently_initializing_chromosome_ = false;\n\t\n\t// per-chromosome initialization; zeroed by initializeChromosome()\n\tint num_mutrate_inits_;\t\t\t\t// number of calls to initializeMutationRate()\n\tint num_recrate_inits_;\t\t\t\t// number of calls to initializeRecombinationRate()\n\tint num_genomic_element_inits_;\t\t// number of calls to initializeGenomicElement()\n\tint num_gene_conv_inits_;\t\t\t// number of calls to initializeGeneConversion()\n\tint num_ancseq_inits_;\t\t\t\t// number of calls to initializeAncestralNucleotides()\n\tint num_hotmap_inits_;\t\t\t\t// number of calls to initializeHotspotMap()\n\t\n\tslim_position_t last_genomic_element_position_ = -1;\t// used to check new genomic elements for consistency\n\t\n\t//\n\t// TREE SEQUENCE RECORDING\n\t//\n#pragma mark -\n#pragma mark treeseq recording ivars\n#pragma mark -\n\t// ********** first we have tree-seq state that is shared across all chromosomes\n\t//\n\tbool recording_tree_ = false;\t\t\t\t// true if we are doing tree sequence recording\n\tbool recording_mutations_ = false;\t\t\t// true if we are recording mutations in our tree sequence tables\n\tbool retain_coalescent_only_ = true;\t\t// true if \"retain\" keeps only individuals for coalescent nodes, not also individuals for unary nodes\n\t\n\tbool tables_initialized_ = false;\t\t\t// not checked everywhere, just when allocing and freeing, to avoid crashes\n\t\n    std::vector<tsk_id_t> remembered_nodes_;\t// used to be called remembered_genomes_, but it remembers tskit nodes, which might\n\t\t\t\t\t\t\t\t\t\t\t\t// actually be shared by multiple haplosomes in different chromosomes\n\t//Individual *current_new_individual_;\n\t\n#if EIDOS_ROBIN_HOOD_HASHING\n\ttypedef robin_hood::unordered_flat_map<slim_pedigreeid_t, tsk_id_t> INDIVIDUALS_HASH;\n #elif STD_UNORDERED_MAP_HASHING\n\ttypedef std::unordered_map<slim_pedigreeid_t, tsk_id_t> INDIVIDUALS_HASH;\n #endif\n\tINDIVIDUALS_HASH tabled_individuals_hash_;\t// look up individuals table row numbers from pedigree IDs\n\n\tbool running_coalescence_checks_ = false;\t// true if we check for coalescence after each simplification\n\tbool running_treeseq_crosschecks_ = false;\t// true if crosschecks between our tree sequence tables and SLiM's data are enabled\n\tint treeseq_crosschecks_interval_ = 1;\t\t// crosschecks, if enabled, will be done every treeseq_crosschecks_interval_ cycles\n\t\n\tdouble simplification_ratio_;\t\t\t\t// the pre:post table size ratio we target with our automatic simplification heuristic\n\tint64_t simplification_interval_;\t\t\t// the cycle interval between simplifications; -1 if not used (in which case the ratio is used)\n\tint64_t simplify_elapsed_ = 0;\t\t\t\t// the number of cycles elapsed since a simplification was done (automatic or otherwise)\n\tdouble simplify_interval_;\t\t\t\t\t// the current number of cycles between automatic simplifications when using simplification_ratio_\n\t\n\tsize_t haplosome_metadata_size_;\t\t\t// the number of bytes for haplosome metadata, for this species, including is_vacant_ flags\n\tsize_t haplosome_metadata_is_vacant_bytes_;\t// the number of bytes used for is_vacant_ in the haplosome metadata\n\tHaplosomeMetadataRec *hap_metadata_1F_ = nullptr;\t\t// malloced; default is_vacant_ flags for first haplosomes in females/hermaphrodites\n\tHaplosomeMetadataRec *hap_metadata_1M_ = nullptr;\t\t// malloced; default is_vacant_ flags for first haplosomes in males\n\tHaplosomeMetadataRec *hap_metadata_2F_ = nullptr;\t\t// malloced; default is_vacant_ flags for second haplosomes in females/hermaphrodites\n\tHaplosomeMetadataRec *hap_metadata_2M_ = nullptr;\t\t// malloced; default is_vacant_ flags for second haplosomes in males\n\tvoid _MakeHaplosomeMetadataRecords(void);\n\t\n\t// ********** then we have tree-seq state that is kept separately for each chromosome; each has its own tree sequence\n\t//\n\ttypedef struct _TreeSeqInfo {\n\t\tslim_chromosome_index_t chromosome_index_;\t// this should range from 0 to N-1, following the corresponding chromosome indices\n\t\ttsk_table_collection_t tables_;\t\t\t\t// the table collection; the node, individual, and popultation tables are shared\n\t\ttsk_bookmark_t table_position_;\t\t\t\t// a bookmarked position in tables_ for retraction of a proposed child\n\t\tbool last_coalescence_state_;\t\t\t\t// have we coalesced? updated after simplify if running_coalescence_checks_==true\n\t} TreeSeqInfo;\n\t\n\tstd::vector<TreeSeqInfo> treeseq_;\t\t\t\t// OWNED; all our tree-sequence state, in the order the chromosomes were defined\n\t\t\t\t\t\t\t\t\t\t\t\t\t// index 0's table collection contains the shared tables; see CopySharedTablesIn()\n\t\npublic:\n\t\n\t// Object pools for individuals and haplosomes, kept population-wide; these must be above their clients in the declaration order\n\t// BCH 28 Jan. 2025: These are now kept by the Species, not the Population, so that they can be destructed after all clients have destructed\n\tEidosObjectPool species_haplosome_pool_;\t// a pool out of which haplosomes are allocated, for within-species locality\n\tEidosObjectPool species_individual_pool_;\t// a pool out of which individuals are allocated, for within-species locality\n\t\n\tSLiMModelType model_type_;\n\tCommunity &community_;\t\t\t\t\t\t// the community that this species belongs to\n\tPopulation population_;\t\t\t\t\t\t// the population, which contains sub-populations\n\n\tstd::string avatar_;\t\t\t\t\t\t// a string used as the \"avatar\" for this species in SLiMgui, and perhaps elsewhere\n\tstd::string name_;\t\t\t\t\t\t\t// the `name` property; \"sim\" by default, configurable in script (not by setting the property)\n\tstd::string description_;\t\t\t\t\t// the `description` property; the empty string by default\n\tslim_objectid_t species_id_;\t\t\t\t// the identifier for the species, which its index into the Community's species vector\n\t\n\tbool has_recalculated_fitness_ = false;\t\t// set to true when recalculateFitness() is called, so we know fitness values are valid\n\t\n\t// optimization of the pure neutral case; this is set to false if (a) a non-neutral mutation is added by the user, (b) a genomic element type is configured to use a\n\t// non-neutral mutation type, (c) an already existing mutation type (assumed to be in use) is set to a non-neutral DFE, or (d) a mutation's selection coefficient is\n\t// changed to non-neutral.  The flag is never set back to true.  Importantly, simply defining a non-neutral mutation type does NOT clear this flag; we want sims to be\n\t// able to run a neutral burn-in at full speed, only slowing down when the non-neutral mutation type is actually used.  BCH 12 January 2018: Also, note that this flag\n\t// is unaffected by the fitness_scaling_ properties on Subpopulation and Individual, which are taken into account even when this flag is set.\n\tbool pure_neutral_ = true;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// optimization flag\n\t\n\t// this flag tracks whether a type 's' mutation type has ever been seen; we just set it to true if we see one, we never set it back to false again, for simplicity\n\t// this switches to a less optimized case when evolving in WF models, if a type 's' DFE could be present, since that can open up various cans of worms\n\tbool type_s_dfes_present_ = false;\t\t\t\t\t\t\t\t\t\t\t\t// optimization flag\n\t\n\t// this counter is incremented when a selection coefficient is changed on any mutation object in the simulation.  This is used as a signal to mutation runs that their\n\t// cache of non-neutral mutations is invalid (because their counter is not equal to this counter).  The caches will be re-validated the next time they are used.  Other\n\t// code can also increment this counter in order to trigger a re-validation of all non-neutral mutation caches; it is a general-purpose mechanism.\n\tint32_t nonneutral_change_counter_ = 0;\n\tint32_t last_nonneutral_regime_ = 0;\t\t// see mutation_run.h; 1 = no mutationEffect() callbacks, 2 = only constant-effect neutral callbacks, 3 = arbitrary callbacks\n\t\n\t// this flag is set if the dominance coeff (regular or haploid) changes on any mutation type, as a signal that recaching needs to occur in Subpopulation::UpdateFitness()\n\tbool any_dominance_coeff_changed_ = false;\n\t\n\t// state about what symbols/names/identifiers have been used or are being used\n\t// used_subpop_ids_ has every subpop id ever used, even if no longer in use, with the *last* name used for that subpop\n\t// used_subpop_names_ has every name ever used EXCEPT standard p1, p2... names, even if the name got replaced by a new name later\n\tstd::unordered_map<slim_objectid_t, std::string> used_subpop_ids_;\n\tstd::unordered_set<std::string> used_subpop_names_;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING : Species keeps track of its memory usage profile info and mutation-related profile info\n\t// BCH 11/24/2024: Note that Chromosome now keeps additional profile information that is per-chromosome\n\tSLiMMemoryUsage_Species profile_last_memory_usage_Species;\n\tSLiMMemoryUsage_Species profile_total_memory_usage_Species;\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tstd::vector<int32_t> profile_nonneutral_regime_history_;\t\t\t\t\t\t// a record of the nonneutral regime used in each cycle\n\tint64_t profile_max_mutation_index_;\t\t\t\t\t\t\t\t\t\t\t// the largest mutation index seen over the course of the profile\n#endif\t// SLIM_USE_NONNEUTRAL_CACHES\n#endif\t// (SLIMPROFILING == 1)\n\t\n\tSpecies(const Species&) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tSpecies& operator=(const Species&) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tSpecies(Community &p_community, slim_objectid_t p_species_id, const std::string &p_name);\t\t\t// construct a Species from a community / id / name\n\t~Species(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\t// Chromosome configuration and access\n\tinline __attribute__((always_inline)) const std::vector<Chromosome *> &Chromosomes(void)\t{ return chromosomes_; }\n\tinline __attribute__((always_inline)) const std::vector<Chromosome *> &ChromosomesForHaplosomeIndices(void) { return chromosome_for_haplosome_index_; }\n\tinline __attribute__((always_inline)) const std::vector<uint8_t> &ChromosomeSubindicesForHaplosomeIndices(void) { return chromosome_subindex_for_haplosome_index_; }\n\tinline __attribute__((always_inline)) const std::vector<int> &FirstHaplosomeIndices(void) { return first_haplosome_index_; }\n\tinline __attribute__((always_inline)) const std::vector<int> &LastHaplosomeIndices(void) { return last_haplosome_index_; }\n\tChromosome *ChromosomeFromID(int64_t p_id);\n\tChromosome *ChromosomeFromSymbol(const std::string &p_symbol);\n\tvoid MakeImplicitChromosome(ChromosomeType p_type);\n\tChromosome *CurrentlyInitializingChromosome(void);\t\t\t\t\t\t\t\t// the last chromosome defined (currently initializing)\n\tvoid AddChromosome(Chromosome *p_chromosome);\t\t\t\t\t\t\t\t\t// takes over a retain count from the caller\n\tinline __attribute__((always_inline)) bool ChromosomesUseNullHaplosomes(void) { return chromosomes_use_null_haplosomes_; }\n\tinline __attribute__((always_inline)) int HaplosomeCountPerIndividual(void) { return haplosome_count_per_individual_; }\n\t\n\tChromosome *GetChromosomeFromEidosValue(EidosValue *chromosome_value);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// with a singleton EidosValue\n\tvoid GetChromosomeIndicesFromEidosValue(std::vector<slim_chromosome_index_t> &chromosome_indices, EidosValue *chromosomes_value);\t// with a vector EidosValue\n\t\n\t// Memory usage\n\tvoid TabulateSLiMMemoryUsage_Species(SLiMMemoryUsage_Species *p_usage);\t\t\t// used by outputUsage() and SLiMgui profiling\n\tvoid DeleteAllMutationRuns(void);\t\t\t\t\t\t\t\t\t\t\t\t// for cleanup\n\t\n\t// Running cycles\n\tstd::vector<SLiMEidosBlock*> CallbackBlocksMatching(slim_tick_t p_tick, SLiMEidosBlockType p_event_type, slim_objectid_t p_mutation_type_id, slim_objectid_t p_interaction_type_id, slim_objectid_t p_subpopulation_id, int64_t p_chromosome_id);\n\tvoid RunInitializeCallbacks(void);\n\tvoid EndCurrentChromosome(bool starting_new_chromosome);\n\tbool HasDoneAnyInitialization(void);\n\tvoid PrepareForCycle(void);\n\tvoid MaintainMutationRegistry(void);\n\tvoid RecalculateFitness(void);\n\tvoid MaintainTreeSequence(void);\n\tvoid EmptyGraveyard(void);\n\tvoid FinishMutationRunExperimentTimings(void);\n\t\n\tvoid WF_GenerateOffspring(void);\n\tvoid WF_SwitchToChildGeneration(void);\n\tvoid WF_SwapGenerations(void);\n\t\n\tvoid nonWF_GenerateOffspring(void);\n\tvoid nonWF_MergeOffspring(void);\n\tvoid nonWF_ViabilitySurvival(void);\n\t\n\tvoid AdvanceCycleCounter(void);\n\tvoid SimulationHasFinished(void);\n\tvoid Species_CheckIntegrity(void);\n\t\n\t// Reproduction pattern inference\n\tvoid InferInheritanceForClone(Chromosome *chromosome, Individual *parent, IndividualSex sex, Haplosome **strand1, Haplosome **strand3, const char *caller_name);\n\tvoid InferInheritanceForCross(Chromosome *chromosome, Individual *parent1, Individual *parent2, IndividualSex sex, Haplosome **strand1, Haplosome **strand2, Haplosome **strand3, Haplosome **strand4, const char *caller_name);\n\t\n\t// Shared shuffle buffer to save\n\tinline bool RandomizingCallbackOrder(void) { return shuffle_buf_is_enabled_; }\n\tslim_popsize_t *BorrowShuffleBuffer(slim_popsize_t p_buffer_size);\n\tvoid ReturnShuffleBuffer(void);\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tvoid CollectMutationProfileInfo(void);\n#endif\n#endif\n\t\n\t// Mutation stack policy checking\n\tinline __attribute__((always_inline)) void MutationStackPolicyChanged(void)\t\t\t\t\t\t\t\t\t\t\t\t{ mutation_stack_policy_changed_ = true; }\n\tinline __attribute__((always_inline)) void CheckMutationStackPolicy(void)\t\t\t\t\t\t\t\t\t\t\t\t{ if (mutation_stack_policy_changed_) _CheckMutationStackPolicy(); }\n\tvoid _CheckMutationStackPolicy(void);\n\t\n\t// Nucleotide-based models\n\tinline __attribute__((always_inline)) double MaxNucleotideMutationRate(void)\t\t\t\t\t\t\t\t\t\t\t{ return max_nucleotide_mut_rate_; }\n\tvoid MaxNucleotideMutationRateChanged(void);\n\t\n\t// accessors\n\tinline __attribute__((always_inline)) slim_tick_t Cycle(void) const\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ return cycle_; }\n\tvoid SetCycle(slim_tick_t p_new_cycle);\n\t\n\tinline __attribute__((always_inline)) bool Active(void) { return species_active_; }\n\tinline __attribute__((always_inline)) void SetActive(bool p_active) { species_active_ = p_active; }\n\tinline __attribute__((always_inline)) slim_tick_t TickModulo(void) { return tick_modulo_; }\n\tinline __attribute__((always_inline)) slim_tick_t TickPhase(void) { return tick_phase_; }\n\t\n\tinline __attribute__((always_inline)) bool HasGenetics(void)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ return has_genetics_; }\n\tinline __attribute__((always_inline)) const std::map<slim_objectid_t,MutationType*> &MutationTypes(void) const\t\t\t{ return mutation_types_; }\n\tinline __attribute__((always_inline)) const std::map<slim_objectid_t,GenomicElementType*> &GenomicElementTypes(void)\t{ return genomic_element_types_; }\n\tinline __attribute__((always_inline)) size_t GraveyardSize(void) const\t\t\t\t\t\t\t\t\t\t\t\t\t{ return graveyard_.size(); }\n\t\n\tinline Subpopulation *SubpopulationWithID(slim_objectid_t p_subpop_id) {\n\t\tauto id_iter = population_.subpops_.find(p_subpop_id);\n\t\treturn (id_iter == population_.subpops_.end()) ? nullptr : id_iter->second;\n\t}\n\tSubpopulation *SubpopulationWithName(const std::string &p_subpop_name);\n\tinline MutationType *MutationTypeWithID(slim_objectid_t p_muttype_id) {\n\t\tauto id_iter = mutation_types_.find(p_muttype_id);\n\t\treturn (id_iter == mutation_types_.end()) ? nullptr : id_iter->second;\n\t}\n#ifdef SLIMGUI\n\tinline MutationType *MutationTypeWithIndex(int p_muttype_index) {\n\t\tfor (const std::pair<const slim_objectid_t,MutationType*> &muttype_pair : mutation_types_)\n\t\t\tif (muttype_pair.second->mutation_type_index_ == p_muttype_index)\n\t\t\t\treturn muttype_pair.second;\n\t\treturn nullptr;\n\t}\n#endif\n\tinline GenomicElementType *GenomicElementTypeWithID(slim_objectid_t p_getype_id) {\n\t\tauto id_iter = genomic_element_types_.find(p_getype_id);\n\t\treturn (id_iter == genomic_element_types_.end()) ? nullptr : id_iter->second;\n\t}\n\t\n\tinline __attribute__((always_inline)) bool SexEnabled(void) const\t\t\t\t\t\t\t\t\t\t\t\t\t\t{ return sex_enabled_; }\n\tinline __attribute__((always_inline)) bool PedigreesEnabled(void) const\t\t\t\t\t\t\t\t\t\t\t\t\t{ return pedigrees_enabled_; }\n\tinline __attribute__((always_inline)) bool PedigreesEnabledByUser(void) const\t\t\t\t\t\t\t\t\t\t\t{ return pedigrees_enabled_by_user_; }\n\tinline __attribute__((always_inline)) bool PreventIncidentalSelfing(void) const\t\t\t\t\t\t\t\t\t\t\t{ return prevent_incidental_selfing_; }\n\tinline __attribute__((always_inline)) int SpatialDimensionality(void) const\t\t\t\t\t\t\t\t\t\t\t\t{ return spatial_dimensionality_; }\n\tinline __attribute__((always_inline)) void SpatialPeriodicity(bool *p_x, bool *p_y, bool *p_z) const\n\t{\n\t\tif (p_x) *p_x = periodic_x_;\n\t\tif (p_y) *p_y = periodic_y_;\n\t\tif (p_z) *p_z = periodic_z_;\n\t}\n\t\n\tinline __attribute__((always_inline)) bool UserWantsMutrunExperiments(void) const\t\t\t\t\t\t\t\t\t\t{ return do_mutrun_experiments_; }\n\tinline __attribute__((always_inline)) void DoingMutrunExperimentsForChromosome(void)\t\t\t\t\t\t\t\t\t{ doing_any_mutrun_experiments_ = true; }\n\tinline __attribute__((always_inline)) bool DoingAnyMutationRunExperiments(void) const\t\t\t\t\t\t\t\t\t{ return doing_any_mutrun_experiments_; }\n\t\n\tinline __attribute__((always_inline)) bool IsNucleotideBased(void) const\t\t\t\t\t\t\t\t\t\t\t\t{ return nucleotide_based_; }\n\t\n\t\n\t// TREE SEQUENCE RECORDING\n#pragma mark -\n#pragma mark treeseq recording methods\n#pragma mark -\n\tinline __attribute__((always_inline)) bool RecordingTreeSequence(void) const\t\t\t\t\t\t\t\t\t\t\t{ return recording_tree_; }\n\tinline __attribute__((always_inline)) bool RecordingTreeSequenceMutations(void) const\t\t\t\t\t\t\t\t\t{ return recording_mutations_; }\n\tvoid AboutToSplitSubpop(void);\t// see Population::AddSubpopulationSplit()\n\t\n\tvoid CopySharedTablesIn(tsk_table_collection_t &p_tables);\t\t\t\t// copies the shared tables for the species into p_tables\n\tvoid DisconnectCopiedSharedTables(tsk_table_collection_t &p_tables);\t// zeroes out the shared table copies in p_tables\n\t\n\tstatic void handle_error(const std::string &msg, int error) __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\tstatic void MetadataForMutation(Mutation *p_mutation, MutationMetadataRec *p_metadata);\n\tstatic void MetadataForSubstitution(Substitution *p_substitution, MutationMetadataRec *p_metadata);\n\tstatic void MetadataForIndividual(Individual *p_individual, IndividualMetadataRec *p_metadata);\n\tstatic void DerivedStatesFromAscii(tsk_table_collection_t *p_tables);\n\tstatic void DerivedStatesToAscii(tsk_table_collection_t *p_tables);\n\t\n\tbool _SubpopulationIDInUse(slim_objectid_t p_subpop_id);\n\tvoid RecordTablePosition(void);\n\tvoid AllocateTreeSequenceTables(void);\n\tvoid SetCurrentNewIndividual(Individual *p_individual);\n\tvoid RecordNewHaplosome(slim_position_t *p_breakpoints, int p_breakpoints_count, Haplosome *p_new_haplosome, const Haplosome *p_initial_parental_haplosome, const Haplosome *p_second_parental_haplosome);\n\tvoid RecordNewHaplosome_NULL(Haplosome *p_new_haplosome);\n\tvoid RecordNewDerivedState(const Haplosome *p_haplosome, slim_position_t p_position, const std::vector<Mutation *> &p_derived_mutations);\n\tvoid RetractNewIndividual(void);\n\tvoid AddIndividualsToTable(Individual * const *p_individual, size_t p_num_individuals, tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash, tsk_flags_t p_flags);\n\tvoid AddLiveIndividualsToIndividualsTable(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash);\n\tvoid FixAliveIndividuals(tsk_table_collection_t *p_tables);\n\tvoid WritePopulationTable(tsk_table_collection_t *p_tables);\n\tvoid WriteProvenanceTable(tsk_table_collection_t *p_tables, bool p_use_newlines, bool p_include_model, slim_chromosome_index_t p_chromosome_index);\n\tvoid WriteTreeSequenceMetadata(tsk_table_collection_t *p_tables, EidosDictionaryUnretained *p_metadata_dict, slim_chromosome_index_t p_chromosome_index);\n\tvoid _MungeIsNullNodeMetadataToIndex0(TreeSeqInfo &p_treeseq, int original_index);\n\tvoid ReadTreeSequenceMetadata(TreeSeqInfo &p_treeseq, slim_tick_t *p_tick, slim_tick_t *p_cycle, SLiMModelType *p_model_type, int *p_file_version);\n\tvoid _CreateDirectoryForMultichromArchive(std::string resolved_user_path, bool p_overwrite_directory);\n\tvoid WriteTreeSequence(std::string &p_recording_tree_path, bool p_simplify, bool p_include_model, EidosDictionaryUnretained *p_metadata_dict, bool p_overwrite_directory);\n    void ReorderIndividualTable(tsk_table_collection_t *p_tables, std::vector<int> p_individual_map, bool p_keep_unmapped);\n\tvoid AddParentsColumnForOutput(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash);\n\tvoid BuildTabledIndividualsHash(tsk_table_collection_t *p_tables, INDIVIDUALS_HASH *p_individuals_hash);\n\tvoid _SimplifyTreeSequence(TreeSeqInfo &tsinfo, const std::vector<tsk_id_t> &samples);\n\tvoid SimplifyAllTreeSequences(void);\n\tvoid CheckCoalescenceAfterSimplification(TreeSeqInfo &tsinfo);\n\tvoid CheckAutoSimplification(void);\n\tvoid FreeTreeSequence();\n\tvoid RecordAllDerivedStatesFromSLiM(void);\n\tvoid CheckTreeSeqIntegrity(void);\t\t// checks the tree sequence tables themselves\n\tvoid CrosscheckTreeSeqIntegrity(void);\t// checks the tree sequence tables against SLiM's data structures\n\t\n\tvoid __CheckPopulationMetadata(TreeSeqInfo &p_treeseq);\n\tvoid __RemapSubpopulationIDs(SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq, int p_file_version);\n\tvoid __PrepareSubpopulationsFromTables(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, TreeSeqInfo &p_treeseq);\n\tvoid __TabulateSubpopulationsFromTreeSequence(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, tsk_treeseq_t *p_ts, TreeSeqInfo &p_treeseq, SLiMModelType p_file_model_type);\n\tvoid __CreateSubpopulationsFromTabulation(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, EidosInterpreter *p_interpreter, std::unordered_map<tsk_id_t, Haplosome *> &p_nodeToHaplosomeMap, TreeSeqInfo &p_treeseq);\n\tvoid __CreateSubpopulationsFromTabulation_SECONDARY(std::unordered_map<slim_objectid_t, ts_subpop_info> &p_subpopInfoMap, EidosInterpreter *p_interpreter, std::unordered_map<tsk_id_t, Haplosome *> &p_nodeToHaplosomeMap, TreeSeqInfo &p_treeseq);\n\tvoid __ConfigureSubpopulationsFromTables(EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq);\n\tvoid __ConfigureSubpopulationsFromTables_SECONDARY(EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq);\n\tvoid __TabulateMutationsFromTables(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutMap, TreeSeqInfo &p_treeseq, int p_file_version);\n\tvoid __TallyMutationReferencesWithTreeSequence(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutMap, std::unordered_map<tsk_id_t, Haplosome *> p_nodeToHaplosomeMap, tsk_treeseq_t *p_ts);\n\tvoid __CreateMutationsFromTabulation(std::unordered_map<slim_mutationid_t, ts_mut_info> &p_mutInfoMap, std::unordered_map<slim_mutationid_t, MutationIndex> &p_mutIndexMap, TreeSeqInfo &p_treeseq);\n\tvoid __AddMutationsFromTreeSequenceToHaplosomes(std::unordered_map<slim_mutationid_t, MutationIndex> &p_mutIndexMap, std::unordered_map<tsk_id_t, Haplosome *> p_nodeToHaplosomeMap, tsk_treeseq_t *p_ts, TreeSeqInfo &p_treeseq);\n\tvoid __CheckNodePedigreeIDs(EidosInterpreter *p_interpreter, TreeSeqInfo &p_treeseq);\n\tvoid _ReadAncestralSequence(const char *p_file, Chromosome &p_chromosome);\n\tvoid _InstantiateSLiMObjectsFromTables(EidosInterpreter *p_interpreter, slim_tick_t p_metadata_tick, slim_tick_t p_metadata_cycle, SLiMModelType p_file_model_type, int p_file_version, SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq);\t// given tree-seq tables, makes individuals, haplosomes, and mutations\n\tvoid _InstantiateSLiMObjectsFromTables_SECONDARY(EidosInterpreter *p_interpreter, slim_tick_t p_metadata_tick, slim_tick_t p_metadata_cycle, SLiMModelType p_file_model_type, int p_file_version, SUBPOP_REMAP_HASH &p_subpop_map, TreeSeqInfo &p_treeseq);\t// given tree-seq tables, makes individuals, haplosomes, and mutations\n\tvoid _PostInstantiationCleanup(EidosInterpreter *p_interpreter);\n\tslim_tick_t _InitializePopulationFromTskitBinaryFile(const char *p_file, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_remap, Chromosome &p_chromosome);\t// initialize the population from an tskit binary file\n\tslim_tick_t _InitializePopulationFromTskitDirectory(std::string p_directory, EidosInterpreter *p_interpreter, SUBPOP_REMAP_HASH &p_subpop_remap);\t// initialize the population from a multi-chromosome directory\n\t\n\tsize_t MemoryUsageForTreeSeqInfo(TreeSeqInfo &p_tsinfo, bool p_count_shared_tables);\n\tvoid TSXC_Enable(void);\n\tvoid TSF_Enable(void);\n\t\n\t//\n\t// Eidos support\n\t//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; };\n\t\n\tEidosValue_SP ExecuteContextFunction_initializeAncestralNucleotides(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeGenomicElement(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeGenomicElementType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeMutationType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeRecombinationRate(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeChromosome(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeGeneConversion(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeMutationRate(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeHotspotMap(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeSex(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeSLiMOptions(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeSpecies(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteContextFunction_initializeTreeSeq(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\tEidosValue_SP ExecuteMethod_addPatternForClone(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addPatternForCross(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addPatternForNull(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addPatternForRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSubpop(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSubpopSplit(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_chromosomesOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_chromosomesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_chromosomesWithSymbols(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_individualsWithPedigreeIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_killIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mutationFreqsCounts(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_mutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_countOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_outputFixedMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_outputFull(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_outputMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_readFromPopulationFile(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_recalculateFitness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerFitnessEffectCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerMateModifyRecSurvCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerMutationCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerMutationEffectCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_registerReproductionCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_simulationFinished(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_skipTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subsetMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_substitutionsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_treeSeqCoalesced(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_treeSeqSimplify(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_treeSeqRememberIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_treeSeqOutput(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod__debug(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass Species_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tSpecies_Class(const Species_Class &p_original) = delete;\t// no copy-construct\n\tSpecies_Class& operator=(const Species_Class&) = delete;\t// no copying\n\tinline Species_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__species__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/species_eidos.cpp",
    "content": "//\n//  species_eidos.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"species.h\"\n\n#include \"community.h\"\n#include \"haplosome.h\"\n#include \"individual.h\"\n#include \"subpopulation.h\"\n#include \"polymorphism.h\"\n#include \"interaction_type.h\"\n#include \"log_file.h\"\n\n#include <iostream>\n#include <iomanip>\n#include <fstream>\n#include <string>\n#include <utility>\n#include <algorithm>\n#include <vector>\n#include <cmath>\n#include <ctime>\n#include <unordered_map>\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\n// Note that the functions below are dispatched out by Community::ContextDefinedFunctionDispatch()\n\n//\t*********************\t(integer$)initializeAncestralNucleotides(is sequence)\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeAncestralNucleotides(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *sequence_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_ancseq_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): initializeAncestralNucleotides() may be called only once.\" << EidosTerminate();\n\tif (!nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): initializeAncestralNucleotides() may be only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tEidosValueType sequence_value_type = sequence_value->Type();\n\tint sequence_value_count = sequence_value->Count();\n\t\n\tif (sequence_value_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): initializeAncestralNucleotides() requires a sequence of length >= 1.\" << EidosTerminate();\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\tif (sequence_value_type == EidosValueType::kValueInt)\n\t{\n\t\t// A vector of integers has been provided, where ACGT == 0123\n\t\tconst int64_t *int_data = sequence_value->IntData();\n\t\t\n\t\tchromosome->ancestral_seq_buffer_ = new NucleotideArray(sequence_value_count, int_data);\n\t}\n\telse if (sequence_value_type == EidosValueType::kValueString)\n\t{\n\t\tif (sequence_value_count != 1)\n\t\t{\n\t\t\t// A vector of characters has been provided, which must all be \"A\" / \"C\" / \"G\" / \"T\"\n\t\t\tconst std::string *string_data = sequence_value->StringData();\n\t\t\t\n\t\t\tchromosome->ancestral_seq_buffer_ = new NucleotideArray(sequence_value_count, string_data);\n\t\t}\n\t\telse\t// sequence_value_count == 1\n\t\t{\n\t\t\tconst std::string &sequence_string = sequence_value->StringData()[0];\n\t\t\tbool contains_only_nuc = true;\n\t\t\t\n\t\t\t// OK, we do a weird thing here.  We want to try to construct a NucleotideArray\n\t\t\t// from sequence_string, which throws with EIDOS_TERMINATION if it fails, but\n\t\t\t// we want to actually catch that exception even if we're running at the\n\t\t\t// command line, where EIDOS_TERMINATION normally calls exit().  So we actually\n\t\t\t// play around with the error-handling state to make it do what we want it to do.\n\t\t\t// This is very naughty and should be redesigned, but right now I'm not seeing\n\t\t\t// the right redesign strategy, so... hacking it for now.  Parallel code is at\n\t\t\t// Chromosome::ExecuteMethod_setAncestralNucleotides()\n\t\t\tbool save_gEidosTerminateThrows = gEidosTerminateThrows;\n\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tchromosome->ancestral_seq_buffer_ = new NucleotideArray(sequence_string.length(), sequence_string.c_str());\n\t\t\t} catch (...) {\n\t\t\t\tcontains_only_nuc = false;\n\t\t\t\t\n\t\t\t\t// clean up the error state since we don't want this throw to be reported\n\t\t\t\tgEidosTermination.clear();\n\t\t\t\tgEidosTermination.str(\"\");\n\t\t\t}\n\t\t\t\n\t\t\tgEidosTerminateThrows = save_gEidosTerminateThrows;\n\t\t\t\n\t\t\tif (!contains_only_nuc)\n\t\t\t{\n\t\t\t\t// A singleton string has been provided that contains characters other than ACGT; we will interpret it as a filesystem path for a FASTA file\n\t\t\t\tstd::string file_path = Eidos_ResolvedPath(sequence_string);\n\t\t\t\tstd::ifstream file_stream(file_path.c_str());\n\t\t\t\t\n\t\t\t\tif (!file_stream.is_open())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): the file at path \" << sequence_string << \" could not be opened or does not exist.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tbool started_sequence = false;\n\t\t\t\tstd::string line, fasta_sequence;\n\t\t\t\t\n\t\t\t\twhile (getline(file_stream, line))\n\t\t\t\t{\n\t\t\t\t\t// skippable lines are blank or start with a '>' or ';'\n\t\t\t\t\t// we skip over them if they're at the start of the file; once we start a sequence, they terminate the sequence\n\t\t\t\t\tbool skippable = ((line.length() == 0) || (line[0] == '>') || (line[0] == ';'));\n\t\t\t\t\t\n\t\t\t\t\tif (!started_sequence && skippable)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (skippable)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// otherwise, append the nucleotides from this line, removing a \\r if one is present at the end of the line\n\t\t\t\t\tif (line.back() == '\\r')\n\t\t\t\t\t\tline.pop_back();\n\t\t\t\t\t\n\t\t\t\t\tfasta_sequence.append(line);\n\t\t\t\t\tstarted_sequence = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (file_stream.bad())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): a filesystem error occurred while reading the file at path \" << sequence_string << \".\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (fasta_sequence.length() == 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): no FASTA sequence found in \" << sequence_string << \".\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tchromosome->ancestral_seq_buffer_ = new NucleotideArray(fasta_sequence.length(), fasta_sequence.c_str());\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (chromosome->extent_immutable_)\n\t{\n\t\tif (chromosome->ancestral_seq_buffer_->size() != (std::size_t)(chromosome->last_position_ + 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeAncestralNucleotides): the length of the provided ancestral sequence does not match the length of the chromosome.\" << EidosTerminate();\n\t}\n\t\n\t// debugging\n\t//std::cout << \"ancestral sequence set: \" << *chromosome_->ancestral_seq_buffer_ << std::endl;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeAncestralNucleotides(\\\"\";\n\t\t\n\t\t// output up to 20 nucleotides, followed by an ellipsis if necessary\n\t\tfor (std::size_t i = 0; (i < 20) && (i < chromosome->ancestral_seq_buffer_->size()); ++i)\n\t\t\toutput_stream << \"ACGT\"[chromosome->ancestral_seq_buffer_->NucleotideAtIndex(i)];\n\t\t\n\t\tif (chromosome->ancestral_seq_buffer_->size() > 20)\n\t\t\toutput_stream << gEidosStr_ELLIPSIS;\n\t\t\n\t\toutput_stream << \"\\\");\" << std::endl;\n\t}\n\t\n\tnum_ancseq_inits_++;\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(chromosome->ancestral_seq_buffer_->size()));\n}\n\n//\t*********************\t(object<Chromosome>$)initializeChromosome(integer$ id, [Ni$ length = NULL], [string$ type = \"A\"], [Ns$ symbol = NULL], [Ns$ name = NULL], [integer$ mutationRuns = 0])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeChromosome(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\t// We are starting the definition of a new explicitly defined chromosome.  We zero out counts for all\n\t// chromosome-specific initialization functions; this is a blank slate.  An implicit chromosome is\n\t// not allowed to have already been defined.\n\tif (has_implicit_chromosome_)\n\t{\n\t\tif (num_mutrate_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeMutationRate() was called.  To fix this error, call initializeChromosome() first and then call initializeMutationRate(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\tif (num_recrate_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeRecombinationRate() was called.  To fix this error, call initializeChromosome() first and then call initializeRecombinationRate(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\tif (num_genomic_element_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeGenomicElement() was called.  To fix this error, call initializeChromosome() first and then call initializeGenomicElement(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\tif (num_gene_conv_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeGeneConversion() was called.  To fix this error, call initializeChromosome() first and then call initializeGeneConversion(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\tif (num_ancseq_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeAncestralNucleotides() was called.  To fix this error, call initializeChromosome() first and then call initializeAncestralNucleotides(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\tif (num_hotmap_inits_ > 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot be called to explicitly create a chromosome, because the chromosome has already been implicitly defined.  This occurred because initializeHotspotMap() was called.  To fix this error, call initializeChromosome() first and then call initializeHotspotMap(), or don't call initializeChromosome() at all if you do not need an explicitly defined chromosome.\" << EidosTerminate();\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): (internal error) initializeChromosome() was called with an implicitly defined chromosome.  However, the cause of this cannot be diagnosed, indicating an internal logic error.\" << EidosTerminate();\n\t}\n\t\n\tif (chromosomes_.size() >= SLIM_MAX_CHROMOSOMES)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() cannot make a new chromosome because the maximum number of chromosomes allowed per species (\" << SLIM_MAX_CHROMOSOMES << \") has already been reached.  If you want to model a large number of unlinked loci, using a recombination rate of 0.5, rather than multiple chromosomes, is recommended.\" << EidosTerminate();\n\t\n\tif (num_chromosome_inits_ > 0)\n\t{\n\t\t// A previous explicitly defined chromosome terminates its definition here,\n\t\t// so we do some checking of that previous chromosome's integrity.\n\t\tEndCurrentChromosome(/* starting_new_chromosome */ true);\n\t}\n\t\n\tnum_mutrate_inits_ = 0;\n\tnum_recrate_inits_ = 0;\n\tnum_genomic_element_inits_ = 0;\n\tnum_gene_conv_inits_ = 0;\n\tnum_ancseq_inits_ = 0;\n\tnum_hotmap_inits_ = 0;\n\t\n\t// Get parameters and bounds-check\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *length_value = p_arguments[1].get();\n\tEidosValue *type_value = p_arguments[2].get();\n\tEidosValue *symbol_value = p_arguments[3].get();\n\tEidosValue *name_value = p_arguments[4].get();\n\tEidosValue *mutationRuns_value = p_arguments[5].get();\n\t\n\tint64_t id = id_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (id < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires id to be non-negative.\" << EidosTerminate();\n\t\n\tif (ChromosomeFromID(id))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires id to be unique within the species; two chromosomes in the same species may not have the same id.\" << EidosTerminate();\n\t\n\t// -1 represents a length of NULL, indicating the length is mutable and will be assessed later\n\tslim_position_t length = -1;\t\n\t\n\tif (length_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tlength = SLiMCastToPositionTypeOrRaise(length_value->IntAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tif (length - 1 > SLIM_MAX_BASE_POSITION)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires the last base position (length-1) to be <= 1e15.\" << EidosTerminate();\n\t}\n\t\n\tstd::string type_string = type_value->StringAtIndex_NOCAST(0, nullptr);\n\tChromosomeType chromosome_type = ChromosomeTypeForString(type_string);\n\t\n\tif (!sex_enabled_ &&\n\t\t((chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t (chromosome_type == ChromosomeType::kY_YSexChromosome) ||\n\t\t (chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t (chromosome_type == ChromosomeType::kW_WSexChromosome) ||\n\t\t //(chromosome_type == ChromosomeType::kHF_HaploidFemaleInherited) ||\t// now allowing; see issue #534\n\t\t (chromosome_type == ChromosomeType::kFL_HaploidFemaleLine) ||\n\t\t //(chromosome_type == ChromosomeType::kHM_HaploidMaleInherited) ||\t\t// now allowing; see issue #534\n\t\t (chromosome_type == ChromosomeType::kML_HaploidMaleLine) ||\n\t\t (chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): chromosome type '\" << chromosome_type << \"' is only allowed in sexual models; call initializeSex() to enable sex first.\" << EidosTerminate();\n\t\n\tstd::string symbol;\n\t\n\tif (symbol_value->Type() == EidosValueType::kValueString)\n\t\tsymbol = symbol_value->StringAtIndex_NOCAST(0, nullptr);\n\telse\n\t\tsymbol = std::to_string(id);\n\t\n\tif ((symbol.length() == 0) || (symbol.length() > 5))\n\t{\n\t\tif (symbol_value->Type() == EidosValueType::kValueString)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires symbol to be a string with a length of 1-3 characters.\" << EidosTerminate();\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires symbol to be a string with a length of 1-3 characters; since the id given to the chromosome (\" << id << \") is more than three digits, a symbol must be supplied explicitly to satisfy this requirement.\" << EidosTerminate();\n\t}\n\t\n\t// these checks for symbol try to ensure that it can be used in a filename, as in tree-seq recording, without causing problems\n\tfor (char c : symbol) {\n\t\tif (!std::isprint(static_cast<unsigned char>(c))) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires symbol to consist only of printable ASCII characters.\" << EidosTerminate();\n\t\t}\n\t}\n\tif (symbol.find_first_of(\" \\\\/:$*?<>|._-\\\"\") != std::string::npos)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() does not allow symbol to contain the characters [space], \\\\, /, :, $, *, ?, <, >, |, ., _, -, or \\\".\" << EidosTerminate();\n\t\n\tif (ChromosomeFromSymbol(symbol))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires symbol to be unique within the species; two chromosomes in the same species may not have the same symbol.\" << EidosTerminate();\n\t\n\tstd::string name;\n\t\n\tif (name_value->Type() == EidosValueType::kValueString)\n\t\tname = name_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tint64_t mutrun_count = mutationRuns_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (mutrun_count != 0)\n\t{\n\t\tif ((mutrun_count < 1) || (mutrun_count > 10000))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeChromosome): initializeChromosome() requires mutationRuns to be between 1 and 10000, inclusive.\" << EidosTerminate();\n\t}\n\t\n\t// Set up the new chromosome object; it gets a retain count on it from EidosDictionaryRetained::EidosDictionaryRetained()\n\tChromosome *chromosome = new Chromosome(*this, chromosome_type, id, symbol, /* p_index */ (uint8_t)num_chromosome_inits_, (int)mutrun_count);\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(chromosome, gSLiM_Chromosome_Class));\n\t\n\tchromosome->SetName(name);\n\t\n\tif (length == -1)\n\t{\n\t\t// the length is NULL, so it is mutable until Chromosome::InitializeDraws() is called\n\t\tchromosome->last_position_ = 0;\n\t\tchromosome->extent_immutable_ = false;\n\t}\n\telse\n\t{\n\t\t// the length has been specified explicitly, so it is immutable\n\t\tchromosome->last_position_ = length - 1;\n\t\tchromosome->extent_immutable_ = true;\n\t}\n\t\n\t// Add it to our registry; AddChromosome() takes its retain count\n\tAddChromosome(chromosome);\n\tnum_chromosome_inits_++;\n\thas_currently_initializing_chromosome_ = true;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\toutput_stream << \"initializeChromosome(\" << id << \", \" << length << \", '\" << type_string << \"'\";\n\t\tif (symbol_value->Type() == EidosValueType::kValueString)\n\t\t\toutput_stream << \", symbol='\" << symbol << \"'\";\n\t\tif (name.length())\n\t\t\toutput_stream << \", name='\" << name << \"'\";\n\t\tif (mutrun_count != 0)\n\t\t\toutput_stream << \", mutationRuns=\" << mutrun_count;\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t(object<GenomicElement>)initializeGenomicElement(io<GenomicElementType> genomicElementType, [Ni start = NULL], [Ni end = NULL])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeGenomicElement(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *genomicElementType_value = p_arguments[0].get();\n\tEidosValue *start_value = p_arguments[1].get();\n\tEidosValue *end_value = p_arguments[2].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// BEWARE: Before we do anything else, we need to handle the start == end == NULL case,\n\t// which modifies start_value and end_value.  Be careful not to break this ugly hack!\n\tbool start_is_NULL = (start_value->Type() == EidosValueType::kValueNULL);\n\tbool end_is_NULL = (end_value->Type() == EidosValueType::kValueNULL);\n\tEidosValue_Int_SP start_value_mocked, end_value_mocked;\n\t\n\tif (start_is_NULL && end_is_NULL)\n\t{\n\t\tif ((num_chromosome_inits_ == 0) || has_implicit_chromosome_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() only allows NULL for start and end with a chromosome that is explicitly defined with initializeChromosome(), so that the length of the chromosome is known.\" << EidosTerminate();\n\t\t\n\t\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\t\n\t\tif (!chromosome->extent_immutable_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() only allows NULL for start and end with a chromosome that has an explicitly defined length.\" << EidosTerminate();\n\t\t\n\t\tslim_position_t last_position = chromosome->last_position_;\n\t\t\n\t\t// Here is the ugly hack!  We want start_value and end_value to have specific values based upon the\n\t\t// focal chromosome.  The simplest way to achieve that is to substitute new EidosValues in for them.\n\t\t// To do that, we have two EidosValue_Int_SPs defined above, for RAII.  We'll make the mocked values,\n\t\t// and substitute them in for use by the remaining code.  They will be freed on exit from this method.\n\t\tstart_value_mocked = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(0));\n\t\tend_value_mocked = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(last_position));\n\t\tstart_value = start_value_mocked.get();\n\t\tend_value = end_value_mocked.get();\n\t}\n\telse if (start_is_NULL || end_is_NULL)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() only allows a start or end value of NULL if _both_ start and end are NULL; they cannot be NULL separately.\" << EidosTerminate();\n\t\n\t// ------ end of ugly hack; from here on, start_value and end_value are guaranteed to be type integer -------\n\t\n\t\n\t// Now check counts and such\n\tif (start_value->Count() != end_value->Count())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() requires start and end to be the same length.\" << EidosTerminate();\n\tif ((genomicElementType_value->Count() != 1) && (genomicElementType_value->Count() != start_value->Count()))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() requires genomicElementType to be a singleton, or to match the length of start and end.\" << EidosTerminate();\n\t\n\tint element_count = start_value->Count();\n\tint type_count = genomicElementType_value->Count();\n\t\n\tif (element_count == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\tGenomicElementType *genomic_element_type_ptr_0 = ((type_count == 1) ? SLiM_ExtractGenomicElementTypeFromEidosValue_io(genomicElementType_value, 0, &community_, this, \"initializeGenomicElement()\") : nullptr);\t\t\t\t\t// SPECIES CONSISTENCY CHECK\n\tGenomicElementType *genomic_element_type_ptr = nullptr;\n\tslim_position_t start_position = 0, end_position = 0;\n\tEidosValue_Object *result_vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElement_Class))->resize_no_initialize(element_count);\n\t\n\tfor (int element_index = 0; element_index < element_count; ++element_index)\n\t{\n\t\tgenomic_element_type_ptr = ((type_count == 1) ? genomic_element_type_ptr_0 : SLiM_ExtractGenomicElementTypeFromEidosValue_io(genomicElementType_value, element_index, &community_, this, \"initializeGenomicElement()\"));\t// SPECIES CONSISTENCY CHECK\n\t\tstart_position = SLiMCastToPositionTypeOrRaise(start_value->IntAtIndex_NOCAST(element_index, nullptr));\n\t\tend_position = SLiMCastToPositionTypeOrRaise(end_value->IntAtIndex_NOCAST(element_index, nullptr));\n\t\t\n\t\tif (end_position < start_position)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() end position \" << end_position << \" is less than start position \" << start_position << \".\" << EidosTerminate();\n\t\t\n\t\tif (chromosome->extent_immutable_)\n\t\t{\n\t\t\tif ((start_position < 0) || (end_position > chromosome->last_position_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() genomic element extent lies outside of the extent of the chromosome.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// Check that the new element will not overlap any existing element; if end_position > last_genomic_element_position we are safe.\n\t\t// Otherwise, we have to check all previously defined elements.  The use of last_genomic_element_position is an optimization to\n\t\t// avoid an O(N) scan with each added element; as long as elements are added in sorted order there is no need to scan.\n\t\tif (start_position <= last_genomic_element_position_)\n\t\t{\n\t\t\tfor (GenomicElement *element : chromosome->GenomicElements())\n\t\t\t{\n\t\t\t\tif ((element->start_position_ <= end_position) && (element->end_position_ >= start_position))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElement): initializeGenomicElement() genomic element from start position \" << start_position << \" to end position \" << end_position << \" overlaps existing genomic element.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (end_position > last_genomic_element_position_)\n\t\t\tlast_genomic_element_position_ = end_position;\n\t\t\n\t\t// Create and add the new element\n\t\tGenomicElement *new_genomic_element = new GenomicElement(genomic_element_type_ptr, start_position, end_position);\n\t\t\n\t\tchromosome->GenomicElements().emplace_back(new_genomic_element);\n\t\tresult_vec->set_object_element_no_check_NORR(new_genomic_element, element_index);\n\t\t\n\t\tcommunity_.chromosome_changed_ = true;\n\t\tnum_genomic_element_inits_++;\n\t}\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tif (start_is_NULL && end_is_NULL)\n\t\t{\n\t\t\toutput_stream << \"initializeGenomicElement(g\" << genomic_element_type_ptr->genomic_element_type_id_ << \");\" << std::endl;\n\t\t}\n\t\telse if (ABBREVIATE_DEBUG_INPUT && (num_genomic_element_inits_ > 20) && (num_genomic_element_inits_ != element_count))\n\t\t{\n\t\t\tif ((num_genomic_element_inits_ - element_count) <= 20)\n\t\t\t\toutput_stream << \"(...initializeGenomicElement() calls omitted...)\" << std::endl;\n\t\t}\n\t\telse if (element_count == 1)\n\t\t{\n\t\t\toutput_stream << \"initializeGenomicElement(g\" << genomic_element_type_ptr->genomic_element_type_id_ << \", \" << start_position << \", \" << end_position << \");\" << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toutput_stream << \"initializeGenomicElement(...);\" << std::endl;\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result_vec);\n}\n\n//\t*********************\t(object<GenomicElementType>$)initializeGenomicElementType(is$ id, io<MutationType> mutationTypes, numeric proportions, [Nf mutationMatrix = NULL])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeGenomicElementType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *mutationTypes_value = p_arguments[1].get();\n\tEidosValue *proportions_value = p_arguments[2].get();\n\tEidosValue *mutationMatrix_value = p_arguments[3].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tslim_objectid_t map_identifier = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 'g');\n\t\n\tif (community_.GenomicElementTypeWithID(map_identifier))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() genomic element type g\" << map_identifier << \" already defined.\" << EidosTerminate();\n\t\n\tint mut_type_id_count = mutationTypes_value->Count();\n\tint proportion_count = proportions_value->Count();\n\t\n\tif (mut_type_id_count != proportion_count)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() requires the sizes of mutationTypes and proportions to be equal.\" << EidosTerminate();\n\t\n\tstd::vector<MutationType*> mutation_types;\n\tstd::vector<double> mutation_fractions;\n\t\n\tfor (int mut_type_index = 0; mut_type_index < mut_type_id_count; ++mut_type_index)\n\t{\n\t\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutationTypes_value, mut_type_index, &community_, this, \"initializeGenomicElementType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\tdouble proportion = proportions_value->NumericAtIndex_NOCAST(mut_type_index, nullptr);\n\t\t\n\t\tif ((proportion < 0) || !std::isfinite(proportion))\t\t// == 0 is allowed but must be fixed before the simulation executes; see InitializeDraws()\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() proportions must be greater than or equal to zero (\" << EidosStringForFloat(proportion) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\tif (std::find(mutation_types.begin(), mutation_types.end(), mutation_type_ptr) != mutation_types.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() mutation type m\" << mutation_type_ptr->mutation_type_id_ << \" used more than once.\" << EidosTerminate();\n\t\t\n\t\tif (nucleotide_based_ && !mutation_type_ptr->nucleotide_based_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): in nucleotide-based models, initializeGenomicElementType() requires all mutation types for the genomic element type to be nucleotide-based.  Non-nucleotide-based mutation types may be used in nucleotide-based models, but they cannot be autogenerated by SLiM, and therefore cannot be referenced by a genomic element type.\" << EidosTerminate();\n\t\t\n\t\tmutation_types.emplace_back(mutation_type_ptr);\n\t\tmutation_fractions.emplace_back(proportion);\n\t\t\n\t\t// check whether we are using a mutation type that is non-neutral; check and set pure_neutral_\n\t\tif ((mutation_type_ptr->dfe_type_ != DFEType::kFixed) || (mutation_type_ptr->dfe_parameters_[0] != 0.0))\n\t\t{\n\t\t\tpure_neutral_ = false;\n\t\t\t// the mutation type's all_pure_neutral_DFE_ flag is presumably already set\n\t\t}\n\t}\n\t\n\tEidosValueType mm_type = mutationMatrix_value->Type();\n\t\n\tif (!nucleotide_based_ && (mm_type != EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() requires mutationMatrix to be NULL in non-nucleotide-based models.\" << EidosTerminate();\n\tif (nucleotide_based_ && (mm_type == EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() requires mutationMatrix to be non-NULL in nucleotide-based models.\" << EidosTerminate();\n\t\n\tGenomicElementType *new_genomic_element_type = new GenomicElementType(*this, map_identifier, mutation_types, mutation_fractions);\n\tif (nucleotide_based_)\n\t\tnew_genomic_element_type->SetNucleotideMutationMatrix(EidosValue_Float_SP((EidosValue_Float *)(mutationMatrix_value)));\n\t\n\tgenomic_element_types_.emplace(map_identifier, new_genomic_element_type);\n\tcommunity_.genomic_element_types_changed_ = true;\n\t\n\t// define a new Eidos variable to refer to the new genomic element type\n\tEidosSymbolTableEntry &symbol_entry = new_genomic_element_type->SymbolTableEntry();\n\t\n\tif (p_interpreter.SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGenomicElementType): initializeGenomicElementType() symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\n\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tif (ABBREVIATE_DEBUG_INPUT && (num_ge_type_inits_ > 99))\n\t\t{\n\t\t\tif (num_ge_type_inits_ == 100)\n\t\t\t\toutput_stream << \"(...more initializeGenomicElementType() calls omitted...)\" << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toutput_stream << \"initializeGenomicElementType(\" << map_identifier;\n\t\t\t\n\t\t\toutput_stream << ((mut_type_id_count > 1) ? \", c(\" : \", \");\n\t\t\tfor (int mut_type_index = 0; mut_type_index < mut_type_id_count; ++mut_type_index)\n\t\t\t\toutput_stream << (mut_type_index > 0 ? \", m\" : \"m\") << mutation_types[mut_type_index]->mutation_type_id_;\n\t\t\toutput_stream << ((mut_type_id_count > 1) ? \")\" : \"\");\n\t\t\t\n\t\t\toutput_stream << ((mut_type_id_count > 1) ? \", c(\" : \", \");\n\t\t\tfor (int mut_type_index = 0; mut_type_index < mut_type_id_count; ++mut_type_index)\n\t\t\t\toutput_stream << (mut_type_index > 0 ? \", \" : \"\") << proportions_value->NumericAtIndex_NOCAST(mut_type_index, nullptr);\n\t\t\toutput_stream << ((mut_type_id_count > 1) ? \")\" : \"\");\n\t\t\t\n\t\t\toutput_stream << \");\" << std::endl;\n\t\t}\n\t}\n\t\n\tnum_ge_type_inits_++;\n\treturn symbol_entry.second;\n}\n\n//\t*********************\t(object<MutationType>$)initializeMutationType(is$ id, numeric$ dominanceCoeff, string$ distributionType, ...)\n//\t*********************\t(object<MutationType>$)initializeMutationTypeNuc(is$ id, numeric$ dominanceCoeff, string$ distributionType, ...)\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeMutationType(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\t// Figure out whether the mutation type is nucleotide-based\n\tbool nucleotide_based = (p_function_name == \"initializeMutationTypeNuc\");\n\t\n\tif (nucleotide_based && !nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationType): initializeMutationTypeNuc() may be only be called in nucleotide-based models.\" << EidosTerminate();\n\t\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *dominanceCoeff_value = p_arguments[1].get();\n\tEidosValue *distributionType_value = p_arguments[2].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tslim_objectid_t map_identifier = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 'm');\n\tdouble dominance_coeff = dominanceCoeff_value->NumericAtIndex_NOCAST(0, nullptr);\n\tstd::string dfe_type_string = distributionType_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (community_.MutationTypeWithID(map_identifier))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationType): \" << p_function_name << \"() mutation type m\" << map_identifier << \" already defined.\" << EidosTerminate();\n\t\n\t// Parse the DFE type and parameters, and do various sanity checks\n\tDFEType dfe_type;\n\tstd::vector<double> dfe_parameters;\n\tstd::vector<std::string> dfe_strings;\n\t\n\tMutationType::ParseDFEParameters(dfe_type_string, p_arguments.data() + 3, (int)p_arguments.size() - 3, &dfe_type, &dfe_parameters, &dfe_strings);\n\t\n#ifdef SLIMGUI\n\t// each new mutation type gets a unique zero-based index, used by SLiMgui to categorize mutations\n\tMutationType *new_mutation_type = new MutationType(*this, map_identifier, dominance_coeff, nucleotide_based, dfe_type, dfe_parameters, dfe_strings, num_mutation_type_inits_);\n#else\n\tMutationType *new_mutation_type = new MutationType(*this, map_identifier, dominance_coeff, nucleotide_based, dfe_type, dfe_parameters, dfe_strings);\n#endif\n\t\n\tmutation_types_.emplace(map_identifier, new_mutation_type);\n\tcommunity_.mutation_types_changed_ = true;\n\t\n\t// keep track of whether we have ever seen a type 's' (scripted) DFE; if so, we switch to a slower case when evolving\n\tif (dfe_type == DFEType::kScript)\n\t\ttype_s_dfes_present_ = true;\n\t\n\t// define a new Eidos variable to refer to the new mutation type\n\tEidosSymbolTableEntry &symbol_entry = new_mutation_type->SymbolTableEntry();\n\t\n\tif (p_interpreter.SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationType): \" << p_function_name << \"() symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\n\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tif (ABBREVIATE_DEBUG_INPUT && (num_mutation_type_inits_ > 99))\n\t\t{\n\t\t\tif (num_mutation_type_inits_ == 100)\n\t\t\t\toutput_stream << \"(...more \" << p_function_name << \"() calls omitted...)\" << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toutput_stream << p_function_name << \"(\" << map_identifier << \", \" << dominance_coeff << \", \\\"\" << dfe_type << \"\\\"\";\n\t\t\t\n\t\t\tif (dfe_parameters.size() > 0)\n\t\t\t{\n\t\t\t\tfor (double dfe_param : dfe_parameters)\n\t\t\t\t\toutput_stream << \", \" << dfe_param;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (const std::string &dfe_param : dfe_strings)\n\t\t\t\t\toutput_stream << \", \\\"\" << dfe_param << \"\\\"\";\n\t\t\t}\n\t\t\t\n\t\t\toutput_stream << \");\" << std::endl;\n\t\t}\n\t}\n\t\n\tnum_mutation_type_inits_++;\n\treturn symbol_entry.second;\n}\n\n//\t*********************\t(void)initializeRecombinationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeRecombinationRate(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *rates_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tint rate_count = rates_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex;\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\tif ((requested_sex != IndividualSex::kUnspecified) && !sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() sex-specific recombination map supplied in non-sexual simulation.\" << EidosTerminate();\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state.  Since single_recombination_map_ has not been set\n\t// yet, we just look to see whether the chromosome's policy has already been determined or not.\n\tif (((requested_sex == IndividualSex::kUnspecified) && ((chromosome->recombination_rates_M_.size() != 0) || (chromosome->recombination_rates_F_.size() != 0))) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && (chromosome->recombination_rates_H_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\tif (((requested_sex == IndividualSex::kUnspecified) && (num_recrate_inits_ > 0)) || ((requested_sex != IndividualSex::kUnspecified) && (num_recrate_inits_ > 1)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() may be called only once (or once per sex, with sex-specific recombination maps).  The multiple recombination regions of a recombination map must be set up in a single call to initializeRecombinationRate().\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->recombination_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t\t   ((requested_sex == IndividualSex::kMale) ? chromosome->recombination_end_positions_M_ : chromosome->recombination_end_positions_F_));\n\tstd::vector<double> &rates = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->recombination_rates_H_ : \n\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? chromosome->recombination_rates_M_ : chromosome->recombination_rates_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tif (rate_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires rates to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values; I thought about requiring a rate of 0.0 for all haploid chromosome types, but maybe\n\t\t// the user wants to recombine them sometimes with addRecombinant(), no need to prevent them\n\t\tif ((recombination_rate < 0.0) || (recombination_rate > 0.5) || std::isnan(recombination_rate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires rates to be in [0.0, 0.5] (\" << EidosStringForFloat(recombination_rate) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.clear();\n\t\tpositions.clear();\n\t\t\n\t\trates.emplace_back(recombination_rate);\n\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\telse\n\t{\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != rate_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires ends and rates to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t recombination_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (recombination_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((recombination_rate < 0.0) || (recombination_rate > 0.5) || std::isnan(recombination_rate))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires rates to be in [0.0, 0.5] (\" << EidosStringForFloat(recombination_rate) << \" supplied).\" << EidosTerminate();\n\t\t\t\n\t\t\tif (chromosome->extent_immutable_)\n\t\t\t{\n\t\t\t\tif ((recombination_end_position <= 0) || (recombination_end_position > chromosome->last_position_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeRecombinationRate): initializeRecombinationRate() requires all end positions to be within the extent of the chromosome.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// then adopt them\n\t\trates.clear();\n\t\tpositions.clear();\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble recombination_rate = rates_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t recombination_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\trates.emplace_back(recombination_rate);\n\t\t\tpositions.emplace_back(recombination_end_position);\n\t\t}\n\t}\n\t\n\tcommunity_.chromosome_changed_ = true;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tint ratesSize = (int)rates.size();\n\t\tint endsSize = (int)positions.size();\n\t\t\n\t\toutput_stream << \"initializeRecombinationRate(\";\n\t\t\n\t\tif (ratesSize > 1)\n\t\t\toutput_stream << \"c(\";\n\t\tfor (int interval_index = 0; interval_index < ratesSize; ++interval_index)\n\t\t{\n\t\t\tif (interval_index >= 50)\n\t\t\t{\n\t\t\t\toutput_stream << \", ...\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << rates[interval_index];\n\t\t}\n\t\tif (ratesSize > 1)\n\t\t\toutput_stream << \")\";\n\t\t\n\t\tif (endsSize > 0)\n\t\t{\n\t\t\toutput_stream << \", \";\n\t\t\t\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \"c(\";\n\t\t\tfor (int interval_index = 0; interval_index < endsSize; ++interval_index)\n\t\t\t{\n\t\t\t\tif (interval_index >= 50)\n\t\t\t\t{\n\t\t\t\t\toutput_stream << \", ...\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << positions[interval_index];\n\t\t\t}\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \")\";\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_recrate_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeGeneConversion(numeric$ nonCrossoverFraction, numeric$ meanLength, numeric$ simpleConversionFraction, [numeric$ bias = 0], [logical$ redrawLengthsOnFailure = F])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeGeneConversion(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *nonCrossoverFraction_value = p_arguments[0].get();\n\tEidosValue *meanLength_value = p_arguments[1].get();\n\tEidosValue *simpleConversionFraction_value = p_arguments[2].get();\n\tEidosValue *bias_value = p_arguments[3].get();\n\tEidosValue *redrawLengthsOnFailure_value = p_arguments[4].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_gene_conv_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() may be called only once.\" << EidosTerminate();\n\t\n\tdouble non_crossover_fraction = nonCrossoverFraction_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble gene_conversion_avg_length = meanLength_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble simple_conversion_fraction = simpleConversionFraction_value->NumericAtIndex_NOCAST(0, nullptr);\n\tdouble bias = bias_value->NumericAtIndex_NOCAST(0, nullptr);\n\tbool redraw_lengths_on_failure = redrawLengthsOnFailure_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((non_crossover_fraction < 0.0) || (non_crossover_fraction > 1.0) || std::isnan(non_crossover_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() nonCrossoverFraction must be between 0.0 and 1.0 inclusive (\" << EidosStringForFloat(non_crossover_fraction) << \" supplied).\" << EidosTerminate();\n\tif ((gene_conversion_avg_length < 0.0) || std::isnan(gene_conversion_avg_length))\t\t// intentionally no upper bound\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() meanLength must be >= 0.0 (\" << EidosStringForFloat(gene_conversion_avg_length) << \" supplied).\" << EidosTerminate();\n\tif ((simple_conversion_fraction < 0.0) || (simple_conversion_fraction > 1.0) || std::isnan(simple_conversion_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() simpleConversionFraction must be between 0.0 and 1.0 inclusive (\" << EidosStringForFloat(simple_conversion_fraction) << \" supplied).\" << EidosTerminate();\n\tif ((bias < -1.0) || (bias > 1.0) || std::isnan(bias))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() bias must be between -1.0 and 1.0 inclusive (\" << EidosStringForFloat(bias) << \" supplied).\" << EidosTerminate();\n\tif ((bias != 0.0) && !nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeGeneConversion): initializeGeneConversion() bias must be 0.0 in non-nucleotide-based models.\" << EidosTerminate();\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\tchromosome->using_DSB_model_ = true;\n\tchromosome->non_crossover_fraction_ = non_crossover_fraction;\n\tchromosome->gene_conversion_avg_length_ = gene_conversion_avg_length;\n\tchromosome->gene_conversion_inv_half_length_ = 1.0 / (gene_conversion_avg_length / 2.0);\n\tchromosome->simple_conversion_fraction_ = simple_conversion_fraction;\n\tchromosome->mismatch_repair_bias_ = bias;\n\tchromosome->redraw_lengths_on_failure_ = redraw_lengths_on_failure;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeGeneConversion(\" << non_crossover_fraction << \", \" << gene_conversion_avg_length << \", \" << simple_conversion_fraction << \", \" << bias;\n\t\t\n\t\tif (redraw_lengths_on_failure)\n\t\t\toutput_stream << \", T\";\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_gene_conv_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeHotspotMap(numeric multipliers, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeHotspotMap(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tif (!nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() may only be called in nucleotide-based models (use initializeMutationRate() to vary the mutation rate along the chromosome).\" << EidosTerminate();\n\t\n\tEidosValue *multipliers_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tint multipliers_count = multipliers_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex;\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\tif ((requested_sex != IndividualSex::kUnspecified) && !sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() sex-specific hotspot map supplied in non-sexual simulation.\" << EidosTerminate();\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state\n\tif (((requested_sex == IndividualSex::kUnspecified) && ((chromosome->hotspot_multipliers_M_.size() != 0) || (chromosome->hotspot_multipliers_F_.size() != 0))) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && (chromosome->hotspot_multipliers_H_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\tif (((requested_sex == IndividualSex::kUnspecified) && (num_hotmap_inits_ > 0)) || ((requested_sex != IndividualSex::kUnspecified) && (num_hotmap_inits_ > 1)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() may be called only once (or once per sex, with sex-specific hotspot maps).  The multiple hotspot regions of a hotspot map must be set up in a single call to initializeHotspotMap().\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->hotspot_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t\t   ((requested_sex == IndividualSex::kMale) ? chromosome->hotspot_end_positions_M_ : chromosome->hotspot_end_positions_F_));\n\tstd::vector<double> &multipliers = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->hotspot_multipliers_H_ : \n\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? chromosome->hotspot_multipliers_M_ : chromosome->hotspot_multipliers_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tif (multipliers_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires multipliers to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values\n\t\tif ((multiplier < 0.0) || !std::isfinite(multiplier))\t\t// intentionally no upper bound\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires multipliers to be >= 0 (\" << EidosStringForFloat(multiplier) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\tmultipliers.clear();\n\t\tpositions.clear();\n\t\t\n\t\tmultipliers.emplace_back(multiplier);\n\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\telse\n\t{\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != multipliers_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires ends and multipliers to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t multiplier_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (multiplier_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((multiplier < 0.0) || !std::isfinite(multiplier))\t\t// intentionally no upper bound\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires multipliers to be >= 0 (\" << EidosStringForFloat(multiplier) << \" supplied).\" << EidosTerminate();\n\t\t\t\n\t\t\tif (chromosome->extent_immutable_)\n\t\t\t{\n\t\t\t\tif ((multiplier_end_position <= 0) || (multiplier_end_position > chromosome->last_position_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeHotspotMap): initializeHotspotMap() requires all end positions to be within the extent of the chromosome.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// then adopt them\n\t\tmultipliers.clear();\n\t\tpositions.clear();\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble multiplier = multipliers_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t multiplier_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\tmultipliers.emplace_back(multiplier);\n\t\t\tpositions.emplace_back(multiplier_end_position);\n\t\t}\n\t}\n\t\n\tcommunity_.chromosome_changed_ = true;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tint multipliersSize = (int)multipliers.size();\n\t\tint endsSize = (int)positions.size();\n\t\t\n\t\toutput_stream << \"initializeHotspotMap(\";\n\t\t\n\t\tif (multipliersSize > 1)\n\t\t\toutput_stream << \"c(\";\n\t\tfor (int interval_index = 0; interval_index < multipliersSize; ++interval_index)\n\t\t{\n\t\t\tif (interval_index >= 50)\n\t\t\t{\n\t\t\t\toutput_stream << \", ...\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << multipliers[interval_index];\n\t\t}\n\t\tif (multipliersSize > 1)\n\t\t\toutput_stream << \")\";\n\t\t\n\t\tif (endsSize > 0)\n\t\t{\n\t\t\toutput_stream << \", \";\n\t\t\t\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \"c(\";\n\t\t\tfor (int interval_index = 0; interval_index < endsSize; ++interval_index)\n\t\t\t{\n\t\t\t\tif (interval_index >= 50)\n\t\t\t\t{\n\t\t\t\t\toutput_stream << \", ...\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << positions[interval_index];\n\t\t\t}\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \")\";\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_hotmap_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeMutationRate(numeric rates, [Ni ends = NULL], [string$ sex = \"*\"])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeMutationRate(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tif (nucleotide_based_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() may not be called in nucleotide-based models (use initializeHotspotMap() to vary the mutation rate along the chromosome).\" << EidosTerminate();\n\t\n\tEidosValue *rates_value = p_arguments[0].get();\n\tEidosValue *ends_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tint rate_count = rates_value->Count();\n\t\n\t// Figure out what sex we are being given a map for\n\tIndividualSex requested_sex;\n\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\tif ((requested_sex != IndividualSex::kUnspecified) && !sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() sex-specific mutation map supplied in non-sexual simulation.\" << EidosTerminate();\n\t\n\t// This function triggers the creation of an implicit chromosome if a chromosome has not already been set up\n\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\tMakeImplicitChromosome(ChromosomeType::kA_DiploidAutosome);\n\t\n\tChromosome *chromosome = CurrentlyInitializingChromosome();\n\t\n\t// Make sure specifying a map for that sex is legal, given our current state.  Since single_mutation_map_ has not been set\n\t// yet, we just look to see whether the chromosome's policy has already been determined or not.\n\tif (((requested_sex == IndividualSex::kUnspecified) && ((chromosome->mutation_rates_M_.size() != 0) || (chromosome->mutation_rates_F_.size() != 0))) ||\n\t\t((requested_sex != IndividualSex::kUnspecified) && (chromosome->mutation_rates_H_.size() != 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() cannot change the chromosome between using a single map versus separate maps for the sexes; the original configuration must be preserved.\" << EidosTerminate();\n\t\n\tif (((requested_sex == IndividualSex::kUnspecified) && (num_mutrate_inits_ > 0)) || ((requested_sex != IndividualSex::kUnspecified) && (num_mutrate_inits_ > 1)))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() may be called only once (or once per sex, with sex-specific mutation maps).  The multiple mutation regions of a mutation map must be set up in a single call to initializeMutationRate().\" << EidosTerminate();\n\t\n\t// Set up to replace the requested map\n\tstd::vector<slim_position_t> &positions = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->mutation_end_positions_H_ : \n\t\t\t\t\t\t\t\t\t\t\t   ((requested_sex == IndividualSex::kMale) ? chromosome->mutation_end_positions_M_ : chromosome->mutation_end_positions_F_));\n\tstd::vector<double> &rates = ((requested_sex == IndividualSex::kUnspecified) ? chromosome->mutation_rates_H_ : \n\t\t\t\t\t\t\t\t  ((requested_sex == IndividualSex::kMale) ? chromosome->mutation_rates_M_ : chromosome->mutation_rates_F_));\n\t\n\tif (ends_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tif (rate_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires rates to be a singleton if ends is not supplied.\" << EidosTerminate();\n\t\t\n\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// check values\n\t\tif ((mutation_rate < 0.0) || (mutation_rate >= 1.0) || !std::isfinite(mutation_rate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires rates to be >= 0.0 and < 1.0 (\" << EidosStringForFloat(mutation_rate) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\t// then adopt them\n\t\trates.clear();\n\t\tpositions.clear();\n\t\t\n\t\trates.emplace_back(mutation_rate);\n\t\t//positions.emplace_back(?);\t// deferred; patched in Chromosome::InitializeDraws().\n\t}\n\telse\n\t{\n\t\tint end_count = ends_value->Count();\n\t\t\n\t\tif ((end_count != rate_count) || (end_count == 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires ends and rates to be of equal and nonzero size.\" << EidosTerminate();\n\t\t\n\t\t// check values\n\t\tfor (int value_index = 0; value_index < end_count; ++value_index)\n\t\t{\n\t\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (value_index > 0)\n\t\t\t\tif (mutation_end_position <= ends_value->IntAtIndex_NOCAST(value_index - 1, nullptr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires ends to be in strictly ascending order.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((mutation_rate < 0.0) || (mutation_rate >= 1.0) || !std::isfinite(mutation_rate))\t\t// intentionally no upper bound\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires rates to be >= 0.0 and < 1.0 (\" << EidosStringForFloat(mutation_rate) << \" supplied).\" << EidosTerminate();\n\t\t\t\n\t\t\tif (chromosome->extent_immutable_)\n\t\t\t{\n\t\t\t\tif ((mutation_end_position <= 0) || (mutation_end_position > chromosome->last_position_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeMutationRate): initializeMutationRate() requires all end positions to be within the extent of the chromosome.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// then adopt them\n\t\trates.clear();\n\t\tpositions.clear();\n\t\t\n\t\tfor (int interval_index = 0; interval_index < end_count; ++interval_index)\n\t\t{\n\t\t\tdouble mutation_rate = rates_value->NumericAtIndex_NOCAST(interval_index, nullptr);\n\t\t\tslim_position_t mutation_end_position = SLiMCastToPositionTypeOrRaise(ends_value->IntAtIndex_NOCAST(interval_index, nullptr));\n\t\t\t\n\t\t\trates.emplace_back(mutation_rate);\n\t\t\tpositions.emplace_back(mutation_end_position);\n\t\t}\n\t}\n\t\n\tcommunity_.chromosome_changed_ = true;\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\tint ratesSize = (int)rates.size();\n\t\tint endsSize = (int)positions.size();\n\t\t\n\t\toutput_stream << \"initializeMutationRate(\";\n\t\t\n\t\tif (ratesSize > 1)\n\t\t\toutput_stream << \"c(\";\n\t\tfor (int interval_index = 0; interval_index < ratesSize; ++interval_index)\n\t\t{\n\t\t\tif (interval_index >= 50)\n\t\t\t{\n\t\t\t\toutput_stream << \", ...\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << rates[interval_index];\n\t\t}\n\t\tif (ratesSize > 1)\n\t\t\toutput_stream << \")\";\n\t\t\n\t\tif (endsSize > 0)\n\t\t{\n\t\t\toutput_stream << \", \";\n\t\t\t\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \"c(\";\n\t\t\tfor (int interval_index = 0; interval_index < endsSize; ++interval_index)\n\t\t\t{\n\t\t\t\tif (interval_index >= 50)\n\t\t\t\t{\n\t\t\t\t\toutput_stream << \", ...\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\toutput_stream << (interval_index == 0 ? \"\" : \", \") << positions[interval_index];\n\t\t\t}\n\t\t\tif (endsSize > 1)\n\t\t\t\toutput_stream << \")\";\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_mutrate_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeSex(Ns$ chromosomeType)\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeSex(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_arguments, p_interpreter)\n\tEidosValue *chromosomeType_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_sex_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSex): initializeSex() may be called only once.\" << EidosTerminate();\n\tif (num_chromosome_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSex): initializeSex() must be called before initializeChromosome(), so that initializeChromosome() knows it is in a sexual model.\" << EidosTerminate();\n\t\n\tif (chromosomeType_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL case: we are enabling sex, but not defining an implicit chromosome, and not setting the chromosome type\n\t\t// An implicit chromosome is OK in this code path; it has already been assumed to be diploid autosomal, which is fine\n\t\t\n\t\tif (SLiM_verbosity_level >= 1)\n\t\t{\n\t\t\toutput_stream << \"initializeSex(NULL);\" << std::endl;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Backward-compatibility case: the user is setting the type of the implicit chromosome with \"A\", \"X\", or \"Y\".\n\t\tstd::string chromosome_type = chromosomeType_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (chromosome_type.compare(gStr_A) == 0)\n\t\t{\n\t\t\t// We want to allow initializeSex() in a no-genetics model; it makes sense to have a sexual but non-genetic species.\n\t\t\t// We allow that only in the \"A\" case, though; it doesn't make much sense if an \"X\" or \"Y\" model is requested.\n\t\t\t// So in this code path we do not make an implicit chromosome; if it is made by somebody else, it will be \"A\".\n\t\t}\n\t\telse if ((chromosome_type.compare(gStr_X) == 0) ||\n\t\t\t\t (chromosome_type.compare(gStr_Y) == 0))\n\t\t{\n\t\t\t// In this \"X\" / \"Y\" code path we want to force an implicit chromosome to be defined.\n\t\t\tif (has_implicit_chromosome_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSex): initializeSex() with type 'X' or 'Y' must be called before other methods that define an implicit chromosome - initializeAncestralNucleotides(), initializeGeneConversion(), initializeGenomicElement(), initializeHotspotMap(), initializeMutationRate(), and initializeRecombinationRate() - so that the implicit chromosome knows it is a sex chromosome when it is created.\" << EidosTerminate();\n\t\t\t\n\t\t\tChromosomeType modeled_chromosome_type;\n\t\t\t\n\t\t\tif (chromosome_type.compare(gStr_X) == 0)\n\t\t\t\tmodeled_chromosome_type = ChromosomeType::kX_XSexChromosome;\n\t\t\telse if (chromosome_type.compare(gStr_Y) == 0)\n\t\t\t\tmodeled_chromosome_type = ChromosomeType::kNullY_YSexChromosomeWithNull;\t// not ChromosomeType::kY_YSexChromosome, for backward compatibility\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSex): (internal error) unexpected type.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((num_chromosome_inits_ == 0) && !has_implicit_chromosome_)\n\t\t\t\tMakeImplicitChromosome(modeled_chromosome_type);\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSex): initializeSex() requires a chromosomeType of 'A', 'X', or 'Y' ('\" << chromosome_type << \"' supplied), or NULL if the chromosome type will be set in initializeChromosome().\" << EidosTerminate();\n\t\t\n\t\tif (SLiM_verbosity_level >= 1)\n\t\t{\n\t\t\toutput_stream << \"initializeSex(\\\"\" << chromosome_type << \"\\\"\";\n\t\t\t\n\t\t\toutput_stream << \");\" << std::endl;\n\t\t}\n\t}\n\t\n\tsex_enabled_ = true;\n\tnum_sex_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeSLiMOptions([logical$ keepPedigrees = F], [string$ dimensionality = \"\"], [string$ periodicity = \"\"], [logical$ doMutationRunExperiments = T], [logical$ preventIncidentalSelfing = F], [logical$ nucleotideBased = F], [logical$ randomizeCallbacks = T], [logical$ checkInfiniteLoops = T])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeSLiMOptions(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_interpreter)\n\tEidosValue *arg_keepPedigrees_value = p_arguments[0].get();\n\tEidosValue *arg_dimensionality_value = p_arguments[1].get();\n\tEidosValue *arg_periodicity_value = p_arguments[2].get();\n\tEidosValue *arg_doMutationRunExperiments_value = p_arguments[3].get();\n\tEidosValue *arg_preventIncidentalSelfing_value = p_arguments[4].get();\n\tEidosValue *arg_nucleotideBased_value = p_arguments[5].get();\n\tEidosValue *arg_randomizeCallbacks_value = p_arguments[6].get();\n#ifdef SLIMGUI\n\tEidosValue *arg_checkInfiniteLoops_value = p_arguments[7].get();\t// this exists outside SLiMgui, but we don't use it\n#endif\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_slimoptions_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): initializeSLiMOptions() may be called only once.\" << EidosTerminate();\n\t\n\tif (num_chromosome_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): initializeSLiMOptions() must be called before initializeChromosome(), so that initializeChromosome() has the model configuration information it needs to set up the chromosome.\" << EidosTerminate();\n\t\n\t// see also Species::HasDoneAnyInitialization() for the check used by initializeModelType()\n\t// we have no order-dependency with initializeSpecies()\n\tif ((num_mutation_type_inits_ > 0) || (num_mutrate_inits_ > 0) || (num_ge_type_inits_ > 0) || (num_genomic_element_inits_ > 0) || (num_recrate_inits_ > 0) || (num_gene_conv_inits_ > 0) || (num_sex_inits_ > 0) || (num_treeseq_inits_ > 0) || (num_ancseq_inits_ > 0) || (num_hotmap_inits_ > 0) || has_implicit_chromosome_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): initializeSLiMOptions() must be called before all other species-specific initialization functions.\" << EidosTerminate();\n\t\n\t{\n\t\t// [logical$ keepPedigrees = F]\n\t\tbool keep_pedigrees = arg_keepPedigrees_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (keep_pedigrees)\n\t\t{\n\t\t\t// pedigree recording can always be turned on by the user\n\t\t\tpedigrees_enabled_ = true;\n\t\t\tpedigrees_enabled_by_user_ = true;\n\t\t}\n\t\telse\t// !keep_pedigrees\n\t\t{\n\t\t\tif (pedigrees_enabled_by_SLiM_)\n\t\t\t{\n\t\t\t\t// if pedigrees were forced on by tree-seq recording or SLiMgui, they stay on, but we remember that the user wanted them off\n\t\t\t\tpedigrees_enabled_by_user_ = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// otherwise, the user can turn them off if so desired\n\t\t\t\tpedigrees_enabled_ = false;\n\t\t\t\tpedigrees_enabled_by_user_ = false;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t{\n\t\t// [string$ dimensionality = \"\"]\n\t\tstd::string space = arg_dimensionality_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (space.length() != 0)\n\t\t{\n\t\t\tif (space == \"x\")\n\t\t\t\tspatial_dimensionality_ = 1;\n\t\t\telse if (space == \"xy\")\n\t\t\t\tspatial_dimensionality_ = 2;\n\t\t\telse if (space == \"xyz\")\n\t\t\t\tspatial_dimensionality_ = 3;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): in initializeSLiMOptions(), legal non-empty values for parameter dimensionality are only 'x', 'xy', and 'xyz'.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t{\n\t\t// [string$ periodicity = \"\"]\n\t\tstd::string periodicity = arg_periodicity_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (periodicity.length() != 0)\n\t\t{\n\t\t\tif (spatial_dimensionality_ == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): in initializeSLiMOptions(), parameter periodicity may not be set in non-spatial simulations.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (periodicity == \"x\")\n\t\t\t\tperiodic_x_ = true;\n\t\t\telse if (periodicity == \"y\")\n\t\t\t\tperiodic_y_ = true;\n\t\t\telse if (periodicity == \"z\")\n\t\t\t\tperiodic_z_ = true;\n\t\t\telse if (periodicity == \"xy\")\n\t\t\t\tperiodic_x_ = periodic_y_ = true;\n\t\t\telse if (periodicity == \"xz\")\n\t\t\t\tperiodic_x_ = periodic_z_ = true;\n\t\t\telse if (periodicity == \"yz\")\n\t\t\t\tperiodic_y_ = periodic_z_ = true;\n\t\t\telse if (periodicity == \"xyz\")\n\t\t\t\tperiodic_x_ = periodic_y_ = periodic_z_ = true;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): in initializeSLiMOptions(), legal non-empty values for parameter periodicity are only 'x', 'y', 'z', 'xy', 'xz', 'yz', and 'xyz'.\" << EidosTerminate();\n\t\t\t\n\t\t\tif ((periodic_y_ && (spatial_dimensionality_ < 2)) || (periodic_z_ && (spatial_dimensionality_ < 3)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSLiMOptions): in initializeSLiMOptions(), parameter periodicity cannot utilize spatial dimensions beyond those set by the dimensionality parameter of initializeSLiMOptions().\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t{\n\t\t// [logical$ doMutationRunExperiments = T]\n\t\t// note this parameter position used to be [integer$ mutationRuns = 0] instead!\n\t\tbool do_mutrun_experiments = arg_doMutationRunExperiments_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tdo_mutrun_experiments_ = do_mutrun_experiments;\n\t}\n\t\n\t{\n\t\t// [logical$ preventIncidentalSelfing = F]\n\t\tbool prevent_selfing = arg_preventIncidentalSelfing_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tprevent_incidental_selfing_ = prevent_selfing;\n\t}\n\t\n\t{\n\t\t// [logical$ nucleotideBased = F]\n\t\tbool nucleotide_based = arg_nucleotideBased_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tnucleotide_based_ = nucleotide_based;\n\t}\n\t\n\t{\n\t\t// [logical$ randomizeCallbacks = T]\n\t\tbool randomize_callbacks = arg_randomizeCallbacks_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tshuffle_buf_is_enabled_ = randomize_callbacks;\n\t}\n\t\n\t{\n\t\t// [logical$ checkInfiniteLoops = T]\n#ifdef SLIMGUI\n\t\tbool check_infinite_loops = arg_checkInfiniteLoops_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\t// set on the current interpreter and the community; if we're executing inside a nested\n\t\t// interpreter, the interpreters above us will not get their flag set, so that is a bug...\n\t\tp_interpreter.check_infinite_loops_ = check_infinite_loops;\n\t\tcommunity_.check_infinite_loops_ = check_infinite_loops;\n#endif\n\t}\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeSLiMOptions(\";\n\t\t\n\t\tbool previous_params = false;\n\t\t\n\t\tif (pedigrees_enabled_by_user_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"keepPedigrees = \" << (pedigrees_enabled_by_user_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (spatial_dimensionality_ != 0)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"dimensionality = \";\n\t\t\t\n\t\t\tif (spatial_dimensionality_ == 1) output_stream << \"'x'\";\n\t\t\telse if (spatial_dimensionality_ == 2) output_stream << \"'xy'\";\n\t\t\telse if (spatial_dimensionality_ == 3) output_stream << \"'xyz'\";\n\t\t\t\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (periodic_x_ || periodic_y_ || periodic_z_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"periodicity = '\";\n\t\t\t\n\t\t\tif (periodic_x_) output_stream << \"x\";\n\t\t\tif (periodic_y_) output_stream << \"y\";\n\t\t\tif (periodic_z_) output_stream << \"z\";\n\t\t\toutput_stream << \"'\";\n\t\t\t\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (prevent_incidental_selfing_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"preventIncidentalSelfing = \" << (prevent_incidental_selfing_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (nucleotide_based_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"nucleotideBased = \" << (nucleotide_based_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (!shuffle_buf_is_enabled_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"randomizeCallbacks = \" << (shuffle_buf_is_enabled_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t\t(void)previous_params;\t// dead store above is deliberate\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_slimoptions_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t(void)initializeSpecies([integer$ tickModulo = 1], [integer$ tickPhase = 1], [string$ avatar = \"\"], [string$ color = \"\"])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeSpecies(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_interpreter)\n\tEidosValue *arg_tickModulo_value = p_arguments[0].get();\n\tEidosValue *arg_tickPhase_value = p_arguments[1].get();\n\tEidosValue *arg_avatar_value = p_arguments[2].get();\n\tEidosValue *arg_color_value = p_arguments[3].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// BCH 27 March 2022: This is not actually necessary, but it seems best to draw a sharp line between explicit-species models\n\t// and implied-species (single-species) models, to avoid confusion.  We do the same for 'ticks' and 'species' specifications\n\t// on events and callbacks.  If you want to do species-related stuff, declare your species.\n\tif (!community_.is_explicit_species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSpecies): initializeSpecies() may only be called if species have been explicitly declared, with a 'species <name>' specifier preceding an initialize() callback.\" << EidosTerminate();\n\t\n\tif (num_species_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSpecies): initializeSpecies() may be called only once per species.\" << EidosTerminate();\n\t\n\tif (num_chromosome_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSpecies): initializeSpecies() must be called before initializeChromosome(), so that initializeChromosome() has the model configuration information it needs to set up the chromosome.\" << EidosTerminate();\n\t\n\tint64_t tickModulo = arg_tickModulo_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((tickModulo < 1) || (tickModulo >= SLIM_MAX_TICK))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSpecies): initializeSpecies() requires a tickModulo value >= 1.\" << EidosTerminate();\n\t\n\ttick_modulo_ = (slim_tick_t)tickModulo;\n\t\n\tint64_t tickPhase = arg_tickPhase_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((tickPhase < 1) || (tickModulo >= SLIM_MAX_TICK))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeSpecies): initializeSpecies() requires a tickPhase value >= 1.\" << EidosTerminate();\n\t\n\ttick_phase_ = (slim_tick_t)tickPhase;\n\t\n\tavatar_ = arg_avatar_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tcolor_ = arg_color_value->StringAtIndex_NOCAST(0, nullptr);\n\tif (!color_.empty())\n\t\tEidos_GetColorComponents(color_, &color_red_, &color_green_, &color_blue_);\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeSpecies(\";\n\t\t\n\t\tbool previous_params = false;\n\t\t\n\t\tif (tickModulo != 1)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"tickModulo = \" << tickModulo;\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (tickPhase != 1)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"tickPhase = \" << tickPhase;\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (avatar_.length() > 0)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"avatar = \\\"\" << avatar_ << \"\\\"\";\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (color_.length() > 0)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"color = \\\"\" << color_ << \"\\\"\";\n\t\t\tprevious_params = true;\n\t\t\t(void)previous_params;\t// dead store above is deliberate\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_species_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// TREE SEQUENCE RECORDING\n//\t*********************\t(void)initializeTreeSeq([logical$ recordMutations = T], [Nif$ simplificationRatio = NULL], [Ni$ simplificationInterval = NULL], [logical$ checkCoalescence = F], [logical$ runCrosschecks = F], [logical$ retainCoalescentOnly = T], [Ns$ timeUnit = NULL])\n//\nEidosValue_SP Species::ExecuteContextFunction_initializeTreeSeq(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_function_name, p_interpreter)\n\tEidosValue *arg_recordMutations_value = p_arguments[0].get();\n\tEidosValue *arg_simplificationRatio_value = p_arguments[1].get();\n\tEidosValue *arg_simplificationInterval_value = p_arguments[2].get();\n\tEidosValue *arg_checkCoalescence_value = p_arguments[3].get();\n\tEidosValue *arg_runCrosschecks_value = p_arguments[4].get();\n\tEidosValue *arg_retainCoalescentOnly_value = p_arguments[5].get();\n\tEidosValue *arg_timeUnit_value = p_arguments[6].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\tif (num_treeseq_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() may be called only once.\" << EidosTerminate();\n\t\n\tif (num_chromosome_inits_ > 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() must be called before initializeChromosome(), so that initializeChromosome() has the model configuration information it needs to set up the chromosome.\" << EidosTerminate();\n\t\n\t// NOTE: the TSXC_Enable() method also sets up tree-seq recording by setting these sorts of flags;\n\t// if the code here changes, that method should probably be updated too.\n\t\n\trecording_tree_ = true;\n\trecording_mutations_ = arg_recordMutations_value->LogicalAtIndex_NOCAST(0, nullptr);\n\trunning_coalescence_checks_ = arg_checkCoalescence_value->LogicalAtIndex_NOCAST(0, nullptr);\n\trunning_treeseq_crosschecks_ = arg_runCrosschecks_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tretain_coalescent_only_ = arg_retainCoalescentOnly_value->LogicalAtIndex_NOCAST(0, nullptr);\n\ttreeseq_crosschecks_interval_ = 1;\t\t// this interval is presently not exposed in the Eidos API\n\t\n\tif ((arg_simplificationRatio_value->Type() == EidosValueType::kValueNULL) && (arg_simplificationInterval_value->Type() == EidosValueType::kValueNULL))\n\t{\n\t\t// Both ratio and interval are NULL; use the default behavior of a ratio of 10\n\t\tsimplification_ratio_ = 10.0;\n\t\tsimplification_interval_ = -1;\n\t\tsimplify_interval_ = 20;\n\t}\n\telse if (arg_simplificationRatio_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\t// The ratio is non-NULL; using the specified ratio\n\t\tsimplification_ratio_ = arg_simplificationRatio_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\tsimplification_interval_ = -1;\n\t\t\n\t\tif (std::isnan(simplification_ratio_) || (simplification_ratio_ < 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() requires simplificationRatio to be >= 0.\" << EidosTerminate();\n\t\t\n\t\t// Choose an initial auto-simplification interval\n\t\tif (arg_simplificationInterval_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\t// Both ratio and interval are non-NULL; the interval is thus interpreted as the *initial* interval\n\t\t\tsimplify_interval_ = arg_simplificationInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (simplify_interval_ <= 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() requires simplificationInterval to be > 0.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The interval is NULL, so use the default\n\t\t\tif (simplification_ratio_ == 0.0)\n\t\t\t\tsimplify_interval_ = 1.0;\n\t\t\telse\n\t\t\t\tsimplify_interval_ = 20;\n\t\t}\n\t}\n\telse if (arg_simplificationInterval_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\t// The ratio is NULL, interval is not; using the specified interval\n\t\tsimplification_ratio_ = 0.0;\n\t\tsimplification_interval_ = arg_simplificationInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (simplification_interval_ <= 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() requires simplificationInterval to be > 0.\" << EidosTerminate();\n\t}\n\t\n\t// Pedigree recording is turned on as a side effect of tree sequence recording, since we need to\n\t// have unique identifiers for every individual; pedigree recording does that for us\n\tpedigrees_enabled_ = true;\n\tpedigrees_enabled_by_SLiM_ = true;\n\t\n\t// Get the time units if set, or set the default time unit as appropriate\n\tif (arg_timeUnit_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// In SLiM 3.7 we set the time unit to \"generations\" for WF models since generations are non-overlapping\n\t\t// there, and to \"ticks\" in nonWF models.  In SLiM 4 we set it to \"ticks\" in all cases, since with the\n\t\t// multispecies changes different WF species may run on different timescales.  A tick is a tick.  The user\n\t\t// can set this otherwise if they want to; we should not try to second-guess what is going on.\n\t\tcommunity_.treeseq_time_unit_ = \"ticks\";\n\t}\n\telse\n\t{\n\t\tcommunity_.treeseq_time_unit_ = arg_timeUnit_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((community_.treeseq_time_unit_.length() == 0) || (community_.treeseq_time_unit_.find('\"') != std::string::npos) || (community_.treeseq_time_unit_.find('\\'') != std::string::npos))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteContextFunction_initializeTreeSeq): initializeTreeSeq() requires the timeUnit to be non-zero length, and it may not contain a quote character.\" << EidosTerminate();\n\t}\n\t\n\tif (SLiM_verbosity_level >= 1)\n\t{\n\t\toutput_stream << \"initializeTreeSeq(\";\n\t\t\n\t\tbool previous_params = false;\n\t\t\n\t\tif (!recording_mutations_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"recordMutations = \" << (recording_mutations_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (arg_simplificationRatio_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"simplificationRatio = \" << simplification_ratio_;\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (arg_simplificationInterval_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"simplificationInterval = \" << arg_simplificationInterval_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (running_coalescence_checks_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"checkCoalescence = \" << (running_coalescence_checks_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (running_treeseq_crosschecks_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"runCrosschecks = \" << (running_treeseq_crosschecks_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (!retain_coalescent_only_)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"retainCoalescentOnly = \" << (retain_coalescent_only_ ? \"T\" : \"F\");\n\t\t\tprevious_params = true;\n\t\t}\n\t\t\n\t\tif (arg_timeUnit_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tif (previous_params) output_stream << \", \";\n\t\t\toutput_stream << \"timeUnit = '\" << community_.treeseq_time_unit_ << \"'\";\t// assumes a simple string with no quotes\n\t\t\tprevious_params = true;\n\t\t\t(void)previous_params;\t// dead store above is deliberate\n\t\t}\n\t\t\n\t\toutput_stream << \");\" << std::endl;\n\t}\n\t\n\tnum_treeseq_inits_++;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\nconst EidosClass *Species::Class(void) const\n{\n\treturn gSLiM_Species_Class;\n}\n\nvoid Species::Print(std::ostream &p_ostream) const\n{\n\t// Show the avatar in multispecies models (or any explicit species model)\n\tif (community_.is_explicit_species_)\n\t\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << species_id_ << \":\" << avatar_ << \">\";\n\telse\n\t\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << species_id_ << \">\";\n}\n\nEidosValue_SP Species::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_avatar:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(avatar_));\n\t\t}\n\t\tcase gID_chromosome:\n\t\t{\n\t\t\tif (chromosomes_.size() != 1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetProperty): property chromosome may only be accessed on a species that has exactly one chromosome; in all other cases the chromosomes property must be used, since it can return multiple chromosomes (or none).\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(chromosomes_[0], gSLiM_Chromosome_Class));\n\t\t}\n\t\tcase gID_chromosomes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\t\tvec->push_object_element_RR(chromosome);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gEidosID_color:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(color_));\n\t\t}\n\t\tcase gID_dimensionality:\n\t\t{\n\t\t\tstatic EidosValue_SP static_dimensionality_string_x;\n\t\t\tstatic EidosValue_SP static_dimensionality_string_xy;\n\t\t\tstatic EidosValue_SP static_dimensionality_string_xyz;\n\t\t\t\n#pragma omp critical (GetProperty_dimensionality_cache)\n\t\t\t{\n\t\t\t\tif (!static_dimensionality_string_x)\n\t\t\t\t{\n\t\t\t\t\tstatic_dimensionality_string_x = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_x));\n\t\t\t\t\tstatic_dimensionality_string_xy = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"xy\"));\n\t\t\t\t\tstatic_dimensionality_string_xyz = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"xyz\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tswitch (spatial_dimensionality_)\n\t\t\t{\n\t\t\t\tcase 0:\t\treturn gStaticEidosValue_StringEmpty;\n\t\t\t\tcase 1:\t\treturn static_dimensionality_string_x;\n\t\t\t\tcase 2:\t\treturn static_dimensionality_string_xy;\n\t\t\t\tcase 3:\t\treturn static_dimensionality_string_xyz;\n\t\t\t\tdefault:\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_id:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(species_id_));\n\t\t}\n\t\tcase gID_periodicity:\n\t\t{\n\t\t\tstatic EidosValue_SP static_periodicity_string_x;\n\t\t\tstatic EidosValue_SP static_periodicity_string_y;\n\t\t\tstatic EidosValue_SP static_periodicity_string_z;\n\t\t\tstatic EidosValue_SP static_periodicity_string_xy;\n\t\t\tstatic EidosValue_SP static_periodicity_string_xz;\n\t\t\tstatic EidosValue_SP static_periodicity_string_yz;\n\t\t\tstatic EidosValue_SP static_periodicity_string_xyz;\n\t\t\t\n#pragma omp critical (GetProperty_periodicity_cache)\n\t\t\t{\n\t\t\t\tif (!static_periodicity_string_x)\n\t\t\t\t{\n\t\t\t\t\tstatic_periodicity_string_x = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_x));\n\t\t\t\t\tstatic_periodicity_string_y = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_y));\n\t\t\t\t\tstatic_periodicity_string_z = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_z));\n\t\t\t\t\tstatic_periodicity_string_xy = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"xy\"));\n\t\t\t\t\tstatic_periodicity_string_xz = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"xz\"));\n\t\t\t\t\tstatic_periodicity_string_yz = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"yz\"));\n\t\t\t\t\tstatic_periodicity_string_xyz = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"xyz\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (periodic_x_ && periodic_y_ && periodic_z_)\treturn static_periodicity_string_xyz;\n\t\t\telse if (periodic_y_ && periodic_z_)\t\t\treturn static_periodicity_string_yz;\n\t\t\telse if (periodic_x_ && periodic_z_)\t\t\treturn static_periodicity_string_xz;\n\t\t\telse if (periodic_x_ && periodic_y_)\t\t\treturn static_periodicity_string_xy;\n\t\t\telse if (periodic_z_)\t\t\t\t\t\t\treturn static_periodicity_string_z;\n\t\t\telse if (periodic_y_)\t\t\t\t\t\t\treturn static_periodicity_string_y;\n\t\t\telse if (periodic_x_)\t\t\t\t\t\t\treturn static_periodicity_string_x;\n\t\t\telse\t\t\t\t\t\t\t\t\t\t\treturn gStaticEidosValue_StringEmpty;\n\t\t}\n\t\tcase gID_genomicElementTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_GenomicElementType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto ge_type : genomic_element_types_)\n\t\t\t\tvec->push_object_element_NORR(ge_type.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_mutations:\n\t\t{\n\t\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\t\tint registry_size;\n\t\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(registry_size);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + registry[registry_index], registry_index);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_mutationTypes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto mutation_type : mutation_types_)\n\t\t\t\tvec->push_object_element_NORR(mutation_type.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name_));\n\t\t}\n\t\tcase gID_nucleotideBased:\n\t\t{\n\t\t\treturn (nucleotide_based_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t}\n\t\tcase gID_scriptBlocks:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_SLiMEidosBlock_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\tconst std::vector<SLiMEidosBlock*> &script_blocks = community_.AllScriptBlocksForSpecies(this);\t\t// this will only be species-specific callbacks\n\t\t\t\n\t\t\tfor (auto script_block : script_blocks)\n\t\t\t\tvec->push_object_element_NORR(script_block);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_sexChromosomes:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : chromosomes_)\n\t\t\t\tif (chromosome->IsSexChromosome())\n\t\t\t\t\tvec->push_object_element_RR(chromosome);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_sexEnabled:\n\t\t\treturn (sex_enabled_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gID_subpopulations:\n\t\t{\n\t\t\tEidosValue_Object *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Subpopulation_Class);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto pop : population_.subpops_)\n\t\t\t\tvec->push_object_element_NORR(pop.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_substitutions:\n\t\t{\n\t\t\tstd::vector<Substitution*> &substitutions = population_.substitutions_;\n\t\t\tint substitution_count = (int)substitutions.size();\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Substitution_Class))->resize_no_initialize_RR(substitution_count);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (int sub_index = 0; sub_index < substitution_count; ++sub_index)\n\t\t\t\tvec->set_object_element_no_check_no_previous_RR(substitutions[sub_index], sub_index);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_description:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(description_));\n\t\t}\n\t\tcase gID_cycle:\n\t\t{\n\t\t\tif (cached_value_cycle_ && (cached_value_cycle_->IntData()[0] != cycle_))\n\t\t\t\tcached_value_cycle_.reset();\n\t\t\tif (!cached_value_cycle_)\n\t\t\t\tcached_value_cycle_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(cycle_));\n\t\t\treturn cached_value_cycle_;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::GetProperty): property tag accessed on simulation object before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nvoid Species::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_description:\n\t\t{\n\t\t\tstd::string description = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\t// there are no restrictions on descriptions at all\n\t\t\t\n\t\t\tdescription_ = description;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_cycle:\n\t\t{\n\t\t\tint64_t value = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\t\tslim_tick_t old_cycle = cycle_;\n\t\t\tslim_tick_t new_cycle = SLiMCastToTickTypeOrRaise(value);\n\t\t\t\n\t\t\tif (new_cycle != old_cycle)\n\t\t\t\tSetCycle(new_cycle);\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t}\n}\n\nEidosValue_SP Species::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\t\t// WF only:\n\t\tcase gID_addSubpopSplit:\t\t\t\t\treturn ExecuteMethod_addSubpopSplit(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\tcase gID_addPatternForClone:\t\t\t\treturn ExecuteMethod_addPatternForClone(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addPatternForCross:\t\t\t\treturn ExecuteMethod_addPatternForCross(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addPatternForNull:\t\t\t\t\treturn ExecuteMethod_addPatternForNull(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addPatternForRecombinant:\t\t\treturn ExecuteMethod_addPatternForRecombinant(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSubpop:\t\t\t\t\t\t\treturn ExecuteMethod_addSubpop(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_chromosomesOfType:\t\t\t\t\treturn ExecuteMethod_chromosomesOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_chromosomesWithIDs:\t\t\t\treturn ExecuteMethod_chromosomesWithIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_chromosomesWithSymbols:\t\t\treturn ExecuteMethod_chromosomesWithSymbols(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_individualsWithPedigreeIDs:\t\treturn ExecuteMethod_individualsWithPedigreeIDs(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_killIndividuals:\t\t\t\t\treturn ExecuteMethod_killIndividuals(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mutationFrequencies:\n\t\tcase gID_mutationCounts:\t\t\t\t\treturn ExecuteMethod_mutationFreqsCounts(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_mutationsOfType:\t\t\t\t\treturn ExecuteMethod_mutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_countOfMutationsOfType:\t\t\treturn ExecuteMethod_countOfMutationsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_outputFixedMutations:\t\t\t\treturn ExecuteMethod_outputFixedMutations(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_outputFull:\t\t\t\t\t\treturn ExecuteMethod_outputFull(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_outputMutations:\t\t\t\t\treturn ExecuteMethod_outputMutations(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_readFromPopulationFile:\t\t\treturn ExecuteMethod_readFromPopulationFile(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_recalculateFitness:\t\t\t\treturn ExecuteMethod_recalculateFitness(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerFitnessEffectCallback:\t\treturn ExecuteMethod_registerFitnessEffectCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerMateChoiceCallback:\n\t\tcase gID_registerModifyChildCallback:\n\t\tcase gID_registerRecombinationCallback:\n\t\tcase gID_registerSurvivalCallback:\t\t\treturn ExecuteMethod_registerMateModifyRecSurvCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerMutationCallback:\t\t\treturn ExecuteMethod_registerMutationCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerMutationEffectCallback:\treturn ExecuteMethod_registerMutationEffectCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_registerReproductionCallback:\t\treturn ExecuteMethod_registerReproductionCallback(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_simulationFinished:\t\t\t\treturn ExecuteMethod_simulationFinished(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_skipTick:\t\t\t\t\t\t\treturn ExecuteMethod_skipTick(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_subsetMutations:\t\t\t\t\treturn ExecuteMethod_subsetMutations(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_substitutionsOfType:\t\t\t\treturn ExecuteMethod_substitutionsOfType(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_treeSeqCoalesced:\t\t\t\t\treturn ExecuteMethod_treeSeqCoalesced(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_treeSeqSimplify:\t\t\t\t\treturn ExecuteMethod_treeSeqSimplify(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_treeSeqRememberIndividuals:\t\treturn ExecuteMethod_treeSeqRememberIndividuals(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_treeSeqOutput:\t\t\t\t\t\treturn ExecuteMethod_treeSeqOutput(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID__debug:\t\t\t\t\t\t\treturn ExecuteMethod__debug(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (object<Dictionary>$)addPatternForClone(iso<Chromosome>$ chromosome, No<Dictionary>$ pattern, object<Individual>$ parent, [Ns$ sex = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_addPatternForClone(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosome_value = p_arguments[0].get();\n\tEidosValue *pattern_value = p_arguments[1].get();\n\tEidosValue *parent_value = p_arguments[2].get();\n\tEidosValue *sex_value = p_arguments[3].get();\n\t\n\t// Get the focal chromosome; NULL is not allowed by signature\n\tChromosome *chromosome = GetChromosomeFromEidosValue(chromosome_value);\n\t\n\t// Get or construct the pattern dictionary; result_SP keeps a retain on it\n\tEidosDictionaryUnretained *pattern;\n\tEidosValue_SP result_SP(nullptr);\n\tbool pattern_uses_integer_keys;\n\t\n\tif (pattern_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tEidosDictionaryRetained *pattern_retained = new EidosDictionaryRetained();\n\t\tpattern = pattern_retained;\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(pattern, gEidosDictionaryRetained_Class));\n\t\tpattern_retained->Release();\t// retained by result_SP\n\t\tpattern_uses_integer_keys = true;\n\t}\n\telse\n\t{\n\t\tpattern = (EidosDictionaryUnretained *)pattern_value->ObjectData()[0];\n\t\tresult_SP = p_arguments[1];\n\t\tpattern_uses_integer_keys = pattern->KeysAreIntegers();\n\t}\n\t\n\t// Get the offspring sex\n\tIndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &sex_string = sex_value->StringData()[0];\n\t\t\n\t\tif (sex_string.compare(\"M\") == 0)\n\t\t\tsex = IndividualSex::kMale;\n\t\telse if (sex_string.compare(\"F\") == 0)\n\t\t\tsex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForClone): addPatternForClone() requires sex to be 'M' or 'F', or NULL.\" << EidosTerminate();\n\t}\n\t\n\t// make a new inheritance dictionary and add it to pattern\n\tEidosDictionaryRetained *inheritance = new EidosDictionaryRetained();\n\tEidosValue_SP inheritance_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(inheritance, gEidosDictionaryRetained_Class));\n\tinheritance->Release();\n\t\n\tif (pattern_uses_integer_keys)\n\t\tpattern->SetKeyValue_IntegerKeys(chromosome->ID(), inheritance_SP);\n\telse\n\t\tpattern->SetKeyValue_StringKeys(chromosome->Symbol(), inheritance_SP);\n\t\n\t//\n\t//\tthe above code is shared with the other addPatternFor...() methods; the remainder of the code is not\n\t//\n\t\n\t// Get the parent for cloning and get info about it\n\tIndividual *parent = (Individual *)parent_value->ObjectData()[0];\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent->subpopulation_->species_ != this)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForClone): addPatternForClone() requires that parent belong to the target species.\" << EidosTerminate();\n\t\n\t// get the inheritance pattern; there are at most two strands involved, and no recombination\n\tHaplosome *strand1 = nullptr, *strand3 = nullptr;\n\t\n\tInferInheritanceForClone(chromosome, parent, sex, &strand1, &strand3, \"addPatternForClone()\");\n\t\n\t// set the inheritance pattern into the dictionary\n\tif (strand1)\tinheritance->SetKeyValue_StringKeys(gStr_strand1, strand1->CachedEidosValue());\n\tif (strand3)\tinheritance->SetKeyValue_StringKeys(gStr_strand3, strand3->CachedEidosValue());\n\t\n\tpattern->ContentsChanged(\"Dictionary()\");\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<Dictionary>$)addPatternForCross(iso<Chromosome>$ chromosome, No<Dictionary>$ pattern, object<Individual>$ parent1, object<Individual>$ parent2, [Ns$ sex = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_addPatternForCross(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosome_value = p_arguments[0].get();\n\tEidosValue *pattern_value = p_arguments[1].get();\n\tEidosValue *parent1_value = p_arguments[2].get();\n\tEidosValue *parent2_value = p_arguments[3].get();\n\tEidosValue *sex_value = p_arguments[4].get();\n\t\n\t// Get the focal chromosome; NULL is not allowed by signature\n\tChromosome *chromosome = GetChromosomeFromEidosValue(chromosome_value);\n\t\n\t// Get or construct the pattern dictionary; result_SP keeps a retain on it\n\tEidosDictionaryUnretained *pattern;\n\tEidosValue_SP result_SP(nullptr);\n\tbool pattern_uses_integer_keys;\n\t\n\tif (pattern_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tEidosDictionaryRetained *pattern_retained = new EidosDictionaryRetained();\n\t\tpattern = pattern_retained;\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(pattern, gEidosDictionaryRetained_Class));\n\t\tpattern_retained->Release();\t// retained by result_SP\n\t\tpattern_uses_integer_keys = true;\n\t}\n\telse\n\t{\n\t\tpattern = (EidosDictionaryUnretained *)pattern_value->ObjectData()[0];\n\t\tresult_SP = p_arguments[1];\n\t\tpattern_uses_integer_keys = pattern->KeysAreIntegers();\n\t}\n\t\n\t// Get the offspring sex\n\tIndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &sex_string = sex_value->StringData()[0];\n\t\t\n\t\tif (sex_string.compare(\"M\") == 0)\n\t\t\tsex = IndividualSex::kMale;\n\t\telse if (sex_string.compare(\"F\") == 0)\n\t\t\tsex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForCross): addPatternForCross() requires sex to be 'M' or 'F', or NULL.\" << EidosTerminate();\n\t}\n\t\n\t// make a new inheritance dictionary and add it to pattern\n\tEidosDictionaryRetained *inheritance = new EidosDictionaryRetained();\n\tEidosValue_SP inheritance_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(inheritance, gEidosDictionaryRetained_Class));\n\tinheritance->Release();\n\t\n\tif (pattern_uses_integer_keys)\n\t\tpattern->SetKeyValue_IntegerKeys(chromosome->ID(), inheritance_SP);\n\telse\n\t\tpattern->SetKeyValue_StringKeys(chromosome->Symbol(), inheritance_SP);\n\t\n\t//\n\t//\tthe above code is shared with the other addPatternFor...() methods; the remainder of the code is not\n\t//\n\t\n\t// Get the parents for crossing and validate them\n\tIndividual *parent1 = (Individual *)parent1_value->ObjectData()[0];\n\tIndividual *parent2 = (Individual *)parent2_value->ObjectData()[0];\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1->subpopulation_->species_ != this) || (&parent2->subpopulation_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForCross): addPatternForCross() requires that parent1 and parent2 belong to the target species.\" << EidosTerminate();\n\t\n\t// get the inheritance pattern; there are at most two strands involved, and no recombination\n\tHaplosome *strand1 = nullptr, *strand2 = nullptr, *strand3 = nullptr, *strand4 = nullptr;\n\t\n\tInferInheritanceForCross(chromosome, parent1, parent2, sex, &strand1, &strand2, &strand3, &strand4, \"addPatternForCross()\");\n\t\n\t// set the inheritance pattern into the dictionary\n\tif (strand1)\tinheritance->SetKeyValue_StringKeys(gStr_strand1, strand1->CachedEidosValue());\n\tif (strand2)\tinheritance->SetKeyValue_StringKeys(gStr_strand2, strand2->CachedEidosValue());\n\tif (strand3)\tinheritance->SetKeyValue_StringKeys(gStr_strand3, strand3->CachedEidosValue());\n\tif (strand4)\tinheritance->SetKeyValue_StringKeys(gStr_strand4, strand4->CachedEidosValue());\n\t\n\tpattern->ContentsChanged(\"Dictionary()\");\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<Dictionary>$)addPatternForNull(iso<Chromosome>$ chromosome, No<Dictionary>$ pattern, [Ns$ sex = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_addPatternForNull(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosome_value = p_arguments[0].get();\n\tEidosValue *pattern_value = p_arguments[1].get();\n\tEidosValue *sex_value = p_arguments[2].get();\n\t\n\t// Get the focal chromosome; NULL is not allowed by signature\n\tChromosome *chromosome = GetChromosomeFromEidosValue(chromosome_value);\n\tChromosomeType chromosome_type = chromosome->Type();\n\t\n\t// Get or construct the pattern dictionary; result_SP keeps a retain on it\n\tEidosDictionaryUnretained *pattern;\n\tEidosValue_SP result_SP(nullptr);\n\tbool pattern_uses_integer_keys;\n\t\n\tif (pattern_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tEidosDictionaryRetained *pattern_retained = new EidosDictionaryRetained();\n\t\tpattern = pattern_retained;\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(pattern, gEidosDictionaryRetained_Class));\n\t\tpattern_retained->Release();\t// retained by result_SP\n\t\tpattern_uses_integer_keys = true;\n\t}\n\telse\n\t{\n\t\tpattern = (EidosDictionaryUnretained *)pattern_value->ObjectData()[0];\n\t\tresult_SP = p_arguments[1];\n\t\tpattern_uses_integer_keys = pattern->KeysAreIntegers();\n\t}\n\t\n\t// Get the offspring sex\n\tIndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &sex_string = sex_value->StringData()[0];\n\t\t\n\t\tif (sex_string.compare(\"M\") == 0)\n\t\t\tsex = IndividualSex::kMale;\n\t\telse if (sex_string.compare(\"F\") == 0)\n\t\t\tsex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForNull): addPatternForNull() requires sex to be 'M' or 'F', or NULL.\" << EidosTerminate();\n\t}\n\t\n\t// make a new inheritance dictionary and add it to pattern\n\tEidosDictionaryRetained *inheritance = new EidosDictionaryRetained();\n\tEidosValue_SP inheritance_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(inheritance, gEidosDictionaryRetained_Class));\n\tinheritance->Release();\n\t\n\tif (pattern_uses_integer_keys)\n\t\tpattern->SetKeyValue_IntegerKeys(chromosome->ID(), inheritance_SP);\n\telse\n\t\tpattern->SetKeyValue_StringKeys(chromosome->Symbol(), inheritance_SP);\n\t\n\t//\n\t//\tthe above code is shared with the other addPatternFor...() methods; the remainder of the code is not\n\t//\n\t\n\tif ((chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kHF_HaploidFemaleInherited) ||\n\t\t(chromosome_type == ChromosomeType::kHM_HaploidMaleInherited) ||\n\t\t(chromosome_type == ChromosomeType::kHNull_HaploidAutosomeWithNull))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForNull): addPatternForNull() cannot be used with chromosome type '\" << chromosome_type << \"', since all individuals must possess at least one non-null haplosome for that chromosome type.  For greater flexibility, use chromosome type 'A' or 'H'.\" << EidosTerminate();\n\t\n\t// check that the offspring sex is compatible with having all null haplosomes for this chromosome\n\tif ((sex == IndividualSex::kUnspecified) || (sex == IndividualSex::kFemale))\n\t\tif ((chromosome_type == ChromosomeType::kW_WSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kFL_HaploidFemaleLine))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForNull): addPatternForNull() requires sex to be 'M' for chromosome type '', since only males can have all null haplosomes for that chromosome type.\" << EidosTerminate();\n\tif ((sex == IndividualSex::kUnspecified) || (sex == IndividualSex::kMale))\n\t\tif ((chromosome_type == ChromosomeType::kY_YSexChromosome) ||\n\t\t\t(chromosome_type == ChromosomeType::kML_HaploidMaleLine) ||\n\t\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForNull): addPatternForNull() requires sex to be 'F' for chromosome type '', since only females can have all null haplosomes for that chromosome type.\" << EidosTerminate();\n\t\n\t// set the inheritance pattern into the dictionary; there no code code here because the offspring\n\t// inherits nothing, so the inheritance dictionary should just be an empty dictionary, NULL for all\n\t\n\tpattern->ContentsChanged(\"Dictionary()\");\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<Dictionary>$)addPatternForRecombinant(iso<Chromosome>$ chromosome, No<Dictionary>$ pattern, No<Haplosome>$ strand1, No<Haplosome>$ strand2, Ni breaks1, No<Haplosome>$ strand3, No<Haplosome>$ strand4, Ni breaks2, [Ns$ sex = NULL], [logical$ randomizeStrands = T])\n//\nEidosValue_SP Species::ExecuteMethod_addPatternForRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosome_value = p_arguments[0].get();\n\tEidosValue *pattern_value = p_arguments[1].get();\n\tEidosValue *strand1_value = p_arguments[2].get();\n\tEidosValue *strand2_value = p_arguments[3].get();\n\tEidosValue *breaks1_value = p_arguments[4].get();\n\tEidosValue *strand3_value = p_arguments[5].get();\n\tEidosValue *strand4_value = p_arguments[6].get();\n\tEidosValue *breaks2_value = p_arguments[7].get();\n\tEidosValue *sex_value = p_arguments[8].get();\n\tEidosValue *randomizeStrands_value = p_arguments[9].get();\n\t\n\t// Get the focal chromosome; NULL is not allowed by signature\n\tChromosome *chromosome = GetChromosomeFromEidosValue(chromosome_value);\n\tChromosomeType chromosome_type = chromosome->Type();\n\tslim_chromosome_index_t chromosome_index = chromosome->Index();\n\t\n\t// Get or construct the pattern dictionary; result_SP keeps a retain on it\n\tEidosDictionaryUnretained *pattern;\n\tEidosValue_SP result_SP(nullptr);\n\tbool pattern_uses_integer_keys;\n\t\n\tif (pattern_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tEidosDictionaryRetained *pattern_retained = new EidosDictionaryRetained();\n\t\tpattern = pattern_retained;\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(pattern, gEidosDictionaryRetained_Class));\n\t\tpattern_retained->Release();\t// retained by result_SP\n\t\tpattern_uses_integer_keys = true;\n\t}\n\telse\n\t{\n\t\tpattern = (EidosDictionaryUnretained *)pattern_value->ObjectData()[0];\n\t\tresult_SP = p_arguments[1];\n\t\tpattern_uses_integer_keys = pattern->KeysAreIntegers();\n\t}\n\t\n\t// Get the offspring sex -- actually we just need to check it here, and then sex_value is passed to _ValidateHaplosomesAndChooseSex() below\n\t//IndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &sex_string = sex_value->StringData()[0];\n\t\t\n\t\tif (sex_string.compare(\"M\") == 0)\n\t\t\t; //sex = IndividualSex::kMale;\n\t\telse if (sex_string.compare(\"F\") == 0)\n\t\t\t; //sex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires sex to be 'M' or 'F', or NULL.\" << EidosTerminate();\n\t}\n\t\n\t// make a new inheritance dictionary and add it to pattern\n\tEidosDictionaryRetained *inheritance = new EidosDictionaryRetained();\n\tEidosValue_SP inheritance_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(inheritance, gEidosDictionaryRetained_Class));\n\tinheritance->Release();\n\t\n\tif (pattern_uses_integer_keys)\n\t\tpattern->SetKeyValue_IntegerKeys(chromosome->ID(), inheritance_SP);\n\telse\n\t\tpattern->SetKeyValue_StringKeys(chromosome->Symbol(), inheritance_SP);\n\t\n\t//\n\t//\tthe above code is shared with the other addPatternFor...() methods; the remainder of the code is not\n\t//\n\t\n\t// Get the strands for recombination and validate them\n\tHaplosome *strand1 = nullptr, *strand2 = nullptr, *strand3 = nullptr, *strand4 = nullptr;\n\t\n\tif (strand1_value->Type() != EidosValueType::kValueNULL)\n\t\tstrand1 = (Haplosome *)strand1_value->ObjectData()[0];\n\tif (strand2_value->Type() != EidosValueType::kValueNULL)\n\t\tstrand2 = (Haplosome *)strand2_value->ObjectData()[0];\n\tif (strand3_value->Type() != EidosValueType::kValueNULL)\n\t\tstrand3 = (Haplosome *)strand3_value->ObjectData()[0];\n\tif (strand4_value->Type() != EidosValueType::kValueNULL)\n\t\tstrand4 = (Haplosome *)strand4_value->ObjectData()[0];\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (strand1 && (&strand1->OwningIndividual()->subpopulation_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand1 belong to the target species.\" << EidosTerminate();\n\tif (strand2 && (&strand2->OwningIndividual()->subpopulation_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand2 belong to the target species.\" << EidosTerminate();\n\tif (strand3 && (&strand3->OwningIndividual()->subpopulation_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand3 belong to the target species.\" << EidosTerminate();\n\tif (strand4 && (&strand4->OwningIndividual()->subpopulation_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand4 belong to the target species.\" << EidosTerminate();\n\t\n\tif (strand1 && strand1->chromosome_index_ != chromosome_index)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand1 belong to the specified chromosome.\" << EidosTerminate();\n\tif (strand2 && strand2->chromosome_index_ != chromosome_index)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand2 belong to the specified chromosome.\" << EidosTerminate();\n\tif (strand3 && strand3->chromosome_index_ != chromosome_index)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand3 belong to the specified chromosome.\" << EidosTerminate();\n\tif (strand4 && strand4->chromosome_index_ != chromosome_index)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addPatternForRecombinant): addPatternForRecombinant() requires that strand4 belong to the specified chromosome.\" << EidosTerminate();\n\t\n\t// validate the haplosome pattern given the chromosome type and sex\n\tbool haplosome1_null = (!strand1 && !strand2);\n\tbool haplosome2_null = (!strand3 && !strand4);\n\tbool make_second_haplosome = false;\n\t\n\tif ((chromosome_type == ChromosomeType::kA_DiploidAutosome) ||\n\t\t(chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\tmake_second_haplosome = true;\n\t\n\tif (!haplosome2_null && !make_second_haplosome)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addPatternForRecombinant): for chromosome type '\" << chromosome_type <<\"', addPatternForRecombinant() requires that the second offspring haplosome is configured to be a null haplosome (since chromosome type '\" << chromosome_type << \"' is intrinsically haploid).\" << EidosTerminate();\n\t\n\tint breaks1count = breaks1_value->Count(), breaks2count = breaks2_value->Count();\n\t\n\tif (breaks1count != 0)\n\t{\n\t\tif (haplosome1_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addPatternForRecombinant): with a NULL strand1 and strand2, breaks1 must be NULL or empty.\" << EidosTerminate();\n\t\telse if (!strand2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addPatternForRecombinant): non-empty breaks1 supplied with a NULL strand2; recombination between strand1 and strand2 is not possible, so breaks1 must be NULL or empty.\" << EidosTerminate();\n\t}\n\tif (breaks2count != 0)\n\t{\n\t\tif (haplosome2_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addPatternForRecombinant): with a NULL strand3 and strand4, breaks2 must be NULL or empty.\" << EidosTerminate();\n\t\telse if (!strand4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addPatternForRecombinant): non-empty breaks2 supplied with a NULL strand4; recombination between strand3 and strand4 is not possible, so breaks2 must be NULL or empty.\" << EidosTerminate();\n\t}\n\t\n\tSubpopulation::_ValidateHaplosomesAndChooseSex(chromosome_type, haplosome1_null, haplosome2_null, sex_value, sex_enabled_, \"addPatternForRecombinant()\");\n\t\n\t// randomize strands if requested\n\teidos_logical_t randomizeStrands = randomizeStrands_value->LogicalData()[0];\n\t\n\tif (randomizeStrands)\n\t{\n\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\n\t\tif (strand1 && strand2 && Eidos_RandomBool(rng_state))\n\t\t\tstd::swap(strand1, strand2);\n\t\tif (strand3 && strand4 && Eidos_RandomBool(rng_state))\n\t\t\tstd::swap(strand3, strand4);\n\t}\n\t\n\t// set the validated inheritance pattern into the dictionary\n\tif (strand1)\tinheritance->SetKeyValue_StringKeys(gStr_strand1, p_arguments[2]);\n\tif (strand2)\tinheritance->SetKeyValue_StringKeys(gStr_strand2, p_arguments[3]);\n\tif (breaks1_value->Type() != EidosValueType::kValueNULL)\n\t\tinheritance->SetKeyValue_StringKeys(gStr_breaks1, p_arguments[4]);\n\t\n\tif (strand3)\tinheritance->SetKeyValue_StringKeys(gStr_strand3, p_arguments[5]);\n\tif (strand4)\tinheritance->SetKeyValue_StringKeys(gStr_strand4, p_arguments[6]);\n\tif (breaks2_value->Type() != EidosValueType::kValueNULL)\n\t\tinheritance->SetKeyValue_StringKeys(gStr_breaks2, p_arguments[7]);\n\t\n\tpattern->ContentsChanged(\"Dictionary()\");\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<Subpopulation>$)addSubpop(is$ subpopID, integer$ size, [float$ sexRatio = 0.5], [l$ haploid = F])\n//\nEidosValue_SP Species::ExecuteMethod_addSubpop(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpop): addSubpop() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpop): addSubpop() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tEidosValue *subpopID_value = p_arguments[0].get();\n\tEidosValue *size_value = p_arguments[1].get();\n\tEidosValue *sexRatio_value = p_arguments[2].get();\n\tEidosValue *haploid_value = p_arguments[3].get();\n\t\n\tslim_objectid_t subpop_id = SLiM_ExtractObjectIDFromEidosValue_is(subpopID_value, 0, 'p');\n\tslim_popsize_t subpop_size = SLiMCastToPopsizeTypeOrRaise(size_value->IntAtIndex_NOCAST(0, nullptr));\n\t\n\tdouble sex_ratio = sexRatio_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((sex_ratio != 0.5) && !sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpop): addSubpop() sex ratio supplied in non-sexual simulation.\" << EidosTerminate();\n\t\n\tbool haploid = haploid_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (haploid)\n\t{\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpop): addSubpop() cannot create haploid individuals with the haploid=T option in WF models.\" << EidosTerminate();\n\t\t// BCH 12/23/2024: For a brief time I also raised an error here if explicit chromosomes had been defined,\n\t\t// but then I realized that this flag remains useful in models of haplodiploidy, where you still want a\n\t\t// diploid chromosome (type \"A\") and want some individuals to have a null second haplosome.\n\t}\n\t\n\t// construct the subpop; we always pass the sex ratio, but AddSubpopulation will not use it if sex is not enabled, for simplicity\n\tSubpopulation *new_subpop = population_.AddSubpopulation(subpop_id, subpop_size, sex_ratio, haploid);\n\t\n\t// define a new Eidos variable to refer to the new subpopulation\n\tEidosSymbolTableEntry &symbol_entry = new_subpop->SymbolTableEntry();\n\t\n\tif (p_interpreter.SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpop): addSubpop() symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\n\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\n\treturn symbol_entry.second;\n}\n\n// WF only:\n//\t*********************\t– (object<Subpopulation>$)addSubpopSplit(is$ subpopID, integer$ size, io<Subpopulation>$ sourceSubpop, [float$ sexRatio = 0.5])\n//\nEidosValue_SP Species::ExecuteMethod_addSubpopSplit(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpopSplit): addSubpopSplit() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpopSplit): addSubpopSplit() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpopSplit): addSubpopSplit() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tEidosValue *subpopID_value = p_arguments[0].get();\n\tEidosValue *size_value = p_arguments[1].get();\n\tEidosValue *sourceSubpop_value = p_arguments[2].get();\n\tEidosValue *sexRatio_value = p_arguments[3].get();\n\t\n\tslim_objectid_t subpop_id = SLiM_ExtractObjectIDFromEidosValue_is(subpopID_value, 0, 'p');\n\tslim_popsize_t subpop_size = SLiMCastToPopsizeTypeOrRaise(size_value->IntAtIndex_NOCAST(0, nullptr));\n\tSubpopulation *source_subpop = SLiM_ExtractSubpopulationFromEidosValue_io(sourceSubpop_value, 0, &community_, this, \"addSubpopSplit()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\tdouble sex_ratio = sexRatio_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((sex_ratio != 0.5) && !sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpopSplit): addSubpopSplit() sex ratio supplied in non-sexual simulation.\" << EidosTerminate();\n\t\n\t// construct the subpop; we always pass the sex ratio, but AddSubpopulation will not use it if sex is not enabled, for simplicity\n\tSubpopulation *new_subpop = population_.AddSubpopulationSplit(subpop_id, *source_subpop, subpop_size, sex_ratio);\n\t\n\t// define a new Eidos variable to refer to the new subpopulation\n\tEidosSymbolTableEntry &symbol_entry = new_subpop->SymbolTableEntry();\n\t\n\tif (p_interpreter.SymbolTable().ContainsSymbol(symbol_entry.first))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_addSubpopSplit): addSubpopSplit() symbol \" << EidosStringRegistry::StringForGlobalStringID(symbol_entry.first) << \" was already defined prior to its definition here.\" << EidosTerminate();\n\t\n\tcommunity_.SymbolTable().InitializeConstantSymbolEntry(symbol_entry);\n\t\n\treturn symbol_entry.second;\n}\n\n//  *********************\t– chromosomesOfType(string$ type)\nEidosValue_SP Species::ExecuteMethod_chromosomesOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *type_value = p_arguments[0].get();\n\tstd::string type_string = type_value->StringAtIndex_NOCAST(0, nullptr);\n\tChromosomeType chromosome_type = ChromosomeTypeForString(type_string);\n\t\n\t// count the number of chromosomes of the requested type\n\tint chromosome_count = 0;\n\t\n\tfor (Chromosome *chromosome : Chromosomes())\n\t\tif (chromosome->Type() == chromosome_type)\n\t\t\tchromosome_count++;\n\t\n\t// gather and return the matches\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class))->reserve(chromosome_count);\t// reserve enough space for all results\n\t\n\tfor (Chromosome *chromosome : Chromosomes())\n\t\tif (chromosome->Type() == chromosome_type)\n\t\t\tresult->push_object_element_no_check_RR(chromosome);\n\t\n\treturn EidosValue_SP(result);\n}\n\n//  *********************\t– chromosomesWithIDs(integer ids)\nEidosValue_SP Species::ExecuteMethod_chromosomesWithIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *ids_value = p_arguments[0].get();\n\tint ids_count = ids_value->Count();\n\t\n\tif (ids_count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class));\n\t\n\tconst int64_t *ids_data = ids_value->IntData();\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class))->reserve(ids_count);\t// reserve enough space for all results\n\t\n\tfor (int ids_index = 0; ids_index < ids_count; ids_index++)\n\t{\n\t\tint64_t id = ids_data[ids_index];\n\t\tChromosome *chromosome = ChromosomeFromID(id);\n\t\t\n\t\tif (!chromosome)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_chromosomesWithIDs): chromosomesWithIDs() could not find a chromosome with the given id (\" << id << \").\" << EidosTerminate();\n\t\t\n\t\tresult->push_object_element_no_check_RR(chromosome);\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//  *********************\t– chromosomesWithSymbols(string symbols)\nEidosValue_SP Species::ExecuteMethod_chromosomesWithSymbols(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *symbols_value = p_arguments[0].get();\n\tint symbols_count = symbols_value->Count();\n\t\n\tif (symbols_count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class));\n\t\n\tconst std::string *symbols_data = symbols_value->StringData();\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Chromosome_Class))->reserve(symbols_count);\t// reserve enough space for all results\n\t\n\tfor (int symbols_index = 0; symbols_index < symbols_count; symbols_index++)\n\t{\n\t\tconst std::string &symbol = symbols_data[symbols_index];\n\t\tChromosome *chromosome = ChromosomeFromSymbol(symbol);\n\t\t\n\t\tif (!chromosome)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_chromosomesWithSymbols): chromosomesWithSymbols() could not find a chromosome with the given symbol (\" << symbol << \").\" << EidosTerminate();\n\t\t\n\t\tresult->push_object_element_no_check_RR(chromosome);\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (object<Individual>)individualsWithPedigreeIDs(integer pedigreeIDs, [Nio<Subpopulation> subpops = NULL])\nEidosValue_SP Species::ExecuteMethod_individualsWithPedigreeIDs(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tif (!PedigreesEnabledByUser())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_individualsWithPedigreeIDs): individualsWithPedigreeIDs() may only be called when pedigree recording has been enabled.\" << EidosTerminate();\n\t\n\tEidosValue *pedigreeIDs_value = p_arguments[0].get();\n\tEidosValue *subpops_value = p_arguments[1].get();\n\t\n\t// Cache the subpops across which we will tally\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::ExecuteMethod_individualsWithPedigreeIDs(): usage of statics\");\n\t\n\tstatic std::vector<Subpopulation*> subpops_to_search;\t// use a static to prevent allocation thrash\n\tsubpops_to_search.resize(0);\n\t\n\tif (subpops_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// Search through all subpops\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t\tsubpops_to_search.emplace_back(subpop_pair.second);\n\t}\n\telse\n\t{\n\t\t// Search through specified subpops\n\t\tint requested_subpop_count = subpops_value->Count();\n\t\t\n\t\tfor (int requested_subpop_index = 0; requested_subpop_index < requested_subpop_count; ++requested_subpop_index)\n\t\t\tsubpops_to_search.emplace_back(SLiM_ExtractSubpopulationFromEidosValue_io(subpops_value, requested_subpop_index, &community_, this, \"individualsWithPedigreeIDs()\"));\t\t// SPECIES CONSISTENCY CHECK\n\t}\n\t\n\t// An empty pedigreeIDs vector gets you an empty result, guaranteed\n\tint pedigreeIDs_count = pedigreeIDs_value->Count();\n\t\n\tif (pedigreeIDs_count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\t// Assemble the result\n\tconst int64_t *pedigree_id_data = pedigreeIDs_value->IntData();\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(pedigreeIDs_count);\t// reserve enough space for all results\n\t\n\tif (pedigreeIDs_count < 30)\t\t// crossover point determined by timing tests on macOS with various subpop sizes; 30 seems good, although it will vary across platforms etc.\n\t{\n\t\t// for smaller problem sizes, we do sequential search for each pedigree ID\n\t\tfor (int value_index = 0; value_index < pedigreeIDs_count; ++value_index)\n\t\t{\n\t\t\tslim_pedigreeid_t pedigree_id = pedigree_id_data[value_index];\n\t\t\t\n\t\t\tfor (Subpopulation *subpop : subpops_to_search)\n\t\t\t{\n\t\t\t\tstd::vector<Individual *> &inds = subpop->parent_individuals_;\n\t\t\t\t\n\t\t\t\tfor (Individual *ind : inds)\n\t\t\t\t{\n\t\t\t\t\tif (ind->PedigreeID() == pedigree_id)\n\t\t\t\t\t{\n\t\t\t\t\t\tresult->push_object_element_no_check_NORR(ind);\n\t\t\t\t\t\tgoto foundMatch;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Either we drop through to here, if we didn't find a match, or we goto to here, if we found one\n\t\tfoundMatch:\n\t\t\tcontinue;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// for larger problem sizes, we speed up lookups by building a hash table first, changing from O(N*M) to O(N)\n\t\t// we could get even more fancy and cache this hash table to speed up successive calls within one cycle,\n\t\t// but since the hash table is specific to the set of subpops we're searching, that would get a bit hairy...\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\trobin_hood::unordered_flat_map<slim_pedigreeid_t, Individual *> fromIDToIndividual;\n\t\t//typedef robin_hood::pair<slim_pedigreeid_t, Individual *> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\tstd::unordered_map<slim_pedigreeid_t, Individual *> fromIDToIndividual;\n\t\t//typedef std::pair<slim_pedigreeid_t, Individual *> MAP_PAIR;\n#endif\n\t\t\n\t\ttry {\n\t\t\tfor (Subpopulation *subpop : subpops_to_search)\n\t\t\t{\n\t\t\t\tstd::vector<Individual *> &inds = subpop->parent_individuals_;\n\t\t\t\t\n\t\t\t\tfor (Individual *ind : inds)\n\t\t\t\t\tfromIDToIndividual.emplace(ind->PedigreeID(), ind);\n\t\t\t}\n\t\t} catch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_individualsWithPedigreeIDs): (internal error) SLiM encountered a raise from an internal hash table; please report this.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n#ifdef _OPENMP\n\t\tif (pedigreeIDs_count >= EIDOS_OMPMIN_INDS_W_PEDIGREE_IDS)\n\t\t{\n\t\t\t// separate parallel implementation, since the logic is somewhat different\n\t\t\tresult->resize_no_initialize(pedigreeIDs_count);\n\n\t\t\tIndividual **result_data = (Individual **)result->data();\n\t\t\tbool any_unmatched = false;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_INDS_W_PEDIGREE_IDS);\n#pragma omp parallel for schedule(static) default(none) shared(pedigreeIDs_count, fromIDToIndividual) firstprivate(pedigree_id_data, result_data) reduction(||: any_unmatched) num_threads(thread_count) // if(EIDOS_OMPMIN_INDS_W_PEDIGREE_IDS) is above\n\t\t\tfor (int value_index = 0; value_index < pedigreeIDs_count; ++value_index)\n\t\t\t{\n\t\t\t\tauto find_iter = fromIDToIndividual.find(pedigree_id_data[value_index]);\n\t\t\t\t\n\t\t\t\tif (find_iter != fromIDToIndividual.end())\n\t\t\t\t{\n\t\t\t\t\tresult_data[value_index] = find_iter->second;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult_data[value_index] = nullptr;\n\t\t\t\t\tany_unmatched = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// because of the parallelization, we had to insert nullptrs into the result vector and then compact it afterwards\n\t\t\t// this compaction needs to preserve order, so it shifts elements down rather than backfilling from the end\n\t\t\tif (any_unmatched)\n\t\t\t{\n\t\t\t\tint next_unfilled_index = 0;\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < pedigreeIDs_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *result_ind = result_data[value_index];\n\t\t\t\t\t\n\t\t\t\t\tif (result_ind != nullptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (value_index != next_unfilled_index)\n\t\t\t\t\t\t\tresult_data[next_unfilled_index] = result_ind;\n\t\t\t\t\t\t\n\t\t\t\t\t\tnext_unfilled_index++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult->resize_no_initialize(next_unfilled_index);\n\t\t\t}\n\t\t}\n\t\telse\n#endif\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < pedigreeIDs_count; ++value_index)\n\t\t\t{\n\t\t\t\tauto find_iter = fromIDToIndividual.find(pedigree_id_data[value_index]);\n\t\t\t\t\n\t\t\t\tif (find_iter != fromIDToIndividual.end())\n\t\t\t\t\tresult->push_object_element_no_check_NORR(find_iter->second);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t- (void)killIndividuals(object<Individual> individuals)\n//\nEidosValue_SP Species::ExecuteMethod_killIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_killIndividuals): killIndividuals() is not available in WF models.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\tif (community_.executing_species_ == this)\n\t\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_killIndividuals): killIndividuals() must be called directly from a first(), early(), or late() event, when called on the currently executing species.\" << EidosTerminate();\n\t\n\tEidosValue_Object *individuals_value = (EidosValue_Object *)p_arguments[0].get();\n\tint individuals_count = individuals_value->Count();\n\tint killed_count = 0;\n\t\n\tif (individuals_count == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(individuals_value);\n\t\n\tif (species != this)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_killIndividuals): killIndividuals() requires that all individuals belong to the same species as the target species.\" << EidosTerminate();\n\t\n\t// Loop over the individuals and kill them one by one; since there might be references to them in script, we can't actually\n\t// free the objects now, so we move them to a temporary \"graveyard\" which we dispose of between tick cycle stages\n\tIndividual * const *individuals_data = (Individual * const *)individuals_value->ObjectData();\n\t\n\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t{\n\t\tIndividual *doomed = individuals_data[individual_index];\n\t\tslim_popsize_t source_subpop_index = doomed->index_;\n\t\t\n\t\tif (source_subpop_index < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_killIndividuals): killIndividuals() may not kill an individual that is not visible in a subpopulation.  This error will occur if you try to kill the same individual more than once.\" << EidosTerminate();\n\t\t\n\t\tSubpopulation *source_subpop = doomed->subpopulation_;\n\t\tslim_popsize_t source_subpop_size = source_subpop->parent_subpop_size_;\n\t\t\n\t\t// remove the originals from source_subpop's vectors\n\t\tif (doomed->sex_ == IndividualSex::kFemale)\n\t\t{\n\t\t\t// females have to be backfilled by the last female, and then that hole is backfilled by a male, and the first male index changes\n\t\t\tslim_popsize_t source_first_male = source_subpop->parent_first_male_index_;\n\t\t\t\n\t\t\tif (source_subpop_index < source_first_male - 1)\n\t\t\t{\n\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_first_male - 1];\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_individuals_[source_subpop_index] = backfill;\n\t\t\t\tbackfill->index_ = source_subpop_index;\n\t\t\t}\n\t\t\t\n\t\t\tif (source_first_male - 1 < source_subpop_size - 1)\n\t\t\t{\n\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_subpop_size - 1];\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_individuals_[source_first_male - 1] = backfill;\n\t\t\t\tbackfill->index_ = source_first_male - 1;\n\t\t\t}\n\t\t\t\n\t\t\tsource_subpop->parent_subpop_size_ = --source_subpop_size;\n\t\t\tsource_subpop->parent_individuals_.resize(source_subpop_size);\n\t\t\t\n\t\t\tsource_subpop->parent_first_male_index_ = --source_first_male;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// males and hermaphrodites can be removed with a simple backfill from the end of the vector\n\t\t\tif (source_subpop_index < source_subpop_size - 1)\n\t\t\t{\n\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_subpop_size - 1];\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_individuals_[source_subpop_index] = backfill;\n\t\t\t\tbackfill->index_ = source_subpop_index;\n\t\t\t}\n\t\t\t\n\t\t\tsource_subpop->parent_subpop_size_ = --source_subpop_size;\n\t\t\tsource_subpop->parent_individuals_.resize(source_subpop_size);\n\t\t}\n\t\t\n\t\t// add the doomed individual to our temporary graveyard\n\t\tgraveyard_.push_back(doomed);\n\t\t\n\t\t// it gets killed_ of true and an index of -1; we need to be careful about these possible values where we need to distinguish killed individuals\n\t\t// note that we do not change the subpopulation_ pointer, even though we have removed it from the subpopulation!  this is a similar state to\n\t\t// new offspring, which also get an index of -1 and are not added to the subpopulation's main data structures yet; the reason not to set\n\t\t// the subpopulation_ to nullptr is that we still need to be able to use subpopulation_ to get to species_ and community_ for various purposes\n\t\t// we hide this from the user, though; accessing the subpopulation property on a killed individual raises an error\n\t\tdoomed->killed_ = true;\n\t\tdoomed->index_ = -1;\n\t\t\n\t\tkilled_count++;\n\t}\n\t\n\tif (killed_count)\n\t{\n\t\t// First, clear our individual caches in all subpopulations; any subpops involved in\n\t\t// this method would be invalidated anyway so this probably isn't even that much overkill in\n\t\t// most models.\n\t\tfor (auto subpop_pair : population_.subpops_)\n\t\t\tsubpop_pair.second->cached_parent_individuals_value_.reset();\n\t\t\n\t\t// Invalidate interactions; we just do this for all subpops, for now, rather than trying to\n\t\t// selectively invalidate only the subpops involved in the deaths that occurred\n\t\tcommunity_.InvalidateInteractionsForSpecies(this);\n\t\t\n\t\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\t\tpopulation_.InvalidateMutationReferencesCache();\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (float)mutationFrequencies(Nio<Subpopulation> subpops, [No<Mutation> mutations = NULL])\n//\t*********************\t– (integer)mutationCounts(Nio<Subpopulation> subpops, [No<Mutation> mutations = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_mutationFreqsCounts(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_interpreter)\n\tEidosValue *subpops_value = p_arguments[0].get();\n\tEidosValue *mutations_value = p_arguments[1].get();\n\t\n\t// tally across the requested subpops; total haplosome counts are put into the chromosomes\n\tif (subpops_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// tally across the whole population\n\t\tpopulation_.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t}\n\telse\n\t{\n\t\t// requested subpops, so get them\n\t\tint requested_subpop_count = subpops_value->Count();\n\t\t\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Species::ExecuteMethod_mutationFreqsCounts(): usage of statics\");\n\t\t\n\t\tstatic std::vector<Subpopulation*> subpops_to_tally;\t// using and clearing a static prevents allocation thrash; should be safe from re-entry\n\t\t\n\t\tsubpops_to_tally.resize(0);\n\t\t\n\t\tif (requested_subpop_count)\n\t\t{\n\t\t\tfor (int requested_subpop_index = 0; requested_subpop_index < requested_subpop_count; ++requested_subpop_index)\n\t\t\t\tsubpops_to_tally.emplace_back(SLiM_ExtractSubpopulationFromEidosValue_io(subpops_value, requested_subpop_index, &community_, this,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t (p_method_id == gID_mutationFrequencies) ? \"mutationFrequencies()\" : \"mutationCounts()\"));\t\t// SPECIES CONSISTENCY CHECK\n\t\t\t\n\t\t\t// unique subpops_to_tally so duplicates don't confuse the count\n\t\t\tstd::sort(subpops_to_tally.begin(), subpops_to_tally.end());\n\t\t\tsubpops_to_tally.resize(static_cast<size_t>(std::distance(subpops_to_tally.begin(), std::unique(subpops_to_tally.begin(), subpops_to_tally.end()))));\n\t\t}\n\t\t\n\t\t// If *all* subpops were requested, then we delegate to the method that is designed to tally across the whole population.\n\t\t// Since we uniqued the subpops_to_tally vector above, we can check for equality by just comparing sizes.\n\t\tif (subpops_to_tally.size() == population_.subpops_.size())\n\t\t\tpopulation_.TallyMutationReferencesAcrossPopulation(/* p_clock_for_mutrun_experiments */ false);\n\t\telse\n\t\t\tpopulation_.TallyMutationReferencesAcrossSubpopulations(&subpops_to_tally);\n\t}\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (mutations_value->Count() >= 1)\n\t{\n\t\tSpecies *mut_species = Community::SpeciesForMutations(mutations_value);\n\t\t\n\t\tif (mut_species != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_mutationFreqsCounts): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requires that all mutations belong to the target species.\" << EidosTerminate();\n\t}\n\t\n\t// OK, now construct our result vector from the tallies for just the requested mutations\n\t// We now have utility methods on Population that do this for us; we pass a denominator\n\t// of nullptr, which says the denominator is the total haplosome count for each chromosome\n\tif (p_method_id == gID_mutationFrequencies)\n\t\treturn population_.Eidos_FrequenciesForTalliedMutations(mutations_value);\n\telse // p_method_id == gID_mutationCounts\n\t\treturn population_.Eidos_CountsForTalliedMutations(mutations_value);\n}\n\n//\t*********************\t- (object<Mutation>)mutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Species::ExecuteMethod_mutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &community_, this, \"mutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t// track calls per cycle to Species::ExecuteMethod_mutationsOfType() and Species::ExecuteMethod_countOfMutationsOfType()\n\tbool start_registry = (mutation_type_ptr->muttype_registry_call_count_++ >= 1);\n\tpopulation_.any_muttype_call_count_used_ = true;\n\t\n\t// start a registry if appropriate, so we can hit the fast case below\n\tif (start_registry && (!population_.keeping_muttype_registries_ || !mutation_type_ptr->keeping_muttype_registry_))\n\t{\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\tMutationRun &muttype_registry = mutation_type_ptr->muttype_registry_;\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutationIndex mut = registry[registry_index];\n\t\t\t\n\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\tmuttype_registry.emplace_back(mut);\n\t\t}\n\t\t\n\t\tpopulation_.keeping_muttype_registries_ = true;\n\t\tmutation_type_ptr->keeping_muttype_registry_ = true;\n\t}\n\t\n\tif (population_.keeping_muttype_registries_ && mutation_type_ptr->keeping_muttype_registry_)\n\t{\n\t\t// We're already keeping a separate registry for this mutation type (see mutation_type.h), so we can answer this directly\n\t\tMutationRun &mutation_registry = mutation_type_ptr->muttype_registry_;\n\t\tint mutation_count = mutation_registry.size();\n\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(mutation_count);\n\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\n\t\tfor (int mut_index = 0; mut_index < mutation_count; ++mut_index)\n\t\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + mutation_registry[mut_index], mut_index);\n\t\t\n\t\treturn result_SP;\n\t}\n\telse\n#endif\n\t{\n\t\t// No registry in the muttype; count the number of mutations of the given type, so we can reserve the right vector size\n\t\t// To avoid having to scan the registry twice for the simplest case of a single mutation, we cache the first mutation found\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\tint match_count = 0, registry_index;\n\t\tMutationIndex first_match = -1;\n\t\t\n\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutationIndex mut = registry[registry_index];\n\t\t\t\n\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t{\n\t\t\t\tif (++match_count == 1)\n\t\t\t\t\tfirst_match = mut;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Now allocate the result vector and assemble it\n\t\tif (match_count == 1)\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(mut_block_ptr + first_match, gSLiM_Mutation_Class));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class))->resize_no_initialize_RR(match_count);\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tif (match_count != 0)\n\t\t\t{\n\t\t\t\tint set_index = 0;\n\t\t\t\t\n\t\t\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\t\t{\n\t\t\t\t\tMutationIndex mut = registry[registry_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t\t\tvec->set_object_element_no_check_no_previous_RR(mut_block_ptr + mut, set_index++);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t}\n}\n\t\t\t\n//\t*********************\t- (integer$)countOfMutationsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Species::ExecuteMethod_countOfMutationsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &community_, this, \"countOfMutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n#ifdef SLIM_KEEP_MUTTYPE_REGISTRIES\n\t// track calls per cycle to Species::ExecuteMethod_mutationsOfType() and Species::ExecuteMethod_countOfMutationsOfType()\n\tbool start_registry = (mutation_type_ptr->muttype_registry_call_count_++ >= 1);\n\tpopulation_.any_muttype_call_count_used_ = true;\n\t\n\t// start a registry if appropriate, so we can hit the fast case below\n\tif (start_registry && (!population_.keeping_muttype_registries_ || !mutation_type_ptr->keeping_muttype_registry_))\n\t{\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\tMutationRun &muttype_registry = mutation_type_ptr->muttype_registry_;\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutationIndex mut = registry[registry_index];\n\t\t\t\n\t\t\tif ((mut_block_ptr + mut)->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\tmuttype_registry.emplace_back(mut);\n\t\t}\n\t\t\n\t\tpopulation_.keeping_muttype_registries_ = true;\n\t\tmutation_type_ptr->keeping_muttype_registry_ = true;\n\t}\n\t\n\tif (population_.keeping_muttype_registries_ && mutation_type_ptr->keeping_muttype_registry_)\n\t{\n\t\t// We're already keeping a separate registry for this mutation type (see mutation_type.h), so we can answer this directly\n\t\tMutationRun &muttype_registry = mutation_type_ptr->muttype_registry_;\n\t\tint mutation_count = muttype_registry.size();\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_count));\n\t}\n\telse\n#endif\n\t{\n\t\t// Count the number of mutations of the given type\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\tint match_count = 0;\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t\tif ((mut_block_ptr + registry[registry_index])->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\t\t++match_count;\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(match_count));\n\t}\n}\n\t\t\t\n//\t*********************\t– (void)outputFixedMutations([Ns$ filePath = NULL], [logical$ append=F], [logical$ objectTags=F])\n//\nEidosValue_SP Species::ExecuteMethod_outputFixedMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *append_value = p_arguments[1].get();\n\tEidosValue *objectTags_value = p_arguments[2].get();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// TIMING RESTRICTION\n\tif (!community_.warned_early_output_)\n\t{\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Species::ExecuteMethod_outputFixedMutations): outputFixedMutations() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity_.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tstd::ofstream outfile;\n\tbool has_file = false;\n\tstd::string outfile_path;\n\t\n\tif (filePath_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\toutfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\thas_file = true;\n\t\t\n\t\tif (!outfile.is_open())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputFixedMutations): outputFixedMutations() could not open \"<< outfile_path << \".\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t}\n\t\n\tstd::ostream &out = *(has_file ? dynamic_cast<std::ostream *>(&outfile) : dynamic_cast<std::ostream *>(&output_stream));\n\t\n#if DO_MEMORY_CHECKS\n\t// This method can burn a huge amount of memory and get us killed, if we have a maximum memory usage.  It's nice to\n\t// try to check for that and terminate with a proper error message, to help the user diagnose the problem.\n\tint mem_check_counter = 0, mem_check_mod = 100;\n\t\n\tif (eidos_do_memory_checks)\n\t\tEidos_CheckRSSAgainstMax(\"Species::ExecuteMethod_outputFixedMutations\", \"(outputFixedMutations(): The memory usage was already out of bounds on entry.)\");\n#endif\n\t\n\t// Output header line.  BCH 3/6/2022: Note that the cycle was added after the tick in SLiM 4.\n\tout << \"#OUT: \" << community_.Tick() << \" \" << Cycle() << \" F\";\n\t\n\tif (has_file)\n\t\tout << \" \" << outfile_path;\n\t\n\tout << std::endl;\n\t\n\t// Output Mutations section\n\tout << \"Mutations:\" << std::endl;\n\t\n\tbool output_object_tags = objectTags_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tstd::vector<Substitution*> &subs = population_.substitutions_;\n\t\n\tfor (unsigned int i = 0; i < subs.size(); i++)\n\t{\n\t\tout << i << \" \";\n\t\t\n\t\tif (output_object_tags)\n\t\t\tsubs[i]->PrintForSLiMOutput_Tag(out);\n\t\telse\n\t\t\tsubs[i]->PrintForSLiMOutput(out);\n\t\t\n#if DO_MEMORY_CHECKS\n\t\tif (eidos_do_memory_checks)\n\t\t{\n\t\t\tmem_check_counter++;\n\t\t\t\n\t\t\tif (mem_check_counter % mem_check_mod == 0)\n\t\t\t\tEidos_CheckRSSAgainstMax(\"Species::ExecuteMethod_outputFixedMutations\", \"(outputFixedMutations(): Out of memory while outputting substitution objects.)\");\n\t\t}\n#endif\n\t}\n\t\n\tif (has_file)\n\t\toutfile.close(); \n\t\n\treturn gStaticEidosValueVOID;\n}\n\t\t\t\n//\t*********************\t– (void)outputFull([Ns$ filePath = NULL], [logical$ binary = F], [logical$ append=F], [logical$ spatialPositions = T], [logical$ ages = T], [logical$ ancestralNucleotides = T], [logical$ pedigreeIDs = F], [logical$ objectTags = F], [logical$ substitutions = F])\n//\nEidosValue_SP Species::ExecuteMethod_outputFull(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *binary_value = p_arguments[1].get();\n\tEidosValue *append_value = p_arguments[2].get();\n\tEidosValue *spatialPositions_value = p_arguments[3].get();\n\tEidosValue *ages_value = p_arguments[4].get();\n\tEidosValue *ancestralNucleotides_value = p_arguments[5].get();\n\tEidosValue *pedigreeIDs_value = p_arguments[6].get();\n\tEidosValue *objectTags_value = p_arguments[7].get();\n\tEidosValue *substitutions_value = p_arguments[8].get();\n\t\n\t// TIMING RESTRICTION\n\tif (!community_.warned_early_output_)\n\t{\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Species::ExecuteMethod_outputFull): outputFull() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity_.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tbool use_binary = binary_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_spatial_positions = spatialPositions_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_ages = ages_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_ancestral_nucs = ancestralNucleotides_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_pedigree_ids = pedigreeIDs_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_object_tags = objectTags_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool output_substitutions = substitutions_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (output_pedigree_ids && !PedigreesEnabledByUser())\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputFull): outputFull() cannot output pedigree IDs, because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\n\t// BCH 3/6/2022: Note that in SLiM 4 we now output the species cycle after the tick.  This breaks backward compatibility\n\t// for code that parses the output from outputFull(), but in a minor way.  It is necessary so that we can round-trip a model\n\t// with outputFull()/readFromPopulationFile(); that needs to restore the species cycle.  The cycle is also added to\n\t// the other text output formats, except those on Haplosome (where the haplosomes might come from multiple species).\n\t\n\tif (filePath_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tif (use_binary)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputFull): outputFull() cannot output in binary format to the standard output stream; specify a file for output.\" << EidosTerminate();\n\t\t\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\tIndividual::PrintIndividuals_SLiM(output_stream, nullptr, 0, *this, output_spatial_positions, output_ages, output_ancestral_nucs, output_pedigree_ids, output_object_tags, output_substitutions, /* p_focal_chromosome */ nullptr);\n\t}\n\telse\n\t{\n\t\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\tstd::ofstream outfile;\n\t\t\n\t\tif (use_binary && append)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputFull): outputFull() cannot append in binary format.\" << EidosTerminate();\n\t\t\n\t\tif (use_binary)\n\t\t\toutfile.open(outfile_path.c_str(), std::ios::out | std::ios::binary);\n\t\telse\n\t\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\t\n\t\tif (outfile.is_open())\n\t\t{\n\t\t\tif (use_binary)\n\t\t\t{\n\t\t\t\tpopulation_.PrintAllBinary(outfile, output_spatial_positions, output_ages, output_ancestral_nucs, output_pedigree_ids, output_object_tags, output_substitutions);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tIndividual::PrintIndividuals_SLiM(outfile, nullptr, 0, *this, output_spatial_positions, output_ages, output_ancestral_nucs, output_pedigree_ids, output_object_tags, output_substitutions, /* p_focal_chromosome */ nullptr);\n\t\t\t}\n\t\t\t\n\t\t\toutfile.close(); \n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputFull): outputFull() could not open \"<< outfile_path << \".\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\t\t\t\n//\t*********************\t– (void)outputMutations(object<Mutation> mutations, [Ns$ filePath = NULL], [logical$ append=F], [logical$ objectTags=F])\n//\nEidosValue_SP Species::ExecuteMethod_outputMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutations_value = p_arguments[0].get();\n\tEidosValue *filePath_value = p_arguments[1].get();\n\tEidosValue *append_value = p_arguments[2].get();\n\tEidosValue *objectTags_value = p_arguments[3].get();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// TIMING RESTRICTION\n\tif (!community_.warned_early_output_)\n\t{\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Species::ExecuteMethod_outputMutations): outputMutations() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity_.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tstd::ofstream outfile;\n\tbool has_file = false;\n\t\n\tif (filePath_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\thas_file = true;\n\t\t\n\t\tif (!outfile.is_open())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputMutations): outputMutations() could not open \"<< outfile_path << \".\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t}\n\t\n\tstd::ostream &out = *(has_file ? (std::ostream *)&outfile : (std::ostream *)&output_stream);\n\t\n\tint mutations_count = mutations_value->Count();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tif (mutations_count > 0)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tSpecies *mutations_species = Community::SpeciesForMutations(mutations_value);\n\t\t\n\t\tif (mutations_species != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_outputMutations): outputMutations() requires that all mutations belong to the target species.\" << EidosTerminate();\n\t\t\n\t\t// as we scan through haplosomes building the polymorphism map, we want to process only mutations that are\n\t\t// in the user-supplied mutations vector; to do that filtering efficiently, we use Mutation::scratch_\n\t\t// first zero out scratch_ in all mutations in the registry...\n\t\tint registry_size;\n\t\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\t\t\n\t\tfor (int registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\tmut->scratch_ = 0;\n\t\t}\n\t\t\n\t\t// ...then set scratch_ = 1 for all mutations that have been requested for output\n\t\tEidosValue_Object *mutations_object = (EidosValue_Object *)mutations_value;\n\t\t\n\t\tfor (int mut_index = 0; mut_index < mutations_count; mut_index++)\n\t\t{\n\t\t\tMutation *mut = (Mutation *)(mutations_object->ObjectElementAtIndex_NOCAST(mut_index, nullptr));\n\t\t\tmut->scratch_ = 1;\n\t\t}\n\t\t\n\t\t// find all polymorphisms of the mutations that are to be tracked\n\t\tfor (const std::pair<const slim_objectid_t,Subpopulation*> &subpop_pair : population_.subpops_)\n\t\t{\n\t\t\tSubpopulation *subpop = subpop_pair.second;\n\t\t\tPolymorphismMap polymorphisms;\n\t\t\t\n\t\t\tfor (Individual *ind : subpop->parent_individuals_)\n\t\t\t{\n\t\t\t\tint haplosome_count_per_individual = HaplosomeCountPerIndividual();\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = ind->haplosomes_[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tint mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\t\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\tint mut_count = mutrun->size();\n\t\t\t\t\t\tconst MutationIndex *mut_ptr = mutrun->begin_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int mut_index = 0; mut_index < mut_count; ++mut_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *scan_mutation = mut_block_ptr + mut_ptr[mut_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// use scratch_ to check whether the mutation is one we are outputting\n\t\t\t\t\t\t\tif (scan_mutation->scratch_)\n\t\t\t\t\t\t\t\tAddMutationToPolymorphismMap(&polymorphisms, scan_mutation);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// output the frequencies of these mutations in each subpopulation; note the format here comes from the old tracked mutations code\n\t\t\t// NOTE the format of this output changed because print_no_id() added the mutation_id_ to its output; BCH 11 June 2016\n\t\t\t// BCH 3/6/2022: Note that the cycle was added after the tick in SLiM 4.\n\t\t\tbool output_object_tags = objectTags_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tfor (const PolymorphismPair &polymorphism_pair : polymorphisms) \n\t\t\t{\n\t\t\t\tout << \"#OUT: \" << community_.Tick() << \" \" << Cycle() << \" T p\" << subpop_pair.first << \" \";\n\t\t\t\t\n\t\t\t\tif (output_object_tags)\n\t\t\t\t\tpolymorphism_pair.second.Print_NoID_Tag(out);\n\t\t\t\telse\n\t\t\t\t\tpolymorphism_pair.second.Print_NoID(out);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (has_file)\n\t\toutfile.close(); \n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (integer$)readFromPopulationFile(string$ filePath, [No<Dictionary>$ subpopMap = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_readFromPopulationFile(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\t// readFromPopulationFile() is strictly limited to first()/early()/late() events; it cannot be called\n\t// from other contexts even for a different species than executing_species_.  This is because\n\t// it can have the side effect of running mutationEffect() callbacks, and those cannot nest inside\n\t// the execution of a different species.\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): readFromPopulationFile() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) &&\n\t\t(community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) &&\n\t\t(community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): readFromPopulationFile() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tif (!community_.warned_early_read_)\n\t{\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts) ||\n\t\t\t(community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Species::ExecuteMethod_readFromPopulationFile): readFromPopulationFile() should probably not be called from a first() or early() event in a WF model; fitness values will not be recalculated prior to generating offspring unless recalculateFitness() is called.\" << std::endl;\n\t\t\t\tcommunity_.warned_early_read_ = true;\n\t\t\t}\n\t\t}\n\t\t// Note that there is no equivalent problem in nonWF models, because fitness values are used for survival,\n\t\t// not reproduction, and there is no event stage in the tick cycle that splits fitness from survival.\n\t}\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string file_path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(filePath_value->StringAtIndex_NOCAST(0, nullptr)));\n\t\n\tEidosValue *subpopMap_value = p_arguments[1].get();\n\tSUBPOP_REMAP_HASH subpopRemap;\n\t\n\tif (subpopMap_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tEidosDictionaryUnretained *subpopMap_dict = (EidosDictionaryUnretained *)subpopMap_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (!subpopMap_dict->KeysAreStrings())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): subpopMap must use strings for its keys; integer keys are not presently supported.\" << EidosTerminate();\n\t\t\n\t\tconst EidosDictionaryHashTable_StringKeys *subpopMap_hash = subpopMap_dict->DictionarySymbols_StringKeys();\n\t\t\n\t\tfor (auto &subpopMap_pair : *subpopMap_hash)\n\t\t{\n\t\t\tstd::string slim_id_string = subpopMap_pair.first;\n\t\t\tslim_objectid_t slim_id = SLiMEidosScript::ExtractIDFromStringWithPrefix(slim_id_string, 'p', nullptr);\n\t\t\tEidosValue *table_id_value = subpopMap_pair.second.get();\n\t\t\t\n\t\t\tif ((table_id_value->Type() != EidosValueType::kValueInt) || (table_id_value->Count() != 1))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): subpopMap values must be singleton integers.\" << EidosTerminate();\n\t\t\t\n\t\t\tint64_t table_id = table_id_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((table_id < 0) || (table_id > SLIM_MAX_ID_VALUE))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): subpopMap value (\" << table_id << \") is out of range.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (subpopRemap.find(table_id) != subpopRemap.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_readFromPopulationFile): subpopMap value (\" << table_id << \") is not unique; more than one subpopulation id is mapped from it.\" << EidosTerminate();\n\t\t\t\n\t\t\tsubpopRemap.emplace(std::pair<int64_t, slim_objectid_t>(table_id, slim_id));\n\t\t}\n\t}\n\t\n\tslim_tick_t file_tick = InitializePopulationFromFile(file_path, &p_interpreter, subpopRemap);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(file_tick));\n}\n\t\t\t\n//\t*********************\t– (void)recalculateFitness([Ni$ tick = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_recalculateFitness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\t// recalculateFitness() is strictly limited to first()/early()/late() events; it cannot be called\n\t// from other contexts even for a different species than executing_species_.  This is because\n\t// it can have the side effect of running mutationEffect() callbacks, and those cannot nest inside\n\t// the execution of a different species.\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_recalculateFitness): recalculateFitness() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_recalculateFitness): recalculateFitness() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tEidosValue *tick_value = p_arguments[0].get();\n\t\n\t// Trigger a fitness recalculation.  This is suggested after making a change that would modify fitness values, such as altering\n\t// a selection coefficient or dominance coefficient, changing the mutation type for a mutation, etc.  It will have the side\n\t// effect of calling mutationEffect() callbacks, so this is quite a heavyweight operation.\n\tslim_tick_t tick = (tick_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(tick_value->IntAtIndex_NOCAST(0, nullptr)) : community_.Tick();\n\t\n\tpopulation_.RecalculateFitness(tick);\n\t\n\t// Remember that we have recalculated fitness values; this unlocks the ability to call cachedFitness(), temporarily\n\thas_recalculated_fitness_ = true;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerFitnessEffectCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_registerFitnessEffectCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *subpop_value = p_arguments[2].get();\n\tEidosValue *start_value = p_arguments[3].get();\n\tEidosValue *end_value = p_arguments[4].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if id_value is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t subpop_id = -1;\t\t// used if subpop_value is NULL, to indicate applicability to all subpops\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerFitnessEffectCallback): registerFitnessEffectCallback() requires start <= end.\" << EidosTerminate();\n\t\n\tcommunity_.CheckScheduling(start_tick, (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage6CalculateFitness : SLiMCycleStage::kNonWFStage3CalculateFitness);\n\t\n\tSLiMEidosBlockType block_type = SLiMEidosBlockType::SLiMEidosFitnessEffectCallback;\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, block_type, start_tick, end_tick, this, nullptr);\n\t\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tcommunity_.AddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerMateChoiceCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\t*********************\t– (object<SLiMEidosBlock>$)registerModifyChildCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\t*********************\t– (object<SLiMEidosBlock>$)registerRecombinationCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Niso<Chromosome>$ chromosome = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\t*********************\t– (object<SLiMEidosBlock>$)registerSurvivalCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_registerMateModifyRecSurvCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (p_method_id == gID_registerMateChoiceCallback)\n\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMateModifyRecSurvCallback): registerMateChoiceCallback() is not available in nonWF models.\" << EidosTerminate();\n\tif (p_method_id == gID_registerSurvivalCallback)\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMateModifyRecSurvCallback): registerSurvivalCallback() is not available in WF models.\" << EidosTerminate();\n\t\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *subpop_value = p_arguments[2].get();\n\tEidosValue *start_value = p_arguments[(p_method_id == gID_registerRecombinationCallback) ? 4 : 3].get();\n\tEidosValue *end_value = p_arguments[(p_method_id == gID_registerRecombinationCallback) ? 5 : 4].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if the id is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t subpop_id = -1;\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMateModifyRecSurvCallback): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requires start <= end.\" << EidosTerminate();\n\t\n\tSLiMEidosBlockType block_type;\n\t\n\tif (p_method_id == gID_registerMateChoiceCallback)\t\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosMateChoiceCallback;\n\telse if (p_method_id == gID_registerModifyChildCallback)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosModifyChildCallback;\n\telse if (p_method_id == gID_registerRecombinationCallback)\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosRecombinationCallback;\n\telse if (p_method_id == gID_registerSurvivalCallback)\t\t\t\tblock_type = SLiMEidosBlockType::SLiMEidosSurvivalCallback;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMateModifyRecSurvCallback): (internal error) unrecognized callback type.\" << EidosTerminate();\n\t\n\tcommunity_.CheckScheduling(start_tick, (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage2GenerateOffspring : SLiMCycleStage::kNonWFStage1GenerateOffspring);\n\t\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, block_type, start_tick, end_tick, this, nullptr);\n\t\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\t\n\t// Get the focal chromosome, for recombination() callbacks\n\tif (p_method_id == gID_registerRecombinationCallback)\n\t{\n\t\tEidosValue *chromosome_value = p_arguments[3].get();\n\t\tChromosome *chromosome = GetChromosomeFromEidosValue(chromosome_value);\t// returns nullptr for NULL\n\t\t\n\t\tif (chromosome)\n\t\t\tnew_script_block->chromosome_id_ = chromosome->ID();\n\t}\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tcommunity_.AddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerMutationCallback(Nis$ id, string$ source, [Nio<MutationType>$ mutType = NULL], [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_registerMutationCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *mutType_value = p_arguments[2].get();\n\tEidosValue *subpop_value = p_arguments[3].get();\n\tEidosValue *start_value = p_arguments[4].get();\n\tEidosValue *end_value = p_arguments[5].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if id_value is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t mut_type_id = -1;\t// used if mutType_value is NULL, to indicate applicability to all mutation types\n\tslim_objectid_t subpop_id = -1;\t\t// used if subpop_value is NULL, to indicate applicability to all subpops\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tif (mutType_value->Type() != EidosValueType::kValueNULL)\n\t\tmut_type_id = (mutType_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(mutType_value->IntAtIndex_NOCAST(0, nullptr)) : ((MutationType *)mutType_value->ObjectElementAtIndex_NOCAST(0, nullptr))->mutation_type_id_;\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMutationCallback): registerMutationCallback() requires start <= end.\" << EidosTerminate();\n\t\n\tcommunity_.CheckScheduling(start_tick, (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage2GenerateOffspring : SLiMCycleStage::kNonWFStage1GenerateOffspring);\n\t\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, SLiMEidosBlockType::SLiMEidosMutationCallback, start_tick, end_tick, this, nullptr);\n\t\n\tnew_script_block->mutation_type_id_ = mut_type_id;\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tcommunity_.AddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerMutationEffectCallback(Nis$ id, string$ source, io<MutationType>$ mutType, [Nio<Subpopulation>$ subpop = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_registerMutationEffectCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *mutType_value = p_arguments[2].get();\n\tEidosValue *subpop_value = p_arguments[3].get();\n\tEidosValue *start_value = p_arguments[4].get();\n\tEidosValue *end_value = p_arguments[5].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if id_value is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t mut_type_id = -1;\n\tslim_objectid_t subpop_id = -1;\t\t// used if subpop_value is NULL, to indicate applicability to all subpops\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tmut_type_id = (mutType_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(mutType_value->IntAtIndex_NOCAST(0, nullptr)) : ((MutationType *)mutType_value->ObjectElementAtIndex_NOCAST(0, nullptr))->mutation_type_id_;\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerMutationEffectCallback): registerMutationEffectCallback() requires start <= end.\" << EidosTerminate();\n\t\n\tcommunity_.CheckScheduling(start_tick, (model_type_ == SLiMModelType::kModelTypeWF) ? SLiMCycleStage::kWFStage6CalculateFitness : SLiMCycleStage::kNonWFStage3CalculateFitness);\n\t\n\tSLiMEidosBlockType block_type = SLiMEidosBlockType::SLiMEidosMutationEffectCallback;\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, block_type, start_tick, end_tick, this, nullptr);\n\t\n\tnew_script_block->mutation_type_id_ = mut_type_id;\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tcommunity_.AddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t– (object<SLiMEidosBlock>$)registerReproductionCallback(Nis$ id, string$ source, [Nio<Subpopulation>$ subpop = NULL], [Ns$ sex = NULL], [Ni$ start = NULL], [Ni$ end = NULL])\n//\nEidosValue_SP Species::ExecuteMethod_registerReproductionCallback(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerReproductionCallback): registerReproductionCallback() is not available in WF models.\" << EidosTerminate();\n\t\n\tEidosValue *id_value = p_arguments[0].get();\n\tEidosValue *source_value = p_arguments[1].get();\n\tEidosValue *subpop_value = p_arguments[2].get();\n\tEidosValue *sex_value = p_arguments[3].get();\n\tEidosValue *start_value = p_arguments[4].get();\n\tEidosValue *end_value = p_arguments[5].get();\n\t\n\tslim_objectid_t script_id = -1;\t\t// used if the id is NULL, to indicate an anonymous block\n\tstd::string script_string = source_value->StringAtIndex_NOCAST(0, nullptr);\n\tslim_objectid_t subpop_id = -1;\n\tIndividualSex sex_specificity = IndividualSex::kUnspecified;\n\tslim_tick_t start_tick = ((start_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(start_value->IntAtIndex_NOCAST(0, nullptr)) : 1);\n\tslim_tick_t end_tick = ((end_value->Type() != EidosValueType::kValueNULL) ? SLiMCastToTickTypeOrRaise(end_value->IntAtIndex_NOCAST(0, nullptr)) : SLIM_MAX_TICK + 1);\n\t\n\tif (id_value->Type() != EidosValueType::kValueNULL)\n\t\tscript_id = SLiM_ExtractObjectIDFromEidosValue_is(id_value, 0, 's');\n\t\n\tif (subpop_value->Type() != EidosValueType::kValueNULL)\n\t\tsubpop_id = (subpop_value->Type() == EidosValueType::kValueInt) ? SLiMCastToObjectidTypeOrRaise(subpop_value->IntAtIndex_NOCAST(0, nullptr)) : ((Subpopulation *)subpop_value->ObjectElementAtIndex_NOCAST(0, nullptr))->subpopulation_id_;\n\t\n\tif (sex_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tstd::string sex_string = sex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (sex_string == \"M\")\t\t\tsex_specificity = IndividualSex::kMale;\n\t\telse if (sex_string == \"F\")\t\tsex_specificity = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerReproductionCallback): registerReproductionCallback() requires sex to be 'M', 'F', or NULL.\" << EidosTerminate();\n\t\t\n\t\tif (!SexEnabled())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerReproductionCallback): registerReproductionCallback() requires sex to be NULL in non-sexual models.\" << EidosTerminate();\n\t}\n\t\n\tif (start_tick > end_tick)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_registerReproductionCallback): registerReproductionCallback() requires start <= end.\" << EidosTerminate();\n\t\n\tcommunity_.CheckScheduling(start_tick, SLiMCycleStage::kNonWFStage1GenerateOffspring);\n\t\n\tSLiMEidosBlockType block_type = SLiMEidosBlockType::SLiMEidosReproductionCallback;\n\tSLiMEidosBlock *new_script_block = new SLiMEidosBlock(script_id, script_string, block_type, start_tick, end_tick, this, nullptr);\n\t\n\tnew_script_block->subpopulation_id_ = subpop_id;\n\tnew_script_block->sex_specificity_ = sex_specificity;\n\t\n\t// SPECIES CONSISTENCY CHECK (done by AddScriptBlock())\n\tcommunity_.AddScriptBlock(new_script_block, &p_interpreter, nullptr);\t\t// takes ownership from us\n\t\n\treturn new_script_block->SelfSymbolTableEntry().second;\n}\n\n//\t*********************\t- (void)simulationFinished(void)\n//\nEidosValue_SP Species::ExecuteMethod_simulationFinished(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tif (community_.AllSpecies().size() != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_simulationFinished): simulationFinished() may only be called on Species in single-species models; this is supported for backward compatibility.  In multispecies models, call community.simulationFinished() instead.\" << EidosTerminate();\n\t\n\t// Call through to our community to forward the message; note this means we must have an identical signature!\n\tcommunity_.ExecuteMethod_simulationFinished(p_method_id, p_arguments, p_interpreter);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)skipTick(void)\n//\nEidosValue_SP Species::ExecuteMethod_skipTick(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_skipTick): skipTick() may only be called from a first() event; skipping ticks should be arranged before any portion of the cycle has occurred.\" << EidosTerminate();\n\t\n\tif (species_active_)\n\t{\n#ifdef SLIMGUI\n\t\tgSLiMScheduling << \"\\t\\tspecies \" << name_ << \" DEACTIVATED by skipTick()\" << std::endl;\n#endif\n\t\t\n\t\tspecies_active_ = false;\n\t\t\n\t\t// deactivate all script blocks that have a \"species\" or \"ticks\" specifier in their declaration that refers to this species\n\t\tstd::vector<SLiMEidosBlock*> &script_blocks = community_.AllScriptBlocks();\n\t\t\n\t\tfor (SLiMEidosBlock *block : script_blocks)\n\t\t\tif ((block->species_spec_ && (block->species_spec_ == this)) || (block->ticks_spec_ && (block->ticks_spec_ == this)))\n\t\t\t\tblock->block_active_ = 0;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (object<Mutation>)subsetMutations([No<Mutation>$ exclude = NULL], [Nio<MutationType>$ mutationType = NULL], [Ni$ position = NULL], [Nis$ nucleotide = NULL], [Ni$ tag = NULL], [Ni$ id = NULL], [Niso<Chromosome> chromosome])\n//\nEidosValue_SP Species::ExecuteMethod_subsetMutations(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *exclude_value = p_arguments[0].get();\n\tEidosValue *mutType_value = p_arguments[1].get();\n\tEidosValue *position_value = p_arguments[2].get();\n\tEidosValue *nucleotide_value = p_arguments[3].get();\n\tEidosValue *tag_value = p_arguments[4].get();\n\tEidosValue *id_value = p_arguments[5].get();\n\tEidosValue *chromosome_value = p_arguments[6].get();\n\t\n\t// parse our arguments\n\tMutation *exclude = (exclude_value->Type() == EidosValueType::kValueNULL) ? nullptr : (Mutation *)exclude_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tMutationType *mutation_type_ptr = (mutType_value->Type() == EidosValueType::kValueNULL) ? nullptr : SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &community_, this, \"subsetMutations()\");\t// SPECIES CONSISTENCY CHECK\n\tslim_position_t position = (position_value->Type() == EidosValueType::kValueNULL) ? -1 : SLiMCastToPositionTypeOrRaise(position_value->IntAtIndex_NOCAST(0, nullptr));\n\tint8_t nucleotide = -1;\n\tbool has_tag = !(tag_value->Type() == EidosValueType::kValueNULL);\n\tslim_usertag_t tag = (has_tag ? tag_value->IntAtIndex_NOCAST(0, nullptr) : 0);\n\tbool has_id = !(id_value->Type() == EidosValueType::kValueNULL);\n\tslim_mutationid_t id = (has_id ? id_value->IntAtIndex_NOCAST(0, nullptr) : 0);\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (exclude && (&exclude->mutation_type_ptr_->species_ != this))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_subsetMutations): subsetMutations() requires that exclude belong to the target species.\" << EidosTerminate();\n\t\n\t// Mark chromosomes that are a match; we set up a vector of chars by chromosome index, for lookup\n\tstd::vector<char> chromosome_index_included(chromosomes_.size(), false);\n\tbool has_chromosome = !(chromosome_value->Type() == EidosValueType::kValueNULL);\n\t\n\tif (has_chromosome)\t\t// NULL case handled above\n\t{\n\t\tstd::vector<slim_chromosome_index_t> chromosome_indices;\n\t\tGetChromosomeIndicesFromEidosValue(chromosome_indices, chromosome_value);\n\t\t\n\t\tfor (slim_chromosome_index_t chromosome_index : chromosome_indices)\n\t\t\tchromosome_index_included[chromosome_index] = true;\n\t}\n\t\n\tif (nucleotide_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tint64_t nuc_int = nucleotide_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((nuc_int < 0) || (nuc_int > 3))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_subsetMutations): subsetMutations() requires integer nucleotide values to be in [0,3].\" << EidosTerminate();\n\t\t\n\t\tnucleotide = (int8_t)nuc_int;\n\t}\n\telse if (nucleotide_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &nuc_string = ((EidosValue_String *)nucleotide_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (nuc_string == \"A\")\t\tnucleotide = 0;\n\t\telse if (nuc_string == \"C\")\tnucleotide = 1;\n\t\telse if (nuc_string == \"G\")\tnucleotide = 2;\n\t\telse if (nuc_string == \"T\")\tnucleotide = 3;\n\t\telse EIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_subsetMutations): subsetMutations() requires string nucleotide values to be 'A', 'C', 'G', or 'T'.\" << EidosTerminate();\n\t}\n\t\n\t// We will scan forward looking for a match, and will keep track of the first match we find.  If we only find one, we return\n\t// a singleton; if we find a second, we will start accumulating a vector result.\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\tint registry_size;\n\tconst MutationIndex *registry = population_.MutationRegistry(&registry_size);\n\tint match_count = 0, registry_index;\n\tMutation *first_match = nullptr;\n\tEidosValue_Object *vec = nullptr;\n\t\n\tif (has_id && !exclude && !mutation_type_ptr && (position == -1) && (nucleotide == -1) && !has_tag && !has_chromosome)\n\t{\n\t\t// id-only search; nice for this to be fast since people will use it to look up a specific mutation\n\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tif (mut->mutation_id_ != id)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tmatch_count++;\n\t\t\t\n\t\t\tif (match_count == 1)\n\t\t\t{\n\t\t\t\tfirst_match = mut;\n\t\t\t}\n\t\t\telse if (match_count == 2)\n\t\t\t{\n\t\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\t\tvec->push_object_element_RR(first_match);\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t}\n\t}\n\telse if (has_chromosome && !exclude && !mutation_type_ptr && (position == -1) && (nucleotide == -1) && !has_tag && !has_id)\n\t{\n\t\t// chromosome-only search; nice for this to be fast since people will use it to look up all the mutations for a chromosome\n\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tif (!chromosome_index_included[mut->chromosome_index_])\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tmatch_count++;\n\t\t\t\n\t\t\tif (match_count == 1)\n\t\t\t{\n\t\t\t\tfirst_match = mut;\n\t\t\t}\n\t\t\telse if (match_count == 2)\n\t\t\t{\n\t\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\t\tvec->push_object_element_RR(first_match);\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t}\n\t}\n\telse if (!exclude && !has_tag && !has_id)\n\t{\n\t\t// no exclude, tag, or id; this is expected to be the common case, for the usage patterns I anticipate\n\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tif (mutation_type_ptr && (mut->mutation_type_ptr_ != mutation_type_ptr))\tcontinue;\n\t\t\tif ((position != -1) && (mut->position_ != position))\t\t\t\t\t\tcontinue;\n\t\t\tif ((nucleotide != -1) && (mut->nucleotide_ != nucleotide))\t\t\t\t\tcontinue;\n\t\t\tif (has_chromosome && !chromosome_index_included[mut->chromosome_index_])\tcontinue;\n\t\t\t\n\t\t\tmatch_count++;\n\t\t\t\n\t\t\tif (match_count == 1)\n\t\t\t{\n\t\t\t\tfirst_match = mut;\n\t\t\t}\n\t\t\telse if (match_count == 2)\n\t\t\t{\n\t\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\t\tvec->push_object_element_RR(first_match);\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// GENERAL CASE\n\t\tfor (registry_index = 0; registry_index < registry_size; ++registry_index)\n\t\t{\n\t\t\tMutation *mut = mut_block_ptr + registry[registry_index];\n\t\t\t\n\t\t\tif (exclude && (mut == exclude))\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\tif (mutation_type_ptr && (mut->mutation_type_ptr_ != mutation_type_ptr))\tcontinue;\n\t\t\tif ((position != -1) && (mut->position_ != position))\t\t\t\t\t\tcontinue;\n\t\t\tif ((nucleotide != -1) && (mut->nucleotide_ != nucleotide))\t\t\t\t\tcontinue;\n\t\t\tif (has_tag && (mut->tag_value_ != tag))\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\tif (has_id && (mut->mutation_id_ != id))\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\tif (has_chromosome && !chromosome_index_included[mut->chromosome_index_])\tcontinue;\n\t\t\t\n\t\t\tmatch_count++;\n\t\t\t\n\t\t\tif (match_count == 1)\n\t\t\t{\n\t\t\t\tfirst_match = mut;\n\t\t\t}\n\t\t\telse if (match_count == 2)\n\t\t\t{\n\t\t\t\tvec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\t\t\t\tvec->push_object_element_RR(first_match);\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvec->push_object_element_RR(mut);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (match_count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Mutation_Class));\n\telse if (match_count == 1)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(first_match, gSLiM_Mutation_Class));\n\telse\n\t\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t- (object<Substitution>)substitutionsOfType(io<MutationType>$ mutType)\n//\nEidosValue_SP Species::ExecuteMethod_substitutionsOfType(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *mutType_value = p_arguments[0].get();\n\t\n\tMutationType *mutation_type_ptr = SLiM_ExtractMutationTypeFromEidosValue_io(mutType_value, 0, &community_, this, \"mutationsOfType()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Substitution_Class));\n\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\n\tstd::vector<Substitution*> &substitutions = population_.substitutions_;\n\tint substitution_count = (int)substitutions.size();\n\n\tfor (int sub_index = 0; sub_index < substitution_count; ++sub_index)\n\t{\n\t\tSubstitution *sub = substitutions[sub_index];\n\t\t\n\t\tif (sub->mutation_type_ptr_ == mutation_type_ptr)\n\t\t\tvec->push_object_element_RR(sub);\n\t}\n\t\n\treturn result_SP;\n}\n\n// TREE SEQUENCE RECORDING\n//\t*********************\t- (logical$)treeSeqCoalesced(void)\n//\nEidosValue_SP Species::ExecuteMethod_treeSeqCoalesced(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqCoalesced): treeSeqCoalesced() may only be called when tree recording is enabled.\" << EidosTerminate();\n\tif (!running_coalescence_checks_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqCoalesced): treeSeqCoalesced() may only be called when coalescence checking is enabled; pass checkCoalescence=T to initializeTreeSeq() to enable this feature.\" << EidosTerminate();\n\t\n\t// This method now checks for *all* of the tree sequences being coalesced.  It could be extended to\n\t// take a [Niso<Chromosome>$ chromosome = NULL] parameter, to allow one chromosome to be checked.\n\tfor (const TreeSeqInfo &tsinfo : treeseq_)\n\t\tif (tsinfo.last_coalescence_state_ == false)\n\t\t\treturn gStaticEidosValue_LogicalF;\n\t\n\treturn gStaticEidosValue_LogicalT;\n}\n\n// TREE SEQUENCE RECORDING\n//\t*********************\t- (void)treeSeqSimplify(void)\n//\nEidosValue_SP Species::ExecuteMethod_treeSeqSimplify(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqSimplify): treeSeqSimplify() may only be called when tree recording is enabled.\" << EidosTerminate();\n\t\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqSimplify): treeSeqSimplify() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqSimplify): treeSeqSimplify() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tSimplifyAllTreeSequences();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// TREE SEQUENCE RECORDING\n//\t*********************\t- (void)treeSeqRememberIndividuals(object<Individual> individuals, [logical$ permanent = T])\n//\nEidosValue_SP Species::ExecuteMethod_treeSeqRememberIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue_Object *individuals_value = (EidosValue_Object *)p_arguments[0].get();\n    EidosValue *permanent_value = p_arguments[1].get();\n\tint ind_count = individuals_value->Count();\n\t\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqRememberIndividuals): treeSeqRememberIndividuals() may only be called when tree recording is enabled.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\t// BCH 14 November 2018: removed a block on calling treeSeqRememberIndividuals() from mutationEffect() callbacks,\n\t// because it turns out that can be useful (see correspondence with Yan Wong)\n\t// BCH 30 April 2019: also allowing mutation() callbacks, since I can see how that could be useful...\n\tif (community_.executing_species_ == this)\n\t\tif ((community_.executing_block_type_ == SLiMEidosBlockType::SLiMEidosMateChoiceCallback) || (community_.executing_block_type_ == SLiMEidosBlockType::SLiMEidosModifyChildCallback) || (community_.executing_block_type_ == SLiMEidosBlockType::SLiMEidosRecombinationCallback))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqRememberIndividuals): treeSeqRememberIndividuals() may not be called from inside a mateChoice(), modifyChild(), or recombination() callback for the currently executing species.\" << EidosTerminate();\n\t\n\tbool permanent = permanent_value->LogicalAtIndex_NOCAST(0, nullptr); \n\tuint32_t flag = permanent ? SLIM_TSK_INDIVIDUAL_REMEMBERED : SLIM_TSK_INDIVIDUAL_RETAINED;\n\t\n\tif (ind_count == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(individuals_value);\n\t\n\tif (species != this)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqRememberIndividuals): treeSeqRememberIndividuals() requires that all individuals belong to the target species.\" << EidosTerminate();\n\t\n\t// This method remembers the given individuals once, in the shared individuals table kept by treeseq_[0]\n\tEidosObject * const *oe_buffer = individuals_value->ObjectData();\n\tIndividual * const *ind_buffer = (Individual * const *)oe_buffer;\n\t\n\tAddIndividualsToTable(ind_buffer, ind_count, &treeseq_[0].tables_, &tabled_individuals_hash_, flag);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// TREE SEQUENCE RECORDING\n//\t*********************\t- (void)treeSeqOutput(string$ path, [logical$ simplify = T], [logical$ includeModel = T], [No<Dictionary>$ metadata = NULL], [logical$ overwriteDirectory = F])\n//\nEidosValue_SP Species::ExecuteMethod_treeSeqOutput(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *path_value = p_arguments[0].get();\n\tEidosValue *simplify_value = p_arguments[1].get();\n\tEidosValue *includeModel_value = p_arguments[2].get();\n\tEidosValue *metadata_value = p_arguments[3].get();\n\tEidosValue *overwriteDirectory_value = p_arguments[4].get();\n\t\n\tif (!recording_tree_)\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqOutput): treeSeqOutput() may only be called when tree recording is enabled.\" << EidosTerminate();\n\t\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqOutput): treeSeqOutput() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) &&\n\t\t(community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) &&\n\t\t(community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_treeSeqOutput): treeSeqOutput() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tstd::string path_string = path_value->StringAtIndex_NOCAST(0, nullptr);\n\tbool simplify = simplify_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tEidosDictionaryUnretained *metadata_dict = nullptr;\n\tbool includeModel = includeModel_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool overwriteDirectory = overwriteDirectory_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (metadata_value->Type() == EidosValueType::kValueObject)\n\t\tmetadata_dict = (EidosDictionaryUnretained *)metadata_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tWriteTreeSequence(path_string, simplify, includeModel, metadata_dict, overwriteDirectory);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)_debug(void)\n//\nEidosValue_SP Species::ExecuteMethod__debug(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// This method is a debugging hook to make it easier to do things on demand during a debugging session.\n\t// It is not user-visible (e.g., with the methods() method) since it starts with an underscore.\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\t//std::unordered_map<slim_objectid_t, std::string> used_subpop_ids_;\n\t//std::unordered_set<std::string> used_subpop_names_;\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\toutput_stream << \"used_subpop_ids_: \" << std::endl;\n\tfor (const auto &element : used_subpop_ids_)\n\t\toutput_stream << \"   \" << element.first << \" : \" << element.second << std::endl;\n\t\n\toutput_stream << \"used_subpop_names_: \" << std::endl;\n\tfor (const auto &element : used_subpop_names_)\n\t\toutput_stream << \"   \" << element << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tSpecies_Class\n//\n#pragma mark -\n#pragma mark Species_Class\n#pragma mark -\n\nEidosClass *gSLiM_Species_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Species_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Species_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_avatar,\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosome,\t\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosomes,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_color,\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_description,\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_dimensionality,\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_periodicity,\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_genomicElementTypes,\ttrue,\tkEidosValueMaskObject, gSLiM_GenomicElementType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutations,\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Mutation_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationTypes,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_MutationType_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_name,\t\t\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotideBased,\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_scriptBlocks,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_SLiMEidosBlock_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_sexChromosomes,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_sexEnabled,\t\t\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_subpopulations,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Subpopulation_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_substitutions,\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Substitution_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_cycle,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Species_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Species_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPatternForClone, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class)->AddArg(kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, \"pattern\", gEidosDictionaryUnretained_Class)->AddObject_S(\"parent\", gSLiM_Individual_Class)->AddString_OSN(\"sex\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPatternForCross, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class)->AddArg(kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, \"pattern\", gEidosDictionaryUnretained_Class)->AddObject_S(\"parent1\", gSLiM_Individual_Class)->AddObject_S(\"parent2\", gSLiM_Individual_Class)->AddString_OSN(\"sex\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPatternForNull, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class)->AddArg(kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, \"pattern\", gEidosDictionaryUnretained_Class)->AddString_OSN(\"sex\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addPatternForRecombinant, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class)->AddArg(kEidosValueMaskNULL | kEidosValueMaskObject | kEidosValueMaskSingleton, \"pattern\", gEidosDictionaryUnretained_Class)->AddObject_SN(gStr_strand1, gSLiM_Haplosome_Class)->AddObject_SN(gStr_strand2, gSLiM_Haplosome_Class)->AddInt_N(gStr_breaks1)->AddObject_SN(gStr_strand3, gSLiM_Haplosome_Class)->AddObject_SN(gStr_strand4, gSLiM_Haplosome_Class)->AddInt_N(gStr_breaks2)->AddString_OSN(\"sex\", gStaticEidosValueNULL)->AddLogical_OS(\"randomizeStrands\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSubpop, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Subpopulation_Class))->AddIntString_S(\"subpopID\")->AddInt_S(\"size\")->AddFloat_OS(\"sexRatio\", gStaticEidosValue_Float0Point5)->AddLogical_OS(\"haploid\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSubpopSplit, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Subpopulation_Class))->AddIntString_S(\"subpopID\")->AddInt_S(\"size\")->AddIntObject_S(\"sourceSubpop\", gSLiM_Subpopulation_Class)->AddFloat_OS(\"sexRatio\", gStaticEidosValue_Float0Point5));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_chromosomesOfType, kEidosValueMaskObject, gSLiM_Chromosome_Class))->AddString_S(\"type\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_chromosomesWithIDs, kEidosValueMaskObject, gSLiM_Chromosome_Class))->AddInt(\"ids\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_chromosomesWithSymbols, kEidosValueMaskObject, gSLiM_Chromosome_Class))->AddString(\"symbols\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_countOfMutationsOfType, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_individualsWithPedigreeIDs, kEidosValueMaskObject, gSLiM_Individual_Class))->AddInt(\"pedigreeIDs\")->AddIntObject_ON(\"subpops\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_killIndividuals, kEidosValueMaskVOID))->AddObject(\"individuals\", gSLiM_Individual_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationCounts, kEidosValueMaskInt))->AddIntObject_N(\"subpops\", gSLiM_Subpopulation_Class)->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationFrequencies, kEidosValueMaskFloat))->AddIntObject_N(\"subpops\", gSLiM_Subpopulation_Class)->AddObject_ON(\"mutations\", gSLiM_Mutation_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_mutationsOfType, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputFixedMutations, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"objectTags\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputFull, kEidosValueMaskVOID))->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"binary\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"spatialPositions\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"ages\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"ancestralNucleotides\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"pedigreeIDs\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"objectTags\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"substitutions\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputMutations, kEidosValueMaskVOID))->AddObject(\"mutations\", gSLiM_Mutation_Class)->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"objectTags\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_readFromPopulationFile, kEidosValueMaskInt | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath)->AddObject_OSN(\"subpopMap\", gEidosDictionaryUnretained_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_recalculateFitness, kEidosValueMaskVOID))->AddInt_OSN(\"tick\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerFitnessEffectCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerMateChoiceCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerModifyChildCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerRecombinationCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerSurvivalCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerMutationCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"mutType\", gSLiM_MutationType_Class, gStaticEidosValueNULL)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerMutationEffectCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_registerReproductionCallback, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SLiMEidosBlock_Class))->AddIntString_SN(\"id\")->AddString_S(gEidosStr_source)->AddIntObject_OSN(\"subpop\", gSLiM_Subpopulation_Class, gStaticEidosValueNULL)->AddString_OSN(\"sex\", gStaticEidosValueNULL)->AddInt_OSN(\"start\", gStaticEidosValueNULL)->AddInt_OSN(\"end\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_simulationFinished, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_skipTick, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_subsetMutations, kEidosValueMaskObject, gSLiM_Mutation_Class))->AddObject_OSN(\"exclude\", gSLiM_Mutation_Class, gStaticEidosValueNULL)->AddIntObject_OSN(\"mutType\", gSLiM_MutationType_Class, gStaticEidosValueNULL)->AddInt_OSN(\"position\", gStaticEidosValueNULL)->AddIntString_OSN(\"nucleotide\", gStaticEidosValueNULL)->AddInt_OSN(\"tag\", gStaticEidosValueNULL)->AddInt_OSN(\"id\", gStaticEidosValueNULL)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_substitutionsOfType, kEidosValueMaskObject, gSLiM_Substitution_Class))->AddIntObject_S(\"mutType\", gSLiM_MutationType_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_treeSeqCoalesced, kEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_treeSeqSimplify, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_treeSeqRememberIndividuals, kEidosValueMaskVOID))->AddObject(\"individuals\", gSLiM_Individual_Class)->AddLogical_OS(\"permanent\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_treeSeqOutput, kEidosValueMaskVOID))->AddString_S(\"path\")->AddLogical_OS(\"simplify\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"includeModel\", gStaticEidosValue_LogicalT)->AddObject_OSN(\"metadata\", gEidosDictionaryUnretained_Class, gStaticEidosValueNULL)->AddLogical_OS(\"overwriteDirectory\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr__debug, kEidosValueMaskVOID)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n"
  },
  {
    "path": "core/subpopulation.cpp",
    "content": "//\n//  subpopulation.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"subpopulation.h\"\n#include \"community.h\"\n#include \"species.h\"\n#include \"slim_globals.h\"\n#include \"population.h\"\n#include \"interaction_type.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_class_Image.h\"\n\n#include <iostream>\n#include <fstream>\n#include <algorithm>\n#include <assert.h>\n#include <string>\n#include <map>\n#include <utility>\n#include <cmath>\n\n\n#pragma mark -\n#pragma mark Subpopulation\n#pragma mark -\n\n// WF only:\nvoid Subpopulation::WipeIndividualsAndHaplosomes(std::vector<Individual *> &p_individuals, slim_popsize_t p_individual_count, slim_popsize_t p_first_male)\n{\n\tif (!species_.HasGenetics())\n\t{\n\t\t// With no genetics, most of the work here is unnecessary, but we do need to fix the sex of the individuals\n\t\tif (p_first_male >= 0)\n\t\t{\n\t\t\tfor (int index = 0; index < p_individual_count; ++index)\n\t\t\t{\n\t\t\t\tIndividual *individual = p_individuals[index];\n\t\t\t\tbool is_female = (index < p_first_male);\n\t\t\t\t\n\t\t\t\tindividual->sex_ = (is_female ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t\n\t// The logic here is similar to GenerateIndividualEmpty(), but instead of making a new individual,\n\t// we are recycling an existing individual.\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\t\n\tif (p_first_male == -1)\n\t{\n\t\t// make hermaphrodites\n\t\tfor (int index = 0; index < p_individual_count; ++index)\n\t\t{\n\t\t\tIndividual *individual = p_individuals[index];\n\t\t\tHaplosome **haplosomes = individual->haplosomes_;\n\t\t\tint haplosome_index = 0;\n\t\t\t\n\t\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\t{\n\t\t\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\t\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\t\t\t\n\t\t\t\tswitch (chromosomeType)\n\t\t\t\t{\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null + null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::WipeIndividualsAndHaplosomes): (internal error) chromosome type is illegal in non-sexual simulations.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// make females and males\n\t\tfor (int index = 0; index < p_individual_count; ++index)\n\t\t{\n\t\t\tIndividual *individual = p_individuals[index];\n\t\t\tHaplosome **haplosomes = individual->haplosomes_;\n\t\t\tint haplosome_index = 0;\n\t\t\tbool is_female = (index < p_first_male);\n\t\t\t\n\t\t\tindividual->sex_ = (is_female ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\n\t\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t\t{\n\t\t\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\t\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\t\t\t\n\t\t\t\tswitch (chromosomeType)\n\t\t\t\t{\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\t{\n\t\t\t\t\t\t// XX for females, X- for males\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (is_female)\n\t\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t{\n\t\t\t\t\t\t// - for females, Y for males\n\t\t\t\t\t\tif (is_female)\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\t{\n\t\t\t\t\t\t// ZZ for males, -Z for females\n\t\t\t\t\t\tif (is_female)\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\t{\n\t\t\t\t\t\t// - for males, W for females\n\t\t\t\t\t\tif (is_female)\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\thaplosome_index += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t{\n\t\t\t\t\t\t// non-null + null for all\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t{\n\t\t\t\t\t\t// -- for females, -Y for males\n\t\t\t\t\t\thaplosomes[haplosome_index]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (is_female)\n\t\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNull(individual);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\thaplosomes[haplosome_index+1]->ReinitializeHaplosomeToNonNull(individual, chromosome);\n\t\t\t\t\t\t\n\t\t\t\t\t\thaplosome_index += 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Reconfigure the child generation to match the set size, sex ratio, etc.  This may involve removing existing individuals,\n// or adding new ones.  It may also involve transmogrifying existing individuals to a new sex, etc.  It can also transmogrify\n// haplosomes between a null and non-null state, as a side effect of changing sex.  So this code is really gross and invasive.\nvoid Subpopulation::GenerateChildrenToFitWF()\n{\n\t// First, make the number of Individual objects match, and make the corresponding Haplosome changes\n\tint old_individual_count = (int)child_individuals_.size();\n\tint new_individual_count = child_subpop_size_;\n\t\n\tif (new_individual_count > old_individual_count)\n\t{\n\t\t// We also have to make space for the pointers to the haplosomes and individuals\n\t\tchild_individuals_.reserve(new_individual_count);\n\t\t\n\t\tif (species_.HasGenetics())\n\t\t{\n\t\t\tconst std::vector<Chromosome *> &chromosome_for_haplosome_index = species_.ChromosomesForHaplosomeIndices();\n\t\t\tconst std::vector<uint8_t> &chromosome_subindices = species_.ChromosomeSubindicesForHaplosomeIndices();\n\t\t\tint haplosome_count_per_individual = HaplosomeCountPerIndividual();\n\t\t\t\n\t\t\t// We just allocate null haplosomes here for all chromosomes; there is no mutrun buffer allocation\n\t\t\t// overhead for that.  WipeIndividualsAndHaplosomes(), called below, will fix them to be the correct\n\t\t\t// type as needed.  There is a little extra overhead for that, presumably, but it only matters when\n\t\t\t// the population size (or perhaps sex ratio, etc.) changes.\n\t\t\tif ((haplosome_count_per_individual == 2) && (species_.Chromosomes().size() == 1))\n\t\t\t{\n\t\t\t\tChromosome *chromosome = chromosome_for_haplosome_index[0];\n\t\t\t\t\n\t\t\t\t// special-case the simple diploid case to avoid the loop\n\t\t\t\tfor (int new_index = old_individual_count; new_index < new_individual_count; ++new_index)\n\t\t\t\t{\n\t\t\t\t\t// allocate out of our junkyard and object pool\n\t\t\t\t\tIndividual *individual = NewSubpopIndividual(new_index, IndividualSex::kHermaphrodite, -1, /* initial fitness for new subpops */ 1.0, /* p_mean_parent_age */ -1.0F);\n\t\t\t\t\t\n\t\t\t\t\tindividual->AddHaplosomeAtIndex(chromosome->NewHaplosome_NULL(individual, 0), 0);\n\t\t\t\t\tindividual->AddHaplosomeAtIndex(chromosome->NewHaplosome_NULL(individual, 1), 1);\n\t\t\t\t\t\n\t\t\t\t\tchild_individuals_.emplace_back(individual);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int new_index = old_individual_count; new_index < new_individual_count; ++new_index)\n\t\t\t\t{\n\t\t\t\t\t// allocate out of our junkyard and object pool\n\t\t\t\t\tIndividual *individual = NewSubpopIndividual(new_index, IndividualSex::kHermaphrodite, -1, /* initial fitness for new subpops */ 1.0, /* p_mean_parent_age */ -1.0F);\n\t\t\t\t\t\n\t\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tChromosome *chromosome = chromosome_for_haplosome_index[haplosome_index];\n\t\t\t\t\t\tuint8_t chromosome_subindex = chromosome_subindices[haplosome_index];\n\t\t\t\t\t\tHaplosome *haplosome = chromosome->NewHaplosome_NULL(individual, chromosome_subindex);\n\t\t\t\t\t\t\n\t\t\t\t\t\tindividual->AddHaplosomeAtIndex(haplosome, haplosome_index);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tchild_individuals_.emplace_back(individual);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// In the no-genetics case no haplosomes are needed, so it is very simple\n\t\t\tfor (int new_index = old_individual_count; new_index < new_individual_count; ++new_index)\n\t\t\t{\n\t\t\t\tIndividual *individual = NewSubpopIndividual(new_index, IndividualSex::kHermaphrodite, -1, /* initial fitness for new subpops */ 1.0, /* p_mean_parent_age */ -1.0F);\n\t\t\t\t\n\t\t\t\tchild_individuals_.emplace_back(individual);\n\t\t\t}\n\t\t}\n\t}\n\telse if (new_individual_count < old_individual_count)\n\t{\n\t\tfor (int old_index = new_individual_count; old_index < old_individual_count; ++old_index)\n\t\t{\n\t\t\tIndividual *individual = child_individuals_[old_index];\n\t\t\t\n\t\t\t// dispose of the individual\n\t\t\t_FreeSubpopIndividual(individual);\n\t\t}\n\t\t\n\t\tchild_individuals_.resize(new_individual_count);\n\t}\n\t\n\t// Next, fix the type of each haplosome, and clear them all, and fix individual sex if necessary\n\tif (sex_enabled_)\n\t{\n\t\tdouble sex_ratio = child_sex_ratio_;\n\t\tslim_popsize_t &first_male_index = child_first_male_index_;\n\t\t\n\t\tslim_popsize_t total_males = static_cast<slim_popsize_t>(lround(sex_ratio * new_individual_count));\t// round in favor of males, arbitrarily\n\t\t\n\t\tfirst_male_index = new_individual_count - total_males;\n\t\t\n\t\tif (first_male_index <= 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateChildrenToFitWF): sex ratio of \" << sex_ratio << \" produced no females.\" << EidosTerminate();\n\t\telse if (first_male_index >= child_subpop_size_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateChildrenToFitWF): sex ratio of \" << sex_ratio << \" produced no males.\" << EidosTerminate();\n\t\t\n\t\tWipeIndividualsAndHaplosomes(child_individuals_, new_individual_count, first_male_index);\n\t}\n\telse\n\t{\n\t\tWipeIndividualsAndHaplosomes(child_individuals_, new_individual_count, -1);\t// make hermaphrodites\n\t}\n}\n\n// Generate new individuals to fill out a freshly created subpopulation, including recording in the tree\n// sequence unless this is the result of addSubpopSplit() (which does its own recording since parents are\n// involved in that case).  This handles both the WF and nonWF cases, which are very similar.\nvoid Subpopulation::GenerateParentsToFit(slim_age_t p_initial_age, double p_sex_ratio, bool p_allow_zero_size, bool p_require_both_sexes, bool p_record_in_treeseq, bool p_haploid, float p_mean_parent_age)\n{\n\tbool recording_tree_sequence = p_record_in_treeseq && species_.RecordingTreeSequence();\n\t\n\tcached_parent_individuals_value_.reset();\n\t\n\tif (parent_individuals_.size())\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateParentsToFit): (internal error) individuals already present in GenerateParentsToFit().\" << EidosTerminate();\n\tif ((parent_subpop_size_ == 0) && !p_allow_zero_size)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateParentsToFit): (internal error) subpop size of 0 requested.\" << EidosTerminate();\n\t\n\t// Make space for the pointers to the haplosomes and individuals\n\tparent_individuals_.reserve(parent_subpop_size_);\n\t\n\t// Now create new individuals and haplosomes appropriate for the requested sex ratio and subpop size\n\t// MULTICHROM FIXME there was code here to make shared empty mutation runs, reused across all of the new individuals.  I'm not sure\n\t// how big a deal this is.  It will probably only affect the time to generate the first generation; I think it wouldn't matter after\n\t// that at all.  Anyhow, it doesn't presently fit into the new scheme, so I'm removing it for now.  Perhaps GenerateIndividualEmpty()\n\t// could do something smart here in future?  How about: the Chromosome keeps a single empty mutrun object that is shared across all\n\t// uses, and users of it are never allowed to modify it, but must instead make a new mutrun if they need to modify it?\n\tif (sex_enabled_)\n\t{\n\t\tslim_popsize_t total_males = static_cast<slim_popsize_t>(lround(p_sex_ratio * parent_subpop_size_));\t// round in favor of males, arbitrarily\n\t\tslim_popsize_t first_male_index = parent_subpop_size_ - total_males;\n\t\t\n\t\tparent_first_male_index_ = first_male_index;\n\t\t\n\t\tif (p_require_both_sexes)\n\t\t{\n\t\t\tif (first_male_index <= 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateParentsToFit): sex ratio of \" << p_sex_ratio << \" produced no females.\" << EidosTerminate();\n\t\t\telse if (first_male_index >= parent_subpop_size_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GenerateParentsToFit): sex ratio of \" << p_sex_ratio << \" produced no males.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// Make females and then males\n\t\tfor (int new_index = 0; new_index < parent_subpop_size_; ++new_index)\n\t\t{\n\t\t\tIndividualSex child_sex = (new_index < first_male_index) ? IndividualSex::kFemale : IndividualSex::kMale;\n\t\t\tIndividual *ind = GenerateIndividualEmpty(/* index */ new_index,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* sex */ child_sex,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* age */ p_initial_age,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* fitness */ 1.0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  p_mean_parent_age,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* haplosome1_null */ false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* haplosome2_null */ p_haploid,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* run_modify_child */ false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  recording_tree_sequence);\n\t\t\t\n\t\t\tparent_individuals_.emplace_back(ind);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Make hermaphrodites\n\t\tfor (int new_index = 0; new_index < parent_subpop_size_; ++new_index)\n\t\t{\n\t\t\tIndividualSex child_sex = IndividualSex::kHermaphrodite;\n\t\t\tIndividual *ind = GenerateIndividualEmpty(/* index */ new_index,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* sex */ child_sex,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* age */ p_initial_age,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* fitness */ 1.0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  p_mean_parent_age,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* haplosome1_null */ false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* haplosome2_null */ p_haploid,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  /* run_modify_child */ false,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  recording_tree_sequence);\n\t\t\t\n\t\t\tparent_individuals_.emplace_back(ind);\n\t\t}\n\t}\n}\n\nvoid Subpopulation::CheckIndividualIntegrity(void)\n{\n\tClearErrorPosition();\n\t\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosNoBlockType)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) executing block type was not maintained correctly.\" << EidosTerminate();\n\t\n\tSLiMModelType model_type = model_type_;\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tsize_t chromosomes_count = chromosomes.size();\n\tbool has_genetics = species_.HasGenetics();\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tif (!has_genetics && (chromosomes_count != 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Community::Species_CheckIntegrity): (internal error) chromosome present in no-genetics species.\" << EidosTerminate();\n\t\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tint32_t mutrun_count = chromosome->mutrun_count_;\n\t\tslim_position_t mutrun_length = chromosome->mutrun_length_;\n\t\t\n\t\tif (has_genetics && ((mutrun_count == 0) || (mutrun_length == 0)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) species with genetics has mutrun count/length of 0.\" << EidosTerminate();\n\t\telse if (!has_genetics && ((mutrun_count != 0) || (mutrun_length != 0)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) species with no genetics has non-zero mutrun count/length.\" << EidosTerminate();\n\t}\n\t\n#if DEBUG_LESS_INTENSIVE\n\t// These tests are extremely intensive, so sometimes it's useful to dial them down...\n\tif ((community_.Tick() % 20) != 5)\n\t\treturn;\n#endif\n\t\n\t// below we will use this map to check that every mutation run in use is used at only one mutrun index\n\trobin_hood::unordered_flat_map<const MutationRun *, slim_mutrun_index_t> mutrun_position_map;\n\t\n\t//\n\t//\tCheck the parental generation; this is essentially the same in WF and nonWF models\n\t//\n\t\n\tif ((int)parent_individuals_.size() != parent_subpop_size_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between parent_subpop_size_ and parent_individuals_.size().\" << EidosTerminate();\n\t\n\tfor (int ind_index = 0; ind_index < parent_subpop_size_; ++ind_index)\n\t{\n\t\tIndividual *individual = parent_individuals_[ind_index];\n\t\tbool invalid_age = false;\n\t\t\n\t\tif (!individual)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for individual.\" << EidosTerminate();\n\t\t\n\t\tif (individual->index_ != ind_index)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->index_ and ind_index.\" << EidosTerminate();\n\t\n\t\tif (individual->subpopulation_ != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->subpopulation_ and subpopulation.\" << EidosTerminate();\n\t\t\n\t\tif (species_.PedigreesEnabled())\n\t\t{\n\t\t\tif (individual->pedigree_id_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) individual has an invalid pedigree ID.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (model_type == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tif (individual->age_ != -1)\n\t\t\t\tinvalid_age = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (individual->age_ < 0)\n\t\t\t\tinvalid_age = true;\n\t\t}\n\t\t\n\t\tif (invalid_age)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) invalid value for individual->age_.\" << EidosTerminate();\n\t\t\n\t\tbool is_female = (ind_index < parent_first_male_index_);\t// only used below in sexual simulations\n\t\t\n\t\tif (sex_enabled_)\n\t\t{\n\t\t\tif ((is_female && (individual->sex_ != IndividualSex::kFemale)) ||\n\t\t\t\t(!is_female && (individual->sex_ != IndividualSex::kMale)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->sex_ and parent_first_male_index_.\" << EidosTerminate();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (individual->sex_ != IndividualSex::kHermaphrodite)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) non-hermaphrodite individual in non-sexual simulation.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// check that we agree with the species on the haplosome count per individual\n\t\t// (we can't check the individual's haplosome count because it simply uses haplosome_count_per_individual_; it has no count of its own!)\n\t\tif (haplosome_count_per_individual_ != species_.HaplosomeCountPerIndividual())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome count is incorrect.\" << EidosTerminate();\n\t\t\n\t\t// loop over chromosomes one by one and check the haplosomes of each chromosome\n\t\tint haplosome_index = 0;\n\t\t\n\t\tfor (size_t chromosome_index = 0; chromosome_index < chromosomes_count; chromosome_index++)\n\t\t{\n\t\t\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t\t\n\t\t\t// check haplosome indices\n\t\t\tint haplosome_count = chromosome->IntrinsicPloidy();\n\t\t\t\n\t\t\t// check haplosome 1 for this chromosome\n\t\t\t{\n\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tif (!haplosome1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for haplosome1.\" << EidosTerminate();\n\t\t\t\tif (haplosome1->individual_ != individual)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between haplosome1->individual_ and individual.\" << EidosTerminate();\n\t\t\t\tif (haplosome1->AssociatedChromosome() != chromosome)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1->AssociatedChromosome() mismatch.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (!haplosome1->IsNull())\n\t\t\t\t{\n\t\t\t\t\tslim_position_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\tslim_position_t mutrun_length = chromosome->mutrun_length_;\n\t\t\t\t\t\n\t\t\t\t\tif ((haplosome1->mutrun_count_ != mutrun_count) || (haplosome1->mutrun_length_ != mutrun_length))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 of individual has the wrong mutrun count/length.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// check that every mutation in the haplosome belongs to the right chromosome\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome1->mutruns_[run_index];\n\t\t\t\t\t\tconst MutationIndex *mutrun_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *mutrun_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (; mutrun_iter != mutrun_end_iter; ++mutrun_iter)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *mut = (mut_block_ptr + *mutrun_iter);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mut->chromosome_index_ != haplosome1->chromosome_index_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mutation with chromosome_index_ \" << (unsigned int)mut->chromosome_index_ << \" is present in haplosome with chromosome_index_ \" << (unsigned int)haplosome1->chromosome_index_ << \".\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (((haplosome1->mutrun_count_ == 0) && ((haplosome1->mutrun_length_ != 0) || (haplosome1->mutruns_ != nullptr))) ||\n\t\t\t\t\t((haplosome1->mutrun_length_ == 0) && ((haplosome1->mutrun_count_ != 0) || (haplosome1->mutruns_ != nullptr))))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 mutrun count/length/pointer inconsistency.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (species_.PedigreesEnabled())\n\t\t\t\t{\n\t\t\t\t\tif (haplosome1->haplosome_id_ != individual->pedigree_id_ * 2)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 has an invalid haplosome pedigree ID.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbool null_problem = false;\n\t\t\t\t\n\t\t\t\tswitch (chromosome_type)\n\t\t\t\t{\n\t\t\t\t\t\t// haplosome1 should be null for these types\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t\tif (!haplosome1->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome1 should be non-null for these types\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\t\tif (haplosome1->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome1 should be null in females, non-null in males\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t\tif (is_female != haplosome1->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome1 should be null in males, non-null in females\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\t\tif (is_female == haplosome1->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we allow either for these types (to allow haplodiploidy, alternation of generations, etc.)\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (null_problem)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 mismatch between expected and actual null haplosome status.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (population_.child_generation_valid_)\n\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t// When the child generation is valid, all parental haplosomes should have null mutrun pointers [OBSOLETE: so mutrun refcounts are correct]\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\tif (haplosome1->mutruns_[mutrun_index] != nullptr)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a nonnull mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t// When the parental generation is valid, all parental haplosomes should have non-null mutrun pointers\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\tif (haplosome1->mutruns_[mutrun_index] == nullptr)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a null mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// check that every mutrun is used at only one mutrun index (particularly salient for empty mutruns)\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome1->mutruns_[mutrun_index];\n\t\t\t\t\t\tauto found_iter = mutrun_position_map.find(mutrun);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (found_iter == mutrun_position_map.end())\n\t\t\t\t\t\t\tmutrun_position_map[mutrun] = mutrun_index;\n\t\t\t\t\t\telse if (found_iter->second != mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// see Population::FreeUnusedMutationRuns() for debugging code helpful for this error\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a mutation run was used at more than one position.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// check haplosome 2 for this chromosome\n\t\t\tif (haplosome_count == 2)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome2 = individual->haplosomes_[haplosome_index + 1];\n\t\t\t\t\n\t\t\t\tif (!haplosome2)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for haplosome2.\" << EidosTerminate();\n\t\t\t\tif (haplosome2->individual_ != individual)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between haplosome2->individual_ and individual.\" << EidosTerminate();\n\t\t\t\tif (haplosome2->AssociatedChromosome() != chromosome)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2->AssociatedChromosome() mismatch.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (!haplosome2->IsNull())\n\t\t\t\t{\n\t\t\t\t\tslim_position_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\tslim_position_t mutrun_length = chromosome->mutrun_length_;\n\t\t\t\t\t\n\t\t\t\t\tif ((haplosome2->mutrun_count_ != mutrun_count) || (haplosome2->mutrun_length_ != mutrun_length))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 of individual has the wrong mutrun count/length.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// check that every mutation in the haplosome belongs to the right chromosome\n\t\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome2->mutruns_[run_index];\n\t\t\t\t\t\tconst MutationIndex *mutrun_iter = mutrun->begin_pointer_const();\n\t\t\t\t\t\tconst MutationIndex *mutrun_end_iter = mutrun->end_pointer_const();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (; mutrun_iter != mutrun_end_iter; ++mutrun_iter)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMutation *mut = (mut_block_ptr + *mutrun_iter);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mut->chromosome_index_ != haplosome2->chromosome_index_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mutation with chromosome_index_ \" << (unsigned int)mut->chromosome_index_ << \" is present in haplosome with chromosome_index_ \" << (unsigned int)haplosome2->chromosome_index_ << \".\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (((haplosome2->mutrun_count_ == 0) && ((haplosome2->mutrun_length_ != 0) || (haplosome2->mutruns_ != nullptr))) ||\n\t\t\t\t\t((haplosome2->mutrun_length_ == 0) && ((haplosome2->mutrun_count_ != 0) || (haplosome2->mutruns_ != nullptr))))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 mutrun count/length/pointer inconsistency.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (species_.PedigreesEnabled())\n\t\t\t\t{\n\t\t\t\t\tif (haplosome2->haplosome_id_ != individual->pedigree_id_ * 2 + 1)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 has an invalid haplosome pedigree ID.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbool null_problem = false;\n\t\t\t\t\n\t\t\t\tswitch (chromosome_type)\n\t\t\t\t{\n\t\t\t\t\t\t// haplosome2 should be null for these types\n\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t\tif (!haplosome2->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome2 should be non-null for these types\n\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\t\tif (haplosome2->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome2 should be null in females, non-null in males\n\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t\tif (is_female != haplosome2->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome2 should be null in males, non-null in females\n\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\t\tif (is_female == haplosome2->IsNull())\n\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we allow either for these types (to allow haplodiploidy, alternation of generations, etc.)\n\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// haplosome2 should not exist at all for these types\n\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) chromosome type should never be used for haplosome2.\" << EidosTerminate();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (null_problem)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 mismatch between expected and actual null haplosome status.\" << EidosTerminate();\n\t\t\t\t\n\t\t\t\tif (population_.child_generation_valid_)\n\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t// When the child generation is valid, all parental haplosomes should have null mutrun pointers [OBSOLETE: so mutrun refcounts are correct]\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\tif (haplosome2->mutruns_[mutrun_index] != nullptr)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a nonnull mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t// When the parental generation is valid, all parental haplosomes should have non-null mutrun pointers\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\tif (haplosome2->mutruns_[mutrun_index] == nullptr)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a null mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// check that every mutrun is used at only one mutrun index (particularly salient for empty mutruns)\n\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst MutationRun *mutrun = haplosome2->mutruns_[mutrun_index];\n\t\t\t\t\t\tauto found_iter = mutrun_position_map.find(mutrun);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (found_iter == mutrun_position_map.end())\n\t\t\t\t\t\t\tmutrun_position_map[mutrun] = mutrun_index;\n\t\t\t\t\t\telse if (found_iter->second != mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// see Population::FreeUnusedMutationRuns() for debugging code helpful for this error\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a mutation run was used at more than one position.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\thaplosome_index += haplosome_count;\n\t\t}\n\t}\n\t\n\t//\n\t//\tCheck the child generation; this is only in WF models\n\t//\n\t\n\tif (model_type == SLiMModelType::kModelTypeWF)\n\t{\n\t\tif ((int)child_individuals_.size() != child_subpop_size_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between child_subpop_size_ and child_individuals_.size().\" << EidosTerminate();\n\t\t\n\t\tfor (int ind_index = 0; ind_index < child_subpop_size_; ++ind_index)\n\t\t{\n\t\t\tIndividual *individual = child_individuals_[ind_index];\n\t\t\t\n\t\t\tif (!individual)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for individual.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (individual->index_ != ind_index)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->index_ and ind_index.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (individual->subpopulation_ != this)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->subpopulation_ and subpopulation.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (species_.PedigreesEnabled() && population_.child_generation_valid_)\n\t\t\t{\n\t\t\t\tif (individual->pedigree_id_ == -1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) individual has an invalid pedigree ID.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\tif (individual->age_ != -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) invalid value for individual->age_.\" << EidosTerminate();\n\t\t\t\n\t\t\tbool is_female = (ind_index < child_first_male_index_);\t\t// only used below in sexual simulations\n\t\t\t\n\t\t\tif (sex_enabled_)\n\t\t\t{\n\t\t\t\tif ((is_female && (individual->sex_ != IndividualSex::kFemale)) ||\n\t\t\t\t\t(!is_female && (individual->sex_ != IndividualSex::kMale)))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between individual->sex_ and child_first_male_index_.\" << EidosTerminate();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (individual->sex_ != IndividualSex::kHermaphrodite)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) non-hermaphrodite individual in non-sexual simulation.\" << EidosTerminate();\n\t\t\t}\n\t\t\t\n\t\t\t// loop over chromosomes one by one and check the haplosomes of each chromosome\n\t\t\tint haplosome_index = 0;\n\t\t\t\n\t\t\tfor (size_t chromosome_index = 0; chromosome_index < chromosomes_count; chromosome_index++)\n\t\t\t{\n\t\t\t\tChromosome *chromosome = chromosomes[chromosome_index];\n\t\t\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t\t\t\n\t\t\t\t// check haplosome indices\n\t\t\t\tint haplosome_count = chromosome->IntrinsicPloidy();\n\t\t\t\t\n\t\t\t\t// check haplosome 1 for this chromosome\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome1)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for haplosome1.\" << EidosTerminate();\n\t\t\t\t\tif (haplosome1->individual_ != individual)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between haplosome1->individual_ and individual.\" << EidosTerminate();\n\t\t\t\t\tif (haplosome1->AssociatedChromosome() != chromosome)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1->AssociatedChromosome() mismatch.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome1->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_position_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t mutrun_length = chromosome->mutrun_length_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((haplosome1->mutrun_count_ != mutrun_count) || (haplosome1->mutrun_length_ != mutrun_length))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 of individual has the wrong mutrun count/length.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// do not check haplosomes in the child generation; they are conceptually cleared to\n\t\t\t\t\t\t// nullptr (but can actually even contain garbage, unless SLIM_CLEAR_HAPLOSOMES is set\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (((haplosome1->mutrun_count_ == 0) && ((haplosome1->mutrun_length_ != 0) || (haplosome1->mutruns_ != nullptr))) ||\n\t\t\t\t\t\t((haplosome1->mutrun_length_ == 0) && ((haplosome1->mutrun_count_ != 0) || (haplosome1->mutruns_ != nullptr))))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 mutrun count/length/pointer inconsistency.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// we don't check pedigree IDs for the child generation; they are not expected to be set up\n\t\t\t\t\t\n\t\t\t\t\tbool null_problem = false;\n\t\t\t\t\t\n\t\t\t\t\tswitch (chromosome_type)\n\t\t\t\t\t{\n\t\t\t\t\t\t\t// haplosome1 should be null for these types\n\t\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t\t\tif (!haplosome1->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome1 should be non-null for these types\n\t\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\t\t\tif (haplosome1->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome1 should be null in females, non-null in males\n\t\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t\t\tif (is_female != haplosome1->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome1 should be null in males, non-null in females\n\t\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\t\t\tif (is_female == haplosome1->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we allow either for these types (to allow haplodiploidy, alternation of generations, etc.)\n\t\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (null_problem)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome1 mismatch between expected and actual null haplosome status.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (!population_.child_generation_valid_)\n\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t// When the parental generation is valid, all child haplosomes should have null mutrun pointers [OBSOLETE: so mutrun refcounts are correct]\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t\tif (haplosome1->mutruns_[mutrun_index] != nullptr)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a child haplosome has a nonnull mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t// When the child generation is valid, all child haplosomes should have non-null mutrun pointers\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t\tif (haplosome1->mutruns_[mutrun_index] == nullptr)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a child haplosome has a null mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t// check that every mutrun is used at only one mutrun index (particularly salient for empty mutruns)\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome1->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome1->mutruns_[mutrun_index];\n\t\t\t\t\t\t\tauto found_iter = mutrun_position_map.find(mutrun);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (found_iter == mutrun_position_map.end())\n\t\t\t\t\t\t\t\tmutrun_position_map[mutrun] = mutrun_index;\n\t\t\t\t\t\t\telse if (found_iter->second != mutrun_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// see Population::FreeUnusedMutationRuns() for debugging code helpful for this error\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a mutation run was used at more than one position.\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// check haplosome 2 for this chromosome\n\t\t\t\tif (haplosome_count == 2)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome2 = individual->haplosomes_[haplosome_index + 1];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome2)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null pointer for haplosome2.\" << EidosTerminate();\n\t\t\t\t\tif (haplosome2->individual_ != individual)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) mismatch between haplosome2->individual_ and individual.\" << EidosTerminate();\n\t\t\t\t\tif (haplosome2->AssociatedChromosome() != chromosome)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2->AssociatedChromosome() mismatch.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome2->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tslim_position_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\t\tslim_position_t mutrun_length = chromosome->mutrun_length_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((haplosome2->mutrun_count_ != mutrun_count) || (haplosome2->mutrun_length_ != mutrun_length))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 of individual has the wrong mutrun count/length.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// do not check haplosomes in the child generation; they are conceptually cleared to\n\t\t\t\t\t\t// nullptr (but can actually even contain garbage, unless SLIM_CLEAR_HAPLOSOMES is set\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (((haplosome2->mutrun_count_ == 0) && ((haplosome2->mutrun_length_ != 0) || (haplosome2->mutruns_ != nullptr))) ||\n\t\t\t\t\t\t((haplosome2->mutrun_length_ == 0) && ((haplosome2->mutrun_count_ != 0) || (haplosome2->mutruns_ != nullptr))))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 mutrun count/length/pointer inconsistency.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t// we don't check pedigree IDs for the child generation; they are not expected to be set up\n\t\t\t\t\t\n\t\t\t\t\tbool null_problem = false;\n\t\t\t\t\t\n\t\t\t\t\tswitch (chromosome_type)\n\t\t\t\t\t{\n\t\t\t\t\t\t\t// haplosome2 should be null for these types\n\t\t\t\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t\t\t\t\tif (!haplosome2->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome2 should be non-null for these types\n\t\t\t\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\t\t\t\tif (haplosome2->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome2 should be null in females, non-null in males\n\t\t\t\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\t\t\t\tif (is_female != haplosome2->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome2 should be null in males, non-null in females\n\t\t\t\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t\t\t\t\tif (is_female == haplosome2->IsNull())\n\t\t\t\t\t\t\t\tnull_problem = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// we allow either for these types (to allow haplodiploidy, alternation of generations, etc.)\n\t\t\t\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// haplosome2 should not exist at all for these types\n\t\t\t\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) chromosome type should never be used for haplosome2.\" << EidosTerminate();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (null_problem)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) haplosome2 mismatch between expected and actual null haplosome status.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tif (!population_.child_generation_valid_)\n\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t// When the parental generation is valid, all child haplosomes should have null mutrun pointers [OBSOLETE: so mutrun refcounts are correct]\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t\tif (haplosome2->mutruns_[mutrun_index] != nullptr)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a nonnull mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t\t\t\t// When the child generation is valid, all child haplosomes should have non-null mutrun pointers\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t\tif (haplosome2->mutruns_[mutrun_index] == nullptr)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a parental haplosome has a null mutrun pointer.\" << EidosTerminate();\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\t// check that every mutrun is used at only one mutrun index (particularly salient for empty mutruns)\n\t\t\t\t\t\tfor (int mutrun_index = 0; mutrun_index < haplosome2->mutrun_count_; ++mutrun_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationRun *mutrun = haplosome2->mutruns_[mutrun_index];\n\t\t\t\t\t\t\tauto found_iter = mutrun_position_map.find(mutrun);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (found_iter == mutrun_position_map.end())\n\t\t\t\t\t\t\t\tmutrun_position_map[mutrun] = mutrun_index;\n\t\t\t\t\t\t\telse if (found_iter->second != mutrun_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// see Population::FreeUnusedMutationRuns() for debugging code helpful for this error\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a mutation run was used at more than one position.\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thaplosome_index += haplosome_count;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//\n\t// Check that every mutation run is being used at a position corresponding to the pool it was allocated from\n\t//\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tslim_mutrun_index_t mutrun_count_multiplier = chromosome->mutrun_count_multiplier_;\n\t\t\n\t\tfor (int thread_num = 0; thread_num < chromosome->ChromosomeMutationRunContextCount(); ++thread_num)\n\t\t{\n\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForThread(thread_num);\n\t\t\tMutationRunPool &in_use_pool = mutrun_context.in_use_pool_;\n\t\t\t\n\t\t\tfor (const MutationRun *mutrun : in_use_pool)\n\t\t\t{\n\t\t\t\tauto found_iter = mutrun_position_map.find(mutrun);\n\t\t\t\t\n\t\t\t\tif (found_iter != mutrun_position_map.end())\n\t\t\t\t{\n\t\t\t\t\tslim_mutrun_index_t used_at_index = found_iter->second;\n\t\t\t\t\tint correct_thread_num = (int)(used_at_index / mutrun_count_multiplier);\n\t\t\t\t\t\n\t\t\t\t\tif (correct_thread_num != thread_num)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) a mutation run is used at a position that does not correspond to its allocation pool.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//\n\t//\tCheck the haplosome junkyards for correct state; BCH 10/15/2024 note that clearing to nullptr is no longer required\n\t//\n\tfor (Chromosome *chromosome : chromosomes)\n\t{\n\t\tconst std::vector<Haplosome *> &haplosomes_junkyard_nonnull = chromosome->HaplosomesJunkyardNonnull();\n\t\tconst std::vector<Haplosome *> &haplosomes_junkyard_null = chromosome->HaplosomesJunkyardNull();\n\t\t\n\t\tif (!has_genetics && haplosomes_junkyard_null.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) the null haplosome junkyard should be empty in no-genetics species.\" << EidosTerminate();\n\t\tif (!has_genetics && haplosomes_junkyard_nonnull.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) the nonnull haplosome junkyard should be empty in no-genetics species.\" << EidosTerminate();\n\t\t\n\t\tfor (Haplosome *haplosome : haplosomes_junkyard_nonnull)\n\t\t{\n\t\t\tif (haplosome->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) null haplosome in the nonnull haplosome junkyard.\" << EidosTerminate();\n\t\t\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\thaplosome->check_cleared_to_nullptr();\n#endif\n\t\t}\n\t\t\n\t\tfor (Haplosome *haplosome : haplosomes_junkyard_null)\n\t\t{\n\t\t\tif (!haplosome->IsNull())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CheckIndividualIntegrity): (internal error) nonnull haplosome in the null haplosome junkyard.\" << EidosTerminate();\n\t\t\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\thaplosome->check_cleared_to_nullptr();\n#endif\n\t\t}\n\t}\n}\n\nSubpopulation::Subpopulation(Population &p_population, slim_objectid_t p_subpopulation_id, slim_popsize_t p_subpop_size, bool p_record_in_treeseq, bool p_haploid) :\n\tself_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('p', p_subpopulation_id)), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Subpopulation_Class))), \n\tcommunity_(p_population.species_.community_), species_(p_population.species_), population_(p_population),\n\tmodel_type_(p_population.model_type_), subpopulation_id_(p_subpopulation_id), name_(SLiMEidosScript::IDStringWithPrefix('p', p_subpopulation_id)),\n\tindividual_pool_(p_population.species_individual_pool_), individuals_junkyard_(p_population.species_individuals_junkyard_),\n\thaplosome_count_per_individual_(p_population.species_.HaplosomeCountPerIndividual()),\n\tparent_subpop_size_(p_subpop_size), child_subpop_size_(p_subpop_size)\n#if defined(SLIMGUI)\n\t, gui_premigration_size_(p_subpop_size)\n#endif\n{\n\t// if the species knows that its chromosomes involve null haplosomes, then we inherit that knowledge\n\thas_null_haplosomes_ = species_.ChromosomesUseNullHaplosomes();\n\t\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\tGenerateParentsToFit(/* p_initial_age */ -1, /* p_sex_ratio */ 0.0, /* p_allow_zero_size */ false, /* p_require_both_sexes */ true, /* p_record_in_treeseq */ p_record_in_treeseq, p_haploid, /* p_mean_parent_age */ -1.0F);\n\t\tGenerateChildrenToFitWF();\n\t}\n\telse\n\t{\n\t\tGenerateParentsToFit(/* p_initial_age */ 0, /* p_sex_ratio */ 0.0, /* p_allow_zero_size */ true, /* p_require_both_sexes */ false, /* p_record_in_treeseq */ p_record_in_treeseq, p_haploid, /* p_mean_parent_age */ 0.0F);\n\t}\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\t// Set up to draw random individuals, based initially on equal fitnesses\n\t\tcached_parental_fitness_ = (double *)realloc(cached_parental_fitness_, sizeof(double) * parent_subpop_size_);\n\t\tif (!cached_parental_fitness_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::Subpopulation): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tcached_fitness_capacity_ = parent_subpop_size_;\n\t\tcached_fitness_size_ = parent_subpop_size_;\n\t\t\n\t\tdouble *fitness_buffer_ptr = cached_parental_fitness_;\n\t\t\n\t\tfor (slim_popsize_t i = 0; i < parent_subpop_size_; i++)\n\t\t\t*(fitness_buffer_ptr++) = 1.0;\n\t\t\n\t\tlookup_parent_ = gsl_ran_discrete_preproc(parent_subpop_size_, cached_parental_fitness_);\n\t}\n}\n\n// SEX ONLY\nSubpopulation::Subpopulation(Population &p_population, slim_objectid_t p_subpopulation_id, slim_popsize_t p_subpop_size, bool p_record_in_treeseq,\n\t\t\t\t\t\t\t double p_sex_ratio, bool p_haploid) :\n\tself_symbol_(EidosStringRegistry::GlobalStringIDForString(SLiMEidosScript::IDStringWithPrefix('p', p_subpopulation_id)), EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(this, gSLiM_Subpopulation_Class))),\n\tcommunity_(p_population.species_.community_), species_(p_population.species_), population_(p_population),\n\tmodel_type_(p_population.model_type_), subpopulation_id_(p_subpopulation_id), name_(SLiMEidosScript::IDStringWithPrefix('p', p_subpopulation_id)),\n\tindividual_pool_(p_population.species_individual_pool_), individuals_junkyard_(p_population.species_individuals_junkyard_),\n\thaplosome_count_per_individual_(p_population.species_.HaplosomeCountPerIndividual()),\n\tparent_subpop_size_(p_subpop_size), parent_sex_ratio_(p_sex_ratio), child_subpop_size_(p_subpop_size), child_sex_ratio_(p_sex_ratio), sex_enabled_(true)\n#if defined(SLIMGUI)\n\t, gui_premigration_size_(p_subpop_size)\n#endif\n{\n\t// if the species knows that its chromosomes involve null haplosomes, then we inherit that knowledge\n\thas_null_haplosomes_ = species_.ChromosomesUseNullHaplosomes();\n\t\n\t// self_symbol_ is always a constant, but can't be marked as such on construction\n\tself_symbol_.second->MarkAsConstant();\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\tGenerateParentsToFit(/* p_initial_age */ -1, /* p_sex_ratio */ p_sex_ratio, /* p_allow_zero_size */ false, /* p_require_both_sexes */ true, /* p_record_in_treeseq */ p_record_in_treeseq, p_haploid, /* p_mean_parent_age */ -1.0F);\n\t\tGenerateChildrenToFitWF();\n\t}\n\telse\n\t{\n\t\tGenerateParentsToFit(/* p_initial_age */ 0, /* p_sex_ratio */ p_sex_ratio, /* p_allow_zero_size */ true, /* p_require_both_sexes */ false, /* p_record_in_treeseq */ p_record_in_treeseq, p_haploid, /* p_mean_parent_age */ 0.0F);\n\t}\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\t// Set up to draw random females, based initially on equal fitnesses\n\t\tcached_parental_fitness_ = (double *)realloc(cached_parental_fitness_, sizeof(double) * parent_subpop_size_);\n\t\tcached_male_fitness_ = (double *)realloc(cached_male_fitness_, sizeof(double) * parent_subpop_size_);\n\t\tif (!cached_parental_fitness_ || !cached_male_fitness_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::Subpopulation): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tcached_fitness_capacity_ = parent_subpop_size_;\n\t\tcached_fitness_size_ = parent_subpop_size_;\n\t\t\n\t\tdouble *fitness_buffer_ptr = cached_parental_fitness_;\n\t\tdouble *male_buffer_ptr = cached_male_fitness_;\n\t\t\n\t\tfor (slim_popsize_t i = 0; i < parent_first_male_index_; i++)\n\t\t{\n\t\t\t*(fitness_buffer_ptr++) = 1.0;\n\t\t\t*(male_buffer_ptr++) = 0.0;\t\t\t\t// this vector has 0 for all females, for mateChoice() callbacks\n\t\t}\n\t\t\n\t\t// Set up to draw random males, based initially on equal fitnesses\n\t\tslim_popsize_t num_males = parent_subpop_size_ - parent_first_male_index_;\n\t\t\n\t\tfor (slim_popsize_t i = 0; i < num_males; i++)\n\t\t{\n\t\t\t*(fitness_buffer_ptr++) = 1.0;\n\t\t\t*(male_buffer_ptr++) = 1.0;\n\t\t}\n\t\t\n\t\tlookup_female_parent_ = gsl_ran_discrete_preproc(parent_first_male_index_, cached_parental_fitness_);\n\t\tlookup_male_parent_ = gsl_ran_discrete_preproc(num_males, cached_parental_fitness_ + parent_first_male_index_);\n\t}\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t{\n\t\t// OK, so.  When reading a nonWF tree-seq file, we get passed in a sex ratio that is the sex ratio of the individuals in the file.\n\t\t// That's good, so the individuals that get created have the correct sex.  However, we want the sex ratio ivars in the subpop\n\t\t// to have their default value of 0.0, ultimately; those variables are not supposed to be updated/accurate in nonWF models.  This\n\t\t// fell through the cracks because, who cares if an undefined/unused variable has the wrong value?  But then we write out that\n\t\t// non-zero value to the .trees file, and that was confusing Peter's test code.  So now we explicitly set the ivars to 0.0 here,\n\t\t// now that we're done using the value.  This might also occur when a new subpop is created in a nonWF model; the initial sex ratio\n\t\t// value might have been sticking around permanently in the ivar, even though it would not be accurate any more.  BCH 9/7/2020\n\t\tparent_sex_ratio_ = 0.0;\n\t\tchild_sex_ratio_ = 0.0;\n\t}\n}\n\n\nSubpopulation::~Subpopulation(void)\n{\n\t//std::cout << \"Subpopulation::~Subpopulation\" << std::endl;\n\t\n\tif (lookup_parent_)\n\t\tgsl_ran_discrete_free(lookup_parent_);\n\t\n\tif (lookup_female_parent_)\n\t\tgsl_ran_discrete_free(lookup_female_parent_);\n\t\n\tif (lookup_male_parent_)\n\t\tgsl_ran_discrete_free(lookup_male_parent_);\n\t\n\tif (cached_parental_fitness_)\n\t\tfree(cached_parental_fitness_);\n\t\n\tif (cached_male_fitness_)\n\t\tfree(cached_male_fitness_);\n\t\n\t{\n\t\t// dispose of haplosomes and individuals with our object pools\n\t\t// note that these might get reused; this is not necessarily the simulation end\n\t\tfor (Individual *individual : parent_individuals_)\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\n\t\tfor (Individual *individual : child_individuals_)\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\n\t\tfor (Individual *individual : nonWF_offspring_individuals_)\n\t\t\tFreeSubpopIndividual(individual);\n\t}\n\t\n\tfor (const auto &map_pair : spatial_maps_)\n\t{\n\t\tSpatialMap *map_ptr = map_pair.second;\n\t\t\n\t\tif (map_ptr)\n\t\t\tmap_ptr->Release();\n\t}\n}\n\nvoid Subpopulation::SetName(const std::string &p_name)\n{\n\tif (p_name == name_)\n\t\treturn;\n\t\n\tif (p_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetName): property name must not be zero-length.\" << EidosTerminate();\n\t\n\tbool isSubpopID = (p_name == SLiMEidosScript::IDStringWithPrefix('p', subpopulation_id_));\n\t\n\t// check that names of the form \"pX\" match our self-symbol; can't use somebody else's identifier!\n\tif (!isSubpopID && SLiMEidosScript::StringIsIDWithPrefix(p_name, 'p'))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetName): property name must not be a subpopulation symbol ('p1', 'p2', etc.) unless it matches the symbol of the subpopulation itself.\" << EidosTerminate();\n\t\n\t// we suggest in the doc that subpopulation names ought to be Python identifiers, for maximum interoperability, but\n\t// we do not enforce that here since tskit itself does not require this; this is more of an msprime/Demes thing\n\t\n\t// names have to be unique across all time, and cannot be shared or reused; check and remember names here\n\t// note that we don't unique or track names that match the subpop ID, since they are guaranteed unique\n\t// and cannot be used by any other subpop anyway (and no other subpop can have the same ID)\n\tif (!isSubpopID)\n\t{\n\t\tif (community_.SubpopulationNameInUse(p_name))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetName): property name must be unique across all subpopulations; \" << p_name << \" is already in use, or was previously used.\" << EidosTerminate();\n\t\t\n\t\tspecies_.used_subpop_names_.emplace(p_name);\t// added; never removed unless the simulation state is reset\n\t}\n\t\n\t// we also need to keep track of the last used name for each subpop id, even if it is the generic name\n\tspecies_.used_subpop_ids_[subpopulation_id_] = p_name;\n\t\n\tname_ = p_name;\n}\n\nslim_refcount_t Subpopulation::NullHaplosomeCount(void)\n{\n\tif (population_.child_generation_valid_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::NullHaplosomeCount): (internal error) called with child generation active!\" << EidosTerminate();\n\t\n\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\tslim_refcount_t null_haplosome_count = 0;\n\t\n\tfor (Individual *ind : parent_individuals_)\n\t{\n\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\n\t\t\tif (haplosome->IsNull())\n\t\t\t\tnull_haplosome_count++;\n\t\t}\n\t}\n\t\n\treturn null_haplosome_count;\n}\n\n#if (defined(_OPENMP) && SLIM_USE_NONNEUTRAL_CACHES)\nvoid Subpopulation::FixNonNeutralCaches_OMP(void)\n{\n\t// This is used in the parallel fitness evaluation case to fix caches up front\n\t// This is task-based; note the top-level parallel is *not* a parallel for loop!\n#pragma omp parallel default(none)\n\t{\n#pragma omp single\n\t\t{\n\t\t\tint32_t nonneutral_change_counter = species_.nonneutral_change_counter_;\n\t\t\tint32_t nonneutral_regime = species_.last_nonneutral_regime_;\n#error \tFIXME this *2 is now based on an incorrect assumption of simple diploidy\n\t\t\tslim_popsize_t haplosomeCount = parent_subpop_size_ * 2;\n\t\t\t\n\t\t\tfor (slim_popsize_t haplosome_index = 0; haplosome_index < haplosomeCount; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = parent_haplosomes_[haplosome_index];\n\t\t\t\tconst int32_t mutrun_count = haplosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\t\t\n\t\t\t\t\t// This will start a new task if the mutrun needs to validate\n\t\t\t\t\t// its nonneutral cache.  It avoids doing so more than once.\n\t\t\t\t\tmutrun->validate_nonneutral_cache(nonneutral_change_counter, nonneutral_regime);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n#endif\n\nvoid Subpopulation::UpdateFitness(std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks, std::vector<SLiMEidosBlock*> &p_fitnessEffect_callbacks)\n{\n\tconst std::map<slim_objectid_t,MutationType*> &mut_types = species_.MutationTypes();\n\t\n\t// The FitnessOfParent...() methods called by this method rely upon cached fitness values\n\t// kept inside the Mutation objects.  Those caches may need to be validated before we can\n\t// calculate fitness values.  We check for that condition and repair it first.\n\tif (species_.any_dominance_coeff_changed_)\n\t{\n\t\tpopulation_.ValidateMutationFitnessCaches();\t// note one subpop triggers it, but the recaching occurs for the whole sim\n\t\tspecies_.any_dominance_coeff_changed_ = false;\n\t}\n\t\n\t// This function calculates the population mean fitness as a side effect\n\tdouble totalFitness = 0.0;\n\t\n\t// Figure out our callback scenario: zero, one, or many?  See the comment below, above FitnessOfParentWithHaplosomeIndices_NoCallbacks(),\n\t// for more info on this complication.  Here we just figure out which version to call and set up for it.\n\tint mutationEffect_callback_count = (int)p_mutationEffect_callbacks.size();\n\tbool mutationEffect_callbacks_exist = (mutationEffect_callback_count > 0);\n\tbool single_mutationEffect_callback = false;\n\t\n\tif (mutationEffect_callback_count == 1)\n\t{\n\t\tslim_objectid_t mutation_type_id = p_mutationEffect_callbacks[0]->mutation_type_id_;\n        MutationType *found_muttype = species_.MutationTypeWithID(mutation_type_id);\n\t\t\n\t\tif (found_muttype)\n\t\t{\n\t\t\tif (mut_types.size() > 1)\n\t\t\t{\n\t\t\t\t// We have a single callback that applies to a known mutation type among more than one defined type; we can optimize that\n\t\t\t\tsingle_mutationEffect_callback = true;\n\t\t\t}\n\t\t\t// else there is only one mutation type, so the callback applies to all mutations in the simulation\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The only callback refers to a mutation type that doesn't exist, so we effectively have no callbacks; we probably never hit this\n\t\t\tmutationEffect_callback_count = 0;\n\t\t\t(void)mutationEffect_callback_count;\t\t// tell the static analyzer that we know we just did a dead store\n\t\t\tmutationEffect_callbacks_exist = false;\n\t\t}\n\t}\n\t\n\t// Can we skip chromosome-based fitness calculations altogether, and just call fitnessEffect() callbacks if any?\n\t// We can do this if (a) all mutation types either use a neutral DFE, or have been made neutral with a \"return 1.0;\"\n\t// mutationEffect() callback that is active, (b) for the mutation types that use a neutral DFE, no mutation has had its\n\t// selection coefficient changed, and (c) no mutationEffect() callbacks are active apart from \"return 1.0;\" type callbacks.\n\t// This is often the case for QTL-based models (such as Misha's coral model), and should produce a big speed gain,\n\t// so we do a pre-check here for this case.  Note that we can ignore fitnessEffect() callbacks in this situation,\n\t// because they are explicitly documented as potentially being executed after mutationEffect() callbacks, so\n\t// they are not allowed, as a matter of policy, to alter the operation of mutationEffect() callbacks.\n\tbool skip_chromosomal_fitness = true;\n\t\n\t// Looping through all of the mutation types and setting flags can be very expensive, so as a first pass we check\n\t// whether it is even conceivable that we will be able to have skip_chromosomal_fitness == true.  If the simulation\n\t// is not pure neutral and we have no mutationEffect() callback that could change that, it is a no-go without checking the\n\t// mutation types at all.\n\tif (!species_.pure_neutral_)\n\t{\n\t\tskip_chromosomal_fitness = false;\t// we're not pure neutral, so we have to prove that it is possible\n\t\t\n\t\tfor (SLiMEidosBlock *mutationEffect_callback : p_mutationEffect_callbacks)\n\t\t{\n\t\t\tif (mutationEffect_callback->block_active_)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *compound_statement_node = mutationEffect_callback->compound_statement_node_;\n\t\t\t\t\n\t\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t\t{\n\t\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\"\n\t\t\t\t\tEidosValue *result = compound_statement_node->cached_return_value_.get();\n\t\t\t\t\t\n\t\t\t\t\tif ((result->Type() == EidosValueType::kValueFloat) || (result->Count() == 1))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result->FloatData()[0] == 1.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have a mutationEffect() callback that is neutral-making, so it could conceivably work;\n\t\t\t\t\t\t\t// change our minds but keep checking\n\t\t\t\t\t\t\tskip_chromosomal_fitness = true;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// if we reach this point, we have an active callback that is not neutral-making, so we fail and we're done\n\t\t\t\tskip_chromosomal_fitness = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// At this point it appears conceivable that we could skip, but we don't yet know.  We need to do a more thorough\n\t// check, actually tracking precisely which mutation types are neutral and non-neutral, and which are made neutral\n\t// by mutationEffect() callbacks.  Note this block is the only place where is_pure_neutral_now_ is valid or used!!!\n\tif (skip_chromosomal_fitness)\n\t{\n\t\t// first set a flag on all mut types indicating whether they are pure neutral according to their DFE\n\t\tfor (auto &mut_type_iter : mut_types)\n\t\t\tmut_type_iter.second->is_pure_neutral_now_ = mut_type_iter.second->all_pure_neutral_DFE_;\n\t\t\n\t\t// then go through the mutationEffect() callback list and set the pure neutral flag for mut types neutralized by an active callback\n\t\tfor (SLiMEidosBlock *mutationEffect_callback : p_mutationEffect_callbacks)\n\t\t{\n\t\t\tif (mutationEffect_callback->block_active_)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *compound_statement_node = mutationEffect_callback->compound_statement_node_;\n\t\t\t\t\n\t\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t\t{\n\t\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\"\n\t\t\t\t\tEidosValue *result = compound_statement_node->cached_return_value_.get();\n\t\t\t\t\t\n\t\t\t\t\tif ((result->Type() == EidosValueType::kValueFloat) && (result->Count() == 1))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result->FloatData()[0] == 1.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the callback returns 1.0, so it makes the mutation types to which it applies become neutral\n\t\t\t\t\t\t\tslim_objectid_t mutation_type_id = mutationEffect_callback->mutation_type_id_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (mutation_type_id == -1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto &mut_type_iter : mut_types)\n\t\t\t\t\t\t\t\t\tmut_type_iter.second->is_pure_neutral_now_ = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n                                MutationType *found_muttype = species_.MutationTypeWithID(mutation_type_id);\n                                \n\t\t\t\t\t\t\t\tif (found_muttype)\n\t\t\t\t\t\t\t\t\tfound_muttype->is_pure_neutral_now_ = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// if we reach this point, we have an active callback that is not neutral-making, so we fail and we're done\n\t\t\t\tskip_chromosomal_fitness = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// finally, tabulate the pure-neutral flags of all the mut types into an overall flag for whether we can skip\n\t\tif (skip_chromosomal_fitness)\n\t\t{\n\t\t\tfor (auto &mut_type_iter : mut_types)\n\t\t\t{\n\t\t\t\tif (!mut_type_iter.second->is_pure_neutral_now_)\n\t\t\t\t{\n\t\t\t\t\tskip_chromosomal_fitness = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// At this point, there is an active callback that is not neutral-making, so we really can't reliably depend\n\t\t\t// upon is_pure_neutral_now_; that rogue callback could make other callbacks active/inactive, etc.  So in\n\t\t\t// principle we should now go through and clear the is_pure_neutral_now_ flags to avoid any confusion.  But\n\t\t\t// we are the only ones to use is_pure_neutral_now_, and we're done using it, so we can skip that work.\n\t\t\t\n\t\t\t//for (auto &mut_type_iter : mut_types)\n\t\t\t//\tmut_type_iter.second->is_pure_neutral_now_ = false;\n\t\t}\n\t}\n\t\n\t// Figure out global callbacks; these are callbacks with NULL supplied for the mut-type id, which means that they are called\n\t// exactly once per individual, for every individual regardless of genetics, to provide an entry point for alternate fitness definitions\n\tint fitnessEffect_callback_count = (int)p_fitnessEffect_callbacks.size();\n\tbool fitnessEffect_callbacks_exist = (fitnessEffect_callback_count > 0);\n\t\n\t// We optimize the pure neutral case, as long as no mutationEffect() or fitnessEffect() callbacks are defined; fitness values are then simply 1.0, for everybody.\n\t// BCH 12 Jan 2018: now fitness_scaling_ modifies even pure_neutral_ models, but the framework here remains valid\n\tbool pure_neutral = (!mutationEffect_callbacks_exist && !fitnessEffect_callbacks_exist && species_.pure_neutral_);\n\tdouble subpop_fitness_scaling = subpop_fitness_scaling_;\n\t\n\t// Reset our override of individual cached fitness values; we make this decision afresh with each UpdateFitness() call.  See\n\t// the header for further comments on this mechanism.\n\tindividual_cached_fitness_OVERRIDE_ = false;\n\t\n\t// Decide whether we need to shuffle the order of operations.  This occurs only if (a) we have mutationEffect() or fitnessEffect() callbacks\n\t// that are enabled, and (b) at least one of them has no cached optimization set.  Otherwise, the order of operations doesn't matter.\n\tbool needs_shuffle = false;\n\t\n\tif (species_.RandomizingCallbackOrder())\n\t{\n\t\tif (!needs_shuffle)\n\t\t\tfor (SLiMEidosBlock *callback : p_fitnessEffect_callbacks)\n\t\t\t\tif (!callback->compound_statement_node_->cached_return_value_ && !callback->has_cached_optimization_)\n\t\t\t\t{\n\t\t\t\t\tneeds_shuffle = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\n\t\tif (!needs_shuffle)\n\t\t\tfor (SLiMEidosBlock *callback : p_mutationEffect_callbacks)\n\t\t\t\tif (!callback->compound_statement_node_->cached_return_value_ && !callback->has_cached_optimization_)\n\t\t\t\t{\n\t\t\t\t\tneeds_shuffle = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t}\n\t\n\t// determine the templated version of FitnessOfParent() that we will call out to for fitness evaluation\n\t// see Population::EvolveSubpopulation() for further comments on this optimization technique\n\tbool mutrun_exp_timing_per_individual = species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() > 1);\n\tdouble (Subpopulation::*FitnessOfParent_TEMPLATED)(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\t\n\tif (mutrun_exp_timing_per_individual)\n\t{\n\t\t// If *any* chromosome is doing mutrun experiments, we can't template them out\n\t\tif (!mutationEffect_callbacks_exist)\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<true, false, false>;\n\t\telse if (single_mutationEffect_callback)\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<true, true, true>;\n\t\telse\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<true, true, false>;\n\t}\n\telse\n\t{\n\t\tif (!mutationEffect_callbacks_exist)\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<false, false, false>;\n\t\telse if (single_mutationEffect_callback)\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<false, true, true>;\n\t\telse\n\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent<false, true, false>;\n\t}\n\t\n\t// refine the above choice with a custom version of optimizations for simple cases\n\tif (!mutrun_exp_timing_per_individual && !mutationEffect_callbacks_exist && (species_.Chromosomes().size() == 1))\n\t{\n\t\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\t\n\t\tswitch (chromosome->Type())\n\t\t{\n\t\t\t\t// diploid, possibly with one or both being null haplosomes\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent_1CH_Diploid;\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\t// haploid, possibly null\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t\tFitnessOfParent_TEMPLATED = &Subpopulation::FitnessOfParent_1CH_Haploid;\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t// Mutrun experiment timing can be per-individual, per-chromosome, but that entails a lot of timing overhead.\n\t// To avoid that overhead, in single-chromosome models we just time across the whole round of fitness evals\n\t// instead.  Note that in this case we chose a template above for FitnessOfParent() that does not time.\n\t// FIXME 4/14/2025: It remains true that in multi-chrom models the timing overhead will be very high.  There\n\t// are various ways that could potentially be cut down.  (a) not measure in every tick, (b) stop measuring\n\t// once you've settled down into stasis, (c) measure a subset of all fitness evals.  This should be done in\n\t// future, but we're out of time for now.\n\tif (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))\n\t\tspecies_.Chromosomes()[0]->StartMutationRunExperimentClock();\n\t\n\t// calculate fitnesses in parent population and cache the values\n\tif (sex_enabled_)\n\t{\n\t\t// SEX ONLY\n\t\tdouble totalMaleFitness = 0.0, totalFemaleFitness = 0.0;\n\t\t\n\t\t// Set up to draw random females\n\t\tif (pure_neutral)\n\t\t{\n\t\t\tif (Individual::s_any_individual_fitness_scaling_set_)\n\t\t\t{\n\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_1);\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_1);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(subpop_fitness_scaling) reduction(+: totalFemaleFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_1) num_threads(thread_count)\n\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = 1.0;\n#endif\n\t\t\t\t\n\t\t\t\tdouble fitness = subpop_fitness_scaling;\t// no individual fitness_scaling_\n\t\t\t\t\n\t\t\t\t// Here we override setting up every cached_fitness_UNSAFE_ value, and set up a subpop-level cache instead.\n\t\t\t\t// This is why cached_fitness_UNSAFE_ is marked \"UNSAFE\".  See the header for details on this.\n\t\t\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\t\t{\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_ = true;\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_value_ = fitness;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_2);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_2);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(fitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_2) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_2);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttotalFemaleFitness = fitness * parent_first_male_index_;\n\t\t\t}\n\t\t}\n\t\telse if (skip_chromosomal_fitness)\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, female_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for females without chromosomal fitness; shuffle buffer needed\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_first_male_index_);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_first_male_index_; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t female_index = shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, female_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\t// FIXME should have some additional criterion for whether to go parallel with this, like the number of mutations\n\t\t\t\tif (!mutationEffect_callbacks_exist && !fitnessEffect_callbacks_exist)\n\t\t\t\t{\n\t\t\t\t\t// a separate loop for parallelization of the no-callback case\n\t\t\t\t\t\n#if (defined(_OPENMP) && SLIM_USE_NONNEUTRAL_CACHES)\n\t\t\t\t\t// we need to fix the nonneutral caches in a separate pass first\n\t\t\t\t\t// because all the correct caches need to get flushed to everyone\n\t\t\t\t\t// before beginning fitness evaluation, for efficiency\n\t\t\t\t\t// beginend_nonneutral_pointers() handles the non-parallel case\n\t\t\t\t\tFixNonNeutralCaches_OMP();\n#endif\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_3);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_3);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(parent_first_male_index_, subpop_fitness_scaling) reduction(+: totalFemaleFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_3) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(female_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_3);\n\t\t\t\t}\n\t\t\t\telse\t// at least one mutationEffect() or fitnessEffect() callback; not parallelized\n\t\t\t\t{\n\t\t\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(female_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, female_index);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for females; we use the shuffle buffer to randomize processing order\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_first_male_index_);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_first_male_index_; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t female_index = shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[female_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(female_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, female_index);\n\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[female_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tparent_individuals_[female_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFemaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\t\n\t\ttotalFitness += totalFemaleFitness;\n\t\tif ((model_type_ == SLiMModelType::kModelTypeWF) && (totalFemaleFitness <= 0.0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateFitness): total fitness of females is <= 0.0.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Set up to draw random males\n\t\tif (pure_neutral)\n\t\t{\n\t\t\tif (Individual::s_any_individual_fitness_scaling_set_)\n\t\t\t{\n\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_1);\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_1);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(subpop_fitness_scaling) reduction(+: totalMaleFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_1) num_threads(thread_count)\n\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = 1.0;\n#endif\n\t\t\t\t\n\t\t\t\tdouble fitness = subpop_fitness_scaling;\t// no individual fitness_scaling_\n\t\t\t\t\n\t\t\t\t// Here we override setting up every cached_fitness_UNSAFE_ value, and set up a subpop-level cache instead.\n\t\t\t\t// This is why cached_fitness_UNSAFE_ is marked \"UNSAFE\".  See the header for details on this.\n\t\t\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\t\t{\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_ = true;\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_value_ = fitness;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_2);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_2);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(fitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_2) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_2);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (parent_subpop_size_ > parent_first_male_index_)\n\t\t\t\t\ttotalMaleFitness = fitness * (parent_subpop_size_ - parent_first_male_index_);\n\t\t\t}\n\t\t}\n\t\telse if (skip_chromosomal_fitness)\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, male_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for females without chromosomal fitness; shuffle buffer needed\n\t\t\t\tslim_popsize_t male_count = parent_subpop_size_ - parent_first_male_index_;\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(male_count);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < male_count; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t male_index = parent_first_male_index_ + shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, male_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\t// FIXME should have some additional criterion for whether to go parallel with this, like the number of mutations\n\t\t\t\tif (!mutationEffect_callbacks_exist && !fitnessEffect_callbacks_exist)\n\t\t\t\t{\n\t\t\t\t\t// a separate loop for parallelization of the no-callback case\n\t\t\t\t\t// note that we rely on the fixup of non-neutral caches done above\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_SEX_3);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_SEX_3);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(parent_first_male_index_, parent_subpop_size_, subpop_fitness_scaling) reduction(+: totalMaleFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_SEX_3) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(male_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_SEX_3);\n\t\t\t\t}\n\t\t\t\telse\t// at least one mutationEffect() or fitnessEffect() callback; not parallelized\n\t\t\t\t{\n\t\t\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(male_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, male_index);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for males; we use the shuffle buffer to randomize processing order\n\t\t\t\tslim_popsize_t male_count = parent_subpop_size_ - parent_first_male_index_;\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(male_count);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < male_count; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t male_index = parent_first_male_index_ + shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[male_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(male_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, male_index);\n\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[male_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tparent_individuals_[male_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalMaleFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\t\n\t\ttotalFitness += totalMaleFitness;\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tif (totalMaleFitness <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateFitness): total fitness of males is <= 0.0.\" << EidosTerminate(nullptr);\n\t\t\tif (!std::isfinite(totalFitness))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateFitness): total fitness of subpopulation is not finite; numerical error will prevent accurate simulation.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (pure_neutral)\n\t\t{\n\t\t\tif (Individual::s_any_individual_fitness_scaling_set_)\n\t\t\t{\n\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_ASEX_1);\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_ASEX_1);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(subpop_fitness_scaling) reduction(+: totalFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_ASEX_1) num_threads(thread_count)\n\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t}\n\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_ASEX_1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = 1.0;\n#endif\n\t\t\t\t\n\t\t\t\tdouble fitness = subpop_fitness_scaling;\t// no individual fitness_scaling_\n\t\t\t\t\n\t\t\t\t// Here we override setting up every cached_fitness_UNSAFE_ value, and set up a subpop-level cache instead.\n\t\t\t\t// This is why cached_fitness_UNSAFE_ is marked \"UNSAFE\".  See the header for details on this.\n\t\t\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t\t\t{\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_ = true;\n\t\t\t\t\tindividual_cached_fitness_OVERRIDE_value_ = fitness;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_ASEX_2);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_ASEX_2);\n#pragma omp parallel for schedule(static) default(none) shared(parent_subpop_size_) firstprivate(fitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_ASEX_2) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_ASEX_2);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\ttotalFitness = fitness * parent_subpop_size_;\n\t\t\t}\n\t\t}\n\t\telse if (skip_chromosomal_fitness)\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t{\n\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, individual_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for hermaphrodites without chromosomal fitness; shuffle buffer needed\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_subpop_size_);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_subpop_size_; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t individual_index = shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, individual_index);\n\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!needs_shuffle)\n\t\t\t{\n\t\t\t\t// FIXME should have some additional criterion for whether to go parallel with this, like the number of mutations\n\t\t\t\tif (!mutationEffect_callbacks_exist && !fitnessEffect_callbacks_exist)\n\t\t\t\t{\n\t\t\t\t\t// a separate loop for parallelization of the no-callback case\n\t\t\t\t\t\n#if (defined(_OPENMP) && SLIM_USE_NONNEUTRAL_CACHES)\n\t\t\t\t\t// we need to fix the nonneutral caches in a separate pass first\n\t\t\t\t\t// because all the correct caches need to get flushed to everyone\n\t\t\t\t\t// before beginning fitness evaluation, for efficiency\n\t\t\t\t\t// beginend_nonneutral_pointers() handles the non-parallel case\n\t\t\t\t\tFixNonNeutralCaches_OMP();\n#endif\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_FITNESS_ASEX_3);\n\t\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FITNESS_ASEX_3);\n#pragma omp parallel for schedule(dynamic, 16) default(none) shared(parent_subpop_size_, subpop_fitness_scaling) reduction(+: totalFitness) if(parent_subpop_size_ >= EIDOS_OMPMIN_FITNESS_ASEX_3) num_threads(thread_count)\n\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(individual_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_FITNESS_ASEX_3);\n\t\t\t\t}\n\t\t\t\telse\t// at least one mutationEffect() or fitnessEffect() callback; not parallelized\n\t\t\t\t{\n\t\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < parent_subpop_size_; individual_index++)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(individual_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, individual_index);\n\t\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// general case for hermaphrodites; we use the shuffle buffer to randomize processing order\n\t\t\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_subpop_size_);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_subpop_size_; shuffle_index++)\n\t\t\t\t{\n\t\t\t\t\tslim_popsize_t individual_index = shuffle_buf[shuffle_index];\n\t\t\t\t\tdouble fitness = parent_individuals_[individual_index]->fitness_scaling_;\n\t\t\t\t\t\n\t\t\t\t\tif (fitness > 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfitness *= (this->*FitnessOfParent_TEMPLATED)(individual_index, p_mutationEffect_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// multiply in the effects of any fitnessEffect() callbacks\n\t\t\t\t\t\tif (fitnessEffect_callbacks_exist && (fitness > 0.0))\n\t\t\t\t\t\t\tfitness *= ApplyFitnessEffectCallbacks(p_fitnessEffect_callbacks, individual_index);\n\t\t\t\t\t\t\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tfitness *= subpop_fitness_scaling;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n#ifdef SLIMGUI\n\t\t\t\t\t\tparent_individuals_[individual_index]->cached_unscaled_fitness_ = fitness;\n#endif\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tparent_individuals_[individual_index]->cached_fitness_UNSAFE_ = fitness;\n\t\t\t\t\ttotalFitness += fitness;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tspecies_.ReturnShuffleBuffer();\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\t{\n\t\t\tif (totalFitness <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateFitness): total fitness of all individuals is <= 0.0.\" << EidosTerminate(nullptr);\n\t\t\tif (!std::isfinite(totalFitness))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateFitness): total fitness of subpopulation is not finite; numerical error will prevent accurate simulation.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\t// Mutrun experiment timing can be per-individual, per-chromosome, but that entails a lot of timing overhead.\n\t// To avoid that overhead, in single-chromosome models we just time across the whole round of fitness evals\n\t// instead.  Note that in this case we chose a template above for FitnessOfParent() that does not time.\n\tif (species_.DoingAnyMutationRunExperiments() && (species_.Chromosomes().size() == 1))\n\t\tspecies_.Chromosomes()[0]->StopMutationRunExperimentClock(\"UpdateFitness()\");\n\t\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tUpdateWFFitnessBuffers(pure_neutral && !Individual::s_any_individual_fitness_scaling_set_);\n}\n\n// WF only:\nvoid Subpopulation::UpdateWFFitnessBuffers(bool p_pure_neutral)\n{\n\t// This is called only by UpdateFitness(), after the fitness of all individuals has been updated, and only in WF models.\n\t// It updates the cached_parental_fitness_ and cached_male_fitness_ buffers, and then generates new lookup tables for mate choice.\n\t\n\t// Reallocate the fitness buffers to be large enough\n\tif (cached_fitness_capacity_ < parent_subpop_size_)\n\t{\n\t\tcached_parental_fitness_ = (double *)realloc(cached_parental_fitness_, sizeof(double) * parent_subpop_size_);\n\t\tif (!cached_parental_fitness_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateWFFitnessBuffers): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (sex_enabled_)\n\t\t{\n\t\t\tcached_male_fitness_ = (double *)realloc(cached_male_fitness_, sizeof(double) * parent_subpop_size_);\n\t\t\tif (!cached_male_fitness_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::UpdateWFFitnessBuffers): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tcached_fitness_capacity_ = parent_subpop_size_;\n\t}\n\t\n\t// Set up the fitness buffers with the new information\n\tif (individual_cached_fitness_OVERRIDE_)\n\t{\n\t\t// This is the optimized case, where all individuals have the same fitness and it is cached at the subpop level\n\t\tdouble universal_cached_fitness = individual_cached_fitness_OVERRIDE_value_;\n\t\t\n\t\tif (sex_enabled_)\n\t\t{\n\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t{\n\t\t\t\tcached_parental_fitness_[female_index] = universal_cached_fitness;\n\t\t\t\tcached_male_fitness_[female_index] = 0;\n\t\t\t}\n\t\t\t\n\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t{\n\t\t\t\tcached_parental_fitness_[male_index] = universal_cached_fitness;\n\t\t\t\tcached_male_fitness_[male_index] = universal_cached_fitness;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (slim_popsize_t i = 0; i < parent_subpop_size_; i++)\n\t\t\t\tcached_parental_fitness_[i] = universal_cached_fitness;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// This is the normal case, where cached_fitness_UNSAFE_ has the cached fitness values for each individual\n\t\tif (sex_enabled_)\n\t\t{\n\t\t\tfor (slim_popsize_t female_index = 0; female_index < parent_first_male_index_; female_index++)\n\t\t\t{\n\t\t\t\tdouble fitness = parent_individuals_[female_index]->cached_fitness_UNSAFE_;\n\t\t\t\t\n\t\t\t\tcached_parental_fitness_[female_index] = fitness;\n\t\t\t\tcached_male_fitness_[female_index] = 0;\n\t\t\t}\n\t\t\t\n\t\t\tfor (slim_popsize_t male_index = parent_first_male_index_; male_index < parent_subpop_size_; male_index++)\n\t\t\t{\n\t\t\t\tdouble fitness = parent_individuals_[male_index]->cached_fitness_UNSAFE_;\n\t\t\t\t\n\t\t\t\tcached_parental_fitness_[male_index] = fitness;\n\t\t\t\tcached_male_fitness_[male_index] = fitness;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (slim_popsize_t i = 0; i < parent_subpop_size_; i++)\n\t\t\t\tcached_parental_fitness_[i] = parent_individuals_[i]->cached_fitness_UNSAFE_;\n\t\t}\n\t}\n\t\n\tcached_fitness_size_ = parent_subpop_size_;\n\t\n\t// Remake our mate-choice lookup tables\n\tif (sex_enabled_)\n\t{\n\t\t// throw out the old tables\n\t\tif (lookup_female_parent_)\n\t\t{\n\t\t\tgsl_ran_discrete_free(lookup_female_parent_);\n\t\t\tlookup_female_parent_ = nullptr;\n\t\t}\n\t\t\n\t\tif (lookup_male_parent_)\n\t\t{\n\t\t\tgsl_ran_discrete_free(lookup_male_parent_);\n\t\t\tlookup_male_parent_ = nullptr;\n\t\t}\n\t\t\n\t\t// in pure neutral models we don't set up the discrete preproc\n\t\tif (!p_pure_neutral)\n\t\t{\n\t\t\tlookup_female_parent_ = gsl_ran_discrete_preproc(parent_first_male_index_, cached_parental_fitness_);\n\t\t\tlookup_male_parent_ = gsl_ran_discrete_preproc(parent_subpop_size_ - parent_first_male_index_, cached_parental_fitness_ + parent_first_male_index_);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// throw out the old tables\n\t\tif (lookup_parent_)\n\t\t{\n\t\t\tgsl_ran_discrete_free(lookup_parent_);\n\t\t\tlookup_parent_ = nullptr;\n\t\t}\n\t\t\n\t\t// in pure neutral models we don't set up the discrete preproc\n\t\tif (!p_pure_neutral)\n\t\t{\n\t\t\tlookup_parent_ = gsl_ran_discrete_preproc(parent_subpop_size_, cached_parental_fitness_);\n\t\t}\n\t}\n}\n\ndouble Subpopulation::ApplyMutationEffectCallbacks(MutationIndex p_mutation, int p_homozygous, double p_computed_fitness, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks, Individual *p_individual)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyMutationEffectCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tslim_objectid_t mutation_type_id = (gSLiM_Mutation_Block + p_mutation)->mutation_type_ptr_->mutation_type_id_;\n\t\n\tfor (SLiMEidosBlock *mutationEffect_callback : p_mutationEffect_callbacks)\n\t{\n\t\tif (mutationEffect_callback->block_active_)\n\t\t{\n\t\t\tslim_objectid_t callback_mutation_type_id = mutationEffect_callback->mutation_type_id_;\n\t\t\t\n\t\t\tif ((callback_mutation_type_id == -1) || (callback_mutation_type_id == mutation_type_id))\n\t\t\t{\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t// SLiMgui debugging point\n\t\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\t\n\t\t\t\t{\n\t\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\t\tEidosToken *decl_token = mutationEffect_callback->root_node_->token_;\n\t\t\t\t\t\n\t\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t\t{\n\t\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG mutationEffect(m\" << mutationEffect_callback->mutation_type_id_;\n\t\t\t\t\t\tif (mutationEffect_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \", p\" << mutationEffect_callback->subpopulation_id_;\n\t\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutationEffect_callback->block_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << mutationEffect_callback->block_id_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\t\tindenter.indent();\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t\t\n\t\t\t\t// The callback is active and matches the mutation type id of the mutation, so we need to execute it\n\t\t\t\t// This code is similar to Population::ExecuteScript, but we set up an additional symbol table, and we use the return value\n\t\t\t\tconst EidosASTNode *compound_statement_node = mutationEffect_callback->compound_statement_node_;\n\t\t\t\t\n\t\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t\t{\n\t\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\", so we can short-circuit it completely\n\t\t\t\t\tEidosValue_SP result_SP = compound_statement_node->cached_return_value_;\n\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyMutationEffectCallbacks): mutationEffect() callbacks must provide a float singleton return value.\" << EidosTerminate(mutationEffect_callback->identifier_token_);\n\t\t\t\t\t\n#if DEBUG\n\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\tp_computed_fitness = result->FloatData()[0];\n#else\n\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\tp_computed_fitness = ((EidosValue_Float *)result)->data()[0];\n#endif\n\t\t\t\t\t\n\t\t\t\t\t// the cached value is owned by the tree, so we do not dispose of it\n\t\t\t\t\t// there is also no script output to handle\n\t\t\t\t}\n\t\t\t\telse if (mutationEffect_callback->has_cached_optimization_)\n\t\t\t\t{\n\t\t\t\t\t// We can special-case particular simple callbacks for speed.  This is similar to the cached_return_value_\n\t\t\t\t\t// mechanism above, but it is done in SLiM, not in Eidos, and is specific to callbacks, not general.\n\t\t\t\t\t// The has_cached_optimization_ flag is the umbrella flag for all such optimizations; we then figure\n\t\t\t\t\t// out below which cached optimization is in effect for this callback.  See Community::OptimizeScriptBlock()\n\t\t\t\t\t// for comments on the specific cases optimized here.\n\t\t\t\t\tif (mutationEffect_callback->has_cached_opt_reciprocal)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble A = mutationEffect_callback->cached_opt_A_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tp_computed_fitness = (A / p_computed_fitness);\t// p_computed_fitness is effect\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyMutationEffectCallbacks): (internal error) cached optimization flag mismatch\" << EidosTerminate(mutationEffect_callback->identifier_token_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// local variables for the callback parameters that we might need to allocate here, and thus need to free below\n\t\t\t\t\tEidosValue_Object local_mut(gSLiM_Mutation_Block + p_mutation, gSLiM_Mutation_Class);\n\t\t\t\t\tEidosValue_Float local_effect(p_computed_fitness);\n\t\t\t\t\t\n\t\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\t\tEidosInterpreter interpreter(mutationEffect_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (mutationEffect_callback->contains_self_)\n\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(mutationEffect_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\t\tif (mutationEffect_callback->contains_mut_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlocal_mut.StackAllocated();\t\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_mut, EidosValue_SP(&local_mut));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (mutationEffect_callback->contains_effect_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlocal_effect.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_effect, EidosValue_SP(&local_effect));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (mutationEffect_callback->contains_individual_)\n\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, p_individual->CachedEidosValue());\n\t\t\t\t\t\tif (mutationEffect_callback->contains_subpop_)\n\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, SymbolTableEntry().second);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// p_homozygous == -1 means the mutation faces a null haplosome; otherwise, 0 means heterozyg., 1 means homozyg.\n\t\t\t\t\t\t// that gets translated into Eidos values of NULL, F, and T, respectively\n\t\t\t\t\t\tif (mutationEffect_callback->contains_homozygous_)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (p_homozygous == -1)\n\t\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_homozygous, gStaticEidosValueNULL);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_homozygous, (p_homozygous != 0) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton double used as a new fitness value\n\t\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(mutationEffect_callback->script_);\n\t\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyMutationEffectCallbacks): mutationEffect() callbacks must provide a float singleton return value.\" << EidosTerminate(mutationEffect_callback->identifier_token_);\n\t\t\t\t\t\t\t\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tp_computed_fitness = result->FloatData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tp_computed_fitness = ((EidosValue_Float *)result)->data()[0];\n#endif\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (...)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthrow;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosMutationEffectCallback)]);\n#endif\n\t\n\treturn p_computed_fitness;\n}\n\ndouble Subpopulation::ApplyFitnessEffectCallbacks(std::vector<SLiMEidosBlock*> &p_fitnessEffect_callbacks, slim_popsize_t p_individual_index)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyFitnessEffectCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tdouble computed_fitness = 1.0;\n\tIndividual *individual = parent_individuals_[p_individual_index];\n\t\n\tfor (SLiMEidosBlock *fitnessEffect_callback : p_fitnessEffect_callbacks)\n\t{\n\t\tif (fitnessEffect_callback->block_active_)\n\t\t{\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = fitnessEffect_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG fitnessEffect(\";\n\t\t\t\t\tif (fitnessEffect_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << fitnessEffect_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << fitnessEffect_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\t\t\t\n\t\t\t// The callback is active, so we need to execute it\n\t\t\t// This code is similar to Population::ExecuteScript, but we set up an additional symbol table, and we use the return value\n\t\t\tconst EidosASTNode *compound_statement_node = fitnessEffect_callback->compound_statement_node_;\n\t\t\t\n\t\t\tif (compound_statement_node->cached_return_value_)\n\t\t\t{\n\t\t\t\t// The script is a constant expression such as \"{ return 1.1; }\", so we can short-circuit it completely\n\t\t\t\tEidosValue_SP result_SP = compound_statement_node->cached_return_value_;\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyFitnessEffectCallbacks): fitnessEffect() callbacks must provide a float singleton return value.\" << EidosTerminate(fitnessEffect_callback->identifier_token_);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// this checks the value type at runtime\n\t\t\t\tcomputed_fitness *= result->FloatData()[0];\n#else\n\t\t\t\t// unsafe cast for speed\n\t\t\t\tcomputed_fitness *= ((EidosValue_Float *)result)->data()[0];\n#endif\n\t\t\t\t\n\t\t\t\t// the cached value is owned by the tree, so we do not dispose of it\n\t\t\t\t// there is also no script output to handle\n\t\t\t}\n\t\t\telse if (fitnessEffect_callback->has_cached_optimization_)\n\t\t\t{\n\t\t\t\t// We can special-case particular simple callbacks for speed.  This is similar to the cached_return_value_\n\t\t\t\t// mechanism above, but it is done in SLiM, not in Eidos, and is specific to callbacks, not general.\n\t\t\t\t// The has_cached_optimization_ flag is the umbrella flag for all such optimizations; we then figure\n\t\t\t\t// out below which cached optimization is in effect for this callback.  See Community::OptimizeScriptBlock()\n\t\t\t\t// for comments on the specific cases optimized here.\n\t\t\t\tif (fitnessEffect_callback->has_cached_opt_dnorm1_)\n\t\t\t\t{\n\t\t\t\t\tdouble A = fitnessEffect_callback->cached_opt_A_;\n\t\t\t\t\tdouble B = fitnessEffect_callback->cached_opt_B_;\n\t\t\t\t\tdouble C = fitnessEffect_callback->cached_opt_C_;\n\t\t\t\t\tdouble D = fitnessEffect_callback->cached_opt_D_;\n\t\t\t\t\t\n\t\t\t\t\tcomputed_fitness *= (D + (gsl_ran_gaussian_pdf(individual->tagF_value_ - A, B) / C));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyFitnessEffectCallbacks): (internal error) cached optimization flag mismatch\" << EidosTerminate(fitnessEffect_callback->identifier_token_);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t{\n\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\tEidosInterpreter interpreter(fitnessEffect_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (fitnessEffect_callback->contains_self_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(fitnessEffect_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\n\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\tif (fitnessEffect_callback->contains_individual_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, individual->CachedEidosValue());\n\t\t\t\t\tif (fitnessEffect_callback->contains_subpop_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, SymbolTableEntry().second);\n\t\t\t\t\t\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton double used as a new fitness value\n\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(fitnessEffect_callback->script_);\n\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((result->Type() != EidosValueType::kValueFloat) || (result->Count() != 1))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyFitnessEffectCallbacks): fitnessEffect() callbacks must provide a float singleton return value.\" << EidosTerminate(fitnessEffect_callback->identifier_token_);\n\t\t\t\t\t\t\n#if DEBUG\n\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\tcomputed_fitness *= result->FloatData()[0];\n#else\n\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\tcomputed_fitness *= ((EidosValue_Float *)result)->data()[0];\n#endif\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\t// There is an error-reporting coordinate system problem here.  The error might have\n\t\t\t\t\t\t// occurred directly in the callback, or in something the callback called, like a\n\t\t\t\t\t\t// user-defined function or a lambda.  Also, we might have been called directly by\n\t\t\t\t\t\t// the SLiM core, and have the user script's coordinates set up, or the call to us\n\t\t\t\t\t\t// might have been triggered by a call like recalculateFitness() called in an event\n\t\t\t\t\t\t// or from a user-defined function.  So there are all sorts of possibilities on both\n\t\t\t\t\t\t// ends.  Since we didn't save and set the error context, the way calls to user-\n\t\t\t\t\t\t// defined functions and lambdas do (because it would be slow), we don't really have\n\t\t\t\t\t\t// a way to repair the situation now, I don't think.  We can't even tell whether\n\t\t\t\t\t\t// things are screwed up or not.  We will do nothing.  Most of the time, the error\n\t\t\t\t\t\t// was directly in our code and we were called by SLiM or an event, so everything\n\t\t\t\t\t\t// is in user script coordinates and we'll get away with it.  In very unusual\n\t\t\t\t\t\t// circumstances, the error position reported will be wrong in the GUI.  Fixing that\n\t\t\t\t\t\t// would require a total redesign of the error-tracking mechanism.  BCH 3/12/2025\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// If any callback puts us at or below zero, we can short-circuit the rest\n\t\t\tif (computed_fitness <= 0.0)\n\t\t\t{\n\t\t\t\tcomputed_fitness = 0.0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosFitnessEffectCallback)]);\n#endif\n\t\n\treturn computed_fitness;\n}\n\n// FitnessOfParent() has three templated versions, for no callbacks, a single callback, and multiple callbacks.  That\n// pattern extends downward to _Fitness_DiploidChromosome() and _Fitness_HaploidChromosome(), which is the level where\n// it actually matters; in FitnessOfParent() the template flags just get passed through.  The goal of this design is\n// twofold.  First, it allows the case without mutationEffect() callbacks to run at full speed.  Second, it allows the\n// single-callback case to be optimized in a special way.  When there is just a single callback, it usually refers to\n// a mutation type that is relatively uncommon.  The model might have neutral mutations in most cases, plus a rare\n// (or unique) mutation type that is subject to more complex selection, for example.  We can optimize that very common\n// case substantially by making the callout to ApplyMutationEffectCallbacks() only for mutations of the mutation type\n// that the callback modifies.  This pays off mostly when there are many common mutations with no callback, plus one\n// rare mutation type that has a callback.  A model of neutral drift across a long chromosome with a high mutation\n// rate, with an introduced beneficial mutation with a selection coefficient extremely close to 0, for example, would\n// hit this case hard and see a speedup of as much as 25%, so the additional complexity seems worth it (since that's\n// quite a realistic and common case).  The only unfortunate thing about this design is that p_mutationEffect_callbacks\n// has to get passed all the way down, even when we know we won't use it.  LTO might optimize that away, with luck.\ntemplate <const bool f_mutrunexps, const bool f_callbacks, const bool f_singlecallback>\ndouble Subpopulation::FitnessOfParent(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks)\n{\n\t// calculate the fitness of the individual at index p_individual_index in the parent population\n\t// this loops through all chromosomes, handling ploidy and callbacks as needed\n\tdouble w = 1.0;\n\tIndividual *individual = parent_individuals_[p_individual_index];\n\tint haplosome_index = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\tswitch (chromosome->Type())\n\t\t{\n\t\t\t\t// diploid, possibly with one or both being null haplosomes\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\tHaplosome *haplosome1 = individual->haplosomes_[haplosome_index];\n\t\t\t\tHaplosome *haplosome2 = individual->haplosomes_[haplosome_index+1];\n\t\t\t\t\n\t\t\t\tw *= _Fitness_DiploidChromosome<f_callbacks, f_singlecallback>(haplosome1, haplosome2, p_mutationEffect_callbacks);\n\t\t\t\tif (w <= 0.0) {\n\t\t\t\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"FitnessOfParent()\");\n\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thaplosome_index += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// haploid, possibly null\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = individual->haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tw *= _Fitness_HaploidChromosome<f_callbacks, f_singlecallback>(haplosome, p_mutationEffect_callbacks);\n\t\t\t\tif (w <= 0.0) {\n\t\t\t\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"FitnessOfParent()\");\n\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thaplosome_index += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// special cases: haploid but with an accompanying null\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = individual->haplosomes_[haplosome_index];\n\t\t\t\t\n\t\t\t\tw *= _Fitness_HaploidChromosome<f_callbacks, f_singlecallback>(haplosome, p_mutationEffect_callbacks);\n\t\t\t\tif (w <= 0.0) {\n\t\t\t\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"FitnessOfParent()\");\n\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thaplosome_index += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = individual->haplosomes_[haplosome_index+1];\n\t\t\t\t\n\t\t\t\tw *= _Fitness_HaploidChromosome<f_callbacks, f_singlecallback>(haplosome, p_mutationEffect_callbacks);\n\t\t\t\tif (w <= 0.0) {\n\t\t\t\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"FitnessOfParent()\");\n\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thaplosome_index += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"FitnessOfParent()\");\n\t}\n\t\n\treturn w;\n}\n\ntemplate double Subpopulation::FitnessOfParent<false, false, false>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::FitnessOfParent<false, true, false>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::FitnessOfParent<false, true, true>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::FitnessOfParent<true, false, false>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::FitnessOfParent<true, true, false>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::FitnessOfParent<true, true, true>(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\ndouble Subpopulation::FitnessOfParent_1CH_Diploid(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks)\n{\n\t// calculate the fitness of the individual at index p_individual_index in the parent population\n\t// this loops through all chromosomes, handling ploidy and callbacks as needed\n\tdouble w = 1.0;\n\tIndividual *individual = parent_individuals_[p_individual_index];\n\tconst int haplosome_index = 0;\n\t\n\t// diploid, possibly with one or both being null haplosomes\n\tHaplosome *haplosome1 = individual->haplosomes_[haplosome_index];\n\tHaplosome *haplosome2 = individual->haplosomes_[haplosome_index+1];\n\t\n\tw *= _Fitness_DiploidChromosome<false, false>(haplosome1, haplosome2, p_mutationEffect_callbacks);\n\tif (w <= 0.0)\n\t\treturn 0.0;\n\t\n\treturn w;\n}\n\ndouble Subpopulation::FitnessOfParent_1CH_Haploid(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks)\n{\n\t// calculate the fitness of the individual at index p_individual_index in the parent population\n\t// this loops through all chromosomes, handling ploidy and callbacks as needed\n\tdouble w = 1.0;\n\tIndividual *individual = parent_individuals_[p_individual_index];\n\tconst int haplosome_index = 0;\n\t\n\t// haploid, possibly null\n\tHaplosome *haplosome = individual->haplosomes_[haplosome_index];\n\t\n\tw *= _Fitness_HaploidChromosome<false, false>(haplosome, p_mutationEffect_callbacks);\n\tif (w <= 0.0)\n\t\treturn 0.0;\n\t\n\treturn w;\n}\n\ntemplate <const bool f_callbacks, const bool f_singlecallback>\ndouble Subpopulation::_Fitness_DiploidChromosome(Haplosome *haplosome1, Haplosome *haplosome2, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks)\n{\n\tdouble w = 1.0;\n\tbool haplosome1_null = haplosome1->IsNull();\n\tbool haplosome2_null = haplosome2->IsNull();\n\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\tint32_t nonneutral_change_counter = species_.nonneutral_change_counter_;\n\tint32_t nonneutral_regime = species_.last_nonneutral_regime_;\n#endif\n\t\n\t// resolve the mutation type for the single callback case; we don't pass this in to keep the non-callback case simple and fast\n\tMutationType *single_callback_mut_type;\n\t\n\tif (f_singlecallback)\n\t{\n\t\t// our caller already did this lookup, to select this case, so this lookup is guaranteed to succeed\n\t\tslim_objectid_t mutation_type_id = p_mutationEffect_callbacks[0]->mutation_type_id_;\n\t\t\n\t\tsingle_callback_mut_type = species_.MutationTypeWithID(mutation_type_id);\n\t}\n\t\n\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\n\tif (haplosome1_null && haplosome2_null)\n\t{\n\t\t// both haplosomes are null placeholders; no mutations, no fitness effects\n\t\treturn w;\n\t}\n\telse if (haplosome1_null || haplosome2_null)\n\t{\n\t\t// one haplosome is null, so we just need to scan through the non-null haplosome and account\n\t\t// for its mutations, including the hemizygous dominance coefficient\n\t\tconst Haplosome *haplosome = haplosome1_null ? haplosome2 : haplosome1;\n\t\tconst int32_t mutrun_count = haplosome->mutrun_count_;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\t\t// Cache non-neutral mutations and read from the non-neutral buffers\n\t\t\tconst MutationIndex *haplosome_iter, *haplosome_max;\n\t\t\t\n\t\t\tmutrun->beginend_nonneutral_pointers(&haplosome_iter, &haplosome_max, nonneutral_change_counter, nonneutral_regime);\n#else\n\t\t\t// Read directly from the MutationRun buffers\n\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\tconst MutationIndex *haplosome_max = mutrun->end_pointer_const();\n#endif\n\t\t\t\n\t\t\t// with an unpaired chromosome, we multiply each selection coefficient by the hemizygous dominance coefficient\n\t\t\t// this is for a single X chromosome in a male, for example; dosage compensation, as opposed to heterozygosity\n\t\t\twhile (haplosome_iter != haplosome_max)\n\t\t\t{\n\t\t\t\tMutationIndex haplosome_mutindex = *haplosome_iter++;\n\t\t\t\tMutation *mutation = mut_block_ptr + haplosome_mutindex;\n\t\t\t\t\n\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t{\n\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome_mutindex, -1, mutation->cached_one_plus_hemizygousdom_sel_, p_mutationEffect_callbacks, haplosome->individual_);\n\t\t\t\t\t\n\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tw *= mutation->cached_one_plus_hemizygousdom_sel_;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn w;\n\t}\n\telse\n\t{\n\t\t// both haplosomes are being modeled, so we need to scan through and figure out which mutations are heterozygous and which are homozygous\n\t\tconst int32_t mutrun_count = haplosome1->mutrun_count_;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun1 = haplosome1->mutruns_[run_index];\n\t\t\tconst MutationRun *mutrun2 = haplosome2->mutruns_[run_index];\n\t\t\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\t\t// Cache non-neutral mutations and read from the non-neutral buffers\n\t\t\tconst MutationIndex *haplosome1_iter, *haplosome2_iter, *haplosome1_max, *haplosome2_max;\n\t\t\t\n\t\t\tmutrun1->beginend_nonneutral_pointers(&haplosome1_iter, &haplosome1_max, nonneutral_change_counter, nonneutral_regime);\n\t\t\tmutrun2->beginend_nonneutral_pointers(&haplosome2_iter, &haplosome2_max, nonneutral_change_counter, nonneutral_regime);\n#else\n\t\t\t// Read directly from the MutationRun buffers\n\t\t\tconst MutationIndex *haplosome1_iter = mutrun1->begin_pointer_const();\n\t\t\tconst MutationIndex *haplosome2_iter = mutrun2->begin_pointer_const();\n\t\t\t\n\t\t\tconst MutationIndex *haplosome1_max = mutrun1->end_pointer_const();\n\t\t\tconst MutationIndex *haplosome2_max = mutrun2->end_pointer_const();\n#endif\n\t\t\t\n\t\t\t// first, handle the situation before either haplosome iterator has reached the end of its haplosome, for simplicity/speed\n\t\t\tif (haplosome1_iter != haplosome1_max && haplosome2_iter != haplosome2_max)\n\t\t\t{\n\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter, haplosome2_mutindex = *haplosome2_iter;\n\t\t\t\tslim_position_t haplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_, haplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tif (haplosome1_iter_position < haplosome2_iter_position)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Process a mutation in haplosome1 since it is leading\n\t\t\t\t\t\tMutation *mutation = mut_block_ptr + haplosome1_mutindex;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome1_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\t\t\treturn 0.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (haplosome1_iter_position > haplosome2_iter_position)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Process a mutation in haplosome2 since it is leading\n\t\t\t\t\t\tMutation *mutation = mut_block_ptr + haplosome2_mutindex;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome2_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\t\t\treturn 0.0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Look for homozygosity: haplosome1_iter_position == haplosome2_iter_position\n\t\t\t\t\t\tslim_position_t position = haplosome1_iter_position;\n\t\t\t\t\t\tconst MutationIndex *haplosome1_start = haplosome1_iter;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// advance through haplosome1 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationIndex *haplosome2_matchscan = haplosome2_iter; \n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// advance through haplosome2 with haplosome2_matchscan, looking for a match for the current mutation in haplosome1, to determine whether we are homozygous or not\n\t\t\t\t\t\t\twhile (haplosome2_matchscan != haplosome2_max && (mut_block_ptr + *haplosome2_matchscan)->position_ == position)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (haplosome1_mutindex == *haplosome2_matchscan)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// a match was found, so we multiply our fitness by the full selection coefficient\n\t\t\t\t\t\t\t\t\tMutation *mutation = mut_block_ptr + haplosome1_mutindex;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome1_mutindex, true, mutation->cached_one_plus_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\t\t\t\t\t\treturn 0.0;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tw *= mutation->cached_one_plus_sel_;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tgoto homozygousExit1;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thaplosome2_matchscan++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// no match was found, so we are heterozygous; we multiply our fitness by the selection coefficient and the dominance coefficient\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutation *mutation = mut_block_ptr + haplosome1_mutindex;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome1_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\t\t\t\t\treturn 0.0;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\thomozygousExit1:\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (++haplosome1_iter == haplosome1_max)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\thaplosome1_mutindex = *haplosome1_iter;\n\t\t\t\t\t\t\t\thaplosome1_iter_position = (mut_block_ptr + haplosome1_mutindex)->position_;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} while (haplosome1_iter_position == position);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// advance through haplosome2 as long as we remain at the same position, handling one mutation at a time\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst MutationIndex *haplosome1_matchscan = haplosome1_start; \n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// advance through haplosome1 with haplosome1_matchscan, looking for a match for the current mutation in haplosome2, to determine whether we are homozygous or not\n\t\t\t\t\t\t\twhile (haplosome1_matchscan != haplosome1_max && (mut_block_ptr + *haplosome1_matchscan)->position_ == position)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (haplosome2_mutindex == *haplosome1_matchscan)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// a match was found; we know this match was already found by the haplosome1 loop above, so our fitness has already been multiplied appropriately\n\t\t\t\t\t\t\t\t\tgoto homozygousExit2;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\thaplosome1_matchscan++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// no match was found, so we are heterozygous; we multiply our fitness by the selection coefficient and the dominance coefficient\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMutation *mutation = mut_block_ptr + haplosome2_mutindex;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome2_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\t\t\t\t\treturn 0.0;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\thomozygousExit2:\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (++haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\thaplosome2_mutindex = *haplosome2_iter;\n\t\t\t\t\t\t\t\thaplosome2_iter_position = (mut_block_ptr + haplosome2_mutindex)->position_;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} while (haplosome2_iter_position == position);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// break out if either haplosome has reached its end\n\t\t\t\t\t\tif (haplosome1_iter == haplosome1_max || haplosome2_iter == haplosome2_max)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} while (true);\n\t\t\t}\n\t\t\t\n\t\t\t// one or the other haplosome has now reached its end, so now we just need to handle the remaining mutations in the unfinished haplosome\n#if DEBUG\n\t\t\tassert(!(haplosome1_iter != haplosome1_max && haplosome2_iter != haplosome2_max));\n#endif\n\t\t\t\n\t\t\t// if haplosome1 is unfinished, finish it\n\t\t\twhile (haplosome1_iter != haplosome1_max)\n\t\t\t{\n\t\t\t\tMutationIndex haplosome1_mutindex = *haplosome1_iter++;\n\t\t\t\tMutation *mutation = mut_block_ptr + haplosome1_mutindex;\n\t\t\t\t\n\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t{\n\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome1_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\n\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// if haplosome2 is unfinished, finish it\n\t\t\twhile (haplosome2_iter != haplosome2_max)\n\t\t\t{\n\t\t\t\tMutationIndex haplosome2_mutindex = *haplosome2_iter++;\n\t\t\t\tMutation *mutation = mut_block_ptr + haplosome2_mutindex;\n\t\t\t\t\n\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t{\n\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome2_mutindex, false, mutation->cached_one_plus_dom_sel_, p_mutationEffect_callbacks, haplosome1->individual_);\n\t\t\t\t\t\n\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tw *= mutation->cached_one_plus_dom_sel_;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn w;\n\t}\n}\n\ntemplate double Subpopulation::_Fitness_DiploidChromosome<false, false>(Haplosome *haplosome1, Haplosome *haplosome2, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::_Fitness_DiploidChromosome<true, false>(Haplosome *haplosome1, Haplosome *haplosome2, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::_Fitness_DiploidChromosome<true, true>(Haplosome *haplosome1, Haplosome *haplosome2, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\ntemplate <const bool f_callbacks, const bool f_singlecallback>\ndouble Subpopulation::_Fitness_HaploidChromosome(Haplosome *haplosome, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks)\n{\n\tif (haplosome->IsNull())\n\t{\n\t\t// the haplosome is a null placeholder; no mutations, no fitness effects\n\t\treturn 1.0;\n\t}\n\telse\n\t{\n\t\t// we just need to scan through the haplosome and account for its mutations,\n\t\t// using the homozygous fitness effect (no dominance effects with haploidy)\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\tint32_t nonneutral_change_counter = species_.nonneutral_change_counter_;\n\t\tint32_t nonneutral_regime = species_.last_nonneutral_regime_;\n#endif\n\t\t\n\t\t// resolve the mutation type for the single callback case; we don't pass this in to keep the non-callback case simple and fast\n\t\tMutationType *single_callback_mut_type;\n\t\t\n\t\tif (f_singlecallback)\n\t\t{\n\t\t\t// our caller already did this lookup, to select this case, so this lookup is guaranteed to succeed\n\t\t\tslim_objectid_t mutation_type_id = p_mutationEffect_callbacks[0]->mutation_type_id_;\n\t\t\t\n\t\t\tsingle_callback_mut_type = species_.MutationTypeWithID(mutation_type_id);\n\t\t}\n\t\t\n\t\tMutation *mut_block_ptr = gSLiM_Mutation_Block;\n\t\tconst int32_t mutrun_count = haplosome->mutrun_count_;\n\t\tdouble w = 1.0;\n\t\t\n\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t{\n\t\t\tconst MutationRun *mutrun = haplosome->mutruns_[run_index];\n\t\t\t\n#if SLIM_USE_NONNEUTRAL_CACHES\n\t\t\t// Cache non-neutral mutations and read from the non-neutral buffers\n\t\t\tconst MutationIndex *haplosome_iter, *haplosome_max;\n\t\t\t\n\t\t\tmutrun->beginend_nonneutral_pointers(&haplosome_iter, &haplosome_max, nonneutral_change_counter, nonneutral_regime);\n#else\n\t\t\t// Read directly from the MutationRun buffers\n\t\t\tconst MutationIndex *haplosome_iter = mutrun->begin_pointer_const();\n\t\t\tconst MutationIndex *haplosome_max = mutrun->end_pointer_const();\n#endif\n\t\t\t\n\t\t\t// with a haploid chromosome, we use the homozygous fitness effect\n\t\t\twhile (haplosome_iter != haplosome_max)\n\t\t\t{\n\t\t\t\tMutationIndex haplosome_mutation = *haplosome_iter++;\n\t\t\t\tMutation *mutation = (mut_block_ptr + haplosome_mutation);\n\t\t\t\t\n\t\t\t\tif (f_callbacks && (!f_singlecallback || (mutation->mutation_type_ptr_ == single_callback_mut_type)))\n\t\t\t\t{\n\t\t\t\t\tw *= ApplyMutationEffectCallbacks(haplosome_mutation, -1, mutation->cached_one_plus_sel_, p_mutationEffect_callbacks, haplosome->individual_);\n\t\t\t\t\t\n\t\t\t\t\tif (w <= 0.0)\n\t\t\t\t\t\treturn 0.0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tw *= mutation->cached_one_plus_sel_;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn w;\n\t}\n}\n\ntemplate double Subpopulation::_Fitness_HaploidChromosome<false, false>(Haplosome *haplosome, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::_Fitness_HaploidChromosome<true, false>(Haplosome *haplosome, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\ntemplate double Subpopulation::_Fitness_HaploidChromosome<true, true>(Haplosome *haplosome, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\n// WF only:\nvoid Subpopulation::TallyLifetimeReproductiveOutput(void)\n{\n\tif (species_.PedigreesEnabled())\n\t{\n\t\tlifetime_reproductive_output_MH_.resize(0);\n\t\tlifetime_reproductive_output_F_.resize(0);\n\t\t\n\t\tif (species_.SexEnabled())\n\t\t{\n\t\t\tfor (Individual *ind : parent_individuals_)\n\t\t\t{\n\t\t\t\tif (ind->sex_ == IndividualSex::kFemale)\n\t\t\t\t\tlifetime_reproductive_output_F_.emplace_back(ind->reproductive_output_);\n\t\t\t\telse\n\t\t\t\t\tlifetime_reproductive_output_MH_.emplace_back(ind->reproductive_output_);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (Individual *ind : parent_individuals_)\n\t\t\t\tlifetime_reproductive_output_MH_.emplace_back(ind->reproductive_output_);\n\t\t}\n\t}\n}\n\nvoid Subpopulation::SwapChildAndParentHaplosomes(void)\n{\n\tbool will_need_new_children = false;\n\t\n\t// If there are any differences between the parent and child haplosome setups (due to change in subpop size, sex ratio, etc.), we will need to create new child haplosomes after swapping\n\t// This is because the parental haplosomes, which are based on the old parental values, will get swapped in to the children, but they will be out of date.\n\tif ((parent_subpop_size_ != child_subpop_size_) || (parent_sex_ratio_ != child_sex_ratio_) || (parent_first_male_index_ != child_first_male_index_))\n\t\twill_need_new_children = true;\n\t\n\t// Execute the swap of the individuals\n\tchild_individuals_.swap(parent_individuals_);\n\tcached_parent_individuals_value_.reset();\n\t\n\t// Clear out any dictionary values and color values stored in what are now the child individuals; since this is per-individual it\n\t// takes a significant amount of time, so we try to minimize the overhead by doing it only when these facilities have been used\n\t// BCH 6 April 2019: likewise, now, with resetting tags in individuals and haplosomes to the \"unset\" value\n\t// BCH 21 November 2020: likewise, now, for resetting reproductive output\n\tif (Individual::s_any_individual_dictionary_set_)\n\t{\n\t\tfor (Individual *child : child_individuals_)\n\t\t\tchild->RemoveAllKeys();\n\t\t\t// no call to ContentsChanged() here, for speed; we know child is a Dictionary not a DataFrame\n\t}\n\t\n\tif (Individual::s_any_individual_color_set_)\n\t{\n\t\tfor (Individual *child : child_individuals_)\n\t\t\tchild->ClearColor();\n\t}\n\t\n\tif (Individual::s_any_individual_tag_set_ || Individual::s_any_individual_tagF_set_)\n\t{\n\t\tfor (Individual *child : child_individuals_)\n\t\t{\n\t\t\tchild->tag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\t\tchild->tagF_value_ = SLIM_TAGF_UNSET_VALUE;\n\t\t}\n\t}\n\tif (Individual::s_any_individual_tagL_set_)\n\t{\n\t\tfor (Individual *child : child_individuals_)\n\t\t{\n\t\t\tchild->tagL0_set_ = false;\n\t\t\tchild->tagL1_set_ = false;\n\t\t\tchild->tagL2_set_ = false;\n\t\t\tchild->tagL3_set_ = false;\n\t\t\tchild->tagL4_set_ = false;\n\t\t}\n\t}\n\tif (Individual::s_any_haplosome_tag_set_)\n\t{\n\t\tint haplosome_count_per_individual = HaplosomeCountPerIndividual();\n\t\t\n\t\tfor (Individual *child : child_individuals_)\n\t\t{\n\t\t\tHaplosome **haplosomes = child->haplosomes_;\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t{\n\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\n\t\t\t\thaplosome->tag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (species_.PedigreesEnabled())\n\t{\n\t\tfor (Individual *child : child_individuals_)\n\t\t\tchild->reproductive_output_ = 0;\n\t}\n\t\n\t// The parents now have the values that used to belong to the children.\n\tparent_subpop_size_ = child_subpop_size_;\n\tparent_sex_ratio_ = child_sex_ratio_;\n\tparent_first_male_index_ = child_first_male_index_;\n\t\n\t// The parental haplosomes, which have now been swapped into the child haplosome vactor, no longer fit the bill.  We need to throw them out and generate new haplosome vectors.\n\tif (will_need_new_children)\n\t\tGenerateChildrenToFitWF();\n}\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nIndividual *Subpopulation::GenerateIndividualCrossed(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex)\n{\n\tSubpopulation &parent1_subpop = *p_parent1->subpopulation_;\n\tSubpopulation &parent2_subpop = *p_parent2->subpopulation_;\n\t\n#if DEBUG\n\tIndividualSex parent1_sex = p_parent1->sex_;\n\tIndividualSex parent2_sex = p_parent2->sex_;\n\t\n\tif ((sex_enabled_ && (parent1_sex != IndividualSex::kFemale)) || (!sex_enabled_ && (parent1_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): parent1 must be female in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((sex_enabled_ && (parent2_sex != IndividualSex::kMale)) || (!sex_enabled_ && (parent2_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): parent2 must be male in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((p_parent1->index_ == -1) || (p_parent2->index_ == -1))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1_subpop.species_ != &this->species_) || (&parent2_subpop.species_ != &this->species_))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): addCrossed() requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of each parent\n\tstd::vector<SLiMEidosBlock*> *parent1_recombination_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *parent2_recombination_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *parent1_mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *parent2_mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\tparent1_recombination_callbacks = &parent1_subpop.registered_recombination_callbacks_;\n\t\tparent2_recombination_callbacks = &parent2_subpop.registered_recombination_callbacks_;\n\t\tparent1_mutation_callbacks = &parent1_subpop.registered_mutation_callbacks_;\n\t\tparent2_mutation_callbacks = &parent2_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent1_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!parent1_recombination_callbacks->size()) parent1_recombination_callbacks = nullptr;\n\t\tif (!parent2_recombination_callbacks->size()) parent2_recombination_callbacks = nullptr;\n\t\tif (!parent1_mutation_callbacks->size()) parent1_mutation_callbacks = nullptr;\n\t\tif (!parent2_mutation_callbacks->size()) parent2_mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Create the offspring and record it\n\tIndividual *individual = NewSubpopIndividual(/* index */ -1, p_child_sex, /* age */ 0, /* fitness */ NAN, /* p_mean_parent_age */ (p_parent1->age_ + (float)p_parent2->age_) / 2.0F);\n\t\n\tslim_pedigreeid_t individual_pid = f_pedigree_rec ? SLiM_GetNextPedigreeID() : 0;\n\t\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Biparental(individual_pid, *p_parent1, *p_parent2);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the first parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent1);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t// each haplosome is generated by recombination between a pair of parental haplosomes\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 1 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 1 copy 2\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, parent1_recombination_callbacks, parent1_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 2 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 2 copy 2\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, parent2_recombination_callbacks, parent2_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t{\n\t\t\t\t// the haplosome is generated by recombination between the haplosomes of the two parents\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 1 copy\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 2 copy\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, parent1_recombination_callbacks, parent1_mutation_callbacks);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t{\n\t\t\t\t// one X comes from recombination from the female parent, the other (to females only) clonally from the male parent\n\t\t\t\t// so females are XX, males are X-\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's X 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// female's X 2\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, parent1_recombination_callbacks, parent1_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t// male's X (from female)\n\t\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parent2_mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t// male's - (from male)\n\t\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t{\n\t\t\t\t// the Y comes (to males only) clonally from the male parent\n\t\t\t\t// so females are -, males are Y\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's Y\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent2_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's -\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\t// one Z comes (to males only) clonally from the female parent, the other from recombination from the male parent\n\t\t\t\t// so females are -Z, males are ZZ (note we think of it as WZ, not ZW, since the female parent is always the first parent)\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t// female's Z\n\t\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome2, parent1_mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t// female's -\n\t\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's Z\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// male's Z\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, parent2_recombination_callbacks, parent2_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t{\n\t\t\t\t// the W comes (to females only) clonally from the female parent\n\t\t\t\t// so females are W, males are -\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's W\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent1_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's -\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t{\n\t\t\t\t// haploid, inherited clonally from the female for both sexes, like the W for females\n\t\t\t\t// BCH 27 August 2025: note that we now allow HF in non-sexual models; \"female\" here is the first parent\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's copy\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent1_mutation_callbacks);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t{\n\t\t\t\t// this comes (to females only) clonally from the female parent, just like a W\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's copy\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent1_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's -\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t{\n\t\t\t\t// haploid, inherited clonally from the male for both sexes, like the Y for males\n\t\t\t\t// BCH 27 August 2025: note that we now allow HM in non-sexual models; \"male\" here is the second parent\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's copy\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent2_mutation_callbacks);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t{\n\t\t\t\t// this comes (to males only) clonally from the male parent, just like a Y\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's copy\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parent2_mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's -\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCrossed): chromosome type 'H-' does not allow reproduction by biparental cross (only cloning); chromosome type 'H' provides greater flexibility for modeling haploids.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 1 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 2 copy 1\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, parental_haplosome2, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// male's Y\n\t\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, parent2_mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// female's -\n\t\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"GenerateIndividualCrossed()\");\n\t\t\n\t\t// For each haplosome generated, we need to add them to the individual.  We also need\n\t\t// to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome1, currentHaplosomeIndex);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = individual_pid * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, currentHaplosomeIndex+1);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = individual_pid * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t\t\n\t\t// move forward 1 or 2 indices in haplosomes_, depending on whether a haplosome2 was created (even if it is null)\n\t\tcurrentHaplosomeIndex += (haplosome2 ? 2 : 1);\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent1, p_parent2, /* p_is_selfing */ false, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ nullptr, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Biparental(*p_parent1, *p_parent2);\n\t\t\t\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\tindividual = nullptr;\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t}\n\t}\n\t\n\treturn individual;\n}\n\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, false, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, false, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, false, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, false, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, true, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, true, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, true, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, false, true, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, false, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, false, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, false, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, false, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, true, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, true, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, true, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<false, true, true, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, false, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, false, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, false, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, false, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, true, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, true, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, true, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, false, true, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, false, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, false, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, false, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, false, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, true, false, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, true, false, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, true, true, false>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate Individual *Subpopulation::GenerateIndividualCrossed<true, true, true, true, true>(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nIndividual *Subpopulation::GenerateIndividualSelfed(Individual *p_parent)\n{\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n#if DEBUG\n\tIndividualSex parent_sex = p_parent->sex_;\n\t\n\tif (parent_sex != IndividualSex::kHermaphrodite)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualSelfed): parent must be hermaphroditic.\" << EidosTerminate();\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualSelfed): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualSelfed): addSelfed() requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of each parent\n\tstd::vector<SLiMEidosBlock*> *recombination_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\trecombination_callbacks = &parent_subpop.registered_recombination_callbacks_;\n\t\tmutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!recombination_callbacks->size()) recombination_callbacks = nullptr;\n\t\tif (!mutation_callbacks->size()) mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Create the offspring and record it\n\tIndividual *individual = NewSubpopIndividual(/* index */ -1, IndividualSex::kHermaphrodite, /* age */ 0, /* fitness */ NAN, /* p_mean_parent_age */ p_parent->age_);\n\t\n\tslim_pedigreeid_t individual_pid = f_pedigree_rec ? SLiM_GetNextPedigreeID() : 0;\n\t\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(individual_pid, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualSelfed): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t// each haplosome is generated by recombination between the pair of parental haplosomes\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t\t\t// parent copy 1\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\t\t// parent copy 2\n\t\t\t\t\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t\n\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t{\n\t\t\t\t// the haplosome is generated by recombination between the haplosome of the parent and itself\n\t\t\t\t// but since the one haplosome is identical to itself, that is the same thing as cloning\n\t\t\t\t// BCH 27 August 2025: Note that HF and HM are now treated here also; they would always be clonal\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent copy\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualSelfed): chromosome type 'H-' does not allow reproduction by selfing (only cloning); chromosome type 'H' provides greater flexibility for modeling haploids.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualEmpty): (internal error) sex-specific chromosome type not supported for selfing.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"GenerateIndividualSelfed()\");\n\t\t\n\t\t// For each haplosome generated, we need to add them to the individual.  We also need\n\t\t// to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome1, currentHaplosomeIndex);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = individual_pid * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, currentHaplosomeIndex+1);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = individual_pid * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t\t\n\t\t// move forward 1 or 2 indices in haplosomes_, depending on whether a haplosome2 was created (even if it is null)\n\t\tcurrentHaplosomeIndex += (haplosome2 ? 2 : 1);\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent, p_parent, /* p_is_selfing */ true, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ &parent_subpop, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Uniparental(*p_parent);\n\t\t\t\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\tindividual = nullptr;\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t}\n\t}\n\t\n\treturn individual;\n}\n\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, false, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<false, true, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, false, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualSelfed<true, true, true, true, true>(Individual *p_parent);\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nIndividual *Subpopulation::GenerateIndividualCloned(Individual *p_parent)\n{\n\tIndividualSex parent_sex = p_parent->sex_;\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n#if DEBUG\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCloned): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCloned): addCloned() requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of each parent\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\tmutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!mutation_callbacks->size()) mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Create the offspring and record it\n\tIndividual *individual = NewSubpopIndividual(/* index */ -1, parent_sex, /* age */ 0, /* fitness */ NAN, /* p_mean_parent_age */ p_parent->age_);\n\t\n\tslim_pedigreeid_t individual_pid = f_pedigree_rec ? SLiM_GetNextPedigreeID() : 0;\n\t\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(individual_pid, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualCloned): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\t// We just faithfully clone the existing haplosomes of the parent, regardless of type\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tif (chromosome->IntrinsicPloidy() == 2)\n\t\t{\n\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\n\t\t\tif (parental_haplosome1->IsNull())\n\t\t\t{\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t}\n\t\t\t\n\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\n\t\t\tif (parental_haplosome2->IsNull())\n\t\t\t{\n\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tHaplosome *parental_haplosome = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\n\t\t\tif (parental_haplosome->IsNull())\n\t\t\t{\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome, mutation_callbacks);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"GenerateIndividualCloned()\");\n\t\t\n\t\t// For each haplosome generated, we need to add them to the individual.  We also need\n\t\t// to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome1, currentHaplosomeIndex);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = individual_pid * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, currentHaplosomeIndex+1);\n\t\t\t\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = individual_pid * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t\t\n\t\t// move forward 1 or 2 indices in haplosomes_, depending on whether a haplosome2 was created (even if it is null)\n\t\tcurrentHaplosomeIndex += (haplosome2 ? 2 : 1);\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent, p_parent, /* p_is_selfing */ false, /* p_is_cloning */ true, /* p_target_subpop */ this, /* p_source_subpop */ &parent_subpop, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\t// revoke parentage\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Uniparental(*p_parent);\n\t\t\t\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\tindividual = nullptr;\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t}\n\t}\n\t\n\treturn individual;\n}\n\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, false, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<false, true, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, false, true, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, false, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, false, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, false, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, false, true, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, true, false, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, true, false, true>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, true, true, false>(Individual *p_parent);\ntemplate Individual *Subpopulation::GenerateIndividualCloned<true, true, true, true, true>(Individual *p_parent);\n\nIndividual *Subpopulation::GenerateIndividualEmpty(slim_popsize_t p_individual_index, IndividualSex p_child_sex, slim_age_t p_age, double p_fitness, float p_mean_parent_age, bool p_haplosome1_null, bool p_haplosome2_null, bool p_run_modify_child, bool p_record_in_treeseq)\n{\n\t// Create the offspring and record it\n\tIndividual *individual = NewSubpopIndividual(p_individual_index, p_child_sex, p_age, p_fitness, p_mean_parent_age);\n\t\n\tbool pedigrees_enabled = species_.PedigreesEnabled();\n\tslim_pedigreeid_t individual_pid = pedigrees_enabled ? SLiM_GetNextPedigreeID() : 0;\n\t\n\tif (pedigrees_enabled)\n\t\tindividual->TrackParentage_Parentless(individual_pid);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (p_record_in_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: note that there is no parent, so the spatial position of the offspring is left uninitialized.\n\t// individual->InheritSpatialPosition(species_.spatial_dimensionality_, ???)\n\t\n\t// Configure the offspring's haplosomes one by one\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::GenerateIndividualEmpty): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t// the flags p_haplosome1_null / p_haplosome2_null apply only here!\n\t\t\t\t// need to set has_null_haplosomes_ here because these haplosomes\n\t\t\t\t// are not normally null, according to the chromosome type\n\t\t\t\tif (p_haplosome1_null)\n\t\t\t\t{\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\thas_null_haplosomes_ = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (p_haplosome2_null)\n\t\t\t\t{\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\t\thas_null_haplosomes_ = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t{\n\t\t\t\t// non-null for all\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t{\n\t\t\t\t// XX for females, X- for males\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\telse\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t{\n\t\t\t\t// - for females, Y for males\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\telse\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\t// ZZ for males, -Z for females\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\telse\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\t\n\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t{\n\t\t\t\t// - for males, W for females\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\telse\n\t\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\t// non-null + null for all\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\t// -- for females, -Y for males\n\t\t\t\thaplosome1 = chromosome->NewHaplosome_NULL(individual, 0);\n\t\t\t\t\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\telse\n\t\t\t\t\thaplosome2 = chromosome->NewHaplosome_NULL(individual, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// For each haplosome generated, we need to add them to the individual.  We also need\n\t\t// to record all haplosomes for tree-seq; since even the non-null haplosomes are empty,\n\t\t// not filled by HaplosomeCrossed() and HaplosomeCloned() which record them, they need\n\t\t// to be recorded here also.\n\t\t\n\t\t// We need to add a *different* empty MutationRun to each mutrun index, so each run comes out of\n\t\t// the correct per-thread allocation pool.  Would be nice to share these empty runs across\n\t\t// multiple calls to addEmpty(), but that's hard now since we don't have refcounts.  How about\n\t\t// we maintain a set of empty mutruns, one for each position, in the Species, and whenever we\n\t\t// need an empty mutrun we reuse from that pool – after checking that the run is still empty??\n\t\tif (haplosome1)\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\thaplosome1->check_cleared_to_nullptr();\n#endif\n\t\t\tif (!haplosome1->IsNull())\n\t\t\t{\n\t\t\t\tint32_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\t\tconst MutationRun *mutrun = MutationRun::NewMutationRun(mutrun_context);\n\t\t\t\t\t\n\t\t\t\t\thaplosome1->mutruns_[run_index] = mutrun;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome1, currentHaplosomeIndex);\n\t\t\t\n\t\t\tif (pedigrees_enabled)\n\t\t\t\thaplosome1->haplosome_id_ = individual_pid * 2;\n\t\t\t\n\t\t\tif (p_record_in_treeseq)\n\t\t\t{\n\t\t\t\tif (haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t\t\telse\n\t\t\t\t\tspecies_.RecordNewHaplosome(nullptr, 0, haplosome1, nullptr, nullptr);\n\t\t\t}\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\thaplosome2->check_cleared_to_nullptr();\n#endif\n\t\t\tif (!haplosome2->IsNull())\n\t\t\t{\n\t\t\t\tint32_t mutrun_count = chromosome->mutrun_count_;\n\t\t\t\t\n\t\t\t\tfor (int run_index = 0; run_index < mutrun_count; ++run_index)\n\t\t\t\t{\n\t\t\t\t\tMutationRunContext &mutrun_context = chromosome->ChromosomeMutationRunContextForMutationRunIndex(run_index);\n\t\t\t\t\tconst MutationRun *mutrun = MutationRun::NewMutationRun(mutrun_context);\n\t\t\t\t\t\n\t\t\t\t\thaplosome2->mutruns_[run_index] = mutrun;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, currentHaplosomeIndex+1);\n\t\t\t\n\t\t\tif (pedigrees_enabled)\n\t\t\t\thaplosome2->haplosome_id_ = individual_pid * 2 + 1;\n\t\t\t\n\t\t\tif (p_record_in_treeseq)\n\t\t\t{\n\t\t\t\tif (haplosome2->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t\t\telse\n\t\t\t\t\tspecies_.RecordNewHaplosome(nullptr, 0, haplosome2, nullptr, nullptr);\n\t\t\t}\n\t\t}\n\t\t\n\t\tchromosome->StopMutationRunExperimentClock(\"GenerateIndividualEmpty()\");\n\t\t\n\t\t// move forward 1 or 2, depending on whether a haplosome2 was created\n\t\tcurrentHaplosomeIndex += (haplosome2 ? 2 : 1);\n\t}\n\t\n\tif (p_run_modify_child)\n\t{\n\t\t// Run the candidate past modifyChild() callbacks; the target subpop's registered callbacks are used\n\t\tif (registered_modify_child_callbacks_.size())\n\t\t{\n\t\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, nullptr, nullptr, /* p_is_selfing */ false, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ nullptr, registered_modify_child_callbacks_);\n\t\t\t\n\t\t\t// If the child was rejected, un-record it and dispose of it\n\t\t\tif (!proposed_child_accepted)\n\t\t\t{\n\t\t\t\tif (pedigrees_enabled)\n\t\t\t\t\tindividual->RevokeParentage_Parentless();\n\t\t\t\t\n\t\t\t\tFreeSubpopIndividual(individual);\n\t\t\t\tindividual = nullptr;\n\t\t\t\t\n\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\tif (p_record_in_treeseq)\n\t\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn individual;\n}\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nbool Subpopulation::MungeIndividualCrossed(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex)\n{\n\tSubpopulation &parent1_subpop = *p_parent1->subpopulation_;\n\t\n#if DEBUG\n\tSubpopulation &parent2_subpop = *p_parent2->subpopulation_;\n\t\n\tif (&parent1_subpop != &parent2_subpop)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): parent1 and parent2 must belong to the same subpopulation; that is assumed, since this method is called only for WF reproduction.\" << EidosTerminate();\n\t\n\tIndividualSex parent1_sex = p_parent1->sex_;\n\tIndividualSex parent2_sex = p_parent2->sex_;\n\t\n\tif ((sex_enabled_ && (parent1_sex != IndividualSex::kFemale)) || (!sex_enabled_ && (parent1_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): parent1 must be female in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((sex_enabled_ && (parent2_sex != IndividualSex::kMale)) || (!sex_enabled_ && (parent2_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): parent2 must be male in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((p_parent1->index_ == -1) || (p_parent2->index_ == -1))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1_subpop.species_ != &this->species_) || (&parent2_subpop.species_ != &this->species_))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): biparental crossing requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of the parents (which must be the same)\n\tstd::vector<SLiMEidosBlock*> *recombination_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\trecombination_callbacks = &parent1_subpop.registered_recombination_callbacks_;\n\t\tmutation_callbacks = &parent1_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent1_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!recombination_callbacks->size()) recombination_callbacks = nullptr;\n\t\tif (!mutation_callbacks->size()) mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Biparental(p_pedigree_id, *p_parent1, *p_parent2);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the first parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent1);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t// each haplosome is generated by recombination between a pair of parental haplosomes\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 1 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 1 copy 2\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 2 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 2 copy 2\n\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\t{\n\t\t\t\t// the haplosome is generated by recombination between the haplosomes of the two parents\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 1 copy\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 2 copy\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t{\n\t\t\t\t// one X comes from recombination from the female parent, the other (to females only) clonally from the male parent\n\t\t\t\t// so females are XX, males are X-\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's X 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// female's X 2\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t// male's X (from female)\n\t\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t// male's - (from male)\n\t\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\t{\n\t\t\t\t// the Y comes (to males only) clonally from the male parent\n\t\t\t\t// so females are -, males are Y\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's Y\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's -\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\t// one Z comes (to males only) clonally from the female parent, the other from recombination from the male parent\n\t\t\t\t// so females are -Z, males are ZZ (note we think of it as WZ, not ZW, since the female parent is always the first parent)\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t// female's Z\n\t\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome2, mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t// female's -\n\t\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's Z\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// male's Z\n\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\t{\n\t\t\t\t// the W comes (to females only) clonally from the female parent\n\t\t\t\t// so females are W, males are -\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's W\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's -\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\t{\n\t\t\t\t// haploid, inherited clonally from the female for both sexes, like the W for females\n\t\t\t\t// BCH 27 August 2025: note that we now allow HF in non-sexual models; \"female\" here is the first parent\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's copy\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t{\n\t\t\t\t// this comes (to females only) clonally from the female parent, just like a W\n\t\t\t\tif (p_child_sex == IndividualSex::kFemale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's copy\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's -\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t{\n\t\t\t\t// haploid, inherited clonally from the male for both sexes, like the Y for males\n\t\t\t\t// BCH 27 August 2025: note that we now allow HM in non-sexual models; \"male\" here is the second parent\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's copy\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t{\n\t\t\t\t// this comes (to males only) clonally from the male parent, just like a Y\n\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// male's copy\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// female's -\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed): chromosome type 'H-' does not allow reproduction by biparental cross (only cloning); chromosome type 'H' provides greater flexibility for modeling haploids.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 1 copy 1\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 2 copy 1\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, parental_haplosome2, haplosome1, chromosome);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tif (p_child_sex == IndividualSex::kMale)\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// male's Y\n\t\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// female's -\n\t\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"MungeIndividualCrossed()\");\n\t\t\n\t\t// We need to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = p_pedigree_id * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent1, p_parent2, /* p_is_selfing */ false, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ &parent1_subpop, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\t// back out child state we created; this restores it to a reuseable state\n\t\t\t// FIXME we could back out the assigned pedigree ID too\n\t\t\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t// BCH 10/15/2024: We used to need to clear here, but we no longer do.  We don't even need to free\n\t\t\t// the haplosomes we made above; they will be garbage collected by FreeUnusedMutationRuns().\n\t\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\thaplosomes[haplosome_index]->clear_to_nullptr();\n#endif\n\t\t\t\n\t\t\t// revoke parentage\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Biparental(*p_parent1, *p_parent2);\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<false, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed<true, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\n// this more limited templated variant assumes there is one chromosome, the chromosome type is \"A\", and f_mutrunexps=F and f_callbacks=F\ntemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\nbool Subpopulation::MungeIndividualCrossed_1CH_A(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, __attribute__ ((unused)) IndividualSex p_child_sex)\n{\n#if DEBUG\n\tSubpopulation &parent1_subpop = *p_parent1->subpopulation_;\n\tSubpopulation &parent2_subpop = *p_parent2->subpopulation_;\n\t\n\tif (&parent1_subpop != &parent2_subpop)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 and parent2 must belong to the same subpopulation; that is assumed, since this method is called only for WF reproduction.\" << EidosTerminate();\n\t\n\tIndividualSex parent1_sex = p_parent1->sex_;\n\tIndividualSex parent2_sex = p_parent2->sex_;\n\t\n\tif ((sex_enabled_ && (parent1_sex != IndividualSex::kFemale)) || (!sex_enabled_ && (parent1_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 must be female in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((sex_enabled_ && (parent2_sex != IndividualSex::kMale)) || (!sex_enabled_ && (parent2_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent2 must be male in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((p_parent1->index_ == -1) || (p_parent2->index_ == -1))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1_subpop.species_ != &this->species_) || (&parent2_subpop.species_ != &this->species_))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): biparental crossing requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Biparental(p_pedigree_id, *p_parent1, *p_parent2);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the first parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent1);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tconst int currentHaplosomeIndex = 0;\n\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\n\t// Determine what kind of haplosomes to make for this chromosome\n\tHaplosome *haplosome1, *haplosome2;\n\t\n\t// each haplosome is generated by recombination between a pair of parental haplosomes\n\t{\n\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 1 copy 1\n\t\tHaplosome *parental_haplosome2 = p_parent1->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 1 copy 2\n\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\n\t\tpopulation_.HaplosomeCrossed<f_treeseq, false>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, nullptr, nullptr);\n\t}\n\t{\n\t\tHaplosome *parental_haplosome1 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t// parent 2 copy 1\n\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex+1];\t\t// parent 2 copy 2\n\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\n\t\tpopulation_.HaplosomeCrossed<f_treeseq, false>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, nullptr, nullptr);\n\t}\n\t\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t}\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome2->haplosome_id_ = p_pedigree_id * 2 + 1;\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_A<true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\n// this more limited templated variant assumes there is one chromosome, the chromosome type is \"H\", and f_mutrunexps=F and f_callbacks=F\ntemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\nbool Subpopulation::MungeIndividualCrossed_1CH_H(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, __attribute__ ((unused)) IndividualSex p_child_sex)\n{\n#if DEBUG\n\tSubpopulation &parent1_subpop = *p_parent1->subpopulation_;\n\tSubpopulation &parent2_subpop = *p_parent2->subpopulation_;\n\t\n\tif (&parent1_subpop != &parent2_subpop)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 and parent2 must belong to the same subpopulation; that is assumed, since this method is called only for WF reproduction.\" << EidosTerminate();\n\t\n\tIndividualSex parent1_sex = p_parent1->sex_;\n\tIndividualSex parent2_sex = p_parent2->sex_;\n\t\n\tif ((sex_enabled_ && (parent1_sex != IndividualSex::kFemale)) || (!sex_enabled_ && (parent1_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 must be female in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((sex_enabled_ && (parent2_sex != IndividualSex::kMale)) || (!sex_enabled_ && (parent2_sex != IndividualSex::kHermaphrodite)))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent2 must be male in sexual models, or hermaphroditic in non-sexual models.\" << EidosTerminate();\n\tif ((p_parent1->index_ == -1) || (p_parent2->index_ == -1))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1_subpop.species_ != &this->species_) || (&parent2_subpop.species_ != &this->species_))\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCrossed_1CH): biparental crossing requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Biparental(p_pedigree_id, *p_parent1, *p_parent2);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the first parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent1);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tconst int currentHaplosomeIndex = 0;\n\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\n\t// Determine what kind of haplosomes to make for this chromosome\n\tHaplosome *haplosome1;\n\t\n\t{\n\t\t// the haplosome is generated by recombination between the haplosomes of the two parents\n\t\tHaplosome *parental_haplosome1 = p_parent1->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 1 copy\n\t\tHaplosome *parental_haplosome2 = p_parent2->haplosomes_[currentHaplosomeIndex];\t\t\t\t// parent 2 copy\n\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\n\t\tpopulation_.HaplosomeCrossed<f_treeseq, false>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, nullptr, nullptr);\n\t}\n\t\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\ntemplate bool Subpopulation::MungeIndividualCrossed_1CH_H<true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nbool Subpopulation::MungeIndividualSelfed(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent)\n{\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n#if DEBUG\n\tIndividualSex parent_sex = p_parent->sex_;\n\t\n\tif (parent_sex != IndividualSex::kHermaphrodite)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): parent must be hermaphroditic.\" << EidosTerminate();\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): selfing requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of each parent\n\tstd::vector<SLiMEidosBlock*> *recombination_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\trecombination_callbacks = &parent_subpop.registered_recombination_callbacks_;\n\t\tmutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!recombination_callbacks->size()) recombination_callbacks = nullptr;\n\t\tif (!mutation_callbacks->size()) mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(p_pedigree_id, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the first parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t// each haplosome is generated by recombination between the pair of parental haplosomes\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t\t\t// parent copy 1\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\t\t// parent copy 2\n\t\t\t\t\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t\n\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\tpopulation_.HaplosomeCrossed<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome1, parental_haplosome2, recombination_callbacks, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t\t{\n\t\t\t\t// the haplosome is generated by recombination between the haplosome of the parent and itself\n\t\t\t\t// but since the one haplosome is identical to itself, that is the same thing as cloning\n\t\t\t\t// BCH 27 August 2025: Note that HF and HM are now treated here also; they would always be clonal\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t\t\t// parent copy\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): chromosome type 'H-' does not allow reproduction by selfing (only cloning); chromosome type 'H' provides greater flexibility for modeling haploids.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualSelfed): (internal error) sex-specific chromosome type not supported for selfing.\" << EidosTerminate();\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"MungeIndividualSelfed()\");\n\t\t\n\t\t// We need to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = p_pedigree_id * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent, p_parent, /* p_is_selfing */ true, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ &parent_subpop, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\t// back out child state we created; this restores it to a reuseable state\n\t\t\t// FIXME we could back out the assigned pedigree ID too\n\t\t\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t// BCH 10/15/2024: We used to need to clear here, but we no longer do.  We don't even need to free\n\t\t\t// the haplosomes we made above; they will be garbage collected by FreeUnusedMutationRuns().\n\t\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\thaplosomes[haplosome_index]->clear_to_nullptr();\n#endif\n\t\t\t\n\t\t\t// revoke parentage\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Uniparental(*p_parent);\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<false, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualSelfed<true, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\ntemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\nbool Subpopulation::MungeIndividualCloned(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent)\n{\n\tIndividualSex parent_sex = p_parent->sex_;\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n#if DEBUG\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\tif (individual->sex_ != parent_sex)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): child sex does not match parent sex (which, for cloning, it should).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): cloning requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Figure out callbacks, which are based on the subpopulation of the parents (which must be the same)\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = nullptr;\n\tstd::vector<SLiMEidosBlock*> *modify_child_callbacks_ = nullptr;\n\t\n\tif (f_callbacks)\n\t{\n\t\t// Figure out callbacks, which are based on the subpopulation of each parent\n\t\tmutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\tmodify_child_callbacks_ = &parent_subpop.registered_modify_child_callbacks_;\n\t\t\n\t\tif (!mutation_callbacks->size()) mutation_callbacks = nullptr;\n\t\tif (!modify_child_callbacks_->size()) modify_child_callbacks_ = nullptr;\n\t}\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(p_pedigree_id, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tint currentHaplosomeIndex = 0;\n\t\n\tfor (Chromosome *chromosome : species_.Chromosomes())\n\t{\n#if DEBUG\n\t\tif (!species_.HasGenetics())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\t\n\t\tif (f_mutrunexps) chromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Determine what kind of haplosomes to make for this chromosome\n\t\t// We just faithfully clone the existing haplosomes of the parent, regardless of type\n\t\tChromosomeType chromosomeType = chromosome->Type();\n\t\tHaplosome *haplosome1 = nullptr, *haplosome2 = nullptr;\n\t\t\n\t\tswitch (chromosomeType)\n\t\t{\n\t\t\t\t// these chromosome types keep two haplosomes per individual\n\t\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\t\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\t\n\t\t\t\t\tif (parent_sex == IndividualSex::kFemale)\n\t\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t\t\telse\n\t\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t}\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tif (parent_sex == IndividualSex::kMale)\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\telse\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\n\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\n\t\t\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\t\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\t\t\n\t\t\t\tif (parent_sex == IndividualSex::kMale)\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome2, parental_haplosome2, mutation_callbacks);\n\t\t\t\telse\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome2, haplosome2, chromosome);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\t\n\t\t\t\t// these chromosome types keep one haplosome per individual\n\t\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\t\t// note male inheritance is not honored by cloning\n\t\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\t// note female inheritance is not honored by cloning\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t// parent 1 copy\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tif (parent_sex == IndividualSex::kMale)\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\telse\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t\t{\n\t\t\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\t\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\t\t\n\t\t\t\tif (parent_sex == IndividualSex::kFemale)\n\t\t\t\t\tpopulation_.HaplosomeCloned<f_treeseq, f_callbacks>(*chromosome, *haplosome1, parental_haplosome1, mutation_callbacks);\n\t\t\t\telse\n\t\t\t\t\tHaplosome::DebugCheckStructureMatch(parental_haplosome1, haplosome1, chromosome);\n\t\t\t\t\n\t\t\t\tcurrentHaplosomeIndex += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (f_mutrunexps) chromosome->StopMutationRunExperimentClock(\"MungeIndividualCloned()\");\n\t\t\n\t\t// We need to record the null haplosomes for tree-seq; non-null haplosomes were already\n\t\t// recorded by the methods above, HaplosomeCrossed() and HaplosomeCloned().  We also\n\t\t// have to set their haplosome_id_ as appropriate.\n\t\tif (haplosome1)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t}\n\t\tif (haplosome2)\n\t\t{\n\t\t\tif (f_pedigree_rec)\n\t\t\t\thaplosome2->haplosome_id_ = p_pedigree_id * 2 + 1;\n\t\t\t\n\t\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t}\n\t}\n\t\n\t// Run the candidate past modifyChild() callbacks; the first parent subpop's registered callbacks are used\n\tif (modify_child_callbacks_)\n\t{\n\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, p_parent, p_parent, /* p_is_selfing */ false, /* p_is_cloning */ true, /* p_target_subpop */ this, /* p_source_subpop */ &parent_subpop, *modify_child_callbacks_);\n\t\t\n\t\t// If the child was rejected, un-record it and dispose of it\n\t\tif (!proposed_child_accepted)\n\t\t{\n\t\t\t// back out child state we created; this restores it to a reuseable state\n\t\t\t// FIXME we could back out the assigned pedigree ID too\n\t\t\t\n#if SLIM_CLEAR_HAPLOSOMES\n\t\t\t// BCH 10/15/2024: We used to need to clear here, but we no longer do.  We don't even need to free\n\t\t\t// the haplosomes we made above; they will be garbage collected by FreeUnusedMutationRuns().\n\t\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\t\n\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\thaplosomes[haplosome_index]->clear_to_nullptr();\n#endif\n\t\t\t\n\t\t\t// revoke parentage\n\t\t\tif (f_pedigree_rec)\n\t\t\t\tindividual->RevokeParentage_Uniparental(*p_parent);\n\t\t\t\n\t\t\t// TREE SEQUENCE RECORDING\n\t\t\tif (f_treeseq)\n\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<false, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, false, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned<true, true, true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\ntemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\nbool Subpopulation::MungeIndividualCloned_1CH_A(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent)\n{\n#if DEBUG\n\tIndividualSex parent_sex = p_parent->sex_;\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\tif (individual->sex_ != parent_sex)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): child sex does not match parent sex (which, for cloning, it should).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): cloning requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(p_pedigree_id, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tconst int currentHaplosomeIndex = 0;\n\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\n#if DEBUG\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\n\t// Determine what kind of haplosomes to make for this chromosome\n\t// We just faithfully clone the existing haplosomes of the parent, regardless of type\n\tHaplosome *haplosome1, *haplosome2;\n\t\n\t{\n\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\n\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\n\t\tpopulation_.HaplosomeCloned<f_treeseq, false>(*chromosome, *haplosome1, parental_haplosome1, nullptr);\n\t}\n\t{\n\t\tHaplosome *parental_haplosome2 = p_parent->haplosomes_[currentHaplosomeIndex+1];\n\t\thaplosome2 = haplosomes[currentHaplosomeIndex+1];\n\t\t\n\t\tpopulation_.HaplosomeCloned<f_treeseq, false>(*chromosome, *haplosome2, parental_haplosome2, nullptr);\n\t}\n\t\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t\t\n\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t}\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome2->haplosome_id_ = p_pedigree_id * 2 + 1;\n\t\t\n\t\tif (f_treeseq && haplosome2->IsNull())\n\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_A<true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\ntemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\nbool Subpopulation::MungeIndividualCloned_1CH_H(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent)\n{\n#if DEBUG\n\tIndividualSex parent_sex = p_parent->sex_;\n\tSubpopulation &parent_subpop = *p_parent->subpopulation_;\n\t\n\tif (p_parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\tif (individual->sex_ != parent_sex)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): child sex does not match parent sex (which, for cloning, it should).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): cloning requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n#endif\n\t\n\t// Record the offspring\n\tif (f_pedigree_rec)\n\t\tindividual->TrackParentage_Uniparental(p_pedigree_id, *p_parent);\n\t\n\t// TREE SEQUENCE RECORDING\n\tif (f_treeseq)\n\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\n\t// BCH 9/26/2023: inherit the spatial position of the parent by default, to set up for deviatePositions()/pointDeviated()\n\tif (f_spatial)\n\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), p_parent);\n\t\n\t// Configure the offspring's haplosomes one by one\n\tHaplosome **haplosomes = individual->haplosomes_;\n\tconst int currentHaplosomeIndex = 0;\n\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\n#if DEBUG\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Population::MungeIndividualCloned): (internal error) a chromosome is defined for a no-genetics species!\" << EidosTerminate();\n#endif\n\t\n\tHaplosome *haplosome1;\n\t\n\t{\n\t\tHaplosome *parental_haplosome1 = p_parent->haplosomes_[currentHaplosomeIndex];\t// parent 1 copy\n\t\thaplosome1 = haplosomes[currentHaplosomeIndex];\n\t\t\n\t\tpopulation_.HaplosomeCloned<f_treeseq, false>(*chromosome, *haplosome1, parental_haplosome1, nullptr);\n\t}\n\t\n\t{\n\t\tif (f_pedigree_rec)\n\t\t\thaplosome1->haplosome_id_ = p_pedigree_id * 2;\n\t\t\n\t\tif (f_treeseq && haplosome1->IsNull())\n\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t}\n\t\n\treturn true;\n}\n\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<false, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<false, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<false, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<false, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<true, false, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<true, false, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<true, true, false>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\ntemplate bool Subpopulation::MungeIndividualCloned_1CH_H<true, true, true>(Individual *individual, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\n// nonWF only:\nvoid Subpopulation::ApplyReproductionCallbacks(std::vector<SLiMEidosBlock*> &p_reproduction_callbacks, slim_popsize_t p_individual_index)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplyReproductionCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tIndividual *individual = parent_individuals_[p_individual_index];\n\t\n\tfor (SLiMEidosBlock *reproduction_callback : p_reproduction_callbacks)\n\t{\n\t\tif (reproduction_callback->block_active_)\n\t\t{\n\t\t\tIndividualSex sex_specificity = reproduction_callback->sex_specificity_;\n\t\t\t\n\t\t\tif ((sex_specificity == IndividualSex::kUnspecified) || (sex_specificity == individual->sex_))\n\t\t\t{\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t// SLiMgui debugging point\n\t\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\t\n\t\t\t\t{\n\t\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\t\tEidosToken *decl_token = reproduction_callback->root_node_->token_;\n\t\t\t\t\t\n\t\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t\t{\n\t\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG reproduction(\";\n\t\t\t\t\t\tif ((reproduction_callback->subpopulation_id_ != -1) && (reproduction_callback->sex_specificity_ != IndividualSex::kUnspecified))\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << reproduction_callback->subpopulation_id_ << \", \\\"\" << reproduction_callback->sex_specificity_ << \"\\\"\";\n\t\t\t\t\t\telse if (reproduction_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << reproduction_callback->subpopulation_id_;\n\t\t\t\t\t\telse if (reproduction_callback->sex_specificity_ != IndividualSex::kUnspecified)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \"NULL, \\\"\" << reproduction_callback->sex_specificity_ << \"\\\"\";\n\t\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (reproduction_callback->block_id_ != -1)\n\t\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << reproduction_callback->block_id_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\t\tindenter.indent();\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t\t\n\t\t\t\t// This code is similar to Population::ExecuteScript, but we set up an additional symbol table, and we use the return value\n\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t{\n\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\tEidosInterpreter interpreter(reproduction_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (reproduction_callback->contains_self_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(reproduction_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\n\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\tif (reproduction_callback->contains_individual_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, individual->CachedEidosValue());\n\t\t\t\t\tif (reproduction_callback->contains_subpop_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, SymbolTableEntry().second);\n\t\t\t\t\t\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be NULL, for now (to allow future extension)\n\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(reproduction_callback->script_);\n\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (result->Type() != EidosValueType::kValueVOID)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (result->Type() == EidosValueType::kValueNULL)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyReproductionCallbacks): reproduction() callbacks must not return a value (i.e., must return void).  (NULL has been returned here instead; NULL was the required return value in the SLiM 3 prerelease, but the policy has been changed.)\" << EidosTerminate(reproduction_callback->identifier_token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplyReproductionCallbacks): reproduction() callbacks must not return a value (i.e., must return void).\" << EidosTerminate(reproduction_callback->identifier_token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosReproductionCallback)]);\n#endif\n}\n\n// nonWF only:\nvoid Subpopulation::ReproduceSubpopulation(void)\n{\n\t// if there are no reproduction() callbacks active, we can avoid all the work\n\tif (registered_reproduction_callbacks_.size() == 0)\n\t\treturn;\n\t\n\tif (species_.RandomizingCallbackOrder())\n\t{\n\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_subpop_size_);\n\t\t\n\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_subpop_size_; shuffle_index++)\n\t\t{\n\t\t\tslim_popsize_t individual_index = shuffle_buf[shuffle_index];\n\t\t\t\n\t\t\tApplyReproductionCallbacks(registered_reproduction_callbacks_, individual_index);\n\t\t}\n\t\t\n\t\tspecies_.ReturnShuffleBuffer();\n\t}\n\telse\n\t{\n\t\tfor (int individual_index = 0; individual_index < parent_subpop_size_; ++individual_index)\n\t\t\tApplyReproductionCallbacks(registered_reproduction_callbacks_, individual_index);\n\t}\n}\n\n// nonWF only:\nvoid Subpopulation::MergeReproductionOffspring(void)\n{\n\t// NOTE: this method is called by Population::ResolveSurvivalPhaseMovement() as well as by reproduction, since the logic is identical!\n\tint new_count = (int)nonWF_offspring_individuals_.size();\n\t\n\tif (sex_enabled_)\n\t{\n\t\t// resize to create new slots for the new individuals\n\t\ttry {\n\t\t\tparent_individuals_.resize(parent_individuals_.size() + new_count);\n\t\t}\n\t\tcatch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::MergeReproductionOffspring): (internal error) resize() exception with parent_individuals_.size() == \" << parent_individuals_.size() << \", new_count == \" << new_count << \".\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// in sexual models, females must be put before males and parent_first_male_index_ must be adjusted\n\t\tIndividual **parent_individual_ptrs = parent_individuals_.data();\n\t\tint old_male_count = parent_subpop_size_ - parent_first_male_index_;\n\t\tint new_female_count = 0;\n\t\t\n\t\t// count the new females\n\t\tfor (int new_index = 0; new_index < new_count; ++new_index)\n\t\t\tif (nonWF_offspring_individuals_[new_index]->sex_ == IndividualSex::kFemale)\n\t\t\t\tnew_female_count++;\n\t\t\n\t\t// move old males up that many slots to make room; need to fix the index_ ivars of the moved males\n\t\tmemmove(parent_individual_ptrs + parent_first_male_index_ + new_female_count, parent_individual_ptrs + parent_first_male_index_, old_male_count * sizeof(Individual *));\n\t\t\n\t\tfor (int moved_index = 0; moved_index < old_male_count; moved_index++)\n\t\t{\n\t\t\tint new_index = parent_first_male_index_ + new_female_count + moved_index;\n\t\t\t\n\t\t\tparent_individual_ptrs[new_index]->index_ = new_index;\n\t\t}\n\t\t\n\t\t// put all the new stuff into place; if the code above did its job, there are slots waiting for each item\n\t\tint new_female_position = parent_first_male_index_;\n\t\tint new_male_position = parent_subpop_size_ + new_female_count;\n\t\t\n\t\tfor (int new_index = 0; new_index < new_count; ++new_index)\n\t\t{\n\t\t\tIndividual *individual = nonWF_offspring_individuals_[new_index];\n\t\t\tslim_popsize_t insert_index;\n\t\t\t\n\t\t\tif (individual->sex_ == IndividualSex::kFemale)\n\t\t\t\tinsert_index = new_female_position++;\n\t\t\telse\n\t\t\t\tinsert_index = new_male_position++;\n\t\t\t\n\t\t\tindividual->index_ = insert_index;\n\t\t\tparent_individual_ptrs[insert_index] = individual;\n\t\t}\n\t\t\n\t\tparent_first_male_index_ += new_female_count;\n\t}\n\telse\n\t{\n\t\t// reserve space for the new offspring to be merged in\n\t\ttry {\n\t\t\tparent_individuals_.reserve(parent_individuals_.size() + new_count);\n\t\t}\n\t\tcatch (...) {\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::MergeReproductionOffspring): (internal error) reserve() exception with parent_individuals_.size() == \" << parent_individuals_.size() << \", new_count == \" << new_count << \".\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// in hermaphroditic models there is no ordering, so just add new stuff at the end\n\t\tfor (int new_index = 0; new_index < new_count; ++new_index)\n\t\t{\n\t\t\tIndividual *individual = nonWF_offspring_individuals_[new_index];\n\t\t\t\n\t\t\tindividual->index_ = parent_subpop_size_ + new_index;\n\t\t\tparent_individuals_.emplace_back(individual);\n\t\t}\n\t}\n\t\n\t// final cleanup\n\tparent_subpop_size_ += new_count;\n\t\n\tcached_parent_individuals_value_.reset();\n\t\n\tnonWF_offspring_individuals_.resize(0);\n}\n\n// nonWF only:\nbool Subpopulation::ApplySurvivalCallbacks(std::vector<SLiMEidosBlock*> &p_survival_callbacks, Individual *p_individual, double p_fitness, double p_draw, bool p_surviving)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Population::ApplySurvivalCallbacks(): running Eidos callback\");\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\n\tSubpopulation *move_destination = nullptr;\n\t\n\tfor (SLiMEidosBlock *survival_callback : p_survival_callbacks)\n\t{\n\t\tif (survival_callback->block_active_)\n\t\t{\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\t\n\t\t\t{\n\t\t\t\tEidosInterpreterDebugPointsSet *debug_points = community_.DebugPoints();\n\t\t\t\tEidosToken *decl_token = survival_callback->root_node_->token_;\n\t\t\t\t\n\t\t\t\tif (debug_points && debug_points->set.size() && (decl_token->token_line_ != -1) &&\n\t\t\t\t\t(debug_points->set.find(decl_token->token_line_) != debug_points->set.end()))\n\t\t\t\t{\n\t\t\t\t\tSLIM_ERRSTREAM << EidosDebugPointIndent::Indent() << \"#DEBUG survival(\";\n\t\t\t\t\tif (survival_callback->subpopulation_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \"p\" << survival_callback->subpopulation_id_;\n\t\t\t\t\tSLIM_ERRSTREAM << \")\";\n\t\t\t\t\t\n\t\t\t\t\tif (survival_callback->block_id_ != -1)\n\t\t\t\t\t\tSLIM_ERRSTREAM << \" s\" << survival_callback->block_id_;\n\t\t\t\t\t\n\t\t\t\t\tSLIM_ERRSTREAM << \" (line \" << (decl_token->token_line_ + 1) << community_.DebugPointInfo() << \")\" << std::endl;\n\t\t\t\t\tindenter.indent();\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// The callback is active, so we need to execute it\n\t\t\t// This code is similar to Population::ExecuteScript, but we set up an additional symbol table, and we use the return value\n\t\t\t{\n\t\t\t\t// local variables for the callback parameters that we might need to allocate here, and thus need to free below\n\t\t\t\tEidosValue_Float local_fitness(p_fitness);\n\t\t\t\tEidosValue_Float local_draw(p_draw);\n\t\t\t\t\n\t\t\t\t// We need to actually execute the script; we start a block here to manage the lifetime of the symbol table\n\t\t\t\t{\n\t\t\t\t\tEidosSymbolTable callback_symbols(EidosSymbolTableType::kContextConstantsTable, &community_.SymbolTable());\n\t\t\t\t\tEidosSymbolTable client_symbols(EidosSymbolTableType::kLocalVariablesTable, &callback_symbols);\n\t\t\t\t\tEidosFunctionMap &function_map = community_.FunctionMap();\n\t\t\t\t\tEidosInterpreter interpreter(survival_callback->compound_statement_node_, client_symbols, function_map, &community_, SLIM_OUTSTREAM, SLIM_ERRSTREAM\n#ifdef SLIMGUI\n\t\t\t\t\t\t, community_.check_infinite_loops_\n#endif\n\t\t\t\t\t\t);\n\t\t\t\t\t\n\t\t\t\t\tif (survival_callback->contains_self_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(survival_callback->SelfSymbolTableEntry());\t\t// define \"self\"\n\t\t\t\t\t\n\t\t\t\t\t// Set all of the callback's parameters; note we use InitializeConstantSymbolEntry() for speed.\n\t\t\t\t\t// We can use that method because we know the lifetime of the symbol table is shorter than that of\n\t\t\t\t\t// the value objects, and we know that the values we are setting here will not change (the objects\n\t\t\t\t\t// referred to by the values may change, but the values themselves will not change).\n\t\t\t\t\t// BCH 11/7/2025: note these symbols are now protected in SLiM_ConfigureContext()\n\t\t\t\t\tif (survival_callback->contains_fitness_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_fitness.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_fitness, EidosValue_SP(&local_fitness));\n\t\t\t\t\t}\n\t\t\t\t\tif (survival_callback->contains_draw_)\n\t\t\t\t\t{\n\t\t\t\t\t\tlocal_draw.StackAllocated();\t\t// prevent Eidos_intrusive_ptr from trying to delete this\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_draw, EidosValue_SP(&local_draw));\n\t\t\t\t\t}\n\t\t\t\t\tif (survival_callback->contains_individual_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_individual, p_individual->CachedEidosValue());\n\t\t\t\t\tif (survival_callback->contains_subpop_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_subpop, SymbolTableEntry().second);\n\t\t\t\t\tif (survival_callback->contains_surviving_)\n\t\t\t\t\t\tcallback_symbols.InitializeConstantSymbolEntry(gID_surviving, p_surviving ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\t\t\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\t// Interpret the script; the result from the interpretation must be a singleton double used as a new fitness value\n\t\t\t\t\t\tEidosValue_SP result_SP = interpreter.EvaluateInternalBlock(survival_callback->script_);\n\t\t\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\t\tEidosValueType result_type = result->Type();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (result_type == EidosValueType::kValueNULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// NULL means don't change the existing decision\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ((result_type == EidosValueType::kValueLogical) &&\n\t\t\t\t\t\t\t\t (result->Count() == 1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// T or F means change the existing decision to that value\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tp_surviving = result->LogicalData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tp_surviving = ((EidosValue_Logical *)result)->data()[0];\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tmove_destination = nullptr;\t\t// cancel a previously made move decision; T/F says \"do not move\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ((result_type == EidosValueType::kValueObject) &&\n\t\t\t\t\t\t\t\t (result->Count() == 1) &&\n\t\t\t\t\t\t\t\t (((EidosValue_Object *)result)->Class() == gSLiM_Subpopulation_Class))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// a Subpopulation object means the individual should move to that subpop (and live); this is done in a post-pass\n\t\t\t\t\t\t\t// moving to one's current subpopulation is not-moving; it is equivalent to returning T (i.e., forces survival)\n\t\t\t\t\t\t\tp_surviving = true;\n\t\t\t\t\t\t\t\n#if DEBUG\n\t\t\t\t\t\t\t// this checks the value type at runtime\n\t\t\t\t\t\t\tSubpopulation *destination = (Subpopulation *)result->ObjectData()[0];\n#else\n\t\t\t\t\t\t\t// unsafe cast for speed\n\t\t\t\t\t\t\tSubpopulation *destination = (Subpopulation *)((EidosValue_Object *)result)->data()[0];\n#endif\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (destination != this)\n\t\t\t\t\t\t\t\tmove_destination = destination;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ApplySurvivalCallbacks): survival() callbacks must provide a return value of NULL, T, F, or object<Subpopulation>$.\" << EidosTerminate(survival_callback->identifier_token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (move_destination)\n\t{\n\t\t// if the callbacks used settled upon a decision of moving the individual, note that now; we do this in a delayed fashion\n\t\t// so that if there is more than one survival() callback active, we register only the final verdict after all callbacks\n\t\tmove_destination->nonWF_survival_moved_individuals_.emplace_back(p_individual);\n\t}\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tSLIM_PROFILE_BLOCK_END(community_.profile_callback_totals_[(int)(SLiMEidosBlockType::SLiMEidosSurvivalCallback)]);\n#endif\n\t\n\treturn p_surviving;\n}\n\nvoid Subpopulation::ViabilitySurvival(std::vector<SLiMEidosBlock*> &p_survival_callbacks)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Subpopulation::ViabilitySurvival(): usage of statics, probably many other issues\");\n\t\n\t// Loop through our individuals and do draws based on fitness to determine who dies; dead individuals get compacted out\n\tIndividual **individual_data = parent_individuals_.data();\n\tint survived_individual_index = 0;\n\tint females_deceased = 0;\n\tbool individuals_died = false;\n\tbool pedigrees_enabled = species_.PedigreesEnabled();\n\tbool no_callbacks = (p_survival_callbacks.size() == 0);\n\t\n\t// We keep a global static buffer that records survival decisions\n\tstatic uint8_t *survival_buffer = nullptr;\n\tstatic int survival_buf_capacity = 0;\n\t\n\tif (parent_subpop_size_ > survival_buf_capacity)\n\t{\n\t\tsurvival_buf_capacity = parent_subpop_size_ * 2;\t\t// double capacity to avoid excessive reallocation\n\t\tif (survival_buffer)\n\t\t\tfree(survival_buffer);\n\t\tsurvival_buffer = (uint8_t *)malloc(survival_buf_capacity * sizeof(uint8_t));\n\t}\n\t\n\t// clear lifetime reproductive outputs, in preparation for new values\n\tif (pedigrees_enabled)\n\t{\n\t\tlifetime_reproductive_output_MH_.resize(0);\n\t\tlifetime_reproductive_output_F_.resize(0);\n\t}\n\t\n\t// pre-plan mortality; this avoids issues with callbacks accessing the subpop state while buffers are being modified\n\tif (no_callbacks)\n\t{\n\t\t// this is the simple case with no callbacks and thus no shuffle buffer\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SURVIVAL);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SURVIVAL);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, survival_buffer, parent_subpop_size_) firstprivate(individual_data) if(parent_subpop_size_ >= EIDOS_OMPMIN_SURVIVAL) num_threads(thread_count)\n\t\t{\n\t\t\tuint8_t *survival_buf_perthread = survival_buffer;\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\tfor (int individual_index = 0; individual_index < parent_subpop_size_; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *individual = individual_data[individual_index];\n\t\t\t\tdouble fitness = individual->cached_fitness_UNSAFE_;\t// never overridden in nonWF models, so this is safe with no check\n\t\t\t\tuint8_t survived;\n\t\t\t\t\n\t\t\t\tif (fitness <= 0.0)\t\t\tsurvived = false;\n\t\t\t\telse if (fitness >= 1.0)\tsurvived = true;\n\t\t\t\telse\t\t\t\t\t\tsurvived = (Eidos_rng_uniform_doubleCO(rng_64) < fitness);\n\t\t\t\t\n\t\t\t\tsurvival_buf_perthread[individual_index] = survived;\n\t\t\t}\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SURVIVAL);\n\t}\n\telse\n\t{\n\t\t// this is the complex case with callbacks, and therefore a shuffle buffer to randomize processing order\n\t\tslim_popsize_t *shuffle_buf = species_.BorrowShuffleBuffer(parent_subpop_size_);\n\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\n\t\tfor (slim_popsize_t shuffle_index = 0; shuffle_index < parent_subpop_size_; shuffle_index++)\n\t\t{\n\t\t\tslim_popsize_t individual_index = shuffle_buf[shuffle_index];\n\t\t\tIndividual *individual = individual_data[individual_index];\n\t\t\tdouble fitness = individual->cached_fitness_UNSAFE_;\t// never overridden in nonWF models, so this is safe with no check\n\t\t\tdouble draw = Eidos_rng_uniform_doubleCO(rng_64);\t\t// always need a draw to pass to the callback\n\t\t\tuint8_t survived = (draw < fitness);\n\t\t\t\n\t\t\t// run the survival() callbacks to allow the above decision to be modified\n\t\t\tsurvived = ApplySurvivalCallbacks(p_survival_callbacks, individual, fitness, draw, survived);\n\t\t\t\n\t\t\tsurvival_buffer[individual_index] = survived;\n\t\t}\n\t\t\n\t\tspecies_.ReturnShuffleBuffer();\n\t}\n\t\n\t// execute the mortality plan; this never uses the shuffle buffer since we are no longer running callbacks\n\tfor (int individual_index = 0; individual_index < parent_subpop_size_; ++individual_index)\n\t{\n\t\tIndividual *individual = individual_data[individual_index];\n\t\tuint8_t survived = survival_buffer[individual_index];\n\t\t\n\t\tif (survived)\n\t\t{\n\t\t\t// individuals that survive get copied down to the next available slot\n\t\t\tif (survived_individual_index != individual_index)\n\t\t\t{\n\t\t\t\tindividual_data[survived_individual_index] = individual;\n\t\t\t\tindividual_data[survived_individual_index]->index_ = survived_individual_index;\n\t\t\t}\n\t\t\t\n\t\t\tsurvived_individual_index++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// individuals that do not survive get deallocated, and will be overwritten\n\t\t\tif (pedigrees_enabled)\n\t\t\t{\n\t\t\t\tif (sex_enabled_)\n\t\t\t\t{\n\t\t\t\t\tif (individual->sex_ == IndividualSex::kFemale)\n\t\t\t\t\t{\n\t\t\t\t\t\tfemales_deceased++;\n\t\t\t\t\t\tlifetime_reproductive_output_F_.emplace_back(individual->reproductive_output_);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tlifetime_reproductive_output_MH_.emplace_back(individual->reproductive_output_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlifetime_reproductive_output_MH_.emplace_back(individual->reproductive_output_);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (sex_enabled_ && (individual->sex_ == IndividualSex::kFemale))\n\t\t\t\t\tfemales_deceased++;\n\t\t\t}\n\t\t\t\n\t\t\tFreeSubpopIndividual(individual);\n\t\t\t\n\t\t\tindividuals_died = true;\n\t\t}\n\t}\n\t\n\t// Then fix our bookkeeping for the first male index, subpop size, caches, etc.\n\tif (individuals_died)\n\t{\n\t\tparent_subpop_size_ = survived_individual_index;\n\t\t\n\t\tif (sex_enabled_)\n\t\t\tparent_first_male_index_ -= females_deceased;\n\t\t\n\t\tparent_individuals_.resize(parent_subpop_size_);\n\t\t\n\t\tcached_parent_individuals_value_.reset();\n\t}\n}\n\n// nonWF only:\nvoid Subpopulation::IncrementIndividualAges(void)\n{\n\t// Loop through our individuals and increment all their ages by one\n\tstd::vector<Individual *> &parents = parent_individuals_;\n\tsize_t parent_count = parents.size();\n\t\n\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_AGE_INCR);\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_AGE_INCR);\n#pragma omp parallel for schedule(static) default(none) shared(parent_count) firstprivate(parents) if(parent_count >= EIDOS_OMPMIN_AGE_INCR) num_threads(thread_count)\n\tfor (size_t parent_index = 0; parent_index < parent_count; ++parent_index)\n\t{\n\t\t(parents[parent_index]->age_)++;\n\t}\n\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_AGE_INCR);\n}\n\nsize_t Subpopulation::MemoryUsageForParentTables(void)\n{\n\tsize_t usage = 0;\n\t\n\tif (lookup_parent_)\n\t\tusage += lookup_parent_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_female_parent_)\n\t\tusage += lookup_female_parent_->K * (sizeof(size_t) + sizeof(double));\n\t\n\tif (lookup_male_parent_)\n\t\tusage += lookup_male_parent_->K * (sizeof(size_t) + sizeof(double));\n\t\n\treturn usage;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *Subpopulation::Class(void) const\n{\n\treturn gSLiM_Subpopulation_Class;\n}\n\nvoid Subpopulation::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<p\" << subpopulation_id_ << \">\";\n}\n\nEidosValue_SP Subpopulation::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_id:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (!cached_value_subpop_id_)\n\t\t\t\tcached_value_subpop_id_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(subpopulation_id_));\n\t\t\treturn cached_value_subpop_id_;\n\t\t}\n\t\tcase gID_firstMaleIndex:\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(parent_first_male_index_));\n\t\t}\n\t\tcase gID_haplosomes:\n\t\t{\n\t\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\tsize_t expected_haplosome_count = parent_individuals_.size() * haplosome_count_per_individual;\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(expected_haplosome_count);\n\t\t\t\n\t\t\tfor (Individual *ind : parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_haplosomesNonNull:\n\t\t{\n\t\t\tint haplosome_count_per_individual = species_.HaplosomeCountPerIndividual();\n\t\t\tsize_t expected_haplosome_count = parent_individuals_.size() * haplosome_count_per_individual;\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class))->reserve(expected_haplosome_count);\n\t\t\t\n\t\t\tfor (Individual *ind : parent_individuals_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = ind->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (!haplosome->IsNull())\n\t\t\t\t\t\tvec->push_object_element_no_check_NORR(haplosome);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_individuals:\n\t\t{\n\t\t\tslim_popsize_t subpop_size = parent_subpop_size_;\n\t\t\t\n\t\t\t// Check for an outdated cache; this should never happen, so we flag it as an error\n\t\t\tif (cached_parent_individuals_value_ && (cached_parent_individuals_value_->Count() != subpop_size))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): (internal error) cached_parent_individuals_value_ out of date.\" << EidosTerminate();\n\t\t\t\n\t\t\t// Build and return an EidosValue_Object with the current set of individuals in it\n\t\t\tif (!cached_parent_individuals_value_)\n\t\t\t{\n\t\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(subpop_size);\n\t\t\t\tcached_parent_individuals_value_ = EidosValue_SP(vec);\n\t\t\t\t\n\t\t\t\tfor (slim_popsize_t individual_index = 0; individual_index < subpop_size; individual_index++)\n\t\t\t\t\tvec->push_object_element_no_check_NORR(parent_individuals_[individual_index]);\n\t\t\t}\n\t\t\t\n\t\t\treturn cached_parent_individuals_value_;\n\t\t}\n\t\tcase gID_immigrantSubpopIDs:\n\t\t{\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property immigrantSubpopIDs is not available in nonWF models.\" << EidosTerminate();\n\t\t\t\n\t\t\tEidosValue_Int *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto migrant_pair : migrant_fractions_)\n\t\t\t\tvec->push_int(migrant_pair.first);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_immigrantSubpopFractions:\n\t\t{\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property immigrantSubpopFractions is not available in nonWF models.\" << EidosTerminate();\n\t\t\t\n\t\t\tEidosValue_Float *vec = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\t\tEidosValue_SP result_SP = EidosValue_SP(vec);\n\t\t\t\n\t\t\tfor (auto migrant_pair : migrant_fractions_)\n\t\t\t\tvec->push_float(migrant_pair.second);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\tcase gID_lifetimeReproductiveOutput:\n\t\t{\n\t\t\tif (!species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property lifetimeReproductiveOutput is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::vector<int32_t> &lifetime_rep_M = lifetime_reproductive_output_MH_;\n\t\t\tstd::vector<int32_t> &lifetime_rep_F = lifetime_reproductive_output_F_;\n\t\t\tint lifetime_rep_count_M = (int)lifetime_rep_M.size();\n\t\t\tint lifetime_rep_count_F = (int)lifetime_rep_F.size();\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(lifetime_rep_count_M + lifetime_rep_count_F);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < lifetime_rep_count_M; ++value_index)\n\t\t\t\tint_result->set_int_no_check(lifetime_rep_M[value_index], value_index);\n\t\t\tfor (int value_index = 0; value_index < lifetime_rep_count_F; ++value_index)\n\t\t\t\tint_result->set_int_no_check(lifetime_rep_F[value_index], value_index + lifetime_rep_count_M);\n\t\t\t\n\t\t\treturn EidosValue_SP(int_result);\n\t\t}\n\t\tcase gID_lifetimeReproductiveOutputM:\n\t\t{\n\t\t\tif (!species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property lifetimeReproductiveOutputM is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\tif (!species_.SexEnabled())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property lifetimeReproductiveOutputM is not defined since separate sexes are not enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::vector<int32_t> &lifetime_rep = lifetime_reproductive_output_MH_;\n\t\t\tint lifetime_rep_count = (int)lifetime_rep.size();\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(lifetime_rep_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < lifetime_rep_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(lifetime_rep[value_index], value_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(int_result);\n\t\t}\n\t\tcase gID_lifetimeReproductiveOutputF:\n\t\t{\n\t\t\tif (!species_.PedigreesEnabledByUser())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property lifetimeReproductiveOutputF is not available because pedigree recording has not been enabled.\" << EidosTerminate();\n\t\t\tif (!species_.SexEnabled())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property lifetimeReproductiveOutputF is not defined since separate sexes are not enabled.\" << EidosTerminate();\n\t\t\t\n\t\t\tstd::vector<int32_t> &lifetime_rep = lifetime_reproductive_output_F_;\n\t\t\tint lifetime_rep_count = (int)lifetime_rep.size();\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(lifetime_rep_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < lifetime_rep_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(lifetime_rep[value_index], value_index);\n\t\t\t\n\t\t\treturn EidosValue_SP(int_result);\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name_));\n\t\t}\n\t\tcase gID_description:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(description_));\n\t\t}\n\t\tcase gID_selfingRate:\n\t\t{\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property selfingRate is not available in nonWF models.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(selfing_fraction_));\n\t\t}\n\t\tcase gID_cloningRate:\n\t\t{\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property cloningRate is not available in nonWF models.\" << EidosTerminate();\n\t\t\t\n\t\t\tif (sex_enabled_)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{female_clone_fraction_, male_clone_fraction_});\n\t\t\telse\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(female_clone_fraction_));\n\t\t}\n\t\tcase gID_sexRatio:\n\t\t{\n\t\t\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property sexRatio is not available in nonWF models.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(parent_sex_ratio_));\n\t\t}\n\t\tcase gID_spatialBounds:\n\t\t{\n\t\t\tint dimensionality = species_.SpatialDimensionality();\n\t\t\t\n\t\t\tswitch (dimensionality)\n\t\t\t{\n\t\t\t\tcase 0: return gStaticEidosValue_Float_ZeroVec;\n\t\t\t\tcase 1: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_x0_, bounds_x1_});\n\t\t\t\tcase 2: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_x0_, bounds_y0_, bounds_x1_, bounds_y1_});\n\t\t\t\tcase 3: return EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{bounds_x0_, bounds_y0_, bounds_z0_, bounds_x1_, bounds_y1_, bounds_z1_});\n\t\t\t\tdefault:\treturn gStaticEidosValueNULL;\t// never hit; here to make the compiler happy\n\t\t\t}\n\t\t}\n\t\tcase gID_spatialMaps:\n\t\t{\n\t\t\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_SpatialMap_Class))->reserve(spatial_maps_.size());\n\t\t\t\n\t\t\tfor (const auto &spatialMapIter : spatial_maps_)\n\t\t\t\tvec->push_object_element_no_check_RR(spatialMapIter.second);\n\t\t\t\n\t\t\treturn EidosValue_SP(vec);\n\t\t}\n\t\tcase gID_species:\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(&species_, gSLiM_Species_Class));\n\t\t}\n\t\tcase gID_individualCount:\t\t// ACCELERATED\n\t\t{\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(parent_subpop_size_));\n\t\t}\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_tag:\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty): property tag accessed on subpopulation before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\tcase gID_fitnessScaling:\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(subpop_fitness_scaling_));\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *Subpopulation::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubpopulation *value = (Subpopulation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->subpopulation_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Subpopulation::GetProperty_Accelerated_firstMaleIndex(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubpopulation *value = (Subpopulation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->parent_first_male_index_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Subpopulation::GetProperty_Accelerated_individualCount(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubpopulation *value = (Subpopulation *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->parent_subpop_size_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Subpopulation::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubpopulation *value = (Subpopulation *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::GetProperty_Accelerated_tag): property tag accessed on subpopulation before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Subpopulation::GetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubpopulation *value = (Subpopulation *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->subpop_fitness_scaling_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nvoid Subpopulation::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_tag:\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_fitnessScaling:\t// ACCELERATED\n\t\t{\n\t\t\tsubpop_fitness_scaling_ = p_value.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((subpop_fitness_scaling_ < 0.0) || std::isnan(subpop_fitness_scaling_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetProperty): property fitnessScaling must be >= 0.0.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase gID_name:\n\t\t{\n\t\t\tSetName(p_value.StringAtIndex_NOCAST(0, nullptr));\n\t\t\treturn;\n\t\t}\n\t\tcase gID_description:\n\t\t{\n\t\t\tstd::string description = p_value.StringAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\t// there are no restrictions on descriptions at all\n\t\t\t\n\t\t\tdescription_ = description;\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nvoid Subpopulation::SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\t// SLiMCastToUsertagTypeOrRaise() is a no-op at present\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Subpopulation *)(p_values[value_index]))->tag_value_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Subpopulation *)(p_values[value_index]))->tag_value_ = source_data[value_index];\n\t}\n}\n\nvoid Subpopulation::SetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tdouble source_value = p_source.FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((source_value < 0.0) || std::isnan(source_value))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetProperty_Accelerated_fitnessScaling): property fitnessScaling must be >= 0.0.\" << EidosTerminate();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t\t((Subpopulation *)(p_values[value_index]))->subpop_fitness_scaling_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst double *source_data = p_source.FloatData();\n\t\t\n\t\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t\t{\n\t\t\tdouble source_value = source_data[value_index];\n\t\t\t\n\t\t\tif ((source_value < 0.0) || std::isnan(source_value))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::SetProperty_Accelerated_fitnessScaling): property fitnessScaling must be >= 0.0.\" << EidosTerminate();\n\t\t\t\n\t\t\t((Subpopulation *)(p_values[value_index]))->subpop_fitness_scaling_ = source_value;\n\t\t}\n\t}\n}\n\nEidosValue_SP Subpopulation::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\t\t// WF only:\n\t\tcase gID_setMigrationRates:\t\treturn ExecuteMethod_setMigrationRates(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setCloningRate:\t\treturn ExecuteMethod_setCloningRate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setSelfingRate:\t\treturn ExecuteMethod_setSelfingRate(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setSexRatio:\t\t\treturn ExecuteMethod_setSexRatio(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setSubpopulationSize:\treturn ExecuteMethod_setSubpopulationSize(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\t\t// nonWF only:\n\t\tcase gID_addCloned:\t\t\t\treturn ExecuteMethod_addCloned(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addCrossed:\t\t\treturn ExecuteMethod_addCrossed(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addEmpty:\t\t\t\treturn ExecuteMethod_addEmpty(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addMultiRecombinant:\treturn ExecuteMethod_addMultiRecombinant(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addRecombinant:\t\treturn ExecuteMethod_addRecombinant(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSelfed:\t\t\t\treturn ExecuteMethod_addSelfed(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_removeSubpopulation:\treturn ExecuteMethod_removeSubpopulation(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_takeMigrants:\t\t\treturn ExecuteMethod_takeMigrants(p_method_id, p_arguments, p_interpreter);\n\n\t\tcase gID_haplosomesForChromosomes:\treturn ExecuteMethod_haplosomesForChromosomes(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_deviatePositions:\t\treturn ExecuteMethod_deviatePositions(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_deviatePositionsWithMap:\treturn ExecuteMethod_deviatePositionsWithMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointDeviated:\t\t\treturn ExecuteMethod_pointDeviated(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointInBounds:\t\t\treturn ExecuteMethod_pointInBounds(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointReflected:\t\treturn ExecuteMethod_pointReflected(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointStopped:\t\t\treturn ExecuteMethod_pointStopped(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointPeriodic:\t\t\treturn ExecuteMethod_pointPeriodic(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointUniform:\t\t\treturn ExecuteMethod_pointUniform(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_pointUniformWithMap:\treturn ExecuteMethod_pointUniformWithMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_setSpatialBounds:\t\treturn ExecuteMethod_setSpatialBounds(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_cachedFitness:\t\t\treturn ExecuteMethod_cachedFitness(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_sampleIndividuals:\t\treturn ExecuteMethod_sampleIndividuals(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_subsetIndividuals:\t\treturn ExecuteMethod_subsetIndividuals(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_defineSpatialMap:\t\treturn ExecuteMethod_defineSpatialMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_addSpatialMap:\t\t\treturn ExecuteMethod_addSpatialMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_removeSpatialMap:\t\treturn ExecuteMethod_removeSpatialMap(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_spatialMapColor:\t\treturn ExecuteMethod_spatialMapColor(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_spatialMapImage:\t\treturn ExecuteMethod_spatialMapImage(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_spatialMapValue:\t\treturn ExecuteMethod_spatialMapValue(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_outputMSSample:\n\t\tcase gID_outputVCFSample:\n\t\tcase gID_outputSample:\t\t\treturn ExecuteMethod_outputXSample(p_method_id, p_arguments, p_interpreter);\n\t\tcase gID_configureDisplay:\t\treturn ExecuteMethod_configureDisplay(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\tdefault:\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n// nonWF only:\nIndividualSex Subpopulation::_ValidateHaplosomesAndChooseSex(ChromosomeType p_chromosome_type, bool p_haplosome1_null, bool p_haplosome2_null, EidosValue *p_sex_value, bool p_sex_enabled, const char *p_caller_name)\n{\n\tIndividualSex offspring_sex;\n\t\n\t// First, figure out what sex the user has requested and bounds-check it\n\tEidosValueType sex_value_type = p_sex_value->Type();\n\t\n\tif (p_sex_enabled)\n\t{\n\t\tif (sex_value_type == EidosValueType::kValueNULL)\n\t\t{\n\t\t\t// A sex value of NULL can be interpreted in either of two ways.  If the haplosome\n\t\t\t// configuration implies that the offspring must be a particular sex, then we\n\t\t\t// infer that sex.  If not, then we choose the sex of the individual with equal\n\t\t\t// probability.  We will defer the decision using kUnspecified here.\n\t\t\toffspring_sex = IndividualSex::kUnspecified;\n\t\t}\n\t\telse if (sex_value_type == EidosValueType::kValueString)\n\t\t{\n\t\t\t// if a string is provided, it must be either \"M\" or \"F\"\n\t\t\tconst std::string &sex_string = p_sex_value->StringData()[0];\n\t\t\t\n\t\t\tif (sex_string == \"M\")\n\t\t\t\toffspring_sex = IndividualSex::kMale;\n\t\t\telse if (sex_string == \"F\")\n\t\t\t\toffspring_sex = IndividualSex::kFemale;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): unrecognized value '\" << sex_string << \"' for parameter sex passed to \" << p_caller_name << \".\" << EidosTerminate();\n\t\t}\n\t\telse // if (sex_value_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble sex_prob = p_sex_value->FloatData()[0];\n\t\t\t\n\t\t\tif ((sex_prob >= 0.0) && (sex_prob <= 1.0))\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n\t\t\t\toffspring_sex = ((Eidos_rng_uniform_doubleCO(rng_64) < sex_prob) ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): probability \" << sex_prob << \" out of range [0.0, 1.0] for parameter sex passed to \" << p_caller_name << \".\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (sex_value_type != EidosValueType::kValueNULL)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): NULL must be passed for parameter sex passed to \" << p_caller_name << \", in non-sexual models.\" << EidosTerminate();\n\t\t\n\t\toffspring_sex = IndividualSex::kHermaphrodite;\n\t}\n\t\n\t// Second, simplify the code below by checking that all haploid chromosome types have\n\t// a null second haplosome.  The types listed here allow a non-null second haplosome.\n\t// This is marked as internal error because the caller should have already checked this.\n#if DEBUG\n\tif (!p_haplosome2_null)\n\t\tif ((p_chromosome_type != ChromosomeType::kA_DiploidAutosome) &&\n\t\t\t(p_chromosome_type != ChromosomeType::kX_XSexChromosome) &&\n\t\t\t(p_chromosome_type != ChromosomeType::kZ_ZSexChromosome) &&\n\t\t\t(p_chromosome_type != ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): (internal error) for chromosome type '\" << p_chromosome_type <<\"', \" << p_caller_name << \" requires that the second offspring haplosome is configured to be a null haplosome (since chromosome type '\" << p_chromosome_type << \"' is haploid).\" << EidosTerminate();\n#endif\n\t\n\t// Third, check the chromosome type and validate.  If a sex was chosen explicitly above,\n\t// this will raise if the haplosomes supplied are not compatible with that sex.  If a sex\n\t// was not explicitly chosen (i.e., NULL was passed), and the haplosomes provided imply\n\t// the sex, it will be chosen here.\n\tswitch (p_chromosome_type)\n\t{\n\t\t// chromosome types where we need to check the second haplosome, because it can be used\n\t\t//\n\t\tcase ChromosomeType::kA_DiploidAutosome:\n\t\t{\n\t\t\t// This type allows any null haplosome configuration in any individual, in addRecombinant() and addMultiRecombinant()\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kX_XSexChromosome:\n\t\t{\n\t\t\t// Males are required to be X-, females to be XX\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome2_null ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && (p_haplosome1_null || !p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'X', \" << p_caller_name << \" requires that for a male offspring the first haplosome is non-null and the second is null (X-).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && (p_haplosome1_null || p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'X', \" << p_caller_name << \" requires that for a female offspring both haplosomes are non-null (XX).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kZ_ZSexChromosome:\n\t\t{\n\t\t\t// Males are required to be ZZ, females to be -Z\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome1_null ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && (p_haplosome1_null || p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'Z', \" << p_caller_name << \" requires that for a male offspring both haplosomes are non-null (ZZ).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && (!p_haplosome1_null || p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'Z', \" << p_caller_name << \" requires that for a female offspring the first haplosome is null and the second is nonnull (-Z).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kNullY_YSexChromosomeWithNull:\n\t\t{\n\t\t\t// Males are required to be -Y, females to be --\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome2_null ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && (!p_haplosome1_null || p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type '-Y', \" << p_caller_name << \" requires that for a male offspring the first haplosome is null and the second is nonnull (-Y).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && (!p_haplosome1_null || !p_haplosome2_null))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type '-Y', \" << p_caller_name << \" requires that for a female offspring both haplosomes are null (--).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\t// chromosomes types that are always haploid, so the second haplosome was already checked above\n\t\t//\n\t\tcase ChromosomeType::kH_HaploidAutosome:\n\t\t{\n\t\t\t// This type allows any null haplosome configuration in any individual, in addRecombinant() and addMultiRecombinant()\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kY_YSexChromosome:\n\t\t{\n\t\t\t// Males are required to be Y, females to be -\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome1_null ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'Y', \" << p_caller_name << \" requires that for a male offspring the first haplosome is non-null (Y) (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && !p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'Y', \" << p_caller_name << \" requires that for a female offspring the first haplosome is null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kW_WSexChromosome:\n\t\t{\n\t\t\t// Males are required to be -, females to be W\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome1_null ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && !p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'W', \" << p_caller_name << \" requires that for a male offspring the first haplosome is null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'W', \" << p_caller_name << \" requires that for a female offspring the first haplosome is non-null (W) (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHF_HaploidFemaleInherited:\n\t\t{\n\t\t\t// Required present in both sexes; not informative about sex\n\t\t\tif (!p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'HF', \" << p_caller_name << \" requires that the first haplosome is non-null in both sexes (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kFL_HaploidFemaleLine:\n\t\t{\n\t\t\t// Males are required to be -, females to be present (like W)\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome1_null ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && !p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'FL', \" << p_caller_name << \" requires that for a male offspring the first haplosome is null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'FL', \" << p_caller_name << \" requires that for a female offspring the first haplosome is non-null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHM_HaploidMaleInherited:\n\t\t{\n\t\t\t// Required present in both sexes; not informative about sex\n\t\t\tif (!p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'HM', \" << p_caller_name << \" requires that the first haplosome is non-null in both sexes (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kML_HaploidMaleLine:\n\t\t{\n\t\t\t// Males are required to be present, females to be - (like Y)\n\t\t\tif (offspring_sex == IndividualSex::kUnspecified)\n\t\t\t\toffspring_sex = (p_haplosome1_null ? IndividualSex::kFemale : IndividualSex::kMale);\n\t\t\t\n\t\t\tif ((offspring_sex == IndividualSex::kMale) && p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'ML', \" << p_caller_name << \" requires that for a male offspring the first haplosome is non-null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tif ((offspring_sex == IndividualSex::kFemale) && !p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'ML', \" << p_caller_name << \" requires that for a female offspring the first haplosome is null (and the second haplosome is null, since this is a haploid chromosome type).\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t\tcase ChromosomeType::kHNull_HaploidAutosomeWithNull:\n\t\t{\n\t\t\t// Required H- in both sexes (not flexible like type H); not informative about sex\n\t\t\tif (p_haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::_ValidateHaplosomesAndChooseSex): for chromosome type 'H-', \" << p_caller_name << \" requires that the first haplosome is non-null (and the second haplosome is null, since this is a haploid chromosome type).  If you want a haploid chromosome type that allows arbitrary null haplosomes to be present, use type 'H'.\" << EidosTerminate();\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t// If the sex was not determined by the code above, we return IndividualSex::kUnspecified\n\t// and the caller will decide what to do with that (important for addMultiRecombinant(),\n\t// where the sex might be determined by any of the chromosomes being handled).\n\treturn offspring_sex;\n}\n\nIndividualSex Subpopulation::_SexForSexValue(EidosValue *p_sex_value, bool p_sex_enabled)\n{\n\tEidosValueType sex_value_type = p_sex_value->Type();\n\tIndividualSex sex;\n\t\n\tif (p_sex_enabled)\n\t{\n\t\tif (sex_value_type == EidosValueType::kValueNULL)\n\t\t{\n\t\t\t// in sexual simulations, NULL (the default) means pick a sex with equal probability\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tsex = (Eidos_RandomBool(rng_state) ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t}\n\t\telse if (sex_value_type == EidosValueType::kValueString)\n\t\t{\n\t\t\t// if a string is provided, it must be either \"M\" or \"F\"\n\t\t\tconst std::string &sex_string = p_sex_value->StringData()[0];\n\t\t\t\n\t\t\tif (sex_string == \"M\")\n\t\t\t\tsex = IndividualSex::kMale;\n\t\t\telse if (sex_string == \"F\")\n\t\t\t\tsex = IndividualSex::kFemale;\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::HaplosomeConfigurationForSex): unrecognized value '\" << sex_string << \"' for parameter sex.\" << EidosTerminate();\n\t\t}\n\t\telse // if (sex_value_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble sex_prob = p_sex_value->FloatData()[0];\n\t\t\t\n\t\t\tif ((sex_prob >= 0.0) && (sex_prob <= 1.0))\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n\t\t\t\tsex = ((Eidos_rng_uniform_doubleCO(rng_64) < sex_prob) ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::HaplosomeConfigurationForSex): probability \" << sex_prob << \" out of range [0.0, 1.0] for parameter sex.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (sex_value_type != EidosValueType::kValueNULL)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::HaplosomeConfigurationForSex): sex must be NULL in non-sexual models.\" << EidosTerminate();\n\t\t\n\t\tsex = IndividualSex::kHermaphrodite;\n\t}\n\t\n\treturn sex;\n}\n\n//\t*********************\t– (o<Individual>)addCloned(object<Individual>$ parent, [integer$ count = 1], [logical$ defer = F])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addCloned(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): addCloned() is not available in WF models.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): addCloned() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): addCloned() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// Get and check the parent\n\tEidosValue *parent_value = p_arguments[0].get();\n\tIndividual *parent = (Individual *)parent_value->ObjectData()[0];\n\tSubpopulation &parent_subpop = *parent->subpopulation_;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): addCloned() requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n\t\n\t// Check for some other illegal setups\n\tif (parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\n\t// Check the count and short-circuit if it is zero\n\tEidosValue *count_value = p_arguments[1].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): addCloned() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// Generate the number of children requested\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tEidosValue *defer_value = p_arguments[2].get();\n\tbool defer = defer_value->LogicalData()[0];\n\t\n\tif (defer)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> *parent_mutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\t\n\t\tif (!parent_mutation_callbacks->size()) parent_mutation_callbacks = nullptr;\n\t\t\n\t\tif (parent_mutation_callbacks)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCloned): deferred reproduction cannot be used when mutation() callbacks are enabled.\" << EidosTerminate();\n\t}\n#endif\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// Make the new individual as a candidate\n\t\tIndividual *individual = (this->*(population_.GenerateIndividualCloned_TEMPLATED))(parent);\n\t\t\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tIndividualSex parent_sex = parent->sex_;\n\t\t\t\t\n\t\t\t\t// note that parent_sex is also the child sex, since this is cloning\n\t\t\t\tif ((parent_sex == IndividualSex::kHermaphrodite) || (parent_sex == IndividualSex::kMale))\n\t\t\t\t\tgui_offspring_cloned_M_++;\n\t\t\t\tif ((parent_sex == IndividualSex::kHermaphrodite) || (parent_sex == IndividualSex::kFemale))\n\t\t\t\t\tgui_offspring_cloned_F_++;\n\t\t\t\t\n\t\t\t\t// this offspring came from a parent in parent_subpop but ended up here, so it is, in effect, a migrant;\n\t\t\t\t// we tally things, SLiMgui display purposes, as if it were generated in parent_subpop and then moved\n\t\t\t\tparent_subpop.gui_premigration_size_++;\n\t\t\t\tif (&parent_subpop != this)\n\t\t\t\t\tgui_migrants_[parent_subpop.subpopulation_id_]++;\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (o<Individual>)addCrossed(object<Individual>$ parent1, object<Individual>$ parent2, [Nfs$ sex = NULL], [integer$ count = 1], [logical$ defer = F])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addCrossed(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): addCrossed() is not available in WF models.\" << EidosTerminate();\n\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): addCrossed() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): addCrossed() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// Get and check the first parent (the mother)\n\tEidosValue *parent1_value = p_arguments[0].get();\n\tIndividual *parent1 = (Individual *)parent1_value->ObjectData()[0];\n\tIndividualSex parent1_sex = parent1->sex_;\n\tSubpopulation &parent1_subpop = *parent1->subpopulation_;\n\t\n\tif ((parent1_sex != IndividualSex::kFemale) && (parent1_sex != IndividualSex::kHermaphrodite))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): parent1 must be female in sexual models (or hermaphroditic in non-sexual models).\" << EidosTerminate();\n\t\n\t// Get and check the second parent (the father)\n\tEidosValue *parent2_value = p_arguments[1].get();\n\tIndividual *parent2 = (Individual *)parent2_value->ObjectData()[0];\n\tIndividualSex parent2_sex = parent2->sex_;\n\tSubpopulation &parent2_subpop = *parent2->subpopulation_;\n\t\n\tif ((parent2_sex != IndividualSex::kMale) && (parent2_sex != IndividualSex::kHermaphrodite))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): parent2 must be male in sexual models (or hermaphroditic in non-sexual models).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((&parent1_subpop.species_ != &this->species_) || (&parent2_subpop.species_ != &this->species_))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): addCrossed() requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\n\t// Check for some other illegal setups\n\tif ((parent1->index_ == -1) || (parent2->index_ == -1))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t\n\tif (species_.PreventIncidentalSelfing() && (parent1 == parent2))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): parent1 and parent2 must be different individuals, since preventIncidentalSelfing has been set to T (use addSelfed to generate a non-incidentally selfed offspring).\" << EidosTerminate();\n\t\n\t// Check the count and short-circuit if it is zero\n\tEidosValue *count_value = p_arguments[3].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): addCrossed() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// Generate the number of children requested\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tEidosValue *defer_value = p_arguments[4].get();\n\tbool defer = defer_value->LogicalData()[0];\n\t\n\tif (defer)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> *parent1_recombination_callbacks = &parent1_subpop.registered_recombination_callbacks_;\n\t\tstd::vector<SLiMEidosBlock*> *parent2_recombination_callbacks = &parent2_subpop.registered_recombination_callbacks_;\n\t\tstd::vector<SLiMEidosBlock*> *parent1_mutation_callbacks = &parent1_subpop.registered_mutation_callbacks_;\n\t\tstd::vector<SLiMEidosBlock*> *parent2_mutation_callbacks = &parent2_subpop.registered_mutation_callbacks_;\n\t\t\n\t\tif (!parent1_recombination_callbacks->size()) parent1_recombination_callbacks = nullptr;\n\t\tif (!parent2_recombination_callbacks->size()) parent2_recombination_callbacks = nullptr;\n\t\tif (!parent1_mutation_callbacks->size()) parent1_mutation_callbacks = nullptr;\n\t\tif (!parent2_mutation_callbacks->size()) parent2_mutation_callbacks = nullptr;\n\t\t\n\t\tif (parent1_recombination_callbacks || parent2_recombination_callbacks || parent1_mutation_callbacks || parent2_mutation_callbacks)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addCrossed): deferred reproduction cannot be used when recombination() or mutation() callbacks are enabled.\" << EidosTerminate();\n\t}\n#endif\n\t\n\tEidosValue *sex_value = p_arguments[2].get();\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// Determine the sex of the offspring based on the sex parameter\n\t\tIndividualSex child_sex = _SexForSexValue(sex_value, sex_enabled_);\n\t\t\n\t\t// Make the new individual; if it doesn't pass modifyChild(), nullptr will be returned\n\t\tIndividual *individual = (this->*(population_.GenerateIndividualCrossed_TEMPLATED))(parent1, parent2, child_sex);\n\t\t\n\t\t// If the child was accepted, add it to our staging area and to our result vector\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tgui_offspring_crossed_++;\n\t\t\t\t\n\t\t\t\t// this offspring came from parents in parent1_subpop and parent2_subpop but ended up here, so it is, in effect, a migrant;\n\t\t\t\t// we tally things, SLiMgui display purposes, as if it were generated in those other subpops and then moved\n\t\t\t\tparent1_subpop.gui_premigration_size_ += 0.5;\n\t\t\t\tparent2_subpop.gui_premigration_size_ += 0.5;\n\t\t\t\tif (&parent1_subpop != this)\n\t\t\t\t\tgui_migrants_[parent1_subpop.subpopulation_id_] += 0.5;\n\t\t\t\tif (&parent2_subpop != this)\n\t\t\t\t\tgui_migrants_[parent2_subpop.subpopulation_id_] += 0.5;\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (o<Individual>)addEmpty([Nfs$ sex = NULL], [Nl$ haplosome1Null = NULL], [Nl$ haplosome2Null = NULL], [integer$ count = 1])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addEmpty(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addEmpty): addEmpty() is not available in WF models.\" << EidosTerminate();\n\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addEmpty): addEmpty() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addEmpty): addEmpty() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// Check the count and short-circuit if it is zero\n\tEidosValue *count_value = p_arguments[3].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addEmpty): addEmpty() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// Process other parameters; haplosome1Null and haplosome2Null are now interpreted specifically for chromosome type \"A\" only,\n\t// saying whether the corresponding haplosome for a type \"A\" chromosome should be null (true) or non-null (false /NULL).\n\tEidosValue *sex_value = p_arguments[0].get();\n\tEidosValue *haplosome1Null_value = p_arguments[1].get();\n\tEidosValue *haplosome2Null_value = p_arguments[2].get();\n\t\n\tbool haplosome1_null = false, haplosome2_null = false;\n\t\n\tif (haplosome1Null_value->Type() != EidosValueType::kValueNULL)\n\t\thaplosome1_null = haplosome1Null_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tif (haplosome2Null_value->Type() != EidosValueType::kValueNULL)\n\t\thaplosome2_null = haplosome2Null_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// Generate the number of children requested\n\tbool record_in_treeseq = species_.RecordingTreeSequence();\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// Determine the sex of the offspring based on the sex parameter\n\t\tIndividualSex child_sex = _SexForSexValue(sex_value, sex_enabled_);\n\t\t\n\t\t// Make the new individual; if it doesn't pass modifyChild(), nullptr will be returned\n\t\tIndividual *individual = GenerateIndividualEmpty(/* index */ -1,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* sex */ child_sex,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* age */ 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* fitness */ NAN,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* mean_parent_age */ 0.0F,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* haplosome1_null */ haplosome1_null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* haplosome2_null */ haplosome2_null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t /* run_modify_child */ true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t record_in_treeseq);\n\t\t\n\t\t// If the child was accepted, add it to our staging area and to our result vector\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tgui_offspring_empty_++;\n\t\t\t\tgui_premigration_size_++;\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (object<Individual>)addMultiRecombinant(object<Dictionary>$ pattern, [Nfs$ sex = NULL], [No<Individual>$ parent1 = NULL], [No<Individual>$ parent2 = NULL], [Nl$ randomizeStrands = NULL], [integer$ count = 1], [logical$ defer = F])\nEidosValue_SP Subpopulation::ExecuteMethod_addMultiRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// This code is strongly patterned on the code for addRecombinant(), and should be maintained in parallel\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() is not available in WF models.\" << EidosTerminate();\n\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// We could technically make this work in the no-genetics case, if the parameters specify that both\n\t// child haplosomes are null, but there's really no reason for anybody to use addRecombinant() in that\n\t// case, and getting all the logic correct below would be error-prone.\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() may not be called for a no-genetics species.\" << EidosTerminate();\n\t\n\t// Get arguments and do trivial processing\n\tEidosValue *pattern_value = p_arguments[0].get();\n\tEidosValue *sex_value = p_arguments[1].get();\n\tEidosValue *parent1_value = p_arguments[2].get();\n\tEidosValue *parent2_value = p_arguments[3].get();\n\tEidosValue *randomizeStrands_value = p_arguments[4].get();\n\tEidosValue *count_value = p_arguments[5].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tEidosValue *defer_value = p_arguments[6].get();\n\tbool defer = defer_value->LogicalData()[0];\n#endif\n\t\n\t// Prepare for processing the pattern dictionary.  Iterating through pattern is a bit tricky because it\n\t// could use either integer or string keys, and we want to share all the code that follows after a value\n\t// has been looked up.  The solution here comes from https://stackoverflow.com/a/44661987/2752221.\n\tEidosDictionaryUnretained *pattern = (EidosDictionaryUnretained *)pattern_value->ObjectData()[0];\n\tbool pattern_keysAreIntegers = pattern->KeysAreIntegers();\n\tbool pattern_keysAreStrings = pattern->KeysAreStrings();\n\tint pattern_keyCount = pattern->KeyCount();\n\t\n\t// We need to be careful, because a new empty dictionary has no dictionary symbols; it hasn't decided yet\n\t// whether it uses integer or string keys.  We can't make an iterator for a dictionary in that state.\n\tbool pattern_empty = (pattern_keyCount == 0);\n\tconst EidosDictionaryHashTable_IntegerKeys *pattern_integerKeys = (!pattern_empty && pattern_keysAreIntegers ? pattern->DictionarySymbols_IntegerKeys() : nullptr);\n\tconst EidosDictionaryHashTable_StringKeys *pattern_stringKeys = (!pattern_empty && pattern_keysAreStrings ? pattern->DictionarySymbols_StringKeys() : nullptr);\n\t\n\ttypedef decltype(std::begin(std::declval<const EidosDictionaryHashTable_IntegerKeys&>())) pattern_integer_keys_iter_type;\n\ttypedef decltype(std::begin(std::declval<const EidosDictionaryHashTable_StringKeys&>())) pattern_string_keys_iter_type;\n\t\n\t// Check the count and short-circuit if it is zero\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// PASS 1:\n\t//\n\t// Check the pattern dictionary and determine the child sex.  This has to be done before the main loop,\n\t// even though it means iterating through the pattern dictionary twice, because we need to determine the\n\t// child sex up front, and it could be constrained by any entry in the pattern dictionary (and those\n\t// entries could even conflict).  It also has the virtue of validating the structure of the pattern\n\t// dictionary, so the actual reproduction code later can be simpler.  We also determine the values of\n\t// randomizeStrands and mean_parent_age here, for similar reasons.\n\tIndividualSex constrained_child_sex = IndividualSex::kUnspecified;\n\tbool randomizeStrands = false;\n\tfloat mean_parent_age = 0.0;\n\tint mean_parent_age_non_null_count = 0;\n\tpattern_integer_keys_iter_type pattern_integer_key_iter;\n\tpattern_string_keys_iter_type pattern_string_key_iter;\n\t\n\tif (pattern_integerKeys)\t\tpattern_integer_key_iter = pattern_integerKeys->begin();\n\telse if (pattern_stringKeys)\tpattern_string_key_iter = pattern_stringKeys->begin();\n\t\n\t// note that if pattern_keyCount == 0, neither iterator will be set up\n\t\n\tfor (int pattern_keyIndex = 0; pattern_keyIndex < pattern_keyCount; ++pattern_keyIndex)\n\t{\n\t\t// Each entry in pattern has a key that identifies a chromosome (id or symbol), and a dictionary value.\n\t\tChromosome *inheritance_chromosome;\n\t\tEidosValue *valueForKey;\n\t\t\n\t\tif (pattern_keysAreIntegers) {\n\t\t\tint64_t chromosome_id = pattern_integer_key_iter->first;\n\t\t\t\n\t\t\tinheritance_chromosome = species_.ChromosomeFromID(chromosome_id);\n\t\t\tif (!inheritance_chromosome)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() could not find a chromosome in the focal species with an id of \" << chromosome_id << \".\" << EidosTerminate();\n\t\t\t\n\t\t\tvalueForKey = pattern_integer_key_iter->second.get();\n\t\t\tpattern_integer_key_iter = std::next(pattern_integer_key_iter);\n\t\t} else {\n\t\t\tconst std::string &chromosome_symbol = pattern_string_key_iter->first;\n\t\t\t\n\t\t\tinheritance_chromosome = species_.ChromosomeFromSymbol(chromosome_symbol);\n\t\t\tif (!inheritance_chromosome)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() could not find a chromosome in the focal species with a symbol of \" << chromosome_symbol << \".\" << EidosTerminate();\n\t\t\t\n\t\t\tvalueForKey = pattern_string_key_iter->second.get();\n\t\t\tpattern_string_key_iter = std::next(pattern_string_key_iter);\n\t\t}\n\t\t\n\t\tif (!valueForKey || (valueForKey->Count() != 1) || (valueForKey->Type() != EidosValueType::kValueObject))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that the values within the pattern dictionary are singletons of class Dictionary (or a subclass of Dictionary).\" << EidosTerminate();\n\t\t\n\t\tEidosDictionaryUnretained *inheritance = dynamic_cast<EidosDictionaryUnretained *>(valueForKey->ObjectData()[0]);\n\t\tif (!inheritance)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that the values within the pattern dictionary are of class Dictionary (or a subclass of Dictionary).\" << EidosTerminate();\n\t\t\n\t\tif (!inheritance->KeysAreStrings())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that the inheritance dictionaries within the pattern dictionary use strings for keys.\" << EidosTerminate();\n\t\t\n\t\t// OK, now we have an inheritance dictionary, and need to decode it; zero entries means all keys are NULL\n\t\tEidosValue *strand1_value = nullptr;\n\t\tEidosValue *strand2_value = nullptr;\n\t\tEidosValue *breaks1_value = nullptr;\n\t\tEidosValue *strand3_value = nullptr;\n\t\tEidosValue *strand4_value = nullptr;\n\t\tEidosValue *breaks2_value = nullptr;\n\t\t\n\t\tif (inheritance->KeyCount() > 0)\n\t\t{\n\t\t\tconst EidosDictionaryHashTable_StringKeys *inheritance_stringKeys = inheritance->DictionarySymbols_StringKeys();\n\t\t\t\n\t\t\tfor (auto const &inheritance_element : *inheritance_stringKeys)\n\t\t\t{\n\t\t\t\tconst std::string &inheritance_key = inheritance_element.first;\n\t\t\t\tEidosValue * const inheritance_value = inheritance_element.second.get();\n\t\t\t\t\n\t\t\t\tif (inheritance_key == gStr_strand1)\t\tstrand1_value = inheritance_value;\n\t\t\t\telse if (inheritance_key == gStr_strand2)\tstrand2_value = inheritance_value;\n\t\t\t\telse if (inheritance_key == gStr_breaks1)\tbreaks1_value = inheritance_value;\n\t\t\t\telse if (inheritance_key == gStr_strand3)\tstrand3_value = inheritance_value;\n\t\t\t\telse if (inheritance_key == gStr_strand4)\tstrand4_value = inheritance_value;\n\t\t\t\telse if (inheritance_key == gStr_breaks2)\tbreaks2_value = inheritance_value;\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): unrecognized inheritance dictionary key '\" << inheritance_key << \"'; keys must be one of 'strand1', 'strand2', 'breaks1', 'strand3', 'strand4', or 'breaks2'.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// OK, now we've decoded the inheritance dictionary, and we need to validate it\n\t\t\n\t\t// Get the haplosomes for the supplied strands, or nullptr for NULL.  Eidos has done no validation!\n\t\tHaplosome *strand1 = nullptr;\n\t\tHaplosome *strand2 = nullptr;\n\t\tHaplosome *strand3 = nullptr;\n\t\tHaplosome *strand4 = nullptr;\n\t\t\n\t\tif (strand1_value)\n\t\t{\n\t\t\tif ((strand1_value->Type() == EidosValueType::kValueObject) && (strand1_value->Count() == 1) && (((EidosValue_Object *)strand1_value)->Class() == gSLiM_Haplosome_Class))\n\t\t\t\tstrand1 = (Haplosome *)strand1_value->ObjectData()[0];\n\t\t\telse if (strand1_value->Type() != EidosValueType::kValueNULL)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'strand1' must either be omitted (NULL), or its value must be a singleton object of class Haplosome.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (strand2_value)\n\t\t{\n\t\t\tif ((strand2_value->Type() == EidosValueType::kValueObject) && (strand2_value->Count() == 1) && (((EidosValue_Object *)strand2_value)->Class() == gSLiM_Haplosome_Class))\n\t\t\t\tstrand2 = (Haplosome *)strand2_value->ObjectData()[0];\n\t\t\telse if (strand2_value->Type() != EidosValueType::kValueNULL)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'strand2' must either be omitted (NULL), or its value must be a singleton object of class Haplosome.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (strand3_value)\n\t\t{\n\t\t\tif ((strand3_value->Type() == EidosValueType::kValueObject) && (strand3_value->Count() == 1) && (((EidosValue_Object *)strand3_value)->Class() == gSLiM_Haplosome_Class))\n\t\t\t\tstrand3 = (Haplosome *)strand3_value->ObjectData()[0];\n\t\t\telse if (strand3_value->Type() != EidosValueType::kValueNULL)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'strand3' must either be omitted (NULL), or its value must be a singleton object of class Haplosome.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tif (strand4_value)\n\t\t{\n\t\t\tif ((strand4_value->Type() == EidosValueType::kValueObject) && (strand4_value->Count() == 1) && (((EidosValue_Object *)strand4_value)->Class() == gSLiM_Haplosome_Class))\n\t\t\t\tstrand4 = (Haplosome *)strand4_value->ObjectData()[0];\n\t\t\telse if (strand4_value->Type() != EidosValueType::kValueNULL)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'strand4' must either be omitted (NULL), or its value must be a singleton object of class Haplosome.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// New in SLiM 5, we raise if a null haplosome was passed in; remarkably, this was not checked for\n\t\t// previously, and could lead to a crash if the user tried to do it!  It never makes sense to do it,\n\t\t// really; if a null haplosome is involved you can't have breakpoints, so you *know* there's a null\n\t\t// haplosome since you have to make that breakpoint decision, so just pass NULL.  This prevents the\n\t\t// user from accidentally passing in a null haplosome and having addRecombinant() do a weird thing.\n\t\tif ((strand1 && strand1->IsNull()) || (strand2 && strand2->IsNull()) || (strand3 && strand3->IsNull()) || (strand4 && strand4->IsNull()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): a parental strand for addMultiRecombinant() is a null haplosome, which is not allowed; pass NULL instead.\" << EidosTerminate();\n\t\t\n\t\t// The parental strands must be visible in the subpopulation\n\t\tIndividual *strand1_parent = (strand1 ? strand1->individual_ : nullptr);\n\t\tIndividual *strand2_parent = (strand2 ? strand2->individual_ : nullptr);\n\t\tIndividual *strand3_parent = (strand3 ? strand3->individual_ : nullptr);\n\t\tIndividual *strand4_parent = (strand4 ? strand4->individual_ : nullptr);\n\t\t\n\t\tif ((strand1 && (strand1_parent->index_ == -1)) || (strand2 && (strand2_parent->index_ == -1)) ||\n\t\t\t(strand3 && (strand3_parent->index_ == -1)) || (strand4 && (strand4_parent->index_ == -1)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): a parental strand is not visible in the subpopulation (i.e., belongs to a new juvenile).\" << EidosTerminate();\n\t\t\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif ((strand1_parent && (&strand1_parent->subpopulation_->species_ != &species_)) ||\n\t\t\t(strand2_parent && (&strand2_parent->subpopulation_->species_ != &species_)) ||\n\t\t\t(strand3_parent && (&strand3_parent->subpopulation_->species_ != &species_)) ||\n\t\t\t(strand4_parent && (&strand4_parent->subpopulation_->species_ != &species_)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that all source haplosomes belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\t\n\t\t// Check that all haplosomes belong to the chromosome that was specified for this inheritance dictionary\n\t\tslim_chromosome_index_t chromosome_index = inheritance_chromosome->Index();\n\t\t\n\t\tif ((strand1 && (strand1->chromosome_index_ != chromosome_index)) ||\n\t\t\t(strand2 && (strand2->chromosome_index_ != chromosome_index)) ||\n\t\t\t(strand3 && (strand3->chromosome_index_ != chromosome_index)) ||\n\t\t\t(strand4 && (strand4->chromosome_index_ != chromosome_index)))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): all strands (haplosomes) in an inheritance dictionary must belong to the chromosome referred to by that inheritance dictionary (as specified by the pattern dictionary key for which the inheritance dictionary is the value).\" << EidosTerminate();\n\t\t\n\t\t// If the first strand of a pair is NULL, the second must also be NULL.  As above, the user has to know\n\t\t// which strands are null and which are not anyway, so this should not be a hardship.\n\t\tif (!strand1 && strand2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): if strand1 is NULL, strand2 must also be NULL.\" << EidosTerminate();\n\t\tif (!strand3 && strand4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): if strand3 is NULL, strand4 must also be NULL.\" << EidosTerminate();\n\t\t\n\t\t// Determine whether we are randomizing strands; note this sets randomizeStrands once for each\n\t\t// iteration, but always to the same value.  We need to check each inheritance dictionary against\n\t\t// the specified value of randomizeStrands to validate it, so we need it in pass 1.\n\t\tif (randomizeStrands_value->Type() == EidosValueType::kValueLogical)\n\t\t{\n\t\t\trandomizeStrands = randomizeStrands_value->LogicalData()[0];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// the default, NULL, raises an error unless the choice does not matter\n\t\t\tif ((strand1 && strand2) || (strand3 && strand4))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that T or F be supplied for randomizeStrands if recombination is involved in offspring generation (as it is here); it needs to know whether to randomize strands or not.\" << EidosTerminate();\n\t\t\t\n\t\t\t// doesn't matter, leave it as false\n\t\t}\n\t\t\n\t\t// Determine whether or not we're making a null haplosome in each position; this is determined wholly\n\t\t// by the input strands.  We will determine whether this is actually legal, according to sex and\n\t\t// chromosome type, below.\n\t\tbool haplosome1_null = (!strand1 && !strand2);\n\t\tbool haplosome2_null = (!strand3 && !strand4);\n\t\t\n\t\t// Determine whether we're going to make a second haplosome -- if the chromosome type is diploid.\n\t\t// The second haplosome might be a null haplosome; the question is whether to make one at all.\n\t\t// _ValidateHaplosomesAndChooseSex() does this check, but only in DEBUG; this is our responsibility.\n\t\tChromosomeType inheritance_chromosome_type = inheritance_chromosome->Type();\n\t\tbool make_second_haplosome = false;\n\t\t\n\t\tif ((inheritance_chromosome_type == ChromosomeType::kA_DiploidAutosome) ||\n\t\t\t(inheritance_chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t\t(inheritance_chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t\t(inheritance_chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\t\tmake_second_haplosome = true;\n\t\t\n\t\tif (!haplosome2_null && !make_second_haplosome)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): for chromosome type '\" << inheritance_chromosome_type <<\"', addMultiRecombinant() requires that the second offspring haplosome is configured to be a null haplosome (since chromosome type '\" << inheritance_chromosome_type << \"' is intrinsically haploid).\" << EidosTerminate();\n\t\t\n\t\t// If we're generating any null haplosomes, we need to remember that in the Subpopulation state,\n\t\t// to turn off optimizations.  If the chromosome is haploid, we chack only haplosome1_null.\n\t\tif (haplosome1_null || (haplosome2_null && make_second_haplosome))\n\t\t\thas_null_haplosomes_ = true;\n\t\t\n\t\t// Check that the breakpoint vectors make sense; breakpoints may not be supplied for a NULL pair or\n\t\t// a half-NULL pair, but must be supplied for a non-NULL pair.  BCH 9/20/2021: Added logic here in\n\t\t// support of the new semantics that (NULL, NULL, NULL) makes a null haplosome, not an empty haplosome.\n\t\t// BCH 1/8/2025: Changed logic here in support of the new semantics that (haplosome, haplosome, NULL)\n\t\t// requests that SLiM generate breakpoints for a cross in the usual way, so the user doesn't have to.\n\t\t//\n\t\t// First we need to check the types of the supplied breakpoint vectors; again, Eidos has done no\n\t\t// validation for us!  We do not sort/unique/bounds-check the breakpoint vectors here, since we don't\n\t\t// need them until the second pass.\n\t\tif (!breaks1_value)\n\t\t\tbreaks1_value = gStaticEidosValueNULL.get();\n\t\tif (!breaks2_value)\n\t\t\tbreaks2_value = gStaticEidosValueNULL.get();\n\t\t\n\t\tif ((breaks1_value->Type() != EidosValueType::kValueNULL) && (breaks1_value->Type() != EidosValueType::kValueInt))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'breaks1' must either be omitted (NULL), or its value must be of type integer.\" << EidosTerminate();\n\t\t\n\t\tif ((breaks2_value->Type() != EidosValueType::kValueNULL) && (breaks2_value->Type() != EidosValueType::kValueInt))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): inheritance dictionary key 'breaks2' must either be omitted (NULL), or its value must be of type integer.\" << EidosTerminate();\n\t\t\n\t\tint breaks1count = breaks1_value->Count(), breaks2count = breaks2_value->Count();\n\t\t\n\t\tif (breaks1count != 0)\n\t\t{\n\t\t\tif (haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): with a NULL strand1 and strand2, breaks1 must be NULL or empty.\" << EidosTerminate();\n\t\t\telse if (!strand2)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): non-empty breaks1 supplied with a NULL strand2; recombination between strand1 and strand2 is not possible, so breaks1 must be NULL or empty.\" << EidosTerminate();\n\t\t}\n\t\tif (breaks2count != 0)\n\t\t{\n\t\t\tif (haplosome2_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): with a NULL strand3 and strand4, breaks2 must be NULL or empty.\" << EidosTerminate();\n\t\t\telse if (!strand4)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): non-empty breaks2 supplied with a NULL strand4; recombination between strand3 and strand4 is not possible, so breaks2 must be NULL or empty.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\t// The mean parent age is averaged across the mean parent age for each non-null child haplosome\n\t\tif (strand1_parent && strand2_parent)\n\t\t{\n\t\t\tmean_parent_age += ((strand1_parent->age_ + (float)strand2_parent->age_) / 2.0F);\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse if (strand1_parent)\n\t\t{\n\t\t\tmean_parent_age += strand1_parent->age_;\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse if (strand2_parent)\n\t\t{\n\t\t\tmean_parent_age += strand2_parent->age_;\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this child haplosome is generated from NULL, NULL for parents, so there is no parent\n\t\t}\n\t\t\n\t\tif (strand3_parent && strand4_parent)\n\t\t{\n\t\t\tmean_parent_age += ((strand3_parent->age_ + (float)strand4_parent->age_) / 2.0F);\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse if (strand3_parent)\n\t\t{\n\t\t\tmean_parent_age += strand3_parent->age_;\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse if (strand4_parent)\n\t\t{\n\t\t\tmean_parent_age += strand4_parent->age_;\n\t\t\tmean_parent_age_non_null_count++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this child haplosome is generated from NULL, NULL for parents, so there is no parent\n\t\t}\n\t\t\n\t\t// Figure out what sex the offspring has to be, based on the chromosome type and haplosomes provided.\n\t\t// If sex_value specifies a sex, or a probability of a sex, then the sex will be chosen and checked\n\t\t// against the user-supplied data.  If it is NULL, then if the data constrains the choice it will be\n\t\t// chosen.  Otherwise, IndividualSex::kUnspecified will be returned, allowing a free choice below.\n\t\t// We allow the user to play many games with addRecombinant(), but the sex-linked constraints of the\n\t\t// chromosome type must be followed, because it is assumed in many places.\n\t\tIndividualSex inheritance_child_sex = _ValidateHaplosomesAndChooseSex(inheritance_chromosome_type, haplosome1_null, haplosome2_null, sex_value, sex_enabled_, \"addMultiRecombinant()\");\n\t\t\n\t\tif (constrained_child_sex == IndividualSex::kUnspecified)\n\t\t{\n\t\t\t// So far we have seen no constraint; accept the choice _ValidateHaplosomesAndChooseSex() made.\n\t\t\t// Note that this might still be IndividualSex::kUnspecified, until we get to a constraint.\n\t\t\tconstrained_child_sex = inheritance_child_sex;\n\t\t}\n\t\telse if ((inheritance_child_sex != IndividualSex::kUnspecified) && (constrained_child_sex != inheritance_child_sex))\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() was unable to determine the sex of the offspring, because it appears to be constrained to be different sexes by the specifications in different inheritance dictionaries.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// set the mean parent age now that we have validated all of the parental haplosomes\n\tif (mean_parent_age_non_null_count > 0)\n\t\tmean_parent_age = mean_parent_age / mean_parent_age_non_null_count;\n\t\n\t// Figure out the parents for purposes of pedigree recording.  If only one parent was supplied, use it\n\t// for both, just as we do for cloning and selfing; it makes relatedness() work.  Note mean_parent_age\n\t// comes from the strands.  BCH 9/26/2023: The first parent can now also be used for spatial positioning,\n\t// even if pedigree tracking is not enabled.  BCH 1/10/2025: We infer selfing/cloning for the parental\n\t// pattern here, which addRecombinant() does not do, because we need that to infer missing inheritance\n\t// dictionaries below.\n\tbool pedigrees_enabled = species_.PedigreesEnabled();\n\tIndividual *pedigree_parent1 = nullptr;\n\tIndividual *pedigree_parent2 = nullptr;\n\t//bool is_selfing = false;\t\t// the inheritance patterm is the same for selfing as for crossing, so we don't need this\n\tbool is_cloning = false;\n\t\n\tif (parent1_value->Type() != EidosValueType::kValueNULL)\n\t\tpedigree_parent1 = (Individual *)parent1_value->ObjectData()[0];\n\tif (parent2_value->Type() != EidosValueType::kValueNULL)\n\t\tpedigree_parent2 = (Individual *)parent2_value->ObjectData()[0];\n\t\n\t//if (pedigree_parent1 == pedigree_parent2)\n\t//\tis_selfing = true;\n\t\n\tif (pedigree_parent1 && !pedigree_parent2)\n\t{\n\t\tpedigree_parent2 = pedigree_parent1;\n\t\tis_cloning = true;\n\t}\n\tif (pedigree_parent2 && !pedigree_parent1)\n\t{\n\t\tpedigree_parent1 = pedigree_parent2;\n\t\tis_cloning = true;\n\t}\n\t\n\tif (pedigree_parent1)\n\t{\n\t\t// if we have pedigree parents, we need to sanity-check them\n\t\tif ((&pedigree_parent1->subpopulation_->species_ != &species_) || (&pedigree_parent2->subpopulation_->species_ != &species_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): addMultiRecombinant() requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\t\n\t\tif ((pedigree_parent1->index_ == -1) || (pedigree_parent2->index_ == -1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t}\n\t\n\t// Generate the number of children requested, using mutation() callbacks from the target subpopulation (this)\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = &registered_mutation_callbacks_;\n\t\n\tif (!mutation_callbacks->size())\n\t\tmutation_callbacks = nullptr;\n\t\n#if DEFER_BROKEN\n\tif (defer && mutation_callbacks)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): deferred reproduction cannot be used when mutation() callbacks are enabled.\" << EidosTerminate();\n#endif\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// If the child's sex is unconstrained, each child generated draws its sex independently\n\t\tIndividualSex child_sex = constrained_child_sex;\n\t\t\n\t\tif (child_sex == IndividualSex::kUnspecified)\n\t\t\tchild_sex = (Eidos_RandomBool(rng_state) ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\n\t\t// Make the new individual as a candidate; we make its haplosomes in the pass 2 loop below\n\t\tIndividual *individual = NewSubpopIndividual(/* index */ -1, child_sex, /* age */ 0, /* fitness */ NAN, mean_parent_age);\n\t\tslim_pedigreeid_t pid = 0;\n\t\t\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tpid = SLiM_GetNextPedigreeID();\n\t\t\t\n\t\t\tif (pedigree_parent1 == nullptr)\n\t\t\t\tindividual->TrackParentage_Parentless(pid);\n\t\t\telse if (pedigree_parent1 == pedigree_parent2)\n\t\t\t\tindividual->TrackParentage_Uniparental(pid, *pedigree_parent1);\n\t\t\telse\n\t\t\t\tindividual->TrackParentage_Biparental(pid, *pedigree_parent1, *pedigree_parent2);\n\t\t}\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (species_.RecordingTreeSequence())\n\t\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\t\n\t\t// BCH 9/26/2023: inherit the spatial position of pedigree_parent1 by default, to set up for deviatePositions()/pointDeviated()\n\t\t// Note that, unlike other addX() methods, the first parent is not necessarily defined; in that case, the\n\t\t// spatial position of the offspring is left uninitialized.\n\t\tif (pedigree_parent1)\n\t\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), pedigree_parent1);\n\t\t\n\t\t// PASS 2:\n\t\t//\n\t\t// Loop through all chromosomes; if an inheritance dictionary specifies what to do, follow those\n\t\t// instructions, otherwise produce the default behavior based on the chromosome type assuming\n\t\t// the given parents\n\t\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\t\tint currentHaplosomeIndex = 0;\n\t\t\n\t\tfor (Chromosome *chromosome : chromosomes)\n\t\t{\n\t\t\tChromosomeType chromosome_type = chromosome->Type();\n\t\t\tEidosDictionaryUnretained *inheritance = nullptr;\n\t\t\t\n\t\t\tif (pattern_integerKeys)\n\t\t\t{\n\t\t\t\tauto found_iter = pattern_integerKeys->find(chromosome->ID());\n\t\t\t\t\n\t\t\t\tif (found_iter != pattern_integerKeys->end())\n\t\t\t\t\tinheritance = (EidosDictionaryUnretained *)(found_iter->second.get()->ObjectData()[0]);\n\t\t\t}\n\t\t\telse if (pattern_stringKeys)\n\t\t\t{\n\t\t\t\tauto found_iter = pattern_stringKeys->find(chromosome->Symbol());\n\t\t\t\t\n\t\t\t\tif (found_iter != pattern_stringKeys->end())\n\t\t\t\t\tinheritance = (EidosDictionaryUnretained *)(found_iter->second.get()->ObjectData()[0]);\n\t\t\t}\n\t\t\t\n\t\t\t// note that if pattern_keyCount == 0, neither hash will be set up; inheritance will remain nullptr\n\t\t\t\n\t\t\tif (!inheritance && !pedigree_parent1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant):  addMultiRecombinant() has insufficient information to handle a chromosome (id \" << chromosome->ID() << \", symbol '\" << chromosome->Symbol() << \"'); no inheritance dictionary was specified for this chromosome, and inference of a default behavior is not possible since parent1 and parent2 are NULL.\" << EidosTerminate();\n\t\t\t\n\t\t\t// this is the information we will need, from the inheritance dictionary or synthesized\n\t\t\tHaplosome *strand1 = nullptr;\n\t\t\tHaplosome *strand2 = nullptr;\n\t\t\tHaplosome *strand3 = nullptr;\n\t\t\tHaplosome *strand4 = nullptr;\n\t\t\tstd::vector<slim_position_t> breakvec1, breakvec2;\n\t\t\tbool generate_breakvec1 = false;\n\t\t\tbool generate_breakvec2 = false;\n\t\t\t\n\t\t\tif (inheritance)\n\t\t\t{\n\t\t\t\t// process the inheritance dictionary; note that validation was done in pass 1\n\t\t\t\tEidosValue *breaks1_value = nullptr;\n\t\t\t\tEidosValue *breaks2_value = nullptr;\n\t\t\t\t\n\t\t\t\t{\n\t\t\t\t\tEidosValue *strand1_value = nullptr;\n\t\t\t\t\tEidosValue *strand2_value = nullptr;\n\t\t\t\t\tEidosValue *strand3_value = nullptr;\n\t\t\t\t\tEidosValue *strand4_value = nullptr;\n\t\t\t\t\t\n\t\t\t\t\tif (inheritance->KeyCount() > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosDictionaryHashTable_StringKeys *inheritance_stringKeys = inheritance->DictionarySymbols_StringKeys();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (auto const &inheritance_element : *inheritance_stringKeys)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst std::string &inheritance_key = inheritance_element.first;\n\t\t\t\t\t\t\tEidosValue * const inheritance_value = inheritance_element.second.get();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (inheritance_key == gStr_strand1)\t\tstrand1_value = inheritance_value;\n\t\t\t\t\t\t\telse if (inheritance_key == gStr_strand2)\tstrand2_value = inheritance_value;\n\t\t\t\t\t\t\telse if (inheritance_key == gStr_breaks1)\tbreaks1_value = inheritance_value;\n\t\t\t\t\t\t\telse if (inheritance_key == gStr_strand3)\tstrand3_value = inheritance_value;\n\t\t\t\t\t\t\telse if (inheritance_key == gStr_strand4)\tstrand4_value = inheritance_value;\n\t\t\t\t\t\t\telse if (inheritance_key == gStr_breaks2)\tbreaks2_value = inheritance_value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Get the haplosomes for the supplied strands, or nullptr for NULL\n\t\t\t\t\tif (strand1_value && (strand1_value->Type() == EidosValueType::kValueObject))\n\t\t\t\t\t\tstrand1 = (Haplosome *)strand1_value->ObjectData()[0];\n\t\t\t\t\tif (strand2_value && (strand2_value->Type() == EidosValueType::kValueObject))\n\t\t\t\t\t\tstrand2 = (Haplosome *)strand2_value->ObjectData()[0];\n\t\t\t\t\tif (strand3_value && (strand3_value->Type() == EidosValueType::kValueObject))\n\t\t\t\t\t\tstrand3 = (Haplosome *)strand3_value->ObjectData()[0];\n\t\t\t\t\tif (strand4_value && (strand4_value->Type() == EidosValueType::kValueObject))\n\t\t\t\t\t\tstrand4 = (Haplosome *)strand4_value->ObjectData()[0];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Copy the breakpoints into local buffers, since we will sort and modify them below.\n\t\t\t\t// If NULL is supplied for breaks, that is a request for the recombination breakpoints\n\t\t\t\t// to be generated automatically for a cross.  Note that the breaks count could also be\n\t\t\t\t// zero because integer(0) was passed; that just means \"no breakpoints for this cross\".\n\t\t\t\tif (!breaks1_value)\n\t\t\t\t\tbreaks1_value = gStaticEidosValueNULL.get();\n\t\t\t\tif (!breaks2_value)\n\t\t\t\t\tbreaks2_value = gStaticEidosValueNULL.get();\n\t\t\t\t\n\t\t\t\tint breaks1count = breaks1_value->Count(), breaks2count = breaks2_value->Count();\n\t\t\t\t\n\t\t\t\tif (breaks1count)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *breaks1_data = breaks1_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int break_index = 0; break_index < breaks1count; ++break_index)\n\t\t\t\t\t\tbreakvec1.emplace_back(SLiMCastToPositionTypeOrRaise(breaks1_data[break_index]));\n\t\t\t\t}\n\t\t\t\telse if ((breaks1_value->Type() == EidosValueType::kValueNULL) && strand1 && strand2)\n\t\t\t\t{\n\t\t\t\t\tgenerate_breakvec1 = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (breaks2count)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *breaks2_data = breaks2_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int break_index = 0; break_index < breaks2count; ++break_index)\n\t\t\t\t\t\tbreakvec2.emplace_back(SLiMCastToPositionTypeOrRaise(breaks2_data[break_index]));\n\t\t\t\t}\n\t\t\t\telse if ((breaks2_value->Type() == EidosValueType::kValueNULL) && strand3 && strand4)\n\t\t\t\t{\n\t\t\t\t\tgenerate_breakvec2 = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Randomly swap initial copy strands, if requested and applicable; this should not alter\n\t\t\t\t// any of the decisions we made earlier about null vs. non-null, child sex, etc.\n\t\t\t\tif (randomizeStrands)\n\t\t\t\t{\n\t\t\t\t\tif (strand1 && strand2 && Eidos_RandomBool(rng_state))\n\t\t\t\t\t\tstd::swap(strand1, strand2);\n\t\t\t\t\tif (strand3 && strand4 && Eidos_RandomBool(rng_state))\n\t\t\t\t\t\tstd::swap(strand3, strand4);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (is_cloning)\n\t\t\t{\n\t\t\t\t// Infer the inheritance dictionary info as addPatternForClone() would (same code path).\n\t\t\t\tspecies_.InferInheritanceForClone(chromosome, pedigree_parent1, child_sex, &strand1, &strand3, \"addMultiRecombinant()\");\n\t\t\t\t\n\t\t\t\t// no breakpoints are involved; strand2 and strand4 are not involved\n\t\t\t}\n\t\t\telse // crossed and selfed cases\n\t\t\t{\n\t\t\t\t// Infer the inheritance dictionary info as addPatternForCross() would (same code path).\n\t\t\t\t// Note that this randomizes the strand order for us, so we can ignore randomizeStrands.\n\t\t\t\tspecies_.InferInheritanceForCross(chromosome, pedigree_parent1, pedigree_parent2, child_sex, &strand1, &strand2, &strand3, &strand4, \"addMultiRecombinant()\");\n\t\t\t\t\n\t\t\t\t// when both parental strands are present, we want to generate breaks\n\t\t\t\tif (strand1 && strand2)\n\t\t\t\t\tgenerate_breakvec1 = true;\n\t\t\t\tif (strand3 && strand4)\n\t\t\t\t\tgenerate_breakvec2 = true;\n\t\t\t}\n\t\t\t\n\t\t\t// Generate breakpoints.  If the user passed NULL for breaks1, but strand1 and strand2 are\n\t\t\t// both non-NULL, it used to be an error but in SLiM 5 it requests that SLiM generate the\n\t\t\t// breakpoints for the cross automatically, avoiding the need to call drawBreakpoints().\n\t\t\t// This also allows addRecombinant() and addMultiRecombinant() to do gene conversion with\n\t\t\t// heteroduplex mismatch repair and gBGC, which was not previously possible.\n\t\t\tstd::vector<slim_position_t> heteroduplex1, heteroduplex2;\n\t\t\t\n\t\t\tif (generate_breakvec1)\n\t\t\t{\n\t\t\t\tchromosome->DrawBreakpoints(pedigree_parent1, strand1, strand2, /* p_num_breakpoints */ -1, breakvec1, &heteroduplex1, \"addMultiRecombinant()\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::sort(breakvec1.begin(), breakvec1.end());\n\t\t\t\tbreakvec1.erase(unique(breakvec1.begin(), breakvec1.end()), breakvec1.end());\n\t\t\t}\n\t\t\t\n\t\t\tif (generate_breakvec2)\n\t\t\t{\n\t\t\t\tchromosome->DrawBreakpoints(pedigree_parent2, strand3, strand4, /* p_num_breakpoints */ -1, breakvec2, &heteroduplex2, \"addMultiRecombinant()\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::sort(breakvec2.begin(), breakvec2.end());\n\t\t\t\tbreakvec2.erase(unique(breakvec2.begin(), breakvec2.end()), breakvec2.end());\n\t\t\t}\n\t\t\t\n\t\t\tif (breakvec1.size() && (breakvec1.back() > chromosome->last_position_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): breaks1 contained a value (\" << breakvec1.back() << \") that lies beyond the end of the chromosome.\" << EidosTerminate();\n\t\t\tif (breakvec2.size() && (breakvec2.back() > chromosome->last_position_))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addMultiRecombinant): breaks2 contained a value (\" << breakvec2.back() << \") that lies beyond the end of the chromosome.\" << EidosTerminate();\n\t\t\t\n\t\t\t// We used to need to look for a leading 0 in the breaks vectors, and swap the corresponding strands,\n\t\t\t// but HaplosomeRecombined() now handles that for us since it is shared functionality.\n\t\t\t\n\t\t\t//\n\t\t\t// Now, one way or another, we have all the information we need to generate the offspring\n\t\t\t// haplosomes for the current chromosome.  Note that for the selfed/crossed case this still\n\t\t\t// goes through HaplosomeRecombined(), not HaplosomeCrossed().  This is actually good; we\n\t\t\t// get consistent behavior from all paths through this method, whether the inheritance\n\t\t\t// dictionary is supplied or inferred.  Inference of an inheritance dictionary should give\n\t\t\t// exactly the same result as setting up the dictionary with addPatternForCross() etc.\n\t\t\t//\n\t\t\t\n\t\t\t// Get parents of the strands\n\t\t\tIndividual *strand1_parent = (strand1 ? strand1->individual_ : nullptr);\n\t\t\tIndividual *strand2_parent = (strand2 ? strand2->individual_ : nullptr);\n\t\t\tIndividual *strand3_parent = (strand3 ? strand3->individual_ : nullptr);\n\t\t\tIndividual *strand4_parent = (strand4 ? strand4->individual_ : nullptr);\n\t\t\t\n\t\t\t// Determine whether or not we're making a null haplosome in each position\n\t\t\tbool haplosome1_null = (!strand1 && !strand2);\n\t\t\tbool haplosome2_null = (!strand3 && !strand4);\n\t\t\t\n\t\t\t// Determine whether we're going to make a second haplosome -- if the chromosome type is diploid.\n\t\t\t// We do this also in pass 1, but we need to do it again because we need make_second_haplosome.\n\t\t\tbool make_second_haplosome = false;\n\t\t\t\n\t\t\tif ((chromosome_type == ChromosomeType::kA_DiploidAutosome) ||\n\t\t\t\t(chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\t\t\tmake_second_haplosome = true;\n\t\t\t\n\t\t\t// Make the new haplosomes for this chromosome\n\t\t\tHaplosome *haplosome1 = haplosome1_null ? chromosome->NewHaplosome_NULL(individual, 0) : chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\t\tHaplosome *haplosome2 = nullptr;\n\t\t\t\n\t\t\tif (make_second_haplosome)\n\t\t\t\thaplosome2 = haplosome2_null ? chromosome->NewHaplosome_NULL(individual, 1) : chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\t\n\t\t\tif (pedigrees_enabled)\n\t\t\t{\n\t\t\t\thaplosome1->haplosome_id_ = pid * 2;\n\t\t\t\tif (make_second_haplosome)\n\t\t\t\t\thaplosome2->haplosome_id_ = pid * 2 + 1;\n\t\t\t}\n\t\t\t\n\t\t\t// This has to happen after SetCurrentNewIndividual(), since it patches the node metadata\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome1, currentHaplosomeIndex);\n\t\t\tif (make_second_haplosome)\n\t\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, currentHaplosomeIndex + 1);\n\t\t\t\n\t\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\t\n\t\t\t// Construct the first child haplosome, depending upon whether recombination is requested, etc.\n\t\t\tif (strand1)\n\t\t\t{\n\t\t\t\tif (strand2 && breakvec1.size())\n\t\t\t\t{\n\t\t\t\t\tif (sex_enabled_ && !chromosome->UsingSingleMutationMap() && (strand1_parent->sex_ != strand2_parent->sex_))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): strand1 and strand2 come from individuals of different sex, and sex-specific mutation rate maps are in use, so it is not clear which mutation rate map to use.\" << EidosTerminate();\n\t\t\t\t\t\n#if DEFER_BROKEN\n\t\t\t\t\tif (defer)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand1, strand2, breakvec1, haplosome1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\t(population_.*(population_.HaplosomeRecombined_TEMPLATED))(*chromosome, *haplosome1, strand1, strand2, breakvec1, mutation_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (heteroduplex1.size() > 0)\n\t\t\t\t\t\t\tpopulation_.DoHeteroduplexRepair(heteroduplex1, breakvec1.data(), (int)breakvec1.size(), strand1, strand2, haplosome1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if DEFER_BROKEN\n\t\t\t\t\tif (defer)\n\t\t\t\t\t{\n\t\t\t\t\t\t// clone one haplosome, using a second strand of nullptr\n\t\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand1, nullptr, breakvec1, haplosome1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\t(population_.*(population_.HaplosomeCloned_TEMPLATED))(*chromosome, *haplosome1, strand1, mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// both strands are NULL, so we make a null haplosome; we do nothing but record it\n\t\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t\t\t\n#if DEBUG\n\t\t\t\tif (!haplosome1_null)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): (internal error) haplosome1_null is false with NULL parental strands!\" << EidosTerminate();\n#endif\n\t\t\t}\n\t\t\t\n\t\t\t// Construct the second child haplosome, depending upon whether recombination is requested, etc.\n\t\t\tif (strand3)\n\t\t\t{\n\t\t\t\tif (strand4 && breakvec2.size())\n\t\t\t\t{\n\t\t\t\t\tif (sex_enabled_ && !chromosome->UsingSingleMutationMap() && (strand3_parent->sex_ != strand4_parent->sex_))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): strand3 and strand4 come from individuals of different sex, and sex-specific mutation rate maps are in use, so it is not clear which mutation rate map to use.\" << EidosTerminate();\n\t\t\t\t\t\n#if DEFER_BROKEN\n\t\t\t\t\tif (defer)\n\t\t\t\t\t{\n\t\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand3, strand4, breakvec2, haplosome2);\n\t\t\t\t\t}\n\t\t\t\t\telse\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\t(population_.*(population_.HaplosomeRecombined_TEMPLATED))(*chromosome, *haplosome2, strand3, strand4, breakvec2, mutation_callbacks);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (heteroduplex2.size() > 0)\n\t\t\t\t\t\t\tpopulation_.DoHeteroduplexRepair(heteroduplex2, breakvec2.data(), (int)breakvec2.size(), strand3, strand4, haplosome2);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if DEFER_BROKEN\n\t\t\t\t\tif (defer)\n\t\t\t\t\t{\n\t\t\t\t\t\t// clone one haplosome, using a second strand of nullptr; note that in this case we pass the child sex, not the parent sex\n\t\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand3, nullptr, breakvec2, haplosome2);\n\t\t\t\t\t}\n\t\t\t\t\telse\n#endif\n\t\t\t\t\t{\n\t\t\t\t\t\t(population_.*(population_.HaplosomeCloned_TEMPLATED))(*chromosome, *haplosome2, strand3, mutation_callbacks);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (make_second_haplosome)\n\t\t\t{\n\t\t\t\t// both strands are NULL and this is a diploid chromosome, so we record a null haplosome\n\t\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t\t\t\n#if DEBUG\n\t\t\t\tif (!haplosome2_null)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): (internal error) haplosome2_null is false with NULL parental strands!\" << EidosTerminate();\n#endif\n\t\t\t}\n\t\t\t\n\t\t\tchromosome->StopMutationRunExperimentClock(\"addMultiRecombinant()\");\n\t\t\tcurrentHaplosomeIndex += (make_second_haplosome ? 2 : 1);\n\t\t}\n\t\t\n\t\t// Run the candidate past modifyChild() callbacks; the target subpop's registered callbacks are used\n\t\tif (registered_modify_child_callbacks_.size())\n\t\t{\n\t\t\t// BCH 4/5/2022: When removing excess pseudo-parameters from callbacks, we lost a bit of\n\t\t\t// functionality here: we used to pass the four recombinant strands to the callback as the\n\t\t\t// four \"parental haplosomes\".  But that was always kind of fictional, and it was never\n\t\t\t// documented, and I doubt anybody was using it, and they can do the same without the\n\t\t\t// modifyChild() callback, so I'm not viewing this loss of functionality as an obstacle\n\t\t\t// to making this change.\n\t\t\t// BCH 1/10/2025: Note that we pass nullptr for the parents, and false for p_is_selfing and\n\t\t\t// p_is_cloning.  We could use pedigree_parent1 and pedigree_parent2, and draw inferences from\n\t\t\t// them about selfing/cloning, but that would not always be correct; it would just be a guess.\n\t\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, /* p_parent1 */ nullptr, /* p_parent2 */ nullptr, /* p_is_selfing */ false, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ nullptr, registered_modify_child_callbacks_);\n\t\t\t\n\t\t\tif (!proposed_child_accepted)\n\t\t\t{\n\t\t\t\t// If the child was rejected, un-record it and dispose of it\n\t\t\t\tif (pedigrees_enabled)\n\t\t\t\t{\n\t\t\t\t\tif (pedigree_parent1 == nullptr)\n\t\t\t\t\t\tindividual->RevokeParentage_Parentless();\n\t\t\t\t\telse if (pedigree_parent1 == pedigree_parent2)\n\t\t\t\t\t\tindividual->RevokeParentage_Uniparental(*pedigree_parent1);\n\t\t\t\t\telse\n\t\t\t\t\t\tindividual->RevokeParentage_Biparental(*pedigree_parent1, *pedigree_parent2);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tFreeSubpopIndividual(individual);\n\t\t\t\tindividual = nullptr;\n\t\t\t\t\n\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// If the child was accepted, add it to our staging area and to our result vector\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tgui_offspring_crossed_++;\n\t\t\t\t\n\t\t\t\t// This offspring came from parents in various subpops but ended up here, so it is, in effect,\n\t\t\t\t// a migrant; we tally things, for SLiMgui display purposes, as if it were generated in the\n\t\t\t\t// parental subpops and then moved.  This is gross, but runs only in SLiMgui, so whatever :->\n\t\t\t\t// We do not set its migrant_ flag, though; that flag is only for takeMigrants() in nonWF.\n\t\t\t\t// Note that we use pedigree_parent1 and pedigree_parent2 for this, rather than the parents\n\t\t\t\t// of the strands; in the addMultiRecombinant() case there are potentially many strands with\n\t\t\t\t// many different parents.  It is just too complex to try to keep track of just for SLiMgui.\n\t\t\t\tif (pedigree_parent1)\n\t\t\t\t{\n\t\t\t\t\tpedigree_parent1->subpopulation_->gui_premigration_size_ += 0.5;\n\t\t\t\t\tif (pedigree_parent1->subpopulation_ != this)\n\t\t\t\t\t\tgui_migrants_[pedigree_parent1->subpopulation_->subpopulation_id_] += 0.5;\n\t\t\t\t}\n\t\t\t\tif (pedigree_parent2)\n\t\t\t\t{\n\t\t\t\t\tpedigree_parent2->subpopulation_->gui_premigration_size_ += 0.5;\n\t\t\t\t\tif (pedigree_parent2->subpopulation_ != this)\n\t\t\t\t\t\tgui_migrants_[pedigree_parent2->subpopulation_->subpopulation_id_] += 0.5;\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (o<Individual>)addRecombinant(No<Haplosome>$ strand1, No<Haplosome>$ strand2, Ni breaks1,\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo<Haplosome>$ strand3, No<Haplosome>$ strand4, Ni breaks2,\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[Nfs$ sex = NULL], [No<Individual>$ parent1 = NULL], [No<Individual>$ parent2 = NULL],\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[Nl$ randomizeStrands = NULL], [integer$ count = 1], [logical$ defer = F])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() is not available in WF models.\" << EidosTerminate();\n\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// We could technically make this work in the no-genetics case, if the parameters specify that both\n\t// child haplosomes are null, but there's really no reason for anybody to use addRecombinant() in that\n\t// case, and getting all the logic correct below would be error-prone.\n\tif (!species_.HasGenetics())\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() may not be called for a no-genetics species.\" << EidosTerminate();\n\t\n\t// This method may only be used in single-chromosome models; it is for the simple case, and for backward compatibility.\n\tif (species_.Chromosomes().size() != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() may only be called in single-chromosome models; see addMultiRecombinant() for the multi-chromosome version of this method.\" << EidosTerminate();\n\t\n\tChromosome *chromosome = species_.Chromosomes()[0];\n\t\n\t// Get arguments and do trivial processing\n\tEidosValue *breaks1_value = p_arguments[2].get();\n\tEidosValue *breaks2_value = p_arguments[5].get();\n\tEidosValue *sex_value = p_arguments[6].get();\n\tEidosValue *parent1_value = p_arguments[7].get();\n\tEidosValue *parent2_value = p_arguments[8].get();\n\tEidosValue *randomizeStrands_value = p_arguments[9].get();\n\tEidosValue *count_value = p_arguments[10].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tEidosValue *defer_value = p_arguments[11].get();\n\tbool defer = defer_value->LogicalData()[0];\n#endif\n\t\n\t// Check the count and short-circuit if it is zero\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// Note that empty Haplosome vectors are not legal values for the strandX parameters; the strands must\n\t// either be NULL or singleton.  If strand1 and strand2 are both NULL, breaks1 must be NULL/empty, and\n\t// the offspring haplosome will be empty and will not receive mutations.  If strand1 is non-NULL and\n\t// strand2 is NULL, breaks1 must be NULL/empty, and the offspring haplosome will be cloned with mutations.\n\t// If strand1 and strand2 are both non-NULL, breaks1 must be non-NULL but need not be sorted, and\n\t// recombination with mutations will occur.  If strand1 is NULL and strand2 is non-NULL, that is presently\n\t// an error, but may be given a meaning later.  The same is true, mutatis mutandis, for strand3, strand4,\n\t// and breaks2.  The sex parameter is interpreted as in addCrossed().\n\t// BCH 9/20/2021: For SLiM 3.7, these semantics are changing a little.  Now, when strand1 and strand2 are\n\t// both NULL and breaks1 is NULL/empty, the offspring haplosome will be a *null* haplosome (not just empty),\n\t// and as before will not receive mutations.  That is the way it always should have worked.  Again, mutatis\n\t// mutandis, for strand3, strand4, and breaks2.  See https://github.com/MesserLab/SLiM/issues/205.\n\t// BCH 1/8/2025: A further change for SLiM 5: if strand1 and strand2 are both non-NULL (doing a cross),\n\t// breaks1 may now be NULL indicating that addRecombinant() should draw breakpoints in the usual way.\n\t\n\t// Get the haplosomes for the supplied strands, or nullptr for NULL\n\tHaplosome *strand1;\n\tHaplosome *strand2;\n\tHaplosome *strand3;\n\tHaplosome *strand4;\n\t\n\t{\n\t\tEidosValue *strand1_value = p_arguments[0].get();\n\t\tEidosValue *strand2_value = p_arguments[1].get();\n\t\tEidosValue *strand3_value = p_arguments[3].get();\n\t\tEidosValue *strand4_value = p_arguments[4].get();\n\t\t\n\t\tstrand1 = ((strand1_value->Type() == EidosValueType::kValueNULL) ? nullptr : (Haplosome *)strand1_value->ObjectData()[0]);\n\t\tstrand2 = ((strand2_value->Type() == EidosValueType::kValueNULL) ? nullptr : (Haplosome *)strand2_value->ObjectData()[0]);\n\t\tstrand3 = ((strand3_value->Type() == EidosValueType::kValueNULL) ? nullptr : (Haplosome *)strand3_value->ObjectData()[0]);\n\t\tstrand4 = ((strand4_value->Type() == EidosValueType::kValueNULL) ? nullptr : (Haplosome *)strand4_value->ObjectData()[0]);\n\t}\n\t\n\t// New in SLiM 5, we raise if a null haplosome was passed in; remarkably, this was not checked for\n\t// previously, and could lead to a crash if the user tried to do it!  It never makes sense to do it,\n\t// really; if a null haplosome is involved you can't have breakpoints, so you *know* there's a null\n\t// haplosome since you have to make that breakpoint decision, so just pass NULL.  This prevents the\n\t// user from accidentally passing in a null haplosome and having addRecombinant() do a weird thing.\n\tif ((strand1 && strand1->IsNull()) || (strand2 && strand2->IsNull()) || (strand3 && strand3->IsNull()) || (strand4 && strand4->IsNull()))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): a parental strand for addRecombinant() is a null haplosome, which is not allowed; pass NULL instead.\" << EidosTerminate();\n\t\n\t// The parental strands must be visible in the subpopulation\n\tIndividual *strand1_parent = (strand1 ? strand1->individual_ : nullptr);\n\tIndividual *strand2_parent = (strand2 ? strand2->individual_ : nullptr);\n\tIndividual *strand3_parent = (strand3 ? strand3->individual_ : nullptr);\n\tIndividual *strand4_parent = (strand4 ? strand4->individual_ : nullptr);\n\t\n\tif ((strand1 && (strand1_parent->index_ == -1)) || (strand2 && (strand2_parent->index_ == -1)) ||\n\t\t(strand3 && (strand3_parent->index_ == -1)) || (strand4 && (strand4_parent->index_ == -1)))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): a parental strand is not visible in the subpopulation (i.e., belongs to a new juvenile).\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif ((strand1_parent && (&strand1_parent->subpopulation_->species_ != &species_)) ||\n\t\t(strand2_parent && (&strand2_parent->subpopulation_->species_ != &species_)) ||\n\t\t(strand3_parent && (&strand3_parent->subpopulation_->species_ != &species_)) ||\n\t\t(strand4_parent && (&strand4_parent->subpopulation_->species_ != &species_)))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() requires that all source haplosomes belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\n\t// We do not need to check that associated chromosomes for the strands match, because this method can\n\t// only be called in a single-chromosome model; addMultiRecombinant() will need to check that, though\n\t\n\t// If the first strand of a pair is NULL, the second must also be NULL.  As above, the user has to know\n\t// which strands are null and which are not anyway, so this should not be a hardship.\n\tif (!strand1 && strand2)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): if strand1 is NULL, strand2 must also be NULL.\" << EidosTerminate();\n\tif (!strand3 && strand4)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): if strand3 is NULL, strand4 must also be NULL.\" << EidosTerminate();\n\t\n\t// Determine whether we are randomizing strands; if we are, we will do it for each child generated\n\tbool randomizeStrands = false;\n\t\n\tif (randomizeStrands_value->Type() == EidosValueType::kValueLogical)\n\t{\n\t\trandomizeStrands = randomizeStrands_value->LogicalData()[0];\n\t}\n\telse\n\t{\n\t\t// the default, NULL, raises an error unless the choice does not matter\n\t\tif ((strand1 && strand2) || (strand3 && strand4))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() requires that T or F be supplied for randomizeStrands if recombination is involved in offspring generation (as it is here); it needs to know whether to randomize strands or not. (The default used to be F, but that was bug-prone since the correct value in most models is T; so now you need to think and make an explicit choice.)\" << EidosTerminate();\n\t\t\n\t\t// doesn't matter, leave it as false\n\t}\n\t\n\t// Determine whether or not we're making a null haplosome in each position; this is determined wholly\n\t// by the input strands.  We will determine whether this is actually legal, according to sex and\n\t// chromosome type, below.\n\tbool haplosome1_null = (!strand1 && !strand2);\n\tbool haplosome2_null = (!strand3 && !strand4);\n\t\n\t// Determine whether we're going to make a second haplosome -- if the chromosome type is diploid.\n\t// The second haplosome might be a null haplosome; the question is whether to make one at all.\n\t// _ValidateHaplosomesAndChooseSex() does this check, but only in DEBUG; this is our responsibility.\n\tChromosomeType chromosome_type = chromosome->Type();\n\tbool make_second_haplosome = false;\n\t\n\tif ((chromosome_type == ChromosomeType::kA_DiploidAutosome) ||\n\t\t(chromosome_type == ChromosomeType::kX_XSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kZ_ZSexChromosome) ||\n\t\t(chromosome_type == ChromosomeType::kNullY_YSexChromosomeWithNull))\n\t\tmake_second_haplosome = true;\n\t\n\tif (!haplosome2_null && !make_second_haplosome)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): for chromosome type '\" << chromosome_type <<\"', addRecombinant() requires that the second offspring haplosome is configured to be a null haplosome (since chromosome type '\" << chromosome_type << \"' is intrinsically haploid).\" << EidosTerminate();\n\t\n\t// If we're generating any null haplosomes, we need to remember that in the Subpopulation state,\n\t// to turn off optimizations.  If the chromosome is haploid, we check only haplosome1_null.\n\tif (haplosome1_null || (haplosome2_null && make_second_haplosome))\n\t\thas_null_haplosomes_ = true;\n\t\n\t// Check that the breakpoint vectors make sense; breakpoints may not be supplied for a NULL pair or\n\t// a half-NULL pair, but must be supplied for a non-NULL pair.  BCH 9/20/2021: Added logic here in\n\t// support of the new semantics that (NULL, NULL, NULL) makes a null haplosome, not an empty haplosome.\n\t// BCH 1/8/2025: Changed logic here in support of the new semantics that (haplosome, haplosome, NULL)\n\t// requests that SLiM generate breakpoints for a cross in the usual way, so the user doesn't have to.\n\tint breaks1count = breaks1_value->Count(), breaks2count = breaks2_value->Count();\n\t\n\tif (breaks1count != 0)\n\t{\n\t\tif (haplosome1_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): with a NULL strand1 and strand2, breaks1 must be NULL or empty.\" << EidosTerminate();\n\t\telse if (!strand2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): non-empty breaks1 supplied with a NULL strand2; recombination between strand1 and strand2 is not possible, so breaks1 must be NULL or empty.\" << EidosTerminate();\n\t}\n\tif (breaks2count != 0)\n\t{\n\t\tif (haplosome2_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): with a NULL strand3 and strand4, breaks2 must be NULL or empty.\" << EidosTerminate();\n\t\telse if (!strand4)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): non-empty breaks2 supplied with a NULL strand4; recombination between strand3 and strand4 is not possible, so breaks2 must be NULL or empty.\" << EidosTerminate();\n\t}\n\t\n\t// Copy the breakpoints into local buffers, since we will sort and modify them below.\n\t// If NULL is supplied for breaks, that is a request for the recombination breakpoints\n\t// to be generated automatically for a cross.  Note that the breaks count could also be\n\t// zero because integer(0) was passed; that just means \"no breakpoints for this cross\".\n\tstd::vector<slim_position_t> breakvec1, breakvec2;\n\tbool generate_breakvec1 = false;\n\tbool generate_breakvec2 = false;\n\t\n\tif (breaks1count)\n\t{\n\t\tconst int64_t *breaks1_data = breaks1_value->IntData();\n\t\t\n\t\tfor (int break_index = 0; break_index < breaks1count; ++break_index)\n\t\t\tbreakvec1.emplace_back(SLiMCastToPositionTypeOrRaise(breaks1_data[break_index]));\n\t}\n\telse if ((breaks1_value->Type() == EidosValueType::kValueNULL) && strand1 && strand2)\n\t{\n\t\tgenerate_breakvec1 = true;\n\t}\n\t\n\tif (breaks2count)\n\t{\n\t\tconst int64_t *breaks2_data = breaks2_value->IntData();\n\t\t\n\t\tfor (int break_index = 0; break_index < breaks2count; ++break_index)\n\t\t\tbreakvec2.emplace_back(SLiMCastToPositionTypeOrRaise(breaks2_data[break_index]));\n\t}\n\telse if ((breaks2_value->Type() == EidosValueType::kValueNULL) && strand3 && strand4)\n\t{\n\t\tgenerate_breakvec2 = true;\n\t}\n\t\n\t// The mean parent age is averaged across the mean parent age for each non-null child haplosome\n\tfloat mean_parent_age = 0.0;\n\tint mean_parent_age_non_null_count = 0;\n\t\n\tif (strand1_parent && strand2_parent)\n\t{\n\t\tmean_parent_age += ((strand1_parent->age_ + (float)strand2_parent->age_) / 2.0F);\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse if (strand1_parent)\n\t{\n\t\tmean_parent_age += strand1_parent->age_;\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse if (strand2_parent)\n\t{\n\t\tmean_parent_age += strand2_parent->age_;\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse\n\t{\n\t\t// this child haplosome is generated from NULL, NULL for parents, so there is no parent\n\t}\n\t\n\tif (strand3_parent && strand4_parent)\n\t{\n\t\tmean_parent_age += ((strand3_parent->age_ + (float)strand4_parent->age_) / 2.0F);\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse if (strand3_parent)\n\t{\n\t\tmean_parent_age += strand3_parent->age_;\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse if (strand4_parent)\n\t{\n\t\tmean_parent_age += strand4_parent->age_;\n\t\tmean_parent_age_non_null_count++;\n\t}\n\telse\n\t{\n\t\t// this child haplosome is generated from NULL, NULL for parents, so there is no parent\n\t}\n\t\n\tif (mean_parent_age_non_null_count > 0)\n\t\tmean_parent_age = mean_parent_age / mean_parent_age_non_null_count;\n\t\n\t// Figure out the parents for purposes of pedigree recording.  If only one parent was supplied, use it\n\t// for both, just as we do for cloning and selfing; it makes relatedness() work.  Note mean_parent_age\n\t// comes from the strands.  BCH 9/26/2023: the first parent can now also be used for spatial positioning,\n\t// even if pedigree tracking is not enabled.  BCH 1/10/2025: We do not need to infer selfing/cloning\n\t// here, the way addMultiRecombinant() does, since we don't need to infer inheritance patterns.\n\tbool pedigrees_enabled = species_.PedigreesEnabled();\n\tIndividual *pedigree_parent1 = nullptr;\n\tIndividual *pedigree_parent2 = nullptr;\n\t\n\tif (parent1_value->Type() != EidosValueType::kValueNULL)\n\t\tpedigree_parent1 = (Individual *)parent1_value->ObjectData()[0];\n\tif (parent2_value->Type() != EidosValueType::kValueNULL)\n\t\tpedigree_parent2 = (Individual *)parent2_value->ObjectData()[0];\n\t\n\tif (pedigree_parent1 && !pedigree_parent2)\n\t\tpedigree_parent2 = pedigree_parent1;\n\tif (pedigree_parent2 && !pedigree_parent1)\n\t\tpedigree_parent1 = pedigree_parent2;\n\t\n\tif (pedigree_parent1)\n\t{\n\t\t// if we have pedigree parents, we need to sanity-check them\n\t\tif ((&pedigree_parent1->subpopulation_->species_ != &species_) || (&pedigree_parent2->subpopulation_->species_ != &species_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): addRecombinant() requires that both parents belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\t\n\t\tif ((pedigree_parent1->index_ == -1) || (pedigree_parent2->index_ == -1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): parent1 and parent2 must be visible in a subpopulation (i.e., may not be new juveniles).\" << EidosTerminate();\n\t}\n\t\n\t// Figure out what sex the offspring has to be, based on the chromosome type and haplosomes provided.\n\t// If sex_value specifies a sex, or a probability of a sex, then the sex will be chosen and checked\n\t// against the user-supplied data.  If it is NULL, then if the data constrains the choice it will be\n\t// chosen.  Otherwise, IndividualSex::kUnspecified will be returned, allowing a free choice below.\n\t// We allow the user to play many games with addRecombinant(), but the sex-linked constraints of the\n\t// chromosome type must be followed, because it is assumed in many places.\n\tIndividualSex constrained_child_sex = _ValidateHaplosomesAndChooseSex(chromosome_type, haplosome1_null, haplosome2_null, sex_value, sex_enabled_, \"addRecombinant()\");\n\t\n\t// Generate the number of children requested, using mutation() callbacks from the target subpopulation (this)\n\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\tstd::vector<SLiMEidosBlock*> *mutation_callbacks = &registered_mutation_callbacks_;\n\t\n\tif (!mutation_callbacks->size())\n\t\tmutation_callbacks = nullptr;\n\t\n#if DEFER_BROKEN\n\tif (defer && mutation_callbacks)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): deferred reproduction cannot be used when mutation() callbacks are enabled.\" << EidosTerminate();\n#endif\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// If the child's sex is unconstrained, each child generated draws its sex independently\n\t\tIndividualSex child_sex = constrained_child_sex;\n\t\t\n\t\tif (child_sex == IndividualSex::kUnspecified)\n\t\t\tchild_sex = (Eidos_RandomBool(rng_state) ? IndividualSex::kMale : IndividualSex::kFemale);\n\t\t\n\t\t// Randomly swap initial copy strands, if requested and applicable; this should not alter\n\t\t// any of the decisions we made earlier about null vs. non-null, child sex, etc.  Note that\n\t\t// with child_count > 1 we'll be swapping back and forth, but that's fine.\n\t\tif (randomizeStrands)\n\t\t{\n\t\t\tif (strand1 && strand2 && Eidos_RandomBool(rng_state))\n\t\t\t{\n\t\t\t\tstd::swap(strand1, strand2);\n\t\t\t\tstd::swap(strand1_parent, strand2_parent);\n\t\t\t}\n\t\t\tif (strand3 && strand4 && Eidos_RandomBool(rng_state))\n\t\t\t{\n\t\t\t\tstd::swap(strand3, strand4);\n\t\t\t\tstd::swap(strand3_parent, strand4_parent);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Generate breakpoints.  If the user passed NULL for breaks1, but strand1 and strand2 are\n\t\t// both non-NULL, it used to be an error but in SLiM 5 it requests that SLiM generate the\n\t\t// breakpoints for the cross automatically, avoiding the need to call drawBreakpoints().\n\t\t// This also allows addRecombinant() and addMultiRecombinant() to do gene conversion with\n\t\t// heteroduplex mismatch repair and gBGC, which was not previously possible.\n\t\tstd::vector<slim_position_t> heteroduplex1, heteroduplex2;\n\t\t\n\t\tif (generate_breakvec1)\n\t\t{\n\t\t\tbreakvec1.resize(0);\t\t// we might be reusing this vector from a previous child\n\t\t\t\n\t\t\tchromosome->DrawBreakpoints(pedigree_parent1, strand1, strand2, /* p_num_breakpoints */ -1, breakvec1, &heteroduplex1, \"addRecombinant()\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::sort(breakvec1.begin(), breakvec1.end());\n\t\t\tbreakvec1.erase(unique(breakvec1.begin(), breakvec1.end()), breakvec1.end());\n\t\t}\n\t\t\n\t\tif (generate_breakvec2)\n\t\t{\n\t\t\tbreakvec2.resize(0);\t\t// we might be reusing this vector from a previous child\n\t\t\t\n\t\t\tchromosome->DrawBreakpoints(pedigree_parent2, strand3, strand4, /* p_num_breakpoints */ -1, breakvec2, &heteroduplex2, \"addRecombinant()\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::sort(breakvec2.begin(), breakvec2.end());\n\t\t\tbreakvec2.erase(unique(breakvec2.begin(), breakvec2.end()), breakvec2.end());\n\t\t}\n\t\t\n\t\tif (breakvec1.size() && (breakvec1.back() > chromosome->last_position_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): breaks1 contained a value (\" << breakvec1.back() << \") that lies beyond the end of the chromosome.\" << EidosTerminate();\n\t\tif (breakvec2.size() && (breakvec2.back() > chromosome->last_position_))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): breaks2 contained a value (\" << breakvec2.back() << \") that lies beyond the end of the chromosome.\" << EidosTerminate();\n\t\t\n\t\t// We used to need to look for a leading 0 in the breaks vectors, and swap the corresponding strands,\n\t\t// but HaplosomeRecombined() now handles that for us since it is shared functionality.\n\t\t\n\t\t// Make the new individual as a candidate\n\t\tIndividual *individual = NewSubpopIndividual(/* index */ -1, child_sex, /* age */ 0, /* fitness */ NAN, mean_parent_age);\n\t\tHaplosome *haplosome1 = haplosome1_null ? chromosome->NewHaplosome_NULL(individual, 0) : chromosome->NewHaplosome_NONNULL(individual, 0);\n\t\tHaplosome *haplosome2 = nullptr;\n\t\t\n\t\tif (make_second_haplosome)\n\t\t\thaplosome2 = haplosome2_null ? chromosome->NewHaplosome_NULL(individual, 1) : chromosome->NewHaplosome_NONNULL(individual, 1);\n\t\t\n\t\tif (pedigrees_enabled)\n\t\t{\n\t\t\tslim_pedigreeid_t pid = SLiM_GetNextPedigreeID();\n\t\t\t\n\t\t\tif (pedigree_parent1 == nullptr)\n\t\t\t\tindividual->TrackParentage_Parentless(pid);\n\t\t\telse if (pedigree_parent1 == pedigree_parent2)\n\t\t\t\tindividual->TrackParentage_Uniparental(pid, *pedigree_parent1);\n\t\t\telse\n\t\t\t\tindividual->TrackParentage_Biparental(pid, *pedigree_parent1, *pedigree_parent2);\n\t\t\t\n\t\t\thaplosome1->haplosome_id_ = pid * 2;\n\t\t\tif (make_second_haplosome)\n\t\t\t\thaplosome2->haplosome_id_ = pid * 2 + 1;\n\t\t}\n\t\t\n\t\t// TREE SEQUENCE RECORDING\n\t\tif (species_.RecordingTreeSequence())\n\t\t\tspecies_.SetCurrentNewIndividual(individual);\n\t\t\n\t\t// This has to happen after SetCurrentNewIndividual(), since it patches the node metadata\n\t\tindividual->AddHaplosomeAtIndex(haplosome1, 0);\n\t\tif (make_second_haplosome)\n\t\t\tindividual->AddHaplosomeAtIndex(haplosome2, 1);\n\t\t\n\t\t// BCH 9/26/2023: inherit the spatial position of pedigree_parent1 by default, to set up for deviatePositions()/pointDeviated()\n\t\t// Note that, unlike other addX() methods, the first parent is not necessarily defined; in that case, the\n\t\t// spatial position of the offspring is left uninitialized.\n\t\tif (pedigree_parent1)\n\t\t\tindividual->InheritSpatialPosition(species_.SpatialDimensionality(), pedigree_parent1);\n\t\t\n\t\tchromosome->StartMutationRunExperimentClock();\n\t\t\n\t\t// Construct the first child haplosome, depending upon whether recombination is requested, etc.\n\t\tif (strand1)\n\t\t{\n\t\t\tif (strand2 && breakvec1.size())\n\t\t\t{\n\t\t\t\tif (sex_enabled_ && !chromosome->UsingSingleMutationMap() && (strand1_parent->sex_ != strand2_parent->sex_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): strand1 and strand2 come from individuals of different sex, and sex-specific mutation rate maps are in use, so it is not clear which mutation rate map to use.\" << EidosTerminate();\n\t\t\t\t\n#if DEFER_BROKEN\n\t\t\t\tif (defer)\n\t\t\t\t{\n\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand1, strand2, breakvec1, haplosome1);\n\t\t\t\t}\n\t\t\t\telse\n#endif\n\t\t\t\t{\n\t\t\t\t\t(population_.*(population_.HaplosomeRecombined_TEMPLATED))(*chromosome, *haplosome1, strand1, strand2, breakvec1, mutation_callbacks);\n\t\t\t\t\t\n\t\t\t\t\tif (heteroduplex1.size() > 0)\n\t\t\t\t\t\tpopulation_.DoHeteroduplexRepair(heteroduplex1, breakvec1.data(), (int)breakvec1.size(), strand1, strand2, haplosome1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#if DEFER_BROKEN\n\t\t\t\tif (defer)\n\t\t\t\t{\n\t\t\t\t\t// clone one haplosome, using a second strand of nullptr\n\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand1, nullptr, breakvec1, haplosome1);\n\t\t\t\t}\n\t\t\t\telse\n#endif\n\t\t\t\t{\n\t\t\t\t\t(population_.*(population_.HaplosomeCloned_TEMPLATED))(*chromosome, *haplosome1, strand1, mutation_callbacks);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// both strands are NULL, so we make a null haplosome; we do nothing but record it\n\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome1);\n\t\t\t\n#if DEBUG\n\t\t\tif (!haplosome1_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): (internal error) haplosome1_null is false with NULL parental strands!\" << EidosTerminate();\n#endif\n\t\t}\n\t\t\n\t\t// Construct the second child haplosome, depending upon whether recombination is requested, etc.\n\t\tif (strand3)\n\t\t{\n\t\t\tif (strand4 && breakvec2.size())\n\t\t\t{\n\t\t\t\tif (sex_enabled_ && !chromosome->UsingSingleMutationMap() && (strand3_parent->sex_ != strand4_parent->sex_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): strand3 and strand4 come from individuals of different sex, and sex-specific mutation rate maps are in use, so it is not clear which mutation rate map to use.\" << EidosTerminate();\n\t\t\t\t\n#if DEFER_BROKEN\n\t\t\t\tif (defer)\n\t\t\t\t{\n\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand3, strand4, breakvec2, haplosome2);\n\t\t\t\t}\n\t\t\t\telse\n#endif\n\t\t\t\t{\n\t\t\t\t\t(population_.*(population_.HaplosomeRecombined_TEMPLATED))(*chromosome, *haplosome2, strand3, strand4, breakvec2, mutation_callbacks);\n\t\t\t\t\t\n\t\t\t\t\tif (heteroduplex2.size() > 0)\n\t\t\t\t\t\tpopulation_.DoHeteroduplexRepair(heteroduplex2, breakvec2.data(), (int)breakvec2.size(), strand3, strand4, haplosome2);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#if DEFER_BROKEN\n\t\t\t\tif (defer)\n\t\t\t\t{\n\t\t\t\t\t// clone one haplosome, using a second strand of nullptr; note that in this case we pass the child sex, not the parent sex\n\t\t\t\t\tpopulation_.deferred_reproduction_recombinant_.emplace_back(SLiM_DeferredReproductionType::kRecombinant, this, strand3, nullptr, breakvec2, haplosome2);\n\t\t\t\t}\n\t\t\t\telse\n#endif\n\t\t\t\t{\n\t\t\t\t\t(population_.*(population_.HaplosomeCloned_TEMPLATED))(*chromosome, *haplosome2, strand3, mutation_callbacks);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (make_second_haplosome)\n\t\t{\n\t\t\t// both strands are NULL and this is a diploid chromosome, so we record a null haplosome\n\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\tspecies_.RecordNewHaplosome_NULL(haplosome2);\n\t\t\t\n#if DEBUG\n\t\t\tif (!haplosome2_null)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addRecombinant): (internal error) haplosome2_null is false with NULL parental strands!\" << EidosTerminate();\n#endif\n\t\t}\n\t\t\n\t\tchromosome->StopMutationRunExperimentClock(\"addMultiRecombinant()\");\n\t\t\n\t\t// Run the candidate past modifyChild() callbacks; the target subpop's registered callbacks are used\n\t\tif (registered_modify_child_callbacks_.size())\n\t\t{\n\t\t\t// BCH 4/5/2022: When removing excess pseudo-parameters from callbacks, we lost a bit of\n\t\t\t// functionality here: we used to pass the four recombinant strands to the callback as the\n\t\t\t// four \"parental haplosomes\".  But that was always kind of fictional, and it was never\n\t\t\t// documented, and I doubt anybody was using it, and they can do the same without the\n\t\t\t// modifyChild() callback, so I'm not viewing this loss of functionality as an obstacle\n\t\t\t// to making this change.\n\t\t\t// BCH 1/10/2025: Note that we pass nullptr for the parents, and false for p_is_selfing and\n\t\t\t// p_is_cloning.  We could use pedigree_parent1 and pedigree_parent2, and draw inferences from\n\t\t\t// them about selfing/cloning, but that would not always be correct; it would just be a guess.\n\t\t\tbool proposed_child_accepted = population_.ApplyModifyChildCallbacks(individual, /* p_parent1 */ nullptr, /* p_parent2 */ nullptr, /* p_is_selfing */ false, /* p_is_cloning */ false, /* p_target_subpop */ this, /* p_source_subpop */ nullptr, registered_modify_child_callbacks_);\n\t\t\t\n\t\t\tif (!proposed_child_accepted)\n\t\t\t{\n\t\t\t\t// If the child was rejected, un-record it and dispose of it\n\t\t\t\tif (pedigrees_enabled)\n\t\t\t\t{\n\t\t\t\t\tif (pedigree_parent1 == nullptr)\n\t\t\t\t\t\tindividual->RevokeParentage_Parentless();\n\t\t\t\t\telse if (pedigree_parent1 == pedigree_parent2)\n\t\t\t\t\t\tindividual->RevokeParentage_Uniparental(*pedigree_parent1);\n\t\t\t\t\telse\n\t\t\t\t\t\tindividual->RevokeParentage_Biparental(*pedigree_parent1, *pedigree_parent2);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tFreeSubpopIndividual(individual);\n\t\t\t\tindividual = nullptr;\n\t\t\t\t\n\t\t\t\t// TREE SEQUENCE RECORDING\n\t\t\t\tif (species_.RecordingTreeSequence())\n\t\t\t\t\tspecies_.RetractNewIndividual();\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tgui_offspring_crossed_++;\n\t\t\t\t\n\t\t\t\t// This offspring came from parents in various subpops but ended up here, so it is, in effect,\n\t\t\t\t// a migrant; we tally things, for SLiMgui display purposes, as if it were generated in the\n\t\t\t\t// parental subpops and then moved.  This is gross, but runs only in SLiMgui, so whatever :->\n\t\t\t\t// We do not set its migrant_ flag, though; that flag is only for takeMigrants() in nonWF.\n\t\t\t\t// Note that we use pedigree_parent1 and pedigree_parent2 for this, rather than the parents\n\t\t\t\t// of the strands; in the addMultiRecombinant() case there are potentially many strands with\n\t\t\t\t// many different parents.  It is just too complex to try to keep track of just for SLiMgui.\n\t\t\t\t// BCH 1/7/2025: It used to be that addRecombinant() did this by strand, but I've dumbed it\n\t\t\t\t// down to match addMultiRecombinant(); nobody will ever notice.  Doing it by strand was\n\t\t\t\t// approximate too, and maybe even less good in some scenarios.\n\t\t\t\tif (pedigree_parent1)\n\t\t\t\t{\n\t\t\t\t\tpedigree_parent1->subpopulation_->gui_premigration_size_ += 0.5;\n\t\t\t\t\tif (pedigree_parent1->subpopulation_ != this)\n\t\t\t\t\t\tgui_migrants_[pedigree_parent1->subpopulation_->subpopulation_id_] += 0.5;\n\t\t\t\t}\n\t\t\t\tif (pedigree_parent2)\n\t\t\t\t{\n\t\t\t\t\tpedigree_parent2->subpopulation_->gui_premigration_size_ += 0.5;\n\t\t\t\t\tif (pedigree_parent2->subpopulation_ != this)\n\t\t\t\t\t\tgui_migrants_[pedigree_parent2->subpopulation_->subpopulation_id_] += 0.5;\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t– (o<Individual>)addSelfed(object<Individual>$ parent, [integer$ count = 1], [logical$ defer = F])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addSelfed(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): addSelfed() is not available in WF models.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\tif (community_.CycleStage() != SLiMCycleStage::kNonWFStage1GenerateOffspring)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): addSelfed() may only be called from a reproduction() callback.\" << EidosTerminate();\n\tif (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosReproductionCallback)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): addSelfed() may not be called from a nested callback.\" << EidosTerminate();\n\t\n\t// Get and check the parent\n\tEidosValue *parent_value = p_arguments[0].get();\n\tIndividual *parent = (Individual *)parent_value->ObjectData()[0];\n\tIndividualSex parent_sex = parent->sex_;\n\tSubpopulation &parent_subpop = *parent->subpopulation_;\n\t\n\tif (parent_sex != IndividualSex::kHermaphrodite)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): parent must be hermaphroditic in addSelfed().\" << EidosTerminate();\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tif (&parent_subpop.species_ != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): addSelfed() requires that parent belongs to the same species as the target subpopulation.\" << EidosTerminate();\n\t\n\t// Check for some other illegal setups\n\tif (parent->index_ == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): parent must be visible in a subpopulation (i.e., may not be a new juvenile).\" << EidosTerminate();\n\t\n\t// Check the count and short-circuit if it is zero\n\tEidosValue *count_value = p_arguments[1].get();\n\tint64_t child_count = count_value->IntData()[0];\n\t\n\tif ((child_count < 0) || (child_count > SLIM_MAX_SUBPOP_SIZE))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): addSelfed() requires an offspring count >= 0 and <= 1000000000.\" << EidosTerminate();\n\t\n\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class))->reserve(child_count);\t// reserve enough space for all results\n\t\n\tif (child_count == 0)\n\t\treturn EidosValue_SP(result);\n\t\n\t// Generate the number of children requested\n#if DEFER_BROKEN\n\t// The \"defer\" flag is simply disregarded at the moment; its design has rotted away,\n\t// and needs to be remade anew once things have settled down.\n\tEidosValue *defer_value = p_arguments[2].get();\n\tbool defer = defer_value->LogicalData()[0];\n\t\n\tif (defer)\n\t{\n\t\tstd::vector<SLiMEidosBlock*> *parent_recombination_callbacks = &parent_subpop.registered_recombination_callbacks_;\n\t\tstd::vector<SLiMEidosBlock*> *parent_mutation_callbacks = &parent_subpop.registered_mutation_callbacks_;\n\t\t\n\t\tif (!parent_recombination_callbacks->size()) parent_recombination_callbacks = nullptr;\n\t\tif (!parent_mutation_callbacks->size()) parent_mutation_callbacks = nullptr;\n\t\t\n\t\tif (parent_recombination_callbacks || parent_mutation_callbacks)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSelfed): deferred reproduction cannot be used when recombination() or mutation() callbacks are enabled.\" << EidosTerminate();\n\t}\n#endif\n\t\n\tfor (int64_t child_index = 0; child_index < child_count; ++child_index)\n\t{\n\t\t// Make the new individual; if it doesn't pass modifyChild(), nullptr will be returned\n\t\tIndividual *individual = (this->*(population_.GenerateIndividualSelfed_TEMPLATED))(parent);\n\t\t\n\t\tif (individual)\n\t\t{\n\t\t\tnonWF_offspring_individuals_.emplace_back(individual);\n\t\t\tresult->push_object_element_NORR(individual);\n\t\t\t\n#if defined(SLIMGUI)\n\t\t\t{\n\t\t\t\tgui_offspring_selfed_++;\n\t\t\t\t\n\t\t\t\t// this offspring came from a parent in parent_subpop but ended up here, so it is, in effect, a migrant;\n\t\t\t\t// we tally things, SLiMgui display purposes, as if it were generated in parent_subpop and then moved\n\t\t\t\tparent_subpop.gui_premigration_size_++;\n\t\t\t\tif (&parent_subpop != this)\n\t\t\t\t\tgui_migrants_[parent_subpop.subpopulation_id_]++;\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(result);\n}\n\n//\t*********************\t- (void)takeMigrants(object<Individual> migrants)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_takeMigrants(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_takeMigrants): takeMigrants() is not available in WF models.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\tif (community_.executing_species_ == &species_)\n\t\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_takeMigrants): takeMigrants() must be called directly from a first(), early(), or late() event, when called on the currently executing species.\" << EidosTerminate();\n\t\n\tEidosValue_Object *migrants_value = (EidosValue_Object *)p_arguments[0].get();\n\tint migrant_count = migrants_value->Count();\n\tint moved_count = 0;\n\t\n\tif (migrant_count == 0)\n\t\treturn gStaticEidosValueVOID;\n\t\n\t// SPECIES CONSISTENCY CHECK\n\tSpecies *species = Community::SpeciesForIndividuals(migrants_value);\n\t\n\tif (species != &this->species_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_takeMigrants): takeMigrants() requires that all individuals belong to the same species as the target subpopulation.\" << EidosTerminate();\n\t\n\tif (has_been_removed_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_takeMigrants): takeMigrants() should not be called to add individuals to a subpopulation that has been removed.\" << EidosTerminate();\n\n\t// Loop over the migrants and move them one by one\n\tint haplosome_count_per_individual = species->HaplosomeCountPerIndividual();\n\tIndividual * const *migrants = (Individual * const *)migrants_value->ObjectData();\n\t\n\tfor (int migrant_index = 0; migrant_index < migrant_count; ++migrant_index)\n\t{\n\t\tIndividual *migrant = migrants[migrant_index];\n\t\tSubpopulation *source_subpop = migrant->subpopulation_;\n\t\t\n\t\tif (source_subpop != this)\n\t\t{\n#if defined(SLIMGUI)\n\t\t\t// before doing anything else, tally this incoming migrant for SLiMgui\n\t\t\t++gui_migrants_[source_subpop->subpopulation_id_];\n#endif\n\t\t\t\n\t\t\tslim_popsize_t source_subpop_size = source_subpop->parent_subpop_size_;\n\t\t\tslim_popsize_t source_subpop_index = migrant->index_;\n\t\t\t\n\t\t\tif (source_subpop_index < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_takeMigrants): takeMigrants() may not move an individual that is not visible in a subpopulation.  This error may also occur if you try to migrate the same individual more than once in a single takeMigrants() call (i.e., if the migrants vector is not uniqued).\" << EidosTerminate();\n\t\t\t\n\t\t\t// remove the originals from source_subpop's vectors\n\t\t\tif (migrant->sex_ == IndividualSex::kFemale)\n\t\t\t{\n\t\t\t\t// females have to be backfilled by the last female, and then that hole is backfilled by a male, and the first male index changes\n\t\t\t\tslim_popsize_t source_first_male = source_subpop->parent_first_male_index_;\n\t\t\t\t\n\t\t\t\tif (source_subpop_index < source_first_male - 1)\n\t\t\t\t{\n\t\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_first_male - 1];\n\t\t\t\t\t\n\t\t\t\t\tsource_subpop->parent_individuals_[source_subpop_index] = backfill;\n\t\t\t\t\tbackfill->index_ = source_subpop_index;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (source_first_male - 1 < source_subpop_size - 1)\n\t\t\t\t{\n\t\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_subpop_size - 1];\n\t\t\t\t\t\n\t\t\t\t\tsource_subpop->parent_individuals_[source_first_male - 1] = backfill;\n\t\t\t\t\tbackfill->index_ = source_first_male - 1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_subpop_size_ = --source_subpop_size;\n\t\t\t\tsource_subpop->parent_individuals_.resize(source_subpop_size);\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_first_male_index_ = --source_first_male;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// males and hermaphrodites can be removed with a simple backfill from the end of the vector\n\t\t\t\tif (source_subpop_index < source_subpop_size - 1)\n\t\t\t\t{\n\t\t\t\t\tIndividual *backfill = source_subpop->parent_individuals_[source_subpop_size - 1];\n\t\t\t\t\t\n\t\t\t\t\tsource_subpop->parent_individuals_[source_subpop_index] = backfill;\n\t\t\t\t\tbackfill->index_ = source_subpop_index;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsource_subpop->parent_subpop_size_ = --source_subpop_size;\n\t\t\t\tsource_subpop->parent_individuals_.resize(source_subpop_size);\n\t\t\t}\n\t\t\t\n\t\t\t// insert the migrant into ourselves\n\t\t\tif ((migrant->sex_ == IndividualSex::kFemale) && (parent_first_male_index_ < parent_subpop_size_))\n\t\t\t{\n\t\t\t\t// room has to be made for females by shifting the first male and changing the first male index\n\t\t\t\tIndividual *backfill = parent_individuals_[parent_first_male_index_];\n\t\t\t\t\n\t\t\t\tparent_individuals_.emplace_back(backfill);\n\t\t\t\tbackfill->index_ = parent_subpop_size_;\n\t\t\t\t\n\t\t\t\tparent_individuals_[parent_first_male_index_] = migrant;\n\t\t\t\t\n\t\t\t\tmigrant->subpopulation_ = this;\n\t\t\t\tmigrant->index_ = parent_first_male_index_;\n\t\t\t\t\n\t\t\t\tparent_subpop_size_++;\n\t\t\t\tparent_first_male_index_++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// males and hermaphrodites can just be added to the end; so can females, if no males are present\n\t\t\t\tparent_individuals_.emplace_back(migrant);\n\t\t\t\t\n\t\t\t\tmigrant->subpopulation_ = this;\n\t\t\t\tmigrant->index_ = parent_subpop_size_;\n\t\t\t\t\n\t\t\t\tparent_subpop_size_++;\n\t\t\t\tif (migrant->sex_ == IndividualSex::kFemale)\n\t\t\t\t\tparent_first_male_index_++;\n\t\t\t}\n\t\t\t\n\t\t\t// has_null_haplosomes_ needs to reflect the presence of null haplosomes\n\t\t\tif (!has_null_haplosomes_ && source_subpop->has_null_haplosomes_)\n\t\t\t{\n\t\t\t\tHaplosome **haplosomes = migrant->haplosomes_;\n\t\t\t\t\n\t\t\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count_per_individual; haplosome_index++)\n\t\t\t\t{\n\t\t\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\t\t\t\n\t\t\t\t\tif (haplosome->IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\thas_null_haplosomes_ = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// set the migrant flag of the migrated individual; note this is not set if the individual was already in the destination subpop\n\t\t\tmigrant->migrant_ = true;\n\t\t\t\n\t\t\tmoved_count++;\n\t\t}\n\t}\n\t\n\tif (moved_count)\n\t{\n\t\t// First, clear our haplosome and individual caches in all subpopulations; any subpops involved in\n\t\t// the migration would be invalidated anyway so this probably isn't even that much overkill in\n\t\t// most models.  Note that the child haplosomes/individuals caches don't need to be thrown away,\n\t\t// because they aren't used in nonWF models and this is a nonWF-only method.\n\t\tfor (auto subpop_pair : population_.subpops_)\n\t\t\tsubpop_pair.second->cached_parent_individuals_value_.reset();\n\t\t\n\t\t// Invalidate interactions; we just do this for all subpops, for now, rather than trying to\n\t\t// selectively invalidate only the subpops involved in the migrations that occurred\n\t\tcommunity_.InvalidateInteractionsForSpecies(&species_);\n\t\t\n\t\t// cached mutation counts/frequencies are no longer accurate; mark the cache as invalid\n\t\tpopulation_.InvalidateMutationReferencesCache();\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// WF only:\n//\t*********************\t- (void)setMigrationRates(io<Subpopulation> sourceSubpops, numeric rates)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setMigrationRates(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setMigrationRates): setMigrationRates() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tEidosValue *sourceSubpops_value = p_arguments[0].get();\n\tEidosValue *rates_value = p_arguments[1].get();\n\t\n\tint source_subpops_count = sourceSubpops_value->Count();\n\tint rates_count = rates_value->Count();\n\tstd::vector<slim_objectid_t> subpops_seen;\n\tbool saw_nonzero_rate = false, saw_self_reference = false;\n\t\n\tif ((source_subpops_count != rates_count) && (rates_count != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setMigrationRates): setMigrationRates() requires sourceSubpops and rates to be equal in size, or rates to be singleton.\" << EidosTerminate();\n\t\n\tfor (int value_index = 0; value_index < source_subpops_count; ++value_index)\n\t{\n\t\tEidosObject *source_subpop = SLiM_ExtractSubpopulationFromEidosValue_io(sourceSubpops_value, value_index, &species_.community_, &species_, \"setMigrationRates()\");\t\t// SPECIES CONSISTENCY CHECK\n\t\tslim_objectid_t source_subpop_id = ((Subpopulation *)(source_subpop))->subpopulation_id_;\n\t\tdouble migrant_fraction = ((rates_count == 1) ? rates_value->NumericAtIndex_NOCAST(0, nullptr) : rates_value->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\n\t\t// BCH 11/16/2025: We used to require that the target subpop was not a member of sourceSubpops; we would\n\t\t// raise an error in all cases if that occurred.  Now we relax those rules slightly, to make it easier\n\t\t// to zero out all immigration into a subpop or subpops; we allow self-reference, but *only* if *all*\n\t\t// rates specified in the call are 0.0.  So you can do, e.g., allSubpops.setMigrationRates(allSubpops, 0).\n\t\t// See https://github.com/MesserLab/SLiM/issues/570.  As part of that fix, we also now allow rates to\n\t\t// provide a singleton value, used for all sourceSubpops.\n\t\tif (migrant_fraction != 0.0)\n\t\t\tsaw_nonzero_rate = true;\n\t\tif (source_subpop_id == subpopulation_id_)\n\t\t\tsaw_self_reference = true;\n\t\tif (saw_self_reference && saw_nonzero_rate)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setMigrationRates): setMigrationRates() does not allow migration to be self-referential (originating within the destination subpopulation), except when all rates are zero (for convenience).\" << EidosTerminate();\n\t\t\n\t\t// can't specify the same source subpopulation twice\n\t\tif (std::find(subpops_seen.begin(), subpops_seen.end(), source_subpop_id) != subpops_seen.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setMigrationRates): setMigrationRates() two rates set for subpopulation p\" << source_subpop_id << \".\" << EidosTerminate();\n\t\t\n\t\tpopulation_.SetMigration(*this, source_subpop_id, migrant_fraction);\n\t\tsubpops_seen.emplace_back(source_subpop_id);\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (object<Haplosome>)haplosomesForChromosomes([Niso<Chromosome> chromosomes = NULL], [Ni$ index = NULL], [logical$ includeNulls = T])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_haplosomesForChromosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *chromosomes_value = p_arguments[0].get();\n\tEidosValue *index_value = p_arguments[1].get();\n\tEidosValue *includeNulls_value = p_arguments[2].get();\n\t\n\t// assemble a vector of chromosome indices we're fetching\n\tstd::vector<slim_chromosome_index_t> chromosome_indices;\n\t\n\tspecies_.GetChromosomeIndicesFromEidosValue(chromosome_indices, chromosomes_value);\n\t\n\t// get index and includeNulls\n\tint64_t index = -1;\t// for NULL\n\t\n\tif (index_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tindex = index_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((index != 0) && (index != 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Individual::ExecuteMethod_haplosomesForChromosomes): haplosomesForChromosomes() requires that index is 0, 1, or NULL.\" << EidosTerminate();\n\t}\n\t\n\tbool includeNulls = includeNulls_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// fetch the requested haplosomes for all individuals\n\tEidosValue_Object *vec = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Haplosome_Class));\n\t\n\tfor (Individual *individual : parent_individuals_)\n\t\tindividual->AppendHaplosomesForChromosomes(vec, chromosome_indices, index, includeNulls);\n\t\n\treturn EidosValue_SP(vec);\n}\n\n//\t*********************\t– (object<Individual>)deviatePositions(No<Individual> individuals, string$ boundary, numeric$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_deviatePositions(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t// NOTE: most of the code of this method is shared with pointDeviated()\n\t\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_deviatePositions): deviatePositions() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_deviatePositions): deviatePositions() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): deviatePositions() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tIndividual * const *individuals;\n\tint individuals_count;\n\t\n\tif (individuals_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL requests that the positions of all individuals in the subpop should be deviated\n\t\tindividuals = parent_individuals_.data();\n\t\tindividuals_count = parent_subpop_size_;\n\t}\n\telse\n\t{\n\t\tindividuals = (Individual * const *)individuals_value->ObjectData();\n\t\tindividuals_count = individuals_value->Count();\n\t}\n\t\n\t// Make a return vector that is initially empty; unless boundary is \"absorbing\", it will remain empty\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get());\n\t\n\tif (individuals_count == 0)\n\t\treturn result_SP;\n\t\n\tEidosValue_String *boundary_value = (EidosValue_String *)p_arguments[1].get();\n\tconst std::string &boundary_str = boundary_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tBoundaryCondition boundary;\n\t\n\tif (boundary_str.compare(\"none\") == 0)\n\t\tboundary = BoundaryCondition::kNone;\n\telse if (boundary_str.compare(\"stopping\") == 0)\n\t\tboundary = BoundaryCondition::kStopping;\n\telse if (boundary_str.compare(\"reflecting\") == 0)\n\t\tboundary = BoundaryCondition::kReflecting;\n\telse if (boundary_str.compare(\"reprising\") == 0)\n\t\tboundary = BoundaryCondition::kReprising;\n\telse if (boundary_str.compare(\"absorbing\") == 0)\n\t\tboundary = BoundaryCondition::kAbsorbing;\n\telse if (boundary_str.compare(\"periodic\") == 0)\n\t\tboundary = BoundaryCondition::kPeriodic;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): unrecognized boundary condition '\" << boundary_str << \"'.\" << EidosTerminate();\n\t\n\t// Periodic boundaries are a bit complicated.  If only some dimensions are periodic, 'none' will be used\n\t// for the non-periodic boundaries, and the user can then use pointReflected(), pointStopped(), etc. to\n\t// enforce a boundary condition on those dimensions.\n\tbool periodic_x = false, periodic_y = false, periodic_z = false;\n\t\n\tif (boundary == BoundaryCondition::kPeriodic)\n\t{\n\t\t// Since periodic boundaries depend upon the species configuration, we require all individuals to belong to the target species here\n\t\t// In other cases, it doesn't seem necessary to enforce this, and it might be useful to be able to violate it\n\t\tif (community_.SpeciesForIndividualsVector(individuals, individuals_count) != &species_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): deviatePositions() requires that all individuals belong to the same species as the target subpopulation, when periodic boundaries are requested.\" << EidosTerminate();\n\t\t\n\t\tspecies_.SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\t\n\t\tif (!periodic_x && !periodic_y && !periodic_z)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): deviatePositions() cannot apply periodic boundary conditions in a model without periodic boundaries.\" << EidosTerminate();\n\t}\n\t\n\tEidosValue *maxDistance_value = p_arguments[2].get();\n\tdouble max_distance = maxDistance_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(dimensionality, max_distance, p_arguments, 3, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif ((kernel_count != 1) && (kernel_count != individuals_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): deviatePositions() requires that the number of spatial kernels defined (by the supplied kernel-definition arguments) either must be 1, or must equal the number of individuals being processed (\" << kernel_count << \" kernels defined; \" << individuals_count << \" individuals processed).\" << EidosTerminate();\n\t\n\tSpatialKernel kernel0(dimensionality, max_distance, p_arguments, 3, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 3\n\t\n\t// I'm not going to worry about unrolling each case, for dimensionality by boundary by kernel type; it would\n\t// be a ton of cases (3 x 5 x 5 = 75), and the overhead for the switches ought to be small compared to the\n\t// overhead of drawing a displacement from the kernel, which requires a random number draw.  I tested doing\n\t// a special-case here for dimensionality==2, boundary==1 (stopping), kernel.kernel_type==kNormal,\n\t// maxDistance==INF, and it clocked at 6.47 seconds versus 7.85 seconds for the unoptimized code below;\n\t// that's about a 17.6% speedup, which is worthwhile for a handful of special cases like that.  I think\n\t// normal deviations in 2D with an INF maxDistance are the 95% case, if not 99%; several boundary conditions\n\t// are common, though.\n\tif ((kernel_count == 1) && (dimensionality == 2) && (kernel0.kernel_type_ == SpatialKernelType::kNormal) && std::isinf(kernel0.max_distance_) && ((boundary == BoundaryCondition::kStopping) || (boundary == BoundaryCondition::kReflecting) || (boundary == BoundaryCondition::kReprising) || (boundary == BoundaryCondition::kAbsorbing) || ((boundary == BoundaryCondition::kPeriodic) && periodic_x && periodic_y)))\n\t{\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\tdouble stddev = kernel0.kernel_param2_;\n\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\n\t\tif (boundary == BoundaryCondition::kStopping)\n\t\t{\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\ta0 = std::max(bx0, std::min(bx1, a0));\n\t\t\t\ta1 = std::max(by0, std::min(by1, a1));\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\tind->spatial_y_ = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kReflecting)\n\t\t{\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (a0 < bx0) a0 = bx0 + (bx0 - a0);\n\t\t\t\t\telse if (a0 > bx1) a0 = bx1 - (a0 - bx1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (a1 < by0) a1 = by0 + (by0 - a1);\n\t\t\t\t\telse if (a1 > by1) a1 = by1 - (a1 - by1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\tind->spatial_y_ = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kReprising)\n\t\t{\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a0_original = ind->spatial_x_;\n\t\t\t\tdouble a1_original = ind->spatial_y_;\n\t\t\t\t\n\t\t\treprise_specialcase:\n\t\t\t\tdouble a0 = a0_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = a1_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\tgoto reprise_specialcase;\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\tind->spatial_y_ = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kAbsorbing)\n\t\t{\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\tind->spatial_y_ = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kPeriodic)\n\t\t{\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\t// (note periodic_x and periodic_y are required to be true above)\n\t\t\t\twhile (a0 < 0.0)\ta0 += bx1;\n\t\t\t\twhile (a0 > bx1)\ta0 -= bx1;\n\t\t\t\twhile (a1 < 0.0)\ta1 += by1;\n\t\t\t\twhile (a1 > by1)\ta1 -= by1;\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\tind->spatial_y_ = a1;\n\t\t\t}\n\t\t}\n\t\treturn result_SP;\n\t}\n\t\n\t// main code path; note that here we may have multiple kernels defined, one per individual\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 3, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[1];\n\t\t\t\t\n\t\t\treprise_1:\n\t\t\t\tkernel.DrawDisplacement_S1(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1))\n\t\t\t\t\t\t\tgoto reprise_1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1))\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\t\t\t// (periodic_x must be true)\n\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 3, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[2];\n\t\t\t\t\n\t\t\treprise_2:\n\t\t\t\tkernel.DrawDisplacement_S2(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\ta[1] += ind->spatial_y_;\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\ta[1] = std::max(by0, std::min(by1, a[1]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[1] < by0) a[1] = by0 + (by0 - a[1]);\n\t\t\t\t\t\t\telse if (a[1] > by1) a[1] = by1 - (a[1] - by1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1))\n\t\t\t\t\t\t\tgoto reprise_2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1))\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tif (periodic_x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_y)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t\tind->spatial_y_ = a[1];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\tdouble bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 3, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[3];\n\t\t\t\t\n\t\t\treprise_3:\n\t\t\t\tkernel.DrawDisplacement_S3(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\ta[1] += ind->spatial_y_;\n\t\t\t\ta[2] += ind->spatial_z_;\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\ta[1] = std::max(by0, std::min(by1, a[1]));\n\t\t\t\t\t\ta[2] = std::max(bz0, std::min(bz1, a[2]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[1] < by0) a[1] = by0 + (by0 - a[1]);\n\t\t\t\t\t\t\telse if (a[1] > by1) a[1] = by1 - (a[1] - by1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[2] < bz0) a[2] = bz0 + (bz0 - a[2]);\n\t\t\t\t\t\t\telse if (a[2] > bz1) a[2] = bz1 - (a[2] - bz1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1) ||\n\t\t\t\t\t\t\t(a[2] < bz0) || (a[2] > bz1))\n\t\t\t\t\t\t\tgoto reprise_3;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1) ||\n\t\t\t\t\t\t\t(a[2] < bz0) || (a[2] > bz1))\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tif (periodic_x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_y)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_z)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[2] < 0.0)\ta[2] += bz1;\n\t\t\t\t\t\t\twhile (a[2] > bz1)\ta[2] -= bz1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t\tind->spatial_y_ = a[1];\n\t\t\t\tind->spatial_z_ = a[2];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositions): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<Individual>)deviatePositionsWithMap(No<Individual> individuals, string$ boundary, so<SpatialMap>$ map, numeric$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_deviatePositionsWithMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t// NOTE: most of the code of this method is shared with pointDeviated(), and even more, with deviatePositions()\n\t\n\tSLiMCycleStage cycle_stage = community_.CycleStage();\n\t\n\t// TIMING RESTRICTION\n\tif ((cycle_stage != SLiMCycleStage::kWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kWFStage1ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kWFStage5ExecuteLateScripts) &&\n\t\t(cycle_stage != SLiMCycleStage::kNonWFStage0ExecuteFirstScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage2ExecuteEarlyScripts) && (cycle_stage != SLiMCycleStage::kNonWFStage6ExecuteLateScripts))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() may only be called from a first(), early(), or late() event.\" << EidosTerminate();\n\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\tEIDOS_TERMINATION << \"ERROR (Species::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() may not be called from inside a callback.\" << EidosTerminate();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tEidosValue *individuals_value = p_arguments[0].get();\n\tIndividual * const *individuals;\n\tint individuals_count;\n\t\n\tif (individuals_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// NULL requests that the positions of all individuals in the subpop should be deviated\n\t\tindividuals = parent_individuals_.data();\n\t\tindividuals_count = parent_subpop_size_;\n\t}\n\telse\n\t{\n\t\tindividuals = (Individual * const *)individuals_value->ObjectData();\n\t\tindividuals_count = individuals_value->Count();\n\t}\n\t\n\t// Make a return vector that is initially empty; unless boundary is \"absorbing\", it will remain empty\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get());\n\t\n\tif (individuals_count == 0)\n\t\treturn result_SP;\n\t\n\tEidosValue_String *boundary_value = (EidosValue_String *)p_arguments[1].get();\n\tconst std::string &boundary_str = boundary_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tBoundaryCondition boundary;\n\t\n\tif (boundary_str.compare(\"reprising\") == 0)\n\t\tboundary = BoundaryCondition::kReprising;\n\telse if (boundary_str.compare(\"absorbing\") == 0)\n\t\tboundary = BoundaryCondition::kAbsorbing;\n\telse if ((boundary_str.compare(\"none\") == 0) ||\n\t\t\t (boundary_str.compare(\"stopping\") == 0) ||\n\t\t\t (boundary_str.compare(\"reflecting\") == 0) ||\n\t\t\t (boundary_str.compare(\"periodic\") == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() does not support boundary condition '\" << boundary_str << \"'.\" << EidosTerminate();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): unrecognized boundary condition '\" << boundary_str << \"'.\" << EidosTerminate();\n\t\n\t// Periodic boundaries are a bit complicated.  Unlike deviatePositions(), we automatically apply periodic\n\t// boundaries if they are defined, so that the deviated point is within spatial bounds and can be checked\n\t// against the spatial map.\n\t// Since periodic boundaries depend upon the species configuration, we require all individuals to belong to the target species here\n\t// In other cases, it doesn't seem necessary to enforce this, and it might be useful to be able to violate it\n\tbool periodic_x = false, periodic_y = false, periodic_z = false;\n\t\n\tspecies_.SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\n\tif (periodic_x || periodic_y || periodic_z)\n\t{\n\t\tif (community_.SpeciesForIndividualsVector(individuals, individuals_count) != &species_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() requires that all individuals belong to the same species as the target subpopulation, when periodic boundaries are in effect.\" << EidosTerminate();\n\t}\n\t\n\t// Get the spatial map's name; see ExecuteMethod_spatialMapValue() for the origin of this code\n\tEidosValue *map_value = p_arguments[2].get();\n\tSpatialMap *map = nullptr;\n\tstd::string map_name;\n\t\n\tif (map_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tmap_name = ((EidosValue_String *)map_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (map_name.length() == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() map name must not be zero-length.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\tmap = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tmap_name = map->name_;\n\t}\n\t\n\t// Find the SpatialMap by name; we do this lookup even if a map object was supplied, to check that that map is present\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *found_map = map_iter->second;\n\t\t\n\t\tif (map && (found_map != map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() could not find map in the target subpopulation (although it did find a different map with the same name).\" << EidosTerminate();\n\t\t\n\t\tmap = found_map;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() could not find map '\" << map_name << \"' in the target subpopulation.\" << EidosTerminate();\n\t\n\tbool map_interpolated = map->interpolate_;\n\t\n\t// The map is required to have spatiality equal to the species dimensionality.  This is because the value\n\t// queries to the map using ValueAtPoint_S2() etc. are in the map's spatiality, and we don't want to have\n\t// to be translating points in and out of that spatiality.  Other methods don't have this problem because\n\t// either they get passed a point (which must be in the map or interaction type's spatiality) or they have\n\t// cached the point in the correct spatiality internally (as InteractionType does).  Users who have a map\n\t// in a weird spatiality can always do the work of this method themselves, with more basic calls.\n\tif (dimensionality != map->spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() requires that the map's spatiality is equal to the dimensionality of the species.\" << EidosTerminate();\n\t\n\t// Process the max distance and kernel\n\tEidosValue *maxDistance_value = p_arguments[3].get();\n\tdouble max_distance = maxDistance_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(dimensionality, max_distance, p_arguments, 4, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif ((kernel_count != 1) && (kernel_count != individuals_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() requires that the number of spatial kernels defined (by the supplied kernel-definition arguments) either must be 1, or must equal the number of individuals being processed (\" << kernel_count << \" kernels defined; \" << individuals_count << \" individuals processed).\" << EidosTerminate();\n\t\n\tSpatialKernel kernel0(dimensionality, max_distance, p_arguments, 4, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 4\n\t\n\t// I'm not going to worry about unrolling each case, for dimensionality by boundary by kernel type; it would\n\t// be a ton of cases (3 x 5 x 5 = 75), and the overhead for the switches ought to be small compared to the\n\t// overhead of drawing a displacement from the kernel, which requires a random number draw.  However, common\n\t// 2D cases are optimized here; see deviatePositions().  This provides about a 10% speedup compared to the\n\t// general-purpose code below.  The sub-optimization here for non-interpolated maps provides another 3% or so,\n\t// which is pretty marginal, but it's an easy optimization.\n\tif ((kernel_count == 1) && (dimensionality == 2) && (kernel0.kernel_type_ == SpatialKernelType::kNormal) && std::isinf(kernel0.max_distance_) && !periodic_x && !periodic_y && !periodic_z && ((boundary == BoundaryCondition::kReprising) || (boundary == BoundaryCondition::kAbsorbing)))\n\t{\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\tdouble stddev = kernel0.kernel_param2_;\n\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\tdouble bounds_size_x = bx1 - bx0;\n\t\tdouble bounds_size_y = by1 - by0;\n\t\t\n\t\tif (boundary == BoundaryCondition::kReprising)\n\t\t{\n\t\t\tif (map_interpolated)\n\t\t\t{\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\t\tdouble a0_original = ind->spatial_x_;\n\t\t\t\t\tdouble a1_original = ind->spatial_y_;\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\treprise_specialcase:\n\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() failed to find a successful deviated point by reprising after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tdouble a0 = a0_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\tdouble a1 = a1_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\t\n\t\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\t\tgoto reprise_specialcase;\n\t\t\t\t\t\n\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\tdouble a_normalized[2];\n\t\t\t\t\t\n\t\t\t\t\ta_normalized[0] = (a0 - bx0) / bounds_size_x;\n\t\t\t\t\ta_normalized[1] = (a1 - by0) / bounds_size_y;\n\t\t\t\t\t\n\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2(a_normalized);\n\t\t\t\t\t\n\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\tgoto reprise_specialcase;\n\t\t\t\t\t}\n\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\tgoto reprise_specialcase;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\t\tind->spatial_y_ = a1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\t// !map_interpolated\n\t\t\t{\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\t\tdouble a0_original = ind->spatial_x_;\n\t\t\t\t\tdouble a1_original = ind->spatial_y_;\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\treprise_specialcase_nointerp:\n\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() failed to find a successful deviated point by reprising after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tdouble a0 = a0_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\tdouble a1 = a1_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\t\n\t\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\t\tgoto reprise_specialcase_nointerp;\n\t\t\t\t\t\n\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\tdouble a0_normalized = (a0 - bx0) / bounds_size_x;\n\t\t\t\t\tdouble a1_normalized = (a1 - by0) / bounds_size_y;\n\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2_NOINTERPOLATE(a0_normalized, a1_normalized);\n\t\t\t\t\t\n\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\tgoto reprise_specialcase_nointerp;\n\t\t\t\t\t}\n\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\tgoto reprise_specialcase_nointerp;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\t\tind->spatial_y_ = a1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kAbsorbing)\n\t\t{\n\t\t\tif (map_interpolated)\n\t\t\t{\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\t\n\t\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\tdouble a_normalized[2];\n\t\t\t\t\t\t\n\t\t\t\t\t\ta_normalized[0] = (a0 - bx0) / bounds_size_x;\n\t\t\t\t\t\ta_normalized[1] = (a1 - by0) / bounds_size_y;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2(a_normalized);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 0: always absorb\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 1: never absorb (drop through)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\t\tind->spatial_y_ = a1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\t// !map_interpolated\n\t\t\t{\n\t\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t\t{\n\t\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\t\tdouble a0 = ind->spatial_x_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\tdouble a1 = ind->spatial_y_ + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\t\n\t\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\t{\n\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\tdouble a0_normalized = (a0 - bx0) / bounds_size_x;\n\t\t\t\t\t\tdouble a1_normalized = (a1 - by0) / bounds_size_y;\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2_NOINTERPOLATE(a0_normalized, a1_normalized);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 0: always absorb\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 1: never absorb (drop through)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tind->spatial_x_ = a0;\n\t\t\t\t\tind->spatial_y_ = a1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result_SP;\n\t}\n\t\n\t// main code path; note that here we may have multiple kernels defined, one per individual\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble bounds_size_x = bx1 - bx0;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[1];\n\t\t\t\tint num_tries = 0;\n\t\t\t\t\n\t\t\treprise_1:\n\t\t\t\tkernel.DrawDisplacement_S1(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\t\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() failed to find a successful deviated point by reprising after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1))\n\t\t\t\t\t\t\tgoto reprise_1;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\tdouble a_normalized[1];\n\t\t\t\t\t\t\n\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S1(a_normalized);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\tgoto reprise_1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\tgoto reprise_1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\t\tdouble a_normalized[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S1(a_normalized);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): (internal error) unsupported boundary condition.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\tdouble bounds_size_x = bx1 - bx0;\n\t\t\tdouble bounds_size_y = by1 - by0;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[2];\n\t\t\t\tint num_tries = 0;\n\t\t\t\t\n\t\t\treprise_2:\n\t\t\t\tkernel.DrawDisplacement_S2(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\ta[1] += ind->spatial_y_;\n\t\t\t\t\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t}\n\t\t\t\tif (periodic_y)\n\t\t\t\t{\n\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() failed to find a successful deviated point by reprising after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1))\n\t\t\t\t\t\t\tgoto reprise_2;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\tdouble a_normalized[2];\n\t\t\t\t\t\t\n\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\ta_normalized[1] = (a[1] - by0) / bounds_size_y;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2(a_normalized);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\tgoto reprise_2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\tgoto reprise_2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\t\tdouble a_normalized[2];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\t\ta_normalized[1] = (a[1] - by0) / bounds_size_y;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2(a_normalized);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): (internal error) unsupported boundary condition.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t\tind->spatial_y_ = a[1];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\tdouble bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\tdouble bounds_size_x = bx1 - bx0;\n\t\t\tdouble bounds_size_y = by1 - by0;\n\t\t\tdouble bounds_size_z = bz1 - bz0;\n\t\t\t\n\t\t\t// FIXME: TO BE PARALLELIZED\n\t\t\tfor (int individual_index = 0; individual_index < individuals_count; ++individual_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, individual_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tIndividual *ind = individuals[individual_index];\n\t\t\t\tdouble a[3];\n\t\t\t\tint num_tries = 0;\n\t\t\t\t\n\t\t\treprise_3:\n\t\t\t\tkernel.DrawDisplacement_S3(a);\n\t\t\t\ta[0] += ind->spatial_x_;\n\t\t\t\ta[1] += ind->spatial_y_;\n\t\t\t\ta[2] += ind->spatial_z_;\n\t\t\t\t\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t}\n\t\t\t\tif (periodic_y)\n\t\t\t\t{\n\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t}\n\t\t\t\tif (periodic_z)\n\t\t\t\t{\n\t\t\t\t\twhile (a[2] < 0.0)\ta[2] += bz1;\n\t\t\t\t\twhile (a[2] > bz1)\ta[2] -= bz1;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t{\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_deviatePositionsWithMap): deviatePositionsWithMap() failed to find a successful deviated point by reprising after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1) ||\n\t\t\t\t\t\t\t(a[2] < bz0) || (a[2] > bz1))\n\t\t\t\t\t\t\tgoto reprise_3;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\tdouble a_normalized[3];\n\t\t\t\t\t\t\n\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\ta_normalized[1] = (a[1] - by0) / bounds_size_y;\n\t\t\t\t\t\ta_normalized[2] = (a[2] - bz0) / bounds_size_z;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S3(a_normalized);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\tgoto reprise_3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\tgoto reprise_3;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1) ||\n\t\t\t\t\t\t\t(a[2] < bz0) || (a[2] > bz1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// within the spatial bounds, so now we have to check the map\n\t\t\t\t\t\t\tdouble a_normalized[3];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ta_normalized[0] = (a[0] - bx0) / bounds_size_x;\n\t\t\t\t\t\t\ta_normalized[1] = (a[1] - by0) / bounds_size_y;\n\t\t\t\t\t\t\ta_normalized[2] = (a[2] - bz0) / bounds_size_z;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S3(a_normalized);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 0: always reprise\n\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// habitability 1: never reprise (drop through)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// intermediate: do a random number draw, where value_for_point is P(within bounds)\n\t\t\t\t\t\t\t\tif (Eidos_rng_uniform_doubleCO(rng_64) > value_for_point)\n\t\t\t\t\t\t\t\t\tresult->push_object_element_capcheck_NORR(ind);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): (internal error) unsupported boundary condition.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tind->spatial_x_ = a[0];\n\t\t\t\tind->spatial_y_ = a[1];\n\t\t\t\tind->spatial_z_ = a[2];\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_deviatePositionsWithMap): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t– (float)pointDeviated(integer$ n, float point, string$ boundary, numeric$ maxDistance, string$ functionType, ...)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointDeviated(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t// NOTE: most of the code of this method is shared with deviatePositions()\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (n < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() requires n >= 0.\" << EidosTerminate();\n\tif (n == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tint64_t length_out = n * dimensionality;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(length_out);\n\tdouble *float_result_data = float_result->data_mutable();\n\tdouble *float_result_ptr = float_result_data;\n\t\n\tEidosValue *point_value = p_arguments[1].get();\n\tint point_count = point_value->Count();\n\tconst double *point_buf = point_value->FloatData();\n\tconst double *point_buf_ptr = point_buf;\n\t\n\tif (point_count % dimensionality != 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() requires the length of point to be a multiple of the model dimensionality (i.e., point should contain an integer number of complete points of the correct dimensionality).\" << EidosTerminate();\n\t\n\tpoint_count /= dimensionality;\t\t// convert from float elements to points\n\t\n\tif ((point_count != 1) && ((int64_t)point_count != n))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() requires point to be contain either a single spatial point (to be deviated n times) or n spatial points (each to be deviated once).\" << EidosTerminate();\n\t\n\tEidosValue_String *boundary_value = (EidosValue_String *)p_arguments[2].get();\n\tconst std::string &boundary_str = boundary_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tBoundaryCondition boundary;\n\t\n\tif (boundary_str.compare(\"none\") == 0)\n\t\tboundary = BoundaryCondition::kNone;\n\telse if (boundary_str.compare(\"stopping\") == 0)\n\t\tboundary = BoundaryCondition::kStopping;\n\telse if (boundary_str.compare(\"reflecting\") == 0)\n\t\tboundary = BoundaryCondition::kReflecting;\n\telse if (boundary_str.compare(\"reprising\") == 0)\n\t\tboundary = BoundaryCondition::kReprising;\n\telse if (boundary_str.compare(\"periodic\") == 0)\n\t\tboundary = BoundaryCondition::kPeriodic;\n\telse if (boundary_str.compare(\"absorbing\") == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() does not support boundary condition 'absorbing', but see Subpopulation method deviatePositions().\" << EidosTerminate();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): unrecognized boundary condition '\" << boundary_str << \"'.\" << EidosTerminate();\n\t\n\t// Periodic boundaries are a bit complicated.  If only some dimensions are periodic, 'none' will be used\n\t// for the non-periodic boundaries, and the user can then use pointReflected(), pointStopped(), etc. to\n\t// enforce a boundary condition on those dimensions.\n\tbool periodic_x = false, periodic_y = false, periodic_z = false;\n\t\n\tif (boundary == BoundaryCondition::kPeriodic)\n\t{\n\t\tspecies_.SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\t\n\t\tif (!periodic_x && !periodic_y && !periodic_z)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() cannot apply periodic boundary conditions in a model without periodic boundaries.\" << EidosTerminate();\n\t}\n\t\n\tEidosValue *maxDistance_value = p_arguments[3].get();\n\tdouble max_distance = maxDistance_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tSpatialKernelType k_type;\n\tint k_param_count;\n\tint kernel_count = SpatialKernel::PreprocessArguments(dimensionality, max_distance, p_arguments, 4, /* p_expect_max_density */ false, &k_type, &k_param_count);\n\t\n\tif ((kernel_count != 1) && (kernel_count != point_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): pointDeviated() requires that the number of spatial kernels defined (by the supplied kernel-definition arguments) either must be 1, or must equal the number of points being processed (\" << kernel_count << \" kernels defined; \" << point_count << \" individuals processed).\" << EidosTerminate();\n\t\n\tSpatialKernel kernel0(dimensionality, max_distance, p_arguments, 4, 0, /* p_expect_max_density */ false, k_type, k_param_count);\t// uses our arguments starting at index 4\n\t\n\t// I'm not going to worry about unrolling each case, for dimensionality by boundary by kernel type; it would\n\t// be a ton of cases (3 x 5 x 5 = 75), and the overhead for the switches ought to be small compared to the\n\t// overhead of drawing a displacement from the kernel, which requires a random number draw.  I tested doing\n\t// a special-case here for dimensionality==2, boundary==1 (stopping), kernel.kernel_type==kNormal,\n\t// maxDistance==INF, and it clocked at 6.47 seconds versus 7.85 seconds for the unoptimized code below;\n\t// that's about a 17.6% speedup, which is worthwhile for a handful of special cases like that.  I think\n\t// normal deviations in 2D with an INF maxDistance are the 95% case, if not 99%; several boundary conditions\n\t// are common, though.\n\tif ((kernel_count == 1) && (dimensionality == 2) && (kernel0.kernel_type_ == SpatialKernelType::kNormal) && std::isinf(kernel0.max_distance_) && ((boundary == BoundaryCondition::kStopping) || (boundary == BoundaryCondition::kReflecting) || (boundary == BoundaryCondition::kReprising) || ((boundary == BoundaryCondition::kPeriodic) && periodic_x && periodic_y)))\n\t{\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\tdouble stddev = kernel0.kernel_param2_;\n\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\n\t\tif (boundary == BoundaryCondition::kStopping)\n\t\t{\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tdouble a0 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\ta0 = std::max(bx0, std::min(bx1, a0));\n\t\t\t\ta1 = std::max(by0, std::min(by1, a1));\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a0;\n\t\t\t\t*(float_result_ptr++) = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kReflecting)\n\t\t{\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tdouble a0 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (a0 < bx0) a0 = bx0 + (bx0 - a0);\n\t\t\t\t\telse if (a0 > bx1) a0 = bx1 - (a0 - bx1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (a1 < by0) a1 = by0 + (by0 - a1);\n\t\t\t\t\telse if (a1 > by1) a1 = by1 - (a1 - by1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a0;\n\t\t\t\t*(float_result_ptr++) = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kReprising)\n\t\t{\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tdouble a0_original = *(point_buf_ptr++);\n\t\t\t\tdouble a1_original = *(point_buf_ptr++);\n\t\t\t\t\n\t\t\treprise_specialcase:\n\t\t\t\tdouble a0 = a0_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = a1_original + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\tif ((a0 < bx0) || (a0 > bx1) ||\n\t\t\t\t\t(a1 < by0) || (a1 > by1))\n\t\t\t\t\tgoto reprise_specialcase;\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a0;\n\t\t\t\t*(float_result_ptr++) = a1;\n\t\t\t}\n\t\t}\n\t\telse if (boundary == BoundaryCondition::kPeriodic)\n\t\t{\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tdouble a0 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\tdouble a1 = *(point_buf_ptr++) + gsl_ran_gaussian(rng_gsl, stddev);\n\t\t\t\t\n\t\t\t\t// (note periodic_x and periodic_y are required to be true above)\n\t\t\t\twhile (a0 < 0.0)\ta0 += bx1;\n\t\t\t\twhile (a0 > bx1)\ta0 -= bx1;\n\t\t\t\twhile (a1 < 0.0)\ta1 += by1;\n\t\t\t\twhile (a1 > by1)\ta1 -= by1;\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a0;\n\t\t\t\t*(float_result_ptr++) = a1;\n\t\t\t}\n\t\t}\n\t\treturn EidosValue_SP(float_result);\n\t}\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tint point_buf_ptr_inc = (point_count > 1) ? 1 : 0;\t\t// move to the next point, unless we're repeatedly processing a single point\n\t\t\t\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tdouble a[1];\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, result_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\t\n\t\t\treprise_1:\n\t\t\t\tkernel.DrawDisplacement_S1(a);\n\t\t\t\ta[0] += point_buf_ptr[0];\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1))\n\t\t\t\t\t\t\tgoto reprise_1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\t\t\t// (periodic_x must be true)\n\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\t\t\t// ruled out above\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): (internal error) absorbing boundaries not implemented.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a[0];\n\t\t\t\tpoint_buf_ptr += point_buf_ptr_inc;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\tint point_buf_ptr_inc = (point_count > 1) ? 2 : 0;\t\t// move to the next point, unless we're repeatedly processing a single point\n\t\t\t\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, result_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tdouble a[2];\n\t\t\t\t\n\t\t\treprise_2:\n\t\t\t\tkernel.DrawDisplacement_S2(a);\n\t\t\t\ta[0] += point_buf_ptr[0];\n\t\t\t\ta[1] += point_buf_ptr[1];\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\ta[1] = std::max(by0, std::min(by1, a[1]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[1] < by0) a[1] = by0 + (by0 - a[1]);\n\t\t\t\t\t\t\telse if (a[1] > by1) a[1] = by1 - (a[1] - by1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1))\n\t\t\t\t\t\t\tgoto reprise_2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tif (periodic_x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_y)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\t\t\t// ruled out above\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): (internal error) absorbing boundaries not implemented.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a[0];\n\t\t\t\t*(float_result_ptr++) = a[1];\n\t\t\t\tpoint_buf_ptr += point_buf_ptr_inc;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\tdouble by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\tdouble bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\tint point_buf_ptr_inc = (point_count > 1) ? 3 : 0;\t\t// move to the next point, unless we're repeatedly processing a single point\n\t\t\t\n\t\t\tfor (int result_index = 0; result_index < n; ++result_index)\n\t\t\t{\n\t\t\t\tSpatialKernel kernel((kernel_count == 1) ? kernel0 : SpatialKernel(dimensionality, max_distance, p_arguments, 4, result_index, /* p_expect_max_density */ false, k_type, k_param_count));\n\t\t\t\tdouble a[3];\n\t\t\t\t\n\t\t\treprise_3:\n\t\t\t\tkernel.DrawDisplacement_S3(a);\n\t\t\t\ta[0] += point_buf_ptr[0];\n\t\t\t\ta[1] += point_buf_ptr[1];\n\t\t\t\ta[2] += point_buf_ptr[2];\n\t\t\t\t\n\t\t\t\t// enforce the boundary condition\n\t\t\t\tswitch (boundary)\n\t\t\t\t{\n\t\t\t\t\tcase BoundaryCondition::kNone:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kStopping:\n\t\t\t\t\t\ta[0] = std::max(bx0, std::min(bx1, a[0]));\n\t\t\t\t\t\ta[1] = std::max(by0, std::min(by1, a[1]));\n\t\t\t\t\t\ta[2] = std::max(bz0, std::min(bz1, a[2]));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReflecting:\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[0] < bx0) a[0] = bx0 + (bx0 - a[0]);\n\t\t\t\t\t\t\telse if (a[0] > bx1) a[0] = bx1 - (a[0] - bx1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[1] < by0) a[1] = by0 + (by0 - a[1]);\n\t\t\t\t\t\t\telse if (a[1] > by1) a[1] = by1 - (a[1] - by1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (true)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (a[2] < bz0) a[2] = bz0 + (bz0 - a[2]);\n\t\t\t\t\t\t\telse if (a[2] > bz1) a[2] = bz1 - (a[2] - bz1);\n\t\t\t\t\t\t\telse break;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kReprising:\n\t\t\t\t\t\tif ((a[0] < bx0) || (a[0] > bx1) ||\n\t\t\t\t\t\t\t(a[1] < by0) || (a[1] > by1) ||\n\t\t\t\t\t\t\t(a[2] < bz0) || (a[2] > bz1))\n\t\t\t\t\t\t\tgoto reprise_3;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kPeriodic:\n\t\t\t\t\t\tif (periodic_x)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[0] < 0.0)\ta[0] += bx1;\n\t\t\t\t\t\t\twhile (a[0] > bx1)\ta[0] -= bx1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_y)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[1] < 0.0)\ta[1] += by1;\n\t\t\t\t\t\t\twhile (a[1] > by1)\ta[1] -= by1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (periodic_z)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (a[2] < 0.0)\ta[2] += bz1;\n\t\t\t\t\t\t\twhile (a[2] > bz1)\ta[2] -= bz1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase BoundaryCondition::kAbsorbing:\t\t\t// ruled out above\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): (internal error) absorbing boundaries not implemented.\" << EidosTerminate();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t*(float_result_ptr++) = a[0];\n\t\t\t\t*(float_result_ptr++) = a[1];\n\t\t\t\t*(float_result_ptr++) = a[2];\n\t\t\t\tpoint_buf_ptr += point_buf_ptr_inc;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointDeviated): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t*********************\t– (logical)pointInBounds(float point)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointInBounds(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\tint value_count = point_value->Count();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointInBounds): pointInBounds() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\tif (value_count == 0)\n\t\treturn gStaticEidosValue_Logical_ZeroVec;\n\t\n\tint point_count = value_count / dimensionality;\n\t\n\tif (value_count != point_count * dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointInBounds): pointInBounds() requires the length of point to be an exact multiple of the spatial dimensionality of the simulation (i.e., point must contain zero or more complete points).\" << EidosTerminate();\n\t\n\tconst double *point_buf = point_value->FloatData();\n\t\n\tif (point_count == 1)\n\t{\n\t\t// single-point case, do it separately to return a singleton logical value\n\t\tswitch (dimensionality)\n\t\t{\n\t\t\tcase 1:\n\t\t\t{\n\t\t\t\tdouble x = point_buf[0];\n\t\t\t\treturn ((x >= bounds_x0_) && (x <= bounds_x1_))\n\t\t\t\t\t? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\t\t}\n\t\t\tcase 2:\n\t\t\t{\n\t\t\t\tdouble x = point_buf[0];\n\t\t\t\tdouble y = point_buf[1];\n\t\t\t\treturn ((x >= bounds_x0_) && (x <= bounds_x1_) && (y >= bounds_y0_) && (y <= bounds_y1_))\n\t\t\t\t\t? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\t\t}\n\t\t\tcase 3:\n\t\t\t{\n\t\t\t\tdouble x = point_buf[0];\n\t\t\t\tdouble y = point_buf[1];\n\t\t\t\tdouble z = point_buf[2];\n\t\t\t\treturn ((x >= bounds_x0_) && (x <= bounds_x1_) && (y >= bounds_y0_) && (y <= bounds_y1_) && (z >= bounds_z0_) && (z <= bounds_z1_))\n\t\t\t\t\t? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointInBounds): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\t// multiple-point case, new in SLiM 3\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(point_count);\n\teidos_logical_t *logical_result_data = logical_result->data_mutable();\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_IN_BOUNDS_1D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, logical_result_data, bx0, bx1) if(point_count >= EIDOS_OMPMIN_POINT_IN_BOUNDS_1D) num_threads(thread_count)\n\t\t\tfor (int point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index];\n\t\t\t\teidos_logical_t in_bounds = ((x >= bx0) && (x <= bx1));\n\t\t\t\t\n\t\t\t\tlogical_result_data[point_index] = in_bounds;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_IN_BOUNDS_2D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, logical_result_data, bx0, bx1, by0, by1) if(point_count >= EIDOS_OMPMIN_POINT_IN_BOUNDS_2D) num_threads(thread_count)\n\t\t\tfor (int point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[(size_t)point_index * 2];\n\t\t\t\tdouble y = point_buf[(size_t)point_index * 2 + 1];\n\t\t\t\teidos_logical_t in_bounds = ((x >= bx0) && (x <= bx1) && (y >= by0) && (y <= by1));\n\t\t\t\t\n\t\t\t\tlogical_result_data[point_index] = in_bounds;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_, bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_IN_BOUNDS_3D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, logical_result_data, bx0, bx1, by0, by1, bz0, bz1) if(point_count >= EIDOS_OMPMIN_POINT_IN_BOUNDS_3D) num_threads(thread_count)\n\t\t\tfor (int point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[(size_t)point_index * 3];\n\t\t\t\tdouble y = point_buf[(size_t)point_index * 3 + 1];\n\t\t\t\tdouble z = point_buf[(size_t)point_index * 3 + 2];\n\t\t\t\teidos_logical_t in_bounds = ((x >= bx0) && (x <= bx1) && (y >= by0) && (y <= by1) && (z >= bz0) && (z <= bz1));\n\t\t\t\t\n\t\t\t\tlogical_result_data[point_index] = in_bounds;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointInBounds): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(logical_result);\n}\t\t\t\n\n//\t*********************\t– (float)pointReflected(float point)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointReflected(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\tint value_count = point_value->Count();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointReflected): pointReflected() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\tif (value_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tint point_count = value_count / dimensionality;\n\t\n\tif (value_count != point_count * dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointReflected): pointReflected() requires the length of point to be an exact multiple of the spatial dimensionality of the simulation (i.e., point must contain zero or more complete points).\" << EidosTerminate();\n\t\n\tconst double *point_buf = point_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(value_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_REFLECTED_1D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1) if(point_count >= EIDOS_OMPMIN_POINT_REFLECTED_1D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (x < bx0) x = bx0 + (bx0 - x);\n\t\t\t\t\telse if (x > bx1) x = bx1 - (x - bx1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index] = x;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_REFLECTED_2D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1, by0, by1) if(point_count >= EIDOS_OMPMIN_POINT_REFLECTED_2D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 2];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (x < bx0) x = bx0 + (bx0 - x);\n\t\t\t\t\telse if (x > bx1) x = bx1 - (x - bx1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 2] = x;\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 2 + 1];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (y < by0) y = by0 + (by0 - y);\n\t\t\t\t\telse if (y > by1) y = by1 - (y - by1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 2 + 1] = y;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_, bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_REFLECTED_3D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1, by0, by1, bz0, bz1) if(point_count >= EIDOS_OMPMIN_POINT_REFLECTED_3D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 3];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (x < bx0) x = bx0 + (bx0 - x);\n\t\t\t\t\telse if (x > bx1) x = bx1 - (x - bx1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3] = x;\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 3 + 1];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (y < by0) y = by0 + (by0 - y);\n\t\t\t\t\telse if (y > by1) y = by1 - (y - by1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3 + 1] = y;\n\t\t\t\t\n\t\t\t\tdouble z = point_buf[point_index * 3 + 2];\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tif (z < bz0) z = bz0 + (bz0 - z);\n\t\t\t\t\telse if (z > bz1) z = bz1 - (z - bz1);\n\t\t\t\t\telse break;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3 + 2] = z;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointReflected): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\t\t\t\n\n//\t*********************\t– (float)pointStopped(float point)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointStopped(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\tint value_count = point_value->Count();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointStopped): pointStopped() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\tif (value_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tint point_count = value_count / dimensionality;\n\t\n\tif (value_count != point_count * dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointStopped): pointStopped() requires the length of point to be an exact multiple of the spatial dimensionality of the simulation (i.e., point must contain zero or more complete points).\" << EidosTerminate();\n\t\n\tconst double *point_buf = point_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(value_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_STOPPED_1D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1) if(point_count >= EIDOS_OMPMIN_POINT_STOPPED_1D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index];\n\t\t\t\tfloat_result_data[point_index] = std::max(bx0, std::min(bx1, x));\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_STOPPED_2D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1, by0, by1) if(point_count >= EIDOS_OMPMIN_POINT_STOPPED_2D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 2];\n\t\t\t\tfloat_result_data[point_index * 2] = std::max(bx0, std::min(bx1, x));\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 2 + 1];\n\t\t\t\tfloat_result_data[point_index * 2 + 1] = std::max(by0, std::min(by1, y));\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx0 = bounds_x0_, bx1 = bounds_x1_, by0 = bounds_y0_, by1 = bounds_y1_, bz0 = bounds_z0_, bz1 = bounds_z1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_STOPPED_3D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx0, bx1, by0, by1, bz0, bz1) if(point_count >= EIDOS_OMPMIN_POINT_STOPPED_3D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 3];\n\t\t\t\tfloat_result_data[point_index * 3] = std::max(bx0, std::min(bx1, x));\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 3 + 1];\n\t\t\t\tfloat_result_data[point_index * 3 + 1] = std::max(by0, std::min(by1, y));\n\t\t\t\t\n\t\t\t\tdouble z = point_buf[point_index * 3 + 2];\n\t\t\t\tfloat_result_data[point_index * 3 + 2] = std::max(bz0, std::min(bz1, z));\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointStopped): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\t\t\t\n\n//\t*********************\t– (float)pointPeriodic(float point)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointPeriodic(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *point_value = p_arguments[0].get();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\tint value_count = point_value->Count();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointPeriodic): pointPeriodic() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tbool periodic_x, periodic_y, periodic_z;\n\t\n\tspecies_.SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\n\tif (!periodic_x && !periodic_y && !periodic_z)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointPeriodic): pointPeriodic() cannot be called when no periodic spatial dimension has been set up.\" << EidosTerminate();\n\t\n\tif (value_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tint point_count = value_count / dimensionality;\n\t\n\tif (value_count != point_count * dimensionality)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointPeriodic): pointPeriodic() requires the length of point to be an exact multiple of the spatial dimensionality of the simulation (i.e., point must contain zero or more complete points).\" << EidosTerminate();\n\t\n\tconst double *point_buf = point_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(value_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\t\n\t// Wrap coordinates; note that we assume here that bounds_x0_ == bounds_y0_ == bounds_z0_ == 0,\n\t// which is enforced when periodic boundary conditions are set, in setSpatialBounds().  Note also\n\t// that we don't use fmod(); maybe we should, rather than looping, but then we have to worry about\n\t// sign, and since new spatial points are probably usually close to being in bounds, these loops\n\t// probably won't execute more than once anyway...\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tdouble bx1 = bounds_x1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_PERIODIC_1D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx1, periodic_x) if(point_count >= EIDOS_OMPMIN_POINT_PERIODIC_1D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index];\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (x < 0.0)\t\t\tx += bx1;\n\t\t\t\t\twhile (x > bx1)\t\t\tx -= bx1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index] = x;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tdouble bx1 = bounds_x1_, by1 = bounds_y1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_PERIODIC_2D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx1, by1, periodic_x, periodic_y) if(point_count >= EIDOS_OMPMIN_POINT_PERIODIC_2D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 2];\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (x < 0.0)\t\t\tx += bx1;\n\t\t\t\t\twhile (x > bx1)\t\t\tx -= bx1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 2] = x;\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 2 + 1];\n\t\t\t\tif (periodic_y)\n\t\t\t\t{\n\t\t\t\t\twhile (y < 0.0)\t\t\ty += by1;\n\t\t\t\t\twhile (y > by1)\t\t\ty -= by1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 2 + 1] = y;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tdouble bx1 = bounds_x1_, by1 = bounds_y1_, bz1 = bounds_z1_;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_PERIODIC_3D);\n#pragma omp parallel for schedule(static) default(none) shared(point_count) firstprivate(point_buf, float_result_data, bx1, by1, bz1, periodic_x, periodic_y, periodic_z) if(point_count >= EIDOS_OMPMIN_POINT_PERIODIC_3D) num_threads(thread_count)\n\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t{\n\t\t\t\tdouble x = point_buf[point_index * 3];\n\t\t\t\tif (periodic_x)\n\t\t\t\t{\n\t\t\t\t\twhile (x < 0.0)\t\t\tx += bx1;\n\t\t\t\t\twhile (x > bx1)\t\t\tx -= bx1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3] = x;\n\t\t\t\t\n\t\t\t\tdouble y = point_buf[point_index * 3 + 1];\n\t\t\t\tif (periodic_y)\n\t\t\t\t{\n\t\t\t\t\twhile (y < 0.0)\t\t\ty += by1;\n\t\t\t\t\twhile (y > by1)\t\t\ty -= by1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3 + 1] = y;\n\t\t\t\t\n\t\t\t\tdouble z = point_buf[point_index * 3 + 2];\n\t\t\t\tif (periodic_z)\n\t\t\t\t{\n\t\t\t\t\twhile (z < 0.0)\t\t\tz += bz1;\n\t\t\t\t\twhile (z > bz1)\t\t\tz -= bz1;\n\t\t\t\t}\n\t\t\t\tfloat_result_data[point_index * 3 + 2] = z;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointPeriodic): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn EidosValue_SP(float_result);\n}\t\t\t\n\n//\t*********************\t– (float)pointUniform([integer$ n = 1])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointUniform(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniform): pointUniform() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t point_count = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (point_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniform): pointUniform() requires n >= 0.\" << EidosTerminate();\n\tif (point_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tint64_t length_out = point_count * dimensionality;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(length_out);\n\tdouble *float_result_data = float_result->data_mutable();\n\tEidosValue_SP result_SP = EidosValue_SP(float_result);\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_UNIFORM_1D);\n#pragma omp parallel default(none) shared(point_count, gEidos_RNG_PERTHREAD) firstprivate(float_result_data) if(point_count >= EIDOS_OMPMIN_POINT_UNIFORM_1D) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tfloat_result_data[point_index] = Eidos_rng_uniform_doubleCO(rng_64) * xsize + xbase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_UNIFORM_2D);\n#pragma omp parallel default(none) shared(point_count, gEidos_RNG_PERTHREAD) firstprivate(float_result_data) if(point_count >= EIDOS_OMPMIN_POINT_UNIFORM_2D) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\tdouble ysize = bounds_y1_ - bounds_y0_, ybase = bounds_y0_;\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tfloat_result_data[point_index * 2] = Eidos_rng_uniform_doubleCO(rng_64) * xsize + xbase;\n\t\t\t\t\tfloat_result_data[point_index * 2 + 1] = Eidos_rng_uniform_doubleCO(rng_64) * ysize + ybase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_POINT_UNIFORM_3D);\n#pragma omp parallel default(none) shared(point_count, gEidos_RNG_PERTHREAD) firstprivate(float_result_data) if(point_count >= EIDOS_OMPMIN_POINT_UNIFORM_3D) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\tdouble ysize = bounds_y1_ - bounds_y0_, ybase = bounds_y0_;\n\t\t\t\tdouble zsize = bounds_z1_ - bounds_z0_, zbase = bounds_z0_;\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tfloat_result_data[point_index * 3] = Eidos_rng_uniform_doubleCO(rng_64) * xsize + xbase;\n\t\t\t\t\tfloat_result_data[point_index * 3 + 1] = Eidos_rng_uniform_doubleCO(rng_64) * ysize + ybase;\n\t\t\t\t\tfloat_result_data[point_index * 3 + 2] = Eidos_rng_uniform_doubleCO(rng_64) * zsize + zbase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniform): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t– (float)pointUniformWithMap(integer$ n, so<SpatialMap>$ map)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_pointUniformWithMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t point_count = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (point_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() requires n >= 0.\" << EidosTerminate();\n\tif (point_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// Get the spatial map's name; see ExecuteMethod_spatialMapValue() for the origin of this code\n\tEidosValue *map_value = p_arguments[1].get();\n\tSpatialMap *map = nullptr;\n\tstd::string map_name;\n\t\n\tif (map_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tmap_name = ((EidosValue_String *)map_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (map_name.length() == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() map name must not be zero-length.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\tmap = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tmap_name = map->name_;\n\t}\n\t\n\t// Find the SpatialMap by name; we do this lookup even if a map object was supplied, to check that that map is present\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *found_map = map_iter->second;\n\t\t\n\t\tif (map && (found_map != map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() could not find map in the target subpopulation (although it did find a different map with the same name).\" << EidosTerminate();\n\t\t\n\t\tmap = found_map;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() could not find map '\" << map_name << \"' in the target subpopulation.\" << EidosTerminate();\n\t\n\t// The map is required to have spatiality equal to the species dimensionality.  This is because the value\n\t// queries to the map using ValueAtPoint_S2() etc. are in the map's spatiality, and we don't want to have\n\t// to be translating points in and out of that spatiality.  Other methods don't have this problem because\n\t// either they get passed a point (which must be in the map or interaction type's spatiality) or they have\n\t// cached the point in the correct spatiality internally (as InteractionType does).  Users who have a map\n\t// in a weird spatiality can always do the work of this method themselves, with more basic calls.\n\tif (dimensionality != map->spatiality_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() requires that the map's spatiality is equal to the dimensionality of the species.\" << EidosTerminate();\n\t\n\t// Generate the points\n\tint64_t length_out = point_count * dimensionality;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(length_out);\n\tdouble *float_result_data = float_result->data_mutable();\n\tEidosValue_SP result_SP = EidosValue_SP(float_result);\n\t\n\t// FIXME: PARALLELIZE\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t{\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\t\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tdouble *point_base = &(float_result_data[point_index]);\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\t\tdo {\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() failed to find a successful drawn point after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// ValueAtPoint_S1() requires points normalized to [0, 1] in the map's spatiality\n\t\t\t\t\t\tpoint_base[0] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S1(point_base);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse if (Eidos_rng_uniform_doubleCO(rng_64) <= value_for_point)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t} while (true);\n\t\t\t\t\t\n\t\t\t\t\tpoint_base[0] = point_base[0] * xsize + xbase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 2:\n\t\t{\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\tdouble ysize = bounds_y1_ - bounds_y0_, ybase = bounds_y0_;\n\t\t\t\t\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tdouble *point_base = &(float_result_data[point_index * 2]);\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\t\tdo {\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() failed to find a successful drawn point after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// ValueAtPoint_S2() requires points normalized to [0, 1] in the map's spatiality\n\t\t\t\t\t\tpoint_base[0] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tpoint_base[1] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S2(point_base);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse if (Eidos_rng_uniform_doubleCO(rng_64) <= value_for_point)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t} while (true);\n\t\t\t\t\t\n\t\t\t\t\tpoint_base[0] = point_base[0] * xsize + xbase;\n\t\t\t\t\tpoint_base[1] = point_base[1] * ysize + ybase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase 3:\n\t\t{\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble xsize = bounds_x1_ - bounds_x0_, xbase = bounds_x0_;\n\t\t\t\tdouble ysize = bounds_y1_ - bounds_y0_, ybase = bounds_y0_;\n\t\t\t\tdouble zsize = bounds_z1_ - bounds_z0_, zbase = bounds_z0_;\n\t\t\t\t\n\t\t\t\tfor (int64_t point_index = 0; point_index < point_count; ++point_index)\n\t\t\t\t{\n\t\t\t\t\tdouble *point_base = &(float_result_data[point_index * 3]);\n\t\t\t\t\tint num_tries = 0;\n\t\t\t\t\t\n\t\t\t\t\tdo {\n\t\t\t\t\t\tif (++num_tries == 1000000)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SpatialMap::ExecuteMethod_pointUniformWithMap): pointUniformWithMap() failed to find a successful drawn point after 1 million attempts; terminating to avoid infinite loop.\" << EidosTerminate();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// ValueAtPoint_S3() requires points normalized to [0, 1] in the map's spatiality\n\t\t\t\t\t\tpoint_base[0] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tpoint_base[1] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tpoint_base[2] = Eidos_rng_uniform_doubleCO(rng_64);\n\t\t\t\t\t\tdouble value_for_point = map->ValueAtPoint_S3(point_base);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (value_for_point <= 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\telse if (value_for_point >= 1)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse if (Eidos_rng_uniform_doubleCO(rng_64) <= value_for_point)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t} while (true);\n\t\t\t\t\t\n\t\t\t\t\tpoint_base[0] = point_base[0] * xsize + xbase;\n\t\t\t\t\tpoint_base[1] = point_base[1] * ysize + ybase;\n\t\t\t\t\tpoint_base[2] = point_base[2] * zsize + zbase;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_pointUniformWithMap): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\treturn result_SP;\n}\t\t\t\n\n// WF only:\n//\t*********************\t- (void)setCloningRate(numeric rate)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setCloningRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tEidosValue *rate_value = p_arguments[0].get();\n\t\n\tint value_count = rate_value->Count();\n\t\n\tif (sex_enabled_)\n\t{\n\t\t// SEX ONLY: either one or two values may be specified; if two, it is female at 0, male at 1\n\t\tif ((value_count < 1) || (value_count > 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() requires a rate vector containing either one or two values, in sexual simulations.\" << EidosTerminate();\n\t\t\n\t\tdouble female_cloning_fraction = rate_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\tdouble male_cloning_fraction = (value_count == 2) ? rate_value->NumericAtIndex_NOCAST(1, nullptr) : female_cloning_fraction;\n\t\t\n\t\tif ((female_cloning_fraction < 0.0) || (female_cloning_fraction > 1.0) || std::isnan(female_cloning_fraction))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() requires cloning fractions within [0,1] (\" << EidosStringForFloat(female_cloning_fraction) << \" supplied).\" << EidosTerminate();\n\t\tif ((male_cloning_fraction < 0.0) || (male_cloning_fraction > 1.0) || std::isnan(male_cloning_fraction))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() requires cloning fractions within [0,1] (\" << EidosStringForFloat(male_cloning_fraction) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\tfemale_clone_fraction_ = female_cloning_fraction;\n\t\tmale_clone_fraction_ = male_cloning_fraction;\n\t}\n\telse\n\t{\n\t\t// ASEX ONLY: only one value may be specified\n\t\tif (value_count != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() requires a rate vector containing exactly one value, in asexual simulations..\" << EidosTerminate();\n\t\t\n\t\tdouble cloning_fraction = rate_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((cloning_fraction < 0.0) || (cloning_fraction > 1.0) || std::isnan(cloning_fraction))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setCloningRate): setCloningRate() requires cloning fractions within [0,1] (\" << EidosStringForFloat(cloning_fraction) << \" supplied).\" << EidosTerminate();\n\t\t\n\t\tfemale_clone_fraction_ = cloning_fraction;\n\t\tmale_clone_fraction_ = cloning_fraction;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\t\t\t\n\n// WF only:\n//\t*********************\t- (void)setSelfingRate(numeric$ rate)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setSelfingRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSelfingRate): setSelfingRate() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tEidosValue *rate_value = p_arguments[0].get();\n\t\n\tdouble selfing_fraction = rate_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((selfing_fraction != 0.0) && sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSelfingRate): setSelfingRate() is limited to the hermaphroditic case, and cannot be called in sexual simulations.\" << EidosTerminate();\n\t\n\tif ((selfing_fraction < 0.0) || (selfing_fraction > 1.0) || std::isnan(selfing_fraction))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSelfingRate): setSelfingRate() requires a selfing fraction within [0,1] (\" << EidosStringForFloat(selfing_fraction) << \" supplied).\" << EidosTerminate();\n\t\n\tselfing_fraction_ = selfing_fraction;\n\t\n\treturn gStaticEidosValueVOID;\n}\t\t\t\n\n// WF only:\n//\t*********************\t- (void)setSexRatio(float$ sexRatio)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSexRatio): setSexRatio() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tEidosValue *sexRatio_value = p_arguments[0].get();\n\t\n\t// SetSexRatio() sets the sex ratio on the child generation, and then that sex ratio takes effect\n\t// when the children are generated from the parents in EvolveSubpopulation().\n\t\n\t// SEX ONLY\n\tif (!sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSexRatio): setSexRatio() is limited to the sexual case, and cannot be called in asexual simulations.\" << EidosTerminate();\n\t\n\tdouble sex_ratio = sexRatio_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((sex_ratio < 0.0) || (sex_ratio > 1.0) || std::isnan(sex_ratio))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSexRatio): setSexRatio() requires a sex ratio within [0,1] (\" << EidosStringForFloat(sex_ratio) << \" supplied).\" << EidosTerminate();\n\t\n\t// After we change the subpop sex ratio, we need to generate new children haplosomes to fit the new requirements\n\tchild_sex_ratio_ = sex_ratio;\n\tGenerateChildrenToFitWF();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)setSpatialBounds(numeric position)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setSpatialBounds(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *position_value = p_arguments[0].get();\n\t\n\tint dimensionality = species_.SpatialDimensionality();\n\tint value_count = position_value->Count();\n\t\n\tif (dimensionality == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): setSpatialBounds() cannot be called in non-spatial simulations.\" << EidosTerminate();\n\t\n\tif (value_count != dimensionality * 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): setSpatialBounds() requires twice as many coordinates as the spatial dimensionality of the simulation.\" << EidosTerminate();\n\t\n\tbool bad_bounds = false, bad_periodic_bounds = false;\n\tbool periodic_x, periodic_y, periodic_z;\n\t\n\tspecies_.SpatialPeriodicity(&periodic_x, &periodic_y, &periodic_z);\n\t\n\tswitch (dimensionality)\n\t{\n\t\tcase 1:\n\t\t\tbounds_x0_ = position_value->NumericAtIndex_NOCAST(0, nullptr);\tbounds_x1_ = position_value->NumericAtIndex_NOCAST(1, nullptr);\n\t\t\t\n\t\t\tif (bounds_x1_ <= bounds_x0_)\n\t\t\t\tbad_bounds = true;\n\t\t\tif (periodic_x && (bounds_x0_ != 0.0))\n\t\t\t\tbad_periodic_bounds = true;\n\t\t\t\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tbounds_x0_ = position_value->NumericAtIndex_NOCAST(0, nullptr);\tbounds_x1_ = position_value->NumericAtIndex_NOCAST(2, nullptr);\n\t\t\tbounds_y0_ = position_value->NumericAtIndex_NOCAST(1, nullptr);\tbounds_y1_ = position_value->NumericAtIndex_NOCAST(3, nullptr);\n\t\t\t\n\t\t\tif ((bounds_x1_ <= bounds_x0_) || (bounds_y1_ <= bounds_y0_))\n\t\t\t\tbad_bounds = true;\n\t\t\tif ((periodic_x && (bounds_x0_ != 0.0)) || (periodic_y && (bounds_y0_ != 0.0)))\n\t\t\t\tbad_periodic_bounds = true;\n\t\t\t\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tbounds_x0_ = position_value->NumericAtIndex_NOCAST(0, nullptr);\tbounds_x1_ = position_value->NumericAtIndex_NOCAST(3, nullptr);\n\t\t\tbounds_y0_ = position_value->NumericAtIndex_NOCAST(1, nullptr);\tbounds_y1_ = position_value->NumericAtIndex_NOCAST(4, nullptr);\n\t\t\tbounds_z0_ = position_value->NumericAtIndex_NOCAST(2, nullptr);\tbounds_z1_ = position_value->NumericAtIndex_NOCAST(5, nullptr);\n\t\t\t\n\t\t\tif ((bounds_x1_ <= bounds_x0_) || (bounds_y1_ <= bounds_y0_) || (bounds_z1_ <= bounds_z0_))\n\t\t\t\tbad_bounds = true;\n\t\t\tif ((periodic_x && (bounds_x0_ != 0.0)) || (periodic_y && (bounds_y0_ != 0.0)) || (periodic_z && (bounds_z0_ != 0.0)))\n\t\t\t\tbad_periodic_bounds = true;\n\t\t\t\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): (internal error) unrecognized dimensionality.\" << EidosTerminate();\n\t}\n\t\n\tif (bad_bounds)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): setSpatialBounds() requires min coordinates to be less than max coordinates.\" << EidosTerminate();\n\t\n\t// When a spatial dimension has been declared to be periodic, we require a min coordinate of 0.0 for that dimension\n\t// to keep the wrapping math simple and fast; it would not be hard to generalize the math but it would be slower\n\tif (bad_periodic_bounds)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): setSpatialBounds() requires min coordinates to be 0.0 for dimensions that are periodic.\" << EidosTerminate();\n\t\n\t// Check that all spatial maps attached to this subpop are compatible with our new bounds; error if not\n\tfor (const auto &map_iter : spatial_maps_)\n\t{\n\t\tSpatialMap *map = map_iter.second;\n\t\t\n\t\tif (!map->IsCompatibleWithSubpopulation(this))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSpatialBounds): setSpatialBounds() new spatial bounds are not compatible with an attached map named '\" << map->name_ << \"'; use removeSpatialMap() to remove incompatible spatial maps before changing the spatial bounds.  (This enforces internal consistency and avoids accidentally stretching a map to new spatial bounds.)\" << EidosTerminate();\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\t\t\t\n\n// WF only:\n//\t*********************\t- (void)setSubpopulationSize(integer$ size)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_setSubpopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeNonWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_setSubpopulationSize): setSubpopulationSize() is not available in nonWF models.\" << EidosTerminate();\n\t\n\tEidosValue *size_value = p_arguments[0].get();\n\t\n\tslim_popsize_t subpop_size = SLiMCastToPopsizeTypeOrRaise(size_value->IntAtIndex_NOCAST(0, nullptr));\n\t\n\tpopulation_.SetSize(*this, subpop_size);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// nonWF only:\n//\t*********************\t- (void)removeSubpopulation()\n//\nEidosValue_SP Subpopulation::ExecuteMethod_removeSubpopulation(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_removeSubpopulation): removeSubpopulation() is not available in WF models.\" << EidosTerminate();\n\t\n\t// TIMING RESTRICTION\n\tif (community_.executing_species_ == &species_)\n\t\tif ((community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventFirst) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventEarly) && (community_.executing_block_type_ != SLiMEidosBlockType::SLiMEidosEventLate))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_removeSubpopulation): removeSubpopulation() must be called directly from a first(), early(), or late() event, when called on the currently executing species.\" << EidosTerminate();\n\t\n\tpopulation_.RemoveSubpopulation(*this);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (float)cachedFitness(Ni indices)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_cachedFitness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *indices_value = p_arguments[0].get();\n\t\n\t// TIMING RESTRICTION\n\tif (model_type_ == SLiMModelType::kModelTypeWF)\n\t{\n\t\tif (community_.executing_species_ == &species_)\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kWFStage6CalculateFitness)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_cachedFitness): cachedFitness() may not be called for the currently executing species while its fitness values are being calculated.\" << EidosTerminate();\n\t\t\n\t\t// We used to disallow calling cachedFitness() in late() events in WF models in all cases (since a commit on 5 March 2018),\n\t\t// because the cached fitness values at that point are typically garbage.  However, it is useful to allow the user to call\n\t\t// recalculateFitness() and then cachedFitness(); in that case the cached fitness values are valid.  This allows WF models\n\t\t// to interpose logic that changes fitness values based upon fitness values (such as hard selection).\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage5ExecuteLateScripts) && !species_.has_recalculated_fitness_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_cachedFitness): cachedFitness() generally cannot be called during late() events in WF models, since the new generation does not yet have fitness values (which are calculated immediately after late() events have executed).  If you really need to get fitness values in a late() event, you can call recalculateFitness() first to force fitness value recalculation to occur, but that is not something to do lightly; proceed with caution.  Usually it is better to access fitness values after SLiM has calculated them, in a first() or early() event.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\tif (community_.executing_species_ == &species_)\n\t\t\tif (community_.CycleStage() == SLiMCycleStage::kNonWFStage3CalculateFitness)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_cachedFitness): cachedFitness() may not be called for the currently executing species while its fitness values are being calculated.\" << EidosTerminate();\n\t\t// in nonWF models uncalculated fitness values for new individuals are guaranteed to be NaN, so there is no need for a check here\n\t}\n\t\n\tbool do_all_indices = (indices_value->Type() == EidosValueType::kValueNULL);\n\tslim_popsize_t index_count = (do_all_indices ? parent_subpop_size_ : SLiMCastToPopsizeTypeOrRaise(indices_value->Count()));\n\tEidosValue_Float *float_return = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(index_count);\n\tEidosValue_SP result_SP = EidosValue_SP(float_return);\n\tconst int64_t *indices = (do_all_indices ? nullptr : indices_value->IntData());\n\t\n\tfor (slim_popsize_t value_index = 0; value_index < index_count; value_index++)\n\t{\n\t\tslim_popsize_t index = value_index;\n\t\t\n\t\tif (!do_all_indices)\n\t\t{\n\t\t\tindex = SLiMCastToPopsizeTypeOrRaise(indices[value_index]);\n\t\t\t\n\t\t\tif (index >= parent_subpop_size_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_cachedFitness): cachedFitness() index \" << index << \" out of range.\" << EidosTerminate();\n\t\t}\n\t\t\n\t\tdouble fitness = (individual_cached_fitness_OVERRIDE_ ? individual_cached_fitness_OVERRIDE_value_ : parent_individuals_[index]->cached_fitness_UNSAFE_);\n\t\t\n\t\tfloat_return->set_float_no_check(fitness, value_index);\n\t}\n\t\n\treturn result_SP;\n}\n\n//  *********************\t– (No<Individual>)sampleIndividuals(integer$ size, [logical$ replace = F], [No<Individual>$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL], [Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_sampleIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// This method is patterned closely upon Eidos_ExecuteFunction_sample(), but with no weights vector, and with various ways to narrow down the candidate pool\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tint64_t sample_size = p_arguments[0]->IntAtIndex_NOCAST(0, nullptr);\n\tbool replace = p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr);\n\tint x_count = parent_subpop_size_;\n\t\n\tif (sample_size < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): sampleIndividuals() requires a sample size >= 0 (\" << sample_size << \" supplied).\" << EidosTerminate(nullptr);\n\tif ((sample_size == 0) || (x_count == 0))\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\t// a specific individual may be excluded\n\tEidosValue *exclude_value = p_arguments[2].get();\n\tIndividual *excluded_individual = nullptr;\n\tslim_popsize_t excluded_index = -1;\n\t\n\tif (exclude_value->Type() != EidosValueType::kValueNULL)\n\t\texcluded_individual = (Individual *)exclude_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tif (excluded_individual)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif (excluded_individual->subpopulation_ != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): the excluded individual must belong to the subpopulation being sampled.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (excluded_individual->index_ == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): the excluded individual must be a valid, visible individual (not a newly generated child).\" << EidosTerminate(nullptr);\n\t\t\n\t\texcluded_index = excluded_individual->index_;\n\t}\n\t\n\t// a sex may be specified\n\tEidosValue *sex_value = p_arguments[3].get();\n\tIndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tconst std::string &sex_string = ((EidosValue_String *)sex_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (sex_string == \"M\")\t\t\tsex = IndividualSex::kMale;\n\t\telse if (sex_string == \"F\")\t\tsex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): unrecognized value for sex in sampleIndividuals(); sex must be 'F', 'M', or NULL.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (!sex_enabled_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): sex must be NULL in non-sexual models.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// a tag value may be specified; if so, tag values must be defined for all individuals\n\tEidosValue *tag_value = p_arguments[4].get();\n\tbool tag_specified = (tag_value->Type() != EidosValueType::kValueNULL);\n\tslim_usertag_t tag = (tag_specified ? tag_value->IntAtIndex_NOCAST(0, nullptr) : 0);\n\t\n\t// an age min or max may be specified in nonWF models\n\tEidosValue *ageMin_value = p_arguments[5].get();\n\tEidosValue *ageMax_value = p_arguments[6].get();\n\tbool ageMin_specified = (ageMin_value->Type() != EidosValueType::kValueNULL);\n\tbool ageMax_specified = (ageMax_value->Type() != EidosValueType::kValueNULL);\n\tint64_t ageMin = (ageMin_specified ? ageMin_value->IntAtIndex_NOCAST(0, nullptr) : -1);\n\tint64_t ageMax = (ageMax_specified ? ageMax_value->IntAtIndex_NOCAST(0, nullptr) : INT64_MAX);\n\t\n\tif ((ageMin_specified || ageMax_specified) && (model_type_ != SLiMModelType::kModelTypeNonWF))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): ageMin and ageMax may only be specified in nonWF models.\" << EidosTerminate(nullptr);\n\t\n\t// a migrant value may be specified\n\tEidosValue *migrant_value = p_arguments[7].get();\n\tbool migrant_specified = (migrant_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t migrant = (migrant_specified ? migrant_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\t\n\t// logical tag values, tagL0 - tagL4, may be specified; if so, those tagL values must be defined for all individuals\n\tEidosValue *tagL0_value = p_arguments[8].get();\n\tbool tagL0_specified = (tagL0_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL0 = (tagL0_specified ? tagL0_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL1_value = p_arguments[9].get();\n\tbool tagL1_specified = (tagL1_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL1 = (tagL1_specified ? tagL1_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL2_value = p_arguments[10].get();\n\tbool tagL2_specified = (tagL2_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL2 = (tagL2_specified ? tagL2_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL3_value = p_arguments[11].get();\n\tbool tagL3_specified = (tagL3_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL3 = (tagL3_specified ? tagL3_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL4_value = p_arguments[12].get();\n\tbool tagL4_specified = (tagL4_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL4 = (tagL4_specified ? tagL4_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tbool any_tagL_specified = (tagL0_specified || tagL1_specified || tagL2_specified || tagL3_specified || tagL4_specified);\n\t\n\t// determine the range the sample will be drawn from; this does not take into account tag, tagLX, or ageMin/ageMax\n\tint first_candidate_index, last_candidate_index, candidate_count;\n\t\n\tif (sex == IndividualSex::kUnspecified)\n\t{\n\t\tfirst_candidate_index = 0;\n\t\tlast_candidate_index = parent_subpop_size_ - 1;\n\t\tcandidate_count = parent_subpop_size_;\n\t}\n\telse if (sex == IndividualSex::kFemale)\n\t{\n\t\tfirst_candidate_index = 0;\n\t\tlast_candidate_index = parent_first_male_index_ - 1;\n\t\tcandidate_count = parent_first_male_index_;\n\t}\n\telse // if (sex == IndividualSex::kMale)\n\t{\n\t\tfirst_candidate_index = parent_first_male_index_;\n\t\tlast_candidate_index = parent_subpop_size_ - 1;\n\t\tcandidate_count = (last_candidate_index - first_candidate_index) + 1;\n\t}\n\t\n\tif ((excluded_index >= first_candidate_index) && (excluded_index <= last_candidate_index))\n\t\tcandidate_count--;\n\telse\n\t\texcluded_index = -1;\n\t\n\tif (!tag_specified && !ageMin_specified && !ageMax_specified && !migrant_specified && !any_tagL_specified)\n\t{\n\t\t// we're in the simple case of no specifed tag/ageMin/ageMax/migrant/tagL, so maybe we can handle it quickly\n\t\tif (candidate_count == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\telse if (!replace && (candidate_count < sample_size))\n\t\t\tsample_size = candidate_count;\n\t\t\n\t\tif (sample_size == 1)\n\t\t{\n\t\t\t// a sample size of 1 is very common; make it as fast as we can by getting a singleton EidosValue directly from x\n\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\tint sample_index = (int)Eidos_rng_interval_uint32(rng_32, candidate_count) + first_candidate_index;\n\t\t\t\n\t\t\tif ((excluded_index != -1) && (sample_index >= excluded_index))\n\t\t\t\tsample_index++;\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(parent_individuals_[sample_index], gSLiM_Individual_Class));\n\t\t}\n\t\telse if (replace)\n\t\t{\n\t\t\t// with replacement, we can just do a series of independent draws\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get())->resize_no_initialize(sample_size);\n\t\t\tEidosObject **object_result_data = result->data_mutable();\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_INDIVIDUALS_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(candidate_count, first_candidate_index, excluded_index, object_result_data) if(sample_size >= EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_1) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tint sample_index = (int)Eidos_rng_interval_uint32(rng_32, candidate_count) + first_candidate_index;\n\t\t\t\t\t\n\t\t\t\t\tif ((excluded_index != -1) && (sample_index >= excluded_index))\n\t\t\t\t\t\tsample_index++;\n\t\t\t\t\t\n\t\t\t\t\tobject_result_data[samples_generated] = parent_individuals_[sample_index];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Retain all of the objects chosen; this is not done in parallel because it would require locks\n\t\t\t// This is dead code at the moment, because Individual does not use retain/release\n\t\t\tif (gSLiM_Individual_Class->UsesRetainRelease())\n\t\t\t{\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tEidosObject *object_element = object_result_data[samples_generated];\n\t\t\t\t\tstatic_cast<EidosDictionaryRetained *>(object_element)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\telse if (sample_size == 2)\n\t\t{\n\t\t\t// a sample size of two without replacement is expected to be common (interacting pairs) so optimize for it\n\t\t\t// note that the code above guarantees that here there are at least two candidates to draw\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\t\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get())->resize_no_initialize(sample_size);\n\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tint sample_index1 = (int)Eidos_rng_interval_uint32(rng_32, candidate_count) + first_candidate_index;\n\t\t\t\n\t\t\tif ((excluded_index != -1) && (sample_index1 >= excluded_index))\n\t\t\t\tsample_index1++;\n\t\t\t\n\t\t\tresult->set_object_element_no_check_NORR(parent_individuals_[sample_index1], 0);\n\t\t\t\n\t\t\tint sample_index2;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tsample_index2 = (int)Eidos_rng_interval_uint32(rng_32, candidate_count) + first_candidate_index;\n\t\t\t\t\n\t\t\t\tif ((excluded_index != -1) && (sample_index2 >= excluded_index))\n\t\t\t\t\tsample_index2++;\n\t\t\t}\n\t\t\twhile (sample_index2 == sample_index1);\n\t\t\t\n\t\t\tresult->set_object_element_no_check_NORR(parent_individuals_[sample_index2], 1);\n\t\t\t\n\t\t\treturn result_SP;\n\t\t}\n\t\t\n\t\t// note that we drop through here if none of the three special cases above is hit\n\t}\n\t\n\t// BCH 12/17/2019: Adding an optimization here.  It is common to call sampleIndividuals() on a large subpopulation\n\t// to draw a single mate in a reproduction() callback.  It takes a long time to build the index vector below; let's\n\t// try optimizing that specific case by trying a few random individuals to see if we get lucky.  If we don't,\n\t// we'll drop through to the base case code, without having lost much time.  At a guess, I'm requiring a candidate\n\t// count of at least 30 since with a smaller size than that building the index vector won't hurt much anyway.\n\t// I'm limiting this to 20 tries, so we don't spend too much time on it; the ideal limit will of course depend on\n\t// the number of candidates versus the number of *valid* candidates, and there's no way to know.\n\tif ((sample_size == 1) && (candidate_count >= 30))\n\t{\n\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\n\t\tfor (int try_count = 0; try_count < 20; ++try_count)\n\t\t{\n\t\t\tint sample_index = (int)Eidos_rng_interval_uint32(rng_32, candidate_count) + first_candidate_index;\n\t\t\t\n\t\t\tif ((excluded_index != -1) && (sample_index >= excluded_index))\n\t\t\t\tsample_index++;\n\t\t\t\n\t\t\tIndividual *candidate = parent_individuals_[sample_index];\n\t\t\t\n\t\t\tif (tag_specified)\n\t\t\t{\n\t\t\t\tslim_usertag_t candidate_tag = candidate->tag_value_;\n\t\t\t\t\n\t\t\t\tif (candidate_tag == SLIM_TAG_UNSET_VALUE)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tag constraint was specified, but an individual in the subpopulation does not have a defined tag value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tif (candidate_tag != tag)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (migrant_specified && (candidate->migrant_ != migrant))\n\t\t\t\tcontinue;\n\t\t\tif (ageMin_specified && (candidate->age_ < ageMin))\n\t\t\t\tcontinue;\n\t\t\tif (ageMax_specified && (candidate->age_ > ageMax))\n\t\t\t\tcontinue;\n\t\t\tif (any_tagL_specified)\n\t\t\t{\n\t\t\t\tif (tagL0_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL0_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL0 constraint was specified, but an individual in the subpopulation does not have a defined tagL0 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL0_value_ != tagL0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL1_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL1_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL1 constraint was specified, but an individual in the subpopulation does not have a defined tagL1 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL1_value_ != tagL1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL2_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL2_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL2 constraint was specified, but an individual in the subpopulation does not have a defined tagL2 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL2_value_ != tagL2)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL3_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL3_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL3 constraint was specified, but an individual in the subpopulation does not have a defined tagL3 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL3_value_ != tagL3)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL4_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL4_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL4 constraint was specified, but an individual in the subpopulation does not have a defined tagL4 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL4_value_ != tagL4)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(parent_individuals_[sample_index], gSLiM_Individual_Class));\n\t\t}\n\t}\n\t\n\t// base case\n\t{\n\t\t// get indices of individuals; we sample from this vector and then look up the corresponding individual\n\t\t// see sample() for some discussion of this implementation\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Subpopulation::ExecuteMethod_sampleIndividuals(): usage of statics\");\n\t\t\n\t\tstatic int *index_buffer = nullptr;\n\t\tstatic int buffer_capacity = 0;\n\t\t\n\t\tif (last_candidate_index + 1 > buffer_capacity)\t\t// just make it big enough for last_candidate_index, not worth worrying\n\t\t{\n\t\t\tbuffer_capacity = (last_candidate_index + 1) * 2;\t\t// double whenever we go over capacity, to avoid reallocations\n\t\t\tif (index_buffer)\n\t\t\t\tfree(index_buffer);\n\t\t\tindex_buffer = (int *)malloc(buffer_capacity * sizeof(int));\t// no need to realloc, we don't need the old data\n\t\t\tif (!index_buffer)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tcandidate_count = 0;\t// we will count how many candidates we actually end up with\n\t\t\n\t\tif (!tag_specified && !ageMin_specified && !ageMax_specified && !migrant_specified && !any_tagL_specified)\n\t\t{\n\t\t\tif (excluded_index == -1)\n\t\t\t{\n\t\t\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t\t\t\tindex_buffer[candidate_count++] = value_index;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tif (value_index != excluded_index)\n\t\t\t\t\t\tindex_buffer[candidate_count++] = value_index;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t\t{\n\t\t\t\tIndividual *candidate = parent_individuals_[value_index];\n\t\t\t\t\n\t\t\t\tif (tag_specified)\n\t\t\t\t{\n\t\t\t\t\tslim_usertag_t candidate_tag = candidate->tag_value_;\n\t\t\t\t\t\n\t\t\t\t\tif (candidate_tag == SLIM_TAG_UNSET_VALUE)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tag constraint was specified, but an individual in the subpopulation does not have a defined tag value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tif (candidate_tag != tag)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (migrant_specified && (candidate->migrant_ != migrant))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (ageMin_specified && (candidate->age_ < ageMin))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (ageMax_specified && (candidate->age_ > ageMax))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (value_index == excluded_index)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (any_tagL_specified)\n\t\t\t\t{\n\t\t\t\t\tif (tagL0_specified)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!candidate->tagL0_set_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL0 constraint was specified, but an individual in the subpopulation does not have a defined tagL0 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\tif (candidate->tagL0_value_ != tagL0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (tagL1_specified)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!candidate->tagL1_set_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL1 constraint was specified, but an individual in the subpopulation does not have a defined tagL1 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\tif (candidate->tagL1_value_ != tagL1)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (tagL2_specified)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!candidate->tagL2_set_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL2 constraint was specified, but an individual in the subpopulation does not have a defined tagL2 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\tif (candidate->tagL2_value_ != tagL2)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (tagL3_specified)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!candidate->tagL3_set_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL3 constraint was specified, but an individual in the subpopulation does not have a defined tagL3 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\tif (candidate->tagL3_value_ != tagL3)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (tagL4_specified)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!candidate->tagL4_set_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): a tagL4 constraint was specified, but an individual in the subpopulation does not have a defined tagL4 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\tif (candidate->tagL4_value_ != tagL4)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindex_buffer[candidate_count++] = value_index;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (candidate_count == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\telse if (!replace && (candidate_count < sample_size))\n\t\t\tsample_size = candidate_count;\n\t\t\n\t\t// do the sampling\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get())->resize_no_initialize(sample_size);\n\t\tEidosObject **object_result_data = result->data_mutable();\n\t\t\n\t\tif (replace)\n\t\t{\n\t\t\t// base case with replacement\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_INDIVIDUALS_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size, index_buffer) firstprivate(candidate_count, object_result_data) if(sample_size >= EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_2) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(static)\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tint rose_index = (int)Eidos_rng_interval_uint32(rng_32, (uint32_t)candidate_count);\n\t\t\t\t\t\n\t\t\t\t\tobject_result_data[samples_generated] = parent_individuals_[index_buffer[rose_index]];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Retain all of the objects chosen; this is not done in parallel because it would require locks\n\t\t\t// This is dead code at the moment, because Individual does not use retain/release\n\t\t\tif (gSLiM_Individual_Class->UsesRetainRelease())\n\t\t\t{\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tEidosObject *object_element = object_result_data[samples_generated];\n\t\t\t\t\tstatic_cast<EidosDictionaryRetained *>(object_element)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// base case without replacement; this is not parallelized because of contention over index_buffer removals\n\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t{\n#if DEBUG\n\t\t\t// this error should never occur, since we checked the count above\n\t\t\tif (candidate_count <= 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_sampleIndividuals): (internal error) sampleIndividuals() ran out of eligible individuals from which to sample.\" << EidosTerminate(nullptr);\t\t// CODE COVERAGE: This is dead code\n#endif\n\t\t\t\n\t\t\t\tint rose_index = (int)Eidos_rng_interval_uint32(rng_32, (uint32_t)candidate_count);\n\t\t\t\t\n\t\t\t\tresult->set_object_element_no_check_NORR(parent_individuals_[index_buffer[rose_index]], samples_generated);\n\t\t\t\t\n\t\t\t\tindex_buffer[rose_index] = index_buffer[--candidate_count];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//  *********************\t– (object<Individual>)subsetIndividuals([No<Individual>$ exclude = NULL], [Ns$ sex = NULL], [Ni$ tag = NULL], [Ni$ minAge = NULL], [Ni$ maxAge = NULL], [Nl$ migrant = NULL], [Nl$ tagL0 = NULL], [Nl$ tagL1 = NULL], [Nl$ tagL2 = NULL], [Nl$ tagL3 = NULL], [Nl$ tagL4 = NULL])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_subsetIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// This method is patterned closely upon ExecuteMethod_sampleIndividuals(), but without the sampling aspect\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tint x_count = parent_subpop_size_;\n\t\n\tif (x_count == 0)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\t\n\t// a specific individual may be excluded\n\tEidosValue *exclude_value = p_arguments[0].get();\n\tIndividual *excluded_individual = nullptr;\n\tslim_popsize_t excluded_index = -1;\n\t\n\tif (exclude_value->Type() != EidosValueType::kValueNULL)\n\t\texcluded_individual = (Individual *)exclude_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tif (excluded_individual)\n\t{\n\t\t// SPECIES CONSISTENCY CHECK\n\t\tif (excluded_individual->subpopulation_ != this)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): the excluded individual must belong to the subpopulation being subset.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (excluded_individual->index_ == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): the excluded individual must be a valid, visible individual (not a newly generated child).\" << EidosTerminate(nullptr);\n\t\t\n\t\texcluded_index = excluded_individual->index_;\n\t}\n\t\n\t// a sex may be specified\n\tEidosValue *sex_value = p_arguments[1].get();\n\tIndividualSex sex = IndividualSex::kUnspecified;\n\t\n\tif (sex_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tconst std::string &sex_string = ((EidosValue_String *)sex_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (sex_string == \"M\")\t\t\tsex = IndividualSex::kMale;\n\t\telse if (sex_string == \"F\")\t\tsex = IndividualSex::kFemale;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): unrecognized value for sex in subsetIndividuals(); sex must be 'F', 'M', or NULL.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (!sex_enabled_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): sex must be NULL in non-sexual models.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// a tag value may be specified; if so, tag values must be defined for all individuals\n\tEidosValue *tag_value = p_arguments[2].get();\n\tbool tag_specified = (tag_value->Type() != EidosValueType::kValueNULL);\n\tslim_usertag_t tag = (tag_specified ? tag_value->IntAtIndex_NOCAST(0, nullptr) : 0);\n\t\n\t// an age min or max may be specified in nonWF models\n\tEidosValue *ageMin_value = p_arguments[3].get();\n\tEidosValue *ageMax_value = p_arguments[4].get();\n\tbool ageMin_specified = (ageMin_value->Type() != EidosValueType::kValueNULL);\n\tbool ageMax_specified = (ageMax_value->Type() != EidosValueType::kValueNULL);\n\tint64_t ageMin = (ageMin_specified ? ageMin_value->IntAtIndex_NOCAST(0, nullptr) : -1);\n\tint64_t ageMax = (ageMax_specified ? ageMax_value->IntAtIndex_NOCAST(0, nullptr) : INT64_MAX);\n\t\n\tif ((ageMin_specified || ageMax_specified) && (model_type_ != SLiMModelType::kModelTypeNonWF))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): ageMin and ageMax may only be specified in nonWF models.\" << EidosTerminate(nullptr);\n\t\n\t// a migrant value may be specified\n\tEidosValue *migrant_value = p_arguments[5].get();\n\tbool migrant_specified = (migrant_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t migrant = (migrant_specified ? migrant_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\t\n\t// logical tag values, tagL0 - tagL4, may be specified; if so, those tagL values must be defined for all individuals\n\tEidosValue *tagL0_value = p_arguments[6].get();\n\tbool tagL0_specified = (tagL0_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL0 = (tagL0_specified ? tagL0_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL1_value = p_arguments[7].get();\n\tbool tagL1_specified = (tagL1_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL1 = (tagL1_specified ? tagL1_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL2_value = p_arguments[8].get();\n\tbool tagL2_specified = (tagL2_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL2 = (tagL2_specified ? tagL2_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL3_value = p_arguments[9].get();\n\tbool tagL3_specified = (tagL3_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL3 = (tagL3_specified ? tagL3_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tEidosValue *tagL4_value = p_arguments[10].get();\n\tbool tagL4_specified = (tagL4_value->Type() != EidosValueType::kValueNULL);\n\teidos_logical_t tagL4 = (tagL4_specified ? tagL4_value->LogicalAtIndex_NOCAST(0, nullptr) : false);\n\tbool any_tagL_specified = (tagL0_specified || tagL1_specified || tagL2_specified || tagL3_specified || tagL4_specified);\n\t\n\t// determine the range the sample will be drawn from; this does not take into account tag, tagLX, or ageMin/ageMax\n\tint first_candidate_index, last_candidate_index, candidate_count;\n\t\n\tif (sex == IndividualSex::kUnspecified)\n\t{\n\t\tfirst_candidate_index = 0;\n\t\tlast_candidate_index = parent_subpop_size_ - 1;\n\t\tcandidate_count = parent_subpop_size_;\n\t}\n\telse if (sex == IndividualSex::kFemale)\n\t{\n\t\tfirst_candidate_index = 0;\n\t\tlast_candidate_index = parent_first_male_index_ - 1;\n\t\tcandidate_count = parent_first_male_index_;\n\t}\n\telse // if (sex == IndividualSex::kMale)\n\t{\n\t\tfirst_candidate_index = parent_first_male_index_;\n\t\tlast_candidate_index = parent_subpop_size_ - 1;\n\t\tcandidate_count = (last_candidate_index - first_candidate_index) + 1;\n\t}\n\t\n\tif ((excluded_index >= first_candidate_index) && (excluded_index <= last_candidate_index))\n\t\tcandidate_count--;\n\telse\n\t\texcluded_index = -1;\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_Individual_Class));\n\tEidosValue_Object *result = ((EidosValue_Object *)result_SP.get());\n\t\n\tif (!tag_specified && !ageMin_specified && !ageMax_specified && !migrant_specified && !any_tagL_specified)\n\t{\n\t\t// usually there will be no specifed tag/ageMin/ageMax/tagL, so handle it more quickly; reserve since we know the size within 1\n\t\tresult->reserve(candidate_count);\n\t\t\n\t\tif (excluded_index == -1)\n\t\t{\n\t\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t\t\tresult->push_object_element_no_check_NORR(parent_individuals_[value_index]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t\t{\n\t\t\t\tif (value_index == excluded_index)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tresult->push_object_element_no_check_NORR(parent_individuals_[value_index]);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// this is the full case, a bit slower; we might reject the large majority of individuals, so we don't reserve here\n\t\tfor (int value_index = first_candidate_index; value_index <= last_candidate_index; ++value_index)\n\t\t{\n\t\t\tIndividual *candidate = parent_individuals_[value_index];\n\t\t\t\n\t\t\tif (tag_specified)\n\t\t\t{\n\t\t\t\tslim_usertag_t candidate_tag = candidate->tag_value_;\n\t\t\t\t\n\t\t\t\tif (candidate_tag == SLIM_TAG_UNSET_VALUE)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tag constraint was specified, but an individual in the subpopulation does not have a defined tag value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tif (candidate_tag != tag)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (migrant_specified && (candidate->migrant_ != migrant))\n\t\t\t\tcontinue;\n\t\t\tif (ageMin_specified && (candidate->age_ < ageMin))\n\t\t\t\tcontinue;\n\t\t\tif (ageMax_specified && (candidate->age_ > ageMax))\n\t\t\t\tcontinue;\n\t\t\tif (value_index == excluded_index)\n\t\t\t\tcontinue;\n\t\t\tif (any_tagL_specified)\n\t\t\t{\n\t\t\t\tif (tagL0_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL0_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tagL0 constraint was specified, but an individual in the subpopulation does not have a defined tagL0 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL0_value_ != tagL0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL1_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL1_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tagL1 constraint was specified, but an individual in the subpopulation does not have a defined tagL1 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL1_value_ != tagL1)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL2_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL2_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tagL2 constraint was specified, but an individual in the subpopulation does not have a defined tagL2 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL2_value_ != tagL2)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL3_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL3_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tagL3 constraint was specified, but an individual in the subpopulation does not have a defined tagL3 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL3_value_ != tagL3)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (tagL4_specified)\n\t\t\t\t{\n\t\t\t\t\tif (!candidate->tagL4_set_)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_subsetIndividuals): a tagL4 constraint was specified, but an individual in the subpopulation does not have a defined tagL4 value, so that constraint cannot be applied.\" << EidosTerminate(nullptr);\n\t\t\t\t\tif (candidate->tagL4_value_ != tagL4)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tresult->push_object_element_capcheck_NORR(parent_individuals_[value_index]);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t– (object<SpatialMap>$)defineSpatialMap(string$ name, string$ spatiality, numeric values, [logical$ interpolate = F], [Nif valueRange = NULL], [Ns colors = NULL])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_defineSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_String *name_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_String *spatiality_value = (EidosValue_String *)p_arguments[1].get();\n\tEidosValue *values = p_arguments[2].get();\n\tEidosValue *interpolate_value = p_arguments[3].get();\n\tEidosValue *value_range = p_arguments[4].get();\n\tEidosValue *colors = p_arguments[5].get();\n\t\n\tconst std::string &map_name = name_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (map_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_defineSpatialMap): defineSpatialMap() map name must not be zero-length.\" << EidosTerminate();\n\t\n\tconst std::string &spatiality_string = spatiality_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tbool interpolate = interpolate_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// Make our SpatialMap object and populate it with the values provided\n\tSpatialMap *spatial_map = new SpatialMap(map_name, spatiality_string, this, values, interpolate, value_range, colors);\n\t\n\tif (!spatial_map->IsCompatibleWithSubpopulation(this))\n\t{\n\t\tspatial_map->Release();\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_defineSpatialMap): defineSpatialMap() requires the spatial map to be compatible with the target subpopulation; spatiality cannot utilize spatial dimensions beyond those set for the target species, and spatial bounds must match.\" << EidosTerminate();\n\t}\n\t\n\t// Add the new SpatialMap to our map for future reference\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\t// there is an existing entry under this name; remove it\n\t\tSpatialMap *old_map = map_iter->second;\n\t\t\n\t\tspatial_maps_.erase(map_iter);\n\t\told_map->Release();\n\t}\n\t\n\tspatial_maps_.emplace(map_name, spatial_map);\t// already retained by new SpatialMap(); that is the retain for spatial_maps_\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(spatial_map, gSLiM_SpatialMap_Class));\n}\n\n//\t*********************\t– (void)addSpatialMap(object<SpatialMap>$ map)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_addSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *map_value = (EidosValue *)p_arguments[0].get();\n\tSpatialMap *spatial_map = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tstd::string map_name = spatial_map->name_;\n\t\n\t// Check for an existing entry under this name; that is an error, unless it is the same spatial map object\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *old_map = map_iter->second;\n\t\t\n\t\tif (old_map == spatial_map)\n\t\t\treturn gStaticEidosValueVOID;\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSpatialMap): addSpatialMap() found an existing map of the same name ('\" << map_name << \"'); map names must be unique within each subpopulation.\" << EidosTerminate();\n\t}\n\t\n\t// Check the new spatial map's compatibility with ourselves\n\tif (!spatial_map->IsCompatibleWithSubpopulation(this))\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_addSpatialMap): addSpatialMap() requires the spatial map to be compatible with the target subpopulation in terms of spatiality/dimensionality and bounds.\" << EidosTerminate();\n\t\n\t// Add the new SpatialMap to our map for future reference\n\tspatial_map->Retain();\n\tspatial_maps_.emplace(map_name, spatial_map);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)removeSpatialMap(so<SpatialMap>$ map)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_removeSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *map_value = (EidosValue *)p_arguments[0].get();\n\t\n\tif (map_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tstd::string map_name = map_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tauto map_iter = spatial_maps_.find(map_name);\n\t\t\n\t\tif (map_iter != spatial_maps_.end())\n\t\t{\n\t\t\t// there is an existing entry under this name; remove it and we're done\n\t\t\tSpatialMap *old_map = map_iter->second;\n\t\t\t\n\t\t\tspatial_maps_.erase(map_iter);\n\t\t\told_map->Release();\n\t\t\t\n\t\t\treturn gStaticEidosValueVOID;\n\t\t}\n\t}\n\telse\n\t{\n\t\tSpatialMap *map = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tstd::string map_name = map->name_;\n\t\tauto map_iter = spatial_maps_.find(map_name);\n\t\t\n\t\tif (map_iter != spatial_maps_.end())\n\t\t{\n\t\t\t// there is an existing entry under this name; if it matches then we're done, if it doesn't, that's an error\n\t\t\tSpatialMap *found_map = map_iter->second;\n\t\t\t\n\t\t\tif (found_map == map)\n\t\t\t{\n\t\t\t\tspatial_maps_.erase(map_iter);\n\t\t\t\tmap->Release();\n\t\t\t\t\n\t\t\t\treturn gStaticEidosValueVOID;\n\t\t\t}\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_removeSpatialMap): removeSpatialMap() found a map of the same name, but it does not match the map requested for removal.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_removeSpatialMap): removeSpatialMap() did not find the map requested to be removed.\" << EidosTerminate();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (string)spatialMapColor(string$ name, numeric value)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_spatialMapColor(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_String *name_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &map_name = name_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (map_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapColor): spatialMapColor() map name must not be zero-length.\" << EidosTerminate();\n\t\n\t// Find the named SpatialMap\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *map = map_iter->second;\n\t\t\n\t\tif (!community_.warned_spatial_map_color_deprecated_ && !gEidosSuppressWarnings) {\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Subpopulation::ExecuteMethod_spatialMapColor): spatialMapColor() has been deprecated; use the SpatialMap method mapColor() instead.\" << std::endl;\n\t\t\tcommunity_.warned_spatial_map_color_deprecated_ = true;\n\t\t}\n\t\t\n\t\t// call out to SpatialMap::ExecuteMethod_mapValue() to do the work\n\t\tstd::vector<EidosValue_SP> subcall_args = {p_arguments[1]};\n\t\t\n\t\treturn map->ExecuteMethod_mapColor(p_method_id, subcall_args, p_interpreter);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapColor): spatialMapColor() could not find map with name \" << map_name << \".\" << EidosTerminate();\n}\n\n//\t(object<Image>$)spatialMapImage(string$ name, [Ni$ width = NULL], [Ni$ height = NULL], [logical$ centers = F], [logical$ color = T])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_spatialMapImage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_String *name_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &map_name = name_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (map_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapImage): spatialMapImage() map name must not be zero-length.\" << EidosTerminate();\n\t\n\t// Find the named SpatialMap\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *map = map_iter->second;\n\t\t\n\t\tif (!community_.warned_spatial_map_image_deprecated_ && !gEidosSuppressWarnings) {\n\t\t\tSLIM_ERRSTREAM << \"#WARNING (Subpopulation::ExecuteMethod_spatialMapImage): spatialMapImage() has been deprecated; use the SpatialMap method mapImage() instead.\" << std::endl;\n\t\t\tcommunity_.warned_spatial_map_image_deprecated_ = true;\n\t\t}\n\t\t\n\t\t// call out to SpatialMap::ExecuteMethod_mapValue() to do the work\n\t\tstd::vector<EidosValue_SP> subcall_args = {p_arguments[1], p_arguments[2], p_arguments[3], p_arguments[4]};\n\t\t\n\t\treturn map->ExecuteMethod_mapImage(p_method_id, subcall_args, p_interpreter);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapImage): spatialMapImage() could not find map with name \" << map_name << \".\" << EidosTerminate();\n}\n\n//\t*********************\t– (float)spatialMapValue(so<SpatialMap>$ map, float point)\n//\nEidosValue_SP Subpopulation::ExecuteMethod_spatialMapValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t// This method, unlike spatialMapColor() and spatialMapImage(), has not been deprecated.  The logic is this.\n\t// We want to un-clog the Subpopulation API, so specialized functionality of SpatialMap should not be mirrored\n\t// there.  However, spatialMapValue() is the core functionality, and it is a nice convenience to be able to\n\t// do it through Subpopulation without having to keep track of the SpatialMap object, just as was done before\n\t// SLiM 4.1.  In addition, using this API has some code safety benefits: the Subpopulation will check itself for\n\t// compatibility with the spatial map, and SLiMgui will display the spatial map correctly (which would not\n\t// be the case if it had not been added to the target subpopulation at all).  Nevertheless, the new SpatialMap\n\t// method -mapValue() is also available, and can be used instead of this.  This redundancy seems worthwhile.\n\tEidosValue *map_value = p_arguments[0].get();\n\tSpatialMap *map = nullptr;\n\tstd::string map_name;\n\t\n\tif (map_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tmap_name = ((EidosValue_String *)map_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (map_name.length() == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapValue): spatialMapValue() map name must not be zero-length.\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\tmap = (SpatialMap *)map_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\tmap_name = map->name_;\n\t}\n\t\n\t// Find the SpatialMap by name; we do this lookup even if a map object was supplied, to check that that map is present\n\tauto map_iter = spatial_maps_.find(map_name);\n\t\n\tif (map_iter != spatial_maps_.end())\n\t{\n\t\tSpatialMap *found_map = map_iter->second;\n\t\t\n\t\tif (map && (found_map != map))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapValue): spatialMapValue() could not find map in the target subpopulation (although it did find a different map with the same name).\" << EidosTerminate();\n\t\t\n\t\t// call out to SpatialMap::ExecuteMethod_mapValue() to do the work\n\t\tstd::vector<EidosValue_SP> subcall_args = {p_arguments[1]};\n\t\t\n\t\treturn found_map->ExecuteMethod_mapValue(p_method_id, subcall_args, p_interpreter);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_spatialMapValue): spatialMapValue() could not find map '\" << map_name << \"' in the target subpopulation.\" << EidosTerminate();\n}\n\n#undef SLiMClampCoordinate\n\n//\t*********************\t– (void)outputMSSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [Ns$ filePath = NULL], [logical$ append=F], [logical$ filterMonomorphic = F], [Niso<Chromosome>$ chromosome = NULL])\n//\t*********************\t– (void)outputSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [Ns$ filePath = NULL], [logical$ append=F], [Niso<Chromosome>$ chromosome = NULL])\n//\t*********************\t– (void)outputVCFSample(integer$ sampleSize, [logical$ replace = T], [string$ requestedSex = \"*\"], [logical$ outputMultiallelics = T], [Ns$ filePath = NULL], [logical$ append=F], [logical$ simplifyNucleotides = F], [logical$ outputNonnucleotides = T], [logical$ groupAsIndividuals = T], [Niso<Chromosome>$ chromosome = NULL])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_outputXSample(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *sampleSize_value = p_arguments[0].get();\n\tEidosValue *replace_value = p_arguments[1].get();\n\tEidosValue *requestedSex_value = p_arguments[2].get();\n\tEidosValue *outputMultiallelics_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[3].get() : nullptr);\n\tEidosValue *filePath_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[4].get() : p_arguments[3].get());\n\tEidosValue *append_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[5].get() : p_arguments[4].get());\n\tEidosValue *filterMonomorphic_arg = ((p_method_id == gID_outputMSSample) ? p_arguments[5].get() : nullptr);\n\tEidosValue *simplifyNucleotides_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[6].get() : nullptr);\n\tEidosValue *outputNonnucleotides_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[7].get() : nullptr);\n\tEidosValue *groupAsIndividuals_arg = ((p_method_id == gID_outputVCFSample) ? p_arguments[8].get() : nullptr);\n\tEidosValue *chromosome_arg;\n\t\n\tif (p_method_id == gID_outputMSSample)\n\t\tchromosome_arg = p_arguments[6].get();\n\telse if (p_method_id == gID_outputSample)\n\t\tchromosome_arg = p_arguments[5].get();\n\telse if (p_method_id == gID_outputVCFSample)\n\t\tchromosome_arg = p_arguments[9].get();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): (internal error) unrecognized method id.\" << EidosTerminate();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// TIMING RESTRICTION\n\tif (!community_.warned_early_output_)\n\t{\n\t\tif ((community_.CycleStage() == SLiMCycleStage::kWFStage0ExecuteFirstScripts) ||\n\t\t\t(community_.CycleStage() == SLiMCycleStage::kWFStage1ExecuteEarlyScripts))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t{\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Subpopulation::ExecuteMethod_outputXSample): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() should probably not be called from a first() or early() event in a WF model; the output will reflect state at the beginning of the cycle, not the end.\" << std::endl;\n\t\t\t\tcommunity_.warned_early_output_ = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tslim_popsize_t sample_size = SLiMCastToPopsizeTypeOrRaise(sampleSize_value->IntAtIndex_NOCAST(0, nullptr));\n\t\n\tbool replace = replace_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tIndividualSex requested_sex;\n\t\n\tstd::string sex_string = requestedSex_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sex_string.compare(\"M\") == 0)\n\t\trequested_sex = IndividualSex::kMale;\n\telse if (sex_string.compare(\"F\") == 0)\n\t\trequested_sex = IndividualSex::kFemale;\n\telse if (sex_string.compare(\"*\") == 0)\n\t\trequested_sex = IndividualSex::kUnspecified;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requested sex '\" << sex_string << \"' unsupported.\" << EidosTerminate();\n\t\n\tif (!species_.SexEnabled() && requested_sex != IndividualSex::kUnspecified)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() requested sex is not legal in a non-sexual simulation.\" << EidosTerminate();\n\t\n\tbool output_multiallelics = true;\n\t\n\tif (p_method_id == gID_outputVCFSample)\n\t\toutput_multiallelics = outputMultiallelics_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool simplify_nucs = false;\n\t\n\tif (p_method_id == gID_outputVCFSample)\n\t\tsimplify_nucs = simplifyNucleotides_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool output_nonnucs = true;\n\t\n\tif (p_method_id == gID_outputVCFSample)\n\t\toutput_nonnucs = outputNonnucleotides_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool group_as_individuals = true;\n\t\n\tif (p_method_id == gID_outputVCFSample)\n\t\tgroup_as_individuals = groupAsIndividuals_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tbool filter_monomorphic = false;\n\t\n\tif (p_method_id == gID_outputMSSample)\n\t\tfilter_monomorphic = filterMonomorphic_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// BCH 2/3/2025: in a multi-chromosome model we need to know which chromosome to sample with; the decision\n\t// is that the Subpopulation methods will probably be deprecated soon, and so porting them forward should\n\t// take the easiest path forward.  In their place I will add a new suite of output methods on Individual.\n\t// The Haplosome output methods will be for an arbitrary set of haplosomes, and will always be single-\n\t// chromosome; the Individual output methods will be for an arbitrary set of individuals, and will be able\n\t// to output one or all chromosomes as desired.  Then the Subpopulation methods are end-of-lifed because\n\t// the only value add they give is that they take the sample for you, and there are easy and good ways to\n\t// do that now yourself; so they would no longer be worth the API bloat, and would go away.  For consistency\n\t// I'm requiring a single chromosome for outputVCFSample() too, even though it samples individuals and thus\n\t// could support multiple chromosomes; best to consistently phase out the old and bring in the new.\n\tconst std::vector<Chromosome *> &chromosomes = species_.Chromosomes();\n\tChromosome *chromosome;\n\t\n\tif (chromosomes.size() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): output cannot be generated from a species with no genetics.\" << EidosTerminate();\n\t\n\tif (chromosome_arg->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tif (chromosomes.size() > 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): output requires a non-NULL value for chromosome in multi-chromosome models.\" << EidosTerminate();\n\t\t\n\t\tchromosome = chromosomes[0];\n\t}\n\telse\n\t{\n\t\t// NULL case handled above\n\t\tchromosome = species_.GetChromosomeFromEidosValue(chromosome_arg);\n\t}\n\t\n\t// Figure out the right output stream\n\tstd::ofstream outfile;\n\tbool has_file = false;\n\tstd::string outfile_path;\n\t\n\tif (filePath_arg->Type() != EidosValueType::kValueNULL)\n\t{\n\t\toutfile_path = Eidos_ResolvedPath(filePath_arg->StringAtIndex_NOCAST(0, nullptr));\n\t\tbool append = append_arg->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\toutfile.open(outfile_path.c_str(), append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\thas_file = true;\n\t\t\n\t\tif (!outfile.is_open())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_outputXSample): \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \"() could not open \"<< outfile_path << \".\" << EidosTerminate();\n\t}\n\telse\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t}\n\t\n\tstd::ostream &out = *(has_file ? dynamic_cast<std::ostream *>(&outfile) : dynamic_cast<std::ostream *>(&output_stream));\n\t\n\tif (!has_file || (p_method_id == gID_outputSample))\n\t{\n\t\t// Output header line.  BCH 3/6/2022: Note that the cycle was added after the tick in SLiM 4.\n\t\tout << \"#OUT: \" << community_.Tick() << \" \" << species_.Cycle() << \" S\";\n\t\t\n\t\tif (p_method_id == gID_outputSample)\n\t\t\tout << \"S\";\n\t\telse if (p_method_id == gID_outputMSSample)\n\t\t\tout << \"M\";\n\t\telse if (p_method_id == gID_outputVCFSample)\n\t\t\tout << \"V\";\n\t\t\n\t\tout << \" p\" << subpopulation_id_ << \" \" << sample_size;\n\t\t\n\t\tif (species_.SexEnabled())\n\t\t\tout << \" \" << requested_sex;\n\t\t\n\t\tif (chromosomes.size() > 1)\n\t\t{\n\t\t\toutput_stream << \" \" << chromosome->Type();\t\t\t\t\t\t// chromosome type, with >1 chromosome\n\t\t\toutput_stream << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\t\t\t// chromosome symbol, with >1 chromosome\n\t\t}\n\t\t\n\t\tif (has_file)\n\t\t\tout << \" \" << outfile_path;\n\t\t\n\t\tout << std::endl;\n\t}\n\t\n\t// Call out to produce the actual sample\n\tif (p_method_id == gID_outputSample)\n\t\tpopulation_.PrintSample_SLiM(out, *this, sample_size, replace, requested_sex, *chromosome);\n\telse if (p_method_id == gID_outputMSSample)\n\t\tpopulation_.PrintSample_MS(out, *this, sample_size, replace, requested_sex, *chromosome, filter_monomorphic);\n\telse if (p_method_id == gID_outputVCFSample)\n\t\tpopulation_.PrintSample_VCF(out, *this, sample_size, replace, requested_sex, *chromosome, output_multiallelics, simplify_nucs, output_nonnucs, group_as_individuals);\n\t\n\tif (has_file)\n\t\toutfile.close(); \n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (void)configureDisplay([Nf center = NULL], [Nf$ scale = NULL], [Ns$ color = NULL])\n//\nEidosValue_SP Subpopulation::ExecuteMethod_configureDisplay(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tEidosValue *center_value = p_arguments[0].get();\n\tEidosValue *scale_value = p_arguments[1].get();\n\tEidosValue *color_value = p_arguments[2].get();\n\t\n\t// This method doesn't actually do anything unless we're running under SLiMgui\n\t\n\tif (center_value->Type() == EidosValueType::kValueNULL)\n\t{\n#ifdef SLIMGUI\n\t\tgui_center_from_user_ = false;\n#endif\n\t}\n\telse\n\t{\n\t\tint center_count = center_value->Count();\n\t\t\n\t\tif (center_count != 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_configureDisplay): configureDisplay() requires that center be of exactly size 2 (x and y).\" << EidosTerminate();\n\t\t\n\t\tdouble x = center_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\tdouble y = center_value->FloatAtIndex_NOCAST(1, nullptr);\n\t\t\n\t\tif ((x < 0.0) || (x > 1.0) || (y < 0.0) || (y > 1.0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_configureDisplay): configureDisplay() requires that the specified center be within [0,1] for both x and y.\" << EidosTerminate();\n\t\t\n#ifdef SLIMGUI\n\t\tgui_center_x_ = x;\n\t\tgui_center_y_ = y;\n\t\tgui_center_from_user_ = true;\n#endif\n\t}\n\t\n\tif (scale_value->Type() == EidosValueType::kValueNULL)\n\t{\n#ifdef SLIMGUI\n\t\tgui_radius_scaling_from_user_ = false;\n#endif\n\t}\n\telse\n\t{\n\t\tdouble scale = scale_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((scale <= 0.0) || (scale > 5.0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::ExecuteMethod_configureDisplay): configureDisplay() requires that the specified scale be within (0,5].\" << EidosTerminate();\n\t\t\n#ifdef SLIMGUI\n\t\tgui_radius_scaling_ = scale;\n\t\tgui_radius_scaling_from_user_ = true;\n#endif\n\t}\n\t\n\tif (color_value->Type() == EidosValueType::kValueNULL)\n\t{\n#ifdef SLIMGUI\n\t\tgui_color_from_user_ = false;\n#endif\n\t}\n\telse\n\t{\n\t\tstd::string &&color = color_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (color.empty())\n\t\t{\n#ifdef SLIMGUI\n\t\t\tgui_color_from_user_ = false;\n#endif\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfloat color_red, color_green, color_blue;\n\t\t\t\n\t\t\tEidos_GetColorComponents(color, &color_red, &color_green, &color_blue);\n\t\t\t\n#ifdef SLIMGUI\n\t\t\tgui_color_red_ = color_red;\n\t\t\tgui_color_green_ = color_green;\n\t\t\tgui_color_blue_ = color_blue;\n\t\t\tgui_color_from_user_ = true;\n#endif\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tSubpopulation_Class\n//\n#pragma mark -\n#pragma mark Subpopulation_Class\n#pragma mark -\n\nEidosClass *gSLiM_Subpopulation_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Subpopulation_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Subpopulation_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Subpopulation::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_firstMaleIndex,\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Subpopulation::GetProperty_Accelerated_firstMaleIndex));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haplosomes,\t\t\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_haplosomesNonNull,\t\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Haplosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_individuals,\t\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_Individual_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_immigrantSubpopIDs,\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_immigrantSubpopFractions,\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_lifetimeReproductiveOutput,\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_lifetimeReproductiveOutputM,\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_lifetimeReproductiveOutputF,\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_name,\t\t\t\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_description,\t\t\t\t\tfalse,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_selfingRate,\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_cloningRate,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_sexRatio,\t\t\t\t\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatialBounds,\t\t\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_spatialMaps,\t\t\t\t\ttrue,\tkEidosValueMaskObject, gSLiM_SpatialMap_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_species,\t\t\t\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Species_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_individualCount,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Subpopulation::GetProperty_Accelerated_individualCount));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Subpopulation::GetProperty_Accelerated_tag)->DeclareAcceleratedSet(Subpopulation::SetProperty_Accelerated_tag));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_fitnessScaling,\t\t\t\t\tfalse,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Subpopulation::GetProperty_Accelerated_fitnessScaling)->DeclareAcceleratedSet(Subpopulation::SetProperty_Accelerated_fitnessScaling));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Subpopulation_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Subpopulation_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setMigrationRates, kEidosValueMaskVOID))->AddIntObject(\"sourceSubpops\", gSLiM_Subpopulation_Class)->AddNumeric(\"rates\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_haplosomesForChromosomes, kEidosValueMaskObject, gSLiM_Haplosome_Class))->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional, \"chromosomes\", gSLiM_Chromosome_Class, gStaticEidosValueNULL)->AddInt_OSN(\"index\", gStaticEidosValueNULL)->AddLogical_OS(\"includeNulls\", gStaticEidosValue_LogicalT));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_deviatePositions, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_N(\"individuals\", gSLiM_Individual_Class)->AddString_S(\"boundary\")->AddNumeric_S(gStr_maxDistance)->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_deviatePositionsWithMap, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_N(\"individuals\", gSLiM_Individual_Class)->AddString_S(\"boundary\")->AddArg(kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"map\", gSLiM_SpatialMap_Class)->AddNumeric_S(gStr_maxDistance)->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointDeviated, kEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddFloat(\"point\")->AddString_S(\"boundary\")->AddNumeric_S(gStr_maxDistance)->AddString_S(\"functionType\")->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointInBounds, kEidosValueMaskLogical))->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointReflected, kEidosValueMaskFloat))->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointStopped, kEidosValueMaskFloat))->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointPeriodic, kEidosValueMaskFloat))->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointUniform, kEidosValueMaskFloat))->AddInt_OS(gEidosStr_n, gStaticEidosValue_Integer1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_pointUniformWithMap, kEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddArg(kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"map\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setCloningRate, kEidosValueMaskVOID))->AddNumeric(\"rate\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSelfingRate, kEidosValueMaskVOID))->AddNumeric_S(\"rate\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSexRatio, kEidosValueMaskVOID))->AddFloat_S(\"sexRatio\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSpatialBounds, kEidosValueMaskVOID))->AddNumeric(\"bounds\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_setSubpopulationSize, kEidosValueMaskVOID))->AddInt_S(\"size\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addCloned, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_S(\"parent\", gSLiM_Individual_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddLogical_OS(\"defer\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addCrossed, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_S(\"parent1\", gSLiM_Individual_Class)->AddObject_S(\"parent2\", gSLiM_Individual_Class)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskOptional, \"sex\", nullptr, gStaticEidosValueNULL)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddLogical_OS(\"defer\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addEmpty, kEidosValueMaskObject, gSLiM_Individual_Class))->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskOptional, \"sex\", nullptr, gStaticEidosValueNULL)->AddLogical_OSN(\"haplosome1Null\", gStaticEidosValueNULL)->AddLogical_OSN(\"haplosome2Null\", gStaticEidosValueNULL)->AddInt_OS(\"count\", gStaticEidosValue_Integer1));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addMultiRecombinant, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_S(\"pattern\", gEidosDictionaryUnretained_Class)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskOptional, \"sex\", nullptr, gStaticEidosValueNULL)->AddObject_OSN(\"parent1\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddObject_OSN(\"parent2\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddLogical_OSN(\"randomizeStrands\", gStaticEidosValueNULL)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddLogical_OS(\"defer\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addRecombinant, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_SN(gStr_strand1, gSLiM_Haplosome_Class)->AddObject_SN(gStr_strand2, gSLiM_Haplosome_Class)->AddInt_N(gStr_breaks1)->AddObject_SN(gStr_strand3, gSLiM_Haplosome_Class)->AddObject_SN(gStr_strand4, gSLiM_Haplosome_Class)->AddInt_N(gStr_breaks2)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskFloat | kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskOptional, \"sex\", nullptr, gStaticEidosValueNULL)->AddObject_OSN(\"parent1\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddObject_OSN(\"parent2\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddLogical_OSN(\"randomizeStrands\", gStaticEidosValueNULL)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddLogical_OS(\"defer\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSelfed, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_S(\"parent\", gSLiM_Individual_Class)->AddInt_OS(\"count\", gStaticEidosValue_Integer1)->AddLogical_OS(\"defer\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_takeMigrants, kEidosValueMaskVOID))->AddObject(\"migrants\", gSLiM_Individual_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_removeSubpopulation, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_cachedFitness, kEidosValueMaskFloat))->AddInt_N(\"indices\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_sampleIndividuals, kEidosValueMaskObject, gSLiM_Individual_Class))->AddInt_S(\"size\")->AddLogical_OS(\"replace\", gStaticEidosValue_LogicalF)->AddObject_OSN(\"exclude\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddString_OSN(\"sex\", gStaticEidosValueNULL)->AddInt_OSN(\"tag\", gStaticEidosValueNULL)->AddInt_OSN(\"minAge\", gStaticEidosValueNULL)->AddInt_OSN(\"maxAge\", gStaticEidosValueNULL)->AddLogical_OSN(\"migrant\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL0\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL1\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL2\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL3\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL4\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_subsetIndividuals, kEidosValueMaskObject, gSLiM_Individual_Class))->AddObject_OSN(\"exclude\", gSLiM_Individual_Class, gStaticEidosValueNULL)->AddString_OSN(\"sex\", gStaticEidosValueNULL)->AddInt_OSN(\"tag\", gStaticEidosValueNULL)->AddInt_OSN(\"minAge\", gStaticEidosValueNULL)->AddInt_OSN(\"maxAge\", gStaticEidosValueNULL)->AddLogical_OSN(\"migrant\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL0\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL1\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL2\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL3\", gStaticEidosValueNULL)->AddLogical_OSN(\"tagL4\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_defineSpatialMap, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_SpatialMap_Class))->AddString_S(\"name\")->AddString_S(\"spatiality\")->AddNumeric(\"values\")->AddLogical_OS(gStr_interpolate, gStaticEidosValue_LogicalF)->AddNumeric_ON(\"valueRange\", gStaticEidosValueNULL)->AddString_ON(\"colors\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_addSpatialMap, kEidosValueMaskVOID, gSLiM_SpatialMap_Class))->AddObject_S(\"map\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_removeSpatialMap, kEidosValueMaskVOID, gSLiM_SpatialMap_Class))->AddArg(kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"map\", gSLiM_SpatialMap_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_spatialMapColor, kEidosValueMaskString))->AddString_S(\"name\")->AddNumeric(\"value\")->MarkDeprecated());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_spatialMapImage, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosImage_Class))->AddString_S(\"name\")->AddInt_OSN(gEidosStr_width, gStaticEidosValueNULL)->AddInt_OSN(gEidosStr_height, gStaticEidosValueNULL)->AddLogical_OS(\"centers\", gStaticEidosValue_LogicalF)->AddLogical_OS(gEidosStr_color, gStaticEidosValue_LogicalT)->MarkDeprecated());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_spatialMapValue, kEidosValueMaskFloat))->AddArg(kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskSingleton, \"map\", gSLiM_SpatialMap_Class)->AddFloat(\"point\"));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputMSSample, kEidosValueMaskVOID))->AddInt_S(\"sampleSize\")->AddLogical_OS(\"replace\", gStaticEidosValue_LogicalT)->AddString_OS(\"requestedSex\", gStaticEidosValue_StringAsterisk)->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"filterMonomorphic\", gStaticEidosValue_LogicalF)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputVCFSample, kEidosValueMaskVOID))->AddInt_S(\"sampleSize\")->AddLogical_OS(\"replace\", gStaticEidosValue_LogicalT)->AddString_OS(\"requestedSex\", gStaticEidosValue_StringAsterisk)->AddLogical_OS(\"outputMultiallelics\", gStaticEidosValue_LogicalT)->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"simplifyNucleotides\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"outputNonnucleotides\", gStaticEidosValue_LogicalT)->AddLogical_OS(\"groupAsIndividuals\", gStaticEidosValue_LogicalT)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_outputSample, kEidosValueMaskVOID))->AddInt_S(\"sampleSize\")->AddLogical_OS(\"replace\", gStaticEidosValue_LogicalT)->AddString_OS(\"requestedSex\", gStaticEidosValue_StringAsterisk)->AddString_OSN(gEidosStr_filePath, gStaticEidosValueNULL)->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"chromosome\", gSLiM_Chromosome_Class, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_configureDisplay, kEidosValueMaskVOID))->AddFloat_ON(\"center\", gStaticEidosValueNULL)->AddFloat_OSN(\"scale\", gStaticEidosValueNULL)->AddString_OSN(gEidosStr_color, gStaticEidosValueNULL));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/subpopulation.h",
    "content": "//\n//  subpopulation.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Subpopulation represents one simulated subpopulation, defined primarily by the individuals it contains and their haplosomes.\n A subpopulation also knows its size, its selfing fraction, and what fraction it receives as migrants from other subpopulations.\n \n The way that Subpopulation handles its Haplosome objects is quite complex, and is at the heart of the operation of the SLiM core,\n so a lengthy comment on it is merited.  Haplosomes contain MutationRuns, and they can allocate a buffer in which they keep pointers\n to those runs.  Allocating and deallocating those buffers takes time, and so is to be avoided; for this reason, Subpopulation\n re-uses Haplosome objects.  When a Haplosome is done being used, it goes into a \"junkyard\" vector (which one depends on whether it is\n a null haplosome or not); FreeHaplosome() handles that.  When a new haplosome is needed, it is preferentially obtained from the\n appropriate junkyard, and is re-purposed to its new use; NewHaplosome() handles that.  Those methods should be called to\n handle most create/dispose requests for Haplosomes, so that those junkyard vectors get used.  When NewHaplosome() finds the\n junkyard to be empty, it needs to actually allocate a new Haplosome object.  This is also complicated.  Haplosomes are allocated out\n of a memory pool, haplosome_pool_, that belongs to the species.  This helps with memory locality; it keeps all of the Haplosome\n objects used by a given species grouped closely together in memory.  (We do the same with Individual objects, with another\n pool, for the same reason).  So allocations of Haplosomes come out of that pool, and deallocations go back into the pool.  Do not\n use new or delete with Haplosome objects.  There is one more complication.  In WF models, separate \"parent\" and \"child\" generations\n are kept by the subpop, and which one is active switches back and forth in each cycle, governed by child_generation_valid_.\n In nonWF models, the child generation variables are all unused; in nonWF models, the parental generation is always active.\n New offspring instead get put into the nonWF_offspring_ ivars, which get moved into the parental generation ivars at the end of\n offspring generation.  So in some ways these schemes are similar, but they use a completely non-intersecting set of ivars.  The\n parental ivars are used by both WF and nonWF models, though.\n \n BCH 10/19/2024: Note that haplosomes are now associated with a particular Chromosome object; each chromosome might use a different\n number of mutation runs, so for efficiency we want to keep the haplosome junkyards for different chromosomes separate.  Each\n chromosome therefore now has its own haplosome junkyard, and NewHaplosome_NULL(), NewHaplosome_NONNULL(), and FreeHaplosome()\n are now Chromosome methods that work with the target chromosome's junkyard.\n \n */\n\n#ifndef __SLiM__subpopulation__\n#define __SLiM__subpopulation__\n\n\n#include \"slim_globals.h\"\n#include \"eidos_rng.h\"\n#include \"haplosome.h\"\n#include \"chromosome.h\"\n#include \"eidos_value.h\"\n#include \"slim_eidos_block.h\"\n#include \"individual.h\"\n#include \"population.h\"\n#include \"species.h\"\n#include \"spatial_map.h\"\n\n#include <vector>\n#include <map>\n#include <limits.h>\n\n\nclass Population;\n\n\nextern EidosClass *gSLiM_Subpopulation_Class;\n\ntypedef std::pair<std::string, SpatialMap *> SpatialMapPair;\ntypedef std::map<std::string, SpatialMap *> SpatialMapMap;\n\n\n#pragma mark -\n#pragma mark Subpopulation\n#pragma mark -\n\nclass Subpopulation : public EidosDictionaryUnretained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\t\n\t// WF only:\n\tgsl_ran_discrete_t *lookup_parent_ = nullptr;\t\t\t// OWNED POINTER: lookup table for drawing a parent based upon fitness\n\tgsl_ran_discrete_t *lookup_female_parent_ = nullptr;\t// OWNED POINTER: lookup table for drawing a female parent based upon fitness, SEX ONLY\n\tgsl_ran_discrete_t *lookup_male_parent_ = nullptr;\t\t// OWNED POINTER: lookup table for drawing a male parent based upon fitness, SEX ONLY\n\t\n\tEidosSymbolTableEntry self_symbol_;\t\t\t\t\t\t// for fast setup of the symbol table\n\t\npublic:\n\t\n\tCommunity &community_;\n\tSpecies &species_;\n\tPopulation &population_;\n\tSLiMModelType model_type_;\n\t\n\tslim_objectid_t subpopulation_id_;\t\t\t\t// the id by which this subpopulation is indexed in the Population\n\tEidosValue_SP cached_value_subpop_id_;\t\t\t// a cached value for subpopulation_id_; reset() if changed\n\tbool has_been_removed_ = false;\t\t\t\t\t// a flag set to true when the subpop is removed and should no longer be used\n\t\n\tstd::string name_;\t\t\t\t\t\t\t\t// the `name` property; \"p1\", \"p2\", etc. by default, following the Eidos self-symbol\n\tstd::string description_;\t\t\t\t\t\t// the `description` property; the empty string by default\n\t\n\t// WF only:\n\tdouble selfing_fraction_ = 0.0;\t\t\t\t\t// ASEX ONLY: selfing fraction, the fraction of offspring generated by self-fertilization\n\tdouble female_clone_fraction_ = 0.0;\t\t\t// both asex and sex; in the asex case, male_clone_fraction_ == female_clone_fraction_ and is simply the clonal fraction\n\tdouble male_clone_fraction_ = 0.0;\t\t\t\t//\t\tthese represent the fraction of offspring generated by asexual clonal reproduction\n\tstd::map<slim_objectid_t,double> migrant_fractions_;\t\t// m[i]: fraction made up of migrants from subpopulation i per cycle\n\t\n\tEidosObjectPool &individual_pool_;\t\t\t\t// NOT OWNED: a pool out of which individuals are allocated, for within-species locality of memory usage across individuals\n\tstd::vector<Individual *> &individuals_junkyard_;\t// NOT OWNED: individuals get put here when we're done with them, so we can reuse them quickly\n\t\n\tint haplosome_count_per_individual_;\t\t\t\t\t// inherits its value from species_.haplosome_count_per_individual_\n\tbool has_null_haplosomes_ = false;\t\t\t\t\t// inherits its value from species_.chromosomes_use_null_haplosomes_ but can additionally be true; use CouldContainNullHaplosomes() to check this flag\n\t\n\tslim_popsize_t parent_subpop_size_;\t\t\t\t// parental subpopulation size\n\tslim_popsize_t parent_first_male_index_ = INT_MAX;\t// the index of the first male in the parental Haplosome vector (NOT premultiplied by 2!); equal to the number of females\n\tstd::vector<Individual *> parent_individuals_;\t// OWNED: objects representing simulated individuals, each of which has two haplosomes\n\tEidosValue_SP cached_parent_individuals_value_;\t// cached for the individuals property; self-maintains\n\tdouble parent_sex_ratio_ = 0.0;\t\t\t\t\t// WF only: what sex ratio the parent individuals approximate (M:M+F)\n\t\n\t// WF only:\n\t// In WF models, we actually switch to a \"child\" generation just after offspring generation; this is then the active generation.\n\t// Then, with SwapChildAndParentHaplosomes(), the child generation gets swapped into the parent generation, which becomes active.\n\t// I'm not sure this is a great design really, but it's pretty entrenched at this point, and pretty harmless...\n\tslim_popsize_t child_subpop_size_;\t\t\t\t// child subpopulation size\n\tslim_popsize_t child_first_male_index_ = INT_MAX;\t// the index of the first male in the child Haplosome vector (NOT premultiplied by 2!); equal to the number of females\n\tstd::vector<Individual *> child_individuals_;\t// OWNED: objects representing simulated individuals, each of which has two haplosomes\n\tdouble child_sex_ratio_ = 0.0;\t\t\t\t\t// what sex ratio the child individuals approximate (M:M+F)\n\t\n\t// nonWF only:\n\t// In nonWF models, we place generated offspring into a temporary holding pen, but it is never made the \"active generation\"\n\t// the way it is in WF models.  At soon as offspring generation is finished, these individuals get merged back in.  The\n\t// individuals here are kept in the order in which they were generated, not in order by sex or anything else.\n\tstd::vector<Individual *> nonWF_offspring_individuals_;\n\t\n\t// nonWF only:\n\t// In nonWF models, survival() callbacks can move individuals to new subpopulations.  These individuals are kept in a\n\t// temporary holding pen, similar to how newly generated individuals are kept.  They are moved after all survival()\n\t// callbacks have finished.  The difference, compared to reproduction, is that the individuals in this holding pen\n\t// already belong to a subpopulation; they are not removed until they get moved to their new destination.\n\tstd::vector<Individual *> nonWF_survival_moved_individuals_;\n\t\n\t// the lifetime reproductive output of all individuals that died in the last mortality event; cleared each cycle\n\tstd::vector<int32_t> lifetime_reproductive_output_MH_;\t\t// males / hermaphrodites\n\tstd::vector<int32_t> lifetime_reproductive_output_F_;\t\t// females\n\t\n\tstd::vector<SLiMEidosBlock*> registered_mate_choice_callbacks_;\t\t// WF only; NOT OWNED: valid only during EvolveSubpopulation; callbacks used when this subpop is parental\n\tstd::vector<SLiMEidosBlock*> registered_modify_child_callbacks_;\t// NOT OWNED: valid only during EvolveSubpopulation; callbacks used when this subpop is parental\n\tstd::vector<SLiMEidosBlock*> registered_recombination_callbacks_;\t// NOT OWNED: valid only during EvolveSubpopulation; callbacks used when this subpop is parental\n\tstd::vector<SLiMEidosBlock*> registered_mutation_callbacks_;\t\t// NOT OWNED: valid only during EvolveSubpopulation; callbacks used when this subpop is parental\n\tstd::vector<SLiMEidosBlock*> registered_reproduction_callbacks_;\t// nonWF only; NOT OWNED: valid only during EvolveSubpopulation; callbacks used when this subpop is parental\n\t\n\t// WF only:\n\t// Fitness caching.  Every individual now caches its fitness internally, and that is what is used by SLiMgui and by the cachedFitness() method of Subpopulation.\n\t// These fitness cache buffers are additional to that, used only in WF models.  They are used for two things.  First, as the data source for setting up our lookup\n\t// objects for drawing mates by fitness; the GSL wants that data to be in the form of a single buffer.  And second, by mateChoice() callbacks, which throw around\n\t// vectors of weights, and want to have default weight vectors for the non-sex and sex cases.  In nonWF models these buffers are not used, and not even set up.\n\t// In WF models we could continue to use these buffers for all uses (i.e., SLiMgui and cachedFitness()), but to keep the code simple it seems better to use the\n\t// caches in Individual for both WF and nonWF models where possible.\n\tdouble *cached_parental_fitness_ = nullptr;\t\t// OWNED POINTER: cached in UpdateFitness()\n\tdouble *cached_male_fitness_ = nullptr;\t\t\t// OWNED POINTER: SEX ONLY: same as cached_parental_fitness_ but with 0 for all females\n\tslim_popsize_t cached_fitness_size_ = 0;\t\t// the size (number of entries used) of cached_parental_fitness_ and cached_male_fitness_\n\tslim_popsize_t cached_fitness_capacity_ = 0;\t// the capacity of the malloced buffers cached_parental_fitness_ and cached_male_fitness_\n\t\n\t// WF only:\n\t// Optimized fitness caching at the Individual level.  Individual has an ivar named cached_fitness_UNSAFE_ that keeps a cached fitness value for each individual.\n\t// When a model is neutral or nearly neutral, every individual may have the same fitness value, and we may know that.  In such cases, we want to avoid setting\n\t// up the cached fitness value in each individual; instead, we set a flag here that overrides cached_fitness_UNSAFE_ and says it has the same value for all.\n\t// This happens only for the parental generation's cached fitness values (cached fitness values for the child generation should never be accessed by anyone\n\t// since they are not valid).  And it happens only in WF models, since in nonWF models the generational overlap makes this scheme impossible.  A somewhat special\n\t// case, then, but it seems worthwhile since the penalty for seting every cached fitness value, and then gathering them back up again in UpdateWFFitnessBuffers(),\n\t// is large – almost 20% of total runtime for the full Gravel model, for example.  Neutral WF models are common and worth special-casing.\n\tbool individual_cached_fitness_OVERRIDE_ = false;\n\tdouble individual_cached_fitness_OVERRIDE_value_;\n\t\n\t// SEX ONLY; the default values here are for the non-sex case\n\tbool sex_enabled_ = false;\t\t\t\t\t\t\t\t\t\t// the subpopulation needs to have easy reference to whether its individuals are sexual or not\n\t\n\t// continuous-space info\n\tdouble bounds_x0_ = 0.0, bounds_x1_ = 1.0;\n\tdouble bounds_y0_ = 0.0, bounds_y1_ = 1.0;\n\tdouble bounds_z0_ = 0.0, bounds_z1_ = 1.0;\n\tSpatialMapMap spatial_maps_;\t\t\t\t\t\t// the SpatialMap objects in this are retained!\n\t\n\tslim_usertag_t tag_value_ = SLIM_TAG_UNSET_VALUE;\t// a user-defined tag value\n\t\n\tdouble subpop_fitness_scaling_ = 1.0;\t\t\t\t// the fitnessScaling property value\n\t\n#ifdef SLIMGUI\n\tbool gui_selected_ = false;\t\t\t\t\t\t\t// keeps track of whether we are selected in SLiMgui's table of subpopulations\n\tdouble parental_mean_unscaled_fitness_ = 0.0;\t\t// updated in SurveyPopulation() when running under SLiMgui\n\t\n\tbool gui_center_from_user_ = false;\t\t\t\t\t// if this flag is true, the center below comes from the user and should not be modified\n\tdouble gui_center_x_, gui_center_y_;\t\t\t\t// the center used by GraphView_PopulationVisualization\n\t\n\tbool gui_radius_scaling_from_user_ = false;\t\t\t// if this flag is true, the radius scaling below comes from the user and should not be modified\n\tdouble gui_radius_scaling_;\t\t\t\t\t\t\t// set/used only when gui_display_from_user_ is true; a scaling factor for the circle size\n\tdouble gui_radius_;\t\t\t\t\t\t\t\t\t// the radius, post-scaling, used by GraphView_PopulationVisualization\n\t\n\tbool gui_color_from_user_ = false;\t\t\t\t\t// if this flag is true, the color below comes from the user and should not be modified\n\tfloat gui_color_red_, gui_color_green_, gui_color_blue_;\t// the color components, used by GraphView_PopulationVisualization\n#endif\n\t\n#if defined(SLIMGUI)\n\t// nonWF only:\n\t// these counters track generated offspring of different types, in nonWF models\n\tint64_t gui_offspring_cloned_M_ = 0;\n\tint64_t gui_offspring_cloned_F_ = 0;\n\tint64_t gui_offspring_selfed_ = 0;\n\tint64_t gui_offspring_crossed_ = 0;\n\tint64_t gui_offspring_empty_ = 0;\n\t\n\t// these track migrants out to us from other subpopulations, in nonWF models\n\tdouble gui_premigration_size_ = 0;\t\t\t\t\t// the size of this subpop without migration\n\tstd::map<slim_objectid_t,double> gui_migrants_;\t\t// m[i]: count of migrants from subpopulation i in this cycle\n#endif\t// defined(SLIMGUI)\n\t\n\tSubpopulation(const Subpopulation&) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tSubpopulation& operator=(const Subpopulation&) = delete;\t\t\t\t\t\t\t\t\t\t// no copying\n\tSubpopulation(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tSubpopulation(Population &p_population, slim_objectid_t p_subpopulation_id, slim_popsize_t p_subpop_size, bool p_record_in_treeseq, bool p_haploid);\n\tSubpopulation(Population &p_population, slim_objectid_t p_subpopulation_id, slim_popsize_t p_subpop_size, bool p_record_in_treeseq,\n\t\t\t\t  double p_sex_ratio, bool p_haploid);\t\t// SEX ONLY: construct with a sex ratio (fraction male)\n\t~Subpopulation(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\tvoid SetName(const std::string &p_name);\t\t\t\t\t\t\t\t\t\t\t\t// change the name property of the subpopulation, handling the uniqueness logic\n\t\n\tinline __attribute__((always_inline)) int HaplosomeCountPerIndividual(void) { return haplosome_count_per_individual_; }\n\tslim_refcount_t NullHaplosomeCount(void);\n\tinline bool CouldContainNullHaplosomes(void) {\n#if DEBUG\n\t\t// in DEBUG, check that has_null_haplosomes_ is not false when null haplosomes in fact exist (we allow the opposite case)\n\t\tif (!has_null_haplosomes_ && (NullHaplosomeCount() > 0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::CouldContainNullHaplosomes): (internal error) has_null_haplosomes_ is not correct.\" << EidosTerminate();\n#endif\n\t\treturn has_null_haplosomes_;\n\t}\n\t\n\tslim_popsize_t DrawParentUsingFitness(Eidos_RNG_State *rng_state) const;\t\t\t\t// WF only: draw an individual from the subpopulation based upon fitness\n\tslim_popsize_t DrawFemaleParentUsingFitness(Eidos_RNG_State *rng_state) const;\t\t\t// WF only: draw a female from the subpopulation based upon fitness; SEX ONLY\n\tslim_popsize_t DrawMaleParentUsingFitness(Eidos_RNG_State *rng_state) const;\t\t\t// WF only: draw a male from the subpopulation based upon fitness; SEX ONLY\n\n\tslim_popsize_t DrawParentEqualProbability(EidosRNG_32_bit &rng_32) const;\t\t\t\t// draw an individual from the subpopulation with equal probabilities\n\tslim_popsize_t DrawFemaleParentEqualProbability(EidosRNG_32_bit &rng_32) const;\t\t\t// draw a female from the subpopulation  with equal probabilities; SEX ONLY\n\tslim_popsize_t DrawMaleParentEqualProbability(EidosRNG_32_bit &rng_32) const;\t\t\t// draw a male from the subpopulation  with equal probabilities; SEX ONLY\n\t\n\tinline __attribute__((always_inline)) Individual *NewSubpopIndividual(slim_popsize_t p_individual_index, IndividualSex p_sex, slim_age_t p_age, double p_fitness, float p_mean_parent_age)\n\t{\n\t\tif (individuals_junkyard_.size())\n\t\t{\n\t\t\tIndividual *back = individuals_junkyard_.back();\n\t\t\tindividuals_junkyard_.pop_back();\n\t\t\t\n#if DEBUG\n\t\t\t// check all ivars that should be guaranteed by the junkyard\n\t\t\tif ((back->KeyCount() != 0) || (back->tag_value_ != SLIM_TAG_UNSET_VALUE) || (back->tagF_value_ != SLIM_TAGF_UNSET_VALUE) || (back->tagL0_set_ != false) || (back->tagL1_set_ != false) || (back->tagL2_set_ != false) || (back->tagL3_set_ != false) || (back->tagL4_set_ != false) || (back->reproductive_output_ != 0)\n#ifdef SLIMGUI\n\t\t\t\t// BCH 3/23/2025: color variables now only exist in SLiMgui, to save on memory footprint\n\t\t\t\t|| (back->color_set_ != false)\n#endif\t\t\t\t\n\t\t\t\t)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::NewSubpopIndividual): (internal error) junkyard individual incorrectly configured.\" << EidosTerminate();\n#endif\n\t\t\t\n#if DEBUG\n\t\t\t// set up our haplosomes vector with nullptr values initially, when in DEBUG\n\t\t\tEIDOS_BZERO(back->haplosomes_, haplosome_count_per_individual_ * sizeof(Haplosome *));\n#endif\n\t\t\t\n\t\t\t// set all ivars that are not guaranteed by the junkyard; see FreeSubpopIndividual()\n\t\t\t// note that we do not reset the pedigree ivars anywhere; they should be overwritten if\n\t\t\t// pedigree tracking is enabled, otherwise they will be left as -1 since they are unused\n\t\t\tback->mean_parent_age_ = p_mean_parent_age;\n\t\t\tback->sex_ = p_sex;\n\t\t\tback->migrant_ = false;\n\t\t\tback->killed_ = false;\n\t\t\tback->fitness_scaling_ = 1.0;\n\t\t\tback->cached_fitness_UNSAFE_ = p_fitness;\n#ifdef SLIMGUI\n\t\t\tback->cached_unscaled_fitness_ = p_fitness;\n#endif\n\t\t\tback->age_ = p_age;\n\t\t\tback->index_ = p_individual_index;\n\t\t\tback->subpopulation_ = this;\n\t\t\treturn back;\n\t\t}\n\t\t\n\t\treturn  new (individual_pool_.AllocateChunk()) Individual(this, p_individual_index, p_sex, p_age, p_fitness, p_mean_parent_age);\n\t}\n\t\n\tinline __attribute__((always_inline)) void FreeSubpopIndividual(Individual *p_individual)\n\t{\n\t\t// The individuals junkyard guarantees certain things, since it can sometimes do so efficiently.\n\t\t// This is based on what can be reset efficiently in WF models in Subpopulation::SwapChildAndParentHaplosomes(),\n\t\t// which performs these resets itself as needed (and GenerateChildrenToFitWF() then returns individuals to the\n\t\t// junkyard directly with _FreeSubpopIndividual(), avoiding these state resets).\n\t\tp_individual->RemoveAllKeys();\t// no call to ContentsChanged() here, for speed; we know individual is a Dictionary not a DataFrame\n\t\tp_individual->ClearColor();\n\t\tp_individual->tag_value_ = SLIM_TAG_UNSET_VALUE;\n\t\tp_individual->tagF_value_ = SLIM_TAGF_UNSET_VALUE;\n\t\tp_individual->tagL0_set_ = false;\n\t\tp_individual->tagL1_set_ = false;\n\t\tp_individual->tagL2_set_ = false;\n\t\tp_individual->tagL3_set_ = false;\n\t\tp_individual->tagL4_set_ = false;\n\t\tp_individual->reproductive_output_ = 0;\n\t\t\n\t\t_FreeSubpopIndividual(p_individual);\n\t}\n\tinline __attribute__((always_inline)) void _FreeSubpopIndividual(Individual *p_individual)\n\t{\n#if 0\n\t\t// To avoid using the junkvard and debug problems with it, just enable this block.\n\t\tindividual->~Individual();\n\t\tpopulation_.species_individual_pool_.DisposeChunk(const_cast<Individual *>(individual));\n\t\treturn;\n#endif\n\t\t\n\t\t// This returns an individual to the junkyard directly; the caller is responsible for\n\t\t// resetting all of the state the junkyard guarantees; see FreeSubpopIndividual().\n\t\t// The only thing we reset here is haplosomes_, since we want to free up those\n\t\t// resources immediately in all code paths.\n\t\tconst std::vector<Chromosome *> &chromosome_for_haplosome_index = species_.ChromosomesForHaplosomeIndices();\n\t\tint haplosome_count = haplosome_count_per_individual_;\n\t\tHaplosome **haplosomes = p_individual->haplosomes_;\n\t\t\n\t\tfor (int haplosome_index = 0; haplosome_index < haplosome_count; haplosome_index++)\n\t\t{\n\t\t\tHaplosome *haplosome = haplosomes[haplosome_index];\n\t\t\tChromosome *chromosome = chromosome_for_haplosome_index[haplosome_index];\n\t\t\t\n\t\t\tchromosome->FreeHaplosome(haplosome);\n\t\t}\n\t\t\n\t\t// Clear our haplosomes vector with nullptr values.  This is perhaps not strictly necessary,\n\t\t// since the nullptr for subpopulation_ set below would already indicate that the individual\n\t\t// is no longer valid and its haplosomes have been freed; but it seems wise to clean up\n\t\t// here to prevent the possibility of access to stale haplosomes.  This is one cleanup that\n\t\t// should not be done only in DEBUG, I think; the risk of logic errors with this is too high.\n\t\tEIDOS_BZERO(p_individual->haplosomes_, haplosome_count_per_individual_ * sizeof(Haplosome *));\n\t\t\n\t\t// The individual needs to be detached from its subpopulation, since the subpopulation\n\t\t// might get freed while the individual is still in the junkyard.  This means it\n\t\t// will not be able to access things through the subpopulation any more; but since\n\t\t// its haplosomes have already been freed, above, that ought to be OK.\n\t\tp_individual->subpopulation_ = nullptr;\n\t\t\n\t\tindividuals_junkyard_.emplace_back(p_individual);\n\t}\n\t\n\tvoid GenerateParentsToFit(slim_age_t p_initial_age, double p_sex_ratio, bool p_allow_zero_size, bool p_require_both_sexes, bool p_record_in_treeseq, bool p_haploid, float p_mean_parent_age);\t// given the set subpop size and requested sex ratio, make new haplosomes and individuals to fit\n\tvoid CheckIndividualIntegrity(void);\n\t\n#if (defined(_OPENMP) && SLIM_USE_NONNEUTRAL_CACHES)\n\tvoid FixNonNeutralCaches_OMP(void);\n#endif\n\tvoid UpdateFitness(std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks, std::vector<SLiMEidosBlock*> &p_fitnessEffect_callbacks);\t// update fitness values based upon current mutations\n\n\t// calculate the fitness of a given individual; the x dominance coeff is used only if the X is modeled\n\ttemplate <const bool f_mutrunexps, const bool f_callbacks, const bool f_singlecallback>\n\tdouble FitnessOfParent(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\tdouble FitnessOfParent_1CH_Diploid(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\tdouble FitnessOfParent_1CH_Haploid(slim_popsize_t p_individual_index, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\t\n\ttemplate <const bool f_callbacks, const bool f_singlecallback>\n\tdouble _Fitness_HaploidChromosome(Haplosome *haplosome, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\ttemplate <const bool f_callbacks, const bool f_singlecallback>\n\tdouble _Fitness_DiploidChromosome(Haplosome *haplosome1, Haplosome *haplosome2, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks);\n\t\n\tdouble ApplyMutationEffectCallbacks(MutationIndex p_mutation, int p_homozygous, double p_computed_fitness, std::vector<SLiMEidosBlock*> &p_mutationEffect_callbacks, Individual *p_individual);\n\tdouble ApplyFitnessEffectCallbacks(std::vector<SLiMEidosBlock*> &p_fitnessEffect_callbacks, slim_popsize_t p_individual_index);\n\t\n\t// generate newly allocated offspring individuals from parent individuals; these methods loop over\n\t// chromosomes/haplosomes, and are templated for speed, providing a set of optimized variants\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tIndividual *GenerateIndividualCrossed(Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\t\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tIndividual *GenerateIndividualSelfed(Individual *p_parent);\n\t\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tIndividual *GenerateIndividualCloned(Individual *p_parent);\n\t\n\tIndividual *GenerateIndividualEmpty(slim_popsize_t p_individual_index, IndividualSex p_child_sex, slim_age_t p_age, double p_fitness, float p_mean_parent_age, bool p_haplosome1_null, bool p_haplosome2_null, bool p_run_modify_child, bool p_record_in_treeseq);\n\t\n\t// these WF-only \"munge\" variants munge an existing individual into the new child, reusing the individual\n\t// and its haplosome objects; they are all templated for speed, providing variants for different milieux\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tbool MungeIndividualCrossed(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\t\n\ttemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\n\tbool MungeIndividualCrossed_1CH_A(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\t\n\ttemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\n\tbool MungeIndividualCrossed_1CH_H(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent1, Individual *p_parent2, IndividualSex p_child_sex);\n\t\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tbool MungeIndividualSelfed(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\t\n\ttemplate <const bool f_mutrunexps, const bool f_pedigree_rec, const bool f_treeseq, const bool f_callbacks, const bool f_spatial>\n\tbool MungeIndividualCloned(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\t\n\ttemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\n\tbool MungeIndividualCloned_1CH_A(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\t\n\ttemplate <const bool f_pedigree_rec, const bool f_treeseq, const bool f_spatial>\n\tbool MungeIndividualCloned_1CH_H(Individual *p_child, slim_pedigreeid_t p_pedigree_id, Individual *p_parent);\n\t\n\t// WF only:\n\tvoid WipeIndividualsAndHaplosomes(std::vector<Individual *> &p_individuals, slim_popsize_t p_individual_count, slim_popsize_t p_first_male);\n\tvoid GenerateChildrenToFitWF(void);\t\t// given the set subpop size and sex ratio, configure the child generation haplosomes and individuals to fit\n\tvoid UpdateWFFitnessBuffers(bool p_pure_neutral);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// update the WF model fitness buffers after UpdateFitness()\n\tvoid TallyLifetimeReproductiveOutput(void);\n\tvoid SwapChildAndParentHaplosomes(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// switch to the next generation by swapping; the children become the parents\n\n\t// nonWF only:\n\tvoid ApplyReproductionCallbacks(std::vector<SLiMEidosBlock*> &p_reproduction_callbacks, slim_popsize_t p_individual_index);\n\tvoid ReproduceSubpopulation(void);\n\tvoid MergeReproductionOffspring(void);\n\tbool ApplySurvivalCallbacks(std::vector<SLiMEidosBlock*> &p_survival_callbacks, Individual *p_individual, double p_fitness, double p_draw, bool p_surviving);\n\tvoid ViabilitySurvival(std::vector<SLiMEidosBlock*> &p_survival_callbacks);\n\tvoid IncrementIndividualAges(void);\n\t\n\tstatic IndividualSex _ValidateHaplosomesAndChooseSex(ChromosomeType p_chromosome_type, bool p_haplosome1_null, bool p_haplosome2_null, EidosValue *p_sex_value, bool p_sex_enabled, const char *p_caller_name);\n\tstatic IndividualSex _SexForSexValue(EidosValue *p_sex_value, bool p_sex_enabled);\n\t\n\t// Memory usage tallying, for outputUsage()\n\tsize_t MemoryUsageForParentTables(void);\n\t\n\t//\n\t// Eidos support\n\t//\n\tinline EidosSymbolTableEntry &SymbolTableEntry(void) { return self_symbol_; };\n\t\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\t// WF only:\n\tEidosValue_SP ExecuteMethod_setMigrationRates(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setCloningRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setSelfingRate(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setSexRatio(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setSubpopulationSize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// nonWF only:\n\tEidosValue_SP ExecuteMethod_addCloned(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addCrossed(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addEmpty(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addMultiRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addRecombinant(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSelfed(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_removeSubpopulation(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_takeMigrants(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\tEidosValue_SP ExecuteMethod_haplosomesForChromosomes(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_deviatePositions(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_deviatePositionsWithMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointDeviated(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointInBounds(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointReflected(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointStopped(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointPeriodic(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointUniform(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_pointUniformWithMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_setSpatialBounds(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_cachedFitness(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_defineSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_addSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_removeSpatialMap(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_spatialMapColor(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_spatialMapImage(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_spatialMapValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_outputXSample(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_sampleIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subsetIndividuals(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_configureDisplay(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_firstMaleIndex(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_individualCount(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size);\n\t\n\tstatic void SetProperty_Accelerated_fitnessScaling(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\tstatic void SetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n};\n\n\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawParentUsingFitness(Eidos_RNG_State *rng_state) const\n{\n#if DEBUG\n\tif (sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawParentUsingFitness): (internal error) called on a population for which sex is enabled.\" << EidosTerminate();\n#endif\n\t\n\tif (lookup_parent_)\n\t\treturn static_cast<slim_popsize_t>(gsl_ran_discrete(&rng_state->gsl_rng_, lookup_parent_));\n\telse\n\t\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_state->pcg32_rng_, parent_subpop_size_));\n}\n\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawParentEqualProbability(EidosRNG_32_bit &rng_32) const\n{\n#if DEBUG\n\tif (sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawParentEqualProbability): (internal error) called on a population for which sex is enabled.\" << EidosTerminate();\n#endif\n\t\n\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, parent_subpop_size_));\n}\n\n// SEX ONLY\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawFemaleParentUsingFitness(Eidos_RNG_State *rng_state) const\n{\n#if DEBUG\n\tif (!sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawFemaleParentUsingFitness): (internal error) called on a population for which sex is not enabled.\" << EidosTerminate();\n#endif\n\t\n\tif (lookup_female_parent_)\n\t\treturn static_cast<slim_popsize_t>(gsl_ran_discrete(&rng_state->gsl_rng_, lookup_female_parent_));\n\telse\n\t\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_state->pcg32_rng_, parent_first_male_index_));\n}\n\n// SEX ONLY\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawFemaleParentEqualProbability(EidosRNG_32_bit &rng_32) const\n{\n#if DEBUG\n\tif (!sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawFemaleParentEqualProbability): (internal error) called on a population for which sex is not enabled.\" << EidosTerminate();\n#endif\n\t\n\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, parent_first_male_index_));\n}\n\n// SEX ONLY\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawMaleParentUsingFitness(Eidos_RNG_State *rng_state) const\n{\n#if DEBUG\n\tif (!sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawMaleParentUsingFitness): (internal error) called on a population for which sex is not enabled.\" << EidosTerminate();\n#endif\n\t\n\tif (lookup_male_parent_)\n\t\treturn static_cast<slim_popsize_t>(gsl_ran_discrete(&rng_state->gsl_rng_, lookup_male_parent_)) + parent_first_male_index_;\n\telse\n\t\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_state->pcg32_rng_, parent_subpop_size_ - parent_first_male_index_) + parent_first_male_index_);\n}\n\n// SEX ONLY\ninline __attribute__((always_inline)) slim_popsize_t Subpopulation::DrawMaleParentEqualProbability(EidosRNG_32_bit &rng_32) const\n{\n#if DEBUG\n\tif (!sex_enabled_)\n\t\tEIDOS_TERMINATION << \"ERROR (Subpopulation::DrawMaleParentEqualProbability): (internal error) called on a population for which sex is not enabled.\" << EidosTerminate();\n#endif\n\t\n\treturn static_cast<slim_popsize_t>(Eidos_rng_interval_uint32(rng_32, parent_subpop_size_ - parent_first_male_index_) + parent_first_male_index_);\n}\n\nclass Subpopulation_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tSubpopulation_Class(const Subpopulation_Class &p_original) = delete;\t// no copy-construct\n\tSubpopulation_Class& operator=(const Subpopulation_Class&) = delete;\t// no copying\n\tinline Subpopulation_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__subpopulation__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/substitution.cpp",
    "content": "//\n//  substitution.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"substitution.h\"\n#include \"slim_globals.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"species.h\"\n\n#include <iostream>\n#include <algorithm>\n#include <string>\n#include <vector>\n\n\n#pragma mark -\n#pragma mark Substitution\n#pragma mark -\n\nSubstitution::Substitution(Mutation &p_mutation, slim_tick_t p_fixation_tick) :\n\tEidosDictionaryRetained(), mutation_type_ptr_(p_mutation.mutation_type_ptr_), position_(p_mutation.position_), selection_coeff_(p_mutation.selection_coeff_), subpop_index_(p_mutation.subpop_index_), origin_tick_(p_mutation.origin_tick_), fixation_tick_(p_fixation_tick), chromosome_index_(p_mutation.chromosome_index_), nucleotide_(p_mutation.nucleotide_), mutation_id_(p_mutation.mutation_id_), tag_value_(p_mutation.tag_value_)\n\t\n{\n\tAddKeysAndValuesFrom(&p_mutation);\n\t// No call to ContentsChanged() here; we know we use Dictionary not DataFrame, and Mutation already vetted the dictionary\n}\n\nSubstitution::Substitution(slim_mutationid_t p_mutation_id, MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, slim_tick_t p_fixation_tick, int8_t p_nucleotide) :\nmutation_type_ptr_(p_mutation_type_ptr), position_(p_position), selection_coeff_(static_cast<slim_selcoeff_t>(p_selection_coeff)), subpop_index_(p_subpop_index), origin_tick_(p_tick), fixation_tick_(p_fixation_tick), chromosome_index_(p_chromosome_index), nucleotide_(p_nucleotide), mutation_id_(p_mutation_id), tag_value_(SLIM_TAG_UNSET_VALUE)\n{\n}\n\nvoid Substitution::PrintForSLiMOutput(std::ostream &p_out) const\n{ \n\tp_out << mutation_id_ << \" m\" << mutation_type_ptr_->mutation_type_id_ << \" \" << position_;\n\t\n\t// BCH 2/2/2025: Note that in multi-chrom models, this method now prints the chromosome symbol after the position\n\t// For brevity and backward compatibility, the chromosome symbol is not printed in single-chromosome models\n\tSpecies &species = mutation_type_ptr_->species_;\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tChromosome *chromosome = chromosomes[chromosome_index_];\n\t\t\n\t\tp_out << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\n\t}\n\t\n\t// and then the remainder of the output line\n\tp_out << \" \" << selection_coeff_ << \" \" << mutation_type_ptr_->dominance_coeff_ << \" p\" << subpop_index_ << \" \" << origin_tick_ << \" \"<< fixation_tick_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[nucleotide_];\n\t\n\tp_out << std::endl;\n}\n\nvoid Substitution::PrintForSLiMOutput_Tag(std::ostream &p_out) const\n{ \n\t// BCH 4/7/2025: This is a copy of PrintForSLiMOutput() with output of tag_value_ added at the end\n\t\n\tp_out << mutation_id_ << \" m\" << mutation_type_ptr_->mutation_type_id_ << \" \" << position_;\n\t\n\t// BCH 2/2/2025: Note that in multi-chrom models, this method now prints the chromosome symbol after the position\n\t// For brevity and backward compatibility, the chromosome symbol is not printed in single-chromosome models\n\tSpecies &species = mutation_type_ptr_->species_;\n\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\n\tif (chromosomes.size() > 1)\n\t{\n\t\tChromosome *chromosome = chromosomes[chromosome_index_];\n\t\t\n\t\tp_out << \" \\\"\" << chromosome->Symbol() << \"\\\"\";\n\t}\n\t\n\t// and then the remainder of the output line\n\tp_out << \" \" << selection_coeff_ << \" \" << mutation_type_ptr_->dominance_coeff_ << \" p\" << subpop_index_ << \" \" << origin_tick_ << \" \"<< fixation_tick_;\n\t\n\t// output a nucleotide if available\n\tif (mutation_type_ptr_->nucleotide_based_)\n\t\tp_out << \" \" << gSLiM_Nucleotides[nucleotide_];\n\t\n\t// output the tag value, or '?' or the tag is not defined\n\tif (tag_value_ == SLIM_TAG_UNSET_VALUE)\n\t\tp_out << ' ' << '?';\n\telse\n\t\tp_out << ' ' << tag_value_;\n\t\n\tp_out << std::endl;\n}\n\n\n//\n//\tEidos support\n//\n#pragma mark -\n#pragma mark Eidos support\n#pragma mark -\n\nconst EidosClass *Substitution::Class(void) const\n{\n\treturn gSLiM_Substitution_Class;\n}\n\nvoid Substitution::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay() << \"<\" << mutation_id_ << \":\" << selection_coeff_ << \">\";\n}\n\nEidosValue_SP Substitution::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gID_chromosome:\n\t\t{\n\t\t\tSpecies &species = mutation_type_ptr_->species_;\n\t\t\tconst std::vector<Chromosome *> &chromosomes = species.Chromosomes();\n\t\t\tChromosome *chromosome = chromosomes[chromosome_index_];\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(chromosome, gSLiM_Chromosome_Class));\n\t\t}\n\t\tcase gID_id:\t\t\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(mutation_id_));\n\t\tcase gID_mutationType:\t\t\t// ACCELERATED\n\t\t\treturn mutation_type_ptr_->SymbolTableEntry().second;\n\t\tcase gID_position:\t\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(position_));\n\t\tcase gID_selectionCoeff:\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(selection_coeff_));\n\t\tcase gID_originTick:\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(origin_tick_));\n\t\tcase gID_fixationTick:\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(fixation_tick_));\n\t\t\t\n\t\t\t// variables\n\t\tcase gID_nucleotide:\t\t\t// ACCELERATED\n\t\t{\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty): property nucleotide is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\t\n\t\t\tswitch (nucleotide_)\n\t\t\t{\n\t\t\t\tcase 0:\treturn gStaticEidosValue_StringA;\n\t\t\t\tcase 1:\treturn gStaticEidosValue_StringC;\n\t\t\t\tcase 2:\treturn gStaticEidosValue_StringG;\n\t\t\t\tcase 3:\treturn gStaticEidosValue_StringT;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty): (internal error) unrecognized value for nucleotide_.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\tcase gID_nucleotideValue:\t\t// ACCELERATED\n\t\t{\n\t\t\tif (nucleotide_ == -1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty): property nucleotideValue is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\t\n\t\t\tswitch (nucleotide_)\n\t\t\t{\n\t\t\t\tcase 0:\treturn gStaticEidosValue_Integer0;\n\t\t\t\tcase 1:\treturn gStaticEidosValue_Integer1;\n\t\t\t\tcase 2:\treturn gStaticEidosValue_Integer2;\n\t\t\t\tcase 3:\treturn gStaticEidosValue_Integer3;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty): (internal error) unrecognized value for nucleotide_.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\tcase gID_subpopID:\t\t\t\t// ACCELERATED\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(subpop_index_));\n\t\tcase gID_tag:\t\t\t\t\t// ACCELERATED\n\t\t{\n\t\t\tslim_usertag_t tag_value = tag_value_;\n\t\t\t\n\t\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty): property tag accessed on substitution before being set.\" << EidosTerminate();\n\t\t\t\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(tag_value));\n\t\t}\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->mutation_id_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_nucleotide(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\tint8_t nucleotide = value->nucleotide_;\n\t\t\n\t\tif (nucleotide == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty_Accelerated_nucleotide): property nucleotide is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\n\t\tif (nucleotide == 0)\n\t\t\tstring_result->PushString(gStr_A);\n\t\telse if (nucleotide == 1)\n\t\t\tstring_result->PushString(gStr_C);\n\t\telse if (nucleotide == 2)\n\t\t\tstring_result->PushString(gStr_G);\n\t\telse if (nucleotide == 3)\n\t\t\tstring_result->PushString(gStr_T);\n\t}\n\t\n\treturn string_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_nucleotideValue(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\tint8_t nucleotide = value->nucleotide_;\n\t\t\n\t\tif (nucleotide == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty_Accelerated_nucleotideValue): property nucleotideValue is only defined for nucleotide-based mutations.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(nucleotide, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_originTick(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->origin_tick_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_fixationTick(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->fixation_tick_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_position(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->position_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tint_result->set_int_no_check(value->subpop_index_, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\tslim_usertag_t tag_value = value->tag_value_;\n\t\t\n\t\tif (tag_value == SLIM_TAG_UNSET_VALUE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Substitution::GetProperty_Accelerated_tag): property tag accessed on substitution before being set.\" << EidosTerminate();\n\t\t\n\t\tint_result->set_int_no_check(tag_value, value_index);\n\t}\n\t\n\treturn int_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_selectionCoeff(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tfloat_result->set_float_no_check(value->selection_coeff_, value_index);\n\t}\n\t\n\treturn float_result;\n}\n\nEidosValue *Substitution::GetProperty_Accelerated_mutationType(EidosObject **p_values, size_t p_values_size)\n{\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gSLiM_MutationType_Class))->resize_no_initialize(p_values_size);\n\t\n\tfor (size_t value_index = 0; value_index < p_values_size; ++value_index)\n\t{\n\t\tSubstitution *value = (Substitution *)(p_values[value_index]);\n\t\t\n\t\tobject_result->set_object_element_no_check_NORR(value->mutation_type_ptr_, value_index);\n\t}\n\t\n\treturn object_result;\n}\n\nvoid Substitution::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\tcase gID_subpopID:\n\t\t{\n\t\t\tslim_objectid_t value = SLiMCastToObjectidTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\tsubpop_index_ = value;\n\t\t\treturn;\n\t\t}\n\t\tcase gID_tag:\n\t\t{\n\t\t\tslim_usertag_t value = SLiMCastToUsertagTypeOrRaise(p_value.IntAtIndex_NOCAST(0, nullptr));\n\t\t\t\n\t\t\ttag_value_ = value;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tdefault:\n\t\t{\n\t\t\treturn super::SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n}\n\nEidosValue_SP Substitution::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tdefault:\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n\n//\n//\tSubstitution_Class\n//\n#pragma mark -\n#pragma mark Substitution_Class\n#pragma mark -\n\nEidosClass *gSLiM_Substitution_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *Substitution_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Substitution_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_chromosome,\t\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_Chromosome_Class)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_id,\t\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_id));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_mutationType,\t\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_MutationType_Class))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_mutationType));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_position,\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_position));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_selectionCoeff,\t\ttrue,\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_selectionCoeff));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_subpopID,\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_subpopID));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotide,\t\t\ttrue,\tkEidosValueMaskString | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_nucleotide));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_nucleotideValue,\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_nucleotideValue));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_originTick,\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_originTick));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_fixationTick,\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_fixationTick));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gStr_tag,\t\t\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(Substitution::GetProperty_Accelerated_tag));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *Substitution_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Substitution_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "core/substitution.h",
    "content": "//\n//  substitution.h\n//  SLiM\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of SLiM.\n//\n//\tSLiM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tSLiM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with SLiM.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class Substitution represents a mutation that has fixed in the population. Fixed mutations are converted to substitutions for\n efficiency, since such mutations no longer need to be tracked in each cycle.  This class is not a subclass of Mutation, to\n avoid any possibility of instances of this class getting confused with mutation instances in the code.  It also adds one new\n piece of information, the time to fixation.\n \n */\n\n#ifndef __SLiM__substitution__\n#define __SLiM__substitution__\n\n\n#include \"mutation.h\"\n#include \"chromosome.h\"\n#include \"eidos_value.h\"\n\n\nextern EidosClass *gSLiM_Substitution_Class;\n\n\nclass Substitution : public EidosDictionaryRetained\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\npublic:\n\t\n\tMutationType *mutation_type_ptr_;\t\t\t// mutation type identifier\n\tslim_position_t position_;\t\t\t\t\t// position\n\tslim_selcoeff_t selection_coeff_;\t\t\t// selection coefficient\n\tslim_objectid_t subpop_index_;\t\t\t\t// subpopulation in which mutation arose\n\tslim_tick_t origin_tick_;\t\t\t\t\t// tick in which mutation arose\n\tslim_tick_t fixation_tick_;\t\t\t\t\t// tick in which mutation fixed\n\tslim_chromosome_index_t chromosome_index_;\t// the (uint8_t) index of this mutation's chromosome\n\tint8_t nucleotide_;\t\t\t\t\t\t\t// the nucleotide being kept: A=0, C=1, G=2, T=3.  -1 is used to indicate non-nucleotide-based.\n\tconst slim_mutationid_t mutation_id_;\t\t// a unique id for each mutation, used to track mutations\n\tslim_usertag_t tag_value_;\t\t\t\t\t// a user-defined tag value\n\t\n\tSubstitution(const Substitution&) = delete;\t\t\t\t\t\t\t// no copying\n\tSubstitution& operator=(const Substitution&) = delete;\t\t\t\t// no copying\n\tSubstitution(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\tSubstitution(Mutation &p_mutation, slim_tick_t p_fixation_tick);\t// construct from the mutation that has fixed, and the tick in which it fixed\n\tSubstitution(slim_mutationid_t p_mutation_id, MutationType *p_mutation_type_ptr, slim_chromosome_index_t p_chromosome_index, slim_position_t p_position, double p_selection_coeff, slim_objectid_t p_subpop_index, slim_tick_t p_tick, slim_tick_t p_fixation_tick, int8_t p_nucleotide);\n\t\n\t// a destructor is needed now that we inherit from EidosDictionaryRetained; we want it to be as minimal as possible, though, and inline\n\tinline virtual ~Substitution(void) override { }\n\t\n\tvoid PrintForSLiMOutput(std::ostream &p_out) const;\n\tvoid PrintForSLiMOutput_Tag(std::ostream &p_out) const;\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated_id(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_nucleotide(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_nucleotideValue(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_originTick(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_fixationTick(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_position(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_subpopID(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_tag(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_selectionCoeff(EidosObject **p_values, size_t p_values_size);\n\tstatic EidosValue *GetProperty_Accelerated_mutationType(EidosObject **p_values, size_t p_values_size);\n};\n\nclass Substitution_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tSubstitution_Class(const Substitution_Class &p_original) = delete;\t// no copy-construct\n\tSubstitution_Class& operator=(const Substitution_Class&) = delete;\t// no copying\n\tinline Substitution_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n};\n\n\n#endif /* defined(__SLiM__substitution__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "data/applications/org.messerlab.slimgui.desktop",
    "content": "[Desktop Entry]\nType=Application\nExec=SLiMgui %f\nName=SLiMgui\nGenericName=The SLiM modeling environment.\nIcon=org.messerlab.slimgui\nStartupWMClass=org.messerlab.SLiMgui\nTerminal=false\nCategories=Education;Science;Biology;\nMimeType=text/slim;text/plain;\n"
  },
  {
    "path": "data/metainfo/org.messerlab.slimgui.appdata.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop-application\">\n  <id>org.messerlab.slimgui</id>\n  <metadata_license>FSFAP</metadata_license>\n  <project_license>GPL-3.0-or-later</project_license>\n  <name>SLiMgui</name>\n  <launchable type=\"desktop-id\">org.messerlab.slimgui.desktop</launchable>\n  <summary>Evolutionary simulation framework</summary>\n  <description>\n    <p>\n      SLiM is an evolutionary simulation framework that combines a powerful engine for population genetic simulations with the capability of modeling arbitrarily complex evolutionary scenarios. Simulations are configured via the integrated Eidos scripting language that allows interactive control over practically every aspect of the simulated evolutionary scenarios. The underlying individual-based simulation engine is highly optimized to enable modeling of entire chromosomes in large populations. We also provide a graphical user interface on macOS and Linux for easy simulation set-up, interactive runtime control, and dynamical visualization of simulation output.\n    </p>\n  </description>\n  <screenshots>\n    <screenshot type=\"default\">\n        <image type=\"source\">https://raw.githubusercontent.com/MesserLab/SLiM/master/org.messerlab.slimgui.screenshot.png</image>\n    </screenshot>\n  </screenshots>\n  <!-- LINKS to display in \"Software Center\" applications-->\n  <url type=\"bugtracker\">https://github.com/MesserLab/SLiM/issues</url>\n  <url type=\"homepage\">https://messerlab.org/slim/</url>\n  <developer_name>Ben Haller</developer_name>\n  <content_rating type=\"oars-1.0\" />\n  <releases>\n      <release version=\"v4.2\" date=\"2024-03-21\" type=\"stable\"/>\n  </releases>\n</component>\n"
  },
  {
    "path": "data/metainfo/org.messerlab.slimgui.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop-application\">\n  <id>org.messerlab.slimgui</id>\n  \n  <name>SLiM</name>\n  <summary>Evolutionary simulation framework for population genetics</summary>\n  \n  <metadata_license>FSFAP</metadata_license>\n  <project_license>GPL-3.0-or-later</project_license>\n  \n  <description>\n    <p>\n      SLiM is an evolutionary simulation framework that combines a powerful engine for population genetic simulations with the capability of modeling arbitrarily complex evolutionary scenarios. Simulations are configured via the integrated Eidos scripting language that allows interactive control over practically every aspect of the simulated evolutionary scenarios. The underlying individual-based simulation engine is highly optimized to enable modeling of entire chromosomes in large populations. We also provide a graphical user interface on macOS and Linux for easy simulation set-up, interactive runtime control, and dynamical visualization of simulation output.\n    </p>\n  </description>\n  \n  <launchable type=\"desktop-id\">org.messerlab.slimgui.desktop</launchable>\n  <screenshots>\n      <screenshot type=\"default\">\n          <image type=\"source\">https://raw.githubusercontent.com/MesserLab/SLiM/master/org.messerlab.slimgui.screenshot.png</image>\n      </screenshot>\n  </screenshots>\n  <!-- LINKS to display in \"Software Center\" applications-->\n  <url type=\"bugtracker\">https://github.com/MesserLab/SLiM/issues</url>\n  <url type=\"homepage\">https://messerlab.org/slim/</url>\n  <developer_name>Ben Haller</developer_name>\n  <content_rating type=\"oars-1.0\" />\n  <releases>\n    <release version=\"v4.2\" date=\"2024-03-21\" type=\"stable\"/>\n</releases>\n</component>\n"
  },
  {
    "path": "data/mime/packages/org.messerlab.slimgui-mime.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n<mime-type type=\"text/slim\">\n    <comment>SLiM evolutionary framework source file</comment>\n    <glob pattern=\"*.slim\"/>\n    <generic-icon name=\"/usr/share/icons/hicolor/scalable/mimetypes/text-slim.svg\"/>\n</mime-type>\n</mime-info>\n"
  },
  {
    "path": "debian/changelog",
    "content": "slimsim (3.7.1-1) buster; urgency=medium\n\n  * First release of binary package for Debian\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 16 Feb 2022 21:18:58 -0700\n\nslimsim (3.7.1-1ubuntu1ppa3) impish; urgency=medium\n\n  * Incrementing PPA version to build for Impish Indri.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 16 Feb 2022 19:44:03 -0700\n\nslimsim (3.7.1-1ubuntu1ppa2) bionic; urgency=medium\n\n  * Incrementing the PPA version to allow uploading to Launchpad.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 16 Feb 2022 19:29:46 -0700\n\nslimsim (3.7.1-1ubuntu1ppa1) bionic; urgency=medium\n\n  * Second release (3.7.1-1ubuntu1ppa1)\n  Specified Qt 5.9.5 as the minimum supported version of Qt5 for\n  building.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Sun, 13 Feb 2022 10:14:48 -0700\n\nslimsim (3.7.1-1) focal; urgency=medium\n\n  * First release (3.7.1-1)\n  Decremented compat to 9 to increase compatibility with the number of\n  Debian systems that this package may ultimately be built for.\n  Incremented version to new upstream sources.\n  \n -- Bryce Carson <bcars268@mtroyal.ca>  Sat, 12 Feb 2022 20:57:42 -0700\n\nslimsim (3.7-7) focal; urgency=medium\n\n  * Seventh release (3.7-7)\n  Removed all version requirements in Depends field of debian/control,\n  as the minimum version of Qt5 required is about 5.9 and all versions\n  of Debian and Ubuntu should have sufficient library versions\n  available.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 09 Feb 2022 12:46:24 -0700\n\nslimsim (3.7-6) focal; urgency=medium\n\n  * Sixth release (3.7-6)\n  Added `dh-exec` to the Build-Depends to provide\n  /usr/share/perl5/Debian/Dh_Lib.pm which is required for debhelper to\n  use the \"file => new_filename\" installation scheme in\n  ~debian/package.install~.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 09 Feb 2022 00:48:33 -0700\n\nslimsim (3.7-5) focal; urgency=medium\n\n  * Fifth release (3.7-5)\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 09 Feb 2022 00:27:04 -0700\n\nslimsim (3.7-4) xenial; urgency=medium\n\n  * Fourth release (3.7-4)\n  Added `debhelper` (without a version specification) to the\n  Build-Depends field because the `dh` command cannot be found on the\n  builder at Launchpad.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 09 Feb 2022 00:18:17 -0700\n\nslimsim (3.7-3) xenial; urgency=medium\n\n  * Third release (3.7-3)\n  Removed the \"Rules-requires-root\" field from the source paragraph of\n  the debian/control file. The poor state of Debian packaging documen-\n  tation led me to think this was somehow necessary. Oh well. One step\n  at a time towards successful builds!\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Wed, 09 Feb 2022 00:03:47 -0700\n\nslimsim (3.7-2) xenial; urgency=medium\n\n  * Second release (3.7-2)\n  Removed debhelper and debhelper-compat entries in build dependencies.\n  Instead, a debian/compat file is now used. Hopefully this resolves\n  the build issues on Launchpad.net.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Tue, 08 Feb 2022 23:45:13 -0700\n\nslimsim (3.7-1) xenial; urgency=medium\n\n  * Initial release (3.7-1)\n  SLiM with SLiMgui packaged as slimsim for Debian and Ubuntu. The use\n  of lintian will complain about the metadata license for the appstream\n  XML, (possible) spelling errors in the binaries, the use of first\n  person grammar in the Description field of the debian/control file, \n  and static linkage to ZLIB and (customized) GSL, which is not\n  addressed in this packaging effort.\n\n -- Bryce Carson <bcars268@mtroyal.ca>  Mon, 07 Feb 2022 02:43:08 -0700\n"
  },
  {
    "path": "debian/compat",
    "content": "10\n"
  },
  {
    "path": "debian/control",
    "content": "Source: slimsim\nSection: science\nPriority: optional\nMaintainer: Bryce Carson <bcars268@mtroyal.ca>\nBuild-Depends: dh-exec, debhelper, cmake (>> 3.10.2), qt5-qmake (>= 5.9.5), qtchooser (>> 64), qtbase5-dev (>= 5.9.5)\nStandards-Version: 4.5.1\nHomepage: https://messerlab.org/slim/\nVcs-Browser: https://github.com/messerlab/slim\nVcs-Git: https://github.com/MesserLab/SLiM.git\n\nPackage: slimsim\nArchitecture: amd64\nDepends: ${misc:Depends}, ${shlibs:Depends}, libgcc-s1, libgl1, libqt5core5a, libqt5gui5 | libqt5gui5-gles, libqt5widgets5, libstdc++6\nDescription: SLiM: Selection on Linked Mutations\n SLiM is an evolutionary simulation framework that combines a powerful\n engine for population genetic simulations with the capability of modeling\n arbitrarily complex evolutionary scenarios. Simulations are configured via\n the integrated Eidos scripting language that allows interactive control a\n over practically every aspect of the simulated evolutionary scenarios. The\n underlying individual-based simulation engine is highly optimized to enable\n modeling of entire chromosomes in large populations. We also provide a\n graphical user interface on macOS and Linux for easy simulation set-up,\n interactive runtime control, and dynamical visualization of simulation\n output.\n"
  },
  {
    "path": "debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: SLiM\nSource: https://messerlab.org/slim/>\n\nFiles: *\nCopyright: 2016-2025 Benjamin C. Haller\nLicense: GPL-3.0-or-later\n SLiM (Selection on Linked Mutations) is free software. The slim-sim package is\n too. Read the full license, and more information on how to apply it to any\n program by reading /usr/share/common-licenses/GPL-3.\n .\n Copyright (C) 2016-2025 Benjamin C. Haller. All rights reserved.  \n .\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n .\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nFiles: debian/*\nCopyright: 2021 Bryce Carson <bryce.a.carson@gmail.com>\nLicense: GPL-2.0-or-later\n This package is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n .\n This package is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <https://www.gnu.org/licenses/>\n .\n On Debian systems, the complete text of the GNU General\n Public License version 2 can be found in \"/usr/share/common-licenses/GPL-2\".\n"
  },
  {
    "path": "debian/rules",
    "content": "#!/usr/bin/make -f\n%:\n\tdh $@\n\noverride_dh_auto_configure:\n\tdh_auto_configure -- \\\n\t-DBUILD_SLIMGUI=ON\n"
  },
  {
    "path": "debian/slimsim.install",
    "content": "#!/usr/bin/dh-exec\nQtSLiM/icons/AppIcon64.svg => usr/share/icons/hicolor/scalable/apps/org.messerlab.slimgui.svg\nQtSLiM/icons/AppIcon16.svg => usr/share/icons/hicolor/symbolic/apps/org.messerlab.slimgui-symbolic.svg\nQtSLiM/icons/DocIcon.svg => usr/share/icons/hicolor/scalable/mimetypes/text-slim.svg\norg.messerlab.slimgui-mime.xml => usr/share/mime/packages/org.messerlab.slimgui-mime.xml\norg.messerlab.slimgui.desktop => usr/share/applications/org.messerlab.slimgui.desktop\norg.messerlab.slimgui.appdata.xml => usr/share/metainfo/org.messerlab.slimgui.appdata.xml\n"
  },
  {
    "path": "debian/source/format",
    "content": "3.0 (quilt)\n"
  },
  {
    "path": "eidos/eidos.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2019-07-10T21:52:05\n#\n#-------------------------------------------------\n\nQT       -= core gui\n\nTEMPLATE = lib\nCONFIG += staticlib\n\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\n# BCH 4/8/2026: I force AVX2 and FMA on for x86_64 builds (true since 2013), and NEON on for ARM64 builds\n# (true since forever), without the compiler capability testing done in CMakeFlags.txt.  This is a hack;\n# if it breaks things for an end user they can build with CMake instead or disable these defines.  Note\n# that building in Qt Creator is not the primary supported build method for SLiM, and is probably mostly\n# used only by me; I just want this on for development.  See https://github.com/MesserLab/SLiM/issues/598.\n# Note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro.\nmessage(\"Target architecture is: $${QMAKE_TARGET.arch}\")\n\nQMAKE_CFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\nQMAKE_CXXFLAGS += -Xarch_x86_64 -mavx2 -Xarch_x86_64 -mfma\n\nQMAKE_CFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\nQMAKE_CXXFLAGS += -Xarch_x86_64 -DEIDOS_HAS_AVX2=1 -Xarch_x86_64 -DEIDOS_HAS_FMA=1\n\nQMAKE_CFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\nQMAKE_CXXFLAGS += -Xarch_arm64 -DEIDOS_HAS_NEON=1\n\n\n# Set up to build QtSLiM; note that these settings are set in eidos.pro, core.pro, and QtSLiM.pro\nDEFINES += EIDOS_GUI\nDEFINES += SLIMGUI=1\n\nCONFIG -= qt\nCONFIG += c++11\nCONFIG += c11\nQMAKE_CFLAGS += -std=c11\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\nQMAKE_CXXFLAGS_DEBUG += -g -Og -DDEBUG=1 -DSLIMPROFILING=0\nQMAKE_CXXFLAGS_RELEASE += -O3 -DSLIMPROFILING=1\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CXXFLAGS += -Wno-unknown-pragmas -Wno-attributes -Wno-unused-parameter\n}\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n# gsl library dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../gsl/release/ -lgsl\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../gsl/debug/ -lgsl\nelse:unix: LIBS += -L$$OUT_PWD/../gsl/ -lgsl\nINCLUDEPATH += $$PWD/../gsl $$PWD/../gsl/blas $$PWD/../gsl/block $$PWD/../gsl/cblas $$PWD/../gsl/cdf\nINCLUDEPATH += $$PWD/../gsl/complex $$PWD/../gsl/err $$PWD/../gsl/interpolation $$PWD/../gsl/linalg $$PWD/../gsl/matrix\nINCLUDEPATH += $$PWD/../gsl/permutation $$PWD/../gsl/randist $$PWD/../gsl/rng $$PWD/../gsl/specfunc $$PWD/../gsl/sys\nINCLUDEPATH += $$PWD/../gsl/vector\nDEPENDPATH += $$PWD/../gsl\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/libgsl.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/libgsl.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/release/gsl.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../gsl/debug/gsl.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../gsl/libgsl.a\n\n# eidos_zlib dependency\nwin32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../eidos_zlib/release/ -leidos_zlib\nelse:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../eidos_zlib/debug/ -leidos_zlib\nelse:unix: LIBS += -L$$OUT_PWD/../eidos_zlib/ -leidos_zlib\nINCLUDEPATH += $$PWD/../eidos_zlib\nDEPENDPATH += $$PWD/../eidos_zlib\nwin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/release/libeidos_zlib.a\nelse:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/debug/libeidos_zlib.a\nelse:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/release/eidos_zlib.lib\nelse:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/debug/eidos_zlib.lib\nelse:unix: PRE_TARGETDEPS += $$OUT_PWD/../eidos_zlib/libeidos_zlib.a\n\n\nSOURCES += \\\n    eidos_ast_node.cpp \\\n    eidos_beep.cpp \\\n    eidos_call_signature.cpp \\\n    eidos_class_DataFrame.cpp \\\n    eidos_class_Dictionary.cpp \\\n    eidos_class_Image.cpp \\\n    eidos_class_Object.cpp \\\n    eidos_class_TestElement.cpp \\\n    eidos_functions.cpp \\\n    eidos_functions_colors.cpp \\\n    eidos_functions_distributions.cpp \\\n    eidos_functions_files.cpp \\\n    eidos_functions_math.cpp \\\n    eidos_functions_matrices.cpp \\\n    eidos_functions_other.cpp \\\n    eidos_functions_stats.cpp \\\n    eidos_functions_strings.cpp \\\n    eidos_functions_values.cpp \\\n    eidos_globals.cpp \\\n    eidos_interpreter.cpp \\\n    eidos_property_signature.cpp \\\n    eidos_rng.cpp \\\n    eidos_script.cpp \\\n    eidos_sorting.cpp \\\n    eidos_symbol_table.cpp \\\n    eidos_test.cpp \\\n    eidos_test_functions_math.cpp \\\n    eidos_test_functions_other.cpp \\\n    eidos_test_functions_statistics.cpp \\\n    eidos_test_functions_vector.cpp \\\n    eidos_test_operators_arithmetic.cpp \\\n    eidos_test_operators_comparison.cpp \\\n    eidos_test_operators_other.cpp \\\n    eidos_token.cpp \\\n    eidos_type_interpreter.cpp \\\n    eidos_type_table.cpp \\\n    eidos_value.cpp \\\n    lodepng.cpp\n\nHEADERS += \\\n    eidos_ast_node.h \\\n    eidos_beep.h \\\n    eidos_call_signature.h \\\n\teidos_class_DataFrame.h \\\n    eidos_class_Dictionary.h \\\n    eidos_class_Object.h \\\n    eidos_class_TestElement.h \\\n    eidos_class_Image.h \\\n    eidos_functions.h \\\n    eidos_globals.h \\\n    eidos_interpreter.h \\\n    eidos_intrusive_ptr.h \\\n    eidos_object_pool.h \\\n    eidos_property_signature.h \\\n    eidos_rng.h \\\n    eidos_script.h \\\n\teidos_simd.h \\\n\teidos_sorting.h \\\n    eidos_symbol_table.h \\\n    eidos_test_builtins.h \\\n    eidos_test.h \\\n    eidos_tinycolormap.h \\\n    eidos_token.h \\\n    eidos_type_interpreter.h \\\n    eidos_type_table.h \\\n    eidos_value.h \\\n\tjson.hpp \\\n\tjson_fwd.hpp \\\n    lodepng.h \\\n    robin_hood.h\n\n\n"
  },
  {
    "path": "eidos/eidos_ast_node.cpp",
    "content": "//\n//  eidos_ast_node.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_ast_node.h\"\n#include \"eidos_interpreter.h\"\n\n#include <string>\n#include <algorithm>\n\n\n// The global object pool for EidosASTNode, initialized in Eidos_WarmUp()\nEidosObjectPool *gEidosASTNodePool = nullptr;\n\n\nEidosASTNode::~EidosASTNode(void)\n{\n\tfor (auto child : children_)\n\t{\n\t\t// destroy children and return them to the pool; all children must be allocated out of gEidosASTNodePool!\n\t\tchild->~EidosASTNode();\n\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(child));\n\t}\n\t\n\tif (token_is_owned_)\n\t{\n\t\tdelete token_;\n\t\ttoken_ = nullptr;\n\t}\n\t\n\tif (argument_cache_)\n\t{\n\t\tdelete argument_cache_;\n\t\targument_cache_ = nullptr;\n\t}\n}\n\nvoid EidosASTNode::AddChild(EidosASTNode *p_child_node)\n{\n\tchildren_.emplace_back(p_child_node);\n}\n\nvoid EidosASTNode::ReplaceTokenWithToken(EidosToken *p_token)\n{\n\t// dispose of our previous token\n\tif (token_is_owned_)\n\t{\n\t\tdelete token_;\n\t\ttoken_ = nullptr;\n\t\ttoken_is_owned_ = false;\n\t}\n\t\n\t// used to fix virtual token to encompass their children; takes ownership\n\ttoken_ = p_token;\n\ttoken_is_owned_ = true;\n}\n\nvoid EidosASTNode::OptimizeTree(void) const\n{\n\t_OptimizeConstants();\t\t// cache values for numeric and string constants, and for return statements and constant compound statements\n\t_OptimizeIdentifiers();\t\t// cache unique IDs for identifiers using EidosStringRegistry::GlobalStringIDForString()\n\t_OptimizeEvaluators();\t\t// cache evaluator functions in cached_evaluator_ for fast node evaluation\n\t_OptimizeAssignments();\t\t// cache information about assignments that allows simple increment/decrement assignments to be accelerated\n}\n\nvoid EidosASTNode::_OptimizeConstants(void) const\n{\n\t// recurse down the tree; determine our children, then ourselves\n\tfor (const EidosASTNode *child : children_)\n\t\tchild->_OptimizeConstants();\n\t\n\t// now find constant expressions and make EidosValues for them\n\tEidosTokenType token_type = token_->token_type_;\n\t\n\tif (token_type == EidosTokenType::kTokenNumber)\n\t{\n\t\ttry {\n\t\t\tcached_literal_value_ = EidosInterpreter::NumericValueForString(token_->token_string_, token_);\n\t\t\tcached_literal_value_->MarkAsConstant();\n\t\t}\n\t\tcatch (...) {\t\t// NOLINT(*-empty-catch) : intentional empty catch\n\t\t\t// if EidosInterpreter::NumericValueForString() raises, we just don't cache the value\n\t\t}\n\t}\n\telse if (token_type == EidosTokenType::kTokenString)\n\t{\n\t\t// This is taken from EidosInterpreter::Evaluate_String and needs to match exactly!\n\t\tcached_literal_value_ = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(token_->token_string_));\n\t\tcached_literal_value_->MarkAsConstant();\n\t}\n\telse if (token_type == EidosTokenType::kTokenIdentifier)\n\t{\n\t\t// Cache values for built-in constants; these can't be changed, so this should be safe, and\n\t\t// should be much faster than having to scan up through all the symbol tables recursively\n\t\t// Note that these values are all constants already, so MarkAsConstant() is not needed.\n\t\tif (token_->token_string_ == gEidosStr_F)\n\t\t\tcached_literal_value_ = gStaticEidosValue_LogicalF;\n\t\telse if (token_->token_string_ == gEidosStr_T)\n\t\t\tcached_literal_value_ = gStaticEidosValue_LogicalT;\n\t\telse if (token_->token_string_ == gEidosStr_INF)\n\t\t\tcached_literal_value_ = gStaticEidosValue_FloatINF;\n\t\telse if (token_->token_string_ == gEidosStr_NAN)\n\t\t\tcached_literal_value_ = gStaticEidosValue_FloatNAN;\n\t\telse if (token_->token_string_ == gEidosStr_E)\n\t\t\tcached_literal_value_ = gStaticEidosValue_FloatE;\n\t\telse if (token_->token_string_ == gEidosStr_PI)\n\t\t\tcached_literal_value_ = gStaticEidosValue_FloatPI;\n\t\telse if (token_->token_string_ == gEidosStr_NULL)\n\t\t\tcached_literal_value_ = gStaticEidosValueNULL;\n\t}\n\telse if (token_type == EidosTokenType::kTokenReturn)\n\t{\n\t\t// A return statement can propagate a single constant value upward.  Note that this is not strictly true;\n\t\t// return statements have side effects on the flow of execution.  It would therefore be inappropriate for\n\t\t// their execution to be short-circuited in favor of a constant value in general; but that is not what\n\t\t// this optimization means.  Rather, it means that these nodes are saying \"I've got just a constant value\n\t\t// inside me, so *if* nothing else is going on around me, I can be taken as equal to that constant.\"  We\n\t\t// honor that conditional statement by only checking for the cached constant in specific places.\n\t\tif (children_.size() == 1)\n\t\t{\n\t\t\tconst EidosASTNode *child = children_[0];\n\t\t\t\n\t\t\tif (child->cached_literal_value_)\n\t\t\t{\n\t\t\t\tcached_return_value_ = child->cached_literal_value_;\n\t\t\t\tcached_return_value_->MarkAsConstant();\t\t\t// should already be marked constant, actually\n\t\t\t}\n\t\t}\n\t}\n\telse if (token_type == EidosTokenType::kTokenLBrace)\n\t{\n\t\t// This dovetails with the caching of returned values above, and the same caveats apply.  Basically, the idea\n\t\t// is that if a block consists of nothing but the return of a constant value, like \"{ return 1.5; }\", then\n\t\t// the block can declare that with cached_value_ and intelligent users of the block can avoid interpreting\n\t\t// the block.  Note that since blocks no longer evaluate to the value of their last statement, we now require\n\t\t// the child of the block to be an explicit return statement.\n\t\tif (children_.size() == 1)\n\t\t{\n\t\t\tconst EidosASTNode *child = children_[0];\n\t\t\t\n\t\t\tif (child->cached_return_value_ && (child->token_->token_type_ == EidosTokenType::kTokenReturn))\n\t\t\t{\n\t\t\t\tcached_return_value_ = child->cached_return_value_;\n\t\t\t\tcached_return_value_->MarkAsConstant();\t\t\t// should already be marked constant, actually\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid EidosASTNode::_OptimizeIdentifiers(void) const\n{\n\t// recurse down the tree; determine our children, then ourselves\n\tfor (auto child : children_)\n\t\tchild->_OptimizeIdentifiers();\n\t\n\tif (token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t{\n\t\tconst std::string &token_string = token_->token_string_;\n\t\t\n\t\t// if the identifier's name matches that of a global function, cache the function signature\n\t\tconst EidosFunctionMap *function_map = EidosInterpreter::BuiltInFunctionMap();\n\t\t\n\t\tif (function_map)\n\t\t{\n\t\t\tauto signature_iter = function_map->find(token_string);\n\t\t\t\n\t\t\tif (signature_iter != function_map->end())\n\t\t\t\tcached_signature_ = signature_iter->second;\n\t\t}\n\t\t\n\t\t// cache a uniqued ID for the identifier, allowing fast matching\n\t\tcached_stringID_ = EidosStringRegistry::GlobalStringIDForString(token_string);\n\t}\n}\n\nvoid EidosASTNode::_OptimizeEvaluators(void) const\n{\n\t// recurse down the tree; determine our children, then ourselves\n\tfor (auto child : children_)\n\t\tchild->_OptimizeEvaluators();\n\t\n\tEidosTokenType token_type = token_->token_type_;\n\t\n\t// The structure here avoids doing a break in the non-error case; a bit faster.\n\tswitch (token_type)\n\t{\n\t\tcase EidosTokenType::kTokenSemicolon:\tcached_evaluator_ = &EidosInterpreter::Evaluate_NullStatement;\t\tbreak;\n\t\tcase EidosTokenType::kTokenColon:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_RangeExpr;\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLBrace:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_CompoundStatement;\tbreak;\n\t\tcase EidosTokenType::kTokenLParen:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Call;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLBracket:\tcached_evaluator_ = &EidosInterpreter::Evaluate_Subset;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenDot:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_MemberRef;\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenPlus:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Plus;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMinus:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Minus;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMod:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Mod;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMult:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Mult;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenExp:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Exp;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenAnd:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_And;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenOr:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Or;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenDiv:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Div;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenConditional:\tcached_evaluator_ = &EidosInterpreter::Evaluate_Conditional;\t\tbreak;\n\t\tcase EidosTokenType::kTokenAssign:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Assign;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenAssign_R:\tcached_evaluator_ = &EidosInterpreter::Evaluate_Assign_R;\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenEq:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Eq;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLt:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Lt;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLtEq:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_LtEq;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenGt:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Gt;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenGtEq:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_GtEq;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNot:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Not;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNotEq:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_NotEq;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNumber:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Number;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenString:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_String;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenIdentifier:\tcached_evaluator_ = &EidosInterpreter::Evaluate_Identifier;\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenIf:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_If;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenDo:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Do;\t\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenWhile:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_While;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenFor:\t\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_For;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNext:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Next;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenBreak:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Break;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenReturn:\t\tcached_evaluator_ = &EidosInterpreter::Evaluate_Return;\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenFunction:\tcached_evaluator_ = &EidosInterpreter::Evaluate_FunctionDecl;\t\tbreak;\n\t\tdefault:\n\t\t\t// Node types with no known evaluator method just don't get an cached evaluator\n\t\t\tbreak;\n\t}\n}\n\nvoid EidosASTNode::_OptimizeAssignments(void) const\n{\n\t// recurse down the tree; determine our children, then ourselves\n\tfor (auto child : children_)\n\t\tchild->_OptimizeAssignments();\n\t\n\tEidosTokenType token_type = token_->token_type_;\n\t\n\tif ((token_type == EidosTokenType::kTokenAssign) && (children_.size() == 2))\n\t{\n\t\t// We have an assignment node with two children...\n\t\tEidosASTNode *child0 = children_[0];\n\t\t\n\t\tif (child0->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\t// ...the lvalue is a simple identifier...\n\t\t\tEidosASTNode *child1 = children_[1];\n\t\t\tEidosTokenType child1_token_type = child1->token_->token_type_;\n\t\t\t\n\t\t\tif ((child1_token_type == EidosTokenType::kTokenPlus) || (child1_token_type == EidosTokenType::kTokenMinus) || (child1_token_type == EidosTokenType::kTokenDiv) || (child1_token_type == EidosTokenType::kTokenMod) || (child1_token_type == EidosTokenType::kTokenMult) || (child1_token_type == EidosTokenType::kTokenExp))\n\t\t\t{\n\t\t\t\t// ... the rvalue uses an eligible operator...\n\t\t\t\tif (child1->children_.size() == 2)\n\t\t\t\t{\n\t\t\t\t\t// ... the rvalue has two children...\n\t\t\t\t\tEidosASTNode *left_operand = child1->children_[0];\n\t\t\t\t\t\n\t\t\t\t\tif (left_operand->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t{\n\t\t\t\t\t\t// ... the left operand is an identifier...\n\t\t\t\t\t\tif (left_operand->token_->token_string_.compare(child0->token_->token_string_) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// ... the left and right identifiers are the same...\n\t\t\t\t\t\t\tEidosASTNode *right_operand = child1->children_[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((right_operand->token_->token_type_ == EidosTokenType::kTokenNumber) && (right_operand->cached_literal_value_))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// ... and the right operand is a constant number with a cached value...\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// we have a simple increment/decrement by one, so we mark that in the tree for Evaluate_Assign() to handle super fast\n\t\t\t\t\t\t\t\tcached_compound_assignment_ = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ((child1_token_type == EidosTokenType::kTokenLParen) && (child1->children_.size() == 3))\n\t\t\t{\n\t\t\t\t// ... the rvalue is a function call with three children...\n\t\t\t\tEidosASTNode *left_operand = child1->children_[0];\n\t\t\t\t\n\t\t\t\tif ((left_operand->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (left_operand->token_->token_string_ == gEidosStr_c))\n\t\t\t\t{\n\t\t\t\t\t// ... it's a call to c()...\n\t\t\t\t\tEidosASTNode *middle_operand = child1->children_[1];\n\t\t\t\t\t\n\t\t\t\t\tif ((middle_operand->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (middle_operand->token_->token_string_ == child0->token_->token_string_))\n\t\t\t\t\t{\n\t\t\t\t\t\t// ... the first argument to c() is the same as the lvalue, so we have x = c(x, <expression>), so we mark that in the tree for Evaluate_Assign()\n\t\t\t\t\t\tcached_append_assignment_ = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool EidosASTNode::HasCachedNumericValue(void) const\n{\n\tif ((token_->token_type_ == EidosTokenType::kTokenNumber) && cached_literal_value_ && (cached_literal_value_->Count() == 1))\n\t\treturn true;\n\t\n\tif ((token_->token_type_ == EidosTokenType::kTokenMinus) && (children_.size() == 1))\n\t{\n\t\tconst EidosASTNode *minus_child = children_[0];\n\t\t\n\t\tif ((minus_child->token_->token_type_ == EidosTokenType::kTokenNumber) && minus_child->cached_literal_value_ && (minus_child->cached_literal_value_->Count() == 1))\n\t\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\ndouble EidosASTNode::CachedNumericValue(void) const\n{\n\tif ((token_->token_type_ == EidosTokenType::kTokenNumber) && cached_literal_value_ && (cached_literal_value_->Count() == 1))\n\t\treturn cached_literal_value_->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((token_->token_type_ == EidosTokenType::kTokenMinus) && (children_.size() == 1))\n\t{\n\t\tconst EidosASTNode *minus_child = children_[0];\n\t\t\n\t\tif ((minus_child->token_->token_type_ == EidosTokenType::kTokenNumber) && minus_child->cached_literal_value_ && (minus_child->cached_literal_value_->Count() == 1))\n\t\t\treturn -minus_child->cached_literal_value_->NumericAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\tEIDOS_TERMINATION << \"ERROR (EidosASTNode::CachedNumericValue): (internal error) no cached numeric value\" << EidosTerminate(nullptr);\n}\n\nvoid EidosASTNode::PrintToken(std::ostream &p_outstream) const\n{\n\t// We want to print some tokens differently when they are in the context of an AST, for readability\n\tswitch (token_->token_type_)\n\t{\n\t\tcase EidosTokenType::kTokenLBrace:\t\tp_outstream << \"BLOCK\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenSemicolon:\tp_outstream << \"NULL_STATEMENT\";\tbreak;\n\t\tcase EidosTokenType::kTokenLParen:\t\tp_outstream << \"CALL\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLBracket:\tp_outstream << \"SUBSET\";\t\t\tbreak;\n\t\t//case EidosTokenType::kTokenComma:\t\tp_outstream << \"ARG_LIST\";\t\t\tbreak;\t\t// no longer used in the AST\n\t\tdefault:\t\t\t\t\t\t\t\tp_outstream << *token_;\t\t\t\tbreak;\n\t}\n}\n\nvoid EidosASTNode::PrintTreeWithIndent(std::ostream &p_outstream, int p_indent) const\n{\n\t// If we are indented, start a new line and indent\n\tif (p_indent > 0)\n\t{\n\t\tp_outstream << \"\\n  \";\n\t\t\n\t\tfor (int i = 0; i < p_indent - 1; ++i)\n\t\t\tp_outstream << \"  \";\n\t}\n\t\n\tif (children_.size() == 0)\n\t{\n\t\t// If we are a leaf, just print our token\n\t\tPrintToken(p_outstream);\n\t}\n\telse\n\t{\n\t\t// Determine whether we have only leaves as children\n\t\tbool childWithChildren = false;\n\t\t\n\t\tfor (auto child : children_)\n\t\t{\n\t\t\tif (child->children_.size() > 0)\n\t\t\t{\n\t\t\t\tchildWithChildren = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (childWithChildren)\n\t\t{\n\t\t\t// If we have non-leaf children, then print them with an incremented indent\n\t\t\tp_outstream << \"(\";\n\t\t\tPrintToken(p_outstream);\n\t\t\t\n\t\t\tfor (auto child : children_)\n\t\t\t\tchild->PrintTreeWithIndent(p_outstream, p_indent + 1);\n\t\t\t\n\t\t\t// and then outdent and show our end paren\n\t\t\tp_outstream << \"\\n\";\n\t\t\t\n\t\t\tif (p_indent > 0)\n\t\t\t{\n\t\t\t\tp_outstream << \"  \";\n\t\t\t\t\n\t\t\t\tfor (int i = 0; i < p_indent - 1; ++i)\n\t\t\t\t\tp_outstream << \"  \";\n\t\t\t}\n\t\t\t\n\t\t\tp_outstream << \")\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If we have only leaves as children, then print everything on one line, for compactness\n\t\t\tp_outstream << \"(\";\n\t\t\tPrintToken(p_outstream);\n\t\t\t\n\t\t\tfor (auto child : children_)\n\t\t\t{\n\t\t\t\tp_outstream << \" \";\n\t\t\t\tchild->PrintToken(p_outstream);\n\t\t\t}\n\t\t\t\n\t\t\tp_outstream << \")\";\n\t\t}\n\t}\n}\n\nEidosErrorPosition EidosASTNode::ErrorPositionForNodeAndChildren(void) const\n{\n\t// Returns the union of all the token ranges for the node and its children; useful when\n\t// you want to report an error that spans a whole region of the AST.\n\tEidosErrorPosition pos;\n\t\n\tpos.characterStartOfError = token_->token_start_;\n\tpos.characterEndOfError = token_->token_end_;\n\tpos.characterStartOfErrorUTF16 = token_->token_UTF16_start_;\n\tpos.characterEndOfErrorUTF16 = token_->token_UTF16_end_;\n\t\n\tfor (auto child : children_)\n\t{\n\t\tEidosErrorPosition child_pos = child->ErrorPositionForNodeAndChildren();\n\t\t\n\t\tpos.characterStartOfError = std::min(pos.characterStartOfError, child_pos.characterStartOfError);\n\t\tpos.characterEndOfError = std::max(pos.characterEndOfError, child_pos.characterEndOfError);\n\t\tpos.characterStartOfErrorUTF16 = std::min(pos.characterStartOfErrorUTF16, child_pos.characterStartOfErrorUTF16);\n\t\tpos.characterEndOfErrorUTF16 = std::max(pos.characterEndOfErrorUTF16, child_pos.characterEndOfErrorUTF16);\n\t}\n\t\n\treturn pos;\n}\n\n#if (SLIMPROFILING == 1)\n// PROFILING\n\nvoid EidosASTNode::ZeroProfileTotals(void) const\n{\n\t// recurse down the tree; zero our children, then ourselves\n\tfor (const EidosASTNode *child : children_)\n\t\tchild->ZeroProfileTotals();\n\t\n\tprofile_total_ = 0;\n}\n\neidos_profile_t EidosASTNode::ConvertProfileTotalsToSelfCounts(void) const\n{\n\t// convert profile counts in the tree to self counts, excluding time spent in children\n\tif (profile_total_)\n\t{\n\t\t// Nodes with a non-zero count return their count as their total, and exclude their children\n\t\teidos_profile_t result = profile_total_;\n\t\teidos_profile_t child_total = 0;\n\t\t\n\t\tfor (const EidosASTNode *child : children_)\n\t\t\tchild_total += child->ConvertProfileTotalsToSelfCounts();\n\t\t\n\t\tif (profile_total_ >= child_total)\n\t\t\tprofile_total_ = profile_total_ - child_total;\n\t\telse\n\t\t\tprofile_total_ = 0;\t\t\t// clip to a minimum of 0\n\t\t\n\t\treturn result;\n\t}\n\telse\n\t{\n\t\t// Nodes with a zero count have a zero self count, and report the total of their children\n\t\teidos_profile_t result = 0;\n\t\t\n\t\tfor (const EidosASTNode *child : children_)\n\t\t\tresult += child->ConvertProfileTotalsToSelfCounts();\n\t\t\n\t\treturn result;\n\t}\n}\n\neidos_profile_t EidosASTNode::TotalOfSelfCounts(void) const\n{\n\teidos_profile_t total = profile_total_;\n\t\n\tfor (const EidosASTNode *child : children_)\n\t\ttotal += child->TotalOfSelfCounts();\n\t\n\treturn total;\n}\n\nvoid EidosASTNode::FullUTF8Range(int32_t *p_start, int32_t *p_end) const\n{\n\tint32_t start = token_->token_start_;\n\tint32_t end = token_->token_end_;\n\t\n\tif (full_range_end_token_)\n\t{\n\t\t// If we have an end token, that defines our range end\n\t\tend = std::max(end, full_range_end_token_->token_end_);\n\t\t\n\t\t// We still need to scan our children for our range start, however\n\t\tfor (const EidosASTNode *child : children_)\n\t\t{\n\t\t\tint32_t child_start = 0, child_end = 0;\n\t\t\t\n\t\t\tchild->FullUTF8Range(&child_start, &child_end);\n\t\t\t\n\t\t\tstart = std::min(start, child_start);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Otherwise, incorporate the ranges of our children\n\t\tfor (const EidosASTNode *child : children_)\n\t\t{\n\t\t\tint32_t child_start = 0, child_end = 0;\n\t\t\t\n\t\t\tchild->FullUTF8Range(&child_start, &child_end);\n\t\t\t\n\t\t\tstart = std::min(start, child_start);\n\t\t\tend = std::max(end, child_end);\n\t\t}\n\t}\n\t\n\t*p_start = start;\n\t*p_end = end;\n}\n\nvoid EidosASTNode::FullUTF16Range(int32_t *p_start, int32_t *p_end) const\n{\n\tint32_t start = token_->token_UTF16_start_;\n\tint32_t end = token_->token_UTF16_end_;\n\t\n\tif (full_range_end_token_)\n\t{\n\t\t// If we have an end token, that defines our range end\n\t\tend = std::max(end, full_range_end_token_->token_UTF16_end_);\n\t\t\n\t\t// We still need to scan our children for our range start, however\n\t\tfor (const EidosASTNode *child : children_)\n\t\t{\n\t\t\tint32_t child_start = 0, child_end = 0;\n\t\t\t\n\t\t\tchild->FullUTF16Range(&child_start, &child_end);\n\t\t\t\n\t\t\tstart = std::min(start, child_start);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Otherwise, incorporate the ranges of our children\n\t\tfor (const EidosASTNode *child : children_)\n\t\t{\n\t\t\tint32_t child_start = 0, child_end = 0;\n\t\t\t\n\t\t\tchild->FullUTF16Range(&child_start, &child_end);\n\t\t\t\n\t\t\tstart = std::min(start, child_start);\n\t\t\tend = std::max(end, child_end);\n\t\t}\n\t}\n\t\n\t*p_start = start;\n\t*p_end = end;\n}\n\n#endif\t// (SLIMPROFILING == 1)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_ast_node.h",
    "content": "//\n//  eidos_ast_node.h\n//  Eidos\n//\n//  Created by Ben Haller on 7/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_ast_node__\n#define __Eidos__eidos_ast_node__\n\n#include <stdio.h>\n#include <vector>\n\n#include \"eidos_token.h\"\n#include \"eidos_value.h\"\n#include \"eidos_call_signature.h\"\n\n\nclass EidosASTNode;\nclass EidosInterpreter;\n\n\n// EidosASTNodes must be allocated out of the global pool, for speed.  See eidos_object_pool.h.  When Eidos disposes of a node,\n// it will assume that it was allocated from this pool, so its use is mandatory except for stack-allocated objects.\nextern EidosObjectPool *gEidosASTNodePool;\n\n\n// A typedef for a pointer to an EidosInterpreter evaluation method, cached for speed\ntypedef EidosValue_SP (EidosInterpreter::*EidosEvaluationMethod)(const EidosASTNode *p_node);\n\n\n// runtime caching for argument list processing; these caches are filled and used ONLY by EidosInterpreter::Evaluate_Call() / EidosInterpreter::_ProcessArgumentList() to accelerate function/method dispatch\n// note that unlike the caches above, this caching is not done at optimization time; it is done lazily at runtime, the first time a given function/method call is hit during interpreted execution\n// BCH 2/5/2021: note that fill_index_ has to be uint32_t because there could be thousands of ellipsis arguments, but other indexes are into the signature and can be uint8_t\nstruct EidosASTNode_ArgumentFill\n{\n\tEidosASTNode *fill_node_;\t\t\t\t// the AST node that should be evaluated to get a fill value for the given index\n\tuint32_t fill_index_;\t\t\t\t\t// the index of the argument that needs evaluation (i.e., not default/constant)\n\tuint8_t signature_index_;\t\t\t\t// the index of the corresponding argument in the signature (may differ due to an intermediate ellipsis)\n\tbool fill_singleton_;\t\t\t\t\t// true if the argument is required to be a singleton, derived from the signature's arg_masks_\n\tEidosValueMask fill_mask_;\t\t\t\t// the stripped type mask for the argument, derived from the signature's arg_masks_\n\t\n\tinline EidosASTNode_ArgumentFill(EidosASTNode *p_node, uint32_t p_index, uint8_t p_signature_index, bool p_singleton, EidosValueMask p_mask) : fill_node_(p_node), fill_index_(p_index), signature_index_(p_signature_index), fill_singleton_(p_singleton), fill_mask_(p_mask) {};\n};\n\nstruct EidosASTNode_ArgumentCache\n{\n\tstd::vector<EidosValue_SP> argument_buffer_;\t\t\t\t\t\t// a buffer big enough to hold all arguments, pre-filled with all default/constant argument values\n\tstd::vector<EidosASTNode_ArgumentFill> fill_info_;\t\t\t\t\t// a buffer of information about arguments in argument_buffer_ needing to be filled at dispatch time\n\tstd::vector<uint8_t> no_fill_index_;\t\t\t\t\t\t\t\t// a buffer of indexes for arguments in argument_buffer_ that are default/constant and not filled\n\tbool argument_buffer_in_use_;\t\t\t\t\t\t\t\t\t\t// prevents argument_buffer_ from being overwritten by recursion\n};\n\n// A class representing a node in a parse tree for a script\nclass EidosASTNode\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\npublic:\n\t\n\tEidosToken *token_;\t\t\t\t\t\t\t\t\t\t\t\t\t// normally not owned (owned by the Script's token stream) but:\n\tstd::vector<EidosASTNode *> children_;\t\t\t\t\t\t\t\t// OWNED POINTERS\n\t\n\tmutable EidosValue_SP cached_literal_value_;\t\t\t\t\t\t// an optional pre-cached EidosValue for numbers, strings, and constant identifiers\n\tmutable EidosValue_SP cached_range_value_;\t\t\t\t\t\t\t// an optional pre-cached EidosValue for constant range-operator expressions\n\tmutable EidosValue_SP cached_return_value_;\t\t\t\t\t\t\t// an optional pre-cached EidosValue for constant return statements and constant-return blocks\n\tmutable EidosFunctionSignature_CSP cached_signature_ = nullptr;\t\t// a cached pointer to the function signature corresponding to the token, on the call name node\n\tmutable EidosEvaluationMethod cached_evaluator_ = nullptr;\t\t\t// a pre-cached pointer to method to evaluate this node; shorthand for EvaluateNode()\n\tmutable EidosGlobalStringID cached_stringID_ = gEidosID_none;\t\t// a pre-cached identifier for the token string, for fast property/method lookup\n\t\n\tuint8_t token_is_owned_ = false;\t\t\t\t\t\t\t\t\t// if T, we own token_ because it is a virtual token that replaced a real token\n\tmutable uint8_t cached_compound_assignment_ = false;\t\t\t\t// pre-cached on assignment nodes if they are of the form \"x=x+1\" or \"x=x-1\" only\n\tmutable uint8_t cached_append_assignment_ = false;\t\t\t\t\t// pre-cached on assignment nodes if they are of the form \"x=c(x, y)\" only\n\t\n\tmutable EidosTypeSpecifier typespec_;\t\t\t\t\t\t\t\t// only valid for type-specifier nodes inside function declarations\n\tmutable bool hit_eof_in_tolerant_parse_ = false;\t\t\t\t\t// only valid for compound statement nodes; used by the type-interpreter to handle scoping\n\tbool was_parenthesized_ = false;\t\t\t\t\t\t\t\t\t// set to true for nodes that are the child of a set of grouping parentheses\n\t\n\tmutable EidosASTNode_ArgumentCache *argument_cache_ = nullptr;\t\t// OWNED POINTER: an argument cache struct, allocated on demand for function/method call nodes\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tmutable eidos_profile_t profile_total_ = 0;\t\t\t\t\t\t\t// profiling clock for this node and its children; only set for some nodes\n\tEidosToken *full_range_end_token_ = nullptr;\t\t\t\t\t\t// the \")\" or \"]\" that ends the full range of tokens like \"(\", \"[\", for, if, and while\n#endif\n\t\n\tEidosASTNode(const EidosASTNode&) = delete;\t\t\t\t\t\t\t// no copying\n\tEidosASTNode& operator=(const EidosASTNode&) = delete;\t\t\t\t// no copying\n\tEidosASTNode(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\t\n\t// standard constructor; if p_token_is_owned, we own the token\n\tinline EidosASTNode(EidosToken *p_token, bool p_token_is_owned = false) : token_(p_token), token_is_owned_(p_token_is_owned) { }\n\tinline EidosASTNode(EidosToken *p_token, EidosASTNode *p_child_node) : token_(p_token)\n\t{\n\t\tthis->AddChild(p_child_node);\n\t}\n\t\n\t~EidosASTNode(void);\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\tvoid AddChild(EidosASTNode *p_child_node);\t\t\t\t\t\t\t// takes ownership of the passed node\n\tvoid ReplaceTokenWithToken(EidosToken *p_token);\t\t\t\t\t// used to fix virtual token to encompass their children; takes ownership\n\t\n\tvoid OptimizeTree(void) const;\t\t\t\t\t\t\t\t\t\t// perform various (required) optimizations on the AST\n\tvoid _OptimizeConstants(void) const;\t\t\t\t\t\t\t\t// cache EidosValues for constants and propagate constants upward\n\tvoid _OptimizeIdentifiers(void) const;\t\t\t\t\t\t\t\t// cache function signatures, global strings for methods and properties, etc.\n\tvoid _OptimizeEvaluators(void) const;\t\t\t\t\t\t\t\t// cache pointers to method for evaluation\n\tvoid _OptimizeAssignments(void) const;\t\t\t\t\t\t\t\t// detect and mark simple increment/decrement assignments on a variable\n\t\n\tbool HasCachedNumericValue(void) const;\n\tdouble CachedNumericValue(void) const;\n\t\n\tvoid PrintToken(std::ostream &p_outstream) const;\n\tvoid PrintTreeWithIndent(std::ostream &p_outstream, int p_indent) const;\n\t\n\tEidosErrorPosition ErrorPositionForNodeAndChildren(void) const;\n\t\n#if (SLIMPROFILING == 1)\n\t// PROFILING\n\tvoid ZeroProfileTotals(void) const;\n\teidos_profile_t ConvertProfileTotalsToSelfCounts(void) const;\n\teidos_profile_t TotalOfSelfCounts(void) const;\n\t\n\tvoid FullUTF8Range(int32_t *p_start, int32_t *p_end) const;\n\tvoid FullUTF16Range(int32_t *p_start, int32_t *p_end) const;\n#endif\n};\n\n\n#endif /* defined(__Eidos__eidos_ast_node__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_beep.cpp",
    "content": "//\n//  eidos_beep.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 5/4/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_beep.h\"\n\n#include <stdio.h>\n#include <sys/stat.h> \n#include <fcntl.h>\n#include <unistd.h>\n\n\n// The base implementation, defined below\nstatic std::string Eidos_Beep_BASE(const std::string &p_sound_name);\n\n// The function pointer that delivers whatever platform-specific implementation we want to use\nstd::string (*Eidos_Beep)(const std::string &p_sound_name) = &Eidos_Beep_BASE;\n\n\n// This code is derived from the code of the beep utility, by Johnathan Nightingale, found at https://github.com/johnath/beep\n// Much of the guts of that code has been removed, since we don't need the command-line parsing, and we don't want to\n// generate tones of specified frequency etc., so this is pretty trivial, but still, credit where credit is due...\n\n/* This code is copyright (C) Johnathan Nightingale, 2000.\n *\n * This code may distributed only under the terms of the GNU Public License \n * which can be found at http://www.gnu.org/copyleft or in the file COPYING \n * supplied with this code.\n *\n * This code is not distributed with warranties of any kind, including implied\n * warranties of merchantability or fitness for a particular use or ability to \n * breed pandas in captivity, it just can't be done.\n *\n */\n\nstd::string Eidos_Beep_BASE(const std::string &p_sound_name)\n{\n#pragma unused (p_sound_name)\n\t// Find a device to output to.  The beep utility uses /dev/tty0 or /dev/vc/0, but those do not seem to work on OS X;\n\t// I think perhaps this usage of them is a Linux-only thing?  No idea.  The mysteries of Unix.  So on OS X, we fall\n\t// through to the printf(\"\\a\"), which outputs a \\a to the output stream, unfortunately; undesirable but apparently\n\t// unavoidable.  We will have to document that using beep() may result in \\a characters in the output stream.\n\tint console_fd = open(\"/dev/tty0\", O_WRONLY);\n\t\n\tif (console_fd == -1)\n\t\tconsole_fd = open(\"/dev/vc/0\", O_WRONLY);\n\t\n\tif (console_fd == -1)\n\t{\n\t\tstatic bool been_here = false;\n\t\t\n\t\tprintf(\"\\a\");\t// Output the only beep we can; note this might corrupt the output stream...\n\t\t\n\t\t// Output an error message only once...\n\t\tif (been_here)\n\t\t\treturn \"\";\n\t\t\n\t\tbeen_here = true;\n\t\treturn \"#WARNING (Eidos_Beep_BASE): function beep() could not open /dev/tty0 or /dev/vc/0 for writing; output stream may contain control characters to produce beeps.\";\n\t}\n\t\n\t// Output a '\\a', which rings the bell.  All the other stuff in the beep utility seems to be Linux-specific...\n\tputchar('\\a');\n\t\n\t// Close the console to clean up\n\tclose(console_fd);\n\t\n\treturn \"\";\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_beep.h",
    "content": "//\n//  eidos_beep.h\n//  Eidos\n//\n//  Created by Ben Haller on 5/4/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_beep__\n#define __Eidos__eidos_beep__\n\n\n#include <string>\n\n\n// This function is defined in eidos_beep.cpp in the command-line case, and in EidosCocoaExtra.mm in the GUI case, since\n// we want a completely different implementation in the two cases.\nextern std::string (*Eidos_Beep)(const std::string &p_sound_name);\n\n\n#endif /* __Eidos__eidos_beep__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_call_signature.cpp",
    "content": "//\n//  eidos_function_signature.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 5/16/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_call_signature.h\"\n\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"eidos_value.h\"\n\n\n//\n//\tEidosCallSignature\n//\n#pragma mark -\n#pragma mark EidosCallSignature\n#pragma mark -\n\nEidosCallSignature::EidosCallSignature(const std::string &p_call_name, EidosValueMask p_return_mask)\n\t: call_name_(p_call_name), call_id_(EidosStringRegistry::GlobalStringIDForString(p_call_name)), return_mask_(p_return_mask), return_class_(nullptr)\n{\n}\n\nEidosCallSignature::EidosCallSignature(const std::string &p_call_name, EidosValueMask p_return_mask, const EidosClass *p_return_class)\n\t: call_name_(p_call_name), call_id_(EidosStringRegistry::GlobalStringIDForString(p_call_name)), return_mask_(p_return_mask), return_class_(p_return_class)\n{\n}\n\nEidosCallSignature::~EidosCallSignature(void)\n{\n}\n\nEidosCallSignature *EidosCallSignature::AddArg(EidosValueMask p_arg_mask, const std::string &p_argument_name, const EidosClass *p_argument_class)\n{\n\treturn AddArgWithDefault(p_arg_mask, p_argument_name, p_argument_class, EidosValue_SP(nullptr));\n}\n\n//NOLINTNEXTLINE : clang-tidy doesn't like that p_default_value gets copied instead of passed by reference, but I prefer this\nEidosCallSignature *EidosCallSignature::AddArgWithDefault(EidosValueMask p_arg_mask, const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value, bool p_fault_tolerant)\n{\n\tbool is_optional = !!(p_arg_mask & kEidosValueMaskOptional);\n\t\n\t// If we're doing a fault-tolerant parse and the signature is badly malformed, we just don't add the offending argument\n\tif (has_optional_args_ && !is_optional)\n\t{\n\t\tif (p_fault_tolerant)\n\t\t\treturn this;\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) cannot add a required argument after an optional argument has been added.\" << EidosTerminate(nullptr);\n\t}\n\tif (p_argument_name.size() == 0)\n\t{\n\t\tif (p_fault_tolerant)\n\t\t\treturn this;\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) an argument name is required.\" << EidosTerminate(nullptr);\n\t}\n\tif (p_argument_class && !(p_arg_mask & kEidosValueMaskObject))\n\t{\n\t\tif (p_fault_tolerant)\n\t\t\treturn this;\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) an object element type may only be supplied for an argument of object type.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Default values should be marked constant, just to be safe.  We just make a copy here;\n\t// it's not worth trying to avoid that, since this is just startup overhead.\n\t// BCH: Note that copying removes the invisible flag that we use internally in some spots;\n\t// we therefore note here whether the original value was invisible NULL, for reference below.\n\tbool default_value_is_invisible_NULL = (p_default_value.get() == gStaticEidosValueNULLInvisible);\n\t\n\tif (p_default_value)\n\t{\n\t\tp_default_value = p_default_value->CopyValues();\n\t\tp_default_value->MarkAsConstant();\n\t}\n\t\n\targ_masks_.emplace_back(p_arg_mask);\n\targ_names_.emplace_back(p_argument_name);\n\targ_name_IDs_.emplace_back(EidosStringRegistry::GlobalStringIDForString(p_argument_name));\n\targ_classes_.emplace_back(p_argument_class);\n\targ_defaults_.emplace_back(p_default_value);\n\t\n\tif (is_optional)\n\t\thas_optional_args_ = true;\n\t\n\t// If we're doing a fault-tolerant parse, skip the rest; we're not going to raise anyway, so there's no point in checking\n\tif (p_fault_tolerant)\n\t\treturn this;\n\t\n\t// Check the default argument; see CheckArguments() for parallel code\n\tif (is_optional && !p_default_value)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) no default argument supplied for optional argument.\" << EidosTerminate(nullptr);\n\tif (!is_optional && p_default_value)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) default argument supplied for required argument.\" << EidosTerminate(nullptr);\n\t\n\tif (is_optional)\n\t{\n\t\tEidosValueMask type_mask = p_arg_mask;\n\t\tbool requires_singleton = !!(type_mask & kEidosValueMaskSingleton);\n\t\t\n\t\ttype_mask &= kEidosValueMaskFlagStrip;\n\t\t\n\t\t// an argument was passed, so check its type\n\t\tEidosValue *argument = p_default_value.get();\n\t\tEidosValueType arg_type = argument->Type();\n\t\t\n\t\tif ((type_mask != kEidosValueMaskAny) && !default_value_is_invisible_NULL)\t// allow gStaticEidosValueNULLInvisible as a default even if the argument is not labelled as taking NULL; this is for internal use only\n\t\t{\n\t\t\tbool type_ok = true;\n\t\t\t\n\t\t\tswitch (arg_type)\n\t\t\t{\n\t\t\t\tcase EidosValueType::kValueVOID:\ttype_ok = false;\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\tcase EidosValueType::kValueNULL:\ttype_ok = !!(type_mask & kEidosValueMaskNULL);\t\tbreak;\n\t\t\t\tcase EidosValueType::kValueLogical:\ttype_ok = !!(type_mask & kEidosValueMaskLogical);\tbreak;\n\t\t\t\tcase EidosValueType::kValueString:\ttype_ok = !!(type_mask & kEidosValueMaskString);\tbreak;\n\t\t\t\tcase EidosValueType::kValueInt:\t\ttype_ok = !!(type_mask & kEidosValueMaskInt);\t\tbreak;\n\t\t\t\tcase EidosValueType::kValueFloat:\ttype_ok = !!(type_mask & kEidosValueMaskFloat);\t\tbreak;\n\t\t\t\tcase EidosValueType::kValueObject:\n\t\t\t\t\ttype_ok = !!(type_mask & kEidosValueMaskObject);\n\t\t\t\t\t\n\t\t\t\t\t// If the argument is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t\t\t// in the signature, check the object element type of the argument.  Note this uses pointer equality!\n\t\t\t\t\tconst EidosClass *signature_class = p_argument_class;\n\t\t\t\t\t\n\t\t\t\t\tif (type_ok && signature_class)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst EidosClass *argument_class = ((EidosValue_Object *)argument)->Class();\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (argument_class != signature_class)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Empty object vectors of undefined class are allowed to be passed for type-specified parameters; such vectors are generic\n\t\t\t\t\t\t\tif ((argument_class == gEidosObject_Class) && (argument->Count() == 0))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) default argument cannot be object element type \" << argument->ElementType() << \"; expected object element type \" << signature_class->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!type_ok)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) default argument cannot be type \" << arg_type << \".\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// if NULL is explicitly permitted by the signature, we skip the singleton check\n\t\t\tif (requires_singleton && (argument->Count() != 1) && (arg_type != EidosValueType::kValueNULL))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddArgWithDefault): (internal error) default argument must be a singleton (size() == 1), but size() == \" << argument->Count() << \".\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\treturn this;\n}\n\nEidosCallSignature *EidosCallSignature::AddEllipsis(void)\n{\n\tif (has_optional_args_)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddEllipsis): cannot add an ellipsis after an optional argument has been added.\" << EidosTerminate(nullptr);\n\t\n\tif (has_ellipsis_)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::AddEllipsis): cannot add more than one ellipsis.\" << EidosTerminate(nullptr);\n\t\n\targ_masks_.emplace_back(kEidosValueMaskAny);\n\targ_names_.emplace_back(gEidosStr_ELLIPSIS);\n\targ_name_IDs_.emplace_back(gEidosID_ELLIPSIS);\n\targ_classes_.emplace_back(nullptr);\n\targ_defaults_.emplace_back(nullptr);\n\t\n\thas_ellipsis_ = true;\n\t\n\treturn this;\n}\n\nEidosCallSignature *EidosCallSignature::AddLogical(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskLogical, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddInt(const std::string &p_argument_name)\t\t\t\t{ return AddArg(kEidosValueMaskInt, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddFloat(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskFloat, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntString(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskString, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddString(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskString, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddNumeric(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskNumeric, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskLogicalEquiv, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddAnyBase(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskAnyBase, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddAny(const std::string &p_argument_name)\t\t\t\t{ return AddArg(kEidosValueMaskAny, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntObject(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskObject, p_argument_name, p_argument_class); }\nEidosCallSignature *EidosCallSignature::AddObject(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t\t{ return AddArg(kEidosValueMaskObject, p_argument_name, p_argument_class); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddInt_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddFloat_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskFloat | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntString_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddString_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskString | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddNumeric_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskNumeric | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskLogicalEquiv | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddAnyBase_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskAnyBase | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddAny_O(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskAny | kEidosValueMaskOptional, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntObject_O(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskOptional, p_argument_name, p_argument_class, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddObject_O(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskObject | kEidosValueMaskOptional, p_argument_name, p_argument_class, std::move(p_default_value)); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_S(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskLogical | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddInt_S(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddFloat_S(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskFloat | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntString_S(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddString_S(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskString | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddNumeric_S(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskNumeric | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_S(const std::string &p_argument_name)\t{ return AddArg(kEidosValueMaskLogicalEquiv | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddAnyBase_S(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskAnyBase | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddAny_S(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskAny | kEidosValueMaskSingleton, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntObject_S(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskSingleton, p_argument_name, p_argument_class); }\nEidosCallSignature *EidosCallSignature::AddObject_S(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t\t{ return AddArg(kEidosValueMaskObject | kEidosValueMaskSingleton, p_argument_name, p_argument_class); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddInt_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddFloat_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskFloat | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntString_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddString_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddNumeric_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskNumeric | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskLogicalEquiv | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddAnyBase_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskAnyBase | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddAny_OS(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskAny | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntObject_OS(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, p_argument_class, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddObject_OS(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton, p_argument_name, p_argument_class, std::move(p_default_value)); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_N(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskLogical | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddInt_N(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddFloat_N(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskFloat | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntString_N(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddString_N(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskString | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddNumeric_N(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskNumeric | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_N(const std::string &p_argument_name)\t{ return AddArg(kEidosValueMaskLogicalEquiv | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntObject_N(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskNULL, p_argument_name, p_argument_class); }\nEidosCallSignature *EidosCallSignature::AddObject_N(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t\t{ return AddArg(kEidosValueMaskObject | kEidosValueMaskNULL, p_argument_name, p_argument_class); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddInt_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddFloat_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskFloat | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntString_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddString_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddNumeric_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskNumeric | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_ON(const std::string &p_argument_name, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskLogicalEquiv | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntObject_ON(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, p_argument_class, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddObject_ON(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskNULL, p_argument_name, p_argument_class, std::move(p_default_value)); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_SN(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskLogical | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddInt_SN(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddFloat_SN(const std::string &p_argument_name)\t\t\t{ return AddArg(kEidosValueMaskFloat | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntString_SN(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddString_SN(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskString | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddNumeric_SN(const std::string &p_argument_name)\t\t{ return AddArg(kEidosValueMaskNumeric | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_SN(const std::string &p_argument_name)\t{ return AddArg(kEidosValueMaskLogicalEquiv | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr); }\nEidosCallSignature *EidosCallSignature::AddIntObject_SN(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t{ return AddArg(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, p_argument_class); }\nEidosCallSignature *EidosCallSignature::AddObject_SN(const std::string &p_argument_name, const EidosClass *p_argument_class)\t\t{ return AddArg(kEidosValueMaskObject | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, p_argument_class); }\n\nEidosCallSignature *EidosCallSignature::AddLogical_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddInt_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddFloat_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskFloat | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntString_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddString_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddNumeric_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskNumeric | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddLogicalEquiv_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value)\t{ return AddArgWithDefault(kEidosValueMaskLogicalEquiv | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, nullptr, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddIntObject_OSN(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskInt | kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, p_argument_class, std::move(p_default_value)); }\nEidosCallSignature *EidosCallSignature::AddObject_OSN(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value)\t\t{ return AddArgWithDefault(kEidosValueMaskObject | kEidosValueMaskOptional | kEidosValueMaskSingleton | kEidosValueMaskNULL, p_argument_name, p_argument_class, std::move(p_default_value)); }\n\nEidosCallSignature *EidosCallSignature::MarkDeprecated(void)\n{\n\t// At present, the only consequence of deprecation is that the property/method is not listed in the documentation\n\tdeprecated_ = true;\n\treturn this;\n}\n\nvoid EidosCallSignature::CheckArgument(EidosValue *p_argument, int p_signature_index) const\n{\n\tEidosValueType arg_type = p_argument->Type();\n\t\n\tif (has_ellipsis_ && (arg_name_IDs_[p_signature_index] == gEidosID_ELLIPSIS))\n\t{\n\t\t// If we're checking against the ellipsis argument, the only rule is that it can't be void\n\t\tif (arg_type == EidosValueType::kValueVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") cannot be type \" << arg_type << \" for \" << CallType() << \" \" << call_name_ << \"().\" << EidosTerminate(nullptr);\n\t}\n\telse\n\t{\n\t\tEidosValueMask type_mask_unstripped = arg_masks_[p_signature_index];\n\t\tEidosValueMask type_mask = (type_mask_unstripped & kEidosValueMaskFlagStrip);\n\t\tbool type_ok;\n\t\t\n\t\tswitch (arg_type)\n\t\t{\n\t\t\tcase EidosValueType::kValueVOID:\ttype_ok = false; break;\t\t// never legal regardless of type_mask; void may never be passed as a parameter\n\t\t\tcase EidosValueType::kValueNULL:\n\t\t\t{\n\t\t\t\tif (type_mask & kEidosValueMaskNULL)\n\t\t\t\t\treturn;\n\t\t\t\t\n\t\t\t\ttype_ok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosValueType::kValueLogical:\ttype_ok = !!(type_mask & kEidosValueMaskLogical);\tbreak;\n\t\t\tcase EidosValueType::kValueString:\ttype_ok = !!(type_mask & kEidosValueMaskString);\tbreak;\n\t\t\tcase EidosValueType::kValueInt:\t\ttype_ok = !!(type_mask & kEidosValueMaskInt);\t\tbreak;\n\t\t\tcase EidosValueType::kValueFloat:\ttype_ok = !!(type_mask & kEidosValueMaskFloat);\t\tbreak;\n\t\t\tcase EidosValueType::kValueObject:\n\t\t\t{\n\t\t\t\ttype_ok = !!(type_mask & kEidosValueMaskObject);\n\t\t\t\t\n\t\t\t\t// If the argument is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t\t// in the signature, check the object element type of the argument.  Note this uses pointer equality!\n\t\t\t\tconst EidosClass *signature_class = arg_classes_[p_signature_index];\n\t\t\t\t\n\t\t\t\tif (type_ok && signature_class)\n\t\t\t\t{\n\t\t\t\t\tconst EidosClass *argument_class = ((EidosValue_Object *)p_argument)->Class();\n\t\t\t\t\t\n\t\t\t\t\tif (argument_class != signature_class)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Empty object vectors of undefined class are allowed to be passed for type-specified parameters; such vectors are generic\n\t\t\t\t\t\tif ((argument_class == gEidosObject_Class) && (p_argument->Count() == 0))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!argument_class->IsSubclassOfClass(signature_class))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" cannot be object element type \" << p_argument->ElementType() << \" for \" << CallType() << \" \" << call_name_ << \"(); expected object element type \" << signature_class->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: type_ok = false; break;\t// never hit, here to make the Ubuntu compiler happy\n\t\t}\n\t\t\n\t\tif (!type_ok)\n\t\t{\n\t\t\t// We have special error-handling for apply() because sapply() used to be named apply() and we want to steer users to the new call\n\t\t\tif ((call_name_ == \"apply\") && (arg_type == EidosValueType::kValueString))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") cannot be type \" << arg_type << \" for \" << CallType() << \" \" << call_name_ << \"().\" << std::endl << \"NOTE: The apply() function was renamed sapply() in Eidos 1.6, and a new function named apply() has been added; you may need to change this call to be a call to sapply() instead.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// Special error-handling for defineSpatialMap() because its gridSize parameter was removed in SLiM 3.5\n\t\t\tif ((call_name_ == \"defineSpatialMap\") &&\n\t\t\t\t(((p_signature_index == 2) && (arg_type == EidosValueType::kValueNULL)) ||\n\t\t\t\t ((p_signature_index == 3) && ((arg_type == EidosValueType::kValueFloat) || (arg_type == EidosValueType::kValueInt))) ||\n\t\t\t\t ((p_signature_index == 4) && (arg_type == EidosValueType::kValueLogical))))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") cannot be type \" << arg_type << \" for \" << CallType() << \" \" << call_name_ << \"().\" << std::endl << \"NOTE: The defineSpatialMap() method was changed in SLiM 3.5, breaking backward compatibility.  Please see the manual for guidance on updating your code.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// Special error-handling for initializeSLiMOptions() because its mutationRuns parameter changed to doMutationRunExperiments, and changed from integer to logical\n\t\t\tif ((call_name_ == \"initializeSLiMOptions\") && (p_signature_index == 3) && (arg_type == EidosValueType::kValueInt))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") cannot be type \" << arg_type << \" for \" << CallType() << \" \" << call_name_ << \"().\" << std::endl << \"NOTE: The mutationRuns parameter to initializeSLiMOptions() was changed in SLiM 5, breaking backward compatibility.  Please see the manual for guidance on updating your code.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") cannot be type \" << arg_type << \" for \" << CallType() << \" \" << call_name_ << \"().\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// if the argument is NULL, this singleton check is skipped by the continue statement above\n\t\tif ((type_mask_unstripped & kEidosValueMaskSingleton) && (p_argument->Count() != 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArgument): argument \" << p_signature_index + 1 << \" (\" << arg_names_[p_signature_index] << \") must be a singleton (size() == 1) for \" << CallType() << \" \" << call_name_ << \"(), but size() == \" << p_argument->Count() << \".\" << EidosTerminate(nullptr);\n\t}\n}\n\nvoid EidosCallSignature::CheckArguments(const std::vector<EidosValue_SP> &p_arguments) const\n{\n\tsize_t argument_count = p_arguments.size();\n\tsize_t arg_masks_size = arg_masks_.size();\n\tsize_t minimum_arg_count = (has_ellipsis_ ? arg_masks_size - 1 : arg_masks_size);\t// if there is an ellipsis, it is optional, but it occupies one argument slot\n\t\n\t// Check the number of arguments supplied; note that now our function dispatch code guarantees that every argument is present, including optional arguments\n\tif (!has_ellipsis_ && (argument_count > arg_masks_size))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArguments): \" << CallType() << \" \" << call_name_ << \"() requires at most \" << minimum_arg_count << \" argument(s), but \" << argument_count << \" are supplied (after incorporating default arguments).\" << EidosTerminate(nullptr);\n\t\n\tif (argument_count < minimum_arg_count)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckArguments): \" << CallType() << \" \" << call_name_ << \"() requires \" << minimum_arg_count << \" argument(s), but \" << argument_count << \" are supplied (after incorporating default arguments).\" << EidosTerminate(nullptr);\n\t\n\t// Check the types of all arguments specified in the signature\n\tint signature_index = 0;\n\t\n\tfor (unsigned int arg_index = 0; arg_index < argument_count; ++arg_index, ++signature_index)\n\t{\n\t\t// If the current signature index is an ellipsis, deal with it completely here; just check the ellipsis arguments for void\n\t\tif (arg_name_IDs_[signature_index] == gEidosID_ELLIPSIS)\n\t\t{\n\t\t\tint first_ellipsis = arg_index;\n\t\t\tint last_ellipsis = first_ellipsis + (int)(argument_count - minimum_arg_count) - 1;\n\t\t\t\n\t\t\tfor (int ellipsis_index = first_ellipsis; ellipsis_index <= last_ellipsis; ++ellipsis_index)\n\t\t\t\tCheckArgument(p_arguments[ellipsis_index].get(), signature_index);\n\t\t\t\n\t\t\t++signature_index;\n\t\t\targ_index = last_ellipsis + 1;\n\t\t\tif (arg_index == argument_count)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tCheckArgument(p_arguments[arg_index].get(), signature_index);\n\t}\n}\n\nvoid EidosCallSignature::CheckReturn(const EidosValue &p_result) const\n{\n\tuint32_t retmask = return_mask_;\n\tbool return_type_ok = true;\n\t\n\tswitch (p_result.Type())\n\t{\n\t\tcase EidosValueType::kValueVOID:\treturn_type_ok = !!(retmask & kEidosValueMaskVOID);\t\tbreak;\n\t\tcase EidosValueType::kValueNULL:\n\t\t{\n\t\t\t// A return type of NULL is always allowed, in fact; we don't want to have to specify this in the return type\n\t\t\t// This is a little fishy, but since NULL is used to indicate error conditions, NULL returns are exceptional,\n\t\t\t// and the return type indicates the type ordinarily returned in non-exceptional cases.  We just return here,\n\t\t\t// since we also don't want to do the singleton check below (since it would raise too).\n\t\t\t\n\t\t\t// BCH 23 March 2018: We do not allow a return of NULL from functions that are declared as returning void.\n\t\t\tif (retmask == kEidosValueMaskVOID)\n\t\t\t{\n\t\t\t\treturn_type_ok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase EidosValueType::kValueLogical:\treturn_type_ok = !!(retmask & kEidosValueMaskLogical);\tbreak;\n\t\tcase EidosValueType::kValueInt:\t\treturn_type_ok = !!(retmask & kEidosValueMaskInt);\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\treturn_type_ok = !!(retmask & kEidosValueMaskFloat);\tbreak;\n\t\tcase EidosValueType::kValueString:\treturn_type_ok = !!(retmask & kEidosValueMaskString);\tbreak;\n\t\tcase EidosValueType::kValueObject:\n\t\t\treturn_type_ok = !!(retmask & kEidosValueMaskObject);\n\t\t\t\n\t\t\t// If the return is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t// in the signature, check the object element type of the return.  Note this uses pointer equality!\n\t\t\tif (return_type_ok && return_class_ && (((EidosValue_Object &)p_result).Class() != return_class_))\n\t\t\t{\n\t\t\t\tif (!((EidosValue_Object &)p_result).Class()->IsSubclassOfClass(return_class_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckReturn): object return value cannot be element type \" << p_result.ElementType() << \" for \" << CallType() << \" \" << call_name_ << \"(); expected object element type \" << return_class_->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t\n\tif (!return_type_ok)\n\t{\n\t\t// We try to emit more helpful error messages when void is involved in the type mismatch\n\t\tif (retmask == kEidosValueMaskVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckReturn): return value must be void for \" << CallType() << \" \" << call_name_ << \"(); use a \\\"return;\\\" statement if you wish to explicitly return with no return value.\" << EidosTerminate(nullptr);\n\t\telse if (p_result.Type() == EidosValueType::kValueVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckReturn): return value cannot be void for \" << CallType() << \" \" << call_name_ << \"(); use a \\\"return\\\" statement to explicitly return a value.\" << EidosTerminate(nullptr);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckReturn): return value cannot be type \" << p_result.Type() << \" for \" << CallType() << \" \" << call_name_ << \"().\" << EidosTerminate(nullptr);\n\t}\n\t\n\tbool return_is_singleton = !!(retmask & kEidosValueMaskSingleton);\n\t\n\tif (return_is_singleton && (p_result.Count() != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckReturn): return value must be a singleton (size() == 1) for \" << CallType() << \" \" << call_name_ << \"(), but size() == \" << p_result.Count() << \".\" << EidosTerminate(nullptr);\n}\n\nvoid EidosCallSignature::CheckAggregateReturn(const EidosValue &p_result, size_t p_expected_size) const\n{\n\tuint32_t retmask = return_mask_;\n\tbool return_type_ok = true;\n\t\n\tswitch (p_result.Type())\n\t{\n\t\tcase EidosValueType::kValueVOID:\treturn_type_ok = !!(retmask & kEidosValueMaskVOID);\t\tbreak;\n\t\tcase EidosValueType::kValueNULL:\n\t\t{\n\t\t\t// A return type of NULL is always allowed, in fact; we don't want to have to specify this in the return type\n\t\t\t// This is a little fishy, but since NULL is used to indicate error conditions, NULL returns are exceptional,\n\t\t\t// and the return type indicates the type ordinarily returned in non-exceptional cases.  We just return here,\n\t\t\t// since we also don't want to do the singleton check below (since it would raise too).\n\t\t\t\n\t\t\t// BCH 23 March 2018: We do not allow a return of NULL from functions that are declared as returning void.\n\t\t\tif (retmask == kEidosValueMaskVOID)\n\t\t\t{\n\t\t\t\treturn_type_ok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t\tcase EidosValueType::kValueLogical:\treturn_type_ok = !!(retmask & kEidosValueMaskLogical);\tbreak;\n\t\tcase EidosValueType::kValueInt:\t\treturn_type_ok = !!(retmask & kEidosValueMaskInt);\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\treturn_type_ok = !!(retmask & kEidosValueMaskFloat);\tbreak;\n\t\tcase EidosValueType::kValueString:\treturn_type_ok = !!(retmask & kEidosValueMaskString);\tbreak;\n\t\tcase EidosValueType::kValueObject:\n\t\t\treturn_type_ok = !!(retmask & kEidosValueMaskObject);\n\t\t\t\n\t\t\t// If the return is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t// in the signature, check the object element type of the return.  Note this uses pointer equality!\n\t\t\tif (return_type_ok && return_class_ && (((EidosValue_Object &)p_result).Class() != return_class_))\n\t\t\t{\n\t\t\t\tif (!((EidosValue_Object &)p_result).Class()->IsSubclassOfClass(return_class_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckAggregateReturn): object return value cannot be element type \" << p_result.ElementType() << \" for \" << CallType() << \" \" << call_name_ << \"(); expected object element type \" << return_class_->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t\n\tif (!return_type_ok)\n\t{\n\t\t// We try to emit more helpful error messages when void is involved in the type mismatch\n\t\tif (retmask == kEidosValueMaskVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckAggregateReturn): return value must be void for \" << CallType() << \" \" << call_name_ << \"(); use a \\\"return;\\\" statement if you wish to explicitly return with no return value.\" << EidosTerminate(nullptr);\n\t\telse if (p_result.Type() == EidosValueType::kValueVOID)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckAggregateReturn): return value cannot be void for \" << CallType() << \" \" << call_name_ << \"(); use a \\\"return\\\" statement to explicitly return a value.\" << EidosTerminate(nullptr);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckAggregateReturn): return value cannot be type \" << p_result.Type() << \" for \" << CallType() << \" \" << call_name_ << \"().\" << EidosTerminate(nullptr);\n\t}\n\t\n\tbool return_is_singleton = !!(retmask & kEidosValueMaskSingleton);\n\t\n\tif (return_is_singleton && ((size_t)p_result.Count() > p_expected_size))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosCallSignature::CheckAggregateReturn): return value must be a singleton (size() == 1) for \" << CallType() << \" \" << call_name_ << \".\" << EidosTerminate(nullptr);\n}\n\nstd::string EidosCallSignature::CallDelegate(void) const\n{\n\treturn \"\";\n}\n\nstd::string EidosCallSignature::SignatureString(void) const\n{\n\tstd::ostringstream ss;\n\t\n\tss << *this;\n\t\n\treturn ss.str();\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosCallSignature &p_signature)\n{\n\t//\n\t//\tNote this logic is paralleled in +[NSAttributedString eidosAttributedStringForCallSignature:].\n\t//\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n\t//\n\t\n\tp_outstream << p_signature.CallPrefix();\t// \"\", \"– \", or \"+ \" depending on our subclass\n\t\n\tp_outstream << \"(\" << StringForEidosValueMask(p_signature.return_mask_, p_signature.return_class_, \"\", nullptr);\n\t\n\tp_outstream << \")\" << p_signature.call_name_ << \"(\";\n\t\n\tint arg_mask_count = (int)p_signature.arg_masks_.size();\n\t\n\tif (arg_mask_count == 0)\n\t{\n\t\tp_outstream << gEidosStr_void;\n\t}\n\telse\n\t{\n\t\tfor (int arg_index = 0; arg_index < arg_mask_count; ++arg_index)\n\t\t{\n\t\t\tEidosValueMask type_mask = p_signature.arg_masks_[arg_index];\n\t\t\tconst std::string &arg_name = p_signature.arg_names_[arg_index];\n\t\t\tconst EidosClass *arg_obj_class = p_signature.arg_classes_[arg_index];\n\t\t\tEidosValue_SP arg_default = p_signature.arg_defaults_[arg_index];\n\t\t\t\n\t\t\t// skip private arguments\n\t\t\tif ((arg_name.length() >= 1) && (arg_name[0] == '_'))\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tif (arg_index > 0)\n\t\t\t\tp_outstream << \", \";\n\t\t\t\n\t\t\tp_outstream << StringForEidosValueMask(type_mask, arg_obj_class, arg_name, arg_default.get());\n\t\t}\n\t}\n\t\n\tp_outstream << \")\";\n\t\n\t// if the function is provided by a delegate, show the delegate's name\n\tp_outstream << p_signature.CallDelegate();\n\t\n\treturn p_outstream;\n}\n\nbool CompareEidosCallSignatures(const EidosCallSignature_CSP &p_i, const EidosCallSignature_CSP &p_j)\n{\n\treturn (p_i->call_name_ < p_j->call_name_);\n}\n\n\n//\n//\tEidosFunctionSignature\n//\n#pragma mark -\n#pragma mark EidosFunctionSignature\n#pragma mark -\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask)\n\t: EidosCallSignature(p_function_name, p_return_mask), internal_function_(p_function_ptr)\n{\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, const EidosClass *p_return_class)\n\t: EidosCallSignature(p_function_name, p_return_mask, p_return_class), internal_function_(p_function_ptr)\n{\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, std::string p_delegate_name)\n\t: EidosCallSignature(p_function_name, p_return_mask), internal_function_(p_function_ptr), delegate_name_(std::move(p_delegate_name))\n{\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, const EidosClass *p_return_class, std::string p_delegate_name)\n\t: EidosCallSignature(p_function_name, p_return_mask, p_return_class), internal_function_(p_function_ptr), delegate_name_(std::move(p_delegate_name))\n{\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask)\n\t: EidosCallSignature(p_function_name, p_return_mask)\n{\n\tProcessEidosScript(p_script_string);\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, const EidosClass *p_return_class)\n\t: EidosCallSignature(p_function_name, p_return_mask, p_return_class)\n{\n\tProcessEidosScript(p_script_string);\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, std::string p_delegate_name)\n\t: EidosCallSignature(p_function_name, p_return_mask), delegate_name_(std::move(p_delegate_name))\n{\n\tProcessEidosScript(p_script_string);\n}\n\nEidosFunctionSignature::EidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, const EidosClass *p_return_class, std::string p_delegate_name)\n\t: EidosCallSignature(p_function_name, p_return_mask, p_return_class), delegate_name_(std::move(p_delegate_name))\n{\n\tProcessEidosScript(p_script_string);\n}\n\nvoid EidosFunctionSignature::ProcessEidosScript(const std::string &p_script_string)\n{\n\t// This method is for built-in functions implemented in Eidos; they have no position in the user's script string\n\tEidosScript *source_script = new EidosScript(p_script_string);\n\t\n\tsource_script->Tokenize();\n\tsource_script->ParseInterpreterBlockToAST(false);\n\t\n\tbody_script_ = source_script;\n}\n\nEidosFunctionSignature::~EidosFunctionSignature(void)\n{\n\tif (body_script_)\n\t\tdelete body_script_;\n}\n\nstd::string EidosFunctionSignature::CallType(void) const\n{\n\treturn \"function\";\n}\n\nstd::string EidosFunctionSignature::CallPrefix(void) const\n{\n\treturn \"\";\n}\n\nstd::string EidosFunctionSignature::CallDelegate(void) const\n{\n\tif (delegate_name_.size())\n\t{\n\t\tstd::string delegate_tag;\n\t\t\n\t\tdelegate_tag += \" <\";\n\t\tdelegate_tag += delegate_name_;\n\t\tdelegate_tag += \">\";\n\t\t\n\t\treturn delegate_tag;\n\t}\n\t\n\treturn \"\";\n}\n\nbool CompareEidosFunctionSignatures(const EidosFunctionSignature_CSP &p_i, const EidosFunctionSignature_CSP &p_j)\n{\n\treturn (p_i->call_name_ < p_j->call_name_);\n}\n\n\n//\n//\tEidosMethodSignature\n//\n#pragma mark -\n#pragma mark EidosMethodSignature\n#pragma mark -\n\nEidosMethodSignature::EidosMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, bool p_is_class_method)\n\t: EidosCallSignature(p_function_name, p_return_mask), is_class_method(p_is_class_method)\n{\n}\n\nEidosMethodSignature::EidosMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class, bool p_is_class_method)\n\t: EidosCallSignature(p_function_name, p_return_mask, p_return_class), is_class_method(p_is_class_method)\n{\n}\n\nstd::string EidosMethodSignature::CallType(void) const\n{\n\treturn \"method\";\n}\n\nEidosMethodSignature::~EidosMethodSignature(void)\n{\n}\n\n\n//\n//\tEidosInstanceMethodSignature\n//\n#pragma mark -\n#pragma mark EidosInstanceMethodSignature\n#pragma mark -\n\nEidosInstanceMethodSignature::EidosInstanceMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask)\n\t: EidosMethodSignature(p_function_name, p_return_mask, false), accelerated_imp_(false)\n{\n}\n\nEidosInstanceMethodSignature::EidosInstanceMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class)\n\t: EidosMethodSignature(p_function_name, p_return_mask, p_return_class, false), accelerated_imp_(false)\n{\n}\n\nstd::string EidosInstanceMethodSignature::CallPrefix(void) const\n{\n\treturn \"–\\u00A0\";\t// en-dash, non-breaking space\n}\n\nEidosInstanceMethodSignature::~EidosInstanceMethodSignature(void)\n{\n}\n\nEidosInstanceMethodSignature *EidosInstanceMethodSignature::DeclareAcceleratedImp(Eidos_AcceleratedMethodImp p_imper)\n{\n\t/*\n\t BCH 1/2/2023: Commented out these checks.  They are well-intentioned but excessively strict.  The class itself knows\n\t what it is doing.  Some methods might consistently return all one type or all a different type, depending on the\n\t parameters passed; there is nothing wrong with that.  It would be more unusual, but the same is technically true\n\t for the object element class, too.  And in the end, the implementation could concatenate values of different types\n\t together on its own, if that turned out to be necessary.  I'm removing this because it is now in the way.\n\t \n\tuint32_t retmask = (return_mask_ & kEidosValueMaskFlagStrip);\n\t\n\tif ((retmask != kEidosValueMaskVOID) && \n\t\t(retmask != kEidosValueMaskNULL) && \n\t\t(retmask != kEidosValueMaskLogical) && \n\t\t(retmask != kEidosValueMaskInt) && \n\t\t(retmask != kEidosValueMaskFloat) && \n\t\t(retmask != kEidosValueMaskString) && \n\t\t(retmask != kEidosValueMaskObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInstanceMethodSignature::DeclareAcceleratedImp): (internal error) only methods returning one guaranteed type may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\tif ((retmask == (kEidosValueMaskObject | kEidosValueMaskSingleton)) && (return_class_ == nullptr))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInstanceMethodSignature::DeclareAcceleratedImp): (internal error) only object methods that declare their class may be accelerated.\" << EidosTerminate(nullptr);\n\t*/\n\t\n\taccelerated_imp_ = true;\n\taccelerated_imper_ = p_imper;\n\t\n\treturn this;\n}\n\n\n//\n//\tEidosClassMethodSignature\n//\n#pragma mark -\n#pragma mark EidosClassMethodSignature\n#pragma mark -\n\nEidosClassMethodSignature::EidosClassMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask)\n\t: EidosMethodSignature(p_function_name, p_return_mask, true)\n{\n}\n\nEidosClassMethodSignature::EidosClassMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class)\n\t: EidosMethodSignature(p_function_name, p_return_mask, p_return_class, true)\n{\n}\n\nstd::string EidosClassMethodSignature::CallPrefix(void) const\n{\n\treturn \"+\\u00A0\";\t// non-breaking space\n}\n\nEidosClassMethodSignature::~EidosClassMethodSignature(void)\n{\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_call_signature.h",
    "content": "//\n//  eidos_function_signature.h\n//  Eidos\n//\n//  Created by Ben Haller on 5/16/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_function_signature__\n#define __Eidos__eidos_function_signature__\n\n#include <iostream>\n#include <memory>\n\n#include \"eidos_globals.h\"\n\nclass EidosValue;\n\n\n// Prototype for a function handler that is internal to Eidos.\ntypedef EidosValue_SP (*EidosInternalFunctionPtr)(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n// This typedef is for an \"accelerated method implementation\"  These are static member functions on a class, designed to provide\n// a whole vector of results given a buffer of EidosObjects.  The imp is expected to return the correct type for the method.\n// The imp is guaranteed that the EidosObjects are of the correct class; it is allowed to do a cast of p_values directly to\n// its own type without checking, according to the calling conventions used here.  There are similarities between this and making\n// a method a class method, but class methods are conceptually called just once and produce one result from the whole call,\n// whereas accelerated method implementations are conceptually called once per element and produce one result per element; they\n// are just implemented internally in a vectorized fashion.\ntypedef EidosValue_SP (*Eidos_AcceleratedMethodImp)(EidosObject **p_values, size_t p_values_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark EidosCallSignature\n#pragma mark -\n\n// EidosCallSignature is used to represent the return type and argument types of a function or method, for shared runtime type checking.\n// This is an abstract base class; clients should use one of the subclasses below.\nclass EidosCallSignature\n{\npublic:\n\tstd::string call_name_;\n\tEidosGlobalStringID call_id_;\n\t\n\tEidosValueMask return_mask_;\t\t\t\t\t\t// a mask specifying the exact return type; the singleton flag is used, the optional flag is not\n\tconst EidosClass *return_class_;\t\t\t\t\t// optional type-check for object returns; used only if the return is an object and this is not nullptr\n\t\n\tstd::vector<EidosValueMask> arg_masks_;\t\t\t\t// the expected types for each argument, as a mask\n\tstd::vector<std::string> arg_names_;\t\t\t\t// the argument names as std::strings; will be gEidosStr_ELLIPSIS for an ellipsis argument\n\tstd::vector<EidosGlobalStringID> arg_name_IDs_;\t\t// the argument names as EidosGlobalStringIDs, allowing fast argument list processing; will be gEidosID_ELLIPSIS for an ellipsis argument\n\tstd::vector<const EidosClass *> arg_classes_;\t\t// the expected object classes for each argument; nullptr unless the argument is object type and specified an element type\n\tstd::vector<EidosValue_SP> arg_defaults_;\t\t\t// default values for each argument; will be nullptr for required arguments\n\t\n\tbool has_optional_args_ = false;\t\t\t\t\t// if true, at least one optional argument has been added\n\tbool has_ellipsis_ = false;\t\t\t\t\t\t\t// if true, the function accepts arbitrary varargs at some point in its signature (given in the arg vectors above)\n\t\n\tbool deprecated_ = false;\t\t\t\t\t\t\t// if true, the API represented by this signature has been deprecated\n\t\n\tEidosCallSignature(const EidosCallSignature&) = delete;\t\t\t\t\t// no copying\n\tEidosCallSignature& operator=(const EidosCallSignature&) = delete;\t\t// no copying\n\tEidosCallSignature(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosCallSignature(void);\n\t\n\tEidosCallSignature(const std::string &p_call_name, EidosValueMask p_return_mask);\n\tEidosCallSignature(const std::string &p_call_name, EidosValueMask p_return_mask, const EidosClass *p_return_class);\n\t\n\t// C++ doesn't have Objective-C's instancetype return, but that's what is needed for all of these...\n\t// instead, callers will have to cast back to the correct subclass type\n\tEidosCallSignature *AddArg(EidosValueMask p_arg_mask, const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddArgWithDefault(EidosValueMask p_arg_mask, const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value, bool p_fault_tolerant=false);\n\tEidosCallSignature *AddEllipsis(void);\n\t\n\t// vanilla type-specified arguments\n\tEidosCallSignature *AddLogical(const std::string &p_argument_name);\n\tEidosCallSignature *AddInt(const std::string &p_argument_name);\n\tEidosCallSignature *AddFloat(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntString(const std::string &p_argument_name);\n\tEidosCallSignature *AddString(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntObject(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddObject(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddNumeric(const std::string &p_argument_name);\n\tEidosCallSignature *AddLogicalEquiv(const std::string &p_argument_name);\n\tEidosCallSignature *AddAnyBase(const std::string &p_argument_name);\n\tEidosCallSignature *AddAny(const std::string &p_argument_name);\n\t\n\t// optional arguments\n\tEidosCallSignature *AddLogical_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddInt_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddFloat_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntString_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddString_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntObject_O(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddObject_O(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddNumeric_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddLogicalEquiv_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddAnyBase_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddAny_O(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\t\n\t// singleton arguments (i.e. required to have a size of exactly 1)\n\tEidosCallSignature *AddLogical_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddInt_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddFloat_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntString_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddString_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntObject_S(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddObject_S(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddNumeric_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddLogicalEquiv_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddAnyBase_S(const std::string &p_argument_name);\n\tEidosCallSignature *AddAny_S(const std::string &p_argument_name);\n\t\n\t// optional singleton arguments\n\tEidosCallSignature *AddLogical_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddInt_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddFloat_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntString_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddString_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntObject_OS(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddObject_OS(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddNumeric_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddLogicalEquiv_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddAnyBase_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddAny_OS(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\t\n\t// type-specified or NULL\n\tEidosCallSignature *AddLogical_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddInt_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddFloat_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntString_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddString_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntObject_N(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddObject_N(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddNumeric_N(const std::string &p_argument_name);\n\tEidosCallSignature *AddLogicalEquiv_N(const std::string &p_argument_name);\n\t\n\t// optional type-specified or NULL\n\tEidosCallSignature *AddLogical_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddInt_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddFloat_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntString_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddString_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntObject_ON(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddObject_ON(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddNumeric_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddLogicalEquiv_ON(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\t\n\t// singleton type-specified or NULL\n\tEidosCallSignature *AddLogical_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddInt_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddFloat_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntString_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddString_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddIntObject_SN(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddObject_SN(const std::string &p_argument_name, const EidosClass *p_argument_class);\n\tEidosCallSignature *AddNumeric_SN(const std::string &p_argument_name);\n\tEidosCallSignature *AddLogicalEquiv_SN(const std::string &p_argument_name);\n\t\n\t// optional singleton type-specified or NULL\n\tEidosCallSignature *AddLogical_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddInt_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddFloat_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntString_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddString_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddIntObject_OSN(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddObject_OSN(const std::string &p_argument_name, const EidosClass *p_argument_class, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddNumeric_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\tEidosCallSignature *AddLogicalEquiv_OSN(const std::string &p_argument_name, EidosValue_SP p_default_value);\n\t\n\t// API deprecation; this prevents deprecated API from being shown in code completion, etc., even though it remains in the doc\n\tEidosCallSignature *MarkDeprecated(void);\n\t\n\t// check arguments and returns\n\tvoid CheckArgument(EidosValue *p_argument, int p_signature_index) const;\n\tvoid CheckArguments(const std::vector<EidosValue_SP> &p_arguments) const;\n\tvoid CheckReturn(const EidosValue &p_result) const;\n\tvoid CheckAggregateReturn(const EidosValue &p_result, size_t p_expected_size) const;\n\t\n\t// Get the signature as a string, via operator<<\n\tstd::string SignatureString(void) const;\n\t\n\t// virtual functions defined by the subclasses below\n\tvirtual std::string CallType(void) const = 0;\t\t\t\t// \"function\" or \"method\"; used for error output\n\tvirtual std::string CallPrefix(void) const = 0;\t\t\t\t// \"\", \"–\\u00A0\", or \"+\\u00A0\"; used for stream output\n\tvirtual std::string CallDelegate(void) const;\t\t\t\t// used for stream output\n};\n\n// These typedefs for shared_ptrs of these classes should generally be used; all signature objects should be under shared_ptr now.\n//typedef std::shared_ptr<EidosCallSignature> EidosCallSignature_SP;\t\t// once under shared_ptr, these should always be const\ntypedef std::shared_ptr<EidosCallSignature const> EidosCallSignature_CSP;\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosCallSignature &p_signature);\nbool CompareEidosCallSignatures(const EidosCallSignature_CSP &p_i, const EidosCallSignature_CSP &p_j);\n\n\n#pragma mark -\n#pragma mark EidosFunctionSignature\n#pragma mark -\n\nclass EidosFunctionSignature : public EidosCallSignature\n{\nprivate:\n\ttypedef EidosCallSignature super;\n\npublic:\n\t// internal function implementations\n\tEidosInternalFunctionPtr internal_function_ = nullptr;\n\t\n\t// user-defined functions; these are dispatched using a sub-interpreter (OWNED pointer)\n\tEidosScript *body_script_ = nullptr;\n\tbool user_defined_ = false;\n\tint32_t user_definition_line_ = -1;\t\t// the line number associated with the \"function\" token, for SLiMgui debug points\n\t\n\t// delegated function implementations; if no implementation is given, these are dispatched through the Context object in the interpreter\n\tstd::string delegate_name_;\n\t\n\tEidosFunctionSignature(const EidosFunctionSignature&) = delete;\t\t\t\t\t\t\t\t// no copying\n\tEidosFunctionSignature& operator=(const EidosFunctionSignature&) = delete;\t\t\t\t\t// no copying\n\tEidosFunctionSignature(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosFunctionSignature(void) override;\n\t\n\t// Constructors for functions written in C++\n\tEidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask);\n\tEidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, const EidosClass *p_return_class);\n\tEidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, std::string p_delegate_name);\n\tEidosFunctionSignature(const std::string &p_function_name, EidosInternalFunctionPtr p_function_ptr, EidosValueMask p_return_mask, const EidosClass *p_return_class, std::string p_delegate_name);\n\t\n\t// Constructors for functions written in Eidos\n\tEidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask);\n\tEidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, const EidosClass *p_return_class);\n\tEidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, std::string p_delegate_name);\n\tEidosFunctionSignature(const std::string &p_function_name, const std::string &p_script_string, EidosValueMask p_return_mask, const EidosClass *p_return_class, std::string p_delegate_name);\n\tvoid ProcessEidosScript(const std::string &p_script_string);\n\t\n\tvirtual std::string CallType(void) const override;\n\tvirtual std::string CallPrefix(void) const override;\n\tvirtual std::string CallDelegate(void) const override;\n};\n\n// These typedefs for shared_ptrs of these classes should generally be used; all signature objects should be under shared_ptr now.\n//typedef std::shared_ptr<EidosFunctionSignature> EidosFunctionSignature_SP;\t\t// once under shared_ptr, these should always be const\ntypedef std::shared_ptr<EidosFunctionSignature const> EidosFunctionSignature_CSP;\n\nbool CompareEidosFunctionSignatures(const EidosFunctionSignature_CSP &p_i, const EidosFunctionSignature_CSP &p_j);\n\n\n#pragma mark -\n#pragma mark EidosMethodSignature\n#pragma mark -\n\nclass EidosMethodSignature : public EidosCallSignature\n{\nprivate:\n\ttypedef EidosCallSignature super;\n\npublic:\n\tbool is_class_method = false;\t// a bit unfortunate, but much faster to check this than to call a virtual function...\n\t\n\tEidosMethodSignature(const EidosMethodSignature&) = delete;\t\t\t\t\t\t\t\t\t// no copying\n\tEidosMethodSignature& operator=(const EidosMethodSignature&) = delete;\t\t\t\t\t\t// no copying\n\tEidosMethodSignature(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosMethodSignature(void) override;\n\t\n\tEidosMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, bool p_is_class_method);\n\tEidosMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class, bool p_is_class_method);\n\t\n\tvirtual std::string CallType(void) const override;\n};\n\n\n#pragma mark -\n#pragma mark EidosInstanceMethodSignature\n#pragma mark -\n\nclass EidosInstanceMethodSignature : public EidosMethodSignature\n{\nprivate:\n\ttypedef EidosMethodSignature super;\n\npublic:\n\tbool accelerated_imp_;\t\t\t\t\t\t\t\t\t// if true, the method has a special vectorized implementation\n\tEidos_AcceleratedMethodImp accelerated_imper_;\t\t\t// a pointer to a (static member) function that handles the accelerated imp\n\t\n\tEidosInstanceMethodSignature(const EidosInstanceMethodSignature&) = delete;\t\t\t\t\t// no copying\n\tEidosInstanceMethodSignature& operator=(const EidosInstanceMethodSignature&) = delete;\t\t// no copying\n\tEidosInstanceMethodSignature(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosInstanceMethodSignature(void) override;\n\t\n\tEidosInstanceMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask);\n\tEidosInstanceMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class);\n\t\n\tvirtual std::string CallPrefix(void) const override;\n\t\n\t// property access acceleration\n\tEidosInstanceMethodSignature *DeclareAcceleratedImp(Eidos_AcceleratedMethodImp p_imper);\n};\n\n\n#pragma mark -\n#pragma mark EidosClassMethodSignature\n#pragma mark -\n\nclass EidosClassMethodSignature : public EidosMethodSignature\n{\nprivate:\n\ttypedef EidosMethodSignature super;\n\npublic:\n\tEidosClassMethodSignature(const EidosClassMethodSignature&) = delete;\t\t\t\t\t\t// no copying\n\tEidosClassMethodSignature& operator=(const EidosClassMethodSignature&) = delete;\t\t\t// no copying\n\tEidosClassMethodSignature(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosClassMethodSignature(void) override;\n\t\n\tEidosClassMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask);\n\tEidosClassMethodSignature(const std::string &p_function_name, EidosValueMask p_return_mask, const EidosClass *p_return_class);\n\t\n\tvirtual std::string CallPrefix(void) const override;\n};\n\n\n// These typedefs for shared_ptrs of these classes should generally be used; all signature objects should be under shared_ptr now.\n//typedef std::shared_ptr<EidosMethodSignature> EidosMethodSignature_SP;\t\t\t\t\t// once under shared_ptr, these should always be const\n//typedef std::shared_ptr<EidosInstanceMethodSignature> EidosInstanceMethodSignature_SP;\t// once under shared_ptr, these should always be const\n//typedef std::shared_ptr<EidosClassMethodSignature> EidosClassMethodSignature_SP;\t\t\t// once under shared_ptr, these should always be const\n\ntypedef std::shared_ptr<EidosMethodSignature const> EidosMethodSignature_CSP;\ntypedef std::shared_ptr<EidosInstanceMethodSignature const> EidosInstanceMethodSignature_CSP;\ntypedef std::shared_ptr<EidosClassMethodSignature const> EidosClassMethodSignature_CSP;\n\n\n#endif /* defined(__Eidos__eidos_function_signature__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_DataFrame.cpp",
    "content": "//\n//  eidos_class_DataFrame.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 10/10/21.\n//  Copyright (c) 2021-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"eidos_class_DataFrame.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n\n#include <fstream>\n#include <regex>\n#include <limits>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\n//\n// EidosDataFrame\n//\n#pragma mark -\n#pragma mark EidosDataFrame\n#pragma mark -\n\nvoid EidosDataFrame::Raise_UsesStringKeys(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::Raise_UsesStringKeys): cannot use an integer key with the target DataFrame object; DataFrame always uses string keys.\" << EidosTerminate(nullptr);\n}\n\nint EidosDataFrame::RowCount(void) const\n{\n\tAssertKeysAreStrings();\n\t\n\t// Get our row count; we don't cache this so we don't have to worry about validating the cache\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\n\tif (!symbols || (symbols->size() == 0))\n\t\treturn 0;\n\t\n\tauto iter = symbols->begin();\n\t\n\treturn iter->second->Count();\n}\n\nEidosDataFrame *EidosDataFrame::SubsetColumns(EidosValue *index_value)\n{\n\tAssertKeysAreStrings();\n\t\n\tEidosDataFrame *dataframe = new EidosDataFrame();\n\t\n\ttry {\n\t\tEidosValueType index_type = index_value->Type();\n\t\tint index_count = index_value->Count();\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\tif (!symbols)\n\t\t{\n\t\t\t// With no columns, we either throw an error (if columns were selected) or return an empty DataFrame\n\t\t\tif (index_count > 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): cannot select columns from an empty DataFrame.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\treturn dataframe;\n\t\t}\n\t\t\n\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\t// if symbols_ptr is not nullptr, this is also not nullptr\n\t\t\n\t\tif (index_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t key_count = (int64_t)keys.size();\n\t\t\tconst int64_t *index_data = index_value->IntData();\n\t\t\t\n\t\t\tfor (int i = 0; i < index_count; ++i)\n\t\t\t{\n\t\t\t\tint64_t index = index_data[i];\n\t\t\t\t\n\t\t\t\tif ((index < 0) || (index >= key_count))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): column index out of range (\" << index << \" not in [0, \" << (key_count - 1) << \"]).\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tconst std::string &key = keys[index];\n\t\t\t\tauto value_iter = symbols->find(key);\n\t\t\t\t\n\t\t\t\tif (value_iter == symbols->end())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): (internal error) no value for defined key.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tdataframe->SetKeyValue_StringKeys(key, value_iter->second);\n\t\t\t}\n\t\t}\n\t\telse if (index_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *index_data = index_value->StringData();\n\t\t\t\n\t\t\tfor (int i = 0; i < index_count; ++i)\n\t\t\t{\n\t\t\t\tconst std::string &key = index_data[i];\n\t\t\t\t\n\t\t\t\tauto value_iter = symbols->find(key);\n\t\t\t\t\n\t\t\t\tif (value_iter == symbols->end())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): key \" << key << \" is not defined in the target DataFrame.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tdataframe->SetKeyValue_StringKeys(key, value_iter->second);\n\t\t\t}\n\t\t}\n\t\telse // (index_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tint64_t symbols_count = (int64_t)symbols->size();\n\t\t\tconst eidos_logical_t *index_data = index_value->LogicalData();\n\t\t\t\n\t\t\tif (index_count != symbols_count)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): logical index vector length does not match the number of columns in the DataFrame.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfor (int i = 0; i < index_count; ++i)\n\t\t\t{\n\t\t\t\tbool selected = index_data[i];\n\t\t\t\t\n\t\t\t\tif (selected)\n\t\t\t\t{\n\t\t\t\t\tconst std::string &key = keys[i];\n\t\t\t\t\tauto value_iter = symbols->find(key);\n\t\t\t\t\t\n\t\t\t\t\tif (value_iter == symbols->end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetColumns): (internal error) no value for defined key.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tdataframe->SetKeyValue_StringKeys(key, value_iter->second);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn dataframe;\n\t} catch (...) {\n\t\tdataframe->Release();\n\t\tthrow;\n\t}\n}\n\nEidosDataFrame *EidosDataFrame::SubsetRows(EidosValue *index_value, bool drop)\n{\n\tAssertKeysAreStrings();\n\t\n\tEidosDataFrame *dataframe = new EidosDataFrame();\n\t\n\ttry {\n\t\t// With no columns, the indices don't matter, and the result is a new empty dictionary\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\tif (!symbols || (symbols->size() == 0))\n\t\t\treturn dataframe;\n\t\t\n\t\t// Otherwise, we subset to get the result value for each key we contain\n\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\t\n\t\tfor (const std::string &key : keys)\n\t\t{\n\t\t\tauto kv_pair = symbols->find(key);\n\t\t\t\n\t\t\tif (kv_pair == symbols->end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SubsetRows): (internal error) key not found in symbols.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_SP subset = SubsetEidosValue(kv_pair->second.get(), index_value, nullptr, /* p_raise_range_errors */ true);\n\t\t\t\n\t\t\tif (!drop || subset->Count())\n\t\t\t\tdataframe->SetKeyValue_StringKeys(kv_pair->first, subset);\n\t\t}\n\t\t\n\t\treturn dataframe;\n\t} catch (...) {\n\t\tdataframe->Release();\n\t\tthrow;\n\t}\n}\n\nstd::vector<std::string> EidosDataFrame::SortedKeys_StringKeys(void) const\n{\n\tAssertKeysAreStrings();\n\t\n\t// Provide our keys in their user-defined order (without sorting as Dictionary does)\n\treturn sorted_keys_;\n}\n\nstd::vector<int64_t> EidosDataFrame::SortedKeys_IntegerKeys(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::SortedKeys_IntegerKeys): (internal error) DataFrame does not support integer keys.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosDataFrame::KeyAddedToDictionary_StringKeys(const std::string &p_key)\n{\n\tif (!state_ptr_)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::KeyAddedToDictionary_StringKeys): (internal error) no state_ptr_.\" << EidosTerminate(nullptr);\n\t\n\tAssertKeysAreStrings();\n\t\n\t// call super\n\tsuper::KeyAddedToDictionary_StringKeys(p_key);\n\t\n\t// Maintain our user-defined key ordering\n\tauto iter = std::find(sorted_keys_.begin(), sorted_keys_.end(), p_key);\n\t\n\tif (iter == sorted_keys_.end())\n\t\tsorted_keys_.emplace_back(p_key);\n}\n\nvoid EidosDataFrame::KeyAddedToDictionary_IntegerKeys(__attribute__((unused)) int64_t p_key)\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::KeyAddedToDictionary_IntegerKeys): (internal error) DataFrame does not support integer keys.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosDataFrame::KeyRemovedFromDictionary_StringKeys(const std::string &p_key)\n{\n\t// call super\n\tsuper::KeyRemovedFromDictionary_StringKeys(p_key);\n\t\n\t// Maintain our user-defined key ordering\n\tauto iter = std::find(sorted_keys_.begin(), sorted_keys_.end(), p_key);\n\t\n\tif (iter != sorted_keys_.end())\n\t\tsorted_keys_.erase(iter);\n}\n\nvoid EidosDataFrame::KeyRemovedFromDictionary_IntegerKeys(__attribute__((unused)) int64_t p_key)\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::KeyRemovedFromDictionary_IntegerKeys): (internal error) DataFrame does not support integer keys.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosDataFrame::AllKeysRemoved(void)\n{\n\t// call super\n\tsuper::AllKeysRemoved();\n\t\n\t// Maintain our user-defined key ordering\n\tsorted_keys_.resize(0);\n}\n\nvoid EidosDataFrame::ContentsChanged(const std::string &p_operation_name)\n{\n\tAssertKeysAreStrings();\n\t\n\t// call super\n\tsuper::ContentsChanged(p_operation_name);\n\t\n\tif (!state_ptr_)\n\t\treturn;\n\t\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\n\t// Check that sorted_keys_ matches DictionarySymbols_StringKeys()\n\tif (symbols->size() != sorted_keys_.size())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ContentsChanged): (internal error) DataFrame found key count mismatch after \" << p_operation_name << \".\" << EidosTerminate(nullptr);\n\t\n\t// Go through all of our columns and check that they are the same size\n\t// Also check that all are simple vectors, not matrices or arrays\n\tint row_count = -1;\n\t\n\tif (!symbols)\n\t\treturn;\n\t\n\tfor (auto const &kv_pair : *symbols)\n\t{\n\t\tconst EidosValue *value = kv_pair.second.get();\n\t\tint value_count = value->Count();\n\t\t\n\t\tif (row_count == -1)\n\t\t\trow_count = value_count;\n\t\telse if (row_count != value_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ContentsChanged): DataFrame found inconsistent column sizes after \" << p_operation_name << \"; all columns must be the same length.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (value->DimensionCount() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ContentsChanged): DataFrame found a matrix or array value after \" << p_operation_name << \"; only vector values are allowed in DataFrame.\" << EidosTerminate(nullptr);\n\t}\n}\n\nconst EidosClass *EidosDataFrame::Class(void) const\n{\n\treturn gEidosDataFrame_Class;\n}\n\nvoid EidosDataFrame::Print(std::ostream &p_ostream) const\n{\n\t// We want to print as a data table (rows and columns), not as a dictionary (keys with associated values).  The layout is the tricky thing.\n\t// We have to pre-plan our output: go through all of our elements, generate their output string, and calculate the width of each column.\n\t// We put all of those strings into a temporary data structure that we build here, organized by column.  We thus keep all the output in\n\t// memory; that would be an issue for a *very* large dataframe, but that seems unlikely.\n\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\tstd::ostringstream ss;\n\t\n\tif (keys.size())\n\t{\n\t\t// First, assemble our planned output\n\t\tstd::vector<std::vector<std::string>> output;\n\t\tstd::vector<int> column_widths;\n\t\tint row_count = RowCount(), col_count = ColumnCount();\n\t\t\n\t\tfor (const std::string &key : keys)\n\t\t{\n\t\t\tstd::vector<std::string> col_output;\n\t\t\t\n\t\t\t// Output the column header (i.e., the key), using quotes only if needed\n\t\t\tEidosStringQuoting key_quoting = EidosStringQuoting::kNoQuotes;\n\t\t\t\n\t\t\tif (key.find_first_of(\"\\\"\\'\\\\\\r\\n\\t =;\") != std::string::npos)\n\t\t\t\tkey_quoting = EidosStringQuoting::kDoubleQuotes;\t\t// if we use quotes, always use double quotes, for ease of parsing\n\t\t\t\n\t\t\tss << Eidos_string_escaped(key, key_quoting);\n\t\t\tcol_output.emplace_back(ss.str());\n\t\t\tss.clear();\n\t\t\tss.str(gEidosStr_empty_string);\n\t\t\t\n\t\t\t// Output all of the values in the column\n\t\t\tauto key_iter = symbols->find(key);\n\t\t\t\n\t\t\tif (key_iter != symbols->end())\n\t\t\t{\n\t\t\t\tEidosValue *value = key_iter->second.get();\n\t\t\t\tint value_count = value->Count();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tvalue->PrintValueAtIndex(value_index, ss);\n\t\t\t\t\tcol_output.emplace_back(ss.str());\n\t\t\t\t\tss.clear();\n\t\t\t\t\tss.str(gEidosStr_empty_string);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Calculate the column width\n\t\t\tint max_width = 0;\n\t\t\t\n\t\t\tfor (auto &col_string : col_output)\n\t\t\t\tmax_width = std::max(max_width, (int)col_string.length());\n\t\t\t\n\t\t\t// Save the results\n\t\t\toutput.emplace_back(col_output);\n\t\t\tcolumn_widths.emplace_back(max_width);\n\t\t}\n\t\t\n\t\t// Figure out the width for the row numbers\n\t\tint max_row_number = row_count - 1;\n\t\tint row_num_width;\n\t\t\n\t\tss << max_row_number;\n\t\trow_num_width = (int)ss.str().length();\n\t\tss.clear();\n\t\tss.str(gEidosStr_empty_string);\n\t\t\n\t\t// Then, generate the output\n\t\tfor (int row = 0; row <= row_count; ++row)\t\t// <= to include the header row, which is row 0 here\n\t\t{\n\t\t\tfor (int col = -1; col < col_count; ++col)\t// -1 to include the row numbers, which are col -1 here since they aren't in `output`\n\t\t\t{\n\t\t\t\tif (col == -1)\n\t\t\t\t{\n\t\t\t\t\t// Emit the row numbers\n\t\t\t\t\tif (row == 0)\n\t\t\t\t\t\tp_ostream << std::string(row_num_width, ' ');\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tss << (row - 1);\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::string row_str = ss.str();\n\t\t\t\t\t\t\n\t\t\t\t\t\tp_ostream << std::string(row_num_width - row_str.length(), ' ') << row_str;\n\t\t\t\t\t\t\n\t\t\t\t\t\tss.clear();\n\t\t\t\t\t\tss.str(gEidosStr_empty_string);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Emit our pre-planned strings\n\t\t\t\t\tconst std::string &out_str = output[col][row];\n\t\t\t\t\t\n\t\t\t\t\tp_ostream << std::string(column_widths[col] - out_str.length() + 1, ' ') << out_str;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// newlines for everything but the last line\n\t\t\tif (row < row_count)\n\t\t\t\tp_ostream << std::endl;\n\t\t}\n\t\t\n\t\tif (row_count == 0)\n\t\t{\n\t\t\tp_ostream << std::endl << \"<0 rows>\";\n\t\t}\n\t}\n\telse\n\t{\n\t\tp_ostream << \"DataFrame with 0 columns and 0 rows\" << std::endl;\n\t}\n}\n\nEidosValue_SP EidosDataFrame::GetProperty(EidosGlobalStringID p_property_id)\n{\n#if DEBUG\n\t// Check for correctness before dispatching out; perhaps excessively cautious, but checks are good\n\tContentsChanged(\"EidosDataFrame::GetProperty\");\n#endif\n\t\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gEidosID_colNames:\n\t\t\treturn AllKeys();\n\t\tcase gEidosID_dim:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{RowCount(), ColumnCount()});\n\t\tcase gEidosID_ncol:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(ColumnCount()));\n\t\tcase gEidosID_nrow:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(RowCount()));\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue_SP EidosDataFrame::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#if DEBUG\n\t// Check for correctness before dispatching out; perhaps excessively cautious, but checks are good\n\tContentsChanged(\"EidosDataFrame::ExecuteInstanceMethod\");\n#endif\n\t\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_asMatrix:\t\t\t\t\treturn ExecuteMethod_asMatrix(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_cbind:\t\t\t\t\treturn ExecuteMethod_cbind(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_rbind:\t\t\t\t\treturn ExecuteMethod_rbind(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_subset:\t\t\t\t\treturn ExecuteMethod_subset(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_subsetColumns:\t\t\treturn ExecuteMethod_subsetColumns(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_subsetRows:\t\t\t\treturn ExecuteMethod_subsetRows(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (void)asMatrix(void)\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_asMatrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\t// First determine what type the matrix would be, and check that all columns match that type\n\tint64_t nrow = RowCount();\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\tint64_t ncol = symbols->size();\n\tEidosValue_SP type_template;\n\tconst EidosClass *class_template = nullptr;\n\t\n\tif (ncol == 0)\n\t{\n\t\ttype_template = gStaticEidosValue_Logical_ZeroVec;\t\t// with no columns, we have no way to know the type, so we go with \"logical\", following R\n\t}\n\telse\n\t{\n\t\tfor (auto const &symbols_iter : *symbols)\n\t\t{\n\t\t\tif (!type_template)\n\t\t\t{\n\t\t\t\ttype_template = symbols_iter.second;\n\t\t\t\tif (type_template->Type() == EidosValueType::kValueObject)\n\t\t\t\t\tclass_template = ((EidosValue_Object *)(type_template.get()))->Class();\n\t\t\t}\n\t\t\telse if (type_template->Type() != symbols_iter.second->Type())\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ExecuteMethod_asMatrix): asMatrix() requires that every column of the target DataFrame is the same type (\" << type_template->Type() << \" != \" << symbols_iter.second->Type() << \").\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\telse if (class_template)\n\t\t\t{\n\t\t\t\tconst EidosClass *class_column = ((EidosValue_Object *)(symbols_iter.second.get()))->Class();\n\t\t\t\t\n\t\t\t\tif (class_template != class_column)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ExecuteMethod_asMatrix): asMatrix() requires that every object element in the target DataFrame is the same class (\" << class_template->ClassNameForDisplay() << \" != \" << class_column->ClassNameForDisplay() << \").\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Create the matrix; for now we use a slow implementation that is type-agnostic and does not resize to fit first, probably this is unlikely to be a bottleneck\n\t//int64_t data_count = nrow * ncol;\n\tEidosValue_SP result_SP = type_template->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\t//result_SP->resize_no_initialize(data_count);\n\t\n\t// Fill in all the values, in sorted column order\n\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\n\tfor (const std::string &key : keys)\n\t{\n\t\tauto key_iter = symbols->find(key);\n\t\t\n\t\tif (key_iter == symbols->end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDataFrame::ExecuteMethod_asMatrix): (internal error) key not found.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue *column_value = key_iter->second.get();\n\t\t\n\t\tfor (int64_t i = 0; i < nrow; ++i)\n\t\t\tresult->PushValueFromIndexOfEidosValue((int)i, *column_value, nullptr);\n\t}\n\t\n\tconst int64_t dim_buf[2] = {nrow, ncol};\n\t\n\tresult_SP->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (void)cbind(object<Dictionary> source, ...)\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_cbind(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\t// This method is similar to addKeysAndValuesFrom(), with a couple of differences.  One, a collision in column names\n\t// is an error, rather than the existing column being replaced.  Two, the lengths of all columns must be the same\n\t// (basic DataFrame requirement).  Three, this method handles multiple adds; source does not have to be a singleton,\n\t// and the ellipsis can contain further Dictionary/DataFrame arguments, which also don't have to be singleton.  We\n\t// can use AddKeysAndValuesFrom() to do the work for us under the hood.\n\tfor (const EidosValue_SP &arg : p_arguments)\n\t{\n\t\tint arg_count = arg->Count();\n\t\t\n\t\tfor (int arg_index = 0; arg_index < arg_count; ++arg_index)\n\t\t{\n\t\t\tEidosObject *source_obj = arg->ObjectElementAtIndex_NOCAST(arg_index, nullptr);\n\t\t\tEidosDictionaryUnretained *source = (EidosDictionaryUnretained *)source_obj;\n\t\t\t\n\t\t\tAddKeysAndValuesFrom(source, /* p_allow_replace */ false);\n\t\t}\n\t}\n\t\n\tContentsChanged(\"cbind()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)rbind(object<Dictionary> source, ...)\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_rbind(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\t// This method is similar to appendKeysAndValuesFrom(), with a couple of differences.  One, the column names of\n\t// the dictionary being appended must match in value and order.  Two, the lengths of all columns must be the same\n\t// (basic DataFrame requirement).  Three, this method handles multiple adds; source does not have to be a singleton,\n\t// and the ellipsis can contain further Dictionary/DataFrame arguments, which also don't have to be singleton.  We\n\t// can use AppendKeysAndValuesFrom() to do the work for us under the hood.\n\tfor (const EidosValue_SP &arg : p_arguments)\n\t{\n\t\tint arg_count = arg->Count();\n\t\t\n\t\tfor (int arg_index = 0; arg_index < arg_count; ++arg_index)\n\t\t{\n\t\t\tEidosObject *source_obj = arg->ObjectElementAtIndex_NOCAST(arg_index, nullptr);\n\t\t\tEidosDictionaryUnretained *source = (EidosDictionaryUnretained *)source_obj;\n\t\t\t\n\t\t\tAppendKeysAndValuesFrom(source, /* p_require_column_match */ true);\n\t\t}\n\t}\n\t\n\tContentsChanged(\"rbind()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (*)subset([Nli rows = NULL], [Nlis cols = NULL])\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_subset(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\tEidosValue *rows_value = p_arguments[0].get();\n\tEidosValue *cols_value = p_arguments[1].get();\n\tEidosValue_SP result_SP(nullptr);\n\t\n\t// First subset the rows\n\tEidosDataFrame *rows_subset;\n\t\n\tif (rows_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\trows_subset = this;\n\t\trows_subset->Retain();\n\t}\n\telse\n\t{\n\t\trows_subset = SubsetRows(rows_value);\n\t\trows_subset->ContentsChanged(\"subset()\");\n\t}\n\t\n\ttry {\n\t\t// Then subset the columns\n\t\tEidosDataFrame *cols_subset;\n\t\t\n\t\tif (cols_value->Type() == EidosValueType::kValueNULL)\n\t\t{\n\t\t\tcols_subset = rows_subset;\n\t\t\tcols_subset->Retain();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcols_subset = rows_subset->SubsetColumns(cols_value);\n\t\t\tcols_subset->ContentsChanged(\"subset()\");\n\t\t}\n\t\t\n\t\t// Then return the resulting DataFrame, or if it contains exactly one column, return the vector of values from that column instead\n\t\tif (cols_subset->ColumnCount() == 1)\n\t\t{\n\t\t\tconst EidosDictionaryHashTable_StringKeys *symbols = cols_subset->DictionarySymbols_StringKeys();\n\t\t\tauto col_iter = symbols->begin();\n\t\t\t\n\t\t\tresult_SP = col_iter->second;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Note that this retains cols_subset, before the call to Release below\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(cols_subset, gEidosDataFrame_Class));\n\t\t}\n\t\t\n\t\trows_subset->Release();\n\t\tcols_subset->Release();\n\t\treturn result_SP;\n\t}\n\tcatch (...) {\n\t\trows_subset->Release();\n\t\tthrow;\n\t}\n}\n\n//\t*********************\t- (object<DataFrame>$)subsetColumns(lis index)\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_subsetColumns(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\tEidosValue *index_value = p_arguments[0].get();\n\tEidosDataFrame *objectElement = SubsetColumns(index_value);\n\tobjectElement->ContentsChanged(\"subsetColumns()\");\n\t\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDataFrame_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (object<DataFrame>$)subsetRows(li index, [logical$ drop = F])\n//\nEidosValue_SP EidosDataFrame::ExecuteMethod_subsetRows(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tAssertKeysAreStrings();\n\t\n\tEidosValue *index_value = p_arguments[0].get();\n\tEidosValue *drop_value = p_arguments[1].get();\n\tEidosDataFrame *objectElement = SubsetRows(index_value, drop_value->LogicalAtIndex_NOCAST(0, nullptr));\n\tobjectElement->ContentsChanged(\"subsetRows()\");\n\t\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDataFrame_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tObject instantiation\n//\n#pragma mark -\n#pragma mark Object instantiation\n#pragma mark -\n\n//\t(object<DataFrame>$)DataFrame(...)\nstatic EidosValue_SP Eidos_Instantiate_EidosDataFrame(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosDataFrame *objectElement = new EidosDataFrame();\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDataFrame_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\t// now use a constructor that we share with Dictionary\n\tobjectElement->ConstructFromEidos(p_arguments, p_interpreter, \"Eidos_Instantiate_EidosDataFrame\" , \"DataFrame\");\n\tobjectElement->ContentsChanged(\"DataFrame()\");\n\t\n\treturn result_SP;\n}\n\n//\t(object<DataFrame>$)readCSV(string$ filePath, [ls colNames = T], [Ns$ colTypes = NULL], [string$ sep = \",\"], [string$ quote = \"\\\"\"], [string$ dec = \".\"], [string$ comment = \"\"])\nstatic EidosValue_SP Eidos_ExecuteFunction_readCSV(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tEidosValue *colNames_value = p_arguments[1].get();\n\tEidosValue *colTypes_value = p_arguments[2].get();\n\tEidosValue *sep_value = p_arguments[3].get();\n\tEidosValue *quote_value = p_arguments[4].get();\n\tEidosValue *dec_value = p_arguments[5].get();\n\tEidosValue *comment_value = p_arguments[6].get();\n\t\n\t// Start by opening the CSV data file; a little weird that we just warn and retunr NULL on a file I/O error, but this follows readFile()\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string file_path = Eidos_ResolvedPath(base_path);\n\t\n\tstd::ifstream file_stream(file_path.c_str());\n\t\n\tif (!file_stream.is_open())\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_readCSV): function readCSV() could not read file at path \" << file_path << \".\" << std::endl;\n\t\treturn gStaticEidosValueNULL;\n\t}\n\n\t// Figure out our various separators/delimiters\n\tstd::string sep_string = sep_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string quote_string = quote_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string dec_string = dec_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string comment_string = comment_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (sep_string.length() > 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires that sep be a string of exactly one character, or the empty string \\\"\\\".\" << EidosTerminate(nullptr);\n\tif (quote_string.length() != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires that quote be a string of exactly one character.\" << EidosTerminate(nullptr);\n\tif (dec_string.length() != 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires that dec be a string of exactly one character.\" << EidosTerminate(nullptr);\n\tif (comment_string.length() > 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires that comment be a string of exactly one character, or the empty string.\" << EidosTerminate(nullptr);\n\t\n\tchar sep = (sep_string.length() ? sep_string[0] : 0);\t\t\t\t// 0 indicates \"whitespace separator\", a special case\n\tchar quote = quote_string[0];\n\tchar dec = dec_string[0];\n\tchar comment = (comment_string.length() ? comment_string[0] : 0);\t// 0 indicates \"no comments\"\n\t\n\tif ((sep && ((sep == quote) || (sep == dec) || (sep == comment))) ||\n\t\t((quote == dec) || (quote == comment) || (dec == comment)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires sep, quote, dec, and comment to be different from each other.\" << EidosTerminate(nullptr);\n\tif (!std::isprint(dec) || std::isalnum(dec) || (dec == '+') || (dec == '-'))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires that dec be a printable, non-alphanumeric character that is not '+' or '-' (typically '.' or ',').\" << EidosTerminate(nullptr);\n\t\n\t// Read lines and split each line up into components; this is non-trivial since it involves parsing out quoted strings and unquoting them\n\t// Check that each line has the same number of components as we go along, to avoid having to make an extra pass\n\tstd::string line;\n\tstd::vector<std::vector<std::string>> rows;\n\tint ncols = -1, line_number = 0;\n\t\n\twhile (getline(file_stream, line))\n\t{\n\t\t// split line into strings based on sep, quote, and comment\n\t\tstd::vector<std::string> row;\n\t\tconst char *line_ptr = line.data();\n\t\tchar ch = *line_ptr;\n\t\t\n\t\tline_number++;\t\t// after this increment, this has the line number (1-based) we are current parsing\n\t\t\n\t\t// a line is allowed to be completely empty, or to be a comment line (starting at its first character)\n\t\tif ((ch == 0) || (comment && (ch == comment)))\n\t\t\tcontinue;\n\t\t\n\t\t// if the separator is \"whitespace\" the line can begin with whitespace, which we eat here\n\t\tif (!sep)\n\t\t\twhile ((ch == ' ') || (ch == '\\t'))\n\t\t\t\tch = *(++line_ptr);\n\t\t\n\t\tdo\n\t\t{\n\t\t\t// ch should always be equal to *line_ptr here already, no need to fetch it again\n\t\t\tbool line_ended_without_separator = false;\n\t\t\t\n\t\t\t// at the top of the loop, we expect a new element; a comment or a null means we have an empty string and then end\n\t\t\t// this might look like: foo,bar,baz,#comment: the last element is an empty string\n\t\t\t// if the separator is \"whitespace\" then an empty string is not implied here; we just end the line\n\t\t\tif ((ch == 0) || (comment && (ch == comment)))\n\t\t\t{\n\t\t\t\t// empty element (if the separator is not whitespace), and then end the line\n\t\t\t\tif (sep)\n\t\t\t\t\trow.emplace_back();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// similarly, a separator character here means we have an empty string and then expect another element\n\t\t\t// we make the empty element, eat the separator, and loop back for the next element\n\t\t\t// note this does not occur for a \"whitespace\" separator; any whitespace would already be eaten at this point,\n\t\t\t// because two consecutive \"whitespace\" separators cannot occur, whereas \",,\" can occur implying an empty string\n\t\t\tif (ch == sep)\n\t\t\t{\n\t\t\t\trow.emplace_back();\n\t\t\t\tch = *(++line_ptr);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t// we are at the start of a new element, which must be either quoted or unquoted\n\t\t\t// note that leading whitespace is part of the element, and indicates an unquoted element\n\t\t\tif (ch == quote)\n\t\t\t{\n\t\t\t\t// quoted string: read until the end quote, unquoting doubled quotes\n\t\t\t\tstd::string element_string;\n\t\t\t\t\n\t\t\t\t// eat the quote and get the next character\n\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// ch should always be the next character to look at in the element, at this point; no need to fetch it again\n\t\t\t\t\t\n\t\t\t\t\t// at the top of the loop, we are inside the quoting and the next character either terminates the quoting or continues inside it\n\t\t\t\t\tif (ch == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we reached the end of the line, but we're still inside the quoted element; incorporate the implied newline and keep going\n\t\t\t\t\t\tif (!getline(file_stream, line))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): function readCSV() encountered an unexpected end-of-file inside a quoted element, at line \" << line_number << \".\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\telement_string.append(1, '\\n');\n\t\t\t\t\t\tline_number++;\n\t\t\t\t\t\tline_ptr = line.data();\n\t\t\t\t\t\tch = *line_ptr;\n\t\t\t\t\t}\n\t\t\t\t\telse if (ch == quote)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we hit a quote character; if the *next* character is also a quote, then we have a double quote,\n\t\t\t\t\t\t// which is an escape indicating a single quote, otherwise we have terminated the element\n\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (ch == quote)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// doubled quote; append one quote and continue\n\t\t\t\t\t\t\telement_string.append(1, quote);\n\t\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// not a doubled quote; the element is terminated and ch is already the character after the end quote\n\t\t\t\t\t\t\t// at this point, we expect only a separator, a comment, or a line end; the element is done\n\t\t\t\t\t\t\tif (sep && (ch == sep))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (!sep && ((ch == ' ') || (ch == '\\t')))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// eat a \"whitespace\" separator, similar to above\n\t\t\t\t\t\t\t\twhile ((ch == ' ') || (ch == '\\t'))\n\t\t\t\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if ((ch == 0) || (comment && (ch == comment)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tline_ended_without_separator = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): function readCSV() encountered an unexpected character '\" << ch << \"' after the end of a quoted element.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// this character is part of the element; the above cases are the only exceptions\n\t\t\t\t\t\telement_string.append(1, ch);\n\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twhile (true);\n\t\t\t\t\n\t\t\t\t// add the completed element to the row\n\t\t\t\trow.emplace_back(element_string);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// unquoted string: read until a separator, comment, or null\n\t\t\t\tstd::string element_string;\n\t\t\t\t\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// at the top of the loop, ch has a valid character to be added to the element; do so\n\t\t\t\t\telement_string.append(1, ch);\n\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\n\t\t\t\t\t// now decide what to do about the next character\n\t\t\t\t\t// NOLINTBEGIN(*-branch-clone) : intentional branch clones\n\t\t\t\t\tif (ch == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we reached the end of the line, which terminates the element\n\t\t\t\t\t\tline_ended_without_separator = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (sep && (ch == sep))\n\t\t\t\t\t{\n\t\t\t\t\t\t// we hit a separator, which terminates the element but expects another\n\t\t\t\t\t\t// eat the separator so we're at the start of the next element\n\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!sep && ((ch == ' ') || (ch == '\\t')))\n\t\t\t\t\t{\n\t\t\t\t\t\t// eat a \"whitespace\" separator, similar to above\n\t\t\t\t\t\twhile ((ch == ' ') || (ch == '\\t'))\n\t\t\t\t\t\t\tch = *(++line_ptr);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (comment && (ch == comment))\n\t\t\t\t\t{\n\t\t\t\t\t\t// we hit a comment character, which terminates the element\n\t\t\t\t\t\tline_ended_without_separator = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t// NOLINTEND(*-branch-clone)\n\t\t\t\t\t\n\t\t\t\t\t// the character is part of the element; let the top of the loop handle it\n\t\t\t\t}\n\t\t\t\twhile (true);\n\t\t\t\t\n\t\t\t\t// add the completed element to the row\n\t\t\t\trow.emplace_back(element_string);\n\t\t\t}\n\t\t\t\n\t\t\t// if we ended the line above without seeing a separator, we do not expect another element; the row is done\n\t\t\t// this flag is effectively a way of breaking out of this outer loop from inside a nested loop\n\t\t\tif (line_ended_without_separator)\n\t\t\t\tbreak;\n\t\t}\n\t\twhile (true);\n\t\t\n\t\t// check the column count, and if it passes, append this row to our buffer and move on\n\t\tif (ncols == -1)\n\t\t\tncols = (int)row.size();\n\t\telse if (ncols != (int)row.size())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): function readCSV() encountered an inconsistent column count in CSV file (\" << row.size() << \" observed, \" << ncols << \" previously), at line \" << line_number << \".\" << EidosTerminate(nullptr);\n\t\t\n\t\trows.emplace_back(row);\n\t}\n\t\n\tif (file_stream.bad())\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_readCSV): function readCSV() encountered stream errors while reading file at path \" << file_path << \".\" << std::endl;\n\t\treturn gStaticEidosValueNULL;\n\t}\n\t\n\t// Decide on the name for each column, using colNames and/or defaults\n\t// If a header line is expected, this removes the first input line to act as the header\n\tstd::vector<std::string> columnNames;\n\t\n\tif ((colNames_value->Type() == EidosValueType::kValueLogical) && (colNames_value->Count() == 1) && (colNames_value->LogicalAtIndex_NOCAST(0, nullptr) == true))\n\t{\n\t\t// colNames == T means \"a header row is present, use it\"\n\t\tif (rows.size() == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() found no header row, but colNames==T indicating that one is expected.\" << EidosTerminate(nullptr);\n\t\t\n\t\tcolumnNames = rows[0];\n\t\trows.erase(rows.begin());\n\t}\n\telse if ((colNames_value->Type() == EidosValueType::kValueLogical) && (colNames_value->Count() == 1) && (colNames_value->LogicalAtIndex_NOCAST(0, nullptr) == false))\n\t{\n\t\t// colNames == F means \"autogenerate column names of the form X1, X2, ...\"\n\t\tfor (int col_index = 0; col_index < ncols; ++col_index)\n\t\t\tcolumnNames.emplace_back(std::string(\"X\") + std::to_string(col_index + 1));\n\t}\n\telse if (colNames_value->Type() == EidosValueType::kValueString)\n\t{\n\t\t// colNames as a string vector supplies column names, but might run out and then we autogenerate\n\t\tint colNames_count = colNames_value->Count();\n\t\t\n\t\tfor (int col_index = 0; col_index < ncols; ++col_index)\n\t\t{\n\t\t\tif (col_index < colNames_count)\n\t\t\t{\n\t\t\t\t// The name is provided by colNames\n\t\t\t\tstd::string colname = colNames_value->StringAtIndex_NOCAST(col_index, nullptr);\n\t\t\t\tauto check_iter = std::find(columnNames.begin(), columnNames.end(), colname);\n\t\t\t\t\n\t\t\t\tif (check_iter != columnNames.end())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires unique column names, but '\" << colname << \"' is not unique.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tcolumnNames.emplace_back(colname);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The name must be autogenerated; try X1, X2, ... starting at the current column index until we find an unused name\n\t\t\t\tint candidate_index = col_index + 1;\n\t\t\t\tstd::string candidate_name;\n\t\t\t\t\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tcandidate_name = std::string(\"X\") + std::to_string(candidate_index);\n\t\t\t\t\t\n\t\t\t\t\tauto check_iter = std::find(columnNames.begin(), columnNames.end(), candidate_name);\n\t\t\t\t\t\n\t\t\t\t\tif (check_iter == columnNames.end())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tcandidate_index++;\n\t\t\t\t}\n\t\t\t\twhile (true);\n\t\t\t\t\n\t\t\t\tcolumnNames.emplace_back(candidate_name);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() requires colNames to be T, F, or a string vector of column names.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Decide on a type for each column, using colTypes and/or guesses; we use kValueVOID to mean \"skip this column\", and kValueNULL to mean \"guess this column\"\n\tstd::vector<EidosValueType> coltypes;\n\tbool has_null_coltype = false;\n\t\n\tif (colTypes_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tstd::string colTypes_string = colTypes_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (char ch : colTypes_string)\n\t\t{\n\t\t\tswitch (ch) {\n\t\t\t\tcase 'l': coltypes.emplace_back(EidosValueType::kValueLogical); break;\n\t\t\t\tcase 'i': coltypes.emplace_back(EidosValueType::kValueInt); break;\n\t\t\t\tcase 'f': coltypes.emplace_back(EidosValueType::kValueFloat); break;\n\t\t\t\tcase 's': coltypes.emplace_back(EidosValueType::kValueString); break;\n\t\t\t\tcase '?': coltypes.emplace_back(EidosValueType::kValueNULL); has_null_coltype = true; break;\n\t\t\t\tcase '_':\n\t\t\t\tcase '-': coltypes.emplace_back(EidosValueType::kValueVOID); break;\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): readCSV() did not recognize column type '\" << ch << \"' in colTypes.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\twhile ((int)coltypes.size() < ncols)\n\t{\n\t\tcoltypes.emplace_back(EidosValueType::kValueNULL);\t\t// guess by default\n\t\thas_null_coltype = true;\n\t}\n\t\n\t// Resolve the type for columns that we're supposed to guess on\n\tif (has_null_coltype)\n\t{\n\t\tif (!Eidos_RegexWorks())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): This build of Eidos does not have a working <regex> library, due to a bug in the underlying C++ standard library provided by the system.  Calls to readCSV() that require guessing the type of a column (which uses regex) are therefore not allowed.  This problem might be resolved by updating your compiler or toolchain, or by upgrading to a more recent version of your operating system.\" << EidosTerminate(nullptr);\n\t\n\t\tstd::regex integer_regex(\"[+-]?[0-9]+\", std::regex_constants::ECMAScript);\n\t\tstd::regex float_regex(std::string(\"[+-]?[0-9]+(\\\\\") + std::string(1, dec) + std::string(\"[0-9]*)?([eE][+-]?[0-9]+)?\"), std::regex_constants::ECMAScript);\n\t\t\n\t\tfor (int col_index = 0; col_index < ncols; ++col_index)\n\t\t{\n\t\t\tif (coltypes[col_index] == EidosValueType::kValueNULL)\n\t\t\t{\n\t\t\t\t// Try EidosValueType::kValueLogical first; candidate values are \"T\", \"TRUE\", \"true\", \"F\", \"FALSE\", or \"false\", case-sensitive\n\t\t\t\tEidosValueType coltype = EidosValueType::kValueLogical;\n\t\t\t\t\n\t\t\t\tif (coltype == EidosValueType::kValueLogical)\n\t\t\t\t{\n\t\t\t\t\tfor (const auto &row : rows)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string &row_value = row[col_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((row_value != \"T\") && (row_value != \"TRUE\") && (row_value != \"true\") && (row_value != \"F\") && (row_value != \"FALSE\") && (row_value != \"false\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcoltype = EidosValueType::kValueInt;\t// try integer next\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (coltype == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tfor (const auto &row : rows)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string &row_value = row[col_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!std::regex_match(row_value, integer_regex))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcoltype = EidosValueType::kValueFloat;\t// try float next\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (coltype == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\tfor (const auto &row : rows)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string &row_value = row[col_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (Eidos_string_equalsCaseInsensitive(row_value, \"NAN\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"INF\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"INFINITY\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"-INF\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"-INFINITY\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"+INF\") ||\n\t\t\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"+INFINITY\"))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!std::regex_match(row_value, float_regex))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcoltype = EidosValueType::kValueString;\t// string is the fallback\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcoltypes[col_index] = coltype;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Make the DataFrame to return\n\tEidosValue_SP result_SP(nullptr);\n\tEidosDataFrame *objectElement = new EidosDataFrame();\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDataFrame_Class));\n\t\n\tobjectElement->Release();\t// objectElement is now retained by result_SP, so we can release it\n\t\n\t// Put the row data into the DataFrame, column by column\n\tint nrows = (int)rows.size();\n\t\n\tfor (int col_index = 0; col_index < ncols; ++col_index)\n\t{\n\t\tEidosValueType coltype = coltypes[col_index];\n\t\t\n\t\t// skip columns if requested\n\t\tif (coltype == EidosValueType::kValueVOID)\n\t\t\tcontinue;\n\t\t\n\t\tif (coltype == EidosValueType::kValueNULL)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): (internal error) column type was not guessed.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_SP column_values;\n\t\t\n\t\tif (coltype == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tEidosValue_Logical *logical_column = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(nrows);\n\t\t\tcolumn_values = EidosValue_SP(logical_column);\n\t\t\t\n\t\t\tfor (int row_index = 0; row_index < nrows; ++row_index)\n\t\t\t{\n\t\t\t\tconst std::string &row_value = rows[row_index][col_index];\n\t\t\t\t\n\t\t\t\tif ((row_value == \"T\") || (row_value == \"TRUE\") || (row_value == \"true\"))\n\t\t\t\t\tlogical_column->set_logical_no_check(true, row_index);\n\t\t\t\telse if ((row_value == \"F\") || (row_value == \"FALSE\") || (row_value == \"false\"))\n\t\t\t\t\tlogical_column->set_logical_no_check(false, row_index);\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): (internal error) unexpected value '\" << row_value << \"' in logical column.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t\telse if (coltype == EidosValueType::kValueInt)\n\t\t{\n\t\t\tEidosValue_Int *integer_column = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(nrows);\n\t\t\tcolumn_values = EidosValue_SP(integer_column);\n\t\t\t\n\t\t\tfor (int row_index = 0; row_index < nrows; ++row_index)\n\t\t\t{\n\t\t\t\tconst std::string &row_value = rows[row_index][col_index];\n\t\t\t\tconst char *row_cstr = row_value.c_str();\n\t\t\t\tchar *last_used_char = nullptr;\n\t\t\t\t\n\t\t\t\terrno = 0;\n\t\t\t\tint64_t int_value = strtoll(row_cstr, &last_used_char, 10);\n\t\t\t\t\n\t\t\t\tif (errno || (last_used_char == row_cstr))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): value '\" << row_value << \"' could not be represented as an integer (strtoll conversion error).\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tinteger_column->set_int_no_check(int_value, row_index);\n\t\t\t}\n\t\t}\n\t\telse if (coltype == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tEidosValue_Float *float_column = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(nrows);\n\t\t\tcolumn_values = EidosValue_SP(float_column);\n\t\t\t\n\t\t\tfor (int row_index = 0; row_index < nrows; ++row_index)\n\t\t\t{\n\t\t\t\tstd::string &row_value = rows[row_index][col_index];\t// non-const here so we can fix the decimal separator\n\t\t\t\tdouble float_value;\n\t\t\t\t\n\t\t\t\tif (Eidos_string_equalsCaseInsensitive(row_value, \"NAN\"))\n\t\t\t\t\tfloat_value = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\telse if (Eidos_string_equalsCaseInsensitive(row_value, \"INF\") ||\n\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"INFINITY\") ||\n\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"+INF\") ||\n\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"+INFINITY\"))\n\t\t\t\t\tfloat_value = std::numeric_limits<double>::infinity();\n\t\t\t\telse if (Eidos_string_equalsCaseInsensitive(row_value, \"-INF\") ||\n\t\t\t\t\tEidos_string_equalsCaseInsensitive(row_value, \"-INFINITY\"))\n\t\t\t\t\tfloat_value = -std::numeric_limits<double>::infinity();\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (dec != '.')\n\t\t\t\t\t{\n\t\t\t\t\t\t// We are in the C locale, so strtod() expects a '.' decimal separator.\n\t\t\t\t\t\tsize_t dec_pos = row_value.find(dec);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (dec_pos != std::string::npos)\n\t\t\t\t\t\t\trow_value.replace(dec_pos, 1, 1, '.');\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tconst char *row_cstr = row_value.c_str();\n\t\t\t\t\tchar *last_used_char = nullptr;\n\t\t\t\t\t\n\t\t\t\t\terrno = 0;\n\t\t\t\t\tfloat_value = strtod(row_cstr, &last_used_char);\n\t\t\t\t\t\n\t\t\t\t\tif (errno || (last_used_char == row_cstr))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): value '\" << row_value << \"' could not be represented as a float (strtod conversion error).\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat_column->set_float_no_check(float_value, row_index);\n\t\t\t}\n\t\t}\n\t\telse if (coltype == EidosValueType::kValueString)\n\t\t{\n\t\t\tEidosValue_String *string_column = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(nrows);\n\t\t\tcolumn_values = EidosValue_SP(string_column);\n\t\t\t\n\t\t\tfor (int row_index = 0; row_index < nrows; ++row_index)\n\t\t\t{\n\t\t\t\tconst std::string &row_value = rows[row_index][col_index];\n\t\t\t\t\n\t\t\t\tstring_column->PushString(row_value);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readCSV): (internal error) unrecognized column type.\" << EidosTerminate(nullptr);\n\t\t\n\t\tobjectElement->SetKeyValue_StringKeys(columnNames[col_index], column_values);\n\t}\n\t\n\tobjectElement->ContentsChanged(\"readCSV()\");\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tEidosDataFrame_Class\n//\n#pragma mark -\n#pragma mark EidosDataFrame_Class\n#pragma mark -\n\nEidosClass *gEidosDataFrame_Class = nullptr;\n\nconst std::vector<EidosPropertySignature_CSP> *EidosDataFrame_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDataFrame_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_colNames,\t\t\ttrue,\tkEidosValueMaskString)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_dim,\t\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_ncol,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_nrow,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *EidosDataFrame_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDataFrame_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_asMatrix, kEidosValueMaskAny)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_cbind, kEidosValueMaskVOID))->AddObject(\"source\", gEidosDictionaryUnretained_Class)->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_rbind, kEidosValueMaskVOID))->AddObject(\"source\", gEidosDictionaryUnretained_Class)->AddEllipsis());\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_subset, kEidosValueMaskAny))\n\t\t\t->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskOptional, \"rows\", nullptr, gStaticEidosValueNULL)\n\t\t\t->AddArgWithDefault(kEidosValueMaskNULL | kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskOptional, \"cols\", nullptr, gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_subsetColumns, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDataFrame_Class))->AddArg(kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskString, \"index\", nullptr));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_subsetRows, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDataFrame_Class))->AddArg(kEidosValueMaskLogical | kEidosValueMaskInt, \"index\", nullptr)->AddLogical_OS(\"drop\", gStaticEidosValue_LogicalF));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosDataFrame_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDataFrame_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_DataFrame, Eidos_Instantiate_EidosDataFrame, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDataFrame_Class))->AddEllipsis());\n\t\t\n\t\t// I'm adding this here rather than in eidos_functions because it feels like a constructor, and thus belongs to the class,\n\t\t// and having the code for it in this source file rather than eidos_functions.cpp feels more cohesive and comprehensible.\n\t\t// Indeed, I can imagine the syntax shifting to DataFrame.newFromCSV() or some such, if Eidos ever makes class objects public.\n\t\t// It is documented in EidosHelpFunctions for now, though, since unless it is *actually* a constructor it would be confusing.\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"readCSV\", Eidos_ExecuteFunction_readCSV, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDataFrame_Class))->AddString_S(\"filePath\")->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional, \"colNames\", nullptr, gStaticEidosValue_LogicalT)->AddString_OSN(\"colTypes\", gStaticEidosValueNULL)->AddString_OS(\"sep\", gStaticEidosValue_StringComma)->AddString_OS(\"quote\", gStaticEidosValue_StringDoubleQuote)->AddString_OS(\"dec\", gStaticEidosValue_StringPeriod)->AddString_OS(\"comment\", gStaticEidosValue_StringEmpty));\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_DataFrame.h",
    "content": "//\n//  eidos_class_DataFrame.h\n//  Eidos\n//\n//  Created by Ben Haller on 10/10/21.\n//  Copyright (c) 2021-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosDataFrame provides a simple dataframe-like object that inherits from Dictionary\n \n */\n\n#ifndef __Eidos__eidos_class_dataframe__\n#define __Eidos__eidos_class_dataframe__\n\n\n#include \"eidos_value.h\"\n\n\nextern EidosClass *gEidosDataFrame_Class;\n\n\nclass EidosDataFrame : public EidosDictionaryRetained\n{\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\t\nprotected:\n\t// We keep a user-defined order for our keys, overriding Dictionary's sorted key order\n\tstd::vector<std::string> sorted_keys_;\n\t\n\tvirtual void Raise_UsesStringKeys() const override __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\t\npublic:\n\tEidosDataFrame(const EidosDataFrame &p_original) = delete;\t\t// no copy-construct\n\tEidosDataFrame& operator=(const EidosDataFrame&) = delete;\t\t// no copying\n\tinline EidosDataFrame(void) { }\n\tinline virtual ~EidosDataFrame(void) override { }\n\t\n\tint ColumnCount(void) const { return KeyCount(); }\t\t\t\t// the number of columns\n\tint RowCount(void) const;\t\t\t\t\t\t\t\t\t\t// the number of rows (for every column)\n\t\n\t// Non-const methods: callers of these methods must ensure that ContentsChanged() is called!\n\tEidosDataFrame *SubsetColumns(EidosValue *index_value);\n\tEidosDataFrame *SubsetRows(EidosValue *index_value, bool drop = false);\n\t\n\t// custom behaviors for string/integer keys: DataFrame does not allow integer keys\n\tvirtual bool KeysAreStrings(void) const override { return true; }\n\tvirtual bool KeysAreIntegers(void) const override { return false; }\n\t\n\t// Provides the keys in the user-visible order: sorted for Dictionary, user-defined for DataFrame\n\tvirtual std::vector<std::string> SortedKeys_StringKeys(void) const override;\n\tvirtual std::vector<int64_t> SortedKeys_IntegerKeys(void) const override;\n\t\n\t// custom behaviors for addition/removal of keys (don't sort) and contents change (check row lengths)\n\tvirtual void KeyAddedToDictionary_StringKeys(const std::string &p_key) override;\n\tvirtual void KeyAddedToDictionary_IntegerKeys(int64_t p_key) override;\n\tvirtual void KeyRemovedFromDictionary_StringKeys(const std::string &p_key) override;\n\tvirtual void KeyRemovedFromDictionary_IntegerKeys(int64_t p_key) override;\n\tvirtual void AllKeysRemoved(void) override;\n\tvirtual void ContentsChanged(const std::string &p_operation_name) override;\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_asMatrix(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_cbind(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_rbind(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subset(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subsetColumns(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_subsetRows(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass EidosDataFrame_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tEidosDataFrame_Class(const EidosDataFrame_Class &p_original) = delete;\t// no copy-construct\n\tEidosDataFrame_Class& operator=(const EidosDataFrame_Class&) = delete;\t// no copying\n\tinline EidosDataFrame_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n};\n\n#endif /* __Eidos__eidos_class_dataframe__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_Dictionary.cpp",
    "content": "//\n//  eidos_class_Dictionary.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 10/12/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"eidos_class_Dictionary.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_value.h\"\n#include \"eidos_functions.h\"\n#include \"json.hpp\"\n\n#include <utility>\n#include <algorithm>\n#include <vector>\n#include <unordered_map>\n#include <string>\n\n\nint64_t gEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n\n\n//\n// EidosDictionaryUnretained\n//\n#pragma mark -\n#pragma mark EidosDictionaryUnretained\n#pragma mark -\n\nEidosDictionaryUnretained::~EidosDictionaryUnretained(void)\n{\n\t// maintain the global counter of dictionaries that contain non-retain-released objects\n\tif (state_ptr_)\n\t{\n\t\tuint8_t contains = ((EidosDictionaryState_StringKeys *)state_ptr_)->contains_non_retain_release_objects_;\n\t\t\n\t\tif (contains)\n\t\t{\n#pragma omp critical (EidosDictionary_Internal)\n\t\t\t{\n\t\t\t\tgEidos_DictionaryNonRetainReleaseReferenceCounter--;\n\t\t\t\t\n\t\t\t\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::~EidosDictionaryUnretained): (internal error) gEidos_DictionaryNonRetainReleaseReferenceCounter is negative\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t//std::cerr << \"=== dictionary \" << this << \" INC   ->   \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << std::endl;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// delete our internal state\n\tif (state_ptr_)\n\t{\n\t\tif (KeysAreStrings())\n\t\t\tdelete (EidosDictionaryState_StringKeys *)state_ptr_;\n\t\telse\n\t\t\tdelete (EidosDictionaryState_IntegerKeys *)state_ptr_;\n\t\t\n\t\tstate_ptr_ = nullptr;\n\t}\n}\n\nvoid EidosDictionaryUnretained::Raise_UsesStringKeys() const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Raise_UsesStringKeys): the target Dictionary object is configured to use string keys; an integer key cannot be used.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosDictionaryUnretained::Raise_UsesIntegerKeys() const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Raise_UsesIntegerKeys): the target Dictionary object is configured to use integer keys; a string key cannot be used.\" << EidosTerminate(nullptr);\n}\n\nstd::vector<std::string> EidosDictionaryUnretained::SortedKeys_StringKeys(void) const\n{\n\t// Dictionary provides keys in sorted order, which is done on demand.  Many use cases\n\t// never need the keys at all, or only once, so we do not maintain the keys sorted.\n\tconst EidosDictionaryHashTable_StringKeys *dict_symbols = DictionarySymbols_StringKeys();\n\t\n\tstd::vector<std::string> string_keys;\n\t\n\tif (dict_symbols)\n\t{\n\t\tfor (auto &iter : *dict_symbols)\n\t\t\tstring_keys.push_back(iter.first);\n\t\t\n\t\tstd::sort(string_keys.begin(), string_keys.end());\n\t}\n\t\n\treturn string_keys;\n}\n\nstd::vector<int64_t> EidosDictionaryUnretained::SortedKeys_IntegerKeys(void) const\n{\n\t// Dictionary provides keys in sorted order, which is done on demand.  Many use cases\n\t// never need the keys at all, or only once, so we do not maintain the keys sorted.\n\tconst EidosDictionaryHashTable_IntegerKeys *dict_symbols = DictionarySymbols_IntegerKeys();\n\t\n\tstd::vector<int64_t> integer_keys;\n\t\n\tif (dict_symbols)\n\t{\n\t\tfor (auto &iter : *dict_symbols)\n\t\t\tinteger_keys.push_back(iter.first);\n\t\t\n\t\tstd::sort(integer_keys.begin(), integer_keys.end());\n\t}\n\t\n\treturn integer_keys;\n}\n\nvoid EidosDictionaryUnretained::KeyAddedToDictionary_StringKeys(__attribute__((unused)) const std::string &p_key)\n{\n\t// Dictionary does not need to do any extra work when a key is added; this is for subclasses\n}\n\nvoid EidosDictionaryUnretained::KeyAddedToDictionary_IntegerKeys(__attribute__((unused)) int64_t p_key)\n{\n\t// Dictionary does not need to do any extra work when a key is added; this is for subclasses\n}\n\nvoid EidosDictionaryUnretained::KeyRemovedFromDictionary_StringKeys(__attribute__((unused)) const std::string &p_key)\n{\n\t// Dictionary does not need to do any extra work when a key is removed; this is for subclasses\n}\n\nvoid EidosDictionaryUnretained::KeyRemovedFromDictionary_IntegerKeys(__attribute__((unused)) int64_t p_key)\n{\n\t// Dictionary does not need to do any extra work when a key is removed; this is for subclasses\n}\n\nvoid EidosDictionaryUnretained::AllKeysRemoved(void)\n{\n\t// Dictionary does not need to do any extra work when a key is removed; this is for subclasses\n}\n\nvoid EidosDictionaryUnretained::ContentsChanged(const std::string &p_operation_name)\n{\n\t// Here we keep track of whether or not we contain any non-retain-release objects\n\t// Note that we don't need to scan down into contained Dictionary objects;\n\t// we retain them, and they will do their own checks of their own contents\n\tif (!state_ptr_)\n\t\treturn;\n\t\n\tuint8_t old_contains = ((EidosDictionaryState_StringKeys *)state_ptr_)->contains_non_retain_release_objects_;\n\tuint8_t new_contains = false;\n\t\n\tif (KeysAreStrings())\n\t{\n\t\tconst EidosDictionaryHashTable_StringKeys *dict_symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\tfor (auto &iter : *dict_symbols)\n\t\t{\n\t\t\tEidosValue *value = iter.second.get();\n\t\t\t\n\t\t\tif ((value->Type() == EidosValueType::kValueObject) && (value->Count() > 0))\n\t\t\t{\n\t\t\t\tconst EidosClass *value_class = ((EidosValue_Object *)value)->Class();\n\t\t\t\t\n\t\t\t\tif (!value_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tnew_contains = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst EidosDictionaryHashTable_IntegerKeys *dict_symbols = DictionarySymbols_IntegerKeys();\n\t\t\n\t\tfor (auto &iter : *dict_symbols)\n\t\t{\n\t\t\tEidosValue *value = iter.second.get();\n\t\t\t\n\t\t\tif ((value->Type() == EidosValueType::kValueObject) && (value->Count() > 0))\n\t\t\t{\n\t\t\t\tconst EidosClass *value_class = ((EidosValue_Object *)value)->Class();\n\t\t\t\t\n\t\t\t\tif (!value_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tnew_contains = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (old_contains != new_contains)\n\t{\n\t\t((EidosDictionaryState_StringKeys *)state_ptr_)->contains_non_retain_release_objects_ = new_contains;\n\t\t\n#pragma omp critical (EidosDictionary_Internal)\n\t\t{\n\t\t\tif (new_contains)\n\t\t\t{\n\t\t\t\tgEidos_DictionaryNonRetainReleaseReferenceCounter++;\n\t\t\t\t\n\t\t\t\t//std::cerr << \"=== dictionary \" << this << \" INC   ->   \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << std::endl;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tgEidos_DictionaryNonRetainReleaseReferenceCounter--;\n\t\t\t\t\n\t\t\t\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ContentsChanged): (internal error) gEidos_DictionaryNonRetainReleaseReferenceCounter is negative in operation \" << p_operation_name << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t//std::cerr << \"   === dictionary \" << this << \" DEC   ->   \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << std::endl;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstd::string EidosDictionaryUnretained::Serialization_SLiM(void) const\n{\n\t// Loop through our key-value pairs and serialize them\n\tif (!state_ptr_)\n\t\treturn \"\";\n\t\n\tstd::ostringstream ss;\n\t\n\tif (KeysAreStrings())\n\t{\n\t\t// Serialize a dictionary with string keys\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\t// We want to output our keys in the same order as allKeys, so we just use AllKeys()\n\t\tEidosValue_SP all_keys = AllKeys();\n\t\tint all_keys_count = all_keys->Count();\n\t\tconst std::string *all_key_strings = all_keys->StringData();\n\t\t\n\t\tfor (int key_index = 0; key_index < all_keys_count; ++key_index)\n\t\t{\n\t\t\tconst std::string key = all_key_strings[key_index];\n\t\t\t\n\t\t\t// emit the key; note that we now always quote stringkeys, to distinguish them from the integer-key case easily\n\t\t\tss << Eidos_string_escaped(key, EidosStringQuoting::kDoubleQuotes) << \"=\";\n\t\t\t\n\t\t\t// emit the value\n\t\t\tauto hash_iter = symbols->find(key);\n\t\t\t\n\t\t\tif (hash_iter == symbols->end())\n\t\t\t{\n\t\t\t\t// We assume that this is not an internal error, but is instead LogFile with a column that is NA;\n\t\t\t\t// it returns all of its column names for AllKeys() even if they have NA as a value, so we play along\n\t\t\t\tss << \"NA;\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tss << *(hash_iter->second) << \";\";\n\t\t\t}\n\t\t}\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\t// Serialize a dictionary with integer keys\n\t\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\t\n\t\t// We want to output our keys in the same order as allKeys, so we just use AllKeys()\n\t\tEidosValue_SP all_keys = AllKeys();\n\t\tEidosValue_Int *integer_vec = (EidosValue_Int *)all_keys.get();\n\t\tconst int64_t *all_key_integers = integer_vec->data();\n\t\tint all_keys_count = integer_vec->Count();\n\t\t\n\t\tfor (int key_index = 0; key_index < all_keys_count; ++key_index)\n\t\t{\n\t\t\tint64_t key = all_key_integers[key_index];\n\t\t\t\n\t\t\t// emit the key\n\t\t\tss << key << \"=\";\n\t\t\t\n\t\t\t// emit the value\n\t\t\tauto hash_iter = symbols->find(key);\n\t\t\t\n\t\t\tif (hash_iter == symbols->end())\n\t\t\t{\n\t\t\t\t// We assume that this is not an internal error, but is instead LogFile with a column that is NA;\n\t\t\t\t// it returns all of its column names for AllKeys() even if they have NA as a value, so we play along\n\t\t\t\tss << \"NA;\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tss << *(hash_iter->second) << \";\";\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn ss.str();\n}\n\nstd::string EidosDictionaryUnretained::Serialization_Pretty(int indent_level) const\n{\n\t// Loop through our key-value pairs and serialize them\n\tif (!state_ptr_)\n\t\treturn \"{}\";\n\t\n\tstd::ostringstream ss;\n\t\n\tss << \"{\";\n\tindent_level++;\n\t\n\tif (KeysAreStrings())\n\t{\n\t\t// Serialize a dictionary with string keys\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\t// We want to output our keys in the same order as allKeys, so we just use AllKeys()\n\t\tEidosValue_SP all_keys = AllKeys();\n\t\tint all_keys_count = all_keys->Count();\n\t\tconst std::string *all_key_strings = all_keys->StringData();\n\t\t\n\t\tfor (int key_index = 0; key_index < all_keys_count; ++key_index)\n\t\t{\n\t\t\tif (key_index == 0)\n\t\t\t\tss << std::endl;\n\t\t\tss << std::string(indent_level, '\\t');\n\t\t\t\n\t\t\tconst std::string key = all_key_strings[key_index];\n\t\t\t\n\t\t\t// emit the key; note that we now always quote stringkeys, to distinguish them from the integer-key case easily\n\t\t\tss << Eidos_string_escaped(key, EidosStringQuoting::kDoubleQuotes) << \" = \";\n\t\t\t\n\t\t\t// emit the value\n\t\t\tauto hash_iter = symbols->find(key);\n\t\t\t\n\t\t\tif (hash_iter == symbols->end())\n\t\t\t{\n\t\t\t\t// We assume that this is not an internal error, but is instead LogFile with a column that is NA;\n\t\t\t\t// it returns all of its column names for AllKeys() even if they have NA as a value, so we play along\n\t\t\t\tss << \"NA\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue *value = hash_iter->second.get();\n\t\t\t\t\n\t\t\t\tif ((value->Type() == EidosValueType::kValueObject) &&\n\t\t\t\t\t((((EidosValue_Object *)value)->Class() == gEidosDictionaryUnretained_Class) || (((EidosValue_Object *)value)->Class() == gEidosDictionaryRetained_Class)))\n\t\t\t\t{\n\t\t\t\t\t// Dictionaries get serialized by recursion; subclasses of them do not\n\t\t\t\t\tint value_count = value->Count();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (value_index > 0)\n\t\t\t\t\t\t\tss << \" \";\n\t\t\t\t\t\t\n\t\t\t\t\t\tEidosDictionaryUnretained *dict = (EidosDictionaryUnretained *)value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tss << dict->Serialization_Pretty(indent_level);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tss << *value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tss << std::endl;\n\t\t}\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\t// Serialize a dictionary with integer keys\n\t\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\t\n\t\t// We want to output our keys in the same order as allKeys, so we just use AllKeys()\n\t\tEidosValue_SP all_keys = AllKeys();\n\t\tEidosValue_Int *integer_vec = (EidosValue_Int *)all_keys.get();\n\t\tconst int64_t *all_key_integers = integer_vec->data();\n\t\tint all_keys_count = integer_vec->Count();\n\t\t\n\t\tfor (int key_index = 0; key_index < all_keys_count; ++key_index)\n\t\t{\n\t\t\tif (key_index == 0)\n\t\t\t\tss << std::endl;\n\t\t\tss << std::string(indent_level, '\\t');\n\t\t\t\n\t\t\tint64_t key = all_key_integers[key_index];\n\t\t\t\n\t\t\t// emit the key\n\t\t\tss << key << \" = \";\n\t\t\t\n\t\t\t// emit the value\n\t\t\tauto hash_iter = symbols->find(key);\n\t\t\t\n\t\t\tif (hash_iter == symbols->end())\n\t\t\t{\n\t\t\t\t// We assume that this is not an internal error, but is instead LogFile with a column that is NA;\n\t\t\t\t// it returns all of its column names for AllKeys() even if they have NA as a value, so we play along\n\t\t\t\tss << \"NA;\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue *value = hash_iter->second.get();\n\t\t\t\t\n\t\t\t\tif ((value->Type() == EidosValueType::kValueObject) &&\n\t\t\t\t\t((((EidosValue_Object *)value)->Class() == gEidosDictionaryUnretained_Class) || (((EidosValue_Object *)value)->Class() == gEidosDictionaryRetained_Class)))\n\t\t\t\t{\n\t\t\t\t\t// Dictionaries get serialized by recursion; subclasses of them do not\n\t\t\t\t\tint value_count = value->Count();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (value_index > 0)\n\t\t\t\t\t\t\tss << \" \";\n\t\t\t\t\t\t\n\t\t\t\t\t\tEidosDictionaryUnretained *dict = (EidosDictionaryUnretained *)value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tss << dict->Serialization_Pretty(indent_level);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tss << *value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tss << std::endl;\n\t\t}\n\t}\n\t\n\tindent_level--;\n\tss << std::string(indent_level, '\\t') << \"}\";\n\t\n\treturn ss.str();\n}\n\nEidosValue_SP EidosDictionaryUnretained::Serialization_CSV(const std::string &p_delimiter) const\n{\n\tif (!state_ptr_)\n\t\treturn gStaticEidosValue_StringEmpty;\n\t\n\t// Determine the longest column, and also generate our header string\n\tbool keysAreStrings = KeysAreStrings();\n\tconst EidosDictionaryHashTable_StringKeys *symbols_string = nullptr;\n\tconst EidosDictionaryHashTable_IntegerKeys *symbols_integer = nullptr;\n\tstd::vector<std::string> keys_string;\n\tstd::vector<int64_t> keys_integer;\n\tsize_t keys_count;\n\tint longest_col = 0;\n\t\n\tif (keysAreStrings)\n\t{\n\t\tsymbols_string = DictionarySymbols_StringKeys();\n\t\tkeys_string = SortedKeys_StringKeys();\n\t\tkeys_count = keys_string.size();\n\t\t\n\t\tfor (auto const &kv_pair : *symbols_string)\n\t\t\tlongest_col = std::max(longest_col, kv_pair.second->Count());\n\t}\n\telse\n\t{\n\t\tsymbols_integer = DictionarySymbols_IntegerKeys();\n\t\tkeys_integer = SortedKeys_IntegerKeys();\n\t\tkeys_count = keys_integer.size();\n\t\t\n\t\tfor (auto const &kv_pair : *symbols_integer)\n\t\t\tlongest_col = std::max(longest_col, kv_pair.second->Count());\n\t}\n\t\n\t// Make a string vector big enough for everything\n\tint result_count = longest_col + 1;\t\t// room for the header\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(result_count);\n\tEidosValue_SP result_SP(string_result);\n\t\n\t// Generate the header\n\t{\n\t\tstd::ostringstream ss;\n\t\tbool first = true;\n\t\t\n\t\tfor (size_t i = 0; i < keys_count; ++i)\n\t\t{\n\t\t\tif (!first)\n\t\t\t\tss << p_delimiter;\n\t\t\tfirst = false;\n\t\t\t\n\t\t\tif (keysAreStrings)\n\t\t\t\tss << Eidos_string_escaped_CSV(keys_string[i]);\n\t\t\telse\n\t\t\t\tss << keys_integer[i];\n\t\t}\n\t\t\n\t\tstring_result->PushString(ss.str());\n\t}\n\t\n\t// Generate the rows\n\tfor (int row_index = 0; row_index < longest_col; ++row_index)\n\t{\n\t\tstd::ostringstream ss;\n\t\tbool first = true;\n\t\t\n\t\tfor (size_t i = 0; i < keys_count; ++i)\n\t\t{\n\t\t\tif (!first)\n\t\t\t\tss << p_delimiter;\n\t\t\tfirst = false;\n\t\t\t\n\t\t\tEidosValue *value = nullptr;\n\t\t\t\n\t\t\tif (keysAreStrings)\n\t\t\t{\n\t\t\t\tauto col_iter = symbols_string->find(keys_string[i]);\n\t\t\t\t\n\t\t\t\tif (col_iter != symbols_string->end())\n\t\t\t\t\tvalue = col_iter->second.get();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto col_iter = symbols_integer->find(keys_integer[i]);\n\t\t\t\t\n\t\t\t\tif (col_iter != symbols_integer->end())\n\t\t\t\t\tvalue = col_iter->second.get();\n\t\t\t}\n\t\t\t\n\t\t\tif (!value)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Serialization_CSV): (internal error) column not found.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint value_count = value->Count();\n\t\t\t\n\t\t\t// if a column has no value for this row, we just skip it (but with the delimiter we already emitted)\n\t\t\tif (row_index < value_count)\n\t\t\t{\n\t\t\t\tswitch (value->Type())\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueVOID:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Serialization_CSV): cannot serialize values of type void to CSV/TSV.\" << EidosTerminate(nullptr);\n\t\t\t\t\tcase EidosValueType::kValueNULL:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Serialization_CSV): cannot serialize values of type NULL to CSV/TSV.\" << EidosTerminate(nullptr);\n\t\t\t\t\tcase EidosValueType::kValueObject:\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::Serialization_CSV): cannot serialize values of type object to CSV/TSV.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosValueType::kValueLogical: ss << (value->LogicalAtIndex_NOCAST(row_index, nullptr) ? \"TRUE\" : \"FALSE\"); break;\n\t\t\t\t\tcase EidosValueType::kValueInt: ss << value->IntAtIndex_NOCAST(row_index, nullptr); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\n\t\t\t\t\t{\n\t\t\t\t\t\tint old_precision = gEidosFloatOutputPrecision;\n\t\t\t\t\t\tgEidosFloatOutputPrecision = EIDOS_DBL_DIGS - 2;\t// try to avoid ugly values that exhibit the precision limits\n\t\t\t\t\t\tss << EidosStringForFloat(value->FloatAtIndex_NOCAST(row_index, nullptr));\n\t\t\t\t\t\tgEidosFloatOutputPrecision = old_precision;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase EidosValueType::kValueString:\n\t\t\t\t\t{\n\t\t\t\t\t\tss << Eidos_string_escaped_CSV(value->StringAtIndex_NOCAST(row_index, nullptr));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tstring_result->PushString(ss.str());\n\t}\n\t\n\treturn result_SP;\n}\n\nnlohmann::json EidosDictionaryUnretained::JSONRepresentation(void) const\n{\n\tif (!KeysAreStrings())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::JSONRepresentation): Dictionary does not support JSON serialization with integer keys, because JSON itself does not support integer keys.\" << EidosTerminate(nullptr);\n\t\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\tnlohmann::json json_object = nlohmann::json::object();\n\t\n\t// We want to output our keys in the same order as allKeys, so we just use AllKeys()\n\tEidosValue_SP all_keys = AllKeys();\n\tint all_keys_count = all_keys->Count();\n\tconst std::string *all_key_strings = all_keys->StringData();\n\t\n\tfor (int key_index = 0; key_index < all_keys_count; ++key_index)\n\t{\n\t\tconst std::string key = all_key_strings[key_index];\n\t\t\n\t\t// get the value\n\t\tauto hash_iter = symbols->find(key);\n\t\t\n\t\tif (hash_iter == symbols->end())\n\t\t{\n\t\t\t// We assume that this is not an internal error, but is instead LogFile with a column that is NA;\n\t\t\t// it returns all of its column names for AllKeys() even if they have NA as a value, so we play along\n\t\t\tjson_object[key] = nullptr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue *value = hash_iter->second.get();\n\t\t\t\n\t\t\tjson_object[key] = value->JSONRepresentation();\n\t\t}\n\t}\n\t\n\treturn json_object;\n}\n\nvoid EidosDictionaryUnretained::SetKeyValue_StringKeys(const std::string &key, EidosValue_SP value)\n{\n\tAssertKeysAreStrings();\n\t\n\tEidosDictionaryState_StringKeys *state_ptr = (EidosDictionaryState_StringKeys *)state_ptr_;\n\tEidosValueType value_type = value->Type();\n\t\n\t// BCH 2/12/2023: We now allow objects to be put into dictionaries whether they use retain-release or not,\n\t// so we no longer check for that here.  See EidosDictionaryUnretained::ContentsChanged() and search for\n\t// contains_non_retain_release_objects_ and gEidos_DictionaryNonRetainReleaseReferenceCounter.\n\t\n\tif (value_type == EidosValueType::kValueNULL)\n\t{\n\t\t// Setting a key to NULL removes it from the map; if we have no state, that is a no-op\n\t\tif (state_ptr)\n\t\t{\n\t\t\tstate_ptr->dictionary_symbols_.erase(key);\n\t\t\tKeyRemovedFromDictionary_StringKeys(key);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!state_ptr)\n\t\t{\n\t\t\tstate_ptr = new EidosDictionaryState_StringKeys();\n\t\t\tstate_ptr->keys_are_integers_ = false;\n\t\t\tstate_ptr_ = state_ptr;\n\t\t}\n\t\t\n\t\t// Copy if necessary; see ExecuteMethod_Accelerated_setValue() for comments\n\t\tif ((value->UseCount() != 1) || value->Invisible())\n\t\t\tvalue = value->CopyValues();\n\t\t\n\t\tstate_ptr->dictionary_symbols_[key] = value;\n\t\t\n\t\t// Add it to our sorted keys\n\t\tKeyAddedToDictionary_StringKeys(key);\n\t}\n}\n\nvoid EidosDictionaryUnretained::SetKeyValue_IntegerKeys(int64_t key, EidosValue_SP value)\n{\n\tAssertKeysAreIntegers();\n\t\n\tEidosDictionaryState_IntegerKeys *state_ptr = (EidosDictionaryState_IntegerKeys *)state_ptr_;\n\tEidosValueType value_type = value->Type();\n\t\n\t// BCH 2/12/2023: We now allow objects to be put into dictionaries whether they use retain-release or not,\n\t// so we no longer check for that here.  See EidosDictionaryUnretained::ContentsChanged() and search for\n\t// contains_non_retain_release_objects_ and gEidos_DictionaryNonRetainReleaseReferenceCounter.\n\t\n\tif (value_type == EidosValueType::kValueNULL)\n\t{\n\t\t// Setting a key to NULL removes it from the map; if we have no state, that is a no-op\n\t\tif (state_ptr)\n\t\t{\n\t\t\tstate_ptr->dictionary_symbols_.erase(key);\n\t\t\tKeyRemovedFromDictionary_IntegerKeys(key);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!state_ptr)\n\t\t{\n\t\t\tstate_ptr = new EidosDictionaryState_IntegerKeys();\n\t\t\tstate_ptr->keys_are_integers_ = true;\n\t\t\tstate_ptr_ = state_ptr;\n\t\t}\n\t\t\n\t\t// Copy if necessary; see ExecuteMethod_Accelerated_setValue() for comments\n\t\tif ((value->UseCount() != 1) || value->Invisible())\n\t\t\tvalue = value->CopyValues();\n\t\t\n\t\tstate_ptr->dictionary_symbols_[key] = value;\n\t\t\n\t\t// Add it to our sorted keys\n\t\tKeyAddedToDictionary_IntegerKeys(key);\n\t}\n}\n\nEidosValue_SP EidosDictionaryUnretained::GetValueForKey_StringKeys(const std::string &key)\n{\n\t// see also EidosDictionaryUnretained::ExecuteMethod_getValue()\n\tAssertKeysAreStrings();\n\t\n\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\n\tif (!symbols)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tauto found_iter = symbols->find(key);\n\t\n\tif (found_iter == symbols->end())\n\t{\n\t\treturn gStaticEidosValueNULL;\n\t}\n\telse\n\t{\n\t\treturn found_iter->second;\n\t}\n}\n\nEidosValue_SP EidosDictionaryUnretained::GetValueForKey_IntegerKeys(int64_t key)\n{\n\t// see also EidosDictionaryUnretained::ExecuteMethod_getValue()\n\tAssertKeysAreIntegers();\n\t\n\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\n\tif (!symbols)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tauto found_iter = symbols->find(key);\n\t\n\tif (found_iter == symbols->end())\n\t{\n\t\treturn gStaticEidosValueNULL;\n\t}\n\telse\n\t{\n\t\treturn found_iter->second;\n\t}\n}\n\nEidosValue_SP EidosDictionaryUnretained::AllKeys(void) const\n{\n\tif (KeysAreStrings())\n\t{\n\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\tint key_count = (int)keys.size();\n\t\t\n\t\tif (key_count == 0)\n\t\t\treturn gStaticEidosValue_String_ZeroVec;\n\t\t\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(key_count);\n\t\t\n\t\tfor (const std::string &key : keys)\n\t\t\tstring_result->PushString(key);\n\t\t\n\t\treturn EidosValue_SP(string_result);\n\t}\n\telse\n\t{\n\t\tconst std::vector<int64_t> keys = SortedKeys_IntegerKeys();\n\t\tint key_count = (int)keys.size();\n\t\t\n\t\tif (key_count == 0)\n\t\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\t\n\t\tEidosValue_Int *integer_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve(key_count);\n\t\t\n\t\tfor (int64_t key : keys)\n\t\t\tinteger_result->push_int_no_check(key);\n\t\t\n\t\treturn EidosValue_SP(integer_result);\n\t}\n}\n\nvoid EidosDictionaryUnretained::AddKeysAndValuesFrom(EidosDictionaryUnretained *p_source, bool p_allow_replace /* = true */)\n{\n\t// Loop through the key-value pairs of source and add them\n\tif (!p_source->state_ptr_)\n\t\treturn;\n\t\n\tif (p_source->KeysAreStrings())\n\t{\n\t\tAssertKeysAreStrings();\n\t\t\n\t\tconst EidosDictionaryHashTable_StringKeys *source_symbols = p_source->DictionarySymbols_StringKeys();\n\t\tconst std::vector<std::string> source_keys = p_source->SortedKeys_StringKeys();\n\t\t\n\t\tif (source_symbols && source_symbols->size())\n\t\t{\n\t\t\tEidosDictionaryState_StringKeys *state_ptr = (EidosDictionaryState_StringKeys *)state_ptr_;\n\t\t\t\n\t\t\tif (!state_ptr)\n\t\t\t{\n\t\t\t\tstate_ptr = new EidosDictionaryState_StringKeys();\n\t\t\t\tstate_ptr->keys_are_integers_ = false;\n\t\t\t\tstate_ptr_ = state_ptr;\n\t\t\t}\n\t\t\t\n\t\t\tfor (const std::string &key : source_keys)\n\t\t\t{\n\t\t\t\tauto kv_pair = source_symbols->find(key);\n\t\t\t\tconst EidosValue_SP &value = kv_pair->second;\n\t\t\t\t\n\t\t\t\tif (!p_allow_replace)\n\t\t\t\t{\n\t\t\t\t\t// This is for DataFrame's -cbind(), which does not want to replace existing columns\n\t\t\t\t\tauto check_iter = state_ptr->dictionary_symbols_.find(key);\n\t\t\t\t\t\n\t\t\t\t\tif (check_iter != state_ptr->dictionary_symbols_.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddKeysAndValuesFrom): a column named '\" << key << \"' already exists.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// always copy values here; unlike setValue(), we know the value is in use elsewhere\n\t\t\t\tstate_ptr->dictionary_symbols_[key] = value->CopyValues();\n\t\t\t\t\n\t\t\t\tKeyAddedToDictionary_StringKeys(key);\n\t\t\t}\n\t\t}\n\t}\n\telse\t// p_source->KeysAreIntegers()\n\t{\n\t\tAssertKeysAreIntegers();\n\t\t\n\t\tconst EidosDictionaryHashTable_IntegerKeys *source_symbols = p_source->DictionarySymbols_IntegerKeys();\n\t\tconst std::vector<int64_t> source_keys = p_source->SortedKeys_IntegerKeys();\n\t\t\n\t\tif (source_symbols && source_symbols->size())\n\t\t{\n\t\t\tEidosDictionaryState_IntegerKeys *state_ptr = (EidosDictionaryState_IntegerKeys *)state_ptr_;\n\t\t\t\n\t\t\tif (!state_ptr)\n\t\t\t{\n\t\t\t\tstate_ptr = new EidosDictionaryState_IntegerKeys();\n\t\t\t\tstate_ptr->keys_are_integers_ = true;\n\t\t\t\tstate_ptr_ = state_ptr;\n\t\t\t}\n\t\t\t\n\t\t\tfor (int64_t key : source_keys)\n\t\t\t{\n\t\t\t\tauto kv_pair = source_symbols->find(key);\n\t\t\t\tconst EidosValue_SP &value = kv_pair->second;\n\t\t\t\t\n\t\t\t\tif (!p_allow_replace)\n\t\t\t\t{\n\t\t\t\t\t// This is for DataFrame's -cbind(), which does not want to replace existing columns\n\t\t\t\t\tauto check_iter = state_ptr->dictionary_symbols_.find(key);\n\t\t\t\t\t\n\t\t\t\t\tif (check_iter != state_ptr->dictionary_symbols_.end())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddKeysAndValuesFrom): a column named \" << key << \" already exists.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// always copy values here; unlike setValue(), we know the value is in use elsewhere\n\t\t\t\tstate_ptr->dictionary_symbols_[key] = value->CopyValues();\n\t\t\t\t\n\t\t\t\tKeyAddedToDictionary_IntegerKeys(key);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid EidosDictionaryUnretained::AppendKeysAndValuesFrom(EidosDictionaryUnretained *p_source, bool p_require_column_match /* = false */)\n{\n\t// Check for x.appendKeysAndValuesFrom(x); I'm not sure that this would confuse the iterator below, but it seems like a bad idea\n\tif (p_source == this)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AppendKeysAndValuesFrom): cannot append a Dictionary to itself.\" << EidosTerminate(nullptr);\n\t\n\tif (!p_source->state_ptr_)\n\t\treturn;\n\t\n\tif (p_source->KeysAreStrings())\n\t{\n\t\tAssertKeysAreStrings();\n\t\t\n\t\t// Loop through the key-value pairs of source and add them\n\t\tconst EidosDictionaryHashTable_StringKeys *source_symbols = p_source->DictionarySymbols_StringKeys();\n\t\t\n\t\tif (source_symbols && source_symbols->size())\n\t\t{\n\t\t\tEidosDictionaryState_StringKeys *state_ptr = (EidosDictionaryState_StringKeys *)state_ptr_;\n\t\t\t\n\t\t\tif (!state_ptr_)\n\t\t\t{\n\t\t\t\tstate_ptr = new EidosDictionaryState_StringKeys();\n\t\t\t\tstate_ptr->keys_are_integers_ = false;\n\t\t\t\tstate_ptr_ = state_ptr;\n\t\t\t}\n\t\t\t\n\t\t\tconst std::vector<std::string> source_keys = p_source->SortedKeys_StringKeys();\n\t\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\t\t\n\t\t\t// This is for DataFrame's rbind(), which wants columns to match exactly (if any columns are already there)\n\t\t\tif (p_require_column_match && keys.size() && (keys != source_keys))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AppendKeysAndValuesFrom): the columns of the target do not match the columns of the dictionary being appended.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfor (const std::string &key : source_keys)\n\t\t\t{\n\t\t\t\tauto kv_pair = source_symbols->find(key);\n\t\t\t\tconst EidosValue_SP &keyvalue = kv_pair->second;\n\t\t\t\t\n\t\t\t\tauto found_iter = state_ptr->dictionary_symbols_.find(key);\n\t\t\t\t\n\t\t\t\tif (found_iter == state_ptr->dictionary_symbols_.end())\n\t\t\t\t{\n\t\t\t\t\t// always copy values here; unlike setValue(), we know the value is in use elsewhere\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = keyvalue->CopyValues();\n\t\t\t\t\t\n\t\t\t\t\tKeyAddedToDictionary_StringKeys(key);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we already have a value; append (which could be done in place, since we have sole ownership of our values,\n\t\t\t\t\t// but at present we're not that smart, and it's complicated since our existing value might be a singleton)\n\t\t\t\t\tEidosValue_SP existing_value = found_iter->second;\n\t\t\t\t\tstd::vector<EidosValue_SP> cat_args = {existing_value, keyvalue};\n\t\t\t\t\tEidosValue_SP appended_value = ConcatenateEidosValues(cat_args, false, false);\n\t\t\t\t\t\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = appended_value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tAssertKeysAreIntegers();\n\t\t\n\t\t// Loop through the key-value pairs of source and add them\n\t\tconst EidosDictionaryHashTable_IntegerKeys *source_symbols = p_source->DictionarySymbols_IntegerKeys();\n\t\t\n\t\tif (source_symbols && source_symbols->size())\n\t\t{\n\t\t\tEidosDictionaryState_IntegerKeys *state_ptr = (EidosDictionaryState_IntegerKeys *)state_ptr_;\n\t\t\t\n\t\t\tif (!state_ptr_)\n\t\t\t{\n\t\t\t\tstate_ptr = new EidosDictionaryState_IntegerKeys();\n\t\t\t\tstate_ptr->keys_are_integers_ = true;\n\t\t\t\tstate_ptr_ = state_ptr;\n\t\t\t}\n\t\t\t\n\t\t\tconst std::vector<int64_t> source_keys = p_source->SortedKeys_IntegerKeys();\n\t\t\tconst std::vector<int64_t> keys = SortedKeys_IntegerKeys();\n\t\t\t\n\t\t\t// This is for DataFrame's rbind(), which wants columns to match exactly (if any columns are already there)\n\t\t\tif (p_require_column_match && keys.size() && (keys != source_keys))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AppendKeysAndValuesFrom): the columns of the target do not match the columns of the dictionary being appended.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfor (int64_t key : source_keys)\n\t\t\t{\n\t\t\t\tauto kv_pair = source_symbols->find(key);\n\t\t\t\tconst EidosValue_SP &keyvalue = kv_pair->second;\n\t\t\t\t\n\t\t\t\tauto found_iter = state_ptr->dictionary_symbols_.find(key);\n\t\t\t\t\n\t\t\t\tif (found_iter == state_ptr->dictionary_symbols_.end())\n\t\t\t\t{\n\t\t\t\t\t// always copy values here; unlike setValue(), we know the value is in use elsewhere\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = keyvalue->CopyValues();\n\t\t\t\t\t\n\t\t\t\t\tKeyAddedToDictionary_IntegerKeys(key);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we already have a value; append (which could be done in place, since we have sole ownership of our values,\n\t\t\t\t\t// but at present we're not that smart, and it's complicated since our existing value might be a singleton)\n\t\t\t\t\tEidosValue_SP existing_value = found_iter->second;\n\t\t\t\t\tstd::vector<EidosValue_SP> cat_args = {existing_value, keyvalue};\n\t\t\t\t\tEidosValue_SP appended_value = ConcatenateEidosValues(cat_args, false, false);\n\t\t\t\t\t\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = appended_value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid EidosDictionaryUnretained::AddJSONFrom(nlohmann::json &json)\n{\n\tif (!KeysAreStrings())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddJSONFrom): JSON objects can only be added to a dictionary that uses string keys, since JSON uses string keys.\" << EidosTerminate(nullptr);\n\t\n\tEidosDictionaryState_StringKeys *state_ptr = (EidosDictionaryState_StringKeys *)state_ptr_;\n\t\n\t// null at the top level indicates an empty dictionary, so we just return\n\tif (!json.is_null())\n\t{\n\t\t// otherwise, we require the top level to be a JSON \"object\" - a key-value dictionary\n\t\tif (json.is_object())\n\t\t{\n\t\t\t// iterate over the key-value pairs in the \"object\"\n\t\t\tfor (auto &element : json.items())\n\t\t\t{\n\t\t\t\tif (!state_ptr)\n\t\t\t\t{\n\t\t\t\t\tstate_ptr = new EidosDictionaryState_StringKeys();\n\t\t\t\t\tstate_ptr->keys_are_integers_ = false;\n\t\t\t\t\tstate_ptr_ = state_ptr;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tstd::string key = element.key();\n\t\t\t\tauto &value = element.value();\n\t\t\t\t\n\t\t\t\t//std::cout << element.key() << \" : \" << element.value() << std::endl;\n\t\t\t\t\n\t\t\t\t// decode the value and assign it to the key\n\t\t\t\tif (value.is_null())\n\t\t\t\t{\n\t\t\t\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\t\t\t\tdictionary->Release();\t\t// now retained by state_ptr->dictionary_symbols_\n\t\t\t\t}\n\t\t\t\telse if (value.is_boolean())\n\t\t\t\t{\n\t\t\t\t\tbool boolean_value = value;\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = (boolean_value ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\t}\n\t\t\t\telse if (value.is_string())\n\t\t\t\t{\n\t\t\t\t\tconst std::string &string_value = value;\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(string_value));\n\t\t\t\t}\n\t\t\t\telse if (value.is_number_integer() || value.is_number_unsigned())\n\t\t\t\t{\n\t\t\t\t\tint64_t int_value = value;\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(int_value));\n\t\t\t\t}\n\t\t\t\telse if (value.is_number_float())\n\t\t\t\t{\n\t\t\t\t\tdouble float_value = value;\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(float_value));\n\t\t\t\t}\n\t\t\t\telse if (value.is_object())\n\t\t\t\t{\n\t\t\t\t\tEidosDictionaryRetained *dictionary = new EidosDictionaryRetained();\n\t\t\t\t\tdictionary->AddJSONFrom(value);\n\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(dictionary, gEidosDictionaryRetained_Class));\n\t\t\t\t\tdictionary->Release();\t\t// now retained by state_ptr->dictionary_symbols_\n\t\t\t\t}\n\t\t\t\telse if (value.is_array())\n\t\t\t\t{\n\t\t\t\t\tsize_t array_count = value.size();\n\t\t\t\t\t\n\t\t\t\t\tif (array_count == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We don't what type the empty vector is; we assume integer\n\t\t\t\t\t\t// This means that empty vectors don't persist accurately through JSON; I see no solution\n\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = gStaticEidosValue_Integer_ZeroVec;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// figure out the type of element 0; we fold unsigned and integer together, and we fold null and object together\n\t\t\t\t\t\tnlohmann::json::value_t array_type = value[0].type();\n\t\t\t\t\t\tif (array_type == nlohmann::json::value_t::number_unsigned)\n\t\t\t\t\t\t\tarray_type = nlohmann::json::value_t::number_integer;\n\t\t\t\t\t\tif (array_type == nlohmann::json::value_t::null)\n\t\t\t\t\t\t\tarray_type = nlohmann::json::value_t::object;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// confirm that all elements in the array have the same type, since Eidos vectors are on a single type\n\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlohmann::json::value_t element_type = value[element_index].type();\n\t\t\t\t\t\t\tif (element_type == nlohmann::json::value_t::number_unsigned)\n\t\t\t\t\t\t\t\telement_type = nlohmann::json::value_t::number_integer;\n\t\t\t\t\t\t\tif (element_type == nlohmann::json::value_t::null)\n\t\t\t\t\t\t\t\telement_type = nlohmann::json::value_t::object;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (element_type != array_type)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddJSONFrom): AddJSONFrom() requires that JSON arrays be of a single type, since Eidos vectors are of a single type.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// ok, all elements are of a single type, so let's create a vector of that type from the values in the array\n\t\t\t\t\t\tif (array_type == nlohmann::json::value_t::number_integer)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosValue_Int *int_value = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(array_count);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint64_t int_element = value[element_index];\n\t\t\t\t\t\t\t\tint_value->set_int_no_check(int_element, element_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(int_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (array_type == nlohmann::json::value_t::number_float)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosValue_Float *float_value = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(array_count);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tdouble float_element = value[element_index];\n\t\t\t\t\t\t\t\tfloat_value->set_float_no_check(float_element, element_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(float_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (array_type == nlohmann::json::value_t::boolean)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosValue_Logical *logical_value = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(array_count);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbool boolean_element = value[element_index];\n\t\t\t\t\t\t\t\tlogical_value->set_logical_no_check(boolean_element, element_index);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(logical_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (array_type == nlohmann::json::value_t::string)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosValue_String *string_value = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)array_count);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconst std::string &string_element = value[element_index];\n\t\t\t\t\t\t\t\tstring_value->PushString(string_element);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(string_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (array_type == nlohmann::json::value_t::object)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosValue_Object *object_value = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosDictionaryRetained_Class);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (size_t element_index = 0; element_index < array_count; ++element_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosDictionaryRetained *element_dictionary = new EidosDictionaryRetained();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tobject_value->push_object_element_RR(element_dictionary);\t// retain it in object_value\n\t\t\t\t\t\t\t\telement_dictionary->Release();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (value[element_index].type() == nlohmann::json::value_t::object)\n\t\t\t\t\t\t\t\t\telement_dictionary->AddJSONFrom(value[element_index]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tstate_ptr->dictionary_symbols_[key] = EidosValue_SP(object_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddJSONFrom): unsupported array value type '\" << value[0].type_name() << \"' in AddJSONFrom().\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddJSONFrom): unsupported value type '\" << value.type_name() << \"' in AddJSONFrom().\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tKeyAddedToDictionary_StringKeys(key);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::AddJSONFrom): AddJSONFrom() can only parse JSON strings that represent a JSON 'object'; i.e., a dictionary of key-value pairs.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n}\n\n\n//\n// EidosDictionaryUnretained Eidos support\n//\n#pragma mark -\n#pragma mark EidosDictionaryUnretained Eidos support\n#pragma mark -\n\nconst EidosClass *EidosDictionaryUnretained::Class(void) const\n{\n\treturn gEidosDictionaryUnretained_Class;\n}\n\nvoid EidosDictionaryUnretained::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << \"{\" << Serialization_SLiM() << \"}\";\n}\n\nEidosValue_SP EidosDictionaryUnretained::GetProperty(EidosGlobalStringID p_property_id)\n{\n#if DEBUG\n\t// Check for correctness before dispatching out; perhaps excessively cautious, but checks are good\n\tContentsChanged(\"EidosDictionaryUnretained::GetProperty\");\n#endif\n\t\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gEidosID_allKeys:\n\t\t\treturn AllKeys();\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue_SP EidosDictionaryUnretained::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#if DEBUG\n\t// Check for correctness before dispatching out; perhaps excessively cautious, but checks are good\n\tContentsChanged(\"EidosDictionaryUnretained::ExecuteInstanceMethod\");\n#endif\n\t\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_addKeysAndValuesFrom:\t\treturn ExecuteMethod_addKeysAndValuesFrom(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_appendKeysAndValuesFrom:\treturn ExecuteMethod_appendKeysAndValuesFrom(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_clearKeysAndValues:\t\treturn ExecuteMethod_clearKeysAndValues(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_compactIndices:\t\t\treturn ExecuteMethod_compactIndices(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_getRowValues:\t\t\t\treturn ExecuteMethod_getRowValues(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_getValue:\t\t\t\t\treturn ExecuteMethod_getValue(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_identicalContents:\t\treturn ExecuteMethod_identicalContents(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_serialize:\t\t\t\treturn ExecuteMethod_serialize(p_method_id, p_arguments, p_interpreter);\n\t\t//case gEidosID_setValue:\t\t\t\treturn ExecuteMethod_Accelerated_setValue(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t- (void)addKeysAndValuesFrom(object<Dictionary>$ source)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_addKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *source_value = p_arguments[0].get();\n\t\n\t// Check that source is a subclass of EidosDictionaryUnretained.  We do this check here because we want to avoid making\n\t// EidosDictionaryUnretained visible in the public API; we want to pretend that there is just one class, Dictionary.\n\t// I'm not sure whether that's going to be right in the long term, but I want to keep my options open for now.\n\tEidosDictionaryUnretained *source = (EidosDictionaryUnretained *)source_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\n\tAddKeysAndValuesFrom(source);\n\t\n\tContentsChanged(\"addKeysAndValuesFrom()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)appendKeysAndValuesFrom(object<Dictionary> source)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_appendKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *source_value = p_arguments[0].get();\n\tint source_count = source_value->Count();\n\t\n\t// Loop through elements in source and handle them sequentially\n\tfor (int value_index = 0; value_index < source_count; ++value_index)\n\t{\n\t\tEidosDictionaryUnretained *source = (EidosDictionaryUnretained *)source_value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\t\n\t\tAppendKeysAndValuesFrom(source);\n\t}\n\t\n\tContentsChanged(\"appendKeysAndValuesFrom()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (void)clearKeysAndValues(void)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_clearKeysAndValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tRemoveAllKeys();\n\t\n\tContentsChanged(\"clearKeysAndValues()\");\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (integer)compactIndices([logical$ preserveOrder = F])\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_compactIndices(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *preserveOrder_value = p_arguments[0].get();\n\tbool preserveOrder = preserveOrder_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (!KeysAreIntegers())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_compactIndices): compactIndices() can only be called on a dictionary that uses integer keys.\" << EidosTerminate(nullptr);\n\t\n\tif (KeyCount() == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\tEidosDictionaryState_IntegerKeys *state_ptr = (EidosDictionaryState_IntegerKeys *)state_ptr_;\n\tEidosDictionaryHashTable_IntegerKeys &symbols = state_ptr->dictionary_symbols_;\n\tsize_t key_count = symbols.size();\n\tEidosValue_Int *integer_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve(key_count);\n\tstd::vector<EidosValue_SP> compacted_values;\n\t\n\tif (preserveOrder)\n\t{\n\t\t// to preserve the original order, we have to iterate through the \n\t\t// sorted keys; that makes the algorithm O(n log n)\n\t\tconst std::vector<int64_t> keys = SortedKeys_IntegerKeys();\n\t\t\n\t\tfor (int64_t key : keys)\n\t\t{\n\t\t\tauto kv_pair = symbols.find(key);\n\t\t\t\n\t\t\tif (kv_pair == symbols.end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_compactIndices): (internal error) key not found in symbols.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue *value = kv_pair->second.get();\n\t\t\t\n\t\t\tif (value->Count() > 0)\n\t\t\t{\n\t\t\t\tinteger_result->push_int_no_check(key);\n\t\t\t\tcompacted_values.push_back(kv_pair->second);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// if we don't need to preserve the order, we can do it in O(n)\n\t\tfor (auto &iter : symbols)\n\t\t{\n\t\t\tint64_t key = iter.first;\n\t\t\tEidosValue *value = iter.second.get();\n\t\t\t\n\t\t\tif (value->Count() > 0)\n\t\t\t{\n\t\t\t\tinteger_result->push_int_no_check(key);\n\t\t\t\tcompacted_values.push_back(iter.second);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// clear our contents and then copy the compacted values back in\n\tsymbols.clear();\n\t\n\tint64_t value_count = (int64_t)compacted_values.size();\n\t\n\tfor (int64_t index = 0; index < value_count; ++index)\n\t{\n\t\tsymbols[index] = std::move(compacted_values[index]);\n\t\t\n\t\t// KeyAddedToDictionary_IntegerKeys() is not needed; for us it is a no-op,\n\t\t// and DataFrame doesn't support integer keys\n\t}\n\t\n\tContentsChanged(\"compactIndices()\");\n\t\n\treturn EidosValue_SP(integer_result);\n}\n\n//\t*********************\t- (object<Dictionary>$)getRowValues(li index, [logical$ drop = F])\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_getRowValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue *index_value = p_arguments[0].get();\n\tEidosValue *drop_value = p_arguments[1].get();\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosDictionaryRetained *objectElement = new EidosDictionaryRetained();\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDictionaryRetained_Class));\n\t\n\t// With no columns, the indices don't matter, and the result is a new empty dictionary\n\tif (KeyCount() == 0)\n\t{\n\t\t// objectElement is now retained by result_SP, so we can release it\n\t\tobjectElement->Release();\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\t// Otherwise, we subset to get the result value for each key we contain\n\t// We go through the keys in sorted order, which probably doesn't matter since we're making a Dictionary, but it follows EidosDataFrame::ExecuteMethod_subsetRows()\n\tif (KeysAreStrings())\n\t{\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\tbool drop = drop_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (const std::string &key : keys)\n\t\t{\n\t\t\tauto kv_pair = symbols->find(key);\n\t\t\t\n\t\t\tif (kv_pair == symbols->end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_getRowValues): (internal error) key not found in symbols.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_SP subset = SubsetEidosValue(kv_pair->second.get(), index_value, nullptr, /* p_raise_range_errors */ false);\n\t\t\t\n\t\t\tif (!drop || subset->Count())\n\t\t\t\tobjectElement->SetKeyValue_StringKeys(kv_pair->first, subset);\n\t\t}\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\tconst std::vector<int64_t> keys = SortedKeys_IntegerKeys();\n\t\tbool drop = drop_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int64_t key : keys)\n\t\t{\n\t\t\tauto kv_pair = symbols->find(key);\n\t\t\t\n\t\t\tif (kv_pair == symbols->end())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_getRowValues): (internal error) key not found in symbols.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_SP subset = SubsetEidosValue(kv_pair->second.get(), index_value, nullptr, /* p_raise_range_errors */ false);\n\t\t\t\n\t\t\tif (!drop || subset->Count())\n\t\t\t\tobjectElement->SetKeyValue_IntegerKeys(kv_pair->first, subset);\n\t\t}\n\t}\n\t\n\tobjectElement->ContentsChanged(\"getRowValues()\");\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n//\t*********************\t- (*)getValue(is$ key)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_getValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *key_value = p_arguments[0].get();\n\t\n\t// see also EidosDictionaryUnretained::GetValueForKey()\n\tif (!state_ptr_)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tif (KeysAreStrings())\n\t{\n\t\tif (key_value->Type() != EidosValueType::kValueString)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_getValue): an integer key was supplied to getValue(), but the target dictionary uses string keys.\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst std::string &key = ((EidosValue_String *)key_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\tauto found_iter = symbols->find(key);\n\t\t\n\t\tif (found_iter == symbols->end())\n\t\t\treturn gStaticEidosValueNULL;\n\t\telse\n\t\t\treturn found_iter->second;\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\tif (key_value->Type() != EidosValueType::kValueInt)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_getValue): a string key was supplied to getValue(), but the target dictionary uses integer keys.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint64_t key = ((EidosValue_Int *)key_value)->IntAtIndex_NOCAST(0, nullptr);\n\t\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\t\n\t\tauto found_iter = symbols->find(key);\n\t\t\n\t\tif (found_iter == symbols->end())\n\t\t\treturn gStaticEidosValueNULL;\n\t\telse\n\t\t\treturn found_iter->second;\n\t}\n}\n\n//\t*********************\t- (logical$)identicalContents(object<Dictionary>$ x)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_identicalContents(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosObject *x_object = x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\tEidosDictionaryUnretained *x_dict = (EidosDictionaryUnretained *)x_object;\n\t\n\tif (!x_dict)\n\t\treturn gStaticEidosValue_LogicalF;\n\t\n\tif ((KeysAreStrings() && !x_dict->KeysAreStrings()) ||\n\t\t(KeysAreIntegers() && !x_dict->KeysAreIntegers()))\n\t\treturn gStaticEidosValue_LogicalF;\n\t\n\tint keycount = KeyCount();\n\tint x_keycount = x_dict->KeyCount();\n\t\n\tif (keycount != x_keycount)\n\t\treturn gStaticEidosValue_LogicalF;\n\t\n\tif (keycount == 0)\n\t\treturn gStaticEidosValue_LogicalT;\n\t\n\t// At this point we know that x is a dictionary, with the same (non-zero) number of keys as us\n\t// For DataFrame we now ensure the columns are in the same order; for Dictionary, keys are\n\t// in sorted order, so this just compares to check that the keys are equal.\n\tif (KeysAreStrings())\n\t{\n\t\tconst std::vector<std::string> x_keys = x_dict->SortedKeys_StringKeys();\n\t\tconst std::vector<std::string> keys = SortedKeys_StringKeys();\n\t\t\n\t\tif (x_keys != keys)\n\t\t\treturn gStaticEidosValue_LogicalF;\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\tconst std::vector<int64_t> x_keys = x_dict->SortedKeys_IntegerKeys();\n\t\tconst std::vector<int64_t> keys = SortedKeys_IntegerKeys();\n\t\t\n\t\tif (x_keys != keys)\n\t\t\treturn gStaticEidosValue_LogicalF;\n\t}\n\t\n\t// Now we know it has the same keys in the same order\n\tif (KeysAreStrings())\n\t{\n\t\tconst EidosDictionaryHashTable_StringKeys *x_symbols = x_dict->DictionarySymbols_StringKeys();\n\t\tconst EidosDictionaryHashTable_StringKeys *symbols = DictionarySymbols_StringKeys();\n\t\t\n\t\tfor (auto const &kv_pair : *symbols)\n\t\t{\n\t\t\tconst std::string &key = kv_pair.first;\n\t\t\tEidosValue *value = kv_pair.second.get();\n\t\t\t\n\t\t\tauto found_iter = x_symbols->find(key);\n\t\t\t\n\t\t\tif (found_iter == x_symbols->end())\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t\t\n\t\t\tEidosValue *found_value = found_iter->second.get();\n\t\t\t\n\t\t\tif (!IdenticalEidosValues(value, found_value))\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t}\n\t}\n\telse\t// KeysAreIntegers()\n\t{\n\t\tconst EidosDictionaryHashTable_IntegerKeys *x_symbols = x_dict->DictionarySymbols_IntegerKeys();\n\t\tconst EidosDictionaryHashTable_IntegerKeys *symbols = DictionarySymbols_IntegerKeys();\n\t\t\n\t\tfor (auto const &kv_pair : *symbols)\n\t\t{\n\t\t\tint64_t key = kv_pair.first;\n\t\t\tEidosValue *value = kv_pair.second.get();\n\t\t\t\n\t\t\tauto found_iter = x_symbols->find(key);\n\t\t\t\n\t\t\tif (found_iter == x_symbols->end())\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t\t\n\t\t\tEidosValue *found_value = found_iter->second.get();\n\t\t\t\n\t\t\tif (!IdenticalEidosValues(value, found_value))\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValue_LogicalT;\n}\n\n//\t*********************\t- (void)setValue(is$ key, * value)\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_Accelerated_setValue(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *key_value = p_arguments[0].get();\n\tconst EidosValue_SP &value = p_arguments[1];\n\t\n\t// This method used to not call SetKeyValue(), in order to set the same value across multiple\n\t// targets.  That made me nervous, and was hard to reconcile with DataFrame, so I removed it.\n\t\n\tif (key_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &key = ((EidosValue_String *)key_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t{\n\t\t\tEidosDictionaryUnretained *element = (EidosDictionaryUnretained *)(p_elements[element_index]);\n\t\t\t\n\t\t\telement->SetKeyValue_StringKeys(key, value);\n\t\t\telement->ContentsChanged(\"setValue()\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tint64_t key = ((EidosValue_Int *)key_value)->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t{\n\t\t\tEidosDictionaryUnretained *element = (EidosDictionaryUnretained *)(p_elements[element_index]);\n\t\t\t\n\t\t\telement->SetKeyValue_IntegerKeys(key, value);\n\t\t\telement->ContentsChanged(\"setValue()\");\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t- (string)serialize([string$ format = \"slim\"])\n//\nEidosValue_SP EidosDictionaryUnretained::ExecuteMethod_serialize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_interpreter)\n\tEidosValue_String *string_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &format_name = string_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (format_name == \"slim\")\n\t{\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(Serialization_SLiM()));\n\t}\n\telse if (format_name == \"pretty\")\n\t{\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(Serialization_Pretty(0)));\n\t}\n\telse if (format_name == \"json\")\n\t{\n\t\tnlohmann::json json_rep = JSONRepresentation();\n\t\tstd::string json_string = json_rep.dump();\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(json_string));\n\t}\n\telse if (format_name == \"csv\")\n\t{\n\t\treturn Serialization_CSV(\",\");\n\t}\n\telse if (format_name == \"tsv\")\n\t{\n\t\treturn Serialization_CSV(\"\\t\");\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained::ExecuteMethod_serialize): serialize() does not recognize the format '\" << format_name << \"'; it should be 'slim', 'pretty', 'json', 'csv', or 'tsv'.\" << EidosTerminate(nullptr);\n\t}\n}\n\n\n//\n//\tEidosDictionaryUnretained_Class\n//\n#pragma mark -\n#pragma mark EidosDictionaryUnretained_Class\n#pragma mark -\n\nEidosClass *gEidosDictionaryUnretained_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *EidosDictionaryUnretained_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDictionaryUnretained_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_allKeys,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskString)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *EidosDictionaryUnretained_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDictionaryUnretained_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_addKeysAndValuesFrom, kEidosValueMaskVOID))->AddObject_S(gEidosStr_source, gEidosDictionaryUnretained_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_appendKeysAndValuesFrom, kEidosValueMaskVOID))->AddObject(gEidosStr_source, gEidosDictionaryUnretained_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_clearKeysAndValues, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_compactIndices, kEidosValueMaskInt, gEidosDictionaryRetained_Class))->AddLogical_OS(\"preserveOrder\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_getRowValues, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddArg(kEidosValueMaskLogical | kEidosValueMaskInt, \"index\", nullptr)->AddLogical_OS(\"drop\", gStaticEidosValue_LogicalF));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_getValue, kEidosValueMaskAny))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, \"key\", nullptr));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_identicalContents, kEidosValueMaskLogical | kEidosValueMaskSingleton))->AddObject_S(\"x\", gEidosDictionaryUnretained_Class));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_serialize, kEidosValueMaskString))->AddString_OS(\"format\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"slim\"))));\n\t\tmethods->emplace_back(((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_setValue, kEidosValueMaskVOID))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, \"key\", nullptr)->AddAny(\"value\"))->DeclareAcceleratedImp(EidosDictionaryUnretained::ExecuteMethod_Accelerated_setValue));\n\t\t\n\t\tmethods->emplace_back(((EidosClassMethodSignature *)(new EidosClassMethodSignature(gEidosStr_setValuesVectorized, kEidosValueMaskVOID))->AddArg(kEidosValueMaskInt | kEidosValueMaskString | kEidosValueMaskSingleton, \"key\", nullptr)->AddAny(\"values\")));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nEidosValue_SP EidosDictionaryUnretained_Class::ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_setValuesVectorized:\treturn ExecuteMethod_setValuesVectorized(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\treturn EidosClass::ExecuteClassMethod(p_method_id, p_target, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t+ (void)setValuesVectorized(is$ key, * values)\n//\nEidosValue_SP EidosDictionaryUnretained_Class::ExecuteMethod_setValuesVectorized(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *key_value = p_arguments[0].get();\n\tconst EidosValue *values = p_arguments[1].get();\n\tint values_count = values->Count();\n\tEidosDictionaryUnretained * const *targets = (EidosDictionaryUnretained * const *)(p_target->ObjectData());\n\tint target_size = p_target->Count();\n\t\n\tif (target_size != values_count)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosDictionaryUnretained_Class::ExecuteMethod_setValuesVectorized): setValuesVectorized() requires that the size of the target vector equals the size of the values parameter, so that the 1:1 vectorized operation can be performed.\" << EidosTerminate();\n\t\n\tif (key_value->Type() == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &key = ((EidosValue_String *)key_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((values->Type() == EidosValueType::kValueObject) && !((EidosValue_Object *)values)->UsesRetainRelease())\n\t\t{\n\t\t\t// If we're setting object values that aren't under retain-release, calling ContentsChanged() is probably important\n\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t{\n\t\t\t\tEidosDictionaryUnretained *target = targets[target_index];\n\t\t\t\t\n\t\t\t\ttarget->SetKeyValue_StringKeys(key, values->GetValueAtIndex(target_index, nullptr));\n\t\t\t\ttarget->ContentsChanged(\"setValuesVectorized()\");\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, we skip ContentsChanged().  This is a small inaccuracy for speed.  If the existing value\n\t\t\t// in the dictionary is a non-RR object, then we fail to clear contains_non_retain_release_objects_,\n\t\t\t// which will cause an error downstream when we hit CheckLongTermBoundary(); we will think there is a\n\t\t\t// a non-RR object held across the long-term boundary when there isn't.  I doubt anyone will EVER hit\n\t\t\t// this; it requires that the user (a) set a non-RR object for a key, and then (b) set some other\n\t\t\t// kind of value into the SAME key, removing the non-RR object and making the dictionary safe.\n\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t{\n\t\t\t\tEidosDictionaryUnretained *target = targets[target_index];\n\t\t\t\t\n\t\t\t\ttarget->SetKeyValue_StringKeys(key, values->GetValueAtIndex(target_index, nullptr));\n\t\t\t\t//target->ContentsChanged(\"setValuesVectorized()\");\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tint64_t key = ((EidosValue_Int *)key_value)->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((values->Type() == EidosValueType::kValueObject) && !((EidosValue_Object *)values)->UsesRetainRelease())\n\t\t{\n\t\t\t// If we're setting object values that aren't under retain-release, calling ContentsChanged() is probably important\n\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t{\n\t\t\t\tEidosDictionaryUnretained *target = targets[target_index];\n\t\t\t\t\n\t\t\t\ttarget->SetKeyValue_IntegerKeys(key, values->GetValueAtIndex(target_index, nullptr));\n\t\t\t\ttarget->ContentsChanged(\"setValuesVectorized()\");\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, we skip ContentsChanged().  This is a small inaccuracy for speed.  If the existing value\n\t\t\t// in the dictionary is a non-RR object, then we fail to clear contains_non_retain_release_objects_,\n\t\t\t// which will cause an error downstream when we hit CheckLongTermBoundary(); we will think there is a\n\t\t\t// a non-RR object held across the long-term boundary when there isn't.  I doubt anyone will EVER hit\n\t\t\t// this; it requires that the user (a) set a non-RR object for a key, and then (b) set some other\n\t\t\t// kind of value into the SAME key, removing the non-RR object and making the dictionary safe.\n\t\t\tfor (int target_index = 0; target_index < target_size; ++target_index)\n\t\t\t{\n\t\t\t\tEidosDictionaryUnretained *target = targets[target_index];\n\t\t\t\t\n\t\t\t\ttarget->SetKeyValue_IntegerKeys(key, values->GetValueAtIndex(target_index, nullptr));\n\t\t\t\t//target->ContentsChanged(\"setValuesVectorized()\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n// EidosDictionaryRetained\n//\n#pragma mark -\n#pragma mark EidosDictionaryRetained\n#pragma mark -\n\n/*\nEidosDictionaryRetained::EidosDictionaryRetained(void)\n{\n//\tstd::cerr << \"EidosDictionaryRetained::EidosDictionaryRetained allocated \" << this << \" with refcount == 1\" << std::endl;\n//\tEidos_PrintStacktrace(stderr, 10);\n}\n\nEidosDictionaryRetained::~EidosDictionaryRetained(void)\n{\n//\tstd::cerr << \"EidosDictionaryRetained::~EidosDictionaryRetained deallocated \" << this << std::endl;\n//\tEidos_PrintStacktrace(stderr, 10);\n}\n*/\n\nvoid EidosDictionaryRetained::SelfDelete(void)\n{\n\t// called when our refcount reaches zero; can be overridden by subclasses to provide custom behavior\n\t// the default behavior assumes that this was allocated by new, and uses delete to free it\n\tdelete this;\n}\n\nvoid EidosDictionaryRetained::ConstructFromEidos(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter, const std::string &p_caller_name, const std::string &p_constructor_name)\n{\n\tif (p_arguments.size() == 0)\n\t{\n\t\t// Create a new empty Dictionary\n\t}\n\telse if (p_arguments.size() == 1)\n\t{\n\t\t// one argument; multiple overloaded meanings\n\t\tEidosValue *source_value = p_arguments[0].get();\n\t\tint source_count = source_value->Count();\n\t\t\n\t\tif (source_value->Type() == EidosValueType::kValueString)\n\t\t{\n\t\t\t// Construct from a JSON string; beginning in SLiM 4.2 this is allowed to be a string vector,\n\t\t\t// as returned by readFile().  We just paste the lines back together with newlines.  Note that\n\t\t\t// if the user tries to put a newline inside a string value, that is actually not legal JSON\n\t\t\t// (see https://stackoverflow.com/a/16690186/2752221), and nlohmann will error below.\n\t\t\tstd::string json_string;\n\t\t\t\n\t\t\tfor (int source_index = 0; source_index < source_count; ++source_index)\n\t\t\t{\n\t\t\t\tif (source_index > 0)\n\t\t\t\t\tjson_string.append(\"\\n\");\n\t\t\t\t\n\t\t\t\tjson_string.append(source_value->StringAtIndex_NOCAST(source_index, nullptr));\n\t\t\t}\n\t\t\t\n\t\t\tnlohmann::json json_rep;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tjson_rep = nlohmann::json::parse(json_string);\n\t\t\t} catch (...) {\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): the string$ argument passed to \" << p_constructor_name << \"() does not parse as a valid JSON string.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tAddJSONFrom(json_rep);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Construct from a singleton Dictionary or Dictionary subclass\n\t\t\tif (source_count != 1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): \" << p_constructor_name << \"(x) requires that x be a singleton Dictionary (or a singleton subclass of Dictionary), or a string vector.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosDictionaryUnretained *source = (source_value->Type() != EidosValueType::kValueObject) ? nullptr : dynamic_cast<EidosDictionaryUnretained *>(source_value->ObjectElementAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\t\tif (!source)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): \" << p_constructor_name << \"(x) requires that x be a singleton Dictionary (or a singleton subclass of Dictionary), or a string vector.\" << EidosTerminate(nullptr);\n\t\t\n\t\t\tAddKeysAndValuesFrom(source);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Set key-value pairs on the new Dictionary\n\t\tint arg_count = (int)p_arguments.size();\n\t\t\n\t\tif (arg_count % 2 != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): \" << p_constructor_name << \"(...) requires an even number of arguments (comprising key-value pairs).\" << EidosTerminate(nullptr);\n\t\t\n\t\tint kv_count = arg_count / 2;\n\t\t\n\t\tfor (int kv_index = 0; kv_index < kv_count; ++kv_index)\n\t\t{\n\t\t\tEidosValue *key = p_arguments[(size_t)kv_index * 2].get();\n\t\t\tconst EidosValue_SP &value = p_arguments[(size_t)kv_index * 2 + 1];\n\t\t\t\n\t\t\tif (key->Count() != 1)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): \" << p_constructor_name << \" requires that keys be singletons.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (key->Type() == EidosValueType::kValueString)\n\t\t\t{\n\t\t\t\tEidosValue_String *key_string_value = (EidosValue_String *)key;\n\t\t\t\t\n\t\t\t\tSetKeyValue_StringKeys(key_string_value->StringRefAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\telse if (key->Type() == EidosValueType::kValueInt)\n\t\t\t{\n\t\t\t\tEidosValue_Int *key_integer_value = (EidosValue_Int *)key;\n\t\t\t\t\n\t\t\t\tSetKeyValue_IntegerKeys(key_integer_value->IntAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (\" << p_caller_name << \"): \" << p_constructor_name << \" requires that keys be of type string or integer.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// The caller must call ContentsChanged()\n}\n\n//\t(object<Dictionary>$)Dictionary(...)\nstatic EidosValue_SP Eidos_Instantiate_EidosDictionaryRetained(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosDictionaryRetained *objectElement = new EidosDictionaryRetained();\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDictionaryRetained_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\t// note that we instantiate EidosDictionaryRetained here, even though Dictionary is EidosDictionaryUnretained\n\t// user-created dictionaries are under retain/release, but the Dictionary class is EidosDictionaryUnretained\n\tobjectElement->ConstructFromEidos(p_arguments, p_interpreter, \"Eidos_Instantiate_EidosDictionaryRetained\", \"Dictionary\");\n\tobjectElement->ContentsChanged(\"Dictionary()\");\n\t\n\treturn result_SP;\n}\n\n\n//\n// EidosDictionaryRetained Eidos support\n//\n#pragma mark -\n#pragma mark EidosDictionaryRetained Eidos support\n#pragma mark -\n\nconst EidosClass *EidosDictionaryRetained::Class(void) const\n{\n\treturn gEidosDictionaryRetained_Class;\n}\n\n\n//\n//\tEidosDictionaryRetained_Class\n//\n#pragma mark -\n#pragma mark EidosDictionaryRetained_Class\n#pragma mark -\n\nEidosClass *gEidosDictionaryRetained_Class = nullptr;\n\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosDictionaryRetained_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosDictionaryRetained_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_Dictionary, Eidos_Instantiate_EidosDictionaryRetained, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class))->AddEllipsis());\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\nbool EidosDictionaryRetained_Class::UsesRetainRelease(void) const\n{\n\treturn true;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_Dictionary.h",
    "content": "//\n//  eidos_class_Dictionary.h\n//  Eidos\n//\n//  Created by Ben Haller on 10/12/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef __Eidos__eidos_class_dictionary__\n#define __Eidos__eidos_class_dictionary__\n\n\n#include \"eidos_globals.h\"\n#include \"eidos_class_Object.h\"\n#include \"json_fwd.hpp\"\n\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\ntypedef robin_hood::unordered_flat_map<std::string, EidosValue_SP> EidosDictionaryHashTable_StringKeys;\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_map>\ntypedef std::unordered_map<std::string, EidosValue_SP> EidosDictionaryHashTable_StringKeys;\n#endif\n\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\ntypedef robin_hood::unordered_flat_map<int64_t, EidosValue_SP> EidosDictionaryHashTable_IntegerKeys;\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_map>\ntypedef std::unordered_map<int64_t, EidosValue_SP> EidosDictionaryHashTable_IntegerKeys;\n#endif\n\n\n#pragma mark -\n#pragma mark EidosDictionaryUnretained\n#pragma mark -\n\nextern EidosClass *gEidosDictionaryUnretained_Class;\n\n// These are helpers for EidosDictionaryUnretained.  The purpose is to put all of its ivars into an allocated block,\n// so that the overhead of inheriting from the class itself is only one pointer, unless the Dictionary functionality is\n// actually used (which it usually isn't, since many SLiM objects inherit from Dictionary but rarely use it).\n//\n// EidosDictionary now supports keys that are either strings (the original semantics) or integers (new in SLiM 4.1).\n// A given dictionary must use one or the other; the key types cannot be mixed within one dictionary, for API and\n// implementation simplicity.  The keys_are_integers_ flag controls which type of key is used; this is set when this\n// struct is created.  Note that code in Eidos_WarmUp() verifies that this flag is at the same memory location in both\n// structs, so that we can access that flag without knowing which struct type we are using.\n//\n// EidosDictionary also (as of SLiM 4.1) can contain objects of any class.  It used to only allow objects that are\n// under the \"retain-release\" memory management system, in order to guarantee that no objects were kept long-term\n// unless under retain-release.  That guarantee is now satisfied, instead, by EidosDictionaryUnretained keeping\n// track of whether it contains non-retain-release objects, with a flag, and a global counter keeps track of how\n// many such dictionaries are extant.  That counter can be checked to throw an error if a non-retain-release object\n// is kept across a \"long-term boundary\" (a point in the code when non-retain-release objects are freed and references\n// to them would become stale).  The contains_non_retain_release_objects_ flag tracks this state.\n//\n// The dictionary_symbols_ hash table contains the values we are tracking.  Note that DictionarySymbols() should be\n// used by all code that does not need to modify the dictionary.\n//\n// The dictionary_symbols_ hash table has no order for the keys.  We want to define an ordering; for Dictionary the\n// ordering is sorted and computed on demand, for DataFrame it is user-defined and maintained by that class.  To allow\n// DataFrame to maintain the correct ordering, call KeyAddedToDictionary_X() to register a new key when it is added,\n// KeyRemovedFromDictionary_X() or AllKeysRemoved() when a key is removed, and ContentsChanged() at the end of a\n// change operation (once, for either a single change or an aggregated set of changes).  The SortedKeys_X() accessors\n// provide the correct sorted order for both classes, but perform a sort for Dictionary, so should be used minimally.\nstruct EidosDictionaryState_StringKeys\n{\n\tuint8_t keys_are_integers_;\t\t// 0 for EidosDictionaryState_StringKeys, 1 for EidosDictionaryState_IntegerKeys\n\tuint8_t contains_non_retain_release_objects_;\t// 0 if none are contained, 1 if any are contained\n\tEidosDictionaryHashTable_StringKeys dictionary_symbols_;\n};\n\nstruct EidosDictionaryState_IntegerKeys\n{\n\tuint8_t keys_are_integers_;\t\t// 0 for EidosDictionaryState_StringKeys, 1 for EidosDictionaryState_IntegerKeys\n\tuint8_t contains_non_retain_release_objects_;\t// 0 if none are contained, 1 if any are contained\n\tEidosDictionaryHashTable_IntegerKeys dictionary_symbols_;\n};\n\n// This is a global counter of how many dictionaries exist that have their contains_non_retain_release_objects_ set.\n// It can be checked at \"long-term boundaries\" to ensure that only retain-released objects are kept long term.\nextern int64_t gEidos_DictionaryNonRetainReleaseReferenceCounter;\n\n// This class is known in Eidos as \"Dictionary\".  The subclass EidosDictionaryRetained is the class that is created\n// by the Dictionary() constructor, however, and that subclass masquerades as Dictionary in various ways, to try\n// to hide the dichotomy here, since the user should be able to treat all dictionaries the same; which classes are\n// under retain/release is an internal implementation detail, to the extent possible.\nclass EidosDictionaryUnretained : public EidosObject\n{\nprivate:\n\ttypedef EidosObject super;\n\nprotected:\n\tvoid *state_ptr_ = nullptr;\t// pointer to EidosDictionaryState_StringKeys or EidosDictionaryState_IntegerKeys\n\t\n\t// Raise exceptions saying \"keys are expected to be string, but are not string\" etc.\n\tvirtual void Raise_UsesStringKeys(void) const __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\tvirtual void Raise_UsesIntegerKeys(void) const __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\t\n\t// Assert that our keys are of a given type; if not, an exception is raised; if it is undecided, neither method raises\n\tinline void AssertKeysAreStrings(void) const { if (!KeysAreStrings()) Raise_UsesIntegerKeys(); }\n\tinline void AssertKeysAreIntegers(void) const { if (!KeysAreIntegers()) Raise_UsesStringKeys(); }\n\t\npublic:\n\tEidosDictionaryUnretained(const EidosDictionaryUnretained &p_original) = delete;\t\t\t\t// no copy-construct\n\tEidosDictionaryUnretained& operator= (const EidosDictionaryUnretained &p_original) = delete;\t// no assignment\n\tinline EidosDictionaryUnretained(void) { }\n\t\n\tvirtual ~EidosDictionaryUnretained(void) override;\n\t\n\t// Test which type our keys are; if that is undecided, both methods return true\n\tvirtual bool KeysAreStrings(void) const { return (!state_ptr_ || !((EidosDictionaryState_StringKeys *)state_ptr_)->keys_are_integers_); }\n\tvirtual bool KeysAreIntegers(void) const { return (!state_ptr_ || ((EidosDictionaryState_IntegerKeys *)state_ptr_)->keys_are_integers_); }\n\t\n\t// Whenever possible, access should go through these accessors to control modification of our symbols\n\tconst EidosDictionaryHashTable_StringKeys *DictionarySymbols_StringKeys(void) const { AssertKeysAreStrings(); return state_ptr_ ? &(((EidosDictionaryState_StringKeys *)state_ptr_)->dictionary_symbols_) : nullptr; }\n\tconst EidosDictionaryHashTable_IntegerKeys *DictionarySymbols_IntegerKeys(void) const { AssertKeysAreIntegers(); return state_ptr_ ? &(((EidosDictionaryState_IntegerKeys *)state_ptr_)->dictionary_symbols_) : nullptr; }\n\t\n\t// Provides the keys in the user-visible order: sorted for Dictionary, user-defined for DataFrame\n\tvirtual std::vector<std::string> SortedKeys_StringKeys(void) const;\n\tvirtual std::vector<int64_t> SortedKeys_IntegerKeys(void) const;\n\t\n\t// These methods must always be called when a key is added or removed, to allow subclasses like DataFrame to do additional work\n\t// Subclassers should call super; the base class may have essential behavior\n\tvirtual void KeyAddedToDictionary_StringKeys(const std::string &p_key);\n\tvirtual void KeyAddedToDictionary_IntegerKeys(int64_t p_key);\n\tvirtual void KeyRemovedFromDictionary_StringKeys(const std::string &p_key);\n\tvirtual void KeyRemovedFromDictionary_IntegerKeys(int64_t p_key);\n\tvirtual void AllKeysRemoved(void);\n\t\n\t// This method must be called at the end of any code that changes the contents of the dictionary; it checks several invariants\n\t// Low-level accessors (RemoveAllKeys(), SetKeyValue(), etc.) should *not* call this; the top-level code controlling the change should\n\t// Subclassers should call super; the base class may have essential behavior\n\tvirtual void ContentsChanged(const std::string &p_operation_name);\n\t\n\tint KeyCount(void) const\n\t{\n\t\tif (!state_ptr_)\n\t\t\treturn 0;\n\t\t\n\t\tif (KeysAreStrings())\n\t\t{\n\t\t\tconst EidosDictionaryHashTable_StringKeys &string_keys = ((EidosDictionaryState_StringKeys *)state_ptr_)->dictionary_symbols_;\n\t\t\t\n\t\t\treturn (int)string_keys.size();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst EidosDictionaryHashTable_IntegerKeys &integer_keys = ((EidosDictionaryState_IntegerKeys *)state_ptr_)->dictionary_symbols_;\n\t\t\t\n\t\t\treturn (int)integer_keys.size();\n\t\t}\n\t}\n\t\n\tvirtual EidosValue_SP AllKeys(void) const;\n\t\n\tstd::string Serialization_SLiM(void) const;\n\tstd::string Serialization_Pretty(int indent_level) const;\n\tEidosValue_SP Serialization_CSV(const std::string &p_delimiter) const;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\t// Non-const methods: callers of these methods must ensure that ContentsChanged() is called!\n\tinline __attribute__((always_inline)) void RemoveAllKeys(void)\n\t{\n\t\tif (state_ptr_)\n\t\t{\n\t\t\t// We keep state_ptr_ allocated to try to avoid allocation thrash\n\t\t\tif (KeysAreStrings())\n\t\t\t{\n\t\t\t\tEidosDictionaryState_StringKeys *state_ptr = ((EidosDictionaryState_StringKeys *)state_ptr_);\n\t\t\t\t\n\t\t\t\tstate_ptr->dictionary_symbols_.clear();\n\t\t\t\tAllKeysRemoved();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosDictionaryState_IntegerKeys *state_ptr = ((EidosDictionaryState_IntegerKeys *)state_ptr_);\n\t\t\t\t\n\t\t\t\tstate_ptr->dictionary_symbols_.clear();\n\t\t\t\tAllKeysRemoved();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid SetKeyValue_StringKeys(const std::string &key, EidosValue_SP value);\n\tvoid SetKeyValue_IntegerKeys(int64_t key, EidosValue_SP value);\n\tEidosValue_SP GetValueForKey_StringKeys(const std::string &key);\n\tEidosValue_SP GetValueForKey_IntegerKeys(int64_t key);\n\t\n\tvoid AddKeysAndValuesFrom(EidosDictionaryUnretained *p_source, bool p_allow_replace = true);\n\tvoid AppendKeysAndValuesFrom(EidosDictionaryUnretained *p_source, bool p_require_column_match = false);\n\tvoid AddJSONFrom(nlohmann::json &json);\n\t\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_addKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_appendKeysAndValuesFrom(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_clearKeysAndValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_compactIndices(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_getRowValues(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_getValue(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_identicalContents(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_serialize(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_setValue(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n};\n\nclass EidosDictionaryUnretained_Class : public EidosClass\n{\nprivate:\n\ttypedef EidosClass super;\n\npublic:\n\tEidosDictionaryUnretained_Class(const EidosDictionaryUnretained_Class &p_original) = delete;\t// no copy-construct\n\tEidosDictionaryUnretained_Class& operator=(const EidosDictionaryUnretained_Class&) = delete;\t// no copying\n\t\n\t// This constructor is used by ourselves and subclasses\n\tinline EidosDictionaryUnretained_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\t// This constructor is used only by EidosDictionaryRetained_Class, to set its display name to \"Dictionary\"\n\tinline EidosDictionaryUnretained_Class(const std::string &p_class_name, const std::string &p_display_name, EidosClass *p_superclass) :\n\t\tsuper(p_class_name, p_display_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\t\n\tvirtual EidosValue_SP ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const override;\n\tEidosValue_SP ExecuteMethod_setValuesVectorized(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n};\n\n\n#pragma mark -\n#pragma mark EidosDictionaryRetained\n#pragma mark -\n\nextern EidosClass *gEidosDictionaryRetained_Class;\n\n// A base class for EidosObject subclasses that are under retain/release.\n\n// There is a complication in Eidos here.  When you make a new object with the Dictionary() class, you\n// get one of these -- an EidosDictionaryRetained.  However, in other respects the class name \"Dictionary\"\n// in Eidos refers to the superclass, EidosDictionaryUnretained, which actually implements the Dictionary\n// APIs, and which many SLiM classes inherit from because they want Dictionary-subclass functionality but\n// do not want to be under retain/release.  Some SLiM classes that do want to be under retain/release\n// inherit from EidosDictionaryRetained, but still are shown as having a superclass of \"Dictionary\".  So,\n// the Dictionary() constructor actually provides a subclass, and the two classes are conflated in the\n// public Eidos APIs and docs.\n\nclass EidosDictionaryRetained : public EidosDictionaryUnretained\n{\nprivate:\n\ttypedef EidosDictionaryUnretained super;\n\nprivate:\n\tuint32_t refcount_ = 1;\t\t\t\t// start life with a refcount of 1; the allocator does not need to call Retain()\n\t\npublic:\n\tEidosDictionaryRetained(const EidosDictionaryRetained &p_original) = delete;\t\t// no copy-construct\n\tEidosDictionaryRetained& operator=(const EidosDictionaryRetained&) = delete;\t\t// no copying\n\tinline EidosDictionaryRetained(void) { }\n\tinline virtual ~EidosDictionaryRetained(void) override { }\n\t\n\tinline __attribute__((always_inline)) void Retain(void)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosDictionaryRetained::Retain(): EidosDictionaryRetained refcount_ change\");\n\t\trefcount_++;\n\t}\n\n\tinline __attribute__((always_inline)) void Release(void)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosDictionaryRetained::Retain(): EidosDictionaryRetained refcount_ change\");\n\t\tif ((--refcount_) == 0)\n\t\t\tSelfDelete();\n\t}\n\t\n\tinline __attribute__((always_inline)) void Release_PARALLEL(void)\n\t{\n\t\t// This version of Release() can be used in parallel code, but must be protected by a lock,\n\t\t// a critical region, etc., or used in a context where it is known that a race does not occur.\n\t\tif ((--refcount_) == 0)\n\t\t\tSelfDelete();\n\t}\n\t\n\tvirtual void SelfDelete(void);\n\t\n\t// construct from Eidos arguments; shared with DataFrame; the caller must call ContentsChanged()\n\tvoid ConstructFromEidos(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter, const std::string &p_caller_name, const std::string &p_constructor_name);\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n};\n\nclass EidosDictionaryRetained_Class : public EidosDictionaryUnretained_Class\n{\nprivate:\n\ttypedef EidosDictionaryUnretained_Class super;\n\npublic:\n\tEidosDictionaryRetained_Class(const EidosDictionaryRetained_Class &p_original) = delete;\t// no copy-construct\n\tEidosDictionaryRetained_Class& operator=(const EidosDictionaryRetained_Class&) = delete;\t// no copying\n\t\n\t// This constructor is used by subclasses of EidosDictionaryRetained_Class\n\tinline EidosDictionaryRetained_Class(const std::string &p_class_name, EidosClass *p_superclass) :\n\t\tsuper(p_class_name, p_superclass) { }\n\t\n\t// This constructor is only for us, and takes a display name in addition to the usual parameters\n\tinline EidosDictionaryRetained_Class(const std::string &p_class_name, const std::string &p_display_name, EidosClass *p_superclass) :\n\t\tsuper(p_class_name, p_display_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n\t\n\tvirtual bool UsesRetainRelease(void) const override;\n};\n\n\n#endif /* __Eidos__eidos_class_dictionary__ */\n"
  },
  {
    "path": "eidos/eidos_class_Image.cpp",
    "content": "//\n//  eidos_class_Image.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 10/8/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_class_Image.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_globals.h\"\n\n#include <stdio.h>\n#include <sys/types.h>\n#include <dirent.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <algorithm>\n#include <string>\n#include <vector>\n\n#include \"lodepng.h\"\n\n\n//\n//\tEidosImage\n//\n#pragma mark -\n#pragma mark EidosImage\n#pragma mark -\n\nEidosImage::EidosImage(const std::string &p_file_path)\n{\n\tif (!Eidos_string_hasSuffix(p_file_path, \".png\") && !Eidos_string_hasSuffix(p_file_path, \".PNG\"))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::EidosImage): only PNG files are supported; a .png or .PNG filename extension must be present\" << EidosTerminate(nullptr);\n\t\n\tfile_path_ = p_file_path;\t// remember the path we were given, in case the user wants it back\n\t\n\tstd::string resolved_path = Eidos_ResolvedPath(p_file_path);\n\tconst char *file_path = resolved_path.c_str();\n\tstd::vector<unsigned char> png_data;\n\tunsigned width, height;\n\tunsigned error;\n\t\n\terror = lodepng::load_file(png_data, file_path);\n\t\n\tif (error)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::EidosImage): lodepng::load_file error \" << error << \" : \" << lodepng_error_text(error) << EidosTerminate(nullptr);\n\t\n\tis_grayscale_ = true;\n\terror = lodepng::decode(pixels_, width, height, png_data, LodePNGColorType::LCT_GREY, 8);\n\t\n\tif (error)\n\t{\n\t\tif (error != 62)\t// \"conversion from color to grayscale not supported\"\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::EidosImage): lodepng::decode error \" << error << \" : \" << lodepng_error_text(error) << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// Apparently the image is not grayscale; let's try RGB (no alpha!)\n\t\tpixels_.clear();\n\t\tis_grayscale_ = false;\n\t\terror = lodepng::decode(pixels_, width, height, png_data, LodePNGColorType::LCT_RGB, 8);\n\t\t\n\t\tif (error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::EidosImage): lodepng::decode error \" << error << \" : \" << lodepng_error_text(error) << EidosTerminate(nullptr);\n\t}\n\t\n\t// We reach this point if we've had a successful load, either grayscale or RGB\n\twidth_ = width;\n\theight_ = height;\n}\n\nEidosImage::EidosImage(int64_t p_width, int64_t p_height, bool p_grayscale) : width_(p_width), height_(p_height), is_grayscale_(p_grayscale)\n{\n\tif ((width_ <= 0) || (width_ > 100000) || (height_ <= 0) || (height_ > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::EidosImage): (internal error) image width and height must be in [1, 100000].\" << EidosTerminate();\n\t\n\t// immediately allocate our pixel buffer at the appropriate size\n\tpixels_.resize(width_ * height_ * (is_grayscale_ ? 1 : 3));\n}\n\nEidosImage::~EidosImage(void)\n{\n#if defined(SLIMGUI)\n\tif (image_)\n\t{\n\t\tif (image_deleter_)\n\t\t\timage_deleter_(image_);\n\t\telse\n\t\t\tstd::cout << \"Missing Image image_deleter_; leaking memory\" << std::endl;\n\t\t\n\t\timage_ = nullptr;\n\t\timage_deleter_ = nullptr;\n\t}\n#endif\n}\n\nconst EidosClass *EidosImage::Class(void) const\n{\n\treturn gEidosImage_Class;\n}\n\nvoid EidosImage::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nvoid EidosImage::GetChannelMetrics(Channel p_channel, int64_t &p_pixel_stride, int64_t &p_pixel_suboffset)\n{\n\tswitch (p_channel)\n\t{\n\t\tcase Channel::kRedChannel:\t\tp_pixel_stride = 3; p_pixel_suboffset = 0; break;\n\t\tcase Channel::kGreenChannel:\tp_pixel_stride = 3; p_pixel_suboffset = 1; break;\n\t\tcase Channel::kBlueChannel:\t\tp_pixel_stride = 3; p_pixel_suboffset = 2; break;\n\t\tcase Channel::kGrayChannel:\t\tp_pixel_stride = 1; p_pixel_suboffset = 0; break;\n\t}\n}\n\nEidosValue_SP EidosImage::ValueForIntegerChannel(EidosValue_SP &p_channel_cache, Channel p_channel)\n{\n\tif (!is_grayscale_ && (p_channel == kGrayChannel))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::ValueForIntegerChannel): grayscale channel requested from a non-grayscale image\" << EidosTerminate(nullptr);\n\tif (is_grayscale_ && (p_channel != kGrayChannel))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::ValueForIntegerChannel): RGB channel requested from a grayscale image\" << EidosTerminate(nullptr);\n\t\n\tif (p_channel_cache)\n\t\treturn p_channel_cache;\n\t\n\tint64_t pixel_stride = 0, pixel_suboffset = 0;\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(height_ * width_);\n\tp_channel_cache = EidosValue_SP(int_result);\n\t\n\tGetChannelMetrics(p_channel, pixel_stride, pixel_suboffset);\n\t\n\t// translate the data from by-row to by-column, to match the in-memory format of matrices in Eidos\n\tfor (int64_t y = 0; y < height_; ++y)\n\t\tfor (int64_t x = 0; x < width_; ++x)\n\t\t\tint_result->set_int_no_check(pixels_[(x + y * width_) * pixel_stride + pixel_suboffset], x * height_ + y);\n\t\n\tconst int64_t dim_buf[2] = {height_, width_};\n\t\n\tint_result->SetDimensions(2, dim_buf);\n\t\n\treturn p_channel_cache;\n}\n\nEidosValue_SP EidosImage::ValueForFloatChannel(EidosValue_SP &p_channel_cache, Channel p_channel)\n{\n\tif (!is_grayscale_ && (p_channel == kGrayChannel))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::ValueForFloatChannel): grayscale channel requested from a non-grayscale image\" << EidosTerminate(nullptr);\n\tif (is_grayscale_ && (p_channel != kGrayChannel))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::ValueForFloatChannel): RGB channel requested from a grayscale image\" << EidosTerminate(nullptr);\n\t\n\tif (p_channel_cache)\n\t\treturn p_channel_cache;\n\t\n\tint64_t pixel_stride = 0, pixel_suboffset = 0;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(height_ * width_);\n\tp_channel_cache = EidosValue_SP(float_result);\n\t\n\tGetChannelMetrics(p_channel, pixel_stride, pixel_suboffset);\n\t\n\t// translate the data from by-row to by-column, to match the in-memory format of matrices in Eidos\n\tfor (int64_t y = 0; y < height_; ++y)\n\t\tfor (int64_t x = 0; x < width_; ++x)\n\t\t\tfloat_result->set_float_no_check(pixels_[(x + y * width_) * pixel_stride + pixel_suboffset] / 255.0, x * height_ + y);\n\t\n\tconst int64_t dim_buf[2] = {height_, width_};\n\t\n\tfloat_result->SetDimensions(2, dim_buf);\n\t\n\treturn p_channel_cache;\n}\n\nEidosValue_SP EidosImage::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_property_id)\n\t{\n\t\t\t// constants\n\t\tcase gEidosID_width:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(width_));\n\t\tcase gEidosID_height:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(height_));\n\t\tcase gEidosID_bitsPerChannel:\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(8));\t// only 8 is supported for now, but this is for future expansion\n\t\tcase gEidosID_isGrayscale:\n\t\t\treturn (is_grayscale_ ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\tcase gEidosID_integerR:\n\t\t\treturn ValueForIntegerChannel(int_red_values_, EidosImage::kRedChannel);\n\t\tcase gEidosID_integerG:\n\t\t\treturn ValueForIntegerChannel(int_green_values_, EidosImage::kGreenChannel);\n\t\tcase gEidosID_integerB:\n\t\t\treturn ValueForIntegerChannel(int_blue_values_, EidosImage::kBlueChannel);\n\t\tcase gEidosID_integerK:\n\t\t\treturn ValueForIntegerChannel(int_gray_values_, EidosImage::kGrayChannel);\n\t\tcase gEidosID_floatR:\n\t\t\treturn ValueForFloatChannel(float_red_values_, EidosImage::kRedChannel);\n\t\tcase gEidosID_floatG:\n\t\t\treturn ValueForFloatChannel(float_green_values_, EidosImage::kGreenChannel);\n\t\tcase gEidosID_floatB:\n\t\t\treturn ValueForFloatChannel(float_blue_values_, EidosImage::kBlueChannel);\n\t\tcase gEidosID_floatK:\n\t\t\treturn ValueForFloatChannel(float_gray_values_, EidosImage::kGrayChannel);\n\t\t\t\n\t\t\t// all others, including gID_none\n\t\tdefault:\n\t\t\treturn super::GetProperty(p_property_id);\n\t}\n}\n\nEidosValue_SP EidosImage::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_write:\t\t\t\t\treturn ExecuteMethod_write(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\n//\t*********************\t– (void)write(string$ filePath)\n//\nEidosValue_SP EidosImage::ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue *filePath_value = p_arguments[0].get();\n\t\n\tstd::string outfile_path = Eidos_ResolvedPath(filePath_value->StringAtIndex_NOCAST(0, nullptr));\n\t\n\tunsigned error;\n\t\n\tif (is_grayscale_)\n\t\terror = lodepng::encode(outfile_path, pixels_, (unsigned)width_, (unsigned)height_, LodePNGColorType::LCT_GREY, 8);\t// K channel, 8 bits per channel\n\telse\n\t\terror = lodepng::encode(outfile_path, pixels_, (unsigned)width_, (unsigned)height_, LodePNGColorType::LCT_RGB, 8);\t// RGB channels, 8 bits per channel\n\t\n\tif (error)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosImage::ExecuteMethod_write): write() could not write to \" << outfile_path << \" (encoder error \" << error << \": \" << lodepng_error_text(error) << \").\" << EidosTerminate();\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n\n//\n//\tObject instantiation\n//\n#pragma mark -\n#pragma mark Object instantiation\n#pragma mark -\n\n//\t(object<Image>$)Image(...)\nstatic EidosValue_SP Eidos_Instantiate_EidosImage(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\tEidosImage *objectElement = nullptr;\n\t\n\tif ((p_arguments.size() == 1) && (p_arguments[0]->Type() == EidosValueType::kValueString) && (p_arguments[0]->Count() == 1))\n\t{\n\t\tEidosValue_String *filePath_value = (EidosValue_String *)p_arguments[0].get();\n\t\tobjectElement = new EidosImage(filePath_value->StringRefAtIndex_NOCAST(0, nullptr));\n\t}\n\telse if ((p_arguments.size() == 1) &&\n\t\t\t ((p_arguments[0]->Type() == EidosValueType::kValueInt) || (p_arguments[0]->Type() == EidosValueType::kValueFloat)) &&\n\t\t\t (p_arguments[0]->Count() >= 1))\n\t{\n\t\t// test: x = matrix(c(255, 255, 255, 0, 0, rep(0, 10)), nrow=3, ncol=5, byrow=T); y = Image(x); y.write(\"~/Desktop/test.png\");\n\t\t// test: x = matrix(c(1.0, 1, 1, 0, 0, rep(0, 10)), nrow=3, ncol=5, byrow=T); y = Image(x); y.write(\"~/Desktop/test.png\");\n\t\tEidosValue *numeric_value = p_arguments[0].get();\n\t\t\n\t\tif (numeric_value->DimensionCount() != 2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_Instantiate_EidosImage): Image(), when passed a numeric vector, requires that vector to be a matrix.\" << EidosTerminate();\n\t\t\n\t\tint64_t height = numeric_value->Dimensions()[0];\t// height in pixels == number of rows\n\t\tint64_t width = numeric_value->Dimensions()[1];\t\t// width in pixels == number of columns\n\t\t\n\t\tif (numeric_value->Type() == EidosValueType::kValueInt)\n\t\t{\n\t\t\tobjectElement = new EidosImage(width, height, true);\n\t\t\t\n\t\t\tunsigned char *image_data = objectElement->Data();\n\t\t\tEidosValue_Int *int_values = (EidosValue_Int *)p_arguments[0].get();\n\t\t\tconst int64_t *int_data = int_values->data();\n\t\t\t\n\t\t\t// translate the data from by-column to by-row, to match the in-memory format of images\n\t\t\tfor (int64_t y = 0; y < height; ++y)\n\t\t\t{\n\t\t\t\tfor (int64_t x = 0; x < width; ++x)\n\t\t\t\t{\n\t\t\t\t\tint64_t int_value = *(int_data + y + x * height);\n\t\t\t\t\t\n\t\t\t\t\tif ((int_value < 0) || (int_value > 255))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_Instantiate_EidosImage): Image(), when passed an integer vector, requires values to be in [0, 255].\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\t*(image_data + x + y * width) = (unsigned char)int_value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (numeric_value->Type() == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tobjectElement = new EidosImage(width, height, true);\n\t\t\t\n\t\t\tunsigned char *image_data = objectElement->Data();\n\t\t\tEidosValue_Float *float_values = (EidosValue_Float *)p_arguments[0].get();\n\t\t\tconst double *float_data = float_values->data();\n\t\t\t\n\t\t\t// translate the data from by-column to by-row, to match the in-memory format of images\n\t\t\tfor (int64_t y = 0; y < height; ++y)\n\t\t\t{\n\t\t\t\tfor (int64_t x = 0; x < width; ++x)\n\t\t\t\t{\n\t\t\t\t\tdouble float_value = *(float_data + y + x * height);\n\t\t\t\t\t\n\t\t\t\t\tif ((float_value < 0.0) || (float_value > 1.0))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_Instantiate_EidosImage): Image(), when passed a float vector, requires values to be in [0.0, 1.0].\" << EidosTerminate();\n\t\t\t\t\t\n\t\t\t\t\tint int_value = (int)round(float_value * 255.0);\n\t\t\t\t\t*(image_data + x + y * width) = (unsigned char)int_value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_Instantiate_EidosImage): (internal error) unexpected type for numeric_value.\" << EidosTerminate();\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_Instantiate_EidosImage): the Image() constructor requires either a singleton string (a file path) or a numeric vector (a matrix of pixel values).\" << EidosTerminate();\n\t}\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosImage_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tEidosImage_Class\n//\n#pragma mark -\n#pragma mark EidosImage_Class\n#pragma mark -\n\nEidosClass *gEidosImage_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *EidosImage_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosImage_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_width,\t\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_height,\t\t\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_isGrayscale,\t\ttrue,\tkEidosValueMaskLogical | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_bitsPerChannel,\ttrue,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_integerR,\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_integerG,\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_integerB,\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_integerK,\t\t\ttrue,\tkEidosValueMaskInt)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_floatR,\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_floatG,\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_floatB,\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr_floatK,\t\t\ttrue,\tkEidosValueMaskFloat)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *EidosImage_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosImage_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_write, kEidosValueMaskVOID))->AddString_S(gEidosStr_filePath));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosImage_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosImage_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_Image, Eidos_Instantiate_EidosImage, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosImage_Class))->AddEllipsis());\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_Image.h",
    "content": "//\n//  eidos_class_Image.h\n//  Eidos\n//\n//  Created by Ben Haller on 10/8/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosImage provides a simple RGB image object based on lodepng\n \n */\n\n#ifndef __Eidos__eidos_class_image__\n#define __Eidos__eidos_class_image__\n\n#include \"eidos_value.h\"\n\n\nextern EidosClass *gEidosImage_Class;\n\n\nclass EidosImage : public EidosDictionaryRetained\n{\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\nprivate:\n\tenum Channel {\n\t\tkRedChannel = 0,\n\t\tkGreenChannel,\n\t\tkBlueChannel,\n\t\tkGrayChannel\n\t};\n\t\n\t// image data from LodePNG; 8-bit grayscale if possible, otherwise 24-bit RGB\n\tstd::string file_path_;\n\tstd::vector<unsigned char> pixels_;\n\tint64_t width_ = 0, height_ = 0;\n\tbool is_grayscale_ = false;\n\t\n#if defined(SLIMGUI)\n\t// This cache is for Plot's image() method\n\tvoid *image_ = nullptr;\t\t\t\t\t\t\t// OWNED POINTER: a QImage* used by Plot\n\tbool image_flipped_;\t\t\t\t\t\t\t// true if the cached image was flipped\n\tvoid (*image_deleter_)(void *ptr) = nullptr;\t// a deleter function for image_ since we don't reference Qt\n#endif\n\t\n\t// cached channel data as EidosValues; these are constructed lazily\n\tEidosValue_SP int_red_values_, int_green_values_, int_blue_values_, int_gray_values_;\n\tEidosValue_SP float_red_values_, float_green_values_, float_blue_values_, float_gray_values_;\n\t\n\tvoid GetChannelMetrics(Channel p_channel, int64_t &p_pixel_stride, int64_t &p_pixel_suboffset);\n\tEidosValue_SP ValueForIntegerChannel(EidosValue_SP &p_channel_cache, Channel p_channel);\n\tEidosValue_SP ValueForFloatChannel(EidosValue_SP &p_channel_cache, Channel p_channel);\n\t\npublic:\n\tEidosImage(const EidosImage &p_original) = delete;\t// no copy-construct\n\tEidosImage& operator=(const EidosImage&) = delete;\t// no copying\n\t\n\texplicit EidosImage(const std::string &p_file_path);\n\tEidosImage(int64_t p_width, int64_t p_height, bool p_grayscale);\n\tvirtual ~EidosImage(void) override;\n\t\n\tinline int64_t Width(void) { return width_; }\n\tinline int64_t Height(void) { return height_; }\n\tinline unsigned char *Data(void) { return pixels_.data(); }\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tEidosValue_SP ExecuteMethod_write(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\tfriend class Plot;\t// in QtSLiM\n};\n\nclass EidosImage_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tEidosImage_Class(const EidosImage_Class &p_original) = delete;\t// no copy-construct\n\tEidosImage_Class& operator=(const EidosImage_Class&) = delete;\t// no copying\n\tinline EidosImage_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n};\n\n\n#endif /* defined(__Eidos__eidos_class_image__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_Object.cpp",
    "content": "//\n//  eidos_class_Object.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 10/12/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_class_Object.h\"\n\n#include <string>\n#include <algorithm>\n#include <vector>\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_value.h\"\n#include \"eidos_class_Object.h\"\n#include \"eidos_class_Dictionary.h\"\n#include \"eidos_class_DataFrame.h\"\n#include \"eidos_class_Image.h\"\n#include \"eidos_class_TestElement.h\"\n#include \"json.hpp\"\n\n\n//\n//\tEidosObject\n//\n#pragma mark -\n#pragma mark EidosObject\n#pragma mark -\n\n// EidosObject::Class() is not defined, to make this an abstract base class; but of course its class is gEidosObject_Class\n/*const EidosClass *EidosObject::Class(void) const\n{\n\treturn gEidosObject_Class;\n}*/\n\nconst EidosClass *EidosObject::Superclass(void) const\n{\n\tconst EidosClass *class_object = Class();\n\tconst EidosClass *superclass_object = class_object ? class_object->Superclass() : nullptr;\n\t\n\treturn superclass_object;\n}\n\nbool EidosObject::IsKindOfClass(const EidosClass *p_class_object) const\n{\n\tconst EidosClass *class_object = Class();\n\t\n\tdo\n\t{\n\t\tif (class_object == p_class_object)\n\t\t\treturn true;\n\t\t\n\t\tclass_object = class_object->Superclass();\n\t}\n\twhile (class_object);\n\t\n\treturn false;\n}\n\nbool EidosObject::IsMemberOfClass(const EidosClass *p_class_object) const\n{\n\treturn (Class() == p_class_object);\n}\n\nvoid EidosObject::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\n}\n\nnlohmann::json EidosObject::JSONRepresentation(void) const\n{\n\t// undefined, raises; subclass that know how to serialize themselves can override\n\tEIDOS_TERMINATION << \"ERROR (EidosObject::JSONRepresentation): objects, apart from Dictionary objects, cannot be converted to JSON.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosObject::GetProperty(EidosGlobalStringID p_property_id)\n{\n\t// This is the backstop, called by subclasses\n\tEIDOS_TERMINATION << \"ERROR (EidosObject::GetProperty for \" << Class()->ClassNameForDisplay() << \"): attempt to get a value for property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" was not handled by subclass.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosObject::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n#pragma unused(p_value)\n\t// This is the backstop, called by subclasses\n\tconst EidosPropertySignature *signature = Class()->SignatureForProperty(p_property_id);\n\t\n\tif (!signature)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosObject::SetProperty): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" is not defined for object element type \" << Class()->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\n\tbool readonly = signature->read_only_;\n\t\n\t// Check whether setting a read-only property was attempted; we can do this on behalf of all our subclasses\n\tif (readonly)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosObject::SetProperty for \" << Class()->ClassNameForDisplay() << \"): attempt to set a new value for read-only property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \".\" << EidosTerminate(nullptr);\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosObject::SetProperty for \" << Class()->ClassNameForDisplay() << \"): (internal error) setting a new value for read-write property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" was not handled by subclass.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosObject::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused(p_arguments, p_interpreter)\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_str:\t\t\t\t\treturn ExecuteMethod_str(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID_stringRepresentation:\treturn ExecuteMethod_stringRepresentation(p_method_id, p_arguments, p_interpreter);\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\t// Check whether the method call failed due to a bad subclass implementation\n\t\t\tconst std::vector<EidosMethodSignature_CSP> *methods = Class()->Methods();\n\t\t\tconst std::string &method_name = EidosStringRegistry::StringForGlobalStringID(p_method_id);\n\t\t\t\n\t\t\tfor (const EidosMethodSignature_CSP &method_sig : *methods)\n\t\t\t\tif (method_sig->call_name_.compare(method_name) == 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosObject::ExecuteInstanceMethod for \" << Class()->ClassNameForDisplay() << \"): (internal error) method \" << method_name << \" was not handled by subclass.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// Otherwise, we have an unrecognized method, so throw\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosObject::ExecuteInstanceMethod for \" << Class()->ClassNameForDisplay() << \"): unrecognized method name \" << method_name << \".\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n}\n\n//\t*********************\t– (void)str(void)\n//\nEidosValue_SP EidosObject::ExecuteMethod_str(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\toutput_stream << Class()->ClassNameForDisplay() << \":\" << std::endl;\n\t\n\tconst std::vector<EidosPropertySignature_CSP> *properties = Class()->Properties();\n\t\n\tfor (const EidosPropertySignature_CSP &property_sig : *properties)\n\t{\n\t\tconst std::string &property_name = property_sig->property_name_;\n\t\tEidosGlobalStringID property_id = property_sig->property_id_;\n\t\tEidosValue_SP property_value;\n\t\tbool oldSuppressWarnings = gEidosSuppressWarnings;\n\t\t\n\t\tgEidosSuppressWarnings = true;\t\t// prevent warnings from questionable property accesses from producing warnings in the user's output pane\n\t\t\n\t\ttry {\n\t\t\tproperty_value = GetProperty(property_id);\n\t\t} catch (...) {\n\t\t\t// throw away the raise message\n\t\t\tgEidosTermination.clear();\n\t\t\tgEidosTermination.str(gEidosStr_empty_string);\n\t\t}\n\t\t\n\t\tgEidosSuppressWarnings = oldSuppressWarnings;\n\t\t\n\t\tif (property_value)\n\t\t{\n\t\t\tEidosValueType property_type = property_value->Type();\n\t\t\tint property_count = property_value->Count();\n\t\t\tint property_dimcount = property_value->DimensionCount();\n\t\t\tconst int64_t *property_dims = property_value->Dimensions();\n\t\t\t\n\t\t\toutput_stream << \"\\t\" << property_name << \" \" << property_sig->PropertySymbol() << \" \";\n\t\t\t\n\t\t\tif (property_count == 0)\n\t\t\t{\n\t\t\t\t// zero-length vectors get printed according to the standard code in EidosValue\n\t\t\t\tproperty_value->Print(output_stream);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// start with the type, and then the class for object-type values\n\t\t\t\toutput_stream << property_type;\n\t\t\t\t\n\t\t\t\tif (property_type == EidosValueType::kValueObject)\n\t\t\t\t\toutput_stream << \"<\" << property_value->ElementType() << \">\";\n\t\t\t\t\n\t\t\t\t// then print the ranges for each dimension\n\t\t\t\toutput_stream << \" [\";\n\t\t\t\t\n\t\t\t\tif (property_dimcount == 1)\n\t\t\t\t\toutput_stream << \"0:\" << (property_count - 1) << \"] \";\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int dim_index = 0; dim_index < property_dimcount; ++dim_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (dim_index > 0)\n\t\t\t\t\t\t\toutput_stream << \", \";\n\t\t\t\t\t\toutput_stream << \"0:\" << (property_dims[dim_index] - 1);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\toutput_stream << \"] \";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// finally, print up to two values, if available, followed by an ellipsis if not all values were printed\n\t\t\t\tint output_count = std::min(2, property_count);\n\t\t\t\t\n\t\t\t\tfor (int output_index = 0; output_index < output_count; ++output_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP value = property_value->GetValueAtIndex(output_index, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tif (output_index > 0)\n\t\t\t\t\t\toutput_stream << gEidosStr_space_string;\n\t\t\t\t\t\n\t\t\t\t\toutput_stream << *value;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (property_count > output_count)\n\t\t\t\t\toutput_stream << \" ...\";\n\t\t\t}\n\t\t\t\n\t\t\toutput_stream << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The property threw an error when we tried to access it, which is allowed\n\t\t\t// for properties that are only valid in specific circumstances\n\t\t\toutput_stream << \"\\t\" << property_name << \" \" << property_sig->PropertySymbol() << \" <inaccessible>\" << std::endl;\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t– (string$)stringRepresentation(void)\n//\nEidosValue_SP EidosObject::ExecuteMethod_stringRepresentation(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\t\n\tstd::ostringstream oss;\n\t\n\tPrint(oss);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(oss.str()));\n}\n\nEidosValue_SP EidosObject::ContextDefinedFunctionDispatch(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused(p_function_name, p_arguments, p_interpreter)\n\tEIDOS_TERMINATION << \"ERROR (EidosObject::ContextDefinedFunctionDispatch for \" << Class()->ClassNameForDisplay() << \"): (internal error) unimplemented Context function dispatch.\" << EidosTerminate(nullptr);\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosObject &p_element)\n{\n\tp_element.Print(p_outstream);\t// get dynamic dispatch\n\t\n\treturn p_outstream;\n}\n\n\n//\n//\tEidosClass\n//\n#pragma mark -\n#pragma mark EidosClass\n#pragma mark -\n\n// global class registry; this non-const accessor is private\nstd::vector<EidosClass *> &EidosClass::EidosClassRegistry(void)\n{\n\t// Our global registry is handled this way, so that we don't run into order-of-initialization issues\n\tstatic std::vector<EidosClass *> *classRegistry = nullptr;\n\t\n\tif (!classRegistry)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::EidosClassRegistry(): not warmed up\");\n\t\t\n\t\tclassRegistry = new std::vector<EidosClass *>;\n\t}\n\t\n\treturn *classRegistry;\n}\n\nstd::vector<EidosClass *> EidosClass::RegisteredClasses(bool p_builtin, bool p_context)\n{\n\t// EidosClass::EidosClassRegistry() contains every class that has an allocated EidosClass object; we want to filter that\n\tstd::vector<EidosClass *> &classRegistry = EidosClass::EidosClassRegistry();\n\t\n\tif (classRegistry.size() == 0)\n\t\tstd::cout << \"EidosClass::RegisteredClasses() called before classes have been registered\" << std::endl;\n\t\n\tstd::vector<EidosClass *> filteredRegistry;\n\t\n\tfor (EidosClass *class_object : classRegistry)\n\t{\n\t\tbool builtin = false;\n\t\t\n\t\t// It's unfortunate to have to hard-code this here, but I can't think of a better\n\t\t// heuristic that wouldn't hard-code some detail about SLiM here...\n\t\tif ((class_object == gEidosObject_Class) ||\n\t\t\t(class_object == gEidosTestElement_Class) ||\n\t\t\t(class_object == gEidosTestElementNRR_Class) ||\n\t\t\t(class_object == gEidosDictionaryUnretained_Class) ||\n\t\t\t(class_object == gEidosDictionaryRetained_Class) ||\n\t\t\t(class_object == gEidosDataFrame_Class) ||\n\t\t\t(class_object == gEidosImage_Class))\n\t\t\tbuiltin = true;\n\t\t\n\t\tif ((builtin && p_builtin) || (!builtin && p_context))\n\t\t\tfilteredRegistry.emplace_back(class_object);\n\t}\n\t\n\treturn filteredRegistry;\n}\n\nstd::vector<EidosPropertySignature_CSP> EidosClass::RegisteredClassProperties(bool p_builtin, bool p_context)\n{\n\tstd::vector<EidosPropertySignature_CSP> propertySignatures;\n\tstd::vector<EidosClass *> classRegistry = EidosClass::RegisteredClasses(p_builtin, p_context);\n\t\n\tfor (EidosClass *class_object : classRegistry)\n\t{\n\t\tconst std::vector<EidosPropertySignature_CSP> *properties = class_object->Properties();\n\t\t\n\t\tpropertySignatures.insert(propertySignatures.end(), properties->begin(), properties->end());\n\t}\n\t\n\t// sort by pointer; we want pointer-identical signatures to end up adjacent\n\tstd::sort(propertySignatures.begin(), propertySignatures.end());\n\t\n\t// then unique by pointer value to get a list of unique signatures (which may not be unique by name)\n\tauto unique_end_iter = std::unique(propertySignatures.begin(), propertySignatures.end());\n\tpropertySignatures.resize(std::distance(propertySignatures.begin(), unique_end_iter));\n\t\n\t// now sort by name\n\tstd::sort(propertySignatures.begin(), propertySignatures.end(), CompareEidosPropertySignatures);\n\t\n\treturn propertySignatures;\n}\n\nstd::vector<EidosMethodSignature_CSP> EidosClass::RegisteredClassMethods(bool p_builtin, bool p_context)\n{\n\tstd::vector<EidosMethodSignature_CSP> methodSignatures;\n\tstd::vector<EidosClass *> classRegistry = EidosClass::RegisteredClasses(p_builtin, p_context);\n\t\n\tfor (EidosClass *class_object : classRegistry)\n\t{\n\t\tconst std::vector<EidosMethodSignature_CSP> *methods = class_object->Methods();\n\t\t\n\t\tmethodSignatures.insert(methodSignatures.end(), methods->begin(), methods->end());\n\t}\n\t\n\t// sort by pointer; we want pointer-identical signatures to end up adjacent\n\tstd::sort(methodSignatures.begin(), methodSignatures.end());\n\t\n\t// then unique by pointer value to get a list of unique signatures (which may not be unique by name)\n\tauto unique_end_iter = std::unique(methodSignatures.begin(), methodSignatures.end());\n\tmethodSignatures.resize(std::distance(methodSignatures.begin(), unique_end_iter));\n\t\n\t// now sort by name\n\tstd::sort(methodSignatures.begin(), methodSignatures.end(), CompareEidosCallSignatures);\n\t\n\treturn methodSignatures;\n}\n\nvoid EidosClass::CheckForDuplicateMethodsOrProperties(void)\n{\n\tstd::vector<EidosPropertySignature_CSP> all_properties = RegisteredClassProperties(true, true);\n\tstd::vector<EidosMethodSignature_CSP> all_methods = RegisteredClassMethods(true, true);\n\t\n\t// print out any property signatures that are identical by name but are not identical\n\t{\n\t\tEidosPropertySignature_CSP previous_sig = nullptr;\n\t\t\n\t\tfor (const EidosPropertySignature_CSP &sig : all_properties)\n\t\t{\n\t\t\tif (previous_sig && (sig->property_name_.compare(previous_sig->property_name_) == 0))\n\t\t\t{\n\t\t\t\t// We have a name collision.  That is OK as long as the property signatures are identical.\n\t\t\t\tif ((sig->property_id_ != previous_sig->property_id_) ||\n\t\t\t\t\t(sig->read_only_ != previous_sig->read_only_) ||\n\t\t\t\t\t(sig->value_mask_ != previous_sig->value_mask_) ||\n\t\t\t\t\t(sig->value_class_ != previous_sig->value_class_))\n\t\t\t\t\tstd::cout << \"Duplicate property name with different signature: \" << sig->property_name_ << std::endl;\n\t\t\t}\n\t\t\t\n\t\t\tprevious_sig = sig;\n\t\t}\n\t}\n\t\n\t// print out any method signatures that are identical by name but are not identical\n\t{\n\t\tEidosMethodSignature_CSP previous_sig = nullptr;\n\t\t\n\t\tfor (const EidosMethodSignature_CSP &sig : all_methods)\n\t\t{\n\t\t\tif (previous_sig && (sig->call_name_.compare(previous_sig->call_name_) == 0))\n\t\t\t{\n\t\t\t\t// We have a name collision.  That is OK as long as the method signatures are identical.\n\t\t\t\tconst EidosMethodSignature *sig1 = sig.get();\n\t\t\t\tconst EidosMethodSignature *sig2 = previous_sig.get();\n\t\t\t\t\n\t\t\t\tif ((typeid(*sig1) != typeid(*sig2)) ||\n\t\t\t\t\t(sig->is_class_method != previous_sig->is_class_method) ||\n\t\t\t\t\t(sig->call_name_ != previous_sig->call_name_) ||\n\t\t\t\t\t(sig->return_mask_ != previous_sig->return_mask_) ||\n\t\t\t\t\t(sig->return_class_ != previous_sig->return_class_) ||\n\t\t\t\t\t(sig->arg_masks_ != previous_sig->arg_masks_) ||\n\t\t\t\t\t(sig->arg_names_ != previous_sig->arg_names_) ||\n\t\t\t\t\t(sig->arg_classes_ != previous_sig->arg_classes_) ||\n\t\t\t\t\t(sig->has_optional_args_ != previous_sig->has_optional_args_) ||\n\t\t\t\t\t(sig->has_ellipsis_ != previous_sig->has_ellipsis_))\n\t\t\t\t\tstd::cout << \"Duplicate method name with a different signature: \" << sig->call_name_ << std::endl;\n\t\t\t}\n\t\t\t\n\t\t\tprevious_sig = sig;\n\t\t}\n\t}\n}\n\n// this constructor sets the display name to be the same as the class name\nEidosClass::EidosClass(const std::string &p_class_name, EidosClass *p_superclass) : class_name_(p_class_name), class_name_for_display_(p_class_name), superclass_(p_superclass)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::EidosClass(): not warmed up\");\n\t\n\t// Every EidosClass instance gets added to a shared registry, so that Eidos can find them all\n\tEidosClassRegistry().emplace_back(this);\n}\n\n// this constructor takes a separate display name; DictionaryRetained uses this to set its display name to Dictionary\nEidosClass::EidosClass(const std::string &p_class_name, const std::string &p_display_name, EidosClass *p_superclass) : class_name_(p_class_name), class_name_for_display_(p_display_name), superclass_(p_superclass)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::EidosClass(): not warmed up\");\n\t\n\t// Every EidosClass instance gets added to a shared registry, so that Eidos can find them all\n\tEidosClassRegistry().emplace_back(this);\n}\n\nEidosClass::~EidosClass(void)\n{\n}\n\nbool EidosClass::UsesRetainRelease(void) const\n{\n\treturn false;\n}\n\nbool EidosClass::IsSubclassOfClass(const EidosClass *p_class_object) const\n{\n\tconst EidosClass *class_object = this;\n\t\n\tdo\n\t{\n\t\tif (class_object == p_class_object)\n\t\t\treturn true;\n\t\t\n\t\tclass_object = class_object->Superclass();\n\t}\n\twhile (class_object);\n\t\n\treturn false;\n}\n\nvoid EidosClass::CacheDispatchTables(void)\n{\n\t// This can be called more than once during startup, because Eidos warms up and the SLiM warms up\n\tif (dispatches_cached_)\n\t\treturn;\n\t\n\t{\n\t\tconst std::vector<EidosPropertySignature_CSP> *properties = Properties();\n\t\tint32_t last_id = -1;\n\t\t\n\t\tfor (const EidosPropertySignature_CSP &sig : *properties)\n\t\t\tlast_id = std::max(last_id, (int32_t)sig->property_id_);\n\t\t\n\t\tproperty_signatures_dispatch_capacity_ = last_id + 1;\n\t\t\n\t\t// this limit may need to be lifted someday, but for now it's a sanity check if the uniquing code changes\n\t\t// all properties should use explicitly registered strings, in the present design, so they should all be <= gEidosID_LastContextEntry\n\t\tif ((int64_t)property_signatures_dispatch_capacity_ > (int64_t)gEidosID_LastContextEntry)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::CacheDispatchTables): (internal error) property dispatch table unreasonably large for class \" << ClassName() << \".\" << EidosTerminate(nullptr);\n\t\t\n\t\tproperty_signatures_dispatch_ = (EidosPropertySignature_CSP *)calloc(property_signatures_dispatch_capacity_, sizeof(EidosPropertySignature_CSP));\n\t\tif (!property_signatures_dispatch_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::CacheDispatchTables): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (const EidosPropertySignature_CSP &sig : *properties)\n\t\t\tproperty_signatures_dispatch_[sig->property_id_] = sig;\n\t}\n\t\n\t{\n\t\tconst std::vector<EidosMethodSignature_CSP> *methods = Methods();\n\t\tint32_t last_id = -1;\n\t\t\n\t\tfor (const EidosMethodSignature_CSP &sig : *methods)\n\t\t\tlast_id = std::max(last_id, (int32_t)sig->call_id_);\n\t\t\n\t\tmethod_signatures_dispatch_capacity_ = last_id + 1;\n\t\t\n\t\t// this limit may need to be lifted someday, but for now it's a sanity check if the uniquing code changes\n\t\tif (method_signatures_dispatch_capacity_ > 640)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::CacheDispatchTables): (internal error) method dispatch table unreasonably large for class \" << ClassName() << \".\" << EidosTerminate(nullptr);\n\t\t\n\t\tmethod_signatures_dispatch_ = (EidosMethodSignature_CSP *)calloc(method_signatures_dispatch_capacity_, sizeof(EidosMethodSignature_CSP));\n\t\tif (!method_signatures_dispatch_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::CacheDispatchTables): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (const EidosMethodSignature_CSP &sig : *methods)\n\t\t\tmethod_signatures_dispatch_[sig->call_id_] = sig;\n\t}\n\t\n\t//std::cout << ElementType() << \" property/method lookup table capacities: \" << property_signatures_dispatch_capacity_ << \" / \" << method_signatures_dispatch_capacity_ << \" (\" << ((property_signatures_dispatch_capacity_ + method_signatures_dispatch_capacity_) * sizeof(EidosPropertySignature *)) << \" bytes)\" << std::endl;\n\t\n\tdispatches_cached_ = true;\n}\n\nvoid EidosClass::RaiseForDispatchUninitialized(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosClass::RaiseForDispatchUninitialized): (internal error) dispatch tables not initialized for class \" << ClassName() << \".\" << EidosTerminate(nullptr);\n}\n\nconst std::vector<EidosPropertySignature_CSP> *EidosClass::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>;\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *EidosClass::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>;\n\t\t\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gEidosStr_methodSignature, kEidosValueMaskVOID))->AddString_OSN(\"methodName\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gEidosStr_propertySignature, kEidosValueMaskVOID))->AddString_OSN(\"propertyName\", gStaticEidosValueNULL));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gEidosStr_size, kEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tmethods->emplace_back((EidosClassMethodSignature *)(new EidosClassMethodSignature(gEidosStr_length, kEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_str, kEidosValueMaskVOID)));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr_stringRepresentation, kEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosClass::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosClass::Functions(): not warmed up\");\n\t\t\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\nEidosValue_SP EidosClass::ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n\tswitch (p_method_id)\n\t{\n\t\tcase gEidosID_propertySignature:\treturn ExecuteMethod_propertySignature(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gEidosID_methodSignature:\t\treturn ExecuteMethod_methodSignature(p_method_id, p_target, p_arguments, p_interpreter);\n\t\tcase gEidosID_size:\t\t\t\t\treturn ExecuteMethod_size_length(p_method_id, p_target, p_arguments, p_interpreter);\t\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\t\tcase gEidosID_length:\t\t\t\treturn ExecuteMethod_size_length(p_method_id, p_target, p_arguments, p_interpreter);\n\t\t\t\n\t\tdefault:\n\t\t{\n\t\t\t// Check whether the method call failed due to a bad subclass implementation\n\t\t\tconst std::vector<EidosMethodSignature_CSP> *methods = Methods();\n\t\t\tconst std::string &method_name = EidosStringRegistry::StringForGlobalStringID(p_method_id);\n\t\t\t\n\t\t\tfor (const EidosMethodSignature_CSP &method_sig : *methods)\n\t\t\t\tif (method_sig->call_name_.compare(method_name) == 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::ExecuteClassMethod for \" << ClassName() << \"): (internal error) method \" << method_name << \" was not handled by subclass.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// Otherwise, we have an unrecognized method, so throw\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosClass::ExecuteClassMethod for \" << ClassNameForDisplay() << \"): unrecognized method name \" << method_name << \".\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n}\n\n//\t*********************\t+ (void)propertySignature([Ns$ propertyName = NULL])\n//\nEidosValue_SP EidosClass::ExecuteMethod_propertySignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\tbool has_match_string = (p_arguments[0]->Type() == EidosValueType::kValueString);\n\tEidosValue *propertyName_value = (EidosValue *)p_arguments[0].get();\n\tconst std::string &match_string = (has_match_string ? ((EidosValue_String *)propertyName_value)->StringRefAtIndex_NOCAST(0, nullptr) : gEidosStr_empty_string);\n\tconst std::vector<EidosPropertySignature_CSP> *properties = Properties();\n\tbool signature_found = false;\n\t\n\tfor (const EidosPropertySignature_CSP &property_sig : *properties)\n\t{\n\t\tconst std::string &property_name = property_sig->property_name_;\n\t\t\n\t\tif (has_match_string && (property_name.compare(match_string) != 0))\n\t\t\tcontinue;\n\t\t\n\t\toutput_stream << property_name << \" \" << property_sig->PropertySymbol() << \" (\" << StringForEidosValueMask(property_sig->value_mask_, property_sig->value_class_, \"\", nullptr) << \")\" << std::endl;\n\t\t\n\t\tsignature_found = true;\n\t}\n\t\n\tif (has_match_string && !signature_found)\n\t\toutput_stream << \"No property found for '\" << match_string << \"'.\" << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t+ (void)methodSignature([Ns$ methodName = NULL])\n//\nEidosValue_SP EidosClass::ExecuteMethod_methodSignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tEidosValue *methodName_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\tbool method_name_specified = (methodName_value->Type() == EidosValueType::kValueString);\n\tconst std::string &match_string = (method_name_specified ? ((EidosValue_String *)methodName_value)->StringRefAtIndex_NOCAST(0, nullptr) : gEidosStr_empty_string);\n\tconst std::vector<EidosMethodSignature_CSP> *methods = Methods();\n\tbool signature_found = false;\n\t\n\t// Output class methods first\n\tfor (const EidosMethodSignature_CSP &method_sig : *methods)\n\t{\n\t\tif (!method_sig->is_class_method)\n\t\t\tcontinue;\n\t\t\n\t\tconst std::string &method_name = method_sig->call_name_;\n\t\t\n\t\tif (method_name_specified && (method_name.compare(match_string) != 0))\n\t\t\tcontinue;\n\t\t\n\t\tif (!method_name_specified && (method_name.substr(0, 1).compare(\"_\") == 0))\n\t\t\tcontinue;\t// skip internal methods that start with an underscore, unless specifically requested\n\t\t\n\t\toutput_stream << *method_sig << std::endl;\n\t\tsignature_found = true;\n\t}\n\t\n\t// Then instance methods\n\tfor (const EidosMethodSignature_CSP &method_sig : *methods)\n\t{\n\t\tif (method_sig->is_class_method)\n\t\t\tcontinue;\n\t\t\n\t\tconst std::string &method_name = method_sig->call_name_;\n\t\t\n\t\tif (method_name_specified && (method_name.compare(match_string) != 0))\n\t\t\tcontinue;\n\t\t\n\t\tif (!method_name_specified && (method_name.substr(0, 1).compare(\"_\") == 0))\n\t\t\tcontinue;\t// skip internal methods that start with an underscore, unless specifically requested\n\t\t\n\t\toutput_stream << *method_sig << std::endl;\n\t\tsignature_found = true;\n\t}\n\t\n\tif (method_name_specified && !signature_found)\n\t\toutput_stream << \"No method signature found for '\" << match_string << \"'.\" << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t*********************\t+ (integer$)size(void)\n//\t*********************\t+ (integer$)length(void)\n//\nEidosValue_SP EidosClass::ExecuteMethod_size_length(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const\n{\n#pragma unused (p_method_id, p_target, p_arguments, p_interpreter)\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(p_target->Count()));\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_Object.h",
    "content": "//\n//  eidos_class_Object.h\n//  Eidos\n//\n//  Created by Ben Haller on 10/12/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef __Eidos__eidos_class_Object__\n#define __Eidos__eidos_class_Object__\n\n\n#include <iostream>\n#include <vector>\n#include <string>\n\n#include \"eidos_globals.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_call_signature.h\"\n#include \"json_fwd.hpp\"\n\nclass EidosClass;\n\n#ifdef SLIMGUI\n// Forward declaration of EidosInterpreterDebugPointsSet; see eidos_interpreter.cpp\nstruct EidosInterpreterDebugPointsSet_struct;\ntypedef EidosInterpreterDebugPointsSet_struct EidosInterpreterDebugPointsSet;\n#endif\n\n\n#pragma mark -\n#pragma mark EidosObject\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n// This is the value type of which EidosValue_Object is a vector, just as double is the value type of which\n// EidosValue_Float is a vector.  EidosValue_Object is just a bag; this class is the abstract base class of\n// the things that can be contained in that bag.  This class defines the methods that can be used by an\n// instance of EidosValue_Object; EidosValue_Object just forwards such things on to this class.\n// EidosObject obeys sharing semantics; many EidosValue_Objects can refer to the same element, and\n// EidosObject never copies itself.  To manage its lifetime, refcounting can be used.  Many objects\n// do not use this refcount, since their lifetime is managed, but some objects, such as Mutation and the\n// internal test class EidosTestElement, use the refcount and delete themselves when they are done.  Those\n// objects inherit from EidosDictionaryRetained, and their EidosClass subclass must subclass from\n// EidosDictionaryRetained_Class (which guarantees inheritance from EidosDictionaryRetained).\n\nclass EidosObject\n{\npublic:\n\tEidosObject(const EidosObject &p_original) = delete;\t\t// no copy-construct\n\tEidosObject& operator=(const EidosObject&) = delete;\t\t// no copying\n\t\n\tinline EidosObject(void) { }\n\tinline virtual ~EidosObject(void) { }\n\t\n\tvirtual const EidosClass *Class(void) const = 0;\n\tconst EidosClass *Superclass(void) const;\n\tbool IsKindOfClass(const EidosClass *p_class_object) const;\n\tbool IsMemberOfClass(const EidosClass *p_class_object) const;\n\t\n\tvirtual void Print(std::ostream &p_ostream) const;\t\t// standard printing; prints Class()->ClassNameForDisplay()\n\tvirtual nlohmann::json JSONRepresentation(void) const;\t// undefined, raises; subclass that know how to serialize themselves can override\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id);\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value);\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_str(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_stringRepresentation(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// EidosContext is a typedef for EidosObject at present, so this class is the superclass of the Context\n\t// object.  If that gets complicated we'll probably want to make a new EidosContext class to formalize things,\n\t// but for now the only addition we need for that is this virtual function stub, used for Context-defined\n\t// function dispatch.\n\tvirtual EidosValue_SP ContextDefinedFunctionDispatch(const std::string &p_function_name, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n#ifdef SLIMGUI\n\t// Because this class is used for the Eidos Context, stuff related to the context has to be defined here.\n\t// We don't want to dictate what subclass of EidosObject the context might actually inherit from, so we\n\t// can't define this in a subclass.  I wish we had Obj-C protocols...\n\t\n\t// Support for debugging points in SLiMgui\n\tvirtual EidosInterpreterDebugPointsSet *DebugPoints(void) { return nullptr; };\n\tvirtual std::string DebugPointInfo(void) { return \"\"; };\n\t\n\t// Support for monitoring of file I/O in SLiMgui\n\tvirtual void FileWriteNotification(__attribute__((unused)) const std::string &p_file_path, __attribute__((unused)) std::vector<std::string> &&p_lines, __attribute__((unused)) bool p_append) { ; };\n#endif\n};\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosObject &p_element);\n\n\n#pragma mark -\n#pragma mark EidosClass\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n// This class is similar to Class objects in Objective-C; it represents the class of an EidosObject.\n// These class objects are not visible in Eidos, at least at present; they just work behind the scenes to\n// enable some behaviors.  In particular: (1) class objects define the interface, of methods and properties,\n// that elements implement; (2) class objects implement class methods, avoiding the need to call class\n// methods on an arbitrarily chosen instance of an element type; and most importantly, (3) class objects exist\n// even when no instance exists, allowing facilities like code completion to handle types and interfaces\n// without having to have instantiated object elements in hand.  It is conceivable that class objects will\n// become visible in Eidos at some point; but there seems to be no need for that at present.\n//\n// Note that this is not an abstract base class!  It is used to represent the class of empty object vectors.\n\nextern EidosClass *gEidosObject_Class;\n\nclass EidosClass\n{\nprivate:\n\t// This is the element type for vectors of this class.  Note that it is a reference to a std::string that\n\t// is defined externally, which must continue to exist for the lifetime of this class object.  This is\n\t// so that we can use pointer equality on class names for speed, notably in takeMigrants().\n\tconst std::string &class_name_;\n\t\n\t// This is the class name displayed to the user, which might be different from class_name.  In particular,\n\t// DictionaryRetained has a class_name_for_display_ of \"Dictionary\" to hide the class hierarchy there.\n\tconst std::string &class_name_for_display_;\n\t\n\t// This is the EidosClass object representing our superclass\n\tEidosClass *superclass_;\n\t\n\tstatic std::vector<EidosClass *> &EidosClassRegistry(void);\n\nprotected:\n\t// cached dispatch tables; these are lookup tables, indexed by EidosGlobalStringID property / method ids\n\tbool dispatches_cached_ = false;\n\t\n\tEidosPropertySignature_CSP *property_signatures_dispatch_ = nullptr;\n\tint32_t property_signatures_dispatch_capacity_ = 0;\n\t\n\tEidosMethodSignature_CSP *method_signatures_dispatch_ = nullptr;\n\tint32_t method_signatures_dispatch_capacity_ = 0;\n\t\npublic:\n\tstatic std::vector<EidosClass *> RegisteredClasses(bool p_builtin, bool p_context);\n\tstatic std::vector<EidosPropertySignature_CSP> RegisteredClassProperties(bool p_builtin, bool p_context);\n\tstatic std::vector<EidosMethodSignature_CSP> RegisteredClassMethods(bool p_builtin, bool p_context);\n\tstatic void CheckForDuplicateMethodsOrProperties(void);\n\t\n\tEidosClass(const EidosClass &p_original) = delete;\t\t// no copy-construct\n\tEidosClass& operator=(const EidosClass&) = delete;\t\t// no copying\n\t\n\tEidosClass(const std::string &p_class_name, EidosClass *p_superclass);\n\tEidosClass(const std::string &p_class_name, const std::string &p_display_name, EidosClass *p_superclass);\n\tvirtual ~EidosClass(void);\n\t\n\tvirtual bool UsesRetainRelease(void) const;\n\t\n\tinline const EidosClass *Class(void) const { return this; }\n\tinline const std::string &ClassName(void) const { return class_name_; };\n\tinline const std::string &ClassNameForDisplay(void) const { return class_name_for_display_; };\n\tinline const EidosClass *Superclass(void) const { return superclass_; }\n\tbool IsSubclassOfClass(const EidosClass *p_class_object) const;\n\t\n\t// We now use dispatch tables to look up our property and method signatures; this is faster than the old switch() dispatch\n\tvoid CacheDispatchTables(void);\n\tvoid RaiseForDispatchUninitialized(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\t\n\tinline __attribute__((always_inline)) const EidosPropertySignature *SignatureForProperty(EidosGlobalStringID p_property_id) const\n\t{\n#if DEBUG\n\t\tif (!dispatches_cached_)\n\t\t\tRaiseForDispatchUninitialized();\n#endif\n\t\tif (p_property_id < (EidosGlobalStringID)property_signatures_dispatch_capacity_)\n\t\t\treturn property_signatures_dispatch_[p_property_id].get();\t// the assumption is short-term use by the caller\n\t\t\n\t\treturn nullptr;\n\t}\n\t\n\tinline __attribute__((always_inline)) const EidosMethodSignature *SignatureForMethod(EidosGlobalStringID p_method_id) const\n\t{\n#if DEBUG\n\t\tif (!dispatches_cached_)\n\t\t\tRaiseForDispatchUninitialized();\n#endif\n\t\tif (p_method_id < (EidosGlobalStringID)method_signatures_dispatch_capacity_)\n\t\t\treturn method_signatures_dispatch_[p_method_id].get();\t// the assumption is short-term use by the caller\n\t\t\n\t\treturn nullptr;\n\t}\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const;\n\t\n\tvirtual EidosValue_SP ExecuteClassMethod(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_propertySignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_methodSignature(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n\tEidosValue_SP ExecuteMethod_size_length(EidosGlobalStringID p_method_id, EidosValue_Object *p_target, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) const;\n};\n\n\n#endif /* __Eidos__eidos_class_Object__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_TestElement.cpp",
    "content": "//\n//  eidos_class_TestElement.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 5/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_class_TestElement.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_globals.h\"\n\n#include <stdio.h>\n#include <sys/types.h>\n#include <dirent.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <algorithm>\n#include <string>\n#include <vector>\n\n\n//\n//\tEidosTestElement\n//\n#pragma mark -\n#pragma mark EidosTestElement\n#pragma mark -\n\nEidosTestElement::EidosTestElement(int64_t p_value) : yolk_(p_value)\n{\n}\n\nEidosTestElement::~EidosTestElement(void)\n{\n\t//std::cout << \"~EidosTestElement : \" << yolk_ << std::endl;\n}\n\nconst EidosClass *EidosTestElement::Class(void) const\n{\n\treturn gEidosTestElement_Class;\n}\n\nvoid EidosTestElement::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP EidosTestElement::GetProperty(EidosGlobalStringID p_property_id)\n{\n\tif (p_property_id == gEidosID__yolk)\t\t\t\t// ACCELERATED\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(yolk_));\n\telse if (p_property_id == gEidosID__increment)\n\t{\n\t\tEidosTestElement *inc_element = new EidosTestElement(yolk_ + 1);\n\t\tEidosValue_SP retval(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(inc_element, gEidosTestElement_Class));\n\t\tinc_element->Release();\t// retval now owns it; release the retain from new\n\t\t\n\t\treturn retval;\n\t}\n\t\n\t// all others, including gID_none\n\telse\n\t\treturn super::GetProperty(p_property_id);\n}\n\nEidosValue *EidosTestElement::GetProperty_Accelerated__yolk(EidosObject **p_elements, size_t p_elements_size)\n{\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_elements_size);\n\t\n\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t{\n\t\tEidosTestElement *element = (EidosTestElement *)(p_elements[element_index]);\n\t\t\n\t\tint_result->set_int_no_check(element->yolk_, element_index);\n\t}\n\t\n\treturn int_result;\n}\n\nvoid EidosTestElement::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tif (p_property_id == gEidosID__yolk)\t\t\t\t// ACCELERATED\n\t{\n\t\tyolk_ = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\treturn;\n\t}\n\t\n\t// all others, including gID_none\n\telse\n\t\treturn super::SetProperty(p_property_id, p_value);\n}\n\nvoid EidosTestElement::SetProperty_Accelerated__yolk(EidosObject **p_elements, size_t p_elements_size, const EidosValue &p_source, size_t p_source_size)\n{\n\tif (p_source_size == 1)\n\t{\n\t\tint64_t source_value = p_source.IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t\t((EidosTestElement *)(p_elements[element_index]))->yolk_ = source_value;\n\t}\n\telse\n\t{\n\t\tconst int64_t *source_data = p_source.IntData();\n\t\t\n\t\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t\t\t((EidosTestElement *)(p_elements[element_index]))->yolk_ = source_data[element_index];\n\t}\n}\n\nEidosValue_SP EidosTestElement::ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// All of our strings are in the global registry, so we can require a successful lookup\n\tswitch (p_method_id)\n\t{\n\t\t//case gEidosID__cubicYolk:\treturn ExecuteMethod_Accelerated_cubicYolk(p_method_id, p_arguments, p_interpreter);\n\t\tcase gEidosID__squareTest:\treturn ExecuteMethod_squareTest(p_method_id, p_arguments, p_interpreter);\n\t\tdefault:\t\t\t\t\treturn super::ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t}\n}\n\nEidosValue_SP EidosTestElement::ExecuteMethod_Accelerated_cubicYolk(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(p_elements_size);\n\t\n\tfor (size_t element_index = 0; element_index < p_elements_size; ++element_index)\n\t{\n\t\tEidosTestElement *element = (EidosTestElement *)(p_elements[element_index]);\n\t\t\n\t\tint_result->set_int_no_check(element->yolk_ * element->yolk_ * element->yolk_, element_index);\n\t}\n\t\n\treturn EidosValue_SP(int_result);\n}\n\nEidosValue_SP EidosTestElement::ExecuteMethod_squareTest(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_method_id, p_arguments, p_interpreter)\n\tEidosTestElement *sq_element = new EidosTestElement(yolk_ * yolk_);\n\tEidosValue_SP retval(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(sq_element, gEidosTestElement_Class));\n\tsq_element->Release();\t// retval now owns it; release the retain from new\n\t\n\treturn retval;\n}\n\n\n//\n//\tObject instantiation\n//\n#pragma mark -\n#pragma mark Object instantiation\n#pragma mark -\n\n//\t(object<_TestElement>$)_Test(integer$ yolk)\nstatic EidosValue_SP Eidos_Instantiate_EidosTestElement(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *yolk_value = p_arguments[0].get();\n\tEidosTestElement *objectElement = new EidosTestElement(yolk_value->IntAtIndex_NOCAST(0, nullptr));\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosTestElement_Class));\n\t\n\t// objectElement is now retained by result_SP, so we can release it\n\tobjectElement->Release();\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tEidosTestElement_Class\n//\n#pragma mark -\n#pragma mark EidosTestElement_Class\n#pragma mark -\n\nEidosClass *gEidosTestElement_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *EidosTestElement_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosTestElement_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr__yolk,\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedGet(EidosTestElement::GetProperty_Accelerated__yolk)->DeclareAcceleratedSet(EidosTestElement::SetProperty_Accelerated__yolk));\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr__increment,\ttrue,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gEidosTestElement_Class)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosMethodSignature_CSP> *EidosTestElement_Class::Methods(void) const\n{\n\tstatic std::vector<EidosMethodSignature_CSP> *methods = nullptr;\n\t\n\tif (!methods)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosTestElement_Class::Methods(): not warmed up\");\n\t\t\n\t\tmethods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());\n\t\t\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr__cubicYolk, kEidosValueMaskInt | kEidosValueMaskSingleton))->DeclareAcceleratedImp(EidosTestElement::ExecuteMethod_Accelerated_cubicYolk));\n\t\tmethods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gEidosStr__squareTest, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosTestElement_Class)));\n\t\t\n\t\tstd::sort(methods->begin(), methods->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn methods;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosTestElement_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosTestElement_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"_Test\", Eidos_Instantiate_EidosTestElement, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosTestElement_Class))->AddInt_S(\"yolk\"));\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\n\n//\n//\tEidosTestElementNRR\n//\n#pragma mark -\n#pragma mark EidosTestElementNRR\n#pragma mark -\n\nEidosTestElementNRR::EidosTestElementNRR(int64_t p_value) : yolk_(p_value)\n{\n}\n\nEidosTestElementNRR::~EidosTestElementNRR(void)\n{\n\t//std::cout << \"~EidosTestElementNRR : \" << yolk_ << std::endl;\n}\n\nconst EidosClass *EidosTestElementNRR::Class(void) const\n{\n\treturn gEidosTestElementNRR_Class;\n}\n\nvoid EidosTestElementNRR::Print(std::ostream &p_ostream) const\n{\n\tp_ostream << Class()->ClassNameForDisplay();\t// standard EidosObject behavior (not Dictionary behavior)\n}\n\nEidosValue_SP EidosTestElementNRR::GetProperty(EidosGlobalStringID p_property_id)\n{\n\tif (p_property_id == gEidosID__yolk)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(yolk_));\n\t\n\t// all others, including gID_none\n\telse\n\t\treturn super::GetProperty(p_property_id);\n}\n\nvoid EidosTestElementNRR::SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value)\n{\n\tif (p_property_id == gEidosID__yolk)\t\t\t\t// ACCELERATED\n\t{\n\t\tyolk_ = p_value.IntAtIndex_NOCAST(0, nullptr);\n\t\treturn;\n\t}\n\t\n\t// all others, including gID_none\n\telse\n\t\treturn super::SetProperty(p_property_id, p_value);\n}\n\n\n//\n//\tObject instantiation\n//\n#pragma mark -\n#pragma mark Object instantiation\n#pragma mark -\n\n//\t(object<_TestElementNRR>$)_TestNRR(integer$ yolk)\nstatic EidosValue_SP Eidos_Instantiate_EidosTestElementNRR(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *yolk_value = p_arguments[0].get();\n\tEidosTestElementNRR *objectElement = new EidosTestElementNRR(yolk_value->IntAtIndex_NOCAST(0, nullptr));\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosTestElementNRR_Class));\n\t\n\t// Note that since these are not under retain/release, and Eidos has no logic to keep track of them and release them, they just leak\n\t// This is probably what EidosTestElement::FreeThunks() used to do before EidosTestElement was put under retain/release, so that\n\t// mechanism will probably need to be revived in order for leak checking to work properly.\n\t\n\treturn result_SP;\n}\n\n\n//\n//\tEidosTestElementNRR_Class\n//\n#pragma mark -\n#pragma mark EidosTestElementNRR_Class\n#pragma mark -\n\nEidosClass *gEidosTestElementNRR_Class = nullptr;\n\n\nconst std::vector<EidosPropertySignature_CSP> *EidosTestElementNRR_Class::Properties(void) const\n{\n\tstatic std::vector<EidosPropertySignature_CSP> *properties = nullptr;\n\t\n\tif (!properties)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosTestElementNRR_Class::Properties(): not warmed up\");\n\t\t\n\t\tproperties = new std::vector<EidosPropertySignature_CSP>(*super::Properties());\n\t\t\n\t\tproperties->emplace_back((EidosPropertySignature *)(new EidosPropertySignature(gEidosStr__yolk,\t\tfalse,\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\t\n\t\tstd::sort(properties->begin(), properties->end(), CompareEidosPropertySignatures);\n\t}\n\t\n\treturn properties;\n}\n\nconst std::vector<EidosFunctionSignature_CSP> *EidosTestElementNRR_Class::Functions(void) const\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *functions = nullptr;\n\t\n\tif (!functions)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosTestElementNRR_Class::Functions(): not warmed up\");\n\t\t\n\t\t// Note there is no call to super, the way there is for methods and properties; functions are not inherited!\n\t\tfunctions = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\tfunctions->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"_TestNRR\", Eidos_Instantiate_EidosTestElementNRR, kEidosValueMaskObject | kEidosValueMaskSingleton, gEidosTestElementNRR_Class))->AddInt_S(\"yolk\"));\n\t\t\n\t\tstd::sort(functions->begin(), functions->end(), CompareEidosCallSignatures);\n\t}\n\t\n\treturn functions;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_class_TestElement.h",
    "content": "//\n//  eidos_class_TestElement.h\n//  Eidos\n//\n//  Created by Ben Haller on 5/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n Two classes are defined in this file, EidosTestElement and EidosTestElementNRR.  They are object element classes\n (i.e. element classes for EidosValue_Object) for testing of Eidos's objects.  They are not user-visible.\n \n */\n\n#ifndef __Eidos__eidos_class_test_element__\n#define __Eidos__eidos_class_test_element__\n\n#include \"eidos_value.h\"\n\n\n//\n// EidosTestElement is used for testing.  It is a subclass of EidosDictionaryRetained,\n// and is under retain-release.  It is instantiated with a hidden constructor:\n//\n//\t\t(object<_TestElement>$)_Test(integer$ value)\n//\n\nextern EidosClass *gEidosTestElement_Class;\n\n\nclass EidosTestElement : public EidosDictionaryRetained\n{\nprivate:\n\ttypedef EidosDictionaryRetained super;\n\nprivate:\n\tint64_t yolk_;\n\t\npublic:\n\tEidosTestElement(const EidosTestElement &p_original) = delete;\t// no copy-construct\n\tEidosTestElement& operator=(const EidosTestElement&) = delete;\t// no copying\n\t\n\texplicit EidosTestElement(int64_t p_value);\n\tvirtual ~EidosTestElement(void) override;\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n\t\n\tvirtual EidosValue_SP ExecuteInstanceMethod(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter) override;\n\tstatic EidosValue_SP ExecuteMethod_Accelerated_cubicYolk(EidosObject **p_elements, size_t p_elements_size, EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\tEidosValue_SP ExecuteMethod_squareTest(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// Accelerated property access; see class EidosObject for comments on this mechanism\n\tstatic EidosValue *GetProperty_Accelerated__yolk(EidosObject **p_elements, size_t p_elements_size);\n\tstatic void SetProperty_Accelerated__yolk(EidosObject **p_elements, size_t p_elements_size, const EidosValue &p_source, size_t p_source_size);\n};\n\nclass EidosTestElement_Class : public EidosDictionaryRetained_Class\n{\nprivate:\n\ttypedef EidosDictionaryRetained_Class super;\n\npublic:\n\tEidosTestElement_Class(const EidosTestElement_Class &p_original) = delete;\t// no copy-construct\n\tEidosTestElement_Class& operator=(const EidosTestElement_Class&) = delete;\t// no copying\n\tinline EidosTestElement_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosMethodSignature_CSP> *Methods(void) const override;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n};\n\n\n//\n// EidosTestElementNRR is used for testing.  It is a direct subclass of EidosObject and is\n// not under retain-release (thus \"NRR\").  It is instantiated with a hidden constructor:\n//\n//\t\t(object<_TestElementNRR>$)_TestNRR(integer$ value)\n//\n\nextern EidosClass *gEidosTestElementNRR_Class;\n\n\nclass EidosTestElementNRR : public EidosObject\n{\nprivate:\n\ttypedef EidosObject super;\n\nprivate:\n\tint64_t yolk_;\n\t\npublic:\n\tEidosTestElementNRR(const EidosTestElementNRR &p_original) = delete;\t// no copy-construct\n\tEidosTestElementNRR& operator=(const EidosTestElementNRR&) = delete;\t// no copying\n\t\n\texplicit EidosTestElementNRR(int64_t p_value);\n\tvirtual ~EidosTestElementNRR(void) override;\n\t\n\t//\n\t// Eidos support\n\t//\n\tvirtual const EidosClass *Class(void) const override;\n\tvirtual void Print(std::ostream &p_ostream) const override;\n\t\n\tvirtual EidosValue_SP GetProperty(EidosGlobalStringID p_property_id) override;\n\tvirtual void SetProperty(EidosGlobalStringID p_property_id, const EidosValue &p_value) override;\n};\n\nclass EidosTestElementNRR_Class : public EidosClass\n{\nprivate:\n\ttypedef EidosClass super;\n\npublic:\n\tEidosTestElementNRR_Class(const EidosTestElementNRR_Class &p_original) = delete;\t// no copy-construct\n\tEidosTestElementNRR_Class& operator=(const EidosTestElementNRR_Class&) = delete;\t// no copying\n\tinline EidosTestElementNRR_Class(const std::string &p_class_name, EidosClass *p_superclass) : super(p_class_name, p_superclass) { }\n\t\n\tvirtual const std::vector<EidosPropertySignature_CSP> *Properties(void) const override;\n\tvirtual const std::vector<EidosFunctionSignature_CSP> *Functions(void) const override;\n};\n\n\n\n\n#endif /* defined(__Eidos__eidos_class_test_element__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions.cpp",
    "content": "//\n//  eidos_functions.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n\n#include <utility>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\n// Source code for built-in functions that are implemented in Eidos.  These strings are globals mostly so the\n// formatting of the code looks nice in Xcode; they are used only by EidosInterpreter::BuiltInFunctions().\n\n// - (void)source(string$ filePath, [logical$ chdir = F])\nconst char *gEidosSourceCode_source =\nR\"V0G0N({\n\twarn = suppressWarnings(T);\n\tlines = readFile(filePath);\n\tsuppressWarnings(warn);\n\tif (isNULL(lines))\n\t\tstop(\"source(): file not found at path '\" + filePath + \"'\");\n\t\n\t_changedwd = (chdir & strcontains(filePath, \"/\"));\n\tif (_changedwd) {\n\t\tcomponents = strsplit(filePath, \"/\");\n\t\tpathComponents = components[seqLen(length(components) - 1)];\n\t\tpath = paste(pathComponents, sep=\"/\");\n\t\t_oldwd = setwd(path);\n\t\t_changedwd = T;\n\t}\n\t\n\t_executeLambda_OUTER(paste(lines, sep='\\n'));\n\t\n\tif (_changedwd)\n\t\tsetwd(_oldwd);\n})V0G0N\";\n\n// - (numeric)outerProduct(numeric x, numeric y)\nconst char *gEidosSourceCode_outerProduct =\nR\"V0G0N({\n\tif (!isNULL(dim(x)) | !isNULL(dim(y)))\n\t\tstop(\"ERROR (outerProduct): outerProduct() requires x and y to be vectors, not matrices or arrays; use drop() to convert to a vector if desired.\");\n\treturn matrixMult(matrix(x), t(matrix(y)));\n})V0G0N\";\n\n// - (numeric)matrixPow(numeric x, integer$ power)\nconst char *gEidosSourceCode_matrixPow = \nR\"V0G0N({\n\td = dim(x);\n\t\n\tif (size(d) != 2)\n\t\tstop(\"ERROR (matrixPow): matrixPow() requires x to be a matrix\");\n\tif (d[0] != d[1])\n\t\tstop(\"ERROR (matrixPow): matrixPow() requires x to be a square matrix\");\n\t\n\tif (power == 0)\n\t\treturn diag(d[0]);\n\telse if (power == 1)\n\t\treturn x;\n\telse if (power < 0) {\n\t\t// check for singularity; we could just let inverse() raise an error, but it would be more confusing for the user\n\t\tif (det(x) == 0)\n\t\t\tstop(\"ERROR (matrixPow): in matrixPow() the vector x is singular and thus non-invertible, so it cannot be raised to a negative power.\");\n\t\treturn matrixPow(inverse(x), -power);\n\t} else // (power >= 2)\n\t\treturn matrixMult(x, matrixPow(x, power - 1));\n})V0G0N\";\n\n\n//\n//\tConstruct our built-in function map\n//\n\n// We allocate all of our function signatures once and keep them forever, for faster EidosInterpreter startup\nconst std::vector<EidosFunctionSignature_CSP> &EidosInterpreter::BuiltInFunctions(void)\n{\n\tstatic std::vector<EidosFunctionSignature_CSP> *signatures = nullptr;\n\t\n\tif (!signatures)\n\t{\n\t\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosInterpreter::BuiltInFunctions(): not warmed up\");\n\t\t\n\t\tsignatures = new std::vector<EidosFunctionSignature_CSP>;\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tmath functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"abs\",\t\t\t\tEidos_ExecuteFunction_abs,\t\t\tkEidosValueMaskNumeric))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"acos\",\t\t\t\tEidos_ExecuteFunction_acos,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asin\",\t\t\t\tEidos_ExecuteFunction_asin,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"atan\",\t\t\t\tEidos_ExecuteFunction_atan,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"atan2\",\t\t\t\tEidos_ExecuteFunction_atan2,\t\tkEidosValueMaskFloat))->AddNumeric(\"x\")->AddNumeric(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"ceil\",\t\t\t\tEidos_ExecuteFunction_ceil,\t\t\tkEidosValueMaskFloat))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cos\",\t\t\t\tEidos_ExecuteFunction_cos,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cumProduct\",\t\tEidos_ExecuteFunction_cumProduct,\tkEidosValueMaskNumeric))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cumSum\",\t\t\tEidos_ExecuteFunction_cumSum,\t\tkEidosValueMaskNumeric))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"exp\",\t\t\t\tEidos_ExecuteFunction_exp,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"floor\",\t\t\t\tEidos_ExecuteFunction_floor,\t\tkEidosValueMaskFloat))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"integerDiv\",\t\tEidos_ExecuteFunction_integerDiv,\tkEidosValueMaskInt))->AddInt(\"x\")->AddInt(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"integerMod\",\t\tEidos_ExecuteFunction_integerMod,\tkEidosValueMaskInt))->AddInt(\"x\")->AddInt(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isFinite\",\t\t\tEidos_ExecuteFunction_isFinite,\t\tkEidosValueMaskLogical))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isInfinite\",\t\tEidos_ExecuteFunction_isInfinite,\tkEidosValueMaskLogical))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isNAN\",\t\t\t\tEidos_ExecuteFunction_isNAN,\t\tkEidosValueMaskLogical))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"log\",\t\t\t\tEidos_ExecuteFunction_log,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"log10\",\t\t\t\tEidos_ExecuteFunction_log10,\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"log2\",\t\t\t\tEidos_ExecuteFunction_log2,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"product\",\t\t\tEidos_ExecuteFunction_product,\t\tkEidosValueMaskNumeric | kEidosValueMaskSingleton))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"round\",\t\t\t\tEidos_ExecuteFunction_round,\t\tkEidosValueMaskFloat))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setUnion\",\t\t\tEidos_ExecuteFunction_setUnion,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddAny(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setIntersection\",\tEidos_ExecuteFunction_setIntersection,\tkEidosValueMaskAny))->AddAny(\"x\")->AddAny(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setDifference\",\t\tEidos_ExecuteFunction_setDifference,\tkEidosValueMaskAny))->AddAny(\"x\")->AddAny(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setSymmetricDifference\",\tEidos_ExecuteFunction_setSymmetricDifference,\tkEidosValueMaskAny))->AddAny(\"x\")->AddAny(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sign\",\t\t\t\tEidos_ExecuteFunction_sign,\t\t\tkEidosValueMaskNumeric))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sin\",\t\t\t\tEidos_ExecuteFunction_sin,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sqrt\",\t\t\t\tEidos_ExecuteFunction_sqrt,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sum\",\t\t\t\tEidos_ExecuteFunction_sum,\t\t\tkEidosValueMaskNumeric | kEidosValueMaskSingleton))->AddLogicalEquiv(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sumExact\",\t\t\tEidos_ExecuteFunction_sumExact,\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddFloat(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"tan\",\t\t\t\tEidos_ExecuteFunction_tan,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"trunc\",\t\t\t\tEidos_ExecuteFunction_trunc,\t\tkEidosValueMaskFloat))->AddFloat(\"x\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tstatistics functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cor\",\t\t\t\tEidos_ExecuteFunction_cor,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\")->AddNumeric_ON(\"y\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cov\",\t\t\t\tEidos_ExecuteFunction_cov,\t\t\tkEidosValueMaskFloat))->AddNumeric(\"x\")->AddNumeric_ON(\"y\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"filter\",\t\t\tEidos_ExecuteFunction_filter,\t\tkEidosValueMaskFloat))->AddNumeric(\"x\")->AddFloat(\"filter\")->AddLogicalEquiv_OS(\"outside\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"max\",\t\t\t\tEidos_ExecuteFunction_max,\t\t\tkEidosValueMaskAnyBase | kEidosValueMaskSingleton))->AddAnyBase(\"x\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"mean\",\t\t\t\tEidos_ExecuteFunction_mean,\t\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddLogicalEquiv(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"min\",\t\t\t\tEidos_ExecuteFunction_min,\t\t\tkEidosValueMaskAnyBase | kEidosValueMaskSingleton))->AddAnyBase(\"x\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"pmax\",\t\t\t\tEidos_ExecuteFunction_pmax,\t\t\tkEidosValueMaskAnyBase))->AddAnyBase(\"x\")->AddAnyBase(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"pmin\",\t\t\t\tEidos_ExecuteFunction_pmin,\t\t\tkEidosValueMaskAnyBase))->AddAnyBase(\"x\")->AddAnyBase(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"quantile\",\t\t\tEidos_ExecuteFunction_quantile,\t\tkEidosValueMaskFloat))->AddNumeric(\"x\")->AddFloat_ON(\"probs\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_range,\t\tEidos_ExecuteFunction_range,\t\tkEidosValueMaskNumeric))->AddNumeric(\"x\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sd\",\t\t\t\tEidos_ExecuteFunction_sd,\t\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"ttest\",\t\t\t\tEidos_ExecuteFunction_ttest,\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddFloat(\"x\")->AddFloat_ON(\"y\", gStaticEidosValueNULL)->AddFloat_OSN(\"mu\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"var\",\t\t\t\tEidos_ExecuteFunction_var,\t\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddNumeric(\"x\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tdistribution draw / density functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"findInterval\",\t\tEidos_ExecuteFunction_findInterval,\tkEidosValueMaskInt))->AddNumeric(\"x\")->AddNumeric(\"vec\")->AddLogical_OS(\"rightmostClosed\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"allInside\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dmvnorm\",\t\t\tEidos_ExecuteFunction_dmvnorm,\t\tkEidosValueMaskFloat))->AddFloat(\"x\")->AddNumeric(\"mu\")->AddNumeric(\"sigma\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dbeta\",\t\t\t\tEidos_ExecuteFunction_dbeta,\t\tkEidosValueMaskFloat))->AddFloat(\"x\")->AddNumeric(\"alpha\")->AddNumeric(\"beta\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dexp\",\t\t\t\tEidos_ExecuteFunction_dexp,\t\t\tkEidosValueMaskFloat))->AddFloat(\"x\")->AddNumeric_O(\"mu\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dgamma\",\t\t\tEidos_ExecuteFunction_dgamma,\t\tkEidosValueMaskFloat))->AddFloat(\"x\")->AddNumeric(\"mean\")->AddNumeric(\"shape\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dnorm\",\t\t\t\tEidos_ExecuteFunction_dnorm,\t\tkEidosValueMaskFloat))->AddFloat(\"x\")->AddNumeric_O(\"mean\", gStaticEidosValue_Integer0)->AddNumeric_O(\"sd\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"pnorm\",\t\t\t\tEidos_ExecuteFunction_pnorm,\t\tkEidosValueMaskFloat))->AddFloat(\"q\")->AddNumeric_O(\"mean\", gStaticEidosValue_Integer0)->AddNumeric_O(\"sd\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"qnorm\",\t\t\t\tEidos_ExecuteFunction_qnorm,\t\tkEidosValueMaskFloat))->AddFloat(\"p\")->AddNumeric_O(\"mean\", gStaticEidosValue_Integer0)->AddNumeric_O(\"sd\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rbeta\",\t\t\t\tEidos_ExecuteFunction_rbeta,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"alpha\")->AddNumeric(\"beta\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rbinom\",\t\t\tEidos_ExecuteFunction_rbinom,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddInt(\"size\")->AddFloat(\"prob\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rcauchy\",\t\t\tEidos_ExecuteFunction_rcauchy,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"location\", gStaticEidosValue_Integer0)->AddNumeric_O(\"scale\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rdirichlet\",\t\tEidos_ExecuteFunction_rdirichlet,\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"alpha\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rdunif\",\t\t\tEidos_ExecuteFunction_rdunif,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddInt_O(\"min\", gStaticEidosValue_Integer0)->AddInt_O(\"max\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rdunif64\",\t\t\tEidos_ExecuteFunction_rdunif64,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rexp\",\t\t\t\tEidos_ExecuteFunction_rexp,\t\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"mu\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rf\",\t\t\t\tEidos_ExecuteFunction_rf,\t\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"d1\")->AddNumeric(\"d2\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rgamma\",\t\t\tEidos_ExecuteFunction_rgamma,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"mean\")->AddNumeric(\"shape\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rgeom\",\t\t\t\tEidos_ExecuteFunction_rgeom,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddFloat(\"p\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rlaplace\",\t\t\tEidos_ExecuteFunction_rlaplace,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"b\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rlnorm\",\t\t\tEidos_ExecuteFunction_rlnorm,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"meanlog\", gStaticEidosValue_Integer0)->AddNumeric_O(\"sdlog\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rmultinom\",\t\t\tEidos_ExecuteFunction_rmultinom,\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddInt_S(gEidosStr_size)->AddNumeric(\"prob\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rmvnorm\",\t\t\tEidos_ExecuteFunction_rmvnorm,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"mu\")->AddNumeric(\"sigma\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rnbinom\",\t\t\tEidos_ExecuteFunction_rnbinom,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddNumeric(\"size\")->AddFloat(\"prob\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rnorm\",\t\t\t\tEidos_ExecuteFunction_rnorm,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"mean\", gStaticEidosValue_Integer0)->AddNumeric_O(\"sd\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rpois\",\t\t\t\tEidos_ExecuteFunction_rpois,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddNumeric(\"lambda\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"runif\",\t\t\t\tEidos_ExecuteFunction_runif,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric_O(\"min\", gStaticEidosValue_Integer0)->AddNumeric_O(\"max\", gStaticEidosValue_Integer1));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rweibull\",\t\t\tEidos_ExecuteFunction_rweibull,\t\tkEidosValueMaskFloat))->AddInt_S(gEidosStr_n)->AddNumeric(\"lambda\")->AddNumeric(\"k\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rztpois\",\t\t\tEidos_ExecuteFunction_rztpois,\t\tkEidosValueMaskInt))->AddInt_S(gEidosStr_n)->AddNumeric(\"lambda\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tvector construction functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_c,\t\t\tEidos_ExecuteFunction_c,\t\t\tkEidosValueMaskAny))->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_float,\t\tEidos_ExecuteFunction_float,\t\tkEidosValueMaskFloat))->AddInt_S(\"length\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_integer,\tEidos_ExecuteFunction_integer,\t\tkEidosValueMaskInt))->AddInt_S(\"length\")->AddInt_OS(\"fill1\", gStaticEidosValue_Integer0)->AddInt_OS(\"fill2\", gStaticEidosValue_Integer1)->AddInt_ON(\"fill2Indices\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_logical,\tEidos_ExecuteFunction_logical,\t\tkEidosValueMaskLogical))->AddInt_S(\"length\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_object,\tEidos_ExecuteFunction_object,\t\tkEidosValueMaskObject, gEidosObject_Class)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rep\",\t\t\t\tEidos_ExecuteFunction_rep,\t\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddInt_S(\"count\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"repEach\",\t\t\tEidos_ExecuteFunction_repEach,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddInt(\"count\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sample\",\t\t\tEidos_ExecuteFunction_sample,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddInt_S(\"size\")->AddLogical_OS(\"replace\", gStaticEidosValue_LogicalF)->AddNumeric_ON(gEidosStr_weights, gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"seq\",\t\t\t\tEidos_ExecuteFunction_seq,\t\t\tkEidosValueMaskNumeric))->AddNumeric_S(\"from\")->AddNumeric_S(\"to\")->AddNumeric_OSN(\"by\", gStaticEidosValueNULL)->AddInt_OSN(\"length\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"seqAlong\",\t\t\tEidos_ExecuteFunction_seqAlong,\t\tkEidosValueMaskInt))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"seqLen\",\t\t\tEidos_ExecuteFunction_seqLen,\t\tkEidosValueMaskInt))->AddInt_S(\"length\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_string,\tEidos_ExecuteFunction_string,\t\tkEidosValueMaskString))->AddInt_S(\"length\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tvalue inspection/manipulation functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"all\",\t\t\t\tEidos_ExecuteFunction_all,\t\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddLogical(\"x\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"allClose\",\t\t\tEidos_ExecuteFunction_allClose,\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddFloat(\"x\")->AddFloat(\"y\")->\n\t\t\t\t\t\t\t\t AddFloat_OS(\"rtol\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-5)))->\n\t\t\t\t\t\t\t\t AddFloat_OS(\"atol\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-8)))->\n\t\t\t\t\t\t\t\t AddLogical_OS(\"equalNAN\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"any\",\t\t\t\tEidos_ExecuteFunction_any,\t\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddLogical(\"x\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cat\",\t\t\t\tEidos_ExecuteFunction_cat,\t\t\tkEidosValueMaskVOID))->AddAny(\"x\")->AddString_OS(\"sep\", gStaticEidosValue_StringSpace)->AddLogical_OS(\"error\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"catn\",\t\t\t\tEidos_ExecuteFunction_catn,\t\t\tkEidosValueMaskVOID))->AddAny_O(\"x\", gStaticEidosValue_StringEmpty)->AddString_OS(\"sep\", gStaticEidosValue_StringSpace)->AddLogical_OS(\"error\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"format\",\t\t\tEidos_ExecuteFunction_format,\t\tkEidosValueMaskString))->AddString_S(\"format\")->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"identical\",\t\t\tEidos_ExecuteFunction_identical,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\")->AddAny(\"y\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"ifelse\",\t\t\tEidos_ExecuteFunction_ifelse,\t\tkEidosValueMaskAny))->AddLogical(\"test\")->AddAny(\"trueValues\")->AddAny(\"falseValues\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isClose\",\t\t\tEidos_ExecuteFunction_isClose,\t\tkEidosValueMaskLogical))->AddFloat(\"x\")->AddFloat(\"y\")->\n\t\t\t\t\t\t\t\t AddFloat_OS(\"rtol\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-5)))->\n\t\t\t\t\t\t\t\t AddFloat_OS(\"atol\", EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1e-8)))->\n\t\t\t\t\t\t\t\t AddLogical_OS(\"equalNAN\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"match\",\t\t\t\tEidos_ExecuteFunction_match,\t\tkEidosValueMaskInt))->AddAny(\"x\")->AddAny(\"table\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"order\",\t\t\t\tEidos_ExecuteFunction_order,\t\tkEidosValueMaskInt))->AddAnyBase(\"x\")->AddLogical_OS(\"ascending\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"paste\",\t\t\t\tEidos_ExecuteFunction_paste,\t\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddEllipsis()->AddString_OS(\"sep\", gStaticEidosValue_StringSpace));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"paste0\",\t\t\tEidos_ExecuteFunction_paste0,\t\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"print\",\t\t\t\tEidos_ExecuteFunction_print,\t\tkEidosValueMaskVOID))->AddAny(\"x\")->AddLogical_OS(\"error\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rank\",\t\t\t\tEidos_ExecuteFunction_rank,\t\t\tkEidosValueMaskNumeric))->AddNumeric(\"x\")->AddString_OS(\"tiesMethod\", gStaticEidosValue_String_average));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rev\",\t\t\t\tEidos_ExecuteFunction_rev,\t\t\tkEidosValueMaskAny))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_size,\t\tEidos_ExecuteFunction_size_length,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_length,\tEidos_ExecuteFunction_size_length,\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sort\",\t\t\t\tEidos_ExecuteFunction_sort,\t\t\tkEidosValueMaskAnyBase))->AddAnyBase(\"x\")->AddLogical_OS(\"ascending\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sortBy\",\t\t\tEidos_ExecuteFunction_sortBy,\t\tkEidosValueMaskObject))->AddObject(\"x\", nullptr)->AddString_S(\"property\")->AddLogical_OS(\"ascending\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_str,\t\tEidos_ExecuteFunction_str,\t\t\tkEidosValueMaskVOID))->AddAny(\"x\")->AddLogical_OS(\"error\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"tabulate\",\t\t\tEidos_ExecuteFunction_tabulate,\t\tkEidosValueMaskInt))->AddInt(\"bin\")->AddInt_OSN(\"maxbin\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"unique\",\t\t\tEidos_ExecuteFunction_unique,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddLogical_OS(\"preserveOrder\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"which\",\t\t\t\tEidos_ExecuteFunction_which,\t\tkEidosValueMaskInt))->AddLogical(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"whichMax\",\t\t\tEidos_ExecuteFunction_whichMax,\t\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAnyBase(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"whichMin\",\t\t\tEidos_ExecuteFunction_whichMin,\t\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAnyBase(\"x\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tvalue type testing/coercion functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asFloat\",\t\t\tEidos_ExecuteFunction_asFloat,\t\tkEidosValueMaskFloat))->AddAnyBase(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asInteger\",\t\t\tEidos_ExecuteFunction_asInteger,\tkEidosValueMaskInt))->AddAnyBase(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asLogical\",\t\t\tEidos_ExecuteFunction_asLogical,\tkEidosValueMaskLogical))->AddAnyBase(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asString\",\t\t\tEidos_ExecuteFunction_asString,\t\tkEidosValueMaskString))->AddAnyBase(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"elementType\",\t\tEidos_ExecuteFunction_elementType,\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isFloat\",\t\t\tEidos_ExecuteFunction_isFloat,\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isInteger\",\t\t\tEidos_ExecuteFunction_isInteger,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isLogical\",\t\t\tEidos_ExecuteFunction_isLogical,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isNULL\",\t\t\tEidos_ExecuteFunction_isNULL,\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isObject\",\t\t\tEidos_ExecuteFunction_isObject,\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"isString\",\t\t\tEidos_ExecuteFunction_isString,\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_type,\t\tEidos_ExecuteFunction_type,\t\t\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tstring manipulation functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"grep\",\t\t\t\tEidos_ExecuteFunction_grep,\t\t\tkEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskString))->AddString_S(\"pattern\")->AddString(\"x\")->AddLogical_OS(\"ignoreCase\", gStaticEidosValue_LogicalF)->AddString_OS(\"grammar\", gStaticEidosValue_String_ECMAScript)->AddString_OS(\"value\", gStaticEidosValue_String_indices)->AddLogical_OS(\"fixed\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"invert\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"nchar\",\t\t\t\tEidos_ExecuteFunction_nchar,\t\tkEidosValueMaskInt))->AddString(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"strcontains\",\t\tEidos_ExecuteFunction_strcontains,\tkEidosValueMaskLogical))->AddString(\"x\")->AddString_S(\"s\")->AddInt_OS(\"pos\", gStaticEidosValue_Integer0));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"strfind\",\t\t\tEidos_ExecuteFunction_strfind,\t\tkEidosValueMaskInt))->AddString(\"x\")->AddString_S(\"s\")->AddInt_OS(\"pos\", gStaticEidosValue_Integer0));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"strprefix\",\t\t\tEidos_ExecuteFunction_strprefix,\tkEidosValueMaskLogical))->AddString(\"x\")->AddString_S(\"s\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"strsplit\",\t\t\tEidos_ExecuteFunction_strsplit,\t\tkEidosValueMaskString))->AddString_S(\"x\")->AddString_OS(\"sep\", gStaticEidosValue_StringSpace));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"strsuffix\",\t\t\tEidos_ExecuteFunction_strsuffix,\tkEidosValueMaskLogical))->AddString(\"x\")->AddString_S(\"s\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"substr\",\t\t\tEidos_ExecuteFunction_substr,\t\tkEidosValueMaskString))->AddString(\"x\")->AddInt(\"first\")->AddInt_ON(\"last\", gStaticEidosValueNULL));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tmatrix and array functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"array\",\t\t\t\tEidos_ExecuteFunction_array,\t\tkEidosValueMaskAny))->AddAny(\"data\")->AddInt(\"dim\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cbind\",\t\t\t\tEidos_ExecuteFunction_cbind,\t\tkEidosValueMaskAny))->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"dim\",\t\t\t\tEidos_ExecuteFunction_dim,\t\t\tkEidosValueMaskInt))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"drop\",\t\t\t\tEidos_ExecuteFunction_drop,\t\t\tkEidosValueMaskAny))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"matrix\",\t\t\tEidos_ExecuteFunction_matrix,\t\tkEidosValueMaskAny))->AddAny(\"data\")->AddInt_OSN(\"nrow\", gStaticEidosValueNULL)->AddInt_OSN(\"ncol\", gStaticEidosValueNULL)->AddLogical_OS(\"byrow\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"matrixMult\",\t\tEidos_ExecuteFunction_matrixMult,\tkEidosValueMaskNumeric))->AddNumeric(\"x\")->AddNumeric(\"y\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"ncol\",\t\t\t\tEidos_ExecuteFunction_ncol,\t\t\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"nrow\",\t\t\t\tEidos_ExecuteFunction_nrow,\t\t\tkEidosValueMaskInt | kEidosValueMaskSingleton))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rbind\",\t\t\t\tEidos_ExecuteFunction_rbind,\t\tkEidosValueMaskAny))->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"t\",\t\t\t\t\tEidos_ExecuteFunction_t,\t\t\tkEidosValueMaskAny))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"upperTri\",\t\t\tEidos_ExecuteFunction_upperTri,\t\tkEidosValueMaskLogical))->AddAny(\"x\")->AddLogical_OS(\"diag\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"lowerTri\",\t\t\tEidos_ExecuteFunction_lowerTri,\t\tkEidosValueMaskLogical))->AddAny(\"x\")->AddLogical_OS(\"diag\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"diag\",\t\t\t\tEidos_ExecuteFunction_diag,\t\t\tkEidosValueMaskAny))->AddAny_O(\"x\", gStaticEidosValue_Integer1)->AddInt_OSN(\"nrow\", gStaticEidosValueNULL)->AddInt_OSN(\"ncol\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"tr\",\t\t\t\tEidos_ExecuteFunction_tr,\t\t\tkEidosValueMaskNumeric | kEidosValueMaskSingleton))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"det\",\t\t\t\tEidos_ExecuteFunction_det,\t\t\tkEidosValueMaskNumeric | kEidosValueMaskSingleton))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"inverse\",\t\t\tEidos_ExecuteFunction_inverse,\t\tkEidosValueMaskFloat))->AddNumeric(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"asVector\",\t\t\tEidos_ExecuteFunction_asVector,\t\tkEidosValueMaskAny))->AddAny(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rowSums\",\t\t\tEidos_ExecuteFunction_rowSums,\t\tkEidosValueMaskNumeric))->AddLogicalEquiv(\"x\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"colSums\",\t\t\tEidos_ExecuteFunction_colSums,\t\tkEidosValueMaskNumeric))->AddLogicalEquiv(\"x\"));\n\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tcolor manipulation functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"cmColors\",\t\t\tEidos_ExecuteFunction_cmColors,\t\tkEidosValueMaskString))->AddInt_S(gEidosStr_n)->MarkDeprecated());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"colors\",\t\t\tEidos_ExecuteFunction_colors,\t\tkEidosValueMaskString))->AddNumeric(gEidosStr_x)->AddString_S(\"name\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"heatColors\",\t\tEidos_ExecuteFunction_heatColors,\t\tkEidosValueMaskString))->AddInt_S(gEidosStr_n)->MarkDeprecated());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rainbow\",\t\t\tEidos_ExecuteFunction_rainbow,\t\tkEidosValueMaskString))->AddInt_S(gEidosStr_n)->AddFloat_OS(gEidosStr_s, gStaticEidosValue_Float1)->AddFloat_OS(\"v\", gStaticEidosValue_Float1)->AddFloat_OS(gEidosStr_start, gStaticEidosValue_Float0)->AddFloat_OSN(gEidosStr_end, gStaticEidosValueNULL)->AddLogical_OS(\"ccw\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"terrainColors\",\t\tEidos_ExecuteFunction_terrainColors,\tkEidosValueMaskString))->AddInt_S(gEidosStr_n)->MarkDeprecated());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"hsv2rgb\",\t\t\tEidos_ExecuteFunction_hsv2rgb,\t\tkEidosValueMaskFloat))->AddFloat(\"hsv\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rgb2hsv\",\t\t\tEidos_ExecuteFunction_rgb2hsv,\t\tkEidosValueMaskFloat))->AddFloat(\"rgb\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"rgb2color\",\t\t\tEidos_ExecuteFunction_rgb2color,\tkEidosValueMaskString))->AddFloat(\"rgb\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"color2rgb\",\t\t\tEidos_ExecuteFunction_color2rgb,\tkEidosValueMaskFloat))->AddString(gEidosStr_color));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tmiscellaneous functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"assert\",\t\t\t\tEidos_ExecuteFunction_assert,\t\t\tkEidosValueMaskVOID))->AddLogical(\"assertions\")->AddString_OSN(\"message\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_apply,\t\tEidos_ExecuteFunction_apply,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddInt(\"margin\")->AddString_S(\"lambdaSource\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_sapply,\tEidos_ExecuteFunction_sapply,\t\tkEidosValueMaskAny))->AddAny(\"x\")->AddString_S(\"lambdaSource\")->AddString_OS(\"simplify\", EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"vector\"))));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"beep\",\t\t\t\tEidos_ExecuteFunction_beep,\t\t\tkEidosValueMaskVOID))->AddString_OSN(\"soundName\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"citation\",\t\t\tEidos_ExecuteFunction_citation,\t\tkEidosValueMaskVOID)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"clock\",\t\t\t\tEidos_ExecuteFunction_clock,\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddString_OS(gEidosStr_type, EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"cpu\"))));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"date\",\t\t\t\tEidos_ExecuteFunction_date,\t\t\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"debugIndent\",\t\tEidos_ExecuteFunction_debugIndent,\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"defineConstant\",\tEidos_ExecuteFunction_defineConstant,\tkEidosValueMaskVOID))->AddString_S(\"symbol\")->AddAny(\"value\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"defineGlobal\",\t\tEidos_ExecuteFunction_defineGlobal,\tkEidosValueMaskVOID))->AddString_S(\"symbol\")->AddAny(\"value\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_doCall,\tEidos_ExecuteFunction_doCall,\t\tkEidosValueMaskAny | kEidosValueMaskVOID))->AddString_S(\"functionName\")->AddEllipsis());\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_executeLambda,\tEidos_ExecuteFunction_executeLambda,\tkEidosValueMaskAny | kEidosValueMaskVOID))->AddString_S(\"lambdaSource\")->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"timed\", nullptr, gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr__executeLambda_OUTER,\tEidos_ExecuteFunction__executeLambda_OUTER,\tkEidosValueMaskAny | kEidosValueMaskVOID))->AddString_S(\"lambdaSource\")->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton, \"timed\", nullptr, gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"exists\",\t\t\tEidos_ExecuteFunction_exists,\t\tkEidosValueMaskLogical))->AddString(\"symbol\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"functionSignature\",\tEidos_ExecuteFunction_functionSignature,\tkEidosValueMaskVOID))->AddString_OSN(\"functionName\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"functionSource\",\tEidos_ExecuteFunction_functionSource,\tkEidosValueMaskVOID))->AddString_S(\"functionName\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_ls,\t\tEidos_ExecuteFunction_ls,\t\t\tkEidosValueMaskVOID))->AddLogical_OS(\"showSymbolTables\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"license\",\t\t\tEidos_ExecuteFunction_license,\t\tkEidosValueMaskVOID)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"parallelGetNumThreads\",\t\t\tEidos_ExecuteFunction_parallelGetNumThreads,\t\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"parallelGetMaxThreads\",\t\t\tEidos_ExecuteFunction_parallelGetMaxThreads,\t\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"parallelGetTaskThreadCounts\",\tEidos_ExecuteFunction_parallelGetTaskThreadCounts,\tkEidosValueMaskObject | kEidosValueMaskSingleton, gEidosDictionaryRetained_Class)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"parallelSetNumThreads\",\t\t\tEidos_ExecuteFunction_parallelSetNumThreads,\t\tkEidosValueMaskVOID))->AddInt_OSN(\"numThreads\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"parallelSetTaskThreadCounts\",\tEidos_ExecuteFunction_parallelSetTaskThreadCounts,\tkEidosValueMaskVOID))->AddObject_SN(\"dict\", gEidosDictionaryUnretained_Class));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_rm,\t\tEidos_ExecuteFunction_rm,\t\t\tkEidosValueMaskVOID))->AddString_ON(\"variableNames\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setSeed\",\t\t\tEidos_ExecuteFunction_setSeed,\t\tkEidosValueMaskVOID))->AddInt_S(\"seed\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"getSeed\",\t\t\tEidos_ExecuteFunction_getSeed,\t\tkEidosValueMaskInt | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"stop\",\t\t\t\tEidos_ExecuteFunction_stop,\t\t\tkEidosValueMaskVOID))->AddString_OSN(\"message\", gStaticEidosValueNULL));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"suppressWarnings\",\tEidos_ExecuteFunction_suppressWarnings,\t\t\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddLogical_S(\"suppress\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"sysinfo\",\t\t\tEidos_ExecuteFunction_sysinfo,\t\tkEidosValueMaskAny))->AddString_S(\"key\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"system\",\t\t\tEidos_ExecuteFunction_system,\t\tkEidosValueMaskString))->AddString_S(\"command\")->AddString_O(\"args\", gStaticEidosValue_StringEmpty)->AddString_O(\"input\", gStaticEidosValue_StringEmpty)->AddLogical_OS(\"stderr\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"wait\", gStaticEidosValue_LogicalT));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"time\",\t\t\t\tEidos_ExecuteFunction_time,\t\t\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_usage,\t\tEidos_ExecuteFunction_usage,\t\tkEidosValueMaskFloat | kEidosValueMaskSingleton))->AddArgWithDefault(kEidosValueMaskLogical | kEidosValueMaskString | kEidosValueMaskOptional | kEidosValueMaskSingleton, gEidosStr_type, nullptr, EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"rss\"))));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"version\",\t\t\tEidos_ExecuteFunction_version,\t\tkEidosValueMaskFloat))->AddLogical_OS(\"print\", gStaticEidosValue_LogicalT));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tfilesystem access functions\n\t\t//\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"createDirectory\",\tEidos_ExecuteFunction_createDirectory,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(\"path\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"filesAtPath\",\t\tEidos_ExecuteFunction_filesAtPath,\tkEidosValueMaskString))->AddString_S(\"path\")->AddLogical_OS(\"fullPaths\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"getwd\",\t\t\t\tEidos_ExecuteFunction_getwd,\t\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"deleteFile\",\t\tEidos_ExecuteFunction_deleteFile,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"fileExists\",\t\tEidos_ExecuteFunction_fileExists,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"flushFile\",\t\t\tEidos_ExecuteFunction_flushFile,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"readFile\",\t\t\tEidos_ExecuteFunction_readFile,\t\tkEidosValueMaskString))->AddString_S(gEidosStr_filePath));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"readLine\",\t\t\tEidos_ExecuteFunction_readLine,\t\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"setwd\",\t\t\t\tEidos_ExecuteFunction_setwd,\t\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddString_S(\"path\"));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"tempdir\",\t\t\tEidos_ExecuteFunction_tempdir,\t\tkEidosValueMaskString | kEidosValueMaskSingleton)));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"writeFile\",\t\t\tEidos_ExecuteFunction_writeFile,\tkEidosValueMaskLogical | kEidosValueMaskSingleton))->AddString_S(gEidosStr_filePath)->AddString(\"contents\")->AddLogical_OS(\"append\", gStaticEidosValue_LogicalF)->AddLogical_OS(\"compress\", gStaticEidosValue_LogicalF));\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"writeTempFile\",\t\tEidos_ExecuteFunction_writeTempFile,\tkEidosValueMaskString | kEidosValueMaskSingleton))->AddString_S(\"prefix\")->AddString_S(\"suffix\")->AddString(\"contents\")->AddLogical_OS(\"compress\", gStaticEidosValue_LogicalF));\n\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tbuilt-in user-defined functions\n\t\t//\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(gEidosStr_source,\tgEidosSourceCode_source,\tkEidosValueMaskVOID))->AddString_S(gEidosStr_filePath)->AddLogical_OS(\"chdir\", gStaticEidosValue_LogicalF));\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"matrixPow\",\t\t\tgEidosSourceCode_matrixPow,\tkEidosValueMaskNumeric))->AddNumeric(\"x\")->AddInt_S(\"power\"));\n\t\t\n\t\tsignatures->emplace_back((EidosFunctionSignature *)(new EidosFunctionSignature(\"outerProduct\",\t\tgEidosSourceCode_outerProduct,\tkEidosValueMaskNumeric))->AddNumeric(\"x\")->AddNumeric(\"y\"));\n\t\t\n\t\t\n\t\t// ************************************************************************************\n\t\t//\n\t\t//\tobject instantiation – delegated to EidosClass subclasses\n\t\t//\n\t\tfor (EidosClass *eidos_class : EidosClass::RegisteredClasses(true, true))\n\t\t{\n\t\t\tconst std::vector<EidosFunctionSignature_CSP> *class_functions = eidos_class->Functions();\n\t\t\t\n\t\t\tsignatures->insert(signatures->end(), class_functions->begin(), class_functions->end());\n\t\t}\n\t\t\n\t\t\n\t\t// alphabetize, mostly to be nice to the auto-completion feature\n\t\tstd::sort(signatures->begin(), signatures->end(), CompareEidosFunctionSignatures);\n\t}\n\t\n\treturn *signatures;\n}\n\nEidosFunctionMap *EidosInterpreter::s_built_in_function_map_ = nullptr;\n\nvoid EidosInterpreter::CacheBuiltInFunctionMap(void)\n{\n\t// The built-in function map is statically allocated for faster EidosInterpreter startup\n\t\n\tif (!s_built_in_function_map_)\n\t{\n\t\tconst std::vector<EidosFunctionSignature_CSP> &built_in_functions = EidosInterpreter::BuiltInFunctions();\n\t\t\n\t\ts_built_in_function_map_ = new EidosFunctionMap;\n\t\t\n\t\tfor (const EidosFunctionSignature_CSP &sig : built_in_functions)\n\t\t\ts_built_in_function_map_->insert(EidosFunctionMapPair(sig->call_name_, sig));\n\t}\n}\n\n\n//\n//\tExecuting function calls\n//\n\nbool IdenticalEidosValues(EidosValue *x_value, EidosValue *y_value, bool p_compare_dimensions)\n{\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif ((x_type != y_type) || (x_count != y_count))\n\t\treturn false;\n\t\n\tif (p_compare_dimensions && !EidosValue::MatchingDimensions(x_value, y_value))\n\t\treturn false;\n\t\n\tif (x_type == EidosValueType::kValueNULL)\n\t\treturn true;\n\t\n\tif (x_type == EidosValueType::kValueLogical)\n\t{\n\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\tconst eidos_logical_t *logical_data1 = y_value->LogicalData();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tif (logical_data0[value_index] != logical_data1[value_index])\n\t\t\t\treturn false;\n\t}\n\telse if (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\tconst int64_t *int_data1 = y_value->IntData();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tif (int_data0[value_index] != int_data1[value_index])\n\t\t\t\treturn false;\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data0 = x_value->FloatData();\n\t\tconst double *float_data1 = y_value->FloatData();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tdouble xv = float_data0[value_index];\n\t\t\tdouble yv = float_data1[value_index];\n\t\t\t\n\t\t\tif (!std::isnan(xv) || !std::isnan(yv))\n\t\t\t\tif (xv != yv)\n\t\t\t\t\treturn false;\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueString)\n\t{\n\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\tconst std::string *string_vec1 = y_value->StringData();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tif (string_vec0[value_index] != string_vec1[value_index])\n\t\t\t\treturn false;\n\t}\n\telse if (x_type == EidosValueType::kValueObject)\n\t{\n\t\tEidosObject * const *objelement_vec0 = x_value->ObjectData();\n\t\tEidosObject * const *objelement_vec1 = y_value->ObjectData();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tif (objelement_vec0[value_index] != objelement_vec1[value_index])\n\t\t\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\nEidosValue_SP ConcatenateEidosValues(const std::vector<EidosValue_SP> &p_arguments, bool p_allow_null, bool p_allow_void)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// This function expects an error range to be set bracketing it externally,\n\t// so no blame token is needed here.\n\t\n\tEidosValueType highest_type = EidosValueType::kValueVOID;\t// start at the lowest\n\tbool has_object_type = false, has_nonobject_type = false, all_invisible = true;\n\tconst EidosClass *element_class = gEidosObject_Class;\n\tint reserve_size = 0;\n\t\n\t// First figure out our return type, which is the highest-promotion type among all our arguments\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg_value->Type();\n\t\tint arg_value_count = arg_value->Count();\n\t\t\n\t\treserve_size += arg_value_count;\n\t\t\n\t\tif (arg_type == EidosValueType::kValueVOID && !p_allow_void)\n\t\t\tEIDOS_TERMINATION << \"ERROR (ConcatenateEidosValues): void is not allowed to be used in this context.\" << EidosTerminate(nullptr);\n\t\tif (arg_type == EidosValueType::kValueNULL && !p_allow_null)\n\t\t\tEIDOS_TERMINATION << \"ERROR (ConcatenateEidosValues): NULL is not allowed to be used in this context.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// The highest type includes arguments of zero length; doing c(3, 7, string(0)) should produce a string vector\n\t\tif (arg_type > highest_type)\n\t\t\thighest_type = arg_type;\n\t\t\n\t\tif (!arg_value->Invisible())\n\t\t\tall_invisible = false;\n\t\t\n\t\tif (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tconst EidosClass *this_element_class = ((EidosValue_Object *)arg_value)->Class();\n\t\t\t\n\t\t\tif (this_element_class != gEidosObject_Class)\t// undefined objects do not conflict with other object types\n\t\t\t{\n\t\t\t\tif (element_class == gEidosObject_Class)\n\t\t\t\t{\n\t\t\t\t\t// we haven't seen a (defined) object type yet, so remember what type we're dealing with\n\t\t\t\t\telement_class = this_element_class;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we've already seen a object type, so check that this one is the same type\n\t\t\t\t\tif (element_class != this_element_class)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (ConcatenateEidosValues): objects of different types cannot be mixed.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\thas_object_type = true;\n\t\t}\n\t\telse if ((arg_type != EidosValueType::kValueNULL) && (arg_type != EidosValueType::kValueVOID))\n\t\t\thas_nonobject_type = true;\n\t}\n\t\n\tif (has_object_type && has_nonobject_type)\n\t\tEIDOS_TERMINATION << \"ERROR (ConcatenateEidosValues): object and non-object types cannot be mixed.\" << EidosTerminate(nullptr);\n\t\n\tif (highest_type == EidosValueType::kValueVOID)\n\t{\n\t\t// If VOID is disallowed by p_allow_void, we will not return it.  Otherwise, if all the values we concatenated are VOID,\n\t\t// we return VOID; the result of a vectorized method call where every call returns VOID is VOID, for instance.\n\t\treturn gStaticEidosValueVOID;\n\t}\n\tif (highest_type == EidosValueType::kValueNULL)\n\t{\n\t\t// If we've got nothing but NULL, then return NULL; preserve invisibility\n\t\tif (all_invisible)\n\t\t\treturn gStaticEidosValueNULLInvisible;\n\t\telse\n\t\t\treturn gStaticEidosValueNULL;\n\t}\n\t\n\t// Create an object of the right return type, concatenate all the arguments together, and return it\n\t// Note that NULLs here concatenate away silently because their Count()==0; a bit dangerous!\n\tif (highest_type == EidosValueType::kValueLogical)\n\t{\n\t\tEidosValue_Logical *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(reserve_size);\n\t\tEidosValue_Logical_SP result_SP = EidosValue_Logical_SP(result);\n\t\tint result_set_index = 0;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\t\n\t\t\tif (arg_value == gStaticEidosValue_LogicalF)\n\t\t\t{\n\t\t\t\tresult->set_logical_no_check(false, result_set_index++);\n\t\t\t}\n\t\t\telse if (arg_value == gStaticEidosValue_LogicalT)\n\t\t\t{\n\t\t\t\tresult->set_logical_no_check(true, result_set_index++);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tint arg_value_count = arg_value->Count();\n\t\t\t\t\n\t\t\t\tif (arg_value_count)\t// weeds out NULL; otherwise we must have a logical vector\n\t\t\t\t{\n\t\t\t\t\tconst eidos_logical_t *arg_data = arg_value->LogicalData();\n\t\t\t\t\t\n\t\t\t\t\t// Unlike the integer and float cases below, memcpy() is much faster for logical values\n\t\t\t\t\t// on OS X 10.12.6, Xcode 8.3; about 1.5 times faster, in fact.  So it is a win here.\n\t\t\t\t\t\n\t\t\t\t\t//for (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t//\tresult->set_logical_no_check(arg_data[value_index], result_set_index++);\n\t\t\t\t\tmemcpy(result->data_mutable() + result_set_index, arg_data, arg_value_count * sizeof(eidos_logical_t));\n\t\t\t\t\tresult_set_index += arg_value_count;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\telse if (highest_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Int *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(reserve_size);\n\t\tEidosValue_Int_SP result_SP = EidosValue_Int_SP(result);\n\t\tint result_set_index = 0;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_value_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_value_count)\n\t\t\t{\n\t\t\t\tif (arg_value->Type() == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\t// Speed up integer arguments, which are probably common since our result is integer\n\t\t\t\t\tconst int64_t *arg_data = arg_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\t// Annoyingly, memcpy() is actually *slower* here on OS X 10.12.6, Xcode 8.3; a test of the\n\t\t\t\t\t// memcpy() version runs in ~53.3 seconds versus ~48.4 seconds for the loop.  So the Clang\n\t\t\t\t\t// optimizer is smarter than the built-in memcpy() implementation, I guess.\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_int_no_check(arg_data[value_index], result_set_index++);\n\t\t\t\t\t//memcpy(result->data() + result_set_index, arg_data, arg_value_count * sizeof(int64_t));\n\t\t\t\t\t//result_set_index += arg_value_count;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_int_no_check(arg_value->IntAtIndex_CAST(value_index, nullptr), result_set_index++);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\telse if (highest_type == EidosValueType::kValueFloat)\n\t{\n\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(reserve_size);\n\t\tEidosValue_Float_SP result_SP = EidosValue_Float_SP(result);\n\t\tint result_set_index = 0;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_value_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_value_count)\n\t\t\t{\n\t\t\t\tif (arg_value->Type() == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\t// Speed up float arguments, which are probably common since our result is float\n\t\t\t\t\tconst double *arg_data = arg_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\t// Annoyingly, memcpy() is actually *slower* here on OS X 10.12.6, Xcode 8.3; a test of the\n\t\t\t\t\t// memcpy() version runs in ~53.3 seconds versus ~48.4 seconds for the loop.  So the Clang\n\t\t\t\t\t// optimizer is smarter than the built-in memcpy() implementation, I guess.\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_float_no_check(arg_data[value_index], result_set_index++);\n\t\t\t\t\t//memcpy(result->data() + result_set_index, arg_data, arg_value_count * sizeof(double));\n\t\t\t\t\t//result_set_index += arg_value_count;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_float_no_check(arg_value->FloatAtIndex_CAST(value_index, nullptr), result_set_index++);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\telse if (highest_type == EidosValueType::kValueString)\n\t{\n\t\tEidosValue_String *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(reserve_size);\n\t\tEidosValue_String_SP result_SP = EidosValue_String_SP(result);\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_value_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_value_count)\n\t\t\t{\n\t\t\t\tif (arg_value->Type() == EidosValueType::kValueString)\n\t\t\t\t{\n\t\t\t\t\t// Speed up string arguments, which are probably common since our result is string\n\t\t\t\t\tconst std::string *arg_vec = arg_value->StringData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->PushString(arg_vec[value_index]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->PushString(arg_value->StringAtIndex_CAST(value_index, nullptr));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\telse if (has_object_type)\n\t{\n\t\tEidosValue_Object *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(element_class))->resize_no_initialize_RR(reserve_size);\n\t\tEidosValue_Object_SP result_SP = EidosValue_Object_SP(result);\n\t\tint result_set_index = 0;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_value_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_value_count)\n\t\t\t{\n\t\t\t\tEidosObject * const *arg_data = arg_value->ObjectData();\n\t\t\t\t\n\t\t\t\t// Given the lack of win for memcpy() for integer and float above, I'm not even going to bother checking it for\n\t\t\t\t// EidosObject*, since there would also be the complexity of retain/release and DeclareClass() to deal with...\n\t\t\t\t\n\t\t\t\t// When retain/release of EidosObject is enabled, we go through the accessors so the copied pointers get retained\n\t\t\t\tif (result->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_object_element_no_check_no_previous_RR(arg_data[value_index], result_set_index++);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int value_index = 0; value_index < arg_value_count; ++value_index)\n\t\t\t\t\t\tresult->set_object_element_no_check_NORR(arg_data[value_index], result_set_index++);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (ConcatenateEidosValues): type '\" << highest_type << \"' is not supported by ConcatenateEidosValues().\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn EidosValue_SP(nullptr);\n}\n\nEidosValue_SP UniqueEidosValue(const EidosValue *p_x_value, bool p_preserve_order)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tconst EidosValue *x_value = p_x_value;\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 0)\n\t{\n\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse if (x_count == 1)\n\t{\n\t\tresult_SP = x_value->CopyValues();\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\tbool containsF = false, containsT = false;\n\t\t\n\t\tif (logical_data[0])\n\t\t{\n\t\t\t// We have a true, look for a false\n\t\t\tcontainsT = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (!logical_data[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have a false, look for a true\n\t\t\tcontainsF = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (logical_data[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (containsF && !containsT)\n\t\t\tresult_SP = (EidosValue_SP)gStaticEidosValue_LogicalF;\n\t\telse if (containsT && !containsF)\n\t\t\tresult_SP = (EidosValue_SP)gStaticEidosValue_LogicalT;\n\t\telse if (!containsT && !containsF)\n\t\t\tresult_SP = (EidosValue_SP)gStaticEidosValue_Logical_ZeroVec;\n\t\telse\t// containsT && containsF\n\t\t{\n\t\t\t// In this case, we need to be careful to preserve the order of occurrence\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(2);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(logical_data[0], 0);\n\t\t\tlogical_result->set_logical_no_check(!logical_data[0], 1);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueInt)\n\t{\n\t\t// We have x_count != 1, so the type of x_value must be EidosValue_Int_vector; we can use the fast API\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (p_preserve_order)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t value = int_data[value_index];\n\t\t\t\tint scan_index;\n\t\t\t\t\n\t\t\t\tfor (scan_index = 0; scan_index < value_index; ++scan_index)\n\t\t\t\t{\n\t\t\t\t\tif (value == int_data[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (scan_index == value_index)\n\t\t\t\t\tint_result->push_int(value);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<int64_t> dup_vec(int_data, int_data + x_count);\n\t\t\t\n\t\t\tstd::sort(dup_vec.begin(), dup_vec.end());\n\t\t\t\n\t\t\tauto unique_iter = std::unique(dup_vec.begin(), dup_vec.end());\n\t\t\tsize_t unique_count = unique_iter - dup_vec.begin();\n\t\t\tint64_t *dup_ptr = dup_vec.data();\n\t\t\t\n\t\t\tint_result->resize_no_initialize(unique_count);\n\t\t\t\n\t\t\tfor (size_t unique_index = 0; unique_index < unique_count; ++unique_index)\n\t\t\t\tint_result->set_int_no_check(dup_ptr[unique_index], unique_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\t// We have x_count != 1, so the type of x_value must be EidosValue_Float_vector; we can use the fast API\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tif (p_preserve_order)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble value = float_data[value_index];\n\t\t\t\tint scan_index;\n\t\t\t\t\n\t\t\t\tfor (scan_index = 0; scan_index < value_index; ++scan_index)\n\t\t\t\t{\n\t\t\t\t\tdouble comp = float_data[scan_index];\n\t\t\t\t\t\n\t\t\t\t\t// We need NAN values to compare equal; we unique multiple NANs down to one\n\t\t\t\t\tif ((std::isnan(value) && std::isnan(comp)) || (value == comp))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (scan_index == value_index)\n\t\t\t\t\tfloat_result->push_float(value);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<double> dup_vec(float_data, float_data + x_count);\n\t\t\t\n\t\t\t// sort NANs to the end\n\t\t\tstd::sort(dup_vec.begin(), dup_vec.end(), [](const double& a, const double& b) {\n\t\t\t\t// If a is NaN and b is not NaN, a should come after b\n\t\t\t\tif (std::isnan(a) && !std::isnan(b))\n\t\t\t\t\treturn false;\n\t\t\t\t\n\t\t\t\t// If b is NaN and a is not NaN, b should come after a\n\t\t\t\tif (!std::isnan(a) && std::isnan(b))\n\t\t\t\t\treturn true;\n\t\t\t\t\n\t\t\t\t// If both are NaN or both are non-NaN, sort numerically (ascending)\n\t\t\t\treturn a < b;\n\t\t\t});\n\t\t\t\n\t\t\t// Remove duplicates, including duplicate NANs\n\t\t\tauto unique_iter = std::unique(dup_vec.begin(), dup_vec.end(), [](const double& a, const double& b) {\n\t\t\t\treturn (std::isnan(a) && std::isnan(b)) || (a == b);\n\t\t\t});\n\t\t\tsize_t unique_count = unique_iter - dup_vec.begin();\n\t\t\tdouble *dup_ptr = dup_vec.data();\n\t\t\t\n\t\t\tfloat_result->resize_no_initialize(unique_count);\n\t\t\t\n\t\t\tfor (size_t unique_index = 0; unique_index < unique_count; ++unique_index)\n\t\t\t\tfloat_result->set_float_no_check(dup_ptr[unique_index], unique_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueString)\n\t{\n\t\t// We have x_count != 1, so the type of x_value must be EidosValue_String_vector; we can use the fast API\n\t\tconst std::string *string_vec = x_value->StringData();\n\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tif (p_preserve_order)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &value = string_vec[value_index];\n\t\t\t\tint scan_index;\n\t\t\t\t\n\t\t\t\tfor (scan_index = 0; scan_index < value_index; ++scan_index)\n\t\t\t\t{\n\t\t\t\t\tif (value == string_vec[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (scan_index == value_index)\n\t\t\t\t\tstring_result->PushString(value);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<std::string> dup_vec;\n\t\t\t\n\t\t\t// first make a copy of string_vec into dup_vec\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tdup_vec.push_back(string_vec[value_index]);\n\t\t\t\n\t\t\t// then sort and unique\n\t\t\tstd::sort(dup_vec.begin(), dup_vec.end());\n\t\t\t\n\t\t\tauto unique_iter = std::unique(dup_vec.begin(), dup_vec.end());\n\t\t\t\n\t\t\tfor (auto iter = dup_vec.begin(); iter != unique_iter; ++iter)\n\t\t\t\tstring_result->PushString(*iter);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueObject)\n\t{\n\t\t// We have x_count != 1, so the type of x_value must be EidosValue_Object_vector; we can use the fast API\n\t\tEidosObject * const *object_data = x_value->ObjectData();\n\t\tEidosValue_Object *object_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)x_value)->Class());\n\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\n\t\tif (p_preserve_order)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tEidosObject *value = object_data[value_index];\n\t\t\t\tint scan_index;\n\t\t\t\t\n\t\t\t\tfor (scan_index = 0; scan_index < value_index; ++scan_index)\n\t\t\t\t{\n\t\t\t\t\tif (value == object_data[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (scan_index == value_index)\n\t\t\t\t\tobject_result->push_object_element_CRR(value);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<EidosObject*> dup_vec(object_data, object_data + x_count);\n\t\t\t\n\t\t\tstd::sort(dup_vec.begin(), dup_vec.end());\n\t\t\t\n\t\t\tauto unique_iter = std::unique(dup_vec.begin(), dup_vec.end());\n\t\t\tsize_t unique_count = unique_iter - dup_vec.begin();\n\t\t\tEidosObject * const *dup_ptr = dup_vec.data();\n\t\t\t\n\t\t\tobject_result->resize_no_initialize_RR(unique_count);\n\t\t\t\n\t\t\tif (object_result->UsesRetainRelease())\n\t\t\t{\n\t\t\t\tfor (size_t unique_index = 0; unique_index < unique_count; ++unique_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_no_previous_RR(dup_ptr[unique_index], unique_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (size_t unique_index = 0; unique_index < unique_count; ++unique_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_NORR(dup_ptr[unique_index], unique_index);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\nEidosValue_SP SubsetEidosValue(const EidosValue *p_original_value, const EidosValue *p_indices, EidosToken *p_error_token, bool p_raise_range_errors)\n{\n\t// We have a simple vector-style subset that is not NULL; handle it as we did in Eidos 1.5 and earlier\n\t// If p_raise_range_errors is false, out-of-range indices will be ignored; if it is true, they will cause an error\n\tEidosValueType original_value_type = p_original_value->Type();\n\tEidosValueType indices_type = p_indices->Type();\n\t\n\tint original_value_count = p_original_value->Count();\n\tint indices_count = p_indices->Count();\n\t\n\tEidosValue_SP result_SP;\n\t\n\t// BCH 12/21/2023: Policy change to outlaw subsetting with float indices.  It was a bad idea, inherited from R.\n\tif (indices_type == EidosValueType::kValueFloat)\n\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): it is no longer legal to subset with float indices; use asInteger() to coerce the indices to integer.\" << EidosTerminate(p_error_token);\n\t\n\tif (indices_type == EidosValueType::kValueLogical)\n\t{\n\t\t// Subsetting with a logical vector means the vectors must match in length, if p_raise_range_errors is true; indices with a T value will be taken\n\t\t// If p_raise_range_errors is false, we here clip indices_count to original_value_count so we can loop over it safely\n\t\tif (original_value_count != indices_count)\n\t\t{\n\t\t\tif (p_raise_range_errors)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): the '[]' operator requires that the size() of a logical index operand must match the size() of the indexed operand.\" << EidosTerminate(p_error_token);\n\t\t\telse\n\t\t\t\tindices_count = std::min(indices_count, original_value_count);\n\t\t}\n\t\t\n\t\t// Subsetting with a logical vector does not attempt to allocate singleton values, for now; seems unlikely to be a frequently hit case\n\t\tconst eidos_logical_t *logical_index_data = p_indices->LogicalData();\n\t\t\n\t\tif (original_value_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *first_child_data = p_original_value->LogicalData();\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t\tif (logical_index_data[value_idx])\n\t\t\t\t\tlogical_result->push_logical_no_check(first_child_data[value_idx]);\n\t\t\t\n\t\t\tresult_SP = logical_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *first_child_data = p_original_value->IntData();\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t\tif (logical_index_data[value_idx])\n\t\t\t\t\tint_result->push_int_no_check(first_child_data[value_idx]);\t\t// cannot use set_int_no_check() because of the if()\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *first_child_data = p_original_value->FloatData();\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t\tif (logical_index_data[value_idx])\n\t\t\t\t\tfloat_result->push_float_no_check(first_child_data[value_idx]);\t// cannot use set_int_no_check() because of the if()\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *first_child_vec = p_original_value->StringData();\n\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t\tif (logical_index_data[value_idx])\n\t\t\t\t\tstring_result->PushString(first_child_vec[value_idx]);\n\t\t\t\n\t\t\tresult_SP = string_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject * const *first_child_vec = p_original_value->ObjectData();\n\t\t\tEidosValue_Object_SP obj_result_SP = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)p_original_value)->Class()));\n\t\t\tEidosValue_Object *obj_result = obj_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t\tif (logical_index_data[value_idx])\n\t\t\t\t\tobj_result->push_object_element_no_check_CRR(first_child_vec[value_idx]);\n\t\t\t\n\t\t\tresult_SP = obj_result_SP;\n\t\t}\n\t}\n\telse\t// (indices_type == EidosValueType::kValueInt)\n\t{\n\t\t// Subsetting with a int vector can use a vector of any length; the specific indices referenced will be taken\n\t\tconst int64_t *int_index_data = p_indices->IntData();\n\t\t\n\t\tif (original_value_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\t// result type is float; optimize for that\n\t\t\tconst double *first_child_data = p_original_value->FloatData();\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tfloat_result->push_float_no_check(first_child_data[index_value]);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\t// result type is integer; optimize for that\n\t\t\tconst int64_t *first_child_data = p_original_value->IntData();\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tint_result->push_int_no_check(first_child_data[index_value]);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\t// result type is object; optimize for that\n\t\t\tEidosObject * const *first_child_vec = p_original_value->ObjectData();\n\t\t\tEidosValue_Object_SP obj_result_SP = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)p_original_value)->Class()));\n\t\t\tEidosValue_Object *obj_result = obj_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tobj_result->push_object_element_no_check_CRR(first_child_vec[index_value]);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = obj_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\t// result type is logical; optimize for that\n\t\t\tconst eidos_logical_t *first_child_data = p_original_value->LogicalData();\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tlogical_result->push_logical_no_check(first_child_data[index_value]);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = logical_result_SP;\n\t\t}\n\t\telse if (original_value_type == EidosValueType::kValueString)\n\t\t{\n\t\t\t// result type is string; optimize for that\n\t\t\tconst std::string *first_child_vec = p_original_value->StringData();\n\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(indices_count);\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tstring_result->PushString(first_child_vec[index_value]);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = string_result_SP;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is the general case; it should never be hit\n\t\t\t// CODE COVERAGE: This is dead code\n\t\t\tresult_SP = p_original_value->NewMatchingType();\n\t\t\t\n\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\n\t\t\tfor (int value_idx = 0; value_idx < indices_count; value_idx++)\n\t\t\t{\n\t\t\t\tint64_t index_value = int_index_data[value_idx];\n\t\t\t\t\n\t\t\t\tif ((index_value < 0) || (index_value >= original_value_count))\n\t\t\t\t{\n\t\t\t\t\tif (p_raise_range_errors)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (SubsetEidosValue): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(p_error_token);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue((int)index_value, *p_original_value, p_error_token);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\nEidosValue_SP AppendEidosValues(EidosValue_SP x_value, EidosValue_SP y_value)\n{\n\t// This concatenates y_value onto the end of x_value, modifying x_value.  This is used to accelerate \"x = c(x, <expr>)\" in\n\t// EidosInterpreter::Evaluate_Assign(), avoiding the overhead of ConcatenateEidosValues(), which has to allocate a new value.\n\t// It can handle some type-promotion cases internally; for the cases it can't handle, it calls ConcatenateEidosValues() to\n\t// do the work for it.  It returns the resulting value for x if it changed, or nullptr if it could append successfully.\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design (like c())\n\tEidosValueType x_type = x_value->Type();\n\t\n\tif ((y_value->Type() == x_type) && (!x_value->IsConstant()) &&\n\t\t((x_type != EidosValueType::kValueObject) || (((EidosValue_Object *)(x_value.get()))->Class() == ((EidosValue_Object *)(y_value.get()))->Class())))\n\t{\n\t\t// x and y are the same type, and x is not a constant, so we can handle this case with a true append operation\n\t\tint x_count = x_value->Count(), y_count = y_value->Count();\n\t\t\n\t\tswitch (x_type)\n\t\t{\n\t\t\tcase EidosValueType::kValueLogical:\n\t\t\t{\n\t\t\t\tEidosValue_Logical *x_vec = (EidosValue_Logical *)x_value.get();\n\t\t\t\tx_vec->resize_by_expanding_no_initialize(x_count + y_count);\t\t\t\t\t// resize first, in case y is x\n\t\t\t\t\n\t\t\t\tconst eidos_logical_t *y_data = y_value->LogicalData();\n\t\t\t\t\n\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\tx_vec->set_logical_no_check(y_data[y_index], x_count + y_index);\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosValueType::kValueInt:\n\t\t\t{\n\t\t\t\tEidosValue_Int *x_vec = (EidosValue_Int *)x_value.get();\n\t\t\t\tx_vec->resize_by_expanding_no_initialize(x_count + y_count);\t\t\t\t\t// resize first, in case y is x\n\t\t\t\t\n\t\t\t\tconst int64_t *y_data = y_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\tx_vec->set_int_no_check(y_data[y_index], x_count + y_index);\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosValueType::kValueFloat:\n\t\t\t{\n\t\t\t\tEidosValue_Float *x_vec = (EidosValue_Float *)x_value.get();\n\t\t\t\tx_vec->resize_by_expanding_no_initialize(x_count + y_count);\t\t\t\t\t// resize first, in case y is x\n\t\t\t\t\n\t\t\t\tconst double *y_data = y_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\tx_vec->set_float_no_check(y_data[y_index], x_count + y_index);\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosValueType::kValueString:\n\t\t\t{\n\t\t\t\tEidosValue_String *x_vec = (EidosValue_String *)x_value.get();\n\t\t\t\tx_vec->Reserve(x_count + y_count);\t\t\t\t\t\t\t\t// resize first, in case y is x\n\t\t\t\t\n\t\t\t\tconst std::string *y_data = y_value->StringData();\n\t\t\t\t\n\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\tx_vec->PushString(y_data[y_index]);\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase EidosValueType::kValueObject:\n\t\t\t{\n\t\t\t\tEidosValue_Object *x_vec = (EidosValue_Object *)x_value.get();\n\t\t\t\tx_vec->resize_by_expanding_no_initialize_RR(x_count + y_count);\t\t\t\t\t// resize first, in case y is x\n\t\t\t\t\n\t\t\t\tEidosObject * const *y_data = y_value->ObjectData();\n\t\t\t\t\n\t\t\t\tif (x_vec->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\t\tx_vec->set_object_element_no_check_no_previous_RR(y_data[y_index], x_count + y_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (int y_index = 0; y_index < y_count; ++y_index)\n\t\t\t\t\t\tx_vec->set_object_element_no_check_NORR(y_data[y_index], x_count + y_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// transform x into a vector, like c() does\n\t\tx_value->SetDimensions(1, nullptr);\n\t\t\n\t\t// return nullptr to indicate that we handled the append\n\t\treturn EidosValue_SP();\n\t}\n\telse\n\t{\n\t\t// Not a case we can handle, because it involves type-promotion, or x is a constant; delegate to ConcatenateEidosValues()\n\t\tstd::vector<EidosValue_SP> arguments;\n\t\t\n\t\targuments.push_back(x_value);\n\t\targuments.push_back(y_value);\n\t\t\n\t\t// return the new object created by ConcatenateEidosValues(), which needs to replace x's value\n\t\treturn ConcatenateEidosValues(arguments, true, false);\t// allow NULL but not VOID\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions.h",
    "content": "//\n//  eidos_functions.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This file contains most of the code for processing function calls in the Eidos interpreter.\n \n */\n\n#ifndef __Eidos__eidos_functions__\n#define __Eidos__eidos_functions__\n\n#include \"eidos_value.h\"\n\n\n// Utility functions usable by everybody\nbool IdenticalEidosValues(EidosValue *x_value, EidosValue *y_value, bool p_compare_dimensions = true);\nEidosValue_SP ConcatenateEidosValues(const std::vector<EidosValue_SP> &p_arguments, bool p_allow_null, bool p_allow_void);\nEidosValue_SP UniqueEidosValue(const EidosValue *p_value, bool p_preserve_order);\nEidosValue_SP Eidos_ExecuteLambdaInternal(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter, bool p_execute_in_outer_scope);\nEidosValue_SP SubsetEidosValue(const EidosValue *p_value, const EidosValue *p_indices, EidosToken *p_error_token, bool p_raise_range_errors);\nEidosValue_SP AppendEidosValues(EidosValue_SP x_value, EidosValue_SP y_value);\n\n\n#pragma mark -\n#pragma mark Math functions\n#pragma mark -\n\n//\tmath functions\nEidosValue_SP Eidos_ExecuteFunction_abs(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_acos(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_asin(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_atan(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_atan2(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_ceil(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cos(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cumProduct(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cumSum(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_exp(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_floor(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_integerDiv(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_integerMod(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isFinite(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isInfinite(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isNAN(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_log(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_log10(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_log2(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_product(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_round(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setDifference(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setIntersection(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setSymmetricDifference(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setUnion(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sign(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sin(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sqrt(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sum(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sumExact(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_tan(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_trunc(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Statistics functions\n#pragma mark -\n\n//\tstatistics functions\nEidosValue_SP Eidos_ExecuteFunction_cor(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cov(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_filter(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_max(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_mean(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_min(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_pmax(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_pmin(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_quantile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_range(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sd(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_ttest(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_var(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Distribution draw/density functions\n#pragma mark -\n\n//\tdistribution draw / density functions\nEidosValue_SP Eidos_ExecuteFunction_findInterval(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dmvnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_qnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_pnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dbeta(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rbeta(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rbinom(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rcauchy(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rdirichlet(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rdunif(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rdunif64(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dexp(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rexp(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rf(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dgamma(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rgamma(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rgeom(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rlaplace(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rlnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rmultinom(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rmvnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rnbinom(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rnorm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rpois(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_runif(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rweibull(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rztpois(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Vector conversion functions\n#pragma mark -\n\n//\tvector construction functions\nEidosValue_SP Eidos_ExecuteFunction_c(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_float(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_integer(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_logical(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_object(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rep(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_repEach(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sample(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_seq(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_seqAlong(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_seqLen(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_string(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Value inspection/manipulation functions\n#pragma mark -\n\n//\tvalue inspection/manipulation functions\nEidosValue_SP Eidos_ExecuteFunction_all(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_allClose(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_any(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cat(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_catn(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_format(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_identical(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_ifelse(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isClose(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_match(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_order(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_paste(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_paste0(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_print(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rank(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rev(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_size_length(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sort(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sortBy(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_str(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_tabulate(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_unique(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_which(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_whichMax(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_whichMin(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Value type testing/coercion functions\n#pragma mark -\n\n//\tvalue type testing/coercion functions\nEidosValue_SP Eidos_ExecuteFunction_asFloat(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_asInteger(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_asLogical(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_asString(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_elementType(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isFloat(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isInteger(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isLogical(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isNULL(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isObject(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_isString(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_type(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark String manipulation functions\n#pragma mark -\n\n//\tstring manipulation functions\nEidosValue_SP Eidos_ExecuteFunction_grep(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_nchar(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_strcontains(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_strfind(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_strprefix(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_strsplit(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_strsuffix(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_substr(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Matrix and array functions\n#pragma mark -\n\n//\tmatrix and array functions\nEidosValue_SP Eidos_ExecuteFunction_apply(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_array(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_cbind(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_dim(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_drop(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_matrix(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_matrixMult(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_ncol(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_nrow(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rbind(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_t(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_upperTri(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_lowerTri(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_diag(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_tr(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_det(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_inverse(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_asVector(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rowSums(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_colSums(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Filesystem access functions\n#pragma mark -\n\n//\tfilesystem access functions\nEidosValue_SP Eidos_ExecuteFunction_createDirectory(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_deleteFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_fileExists(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_filesAtPath(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_flushFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_getwd(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_readFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_readLine(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setwd(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_tempdir(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_writeFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_writeTempFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Color manipulation functions\n#pragma mark -\n\n//\tcolor manipulation functions\nEidosValue_SP Eidos_ExecuteFunction_cmColors(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_colors(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_color2rgb(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_heatColors(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_hsv2rgb(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rainbow(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rgb2color(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rgb2hsv(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_terrainColors(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n\n#pragma mark -\n#pragma mark Miscellaneous functions\n#pragma mark -\n\n//\tmiscellaneous functions\nEidosValue_SP Eidos_ExecuteFunction_assert(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_beep(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_citation(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_clock(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_date(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_debugIndent(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_defineConstant(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_defineGlobal(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_doCall(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_executeLambda(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction__executeLambda_OUTER(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_exists(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_functionSignature(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_functionSource(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_getSeed(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_license(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_ls(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_parallelGetNumThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_parallelGetMaxThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_parallelGetTaskThreadCounts(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_parallelSetNumThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_parallelSetTaskThreadCounts(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_rm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sapply(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_setSeed(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_stop(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_suppressWarnings(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_sysinfo(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_system(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_time(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_usage(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP Eidos_ExecuteFunction_version(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\nEidosValue_SP SLiM_ExecuteFunction__startBenchmark(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\nEidosValue_SP SLiM_ExecuteFunction__stopBenchmark(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\n#endif /* defined(__Eidos__eidos_functions__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_colors.cpp",
    "content": "//\n//  eidos_functions_color.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n\n#include <string>\n#include <vector>\n\n\n// ************************************************************************************\n//\n//\tcolor manipulation functions\n//\n#pragma mark -\n#pragma mark Color manipulation functions\n#pragma mark -\n\n\n//\t(string)cmColors(integer$ n)\n//\tDEPRECATED IN SLIM 3.5; use colors()\nEidosValue_SP Eidos_ExecuteFunction_cmColors(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tchar hex_chars[8];\n\t\n\tif ((n < 0) || (n > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cmColors): cmColors() requires 0 <= n <= 100000.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = (int)n;\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble fraction = (value_index ? value_index / (double)(color_count - 1) : 0.0);\n\t\tdouble red, green, blue;\n\t\t\n\t\tEidos_ColorPaletteLookup(fraction, EidosColorPalette::kPalette_cm, red, green, blue);\n\t\tEidos_GetColorString(red, green, blue, hex_chars);\n\t\tstring_result->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string)colors(numeric x, string$ name)\nEidosValue_SP Eidos_ExecuteFunction_colors(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_String *name_value = (EidosValue_String *)p_arguments[1].get();\n\tconst std::string &name = name_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tEidosColorPalette palette = Eidos_PaletteForName(name);\n\tchar hex_chars[8];\n\t\n\tif (palette == EidosColorPalette::kPalette_INVALID)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_colors): unrecognized color palette name in colors().\" << EidosTerminate(nullptr);\n\t\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tif (x_value->Count() != 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_colors): colors() requires an integer x parameter value to be singleton (the number of colors to generate).\" << EidosTerminate(nullptr);\n\t\t\n\t\tint64_t x = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tif ((x < 0) || (x > 100000))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_colors): colors() requires 0 <= x <= 100000.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint color_count = (int)x;\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t\t{\n\t\t\tdouble fraction = (value_index ? value_index / (double)(color_count - 1) : 0.0);\n\t\t\tdouble red, green, blue;\n\t\t\t\n\t\t\tEidos_ColorPaletteLookup(fraction, palette, red, green, blue);\n\t\t\t\n\t\t\tEidos_GetColorString(red, green, blue, hex_chars);\n\t\t\tstring_result->PushString(std::string(hex_chars));\n\t\t}\n\t}\n\telse if (x_value->Type() == EidosValueType::kValueFloat)\n\t{\n\t\tint color_count = x_value->Count();\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t\t{\n\t\t\tdouble fraction = x_value->FloatAtIndex_NOCAST(value_index, nullptr);\n\t\t\tdouble red, green, blue;\n\t\t\t\n\t\t\tEidos_ColorPaletteLookup(fraction, palette, red, green, blue);\n\t\t\t\n\t\t\tEidos_GetColorString(red, green, blue, hex_chars);\n\t\t\tstring_result->PushString(std::string(hex_chars));\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)color2rgb(string color)\nEidosValue_SP Eidos_ExecuteFunction_color2rgb(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *color_value = (EidosValue_String *)p_arguments[0].get();\n\tint color_count = color_value->Count();\n\tfloat r, g, b;\n\t\n\tif (color_count == 1)\n\t{\n\t\t// returns a vector\n\t\tEidos_GetColorComponents(color_value->StringRefAtIndex_NOCAST(0, nullptr), &r, &g, &b);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{r, g, b});\n\t}\n\telse\n\t{\n\t\t// returns a matrix\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((size_t)color_count * 3);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t\t{\n\t\t\tEidos_GetColorComponents(color_value->StringRefAtIndex_NOCAST(value_index, nullptr), &r, &g, &b);\n\t\t\tfloat_result->set_float_no_check(r, value_index);\n\t\t\tfloat_result->set_float_no_check(g, value_index + color_count);\n\t\t\tfloat_result->set_float_no_check(b, value_index + color_count + color_count);\n\t\t}\n\t\t\n\t\tconst int64_t dim_buf[2] = {color_count, 3};\n\t\t\n\t\tresult_SP->SetDimensions(2, dim_buf);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string)heatColors(integer$ n)\n//\tDEPRECATED IN SLIM 3.5; use colors()\nEidosValue_SP Eidos_ExecuteFunction_heatColors(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tchar hex_chars[8];\n\t\n\tif ((n < 0) || (n > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_heatColors): heatColors() requires 0 <= n <= 100000.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = (int)n;\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble fraction = (value_index ? value_index / (double)(color_count - 1) : 0.0);\n\t\tdouble red, green, blue;\n\t\t\n\t\tEidos_ColorPaletteLookup(fraction, EidosColorPalette::kPalette_heat, red, green, blue);\n\t\tEidos_GetColorString(red, green, blue, hex_chars);\n\t\tstring_result->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)hsv2rgb(float hsv)\nEidosValue_SP Eidos_ExecuteFunction_hsv2rgb(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *hsv_value = p_arguments[0].get();\n\tint hsv_count = hsv_value->Count();\n\t\n\tif (((hsv_value->DimensionCount() != 1) || (hsv_count != 3)) &&\n\t\t((hsv_value->DimensionCount() != 2) || (hsv_value->Dimensions()[1] != 3)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_hsv2rgb): in function hsv2rgb(), hsv must contain exactly three elements, or be a matrix with exactly three columns.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = hsv_count / 3;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((size_t)color_count * 3);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble h = hsv_value->FloatAtIndex_NOCAST(value_index, nullptr);\n\t\tdouble s = hsv_value->FloatAtIndex_NOCAST(value_index + color_count, nullptr);\n\t\tdouble v = hsv_value->FloatAtIndex_NOCAST(value_index + color_count + color_count, nullptr);\n\t\tdouble r, g, b;\n\t\t\n\t\tEidos_HSV2RGB(h, s, v, &r, &g, &b);\n\t\t\n\t\tfloat_result->set_float_no_check(r, value_index);\n\t\tfloat_result->set_float_no_check(g, value_index + color_count);\n\t\tfloat_result->set_float_no_check(b, value_index + color_count + color_count);\n\t}\n\t\n\tfloat_result->CopyDimensionsFromValue(hsv_value);\n\t\n\treturn result_SP;\n}\n\n//\t(string)rainbow(integer$ n, [float$ s = 1], [float$ v = 1], [float$ start = 0], [Nf$ end = NULL], [logical$ ccw = T])\nEidosValue_SP Eidos_ExecuteFunction_rainbow(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *s_value = p_arguments[1].get();\n\tEidosValue *v_value = p_arguments[2].get();\n\tEidosValue *start_value = p_arguments[3].get();\n\tEidosValue *end_value = p_arguments[4].get();\n\tEidosValue *ccw_value = p_arguments[5].get();\n\t\n\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((n < 0) || (n > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires 0 <= n <= 100000.\" << EidosTerminate(nullptr);\n\t\n\tdouble s = s_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((s < 0.0) || (s > 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires HSV saturation s to be in the interval [0.0, 1.0].\" << EidosTerminate(nullptr);\n\t\n\tdouble v = v_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((v < 0.0) || (v > 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires HSV value v to be in the interval [0.0, 1.0].\" << EidosTerminate(nullptr);\n\t\n\tdouble start = start_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((start < 0.0) || (start > 1.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires HSV hue start to be in the interval [0.0, 1.0].\" << EidosTerminate(nullptr);\n\t\n\tdouble end = (end_value->Type() == EidosValueType::kValueNULL) ? ((n-1) / (double)n) : end_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((n > 0) && ((end < 0.0) || (end > 1.0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires HSV hue end to be in the interval [0.0, 1.0], or NULL.\" << EidosTerminate(nullptr);\n\t\n\tif ((n > 1) && (start == end))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rainbow): rainbow() requires start != end.\" << EidosTerminate(nullptr);\n\t\n\teidos_logical_t ccw = ccw_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (ccw && (end < start))\n\t\tend += 1.0;\n\telse if (!ccw && (end > start))\n\t\tstart += 1.0;\n\t\n\tchar hex_chars[8];\n\tint color_count = (int)n;\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\tresult_SP = EidosValue_SP(string_result);\n\tdouble r, g, b;\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble w = (value_index ? value_index / (double)(color_count - 1) : 0.0);\n\t\tdouble h = start + (end - start) * w;\n\t\t\n\t\tif (h >= 1.0)\n\t\t\th -= 1.0;\n\t\t\n\t\tEidos_HSV2RGB(h, s, v, &r, &g, &b);\n\t\tEidos_GetColorString(r, g, b, hex_chars);\n\t\tstring_result->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string)rgb2color(float rgb)\nEidosValue_SP Eidos_ExecuteFunction_rgb2color(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *rgb_value = p_arguments[0].get();\n\tint rgb_count = rgb_value->Count();\n\tchar hex_chars[8];\n\t\n\tif (((rgb_value->DimensionCount() != 1) || (rgb_count != 3)) &&\n\t\t((rgb_value->DimensionCount() != 2) || (rgb_value->Dimensions()[1] != 3)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgb2color): in function rgb2color(), rgb must contain exactly three elements, or be a matrix with exactly three columns.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = rgb_count / 3;\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble r = rgb_value->FloatAtIndex_NOCAST(value_index, nullptr);\n\t\tdouble g = rgb_value->FloatAtIndex_NOCAST(value_index + color_count, nullptr);\n\t\tdouble b = rgb_value->FloatAtIndex_NOCAST(value_index + color_count + color_count, nullptr);\n\t\t\n\t\tif (std::isnan(r) || std::isnan(g) || std::isnan(b))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgb2color): color component with value NAN is not legal.\" << EidosTerminate();\n\t\t\n\t\tEidos_GetColorString(r, g, b, hex_chars);\n\t\t\n\t\tstring_result->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rgb2hsv(float rgb)\nEidosValue_SP Eidos_ExecuteFunction_rgb2hsv(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *rgb_value = p_arguments[0].get();\n\tint rgb_count = rgb_value->Count();\n\t\n\tif (((rgb_value->DimensionCount() != 1) || (rgb_count != 3)) &&\n\t\t((rgb_value->DimensionCount() != 2) || (rgb_value->Dimensions()[1] != 3)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgb2hsv): in function rgb2hsv(), rgb must contain exactly three elements, or be a matrix with exactly three columns.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = rgb_count / 3;\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((size_t)color_count * 3);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble r = rgb_value->FloatAtIndex_NOCAST(value_index, nullptr);\n\t\tdouble g = rgb_value->FloatAtIndex_NOCAST(value_index + color_count, nullptr);\n\t\tdouble b = rgb_value->FloatAtIndex_NOCAST(value_index + color_count + color_count, nullptr);\n\t\tdouble h, s, v;\n\t\t\n\t\tEidos_RGB2HSV(r, g, b, &h, &s, &v);\n\t\t\n\t\tfloat_result->set_float_no_check(h, value_index);\n\t\tfloat_result->set_float_no_check(s, value_index + color_count);\n\t\tfloat_result->set_float_no_check(v, value_index + color_count + color_count);\n\t}\n\t\n\tfloat_result->CopyDimensionsFromValue(rgb_value);\n\t\n\treturn result_SP;\n}\n\n//\t(string)terrainColors(integer$ n)\n//\tDEPRECATED IN SLIM 3.5; use colors()\nEidosValue_SP Eidos_ExecuteFunction_terrainColors(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t n = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tchar hex_chars[8];\n\t\n\tif ((n < 0) || (n > 100000))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_terrainColors): terrainColors() requires 0 <= n <= 100000.\" << EidosTerminate(nullptr);\n\t\n\tint color_count = (int)n;\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(color_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tfor (int value_index = 0; value_index < color_count; ++value_index)\n\t{\n\t\tdouble fraction = (value_index ? value_index / (double)(color_count - 1) : 0.0);\n\t\tdouble red, green, blue;\n\t\t\n\t\tEidos_ColorPaletteLookup(fraction, EidosColorPalette::kPalette_terrain, red, green, blue);\n\t\tEidos_GetColorString(red, green, blue, hex_chars);\n\t\tstring_result->PushString(std::string(hex_chars));\n\t}\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_distributions.cpp",
    "content": "//\n//  eidos_functions_distributions.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_rng.h\"\n\n#include <vector>\n\n#include \"gsl_linalg.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_cdf.h\"\n#include \"eidos_simd.h\"\n\n\n// BCH 20 October 2016: continuing to try to fix problems with gcc 5.4.0 on Linux without breaking other\n// builds.  We will switch to including <cmath> and using the std:: namespace math functions, since on\n// that platform <cmath> is included as a side effect even if we don't include it ourselves, and on\n// that platform that actually (incorrectly) undefines the global functions defined by math.h.  On other\n// platforms, we get the global math.h functions defined as well, so we can't use using to select the\n// <cmath> functions, we have to specify them explicitly.\n// BCH 21 May 2017: since this continues to come up as an issue, it's worth adding a bit more commentary.\n// New code introduced on OS X may not correctly use the std:: namespace qualifier for math functions,\n// because it is not required in Xcode, and then the build breaks on Linux.  This problem is made worse\n// by the fact that gsl_math.h includes math.h, so that brings in the C functions in the global namespace.\n// We can't change that, because the GSL is C code and needs to use the C math library; it has not been\n// validated against the C++ math library as far as I know, so changing it to use cmath would be\n// dangerous.  So I think we need to just tolerate this build issue and fix it when it arises.\n#include <cmath>\n\n\n// ************************************************************************************\n//\n//\tdistribution draw / density functions\n//\n#pragma mark -\n#pragma mark Distribution draw/density functions\n#pragma mark -\n\n\n//\t(integer)findInterval(numeric x, numeric vec, [logical$ rightmostClosed = F], [logical$ allInside = F])\nEidosValue_SP Eidos_ExecuteFunction_findInterval(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Switching to using binary search for this algorithm, but I want to keep the old code around in case it is needed\n#define EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH\t1\n\t\n\tEidosValue *arg_x = p_arguments[0].get();\n\tEidosValue *arg_vec = p_arguments[1].get();\n\tEidosValue *arg_rightmostClosed = p_arguments[2].get();\n\tEidosValue *arg_allInside = p_arguments[3].get();\n\t\n\tEidosValueType x_type = arg_x->Type();\n\tint x_count = arg_x->Count();\n\t\n\tEidosValueType vec_type = arg_vec->Type();\n\tint vec_count = arg_vec->Count();\n\t\n\tif (vec_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_findInterval): findInterval() requires vec to be of length > 0.\" << EidosTerminate(nullptr);\n\t\n\tbool rightmostClosed = arg_rightmostClosed->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool allInside = arg_allInside->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n#if !(EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH)\n\t// Used by the old linear-search algorithm\n\tint initial_x_result = allInside ? 0 : -1;\n#endif\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\n\tif (vec_type == EidosValueType::kValueInt)\n\t{\n\t\t// Get a raw pointer to vec's values\n\t\tconst int64_t *vec_data = arg_vec->IntData();\n\t\t\n\t\t// Check that vec is sorted\n\t\tfor (int vec_index = 0; vec_index < vec_count - 1; ++vec_index)\n\t\t\tif (vec_data[vec_index] > vec_data[vec_index + 1])\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_findInterval): findInterval() requires vec to be sorted into non-decreasing order.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Branch on the type of arg_x\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *x_data = arg_x->IntData();\n\t\t\t\n\t\t\t// Find intervals for integer vec, integer x\n\t\t\t\n#if EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH\n\t\t\t// binary search - testing indicates this is pretty much always as fast or faster than linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tint64_t x_value = x_data[x_index];\n\t\t\t\tlong x_result;\n\t\t\t\t\n\t\t\t\tif (x_value < vec_data[0])\n\t\t\t\t\tx_result = (allInside ? 0 : -1);\n\t\t\t\telse if (x_value > vec_data[vec_count - 1])\n\t\t\t\t\tx_result = (allInside ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse if (x_value == vec_data[vec_count - 1])\n\t\t\t\t\tx_result = ((rightmostClosed || allInside) ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse\n\t\t\t\t\tx_result = (std::upper_bound(vec_data, vec_data + vec_count, x_value) - vec_data) - 1;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#else\n\t\t\t// linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tint64_t x_value = x_data[x_index];\n\t\t\t\tint x_result = initial_x_result;\n\t\t\t\t\n\t\t\t\tif (x_value >= vec_data[0])\n\t\t\t\t{\n\t\t\t\t\tfor (x_result = 0; x_result < vec_count - 1; ++x_result)\n\t\t\t\t\t\tif ((x_value >= vec_data[x_result]) && (x_value < vec_data[x_result + 1]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (rightmostClosed && (x_result == vec_count - 1) && (x_value == vec_data[vec_count - 1]))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t\tif (allInside && (x_result > vec_count - 2))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#endif\n\t\t}\n\t\telse\t// (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *x_data = arg_x->FloatData();\n\t\t\t\n\t\t\t// Find intervals for integer vec, float x\n\t\t\t\n#if EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH\n\t\t\t// binary search - testing indicates this is pretty much always as fast or faster than linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tdouble x_value = x_data[x_index];\n\t\t\t\tlong x_result;\n\t\t\t\t\n\t\t\t\tif (x_value < vec_data[0])\n\t\t\t\t\tx_result = (allInside ? 0 : -1);\n\t\t\t\telse if (x_value > vec_data[vec_count - 1])\n\t\t\t\t\tx_result = (allInside ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse if (x_value == vec_data[vec_count - 1])\n\t\t\t\t\tx_result = ((rightmostClosed || allInside) ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse\n\t\t\t\t\tx_result = (std::upper_bound(vec_data, vec_data + vec_count, x_value) - vec_data) - 1;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#else\n\t\t\t// linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tdouble x_value = x_data[x_index];\n\t\t\t\tint x_result = initial_x_result;\n\t\t\t\t\n\t\t\t\tif (x_value >= vec_data[0])\n\t\t\t\t{\n\t\t\t\t\tfor (x_result = 0; x_result < vec_count - 1; ++x_result)\n\t\t\t\t\t\tif ((x_value >= vec_data[x_result]) && (x_value < vec_data[x_result + 1]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (rightmostClosed && (x_result == vec_count - 1) && (x_value == vec_data[vec_count - 1]))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t\tif (allInside && (x_result > vec_count - 2))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#endif\n\t\t}\n\t}\n\telse // (vec_type == EidosValueType::kValueFloat))\n\t{\n\t\t// Get a raw pointer to vec's values\n\t\tconst double *vec_data = arg_vec->FloatData();\n\t\t\n\t\t// Check that vec is sorted\n\t\tfor (int vec_index = 0; vec_index < vec_count - 1; ++vec_index)\n\t\t\tif (vec_data[vec_index] > vec_data[vec_index + 1])\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_findInterval): findInterval() requires vec to be sorted into non-decreasing order.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Branch on the type of arg_x\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *x_data = arg_x->IntData();\n\t\t\t\n\t\t\t// Find intervals for float vec, integer x\n\t\t\t\n#if EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH\n\t\t\t// binary search - testing indicates this is pretty much always as fast or faster than linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tint64_t x_value = x_data[x_index];\n\t\t\t\tlong x_result;\n\t\t\t\t\n\t\t\t\tif (x_value < vec_data[0])\n\t\t\t\t\tx_result = (allInside ? 0 : -1);\n\t\t\t\telse if (x_value > vec_data[vec_count - 1])\n\t\t\t\t\tx_result = (allInside ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse if (x_value == vec_data[vec_count - 1])\n\t\t\t\t\tx_result = ((rightmostClosed || allInside) ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse\n\t\t\t\t\tx_result = (std::upper_bound(vec_data, vec_data + vec_count, x_value) - vec_data) - 1;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#else\n\t\t\t// linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tint64_t x_value = x_data[x_index];\n\t\t\t\tint x_result = initial_x_result;\n\t\t\t\t\n\t\t\t\tif (x_value >= vec_data[0])\n\t\t\t\t{\n\t\t\t\t\tfor (x_result = 0; x_result < vec_count - 1; ++x_result)\n\t\t\t\t\t\tif ((x_value >= vec_data[x_result]) && (x_value < vec_data[x_result + 1]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (rightmostClosed && (x_result == vec_count - 1) && (x_value == vec_data[vec_count - 1]))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t\tif (allInside && (x_result > vec_count - 2))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#endif\n\t\t}\n\t\telse\t// (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *x_data = arg_x->FloatData();\n\t\t\t\n\t\t\t// Find intervals for float vec, float x\n\t\t\t\n#if EIDOS_FIND_INTERVAL_USE_BINARY_SEARCH\n\t\t\t// binary search - testing indicates this is pretty much always as fast or faster than linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tdouble x_value = x_data[x_index];\n\t\t\t\tlong x_result;\n\t\t\t\t\n\t\t\t\tif (x_value < vec_data[0])\n\t\t\t\t\tx_result = (allInside ? 0 : -1);\n\t\t\t\telse if (x_value > vec_data[vec_count - 1])\n\t\t\t\t\tx_result = (allInside ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse if (x_value == vec_data[vec_count - 1])\n\t\t\t\t\tx_result = ((rightmostClosed || allInside) ? vec_count - 2 : vec_count - 1);\n\t\t\t\telse\n\t\t\t\t\tx_result = (std::upper_bound(vec_data, vec_data + vec_count, x_value) - vec_data) - 1;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#else\n\t\t\t// linear search\n\t\t\tfor (int x_index = 0; x_index < x_count; ++x_index)\n\t\t\t{\n\t\t\t\tdouble x_value = x_data[x_index];\n\t\t\t\tint x_result = initial_x_result;\n\t\t\t\t\n\t\t\t\tif (x_value >= vec_data[0])\n\t\t\t\t{\n\t\t\t\t\tfor (x_result = 0; x_result < vec_count - 1; ++x_result)\n\t\t\t\t\t\tif ((x_value >= vec_data[x_result]) && (x_value < vec_data[x_result + 1]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (rightmostClosed && (x_result == vec_count - 1) && (x_value == vec_data[vec_count - 1]))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t\tif (allInside && (x_result > vec_count - 2))\n\t\t\t\t\t\tx_result = vec_count - 2;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(x_result, x_index);\n\t\t\t}\n#endif\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(int_result);\n}\n\n//\t(float)dmvnorm(float x, numeric mu, numeric sigma)\nEidosValue_SP Eidos_ExecuteFunction_dmvnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_x = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\t\n\tif (arg_x->Count() == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// matrix with n rows (one row per quantile vector) and k columns (one column per dimension)\n\tint dimension_count = arg_x->DimensionCount();\n\tint64_t num_quantiles;\n\tint d;\n\t\n\tif (dimension_count == 1)\n\t{\n\t\tnum_quantiles = 1;\n\t\td = arg_x->Count();\n\t}\n\telse if (dimension_count == 2)\n\t{\n\t\tconst int64_t *dimensions = arg_x->Dimensions();\n\t\tnum_quantiles = dimensions[0];\n\t\td = (int)dimensions[1];\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires x to be a vector containing a single quantile, or a matrix of quantiles.\" << EidosTerminate(nullptr);\n\t\n\tif (d <= 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires a Gaussian function dimensionality of >= 2 (use dnorm() for dimensionality of 1).\" << EidosTerminate(nullptr);\n\t\n\tint mu_count = arg_mu->Count();\n\tint mu_dimcount = arg_mu->DimensionCount();\n\tint sigma_dimcount = arg_sigma->DimensionCount();\n\tconst int64_t *sigma_dims = arg_sigma->Dimensions();\n\t\n\tif ((mu_dimcount != 1) || (mu_count != d))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires mu to be a plain vector of length k, where k is the number of dimensions for the multivariate Gaussian function (>= 2), matching the dimensionality of the quantile vectors in x.\" << EidosTerminate(nullptr);\n\tif (sigma_dimcount != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires sigma to be a matrix.\" << EidosTerminate(nullptr);\n\tif ((sigma_dims[0] != d) || (sigma_dims[1] != d))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires sigma to be a k x k matrix, where k is the number of dimensions for the multivariate Gaussian function (>= 2), matching the dimensionality of the quantile vectors in x.\" << EidosTerminate(nullptr);\n\t\n\t// Set up the GSL vectors\n\tgsl_vector *gsl_mu = gsl_vector_calloc(d);\n\tgsl_matrix *gsl_Sigma = gsl_matrix_calloc(d, d);\n\tgsl_matrix *gsl_L = gsl_matrix_calloc(d, d);\n\tgsl_vector *gsl_x = gsl_vector_calloc(d);\n\tgsl_vector *gsl_work = gsl_vector_calloc(d);\n\t\n\tif (!gsl_mu || !gsl_Sigma || !gsl_L || !gsl_x || !gsl_work)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\ttry {\n\t\tfor (int dim_index = 0; dim_index < d; ++dim_index)\n\t\t\tgsl_vector_set(gsl_mu, dim_index, arg_mu->NumericAtIndex_NOCAST(dim_index, nullptr));\n\t\t\n\t\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\t{\n\t\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\t{\n\t\t\t\tdouble value = arg_sigma->NumericAtIndex_NOCAST(row_index + col_index * d, nullptr);\n\t\t\t\t\n\t\t\t\tif (std::isnan(value))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() does not allow sigma to contain NANs.\" << EidosTerminate(nullptr);\t// oddly, GSL does not raise an error on this!\n\t\t\t\t\n\t\t\t\tgsl_matrix_set(gsl_Sigma, row_index, col_index, value);\n\t\t\t}\n\t\t}\n\t\t\n\t\tgsl_matrix_memcpy(gsl_L, gsl_Sigma);\n\t}\n\tcatch (...) {\n\t\tgsl_vector_free(gsl_mu);\n\t\tgsl_matrix_free(gsl_Sigma);\n\t\tgsl_matrix_free(gsl_L);\n\t\tgsl_vector_free(gsl_x);\n\t\tgsl_vector_free(gsl_work);\n\t\tthrow;\n\t}\n\t\n\t// Disable the GSL's default error handler, which calls abort().  Normally we run with that handler,\n\t// which is perhaps a bit risky, but we want to check for all error cases and avert them before we\n\t// ever call into the GSL; having the GSL raise when it encounters an error condition is kind of OK\n\t// because it should never ever happen.  But the GSL calls we will make in this function could hit\n\t// errors unpredictably, if for example it turns out that Sigma is not positive-definite.  So for\n\t// this stretch of code we disable the default handler and check for errors returned from the GSL.\n\tgsl_error_handler_t *old_handler = gsl_set_error_handler_off();\n\tint gsl_err;\n\t\n\t// Do the draws, which involves a preliminary step of doing a Cholesky decomposition\n\tgsl_err = gsl_linalg_cholesky_decomp1(gsl_L);\n\t\n\tif (gsl_err)\n\t{\n\t\tgsl_set_error_handler(old_handler);\n\t\t\n\t\t// Clean up GSL stuff\n\t\tgsl_vector_free(gsl_mu);\n\t\tgsl_matrix_free(gsl_Sigma);\n\t\tgsl_matrix_free(gsl_L);\n\t\tgsl_vector_free(gsl_x);\n\t\tgsl_vector_free(gsl_work);\n\t\t\n\t\tif (gsl_err == GSL_EDOM)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): function dmvnorm() requires that sigma, the variance-covariance matrix, be positive-definite.\" << EidosTerminate(nullptr);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): (internal error) an unknown error with code \" << gsl_err << \" occurred inside the GNU Scientific Library's gsl_linalg_cholesky_decomp1() function.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tconst double *float_data = arg_x->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int64_t value_index = 0; value_index < num_quantiles; ++value_index)\n\t{\n\t\tdouble gsl_result;\n\t\t\n\t\tfor (int dim_index = 0; dim_index < d; ++dim_index)\n\t\t\tgsl_vector_set(gsl_x, dim_index, *(float_data + value_index + dim_index * num_quantiles));\n\t\t\n\t\tgsl_err = gsl_ran_multivariate_gaussian_pdf (gsl_x, gsl_mu, gsl_L, &gsl_result, gsl_work);\n\t\t\n\t\tif (gsl_err)\n\t\t{\n\t\t\tgsl_set_error_handler(old_handler);\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dmvnorm): (internal error) an unknown error with code \" << gsl_err << \" occurred inside the GNU Scientific Library's gsl_ran_multivariate_gaussian_pdf() function.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tfloat_result->set_float_no_check(gsl_result, value_index);\n\t}\n\t\n\t// Clean up GSL stuff\n\tgsl_vector_free(gsl_mu);\n\tgsl_matrix_free(gsl_Sigma);\n\tgsl_matrix_free(gsl_L);\n\tgsl_vector_free(gsl_x);\n\tgsl_vector_free(gsl_work);\n\t\n\tgsl_set_error_handler(old_handler);\n\t\n\treturn result_SP;\n}\n\n//\t(float)dnorm(float x, [numeric mean = 0], [numeric sd = 1])\nEidosValue_SP Eidos_ExecuteFunction_dnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_quantile = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\tint num_quantiles = arg_quantile->Count();\n\tint arg_mu_count = arg_mu->Count();\n\tint arg_sigma_count = arg_sigma->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\tbool sigma_singleton = (arg_sigma_count == 1);\n\t\n\tif (!mu_singleton && (arg_mu_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dnorm): function dnorm() requires mean to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\tif (!sigma_singleton && (arg_sigma_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dnorm): function dnorm() requires sd to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\t\n\tdouble mu0 = (arg_mu_count ? arg_mu->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble sigma0 = (arg_sigma_count ? arg_sigma->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (mu_singleton && sigma_singleton)\n\t{\n\t\t// Note that this case, EIDOS_OMPMIN_DNORM_1, running SINGLE-threaded, got about 20% slower from SLiM 4.0.1 to now.  I have looked into it\n\t\t// and have no idea why.  My best hypothesis is that it is due to a change in the compiler/toolchain treatment of this code.  The only code\n\t\t// change here is the addition of the omp pragma, and removing that makes no difference.  A profile shows nothing, reverting the whole\n\t\t// function shows nothing, doing an Archive build shows nothing.  Total mystery, without delving into the assembly code.  Such is life.\n\t\tif (sigma0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dnorm): function dnorm() requires sd > 0.0 (\" << EidosStringForFloat(sigma0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_DNORM_1);\n#pragma omp parallel for schedule(static) default(none) shared(num_quantiles) firstprivate(float_data, float_result, mu0, sigma0) if(num_quantiles >= EIDOS_OMPMIN_DNORM_1) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gaussian_pdf(float_data[value_index] - mu0, sigma0), value_index);\n#else\n\t\t// SIMD-optimized version: batch the exp() calls\n\t\tdouble norm = 1.0 / (std::sqrt(2.0 * M_PI) * sigma0);\n\t\tdouble inv_2var = -1.0 / (2.0 * sigma0 * sigma0);\n\t\tdouble *result_data = float_result->data_mutable();\n\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble diff = float_data[value_index] - mu0;\n\t\t\tresult_data[value_index] = diff * diff * inv_2var;\n\t\t}\n\t\tEidos_SIMD::exp_float64(result_data, result_data, num_quantiles);\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tresult_data[value_index] *= norm;\n#endif\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tbool saw_error = false;\n\t\t\n#ifdef _OPENMP\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_DNORM_2);\n#pragma omp parallel for schedule(static) default(none) shared(num_quantiles) firstprivate(float_data, float_result, mu_singleton, sigma_singleton, mu0, sigma0, arg_mu, arg_sigma) reduction(||: saw_error) if(num_quantiles >= EIDOS_OMPMIN_DNORM_2) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble mu = (mu_singleton ? mu0 : arg_mu->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble sigma = (sigma_singleton ? sigma0 : arg_sigma->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (sigma <= 0.0)\n\t\t\t{\n\t\t\t\tsaw_error = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gaussian_pdf(float_data[value_index] - mu, sigma), value_index);\n\t\t}\n#else\n\t\t// SIMD-optimized version: batch the exp() calls\n\t\tdouble *result_data = float_result->data_mutable();\n\t\tstd::vector<double> norms(num_quantiles);\n\n\t\t// Pass 1: compute exponents and norms, check for errors\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble mu = (mu_singleton ? mu0 : arg_mu->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble sigma = (sigma_singleton ? sigma0 : arg_sigma->NumericAtIndex_NOCAST(value_index, nullptr));\n\n\t\t\tif (sigma <= 0.0)\n\t\t\t{\n\t\t\t\tsaw_error = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdouble diff = float_data[value_index] - mu;\n\t\t\tresult_data[value_index] = -diff * diff / (2.0 * sigma * sigma);\n\t\t\tnorms[value_index] = 1.0 / (std::sqrt(2.0 * M_PI) * sigma);\n\t\t}\n\n\t\t// Pass 2: batch exp() - SIMD accelerated\n\t\tEidos_SIMD::exp_float64(result_data, result_data, num_quantiles);\n\n\t\t// Pass 3: scale by per-element norms\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tresult_data[value_index] *= norms[value_index];\n#endif\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dnorm): function dnorm() requires sd > 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)qnorm(float p, [numeric mean = 0], [numeric sd = 1])\nEidosValue_SP Eidos_ExecuteFunction_qnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_prob = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\tint64_t num_probs = arg_prob->Count();\n\tint arg_mu_count = arg_mu->Count();\n\tint arg_sigma_count = arg_sigma->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\tbool sigma_singleton = (arg_sigma_count == 1);\n\t\n\tif (!mu_singleton && (arg_mu_count != num_probs))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires mean to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\tif (!sigma_singleton && (arg_sigma_count != num_probs))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires sd to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\t\n\tdouble mu0 = (arg_mu_count ? arg_mu->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble sigma0 = (arg_sigma_count ? arg_sigma->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (mu_singleton && sigma_singleton)\n\t{\n\t\tif (sigma0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires sd > 0.0 (\" << EidosStringForFloat(sigma0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *float_data = arg_prob->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_probs);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t value_index = 0; value_index < num_probs; ++value_index) {\n\t\t\tif (float_data[value_index] < 0.0 || float_data[value_index] > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires 0.0 <= p <= 1.0 (\" << EidosStringForFloat(float_data[value_index]) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tfloat_result->set_float_no_check(gsl_cdf_gaussian_Pinv(float_data[value_index], sigma0) + mu0, value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_prob->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_probs);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_probs; ++value_index)\n\t\t{\n\t\t\tdouble mu = (mu_singleton ? mu0 : arg_mu->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble sigma = (sigma_singleton ? sigma0 : arg_sigma->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tif (float_data[value_index] < 0.0 || float_data[value_index] > 1.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires 0.0 <= p <= 1.0 (\" << EidosStringForFloat(float_data[value_index]) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (sigma <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_qnorm): function qnorm() requires sd > 0.0 (\" << EidosStringForFloat(sigma) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_cdf_gaussian_Pinv(float_data[value_index], sigma) + mu, value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n\n//\t(float)pnorm(float q, [numeric mean = 0], [numeric sd = 1])\nEidosValue_SP Eidos_ExecuteFunction_pnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_quantile = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\tint64_t num_quantiles = arg_quantile->Count();\n\tint arg_mu_count = arg_mu->Count();\n\tint arg_sigma_count = arg_sigma->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\tbool sigma_singleton = (arg_sigma_count == 1);\n\t\n\tif (!mu_singleton && (arg_mu_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pnorm): function pnorm() requires mean to be of length 1 or equal in length to q.\" << EidosTerminate(nullptr);\n\tif (!sigma_singleton && (arg_sigma_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pnorm): function pnorm() requires sd to be of length 1 or equal in length to q.\" << EidosTerminate(nullptr);\n\t\n\tdouble mu0 = (arg_mu_count ? arg_mu->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble sigma0 = (arg_sigma_count ? arg_sigma->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (mu_singleton && sigma_singleton)\n\t{\n\t\tif (sigma0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pnorm): function pnorm() requires sd > 0.0 (\" << EidosStringForFloat(sigma0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tfloat_result->set_float_no_check(gsl_cdf_gaussian_P(float_data[value_index] - mu0, sigma0), value_index);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble mu = (mu_singleton ? mu0 : arg_mu->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble sigma = (sigma_singleton ? sigma0 : arg_sigma->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (sigma <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pnorm): function pnorm() requires sd > 0.0 (\" << EidosStringForFloat(sigma) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_cdf_gaussian_P(float_data[value_index] - mu, sigma), value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)dbeta(float x, numeric alpha, numeric beta)\nEidosValue_SP Eidos_ExecuteFunction_dbeta(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_quantile = p_arguments[0].get();\n\tEidosValue *arg_alpha = p_arguments[1].get();\n\tEidosValue *arg_beta = p_arguments[2].get();\n\tint num_quantiles = arg_quantile->Count();\n\tint arg_alpha_count = arg_alpha->Count();\n\tint arg_beta_count = arg_beta->Count();\n\tbool alpha_singleton = (arg_alpha_count == 1);\n\tbool beta_singleton = (arg_beta_count == 1);\n\t\n\tif (!alpha_singleton && (arg_alpha_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires alpha to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\tif (!beta_singleton && (arg_beta_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires beta to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\t\n\tdouble alpha0 = (arg_alpha_count ? arg_alpha->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble beta0 = (arg_beta_count ? arg_beta->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\t\n\tif (alpha_singleton && beta_singleton)\n\t{\n\t\tif (!(alpha0 > 0.0))\t// true for NaN\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires alpha > 0.0 (\" << EidosStringForFloat(alpha0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif (!(beta0 > 0.0))\t\t// true for NaN\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires beta > 0.0 (\" << EidosStringForFloat(beta0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_beta_pdf(float_data[value_index], alpha0, beta0), value_index);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble alpha = (alpha_singleton ? alpha0 : arg_alpha->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble beta = (beta_singleton ? beta0 : arg_beta->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (!(alpha > 0.0))\t\t// true for NaN\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires alpha > 0.0 (\" << EidosStringForFloat(alpha) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif (!(beta > 0.0))\t\t// true for NaN\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dbeta): function dbeta() requires beta > 0.0 (\" << EidosStringForFloat(beta) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_beta_pdf(float_data[value_index], alpha, beta), value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rbeta(integer$ n, numeric alpha, numeric beta)\nEidosValue_SP Eidos_ExecuteFunction_rbeta(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_alpha = p_arguments[1].get();\n\tEidosValue *arg_beta = p_arguments[2].get();\n\tint arg_alpha_count = arg_alpha->Count();\n\tint arg_beta_count = arg_beta->Count();\n\tbool alpha_singleton = (arg_alpha_count == 1);\n\tbool beta_singleton = (arg_beta_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!alpha_singleton && (arg_alpha_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires alpha to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!beta_singleton && (arg_beta_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires beta to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble alpha0 = (arg_alpha_count ? arg_alpha->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble beta0 = (arg_beta_count ? arg_beta->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (alpha_singleton && beta_singleton)\n\t{\n\t\tif (alpha0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires alpha > 0.0 (\" << EidosStringForFloat(alpha0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif (beta0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires beta > 0.0 (\" << EidosStringForFloat(beta0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_beta(rng_gsl, alpha0, beta0), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble alpha = (alpha_singleton ? alpha0 : arg_alpha->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble beta = (beta_singleton ? beta0 : arg_beta->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (alpha <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires alpha > 0.0 (\" << EidosStringForFloat(alpha) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif (beta <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbeta): function rbeta() requires beta > 0.0 (\" << EidosStringForFloat(beta) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_beta(rng_gsl, alpha, beta), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rbinom(integer$ n, integer size, float prob)\nEidosValue_SP Eidos_ExecuteFunction_rbinom(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_size = p_arguments[1].get();\n\tEidosValue *arg_prob = p_arguments[2].get();\n\tint arg_size_count = arg_size->Count();\n\tint arg_prob_count = arg_prob->Count();\n\tbool size_singleton = (arg_size_count == 1);\n\tbool prob_singleton = (arg_prob_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!size_singleton && (arg_size_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires size to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!prob_singleton && (arg_prob_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires prob to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *size_data = arg_size->IntData();\n\tint size0 = (int)size_data[0];\n\t\n\tconst double *prob_data = arg_prob->FloatData();\n\tdouble probability0 = prob_data[0];\n\t\n\tif (size_singleton && prob_singleton)\n\t{\n\t\tif (size0 < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires size >= 0 (\" << size0 << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif ((probability0 < 0.0) || (probability0 > 1.0) || std::isnan(probability0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires probability in [0.0, 1.0] (\" << EidosStringForFloat(probability0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif ((probability0 == 0.5) && (size0 == 1))\n\t\t{\n\t\t\t// Special-case a probability of 0.5 since we can use Eidos_RandomBool() for it\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RBINOM_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result) if(num_draws >= EIDOS_OMPMIN_RBINOM_1) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t\tint_result->set_int_no_check((int64_t)Eidos_RandomBool(rng_state), draw_index);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RBINOM_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, probability0, size0) if(num_draws >= EIDOS_OMPMIN_RBINOM_2) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t\tint_result->set_int_no_check(gsl_ran_binomial(rng_gsl, probability0, size0), draw_index);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tbool saw_error1 = false, saw_error2 = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RBINOM_3);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, size_singleton, prob_singleton, size0, probability0, size_data, prob_data) reduction(||: saw_error1) reduction(||: saw_error2) if(num_draws >= EIDOS_OMPMIN_RBINOM_3) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tint size = (size_singleton ? size0 : (int)size_data[draw_index]);\n\t\t\t\tdouble probability = (prob_singleton ? probability0 : prob_data[draw_index]);\n\t\t\t\t\n\t\t\t\tif (size < 0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error1 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif ((probability < 0.0) || (probability > 1.0) || std::isnan(probability))\n\t\t\t\t{\n\t\t\t\t\tsaw_error2 = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(gsl_ran_binomial(rng_gsl, probability, size), draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires size >= 0.\" << EidosTerminate(nullptr);\n\t\tif (saw_error2)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbinom): function rbinom() requires probability in [0.0, 1.0].\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rcauchy(integer$ n, [numeric location = 0], [numeric scale = 1])\nEidosValue_SP Eidos_ExecuteFunction_rcauchy(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_location = p_arguments[1].get();\n\tEidosValue *arg_scale = p_arguments[2].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_location_count = arg_location->Count();\n\tint arg_scale_count = arg_scale->Count();\n\tbool location_singleton = (arg_location_count == 1);\n\tbool scale_singleton = (arg_scale_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rcauchy): function rcauchy() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!location_singleton && (arg_location_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rcauchy): function rcauchy() requires location to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!scale_singleton && (arg_scale_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rcauchy): function rcauchy() requires scale to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble location0 = (arg_location_count ? arg_location->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble scale0 = (arg_scale_count ? arg_scale->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (location_singleton && scale_singleton)\n\t{\n\t\tif (scale0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rcauchy): function rcauchy() requires scale > 0.0 (\" << EidosStringForFloat(scale0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_cauchy(rng_gsl, scale0) + location0, draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble location = (location_singleton ? location0 : arg_location->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble scale = (scale_singleton ? scale0 : arg_scale->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (scale <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rcauchy): function rcauchy() requires scale > 0.0 (\" << EidosStringForFloat(scale) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_cauchy(rng_gsl, scale) + location, draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rdirichlet(integer$ n, numeric alpha)\nEidosValue_SP Eidos_ExecuteFunction_rdirichlet(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *alpha_value = p_arguments[1].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint alpha_count = alpha_value->Count();\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdirichlet): function rdirichlet() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\t// alpha\n\tif (alpha_value->DimensionCount() > 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdirichlet): function rdirichlet() requires alpha to be a vector (not a matrix or array).\" << EidosTerminate(nullptr);\n\t\n\tif ((alpha_count < 2) || (alpha_count > 1000000))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdirichlet): function rdirichlet() requires alpha to have length >= 2 (and <= 1e6).\" << EidosTerminate(nullptr);\n\t\n\t// check for zero draws; we don't support zero-length dimensions in Eidos\n\tif (num_draws == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\t// prepare input and output vector\n\tdouble *alpha = (double *)malloc(alpha_count * sizeof(double));\t\t// incoming alpha values\n\tdouble *theta = (double *)malloc(alpha_count * sizeof(double));\t\t// outgoing theta values\n\t\n\tfor (int alpha_index = 0; alpha_index < alpha_count; ++alpha_index)\n\t{\n\t\tdouble one_alpha = alpha_value->FloatAtIndex_CAST(alpha_index, nullptr);\n\t\t\n\t\tif (!std::isfinite(one_alpha) || (one_alpha <= 0.0))\n\t\t{\n\t\t\tfree(alpha);\n\t\t\tfree(theta);\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdirichlet): function rdirichlet() requires every alpha value to be positive and finite.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\talpha[alpha_index] = one_alpha;\n\t}\n\t\n\t// generate draws\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws * alpha_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\t\n\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t{\n\t\tgsl_ran_dirichlet(rng_gsl, alpha_count, alpha, theta);\n\t\t\n\t\t// we need to transcribe the theta values into a row of float_result_data\n\t\tfor (int theta_index = 0; theta_index < alpha_count; ++theta_index)\n\t\t\tfloat_result_data[draw_index + theta_index * num_draws] = theta[theta_index];\n\t}\n\t\n\t// Set the dimensions of the result; we want one row per draw\n\tint64_t dim[2] = {num_draws, alpha_count};\n\t\n\tfloat_result->SetDimensions(2, dim);\n\t\n\tfree(alpha);\n\tfree(theta);\n\t\n\treturn EidosValue_SP(float_result);\n}\n\n//\t(integer)rdunif(integer$ n, [integer min = 0], [integer max = 1])\nEidosValue_SP Eidos_ExecuteFunction_rdunif(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_min = p_arguments[1].get();\n\tEidosValue *arg_max = p_arguments[2].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_min_count = arg_min->Count();\n\tint arg_max_count = arg_max->Count();\n\tbool min_singleton = (arg_min_count == 1);\n\tbool max_singleton = (arg_max_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif): function rdunif() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!min_singleton && (arg_min_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif): function rdunif() requires min to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!max_singleton && (arg_max_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif): function rdunif() requires max to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *min_data = arg_min->IntData();\n\tint64_t min_value0 = (arg_min_count ? min_data[0] : 0);\n\t\n\tconst int64_t *max_data = arg_max->IntData();\n\tint64_t max_value0 = (arg_max_count ? max_data[0] : 1);\n\t\n\tif (min_singleton && max_singleton)\n\t{\n\t\tif ((max_value0 < min_value0) || (max_value0 - min_value0 >= INT64_MAX))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif): function rdunif() requires min <= max and max - min < INT64_MAX.\" << EidosTerminate(nullptr);\n\t\t\n\t\tuint64_t count0 = (max_value0 - min_value0) + 1;\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (count0 == 2)\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RDUNIF_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, min_value0) if(num_draws >= EIDOS_OMPMIN_RDUNIF_1) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t\tint_result->set_int_no_check(Eidos_RandomBool(rng_state) + min_value0, draw_index);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RDUNIF_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, min_value0, count0) if(num_draws >= EIDOS_OMPMIN_RDUNIF_2) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t\tint_result->set_int_no_check(Eidos_rng_interval_uint64(rng_64, count0) + min_value0, draw_index);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tbool saw_error = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RDUNIF_3);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, min_singleton, max_singleton, min_value0, max_value0, min_data, max_data) reduction(||: saw_error) if(num_draws >= EIDOS_OMPMIN_RDUNIF_3) num_threads(thread_count)\n\t\t{\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tint64_t min_value = (min_singleton ? min_value0 : min_data[draw_index]);\n\t\t\t\tint64_t max_value = (max_singleton ? max_value0 : max_data[draw_index]);\n\t\t\t\t\n\t\t\t\tif ((max_value < min_value) || (max_value - min_value >= INT64_MAX))\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint64_t count = (max_value - min_value) + 1;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(Eidos_rng_interval_uint64(rng_64, count) + min_value, draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif): function rdunif() requires min <= max and max - min < INT64_MAX.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rdunif64(integer$ n)\nEidosValue_SP Eidos_ExecuteFunction_rdunif64(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rdunif64): function rdunif64() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\n\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t{\n\t\tint64_t draw = Eidos_rng_uniform_int64(rng_64);\n\t\t\n\t\tint_result->set_int_no_check(draw, draw_index);\n\t}\n\t\n\treturn EidosValue_SP(int_result);\n}\n\n//\t(float)dexp(float x, [numeric mu = 1])\nEidosValue_SP Eidos_ExecuteFunction_dexp(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_quantile = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tint num_quantiles = arg_quantile->Count();\n\tint arg_mu_count = arg_mu->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\t\n\tif (!mu_singleton && (arg_mu_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dexp): function dexp() requires mu to be of length 1 or equal in length to x.\" << EidosTerminate(nullptr);\n\t\n\tif (mu_singleton)\n\t{\n\t\tdouble mu0 = arg_mu->NumericAtIndex_NOCAST(0, nullptr);\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_exponential_pdf(float_data[value_index], mu0), value_index);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble mu = arg_mu->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_exponential_pdf(float_data[value_index], mu), value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rexp(integer$ n, [numeric mu = 1])\nEidosValue_SP Eidos_ExecuteFunction_rexp(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_mu_count = arg_mu->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rexp): function rexp() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!mu_singleton && (arg_mu_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rexp): function rexp() requires mu to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tif (mu_singleton)\n\t{\n\t\tdouble mu0 = arg_mu->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (mu0 < 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rexp): function rexp() requires mu >= 0.0 (\" << EidosStringForFloat(mu0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_REXP_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, mu0) if(num_draws >= EIDOS_OMPMIN_REXP_1) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_exponential(rng_gsl, mu0), draw_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\tbool saw_error = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_REXP_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, arg_mu) reduction(||: saw_error) if(num_draws >= EIDOS_OMPMIN_REXP_2) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble mu = arg_mu->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tif (mu < 0.0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_exponential(rng_gsl, mu), draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rexp): function rexp() requires mu >= 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rf(integer$ n, numeric d1, numeric d2)\nEidosValue_SP Eidos_ExecuteFunction_rf(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_d1 = p_arguments[1].get();\n\tEidosValue *arg_d2 = p_arguments[2].get();\n\tint arg_d1_count = arg_d1->Count();\n\tint arg_d2_count = arg_d2->Count();\n\tbool d1_singleton = (arg_d1_count == 1);\n\tbool d2_singleton = (arg_d2_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!d1_singleton && (arg_d1_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d1 to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!d2_singleton && (arg_d2_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d2 to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble d1_0 = (arg_d1_count ? arg_d1->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble d2_0 = (arg_d2_count ? arg_d2->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (d1_singleton && d2_singleton)\n\t{\n\t\tif (d1_0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d1 > 0.0 (\" << EidosStringForFloat(d1_0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif (d2_0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d2 > 0.0 (\" << EidosStringForFloat(d2_0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_fdist(rng_gsl, d1_0, d2_0), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble d1 = (d1_singleton ? d1_0 : arg_d1->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble d2 = (d2_singleton ? d2_0 : arg_d2->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (d1 <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d1 > 0.0 (\" << EidosStringForFloat(d1) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif (d2 <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rf): function rf() requires d2 > 0.0 (\" << EidosStringForFloat(d2) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_fdist(rng_gsl, d1, d2), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)dgamma(float x, numeric mean, numeric shape)\nEidosValue_SP Eidos_ExecuteFunction_dgamma(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_quantile = p_arguments[0].get();\n\tEidosValue *arg_mean = p_arguments[1].get();\n\tEidosValue *arg_shape = p_arguments[2].get();\n\tint num_quantiles = arg_quantile->Count();\n\tint arg_mean_count = arg_mean->Count();\n\tint arg_shape_count = arg_shape->Count();\n\tbool mean_singleton = (arg_mean_count == 1);\n\tbool shape_singleton = (arg_shape_count == 1);\n\t\n\tif (!mean_singleton && (arg_mean_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dgamma): function dgamma() requires mean to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!shape_singleton && (arg_shape_count != num_quantiles))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dgamma): function dgamma() requires shape to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble mean0 = (arg_mean_count ? arg_mean->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\tdouble shape0 = (arg_shape_count ? arg_shape->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\t\n\tif (mean_singleton && shape_singleton)\n\t{\n\t\tif (!(shape0 > 0.0))\t// true for NaN\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dgamma): function dgamma() requires shape > 0.0 (\" << EidosStringForFloat(shape0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tdouble scale = mean0 / shape0;\n\t\t\n\t\tfor (int64_t value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gamma_pdf(float_data[value_index], shape0, scale), value_index);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = arg_quantile->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_quantiles);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < num_quantiles; ++value_index)\n\t\t{\n\t\t\tdouble mean = (mean_singleton ? mean0 : arg_mean->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\tdouble shape = (shape_singleton ? shape0 : arg_shape->NumericAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (!(shape > 0.0))\t\t// true for NaN\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_dgamma): function dgamma() requires shape > 0.0 (\" << EidosStringForFloat(shape) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gamma_pdf(float_data[value_index], shape, mean / shape), value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rgamma(integer$ n, numeric mean, numeric shape)\nEidosValue_SP Eidos_ExecuteFunction_rgamma(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_mean = p_arguments[1].get();\n\tEidosValue *arg_shape = p_arguments[2].get();\n\tint arg_mean_count = arg_mean->Count();\n\tint arg_shape_count = arg_shape->Count();\n\tbool mean_singleton = (arg_mean_count == 1);\n\tbool shape_singleton = (arg_shape_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgamma): function rgamma() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!mean_singleton && (arg_mean_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgamma): function rgamma() requires mean to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!shape_singleton && (arg_shape_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgamma): function rgamma() requires shape to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble mean0 = (arg_mean_count ? arg_mean->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\tdouble shape0 = (arg_shape_count ? arg_shape->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (mean_singleton && shape_singleton)\n\t{\n\t\tif (shape0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgamma): function rgamma() requires shape > 0.0 (\" << EidosStringForFloat(shape0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tdouble scale = mean0 / shape0;\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gamma(rng_gsl, shape0, scale), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble mean = (mean_singleton ? mean0 : arg_mean->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble shape = (shape_singleton ? shape0 : arg_shape->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (shape <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgamma): function rgamma() requires shape > 0.0 (\" << EidosStringForFloat(shape) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_gamma(rng_gsl, shape, mean / shape), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rgeom(integer$ n, float p)\nEidosValue_SP Eidos_ExecuteFunction_rgeom(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_p = p_arguments[1].get();\n\tint arg_p_count = arg_p->Count();\n\tbool p_singleton = (arg_p_count == 1);\n\tconst double *p_data = arg_p->FloatData();\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgeom): function rgeom() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!p_singleton && (arg_p_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgeom): function rgeom() requires p to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\t// Note that there are two different definitions of the geometric distribution (see https://en.wikipedia.org/wiki/Geometric_distribution).\n\t// We follow R in using the definition that is supported on the set {0, 1, 2, 3, ...}.  Unfortunately, gsl_ran_geometric() uses the other\n\t// definition, which is supported on the set {1, 2, 3, ...}.  The GSL's version does not allow p==1.0, so we have to special-case that.\n\t// Otherwise, the result of our definition is equal to the result from the GSL's definition minus 1; the GSL uses the \"shifted geometric\".\n\t\n\tif (p_singleton)\n\t{\n\t\tdouble p0 = p_data[0];\n\t\t\n\t\tif ((p0 <= 0.0) || (p0 > 1.0) || std::isnan(p0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgeom): function rgeom() requires 0.0 < p <= 1.0 (\" << EidosStringForFloat(p0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (p0 == 1.0)\t// special-case p==1.0\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tint_result->set_int_no_check(0, draw_index);\n\t\telse\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tint_result->set_int_no_check(gsl_ran_geometric(rng_gsl, p0) - 1, draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble p = p_data[draw_index];\n\t\t\t\n\t\t\tif ((p <= 0.0) || (p >= 1.0) || std::isnan(p))\n\t\t\t{\n\t\t\t\tif (p == 1.0)\t// special-case p==1.0; inside here to avoid an extra comparison per loop in the standard case\n\t\t\t\t{\n\t\t\t\t\tint_result->set_int_no_check(0, draw_index);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rgeom): function rgeom() requires 0.0 < p <= 1.0 (\" << EidosStringForFloat(p) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tint_result->set_int_no_check(gsl_ran_geometric(rng_gsl, p) - 1, draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rlaplace(integer$ n, [numeric b = 1])\nEidosValue_SP Eidos_ExecuteFunction_rlaplace(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_b = p_arguments[1].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_b_count = arg_b->Count();\n\tbool b_singleton = (arg_b_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlaplace): function rlaplace() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!b_singleton && (arg_b_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlaplace): function rlaplace() requires b to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tif (b_singleton)\n\t{\n\t\tdouble b0 = arg_b->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (b0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlaplace): function rlaplace() requires b > 0.0 (\" << EidosStringForFloat(b0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\t// FIXME PARALLELIZE\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_laplace(rng_gsl, b0), draw_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\tbool saw_error = false;\n\t\t\n\t\t// FIXME PARALLELIZE\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble b = arg_b->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tif (b <= 0.0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_laplace(rng_gsl, b), draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlaplace): function rlaplace() requires b > 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rlnorm(integer$ n, [numeric meanlog = 0], [numeric sdlog = 1])\nEidosValue_SP Eidos_ExecuteFunction_rlnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_meanlog = p_arguments[1].get();\n\tEidosValue *arg_sdlog = p_arguments[2].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_meanlog_count = arg_meanlog->Count();\n\tint arg_sdlog_count = arg_sdlog->Count();\n\tbool meanlog_singleton = (arg_meanlog_count == 1);\n\tbool sdlog_singleton = (arg_sdlog_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlnorm): function rlnorm() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!meanlog_singleton && (arg_meanlog_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlnorm): function rlnorm() requires meanlog to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!sdlog_singleton && (arg_sdlog_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlnorm): function rlnorm() requires sdlog to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble meanlog0 = (arg_meanlog_count ? arg_meanlog->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble sdlog0 = (arg_sdlog_count ? arg_sdlog->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (sdlog_singleton && (sdlog0 < 0.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlnorm): function rlnorm() requires sd >= 0.0 (\" << EidosStringForFloat(sdlog0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (meanlog_singleton && sdlog_singleton)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_lognormal(rng_gsl, meanlog0, sdlog0), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble meanlog = (meanlog_singleton ? meanlog0 : arg_meanlog->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble sdlog = (sdlog_singleton ? sdlog0 : arg_sdlog->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (sdlog < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rlnorm): function rlnorm() requires sd >= 0.0 (\" << EidosStringForFloat(sdlog0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_lognormal(rng_gsl, meanlog, sdlog), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n// (integer)rmultinom(integer$ n, integer$ size, numeric prob)\nEidosValue_SP Eidos_ExecuteFunction_rmultinom(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_n = p_arguments[0].get();\n\tEidosValue *arg_size = p_arguments[1].get();\n\tEidosValue *arg_prob = p_arguments[2].get();\n\t\n\t// get and bounds-check the number of draws we will do\n\tint64_t num_draws = arg_n->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (num_draws < 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires n to be greater than or equal to 1 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\t// get and check the size of each multinomial draw\n\t// the upper limit is because the GSL requires size to be cast down to unsigned int\n\tint64_t size = arg_size->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (size < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires size to be greater than or equal to 0.\" << EidosTerminate(nullptr);\n\tif (size > 1000000000)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires size to be less than or equal to 1000000000.\" << EidosTerminate(nullptr);\n\t\n\t// get and check the number of \"boxes\", i.e., the number of probabilities supplied\n\t// the upper limit is arbitrary, but it seems wise to have a limit\n\tint k = arg_prob->Count();\n\t\n\tif (k <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires prob to be of length 1 or greater.\" << EidosTerminate(nullptr);\n\tif (k > 1000000)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires prob to be of length 1000000 or less.\" << EidosTerminate(nullptr);\n\t\n\t// fetch the probability vector into a local static buffer, checking as we go; note the gsl normalizes prob_vec for us\n\tdouble prob_sum = 0.0;\n\tstatic std::vector<double> prob_vec;\n\tprob_vec.reserve(k);\n\tprob_vec.resize(0);\n\t\n\tfor (int prob_index = 0; prob_index < k; ++prob_index)\n\t{\n\t\tdouble prob = arg_prob->FloatAtIndex_CAST(prob_index, nullptr);\n\t\t\n\t\tif (prob < 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires all probabilities in prob to be >= 0.0.\" << EidosTerminate(nullptr);\n\t\tif (!std::isfinite(prob))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires all probabilities in prob to be finite (not INF or NAN).\" << EidosTerminate(nullptr);\n\t\t\n\t\tprob_sum += prob;\n\t\tprob_vec.push_back(prob);\n\t}\n\t\n\tif (prob_sum == 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() requires the sum of prob to be greater than zero; there must be at least one non-zero probability.\" << EidosTerminate(nullptr);\n\tif (!std::isfinite(prob_sum))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmultinom): function rmultinom() could not compute the multinomial draws because the sum of prob overflowed to infinity.\" << EidosTerminate(nullptr);\n\t\n\tif (k == 1)\n\t{\n\t\t// If k == 1, every object goes into the same single box, so the result is trivial\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tint_result->set_int_no_check(size, draw_index);\n\t}\n\telse if (size == 0)\n\t{\n\t\t// if size == 0, zero objects are drawn in each multinomial trial, so the result is trivial\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve((int)num_draws * k);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfor (int k_index = 0; k_index < k; ++k_index)\n\t\t\t\tint_result->push_int_no_check(0);\n\t}\n\telse\n\t{\n\t\t// the main case, where we need to call gsl_ran_multinomial() to do the work\n\t\t// we put the drawn values into a local static buffer, and then copy them into the Eidos result\n\t\tstatic std::vector<unsigned int> draw_vec;\n\t\tdraw_vec.resize(k);\n\t\t\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve((int)num_draws * k);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tgsl_ran_multinomial(rng_gsl, k, (unsigned int)size, prob_vec.data(), draw_vec.data());\n\t\t\t\n\t\t\tfor (int k_index = 0; k_index < k; ++k_index)\n\t\t\t\tint_result->push_int_no_check(draw_vec[k_index]);\n\t\t}\n\t}\n\t\n\tint64_t dim_buffer[2] = {k, num_draws};\n\tresult_SP->SetDimensions(2, dim_buffer);\n\t\n\treturn result_SP;\n}\n\n// (float)rmvnorm(integer$ n, numeric mu, numeric sigma)\nEidosValue_SP Eidos_ExecuteFunction_rmvnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *arg_n = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\tint64_t num_draws = arg_n->IntAtIndex_NOCAST(0, nullptr);\n\tint mu_count = arg_mu->Count();\n\tint mu_dimcount = arg_mu->DimensionCount();\n\tint sigma_dimcount = arg_sigma->DimensionCount();\n\tconst int64_t *sigma_dims = arg_sigma->Dimensions();\n\tint d = mu_count;\n\t\n\tif (num_draws < 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() requires n to be greater than or equal to 1 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif ((mu_dimcount != 1) || (mu_count < 2))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() requires mu to be a plain vector of length k, where k is the number of dimensions for the multivariate Gaussian function (k must be >= 2).\" << EidosTerminate(nullptr);\n\tif (sigma_dimcount != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() requires sigma to be a matrix.\" << EidosTerminate(nullptr);\n\tif ((sigma_dims[0] != d) || (sigma_dims[1] != d))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() requires sigma to be a k x k matrix, where k is the number of dimensions for the multivariate Gaussian function (k must be >= 2).\" << EidosTerminate(nullptr);\n\t\n\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\tif (std::isnan(arg_sigma->NumericAtIndex_NOCAST(row_index + col_index * d, nullptr)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() does not allow sigma to contain NANs.\" << EidosTerminate(nullptr);\t// oddly, GSL does not raise an error on this!\n\t\n\t// Set up the GSL vectors\n\tgsl_vector *gsl_mu = gsl_vector_calloc(d);\n\tgsl_matrix *gsl_Sigma = gsl_matrix_calloc(d, d);\n\tgsl_matrix *gsl_L = gsl_matrix_calloc(d, d);\n\tgsl_vector *gsl_result = gsl_vector_calloc(d);\n\t\n\tif (!gsl_mu || !gsl_Sigma || !gsl_L || !gsl_result)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tfor (int dim_index = 0; dim_index < d; ++dim_index)\n\t\tgsl_vector_set(gsl_mu, dim_index, arg_mu->NumericAtIndex_NOCAST(dim_index, nullptr));\n\t\n\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\tgsl_matrix_set(gsl_Sigma, row_index, col_index, arg_sigma->NumericAtIndex_NOCAST(row_index + col_index * d, nullptr));\n\t\n\tgsl_matrix_memcpy(gsl_L, gsl_Sigma);\n\t\n\t// Disable the GSL's default error handler, which calls abort().  Normally we run with that handler,\n\t// which is perhaps a bit risky, but we want to check for all error cases and avert them before we\n\t// ever call into the GSL; having the GSL raise when it encounters an error condition is kind of OK\n\t// because it should never ever happen.  But the GSL calls we will make in this function could hit\n\t// errors unpredictably, if for example it turns out that Sigma is not positive-definite.  So for\n\t// this stretch of code we disable the default handler and check for errors returned from the GSL.\n\tgsl_error_handler_t *old_handler = gsl_set_error_handler_off();\n\tint gsl_err;\n\t\n\t// Do the draws, which involves a preliminary step of doing a Cholesky decomposition\n\tgsl_err = gsl_linalg_cholesky_decomp1(gsl_L);\n\t\n\tif (gsl_err)\n\t{\n\t\tgsl_set_error_handler(old_handler);\n\t\t\n\t\t// Clean up GSL stuff\n\t\tgsl_vector_free(gsl_mu);\n\t\tgsl_matrix_free(gsl_Sigma);\n\t\tgsl_matrix_free(gsl_L);\n\t\tgsl_vector_free(gsl_result);\n\t\t\n\t\tif (gsl_err == GSL_EDOM)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): function rmvnorm() requires that sigma, the variance-covariance matrix, be positive-definite.\" << EidosTerminate(nullptr);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): (internal error) an unknown error with code \" << gsl_err << \" occurred inside the GNU Scientific Library's gsl_linalg_cholesky_decomp1() function.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws * d);\n\tresult_SP = EidosValue_SP(float_result);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t{\n\t\tgsl_err = gsl_ran_multivariate_gaussian(rng_gsl, gsl_mu, gsl_L, gsl_result);\n\t\t\n\t\tif (gsl_err)\n\t\t{\n\t\t\tgsl_set_error_handler(old_handler);\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rmvnorm): (internal error) an unknown error with code \" << gsl_err << \" occurred inside the GNU Scientific Library's gsl_ran_multivariate_gaussian() function.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tfor (int dim_index = 0; dim_index < d; ++dim_index)\n\t\t\tfloat_result->set_float_no_check(gsl_vector_get(gsl_result, dim_index), draw_index + dim_index * num_draws);\n\t}\n\t\n\t// Clean up GSL stuff\n\tgsl_vector_free(gsl_mu);\n\tgsl_matrix_free(gsl_Sigma);\n\tgsl_matrix_free(gsl_L);\n\tgsl_vector_free(gsl_result);\n\t\n\tgsl_set_error_handler(old_handler);\n\t\n\t// Set the dimensions of the result; we want one row per draw\n\tint64_t dim[2] = {num_draws, d};\n\t\n\tfloat_result->SetDimensions(2, dim);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rnbinom(integer$ n, numeric size, float prob)\nEidosValue_SP Eidos_ExecuteFunction_rnbinom(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_size = p_arguments[1].get();\n\tEidosValue *arg_prob = p_arguments[2].get();\n\tint arg_size_count = arg_size->Count();\n\tint arg_prob_count = arg_prob->Count();\n\tbool size_singleton = (arg_size_count == 1);\n\tbool prob_singleton = (arg_prob_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!size_singleton && (arg_size_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires size to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!prob_singleton && (arg_prob_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires prob to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble size0 = arg_size->NumericAtIndex_NOCAST(0, nullptr);\n\t\n\tconst double *prob_data = arg_prob->FloatData();\n\tdouble probability0 = prob_data[0];\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (size_singleton && prob_singleton)\n\t{\n\t\tif ((size0 < 0) || std::isnan(size0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires size >= 0 (\" << size0 << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif ((probability0 <= 0.0) || (probability0 > 1.0) || std::isnan(probability0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires probability in (0.0, 1.0] (\" << EidosStringForFloat(probability0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tint_result->set_int_no_check(gsl_ran_negative_binomial(rng_gsl, probability0, size0), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble size = (size_singleton ? size0 : arg_size->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble probability = (prob_singleton ? probability0 : prob_data[draw_index]);\n\t\t\t\n\t\t\tif ((size < 0) || std::isnan(size))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires size >= 0 (\" << size << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif ((probability <= 0.0) || (probability > 1.0) || std::isnan(probability))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnbinom): function rnbinom() requires probability in (0.0, 1.0] (\" << EidosStringForFloat(probability) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(gsl_ran_negative_binomial(rng_gsl, probability, size), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rnorm(integer$ n, [numeric mean = 0], [numeric sd = 1])\nEidosValue_SP Eidos_ExecuteFunction_rnorm(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_mu = p_arguments[1].get();\n\tEidosValue *arg_sigma = p_arguments[2].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_mu_count = arg_mu->Count();\n\tint arg_sigma_count = arg_sigma->Count();\n\tbool mu_singleton = (arg_mu_count == 1);\n\tbool sigma_singleton = (arg_sigma_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnorm): function rnorm() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!mu_singleton && (arg_mu_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnorm): function rnorm() requires mean to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!sigma_singleton && (arg_sigma_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnorm): function rnorm() requires sd to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble mu0 = (arg_mu_count ? arg_mu->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble sigma0 = (arg_sigma_count ? arg_sigma->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (sigma_singleton && (sigma0 < 0.0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnorm): function rnorm() requires sd >= 0.0 (\" << EidosStringForFloat(sigma0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (num_draws == 1)\n\t{\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(gsl_ran_gaussian(rng_gsl, sigma0) + mu0));\n\t}\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tif (mu_singleton && sigma_singleton)\n\t{\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RNORM_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, sigma0, mu0) if(num_draws >= EIDOS_OMPMIN_RNORM_1) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_gaussian(rng_gsl, sigma0) + mu0, draw_index);\n\t\t}\n\t}\n\telse if (sigma_singleton)\t// && !mu_singleton\n\t{\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RNORM_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, sigma0, arg_mu) if(num_draws >= EIDOS_OMPMIN_RNORM_2) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble mu = arg_mu->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_gaussian(rng_gsl, sigma0) + mu, draw_index);\n\t\t\t}\n\t\t}\n\t}\n\telse\t// !sigma_singleton\n\t{\n\t\tbool saw_error = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RNORM_3);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, mu_singleton, mu0, arg_mu, arg_sigma) reduction(||: saw_error) if(num_draws >= EIDOS_OMPMIN_RNORM_3) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble mu = (mu_singleton ? mu0 : arg_mu->NumericAtIndex_NOCAST((int)draw_index, nullptr));\n\t\t\t\tdouble sigma = arg_sigma->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tif (sigma < 0.0)\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfloat_result->set_float_no_check(gsl_ran_gaussian(rng_gsl, sigma) + mu, draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rnorm): function rnorm() requires sd >= 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rpois(integer$ n, numeric lambda)\nEidosValue_SP Eidos_ExecuteFunction_rpois(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_lambda = p_arguments[1].get();\n\tint arg_lambda_count = arg_lambda->Count();\n\tbool lambda_singleton = (arg_lambda_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rpois): function rpois() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!lambda_singleton && (arg_lambda_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rpois): function rpois() requires lambda to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\t// Here we ignore USE_GSL_POISSON and always use the GSL.  This is because we don't know whether lambda (otherwise known as mu) is\n\t// small or large, and because we don't know what level of accuracy is demanded by whatever the user is doing with the deviates,\n\t// and so forth; it makes sense to just rely on the GSL for maximal accuracy and reliability.\n\t\n\tif (lambda_singleton)\n\t{\n\t\tdouble lambda0 = arg_lambda->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((lambda0 <= 0.0) || std::isnan(lambda0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rpois): function rpois() requires lambda > 0.0 (\" << EidosStringForFloat(lambda0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RPOIS_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, lambda0) if(num_draws >= EIDOS_OMPMIN_RPOIS_1) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tint_result->set_int_no_check(gsl_ran_poisson(rng_gsl, lambda0), draw_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tbool saw_error = false;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RPOIS_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(int_result, arg_lambda) reduction(||: saw_error) if(num_draws >= EIDOS_OMPMIN_RPOIS_2) num_threads(thread_count)\n\t\t{\n\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble lambda = arg_lambda->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tif ((lambda <= 0.0) || std::isnan(lambda))\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(gsl_ran_poisson(rng_gsl, lambda), draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rpois): function rpois() requires lambda > 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)runif(integer$ n, [numeric min = 0], [numeric max = 1])\nEidosValue_SP Eidos_ExecuteFunction_runif(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tEidosValue *arg_min = p_arguments[1].get();\n\tEidosValue *arg_max = p_arguments[2].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tint arg_min_count = arg_min->Count();\n\tint arg_max_count = arg_max->Count();\n\tbool min_singleton = (arg_min_count == 1);\n\tbool max_singleton = (arg_max_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_runif): function runif() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!min_singleton && (arg_min_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_runif): function runif() requires min to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!max_singleton && (arg_max_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_runif): function runif() requires max to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble min_value0 = (arg_min_count ? arg_min->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble max_value0 = (arg_max_count ? arg_max->NumericAtIndex_NOCAST(0, nullptr) : 1.0);\n\t\n\tif (min_singleton && max_singleton && (min_value0 == 0.0) && (max_value0 == 1.0))\n\t{\n\t\t// With the default min and max, we can streamline quite a bit\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RUNIF_1);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws, std::cout) firstprivate(float_result) if(num_draws >= EIDOS_OMPMIN_RUNIF_1) num_threads(thread_count)\n\t\t{\n\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tfloat_result->set_float_no_check(Eidos_rng_uniform_doubleCO(rng_64), draw_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble range0 = max_value0 - min_value0;\n\t\t\n\t\tif (min_singleton && max_singleton)\n\t\t{\n\t\t\tif (range0 < 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_runif): function runif() requires min < max.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RUNIF_2);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, range0, min_value0) if(num_draws >= EIDOS_OMPMIN_RUNIF_2) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t\tfloat_result->set_float_no_check(Eidos_rng_uniform_doubleCO(rng_64) * range0 + min_value0, draw_index);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tbool saw_error = false;\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_RUNIF_3);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, num_draws) firstprivate(float_result, min_singleton, max_singleton, min_value0, max_value0, arg_min, arg_max) reduction(||: saw_error) if(num_draws >= EIDOS_OMPMIN_RUNIF_3) num_threads(thread_count)\n\t\t\t{\n\t\t\t\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\t{\n\t\t\t\t\tdouble min_value = (min_singleton ? min_value0 : arg_min->NumericAtIndex_NOCAST((int)draw_index, nullptr));\n\t\t\t\t\tdouble max_value = (max_singleton ? max_value0 : arg_max->NumericAtIndex_NOCAST((int)draw_index, nullptr));\n\t\t\t\t\tdouble range = max_value - min_value;\n\t\t\t\t\t\n\t\t\t\t\tif (range < 0.0)\n\t\t\t\t\t{\n\t\t\t\t\t\tsaw_error = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tfloat_result->set_float_no_check(Eidos_rng_uniform_doubleCO(rng_64) * range + min_value, draw_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (saw_error)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_runif): function runif() requires min < max.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)rweibull(integer$ n, numeric lambda, numeric k)\nEidosValue_SP Eidos_ExecuteFunction_rweibull(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_lambda = p_arguments[1].get();\n\tEidosValue *arg_k = p_arguments[2].get();\n\tint arg_lambda_count = arg_lambda->Count();\n\tint arg_k_count = arg_k->Count();\n\tbool lambda_singleton = (arg_lambda_count == 1);\n\tbool k_singleton = (arg_k_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!lambda_singleton && (arg_lambda_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires lambda to be of length 1 or n.\" << EidosTerminate(nullptr);\n\tif (!k_singleton && (arg_k_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires k to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\tdouble lambda0 = (arg_lambda_count ? arg_lambda->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tdouble k0 = (arg_k_count ? arg_k->NumericAtIndex_NOCAST(0, nullptr) : 0.0);\n\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\n\tif (lambda_singleton && k_singleton)\n\t{\n\t\tif (lambda0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires lambda > 0.0 (\" << EidosStringForFloat(lambda0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\tif (k0 <= 0.0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires k > 0.0 (\" << EidosStringForFloat(k0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\tfloat_result->set_float_no_check(gsl_ran_weibull(rng_gsl, lambda0, k0), draw_index);\n\t}\n\telse\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t{\n\t\t\tdouble lambda = (lambda_singleton ? lambda0 : arg_lambda->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\tdouble k = (k_singleton ? k0 : arg_k->NumericAtIndex_NOCAST(draw_index, nullptr));\n\t\t\t\n\t\t\tif (lambda <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires lambda > 0.0 (\" << EidosStringForFloat(lambda) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif (k <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rweibull): function rweibull() requires k > 0.0 (\" << EidosStringForFloat(k) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(gsl_ran_weibull(rng_gsl, lambda, k), draw_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)rztpois(integer$ n, numeric lambda)\nEidosValue_SP Eidos_ExecuteFunction_rztpois(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *n_value = p_arguments[0].get();\n\tint64_t num_draws = n_value->IntAtIndex_NOCAST(0, nullptr);\n\tEidosValue *arg_lambda = p_arguments[1].get();\n\tint arg_lambda_count = arg_lambda->Count();\n\tbool lambda_singleton = (arg_lambda_count == 1);\n\t\n\tif (num_draws < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rztpois): function rztpois() requires n to be greater than or equal to 0 (\" << num_draws << \" supplied).\" << EidosTerminate(nullptr);\n\tif (!lambda_singleton && (arg_lambda_count != num_draws))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rztpois): function rztpois() requires lambda to be of length 1 or n.\" << EidosTerminate(nullptr);\n\t\n\t// The rpois() function ignores USE_GSL_POISSON and always uses the GSL for maximal accuracy and reliability.\n\t// This function does NOT do that, because to use the GSL we would have to rejection sample, and for small\n\t// lambda, that could be extremely slow.  We therefore use Eidos_FastRandomPoisson_NONZERO() instead.  It\n\t// should fall back on rejection sampling with the GSL in cases where its algorithm is problematic.\n\t\n\tif (lambda_singleton)\n\t{\n\t\tdouble lambda0 = arg_lambda->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif ((lambda0 <= 0.0) || std::isnan(lambda0))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rztpois): function rztpois() requires lambda > 0.0 (\" << EidosStringForFloat(lambda0) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tdouble exp_neg_lambda = exp(-lambda0);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\t// FIXME PARALLELIZE THIS\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t\tint_result->set_int_no_check(Eidos_FastRandomPoisson_NONZERO(rng_state, lambda0, exp_neg_lambda), draw_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize((int)num_draws);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tbool saw_error = false;\n\t\t\n\t\t// FIXME PARALLELIZE THIS\n\t\t{\n\t\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\tfor (int64_t draw_index = 0; draw_index < num_draws; ++draw_index)\n\t\t\t{\n\t\t\t\tdouble lambda = arg_lambda->NumericAtIndex_NOCAST((int)draw_index, nullptr);\n\t\t\t\t\n\t\t\t\tif ((lambda <= 0.0) || std::isnan(lambda))\n\t\t\t\t{\n\t\t\t\t\tsaw_error = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(Eidos_FastRandomPoisson_NONZERO(rng_state, lambda, exp(-lambda)), draw_index);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (saw_error)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rztpois): function rztpois() requires lambda > 0.0.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_files.cpp",
    "content": "//\n//  eidos_functions_files.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n\n#include <utility>\n#include <string>\n#include <vector>\n#include <stdio.h>\n#include <dirent.h>\n#include <fstream>\n#include <iostream>\n#include <sys/stat.h>\n#include <unistd.h>\n\n#include \"../eidos_zlib/zlib.h\"\n\n\n// ************************************************************************************\n//\n//\tfilesystem access functions\n//\n#pragma mark -\n#pragma mark Filesystem access functions\n#pragma mark -\n\n\n//\t(logical$)createDirectory(string$ path)\nEidosValue_SP Eidos_ExecuteFunction_createDirectory(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *path_value = p_arguments[0].get();\n\tstd::string base_path = path_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string error_string;\n\tbool success = Eidos_CreateDirectory(base_path, &error_string);\n\t\n\t// Emit a warning if there was one\n\tif (error_string.length())\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tp_interpreter.ErrorOutputStream() << error_string << std::endl;\n\t\n\treturn (success ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n}\n\n//\t(logical$)deleteFile(string$ filePath)\nEidosValue_SP Eidos_ExecuteFunction_deleteFile(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string file_path = Eidos_ResolvedPath(base_path);\n\t\n\tresult_SP = ((remove(file_path.c_str()) == 0) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)fileExists(string$ filePath)\nEidosValue_SP Eidos_ExecuteFunction_fileExists(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string file_path = Eidos_ResolvedPath(base_path);\n\t\n\tstruct stat file_info;\n\tbool path_exists = (stat(file_path.c_str(), &file_info) == 0);\n\t\n\tresult_SP = (path_exists ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\n\treturn result_SP;\n}\n\n//\t(string)filesAtPath(string$ path, [logical$ fullPaths = F])\nEidosValue_SP Eidos_ExecuteFunction_filesAtPath(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *path_value = p_arguments[0].get();\n\tstd::string base_path = path_value->StringAtIndex_NOCAST(0, nullptr);\n\tint base_path_length = (int)base_path.length();\n\tbool base_path_ends_in_slash = (base_path_length > 0) && (base_path[base_path_length-1] == '/');\n\tstd::string path = Eidos_ResolvedPath(base_path);\n\tbool fullPaths = p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// this code modified from GNU: http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister\n\t// I'm not sure if it works on Windows... sigh...\n\tDIR *dp;\n\t\n\tdp = opendir(path.c_str());\n\t\n\tif (dp != NULL)\n\t{\n\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\twhile (true)\n\t\t{\n\t\t\t// BCH 5 April 2018: switching to readdir() instead of readdir_r().  It seemed like readdir_r() would be better in principle, since\n\t\t\t// it's thread-safe, but apparently it has been deprecated in POSIX because of several issues, and readdir() is now recommended\n\t\t\t// after all (and is thread-safe in most situations, supposedly, but if we ever go multithreaded that will need to be checked.)\n\t\t\terrno = 0;\n\t\t\t\n\t\t\tstruct dirent *ep = readdir(dp);\n\t\t\tint error = errno;\n\t\t\t\n\t\t\tif (!ep && error)\n\t\t\t{\n\t\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_filesAtPath): function filesAtPath() encountered error code \" << error << \" while iterating through path \" << path << \".\" << std::endl;\n\t\t\t\tresult_SP = gStaticEidosValueNULL;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (!ep)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tstd::string filename = ep->d_name;\n\t\t\t\n\t\t\tif (fullPaths)\n\t\t\t\tfilename = base_path + (base_path_ends_in_slash ? \"\" : \"/\") + filename;\t\t// NOLINT(*-inefficient-string-concatenation) : this is fine\n\t\t\t\n\t\t\tstring_result->PushString(filename);\n\t\t}\n\t\t\n\t\t(void)closedir(dp);\n\t}\n\telse\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_filesAtPath): function filesAtPath() could not open path \" << path << \".\" << std::endl;\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string$)getwd(void)\nEidosValue_SP Eidos_ExecuteFunction_getwd(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\tstd::string cwd = Eidos_CurrentDirectory();\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(cwd));\n\t\n\treturn result_SP;\n}\n\n//\t(string)readFile(string$ filePath)\nEidosValue_SP Eidos_ExecuteFunction_readFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string file_path = Eidos_ResolvedPath(base_path);\n\t\n\t// read the contents in\n\tstd::ifstream file_stream(file_path.c_str());\n\t\n\tif (!file_stream.is_open())\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_readFile): function readFile() could not read file at path \" << file_path << \".\" << std::endl;\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse\n\t{\n\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tstd::string line;\n\t\t\n\t\twhile (getline(file_stream, line))\n\t\t{\n\t\t\t// BCH 8/22/2024: files created on Windows have CRLF as their line ending; macOS and Linux use LF only,\n\t\t\t// which means that a Windows file read on those platforms will have stray \\r characters left at the ends,\n\t\t\t// which we want to strip off for platform inter-operability.\n\t\t\tif (!line.empty() && line[line.size() - 1] == '\\r')\n\t\t\t\tline.pop_back();\n\t\t\t\n\t\t\tstring_result->PushString(line);\n\t\t}\n\t\t\n\t\tif (file_stream.bad())\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_readFile): function readFile() encountered stream errors while reading file at path \" << file_path << \".\" << std::endl;\n\t\t\tresult_SP = gStaticEidosValueNULL;\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string$)readLine(void)\nEidosValue_SP Eidos_ExecuteFunction_readLine(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n#pragma unused (p_arguments, p_interpreter)\n\t\n\t// This function was implemented by Chris Talbot 11/19/25 for use in reinforcement learning environments.\n\t// Associated with issue #576.\n\t\n#ifdef EIDOS_GUI\n\t// Cannot be called inside a GUI since there is (presumably) no stdin set up for the script to read.\n\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_readLine): function readLine() is not available in GUI environments (SLiMgui, SLiMguiLegacy, or EidosScribe).\" << EidosTerminate(nullptr);\n#else\n\t// Read a single line from stdin (command-line mode with interactive terminal)\n\tstd::string line;\n\t\n\tif (std::getline(std::cin, line))\n\t{\n\t\t// Control for CRLF vs. LF line endings\n\t\tif (!line.empty() && line[line.size() - 1] == '\\r')\n\t\t\tline.pop_back();\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(line));\n\t}\n\telse\n\t{\n\t\t// EOF or error reading from stdin; return empty string\n\t\treturn gStaticEidosValue_StringEmpty;\n\t}\n#endif\n}\n\n//\t(string$)setwd(string$ path)\nEidosValue_SP Eidos_ExecuteFunction_setwd(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\t// Get the path; this code is identical to getwd() above, except it makes the value invisible\n\tstd::string cwd = Eidos_CurrentDirectory();\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(cwd));\n\tresult_SP->SetInvisible(true);\n\t\n\t// Now set the path\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string final_path = Eidos_ResolvedPath(base_path);\n\t\n\terrno = 0;\n\tint retval = chdir(final_path.c_str());\n\t\n\tif (retval == -1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setwd): the working directory could not be set (error \" << errno << \")\" << EidosTerminate(nullptr);\n\t\n\treturn result_SP;\n}\n\n//\t(string$)tempdir(void)\nEidosValue_SP Eidos_ExecuteFunction_tempdir(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(Eidos_TemporaryDirectory()));\n}\n\n//\t(logical$)flushFile(string$ filePath)\nEidosValue_SP Eidos_ExecuteFunction_flushFile(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\t// resolve the user-supplied path to a canonical absolute path, so that it remains valid even if the current directory changes\n\t// this is needed because we buffer writes in some cases, and don't actually write them out until a later time\n\tstd::string file_path = Eidos_AbsolutePath(base_path);\n\t\n\t// note that writeFile() adds \".gz\" to the filename if compression is specified and it is not already present; we don't,\n\t// since we don't know if compression is on for this file; the user will therefore have to use the correct path\n\t\n\t// flush the contents out\n\tEidos_FlushFile(file_path);\n\t\n\treturn gStaticEidosValue_LogicalT;\t// we used to return F if we had a warning condition; now those are errors, so we always return T\n}\n\n//\t(logical$)writeFile(string$ filePath, string contents, [logical$ append = F], [logical$ compress = F])\nEidosValue_SP Eidos_ExecuteFunction_writeFile(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *filePath_value = p_arguments[0].get();\n\tstd::string base_path = filePath_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\t// resolve the user-supplied path to a canonical absolute path, so that it remains valid even if the current directory changes\n\t// this is needed because we buffer writes in some cases, and don't actually write them out until a later time\n\tstd::string file_path = Eidos_AbsolutePath(base_path);\n\t\n\t// the second argument is the file contents to write, which we put into a vector\n\tEidosValue_String *contents_value = (EidosValue_String *)p_arguments[1].get();\n\tint contents_count = contents_value->Count();\n\tstd::vector<const std::string *> contents_buffer;\n\t\n\tcontents_buffer.reserve(contents_count);\n\t\n\tfor (int value_index = 0; value_index < contents_count; ++value_index)\n\t\tcontents_buffer.emplace_back(&contents_value->StringRefAtIndex_NOCAST(value_index, nullptr));\n\t\n\t// the third argument is an optional append flag, F by default\n\tbool append = p_arguments[2]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// and then there is a flag for optional gzip compression\n\tbool do_compress = p_arguments[3]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (do_compress && !Eidos_string_hasSuffix(file_path, \".gz\"))\n\t\tfile_path.append(\".gz\");\n\t\n\t// write the contents out\n\tEidos_WriteToFile(file_path, contents_buffer, append, do_compress, EidosFileFlush::kDefaultFlush);\n\t\n#ifdef SLIMGUI\n\t// we need to provide SLiMgui with information about the file write we just did; this is gross, but it wants to know\n\t// we make a separate buffer for this purpose, with string copies, to donate to Community with &&\n\tEidosContext *context = p_interpreter.Context();\n\t\n\tif (context)\n\t{\n\t\tstd::vector<std::string> slimgui_buffer;\n\t\t\n\t\tslimgui_buffer.reserve(contents_count);\n\t\t\n\t\tfor (int value_index = 0; value_index < contents_count; ++value_index)\n\t\t\tslimgui_buffer.emplace_back(contents_value->StringRefAtIndex_NOCAST(value_index, nullptr));\n\t\t\n\t\tcontext->FileWriteNotification(file_path, std::move(slimgui_buffer), append);\n\t}\n#endif\n\t\n\treturn gStaticEidosValue_LogicalT;\t// we used to return F if we had a warning condition; now those are errors, so we always return T\n}\n\n//\t(string$)writeTempFile(string$ prefix, string$ suffix, string contents, [logical$ compress = F])\nEidosValue_SP Eidos_ExecuteFunction_writeTempFile(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tif (!Eidos_TemporaryDirectoryExists())\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_writeTempFile): in function writeTempFile(), the temporary directory appears not to exist or is not writeable.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue *prefix_value = p_arguments[0].get();\n\tstd::string prefix = prefix_value->StringAtIndex_NOCAST(0, nullptr);\n\tEidosValue *suffix_value = p_arguments[1].get();\n\tstd::string suffix = suffix_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\t// the third argument is the file contents to write\n\tEidosValue_String *contents_value = (EidosValue_String *)p_arguments[2].get();\n\tint contents_count = contents_value->Count();\n\t\n\t// and then there is a flag for optional gzip compression\n\tbool do_compress = p_arguments[3]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (do_compress && !Eidos_string_hasSuffix(suffix, \".gz\"))\n\t\tsuffix.append(\".gz\");\n\t\n\t// generate the filename template from the prefix/suffix\n\tstd::string filename = prefix + \"XXXXXX\" + suffix;\n\tstd::string file_path_template = Eidos_TemporaryDirectory() + filename;\n\t\n\tif ((filename.find('~') != std::string::npos) || (filename.find('/') != std::string::npos))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_writeTempFile): in function writeTempFile(), prefix and suffix may not contain '~' or '/'; they may specify only a filename.\" << EidosTerminate(nullptr);\n\t\n\t// write the contents out; thanks to http://stackoverflow.com/questions/499636/how-to-create-a-stdofstream-to-a-temp-file for the temp file creation code\n\tchar *file_path_cstr = strdup(file_path_template.c_str());\n\tint fd = Eidos_mkstemps(file_path_cstr, (int)suffix.length());\n\t\n\tif (fd == -1)\n\t{\n\t\tfree(file_path_cstr);\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_writeTempFile): (internal error) Eidos_mkstemps() failed!\" << EidosTerminate(nullptr);\n\t}\n\t\n#ifdef SLIMGUI\n\t// we need to provide SLiMgui with information about the file write we just did; this is gross, but it wants to know\n\t// we make a separate buffer for this purpose, with string copies, to donate to Community with &&\n\tEidosContext *context = p_interpreter.Context();\n\t\n\tif (context)\n\t{\n\t\tstd::string file_path(file_path_cstr);\n\t\tstd::vector<std::string> slimgui_buffer;\n\t\t\n\t\tslimgui_buffer.reserve(contents_count);\n\t\t\n\t\tfor (int value_index = 0; value_index < contents_count; ++value_index)\n\t\t\tslimgui_buffer.emplace_back(contents_value->StringRefAtIndex_NOCAST(value_index, nullptr));\n\t\t\n\t\tcontext->FileWriteNotification(file_path, std::move(slimgui_buffer), false);\n\t}\n#endif\n\t\n\tif (do_compress)\n\t{\n\t\t// compression using zlib; very different from the no-compression case, unfortunately, because here we use C-based APIs\n\t\tgzFile gzf = gzdopen(fd, \"wb\");\n\t\t\n\t\tif (!gzf)\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_writeTempFile): function writeTempFile() could not write to file at path \" << file_path_cstr << \".\" << std::endl;\n\t\t\tresult_SP = gStaticEidosValue_StringEmpty;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::ostringstream outstream;\n\t\t\t\n\t\t\tif (contents_count == 1)\n\t\t\t{\n\t\t\t\t// no final newline in this case, so the user can precisely specify the file contents if desired\n\t\t\t\toutstream << contents_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst std::string *string_vec = contents_value->StringData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < contents_count; ++value_index)\n\t\t\t\t\toutstream << string_vec[value_index] << std::endl;\n\t\t\t}\n\t\t\t\n\t\t\tstd::string outstring = outstream.str();\n\t\t\tconst char *outcstr = outstring.c_str();\n\t\t\tsize_t outcstr_length = strlen(outcstr);\n\t\t\t\n\t\t\t// do the writing with zlib\n\t\t\tbool failed = true;\n\t\t\tint retval = gzbuffer(gzf, 128*1024L);\t// bigger buffer for greater speed\n\t\t\t\n\t\t\tif (retval != -1)\n\t\t\t{\n\t\t\t\tretval = gzwrite(gzf, outcstr, (unsigned)outcstr_length);\n\t\t\t\t\n\t\t\t\tif ((retval != 0) || (outcstr_length == 0))\t// writing 0 bytes returns 0, which is supposed to be an error code\n\t\t\t\t{\n\t\t\t\t\tretval = gzclose_w(gzf);\n\t\t\t\t\t\n\t\t\t\t\tif (retval == Z_OK)\n\t\t\t\t\t\tfailed = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (failed)\n\t\t\t{\n\t\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_writeTempFile): function writeTempFile() encountered zlib errors while writing to file at path \" << file_path_cstr << \".\" << std::endl;\n\t\t\t\tresult_SP = gStaticEidosValue_StringEmpty;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::string file_path(file_path_cstr);\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(file_path));\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no compression\n\t\tstd::string file_path(file_path_cstr);\n\t\tstd::ofstream file_stream(file_path.c_str(), std::ios_base::out);\n\t\tclose(fd);\t// opened by Eidos_mkstemps()\n\t\t\n\t\tif (!file_stream.is_open())\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_writeTempFile): function writeTempFile() could not write to file at path \" << file_path << \".\" << std::endl;\n\t\t\tresult_SP = gStaticEidosValue_StringEmpty;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (contents_count == 1)\n\t\t\t{\n\t\t\t\t// no final newline in this case, so the user can precisely specify the file contents if desired\n\t\t\t\tfile_stream << contents_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst std::string *string_vec = contents_value->StringData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < contents_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tfile_stream << string_vec[value_index];\n\t\t\t\t\t\n\t\t\t\t\t// Add newlines after all lines but the last\n\t\t\t\t\t// BCH 27 January 2017: changed to add a newline after the last line, too, so appending new content to a file produces correct line breaks\n\t\t\t\t\t//if (value_index + 1 < contents_count)\n\t\t\t\t\tfile_stream << std::endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (file_stream.bad())\n\t\t\t{\n\t\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\t\tp_interpreter.ErrorOutputStream() << \"#WARNING (Eidos_ExecuteFunction_writeTempFile): function writeTempFile() encountered stream errors while writing to file at path \" << file_path << \".\" << std::endl;\n\t\t\t\tresult_SP = gStaticEidosValue_StringEmpty;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(file_path));\n\t\t\t}\n\t\t}\n\t}\n\t\n\tfree(file_path_cstr);\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_math.cpp",
    "content": "//\n//  eidos_functions_math.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_simd.h\"\n\n#include <utility>\n#include <string>\n#include <vector>\n#include <limits>\n\n// BCH 20 October 2016: continuing to try to fix problems with gcc 5.4.0 on Linux without breaking other\n// builds.  We will switch to including <cmath> and using the std:: namespace math functions, since on\n// that platform <cmath> is included as a side effect even if we don't include it ourselves, and on\n// that platform that actually (incorrectly) undefines the global functions defined by math.h.  On other\n// platforms, we get the global math.h functions defined as well, so we can't use using to select the\n// <cmath> functions, we have to specify them explicitly.\n// BCH 21 May 2017: since this continues to come up as an issue, it's worth adding a bit more commentary.\n// New code introduced on OS X may not correctly use the std:: namespace qualifier for math functions,\n// because it is not required in Xcode, and then the build breaks on Linux.  This problem is made worse\n// by the fact that gsl_math.h includes math.h, so that brings in the C functions in the global namespace.\n// We can't change that, because the GSL is C code and needs to use the C math library; it has not been\n// validated against the C++ math library as far as I know, so changing it to use cmath would be\n// dangerous.  So I think we need to just tolerate this build issue and fix it when it arises.\n#include <cmath>\n\n\n// ************************************************************************************\n//\n//\tmath functions\n//\n#pragma mark -\n#pragma mark Math functions\n#pragma mark -\n\n\n//\t(numeric)abs(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_abs(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\t// This is an overflow-safe version of:\n\t\t\t//int_result->set_int_no_check(llabs(int_vec[value_index]), value_index);\n\t\t\t\n\t\t\tint64_t operand = int_data[value_index];\n\t\t\t\n\t\t\t// the absolute value of INT64_MIN cannot be represented in int64_t\n\t\t\tif (operand == INT64_MIN)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_abs): function abs() cannot take the absolute value of the most negative integer.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint64_t abs_result = llabs(operand);\n\t\t\t\n\t\t\tint_result->set_int_no_check(abs_result, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_ABS_FLOAT);\n\t\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_ABS_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = fabs(float_data[value_index]);\n#else\n\t\tEidos_SIMD::abs_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)acos(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_acos(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(acos(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::acos_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)asin(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_asin(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(asin(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::asin_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)atan(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_atan(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(atan(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::atan_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)atan2(numeric x, numeric y)\nEidosValue_SP Eidos_ExecuteFunction_atan2(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValueType x_type = x_value->Type();\n\tEidosValue *y_value = p_arguments[1].get();\n\tint y_count = y_value->Count();\n\tEidosValueType y_type = y_value->Type();\n\t\n\tif (x_count != y_count)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_atan2): function atan2() requires arguments of equal length.\" << EidosTerminate(nullptr);\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint x_dimcount = x_value->DimensionCount();\n\tint y_dimcount = y_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(x_value, y_value));\n\t\n\tif ((x_dimcount > 1) && (y_dimcount > 1) && !EidosValue::MatchingDimensions(x_value, y_value))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_atan2): non-conformable array operands in atan2().\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\t// Use SIMD when both operands are float type\n\tif ((x_type == EidosValueType::kValueFloat) && (y_type == EidosValueType::kValueFloat))\n\t{\n\t\tconst double *x_data = x_value->FloatData();\n\t\tconst double *y_data = y_value->FloatData();\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\n\t\tEidos_SIMD::atan2_float64(x_data, y_data, float_result_data, x_count);\n\t}\n\telse\n\t{\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(atan2(x_value->NumericAtIndex_NOCAST(value_index, nullptr), y_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\treturn result_SP;\n}\n\n//\t(float)ceil(float x)\nEidosValue_SP Eidos_ExecuteFunction_ceil(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tconst double *float_data = x_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\tresult_SP = EidosValue_SP(float_result);\n\t\n#ifdef _OPENMP\n\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_CEIL);\n\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_CEIL) num_threads(thread_count)\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tfloat_result_data[value_index] = ceil(float_data[value_index]);\n#else\n\tEidos_SIMD::ceil_float64(float_data, float_result_data, x_count);\n#endif\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)cos(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_cos(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(cos(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::cos_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)cumProduct(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_cumProduct(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tint64_t product = 1;\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t operand = int_data[value_index];\n\t\t\t\n\t\t\tbool overflow = Eidos_mul_overflow(product, operand, &product);\n\t\t\t\n\t\t\tif (overflow)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cumProduct): integer multiplication overflow in function cumProduct().\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(product, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tdouble product = 1.0;\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tproduct *= float_data[value_index];\n\t\t\tfloat_result->set_float_no_check(product, value_index);\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)cumSum(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_cumSum(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tint64_t sum = 0;\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t operand = int_data[value_index];\n\t\t\t\n\t\t\tbool overflow = Eidos_add_overflow(sum, operand, &sum);\n\t\t\t\n\t\t\tif (overflow)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cumSum): integer addition overflow in function cumSum().\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(sum, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tdouble sum = 0.0;\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tsum += float_data[value_index];\n\t\t\tfloat_result->set_float_no_check(sum, value_index);\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)exp(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_exp(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(exp(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_EXP_FLOAT);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_EXP_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = exp(float_data[value_index]);\n#else\n\t\tEidos_SIMD::exp_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)floor(float x)\nEidosValue_SP Eidos_ExecuteFunction_floor(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tconst double *float_data = x_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\tresult_SP = EidosValue_SP(float_result);\n\t\n#ifdef _OPENMP\n\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_FLOOR);\n\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_FLOOR) num_threads(thread_count)\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tfloat_result_data[value_index] = floor(float_data[value_index]);\n#else\n\tEidos_SIMD::floor_float64(float_data, float_result_data, x_count);\n#endif\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)integerDiv(integer x, integer y)\nEidosValue_SP Eidos_ExecuteFunction_integerDiv(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *y_value = p_arguments[1].get();\n\tint y_count = y_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint x_dimcount = x_value->DimensionCount();\n\tint y_dimcount = y_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(x_value, y_value));\n\t\n\tif ((x_dimcount > 1) && (y_dimcount > 1) && !EidosValue::MatchingDimensions(x_value, y_value))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerDiv): non-conformable array arguments to integerDiv().\" << EidosTerminate(nullptr);\n\t\n\tif (x_count == y_count)\n\t{\n\t\tconst int64_t *int1_data = x_value->IntData();\n\t\tconst int64_t *int2_data = y_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t int1 = int1_data[value_index];\n\t\t\tint64_t int2 = int2_data[value_index];\n\t\t\t\n\t\t\tif (int2 == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerDiv): function integerDiv() cannot perform division by 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(int1 / int2, value_index);\n\t\t}\n\t}\n\telse if (x_count == 1)\n\t{\n\t\tint64_t int1 = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tconst int64_t *int2_data = y_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(y_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t{\n\t\t\tint64_t int2 = int2_data[value_index];\n\t\t\t\n\t\t\tif (int2 == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerDiv): function integerDiv() cannot perform division by 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(int1 / int2, value_index);\n\t\t}\n\t}\n\telse if (y_count == 1)\n\t{\n\t\tconst int64_t *int1_data = x_value->IntData();\n\t\tint64_t int2 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (int2 == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerDiv): function integerDiv() cannot perform division by 0.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Special-case division by 2, since it is common\n\t\t// BCH 13 April 2017: Removing this optimization; it produces inconsistent behavior for negative numerators.\n\t\t// This optimization was originally committed on 2 March 2017; it was never in any release version of SLiM.\n//\t\t\tif (int2 == 2)\n//\t\t\t{\n//\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n//\t\t\t\t\tint_result->set_int_no_check(int1_vec[value_index] >> 1, value_index);\n//\t\t\t}\n//\t\t\telse\n//\t\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(int1_data[value_index] / int2, value_index);\n//\t\t\t}\n\t}\n\telse\t// if ((x_count != y_count) && (x_count != 1) && (y_count != 1))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerDiv): function integerDiv() requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\treturn result_SP;\n}\n\n//\t(integer)integerMod(integer x, integer y)\nEidosValue_SP Eidos_ExecuteFunction_integerMod(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *y_value = p_arguments[1].get();\n\tint y_count = y_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint x_dimcount = x_value->DimensionCount();\n\tint y_dimcount = y_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(x_value, y_value));\n\t\n\tif ((x_dimcount > 1) && (y_dimcount > 1) && !EidosValue::MatchingDimensions(x_value, y_value))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerMod): non-conformable array arguments to integerMod().\" << EidosTerminate(nullptr);\n\t\n\tif (x_count == y_count)\n\t{\n\t\tconst int64_t *int1_data = x_value->IntData();\n\t\tconst int64_t *int2_data = y_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t int1 = int1_data[value_index];\n\t\t\tint64_t int2 = int2_data[value_index];\n\t\t\t\n\t\t\tif (int2 == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerMod): function integerMod() cannot perform modulo by 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(int1 % int2, value_index);\n\t\t}\n\t}\n\telse if (x_count == 1)\n\t{\n\t\tint64_t int1 = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tconst int64_t *int2_data = y_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(y_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t{\n\t\t\tint64_t int2 = int2_data[value_index];\n\t\t\t\n\t\t\tif (int2 == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerMod): function integerMod() cannot perform modulo by 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint_result->set_int_no_check(int1 % int2, value_index);\n\t\t}\n\t}\n\telse if (y_count == 1)\n\t{\n\t\tconst int64_t *int1_data = x_value->IntData();\n\t\tint64_t int2 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (int2 == 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerMod): function integerMod() cannot perform modulo by 0.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Special-case modulo by 2, since it is common\n\t\t// BCH 13 April 2017: Removing this optimization; it produces inconsistent behavior for negative numerators.\n\t\t// This optimization was originally committed on 2 March 2017; it was never in any release version of SLiM.\n//\t\t\tif (int2 == 2)\n//\t\t\t{\n//\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n//\t\t\t\t\tint_result->set_int_no_check(int1_vec[value_index] & (int64_t)0x01, value_index);\n//\t\t\t}\n//\t\t\telse\n//\t\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(int1_data[value_index] % int2, value_index);\n//\t\t\t}\n\t}\n\telse\t// if ((x_count != y_count) && (x_count != 1) && (y_count != 1))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integerMod): function integerMod() requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\treturn result_SP;\n}\n\n//\t(logical)isFinite(float x)\nEidosValue_SP Eidos_ExecuteFunction_isFinite(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif ((x_count == 1) && (x_value->DimensionCount() == 1))\n\t{\n\t\tresult_SP = (std::isfinite(x_value->FloatAtIndex_NOCAST(0, nullptr)) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tlogical_result->set_logical_no_check(std::isfinite(float_data[value_index]), value_index);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)isInfinite(float x)\nEidosValue_SP Eidos_ExecuteFunction_isInfinite(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif ((x_count == 1) && (x_value ->DimensionCount() == 1))\n\t{\n\t\tresult_SP = (std::isinf(x_value->FloatAtIndex_NOCAST(0, nullptr)) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tlogical_result->set_logical_no_check(std::isinf(float_data[value_index]), value_index);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)isNAN(float x)\nEidosValue_SP Eidos_ExecuteFunction_isNAN(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif ((x_count == 1) && (x_value->DimensionCount() == 1))\n\t{\n\t\tresult_SP = (std::isnan(x_value->FloatAtIndex_NOCAST(0, nullptr)) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tlogical_result->set_logical_no_check(std::isnan(float_data[value_index]), value_index);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)log(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_log(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(log(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_LOG_FLOAT);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_LOG_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = log(float_data[value_index]);\n#else\n\t\tEidos_SIMD::log_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)log10(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_log10(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(log10(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_LOG10_FLOAT);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_LOG10_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = log10(float_data[value_index]);\n#else\n\t\tEidos_SIMD::log10_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)log2(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_log2(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(log2(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_LOG2_FLOAT);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_LOG2_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = log2(float_data[value_index]);\n#else\n\t\tEidos_SIMD::log2_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(numeric$)product(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_product(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tint64_t product = 1;\n\t\tdouble product_d = 1.0;\n\t\tbool fits_in_integer = true;\n\t\t\n\t\t// We do a tricky thing here.  We want to try to compute in integer, but switch to float if we overflow.\n\t\t// If we do overflow, we want to minimize numerical error by accumulating in integer for as long as we\n\t\t// can, and then throwing the integer accumulator over into the float accumulator only when it is about\n\t\t// to overflow.  We perform both computations in parallel, and use integer for the result if we can.\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t old_product = product;\n\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\n\t\t\tbool overflow = Eidos_mul_overflow(old_product, temp, &product);\n\t\t\t\n\t\t\t// switch to float computation on overflow, and accumulate in the float product just before overflow\n\t\t\tif (overflow)\n\t\t\t{\n\t\t\t\tfits_in_integer = false;\n\t\t\t\tproduct_d *= old_product;\n\t\t\t\tproduct = temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tproduct_d *= product;\t\t// multiply in whatever integer accumulation has not overflowed\n\t\t\n\t\tif (fits_in_integer)\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(product));\n\t\telse\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(product_d));\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tdouble product = Eidos_SIMD::product_float64(float_data, x_count);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(product));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)round(float x)\nEidosValue_SP Eidos_ExecuteFunction_round(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tconst double *float_data = x_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\tresult_SP = EidosValue_SP(float_result);\n\t\n#ifdef _OPENMP\n\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_ROUND);\n\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_ROUND) num_threads(thread_count)\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tfloat_result_data[value_index] = round(float_data[value_index]);\n#else\n\tEidos_SIMD::round_float64(float_data, float_result_data, x_count);\n#endif\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(*)setDifference(* x, * y)\nEidosValue_SP Eidos_ExecuteFunction_setDifference(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setDifference): function setDifference() requires that both operands have the same type.\" << EidosTerminate(nullptr);\n\t\n\tEidosValueType arg_type = x_type;\n\tconst EidosClass *class0 = nullptr, *class1 = nullptr;\n\t\n\tif (arg_type == EidosValueType::kValueObject)\n\t{\n\t\tclass0 = ((EidosValue_Object *)x_value)->Class();\n\t\tclass1 = ((EidosValue_Object *)y_value)->Class();\n\t\t\n\t\tif ((class0 != class1) && (class0 != gEidosObject_Class) && (class1 != gEidosObject_Class))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setDifference): function setDifference() requires that both operands of object type have the same class (or undefined class).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (x_count == 0)\n\t{\n\t\t// If x is empty, the difference is the empty set\n\t\tif (class1 && (class1 != gEidosObject_Class))\n\t\t\tresult_SP = y_value->NewMatchingType();\n\t\telse\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse if (y_count == 0)\n\t{\n\t\t// If y is empty, the difference is x, uniqued\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t}\n\telse if (arg_type == EidosValueType::kValueLogical)\n\t{\n\t\t// Because EidosValue_Logical works differently than other EidosValue types, this code can handle\n\t\t// both the singleton and non-singleton cases\n\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\tconst eidos_logical_t *logical_data1 = y_value->LogicalData();\n\t\tbool containsF0 = false, containsT0 = false, containsF1 = false, containsT1 = false;\n\t\t\n\t\tif (logical_data0[0])\n\t\t{\n\t\t\tcontainsT0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (!logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (logical_data1[0])\n\t\t{\n\t\t\tcontainsT1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (!logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\t// NOLINTBEGIN(*-branch-clone) : intentional branch clones\n\t\tif (containsF1 && containsT1)\n\t\t\tresult_SP = gStaticEidosValue_Logical_ZeroVec;\n\t\telse if (containsT0 && containsF0 && !containsT1 && !containsF1)\n\t\t{\n\t\t\t// CODE COVERAGE: This is dead code\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(2);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(false, 0);\n\t\t\tlogical_result->set_logical_no_check(true, 1);\n\t\t}\n\t\telse if (containsT0 && !containsT1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t\telse if (containsF0 && !containsF1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t\telse\n\t\t\tresult_SP = gStaticEidosValue_Logical_ZeroVec;\n\t\t// NOLINTEND(*-branch-clone)\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// If both arguments are singleton, handle that case with a simple equality check\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int0 = x_value->IntAtIndex_NOCAST(0, nullptr), int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (int0 == int1)\n\t\t\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(int0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float0 = x_value->FloatAtIndex_NOCAST(0, nullptr), float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float0 == float1))\n\t\t\t\tresult_SP = gStaticEidosValue_Float_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(float0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (string0 == string1)\n\t\t\t\tresult_SP = gStaticEidosValue_String_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(string0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr), *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (obj0 == obj1)\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(obj0, ((EidosValue_Object *)x_value)->Class()));\n\t\t}\n\t}\n\telse if (x_count == 1)\n\t{\n\t\t// If any element in y matches the element in x, the result is an empty vector\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int0 = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *int_data = y_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t\tif (int0 == int_data[value_index])\n\t\t\t\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(int0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float0 = x_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *float_data = y_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble float1 = float_data[value_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float0 == float1))\n\t\t\t\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(float0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string *string_vec = y_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t\tif (string0 == string_vec[value_index])\n\t\t\t\t\treturn gStaticEidosValue_String_ZeroVec;\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(string0));\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject * const *object_vec = y_value->ObjectData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t\tif (obj0 == object_vec[value_index])\n\t\t\t\t\treturn x_value->NewMatchingType();\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(obj0, ((EidosValue_Object *)x_value)->Class()));\n\t\t}\n\t}\n\telse if (y_count == 1)\n\t{\n\t\t// The result is x uniqued, minus the element in y if it matches\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t\t\n\t\tint result_count = result_SP->Count();\n\t\t\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int *int_vec = (EidosValue_Int *)result_SP.get();\n\t\t\tconst int64_t *int_data = int_vec->data();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (int1 == int_data[value_index])\n\t\t\t\t{\n\t\t\t\t\tint_vec->erase_index(value_index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float *float_vec = (EidosValue_Float *)result_SP.get();\n\t\t\tdouble *float_data = float_vec->FloatData_Mutable();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble float0 = float_data[value_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(float1) && std::isnan(float0)) || (float1 == float0))\n\t\t\t\t{\n\t\t\t\t\tfloat_vec->erase_index(value_index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_String *string_vector_obj = (EidosValue_String *)result_SP.get();\n\t\t\tstd::vector<std::string> &string_vec = string_vector_obj->StringVectorData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (string1 == string_vec[value_index])\n\t\t\t\t{\n\t\t\t\t\tstring_vec.erase(string_vec.begin() + value_index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Object *object_element_vec = (EidosValue_Object *)result_SP.get();\n\t\t\tEidosObject * const *object_element_data = object_element_vec->data();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (obj1 == object_element_data[value_index])\n\t\t\t\t{\n\t\t\t\t\tobject_element_vec->erase_index(value_index);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Both arguments have size >1, so we can use fast APIs for both\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\t\tconst int64_t *int_data1 = y_value->IntData();\n\t\t\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tint64_t value = int_data0[value_index0];\n\t\t\t\tint value_index1, scan_index;\n\t\t\t\t\n\t\t\t\t// First check that the value does not exist in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == int_data1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 < y_count)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\tif (value == int_data0[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (scan_index < value_index0)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tint_result->push_int(value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data0 = x_value->FloatData();\n\t\t\tconst double *float_data1 = y_value->FloatData();\n\t\t\tEidosValue_Float *float_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tdouble value0 = float_data0[value_index0];\n\t\t\t\tint value_index1, scan_index;\n\t\t\t\t\n\t\t\t\t// First check that the value does not exist in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t{\n\t\t\t\t\tdouble value1 = float_data1[value_index1];\n\t\t\t\t\t\n\t\t\t\t\tif ((std::isnan(value0) && std::isnan(value1)) || (value0 == value1))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (value_index1 < y_count)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t{\n\t\t\t\t\tdouble value_scan = float_data0[scan_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((std::isnan(value0) && std::isnan(value_scan)) || (value0 == value_scan))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (scan_index < value_index0)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tfloat_result->push_float(value0);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\t\tconst std::string *string_vec1 = y_value->StringData();\n\t\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tstd::string value = string_vec0[value_index0];\n\t\t\t\tint value_index1, scan_index;\n\t\t\t\t\n\t\t\t\t// First check that the value does not exist in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == string_vec1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 < y_count)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\tif (value == string_vec0[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (scan_index < value_index0)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tstring_result->PushString(value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject * const *object_vec0 = x_value->ObjectData();\n\t\t\tEidosObject * const *object_vec1 = y_value->ObjectData();\n\t\t\tEidosValue_Object *object_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)x_value)->Class());\n\t\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tEidosObject *value = object_vec0[value_index0];\n\t\t\t\tint value_index1, scan_index;\n\t\t\t\t\n\t\t\t\t// First check that the value does not exist in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == object_vec1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 < y_count)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\tif (value == object_vec0[scan_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (scan_index < value_index0)\n\t\t\t\t\tcontinue;\n\t\t\t\t\n\t\t\t\tobject_result->push_object_element_CRR(value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(*)setIntersection(* x, * y)\nEidosValue_SP Eidos_ExecuteFunction_setIntersection(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setIntersection): function setIntersection() requires that both operands have the same type.\" << EidosTerminate(nullptr);\n\t\n\tEidosValueType arg_type = x_type;\n\tconst EidosClass *class0 = nullptr, *class1 = nullptr;\n\t\n\tif (arg_type == EidosValueType::kValueObject)\n\t{\n\t\tclass0 = ((EidosValue_Object *)x_value)->Class();\n\t\tclass1 = ((EidosValue_Object *)y_value)->Class();\n\t\t\n\t\tif ((class0 != class1) && (class0 != gEidosObject_Class) && (class1 != gEidosObject_Class))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setIntersection): function setIntersection() requires that both operands of object type have the same class (or undefined class).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif ((x_count == 0) || (y_count == 0))\n\t{\n\t\t// If either argument is empty, the intersection is the empty set\n\t\tif (class1 && (class1 != gEidosObject_Class))\n\t\t\tresult_SP = y_value->NewMatchingType();\n\t\telse\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse if (arg_type == EidosValueType::kValueLogical)\n\t{\n\t\t// Because EidosValue_Logical works differently than other EidosValue types, this code can handle\n\t\t// both the singleton and non-singleton cases\n\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\tconst eidos_logical_t *logical_data1 = y_value->LogicalData();\n\t\tbool containsF0 = false, containsT0 = false, containsF1 = false, containsT1 = false;\n\t\t\n\t\tif (logical_data0[0])\n\t\t{\n\t\t\tcontainsT0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (!logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (logical_data1[0])\n\t\t{\n\t\t\tcontainsT1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (!logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (containsF0 && containsT0 && containsF1 && containsT1)\n\t\t{\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(2);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(false, 0);\n\t\t\tlogical_result->set_logical_no_check(true, 1);\n\t\t}\n\t\telse if (containsF0 && containsF1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t\telse if (containsT0 && containsT1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t\telse\n\t\t\tresult_SP = gStaticEidosValue_Logical_ZeroVec;\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// If both arguments are singleton, handle that case with a simple equality check\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int0 = x_value->IntAtIndex_NOCAST(0, nullptr), int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (int0 == int1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(int0));\n\t\t\telse\n\t\t\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float0 = x_value->FloatAtIndex_NOCAST(0, nullptr), float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float0 == float1))\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(float0));\n\t\t\telse\n\t\t\t\tresult_SP = gStaticEidosValue_Float_ZeroVec;\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (string0 == string1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(string0));\n\t\t\telse\n\t\t\t\tresult_SP = gStaticEidosValue_String_ZeroVec;\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr), *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (obj0 == obj1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(obj0, ((EidosValue_Object *)x_value)->Class()));\n\t\t\telse\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t}\n\t}\n\telse if ((x_count == 1) || (y_count == 1))\n\t{\n\t\t// If either argument is singleton (but not both), handle that case with a fast check\n\t\tif (x_count == 1)\n\t\t{\n\t\t\tstd::swap(x_count, y_count);\n\t\t\tstd::swap(x_value, y_value);\n\t\t}\n\t\t\n\t\t// now x_count > 1, y_count == 1\n\t\tbool found_match = false;\n\t\t\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t value = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\t\n\t\t\tfor (int scan_index = 0; scan_index < x_count; ++scan_index)\n\t\t\t\tif (value == int_data[scan_index])\n\t\t\t\t{\n\t\t\t\t\tfound_match = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble value0 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\t\n\t\t\tfor (int scan_index = 0; scan_index < x_count; ++scan_index)\n\t\t\t{\n\t\t\t\tdouble value1 = float_data[scan_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(value0) && std::isnan(value1)) || (value0 == value1))\n\t\t\t\t{\n\t\t\t\t\tfound_match = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &value = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\t\n\t\t\tfor (int scan_index = 0; scan_index < x_count; ++scan_index)\n\t\t\t\tif (value == string_vec[scan_index])\n\t\t\t\t{\n\t\t\t\t\tfound_match = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *value = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject * const *object_vec = x_value->ObjectData();\n\t\t\t\n\t\t\tfor (int scan_index = 0; scan_index < x_count; ++scan_index)\n\t\t\t\tif (value == object_vec[scan_index])\n\t\t\t\t{\n\t\t\t\t\tfound_match = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (found_match)\n\t\t\tresult_SP = y_value->CopyValues();\n\t\telse\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse\n\t{\n\t\t// Both arguments have size >1, so we can use fast APIs for both\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\t\tconst int64_t *int_data1 = y_value->IntData();\n\t\t\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tint64_t value = int_data0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (int value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == int_data1[value_index1])\n\t\t\t\t\t{\n\t\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\t\tint scan_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (value == int_data0[scan_index])\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\t\tint_result->push_int(value);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data0 = x_value->FloatData();\n\t\t\tconst double *float_data1 = y_value->FloatData();\n\t\t\tEidosValue_Float *float_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tdouble value0 = float_data0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (int value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t{\n\t\t\t\t\tdouble value1 = float_data1[value_index1];\n\t\t\t\t\t\n\t\t\t\t\tif ((std::isnan(value0) && std::isnan(value1)) || (value0 == value1))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\t\tint scan_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble value_scan = float_data0[scan_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((std::isnan(value0) && std::isnan(value_scan)) || (value0 == value_scan))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\t\tfloat_result->push_float(value0);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\t\tconst std::string *string_vec1 = y_value->StringData();\n\t\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tstd::string value = string_vec0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (int value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == string_vec1[value_index1])\n\t\t\t\t\t{\n\t\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\t\tint scan_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (value == string_vec0[scan_index])\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\t\tstring_result->PushString(value);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject * const *object_vec0 = x_value->ObjectData();\n\t\t\tEidosObject * const *object_vec1 = y_value->ObjectData();\n\t\t\tEidosValue_Object *object_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)x_value)->Class());\n\t\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\t\n\t\t\tfor (int value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tEidosObject *value = object_vec0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (int value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == object_vec1[value_index1])\n\t\t\t\t\t{\n\t\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\t\tint scan_index;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (value == object_vec0[scan_index])\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\t\tobject_result->push_object_element_CRR(value);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(*)setSymmetricDifference(* x, * y)\nEidosValue_SP Eidos_ExecuteFunction_setSymmetricDifference(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setSymmetricDifference): function setSymmetricDifference() requires that both operands have the same type.\" << EidosTerminate(nullptr);\n\t\n\tEidosValueType arg_type = x_type;\n\tconst EidosClass *class0 = nullptr, *class1 = nullptr;\n\t\n\tif (arg_type == EidosValueType::kValueObject)\n\t{\n\t\tclass0 = ((EidosValue_Object *)x_value)->Class();\n\t\tclass1 = ((EidosValue_Object *)y_value)->Class();\n\t\t\n\t\tif ((class0 != class1) && (class0 != gEidosObject_Class) && (class1 != gEidosObject_Class))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setSymmetricDifference): function setSymmetricDifference() requires that both operands of object type have the same class (or undefined class).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (x_count + y_count == 0)\n\t{\n\t\tif (class1 && (class1 != gEidosObject_Class))\n\t\t\tresult_SP = y_value->NewMatchingType();\n\t\telse\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse if ((x_count == 1) && (y_count == 0))\n\t{\n\t\tresult_SP = x_value->CopyValues();\n\t}\n\telse if ((x_count == 0) && (y_count == 1))\n\t{\n\t\tresult_SP = y_value->CopyValues();\n\t}\n\telse if (x_count == 0)\n\t{\n\t\tresult_SP = UniqueEidosValue(y_value, true);\n\t}\n\telse if (y_count == 0)\n\t{\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t}\n\telse if (arg_type == EidosValueType::kValueLogical)\n\t{\n\t\t// Because EidosValue_Logical works differently than other EidosValue types, this code can handle\n\t\t// both the singleton and non-singleton cases\n\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\tconst eidos_logical_t *logical_data1 = y_value->LogicalData();\n\t\tbool containsF0 = false, containsT0 = false, containsF1 = false, containsT1 = false;\n\t\t\n\t\tif (logical_data0[0])\n\t\t{\n\t\t\tcontainsT0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (!logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF0 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t\tif (logical_data0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT0 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (logical_data1[0])\n\t\t{\n\t\t\tcontainsT1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (!logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontainsF1 = true;\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < y_count; ++value_index)\n\t\t\t\tif (logical_data1[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT1 = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif ((containsF0 != containsF1) && (containsT0 != containsT1))\n\t\t{\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(2);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(false, 0);\n\t\t\tlogical_result->set_logical_no_check(true, 1);\n\t\t}\n\t\telse if ((containsF0 == containsF1) && (containsT0 == containsT1))\n\t\t\tresult_SP = gStaticEidosValue_Logical_ZeroVec;\n\t\telse if (containsT0 != containsT1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t\telse // (containsF0 != containsF1)\n\t\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// If both arguments are singleton, handle that case with a simple equality check\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int0 = x_value->IntAtIndex_NOCAST(0, nullptr), int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (int0 == int1)\n\t\t\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{int0, int1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float0 = x_value->FloatAtIndex_NOCAST(0, nullptr), float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float0 == float1))\n\t\t\t\tresult_SP = gStaticEidosValue_Float_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{float0, float1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (string0 == string1)\n\t\t\t\tresult_SP = gStaticEidosValue_String_ZeroVec;\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String{string0, string1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr), *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (obj0 == obj1)\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object({obj0, obj1}, ((EidosValue_Object *)x_value)->Class()));\n\t\t}\n\t}\n\telse if ((x_count == 1) || (y_count == 1))\n\t{\n\t\t// We have one value that is a singleton, one that is a vector.  We'd like this case to be fast,\n\t\t// so that addition of a single element to a set is a fast operation.\n\t\tif (x_count == 1)\n\t\t{\n\t\t\tstd::swap(x_count, y_count);\n\t\t\tstd::swap(x_value, y_value);\n\t\t}\n\t\t\n\t\t// now x_count > 1, y_count == 1\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t\t\n\t\tint result_count = result_SP->Count();\n\t\t\n\t\t// result_SP is modifiable and is guaranteed to be a vector, so now the result is x uniqued,\n\t\t// minus the element in y if it matches, but plus the element in y if it does not match\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int *int_vec = (EidosValue_Int *)result_SP.get();\n\t\t\tconst int64_t *int_data = int_vec->data();\n\t\t\tint value_index;\n\t\t\t\n\t\t\tfor (value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (int1 == int_data[value_index])\n\t\t\t\t\tbreak;\n\t\t\t\n\t\t\tif (value_index == result_count)\n\t\t\t\tint_vec->push_int(int1);\n\t\t\telse\n\t\t\t\tint_vec->erase_index(value_index);\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float *float_vec = (EidosValue_Float *)result_SP.get();\n\t\t\tdouble *float_data = float_vec->FloatData_Mutable();\n\t\t\tint value_index;\n\t\t\t\n\t\t\tfor (value_index = 0; value_index < result_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble float0 = float_data[value_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float1 == float0))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (value_index == result_count)\n\t\t\t\tfloat_vec->push_float(float1);\n\t\t\telse\n\t\t\t\tfloat_vec->erase_index(value_index);\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_String *string_vector_obj = (EidosValue_String *)result_SP.get();\n\t\t\tstd::vector<std::string> &string_vec = string_vector_obj->StringVectorData();\n\t\t\tint value_index;\n\t\t\t\n\t\t\tfor (value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (string1 == string_vec[value_index])\n\t\t\t\t\tbreak;\n\t\t\t\n\t\t\tif (value_index == result_count)\n\t\t\t\tstring_vec.emplace_back(string1);\n\t\t\telse\n\t\t\t\tstring_vec.erase(string_vec.begin() + value_index);\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Object *object_element_vec = (EidosValue_Object *)result_SP.get();\n\t\t\tEidosObject * const *object_element_data = object_element_vec->data();\n\t\t\tint value_index;\n\t\t\t\n\t\t\tfor (value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\tif (obj1 == object_element_data[value_index])\n\t\t\t\t\tbreak;\n\t\t\t\n\t\t\tif (value_index == result_count)\n\t\t\t\tobject_element_vec->push_object_element_CRR(obj1);\n\t\t\telse\n\t\t\t\tobject_element_vec->erase_index(value_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Both arguments have size >1, so we can use fast APIs for both.  Loop through x adding\n\t\t// unique values not in y, then loop through y adding unique values not in x.\n\t\tint value_index0, value_index1, scan_index;\n\t\t\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\t\tconst int64_t *int_data1 = y_value->IntData();\n\t\t\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tint64_t value = int_data0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == int_data1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 == y_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\tif (value == int_data0[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\tint_result->push_int(value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t{\n\t\t\t\tint64_t value = int_data1[value_index1];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t\t\tif (value == int_data0[value_index0])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index0 == x_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index1; ++scan_index)\n\t\t\t\t\t\tif (value == int_data1[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index1)\n\t\t\t\t\t\tint_result->push_int(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_vec0 = x_value->FloatData();\n\t\t\tconst double *float_vec1 = y_value->FloatData();\n\t\t\tEidosValue_Float *float_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tdouble value0 = float_vec0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t{\n\t\t\t\t\tdouble float1 = float_vec1[value_index1];\n\t\t\t\t\t\n\t\t\t\t\tif ((std::isnan(value0) && std::isnan(float1)) || (value0 == float1))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (value_index1 == y_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble value_scan = float_vec0[scan_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((std::isnan(value0) && std::isnan(value_scan)) || (value0 == value_scan))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\tfloat_result->push_float(value0);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t{\n\t\t\t\tdouble value1 = float_vec1[value_index1];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t\t{\n\t\t\t\t\tdouble value0 = float_vec0[value_index0];\n\t\t\t\t\t\n\t\t\t\t\tif ((std::isnan(value1) && std::isnan(value0)) || (value1 == value0))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (value_index0 == x_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index1; ++scan_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble value_scan = float_vec1[scan_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((std::isnan(value1) && std::isnan(value_scan)) || (value1 == value_scan))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index1)\n\t\t\t\t\t\tfloat_result->push_float(value1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\t\tconst std::string *string_vec1 = y_value->StringData();\n\t\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tstd::string value = string_vec0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == string_vec1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 == y_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\tif (value == string_vec0[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\tstring_result->PushString(value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t{\n\t\t\t\tstd::string value = string_vec1[value_index1];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t\t\tif (value == string_vec0[value_index0])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index0 == x_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index1; ++scan_index)\n\t\t\t\t\t\tif (value == string_vec1[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index1)\n\t\t\t\t\t\tstring_result->PushString(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject * const *object_vec0 = x_value->ObjectData();\n\t\t\tEidosObject * const *object_vec1 = y_value->ObjectData();\n\t\t\tEidosValue_Object *object_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)x_value)->Class());\n\t\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\t\n\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t{\n\t\t\t\tEidosObject *value = object_vec0[value_index0];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t\t\tif (value == object_vec1[value_index1])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index1 == y_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index0; ++scan_index)\n\t\t\t\t\t\tif (value == object_vec0[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index0)\n\t\t\t\t\t\tobject_result->push_object_element_CRR(value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (value_index1 = 0; value_index1 < y_count; ++value_index1)\n\t\t\t{\n\t\t\t\tEidosObject *value = object_vec1[value_index1];\n\t\t\t\t\n\t\t\t\t// First check that the value also exists in y\n\t\t\t\tfor (value_index0 = 0; value_index0 < x_count; ++value_index0)\n\t\t\t\t\tif (value == object_vec0[value_index0])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tif (value_index0 == x_count)\n\t\t\t\t{\n\t\t\t\t\t// Then check that we have not already handled the same value (uniquing)\n\t\t\t\t\tfor (scan_index = 0; scan_index < value_index1; ++scan_index)\n\t\t\t\t\t\tif (value == object_vec1[scan_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tif (scan_index == value_index1)\n\t\t\t\t\t\tobject_result->push_object_element_CRR(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(*)setUnion(* x, * y)\nEidosValue_SP Eidos_ExecuteFunction_setUnion(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setUnion): function setUnion() requires that both operands have the same type.\" << EidosTerminate(nullptr);\n\t\n\tEidosValueType arg_type = x_type;\n\tconst EidosClass *class0 = nullptr, *class1 = nullptr;\n\t\n\tif (arg_type == EidosValueType::kValueObject)\n\t{\n\t\tclass0 = ((EidosValue_Object *)x_value)->Class();\n\t\tclass1 = ((EidosValue_Object *)y_value)->Class();\n\t\t\n\t\tif ((class0 != class1) && (class0 != gEidosObject_Class) && (class1 != gEidosObject_Class))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_setUnion): function setUnion() requires that both operands of object type have the same class (or undefined class).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (x_count + y_count == 0)\n\t{\n\t\tif (class1 && (class1 != gEidosObject_Class))\n\t\t\tresult_SP = y_value->NewMatchingType();\n\t\telse\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t}\n\telse if ((x_count == 1) && (y_count == 0))\n\t{\n\t\tresult_SP = x_value->CopyValues();\n\t}\n\telse if ((x_count == 0) && (y_count == 1))\n\t{\n\t\tresult_SP = y_value->CopyValues();\n\t}\n\telse if (arg_type == EidosValueType::kValueLogical)\n\t{\n\t\t// Because EidosValue_Logical works differently than other EidosValue types, this code can handle\n\t\t// both the singleton and non-singleton cases\n\t\tconst eidos_logical_t *logical_vec0 = x_value->LogicalData();\n\t\tconst eidos_logical_t *logical_vec1 = y_value->LogicalData();\n\t\tbool containsF = false, containsT = false;\n\t\t\n\t\tif (((x_count > 0) && logical_vec0[0]) || ((y_count > 0) && logical_vec1[0]))\n\t\t{\n\t\t\t// We have a true value; look for a false value\n\t\t\tcontainsT = true;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tif (!logical_vec0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsF = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\n\t\t\tif (!containsF)\n\t\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t\t\tif (!logical_vec1[value_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tcontainsF = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have a false value; look for a true value\n\t\t\tcontainsF = true;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tif (logical_vec0[value_index])\n\t\t\t\t{\n\t\t\t\t\tcontainsT = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\n\t\t\tif (!containsT)\n\t\t\t\tfor (int value_index = 0; value_index < y_count; ++value_index)\n\t\t\t\t\tif (logical_vec1[value_index])\n\t\t\t\t\t{\n\t\t\t\t\t\tcontainsT = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (containsF && !containsT)\n\t\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t\telse if (containsT && !containsF)\n\t\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t\telse if (!containsT && !containsF)\n\t\t\tresult_SP = gStaticEidosValue_Logical_ZeroVec;\t\t// CODE COVERAGE: This is dead code\n\t\telse\t// containsT && containsF\n\t\t{\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(2);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(false, 0);\n\t\t\tlogical_result->set_logical_no_check(true, 1);\n\t\t}\n\t}\n\telse if (x_count == 0)\n\t{\n\t\t// x is zero-length, y is >1, so we just need to unique y\n\t\tresult_SP = UniqueEidosValue(y_value, true);\n\t}\n\telse if (y_count == 0)\n\t{\n\t\t// y is zero-length, x is >1, so we just need to unique x\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// Make a bit of an effort to produce a singleton result, while handling the singleton/singleton case\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t int0 = x_value->IntAtIndex_NOCAST(0, nullptr), int1 = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (int0 == int1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(int0));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{int0, int1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble float0 = x_value->FloatAtIndex_NOCAST(0, nullptr), float1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((std::isnan(float0) && std::isnan(float1)) || (float0 == float1))\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(float0));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float{float0, float1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &string0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &string1 = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (string0 == string1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(string0));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String{string0, string1});\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *obj0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr), *obj1 = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (obj0 == obj1)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(obj0, ((EidosValue_Object *)x_value)->Class()));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object({obj0, obj1}, ((EidosValue_Object *)x_value)->Class()));\n\t\t}\n\t}\n\telse if ((x_count == 1) || (y_count == 1))\n\t{\n\t\t// We have one value that is a singleton, one that is a vector.  We'd like this case to be fast,\n\t\t// so that addition of a single element to a set is a fast operation.\n\t\tif (x_count == 1)\n\t\t{\n\t\t\tstd::swap(x_count, y_count);\n\t\t\tstd::swap(x_value, y_value);\n\t\t}\n\t\t\n\t\t// now x_count > 1, y_count == 1\n\t\tresult_SP = UniqueEidosValue(x_value, true);\n\t\t\n\t\tint result_count = result_SP->Count();\n\t\t\n\t\t// result_SP is modifiable and is guaranteed to be a vector, so now add y if necessary using the fast APIs\n\t\tif (arg_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t value = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *int_data = result_SP->IntData();\n\t\t\tint scan_index;\n\t\t\t\n\t\t\tfor (scan_index = 0; scan_index < result_count; ++scan_index)\n\t\t\t{\n\t\t\t\tif (value == int_data[scan_index])\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (scan_index == result_count)\n\t\t\t{\n\t\t\t\tEidosValue_Int *int_vec = (EidosValue_Int *)result_SP.get();\n\t\t\t\t\n\t\t\t\tint_vec->push_int(value);\n\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble value1 = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *float_data = result_SP->FloatData();\n\t\t\tint scan_index;\n\t\t\t\n\t\t\tfor (scan_index = 0; scan_index < result_count; ++scan_index)\n\t\t\t{\n\t\t\t\tdouble value0 = float_data[scan_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(value1) && std::isnan(value0)) || (value1 == value0))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (scan_index == result_count)\n\t\t\t{\n\t\t\t\tEidosValue_Float *float_vec = (EidosValue_Float *)result_SP.get();\n\t\t\t\t\n\t\t\t\tfloat_vec->push_float(value1);\n\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &value = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string *string_data = result_SP->StringData();\n\t\t\tint scan_index;\n\t\t\t\n\t\t\tfor (scan_index = 0; scan_index < result_count; ++scan_index)\n\t\t\t{\n\t\t\t\tif (value == string_data[scan_index])\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (scan_index == result_count)\n\t\t\t{\n\t\t\t\tEidosValue_String *string_vector_obj = (EidosValue_String *)result_SP.get();\n\t\t\t\tstd::vector<std::string> &string_vec = string_vector_obj->StringVectorData();\n\t\t\t\t\n\t\t\t\tstring_vec.emplace_back(value);\n\t\t\t}\n\t\t}\n\t\telse if (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *value = y_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject * const *object_data = result_SP->ObjectData();\n\t\t\tint scan_index;\n\t\t\t\n\t\t\tfor (scan_index = 0; scan_index < result_count; ++scan_index)\n\t\t\t{\n\t\t\t\tif (value == object_data[scan_index])\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (scan_index == result_count)\n\t\t\t{\n\t\t\t\tEidosValue_Object *object_element_vec = (EidosValue_Object *)result_SP.get();\n\t\t\t\t\n\t\t\t\tobject_element_vec->push_object_element_CRR(value);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We have two arguments which are both vectors of >1 value, so this is the base case.  We construct\n\t\t// a new EidosValue containing all elements from both arguments, and then call UniqueEidosValue() to unique it.\n\t\t// This code might look slow, but really the uniquing is O(N^2) and everything else is O(N), so since\n\t\t// we are in the vector/vector case here, it really isn't worth worrying about optimizing the O(N) part.\n\t\tresult_SP = ConcatenateEidosValues(p_arguments, false, false);\t// no NULL, no VOID\n\t\tresult_SP = UniqueEidosValue(result_SP.get(), true);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)sign(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_sign(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tint64_t *int_result_data = int_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\t// PARALLELIZE ME\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tint64_t element = int_data[value_index];\n\t\t\t\n\t\t\tif (element > 0)\n\t\t\t\tint_result_data[value_index] = 1;\n\t\t\telse if (element < 0)\n\t\t\t\tint_result_data[value_index] = -1;\n\t\t\telse\n\t\t\t\tint_result_data[value_index] = 0;\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\t// PARALLELIZE ME\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tdouble element = float_data[value_index];\n\t\t\t\n\t\t\tif (element > 0)\n\t\t\t\tfloat_result_data[value_index] = 1.0;\n\t\t\telse if (element < 0)\n\t\t\t\tfloat_result_data[value_index] = -1.0;\n\t\t\telse if (std::isnan(element))\n\t\t\t\tfloat_result_data[value_index] = std::numeric_limits<double>::quiet_NaN();\n\t\t\telse\n\t\t\t\tfloat_result_data[value_index] = 0.0;\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)sin(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_sin(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(sin(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::sin_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)sqrt(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_sqrt(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(sqrt(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SQRT_FLOAT);\n\t\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_SQRT_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result_data[value_index] = sqrt(float_data[value_index]);\n#else\n\t\tEidos_SIMD::sqrt_float64(float_data, float_result_data, x_count);\n#endif\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(numeric$)sum(lif x)\nEidosValue_SP Eidos_ExecuteFunction_sum(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// BEWARE: this is called by Eidos_ExecuteFunction_mean(), which assumes that arguments match!\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tif (x_count == 1)\n\t\t{\n\t\t\t// Worth treating the singleton case separately given the complexity below\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(x_value->IntAtIndex_NOCAST(0, nullptr)));\n\t\t}\n\t\telse\n#ifndef _OPENMP\n\t\t{\n\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\tint64_t sum = 0;\n\t\t\tdouble sum_d = 0;\n\t\t\tbool fits_in_integer = true;\n\t\t\t\n\t\t\t// We do a tricky thing here.  We want to try to compute in integer, but switch to float if we overflow.\n\t\t\t// If we do overflow, we want to minimize numerical error by accumulating in integer for as long as we\n\t\t\t// can, and then throwing the integer accumulator over into the float accumulator only when it is about\n\t\t\t// to overflow.  We perform both computations in parallel, and use integer for the result if we can.\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t old_sum = sum;\n\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\t\n\t\t\t\tbool overflow = Eidos_add_overflow(old_sum, temp, &sum);\n\t\t\t\t\n\t\t\t\t// switch to float computation on overflow, and accumulate in the float sum just before overflow\n\t\t\t\tif (overflow)\n\t\t\t\t{\n\t\t\t\t\tfits_in_integer = false;\n\t\t\t\t\tsum_d += old_sum;\n\t\t\t\t\tsum = temp;\t\t// start integer accumulation again from 0 until it overflows again\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tsum_d += sum;\t\t\t// add in whatever integer accumulation has not overflowed\n\t\t\t\n\t\t\tif (fits_in_integer)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(sum));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sum_d));\n\t\t}\n#else\n\t\t{\n\t\t\t// In the OpenMP case we want to follow fairly different logic, because dealing with catching the overflow\n\t\t\t// case across multiple threads seems excessively complex; instead we look for an overflow afterwards\n\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\tdouble sum_d = 0;\n\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SUM_INTEGER);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(int_data) reduction(+: sum_d) if(parallel:x_count >= EIDOS_OMPMIN_SUM_INTEGER) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tsum_d += int_data[value_index];\n\n\t\t\t// 2^53 is the largest integer such that it and all smaller integers can be represented in double losslessly\n\t\t\tint64_t sum = (int64_t)sum_d;\n\t\t\tbool fits_in_integer = (((double)sum == sum_d) && (sum < 9007199254740992L) && (sum > -9007199254740992L));\n\n\t\t\tif (fits_in_integer)\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(sum));\n\t\t\telse\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sum_d));\n\t\t}\n#endif\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tdouble sum = 0;\n\t\t\n#ifdef _OPENMP\n\t\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SUM_FLOAT);\n\t\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data) reduction(+: sum) if(parallel:x_count >= EIDOS_OMPMIN_SUM_FLOAT) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tsum += float_data[value_index];\n#else\n\t\tsum = Eidos_SIMD::sum_float64(float_data, x_count);\n#endif\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sum));\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\tint64_t sum = 0;\n\t\t\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SUM_LOGICAL);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(logical_data) reduction(+: sum) if(parallel:x_count >= EIDOS_OMPMIN_SUM_LOGICAL) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tsum += logical_data[value_index];\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(sum));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float$)sumExact(float x)\nEidosValue_SP Eidos_ExecuteFunction_sumExact(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 1)\n\t{\n\t\t// Worth treating the singleton case separately given the complexity below\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(x_value->FloatAtIndex_NOCAST(0, nullptr)));\n\t}\n\telse\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tdouble sum = Eidos_ExactSum(float_data, x_count);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sum));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)tan(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_tan(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tfloat_result->set_float_no_check(tan(x_value->NumericAtIndex_NOCAST(value_index, nullptr)), value_index);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\tdouble *float_result_data = float_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\n\t\tEidos_SIMD::tan_float64(float_data, float_result_data, x_count);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)trunc(float x)\nEidosValue_SP Eidos_ExecuteFunction_trunc(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tconst double *float_data = x_value->FloatData();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tdouble *float_result_data = float_result->data_mutable();\n\tresult_SP = EidosValue_SP(float_result);\n\t\n#ifdef _OPENMP\n\t// FIXME: refactor this parallel code to use the Eidos_SIMD code path, chunked; see github.com/MesserLab/SLiM/pull/578#issuecomment-3640288984\n\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_TRUNC);\n\t#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(float_data, float_result_data) if(parallel:x_count >= EIDOS_OMPMIN_TRUNC) num_threads(thread_count)\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tfloat_result_data[value_index] = trunc(float_data[value_index]);\n#else\n\tEidos_SIMD::trunc_float64(float_data, float_result_data, x_count);\n#endif\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_matrices.cpp",
    "content": "//\n//  eidos_functions_matrices.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n\n#include <utility>\n#include <vector>\n#include <algorithm>\n\n#include \"gsl_linalg.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_errno.h\"\n\n\n// ************************************************************************************\n//\n//\tmatrix and array functions\n//\n\n#pragma mark -\n#pragma mark Matrix and array functions\n#pragma mark -\n\n\n//\t(*)apply(* x, integer margin, string$ lambdaSource)\nEidosValue_SP Eidos_ExecuteFunction_apply(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_dimcount = x_value->DimensionCount();\n\tconst int64_t *x_dim = x_value->Dimensions();\n\t\n\tif (x_dimcount < 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): function apply() requires parameter x to be a matrix or array.\" << std::endl << \"NOTE: The apply() function was renamed sapply() in Eidos 1.6, and a new function named apply() has been added; you may need to change this call to be a call to sapply() instead.\" << EidosTerminate(nullptr);\n\t\n\t// Determine the margins requested and check their validity\n\tEidosValue *margin_value = p_arguments[1].get();\n\tint margin_count = margin_value->Count();\n\tstd::vector<int> margins;\n\tstd::vector<int64_t> margin_sizes;\n\t\n\tif (margin_count <= 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): function apply() requires that margins be specified.\" << EidosTerminate(nullptr);\n\t\n\tfor (int margin_index = 0; margin_index < margin_count; ++margin_index)\n\t{\n\t\tint64_t margin = margin_value->IntAtIndex_NOCAST(margin_index, nullptr);\n\t\t\n\t\tif ((margin < 0) || (margin >= x_dimcount))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): specified margin \" << margin << \" is out of range in function apply(); margin indices are zero-based, and thus must be from 0 to size(dim(x)) - 1.\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (int margin_index_2 = 0; margin_index_2 < margin_index; ++margin_index_2)\n\t\t{\n\t\t\tint64_t margin_2 = margin_value->IntAtIndex_NOCAST(margin_index_2, nullptr);\n\t\t\t\n\t\t\tif (margin_2 == margin)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): specified margin \" << margin << \" was already specified to function apply(); a given margin may be specified only once.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tmargins.emplace_back((int)margin);\n\t\tmargin_sizes.emplace_back(x_dim[margin]);\n\t}\n\t\n\t// Get the lambda string and cache its script\n\tEidosValue *lambda_value = p_arguments[2].get();\n\tEidosValue_String *lambda_value_singleton = (EidosValue_String *)p_arguments[2].get();\n\tEidosScript *script = lambda_value_singleton->CachedScript();\n\t\n\t// Errors in lambdas should be reported for the lambda script, not for the calling script,\n\t// if possible.  In the GUI this does not work well, however; there, errors should be\n\t// reported as occurring in the call to sapply().  Here we save off the current\n\t// error context and set up the error context for reporting errors inside the lambda,\n\t// in case that is possible; see how exceptions are handled below.\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\n\t// We try to do tokenization and parsing once per script, by caching the script inside the EidosValue_String_singleton instance\n\tif (!script)\n\t{\n\t\tscript = new EidosScript(lambda_value->StringAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\t\n\t\ttry\n\t\t{\n\t\t\tscript->Tokenize();\n\t\t\tscript->ParseInterpreterBlockToAST(false);\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tif (gEidosTerminateThrows)\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"Eidos_ExecuteFunction_apply()\");\n\t\t\t}\n\t\t\t\n\t\t\tdelete script;\n\t\t\t\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\tif (lambda_value_singleton)\n\t\t\tlambda_value_singleton->SetCachedScript(script);\n\t}\n\t\n\tstd::vector<EidosValue_SP> results;\n\t\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\n\ttry\n\t{\n\t\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\t\t\t\t\t\t\t\t\t// use our own symbol table\n\t\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\t\t\t\t\t\t\t\t// use our own function map\n\t\tEidosInterpreter interpreter(*script, symbols, function_map, p_interpreter.Context(), p_interpreter.ExecutionOutputStream(), p_interpreter.ErrorOutputStream()\n#ifdef SLIMGUI\n\t\t\t, p_interpreter.check_infinite_loops_\n#endif\n\t\t\t);\n\t\tbool consistent_return_length = true;\t// consistent across all values, including NULLs?\n\t\tint return_length = -1;\t\t\t\t\t// what the consistent length is\n\t\t\n\t\t// Set up inclusion_indices and inclusion_counts vectors as a skeleton for each marginal subset below\n\t\tstd::vector<std::vector<int64_t>> inclusion_indices;\t// the chosen indices for each dimension\n\t\tstd::vector<int> inclusion_counts;\t\t\t\t\t\t// the number of chosen indices for each dimension\n\t\t\n\t\tinclusion_indices.reserve(x_dimcount);\n\t\tinclusion_counts.reserve(x_dimcount);\n\t\t\n\t\tfor (int subset_index = 0; subset_index < x_dimcount; ++subset_index)\n\t\t{\n\t\t\tint dim_size = (int)x_dim[subset_index];\n\t\t\tstd::vector<int64_t> indices;\n\t\t\t\n\t\t\tindices.reserve(dim_size);\n\t\t\t\n\t\t\tfor (int dim_index = 0; dim_index < dim_size; ++dim_index)\n\t\t\t\tindices.emplace_back(dim_index);\n\t\t\t\n\t\t\tinclusion_counts.emplace_back((int)indices.size());\n\t\t\tinclusion_indices.emplace_back(indices);\n\t\t}\n\t\t\n\t\tfor (int margin_index = 0; margin_index < margin_count; ++margin_index)\n\t\t\tinclusion_counts[margins[margin_index]] = 1;\n\t\t\n\t\t// Iterate through each index for the marginal dimensions, in order\n\t\tstd::vector<int64_t> margin_counter(margin_count, 0);\n\t\t\n\t\tdo\n\t\t{\n\t\t\t// margin_counter has values for each margin; generate a slice through x with them\n\t\t\tfor (int margin_index = 0; margin_index < margin_count; ++margin_index)\n\t\t\t{\n\t\t\t\tint margin_dim = margins[margin_index];\n\t\t\t\t\n\t\t\t\tinclusion_indices[margin_dim].resize(0);\n\t\t\t\tinclusion_indices[margin_dim].emplace_back(margin_counter[margin_index]);\n\t\t\t}\n\t\t\t\n\t\t\tEidosValue_SP apply_value = x_value->Subset(inclusion_indices, true, nullptr);\n\t\t\t\n\t\t\t// Set the iterator variable \"applyValue\" to the value\n\t\t\tsymbols.SetValueForSymbolNoCopy(gEidosID_applyValue, std::move(apply_value));\n\t\t\t\n\t\t\t// Get the result.  BEWARE!  This calls causes re-entry into the Eidos interpreter, which is not usually\n\t\t\t// possible since Eidos does not support multithreaded usage.  This is therefore a key failure point for\n\t\t\t// bugs that would otherwise not manifest.\n\t\t\tEidosValue_SP &&return_value_SP = interpreter.EvaluateInterpreterBlock(false, true);\t\t// do not print output, return the last statement value\n\t\t\t\n\t\t\tif (return_value_SP->Type() == EidosValueType::kValueVOID)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): each iteration within apply() must return a non-void value.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (consistent_return_length)\n\t\t\t{\n\t\t\t\tint length = return_value_SP->Count();\n\t\t\t\t\n\t\t\t\tif (return_length == -1)\n\t\t\t\t\treturn_length = length;\n\t\t\t\telse if (length != return_length)\n\t\t\t\t\tconsistent_return_length = false;\n\t\t\t}\n\t\t\t\n\t\t\tresults.emplace_back(return_value_SP);\n\t\t\t\n\t\t\t// increment margin_counter in the base system of margin_sizes\n\t\t\tint margin_counter_index = 0;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (++margin_counter[margin_counter_index] == margin_sizes[margin_counter_index])\n\t\t\t\t{\n\t\t\t\t\tmargin_counter[margin_counter_index] = 0;\n\t\t\t\t\tmargin_counter_index++;\t\t// carry\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\twhile (margin_counter_index < margin_count);\n\t\t\t\n\t\t\t// if we carried out off the top, we are done iterating across all margins\n\t\t\tif (margin_counter_index == margin_count)\n\t\t\t\tbreak;\n\t\t}\n\t\twhile (true);\n\t\t\n\t\t// We do not want a leftover applyValue symbol in the symbol table, so we remove it now\n\t\tsymbols.RemoveValueForSymbol(gEidosID_applyValue);\n\t\t\n\t\t// Assemble all the individual results together, just as c() does\n\t\tresult_SP = ConcatenateEidosValues(results, true, false);\t// allow NULL but not VOID\n\t\t\n\t\t// Set the dimensions of the result.  If the returns from the lambda were not consistent in their\n\t\t// length and dimensions, we just return the plain vector without dimensions; we can't do anything\n\t\t// with it.  With returns of a consistent length n, (1) if n == 1, the return value will be a vector\n\t\t// if only one margin was used, or a matrix/array of dimension dim(x)[margin] if more than one\n\t\t// margin was used, (2) if n > 1, the return value will be an array of dimension c(n, dim(x)[margin]),\n\t\t// or (3) if n == 0, the return value will be a length zero vector of the appropriate type.  I think\n\t\t// we follow R's policy more or less exactly; that is my intent.\n\t\tif (consistent_return_length && (return_length > 0))\n\t\t{\n\t\t\tif (return_length == 1)\n\t\t\t{\n\t\t\t\tif (margin_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// do nothing and return a plain vector\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// dimensions of dim(x)[margin]; in other words, the sizes of the marginal dimensions of x, in the specified order of the margins\n\t\t\t\t\tresult_SP->SetDimensions(margin_count, margin_sizes.data());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse // return_length > 1)\n\t\t\t{\n\t\t\t\t// dimensions of c(n, dim(x)[margin]); in other words, n rows, and the marginal dim sizes after that\n\t\t\t\tint64_t *dims = (int64_t *)malloc((margin_count + 1) * sizeof(int64_t));\n\t\t\t\tif (!dims)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_apply): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tdims[0] = return_length;\n\t\t\t\t\n\t\t\t\tfor (int dim_index = 0; dim_index < margin_count; ++dim_index)\n\t\t\t\t\tdims[dim_index + 1] = margin_sizes[dim_index];\n\t\t\t\t\n\t\t\t\tresult_SP->SetDimensions(margin_count + 1, dims);\n\t\t\t\t\n\t\t\t\tfree(dims);\n\t\t\t}\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\t// If exceptions throw, then we want to set up the error information to highlight the\n\t\t// apply() that failed, since we can't highlight the actual error.  (If exceptions\n\t\t// don't throw, this catch block will never be hit; exit() will already have been called\n\t\t// and the error will have been reported from the context of the lambda script string.)\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"Eidos_ExecuteFunction_apply()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!lambda_value_singleton)\n\t\t\tdelete script;\n\t\t\n\t\tthrow;\n\t}\n\t\n\t// Restore the normal error context in the event that no exception occurring within the lambda\n\tgEidosErrorContext = error_context_save;\n\t\n\tif (!lambda_value_singleton)\n\t\tdelete script;\n\t\n\treturn result_SP;\n}\n\n// (*)array(* data, integer dim)\nEidosValue_SP Eidos_ExecuteFunction_array(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *data_value = p_arguments[0].get();\n\tEidosValue *dim_value = p_arguments[1].get();\n\t\n\tint data_count = data_value->Count();\n\tint dim_count = dim_value->Count();\n\t\n\tif (dim_count < 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_array): function array() requires at least two dimensions (i.e., at least a matrix)\" << EidosTerminate(nullptr);\n\t\n\tint64_t dim_product = 1;\n\t\n\tfor (int dim_index = 0; dim_index < dim_count; ++dim_index)\n\t{\n\t\tint64_t dim = dim_value->IntAtIndex_NOCAST(dim_index, nullptr);\n\t\t\n\t\tif (dim < 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_array): function array() requires that all dimensions be >= 1.\" << EidosTerminate(nullptr);\n\t\t\n\t\tdim_product *= dim;\n\t}\n\t\n\tif (data_count != dim_product)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_array): function array() requires a data vector with a length equal to the product of the proposed dimensions.\" << EidosTerminate(nullptr);\n\t\n\t// construct the array from the data and dimensions\n\tresult_SP = data_value->CopyValues();\n\t\n\tresult_SP->SetDimensions(dim_count, dim_value->IntData());\n\t\n\treturn result_SP;\n}\n\n// (*)cbind(...)\nEidosValue_SP Eidos_ExecuteFunction_cbind(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// First check the type and class of the result; NULL may be mixed in, but otherwise all arguments must be the same type and class\n\tEidosValueType result_type = EidosValueType::kValueNULL;\n\tconst EidosClass *result_class = gEidosObject_Class;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg->Type();\n\t\t\n\t\tif (arg_type == EidosValueType::kValueNULL)\n\t\t\tcontinue;\n\t\telse if (result_type == EidosValueType::kValueNULL)\n\t\t\tresult_type = arg_type;\n\t\telse if (arg_type != result_type)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cbind): function cbind() requires that all arguments be the same type (or NULL).\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosValue_Object *arg_object = (EidosValue_Object *)arg;\n\t\t\tconst EidosClass *arg_class = arg_object->Class();\n\t\t\t\n\t\t\tif (arg_class == gEidosObject_Class)\n\t\t\t\tcontinue;\n\t\t\telse if (result_class == gEidosObject_Class)\n\t\t\t\tresult_class = arg_class;\n\t\t\telse if (arg_class != result_class)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cbind): function cbind() requires that all object arguments be of the same class.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\tif (result_type == EidosValueType::kValueNULL)\n\t\treturn gStaticEidosValueNULL;\n\t\n\t// Next determine the dimensions of the result; every argument must be zero-size or a match for the dimensions we already have\n\tint64_t result_rows = 0;\n\tint64_t result_cols = 0;\n\tint64_t result_length = 0;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\tint64_t arg_length = arg->Count();\n\t\t\n\t\t// skip over zero-length arguments, including NULL; zero-length vectors must match in type (above) but are otherwise ignored\n\t\tif (arg_length == 0)\n\t\t\tcontinue;\n\t\t\n\t\tint arg_dimcount = arg->DimensionCount();\n\t\t\n\t\tif ((arg_dimcount != 1) && (arg_dimcount != 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cbind): function cbind() requires that all arguments be vectors or matrices.\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst int64_t *arg_dims = arg->Dimensions();\n\t\tint64_t arg_nrow = (arg_dimcount == 1) ? arg_length : arg_dims[0];\n\t\tint64_t arg_ncol = (arg_dimcount == 1) ? 1 : arg_dims[1];\n\t\t\n\t\tif (result_rows == 0)\n\t\t\tresult_rows = arg_nrow;\n\t\telse if (result_rows != arg_nrow)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cbind): function cbind() mismatch among arguments in their number of rows.\" << EidosTerminate(nullptr);\n\t\t\n\t\tresult_cols += arg_ncol;\n\t\tresult_length += arg_length;\n\t}\n\t\n\t// Construct our result; this is simpler than rbind(), here we basically just concatenate the arguments directly...\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tswitch (result_type)\n\t{\n\t\tcase EidosValueType::kValueVOID:\tbreak;\t\t// never hit\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\t\tcase EidosValueType::kValueNULL:\tbreak;\t\t// never hit\n\t\tcase EidosValueType::kValueLogical:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueInt:\t\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueFloat:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueString:\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String()); break;\n\t\tcase EidosValueType::kValueObject:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Object(result_class))->reserve(result_length)); break;\n\t}\n\t\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\tint64_t arg_length = arg->Count();\n\t\t\n\t\t// skip over zero-length arguments, including NULL; zero-length vectors must match in type (above) but are otherwise ignored\n\t\tif (arg_length == 0)\n\t\t\tcontinue;\n\t\t\n\t\tfor (int element_index = 0; element_index < arg_length; ++element_index)\n\t\t\tresult->PushValueFromIndexOfEidosValue(element_index, *arg, nullptr);\n\t}\n\t\n\tconst int64_t dim_buf[2] = {result_rows, result_cols};\n\t\n\tresult->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (integer)dim(* x)\nEidosValue_SP Eidos_ExecuteFunction_dim(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *data_value = p_arguments[0].get();\n\tint dim_count = data_value->DimensionCount();\n\t\n\tif (dim_count <= 1)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tconst int64_t *dim_values = data_value->Dimensions();\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(dim_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int dim_index = 0; dim_index < dim_count; ++dim_index)\n\t\tint_result->set_int_no_check(dim_values[dim_index], dim_index);\n\t\n\treturn result_SP;\n}\n\n// (*)drop(* x)\nEidosValue_SP Eidos_ExecuteFunction_drop(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\tEidosValue *x_value = p_arguments[0].get();\n\tint source_dimcount = x_value->DimensionCount();\n\tconst int64_t *source_dim = x_value->Dimensions();\n\t\n\tif (source_dimcount <= 1)\n\t{\n\t\t// x is already a vector, so just return it\n\t\tresult_SP = EidosValue_SP(x_value);\n\t}\n\telse\n\t{\n\t\t// Count the number of dimensions that have a size != 1\n\t\tint needed_dim_count = 0;\n\t\t\n\t\tfor (int dim_index = 0; dim_index < source_dimcount; dim_index++)\n\t\t\tif (source_dim[dim_index] > 1)\n\t\t\t\tneeded_dim_count++;\n\t\t\n\t\tif (needed_dim_count == source_dimcount)\n\t\t{\n\t\t\t// No dimensions can be dropped, so do nothing\n\t\t\tresult_SP = EidosValue_SP(x_value);\n\t\t}\n\t\telse if (needed_dim_count <= 1)\n\t\t{\n\t\t\t// A vector is all that is needed\n\t\t\tresult_SP = x_value->CopyValues();\n\t\t\t\n\t\t\tresult_SP->SetDimensions(1, nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We need to drop some dimensions but still end up with a matrix or array\n\t\t\tresult_SP = x_value->CopyValues();\n\t\t\t\n\t\t\tint64_t *dim_buf = (int64_t *)malloc(needed_dim_count * sizeof(int64_t));\n\t\t\tif (!dim_buf)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_drop): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint dim_buf_index = 0;\n\t\t\t\n\t\t\tfor (int dim_index = 0; dim_index < source_dimcount; dim_index++)\n\t\t\t\tif (source_dim[dim_index] > 1)\n\t\t\t\t\tdim_buf[dim_buf_index++] = source_dim[dim_index];\n\t\t\t\n\t\t\tresult_SP->SetDimensions(needed_dim_count, dim_buf);\n\t\t\t\n\t\t\tfree(dim_buf);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n// (*)matrix(* data, [integer$ nrow = 1], [integer$ ncol = 1], [logical$ byrow = F])\nEidosValue_SP Eidos_ExecuteFunction_matrix(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *data_value = p_arguments[0].get();\n\tEidosValue *nrow_value = p_arguments[1].get();\n\tEidosValue *ncol_value = p_arguments[2].get();\n\tEidosValue *byrow_value = p_arguments[3].get();\n\t\n\tint data_count = data_value->Count();\n\tbool nrow_null = (nrow_value->Type() == EidosValueType::kValueNULL);\n\tbool ncol_null = (ncol_value->Type() == EidosValueType::kValueNULL);\n\t\n\tint64_t nrow = nrow_null ? -1 : nrow_value->IntAtIndex_NOCAST(0, nullptr);\n\tint64_t ncol = ncol_null ? -1 : ncol_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((!nrow_null && (nrow <= 0)) || (!ncol_null && (ncol <= 0)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrix): dimension <= 0 requested, which is not allowed.\" << EidosTerminate(nullptr);\n\tif (data_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrix): matrix() cannot create a matrix with zero elements; matrix dimensions equal to zero are not allowed.\" << EidosTerminate(nullptr);\n\t\n\tif (nrow_null && ncol_null)\n\t{\n\t\t// return a one-column matrix, following R\n\t\tncol = 1;\n\t\tnrow = data_count;\n\t}\n\telse if (nrow_null)\n\t{\n\t\t// try to infer a row count\n\t\tif (data_count % ncol == 0)\n\t\t\tnrow = data_count / ncol;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrix): function matrix() data size is not a multiple of the supplied column count.\" << EidosTerminate(nullptr);\n\t}\n\telse if (ncol_null)\n\t{\n\t\t// try to infer a column count\n\t\tif (data_count % nrow == 0)\n\t\t\tncol = data_count / nrow;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrix): function matrix() data size is not a multiple of the supplied row count.\" << EidosTerminate(nullptr);\n\t}\n\telse\n\t{\n\t\tnrow = nrow_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tncol = ncol_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (data_count != nrow * ncol)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrix): function matrix() requires a data vector with a length equal to the product of the proposed number of rows and columns.\" << EidosTerminate(nullptr);\n\t}\n\t\n\teidos_logical_t byrow = byrow_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (byrow)\n\t{\n\t\t// The non-default case: use the values in data to fill rows one by one, requiring transposition here; singletons are easy, though\n\t\tif (data_count <= 1)\n\t\t\tresult_SP = data_value->CopyValues();\n\t\telse\n\t\t{\n\t\t\t// non-singleton byrow case, so we need to actually transpose\n\t\t\tresult_SP = data_value->NewMatchingType();\n\t\t\t\n\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\n\t\t\tfor (int64_t value_index = 0; value_index < data_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t dest_col = (value_index / nrow);\n\t\t\t\tint64_t dest_row = (value_index % nrow);\n\t\t\t\tint64_t src_index = dest_col + dest_row * ncol;\n\t\t\t\t\n\t\t\t\tresult->PushValueFromIndexOfEidosValue((int)src_index, *data_value, nullptr);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// The default case: use the values in data to fill columns one by one, mirroring the internal layout used by Eidos\n\t\tresult_SP = data_value->CopyValues();\n\t}\n\t\n\tconst int64_t dim_buf[2] = {nrow, ncol};\n\t\n\tresult_SP->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (numeric)matrixMult(numeric x, numeric y)\nEidosValue_SP Eidos_ExecuteFunction_matrixMult(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *y_value = p_arguments[1].get();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): function matrixMult() x is not a matrix.\" << EidosTerminate(nullptr);\n\tif (y_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): function matrixMult() y is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tEidosValueType x_type = x_value->Type();\n\tEidosValueType y_type = y_value->Type();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): function matrixMult() requires that x and y are the same type.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *x_dim = x_value->Dimensions();\n\tint64_t x_rows = x_dim[0];\n\tint64_t x_cols = x_dim[1];\n\tint64_t x_length = x_rows * x_cols;\n\tconst int64_t *y_dim = y_value->Dimensions();\n\tint64_t y_rows = y_dim[0];\n\tint64_t y_cols = y_dim[1];\n\tint64_t y_length = y_rows * y_cols;\n\t\n\tif (x_cols != y_rows)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): in function matrixMult(), x and y are not conformable.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_SP result_SP(nullptr);\n\tint64_t result_rows = x_rows;\n\tint64_t result_cols = y_cols;\n\tint64_t result_length = result_rows * result_cols;\n\t\n\t// Do the multiplication.  We split out singleton cases here so that the big general case can run fast.\n\t// We also split by integer integer versus float, because we have to in order to multiply.  Finally,\n\t// in the integer cases we have to check for overflows; see EidosInterpreter::Evaluate_Mult().\n\t\n\tif ((x_length == 1) && (y_length == 1))\n\t{\n\t\t// a 1x1 vector multiplied by a 1x1 vector\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t x_singleton = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t y_singleton = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t multiply_result;\n\t\t\tbool overflow = Eidos_mul_overflow(x_singleton, y_singleton, &multiply_result);\n\t\t\t\n\t\t\tif (overflow)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): integer multiplication overflow in function matrixMult(); you may wish to cast the matrices to float with asFloat() before multiplying.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(multiply_result));\n\t\t}\n\t\telse // (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble x_singleton = x_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble y_singleton = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(x_singleton * y_singleton));\n\t\t}\n\t}\n\telse if (x_length == 1)\n\t{\n\t\t// a 1x1 vector multiplied by a row vector\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t x_singleton = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *y_data = y_value->IntData();\n\t\t\tEidosValue_Int *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t y_index = 0; y_index < y_length; ++y_index)\n\t\t\t{\n\t\t\t\tint64_t y_operand = y_data[y_index];\n\t\t\t\tint64_t multiply_result;\n\t\t\t\tbool overflow = Eidos_mul_overflow(x_singleton, y_operand, &multiply_result);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): integer multiplication overflow in function matrixMult(); you may wish to cast the matrices to float with asFloat() before multiplying.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tresult->set_int_no_check(multiply_result, y_index);\n\t\t\t}\n\t\t}\n\t\telse // (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble x_singleton = x_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *y_data = y_value->FloatData();\n\t\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t y_index = 0; y_index < y_length; ++y_index)\n\t\t\t\tresult->set_float_no_check(x_singleton * y_data[y_index], y_index);\n\t\t}\n\t}\n\telse if (y_length == 1)\n\t{\n\t\t// a column vector multiplied by a 1x1 vector\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\tint64_t y_singleton = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t x_index = 0; x_index < x_length; ++x_index)\n\t\t\t{\n\t\t\t\tint64_t x_operand = x_data[x_index];\n\t\t\t\tint64_t multiply_result;\n\t\t\t\tbool overflow = Eidos_mul_overflow(x_operand, y_singleton, &multiply_result);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): integer multiplication overflow in function matrixMult(); you may wish to cast the matrices to float with asFloat() before multiplying.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tresult->set_int_no_check(multiply_result, x_index);\n\t\t\t}\n\t\t}\n\t\telse // (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *x_data = x_value->FloatData();\n\t\t\tdouble y_singleton = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t x_index = 0; x_index < x_length; ++x_index)\n\t\t\t\tresult->set_float_no_check(x_data[x_index] * y_singleton, x_index);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// this is the general case; we have non-singleton matrices for both x and y, so we can divide by integer/float and use direct access\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\tconst int64_t *y_data = y_value->IntData();\n\t\t\tEidosValue_Int *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t result_col_index = 0; result_col_index < result_cols; ++result_col_index)\n\t\t\t{\n\t\t\t\tfor (int64_t result_row_index = 0; result_row_index < result_rows; ++result_row_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t result_index = result_col_index * result_rows + result_row_index;\n\t\t\t\t\tint64_t summation_result = 0;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t product_index = 0; product_index < x_cols; ++product_index)\t// x_cols == y_rows; this is the dimension that matches, n x m * m x p\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t x_row = result_row_index;\n\t\t\t\t\t\tint64_t x_col = product_index;\n\t\t\t\t\t\tint64_t x_index = x_col * x_rows + x_row;\n\t\t\t\t\t\tint64_t y_row = product_index;\n\t\t\t\t\t\tint64_t y_col = result_col_index;\n\t\t\t\t\t\tint64_t y_index = y_col * y_rows + y_row;\n\t\t\t\t\t\tint64_t x_operand = x_data[x_index];\n\t\t\t\t\t\tint64_t y_operand = y_data[y_index];\n\t\t\t\t\t\tint64_t multiply_result;\n\t\t\t\t\t\tbool overflow = Eidos_mul_overflow(x_operand, y_operand, &multiply_result);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (overflow)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): integer multiplication overflow in function matrixMult(); you may wish to cast the matrices to float with asFloat() before multiplying.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tint64_t add_result;\n\t\t\t\t\t\tbool overflow2 = Eidos_add_overflow(summation_result, multiply_result, &add_result);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (overflow2)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_matrixMult): integer addition overflow in function matrixMult(); you may wish to cast the matrices to float with asFloat() before multiplying.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tsummation_result = add_result;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->set_int_no_check(summation_result, result_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse // (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *x_data = x_value->FloatData();\n\t\t\tconst double *y_data = y_value->FloatData();\n\t\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(result_length);\n\t\t\tresult_SP = EidosValue_SP(result);\n\t\t\t\n\t\t\tfor (int64_t result_col_index = 0; result_col_index < result_cols; ++result_col_index)\n\t\t\t{\n\t\t\t\tfor (int64_t result_row_index = 0; result_row_index < result_rows; ++result_row_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t result_index = result_col_index * result_rows + result_row_index;\n\t\t\t\t\tdouble summation_result = 0;\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t product_index = 0; product_index < x_cols; ++product_index)\t// x_cols == y_rows; this is the dimension that matches, n x m * m x p\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t x_row = result_row_index;\n\t\t\t\t\t\tint64_t x_col = product_index;\n\t\t\t\t\t\tint64_t x_index = x_col * x_rows + x_row;\n\t\t\t\t\t\tint64_t y_row = product_index;\n\t\t\t\t\t\tint64_t y_col = result_col_index;\n\t\t\t\t\t\tint64_t y_index = y_col * y_rows + y_row;\n\t\t\t\t\t\tdouble x_operand = x_data[x_index];\n\t\t\t\t\t\tdouble y_operand = y_data[y_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tsummation_result += x_operand * y_operand;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->set_float_no_check(summation_result, result_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tconst int64_t dim_buf[2] = {result_rows, result_cols};\n\t\n\tresult_SP->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (integer$)ncol(* x)\nEidosValue_SP Eidos_ExecuteFunction_ncol(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *data_value = p_arguments[0].get();\n\tint dim_count = data_value->DimensionCount();\n\t\n\tif (dim_count < 2)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tconst int64_t *dim_values = data_value->Dimensions();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(dim_values[1]));\n}\n\n// (integer$)nrow(* x)\nEidosValue_SP Eidos_ExecuteFunction_nrow(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *data_value = p_arguments[0].get();\n\tint dim_count = data_value->DimensionCount();\n\t\n\tif (dim_count < 2)\n\t\treturn gStaticEidosValueNULL;\n\t\n\tconst int64_t *dim_values = data_value->Dimensions();\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(dim_values[0]));\n}\n\n// (*)rbind(...)\nEidosValue_SP Eidos_ExecuteFunction_rbind(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// First check the type and class of the result; NULL may be mixed in, but otherwise all arguments must be the same type and class\n\tEidosValueType result_type = EidosValueType::kValueNULL;\n\tconst EidosClass *result_class = gEidosObject_Class;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg->Type();\n\t\t\n\t\tif (arg_type == EidosValueType::kValueNULL)\n\t\t\tcontinue;\n\t\telse if (result_type == EidosValueType::kValueNULL)\n\t\t\tresult_type = arg_type;\n\t\telse if (arg_type != result_type)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbind): function rbind() requires that all arguments be the same type (or NULL).\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (arg_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosValue_Object *arg_object = (EidosValue_Object *)arg;\n\t\t\tconst EidosClass *arg_class = arg_object->Class();\n\t\t\t\n\t\t\tif (arg_class == gEidosObject_Class)\n\t\t\t\tcontinue;\n\t\t\telse if (result_class == gEidosObject_Class)\n\t\t\t\tresult_class = arg_class;\n\t\t\telse if (arg_class != result_class)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbind): function rbind() requires that all object arguments be of the same class.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\tif (result_type == EidosValueType::kValueNULL)\n\t\treturn gStaticEidosValueNULL;\n\t\n\t// Next determine the dimensions of the result; every argument must be zero-size or a match for the dimensions we already have\n\tint64_t result_rows = 0;\n\tint64_t result_cols = 0;\n\tint64_t result_length = 0;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\tint64_t arg_length = arg->Count();\n\t\t\n\t\t// skip over zero-length arguments, including NULL; zero-length vectors must match in type (above) but are otherwise ignored\n\t\tif (arg_length == 0)\n\t\t\tcontinue;\n\t\t\n\t\tint arg_dimcount = arg->DimensionCount();\n\t\t\n\t\tif ((arg_dimcount != 1) && (arg_dimcount != 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbind): function rbind() requires that all arguments be vectors or matrices.\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst int64_t *arg_dims = arg->Dimensions();\n\t\tint64_t arg_nrow = (arg_dimcount == 1) ? 1 : arg_dims[0];\n\t\tint64_t arg_ncol = (arg_dimcount == 1) ? arg_length : arg_dims[1];\n\t\t\n\t\tif (result_cols == 0)\n\t\t\tresult_cols = arg_ncol;\n\t\telse if (result_cols != arg_ncol)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rbind): function rbind() mismatch among arguments in their number of columns.\" << EidosTerminate(nullptr);\n\t\t\n\t\tresult_rows += arg_nrow;\n\t\tresult_length += arg_length;\n\t}\n\t\n\t// Construct our result; for each column, we scan through our arguments and append rows from that column; not very efficient, but general...\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tswitch (result_type)\n\t{\n\t\tcase EidosValueType::kValueVOID:\tbreak;\t\t// never hit\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\t\tcase EidosValueType::kValueNULL:\tbreak;\t\t// never hit\n\t\tcase EidosValueType::kValueLogical:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueInt:\t\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueFloat:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->reserve(result_length)); break;\n\t\tcase EidosValueType::kValueString:\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String()); break;\n\t\tcase EidosValueType::kValueObject:\tresult_SP = EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Object(result_class))->reserve(result_length)); break;\n\t}\n\t\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int col_index = 0; col_index < result_cols; ++col_index)\n\t{\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg = p_arguments[arg_index].get();\n\t\t\tint64_t arg_length = arg->Count();\n\t\t\t\n\t\t\t// skip over zero-length arguments, including NULL; zero-length vectors must match in type (above) but are otherwise ignored\n\t\t\tif (arg_length == 0)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tint arg_dimcount = arg->DimensionCount();\n\t\t\t\n\t\t\tif (arg_dimcount == 1)\n\t\t\t{\n\t\t\t\t// vector; take the nth value to fill the nth column in the result\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(col_index, *arg, nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// matrix; take the whole nth column of the matrix to fill the nth column in the result\n\t\t\t\tconst int64_t *arg_dims = arg->Dimensions();\n\t\t\t\tint64_t arg_nrow = arg_dims[0];\n\t\t\t\t\n\t\t\t\tfor (int64_t row_index = 0; row_index < arg_nrow; ++row_index)\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue((int)(col_index * arg_nrow + row_index), *arg, nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tconst int64_t dim_buf[2] = {result_rows, result_cols};\n\t\n\tresult->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (*)t(* x)\nEidosValue_SP Eidos_ExecuteFunction_t(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_t): in function t() x is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *source_dim = x_value->Dimensions();\n\tint64_t source_rows = source_dim[0];\n\tint64_t source_cols = source_dim[1];\n\tint64_t dest_rows = source_cols;\n\tint64_t dest_cols = source_rows;\n\t\n\tresult_SP = x_value->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int64_t col_index = 0; col_index < dest_cols; ++col_index)\n\t{\n\t\tfor (int64_t row_index = 0; row_index < dest_rows; ++row_index)\n\t\t{\n\t\t\t//int64_t dest_index = col_index * dest_rows + row_index;\n\t\t\tint64_t source_index = row_index * source_rows + col_index;\n\t\t\t\n\t\t\tresult->PushValueFromIndexOfEidosValue((int)source_index, *x_value, nullptr);\n\t\t}\n\t}\n\t\n\tconst int64_t dim_buf[2] = {dest_rows, dest_cols};\n\t\n\tresult->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (logical)lowerTri(* x, [logical$ diag = F])\nEidosValue_SP Eidos_ExecuteFunction_lowerTri(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// contributed by Nick O'Brien (@nobrien97)\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\teidos_logical_t diag = p_arguments[1].get()->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_lowerTri): in function lowerTri() x is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *dim = x_value->Dimensions();\n\tint64_t nrows = dim[0];\n\tint64_t ncols = dim[1];\n\t\n\t// Create new empty logical matrix\n\tEidosValue_Logical *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(nrows * ncols);\n\tEidosValue_SP result_SP(result);\n\t\n\t// Iterate through result matrix and set lower triangle to T, remaining values to F\n\t// If we want the diagonal elements included, we need to include them in our condition\n\tfor (int64_t row_index = 0; row_index < nrows; ++row_index)\n\t{\n\t\tfor (int64_t col_index = 0; col_index < ncols; ++col_index)\n\t\t{\n\t\t\t// Get 1D index from rows/cols\n\t\t\tint64_t index = col_index * nrows + row_index;\n\t\t\t\n\t\t\tbool in_triangle;\n\t\t\t\n\t\t\tif (row_index > col_index)\n\t\t\t\tin_triangle = true;\n\t\t\telse if (diag && (row_index == col_index))\n\t\t\t\tin_triangle = true;\n\t\t\telse\n\t\t\t\tin_triangle = false;\n\t\t\t\n\t\t\tresult->set_logical_no_check(in_triangle, (int)index);\n\t\t}\n\t}\n\t\n\t// Apply dimension attributes and return\n\tconst int64_t dim_buf[2] = {nrows, ncols};\n\tresult->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (logical)upperTri(* x, [logical$ diag = F])\nEidosValue_SP Eidos_ExecuteFunction_upperTri(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// contributed by Nick O'Brien (@nobrien97)\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\teidos_logical_t diag = p_arguments[1].get()->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_upperTri): in function upperTri() x is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *dim = x_value->Dimensions();\n\tint64_t nrows = dim[0];\n\tint64_t ncols = dim[1];\n\t\n\t// Create new empty logical matrix\n\tEidosValue_Logical *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(nrows * ncols);\n\tEidosValue_SP result_SP(result);\n\t\n\t// Iterate through result matrix and set upper triangle to T, remaining values to F\n\t// If we want the diagonal elements included, we need to include them in our condition\n\tfor (int64_t row_index = 0; row_index < nrows; ++row_index)\n\t{\n\t\tfor (int64_t col_index = 0; col_index < ncols; ++col_index)\n\t\t{\n\t\t\t// Get 1D index from rows/cols\n\t\t\tint64_t index = col_index * nrows + row_index;\n\n\t\t\tbool in_triangle;\n\t\t\t\n\t\t\tif (row_index < col_index)\n\t\t\t\tin_triangle = true;\n\t\t\telse if (diag && (row_index == col_index))\n\t\t\t\tin_triangle = true;\n\t\t\telse\n\t\t\t\tin_triangle = false;\n\t\t\t\n\t\t\tresult->set_logical_no_check(in_triangle, (int)index);\n\t\t}\n\t}\n\t\n\t// Apply dimension attributes and return\n\tconst int64_t dim_buf[2] = {nrows, ncols};\n\tresult->SetDimensions(2, dim_buf);\n\t\n\treturn result_SP;\n}\n\n// (*)diag([* x = 1], [integer$ nrow], [integer$ ncol])\nEidosValue_SP Eidos_ExecuteFunction_diag(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// contributed by Nick O'Brien (@nobrien97)\n\t\n\t/* \n\t\tFour return modes depending on the form of inputs (matching R behaviour)\n\t\t1: x is a matrix - return the diagonal elements of x (nrow and ncol cannot be specified in this mode)\n\t \t2: x is missing and nrow and/or ncol is given - return an identity matrix with dimensions nrow * ncol, nrow*nrow, 1*ncol\n\t\t3: x is a singleton vector and is the only input - return an identity matrix with dimensions equal to the length of x\n\t\t4: x is a numeric or logical vector - return a matrix with the given diagonal entries and 0/F in the off diagonals\n\t*/\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *nrow_value = p_arguments[1].get();\n\tEidosValue *ncol_value = p_arguments[2].get();\n\tint64_t x_count = x_value->Count();\n\tEidosValueType x_type = x_value->Type();\n\tbool nrow_null = (nrow_value->Type() == EidosValueType::kValueNULL);\n\tbool ncol_null = (ncol_value->Type() == EidosValueType::kValueNULL);\n\t\n\tif (x_value->DimensionCount() > 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): in function diag() x must be a vector or a matrix.\" << EidosTerminate(nullptr);\n\t\n\t// 1: If x is a matrix we return the diagonals\n\tif (x_value->DimensionCount() == 2)\n\t{\t\n\t\tif (!nrow_null || !ncol_null) \t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): in function diag() nrow and ncol must be NULL when x is a matrix.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// Setup output\n\t\tEidosValue_SP result_SP = x_value->NewMatchingType();\n\t\tEidosValue *result = result_SP.get();\n\t\t\n\t\tconst int64_t *source_dim = x_value->Dimensions();\n\t\tint64_t source_nrow = source_dim[0];\n\t\tint64_t source_ncol= source_dim[1];\n\t\tint64_t max_diag_index = std::min(source_nrow, source_ncol);\n\t\t\n\t\t// Iterate over diagonals: number of diagonals is the minimum of nrows and ncols \n\t\tfor (int64_t diag_index = 0; diag_index < max_diag_index; ++diag_index)\n\t\t{\n\t\t\t// Convert to 1D: because row == col, we can use diag_index in place of both\n\t\t\tint64_t source_index = diag_index * source_nrow + diag_index;\n\t\t\t\n\t\t\tresult->PushValueFromIndexOfEidosValue((int)source_index, *x_value, nullptr);\t\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\t// 2: If x is 1 and nrow is non-NULL, return an identity matrix of size nrow (by ncol, if specified)\n\tif ((x_type == EidosValueType::kValueInt) && (x_count == 1) && (x_value->IntAtIndex_NOCAST(0, nullptr) == 1) && !nrow_null)\n\t{\n\t\tint64_t nrow = nrow_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tint64_t ncol = (ncol_null ? nrow : ncol_value->IntAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tif ((nrow < 1) || (ncol < 1))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): in function diag() when an identity matrix is being generated, both dimensions of that matrix must be >= 1.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(nrow * ncol);\n\t\tEidosValue_SP result_SP(int_result);\n\t\t\n\t\tfor (int64_t col_index = 0; col_index < ncol; ++col_index)\n\t\t\tfor (int64_t row_index = 0; row_index < nrow; ++row_index)\n\t\t\t\tint_result->set_int_no_check((row_index == col_index) ? 1 : 0, col_index * nrow + row_index);\n\t\t\n\t\tconst int64_t dim_buf[2] = {nrow, ncol};\n\t\tint_result->SetDimensions(2, dim_buf);\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\t// 3: If x is a singleton integer, nrow/ncol must not be set, and a square identity matrix of size x is returned\n\tif ((x_type == EidosValueType::kValueInt) && (x_count == 1) && nrow_null && ncol_null)\n\t{\n\t\tint64_t size = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (size < 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): in function diag() when x specificies an identity matrix size, that size must be >= 1.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(size * size);\n\t\tEidosValue_SP result_SP(int_result);\n\t\t\n\t\tfor (int64_t col_index = 0; col_index < size; ++col_index)\n\t\t\tfor (int64_t row_index = 0; row_index < size; ++row_index)\n\t\t\t\tint_result->set_int_no_check((row_index == col_index) ? 1 : 0, col_index * size + row_index);\n\t\t\n\t\tconst int64_t dim_buf[2] = {size, size};\n\t\tint_result->SetDimensions(2, dim_buf);\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\t// 4: If x is a logical/integer/float vector of length >= 2, use the values of x for the diagonal\n\tif (((x_type == EidosValueType::kValueLogical) || (x_type == EidosValueType::kValueInt) || (x_type == EidosValueType::kValueFloat)) && (x_count >= 2))\n\t{\n\t\tint64_t nrow = (nrow_null ? x_count : nrow_value->IntAtIndex_NOCAST(0, nullptr));\n\t\tint64_t ncol = (ncol_null ? nrow : ncol_value->IntAtIndex_NOCAST(0, nullptr));\t\t// it is weird that the default is nrow, not x_count, but this mirrors R's behavior\n\t\tint64_t max_diag_index = std::min(nrow, ncol);\n\t\t\n\t\tif (max_diag_index != x_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): in function diag(), when values for the diagonal are supplied in x, those values may not be truncated or recycled by the dimensions specified with nrow and ncol.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// define default value to copy to off-diagonals\n\t\tEidosValue_SP default_value;\n\t\t\n\t\tswitch (x_type)\n\t\t{\n\t\tcase EidosValueType::kValueLogical:\t\tdefault_value = gStaticEidosValue_LogicalF;\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\t\tdefault_value = gStaticEidosValue_Float0;\t\tbreak;\n\t\tcase EidosValueType::kValueInt:\t\t\tdefault_value = gStaticEidosValue_Integer0;\t\tbreak;\n\t\tdefault:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tEidosValue_SP result_SP = x_value->NewMatchingType();\n\t\tEidosValue *result = result_SP.get();\n\t\t\n\t\t// Initialise result matrix and fill in diagonals with x values\n\t\tfor (int64_t col_index = 0; col_index < ncol; ++col_index)\n\t\t{\n\t\t\tfor (int64_t row_index = 0; row_index < nrow; ++row_index)\n\t\t\t{\n\t\t\t\t// Set diagonal to the corresponding value of x, other values to F/0/0.0\n\t\t\t\tif (row_index == col_index)\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue((int)col_index, *x_value, nullptr);\n\t\t\t\telse\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(0, *default_value, nullptr);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Apply dimension attributes and return\n\t\tconst int64_t dim_buf[2] = {nrow, ncol};\n\t\tresult->SetDimensions(2, dim_buf);\n\t\t\n\t\treturn result_SP;\t\t\n\t}\n\t\n\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_diag): diag() requires one of four specific input parameter patterns; see the documentation.\" << EidosTerminate(nullptr);\n}\n\n// (numeric$)tr(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_tr(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_tr): in function tr() x must be a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *x_dim = x_value->Dimensions();\n\tint64_t x_nrow = x_dim[0];\n\tint64_t x_ncol= x_dim[1];\n\t\n\t// The R psych package throws an error, which seems appropriate; this should not be called with a non-square matrix\n\tif (x_nrow != x_ncol)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_tr): in function tr() x must be a square matrix.\" << EidosTerminate(nullptr);\n\t\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tint64_t diag_sum = 0;\n\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\n\t\tfor (int64_t diag_index = 0; diag_index < x_nrow; ++diag_index)\n\t\t{\n\t\t\tint64_t diag_element = x_data[diag_index * x_nrow + diag_index];\n\t\t\tbool overflow = Eidos_add_overflow(diag_sum, diag_element, &diag_sum);\n\t\t\t\n\t\t\tif (overflow)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_tr): integer addition overflow in function tr(); you may wish to cast the matrix to float with asFloat() before calling this function.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(diag_sum));\n\t}\n\telse\n\t{\n\t\tdouble diag_sum = 0.0;\n\t\tconst double *x_data = x_value->FloatData();\n\t\t\n\t\tfor (int64_t diag_index = 0; diag_index < x_nrow; ++diag_index)\n\t\t\tdiag_sum += x_data[diag_index * x_nrow + diag_index];\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(diag_sum));\n\t}\n}\n\n// (numeric$)det(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_det(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): in function det() x must be a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *x_dim = x_value->Dimensions();\n\tint64_t x_nrow = x_dim[0];\n\tint64_t x_ncol= x_dim[1];\n\t\n\t// The R base package throws an error, which seems appropriate; this should not be called with a non-square matrix\n\tif (x_nrow != x_ncol)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): in function det() x must be a square matrix.\" << EidosTerminate(nullptr);\n\t\n\tint64_t d = x_nrow;\t\t// square matrix\n\t\n\t// Set up the input matrix and allocate a permutation object\n\tgsl_matrix *A = gsl_matrix_alloc(d, d);\n\tint signum;\n\t\n\tif (!A)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\n\t\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\t{\n\t\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\t{\n\t\t\t\tint64_t value = x_data[row_index + col_index * d];\n\t\t\t\t\n\t\t\t\tgsl_matrix_set(A, row_index, col_index, value);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst double *x_data = x_value->FloatData();\n\t\t\n\t\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\t{\n\t\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\t{\n\t\t\t\tdouble value = x_data[row_index + col_index * d];\n\t\t\t\t\n\t\t\t\tif (std::isnan(value))\n\t\t\t\t{\n\t\t\t\t\tgsl_matrix_free(A);\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): function det() does not allow x to contain NANs.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgsl_matrix_set(A, row_index, col_index, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Perform LU decomposition\n\tgsl_permutation *p = gsl_permutation_alloc(d);\n\t\n\tif (!p)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint result = gsl_linalg_LU_decomp(A, p, &signum);\n\t\n\tif (result != GSL_SUCCESS)\n\t{\n\t\t// This indicates that the matrix is singular, and the determinant is zero.\n\t\tif (x_value->Type() == EidosValueType::kValueInt)\n\t\t\treturn gStaticEidosValue_Integer0;\n\t\telse\n\t\t\treturn gStaticEidosValue_Float0;\n\t}\n\t\n\t// Calculate the determinant from the LU decomposition, since the matrix is not singular\n\tdouble determinant = gsl_linalg_LU_det(A, signum);\n\t\n\tgsl_matrix_free(A);\n\tgsl_permutation_free(p);\n\t\n\t// If the original matrix is of type integer, the determinant is also an integer.\n\t// The conversion to integer might overflow, in which case we raise an error.\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tdeterminant = std::round(determinant);\t// in case of numerical error\n\t\t\n\t\tif (!std::isfinite(determinant) || (determinant < INT64_MIN) || (determinant > INT64_MAX))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_det): integer overflow in function det(); you may wish to cast the matrix to float with asFloat() before calling this function.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint64_t determinant_int = (int64_t)determinant;\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(determinant_int));\n\t}\n\telse\n\t{\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(determinant));\n\t}\n}\n\n// (float)inverse(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_inverse(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): in function inverse() x must be a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *x_dim = x_value->Dimensions();\n\tint64_t x_nrow = x_dim[0];\n\tint64_t x_ncol= x_dim[1];\n\t\n\t// this should not be called with a non-square matrix\n\tif (x_nrow != x_ncol)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): in function inverse() x must be a square matrix.\" << EidosTerminate(nullptr);\n\t\n\tint64_t d = x_nrow;\t\t// square matrix\n\t\n\t// Set up the input matrix and allocate a permutation object\n\tgsl_matrix *A = gsl_matrix_alloc(d, d);\n\tint signum;\n\t\n\tif (!A)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\n\t\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\t{\n\t\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\t{\n\t\t\t\tint64_t value = x_data[row_index + col_index * d];\n\t\t\t\t\n\t\t\t\tgsl_matrix_set(A, row_index, col_index, value);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst double *x_data = x_value->FloatData();\n\t\t\n\t\tfor (int row_index = 0; row_index < d; ++row_index)\n\t\t{\n\t\t\tfor (int col_index = 0; col_index < d; ++col_index)\n\t\t\t{\n\t\t\t\tdouble value = x_data[row_index + col_index * d];\n\t\t\t\t\n\t\t\t\tif (std::isnan(value))\n\t\t\t\t{\n\t\t\t\t\tgsl_matrix_free(A);\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): function inverse() does not allow x to contain NANs.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgsl_matrix_set(A, row_index, col_index, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Perform LU decomposition\n\tgsl_permutation *p = gsl_permutation_alloc(d);\n\t\n\tif (!p)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tint result = gsl_linalg_LU_decomp(A, p, &signum);\n\t\n\tif (result != GSL_SUCCESS)\n\t{\n\t\t// This indicates that the matrix is singular, and the determinant is zero; for inverse() this is an error\n\t\tgsl_matrix_free(A);\n\t\tgsl_permutation_free(p);\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): in function inverse() x must not be singular (i.e., must be invertible).  You can use det() to check for singularity prior to calling inverse().\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Calculate the inverse from the LU decomposition, since the matrix is not singular\n\tgsl_matrix *inverse = gsl_matrix_calloc(d, d);\n\t\n\tif (!inverse)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\tgsl_error_handler_t *old_handler = gsl_set_error_handler_off();\n\tresult = gsl_linalg_LU_invert(A, p, inverse);\n\tgsl_set_error_handler(old_handler);\n\t\n\tif (result == GSL_EDOM)\n\t{\n\t\t// This indicates that the matrix is singular, and the determinant is zero; for inverse() this is an error\n\t\tgsl_matrix_free(A);\n\t\tgsl_permutation_free(p);\n\t\tgsl_matrix_free(inverse);\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): in function inverse() x must not be singular (i.e., must be invertible).  You can use det() to check for singularity prior to calling inverse().\" << EidosTerminate(nullptr);\n\t}\n\telse if (result != GSL_SUCCESS)\n\t{\n\t\t// Some other error occurred\n\t\tgsl_matrix_free(A);\n\t\tgsl_permutation_free(p);\n\t\tgsl_matrix_free(inverse);\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_inverse): in function inverse() an internal GSL error occurred (code == \" << result << \").\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Create a new EidosValue matrix from inverse\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(d * d);\n\tEidosValue_SP result_SP(float_result);\n\t\n\tfor (int64_t col_index = 0; col_index < d; ++col_index)\n\t\tfor (int64_t row_index = 0; row_index < d; ++row_index)\n\t\t\tfloat_result->set_float_no_check(gsl_matrix_get(inverse, row_index, col_index), col_index * d + row_index);\n\t\n\tconst int64_t dim_buf[2] = {d, d};\n\t\n\tfloat_result->SetDimensions(2, dim_buf);\n\t\n\tgsl_matrix_free(A);\n\tgsl_permutation_free(p);\n\tgsl_matrix_free(inverse);\n\t\n\treturn result_SP;\n}\n\n//\t(*)asVector(* x)\nEidosValue_SP Eidos_ExecuteFunction_asVector(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tif (x_value->DimensionCount() == 1)\n\t{\n\t\tresult_SP.reset(x_value);\n\t}\n\telse\n\t{\n\t\tresult_SP = x_value->CopyValues();\n\t\t\n\t\tresult_SP->SetDimensions(1, nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)rowSums(lif x)\nEidosValue_SP Eidos_ExecuteFunction_rowSums(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rowSums): in function rowSums() x is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *dim_values = x_value->Dimensions();\n\tsize_t x_rowcount = (size_t)dim_values[0];\n\tsize_t x_colcount = (size_t)dim_values[1];\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_rowcount);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_rowcount; ++value_index)\n\t\t{\n\t\t\tint64_t sum = 0;\n\t\t\tconst int64_t *series_ptr = int_data + value_index;\n\t\t\t\n\t\t\tfor (size_t col_index = 0; col_index < x_colcount; ++col_index)\n\t\t\t{\n\t\t\t\t// do sum += *series_ptr but check for overflow\n\t\t\t\tint64_t old_sum = sum;\n\t\t\t\tint64_t temp = *series_ptr;\n\t\t\t\tbool overflow = Eidos_add_overflow(old_sum, temp, &sum);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rowSums): integer overflow in rowSums(); you might wish to convert to float before calling rowSums().\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tseries_ptr += x_rowcount;\n\t\t\t}\n\t\t\t\n\t\t\tint_result->set_int_no_check(sum, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_rowcount);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_rowcount; ++value_index)\n\t\t{\n\t\t\tdouble sum = 0;\n\t\t\tconst double *series_ptr = float_data + value_index;\n\t\t\t\n\t\t\tfor (size_t col_index = 0; col_index < x_colcount; ++col_index)\n\t\t\t{\n\t\t\t\tsum += *series_ptr;\n\t\t\t\tseries_ptr += x_rowcount;\n\t\t\t}\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(sum, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_rowcount);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_rowcount; ++value_index)\n\t\t{\n\t\t\tint64_t sum = 0;\n\t\t\tconst eidos_logical_t *series_ptr = logical_data + value_index;\n\t\t\t\n\t\t\tfor (size_t col_index = 0; col_index < x_colcount; ++col_index)\n\t\t\t{\n\t\t\t\tsum += *series_ptr;\n\t\t\t\tseries_ptr += x_rowcount;\n\t\t\t}\n\t\t\t\n\t\t\tint_result->set_int_no_check(sum, value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)colSums(lif x)\nEidosValue_SP Eidos_ExecuteFunction_colSums(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tif (x_value->DimensionCount() != 2)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_colSums): in function colSums() x is not a matrix.\" << EidosTerminate(nullptr);\n\t\n\tconst int64_t *dim_values = x_value->Dimensions();\n\tsize_t x_rowcount = (size_t)dim_values[0];\n\tsize_t x_colcount = (size_t)dim_values[1];\n\t\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_colcount);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_colcount; ++value_index)\n\t\t{\n\t\t\tint64_t sum = 0;\n\t\t\tconst int64_t *series_ptr = int_data + value_index * x_rowcount;\n\t\t\t\n\t\t\tfor (size_t row_index = 0; row_index < x_rowcount; ++row_index)\n\t\t\t{\n\t\t\t\t// do sum += *series_ptr but check for overflow\n\t\t\t\tint64_t old_sum = sum;\n\t\t\t\tint64_t temp = *series_ptr;\n\t\t\t\tbool overflow = Eidos_add_overflow(old_sum, temp, &sum);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_colSums): integer overflow in colSums(); you might wish to convert to float before calling colSums().\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tseries_ptr++;\n\t\t\t}\n\t\t\t\n\t\t\tint_result->set_int_no_check(sum, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *float_data = x_value->FloatData();\n\t\t\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_colcount);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_colcount; ++value_index)\n\t\t{\n\t\t\tdouble sum = 0;\n\t\t\tconst double *series_ptr = float_data + value_index * x_rowcount;\n\t\t\t\n\t\t\tfor (size_t row_index = 0; row_index < x_rowcount; ++row_index)\n\t\t\t\tsum += *(series_ptr++);\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(sum, value_index);\n\t\t}\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_colcount);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tfor (size_t value_index = 0; value_index < x_colcount; ++value_index)\n\t\t{\n\t\t\tint64_t sum = 0;\n\t\t\tconst eidos_logical_t *series_ptr = logical_data + value_index * x_rowcount;\n\t\t\t\n\t\t\tfor (size_t row_index = 0; row_index < x_rowcount; ++row_index)\n\t\t\t\tsum += *(series_ptr++);\n\t\t\t\n\t\t\tint_result->set_int_no_check(sum, value_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_other.cpp",
    "content": "//\n//  eidos_functions_other.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_beep.h\"\n#include \"eidos_openmp.h\"\n\n#include <utility>\n#include <memory>\n#include <string>\n#include <vector>\n#include <unistd.h>\n#include <fstream>\n#include <sys/utsname.h>\n#include <chrono>\n#include <ctime>\n#include <algorithm>\n\n#if 0\n// These would enable further keys in sysinfo(), but cause problems on Ubuntu 18.04 and/or Windows\n#include <pwd.h>\n#include <uuid/uuid.h>\n#endif\n\n\n// ************************************************************************************\n//\n//\tmiscellaneous functions\n//\n#pragma mark -\n#pragma mark Miscellaneous functions\n#pragma mark -\n\n\n//\t(void)assert(logical assertions, [Ns$ message = NULL])\nEidosValue_SP Eidos_ExecuteFunction_assert(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue *assertions_value = p_arguments[0].get();\n\t\n\t// determine whether the assertions vector is all true\n\tint assertions_count = assertions_value->Count();\n\tconst eidos_logical_t *logical_data = assertions_value->LogicalData();\n\tbool any_false = false;\n\t\n\tfor (int assertions_index = 0; assertions_index < assertions_count; ++assertions_index)\n\t\tif (!logical_data[assertions_index])\n\t\t{\n\t\t\tany_false = true;\n\t\t\tbreak;\n\t\t}\n\t\n\t// stop with a message if an assertion is false\n\tif (any_false)\n\t{\n\t\tEidosValue *message_value = p_arguments[1].get();\n\t\t\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tif (message_value->Type() != EidosValueType::kValueNULL)\n\t\t{\n\t\t\tstd::string &&stop_string = message_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tp_interpreter.ErrorOutputStream() << stop_string << std::endl;\n\t\t\t\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_assert): assertion failed: \" << stop_string << \".\" << EidosTerminate(nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_assert): assertion failed.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)beep([Ns$ soundName = NULL])\nEidosValue_SP Eidos_ExecuteFunction_beep(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Eidos_ExecuteFunction_beep(): main thread only\");\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *soundName_value = p_arguments[0].get();\n\tstd::string name_string = ((soundName_value->Type() == EidosValueType::kValueString) ? soundName_value->StringAtIndex_NOCAST(0, nullptr) : gEidosStr_empty_string);\n\t\n\tstd::string beep_error = Eidos_Beep(name_string);\n\t\n\tif (beep_error.length())\n\t{\n\t\tif (!gEidosSuppressWarnings)\n\t\t{\n\t\t\tstd::ostream &output_stream = p_interpreter.ErrorOutputStream();\n\t\t\n\t\t\toutput_stream << beep_error << std::endl;\n\t\t}\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)citation(void)\nEidosValue_SP Eidos_ExecuteFunction_citation(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\toutput_stream << \"To cite Eidos in publications please use:\" << std::endl << std::endl;\n\toutput_stream << \"Haller, B.C. (2016). Eidos: A Simple Scripting Language.\" << std::endl;\n\toutput_stream << \"URL: http://benhaller.com/slim/Eidos_Manual.pdf\" << std::endl << std::endl;\n\t\n\tif (gEidosContextCitation.length())\n\t{\n\t\toutput_stream << \"---------------------------------------------------------\" << std::endl << std::endl;\n\t\toutput_stream << gEidosContextCitation << std::endl;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(float$)clock([string$ type = \"cpu\"])\nEidosValue_SP Eidos_ExecuteFunction_clock(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_String *string_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &type_name = string_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (type_name == \"cpu\")\n\t{\n\t\t// elapsed CPU time; this is across all cores, so it can be larger than the elapsed wall clock time!\n\t\tstd::clock_t cpu_time = std::clock();\n\t\tdouble cpu_time_d = static_cast<double>(cpu_time) / CLOCKS_PER_SEC;\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(cpu_time_d));\n\t}\n\telse if (type_name == \"mono\")\n\t{\n\t\t// monotonic clock time; this is best for measured user-perceived elapsed times\n\t\tdouble seconds = Eidos_WallTimeSeconds();\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(seconds));\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_clock): unrecognized clock type \" << type_name << \" in function clock().\" << EidosTerminate(nullptr);\n\t}\n}\n\n//\t(string$)date(void)\nEidosValue_SP Eidos_ExecuteFunction_date(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\ttime_t rawtime;\n\tstruct tm timeinfo;\n\tchar buffer[25];\t// should never be more than 10, in fact, plus a null\n\t\n\ttime(&rawtime);\n\tlocaltime_r(&rawtime, &timeinfo);\n\tstrftime(buffer, 25, \"%d-%m-%Y\", &timeinfo);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(std::string(buffer)));\n\t\n\treturn result_SP;\n}\n\n//\t(string$)debugIndent(void)\nEidosValue_SP Eidos_ExecuteFunction_debugIndent(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n#if DEBUG_POINTS_ENABLED\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(EidosDebugPointIndent::Indent()));\n#else\n\treturn gStaticEidosValue_StringEmpty;\n#endif\n}\n\nstatic bool Eidos_IsIdentifier(const std::string &symbol_name)\n{\n\t// checks that symbol_name is a valid identifier; this is similar to the identifier parsing code in EidosScript::Tokenize(),\n\t// but we know the length of symbol_name ahead of time, so the UTF handling is a bit different\n\tbool first_char = true, saw_unicode = false;\n\tsize_t pos = 0, len = symbol_name.length();\n\t\n\twhile (pos < len)\n\t{\n\t\tint chx = (unsigned char)symbol_name[pos];\n\t\t\n\t\t// 0..9 are fine as long as it's not the first position\n\t\tif (!first_char)\n\t\t\tif ((chx >= '0') && (chx <= '9'))\n\t\t\t{\n\t\t\t\tpos++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\n\t\tfirst_char = false;\n\t\t\n\t\t// a..z, A..Z, _ are all fine anywhere in an identifier\n\t\tif (((chx >= 'a') && (chx <= 'z')) || ((chx >= 'A') && (chx <= 'Z')) || (chx == '_'))\n\t\t{\n\t\t\tpos++;\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// if the high bit is set, this is the start of a UTF-8 multi-byte sequence; eat the whole sequence\n\t\t// the design of this code assumes that UTF-8 sequences are compliant; checking compliance is harder\n\t\tif (chx & 0x0080)\n\t\t{\n\t\t\t// we accept the current character, and now advance over the characters following it\n\t\t\tpos++;\n\t\t\tsaw_unicode = true;\n\t\t\t\n\t\t\twhile (pos < len)\n\t\t\t{\n\t\t\t\tint chn = (unsigned char)symbol_name[pos];\n\t\t\t\t\n\t\t\t\tif ((chn & 0x00C0) == 0x00C0)\t// start of a new Unicode multi-byte sequence; stop\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (chn & 0x0080)\t\t\t// trailing byte of the current Unicode multi-byte sequence; eat it\n\t\t\t\t{\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\telse\t\t\t\t\t\t\t// an ordinary character following the Unicode sequence; stop\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// at this point, we have advanced to the character after the end of the Unicode sequence; pos++ is not needed\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// an illegal character was encountered\n\t\treturn false;\n\t}\n\t\n\tif (saw_unicode && Eidos_ContainsIllegalUnicode(symbol_name))\n\t\treturn false;\n\t\n\treturn true;\n}\n\n//\t(void)defineConstant(string$ symbol, * x)\nEidosValue_SP Eidos_ExecuteFunction_defineConstant(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_String *symbol_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &symbol_name = symbol_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (!Eidos_IsIdentifier(symbol_name))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_defineConstant): defineConstant() requires that symbol is a valid Eidos identifier.\" << EidosTerminate(nullptr);\n\t\n\tconst EidosValue_SP &x_value_sp = p_arguments[1];\n\tEidosGlobalStringID symbol_id = EidosStringRegistry::GlobalStringIDForString(symbol_name);\n\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\n\t\n\t// Object values can only be remembered if their class is under retain/release, so that we have control over the object lifetime\n\t// See also EidosDictionaryUnretained::ExecuteMethod_Accelerated_setValue() and Eidos_ExecuteFunction_defineGlobal(), which enforce the same rule\n\tif (x_value_sp->Type() == EidosValueType::kValueObject)\n\t{\n\t\tconst EidosClass *x_value_class = ((EidosValue_Object *)x_value_sp.get())->Class();\n\t\t\n\t\tif (!x_value_class->UsesRetainRelease())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_defineConstant): defineConstant() can only accept object classes that are under retain/release memory management internally; class \" << x_value_class->ClassName() << \" is not.  This restriction is necessary in order to guarantee that the kept object elements remain valid.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tsymbols.DefineConstantForSymbol(symbol_id, x_value_sp);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)defineGlobal(string$ symbol, * x)\nEidosValue_SP Eidos_ExecuteFunction_defineGlobal(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_String *symbol_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &symbol_name = symbol_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (!Eidos_IsIdentifier(symbol_name))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_defineConstant): defineConstant() requires that symbol is a valid Eidos identifier.\" << EidosTerminate(nullptr);\n\t\n\tconst EidosValue_SP &x_value_sp = p_arguments[1];\n\tEidosGlobalStringID symbol_id = EidosStringRegistry::GlobalStringIDForString(symbol_name);\n\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\n\t\n\t// Object values can only be remembered if their class is under retain/release, so that we have control over the object lifetime\n\t// See also EidosDictionaryUnretained::ExecuteMethod_Accelerated_setValue() and Eidos_ExecuteFunction_defineConstant(), which enforce the same rule\n\tif (x_value_sp->Type() == EidosValueType::kValueObject)\n\t{\n\t\tconst EidosClass *x_value_class = ((EidosValue_Object *)x_value_sp.get())->Class();\n\t\t\n\t\tif (!x_value_class->UsesRetainRelease())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_defineGlobal): defineGlobal() can only accept object classes that are under retain/release memory management internally; class \" << x_value_class->ClassName() << \" is not.  This restriction is necessary in order to guarantee that the kept object elements remain valid.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// this checks IsIteratorVariable() on an existing global value for us\n\tsymbols.DefineGlobalForSymbol(symbol_id, x_value_sp);\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(*)doCall(string$ functionName, ...)\nEidosValue_SP Eidos_ExecuteFunction_doCall(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *functionName_value = (EidosValue_String *)p_arguments[0].get();\n\tconst std::string &function_name = functionName_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\t// Copy the argument list; this is a little slow, but not a big deal, and it provides protection against re-entrancy\n\tstd::vector<EidosValue_SP> arguments;\n\t\n\tfor (int argument_index = 1; argument_index < argument_count; argument_index++)\n\t\targuments.emplace_back(p_arguments[argument_index]);\n\t\n\t// Look up the signature for this function dynamically\n\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\n\tauto signature_iter = function_map.find(function_name);\n\t\n\tif (signature_iter == function_map.end())\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_doCall): unrecognized function name \" << function_name << \" in function doCall().\";\n\t\tif (p_interpreter.Context() == nullptr)\n\t\t\tEIDOS_TERMINATION << \"  This may be because the current Eidos context (such as the current SLiM simulation) is invalid.\";\n\t\tEIDOS_TERMINATION << EidosTerminate(nullptr);\n\t}\n\t\n\tconst EidosFunctionSignature *function_signature = signature_iter->second.get();\n\t\n\t// Check the function's arguments\n\tfunction_signature->CheckArguments(arguments);\n\t\n\t// BEWARE!  Since the function called here could be a function, like executeLambda() or apply() or sapply(),\n\t// that causes re-entrancy into the Eidos engine, this call is rather dangerous.  See the comments on those\n\t// functions for further details.\n\tif (function_signature->internal_function_)\n\t{\n\t\tresult_SP = function_signature->internal_function_(arguments, p_interpreter);\n\t}\n\telse if (function_signature->body_script_)\n\t{\n\t\tresult_SP = p_interpreter.DispatchUserDefinedFunction(*function_signature, arguments);\n\t}\n\telse if (!function_signature->delegate_name_.empty())\n\t{\n\t\tEidosContext *context = p_interpreter.Context();\n\t\t\n\t\tif (context)\n\t\t\tresult_SP = context->ContextDefinedFunctionDispatch(function_name, arguments, p_interpreter);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_doCall): (internal error) function \" << function_name << \" is defined by the Context, but the Context is not defined.\" << EidosTerminate(nullptr);\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_doCall): (internal error) unbound function \" << function_name << \".\" << EidosTerminate(nullptr);\n\t\n\t// Check the return value against the signature\n\tfunction_signature->CheckReturn(*result_SP);\n\t\n\treturn result_SP;\n}\n\n// This is an internal utility method that implements executeLambda() and _executeLambda_OUTER().\n// The purpose of the p_execute_in_outer_scope flag is specifically for the source() function.  Since\n// source() is a user-defined function, it executes in a new scope with its own variables table.\n// However, we don't want that; we want it to execute the source file in the caller's scope.  So it\n// uses a special internal version of executeLambda(), named _executeLambda_OUTER(), that achieves\n// that by passing true here for p_execute_in_outer_scope.  Yes, this is a hack; an end-user could\n// not implement source() themselves as a user-defined function without using private API.  That's\n// OK, though; many Eidos built-in functions could not be implemented in Eidos themselves.\nEidosValue_SP Eidos_ExecuteLambdaInternal(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter, bool p_execute_in_outer_scope)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *lambdaSource_value = p_arguments[0].get();\n\tEidosValue_String *lambdaSource_value_singleton = (EidosValue_String *)p_arguments[0].get();\n\tEidosScript *script = lambdaSource_value_singleton->CachedScript();\n\t\n\t// Errors in lambdas should be reported for the lambda script, not for the calling script,\n\t// if possible.  In the GUI this does not work well, however; there, errors should be\n\t// reported as occurring in the call to executeLambda().  Here we save off the current\n\t// error context and set up the error context for reporting errors inside the lambda,\n\t// in case that is possible; see how exceptions are handled below.\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\n\t// We try to do tokenization and parsing once per script, by caching the script inside the EidosValue_String_singleton instance\n\tif (!script)\n\t{\n\t\tscript = new EidosScript(lambdaSource_value->StringAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\t\n\t\ttry\n\t\t{\n\t\t\tscript->Tokenize();\n\t\t\tscript->ParseInterpreterBlockToAST(true);\n\t\t\t\n\t\t\t// Note that true is passed to ParseInterpreterBlockToAST(), indicating that the script is to parse the code for the lambda\n\t\t\t// as if it were a top-level interpreter block, allowing functions to be defined.  We don't actually know, here, whether we\n\t\t\t// have been called at the top level or not, but we allow function definitions regardless.  Eidos doesn't disallow function\n\t\t\t// definitions inside blocks for any particularly strong reason; the reason is mostly just that such declarations look like\n\t\t\t// they should be scoped, because in most languages they are.  Since in Eidos they wouldn't be (no scope), we disallow them\n\t\t\t// to prevent confusion.  But when a function is declared inside executeLambda(), the user is presumably advanced and knows\n\t\t\t// what they're doing; there's no need to get in their way.  Sometimes it might be convenient to declare a function in this\n\t\t\t// way, particularly inside a file executed by source(); so let's  let the user do that, rather than bending over backwards\n\t\t\t// to prevent it (which is actually difficult, if you want to allow it when executeLambda() is called at the top level).\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tif (gEidosTerminateThrows)\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"ExecuteLambdaInternal()\");\n\t\t\t}\n\t\t\t\n\t\t\tdelete script;\n\t\t\t\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\tif (lambdaSource_value_singleton)\n\t\t\tlambdaSource_value_singleton->SetCachedScript(script);\n\t}\n\t\n\t// Execute inside try/catch so we can handle errors well\n\tEidosValue *timed_value = p_arguments[1].get();\n\tEidosValueType timed_value_type = timed_value->Type();\n\tbool timed = false;\n\tint timer_type = 0;\t\t// cpu by default, for legacy reasons\n\t\n\tif (timed_value_type == EidosValueType::kValueLogical)\n\t{\n\t\tif (timed_value->LogicalAtIndex_NOCAST(0, nullptr))\n\t\t\ttimed = true;\n\t}\n\telse if (timed_value_type == EidosValueType::kValueString)\n\t{\n\t\tconst std::string &timed_string = ((EidosValue_String *)timed_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (timed_string == \"cpu\")\n\t\t{\n\t\t\ttimed = true;\n\t\t\ttimer_type = 0;\t\t// cpu timer\n\t\t}\n\t\telse if (timed_string == \"mono\")\n\t\t{\n\t\t\ttimed = true;\n\t\t\ttimer_type = 1;\t\t// monotonic timer\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteLambdaInternal): unrecognized clock type \" << timed_string << \" in function executeLambda().\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\t\n\tstd::clock_t begin_clock = 0, end_clock = 0;\n\tstd::chrono::steady_clock::time_point begin_ts, end_ts;\n\t\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\n\ttry\n\t{\n\t\tEidosSymbolTable *symbols = &p_interpreter.SymbolTable();\t\t\t\t\t\t\t\t\t// use our own symbol table\n\t\t\n\t\tif (p_execute_in_outer_scope)\n\t\t\tsymbols = symbols->ParentSymbolTable();\n\t\t\n\t\tEidosInterpreter interpreter(*script, *symbols, p_interpreter.FunctionMap(), p_interpreter.Context(), p_interpreter.ExecutionOutputStream(), p_interpreter.ErrorOutputStream()\n#ifdef SLIMGUI\n\t\t\t, p_interpreter.check_infinite_loops_\n#endif\n\t\t\t);\n\t\t\n\t\tif (timed)\n\t\t{\n\t\t\tif (timer_type == 0)\n\t\t\t\tbegin_clock = std::clock();\n\t\t\telse\n\t\t\t\tbegin_ts = std::chrono::steady_clock::now();\n\t\t}\n\t\t\n\t\t// Get the result.  BEWARE!  This calls causes re-entry into the Eidos interpreter, which is not usually\n\t\t// possible since Eidos does not support multithreaded usage.  This is therefore a key failure point for\n\t\t// bugs that would otherwise not manifest.\n\t\tresult_SP = interpreter.EvaluateInterpreterBlock(false, true);\t\t// do not print output, return the last statement value\n\t\t\n\t\tif (timed)\n\t\t{\n\t\t\tif (timer_type == 0)\n\t\t\t\tend_clock = std::clock();\n\t\t\telse\n\t\t\t\tend_ts = std::chrono::steady_clock::now();\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\t// If exceptions throw, then we want to set up the error information to highlight the\n\t\t// executeLambda() that failed, since we can't highlight the actual error.  (If exceptions\n\t\t// don't throw, this catch block will never be hit; exit() will already have been called\n\t\t// and the error will have been reported from the context of the lambda script string.)\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"ExecuteLambdaInternal()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!lambdaSource_value_singleton)\n\t\t\tdelete script;\n\t\t\n\t\tthrow;\n\t}\n\t\n\t// Restore the normal error context in the event that no exception occurring within the lambda\n\tgEidosErrorContext = error_context_save;\n\t\n\tif (timed)\n\t{\n\t\tdouble time_spent;\n\t\t\n\t\tif (timer_type == 0)\n\t\t\ttime_spent = static_cast<double>(end_clock - begin_clock) / CLOCKS_PER_SEC;\n\t\telse\n\t\t\ttime_spent = std::chrono::duration<double>(end_ts - begin_ts).count();\n\t\t\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tp_interpreter.ExecutionOutputStream() << \"// ********** executeLambda() elapsed time: \" << time_spent << std::endl;\n\t}\n\t\n\tif (!lambdaSource_value_singleton)\n\t\tdelete script;\n\t\n\treturn result_SP;\n}\n\n//\t(*)executeLambda(string$ lambdaSource, [ls$ timed = F])\nEidosValue_SP Eidos_ExecuteFunction_executeLambda(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\treturn Eidos_ExecuteLambdaInternal(p_arguments, p_interpreter, false);\n}\n\n//\t(*)_executeLambda_OUTER(string$ lambdaSource, [ls$ timed = F])\nEidosValue_SP Eidos_ExecuteFunction__executeLambda_OUTER(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\treturn Eidos_ExecuteLambdaInternal(p_arguments, p_interpreter, true);\t// see Eidos_ExecuteLambdaInternal() for comments on the true flag\n}\n\n//\t(logical)exists(string symbol)\nEidosValue_SP Eidos_ExecuteFunction_exists(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\n\tEidosValue_String *symbol_value = (EidosValue_String *)p_arguments[0].get();\n\tint symbol_count = symbol_value->Count();\n\t\n\tif ((symbol_count == 1) && (symbol_value->DimensionCount() == 1))\n\t{\n\t\t// Use the global constants, but only if we do not have to impose a dimensionality upon the value below\n\t\tEidosGlobalStringID symbol_id = EidosStringRegistry::GlobalStringIDForString(symbol_value->StringRefAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tresult_SP = (symbols.ContainsSymbol(symbol_id) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(symbol_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < symbol_count; ++value_index)\n\t\t{\n\t\t\tEidosGlobalStringID symbol_id = EidosStringRegistry::GlobalStringIDForString(symbol_value->StringRefAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tlogical_result->set_logical_no_check(symbols.ContainsSymbol(symbol_id), value_index);\n\t\t}\n\t\t\n\t\tresult_SP->CopyDimensionsFromValue(symbol_value);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(void)functionSignature([Ns$ functionName = NULL])\nEidosValue_SP Eidos_ExecuteFunction_functionSignature(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *functionName_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\tbool function_name_specified = (functionName_value->Type() == EidosValueType::kValueString);\n\tstd::string match_string = (function_name_specified ? functionName_value->StringAtIndex_NOCAST(0, nullptr) : gEidosStr_empty_string);\n\tbool signature_found = false;\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\t// function_map_ is already alphabetized since maps keep sorted order\n\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\n\t\n\tfor (const auto &functionPairIter : function_map)\n\t{\n\t\tconst EidosFunctionSignature *iter_signature = functionPairIter.second.get();\n\t\t\n\t\tif (function_name_specified && (iter_signature->call_name_.compare(match_string) != 0))\n\t\t\tcontinue;\n\t\t\n\t\tif (!function_name_specified && (iter_signature->call_name_.substr(0, 1).compare(\"_\") == 0))\n\t\t\tcontinue;\t// skip internal functions that start with an underscore, unless specifically requested\n\t\t\n\t\toutput_stream << *iter_signature;\n\t\t\n\t\tif (iter_signature->body_script_ && iter_signature->user_defined_)\n\t\t{\n\t\t\toutput_stream << \" <user-defined>\";\n\t\t}\n\t\t\n\t\toutput_stream << std::endl;\n\t\t\n\t\tsignature_found = true;\n\t}\n\t\n\tif (function_name_specified && !signature_found)\n\t{\n\t\toutput_stream << \"No function signature found for '\" << match_string << \"'.\";\n\t\tif (p_interpreter.Context() == nullptr)\n\t\t\toutput_stream << \"  This may be because the current Eidos context (such as the current SLiM simulation) is invalid.\";\n\t\toutput_stream << std::endl;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)functionSource(s$ functionName)\nEidosValue_SP Eidos_ExecuteFunction_functionSource(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *functionName_value = p_arguments[0].get();\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\tstd::string match_string = functionName_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\t// function_map_ is already alphabetized since maps keep sorted order\n\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\n\t\n\tfor (const auto &functionPairIter : function_map)\n\t{\n\t\tconst EidosFunctionSignature *iter_signature = functionPairIter.second.get();\n\t\t\n\t\tif (iter_signature->call_name_.compare(match_string) != 0)\n\t\t\tcontinue;\n\t\t\n\t\toutput_stream << *iter_signature;\n\t\t\n\t\tif (iter_signature->body_script_ && iter_signature->user_defined_)\n\t\t{\n\t\t\toutput_stream << \" <user-defined>\";\n\t\t}\n\t\t\n\t\toutput_stream << std::endl;\n\t\t\n\t\tif (iter_signature->body_script_)\n\t\t\toutput_stream << iter_signature->body_script_->String() << std::endl;\n\t\telse\n\t\t\toutput_stream << \"no Eidos source available (implemented in C++)\" << std::endl;\n\t\t\n\t\treturn gStaticEidosValueVOID;\n\t}\n\t\n\toutput_stream << \"No function found for '\" << match_string << \"'.\";\n\tif (p_interpreter.Context() == nullptr)\n\t\toutput_stream << \"  This may be because the current Eidos context (such as the current SLiM simulation) is invalid.\";\n\toutput_stream << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(integer$)getSeed(void)\nEidosValue_SP Eidos_ExecuteFunction_getSeed(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tunsigned long int last_seed;\n\t\n#pragma omp critical (Eidos_RNG_State)\n\t{\n\t\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(0);\t// thread 0 has the original RNG seed requested by the user\n\t\t\n\t\tlast_seed = rng_state->rng_last_seed_;\n\t}\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(last_seed));\n\t\n\treturn result_SP;\n}\n\n//\t(void)license(void)\nEidosValue_SP Eidos_ExecuteFunction_license(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\n\toutput_stream << \"Eidos is free software: you can redistribute it and/or\" << std::endl;\n\toutput_stream << \"modify it under the terms of the GNU General Public\" << std::endl;\n\toutput_stream << \"License as published by the Free Software Foundation,\" << std::endl;\n\toutput_stream << \"either version 3 of the License, or (at your option)\" << std::endl;\n\toutput_stream << \"any later version.\" << std::endl << std::endl;\n\t\n\toutput_stream << \"Eidos is distributed in the hope that it will be\" << std::endl;\n\toutput_stream << \"useful, but WITHOUT ANY WARRANTY; without even the\" << std::endl;\n\toutput_stream << \"implied warranty of MERCHANTABILITY or FITNESS FOR\" << std::endl;\n\toutput_stream << \"A PARTICULAR PURPOSE.  See the GNU General Public\" << std::endl;\n\toutput_stream << \"License for more details.\" << std::endl << std::endl;\n\t\n\toutput_stream << \"You should have received a copy of the GNU General\" << std::endl;\n\toutput_stream << \"Public License along with Eidos.  If not, see\" << std::endl;\n\toutput_stream << \"<http://www.gnu.org/licenses/>.\" << std::endl << std::endl;\n\t\n\tif (gEidosContextLicense.length())\n\t{\n\t\toutput_stream << \"---------------------------------------------------------\" << std::endl << std::endl;\n\t\toutput_stream << gEidosContextLicense << std::endl;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)ls([logical$ showSymbolTables = F])\nEidosValue_SP Eidos_ExecuteFunction_ls(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tbool showSymbolTables = p_arguments[0]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tstd::ostream &outstream = p_interpreter.ExecutionOutputStream();\n\tEidosSymbolTable &current_symbol_table = p_interpreter.SymbolTable();\n\t\n\tif (showSymbolTables)\n\t{\n\t\tEidosSymbolTable *table = &current_symbol_table;\n\t\t\n\t\twhile (table)\n\t\t{\n\t\t\ttable->PrintSymbolTable(outstream);\n\t\t\toutstream << std::endl;\n\t\t\t\n\t\t\t// Go to the next symbol table up in the chain; note that we use ChainSymbolTable(), not ParentSymbolTable(),\n\t\t\t// because we only want to show symbol tables that are relevant to the current scope\n\t\t\ttable = table->ChainSymbolTable();\n\t\t}\n\t}\n\telse\n\t{\n\t\toutstream << current_symbol_table;\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(integer$)parallelGetNumThreads(void)\nEidosValue_SP Eidos_ExecuteFunction_parallelGetNumThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidosNumThreads));\n\t\n\treturn result_SP;\n}\n\n//\t(integer$)parallelGetMaxThreads(void)\nEidosValue_SP Eidos_ExecuteFunction_parallelGetMaxThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidosMaxThreads));\n\t\n\treturn result_SP;\n}\n\n//\t(object<Dictionary>$)parallelGetTaskThreadCounts(void)\nEidosValue_SP Eidos_ExecuteFunction_parallelGetTaskThreadCounts(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosDictionaryRetained *objectElement = new EidosDictionaryRetained();\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(objectElement, gEidosDictionaryRetained_Class));\n\t\n\tobjectElement->Release();\t// retained by result_SP now\n\t\n#ifdef _OPENMP\n\tobjectElement->SetKeyValue_StringKeys(\"ABS_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_ABS_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"CEIL\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_CEIL)));\n\tobjectElement->SetKeyValue_StringKeys(\"EXP_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_EXP_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"FLOOR\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FLOOR)));\n\tobjectElement->SetKeyValue_StringKeys(\"LOG_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_LOG_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"LOG10_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_LOG10_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"LOG2_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_LOG2_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"ROUND\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_ROUND)));\n\tobjectElement->SetKeyValue_StringKeys(\"SQRT_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SQRT_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SUM_INTEGER\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SUM_INTEGER)));\n\tobjectElement->SetKeyValue_StringKeys(\"SUM_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SUM_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SUM_LOGICAL\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SUM_LOGICAL)));\n\tobjectElement->SetKeyValue_StringKeys(\"TRUNC\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_TRUNC)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"MAX_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MAX_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"MAX_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MAX_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"MIN_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MIN_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"MIN_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MIN_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMAX_INT_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMAX_INT_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMAX_INT_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMAX_INT_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMAX_FLOAT_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMAX_FLOAT_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMAX_FLOAT_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMAX_FLOAT_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMIN_INT_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMIN_INT_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMIN_INT_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMIN_INT_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMIN_FLOAT_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMIN_FLOAT_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"PMIN_FLOAT_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PMIN_FLOAT_2)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"MATCH_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MATCH_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"MATCH_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MATCH_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"MATCH_STRING\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MATCH_STRING)));\n\tobjectElement->SetKeyValue_StringKeys(\"MATCH_OBJECT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MATCH_OBJECT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_INDEX\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_INDEX)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_R_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_R_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_R_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_R_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_R_OBJECT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_R_OBJECT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_WR_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_WR_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_WR_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_WR_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_WR_OBJECT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_WR_OBJECT)));\n\tobjectElement->SetKeyValue_StringKeys(\"TABULATE_MAXBIN\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_TABULATE_MAXBIN)));\n\tobjectElement->SetKeyValue_StringKeys(\"TABULATE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_TABULATE)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"CONTAINS_MARKER_MUT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_CONTAINS_MARKER_MUT)));\n\tobjectElement->SetKeyValue_StringKeys(\"I_COUNT_OF_MUTS_OF_TYPE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE)));\n\tobjectElement->SetKeyValue_StringKeys(\"G_COUNT_OF_MUTS_OF_TYPE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE)));\n\tobjectElement->SetKeyValue_StringKeys(\"INDS_W_PEDIGREE_IDS\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_INDS_W_PEDIGREE_IDS)));\n\tobjectElement->SetKeyValue_StringKeys(\"RELATEDNESS\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RELATEDNESS)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_INDIVIDUALS_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_INDIVIDUALS_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"SAMPLE_INDIVIDUALS_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SAMPLE_INDIVIDUALS_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_FITNESS_SCALE_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_FITNESS_SCALE_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_FITNESS_SCALE_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_FITNESS_SCALE_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"SUM_OF_MUTS_OF_TYPE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"DNORM_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_DNORM_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"DNORM_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_DNORM_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RBINOM_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RBINOM_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"RBINOM_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RBINOM_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RBINOM_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RBINOM_3)));\n\tobjectElement->SetKeyValue_StringKeys(\"RDUNIF_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RDUNIF_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"RDUNIF_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RDUNIF_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RDUNIF_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RDUNIF_3)));\n\tobjectElement->SetKeyValue_StringKeys(\"REXP_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_REXP_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"REXP_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_REXP_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RNORM_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RNORM_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"RNORM_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RNORM_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RNORM_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RNORM_3)));\n\tobjectElement->SetKeyValue_StringKeys(\"RPOIS_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RPOIS_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"RPOIS_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RPOIS_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RUNIF_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RUNIF_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"RUNIF_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RUNIF_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"RUNIF_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_RUNIF_3)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"SORT_INT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SORT_INT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SORT_FLOAT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SORT_FLOAT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SORT_STRING\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SORT_STRING)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_IN_BOUNDS_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_IN_BOUNDS_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_IN_BOUNDS_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_IN_BOUNDS_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_IN_BOUNDS_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_IN_BOUNDS_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_PERIODIC_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_PERIODIC_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_PERIODIC_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_PERIODIC_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_PERIODIC_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_PERIODIC_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_REFLECTED_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_REFLECTED_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_REFLECTED_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_REFLECTED_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_REFLECTED_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_REFLECTED_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_STOPPED_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_STOPPED_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_STOPPED_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_STOPPED_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_STOPPED_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_STOPPED_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_UNIFORM_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_UNIFORM_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_UNIFORM_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_UNIFORM_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"POINT_UNIFORM_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_POINT_UNIFORM_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_1_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_1_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_1_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_1_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_1_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_1_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_2_1D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_2_1D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_2_2D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_2_2D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SET_SPATIAL_POS_2_3D\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SET_SPATIAL_POS_2_3D)));\n\tobjectElement->SetKeyValue_StringKeys(\"SPATIAL_MAP_VALUE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SPATIAL_MAP_VALUE)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"CLIPPEDINTEGRAL_1S\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_CLIPPEDINTEGRAL_1S)));\n\tobjectElement->SetKeyValue_StringKeys(\"CLIPPEDINTEGRAL_2S\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_CLIPPEDINTEGRAL_2S)));\n\t//objectElement->SetKeyValue_StringKeys(\"CLIPPEDINTEGRAL_3S\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_CLIPPEDINTEGRAL_3S)));\n\tobjectElement->SetKeyValue_StringKeys(\"DRAWBYSTRENGTH\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_DRAWBYSTRENGTH)));\n\tobjectElement->SetKeyValue_StringKeys(\"INTNEIGHCOUNT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_INTNEIGHCOUNT)));\n\tobjectElement->SetKeyValue_StringKeys(\"LOCALPOPDENSITY\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_LOCALPOPDENSITY)));\n\tobjectElement->SetKeyValue_StringKeys(\"NEARESTINTNEIGH\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_NEARESTINTNEIGH)));\n\tobjectElement->SetKeyValue_StringKeys(\"NEARESTNEIGH\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_NEARESTNEIGH)));\n\tobjectElement->SetKeyValue_StringKeys(\"NEIGHCOUNT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_NEIGHCOUNT)));\n\tobjectElement->SetKeyValue_StringKeys(\"TOTNEIGHSTRENGTH\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_TOTNEIGHSTRENGTH)));\n\t\n\tobjectElement->SetKeyValue_StringKeys(\"AGE_INCR\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_AGE_INCR)));\n\tobjectElement->SetKeyValue_StringKeys(\"DEFERRED_REPRO\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_DEFERRED_REPRO)));\n\tobjectElement->SetKeyValue_StringKeys(\"WF_REPRO\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_WF_REPRO)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_ASEX_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_ASEX_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_ASEX_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_ASEX_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_ASEX_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_ASEX_3)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_SEX_1\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_SEX_1)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_SEX_2\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_SEX_2)));\n\tobjectElement->SetKeyValue_StringKeys(\"FITNESS_SEX_3\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_FITNESS_SEX_3)));\n\tobjectElement->SetKeyValue_StringKeys(\"MIGRANT_CLEAR\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_MIGRANT_CLEAR)));\n\tobjectElement->SetKeyValue_StringKeys(\"SIMPLIFY_SORT_PRE\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SIMPLIFY_SORT_PRE)));\n\tobjectElement->SetKeyValue_StringKeys(\"SIMPLIFY_SORT\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SIMPLIFY_SORT)));\n\tobjectElement->SetKeyValue_StringKeys(\"SIMPLIFY_SORT_POST\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SIMPLIFY_SORT_POST)));\n\tobjectElement->SetKeyValue_StringKeys(\"PARENTS_CLEAR\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_PARENTS_CLEAR)));\n\tobjectElement->SetKeyValue_StringKeys(\"UNIQUE_MUTRUNS\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_UNIQUE_MUTRUNS)));\n\tobjectElement->SetKeyValue_StringKeys(\"SURVIVAL\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(gEidos_OMP_threads_SURVIVAL)));\n#endif\n\t\n\tobjectElement->ContentsChanged(\"parallelGetTaskThreadCounts()\");\n\treturn result_SP;\n}\n\n//\t(void)parallelSetNumThreads([Ni$ numThreads = NULL])\nEidosValue_SP Eidos_ExecuteFunction_parallelSetNumThreads(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *numThreads_value = p_arguments[0].get();\n\t\n\tint64_t numThreads = gEidosMaxThreads;\t\t// the default value, used for NULL\n\t\n\tif (numThreads_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\t// An explicit override has been requested, even if numThreads == gEidosMaxThreads\n\t\tnumThreads = numThreads_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tgEidosNumThreadsOverride = true;\n\t}\n\telse\n\t{\n\t\t// The user has requested, with NULL, that the default thread usage pattern not be overridden\n\t\tgEidosNumThreadsOverride = false;\n\t}\n\t\n\tif (numThreads < 1)\n\t\tnumThreads = 1;\n\tif (numThreads > gEidosMaxThreads)\n\t\tnumThreads = gEidosMaxThreads;\n\t\n\tgEidosNumThreads = (int)numThreads;\n\tomp_set_num_threads((int)numThreads);\n\t\n\t// Note that this affects every running model, in SLiMgui.  Since we don't really support end users running SLiMgui\n\t// multithreaded, I'm not going to bother fixing that by saving/restoring it across SLiMgui context switches.\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)parallelSetTaskThreadCounts(No<Dictionary>$ dict)\nEidosValue_SP Eidos_ExecuteFunction_parallelSetTaskThreadCounts(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *source_value = p_arguments[0].get();\n\t\n\tif (source_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\t// A dict value of NULL means \"reset to the command-line default settings\"\n#ifdef _OPENMP\n\t\t_Eidos_SetOpenMPThreadCounts(gEidosDefaultPerTaskThreadCounts);\n#endif\n\t}\n\telse\n\t{\n\t\tEidosDictionaryUnretained *source = (EidosDictionaryUnretained *)source_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (source->KeysAreStrings())\n\t\t{\n\t\t\tconst EidosDictionaryHashTable_StringKeys *source_symbols = source->DictionarySymbols_StringKeys();\n\t\t\tconst std::vector<std::string> source_keys = source->SortedKeys_StringKeys();\n\t\t\t\n\t\t\tif (source_symbols && source_symbols->size())\n\t\t\t{\n\t\t\t\tfor (const std::string &key : source_keys)\n\t\t\t\t{\n\t\t\t\t\tauto kv_pair = source_symbols->find(key);\n\t\t\t\t\tconst EidosValue_SP &value = kv_pair->second;\n\t\t\t\t\t\n\t\t\t\t\tif ((value->Type() == EidosValueType::kValueInt) && (value->Count() == 1))\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t value_int64 = value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((value_int64 < 1) || (value_int64 > EIDOS_OMP_MAX_THREADS))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_parallelSetTaskThreadCounts): parallelSetTaskThreadCounts() requires thread counts to be in [1, \" << EIDOS_OMP_MAX_THREADS << \"].\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n#ifdef _OPENMP\n\t\t\t\t\t\t// We only actually process the key-value pairs when running multithreaded;\n\t\t\t\t\t\t// single-threaded, they are all ignored (for cross-compatibility).\n\t\t\t\t\t\tif (key == \"ABS_FLOAT\")\t\t\t\t\t\t\tgEidos_OMP_threads_ABS_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"CEIL\")\t\t\t\t\t\t\tgEidos_OMP_threads_CEIL = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"EXP_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_EXP_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FLOOR\")\t\t\t\t\t\tgEidos_OMP_threads_FLOOR = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"LOG_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_LOG_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"LOG10_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_LOG10_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"LOG2_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_LOG2_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"ROUND\")\t\t\t\t\t\tgEidos_OMP_threads_ROUND = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SQRT_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_SQRT_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SUM_INTEGER\")\t\t\t\t\tgEidos_OMP_threads_SUM_INTEGER = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SUM_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_SUM_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SUM_LOGICAL\")\t\t\t\t\tgEidos_OMP_threads_SUM_LOGICAL = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"TRUNC\")\t\t\t\t\t\tgEidos_OMP_threads_TRUNC = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"MAX_INT\")\t\t\t\t\t\tgEidos_OMP_threads_MAX_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MAX_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_MAX_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MIN_INT\")\t\t\t\t\t\tgEidos_OMP_threads_MIN_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MIN_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_MIN_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMAX_INT_1\")\t\t\t\t\tgEidos_OMP_threads_PMAX_INT_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMAX_INT_2\")\t\t\t\t\tgEidos_OMP_threads_PMAX_INT_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMAX_FLOAT_1\")\t\t\t\t\tgEidos_OMP_threads_PMAX_FLOAT_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMAX_FLOAT_2\")\t\t\t\t\tgEidos_OMP_threads_PMAX_FLOAT_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMIN_INT_1\")\t\t\t\t\tgEidos_OMP_threads_PMIN_INT_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMIN_INT_2\")\t\t\t\t\tgEidos_OMP_threads_PMIN_INT_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMIN_FLOAT_1\")\t\t\t\t\tgEidos_OMP_threads_PMIN_FLOAT_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PMIN_FLOAT_2\")\t\t\t\t\tgEidos_OMP_threads_PMIN_FLOAT_2 = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"MATCH_INT\")\t\t\t\t\tgEidos_OMP_threads_MATCH_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MATCH_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_MATCH_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MATCH_STRING\")\t\t\t\t\tgEidos_OMP_threads_MATCH_STRING = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MATCH_OBJECT\")\t\t\t\t\tgEidos_OMP_threads_MATCH_OBJECT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_INDEX\")\t\t\t\t\tgEidos_OMP_threads_SAMPLE_INDEX = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_R_INT\")\t\t\t\t\tgEidos_OMP_threads_SAMPLE_R_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_R_FLOAT\")\t\t\t\tgEidos_OMP_threads_SAMPLE_R_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_R_OBJECT\")\t\t\t\tgEidos_OMP_threads_SAMPLE_R_OBJECT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_WR_INT\")\t\t\t\tgEidos_OMP_threads_SAMPLE_WR_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_WR_FLOAT\")\t\t\t\tgEidos_OMP_threads_SAMPLE_WR_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_WR_OBJECT\")\t\t\t\tgEidos_OMP_threads_SAMPLE_WR_OBJECT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"TABULATE_MAXBIN\")\t\t\t\tgEidos_OMP_threads_TABULATE_MAXBIN = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"TABULATE\")\t\t\t\t\t\tgEidos_OMP_threads_TABULATE = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"CONTAINS_MARKER_MUT\")\t\t\tgEidos_OMP_threads_CONTAINS_MARKER_MUT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"I_COUNT_OF_MUTS_OF_TYPE\")\t\tgEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"G_COUNT_OF_MUTS_OF_TYPE\")\t\tgEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"INDS_W_PEDIGREE_IDS\")\t\t\tgEidos_OMP_threads_INDS_W_PEDIGREE_IDS = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RELATEDNESS\")\t\t\t\t\tgEidos_OMP_threads_RELATEDNESS = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_INDIVIDUALS_1\")\t\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SAMPLE_INDIVIDUALS_2\")\t\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_FITNESS_SCALE_1\")\t\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_FITNESS_SCALE_2\")\t\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SUM_OF_MUTS_OF_TYPE\")\t\t\tgEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"DNORM_1\")\t\t\t\t\t\tgEidos_OMP_threads_DNORM_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"DNORM_2\")\t\t\t\t\t\tgEidos_OMP_threads_DNORM_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RBINOM_1\")\t\t\t\t\t\tgEidos_OMP_threads_RBINOM_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RBINOM_2\")\t\t\t\t\t\tgEidos_OMP_threads_RBINOM_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RBINOM_3\")\t\t\t\t\t\tgEidos_OMP_threads_RBINOM_3 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RDUNIF_1\")\t\t\t\t\t\tgEidos_OMP_threads_RDUNIF_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RDUNIF_2\")\t\t\t\t\t\tgEidos_OMP_threads_RDUNIF_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RDUNIF_3\")\t\t\t\t\t\tgEidos_OMP_threads_RDUNIF_3 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"REXP_1\")\t\t\t\t\t\tgEidos_OMP_threads_REXP_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"REXP_2\")\t\t\t\t\t\tgEidos_OMP_threads_REXP_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RNORM_1\")\t\t\t\t\t\tgEidos_OMP_threads_RNORM_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RNORM_2\")\t\t\t\t\t\tgEidos_OMP_threads_RNORM_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RNORM_3\")\t\t\t\t\t\tgEidos_OMP_threads_RNORM_3 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RPOIS_1\")\t\t\t\t\t\tgEidos_OMP_threads_RPOIS_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RPOIS_2\")\t\t\t\t\t\tgEidos_OMP_threads_RPOIS_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RUNIF_1\")\t\t\t\t\t\tgEidos_OMP_threads_RUNIF_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RUNIF_2\")\t\t\t\t\t\tgEidos_OMP_threads_RUNIF_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"RUNIF_3\")\t\t\t\t\t\tgEidos_OMP_threads_RUNIF_3 = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"SORT_INT\")\t\t\t\t\t\tgEidos_OMP_threads_SORT_INT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SORT_FLOAT\")\t\t\t\t\tgEidos_OMP_threads_SORT_FLOAT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SORT_STRING\")\t\t\t\t\tgEidos_OMP_threads_SORT_STRING = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"POINT_IN_BOUNDS_1D\")\t\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_IN_BOUNDS_2D\")\t\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_IN_BOUNDS_3D\")\t\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_PERIODIC_1D\")\t\t\tgEidos_OMP_threads_POINT_PERIODIC_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_PERIODIC_2D\")\t\t\tgEidos_OMP_threads_POINT_PERIODIC_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_PERIODIC_3D\")\t\t\tgEidos_OMP_threads_POINT_PERIODIC_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_REFLECTED_1D\")\t\t\tgEidos_OMP_threads_POINT_REFLECTED_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_REFLECTED_2D\")\t\t\tgEidos_OMP_threads_POINT_REFLECTED_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_REFLECTED_3D\")\t\t\tgEidos_OMP_threads_POINT_REFLECTED_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_STOPPED_1D\")\t\t\t\tgEidos_OMP_threads_POINT_STOPPED_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_STOPPED_2D\")\t\t\t\tgEidos_OMP_threads_POINT_STOPPED_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_STOPPED_3D\")\t\t\t\tgEidos_OMP_threads_POINT_STOPPED_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_UNIFORM_1D\")\t\t\t\tgEidos_OMP_threads_POINT_UNIFORM_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_UNIFORM_2D\")\t\t\t\tgEidos_OMP_threads_POINT_UNIFORM_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"POINT_UNIFORM_3D\")\t\t\t\tgEidos_OMP_threads_POINT_UNIFORM_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_1_1D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_1_2D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_1_3D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_2_1D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_1D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_2_2D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_2D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SET_SPATIAL_POS_2_3D\")\t\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_3D = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SPATIAL_MAP_VALUE\")\t\t\tgEidos_OMP_threads_SPATIAL_MAP_VALUE = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"CLIPPEDINTEGRAL_1S\")\t\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_1S = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"CLIPPEDINTEGRAL_2S\")\t\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_2S = (int)value_int64;\n\t\t\t\t\t\t//else if (key == \"CLIPPEDINTEGRAL_3S\")\t\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_3S = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"DRAWBYSTRENGTH\")\t\t\t\tgEidos_OMP_threads_DRAWBYSTRENGTH = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"INTNEIGHCOUNT\")\t\t\t\tgEidos_OMP_threads_INTNEIGHCOUNT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"LOCALPOPDENSITY\")\t\t\t\tgEidos_OMP_threads_LOCALPOPDENSITY = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"NEARESTINTNEIGH\")\t\t\t\tgEidos_OMP_threads_NEARESTINTNEIGH = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"NEARESTNEIGH\")\t\t\t\t\tgEidos_OMP_threads_NEARESTNEIGH = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"NEIGHCOUNT\")\t\t\t\t\tgEidos_OMP_threads_NEIGHCOUNT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"TOTNEIGHSTRENGTH\")\t\t\t\tgEidos_OMP_threads_TOTNEIGHSTRENGTH = (int)value_int64;\n\t\t\t\t\t\t\n\t\t\t\t\t\telse if (key == \"AGE_INCR\")\t\t\t\t\t\tgEidos_OMP_threads_AGE_INCR = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"DEFERRED_REPRO\")\t\t\t\tgEidos_OMP_threads_DEFERRED_REPRO = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"WF_REPRO\")\t\t\t\t\t\tgEidos_OMP_threads_WF_REPRO = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_ASEX_1\")\t\t\t\tgEidos_OMP_threads_FITNESS_ASEX_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_ASEX_2\")\t\t\t\tgEidos_OMP_threads_FITNESS_ASEX_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_ASEX_3\")\t\t\t\tgEidos_OMP_threads_FITNESS_ASEX_3 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_SEX_1\")\t\t\t\tgEidos_OMP_threads_FITNESS_SEX_1 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_SEX_2\")\t\t\t\tgEidos_OMP_threads_FITNESS_SEX_2 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"FITNESS_SEX_3\")\t\t\t\tgEidos_OMP_threads_FITNESS_SEX_3 = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"MIGRANT_CLEAR\")\t\t\t\tgEidos_OMP_threads_MIGRANT_CLEAR = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SIMPLIFY_SORT_PRE\")\t\t\tgEidos_OMP_threads_SIMPLIFY_SORT_PRE = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SIMPLIFY_SORT\")\t\t\t\tgEidos_OMP_threads_SIMPLIFY_SORT = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SIMPLIFY_SORT_POST\")\t\t\tgEidos_OMP_threads_SIMPLIFY_SORT_POST = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"PARENTS_CLEAR\")\t\t\t\tgEidos_OMP_threads_PARENTS_CLEAR = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"UNIQUE_MUTRUNS\")\t\t\t\tgEidos_OMP_threads_UNIQUE_MUTRUNS = (int)value_int64;\n\t\t\t\t\t\telse if (key == \"SURVIVAL\")\t\t\t\t\t\tgEidos_OMP_threads_SURVIVAL = (int)value_int64;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_parallelSetTaskThreadCounts): parallelSetTaskThreadCounts() does not recognize the task name \" << key << \".\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// This assumes that any thread count set might push the maximum per-task thread count higher, but not lower\n\t\t\t\t\t\tgEidosPerTaskThreadCountsSetName = \"UserDefined\";\n\t\t\t\t\t\tgEidosPerTaskOriginalMaxThreadCount = std::max(gEidosPerTaskOriginalMaxThreadCount, (int)value_int64);\n#endif\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_parallelSetTaskThreadCounts): parallelSetTaskThreadCounts() expects dict to contain singleton integer values.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Clip all values to gEidosMaxThreads in preparation for use\n#ifdef _OPENMP\n\t\t\t\t_Eidos_ClipOpenMPThreadCounts();\n#endif\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_parallelSetTaskThreadCounts): parallelSetTaskThreadCounts() expects dict to use string keys.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)rm([Ns variableNames = NULL])\t\t// [logical$ removeConstants = F] removed in SLiM 4\nEidosValue_SP Eidos_ExecuteFunction_rm(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *variableNames_value = p_arguments[0].get();\n\tstd::vector<std::string> symbols_to_remove;\n\t\n\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\n\t\n\tif (variableNames_value->Type() == EidosValueType::kValueNULL)\n\t\tsymbols_to_remove = symbols.ReadWriteSymbols();\n\telse\n\t{\n\t\tint variableNames_count = variableNames_value->Count();\n\t\t\n\t\tfor (int value_index = 0; value_index < variableNames_count; ++value_index)\n\t\t\tsymbols_to_remove.emplace_back(variableNames_value->StringAtIndex_NOCAST(value_index, nullptr));\n\t}\n\t\n\tfor (std::string &symbol : symbols_to_remove)\n\t\tsymbols.RemoveValueForSymbol(EidosStringRegistry::GlobalStringIDForString(symbol));\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(*)sapply(* x, string$ lambdaSource, [string$ simplify = \"vector\"])\nEidosValue_SP Eidos_ExecuteFunction_sapply(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\t// an empty x argument yields invisible NULL; this short-circuit is new but the behavior is the same as it was before,\n\t// except that we skip all the script tokenizing/parsing and so forth...\n\tif (x_count == 0)\n\t\treturn gStaticEidosValueNULLInvisible;\n\t\n\t// Determine the simplification mode requested\n\tEidosValue_String *simplify_value = (EidosValue_String *)p_arguments[2].get();\n\tconst std::string &simplify_string = simplify_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tint simplify;\n\t\n\tif (simplify_string == \"vector\")\t\tsimplify = 0;\n\telse if (simplify_string == \"matrix\")\tsimplify = 1;\n\telse if (simplify_string == \"match\")\tsimplify = 2;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sapply): unrecognized simplify option '\" << simplify_string << \"' in function sapply().\" << EidosTerminate(nullptr);\n\t\n\t// Get the lambda string and cache its script\n\tEidosValue *lambda_value = p_arguments[1].get();\n\tEidosValue_String *lambda_value_singleton = (EidosValue_String *)p_arguments[1].get();\n\tEidosScript *script = lambda_value_singleton->CachedScript();\n\t\n\t// Errors in lambdas should be reported for the lambda script, not for the calling script,\n\t// if possible.  In the GUI this does not work well, however; there, errors should be\n\t// reported as occurring in the call to sapply().  Here we save off the current\n\t// error context and set up the error context for reporting errors inside the lambda,\n\t// in case that is possible; see how exceptions are handled below.\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\n\t// We try to do tokenization and parsing once per script, by caching the script inside the EidosValue_String_singleton instance\n\tif (!script)\n\t{\n\t\tscript = new EidosScript(lambda_value->StringAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\t\n\t\ttry\n\t\t{\n\t\t\tscript->Tokenize();\n\t\t\tscript->ParseInterpreterBlockToAST(false);\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tif (gEidosTerminateThrows)\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"Eidos_ExecuteFunction_sapply()\");\n\t\t\t}\n\t\t\t\n\t\t\tdelete script;\n\t\t\t\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\tif (lambda_value_singleton)\n\t\t\tlambda_value_singleton->SetCachedScript(script);\n\t}\n\t\n\t// Execute inside try/catch so we can handle errors well\n\tstd::vector<EidosValue_SP> results;\n\t\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, script};\n\t\n\ttry\n\t{\n\t\tEidosSymbolTable &symbols = p_interpreter.SymbolTable();\t\t\t\t\t\t\t\t\t// use our own symbol table\n\t\tEidosFunctionMap &function_map = p_interpreter.FunctionMap();\t\t\t\t\t\t\t\t// use our own function map\n\t\tEidosInterpreter interpreter(*script, symbols, function_map, p_interpreter.Context(), p_interpreter.ExecutionOutputStream(), p_interpreter.ErrorOutputStream()\n#ifdef SLIMGUI\n\t\t\t, p_interpreter.check_infinite_loops_\n#endif\n\t\t\t);\n\t\tbool null_included = false;\t\t\t\t// has a NULL been seen among the return values\n\t\tbool consistent_return_length = true;\t// consistent except for any NULLs returned\n\t\tint return_length = -1;\t\t\t\t\t// what the consistent length is\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tEidosValue_SP apply_value = x_value->GetValueAtIndex(value_index, nullptr);\n\t\t\t\n\t\t\t// Set the iterator variable \"applyValue\" to the value\n\t\t\tsymbols.SetValueForSymbolNoCopy(gEidosID_applyValue, std::move(apply_value));\n\t\t\t\n\t\t\t// Get the result.  BEWARE!  This calls causes re-entry into the Eidos interpreter, which is not usually\n\t\t\t// possible since Eidos does not support multithreaded usage.  This is therefore a key failure point for\n\t\t\t// bugs that would otherwise not manifest.\n\t\t\tEidosValue_SP &&return_value_SP = interpreter.EvaluateInterpreterBlock(false, true);\t\t// do not print output, return the last statement value\n\t\t\t\n\t\t\tif (return_value_SP->Type() == EidosValueType::kValueVOID)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sapply): each iteration within sapply() must return a non-void value.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (return_value_SP->Type() == EidosValueType::kValueNULL)\n\t\t\t{\n\t\t\t\tnull_included = true;\n\t\t\t}\n\t\t\telse if (consistent_return_length)\n\t\t\t{\n\t\t\t\tint length = return_value_SP->Count();\n\t\t\t\t\n\t\t\t\tif (return_length == -1)\n\t\t\t\t\treturn_length = length;\n\t\t\t\telse if (length != return_length)\n\t\t\t\t\tconsistent_return_length = false;\n\t\t\t}\n\t\t\t\n\t\t\tresults.emplace_back(return_value_SP);\n\t\t}\n\t\t\n\t\t// We do not want a leftover applyValue symbol in the symbol table, so we remove it now\n\t\tsymbols.RemoveValueForSymbol(gEidosID_applyValue);\n\t\t\n\t\t// Assemble all the individual results together, just as c() does\n\t\tresult_SP = ConcatenateEidosValues(results, true, false);\t// allow NULL but not VOID\n\t\t\n\t\t// Finally, we restructure the results:\n\t\t//\n\t\t//\tsimplify == 0 (\"vector\") returns a plain vector, which is what we have already\n\t\t//\tsimplify == 1 (\"matrix\") returns a matrix with one column per return value\n\t\t//\tsimplify == 2 (\"match\") returns a matrix/array exactly matching the dimensions of x\n\t\tif (simplify == 1)\n\t\t{\n\t\t\t// A zero-length result is allowed and is returned verbatim\n\t\t\tif (result_SP->Count() > 0)\n\t\t\t{\n\t\t\t\tif (!consistent_return_length)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sapply): simplify = \\\"matrix\\\" was requested in function sapply(), but return values from lambdaSource were not of a consistent length.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\t// one matrix column per return value, omitting NULLs; no need to reorder values to achieve this\n\t\t\t\tint64_t dim[2] = {return_length, result_SP->Count() / return_length};\n\t\t\t\t\n\t\t\t\tresult_SP->SetDimensions(2, dim);\n\t\t\t}\n\t\t}\n\t\telse if (simplify == 2)\n\t\t{\n\t\t\tif (null_included)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sapply): simplify = \\\"match\\\" was requested in function sapply(), but return values included NULL.\" << EidosTerminate(nullptr);\n\t\t\tif (!consistent_return_length || (return_length != 1))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sapply): simplify = \\\"match\\\" was requested in function sapply(), but return values from lambdaSource were not all singletons.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// match the dimensionality of x\n\t\t\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\t// If exceptions throw, then we want to set up the error information to highlight the\n\t\t// sapply() that failed, since we can't highlight the actual error.  (If exceptions\n\t\t// don't throw, this catch block will never be hit; exit() will already have been called\n\t\t// and the error will have been reported from the context of the lambda script string.)\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"Eidos_ExecuteFunction_sapply()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!lambda_value_singleton)\n\t\t\tdelete script;\n\t\t\n\t\tthrow;\n\t}\n\t\n\t// Restore the normal error context in the event that no exception occurring within the lambda\n\tgEidosErrorContext = error_context_save;\n\t\n\tif (!lambda_value_singleton)\n\t\tdelete script;\n\t\n\treturn result_SP;\n}\n\n//\t(void)setSeed(integer$ seed)\nEidosValue_SP Eidos_ExecuteFunction_setSeed(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *seed_value = p_arguments[0].get();\n\t\n\tEidos_SetRNGSeed(seed_value->IntAtIndex_NOCAST(0, nullptr));\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)stop([Ns$ message = NULL])\nEidosValue_SP Eidos_ExecuteFunction_stop(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *message_value = p_arguments[0].get();\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tif (message_value->Type() != EidosValueType::kValueNULL)\n\t{\n\t\tstd::string &&stop_string = p_arguments[0]->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tp_interpreter.ErrorOutputStream() << stop_string << std::endl;\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_stop): stop() called with error message:\\n\\n\" << stop_string << EidosTerminate(nullptr);\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_stop): stop() called.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// CODE COVERAGE: This is dead code\n\treturn result_SP;\n}\n\n//\t(logical$)suppressWarnings(logical$ suppress)\nEidosValue_SP Eidos_ExecuteFunction_suppressWarnings(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *suppress_value = p_arguments[0].get();\n\teidos_logical_t new_suppress = suppress_value->LogicalAtIndex_NOCAST(0, nullptr);\n\teidos_logical_t old_suppress = gEidosSuppressWarnings;\n\t\n\tgEidosSuppressWarnings = new_suppress;\n\t\n\treturn (old_suppress ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n}\n\n//\t(*)sysinfo(string$ key)\nEidosValue_SP Eidos_ExecuteFunction_sysinfo(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *key_value = p_arguments[0].get();\n\tstd::string key = key_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (key == \"os\")\n\t{\n#if defined(__APPLE__)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"macOS\"));\n#elif defined(_WIN32) || (_WIN64)\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"Windows\"));\n#else\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"Unix\"));\t\t// assumed if we are not macOS or Windows\n#endif\n\t}\n\telse if (key == \"sysname\")\n\t{\n\t\tstruct utsname name;\n\t\tint ret = uname(&name);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name.sysname));\n\t}\n\telse if (key == \"release\")\n\t{\n\t\tstruct utsname name;\n\t\tint ret = uname(&name);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name.release));\n\t}\n\telse if (key == \"version\")\n\t{\n\t\tstruct utsname name;\n\t\tint ret = uname(&name);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name.version));\n\t}\n\telse if (key == \"nodename\")\n\t{\n\t\tstruct utsname name;\n\t\tint ret = uname(&name);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name.nodename));\n\t}\n\telse if (key == \"machine\")\n\t{\n\t\tstruct utsname name;\n\t\tint ret = uname(&name);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name.machine));\n\t}\n#if 0\n\t// \"login\" doesn't work on Windows, and \"user\" doesn't work on both Windows and Ubuntu 18.04; disabling both for now, nobody has asked for them anyway\n\telse if (key == \"login\")\n\t{\n\t\tchar *name = getlogin();\n\t\t\n\t\tif (name)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(name));\n\t}\n\telse if (key == \"user\")\n\t{\n\t\tuid_t uid = getuid();\n\t\tstruct passwd *pwd = getpwuid(uid);\n\t\t\n\t\tif (pwd && pwd->pw_name)\n\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(pwd->pw_name));\n\t}\n#endif\n\t\n\t// if we fall through the here, the value is unknown\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"unknown\"));\n}\n\n//\t(string)system(string$ command, [string args = \"\"], [string input = \"\"], [logical$ stderr = F], [logical$ wait = T])\nEidosValue_SP Eidos_ExecuteFunction_system(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tif (!Eidos_TemporaryDirectoryExists())\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): in function system(), the temporary directory appears not to exist or is not writeable.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_String *command_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_String *args_value = (EidosValue_String *)p_arguments[1].get();\n\tint arg_count = args_value->Count();\n\tbool has_args = ((arg_count > 1) || ((arg_count == 1) && (args_value->StringRefAtIndex_NOCAST(0, nullptr).length() > 0)));\n\tEidosValue_String *input_value = (EidosValue_String *)p_arguments[2].get();\n\tint input_count = input_value->Count();\n\tbool has_input = ((input_count > 1) || ((input_count == 1) && (input_value->StringRefAtIndex_NOCAST(0, nullptr).length() > 0)));\n\tbool redirect_stderr = p_arguments[3]->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool wait = p_arguments[4]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\t// Construct the command string\n\tstd::string command_string = command_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (command_string.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): a non-empty command string must be supplied to system().\" << EidosTerminate(nullptr);\n\t\n\tif (has_args)\n\t{\n\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t{\n\t\t\tcommand_string.append(\" \");\n\t\t\tcommand_string.append(args_value->StringRefAtIndex_NOCAST(value_index, nullptr));\n\t\t}\n\t}\n\t\n\t// Make the input temporary file and redirect, if requested\n\tif (has_input)\n\t{\n\t\t// thanks to http://stackoverflow.com/questions/499636/how-to-create-a-stdofstream-to-a-temp-file for the temp file creation code\n\t\t\n\t\tstd::string name_string = Eidos_TemporaryDirectory() + \"eidos_system_XXXXXX\";\n\t\tchar *name = strdup(name_string.c_str());\n\t\tint fd = mkstemp(name);\n\t\t\n\t\tif (fd == -1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): (internal error) mkstemp() failed!\" << EidosTerminate(nullptr);\n\t\t\n\t\tstd::ofstream file_stream(name, std::ios_base::out);\n\t\tclose(fd);\t// opened by mkstemp()\n\t\t\n\t\tif (!file_stream.is_open())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): (internal error) ofstream() failed!\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (input_count == 1)\n\t\t{\n\t\t\t// no final newline in this case, so the user can precisely specify the file contents if desired\n\t\t\tfile_stream << input_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst std::string *string_vec = input_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < input_count; ++value_index)\n\t\t\t{\n\t\t\t\tfile_stream << string_vec[value_index];\n\t\t\t\t\n\t\t\t\t// Add newlines after all lines, including the last\n\t\t\t\tfile_stream << std::endl;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (file_stream.bad())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): (internal error) stream errors writing temporary file for input\" << EidosTerminate(nullptr);\n\t\t\n\t\tcommand_string.append(\" < \");\n\t\tcommand_string.append(name);\n\t\t\n\t\tfree(name);\n\t}\n\t\n\t// Redirect standard error, if requested\n\tif (redirect_stderr)\n\t{\n\t\tcommand_string.append(\" 2>&1\");\n\t}\n\t\n\t// Run in the background, if requested\n\tif (!wait)\n\t{\n\t\tcommand_string.append(\" &\");\n\t}\n\t\n\t// Determine whether we are running in the background, as indicated by a command line ending in \" &\"\n\tif ((command_string.length() > 2) && (command_string.substr(command_string.length() - 2, std::string::npos) == \" &\"))\n\t{\n\t\twait = false;\n\t}\n\t\n\tif (wait)\n\t{\n\t\t// Execute the command string; thanks to http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix\n\t\t//std::cout << \"Executing command string: \" << command_string << std::endl;\n\t\t//std::cout << \"Command string length: \" << command_string.length() << \" bytes\" << std::endl;\n\t\t\n\t\tchar buffer[128];\n\t\tstd::string result = \"\";\n\t\tstd::shared_ptr<FILE> command_pipe(popen(command_string.c_str(), \"r\"), pclose);\n\t\tif (!command_pipe)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): (internal error) popen() failed!\" << EidosTerminate(nullptr);\n\t\twhile (!feof(command_pipe.get())) {\n\t\t\tif (fgets(buffer, 128, command_pipe.get()) != NULL)\n\t\t\t\tresult += buffer;\n\t\t}\n\t\t\n\t\t// Parse the result into lines and make a result vector\n\t\tstd::istringstream result_stream(result);\n\t\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tstd::string line;\n\t\t\n\t\twhile (getline(result_stream, line))\n\t\t\tstring_result->PushString(line);\n\t\t\n\t\treturn result_SP;\n\t}\n\telse\n\t{\n\t\t// Execute the command string without collecting output, hopefully in the background with an immediate return from system()\n\t\tint ret = system(command_string.c_str());\n\t\t\n\t\tif (ret != 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_system): (internal error) system() failed with return code \" << ret << \".\" << EidosTerminate(nullptr);\n\t\t\n\t\treturn gStaticEidosValue_String_ZeroVec;\n\t}\n}\n\n//\t(string$)time(void)\nEidosValue_SP Eidos_ExecuteFunction_time(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\ttime_t rawtime;\n\tstruct tm timeinfo;\n\tchar buffer[20];\t\t// should never be more than 8, in fact, plus a null\n\t\n\ttime(&rawtime);\n\tlocaltime_r(&rawtime, &timeinfo);\n\tstrftime(buffer, 20, \"%H:%M:%S\", &timeinfo);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(std::string(buffer)));\n\t\n\treturn result_SP;\n}\n\n//\t(float$)usage([ls$ type = \"rss\"])\nEidosValue_SP Eidos_ExecuteFunction_usage(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue *type_value = p_arguments[0].get();\n\tsize_t usage = 0;\n\t\n\tif (type_value->Type() == EidosValueType::kValueLogical)\n\t{\n\t\t// old-style API, through SLiM 4.0.1 (but still supported): logical value, F == current RSS, T == peak RSS\n\t\tbool peak = type_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tusage = (peak ? Eidos_GetPeakRSS() : Eidos_GetCurrentRSS());\n\t}\n\telse\n\t{\n\t\t// new-style API, after SLiM 4.0.1: string value, \"rss\" == current RSS, \"rss_peak\" = peak RSS, \"vm\" = current VM\n\t\tstd::string type = type_value->StringAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (type == \"rss\")\n\t\t\tusage = Eidos_GetCurrentRSS();\n\t\telse if (type == \"rss_peak\")\n\t\t\tusage = Eidos_GetPeakRSS();\n\t\telse if (type == \"vm\")\n\t\t\tusage = Eidos_GetVMUsage();\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_usage): usage() did not recognize the requested type, '\" << type << \"'; type should be 'rss', 'rss_peak', or 'vm'.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tdouble usage_MB = usage / (1024.0 * 1024.0);\n\tEidosValue_SP result_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(usage_MB));\n\t\n\treturn result_SP;\n}\n\n//\t(void)version([logical$ print = T])\nEidosValue_SP Eidos_ExecuteFunction_version(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tbool print = p_arguments[0]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (print)\n\t{\n\t\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\t\tEidos_EraseProgress();\n\t\t\n\t\tstd::ostream &output_stream = p_interpreter.ExecutionOutputStream();\n\t\t\n\t\toutput_stream << \"Eidos version \" << EIDOS_VERSION_STRING << std::endl;\n\t\t\n\t\tif (gEidosContextVersionString.length())\n\t\t\toutput_stream << gEidosContextVersionString << std::endl;\n\t}\n\t\n\t// Return the versions as floats\n\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->reserve(2);\n\tresult_SP = EidosValue_SP(result);\n\t\n\tresult->push_float_no_check(EIDOS_VERSION_FLOAT);\n\t\n\tif (gEidosContextVersion != 0.0)\n\t\tresult->push_float_no_check(gEidosContextVersion);\n\t\n\tif (print)\n\t\tresult->SetInvisible(true);\n\t\n\treturn result_SP;\n}\n\n// (void)_startBenchmark(string$ type)\nEidosValue_SP SLiM_ExecuteFunction__startBenchmark(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *type_value = p_arguments[0].get();\n\t\n\tif (gEidosBenchmarkType != EidosBenchmarkType::kNone)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction__startBenchmark): benchmarking has already been started.\" << EidosTerminate();\n\t\n\tstd::string type = type_value->StringAtIndex_NOCAST(0, nullptr);\n\t\n\tif (type == \"SAMPLE_INDEX\")\t\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_SAMPLE_INDEX;\n\telse if (type == \"TABULATE_MAXBIN\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_TABULATE_MAXBIN;\n\telse if (type == \"AGE_INCR\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_AGE_INCR;\n\telse if (type == \"DEFERRED_REPRO\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_DEFERRED_REPRO;\n\telse if (type == \"WF_REPRO\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_WF_REPRO;\n\telse if (type == \"FITNESS_ASEX_1\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_ASEX_1;\n\telse if (type == \"FITNESS_ASEX_2\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_ASEX_2;\n\telse if (type == \"FITNESS_ASEX_3\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_ASEX_3;\n\telse if (type == \"FITNESS_SEX_1\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_SEX_1;\n\telse if (type == \"FITNESS_SEX_2\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_SEX_2;\n\telse if (type == \"FITNESS_SEX_3\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_FITNESS_SEX_3;\n\telse if (type == \"MIGRANT_CLEAR\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_MIGRANT_CLEAR;\n\telse if (type == \"SIMPLIFY_SORT_PRE\")\tgEidosBenchmarkType = EidosBenchmarkType::k_SIMPLIFY_SORT_PRE;\n\telse if (type == \"SIMPLIFY_SORT\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_SIMPLIFY_SORT;\n\telse if (type == \"SIMPLIFY_SORT_POST\")\tgEidosBenchmarkType = EidosBenchmarkType::k_SIMPLIFY_SORT_POST;\n\telse if (type == \"PARENTS_CLEAR\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_PARENTS_CLEAR;\n\telse if (type == \"UNIQUE_MUTRUNS\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_UNIQUE_MUTRUNS;\n\telse if (type == \"SURVIVAL\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_SURVIVAL;\n\telse if (type == \"MUT_TALLY\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_MUT_TALLY;\n\telse if (type == \"MUTRUN_FREE\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_MUTRUN_FREE;\n\telse if (type == \"MUT_FREE\")\t\t\tgEidosBenchmarkType = EidosBenchmarkType::k_MUT_FREE;\n\telse if (type == \"SIMPLIFY_CORE\")\t\tgEidosBenchmarkType = EidosBenchmarkType::k_SIMPLIFY_CORE;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction__startBenchmark): unrecognized benchmark type \" << type << \".\" << EidosTerminate();\n\t\n\tgEidosBenchmarkAccumulator = 0;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n// (float$)_stopBenchmark(void)\nEidosValue_SP SLiM_ExecuteFunction__stopBenchmark(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tif (gEidosBenchmarkType == EidosBenchmarkType::kNone)\n\t\tEIDOS_TERMINATION << \"ERROR (SLiM_ExecuteFunction__stopBenchmark): benchmarking has not been started.\" << EidosTerminate();\n\t\n\tdouble benchmark_time = Eidos_ElapsedProfileTime(gEidosBenchmarkAccumulator);\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(benchmark_time));\n\t\n\t// reset so a new benchmark can be started\n\tgEidosBenchmarkType = EidosBenchmarkType::kNone;\n\tgEidosBenchmarkAccumulator = 0;\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_stats.cpp",
    "content": "//\n//  eidos_functions_stats.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_sorting.h\"\n\n#include <utility>\n#include <limits>\n#include <string>\n#include <algorithm>\n#include <vector>\n\n\n// ************************************************************************************\n//\n//\tstatistics functions\n//\n#pragma mark -\n#pragma mark Statistics functions\n#pragma mark -\n\nstatic double _Eidos_CalcCorrelation(size_t count, EidosValue *x_value, EidosValue *y_value, size_t x_offset, size_t y_offset)\n{\n\t// A thin wrapper for Eidos_Correlation() that can be used with both integer and float EidosValues,\n\t// and takes an offset for x and y that allow a particular column of a matrix to be selected\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tif (y_value->Type() == EidosValueType::kValueInt)\n\t\t\treturn Eidos_Correlation<const int64_t, const int64_t>(x_value->IntData() + x_offset, y_value->IntData() + y_offset, count);\n\t\telse\t\t\t\t// EidosValueType::kValueFloat\n\t\t\treturn Eidos_Correlation<const int64_t, const double>(x_value->IntData() + x_offset, y_value->FloatData() + y_offset, count);\n\t}\n\telse\t\t\t\t\t// EidosValueType::kValueFloat\n\t{\n\t\tif (y_value->Type() == EidosValueType::kValueInt)\n\t\t\treturn Eidos_Correlation<const double, const int64_t>(x_value->FloatData() + x_offset, y_value->IntData() + y_offset, count);\n\t\telse\t\t\t\t// EidosValueType::kValueFloat\n\t\t\treturn Eidos_Correlation<const double, const double>(x_value->FloatData() + x_offset, y_value->FloatData() + y_offset, count);\n\t}\n}\n\n//\t(float)cor(numeric x, [Nif y = NULL])\nEidosValue_SP Eidos_ExecuteFunction_cor(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *y_value = p_arguments[1].get();\n\tbool x_is_matrix = x_value->IsMatrixOrArray();\n\tbool y_is_matrix = y_value->IsMatrixOrArray();\n\t\n\tif (x_is_matrix || y_is_matrix)\n\t{\n\t\t// correlation involving at least one matrix (treated by column); y=NULL means do cor(x, x) for matrix x\n\t\tif (y_value->Type() == EidosValueType::kValueNULL)\n\t\t{\n\t\t\ty_value = x_value;\n\t\t\ty_is_matrix = x_is_matrix;\n\t\t}\n\t\t\n\t\t// arrays are not allowed, just matrices and vectors\n\t\tif ((x_value->DimensionCount() > 2) || (y_value->DimensionCount() > 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cor): function cor() does not allow x or y to be an array.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// get the lengths of the vectors we're calculating correlation on: vector length or matrix row count\n\t\tsize_t x_vec_length = x_is_matrix ? x_value->Dimensions()[0] : x_value->Count();\n\t\tsize_t y_vec_length = y_is_matrix ? y_value->Dimensions()[0] : y_value->Count();\n\t\t\n\t\tif (x_vec_length != y_vec_length)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cor): incompatible dimensions in cor().\" << EidosTerminate(nullptr);\n\t\t\n\t\tsize_t vec_length = x_vec_length;\n\t\t\n\t\tif (vec_length == 0)\n\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\t// so we're making a correlation matrix; let's determine its size first\n\t\tint64_t nrows = x_is_matrix ? x_value->Dimensions()[1] : 1;\n\t\tint64_t ncols = y_is_matrix ? y_value->Dimensions()[1] : 1;\n\t\t\n\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(nrows * ncols);\n\t\tdouble *result_data = result->FloatData_Mutable();\n\t\tresult_SP = EidosValue_SP(result);\n\t\t\n\t\tif (x_value == y_value)\n\t\t{\n\t\t\t// if x_value and y_value are the same, we're making a correlation matrix for x_value with itself\n\t\t\t// the result will be a symmetric matrix, so we can save time by calculating only one triangle\n\t\t\tfor (int64_t row = 0; row < nrows; ++row)\n\t\t\t{\n\t\t\t\tfor (int64_t col = 0; col < ncols; ++col)\n\t\t\t\t{\n\t\t\t\t\tif (row == col)\n\t\t\t\t\t{\n\t\t\t\t\t\tresult_data[col * nrows + row] = 1.0;\n\t\t\t\t\t}\n\t\t\t\t\telse if (row < col)\n\t\t\t\t\t{\n\t\t\t\t\t\tsize_t x_offset = row * vec_length;\n\t\t\t\t\t\tsize_t y_offset = col * vec_length;\n\t\t\t\t\t\tdouble cor = _Eidos_CalcCorrelation(vec_length, x_value, y_value, x_offset, y_offset);\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_data[col * nrows + row] = cor;\n\t\t\t\t\t\tresult_data[row * nrows + col] = cor;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// general case: loop over the elements of the result and calculate each one\n\t\t\tfor (int64_t row = 0; row < nrows; ++row)\n\t\t\t{\n\t\t\t\tfor (int64_t col = 0; col < ncols; ++col)\n\t\t\t\t{\n\t\t\t\t\tsize_t x_offset = row * vec_length;\n\t\t\t\t\tsize_t y_offset = col * vec_length;\n\t\t\t\t\tdouble cor = _Eidos_CalcCorrelation(vec_length, x_value, y_value, x_offset, y_offset);\n\t\t\t\t\t\n\t\t\t\t\tresult_data[col * nrows + row] = cor;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tconst int64_t dim_buf[2] = {nrows, ncols};\n\t\tresult->SetDimensions(2, dim_buf);\n\t}\n\telse\n\t{\n\t\t// correlation of two vectors x and y; in this case, y is not allowed to be NULL\n\t\tif (y_value->Type() == EidosValueType::kValueNULL)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cor): function cor() requires both x and y to be supplied, or a matrix x.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint count = x_value->Count();\n\t\t\n\t\tif (count != y_value->Count())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cor): function cor() requires that x and y be the same size.\" << EidosTerminate(nullptr);\n\t\tif (count <= 1)\n\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\t// calculate correlation between x and y\n\t\tdouble cor = _Eidos_CalcCorrelation(count, x_value, y_value, 0, 0);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(cor));\n\t}\n\t\n\treturn result_SP;\n}\n\nstatic double _Eidos_CalcCovariance(size_t count, EidosValue *x_value, EidosValue *y_value, size_t x_offset, size_t y_offset)\n{\n\t// A thin wrapper for Eidos_Covariance() that can be used with both integer and float EidosValues,\n\t// and takes an offset for x and y that allow a particular column of a matrix to be selected\n\tif (x_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tif (y_value->Type() == EidosValueType::kValueInt)\n\t\t\treturn Eidos_Covariance<const int64_t, const int64_t>(x_value->IntData() + x_offset, y_value->IntData() + y_offset, count);\n\t\telse\t\t\t\t// EidosValueType::kValueFloat\n\t\t\treturn Eidos_Covariance<const int64_t, const double>(x_value->IntData() + x_offset, y_value->FloatData() + y_offset, count);\n\t}\n\telse\t\t\t\t\t// EidosValueType::kValueFloat\n\t{\n\t\tif (y_value->Type() == EidosValueType::kValueInt)\n\t\t\treturn Eidos_Covariance<const double, const int64_t>(x_value->FloatData() + x_offset, y_value->IntData() + y_offset, count);\n\t\telse\t\t\t\t// EidosValueType::kValueFloat\n\t\t\treturn Eidos_Covariance<const double, const double>(x_value->FloatData() + x_offset, y_value->FloatData() + y_offset, count);\n\t}\n}\n\n//\t(float)cov(numeric x, [Nif y = NULL])\nEidosValue_SP Eidos_ExecuteFunction_cov(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *y_value = p_arguments[1].get();\n\tbool x_is_matrix = x_value->IsMatrixOrArray();\n\tbool y_is_matrix = y_value->IsMatrixOrArray();\n\t\n\tif (x_is_matrix || y_is_matrix)\n\t{\n\t\t// covariance involving at least one matrix (treated by column); y=NULL means do cov(x, x) for matrix x\n\t\tif (y_value->Type() == EidosValueType::kValueNULL)\n\t\t{\n\t\t\ty_value = x_value;\n\t\t\ty_is_matrix = x_is_matrix;\n\t\t}\n\t\t\n\t\t// arrays are not allowed, just matrices and vectors\n\t\tif ((x_value->DimensionCount() > 2) || (y_value->DimensionCount() > 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cov): function cov() does not allow x or y to be an array.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// get the lengths of the vectors we're calculating covariance on: vector length or matrix row count\n\t\tsize_t x_vec_length = x_is_matrix ? x_value->Dimensions()[0] : x_value->Count();\n\t\tsize_t y_vec_length = y_is_matrix ? y_value->Dimensions()[0] : y_value->Count();\n\t\t\n\t\tif (x_vec_length != y_vec_length)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cov): incompatible dimensions in cov().\" << EidosTerminate(nullptr);\n\t\t\n\t\tsize_t vec_length = x_vec_length;\n\t\t\n\t\tif (vec_length == 0)\n\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\t// so we're making a covariance matrix; let's determine its size first\n\t\tint64_t nrows = x_is_matrix ? x_value->Dimensions()[1] : 1;\n\t\tint64_t ncols = y_is_matrix ? y_value->Dimensions()[1] : 1;\n\t\t\n\t\tEidosValue_Float *result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(nrows * ncols);\n\t\tdouble *result_data = result->FloatData_Mutable();\n\t\tresult_SP = EidosValue_SP(result);\n\t\t\n\t\tif (x_value == y_value)\n\t\t{\n\t\t\t// if x_value and y_value are the same, we're making a covariance matrix for x_value with itself\n\t\t\t// the result will be a symmetric matrix, so we can save time by calculating only one triangle\n\t\t\tfor (int64_t row = 0; row < nrows; ++row)\n\t\t\t{\n\t\t\t\tfor (int64_t col = 0; col < ncols; ++col)\n\t\t\t\t{\n\t\t\t\t\tif (row <= col)\n\t\t\t\t\t{\n\t\t\t\t\t\tsize_t x_offset = row * vec_length;\n\t\t\t\t\t\tsize_t y_offset = col * vec_length;\n\t\t\t\t\t\tdouble cov = _Eidos_CalcCovariance(vec_length, x_value, y_value, x_offset, y_offset);\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_data[col * nrows + row] = cov;\n\t\t\t\t\t\tresult_data[row * nrows + col] = cov;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// general case: loop over the elements of the result and calculate each one\n\t\t\tfor (int64_t row = 0; row < nrows; ++row)\n\t\t\t{\n\t\t\t\tfor (int64_t col = 0; col < ncols; ++col)\n\t\t\t\t{\n\t\t\t\t\tsize_t x_offset = row * vec_length;\n\t\t\t\t\tsize_t y_offset = col * vec_length;\n\t\t\t\t\tdouble cov = _Eidos_CalcCovariance(vec_length, x_value, y_value, x_offset, y_offset);\n\t\t\t\t\t\n\t\t\t\t\tresult_data[col * nrows + row] = cov;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tconst int64_t dim_buf[2] = {nrows, ncols};\n\t\tresult->SetDimensions(2, dim_buf);\n\t}\n\telse\n\t{\n\t\t// covariance of two vectors x and y; in this case, y is not allowed to be NULL\n\t\tif (y_value->Type() == EidosValueType::kValueNULL)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cov): function cov() requires both x and y to be supplied, or a matrix x.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint count = x_value->Count();\n\t\t\n\t\tif (count != y_value->Count())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_cov): function cov() requires that x and y be the same size.\" << EidosTerminate(nullptr);\n\t\tif (count <= 1)\n\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\t// calculate covariance between x and y\n\t\tdouble cov = _Eidos_CalcCovariance(count, x_value, y_value, 0, 0);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(cov));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float)filter(numeric x, float filter, [lif$ outside = F])\nEidosValue_SP Eidos_ExecuteFunction_filter(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// this is patterned after the R function filter(), but only for method=\"convolution\", sides=2, circular=F\n\t// so for now we support only a centered filter convolved over x with a non-circular buffer\n\t// values where the filter extends beyond the range of x are handled according to the `outside` parameter\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *filter_value = p_arguments[1].get();\n\tEidosValue *outside_value = p_arguments[2].get();\n\tint x_count = x_value->Count();\n\tint filter_count = filter_value->Count();\n\t\n\t// the maximum filter length is arbitrary, but it seems like a good idea to flag weird bugs?\n\tif ((filter_count <= 0) | (filter_count > 999) | (filter_count % 2 == 0))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_filter): function filter() requires filter to have a length that is odd and within the interval [1, 999].\" << EidosTerminate(nullptr);\n\t\n\t// decode the value of outside, which must be T (use NAN), F (exclude), or a numeric value (use constant)\n\ttypedef enum _OutsideValue {\n\t\tkUseNAN = 0,\n\t\tkExcludeOuter,\n\t\tkUseConstant\n\t} OutsideValue;\n\t\n\tOutsideValue outside;\n\tdouble outsideConstant = 0.0;\t// only used for OutsideValue::kUseConstant\n\t\n\tif (outside_value->Type() == EidosValueType::kValueLogical)\n\t{\n\t\tif (outside_value->LogicalAtIndex_NOCAST(0, nullptr) == false)\n\t\t{\n\t\t\t// outside=F is the default: use NAN for all positions where the filter extends beyond x\n\t\t\toutside = OutsideValue::kUseNAN;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// outside=T: exclude positions where the filter extends beyond x, and rescale to compensate\n\t\t\toutside = OutsideValue::kExcludeOuter;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// outside is integer or float: it gives the mean/expected value to be used for all values beyond x\n\t\toutside = OutsideValue::kUseConstant;\n\t\toutsideConstant = outside_value->NumericAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\t// half rounded down; e.g., for a filter of length 5, this is 2; this is the number of\n\t// positions at the start/end of the result where the filter extends past the end of x\n\tint half_filter = filter_count / 2;\n\t\n\t// the result is the same length as x, in all cases\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tEidosValue_SP result_SP(float_result);\n\tdouble *result_data = float_result->FloatData_Mutable();\n\t\n\t// test for a simple moving average, with equal weights summing to 1.0, to special-case it\n\tconst double *filter_data = filter_value->FloatData();\n\tbool is_simple_moving_average = true;\n\t\n\tfor (int index = 0; index < filter_count; ++index)\n\t{\n\t\tif (std::abs(filter_data[index] - (1.0 / filter_count)) > 1e-15)\t// 1e-15 is a roundoff epsilon\n\t\t{\n\t\t\tis_simple_moving_average = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t// if outside is kExcludeOuter, we need to know the sum of the filter's absolute values for scaling\n\tdouble sum_abs_filter = 0.0;\n\t\n\tif (outside == OutsideValue::kExcludeOuter)\n\t{\n\t\tfor (int pos = 0; pos < filter_count; ++pos)\n\t\t{\n\t\t\tdouble filter_element = filter_data[pos];\n\t\t\t\n\t\t\tif ((filter_element == 0) && ((pos == 0) || (pos == filter_count - 1)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_filter): when outside=T, function filter() requires the first and last values of filter to be non-zero to avoid numerical issues.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tsum_abs_filter += std::abs(filter_element);\n\t\t}\n\t}\n\t\n\t// now that we've checked all error cases, short-circuit for zero-length x\n\tif (x_count == 0)\n\t\treturn result_SP;\n\t\n\t// now we start generating the result vector; we will use the variable result_pos to track the result\n\t// position we are calculating throughout, and will handle it three sections, left/middle/right\n\tint result_pos = 0;\n\t\n\t// handle the half-filter length at the start, where positions on the left lie outside x\n\t// this section also handles cases where positions on the right are also outside, because x_count is small\n\tswitch (outside)\n\t{\n\t\tcase OutsideValue::kUseNAN:\t\t\t// use NAN for all positions where the filter extends beyond x\n\t\t{\n\t\t\tfor ( ; (result_pos < half_filter) && (result_pos < x_count); ++result_pos)\n\t\t\t\tresult_data[result_pos] = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase OutsideValue::kExcludeOuter:\t// exclude positions where the filter extends beyond x\n\t\t{\n\t\t\tfor ( ; (result_pos < half_filter) && (result_pos < x_count); ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filtered_total = 0.0;\n\t\t\t\tdouble sum_abs_filter_inside = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t{\n\t\t\t\t\tdouble filter_datum = filter_data[filter_pos];\n\t\t\t\t\tint x_pos = result_pos + (filter_pos - half_filter);\n\t\t\t\t\t\n\t\t\t\t\tif ((x_pos >= 0) && (x_pos < x_count))\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble x_datum = x_value->NumericAtIndex_NOCAST(x_pos, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfiltered_total += filter_datum * x_datum;\n\t\t\t\t\t\tsum_abs_filter_inside += std::abs(filter_datum);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filtered_total * (sum_abs_filter / sum_abs_filter_inside);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase OutsideValue::kUseConstant:\t// use the given numeric value for values beyond x\n\t\t{\n\t\t\tfor ( ; (result_pos < half_filter) && (result_pos < x_count); ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filtered_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t{\n\t\t\t\t\tdouble filter_datum = filter_data[filter_pos];\n\t\t\t\t\tint x_pos = result_pos + (filter_pos - half_filter);\n\t\t\t\t\tdouble x_datum;\n\t\t\t\t\t\n\t\t\t\t\tif ((x_pos >= 0) && (x_pos < x_count))\n\t\t\t\t\t\tx_datum = x_value->NumericAtIndex_NOCAST(x_pos, nullptr);\n\t\t\t\t\telse\n\t\t\t\t\t\tx_datum = outsideConstant;\n\t\t\t\t\t\n\t\t\t\t\tfiltered_total += filter_datum * x_datum;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filtered_total;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\t// now we branch depending on whether x is integer or float, and special-case simple moving averages\n\t// for this middle loop we don't need to worry about the x position being outside bounds\n\tif (x_value->Type() == EidosValueType::kValueFloat)\n\t{\n\t\tconst double *x_data = x_value->FloatData();\n\t\t\n\t\tif (is_simple_moving_average)\n\t\t{\n\t\t\t// the first position after the half-filter length sets up a moving total\n\t\t\tdouble moving_total = 0.0;\n\t\t\t\n\t\t\tif (result_pos < x_count - half_filter)\n\t\t\t{\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; ++filter_pos)\n\t\t\t\t\tmoving_total += x_data[filter_pos];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = moving_total / filter_count;\n\t\t\t\t++result_pos;\n\t\t\t}\n\t\t\t\n\t\t\t// the remaining positions modify the moving total\n\t\t\tfor ( ; result_pos < x_count - half_filter; ++result_pos)\n\t\t\t{\n\t\t\t\tmoving_total -= x_data[result_pos - half_filter - 1];\n\t\t\t\tmoving_total += x_data[result_pos + half_filter];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = moving_total / filter_count;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we compute the filter over the appropriate range of x at each position\n\t\t\tfor ( ; result_pos < x_count - half_filter; ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filter_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t\tfilter_total += filter_data[filter_pos] * x_data[filter_pos + result_pos - half_filter];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filter_total;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tconst int64_t *x_data = x_value->IntData();\n\t\t\n\t\tif (is_simple_moving_average)\n\t\t{\n\t\t\t// the first position after the half-filter length sets up a moving total\n\t\t\tdouble moving_total = 0.0;\n\t\t\t\n\t\t\tif (result_pos < x_count - half_filter)\n\t\t\t{\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; ++filter_pos)\n\t\t\t\t\tmoving_total += x_data[filter_pos];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = moving_total / filter_count;\n\t\t\t\t++result_pos;\n\t\t\t}\n\t\t\t\n\t\t\t// the remaining non-NAN positions modify the moving total\n\t\t\tfor ( ; result_pos < x_count - half_filter; ++result_pos)\n\t\t\t{\n\t\t\t\tmoving_total -= x_data[result_pos - half_filter - 1];\n\t\t\t\tmoving_total += x_data[result_pos + half_filter];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = moving_total / filter_count;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we compute the filter over the appropriate range of x at each position\n\t\t\tfor ( ; result_pos < x_count - half_filter; ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filter_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t\tfilter_total += filter_data[filter_pos] * x_data[filter_pos + result_pos - half_filter];\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filter_total;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// the remaining positions at the end have positions outside x on the right, but never on the left\n\tswitch (outside)\n\t{\n\t\tcase OutsideValue::kUseNAN:\t\t\t// use NAN for all positions where the filter extends beyond x\n\t\t{\n\t\t\tfor ( ; result_pos < x_count; ++result_pos)\n\t\t\t\tresult_data[result_pos] = std::numeric_limits<double>::quiet_NaN();\n\t\t\tbreak;\n\t\t}\n\t\tcase OutsideValue::kExcludeOuter:\t// exclude positions where the filter extends beyond x\n\t\t{\n\t\t\tfor ( ; result_pos < x_count; ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filtered_total = 0.0;\n\t\t\t\tdouble sum_abs_filter_inside = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t{\n\t\t\t\t\tdouble filter_datum = filter_data[filter_pos];\n\t\t\t\t\tint x_pos = result_pos + (filter_pos - half_filter);\n\t\t\t\t\t\n\t\t\t\t\tif (x_pos < x_count)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble x_datum = x_value->NumericAtIndex_NOCAST(x_pos, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfiltered_total += filter_datum * x_datum;\n\t\t\t\t\t\tsum_abs_filter_inside += std::abs(filter_datum);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filtered_total * (sum_abs_filter / sum_abs_filter_inside);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase OutsideValue::kUseConstant:\t// use the given numeric value for values beyond x\n\t\t{\n\t\t\tfor ( ; result_pos < x_count; ++result_pos)\n\t\t\t{\n\t\t\t\tdouble filtered_total = 0.0;\n\t\t\t\t\n\t\t\t\tfor (int filter_pos = 0; filter_pos < filter_count; filter_pos++)\n\t\t\t\t{\n\t\t\t\t\tdouble filter_datum = filter_data[filter_pos];\n\t\t\t\t\tint x_pos = result_pos + (filter_pos - half_filter);\n\t\t\t\t\tdouble x_datum;\n\t\t\t\t\t\n\t\t\t\t\tif (x_pos < x_count)\n\t\t\t\t\t\tx_datum = x_value->NumericAtIndex_NOCAST(x_pos, nullptr);\n\t\t\t\t\telse\n\t\t\t\t\t\tx_datum = outsideConstant;\n\t\t\t\t\t\n\t\t\t\t\tfiltered_total += filter_datum * x_datum;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_data[result_pos] = filtered_total;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(+$)max(+ x, ...)\nEidosValue_SP Eidos_ExecuteFunction_max(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValueType x_type = p_arguments[0].get()->Type();\n\t\n\t// check the types of ellipsis arguments and find the first nonempty argument\n\tint first_nonempty_argument = -1;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg_value->Type();\n\t\t\n\t\tif (arg_type != x_type)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_max): function max() requires all arguments to be the same type.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (first_nonempty_argument == -1)\n\t\t{\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count > 0)\n\t\t\t\tfirst_nonempty_argument = arg_index;\n\t\t}\n\t}\n\t\n\tif (first_nonempty_argument == -1)\n\t{\n\t\t// R uses -Inf or +Inf for max/min of a numeric vector, but we want to be consistent between integer and float, and we\n\t\t// want to return an integer value for integer arguments, and there is no integer -Inf/+Inf, so we return NULL.  Note\n\t\t// this means that, unlike R, min() and max() in Eidos are not transitive; min(a, min(b)) != min(a, b) in general.  We\n\t\t// could fix that by returning NULL whenever any of the arguments are zero-length, but that does not seem desirable.\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\t// For logical, we can just scan for a T, in which the result is T, otherwise it is F\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst eidos_logical_t *logical_data = arg_value->LogicalData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\tif (logical_data[value_index] == true)\n\t\t\t\t\treturn gStaticEidosValue_LogicalT;\n\t\t}\n\t\t\n\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t}\n\telse if (x_type == EidosValueType::kValueInt)\n\t{\n\t\tint64_t max = p_arguments[first_nonempty_argument]->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count == 1)\n\t\t\t{\n\t\t\t\tint64_t temp = arg_value->IntData()[0];\n\t\t\t\tif (max < temp)\n\t\t\t\t\tmax = temp;\n\t\t\t}\n\t\t\telse if (arg_count > 1)\n\t\t\t{\n\t\t\t\tconst int64_t *int_data = arg_value->IntData();\n\t\t\t\tint64_t loop_max = INT64_MIN;\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MAX_INT);\n#pragma omp parallel for schedule(static) default(none) shared(arg_count) firstprivate(int_data) reduction(max: loop_max) if(arg_count >= EIDOS_OMPMIN_MAX_INT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\t\tif (loop_max < temp)\n\t\t\t\t\t\tloop_max = temp;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (max < loop_max)\n\t\t\t\t\tmax = loop_max;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(max));\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tdouble max = p_arguments[first_nonempty_argument]->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count == 1)\n\t\t\t{\n\t\t\t\tdouble temp = arg_value->FloatData()[0];\n\t\t\t\t\n\t\t\t\t// if there is a NAN the result is always NAN, so we don't need to scan further\n\t\t\t\tif (std::isnan(temp))\n\t\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\t\t\n\t\t\t\tif (max < temp)\n\t\t\t\t\tmax = temp;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst double *float_data = arg_value->FloatData();\n\t\t\t\tdouble loop_max = -std::numeric_limits<double>::infinity();\n\t\t\t\tbool saw_NAN = false;\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MAX_FLOAT);\n#pragma omp parallel for schedule(static) default(none) shared(arg_count) firstprivate(float_data) reduction(max: loop_max) reduction(||: saw_NAN) if(arg_count >= EIDOS_OMPMIN_MAX_FLOAT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tdouble temp = float_data[value_index];\n\t\t\t\t\t\n\t\t\t\t\t// if there is a NAN the result is always NAN, but we can't return from a parallel region\n\t\t\t\t\tif (std::isnan(temp))\n\t\t\t\t\t\tsaw_NAN = true;\n\t\t\t\t\t\n\t\t\t\t\tif (loop_max < temp)\n\t\t\t\t\t\tloop_max = temp;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (saw_NAN)\n\t\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\t\t\n\t\t\t\tif (max < loop_max)\n\t\t\t\t\tmax = loop_max;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(max));\n\t}\n\telse if (x_type == EidosValueType::kValueString)\n\t{\n\t\tconst std::string *max = &(((EidosValue_String *)(p_arguments[first_nonempty_argument].get()))->StringRefAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue_String *arg_value = (EidosValue_String *)(p_arguments[arg_index].get());\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst std::string *string_vec = arg_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &temp = string_vec[value_index];\n\t\t\t\tif (*max < temp)\n\t\t\t\t\tmax = &temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(*max));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float$)mean(lif x)\nEidosValue_SP Eidos_ExecuteFunction_mean(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 0)\n\t{\n\t\t// BCH 1/11/2026: changing this case from NULL to NAN, to match R;\n\t\t// I just noticed this, and I don't think there's any reason for it\n\t\tresult_SP = gStaticEidosValue_FloatNAN;\n\t}\n\telse if (x_count == 1)\n\t{\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(x_value->FloatAtIndex_CAST(0, nullptr)));\n\t}\n\telse\n\t{\n\t\t// Call sum() to do the addition for us, since it takes exactly the same arguments; it will return numeric$ which we treat as float$\n\t\t// Note this means we inherit the parallelization/vectorization behavior of sum(); we have no separate benchmarks for mean()\n\t\tEidosValue_SP sum_value = Eidos_ExecuteFunction_sum(p_arguments, p_interpreter);\n\t\tdouble sum = sum_value->FloatAtIndex_CAST(0, nullptr);\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sum / x_count));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(+$)min(+ x, ...)\nEidosValue_SP Eidos_ExecuteFunction_min(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValueType x_type = p_arguments[0].get()->Type();\n\t\n\t// check the types of ellipsis arguments and find the first nonempty argument\n\tint first_nonempty_argument = -1;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg_value->Type();\n\t\t\n\t\tif (arg_type != x_type)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_min): function min() requires all arguments to be the same type.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (first_nonempty_argument == -1)\n\t\t{\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count > 0)\n\t\t\t\tfirst_nonempty_argument = arg_index;\n\t\t}\n\t}\n\t\n\tif (first_nonempty_argument == -1)\n\t{\n\t\t// R uses -Inf or +Inf for max/min of a numeric vector, but we want to be consistent between integer and float, and we\n\t\t// want to return an integer value for integer arguments, and there is no integer -Inf/+Inf, so we return NULL.  Note\n\t\t// this means that, unlike R, min() and max() in Eidos are not transitive; min(a, min(b)) != min(a, b) in general.  We\n\t\t// could fix that by returning NULL whenever any of the arguments are zero-length, but that does not seem desirable.\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if (x_type == EidosValueType::kValueLogical)\n\t{\n\t\t// For logical, we can just scan for a F, in which the result is F, otherwise it is T\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst eidos_logical_t *logical_data = arg_value->LogicalData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\tif (logical_data[value_index] == false)\n\t\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t}\n\t\t\n\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t}\n\telse if (x_type == EidosValueType::kValueInt)\n\t{\n\t\tint64_t min = p_arguments[first_nonempty_argument]->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count == 1)\n\t\t\t{\n\t\t\t\tint64_t temp = arg_value->IntData()[0];\n\t\t\t\tif (min > temp)\n\t\t\t\t\tmin = temp;\n\t\t\t}\n\t\t\telse if (arg_count > 1)\n\t\t\t{\n\t\t\t\tconst int64_t *int_data = arg_value->IntData();\n\t\t\t\tint64_t loop_min = INT64_MAX;\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MIN_INT);\n#pragma omp parallel for schedule(static) default(none) shared(arg_count) firstprivate(int_data) reduction(min: loop_min) if(arg_count >= EIDOS_OMPMIN_MIN_INT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\t\tif (loop_min > temp)\n\t\t\t\t\t\tloop_min = temp;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (min > loop_min)\n\t\t\t\t\tmin = loop_min;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(min));\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tdouble min = p_arguments[first_nonempty_argument]->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count == 1)\n\t\t\t{\n\t\t\t\tdouble temp = arg_value->FloatData()[0];\n\t\t\t\t\n\t\t\t\t// if there is a NAN the result is always NAN, so we don't need to scan further\n\t\t\t\tif (std::isnan(temp))\n\t\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\t\t\n\t\t\t\tif (min > temp)\n\t\t\t\t\tmin = temp;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst double *float_data = arg_value->FloatData();\n\t\t\t\tdouble loop_min = std::numeric_limits<double>::infinity();\n\t\t\t\tbool saw_NAN = false;\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MIN_FLOAT);\n#pragma omp parallel for schedule(static) default(none) shared(arg_count) firstprivate(float_data) reduction(min: loop_min) reduction(||: saw_NAN) if(arg_count >= EIDOS_OMPMIN_MIN_FLOAT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tdouble temp = float_data[value_index];\n\t\t\t\t\t\n\t\t\t\t\t// if there is a NAN the result is always NAN, but we can't return from a parallel region\n\t\t\t\t\tif (std::isnan(temp))\n\t\t\t\t\t\tsaw_NAN = true;\n\t\t\t\t\t\n\t\t\t\t\tif (loop_min > temp)\n\t\t\t\t\t\tloop_min = temp;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (saw_NAN)\n\t\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\t\t\n\t\t\t\tif (min > loop_min)\n\t\t\t\t\tmin = loop_min;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(min));\n\t}\n\telse if (x_type == EidosValueType::kValueString)\n\t{\n\t\tconst std::string *min = &(((EidosValue_String *)(p_arguments[first_nonempty_argument].get()))->StringRefAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue_String *arg_value = (EidosValue_String *)(p_arguments[arg_index].get());\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst std::string *string_vec = arg_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &temp = string_vec[value_index];\n\t\t\t\tif (*min > temp)\n\t\t\t\t\tmin = &temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(*min));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(+)pmax(+ x, + y)\nEidosValue_SP Eidos_ExecuteFunction_pmax(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmax): function pmax() requires arguments x and y to be the same type.\" << EidosTerminate(nullptr);\n\tif ((x_count != y_count) && (x_count != 1) && (y_count != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmax): function pmax() requires arguments x and y to be of equal length, or either x or y must be a singleton.\" << EidosTerminate(nullptr);\n\t\n\t// Since we want this operation to be *parallel*, we are stricter about dimensionality than most binary operations; we require the same\n\t// dimensionality unless we have a vector singleton vs. (any) non-singleton pairing, in which case the non-singleton's dimensions are used\n\tif (((x_count != 1) && (y_count != 1)) ||\t\t\t\t\t\t\t// dims must match if both are non-singleton\n\t\t ((x_count == 1) && (y_count == 1)))\t\t\t\t\t\t\t// dims must match if both are singleton\n\t{\n\t\tif (!EidosValue::MatchingDimensions(x_value, y_value))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmax): function pmax() requires arguments x and y to be of the same vector/matrix/array dimensions, unless either x or y (but not both) is a singleton .\" << EidosTerminate(nullptr);\n\t}\n\telse if (((x_count == 1) && (x_value->DimensionCount() != 1)) ||\t// if just one is singleton, it must be a vector\n\t\t\t ((y_count == 1) && (y_value->DimensionCount() != 1)))\t\t// if just one is singleton, it must be a vector\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmax): function pmax() requires that if arguments x and y involve a singleton-to-non-singleton comparison, the singleton is a vector (not a matrix or array).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (x_type == EidosValueType::kValueNULL)\n\t{\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// Handle the singleton case separately so we can handle the vector case quickly\n\t\t\n\t\t// if there is a NAN the result is always NAN\n\t\tif (x_type == EidosValueType::kValueFloat)\n\t\t\tif (std::isnan(x_value->FloatAtIndex_NOCAST(0, nullptr)) || std::isnan(y_value->FloatAtIndex_NOCAST(0, nullptr)))\n\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\tif (CompareEidosValues(*x_value, 0, *y_value, 0, EidosComparisonOperator::kLess, nullptr))\n\t\t\tresult_SP = y_value->CopyValues();\n\t\telse\n\t\t\tresult_SP = x_value->CopyValues();\n\t}\n\telse if ((x_count == 1) || (y_count == 1))\n\t{\n\t\t// One argument, but not both, is singleton; get the singleton value and use fast access on the vector\n\t\t\n\t\t// First, swap as needed to make y be the singleton\n\t\tif (x_count == 1)\n\t\t{\n\t\t\tstd::swap(x_value, y_value);\n\t\t\tstd::swap(x_count, y_count);\n\t\t}\n\t\t\n\t\t// Then split up by type\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical0_data = x_value->LogicalData();\n\t\t\teidos_logical_t y_singleton_value = y_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical0_data[value_index] || y_singleton_value, value_index); // || is logical max\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t * __restrict__ int0_data = x_value->IntData();\n\t\t\tint64_t y_singleton_value = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\t\tint64_t * __restrict__ int_result_data = int_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\t// BCH 12/27/2022: This and the corresponding loop in pmin() show an unusually high variance in execution time, for the same data.\n\t\t\t// The benchmark model typically runs in either 7-8 seconds, or 11-12 seconds, not in between.  Timing indicates that this is due\n\t\t\t// to an overall slowdown of the whole process, not a 3-4 second pause with a massive one-time stall.  I suspect that there is\n\t\t\t// something about this loop that tends to encourage macOS to move the thread to an efficiency core, as bizarre as that sounds.\n\t\t\t// (I'm... too sexy for my core... too sexy for my core... core's going to offload me...)  Well, it's the only hypothesis left.\n\t\t\t// I tried upping the QoS (\"quality of service\") setting for the process to encourage it to stay on the performance cores, but\n\t\t\t// that actually made things worse, maybe by increasing contention with UI-based apps.  Removing SIMD from this loop makes no\n\t\t\t// difference.  I looked at the alignment of int0_data and int_result_data, and that is uncorrelated with the performance issue.\n\t\t\t// I haven't figured out how to confirm my hypothesis with profiling tools yet.  It's a mystery.  Leaving this comment here\n\t\t\t// for posterity.  It's not a big deal in the grand scheme of things, but I would love to know what's going on.  FIXME\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMAX_INT_1);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(int0_data, int_result_data, y_singleton_value) if(parallel:x_count >= EIDOS_OMPMIN_PMAX_INT_1) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t int0_value = int0_data[value_index];\n\t\t\t\tint_result_data[value_index] = ((int0_value > y_singleton_value) ? int0_value : y_singleton_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double * __restrict__ float0_data = x_value->FloatData();\n\t\t\tdouble y_singleton_value = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\t\tdouble * __restrict__ float_result_data = float_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMAX_FLOAT_1);\n#pragma omp parallel for schedule(static) default(none) shared(x_count) firstprivate(float0_data, float_result_data, y_singleton_value) if(x_count >= EIDOS_OMPMIN_PMAX_FLOAT_1) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\t// if there is a NAN the result is always NAN\n\t\t\t\tdouble float0_value = float0_data[value_index];\n\t\t\t\tif (std::isnan(float0_value) || std::isnan(y_singleton_value))\n\t\t\t\t\tfloat_result_data[value_index] = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\telse\n\t\t\t\t\tfloat_result_data[value_index] = ((float0_value > y_singleton_value) ? float0_value : y_singleton_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string0_vec = x_value->StringData();\n\t\t\tconst std::string &y_singleton_value = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(std::max(string0_vec[value_index], y_singleton_value));\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We know the type is not NULL or object, that x_count == y_count, and that they are not singletons; we split up by type and handle fast\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical0_data = x_value->LogicalData();\n\t\t\tconst eidos_logical_t *logical1_data = y_value->LogicalData();\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical0_data[value_index] || logical1_data[value_index], value_index); // || is logical max\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t * __restrict__ int0_data = x_value->IntData();\n\t\t\tconst int64_t * __restrict__ int1_data = y_value->IntData();\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\t\tint64_t * __restrict__ int_result_data = int_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMAX_INT_2);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(int0_data, int1_data, int_result_data) if(parallel:x_count >= EIDOS_OMPMIN_PMAX_INT_2) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t int0_value = int0_data[value_index];\n\t\t\t\tint64_t int1_value = int1_data[value_index];\n\t\t\t\tint_result_data[value_index] = (int0_value > int1_value) ? int0_value : int1_value;\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double * __restrict__ float0_data = x_value->FloatData();\n\t\t\tconst double * __restrict__ float1_data = y_value->FloatData();\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\t\tdouble * __restrict__ float_result_data = float_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMAX_FLOAT_2);\n#pragma omp parallel for schedule(static) default(none) shared(x_count) firstprivate(float0_data, float1_data, float_result_data) if(x_count >= EIDOS_OMPMIN_PMAX_FLOAT_2) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\t// if there is a NAN the result is always NAN\n\t\t\t\tdouble float0_value = float0_data[value_index];\n\t\t\t\tdouble float1_value = float1_data[value_index];\n\t\t\t\tif (std::isnan(float0_data[value_index]) || std::isnan(float1_data[value_index]))\n\t\t\t\t\tfloat_result_data[value_index] = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\telse\n\t\t\t\t\tfloat_result_data[value_index] = ((float0_value > float1_value) ? float0_value : float1_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string0_vec = x_value->StringData();\n\t\t\tconst std::string *string1_vec = y_value->StringData();\n\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(std::max(string0_vec[value_index], string1_vec[value_index]));\n\t\t}\n\t}\n\t\n\t// Either x and y have the same dimensionality (so it doesn't matter which we copy from), or x is the non-singleton\n\t// and y is the singleton (due to the swap call above).  So this is the correct choice for all of the cases above.\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(+)pmin(+ x, + y)\nEidosValue_SP Eidos_ExecuteFunction_pmin(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\t\n\tif (x_type != y_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmin): function pmin() requires arguments x and y to be the same type.\" << EidosTerminate(nullptr);\n\tif ((x_count != y_count) && (x_count != 1) && (y_count != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmin): function pmin() requires arguments x and y to be of equal length, or either x or y must be a singleton.\" << EidosTerminate(nullptr);\n\t\n\t// Since we want this operation to be *parallel*, we are stricter about dimensionality than most binary operations; we require the same\n\t// dimensionality unless we have a vector singleton vs. (any) non-singleton pairing, in which the non-singleton's dimensions are used\n\tif (((x_count != 1) && (y_count != 1)) ||\t\t\t\t\t\t\t// dims must match if both are non-singleton\n\t\t ((x_count == 1) && (y_count == 1)))\t\t\t\t\t\t\t// dims must match if both are singleton\n\t{\n\t\tif (!EidosValue::MatchingDimensions(x_value, y_value))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmin): function pmin() requires arguments x and y to be of the same vector/matrix/array dimensions, unless either x or y (but not both) is a singleton .\" << EidosTerminate(nullptr);\n\t}\n\telse if (((x_count == 1) && (x_value->DimensionCount() != 1)) ||\t// if just one is singleton, it must be a vector\n\t\t\t ((y_count == 1) && (y_value->DimensionCount() != 1)))\t\t// if just one is singleton, it must be a vector\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_pmin): function pmin() requires that if arguments x and y involve a singleton-to-non-singleton comparison, the singleton is a vector (not a matrix or array).\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (x_type == EidosValueType::kValueNULL)\n\t{\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if ((x_count == 1) && (y_count == 1))\n\t{\n\t\t// Handle the singleton case separately so we can handle the vector case quickly\n\t\t\n\t\t// if there is a NAN the result is always NAN\n\t\tif (x_type == EidosValueType::kValueFloat)\n\t\t\tif (std::isnan(x_value->FloatAtIndex_NOCAST(0, nullptr)) || std::isnan(y_value->FloatAtIndex_NOCAST(0, nullptr)))\n\t\t\t\treturn gStaticEidosValue_FloatNAN;\n\t\t\n\t\tif (CompareEidosValues(*x_value, 0, *y_value, 0, EidosComparisonOperator::kGreater, nullptr))\n\t\t\tresult_SP = y_value->CopyValues();\n\t\telse\n\t\t\tresult_SP = x_value->CopyValues();\n\t}\n\telse if ((x_count == 1) || (y_count == 1))\n\t{\n\t\t// One argument, but not both, is singleton; get the singleton value and use fast access on the vector\n\t\t\n\t\t// First, swap as needed to make y be the singleton\n\t\tif (x_count == 1)\n\t\t{\n\t\t\tstd::swap(x_value, y_value);\n\t\t\tstd::swap(x_count, y_count);\n\t\t}\n\t\t\n\t\t// Then split up by type\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical0_data = x_value->LogicalData();\n\t\t\teidos_logical_t y_singleton_value = y_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical0_data[value_index] && y_singleton_value, value_index); // && is logical min\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t * __restrict__ int0_data = x_value->IntData();\n\t\t\tint64_t y_singleton_value = y_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\t\tint64_t * __restrict__ int_result_data = int_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMIN_INT_1);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(int0_data, int_result_data, y_singleton_value) if(parallel:x_count >= EIDOS_OMPMIN_PMIN_INT_1) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t int0_value = int0_data[value_index];\n\t\t\t\tint_result_data[value_index] = ((int0_value < y_singleton_value) ? int0_value : y_singleton_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double * __restrict__ float0_data = x_value->FloatData();\n\t\t\tdouble y_singleton_value = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\t\tdouble * __restrict__ float_result_data = float_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMIN_FLOAT_1);\n#pragma omp parallel for schedule(static) default(none) shared(x_count) firstprivate(float0_data, float_result_data, y_singleton_value) if(x_count >= EIDOS_OMPMIN_PMIN_FLOAT_1) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\t// if there is a NAN the result is always NAN\n\t\t\t\tdouble float0_value = float0_data[value_index];\n\t\t\t\tif (std::isnan(float0_value) || std::isnan(y_singleton_value))\n\t\t\t\t\tfloat_result_data[value_index] = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\telse\n\t\t\t\t\tfloat_result_data[value_index] = ((float0_value < y_singleton_value) ? float0_value : y_singleton_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string0_vec = x_value->StringData();\n\t\t\tconst std::string &y_singleton_value = ((EidosValue_String *)y_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(std::min(string0_vec[value_index], y_singleton_value));\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We know the type is not NULL or object, that x_count == y_count, and that they are not singletons; we split up by type and handle fast\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical0_data = x_value->LogicalData();\n\t\t\tconst eidos_logical_t *logical1_data = y_value->LogicalData();\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical0_data[value_index] && logical1_data[value_index], value_index); // && is logical min\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t * __restrict__ int0_data = x_value->IntData();\n\t\t\tconst int64_t * __restrict__ int1_data = y_value->IntData();\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\t\tint64_t * __restrict__ int_result_data = int_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMIN_INT_2);\n#pragma omp parallel for simd schedule(simd:static) default(none) shared(x_count) firstprivate(int0_data, int1_data, int_result_data) if(parallel:x_count >= EIDOS_OMPMIN_PMIN_INT_2) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t int0_value = int0_data[value_index];\n\t\t\t\tint64_t int1_value = int1_data[value_index];\n\t\t\t\tint_result_data[value_index] = (int0_value < int1_value) ? int0_value : int1_value;\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double * __restrict__ float0_data = x_value->FloatData();\n\t\t\tconst double * __restrict__ float1_data = y_value->FloatData();\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\t\tdouble * __restrict__ float_result_data = float_result->data_mutable();\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_PMIN_FLOAT_2);\n#pragma omp parallel for schedule(static) default(none) shared(x_count) firstprivate(float0_data, float1_data, float_result_data) if(x_count >= EIDOS_OMPMIN_PMIN_FLOAT_2) num_threads(thread_count)\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\t// if there is a NAN the result is always NAN\n\t\t\t\tdouble float0_value = float0_data[value_index];\n\t\t\t\tdouble float1_value = float1_data[value_index];\n\t\t\t\tif (std::isnan(float0_data[value_index]) || std::isnan(float1_data[value_index]))\n\t\t\t\t\tfloat_result_data[value_index] = std::numeric_limits<double>::quiet_NaN();\n\t\t\t\telse\n\t\t\t\t\tfloat_result_data[value_index] = ((float0_value < float1_value) ? float0_value : float1_value);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string0_vec = x_value->StringData();\n\t\t\tconst std::string *string1_vec = y_value->StringData();\n\t\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(std::min(string0_vec[value_index], string1_vec[value_index]));\n\t\t}\n\t}\n\t\n\t// Either x and y have the same dimensionality (so it doesn't matter which we copy from), or x is the non-singleton\n\t// and y is the singleton (due to the swap call above).  So this is the correct choice for all of the cases above.\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(float)quantile(numeric x, [Nf probs = NULL])\nEidosValue_SP Eidos_ExecuteFunction_quantile(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tEidosValue *probs_value = p_arguments[1].get();\n\tint probs_count = probs_value->Count();\n\t\n\tif (x_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_quantile): function quantile() requires x to have length greater than 0.\" << EidosTerminate(nullptr);\n\t\n\t// get the probabilities; this is mostly so we don't have to special-case NULL below, but we also pre-check the probabilities here\n\tstd::vector<double> probs;\n\t\n\tif (probs_value->Type() == EidosValueType::kValueNULL)\n\t{\n\t\tprobs.emplace_back(0.0);\n\t\tprobs.emplace_back(0.25);\n\t\tprobs.emplace_back(0.50);\n\t\tprobs.emplace_back(0.75);\n\t\tprobs.emplace_back(1.0);\n\t\tprobs_count = 5;\n\t}\n\telse\n\t{\n\t\tfor (int probs_index = 0; probs_index < probs_count; ++probs_index)\n\t\t{\n\t\t\tdouble prob = probs_value->FloatAtIndex_NOCAST(probs_index, nullptr);\n\t\t\t\n\t\t\tif ((prob < 0.0) || (prob > 1.0))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_quantile): function quantile() requires probabilities to be in [0, 1].\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tprobs.emplace_back(prob);\n\t\t}\n\t}\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(probs_count);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tif (x_count == 1)\n\t{\n\t\t// All quantiles of a singleton are the value of the singleton; the probabilities don't matter as long as they're in range (checked above)\n\t\tdouble x_singleton = x_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (std::isnan(x_singleton))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_quantile): quantiles of NAN are undefined.\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (int probs_index = 0; probs_index < probs_count; ++probs_index)\n\t\t\tfloat_result->set_float_no_check(x_singleton, probs_index);\n\t}\n\telse\n\t{\n\t\t// Here we handle the non-singleton case, which can be done with direct access\n\t\t// First, if x is float, we check for NANs, which are not allowed\n\t\tEidosValueType x_type = x_value->Type();\n\t\t\n\t\tif (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tif (std::isnan(float_data[value_index]))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_quantile): quantiles of NAN are undefined.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\t// Next we get an order vector for x, which can be integer or float\n\t\tstd::vector<int64_t> order;\n\t\t\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t\torder = EidosSortIndexes(x_value->IntData(), x_count, true);\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t\torder = EidosSortIndexes(x_value->FloatData(), x_count, true);\n\t\t\n\t\t// Now loop over the requested probabilities and calculate them\n\t\tfor (int probs_index = 0; probs_index < probs_count; ++probs_index)\n\t\t{\n\t\t\tdouble prob = probs[probs_index];\n\t\t\tdouble index = (x_count - 1) * prob;\n\t\t\tint64_t lo = (int64_t)std::floor(index);\n\t\t\tint64_t hi = (int64_t)std::ceil(index);\n\t\t\t\n\t\t\tdouble quantile = x_value->NumericAtIndex_NOCAST((int)order[lo], nullptr);\n\t\t\tif (lo != hi) {\n\t\t\t\tdouble h = index - lo;\n\t\t\t\tquantile *= (1.0 - h);\n\t\t\t\tquantile += h * x_value->NumericAtIndex_NOCAST((int)order[hi], nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tfloat_result->set_float_no_check(quantile, probs_index);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)range(numeric x, ...)\nEidosValue_SP Eidos_ExecuteFunction_range(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValueType x_type = p_arguments[0].get()->Type();\n\t\n\t// check the types of ellipsis arguments and find the first nonempty argument\n\tint first_nonempty_argument = -1;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\tEidosValueType arg_type = arg_value->Type();\n\t\t\n\t\tif (arg_type != x_type)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_range): function range() requires all arguments to be the same type.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (first_nonempty_argument == -1)\n\t\t{\n\t\t\tint arg_count = arg_value->Count();\n\t\t\t\n\t\t\tif (arg_count > 0)\n\t\t\t\tfirst_nonempty_argument = arg_index;\n\t\t}\n\t}\n\t\n\tif (first_nonempty_argument == -1)\n\t{\n\t\t// R uses -Inf or +Inf for max/min of a numeric vector, but we want to be consistent between integer and float, and we\n\t\t// want to return an integer value for integer arguments, and there is no integer -Inf/+Inf, so we return NULL.  Note\n\t\t// this means that, unlike R, min() and max() in Eidos are not transitive; min(a, min(b)) != min(a, b) in general.  We\n\t\t// could fix that by returning NULL whenever any of the arguments are zero-length, but that does not seem desirable.\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if (x_type == EidosValueType::kValueInt)\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(2);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tint64_t max = p_arguments[first_nonempty_argument]->IntAtIndex_NOCAST(0, nullptr);\n\t\tint64_t min = max;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst int64_t *int_data = arg_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\tif (max < temp)\n\t\t\t\t\tmax = temp;\n\t\t\t\telse if (min > temp)\n\t\t\t\t\tmin = temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tint_result->set_int_no_check(min, 0);\n\t\tint_result->set_int_no_check(max, 1);\n\t}\n\telse if (x_type == EidosValueType::kValueFloat)\n\t{\n\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(2);\n\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\n\t\tdouble max = p_arguments[first_nonempty_argument]->FloatAtIndex_NOCAST(0, nullptr);\n\t\tdouble min = max;\n\t\t\n\t\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t\t{\n\t\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\tint arg_count = arg_value->Count();\n\t\t\tconst double *float_data = arg_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble temp = float_data[value_index];\n\t\t\t\t\n\t\t\t\t// if there is a NAN, the range is always (NAN,NAN); short-circuit\n\t\t\t\tif (std::isnan(temp))\n\t\t\t\t{\n\t\t\t\t\tfloat_result->set_float_no_check(std::numeric_limits<double>::quiet_NaN(), 0);\n\t\t\t\t\tfloat_result->set_float_no_check(std::numeric_limits<double>::quiet_NaN(), 1);\n\t\t\t\t\treturn result_SP;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (max < temp)\n\t\t\t\t\tmax = temp;\n\t\t\t\telse if (min > temp)\n\t\t\t\t\tmin = temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfloat_result->set_float_no_check(min, 0);\n\t\tfloat_result->set_float_no_check(max, 1);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(float$)sd(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_sd(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t// This is different from the behavior of var(), cor(), and cov(), but follows R\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count <= 1)\n\t\treturn gStaticEidosValue_FloatNAN;\n\t\n\tdouble mean = 0;\n\tdouble sd = 0;\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tmean += x_value->NumericAtIndex_NOCAST(value_index, nullptr);\n\t\n\tmean /= x_count;\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t{\n\t\tdouble temp = (x_value->NumericAtIndex_NOCAST(value_index, nullptr) - mean);\n\t\tsd += temp * temp;\n\t}\n\t\n\tsd = sqrt(sd / (x_count - 1));\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(sd));\n\t\n\treturn result_SP;\n}\n\n//\t(float$)ttest(float x, [Nf y = NULL], [Nf$ mu = NULL])\nEidosValue_SP Eidos_ExecuteFunction_ttest(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValueType y_type = y_value->Type();\n\tint y_count = y_value->Count();\n\tEidosValue *mu_value = p_arguments[2].get();\n\tEidosValueType mu_type = mu_value->Type();\n\t\n\tif ((y_type == EidosValueType::kValueNULL) && (mu_type == EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ttest): function ttest() requires either y or mu to be non-NULL.\" << EidosTerminate(nullptr);\n\tif ((y_type != EidosValueType::kValueNULL) && (mu_type != EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ttest): function ttest() requires either y or mu to be NULL.\" << EidosTerminate(nullptr);\n\tif (x_count <= 1)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ttest): function ttest() requires enough elements in x to compute variance.\" << EidosTerminate(nullptr);\n\t\n\tconst double *vec1 = x_value->FloatData();\n\tdouble pvalue = 0.0;\n\t\n\tif (y_type != EidosValueType::kValueNULL)\n\t{\n\t\t// This is the x & y case, which is a two-sample Welch's t-test\n\t\tif (y_count <= 1)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ttest): function ttest() requires enough elements in y to compute variance.\" << EidosTerminate(nullptr);\n\t\t\n\t\tconst double *vec2 = y_value->FloatData();\n\t\t\n\t\t// Right now this function only provides a two-sample t-test; we could add an optional mu argument and make y optional in order to allow a one-sample test as well\n\t\t// If we got into that, we'd probably want to provide one-sided t-tests as well, yada yada...\n\t\tpvalue = Eidos_TTest_TwoSampleWelch(vec1, x_count, vec2, y_count, nullptr, nullptr);\n\t}\n\telse if (mu_type != EidosValueType::kValueNULL)\n\t{\n\t\t// This is the x & mu case, which is a one-sample t-test\n\t\tdouble mu = mu_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tpvalue = Eidos_TTest_OneSample(vec1, x_count, mu, nullptr);\n\t}\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(pvalue));\n\t\n\treturn result_SP;\n}\n\n//\t(float$)var(numeric x)\nEidosValue_SP Eidos_ExecuteFunction_var(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tif (x_value->IsMatrixOrArray())\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_var): function var() does not support a matrix/array argument; use cov() to calculate variance-covariance matrices.\" << EidosTerminate(nullptr);\n\t\n\tint x_count = x_value->Count();\n\t\n\tif (x_count <= 1)\n\t\treturn gStaticEidosValue_FloatNAN;\n\t\n\t// calculate variance of x (covariance between x and itself)\n\tdouble cov = _Eidos_CalcCovariance(x_count, x_value, x_value, 0, 0);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(cov));\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_strings.cpp",
    "content": "//\n//  eidos_functions_strings.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n\n#include <string>\n#include <vector>\n#include <regex>\n\n\n// ************************************************************************************\n//\n//\tstring manipulation functions\n//\n\n#pragma mark -\n#pragma mark String manipulation functions\n#pragma mark -\n\n\n//\t(lis)grep(string$ pattern, string x, [logical$ ignoreCase = F], [string$ grammar = \"ECMAScript\"], [string$ value = \"indices\"], [logical$ fixed = F], [logical$ invert = F])\nEidosValue_SP Eidos_ExecuteFunction_grep(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_String *pattern_value = (EidosValue_String *)(p_arguments[0].get());\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[1].get());\n\tEidosValue_Logical *ignoreCase_value = (EidosValue_Logical *)(p_arguments[2].get());\n\tEidosValue_String *grammar_value = (EidosValue_String *)(p_arguments[3].get());\n\tEidosValue_String *value_value = (EidosValue_String *)(p_arguments[4].get());\n\tEidosValue_Logical *fixed_value = (EidosValue_Logical *)(p_arguments[5].get());\n\tEidosValue_Logical *invert_value = (EidosValue_Logical *)(p_arguments[6].get());\n\t\n\t// Figure out our parameters\n\tconst std::string &pattern = pattern_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tsize_t pattern_length = pattern.length();\n\tint x_count = x_value->Count();\n\tbool ignoreCase = ignoreCase_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tconst std::string &grammar = grammar_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tconst std::string &value = value_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tbool fixed = fixed_value->LogicalAtIndex_NOCAST(0, nullptr);\n\tbool invert = invert_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif (pattern_length == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): function grep() requires pattern to be of length >= 1.\" << EidosTerminate(nullptr);\n\t\n\tstd::regex_constants::syntax_option_type grammar_enum;\n\t\n\tif (grammar == \"ECMAScript\")\tgrammar_enum = std::regex_constants::ECMAScript;\n\telse if (grammar == \"basic\")\tgrammar_enum = std::regex_constants::basic;\n\telse if (grammar == \"extended\")\tgrammar_enum = std::regex_constants::extended;\n\telse if (grammar == \"awk\")\t\tgrammar_enum = std::regex_constants::awk;\n\telse if (grammar == \"grep\")\t\tgrammar_enum = std::regex_constants::grep;\n\telse if (grammar == \"egrep\")\tgrammar_enum = std::regex_constants::egrep;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): function grep() requires grammar to be one of 'ECMAScript', 'basic', 'extended', 'awk', 'grep', or 'egrep'.\" << EidosTerminate(nullptr);\n\t\n\tenum Eidos_grepValueType {\n\t\tkIndices = 0,\n\t\tkElements,\n\t\tkMatches,\n\t\tkLogical\n\t};\n\t\n\tEidos_grepValueType value_enum;\n\t\n\tif (value == \"indices\")\t\t\tvalue_enum = kIndices;\n\telse if (value == \"elements\")\tvalue_enum = kElements;\n\telse if (value == \"matches\")\tvalue_enum = kMatches;\n\telse if (value == \"logical\")\tvalue_enum = kLogical;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): function grep() requires value to be one of 'indices', 'elements', 'matches', or 'logical'.\" << EidosTerminate(nullptr);\n\t\n\tif (invert && (value_enum == kMatches))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): function grep() does not allow value='matches' when invert=T.\" << EidosTerminate(nullptr);\n\t\n\t// Make our return value\n\tEidosValue_SP result_SP(nullptr);\n\tEidosValue_Logical *result_logical = nullptr;\n\tEidosValue_Int *result_int = nullptr;\n\tEidosValue_String *result_string = nullptr;\n\t\n\tif (value_enum == kIndices)\n\t{\n\t\tresult_int = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\tresult_SP = EidosValue_SP(result_int);\n\t}\n\telse if ((value_enum == kElements) || (value_enum == kMatches))\n\t{\n\t\tresult_string = (new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\tresult_SP = EidosValue_SP(result_string);\n\t}\n\telse if (value_enum == kLogical)\n\t{\n\t\tresult_logical = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(result_logical);\n\t}\n\t\n\t// Do the matching, producing the appropriate value type into the result\n\tif (fixed)\n\t{\n\t\t// pattern is a fixed string, so use basic C++ string searching, honoring ignoreCase and invert\n\t\tfor (int i = 0; i < x_count; ++i)\n\t\t{\n\t\t\tconst std::string &x_element = x_value->StringRefAtIndex_NOCAST(i, nullptr);\n\t\t\tsize_t match_pos = std::string::npos;\t// not valid when invert==T, which is why \"match\" is disallowed then\n\t\t\tbool is_match = false;\n\t\t\t\n\t\t\tif (ignoreCase)\n\t\t\t{\n\t\t\t\t// see https://stackoverflow.com/a/19839371/2752221\n\t\t\t\tauto iter = std::search(x_element.begin(), x_element.end(),\n\t\t\t\t\t\t\t\t\t  pattern.begin(),   pattern.end(),\n\t\t\t\t\t\t\t\t\t  [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); });\n\t\t\t\tis_match = (iter != x_element.end());\n\t\t\t\tif (is_match)\n\t\t\t\t\tmatch_pos = iter - x_element.begin();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmatch_pos = x_element.find(pattern, 0);\n\t\t\t\tis_match = (match_pos != std::string::npos);\n\t\t\t}\n\t\t\t\n\t\t\tif (invert)\n\t\t\t\tis_match = !is_match;\n\t\t\t\n\t\t\tif (is_match)\n\t\t\t{\n\t\t\t\tif (value_enum == kIndices)\n\t\t\t\t{\n\t\t\t\t\tresult_int->push_int(i);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kElements)\n\t\t\t\t{\n\t\t\t\t\tstd::string x_element_copy = x_element;\n\t\t\t\t\tresult_string->PushString(x_element_copy);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kMatches)\n\t\t\t\t{\n\t\t\t\t\tstd::string matched_substring = x_element.substr(match_pos, pattern_length);\n\t\t\t\t\tresult_string->PushString(matched_substring);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kLogical)\n\t\t\t\t{\n\t\t\t\t\tresult_logical->set_logical_no_check(true, i);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (value_enum == kLogical)\n\t\t\t\t\tresult_logical->set_logical_no_check(false, i);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!Eidos_RegexWorks())\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_grep): This build of Eidos does not have a working <regex> library, due to a bug in the underlying C++ standard library provided by the system.  Calls to grep() with fixed=F, to do regular expression matching, are therefore not allowed.  This problem might be resolved by updating your compiler or toolchain, or by upgrading to a more recent version of your operating system.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// pattern is a regular expression, so use <regex> to find matches using grammar, honoring ignoreCase and invert\n\t\tif (ignoreCase)\n\t\t\tgrammar_enum |= std::regex_constants::icase;\n\t\t\n\t\tstd::regex pattern_regex(pattern, grammar_enum);\n\t\t\n\t\tfor (int i = 0; i < x_count; ++i)\n\t\t{\n\t\t\tconst std::string &x_element = x_value->StringRefAtIndex_NOCAST(i, nullptr);\n\t\t\tstd::smatch match_info;\n\t\t\tbool is_match = std::regex_search(x_element, match_info, pattern_regex);\n\t\t\t\n\t\t\tif (invert)\n\t\t\t\tis_match = !is_match;\n\t\t\t\n\t\t\tif (is_match)\n\t\t\t{\n\t\t\t\tif (value_enum == kIndices)\n\t\t\t\t{\n\t\t\t\t\tresult_int->push_int(i);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kElements)\n\t\t\t\t{\n\t\t\t\t\tstd::string x_element_copy = x_element;\n\t\t\t\t\tresult_string->PushString(x_element_copy);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kMatches)\n\t\t\t\t{\n\t\t\t\t\tstd::string matched_substring = match_info.str(0);\n\t\t\t\t\tresult_string->PushString(matched_substring);\n\t\t\t\t}\n\t\t\t\telse if (value_enum == kLogical)\n\t\t\t\t{\n\t\t\t\t\tresult_logical->set_logical_no_check(true, i);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (value_enum == kLogical)\n\t\t\t\t\tresult_logical->set_logical_no_check(false, i);\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)nchar(string x)\nEidosValue_SP Eidos_ExecuteFunction_nchar(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[0].get());\n\tint x_count = x_value->Count();\n\tconst std::string *string_vec = x_value->StringData();\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tint_result->set_int_no_check(string_vec[value_index].size(), value_index);\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)strcontains(string x, string$ s, [i$ pos = 0])\nEidosValue_SP Eidos_ExecuteFunction_strcontains(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[0].get());\n\tEidosValue_String *s_value = (EidosValue_String *)(p_arguments[1].get());\n\tEidosValue_Int *pos_value = (EidosValue_Int *)(p_arguments[2].get());\n\t\n\tint x_count = x_value->Count();\n\tconst std::string &s = s_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tint64_t pos = pos_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (s.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strcontains): function strcontains() requires s to be of length >= 1.\" << EidosTerminate(nullptr);\n\tif (pos < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strcontains): function strcontains() requires pos to be >= 0.\" << EidosTerminate(nullptr);\n\t\n\tif ((x_count == 1) && (x_value ->DimensionCount() == 1))\n\t{\n\t\tconst std::string &x = x_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\tsize_t index = x.find(s, pos);\n\t\t\n\t\treturn (index != std::string::npos ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tsize_t index = string_vec[value_index].find(s, pos);\n\t\t\tlogical_result->set_logical_no_check(index != std::string::npos, value_index);\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)strfind(string x, string$ s, [i$ pos = 0])\nEidosValue_SP Eidos_ExecuteFunction_strfind(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[0].get());\n\tEidosValue_String *s_value = (EidosValue_String *)(p_arguments[1].get());\n\tEidosValue_Int *pos_value = (EidosValue_Int *)(p_arguments[2].get());\n\t\n\tint x_count = x_value->Count();\n\tconst std::string &s = s_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tint64_t pos = pos_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (s.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strfind): function strfind() requires s to be of length >= 1.\" << EidosTerminate(nullptr);\n\tif (pos < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strfind): function strfind() requires pos to be >= 0.\" << EidosTerminate(nullptr);\n\t\n\tconst std::string *string_vec = x_value->StringData();\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t{\n\t\tsize_t index = string_vec[value_index].find(s, pos);\n\t\tint_result->set_int_no_check(index == std::string::npos ? -1 : (int64_t)index, value_index);\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)strprefix(string x, string$ s)\nEidosValue_SP Eidos_ExecuteFunction_strprefix(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[0].get());\n\tEidosValue_String *s_value = (EidosValue_String *)(p_arguments[1].get());\n\t\n\tint x_count = x_value->Count();\n\tconst std::string &s = s_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (s.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strprefix): function strprefix() requires s to be of length >= 1.\" << EidosTerminate(nullptr);\n\t\n\tif ((x_count == 1) && (x_value ->DimensionCount() == 1))\n\t{\n\t\tconst std::string &x = x_value->StringData()[0];\n\t\tbool has_prefix = Eidos_string_hasPrefix(x, s);\n\t\t\n\t\treturn (has_prefix ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tbool has_prefix = Eidos_string_hasPrefix(string_vec[value_index], s);\n\t\t\tlogical_result->set_logical_no_check(has_prefix, value_index);\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(string)strsplit(string$ x, [string$ sep = \" \"])\nEidosValue_SP Eidos_ExecuteFunction_strsplit(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)p_arguments[0].get();\n\tEidosValue_String *sep_value = (EidosValue_String *)p_arguments[1].get();\n\tEidosValue_String *string_result = new (gEidosValuePool->AllocateChunk()) EidosValue_String();\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tconst std::string &joined_string = x_value->StringRefAtIndex_NOCAST(0, nullptr);\n\tconst std::string &separator = sep_value->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string::size_type start_idx = 0, sep_idx;\n\t\n\tif (separator.length() == 0)\n\t{\n\t\t// special-case a zero-length separator\n\t\tfor (const char &ch : joined_string)\n\t\t\tstring_result->PushString(std::string(&ch, 1));\n\t}\n\telse\n\t{\n\t\t// non-zero-length separator\n\t\twhile (true)\n\t\t{\n\t\t\tsep_idx = joined_string.find(separator, start_idx);\n\t\t\t\n\t\t\tif (sep_idx == std::string::npos)\n\t\t\t{\n\t\t\t\tstring_result->PushString(joined_string.substr(start_idx));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstring_result->PushString(joined_string.substr(start_idx, sep_idx - start_idx));\n\t\t\t\tstart_idx = sep_idx + separator.size();\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(logical)strsuffix(string x, string$ s)\nEidosValue_SP Eidos_ExecuteFunction_strsuffix(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)(p_arguments[0].get());\n\tEidosValue_String *s_value = (EidosValue_String *)(p_arguments[1].get());\n\t\n\tint x_count = x_value->Count();\n\tconst std::string &s = s_value->StringRefAtIndex_NOCAST(0, nullptr);\n\t\n\tif (s.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_strsuffix): function strsuffix() requires s to be of length >= 1.\" << EidosTerminate(nullptr);\n\t\n\tif ((x_count == 1) && (x_value ->DimensionCount() == 1))\n\t{\n\t\tconst std::string &x = x_value->StringData()[0];\n\t\tbool has_prefix = Eidos_string_hasSuffix(x, s);\n\t\t\n\t\treturn (has_prefix ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tbool has_prefix = Eidos_string_hasSuffix(string_vec[value_index], s);\n\t\t\tlogical_result->set_logical_no_check(has_prefix, value_index);\n\t\t}\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(string)substr(string x, integer first, [Ni last = NULL])\nEidosValue_SP Eidos_ExecuteFunction_substr(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue_String *x_value = (EidosValue_String *)p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *arg_last = p_arguments[2].get();\n\tEidosValueType arg_last_type = arg_last->Type();\n\tconst std::string *string_vec = x_value->StringData();\n\tEidosValue *arg_first = p_arguments[1].get();\n\tint arg_first_count = arg_first->Count();\n\tbool first_singleton = (arg_first_count == 1);\n\t\n\tif (!first_singleton && (arg_first_count != x_count))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_substr): function substr() requires the size of first to be 1, or equal to the size of x.\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tint64_t first0 = arg_first->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (arg_last_type != EidosValueType::kValueNULL)\n\t{\n\t\t// last supplied\n\t\tint arg_last_count = arg_last->Count();\n\t\tbool last_singleton = (arg_last_count == 1);\n\t\t\n\t\tif (!last_singleton && (arg_last_count != x_count))\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_substr): function substr() requires the size of last to be 1, or equal to the size of x.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint64_t last0 = arg_last->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tconst std::string &str = string_vec[value_index];\n\t\t\tint64_t len = (int64_t)str.size();\n\t\t\tint64_t clamped_first = (first_singleton ? first0 : arg_first->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\tint64_t clamped_last = (last_singleton ? last0 : arg_last->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (clamped_first < 0) clamped_first = 0;\n\t\t\tif (clamped_last >= len) clamped_last = (int)len - 1;\n\t\t\t\n\t\t\tif ((clamped_first >= len) || (clamped_last < 0) || (clamped_first > clamped_last))\n\t\t\t\tstring_result->PushString(gEidosStr_empty_string);\n\t\t\telse\n\t\t\t\tstring_result->PushString(str.substr(clamped_first, clamped_last - clamped_first + 1));\n\t\t}\n\t}\n\telse\n\t{\n\t\t// last not supplied; take substrings to the end of each string\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tconst std::string &str = string_vec[value_index];\n\t\t\tint64_t len = (int64_t)str.size();\n\t\t\tint64_t clamped_first = (first_singleton ? first0 : arg_first->IntAtIndex_NOCAST(value_index, nullptr));\n\t\t\t\n\t\t\tif (clamped_first < 0) clamped_first = 0;\n\t\t\t\n\t\t\tif (clamped_first >= len)\t\t\t\t\t\t\n\t\t\t\tstring_result->PushString(gEidosStr_empty_string);\n\t\t\telse\n\t\t\t\tstring_result->PushString(str.substr(clamped_first, len));\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_functions_values.cpp",
    "content": "//\n//  eidos_functions_values.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/6/15; split from eidos_functions.cpp 09/26/2022\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_functions.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_sorting.h\"\n\n#include <unordered_map>\n#include <vector>\n#include <algorithm>\n#include <utility>\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\n#endif\n\n\n// From stackoverflow: http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf/\n// I chose to use iFreilicht's answer, which requires C++11.  BCH 26 April 2016\n#include <memory>\n#include <iostream>\n#include <string>\n#include <cstdio>\n#include <cinttypes>\n\ntemplate<typename ... Args>\nstd::string EidosStringFormat(const std::string& format, Args ... args)\n{\n\tsize_t size = snprintf(nullptr, 0, format.c_str(), args ...) + 1;\t// Extra space for '\\0'\n\tstd::unique_ptr<char[]> buf(new char[size]); \n\tsnprintf(buf.get(), size, format.c_str(), args ...);\n\treturn std::string(buf.get(), buf.get() + size - 1);\t\t\t\t// We don't want the '\\0' inside\n}\n\n\n// ************************************************************************************\n//\n//\tvector construction functions\n//\n#pragma mark -\n#pragma mark Vector conversion functions\n#pragma mark -\n\n\n//\t(*)c(...)\nEidosValue_SP Eidos_ExecuteFunction_c(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tif (p_arguments.size() == 0)\n\t\tresult_SP = gStaticEidosValueNULL;\t// c() returns NULL, by definition\n\telse\n\t\tresult_SP = ConcatenateEidosValues(p_arguments, true, false);\t// allow NULL but not VOID\n\t\n\treturn result_SP;\n}\n\n//\t(float)float(integer$ length)\nEidosValue_SP Eidos_ExecuteFunction_float(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tint64_t element_count = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (element_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_float): function float() requires length to be greater than or equal to 0 (\" << element_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (element_count == 0)\n\t\treturn gStaticEidosValue_Float_ZeroVec;\n\t\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(element_count);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int64_t value_index = 0; value_index < element_count; ++value_index)\n\t\tfloat_result->set_float_no_check(0.0, value_index);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)integer(integer$ length, [integer$ fill1 = 0], [integer$ fill2 = 1], [Ni fill2Indices = NULL])\nEidosValue_SP Eidos_ExecuteFunction_integer(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tEidosValue *fill1_value = p_arguments[1].get();\n\tEidosValue *fill2_value = p_arguments[2].get();\n\tEidosValue *fill2Indices_value = p_arguments[3].get();\n\tint64_t element_count = length_value->IntAtIndex_NOCAST(0, nullptr);\n\tint64_t fill1 = fill1_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (element_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integer): function integer() requires length to be greater than or equal to 0 (\" << element_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (element_count == 0)\n\t\treturn gStaticEidosValue_Integer_ZeroVec;\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(element_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int64_t value_index = 0; value_index < element_count; ++value_index)\n\t\tint_result->set_int_no_check(fill1, value_index);\n\t\n\tif (fill2Indices_value->Type() == EidosValueType::kValueInt)\n\t{\n\t\tint64_t fill2 = fill2_value->IntAtIndex_NOCAST(0, nullptr);\n\t\tint64_t *result_data = int_result->data_mutable();\n\t\tint positions_count = fill2Indices_value->Count();\n\t\tconst int64_t *positions_data = fill2Indices_value->IntData();\n\t\t\n\t\tfor (int positions_index = 0; positions_index < positions_count; ++positions_index)\n\t\t{\n\t\t\tint64_t position = positions_data[positions_index];\n\t\t\t\n\t\t\tif ((position < 0) || (position >= element_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_integer): function integer() requires positions in fill2Indices to be between 0 and length - 1 (\" << position << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tresult_data[position] = fill2;\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(logical)logical(integer$ length)\nEidosValue_SP Eidos_ExecuteFunction_logical(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tint64_t element_count = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (element_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_logical): function logical() requires length to be greater than or equal to 0 (\" << element_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (element_count == 0)\n\t\treturn gStaticEidosValue_Logical_ZeroVec;\n\t\n\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(element_count);\n\tresult_SP = EidosValue_SP(logical_result);\n\t\n\tfor (int64_t value_index = 0; value_index < element_count; ++value_index)\n\t\tlogical_result->set_logical_no_check(false, value_index);\n\t\n\treturn result_SP;\n}\n\n//\t(object<Object>)object(void)\nEidosValue_SP Eidos_ExecuteFunction_object(__attribute__((unused)) const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = gStaticEidosValue_Object_ZeroVec;\n\t\n\treturn result_SP;\n}\n\n//\t(*)rep(* x, integer$ count)\nEidosValue_SP Eidos_ExecuteFunction_rep(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *count_value = p_arguments[1].get();\n\t\n\tint64_t rep_count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (rep_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rep): function rep() requires count to be greater than or equal to 0 (\" << rep_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\t// the return type depends on the type of the first argument, which will get replicated\n\tresult_SP = x_value->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int rep_idx = 0; rep_idx < rep_count; rep_idx++)\n\t\tfor (int value_idx = 0; value_idx < x_count; value_idx++)\n\t\t\tresult->PushValueFromIndexOfEidosValue(value_idx, *x_value, nullptr);\n\t\n\treturn result_SP;\n}\n\n//\t(*)repEach(* x, integer count)\nEidosValue_SP Eidos_ExecuteFunction_repEach(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue *count_value = p_arguments[1].get();\n\tint count_count = count_value->Count();\n\t\n\t// the return type depends on the type of the first argument, which will get replicated\n\tresult_SP = x_value->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\tif (count_count == 1)\n\t{\n\t\tint64_t rep_count = count_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (rep_count < 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_repEach): function repEach() requires count to be greater than or equal to 0 (\" << rep_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (int value_idx = 0; value_idx < x_count; value_idx++)\n\t\t\tfor (int rep_idx = 0; rep_idx < rep_count; rep_idx++)\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(value_idx, *x_value, nullptr);\n\t}\n\telse if (count_count == x_count)\n\t{\n\t\tfor (int value_idx = 0; value_idx < x_count; value_idx++)\n\t\t{\n\t\t\tint64_t rep_count = count_value->IntAtIndex_NOCAST(value_idx, nullptr);\n\t\t\t\n\t\t\tif (rep_count < 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_repEach): function repEach() requires all elements of count to be greater than or equal to 0 (\" << rep_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tfor (int rep_idx = 0; rep_idx < rep_count; rep_idx++)\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(value_idx, *x_value, nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_repEach): function repEach() requires that parameter count's size() either (1) be equal to 1, or (2) be equal to the size() of its first argument.\" << EidosTerminate(nullptr);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(*)sample(* x, integer$ size, [logical$ replace = F], [Nif weights = NULL])\nEidosValue_SP Eidos_ExecuteFunction_sample(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint64_t sample_size = p_arguments[1]->IntAtIndex_NOCAST(0, nullptr);\n\tbool replace = p_arguments[2]->LogicalAtIndex_NOCAST(0, nullptr);\n\tEidosValue *weights_value = p_arguments[3].get();\n\tint x_count = x_value->Count();\n\t\n\tif (sample_size < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires a sample size >= 0 (\" << sample_size << \" supplied).\" << EidosTerminate(nullptr);\n\tif (sample_size == 0)\n\t{\n\t\tresult_SP = x_value->NewMatchingType();\n\t\treturn result_SP;\n\t}\n\t\n\tif (x_count == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() provided with insufficient elements (0 supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (!replace && (x_count < sample_size))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() provided with insufficient elements (\" << x_count << \" supplied, \" << sample_size << \" needed).\" << EidosTerminate(nullptr);\n\t\n\t// decide whether to use weights, if weights were supplied\n\tEidosValueType weights_type = weights_value->Type();\n\tint weights_count = weights_value->Count();\n\t\n\tif (weights_type == EidosValueType::kValueNULL)\n\t{\n\t\tweights_value = nullptr;\n\t}\n\telse\n\t{\n\t\tif (weights_count != x_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires x and weights to be the same length.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif (weights_count == 1)\n\t\t{\n\t\t\tdouble weight = weights_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif ((weight < 0.0) || std::isnan(weight))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires all weights to be non-negative (\" << EidosStringForFloat(weight) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\tif (weight == 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// one weight, greater than zero; no need to use it, and this guarantees below that weights_value is non-singleton\n\t\t\tweights_value = nullptr;\n\t\t}\n\t}\n\t\n\t// if replace==F but we're only sampling one item, we might as well set replace=T, which chooses a simpler case below\n\t// at present this doesn't matter since sample_size == 1 is handled separately anyway, but it is a good inference to draw\n\tif (!replace && (sample_size == 1))\n\t\treplace = true;\n\t\n\t// full shuffle; optimized case for everything but std::string, which is difficult as usual\n\t// and is handled below, because gsl_ran_shuffle() can't move std::string safely\n\tif (!weights_value && !replace && (sample_size == x_count) && (sample_size != 1) && (x_type != EidosValueType::kValueString))\n\t{\n\t\tEidosRNG_32_bit &main_thread_rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\n\t\tresult_SP = x_value->CopyValues();\n\t\tEidosValue *result = result_SP.get();\n\t\t\n\t\tswitch (x_type)\n\t\t{\n\t\t\tcase EidosValueType::kValueVOID: break;\t\t\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\t\t\tcase EidosValueType::kValueNULL: break;\n\t\t\tcase EidosValueType::kValueLogical:\n\t\t\t\tEidos_ran_shuffle_uint32(main_thread_rng_32, result->LogicalData_Mutable(), x_count);\n\t\t\t\tbreak;\n\t\t\tcase EidosValueType::kValueInt:\n\t\t\t\tEidos_ran_shuffle_uint32(main_thread_rng_32, result->IntData_Mutable(), x_count);\n\t\t\t\tbreak;\n\t\t\tcase EidosValueType::kValueFloat:\n\t\t\t\tEidos_ran_shuffle_uint32(main_thread_rng_32, result->FloatData_Mutable(), x_count);\n\t\t\t\tbreak;\n\t\t\tcase EidosValueType::kValueObject:\n\t\t\t\tEidos_ran_shuffle_uint32(main_thread_rng_32, result->ObjectData_Mutable(), x_count);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): (internal error) unsupported type in sample()\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\treturn result_SP;\n\t}\n\t\n\t// several algorithms below use a buffer of indexes; we share that here as static locals\n\t// whenever sampling without replacement, we resize the buffer to the needed capacity here, too,\n\t// and initialize the buffer; all the code paths below use it in essentially the same way\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_ExecuteFunction_sample(): usage of statics\");\n\t\n\tstatic int *index_buffer = nullptr;\n\tstatic int buffer_capacity = 0;\n\tbool needs_index_buffer = !replace;\t\t// if we are sampling without replacement, we will need this buffer\n\t\n\tif (needs_index_buffer)\n\t{\n\t\tif (x_count > buffer_capacity)\n\t\t{\n\t\t\tbuffer_capacity = x_count * 2;\t\t// double whenever we go over capacity, to avoid reallocations\n\t\t\tif (index_buffer)\n\t\t\t\tfree(index_buffer);\n\t\t\tindex_buffer = (int *)malloc(buffer_capacity * sizeof(int));\t// no need to realloc, we don't need the old data\n\t\t\tif (!index_buffer)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_SAMPLE_INDEX);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_INDEX);\n#pragma omp parallel for schedule(static) default(none) shared(index_buffer, x_count) if(x_count > EIDOS_OMPMIN_SAMPLE_INDEX) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tindex_buffer[value_index] = value_index;\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_SAMPLE_INDEX);\n\t}\n\t\n\t// the algorithm used depends on whether weights were supplied\n\tif (weights_value)\n\t{\n\t\tif (replace && ((x_count > 100) || (sample_size > 100)) && (sample_size > 1))\n\t\t{\n\t\t\t// a large sampling task with replacement and weights goes through an optimized code path here\n\t\t\t// so that we can optimize the code more deeply for the type of x_value, and parallelize\n\t\t\t\n\t\t\t// first we check and prepare the weights vector as doubles, so the GSL can work with it\n\t\t\tconst double *weights_float = nullptr;\n\t\t\tdouble *weights_float_malloced = nullptr;\n\t\t\tdouble weights_sum = 0.0;\n\t\t\t\n\t\t\tif (weights_type == EidosValueType::kValueFloat)\n\t\t\t{\n\t\t\t\tweights_float = weights_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tdouble weight = weights_float[value_index];\n\t\t\t\t\t\n\t\t\t\t\tif ((weight < 0.0) || std::isnan(weight))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires all weights to be non-negative (\" << EidosStringForFloat(weight) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tweights_sum += weight;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\t// EidosValueType::kValueInt : convert the weights to doubles\n\t\t\t{\n\t\t\t\tconst int64_t *weights_int = weights_value->IntData();\n\t\t\t\t\n\t\t\t\tweights_float_malloced = (double *)malloc(x_count * sizeof(double));\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tint64_t weight = weights_int[value_index];\n\t\t\t\t\t\n\t\t\t\t\tif (weight < 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfree(weights_float_malloced);\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires all weights to be non-negative (\" << weight << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tweights_float_malloced[value_index] = weight;\n\t\t\t\t\tweights_sum += weight;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// weights_float_malloced will be freed below\n\t\t\t\tweights_float = weights_float_malloced;\n\t\t\t}\n\t\t\t\n\t\t\tif (weights_sum <= 0.0)\n\t\t\t{\n\t\t\t\tfree(weights_float_malloced);\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\t// prepare the GSL to draw from the discrete distribution\n\t\t\tgsl_ran_discrete_t *discrete_draw = gsl_ran_discrete_preproc(x_count, weights_float);\n\t\t\t\n\t\t\t// now treat each type separately\n\t\t\tif (x_type == EidosValueType::kValueInt)\n\t\t\t{\n\t\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(sample_size);\n\t\t\t\tint64_t *int_result_data = int_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_WR_INT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(discrete_draw, int_data, int_result_data) if(sample_size >= EIDOS_OMPMIN_SAMPLE_WR_INT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint rose_index = (int)gsl_ran_discrete(rng_gsl, discrete_draw);\n\t\t\t\t\t\t\n\t\t\t\t\t\tint_result_data[samples_generated] = int_data[rose_index];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t\t{\n\t\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(sample_size);\n\t\t\t\tdouble *float_result_data = float_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_WR_FLOAT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(discrete_draw, float_data, float_result_data) if(sample_size >= EIDOS_OMPMIN_SAMPLE_WR_FLOAT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint rose_index = (int)gsl_ran_discrete(rng_gsl, discrete_draw);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfloat_result_data[samples_generated] = float_data[rose_index];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t\t{\n\t\t\t\tEidosObject * const *object_data = x_value->ObjectData();\n\t\t\t\tconst EidosClass *object_class = ((EidosValue_Object *)x_value)->Class();\n\t\t\t\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(object_class))->resize_no_initialize(sample_size);\n\t\t\t\tEidosObject **object_result_data = object_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_WR_OBJECT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(discrete_draw, object_data, object_result_data) if(sample_size >= EIDOS_OMPMIN_SAMPLE_WR_OBJECT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint rose_index = (int)gsl_ran_discrete(rng_gsl, discrete_draw);\n\t\t\t\t\t\tEidosObject *object_element = object_data[rose_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tobject_result_data[samples_generated] = object_element;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (object_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\t// Retain all of the objects chosen; this is not done in parallel because it would require locks\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosObject *object_element = object_result_data[samples_generated];\n\t\t\t\t\t\tstatic_cast<EidosDictionaryRetained *>(object_element)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This handles the logical and string cases\n\t\t\t\tgsl_rng *main_thread_rng = EIDOS_GSL_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tint rose_index = (int)gsl_ran_discrete(main_thread_rng, discrete_draw);\n\t\t\t\t\t\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(rose_index, *x_value, nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tgsl_ran_discrete_free(discrete_draw);\n\t\t\t\n\t\t\tif (weights_float_malloced)\n\t\t\t\tfree(weights_float_malloced);\n\t\t}\n\t\t// handle the weights vector with separate cases for float and integer, so we can access it directly for speed\n\t\telse if (weights_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *weights_float = weights_value->FloatData();\n\t\t\tdouble weights_sum = 0.0;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble weight = weights_float[value_index];\n\t\t\t\t\n\t\t\t\tif ((weight < 0.0) || std::isnan(weight))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires all weights to be non-negative (\" << EidosStringForFloat(weight) << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tweights_sum += weight;\n\t\t\t}\n\t\t\t\n\t\t\tif (weights_sum <= 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (sample_size == 1)\n\t\t\t{\n\t\t\t\t// a sample size of 1 is very common; make it as fast as we can by getting a singleton EidosValue directly from x\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tdouble rose = Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum;\n\t\t\t\tdouble rose_sum = 0.0;\n\t\t\t\tint rose_index;\n\t\t\t\t\n\t\t\t\tfor (rose_index = 0; rose_index < x_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t{\n\t\t\t\t\trose_sum += weights_float[rose_index];\n\t\t\t\t\t\n\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn x_value->GetValueAtIndex(rose_index, nullptr);\n\t\t\t}\n\t\t\telse if (replace)\n\t\t\t{\n\t\t\t\t// with replacement, we can just do a series of independent draws\n\t\t\t\t// (note the large-task case is handled with the GSL above)\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tdouble rose = Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum;\n\t\t\t\t\tdouble rose_sum = 0.0;\n\t\t\t\t\tint rose_index;\n\t\t\t\t\t\n\t\t\t\t\tfor (rose_index = 0; rose_index < x_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t\t{\n\t\t\t\t\t\trose_sum += weights_float[rose_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(rose_index, *x_value, nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// without replacement, we remove each item after it is drawn, so brute force seems like the only way\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\t// do the sampling\n\t\t\t\tint64_t contender_count = x_count;\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tif (weights_sum <= 0.0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tdouble rose = Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum;\n\t\t\t\t\tdouble rose_sum = 0.0;\n\t\t\t\t\tint rose_index;\n\t\t\t\t\t\n\t\t\t\t\tfor (rose_index = 0; rose_index < contender_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t\t{\n\t\t\t\t\t\trose_sum += weights_float[index_buffer[rose_index]];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(index_buffer[rose_index], *x_value, nullptr);\n\t\t\t\t\t\n\t\t\t\t\t// remove the sampled index since replace==F; note this algorithm is terrible if we are sampling\n\t\t\t\t\t// a large number of elements without replacement, with weights, but that seems unlikely to me...\n\t\t\t\t\tweights_sum -= weights_float[index_buffer[rose_index]];\t// possible source of numerical error\n\t\t\t\t\tmemmove(index_buffer + rose_index, index_buffer + rose_index + 1, (contender_count - rose_index - 1) * sizeof(int));\n\t\t\t\t\t--contender_count;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (weights_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *weights_int = weights_value->IntData();\n\t\t\tint64_t weights_sum = 0;\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t weight = weights_int[value_index];\n\t\t\t\t\n\t\t\t\tif (weight < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() requires all weights to be non-negative (\" << weight << \" supplied).\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tweights_sum += weight;\n\t\t\t\t\n\t\t\t\tif (weights_sum < 0)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): overflow of integer sum of weights in function sample(); the weights used are too large.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tif (weights_sum <= 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (sample_size == 1)\n\t\t\t{\n\t\t\t\t// a sample size of 1 is very common; make it as fast as we can by getting a singleton EidosValue directly from x\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tint64_t rose = (int64_t)ceil(Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum);\n\t\t\t\tint64_t rose_sum = 0;\n\t\t\t\tint rose_index;\n\t\t\t\t\n\t\t\t\tfor (rose_index = 0; rose_index < x_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t{\n\t\t\t\t\trose_sum += weights_int[rose_index];\n\t\t\t\t\t\n\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn x_value->GetValueAtIndex(rose_index, nullptr);\n\t\t\t}\n\t\t\telse if (replace)\n\t\t\t{\n\t\t\t\t// with replacement, we can just do a series of independent draws\n\t\t\t\t// (note the large-task case is handled with the GSL above)\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tint64_t rose = (int64_t)ceil(Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum);\n\t\t\t\t\tint64_t rose_sum = 0;\n\t\t\t\t\tint rose_index;\n\t\t\t\t\t\n\t\t\t\t\tfor (rose_index = 0; rose_index < x_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t\t{\n\t\t\t\t\t\trose_sum += weights_int[rose_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(rose_index, *x_value, nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// without replacement, we remove each item after it is drawn, so brute force seems like the only way\n\t\t\t\tEidosRNG_64_bit &main_thread_rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\t// do the sampling\n\t\t\t\tint64_t contender_count = x_count;\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t{\n\t\t\t\t\tif (weights_sum <= 0)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): function sample() encountered weights summing to <= 0.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\n\t\t\t\t\tint64_t rose = (int64_t)ceil(Eidos_rng_uniform_doubleCO(main_thread_rng_64) * weights_sum);\n\t\t\t\t\tint64_t rose_sum = 0;\n\t\t\t\t\tint rose_index;\n\t\t\t\t\t\n\t\t\t\t\tfor (rose_index = 0; rose_index < contender_count - 1; ++rose_index)\t// -1 so roundoff gives the result to the last contender\n\t\t\t\t\t{\n\t\t\t\t\t\trose_sum += weights_int[index_buffer[rose_index]];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (rose <= rose_sum)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(index_buffer[rose_index], *x_value, nullptr);\n\t\t\t\t\t\n\t\t\t\t\t// remove the sampled index since replace==F; note this algorithm is terrible if we are sampling\n\t\t\t\t\t// a large number of elements without replacement, with weights, but that seems unlikely to me...\n\t\t\t\t\tweights_sum -= weights_int[index_buffer[rose_index]];\n\t\t\t\t\tmemmove(index_buffer + rose_index, index_buffer + rose_index + 1, (contender_count - rose_index - 1) * sizeof(int));\n\t\t\t\t\t--contender_count;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// CODE COVERAGE: This is dead code\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_sample): (internal error) weights vector must be type float or integer.\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// weights not supplied; use equal weights\n\t\tif (sample_size == 1)\n\t\t{\n\t\t\t// a sample size of 1 is very common; make it as fast as we can by getting a singleton EidosValue directly from x\n\t\t\tEidosRNG_32_bit &main_thread_rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\n\t\t\treturn x_value->GetValueAtIndex((int)Eidos_rng_interval_uint32(main_thread_rng_32, x_count), nullptr);\n\t\t}\n\t\telse if (replace)\n\t\t{\n\t\t\t// with replacement, we can just do a series of independent draws\n\t\t\tif (x_count == 1)\n\t\t\t{\n\t\t\t\t// If there is only one element to sample from, there is no need to draw elements\n\t\t\t\t// This case removes the possibility of x_value being singleton from the branches below\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue(0, *x_value, nullptr);\n\t\t\t}\n\t\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t\t{\n\t\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(sample_size);\n\t\t\t\tint64_t *int_result_data = int_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_R_INT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(int_data, int_result_data, x_count) if(sample_size >= EIDOS_OMPMIN_SAMPLE_R_INT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t sample = Eidos_rng_interval_uint32(rng_32, x_count);\n\t\t\t\t\t\tint_result_data[samples_generated] = int_data[sample];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t\t{\n\t\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(sample_size);\n\t\t\t\tdouble *float_result_data = float_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_R_FLOAT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(float_data, float_result_data, x_count) if(sample_size >= EIDOS_OMPMIN_SAMPLE_R_FLOAT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t sample = Eidos_rng_interval_uint32(rng_32, x_count);\n\t\t\t\t\t\tfloat_result_data[samples_generated] = float_data[sample];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t\t{\n\t\t\t\tEidosObject * const *object_data = x_value->ObjectData();\n\t\t\t\tconst EidosClass *object_class = ((EidosValue_Object *)x_value)->Class();\n\t\t\t\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(object_class))->resize_no_initialize(sample_size);\n\t\t\t\tEidosObject **object_result_data = object_result->data_mutable();\n\t\t\t\tresult_SP = EidosValue_SP(object_result);\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SAMPLE_R_OBJECT);\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, sample_size) firstprivate(object_data, object_result_data, x_count) if(sample_size >= EIDOS_OMPMIN_SAMPLE_R_OBJECT) num_threads(thread_count)\n\t\t\t\t{\n\t\t\t\t\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\t\t\n#pragma omp for schedule(static) nowait\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tint32_t sample = Eidos_rng_interval_uint32(rng_32, x_count);\n\t\t\t\t\t\tEidosObject *object_element = object_data[sample];\n\t\t\t\t\t\tobject_result_data[samples_generated] = object_element;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (object_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\t// Retain all of the objects chosen; this is not done in parallel because it would require locks\n\t\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosObject *object_element = object_result_data[samples_generated];\n\t\t\t\t\t\tstatic_cast<EidosDictionaryRetained *>(object_element)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This handles the logical and string cases\n\t\t\t\tEidosRNG_32_bit &main_thread_rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\t\n\t\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t\t\tresult->PushValueFromIndexOfEidosValue((int)Eidos_rng_interval_uint32(main_thread_rng_32, x_count), *x_value, nullptr);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// get indices of x; we sample from this vector and then look up the corresponding EidosValue element\n\t\t\t// this is generally faster than gsl_ran_choose(), which is O(n) in x_count with a large constant factor;\n\t\t\t// we are O(n+m) in x_count and sample_size, but our constant factor is much, much smaller, because\n\t\t\t// gsl_ran_choose() does a gsl_rng_uniform() call for every element in x_value()!  We only do one\n\t\t\t// Eidos_rng_uniform_int() call per element in sample_size, at the price of a separate index buffer\n\t\t\t// and a lack of re-entrancy and thread-safety.  This is a *lot* faster for sample_size << x_count.\n\t\t\tEidosRNG_32_bit &main_thread_rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n\t\t\tresult_SP = x_value->NewMatchingType();\n\t\t\tEidosValue *result = result_SP.get();\n\t\t\t\n\t\t\t// do the sampling; this is not parallelized because of contention over index_buffer removals\n\t\t\tint64_t contender_count = x_count;\n\t\t\t\n\t\t\tfor (int64_t samples_generated = 0; samples_generated < sample_size; ++samples_generated)\n\t\t\t{\n\t\t\t\tint rose_index = (int)Eidos_rng_interval_uint32(main_thread_rng_32, (uint32_t)contender_count);\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(index_buffer[rose_index], *x_value, nullptr);\n\t\t\t\tindex_buffer[rose_index] = index_buffer[--contender_count];\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(numeric)seq(numeric$ from, numeric$ to, [Nif$ by = NULL], [Ni$ length = NULL])\nEidosValue_SP Eidos_ExecuteFunction_seq(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *from_value = p_arguments[0].get();\n\tEidosValueType from_type = from_value->Type();\n\tEidosValue *to_value = p_arguments[1].get();\n\tEidosValueType to_type = to_value->Type();\n\tEidosValue *by_value = p_arguments[2].get();\n\tEidosValueType by_type = by_value->Type();\n\tEidosValue *length_value = p_arguments[3].get();\n\tEidosValueType length_type = length_value->Type();\n\t\n\tif ((from_type == EidosValueType::kValueFloat) && !std::isfinite(from_value->FloatAtIndex_NOCAST(0, nullptr)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires a finite value for the 'from' parameter.\" << EidosTerminate(nullptr);\n\tif ((to_type == EidosValueType::kValueFloat) && !std::isfinite(to_value->FloatAtIndex_NOCAST(0, nullptr)))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires a finite value for the 'to' parameter.\" << EidosTerminate(nullptr);\n\tif ((by_type != EidosValueType::kValueNULL) && (length_type != EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() may be supplied with either 'by' or 'length', but not both.\" << EidosTerminate(nullptr);\n\t\n\tif (length_type != EidosValueType::kValueNULL)\n\t{\n\t\t// A length value has been supplied, so we guarantee a vector of that length even if from==to\n\t\tint64_t length = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\n\t\tif (length <= 0)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires that length, if supplied, must be > 0.\" << EidosTerminate(nullptr);\n\t\tif (length > 10000000)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() cannot construct a sequence with more than 10000000 entries.\" << EidosTerminate(nullptr);\n\t\t\n\t\tif ((from_type == EidosValueType::kValueFloat) || (to_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\t// a float value was given, so we will generate a float sequence in all cases\n\t\t\tdouble first_value = from_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble second_value = to_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(length);\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tfor (int64_t seq_index = 0; seq_index < length; ++seq_index)\n\t\t\t{\n\t\t\t\tif (seq_index == 0)\n\t\t\t\t\tfloat_result->set_float_no_check(first_value, seq_index);\n\t\t\t\telse if (seq_index == length - 1)\n\t\t\t\t\tfloat_result->set_float_no_check(second_value, seq_index);\n\t\t\t\telse\n\t\t\t\t\tfloat_result->set_float_no_check(first_value + (second_value - first_value) * (seq_index / (double)(length - 1)), seq_index);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// int values were given, so whether we generate a float sequence or an int sequence depends on whether length divides evenly\n\t\t\tint64_t first_value = from_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t second_value = to_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (length == 1)\n\t\t\t{\n\t\t\t\t// If a sequence of length 1 is requested, generate a single integer at the start\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(first_value));\n\t\t\t}\n\t\t\telse if ((second_value - first_value) % (length - 1) == 0)\n\t\t\t{\n\t\t\t\t// length divides evenly, so generate an integer sequence\n\t\t\t\tint64_t by = (second_value - first_value) / (length - 1);\n\t\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(length);\n\t\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\t\n\t\t\t\tfor (int64_t seq_index = 0; seq_index < length; ++seq_index)\n\t\t\t\t\tint_result->set_int_no_check(first_value + by * seq_index, seq_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// length does not divide evenly, so generate a float sequence\n\t\t\t\tdouble by = (second_value - first_value) / (double)(length - 1);\n\t\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(length);\n\t\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\t\n\t\t\t\tfor (int64_t seq_index = 0; seq_index < length; ++seq_index)\n\t\t\t\t{\n\t\t\t\t\tif (seq_index == 0)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_value, seq_index);\n\t\t\t\t\telse if (seq_index == length - 1)\n\t\t\t\t\t\tfloat_result->set_float_no_check(second_value, seq_index);\n\t\t\t\t\telse\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_value + by * seq_index, seq_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Either a by value has been supplied, or we're using our default step\n\t\tif ((from_type == EidosValueType::kValueFloat) || (to_type == EidosValueType::kValueFloat) || (by_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\t// float return case\n\t\t\tdouble first_value = from_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble second_value = to_value->NumericAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble default_by = ((first_value < second_value) ? 1 : -1);\n\t\t\tdouble by = ((by_type != EidosValueType::kValueNULL) ? by_value->NumericAtIndex_NOCAST(0, nullptr) : default_by);\n\t\t\t\n\t\t\tif (by == 0.0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires by != 0.\" << EidosTerminate(nullptr);\n\t\t\tif (!std::isfinite(by))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires a finite value for the 'by' parameter.\" << EidosTerminate(nullptr);\n\t\t\tif (((first_value < second_value) && (by < 0)) || ((first_value > second_value) && (by > 0)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() by has incorrect sign.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->reserve(int(1 + ceil((second_value - first_value) / by)));\t// take a stab at a reserve size; might not be quite right, but no harm\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t\t\n\t\t\tif (by > 0)\n\t\t\t\tfor (double seq_value = first_value; seq_value <= second_value; seq_value += by)\n\t\t\t\t\tfloat_result->push_float(seq_value);\n\t\t\telse\n\t\t\t\tfor (double seq_value = first_value; seq_value >= second_value; seq_value += by)\n\t\t\t\t\tfloat_result->push_float(seq_value);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// int return case\n\t\t\tint64_t first_value = from_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t second_value = to_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t default_by = ((first_value < second_value) ? 1 : -1);\n\t\t\tint64_t by = ((by_type != EidosValueType::kValueNULL) ? by_value->IntAtIndex_NOCAST(0, nullptr) : default_by);\n\t\t\t\n\t\t\tif (by == 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() requires by != 0.\" << EidosTerminate(nullptr);\n\t\t\tif (((first_value < second_value) && (by < 0)) || ((first_value > second_value) && (by > 0)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seq): function seq() by has incorrect sign.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->reserve((int)(1 + (second_value - first_value) / by));\t\t// take a stab at a reserve size; might not be quite right, but no harm\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\t\n\t\t\tif (by > 0)\n\t\t\t\tfor (int64_t seq_value = first_value; seq_value <= second_value; seq_value += by)\n\t\t\t\t\tint_result->push_int(seq_value);\n\t\t\telse\n\t\t\t\tfor (int64_t seq_value = first_value; seq_value >= second_value; seq_value += by)\n\t\t\t\t\tint_result->push_int(seq_value);\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)seqAlong(* x)\nEidosValue_SP Eidos_ExecuteFunction_seqAlong(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t// That might seem like an odd policy, since the sequence doesn't match the reality of the value,\n\t// but it follows R's behavior, and it gives one sequence-element per value-element.\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tint x_count = x_value->Count();\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tint_result->set_int_no_check(value_index, value_index);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)seqLen(integer$ length)\nEidosValue_SP Eidos_ExecuteFunction_seqLen(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tint64_t length = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (length < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_seqLen): function seqLen() requires length to be greater than or equal to 0 (\" << length << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(length);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < length; ++value_index)\n\t\tint_result->set_int_no_check(value_index, value_index);\n\t\n\treturn result_SP;\n}\n\n//\t(string)string(integer$ length)\nEidosValue_SP Eidos_ExecuteFunction_string(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *length_value = p_arguments[0].get();\n\tint64_t element_count = length_value->IntAtIndex_NOCAST(0, nullptr);\n\t\n\tif (element_count < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_string): function string() requires length to be greater than or equal to 0 (\" << element_count << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif (element_count == 0)\n\t\treturn gStaticEidosValue_String_ZeroVec;\n\t\n\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve((int)element_count);\n\tresult_SP = EidosValue_SP(string_result);\n\t\n\tfor (int64_t value_index = element_count; value_index > 0; --value_index)\n\t\tstring_result->PushString(gEidosStr_empty_string);\n\t\n\treturn result_SP;\n}\n\n\n// ************************************************************************************\n//\n//\tvalue inspection/manipulation functions\n//\n#pragma mark -\n#pragma mark Value inspection/manipulation functions\n#pragma mark -\n\n\n//\t(logical$)all(logical x, ...)\nEidosValue_SP Eidos_ExecuteFunction_all(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = gStaticEidosValue_LogicalT;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\n\t\tif (arg_value->Type() != EidosValueType::kValueLogical)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_all): function all() requires that all arguments be of type logical.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint arg_count = arg_value->Count();\n\t\tconst eidos_logical_t *logical_data = arg_value->LogicalData();\n\t\t\n\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\tif (!logical_data[value_index])\n\t\t\t{\n\t\t\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t\t\t\tbreak;\n\t\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)allClose(float x, float y, [float$ rtol = 1.0e-05], [float$ atol = 1.0e-08], [logical$ equalNAN = F])\nEidosValue_SP Eidos_ExecuteFunction_allClose(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// BEWARE: This method shares code with Eidos_ExecuteFunction_isClose(); they should be changed in parallel.\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValue *rtol_value = p_arguments[2].get();\n\tEidosValue *atol_value = p_arguments[3].get();\n\tEidosValue *equalNAN_value = p_arguments[4].get();\n\tint x_count = x_value->Count();\n\tint y_count = y_value->Count();\n\t\n\t// rtol\n\tdouble rtol = rtol_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif (rtol < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_allClose): function allClose() requires rtol >= 0.0.\" << EidosTerminate(nullptr);\n\t\n\t// atol\n\tdouble atol = atol_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif (atol < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_allClose): function allClose() requires atol >= 0.0.\" << EidosTerminate(nullptr);\n\t\n\t// equalNAN\n\teidos_logical_t equalNAN = equalNAN_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((x_count == y_count) || (x_count == 1) || (y_count == 1))\n\t{\n\t\tconst double *x_data = x_value->FloatData();\n\t\tconst double *y_data = y_value->FloatData();\n\t\tconst double xv_singleton = (x_count == 1) ? x_data[0] : 0.0;\n\t\tconst double yv_singleton = (y_count == 1) ? y_data[0] : 0.0;\n\t\tint value_count = std::max(x_count, y_count);\n\t\t\n\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t{\n\t\t\tdouble xv = (x_count == 1) ? xv_singleton : x_data[value_index];\n\t\t\tdouble yv = (y_count == 1) ? yv_singleton : y_data[value_index];\n\t\t\t\n\t\t\tif (std::isfinite(xv) && std::isfinite(yv))\n\t\t\t{\n\t\t\t\tif (std::abs(xv - yv) <= atol + rtol * std::abs(yv))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (std::isinf(xv) && std::isinf(yv))\n\t\t\t{\n\t\t\t\tif (std::signbit(xv) == std::signbit(yv))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (std::isnan(xv) && std::isnan(yv))\n\t\t\t{\n\t\t\t\tif (equalNAN)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t}\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_allClose): function allClose() requires the lengths of x and y to be equal, or that either x or y is singleton.\" << EidosTerminate(nullptr);\n\t\n\treturn gStaticEidosValue_LogicalT;\n}\n\n//\t(logical$)any(logical x, ...)\nEidosValue_SP Eidos_ExecuteFunction_any(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tint argument_count = (int)p_arguments.size();\n\t\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tresult_SP = gStaticEidosValue_LogicalF;\n\t\n\tfor (int arg_index = 0; arg_index < argument_count; ++arg_index)\n\t{\n\t\tEidosValue *arg_value = p_arguments[arg_index].get();\n\t\t\n\t\tif (arg_value->Type() != EidosValueType::kValueLogical)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_any): function any() requires that all arguments be of type logical.\" << EidosTerminate(nullptr);\n\t\t\n\t\tint arg_count = arg_value->Count();\n\t\tconst eidos_logical_t *logical_data = arg_value->LogicalData();\n\t\t\n\t\tfor (int value_index = 0; value_index < arg_count; ++value_index)\n\t\t\tif (logical_data[value_index])\n\t\t\t{\n\t\t\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t\t\t\tbreak;\n\t\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(void)cat(* x, [string$ sep = \" \"], [logical$ error = F])\nEidosValue_SP Eidos_ExecuteFunction_cat(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// SYNCH WITH catn() BELOW!\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValueType x_type = x_value->Type();\n\tstd::string separator = p_arguments[1]->StringAtIndex_NOCAST(0, nullptr);\n\teidos_logical_t use_error_stream = p_arguments[2]->LogicalAtIndex_NOCAST(0, nullptr);\n\tstd::ostream &output_stream = (use_error_stream ? p_interpreter.ErrorOutputStream() : p_interpreter.ExecutionOutputStream());\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t{\n\t\tif (value_index > 0)\n\t\t\toutput_stream << separator;\n\t\t\n\t\tif (x_type == EidosValueType::kValueObject)\n\t\t\toutput_stream << *x_value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\telse\n\t\t\toutput_stream << x_value->StringAtIndex_CAST(value_index, nullptr);\n\t}\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(void)catn([* x = \"\"], [string$ sep = \" \"], [logical$ error = F])\nEidosValue_SP Eidos_ExecuteFunction_catn(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// SYNCH WITH cat() ABOVE!\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValueType x_type = x_value->Type();\n\tstd::string separator = p_arguments[1]->StringAtIndex_NOCAST(0, nullptr);\n\teidos_logical_t use_error_stream = p_arguments[2]->LogicalAtIndex_NOCAST(0, nullptr);\n\tstd::ostream &output_stream = (use_error_stream ? p_interpreter.ErrorOutputStream() : p_interpreter.ExecutionOutputStream());\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t{\n\t\tif (value_index > 0)\n\t\t\toutput_stream << separator;\n\t\t\n\t\tif (x_type == EidosValueType::kValueObject)\n\t\t\toutput_stream << *x_value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\telse\n\t\t\toutput_stream << x_value->StringAtIndex_CAST(value_index, nullptr);\n\t}\n\t\n\toutput_stream << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(string)format(string$ format, numeric x)\nEidosValue_SP Eidos_ExecuteFunction_format(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *format_value = p_arguments[0].get();\n\tstd::string format = format_value->StringAtIndex_NOCAST(0, nullptr);\n\tEidosValue *x_value = p_arguments[1].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\t// Check the format string for correct syntax.  We have to be pretty careful about what we pass on to C++, both\n\t// for robustness and for security.  We allow the standard flags (+- #0), an integer field width (but not *), and\n\t// an integer precision (but not *).  For integer x we allow %d %i %o %x %X, for float x we allow %f %F %e %E %g %G;\n\t// other conversion specifiers are not allowed.  We do not allow a length modifier; we supply the correct length\n\t// modifier ourselves, which is platform-dependent.  We allow the format to be embedded within a longer string,\n\t// as usual, for convenience, but only one % specifier may exist within the format string.\n\tint length = (int)format.length();\n\tint pos = 0;\n\tint conversion_specifier_pos = -1;\n\tchar conv_ch = ' ';\n\tbool flag_plus = false, flag_minus = false, flag_space = false, flag_pound = false, flag_zero = false;\n\t\n\twhile (pos < length)\n\t{\n\t\tif (format[pos] == '%')\n\t\t{\n\t\t\tif ((pos + 1 < length) && (format[pos + 1] == '%'))\n\t\t\t{\n\t\t\t\t// skip over %% escapes\n\t\t\t\tpos += 2;\n\t\t\t}\n\t\t\telse if (conversion_specifier_pos != -1)\n\t\t\t{\n\t\t\t\t// we already saw a format specifier\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); only one % escape is allowed.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// other uses of % must be the format specifier, which we now parse\n\t\t\t\t\n\t\t\t\t// skip the %\n\t\t\t\t++pos;\n\t\t\t\t\n\t\t\t\t// skip over the optional +- #0 flags\n\t\t\t\twhile (pos < length)\n\t\t\t\t{\n\t\t\t\t\tchar flag = format[pos];\n\t\t\t\t\t\n\t\t\t\t\tif (flag == '+')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (flag_plus)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); flag '+' specified more than once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tflag_plus = true;\n\t\t\t\t\t\t++pos;\t// skip the '+'\n\t\t\t\t\t}\n\t\t\t\t\telse if (flag == '-')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (flag_minus)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); flag '-' specified more than once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tflag_minus = true;\n\t\t\t\t\t\t++pos;\t// skip the '-'\n\t\t\t\t\t}\n\t\t\t\t\telse if (flag == ' ')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (flag_space)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); flag ' ' specified more than once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tflag_space = true;\n\t\t\t\t\t\t++pos;\t// skip the ' '\n\t\t\t\t\t}\n\t\t\t\t\telse if (flag == '#')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (flag_pound)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); flag '#' specified more than once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tflag_pound = true;\n\t\t\t\t\t\t++pos;\t// skip the '#'\n\t\t\t\t\t}\n\t\t\t\t\telse if (flag == '0')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (flag_zero)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); flag '0' specified more than once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tflag_zero = true;\n\t\t\t\t\t\t++pos;\t// skip the '0'\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// not a flag character, so we are done with our optional flags\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// skip over the optional field width; eat a [1-9] followed by any number of [0-9]\n\t\t\t\tif (pos < length)\n\t\t\t\t{\n\t\t\t\t\tchar fieldwidth_ch = format[pos];\n\t\t\t\t\t\n\t\t\t\t\tif ((fieldwidth_ch >= '1') && (fieldwidth_ch <= '9'))\n\t\t\t\t\t{\n\t\t\t\t\t\t// skip the leading digit\n\t\t\t\t\t\t++pos;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (pos < length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfieldwidth_ch = format[pos];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((fieldwidth_ch >= '0') && (fieldwidth_ch <= '9'))\n\t\t\t\t\t\t\t\t++pos;\t// skip the digit\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// skip the optional precision specifier, a '.' followed by an integer\n\t\t\t\tif ((pos < length) && (format[pos] == '.'))\n\t\t\t\t{\n\t\t\t\t\t// skip the leading '.'\n\t\t\t\t\t++pos;\n\t\t\t\t\t\n\t\t\t\t\twhile (pos < length)\n\t\t\t\t\t{\n\t\t\t\t\t\tchar precision_ch = format[pos];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((precision_ch >= '0') && (precision_ch <= '9'))\n\t\t\t\t\t\t\t++pos;\t// skip the digit\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// now eat the required conversion specifier\n\t\t\t\tif (pos < length)\n\t\t\t\t{\n\t\t\t\t\tconv_ch = format[pos];\n\t\t\t\t\t\n\t\t\t\t\tconversion_specifier_pos = pos;\n\t\t\t\t\t++pos;\n\t\t\t\t\t\n\t\t\t\t\tif ((conv_ch == 'd') || (conv_ch == 'i') || (conv_ch == 'o') || (conv_ch == 'x') || (conv_ch == 'X'))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (x_type != EidosValueType::kValueInt)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); conversion specifier '\" << conv_ch << \"' requires an argument of type integer.\" << EidosTerminate(nullptr);\n\t\t\t\t\t}\n\t\t\t\t\telse if ((conv_ch == 'f') || (conv_ch == 'F') || (conv_ch == 'e') || (conv_ch == 'E') || (conv_ch == 'g') || (conv_ch == 'G'))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (x_type != EidosValueType::kValueFloat)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); conversion specifier '\" << conv_ch << \"' requires an argument of type float.\" << EidosTerminate(nullptr);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); conversion specifier '\" << conv_ch << \"' not supported.\" << EidosTerminate(nullptr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); missing conversion specifier after '%'.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Skip over all other characters\n\t\t\t++pos;\n\t\t}\n\t}\n\t\n\t// Fix the format string to have the correct length modifier.  This is an issue only for integer; for float, the\n\t// default is double anyway so we're fine.  For integer, the correct format strings are defined by <cinttypes>:\n\t// PRId64, PRIi64, PRIo64, PRIx64, and PRIX64.\n\tif (x_type == EidosValueType::kValueInt)\n\t{\n\t\tstd::string new_conv_string;\n\t\t\n\t\tif (conv_ch == 'd')\n\t\t\tnew_conv_string = PRId64;\n\t\telse if (conv_ch == 'i')\n\t\t\tnew_conv_string = PRIi64;\n\t\telse if (conv_ch == 'o')\n\t\t\tnew_conv_string = PRIo64;\n\t\telse if (conv_ch == 'x')\n\t\t\tnew_conv_string = PRIx64;\n\t\telse if (conv_ch == 'X')\n\t\t\tnew_conv_string = PRIX64;\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): (internal error) bad format string in function format(); conversion specifier '\" << conv_ch << \"' not recognized.\" << EidosTerminate(nullptr);\t\t// CODE COVERAGE: This is dead code\n\t\t\n\t\tformat.replace(conversion_specifier_pos, 1, new_conv_string);\n\t}\n\t\n\t// Check for possibilities that produce undefined behavior according to the C++11 standard\n\tif (flag_pound && ((conv_ch == 'd') || (conv_ch == 'i')))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_format): bad format string in function format(); the flag '#' may not be used with the conversion specifier '\" << conv_ch << \"'.\" << EidosTerminate(nullptr);\n\t\n\tif (x_count == 1)\n\t{\n\t\t// singleton case\n\t\tstd::string result_string;\n\t\t\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t\tresult_string = EidosStringFormat(format, x_value->IntAtIndex_NOCAST(0, nullptr));\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t\tresult_string = EidosStringFormat(format, x_value->FloatAtIndex_NOCAST(0, nullptr));\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(result_string));\n\t}\n\telse\n\t{\n\t\t// non-singleton x vector, with a singleton format vector\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(EidosStringFormat(format, x_value->IntAtIndex_NOCAST(value_index, nullptr)));\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tstring_result->PushString(EidosStringFormat(format, x_value->FloatAtIndex_NOCAST(value_index, nullptr)));\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)identical(* x, * y, ...)\nEidosValue_SP Eidos_ExecuteFunction_identical(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\t// BCH 1/2/2026: extending this function to now accept additional arguments beyond y, but the logic is the\n\t// same.  All arguments must be identical to x for T to be returned, otherwise F is returned.\n\tfor (size_t value_index = 1; value_index < p_arguments.size(); ++value_index)\n\t{\n\t\tEidosValue *y_value = p_arguments[value_index].get();\n\t\t\n\t\tif (!IdenticalEidosValues(x_value, y_value))\n\t\t\treturn gStaticEidosValue_LogicalF;\n\t}\n\t\n\treturn gStaticEidosValue_LogicalT;\n}\n\n//\t(*)ifelse(logical test, * trueValues, * falseValues)\nEidosValue_SP Eidos_ExecuteFunction_ifelse(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *test_value = p_arguments[0].get();\n\tint test_count = test_value->Count();\n\tconst eidos_logical_t *logical_vec = test_value->LogicalData();\n\t\n\tEidosValue *trueValues_value = p_arguments[1].get();\n\tEidosValueType trueValues_type = trueValues_value->Type();\n\tint trueValues_count = trueValues_value->Count();\n\t\n\tEidosValue *falseValues_value = p_arguments[2].get();\n\tEidosValueType falseValues_type = falseValues_value->Type();\n\tint falseValues_count = falseValues_value->Count();\n\t\n\tif (trueValues_type != falseValues_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ifelse): function ifelse() requires arguments 2 and 3 to be the same type (\" << trueValues_type << \" and \" << falseValues_type << \" supplied).\" << EidosTerminate(nullptr);\n\t\n\tif ((trueValues_count == test_count) && (falseValues_count == test_count))\n\t{\n\t\t// All three are equal counts, so we can do the whole thing in parallel\n\t\tif (trueValues_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *true_vec = trueValues_value->LogicalData();\n\t\t\tconst eidos_logical_t *false_vec = falseValues_value->LogicalData();\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical_vec[value_index] ? true_vec[value_index] : false_vec[value_index], value_index);\n\t\t\t\n\t\t\tresult_SP = logical_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *true_data = trueValues_value->IntData();\n\t\t\tconst int64_t *false_data = falseValues_value->IntData();\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(logical_vec[value_index] ? true_data[value_index] : false_data[value_index], value_index);\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *true_data = trueValues_value->FloatData();\n\t\t\tconst double *false_data = falseValues_value->FloatData();\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(logical_vec[value_index] ? true_data[value_index] : false_data[value_index], value_index);\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *true_vec = trueValues_value->StringData();\n\t\t\tconst std::string *false_vec = falseValues_value->StringData();\n\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tstring_result->PushString(logical_vec[value_index] ? true_vec[value_index] : false_vec[value_index]);\n\t\t\t\n\t\t\tresult_SP = string_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tconst EidosClass *trueValues_class = ((EidosValue_Object *)trueValues_value)->Class();\n\t\t\tconst EidosClass *falseValues_class = ((EidosValue_Object *)falseValues_value)->Class();\n\t\t\t\n\t\t\tif (trueValues_class != falseValues_class)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ifelse): objects of different types cannot be mixed in function ifelse().\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosObject * const *true_vec = trueValues_value->ObjectData();\n\t\t\tEidosObject * const *false_vec = falseValues_value->ObjectData();\n\t\t\tEidosValue_Object_SP object_result_SP = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(trueValues_class));\n\t\t\tEidosValue_Object *object_result = object_result_SP->resize_no_initialize_RR(test_count);\n\t\t\t\n\t\t\tif (object_result->UsesRetainRelease())\n\t\t\t{\n\t\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_no_previous_RR(logical_vec[value_index] ? true_vec[value_index] : false_vec[value_index], value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_NORR(logical_vec[value_index] ? true_vec[value_index] : false_vec[value_index], value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = object_result_SP;\n\t\t}\n\t}\n\telse if ((trueValues_count == 1) && (falseValues_count == 1))\n\t{\n\t\t// trueValues and falseValues are both singletons, so we can prefetch both values\n\t\tif (trueValues_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\teidos_logical_t true_value = trueValues_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\teidos_logical_t false_value = falseValues_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tlogical_result->set_logical_no_check(logical_vec[value_index] ? true_value : false_value, value_index);\n\t\t\t\n\t\t\tresult_SP = logical_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t true_value = trueValues_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tint64_t false_value = falseValues_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(logical_vec[value_index] ? true_value : false_value, value_index);\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble true_value = trueValues_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble false_value = falseValues_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(logical_vec[value_index] ? true_value : false_value, value_index);\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &true_value = ((EidosValue_String *)trueValues_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &false_value = ((EidosValue_String *)falseValues_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(test_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\tstring_result->PushString(logical_vec[value_index] ? true_value : false_value);\n\t\t\t\n\t\t\tresult_SP = string_result_SP;\n\t\t}\n\t\telse if (trueValues_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tconst EidosClass *trueValues_class = ((EidosValue_Object *)trueValues_value)->Class();\n\t\t\tconst EidosClass *falseValues_class = ((EidosValue_Object *)falseValues_value)->Class();\n\t\t\t\n\t\t\tif (trueValues_class != falseValues_class)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ifelse): objects of different types cannot be mixed in function ifelse().\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosObject *true_value = trueValues_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject *false_value = falseValues_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosValue_Object_SP object_result_SP = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(trueValues_class));\n\t\t\tEidosValue_Object *object_result = object_result_SP->resize_no_initialize_RR(test_count);\n\t\t\t\n\t\t\tif (object_result->UsesRetainRelease())\n\t\t\t{\n\t\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_no_previous_RR(logical_vec[value_index] ? true_value : false_value, value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t\t\t\tobject_result->set_object_element_no_check_NORR(logical_vec[value_index] ? true_value : false_value, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = object_result_SP;\n\t\t}\n\t}\n\telse if ((trueValues_count == test_count) && (falseValues_count == 1))\n\t{\n\t\t// vector trueValues, singleton falseValues; I suspect this case is less common so I'm deferring optimization\n\t\tresult_SP = trueValues_value->NewMatchingType();\n\t\tEidosValue *result = result_SP.get();\n\t\t\n\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t{\n\t\t\tif (logical_vec[value_index])\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(value_index, *trueValues_value, nullptr);\n\t\t\telse\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(0, *falseValues_value, nullptr);\n\t\t}\n\t}\n\telse if ((trueValues_count == 1) && (falseValues_count == test_count))\n\t{\n\t\t// singleton trueValues, vector falseValues; I suspect this case is less common so I'm deferring optimization\n\t\tresult_SP = trueValues_value->NewMatchingType();\n\t\tEidosValue *result = result_SP.get();\n\t\t\n\t\tfor (int value_index = 0; value_index < test_count; ++value_index)\n\t\t{\n\t\t\tif (logical_vec[value_index])\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(0, *trueValues_value, nullptr);\n\t\t\telse\n\t\t\t\tresult->PushValueFromIndexOfEidosValue(value_index, *falseValues_value, nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_ifelse): function ifelse() requires that trueValues and falseValues each be either of length 1, or equal in length to test.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Dimensionality of the result always matches that of the test parameter; this is R's policy and it makes sense\n\tresult_SP->CopyDimensionsFromValue(test_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)isClose(float x, float y, [float$ rtol = 1.0e-05], [float$ atol = 1.0e-08], [logical$ equalNAN = F])\nEidosValue_SP Eidos_ExecuteFunction_isClose(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// BEWARE: This method shares code with Eidos_ExecuteFunction_allClose(); they should be changed in parallel.\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *y_value = p_arguments[1].get();\n\tEidosValue *rtol_value = p_arguments[2].get();\n\tEidosValue *atol_value = p_arguments[3].get();\n\tEidosValue *equalNAN_value = p_arguments[4].get();\n\tint x_count = x_value->Count();\n\tint y_count = y_value->Count();\n\t\n\t// rtol\n\tdouble rtol = rtol_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif (rtol < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_isClose): function isClose() requires rtol >= 0.0.\" << EidosTerminate(nullptr);\n\t\n\t// atol\n\tdouble atol = atol_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\n\tif (atol < 0.0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_isClose): function isClose() requires atol >= 0.0.\" << EidosTerminate(nullptr);\n\t\n\t// equalNAN\n\teidos_logical_t equalNAN = equalNAN_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\n\tif ((x_count == y_count) || (x_count == 1) || (y_count == 1))\n\t{\n\t\tif ((x_count == 1) && (y_count == 1))\n\t\t{\n\t\t\tdouble xv = x_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tdouble yv = y_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\t\n\t\t\tif (std::isfinite(xv) && std::isfinite(yv))\n\t\t\t{\n\t\t\t\t// if xv and yv are finite, they are \"close\" if absolute(xv - yv) <= (atol + rtol * absolute(yv))\n\t\t\t\t// note that this mirrors the behavior of the numpy function isclose(), which this is based upon;\n\t\t\t\t// it is documented at https://numpy.org/doc/stable/reference/generated/numpy.isclose.html.\n\t\t\t\t// Note that Python's built-in math.isclose() has a different criterion, and different defaults;\n\t\t\t\t// see https://docs.python.org/3/library/math.html#math.isclose.\n\t\t\t\tbool close = (std::abs(xv - yv) <= atol + rtol * std::abs(yv));\n\t\t\t\t\n\t\t\t\treturn (close ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// if xv and yv are infinite, they are \"close\" if and only if they have the same sign\n\t\t\t\tif (std::isinf(xv) && std::isinf(yv))\n\t\t\t\t\treturn ((std::signbit(xv) == std::signbit(yv)) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\t\n\t\t\t\t// if xv and yv are NAN, they are \"close\" if and only if the equalNAN flag is true\n\t\t\t\tif (std::isnan(xv) && std::isnan(yv))\n\t\t\t\t\treturn (equalNAN ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t\t\n\t\t\t\t// all other cases involving INF and/or NAN are not \"close\"\n\t\t\t\treturn gStaticEidosValue_LogicalF;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst double *x_data = x_value->FloatData();\n\t\t\tconst double *y_data = y_value->FloatData();\n\t\t\tconst double xv_singleton = (x_count == 1) ? x_data[0] : 0.0;\n\t\t\tconst double yv_singleton = (y_count == 1) ? y_data[0] : 0.0;\n\t\t\t\n\t\t\tint value_count = std::max(x_count, y_count);\n\t\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(value_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble xv = (x_count == 1) ? xv_singleton : x_data[value_index];\n\t\t\t\tdouble yv = (y_count == 1) ? yv_singleton : y_data[value_index];\n\t\t\t\tbool close;\n\t\t\t\t\n\t\t\t\tif (std::isfinite(xv) && std::isfinite(yv))\n\t\t\t\t\tclose = (std::abs(xv - yv) <= atol + rtol * std::abs(yv));\n\t\t\t\telse if (std::isinf(xv) && std::isinf(yv))\n\t\t\t\t\tclose = (std::signbit(xv) == std::signbit(yv));\n\t\t\t\telse if (std::isnan(xv) && std::isnan(yv))\n\t\t\t\t\tclose = equalNAN;\n\t\t\t\telse\n\t\t\t\t\tclose = false;\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(close, value_index);\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(logical_result);\n\t\t}\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_isClose): function isClose() requires the lengths of x and y to be equal, or that either x or y is singleton.\" << EidosTerminate(nullptr);\n}\n\n//\t(integer)match(* x, * table)\nEidosValue_SP Eidos_ExecuteFunction_match(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\tEidosValue *table_value = p_arguments[1].get();\n\tEidosValueType table_type = table_value->Type();\n\tint table_count = table_value->Count();\n\t\n\tif (x_type != table_type)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_match): function match() requires arguments x and table to be the same type.\" << EidosTerminate(nullptr);\n\t\n\tif (x_type == EidosValueType::kValueNULL)\n\t{\n\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t\treturn result_SP;\n\t}\n\t\n\tif ((x_count == 1) && (table_count == 1))\n\t{\n\t\t// Handle singleton matching separately, to allow the use of the fast vector API below\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(x_value->LogicalAtIndex_NOCAST(0, nullptr) == table_value->LogicalAtIndex_NOCAST(0, nullptr) ? 0 : -1));\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(x_value->IntAtIndex_NOCAST(0, nullptr) == table_value->IntAtIndex_NOCAST(0, nullptr) ? 0 : -1));\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble f0 = x_value->FloatAtIndex_NOCAST(0, nullptr), f1 = table_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(((std::isnan(f0) && std::isnan(f1)) || (f0 == f1)) ? 0 : -1));\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &s0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string &s1 = ((EidosValue_String *)table_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(s0 == s1 ? 0 : -1));\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(x_value->ObjectElementAtIndex_NOCAST(0, nullptr) == table_value->ObjectElementAtIndex_NOCAST(0, nullptr) ? 0 : -1));\n\t}\n\telse if (x_count == 1)\t// && (table_count != 1)\n\t{\n\t\tint table_index;\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\teidos_logical_t value0 = x_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\tconst eidos_logical_t *logical_data1 = table_value->LogicalData();\n\t\t\t\n\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\tif (value0 == logical_data1[table_index])\n\t\t\t\t{\n\t\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(table_index));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t value0 = x_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *int_data1 = table_value->IntData();\n\t\t\t\n\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\tif (value0 == int_data1[table_index])\n\t\t\t\t{\n\t\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(table_index));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble value0 = x_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *float_data1 = table_value->FloatData();\n\t\t\t\n\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t{\n\t\t\t\tdouble f1 = float_data1[table_index];\n\t\t\t\t\n\t\t\t\tif ((std::isnan(value0) && std::isnan(f1)) || (value0 == f1))\n\t\t\t\t{\n\t\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(table_index));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &value0 = ((EidosValue_String *)x_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string *string_vec1 = table_value->StringData();\n\t\t\t\n\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\tif (value0 == string_vec1[table_index])\n\t\t\t\t{\n\t\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(table_index));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\telse // if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *value0 = x_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject * const *objelement_vec1 = table_value->ObjectData();\n\t\t\t\n\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\tif (value0 == objelement_vec1[table_index])\n\t\t\t\t{\n\t\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(table_index));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t}\n\t\t\n\t\tif (table_index == table_count)\n\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(-1));\n\t}\n\telse if (table_count == 1)\t// && (x_count != 1)\n\t{\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\teidos_logical_t value1 = table_value->LogicalAtIndex_NOCAST(0, nullptr);\n\t\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(logical_data0[value_index] == value1 ? 0 : -1, value_index);\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tint64_t value1 = table_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(int_data0[value_index] == value1 ? 0 : -1, value_index);\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tdouble value1 = table_value->FloatAtIndex_NOCAST(0, nullptr);\n\t\t\tconst double *float_data0 = x_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble f0 = float_data0[value_index];\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(((std::isnan(f0) && std::isnan(value1)) || (f0 == value1)) ? 0 : -1, value_index);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string &value1 = ((EidosValue_String *)table_value)->StringRefAtIndex_NOCAST(0, nullptr);\n\t\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(string_vec0[value_index] == value1 ? 0 : -1, value_index);\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject *value1 = table_value->ObjectElementAtIndex_NOCAST(0, nullptr);\n\t\t\tEidosObject * const *objelement_vec0 = x_value->ObjectData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\tint_result->set_int_no_check(objelement_vec0[value_index] == value1 ? 0 : -1, value_index);\n\t\t}\n\t}\n\telse\t\t\t\t\t\t// ((x_count != 1) && (table_count != 1))\n\t{\n\t\t// We can use the fast vector API; we want match() to be very fast since it is a common bottleneck\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\tint64_t *int_result_data = int_result->data_mutable();\n\t\tresult_SP = EidosValue_SP(int_result);\n\t\t\n\t\tint table_index;\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical_data0 = x_value->LogicalData();\n\t\t\tconst eidos_logical_t *logical_data1 = table_value->LogicalData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\tif (logical_data0[value_index] == logical_data1[table_index])\n\t\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(table_index == table_count ? -1 : table_index, value_index);\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data0 = x_value->IntData();\n\t\t\tconst int64_t *int_data1 = table_value->IntData();\n\t\t\t\n\t\t\tif ((x_count >= 500) && (table_count >= 5))\t\t// a guess based on timing data; will be platform-dependent and dataset-dependent\n\t\t\t{\n\t\t\t\t// use a hash table to speed up lookups from O(N) to O(1)\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\t\t\trobin_hood::unordered_flat_map<int64_t, int64_t> fromValueToIndex;\n\t\t\t\t//typedef robin_hood::pair<int64_t, int64_t> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\t\t\tstd::unordered_map<int64_t, int64_t> fromValueToIndex;\n\t\t\t\t//typedef std::pair<int64_t, int64_t> MAP_PAIR;\n#endif\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tfromValueToIndex.emplace(int_data1[table_index], table_index);\t// does nothing if the key is already in the map\n\t\t\t\t} catch (...) {\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_match): (internal error) function match() encountered a raise from its internal hash table (kValueInt); please report this.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MATCH_INT);\n#pragma omp parallel for schedule(static) default(none) shared(x_count, fromValueToIndex) firstprivate(int_data0, int_result_data) if(x_count >= EIDOS_OMPMIN_MATCH_INT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tauto find_iter = fromValueToIndex.find(int_data0[value_index]);\n\t\t\t\t\tint64_t find_index = (find_iter == fromValueToIndex.end()) ? -1 : find_iter->second;\n\t\t\t\t\t\n\t\t\t\t\tint_result_data[value_index] = find_index;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// brute-force lookup, since the problem probably isn't big enough to merit building a hash table\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tif (int_data0[value_index] == int_data1[table_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(table_index == table_count ? -1 : table_index, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data0 = x_value->FloatData();\n\t\t\tconst double *float_data1 = table_value->FloatData();\n\t\t\t\n\t\t\tif ((x_count >= 500) && (table_count >= 5))\t\t// a guess based on timing data; will be platform-dependent and dataset-dependent\n\t\t\t{\n\t\t\t\t// use a hash table to speed up lookups from O(N) to O(1)\n\t\t\t\t// we have to use a custom comparator so that NAN==NAN is true, so that NAN gets matched correctly\n\t\t\t\tauto equal = [](const double& l, const double& r) { if (std::isnan(l) && std::isnan(r)) return true; return l == r; };\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\t\t\trobin_hood::unordered_flat_map<double, int64_t, robin_hood::hash<double>, decltype(equal)> fromValueToIndex(0, robin_hood::hash<double>{}, equal);\n\t\t\t\t//typedef robin_hood::pair<double, int64_t> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\t\t\tstd::unordered_map<double, int64_t, std::hash<double>, decltype(equal)> fromValueToIndex(0, std::hash<double>{}, equal);\n\t\t\t\t//typedef std::pair<double, int64_t> MAP_PAIR;\n#endif\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tfromValueToIndex.emplace(float_data1[table_index], table_index);\t// does nothing if the key is already in the map\n\t\t\t\t} catch (...) {\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_match): (internal error) function match() encountered a raise from its internal hash table (kValueFloat); please report this.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MATCH_FLOAT);\n#pragma omp parallel for schedule(static) default(none) shared(x_count, fromValueToIndex) firstprivate(float_data0, int_result_data) if(x_count >= EIDOS_OMPMIN_MATCH_FLOAT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tauto find_iter = fromValueToIndex.find(float_data0[value_index]);\n\t\t\t\t\tint64_t find_index = (find_iter == fromValueToIndex.end()) ? -1 : find_iter->second;\n\t\t\t\t\t\n\t\t\t\t\tint_result_data[value_index] = find_index;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// brute-force lookup, since the problem probably isn't big enough to merit building a hash table\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble f0 = float_data0[value_index], f1 = float_data1[table_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((std::isnan(f0) && std::isnan(f1)) || (f0 == f1))\t// need to make NAN match NAN\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(table_index == table_count ? -1 : table_index, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec0 = x_value->StringData();\n\t\t\tconst std::string *string_vec1 = table_value->StringData();\n\t\t\t\n\t\t\tif ((x_count >= 500) && (table_count >= 5))\t\t// a guess based on timing data; will be platform-dependent and dataset-dependent\n\t\t\t{\n\t\t\t\t// use a hash table to speed up lookups from O(N) to O(1)\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\t\t\trobin_hood::unordered_flat_map<std::string, int64_t> fromValueToIndex;\n\t\t\t\t//typedef robin_hood::pair<std::string, int64_t> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\t\t\tstd::unordered_map<std::string, int64_t> fromValueToIndex;\n\t\t\t\t//typedef std::pair<std::string, int64_t> MAP_PAIR;\n#endif\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tfromValueToIndex.emplace(string_vec1[table_index], table_index);\t// does nothing if the key is already in the map\n\t\t\t\t} catch (...) {\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_match): (internal error) function match() encountered a raise from its internal hash table (kValueString); please report this.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Note that if string_vec0 were firstprivate, OpenMP would copy the data, NOT the reference!!!\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MATCH_STRING);\n#pragma omp parallel for schedule(static) default(none) shared(x_count, fromValueToIndex, string_vec0) firstprivate(int_result_data) if(x_count >= EIDOS_OMPMIN_MATCH_STRING) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tauto find_iter = fromValueToIndex.find(string_vec0[value_index]);\n\t\t\t\t\tint64_t find_index = (find_iter == fromValueToIndex.end()) ? -1 : find_iter->second;\n\t\t\t\t\t\n\t\t\t\t\tint_result_data[value_index] = find_index;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// brute-force lookup, since the problem probably isn't big enough to merit building a hash table\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tif (string_vec0[value_index] == string_vec1[table_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(table_index == table_count ? -1 : table_index, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueObject)\n\t\t{\n\t\t\tEidosObject * const *objelement_vec0 = x_value->ObjectData();\n\t\t\tEidosObject * const *objelement_vec1 = table_value->ObjectData();\n\t\t\t\n\t\t\tif ((x_count >= 500) && (table_count >= 5))\t\t// a guess based on timing data; will be platform-dependent and dataset-dependent\n\t\t\t{\n\t\t\t\t// use a hash table to speed up lookups from O(N) to O(1)\n#if EIDOS_ROBIN_HOOD_HASHING\n\t\t\t\trobin_hood::unordered_flat_map<EidosObject *, int64_t> fromValueToIndex;\n\t\t\t\t//typedef robin_hood::pair<EidosObject *, int64_t> MAP_PAIR;\n#elif STD_UNORDERED_MAP_HASHING\n\t\t\t\tstd::unordered_map<EidosObject *, int64_t> fromValueToIndex;\n\t\t\t\t//typedef std::pair<EidosObject *, int64_t> MAP_PAIR;\n#endif\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tfromValueToIndex.emplace(objelement_vec1[table_index], table_index);\t// does nothing if the key is already in the map\n\t\t\t\t} catch (...) {\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_match): (internal error) function match() encountered a raise from its internal hash table (kValueObject); please report this.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_MATCH_OBJECT);\n#pragma omp parallel for schedule(static) default(none) shared(x_count, fromValueToIndex) firstprivate(objelement_vec0, int_result_data) if(x_count >= EIDOS_OMPMIN_MATCH_OBJECT) num_threads(thread_count)\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tauto find_iter = fromValueToIndex.find(objelement_vec0[value_index]);\n\t\t\t\t\tint64_t find_index = (find_iter == fromValueToIndex.end()) ? -1 : find_iter->second;\n\t\t\t\t\t\n\t\t\t\t\tint_result_data[value_index] = find_index;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// brute-force lookup, since the problem probably isn't big enough to merit building a hash table\n\t\t\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tfor (table_index = 0; table_index < table_count; ++table_index)\n\t\t\t\t\t\tif (objelement_vec0[value_index] == objelement_vec1[table_index])\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(table_index == table_count ? -1 : table_index, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer)order(+ x, [logical$ ascending = T])\nEidosValue_SP Eidos_ExecuteFunction_order(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 0)\n\t{\n\t\t// This handles all the zero-length cases by returning integer(0)\n\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t}\n\telse if (x_count == 1)\n\t{\n\t\t// This handles all the singleton cases by returning 0\n\t\tresult_SP = gStaticEidosValue_Integer0;\n\t}\n\telse\n\t{\n\t\t// Here we handle the vector cases, which can be done with direct access\n\t\tEidosValueType x_type = x_value->Type();\n\t\tbool ascending = p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr);\n\t\tstd::vector<int64_t> order;\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t\torder = EidosSortIndexes(x_value->LogicalData(), x_count, ascending);\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t\torder = EidosSortIndexes(x_value->IntData(), x_count, ascending);\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t\torder = EidosSortIndexes(x_value->FloatData(), x_count, ascending);\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t\torder = EidosSortIndexes(x_value->StringData(), x_count, ascending);\n\t\t\n\t\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int(order));\n\t\tresult_SP = EidosValue_SP(int_result);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string$)paste(..., [string$ sep = \" \"])\nEidosValue_SP Eidos_ExecuteFunction_paste(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// SYNCH WITH paste0() BELOW!\n\tsize_t argument_count = p_arguments.size();\n\tstd::string separator = p_arguments[argument_count - 1]->StringAtIndex_NOCAST(0, nullptr);\n\tstd::string result_string;\n\t\n\t// SLiM 3.5 breaks backward compatibility for paste() because the second argument, which would have been interpreted as \"sep=\"\n\t// before, now gets eaten by the ellipsis unless it is explicitly named.  Here we try to issue a useful warning about this,\n\t// for the strings that seem like the most likely to be used as separators.\n\tif ((argument_count == 3) && (separator == \" \") &&\n\t\t((p_arguments[1]->Type() == EidosValueType::kValueString) && (p_arguments[1]->Count() == 1)))\n\t{\n\t\tstd::string pseudosep = p_arguments[1]->StringAtIndex_NOCAST(0, nullptr);\t// perhaps intended as sep, and now sep=\" \" has been used as a default?\n\t\t\n\t\tif ((pseudosep == \"\") || (pseudosep == \" \") || (pseudosep == \"\\t\") || (pseudosep == \"\\n\") || (pseudosep == \",\") || (pseudosep == \", \") || (pseudosep == \" , \") || (pseudosep == \";\") || (pseudosep == \"; \") || (pseudosep == \" ; \"))\n\t\t{\n\t\t\tif (!gEidosSuppressWarnings)\n\t\t\t\tp_interpreter.ErrorOutputStream() << R\"V0G0N(#WARNING (Eidos_ExecuteFunction_paste): function paste() changed its semantics in Eidos 2.5 (SLiM 3.5).  The second argument here is no longer interpreted to be a separator string; if you want those semantics, use 'sep=' to name the second argument, as in 'paste(1:5, sep=\",\");'.  That is the way to regain backward compatibility.  If, on the other hand, you do not intend the second argument here to be a separator string, you can get rid of this warning by appending the second argument using the + operator instead.  For example, you would transform 'x = paste(1:5, \",\");' into 'x = paste(1:5) + \" ,\";'.  You can also use suppressWarnings() to avoid this warning message.)V0G0N\" << std::endl;\n\t\t}\n\t}\n\t\n\tfor (size_t argument_index = 0; argument_index < argument_count - 1; ++argument_index)\n\t{\n\t\tEidosValue *x_value = p_arguments[argument_index].get();\n\t\tint x_count = x_value->Count();\n\t\tEidosValueType x_type = x_value->Type();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tif (!((value_index == 0) && (argument_index == 0)))\n\t\t\t\tresult_string.append(separator);\n\t\t\t\n\t\t\tif (x_type == EidosValueType::kValueObject)\n\t\t\t{\n\t\t\t\tstd::ostringstream oss;\n\t\t\t\t\n\t\t\t\toss << *x_value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\t\t\t\n\t\t\t\tresult_string.append(oss.str());\n\t\t\t}\n\t\t\telse\n\t\t\t\tresult_string.append(x_value->StringAtIndex_CAST(value_index, nullptr));\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(result_string));\n}\n\n//\t(string$)paste0(...)\nEidosValue_SP Eidos_ExecuteFunction_paste0(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\t// SYNCH WITH paste() ABOVE!\n\tsize_t argument_count = p_arguments.size();\n\tstd::string result_string;\n\t\n\tfor (size_t argument_index = 0; argument_index < argument_count; ++argument_index)\n\t{\n\t\tEidosValue *x_value = p_arguments[argument_index].get();\n\t\tint x_count = x_value->Count();\n\t\tEidosValueType x_type = x_value->Type();\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t{\n\t\t\tif (x_type == EidosValueType::kValueObject)\n\t\t\t{\n\t\t\t\tstd::ostringstream oss;\n\t\t\t\t\n\t\t\t\toss << *x_value->ObjectElementAtIndex_NOCAST(value_index, nullptr);\n\t\t\t\t\n\t\t\t\tresult_string.append(oss.str());\n\t\t\t}\n\t\t\telse\n\t\t\t\tresult_string.append(x_value->StringAtIndex_CAST(value_index, nullptr));\n\t\t}\n\t}\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(result_string));\n}\n\n//\t(void)print(* x, [logical$ error = F])\nEidosValue_SP Eidos_ExecuteFunction_print(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\teidos_logical_t use_error_stream = p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr);\n\tstd::ostream &output_stream = (use_error_stream ? p_interpreter.ErrorOutputStream() : p_interpreter.ExecutionOutputStream());\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\toutput_stream << *x_value << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(integer)rank(numeric x, [string$ tiesMethod = \"average\"])\nEidosValue_SP Eidos_ExecuteFunction_rank(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValue *tiesMethod_value = p_arguments[1].get();\n\tint x_count = x_value->Count();\n\t\n\t// figure out how we will resolve ties\n\ttypedef enum {\n\t\tkTiesAverage,\t\t// produces a result of type float, unlike all the others\n\t\tkTiesFirst,\n\t\tkTiesLast,\n\t\tkTiesRandom,\t\t// not currently supported, but supported in R\n\t\tkTiesMax,\n\t\tkTiesMin\n\t} TiesMethod;\n\t\n\tstd::string tiesMethod_string = tiesMethod_value->StringAtIndex_NOCAST(0, nullptr);\n\tTiesMethod tiesMethod;\n\t\n\tif (tiesMethod_string == \"average\")\n\t\ttiesMethod = TiesMethod::kTiesAverage;\n\telse if (tiesMethod_string == \"first\")\n\t\ttiesMethod = TiesMethod::kTiesFirst;\n\telse if (tiesMethod_string == \"last\")\n\t\ttiesMethod = TiesMethod::kTiesLast;\n\telse if (tiesMethod_string == \"random\")\n\t\ttiesMethod = TiesMethod::kTiesRandom;\n\telse if (tiesMethod_string == \"max\")\n\t\ttiesMethod = TiesMethod::kTiesMax;\n\telse if (tiesMethod_string == \"min\")\n\t\ttiesMethod = TiesMethod::kTiesMin;\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rank): function rank() requires tiesMethod to be 'average', 'first', 'last', 'random', 'max', or 'min'.\" << EidosTerminate(nullptr);\n\t\n\tif (tiesMethod == TiesMethod::kTiesRandom)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_rank): tiesMethod == 'random' is not currently supported.\" << EidosTerminate(nullptr);\n\t\n\tif (x_count == 0)\n\t{\n\t\t// This handles all the zero-length cases by returning float(0) or integer(0)\n\t\tif (tiesMethod == TiesMethod::kTiesAverage)\n\t\t\tresult_SP = gStaticEidosValue_Float_ZeroVec;\n\t\telse\n\t\t\tresult_SP = gStaticEidosValue_Integer_ZeroVec;\n\t}\n\telse if (x_count == 1)\n\t{\n\t\t// This handles all the singleton cases by returning 1.0 or 1\n\t\tif (tiesMethod == TiesMethod::kTiesAverage)\n\t\t\tresult_SP = gStaticEidosValue_Float1;\n\t\telse\n\t\t\tresult_SP = gStaticEidosValue_Integer1;\n\t}\n\telse\n\t{\n\t\t// Here we handle the vector cases, which can be done with direct access\n\t\tEidosValue_Float *float_result = nullptr;\n\t\tEidosValue_Int *int_result = nullptr;\n\t\tEidosValueType x_type = x_value->Type();\n\t\t\n\t\tif (tiesMethod == TiesMethod::kTiesAverage)\n\t\t{\n\t\t\tfloat_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(float_result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\t\t\tresult_SP = EidosValue_SP(int_result);\n\t\t}\n\t\t\n\t\t// Handle integer and float; note that this is unrelated to the type of the result!\n\t\tif (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tstd::vector<std::pair<int64_t, size_t>> pairs;\n\t\t\t\n\t\t\t{\n\t\t\t\t// construct our vector of pairs: std::pair<original x value, index in x>\n\t\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int index = 0; index < x_count; ++index)\n\t\t\t\t\tpairs.emplace_back(int_data[index], index);\n\t\t\t\t\n\t\t\t\t// sort by the original x value; we use a stable sort if needed by the ties method\n\t\t\t\tif ((tiesMethod == TiesMethod::kTiesFirst) || (tiesMethod == TiesMethod::kTiesLast))\n\t\t\t\t\tstd::stable_sort(pairs.begin(), pairs.end(), [](const std::pair<int64_t, size_t> &l, const std::pair<int64_t, size_t> &r) { return l.first < r.first; });\n\t\t\t\telse\n\t\t\t\t\tstd::sort(pairs.begin(), pairs.end(), [](const std::pair<int64_t, size_t> &l, const std::pair<int64_t, size_t> &r) { return l.first < r.first; });\n\t\t\t}\n\t\t\t\n\t\t\t// handle shared ranks one at a time, starting with rank 1\n\t\t\tfor (int run_start = 0; run_start < x_count; )\n\t\t\t{\n\t\t\t\t// look for runs of equal x values, which get handled as a block\n\t\t\t\tint64_t run_value = pairs[run_start].first;\n\t\t\t\tint run_end;\n\t\t\t\t\n\t\t\t\tfor (run_end = run_start + 1; run_end < x_count; ++run_end)\n\t\t\t\t\tif (pairs[run_end].first != run_value)\n\t\t\t\t\t\tbreak;\n\t\t\t\trun_end--;\n\t\t\t\t\n\t\t\t\t// the run ranges from run_start to run_end\n\t\t\t\tswitch (tiesMethod)\n\t\t\t\t{\n\t\t\t\t\tcase TiesMethod::kTiesAverage:\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble rank = (run_end + run_start) / 2.0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tfloat_result->set_float_no_check((double)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesFirst:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)run_pos + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesLast:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)(run_end - (run_pos - run_start)) + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesRandom:\n\t\t\t\t\t{\n\t\t\t\t\t\t// not currently supported, errors out above\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesMax:\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t rank = run_end;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesMin:\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t rank = run_start;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// go to the next element to handle the next rank\n\t\t\t\trun_start = run_end + 1;\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tstd::vector<std::pair<double, size_t>> pairs;\n\t\t\t\n\t\t\t{\n\t\t\t\t// construct our vector of pairs: std::pair<original x value, index in x>\n\t\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int index = 0; index < x_count; ++index)\n\t\t\t\t\tpairs.emplace_back(float_data[index], index);\n\t\t\t\t\n\t\t\t\t// sort by the original x value; we use a stable sort if needed by the ties method\n\t\t\t\tif ((tiesMethod == TiesMethod::kTiesFirst) || (tiesMethod == TiesMethod::kTiesLast))\n\t\t\t\t\tstd::stable_sort(pairs.begin(), pairs.end(), [](const std::pair<double, size_t> &l, const std::pair<double, size_t> &r) { return l.first < r.first; });\n\t\t\t\telse\n\t\t\t\t\tstd::sort(pairs.begin(), pairs.end(), [](const std::pair<double, size_t> &l, const std::pair<double, size_t> &r) { return l.first < r.first; });\n\t\t\t}\n\t\t\t\n\t\t\t// handle shared ranks one at a time, starting with rank 1\n\t\t\tfor (int run_start = 0; run_start < x_count; )\n\t\t\t{\n\t\t\t\t// look for runs of equal x values, which get handled as a block\n\t\t\t\tdouble run_value = pairs[run_start].first;\n\t\t\t\tint run_end;\n\t\t\t\t\n\t\t\t\tfor (run_end = run_start + 1; run_end < x_count; ++run_end)\n\t\t\t\t\tif (pairs[run_end].first != run_value)\n\t\t\t\t\t\tbreak;\n\t\t\t\trun_end--;\n\t\t\t\t\n\t\t\t\t// the run ranges from run_start to run_end\n\t\t\t\tswitch (tiesMethod)\n\t\t\t\t{\n\t\t\t\t\tcase TiesMethod::kTiesAverage:\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble rank = (run_end + run_start) / 2.0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tfloat_result->set_float_no_check((double)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesFirst:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)run_pos + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesLast:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)(run_end - (run_pos - run_start)) + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesRandom:\n\t\t\t\t\t{\n\t\t\t\t\t\t// not currently supported, errors out above\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesMax:\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t rank = run_end;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase TiesMethod::kTiesMin:\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t rank = run_start;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int run_pos = run_start; run_pos <= run_end; ++run_pos)\n\t\t\t\t\t\t\tint_result->set_int_no_check((int64_t)rank + 1, pairs[run_pos].second);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// go to the next element to handle the next rank\n\t\t\t\trun_start = run_end + 1;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(*)rev(* x)\nEidosValue_SP Eidos_ExecuteFunction_rev(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tresult_SP = x_value->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int value_index = x_count - 1; value_index >= 0; --value_index)\n\t\tresult->PushValueFromIndexOfEidosValue(value_index, *x_value, nullptr);\n\t\n\treturn result_SP;\n}\n\n//\t(integer$)size(* x)\n//\t(integer$)length(* x)\nEidosValue_SP Eidos_ExecuteFunction_size_length(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(x_value->Count()));\n\t\n\treturn result_SP;\n}\n\n//\t(+)sort(+ x, [logical$ ascending = T])\nEidosValue_SP Eidos_ExecuteFunction_sort(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter __attribute__((unused)) &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tresult_SP = x_value->NewMatchingType();\n\tEidosValue *result = result_SP.get();\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tresult->PushValueFromIndexOfEidosValue(value_index, *x_value, nullptr);\n\t\n\tresult->Sort(p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr));\n\t\n\treturn result_SP;\n}\n\n//\t(object)sortBy(object x, string$ property, [logical$ ascending = T])\nEidosValue_SP Eidos_ExecuteFunction_sortBy(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosObject * const *x_data = x_value->ObjectData();\n\tEidosValue_Object *object_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Object(((EidosValue_Object *)x_value)->Class()))->resize_no_initialize_RR(x_count);\n\tresult_SP = EidosValue_SP(object_result);\n\t\n\tif (object_result->UsesRetainRelease())\n\t{\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tobject_result->set_object_element_no_check_no_previous_RR(x_data[value_index], value_index);\n\t}\n\telse\n\t{\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tobject_result->set_object_element_no_check_NORR(x_data[value_index], value_index);\n\t}\n\t\n\tobject_result->SortBy(p_arguments[1]->StringAtIndex_NOCAST(0, nullptr), p_arguments[2]->LogicalAtIndex_NOCAST(0, nullptr));\n\t\n\treturn result_SP;\n}\n\n//\t(void)str(* x, [logical$ error = F])\nEidosValue_SP Eidos_ExecuteFunction_str(const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\tEidosValue *x_value = p_arguments[0].get();\n\teidos_logical_t use_error_stream = p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr);\n\tstd::ostream &output_stream = (use_error_stream ? p_interpreter.ErrorOutputStream() : p_interpreter.ExecutionOutputStream());\n\t\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tx_value->PrintStructure(output_stream, 2);\n\toutput_stream << std::endl;\n\t\n\treturn gStaticEidosValueVOID;\n}\n\n//\t(integer)tabulate(integer bin, [Ni$ maxbin = NULL])\nEidosValue_SP Eidos_ExecuteFunction_tabulate(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *bin_value = p_arguments[0].get();\n\tint value_count = bin_value->Count();\t\t\t// the name \"bin_count\" is just too confusing\n\t\n\tEidosValue *maxbin_value = p_arguments[1].get();\n\tEidosValueType maxbin_type = maxbin_value->Type();\n\t\n\tconst int64_t *int_data = bin_value->IntData();\n\t\n\t// determine maxbin\n\tint64_t maxbin;\n\t\n\tif (maxbin_type == EidosValueType::kValueNULL)\n\t{\n\t\tmaxbin = 0;\t\t// note that if the parallel loop runs, this gets reinitialized to the most negative number!\n\t\t\n\t\tEIDOS_BENCHMARK_START(EidosBenchmarkType::k_TABULATE_MAXBIN);\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_TABULATE_MAXBIN);\n#pragma omp parallel for schedule(static) default(none) shared(value_count) firstprivate(int_data) reduction(max: maxbin) if(value_count >= EIDOS_OMPMIN_TABULATE_MAXBIN) num_threads(thread_count)\n\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t{\n\t\t\tint64_t value = int_data[value_index];\n\t\t\tif (value > maxbin)\n\t\t\t\tmaxbin = value;\n\t\t}\n\t\tEIDOS_BENCHMARK_END(EidosBenchmarkType::k_TABULATE_MAXBIN);\n\t}\n\telse\n\t{\n\t\tmaxbin = maxbin_value->IntAtIndex_NOCAST(0, nullptr);\n\t}\n\t\n\tif (maxbin < 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExecuteFunction_tabulate): function tabulate() requires maxbin to be greater than or equal to 0.\" << EidosTerminate(nullptr);\n\t\n\t// set up the result vector and zero it out\n\tint64_t num_bins = maxbin + 1;\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(num_bins);\n\tint64_t *result_data = int_result->data_mutable();\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int bin_index = 0; bin_index < num_bins; ++bin_index)\n\t\tresult_data[bin_index] = 0;\n\t\n\t// do the tabulation\n#ifdef _OPENMP\n\tif ((value_count > EIDOS_OMPMIN_TABULATE) && (gEidosNumThreads > 1))\n\t{\n\t\t// Our custom OpenMP implementation has some extra overhead that we want to avoid when running single-threaded\n\t\t// We make completely separate tallies in each thread, and then do a reduction at the end into result_data.\n\t\t// I tried some other approaches – per-thread locks, and atomic updates – and they were much slower.\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_TABULATE);\n#pragma omp parallel default(none) shared(value_count, num_bins) firstprivate(int_data, result_data) num_threads(thread_count) // if(EIDOS_OMPMIN_TABULATE) is above\n\t\t{\n\t\t\tint64_t *perthread_tallies = (int64_t *)calloc(num_bins, sizeof(int64_t));\n\t\t\t\n#pragma omp for schedule(dynamic, 1024) nowait\n\t\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t value = int_data[value_index];\n\t\t\t\t\n\t\t\t\tif ((value >= 0) && (value < num_bins))\n\t\t\t\t{\n\t\t\t\t\t// I tried using per-bin locks instead, but the locking overhead was huge.\n\t\t\t\t\tperthread_tallies[value]++;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n#pragma omp critical\n\t\t\t{\n\t\t\t\t// Given the nowait on the for loop above, there is some hope that the threads won't stack up too badly here\n\t\t\t\tfor (int bin_index = 0; bin_index < num_bins; ++bin_index)\n\t\t\t\t\tresult_data[bin_index] += perthread_tallies[bin_index];\n\t\t\t}\n\t\t\t\n\t\t\tfree(perthread_tallies);\n\t\t}\n\t}\n\telse\n#endif\n\t{\n\t\t// Non-parallel implementation\n\t\tfor (int value_index = 0; value_index < value_count; ++value_index)\n\t\t{\n\t\t\tint64_t value = int_data[value_index];\n\t\t\t\n\t\t\tif ((value >= 0) && (value <= maxbin))\n\t\t\t\tresult_data[value]++;\n\t\t}\n\t}\n\treturn result_SP;\n}\n\n//\t(*)unique(* x, [logical$ preserveOrder = T])\nEidosValue_SP Eidos_ExecuteFunction_unique(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\treturn UniqueEidosValue(p_arguments[0].get(), p_arguments[1]->LogicalAtIndex_NOCAST(0, nullptr));\n}\n\n//\t(integer)which(logical x)\nEidosValue_SP Eidos_ExecuteFunction_which(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\tEidosValue_Int *int_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tif (logical_data[value_index])\n\t\t\tint_result->push_int(value_index);\n\t\n\treturn result_SP;\n}\n\n//\t(integer$)whichMax(+ x)\nEidosValue_SP Eidos_ExecuteFunction_whichMax(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 0)\n\t{\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse\n\t{\n\t\tint first_index = 0;\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\t\teidos_logical_t max = logical_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\teidos_logical_t temp = logical_data[value_index];\n\t\t\t\tif (max < temp) { max = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\tint64_t max = int_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\tif (max < temp) { max = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\tdouble max = float_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble temp = float_data[value_index];\n\t\t\t\tif (max < temp) { max = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\tconst std::string *max = &string_vec[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &temp = string_vec[value_index];\n\t\t\t\tif (*max < temp) { max = &temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(first_index));\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(integer$)whichMin(+ x)\nEidosValue_SP Eidos_ExecuteFunction_whichMin(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\tint x_count = x_value->Count();\n\t\n\tif (x_count == 0)\n\t{\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse\n\t{\n\t\tint first_index = 0;\n\t\t\n\t\tif (x_type == EidosValueType::kValueLogical)\n\t\t{\n\t\t\tconst eidos_logical_t *logical_data = x_value->LogicalData();\n\t\t\teidos_logical_t min = logical_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\teidos_logical_t temp = logical_data[value_index];\n\t\t\t\tif (min > temp) { min = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *int_data = x_value->IntData();\n\t\t\tint64_t min = int_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tint64_t temp = int_data[value_index];\n\t\t\t\tif (min > temp) { min = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *float_data = x_value->FloatData();\n\t\t\tdouble min = float_data[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tdouble temp = float_data[value_index];\n\t\t\t\tif (min > temp) { min = temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\telse if (x_type == EidosValueType::kValueString)\n\t\t{\n\t\t\tconst std::string *string_vec = x_value->StringData();\n\t\t\tconst std::string *min = &string_vec[0];\n\t\t\t\n\t\t\tfor (int value_index = 1; value_index < x_count; ++value_index)\n\t\t\t{\n\t\t\t\tconst std::string &temp = string_vec[value_index];\n\t\t\t\tif (*min > temp) { min = &temp; first_index = value_index; }\n\t\t\t}\n\t\t}\n\t\t\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(first_index));\n\t}\n\t\n\treturn result_SP;\n}\n\n\n// ************************************************************************************\n//\n//\tvalue type testing/coercion functions\n//\n#pragma mark -\n#pragma mark Value type testing/coercion functions\n#pragma mark -\n\n\n//\t(float)asFloat(+ x)\nEidosValue_SP Eidos_ExecuteFunction_asFloat(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue_Float *float_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Float())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(float_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tfloat_result->set_float_no_check(x_value->FloatAtIndex_CAST(value_index, nullptr), value_index);\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(integer)asInteger(+ x)\nEidosValue_SP Eidos_ExecuteFunction_asInteger(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\tEidosValue_Int *int_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Int())->resize_no_initialize(x_count);\n\tresult_SP = EidosValue_SP(int_result);\n\t\n\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\tint_result->set_int_no_check(x_value->IntAtIndex_CAST(value_index, nullptr), value_index);\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(logical)asLogical(+ x)\nEidosValue_SP Eidos_ExecuteFunction_asLogical(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif ((x_count == 1) && (x_value->DimensionCount() == 1))\n\t{\n\t\t// Use the global constants, but only if we do not have to impose a dimensionality upon the value below\n\t\tresult_SP = (x_value->LogicalAtIndex_CAST(0, nullptr) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\telse\n\t{\n\t\tEidosValue_Logical *logical_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(x_count);\n\t\tresult_SP = EidosValue_SP(logical_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tlogical_result->set_logical_no_check(x_value->LogicalAtIndex_CAST(value_index, nullptr), value_index);\n\t\t\n\t\tresult_SP->CopyDimensionsFromValue(x_value);\n\t}\n\t\n\treturn result_SP;\n}\n\n//\t(string)asString(+ x)\nEidosValue_SP Eidos_ExecuteFunction_asString(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tint x_count = x_value->Count();\n\t\n\tif ((x_count == 0) && (x_value->Type() == EidosValueType::kValueNULL))\n\t{\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(gEidosStr_NULL));\n\t}\n\telse\n\t{\n\t\tEidosValue_String *string_result = (new (gEidosValuePool->AllocateChunk()) EidosValue_String())->Reserve(x_count);\n\t\tresult_SP = EidosValue_SP(string_result);\n\t\t\n\t\tfor (int value_index = 0; value_index < x_count; ++value_index)\n\t\t\tstring_result->PushString(x_value->StringAtIndex_CAST(value_index, nullptr));\n\t}\n\t\n\tresult_SP->CopyDimensionsFromValue(x_value);\n\t\n\treturn result_SP;\n}\n\n//\t(string$)elementType(* x)\nEidosValue_SP Eidos_ExecuteFunction_elementType(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(x_value->ElementType()));\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isFloat(* x)\nEidosValue_SP Eidos_ExecuteFunction_isFloat(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueFloat) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isInteger(* x)\nEidosValue_SP Eidos_ExecuteFunction_isInteger(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueInt) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isLogical(* x)\nEidosValue_SP Eidos_ExecuteFunction_isLogical(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueLogical) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isNULL(* x)\nEidosValue_SP Eidos_ExecuteFunction_isNULL(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueNULL) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isObject(* x)\nEidosValue_SP Eidos_ExecuteFunction_isObject(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueObject) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(logical$)isString(* x)\nEidosValue_SP Eidos_ExecuteFunction_isString(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\tEidosValueType x_type = x_value->Type();\n\t\n\tresult_SP = (x_type == EidosValueType::kValueString) ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF;\n\t\n\treturn result_SP;\n}\n\n//\t(string$)type(* x)\nEidosValue_SP Eidos_ExecuteFunction_type(const std::vector<EidosValue_SP> &p_arguments, __attribute__((unused)) EidosInterpreter &p_interpreter)\n{\n\t// Note that this function ignores matrix/array attributes, and always returns a vector, by design\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\tEidosValue *x_value = p_arguments[0].get();\n\t\n\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(StringForEidosValueType(x_value->Type())));\n\t\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_globals.cpp",
    "content": "//\n//  eidos_globals.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 6/28/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_globals.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_script.h\"\n#include \"eidos_value.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_object_pool.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_class_Object.h\"\n#include \"eidos_class_Dictionary.h\"\n#include \"eidos_class_DataFrame.h\"\n#include \"eidos_class_Image.h\"\n#include \"eidos_class_TestElement.h\"\n\n#include <stdlib.h>\n#include <execinfo.h>\n#include <cxxabi.h>\n#include <ctype.h>\n#include <stdexcept>\n#include <string>\n#include <unordered_map>\n#ifndef _WIN32\n#include <pwd.h> // used only by Eidos_ResolvedPath(), which is not used on Windows\n#endif\n#include <unistd.h>\n#include <algorithm>\n#include \"string.h\"\n#include <sys/types.h>\n#include <sys/time.h>\n#include <sys/resource.h>\n#include <limits>\n#include <cmath>\n#include <utility>\n#include <iomanip>\n#include <sys/param.h>\n#include <regex>\n\n// added for Eidos_mkstemps() and Eidos_TemporaryDirectoryExists()\n#include <sys/stat.h>\n#include <fstream>\n#include <fcntl.h>\n#include <errno.h>\n#include <stdio.h>\n#ifdef _WIN32\n#include <fileapi.h>\n#endif\n\n// for Eidos_WelchTTest()\n#include \"gsl_cdf.h\"\n\n// for Eidos_calc_sha_256()\n#include <stdint.h>\n\n// for _Eidos_FlushZipBuffer()\n#include \"../eidos_zlib/zlib.h\"\n\n// for Eidos_ColorPaletteLookup()\n#include \"eidos_tinycolormap.h\"\n\n//Replace some functions with their gnulib equivalents on Windows\n#ifdef _WIN32\n#define mkdir gnulib::mkdir\n#define gettimeofday gnulib::gettimeofday\n#endif\n\n#ifdef _OPENMP\n#include <stdlib.h>\n#endif\n\n\n// declared in eidos_openmp.h, set in Eidos_WarmUpOpenMP() when parallel\nint gEidosMaxThreads = 1;\nint gEidosNumThreads = 1;\nbool gEidosNumThreadsOverride = false;\n\n\n// Require 64-bit; apparently there are some issues on 32-bit, and nobody should be doing that anyway\nstatic_assert(sizeof(char *) == 8, \"SLiM must be built for 64-bit, not 32-bit.\");\n\n\nbool eidos_do_memory_checks = true;\n\nEidosSymbolTable *gEidosConstantsSymbolTable = nullptr;\n\nint gEidosFloatOutputPrecision = 6;\n\n#if DEBUG_POINTS_ENABLED\nint gEidosDebugIndent = 0;\n#endif\n\n// start our wall clock duration timer at launch; this is for Eidos_WallTimeSeconds().\nstd::chrono::steady_clock::time_point gEidos_WallTimeBegin = std::chrono::steady_clock::now();\n\n\n#pragma mark -\n#pragma mark Error tracking\n#pragma mark -\n\nvoid TranslateErrorContextToUserScript(__attribute__ ((unused)) const char *p_caller)\n{\n\t// This attempts to translate an error position from the current script out to the user script, so\n\t// the position of the error can be highlighted in the GUI.  If the current script is not derived\n\t// from the user script, this will fail, and we might try again in a more outer/enclosing script\n\t// level, later on in the unwinding of the stack due to the raise.\n\t\n\t// Note that gEidosErrorContext.currentScript is normally non-nullptr, but in the Eidos console,\n\t// lines are executed with gEidosErrorContext.currentScript being nullptr.  There is no \"script\",\n\t// there is only the code that was entered at the prompt, I guess.  Historical reasons, really.\n\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t// Debugging code for error-tracking\n\tstd::cout << \"=== TranslateErrorContextToUserScript() called from \" << p_caller << \":\" << std::endl;\n\tstd::cout << \"    gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 == \" << gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 << std::endl;\n\tstd::cout << \"    gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 == \" << gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 << std::endl;\n\tstd::cout << \"    gEidosErrorContext.currentScript == \" << gEidosErrorContext.currentScript << std::endl;\n\t\n\tif (gEidosErrorContext.currentScript)\n\t{\n\t\tEidosScript *currentScript = gEidosErrorContext.currentScript;\n\t\tEidosScript *userScript = currentScript->UserScript();\n\t\tEidosScript *errorScript = (userScript ? userScript : currentScript);\n\t\t\n\t\tstd::cout << \"    currentScript->UserScriptUTF16Offset() == \" << currentScript->UserScriptUTF16Offset() << std::endl;\n\t\tstd::cout << \"    currentScript->UserScriptCharOffset() == \" << currentScript->UserScriptCharOffset() << std::endl;\n\t\tstd::cout << \"    currentScript->String() == \" << currentScript->String().substr(0, 20) << \"...\" << std::endl;\n\t\tstd::cout << \"    currentScript->UserScript() == \" << userScript << std::endl;\n\t\t\n\t\tif (errorScript)\n\t\t{\n\t\t\tconst std::string &errorScriptString = errorScript->String();\n\t\t\tint32_t error_start_utf = gEidosErrorContext.errorPosition.characterStartOfErrorUTF16;\n\t\t\tint32_t error_end_utf = gEidosErrorContext.errorPosition.characterEndOfErrorUTF16;\n\t\t\tint32_t offset_to_user_script = (userScript ? currentScript->UserScriptUTF16Offset() : 0);\n\t\t\t\n\t\t\tif (offset_to_user_script == -1)\n\t\t\t\toffset_to_user_script = 0;\n\t\t\t\n\t\t\tint32_t user_error_pos = error_start_utf + offset_to_user_script;\n\t\t\tint32_t user_error_length = (error_end_utf - error_start_utf) + 1;\n\t\t\tstd::string errorSubstring = errorScriptString.substr(user_error_pos, user_error_length);\n\t\t\t\n\t\t\tstd::cout << \"    errorScript substring == \" << errorSubstring << std::endl;\n\t\t}\n\t}\n#endif\n\t\n\t// If the error is in a script derived from the user's script, translate the error up to the user's script.\n\t// Doing this here ensures that it takes effect for all the different downstream code paths, of which there\n\t// are many.  Note that there are two cases here.  If we have error info that indicates that we're running\n\t// in a derived script with a known offset in the user script, then we translate the error position up to\n\t// the user script.  If not, we're running in an unmoored script and the error position refers only to that\n\t// script; in that case, we leave the error information untouched, and user_script here is nullptr.\n\tif (gEidosErrorContext.currentScript)\n\t{\n\t\tEidosScript *user_script = gEidosErrorContext.currentScript->UserScript();\n\t\tint32_t utf_offset = gEidosErrorContext.currentScript->UserScriptUTF16Offset();\n\t\tint32_t char_offset = gEidosErrorContext.currentScript->UserScriptCharOffset();\n\t\t\n\t\tif ((utf_offset != -1) && (char_offset != -1) && (user_script != nullptr) && (user_script != gEidosErrorContext.currentScript))\n\t\t{\n\t\t\t// shift the error position to the user script coordinates\n\t\t\tgEidosErrorContext.errorPosition.characterStartOfErrorUTF16 += utf_offset;\n\t\t\tgEidosErrorContext.errorPosition.characterEndOfErrorUTF16 += utf_offset;\n\t\t\t\n\t\t\tgEidosErrorContext.errorPosition.characterStartOfError += char_offset;\n\t\t\tgEidosErrorContext.errorPosition.characterEndOfError += char_offset;\n\t\t\t\n\t\t\tgEidosErrorContext.currentScript = user_script;\n\t\t\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"    ==> translated error context to script \" << user_script << \" (UTF offset \" << utf_offset << \")\" << std::endl;\n\t\t\tstd::cout << \"        new gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 == \" << gEidosErrorContext.errorPosition.characterStartOfErrorUTF16 << std::endl;\n\t\t\tstd::cout << \"        new gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 == \" << gEidosErrorContext.errorPosition.characterEndOfErrorUTF16 << std::endl;\n\t\t\tstd::cout << \"        new gEidosErrorContext.currentScript == \" << gEidosErrorContext.currentScript << std::endl;\n\t\t\t\n\t\t\tif (user_script)\n\t\t\t{\n\t\t\t\tstd::cout << \"        new currentScript->UserScriptUTF16Offset() == \" << user_script->UserScriptUTF16Offset() << std::endl;\n\t\t\t\tstd::cout << \"        new currentScript->UserScriptCharOffset() == \" << user_script->UserScriptCharOffset() << std::endl;\n\t\t\t\tstd::cout << \"        new currentScript->String() == \" << user_script->String().substr(0, 20) << \"...\" << std::endl;\n\t\t\t\tstd::cout << \"        new currentScript->UserScript() == \" << user_script->UserScript() << std::endl;\n\t\t\t}\n#endif\n\t\t}\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\telse\n\t\t{\n\t\t\tstd::cout << \"    ==> did not translate error context\" << std::endl;\n\t\t}\n#endif\n\t}\n}\n\n#pragma mark -\n#pragma mark Profiling support\n#pragma mark -\n\n// Base support used by EidosBenchmark as well as profiling\n#if defined(MACH_PROFILING)\n\ndouble Eidos_ElapsedProfileTime(eidos_profile_t p_elapsed_profile_time)\n{\n\t// Eidos_ProfileTime() calls out to mach_absolute_time() at present.  It returns uint64_t, and the client would\n\t// then collect a start and end clock, subtract (end - start), and pass the result to this function to convert to\n\t// seconds as a double.  Interestingly, mach_absolute_time() uses CPU-specific units; we are close to the metal\n\t// here, which is why it is about twice as fast as other clock functions.  To convert a duration from CPU units,\n\t// we have to jump through a few hoops; see https://developer.apple.com/library/content/qa/qa1398/_index.html\n\t\n\t// If this is the first time we've run, get the timebase.  We can use denom == 0 to indicate that sTimebaseInfo\n\t// is uninitialised because it makes no sense to have a zero denominator in a fraction.\n\tstatic mach_timebase_info_data_t    sTimebaseInfo;\n\tstatic double timebaseRatio;\n\t\n\tif (sTimebaseInfo.denom == 0)\n\t{\n\t\t(void)mach_timebase_info(&sTimebaseInfo);\n\t\t\n\t\t// this ratio will convert from CPU time units to nanoseconds, AND from nanoseconds to seconds\n\t\ttimebaseRatio = (sTimebaseInfo.numer / (double)sTimebaseInfo.denom) / 1000000000.0;\n\t}\n\t\n\treturn p_elapsed_profile_time * timebaseRatio;\n}\n\n#elif defined(CHRONO_PROFILING)\n\ndouble Eidos_ElapsedProfileTime(eidos_profile_t p_elapsed_profile_time)\n{\n\t// Eidos_ProfileTime() provides time points in nanoseconds since epoch, and thus a duration is a duration in\n\t// nanoseconds.  We just need to convert from nanoseconds to seconds.\n\treturn p_elapsed_profile_time / 1000000000.0;\n}\n\n#endif\n\n\n// EidosBenchmark support\n\nEidosBenchmarkType gEidosBenchmarkType = EidosBenchmarkType::kNone;\neidos_profile_t gEidosBenchmarkAccumulator = 0;\n\n\n#if (SLIMPROFILING == 1)\n// PROFILING\n\nint gEidosProfilingClientCount = 0;\n\nuint64_t gEidos_ProfileCounter;\ndouble gEidos_ProfileOverheadTicks;\ndouble gEidos_ProfileOverheadSeconds;\ndouble gEidos_ProfileLagTicks;\ndouble gEidos_ProfileLagSeconds;\n\nstatic eidos_profile_t gEidos_ProfilePrep_Ticks;\n\nvoid Eidos_PrepareForProfiling(void)\n{\n\t// Prepare for profiling by measuring the overhead due to a profiling block itself\n\t// We will subtract out this overhead each time we use a profiling block, to compensate\n\tgEidos_ProfilePrep_Ticks = 0;\n\tgEidosProfilingClientCount++;\n\t\n\tgEidos_ProfileOverheadTicks = 0;\n\tgEidos_ProfileOverheadSeconds = 0;\n\t\n\tgEidos_ProfileLagTicks = 0;\n\tgEidos_ProfileLagSeconds = 0;\n\t\n\teidos_profile_t clock1 = Eidos_ProfileTime();\n\t\n\tfor (int i = 0; i < 1000000; ++i)\n\t{\n\t\t// Each iteration of this loop is meant to represent the overhead for one profiling block\n\t\t// Profiling blocks should all follow this structure for accuracy, even when it is overkill\n\t\tSLIM_PROFILE_BLOCK_START();\n\t\t\n\t\t;\t\t// a null statement, so the measured execution time of this block should be zero\n\t\t\n\t\tSLIM_PROFILE_BLOCK_END(gEidos_ProfilePrep_Ticks);\t\t// we use a global because real profile blocks will use a global\n\t}\n\t\n\teidos_profile_t clock2 = Eidos_ProfileTime();\n\t\n\tgEidosProfilingClientCount--;\n\t\n\teidos_profile_t profile_overhead_ticks = clock2 - clock1;\n\t\n\tgEidos_ProfileOverheadTicks = profile_overhead_ticks / 2000000.0;\t// two increments of the profile counter per block\n\tgEidos_ProfileOverheadSeconds = Eidos_ElapsedProfileTime(profile_overhead_ticks) / 2000000.0;\n\t\n\tgEidos_ProfileLagTicks = gEidos_ProfilePrep_Ticks / 1000000.0;\n\tgEidos_ProfileLagSeconds = Eidos_ElapsedProfileTime(gEidos_ProfilePrep_Ticks) / 1000000.0;\n\t\n\t//std::cout << \"Profile overhead external to block: \" << gEidos_ProfileOverhead_double << \" ticks, \" << gEidos_ProfileOverheadSeconds << \" seconds\" << std::endl;\n\t//std::cout << \"Profile lag internal to block: \" << gEidos_ProfileLag_double << \" ticks, \" << gEidos_ProfileLagSeconds << \" seconds\" << std::endl;\n}\n\n#endif\t// (SLIMPROFILING == 1)\n\n\n#pragma mark -\n#pragma mark Warm-up and command line processing\n#pragma mark -\n\nEidosValue_SP Eidos_ValueForCommandLineExpression(std::string &p_value_expression);\n\n\n#ifdef _OPENMP\n\n// Declarations for the number of threads we prefer to use for each parallel loop.\n// These default values are all EIDOS_OMP_MAX_THREADS, to use the maximum number\n// of threads in all cases.  This is primarily useful for benchmarking; normally\n// these default values get overwritten by _Eidos_SetOpenMPThreadCounts().\nint gEidos_OMP_threads_ABS_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_CEIL = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_EXP_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FLOOR = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_LOG_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_LOG10_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_LOG2_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_ROUND = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SQRT_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SUM_INTEGER = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SUM_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SUM_LOGICAL = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_TRUNC = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_MAX_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MAX_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MIN_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MIN_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMAX_INT_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMAX_INT_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMAX_FLOAT_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMAX_FLOAT_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMIN_INT_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMIN_INT_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMIN_FLOAT_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PMIN_FLOAT_2 = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_MATCH_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MATCH_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MATCH_STRING = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MATCH_OBJECT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_INDEX = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_R_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_R_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_R_OBJECT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_WR_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_WR_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_WR_OBJECT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_TABULATE_MAXBIN = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_TABULATE = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_CONTAINS_MARKER_MUT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_INDS_W_PEDIGREE_IDS = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RELATEDNESS = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_FITNESS_SCALE_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_FITNESS_SCALE_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_DNORM_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_DNORM_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RBINOM_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RBINOM_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RBINOM_3 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RDUNIF_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RDUNIF_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RDUNIF_3 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_REXP_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_REXP_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RNORM_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RNORM_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RNORM_3 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RPOIS_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RPOIS_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RUNIF_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RUNIF_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_RUNIF_3 = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_SORT_INT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SORT_FLOAT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SORT_STRING = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_POINT_IN_BOUNDS_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_IN_BOUNDS_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_IN_BOUNDS_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_PERIODIC_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_PERIODIC_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_PERIODIC_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_REFLECTED_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_REFLECTED_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_REFLECTED_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_STOPPED_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_STOPPED_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_STOPPED_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_UNIFORM_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_UNIFORM_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_POINT_UNIFORM_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_1_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_1_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_1_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_2_1D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_2_2D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SET_SPATIAL_POS_2_3D = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SPATIAL_MAP_VALUE = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_CLIPPEDINTEGRAL_1S = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_CLIPPEDINTEGRAL_2S = EIDOS_OMP_MAX_THREADS;\n//int gEidos_OMP_threads_CLIPPEDINTEGRAL_3S = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_DRAWBYSTRENGTH = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_INTNEIGHCOUNT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_LOCALPOPDENSITY = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_NEARESTINTNEIGH = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_NEARESTNEIGH = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_NEIGHCOUNT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_TOTNEIGHSTRENGTH = EIDOS_OMP_MAX_THREADS;\n\nint gEidos_OMP_threads_AGE_INCR = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_DEFERRED_REPRO = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_WF_REPRO = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_ASEX_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_ASEX_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_ASEX_3 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_SEX_1 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_SEX_2 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_FITNESS_SEX_3 = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_MIGRANT_CLEAR = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SIMPLIFY_SORT_PRE = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SIMPLIFY_SORT = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SIMPLIFY_SORT_POST = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_PARENTS_CLEAR = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_UNIQUE_MUTRUNS = EIDOS_OMP_MAX_THREADS;\nint gEidos_OMP_threads_SURVIVAL = EIDOS_OMP_MAX_THREADS;\n\nEidosPerTaskThreadCounts gEidosDefaultPerTaskThreadCounts = EidosPerTaskThreadCounts::kDefault;\nstd::string gEidosPerTaskThreadCountsSetName = \"DEFAULT\";\t// should get overwritten\nint gEidosPerTaskOriginalMaxThreadCount = EIDOS_OMP_MAX_THREADS;\nint gEidosPerTaskClippedMaxThreadCount = EIDOS_OMP_MAX_THREADS;\n\nvoid _Eidos_SetOpenMPThreadCounts(EidosPerTaskThreadCounts per_task_thread_counts)\n{\n\t// This switches to a set of per-task thread counts.  Ideally, these are determined using the\n\t// SLiM-Benchmarks repo on GitHub, on the actual machine where production runs will be done.\n\t// Where the scaling curve tops out for a given test, that determines the default number of\n\t// threads that should be used (since performance degrades beyond that point).  The values\n\t// here come from tests on specific hardware that I use; they may or may not correspond to\n\t// what provides good performance on the end user's hardware!\n\t\n\t// One question is what to put in when a task scales all the way up to the maximum number of\n\t// threads that was tested.  For example, if tests went to 16 threads and it scaled to 16,\n\t// do you put 16, or do you put EIDOS_OMP_MAX_THREADS figuring that if someone uses those\n\t// per-task maximum thread counts on a similar machine with even more cores, the task might\n\t// well continue to scale?  This is a guess; it's extrapolating beyond the data we have.\n\t// But I have chosen, for that example, to use 16, not EIDOS_OMP_MAX_THREADS.  The user can\n\t// always fix this if they want to; better to err on the side of caution and not scale up\n\t// to levels where performance might become atrocious.\n\t\n\tif (per_task_thread_counts == EidosPerTaskThreadCounts::kMaxThreads)\n\t{\n\t\t// These are all EIDOS_OMP_MAX_THREADS, as a template for modification\n\t\tgEidosPerTaskThreadCountsSetName = \"maxThreads\";\n\t\tgEidosPerTaskOriginalMaxThreadCount = EIDOS_OMP_MAX_THREADS;\n\t\tgEidosPerTaskClippedMaxThreadCount = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_ABS_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_CEIL = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_EXP_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FLOOR = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_LOG_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_LOG10_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_LOG2_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_ROUND = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SQRT_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SUM_INTEGER = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SUM_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SUM_LOGICAL = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_TRUNC = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_MAX_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MAX_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MIN_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MIN_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMAX_INT_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMAX_INT_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMIN_INT_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMIN_INT_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_2 = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_MATCH_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MATCH_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MATCH_STRING = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MATCH_OBJECT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_INDEX = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_R_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_R_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_R_OBJECT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_WR_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_WR_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_WR_OBJECT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_TABULATE_MAXBIN = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_TABULATE = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_CONTAINS_MARKER_MUT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_INDS_W_PEDIGREE_IDS = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RELATEDNESS = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_DNORM_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_DNORM_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RBINOM_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RBINOM_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RBINOM_3 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RDUNIF_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RDUNIF_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RDUNIF_3 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_REXP_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_REXP_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RNORM_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RNORM_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RNORM_3 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RPOIS_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RPOIS_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RUNIF_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RUNIF_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_RUNIF_3 = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_SORT_INT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SORT_FLOAT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SORT_STRING = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_STOPPED_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_STOPPED_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_STOPPED_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_1D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_2D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_3D = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SPATIAL_MAP_VALUE = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_1S = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_2S = EIDOS_OMP_MAX_THREADS;\n\t\t//gEidos_OMP_threads_CLIPPEDINTEGRAL_3S = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_DRAWBYSTRENGTH = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_INTNEIGHCOUNT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_LOCALPOPDENSITY = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_NEARESTINTNEIGH = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_NEARESTNEIGH = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_NEIGHCOUNT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_TOTNEIGHSTRENGTH = EIDOS_OMP_MAX_THREADS;\n\t\t\n\t\tgEidos_OMP_threads_AGE_INCR = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_DEFERRED_REPRO = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_WF_REPRO = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_3 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_SEX_1 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_SEX_2 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_FITNESS_SEX_3 = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_MIGRANT_CLEAR = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_PRE = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_POST = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_PARENTS_CLEAR = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_UNIQUE_MUTRUNS = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_SURVIVAL = EIDOS_OMP_MAX_THREADS;\n\t}\n\telse if (per_task_thread_counts == EidosPerTaskThreadCounts::kMacStudio2022_16)\n\t{\n\t\t// These counts are from a Mac Studio 2022 (Mac13,2), 20-core M1 Ultra, 128 GB\n\t\t// It has 20 cores: 16 performance cores and 4 efficiency cores\n\t\t// An effort was made with OMP_PLACES and OMP_PROC_BIND to stay on the perf cores,\n\t\t// but I don't know how to tell whether that effort was successful or not, so.\n\t\t// The raw data for these choices is presently in benchmarking/STUDIO 2023-08-07\n\t\tgEidosPerTaskThreadCountsSetName = \"MacStudio2022_16\";\n\t\tgEidosPerTaskOriginalMaxThreadCount = 16;\n\t\tgEidosPerTaskClippedMaxThreadCount = 16;\n\t\t\n\t\tgEidos_OMP_threads_ABS_FLOAT = 8;\n\t\tgEidos_OMP_threads_CEIL = 8;\n\t\tgEidos_OMP_threads_EXP_FLOAT = 16;\n\t\tgEidos_OMP_threads_FLOOR = 8;\n\t\tgEidos_OMP_threads_LOG_FLOAT = 16;\n\t\tgEidos_OMP_threads_LOG10_FLOAT = 16;\n\t\tgEidos_OMP_threads_LOG2_FLOAT = 16;\n\t\tgEidos_OMP_threads_ROUND = 8;\n\t\tgEidos_OMP_threads_SQRT_FLOAT = 8;\n\t\tgEidos_OMP_threads_SUM_INTEGER = 8;\n\t\tgEidos_OMP_threads_SUM_FLOAT = 8;\n\t\tgEidos_OMP_threads_SUM_LOGICAL = 8;\n\t\tgEidos_OMP_threads_TRUNC = 8;\n\t\t\n\t\tgEidos_OMP_threads_MAX_INT = 8;\n\t\tgEidos_OMP_threads_MAX_FLOAT = 16;\n\t\tgEidos_OMP_threads_MIN_INT = 8;\n\t\tgEidos_OMP_threads_MIN_FLOAT = 16;\n\t\tgEidos_OMP_threads_PMAX_INT_1 = 8;\n\t\tgEidos_OMP_threads_PMAX_INT_2 = 8;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_1 = 16;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_2 = 16;\n\t\tgEidos_OMP_threads_PMIN_INT_1 = 8;\n\t\tgEidos_OMP_threads_PMIN_INT_2 = 8;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_1 = 16;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_2 = 16;\n\t\t\n\t\tgEidos_OMP_threads_MATCH_INT = 16;\n\t\tgEidos_OMP_threads_MATCH_FLOAT = 16;\n\t\tgEidos_OMP_threads_MATCH_STRING = 16;\n\t\tgEidos_OMP_threads_MATCH_OBJECT = 16;\n\t\tgEidos_OMP_threads_SAMPLE_INDEX = 12;\n\t\tgEidos_OMP_threads_SAMPLE_R_INT = 16;\n\t\tgEidos_OMP_threads_SAMPLE_R_FLOAT = 16;\n\t\tgEidos_OMP_threads_SAMPLE_R_OBJECT = 16;\n\t\tgEidos_OMP_threads_SAMPLE_WR_INT = 12;\n\t\tgEidos_OMP_threads_SAMPLE_WR_FLOAT = 8;\n\t\tgEidos_OMP_threads_SAMPLE_WR_OBJECT = 16;\n\t\tgEidos_OMP_threads_TABULATE_MAXBIN = 8;\n\t\tgEidos_OMP_threads_TABULATE = 16;\n\t\t\n\t\tgEidos_OMP_threads_CONTAINS_MARKER_MUT = 16;\n\t\tgEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = 16;\n\t\tgEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = 16;\n\t\tgEidos_OMP_threads_INDS_W_PEDIGREE_IDS = 8;\n\t\tgEidos_OMP_threads_RELATEDNESS = 16;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = 12;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = 12;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_1 = 8;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_2 = 8;\n\t\tgEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = 16;\n\t\t\n\t\tgEidos_OMP_threads_DNORM_1 = 16;\n\t\tgEidos_OMP_threads_DNORM_2 = 16;\n\t\tgEidos_OMP_threads_RBINOM_1 = 16;\n\t\tgEidos_OMP_threads_RBINOM_2 = 16;\n\t\tgEidos_OMP_threads_RBINOM_3 = 16;\n\t\tgEidos_OMP_threads_RDUNIF_1 = 16;\n\t\tgEidos_OMP_threads_RDUNIF_2 = 16;\n\t\tgEidos_OMP_threads_RDUNIF_3 = 16;\n\t\tgEidos_OMP_threads_REXP_1 = 16;\n\t\tgEidos_OMP_threads_REXP_2 = 16;\n\t\tgEidos_OMP_threads_RNORM_1 = 16;\n\t\tgEidos_OMP_threads_RNORM_2 = 16;\n\t\tgEidos_OMP_threads_RNORM_3 = 16;\n\t\tgEidos_OMP_threads_RPOIS_1 = 16;\n\t\tgEidos_OMP_threads_RPOIS_2 = 16;\n\t\tgEidos_OMP_threads_RUNIF_1 = 16;\n\t\tgEidos_OMP_threads_RUNIF_2 = 16;\n\t\tgEidos_OMP_threads_RUNIF_3 = 16;\n\t\t\n\t\tgEidos_OMP_threads_SORT_INT = 16;\n\t\tgEidos_OMP_threads_SORT_FLOAT = 4;\n\t\tgEidos_OMP_threads_SORT_STRING = 16;\n\t\t\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_1D = 12;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_2D = 12;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_3D = 16;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_1D = 16;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_2D = 16;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_3D = 16;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_1D = 16;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_2D = 16;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_3D = 16;\n\t\tgEidos_OMP_threads_POINT_STOPPED_1D = 16;\n\t\tgEidos_OMP_threads_POINT_STOPPED_2D = 8;\n\t\tgEidos_OMP_threads_POINT_STOPPED_3D = 8;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_1D = 16;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_2D = 16;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_3D = 16;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_1D = 4;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_2D = 4;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_3D = 4;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_1D = 4;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_2D = 4;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_3D = 4;\n\t\tgEidos_OMP_threads_SPATIAL_MAP_VALUE = 16;\n\t\t\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_1S = 16;\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_2S = 16;\n\t\t//gEidos_OMP_threads_CLIPPEDINTEGRAL_3S = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_DRAWBYSTRENGTH = 16;\n\t\tgEidos_OMP_threads_INTNEIGHCOUNT = 16;\n\t\tgEidos_OMP_threads_LOCALPOPDENSITY = 16;\n\t\tgEidos_OMP_threads_NEARESTINTNEIGH = 16;\n\t\tgEidos_OMP_threads_NEARESTNEIGH = 16;\n\t\tgEidos_OMP_threads_NEIGHCOUNT = 16;\n\t\tgEidos_OMP_threads_TOTNEIGHSTRENGTH = 16;\n\t\t\n\t\tgEidos_OMP_threads_AGE_INCR = 4;\n\t\tgEidos_OMP_threads_DEFERRED_REPRO = 4;\n\t\tgEidos_OMP_threads_WF_REPRO = 4;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_1 = 8;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_2 = 8;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_3 = 2;\n\t\tgEidos_OMP_threads_FITNESS_SEX_1 = 8;\n\t\tgEidos_OMP_threads_FITNESS_SEX_2 = 8;\n\t\tgEidos_OMP_threads_FITNESS_SEX_3 = 2;\n\t\tgEidos_OMP_threads_MIGRANT_CLEAR = 4;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_PRE = 8;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT = 16;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_POST = 6;\n\t\tgEidos_OMP_threads_PARENTS_CLEAR = 16;\n\t\tgEidos_OMP_threads_UNIQUE_MUTRUNS = 16;\n\t\tgEidos_OMP_threads_SURVIVAL = 16;\n\t}\n\telse if (per_task_thread_counts == EidosPerTaskThreadCounts::kXeonGold2_40)\n\t{\n\t\t// These counts are from cbsulm21, a node in Cornell's BioHPC cluster\n\t\t// It has two 20-core (40-hyperthreaded) Intel Xeon Gold 6148 2.4GHz\n\t\t// That makes a total of 40 physical cores, 80 virtual cores\n\t\t// These tests went up to 40 cores, avoiding hyperthreading\n\t\t// The raw data for these choices is presently in benchmarking/BHPC 2023-08-07\n\t\t// These should be the defaults for production builds, on the\n\t\t// assumption that users will be on similar big HPC nodes\n\t\tgEidosPerTaskThreadCountsSetName = \"XeonGold2_40\";\n\t\tgEidosPerTaskOriginalMaxThreadCount = 40;\n\t\tgEidosPerTaskClippedMaxThreadCount = 40;\n\t\t\n\t\tgEidos_OMP_threads_ABS_FLOAT = 40;\n\t\tgEidos_OMP_threads_CEIL = 40;\n\t\tgEidos_OMP_threads_EXP_FLOAT = 40;\n\t\tgEidos_OMP_threads_FLOOR = 40;\n\t\tgEidos_OMP_threads_LOG_FLOAT = 40;\n\t\tgEidos_OMP_threads_LOG10_FLOAT = 40;\n\t\tgEidos_OMP_threads_LOG2_FLOAT = 40;\n\t\tgEidos_OMP_threads_ROUND = 40;\n\t\tgEidos_OMP_threads_SQRT_FLOAT = 40;\n\t\tgEidos_OMP_threads_SUM_INTEGER = 40;\n\t\tgEidos_OMP_threads_SUM_FLOAT = 40;\n\t\tgEidos_OMP_threads_SUM_LOGICAL = 40;\n\t\tgEidos_OMP_threads_TRUNC = 40;\n\t\t\n\t\tgEidos_OMP_threads_MAX_INT = 40;\n\t\tgEidos_OMP_threads_MAX_FLOAT = 40;\n\t\tgEidos_OMP_threads_MIN_INT = 40;\n\t\tgEidos_OMP_threads_MIN_FLOAT = 40;\n\t\tgEidos_OMP_threads_PMAX_INT_1 = 40;\n\t\tgEidos_OMP_threads_PMAX_INT_2 = 40;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_1 = 40;\n\t\tgEidos_OMP_threads_PMAX_FLOAT_2 = 40;\n\t\tgEidos_OMP_threads_PMIN_INT_1 = 40;\n\t\tgEidos_OMP_threads_PMIN_INT_2 = 40;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_1 = 40;\n\t\tgEidos_OMP_threads_PMIN_FLOAT_2 = 40;\n\t\t\n\t\tgEidos_OMP_threads_MATCH_INT = 40;\n\t\tgEidos_OMP_threads_MATCH_FLOAT = 40;\n\t\tgEidos_OMP_threads_MATCH_STRING = 40;\n\t\tgEidos_OMP_threads_MATCH_OBJECT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_INDEX = 40;\n\t\tgEidos_OMP_threads_SAMPLE_R_INT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_R_FLOAT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_R_OBJECT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_WR_INT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_WR_FLOAT = 40;\n\t\tgEidos_OMP_threads_SAMPLE_WR_OBJECT = 40;\n\t\tgEidos_OMP_threads_TABULATE_MAXBIN = 40;\n\t\tgEidos_OMP_threads_TABULATE = 20;\n\t\t\n\t\tgEidos_OMP_threads_CONTAINS_MARKER_MUT = 40;\n\t\tgEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = 40;\n\t\tgEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = 40;\n\t\tgEidos_OMP_threads_INDS_W_PEDIGREE_IDS = 5;\n\t\tgEidos_OMP_threads_RELATEDNESS = 40;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = 40;\n\t\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = 40;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_1 = 40;\n\t\tgEidos_OMP_threads_SET_FITNESS_SCALE_2 = 40;\n\t\tgEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = 40;\n\t\t\n\t\tgEidos_OMP_threads_DNORM_1 = 40;\n\t\tgEidos_OMP_threads_DNORM_2 = 40;\n\t\tgEidos_OMP_threads_RBINOM_1 = 10;\n\t\tgEidos_OMP_threads_RBINOM_2 = 40;\n\t\tgEidos_OMP_threads_RBINOM_3 = 40;\n\t\tgEidos_OMP_threads_RDUNIF_1 = 10;\n\t\tgEidos_OMP_threads_RDUNIF_2 = 10;\n\t\tgEidos_OMP_threads_RDUNIF_3 = 20;\n\t\tgEidos_OMP_threads_REXP_1 = 40;\n\t\tgEidos_OMP_threads_REXP_2 = 40;\n\t\tgEidos_OMP_threads_RNORM_1 = 40;\n\t\tgEidos_OMP_threads_RNORM_2 = 40;\n\t\tgEidos_OMP_threads_RNORM_3 = 40;\n\t\tgEidos_OMP_threads_RPOIS_1 = 40;\n\t\tgEidos_OMP_threads_RPOIS_2 = 40;\n\t\tgEidos_OMP_threads_RUNIF_1 = 40;\n\t\tgEidos_OMP_threads_RUNIF_2 = 40;\n\t\tgEidos_OMP_threads_RUNIF_3 = 40;\n\t\t\n\t\tgEidos_OMP_threads_SORT_INT = 10;\n\t\tgEidos_OMP_threads_SORT_FLOAT = 10;\n\t\tgEidos_OMP_threads_SORT_STRING = 10;\n\t\t\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_1D = 40;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_2D = 40;\n\t\tgEidos_OMP_threads_POINT_IN_BOUNDS_3D = 40;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_1D = 40;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_2D = 40;\n\t\tgEidos_OMP_threads_POINT_PERIODIC_3D = 40;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_1D = 40;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_2D = 40;\n\t\tgEidos_OMP_threads_POINT_REFLECTED_3D = 40;\n\t\tgEidos_OMP_threads_POINT_STOPPED_1D = 40;\n\t\tgEidos_OMP_threads_POINT_STOPPED_2D = 40;\n\t\tgEidos_OMP_threads_POINT_STOPPED_3D = 40;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_1D = 40;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_2D = 40;\n\t\tgEidos_OMP_threads_POINT_UNIFORM_3D = 40;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_1D = 5;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_2D = 20;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_1_3D = 20;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_1D = 10;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_2D = 20;\n\t\tgEidos_OMP_threads_SET_SPATIAL_POS_2_3D = 20;\n\t\tgEidos_OMP_threads_SPATIAL_MAP_VALUE = 40;\n\t\t\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_1S = 40;\n\t\tgEidos_OMP_threads_CLIPPEDINTEGRAL_2S = 40;\n\t\t//gEidos_OMP_threads_CLIPPEDINTEGRAL_3S = EIDOS_OMP_MAX_THREADS;\n\t\tgEidos_OMP_threads_DRAWBYSTRENGTH = 40;\n\t\tgEidos_OMP_threads_INTNEIGHCOUNT = 40;\n\t\tgEidos_OMP_threads_LOCALPOPDENSITY = 40;\n\t\tgEidos_OMP_threads_NEARESTINTNEIGH = 10;\n\t\tgEidos_OMP_threads_NEARESTNEIGH = 10;\n\t\tgEidos_OMP_threads_NEIGHCOUNT = 40;\n\t\tgEidos_OMP_threads_TOTNEIGHSTRENGTH = 40;\n\t\t\n\t\tgEidos_OMP_threads_AGE_INCR = 10;\n\t\tgEidos_OMP_threads_DEFERRED_REPRO = 5;\n\t\tgEidos_OMP_threads_WF_REPRO = 5;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_1 = 40;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_2 = 40;\n\t\tgEidos_OMP_threads_FITNESS_ASEX_3 = 5;\n\t\tgEidos_OMP_threads_FITNESS_SEX_1 = 40;\n\t\tgEidos_OMP_threads_FITNESS_SEX_2 = 40;\n\t\tgEidos_OMP_threads_FITNESS_SEX_3 = 5;\n\t\tgEidos_OMP_threads_MIGRANT_CLEAR = 20;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_PRE = 20;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT = 40;\n\t\tgEidos_OMP_threads_SIMPLIFY_SORT_POST = 40;\n\t\tgEidos_OMP_threads_PARENTS_CLEAR = 40;\n\t\tgEidos_OMP_threads_UNIQUE_MUTRUNS = 40;\n\t\tgEidos_OMP_threads_SURVIVAL = 40;\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (_Eidos_SetOpenMPThreadCounts): (internal error) unrecognized EidosPerTaskThreadCounts value.\" << EidosTerminate(nullptr);\n\t}\n\t\n\t// Always clip the above counts to gEidosMaxThreads\n\t_Eidos_ClipOpenMPThreadCounts();\n}\n\nvoid _Eidos_ChooseDefaultOpenMPThreadCounts()\n{\n#if USE_OMP_LIMITS\n\t\n\t// If we are supposed to use our built-in default OMP limits, set them for our task thread counts\n\t// Note that the default behavior here is nothing but a wild shot in the dark!\n#ifdef __APPLE__\n\t// On macOS, we use the results from my Mac Studio 2022 by default; note it maxes out at 16 threads\n\tgEidosDefaultPerTaskThreadCounts = EidosPerTaskThreadCounts::kMacStudio2022_16;\n#else\n\t// On other systems, we use the results from the Cornell BioHPC cluster machine I test on, with a max of 40 threads\n\tgEidosDefaultPerTaskThreadCounts = EidosPerTaskThreadCounts::kXeonGold2_40;\n#endif\n\t\n#else\n\t\n\t// Enforce gEidosMaxThreads for the thread count ivars that govern how many threads various loops will use\n\tgEidosDefaultPerTaskThreadCounts = EidosPerTaskThreadCounts::kMaxThreads;\n\t\n#endif\n\t\n\t_Eidos_SetOpenMPThreadCounts(gEidosDefaultPerTaskThreadCounts);\n}\n\nvoid _Eidos_ClipOpenMPThreadCounts(void)\n{\n\t// This clips all thread-count ivars to gEidosMaxThreads, so they can be used at runtime without checking\n\tgEidosPerTaskClippedMaxThreadCount = std::min(gEidosMaxThreads, gEidosPerTaskOriginalMaxThreadCount);\n\t\n\tgEidos_OMP_threads_ABS_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_ABS_FLOAT);\n\tgEidos_OMP_threads_CEIL = std::min(gEidosMaxThreads, gEidos_OMP_threads_CEIL);\n\tgEidos_OMP_threads_EXP_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_EXP_FLOAT);\n\tgEidos_OMP_threads_FLOOR = std::min(gEidosMaxThreads, gEidos_OMP_threads_FLOOR);\n\tgEidos_OMP_threads_LOG_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_LOG_FLOAT);\n\tgEidos_OMP_threads_LOG10_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_LOG10_FLOAT);\n\tgEidos_OMP_threads_LOG2_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_LOG2_FLOAT);\n\tgEidos_OMP_threads_ROUND = std::min(gEidosMaxThreads, gEidos_OMP_threads_ROUND);\n\tgEidos_OMP_threads_SQRT_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SQRT_FLOAT);\n\tgEidos_OMP_threads_SUM_INTEGER = std::min(gEidosMaxThreads, gEidos_OMP_threads_SUM_INTEGER);\n\tgEidos_OMP_threads_SUM_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SUM_FLOAT);\n\tgEidos_OMP_threads_SUM_LOGICAL = std::min(gEidosMaxThreads, gEidos_OMP_threads_SUM_LOGICAL);\n\tgEidos_OMP_threads_TRUNC = std::min(gEidosMaxThreads, gEidos_OMP_threads_TRUNC);\n\n\tgEidos_OMP_threads_MAX_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MAX_INT);\n\tgEidos_OMP_threads_MAX_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MAX_FLOAT);\n\tgEidos_OMP_threads_MIN_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MIN_INT);\n\tgEidos_OMP_threads_MIN_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MIN_FLOAT);\n\tgEidos_OMP_threads_PMAX_INT_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMAX_INT_1);\n\tgEidos_OMP_threads_PMAX_INT_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMAX_INT_2);\n\tgEidos_OMP_threads_PMAX_FLOAT_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMAX_FLOAT_1);\n\tgEidos_OMP_threads_PMAX_FLOAT_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMAX_FLOAT_2);\n\tgEidos_OMP_threads_PMIN_INT_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMIN_INT_1);\n\tgEidos_OMP_threads_PMIN_INT_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMIN_INT_2);\n\tgEidos_OMP_threads_PMIN_FLOAT_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMIN_FLOAT_1);\n\tgEidos_OMP_threads_PMIN_FLOAT_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_PMIN_FLOAT_2);\n\n\tgEidos_OMP_threads_MATCH_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MATCH_INT);\n\tgEidos_OMP_threads_MATCH_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MATCH_FLOAT);\n\tgEidos_OMP_threads_MATCH_STRING = std::min(gEidosMaxThreads, gEidos_OMP_threads_MATCH_STRING);\n\tgEidos_OMP_threads_MATCH_OBJECT = std::min(gEidosMaxThreads, gEidos_OMP_threads_MATCH_OBJECT);\n\tgEidos_OMP_threads_SAMPLE_INDEX = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_INDEX);\n\tgEidos_OMP_threads_SAMPLE_R_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_R_INT);\n\tgEidos_OMP_threads_SAMPLE_R_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_R_FLOAT);\n\tgEidos_OMP_threads_SAMPLE_R_OBJECT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_R_OBJECT);\n\tgEidos_OMP_threads_SAMPLE_WR_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_WR_INT);\n\tgEidos_OMP_threads_SAMPLE_WR_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_WR_FLOAT);\n\tgEidos_OMP_threads_SAMPLE_WR_OBJECT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_WR_OBJECT);\n\tgEidos_OMP_threads_TABULATE_MAXBIN = std::min(gEidosMaxThreads, gEidos_OMP_threads_TABULATE_MAXBIN);\n\tgEidos_OMP_threads_TABULATE = std::min(gEidosMaxThreads, gEidos_OMP_threads_TABULATE);\n\n\tgEidos_OMP_threads_CONTAINS_MARKER_MUT = std::min(gEidosMaxThreads, gEidos_OMP_threads_CONTAINS_MARKER_MUT);\n\tgEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE = std::min(gEidosMaxThreads, gEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE);\n\tgEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE = std::min(gEidosMaxThreads, gEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE);\n\tgEidos_OMP_threads_INDS_W_PEDIGREE_IDS = std::min(gEidosMaxThreads, gEidos_OMP_threads_INDS_W_PEDIGREE_IDS);\n\tgEidos_OMP_threads_RELATEDNESS = std::min(gEidosMaxThreads, gEidos_OMP_threads_RELATEDNESS);\n\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_INDIVIDUALS_1);\n\tgEidos_OMP_threads_SAMPLE_INDIVIDUALS_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_SAMPLE_INDIVIDUALS_2);\n\tgEidos_OMP_threads_SET_FITNESS_SCALE_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_FITNESS_SCALE_1);\n\tgEidos_OMP_threads_SET_FITNESS_SCALE_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_FITNESS_SCALE_2);\n\tgEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE = std::min(gEidosMaxThreads, gEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE);\n\n\tgEidos_OMP_threads_DNORM_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_DNORM_1);\n\tgEidos_OMP_threads_DNORM_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_DNORM_2);\n\tgEidos_OMP_threads_RBINOM_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RBINOM_1);\n\tgEidos_OMP_threads_RBINOM_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RBINOM_2);\n\tgEidos_OMP_threads_RBINOM_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RBINOM_3);\n\tgEidos_OMP_threads_RDUNIF_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RDUNIF_1);\n\tgEidos_OMP_threads_RDUNIF_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RDUNIF_2);\n\tgEidos_OMP_threads_RDUNIF_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RDUNIF_3);\n\tgEidos_OMP_threads_REXP_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_REXP_1);\n\tgEidos_OMP_threads_REXP_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_REXP_2);\n\tgEidos_OMP_threads_RNORM_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RNORM_1);\n\tgEidos_OMP_threads_RNORM_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RNORM_2);\n\tgEidos_OMP_threads_RNORM_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RNORM_3);\n\tgEidos_OMP_threads_RPOIS_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RPOIS_1);\n\tgEidos_OMP_threads_RPOIS_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RPOIS_2);\n\tgEidos_OMP_threads_RUNIF_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RUNIF_1);\n\tgEidos_OMP_threads_RUNIF_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RUNIF_2);\n\tgEidos_OMP_threads_RUNIF_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_RUNIF_3);\n\n\tgEidos_OMP_threads_SORT_INT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SORT_INT);\n\tgEidos_OMP_threads_SORT_FLOAT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SORT_FLOAT);\n\tgEidos_OMP_threads_SORT_STRING = std::min(gEidosMaxThreads, gEidos_OMP_threads_SORT_STRING);\n\t\n\tgEidos_OMP_threads_POINT_IN_BOUNDS_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_IN_BOUNDS_1D);\n\tgEidos_OMP_threads_POINT_IN_BOUNDS_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_IN_BOUNDS_2D);\n\tgEidos_OMP_threads_POINT_IN_BOUNDS_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_IN_BOUNDS_3D);\n\tgEidos_OMP_threads_POINT_PERIODIC_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_PERIODIC_1D);\n\tgEidos_OMP_threads_POINT_PERIODIC_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_PERIODIC_2D);\n\tgEidos_OMP_threads_POINT_PERIODIC_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_PERIODIC_3D);\n\tgEidos_OMP_threads_POINT_REFLECTED_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_REFLECTED_1D);\n\tgEidos_OMP_threads_POINT_REFLECTED_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_REFLECTED_2D);\n\tgEidos_OMP_threads_POINT_REFLECTED_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_REFLECTED_3D);\n\tgEidos_OMP_threads_POINT_STOPPED_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_STOPPED_1D);\n\tgEidos_OMP_threads_POINT_STOPPED_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_STOPPED_2D);\n\tgEidos_OMP_threads_POINT_STOPPED_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_STOPPED_3D);\n\tgEidos_OMP_threads_POINT_UNIFORM_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_UNIFORM_1D);\n\tgEidos_OMP_threads_POINT_UNIFORM_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_UNIFORM_2D);\n\tgEidos_OMP_threads_POINT_UNIFORM_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_POINT_UNIFORM_3D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_1_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_1_1D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_1_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_1_2D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_1_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_1_3D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_2_1D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_2_1D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_2_2D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_2_2D);\n\tgEidos_OMP_threads_SET_SPATIAL_POS_2_3D = std::min(gEidosMaxThreads, gEidos_OMP_threads_SET_SPATIAL_POS_2_3D);\n\tgEidos_OMP_threads_SPATIAL_MAP_VALUE = std::min(gEidosMaxThreads, gEidos_OMP_threads_SPATIAL_MAP_VALUE);\n\n\tgEidos_OMP_threads_CLIPPEDINTEGRAL_1S = std::min(gEidosMaxThreads, gEidos_OMP_threads_CLIPPEDINTEGRAL_1S);\n\tgEidos_OMP_threads_CLIPPEDINTEGRAL_2S = std::min(gEidosMaxThreads, gEidos_OMP_threads_CLIPPEDINTEGRAL_2S);\n\t//gEidos_OMP_threads_CLIPPEDINTEGRAL_3S = std::min(gEidosMaxThreads, gEidos_OMP_threads_CLIPPEDINTEGRAL_3S);\n\tgEidos_OMP_threads_DRAWBYSTRENGTH = std::min(gEidosMaxThreads, gEidos_OMP_threads_DRAWBYSTRENGTH);\n\tgEidos_OMP_threads_INTNEIGHCOUNT = std::min(gEidosMaxThreads, gEidos_OMP_threads_INTNEIGHCOUNT);\n\tgEidos_OMP_threads_LOCALPOPDENSITY = std::min(gEidosMaxThreads, gEidos_OMP_threads_LOCALPOPDENSITY);\n\tgEidos_OMP_threads_NEARESTINTNEIGH = std::min(gEidosMaxThreads, gEidos_OMP_threads_NEARESTINTNEIGH);\n\tgEidos_OMP_threads_NEARESTNEIGH = std::min(gEidosMaxThreads, gEidos_OMP_threads_NEARESTNEIGH);\n\tgEidos_OMP_threads_NEIGHCOUNT = std::min(gEidosMaxThreads, gEidos_OMP_threads_NEIGHCOUNT);\n\tgEidos_OMP_threads_TOTNEIGHSTRENGTH = std::min(gEidosMaxThreads, gEidos_OMP_threads_TOTNEIGHSTRENGTH);\n\n\tgEidos_OMP_threads_AGE_INCR = std::min(gEidosMaxThreads, gEidos_OMP_threads_AGE_INCR);\n\tgEidos_OMP_threads_DEFERRED_REPRO = std::min(gEidosMaxThreads, gEidos_OMP_threads_DEFERRED_REPRO);\n\tgEidos_OMP_threads_WF_REPRO = std::min(gEidosMaxThreads, gEidos_OMP_threads_WF_REPRO);\n\tgEidos_OMP_threads_FITNESS_ASEX_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_ASEX_1);\n\tgEidos_OMP_threads_FITNESS_ASEX_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_ASEX_2);\n\tgEidos_OMP_threads_FITNESS_ASEX_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_ASEX_3);\n\tgEidos_OMP_threads_FITNESS_SEX_1 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_SEX_1);\n\tgEidos_OMP_threads_FITNESS_SEX_2 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_SEX_2);\n\tgEidos_OMP_threads_FITNESS_SEX_3 = std::min(gEidosMaxThreads, gEidos_OMP_threads_FITNESS_SEX_3);\n\tgEidos_OMP_threads_MIGRANT_CLEAR = std::min(gEidosMaxThreads, gEidos_OMP_threads_MIGRANT_CLEAR);\n\tgEidos_OMP_threads_SIMPLIFY_SORT_PRE = std::min(gEidosMaxThreads, gEidos_OMP_threads_SIMPLIFY_SORT_PRE);\n\tgEidos_OMP_threads_SIMPLIFY_SORT = std::min(gEidosMaxThreads, gEidos_OMP_threads_SIMPLIFY_SORT);\n\tgEidos_OMP_threads_SIMPLIFY_SORT_POST = std::min(gEidosMaxThreads, gEidos_OMP_threads_SIMPLIFY_SORT_POST);\n\tgEidos_OMP_threads_PARENTS_CLEAR = std::min(gEidosMaxThreads, gEidos_OMP_threads_PARENTS_CLEAR);\n\tgEidos_OMP_threads_UNIQUE_MUTRUNS = std::min(gEidosMaxThreads, gEidos_OMP_threads_UNIQUE_MUTRUNS);\n\tgEidos_OMP_threads_SURVIVAL = std::min(gEidosMaxThreads, gEidos_OMP_threads_SURVIVAL);\n}\n\nvoid Eidos_WarmUpOpenMP(std::ostream *outstream, bool changed_max_thread_count, int new_max_thread_count, bool active_threads, std::string thread_count_set_name)\n{\n\t// When running under OpenMP, print a log, and also set values for the OpenMP ICV's that we want to guarantee\n\t// See http://www.archer.ac.uk/training/course-material/2018/09/openmp-imp/Slides/L10-TipsTricksGotchas.pdf\n\t// We set these with overwrite=0 so the user can override them with custom values from the environment\n\t// FIXME: This should all be documented somewhere...\n\t\n\t// \"active\" encourages idle threads to spin rather than sleep; \"active\" seems to be much faster, maybe lower lag?\n\t// In SLiMgui and EidosScribe, we don't want to use \"active\", though, as it will pin the CPU usage even when not running a parallel section.\n\tconst char *wait_policy = active_threads ? \"ACTIVE\" : \"PASSIVE\";\n\tsetenv(\"OMP_WAIT_POLICY\", wait_policy, 0);\n\t\n\t// \"true\" prevents threads migrating between cores; this generally improves performance, especially with per-thread memory usage\n\tconst char *bind_policy = \"true\";\n\tsetenv(\"OMP_PROC_BIND\", bind_policy, 0);\n\t\n\t// We do not support dynamic adjustment of the number of threads; if we ask for N threads, we expect N threads\n\t// It is important not to change that, or a variety of things will no longer work correctly\n\tomp_set_dynamic(false);\n\t\n\t// We do not support nested parallelism; we set the relevant ICVs here to make sure it is off, overriding defaults/environment\n\tomp_set_max_active_levels(1);\n\t//omp_set_nested(false);\t\t// deprecated in favor of omp_set_max_active_levels()\n\t\n\t// Set the maximum number of threads to the user's request, but never higher than the intrinsic max thread count\n\tif (changed_max_thread_count)\n\t{\n\t\tint thread_limit = omp_get_thread_limit();\n\t\t\n\t\tif (new_max_thread_count > thread_limit)\n\t\t\tnew_max_thread_count = thread_limit;\n\t\t\n\t\tomp_set_num_threads(new_max_thread_count);\t\t// confusingly, sets the *max* threads as returned by omp_get_max_threads()\n\t}\n\t\n\t// Get the maximum number of threads in effect, which might be different from the number requested\n\tgEidosMaxThreads = omp_get_max_threads();\n\tgEidosNumThreads = gEidosMaxThreads;\n\tgEidosNumThreadsOverride = false;\n\t\n\t// Set up per-task thread counts according to thread_count_set_name.  If it is empty, we choose a\n\t// default set heuristically, based upon the hardware platform.  Otherwise, we look for a name we\n\t// recognize, or error out.  There are very few sets here now, so this is not terribly useful;\n\t// but it does allow the benchmarking suite to turn off per-task limits with \"maxThreads\".\n\tif (thread_count_set_name.length() == 0)\n\t\t_Eidos_ChooseDefaultOpenMPThreadCounts();\n\telse if (thread_count_set_name == \"maxThreads\")\n\t\t_Eidos_SetOpenMPThreadCounts(EidosPerTaskThreadCounts::kMaxThreads);\n\telse if (thread_count_set_name == \"MacStudio2022_16\")\n\t\t_Eidos_SetOpenMPThreadCounts(EidosPerTaskThreadCounts::kMacStudio2022_16);\n\telse if (thread_count_set_name == \"XeonGold2_40\")\n\t\t_Eidos_SetOpenMPThreadCounts(EidosPerTaskThreadCounts::kXeonGold2_40);\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_WarmUpOpenMP): (internal error) unrecognized EidosPerTaskThreadCounts value.\" << EidosTerminate(nullptr);\n\t\n\t// Write some diagnostic output about our configuration.  If the verbosity level is 0, outstream will be nullptr.\n\tif (outstream)\n\t{\n\t\t(*outstream) << \"// ********** Running multithreaded with OpenMP (maxThreads == \" << gEidosMaxThreads << \")\" << std::endl;\n\t\t(*outstream) << \"// ********** OMP_WAIT_POLICY == \" << getenv(\"OMP_WAIT_POLICY\") << \", OMP_PROC_BIND == \" << getenv(\"OMP_PROC_BIND\") << std::endl;\n\t\t\n#if 1\n\t\t(*outstream) << \"// ********** Per-task thread counts: '\" << gEidosPerTaskThreadCountsSetName << \"', max \" << gEidosPerTaskOriginalMaxThreadCount;\n\t\tif (gEidosPerTaskClippedMaxThreadCount < gEidosPerTaskOriginalMaxThreadCount)\n\t\t\t(*outstream) << \" (clipped to \" << gEidosPerTaskClippedMaxThreadCount << \")\";\n\t\t(*outstream) << std::endl;\n#endif\n\t\t\n#if 0\n\t\t// BCH 5/19/2023: #if 0 for now, because this gives an error on some platforms; we don't support offloading anyway.\n\t\t// Look for devices (GPUs, accelerators) that we are able to offload to.\n\t\t// Note that OpenMP offloading to the GPUs on Apple Silicon is not currently supported by any compiler.\n\t\t// Other devices may not be visible unless you build slim_multi with a special build of your compiler;\n\t\t// see https://stackoverflow.com/a/66337011/2752221 for some details.\n\t\tint num_devices = omp_get_num_devices();\n\t\tint default_device = omp_get_default_device();\n\t\t\n\t\tif (num_devices > 0)\n\t\t{\n\t\t\t(*outstream) << \"// ********** OpenMP target device count (GPUs, accelerators): \" << num_devices << std::endl;\n\t\t\t(*outstream) << \"// ********** Default target device for OpenMP offloading: \" << default_device << std::endl;\n\t\t}\n#endif\n\t}\n\t\n#ifdef EIDOS_GUI\n\t// The GUI apps don't work well multithreaded.  They have to allow threads to sleep (otherwise they peg the\n\t// CPU the whole time they're running), and that is so inefficient that it makes the apps actually run much\n\t// slower than if they were just single-threaded, as far as I can tell.  I think the threads fall asleep\n\t// whenever they get suspended at all, and then waking them up again is heavyweight.  So running them\n\t// multithreaded is really just for my own development/testing work; end users should not do so.\n\tif (outstream)\n\t\t(*outstream) << \"// ********** RUNNING SLIMGUI / EIDOSSCRIBE WITH OPENMP IS NOT RECOMMENDED!\" << std::endl;\n#endif\n\t\n\tif (outstream)\n\t\t(*outstream) << std::endl;\n}\n#endif\n\nvoid Eidos_WarmUp(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Eidos_WarmUp(): illegal when parallel\");\n\t\n\tstatic bool been_here = false;\n\t\n\tif (!been_here)\n\t{\n\t\tbeen_here = true;\n\t\t\n\t\t// Initialize the random number generator with a random-ish seed.  This seed may be overridden by the Context downstream.\n\t\tEidos_InitializeRNG();\n\t\tEidos_SetRNGSeed(Eidos_GenerateRNGSeed());\n\t\t\n\t\t// Set up the vector of Eidos constant names\n\t\tgEidosConstantNames.emplace_back(gEidosStr_T);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_F);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_NULL);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_PI);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_E);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_INF);\n\t\tgEidosConstantNames.emplace_back(gEidosStr_NAN);\n\t\t\n\t\t// Make the shared EidosValue pool\n\t\tsize_t maxEidosValueSize = sizeof(EidosValue_NULL);\n\t\tmaxEidosValueSize = std::max(maxEidosValueSize, sizeof(EidosValue_Logical));\n\t\tmaxEidosValueSize = std::max(maxEidosValueSize, sizeof(EidosValue_String));\n\t\tmaxEidosValueSize = std::max(maxEidosValueSize, sizeof(EidosValue_Int));\n\t\tmaxEidosValueSize = std::max(maxEidosValueSize, sizeof(EidosValue_Float));\n\t\tmaxEidosValueSize = std::max(maxEidosValueSize, sizeof(EidosValue_Object));\n\t\t\n//\t\tstd::cout << \"sizeof(EidosValue) ==                  \" << sizeof(EidosValue) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_NULL) ==             \" << sizeof(EidosValue_NULL) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_Logical) ==          \" << sizeof(EidosValue_Logical) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_String) ==           \" << sizeof(EidosValue_String) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_Int) ==              \" << sizeof(EidosValue_Int) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_Float) ==            \" << sizeof(EidosValue_Float) << std::endl;\n//\t\tstd::cout << \"sizeof(EidosValue_Object) ==           \" << sizeof(EidosValue_Object) << std::endl;\n//\t\tstd::cout << \"maxEidosValueSize ==                   \" << maxEidosValueSize << std::endl;\n\t\t\n\t\tgEidosValuePool = new EidosObjectPool(\"EidosObjectPool(EidosValue)\", maxEidosValueSize);\n\t\t\n\t\t// Make the shared EidosASTNode pool\n\t\tgEidosASTNodePool = new EidosObjectPool(\"EidosObjectPool(EidosASTNode)\", sizeof(EidosASTNode));\n\t\t\n\t\t// Allocate global permanents.  All of these constants should be marked as constant here.\n\t\tgStaticEidosValueVOID = EidosValue_VOID_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_VOID());\n\t\tgStaticEidosValueVOID->SetInvisible(true);\n\t\tgStaticEidosValueVOID->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValueNULL = EidosValue_NULL_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_NULL());\n\t\tgStaticEidosValueNULL->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValueNULLInvisible = EidosValue_NULL_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_NULL());\n\t\tgStaticEidosValueNULLInvisible->SetInvisible(true);\n\t\tgStaticEidosValueNULLInvisible->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_LogicalT = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical({true}));\n\t\tgStaticEidosValue_LogicalT->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_LogicalF = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical({false}));\n\t\tgStaticEidosValue_LogicalF->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Logical_ZeroVec = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\tgStaticEidosValue_Logical_ZeroVec->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Integer_ZeroVec = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\tgStaticEidosValue_Integer_ZeroVec->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Float_ZeroVec = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tgStaticEidosValue_Float_ZeroVec->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_String_ZeroVec = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\tgStaticEidosValue_String_ZeroVec->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Integer0 = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(0));\n\t\tgStaticEidosValue_Integer0->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Integer1 = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(1));\n\t\tgStaticEidosValue_Integer1->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Integer2 = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(2));\n\t\tgStaticEidosValue_Integer2->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Integer3 = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(3));\n\t\tgStaticEidosValue_Integer3->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Float0 = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(0.0));\n\t\tgStaticEidosValue_Float0->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Float0Point5 = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(0.5));\n\t\tgStaticEidosValue_Float0Point5->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Float1 = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(1.0));\n\t\tgStaticEidosValue_Float1->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_Float10 = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(10.0));\n\t\tgStaticEidosValue_Float10->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_FloatINF = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(std::numeric_limits<double>::infinity()));\n\t\tgStaticEidosValue_FloatINF->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_FloatNAN = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(std::numeric_limits<double>::quiet_NaN()));\n\t\tgStaticEidosValue_FloatNAN->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_FloatE = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(M_E));\n\t\tgStaticEidosValue_FloatE->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_FloatPI = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(M_PI));\n\t\tgStaticEidosValue_FloatPI->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringEmpty = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\"));\n\t\tgStaticEidosValue_StringEmpty->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringSpace = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\" \"));\n\t\tgStaticEidosValue_StringSpace->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringAsterisk = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"*\"));\n\t\tgStaticEidosValue_StringAsterisk->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringDoubleAsterisk = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"**\"));\n\t\tgStaticEidosValue_StringDoubleAsterisk->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringComma = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\",\"));\n\t\tgStaticEidosValue_StringComma->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringTab = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\\t\"));\n\t\tgStaticEidosValue_StringTab->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringPeriod = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\".\"));\n\t\tgStaticEidosValue_StringPeriod->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_StringDoubleQuote = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"\\\"\"));\n\t\tgStaticEidosValue_StringDoubleQuote->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_String_ECMAScript = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"ECMAScript\"));\n\t\tgStaticEidosValue_String_ECMAScript->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_String_indices = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"indices\"));\n\t\tgStaticEidosValue_String_indices->MarkAsConstant();\n\t\t\n\t\tgStaticEidosValue_String_average = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(\"average\"));\n\t\tgStaticEidosValue_String_average->MarkAsConstant();\n\t\t\n\t\t// Create the global class objects for all Eidos classes, from superclass to subclass\n\t\t// This breaks encapsulation, kind of, but it needs to be done here, in order, so that superclass objects exist,\n\t\t// and so that the global string names for the classes have already been set up by C++'s static initialization.\n\t\t// Note the special constructor for EidosDictionaryRetained_Class, with a custom display name for it.\n\t\tgEidosObject_Class =\t\t\t\tnew EidosClass(\t\t\t\t\t\t\tgEidosStr_Object,\t\t\t\tnullptr);\n\t\tgEidosDictionaryUnretained_Class =\tnew EidosDictionaryUnretained_Class(\tgEidosStr_Dictionary,\t\t\tgEidosObject_Class);\n\t\tgEidosDictionaryRetained_Class =\tnew EidosDictionaryRetained_Class(\t\tgEidosStr_DictionaryRetained,\tgEidosStr_Dictionary,\tgEidosDictionaryUnretained_Class);\n\t\tgEidosDataFrame_Class =\t\t\t\tnew EidosDataFrame_Class(\t\t\t\tgEidosStr_DataFrame,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgEidosImage_Class =\t\t\t\t\tnew EidosImage_Class(\t\t\t\t\tgEidosStr_Image,\t\t\t\tgEidosDictionaryRetained_Class);\n\t\tgEidosTestElement_Class =\t\t\tnew EidosTestElement_Class(\t\t\t\tgEidosStr__TestElement,\t\t\tgEidosDictionaryRetained_Class);\n\t\tgEidosTestElementNRR_Class =\t\tnew EidosTestElementNRR_Class(\t\t\tgEidosStr__TestElementNRR,\t\tgEidosObject_Class);\n\t\t\n\t\t// This has to be allocated after gEidosObject_Class has been initialized above; the other global permanents must be initialized\n\t\t// before that point, however, since properties and method signatures may use some of those global permanent values\n\t\tgStaticEidosValue_Object_ZeroVec = EidosValue_Object_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosObject_Class));\n\t\tgStaticEidosValue_Object_ZeroVec->MarkAsConstant();\n\t\t\n\t\t// Set up the built-in function map, which is immutable\n\t\tEidosInterpreter::CacheBuiltInFunctionMap();\n\t\t\n\t\t// Set up the symbol table for Eidos constants\n\t\tgEidosConstantsSymbolTable = new EidosSymbolTable(EidosSymbolTableType::kEidosIntrinsicConstantsTable, nullptr);\n\t\t\n\t\t// Tell all registered classes to initialize their dispatch tables; doing this here saves a flag check later\n\t\t// Note that this can't be done in the EidosClass constructor because the vtable is not set up for the subclass yet\n\t\tfor (EidosClass *eidos_class : EidosClass::RegisteredClasses(true, true))\n\t\t\teidos_class->CacheDispatchTables();\n\t\t\n\t\t// Check classes for mismatched duplicate interfaces\n\t\tEidosClass::CheckForDuplicateMethodsOrProperties();\n\t\t\n\t\t// Check that class names are pointers to the original global strings, which is required\n\t\tif (&gEidosImage_Class->ClassName() != &gEidosStr_Image)\n\t\t{\n\t\t\tstd::cerr << \"***** Class name mismatch in Eidos_WarmUp()!\";\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\t\t\n\t\t// Check that EidosDictionaryState_StringKeys and EidosDictionaryState_IntegerKeys have matching layouts\n\t\t// as far as keys_are_integers_ is concerned, so that that flag can distinguish between them\n\t\t// BCH 3/27/2023: we have to actually allocate objects here to avoid getting flagged by UBSan...\n\t\t{\n\t\t\tEidosDictionaryState_StringKeys *dict_state_ptr_string = new EidosDictionaryState_StringKeys;\n\t\t\tEidosDictionaryState_IntegerKeys *dict_state_ptr_integer = new EidosDictionaryState_IntegerKeys;\n\t\t\t\n\t\t\tuint8_t *flag_addr_string_keys = &((dict_state_ptr_string)->keys_are_integers_);\n\t\t\tuint8_t *flag_addr_integer_keys = &((dict_state_ptr_integer)->keys_are_integers_);\n\t\t\tuint8_t *flag_addr_string_contains = &((dict_state_ptr_string)->contains_non_retain_release_objects_);\n\t\t\tuint8_t *flag_addr_integer_contains = &((dict_state_ptr_integer)->contains_non_retain_release_objects_);\n\t\t\t\n\t\t\tsize_t string_keys_offset = flag_addr_string_keys - (uint8_t *)dict_state_ptr_string;\n\t\t\tsize_t integer_keys_offset = flag_addr_integer_keys - (uint8_t *)dict_state_ptr_integer;\n\t\t\tsize_t string_contains_offset = flag_addr_string_contains - (uint8_t *)dict_state_ptr_string;\n\t\t\tsize_t integer_contains_offset = flag_addr_integer_contains - (uint8_t *)dict_state_ptr_integer;\n\t\t\t\n\t\t\tif ((string_keys_offset != integer_keys_offset) || (string_contains_offset != integer_contains_offset))\n\t\t\t{\n\t\t\t\tstd::cerr << \"***** EidosDictionaryState layout mismatch in Eidos_WarmUp()!\";\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tdelete dict_state_ptr_string;\n\t\t\tdelete dict_state_ptr_integer;\n\t\t}\n\t\t\n#if (defined(_MSC_VER) && _MSC_VER <= 1900) || (defined(__MINGW32__) && !defined(_UCRT))\n\t\t// Work around non-conformance of Microsoft's printf %e format specifier,\n\t\t// which uses 3 digits for the exponent instead of 2.\n\t\t// Until Visual Studio 2015, the _set_output_format() function can be used to obtain standards compliant behaviour.\n\t\t// More recent Visual Studio compilers are standards compliant, and Mingw provides _set_output_format() since 2008.\n\t\t_set_output_format(_TWO_DIGIT_EXPONENT);\n#endif\n\t}\n}\n\nbool Eidos_GoodSymbolForDefine(std::string &p_symbol_name)\n{\n\t// Unfortunately, some symbols need to be reserved to prevent potential conflicts down the road.  In\n\t// particular, anything that we would later define with InitializeConstantSymbolEntry() without checking\n\t// for a conflict at that point needs to be reserved up front here.  This applies particularly to\n\t// pseudo-parameters in SLiM, which get defined with InitializeConstantSymbolEntry() for speed; we don't\n\t// want to take the time to check for a conflict at that point, so we have to reserve the symbol up front.\n\t// Note that this does *not* prevent the use of such symbols as local variable names; in that use case\n\t// the conflict would be detected when the local variable was defined, since the conflicting pseudo-\n\t// parameter would already exist (or, if created in a deeper scope later, would not conflict with the local\n\t// variable in the outside scope since it is not visible anyway).  It only prevents the use of such symbols\n\t// as global variables or constants, because those are supposed to be in scope everywhere, and so they will\n\t// conflict with the same symbol defined in any subsequent scope.\n\t// see https://github.com/MesserLab/SLiM/issues/574\n\t\n\t// There are three sources of prohibited symbols.  One is Eidos keywords like \"if\", which we shouldn't allow\n\t// since they won't be usable later – the tokenizer will see the keyword, not the identifier.  Two is things\n\t// like \"applyValue\" that are used inside Eidos.  Three is things like \"subpop\" that are defined by SLiM,\n\t// or by any other Context, as conflicts -- in particular because they are pseudo-parameters, but there are\n\t// other symbols like \"slimgui\" that we want to block as well.\n\t\n\tbool good_symbol = true;\n\t\n\t// Eidos constants are reserved\n\tif (std::find(gEidosConstantNames.begin(), gEidosConstantNames.end(), p_symbol_name) != gEidosConstantNames.end())\n\t\tgood_symbol = false;\n\t\n\t// Eidos keywords are reserved (probably won't reach here anyway)\n\tif ((p_symbol_name == gEidosStr_if) ||\n\t\t(p_symbol_name == gEidosStr_else) ||\n\t\t(p_symbol_name == gEidosStr_do) ||\n\t\t(p_symbol_name == gEidosStr_while) ||\n\t\t(p_symbol_name == gEidosStr_for) ||\n\t\t(p_symbol_name == gEidosStr_in) ||\n\t\t(p_symbol_name == gEidosStr_next) ||\n\t\t(p_symbol_name == gEidosStr_break) ||\n\t\t(p_symbol_name == gEidosStr_return) ||\n\t\t(p_symbol_name == gEidosStr_function))\n\t\tgood_symbol = false;\n\t\n\t// SLiM constants are reserved too; this code belongs in SLiM, but only\n\t// SLiM uses this facility right now anyway, so I'm not going to sweat it...\n\tif (std::find(gEidosContextReservedSymbols.begin(), gEidosContextReservedSymbols.end(), p_symbol_name) != gEidosContextReservedSymbols.end())\n\t\tgood_symbol = false;\n\t\n\tint len = (int)p_symbol_name.length();\n\t\n\tif (len >= 2)\n\t{\n\t\tchar first_ch = p_symbol_name[0];\n\t\t\n\t\tif ((first_ch == 'p') || (first_ch == 'g') || (first_ch == 'm') || (first_ch == 's') || (first_ch == 'i'))\n\t\t{\n\t\t\tint ch_index;\n\t\t\t\n\t\t\tfor (ch_index = 1; ch_index < len; ++ch_index)\n\t\t\t{\n\t\t\t\tchar idx_ch = p_symbol_name[ch_index];\n\t\t\t\t\n\t\t\t\tif ((idx_ch < '0') || (idx_ch > '9'))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (ch_index == len)\n\t\t\t\tgood_symbol = false;\n\t\t}\n\t}\n\t\n\treturn good_symbol;\n}\n\nEidosValue_SP Eidos_ValueForCommandLineExpression(std::string &p_value_expression)\n{\n\tEidosValue_SP value;\n\tEidosScript script(p_value_expression);\n\t\n\t// Note this can raise; the caller should be prepared for that\n\tscript.SetFinalSemicolonOptional(true);\n\tscript.Tokenize();\n\tscript.ParseInterpreterBlockToAST(false);\n\t\n\tEidosSymbolTable symbol_table(EidosSymbolTableType::kLocalVariablesTable, gEidosConstantsSymbolTable);\n\tEidosFunctionMap function_map(*EidosInterpreter::BuiltInFunctionMap());\n\tEidosInterpreter interpreter(script, symbol_table, function_map, nullptr, std::cout, std::cerr\n#ifdef SLIMGUI\n\t\t, false\n#endif\n\t\t);\t// we're at the command line, so we assume we're using stdout/stderr\n\t\n\tvalue = interpreter.EvaluateInterpreterBlock(false, true);\t// do not print output, return the last statement value\n\tvalue->MarkAsConstant();\n\t\n\treturn value;\n}\n\nvoid Eidos_DefineConstantsFromCommandLine(const std::vector<std::string> &p_constants)\n{\n\t// We want to throw exceptions, even in SLiM, so that we can catch them here\n\tbool save_throws = gEidosTerminateThrows;\n\t\n\tgEidosTerminateThrows = true;\n\t\n\tfor (const std::string &constant : p_constants)\n\t{\n\t\t// Each constant must be in the form x=y, where x is a valid identifier and y is a valid Eidos expression.\n\t\t// We parse the assignment using EidosScript, and work with the resulting AST, for generality.\n\t\tEidosScript script(constant);\n\t\tbool malformed = false;\n\t\t\n\t\ttry\n\t\t{\n\t\t\tscript.SetFinalSemicolonOptional(true);\n\t\t\tscript.Tokenize();\n\t\t\tscript.ParseInterpreterBlockToAST(false);\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tmalformed = true;\n\t\t}\n\t\t\n\t\tif (!malformed)\n\t\t{\n\t\t\t//script.PrintTokens(std::cout);\n\t\t\t//script.PrintAST(std::cout);\n\t\t\t\n\t\t\tconst EidosASTNode *AST = script.AST();\n\t\t\t\n\t\t\tif (AST && (AST->token_->token_type_ == EidosTokenType::kTokenInterpreterBlock) && (AST->children_.size() == 1))\n\t\t\t{\n\t\t\t\tconst EidosASTNode *top_node = AST->children_[0];\n\t\t\t\t\n\t\t\t\tif (top_node && (top_node->token_->token_type_ == EidosTokenType::kTokenAssign) && (top_node->children_.size() == 2))\n\t\t\t\t{\n\t\t\t\t\tconst EidosASTNode *left_node = top_node->children_[0];\n\t\t\t\t\t\n\t\t\t\t\tif (left_node && (left_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && (left_node->children_.size() == 0))\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string symbol_name = left_node->token_->token_string_;\n\t\t\t\t\t\tEidosGlobalStringID symbol_id = EidosStringRegistry::GlobalStringIDForString(symbol_name);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (gEidosConstantsSymbolTable->ContainsSymbol(symbol_id))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgEidosTerminateThrows = save_throws;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_DefineConstantsFromCommandLine): symbol '\" << symbol_name << \"' is already defined.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// OK, if the symbol name is acceptable, keep digging\n\t\t\t\t\t\tif (Eidos_GoodSymbolForDefine(symbol_name))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst EidosASTNode *right_node = top_node->children_[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (right_node)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Rather than try to make a new script with right_node as its root, we simply take the substring\n\t\t\t\t\t\t\t\t// to the right of the = operator and make a new script object from that, and evaluate that.\n\t\t\t\t\t\t\t\t// Note that the expression also parsed in the context of \"value = <expr>\", so this limits the\n\t\t\t\t\t\t\t\t// syntax allowed; the value cannot be a compound statement, for example.\n\t\t\t\t\t\t\t\tint32_t assign_end = top_node->token_->token_end_;\n\t\t\t\t\t\t\t\tstd::string value_expression = constant.substr(assign_end + 1);\n\t\t\t\t\t\t\t\tEidosValue_SP x_value_sp;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tx_value_sp = Eidos_ValueForCommandLineExpression(value_expression);\n\t\t\t\t\t\t\t\t} catch (...) {\n\t\t\t\t\t\t\t\t\t// Syntactic errors should have already been caught, but semantic errors can raise here, and we re-raise\n\t\t\t\t\t\t\t\t\t// with a generic \"could not be evaluated\" message to lead the user toward the commend-line def as the problem\n\t\t\t\t\t\t\t\t\tgEidosTerminateThrows = save_throws;\n\t\t\t\t\t\t\t\t\tstd::string terminationMessage = gEidosTermination.str();\n\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_DefineConstantsFromCommandLine): command-line expression could not be evaluated: \" << constant << std::endl;\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"original error: \" << terminationMessage;\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (x_value_sp)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t//std::cout << \"define \" << symbol_name << \" = \" << value_expression << std::endl;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t// Permanently alter the global Eidos symbol table; don't do this at home!\n\t\t\t\t\t\t\t\t\tEidosSymbolTableEntry table_entry(symbol_id, x_value_sp);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tgEidosConstantsSymbolTable->InitializeConstantSymbolEntry(table_entry);\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tgEidosTerminateThrows = save_throws;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_DefineConstantsFromCommandLine): identifier '\" << symbol_name << \"' is reserved, and cannot be used for a global constant.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tgEidosTerminateThrows = save_throws;\n\t\t\n\t\t// Terminate without putting out a script line/character diagnostic; that looks weird\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_DefineConstantsFromCommandLine): malformed command-line constant definition: \" << constant;\n\t\t\n\t\tif (gEidosTerminateThrows)\n\t\t{\n\t\t\tEIDOS_TERMINATION << EidosTerminate(nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is from operator<<(std::ostream& p_out, const EidosTerminate &p_terminator)\n\t\t\tEIDOS_TERMINATION << std::endl;\n\t\t\tEIDOS_TERMINATION.flush();\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\t}\n\t\n\tgEidosTerminateThrows = save_throws;\n}\n\n\n// Information on the Context within which Eidos is running (if any).\ndouble gEidosContextVersion = 0.0;\nstd::string gEidosContextVersionString;\nstd::string gEidosContextLicense;\nstd::string gEidosContextCitation;\nstd::vector<std::string> gEidosContextReservedSymbols;\t// see Eidos_GoodSymbolForDefine()\n\n\n// *******************************************************************************************************************\n//\n//\tCLI progress reporting\n//\n#pragma mark -\n#pragma mark CLI progress reporting\n#pragma mark -\n\nstd::ostream *gEidos_progress_outstream = nullptr;\nint gEidos_progress_length = 0;\n\nvoid Eidos_StartProgress(std::ostream *p_progress_stream)\n{\n\tif (!gEidos_progress_outstream)\n\t\tgEidos_progress_outstream = p_progress_stream;\n}\n\nvoid Eidos_WriteProgress(const std::string &p_progress_line)\n{\n\tif (gEidos_progress_outstream)\n\t{\n\t\t// If we have a progress line up already, erase it in case the new line is shorter\n\t\tEidos_EraseProgress();\n\t\t\n\t\t// Then show the new line and move to the start of it, so it will get overwritten\n\t\t*gEidos_progress_outstream << p_progress_line << \"\\r\" << std::flush;\n\t\tgEidos_progress_length = (int)p_progress_line.length();\n\t}\n}\n\nvoid Eidos_EraseProgress(void)\n{\n\t// Try to erase a progress line we have up.  This will not work well with all styles of output in the\n\t// running model.  If the user writes a partial output line without a newline, our progress line\n\t// may get tacked on to the end of that, and then not get erased correctly later.  It's hard to\n\t// coordinate the progress bar with other output.  We're not going to worry about such issues too\n\t// much; the user can always turn off the progress bar, it's an optional feature.\n\tif (gEidos_progress_outstream && (gEidos_progress_length > 0))\n\t{\n\t\tstd::string erase_str = std::string(gEidos_progress_length, ' ');\n\t\t\n\t\t*gEidos_progress_outstream << erase_str << \"\\r\" << std::flush;\n\t\tgEidos_progress_length = 0;\n\t}\n}\n\n\n#pragma mark -\n#pragma mark Termination handling\n#pragma mark -\n\n// The part of the input file that caused an error; used to highlight the token or text that caused the error.\n// The initial state set here is not legal; the currentScript member will need to be set before any error.\nEidosErrorContext gEidosErrorContext = {{-1, -1, -1, -1}, nullptr};\n\n// Warnings\nbool gEidosSuppressWarnings = false;\n\n\n// define string stream used for output when gEidosTerminateThrows == 1; otherwise, terminates call exit()\nbool gEidosTerminateThrows = true;\nstd::ostringstream gEidosTermination;\nbool gEidosTerminated;\n\n\n// Print a demangled stack backtrace of the caller function to FILE* out.\n// Note that in Cocoa this works better: NSLog(@\"%@\", NSThread.callStackSymbols);\n// For a shortened backtrace: NSLog(@\"%@\", [NSThread.callStackSymbols subarrayWithRange:NSMakeRange(0, MIN(5UL, NSThread.callStackSymbols.count))]);\nvoid Eidos_PrintStacktrace(FILE *p_out, unsigned int p_max_frames)\n{\n\t// before writing anything, erase a progress line if we've got one up, to try to make a clean slate\n\tEidos_EraseProgress();\n\t\n\tfprintf(p_out, \"stack trace:\\n\");\n\t\n\t// storage array for stack trace address data\n\tvoid* addrlist[p_max_frames+1];\n\t\n\t// retrieve current stack addresses\n\tint addrlen = backtrace(addrlist, static_cast<int>(sizeof(addrlist) / sizeof(void*)));\n\t\n\tif (addrlen == 0)\n\t{\n\t\tfprintf(p_out, \"  <empty, possibly corrupt>\\n\");\n\t\treturn;\n\t}\n\t\n\t// resolve addresses into strings containing \"filename(function+address)\",\n\t// this array must be free()-ed\n\tchar** symbollist = backtrace_symbols(addrlist, addrlen);\n\t\n\t// allocate string which will be filled with the demangled function name\n\tsize_t funcnamesize = 256;\n\tchar* funcname = (char*)malloc(funcnamesize);\n\t\n\t// iterate over the returned symbol lines. skip the first, it is the\n\t// address of this function.\n\tfor (int i = 1; i < addrlen; i++)\n\t{\n\t\tchar *begin_name = 0, *end_name = 0, *begin_offset = 0, *end_offset = 0;\n\t\t\n\t\t// find parentheses and +address offset surrounding the mangled name:\n\t\t// ./module(function+0x15c) [0x8048a6d]\n\t\tfor (char *p = symbollist[i]; *p; ++p)\n\t\t{\n\t\t\tif (*p == '(')\n\t\t\t\tbegin_name = p;\n\t\t\telse if (*p == '+')\n\t\t\t\tbegin_offset = p;\n\t\t\telse if (*p == ')' && begin_offset)\n\t\t\t{\n\t\t\t\tend_offset = p;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// BCH 24 Dec 2014: backtrace_symbols() on OS X seems to return strings in a different, non-standard format.\n\t\t// Added this code in an attempt to parse that format.  No doubt it could be done more cleanly.  :->\n\t\tif (!(begin_name && begin_offset && end_offset\n\t\t\t  && begin_name < begin_offset))\n\t\t{\n\t\t\tenum class ParseState {\n\t\t\t\tkInWhitespace1 = 1,\n\t\t\t\tkInLineNumber,\n\t\t\t\tkInWhitespace2,\n\t\t\t\tkInPackageName,\n\t\t\t\tkInWhitespace3,\n\t\t\t\tkInAddress,\n\t\t\t\tkInWhitespace4,\n\t\t\t\tkInFunction,\n\t\t\t\tkInWhitespace5,\n\t\t\t\tkInPlus,\n\t\t\t\tkInWhitespace6,\n\t\t\t\tkInOffset,\n\t\t\t\tkInOverrun\n\t\t\t};\n\t\t\tParseState parse_state = ParseState::kInWhitespace1;\n\t\t\tchar *p;\n\t\t\t\n\t\t\tfor (p = symbollist[i]; *p; ++p)\n\t\t\t{\n\t\t\t\tswitch (parse_state)\n\t\t\t\t{\n\t\t\t\t\tcase ParseState::kInWhitespace1:\tif (!isspace(*p)) parse_state = ParseState::kInLineNumber;\tbreak;\n\t\t\t\t\tcase ParseState::kInLineNumber:\t\tif (isspace(*p)) parse_state = ParseState::kInWhitespace2;\tbreak;\n\t\t\t\t\tcase ParseState::kInWhitespace2:\tif (!isspace(*p)) parse_state = ParseState::kInPackageName;\tbreak;\n\t\t\t\t\tcase ParseState::kInPackageName:\tif (isspace(*p)) parse_state = ParseState::kInWhitespace3;\tbreak;\n\t\t\t\t\tcase ParseState::kInWhitespace3:\tif (!isspace(*p)) parse_state = ParseState::kInAddress;\t\tbreak;\n\t\t\t\t\tcase ParseState::kInAddress:\t\tif (isspace(*p)) parse_state = ParseState::kInWhitespace4;\tbreak;\n\t\t\t\t\tcase ParseState::kInWhitespace4:\n\t\t\t\t\t\tif (!isspace(*p))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparse_state = ParseState::kInFunction;\n\t\t\t\t\t\t\tbegin_name = p - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ParseState::kInFunction:\n\t\t\t\t\t\tif (isspace(*p))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparse_state = ParseState::kInWhitespace5;\n\t\t\t\t\t\t\tend_name = p;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ParseState::kInWhitespace5:\tif (!isspace(*p)) parse_state = ParseState::kInPlus;\t\tbreak;\n\t\t\t\t\tcase ParseState::kInPlus:\t\t\tif (isspace(*p)) parse_state = ParseState::kInWhitespace6;\tbreak;\n\t\t\t\t\tcase ParseState::kInWhitespace6:\n\t\t\t\t\t\tif (!isspace(*p))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparse_state = ParseState::kInOffset;\n\t\t\t\t\t\t\tbegin_offset = p - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ParseState::kInOffset:\n\t\t\t\t\t\tif (isspace(*p))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tparse_state = ParseState::kInOverrun;\n\t\t\t\t\t\t\tend_offset = p;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ParseState::kInOverrun:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (parse_state == ParseState::kInOffset && !end_offset)\n\t\t\t\tend_offset = p;\n\t\t}\n\t\t\n\t\tif (begin_name && begin_offset && end_offset\n\t\t\t&& begin_name < begin_offset)\n\t\t{\n\t\t\t*begin_name++ = '\\0';\n\t\t\tif (end_name)\n\t\t\t\t*end_name = '\\0';\n\t\t\t*begin_offset++ = '\\0';\n\t\t\t*end_offset = '\\0';\n\t\t\t\n\t\t\t// mangled name is now in [begin_name, begin_offset) and caller\n\t\t\t// offset in [begin_offset, end_offset). now apply __cxa_demangle():\n\t\t\t\n\t\t\tint status;\n\t\t\tchar *ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);\n\t\t\t\n\t\t\tif (status == 0)\n\t\t\t{\n\t\t\t\tfuncname = ret; // use possibly realloc()-ed string; static analyzer doesn't like this but it is OK I think\n\t\t\t\tfprintf(p_out, \"  %s : %s + %s\\n\", symbollist[i], funcname, begin_offset);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// demangling failed. Output function name as a C function with\n\t\t\t\t// no arguments.\n\t\t\t\tfprintf(p_out, \"  %s : %s() + %s\\n\", symbollist[i], begin_name, begin_offset);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// couldn't parse the line? print the whole line.\n\t\t\tfprintf(p_out, \"URF:  %s\\n\", symbollist[i]);\n\t\t}\n\t}\n\t\n\tfree(funcname);\n\tfree(symbollist);\n\t\n\tfflush(p_out);\n}\n\nvoid Eidos_LogScriptError(std::ostream& p_out, const EidosErrorContext &p_error_context)\n{\n\tEidosScript *errorScript = p_error_context.currentScript;\n\tint errorStart = p_error_context.errorPosition.characterStartOfError;\n\tint errorEnd = p_error_context.errorPosition.characterEndOfError;\n\t\n\tif (errorScript && (errorStart >= 0) && (errorEnd >= errorStart))\n\t{\n\t\t// figure out the script line, print it, show the error position\n\t\tconst std::string &script_string = errorScript->String();\n\t\tint length = (int)script_string.length();\n\t\t\n\t\tif ((length >= errorStart) && (length >= errorEnd))\t// == is the EOF position, which we want to allow but have to treat carefully\n\t\t{\n\t\t\tint lineStart = (errorStart < length) ? errorStart : length - 1;\n\t\t\tint lineEnd = (errorEnd < length) ? errorEnd : length - 1;\n\t\t\tint lineNumber;\n\t\t\t\n\t\t\tfor (; lineStart > 0; --lineStart)\n\t\t\t\tif ((script_string[lineStart - 1] == '\\n') || (script_string[lineStart - 1] == '\\r'))\n\t\t\t\t\tbreak;\n\t\t\tfor (; lineEnd < length - 1; ++lineEnd)\n\t\t\t\tif ((script_string[lineEnd + 1] == '\\n') || (script_string[lineEnd + 1] == '\\r'))\n\t\t\t\t\tbreak;\n\t\t\t\n\t\t\t// Figure out the line number in the script where the error starts\n\t\t\tlineNumber = 1;\n\t\t\t\n\t\t\tfor (int i = 0; i < lineStart; ++i)\n\t\t\t\tif (script_string[i] == '\\n')\n\t\t\t\t\tlineNumber++;\n\t\t\t\n\t\t\tint errorLine = lineNumber;\n\t\t\tint errorLineCharacter = errorStart - lineStart;\n\t\t\t\n\t\t\tp_out << std::endl << \"Error on script line \" << errorLine << \", character \" << errorLineCharacter;\n\t\t\t\n\t\t\tif (errorScript->UserScriptCharOffset() == -1)\n\t\t\t\tp_out << \" (not inside the main user script)\";\n\t\t\t\n\t\t\tp_out << \":\" << std::endl << std::endl;\n\t\t\t\n\t\t\t// Emit the script line, converting tabs to three spaces\n\t\t\tfor (int i = lineStart; i <= lineEnd; ++i)\n\t\t\t{\n\t\t\t\tchar script_char = script_string[i];\n\t\t\t\t\n\t\t\t\tif (script_char == '\\t')\n\t\t\t\t\tp_out << \"   \";\n\t\t\t\telse if ((script_char == '\\n') || (script_char == '\\r'))\t// don't show more than one line\n\t\t\t\t\tbreak;\n\t\t\t\telse\n\t\t\t\t\tp_out << script_char;\n\t\t\t}\n\t\t\t\n\t\t\tp_out << std::endl;\n\t\t\t\n\t\t\t// Emit the error indicator line, again emitting three spaces where the script had a tab\n\t\t\tfor (int i = lineStart; i < errorStart; ++i)\n\t\t\t{\n\t\t\t\tchar script_char = script_string[i];\n\t\t\t\t\n\t\t\t\tif (script_char == '\\t')\n\t\t\t\t\tp_out << \"   \";\n\t\t\t\telse if ((script_char == '\\n') || (script_char == '\\r'))\t// don't show more than one line\n\t\t\t\t\tbreak;\n\t\t\t\telse\n\t\t\t\t\tp_out << ' ';\n\t\t\t}\n\t\t\t\n\t\t\t// Emit the error indicator\n\t\t\tfor (int i = 0; i < errorEnd - errorStart + 1; ++i)\n\t\t\t\tp_out << \"^\";\n\t\t\t\n\t\t\tp_out << std::endl;\n\t\t}\n\t}\n}\n\nEidosTerminate::EidosTerminate(const EidosToken *p_error_token)\n{\n\t// This is the end of the line, so we don't need to treat the error position as a stack\n\tif (p_error_token)\n\t\tPushErrorPositionFromToken(p_error_token);\n}\n\nEidosTerminate::EidosTerminate(const EidosErrorPosition &p_error_position)\n{\n\tgEidosErrorContext.errorPosition = p_error_position;\n}\n\nEidosTerminate::EidosTerminate(bool p_print_backtrace) : print_backtrace_(p_print_backtrace)\n{\n}\n\nEidosTerminate::EidosTerminate(const EidosToken *p_error_token, bool p_print_backtrace) : print_backtrace_(p_print_backtrace)\n{\n\t// This is the end of the line, so we don't need to treat the error position as a stack\n\tif (p_error_token)\n\t\tPushErrorPositionFromToken(p_error_token);\n}\n\nvoid operator<<(std::ostream& p_out, const EidosTerminate &p_terminator)\n{\n\t// At the time that an EidosTerminate error is first raised, we try to translate it from the current script\n\t// (which might be an event, a callback, a lambda...) into the user script's context.  This might fail,\n\t// because the error might have occurred inside a script that is not derived from the user script; the\n\t// code for the error position simply doesn't exist in the user script (perhaps it's a string, or it was\n\t// created programmatically).  When we move outward from one script context to another, we will try again\n\t// to translate the error context outward to the user script.  The first time we succeed, that defines the\n\t// position at which the error will be shown in the GUI.\n\tTranslateErrorContextToUserScript(\"operator<<(EidosTerminate)\");\n\t\n\tp_out << std::endl;\n\t\n\tp_out.flush();\n\t\n\tif (p_terminator.print_backtrace_)\n\t\tEidos_PrintStacktrace(stderr);\n\t\n\tif (gEidosTerminateThrows)\n\t{\n\t\t// BCH 5/14/2023: I used to have a check here for (omp_get_level() > 0), and would do raise(SIGTRAP) in that situation\n\t\t// to get a trap in the debugger for the point when an exception was raised inside a parallel region.  However, we now\n\t\t// have some places in the code where such raises are guarded by try/catch, so they are no longer unambiguously wrong.\n\t\t// So I've deleted that check here.  The throw below will happen, and if no try/catch is in place and we're inside a\n\t\t// parallel region, we will end up with an uncaught C++ exception error.\n\t\t\n\t\t// In this case, EidosTerminate() throws an exception that gets caught by the Context.  That invalidates the simulation object, and\n\t\t// causes the Context to display an error message and ends the simulation run, but it does not terminate the app.\n\t\tthrow std::runtime_error(\"A runtime error occurred in Eidos\");\n\t}\n\telse\n\t{\n\t\t// In this case, EidosTerminate() does in fact terminate; this is appropriate when errors are simply fatal and there is no UI.\n\t\t// In this case, we want to emit a diagnostic showing the line of script where the error occurred, if we can.\n\t\t// This facility uses only the non-UTF16 positions, since it is based on std::string, so those positions can be ignored.\n\t\tEidos_LogScriptError(p_out, gEidosErrorContext);\n\t\t\n\t\t// Try to flush any outstanding file buffers\n\t\tEidos_FlushFiles();\n\t\t\n\t\texit(EXIT_FAILURE);\n\t}\n}\n\nstd::string Eidos_GetTrimmedRaiseMessage(void)\n{\n\tif (gEidosTerminateThrows)\n\t{\n\t\tstd::string terminationMessage = gEidosTermination.str();\n\t\t\n\t\tgEidosTermination.clear();\n\t\tgEidosTermination.str(gEidosStr_empty_string);\n\t\t\n\t\t// trim off newlines at the end of the raise string\n\t\tsize_t endpos = terminationMessage.find_last_not_of(\"\\n\\r\");\n\t\tif (std::string::npos != endpos)\n\t\t\tterminationMessage = terminationMessage.substr(0, endpos + 1);\n\t\t\n\t\treturn terminationMessage;\n\t}\n\telse\n\t{\n\t\treturn gEidosStr_empty_string;\n\t}\n}\n\nstd::string Eidos_GetUntrimmedRaiseMessage(void)\n{\n\tif (gEidosTerminateThrows)\n\t{\n\t\tstd::string terminationMessage = gEidosTermination.str();\n\t\t\n\t\tgEidosTermination.clear();\n\t\tgEidosTermination.str(gEidosStr_empty_string);\n\t\t\n\t\treturn terminationMessage;\n\t}\n\telse\n\t{\n\t\treturn gEidosStr_empty_string;\n\t}\n}\n\n\n#pragma mark -\n#pragma mark Debugging support\n#pragma mark -\n\nvoid CheckLongTermBoundary()\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"CheckLongTermBoundary(): illegal when parallel\");\n\t\n\t// Right now, EidosDictionary is the only part of Eidos that is smart about long-term\n\t// boundaries, so we just need to check its state.  But in future, we could allow the\n\t// user to call defineGlobal() with a non-retain-release object as long as they fix\n\t// the reference by the next long-term boundary.\n\tbool violation = false;\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter != 0)\n\t\tviolation = true;\n\t\n\t// See EidosDictionaryUnretained_Class::ExecuteMethod_setValuesVectorized() for a very obscure\n\t// and very unlikely code path that would cause this error to occur... erroneously.  :->\n\t\n\tif (violation)\n\t\tEIDOS_TERMINATION << \"ERROR (CheckLongTermBoundary): A long-term reference has been kept to an Eidos object that is not under retain-release memory management.  For example, a SLiM Individual or Subpopulation may have been placed in a global dictionary.  This is illegal; only objects that are under retain-release memory management can be kept long-term.\" << EidosTerminate(nullptr);\n}\n\n\n#pragma mark -\n#pragma mark Memory usage and runtime monitoring\n#pragma mark -\n\n//\n//\tThe code below was obtained from http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use.  It may or may not work.\n//\tOn Windows, it requires linking with Microsoft's psapi.lib.  That is left as an exercise for the reader.  Nadeau says \"On other OSes, the default libraries are sufficient.\"\n//\n\n/*\n * Author:  David Robert Nadeau\n * Site:    http://NadeauSoftware.com/\n * License: Creative Commons Attribution 3.0 Unported License\n *          http://creativecommons.org/licenses/by/3.0/deed.en_US\n */\n\n#if defined(_WIN32)\n#include <windows.h>\n#include <psapi.h>\n\n#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))\n#include <unistd.h>\n#include <sys/resource.h>\n\n#if defined(__APPLE__) && defined(__MACH__)\n#include <mach/mach.h>\n\n#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))\n#include <fcntl.h>\n#include <procfs.h>\n\n#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)\n#include <stdio.h>\n\n#endif\n\n#else\n#error \"Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS.\"\n#endif\n\n/**\n * Returns the peak (maximum so far) resident set size (physical\n * memory use) measured in bytes, or zero if the value cannot be\n * determined on this OS.\n */\nsize_t Eidos_GetPeakRSS(void)\n{\n#if defined(_WIN32)\n\t/* Windows -------------------------------------------------- */\n\tPROCESS_MEMORY_COUNTERS info;\n\tGetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );\n\treturn (size_t)info.PeakWorkingSetSize;\n\t\n#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))\n\t/* AIX and Solaris ------------------------------------------ */\n\tstruct psinfo psinfo;\n\tint fd = -1;\n\tif ( (fd = open( \"/proc/self/psinfo\", O_RDONLY )) == -1 )\n\t\treturn (size_t)0L;\t\t/* Can't open? */\n\tif ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )\n\t{\n\t\tclose( fd );\n\t\treturn (size_t)0L;\t\t/* Can't read? */\n\t}\n\tclose( fd );\n\treturn (size_t)(psinfo.pr_rssize * 1024L);\n\t\n#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))\n\t/* BSD, Linux, and OSX -------------------------------------- */\n\tstruct rusage rusage;\n\tgetrusage( RUSAGE_SELF, &rusage );\n#if defined(__APPLE__) && defined(__MACH__)\n\treturn (size_t)rusage.ru_maxrss;\n#else\n\treturn (size_t)(rusage.ru_maxrss * 1024L);\n#endif\n\t\n#else\n\t/* Unknown OS ----------------------------------------------- */\n\treturn (size_t)0L;\t\t\t/* Unsupported. */\n#endif\n}\n\n\n/**\n * Returns the current resident set size (physical memory use) measured\n * in bytes, or zero if the value cannot be determined on this OS.\n */\nsize_t Eidos_GetCurrentRSS(void)\n{\n#if defined(_WIN32)\n\t/* Windows -------------------------------------------------- */\n\tPROCESS_MEMORY_COUNTERS info;\n\tGetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );\n\treturn (size_t)info.WorkingSetSize;\n\t\n#elif defined(__APPLE__) && defined(__MACH__)\n\t/* OSX ------------------------------------------------------ */\n\tstruct mach_task_basic_info info;\n\tmach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;\n\tif ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,\n\t\t\t\t   (task_info_t)&info, &infoCount ) != KERN_SUCCESS )\n\t\treturn (size_t)0L;\t\t/* Can't access? */\n\treturn (size_t)info.resident_size;\n\t\n#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)\n\t/* Linux ---------------------------------------------------- */\n\tlong rss = 0L;\n\tFILE* fp = NULL;\n\tif ( (fp = fopen( \"/proc/self/statm\", \"r\" )) == NULL )\n\t\treturn (size_t)0L;\t\t/* Can't open? */\n\tif ( fscanf( fp, \"%*s%ld\", &rss ) != 1 )\n\t{\n\t\tfclose( fp );\n\t\treturn (size_t)0L;\t\t/* Can't read? */\n\t}\n\tfclose( fp );\n\treturn (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);\n\t\n#else\n\t/* AIX, BSD, Solaris, and Unknown OS ------------------------ */\n\treturn (size_t)0L;\t\t\t/* Unsupported. */\n#endif\n}\n\n/**\n *This is my own code, patterned after Nadeau's code above\n *\n * Returns the current virtual memory use measured\n * in bytes, or zero if the value cannot be determined on this OS.\n */\nsize_t Eidos_GetVMUsage(void)\n{\n#if defined(_WIN32)\n\t/* Windows -------------------------------------------------- */\n\t// see https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-process_memory_counters\n\tPROCESS_MEMORY_COUNTERS info;\n\tGetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );\n\treturn (size_t)info.PagefileUsage;\n\t\n#elif defined(__APPLE__) && defined(__MACH__)\n\t/* OSX ------------------------------------------------------ */\n\tstruct mach_task_basic_info info;\n\tmach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;\n\tif ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,\n\t\t\t\t   (task_info_t)&info, &infoCount ) != KERN_SUCCESS )\n\t\treturn (size_t)0L;\t\t/* Can't access? */\n\treturn (size_t)info.virtual_size;\n\t\n#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)\n\t/* Linux ---------------------------------------------------- */\n\t// see https://man7.org/linux/man-pages/man5/proc.5.html\n\tlong vmsize = 0L;\n\tFILE* fp = NULL;\n\tif ( (fp = fopen( \"/proc/self/statm\", \"r\" )) == NULL )\n\t\treturn (size_t)0L;\t\t/* Can't open? */\n\tif ( fscanf( fp, \"%ld\", &vmsize ) != 1 )\n\t{\n\t\tfclose( fp );\n\t\treturn (size_t)0L;\t\t/* Can't read? */\n\t}\n\tfclose( fp );\n\treturn (size_t)vmsize * (size_t)sysconf( _SC_PAGESIZE);\n\t\n#else\n\t/* AIX, BSD, Solaris, and Unknown OS ------------------------ */\n\treturn (size_t)0L;\t\t\t/* Unsupported. */\n#endif\n}\n\nsize_t Eidos_GetMaxRSS(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_GetMaxRSS(): usage of statics\");\n\t\n\tstatic bool beenHere = false;\n\tstatic size_t max_rss = 0;\n\t\n\tif (!beenHere)\n\t{\n\n#if defined(_WIN32)\n\t// Assume unlimited on Windows with warning\n\tstd::cerr << \"WARNING: Eidos_GetMaxRSS() does not work properly in Windows, so return assumes no limit, which may be incorrect.\";\n\tmax_rss = 0;\n\n#else\n#if 0\n\t\t// Find our RSS limit by launching a subshell to run \"ulimit -m\"\n\t\tstd::string limit_string = Eidos_Exec(\"ulimit -m\");\n\t\t\n\t\tstd::string unlimited(\"unlimited\");\n\t\t\n\t\tif (std::mismatch(unlimited.begin(), unlimited.end(), limit_string.begin()).first == unlimited.end())\n\t\t{\n\t\t\t// \"unlimited\" is a prefix of foobar, so use 0 to represent that\n\t\t\tmax_rss = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\terrno = 0;\n\t\t\t\n\t\t\tconst char *c_str = limit_string.c_str();\n\t\t\tchar *last_used_char = nullptr;\n\t\t\t\n\t\t\tmax_rss = strtoll(c_str, &last_used_char, 10);\n\t\t\t\n\t\t\tif (errno || (last_used_char == c_str))\n\t\t\t{\n\t\t\t\t// If an error occurs, assume we are unlimited\n\t\t\t\tmax_rss = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// This value is in 1024-byte units, so multiply to get a limit in bytes\n\t\t\t\tmax_rss *= 1024L;\n\t\t\t}\n\t\t}\n#else\n\t\t// Find our RSS limit using getrlimit() – easier and safer\n\t\tstruct rlimit rlim;\n\t\t\n\t\tif (getrlimit(RLIMIT_RSS, &rlim) == 0)\n\t\t{\n\t\t\t// This value is in bytes, no scaling needed\n\t\t\tmax_rss = (uint64_t)rlim.rlim_max;\n\t\t\t\n\t\t\t// If the claim is that we have more than 1024 TB at our disposal, then we will consider ourselves unlimited :->\n\t\t\tif (max_rss > 1024LL * 1024L * 1024L * 1024L * 1024L)\n\t\t\t\tmax_rss = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If an error occurs, assume we are unlimited\n\t\t\tmax_rss = 0;\n\t\t}\n#endif\n#endif\n\t\t\n\t\tbeenHere = true;\n\t}\n\n\treturn max_rss;\n}\n\nvoid Eidos_CheckRSSAgainstMax(const std::string &p_message1, const std::string &p_message2)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_CheckRSSAgainstMax():  usage of statics\");\n\t\n\tstatic bool beenHere = false;\n\tstatic size_t max_rss = 0;\n\t\n\tif (!beenHere)\n\t{\n\t\t// The first time we are called, we get the memory limit and sanity-check it\n\t\tmax_rss = Eidos_GetMaxRSS();\n\t\t\n#if 0\n\t\t// Impose a 20 MB limit, for testing\n\t\tmax_rss = 20*1024*1024;\n#warning Turn this off!\n#endif\n\t\t\n\t\tif (max_rss != 0)\n\t\t{\n\t\t\tsize_t current_rss = Eidos_GetCurrentRSS();\n\t\t\t\n\t\t\t// If we are already within 10 MB of overrunning our supposed limit, disable checking; assume that\n\t\t\t// either Eidos_GetMaxRSS() or Eidos_GetCurrentRSS() is not telling us the truth.\n\t\t\tif (current_rss + 10L*1024L*1024L > max_rss)\n\t\t\t\tmax_rss = 0;\n\t\t}\n\t\t\n\t\t// Switch off our memory check flag if we are not going to enforce a limit anyway;\n\t\t// this allows the caller to skip calling us when possible, for speed\n\t\tif (max_rss == 0)\n\t\t\teidos_do_memory_checks = false;\n\t\t\n\t\tbeenHere = true;\n\t}\n\t\n\tif (eidos_do_memory_checks && (max_rss != 0))\n\t{\n\t\tsize_t current_rss = Eidos_GetCurrentRSS();\n\t\t\n\t\t// If we are within 10 MB of overrunning our limit, then terminate with a message before\n\t\t// the system does it for us.  10 MB gives us a little headroom, so that we detect this\n\t\t// condition before the system does.\n\t\tif (current_rss + 10L*1024L*1024L > max_rss)\n\t\t{\n\t\t\t// We output our warning to std::cerr, because we may get killed by the OS for exceeding our memory limit before other streams would get flushed\n\t\t\t// Note this warning is not suppressed by gEidosSuppressWarnings; that is deliberate\n\t\t\tstd::cerr << \"WARNING (\" << p_message1 << \"): memory usage of \" << (current_rss / (1024.0 * 1024.0)) << \" MB is dangerously close to the limit of \" << (max_rss / (1024.0 * 1024.0)) << \" MB reported by the operating system.  This SLiM process may soon be killed by the operating system for exceeding the memory limit.  You might raise the per-process memory limit, or modify your model to decrease memory usage.  You can turn off this memory check with the '-x' command-line option.  \" << p_message2 << std::endl;\n\t\t\tstd::cerr.flush();\n\t\t\t\n\t\t\t// We want to issue only one warning, so turn off warnings now\n\t\t\teidos_do_memory_checks = false;\n\t\t}\n\t}\n}\n\ndouble Eidos_WallTimeSeconds(void)\n{\n\tstd::chrono::steady_clock::time_point end_wall = std::chrono::steady_clock::now();\n\tstd::chrono::steady_clock::duration wall_duration = end_wall - gEidos_WallTimeBegin;\n\tdouble wall_time_secs = std::chrono::duration<double>(wall_duration).count();\n\t\n\treturn wall_time_secs;\n}\n\nvoid Eidos_GetUserSysTime(double *p_user_time, double *p_sys_time)\n{\n\tdouble user_time, sys_time;\n\t\n#if defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))\n\t/* BSD, Linux, and OSX -------------------------------------- */\n\tstruct rusage rusage;\n\tgetrusage( RUSAGE_SELF, &rusage );\n\t\n\tuser_time = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec / 1000000.0;\n\tsys_time = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec / 1000000.0;\t\n#elif defined(_WIN32)\n\t/* Windows does not have getrusage() ------------------------ */\n\tFILETIME proc_creation_time, proc_exit_time, proc_kernel_time, proc_user_time;\n\tGetProcessTimes(GetCurrentProcess(), &proc_creation_time, &proc_exit_time, &proc_kernel_time, &proc_user_time);\n\t\n\t// Windows programming is weird.  Thanks to https://stackoverflow.com/a/12845669/2752221.\n\tULARGE_INTEGER kernel_ularge;\n\tULARGE_INTEGER user_ularge;\n\t\n\tkernel_ularge.LowPart = proc_kernel_time.dwLowDateTime;\n\tkernel_ularge.HighPart = proc_kernel_time.dwHighDateTime;\n\tuser_ularge.LowPart = proc_user_time.dwLowDateTime;\n\tuser_ularge.HighPart = proc_user_time.dwHighDateTime;\n\t\n\tuser_time = user_ularge.QuadPart / 10000000.0;\n\tsys_time = kernel_ularge.QuadPart / 10000000.0;\n#else\n\t/* Unknown OS ----------------------------------------------- */\n\tuser_time = 0.0;\t\t\t/* Unsupported. */\n\tsys_time = 0.0;\t\t\t\t/* Unsupported. */\n#endif\n\t\n\tif (p_user_time)\n\t\t*p_user_time = user_time;\n\tif (p_sys_time)\n\t\t*p_sys_time = sys_time;\n}\n\n\n#pragma mark -\n#pragma mark File I/O\n#pragma mark -\n\n// resolve a leading ~ in a filesystem path to the user's home directory\nstd::string Eidos_ResolvedPath(const std::string &p_path)\n{\n\tstd::string path = p_path;\n\t\n\t// if there is a leading '~', replace it with the user's home directory; this does not work on Windows\n#ifndef _WIN32\n\tif ((path.length() > 0) && (path[0] == '~'))\n\t{\n\t\tlong bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);\n\t\t\n\t\tif (bufsize == -1)\n\t\t{\n\t\t\t// non-reentrant code when we can't get a buffer size\n\t\t\tconst char *homedir = getenv(\"HOME\");\n\t\t\t\n\t\t\tif (homedir == NULL)\n\t\t\t\thomedir = getpwuid(getuid())->pw_dir;\n\t\t\t\n\t\t\tif (strlen(homedir))\n\t\t\t\tpath.replace(0, 1, homedir);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// reentrant version using getpwuid_r\n\t\t\tchar buffer[bufsize];\n\t\t\tstruct passwd pwd, *result = NULL;\n\t\t\tint retval = getpwuid_r(getuid(), &pwd, buffer, bufsize, &result);\n\t\t\t\n\t\t\tif (retval || !result)\n\t\t\t{\n\t\t\t\tstd::cerr << \"Eidos_ResolvedPath(): Could not resolve ~ in path due to failure of getpwuid_r\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst char *homedir = pwd.pw_dir;\n\t\t\t\t\n\t\t\t\tif (strlen(homedir))\n\t\t\t\t\tpath.replace(0, 1, homedir);\n\t\t\t}\n\t\t}\n\t}\n#else\n\tif ((path.length() > 0) && (path[0] == '~'))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ResolvedPath): Could not resolve ~ in path because it is not supported on Windows.\" << EidosTerminate();\n\t}\n#endif\t\n\t\n\treturn path;\n}\n\n// generate a canonical absolute path corresponding to the provided path\nstd::string Eidos_AbsolutePath(const std::string &p_path)\n{\n\t// Resolve a ~ at the start of the path\n\tstd::string resolved_file_path = Eidos_ResolvedPath(p_path);\n\t\n\t// A zero-length path is an error\n\tif (resolved_file_path.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_AbsolutePath): resolved path is zero-length.\" << EidosTerminate();\n\t\n\t// Convert to an absolute path so we do not depend on the current working directory, which could change\n#ifdef _WIN32\n\t// On Windows, absolute paths start with a drive identifier from \"A:\" to \"Z:\", and then a path separator \"/\" or \"\\\"\n\t// Note that we do not presently support absolute paths from the \"current drive\", like \"\\Program Files\\Custom Utilities\\StringFinder.exe\"\n\t// We also do not support relative paths from per-drive current directories, like \"C:Projects\\apilibrary\\apilibrary.sln\"\n\t// I'm not sure what happens if such paths are used, nor what ought to happen, since I don't really understand Windows paths well.\n\t// Our support for Windows-style paths could thus be improxed; FIXME.  See https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats\n\tbool is_absolute_path = ((resolved_file_path.length() >= 3) && (resolved_file_path[0] >= 'A') && (resolved_file_path[0] <= 'Z') && (resolved_file_path[1] == ':') && ((resolved_file_path[2] == '/') || (resolved_file_path[2] == '\\\\')));\n#else\n\t// On other platforms, absolute paths start with a \"/\"\n\tbool is_absolute_path = ((resolved_file_path.length() >= 1) && (resolved_file_path[0] == '/'));\n#endif\n\t\n\tif (!is_absolute_path)\n\t{\n\t\tstd::string current_dir = Eidos_CurrentDirectory();\n\t\tsize_t current_dir_length = current_dir.length();\n\t\t\n\t\tif (current_dir_length > 0)\n\t\t{\n\t\t\t// Figure out whether we need to append a slash to the CWD or not\n#ifdef _WIN32\n\t\t\tif ((current_dir[current_dir_length - 1] == '/') || (current_dir[current_dir_length - 1] == '\\\\'))\n#else\n\t\t\tif (current_dir[current_dir_length - 1] == '/')\n#endif\n\t\t\t\tresolved_file_path = current_dir + resolved_file_path;\n\t\t\telse\n\t\t\t\tresolved_file_path = current_dir + \"/\" + resolved_file_path;\t// append / in all cases to avoid quoting issues\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_AbsolutePath): the current working directory seems to be invalid.\" << EidosTerminate();\n\t\t}\n\t}\n\t\n\treturn resolved_file_path;\n}\n\n// Get the filename (or a trailing directory name) from a path\nstd::string Eidos_LastPathComponent(const std::string &p_path)\n{\n\tstd::string path = Eidos_StripTrailingSlash(p_path);\n\t\n#ifdef _WIN32\n\t// replace \\ with / first, so the split works correctly with both separators\n\tstd::replace(path.begin(), path.end(), '\\\\', '/'); \n#endif\n\t\n\tauto components = Eidos_string_split(path, \"/\");\n\t\n\tif (components.size() == 0)\n\t\treturn \"\";\n\t\n\treturn components.back();\n}\n\n// Get the current working directory; oddly, C++ has no API for this\nstd::string Eidos_CurrentDirectory(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_CurrentDirectory(): usage of statics\");\n\t\n\t// buffer of size MAXPATHLEN * 8 to accommodate relatively long paths\n\tstatic char *path_buffer = nullptr;\n\t\n\tif (!path_buffer)\n\t\tpath_buffer = (char *)malloc(MAXPATHLEN * 8 * sizeof(char));\n\t\n\terrno = 0;\n\tchar *buf = getcwd(path_buffer, MAXPATHLEN * 8 * sizeof(char));\n\t\n\t// BCH 7/19/2024: Arguably we should convert \\ to / here on Windows, as\n\t// Eidos_TemporaryDirectory() does, but I'm not going to make that breaking\n\t// change unless someone complains.\n\t\n\tif (!buf)\n\t{\n\t\tstd::cout << \"Eidos_CurrentDirectory(): Unable to get the current working directory (error \" << errno << \")\" << std::endl;\n\t\treturn \"ERROR\";\n\t}\n\t\n\treturn buf;\n}\n\n// Remove a trailing slash in a path like ~/foo/bar/\nstd::string Eidos_StripTrailingSlash(const std::string &p_path)\n{\n\tint path_length = (int)p_path.length();\n\t\n#ifdef _WIN32\n\tbool path_ends_in_slash = (path_length > 0) && ((p_path[path_length-1] == '/') || (p_path[path_length-1] == '\\\\'));\n#else\n\tbool path_ends_in_slash = (path_length > 0) && (p_path[path_length-1] == '/');\n#endif\n\t\n\tif (path_ends_in_slash)\n\t{\n\t\tstd::string path = p_path;\n\t\t\n\t\tpath.pop_back();\t\t// remove the trailing slash, which just confuses stat()\n\t\treturn path;\n\t}\n\t\n\treturn p_path;\n}\n\n// Create a directory at the given path if it does not already exist; returns false if an error occurred (which emits a warning)\nbool Eidos_CreateDirectory(const std::string &p_path, std::string *p_error_string)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_CreateDirectory():  filesystem write\");\n\t\n\tstd::string path = Eidos_ResolvedPath(Eidos_StripTrailingSlash(p_path));\n\t\n\terrno = 0;\n\t\n\tstruct stat file_info;\n\tbool path_exists = (stat(path.c_str(), &file_info) == 0);\n\t\n\tif (path_exists)\n\t{\n\t\tbool is_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\n\t\tif (is_directory)\n\t\t{\n\t\t\tp_error_string->assign(\"#WARNING (Eidos_ExecuteFunction_createDirectory): function createDirectory() could not create a directory because a directory at the specified path already exists.\");\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tp_error_string->assign(\"#WARNING (Eidos_ExecuteFunction_createDirectory): function createDirectory() could not create a directory because a file at the specified path already exists.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse if (errno == ENOENT)\n\t{\n\t\t// The path does not exist, so let's try to create it\n\t\terrno = 0;\n\t\t\n\t\tif (mkdir(path.c_str(), 0777) == 0)\n\t\t{\n\t\t\t// success\n\t\t\tp_error_string->assign(\"\");\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tp_error_string->assign(\"#WARNING (Eidos_ExecuteFunction_createDirectory): function createDirectory() could not create a directory because of an unspecified filesystem error.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// The stat() call failed for an unknown reason\n\t\tp_error_string->assign(\"#WARNING (Eidos_ExecuteFunction_createDirectory): function createDirectory() could not create a directory because of an unspecified filesystem error.\");\n\t\treturn false;\n\t}\n}\n\n// This is /tmp/ (with trailing slash!) on macOS and Linux, but will be elsewhere on Windows.  Should be used instead of /tmp/ everywhere.\nstd::string Eidos_TemporaryDirectory(void)\n{\n#ifdef _WIN32\n\tstd::string temp_path;\n\tchar charPath[MAX_PATH];\n\tif (GetTempPathA(MAX_PATH, charPath))\n  \t\ttemp_path = charPath;\n\t// GetTempPathA gives a Windows path with Windows backslashes in it.\n\t// This breaks some other code because Eidos treats backslashes\n\t// as escape characters. So we replace them with forward slashes\n\t// which is understood by both linux and Windows.\n\tstd::replace(temp_path.begin(), temp_path.end(), '\\\\', '/'); \n\treturn temp_path;\n#else\n\treturn \"/tmp/\";\n#endif\n}\n\nbool Eidos_TemporaryDirectoryExists(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_TemporaryDirectoryExists(): usage of statics\");\n\t\n\t// we cache the result for speed, making the assumption that the temporary directory will not change underneath us\n\tstatic bool been_here = false;\n\tstatic bool exists = false;\n\t\n\tif (!been_here)\n\t{\n\t\tstd::string path = Eidos_TemporaryDirectory();\n\t\tstruct stat file_info;\n\t\tbool path_exists = (stat(path.c_str(), &file_info) == 0);\n\t\t\n\t\t// test that Eidos_TemporaryDirectory() itself exists and is a directory\n\t\tif (path_exists)\n\t\t{\n\t\t\tbool is_directory = !!(file_info.st_mode & S_IFDIR);\n\t\t\t\n\t\t\tif (is_directory)\n\t\t\t{\n\t\t\t\t// test that it is writeable, in practice, by creating a temp file\n\t\t\t\tstd::string prefix = Eidos_TemporaryDirectory() + \"eidos_tmp_test\";\n\t\t\t\tstd::string suffix = \".txt\";\n\t\t\t\tstd::string file_path_template = prefix + \"XXXXXX\" + suffix;\n\t\t\t\tchar *file_path_cstr = strdup(file_path_template.c_str());\n\t\t\t\tint fd = Eidos_mkstemps(file_path_cstr, 4);\n\t\t\t\t\n\t\t\t\tif (fd != -1)\n\t\t\t\t{\n\t\t\t\t\tstd::string file_path(file_path_cstr);\n\t\t\t\t\tstd::ofstream file_stream(file_path.c_str(), std::ios_base::out);\n\t\t\t\t\tclose(fd);\t// opened by Eidos_mkstemps()\n\t\t\t\t\t\n\t\t\t\t\tif (file_stream.is_open())\n\t\t\t\t\t{\n\t\t\t\t\t\tfile_stream << \"Eidos test of the temporary directory\" << std::endl;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (!file_stream.bad())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfile_stream.close();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// test that we can delete the temp file\n\t\t\t\t\t\t\tif (remove(file_path.c_str()) == 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// passed all tests, so we consider that Eidos_TemporaryDirectory() exists\n\t\t\t\t\t\t\t\texists = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfree(file_path_cstr);\n\t\t\t\tfile_path_cstr = nullptr;\n\t\t\t}\n\t\t}\n\t\t\n\t\tbeen_here = true;\n\t}\n\t\n\treturn exists;\n}\n\n// Create a temporary file based upon a template filename; note that pattern is modified!\n\n// There is a function called mkstemps() on OS X, and on many Linux systems, but it is not\n// standard and so we can't rely on it being present.  It is also not clear that it has\n// exactly the same behavior on all systems where it is present.  So we use our own version\n// of the function, taken indirectly from the GNU C library.\n\n// This is based upon code from https://github.com/HSAFoundation/HSA-Debugger-GDB-Source-AMD/blob/master/gdb-7.8/libiberty/mkstemps.c\n// That code has the following license notice:\n\n/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc.\n This file is derived from mkstemp.c from the GNU C Library.\n The GNU C Library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Library General Public License as\n published by the Free Software Foundation; either version 2 of the\n License, or (at your option) any later version.\n The GNU C Library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n Library General Public License for more details.\n You should have received a copy of the GNU Library General Public\n License along with the GNU C Library; see the file COPYING.LIB.  If not,\n write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,\n Boston, MA 02110-1301, USA.  */\n\n// Since we are GPL anyway, there should be no problem with the inclusion of this code.\n\n/*\n @deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len})\n Generate a unique temporary file name from @var{pattern}.\n @var{pattern} has the form:\n @example\n @var{path}/ccXXXXXX@var{suffix}\n @end example\n @var{suffix_len} tells us how long @var{suffix} is (it can be zero\n length).  The last six characters of @var{pattern} before @var{suffix}\n must be @samp{XXXXXX}; they are replaced with a string that makes the\n filename unique.  Returns a file descriptor open on the file for\n reading and writing.\n @end deftypefn\n */\n\n#ifndef O_BINARY\n#define O_BINARY 0\n#endif\n\n#ifndef TMP_MAX_EIDOS\n#define TMP_MAX_EIDOS 16384\n#endif\n\nint Eidos_mkstemps(char *p_pattern, int p_suffix_len)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_mkstemps():  filesystem write\");\n\t\n\tstatic const char letters[] = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n\tstatic uint64_t value;\n\tsize_t len = strlen(p_pattern);\n\t\n\tif (((int)len < 6 + p_suffix_len) || (strncmp(&p_pattern[len - 6 - p_suffix_len], \"XXXXXX\", 6) != 0))\n\t\treturn -1;\n\t\n\tchar *XXXXXX = &p_pattern[len - 6 - p_suffix_len];\n\t\n\t// Get some more or less random data\n\tstruct timeval tv;\n\t\n\tgettimeofday(&tv, NULL);\n\tvalue += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();\n\t\n\tfor (int count = 0; count < TMP_MAX_EIDOS; ++count)\n\t{\n\t\tuint64_t v = value;\n\t\t\n\t\t// Fill in the random bits\n\t\tXXXXXX[0] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[1] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[2] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[3] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[4] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[5] = letters[v % 62];\n\t\t\n\t\tint fd = open(p_pattern, O_BINARY | O_RDWR | O_CREAT | O_EXCL, 0600);\n\t\t\n\t\tif (fd >= 0)\n\t\t\treturn fd;\t\t\t\t\t\t\t\t\t// The file did not already exist; we have created it\n\t\t\n\t\tif ((errno != EEXIST) && (errno != EISDIR))\t\t// Fatal error (EPERM, ENOSPC etc); doesn't make sense to loop\n\t\t\tbreak;\n\t\t\n\t\t// This is a random value.  It is only necessary that the next TMP_MAX_EIDOS\n\t\t// values generated by adding 7777 to value are different with (modulo 2^32).\n\t\tvalue += 7777;\n\t}\n\t\n\t// We return the null string if we can't find a unique file name\n\tp_pattern[0] = '\\0';\n\treturn -1;\n}\n\nint Eidos_mkstemps_directory(char *p_pattern, int p_suffix_len)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_mkstemps_directory():  filesystem write\");\n\t\n\tstatic const char letters[] = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n\tstatic uint64_t value;\n\tsize_t len = strlen(p_pattern);\n\t\n\tif (((int)len < 6 + p_suffix_len) || (strncmp(&p_pattern[len - 6 - p_suffix_len], \"XXXXXX\", 6) != 0))\n\t\treturn -1;\n\t\n\tchar *XXXXXX = &p_pattern[len - 6 - p_suffix_len];\n\t\n\t// Get some more or less random data\n\tstruct timeval tv;\n\t\n\tgettimeofday(&tv, NULL);\n\tvalue += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();\n\t\n\tfor (int count = 0; count < TMP_MAX_EIDOS; ++count)\n\t{\n\t\tuint64_t v = value;\n\t\t\n\t\t// Fill in the random bits\n\t\tXXXXXX[0] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[1] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[2] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[3] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[4] = letters[v % 62];\n\t\tv /= 62;\n\t\tXXXXXX[5] = letters[v % 62];\n\t\t\n\t\terrno = 0;\n\t\tint ret = mkdir(p_pattern, 0777);\n\t\t\n\t\tif (ret == 0)\n\t\t\treturn 0;\t\t\t\t// The directory did not already exist; we have created it\n\t\t\n\t\tif (errno != EEXIST)\t\t// Fatal error (EPERM, ENOSPC etc); doesn't make sense to loop\n\t\t\tbreak;\n\t\t\n\t\t// This is a random value.  It is only necessary that the next TMP_MAX_EIDOS\n\t\t// values generated by adding 7777 to value are different with (modulo 2^32).\n\t\tvalue += 7777;\n\t}\n\t\n\t// We return the null string if we can't find a unique file name\n\tp_pattern[0] = '\\0';\n\treturn -1;\n}\n\n#if EIDOS_BUFFER_ZIP_APPENDS\n// This contains all unflushed append data for zip files written by writeFile(); see Eidos_FlushFiles() below\nstd::unordered_map<std::string, std::string> gEidosBufferedZipAppendData;\n\n// This flushes the bytes in outstring to the file at file_path, with gzip append\n// If an error occurs, it returns false; it should not raise\nbool _Eidos_FlushZipBuffer(const std::string &file_path, const std::string &outstring)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"_Eidos_FlushZipBuffer():  filesystem write\");\n\t\n\t//std::cout << \"_Eidos_FlushZipBuffer() called for \" << file_path << std::endl;\n\t\n\tconst char *outcstr = outstring.c_str();\n\tsize_t outcstr_length = outstring.length();\n\t\n\tif (outcstr_length == 0)\n\t\treturn true;\n\t\n\tgzFile gzf = gzopen(file_path.c_str(), \"ab\");\n\t\n\tif (!gzf)\n\t{\n\t\t//std::cerr << \"errno == \" << errno << std::endl;\n\t\treturn false;\n\t}\n\t\n\t// do the writing with zlib\n\tint retval = gzbuffer(gzf, 128*1024L);\t// bigger buffer for greater speed\n\t\n\tif (retval == -1)\n\t\treturn false;\n\t\n\tretval = gzwrite(gzf, outcstr, (unsigned)outcstr_length);\n\t\n\tif (retval == 0)\n\t\treturn false;\n\t\n\tretval = gzclose_w(gzf);\n\t\n\tif (retval != Z_OK)\n\t\treturn false;\n\t\n\treturn true;\n}\n#endif\n\n// This flushes a given file, if it is buffering zip output\n// This raises if an error occurs\nvoid Eidos_FlushFile(const std::string &p_file_path)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_FlushFile():  filesystem write\");\n\t\n#if EIDOS_BUFFER_ZIP_APPENDS\n\tauto buffer_iter = gEidosBufferedZipAppendData.find(p_file_path);\n\t\n\tif (buffer_iter != gEidosBufferedZipAppendData.end())\n\t{\n\t\tbool result = _Eidos_FlushZipBuffer(buffer_iter->first, buffer_iter->second);\n\t\t\n\t\tif (!result)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_FlushFile): Flush of gzip data to file \" << buffer_iter->first << \" failed!\" << EidosTerminate(nullptr);\n\t\t\n\t\tgEidosBufferedZipAppendData.erase(buffer_iter);\n\t}\n#endif\n}\n\n// This flushes all outstanding buffered zip data to the appropriate files\n// This returns false if an error occurs\nbool Eidos_FlushFiles(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_FlushFiles():  filesystem write\");\n\t\n#if EIDOS_BUFFER_ZIP_APPENDS\n\t// Write out buffered data in gEidosBufferedZipAppendData to the appropriate files, using zlib's gzip append mode\n\tbool success = true;\n\t\n\tfor (auto &buffer_pair : gEidosBufferedZipAppendData)\n\t{\n\t\tbool result = _Eidos_FlushZipBuffer(buffer_pair.first, buffer_pair.second);\n\t\t\n\t\tif (!result)\n\t\t{\n\t\t\t// Note that we do this without a raise, because we often want to flush when we're already handling a raise,\n\t\t\t// and also we want to try to flush all of our files before halting, not halt on the first flush failure.\n\t\t\t// The caller should report the error to the user in some way, if this stderr log is insufficient.\n\t\t\tstd::cerr << std::endl << \"ERROR (Eidos_FlushFiles): Flush of gzip data to file \" << buffer_pair.first << \" failed!\" << std::endl;\n\t\t\tsuccess = false;\n\t\t}\n\t}\n\t\n\tgEidosBufferedZipAppendData.clear();\n\t\n\treturn success;\n#endif\n\t\n\treturn true;\n}\n\nvoid Eidos_WriteToFile(const std::string &p_file_path, const std::vector<const std::string *> &p_contents, bool p_append, bool p_compress, EidosFileFlush p_flush_option)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_WriteToFile():  filesystem write\");\n\t\n\t// note that we add a newline after the last line in all cases, so that appending new content to a file produces correct line breaks\n\t\n\tif (p_compress)\n\t{\n\t\t// compression using zlib; very different from the no-compression case, unfortunately, because here we use C-based APIs\n\t\t#if EIDOS_BUFFER_ZIP_APPENDS\n\t\tif (p_append)\n\t\t{\n\t\t\t// the append case gets handled by _Eidos_FlushZipBuffer() if EIDOS_BUFFER_ZIP_APPENDS is true\n\t\t\tauto buffer_iter = gEidosBufferedZipAppendData.find(p_file_path);\n\t\t\t\n\t\t\tif (buffer_iter == gEidosBufferedZipAppendData.end())\n\t\t\t\tbuffer_iter = gEidosBufferedZipAppendData.emplace(p_file_path, \"\").first;\n\t\t\t\n\t\t\tstd::string &buffer = buffer_iter->second;\n\t\t\t\n\t\t\t// append lines to the buffer; this copies bytes, which is a bit inefficient but shouldn't matter in the big picture\n\t\t\tfor (const std::string *content_line : p_contents)\n\t\t\t{\n\t\t\t\tbuffer.append(*content_line);\n\t\t\t\tbuffer.append(1, '\\n');\n\t\t\t}\n\t\t\t\n\t\t\t// if the buffer data exceeds a (somewhat arbitrary) 128K buffer maximum, write it out and remove the buffer entry\n\t\t\tif ((p_flush_option == EidosFileFlush::kForceFlush) ||\n\t\t\t\t((p_flush_option == EidosFileFlush::kDefaultFlush) && (buffer.length() > 1024L * 128L)))\n\t\t\t{\n\t\t\t\tbool result = _Eidos_FlushZipBuffer(p_file_path, buffer);\n\t\t\t\tgEidosBufferedZipAppendData.erase(buffer_iter);\n\t\t\t\t\n\t\t\t\tif (!result)\n\t\t\t\t\tEIDOS_TERMINATION << \"#ERROR (Eidos_WriteToFile): could not flush zip buffer to file at path \" << p_file_path << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t#endif\n\t\t{\n\t\t\t// this code can handle both the append and the non-append case, but the append case may generate very low-quality\n\t\t\t// compression (potentially even worse than the uncompressed data) due to having an excess of gzip headers\n\t\t\tgzFile gzf = gzopen(p_file_path.c_str(), p_append ? \"ab\" : \"wb\");\n\t\t\t\n\t\t\tif (!gzf)\n\t\t\t\tEIDOS_TERMINATION << \"#ERROR (Eidos_WriteToFile): could not write to file at path \" << p_file_path << \".\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tstd::ostringstream outstream;\n\t\t\t\n\t\t\tfor (const std::string *content_line : p_contents)\n\t\t\t\toutstream << *content_line << std::endl;\n\t\t\t\n\t\t\tstd::string outstring = outstream.str();\n\t\t\tconst char *outcstr = outstring.c_str();\n\t\t\tsize_t outcstr_length = strlen(outcstr);\n\t\t\t\n\t\t\t// do the writing with zlib\n\t\t\tbool failed = true;\n\t\t\tint retval = gzbuffer(gzf, 128*1024L);\t// bigger buffer for greater speed\n\t\t\t\n\t\t\tif (retval != -1)\n\t\t\t{\n\t\t\t\tretval = gzwrite(gzf, outcstr, (unsigned)outcstr_length);\n\t\t\t\t\n\t\t\t\tif ((retval != 0) || (outcstr_length == 0))\t// writing 0 bytes returns 0, which is supposed to be an error code\n\t\t\t\t{\n\t\t\t\t\tretval = gzclose_w(gzf);\n\t\t\t\t\t\n\t\t\t\t\tif (retval == Z_OK)\n\t\t\t\t\t\tfailed = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (failed)\n\t\t\t\tEIDOS_TERMINATION << \"#ERROR (Eidos_WriteToFile): encountered zlib errors while writing to file at path \" << p_file_path << \".\" << EidosTerminate(nullptr);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no compression\n\t\tstd::ofstream file_stream(p_file_path.c_str(), p_append ? (std::ios_base::app | std::ios_base::out) : std::ios_base::out);\n\t\t\n\t\tif (!file_stream.is_open())\n\t\t\tEIDOS_TERMINATION << \"#ERROR (Eidos_WriteToFile): could not write to file at path \" << p_file_path << \".\" << EidosTerminate(nullptr);\n\t\t\n\t\tfor (const std::string *content_line : p_contents)\n\t\t\tfile_stream << *content_line << std::endl;\n\t\t\n\t\tif (file_stream.bad())\n\t\t\tEIDOS_TERMINATION << \"#ERROR (Eidos_WriteToFile): encountered stream errors while writing to file at path \" << p_file_path << \".\" << EidosTerminate(nullptr);\n\t}\n}\n\n\n#pragma mark -\n#pragma mark Utility functions\n#pragma mark -\n\n// Welch's t-test.  This function returns the p-value for a two-sided unpaired Welch's\n// t-test between two samples.  The null hypothesis is that the means of the two samples\n// are not different.  If p < alpha, this null hypothesis is rejected, supporting the\n// alternative hypothesis that the two samples are drawn from different distributions.\n// As I understand it, that this code uses biased estimators of the variance and std.\n// deviation, presumably for simplicity and speed, so the results will be somewhat\n// inexact for small sample sizes.\n\n// This code is modified from WiggleTools ( https://github.com/Ensembl/WiggleTools ),\n// from https://github.com/Ensembl/WiggleTools/blob/master/src/setComparisons.c .\n// Thanks to EMBL-European Bioinformatics Institute for making this code available.\n\n// WiggleTools is licensed under the Apache 2.0 license\n// That license is compatible with the GPL 3.0 that we are licensed under, according\n// to https://www.apache.org/licenses/GPL-compatibility.html )\n// The original notice from WiggleTools follows:\n\n// Copyright [1999-2017] EMBL-European Bioinformatics Institute\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ndouble Eidos_TTest_TwoSampleWelch(const double *p_set1, int p_count1, const double *p_set2, int p_count2, double *p_set_mean1, double *p_set_mean2)\n{\n\tif ((p_count1 <= 1) || (p_count2 <= 1))\n\t{\n\t\tstd::cout << \"Eidos_TTest_TwoSampleWelch requires enough elements to compute variance\" << std::endl;\n\t\treturn NAN;\n\t}\n\t\n\t// Compute measurements\n\tdouble sum1 = 0, sum2 = 0, sumSq1 = 0, sumSq2 = 0;\n\tint index;\n\t\n\tfor (index = 0; index < p_count1; index++) {\n\t\tdouble value = p_set1[index];\n\t\t\n\t\tsum1 += value;\n\t\tsumSq1 += value * value;\n\t}\n\t\n\tfor (index = 0; index < p_count2; index++) {\n\t\tdouble value = p_set2[index];\n\t\t\n\t\tsum2 += value;\n\t\tsumSq2 += value * value;\n\t}\n\t\n\tdouble mean1 = sum1 / p_count1;\n\tdouble mean2 = sum2 / p_count2;\n\tdouble meanSq1 = sumSq1 / p_count1;\n\tdouble meanSq2 = sumSq2 / p_count2;\n\tdouble var1 = meanSq1 - mean1 * mean1;\n\tdouble var2 = meanSq2 - mean2 * mean2;\n\t\n\tif (p_set_mean1)\n\t\t*p_set_mean1 = mean1;\n\tif (p_set_mean2)\n\t\t*p_set_mean2 = mean2;\n\t\n\t// To avoid divisions by 0:\n\tif (var1 + var2 == 0)\n\t\treturn NAN;\n\t\n\t// two-sample test\n\tdouble t = (mean1 - mean2) / sqrt(var1 / p_count1 + var2 / p_count2);\n\t\n\tif (t < 0)\n\t\tt = -t;\n\t\n\tdouble nu = (var1 / p_count1 + var2 / p_count2) * (var1 / p_count1 + var2 / p_count2) / ((var1 * var1) / (p_count1 * p_count1 * (p_count1 - 1)) + (var2 * var2) / (p_count2 * p_count2 * (p_count2 - 1)));\n\t\n\t// return the P-value\n\treturn (std::isnan(t) ? t : 2 * gsl_cdf_tdist_Q(t, nu));\n}\n\n// This function returns a one-sample t-test, testing the null hypothesis that\n// the mean of the sample is equal to mu.  This code is obviously derived from\n// the code above, but was written by me in consultation with Wikipedia.\n\ndouble Eidos_TTest_OneSample(const double *p_set1, int p_count1, double p_mu, double *p_set_mean1)\n{\n\tif (p_count1 <= 1)\n\t{\n\t\tstd::cout << \"Eidos_TTest_OneSample requires enough elements to compute variance\" << std::endl;\n\t\treturn NAN;\n\t}\n\t\n\t// Compute measurements\n\tdouble sum1 = 0, sumSq1 = 0;\n\tint index;\n\t\n\tfor (index = 0; index < p_count1; index++) {\n\t\tdouble value = p_set1[index];\n\t\t\n\t\tsum1 += value;\n\t\tsumSq1 += value * value;\n\t}\n\t\n\tdouble mean1 = sum1 / p_count1;\n\tdouble meanSq1 = sumSq1 / p_count1;\n\tdouble var1 = meanSq1 - mean1 * mean1;\n\t\n\tif (p_set_mean1)\n\t\t*p_set_mean1 = mean1;\n\t\n\t// To avoid divisions by 0:\n\tif (var1 == 0)\n\t\treturn NAN;\n\t\n\t// one-sample test\n\tdouble t = (mean1 - p_mu) / (sqrt(var1) / sqrt(p_count1));\n\t\n\tif (t < 0)\n\t\tt = -t;\n\t\n\tdouble nu = p_count1 - 1;\n\t\n\t// return the P-value\n\treturn (std::isnan(t) ? t : 2 * gsl_cdf_tdist_Q(t, nu));\n}\n\n// This function uses an algorithm by Shewchuk (http://www.cs.berkeley.edu/~jrs/papers/robustr.pdf) to provide\n// an exact sum (within the precision limits of the double type) for a vector of double values.  This code is\n// adapted from source code in Python for its fsum() function, as implemented in the file mathmodule.c in the\n// math_fsum() C function, from Python version 3.6.2, downloaded from https://www.python.org/getit/source/.\n// The authors of that code appear to be Raymond Hettinger and Mark Dickinson; a big thank-you to them.\n// The PSF open-source license for Python 3.6.2, which the PSF states is GSL-compatible, may be found on their\n// website at https://docs.python.org/3.6/license.html.  Their license follows:\n\n/*\n\n1. This LICENSE AGREEMENT is between the Python Software Foundation (\"PSF\"), and\nthe Individual or Organization (\"Licensee\") accessing and otherwise using Python\n3.6.2 software in source or binary form and its associated documentation.\n\n2. Subject to the terms and conditions of this License Agreement, PSF hereby\ngrants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,\nanalyze, test, perform and/or display publicly, prepare derivative works,\ndistribute, and otherwise use Python 3.6.2 alone or in any derivative\nversion, provided, however, that PSF's License Agreement and PSF's notice of\ncopyright, i.e., \"Copyright © 2001-2017 Python Software Foundation; All Rights\nReserved\" are retained in Python 3.6.2 alone or in any derivative version\nprepared by Licensee.\n\n3. In the event Licensee prepares a derivative work that is based on or\nincorporates Python 3.6.2 or any part thereof, and wants to make the\nderivative work available to others as provided herein, then Licensee hereby\nagrees to include in any such work a brief summary of the changes made to Python\n3.6.2.\n\n4. PSF is making Python 3.6.2 available to Licensee on an \"AS IS\" basis.\nPSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.  BY WAY OF\nEXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR\nWARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE\nUSE OF PYTHON 3.6.2 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.\n\n5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.6.2\nFOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF\nMODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.6.2, OR ANY DERIVATIVE\nTHEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.\n\n6. This License Agreement will automatically terminate upon a material breach of\nits terms and conditions.\n\n7. Nothing in this License Agreement shall be deemed to create any relationship\nof agency, partnership, or joint venture between PSF and Licensee.  This License\nAgreement does not grant permission to use PSF trademarks or trade name in a\ntrademark sense to endorse or promote products or services of Licensee, or any\nthird party.\n\n8. By copying, installing or otherwise using Python 3.6.2, Licensee agrees\nto be bound by the terms and conditions of this License Agreement.\n\n*/\n\n// As to the \"brief summary of the changes made\" requested by their license, I have de-Pythoned their\n// code to make it work directly with a vector of doubles and return a double value; and I have changed\n// the way that the partials array is kept, now using a permanently allocated buffer grown with realloc();\n// and I have renamed the function; and I have removed some asserts and error checks; otherwise I have\n// tried to preserve their algorithm. The comments below are from the Python source.  BCH 3 August 2017.\n\n/* Precision summation function as msum() by Raymond Hettinger in\n <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/393090>,\n enhanced with the exact partials sum and roundoff from Mark\n Dickinson's post at <http://bugs.python.org/file10357/msum4.py>.\n See those links for more details, proofs and other references.\n \n Note 1: IEEE 754R floating point semantics are assumed,\n but the current implementation does not re-establish special\n value semantics across iterations (i.e. handling -Inf + Inf).\n \n Note 2:  No provision is made for intermediate overflow handling;\n therefore, sum([1e+308, 1e-308, 1e+308]) returns 1e+308 while\n sum([1e+308, 1e+308, 1e-308]) raises an OverflowError due to the\n overflow of the first partial sum.\n \n Note 3: The intermediate values lo, yr, and hi are declared volatile so\n aggressive compilers won't algebraically reduce lo to always be exactly 0.0.\n Also, the volatile declaration forces the values to be stored in memory as\n regular doubles instead of extended long precision (80-bit) values.  This\n prevents double rounding because any addition or subtraction of two doubles\n can be resolved exactly into double-sized hi and lo values.  As long as the\n hi value gets forced into a double before yr and lo are computed, the extra\n bits in downstream extended precision operations (x87 for example) will be\n exactly zero and therefore can be losslessly stored back into a double,\n thereby preventing double rounding.\n \n Note 4: A similar implementation is in Modules/cmathmodule.c.\n Be sure to update both when making changes.\n \n Note 5: The signature of math.fsum() differs from builtins.sum()\n because the start argument doesn't make sense in the context of\n accurate summation.  Since the partials table is collapsed before\n returning a result, sum(seq2, start=sum(seq1)) may not equal the\n accurate result returned by sum(itertools.chain(seq1, seq2)).\n */\n\n/* Full precision summation of a sequence of floats.\n \n\tdef msum(iterable):\n\t\tpartials = []  # sorted, non-overlapping partial sums\n\t\tfor x in iterable:\n\t\t\ti = 0\n\t\t\tfor y in partials:\n\t\t\t\tif abs(x) < abs(y):\n\t\t\t\t\tx, y = y, x\n\t\t\t\thi = x + y\n\t\t\t\tlo = y - (hi - x)\n\t\t\t\tif lo:\n\t\t\t\t\tpartials[i] = lo\n\t\t\t\t\ti += 1\n\t\t\t\tx = hi\n\t\t\tpartials[i:] = [x]\n\t\treturn sum_exact(partials)\n \n Rounded x+y stored in hi with the roundoff stored in lo.  Together hi+lo\n are exactly equal to x+y.  The inner loop applies hi/lo summation to each\n partial so that the list of partial sums remains exact.\n \n Sum_exact() adds the partial sums exactly and correctly rounds the final\n result (using the round-half-to-even rule).  The items in partials remain\n non-zero, non-special, non-overlapping and strictly increasing in\n magnitude, but possibly not all having the same sign.\n \n Depends on IEEE 754 arithmetic guarantees and half-even rounding.\n */\n\ndouble Eidos_ExactSum(const double *p_double_vec, int64_t p_vec_length)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_ExactSum(): usage of statics\");\n\t\n\t// We allocate the partials using malloc() rather than initially using the stack,\n\t// and keep the allocated block around forever; simpler if a bit less efficient.\n\tstatic double *p = nullptr;\t\t// partials array\n\tstatic int m = 0;\t\t\t\t// size of partials array\n\t\n\tif (m == 0)\n\t{\n\t\tm = 32;\t\t\t// this is NUM_PARTIALS in the Python code\n\t\tp = (double *)malloc(m * sizeof(double));\n\t\tif (!p)\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExactSum): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tint i, j, n = 0;\n\tdouble x, y;\n\tdouble xsave, special_sum = 0.0, inf_sum = 0.0;\n\tvolatile double hi, yr, lo = 0.0;\t\t// see comment above re: volatile; added initializer to get rid of a false warning\n\t\n\tfor (int64_t vec_index = 0; vec_index < p_vec_length; ++vec_index)\n\t{\n\t\t//assert(0 <= n && n <= m);\n\t\t\n\t\tx = p_double_vec[vec_index];\n\t\t\n\t\txsave = x;\n\t\tfor (i = j = 0; j < n; j++) {       /* for y in partials */\n\t\t\ty = p[j];\n\t\t\tif (fabs(x) < fabs(y))\n\t\t\t\tstd::swap(x, y);\n\t\t\thi = x + y;\n\t\t\tyr = hi - x;\n\t\t\tlo = y - yr;\n\t\t\tif (lo != 0.0)\n\t\t\t\tp[i++] = lo;\n\t\t\tx = hi;\n\t\t}\n\t\t\n\t\tn = i;                              /* ps[i:] = [x] */\n\t\tif (x != 0.0) {\n\t\t\tif (!std::isfinite(x)) {\n\t\t\t\t/* a nonfinite x could arise either as\n\t\t\t\t a result of intermediate overflow, or\n\t\t\t\t as a result of a nan or inf in the\n\t\t\t\t summands */\n\t\t\t\tif (std::isfinite(xsave))\n\t\t\t\t{\n\t\t\t\t\t// Python returns some sort of error object in this case; we throw\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExactSum): intermediate overflow in Eidos_ExactSum().\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (std::isinf(xsave))\n\t\t\t\t\tinf_sum += xsave;\n\t\t\t\tspecial_sum += xsave;\n\t\t\t\t/* reset partials */\n\t\t\t\tn = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (n >= m)\n\t\t\t\t{\n\t\t\t\t\tm = m * 2;\n\t\t\t\t\tp = (double *)realloc(p, m * sizeof(double));\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\t\t\t\tif (!p)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExactSum): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tp[n++] = x;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (special_sum != 0.0) {\n\t\tif (std::isnan(inf_sum))\n\t\t{\n\t\t\t// Python returns some sort of error object in this case; we throw\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ExactSum): -inf + inf in Eidos_ExactSum().\" << EidosTerminate(nullptr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn special_sum;\n\t\t}\n\t}\n\t\n\thi = 0.0;\n\tif (n > 0) {\n\t\thi = p[--n];\n\t\t/* sum_exact(ps, hi) from the top, stop when the sum becomes\n\t\t inexact. */\n\t\twhile (n > 0) {\n\t\t\tx = hi;\n\t\t\ty = p[--n];\n\t\t\t//assert(fabs(y) < fabs(x));\n\t\t\thi = x + y;\n\t\t\tyr = hi - x;\n\t\t\tlo = y - yr;\n\t\t\tif (lo != 0.0)\n\t\t\t\tbreak;\n\t\t}\n\t\t/* Make half-even rounding work across multiple partials.\n\t\t Needed so that sum([1e-16, 1, 1e16]) will round-up the last\n\t\t digit to two instead of down to zero (the 1e-16 makes the 1\n\t\t slightly closer to two).  With a potential 1 ULP rounding\n\t\t error fixed-up, math.fsum() can guarantee commutativity. */\n\t\tif (n > 0 && ((lo < 0.0 && p[n-1] < 0.0) ||\n\t\t\t\t\t  (lo > 0.0 && p[n-1] > 0.0))) {\n\t\t\ty = lo * 2.0;\n\t\t\tx = hi + y;\n\t\t\tyr = x - hi;\n\t\t\tif (y == yr)\n\t\t\t\thi = x;\n\t\t}\n\t}\n\treturn hi;\n}\n\nbool Eidos_ApproximatelyEqual(double a, double b)\n{\n\t// different signs is a mismatch\n\tif (std::signbit(a) != std::signbit(b))\n\t\treturn false;\n\t\n\t// both zero is not a mismatch (getting rid of this case for div-by-zero safety\n\tif ((a == 0) && (b == 0))\n\t\treturn true;\n\t\n\t// one zero (and one not) is a mismatch\n\tif ((a == 0) || (b == 0))\n\t\treturn false;\n\t\n\t// one significantly bigger is a mismatch\n\tif (a / b > 1.0001)\n\t\treturn false;\n\t\n\t// the other significantly bigger is a mismatch\n\tif (b / a > 1.0001)\n\t\treturn false;\n\t\n\treturn true;\n}\n\nstd::vector<std::string> Eidos_string_split(const std::string &joined_string, const std::string &separator)\n{\n\tstd::vector<std::string> tokens;\n\tstd::string::size_type start_idx = 0, sep_idx;\n\t\n\tif (separator.length() == 0)\n\t{\n\t\t// special-case a zero-length separator\n\t\tfor (const char &ch : joined_string)\n\t\t\ttokens.emplace_back(&ch, 1);\n\t}\n\telse\n\t{\n\t\t// non-zero-length separator\n\t\twhile (true)\n\t\t{\n\t\t\tsep_idx = joined_string.find(separator, start_idx);\n\t\t\t\n\t\t\tif (sep_idx == std::string::npos)\n\t\t\t{\n\t\t\t\ttokens.emplace_back(joined_string.substr(start_idx));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttokens.emplace_back(joined_string.substr(start_idx, sep_idx - start_idx));\n\t\t\t\tstart_idx = sep_idx + separator.size();\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn tokens;\n}\n\nstd::string Eidos_string_join(const std::vector<std::string> &p_vec, const std::string &p_delim)\n{\n\tstd::string result;\n\tsize_t vec_size = p_vec.size();\n\t\n\tfor (size_t i = 0; i < vec_size; ++i)\n\t{\n\t\tif (i > 0)\n\t\t\tresult.append(p_delim);\n\t\tresult.append(p_vec[i]);\n\t}\n\t\n\treturn result;\n}\n\n// thanks to https://stackoverflow.com/a/874160/2752221\nbool Eidos_string_hasPrefix(std::string const &fullString, std::string const &prefix)\n{\n\tif (fullString.length() >= prefix.length()) {\n\t\treturn (0 == fullString.compare(0, prefix.length(), prefix));\n\t} else {\n\t\treturn false;\n\t}\n}\n\n// thanks to https://stackoverflow.com/a/874160/2752221\nbool Eidos_string_hasSuffix(std::string const &fullString, std::string const &suffix)\n{\n\tif (fullString.length() >= suffix.length()) {\n\t\treturn (0 == fullString.compare(fullString.length() - suffix.length(), suffix.length(), suffix));\n\t} else {\n\t\treturn false;\n\t}\n}\n\n// case-insensitive string find and string equality; see https://stackoverflow.com/a/19839371/2752221\nbool Eidos_string_containsCaseInsensitive(const std::string &strHaystack, const std::string &strNeedle)\n{\n\tauto it = std::search(\n\t\t\t\t\t\t  strHaystack.begin(), strHaystack.end(),\n\t\t\t\t\t\t  strNeedle.begin(),   strNeedle.end(),\n\t\t\t\t\t\t  [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }\n\t\t\t\t\t\t  );\n\treturn (it != strHaystack.end() );\n}\n\nbool Eidos_string_equalsCaseInsensitive(const std::string &s1, const std::string &s2)\n{\n\tif (s1.length() != s2.length())\n\t\treturn false;\n\t\n\treturn Eidos_string_containsCaseInsensitive(s1, s2);\n}\n\n// quotes and adds backslash escapes\nstd::string Eidos_string_escaped(const std::string &unescapedString, EidosStringQuoting quoting)\n{\n\tbool use_single_quote = false, use_double_quote = false;\n\t\n\tif (quoting == EidosStringQuoting::kDoubleQuotes)\n\t\tuse_double_quote = true;\n\telse if (quoting == EidosStringQuoting::kSingleQuotes)\n\t\tuse_single_quote = true;\n\telse if (quoting == EidosStringQuoting::kChooseQuotes)\n\t{\n\t\tif (unescapedString.find('\"') != std::string::npos)\n\t\t\tuse_single_quote = true;\n\t\telse\n\t\t\tuse_double_quote = true;\n\t}\n\t\n\tstd::string escapedString;\n\t\n\t// add the opening quote\n\tif (use_single_quote)\n\t\tescapedString = '\\'';\n\telse if (use_double_quote)\n\t\tescapedString = '\"';\n\t\n\t// add characters from unquotedString one by one, escaping them if necessary; we do not do arbitrary unicode or control-character escapes\n\tfor (char ch : unescapedString)\n\t{\n\t\tif (ch == '\\r')\n\t\t\tescapedString += \"\\\\r\";\n\t\telse if (ch == '\\n')\n\t\t\tescapedString += \"\\\\n\";\n\t\telse if (ch == '\\t')\n\t\t\tescapedString += \"\\\\t\";\n\t\telse if (ch == '\\\\')\n\t\t\tescapedString += \"\\\\\\\\\";\n\t\telse if ((ch == '\\\"') && use_double_quote)\t\t// only escape double quotes if the exterior quotes are double\n\t\t\tescapedString += \"\\\\\\\"\";\n\t\telse if ((ch == '\\'') && use_single_quote)\t\t// only escape single quotes if the exterior quotes are single\n\t\t\tescapedString += \"\\\\\\'\";\n\t\telse\n\t\t\tescapedString += ch;\n\t}\n\t\n\t// add the closing quote\n\tif (use_single_quote)\n\t\tescapedString += '\\'';\n\telse if (use_double_quote)\n\t\tescapedString += '\"';\n\t\n\treturn escapedString;\n}\n\n// quotes and \"\"-escapes quotes\nstd::string Eidos_string_escaped_CSV(const std::string &unescapedString)\n{\n\tstd::string escapedString;\n\t\n\tescapedString = '\"';\n\t\n\t// add characters from unquotedString one by one, escaping them if necessary; for CSV we only escape double quotes\n\tfor (char ch : unescapedString)\n\t{\n\t\tif (ch == '\\\"')\n\t\t\tescapedString += \"\\\"\\\"\";\t// a single \" turns into \"\", in the CSV quoting style\n\t\telse\n\t\t\tescapedString += ch;\n\t}\n\t\n\t// add the closing quote\n\tescapedString += '\"';\n\t\n\treturn escapedString;\n}\n\n// run a Un*x command; thanks to http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix\n/*std::string Eidos_Exec(const char *p_cmd)\n{\n\tchar buffer[128];\n\tstd::string result = \"\";\n\tstd::shared_ptr<FILE> command_pipe(popen(p_cmd, \"r\"), pclose);\n\tif (!command_pipe) throw std::runtime_error(\"popen() failed!\");\n\twhile (!feof(command_pipe.get())) {\n\t\tif (fgets(buffer, 128, command_pipe.get()) != NULL)\n\t\t\tresult += buffer;\n\t}\n\treturn result;\n}*/\n\nstd::string EidosStringForFloat(double p_value)\n{\n\t// Customize our output a bit to look like Eidos, not C++\n\tif (std::isinf(p_value))\n\t{\n\t\tif (std::signbit(p_value))\n\t\t\treturn gEidosStr_MINUS_INF;\n\t\telse\n\t\t\treturn gEidosStr_INF;\n\t}\n\telse if (std::isnan(p_value))\n\t\treturn gEidosStr_NAN;\n\telse\n\t{\n\t\t// could probably use std::to_string() instead, but need to think about precision etc.\n\t\tstd::ostringstream ss;\n\t\tss << std::setprecision(gEidosFloatOutputPrecision);\n\t\tss << p_value;\n\t\tstd::string string_value = ss.str();\n\t\t\n\t\t// BCH 10/13/2021: I'd like float values to always print with a decimal point.  This is a change in\n\t\t// behavior in Eidos 2.7 (SLiM 3.7), but it seems unlikely to bite anybody – the opposite, really,\n\t\t// since it increases clarity and consistency.  So now we look for a decimal point in the float,\n\t\t// and if there is none, we append \".0\".  We also need to worry about scientific notation; if there\n\t\t// is an \"e\" or \"E\", we insert the \".0\" just before that to produce 1.0e30 rather than 1e30.\n\t\t// BCH 4/8/2026: Well, I messed this up, and didn't catch it for 4.5 years (and nobody else noticed\n\t\t// it either).  I've added some unit tests for this so hopefully it will be correct this time.\n\t\tif (string_value.find('.') == std::string::npos)\n\t\t{\n\t\t\tsize_t e_pos = string_value.find_first_of(\"eE\");\n\t\t\t\n\t\t\tif (e_pos == std::string::npos)\n\t\t\t{\n\t\t\t\t// BCH 4/8/2026: if a decimal point and digit was not output, and scientific notation was\n\t\t\t\t// not used, force an extra digit of precision in fixed-point.  This might result in an\n\t\t\t\t// extra digit of precision being output, beyond gEidosFloatOutputPrecision; the alternative\n\t\t\t\t// would be to flip to scientific notation, but it's harder to decide when to do that.\n\t\t\t\tss.str(\"\");\n\t\t\t\tss << std::fixed << std::setprecision(1) << p_value;\n\t\t\t\tstring_value = ss.str();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// BCH 4/8/2026: if a decimal point and digit was not output, and scientific notation was used,\n\t\t\t\t// as far as I can see that means the digit after the decimal place must be 0, since the way\n\t\t\t\t// that C++ handles scientific notation there would only be one digit in the mantissa, like\n\t\t\t\t// \"1e6\"; if it were anything but \"1.0e6\" the extra digit would have been emitted.\n\t\t\t\tstring_value.insert(e_pos, \".0\");\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn string_value;\n\t}\n}\n\nint DisplayDigitsForIntegerPart(double x)\n{\n\t// This function just uses log10 to give the number of digits needed to display the integer part of a double.\n\t// The reason it's split out into a function is that the result, for x==0, is -inf, and we want to return 1.\n\tdouble digits = ceil(log10(floor(x)));\n\t\n\tif (std::isfinite(digits))\n\t\treturn (int)digits;\n\treturn 1;\n}\n\nbool Eidos_RegexWorks(void)\n{\n\t// check whether <regex> works, because on some platforms it doesn't (!); test just once and cache the result\n\tstatic bool beenHere = false;\n\tstatic bool regex_works = false;\n\t\n#pragma omp critical (Eidos_RegexWorks)\n\t{\n\t\tif (!beenHere)\n\t\t{\n\t\t\tstd::regex pattern_regex(\"cd\", std::regex_constants::ECMAScript);\n\t\t\tstd::string x_element = \"bcd\";\n\t\t\tstd::smatch match_info;\n\t\t\tbool is_match = std::regex_search(x_element, match_info, pattern_regex);\n\t\t\t\n\t\t\tregex_works = is_match;\n\t\t\tbeenHere = true;\n\t\t}\n\t}\n\t\n\treturn regex_works;\n}\n\nbool Eidos_ContainsIllegalUnicode(const std::string &symbol_name)\n{\n\tbool contains_illegal = false;\n\t\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunknown-warning-option\"\n#pragma GCC diagnostic ignored \"-Wbidi-chars\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-warning-option\"\n#pragma clang diagnostic ignored \"-Wbidi-chars\"\n\t// BCH 8/14/2023: Note that seven lines are commented out below.  They are correct, but they\n\t// produce a warning \"unpaired UTF-8 bidirectional control character detected [-Wbidi-chars=]\",\n\t// and disabling the bidi-chars warning does not suppress that warning, annoyingly.  This is\n\t// very edge anyhow, so I'm commenting these lines out for now.  A better fix should be\n\t// possible, but it doesn't seem worth worrying about for now.\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2000\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2001\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2002\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2003\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2004\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2005\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2006\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2007\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2008\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2009\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200a\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200b\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200c\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200d\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200e\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u200f\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2028\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2029\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u202a\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u202b\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u202c\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u202d\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u202e\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u202f\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u205f\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2060\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2061\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2062\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2063\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2064\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2065\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u2066\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u2067\") != std::string::npos);\n\t//contains_illegal = contains_illegal || (symbol_name.find(\"\\u2068\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u2069\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206a\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206b\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206c\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206d\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206e\") != std::string::npos);\n\tcontains_illegal = contains_illegal || (symbol_name.find(\"\\u206f\") != std::string::npos);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\t\n\treturn contains_illegal;\n}\n\n\n// *******************************************************************************************************************\n//\n//\tSHA-256\n//\n\n// This code is from https://github.com/amosnier/sha-2 which is under the public-domain \"unlicense\".\n// Thanks to Alain Mosnier for this code.  License follows:\n\n/*\n\nThis is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <http://unlicense.org>\n\n*/\n\n#pragma mark -\n#pragma mark SHA-256\n#pragma mark -\n\n#define CHUNK_SIZE 64\n#define TOTAL_LEN_LEN 8\n\n/*\n * ABOUT bool: this file does not use bool in order to be as pre-C99 compatible as possible.\n */\n\n/*\n * Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here.\n * When useful for clarification, portions of the pseudo-code are reproduced here too.\n */\n\n/*\n * Initialize array of round constants:\n * (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):\n */\nstatic const uint32_t SHA_k[] = {\n\t0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n\t0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n\t0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n\t0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n\t0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n\t0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n\t0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n\t0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n};\n\nstruct SHA_buffer_state {\n\tconst uint8_t * p;\n\tsize_t len;\n\tsize_t total_len;\n\tint single_one_delivered; /* bool */\n\tint total_len_delivered; /* bool */\n};\n\nstatic inline uint32_t right_rot(uint32_t value, unsigned int count)\n{\n\t/*\n\t * Defined behaviour in standard C for all count where 0 < count < 32,\n\t * which is what we need here.\n\t */\n\treturn value >> count | value << (32 - count);\n}\n\nstatic void init_buf_state(struct SHA_buffer_state * state, const void * input, size_t len)\n{\n\tstate->p = static_cast<const uint8_t *>(input);\n\tstate->len = len;\n\tstate->total_len = len;\n\tstate->single_one_delivered = 0;\n\tstate->total_len_delivered = 0;\n}\n\n/* Return value: bool */\nstatic int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct SHA_buffer_state * state)\n{\n\tsize_t space_in_chunk;\n\n\tif (state->total_len_delivered) {\n\t\treturn 0;\n\t}\n\n\tif (state->len >= CHUNK_SIZE) {\n\t\tmemcpy(chunk, state->p, CHUNK_SIZE);\n\t\tstate->p += CHUNK_SIZE;\n\t\tstate->len -= CHUNK_SIZE;\n\t\treturn 1;\n\t}\n\n\tmemcpy(chunk, state->p, state->len);\n\tchunk += state->len;\n\tspace_in_chunk = CHUNK_SIZE - state->len;\n\tstate->p += state->len;\n\tstate->len = 0;\n\n\t/* If we are here, space_in_chunk is one at minimum. */\n\tif (!state->single_one_delivered) {\n\t\t*chunk++ = 0x80;\n\t\tspace_in_chunk -= 1;\n\t\tstate->single_one_delivered = 1;\n\t}\n\n\t/*\n\t * Now:\n\t * - either there is enough space left for the total length, and we can conclude,\n\t * - or there is too little space left, and we have to pad the rest of this chunk with zeroes.\n\t * In the latter case, we will conclude at the next invokation of this function.\n\t */\n\tif (space_in_chunk >= TOTAL_LEN_LEN) {\n\t\tconst size_t left = space_in_chunk - TOTAL_LEN_LEN;\n\t\tsize_t len = state->total_len;\n\t\tint i;\n\t\tmemset(chunk, 0x00, left);\n\t\tchunk += left;\n\n\t\t/* Storing of len * 8 as a big endian 64-bit without overflow. */\n\t\tchunk[7] = (uint8_t) (len << 3);\n\t\tlen >>= 5;\n\t\tfor (i = 6; i >= 0; i--) {\n\t\t\tchunk[i] = (uint8_t) len;\n\t\t\tlen >>= 8;\n\t\t}\n\t\tstate->total_len_delivered = 1;\n\t} else {\n\t\tmemset(chunk, 0x00, space_in_chunk);\n\t}\n\n\treturn 1;\n}\n\n/*\n * Limitations:\n * - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem\n *   for large data sizes.\n * - SHA algorithms theoretically operate on bit strings. However, this implementation has no support\n *   for bit string lengths that are not multiples of eight, and it really operates on arrays of bytes.\n *   In particular, the len parameter is a number of bytes.\n */\nvoid Eidos_calc_sha_256(uint8_t hash[32], const void *input, size_t len)\n{\n\t/*\n\t * Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32.\n\t * Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63\n\t * Note 3: The compression function uses 8 working variables, a through h\n\t * Note 4: Big-endian convention is used when expressing the constants in this pseudocode,\n\t *     and when parsing message block data from bytes to words, for example,\n\t *     the first word of the input message \"abc\" after padding is 0x61626380\n\t */\n\n\t/*\n\t * Initialize hash values:\n\t * (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):\n\t */\n\tuint32_t h[] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };\n\tunsigned i, j;\n\n\t/* 512-bit chunks is what we will operate on. */\n\tuint8_t chunk[64];\n\n\tstruct SHA_buffer_state state;\n\n\tinit_buf_state(&state, input, len);\n\n\twhile (calc_chunk(chunk, &state)) {\n\t\tuint32_t ah[8];\n\n\t\tconst uint8_t *p = chunk;\n\n\t\t/* Initialize working variables to current hash value: */\n\t\tfor (i = 0; i < 8; i++)\n\t\t\tah[i] = h[i];\n\n\t\t/* Compression function main loop: */\n\t\tfor (i = 0; i < 4; i++) {\n\t\t\t/*\n\t\t\t * The w-array is really w[64], but since we only need\n\t\t\t * 16 of them at a time, we save stack by calculating\n\t\t\t * 16 at a time.\n\t\t\t *\n\t\t\t * This optimization was not there initially and the\n\t\t\t * rest of the comments about w[64] are kept in their\n\t\t\t * initial state.\n\t\t\t */\n\n\t\t\t/*\n\t\t\t * create a 64-entry message schedule array w[0..63] of 32-bit words\n\t\t\t * (The initial values in w[0..63] don't matter, so many implementations zero them here)\n\t\t\t * copy chunk into first 16 words w[0..15] of the message schedule array\n\t\t\t */\n\t\t\tuint32_t w[16];\n\n\t\t\tfor (j = 0; j < 16; j++) {\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tw[j] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16 |\n\t\t\t\t\t\t(uint32_t) p[2] << 8 | (uint32_t) p[3];\n\t\t\t\t\tp += 4;\n\t\t\t\t} else {\n\t\t\t\t\t/* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */\n\t\t\t\t\tconst uint32_t s0 = right_rot(w[(j + 1) & 0xf], 7) ^ right_rot(w[(j + 1) & 0xf], 18) ^ (w[(j + 1) & 0xf] >> 3);\n\t\t\t\t\tconst uint32_t s1 = right_rot(w[(j + 14) & 0xf], 17) ^ right_rot(w[(j + 14) & 0xf], 19) ^ (w[(j + 14) & 0xf] >> 10);\n\t\t\t\t\tw[j] = w[j] + s0 + w[(j + 9) & 0xf] + s1;\n\t\t\t\t}\n\t\t\t\tconst uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25);\n\t\t\t\tconst uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]);\n\t\t\t\tconst uint32_t temp1 = ah[7] + s1 + ch + SHA_k[i << 4 | j] + w[j];\n\t\t\t\tconst uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22);\n\t\t\t\tconst uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]);\n\t\t\t\tconst uint32_t temp2 = s0 + maj;\n\n\t\t\t\tah[7] = ah[6];\n\t\t\t\tah[6] = ah[5];\n\t\t\t\tah[5] = ah[4];\n\t\t\t\tah[4] = ah[3] + temp1;\n\t\t\t\tah[3] = ah[2];\n\t\t\t\tah[2] = ah[1];\n\t\t\t\tah[1] = ah[0];\n\t\t\t\tah[0] = temp1 + temp2;\n\t\t\t}\n\t\t}\n\n\t\t/* Add the compressed chunk to the current hash value: */\n\t\tfor (i = 0; i < 8; i++)\n\t\t\th[i] += ah[i];\n\t}\n\n\t/* Produce the final hash value (big-endian): */\n\tfor (i = 0, j = 0; i < 8; i++)\n\t{\n\t\thash[j++] = (uint8_t) (h[i] >> 24);\n\t\thash[j++] = (uint8_t) (h[i] >> 16);\n\t\thash[j++] = (uint8_t) (h[i] >> 8);\n\t\thash[j++] = (uint8_t) h[i];\n\t}\n}\n\n#undef CHUNK_SIZE\n#undef TOTAL_LEN_LEN\n\nvoid Eidos_hash_to_string(char string[65], const uint8_t hash[32])\n{\n\tsize_t i;\n\tsize_t buf_left = 65;\n\t\n\tfor (i = 0; i < 32; i++) {\n\t\tstring += snprintf(string, buf_left, \"%02x\", hash[i]);\n\t\tbuf_left -= 2;\n\t}\n}\t\n\n\n#pragma mark -\n#pragma mark Global strings & IDs\n#pragma mark -\n\n//\tGlobal std::string objects.\nconst std::string &gEidosStr_empty_string = EidosRegisteredString(\"\", gEidosID_empty_string);\nconst std::string &gEidosStr_space_string = EidosRegisteredString(\" \", gEidosID_space_string);\n\n// mostly function names used in multiple places\nconst std::string &gEidosStr_apply = EidosRegisteredString(\"apply\", gEidosID_apply);\nconst std::string &gEidosStr_sapply = EidosRegisteredString(\"sapply\", gEidosID_sapply);\nconst std::string &gEidosStr_doCall = EidosRegisteredString(\"doCall\", gEidosID_doCall);\nconst std::string &gEidosStr_executeLambda = EidosRegisteredString(\"executeLambda\", gEidosID_executeLambda);\nconst std::string &gEidosStr__executeLambda_OUTER = EidosRegisteredString(\"_executeLambda_OUTER\", gEidosID__executeLambda_OUTER);\nconst std::string &gEidosStr_ls = EidosRegisteredString(\"ls\", gEidosID_ls);\nconst std::string &gEidosStr_rm = EidosRegisteredString(\"rm\", gEidosID_rm);\nconst std::string &gEidosStr_usage = EidosRegisteredString(\"usage\", gEidosID_usage);\n\n// mostly language keywords\nconst std::string &gEidosStr_if = EidosRegisteredString(\"if\", gEidosID_if);\nconst std::string &gEidosStr_else = EidosRegisteredString(\"else\", gEidosID_else);\nconst std::string &gEidosStr_do = EidosRegisteredString(\"do\", gEidosID_do);\nconst std::string &gEidosStr_while = EidosRegisteredString(\"while\", gEidosID_while);\nconst std::string &gEidosStr_for = EidosRegisteredString(\"for\", gEidosID_for);\nconst std::string &gEidosStr_in = EidosRegisteredString(\"in\", gEidosID_in);\nconst std::string &gEidosStr_next = EidosRegisteredString(\"next\", gEidosID_next);\nconst std::string &gEidosStr_break = EidosRegisteredString(\"break\", gEidosID_break);\nconst std::string &gEidosStr_return = EidosRegisteredString(\"return\", gEidosID_return);\nconst std::string &gEidosStr_function = EidosRegisteredString(\"function\", gEidosID_function);\n\n// mostly Eidos global constants\nconst std::string &gEidosStr_T = EidosRegisteredString(\"T\", gEidosID_T);\nconst std::string &gEidosStr_F = EidosRegisteredString(\"F\", gEidosID_F);\nconst std::string &gEidosStr_NULL = EidosRegisteredString(\"NULL\", gEidosID_NULL);\nconst std::string &gEidosStr_PI = EidosRegisteredString(\"PI\", gEidosID_PI);\nconst std::string &gEidosStr_E = EidosRegisteredString(\"E\", gEidosID_E);\nconst std::string &gEidosStr_INF = EidosRegisteredString(\"INF\", gEidosID_INF);\nconst std::string &gEidosStr_MINUS_INF = EidosRegisteredString(\"-INF\", gEidosID_MINUS_INF);\nconst std::string &gEidosStr_NAN = EidosRegisteredString(\"NAN\", gEidosID_NAN);\n\n// mostly Eidos type names\nconst std::string &gEidosStr_void = EidosRegisteredString(\"void\", gEidosID_void);\nconst std::string &gEidosStr_logical = EidosRegisteredString(\"logical\", gEidosID_logical);\nconst std::string &gEidosStr_string = EidosRegisteredString(\"string\", gEidosID_string);\nconst std::string &gEidosStr_integer = EidosRegisteredString(\"integer\", gEidosID_integer);\nconst std::string &gEidosStr_float = EidosRegisteredString(\"float\", gEidosID_float);\nconst std::string &gEidosStr_object = EidosRegisteredString(\"object\", gEidosID_object);\nconst std::string &gEidosStr_numeric = EidosRegisteredString(\"numeric\", gEidosID_numeric);\n\n// other miscellaneous strings\nconst std::string &gEidosStr_ELLIPSIS = EidosRegisteredString(\"...\", gEidosID_ELLIPSIS);\nconst std::string &gEidosStr_type = EidosRegisteredString(\"type\", gEidosID_type);\nconst std::string &gEidosStr_source = EidosRegisteredString(\"source\", gEidosID_source);\nconst std::string &gEidosStr_GetPropertyOfElements = EidosRegisteredString(\"GetPropertyOfElements\", gEidosID_GetPropertyOfElements);\nconst std::string &gEidosStr_ExecuteInstanceMethod = EidosRegisteredString(\"ExecuteInstanceMethod\", gEidosID_ExecuteInstanceMethod);\nconst std::string &gEidosStr_undefined = EidosRegisteredString(\"undefined\", gEidosID_undefined);\nconst std::string &gEidosStr_applyValue = EidosRegisteredString(\"applyValue\", gEidosID_applyValue);\n\n// strings for EidosObject\nconst std::string &gEidosStr_Object = EidosRegisteredString(\"Object\", gEidosID_Object);\nconst std::string &gEidosStr_size = EidosRegisteredString(\"size\", gEidosID_size);\nconst std::string &gEidosStr_length = EidosRegisteredString(\"length\", gEidosID_length);\nconst std::string &gEidosStr_methodSignature = EidosRegisteredString(\"methodSignature\", gEidosID_methodSignature);\nconst std::string &gEidosStr_propertySignature = EidosRegisteredString(\"propertySignature\", gEidosID_propertySignature);\nconst std::string &gEidosStr_str = EidosRegisteredString(\"str\", gEidosID_str);\nconst std::string &gEidosStr_stringRepresentation = EidosRegisteredString(\"stringRepresentation\", gEidosID_stringRepresentation);\n\n// strings for EidosTestElement\nconst std::string &gEidosStr__TestElement = EidosRegisteredString(\"_TestElement\", gEidosID__TestElement);\nconst std::string &gEidosStr__TestElementNRR = EidosRegisteredString(\"_TestElementNRR\", gEidosID__TestElementNRR);\nconst std::string &gEidosStr__yolk = EidosRegisteredString(\"_yolk\", gEidosID__yolk);\nconst std::string &gEidosStr__increment = EidosRegisteredString(\"_increment\", gEidosID__increment);\nconst std::string &gEidosStr__cubicYolk = EidosRegisteredString(\"_cubicYolk\", gEidosID__cubicYolk);\nconst std::string &gEidosStr__squareTest = EidosRegisteredString(\"_squareTest\", gEidosID__squareTest);\n\n// strings for Dictionary (i.e., for EidosDictionaryUnretained, but also inherited by EidosDictionaryRetained)\nconst std::string &gEidosStr_Dictionary = EidosRegisteredString(\"Dictionary\", gEidosID_Dictionary);\nconst std::string &gEidosStr_allKeys = EidosRegisteredString(\"allKeys\", gEidosID_allKeys);\nconst std::string &gEidosStr_addKeysAndValuesFrom = EidosRegisteredString(\"addKeysAndValuesFrom\", gEidosID_addKeysAndValuesFrom);\nconst std::string &gEidosStr_appendKeysAndValuesFrom = EidosRegisteredString(\"appendKeysAndValuesFrom\", gEidosID_appendKeysAndValuesFrom);\nconst std::string &gEidosStr_clearKeysAndValues = EidosRegisteredString(\"clearKeysAndValues\", gEidosID_clearKeysAndValues);\nconst std::string &gEidosStr_compactIndices = EidosRegisteredString(\"compactIndices\", gEidosID_compactIndices);\nconst std::string &gEidosStr_getRowValues = EidosRegisteredString(\"getRowValues\", gEidosID_getRowValues);\nconst std::string &gEidosStr_getValue = EidosRegisteredString(\"getValue\", gEidosID_getValue);\nconst std::string &gEidosStr_identicalContents = EidosRegisteredString(\"identicalContents\", gEidosID_identicalContents);\nconst std::string &gEidosStr_serialize = EidosRegisteredString(\"serialize\", gEidosID_serialize);\nconst std::string &gEidosStr_setValue = EidosRegisteredString(\"setValue\", gEidosID_setValue);\nconst std::string &gEidosStr_setValuesVectorized = EidosRegisteredString(\"setValuesVectorized\", gEidosID_setValuesVectorized);\n\n// strings for DictionaryRetained (the retain/released subclass created by the Dictionary() constructor)\nconst std::string &gEidosStr_DictionaryRetained = EidosRegisteredString(\"DictionaryRetained\", gEidosID_DictionaryRetained);\n\n// strings for DataFrame\nconst std::string &gEidosStr_DataFrame = EidosRegisteredString(\"DataFrame\", gEidosID_DataFrame);\nconst std::string &gEidosStr_colNames = EidosRegisteredString(\"colNames\", gEidosID_colNames);\nconst std::string &gEidosStr_dim = EidosRegisteredString(\"dim\", gEidosID_dim);\nconst std::string &gEidosStr_ncol = EidosRegisteredString(\"ncol\", gEidosID_ncol);\nconst std::string &gEidosStr_nrow = EidosRegisteredString(\"nrow\", gEidosID_nrow);\nconst std::string &gEidosStr_asMatrix = EidosRegisteredString(\"asMatrix\", gEidosID_asMatrix);\nconst std::string &gEidosStr_cbind = EidosRegisteredString(\"cbind\", gEidosID_cbind);\nconst std::string &gEidosStr_rbind = EidosRegisteredString(\"rbind\", gEidosID_rbind);\nconst std::string &gEidosStr_subset = EidosRegisteredString(\"subset\", gEidosID_subset);\nconst std::string &gEidosStr_subsetColumns = EidosRegisteredString(\"subsetColumns\", gEidosID_subsetColumns);\nconst std::string &gEidosStr_subsetRows = EidosRegisteredString(\"subsetRows\", gEidosID_subsetRows);\n\n// strings for EidosImage\nconst std::string &gEidosStr_Image = EidosRegisteredString(\"Image\", gEidosID_Image);\nconst std::string &gEidosStr_width = EidosRegisteredString(\"width\", gEidosID_width);\nconst std::string &gEidosStr_height = EidosRegisteredString(\"height\", gEidosID_height);\nconst std::string &gEidosStr_bitsPerChannel = EidosRegisteredString(\"bitsPerChannel\", gEidosID_bitsPerChannel);\nconst std::string &gEidosStr_isGrayscale = EidosRegisteredString(\"isGrayscale\", gEidosID_isGrayscale);\nconst std::string &gEidosStr_integerR = EidosRegisteredString(\"integerR\", gEidosID_integerR);\nconst std::string &gEidosStr_integerG = EidosRegisteredString(\"integerG\", gEidosID_integerG);\nconst std::string &gEidosStr_integerB = EidosRegisteredString(\"integerB\", gEidosID_integerB);\nconst std::string &gEidosStr_integerK = EidosRegisteredString(\"integerK\", gEidosID_integerK);\nconst std::string &gEidosStr_floatR = EidosRegisteredString(\"floatR\", gEidosID_floatR);\nconst std::string &gEidosStr_floatG = EidosRegisteredString(\"floatG\", gEidosID_floatG);\nconst std::string &gEidosStr_floatB = EidosRegisteredString(\"floatB\", gEidosID_floatB);\nconst std::string &gEidosStr_floatK = EidosRegisteredString(\"floatK\", gEidosID_floatK);\nconst std::string &gEidosStr_write = EidosRegisteredString(\"write\", gEidosID_write);\n\n// strings for parameters, function names, etc., that are needed as explicit registrations in a Context and thus have to be\n// explicitly registered by Eidos; see the comment in EidosStringRegistry::RegisterStringForGlobalID() below\nconst std::string &gEidosStr_start = EidosRegisteredString(\"start\", gEidosID_start);\nconst std::string &gEidosStr_end = EidosRegisteredString(\"end\", gEidosID_end);\nconst std::string &gEidosStr_weights = EidosRegisteredString(\"weights\", gEidosID_weights);\nconst std::string &gEidosStr_range = EidosRegisteredString(\"range\", gEidosID_range);\nconst std::string &gEidosStr_c = EidosRegisteredString(\"c\", gEidosID_c);\nconst std::string &gEidosStr_t = EidosRegisteredString(\"t\", gEidosID_t);\nconst std::string &gEidosStr_n = EidosRegisteredString(\"n\", gEidosID_n);\nconst std::string &gEidosStr_s = EidosRegisteredString(\"s\", gEidosID_s);\nconst std::string &gEidosStr_x = EidosRegisteredString(\"x\", gEidosID_x);\nconst std::string &gEidosStr_y = EidosRegisteredString(\"y\", gEidosID_y);\nconst std::string &gEidosStr_z = EidosRegisteredString(\"z\", gEidosID_z);\nconst std::string &gEidosStr_xy = EidosRegisteredString(\"xy\", gEidosID_xy);\nconst std::string &gEidosStr_xz = EidosRegisteredString(\"xz\", gEidosID_xz);\nconst std::string &gEidosStr_yz = EidosRegisteredString(\"yz\", gEidosID_yz);\nconst std::string &gEidosStr_xyz = EidosRegisteredString(\"xyz\", gEidosID_xyz);\nconst std::string &gEidosStr_color = EidosRegisteredString(\"color\", gEidosID_color);\nconst std::string &gEidosStr_filePath = EidosRegisteredString(\"filePath\", gEidosID_filePath);\n\nconst std::string &gEidosStr_Mutation = EidosRegisteredString(\"Mutation\", gEidosID_Mutation);\t\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\nconst std::string &gEidosStr_Haplosome = EidosRegisteredString(\"Haplosome\", gEidosID_Haplosome);\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\nconst std::string &gEidosStr_Individual = EidosRegisteredString(\"Individual\", gEidosID_Individual);\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\n\nstd::vector<std::string> gEidosConstantNames;\n\n\nEidosStringRegistry::EidosStringRegistry(void) : gNextUnusedID(gEidosID_LastContextEntry)\n{\n}\n\nEidosStringRegistry::~EidosStringRegistry(void)\n{\n\t// The gIDToString map will not be safe to use, since we will have freed strings out from under it\n\tgIDToString.clear();\n\t\n\t// Now we free all of the registration objects that we made above in EidosRegisteredString().\n\t// The point of this thunk vector is to prevent Valgrind from being confused and thinking we\n\t// have leaked the global strings that we constructed; apparently unordered_map keeps them in\n\t// a way (unaligned?) that Valgrind does not recognize as a reference to the copies, so it\n\t// reports them as leaked even though they're not.\n\tfor (auto gstr_iter : gIDToString_Thunk)\n\t\tdelete (gstr_iter);\n\t\n\tgIDToString_Thunk.clear();\n\n\t// We also free all the std::strings we allocated in _GlobalStringIDForString() to avoid\n\t// them being reported as leaks.\n\tfor (auto g_string : globalString_Thunk)\n\t\tdelete (g_string);\n\t\n\tglobalString_Thunk.clear();\n}\n\nvoid EidosStringRegistry::_RegisterStringForGlobalID(const std::string &p_string, EidosGlobalStringID p_string_id)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"EidosStringRegistry::_RegisterStringForGlobalID(): string registry change\");\n\t\n\t// BCH 13 September 2016: So, this is a tricky issue without a good resolution at the moment.  Eidos explicitly registers\n\t// a few strings, using this method, using the function EidosRegisteredString().  And SLiM explicitly registers\n\t// a bunch more strings, in SLiM_RegisterGlobalStringsAndIDs().  So far so good.  But Eidos also registers a bunch of\n\t// strings \"in passing\", as a side effect of calling GlobalStringIDForString(), because it doesn't care what the\n\t// IDs of those strings are, it just wants them to be registered for later matching.  This happens to function names and\n\t// parameter names, in particular.  This is good; we don't want to have to explicitly enumerate and register all of those\n\t// strings, that would be a tremendous pain.  The problem is that these \"in passing\" registrations can conflict with\n\t// registrations done in the Context, unpredictably.  A new parameter named \"weights\" is added to a new Eidos function,\n\t// and suddenly the explicit registration of \"weights\" in SLiM has broken and needs to be removed.  At least you know\n\t// that that has happened, because you end up here.  When you end up here, don't just comment out the registration call\n\t// in the Context; you also need to add an explicit registration call in Eidos, and remove the string and ID definitions\n\t// in the Context, and so forth.  Migrate the whole explicit registration from the Context back into Eidos.  Unfortunate,\n\t// but I don't see any good solution.  Sure is nice how uniquing of selectors just happens automatically in Obj-C!  That\n\t// is basically what we're trying to duplicate here, without language support.\n\tif (gStringToID.find(p_string) != gStringToID.end())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosStringRegistry::_RegisterStringForGlobalID): string \" << p_string << \" has already been registered.\" << EidosTerminate(nullptr);\n\t\n\tif (gIDToString.find(p_string_id) != gIDToString.end())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosStringRegistry::_RegisterStringForGlobalID): id \" << p_string_id << \" has already been registered.\" << EidosTerminate(nullptr);\n\t\n\tif (p_string_id >= gEidosID_LastContextEntry)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosStringRegistry::_RegisterStringForGlobalID): id \" << p_string_id << \" is out of the legal range for preregistered strings.\" << EidosTerminate(nullptr);\n\t\n\tgStringToID[p_string] = p_string_id;\n\tgIDToString[p_string_id] = &p_string;\n\t\n\t//std::cout << \"_RegisterStringForGlobalID(): added string \" << p_string << \", id \" << p_string_id << std::endl;\n}\n\nEidosGlobalStringID EidosStringRegistry::_GlobalStringIDForString(const std::string &p_string)\n{\n\t//std::cerr << \"EidosStringRegistry::_GlobalStringIDForString: \" << p_string << std::endl;\n\tauto found_iter = gStringToID.find(p_string);\n\t\n\tif (found_iter == gStringToID.end())\n\t{\n\t\t// If the hash table does not already contain this key, then we add it to the table as a side effect.\n\t\t// We have to copy the string, because we have no idea what the caller might do with the string they passed us.\n\t\t// Since the hash table makes its own copy of the key, this copy is used only for the value in the hash tables.\n\t\tuint32_t string_id = gNextUnusedID++;\n\t\t\n#if DEBUG\n\t\t// Check that this string ID has not already been used; this should never happen\n\t\tauto found_ID_iter = gIDToString.find(string_id);\n\t\t\n\t\tif (found_ID_iter != gIDToString.end())\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosStringRegistry::_GlobalStringIDForString): id \" << string_id << \" was already in use; collision during in-passing registration of global string '\" << p_string << \"'.\" << EidosTerminate(nullptr);\n#endif\n\t\t\n\t\tconst std::string *copied_string = new const std::string(p_string);\n\t\t\n\t\tgStringToID[*copied_string] = string_id;\t// makes another copy for the key\n\t\tgIDToString[string_id] = copied_string;\t\t// uses the copy we made above\n\t\t\n#if SLIM_LEAK_CHECKING\n\t\t// We add the string copies to a thunk object for later freeing, if we're leak-checking.\n\t\t// Normally all these copied strings live for the lifespan of the process.\n\t\tglobalString_Thunk.emplace_back(copied_string);\n#endif\n\t\t\n\t\t//std::cout << \"_GlobalStringIDForString(): added string \" << p_string << \", id \" << string_id << std::endl;\n\t\t\n\t\treturn string_id;\n\t}\n\telse\n\t\treturn found_iter->second;\n}\n\nconst std::string &EidosStringRegistry::_StringForGlobalStringID(EidosGlobalStringID p_string_id)\n{\n\t//std::cerr << \"EidosStringRegistry::_StringForGlobalStringID: \" << p_string_id << std::endl;\n\tauto found_iter = gIDToString.find(p_string_id);\n\t\n\tif (found_iter == gIDToString.end())\n\t\treturn gEidosStr_undefined;\n\telse\n\t\treturn *(found_iter->second);\n}\n\nconst std::string &EidosRegisteredString(const char *p_cstr, EidosGlobalStringID p_id)\n{\n\t_EidosRegisteredString *registration_object = new _EidosRegisteredString(p_cstr, p_id);\n\t\n#if SLIM_LEAK_CHECKING\n\t// We add registration objects to a thunk vector so we can free them at the end to un-confuse Valgrind;\n\t// see ~EidosStringRegistry().  Note that this thunk vector is not used by Eidos or SLiM, but the\n\t// registration objects are; they hold onto the std::string objects used by _RegisterStringForGlobalID().\n\tEidosStringRegistry::ThunkRegistration(registration_object);\n#endif\n\t\n\treturn registration_object->string_;\n}\n\n\n#pragma mark -\n#pragma mark Named/specified color support\n#pragma mark -\n\n// *******************************************************************************************************************\n//\n//\tSupport for named / specified colors in Eidos\n//\n\n// Named colors.  This list is taken directly from R, used under their GPL-3.\n\nEidosNamedColor gEidosNamedColors[] = {\n\t{\"white\", 255, 255, 255},\n\t{\"aliceblue\", 240, 248, 255},\n\t{\"antiquewhite\", 250, 235, 215},\n\t{\"antiquewhite1\", 255, 239, 219},\n\t{\"antiquewhite2\", 238, 223, 204},\n\t{\"antiquewhite3\", 205, 192, 176},\n\t{\"antiquewhite4\", 139, 131, 120},\n\t{\"aquamarine\", 127, 255, 212},\n\t{\"aquamarine1\", 127, 255, 212},\n\t{\"aquamarine2\", 118, 238, 198},\n\t{\"aquamarine3\", 102, 205, 170},\n\t{\"aquamarine4\", 69, 139, 116},\n\t{\"azure\", 240, 255, 255},\n\t{\"azure1\", 240, 255, 255},\n\t{\"azure2\", 224, 238, 238},\n\t{\"azure3\", 193, 205, 205},\n\t{\"azure4\", 131, 139, 139},\n\t{\"beige\", 245, 245, 220},\n\t{\"bisque\", 255, 228, 196},\n\t{\"bisque1\", 255, 228, 196},\n\t{\"bisque2\", 238, 213, 183},\n\t{\"bisque3\", 205, 183, 158},\n\t{\"bisque4\", 139, 125, 107},\n\t{\"black\", 0, 0, 0},\n\t{\"blanchedalmond\", 255, 235, 205},\n\t{\"blue\", 0, 0, 255},\n\t{\"blue1\", 0, 0, 255},\n\t{\"blue2\", 0, 0, 238},\n\t{\"blue3\", 0, 0, 205},\n\t{\"blue4\", 0, 0, 139},\n\t{\"blueviolet\", 138, 43, 226},\n\t{\"brown\", 165, 42, 42},\n\t{\"brown1\", 255, 64, 64},\n\t{\"brown2\", 238, 59, 59},\n\t{\"brown3\", 205, 51, 51},\n\t{\"brown4\", 139, 35, 35},\n\t{\"burlywood\", 222, 184, 135},\n\t{\"burlywood1\", 255, 211, 155},\n\t{\"burlywood2\", 238, 197, 145},\n\t{\"burlywood3\", 205, 170, 125},\n\t{\"burlywood4\", 139, 115, 85},\n\t{\"cadetblue\", 95, 158, 160},\n\t{\"cadetblue1\", 152, 245, 255},\n\t{\"cadetblue2\", 142, 229, 238},\n\t{\"cadetblue3\", 122, 197, 205},\n\t{\"cadetblue4\", 83, 134, 139},\n\t{\"chartreuse\", 127, 255, 0},\n\t{\"chartreuse1\", 127, 255, 0},\n\t{\"chartreuse2\", 118, 238, 0},\n\t{\"chartreuse3\", 102, 205, 0},\n\t{\"chartreuse4\", 69, 139, 0},\n\t{\"chocolate\", 210, 105, 30},\n\t{\"chocolate1\", 255, 127, 36},\n\t{\"chocolate2\", 238, 118, 33},\n\t{\"chocolate3\", 205, 102, 29},\n\t{\"chocolate4\", 139, 69, 19},\n\t{\"coral\", 255, 127, 80},\n\t{\"coral1\", 255, 114, 86},\n\t{\"coral2\", 238, 106, 80},\n\t{\"coral3\", 205, 91, 69},\n\t{\"coral4\", 139, 62, 47},\n\t{\"cornflowerblue\", 100, 149, 237},\n\t{\"cornsilk\", 255, 248, 220},\n\t{\"cornsilk1\", 255, 248, 220},\n\t{\"cornsilk2\", 238, 232, 205},\n\t{\"cornsilk3\", 205, 200, 177},\n\t{\"cornsilk4\", 139, 136, 120},\n\t{\"cyan\", 0, 255, 255},\n\t{\"cyan1\", 0, 255, 255},\n\t{\"cyan2\", 0, 238, 238},\n\t{\"cyan3\", 0, 205, 205},\n\t{\"cyan4\", 0, 139, 139},\n\t{\"darkblue\", 0, 0, 139},\n\t{\"darkcyan\", 0, 139, 139},\n\t{\"darkgoldenrod\", 184, 134, 11},\n\t{\"darkgoldenrod1\", 255, 185, 15},\n\t{\"darkgoldenrod2\", 238, 173, 14},\n\t{\"darkgoldenrod3\", 205, 149, 12},\n\t{\"darkgoldenrod4\", 139, 101, 8},\n\t{\"darkgray\", 169, 169, 169},\n\t{\"darkgreen\", 0, 100, 0},\n\t{\"darkgrey\", 169, 169, 169},\n\t{\"darkkhaki\", 189, 183, 107},\n\t{\"darkmagenta\", 139, 0, 139},\n\t{\"darkolivegreen\", 85, 107, 47},\n\t{\"darkolivegreen1\", 202, 255, 112},\n\t{\"darkolivegreen2\", 188, 238, 104},\n\t{\"darkolivegreen3\", 162, 205, 90},\n\t{\"darkolivegreen4\", 110, 139, 61},\n\t{\"darkorange\", 255, 140, 0},\n\t{\"darkorange1\", 255, 127, 0},\n\t{\"darkorange2\", 238, 118, 0},\n\t{\"darkorange3\", 205, 102, 0},\n\t{\"darkorange4\", 139, 69, 0},\n\t{\"darkorchid\", 153, 50, 204},\n\t{\"darkorchid1\", 191, 62, 255},\n\t{\"darkorchid2\", 178, 58, 238},\n\t{\"darkorchid3\", 154, 50, 205},\n\t{\"darkorchid4\", 104, 34, 139},\n\t{\"darkred\", 139, 0, 0},\n\t{\"darksalmon\", 233, 150, 122},\n\t{\"darkseagreen\", 143, 188, 143},\n\t{\"darkseagreen1\", 193, 255, 193},\n\t{\"darkseagreen2\", 180, 238, 180},\n\t{\"darkseagreen3\", 155, 205, 155},\n\t{\"darkseagreen4\", 105, 139, 105},\n\t{\"darkslateblue\", 72, 61, 139},\n\t{\"darkslategray\", 47, 79, 79},\n\t{\"darkslategray1\", 151, 255, 255},\n\t{\"darkslategray2\", 141, 238, 238},\n\t{\"darkslategray3\", 121, 205, 205},\n\t{\"darkslategray4\", 82, 139, 139},\n\t{\"darkslategrey\", 47, 79, 79},\n\t{\"darkturquoise\", 0, 206, 209},\n\t{\"darkviolet\", 148, 0, 211},\n\t{\"deeppink\", 255, 20, 147},\n\t{\"deeppink1\", 255, 20, 147},\n\t{\"deeppink2\", 238, 18, 137},\n\t{\"deeppink3\", 205, 16, 118},\n\t{\"deeppink4\", 139, 10, 80},\n\t{\"deepskyblue\", 0, 191, 255},\n\t{\"deepskyblue1\", 0, 191, 255},\n\t{\"deepskyblue2\", 0, 178, 238},\n\t{\"deepskyblue3\", 0, 154, 205},\n\t{\"deepskyblue4\", 0, 104, 139},\n\t{\"dimgray\", 105, 105, 105},\n\t{\"dimgrey\", 105, 105, 105},\n\t{\"dodgerblue\", 30, 144, 255},\n\t{\"dodgerblue1\", 30, 144, 255},\n\t{\"dodgerblue2\", 28, 134, 238},\n\t{\"dodgerblue3\", 24, 116, 205},\n\t{\"dodgerblue4\", 16, 78, 139},\n\t{\"firebrick\", 178, 34, 34},\n\t{\"firebrick1\", 255, 48, 48},\n\t{\"firebrick2\", 238, 44, 44},\n\t{\"firebrick3\", 205, 38, 38},\n\t{\"firebrick4\", 139, 26, 26},\n\t{\"floralwhite\", 255, 250, 240},\n\t{\"forestgreen\", 34, 139, 34},\n\t{\"gainsboro\", 220, 220, 220},\n\t{\"ghostwhite\", 248, 248, 255},\n\t{\"gold\", 255, 215, 0},\n\t{\"gold1\", 255, 215, 0},\n\t{\"gold2\", 238, 201, 0},\n\t{\"gold3\", 205, 173, 0},\n\t{\"gold4\", 139, 117, 0},\n\t{\"goldenrod\", 218, 165, 32},\n\t{\"goldenrod1\", 255, 193, 37},\n\t{\"goldenrod2\", 238, 180, 34},\n\t{\"goldenrod3\", 205, 155, 29},\n\t{\"goldenrod4\", 139, 105, 20},\n\t{\"gray\", 190, 190, 190},\n\t{\"gray0\", 0, 0, 0},\n\t{\"gray1\", 3, 3, 3},\n\t{\"gray2\", 5, 5, 5},\n\t{\"gray3\", 8, 8, 8},\n\t{\"gray4\", 10, 10, 10},\n\t{\"gray5\", 13, 13, 13},\n\t{\"gray6\", 15, 15, 15},\n\t{\"gray7\", 18, 18, 18},\n\t{\"gray8\", 20, 20, 20},\n\t{\"gray9\", 23, 23, 23},\n\t{\"gray10\", 26, 26, 26},\n\t{\"gray11\", 28, 28, 28},\n\t{\"gray12\", 31, 31, 31},\n\t{\"gray13\", 33, 33, 33},\n\t{\"gray14\", 36, 36, 36},\n\t{\"gray15\", 38, 38, 38},\n\t{\"gray16\", 41, 41, 41},\n\t{\"gray17\", 43, 43, 43},\n\t{\"gray18\", 46, 46, 46},\n\t{\"gray19\", 48, 48, 48},\n\t{\"gray20\", 51, 51, 51},\n\t{\"gray21\", 54, 54, 54},\n\t{\"gray22\", 56, 56, 56},\n\t{\"gray23\", 59, 59, 59},\n\t{\"gray24\", 61, 61, 61},\n\t{\"gray25\", 64, 64, 64},\n\t{\"gray26\", 66, 66, 66},\n\t{\"gray27\", 69, 69, 69},\n\t{\"gray28\", 71, 71, 71},\n\t{\"gray29\", 74, 74, 74},\n\t{\"gray30\", 77, 77, 77},\n\t{\"gray31\", 79, 79, 79},\n\t{\"gray32\", 82, 82, 82},\n\t{\"gray33\", 84, 84, 84},\n\t{\"gray34\", 87, 87, 87},\n\t{\"gray35\", 89, 89, 89},\n\t{\"gray36\", 92, 92, 92},\n\t{\"gray37\", 94, 94, 94},\n\t{\"gray38\", 97, 97, 97},\n\t{\"gray39\", 99, 99, 99},\n\t{\"gray40\", 102, 102, 102},\n\t{\"gray41\", 105, 105, 105},\n\t{\"gray42\", 107, 107, 107},\n\t{\"gray43\", 110, 110, 110},\n\t{\"gray44\", 112, 112, 112},\n\t{\"gray45\", 115, 115, 115},\n\t{\"gray46\", 117, 117, 117},\n\t{\"gray47\", 120, 120, 120},\n\t{\"gray48\", 122, 122, 122},\n\t{\"gray49\", 125, 125, 125},\n\t{\"gray50\", 127, 127, 127},\n\t{\"gray51\", 130, 130, 130},\n\t{\"gray52\", 133, 133, 133},\n\t{\"gray53\", 135, 135, 135},\n\t{\"gray54\", 138, 138, 138},\n\t{\"gray55\", 140, 140, 140},\n\t{\"gray56\", 143, 143, 143},\n\t{\"gray57\", 145, 145, 145},\n\t{\"gray58\", 148, 148, 148},\n\t{\"gray59\", 150, 150, 150},\n\t{\"gray60\", 153, 153, 153},\n\t{\"gray61\", 156, 156, 156},\n\t{\"gray62\", 158, 158, 158},\n\t{\"gray63\", 161, 161, 161},\n\t{\"gray64\", 163, 163, 163},\n\t{\"gray65\", 166, 166, 166},\n\t{\"gray66\", 168, 168, 168},\n\t{\"gray67\", 171, 171, 171},\n\t{\"gray68\", 173, 173, 173},\n\t{\"gray69\", 176, 176, 176},\n\t{\"gray70\", 179, 179, 179},\n\t{\"gray71\", 181, 181, 181},\n\t{\"gray72\", 184, 184, 184},\n\t{\"gray73\", 186, 186, 186},\n\t{\"gray74\", 189, 189, 189},\n\t{\"gray75\", 191, 191, 191},\n\t{\"gray76\", 194, 194, 194},\n\t{\"gray77\", 196, 196, 196},\n\t{\"gray78\", 199, 199, 199},\n\t{\"gray79\", 201, 201, 201},\n\t{\"gray80\", 204, 204, 204},\n\t{\"gray81\", 207, 207, 207},\n\t{\"gray82\", 209, 209, 209},\n\t{\"gray83\", 212, 212, 212},\n\t{\"gray84\", 214, 214, 214},\n\t{\"gray85\", 217, 217, 217},\n\t{\"gray86\", 219, 219, 219},\n\t{\"gray87\", 222, 222, 222},\n\t{\"gray88\", 224, 224, 224},\n\t{\"gray89\", 227, 227, 227},\n\t{\"gray90\", 229, 229, 229},\n\t{\"gray91\", 232, 232, 232},\n\t{\"gray92\", 235, 235, 235},\n\t{\"gray93\", 237, 237, 237},\n\t{\"gray94\", 240, 240, 240},\n\t{\"gray95\", 242, 242, 242},\n\t{\"gray96\", 245, 245, 245},\n\t{\"gray97\", 247, 247, 247},\n\t{\"gray98\", 250, 250, 250},\n\t{\"gray99\", 252, 252, 252},\n\t{\"gray100\", 255, 255, 255},\n\t{\"green\", 0, 255, 0},\n\t{\"green1\", 0, 255, 0},\n\t{\"green2\", 0, 238, 0},\n\t{\"green3\", 0, 205, 0},\n\t{\"green4\", 0, 139, 0},\n\t{\"greenyellow\", 173, 255, 47},\n\t{\"grey\", 190, 190, 190},\n\t{\"grey0\", 0, 0, 0},\n\t{\"grey1\", 3, 3, 3},\n\t{\"grey2\", 5, 5, 5},\n\t{\"grey3\", 8, 8, 8},\n\t{\"grey4\", 10, 10, 10},\n\t{\"grey5\", 13, 13, 13},\n\t{\"grey6\", 15, 15, 15},\n\t{\"grey7\", 18, 18, 18},\n\t{\"grey8\", 20, 20, 20},\n\t{\"grey9\", 23, 23, 23},\n\t{\"grey10\", 26, 26, 26},\n\t{\"grey11\", 28, 28, 28},\n\t{\"grey12\", 31, 31, 31},\n\t{\"grey13\", 33, 33, 33},\n\t{\"grey14\", 36, 36, 36},\n\t{\"grey15\", 38, 38, 38},\n\t{\"grey16\", 41, 41, 41},\n\t{\"grey17\", 43, 43, 43},\n\t{\"grey18\", 46, 46, 46},\n\t{\"grey19\", 48, 48, 48},\n\t{\"grey20\", 51, 51, 51},\n\t{\"grey21\", 54, 54, 54},\n\t{\"grey22\", 56, 56, 56},\n\t{\"grey23\", 59, 59, 59},\n\t{\"grey24\", 61, 61, 61},\n\t{\"grey25\", 64, 64, 64},\n\t{\"grey26\", 66, 66, 66},\n\t{\"grey27\", 69, 69, 69},\n\t{\"grey28\", 71, 71, 71},\n\t{\"grey29\", 74, 74, 74},\n\t{\"grey30\", 77, 77, 77},\n\t{\"grey31\", 79, 79, 79},\n\t{\"grey32\", 82, 82, 82},\n\t{\"grey33\", 84, 84, 84},\n\t{\"grey34\", 87, 87, 87},\n\t{\"grey35\", 89, 89, 89},\n\t{\"grey36\", 92, 92, 92},\n\t{\"grey37\", 94, 94, 94},\n\t{\"grey38\", 97, 97, 97},\n\t{\"grey39\", 99, 99, 99},\n\t{\"grey40\", 102, 102, 102},\n\t{\"grey41\", 105, 105, 105},\n\t{\"grey42\", 107, 107, 107},\n\t{\"grey43\", 110, 110, 110},\n\t{\"grey44\", 112, 112, 112},\n\t{\"grey45\", 115, 115, 115},\n\t{\"grey46\", 117, 117, 117},\n\t{\"grey47\", 120, 120, 120},\n\t{\"grey48\", 122, 122, 122},\n\t{\"grey49\", 125, 125, 125},\n\t{\"grey50\", 127, 127, 127},\n\t{\"grey51\", 130, 130, 130},\n\t{\"grey52\", 133, 133, 133},\n\t{\"grey53\", 135, 135, 135},\n\t{\"grey54\", 138, 138, 138},\n\t{\"grey55\", 140, 140, 140},\n\t{\"grey56\", 143, 143, 143},\n\t{\"grey57\", 145, 145, 145},\n\t{\"grey58\", 148, 148, 148},\n\t{\"grey59\", 150, 150, 150},\n\t{\"grey60\", 153, 153, 153},\n\t{\"grey61\", 156, 156, 156},\n\t{\"grey62\", 158, 158, 158},\n\t{\"grey63\", 161, 161, 161},\n\t{\"grey64\", 163, 163, 163},\n\t{\"grey65\", 166, 166, 166},\n\t{\"grey66\", 168, 168, 168},\n\t{\"grey67\", 171, 171, 171},\n\t{\"grey68\", 173, 173, 173},\n\t{\"grey69\", 176, 176, 176},\n\t{\"grey70\", 179, 179, 179},\n\t{\"grey71\", 181, 181, 181},\n\t{\"grey72\", 184, 184, 184},\n\t{\"grey73\", 186, 186, 186},\n\t{\"grey74\", 189, 189, 189},\n\t{\"grey75\", 191, 191, 191},\n\t{\"grey76\", 194, 194, 194},\n\t{\"grey77\", 196, 196, 196},\n\t{\"grey78\", 199, 199, 199},\n\t{\"grey79\", 201, 201, 201},\n\t{\"grey80\", 204, 204, 204},\n\t{\"grey81\", 207, 207, 207},\n\t{\"grey82\", 209, 209, 209},\n\t{\"grey83\", 212, 212, 212},\n\t{\"grey84\", 214, 214, 214},\n\t{\"grey85\", 217, 217, 217},\n\t{\"grey86\", 219, 219, 219},\n\t{\"grey87\", 222, 222, 222},\n\t{\"grey88\", 224, 224, 224},\n\t{\"grey89\", 227, 227, 227},\n\t{\"grey90\", 229, 229, 229},\n\t{\"grey91\", 232, 232, 232},\n\t{\"grey92\", 235, 235, 235},\n\t{\"grey93\", 237, 237, 237},\n\t{\"grey94\", 240, 240, 240},\n\t{\"grey95\", 242, 242, 242},\n\t{\"grey96\", 245, 245, 245},\n\t{\"grey97\", 247, 247, 247},\n\t{\"grey98\", 250, 250, 250},\n\t{\"grey99\", 252, 252, 252},\n\t{\"grey100\", 255, 255, 255},\n\t{\"honeydew\", 240, 255, 240},\n\t{\"honeydew1\", 240, 255, 240},\n\t{\"honeydew2\", 224, 238, 224},\n\t{\"honeydew3\", 193, 205, 193},\n\t{\"honeydew4\", 131, 139, 131},\n\t{\"hotpink\", 255, 105, 180},\n\t{\"hotpink1\", 255, 110, 180},\n\t{\"hotpink2\", 238, 106, 167},\n\t{\"hotpink3\", 205, 96, 144},\n\t{\"hotpink4\", 139, 58, 98},\n\t{\"indianred\", 205, 92, 92},\n\t{\"indianred1\", 255, 106, 106},\n\t{\"indianred2\", 238, 99, 99},\n\t{\"indianred3\", 205, 85, 85},\n\t{\"indianred4\", 139, 58, 58},\n\t{\"ivory\", 255, 255, 240},\n\t{\"ivory1\", 255, 255, 240},\n\t{\"ivory2\", 238, 238, 224},\n\t{\"ivory3\", 205, 205, 193},\n\t{\"ivory4\", 139, 139, 131},\n\t{\"khaki\", 240, 230, 140},\n\t{\"khaki1\", 255, 246, 143},\n\t{\"khaki2\", 238, 230, 133},\n\t{\"khaki3\", 205, 198, 115},\n\t{\"khaki4\", 139, 134, 78},\n\t{\"lavender\", 230, 230, 250},\n\t{\"lavenderblush\", 255, 240, 245},\n\t{\"lavenderblush1\", 255, 240, 245},\n\t{\"lavenderblush2\", 238, 224, 229},\n\t{\"lavenderblush3\", 205, 193, 197},\n\t{\"lavenderblush4\", 139, 131, 134},\n\t{\"lawngreen\", 124, 252, 0},\n\t{\"lemonchiffon\", 255, 250, 205},\n\t{\"lemonchiffon1\", 255, 250, 205},\n\t{\"lemonchiffon2\", 238, 233, 191},\n\t{\"lemonchiffon3\", 205, 201, 165},\n\t{\"lemonchiffon4\", 139, 137, 112},\n\t{\"lightblue\", 173, 216, 230},\n\t{\"lightblue1\", 191, 239, 255},\n\t{\"lightblue2\", 178, 223, 238},\n\t{\"lightblue3\", 154, 192, 205},\n\t{\"lightblue4\", 104, 131, 139},\n\t{\"lightcoral\", 240, 128, 128},\n\t{\"lightcyan\", 224, 255, 255},\n\t{\"lightcyan1\", 224, 255, 255},\n\t{\"lightcyan2\", 209, 238, 238},\n\t{\"lightcyan3\", 180, 205, 205},\n\t{\"lightcyan4\", 122, 139, 139},\n\t{\"lightgoldenrod\", 238, 221, 130},\n\t{\"lightgoldenrod1\", 255, 236, 139},\n\t{\"lightgoldenrod2\", 238, 220, 130},\n\t{\"lightgoldenrod3\", 205, 190, 112},\n\t{\"lightgoldenrod4\", 139, 129, 76},\n\t{\"lightgoldenrodyellow\", 250, 250, 210},\n\t{\"lightgray\", 211, 211, 211},\n\t{\"lightgreen\", 144, 238, 144},\n\t{\"lightgrey\", 211, 211, 211},\n\t{\"lightpink\", 255, 182, 193},\n\t{\"lightpink1\", 255, 174, 185},\n\t{\"lightpink2\", 238, 162, 173},\n\t{\"lightpink3\", 205, 140, 149},\n\t{\"lightpink4\", 139, 95, 101},\n\t{\"lightsalmon\", 255, 160, 122},\n\t{\"lightsalmon1\", 255, 160, 122},\n\t{\"lightsalmon2\", 238, 149, 114},\n\t{\"lightsalmon3\", 205, 129, 98},\n\t{\"lightsalmon4\", 139, 87, 66},\n\t{\"lightseagreen\", 32, 178, 170},\n\t{\"lightskyblue\", 135, 206, 250},\n\t{\"lightskyblue1\", 176, 226, 255},\n\t{\"lightskyblue2\", 164, 211, 238},\n\t{\"lightskyblue3\", 141, 182, 205},\n\t{\"lightskyblue4\", 96, 123, 139},\n\t{\"lightslateblue\", 132, 112, 255},\n\t{\"lightslategray\", 119, 136, 153},\n\t{\"lightslategrey\", 119, 136, 153},\n\t{\"lightsteelblue\", 176, 196, 222},\n\t{\"lightsteelblue1\", 202, 225, 255},\n\t{\"lightsteelblue2\", 188, 210, 238},\n\t{\"lightsteelblue3\", 162, 181, 205},\n\t{\"lightsteelblue4\", 110, 123, 139},\n\t{\"lightyellow\", 255, 255, 224},\n\t{\"lightyellow1\", 255, 255, 224},\n\t{\"lightyellow2\", 238, 238, 209},\n\t{\"lightyellow3\", 205, 205, 180},\n\t{\"lightyellow4\", 139, 139, 122},\n\t{\"limegreen\", 50, 205, 50},\n\t{\"linen\", 250, 240, 230},\n\t{\"magenta\", 255, 0, 255},\n\t{\"magenta1\", 255, 0, 255},\n\t{\"magenta2\", 238, 0, 238},\n\t{\"magenta3\", 205, 0, 205},\n\t{\"magenta4\", 139, 0, 139},\n\t{\"maroon\", 176, 48, 96},\n\t{\"maroon1\", 255, 52, 179},\n\t{\"maroon2\", 238, 48, 167},\n\t{\"maroon3\", 205, 41, 144},\n\t{\"maroon4\", 139, 28, 98},\n\t{\"mediumaquamarine\", 102, 205, 170},\n\t{\"mediumblue\", 0, 0, 205},\n\t{\"mediumorchid\", 186, 85, 211},\n\t{\"mediumorchid1\", 224, 102, 255},\n\t{\"mediumorchid2\", 209, 95, 238},\n\t{\"mediumorchid3\", 180, 82, 205},\n\t{\"mediumorchid4\", 122, 55, 139},\n\t{\"mediumpurple\", 147, 112, 219},\n\t{\"mediumpurple1\", 171, 130, 255},\n\t{\"mediumpurple2\", 159, 121, 238},\n\t{\"mediumpurple3\", 137, 104, 205},\n\t{\"mediumpurple4\", 93, 71, 139},\n\t{\"mediumseagreen\", 60, 179, 113},\n\t{\"mediumslateblue\", 123, 104, 238},\n\t{\"mediumspringgreen\", 0, 250, 154},\n\t{\"mediumturquoise\", 72, 209, 204},\n\t{\"mediumvioletred\", 199, 21, 133},\n\t{\"midnightblue\", 25, 25, 112},\n\t{\"mintcream\", 245, 255, 250},\n\t{\"mistyrose\", 255, 228, 225},\n\t{\"mistyrose1\", 255, 228, 225},\n\t{\"mistyrose2\", 238, 213, 210},\n\t{\"mistyrose3\", 205, 183, 181},\n\t{\"mistyrose4\", 139, 125, 123},\n\t{\"moccasin\", 255, 228, 181},\n\t{\"navajowhite\", 255, 222, 173},\n\t{\"navajowhite1\", 255, 222, 173},\n\t{\"navajowhite2\", 238, 207, 161},\n\t{\"navajowhite3\", 205, 179, 139},\n\t{\"navajowhite4\", 139, 121, 94},\n\t{\"navy\", 0, 0, 128},\n\t{\"navyblue\", 0, 0, 128},\n\t{\"oldlace\", 253, 245, 230},\n\t{\"olivedrab\", 107, 142, 35},\n\t{\"olivedrab1\", 192, 255, 62},\n\t{\"olivedrab2\", 179, 238, 58},\n\t{\"olivedrab3\", 154, 205, 50},\n\t{\"olivedrab4\", 105, 139, 34},\n\t{\"orange\", 255, 165, 0},\n\t{\"orange1\", 255, 165, 0},\n\t{\"orange2\", 238, 154, 0},\n\t{\"orange3\", 205, 133, 0},\n\t{\"orange4\", 139, 90, 0},\n\t{\"orangered\", 255, 69, 0},\n\t{\"orangered1\", 255, 69, 0},\n\t{\"orangered2\", 238, 64, 0},\n\t{\"orangered3\", 205, 55, 0},\n\t{\"orangered4\", 139, 37, 0},\n\t{\"orchid\", 218, 112, 214},\n\t{\"orchid1\", 255, 131, 250},\n\t{\"orchid2\", 238, 122, 233},\n\t{\"orchid3\", 205, 105, 201},\n\t{\"orchid4\", 139, 71, 137},\n\t{\"palegoldenrod\", 238, 232, 170},\n\t{\"palegreen\", 152, 251, 152},\n\t{\"palegreen1\", 154, 255, 154},\n\t{\"palegreen2\", 144, 238, 144},\n\t{\"palegreen3\", 124, 205, 124},\n\t{\"palegreen4\", 84, 139, 84},\n\t{\"paleturquoise\", 175, 238, 238},\n\t{\"paleturquoise1\", 187, 255, 255},\n\t{\"paleturquoise2\", 174, 238, 238},\n\t{\"paleturquoise3\", 150, 205, 205},\n\t{\"paleturquoise4\", 102, 139, 139},\n\t{\"palevioletred\", 219, 112, 147},\n\t{\"palevioletred1\", 255, 130, 171},\n\t{\"palevioletred2\", 238, 121, 159},\n\t{\"palevioletred3\", 205, 104, 137},\n\t{\"palevioletred4\", 139, 71, 93},\n\t{\"papayawhip\", 255, 239, 213},\n\t{\"peachpuff\", 255, 218, 185},\n\t{\"peachpuff1\", 255, 218, 185},\n\t{\"peachpuff2\", 238, 203, 173},\n\t{\"peachpuff3\", 205, 175, 149},\n\t{\"peachpuff4\", 139, 119, 101},\n\t{\"peru\", 205, 133, 63},\n\t{\"pink\", 255, 192, 203},\n\t{\"pink1\", 255, 181, 197},\n\t{\"pink2\", 238, 169, 184},\n\t{\"pink3\", 205, 145, 158},\n\t{\"pink4\", 139, 99, 108},\n\t{\"plum\", 221, 160, 221},\n\t{\"plum1\", 255, 187, 255},\n\t{\"plum2\", 238, 174, 238},\n\t{\"plum3\", 205, 150, 205},\n\t{\"plum4\", 139, 102, 139},\n\t{\"powderblue\", 176, 224, 230},\n\t{\"purple\", 160, 32, 240},\n\t{\"purple1\", 155, 48, 255},\n\t{\"purple2\", 145, 44, 238},\n\t{\"purple3\", 125, 38, 205},\n\t{\"purple4\", 85, 26, 139},\n\t{\"red\", 255, 0, 0},\n\t{\"red1\", 255, 0, 0},\n\t{\"red2\", 238, 0, 0},\n\t{\"red3\", 205, 0, 0},\n\t{\"red4\", 139, 0, 0},\n\t{\"rosybrown\", 188, 143, 143},\n\t{\"rosybrown1\", 255, 193, 193},\n\t{\"rosybrown2\", 238, 180, 180},\n\t{\"rosybrown3\", 205, 155, 155},\n\t{\"rosybrown4\", 139, 105, 105},\n\t{\"royalblue\", 65, 105, 225},\n\t{\"royalblue1\", 72, 118, 255},\n\t{\"royalblue2\", 67, 110, 238},\n\t{\"royalblue3\", 58, 95, 205},\n\t{\"royalblue4\", 39, 64, 139},\n\t{\"saddlebrown\", 139, 69, 19},\n\t{\"salmon\", 250, 128, 114},\n\t{\"salmon1\", 255, 140, 105},\n\t{\"salmon2\", 238, 130, 98},\n\t{\"salmon3\", 205, 112, 84},\n\t{\"salmon4\", 139, 76, 57},\n\t{\"sandybrown\", 244, 164, 96},\n\t{\"seagreen\", 46, 139, 87},\n\t{\"seagreen1\", 84, 255, 159},\n\t{\"seagreen2\", 78, 238, 148},\n\t{\"seagreen3\", 67, 205, 128},\n\t{\"seagreen4\", 46, 139, 87},\n\t{\"seashell\", 255, 245, 238},\n\t{\"seashell1\", 255, 245, 238},\n\t{\"seashell2\", 238, 229, 222},\n\t{\"seashell3\", 205, 197, 191},\n\t{\"seashell4\", 139, 134, 130},\n\t{\"sienna\", 160, 82, 45},\n\t{\"sienna1\", 255, 130, 71},\n\t{\"sienna2\", 238, 121, 66},\n\t{\"sienna3\", 205, 104, 57},\n\t{\"sienna4\", 139, 71, 38},\n\t{\"skyblue\", 135, 206, 235},\n\t{\"skyblue1\", 135, 206, 255},\n\t{\"skyblue2\", 126, 192, 238},\n\t{\"skyblue3\", 108, 166, 205},\n\t{\"skyblue4\", 74, 112, 139},\n\t{\"slateblue\", 106, 90, 205},\n\t{\"slateblue1\", 131, 111, 255},\n\t{\"slateblue2\", 122, 103, 238},\n\t{\"slateblue3\", 105, 89, 205},\n\t{\"slateblue4\", 71, 60, 139},\n\t{\"slategray\", 112, 128, 144},\n\t{\"slategray1\", 198, 226, 255},\n\t{\"slategray2\", 185, 211, 238},\n\t{\"slategray3\", 159, 182, 205},\n\t{\"slategray4\", 108, 123, 139},\n\t{\"slategrey\", 112, 128, 144},\n\t{\"snow\", 255, 250, 250},\n\t{\"snow1\", 255, 250, 250},\n\t{\"snow2\", 238, 233, 233},\n\t{\"snow3\", 205, 201, 201},\n\t{\"snow4\", 139, 137, 137},\n\t{\"springgreen\", 0, 255, 127},\n\t{\"springgreen1\", 0, 255, 127},\n\t{\"springgreen2\", 0, 238, 118},\n\t{\"springgreen3\", 0, 205, 102},\n\t{\"springgreen4\", 0, 139, 69},\n\t{\"steelblue\", 70, 130, 180},\n\t{\"steelblue1\", 99, 184, 255},\n\t{\"steelblue2\", 92, 172, 238},\n\t{\"steelblue3\", 79, 148, 205},\n\t{\"steelblue4\", 54, 100, 139},\n\t{\"tan\", 210, 180, 140},\n\t{\"tan1\", 255, 165, 79},\n\t{\"tan2\", 238, 154, 73},\n\t{\"tan3\", 205, 133, 63},\n\t{\"tan4\", 139, 90, 43},\n\t{\"thistle\", 216, 191, 216},\n\t{\"thistle1\", 255, 225, 255},\n\t{\"thistle2\", 238, 210, 238},\n\t{\"thistle3\", 205, 181, 205},\n\t{\"thistle4\", 139, 123, 139},\n\t{\"tomato\", 255, 99, 71},\n\t{\"tomato1\", 255, 99, 71},\n\t{\"tomato2\", 238, 92, 66},\n\t{\"tomato3\", 205, 79, 57},\n\t{\"tomato4\", 139, 54, 38},\n\t{\"turquoise\", 64, 224, 208},\n\t{\"turquoise1\", 0, 245, 255},\n\t{\"turquoise2\", 0, 229, 238},\n\t{\"turquoise3\", 0, 197, 205},\n\t{\"turquoise4\", 0, 134, 139},\n\t{\"violet\", 238, 130, 238},\n\t{\"violetred\", 208, 32, 144},\n\t{\"violetred1\", 255, 62, 150},\n\t{\"violetred2\", 238, 58, 140},\n\t{\"violetred3\", 205, 50, 120},\n\t{\"violetred4\", 139, 34, 82},\n\t{\"wheat\", 245, 222, 179},\n\t{\"wheat1\", 255, 231, 186},\n\t{\"wheat2\", 238, 216, 174},\n\t{\"wheat3\", 205, 186, 150},\n\t{\"wheat4\", 139, 126, 102},\n\t{\"whitesmoke\", 245, 245, 245},\n\t{\"yellow\", 255, 255, 0},\n\t{\"yellow1\", 255, 255, 0},\n\t{\"yellow2\", 238, 238, 0},\n\t{\"yellow3\", 205, 205, 0},\n\t{\"yellow4\", 139, 139, 0},\n\t{\"yellowgreen\", 154, 205, 50},\n\t{nullptr, 0, 0, 0}\n};\n\nvoid Eidos_GetColorComponents(const std::string &p_color_name, float *p_red_component, float *p_green_component, float *p_blue_component)\n{\n\t// Colors can be specified either in hex as \"#RRGGBB\" or as a named color from the list above\n\tif ((p_color_name.length() == 7) && (p_color_name[0] == '#'))\n\t{\n\t\ttry\n\t\t{\n\t\t\tunsigned long r = stoul(p_color_name.substr(1, 2), nullptr, 16);\n\t\t\tunsigned long g = stoul(p_color_name.substr(3, 2), nullptr, 16);\n\t\t\tunsigned long b = stoul(p_color_name.substr(5, 2), nullptr, 16);\n\t\t\t\n\t\t\t*p_red_component = r / 255.0F;\n\t\t\t*p_green_component = g / 255.0F;\n\t\t\t*p_blue_component = b / 255.0F;\n\t\t\treturn;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color specification '\" << p_color_name << \"' is malformed.\" << EidosTerminate();\n\t\t}\n\t}\n\telse if (p_color_name.length() > 0)\n\t{\n\t\tfor (EidosNamedColor *color_table = gEidosNamedColors; color_table->name; ++color_table)\n\t\t{\n\t\t\tif (p_color_name == color_table->name)\n\t\t\t{\n\t\t\t\t*p_red_component = color_table->red / 255.0F;\n\t\t\t\t*p_green_component = color_table->green / 255.0F;\n\t\t\t\t*p_blue_component = color_table->blue / 255.0F;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (p_color_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color strings may not be zero-length.\" << EidosTerminate();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color named '\" << p_color_name << \"' could not be found.\" << EidosTerminate();\n}\n\nvoid Eidos_GetColorComponents(const std::string &p_color_name, uint8_t *p_red_component, uint8_t *p_green_component, uint8_t *p_blue_component)\n{\n\t// Colors can be specified either in hex as \"#RRGGBB\" or as a named color from the list above\n\tif ((p_color_name.length() == 7) && (p_color_name[0] == '#'))\n\t{\n\t\ttry\n\t\t{\n\t\t\tunsigned long r = stoul(p_color_name.substr(1, 2), nullptr, 16);\n\t\t\tunsigned long g = stoul(p_color_name.substr(3, 2), nullptr, 16);\n\t\t\tunsigned long b = stoul(p_color_name.substr(5, 2), nullptr, 16);\n\t\t\t\n\t\t\t*p_red_component = (uint8_t)r;\n\t\t\t*p_green_component = (uint8_t)g;\n\t\t\t*p_blue_component = (uint8_t)b;\n\t\t\treturn;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color specification '\" << p_color_name << \"' is malformed.\" << EidosTerminate();\n\t\t}\n\t}\n\telse if (p_color_name.length() > 0)\n\t{\n\t\tfor (EidosNamedColor *color_table = gEidosNamedColors; color_table->name; ++color_table)\n\t\t{\n\t\t\tif (p_color_name == color_table->name)\n\t\t\t{\n\t\t\t\t*p_red_component = color_table->red;\n\t\t\t\t*p_green_component = color_table->green;\n\t\t\t\t*p_blue_component = color_table->blue;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (p_color_name.length() == 0)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color strings may not be zero-length.\" << EidosTerminate();\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorComponents): color named '\" << p_color_name << \"' could not be found.\" << EidosTerminate();\n}\n\nvoid Eidos_GetColorString(double p_red, double p_green, double p_blue, char *p_string_buffer)\n{\n\tif (std::isnan(p_red) || std::isnan(p_green) || std::isnan(p_blue))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_GetColorString): color component with value NAN is not legal.\" << EidosTerminate();\n\t\n\tif (p_red < 0.0) p_red = 0.0;\n\tif (p_red > 1.0) p_red = 1.0;\n\tif (p_green < 0.0) p_green = 0.0;\n\tif (p_green > 1.0) p_green = 1.0;\n\tif (p_blue < 0.0) p_blue = 0.0;\n\tif (p_blue > 1.0) p_blue = 1.0;\n\t\n\tint r_i = (int)round(p_red * 255.0);\n\tint g_i = (int)round(p_green * 255.0);\n\tint b_i = (int)round(p_blue * 255.0);\n\t\n\tstatic char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n\t\n\tp_string_buffer[0] = '#';\n\tp_string_buffer[1] = hex[r_i / 16];\n\tp_string_buffer[2] = hex[r_i % 16];\n\tp_string_buffer[3] = hex[g_i / 16];\n\tp_string_buffer[4] = hex[g_i % 16];\n\tp_string_buffer[5] = hex[b_i / 16];\n\tp_string_buffer[6] = hex[b_i % 16];\n\tp_string_buffer[7] = 0;\n}\n\nvoid Eidos_GetColorString(uint8_t p_red, uint8_t p_green, uint8_t p_blue, char *p_string_buffer)\n{\n\tint r_i = (int)p_red;\n\tint g_i = (int)p_green;\n\tint b_i = (int)p_blue;\n\t\n\tstatic char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n\t\n\tp_string_buffer[0] = '#';\n\tp_string_buffer[1] = hex[r_i / 16];\n\tp_string_buffer[2] = hex[r_i % 16];\n\tp_string_buffer[3] = hex[g_i / 16];\n\tp_string_buffer[4] = hex[g_i % 16];\n\tp_string_buffer[5] = hex[b_i / 16];\n\tp_string_buffer[6] = hex[b_i % 16];\n\tp_string_buffer[7] = 0;\n}\n\nvoid Eidos_HSV2RGB(double h, double s, double v, double *p_r, double *p_g, double *p_b)\n{\n\tif (std::isnan(h) || std::isnan(s) || std::isnan(v))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_HSV2RGB): color component with value NAN is not legal.\" << EidosTerminate();\n\t\n\tif (h < 0.0) h = 0.0;\n\tif (h > 1.0) h = 1.0;\n\tif (s < 0.0) s = 0.0;\n\tif (s > 1.0) s = 1.0;\n\tif (v < 0.0) v = 0.0;\n\tif (v > 1.0) v = 1.0;\n\t\n\tdouble c = v * s;\n\tdouble x = c * (1.0 - fabs(fmod(h * 6.0, 2.0) - 1.0));\n\tdouble m = v - c;\n\tdouble r, g, b;\n\t\n\tif (h < 1.0 / 6.0)\t\t\t{\tr = c;\tg = x;\tb = 0;\t}\n\telse if (h < 2.0 / 6.0)\t\t{\tr = x;\tg = c;\tb = 0;\t}\n\telse if (h < 3.0 / 6.0)\t\t{\tr = 0;\tg = c;\tb = x;\t}\n\telse if (h < 4.0 / 6.0)\t\t{\tr = 0;\tg = x;\tb = c;\t}\n\telse if (h < 5.0 / 6.0)\t\t{\tr = x;\tg = 0;\tb = c;\t}\n\telse\t\t\t\t\t\t{\tr = c;\tg = 0;\tb = x;\t}\n\t\n\t*p_r = r + m;\n\t*p_g = g + m;\n\t*p_b = b + m;\n}\n\nvoid Eidos_RGB2HSV(double r, double g, double b, double *p_h, double *p_s, double *p_v)\n{\n\tif (std::isnan(r) || std::isnan(g) || std::isnan(b))\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_RGB2HSV): color component with value NAN is not legal.\" << EidosTerminate();\n\t\n\tif (r < 0.0) r = 0.0;\n\tif (r > 1.0) r = 1.0;\n\tif (g < 0.0) g = 0.0;\n\tif (g > 1.0) g = 1.0;\n\tif (b < 0.0) b = 0.0;\n\tif (b > 1.0) b = 1.0;\n\t\n\tdouble c_max = std::max(r, std::max(g, b));\n\tdouble c_min = std::min(r, std::min(g, b));\n\tdouble delta = c_max - c_min;\n\tdouble h, s, v;\n\t\n\tif (delta == 0)\n\t\th = 0.0;\n\telse if (c_max == r)\n\t\th = (1.0/6.0) * fmod(((g - b) / delta) + 6.0, 6.0);\n\telse if (c_max == g)\n\t\th = (1.0/6.0) * (((b - r) / delta) + 2.0);\n\telse // if (c_max == b)\n\t\th = (1.0/6.0) * (((r - g) / delta) + 4.0);\n\t\n\tif (c_max == 0.0)\n\t\ts = 0.0;\n\telse\n\t\ts = delta / c_max;\n\t\n\tv = c_max;\n\t\n\t*p_h = h;\n\t*p_s = s;\n\t*p_v = v;\n}\n\nEidosColorPalette Eidos_PaletteForName(const std::string &name)\n{\n\tif (name == \"cm\")\t\t\t\treturn EidosColorPalette::kPalette_cm;\n\telse if (name == \"heat\")\t\treturn EidosColorPalette::kPalette_heat;\n\telse if (name == \"terrain\")\t\treturn EidosColorPalette::kPalette_terrain;\n\telse if (name == \"parula\")\t\treturn EidosColorPalette::kPalette_parula;\n\telse if (name == \"hot\")\t\t\treturn EidosColorPalette::kPalette_hot;\n\telse if (name == \"jet\")\t\t\treturn EidosColorPalette::kPalette_jet;\n\telse if (name == \"turbo\")\t\treturn EidosColorPalette::kPalette_turbo;\n\telse if (name == \"gray\")\t\treturn EidosColorPalette::kPalette_gray;\n\telse if (name == \"magma\")\t\treturn EidosColorPalette::kPalette_magma;\n\telse if (name == \"inferno\")\t\treturn EidosColorPalette::kPalette_inferno;\n\telse if (name == \"plasma\")\t\treturn EidosColorPalette::kPalette_plasma;\n\telse if (name == \"viridis\")\t\treturn EidosColorPalette::kPalette_viridis;\n\telse if (name == \"cividis\")\t\treturn EidosColorPalette::kPalette_cividis;\n\telse\t\t\t\t\t\t\treturn EidosColorPalette::kPalette_INVALID;\n}\n\nvoid Eidos_ColorPaletteLookup(double fraction, EidosColorPalette palette, double &r, double &g, double &b)\n{\n\tif (fraction < 0.0) fraction = 0.0;\n\tif (fraction > 1.0) fraction = 1.0;\n\t\n\tswitch (palette)\n\t{\n\t\tcase EidosColorPalette::kPalette_cm:\n\t\t{\n\t\t\t// Note that for even n, this generates somewhat different values than R does, but I think\n\t\t\t// that is a bug in their code; the space between the two central values is doubled.\n\t\t\tr = (fraction >= 0.5) ? 1.0 : (fraction + 0.5);\n\t\t\tg = (fraction <= 0.5) ? 1.0 : (1.5 - fraction);\n\t\t\tb = 1.0;\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_heat:\n\t\t{\n\t\t\t// Note the behavior of this palette was changed slightly in Eidos 1.5, to be more consistent\n\t\t\tif (fraction < 0.75)\n\t\t\t{\n\t\t\t\tr = 1.0;\n\t\t\t\tg = fraction / 0.75;\n\t\t\t\tb = 0.0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tr = 1.0;\n\t\t\t\tg = 1.0;\n\t\t\t\tb = (fraction - 0.75) / 0.25;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_terrain:\n\t\t{\n\t\t\t// Note the behavior of this palette was changed slightly in Eidos 1.5, to be more consistent\n\t\t\tif (fraction < 0.5)\n\t\t\t{\n\t\t\t\tdouble w = fraction / 0.5;\n\t\t\t\tdouble h = 4/12.0 + (2/12.0 - 4/12.0) * w;\n\t\t\t\tdouble s = 1.0 + (1.0 - 1.0) * w;\n\t\t\t\tdouble v = 0.65 + (0.9 - 0.65) * w;\n\t\t\t\t\n\t\t\t\tEidos_HSV2RGB(h, s, v, &r, &g, &b);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdouble w = (fraction - 0.5) / 0.5;\n\t\t\t\tdouble h = 2/12.0 + (0/12.0 - 2/12.0) * w;\n\t\t\t\tdouble s = 1.0 + (0.0 - 1.0) * w;\n\t\t\t\tdouble v = 0.9 + (0.95 - 0.9) * w;\n\t\t\t\t\n\t\t\t\tEidos_HSV2RGB(h, s, v, &r, &g, &b);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_parula:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetParulaColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_hot:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetHotColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_jet:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetJetColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_turbo:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetTurboColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_gray:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetGrayColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_magma:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetMagmaColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_inferno:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetInfernoColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_plasma:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetPlasmaColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_viridis:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetViridisColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosColorPalette::kPalette_cividis:\n\t\t{\n\t\t\ttinycolormap::Color color = tinycolormap::GetCividisColor(fraction);\n\t\t\tr = color.r(); g = color.g(); b = color.b();\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (Eidos_ColorPaletteLookup): unrecognized color palette in Eidos_ColorPaletteLookup().\" << EidosTerminate(nullptr);\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_globals.h",
    "content": "//\n//  eidos_globals.h\n//  Eidos\n//\n//  Created by Ben Haller on 6/28/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_globals__\n#define __Eidos__eidos_globals__\n\n#include <stdio.h>\n#include <iostream>\n#include <sstream>\n#include <vector>\n#include <string>\n#include <cmath>\n#include <float.h>\n#include <string.h>\n#include <numeric>\n#include <algorithm>\n#include <unordered_map>\n#include <cstdint>\n\n// Workaround for Xcode bug: when you want to debug build problems with a Release build related to profiling, uncomment this,\n// since the target-level definition of SLIMPROFILING doesn't seem to affect syntax highlighting and build errors correctly.\n//#define SLIMPROFILING 1\n\n#if defined(__APPLE__) && defined(__MACH__)\n// On macOS we use mach_absolute_time() for profiling and benchmarking\n#include <mach/mach_time.h>\n#define MACH_PROFILING\n#else\n// On other platforms we use std::chrono::steady_clock\n#include <chrono>\n#define CHRONO_PROFILING\n#endif\n\n#include \"eidos_openmp.h\"\n#include \"eidos_intrusive_ptr.h\"\n\nclass EidosScript;\nclass EidosToken;\n\n\n// Eidos version: See also Info.plist\n#define EIDOS_VERSION_STRING\t(\"4.2\")\n#define EIDOS_VERSION_FLOAT\t\t(4.2)\n\n\n#ifdef _OPENMP\ntypedef enum {\n\tkDefault = 0,\t\t\t\t// indicates that one of the other values should be chosen heuristically\n\tkMaxThreads,\t\t\t\t// use EIDOS_OMP_MAX_THREADS for everything\n\tkMacStudio2022_16,\t\t\t// Mac Studio 2022 (Mac13,2), 20-core M1 Ultra (16 performance cores)\n\tkXeonGold2_40,\t\t\t\t// two 20-core (40-hyperthreaded) Intel Xeon Gold 6148 2.4GHz (40 physical cores)\n} EidosPerTaskThreadCounts;\n\n// Some state variables for user output regarding the OpenMP configuration\nextern EidosPerTaskThreadCounts gEidosDefaultPerTaskThreadCounts;\t// the default set on the command line, or kDefault\nextern std::string gEidosPerTaskThreadCountsSetName;\nextern int gEidosPerTaskOriginalMaxThreadCount, gEidosPerTaskClippedMaxThreadCount;\n\n// Eidos_WarmUpOpenMP() should be called once at startup to give Eidos an opportunity to initialize static state\nvoid _Eidos_SetOpenMPThreadCounts(EidosPerTaskThreadCounts per_task_thread_counts);\nvoid _Eidos_ChooseDefaultOpenMPThreadCounts(void);\nvoid _Eidos_ClipOpenMPThreadCounts(void);\nvoid Eidos_WarmUpOpenMP(std::ostream *outstream, bool changed_max_thread_count, int new_max_thread_count, bool active_threads, std::string thread_count_set_name);\n#endif\n\nvoid Eidos_WarmUp(void);\n\n// This can be called at startup, after Eidos_WarmUp(), to define global constants from the command line\nvoid Eidos_DefineConstantsFromCommandLine(const std::vector<std::string> &p_constants);\n\n\n// This governs whether \"Robin Hood Hashing\" is used instead of std::unordered_map in key spots, for speed\n// Robin Hood Hashing is in robin_hood.h, and is by Martin Ankerl (https://github.com/martinus/robin-hood-hashing)\n// Change this define to 1 to enable Robin Hood Hashing, or change it to 0 to disable it\n// Note that you have a choice of robin_hood::unordered_node_map or robin_hood::unordered_flat_map\n// With robin_hood::unordered_flat_map, references to elements are not stable, but it is probably a bit faster\n// STD_UNORDERED_MAP_HASHING is the reverse flag; this just makes it easy to get an error message if this header\n// is not included, following a standard usage pattern, since then neither of these defines will exist.\n#define EIDOS_ROBIN_HOOD_HASHING\t1\n\n#if EIDOS_ROBIN_HOOD_HASHING\n#define STD_UNORDERED_MAP_HASHING\t0\n#else\n#define STD_UNORDERED_MAP_HASHING\t1\n#endif\n\n\n// *******************************************************************************************************************\n//\n//\tContext customization\n//\n#pragma mark -\n#pragma mark Context customization\n#pragma mark -\n\n// Information on the Context within which Eidos is running (if any).  This is basically a way to let the Context\n// customize the version and license and citation information printed by Eidos.\n\nextern double gEidosContextVersion;\nextern std::string gEidosContextVersionString;\nextern std::string gEidosContextLicense;\nextern std::string gEidosContextCitation;\nextern std::vector<std::string> gEidosContextReservedSymbols;\t// see Eidos_GoodSymbolForDefine()\n\nbool Eidos_GoodSymbolForDefine(std::string &p_symbol_name);\n\n\n// *******************************************************************************************************************\n//\n//\tError tracking\n//\n#pragma mark -\n#pragma mark Error tracking\n#pragma mark -\n\n// The part of the input file that caused an error; used to highlight the token or text that caused the error.\n// Eidos now also supports reporting of errors with quoted script lines, using the EidosScript* here.  The\n// error tracking and reporting stuff is unfortunately very fragile, because it is based on global variables\n// that get magically set up in various places and then get used in various completely different places.  This\n// is a big reason why Eidos is not thread-safe at present, and it's one of the trickiest parts of the code,\n// for no very good reason except that I haven't yet figured out the right way to fix it.  FIXME\n\n// A small struct used for saving and restoring the error position in a stack-like manner.  Positions of -1\n// in this struct always mean \"not a valid error position\"; that is legal, but the error position is unknown.\ntypedef struct\n{\n\tint characterStartOfError;\n\tint characterEndOfError;\n\tint characterStartOfErrorUTF16;\n\tint characterEndOfErrorUTF16;\n} EidosErrorPosition;\n\n// A bigger struct used when saving and restoring not only the error position but also the script context.\n// When an occur occurs, currentScript will usually point to a script.  The state inside currentScript\n// tells us what's going on.  If its offsets (like user_script_offset_UTF16_) are -1, that means the script\n// is independent of the user's script, such as a lambda; there's no way to translate error positions back,\n// so any error we show must be within the context of currentScript itself (e.g., within the lambda string).\n// If its offsets are not -1, the script is in some way derived from the user script, and there are two\n// possibilities.  One is that the offsets are 0 and the user_script_ pointer inside currentScript is\n// nullptr; this says \"I *am* the user script\".  The offsets can be used; since they are zero, no harm will\n// occur.  The other is that the offsets are (probably) non-zero, and the user_script_ pointer is (certainly)\n// non-nullptr, pointing to the user script.  This says \"I am a subset of the user script\".  The offsets\n// will translate a given error position back into the corresponding position in the user script.  That\n// translation is done by operator<<(std::ostream& p_out, const EidosTerminate &p_terminator) when an error\n// is raised.  (I think currentScript is nullptr only when executing statements in the Eidos console.)\ntypedef struct {\n\tEidosErrorPosition errorPosition;\n\tEidosScript *currentScript;\n} EidosErrorContext;\n\n// this global struct contains the current error context\nextern EidosErrorContext gEidosErrorContext;\n\n// declared in eidos_token.h due to EidosToken dependency:\n// inline __attribute__((always_inline)) EidosErrorPosition PushErrorPositionFromToken(const EidosToken *p_naughty_token_)\n\ninline __attribute__((always_inline)) void RestoreErrorPosition(const EidosErrorPosition &p_saved_position)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"RestoreErrorPosition(): gEidosErrorContext change\");\n\t\n\tgEidosErrorContext.errorPosition = p_saved_position;\n}\n\ninline __attribute__((always_inline)) void ClearErrorPosition(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"ClearErrorPosition(): gEidosErrorContext change\");\n\t\n\tgEidosErrorContext.errorPosition = EidosErrorPosition{-1, -1, -1, -1};\n}\n\ninline __attribute__((always_inline)) void ClearErrorContext(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"ClearErrorContext(): gEidosErrorContext change\");\n\t\n\t// Note that this clears to an illegal state; an error cannot be thrown in this state.\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, nullptr};\n}\n\n// Attempt to translate an error position from the current script to the user script.\nvoid TranslateErrorContextToUserScript(const char *p_caller);\n\n// Warnings: consult this flag before emitting a warning\nextern bool gEidosSuppressWarnings;\n\n\n// *******************************************************************************************************************\n//\n//\tDebugging support\n//\n#pragma mark -\n#pragma mark Debugging support\n#pragma mark -\n\n// Debugging #defines that can be turned on\n#define EIDOS_DEBUG_COMPLETION\t0\t// turn on to log information about symbol types whenever doing code completion\n#define EIDOS_DEBUG_ERROR_POSITIONS\t\t0\t// turn on to log information about error positions in scripts\n\n// Flags for various runtime checks that can be turned on or off; in SLiM, -x turns these off.\nextern bool eidos_do_memory_checks;\n\n// To leak-check slim, a few steps are recommended (BCH 5/1/2019):\n//\n//\t- turn on Malloc Scribble so spurious pointers left over in deallocated blocks are not taken to be live references\n//\t- turn on Malloc Logging so you get backtraces from every leaked allocation\n//\t- use a DEBUG build of slim so the backtraces are accurate and not obfuscated by optimization\n//\t- set this #define to 1 so slim cleans up a bit and then sleeps before exit, waiting for its leaks to be assessed\n//\t- run \"leaks slim\" in Terminal; the leaks tool in Instruments seems to be very confused and reports tons of false positives\n//\n// To run slim under Valgrind, setting this flag to 1 is also recommended as it will enable some thunks that will\n// keep Valgrind from getting confused.  Use a DEBUG build so it is symbolicated (-g) and minimally optimized (-Og),\n// or add those flags to CMAKE_C_FLAGS_RELEASE and CMAKE_CXX_FLAGS_RELEASE in CMakeLists.txt.\n#define SLIM_LEAK_CHECKING\t0\n\n#if SLIM_LEAK_CHECKING\n#warning SLIM_LEAK_CHECKING enabled!\n#endif\n\n// Enabling \"debug points\" in SLiMgui.  These are only enabled under SLiMgui (i.e., QtSLiM), and should always be enabled\n// in that scenario, for end users.  However, I've put a define here to control them for my own debugging purposes.\n#ifdef SLIMGUI\n#define DEBUG_POINTS_ENABLED\t1\nextern int gEidosDebugIndent;\n#else\n#define DEBUG_POINTS_ENABLED\t0\n#endif\n\n#if DEBUG_POINTS_ENABLED\n// A simple class for RAII-based debug point indentation; saves some hassle with exceptions, etc.\nclass EidosDebugPointIndent\n{\nprivate:\n\tint indent_;\npublic:\n\tEidosDebugPointIndent(void) : indent_(0) { }\n\t~EidosDebugPointIndent(void) { gEidosDebugIndent -= indent_; }\n\tinline void indent(int spaces = 4) { gEidosDebugIndent += spaces; indent_ += spaces; }\n\tinline void outdent(int spaces = 4) { gEidosDebugIndent -= spaces; indent_ -= spaces; }\n\t\n\tstatic inline const std::string Indent(void) { return std::string(gEidosDebugIndent, ' '); }\n};\n#endif\n\n// Eidos defines the concept of \"long-term boundaries\", which are moments in time when Eidos objects\n// that are not under retain-release memory management could be freed.  Keeping a reference to such\n// an object between long-term boundaries is generally safe; keeping a reference to such an object\n// across a long-term boundary is generally NOT safe.  This function should be called, internally by\n// Eidos and externally by the Context, at such boundaries, and code should not free Eidos objects\n// (except local temporaries) without calling this function first.  This allows internal bookkeeping\n// to check for violations of the long-term boundary conventions.\nvoid CheckLongTermBoundary();\n\n\n// *******************************************************************************************************************\n//\n//\tMemory usage and runtime monitoring\n//\n#pragma mark -\n#pragma mark Memory usage and runtime monitoring\n#pragma mark -\n\n// Memory-monitoring calls.  See the .cpp for comments.  These return a size in bytes.\nsize_t Eidos_GetPeakRSS(void);\nsize_t Eidos_GetCurrentRSS(void);\nsize_t Eidos_GetVMUsage(void);\n\n// Memory limits, retrieved by calling \"ulimit -m\"; cached internally.  Returns a size in bytes; 0 means \"no limit\".\nsize_t Eidos_GetMaxRSS(void);\n\n// This checks whether our memory usage has gotten within 10 MB of the maximum memory usage, and terminates if so.\n// p_message1 should be the name of the calling function/method; p_message2 can be any clarifying message.\n// It is a good idea to check eidos_do_memory_checks before calling this, to save calling overhead.\nvoid Eidos_CheckRSSAgainstMax(const std::string &p_message1, const std::string &p_message2);\n\n// This provides the elapsed wall clock time, in seconds, since process startup.\ndouble Eidos_WallTimeSeconds(void);\n\n// This provides total process time usage in terms of user CPU time and system CPU time, not wall clock time.\nvoid Eidos_GetUserSysTime(double *p_user_time, double *p_sys_time);\n\n\n// *******************************************************************************************************************\n//\n//\tProfiling support\n//\n#pragma mark -\n#pragma mark Profiling support\n#pragma mark -\n\n// BCH 1/22/2023: Note that profiling can now be enabled for both command-line and GUI builds.  It is enabled\n// when SLIMPROFILING is defined to 1; if it is undefined, 0, or any other value, profiling is disabled.\n// BCH 8/5/2023: Also, note that the foundational profiling code is now also used for the EidosBenchmark facility,\n// even when SLiM is not built for profiling, so that foundational code is now always included in the build.\n\n#if defined(MACH_PROFILING)\n\n// This is the fastest clock, is available across OS X versions, and gives us nanoseconds.  The only disadvantage to\n// it is that it is platform-specific, so we can only use this clock in SLiMgui and Eidos_GUI.  That is OK.  This\n// returns uint64_t in CPU-specific time units; see https://developer.apple.com/library/content/qa/qa1398/_index.html\ntypedef uint64_t eidos_profile_t;\n\n// Get an uncorrected profile clock measurement (for EidosBenchmark), to be used as a start or end time\ninline __attribute__((always_inline)) eidos_profile_t Eidos_BenchmarkTime(void) { return mach_absolute_time(); }\n\n#elif defined(CHRONO_PROFILING)\n\n// For the <chrono> steady_clock time point representation, we will convert time points to nanoseconds since epoch\ntypedef uint64_t eidos_profile_t;\n\n// Get an uncorrected profile clock measurement (for EidosBenchmark), to be used as a start or end time\ninline __attribute__((always_inline)) eidos_profile_t Eidos_BenchmarkTime(void) { return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); }\n\n#endif\n\n#define EIDOS_BENCHMARK_START(x)\teidos_profile_t slim__benchmark_start = ((gEidosBenchmarkType == (x)) ? Eidos_BenchmarkTime() : 0);\n#define EIDOS_BENCHMARK_END(x)\tif (gEidosBenchmarkType == (x)) gEidosBenchmarkAccumulator += (Eidos_BenchmarkTime() - slim__benchmark_start);\n\n// Convert an elapsed profiling time (the difference between two Eidos_ProfileTime() results) to seconds\ndouble Eidos_ElapsedProfileTime(eidos_profile_t p_elapsed_profile_time);\n\n\n// For benchmarking purposes, we now have a small timing facility that can time one selected\n// piece of code, reporting the total time taken in that one piece of code as the total runtime\n// of the SLiM model.  This is entirely separate from the user-level profiling feature that\n// generates a profile report of a whole running model, and it is not user-visible.  The piece\n// of code selected for timing is chosen with an internal Eidos function, _startBenchmark().\n// You can either end benchmarking with _stopBenchmark() and get the elapsed seconds inside\n// the code benchmarked, as the return value, or let a command-line run finish and get the\n// total benchmarked time as console output.  Note that EidosBenchmark does not attempt to\n// correct for its own overhead/lag, so it is less accurate than profiling; it should be\n// used where relative times are more important than absolute times, and where the time spent\n// for one execution of the benchmarked code block takes a significant amount of time (making\n// overhead/lag negligible).  The enum has stuff for SLiM as well, for convenience.\n\ntypedef enum {\n\tkNone = 0,\n\t\n\t// Eidos internal\n\tk_SAMPLE_INDEX,\t\t\t\t\t// making an index buffer for sample(), to use in the sampling algorithm\n\tk_TABULATE_MAXBIN,\t\t\t\t// calculating the maxbin value for tabulate(), if not user-supplied\n\t\n\t// SLiM internal parallel loops\n\tk_AGE_INCR,\t\t\t\t\t\t// age increment, at end of tick\n\tk_DEFERRED_REPRO,\t\t\t\t// deferred reproduction (without callbacks) in nonWF models\n\tk_WF_REPRO,\t\t\t\t\t\t// WF reproduction (without callbacks)\n\tk_FITNESS_ASEX_1,\t\t\t\t// fitness calculation, asexual, with individual fitnessScaling values but no non-neutral mutations\n\tk_FITNESS_ASEX_2,\t\t\t\t// fitness calculation, asexual, with neither individual fitnessScaling nor non-neutral mutations\n\tk_FITNESS_ASEX_3,\t\t\t\t// fitness calculation, asexual, with individual fitnessScaling values and non-neutral mutations\n\tk_FITNESS_SEX_1,\t\t\t\t// fitness calculation, sexual, with individual fitnessScaling values but no non-neutral mutations\n\tk_FITNESS_SEX_2,\t\t\t\t// fitness calculation, sexual, with neither individual fitnessScaling nor non-neutral mutations\n\tk_FITNESS_SEX_3,\t\t\t\t// fitness calculation, sexual, with individual fitnessScaling values and non-neutral mutations\n\tk_MIGRANT_CLEAR,\t\t\t\t// clearing the migrant flag of individuals, at end of tick\n\tk_PARENTS_CLEAR,\t\t\t\t// clearing the haplosomes of parents at generation switch, in WF models\n\tk_UNIQUE_MUTRUNS,\t\t\t\t// uniquing mutation runs (periodic bookkeeping)\n\tk_SURVIVAL,\t\t\t\t\t\t// evaluating survival in nonWF models (without callbacks)\n\t\n\t// SLiM, whole tasks (not parallel loops)\n\tk_MUT_TALLY,\t\t\t\t\t// tally mutation reference counts, in Population::MaintainMutationRegistry()\n\tk_MUTRUN_FREE,\t\t\t\t\t// free unused mutation runs, in Population::MaintainMutationRegistry()\n\tk_MUT_FREE,\t\t\t\t\t\t// free fixed or unused mutations, in Population::MaintainMutationRegistry()\n\tk_SIMPLIFY_SORT_PRE,\t\t\t// pre-sorting for simplification, in slim_sort_edges()\n\tk_SIMPLIFY_SORT,\t\t\t\t// sorting for simplification, in slim_sort_edges()\n\tk_SIMPLIFY_SORT_POST,\t\t\t// post-sorting for simplification, in slim_sort_edges()\n\tk_SIMPLIFY_CORE,\t\t\t\t// the core simplification algorithm, in Species::SimplifyTreeSequence()\n} EidosBenchmarkType;\n\nextern EidosBenchmarkType gEidosBenchmarkType;\t\t\t// which code is being benchmarked in this run; kNone by default\nextern eidos_profile_t gEidosBenchmarkAccumulator;\t\t// accumulated profile counts for the benchmarked code\n\n\n#if (SLIMPROFILING == 1)\n// PROFILING\n\nextern int gEidosProfilingClientCount;\t// if non-zero, profiling is happening in some context\n\n// Profiling clocks; note that these can overflow, we don't care, only (t2-t1) ever matters and that is overflow-robust\n\nextern uint64_t gEidos_ProfileCounter;\t\t\t// incremented by Eidos_ProfileTime() every time it is called\nextern double gEidos_ProfileOverheadTicks;\t\t// the overhead for one profile call, in ticks\nextern double gEidos_ProfileOverheadSeconds;\t// the overhead for one profile call, in seconds\nextern double gEidos_ProfileLagTicks;\t\t\t// the clocked length of an empty profile block, in ticks\nextern double gEidos_ProfileLagSeconds;\t\t\t// the clocked length of an empty profile block, in seconds\n\n#if defined(MACH_PROFILING)\n\n// Get a profile clock measurement, to be used as a start or end time\ninline __attribute__((always_inline)) eidos_profile_t Eidos_ProfileTime(void) { gEidos_ProfileCounter++; return mach_absolute_time(); }\n\n#elif defined(CHRONO_PROFILING)\n\n// Get a profile clock measurement, to be used as a start or end time\ninline __attribute__((always_inline)) eidos_profile_t Eidos_ProfileTime(void) { gEidos_ProfileCounter++; return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); }\n\n#endif\n\n// This should be called immediately before profiling to measure the overhead and lag for profile blocks\nvoid Eidos_PrepareForProfiling(void);\n\n// Macros for profile blocks\n#define\tSLIM_PROFILE_BLOCK_START()\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tbool slim__condition_a = (gEidosProfilingClientCount ? true : false);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\teidos_profile_t slim__start_clock = (slim__condition_a ? Eidos_ProfileTime() : eidos_profile_t());\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tuint64_t slim__start_profile_counter = (slim__condition_a ? gEidos_ProfileCounter : 0);\n\n#define\tSLIM_PROFILE_BLOCK_START_NESTED()\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\teidos_profile_t slim__start_clock2 = (slim__condition_a ? Eidos_ProfileTime() : eidos_profile_t());\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tuint64_t slim__start_profile_counter2 = (slim__condition_a ? gEidos_ProfileCounter : 0);\n\n#define\tSLIM_PROFILE_BLOCK_START_CONDITION(slim__condition_param)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tbool slim__condition_b = gEidosProfilingClientCount && (slim__condition_param);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\teidos_profile_t slim__start_clock = (slim__condition_b ? Eidos_ProfileTime() : eidos_profile_t());\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tuint64_t slim__start_profile_counter = (slim__condition_b ? gEidos_ProfileCounter : 0);\n\n#define SLIM_PROFILE_BLOCK_END(slim__accumulator)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tif (slim__condition_a)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__end_profile_counter = gEidos_ProfileCounter;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__contained_profile_calls = slim__end_profile_counter - slim__start_profile_counter;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\teidos_profile_t slim__end_clock = Eidos_ProfileTime();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__uncorrected_ticks = (slim__end_clock - slim__start_clock);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__correction = static_cast<eidos_profile_t>(round(gEidos_ProfileLagTicks + gEidos_ProfileOverheadTicks * slim__contained_profile_calls));\t\t\t\t\\\n\t\tuint64_t slim__corrected_ticks = ((slim__correction < slim__uncorrected_ticks) ? (slim__uncorrected_ticks - slim__correction) : 0);\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t(slim__accumulator) += slim__corrected_ticks;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\n\n#define SLIM_PROFILE_BLOCK_END_NESTED(slim__accumulator)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tif (slim__condition_a)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__end_profile_counter2 = gEidos_ProfileCounter;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__contained_profile_calls2 = slim__end_profile_counter2 - slim__start_profile_counter2;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\teidos_profile_t slim__end_clock2 = Eidos_ProfileTime();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__uncorrected_ticks2 = (slim__end_clock2 - slim__start_clock2);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__correction2 = (eidos_profile_t)round(gEidos_ProfileLagTicks + gEidos_ProfileOverheadTicks * slim__contained_profile_calls2);\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__corrected_ticks2 = ((slim__correction2 < slim__uncorrected_ticks2) ? (slim__uncorrected_ticks2 - slim__correction2) : 0);\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t(slim__accumulator) += slim__corrected_ticks2;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\n\n#define SLIM_PROFILE_BLOCK_END_CONDITION(slim__accumulator)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tif (slim__condition_b)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__end_profile_counter = gEidos_ProfileCounter;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__contained_profile_calls = slim__end_profile_counter - slim__start_profile_counter;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\teidos_profile_t slim__end_clock = Eidos_ProfileTime();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__uncorrected_ticks = (slim__end_clock - slim__start_clock);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__correction = (eidos_profile_t)round(gEidos_ProfileLagTicks + gEidos_ProfileOverheadTicks * slim__contained_profile_calls);\t\t\t\t\t\t\t\\\n\t\tuint64_t slim__corrected_ticks = ((slim__correction < slim__uncorrected_ticks) ? (slim__uncorrected_ticks - slim__correction) : 0);\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t(slim__accumulator) += slim__corrected_ticks;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\n\n#endif\t// (SLIMPROFILING == 1)\n\n\n// *******************************************************************************************************************\n//\n//\tCLI progress reporting\n//\n#pragma mark -\n#pragma mark CLI progress reporting\n#pragma mark -\n\n// This is a nice open-source project showing how to do a progress bar: https://github.com/htailor/cpp_progress_bar\n// I didn't end up directly using it -- the approach is pretty simple and obvious, and I wanted something much\n// simpler really -- but I found a couple of useful snippets for formatting the stream output and stuff.  So,\n// thanks to Hemant Tailor for the nice project!  I'll give credit here in case someone else finds it useful.\n\nextern std::ostream *gEidos_progress_outstream;\t\t// the stream that progress lines are being written to\nextern int gEidos_progress_length;\t\t\t\t\t// the length of the last progress line written (for erasing)\n\nvoid Eidos_StartProgress(std::ostream *p_progress_stream);\t\t\t\t\t\t\t// tell Eidos you want to start writing\ninline bool Eidos_ShowingProgress(void) { return !!(gEidos_progress_outstream); }\t// are we showing progress?\nvoid Eidos_WriteProgress(const std::string &p_progress_line);\t\t\t\t\t\t// write a line out\nvoid Eidos_EraseProgress(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// erase the last line written\ninline int Eidos_ProgressLength(void) { return gEidos_progress_length; }\t\t\t// the length of the visible progress line\n\n\n// *******************************************************************************************************************\n//\n//\tTermination handling\n//\n#pragma mark -\n#pragma mark Termination handling\n#pragma mark -\n\n// Print a demangled stack backtrace of the caller function to FILE* out; see eidos_globals.cpp for credits and comments.\nvoid Eidos_PrintStacktrace(FILE *p_out = stderr, unsigned int p_max_frames = 63);\n\n// Print an offending line of script with carets indicating an error position\nvoid Eidos_LogScriptError(std::ostream& p_out, const EidosErrorContext &p_error_context);\n\n// If gEidosTerminateThrows == 0, << EidosTerminate causes a call to exit().  In that mode, output\n// related to termination output goes to cerr.  The other mode has gEidosTerminateThrows == 1.  In that mode,\n// we use a global ostringstream to capture all termination-related output, and whoever catches the raise handles\n// the termination stream.  All other Eidos output goes to ExecutionOutputStream(), defined on EidosInterpreter.\n// BCH 2/9/2021: Eidos output can now also go to ErrorOutputStream(), also defined on EidosInterpreter.\nextern bool gEidosTerminateThrows;\nextern std::ostringstream gEidosTermination;\n\n// BCH 3/9/2025: before starting error output, it would be nice to call Eidos_EraseProgress() to erase a\n// progress line, so the output doesn't get garbled; but that would complicate the flow a fair bit, and\n// probably it isn't really necessary since error output will almost always overwrite the progress completely.\n#define EIDOS_TERMINATION\t(gEidosTerminateThrows ? gEidosTermination : std::cerr)\n\n// This little class is used as a stream manipulator that causes termination with EXIT_FAILURE, optionally\n// with a backtrace.  This is nice since it lets us log and terminate in a single line of code.  It also allows\n// a GUI to intercept the exit() call and do something more graceful with it.\nclass EidosTerminate\n{\npublic:\n\tbool print_backtrace_ = false;\n\t\n\tEidosTerminate(void) = default;\t\t\t\t\t\t\t// default constructor, no backtrace, does not change error range\n\texplicit EidosTerminate(const EidosToken *p_error_token);\t// supply a token from which an error range is taken\n\texplicit EidosTerminate(const EidosErrorPosition &p_error_position);\t// supply an error position yourself\n\t\n\t// These constructors request a backtrace as well\n\texplicit EidosTerminate(bool p_print_backtrace);\n\tEidosTerminate(const EidosToken *p_error_token, bool p_print_backtrace);\n};\n\n// Send an EidosTerminate object to an output stream, causing a raise or an exit() call depending on\n// gEidosTerminateThrows.  Either way, this call does not return, so it is marked as noreturn as a hint\n// to the compiler.  Also, since this is always an error case, it is marked as cold as a hint to branch\n// prediction and optimization; all code paths that lead to this will be considered cold.\nvoid operator<<(std::ostream& p_out, const EidosTerminate &p_terminator) __attribute__((__noreturn__)) __attribute__((cold)) __attribute__((analyzer_noreturn));\n\n// Get the message from the last raise out of gEidosTermination, optionally with newlines trimmed from the ends\nstd::string Eidos_GetTrimmedRaiseMessage(void);\nstd::string Eidos_GetUntrimmedRaiseMessage(void);\n\n// This custom exception subclass is used to allow tick range evaluation in SLiM to be error-tolerant,\n// for the specific case of expressions that reference global constants that are not yet defined.\n// See Community::_EvaluateTickRangeNode() for the use of this facility.  It is thrown by\n// EidosSymbolTable::_GetValue_SpecialRaise() when a specific flag is set on the interpreter.\n// The message property is used by SLiM to pass up the name of the identifier that was undefined.\nclass SLiMUndefinedIdentifierException : public std::exception\n{ \nprivate: \n\tstd::string message;\n\t\npublic: \n\texplicit SLiMUndefinedIdentifierException(const char* msg) : message(msg) {}\n\texplicit SLiMUndefinedIdentifierException(const std::string &msg) : message(msg) {}\n\t\n\tconst char* what() const noexcept { return message.c_str(); } \n};\n\n// Similarly, this custom exception subclass is used to allow tick range evaluation to tolerate\n// undefined function names during the initial attempt in Community::FinishInitialization(),\n// before initialize() callbacks have run and thus before user-defined functions are set up.\n// Unlike SLiMUndefinedIdentifierException, an error string is not needed.\nclass SLiMUndefinedFunctionException : public std::exception\n{ \npublic: \n\tSLiMUndefinedFunctionException() {}\n\t\n\tconst char* what() const noexcept { return \"\"; } \n};\n\n\n// *******************************************************************************************************************\n//\n//\tFile I/O functions\n//\n#pragma mark -\n#pragma mark File I/O\n#pragma mark -\n\n// Resolve a leading ~ in a filesystem path to the user's home directory\nstd::string Eidos_ResolvedPath(const std::string &p_path);\n\n// Generate a canonical absolute path corresponding to the provided path\nstd::string Eidos_AbsolutePath(const std::string &p_path);\n\n// Get the filename (or a trailing directory name) from a path\nstd::string Eidos_LastPathComponent(const std::string &p_path);\n\n// Get the current working directory; oddly, C++ has no API for this\nstd::string Eidos_CurrentDirectory(void);\n\n// Remove a trailing slash in a path like ~/foo/bar/\nstd::string Eidos_StripTrailingSlash(const std::string &p_path);\n\n// Create a directory at a given filesystem path if it does not already exist (which is not an error);\n// calls Eidos_ResolvedPath() on the given path, since I think we always want that anyway.  Returns false\n// if the operation fails (i.e. the directory may or may not even exist).  Returns true if the directory\n// exists.  A warning string can be returned through p_error_string, even if true is returned; for example,\n// if the directory already exists a warning is emitted but the return value is true.\nbool Eidos_CreateDirectory(const std::string &p_path, std::string *p_error_string);\n\n// This is /tmp/ (with trailing slash!) on macOS and Linux, but will be elsewhere on Windows.  Should be used instead of /tmp/ everywhere.\nstd::string Eidos_TemporaryDirectory(void);\n\n// Returns true if Eidos_TemporaryDirectory() appears to exist and be writeable, false otherwise\n// Apparently on some cluster systems /tmp does not exist, weirdly... I have no idea what's up with that...\nbool Eidos_TemporaryDirectoryExists(void);\n\n// Create a temporary file based upon a template filename; note that pattern is modified!\nint Eidos_mkstemps(char *p_pattern, int p_suffix_len);\nint Eidos_mkstemps_directory(char *p_pattern, int p_suffix_len);\n\n// Writing files with support for gzip compression and buffered flushing\n#define EIDOS_BUFFER_ZIP_APPENDS\t1\n\n#if EIDOS_BUFFER_ZIP_APPENDS\t// implementation details for Eidos_FlushFiles(); for internal use only\nextern std::unordered_map<std::string, std::string> gEidosBufferedZipAppendData;\t// canonical absolute file path -> buffered text\nbool _Eidos_FlushZipBuffer(const std::string &p_file_path, const std::string &p_outstring);\n#endif\n\nvoid Eidos_FlushFile(const std::string &p_file_path);\nbool Eidos_FlushFiles(void);\t\t\t// This should be called at the end of execution, or any other appropriate time, to flush buffered file append data; returns false for failure\n\nenum class EidosFileFlush {\n\tkNoFlush = 0,\t\t// no flush, no matter what\n\tkDefaultFlush,\t\t// flush if the buffer is over a threshold number of bytes\n\tkForceFlush\t\t\t// flush, no matter what; not recommended with compression\n};\n\nvoid Eidos_WriteToFile(const std::string &p_file_path, const std::vector<const std::string *> &p_contents, bool p_append, bool p_compress, EidosFileFlush p_flush_option);\n\n\n// *******************************************************************************************************************\n//\n//\tUtility functions\n//\n#pragma mark -\n#pragma mark Utility functions\n#pragma mark -\n\n// bzero() is deprecated, but memset() is not a perfect substitute, so this is a macro to use instead\n// this follows the standard bzero() declaration: void bzero(void *s, size_t n);\n// see https://stackoverflow.com/a/17097978/2752221 for some justification\n#define EIDOS_BZERO(s, n) memset((s), 0, (n))\n\n// Correlation between two vectors x and y of equal length; int64_t or double are used, and can be mixed\ntemplate <typename T1, typename T2>\ndouble Eidos_Correlation(T1 *x, T2 *y, size_t count)\n{\n\t// when the covariance is undefined because there are too few values, R returns NA; we return NAN\n\tif (count <= 1)\n\t\treturn std::numeric_limits<double>::quiet_NaN();\n\t\n\tif (static_cast<const void *>(x) == static_cast<const void *>(y))\n\t{\n\t\t// if x == y, we're being asked to calculate a self-correlation, which is simply 1.0\n\t\treturn 1.0;\n\t}\n\telse\n\t{\n\t\t// calculate means\n\t\tdouble mean_x = 0, mean_y = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tmean_x += x[value_index];\n\t\t\tmean_y += y[value_index];\n\t\t}\n\t\t\n\t\tmean_x /= count;\n\t\tmean_y /= count;\n\t\t\n\t\t// calculate sums of squares and products of differences\n\t\tdouble ss_x = 0, ss_y = 0, diff_prod = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tdouble dx = x[value_index] - mean_x;\n\t\t\tdouble dy = y[value_index] - mean_y;\n\t\t\t\n\t\t\tss_x += dx * dx;\n\t\t\tss_y += dy * dy;\n\t\t\tdiff_prod += dx * dy;\n\t\t}\n\t\t\n\t\t// calculate correlation\n\t\treturn (diff_prod / (sqrt(ss_x) * sqrt(ss_y)));\n\t}\n}\n\n// Covariance between two vectors x and y of equal length; int64_t or double are used, and can be mixed\ntemplate <typename T1, typename T2>\ndouble Eidos_Covariance(T1 *x, T2 *y, size_t count)\n{\n\t// when the covariance is undefined because there are too few values, R returns NA; we return NAN\n\tif (count <= 1)\n\t\treturn std::numeric_limits<double>::quiet_NaN();\n\t\n\tif (static_cast<const void *>(x) == static_cast<const void *>(y))\n\t{\n\t\t// if x == y, we're being asked to calculate variance, which can be done more efficiently\n\t\t\n\t\t// calculate mean\n\t\tdouble mean = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t\tmean += x[value_index];\n\t\t\n\t\tmean /= count;\n\t\t\n\t\t// calculate variance\n\t\tdouble var = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tdouble d = x[value_index] - mean;\n\t\t\t\n\t\t\tvar += d * d;\n\t\t}\n\t\t\n\t\t// calculate correlation\n\t\treturn (var / (count - 1));\n\t}\n\telse\n\t{\n\t\t// calculate means\n\t\tdouble mean_x = 0, mean_y = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tmean_x += x[value_index];\n\t\t\tmean_y += y[value_index];\n\t\t}\n\t\t\n\t\tmean_x /= count;\n\t\tmean_y /= count;\n\t\t\n\t\t// calculate covariance\n\t\tdouble cov = 0;\n\t\t\n\t\tfor (size_t value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tdouble dx = x[value_index] - mean_x;\n\t\t\tdouble dy = y[value_index] - mean_y;\n\t\t\t\n\t\t\tcov += dx * dy;\n\t\t}\n\t\t\n\t\t// calculate correlation\n\t\treturn (cov / (count - 1));\n\t}\n}\n\n// Welch's t-test functions; sample means are returned in mean1 and mean2, which may be nullptr\ndouble Eidos_TTest_TwoSampleWelch(const double *p_set1, int p_count1, const double *p_set2, int p_count2, double *p_mean1, double *p_mean2);\ndouble Eidos_TTest_OneSample(const double *p_set1, int p_count1, double p_mu, double *p_mean1);\n\n// Exact summation of a floating-point vector using the Shewchuk algorithm; surprisingly, not in the GSL\ndouble Eidos_ExactSum(const double *p_double_vec, int64_t p_vec_length);\n\n// Approximate equality of two floating-point numbers, within a ratio tolerance of 1.0001\nbool Eidos_ApproximatelyEqual(double a, double b);\n\n// Split a std::string into a vector of substrings separated by a given delimiter\nstd::vector<std::string> Eidos_string_split(const std::string &p_str, const std::string &p_delim);\nstd::string Eidos_string_join(const std::vector<std::string> &p_vec, const std::string &p_delim);\nbool Eidos_string_hasPrefix(std::string const &fullString, std::string const &prefix);\nbool Eidos_string_hasSuffix(std::string const &fullString, std::string const &suffix);\nbool Eidos_string_containsCaseInsensitive(const std::string &strHaystack, const std::string &strNeedle);\nbool Eidos_string_equalsCaseInsensitive(const std::string &s1, const std::string &s2);\n\n// Quote and escape a string\nenum class EidosStringQuoting {\n\tkNoQuotes = 0,\n\tkSingleQuotes,\n\tkDoubleQuotes,\n\tkChooseQuotes\t\t// chooses single or double, whichever seems better\n};\n\nstd::string Eidos_string_escaped(const std::string &unescapedString, EidosStringQuoting quoting);\t\t// quotes and adds backslash escapes\nstd::string Eidos_string_escaped_CSV(const std::string &unescapedString);\t\t\t\t\t\t\t\t// quotes and \"\"-escapes quotes\n\n// Run a Unix command\n// BCH 13 December 2017: no longer used, commenting this out\n//std::string Eidos_Exec(const char *p_cmd);\n\nextern int gEidosFloatOutputPrecision;\t\t// precision used for output of float values in Eidos; not user-visible at present\n\nstd::string EidosStringForFloat(double p_value);\n\nint DisplayDigitsForIntegerPart(double x);\t// number of digits needed to display the integer part of a double\n\n// Fisher-Yates Shuffle: choose a random subset of a std::vector, without replacement.\n// see https://stackoverflow.com/questions/9345087/choose-m-elements-randomly-from-a-vector-containing-n-elements\n// see also https://ideone.com/3A3cv for demo code using this\n// Note that this uses random(), not the GSL RNG.  This is actually desirable, because we use this\n// for doing haplotype display stuff; using random() avoids altering the simulation state.  For use\n// in a simulation, see the implementation of sample() for some useful approaches.\ntemplate<class BidiIter>\nBidiIter Eidos_random_unique(BidiIter begin, BidiIter end, size_t num_random)\n{\n\tsize_t left = std::distance(begin, end);\n\t\n\twhile (num_random--)\n\t{\n\t\tBidiIter r = begin;\n\t\tstd::advance(r, random() % left);\n\t\tstd::swap(*begin, *r);\n\t\t++begin;\n\t\t--left;\n\t}\n\t\n\treturn begin;\n}\n\n// The <regex> library does not work on Ubuntu 18.04, annoyingly; probably a very old compiler or something.  So we have to check.\nbool Eidos_RegexWorks(void);\n\n// Checks that symbol_name does not contain any illegal Unicode characters; used to check identifiers, in particular\nbool Eidos_ContainsIllegalUnicode(const std::string &symbol_name);\n\n\n// *******************************************************************************************************************\n//\n//\tSHA-256\n//\n#pragma mark -\n#pragma mark SHA-256\n#pragma mark -\n\n// from https://github.com/amosnier/sha-2 which is under the public-domain \"unlicense\"; see .cpp for further details\nvoid Eidos_calc_sha_256(uint8_t hash[32], const void *input, size_t len);\t// len is the number of bytes in input\nvoid Eidos_hash_to_string(char string[65], const uint8_t hash[32]);\n\n\n// *******************************************************************************************************************\n//\n//\tLocking\n//\n#pragma mark -\n#pragma mark Locking\n#pragma mark -\n\n// exception-safe RAII-based locking; modified from https://stackoverflow.com/a/2201076/2752221\n// I didn't want to depend upon assert(), so I removed that; the user is responsible for checking the flag before locking\n// The point of this is simply that the lock flag gets cleared automatically on exit by RAII, even with exceptions\nclass Eidos_simple_lock\n{\nprivate:\n\tEidos_simple_lock(const Eidos_simple_lock&) = delete;\n\tEidos_simple_lock& operator=(const Eidos_simple_lock&) = delete;\n\t\n\tbool& mLock;\n\t\npublic:\n\texplicit Eidos_simple_lock(bool& pLock) : mLock(pLock)\t{\tmLock = true;\t}\n\t~Eidos_simple_lock(void)\t\t\t\t\t\t\t\t{\tmLock = false;\t}\n};\n\n\n// *******************************************************************************************************************\n//\n//\tOverflow-detecting integer operations\n//\n#pragma mark -\n#pragma mark Overflow-detecting integer operations\n#pragma mark -\n\n// Clang and GCC 5.0 support a suite a builtin functions that perform integer operations with detection of overflow.\n//\n//     http://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins and\n//     https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html\n//\n// We want to use those builtins when possible, so that Eidos integer arithmetic is robust against overflow bugs.\n// However, since GCC pre-5.0 doesn't have these builtins, and other compilers probably don't either, we have to\n// do some messy version checking and such.\n\n// BCH 6 April 2016: switched from the type-specific variants (i.e. __builtin_saddll_overflow, etc.) to the\n// type-non-specific variants (i.e. __builtin_add_overflow) since some platforms use more than 64 bits for\n// \"long long\".  The non-specific variants should choose which type-specific variant to use at compile time\n// anyway, so this should not be an issue as long as we are careful to always use int64_t operands.\n\n#if (defined(__clang__) && defined(__has_builtin))\n\n#if __has_builtin(__builtin_add_overflow)\n// Clang with support for overflow built-ins (if one is defined we assume all of them are)\n#define Eidos_add_overflow(a, b, c)\t__builtin_add_overflow((a), (b), (c))\n#define Eidos_sub_overflow(a, b, c)\t__builtin_sub_overflow((a), (b), (c))\n#define Eidos_mul_overflow(a, b, c)\t__builtin_mul_overflow((a), (b), (c))\n#endif\n\n#elif defined(__GNUC__)\n\n#if (__GNUC__ >= 5)\n// GCC 5.0 or later; overflow built-ins supported\n#define Eidos_add_overflow(a, b, c)\t__builtin_add_overflow((a), (b), (c))\n#define Eidos_sub_overflow(a, b, c)\t__builtin_sub_overflow((a), (b), (c))\n#define Eidos_mul_overflow(a, b, c)\t__builtin_mul_overflow((a), (b), (c))\n#endif\n\n#endif\n\n// Uncomment these to test handling of missing built-ins on a system that does have the built-ins; with these\n// uncommented, the Eidos test suite should emit a warning about missing integer overflow checks, but all tests\n// that are run should pass.\n//#undef Eidos_add_overflow\n//#undef Eidos_sub_overflow\n//#undef Eidos_mul_overflow\n\n\n#ifdef Eidos_add_overflow\n\n#define EIDOS_HAS_OVERFLOW_BUILTINS\t\t1\n\n#else\n\n// Define the macros to just use simple operators, in all other cases.  Note that this means overflows are not\n// detected!  The Eidos test suite will emit a warning in this case, telling the user to upgrade their compiler.\n#define Eidos_add_overflow(a, b, c)\t(*(c)=(a)+(b), false)\n#define Eidos_sub_overflow(a, b, c)\t(*(c)=(a)-(b), false)\n#define Eidos_mul_overflow(a, b, c)\t(*(c)=(a)*(b), false)\n#define EIDOS_HAS_OVERFLOW_BUILTINS\t\t0\n\n#endif\n\n\n// *******************************************************************************************************************\n//\n//\tFloating point representation in text\n//\n#pragma mark -\n#pragma mark Floating point representation\n#pragma mark -\n\n// The question here is how many digits are needed to print out in text representations of floating-point numbers\n// in order to preserve their exact value.  This is quite a complicated question, and the macros in float.h needed\n// to resolve it are not always available.  See the answer from chux at https://stackoverflow.com/a/19897395/2752221,\n// which this is based upon.  The EIDOS_DBL_DIGS and EIDOS_FLT_DIGS macros defined here can be used directly with\n// a printf() format of %.*g with a double or float argument, respectively, to produce a correct representation in\n// all cases, if I understand that thread correctly.\n\n#ifdef DBL_DECIMAL_DIG\n#define EIDOS_DBL_DIGS (DBL_DECIMAL_DIG)\n#else  \n#define EIDOS_DBL_DIGS (DBL_DIG + 3)\n#endif\n\n#ifdef FLT_DECIMAL_DIG\n#define EIDOS_FLT_DIGS (FLT_DECIMAL_DIG)\n#else  \n#define EIDOS_FLT_DIGS (FLT_DIG + 3)\n#endif\n\n\n// *******************************************************************************************************************\n//\n//\tGlobal strings & IDs\n//\n#pragma mark -\n#pragma mark Global strings & IDs\n#pragma mark -\n\n//\n//\tGlobal std::string objects.  This is kind of gross, but there are several rationales for it.  First of all, it makes\n//\ta speed difference; converting a C string to a std::string is done every time it is hit in the code (C++ does not\n//\ttreat that as a constant expression and cache it for you, at least with the current generation of compilers).  The\n//\tconversion is surprisingly slow; it has shown up repeatedly in profiles I have done.  Second, there is the issue of\n//\tuniqueness; many of these strings occur in multiple places in the code, and a typo in one of those multiple occurrences\n//\twould cause a bug that would be very difficult to find.  If multiple places in the code intend to refer to the same\n//\tconceptual string, and rely on those references being the same, then a shared constant should be used.  So... oh well.\n//\n\ntypedef uint32_t EidosGlobalStringID;\n\nclass _EidosRegisteredString;\n\n// The string registry itself.  This is a bit of an odd design; the class has a singleton instance, but that is hidden\n// and all the public API is static methods.  This makes the syntax for using the registry smoother; you don't have\n// to ask for the shared instance, that's an implementation detail.  The reason for this implementation choice is that\n// it gets us past C++'s incredibly annoying \"static initialization order fiasco\"; since all access to the internals\n// of the registry is guarded by the singleton bottleneck, our private ivars are guaranteed to get initialized on\n// demand.  If we just made them static data members and got rid of the singleton pattern, there would be a global\n// initialize-time order dependency, since calls to register strings get made as a side effect of global initialization;\n// the registration call might occur when the statics for the registry had not been set up yet.\nclass EidosStringRegistry\n{\nprivate:\n\t// robin_hood seems unnecessary here, dynamic lookups are generally not a bottleneck because EidosGlobalStringID gets cached\n\tstd::unordered_map<std::string, EidosGlobalStringID> gStringToID;\n\tstd::unordered_map<EidosGlobalStringID, const std::string *> gIDToString;\n\tstd::vector<const _EidosRegisteredString *> gIDToString_Thunk;\n\tstd::vector<const std::string *> globalString_Thunk;\n\tEidosGlobalStringID gNextUnusedID;\n\t\n\tEidosStringRegistry(const EidosStringRegistry&) = delete;\t\t\t\t\t// no copying\n\tEidosStringRegistry& operator=(const EidosStringRegistry&) = delete;\t\t// no copying\n\tEidosStringRegistry(void);\t\t\t\t\t\t\t\t\t\t\t\t\t// construction is private\n\t~EidosStringRegistry(void);\n\t\n\t// this is the singleton bottleneck, thread-safe with C++11\n\tstatic inline EidosStringRegistry& sharedRegistry(void)\n\t{\n\t\tstatic EidosStringRegistry instance;\n\t\treturn instance;\n\t}\n\t\n\tEidosGlobalStringID _GlobalStringIDForString(const std::string &p_string);\n\tconst std::string &_StringForGlobalStringID(EidosGlobalStringID p_string_id);\n\tvoid _RegisterStringForGlobalID(const std::string &p_string, EidosGlobalStringID p_string_id);\n\t\n\t// This registers a standard string with a given ID.  This should not be called directly, to avoid initialization order\n\t// problems; instead, declare a global EidosRegisteredString.  All IDs used by the Context should start at gEidosID_LastEntry.\n\t// This function does not make a copy of the string that it is passed, since it is intended for use with global strings.\n\tstatic void RegisterStringForGlobalID(const std::string &p_string, EidosGlobalStringID p_string_id)\n\t{\n\t\treturn EidosStringRegistry::sharedRegistry()._RegisterStringForGlobalID(p_string, p_string_id);\n\t}\n    \npublic:\n\t// GlobalStringIDForString() takes any string and uniques it through a hash table.  If the string does not already exist\n\t// in the hash table, it is copied, and the copy is registered and returned as the uniqued string.\n\tstatic inline EidosGlobalStringID GlobalStringIDForString(const std::string &p_string)\n\t{\n\t\treturn EidosStringRegistry::sharedRegistry()._GlobalStringIDForString(p_string);\n\t}\n\t\n\t// StringForGlobalStringID() returns the uniqued global string for the ID through a reverse lookup.  The reference\n\t// returned is to the uniqued string stored internally by the registry, so it will be the same every time this is called,\n\t// and does not need to be copied if kept externally.\n\tstatic const std::string &StringForGlobalStringID(EidosGlobalStringID p_string_id)\n\t{\n\t\treturn EidosStringRegistry::sharedRegistry()._StringForGlobalStringID(p_string_id);\n\t}\n    \n#if SLIM_LEAK_CHECKING\n    static inline void ThunkRegistration(_EidosRegisteredString *p_registration_object)\n    {\n        EidosStringRegistry::sharedRegistry().gIDToString_Thunk.emplace_back(p_registration_object);\n    }\n#endif\n\t\n\tfriend class _EidosRegisteredString;\n};\n\n// This class is used to register a string with a given id, calling RegisterStringForGlobalID() as a construction side effect.\nclass _EidosRegisteredString\n{\nprivate:\n\tconst std::string string_;\n\tconst EidosGlobalStringID string_id_;\n\tinline _EidosRegisteredString(const char *p_cstr, EidosGlobalStringID p_id) : string_(p_cstr), string_id_(p_id)\n\t{\n\t\tEidosStringRegistry::RegisterStringForGlobalID(string_, string_id_);\n\t}\npublic:\n\tfriend const std::string &EidosRegisteredString(const char *p_cstr, EidosGlobalStringID p_id);\n};\n\n// This should be used as the \"constructor\" for _EidosRegisteredString, yielding a std::string& that is the uniqued string object\nconst std::string &EidosRegisteredString(const char *p_cstr, EidosGlobalStringID p_id);\n\n\nextern const std::string &gEidosStr_empty_string;\nextern const std::string &gEidosStr_space_string;\n\nextern const std::string &gEidosStr_apply;\nextern const std::string &gEidosStr_sapply;\nextern const std::string &gEidosStr_doCall;\nextern const std::string &gEidosStr_executeLambda;\nextern const std::string &gEidosStr__executeLambda_OUTER;\nextern const std::string &gEidosStr_ls;\nextern const std::string &gEidosStr_rm;\nextern const std::string &gEidosStr_usage;\n\nextern const std::string &gEidosStr_if;\nextern const std::string &gEidosStr_else;\nextern const std::string &gEidosStr_do;\nextern const std::string &gEidosStr_while;\nextern const std::string &gEidosStr_for;\nextern const std::string &gEidosStr_in;\nextern const std::string &gEidosStr_next;\nextern const std::string &gEidosStr_break;\nextern const std::string &gEidosStr_return;\nextern const std::string &gEidosStr_function;\n\nextern const std::string &gEidosStr_T;\nextern const std::string &gEidosStr_F;\nextern const std::string &gEidosStr_NULL;\nextern const std::string &gEidosStr_PI;\nextern const std::string &gEidosStr_E;\nextern const std::string &gEidosStr_INF;\nextern const std::string &gEidosStr_MINUS_INF;\t// \"-INF\"\nextern const std::string &gEidosStr_NAN;\n\nextern const std::string &gEidosStr_void;\nextern const std::string &gEidosStr_logical;\nextern const std::string &gEidosStr_string;\nextern const std::string &gEidosStr_integer;\nextern const std::string &gEidosStr_float;\nextern const std::string &gEidosStr_object;\nextern const std::string &gEidosStr_numeric;\n\nextern const std::string &gEidosStr_ELLIPSIS;\nextern const std::string &gEidosStr_type;\nextern const std::string &gEidosStr_source;\nextern const std::string &gEidosStr_GetPropertyOfElements;\nextern const std::string &gEidosStr_ExecuteInstanceMethod;\nextern const std::string &gEidosStr_undefined;\nextern const std::string &gEidosStr_applyValue;\n\nextern const std::string &gEidosStr_Object;\nextern const std::string &gEidosStr_size;\nextern const std::string &gEidosStr_length;\nextern const std::string &gEidosStr_methodSignature;\nextern const std::string &gEidosStr_propertySignature;\nextern const std::string &gEidosStr_str;\nextern const std::string &gEidosStr_stringRepresentation;\n\nextern const std::string &gEidosStr__TestElement;\nextern const std::string &gEidosStr__TestElementNRR;\nextern const std::string &gEidosStr__yolk;\nextern const std::string &gEidosStr__increment;\nextern const std::string &gEidosStr__cubicYolk;\nextern const std::string &gEidosStr__squareTest;\n\nextern const std::string &gEidosStr_Dictionary;\nextern const std::string &gEidosStr_allKeys;\nextern const std::string &gEidosStr_addKeysAndValuesFrom;\nextern const std::string &gEidosStr_appendKeysAndValuesFrom;\nextern const std::string &gEidosStr_clearKeysAndValues;\nextern const std::string &gEidosStr_compactIndices;\nextern const std::string &gEidosStr_getRowValues;\nextern const std::string &gEidosStr_getValue;\nextern const std::string &gEidosStr_identicalContents;\nextern const std::string &gEidosStr_serialize;\nextern const std::string &gEidosStr_setValue;\nextern const std::string &gEidosStr_setValuesVectorized;\n\nextern const std::string &gEidosStr_DictionaryRetained;\n\nextern const std::string &gEidosStr_DataFrame;\nextern const std::string &gEidosStr_colNames;\nextern const std::string &gEidosStr_dim;\nextern const std::string &gEidosStr_ncol;\nextern const std::string &gEidosStr_nrow;\nextern const std::string &gEidosStr_asMatrix;\nextern const std::string &gEidosStr_cbind;\nextern const std::string &gEidosStr_rbind;\nextern const std::string &gEidosStr_subset;\nextern const std::string &gEidosStr_subsetColumns;\nextern const std::string &gEidosStr_subsetRows;\n\nextern const std::string &gEidosStr_Image;\nextern const std::string &gEidosStr_width;\nextern const std::string &gEidosStr_height;\nextern const std::string &gEidosStr_bitsPerChannel;\nextern const std::string &gEidosStr_isGrayscale;\nextern const std::string &gEidosStr_integerR;\nextern const std::string &gEidosStr_integerG;\nextern const std::string &gEidosStr_integerB;\nextern const std::string &gEidosStr_integerK;\nextern const std::string &gEidosStr_floatR;\nextern const std::string &gEidosStr_floatG;\nextern const std::string &gEidosStr_floatB;\nextern const std::string &gEidosStr_floatK;\nextern const std::string &gEidosStr_write;\n\nextern const std::string &gEidosStr_start;\nextern const std::string &gEidosStr_end;\nextern const std::string &gEidosStr_weights;\nextern const std::string &gEidosStr_range;\nextern const std::string &gEidosStr_c;\nextern const std::string &gEidosStr_t;\nextern const std::string &gEidosStr_n;\nextern const std::string &gEidosStr_s;\nextern const std::string &gEidosStr_x;\nextern const std::string &gEidosStr_y;\nextern const std::string &gEidosStr_z;\nextern const std::string &gEidosStr_xy;\nextern const std::string &gEidosStr_xz;\nextern const std::string &gEidosStr_yz;\nextern const std::string &gEidosStr_xyz;\nextern const std::string &gEidosStr_color;\nextern const std::string &gEidosStr_filePath;\n\nextern const std::string &gEidosStr_Mutation;\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\nextern const std::string &gEidosStr_Haplosome;\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\nextern const std::string &gEidosStr_Individual;\t// in Eidos for hack reasons; see EidosValue_Object::EidosValue_Object()\n\n// the compile-time-constant IDs associated with the above strings\nenum _EidosGlobalStringID : uint32_t\n{\n\tgEidosID_none = 0,\n\t\n\tgEidosID_empty_string,\n\tgEidosID_space_string,\n\n\tgEidosID_apply,\n\tgEidosID_sapply,\n\tgEidosID_doCall,\n\tgEidosID_executeLambda,\n\tgEidosID__executeLambda_OUTER,\n\tgEidosID_ls,\n\tgEidosID_rm,\n\tgEidosID_usage,\n\n\tgEidosID_if,\n\tgEidosID_else,\n\tgEidosID_do,\n\tgEidosID_while,\n\tgEidosID_for,\n\tgEidosID_in,\n\tgEidosID_next,\n\tgEidosID_break,\n\tgEidosID_return,\n\tgEidosID_function,\n\n\tgEidosID_T,\n\tgEidosID_F,\n\tgEidosID_NULL,\n\tgEidosID_PI,\n\tgEidosID_E,\n\tgEidosID_INF,\n\tgEidosID_MINUS_INF,\n\tgEidosID_NAN,\n\n\tgEidosID_void,\n\tgEidosID_logical,\n\tgEidosID_string,\n\tgEidosID_integer,\n\tgEidosID_float,\n\tgEidosID_object,\n\tgEidosID_numeric,\n\n\tgEidosID_ELLIPSIS,\n\tgEidosID_type,\n\tgEidosID_source,\n\tgEidosID_GetPropertyOfElements,\n\tgEidosID_ExecuteInstanceMethod,\n\tgEidosID_undefined,\n\tgEidosID_applyValue,\n\t\n\tgEidosID_Object,\n\tgEidosID_size,\n\tgEidosID_length,\n\tgEidosID_methodSignature,\n\tgEidosID_propertySignature,\n\tgEidosID_str,\n\tgEidosID_stringRepresentation,\n\n\tgEidosID__TestElement,\n\tgEidosID__TestElementNRR,\n\tgEidosID__yolk,\n\tgEidosID__increment,\n\tgEidosID__cubicYolk,\n\tgEidosID__squareTest,\n\n\tgEidosID_Dictionary,\n\tgEidosID_allKeys,\n\tgEidosID_addKeysAndValuesFrom,\n\tgEidosID_appendKeysAndValuesFrom,\n\tgEidosID_clearKeysAndValues,\n\tgEidosID_compactIndices,\n\tgEidosID_getRowValues,\n\tgEidosID_getValue,\n\tgEidosID_identicalContents,\n\tgEidosID_serialize,\n\tgEidosID_setValue,\n\tgEidosID_setValuesVectorized,\n\n\tgEidosID_DictionaryRetained,\n\n\tgEidosID_DataFrame,\n\tgEidosID_colNames,\n\tgEidosID_dim,\n\tgEidosID_ncol,\n\tgEidosID_nrow,\n\tgEidosID_asMatrix,\n\tgEidosID_cbind,\n\tgEidosID_rbind,\n\tgEidosID_subset,\n\tgEidosID_subsetColumns,\n\tgEidosID_subsetRows,\n\n\tgEidosID_Image,\n\tgEidosID_width,\n\tgEidosID_height,\n\tgEidosID_bitsPerChannel,\n\tgEidosID_isGrayscale,\n\tgEidosID_integerR,\n\tgEidosID_integerG,\n\tgEidosID_integerB,\n\tgEidosID_integerK,\n\tgEidosID_floatR,\n\tgEidosID_floatG,\n\tgEidosID_floatB,\n\tgEidosID_floatK,\n\tgEidosID_write,\n\n\tgEidosID_start,\n\tgEidosID_end,\n\tgEidosID_weights,\n\tgEidosID_range,\n\tgEidosID_c,\n\tgEidosID_t,\n\tgEidosID_n,\n\tgEidosID_s,\n\tgEidosID_x,\n\tgEidosID_y,\n\tgEidosID_z,\n\tgEidosID_xy,\n\tgEidosID_xz,\n\tgEidosID_yz,\n\tgEidosID_xyz,\n\tgEidosID_color,\n\tgEidosID_filePath,\n\n\tgEidosID_Mutation,\n\tgEidosID_Haplosome,\n\tgEidosID_Individual,\n\t\n\tgEidosID_LastEntry,\t\t\t\t\t// IDs added by the Context should start here\n\tgEidosID_LastContextEntry = 550\t\t// IDs added by the Context must end before this value; Eidos reserves the remaining values\n};\n\nextern std::vector<std::string> gEidosConstantNames;\t// T, F, NULL, PI, E, INF, NAN\n\n\n// *******************************************************************************************************************\n//\n//\tSupport for named / specified colors in SLiM\n//\n#pragma mark -\n#pragma mark Named/specified color support\n#pragma mark -\n\ntypedef struct {\n\tconst char *name;\n\tuint8_t red, green, blue;\n} EidosNamedColor;\n\nextern EidosNamedColor gEidosNamedColors[];\n\nvoid Eidos_GetColorComponents(const std::string &p_color_name, float *p_red_component, float *p_green_component, float *p_blue_component);\nvoid Eidos_GetColorComponents(const std::string &p_color_name, uint8_t *p_red_component, uint8_t *p_green_component, uint8_t *p_blue_component);\n\nvoid Eidos_GetColorString(double p_red, double p_green, double p_blue, char *p_string_buffer);\t\t// p_string_buffer must have room for 8 chars, including the null\nvoid Eidos_GetColorString(uint8_t p_red, uint8_t p_green, uint8_t p_blue, char *p_string_buffer);\t// p_string_buffer must have room for 8 chars, including the null\n\nvoid Eidos_HSV2RGB(double h, double s, double v, double *p_r, double *p_g, double *p_b);\nvoid Eidos_RGB2HSV(double r, double g, double b, double *p_h, double *p_s, double *p_v);\n\nenum class EidosColorPalette : int\n{\n\tkPalette_INVALID = -1,\n\tkPalette_cm = 0,\n\tkPalette_heat,\n\tkPalette_terrain,\n\tkPalette_parula,\n\tkPalette_hot,\n\tkPalette_jet,\n\tkPalette_turbo,\n\tkPalette_gray,\n\tkPalette_magma,\n\tkPalette_inferno,\n\tkPalette_plasma,\n\tkPalette_viridis,\n\tkPalette_cividis,\n};\n\nEidosColorPalette Eidos_PaletteForName(const std::string &name);\n\nvoid Eidos_ColorPaletteLookup(double fraction, EidosColorPalette palette, double &r, double &g, double &b);\n\n\n// *******************************************************************************************************************\n//\n//\tBasic EidosValue stuff (not in eidos_value.h to break circular header problems)\n//\n#pragma mark -\n#pragma mark Basic EidosValue stuff\n#pragma mark -\n\nclass EidosValue;\nclass EidosValue_VOID;\nclass EidosValue_NULL;\nclass EidosValue_Logical;\nclass EidosValue_Int;\nclass EidosValue_Float;\nclass EidosValue_String;\nclass EidosValue_Object;\n\nclass EidosObjectPool;\nclass EidosPropertySignature;\nclass EidosMethodSignature;\nclass EidosInstanceMethodSignature;\nclass EidosInterpreter;\nclass EidosToken;\n\nclass EidosObject;\t// the value type for EidosValue_Object\nclass EidosClass;\t\t// the class definition object for EidosObject\n\n\n// Type int64_t is used for Eidos \"integer\", type double is used for Eidos \"float\", type std::string is used\n// for Eidos \"string\", and EidosObject* is used for Eidos \"object\".  The type used for Eidos \"logical\"\n// is a bit less clear, and so is controlled by a typedef here.  Type bool would be the obvious choice, but\n// std::vector<bool> is a special class that may not be desirable; it generally encapsulates a priority for\n// small memory usage over high speed, which is not our priority.  The measured speed difference is not large,\n// about 4% for fairly logical-intensive tests, but the memory penalty seems irrelevant, so why not.  If you\n// feel differently, switching the typedef below should cleanly switch over to bool instead of uint8_t.\ntypedef uint8_t eidos_logical_t;\n//typedef bool eidos_logical_t;\n\n\n// We use Eidos_intrusive_ptr to refer to most EidosValue instances, unless they are used only in one place with\n// a single owner.  For convenience, there is a typedef for Eidos_intrusive_ptr for each EidosValue subclass.\ntypedef Eidos_intrusive_ptr<EidosValue>\t\t\t\t\t\tEidosValue_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_VOID>\t\t\t\tEidosValue_VOID_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_NULL>\t\t\t\tEidosValue_NULL_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_Logical>\t\t\t\tEidosValue_Logical_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_Int>\t\t\t\t\tEidosValue_Int_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_Float>\t\t\t\tEidosValue_Float_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_String>\t\t\t\tEidosValue_String_SP;\ntypedef Eidos_intrusive_ptr<EidosValue_Object>\t\t\t\tEidosValue_Object_SP;\n\n\n// EidosValueType is an enum of the possible types for EidosValue objects.  Note that all of these types are vectors of the stated\n// type; all objects in Eidos are vectors.  The order of these types is in type-promotion order, from lowest to highest, except\n// that NULL never gets promoted to any other type, and nothing ever gets promoted to object type.\nenum class EidosValueType : uint8_t\n{\n\tkValueVOID = 0,\t\t// special void type; this cannot be mixed with other types or promoted to other types, cannot be passed to a function/method, cannot be assigned to a variable\n\tkValueNULL,\t\t\t// special NULL type; this cannot be mixed with other types or promoted to other types\n\t\n\tkValueLogical,\t\t// logicals (eidos_logical_t)\n\tkValueInt,\t\t\t// integers (int64_t)\n\tkValueFloat,\t\t// floats (double)\n\tkValueString,\t\t// strings (std:string)\n\t\n\tkValueObject\t\t// a vector of EidosObject objects: these represent built-in objects with properties and methods\n};\n\nstd::string StringForEidosValueType(const EidosValueType p_type);\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosValueType p_type);\n\n\n// EidosValueMask is a uint32_t used as a bit mask to identify permitted types for EidosValue objects (arguments, returns)\n// Note that these mask values must correspond to the values in EidosValueType directly; (1 << (int)type) == mask must be true.\ntypedef uint32_t EidosValueMask;\n\nconst EidosValueMask kEidosValueMaskNone =\t\t\t0x00000000;\nconst EidosValueMask kEidosValueMaskVOID =\t\t\t0x00000001;\nconst EidosValueMask kEidosValueMaskNULL =\t\t\t0x00000002;\nconst EidosValueMask kEidosValueMaskLogical =\t\t0x00000004;\nconst EidosValueMask kEidosValueMaskInt =\t\t\t0x00000008;\nconst EidosValueMask kEidosValueMaskFloat =\t\t\t0x00000010;\nconst EidosValueMask kEidosValueMaskString =\t\t0x00000020;\nconst EidosValueMask kEidosValueMaskObject =\t\t0x00000040;\n\nconst EidosValueMask kEidosValueMaskOptional =\t\t0x80000000;\nconst EidosValueMask kEidosValueMaskSingleton =\t\t0x40000000;\nconst EidosValueMask kEidosValueMaskFlagStrip =\t\t0x3FFFFFFF;\n\nconst EidosValueMask kEidosValueMaskNumeric =\t\t(kEidosValueMaskInt | kEidosValueMaskFloat);\t\t\t\t\t\t\t\t\t// integer or float\nconst EidosValueMask kEidosValueMaskLogicalEquiv =\t(kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskFloat);\t\t\t// logical, integer, or float\nconst EidosValueMask kEidosValueMaskAnyBase =\t\t(kEidosValueMaskNULL | kEidosValueMaskLogicalEquiv | kEidosValueMaskString);\t// any non-void type except object\nconst EidosValueMask kEidosValueMaskAny =\t\t\t(kEidosValueMaskAnyBase | kEidosValueMaskObject);\t\t\t\t\t\t\t\t// any non-void type including object\n\nstd::string StringForEidosValueMask(const EidosValueMask p_mask, const EidosClass *p_object_class, const std::string &p_name, EidosValue *p_default);\n//std::ostream &operator<<(std::ostream &p_outstream, const EidosValueMask p_mask);\t// can't do this since EidosValueMask is just uint32_t\n\n\n// EidosTypeSpecifier is a struct that provides a full type specifier, including an optional object class, for a value\ntypedef struct {\n\tEidosValueMask type_mask;\t\t\t\t\t// can specify kEidosValueMaskNone for no known type, or any combination of type masks\n\tconst EidosClass *object_class;\t\t// if kEidosValueMaskObject is included in type_mask, this can specify a class (or can be nullptr)\n} EidosTypeSpecifier;\n\n\n\n\n\n#endif /* defined(__Eidos__eidos_globals__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_interpreter.cpp",
    "content": "//\n//  eidos_interpreter.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/4/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_interpreter.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_simd.h\"\n\n#include <sstream>\n#include <stdexcept>\n#include <utility>\n#include <cmath>\n#include <algorithm>\n#include <limits.h>\n\n\n// We have a bunch of behaviors that we want to do only when compiled DEBUG or EIDOS_GUI; #if tests everywhere are very ugly, so we make\n// some #defines here that help structure this.\n\n#if DEBUG || defined(EIDOS_GUI)\n\n#define EIDOS_ENTRY_EXECUTION_LOG(method_name)\t\t\t\t\t\tif (logging_execution_) *execution_log_ << IndentString(execution_log_indent_++) << (method_name) << \" entered\\n\";\n#define EIDOS_EXIT_EXECUTION_LOG(method_name)\t\t\t\t\t\tif (logging_execution_) *execution_log_ << IndentString(--execution_log_indent_) << (method_name) << \" : return == \" << *result_SP << \"\\n\";\n#define EIDOS_BEGIN_EXECUTION_LOG()\t\t\t\t\t\t\t\t\tif (logging_execution_) execution_log_indent_ = 0;\n#define EIDOS_END_EXECUTION_LOG()\t\t\t\t\t\t\t\t\tif (gEidosLogEvaluation) std::cout << ExecutionLog();\n#define EIDOS_ASSERT_CHILD_COUNT(method_name, count)\t\t\t\tif (p_node->children_.size() != (count)) EIDOS_TERMINATION << \"ERROR (\" << (method_name) << \"): (internal error) expected \" << (count) << \" child(ren).\" << EidosTerminate(p_node->token_);\n#define EIDOS_ASSERT_CHILD_COUNT_GTEQ(method_name, min_count)\t\tif (p_node->children_.size() < (min_count)) EIDOS_TERMINATION << \"ERROR (\" << (method_name) << \"): (internal error) expected \" << (min_count) << \"+ child(ren).\" << EidosTerminate(p_node->token_);\n#define EIDOS_ASSERT_CHILD_RANGE(method_name, lower, upper)\t\t\tif ((p_node->children_.size() < (lower)) || (p_node->children_.size() > (upper))) EIDOS_TERMINATION << \"ERROR (\" << (method_name) << \"): (internal error) expected \" << (lower) << \" to \" << (upper) << \" children.\" << EidosTerminate(p_node->token_);\n#define EIDOS_ASSERT_CHILD_COUNT_X(node, node_type, method_name, count, blame_token)\t\tif ((node)->children_.size() != (count)) EIDOS_TERMINATION << \"ERROR (\" << (method_name) << \"): (internal error) expected \" << (count) << \" child(ren) for \" << (node_type) << \" node.\" << EidosTerminate(blame_token);\n#define EIDOS_ASSERT_CHILD_COUNT_GTEQ_X(node, node_type, method_name, min_count, blame_token)\t\tif ((node)->children_.size() < (min_count)) EIDOS_TERMINATION << \"ERROR (\" << (method_name) << \"): (internal error) expected \" << (min_count) << \"+ child(ren) for \" << (node_type) << \" node.\" << EidosTerminate(blame_token);\n\n#else\n\n#define EIDOS_ENTRY_EXECUTION_LOG(method_name)\n#define EIDOS_EXIT_EXECUTION_LOG(method_name)\n#define EIDOS_BEGIN_EXECUTION_LOG()\n#define EIDOS_END_EXECUTION_LOG()\n#define EIDOS_ASSERT_CHILD_COUNT(method_name, count)\n#define EIDOS_ASSERT_CHILD_COUNT_GTEQ(method_name, min_count)\n#define EIDOS_ASSERT_CHILD_RANGE(method_name, lower, upper)\n#define EIDOS_ASSERT_CHILD_COUNT_X(node, node_type, method_name, count, blame_token)\n#define EIDOS_ASSERT_CHILD_COUNT_GTEQ_X(node, node_type, method_name, min_count, blame_token)\n\n#endif\n\n\nbool TypeCheckAssignmentOfEidosValueIntoEidosValue(const EidosValue &p_base_value, const EidosValue &p_dest_value)\n{\n\tEidosValueType base_type = p_base_value.Type();\n\tEidosValueType dest_type = p_dest_value.Type();\n\tbool base_is_object = (base_type == EidosValueType::kValueObject);\n\tbool dest_is_object = (dest_type == EidosValueType::kValueObject);\n\t\n\tif (base_is_object && dest_is_object)\n\t{\n\t\t// objects must match in their element type, or one or both must have no defined element type (due to being empty)\n\t\tconst EidosClass *base_element_class = ((const EidosValue_Object &)p_base_value).Class();\n\t\tconst EidosClass *dest_element_class = ((const EidosValue_Object &)p_dest_value).Class();\n\t\tbool base_is_typeless = (base_element_class == gEidosObject_Class);\n\t\tbool dest_is_typeless = (dest_element_class == gEidosObject_Class);\n\t\t\n\t\tif (base_is_typeless || dest_is_typeless)\n\t\t\treturn true;\n\t\t\n\t\treturn (base_element_class == dest_element_class);\n\t}\n\telse if (base_is_object || dest_is_object)\n\t{\n\t\t// objects cannot be mixed with non-objects\n\t\treturn false;\n\t}\n\t\n\t// identical types are always compatible, apart from object types handled above\n\tif (base_type == dest_type)\n\t\treturn true;\n\t\n\t// NULL cannot be assigned into other things; this is a difference from R, because NULL cannot be represented as a value in other types\n\t// (it is its own type, not a value within types).\n\tif (base_type == EidosValueType::kValueNULL)\n\t\treturn false;\n\t\n\t// otherwise, we follow the promotion order defined in EidosValueType\n\treturn (dest_type > base_type);\n}\n\n\n//\n//\tEidosInterpreter\n//\n#pragma mark -\n#pragma mark EidosInterpreter\n#pragma mark -\n\nEidosInterpreter::EidosInterpreter(const EidosScript &p_script, EidosSymbolTable &p_symbols, EidosFunctionMap &p_functions, EidosContext *p_eidos_context, std::ostream &p_outstream, std::ostream &p_errstream\n#ifdef SLIMGUI\n\t, bool p_check_infinite_loops\n#endif\n)\n\t: eidos_context_(p_eidos_context), root_node_(p_script.AST()), global_symbols_(&p_symbols), function_map_(p_functions), execution_output_(p_outstream), error_output_(p_errstream)\n#ifdef SLIMGUI\n\t\t, check_infinite_loops_(p_check_infinite_loops)\n#endif\n{\n#ifdef SLIMGUI\n\t// Take a pointer to the context's debugging points; we do not copy, so the context can update the debug points underneath us\n\tif (eidos_context_)\n        debug_points_ = eidos_context_->DebugPoints();\n#endif\n}\n\nEidosInterpreter::EidosInterpreter(const EidosASTNode *p_root_node_, EidosSymbolTable &p_symbols, EidosFunctionMap &p_functions, EidosContext *p_eidos_context, std::ostream &p_outstream, std::ostream &p_errstream\n#ifdef SLIMGUI\n\t, bool p_check_infinite_loops\n#endif\n)\n\t: eidos_context_(p_eidos_context), root_node_(p_root_node_), global_symbols_(&p_symbols), function_map_(p_functions), execution_output_(p_outstream), error_output_(p_errstream)\n#ifdef SLIMGUI\n\t\t, check_infinite_loops_(p_check_infinite_loops)\n#endif\n{\n#ifdef SLIMGUI\n\t// Take a pointer to the context's debugging points; we do not copy, so the context can update the debug points underneath us\n\tdebug_points_ = eidos_context_->DebugPoints();\n#endif\n}\n\nvoid EidosInterpreter::SetShouldLogExecution(bool p_log)\n{\n\tlogging_execution_ = p_log;\n\t\n\tif (logging_execution_)\n\t{\n#if DEBUG || defined(EIDOS_GUI)\n\t\t// execution_log_ is allocated when logging execution is turned on; all use of execution_log_\n\t\t// should be inside \"if (logging_execution_)\", so this should suffice.\n\t\tif (!execution_log_)\n\t\t\texecution_log_ = new std::ostringstream();\n#else\n\t\t// Logging execution is disabled until we are either in a DEBUG build or a GUI (EIDOS_GUI)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::SetShouldLogExecution): execution logging is disabled in this build configuration of Eidos.\" << EidosTerminate(nullptr);\n#endif\n\t}\n}\n\nbool EidosInterpreter::ShouldLogExecution(void)\n{\n\treturn logging_execution_;\n}\n\nstd::string EidosInterpreter::ExecutionLog(void)\n{\n\treturn (execution_log_ ? execution_log_->str() : gEidosStr_empty_string);\n}\n\n// the starting point for internally executed blocks, which require braces and suppress output\nEidosValue_SP EidosInterpreter::EvaluateInternalBlock(EidosScript *p_script_for_block)\n{\n\t// EvaluateInternalBlock() does not log execution, since it is not user-initiated\n\t\n\t// Internal blocks may be associated with their own script object; if so, the error tracking code needs to track that\n\t// Note that if there is not a separate script block, then we do NOT set up an error context here; we assume that\n\t// that has been done externally, just like EvaluateInterpreterBlock().\n\tEidosValue_SP result_SP;\n\t\n\tif ((p_script_for_block != nullptr) && (p_script_for_block != gEidosErrorContext.currentScript))\n\t{\n\t\t// This script block is constructed at runtime and has its own script, so we need to redirect error tracking\n\t\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, p_script_for_block};\n\t\t\n\t\t// Same code as below, just bracketed by the error context save/restore\n\t\tresult_SP = FastEvaluateNode(root_node_);\n\t\t\n\t\t// if a next or break statement was hit and was not handled by a loop, throw an error\n\t\tif (next_statement_hit_ || break_statement_hit_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::EvaluateInternalBlock): statement '\" << (next_statement_hit_ ? gEidosStr_next : gEidosStr_break) << \"' encountered with no enclosing loop.\" << EidosTerminate(nullptr);\t\t// nullptr used to allow the token set by the next/break to be used\n\t\t\n\t\t// Restore the normal error context; note that a raise blows through this, of course, since we want the raise-catch\n\t\t// machinery to report the error using the error information set up by the raise.\n\t\tgEidosErrorContext = error_context_save;\n\t}\n\telse\n\t{\n\t\tresult_SP = FastEvaluateNode(root_node_);\n\t\t\n\t\t// if a next or break statement was hit and was not handled by a loop, throw an error\n\t\tif (next_statement_hit_ || break_statement_hit_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::EvaluateInternalBlock): statement '\" << (next_statement_hit_ ? gEidosStr_next : gEidosStr_break) << \"' encountered with no enclosing loop.\" << EidosTerminate(nullptr);\t\t// nullptr used to allow the token set by the next/break to be used\n\t}\n\t\n\t// handle a return statement; we're at the top level, so there's not much to do\n\tif (return_statement_hit_)\n\t\treturn_statement_hit_ = false;\n\t\n\t// EvaluateInternalBlock() does not send the result of execution to the output stream; EvaluateInterpreterBlock() does,\n\t// because it is for interactive use, but EvaluateInternalBlock() is for internal use, and so interactive output\n\t// is undesirable.  Eidos code that wants to generate output can always use print(), cat(), etc.\n\t\n\t// EvaluateInternalBlock() does not log execution, since it is not user-initiated\n\t\n\treturn result_SP;\n}\n\n// the starting point for script blocks in Eidos, which do not require braces; this is not really a \"block\" but a series of\n// independent statements grouped only by virtue of having been executed together as a unit in the interpreter\nEidosValue_SP EidosInterpreter::EvaluateInterpreterBlock(bool p_print_output, bool p_return_last_value)\n{\n\tEIDOS_BEGIN_EXECUTION_LOG();\n\tEIDOS_ENTRY_EXECUTION_LOG(\"EvaluateInterpreterBlock()\");\n\t\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tfor (EidosASTNode *child_node : root_node_->children_)\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tEidosValue_SP statement_result_SP = FastEvaluateNode(child_node);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(child_node->profile_total_);\n#endif\n\t\t\n\t\t// if a next or break statement was hit and was not handled by a loop, throw an error\n\t\tif (next_statement_hit_ || break_statement_hit_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::EvaluateInterpreterBlock): statement '\" << (next_statement_hit_ ? gEidosStr_next : gEidosStr_break) << \"' encountered with no enclosing loop.\" << EidosTerminate(nullptr);\t\t// nullptr used to allow the token set by the next/break to be used\n\t\t\n\t\t// send the result of each statement to our output stream; result==nullptr indicates invisible NULL, so we don't print\n\t\tEidosValue *statement_result = statement_result_SP.get();\n\t\t\n\t\tif (p_print_output && statement_result && !statement_result->Invisible())\n\t\t{\n\t\t\tstd::ostream &execution_output = ExecutionOutputStream();\n\t\t\t\n\t\t\tauto position = execution_output.tellp();\n\t\t\texecution_output << *statement_result;\n\t\t\t\n\t\t\t// EidosValue does not put an endl on the stream, so if it emitted any output, add an endl\n\t\t\tif (position != execution_output.tellp())\n\t\t\t\texecution_output << std::endl;\n\t\t}\n\t\t\n\t\t// handle a return statement; we're at the top level, so there's not much to do except stop execution\n\t\tif (return_statement_hit_)\n\t\t{\n\t\t\treturn_statement_hit_ = false;\n\t\t\tresult_SP = std::move(statement_result_SP);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// If we're returning the last value seen, keep track of it.  The policy now (starting in SLiM 3) is that lambdas – blocks\n\t\t// of code without braces, such as supplied to apply(), sapply(), executeLambda(), as command-line defines in SLiM, etc. –\n\t\t// implicitly evaluate to the value of the last statement they execute, and a return is not needed.  Functions – blocks\n\t\t// of code with braces, such as user-defined functions, events and callbacks in SLiM, etc. – do not make any implicit return,\n\t\t// and evaluate to VOID unless a return statement is explicitly executed.  Functions that are required to return a value\n\t\t// must therefore do so explicitly with a return; and functions that are declared as returning void must never return a value.\n\t\tif (p_return_last_value)\n\t\t\tresult_SP = std::move(statement_result_SP);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"EvaluateInterpreterBlock()\");\n\tEIDOS_END_EXECUTION_LOG();\n\treturn result_SP;\n}\n\n// A subscript has been encountered as the top-level operation on the left-hand side of an assignment – x[5] = y, x.foo[5] = y, or more\n// complex cases like x[3:10].foo[2:5][1:2] = y.  The job of this function is to determine the identity of the symbol host (x, x, and\n// x[3:10], respectively), the name of the property within the symbol host (none, foo, and foo, respectively), and the indices of the final\n// subscript operation (5, 5, and {3,4}, respectively), and return them to the caller, who will assign into those subscripts.\nvoid EidosInterpreter::_ProcessSubsetAssignment(EidosValue_SP *p_base_value_ptr, EidosGlobalStringID *p_property_string_id_ptr, std::vector<int> *p_indices_ptr, const EidosASTNode *p_parent_node)\n{\n\t// The left operand is the thing we're subscripting.  If it is an identifier or a dot operator, then we are the deepest (i.e. first)\n\t// subscript operation, and we can resolve the symbol host, set up a vector of indices, and return.  If it is a subscript, we recurse.\n\tEidosToken *parent_token = p_parent_node->token_;\n\tEidosTokenType token_type = parent_token->token_type_;\n\t\n\tswitch (token_type)\n\t{\n\t\tcase EidosTokenType::kTokenLBracket:\n\t\t{\n\t\t\t// Note that the logic here is very parallel to that of EidosInterpreter::Evaluate_Subset()\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_GTEQ_X(p_parent_node, \"'['\", \"EidosInterpreter::_ProcessSubsetAssignment\", 2, parent_token);\n\t\t\t\n\t\t\tEidosASTNode *left_operand = p_parent_node->children_[0];\n\t\t\t\n\t\t\tstd::vector<int> base_indices;\n\t\t\t\n\t\t\t// Recurse to find the symbol host and property name that we are ultimately subscripting off of\n\t\t\t_ProcessSubsetAssignment(p_base_value_ptr, p_property_string_id_ptr, &base_indices, left_operand);\n\t\t\t\n\t\t\tint base_indices_count = (int)base_indices.size();\n\t\t\tEidosValue_SP first_child_value = *p_base_value_ptr;\n\t\t\tint first_child_dim_count = first_child_value->DimensionCount();\n\t\t\t\n\t\t\t// organize our subset arguments\n\t\t\tint child_count = (int)p_parent_node->children_.size();\n\t\t\tstd::vector <EidosValue_SP> subset_indices;\n\t\t\t\n\t\t\tfor (int child_index = 1; child_index < child_count; ++child_index)\n\t\t\t{\n\t\t\t\tconst EidosASTNode *subset_index_node = p_parent_node->children_[child_index];\n\t\t\t\tEidosTokenType subset_index_token_type = subset_index_node->token_->token_type_;\n\t\t\t\t\n\t\t\t\tif ((subset_index_token_type == EidosTokenType::kTokenComma) || (subset_index_token_type == EidosTokenType::kTokenRBracket))\n\t\t\t\t{\n\t\t\t\t\t// We have a placeholder node indicating a skipped expression, so we save NULL as the value\n\t\t\t\t\tsubset_indices.emplace_back(gStaticEidosValueNULL);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We have an expression node, so we evaluate it, check the value, and save it\n\t\t\t\t\tEidosValue_SP child_value = FastEvaluateNode(subset_index_node);\n\t\t\t\t\tEidosValueType child_type = child_value->Type();\n\t\t\t\t\t\n\t\t\t\t\tif (child_type == EidosValueType::kValueFloat)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): it is no longer legal to subset with float indices; use asInteger() to cast the indices to integer.\" << EidosTerminate(parent_token);\n\t\t\t\t\tif ((child_type != EidosValueType::kValueInt) && (child_type != EidosValueType::kValueLogical) && (child_type != EidosValueType::kValueNULL))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): index operand type \" << child_type << \" is not supported by the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\n\t\t\t\t\t// BCH 9/10/2025: we now want to support subsetting of a matrix by a matrix, in two specific cases; other cases continue to be an error\n\t\t\t\t\tif (child_value->DimensionCount() != 1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// if we're subsetting with a matrix or array, the target of the subset must be a matrix or array\n\t\t\t\t\t\tif (first_child_dim_count == 1)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): subsetting of a vector with a matrix or array index operand is not supported by the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we're subsetting with a matrix or array, that must be the only subset argument\n\t\t\t\t\t\tif (child_count != 2)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): this type of subsetting of a matrix or array index operand is not supported by the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// as below also, we do not allow this style of subsetting off of a previous subset or\n\t\t\t\t\t\t// property access; we only know the dimensions of the base value, not of previous\n\t\t\t\t\t\t// results from processing of that base value, so we don't have the info we need\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEidosToken *left_token = left_operand->token_;\n\t\t\t\t\t\t\tEidosTokenType left_token_type = left_token->token_type_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (left_token_type == EidosTokenType::kTokenLBracket)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): chaining of matrix/array-style subsets in assignments is not supported.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\tif (left_token_type == EidosTokenType::kTokenDot)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): cannot assign into a subset of a property; not an lvalue.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// and as below, Evaluate_Subset() returns a vector from this section of the code, changing the dimensionality\n\t\t\t\t\t\t// of the target value from a matrix/array to a vector; we are just returning a set of indices, so we don't do\n\t\t\t\t\t\t// that, but the check above should prevent that from being a problem since the user can't chain off of our\n\t\t\t\t\t\t// result here in a way that uses the matrix/array dimensionality, I think...\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if the subset argument is of type logical, its dimensions must exactly match the target\n\t\t\t\t\t\t// this produces a result vector containing the target elements selected by true elements\n\t\t\t\t\t\tif (child_type == EidosValueType::kValueLogical)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!EidosValue::MatchingDimensions(first_child_value.get(), child_value.get()))\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): non-conformable logical matrix or array operand for the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tconst eidos_logical_t *operand_data = child_value->LogicalData();\n\t\t\t\t\t\t\tint operand_count = child_value->Count();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int operand_index = 0; operand_index < operand_count; ++operand_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\teidos_logical_t logical_value = operand_data[operand_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (logical_value)\n\t\t\t\t\t\t\t\t\tp_indices_ptr->emplace_back(base_indices[operand_index]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if the subset argument is integer, it must have a column count that matches the target's\n\t\t\t\t\t\t// dimensionality -- e.g., two columns (row,col) for a matrix target -- and any number of rows\n\t\t\t\t\t\t// this produces a result vector containing the target elements selected by the operand rows\n\t\t\t\t\t\tif (child_type == EidosValueType::kValueInt)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (child_value->DimensionCount() != 2)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): subsetting a matrix or array with an integer array is not supported by the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\tif (child_value->Dimensions()[1] != first_child_value->DimensionCount())\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): subsetting a matrix or array with an integer matrix requires that the integer matrix have a column count equal to the number of dimensions of the target matrix or array (e.g., two columns if the target is a matrix).\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tconst int64_t *operand_data = child_value->IntData();\n\t\t\t\t\t\t\tint64_t operand_nrow = child_value->Dimensions()[0];\n\t\t\t\t\t\t\tint64_t operand_ncol = child_value->Dimensions()[1];\n\t\t\t\t\t\t\tconst int64_t *target_dimensions = first_child_value->Dimensions();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int64_t operand_row = 0; operand_row < operand_nrow; ++operand_row)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint target_index = 0;\n\t\t\t\t\t\t\t\tint stride = 1;\n\t\t\t\t\t\t\t\tconst int64_t *operand_row_ptr = operand_data + operand_row;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int64_t operand_col = 0; operand_col < operand_ncol; ++operand_col)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tint64_t coordinate = *operand_row_ptr;\n\t\t\t\t\t\t\t\t\toperand_row_ptr += operand_nrow;\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\ttarget_index += (coordinate * stride);\n\t\t\t\t\t\t\t\t\tstride *= target_dimensions[operand_col];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((target_index < 0) || (target_index >= base_indices_count))\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): out-of-range index \" << target_index << \" used with the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tp_indices_ptr->emplace_back(base_indices[target_index]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tsubset_indices.emplace_back(child_value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tint subset_index_count = (int)subset_indices.size();\n\t\t\t\n\t\t\tif ((subset_index_count != first_child_dim_count) && (subset_index_count != 1))\n\t\t\t{\n\t\t\t\t// We have the wrong number of subset arguments for our dimensionality, so this is an error\n\t\t\t\tif (subset_index_count > first_child_dim_count)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): too many subset arguments for the indexed operand's dimensionality.\" << EidosTerminate(parent_token);\n\t\t\t\telse // (subset_index_count < first_child_dim_count)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): too few subset arguments for the indexed operand's dimensionality.\" << EidosTerminate(parent_token);\n\t\t\t}\n\t\t\t// \telse if (first_child_type == EidosValueType::kValueNULL)\t: Evaluate_Subset() returns NULL for subsets of NULL, we let them fall through; assigning into an empty subset of NULL is legal\n\t\t\telse if ((subset_index_count == 1) && (subset_indices[0] == gStaticEidosValueNULL))\n\t\t\t{\n\t\t\t\t// We have a single subset argument of NULL, so we have x[] or x[NULL]; just return all legal indices\n\t\t\t\tfor (int value_idx = 0; value_idx < base_indices_count; value_idx++)\n\t\t\t\t\tp_indices_ptr->emplace_back(base_indices[value_idx]);\n\t\t\t}\n\t\t\telse if (subset_index_count == 1)\n\t\t\t{\n\t\t\t\t// OK, we have a simple vector-style subset that is not NULL; handle it as we did in Eidos 1.5 and earlier\n\t\t\t\tEidosValue_SP second_child_value = subset_indices[0];\n\t\t\t\tEidosValueType second_child_type = second_child_value->Type();\n\t\t\t\t\n\t\t\t\tif (second_child_value->DimensionCount() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): a matrix or array index operand is not supported by the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\n\t\t\t\tint second_child_count = second_child_value->Count();\n\t\t\t\t\n\t\t\t\tif (second_child_type == EidosValueType::kValueLogical)\n\t\t\t\t{\n\t\t\t\t\t// A logical vector must exactly match in length; if it does, it selects corresponding indices from base_indices\n\t\t\t\t\tif (second_child_count != base_indices_count)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): the '[]' operator requires that the size() of a logical index operand must match the size() of the indexed operand.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_idx = 0; value_idx < second_child_count; value_idx++)\n\t\t\t\t\t{\n\t\t\t\t\t\teidos_logical_t logical_value = second_child_value->LogicalAtIndex_NOCAST(value_idx, parent_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (logical_value)\n\t\t\t\t\t\t\tp_indices_ptr->emplace_back(base_indices[value_idx]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\t// (second_child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\t// An integer vector can be of any length; each number selects the index at that index in base_indices\n\t\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_idx = 0; value_idx < second_child_count; value_idx++)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t index_value = second_child_data[value_idx];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((index_value < 0) || (index_value >= base_indices_count))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tp_indices_ptr->emplace_back(base_indices[index_value]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We have a new matrix/array-style subset, like x[1,], x[,1], x[,], etc.; this is Eidos 1.6 and later\n\t\t\t\t// Handle each subset value in turn, determining which subset of each dimension will be carried forward\n\t\t\t\t// We tabulate the status of each dimension, and then put it all together at the end as a result value\n\t\t\t\t\n\t\t\t\t// First, however, we have to check that the user is not attempting something like x[1,][,3] = rvalue.\n\t\t\t\t// That is not allowed at present, because the [1,] changes the dimensions of the value, and we have\n\t\t\t\t// no obvious way of tracking that.  It would be nice if it worked, since it makes sense in principle,\n\t\t\t\t// but it isn't worth building a whole complex code architecture around.  So here we check the left-hand\n\t\t\t\t// side that provided us with the host that we're subsetting, and if it is itself a subset operation\n\t\t\t\t// then it's an error.  A similar problem exists for property access, like x.foo[1,] = rvalue, because\n\t\t\t\t// the property access erases the dimensions of x, and so a matrix/array-style subscript makes no sense;\n\t\t\t\t// that might get caught somewhere else, but to make sure we're not heading into a situation that will\n\t\t\t\t// cause us to produce incorrect output, we check for it here as well.\n\t\t\t\t{\n\t\t\t\t\tEidosToken *left_token = left_operand->token_;\n\t\t\t\t\tEidosTokenType left_token_type = left_token->token_type_;\n\t\t\t\t\t\n\t\t\t\t\tif (left_token_type == EidosTokenType::kTokenLBracket)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): chaining of matrix/array-style subsets in assignments is not supported.\" << EidosTerminate(parent_token);\n\t\t\t\t\tif (left_token_type == EidosTokenType::kTokenDot)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): cannot assign into a subset of a property; not an lvalue.\" << EidosTerminate(parent_token);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// OK, we are subsetting directly off of an identifier, given the check above.  This means we can ignore\n\t\t\t\t// base_indices and p_property_string_id_ptr, and just work directly with first_child_value; it is what\n\t\t\t\t// we are subsetting off of.\n\t\t\t\t\n\t\t\t\tconst int64_t *first_child_dim = first_child_value->Dimensions();\n\t\t\t\tstd::vector<std::vector<int64_t>> inclusion_indices;\t// the chosen indices for each dimension\n\t\t\t\tstd::vector<int> inclusion_counts;\t\t\t\t\t\t// the number of chosen indices for each dimension\n\t\t\t\tbool empty_dimension = false;\n\t\t\t\t\n\t\t\t\tfor (int subset_index = 0; subset_index < subset_index_count; ++subset_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP subset_value = subset_indices[subset_index];\n\t\t\t\t\tEidosValueType subset_type = subset_value->Type();\n\t\t\t\t\tint subset_count = subset_value->Count();\n\t\t\t\t\tint dim_size = (int)first_child_dim[subset_index];\n\t\t\t\t\tstd::vector<int64_t> indices;\n\t\t\t\t\t\n\t\t\t\t\tif (subset_type == EidosValueType::kValueNULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We skipped over this dimension or had NULL, so every valid index in the dimension is included\n\t\t\t\t\t\tfor (int dim_index = 0; dim_index < dim_size; ++dim_index)\n\t\t\t\t\t\t\tindices.emplace_back(dim_index);\n\t\t\t\t\t}\n\t\t\t\t\telse if (subset_type == EidosValueType::kValueLogical)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We have a logical subset, which must equal the dimension size and gets translated directly into inclusion_indices\n\t\t\t\t\t\tif (subset_count != dim_size)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): the '[]' operator requires that the size() of a logical index operand must match the corresponding dimension of the indexed operand.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst eidos_logical_t *logical_index_data = subset_value->LogicalData();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int dim_index = 0; dim_index < dim_size; dim_index++)\n\t\t\t\t\t\t\tif (logical_index_data[dim_index])\n\t\t\t\t\t\t\t\tindices.emplace_back(dim_index);\n\t\t\t\t\t}\n\t\t\t\t\telse\t// (subset_type == EidosValueType::kValueInt)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We have an integer subset, which selects indices within inclusion_indices\n\t\t\t\t\t\tfor (int index_index = 0; index_index < subset_count; index_index++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint64_t index_value = subset_value->IntAtIndex_NOCAST(index_index, parent_token);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((index_value < 0) || (index_value >= dim_size))\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(parent_token);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tindices.emplace_back(index_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (indices.size() == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tempty_dimension = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tinclusion_counts.emplace_back((int)indices.size());\n\t\t\t\t\tinclusion_indices.emplace_back(indices);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (empty_dimension)\n\t\t\t\t{\n\t\t\t\t\t// If there was a dimension where no index was included, no indices are included, so we do nothing\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We have tabulated the subsets; now tabulate the included values into p_indices_ptr.  To do this, we count up\n\t\t\t\t\t// in the base system established by inclusion_counts, and add the referenced index at each step along the way.\n\t\t\t\t\tstd::vector<int> generating_counter(subset_index_count, 0);\n\t\t\t\t\t\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// add the value referenced by generating_counter in inclusion_indices\n\t\t\t\t\t\tint64_t referenced_index = 0;\n\t\t\t\t\t\tint64_t dim_skip = 1;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int counter_index = 0; counter_index < subset_index_count; ++counter_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint counter_value = generating_counter[counter_index];\n\t\t\t\t\t\t\tint64_t inclusion_index_value = inclusion_indices[counter_index][counter_value];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\treferenced_index += inclusion_index_value * dim_skip;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tdim_skip *= first_child_dim[counter_index];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tp_indices_ptr->emplace_back(referenced_index);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// increment generating_counter in the base system of inclusion_counts\n\t\t\t\t\t\tint generating_counter_index = 0;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (++generating_counter[generating_counter_index] == inclusion_counts[generating_counter_index])\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tgenerating_counter[generating_counter_index] = 0;\n\t\t\t\t\t\t\t\tgenerating_counter_index++;\t\t// carry\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile (generating_counter_index < subset_index_count);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if we carried out off the top, we are done adding included values\n\t\t\t\t\t\tif (generating_counter_index == subset_index_count)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\twhile (true);\n\t\t\t\t\t\n\t\t\t\t\t// At this point, Evaluate_Subset() sets the dimensionality of the result.  We are just returning a set of indices,\n\t\t\t\t\t// so we don't do that.  If we ever wanted to actually get into allowing x[1,][,3] = rvalue; and such things, at\n\t\t\t\t\t// this point we would compute the dimensionality of the result and pass it upward to the caller through another\n\t\t\t\t\t// modifiable parameter, I suppose, so that the caller would know what sort of thing they were chaining off of.\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosTokenType::kTokenDot:\n\t\t{\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_X(p_parent_node, \"'.'\", \"EidosInterpreter::_ProcessSubsetAssignment\", 2, parent_token);\n\t\t\t\n\t\t\tEidosASTNode *left_operand = p_parent_node->children_[0];\n\t\t\tEidosASTNode *right_operand = p_parent_node->children_[1];\n\t\t\t\n\t\t\tEidosValue_SP first_child_value = FastEvaluateNode(left_operand);\n\t\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\t\n\t\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): operand type \" << first_child_type << \" is not supported by the '.' operator (not an object).\" << EidosTerminate(parent_token);\n\t\t\t\n\t\t\tif (right_operand->token_->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(parent_token);\n\t\t\t\n\t\t\t*p_base_value_ptr = first_child_value;\n\t\t\t*p_property_string_id_ptr = EidosStringRegistry::GlobalStringIDForString(right_operand->token_->token_string_);\n\t\t\t\n\t\t\tint number_of_elements = first_child_value->Count();\t// property operations are guaranteed to produce one value per element\n\t\t\t\n\t\t\tfor (int element_idx = 0; element_idx < number_of_elements; element_idx++)\n\t\t\t\tp_indices_ptr->emplace_back(element_idx);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosTokenType::kTokenIdentifier:\n\t\t{\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_X(p_parent_node, \"identifier\", \"EidosInterpreter::_ProcessSubsetAssignment\", 0, parent_token);\n\t\t\t\n\t\t\tbool identifier_is_const = false;\n\t\t\tbool identifier_is_local = false;\t\t// not used, just needed by the API\n\t\t\tEidosValue_SP identifier_value_SP = global_symbols_->GetValueOrRaiseForASTNode_IsConstIsLocal(p_parent_node, &identifier_is_const, &identifier_is_local);\n\t\t\tEidosValue *identifier_value = identifier_value_SP.get();\n\t\t\t\n\t\t\t// Check for a constant symbol table.  Note that _AssignRValueToLValue() will check for a constant EidosValue.\n\t\t\t// The work of checking constness is divided between these methods for historical reasons.\n\t\t\tif (identifier_is_const || identifier_value->IsIteratorVariable())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_parent_node->cached_stringID_) << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// BCH 12/21/2023: We used to munge singletons into vectors here, because we didn't have the tools to modify the\n\t\t\t// element in a singleton value.  That limitation has now been fixed, so this munging is no longer necessary.\n\t\t\t/*if (identifier_value->IsSingleton())\n\t\t\t{\n\t\t\t\tidentifier_value_SP = identifier_value->VectorBasedCopy();\n\t\t\t\tidentifier_value = identifier_value_SP.get();\n\t\t\t\t\n\t\t\t\tglobal_symbols_->SetValueForSymbolNoCopy(p_parent_node->cached_stringID_, identifier_value_SP);\n\t\t\t}*/\n\t\t\t\n\t\t\t*p_base_value_ptr = std::move(identifier_value_SP);\n\t\t\t\n\t\t\tint number_of_elements = identifier_value->Count();\t// this value is already defined, so this is fast\n\t\t\t\n\t\t\tfor (int element_idx = 0; element_idx < number_of_elements; element_idx++)\n\t\t\t\tp_indices_ptr->emplace_back(element_idx);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessSubsetAssignment): (internal error) unexpected node token type \" << token_type << \"; lvalue required.\" << EidosTerminate(parent_token);\n\t\t\tbreak;\n\t}\n}\n\nvoid EidosInterpreter::_AssignRValueToLValue(EidosValue_SP p_rvalue, const EidosASTNode *p_lvalue_node)\n{\n\t// This function expects an error range to be set bracketing it externally,\n\t// so no blame token is needed here.\n\t\n\tEidosTokenType token_type = p_lvalue_node->token_->token_type_;\n\t\n#if DEBUG || defined(EIDOS_GUI)\n\tif (logging_execution_)\n\t{\n\t\t*execution_log_ << IndentString(execution_log_indent_) << \"_AssignRValueToLValue() : lvalue token \";\n\t\tp_lvalue_node->PrintToken(*execution_log_);\n\t\t*execution_log_ << \"\\n\";\n\t}\n#endif\n\t\n\t// any assignment involving a void rvalue is illegal; check for that up front\n\tif (p_rvalue->Type() == EidosValueType::kValueVOID)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): void may never be assigned.\" << EidosTerminate(nullptr);\n\t\n\tswitch (token_type)\n\t{\n\t\tcase EidosTokenType::kTokenLBracket:\n\t\t{\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_GTEQ_X(p_lvalue_node, \"'['\", \"EidosInterpreter::_AssignRValueToLValue\", 2, nullptr);\n\t\t\t\n\t\t\tEidosValue_SP base_value;\n\t\t\tEidosGlobalStringID property_string_id = gEidosID_none;\n\t\t\tstd::vector<int> indices;\n\t\t\t\n\t\t\t_ProcessSubsetAssignment(&base_value, &property_string_id, &indices, p_lvalue_node);\n\t\t\t\n\t\t\tint index_count = (int)indices.size();\n\t\t\tint rvalue_count = p_rvalue->Count();\n\t\t\t\n\t\t\tif ((rvalue_count != 1) && (rvalue_count != index_count))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): assignment to a subscript requires an rvalue that is a singleton (multiplex assignment) or that has a .size() matching the .size of the lvalue.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tif (property_string_id != gEidosID_none)\n\t\t\t{\n\t\t\t\t// This would be a multiplex assignment of one value to (maybe) more than one index in a property of a symbol host: x.foo[5:10] = 10,\n\t\t\t\t// or a one-to-one assignment of values to indices in a property of a symbol host: x.foo[5:10] = 5:10\n\t\t\t\t\n\t\t\t\t// BCH 12/8/2017: We used to allow assignments of the form host.property[indices] = rvalue.  I have decided to change Eidos policy\n\t\t\t\t// to disallow that form of assignment.  Conceptually, it sort of doesn't make sense, because it implies fetching the property\n\t\t\t\t// values and assigning into a subset of those fetched values; but the fetched values are not an lvalue at that point.  We did it\n\t\t\t\t// anyway through a semantic rearrangement, but I now think that was a bad idea.  The conceptual problem became more stark with the\n\t\t\t\t// addition of matrices and arrays; if host is a matrix/array, host[i,j,...] is too, and so assigning into a host with that form of\n\t\t\t\t// subset makes conceptual sense, and host[i,j,...].property = rvalue makes sense as well – fetch the indexed values and assign\n\t\t\t\t// into their property.  But host.property[i,j,...] = rvalue does not make sense, because host.property is always a vector, and\n\t\t\t\t// cannot be subset in that way!  So the underlying contradiction in the old policy is exposed.  Time for it to change.\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): cannot assign into a subset of a property; not an lvalue.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tif (!TypeCheckAssignmentOfEidosValueIntoEidosValue(*p_rvalue, *base_value))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): type mismatch in assignment (\" << p_rvalue->Type() << \" versus \" << base_value->Type() << \").\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// Assignments like x[logical(0)] = y, where y is zero-length, are no-ops as long as they're not errors\n\t\t\tif (index_count == 0)\n\t\t\t\treturn;\n\t\t\t\n\t\t\t// Check for a constant value.  Note that ProcessSubsetAssignment() already checked for a constant symbol table.\n\t\t\t// The work of checking constness is divided between these methods for historical reasons.\n\t\t\tif (base_value->IsConstant())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): value cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// At this point, we have either a multiplex assignment of one value to (maybe) more than one index in a symbol host: x[5:10] = 10, when\n\t\t\t// (rvalue_count == 1), or a one-to-one assignment of values to indices in a symbol host: x[5:10] = 5:10, when (rvalue_count == index_count)\n\t\t\t// We handle them both together, as far as we can.  BCH 12/21/2023: This used to be done with SetValueAtIndex(); that method has been removed.\n\t\t\tswitch (base_value->Type())\n\t\t\t{\n\t\t\t\tcase EidosValueType::kValueLogical:\n\t\t\t\t{\n\t\t\t\t\teidos_logical_t *base_value_data = base_value->LogicalData_Mutable();\n\t\t\t\t\t\n\t\t\t\t\tif (rvalue_count == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\teidos_logical_t rvalue = p_rvalue->LogicalAtIndex_CAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = rvalue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = p_rvalue->LogicalAtIndex_CAST(value_idx, nullptr);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase EidosValueType::kValueInt:\n\t\t\t\t{\n\t\t\t\t\tint64_t *base_value_data = base_value->IntData_Mutable();\n\t\t\t\t\t\n\t\t\t\t\tif (rvalue_count == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t rvalue = p_rvalue->IntAtIndex_CAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = rvalue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = p_rvalue->IntAtIndex_CAST(value_idx, nullptr);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase EidosValueType::kValueFloat:\n\t\t\t\t{\n\t\t\t\t\tdouble *base_value_data = base_value->FloatData_Mutable();\n\t\t\t\t\t\n\t\t\t\t\tif (rvalue_count == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble rvalue = p_rvalue->FloatAtIndex_CAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = rvalue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = p_rvalue->FloatAtIndex_CAST(value_idx, nullptr);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase EidosValueType::kValueString:\n\t\t\t\t{\n\t\t\t\t\tstd::string *base_value_data = base_value->StringData_Mutable();\n\t\t\t\t\t\n\t\t\t\t\tif (rvalue_count == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::string rvalue = p_rvalue->StringAtIndex_CAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = rvalue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_value_data[indices[value_idx]] = p_rvalue->StringAtIndex_CAST(value_idx, nullptr);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase EidosValueType::kValueObject:\n\t\t\t\t{\n\t\t\t\t\tEidosValue_Object *base_object_vector = (EidosValue_Object *)base_value.get();\n\t\t\t\t\t\n\t\t\t\t\tif (rvalue_count == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosObject *rvalue = p_rvalue->ObjectElementAtIndex_CAST(0, nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_object_vector->set_object_element_no_check_CRR(rvalue, indices[value_idx]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (int value_idx = 0; value_idx < index_count; value_idx++)\n\t\t\t\t\t\t\tbase_object_vector->set_object_element_no_check_CRR(p_rvalue->ObjectElementAtIndex_CAST(value_idx, nullptr), indices[value_idx]);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): cannot do subset assignment into type \" << base_value->Type() << \").\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosTokenType::kTokenDot:\n\t\t{\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_X(p_lvalue_node, \"'.'\", \"EidosInterpreter::_AssignRValueToLValue\", 2, nullptr);\n\t\t\t\n\t\t\tEidosValue_SP first_child_value = FastEvaluateNode(p_lvalue_node->children_[0]);\n\t\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\t\n\t\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): operand type \" << first_child_type << \" is not supported by the '.' operator.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tEidosASTNode *second_child_node = p_lvalue_node->children_[1];\n\t\t\t\n\t\t\tif (second_child_node->token_->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): (internal error) the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\t// OK, we have <object type>.<identifier>; we can work with that\n\t\t\tstatic_cast<EidosValue_Object *>(first_child_value.get())->SetPropertyOfElements(second_child_node->cached_stringID_, *p_rvalue, second_child_node->token_);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase EidosTokenType::kTokenIdentifier:\n\t\t{\n\t\t\tEIDOS_ASSERT_CHILD_COUNT_X(p_lvalue_node, \"identifier\", \"EidosInterpreter::_AssignRValueToLValue\", 0, nullptr);\n\t\t\t\n\t\t\t// Check for an lvalue that is a loop iterator, which cannot be changed\n\t\t\tif (global_symbols_->ContainsSymbol(p_lvalue_node->cached_stringID_))\n\t\t\t{\n\t\t\t\tEidosValue *existing_value = global_symbols_->GetValueRawOrRaiseForSymbol(p_lvalue_node->cached_stringID_);\n\t\t\t\t\n\t\t\t\tif (existing_value->IsIteratorVariable())\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): identifier '\" << p_lvalue_node->token_->token_string_ << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\t// Simple identifier; the symbol host is the global symbol table, at least for now\n\t\t\tglobal_symbols_->SetValueForSymbol(p_lvalue_node->cached_stringID_, std::move(p_rvalue));\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_AssignRValueToLValue): unexpected node token type \" << token_type << \"; lvalue required.\" << EidosTerminate(nullptr);\n\t\t\tbreak;\n\t}\n}\n\nEidosValue_SP EidosInterpreter::EvaluateNode(const EidosASTNode *p_node)\n{\n\t// The structure here avoids doing a break in the non-error case; a bit faster.\n\tswitch (p_node->token_->token_type_)\n\t{\n\t\tcase EidosTokenType::kTokenSemicolon:\treturn Evaluate_NullStatement(p_node);\n\t\tcase EidosTokenType::kTokenColon:\t\treturn Evaluate_RangeExpr(p_node);\n\t\tcase EidosTokenType::kTokenLBrace:\t\treturn Evaluate_CompoundStatement(p_node);\n\t\tcase EidosTokenType::kTokenLParen:\t\treturn Evaluate_Call(p_node);\n\t\tcase EidosTokenType::kTokenLBracket:\treturn Evaluate_Subset(p_node);\n\t\tcase EidosTokenType::kTokenDot:\t\t\treturn Evaluate_MemberRef(p_node);\n\t\tcase EidosTokenType::kTokenPlus:\t\treturn Evaluate_Plus(p_node);\n\t\tcase EidosTokenType::kTokenMinus:\t\treturn Evaluate_Minus(p_node);\n\t\tcase EidosTokenType::kTokenMod:\t\t\treturn Evaluate_Mod(p_node);\n\t\tcase EidosTokenType::kTokenMult:\t\treturn Evaluate_Mult(p_node);\n\t\tcase EidosTokenType::kTokenExp:\t\t\treturn Evaluate_Exp(p_node);\n\t\tcase EidosTokenType::kTokenAnd:\t\t\treturn Evaluate_And(p_node);\n\t\tcase EidosTokenType::kTokenOr:\t\t\treturn Evaluate_Or(p_node);\n\t\tcase EidosTokenType::kTokenDiv:\t\t\treturn Evaluate_Div(p_node);\n\t\tcase EidosTokenType::kTokenConditional:\treturn Evaluate_Conditional(p_node);\n\t\tcase EidosTokenType::kTokenAssign:\t\treturn Evaluate_Assign(p_node);\n\t\tcase EidosTokenType::kTokenAssign_R:\treturn Evaluate_Assign_R(p_node);\n\t\tcase EidosTokenType::kTokenEq:\t\t\treturn Evaluate_Eq(p_node);\n\t\tcase EidosTokenType::kTokenLt:\t\t\treturn Evaluate_Lt(p_node);\n\t\tcase EidosTokenType::kTokenLtEq:\t\treturn Evaluate_LtEq(p_node);\n\t\tcase EidosTokenType::kTokenGt:\t\t\treturn Evaluate_Gt(p_node);\n\t\tcase EidosTokenType::kTokenGtEq:\t\treturn Evaluate_GtEq(p_node);\n\t\tcase EidosTokenType::kTokenNot:\t\t\treturn Evaluate_Not(p_node);\n\t\tcase EidosTokenType::kTokenNotEq:\t\treturn Evaluate_NotEq(p_node);\n\t\tcase EidosTokenType::kTokenNumber:\t\treturn Evaluate_Number(p_node);\n\t\tcase EidosTokenType::kTokenString:\t\treturn Evaluate_String(p_node);\n\t\tcase EidosTokenType::kTokenIdentifier:\treturn Evaluate_Identifier(p_node);\n\t\tcase EidosTokenType::kTokenIf:\t\t\treturn Evaluate_If(p_node);\n\t\tcase EidosTokenType::kTokenDo:\t\t\treturn Evaluate_Do(p_node);\n\t\tcase EidosTokenType::kTokenWhile:\t\treturn Evaluate_While(p_node);\n\t\tcase EidosTokenType::kTokenFor:\t\t\treturn Evaluate_For(p_node);\n\t\tcase EidosTokenType::kTokenNext:\t\treturn Evaluate_Next(p_node);\n\t\tcase EidosTokenType::kTokenBreak:\t\treturn Evaluate_Break(p_node);\n\t\tcase EidosTokenType::kTokenReturn:\t\treturn Evaluate_Return(p_node);\n\t\tcase EidosTokenType::kTokenFunction:\treturn Evaluate_FunctionDecl(p_node);\n\t\tdefault:\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::EvaluateNode): unexpected node token type \" << p_node->token_->token_type_ << \".\" << EidosTerminate(p_node->token_);\n\t}\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_NullStatement(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_NullStatement()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_NullStatement\", 0);\n\t\n#ifndef DEBUG_POINTS_ENABLED\n#error \"DEBUG_POINTS_ENABLED is not defined; include eidos_globals.h\"\n#endif\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tif (debug_points_ && debug_points_->set.size() && (p_node->token_->token_line_ != -1) &&\n\t\t(debug_points_->set.find(p_node->token_->token_line_) != debug_points_->set.end()))\n\t{\n\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG NULL_STATEMENT (line \" << (p_node->token_->token_line_ + 1) << eidos_context_->DebugPointInfo() << \")\" << std::endl;\n\t}\n#endif\n\t\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_NullStatement()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_CompoundStatement(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_CompoundStatement()\");\n\t\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tfor (EidosASTNode *child_node : p_node->children_)\n\t{\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_START();\n#endif\n\t\t\n\t\tEidosValue_SP statement_result_SP = FastEvaluateNode(child_node);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END(child_node->profile_total_);\n#endif\n\t\t\n\t\t// a next, break, or return makes us exit immediately, out to the (presumably enclosing) loop evaluator\n\t\tif (next_statement_hit_ || break_statement_hit_)\n\t\t\tbreak;\n\t\tif (return_statement_hit_)\n\t\t{\n\t\t\tresult_SP = std::move(statement_result_SP);\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_CompoundStatement()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::_Evaluate_RangeExpr_Internal(const EidosASTNode *p_node, const EidosValue &p_first_child_value, const EidosValue &p_second_child_value)\n{\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValueType first_child_type = p_first_child_value.Type();\n\tEidosValueType second_child_type = p_second_child_value.Type();\n\tEidosValue_SP result_SP;\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): operand type \" << first_child_type << \" is not supported by the ':' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): operand type \" << second_child_type << \" is not supported by the ':' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = p_first_child_value.Count();\n\tint second_child_count = p_second_child_value.Count();\n\t\n\tif ((first_child_count != 1) || (second_child_count != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): operands of the ':' operator must have size() == 1.\" << EidosTerminate(operator_token);\n\t\n\tif ((p_first_child_value.DimensionCount() != 1) || (p_second_child_value.DimensionCount() != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): operands of the ':' operator must not be matrices or arrays.\" << EidosTerminate(operator_token);\n\t\n\t// OK, we've got good operands; calculate the result.  If both operands are int, the result is int, otherwise float.\n\tbool underflow = false;\n\t\n\tif ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t{\n\t\tint64_t first_int = p_first_child_value.IntAtIndex_NOCAST(0, operator_token);\n\t\tint64_t second_int = p_second_child_value.IntAtIndex_NOCAST(0, operator_token);\n\t\t\n\t\tif (first_int <= second_int)\n\t\t{\n\t\t\tif (second_int - first_int + 1 > 100000000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): a range with more than 100000000 entries cannot be constructed.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(second_int - first_int + 1);\n\t\t\t\n\t\t\tfor (int64_t range_index = 0; range_index <= second_int - first_int; ++range_index)\n\t\t\t\tint_result->set_int_no_check(range_index + first_int, range_index);\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (first_int - second_int + 1 > 100000000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): a range with more than 100000000 entries cannot be constructed.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_int - second_int + 1);\n\t\t\t\n\t\t\tfor (int64_t range_index = 0; range_index <= first_int - second_int; ++range_index)\n\t\t\t\tint_result->set_int_no_check(first_int - range_index, range_index);\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble first_float = p_first_child_value.NumericAtIndex_NOCAST(0, operator_token);\n\t\tdouble second_float = p_second_child_value.NumericAtIndex_NOCAST(0, operator_token);\n\t\t\n\t\tif (std::isnan(first_float) || std::isnan(second_float))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): operands of the ':' operator must not be NAN.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_float <= second_float)\n\t\t{\n\t\t\tif (second_float - first_float + 1 > 100000000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): a range with more than 100000000 entries cannot be constructed.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->reserve((int)(second_float - first_float + 1));\n\t\t\t\n\t\t\tfor (double range_index = first_float; range_index <= second_float; )\n\t\t\t{\n\t\t\t\tfloat_result->push_float(range_index);\n\t\t\t\t\n\t\t\t\t// be careful not to hang due to underflow\n\t\t\t\tdouble next_index = range_index + 1.0;\n\t\t\t\t\n\t\t\t\tif (next_index == range_index)\n\t\t\t\t{\n\t\t\t\t\t// CODE COVERAGE: This is dead code\n\t\t\t\t\tunderflow = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\trange_index = next_index;\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (first_float - second_float + 1 > 100000000)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): a range with more than 100000000 entries cannot be constructed.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->reserve((int)(first_float - second_float + 1));\n\t\t\t\n\t\t\tfor (double range_index = first_float; range_index >= second_float; )\n\t\t\t{\n\t\t\t\tfloat_result->push_float(range_index);\n\t\t\t\t\n\t\t\t\t// be careful not to hang due to underflow\n\t\t\t\tdouble next_index = range_index - 1.0;\n\t\t\t\t\n\t\t\t\tif (next_index == range_index)\n\t\t\t\t{\n\t\t\t\t\t// CODE COVERAGE: This is dead code\n\t\t\t\t\tunderflow = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\trange_index = next_index;\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t}\n\t\n\tif (underflow)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_Evaluate_RangeExpr_Internal): the floating-point range could not be constructed due to underflow.\" << EidosTerminate(operator_token);\t// CODE COVERAGE: This is dead code\n\t\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_RangeExpr(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_RangeExpr()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_RangeExpr\", 2);\n\n\t// Constant expressions involving the range operator are particularly common, so we cache them for reuse\n\t// here, as an optimization.  If we have a cached value, we can simply return it.\n\tEidosValue_SP result_SP = p_node->cached_range_value_;\n\t\n\tif (!result_SP)\n\t{\n\t\tconst EidosASTNode *child0 = p_node->children_[0];\n\t\tconst EidosASTNode *child1 = p_node->children_[1];\n\t\tbool cacheable = ((child0->token_->token_type_ == EidosTokenType::kTokenNumber) && (child1->token_->token_type_ == EidosTokenType::kTokenNumber));\n\t\t\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(child0);\n\t\tEidosValue_SP second_child_value = FastEvaluateNode(child1);\n\t\t\n\t\tresult_SP = _Evaluate_RangeExpr_Internal(p_node, *first_child_value, *second_child_value);\t\t// gives ownership of the child values\n\t\t\n\t\t// cache our range as a constant in the tree if we can\n\t\tif (cacheable)\n\t\t{\n\t\t\tp_node->cached_range_value_ = result_SP;\n\t\t\tp_node->cached_range_value_->MarkAsConstant();\n\t\t}\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_RangeExpr()\");\n\treturn result_SP;\n}\n\nvoid EidosInterpreter::_CreateArgumentList(const EidosASTNode *p_node, const EidosCallSignature *p_call_signature)\n{\n\tEidosASTNode_ArgumentCache *argument_cache = new EidosASTNode_ArgumentCache();\n\tp_node->argument_cache_ = argument_cache;\n\t\n\tstd::vector<EidosValue_SP> &arg_buffer = argument_cache->argument_buffer_;\n\tstd::vector<EidosASTNode_ArgumentFill> &fill_info = argument_cache->fill_info_;\n\tstd::vector<uint8_t> &no_fill_index = argument_cache->no_fill_index_;\n\tconst std::vector<EidosASTNode *> &node_children = p_node->children_;\n\t\n\tstd::vector<uint8_t> filled_explicitly;\t\t// locally, we need a vector that tells us whether an index was filed explicitly or by default\n\t\n\t// Run through the argument nodes, reserve space for them in the arguments buffer, and evaluate default/constant values once for all calls\n\tauto node_children_end = node_children.end();\n\tint sig_arg_index = 0;\n\tint sig_arg_count = (int)p_call_signature->arg_name_IDs_.size();\n\tbool had_named_argument = false;\n\tbool in_ellipsis = (sig_arg_count > 0) && (p_call_signature->arg_name_IDs_[0] == gEidosID_ELLIPSIS);\n\t\n\tfor (auto child_iter = node_children.begin() + 1; child_iter != node_children_end; ++child_iter)\n\t{\n\t\tEidosASTNode *child = *child_iter;\n\t\tbool is_named_argument = (child->token_->token_type_ == EidosTokenType::kTokenAssign);\n\t\t\n#if DEBUG\n\t\tif (is_named_argument && (child->children_.size() != 2))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): (internal error) named argument node child count != 2.\" << EidosTerminate(nullptr);\n#endif\n\t\t\n\t\tif (in_ellipsis)\n\t\t{\n\t\t\t// While in an ellipsis, all arguments get consumed without type-checking; this ends when we hit a named argument, or run out of arguments\n\t\t\tif (is_named_argument)\n\t\t\t{\n\t\t\t\t// We have a named argument, so it doesn't go in the ellipsis section\n\t\t\t\tin_ellipsis = false;\n\t\t\t\tsig_arg_index++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Unnamed ellipsis argument; make a fill entry for it and move on\n\t\t\t\tif (child->cached_literal_value_)\n\t\t\t\t{\n\t\t\t\t\t// if a cached literal value is available for the node, we don't need to evaluate it at runtime, we can use the cached value forever\n\t\t\t\t\tp_call_signature->CheckArgument(child->cached_literal_value_.get(), sig_arg_index);\n\t\t\t\t\tno_fill_index.emplace_back((uint8_t)arg_buffer.size());\n\t\t\t\t\targ_buffer.emplace_back(child->cached_literal_value_);\n\t\t\t\t\tfilled_explicitly.emplace_back(true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfill_info.emplace_back(child, arg_buffer.size(), sig_arg_index, false, kEidosValueMaskAny);\n\t\t\t\t\targ_buffer.emplace_back(nullptr);\n\t\t\t\t\tfilled_explicitly.emplace_back(true);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (sig_arg_index < sig_arg_count)\n\t\t{\n\t\t\tbool sig_arg_is_singleton = !!(p_call_signature->arg_masks_[sig_arg_index] & kEidosValueMaskSingleton);\n\t\t\tEidosValueMask sig_arg_type_mask = p_call_signature->arg_masks_[sig_arg_index];\n\t\t\t\n\t\t\tif (!is_named_argument)\n\t\t\t{\n\t\t\t\t// We have a non-named argument; it will go into the next argument slot from the signature\n\t\t\t\tif (had_named_argument)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): unnamed argument may not follow after named arguments; once named arguments begin, all arguments must be named arguments (or ellipsis arguments).\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We have a named argument; get information on it from its children\n\t\t\t\tconst std::vector<EidosASTNode *> &child_children = child->children_;\n\t\t\t\t\n\t\t\t\tEidosASTNode *named_arg_name_node = child_children[0];\n\t\t\t\tEidosASTNode *named_arg_value_node = child_children[1];\n\t\t\t\t\n\t\t\t\t// Get the identifier for the argument name\n\t\t\t\tEidosGlobalStringID named_arg_nameID = named_arg_name_node->cached_stringID_;\n\t\t\t\t\n\t\t\t\t// Now re-point child at the value node\n\t\t\t\tchild = named_arg_value_node;\n\t\t\t\t\n\t\t\t\t// While this argument's name doesn't match the expected argument, insert default values for optional arguments\n\t\t\t\tdo \n\t\t\t\t{\n\t\t\t\t\tEidosGlobalStringID arg_name_ID = p_call_signature->arg_name_IDs_[sig_arg_index];\n\t\t\t\t\t\n\t\t\t\t\tif (named_arg_nameID == arg_name_ID)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t// An ellipsis argument may be omitted; it is optional, but gets no default value\n\t\t\t\t\tif (p_call_signature->arg_name_IDs_[sig_arg_index] != gEidosID_ELLIPSIS)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!(sig_arg_type_mask & kEidosValueMaskOptional))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst std::string &named_arg = named_arg_name_node->token_->token_string_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// We have special error-handling for apply() because sapply() used to be named apply() and we want to steer users to the new call\n\t\t\t\t\t\t\tif ((p_call_signature->call_name_ == \"apply\") && ((named_arg == \"lambdaSource\") || (named_arg == \"simplify\")))\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' skipped over required argument '\" << p_call_signature->arg_names_[sig_arg_index] << \"'.\" << std::endl << \"NOTE: The apply() function was renamed sapply() in Eidos 1.6, and a new function named apply() has been added; you may need to change this call to be a call to sapply() instead.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// Special error-handling for defineSpatialMap() because its gridSize parameter was removed in SLiM 3.5\n\t\t\t\t\t\t\tif ((p_call_signature->call_name_ == \"defineSpatialMap\") && (named_arg == \"gridSize\"))\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' skipped over required argument '\" << p_call_signature->arg_names_[sig_arg_index] << \"'.\" << std::endl << \"NOTE: The defineSpatialMap() method was changed in SLiM 3.5, breaking backward compatibility.  Please see the manual for guidance on updating your code.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' skipped over required argument '\" << p_call_signature->arg_names_[sig_arg_index] << \"'; all required arguments must be supplied in order.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tEidosValue_SP default_value = p_call_signature->arg_defaults_[sig_arg_index];\n\t\t\t\t\t\t\n#if DEBUG\n\t\t\t\t\t\tif (!default_value)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): (internal error) missing default value for optional argument.\" << EidosTerminate(nullptr);\n#endif\n\t\t\t\t\t\t\n\t\t\t\t\t\tno_fill_index.emplace_back((uint8_t)arg_buffer.size());\n\t\t\t\t\t\targ_buffer.emplace_back(default_value);\n\t\t\t\t\t\tfilled_explicitly.emplace_back(false);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Move to the next signature argument; if we have run out of them, then treat this argument as illegal\n\t\t\t\t\tsig_arg_index++;\n\t\t\t\t\tif (sig_arg_index == sig_arg_count)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string &named_arg = named_arg_name_node->token_->token_string_;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Special error-handling for defineSpatialMap() because its gridSize parameter was removed in SLiM 3.5\n\t\t\t\t\t\tif ((p_call_signature->call_name_ == \"defineSpatialMap\") && ((named_arg == \"values\") || (named_arg == \"interpolate\")))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' could not be matched.\" << std::endl << \"NOTE: The defineSpatialMap() method was changed in SLiM 3.5, breaking backward compatibility.  Please see the manual for guidance on updating your code.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Special error-handling for initializeSLiMOptions() because its mutationRuns parameter changed to doMutationRunExperiments in SLiM 5\n\t\t\t\t\t\tif ((p_call_signature->call_name_ == \"initializeSLiMOptions\") && (named_arg == \"mutationRuns\"))\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' could not be matched.\" << std::endl << \"NOTE: The mutationRuns parameter to initializeSLiMOptions() was changed in SLiM 5, breaking backward compatibility.  Please see the manual for guidance on updating your code.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Try to diagnose the exact nature of the error, to give a better error message\n\t\t\t\t\t\tconst std::vector<EidosGlobalStringID> &arg_list = p_call_signature->arg_name_IDs_;\n\t\t\t\t\t\tauto arg_iter = std::find(arg_list.begin(), arg_list.end(), named_arg_nameID);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (arg_iter != arg_list.end())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// it is a legit parameter name; so either it was supplied twice, or out of order\n\t\t\t\t\t\t\t// we distinguish those cases because if it was supplied twice, it was filled explicitly;\n\t\t\t\t\t\t\t// if it was supplied out of order, then its value was filled non-explicitly, by a default\n\t\t\t\t\t\t\tsize_t named_arg_index = std::distance(arg_list.begin(), arg_iter);\n\t\t\t\t\t\t\tbool named_arg_was_filled_explicitly = filled_explicitly[named_arg_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (named_arg_was_filled_explicitly)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' was supplied twice in the argument list; each parameter may be supplied only once.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' was supplied out of order; another argument that comes after it in the parameter list was supplied before it.  Eidos requires that parameters be supplied in the order they are given.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// this parameter name does not exist in the call signature\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): named argument '\" << named_arg << \"' could not be matched, because there is no parameter with that name in the call signature.\" << EidosTerminate(nullptr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twhile (true);\n\t\t\t\t\n\t\t\t\thad_named_argument = true;\n\t\t\t}\n\t\t\t\n\t\t\t// This argument will need to be evaluated at dispatch time; place a nullptr in the arguments buffer for now, and create a fill info entry for it\n\t\t\tif (child->cached_literal_value_)\n\t\t\t{\n\t\t\t\t// if a cached literal value is available for the node, we don't need to evaluate it at runtime, we can use the cached value forever\n\t\t\t\tp_call_signature->CheckArgument(child->cached_literal_value_.get(), sig_arg_index);\n\t\t\t\tno_fill_index.emplace_back((uint8_t)arg_buffer.size());\n\t\t\t\targ_buffer.emplace_back(child->cached_literal_value_);\n\t\t\t\tfilled_explicitly.emplace_back(true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfill_info.emplace_back(child, arg_buffer.size(), sig_arg_index, sig_arg_is_singleton, sig_arg_type_mask & kEidosValueMaskFlagStrip);\n\t\t\t\targ_buffer.emplace_back(nullptr);\n\t\t\t\tfilled_explicitly.emplace_back(true);\n\t\t\t}\n\t\t\t\n\t\t\t// Move to the next signature argument, and check whether it is an ellipsis\n\t\t\tsig_arg_index++;\n\t\t\tif (sig_arg_index < sig_arg_count)\n\t\t\t\tin_ellipsis = (p_call_signature->arg_name_IDs_[sig_arg_index] == gEidosID_ELLIPSIS);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this argument is illegal; check whether it is a named argument that is out of order, or just an excess argument\n\t\t\tif (is_named_argument)\n\t\t\t{\n\t\t\t\t// We have a named argument; get information on it from its children\n\t\t\t\tEidosASTNode *named_arg_name_node = child->children_[0];\n\t\t\t\tEidosGlobalStringID named_arg_nameID = named_arg_name_node->cached_stringID_;\n\t\t\t\tconst std::string &named_arg = named_arg_name_node->token_->token_string_;\n\t\t\t\t\n\t\t\t\t// Look for a named parameter in the call signature that matches\n\t\t\t\tfor (int sig_check_index = 0; sig_check_index < sig_arg_count; ++sig_check_index)\n\t\t\t\t{\n\t\t\t\t\tEidosGlobalStringID arg_name_ID = p_call_signature->arg_name_IDs_[sig_check_index];\n\t\t\t\t\t\n\t\t\t\t\tif (named_arg_nameID == arg_name_ID)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): argument '\" << named_arg << \"' to \" << p_call_signature->call_name_ << \"() could not be matched; probably supplied more than once or supplied out of order (note that arguments must be supplied in order).\" << EidosTerminate(nullptr);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): unrecognized named argument '\" << named_arg << \"' to \" << p_call_signature->call_name_ << \"().\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (had_named_argument)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): too many arguments supplied to \" << p_call_signature->call_name_ << \"() (after handling named arguments, which might have filled in default values for previous arguments).\" << EidosTerminate(nullptr);\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): too many arguments supplied to \" << p_call_signature->call_name_ << \"().\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Handle any remaining arguments in the signature\n\twhile (sig_arg_index < sig_arg_count)\n\t{\n\t\t// An ellipsis argument may be omitted; it is optional, but gets no default value\n\t\tif (p_call_signature->arg_name_IDs_[sig_arg_index] != gEidosID_ELLIPSIS)\n\t\t{\n\t\t\tEidosValueMask arg_mask = p_call_signature->arg_masks_[sig_arg_index];\n\t\t\t\n\t\t\tif (!(arg_mask & kEidosValueMaskOptional))\n\t\t\t{\n\t\t\t\t// We have special error-handling for apply() because sapply() used to be named apply() and we want to steer users to the new call\n\t\t\t\tif ((p_call_signature->call_name_ == \"apply\") && (p_call_signature->arg_names_[sig_arg_index] == \"lambdaSource\"))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): missing required argument '\" << p_call_signature->arg_names_[sig_arg_index] << \"'.\" << std::endl << \"NOTE: The apply() function was renamed sapply() in Eidos 1.6, and a new function named apply() has been added; you may need to change this call to be a call to sapply() instead.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): missing required argument '\" << p_call_signature->arg_names_[sig_arg_index] << \"'.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tEidosValue_SP default_value = p_call_signature->arg_defaults_[sig_arg_index];\n\t\t\t\n#if DEBUG\n\t\t\tif (!default_value)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_ProcessArgumentList): (internal error) missing default value for optional argument.\" << EidosTerminate(nullptr);\n#endif\n\t\t\t\n\t\t\tno_fill_index.emplace_back((uint8_t)arg_buffer.size());\n\t\t\targ_buffer.emplace_back(default_value);\n\t\t\tfilled_explicitly.emplace_back(true);\n\t\t}\n\t\t\n\t\tsig_arg_index++;\n\t}\n}\n\nEidosValue_SP EidosInterpreter::DispatchUserDefinedFunction(const EidosFunctionSignature &p_function_signature, const std::vector<EidosValue_SP> &p_arguments)\n{\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tEidosDebugPointIndent indenter;\n\t\n\tif (debug_points_ && debug_points_->set.size() && (p_function_signature.user_definition_line_ != -1) &&\n\t\t(debug_points_->set.find(p_function_signature.user_definition_line_) != debug_points_->set.end()))\n\t{\n\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\n\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG FUNCTION (line \" << (p_function_signature.user_definition_line_ + 1) << eidos_context_->DebugPointInfo() << \"): function \" << p_function_signature.call_name_ << \"() called with arguments:\" << std::endl;\n\t\t\n\t\tindenter.indent(2);\n\t\t\n\t\tfor (size_t arg_index = 0; arg_index < p_arguments.size(); ++arg_index)\n\t\t{\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << p_function_signature.arg_names_[arg_index] << \" == \";\n\t\t\tp_arguments[arg_index]->PrintStructure(output_stream, 5);\n\t\t\toutput_stream << std::endl;\n\t\t}\n\t\t\n\t\tindenter.indent(2);\n\t}\n#endif\n\t\n\tEidosValue_SP result_SP(nullptr);\n\t\n\t// We need to add a new variables symbol table on to the top of the symbol table stack, for parameters and local variables.\n\tEidosSymbolTable new_symbols(EidosSymbolTableType::kLocalVariablesTable, global_symbols_);\n\t\n\t// Set up variables for the function's parameters; they have already been type-checked and had default\n\t// values substituted and so forth, by the Eidos function call dispatch code.\n\tif (p_function_signature.arg_name_IDs_.size() != p_arguments.size())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::DispatchUserDefinedFunction): (internal error) parameter count does not match argument count.\" << EidosTerminate(nullptr);\n\t\n\tfor (size_t arg_index = 0; arg_index < p_arguments.size(); ++arg_index)\n\t\tnew_symbols.SetValueForSymbol(p_function_signature.arg_name_IDs_[arg_index], p_arguments[arg_index]);\n\t\n\t// Save off the current error context for restoration later, if no error occurs.\n\tEidosErrorContext error_context_save = gEidosErrorContext;\n\t\n\t// Set up to indicate that we're now going to be executing from our own private script object.  That\n\t// private script object might or might not be derived from the user script, so errors that occur\n\t// within it might or might not be reportable as positions in the user script; see below.\n\tgEidosErrorContext = EidosErrorContext{{-1, -1, -1, -1}, p_function_signature.body_script_};\n\t\n\t// Execute inside try/catch so we can handle errors well\n\ttry\n\t{\n\t\tEidosInterpreter interpreter(*p_function_signature.body_script_, new_symbols, function_map_, Context(), execution_output_, error_output_\n#ifdef SLIMGUI\n\t\t\t, check_infinite_loops_\n#endif\n\t\t\t);\n\t\t\n\t\t// Get the result.  BEWARE!  This calls causes re-entry into the Eidos interpreter, which is not usually\n\t\t// possible since Eidos does not support multithreaded usage.  This is therefore a key failure point for\n\t\t// bugs that would otherwise not manifest.\n\t\tresult_SP = interpreter.EvaluateInterpreterBlock(false, false);\t// don't print output, don't return last statement value\n\t}\n\tcatch (...)\n\t{\n\t\t// If we're executing a script that does not have a position in the user's script, then the best\n\t\t// we can do is to report the call to the function as the error position.  If the script knows\n\t\t// its position in the user's script, then we don't need to make that correction.  We only make\n\t\t// this correction for gEidosTerminateThrows==true because that is the case when errors are\n\t\t// shown in the GUI.  When at the command line, showing an error position inside an unmoored\n\t\t// script is perfectly fine, and preferable to obscuring that position.  (We could show *both*\n\t\t// pieces of information, in fact, but that is a project for another day.)\n\t\tif (gEidosTerminateThrows && (p_function_signature.body_script_->UserScriptCharOffset() == -1))\n\t\t{\n\t\t\t// In some cases, such as if the error occurred in a derived user-defined function, we can\n\t\t\t// actually get a user script error context at this point, and don't need to intervene.\n\t\t\tif (!gEidosErrorContext.currentScript || (gEidosErrorContext.currentScript->UserScriptUTF16Offset() == -1))\n\t\t\t{\n\t\t\t\tgEidosErrorContext = error_context_save;\n\t\t\t\tTranslateErrorContextToUserScript(\"DispatchUserDefinedFunction()\");\n\t\t\t}\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\t// Restore the normal error context in the event that no exception occurring within the function\n\tgEidosErrorContext = error_context_save;\n\t\n\treturn result_SP;\n}\n\n#ifdef SLIMGUI\nvoid EidosInterpreter::_LogCallArguments(const EidosCallSignature *call_signature, std::vector<EidosValue_SP> *argument_buffer)\n{\n\t// called by EidosInterpreter::Evaluate_Call() to do debug point logging of call arguments\n\tstd::ostream &output_stream = ErrorOutputStream();\n\t\n#if 0\n\t// log out arguments with positional numbers\n\tfor (size_t argument_index = 0; argument_index < argument_buffer->size(); ++argument_index)\n\t{\n\t\toutput_stream << EidosDebugPointIndent::Indent() << \"[\" << argument_index << \"] == \";\n\t\t(*argument_buffer)[argument_index]->PrintStructure(output_stream, 5);\n\t\toutput_stream << std::endl;\n\t}\n#else\n\t// log out arguments with symbols; complicated because of ellipsis arguments\n\tint sig_ellipsis_index = -1, ellipsis_arg_count = 0, ellipsis_start = INT_MAX, ellipsis_end = INT_MAX;\n\tint signature_arg_count = (int)call_signature->arg_name_IDs_.size();\n\tint buffer_arg_count = (int)argument_buffer->size();\n\t\n\tif (call_signature->has_ellipsis_)\n\t{\n\t\tfor (int sig_index = 0; sig_index < signature_arg_count; sig_index++)\n\t\t\tif (call_signature->arg_name_IDs_[sig_index] == gEidosID_ELLIPSIS)\n\t\t\t{\n\t\t\t\tsig_ellipsis_index = sig_index;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\n\t\tif (sig_ellipsis_index != -1)\n\t\t{\n\t\t\t// found the ellipsis; figure out the details\n\t\t\tellipsis_arg_count = buffer_arg_count - signature_arg_count + 1;\t// + 1 because the ellipsis gets one entry in the sig\n\t\t\tellipsis_start = sig_ellipsis_index;\n\t\t\tellipsis_end = sig_ellipsis_index + ellipsis_arg_count - 1;\n\t\t}\n\t}\n\t\n\tfor (int buffer_arg_index = 0; buffer_arg_index < buffer_arg_count; ++buffer_arg_index)\n\t{\n\t\tint signature_arg_index;\n\t\t\n\t\tif (buffer_arg_index < ellipsis_start)\n\t\t\tsignature_arg_index = buffer_arg_index;\n\t\telse if ((buffer_arg_index >= ellipsis_start) && (buffer_arg_index <= ellipsis_end))\n\t\t\tsignature_arg_index = sig_ellipsis_index;\n\t\telse\n\t\t\tsignature_arg_index = buffer_arg_index - ellipsis_arg_count + 1;\t// + 1 because the ellipsis gets one entry in the sig\n\t\t\n\t\toutput_stream << EidosDebugPointIndent::Indent() << call_signature->arg_names_[signature_arg_index] << \" == \";\n\t\t(*argument_buffer)[buffer_arg_index]->PrintStructure(output_stream, 5);\n\t\toutput_stream << std::endl;\n\t}\n#endif\n}\n#endif\n\nEidosValue_SP EidosInterpreter::Evaluate_Call(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Call()\");\n\t\n\tEidosValue_SP result_SP;\n\t\n\t// We do not evaluate the call name node (our first child) to get a function/method object; there is no such type\n\t// in Eidos for now.  Instead, we extract the identifier name directly from the node and work with it.  If the\n\t// node is an identifier, it is a function call; if it is a dot operator, it is a method call; other constructs\n\t// are illegal since expressions cannot evaluate to function/method objects.\n\tconst std::vector<EidosASTNode *> &node_children = p_node->children_;\n\tEidosASTNode *call_name_node = node_children[0];\n\tEidosTokenType call_name_token_type = call_name_node->token_->token_type_;\n\tEidosToken *call_identifier_token = nullptr;\n\t\n\tif (call_name_token_type == EidosTokenType::kTokenIdentifier)\n\t{\n\t\t//\n\t\t//\tFUNCTION CALL DISPATCH\n\t\t//\n\t\tcall_identifier_token = call_name_node->token_;\n\t\t\n\t\t// OK, we have <identifier>(...); that's a well-formed function call\n\t\tconst std::string *function_name = &(call_identifier_token->token_string_);\n\t\tconst EidosFunctionSignature *function_signature = call_name_node->cached_signature_.get();\n\t\t\n\t\t// If the function call is a built-in Eidos function, we might already have a pointer to its signature cached; if not, we'll have to look it up\n\t\tif (!function_signature)\n\t\t{\n\t\t\t// Get the function signature and check our arguments against it\n\t\t\tauto signature_iter = function_map_.find(*function_name);\n\t\t\t\n\t\t\tif (signature_iter == function_map_.end())\n\t\t\t{\n\t\t\t\t// This raises a special exception if the function name is undefined.\n\t\t\t\t// This facility is used by Community::_EvaluateTickRangeNode() for tolerant evaluation.\n\t\t\t\tif (use_custom_undefined_function_raise_)\n\t\t\t\t\tthrow SLiMUndefinedFunctionException();\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): unrecognized function name \" << *function_name << \".\";\n\t\t\t\tif (Context() == nullptr)\n\t\t\t\t\tEIDOS_TERMINATION << \"  This may be because the current Eidos context (such as the current SLiM simulation) is invalid.\";\n\t\t\t\tEIDOS_TERMINATION << EidosTerminate(call_identifier_token);\n\t\t\t}\n\t\t\t\n\t\t\tfunction_signature = signature_iter->second.get();\n\t\t}\n\t\t\n\t\t// If an error occurs inside a function or method call, we want to highlight the call\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(call_identifier_token);\n\t\t\n\t\t// Argument processing\n\t\tstd::vector<EidosValue_SP> *argument_buffer = _ProcessArgumentList(p_node, function_signature);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tEidosDebugPointIndent indenter;\n\t\t\n\t\tif (debug_points_ && debug_points_->set.size() && (call_identifier_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(call_identifier_token->token_line_) != debug_points_->set.end()))\n\t\t{\n\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG CALL (line \" << (call_identifier_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): call to function \" <<\n\t\t\t\t*function_name << \"() with arguments:\" << std::endl;\n\t\t\tindenter.indent(2);\n\t\t\t_LogCallArguments(function_signature, argument_buffer);\n\t\t\tindenter.indent(2);\n\t\t}\n#endif\n\t\t\n\t\ttry {\n\t\t\tif (function_signature->internal_function_)\n\t\t\t{\n\t\t\t\tresult_SP = function_signature->internal_function_(*argument_buffer, *this);\n\t\t\t}\n\t\t\telse if (function_signature->body_script_)\n\t\t\t{\n\t\t\t\tresult_SP = DispatchUserDefinedFunction(*function_signature, *argument_buffer);\n\t\t\t}\n\t\t\telse if (!function_signature->delegate_name_.empty())\n\t\t\t{\n\t\t\t\tif (eidos_context_)\n\t\t\t\t\tresult_SP = eidos_context_->ContextDefinedFunctionDispatch(*function_name, *argument_buffer, *this);\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): function \" << function_name << \" is defined by the Context, but the Context is not defined.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): unbound function \" << *function_name << \".\" << EidosTerminate(call_identifier_token);\n\t\t} catch (...) {\n\t\t\t// BCH 4/15/2025: Adding the try/catch and _DeprocessArgumentList() call here to fix a leak that\n\t\t\t// occurred for recursive function calls, for which argument_buffer is heap-allocated.\n\t\t\t_DeprocessArgumentList(p_node, argument_buffer);\n\t\t\tthrow;\n\t\t}\n\t\t\n\t\t_DeprocessArgumentList(p_node, argument_buffer);\n\t\t\n\t\t// If the code above supplied no return value, raise when in debug.  Not in debug, we crash.\n#if DEBUG\n\t\tif (!result_SP)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): (internal error) function \" << *function_name << \" returned nullptr.\" << EidosTerminate(call_identifier_token);\n#endif\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tif (debug_points_ && debug_points_->set.size() && (call_identifier_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(call_identifier_token->token_line_) != debug_points_->set.end()))\n\t\t{\n\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\n\t\t\tindenter.outdent();\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG CALL (line \" << (call_identifier_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): function \" <<\n\t\t\t\t*function_name << \"() return: \";\n\t\t\tif (result_SP->Count() <= 1)\n\t\t\t{\n\t\t\t\tresult_SP->PrintStructure(output_stream, 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// print multiple values on a new line, with indent\n\t\t\t\tresult_SP->PrintStructure(output_stream, 0);\n\t\t\t\toutput_stream << std::endl;\n\t\t\t\tindenter.indent(2);\n\t\t\t\tresult_SP->Print(output_stream, EidosDebugPointIndent::Indent());\n\t\t\t\tindenter.outdent(2);\n\t\t\t}\n\t\t\toutput_stream << std::endl;\n\t\t}\n#endif\n\t\t\n\t\t// Check the return value against the signature\n\t\tfunction_signature->CheckReturn(*result_SP);\n\t\t\n\t\t// Forget the function token, since it is not responsible for any future errors\n\t\tRestoreErrorPosition(error_pos_save);\n\t}\n\telse if (call_name_token_type == EidosTokenType::kTokenDot)\n\t{\n\t\t//\n\t\t//\tMETHOD CALL DISPATCH\n\t\t//\n\t\tEIDOS_ASSERT_CHILD_COUNT_X(call_name_node, \"'.'\", \"EidosInterpreter::Evaluate_Call\", 2, call_name_node->token_);\n\t\t\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(call_name_node->children_[0]);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): operand type \" << first_child_type << \" is not supported by the '.' operator.\" << EidosTerminate(call_name_node->token_);\n\t\t\n\t\tEidosASTNode *second_child_node = call_name_node->children_[1];\n\t\t\n\t\tif (second_child_node->token_->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): (internal error) the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(call_name_node->token_);\n\t\t\n\t\t// OK, we have <object type>.<identifier>(...); that's a well-formed method call\n\t\tcall_identifier_token = second_child_node->token_;\n\t\t\n\t\tEidosGlobalStringID method_id = second_child_node->cached_stringID_;\n\t\tEidosValue_Object_SP method_object = static_pointer_cast<EidosValue_Object>(first_child_value);\t// guaranteed by the Type() call above\n\t\t\n\t\t// Look up the method signature; this could be cached in the tree, probably, since we guarantee that method signatures are unique by name\n\t\tconst EidosMethodSignature *method_signature = method_object->Class()->SignatureForMethod(method_id);\n\t\t\n\t\tif (!method_signature)\n\t\t{\n\t\t\t// Give more helpful error messages for deprecated methods\n\t\t\tif (call_identifier_token->token_string_ == \"method\")\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): method \" << EidosStringRegistry::StringForGlobalStringID(method_id) << \"() is not defined on object element type \" << method_object->ElementType() << \".  Note that method() has been renamed to methodSignature().\" << EidosTerminate(call_identifier_token);\n\t\t\telse if (call_identifier_token->token_string_ == \"property\")\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): method \" << EidosStringRegistry::StringForGlobalStringID(method_id) << \"() is not defined on object element type \" << method_object->ElementType() << \".  Note that property() has been renamed to propertySignature().\" << EidosTerminate(call_identifier_token);\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): method \" << EidosStringRegistry::StringForGlobalStringID(method_id) << \"() is not defined on object element type \" << method_object->ElementType() << \".\" << EidosTerminate(call_identifier_token);\n\t\t}\n\t\t\n\t\t// If an error occurs inside a function or method call, we want to highlight the call\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(call_identifier_token);\n\t\t\n\t\t// Argument processing\n\t\tstd::vector<EidosValue_SP> *argument_buffer = _ProcessArgumentList(p_node, method_signature);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tEidosDebugPointIndent indenter;\n\t\t\n\t\tif (debug_points_ && debug_points_->set.size() && (call_identifier_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(call_identifier_token->token_line_) != debug_points_->set.end()))\n\t\t{\n\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG CALL (line \" << (call_identifier_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): call to method \" <<\n\t\t\t\tEidosStringRegistry::StringForGlobalStringID(method_id) << \"() with arguments:\" << std::endl;\n\t\t\tindenter.indent(2);\n\t\t\t_LogCallArguments(method_signature, argument_buffer);\n\t\t\tindenter.indent(2);\n\t\t}\n#endif\n\t\t\n\t\t// If the method is a class method, dispatch it to the class object\n\t\tif (method_signature->is_class_method)\n\t\t{\n\t\t\t// Note that starting in Eidos 1.1 we pass method_object to ExecuteClassMethod(), to allow class methods to\n\t\t\t// act as non-multicasting methods that operate on the whole target vector.  BCH 11 June 2016\n\t\t\tresult_SP = method_object->Class()->ExecuteClassMethod(method_id, method_object.get(), *argument_buffer, *this);\n\t\t\t\n\t\t\tmethod_signature->CheckReturn(*result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult_SP = method_object->ExecuteMethodCall(method_id, (EidosInstanceMethodSignature *)method_signature, *argument_buffer, *this);\n\t\t}\n\t\t\n\t\t_DeprocessArgumentList(p_node, argument_buffer);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tif (debug_points_ && debug_points_->set.size() && (call_identifier_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(call_identifier_token->token_line_) != debug_points_->set.end()))\n\t\t{\n\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\n\t\t\tindenter.outdent();\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG CALL (line \" << (call_identifier_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): method \" <<\n\t\t\t\tEidosStringRegistry::StringForGlobalStringID(method_id) << \"() return: \";\n\t\t\tif (result_SP->Count() <= 1)\n\t\t\t{\n\t\t\t\tresult_SP->PrintStructure(output_stream, 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// print multiple values on a new line, with indent\n\t\t\t\tresult_SP->PrintStructure(output_stream, 0);\n\t\t\t\toutput_stream << std::endl;\n\t\t\t\tindenter.indent(2);\n\t\t\t\tresult_SP->Print(output_stream, EidosDebugPointIndent::Indent());\n\t\t\t\tindenter.outdent(2);\n\t\t\t}\n\t\t\toutput_stream << std::endl;\n\t\t}\n#endif\n\t\t\n\t\t// Forget the function token, since it is not responsible for any future errors\n\t\tRestoreErrorPosition(error_pos_save);\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Call): the '()' operator may only be used with a function name or method name (illegal operand for a function call operation).\" << EidosTerminate(call_name_node->token_);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Call()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Subset(const EidosASTNode *p_node)\n{\n\t// Note that the logic here is very parallel to that of EidosInterpreter::_ProcessSubsetAssignment()\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Subset()\");\n\tEIDOS_ASSERT_CHILD_COUNT_GTEQ(\"EidosInterpreter::Evaluate_Subset\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValueType first_child_type = first_child_value->Type();\n\tint first_child_dim_count = first_child_value->DimensionCount();\n\t\n\tif (first_child_type == EidosValueType::kValueVOID)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): subsetting of a value of type void is not supported by the '[]' operator.\" << EidosTerminate(operator_token);\n\t\n\t// organize our subset arguments\n\tint child_count = (int)p_node->children_.size();\n\tstd::vector <EidosValue_SP> subset_indices;\n\t\n\tfor (int child_index = 1; child_index < child_count; ++child_index)\n\t{\n\t\tconst EidosASTNode *subset_index_node = p_node->children_[child_index];\n\t\tEidosTokenType subset_index_token_type = subset_index_node->token_->token_type_;\n\t\t\n\t\tif ((subset_index_token_type == EidosTokenType::kTokenComma) || (subset_index_token_type == EidosTokenType::kTokenRBracket))\n\t\t{\n\t\t\t// We have a placeholder node indicating a skipped expression, so we save NULL as the value\n\t\t\tsubset_indices.emplace_back(gStaticEidosValueNULL);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have an expression node, so we evaluate it, check the value, and save it\n\t\t\tEidosValue_SP child_value = FastEvaluateNode(subset_index_node);\n\t\t\tEidosValueType child_type = child_value->Type();\n\t\t\t\n\t\t\t// BCH 4/29/2019: handle the simple case of a singleton integer subset as fast as we can, since this is the common case\n\t\t\t// This can be commented out harmlessly; this case is also handled below, just slower\n\t\t\tif ((child_count == 2) && (child_type == EidosValueType::kValueInt) && (child_value->Count() == 1) && (child_value->DimensionCount() == 1))\n\t\t\t{\n\t\t\t\tint subset_index = (int)child_value->IntData()[0];\n\t\t\t\t\n\t\t\t\tresult_SP = first_child_value->GetValueAtIndex(subset_index, operator_token);\n\t\t\t\t\n\t\t\t\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Subset()\");\n\t\t\t\treturn result_SP;\n\t\t\t}\n\t\t\t\n\t\t\tif (child_type == EidosValueType::kValueFloat)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): it is no longer legal to subset with float indices; use asInteger() to cast the indices to integer.\" << EidosTerminate(operator_token);\n\t\t\tif ((child_type != EidosValueType::kValueInt) && (child_type != EidosValueType::kValueLogical) && (child_type != EidosValueType::kValueNULL))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): index operand type \" << child_type << \" is not supported by the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\t// BCH 9/10/2025: we now want to support subsetting of a matrix by a matrix, in two specific cases; other cases continue to be an error\n\t\t\tif (child_value->DimensionCount() != 1)\n\t\t\t{\n\t\t\t\t// if we're subsetting with a matrix or array, the target of the subset must be a matrix or array\n\t\t\t\tif (first_child_dim_count == 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): subsetting of a vector with a matrix or array index operand is not supported by the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\t// if we're subsetting with a matrix or array, that must be the only subset argument\n\t\t\t\tif (child_count != 2)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): this type of subsetting of a matrix or array index operand is not supported by the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\t// if the subset argument is of type logical, its dimensions must exactly match the target\n\t\t\t\t// this produces a result vector containing the target elements selected by true elements\n\t\t\t\tif (child_type == EidosValueType::kValueLogical)\n\t\t\t\t{\n\t\t\t\t\tif (!EidosValue::MatchingDimensions(first_child_value.get(), child_value.get()))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): non-conformable logical matrix or array operand for the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tconst eidos_logical_t *operand_data = child_value->LogicalData();\n\t\t\t\t\tint operand_count = child_value->Count();\n\t\t\t\t\tresult_SP = first_child_value->NewMatchingType();\n\t\t\t\t\t\n\t\t\t\t\tfor (int operand_index = 0; operand_index < operand_count; ++operand_index)\n\t\t\t\t\t\tif (operand_data[operand_index])\n\t\t\t\t\t\t\tresult_SP->PushValueFromIndexOfEidosValue(operand_index, *first_child_value, operator_token);\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Subset()\");\n\t\t\t\t\treturn result_SP;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// if the subset argument is integer, it must have a column count that matches the target's\n\t\t\t\t// dimensionality -- e.g., two columns (row,col) for a matrix target -- and any number of rows\n\t\t\t\t// this produces a result vector containing the target elements selected by the operand rows\n\t\t\t\tif (child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tif (child_value->DimensionCount() != 2)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): subsetting a matrix or array with an integer array is not supported by the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\tif (child_value->Dimensions()[1] != first_child_value->DimensionCount())\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): subsetting a matrix or array with an integer matrix requires that the integer matrix have a column count equal to the number of dimensions of the target matrix or array (e.g., two columns if the target is a matrix).\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tconst int64_t *operand_data = child_value->IntData();\n\t\t\t\t\tint64_t operand_nrow = child_value->Dimensions()[0];\n\t\t\t\t\tint64_t operand_ncol = child_value->Dimensions()[1];\n\t\t\t\t\tconst int64_t *target_dimensions = first_child_value->Dimensions();\n\t\t\t\t\tresult_SP = first_child_value->NewMatchingType();\n\t\t\t\t\t\n\t\t\t\t\tfor (int64_t operand_row = 0; operand_row < operand_nrow; ++operand_row)\n\t\t\t\t\t{\n\t\t\t\t\t\tint target_index = 0;\n\t\t\t\t\t\tint stride = 1;\n\t\t\t\t\t\tconst int64_t *operand_row_ptr = operand_data + operand_row;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int64_t operand_col = 0; operand_col < operand_ncol; ++operand_col)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint64_t coordinate = *operand_row_ptr;\n\t\t\t\t\t\t\toperand_row_ptr += operand_nrow;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttarget_index += (coordinate * stride);\n\t\t\t\t\t\t\tstride *= target_dimensions[operand_col];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tresult_SP->PushValueFromIndexOfEidosValue(target_index, *first_child_value, operator_token);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Subset()\");\n\t\t\t\t\treturn result_SP;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tsubset_indices.emplace_back(child_value);\n\t\t}\n\t}\n\t\n\tint subset_index_count = (int)subset_indices.size();\n\t\n\tif ((subset_index_count != first_child_dim_count) && (subset_index_count != 1))\n\t{\n\t\t// We have the wrong number of subset arguments for our dimensionality, so this is an error\n\t\tif (subset_index_count > first_child_dim_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): too many subset arguments for the indexed operand's dimensionality.\" << EidosTerminate(operator_token);\n\t\telse // (subset_index_count < first_child_dim_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): too few subset arguments for the indexed operand's dimensionality.\" << EidosTerminate(operator_token);\n\t}\n\telse if (first_child_type == EidosValueType::kValueNULL)\n\t{\n\t\t// Any subset of NULL returns NULL; however, we evaluated the expression nodes above first, for side effects and to check for errors\n\t\tresult_SP = gStaticEidosValueNULL;\n\t}\n\telse if ((subset_index_count == 1) && (subset_indices[0] == gStaticEidosValueNULL))\n\t{\n\t\t// We have a single subset argument of NULL, so we have x[] or x[NULL]; just return x, but as a vector, not a matrix/array\n\t\tif (first_child_dim_count == 1)\n\t\t\tresult_SP = first_child_value;\n\t\telse\n\t\t{\n\t\t\tresult_SP = first_child_value->CopyValues();\n\t\t\t\n\t\t\tresult_SP->SetDimensions(1, nullptr);\n\t\t}\n\t}\n\telse if (subset_index_count == 1)\n\t{\n\t\t// OK, we have a simple vector-style subset that is not NULL; handle it as we did in Eidos 1.5 and earlier\n\t\tEidosValue_SP second_child_value = subset_indices[0];\n\t\t\n\t\tresult_SP = SubsetEidosValue(first_child_value.get(), second_child_value.get(), operator_token, /* p_raise_range_errors */ true);\n\t}\n\telse\n\t{\n\t\t// We have a new matrix/array-style subset, like x[1,], x[,1], x[,], etc.; this is Eidos 1.6 and later\n\t\t// Handle each subset value in turn, determining which subset of each dimension will be carried forward\n\t\t// We tabulate the status of each dimension, and then put it all together at the end as a result value\n\t\tconst int64_t *first_child_dim = first_child_value->Dimensions();\n\t\tstd::vector<std::vector<int64_t>> inclusion_indices;\t// the chosen indices for each dimension\n\t\tbool empty_dimension = false;\n\t\t\n\t\tfor (int subset_index = 0; subset_index < subset_index_count; ++subset_index)\n\t\t{\n\t\t\tEidosValue_SP subset_value = subset_indices[subset_index];\n\t\t\tEidosValueType subset_type = subset_value->Type();\n\t\t\tint subset_count = subset_value->Count();\n\t\t\tint dim_size = (int)first_child_dim[subset_index];\n\t\t\tstd::vector<int64_t> indices;\n\t\t\t\n\t\t\tif (subset_type == EidosValueType::kValueNULL)\n\t\t\t{\n\t\t\t\t// We skipped over this dimension or had NULL, so every valid index in the dimension is included\n\t\t\t\tfor (int dim_index = 0; dim_index < dim_size; ++dim_index)\n\t\t\t\t\tindices.emplace_back(dim_index);\n\t\t\t}\n\t\t\telse if (subset_type == EidosValueType::kValueLogical)\n\t\t\t{\n\t\t\t\t// We have a logical subset, which must equal the dimension size and gets translated directly into inclusion_indices\n\t\t\t\tif (subset_count != dim_size)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): the '[]' operator requires that the size() of a logical index operand must match the corresponding dimension of the indexed operand.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tconst eidos_logical_t *logical_index_data = subset_value->LogicalData();\n\t\t\t\t\n\t\t\t\tfor (int dim_index = 0; dim_index < dim_size; dim_index++)\n\t\t\t\t\tif (logical_index_data[dim_index])\n\t\t\t\t\t\tindices.emplace_back(dim_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We have an integer subset, which selects indices within inclusion_indices\n\t\t\t\tfor (int index_index = 0; index_index < subset_count; index_index++)\n\t\t\t\t{\n\t\t\t\t\tint64_t index_value = subset_value->IntAtIndex_NOCAST(index_index, operator_token);\n\t\t\t\t\t\n\t\t\t\t\tif ((index_value < 0) || (index_value >= dim_size))\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Subset): out-of-range index \" << index_value << \" used with the '[]' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\telse\n\t\t\t\t\t\tindices.emplace_back(index_value);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (indices.size() == 0)\n\t\t\t{\n\t\t\t\tempty_dimension = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tinclusion_indices.emplace_back(indices);\n\t\t}\n\t\t\n\t\tif (empty_dimension)\n\t\t{\n\t\t\t// If there was a dimension where no index was included, the result is an empty vector of the right type\n\t\t\tresult_SP = first_child_value->NewMatchingType();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult_SP = first_child_value->Subset(inclusion_indices, false, operator_token);\n\t\t}\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Subset()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_MemberRef(const EidosASTNode *p_node)\n{\n#if DEBUG || defined(EIDOS_GUI)\n\tif (logging_execution_)\n\t{\n\t\t// When logging execution, use the slow path so everything gets logged correctly\n\t\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_MemberRef()\");\n\t\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_MemberRef\", 2);\n\t\t\n\t\tEidosToken *operator_token = p_node->token_;\n\t\tEidosValue_SP result_SP;\n\t\t\n\t\tconst EidosASTNode *first_child_node = p_node->children_[0];\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(first_child_node);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) operand type \" << first_child_type << \" is not supported by the '.' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tEidosASTNode *second_child_node = p_node->children_[1];\n\t\tEidosToken *second_child_token = second_child_node->token_;\n\t\t\n\t\tif (second_child_token->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(operator_token);\n\t\t\n\t\t// If an error occurs inside a function or method call, we want to highlight the call\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(second_child_token);\n\t\t\n\t\t// We offload the actual work to GetPropertyOfElements() to keep things simple here\n\t\tresult_SP = static_cast<EidosValue_Object *>(first_child_value.get())->GetPropertyOfElements(second_child_node->cached_stringID_);\n\t\t\n\t\t// Forget the function token, since it is not responsible for any future errors\n\t\tRestoreErrorPosition(error_pos_save);\n\t\t\n\t\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_MemberRef()\");\n\t\treturn result_SP;\n\t}\n#endif\n\t\n\t// When not logging execution, we can use a fast code path that assumes no logging\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n\tconst EidosASTNode *first_child_node = p_node->children_[0];\n\t\n\t// use_custom_undefined_identifier_raise_ is tested here because when it is set, we want EidosInterpreter::Evaluate_Identifier() to be\n\t// called, to receive the special treatment of that flag that that method implements; Evaluate_Identifier_RAW() doesn't do it.\n\tif ((first_child_node->token_->token_type_ == EidosTokenType::kTokenIdentifier) && !use_custom_undefined_identifier_raise_)\n\t{\n\t\t// <identifier>.<identifier> is an extremely common pattern so we optimize for it here\n\t\t// with Evaluate_Identifier_RAW(), which avoids EidosValue_SP, call logging, and other overhead\n\t\tEidosValue *first_child_value = Evaluate_Identifier_RAW(first_child_node);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) operand type \" << first_child_type << \" is not supported by the '.' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tEidosASTNode *second_child_node = p_node->children_[1];\n\t\tEidosToken *second_child_token = second_child_node->token_;\n\t\t\n\t\tif (second_child_token->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(operator_token);\n\t\t\n\t\t// If an error occurs inside a function or method call, we want to highlight the call\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(second_child_token);\n\t\t\n\t\t// We offload the actual work to GetPropertyOfElements() to keep things simple here\n\t\tresult_SP = static_cast<EidosValue_Object *>(first_child_value)->GetPropertyOfElements(second_child_node->cached_stringID_);\n\t\t\n\t\t// Forget the function token, since it is not responsible for any future errors\n\t\tRestoreErrorPosition(error_pos_save);\n\t}\n\telse\n\t{\n\t\t// the general <expression>.<identifier> case has to use EidosValue_SP\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(first_child_node);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif (first_child_type != EidosValueType::kValueObject)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) operand type \" << first_child_type << \" is not supported by the '.' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tEidosASTNode *second_child_node = p_node->children_[1];\n\t\tEidosToken *second_child_token = second_child_node->token_;\n\t\t\n\t\tif (second_child_token->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_MemberRef): (internal error) the '.' operator for x.y requires operand y to be an identifier.\" << EidosTerminate(operator_token);\n\t\t\n\t\t// If an error occurs inside a function or method call, we want to highlight the call\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(second_child_token);\n\t\t\n\t\t// We offload the actual work to GetPropertyOfElements() to keep things simple here\n\t\tresult_SP = static_cast<EidosValue_Object *>(first_child_value.get())->GetPropertyOfElements(second_child_node->cached_stringID_);\n\t\t\n\t\t// Forget the function token, since it is not responsible for any future errors\n\t\tRestoreErrorPosition(error_pos_save);\n\t}\n\t\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Plus(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Plus()\");\n\tEIDOS_ASSERT_CHILD_RANGE(\"EidosInterpreter::Evaluate_Plus\", 1, 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n\tif (p_node->children_.size() == 1)\n\t{\n\t\t// unary plus is a no-op, but legal only for numeric types\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): operand type \" << first_child_type << \" is not supported by the unary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tresult_SP = std::move(first_child_value);\n\t}\n\telse\n\t{\n\t\t// binary plus is legal either between two numeric types, or between a string and any other non-NULL operand\n\t\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\tEidosValueType second_child_type = second_child_value->Type();\n\t\t\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): non-conformable array operands to binary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): operand type void is not supported by the '+' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueString) || (second_child_type == EidosValueType::kValueString))\n\t\t{\n\t\t\t// If either operand is a string, then we are doing string concatenation, with promotion to strings if needed\n\t\t\t// BCH 10/12/2018: Starting in Eidos 2.2, we allow string concatenation of NULL, which acts just as if the NULL were\n\t\t\t// a singleton string vector containing \"NULL\".  It is handled by pretending that NULL is length 1 and special-casing.\n\t\t\tif (first_child_type == EidosValueType::kValueNULL)\n\t\t\t{\n\t\t\t\tfirst_child_count = 1;\n\t\t\t\tresult_dim_source = second_child_value;\n\t\t\t}\n\t\t\tif (second_child_type == EidosValueType::kValueNULL)\n\t\t\t{\n\t\t\t\tsecond_child_count = 1;\n\t\t\t\tresult_dim_source = first_child_value;\n\t\t\t}\n\t\t\t\n\t\t\tif ((first_child_count == 1) && (second_child_count == 1))\n\t\t\t{\n\t\t\t\tconst std::string &&first_string = (first_child_type == EidosValueType::kValueNULL) ? gEidosStr_NULL : first_child_value->StringAtIndex_CAST(0, operator_token);\n\t\t\t\tconst std::string &&second_string = (second_child_type == EidosValueType::kValueNULL) ? gEidosStr_NULL : second_child_value->StringAtIndex_CAST(0, operator_token);\n\t\t\t\t\n\t\t\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(first_string + second_string));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (first_child_count == second_child_count)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(first_child_count);\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tstring_result->PushString(first_child_value->StringAtIndex_CAST(value_index, operator_token) + second_child_value->StringAtIndex_CAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tresult_SP = string_result_SP;\n\t\t\t\t}\n\t\t\t\telse if (first_child_count == 1)\n\t\t\t\t{\n\t\t\t\t\tstd::string singleton_string = (first_child_type == EidosValueType::kValueNULL) ? gEidosStr_NULL : first_child_value->StringAtIndex_CAST(0, operator_token);\n\t\t\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(second_child_count);\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\t\tstring_result->PushString(singleton_string + second_child_value->StringAtIndex_CAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tresult_SP = string_result_SP;\n\t\t\t\t}\n\t\t\t\telse if (second_child_count == 1)\n\t\t\t\t{\n\t\t\t\t\tstd::string singleton_string = (second_child_type == EidosValueType::kValueNULL) ? gEidosStr_NULL : second_child_value->StringAtIndex_CAST(0, operator_token);\n\t\t\t\t\tEidosValue_String_SP string_result_SP = EidosValue_String_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n\t\t\t\t\tEidosValue_String *string_result = string_result_SP->Reserve(first_child_count);\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tstring_result->PushString(first_child_value->StringAtIndex_CAST(value_index, operator_token) + singleton_string);\n\t\t\t\t\t\n\t\t\t\t\tresult_SP = string_result_SP;\n\t\t\t\t}\n\t\t\t\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t\t\t\t{\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): the string concatenation '+' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1, or (3) one operand is NULL.\" << EidosTerminate(operator_token);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\t// both operands are integer, so we are computing an integer result, which entails overflow testing\n\t\t\tif (first_child_count == second_child_count)\n\t\t\t{\n\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->set_int_no_check(first_child_value->IntAtIndex_NOCAST(value_index, operator_token) + second_child_value->IntAtIndex_NOCAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tint64_t first_operand = first_child_data[value_index];\n\t\t\t\t\tint64_t second_operand = second_child_data[value_index];\n\t\t\t\t\tint64_t add_result;\n\t\t\t\t\tbool overflow = Eidos_add_overflow(first_operand, second_operand, &add_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): integer addition overflow with the binary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(add_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse if (first_child_count == 1)\n\t\t\t{\n\t\t\t\tint64_t singleton_int = first_child_value->IntAtIndex_NOCAST(0, operator_token);\n\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->PushInt(singleton_int + second_child_value->IntAtIndex_NOCAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tint64_t second_operand = second_child_data[value_index];\n\t\t\t\t\tint64_t add_result;\n\t\t\t\t\tbool overflow = Eidos_add_overflow(singleton_int, second_operand, &add_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): integer addition overflow with the binary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(add_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse if (second_child_count == 1)\n\t\t\t{\n\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\tint64_t singleton_int = second_child_value->IntAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->PushInt(first_child_value->IntAtIndex_NOCAST(value_index, operator_token) + singleton_int);\n\t\t\t\t\t\n\t\t\t\t\tint64_t first_operand = first_child_data[value_index];\n\t\t\t\t\tint64_t add_result;\n\t\t\t\t\tbool overflow = Eidos_add_overflow(first_operand, singleton_int, &add_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): integer addition overflow with the binary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(add_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): the '+' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat)) || ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): the combination of operand types \" << first_child_type << \" and \" << second_child_type << \" is not supported by the binary '+' operator.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\t// We have at least one float operand, so we are computing a float result\n\t\t\tif (first_child_count == second_child_count)\n\t\t\t{\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] + second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] + second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse // ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] + second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse if (first_child_count == 1)\n\t\t\t{\n\t\t\t\tdouble singleton_float = first_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\t\n\t\t\t\tif (second_child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(singleton_float + second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse\t// (second_child_type == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(singleton_float + second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse if (second_child_count == 1)\n\t\t\t{\n\t\t\t\tdouble singleton_float = second_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] + singleton_float, value_index);\n\t\t\t\t}\n\t\t\t\telse\t// (first_child_type == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] + singleton_float, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Plus): the '+' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Plus()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Minus(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Minus()\");\n\tEIDOS_ASSERT_CHILD_RANGE(\"EidosInterpreter::Evaluate_Minus\", 1, 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValueType first_child_type = first_child_value->Type();\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): operand type \" << first_child_type << \" is not supported by the '-' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = first_child_value->Count();\n\t\n\tif (p_node->children_.size() == 1)\n\t{\n\t\t// unary minus\n\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t//int_result->set_int_no_check(-first_child_value->IntAtIndex_NOCAST(value_index, operator_token), value_index);\n\t\t\t\t\n\t\t\t\tint64_t operand = first_child_data[value_index];\n\t\t\t\tint64_t subtract_result;\n\t\t\t\tbool overflow = Eidos_sub_overflow((int64_t)0, operand, &subtract_result);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): integer negation overflow with the unary '-' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(subtract_result, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(-first_child_data[value_index], value_index);\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\t\n\t\tresult_SP->CopyDimensionsFromValue(first_child_value.get());\n\t}\n\telse\n\t{\n\t\t// binary minus\n\t\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\tEidosValueType second_child_type = second_child_value->Type();\n\t\t\n\t\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): operand type \" << second_child_type << \" is not supported by the '-' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tint second_child_count = second_child_value->Count();\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): non-conformable array operands to binary '-' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\t// both operands are integer, so we are computing an integer result, which entails overflow testing\n\t\t\tif (first_child_count == second_child_count)\n\t\t\t{\n\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->set_int_no_check(first_child_value->IntAtIndex_NOCAST(value_index, operator_token) - second_child_value->IntAtIndex_NOCAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tint64_t first_operand = first_child_data[value_index];\n\t\t\t\t\tint64_t second_operand = second_child_data[value_index];\n\t\t\t\t\tint64_t subtract_result;\n\t\t\t\t\tbool overflow = Eidos_sub_overflow(first_operand, second_operand, &subtract_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): integer subtraction overflow with the binary '-' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(subtract_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse if (first_child_count == 1)\n\t\t\t{\n\t\t\t\tint64_t singleton_int = first_child_value->IntAtIndex_NOCAST(0, operator_token);\n\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->set_int_no_check(singleton_int - second_child_value->IntAtIndex_NOCAST(value_index, operator_token));\n\t\t\t\t\t\n\t\t\t\t\tint64_t second_operand = second_child_data[value_index];\n\t\t\t\t\tint64_t subtract_result;\n\t\t\t\t\tbool overflow = Eidos_sub_overflow(singleton_int, second_operand, &subtract_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): integer subtraction overflow with the binary '-' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(subtract_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse if (second_child_count == 1)\n\t\t\t{\n\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\tint64_t singleton_int = second_child_value->IntAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t\t//int_result->set_int_no_check(first_child_value->IntAtIndex_NOCAST(value_index, operator_token) - singleton_int);\n\t\t\t\t\t\n\t\t\t\t\tint64_t first_operand = first_child_data[value_index];\n\t\t\t\t\tint64_t subtract_result;\n\t\t\t\t\tbool overflow = Eidos_sub_overflow(first_operand, singleton_int, &subtract_result);\n\t\t\t\t\t\n\t\t\t\t\tif (overflow)\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): integer subtraction overflow with the binary '-' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\t\n\t\t\t\t\tint_result->set_int_no_check(subtract_result, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = int_result_SP;\n\t\t\t}\n\t\t\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): the '-' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have at least one float operand, so we are computing a float result\n\t\t\tif (first_child_count == second_child_count)\n\t\t\t{\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] - second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] - second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse // ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] - second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse if (first_child_count == 1)\n\t\t\t{\n\t\t\t\tdouble singleton_float = first_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\t\n\t\t\t\tif (second_child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(singleton_float - second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse\t// (second_child_type == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(singleton_float - second_child_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse if (second_child_count == 1)\n\t\t\t{\n\t\t\t\tdouble singleton_float = second_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] - singleton_float, value_index);\n\t\t\t\t}\n\t\t\t\telse\t// (first_child_type == EidosValueType::kValueFloat)\n\t\t\t\t{\n\t\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] - singleton_float, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = float_result_SP;\n\t\t\t}\n\t\t\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Minus): the '-' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Minus()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Mod(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Mod()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Mod\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mod): operand type \" << first_child_type << \" is not supported by the '%' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mod): operand type \" << second_child_type << \" is not supported by the '%' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = first_child_value->Count();\n\tint second_child_count = second_child_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint first_child_dimcount = first_child_value->DimensionCount();\n\tint second_child_dimcount = second_child_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\n\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mod): non-conformable array operands to the '%' operator.\" << EidosTerminate(operator_token);\n\t\n\tEidosValue_SP result_SP;\n\t\n\t// I've decided to make division perform float division always; wanting integer division is rare, and providing it as the default is error-prone.  If\n\t// people want integer division, a function has been provided, integerDiv(). This decision applies also to modulo, with function integerMod().\n\t\n\t// floating-point modulo by zero is safe; it will produce an NaN, following IEEE as implemented by C++\n\tif (first_child_count == second_child_count)\n\t{\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\telse // ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (first_child_count == 1)\n\t{\n\t\tdouble singleton_float = first_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(second_child_count);\n\t\t\n\t\tif (second_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(singleton_float, second_child_data[value_index]), value_index);\n\t\t}\n\t\telse\t// (second_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(singleton_float, second_child_data[value_index]), value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (second_child_count == 1)\n\t{\n\t\tdouble singleton_float = second_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], singleton_float), value_index);\n\t\t}\n\t\telse\t// (first_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(fmod(first_child_data[value_index], singleton_float), value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mod): the '%' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Mod()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Mult(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Mult()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Mult\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): operand type \" << first_child_type << \" is not supported by the '*' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): operand type \" << second_child_type << \" is not supported by the '*' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = first_child_value->Count();\n\tint second_child_count = second_child_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint first_child_dimcount = first_child_value->DimensionCount();\n\tint second_child_dimcount = second_child_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\n\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): non-conformable array operands to the '*' operator.\" << EidosTerminate(operator_token);\n\t\n\tEidosValue_SP result_SP;\n\t\n\tif (first_child_count == second_child_count)\n\t{\n\t\t// OK, we've got good operands; calculate the result.  If both operands are int, the result is int, otherwise float.\n\t\tif ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t//int_result->set_int_no_check(first_child_value->IntAtIndex_NOCAST(value_index, operator_token) * second_child_value->IntAtIndex_NOCAST(value_index, operator_token));\n\t\t\t\t\n\t\t\t\tint64_t first_operand = first_child_data[value_index];\n\t\t\t\tint64_t second_operand = second_child_data[value_index];\n\t\t\t\tint64_t multiply_result;\n\t\t\t\tbool overflow = Eidos_mul_overflow(first_operand, second_operand, &multiply_result);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): integer multiplication overflow with the '*' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(multiply_result, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] * second_child_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t{\n\t\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] * second_child_data[value_index], value_index);\n\t\t\t}\n\t\t\telse\t// ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] * second_child_data[value_index], value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t}\n\telse if ((first_child_count == 1) || (second_child_count == 1))\n\t{\n\t\tEidosValue_SP one_count_child;\n\t\tEidosValue_SP any_count_child;\n\t\tint any_count;\n\t\tEidosValueType any_type;\n\t\t\n\t\tif (first_child_count == 1)\n\t\t{\n\t\t\tone_count_child = std::move(first_child_value);\n\t\t\tany_count_child = std::move(second_child_value);\n\t\t\tany_count = second_child_count;\n\t\t\tany_type = second_child_type;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tone_count_child = std::move(second_child_value);\n\t\t\tany_count_child = std::move(first_child_value);\n\t\t\tany_count = first_child_count;\n\t\t\tany_type = first_child_type;\n\t\t}\n\t\t\n\t\t// OK, we've got good operands; calculate the result.  If both operands are int, the result is int, otherwise float.\n\t\tif ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst int64_t *any_count_data = any_count_child->IntData();\n\t\t\tint64_t singleton_int = one_count_child->IntAtIndex_NOCAST(0, operator_token);\n\t\t\tEidosValue_Int_SP int_result_SP = EidosValue_Int_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n\t\t\tEidosValue_Int *int_result = int_result_SP->resize_no_initialize(any_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < any_count; ++value_index)\n\t\t\t{\n\t\t\t\t// This is an overflow-safe version of:\n\t\t\t\t//int_result->set_int_no_check(any_count_child->IntAtIndex(value_index, operator_token) * singleton_int);\n\t\t\t\t\n\t\t\t\tint64_t first_operand = any_count_data[value_index];\n\t\t\t\tint64_t multiply_result;\n\t\t\t\tbool overflow = Eidos_mul_overflow(first_operand, singleton_int, &multiply_result);\n\t\t\t\t\n\t\t\t\tif (overflow)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): integer multiplication overflow with the '*' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tint_result->set_int_no_check(multiply_result, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = int_result_SP;\n\t\t}\n\t\telse if (any_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *any_count_data = any_count_child->IntData();\n\t\t\tdouble singleton_float = one_count_child->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(any_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < any_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(any_count_data[value_index] * singleton_float, value_index);\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t\telse\t// (any_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *any_count_data = any_count_child->FloatData();\n\t\t\tdouble singleton_float = one_count_child->NumericAtIndex_NOCAST(0, operator_token);\n\t\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(any_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < any_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(any_count_data[value_index] * singleton_float, value_index);\n\t\t\t\n\t\t\tresult_SP = float_result_SP;\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Mult): the '*' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Mult()\");\n\treturn result_SP;\n}\n\n#if defined(__clang__)\n__attribute__((no_sanitize(\"float-divide-by-zero\")))\n__attribute__((no_sanitize(\"integer-divide-by-zero\")))\n#endif\nEidosValue_SP EidosInterpreter::Evaluate_Div(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Div()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Div\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Div): operand type \" << first_child_type << \" is not supported by the '/' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Div): operand type \" << second_child_type << \" is not supported by the '/' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = first_child_value->Count();\n\tint second_child_count = second_child_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint first_child_dimcount = first_child_value->DimensionCount();\n\tint second_child_dimcount = second_child_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\n\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Div): non-conformable array operands to the '/' operator.\" << EidosTerminate(operator_token);\n\t\n\tEidosValue_SP result_SP;\n\t\n\t// I've decided to make division perform float division always; wanting integer division is rare, and providing it as the default is error-prone.  If\n\t// people want integer division, a function has been provided, integerDiv(). This decision applies also to modulo, with function integerMod().\n\n\t// floating-point division by zero is safe; it will produce an infinity, following IEEE as implemented by C++\n\tif (first_child_count == second_child_count)\n\t{\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / second_child_data[value_index], value_index);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / second_child_data[value_index], value_index);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / second_child_data[value_index], value_index);\n\t\t}\n\t\telse // ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / (double)second_child_data[value_index], value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (first_child_count == 1)\n\t{\n\t\tdouble singleton_float = first_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(second_child_count);\n\t\t\n\t\tif (second_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(singleton_float / second_child_data[value_index], value_index);\n\t\t}\n\t\telse\t// (second_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(singleton_float / second_child_data[value_index], value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (second_child_count == 1)\n\t{\n\t\tdouble singleton_float = second_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / singleton_float, value_index);\n\t\t}\n\t\telse\t// (first_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(first_child_data[value_index] / singleton_float, value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse\t// if ((first_child_count != second_child_count) && (first_child_count != 1) && (second_child_count != 1))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Div): the '/' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Div()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Conditional(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Conditional()\");\n\tEIDOS_ASSERT_CHILD_RANGE(\"EidosInterpreter::Evaluate_Conditional\", 3, 3);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\t\n\tEidosValue_SP result_SP;\n\t\n\tEidosASTNode *condition_node = p_node->children_[0];\n\tEidosValue_SP condition_result = FastEvaluateNode(condition_node);\n\t\n\tif (condition_result == gStaticEidosValue_LogicalT)\n\t{\n\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\tresult_SP = FastEvaluateNode(p_node->children_[1]);\n\t}\n\telse if (condition_result == gStaticEidosValue_LogicalF)\n\t{\n\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\tresult_SP = FastEvaluateNode(p_node->children_[2]);\n\t}\n\telse if (condition_result->Count() == 1)\n\t{\n\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\n\t\tif (condition_logical)\n\t\t\tresult_SP = FastEvaluateNode(p_node->children_[1]);\n\t\telse\n\t\t\tresult_SP = FastEvaluateNode(p_node->children_[2]);\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Conditional): condition for ternary conditional has size() != 1.\" << EidosTerminate(p_node->token_);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Conditional()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Exp(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Exp()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Exp\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Exp): operand type \" << first_child_type << \" is not supported by the '^' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((second_child_type != EidosValueType::kValueInt) && (second_child_type != EidosValueType::kValueFloat))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Exp): operand type \" << second_child_type << \" is not supported by the '^' operator.\" << EidosTerminate(operator_token);\n\t\n\tint first_child_count = first_child_value->Count();\n\tint second_child_count = second_child_value->Count();\n\t\n\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\tint first_child_dimcount = first_child_value->DimensionCount();\n\tint second_child_dimcount = second_child_value->DimensionCount();\n\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\n\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Exp): non-conformable array operands to the '^' operator.\" << EidosTerminate(operator_token);\n\t\n\t// Exponentiation always produces a float result; the user can cast back to integer if they really want\n\tEidosValue_SP result_SP;\n\t\n\tif (first_child_count == second_child_count)\n\t{\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\tdouble *float_result_data = float_result->data_mutable();\n\t\t\t\n\t\t\tEidos_SIMD::pow_float64(first_child_data, second_child_data, float_result_data, first_child_count);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(pow(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueFloat))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(pow(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\telse // ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(pow(first_child_data[value_index], second_child_data[value_index]), value_index);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (first_child_count == 1)\n\t{\n\t\tdouble singleton_float = first_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(second_child_count);\n\t\t\n\t\tif (second_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *second_child_data = second_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(pow(singleton_float, second_child_data[value_index]), value_index);\n\t\t}\n\t\telse\t// (second_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *second_child_data = second_child_value->FloatData();\n\t\t\tdouble *float_result_data = float_result->data_mutable();\n\t\t\t\n\t\t\tEidos_SIMD::pow_float64_scalar_base(singleton_float, second_child_data, float_result_data, second_child_count);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse if (second_child_count == 1)\n\t{\n\t\tdouble singleton_float = second_child_value->NumericAtIndex_NOCAST(0, operator_token);\n\t\tEidosValue_Float_SP float_result_SP = EidosValue_Float_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n\t\tEidosValue_Float *float_result = float_result_SP->resize_no_initialize(first_child_count);\n\t\t\n\t\tif (first_child_type == EidosValueType::kValueInt)\n\t\t{\n\t\t\tconst int64_t *first_child_data = first_child_value->IntData();\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\tfloat_result->set_float_no_check(pow(first_child_data[value_index], singleton_float), value_index);\n\t\t}\n\t\telse\t// (first_child_type == EidosValueType::kValueFloat)\n\t\t{\n\t\t\tconst double *first_child_data = first_child_value->FloatData();\n\t\t\tdouble *float_result_data = float_result->data_mutable();\n\t\t\t\n\t\t\tEidos_SIMD::pow_float64_scalar_exp(first_child_data, singleton_float, float_result_data, first_child_count);\n\t\t}\n\t\t\n\t\tresult_SP = float_result_SP;\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Exp): the '^' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t}\n\t\n\t// Copy dimensions from whichever operand we chose at the beginning\n\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Exp()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_And(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_And()\");\n\tEIDOS_ASSERT_CHILD_COUNT_GTEQ(\"EidosInterpreter::Evaluate_And\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\t\n\t// We try to avoid allocating a result object if we can.  If result==nullptr but result_count==1, logical_result contains the result so far.\n\tEidosValue_Logical_SP result_SP;\n\teidos_logical_t logical_result = false;\n\tint result_count = 0;\n\tbool first_child = true;\n\t\n\t// Dimensionality with & and | is different from the binary operators, since & and | can have any number of children.  Basically we want\n\t// that (1) a simple T or F can always be included, but never determines the dimensionality of the result, (2) if more than one matrix or\n\t// array is included, all such must be conformable, even singletons, (3) singleton matrices/arrays may be mixed with non-singleton vectors,\n\t// in which case the result is a non-singleton vector, *not* a matrix/array, and (4) in all other cases dimensionality is determined by any\n\t// matrix/array operand.  These rules are consistent with the binary operator rules, just extended to an arbitrary number of arguments.\n\t// To implement these rules, we keep track of two new pieces of state.  One, result_dim_source, keeps track of the value that will be used\n\t// as the source of the result's dimensionality; it is set to the first matrix/array argument seen, but if a non-singleton vector is seen\n\t// and result_dim_source is set to a singleton matrix/array, it gets upgraded to the non-singleton vector since that has priority.  Two,\n\t// first_array_operand forever keeps the first matrix/array operand seen, to check conformability against any later matrix/array operands.\n\t// Between these two mechanisms, I believe the intended rules are fully implemented.\n\tEidosValue_SP result_dim_source;\n\tEidosValue_SP first_array_operand;\n\t\n\tfor (EidosASTNode *child_node : p_node->children_)\n\t{\n\t\tEidosValue_SP child_result = FastEvaluateNode(child_node);\n\t\t\n\t\tif (child_result == gStaticEidosValue_LogicalT)\n\t\t{\n\t\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\tfirst_child = false;\n\t\t\t\tlogical_result = true;\n\t\t\t\tresult_count = 1;\n\t\t\t}\n\t\t\t// if we're not on the first child, doing an AND with T is a no-op; it does not even change the size of the result vector\n\t\t}\n\t\telse if (child_result == gStaticEidosValue_LogicalF)\n\t\t{\n\t\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\tfirst_child = false;\n\t\t\t\tlogical_result = false;\n\t\t\t\tresult_count = 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (result_SP)\n\t\t\t\t{\n\t\t\t\t\t// we have a result allocated, so alter the values in it\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\tresult->set_logical_no_check(false, value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we have no result allocated, so we must be using logical_result\n\t\t\t\t\tlogical_result = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Cases that the code above can't handle drop through to the more general case here\n\t\t\tEidosValueType child_type = child_result->Type();\n\t\t\t\n\t\t\tif ((child_type != EidosValueType::kValueLogical) && (child_type != EidosValueType::kValueString) && (child_type != EidosValueType::kValueInt) && (child_type != EidosValueType::kValueFloat))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_And): operand type \" << child_type << \" is not supported by the '&' operator.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tint child_count = child_result->Count();\n\t\t\tint child_dimcount = child_result->DimensionCount();\n\t\t\t\n\t\t\t// handle dimensionality issues first; see the comment at top regarding the policies we enforce here\n\t\t\tif (child_dimcount > 1)\n\t\t\t{\n\t\t\t\t// we are an array operand; if we're the first, track that, otherwise check conformability against the first\n\t\t\t\tif (!first_array_operand)\n\t\t\t\t\tfirst_array_operand = child_result;\n\t\t\t\telse if (!EidosValue::MatchingDimensions(first_array_operand.get(), child_result.get()))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_And): non-conformable array operands to the '&' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\t// if there is no dimensionality source yet, we qualify; otherwise, if we are a non-singleton array, and the current\n\t\t\t\t// dimensionality source is a (non-singleton) vector, we represent an upgrade; if we're a singleton, though, we don't\n\t\t\t\tif (!result_dim_source || ((child_count != 1) && (result_dim_source->DimensionCount() == 1)))\n\t\t\t\t\tresult_dim_source = child_result;\n\t\t\t}\n\t\t\telse if (child_count != 1)\n\t\t\t{\n\t\t\t\t// we are a non-singleton vector operand; no updating of first_array_operand and no conformability check,\n\t\t\t\t// but we could be the dimensionality source if there is none, or if it is currently a singleton array\n\t\t\t\tif (!result_dim_source || (result_dim_source->Count() == 1))\n\t\t\t\t\tresult_dim_source = child_result;\n\t\t\t}\n\t\t\t\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\t// if this is our first operand, we need to set up an initial result value from it\n\t\t\t\tfirst_child = false;\n\t\t\t\t\n\t\t\t\tif (child_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// if we have a singleton, avoid allocating a result yet, by using logical_result instead\n\t\t\t\t\tlogical_result = child_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\tresult_count = 1;\n\t\t\t\t}\n\t\t\t\telse if ((child_type == EidosValueType::kValueLogical) && (child_result->UseCount() == 1))\n\t\t\t\t{\n\t\t\t\t\t// child_result is a logical EidosValue owned only by us, so we can just take it over as our initial result\n\t\t\t\t\tresult_SP = static_pointer_cast<EidosValue_Logical>(child_result);\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// for other cases, we just clone child_result – but note that it may not be of type logical\n\t\t\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(child_count));\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t\t\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\tresult->set_logical_no_check(child_result->LogicalAtIndex_CAST(value_index, operator_token), value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// otherwise, we treat our current result as the left operand, and perform our operation with the right operand\n\t\t\t\tif ((result_count != child_count) && (result_count != 1) && (child_count != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_And): operands to the '&' operator are not compatible in size().\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tif (child_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// if child_logical is T, it has no effect on result; if it is F, it turns result to all F\n\t\t\t\t\teidos_logical_t child_logical = child_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\t\n\t\t\t\t\tif (!child_logical)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result_SP)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have a result allocated, so alter the values in it\n\t\t\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\t\t\tresult->set_logical_no_check(false, value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have no result allocated, so we must be using logical_result\n\t\t\t\t\t\t\tlogical_result = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (result_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// we had a one-length result vector, but now we need to upscale it to match child_result\n\t\t\t\t\teidos_logical_t result_logical;\n\t\t\t\t\t\n\t\t\t\t\tif (result_SP)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we have a result allocated; work with that\n\t\t\t\t\t\tresult_logical = result_SP->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// no result allocated, so we now need to upgrade to an allocated result\n\t\t\t\t\t\tresult_logical = logical_result;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(child_count));\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t\t\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tif (result_logical)\n\t\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\t\tresult->set_logical_no_check(child_result->LogicalAtIndex_CAST(value_index, operator_token), value_index);\n\t\t\t\t\telse\n\t\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\t\tresult->set_logical_no_check(false, value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// result and child_result are both != 1 length, so we match them one to one, and if child_result is F we turn result to F\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\tif (!child_result->LogicalAtIndex_CAST(value_index, operator_token))\n\t\t\t\t\t\t\tresult->set_logical_no_check(false, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (result_dim_source)\n\t{\n\t\t// if we avoided allocating a result, make a singleton now, because we need to apply dimensionality to it; this\n\t\t// occurs when matrix/array singletons were mixed into the operands and a non-singleton vector was not present\n\t\tif (!result_SP)\n\t\t{\n\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(1));\n\t\t\tresult_SP->set_logical_no_check(logical_result, 0);\n\t\t}\n\t\t\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if we avoided allocating a result, use a static logical value\n\t\tif (!result_SP)\n\t\t\tresult_SP = (logical_result ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_And()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Or(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Or()\");\n\tEIDOS_ASSERT_CHILD_COUNT_GTEQ(\"EidosInterpreter::Evaluate_Or\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\t\n\t// We try to avoid allocating a result object if we can.  If result==nullptr but result_count==1, logical_result contains the result so far.\n\tEidosValue_Logical_SP result_SP;\n\teidos_logical_t logical_result = false;\n\tint result_count = 0;\n\tbool first_child = true;\n\t\n\t// Dimensionality with & and | is different from the binary operators, since & and | can have any number of children.  Basically we want\n\t// that (1) a simple T or F can always be included, but never determines the dimensionality of the result, (2) if more than one matrix or\n\t// array is included, all such must be conformable, even singletons, (3) singleton matrices/arrays may be mixed with non-singleton vectors,\n\t// in which case the result is a non-singleton vector, *not* a matrix/array, and (4) in all other cases dimensionality is determined by any\n\t// matrix/array operand.  These rules are consistent with the binary operator rules, just extended to an arbitrary number of arguments.\n\t// To implement these rules, we keep track of two new pieces of state.  One, result_dim_source, keeps track of the value that will be used\n\t// as the source of the result's dimensionality; it is set to the first matrix/array argument seen, but if a non-singleton vector is seen\n\t// and result_dim_source is set to a singleton matrix/array, it gets upgraded to the non-singleton vector since that has priority.  Two,\n\t// first_array_operand forever keeps the first matrix/array operand seen, to check conformability against any later matrix/array operands.\n\t// Between these two mechanisms, I believe the intended rules are fully implemented.\n\tEidosValue_SP result_dim_source;\n\tEidosValue_SP first_array_operand;\n\t\n\tfor (EidosASTNode *child_node : p_node->children_)\n\t{\n\t\tEidosValue_SP child_result = FastEvaluateNode(child_node);\n\t\t\n\t\tif (child_result == gStaticEidosValue_LogicalT)\n\t\t{\n\t\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\tfirst_child = false;\n\t\t\t\tlogical_result = true;\n\t\t\t\tresult_count = 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (result_SP)\n\t\t\t\t{\n\t\t\t\t\t// we have a result allocated, so alter the values in it\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\tresult->set_logical_no_check(true, value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we have no result allocated, so we must be using logical_result\n\t\t\t\t\tlogical_result = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (child_result == gStaticEidosValue_LogicalF)\n\t\t{\n\t\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\tfirst_child = false;\n\t\t\t\tlogical_result = false;\n\t\t\t\tresult_count = 1;\n\t\t\t}\n\t\t\t// if we're not on the first child, doing an OR with F is a no-op; it does not even change the size of the result vector\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Cases that the code above can't handle drop through to the more general case here\n\t\t\tEidosValueType child_type = child_result->Type();\n\t\t\t\n\t\t\tif ((child_type != EidosValueType::kValueLogical) && (child_type != EidosValueType::kValueString) && (child_type != EidosValueType::kValueInt) && (child_type != EidosValueType::kValueFloat))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Or): operand type \" << child_type << \" is not supported by the '|' operator.\" << EidosTerminate(operator_token);\n\t\t\t\n\t\t\tint child_count = child_result->Count();\n\t\t\tint child_dimcount = child_result->DimensionCount();\n\t\t\t\n\t\t\t// handle dimensionality issues first; see the comment at top regarding the policies we enforce here\n\t\t\tif (child_dimcount > 1)\n\t\t\t{\n\t\t\t\t// we are an array operand; if we're the first, track that, otherwise check conformability against the first\n\t\t\t\tif (!first_array_operand)\n\t\t\t\t\tfirst_array_operand = child_result;\n\t\t\t\telse if (!EidosValue::MatchingDimensions(first_array_operand.get(), child_result.get()))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Or): non-conformable array operands to the '|' operator.\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\t// if there is no dimensionality source yet, we qualify; otherwise, if we are a non-singleton array, and the current\n\t\t\t\t// dimensionality source is a (non-singleton) vector, we represent an upgrade; if we're a singleton, though, we don't\n\t\t\t\tif (!result_dim_source || ((child_count != 1) && (result_dim_source->DimensionCount() == 1)))\n\t\t\t\t\tresult_dim_source = child_result;\n\t\t\t}\n\t\t\telse if (child_count != 1)\n\t\t\t{\n\t\t\t\t// we are a non-singleton vector operand; no updating of first_array_operand and no conformability check,\n\t\t\t\t// but we could be the dimensionality source if there is none, or if it is currently a singleton array\n\t\t\t\tif (!result_dim_source || (result_dim_source->Count() == 1))\n\t\t\t\t\tresult_dim_source = child_result;\n\t\t\t}\n\t\t\t\n\t\t\tif (first_child)\n\t\t\t{\n\t\t\t\t// if this is our first operand, we need to set up an initial result value from it\n\t\t\t\tfirst_child = false;\n\t\t\t\t\n\t\t\t\tif (child_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// if we have a singleton, avoid allocating a result yet, by using logical_result instead\n\t\t\t\t\tlogical_result = child_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\tresult_count = 1;\n\t\t\t\t}\n\t\t\t\telse if ((child_type == EidosValueType::kValueLogical) && (child_result->UseCount() == 1))\n\t\t\t\t{\n\t\t\t\t\t// child_result is a logical EidosValue owned only by us, so we can just take it over as our initial result\n\t\t\t\t\tresult_SP = static_pointer_cast<EidosValue_Logical>(child_result);\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// for other cases, we just clone child_result – but note that it may not be of type logical\n\t\t\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(child_count));\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t\t\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\tresult->set_logical_no_check(child_result->LogicalAtIndex_CAST(value_index, operator_token), value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// otherwise, we treat our current result as the left operand, and perform our operation with the right operand\n\t\t\t\tif ((result_count != child_count) && (result_count != 1) && (child_count != 1))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Or): operands to the '|' operator are not compatible in size().\" << EidosTerminate(operator_token);\n\t\t\t\t\n\t\t\t\tif (child_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// if child_logical is F, it has no effect on result; if it is T, it turns result to all T\n\t\t\t\t\teidos_logical_t child_logical = child_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\t\n\t\t\t\t\tif (child_logical)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result_SP)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have a result allocated, so alter the values in it\n\t\t\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\t\t\tresult->set_logical_no_check(true, value_index);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have no result allocated, so we must be using logical_result\n\t\t\t\t\t\t\tlogical_result = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (result_count == 1)\n\t\t\t\t{\n\t\t\t\t\t// we had a one-length result vector, but now we need to upscale it to match child_result\n\t\t\t\t\teidos_logical_t result_logical;\n\t\t\t\t\t\n\t\t\t\t\tif (result_SP)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we have a result allocated; work with that\n\t\t\t\t\t\tresult_logical = result_SP->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// no result allocated, so we now need to upgrade to an allocated result\n\t\t\t\t\t\tresult_logical = logical_result;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(child_count));\n\t\t\t\t\tresult_count = child_count;\n\t\t\t\t\t\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tif (result_logical)\n\t\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\t\tresult->set_logical_no_check(true, value_index);\n\t\t\t\t\telse\n\t\t\t\t\t\tfor (int value_index = 0; value_index < child_count; ++value_index)\n\t\t\t\t\t\t\tresult->set_logical_no_check(child_result->LogicalAtIndex_CAST(value_index, operator_token), value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// result and child_result are both != 1 length, so we match them one to one, and if child_result is T we turn result to T\n\t\t\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < result_count; ++value_index)\n\t\t\t\t\t\tif (child_result->LogicalAtIndex_CAST(value_index, operator_token))\n\t\t\t\t\t\t\tresult->set_logical_no_check(true, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (result_dim_source)\n\t{\n\t\t// if we avoided allocating a result, make a singleton now, because we need to apply dimensionality to it; this\n\t\t// occurs when matrix/array singletons were mixed into the operands and a non-singleton vector was not present\n\t\tif (!result_SP)\n\t\t{\n\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(1));\n\t\t\tresult_SP->set_logical_no_check(logical_result, 0);\n\t\t}\n\t\t\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if we avoided allocating a result, use a static logical value\n\t\tif (!result_SP)\n\t\t\tresult_SP = (logical_result ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Or()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Not(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Not()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Not\", 1);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_Logical_SP result_SP;\n\t\n\tif (first_child_value == gStaticEidosValue_LogicalT)\n\t{\n\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\tresult_SP = gStaticEidosValue_LogicalF;\n\t}\n\telse if (first_child_value == gStaticEidosValue_LogicalF)\n\t{\n\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\tresult_SP = gStaticEidosValue_LogicalT;\n\t}\n\telse\n\t{\n\t\tEidosValueType first_child_type = first_child_value->Type();\n\t\t\n\t\tif ((first_child_type != EidosValueType::kValueLogical) && (first_child_type != EidosValueType::kValueString) && (first_child_type != EidosValueType::kValueInt) && (first_child_type != EidosValueType::kValueFloat))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Not): operand type \" << first_child_type << \" is not supported by the '!' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tint first_child_count = first_child_value->Count();\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\t\n\t\tif ((first_child_count == 1) && (first_child_dimcount == 1))\n\t\t{\n\t\t\t// If we're generating a singleton non-array result, use cached static logical values\n\t\t\tresult_SP = (first_child_value->LogicalAtIndex_CAST(0, operator_token) ? gStaticEidosValue_LogicalF : gStaticEidosValue_LogicalT);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// for other cases, we just create the negation of first_child_value – but note that it may not be of type logical\n\t\t\tresult_SP = EidosValue_Logical_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical())->resize_no_initialize(first_child_count));\n\t\t\t\n\t\t\tEidosValue_Logical *result = result_SP.get();\n\t\t\t\n\t\t\tif (first_child_type == EidosValueType::kValueLogical)\n\t\t\t{\n\t\t\t\tconst eidos_logical_t *child_data = first_child_value->LogicalData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tresult->set_logical_no_check(!child_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if (first_child_type == EidosValueType::kValueInt)\n\t\t\t{\n\t\t\t\tconst int64_t *child_data = first_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tresult->set_logical_no_check(child_data[value_index] == 0, value_index);\n\t\t\t}\n\t\t\telse if (first_child_type == EidosValueType::kValueString)\n\t\t\t{\n\t\t\t\tconst std::string *child_vec = first_child_value->StringData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tresult->set_logical_no_check(child_vec[value_index].length() == 0, value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case; hit by type float, since we don't want to duplicate the NAN check here\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tresult->set_logical_no_check(!first_child_value->LogicalAtIndex_CAST(value_index, operator_token), value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP->CopyDimensionsFromValue(first_child_value.get());\n\t\t}\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Not()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Assign(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Assign()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Assign\", 2);\n\t\n#ifdef SLIMGUI\n\t// When running under SLiMgui, skip the compound assignment optimization if debug points are set\n\t// This makes compound assignments emit debug logs, while keeping the optimization for testing and most usage\n\tif (debug_points_ && debug_points_->set.size())\n\t\tgoto compoundAssignmentSkip;\n#endif\n\t\n\tif (p_node->cached_compound_assignment_)\n\t{\n\t\t// if _OptimizeAssignments() set this flag, this assignment is of the form \"x = x <operator> <number>\",\n\t\t// where x is a simple identifier and the operator is one of +-/%*^; we try to optimize that case\n\t\tEidosASTNode *lvalue_node = p_node->children_[0];\n\t\tbool is_const, is_local;\n\t\tEidosValue_SP lvalue_SP = global_symbols_->GetValueOrRaiseForASTNode_IsConstIsLocal(lvalue_node, &is_const, &is_local);\n\t\t\n\t\t// Check for a constant value.  If either the EidosValue or the table it comes from is constant, there is an error.\n\t\tif (is_const || lvalue_SP->IsConstant() || lvalue_SP->IsIteratorVariable())\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): identifier '\" << lvalue_node->token_->token_string_ << \"' cannot be redefined because it is a constant.\" << EidosTerminate(p_node->token_);\n\t\t\n\t\t// Check for a non-local value (global, or at any higher scope).  This is an assignment where the\n\t\t// rvalue resolves to a non-local variable, but the assignment needs to go into a new local value;\n\t\t// see https://github.com/MesserLab/SLiM/issues/430.  This is legal but confusing, and the code\n\t\t// here mishandles it, so we skip to the general case, which handles it correctly.\n\t\tif (!is_local)\n\t\t{\n\t\t\tp_node->cached_compound_assignment_ = false;\n\t\t\tgoto compoundAssignmentSkip;\n\t\t}\n\t\t\n\t\tEidosValue *lvalue = lvalue_SP.get();\n\t\tint lvalue_count = lvalue->Count();\n\t\t\n\t\t// somewhat unusually, we will now modify the lvalue in place, for speed; this is legal since we just got\n\t\t// it from the symbol table (we want to modify it in the symbol table, and others should not have a\n\t\t// reference to the object that they expect to be constant), but doing it right requires care given\n\t\t// different value subclasses, singletons, etc.\n\t\tif (lvalue_count > 0)\n\t\t{\n\t\t\tEidosValueType lvalue_type = lvalue->Type();\n\t\t\t\n\t\t\tif (lvalue_type == EidosValueType::kValueInt)\n\t\t\t{\n\t\t\t\tEidosASTNode *rvalue_node = p_node->children_[1];\t\t\t\t\t\t\t\t\t\t// the operator node\n\t\t\t\tEidosValue *cached_operand2 = rvalue_node->children_[1]->cached_literal_value_.get();\t// the numeric constant\n\t\t\t\t\n\t\t\t\t// if the lvalue is an integer, we require the rvalue to be an integer also; we don't handle mixed types here\n\t\t\t\tif (cached_operand2->Type() == EidosValueType::kValueInt)\n\t\t\t\t{\n\t\t\t\t\tEidosTokenType compound_operator = rvalue_node->token_->token_type_;\n\t\t\t\t\tint64_t operand2_value = cached_operand2->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\tint64_t *int_data = lvalue->IntData_Mutable();\n\t\t\t\t\t\n\t\t\t\t\tswitch (compound_operator)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosTokenType::kTokenPlus:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint64_t &int_vec_value = int_data[value_index];\n\t\t\t\t\t\t\t\tbool overflow = Eidos_add_overflow(int_vec_value, operand2_value, &int_vec_value);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (overflow)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): integer addition overflow with the binary '+' operator.\" << EidosTerminate(rvalue_node->token_);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase EidosTokenType::kTokenMinus:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint64_t &int_vec_value = int_data[value_index];\n\t\t\t\t\t\t\t\tbool overflow = Eidos_sub_overflow(int_vec_value, operand2_value, &int_vec_value);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (overflow)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): integer subtraction overflow with the binary '-' operator.\" << EidosTerminate(rvalue_node->token_);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase EidosTokenType::kTokenMult:\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint64_t &int_vec_value = int_data[value_index];\n\t\t\t\t\t\t\t\tbool overflow = Eidos_mul_overflow(int_vec_value, operand2_value, &int_vec_value);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (overflow)\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): integer multiplication overflow with the '*' operator.\" << EidosTerminate(rvalue_node->token_);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\t// div, mod, and exp always produce float, so we don't handle them for int; we can't change the type of x here\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (lvalue_type == EidosValueType::kValueFloat)\n\t\t\t{\n\t\t\t\t// if the lvalue is a float, we do not require the rvalue to be a float also; the integer will promote to float seamlessly\n\t\t\t\tEidosASTNode *rvalue_node = p_node->children_[1];\t\t\t\t\t\t\t\t\t\t// the operator node\n\t\t\t\tEidosValue *cached_operand2 = rvalue_node->children_[1]->cached_literal_value_.get();\t// the numeric constant\n\t\t\t\tEidosTokenType compound_operator = rvalue_node->token_->token_type_;\n\t\t\t\tdouble operand2_value = cached_operand2->NumericAtIndex_NOCAST(0, nullptr);\t\t\t\t// might be an int64_t and get converted\n\t\t\t\tdouble *float_data = lvalue->FloatData_Mutable();\n\t\t\t\t\n\t\t\t\tswitch (compound_operator)\n\t\t\t\t{\n\t\t\t\t\tcase EidosTokenType::kTokenPlus:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\tfloat_data[value_index] += operand2_value;\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosTokenType::kTokenMinus:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\tfloat_data[value_index] -= operand2_value;\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosTokenType::kTokenMult:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\tfloat_data[value_index] *= operand2_value;\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosTokenType::kTokenDiv:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t\tfloat_data[value_index] /= operand2_value;\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosTokenType::kTokenMod:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble &float_vec_value = float_data[value_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_vec_value = fmod(float_vec_value, operand2_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tcase EidosTokenType::kTokenExp:\n\t\t\t\t\t\tfor (int value_index = 0; value_index < lvalue_count; ++value_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdouble &float_vec_value = float_data[value_index];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfloat_vec_value = pow(float_vec_value, operand2_value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t\t\t\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// CODE COVERAGE: This is dead code\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tgoto compoundAssignmentSuccess;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// maybe we should flip our flag so we don't waste time trying this again for this node\n\t\tp_node->cached_compound_assignment_ = false;\n\t\t\n\t\t// and then we drop through to be handled normally by the standard assign operator code\n\t}\n\telse if (p_node->cached_append_assignment_)\n\t{\n\t\t// we have an assignment statement of the form x = c(x, y), where x is a simple identifier and y is any single expression node\n\t\t// as above, we will try to modify the value of x in place if we can, which should be safe in this context\n\t\tEidosASTNode *lvalue_node = p_node->children_[0];\n\t\tbool is_const, is_local;\t// is_const is needed by the API but unused; the const case gets caught by the code below\n\t\tEidosValue_SP lvalue_SP = global_symbols_->GetValueOrRaiseForASTNode_IsConstIsLocal(lvalue_node, &is_const, &is_local);\n\t\t\n\t\t// Check for an lvalue that is a loop iterator, which cannot be changed\n\t\tif (lvalue_SP->IsIteratorVariable())\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Assign): identifier '\" << lvalue_node->token_->token_string_ << \"' cannot be redefined because it is a constant.\" << EidosTerminate(p_node->token_);\n\t\t\n\t\t// Check for a non-local value (global, or at any higher scope).  This is an assignment where the\n\t\t// rvalue resolves to a non-local variable, but the assignment needs to go into a new local value;\n\t\t// see https://github.com/MesserLab/SLiM/issues/430.  This is legal but confusing, and the code\n\t\t// here mishandles it, so we skip to the general case, which handles it correctly.\n\t\tif (!is_local)\n\t\t{\n\t\t\tp_node->cached_append_assignment_ = false;\n\t\t\tgoto compoundAssignmentSkip;\n\t\t}\n\t\t\n\t\tEidosASTNode *call_node = p_node->children_[1];\n\t\tEidosASTNode *rvalue_node = call_node->children_[2];\t// \"c\" is [0], \"x\" is [1], \"y\" is [2]\n\t\tEidosValue_SP rvalue_SP = FastEvaluateNode(rvalue_node);\n\t\t\n\t\tEidosValue_SP result_SP = AppendEidosValues(lvalue_SP, rvalue_SP);\n\t\t\n\t\tif (!result_SP)\n\t\t{\n\t\t\t// a nullptr return means the append was successful, so we're done\n\t\t\tgoto compoundAssignmentSuccess;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// a non-nullptr return means that a new value had to be created for x = c(x,y), so we need to replace\n\t\t\t// the value of x with that new value; std::swap(lvalue_SP, result_SP) does not do it because lvalue_SP\n\t\t\t// is not the EidosValue_SP that is inside the symbol table, it just points to the same EidosValue!\n\t\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(p_node->token_);\n\t\t\t\n\t\t\tglobal_symbols_->SetValueForSymbolNoCopy(lvalue_node->cached_stringID_, std::move(result_SP));\n\t\t\t\n\t\t\tRestoreErrorPosition(error_pos_save);\n\t\t\tgoto compoundAssignmentSuccess;\n\t\t}\n\t}\n\t\n\t// we can drop through to here even if cached_compound_assignment_ or cached_append_assignment_ is set, if the code above bailed for some reason\ncompoundAssignmentSkip:\n\t\n\t{\n\t\tEidosToken *operator_token = p_node->token_;\n\t\tEidosASTNode *lvalue_node = p_node->children_[0];\n\t\tEidosValue_SP rvalue = FastEvaluateNode(p_node->children_[1]);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tEidosDebugPointIndent indenter;\n\t\t\n\t\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()))\n\t\t{\n\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\n\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG ASSIGN (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): \";\n\t\t\tif (lvalue_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\toutput_stream << lvalue_node->token_->token_string_ << \" = \";\n\t\t\tif (rvalue->Count() <= 1)\n\t\t\t{\n\t\t\t\trvalue->PrintStructure(output_stream, 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// print multiple values on a new line, with indent\n\t\t\t\trvalue->PrintStructure(output_stream, 0);\n\t\t\t\toutput_stream << std::endl;\n\t\t\t\tindenter.indent(2);\n\t\t\t\trvalue->Print(output_stream, EidosDebugPointIndent::Indent());\n\t\t\t\tindenter.outdent(2);\n\t\t\t}\n\t\t\toutput_stream << std::endl;\n\t\t}\n#endif\n\t\t\n\t\tEidosErrorPosition error_pos_save = PushErrorPositionFromToken(operator_token);\n\t\t\n\t\t_AssignRValueToLValue(std::move(rvalue), lvalue_node);\n\t\t\n\t\tRestoreErrorPosition(error_pos_save);\n\t}\n\t\ncompoundAssignmentSuccess:\n\t\n\t// by design, assignment does not yield a usable value; instead it produces void – this prevents the bug \"if (x = 3) ...\"\n\t// since the condition is void and will raise; the loss of legitimate uses of \"if (x = 3)\" seems a small price to pay\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Assign()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Assign_R(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Assign_R()\");\n\t\n\t// The <- operator is always illegal in Eidos, to safeguard against erroneous accidental usage for users coming from R.\n\t// It would parse as \"a < -b;\" and thus do nothing, silently, instead of assigning.  For this reason, we make it a\n\t// token and make the use of that token illegal.  We won't actually make it here, typically; use of this operator will\n\t// be a parse error caught in EidosScript::Match(), giving an error message similar to the one here.\n\tEidosToken *operator_token = p_node->token_;\n\t\n\tEIDOS_TERMINATION << R\"V0G0N(ERROR (EidosInterpreter::Evaluate_Assign_R): the R-style assignment operator <- is not legal in Eidos.  For assignment, use operator =, like \"a = b;\".  For comparison to a negative quantity, use spaces to fix the tokenization, like \"a < -b;\".)V0G0N\" << EidosTerminate(operator_token);\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Eq(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Eq()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Eq\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Eq): operand type void is not supported by the '==' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Eq): non-conformable array operands to the '==' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool equal;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: equal = (first_child_value->LogicalAtIndex_CAST(0, operator_token) == second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tequal = (first_child_value->IntAtIndex_CAST(0, operator_token) == second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tequal = (first_child_value->FloatAtIndex_CAST(0, operator_token) == second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tequal = (first_child_value->StringAtIndex_CAST(0, operator_token) == second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tequal = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) == second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: equal = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (equal ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\t// Direct float-to-float compare can be optimized through vector access\n\t\t\t\t\tconst double *float1_data = first_child_value->FloatData();\n\t\t\t\t\tconst double *float2_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(float1_data[value_index] == float2_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t\t{\n\t\t\t\t\t// Direct int-to-int compare can be optimized through vector access\n\t\t\t\t\tconst int64_t *int1_data = first_child_value->IntData();\n\t\t\t\t\tconst int64_t *int2_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(int1_data[value_index] == int2_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueObject) && (second_child_type == EidosValueType::kValueObject))\n\t\t\t\t{\n\t\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\t\tEidosObject * const *obj1_vec = first_child_value->ObjectData();\n\t\t\t\t\tEidosObject * const *obj2_vec = second_child_value->ObjectData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(obj1_vec[value_index] == obj2_vec[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// General case\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tbool equal;\n\t\t\t\t\t\t\n\t\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase EidosValueType::kValueLogical: equal = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) == second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tequal = (first_child_value->IntAtIndex_CAST(value_index, operator_token) == second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tequal = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) == second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueString:\tequal = (first_child_value->StringAtIndex_CAST(value_index, operator_token) == second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueObject:\tequal = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) == second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tdefault: equal = false; break;\t\t// never hit\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tlogical_result->set_logical_no_check(equal, value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tif ((promotion_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\t// Direct float-to-float compare can be optimized through vector access; note the singleton might get promoted to float\n\t\t\t\tdouble float1 = first_child_value->FloatAtIndex_CAST(0, operator_token);\n\t\t\t\tconst double *float_data = second_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(float1 == float_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t{\n\t\t\t\t// Direct int-to-int compare can be optimized through vector access; note the singleton might get promoted to int\n\t\t\t\tint64_t int1 = first_child_value->IntAtIndex_CAST(0, operator_token);\n\t\t\t\tconst int64_t *int_data = second_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(int1 == int_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueObject) && (second_child_type == EidosValueType::kValueObject))\n\t\t\t{\n\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\tEidosObject *obj1 = first_child_value->ObjectElementAtIndex_CAST(0, operator_token);\n\t\t\t\tEidosObject * const *obj_vec = second_child_value->ObjectData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(obj1 == obj_vec[value_index], value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool equal;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: equal = (first_child_value->LogicalAtIndex_CAST(0, operator_token) == second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tequal = (first_child_value->IntAtIndex_CAST(0, operator_token) == second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tequal = (first_child_value->FloatAtIndex_CAST(0, operator_token) == second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tequal = (first_child_value->StringAtIndex_CAST(0, operator_token) == second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tequal = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) == second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: equal = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(equal, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tif ((promotion_type == EidosValueType::kValueFloat) && (first_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\t// Direct float-to-float compare can be optimized through vector access; note the singleton might get promoted to float\n\t\t\t\tdouble float2 = second_child_value->FloatAtIndex_CAST(0, operator_token);\n\t\t\t\tconst double *float_data = first_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(float_data[value_index] == float2, value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueInt) && (first_child_type == EidosValueType::kValueInt))\n\t\t\t{\n\t\t\t\t// Direct int-to-int compare can be optimized through vector access; note the singleton might get promoted to int\n\t\t\t\tint64_t int2 = second_child_value->IntAtIndex_CAST(0, operator_token);\n\t\t\t\tconst int64_t *int_data = first_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(int_data[value_index] == int2, value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueObject) && (first_child_type == EidosValueType::kValueObject))\n\t\t\t{\n\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\tEidosObject *obj2 = second_child_value->ObjectElementAtIndex_CAST(0, operator_token);\n\t\t\t\tEidosObject * const *obj_vec = first_child_value->ObjectData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(obj_vec[value_index] == obj2, value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool equal;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: equal = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) == second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tequal = (first_child_value->IntAtIndex_CAST(value_index, operator_token) == second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tequal = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) == second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tequal = (first_child_value->StringAtIndex_CAST(value_index, operator_token) == second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tequal = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) == second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tdefault: equal = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(equal, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Eq): the '==' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Eq): testing NULL with the '==' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Eq()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Lt(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Lt()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Lt\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Lt): operand type void is not supported by the '<' operator.\" << EidosTerminate(operator_token);\n\tif ((first_child_type == EidosValueType::kValueObject) || (second_child_type == EidosValueType::kValueObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Lt): the '<' operator cannot be used with type object.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Lt): non-conformable array operands to the '<' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool lt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lt = (first_child_value->LogicalAtIndex_CAST(0, operator_token) < second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlt = (first_child_value->IntAtIndex_CAST(0, operator_token) < second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlt = (first_child_value->FloatAtIndex_CAST(0, operator_token) < second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlt = (first_child_value->StringAtIndex_CAST(0, operator_token) < second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlt = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) < second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: lt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (lt ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool lt;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: lt = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) < second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlt = (first_child_value->IntAtIndex_CAST(value_index, operator_token) < second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tlt = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) < second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tlt = (first_child_value->StringAtIndex_CAST(value_index, operator_token) < second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tlt = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) < second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: lt = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(lt, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool lt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lt = (first_child_value->LogicalAtIndex_CAST(0, operator_token) < second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlt = (first_child_value->IntAtIndex_CAST(0, operator_token) < second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlt = (first_child_value->FloatAtIndex_CAST(0, operator_token) < second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlt = (first_child_value->StringAtIndex_CAST(0, operator_token) < second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlt = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) < second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tdefault: lt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(lt, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool lt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lt = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) < second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlt = (first_child_value->IntAtIndex_CAST(value_index, operator_token) < second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlt = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) < second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlt = (first_child_value->StringAtIndex_CAST(value_index, operator_token) < second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlt = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) < second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: lt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(lt, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Lt): the '<' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if either operand is NULL (including if both are), it is an error\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Lt): testing NULL with the '<' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Lt()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_LtEq(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_LtEq()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_LtEq\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_LtEq): operand type void is not supported by the '<=' operator.\" << EidosTerminate(operator_token);\n\tif ((first_child_type == EidosValueType::kValueObject) || (second_child_type == EidosValueType::kValueObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_LtEq): the '<=' operator cannot be used with type object.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_LtEq): non-conformable array operands to the '<=' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool lteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lteq = (first_child_value->LogicalAtIndex_CAST(0, operator_token) <= second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlteq = (first_child_value->IntAtIndex_CAST(0, operator_token) <= second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlteq = (first_child_value->FloatAtIndex_CAST(0, operator_token) <= second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlteq = (first_child_value->StringAtIndex_CAST(0, operator_token) <= second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlteq = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) <= second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: lteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (lteq ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool lteq;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: lteq = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) <= second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlteq = (first_child_value->IntAtIndex_CAST(value_index, operator_token) <= second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tlteq = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) <= second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tlteq = (first_child_value->StringAtIndex_CAST(value_index, operator_token) <= second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tlteq = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) <= second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: lteq = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(lteq, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool lteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lteq = (first_child_value->LogicalAtIndex_CAST(0, operator_token) <= second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlteq = (first_child_value->IntAtIndex_CAST(0, operator_token) <= second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlteq = (first_child_value->FloatAtIndex_CAST(0, operator_token) <= second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlteq = (first_child_value->StringAtIndex_CAST(0, operator_token) <= second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlteq = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) <= second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tdefault: lteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(lteq, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool lteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: lteq = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) <= second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tlteq = (first_child_value->IntAtIndex_CAST(value_index, operator_token) <= second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tlteq = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) <= second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tlteq = (first_child_value->StringAtIndex_CAST(value_index, operator_token) <= second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tlteq = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) <= second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: lteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(lteq, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_LtEq): the '<=' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if either operand is NULL (including if both are), it is an error\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_LtEq): testing NULL with the '<=' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_LtEq()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Gt(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Gt()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Gt\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Gt): operand type void is not supported by the '>' operator.\" << EidosTerminate(operator_token);\n\tif ((first_child_type == EidosValueType::kValueObject) || (second_child_type == EidosValueType::kValueObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Gt): the '>' operator cannot be used with type object.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Gt): non-conformable array operands to the '>' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool gt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gt = (first_child_value->LogicalAtIndex_CAST(0, operator_token) > second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgt = (first_child_value->IntAtIndex_CAST(0, operator_token) > second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgt = (first_child_value->FloatAtIndex_CAST(0, operator_token) > second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgt = (first_child_value->StringAtIndex_CAST(0, operator_token) > second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgt = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) > second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: gt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (gt ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool gt;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: gt = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) > second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgt = (first_child_value->IntAtIndex_CAST(value_index, operator_token) > second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tgt = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) > second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tgt = (first_child_value->StringAtIndex_CAST(value_index, operator_token) > second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tgt = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) > second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: gt = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(gt, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool gt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gt = (first_child_value->LogicalAtIndex_CAST(0, operator_token) > second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgt = (first_child_value->IntAtIndex_CAST(0, operator_token) > second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgt = (first_child_value->FloatAtIndex_CAST(0, operator_token) > second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgt = (first_child_value->StringAtIndex_CAST(0, operator_token) > second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgt = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) > second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tdefault: gt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(gt, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool gt;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gt = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) > second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgt = (first_child_value->IntAtIndex_CAST(value_index, operator_token) > second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgt = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) > second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgt = (first_child_value->StringAtIndex_CAST(value_index, operator_token) > second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgt = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) > second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: gt = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(gt, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Gt): the '>' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if either operand is NULL (including if both are), it is an error\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Gt): testing NULL with the '>' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Gt()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_GtEq(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_GtEq()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_GtEq\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_GtEq): operand type void is not supported by the '>=' operator.\" << EidosTerminate(operator_token);\n\tif ((first_child_type == EidosValueType::kValueObject) || (second_child_type == EidosValueType::kValueObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_GtEq): the '>=' operator cannot be used with type object.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_GtEq): non-conformable array operands to the '>=' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool gteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gteq = (first_child_value->LogicalAtIndex_CAST(0, operator_token) >= second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgteq = (first_child_value->IntAtIndex_CAST(0, operator_token) >= second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgteq = (first_child_value->FloatAtIndex_CAST(0, operator_token) >= second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgteq = (first_child_value->StringAtIndex_CAST(0, operator_token) >= second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgteq = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) >= second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: gteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (gteq ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool gteq;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: gteq = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) >= second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgteq = (first_child_value->IntAtIndex_CAST(value_index, operator_token) >= second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tgteq = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) >= second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tgteq = (first_child_value->StringAtIndex_CAST(value_index, operator_token) >= second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tgteq = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) >= second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: gteq = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(gteq, value_index);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool gteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gteq = (first_child_value->LogicalAtIndex_CAST(0, operator_token) >= second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgteq = (first_child_value->IntAtIndex_CAST(0, operator_token) >= second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgteq = (first_child_value->FloatAtIndex_CAST(0, operator_token) >= second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgteq = (first_child_value->StringAtIndex_CAST(0, operator_token) >= second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgteq = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) >= second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\tdefault: gteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(gteq, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t{\n\t\t\t\tbool gteq;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: gteq = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) >= second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tgteq = (first_child_value->IntAtIndex_CAST(value_index, operator_token) >= second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tgteq = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) >= second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tgteq = (first_child_value->StringAtIndex_CAST(value_index, operator_token) >= second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tgteq = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) >= second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: gteq = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogical_result->set_logical_no_check(gteq, value_index);\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_GtEq): the '>=' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if either operand is NULL (including if both are), it is an error\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_GtEq): testing NULL with the '>=' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_GtEq()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_NotEq(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_NotEq()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_NotEq\", 2);\n\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_Logical_SP result_SP;\n\t\n\tEidosValue_SP first_child_value = FastEvaluateNode(p_node->children_[0]);\n\tEidosValue_SP second_child_value = FastEvaluateNode(p_node->children_[1]);\n\t\n\tEidosValueType first_child_type = first_child_value->Type();\n\tEidosValueType second_child_type = second_child_value->Type();\n\t\n\tif ((first_child_type == EidosValueType::kValueVOID) || (second_child_type == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_NotEq): operand type void is not supported by the '!=' operator.\" << EidosTerminate(operator_token);\n\t\n\tif ((first_child_type != EidosValueType::kValueNULL) && (second_child_type != EidosValueType::kValueNULL))\n\t{\n\t\t// both operands are non-NULL, so we're doing a real comparison\n\t\tint first_child_count = first_child_value->Count();\n\t\tint second_child_count = second_child_value->Count();\n\t\tEidosValueType promotion_type = EidosTypeForPromotion(first_child_type, second_child_type, operator_token);\n\t\t\n\t\t// matrices/arrays must be conformable, and we need to decide here which operand's dimensionality will be used for the result\n\t\tint first_child_dimcount = first_child_value->DimensionCount();\n\t\tint second_child_dimcount = second_child_value->DimensionCount();\n\t\tEidosValue_SP result_dim_source(EidosValue::BinaryOperationDimensionSource(first_child_value.get(), second_child_value.get()));\n\t\t\n\t\tif ((first_child_dimcount > 1) && (second_child_dimcount > 1) && !EidosValue::MatchingDimensions(first_child_value.get(), second_child_value.get()))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_NotEq): non-conformable array operands to the '!=' operator.\" << EidosTerminate(operator_token);\n\t\t\n\t\tif (first_child_count == second_child_count)\n\t\t{\n\t\t\tif ((first_child_count == 1) && (!result_dim_source))\n\t\t\t{\n\t\t\t\t// special-case the 1-to-1 comparison to return a statically allocated logical value, for speed\n\t\t\t\tbool notequal;\n\t\t\t\t\n\t\t\t\tswitch (promotion_type)\n\t\t\t\t{\n\t\t\t\t\tcase EidosValueType::kValueLogical: notequal = (first_child_value->LogicalAtIndex_CAST(0, operator_token) != second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueInt:\t\tnotequal = (first_child_value->IntAtIndex_CAST(0, operator_token) != second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueFloat:\tnotequal = (first_child_value->FloatAtIndex_CAST(0, operator_token) != second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueString:\tnotequal = (first_child_value->StringAtIndex_CAST(0, operator_token) != second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tcase EidosValueType::kValueObject:\tnotequal = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) != second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\tdefault: notequal = false; break;\t\t// never hit\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn (notequal ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\t\n\t\t\t\tif ((first_child_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t\t{\n\t\t\t\t\t// Direct float-to-float compare can be optimized through vector access\n\t\t\t\t\tconst double *float1_data = first_child_value->FloatData();\n\t\t\t\t\tconst double *float2_data = second_child_value->FloatData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(float1_data[value_index] != float2_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t\t{\n\t\t\t\t\t// Direct int-to-int compare can be optimized through vector access\n\t\t\t\t\tconst int64_t *int1_data = first_child_value->IntData();\n\t\t\t\t\tconst int64_t *int2_data = second_child_value->IntData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(int1_data[value_index] != int2_data[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse if ((first_child_type == EidosValueType::kValueObject) && (second_child_type == EidosValueType::kValueObject))\n\t\t\t\t{\n\t\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\t\tEidosObject * const *obj1_vec = first_child_value->ObjectData();\n\t\t\t\t\tEidosObject * const *obj2_vec = second_child_value->ObjectData();\n\t\t\t\t\t\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t\tlogical_result->set_logical_no_check(obj1_vec[value_index] != obj2_vec[value_index], value_index);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// General case\n\t\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tbool notequal;\n\t\t\t\t\t\t\n\t\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase EidosValueType::kValueLogical: notequal = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) != second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tnotequal = (first_child_value->IntAtIndex_CAST(value_index, operator_token) != second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tnotequal = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) != second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueString:\tnotequal = (first_child_value->StringAtIndex_CAST(value_index, operator_token) != second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueObject:\tnotequal = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) != second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\t\tdefault: notequal = false; break;\t\t// never hit\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tlogical_result->set_logical_no_check(notequal, value_index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t\t}\n\t\t}\n\t\telse if (first_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(second_child_count);\n\t\t\t\n\t\t\tif ((promotion_type == EidosValueType::kValueFloat) && (second_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\t// Direct float-to-float compare can be optimized through vector access; note the singleton might get promoted to float\n\t\t\t\tdouble float1 = first_child_value->FloatAtIndex_CAST(0, operator_token);\n\t\t\t\tconst double *float_data = second_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(float1 != float_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueInt) && (second_child_type == EidosValueType::kValueInt))\n\t\t\t{\n\t\t\t\t// Direct int-to-int compare can be optimized through vector access; note the singleton might get promoted to int\n\t\t\t\tint64_t int1 = first_child_value->IntAtIndex_CAST(0, operator_token);\n\t\t\t\tconst int64_t *int_data = second_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(int1 != int_data[value_index], value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueObject) && (second_child_type == EidosValueType::kValueObject))\n\t\t\t{\n\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\tEidosObject *obj1 = first_child_value->ObjectElementAtIndex_CAST(0, operator_token);\n\t\t\t\tEidosObject * const *obj_vec = second_child_value->ObjectData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(obj1 != obj_vec[value_index], value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case\n\t\t\t\tfor (int value_index = 0; value_index < second_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool notequal;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: notequal = (first_child_value->LogicalAtIndex_CAST(0, operator_token) != second_child_value->LogicalAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tnotequal = (first_child_value->IntAtIndex_CAST(0, operator_token) != second_child_value->IntAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tnotequal = (first_child_value->FloatAtIndex_CAST(0, operator_token) != second_child_value->FloatAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tnotequal = (first_child_value->StringAtIndex_CAST(0, operator_token) != second_child_value->StringAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tnotequal = (first_child_value->ObjectElementAtIndex_CAST(0, operator_token) != second_child_value->ObjectElementAtIndex_CAST(value_index, operator_token)); break;\n\t\t\t\t\t\tdefault: notequal = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(notequal, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse if (second_child_count == 1)\n\t\t{\n\t\t\tEidosValue_Logical_SP logical_result_SP = EidosValue_Logical_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n\t\t\tEidosValue_Logical *logical_result = logical_result_SP->resize_no_initialize(first_child_count);\n\t\t\t\n\t\t\tif ((promotion_type == EidosValueType::kValueFloat) && (first_child_type == EidosValueType::kValueFloat))\n\t\t\t{\n\t\t\t\t// Direct float-to-float compare can be optimized through vector access; note the singleton might get promoted to float\n\t\t\t\tdouble float2 = second_child_value->FloatAtIndex_CAST(0, operator_token);\n\t\t\t\tconst double *float_data = first_child_value->FloatData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(float_data[value_index] != float2, value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueInt) && (first_child_type == EidosValueType::kValueInt))\n\t\t\t{\n\t\t\t\t// Direct int-to-int compare can be optimized through vector access; note the singleton might get promoted to int\n\t\t\t\tint64_t int2 = second_child_value->IntAtIndex_CAST(0, operator_token);\n\t\t\t\tconst int64_t *int_data = first_child_value->IntData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(int_data[value_index] != int2, value_index);\n\t\t\t}\n\t\t\telse if ((promotion_type == EidosValueType::kValueObject) && (first_child_type == EidosValueType::kValueObject))\n\t\t\t{\n\t\t\t\t// Direct object-to-object compare can be optimized through vector access\n\t\t\t\tEidosObject *obj2 = second_child_value->ObjectElementAtIndex_CAST(0, operator_token);\n\t\t\t\tEidosObject * const *obj_vec = first_child_value->ObjectData();\n\t\t\t\t\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t\tlogical_result->set_logical_no_check(obj_vec[value_index] != obj2, value_index);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// General case\n\t\t\t\tfor (int value_index = 0; value_index < first_child_count; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tbool notequal;\n\t\t\t\t\t\n\t\t\t\t\tswitch (promotion_type)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase EidosValueType::kValueLogical: notequal = (first_child_value->LogicalAtIndex_CAST(value_index, operator_token) != second_child_value->LogicalAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\tnotequal = (first_child_value->IntAtIndex_CAST(value_index, operator_token) != second_child_value->IntAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueFloat:\tnotequal = (first_child_value->FloatAtIndex_CAST(value_index, operator_token) != second_child_value->FloatAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueString:\tnotequal = (first_child_value->StringAtIndex_CAST(value_index, operator_token) != second_child_value->StringAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tcase EidosValueType::kValueObject:\tnotequal = (first_child_value->ObjectElementAtIndex_CAST(value_index, operator_token) != second_child_value->ObjectElementAtIndex_CAST(0, operator_token)); break;\n\t\t\t\t\t\tdefault: notequal = false; break;\t\t// never hit\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tlogical_result->set_logical_no_check(notequal, value_index);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP = std::move(logical_result_SP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_NotEq): the '!=' operator requires that either (1) both operands have the same size(), or (2) one operand has size() == 1.\" << EidosTerminate(operator_token);\n\t\t}\n\t\t\n\t\t// Copy dimensions from whichever operand we chose at the beginning\n\t\tresult_SP->CopyDimensionsFromValue(result_dim_source.get());\n\t}\n\telse\n\t{\n\t\t// if either operand is NULL (including if both are), it is an error\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_NotEq): testing NULL with the '!=' operator is an error; use isNULL().\" << EidosTerminate(operator_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_NotEq()\");\n\treturn result_SP;\n}\n\n// A utility static method for getting an int for a string outside of a EidosInterpreter session\nint64_t EidosInterpreter::NonnegativeIntegerForString(const std::string &p_number_string, const EidosToken *p_blame_token)\n{\n\t// This needs to use the same criteria as NumericValueForString() below; it raises if the number is a float.\n\t// BCH 23 Jan. 2017: actually, this is *slightly* different from NumericValueForString(), because this\n\t// function will only parse/return non-negative ints; it does not allow a leading minus sign.  I'm changing\n\t// the name of this function to reflect this fact, since it is the expected/desired behavior for this function.\n\tconst char *c_str = p_number_string.c_str();\n\tchar *last_used_char = nullptr;\n\t\n\terrno = 0;\n\t\n\tif ((p_number_string.find('.') != std::string::npos) || (p_number_string.find('-') != std::string::npos))\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NonnegativeIntegerForString): '\" << p_number_string << \"' could not be represented as an integer (decimal or negative exponent).\" << EidosTerminate(p_blame_token);\n\t\treturn 0;\n\t}\n\telse if ((p_number_string.find('e') != std::string::npos) || (p_number_string.find('E') != std::string::npos))\t// has an exponent\n\t{\n\t\tdouble converted_value = strtod(c_str, &last_used_char);\n\t\t\n\t\tif (errno || (last_used_char == c_str))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NonnegativeIntegerForString): '\" << p_number_string << \"' could not be represented as an integer (strtod conversion error).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\t// nwellnhof on stackoverflow points out that the >= here is correct even though it looks wrong, because reasons...\n\t\tif ((converted_value < (double)INT64_MIN) || (converted_value >= (double)INT64_MAX))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NonnegativeIntegerForString): '\" << p_number_string << \"' could not be represented as an integer (out of range).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\treturn static_cast<int64_t>(converted_value);\n\t}\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// plain integer\n\t{\n\t\tint64_t converted_value = strtoll(c_str, &last_used_char, 10);\n\t\t\n\t\tif (errno || (last_used_char == c_str))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NonnegativeIntegerForString): '\" << p_number_string << \"' could not be represented as an integer (strtoll conversion error).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\treturn converted_value;\n\t}\n}\n\n// A utility static method for getting a double for a string outside of a EidosInterpreter session\ndouble EidosInterpreter::FloatForString(const std::string &p_number_string, const EidosToken *p_blame_token)\n{\n\t// This needs to use the same criteria as NumericValueForString() below; it raises if the number is a float.\n\tconst char *c_str = p_number_string.c_str();\n\tchar *last_used_char = nullptr;\n\t\n\terrno = 0;\n\t\n\tdouble converted_value = strtod(c_str, &last_used_char);\n\t\n\tif (errno || (last_used_char == c_str))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::FloatForString): '\" << p_number_string << \"' could not be represented as a float (strtod conversion error).\" << EidosTerminate(p_blame_token);\n\t\n\treturn converted_value;\n}\n\n// A utility static method for getting a numeric EidosValue* for a string outside of a EidosInterpreter session\nEidosValue_SP EidosInterpreter::NumericValueForString(const std::string &p_number_string, const EidosToken *p_blame_token)\n{\n\tconst char *c_str = p_number_string.c_str();\n\tchar *last_used_char = nullptr;\n\t\n\terrno = 0;\n\t\n\t// At this point, we have to decide whether to instantiate an int or a float.  If it has a decimal point or\n\t// a non-leading minus sign (which would be in the exponent), we'll make a float.  Otherwise, we'll make an int.\n\t// This might need revision in future; 1.2e3 could be an int, for example.  However, it is an ambiguity in\n\t// the syntax that will never be terribly comfortable; it's the price we pay for wanting ints to be\n\t// expressable using scientific notation.\n\tif ((p_number_string.find('.') != std::string::npos) || (p_number_string.find('-', 1) != std::string::npos))\t\t\t// requires a float\n\t{\n\t\tdouble converted_value = strtod(c_str, &last_used_char);\n\t\t\n\t\tif (errno || (last_used_char == c_str))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NumericValueForString): '\" << p_number_string << \"' could not be represented as a float (strtod conversion error).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(converted_value));\n\t}\n\telse if ((p_number_string.find('e') != std::string::npos) || (p_number_string.find('E') != std::string::npos))\t\t// has an exponent\n\t{\n\t\tdouble converted_value = strtod(c_str, &last_used_char);\n\t\t\n\t\tif (errno || (last_used_char == c_str))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NumericValueForString): '\" << p_number_string << \"' could not be represented as an integer (strtod conversion error).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\t// nwellnhof on stackoverflow points out that the >= here is correct even though it looks wrong, because reasons...\n\t\tif ((converted_value < (double)INT64_MIN) || (converted_value >= (double)INT64_MAX))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NumericValueForString): '\" << p_number_string << \"' could not be represented as an integer (out of range).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(static_cast<int64_t>(converted_value)));\n\t}\n\telse\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// plain integer\n\t{\n\t\tint64_t converted_value = strtoll(c_str, &last_used_char, 10);\n\t\t\n\t\tif (errno || (last_used_char == c_str))\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::NumericValueForString): '\" << p_number_string << \"' could not be represented as an integer (strtoll conversion error).\" << EidosTerminate(p_blame_token);\n\t\t\n\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(converted_value));\n\t}\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Number(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Number()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Number\", 0);\n\t\n\t// use a cached value from EidosASTNode::_OptimizeConstants() if present; this should always be hit now!\n\tEidosValue_SP result_SP = p_node->cached_literal_value_;\n\t\n\tif (!result_SP)\n\t{\n\t\t// CODE COVERAGE: This is dead code\n\t\tEidosToken *string_token = p_node->token_;\n\t\t\n\t\tresult_SP = EidosInterpreter::NumericValueForString(string_token->token_string_, string_token);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Number()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_String(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_String()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_String\", 0);\n\t\n\t// use a cached value from EidosASTNode::_OptimizeConstants() if present; this should always be hit now!\n\tEidosValue_SP result_SP = p_node->cached_literal_value_;\n\t\n\tif (!result_SP)\n\t{\n\t\t// CODE COVERAGE: This is dead code\n\t\tresult_SP = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(p_node->token_->token_string_));\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_String()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Identifier(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Identifier()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Identifier\", 0);\n\t\n\t// use a cached value from EidosASTNode::_OptimizeConstants() if present\n\tEidosValue_SP result_SP = p_node->cached_literal_value_;\n\t\n\tif (!result_SP)\n\t{\n\t\tif (use_custom_undefined_identifier_raise_)\n\t\t{\n\t\t\t// This branch raises a special exception if the identifier is undefined in the symbol table.\n\t\t\t// This facility is used by Community::_EvaluateTickRangeNode() for tolerant evaluation.\n\t\t\tresult_SP = global_symbols_->GetValueOrRaiseForASTNode_SpecialRaise(p_node);\t// raises if undefined\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult_SP = global_symbols_->GetValueOrRaiseForASTNode(p_node);\t// raises if undefined\n\t\t}\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Identifier()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_If(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_If()\");\n\tEIDOS_ASSERT_CHILD_RANGE(\"EidosInterpreter::Evaluate_If\", 2, 3);\n\n\tEidosToken *operator_token = p_node->token_;\n\tauto children_size = p_node->children_.size();\n\t\n\tEidosValue_SP result_SP;\n\t\n\tEidosASTNode *condition_node = p_node->children_[0];\n\tEidosValue_SP condition_result = FastEvaluateNode(condition_node);\n\t\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tEidosDebugPointIndent indenter;\n\t\n\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()) &&\n\t\t(condition_result->Count() == 1))\n\t{\n\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\n\t\t// the above might raise, but if it does, it will be the same error as produced below\n\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG IF (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): condition == \" <<\n\t\t\t(condition_logical ? \"T\" : \"F\") << std::endl;\n\t\tindenter.indent();\n\t}\n#endif\n\t\n\tif (condition_result == gStaticEidosValue_LogicalT)\n\t{\n\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\tEidosASTNode *true_node = p_node->children_[1];\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\tSLIM_PROFILE_BLOCK_START_CONDITION(true_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\n\t\tresult_SP = FastEvaluateNode(true_node);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END_CONDITION(true_node->profile_total_);\n#endif\n\t}\n\telse if (condition_result == gStaticEidosValue_LogicalF)\n\t{\n\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\tif (children_size == 3)\t\t// has an 'else' node\n\t\t{\n\t\t\tEidosASTNode *false_node = p_node->children_[2];\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\t\tSLIM_PROFILE_BLOCK_START_CONDITION(false_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\t\n\t\t\tresult_SP = FastEvaluateNode(false_node);\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tSLIM_PROFILE_BLOCK_END_CONDITION(false_node->profile_total_);\n#endif\n\t\t}\n\t\telse\t\t\t\t\t\t\t\t// no 'else' node, so the result is void\n\t\t{\n\t\t\tresult_SP = gStaticEidosValueVOID;\n\t\t}\n\t}\n\telse if (condition_result->Count() == 1)\n\t{\n\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\n\t\tif (condition_logical)\n\t\t{\n\t\t\tEidosASTNode *true_node = p_node->children_[1];\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\t\tSLIM_PROFILE_BLOCK_START_CONDITION(true_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\t\n\t\t\tresult_SP = FastEvaluateNode(true_node);\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tSLIM_PROFILE_BLOCK_END_CONDITION(true_node->profile_total_);\n#endif\n\t\t}\n\t\telse if (children_size == 3)\t\t// has an 'else' node\n\t\t{\n\t\t\tEidosASTNode *false_node = p_node->children_[2];\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\t\tSLIM_PROFILE_BLOCK_START_CONDITION(false_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\t\n\t\t\tresult_SP = FastEvaluateNode(false_node);\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tSLIM_PROFILE_BLOCK_END_CONDITION(false_node->profile_total_);\n#endif\n\t\t}\n\t\telse\t\t\t\t\t\t\t\t// no 'else' node, so the result is void\n\t\t{\n\t\t\tresult_SP = gStaticEidosValueVOID;\n\t\t}\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_If): condition for if statement has size() != 1.\" << EidosTerminate(p_node->token_);\n\t}\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_If()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Do(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Do()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Do\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tEidosDebugPointIndent indenter;\n\t\n\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()))\n\t{\n\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG DO (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): entering loop\" << std::endl;\n\t\tindenter.indent();\n\t}\n#endif\n\t\n#ifdef SLIMGUI\n\t// BCH 17 August 2025: adding a SLiMgui-only check for infinite loops, triggered by looping 10 million times;\n\t// note that this check can be turned off with the flag checkInfiniteLoops=F in initializeSLiMOptions()\n\tint64_t loop_counter = 0;\n#endif\n\t\n\tdo\n\t{\n#ifdef SLIMGUI\n\t\tif (check_infinite_loops_)\n\t\t\tif (++loop_counter == 10000001)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Do): this do-while loop iterated 10 million times; it might be an infinite loop.  This check can be turned off with initializeSLiMOptions(checkInfiniteLoops=F) if you intend to loop such a large number of times.  This check is only active when running under SLiMgui.\" << EidosTerminate(p_node->token_);\n#endif\n\t\t\n\t\t// execute the do...while loop's statement by evaluating its node; evaluation values get thrown away\n\t\tEidosASTNode *statement_node = p_node->children_[0];\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\tSLIM_PROFILE_BLOCK_START_CONDITION(statement_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\n\t\tEidosValue_SP statement_value = FastEvaluateNode(statement_node);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END_CONDITION(statement_node->profile_total_);\n#endif\n\t\t\n\t\t// if a return statement has occurred, we pass the return value outward\n\t\tif (return_statement_hit_)\n\t\t{\n\t\t\tresult_SP = std::move(statement_value);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// handle next and break statements\n\t\tif (next_statement_hit_)\n\t\t\tnext_statement_hit_ = false;\t\t// this is all we need to do; the rest of the function of \"next\" was done by Evaluate_CompoundStatement()\n\t\t\n\t\tif (break_statement_hit_)\n\t\t{\n\t\t\tbreak_statement_hit_ = false;\n\t\t\tbreak;\t\t\t\t\t\t\t// break statements, on the other hand, get handled additionally by a break from our loop here\n\t\t}\n\t\t\n\t\t// test the loop condition\n\t\tEidosASTNode *condition_node = p_node->children_[1];\n\t\tEidosValue_SP condition_result = FastEvaluateNode(condition_node);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()) &&\n\t\t\t(condition_result->Count() == 1))\n\t\t{\n\t\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\n\t\t\t// the above might raise, but if it does, it will be the same error as produced below\n\t\t\tindenter.outdent();\n\t\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG DO (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): condition == \" <<\n\t\t\t(condition_logical ? \"T\" : \"F\") << std::endl;\n\t\t\tindenter.indent();\n\t\t}\n#endif\n\t\t\n\t\tif (condition_result == gStaticEidosValue_LogicalT)\n\t\t{\n\t\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\t}\n\t\telse if (condition_result == gStaticEidosValue_LogicalF)\n\t\t{\n\t\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\t\tbreak;\n\t\t}\n\t\telse if (condition_result->Count() == 1)\n\t\t{\n\t\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\n\t\t\tif (!condition_logical)\n\t\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_Do): condition for do-while loop has size() != 1.\" << EidosTerminate(p_node->token_);\n\t\t}\n\t}\n\twhile (true);\n\t\n\tif (!result_SP)\n\t\tresult_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Do()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_While(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_While()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_While\", 2);\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tEidosValue_SP result_SP;\n\t\n#ifdef SLIMGUI\n\t// BCH 17 August 2025: adding a SLiMgui-only check for infinite loops, triggered by looping 10 million times;\n\t// note that this check can be turned off with the flag checkInfiniteLoops=F in initializeSLiMOptions()\n\tint64_t loop_counter = 0;\n#endif\n\t\n\twhile (true)\n\t{\n#ifdef SLIMGUI\n\t\tif (check_infinite_loops_)\n\t\t\tif (++loop_counter == 10000001)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_While): this while loop iterated 10 million times; it might be an infinite loop.  This check can be turned off with initializeSLiMOptions(checkInfiniteLoops=F) if you intend to loop such a large number of times.  This check is only active when running under SLiMgui.\" << EidosTerminate(p_node->token_);\n#endif\n\t\t\n\t\t// test the loop condition\n\t\tEidosASTNode *condition_node = p_node->children_[0];\n\t\tEidosValue_SP condition_result = FastEvaluateNode(condition_node);\n\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t// SLiMgui debugging point\n\t\tEidosDebugPointIndent indenter;\n\t\t\n\t\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()) &&\n\t\t\t(condition_result->Count() == 1))\n\t\t{\n\t\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\n\t\t\t// the above might raise, but if it does, it will be the same error as produced below\n\t\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG WHILE (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): condition == \" <<\n\t\t\t(condition_logical ? \"T\" : \"F\") << std::endl;\n\t\t\tindenter.indent();\n\t\t}\n#endif\n\t\t\n\t\tif (condition_result == gStaticEidosValue_LogicalT)\n\t\t{\n\t\t\t// Handle a static singleton logical true super fast; no need for type check, count, etc\n\t\t}\n\t\telse if (condition_result == gStaticEidosValue_LogicalF)\n\t\t{\n\t\t\t// Handle a static singleton logical false super fast; no need for type check, count, etc\n\t\t\tbreak;\n\t\t}\n\t\telse if (condition_result->Count() == 1)\n\t\t{\n\t\t\teidos_logical_t condition_logical = condition_result->LogicalAtIndex_CAST(0, operator_token);\n\t\t\t\n\t\t\tif (!condition_logical)\n\t\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_While): condition for while loop has size() != 1.\" << EidosTerminate(p_node->token_);\n\t\t}\n\t\t\n\t\t// execute the while loop's statement by evaluating its node; evaluation values get thrown away\n\t\tEidosASTNode *statement_node = p_node->children_[1];\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\tSLIM_PROFILE_BLOCK_START_CONDITION(statement_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\n\t\tEidosValue_SP statement_value = FastEvaluateNode(statement_node);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tSLIM_PROFILE_BLOCK_END_CONDITION(statement_node->profile_total_);\n#endif\n\t\t\n\t\t// if a return statement has occurred, we pass the return value outward\n\t\tif (return_statement_hit_)\n\t\t{\n\t\t\tresult_SP = std::move(statement_value);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t// handle next and break statements\n\t\tif (next_statement_hit_)\n\t\t\tnext_statement_hit_ = false;\t\t// this is all we need to do; the rest of the function of \"next\" was done by Evaluate_CompoundStatement()\n\t\t\n\t\tif (break_statement_hit_)\n\t\t{\n\t\t\tbreak_statement_hit_ = false;\n\t\t\tbreak;\t\t\t\t\t\t\t// break statements, on the other hand, get handled additionally by a break from our loop here\n\t\t}\n\t}\n\t\n\tif (!result_SP)\n\t\tresult_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_While()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_For(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_For()\");\n\t\n\t// We now allow multiple \"in\" clauses, so the number of children is just required to be >= 3 and odd\n\t// Each \"in\" clause is two children (identifier and expression), and the statement is the last child.\n\tEIDOS_ASSERT_CHILD_COUNT_GTEQ(\"EidosInterpreter::Evaluate_For\", 3);\n#if DEBUG\n\tif (p_node->children_.size() % 2 != 1) EIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): (internal error) expected an odd number of children.\" << EidosTerminate(p_node->token_);\n#endif\n\t\n\tEidosToken *operator_token = p_node->token_;\n\tint in_clause_count = (int)((p_node->children_.size() - 1) / 2);\n\t\n\t// This structure is used to keep track of the range and the index variable for each \"in\" clause\n\ttypedef struct {\n\t\tEidosGlobalStringID identifier_name;\n\t\tint64_t iteration_count;\n\t\t\n\t\t// we handle simple integer ranges more efficiently\n\t\tbool simpleIntegerRange;\n\t\tint64_t start_int, end_int;\n\t\t\n\t\t// otherwise we keep an EidosValue for the range of the \"in\" clause\n\t\tEidosValue_SP range_value;\n\t\t\n\t\t// we keep a reference to the loop iterator variable if we need one\n\t\tEidosValue_SP iterator_variable;\n\t\tEidosValueType iterator_type;\n\t\tvoid *iterator_data;\n\t} ForLoopHandler;\n\t\n\t// start by evaluating each \"in\" clause range and caching information about each clause\n\tstd::vector<ForLoopHandler> loop_handlers;\n\tloop_handlers.resize(in_clause_count);\n\t\n\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t{\n\t\tEidosASTNode *identifier_child = p_node->children_[in_clause_index * 2];\t\t\t// guaranteed by the parser to be an identifier token\n\t\tconst EidosASTNode *range_node = p_node->children_[in_clause_index * 2 + 1];\n\t\tEidosGlobalStringID identifier_name = identifier_child->cached_stringID_;\n\t\tbool is_const = false;\n\t\t\n\t\t// check for a constant up front, to give a better error message with the token highlighted\n\t\tif (global_symbols_->ContainsSymbol_IsConstant(identifier_name, &is_const))\n\t\t{\n\t\t\tEidosValue *existing_value = global_symbols_->GetValueRawOrRaiseForSymbol(identifier_name);\n\t\t\t\n\t\t\tif (is_const || existing_value->IsIteratorVariable())\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): identifier '\" << identifier_child->token_->token_string_ << \"' cannot be redefined because it is a constant.\" << EidosTerminate(identifier_child->token_);\n\t\t}\n\t\t\n\t\t// In some cases we do not need to actually construct the range that we are going to iterate over; we check for those cases first\n\t\tbool range_setup_handled = false;\n\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\tloop_handler.identifier_name = identifier_name;\n\t\tloop_handler.simpleIntegerRange = false;\n\t\t\n\t\tif ((range_node->token_->token_type_ == EidosTokenType::kTokenColon) && (range_node->children_.size() == 2))\n\t\t{\n\t\t\t// Maybe we can streamline a colon-operator range expression; let's check\n\t\t\tif (!range_node->cached_range_value_)\n\t\t\t{\n\t\t\t\tEidosValue_SP range_start_value_SP = FastEvaluateNode(range_node->children_[0]);\n\t\t\t\tEidosValue *range_start_value = range_start_value_SP.get();\n\t\t\t\tEidosValue_SP range_end_value_SP = FastEvaluateNode(range_node->children_[1]);\n\t\t\t\tEidosValue *range_end_value = range_end_value_SP.get();\n\t\t\t\t\n\t\t\t\tif ((range_start_value->Type() == EidosValueType::kValueInt) && (range_start_value->Count() == 1) && (range_start_value->DimensionCount() == 1) &&\n\t\t\t\t\t(range_end_value->Type() == EidosValueType::kValueInt) && (range_end_value->Count() == 1) && (range_end_value->DimensionCount() == 1))\n\t\t\t\t{\n\t\t\t\t\t// OK, we have a simple integer:integer range, so this should be very straightforward\n\t\t\t\t\tloop_handler.simpleIntegerRange = true;\n\t\t\t\t\tloop_handler.start_int = range_start_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\tloop_handler.end_int = range_end_value->IntAtIndex_NOCAST(0, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tif (loop_handler.start_int < loop_handler.end_int)\n\t\t\t\t\t\tloop_handler.iteration_count = loop_handler.end_int - loop_handler.start_int + 1;\n\t\t\t\t\telse\n\t\t\t\t\t\tloop_handler.iteration_count = loop_handler.start_int - loop_handler.end_int + 1;\n\t\t\t\t\t\n\t\t\t\t\trange_setup_handled = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If we are not using the general case, we have a bit of a problem now, because we have evaluated the child nodes\n\t\t\t\t\t// of the range expression.  Because that might have side effects, we can't let the code below do it again.\n\t\t\t\t\t// We therefore have to construct the range here that will be used below.  No good deed goes unpunished.\n\t\t\t\t\t\n\t\t\t\t\t// Note that this call to Evaluate_RangeExpr_Internal() gives ownership of the child values; it deletes them for us\n\t\t\t\t\tloop_handler.range_value = _Evaluate_RangeExpr_Internal(range_node, *range_start_value, *range_end_value);\n\t\t\t\t\tloop_handler.iteration_count = loop_handler.range_value->Count();\n\t\t\t\t\trange_setup_handled = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((range_node->token_->token_type_ == EidosTokenType::kTokenLParen) && (range_node->children_.size() == 2))\n\t\t{\n\t\t\t// Maybe we can streamline a seqAlong() or seqLen() call; let's check\n\t\t\tconst EidosASTNode *call_name_node = range_node->children_[0];\n\t\t\t\n\t\t\tif (call_name_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tconst EidosFunctionSignature *signature = call_name_node->cached_signature_.get();\n\t\t\t\t\n\t\t\t\tif (signature)\n\t\t\t\t{\n\t\t\t\t\tif (signature->internal_function_ == &Eidos_ExecuteFunction_seqAlong)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (range_node->children_.size() == 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We have a qualifying seqAlong() call, so evaluate its argument and set up our simple integer sequence\n\t\t\t\t\t\t\tconst EidosASTNode *argument_node = range_node->children_[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tloop_handler.simpleIntegerRange = true;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEidosValue_SP argument_value = FastEvaluateNode(argument_node);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tloop_handler.iteration_count = argument_value->Count();\n\t\t\t\t\t\t\tloop_handler.start_int = 0;\n\t\t\t\t\t\t\tloop_handler.end_int = loop_handler.iteration_count - 1;\n\t\t\t\t\t\t\trange_setup_handled = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (signature->internal_function_ == &Eidos_ExecuteFunction_seqLen)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (range_node->children_.size() == 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We have a qualifying seqLen() call, so evaluate its argument and set up our simple integer sequence\n\t\t\t\t\t\t\tconst EidosASTNode *argument_node = range_node->children_[1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tloop_handler.simpleIntegerRange = true;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tEidosValue_SP argument_value = FastEvaluateNode(argument_node);\n\t\t\t\t\t\t\tEidosValueType arg_type = argument_value->Type();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// check the argument; could call CheckArguments() except that it would use the wrong error position\n\t\t\t\t\t\t\tif (arg_type != EidosValueType::kValueInt)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): argument 1 (length) cannot be type \" << arg_type << \" for function seqLen().\" << EidosTerminate(call_name_node->token_);\n\t\t\t\t\t\t\tif (argument_value->Count() != 1)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): argument 1 (length) must be a singleton (size() == 1) for function seqLen(), but size() == \" << argument_value->Count() << \".\" << EidosTerminate(call_name_node->token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tint64_t length = argument_value->IntAtIndex_NOCAST(0, call_name_node->token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (length < 0)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): function seqLen() requires length to be greater than or equal to 0 (\" << length << \" supplied).\" << EidosTerminate(call_name_node->token_);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tloop_handler.iteration_count = length;\n\t\t\t\t\t\t\tloop_handler.start_int = 0;\n\t\t\t\t\t\t\tloop_handler.end_int = length - 1;\n\t\t\t\t\t\t\trange_setup_handled = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!range_setup_handled)\n\t\t{\n\t\t\t// We have something other than a simple integer range, so we have to do more work to figure out the range\n\t\t\tif (!loop_handler.range_value)\n\t\t\t\tloop_handler.range_value = FastEvaluateNode(range_node);\n\t\t\t\n\t\t\tloop_handler.iteration_count = loop_handler.range_value->Count();\n\t\t}\n\t}\n\t\n\t// check that all \"in\" clauses have the same iteration count\n\tint64_t iteration_count = 0;\n\t\n\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t{\n\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\tint64_t clause_count = loop_handler.iteration_count;\n\t\t\n\t\tif (in_clause_index == 0)\n\t\t\titeration_count = clause_count;\n\t\telse if (iteration_count != clause_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): all 'in' clauses of a for loop must have the same number of iterations.\" << EidosTerminate(p_node->token_);\n\t}\n\t\n\t// short-circuit if we have no work to do\n\tEidosValue_SP result_SP;\n\tEidosASTNode *statement_node = p_node->children_[in_clause_count * 2];\n\t\n\tif (iteration_count == 0)\n\t{\n\t\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t\t{\n\t\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\t\t\n\t\t\tif (!loop_handler.simpleIntegerRange)\n\t\t\t{\n\t\t\t\tEidosValueType range_type = loop_handler.range_value->Type();\n\t\t\t\t\n\t\t\t\tif (range_type == EidosValueType::kValueVOID)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): the 'for' keyword does not allow void for its right operand (the range to be iterated over).\" << EidosTerminate(p_node->token_);\n\t\t\t\tif (range_type == EidosValueType::kValueNULL)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): the 'for' keyword does not allow NULL for its right operand (the range to be iterated over).\" << EidosTerminate(p_node->token_);\n\t\t\t}\n\t\t}\n\t\t\n\t\tgoto for_exit;\n\t}\n\t\n\t// any loop index variables that already exist should be removed so that we can redefine them below\n\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t{\n\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\t\n\t\tif (global_symbols_->ContainsSymbol(loop_handler.identifier_name))\n\t\t\tglobal_symbols_->RemoveValueForSymbol(loop_handler.identifier_name);\n\t}\n\t\n\t// actually run the for loop\n\ttry\n\t{\n\t\tfor (int range_index = 0; range_index < iteration_count; ++range_index)\n\t\t{\n#if DEBUG_POINTS_ENABLED\n\t\t\t// SLiMgui debugging point\n\t\t\tEidosDebugPointIndent indenter;\n\t\t\tbool log_debug_point = false;\n\t\t\t\n\t\t\tif (debug_points_ && debug_points_->set.size() && (operator_token->token_line_ != -1) &&\n\t\t\t\t(debug_points_->set.find(operator_token->token_line_) != debug_points_->set.end()))\n\t\t\t{\n\t\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\t\n\t\t\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG FOR (line \" << (operator_token->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): \";\n\t\t\t\tlog_debug_point = true;\n\t\t\t}\n#endif\n\t\t\t\n\t\t\t// set up each iterator variable\n\t\t\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t\t\t{\n\t\t\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\t\t\t\n\t\t\t\tif (loop_handler.simpleIntegerRange)\n\t\t\t\t{\n\t\t\t\t\tbool counting_up = (loop_handler.start_int < loop_handler.end_int);\n\t\t\t\t\tint64_t iterator_int_value = (counting_up ? loop_handler.start_int + range_index : loop_handler.start_int - range_index);\n\t\t\t\t\t\n\t\t\t\t\tif (range_index == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_Int *index_value = new (gEidosValuePool->AllocateChunk()) EidosValue_Int(iterator_int_value);\n\t\t\t\t\t\t\n\t\t\t\t\t\tloop_handler.iterator_variable = EidosValue_Int_SP(index_value);\n\t\t\t\t\t\tloop_handler.iterator_type = EidosValueType::kValueInt;\n\t\t\t\t\t\tloop_handler.iterator_data = index_value->data_mutable();\n\t\t\t\t\t\t\n\t\t\t\t\t\t// make a constant for the loop index variable; but note that we have a mutable pointer to its data\n\t\t\t\t\t\t// the MarkAsConstant() call marks the *value* as constant, so it can't be modified with, e.g.,\n\t\t\t\t\t\t// x[0] = 7, whereas the MarkAsIteratorVariable() call marks the value as not being allowed to be\n\t\t\t\t\t\t// replaced by a new value with, e.g., x = 7; making an actual constant in the constants symbol table\n\t\t\t\t\t\t// is a no-go because it would prevent user-defined functions from using the same variable name\n\t\t\t\t\t\tglobal_symbols_->SetValueForSymbolNoCopy(loop_handler.identifier_name, loop_handler.iterator_variable);\n\t\t\t\t\t\tloop_handler.iterator_variable->MarkAsConstant();\n\t\t\t\t\t\tloop_handler.iterator_variable->MarkAsIteratorVariable();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t *int_data = (int64_t *)loop_handler.iterator_data;\n\t\t\t\t\t\t\n\t\t\t\t\t\t*int_data = iterator_int_value;\n\t\t\t\t\t}\n\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t\t// SLiMgui debugging point\n\t\t\t\t\tif (log_debug_point)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\t\t\t\n\t\t\t\t\t\toutput_stream << EidosStringRegistry::StringForGlobalStringID(loop_handler.identifier_name) << \" = integer$ \" << iterator_int_value;\n\t\t\t\t\t}\n#endif\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (range_index == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Start out with GetValueAtIndex(), which will return the correct type, handle retain/release, etc. for us\n\t\t\t\t\t\tloop_handler.iterator_type = loop_handler.range_value->Type();\n\t\t\t\t\t\tloop_handler.iterator_variable = loop_handler.range_value->GetValueAtIndex(range_index, operator_token);\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (loop_handler.iterator_variable->IsConstant())\n\t\t\t\t\t\t\tloop_handler.iterator_variable = loop_handler.iterator_variable->CopyValues();\n\t\t\t\t\t\t\n\t\t\t\t\t\tEidosValue *index_value = loop_handler.iterator_variable.get();\n\t\t\t\t\t\t\n\t\t\t\t\t\tswitch (loop_handler.iterator_type)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase EidosValueType::kValueLogical:\t\tloop_handler.iterator_data = ((EidosValue_Logical *)index_value)->data_mutable(); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueInt:\t\t\tloop_handler.iterator_data = ((EidosValue_Int *)index_value)->data_mutable(); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueFloat:\t\tloop_handler.iterator_data = ((EidosValue_Float *)index_value)->data_mutable(); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueString:\t\tloop_handler.iterator_data = ((EidosValue_String *)index_value)->StringData_Mutable(); break;\n\t\t\t\t\t\t\tcase EidosValueType::kValueObject:\t\tloop_handler.iterator_data = ((EidosValue_Object *)index_value)->data_mutable(); break;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): (internal error) unexpected range value type in for loop.\" << EidosTerminate(p_node->token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// make a constant for the loop index variable; but note that we have a mutable pointer to its data\n\t\t\t\t\t\t// the MarkAsConstant() call marks the *value* as constant, so it can't be modified with, e.g.,\n\t\t\t\t\t\t// x[0] = 7, whereas the MarkAsIteratorVariable() call marks the value as not being allowed to be\n\t\t\t\t\t\t// replaced by a new value with, e.g., x = 7; making an actual constant in the constants symbol table\n\t\t\t\t\t\t// is a no-go because it would prevent user-defined functions from using the same variable name\n\t\t\t\t\t\tglobal_symbols_->SetValueForSymbolNoCopy(loop_handler.identifier_name, loop_handler.iterator_variable);\n\t\t\t\t\t\tloop_handler.iterator_variable->MarkAsConstant();\n\t\t\t\t\t\tloop_handler.iterator_variable->MarkAsIteratorVariable();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (loop_handler.iterator_type)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase EidosValueType::kValueLogical:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosValue_Logical *logical_range_value = (EidosValue_Logical *)(loop_handler.range_value.get());\n\t\t\t\t\t\t\t\teidos_logical_t iterator_logical_value = logical_range_value->data()[range_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t*(eidos_logical_t *)loop_handler.iterator_data = iterator_logical_value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase EidosValueType::kValueInt:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosValue_Int *int_range_value = (EidosValue_Int *)(loop_handler.range_value.get());\n\t\t\t\t\t\t\t\tint64_t iterator_int_value = int_range_value->data()[range_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t*(int64_t *)loop_handler.iterator_data = iterator_int_value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase EidosValueType::kValueFloat:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosValue_Float *float_range_value = (EidosValue_Float *)(loop_handler.range_value.get());\n\t\t\t\t\t\t\t\tdouble iterator_float_value = float_range_value->data()[range_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t*(double *)loop_handler.iterator_data = iterator_float_value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase EidosValueType::kValueString:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosValue_String *string_range_value = (EidosValue_String *)(loop_handler.range_value.get());\n\t\t\t\t\t\t\t\tstd::string &iterator_logical_value = string_range_value->StringData_Mutable()[range_index];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t*(std::string *)loop_handler.iterator_data = iterator_logical_value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase EidosValueType::kValueObject:\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEidosValue_Object *float_range_value = (EidosValue_Object *)(loop_handler.range_value.get());\n\t\t\t\t\t\t\t\tEidosObject *iterator_object_value = float_range_value->data()[range_index];\n\t\t\t\t\t\t\t\tEidosObject **iterator_variable_data = (EidosObject **)loop_handler.iterator_data;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (iterator_object_value->Class()->UsesRetainRelease())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t((EidosDictionaryRetained *)iterator_object_value)->Retain();\n\t\t\t\t\t\t\t\t\t((EidosDictionaryRetained *)*iterator_variable_data)->Release();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t*iterator_variable_data = iterator_object_value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_For): (internal error) unexpected range value type in for loop.\" << EidosTerminate(p_node->token_);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t\t// SLiMgui debugging point\n\t\t\t\t\tif (log_debug_point)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\t\t\t\n\t\t\t\t\t\toutput_stream << EidosStringRegistry::StringForGlobalStringID(loop_handler.identifier_name) << \" = \" << loop_handler.iterator_type;\n\t\t\t\t\t\tif (loop_handler.iterator_type == EidosValueType::kValueObject)\n\t\t\t\t\t\t\toutput_stream << \"<\" << loop_handler.range_value->ElementType() << \">\";\n\t\t\t\t\t\toutput_stream << \"$ \" << *loop_handler.iterator_variable;\n\t\t\t\t\t}\n#endif\n\t\t\t\t}\n\t\t\t\t\n#if DEBUG_POINTS_ENABLED\n\t\t\t\t// SLiMgui debugging point\n\t\t\t\tif (log_debug_point)\n\t\t\t\t{\n\t\t\t\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\t\t\t\n\t\t\t\t\tif (in_clause_index == in_clause_count - 1)\n\t\t\t\t\t{\n\t\t\t\t\t\toutput_stream << std::endl;\n\t\t\t\t\t\tindenter.indent();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\toutput_stream << \", \";\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING: profile child statement unless it is a compound statement (which does its own profiling)\n\t\t\tSLIM_PROFILE_BLOCK_START_CONDITION(statement_node->token_->token_type_ != EidosTokenType::kTokenLBrace);\n#endif\n\t\t\t\n\t\t\tEidosValue_SP statement_value = FastEvaluateNode(statement_node);\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tSLIM_PROFILE_BLOCK_END_CONDITION(statement_node->profile_total_);\n#endif\n\t\t\t\n\t\t\t// if a return statement has occurred, we pass the return value outward\n\t\t\tif (return_statement_hit_)\n\t\t\t{\n\t\t\t\tresult_SP = std::move(statement_value);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t// handle next and break statements\n\t\t\tif (next_statement_hit_)\n\t\t\t\tnext_statement_hit_ = false;\t\t// this is all we need to do; the rest of the function of \"next\" was done by Evaluate_CompoundStatement()\n\t\t\t\n\t\t\tif (break_statement_hit_)\n\t\t\t{\n\t\t\t\tbreak_statement_hit_ = false;\n\t\t\t\tbreak;\t\t\t\t\t\t\t// break statements, on the other hand, get handled additionally by a break from our loop here\n\t\t\t}\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\t// transmute our iterator variables to no longer be constants; the user is allowed to modify them after the loop finishes\n\t\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t\t{\n\t\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\t\t\n\t\t\tif (loop_handler.iterator_variable)\n\t\t\t{\n\t\t\t\tloop_handler.iterator_variable->MarkAsMutable();\n\t\t\t\tloop_handler.iterator_variable->MarkAsNonIteratorVariable();\n\t\t\t}\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\t// transmute our iterator variables to no longer be constants; the user is allowed to modify them after the loop finishes\n\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t{\n\t\tForLoopHandler &loop_handler = loop_handlers[in_clause_index];\n\t\t\n\t\tif (loop_handler.iterator_variable)\n\t\t{\n\t\t\tloop_handler.iterator_variable->MarkAsMutable();\n\t\t\tloop_handler.iterator_variable->MarkAsNonIteratorVariable();\n\t\t}\n\t}\n\t\nfor_exit:\n\t\n\tif (!result_SP)\n\t\tresult_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_For()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Next(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Next()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Next\", 0);\n\t\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tif (debug_points_ && debug_points_->set.size() && (p_node->token_->token_line_ != -1) &&\n\t\t(debug_points_->set.find(p_node->token_->token_line_) != debug_points_->set.end()))\n\t{\n\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG NEXT (line \" << (p_node->token_->token_line_ + 1) << eidos_context_->DebugPointInfo() << \")\" << std::endl;\n\t}\n#endif\n\t\n\t// just like a null statement, except that we set a flag in the interpreter, which will be seen by the eval\n\t// methods and will cause them to return up to the for loop immediately; Evaluate_For will handle the flag.\n\tnext_statement_hit_ = true;\n\t\n\t// We set up the error state on our token so that if we don't get handled properly above, we are highlighted.\n\tPushErrorPositionFromToken(p_node->token_);\n\t\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Next()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Break(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Break()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_Break\", 0);\n\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tif (debug_points_ && debug_points_->set.size() && (p_node->token_->token_line_ != -1) &&\n\t\t(debug_points_->set.find(p_node->token_->token_line_) != debug_points_->set.end()))\n\t{\n\t\tErrorOutputStream() << EidosDebugPointIndent::Indent() << \"#DEBUG BREAK (line \" << (p_node->token_->token_line_ + 1) << eidos_context_->DebugPointInfo() << \")\" << std::endl;\n\t}\n#endif\n\t\n\t// just like a null statement, except that we set a flag in the interpreter, which will be seen by the eval\n\t// methods and will cause them to return up to the for loop immediately; Evaluate_For will handle the flag.\n\tbreak_statement_hit_ = true;\n\t\n\t// We set up the error state on our token so that if we don't get handled properly above, we are highlighted.\n\tPushErrorPositionFromToken(p_node->token_);\n\t\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Break()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_Return(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_Return()\");\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wtype-limits\"\t// the number of children is unsigned and cannot be less than 0, which some compilers warn about...\n\tEIDOS_ASSERT_CHILD_RANGE(\"EidosInterpreter::Evaluate_Return\", 0, 1);\n#pragma GCC diagnostic pop\n\t\n\t// set a flag in the interpreter, which will be seen by the eval methods and will cause them to return up to the top-level block immediately\n\treturn_statement_hit_ = true;\n\t\n\t// We set up the error state on our token so that if we don't get handled properly above, we are highlighted.\n\tPushErrorPositionFromToken(p_node->token_);\n\t\n\tEidosValue_SP result_SP;\n\t\n\tif (p_node->children_.size() == 0)\n\t\tresult_SP = gStaticEidosValueVOID;\t// no return value; note that \"return;\" is semantically different from \"return NULL;\" because it returns void\n\telse\n\t\tresult_SP = FastEvaluateNode(p_node->children_[0]);\n\t\n#if DEBUG_POINTS_ENABLED\n\t// SLiMgui debugging point\n\tEidosDebugPointIndent indenter;\n\t\n\tif (debug_points_ && debug_points_->set.size() && (p_node->token_->token_line_ != -1) &&\n\t\t(debug_points_->set.find(p_node->token_->token_line_) != debug_points_->set.end()))\n\t{\n\t\tstd::ostream &output_stream = ErrorOutputStream();\n\t\t\n\t\toutput_stream << EidosDebugPointIndent::Indent() << \"#DEBUG RETURN (line \" << (p_node->token_->token_line_ + 1) << eidos_context_->DebugPointInfo() << \"): \";\n\t\tif (result_SP->Count() <= 1)\n\t\t{\n\t\t\tresult_SP->PrintStructure(output_stream, 1);\n\t\t}\n\t\telse {\n\t\t\t// print multiple values on a new line, with indent\n\t\t\tresult_SP->PrintStructure(output_stream, 0);\n\t\t\toutput_stream << std::endl;\n\t\t\tindenter.indent(2);\n\t\t\tresult_SP->Print(output_stream, EidosDebugPointIndent::Indent());\n\t\t\tindenter.outdent(2);\n\t\t}\n\t\toutput_stream << std::endl;\n\t}\n#endif\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_Return()\");\n\treturn result_SP;\n}\n\nEidosValue_SP EidosInterpreter::Evaluate_FunctionDecl(const EidosASTNode *p_node)\n{\n\tEIDOS_ENTRY_EXECUTION_LOG(\"Evaluate_FunctionDecl()\");\n\tEIDOS_ASSERT_CHILD_COUNT(\"EidosInterpreter::Evaluate_FunctionDecl\", 4);\n\t\n\tconst EidosASTNode *return_type_node = p_node->children_[0];\n\tconst EidosASTNode *function_name_node = p_node->children_[1];\n\tconst EidosASTNode *param_list_node = p_node->children_[2];\n\tconst EidosASTNode *body_node = p_node->children_[3];\n\t\n\t// Build a signature object for this function\n\tEidosTypeSpecifier &return_type = return_type_node->typespec_;\n\tconst std::string &function_name = function_name_node->token_->token_string_;\n\tconst std::vector<EidosASTNode *> &param_nodes = param_list_node->children_;\n\tstd::vector<std::string> used_param_names;\n\t\n\t{\n\t\tEidosFunctionSignature *sig;\n\t\t\n\t\tif (return_type.object_class == nullptr)\n\t\t\tsig = (EidosFunctionSignature *)(new EidosFunctionSignature(function_name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullptr,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.type_mask));\n\t\telse\n\t\t\tsig = (EidosFunctionSignature *)(new EidosFunctionSignature(function_name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullptr,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.type_mask,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.object_class));\n\t\t\n\t\ttry {\n\t\t\tfor (EidosASTNode *param_node : param_nodes)\n\t\t\t{\n\t\t\t\tconst std::vector<EidosASTNode *> &param_children = param_node->children_;\n\t\t\t\tint param_children_count = (int)param_children.size();\n\t\t\t\t\n\t\t\t\tif ((param_children_count == 2) || (param_children_count == 3))\n\t\t\t\t{\n\t\t\t\t\tEidosTypeSpecifier &param_type = param_children[0]->typespec_;\n\t\t\t\t\tconst std::string &param_name = param_children[1]->token_->token_string_;\n\t\t\t\t\t\n\t\t\t\t\t// Check param_name; it needs to not be used by another parameter\n\t\t\t\t\tif (std::find(used_param_names.begin(), used_param_names.end(), param_name) != used_param_names.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_FunctionDecl): invalid name for parameter '\" << param_name << \"'; this name was already used for a previous parameter in this declaration.\" << EidosTerminate(p_node->token_);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (param_children_count == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\t// param_node has 2 children (type, identifier)\n\t\t\t\t\t\tsig->AddArg(param_type.type_mask, param_name, param_type.object_class);\n\t\t\t\t\t}\n\t\t\t\t\telse if (param_children_count == 3)\n\t\t\t\t\t{\n\t\t\t\t\t\t// param_node has 3 children (type, identifier, default); we need to figure out the default value,\n\t\t\t\t\t\t// which is either a constant of some sort, or is an identifier representing a built-in Eidos constant\n\t\t\t\t\t\tEidosASTNode *default_node = param_children[2];\n\t\t\t\t\t\tEidosValue_SP default_value;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (default_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We just hard-code the names of the built-in Eidos constants here, for now\n\t\t\t\t\t\t\tconst std::string &default_string = default_node->token_->token_string_;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (std::find(gEidosConstantNames.begin(), gEidosConstantNames.end(), default_string) != gEidosConstantNames.end())\n\t\t\t\t\t\t\t\tdefault_value = FastEvaluateNode(default_node);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_FunctionDecl): invalid default value for parameter '\" << param_name << \"'; a default value must be a numeric constant, a string constant, or a built-in Eidos constant (T, F, NULL, PI, E, INF, or NAN).\" << EidosTerminate(default_node->token_);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdefault_value = FastEvaluateNode(default_node);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tsig->AddArgWithDefault(param_type.type_mask, param_name, param_type.object_class, std::move(default_value));\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tused_param_names.emplace_back(param_name);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// Add the function body to the function signature.  We can't just use body_node, because we don't know what its\n\t\t\t// lifetime will be; we need our own private copy.  The best thing, really, is to make our own EidosScript object\n\t\t\t// with the appropriate substring, and re-tokenize and re-parse.  This is somewhat wasteful, but it's one-time\n\t\t\t// overhead so it shouldn't matter.  It will smooth out all of the related issues with error reporting, etc.,\n\t\t\t// since we won't be dependent upon somebody else's script object.  Errors in tokenization/parsing should never\n\t\t\t// occur, since the code for the function body already passed through that process once.\n\t\t\t\n\t\t\t// BCH 2/8/2021: Note that we now base this EidosScript on body_node->token_->token_line_ for purposes of debug\n\t\t\t// point detection, so Eidos knows that this script is a substring of the original user script.\n\t\t\t\n\t\t\t// BCH 3/12/2025: For error-tracking, we now need to locate this function declaration within the user's script.\n\t\t\t// Finding the user's script here is a bit gross, though!  We get it from the error position, which generally\n\t\t\t// ought to be set up now with the user script whenever we hit a function declaration.  Maybe in a place like a\n\t\t\t// lambda it would not be set up, which is OK; then we are unmoored from the user's script, and use nullptr.\n\t\t\t// It feels weird to use the error info here to find the user script, but maybe it is OK; the error info is the\n\t\t\t// thing that says \"you are interpreting in this script, which is located right here in this other script\", and\n\t\t\t// that's exactly what we need to know.  If using it here proves problematic, the alternative seems to me to be\n\t\t\t// for EidosInterpreter to have a pointer to the user script within which it is interpreting; but that would\n\t\t\t// be a big change, and it wouldn't use the information anywhere but here.\n\t\t\tEidosScript *userScript = nullptr;\n\t\t\t\n\t\t\tif (gEidosErrorContext.currentScript)\n\t\t\t{\n\t\t\t\tEidosScript *error_userScript = gEidosErrorContext.currentScript->UserScript();\n\t\t\t\tint32_t error_offset = gEidosErrorContext.currentScript->UserScriptUTF16Offset();\n\t\t\t\t\n\t\t\t\tif (error_userScript)\n\t\t\t\t{\n\t\t\t\t\t// the current script is derived from the user script\n\t\t\t\t\tuserScript = error_userScript;\n\t\t\t\t}\n\t\t\t\telse if (error_offset == 0)\n\t\t\t\t{\n\t\t\t\t\t// the current script *is* the user script\n\t\t\t\t\tuserScript = gEidosErrorContext.currentScript;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tEidosScript *script;\n\t\t\t\n\t\t\tif (userScript)\n\t\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\t\tstd::cout << \"=== User-defined function definition found user script \" << userScript << \"; using that with char offset \" << body_node->token_->token_start_ << \", UTF offset \" << body_node->token_->token_UTF16_start_ << std::endl;\n#endif\n\t\t\t\t\n\t\t\t\tscript = new EidosScript(body_node->token_->token_string_, userScript, body_node->token_->token_line_, body_node->token_->token_start_, body_node->token_->token_UTF16_start_);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\t\tstd::cout << \"=== User-defined function definition did not find user script (gEidosErrorContext.currentScript == \" << gEidosErrorContext.currentScript << \")\" << std::endl;\n#endif\n\t\t\t\t\n\t\t\t\tscript = new EidosScript(body_node->token_->token_string_);\n\t\t\t}\n\t\t\t\n#if EIDOS_DEBUG_ERROR_POSITIONS\n\t\t\tstd::cout << \"    script object for the user-defined function == \" << script << \"\" << std::endl;\n#endif\n\t\t\t\n\t\t\tscript->Tokenize();\n\t\t\tscript->ParseInterpreterBlockToAST(false);\n\t\t\t\n\t\t\tsig->body_script_ = script;\n\t\t\tsig->user_defined_ = true;\n\t\t\t\n\t\t\t// this is the line that `function` is on, so we want to use p_node->token_; note this is different\n\t\t\t// from the line offset kept by the script, which refers to the line offset to the starting brace\n\t\t\t// of the body; we want the offset to `function` for debug points, so this is not redundant\n\t\t\tsig->user_definition_line_ = p_node->token_->token_line_;\n\t\t\t\n\t\t\t//std::cout << *sig << std::endl;\n\t\t\t\n\t\t\t// Check that a built-in function is not already defined with this name; no replacing the built-ins.\n\t\t\tauto signature_iter = function_map_.find(function_name);\n\t\t\t\n\t\t\tif (signature_iter != function_map_.end())\n\t\t\t{\n\t\t\t\tconst EidosFunctionSignature *prior_sig = signature_iter->second.get();\n\t\t\t\t\n\t\t\t\tif (prior_sig->internal_function_ || !prior_sig->delegate_name_.empty() || !prior_sig->user_defined_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::Evaluate_FunctionDecl): cannot replace built-in function \" << function_name << \"().\" << EidosTerminate(p_node->token_);\n\t\t\t}\n\t\t\t\n\t\t\t// Add the user-defined function to our function map (possibly replacing a previous version)\n\t\t\tauto found_iter = function_map_.find(sig->call_name_);\n\t\t\t\n\t\t\tif (found_iter != function_map_.end())\n\t\t\t\tfunction_map_.erase(found_iter);\n\t\t\t\n\t\t\tfunction_map_.insert(EidosFunctionMapPair(sig->call_name_, EidosFunctionSignature_CSP(sig)));\n\t\t\t\n\t\t\t// the signature is now under shared_ptr, or deleted, and so variable sig falls out of scope here\n\t\t}\n\t\tcatch (...) {\n\t\t\tdelete sig;\n\t\t\tthrow;\n\t\t}\n\t}\n\t\n\t// Always return void\n\tEidosValue_SP result_SP = gStaticEidosValueVOID;\n\t\n\tEIDOS_EXIT_EXECUTION_LOG(\"Evaluate_FunctionDecl()\");\n\treturn result_SP;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_interpreter.h",
    "content": "//\n//  eidos_interpreter.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/4/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosInterpreter embodies an interpreter for a script, and handles symbol lookup, operation execution,\n etc., using classes that are, for simplicity, also defined in this header.\n \n */\n\n#ifndef __Eidos__eidos_interpreter__\n#define __Eidos__eidos_interpreter__\n\n#include <vector>\n#include <string>\n#include <map>\n#include <cassert>\n\n#include \"eidos_script.h\"\n#include \"eidos_value.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_symbol_table.h\"\n#include \"eidos_ast_node.h\"\n\nclass EidosCallSignature;\n\n\n// EidosInterpreter keeps track of the EidosContext object that is in charge of the whole show.  This should\n// be an object of type EidosObject; this allows dynamic_cast to work, whereas void* would not.  This\n// is optional; you can pass nullptr if you don't want to register a Context.  Eidos itself does nothing\n// with the Context except keep track of it for you; the purpose of it is to allow your Eidos method\n// implementations, function implementations, etc., to get up to the big picture without every object in\n// your object graph having a back pointer of some kind.  If you think this is gross, don't use it.  :->\ntypedef EidosObject EidosContext;\n\n// typedefs used to set up our map table of EidosFunctionSignature objects; std::map is used instead of\n// std::unordered_map mostly for convenience, speed should not matter much since signatures get cached anyway\ntypedef std::pair<std::string, EidosFunctionSignature_CSP> EidosFunctionMapPair;\ntypedef std::map<std::string, EidosFunctionSignature_CSP> EidosFunctionMap;\n\n// utility functions\nbool TypeCheckAssignmentOfEidosValueIntoEidosValue(const EidosValue &p_base_value, const EidosValue &p_destination_value);\t// codifies what promotions can occur in assignment\n\n\n// This typedef is used to represent the line numbers that have \"debug points\" associated with them in SLiMgui.\n// This is a bit convoluted so that we can forward-declare it in other headers even though it's a typedef of a\n// templated class; I couldn't figure out a better way to do it than wrapping it in a struct, ugh.\n#ifdef SLIMGUI\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\nstruct EidosInterpreterDebugPointsSet_struct {\n\trobin_hood::unordered_set<int> set;\n};\ntypedef EidosInterpreterDebugPointsSet_struct EidosInterpreterDebugPointsSet;\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_set>\nstruct EidosInterpreterDebugPointsSet_struct {\n\tstd::unordered_set<int> set;\n};\ntypedef EidosInterpreterDebugPointsSet_struct EidosInterpreterDebugPointsSet;\n#endif\n#endif\n\n\n// A class representing a script interpretation context with all associated symbol table state\nclass EidosInterpreter\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprivate:\n\tEidosContext *eidos_context_;\t\t\t\t// not owned\n\tconst EidosASTNode *root_node_;\t\t\t\t// not owned\n\tEidosSymbolTable *global_symbols_;\t\t\t// NOT OWNED: whoever creates us must give us a reference to a symbol table, which we use\n\t\n\tEidosFunctionMap &function_map_;\t\t\t// a map table of EidosFunctionSignature objects, keyed by function name\n\t\n\t// flags to handle next/break statements in do...while, while, and for loops\n\tbool next_statement_hit_ = false;\n\tbool break_statement_hit_ = false;\n\tbool return_statement_hit_ = false;\n\t\n\t// flags and streams for execution logging – a trace of the DFS of the parse tree\n\tbool logging_execution_ = false;\n\tint execution_log_indent_ = 0;\n\tstd::ostringstream *execution_log_ = nullptr;\t\t// allocated lazily; for internal tokenization/parse/execution traces\n\t\n\t// output streams for standard and error output from executed nodes and functions; these go into the user's console\n\tstd::ostream &execution_output_;\n\tstd::ostream &error_output_;\n\t\n\t// a flag controlling the special use of SLiMUndefinedIdentifierException by\n\t// EidosSymbolTable::_GetValue(); see Community::_EvaluateTickRangeNode() for\n\t// the use of this facility.\n\tbool use_custom_undefined_identifier_raise_ = false;\n\t\n\t// similarly, a flag controlling the special use of SLiMUndefinedFunctionException\n\t// by EidosInterpreter::Evaluate_Call(); see Community::_EvaluateTickRangeNode() for\n\t// the use of this facility.\n\tbool use_custom_undefined_function_raise_ = false;\n\t\n\t// The standard built-in function map, set up by CacheBuiltInFunctionMap()\n\tstatic EidosFunctionMap *s_built_in_function_map_;\n\t\n#ifdef SLIMGUI\n\tEidosInterpreterDebugPointsSet *debug_points_ = nullptr;\t\t// NOT OWNED; line numbers for all lines with debugging points set\n#endif\n\t\npublic:\n\t\n#ifdef SLIMGUI\n\tbool check_infinite_loops_ = true;\t\t\t\t\t\t\t\t// check for infinite loops, only in SLiMgui\n#endif\n\t\n\tEidosInterpreter(const EidosInterpreter&) = delete;\t\t\t\t\t// no copying\n\tEidosInterpreter& operator=(const EidosInterpreter&) = delete;\t\t// no copying\n\tEidosInterpreter(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\t\n\t// we use the symbol table passed in to these constructors, but do not own it\n\tEidosInterpreter(const EidosScript &p_script, EidosSymbolTable &p_symbols, EidosFunctionMap &p_functions, EidosContext *p_eidos_context, std::ostream &p_outstream, std::ostream &p_errstream\n#ifdef SLIMGUI\n\t\t, bool p_check_infinite_loops\n#endif\n\t);\n\t\n\tEidosInterpreter(const EidosASTNode *p_root_node_, EidosSymbolTable &p_symbols, EidosFunctionMap &p_functions, EidosContext *p_eidos_context, std::ostream &p_outstream, std::ostream &p_errstream\n#ifdef SLIMGUI\n\t\t, bool p_check_infinite_loops\n#endif\n\t);\n\t\n\tinline ~EidosInterpreter(void)\n\t{\n\t\tif (execution_log_)\n\t\t\tdelete execution_log_;\n\t\t\n#ifdef SLIMGUI\n\t\tdebug_points_ = nullptr;\n#endif\n\t}\n\t\n\tinline __attribute__((always_inline)) std::string IndentString(int p_indent_level) { return std::string(p_indent_level * 2, ' '); };\n\t\n\tvoid SetShouldLogExecution(bool p_log);\n\tbool ShouldLogExecution(void);\n\tstd::string ExecutionLog(void);\n\t\n\tinline __attribute__((always_inline)) std::ostream &ExecutionOutputStream(void) { return execution_output_; }\n\tinline __attribute__((always_inline)) std::ostream &ErrorOutputStream(void) { return error_output_; }\n\t\n\tinline __attribute__((always_inline)) EidosSymbolTable &SymbolTable(void) { return *global_symbols_; };\t\t\t// the returned reference is to the symbol table that the interpreter has borrowed\n\tinline __attribute__((always_inline)) EidosFunctionMap &FunctionMap(void) { return function_map_; };\t\t\t\t// the returned reference is to the function map that the interpreter has borrowed\n\tinline __attribute__((always_inline)) EidosContext *Context(void) const { return eidos_context_; };\n\t\n\t// Evaluation methods; the caller owns the returned EidosValue object\n\tEidosValue_SP EvaluateInternalBlock(EidosScript *p_script_for_block);\t\t// the starting point for internally executed blocks, which require braces and suppress output\n\tEidosValue_SP EvaluateInterpreterBlock(bool p_print_output, bool p_return_last_value);\t\t// the starting point for executed blocks in Eidos, which do not require braces\n\t\n\tvoid _ProcessSubsetAssignment(EidosValue_SP *p_base_value_ptr, EidosGlobalStringID *p_property_string_id_ptr, std::vector<int> *p_indices_ptr, const EidosASTNode *p_parent_node);\n\tvoid _AssignRValueToLValue(EidosValue_SP p_rvalue, const EidosASTNode *p_lvalue_node);\n\tEidosValue_SP _Evaluate_RangeExpr_Internal(const EidosASTNode *p_node, const EidosValue &p_first_child_value, const EidosValue &p_second_child_value);\n\t\n\t// These process the arguments for a call node (either a function call or a method call), ignoring the first child\n\t// node since that is the call name node, not an argument node.  Named arguments and default arguments are handled\n\t// here, and a final argument list is placed into the argument_cache_'s argument_buffer_, in the node, for use.\n\t// Note that recursion in Eidos code requires the use of separately allocated argument buffers for the recursive\n\t// calls; slow, but presumably an edge case for typical code.  If Eidos interpretation is ever made multithreaded,\n\t// the argument_buffer_in_use_ flag will need to be governed by a lock.\n\tvoid _CreateArgumentList(const EidosASTNode *p_node, const EidosCallSignature *p_call_signature);\n\t\n\tstd::vector<EidosValue_SP> *_ProcessArgumentList(const EidosASTNode *p_node, const EidosCallSignature *p_call_signature)\n\t{\n\t\tEidosASTNode_ArgumentCache *argument_cache = p_node->argument_cache_;\t// the argument cache lives on the call node itself, conventionally\n\t\tstd::vector<EidosValue_SP> *argument_buffer = nullptr;\n\t\t\n\t\t// Allocate and configure an argument cache struct if we don't already have one\n\t\tif (!argument_cache)\n\t\t{\n\t\t\t// We don't already have an argument cache, so create one and use it\n\t\t\t_CreateArgumentList(p_node, p_call_signature);\n\t\t\targument_cache = p_node->argument_cache_;\n\t\t\tassert(argument_cache);\t\t// static analyzer doesn't understand that _CreateArgumentList() created the cache\n\t\t\targument_buffer = &argument_cache->argument_buffer_;\n\t\t\targument_cache->argument_buffer_in_use_ = true;\n\t\t}\n\t\telse if (argument_cache->argument_buffer_in_use_)\n\t\t{\n\t\t\t// We have an argument cache, but its argument buffer is already in use, so make a new temporary one\n\t\t\targument_buffer = new std::vector<EidosValue_SP>;\n\t\t\targument_buffer->resize(argument_cache->argument_buffer_.size());\t// fill with nullptr up to the required size\n\t\t\t\n\t\t\t// Copy the non-filled (default/constant) arguments into the temporary argument buffer\n\t\t\tfor (uint8_t no_fill_index : argument_cache->no_fill_index_)\n\t\t\t\t(*argument_buffer)[no_fill_index] = argument_cache->argument_buffer_[no_fill_index];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have an argument cache, and its argument buffer is not already in use, so use it now\n\t\t\targument_buffer = &argument_cache->argument_buffer_;\n\t\t\targument_cache->argument_buffer_in_use_ = true;\n\t\t}\n\t\t\n\t\tstd::vector<EidosASTNode_ArgumentFill> &fill_info = argument_cache->fill_info_;\n\t\t\n\t\t// Now our argument cache is all ready to use; we just need to fill and type-check arguments\n\t\tfor (const EidosASTNode_ArgumentFill &fill : fill_info)\n\t\t{\n\t\t\t// Get the argument value by evaluating the AST node responsible for providing it\n\t\t\tEidosValue_SP arg_value = FastEvaluateNode(fill.fill_node_);\n\t\t\t\n\t\t\t// Type-check the value; note that default/constant arguments are type-checked during signature construction\n\t\t\tp_call_signature->CheckArgument(arg_value.get(), fill.signature_index_);\n\t\t\t\n\t\t\t// Move the argument value into the argument buffer\n\t\t\t(*argument_buffer)[fill.fill_index_] = std::move(arg_value);\n\t\t}\n\t\t\n\t\t// call CheckArguments() to double-check for errors when in DEBUG; this can be removed eventually, it's just for the transition to the new argument buffers\n#if DEBUG\n\t\tp_call_signature->CheckArguments(*argument_buffer);\n#endif\n\t\t\n\t\treturn argument_buffer;\n\t}\n\t\n\tinline void _DeprocessArgumentList(const EidosASTNode *p_node, std::vector<EidosValue_SP> *p_argument_buffer)\n\t{\n\t\tEidosASTNode_ArgumentCache *argument_cache = p_node->argument_cache_;\n\t\t\n#if DEBUG\n\t\tif (!argument_cache)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosInterpreter::_DeprocessArgumentList): (internal) missing argument cache.\" << EidosTerminate(nullptr);\n#endif\n\t\t\n\t\tif (p_argument_buffer == &argument_cache->argument_buffer_)\n\t\t{\n\t\t\t// We're deprocessing the argument list inside the argument cache, so we just want to nil out the filled entries\n\t\t\tstd::vector<EidosASTNode_ArgumentFill> &fill_info = argument_cache->fill_info_;\n\t\t\t\n\t\t\t// Loop through the fill indices and reset the shared pointers so the EidosValues get released in a timely fashion\n\t\t\t// Note that we leave the non-fill indices alone; they are default values and constants that will get reused next time\n\t\t\tfor (const EidosASTNode_ArgumentFill &fill : fill_info)\n\t\t\t\t(*p_argument_buffer)[fill.fill_index_].reset();\n\t\t\t\n\t\t\t// The argument cache's argument buffer is no longer in use\n\t\t\targument_cache->argument_buffer_in_use_ = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We're deprocessing a heap-allocated argument buffer created due to recursion; free everything\n\t\t\t// The argument cache's argument buffer remains in use, by the root call of the recursion\n\t\t\tdelete p_argument_buffer;\n\t\t}\n\t}\n\t\n#ifdef SLIMGUI\n\tvoid _LogCallArguments(const EidosCallSignature *call_signature, std::vector<EidosValue_SP> *argument_buffer);\n#endif\n\t\n\tEidosValue_SP DispatchUserDefinedFunction(const EidosFunctionSignature &p_function_signature, const std::vector<EidosValue_SP> &p_arguments);\n\t\n\tvoid NullReturnRaiseForNode(const EidosASTNode *p_node);\n\tEidosValue_SP EvaluateNode(const EidosASTNode *p_node);\n\t\n\tEidosValue_SP Evaluate_NullStatement(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_CompoundStatement(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_RangeExpr(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Call(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Subset(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_MemberRef(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Plus(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Minus(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Mod(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Mult(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Div(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Conditional(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Exp(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_And(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Or(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Assign(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Assign_R(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Eq(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Lt(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_LtEq(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Gt(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_GtEq(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Not(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_NotEq(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Number(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_String(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Identifier(const EidosASTNode *p_node);\n\tinline __attribute__((always_inline)) EidosValue *Evaluate_Identifier_RAW(const EidosASTNode *p_node)\n\t{\n\t\t// this is a fast inline version of Evaluate_Identifier() that returns a raw EidosValue *\n\t\t// it also skips call logging (in DEBUG and SLiMgui), and assumes no value is cached (because\n\t\t// this code path is used when the expectation is that we're fetching an object from the symbol table)\n\t\t// use a cached value from EidosASTNode::_OptimizeConstants() if present\n\t\t\n\t\treturn global_symbols_->GetValueRawOrRaiseForASTNode(p_node);\t// raises if undefined\n\t}\n\tEidosValue_SP Evaluate_If(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Do(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_While(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_For(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Next(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Break(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_Return(const EidosASTNode *p_node);\n\tEidosValue_SP Evaluate_FunctionDecl(const EidosASTNode *p_node);\n\t\n\t// Function dispatch/execution; these are implemented in eidos_functions.cpp\n\tstatic const std::vector<EidosFunctionSignature_CSP> &BuiltInFunctions(void);\n\tstatic inline __attribute__((always_inline)) const EidosFunctionMap *BuiltInFunctionMap(void) { return s_built_in_function_map_; }\n\tstatic void CacheBuiltInFunctionMap(void);\t// must be called by Eidos_WarmUp() before BuiltInFunctionMap() is called\n\t\n\t// Utility static methods for numeric conversions\n\tstatic int64_t NonnegativeIntegerForString(const std::string &p_number_string, const EidosToken *p_blame_token);\n\tstatic double FloatForString(const std::string &p_number_string, const EidosToken *p_blame_token);\n\tstatic EidosValue_SP NumericValueForString(const std::string &p_number_string, const EidosToken *p_blame_token);\n\t\n\t// An inline function for super-fast node evaluation, skipping EvaluateNode()\n\tinline __attribute__((always_inline)) EidosValue_SP FastEvaluateNode(const EidosASTNode *p_node)\n\t{\n\t\t// We should have cached p_node->cached_evaluator.  If not, the call below will simply crash with a zero deref, which\n\t\t// is sufficiently diagnostic given that it should never happen.  The if() slows us down quite a bit!\n\t\t\n\t\t//if (p_node->cached_evaluator)\n\t\t\treturn (this->*(p_node->cached_evaluator_))(p_node);\n\t\t//else\n\t\t//\treturn EvaluateNode(p_node);\n\t}\n\t\n\t// Support for tick range expression parsing; see Community::_EvaluateTickRangeNode()\n\tbool UseCustomUndefinedIdentifierRaise(void) { return use_custom_undefined_identifier_raise_; }\n\tvoid SetUseCustomUndefinedIdentifierRaise(bool p_flag) { use_custom_undefined_identifier_raise_ = p_flag; }\n\t\n\tbool UseCustomUndefinedFunctionRaise(void) { return use_custom_undefined_function_raise_; }\n\tvoid SetUseCustomUndefinedFunctionRaise(bool p_flag) { use_custom_undefined_function_raise_ = p_flag; }\n};\n\n\n#endif /* defined(__Eidos__eidos_interpreter__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_intrusive_ptr.h",
    "content": "//\n//  eidos_intrusive_ptr.h\n//  Eidos\n//\n//  Created by Ben Haller on 9/25/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n//\tEidos_intrusive_ptr is adapted from Boost's intrusive_ptr.hpp, version 1.59.0.\n//\tThat distribution was commented as follows:\n//\n//  Copyright (c) 2001, 2002 Peter Dimov\n//\n// Distributed under the Boost Software License, Version 1.0. See\n// accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt\n\n\n// Apropos of that, the Boost Software License Version 1.0 is as follows:\n\n/*\n\tBoost Software License - Version 1.0 - August 17th, 2003\n\n\tPermission is hereby granted, free of charge, to any person or organization\n\tobtaining a copy of the software and accompanying documentation covered by\n\tthis license (the \"Software\") to use, reproduce, display, distribute,\n\texecute, and transmit the Software, and to prepare derivative works of the\n\tSoftware, and to permit third-parties to whom the Software is furnished to\n\tdo so, all subject to the following:\n\n\tThe copyright notices in the Software and this entire statement, including\n\tthe above license grant, this restriction and the following disclaimer,\n\tmust be included in all copies of the Software, in whole or in part, and\n\tall derivative works of the Software, unless such copies or derivative\n\tworks are solely in the form of machine-executable object code generated by\n\ta source language processor.\n\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n\tFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n\tSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n\tFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n\tARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n\tDEALINGS IN THE SOFTWARE.\n*/\n\n// This source file has been derived from Boost's intrusive_ptr.hpp and\n// intrusive_ref_counter.hpp in accordance with this license.\n\n\n#ifndef __Eidos__eidos_intrusive_ptr_h\n#define __Eidos__eidos_intrusive_ptr_h\n\n#include <ostream>\n\n\n//\n//  Eidos_intrusive_ptr\n//\n//  A smart pointer that uses intrusive reference counting.\n//\n//  Relies on unqualified calls to\n//  \n//      void Eidos_intrusive_ptr_add_ref(T * p);\n//      void Eidos_intrusive_ptr_release(T * p);\n//\n//          (p != 0)\n//\n//  The object is responsible for destroying itself.\n//\n\ntemplate<class T> class Eidos_intrusive_ptr\n{\nprivate:\n\t\n\ttypedef Eidos_intrusive_ptr this_type;\n\t\npublic:\n\t\n\ttypedef T element_type;\n\t\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr() : px( 0 )\n\t{\n\t}\n\t\n\texplicit inline __attribute__((always_inline)) Eidos_intrusive_ptr( T * p, bool add_ref = true ): px( p )\n\t{\n\t\tif( px != 0 && add_ref ) Eidos_intrusive_ptr_add_ref( px );\n\t}\n\t\n\ttemplate<class U>\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr( Eidos_intrusive_ptr<U> const & rhs ) : px( rhs.get() )\n\t{\n\t\tif( px != 0 ) Eidos_intrusive_ptr_add_ref( px );\n\t}\n\t\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr(Eidos_intrusive_ptr const & rhs): px( rhs.px )\n\t{\n\t\tif( px != 0 ) Eidos_intrusive_ptr_add_ref( px );\n\t}\n\t\n\tinline __attribute__((always_inline)) ~Eidos_intrusive_ptr()\n\t{\n\t\tif( px != 0 ) Eidos_intrusive_ptr_release( px );\n\t}\n\t/*\n\t // I think I don't need/want this...\n\ttemplate<class U> Eidos_intrusive_ptr & operator=(Eidos_intrusive_ptr<U> const & rhs)\n\t{\n\t\tthis_type(rhs).swap(*this);\n\t\treturn *this;\n\t}\n\t*/\n\t// Move support\n\t\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr(Eidos_intrusive_ptr && rhs) : px( rhs.px )\n\t{\n\t\trhs.px = 0;\n\t}\n\t\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr & operator=(Eidos_intrusive_ptr && rhs)\n\t{\n\t\tthis_type( static_cast< Eidos_intrusive_ptr && >( rhs ) ).swap(*this);\n\t\treturn *this;\n\t}\n\t\n\tinline __attribute__((always_inline)) Eidos_intrusive_ptr & operator=(Eidos_intrusive_ptr const & rhs)\n\t{\n\t\tthis_type(rhs).swap(*this);\n\t\treturn *this;\n\t}\n\t/*\n\t // I think I don't need/want this...\n\tEidos_intrusive_ptr & operator=(T * rhs)\n\t{\n\t\tthis_type(rhs).swap(*this);\n\t\treturn *this;\n\t}\n\t*/\n\tinline __attribute__((always_inline)) void reset()\n\t{\n\t\tthis_type().swap( *this );\n\t}\n\t\n\tinline __attribute__((always_inline)) void reset( T * rhs )\n\t{\n\t\tthis_type( rhs ).swap( *this );\n\t}\n\t\n\tinline __attribute__((always_inline)) void reset( T * rhs, bool add_ref )\n\t{\n\t\tthis_type( rhs, add_ref ).swap( *this );\n\t}\n\t\n\tinline __attribute__((always_inline)) T * get() const\n\t{\n\t\treturn px;\n\t}\n\t\n\tinline __attribute__((always_inline)) T * detach()\n\t{\n\t\tT * ret = px;\n\t\tpx = 0;\n\t\treturn ret;\n\t}\n\t\n\tinline __attribute__((always_inline)) T & operator*() const\n\t{\n\t\treturn *px;\n\t}\n\t\n\tinline __attribute__((always_inline)) T * operator->() const\n\t{\n\t\treturn px;\n\t}\n\t\n\t// implicit conversion to \"bool\", from boost/smart_ptr/detail/operator_bool.hpp\n\t\n\tinline __attribute__((always_inline)) explicit operator bool () const\n\t{\n\t\treturn px != 0;\n\t}\n\t\n\tinline __attribute__((always_inline)) bool operator! () const\n\t{\n\t\treturn px == 0;\n\t}\n\t\n\tinline __attribute__((always_inline)) void swap(Eidos_intrusive_ptr & rhs)\n\t{\n\t\tT * tmp = px;\n\t\tpx = rhs.px;\n\t\trhs.px = tmp;\n\t}\n\t\nprivate:\n\t\n\tT * px;\n};\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator==(Eidos_intrusive_ptr<T> const & a, Eidos_intrusive_ptr<U> const & b)\n{\n\treturn a.get() == b.get();\n}\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator!=(Eidos_intrusive_ptr<T> const & a, Eidos_intrusive_ptr<U> const & b)\n{\n\treturn a.get() != b.get();\n}\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator==(Eidos_intrusive_ptr<T> const & a, U * b)\n{\n\treturn a.get() == b;\n}\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator!=(Eidos_intrusive_ptr<T> const & a, U * b)\n{\n\treturn a.get() != b;\n}\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator==(T * a, Eidos_intrusive_ptr<U> const & b)\n{\n\treturn a == b.get();\n}\n\ntemplate<class T, class U> inline __attribute__((always_inline)) bool operator!=(T * a, Eidos_intrusive_ptr<U> const & b)\n{\n\treturn a != b.get();\n}\n\ntemplate<class T> inline __attribute__((always_inline)) bool operator<(Eidos_intrusive_ptr<T> const & a, Eidos_intrusive_ptr<T> const & b)\n{\n\treturn std::less<T *>()(a.get(), b.get());\n}\n\ntemplate<class T> void swap(Eidos_intrusive_ptr<T> & lhs, Eidos_intrusive_ptr<T> & rhs)\n{\n\tlhs.swap(rhs);\n}\n\n// mem_fn support\n\ntemplate<class T> inline __attribute__((always_inline)) T * get_pointer(Eidos_intrusive_ptr<T> const & p)\n{\n\treturn p.get();\n}\n\ntemplate<class T, class U> Eidos_intrusive_ptr<T> static_pointer_cast(Eidos_intrusive_ptr<U> const & p)\n{\n\treturn static_cast<Eidos_intrusive_ptr<T>>(static_cast<T *>(p.get()));\n}\n\ntemplate<class T, class U> Eidos_intrusive_ptr<T> const_pointer_cast(Eidos_intrusive_ptr<U> const & p)\n{\n\treturn static_cast<Eidos_intrusive_ptr<T>>(const_cast<T *>(p.get()));\n}\n\ntemplate<class T, class U> Eidos_intrusive_ptr<T> dynamic_pointer_cast(Eidos_intrusive_ptr<U> const & p)\n{\n\treturn static_cast<Eidos_intrusive_ptr<T>>(dynamic_cast<T *>(p.get()));\n}\n\n// operator<<\n\ntemplate<class Y> std::ostream & operator<< (std::ostream & os, Eidos_intrusive_ptr<Y> const & p)\n{\n\tos << p.get();\n\treturn os;\n}\n\n\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_object_pool.h",
    "content": "//\n//  eidos_object_pool.h\n//  Eidos\n//\n//  Created by Ben Haller on 9/28/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This is a modified version of an object pool published by Paulo Zemek at\n http://www.codeproject.com/Articles/746630/O-Object-Pool-in-Cplusplus .\n His code is published under the Code Project Open License (CPOL), available\n at http://www.codeproject.com/info/cpol10.aspx .  The CPOL is not compatible\n with the GPL.  Paulo Zemek has explicitly granted permission for his code\n to be used in Eidos and SLiM, and thus placed under the GPL as an alternative\n license.  An email granting this permission has been archived and can be\n provided upon request.  This code is therefore now under the same GPL license\n as the rest of SLiM and Eidos, as stated above.\n \n */\n\n\n#ifndef __Eidos__eidos_object_pool_h\n#define __Eidos__eidos_object_pool_h\n\n#include <stdexcept>\n\n#include \"eidos_openmp.h\"\n\n\nclass EidosObjectPool\n{\nprivate:\n\tstruct _Node\n\t{\n\t\tvoid *_memory;\n\t\tsize_t _capacity;\n\t\t_Node *_nextNode;\n\t\t\n\t\t_Node(size_t capacity, size_t itemSize)\n\t\t{\n\t\t\tif (capacity < 1)\n\t\t\t\tthrow std::invalid_argument(\"capacity must be at least 1.\");\n\t\t\t\n\t\t\t_memory = malloc(itemSize * capacity);\n\t\t\tif (_memory == NULL)\n\t\t\t\tthrow std::bad_alloc();\n\t\t\t\n\t\t\t_capacity = capacity;\n\t\t\t_nextNode = NULL;\n\t\t}\n\t\t~_Node()\n\t\t{\n\t\t\tfree(_memory);\n\t\t}\n\t};\n\t\n\tstd::string _name;\t\t\t// a client-provided name to identify the pool in debug output\n\tconst size_t _itemSize;\n\t\n\tvoid *_nodeMemory;\n\tvoid *_firstDeleted;\n\tsize_t _countInNode;\n\tsize_t _nodeCapacity;\n\t_Node _firstNode;\n\t_Node *_lastNode;\n\tsize_t _maxBlockLength;\n\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t// We do not arbitrate access to EidosObjectPool with a lock; instead, we expect that clients\n\t// will manage their own multithreading issues.  In DEBUG mode we check for incorrect uses (races).\n\tEidosDebugLock _object_pool_LOCK;\n#endif\n\t\n\tvoid _AllocateNewNode()\n\t{\n\t\t// Determine the number of chunks in the new node\n\t\tsize_t size = _countInNode;\n\t\t\n\t\tif (size >= _maxBlockLength)\n\t\t{\n\t\t\tsize = _maxBlockLength;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsize *= 2;\n\t\t\t\n\t\t\tif (size < _countInNode)\n\t\t\t\tthrow std::overflow_error(\"size became too big.\");\n\t\t\t\n\t\t\tif (size >= _maxBlockLength)\n\t\t\t\tsize = _maxBlockLength;\n\t\t}\n\t\t\n\t\t// Allocate the new node\n\t\t_Node *newNode = new _Node(size, _itemSize);\n\t\t\n\t\t// Link the new node in to our linked list\n\t\t_lastNode->_nextNode = newNode;\n\t\t_lastNode = newNode;\n\t\t\n\t\t// Set up to allocate out of the new node\n\t\t_nodeMemory = newNode->_memory;\n\t\t_countInNode = 0;\n\t\t_nodeCapacity = size;\n\t}\n\t\npublic:\n\tEidosObjectPool(const EidosObjectPool &) = delete;\t\t\t\t\t// no copy-construct\n\tEidosObjectPool &operator=(const EidosObjectPool &) = delete;\t\t// no copying\n\t\n\t// BCH 11 Sept. 2019: changing the default maxBlockLength to a power of two, and more importantly,\n\t// enforcing maxBlockLength even on _firstNode to avoid bad allocs on systems where the max malloc\n\t// size is restricted (such as Debian, apparently); see GitHub issue #54.\n\texplicit EidosObjectPool(const char *name, size_t itemSize, size_t initialCapacity=1024, size_t maxBlockLength=1048576) : _name(name), _itemSize(itemSize), _firstDeleted(nullptr), _countInNode(0), _nodeCapacity(initialCapacity > maxBlockLength ? maxBlockLength : initialCapacity), _firstNode(_nodeCapacity, itemSize), _maxBlockLength(maxBlockLength)\n#ifdef DEBUG_LOCKS_ENABLED\n\t, _object_pool_LOCK(name)\n#endif\n\t{\n\t\tif (maxBlockLength < 1)\n\t\t\tthrow std::invalid_argument(\"maxBlockLength must be at least 1.\");\n\t\t\n\t\t_nodeMemory = _firstNode._memory;\n\t\t_lastNode = &_firstNode;\n\t}\n\t\n\t~EidosObjectPool()\n\t{\n\t\t_Node *node = _firstNode._nextNode;\n\t\twhile(node)\n\t\t{\n\t\t\t_Node *nextNode = node->_nextNode;\n\t\t\tdelete node;\n\t\t\tnode = nextNode;\n\t\t}\n\t}\n\t\n\tsize_t MemoryUsageForAllNodes(void)\n\t{\n\t\tsize_t usage = 0;\n\t\t_Node *node = &_firstNode;\n\t\twhile(node)\n\t\t{\n\t\t\t_Node *nextNode = node->_nextNode;\n\t\t\tusage += node->_capacity * _itemSize;\n\t\t\tnode = nextNode;\n\t\t}\n\t\treturn usage;\n\t}\n\t\n\t// usage: new (gXPool->AllocateChunk()) ObjectType(... parameters ...);\n\tinline __attribute__((always_inline)) void *AllocateChunk()\n\t{\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t_object_pool_LOCK.start_critical(0);\n#endif\n\t\t\n\t\tif (_firstDeleted)\n\t\t{\n\t\t\tvoid *result = _firstDeleted;\n\t\t\t_firstDeleted = *((void **)_firstDeleted);\n\t\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t\t_object_pool_LOCK.end_critical();\n#endif\n\t\t\treturn result;\n\t\t}\n\t\t\n\t\tif (_countInNode >= _nodeCapacity)\n\t\t\t_AllocateNewNode();\n\t\t\n\t\tuint8_t *address = (uint8_t *)_nodeMemory;\n\t\taddress += _countInNode * _itemSize;\n\t\t_countInNode++;\n\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t_object_pool_LOCK.end_critical();\n#endif\n\t\treturn (void *)address;\n\t}\n\t\n\t// usage:\n\t//\n\t//\tobject->~ObjectType();\n\t//\tgXPool->DisposeChunk(const_cast<ObjectType*>(object));\n\tinline __attribute__((always_inline)) void DisposeChunk(void *content)\n\t{\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t_object_pool_LOCK.start_critical(1);\n#endif\n\t\t\n\t\t*((void **)content) = _firstDeleted;\n\t\t_firstDeleted = content;\n\t\t\n#ifdef DEBUG_LOCKS_ENABLED\n\t\t_object_pool_LOCK.end_critical();\n#endif\n\t}\n};\n\n\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_openmp.h",
    "content": "//\n//  eidos_openmp.h\n//  SLiM_OpenMP\n//\n//  Created by Benjamin C. Haller on 8/4/20.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This header should be included instead of omp.h.  It will include omp.h only if we are doing a parallel build of SLiM;\n otherwise, it will provide inline stub implementations of the OpenMP API.  We require OpenMP 4.5.\n \n Some basic instructions for building and using parallel SLiM (spelled out more in the manual):\n \n\t on macOS, Apple has disabled OpenMP support in the version of clang they ship, and they do not include the OpenMP library or headers (WTF), so this needs to be fixed to build\n\t\t first of all, the R folks have figured this out; see https://mac.r-project.org/openmp/ for information and downloads\n\t\t do \"About Xcode\" to find out the Xcode version you're using, and download the corresponding openmp (\"Release\", probably) from that web page\n\t\t install it as shown there (\"sudo tar fvxz <file>.tar.gz -C /\"); you may see \"tar: Error exit delayed from previous errors\" which seems to be fine\n\t\t the rest of that web page is R-specific and can be ignored\n\t\t note that we used to use MacPorts or Homebrew to install a separate version of clang; it seems better to use the native clang and patch it up as we do now, but this no longer links in libomp automatically\n\t on other platforms, you may need to get a newer/different compiler to get one with OpenMP support; we have targeted OpenMP 4.5 as a minimum for now\n\t\t if you need to use a different compiler, you may need to switch CMake over to using that compiler, etc.\n\t\t you may also need to install the OpenMP library if it doesn't come installed for your toolchain; and the paths for the includes and libomp might be different than in CMakeLists.txt\n\t\t if you figure how to make this work for a particular platform, please send us step-by-step instructions that we can share with other users!\n\t if building at the command line with CMake, set -DPARALLEL=ON, and do not build SLiMgui (it will error out)\n\t if building in Xcode, use the provided separate version of the project, SLiM_OpenMP.xcodeproj, and the separate targets eidos_multi and slim_multi\n\t with -DPARALLEL=ON, the built executables will be slim_multi and eidos_multi, to make it easier to distinguish them; but of course you may rename them as you see fit\n\t on macOS, you may (several times!) get a system alert that libomp was blocked for security; after that, go to System Preferences, Security & Privacy, tab General, click \"Allow Anyway\", and then click \"Open\" back in the system panel\n\t use the -maxThreads <x> command-line option to change the maximum number of threads from OpenMP's default\n\n We allocate per-thread storage (for gEidosMaxThreads threads) at the global/species level for these facilities:\n \n\tSparseVector pools; see s_freed_sparse_vectors_PERTHREAD vs. s_freed_sparse_vectors_SINGLE\n\trandom number generators; see gEidos_RNG_PERTHREAD vs. gEidos_RNG_SINGLE\n\tMutationRunContexts; see mutation_run_context_PERTHREAD vs. mutation_run_SINGLE\n \n We use #pragma omp critical to protect some places in the code, with specified names\n \n Places in the code that cannot be encountered when parallel use THREAD_SAFETY macros, defined below,\n as a runtime guard; but be aware that it only checks for Debug builds.  Release builds may just produce\n race conditions or incorrect results with no warning or error.  Always check with a Debug build.\n \n */\n\n#ifndef eidos_openmp_h\n#define eidos_openmp_h\n\n#include <signal.h>\n#include <limits.h>\n#include <errno.h>\n#include <string.h>\n#include <iostream>\n\n\n/*\n *\tFor simplicity, ongoing work related to the parallelization of SLiM with OpenMP now resides in the master branch.\n *\tHowever, multithreaded SLiM is not released, not thoroughly tested, and generally not yet ready for prime time.\n *\tIt is not recommended for end-user use, especially not for \"production\" runs, and the documentation for it is\n *\tnot yet public.  Please do not ask for any kind of support for this feature if you choose to experiment with it.\n *\n *\t\t- BCH 12/4/2023\n */\n#ifdef _OPENMP\n#error Building multithreaded SLiM is presently disabled and unsupported.  This feature is still under development.\n#endif\n\n\n// This is the largest number of threads we allow the user to set.  There is no hard limit in the code;\n// this is primarily just to prevent people from doing anything stupid.\n#define EIDOS_OMP_MAX_THREADS\t1024\n\n// This is a cached result from omp_get_max_threads() after warmup, providing the final number of threads that we will\n// be using (maximum) in parallel regions.  This can be used to preallocate per-thread data structures.\nextern int gEidosMaxThreads;\n\n// This is the number of threads that will be used in the next parallel region to execute, as set by the Eidos\n// function parallelSetNumThreads().  This will generally be equal to omp_get_max_threads().  It will be clamped\n// to the interval [1, gEidosMaxThreads].  If it has been set explicitly, gEidosNumThreadsOverride is set to true;\n// if not, gEidosNumThreadsOverride is false.  This allows Eidos to distinguish between gEidosNumThreads == gEidosMaxThreads\n// simply because it hasn't been set (gEidosNumThreadsOverride == false), indicating a desire to receive the default\n// number of threads, versus having been explicitly set to gEidosMaxThreads (gEidosNumThreadsOverride == true),\n// indicating a desire to force the maximum number of threads to be used even if it normally wouldn't.\nextern int gEidosNumThreads;\nextern bool gEidosNumThreadsOverride;\n\n\n// We want to use SIGTRAP to catch problems in the debugger in a few key spots, but it doesn't exist on Windows.\n// So we will just define SIGTRAP to be SIGABRT instead; SIGABRT is supported on Windows.\n#ifdef _WIN32\n#define SIGTRAP SIGABRT\n#endif\n\n\n// Thread safety checking: places in the code that have identified thread safety concerns should use this macro.  It will\n// produce a runtime error for DEBUG builds if it is hit while parallel.  Put it in places that are not currently thread-safe.\n// For example, object pools and other such global state are not thread-safe right now, so they should use this.\n// Many of these places might be made safe with a simple locking protocol, but that has not yet been done, so beware.\n// This tagging of unsafe spots is undoubtedly not comprehensive; I'm just trying to catch the most obvious problems!\n// Note that this macro uses a GCC built-in; it is supported by Clang as well, but may need a tweak for other platforms.\n// This macro checks only for DEBUG builds!  When working on parallel code, be sure to check correctness with DEBUG!\n//\n// BCH 5/14/2023: We now have two versions of this, because there are two checks one might want to do:\n//\n//\t\tTHREAD_SAFETY_IN_ANY_PARALLEL() - errors if inside a parallel region, even if inactive (i.e., running with\n//\t\t\tonly one thread).  This is particularly relevant for code that is known to raise without protection,\n//\t\t\tand particularly, for code that executes Eidos lambda/callback code without protection.  It is also\n//\t\t\tuseful for code that, semantically, should just never be inside a parallel region at all.  Some\n//\t\t\tparts of the Eidos interpreter fall into this category.\n//\n//\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL() - errors if inside an active (i.e., multithreaded) parallel region.\n//\t\t\tThis is particularly relevant for code that is not thread-safe due to use of statics, presence of races,\n//\t\t\tetc.; the code is fine run-single-threaded, even in an inactive parallel region.  Some parts of the\n//\t\t\tEidos interpreter fall into this category, because we sometimes want to use the same code path for\n//\t\t\tboth single-threaded and multi-threaded execution when running under OpenMP, and that can mean that\n//\t\t\tEidos code ends up running inside an inactive parallel region.  Any code that does this must be prepared\n//\t\t\tto catch throws coming out of the Eidos interpreter, however, since they must be caught inside the\n//\t\t\tparallel region!\n\n#ifdef _OPENMP\n\n#if DEBUG\n#define THREAD_SAFETY_IN_ACTIVE_PARALLEL(s) if (omp_in_parallel()) { std::cerr << \"THREAD_SAFETY_IN_ACTIVE_PARALLEL error in \" << s; raise(SIGTRAP); }\n#define THREAD_SAFETY_IN_ANY_PARALLEL(s) if (omp_get_level() > 0) { std::cerr << \"THREAD_SAFETY_IN_ANY_PARALLEL error in \" << s; raise(SIGTRAP); }\n#else\n#define THREAD_SAFETY_IN_ACTIVE_PARALLEL(s)\t{ ; }\n#define THREAD_SAFETY_IN_ANY_PARALLEL(s)\t{ ; }\n#endif\n\n#else\n\n#define THREAD_SAFETY_IN_ACTIVE_PARALLEL(s)\t{ ; }\n#define THREAD_SAFETY_IN_ANY_PARALLEL(s)\t{ ; }\n\n#endif\n\n\n// This macro is for calculating the correct number of threads to use for a given loop; it uses a thread count set with\n// parallelSetNumThreads() if it exists, otherwise uses the thread count provided by (x), expected to be <= gEidosMaxThreads.\n#ifdef _OPENMP\n#define EIDOS_THREAD_COUNT(x) int thread_count = (gEidosNumThreadsOverride ? gEidosNumThreads : (x))\n#else\n#define EIDOS_THREAD_COUNT(x)\n#endif\n\n\n#ifdef _OPENMP\n\n// Check that the OpenMP version supported by the compiler suffices.  Note that _OPENMP is formatted as a \"YYYYMM\" date of\n// release.  See https://github.com/Kitware/CMake/blob/v3.16.3/Modules/FindOpenMP.cmake#L384 for dates of release.  For\n// quick reference, \"200805=3.0\", \"201107=3.1\", \"201307=4.0\", \"201511=4.5\", \"201811=5.0\".  Right now we require 4.5.\n#if (_OPENMP < 201511)\n#error OpenMP version 4.5 or later is required.\n#endif\n\n// We're building SLiM for running in parallel, and OpenMP is present; include the header.\n#include \"omp.h\"\n\n// C++ wrappers for OpenMP's lock types.  For now we define these only in the OpenMP case, not with the stubs below for\n// the non-OpenMP case, to encourage this to be used only when we are multithreading, to avoid single-threaded overhead.\n// The big benefit to using these classes is that you get automatic RAII construction/destruction of the lock.\nclass OMPLock\n{\npublic:\n\tOMPLock() { omp_init_lock(&lock_); }\n\t~OMPLock() { omp_destroy_lock(&lock_); }\n\t\n\tvoid set() { omp_set_lock(&lock_); }\n\tvoid unset() { omp_unset_lock(&lock_); }\n\tint test() { return omp_test_lock(&lock_); }\t\t// true (non-zero) if the lock was obtained\n\t\nprivate:\n\tomp_lock_t lock_;\n};\n\nclass OMPNestLock\n{\npublic:\n\tOMPNestLock() { omp_init_nest_lock(&lock_); }\n\t~OMPNestLock() { omp_destroy_nest_lock(&lock_); }\n\t\n\tvoid set() { omp_set_nest_lock(&lock_); }\n\tvoid unset() { omp_unset_nest_lock(&lock_); }\n\tint test() { return omp_test_nest_lock(&lock_); }\t// true (non-zero) if the lock was obtained\n\t\nprivate:\n\tomp_nest_lock_t lock_;\n};\n\n// This is a lock-based class used in DEBUG builds to test for race conditions involving code that is not locked\n// or otherwise arbitrated.  The expectation is that only one thread at a time will be executing in regions\n// governed by a debug lock, but that is not enforced; it is supposed to be a consequence of the design of the code\n// itself.  This class makes it easy to check for race conditions involving such regions.\n#if (defined(_OPENMP) && DEBUG)\n#define DEBUG_LOCKS_ENABLED\n\nclass EidosDebugLock\n{\npublic:\n\tEidosDebugLock() = delete;\n\tEidosDebugLock(const char *p_name) : lock_name_(p_name) { omp_init_nest_lock(&lock_); }\n\t~EidosDebugLock() { omp_destroy_nest_lock(&lock_); }\n\t\n\tvoid start_critical(int p_owner) {\n\t\tint result = omp_test_nest_lock(&lock_);\n\t\t\n\t\tif (!result)\n\t\t{\n\t\t\t// We did not get the lock; somebody else is using the same resource.  This is a fatal error.\n\t\t\tstd::cerr << \"race with \" << lock_name_ << \": EidosDebugLock owner == \" << owner_ << \", racing owner == \" << p_owner << std::endl;\n\t\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosDebugLock::start_critical(): race condition hit!\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We got the lock; mark our turf so if somebody races with us they know who got the lock first\n#pragma omp atomic write\n\t\t\towner_ = p_owner;\n\t\t\tcurrent_nest_ = result;\n\t\t}\n\t}\n\tvoid end_critical() {\n\t\tif (current_nest_ == 1)\n\t\t{\n#pragma omp atomic write\n\t\t\towner_ = -1;\n\t\t}\n\t\t--current_nest_;\n\t\tomp_unset_nest_lock(&lock_);\n\t}\n\t\nprivate:\n\tomp_nest_lock_t lock_;\n\tstd::string lock_name_;\t\t\t// a client-defined string name for the lock, to identify it in debug output\n\tint owner_ = -1;\t\t\t\t// a client-defined integer value identifying which code region has taken the lock\n\tint current_nest_ = 0;\t\t\t// the current nesting count, so we know if we're about to unlock\n};\n#endif\n\n\n// Define minimum counts for all the parallel loops we use.  Some of these loops are in SLiM, so we violate encapsulation\n// here a bit; a slim_openmp.h header could be created to alleviate that if it's a problem, but it seems harmless for now.\n// These counts are collected in one place to make it easier to optimize their values in a pre-build optimization pass.\n\n// Set this flag to 0 to switch to running parallel loops with the maximum number of threads, regardless of the per-task\n// default thread counts or the task size thresholds (but not regardless of the user's parallelSetNumThreads() setting).\n#define USE_OMP_LIMITS\t1\n\n#if USE_OMP_LIMITS\n// This set of minimum counts is for production code\n\n// Eidos: math functions\n#define EIDOS_OMPMIN_ABS_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_CEIL\t\t\t\t\t2000\n#define EIDOS_OMPMIN_EXP_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_FLOOR\t\t\t\t\t2000\n#define EIDOS_OMPMIN_LOG_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_LOG10_FLOAT\t\t\t2000\n#define EIDOS_OMPMIN_LOG2_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_ROUND\t\t\t\t\t2000\n#define EIDOS_OMPMIN_SQRT_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_SUM_INTEGER\t\t\t2000\n#define EIDOS_OMPMIN_SUM_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_SUM_LOGICAL\t\t\t6000\n#define EIDOS_OMPMIN_TRUNC\t\t\t\t\t2000\n\n// Eidos: max(), min(), pmax(), pmin()\n#define EIDOS_OMPMIN_MAX_INT\t\t\t\t2000\n#define EIDOS_OMPMIN_MAX_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_MIN_INT\t\t\t\t2000\n#define EIDOS_OMPMIN_MIN_FLOAT\t\t\t\t2000\n#define EIDOS_OMPMIN_PMAX_INT_1\t\t\t\t2000\n#define EIDOS_OMPMIN_PMAX_INT_2\t\t\t\t2000\n#define EIDOS_OMPMIN_PMAX_FLOAT_1\t\t\t2000\n#define EIDOS_OMPMIN_PMAX_FLOAT_2\t\t\t2000\n#define EIDOS_OMPMIN_PMIN_INT_1\t\t\t\t2000\n#define EIDOS_OMPMIN_PMIN_INT_2\t\t\t\t2000\n#define EIDOS_OMPMIN_PMIN_FLOAT_1\t\t\t2000\n#define EIDOS_OMPMIN_PMIN_FLOAT_2\t\t\t2000\n\n// Eidos: match(), sample(), tabulate()\n#define EIDOS_OMPMIN_MATCH_INT\t\t\t\t2000\n#define EIDOS_OMPMIN_MATCH_FLOAT\t\t\t2000\n#define EIDOS_OMPMIN_MATCH_STRING\t\t\t2000\n#define EIDOS_OMPMIN_MATCH_OBJECT\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_INDEX\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_R_INT\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_R_FLOAT\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_R_OBJECT\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_WR_INT\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_WR_FLOAT\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_WR_OBJECT\t\t2000\n#define EIDOS_OMPMIN_TABULATE_MAXBIN\t\t2000\n#define EIDOS_OMPMIN_TABULATE\t\t\t\t2000\n\n// SLiM methods/properties\n#define EIDOS_OMPMIN_CONTAINS_MARKER_MUT\t900\n#define EIDOS_OMPMIN_I_COUNT_OF_MUTS_OF_TYPE\t2\n#define EIDOS_OMPMIN_G_COUNT_OF_MUTS_OF_TYPE\t2\n#define EIDOS_OMPMIN_INDS_W_PEDIGREE_IDS\t2000\n#define EIDOS_OMPMIN_RELATEDNESS\t\t\t2000\n#define EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_1\t2000\n#define EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_2\t2000\n#define EIDOS_OMPMIN_SET_FITNESS_SCALE_1\t900\n#define EIDOS_OMPMIN_SET_FITNESS_SCALE_2\t1500\n#define EIDOS_OMPMIN_SUM_OF_MUTS_OF_TYPE\t2\n\n// Distribution draws and related\n#define EIDOS_OMPMIN_DNORM_1\t\t\t\t10000\n#define EIDOS_OMPMIN_DNORM_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RBINOM_1\t\t\t\t10000\n#define EIDOS_OMPMIN_RBINOM_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RBINOM_3\t\t\t\t10000\n#define EIDOS_OMPMIN_RDUNIF_1\t\t\t\t10000\n#define EIDOS_OMPMIN_RDUNIF_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RDUNIF_3\t\t\t\t10000\n#define EIDOS_OMPMIN_REXP_1\t\t\t\t\t10000\n#define EIDOS_OMPMIN_REXP_2\t\t\t\t\t10000\n#define EIDOS_OMPMIN_RNORM_1\t\t\t\t10000\n#define EIDOS_OMPMIN_RNORM_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RNORM_3\t\t\t\t10000\n#define EIDOS_OMPMIN_RPOIS_1\t\t\t\t10000\n#define EIDOS_OMPMIN_RPOIS_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RUNIF_1\t\t\t\t10000\n#define EIDOS_OMPMIN_RUNIF_2\t\t\t\t10000\n#define EIDOS_OMPMIN_RUNIF_3\t\t\t\t10000\n\n// Sorting & ordering\n#define EIDOS_OMPMIN_SORT_INT\t\t\t\t4000\n#define EIDOS_OMPMIN_SORT_FLOAT\t\t\t\t4000\n#define EIDOS_OMPMIN_SORT_STRING\t\t\t4000\n\n// Spatial point/map manipulation\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_1D\t\t2000\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_2D\t\t2000\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_3D\t\t2000\n#define EIDOS_OMPMIN_POINT_PERIODIC_1D\t\t2000\n#define EIDOS_OMPMIN_POINT_PERIODIC_2D\t\t2000\n#define EIDOS_OMPMIN_POINT_PERIODIC_3D\t\t2000\n#define EIDOS_OMPMIN_POINT_REFLECTED_1D\t\t2000\n#define EIDOS_OMPMIN_POINT_REFLECTED_2D\t\t2000\n#define EIDOS_OMPMIN_POINT_REFLECTED_3D\t\t2000\n#define EIDOS_OMPMIN_POINT_STOPPED_1D\t\t2000\n#define EIDOS_OMPMIN_POINT_STOPPED_2D\t\t2000\n#define EIDOS_OMPMIN_POINT_STOPPED_3D\t\t2000\n#define EIDOS_OMPMIN_POINT_UNIFORM_1D\t\t2000\n#define EIDOS_OMPMIN_POINT_UNIFORM_2D\t\t2000\n#define EIDOS_OMPMIN_POINT_UNIFORM_3D\t\t2000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_1D\t10000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_2D\t10000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_3D\t10000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_1D\t10000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_2D\t10000\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_3D\t10000\n#define EIDOS_OMPMIN_SPATIAL_MAP_VALUE\t\t2000\n\n// Spatial queries\n#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S\t\t10000\n#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S\t\t10000\n//#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_3S\t\t10000\n#define EIDOS_OMPMIN_DRAWBYSTRENGTH\t\t\t10\n#define EIDOS_OMPMIN_INTNEIGHCOUNT\t\t\t10\n#define EIDOS_OMPMIN_LOCALPOPDENSITY\t\t10\n#define EIDOS_OMPMIN_NEARESTINTNEIGH\t\t10\n#define EIDOS_OMPMIN_NEARESTNEIGH\t\t\t10\n#define EIDOS_OMPMIN_NEIGHCOUNT\t\t\t\t10\n#define EIDOS_OMPMIN_TOTNEIGHSTRENGTH\t\t10\n\n// SLiM core\n#define EIDOS_OMPMIN_AGE_INCR\t\t\t\t10000\n#define EIDOS_OMPMIN_DEFERRED_REPRO\t\t\t100\n#define EIDOS_OMPMIN_WF_REPRO\t\t\t\t100\n#define EIDOS_OMPMIN_FITNESS_ASEX_1\t\t\t10000\n#define EIDOS_OMPMIN_FITNESS_ASEX_2\t\t\t10000\n#define EIDOS_OMPMIN_FITNESS_ASEX_3\t\t\t10000\n#define EIDOS_OMPMIN_FITNESS_SEX_1\t\t\t10000\n#define EIDOS_OMPMIN_FITNESS_SEX_2\t\t\t10000\n#define EIDOS_OMPMIN_FITNESS_SEX_3\t\t\t10000\n#define EIDOS_OMPMIN_MIGRANT_CLEAR\t\t\t10000\n#define EIDOS_OMPMIN_SIMPLIFY_SORT_PRE\t\t4000\n#define EIDOS_OMPMIN_SIMPLIFY_SORT\t\t\t4000\n#define EIDOS_OMPMIN_SIMPLIFY_SORT_POST\t\t4000\n#define EIDOS_OMPMIN_SURVIVAL\t\t\t\t10000\n\n#else\n// This set of minimum counts is for debugging; we want to run all self-tests in parallel, so that\n// bugs don't get masked just by virtue of the bug-inducing task being too small to run parallel\n#warning switch back to production minimum counts!\n\n// Eidos: math functions\n#define EIDOS_OMPMIN_ABS_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_CEIL\t\t\t\t\t0\n#define EIDOS_OMPMIN_EXP_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_FLOOR\t\t\t\t\t0\n#define EIDOS_OMPMIN_LOG_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_LOG10_FLOAT\t\t\t0\n#define EIDOS_OMPMIN_LOG2_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_ROUND\t\t\t\t\t0\n#define EIDOS_OMPMIN_SQRT_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_SUM_INTEGER\t\t\t0\n#define EIDOS_OMPMIN_SUM_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_SUM_LOGICAL\t\t\t0\n#define EIDOS_OMPMIN_TRUNC\t\t\t\t\t0\n\n// Eidos: max(), min(), pmax(), pmin()\n#define EIDOS_OMPMIN_MAX_INT\t\t\t\t0\n#define EIDOS_OMPMIN_MAX_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_MIN_INT\t\t\t\t0\n#define EIDOS_OMPMIN_MIN_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_PMAX_INT_1\t\t\t\t0\n#define EIDOS_OMPMIN_PMAX_INT_2\t\t\t\t0\n#define EIDOS_OMPMIN_PMAX_FLOAT_1\t\t\t0\n#define EIDOS_OMPMIN_PMAX_FLOAT_2\t\t\t0\n#define EIDOS_OMPMIN_PMIN_INT_1\t\t\t\t0\n#define EIDOS_OMPMIN_PMIN_INT_2\t\t\t\t0\n#define EIDOS_OMPMIN_PMIN_FLOAT_1\t\t\t0\n#define EIDOS_OMPMIN_PMIN_FLOAT_2\t\t\t0\n\n// Eidos: match(), sample(), tabulate()\n#define EIDOS_OMPMIN_MATCH_INT\t\t\t\t0\n#define EIDOS_OMPMIN_MATCH_FLOAT\t\t\t0\n#define EIDOS_OMPMIN_MATCH_STRING\t\t\t0\n#define EIDOS_OMPMIN_MATCH_OBJECT\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_INDEX\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_R_INT\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_R_FLOAT\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_R_OBJECT\t\t0\n#define EIDOS_OMPMIN_SAMPLE_WR_INT\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_WR_FLOAT\t\t0\n#define EIDOS_OMPMIN_SAMPLE_WR_OBJECT\t\t0\n#define EIDOS_OMPMIN_TABULATE_MAXBIN\t\t0\n#define EIDOS_OMPMIN_TABULATE\t\t\t\t0\n\n// SLiM methods/properties\n#define EIDOS_OMPMIN_CONTAINS_MARKER_MUT\t0\n#define EIDOS_OMPMIN_I_COUNT_OF_MUTS_OF_TYPE\t0\n#define EIDOS_OMPMIN_G_COUNT_OF_MUTS_OF_TYPE\t0\n#define EIDOS_OMPMIN_INDS_W_PEDIGREE_IDS\t0\n#define EIDOS_OMPMIN_RELATEDNESS\t\t\t0\n#define EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_1\t0\n#define EIDOS_OMPMIN_SAMPLE_INDIVIDUALS_2\t0\n#define EIDOS_OMPMIN_SET_FITNESS_SCALE_1\t0\n#define EIDOS_OMPMIN_SET_FITNESS_SCALE_2\t0\n#define EIDOS_OMPMIN_SUM_OF_MUTS_OF_TYPE\t0\n\n// Distribution draws and related\n#define EIDOS_OMPMIN_DNORM_1\t\t\t\t0\n#define EIDOS_OMPMIN_DNORM_2\t\t\t\t0\n#define EIDOS_OMPMIN_RBINOM_1\t\t\t\t0\n#define EIDOS_OMPMIN_RBINOM_2\t\t\t\t0\n#define EIDOS_OMPMIN_RBINOM_3\t\t\t\t0\n#define EIDOS_OMPMIN_RDUNIF_1\t\t\t\t0\n#define EIDOS_OMPMIN_RDUNIF_2\t\t\t\t0\n#define EIDOS_OMPMIN_RDUNIF_3\t\t\t\t0\n#define EIDOS_OMPMIN_REXP_1\t\t\t\t\t0\n#define EIDOS_OMPMIN_REXP_2\t\t\t\t\t0\n#define EIDOS_OMPMIN_RNORM_1\t\t\t\t0\n#define EIDOS_OMPMIN_RNORM_2\t\t\t\t0\n#define EIDOS_OMPMIN_RNORM_3\t\t\t\t0\n#define EIDOS_OMPMIN_RPOIS_1\t\t\t\t0\n#define EIDOS_OMPMIN_RPOIS_2\t\t\t\t0\n#define EIDOS_OMPMIN_RUNIF_1\t\t\t\t0\n#define EIDOS_OMPMIN_RUNIF_2\t\t\t\t0\n#define EIDOS_OMPMIN_RUNIF_3\t\t\t\t0\n\n// Sorting & ordering\n#define EIDOS_OMPMIN_SORT_INT\t\t\t\t0\n#define EIDOS_OMPMIN_SORT_FLOAT\t\t\t\t0\n#define EIDOS_OMPMIN_SORT_STRING\t\t\t0\n\n// Spatial point/map manipulation\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_1D\t\t0\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_2D\t\t0\n#define EIDOS_OMPMIN_POINT_IN_BOUNDS_3D\t\t0\n#define EIDOS_OMPMIN_POINT_PERIODIC_1D\t\t0\n#define EIDOS_OMPMIN_POINT_PERIODIC_2D\t\t0\n#define EIDOS_OMPMIN_POINT_PERIODIC_3D\t\t0\n#define EIDOS_OMPMIN_POINT_REFLECTED_1D\t\t0\n#define EIDOS_OMPMIN_POINT_REFLECTED_2D\t\t0\n#define EIDOS_OMPMIN_POINT_REFLECTED_3D\t\t0\n#define EIDOS_OMPMIN_POINT_STOPPED_1D\t\t0\n#define EIDOS_OMPMIN_POINT_STOPPED_2D\t\t0\n#define EIDOS_OMPMIN_POINT_STOPPED_3D\t\t0\n#define EIDOS_OMPMIN_POINT_UNIFORM_1D\t\t0\n#define EIDOS_OMPMIN_POINT_UNIFORM_2D\t\t0\n#define EIDOS_OMPMIN_POINT_UNIFORM_3D\t\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_1D\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_2D\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_1_3D\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_1D\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_2D\t0\n#define EIDOS_OMPMIN_SET_SPATIAL_POS_2_3D\t0\n#define EIDOS_OMPMIN_SPATIAL_MAP_VALUE\t\t0\n\n// Spatial queries\n#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_1S\t\t0\n#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_2S\t\t0\n//#define EIDOS_OMPMIN_CLIPPEDINTEGRAL_3S\t\t0\n#define EIDOS_OMPMIN_DRAWBYSTRENGTH\t\t\t0\n#define EIDOS_OMPMIN_INTNEIGHCOUNT\t\t\t0\n#define EIDOS_OMPMIN_LOCALPOPDENSITY\t\t0\n#define EIDOS_OMPMIN_NEARESTINTNEIGH\t\t0\n#define EIDOS_OMPMIN_NEARESTNEIGH\t\t\t0\n#define EIDOS_OMPMIN_NEIGHCOUNT\t\t\t\t0\n#define EIDOS_OMPMIN_TOTNEIGHSTRENGTH\t\t0\n\n// SLiM core\n#define EIDOS_OMPMIN_AGE_INCR\t\t\t\t0\n#define EIDOS_OMPMIN_DEFERRED_REPRO\t\t\t0\n#define EIDOS_OMPMIN_WF_REPRO\t\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_ASEX_1\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_ASEX_2\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_ASEX_3\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_SEX_1\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_SEX_2\t\t\t0\n#define EIDOS_OMPMIN_FITNESS_SEX_3\t\t\t0\n#define EIDOS_OMPMIN_MIGRANT_CLEAR\t\t\t0\n#define EIDOS_OMPMIN_SIMPLIFY_SORT_PRE\t\t0\n#define EIDOS_OMPMIN_SIMPLIFY_SORT\t\t\t0\n#define EIDOS_OMPMIN_SIMPLIFY_SORT_POST\t\t0\n#define EIDOS_OMPMIN_SURVIVAL\t\t\t\t0\n\n#endif\n\n\n// Here we declare variables that hold the number of threads we prefer to use for each parallel loop.\n// These have default values, which can be overridden with parallelSetTaskThreadCounts().\n\n// Eidos: math functions; benchmark section E\nextern int gEidos_OMP_threads_ABS_FLOAT;\nextern int gEidos_OMP_threads_CEIL;\nextern int gEidos_OMP_threads_EXP_FLOAT;\nextern int gEidos_OMP_threads_FLOOR;\nextern int gEidos_OMP_threads_LOG_FLOAT;\nextern int gEidos_OMP_threads_LOG10_FLOAT;\nextern int gEidos_OMP_threads_LOG2_FLOAT;\nextern int gEidos_OMP_threads_ROUND;\nextern int gEidos_OMP_threads_SQRT_FLOAT;\nextern int gEidos_OMP_threads_SUM_INTEGER;\nextern int gEidos_OMP_threads_SUM_FLOAT;\nextern int gEidos_OMP_threads_SUM_LOGICAL;\nextern int gEidos_OMP_threads_TRUNC;\n\n// Eidos: max(), min(), pmax(), pmin(); benchmark section X\nextern int gEidos_OMP_threads_MAX_INT;\nextern int gEidos_OMP_threads_MAX_FLOAT;\nextern int gEidos_OMP_threads_MIN_INT;\nextern int gEidos_OMP_threads_MIN_FLOAT;\nextern int gEidos_OMP_threads_PMAX_INT_1;\nextern int gEidos_OMP_threads_PMAX_INT_2;\nextern int gEidos_OMP_threads_PMAX_FLOAT_1;\nextern int gEidos_OMP_threads_PMAX_FLOAT_2;\nextern int gEidos_OMP_threads_PMIN_INT_1;\nextern int gEidos_OMP_threads_PMIN_INT_2;\nextern int gEidos_OMP_threads_PMIN_FLOAT_1;\nextern int gEidos_OMP_threads_PMIN_FLOAT_2;\n\n// Eidos: match(), sample(), tabulate(); benchmark section V\nextern int gEidos_OMP_threads_MATCH_INT;\nextern int gEidos_OMP_threads_MATCH_FLOAT;\nextern int gEidos_OMP_threads_MATCH_STRING;\nextern int gEidos_OMP_threads_MATCH_OBJECT;\nextern int gEidos_OMP_threads_SAMPLE_INDEX;\nextern int gEidos_OMP_threads_SAMPLE_R_INT;\nextern int gEidos_OMP_threads_SAMPLE_R_FLOAT;\nextern int gEidos_OMP_threads_SAMPLE_R_OBJECT;\nextern int gEidos_OMP_threads_SAMPLE_WR_INT;\nextern int gEidos_OMP_threads_SAMPLE_WR_FLOAT;\nextern int gEidos_OMP_threads_SAMPLE_WR_OBJECT;\nextern int gEidos_OMP_threads_TABULATE_MAXBIN;\nextern int gEidos_OMP_threads_TABULATE;\n\n// SLiM methods/properties; benchmark section C\nextern int gEidos_OMP_threads_CONTAINS_MARKER_MUT;\nextern int gEidos_OMP_threads_I_COUNT_OF_MUTS_OF_TYPE;\nextern int gEidos_OMP_threads_G_COUNT_OF_MUTS_OF_TYPE;\nextern int gEidos_OMP_threads_INDS_W_PEDIGREE_IDS;\nextern int gEidos_OMP_threads_RELATEDNESS;\nextern int gEidos_OMP_threads_SAMPLE_INDIVIDUALS_1;\nextern int gEidos_OMP_threads_SAMPLE_INDIVIDUALS_2;\nextern int gEidos_OMP_threads_SET_FITNESS_SCALE_1;\nextern int gEidos_OMP_threads_SET_FITNESS_SCALE_2;\nextern int gEidos_OMP_threads_SUM_OF_MUTS_OF_TYPE;\n\n// Distribution draws and related; benchmark section R\nextern int gEidos_OMP_threads_DNORM_1;\nextern int gEidos_OMP_threads_DNORM_2;\nextern int gEidos_OMP_threads_RBINOM_1;\nextern int gEidos_OMP_threads_RBINOM_2;\nextern int gEidos_OMP_threads_RBINOM_3;\nextern int gEidos_OMP_threads_RDUNIF_1;\nextern int gEidos_OMP_threads_RDUNIF_2;\nextern int gEidos_OMP_threads_RDUNIF_3;\nextern int gEidos_OMP_threads_REXP_1;\nextern int gEidos_OMP_threads_REXP_2;\nextern int gEidos_OMP_threads_RNORM_1;\nextern int gEidos_OMP_threads_RNORM_2;\nextern int gEidos_OMP_threads_RNORM_3;\nextern int gEidos_OMP_threads_RPOIS_1;\nextern int gEidos_OMP_threads_RPOIS_2;\nextern int gEidos_OMP_threads_RUNIF_1;\nextern int gEidos_OMP_threads_RUNIF_2;\nextern int gEidos_OMP_threads_RUNIF_3;\n\n// Sorting & ordering\nextern int gEidos_OMP_threads_SORT_INT;\nextern int gEidos_OMP_threads_SORT_FLOAT;\nextern int gEidos_OMP_threads_SORT_STRING;\n\n// Spatial point/map manipulation; benchmark section P\nextern int gEidos_OMP_threads_POINT_IN_BOUNDS_1D;\nextern int gEidos_OMP_threads_POINT_IN_BOUNDS_2D;\nextern int gEidos_OMP_threads_POINT_IN_BOUNDS_3D;\nextern int gEidos_OMP_threads_POINT_PERIODIC_1D;\nextern int gEidos_OMP_threads_POINT_PERIODIC_2D;\nextern int gEidos_OMP_threads_POINT_PERIODIC_3D;\nextern int gEidos_OMP_threads_POINT_REFLECTED_1D;\nextern int gEidos_OMP_threads_POINT_REFLECTED_2D;\nextern int gEidos_OMP_threads_POINT_REFLECTED_3D;\nextern int gEidos_OMP_threads_POINT_STOPPED_1D;\nextern int gEidos_OMP_threads_POINT_STOPPED_2D;\nextern int gEidos_OMP_threads_POINT_STOPPED_3D;\nextern int gEidos_OMP_threads_POINT_UNIFORM_1D;\nextern int gEidos_OMP_threads_POINT_UNIFORM_2D;\nextern int gEidos_OMP_threads_POINT_UNIFORM_3D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_1_1D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_1_2D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_1_3D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_2_1D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_2_2D;\nextern int gEidos_OMP_threads_SET_SPATIAL_POS_2_3D;\nextern int gEidos_OMP_threads_SPATIAL_MAP_VALUE;\n\n// Spatial queries; benchmark sections D and S\nextern int gEidos_OMP_threads_CLIPPEDINTEGRAL_1S;\nextern int gEidos_OMP_threads_CLIPPEDINTEGRAL_2S;\n//extern int gEidos_OMP_threads_CLIPPEDINTEGRAL_3S;\nextern int gEidos_OMP_threads_DRAWBYSTRENGTH;\nextern int gEidos_OMP_threads_INTNEIGHCOUNT;\nextern int gEidos_OMP_threads_LOCALPOPDENSITY;\nextern int gEidos_OMP_threads_NEARESTINTNEIGH;\nextern int gEidos_OMP_threads_NEARESTNEIGH;\nextern int gEidos_OMP_threads_NEIGHCOUNT;\nextern int gEidos_OMP_threads_TOTNEIGHSTRENGTH;\n\n// SLiM internals; benchmark section I\nextern int gEidos_OMP_threads_AGE_INCR;\nextern int gEidos_OMP_threads_DEFERRED_REPRO;\nextern int gEidos_OMP_threads_WF_REPRO;\nextern int gEidos_OMP_threads_FITNESS_ASEX_1;\nextern int gEidos_OMP_threads_FITNESS_ASEX_2;\nextern int gEidos_OMP_threads_FITNESS_ASEX_3;\nextern int gEidos_OMP_threads_FITNESS_SEX_1;\nextern int gEidos_OMP_threads_FITNESS_SEX_2;\nextern int gEidos_OMP_threads_FITNESS_SEX_3;\nextern int gEidos_OMP_threads_MIGRANT_CLEAR;\nextern int gEidos_OMP_threads_SIMPLIFY_SORT_PRE;\nextern int gEidos_OMP_threads_SIMPLIFY_SORT;\nextern int gEidos_OMP_threads_SIMPLIFY_SORT_POST;\nextern int gEidos_OMP_threads_PARENTS_CLEAR;\nextern int gEidos_OMP_threads_UNIQUE_MUTRUNS;\nextern int gEidos_OMP_threads_SURVIVAL;\n\n// benchmark section M is for \"models\", whole SLiM models that test overall scaling\n// for different model types; they do not correspond to per-task keys\n\n\n#else /* ifdef _OPENMP */\n\n// No OpenMP.  This is the \"stub header\" from the OpenMP 4.5 specification.  I've added \"inline\" in various spots to\n// make it more performant, and __attribute__((unused)) to get rid of warnings, and copied some enum and typedef\n// definitions that for some reason are not included in the provided stub header.\n\n#include <stdio.h>\n#include <stdlib.h>\n\ninline void omp_set_num_threads(__attribute__((unused)) int num_threads)\n{\n}\n\ninline int omp_get_num_threads(void)\n{\n\treturn 1;\n}\n\ninline int omp_get_max_threads(void)\n{\n\treturn 1;\n}\n\ninline int omp_get_thread_num(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_num_procs(void)\n{\n\treturn 1;\n}\n\ninline int omp_in_parallel(void)\n{\n\treturn 0;\n}\n\ninline void omp_set_dynamic(__attribute__((unused)) int dynamic_threads)\n{\n}\n\ninline int omp_get_dynamic(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_cancellation(void)\n{\n\treturn 0;\n}\n\ninline void omp_set_nested(__attribute__((unused)) int nested)\n{\n}\n\ninline int omp_get_nested(void)\n{\n\treturn 0;\n}\n\ntypedef enum omp_sched_t {\n\tomp_sched_static = 1,\n\tomp_sched_dynamic = 2,\n\tomp_sched_guided = 3,\n\tomp_sched_auto = 4\n} omp_sched_t;\n\ninline void omp_set_schedule(__attribute__((unused)) omp_sched_t kind, __attribute__((unused)) int modifier)\n{\n}\n\ninline void omp_get_schedule(omp_sched_t *kind, int *chunk_size)\n{\n\t*kind = omp_sched_static;\n\t*chunk_size = 0;\n}\n\ninline int omp_get_thread_limit(void)\n{\n\treturn 1;\n}\n\ninline void omp_set_max_active_levels(__attribute__((unused)) int max_active_levels)\n{\n}\n\ninline int omp_get_max_active_levels(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_level(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_ancestor_thread_num(int level)\n{\n\tif (level == 0)\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn -1;\n\t}\n}\n\ninline int omp_get_team_size(int level)\n{\n\tif (level == 0)\n\t{\n\t\treturn 1;\n\t}\n\telse\n\t{\n\t\treturn -1;\n\t}\n}\n\ninline int omp_get_active_level(void)\n{\n\treturn 0;\n}\n\ninline int omp_in_final(void)\n{\n\treturn 1;\n}\n\ntypedef enum omp_proc_bind_t\n{\n\tomp_proc_bind_false = 0,\n\tomp_proc_bind_true = 1,\n\tomp_proc_bind_master = 2,\n\tomp_proc_bind_close = 3,\n\tomp_proc_bind_spread = 4\n} omp_proc_bind_t;\n\ninline omp_proc_bind_t omp_get_proc_bind(void)\n{\n\treturn omp_proc_bind_false;\n}\n\ninline int omp_get_num_places(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_place_num_procs(__attribute__((unused)) int place_num)\n{\n\treturn 0;\n}\n\ninline void omp_get_place_proc_ids(__attribute__((unused)) int place_num, __attribute__((unused)) int *ids)\n{\n}\n\ninline int omp_get_place_num(void)\n{\n\treturn -1;\n}\n\ninline int omp_get_partition_num_places(void)\n{\n\treturn 0;\n}\n\ninline void omp_get_partition_place_nums(__attribute__((unused)) int *place_nums)\n{\n}\n\ninline void omp_set_default_device(__attribute__((unused)) int device_num)\n{\n}\n\ninline int omp_get_default_device(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_num_devices(void)\n{\n\treturn 0;\n}\n\ninline int omp_get_num_teams(void)\n{\n\treturn 1;\n}\n\ninline int omp_get_team_num(void)\n{\n\treturn 0;\n}\n\ninline int omp_is_initial_device(void)\n{\n\treturn 1;\n}\n\ninline int omp_get_initial_device(void)\n{\n\treturn -10;\n}\n\ninline int omp_get_max_task_priority(void)\n{\n\treturn 0;\n}\n\nstruct __omp_lock\n{\n\tint lock;\n};\n\ntypedef struct __omp_lock omp_lock_t;\n\nenum { UNLOCKED = -1, INIT, LOCKED };\n\ninline void omp_init_lock(omp_lock_t *arg)\n{\n\tstruct __omp_lock *lock = (struct __omp_lock *)arg;\n\tlock->lock = UNLOCKED;\n}\n\ntypedef enum omp_lock_hint_t\n{\n\tomp_lock_hint_none = 0,\n\tomp_lock_hint_uncontended = 1,\n\tomp_lock_hint_contended = 2,\n\tomp_lock_hint_nonspeculative = 4,\n\tomp_lock_hint_speculative = 8\n\t/* , Add vendor specific constants for lock hints here,\n\t starting from the most-significant bit. */\n} omp_lock_hint_t;\n\ninline void omp_init_lock_with_hint(omp_lock_t *arg, __attribute__((unused)) omp_lock_hint_t hint)\n{\n\tomp_init_lock(arg);\n}\n\ninline void omp_destroy_lock(omp_lock_t *arg)\n{\n\tstruct __omp_lock *lock = (struct __omp_lock *)arg;\n\tlock->lock = INIT;\n}\n\ninline void omp_set_lock(omp_lock_t *arg)\n{\n\tstruct __omp_lock *lock = (struct __omp_lock *)arg;\n\tif (lock->lock == UNLOCKED)\n\t{\n\t\tlock->lock = LOCKED;\n\t}\n\telse if (lock->lock == LOCKED)\n\t{\n\t\tfprintf(stderr, \"error: deadlock in using lock variable\\n\");\n\t\texit(1);\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"error: lock not initialized\\n\");\n\t\texit(1);\n\t}\n}\n\ninline void omp_unset_lock(omp_lock_t *arg)\n{\n\tstruct __omp_lock *lock = (struct __omp_lock *)arg;\n\tif (lock->lock == LOCKED)\n\t{\n\t\tlock->lock = UNLOCKED;\n\t}\n\telse if (lock->lock == UNLOCKED)\n\t{\n\t\tfprintf(stderr, \"error: lock not set\\n\");\n\t\texit(1);\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"error: lock not initialized\\n\");\n\t\texit(1);\n\t}\n}\n\ninline int omp_test_lock(omp_lock_t *arg)\n{\n\tstruct __omp_lock *lock = (struct __omp_lock *)arg;\n\tif (lock->lock == UNLOCKED)\n\t{\n\t\tlock->lock = LOCKED;\n\t\treturn 1;\n\t}\n\telse if (lock->lock == LOCKED)\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"error: lock not initialized\\n\");\n\t\texit(1);\n\t}\n}\n\nstruct __omp_nest_lock\n{\n\tshort owner;\n\tshort count;\n};\n\ntypedef struct __omp_nest_lock omp_nest_lock_t;\n\nenum { NOOWNER = -1, MASTER = 0 };\n\ninline void omp_init_nest_lock(omp_nest_lock_t *arg)\n{\n\tstruct __omp_nest_lock *nlock=(struct __omp_nest_lock *)arg;\n\tnlock->owner = NOOWNER;\n\tnlock->count = 0;\n}\n\ninline void omp_init_nest_lock_with_hint(omp_nest_lock_t *arg, __attribute__((unused)) omp_lock_hint_t hint)\n{\n\tomp_init_nest_lock(arg);\n}\n\ninline void omp_destroy_nest_lock(omp_nest_lock_t *arg)\n{\n\tstruct __omp_nest_lock *nlock=(struct __omp_nest_lock *)arg;\n\tnlock->owner = NOOWNER;\n\tnlock->count = UNLOCKED;\n}\n\ninline void omp_set_nest_lock(omp_nest_lock_t *arg)\n{\n\tstruct __omp_nest_lock *nlock=(struct __omp_nest_lock *)arg;\n\tif (nlock->owner == MASTER && nlock->count >= 1)\n\t{\n\t\tnlock->count++;\n\t}\n\telse if (nlock->owner == NOOWNER && nlock->count == 0)\n\t{\n\t\tnlock->owner = MASTER;\n\t\tnlock->count = 1;\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"error: lock corrupted or not initialized\\n\");\n\t\texit(1);\n\t}\n}\n\ninline void omp_unset_nest_lock(omp_nest_lock_t *arg)\n{\n\tstruct __omp_nest_lock *nlock=(struct __omp_nest_lock *)arg;\n\tif (nlock->owner == MASTER && nlock->count >= 1)\n\t{\n\t\tnlock->count--;\n\t\tif (nlock->count == 0)\n\t\t{\n\t\t\tnlock->owner = NOOWNER;\n\t\t}\n\t}\n\telse if (nlock->owner == NOOWNER && nlock->count == 0)\n\t{\n\t\tfprintf(stderr, \"error: lock not set\\n\");\n\t\texit(1);\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"error: lock corrupted or not initialized\\n\");\n\t\texit(1);\n\t}\n}\n\ninline int omp_test_nest_lock(omp_nest_lock_t *arg)\n{\n\tstruct __omp_nest_lock *nlock=(struct __omp_nest_lock *)arg;\n\tomp_set_nest_lock(arg);\n\treturn nlock->count;\n}\n\ninline double omp_get_wtime(void)\n{\n\t/* This function does not provide a working\n\t * wallclock timer. Replace it with a version\n\t * customized for the target machine.\n\t */\n\treturn 0.0;\n}\n\ninline double omp_get_wtick(void)\n{\n\t/* This function does not provide a working\n\t * clock tick function. Replace it with\n\t * a version customized for the target machine.\n\t */\n\treturn 365. * 86400.;\n}\n\ninline void * omp_target_alloc(size_t size, int device_num)\n{\n\tif (device_num != -10)\n\t\treturn NULL;\n\treturn malloc(size);\n}\n\ninline void omp_target_free(void *device_ptr, __attribute__((unused)) int device_num)\n{\n\tfree(device_ptr);\n}\n\ninline int omp_target_is_present(__attribute__((unused)) void *ptr, __attribute__((unused)) int device_num)\n{\n\treturn 1;\n}\n\ninline int omp_target_memcpy(void *dst, void *src, size_t length,\n\t\t\t\t\t  size_t dst_offset, size_t src_offset,\n\t\t\t\t\t  int dst_device, int src_device)\n{\n\t// only the default device is valid in a stub\n\tif (dst_device != -10 || src_device != -10 || ! dst || ! src )\n\t\treturn EINVAL;\n\tmemcpy((char *)dst + dst_offset, (char *)src + src_offset, length);\n\treturn 0;\n}\n\ninline int omp_target_memcpy_rect(\n\t\t\t\t\t\t   void *dst, void *src,\n\t\t\t\t\t\t   size_t element_size,\n\t\t\t\t\t\t   int num_dims,\n\t\t\t\t\t\t   const size_t *volume,\n\t\t\t\t\t\t   const size_t *dst_offsets,\n\t\t\t\t\t\t   const size_t *src_offsets,\n\t\t\t\t\t\t   const size_t *dst_dimensions,\n\t\t\t\t\t\t   const size_t *src_dimensions,\n\t\t\t\t\t\t   int dst_device_num, int src_device_num)\n{\n\tint ret=0;\n\t// Both null, return number of dimensions supported,\n\t// this stub supports an arbitrary number\n\tif (dst == NULL && src == NULL) return INT_MAX;\n\t\n\tif (!volume || !dst_offsets || !src_offsets\n\t\t|| !dst_dimensions || !src_dimensions\n\t\t|| num_dims < 1 ) {\n\t\tret = EINVAL;\n\t\tgoto done;\n\t}\n\tif (num_dims == 1) {\n\t\tret = omp_target_memcpy(dst, src,\n\t\t\t\t\t\t\t\telement_size * volume[0],\n\t\t\t\t\t\t\t\tdst_offsets[0] * element_size,\n\t\t\t\t\t\t\t\tsrc_offsets[0] * element_size,\n\t\t\t\t\t\t\t\tdst_device_num, src_device_num);\n\t\tif(ret) goto done;\n\t} else {\n\t\tsize_t dst_slice_size = element_size;\n\t\tsize_t src_slice_size = element_size;\n\t\tfor (int i=1; i < num_dims; i++) {\n\t\t\tdst_slice_size *= dst_dimensions[i];\n\t\t\tsrc_slice_size *= src_dimensions[i];\n\t\t}\n\t\tsize_t dst_off = dst_offsets[0] * dst_slice_size;\n\t\tsize_t src_off = src_offsets[0] * src_slice_size;\n\t\tfor (size_t i=0; i < volume[0]; i++) {\n\t\t\tret = omp_target_memcpy_rect(\n\t\t\t\t\t\t\t\t\t\t (char *)dst + dst_off + dst_slice_size*i,\n\t\t\t\t\t\t\t\t\t\t (char *)src + src_off + src_slice_size*i,\n\t\t\t\t\t\t\t\t\t\t element_size,\n\t\t\t\t\t\t\t\t\t\t num_dims - 1,\n\t\t\t\t\t\t\t\t\t\t volume + 1,\n\t\t\t\t\t\t\t\t\t\t dst_offsets + 1,\n\t\t\t\t\t\t\t\t\t\t src_offsets + 1,\n\t\t\t\t\t\t\t\t\t\t dst_dimensions + 1,\n\t\t\t\t\t\t\t\t\t\t src_dimensions + 1,\n\t\t\t\t\t\t\t\t\t\t dst_device_num,\n\t\t\t\t\t\t\t\t\t\t src_device_num);\n\t\t\tif (ret) goto done;\n\t\t}\n\t}\ndone:\n\treturn ret;\n}\n\ninline int omp_target_associate_ptr(__attribute__((unused)) void *host_ptr, __attribute__((unused)) void *device_ptr,\n\t\t\t\t\t\t\t\t\t__attribute__((unused)) size_t size, __attribute__((unused)) size_t device_offset,\n\t\t\t\t\t\t\t\t\t__attribute__((unused)) int device_num)\n{\n\t// No association is possible because all host pointers\n\t// are considered present\n\treturn EINVAL;\n}\n\ninline int omp_target_disassociate_ptr(__attribute__((unused)) void *ptr, __attribute__((unused)) int device_num)\n{\n\treturn EINVAL;\n}\n\n\n#endif /* ifdef _OPENMP */\n\n\n#endif /* eidos_openmp_h */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_property_signature.cpp",
    "content": "//\n//  eidos_property_signature.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 8/3/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_property_signature.h\"\n#include \"eidos_value.h\"\n\n#include <string>\n\n\nEidosPropertySignature::EidosPropertySignature(const std::string &p_property_name, bool p_read_only, EidosValueMask p_value_mask)\n\t: property_name_(p_property_name), property_id_(EidosStringRegistry::GlobalStringIDForString(p_property_name)), read_only_(p_read_only), value_mask_(p_value_mask), value_class_(nullptr), accelerated_get_(false), accelerated_set_(false)\n{\n\tif (!read_only_ && !(value_mask_ & kEidosValueMaskSingleton))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) read-write property \" << property_name_ << \" must produce a singleton value according to Eidos semantics.\" << EidosTerminate(nullptr);\n\tif (value_mask_ & kEidosValueMaskVOID)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) properties are not allowed to return void.\" << EidosTerminate(nullptr);\n\tif (value_mask_ & kEidosValueMaskNULL)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) properties are not allowed to return NULL.\" << EidosTerminate(nullptr);\n}\n\nEidosPropertySignature::EidosPropertySignature(const std::string &p_property_name, bool p_read_only, EidosValueMask p_value_mask, const EidosClass *p_value_class)\n\t: property_name_(p_property_name), property_id_(EidosStringRegistry::GlobalStringIDForString(p_property_name)), read_only_(p_read_only), value_mask_(p_value_mask), value_class_(p_value_class), accelerated_get_(false), accelerated_set_(false)\n{\n\tif (!read_only_ && !(value_mask_ & kEidosValueMaskSingleton))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) read-write property \" << property_name_ << \" must produce a singleton value according to Eidos semantics.\" << EidosTerminate(nullptr);\n\tif (value_mask_ & kEidosValueMaskVOID)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) properties are not allowed to return void.\" << EidosTerminate(nullptr);\n\tif (value_mask_ & kEidosValueMaskNULL)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::EidosPropertySignature): (internal error) properties are not allowed to return NULL.\" << EidosTerminate(nullptr);\n}\n\nEidosPropertySignature::~EidosPropertySignature(void)\n{\n}\n\nvoid EidosPropertySignature::CheckAssignedValue(const EidosValue &p_value) const\n{\n\tuint32_t retmask = value_mask_;\n\tbool value_type_ok = true;\n\t\n\t// BCH 12/22/2023: We used to allow type promotion when assigning into properties.  I think we ought to be\n\t// strict about that; this comes from the days when Eidos was much more oriented towards automatic type\n\t// promotion, but it's bug-prone and provides little value.\n\t\n\tswitch (p_value.Type())\n\t{\n\t\tcase EidosValueType::kValueVOID:\t\t\t\t\t\t\t\t// NOLINT(*-branch-clone) : intentional consecutive branches\n\t\t\tvalue_type_ok = false;\t// never OK regardless of retmask\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueNULL:\n\t\t\t// BCH 30 January 2017: setting NULL into a property used to be allowed here without declaration (as it is\n\t\t\t// when getting the value of a property), but I think that was just a bug.  I'm modifying this to throw an\n\t\t\t// exception unless NULL is explicitly declared as acceptable in the signature.\n\t\t\t\n\t\t\t// BCH 11 December 2017: note that NULL can no longer be declared in a property signature, so setting\n\t\t\t// a property to NULL will always raise now; this is official Eidos semantics now, strict no-no, so\n\t\t\t// rather than checking retmask we just set value_type_ok to false unconditionally now.\n\t\t\t//value_type_ok = !!(retmask & kEidosValueMaskNULL);\n\t\t\tvalue_type_ok = false;\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueLogical:\n\t\t\t//value_type_ok = !!(retmask & (kEidosValueMaskLogical | kEidosValueMaskInt | kEidosValueMaskFloat));\t\t// can give logical to an int or float property\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskLogical);\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueInt:\n\t\t\t//value_type_ok = !!(retmask & (kEidosValueMaskInt | kEidosValueMaskFloat));\t\t\t\t\t\t\t\t// can give int to a float property\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskInt);\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskFloat);\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueString:\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskString);\n\t\t\tbreak;\n\t\tcase EidosValueType::kValueObject:\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskObject);\n\t\t\t\n\t\t\t// If the value is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t// in the signature, check the object element type of the value.  Note this uses pointer equality!\n\t\t\t// This check is applied only if the value contains elements, since an empty object does not know its type.\n\t\t\tif (value_type_ok && value_class_ && (((EidosValue_Object *)&p_value)->Class() != value_class_) && (p_value.Count() > 0))\n\t\t\t{\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAssignedValue): object value cannot be object element type \" << p_value.ElementType() << \" for \" << PropertyType() << \" property \" << property_name_ << \"; expected object element type \" << value_class_->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t\n\tif (!value_type_ok)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAssignedValue): value cannot be type \" << p_value.Type() << \" for \" << PropertyType() << \" property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\n\t// No check for size, because we're checking a whole vector being assigned into an object; EidosValue_Object will check the sizes\n}\n\nvoid EidosPropertySignature::CheckResultValue(const EidosValue &p_value) const\n{\n\tuint32_t retmask = value_mask_;\n\tbool value_type_ok = true;\n\t\n\tswitch (p_value.Type())\n\t{\n\t\tcase EidosValueType::kValueVOID:\n\t\t\t// void is not allowed as a property value, getting or setting, ever.\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckResultValue): (internal error) void returned for property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\t\treturn;\n\t\tcase EidosValueType::kValueNULL:\n\t\t\t// A return type of NULL is always allowed, in fact; we don't want to have to specify this in the return type\n\t\t\t// This is a little fishy, but since NULL is used to indicate error conditions, NULL returns are exceptional,\n\t\t\t// and the return type indicates the type ordinarily returned in non-exceptional cases.  We just return here,\n\t\t\t// since we also don't want to do the singleton check below (since it would raise too).\n\t\t\t\n\t\t\t// BCH 30 January 2017: Modifying this a bit.  The policy is still that a return type of NULL is always\n\t\t\t// allowed.  However, this is incompatible with accelerated gets, so if a property is declared as accelerated,\n\t\t\t// the code here will throw an error.  This should probably never happen, since if someone tries to accelerate\n\t\t\t// a property that can return NULL they will immediately realize the error of their ways, as they will find it\n\t\t\t// to be impossible to implement.  :->  Still, for clarity and possible debugging value, I'm adding a check.\n\t\t\t\n\t\t\t// BCH 11 December 2017: note that NULL can no longer be declared in a property signature, and is no longer\n\t\t\t// ever allowed as a value for a property, so the above comments are obsolete.  This is now official Eidos\n\t\t\t// semantics, to allow guaranteed one-to-one matching of objects and their singleton properties: NULL is not\n\t\t\t// allowed as a property value, getting or setting, ever.\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckResultValue): (internal error) NULL returned for property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\t\treturn;\n\t\tcase EidosValueType::kValueLogical:\tvalue_type_ok = !!(retmask & kEidosValueMaskLogical);\tbreak;\n\t\tcase EidosValueType::kValueInt:\t\tvalue_type_ok = !!(retmask & kEidosValueMaskInt);\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\tvalue_type_ok = !!(retmask & kEidosValueMaskFloat);\t\tbreak;\n\t\tcase EidosValueType::kValueString:\tvalue_type_ok = !!(retmask & kEidosValueMaskString);\t\tbreak;\n\t\tcase EidosValueType::kValueObject:\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskObject);\n\t\t\t\n\t\t\t// If the value is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t// in the signature, check the object element type of the value.  Note this uses pointer equality!\n\t\t\t// This check is applied only if the value contains elements, since an empty object does not know its type.\n\t\t\tif (value_type_ok && value_class_ && (((EidosValue_Object *)&p_value)->Class() != value_class_) && (p_value.Count() > 0))\n\t\t\t{\n\t\t\t\tif (!((EidosValue_Object *)&p_value)->Class()->IsSubclassOfClass(value_class_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckResultValue): (internal error) object value cannot be object element type \" << p_value.ElementType() << \" for \" << PropertyType() << \" property \" << property_name_ << \"; expected object element type \" << value_class_->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t\n\tif (!value_type_ok)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckResultValue): (internal error) value cannot be type \" << p_value.Type() << \" for \" << PropertyType() << \" property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\n\tbool return_is_singleton = !!(retmask & kEidosValueMaskSingleton);\n\t\n\tif (return_is_singleton && (p_value.Count() != 1))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckResultValue): (internal error) value must be a singleton (size() == 1) for \" << PropertyType() << \" property \" << property_name_ << \", but size() == \" << p_value.Count() << \".\" << EidosTerminate(nullptr);\n}\n\nvoid EidosPropertySignature::CheckAggregateResultValue(const EidosValue &p_value, size_t p_expected_size) const\n{\n\tuint32_t retmask = value_mask_;\n\tbool value_type_ok = true;\n\t\n\tswitch (p_value.Type())\n\t{\n\t\tcase EidosValueType::kValueVOID:\n\t\t\t// void is not allowed as a property value, getting or setting, ever.\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAggregateResultValue): (internal error) void returned for property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\t\treturn;\n\t\tcase EidosValueType::kValueNULL:\n\t\t\t// BCH 11 December 2017: NULL is not allowed as a property value, getting or setting, ever.\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAggregateResultValue): (internal error) NULL returned for property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\t\treturn;\n\t\tcase EidosValueType::kValueLogical:\tvalue_type_ok = !!(retmask & kEidosValueMaskLogical);\tbreak;\n\t\tcase EidosValueType::kValueInt:\t\tvalue_type_ok = !!(retmask & kEidosValueMaskInt);\t\tbreak;\n\t\tcase EidosValueType::kValueFloat:\tvalue_type_ok = !!(retmask & kEidosValueMaskFloat);\t\tbreak;\n\t\tcase EidosValueType::kValueString:\tvalue_type_ok = !!(retmask & kEidosValueMaskString);\t\tbreak;\n\t\tcase EidosValueType::kValueObject:\n\t\t\tvalue_type_ok = !!(retmask & kEidosValueMaskObject);\n\t\t\t\n\t\t\t// If the value is object type, and is allowed to be object type, and an object element type was specified\n\t\t\t// in the signature, check the object element type of the value.  Note this uses pointer equality!\n\t\t\t// This check is applied only if the value contains elements, since an empty object does not know its type.\n\t\t\tif (value_type_ok && value_class_ && (((EidosValue_Object *)&p_value)->Class() != value_class_) && (p_value.Count() > 0))\n\t\t\t{\n\t\t\t\tif (!((EidosValue_Object *)&p_value)->Class()->IsSubclassOfClass(value_class_))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAggregateResultValue): (internal error) object value cannot be object element type \" << p_value.ElementType() << \" for \" << PropertyType() << \" property \" << property_name_ << \"; expected object element type \" << value_class_->ClassNameForDisplay() << \".\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\t\n\tif (!value_type_ok)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAggregateResultValue): (internal error) value cannot be type \" << p_value.Type() << \" for \" << PropertyType() << \" property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n\t\n\tbool return_is_singleton = !!(retmask & kEidosValueMaskSingleton);\n\t\n\tif (return_is_singleton && ((size_t)p_value.Count() != p_expected_size))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::CheckAggregateResultValue): (internal error) value must be a singleton (size() == 1) for \" << PropertyType() << \" property \" << property_name_ << \".\" << EidosTerminate(nullptr);\n}\n\nstd::string EidosPropertySignature::PropertyType(void) const\n{\n\treturn (read_only_ ? \"read-only\" : \"read-write\");\n}\n\nstd::string EidosPropertySignature::PropertySymbol(void) const\n{\n\treturn (read_only_ ? \"=>\" : \"<–>\");\n}\n\nEidosPropertySignature *EidosPropertySignature::DeclareAcceleratedGet(Eidos_AcceleratedPropertyGetter p_getter)\n{\n\tuint32_t retmask = (value_mask_ & kEidosValueMaskFlagStrip);\n\t\n\tif ((retmask != kEidosValueMaskLogical) && \n\t\t(retmask != kEidosValueMaskInt) && \n\t\t(retmask != kEidosValueMaskFloat) && \n\t\t(retmask != kEidosValueMaskString) && \n\t\t(retmask != kEidosValueMaskObject))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedGet): (internal error) only properties returning one guaranteed type may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\tif ((retmask == (kEidosValueMaskObject | kEidosValueMaskSingleton)) && (value_class_ == nullptr))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedGet): (internal error) only object properties that declare their class may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\taccelerated_get_ = true;\n\taccelerated_getter = p_getter;\n\t\n\treturn this;\n}\n\nEidosPropertySignature *EidosPropertySignature::DeclareAcceleratedSet(Eidos_AcceleratedPropertySetter p_setter)\n{\n\tif (read_only_)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedSet): (internal error) only read-write properties may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\tuint32_t retmask = value_mask_;\n\tbool return_is_singleton = !!(retmask & kEidosValueMaskSingleton);\n\t\n\tif (!return_is_singleton)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedSet): (internal error) only singleton properties may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\tif ((retmask != (kEidosValueMaskLogical | kEidosValueMaskSingleton)) && \n\t\t(retmask != (kEidosValueMaskInt | kEidosValueMaskSingleton)) && \n\t\t(retmask != (kEidosValueMaskFloat | kEidosValueMaskSingleton)) && \n\t\t(retmask != (kEidosValueMaskString | kEidosValueMaskSingleton)) && \n\t\t(retmask != (kEidosValueMaskObject | kEidosValueMaskSingleton)))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedSet): (internal error) only properties returning one guaranteed type may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\tif ((retmask == (kEidosValueMaskObject | kEidosValueMaskSingleton)) && (value_class_ == nullptr))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosPropertySignature::DeclareAcceleratedSet): (internal error) only object properties that declare their class may be accelerated.\" << EidosTerminate(nullptr);\n\t\n\taccelerated_set_ = true;\n\taccelerated_setter = p_setter;\n\t\n\treturn this;\n}\n\nEidosPropertySignature *EidosPropertySignature::MarkDeprecated(void)\n{\n\t// At present, the only consequence of deprecation is that the property/method is not listed in the documentation\n\tdeprecated_ = true;\n\treturn this;\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosPropertySignature &p_signature)\n{\n\tp_outstream << p_signature.property_name_ << \" \" << p_signature.PropertySymbol() << \" (\";\n\tp_outstream << StringForEidosValueMask(p_signature.value_mask_, p_signature.value_class_, \"\", nullptr) << \")\";\n\t\n\treturn p_outstream;\n}\n\nbool CompareEidosPropertySignatures(const EidosPropertySignature_CSP &p_i, const EidosPropertySignature_CSP &p_j)\n{\n\treturn (p_i->property_name_ < p_j->property_name_);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_property_signature.h",
    "content": "//\n//  eidos_property_signature.h\n//  Eidos\n//\n//  Created by Ben Haller on 8/3/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_property_signature__\n#define __Eidos__eidos_property_signature__\n\n#include <memory>\n\n#include \"eidos_globals.h\"\n\nclass EidosValue;\nclass EidosObject;\nclass EidosClass;\n\n\n// This typedef is for an \"accelerated property getter\".  These are static member functions on a class, designed to provide a whole\n// vector of property values given a buffer of EidosObjects.  The getter is expected to return the correct type for the\n// property (this is checked).  The getter is guaranteed that the EidosObjects are of the correct class; it is allowed to\n// do a cast of p_values directly to its own type without checking, according to the calling conventions used here.\ntypedef EidosValue *(*Eidos_AcceleratedPropertyGetter)(EidosObject **p_values, size_t p_values_size);\n\n// This typedef is for an \"accelerated property setter\".  These are static member functions on a class, designed to set a property\n// value across a buffer of EidosObjects.  This is more complex than the getter case, because there are two possibilities:\n// p_source could be a singleton, providing one value to be set across the whole buffer, OR it could be a vector of length equal\n// to the buffer size.  It is guaranteed to be one of those two things; the setter does not need to cover the case where the length\n// of p_source is not singleton but not equal to p_values_size.  As with accelerated getters, p_values is guaranteed by the caller\n// to be of the correct class, and may be cast directly.  (This is actually guaranteed and checked by the property signature, so if\n// the signature is declared incorrectly then a mismatch is possible; but that is not the getter/setter's problem to detect.)  The\n// type of p_source is also checked against the signature, and so may be assumed to be of the declared type.\ntypedef void (*Eidos_AcceleratedPropertySetter)(EidosObject **p_values, size_t p_values_size, const EidosValue &p_source, size_t p_source_size);\n\n\nclass EidosPropertySignature\n{\npublic:\n\tstd::string property_name_;\n\tEidosGlobalStringID property_id_;\n\t\n\tbool read_only_;\t\t\t\t\t\t\t\t\t// true if the property is read-only, false if it is read-write\n\tEidosValueMask value_mask_;\t\t\t\t\t\t\t// a mask for the type returned; singleton is used, optional is not\n\tconst EidosClass *value_class_;\t\t\t\t// optional type-check for object values; used only if this is not nullptr\n\t\n\tbool accelerated_get_;\t\t\t\t\t\t\t\t\t// if true, can be read using a fast-access GetProperty_Accelerated_X() method\n\tEidos_AcceleratedPropertyGetter accelerated_getter;\t\t// a pointer to a (static member) function that handles the accelerated get\n\t\n\tbool accelerated_set_;\t\t\t\t\t\t\t\t\t// if true, can be written using a fast-access SetProperty_Accelerated_X() method\n\tEidos_AcceleratedPropertySetter accelerated_setter;\t\t// a pointer to a (static member) function that handles the accelerated set\n\t\n\tbool deprecated_ = false;\t\t\t\t\t\t\t// if true, the API represented by this signature has been deprecated\n\n\tEidosPropertySignature(const EidosPropertySignature&) = delete;\t\t\t\t\t// no copying\n\tEidosPropertySignature& operator=(const EidosPropertySignature&) = delete;\t\t// no copying\n\tEidosPropertySignature(void) = delete;\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\tvirtual ~EidosPropertySignature(void);\n\t\n\tEidosPropertySignature(const std::string &p_property_name, bool p_read_only, EidosValueMask p_value_mask);\n\tEidosPropertySignature(const std::string &p_property_name, bool p_read_only, EidosValueMask p_value_mask, const EidosClass *p_value_class);\n\t\n\t// check arguments and returns\n\tvoid CheckAssignedValue(const EidosValue &p_value) const;\t// checks a vector being assigned into a whole object; raises on mismatch\n\tvoid CheckResultValue(const EidosValue &p_value) const;\t// checks the result from a single element\n\tvoid CheckAggregateResultValue(const EidosValue &p_value, size_t p_expected_size) const;\t// checks the result from a vector\n\t\n\t// informational strings about the property\n\tstd::string PropertyType(void) const;\t\t\t\t// \"read-only\" or \"read-write\"\n\tstd::string PropertySymbol(void) const;\t\t\t\t// \"=>\" or \"–>\"\n\t\n\t// property access acceleration\n\tEidosPropertySignature *DeclareAcceleratedGet(Eidos_AcceleratedPropertyGetter p_getter);\n\tEidosPropertySignature *DeclareAcceleratedSet(Eidos_AcceleratedPropertySetter p_setter);\n\t\n\t// API deprecation; this prevents deprecated API from being shown in code completion, etc., even though it remains in the doc\n\tEidosPropertySignature *MarkDeprecated(void);\n};\n\n// These typedefs for shared_ptrs of these classes should generally be used; all signature objects should be under shared_ptr now.\n//typedef std::shared_ptr<EidosPropertySignature> EidosPropertySignature_SP;\t\t// once under shared_ptr, these should always be const\ntypedef std::shared_ptr<EidosPropertySignature const> EidosPropertySignature_CSP;\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosPropertySignature &p_signature);\nbool CompareEidosPropertySignatures(const EidosPropertySignature_CSP &p_i, const EidosPropertySignature_CSP &p_j);\n\n\n#endif /* defined(__Eidos__eidos_property_signature__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_rng.cpp",
    "content": "//\n//  eidos_rng.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_rng.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef _WIN32\n\t// --- These are the required includes for the new Windows RNG code ---\n\t#include <windows.h>  // Main header for Windows data types like PBYTE\n\t#include <bcrypt.h>   // Header for the Cryptography API where BCryptGenRandom is declared\n#else\n\t// --- These are the other headers, now only used for non-Windows systems ---\n\t#include <unistd.h>\n\t#include <fcntl.h>\n\t#include <sys/time.h>\n#endif\n\n\n// GSL-compatible wrapper for the PCG64 generator\nstatic void Eidos_GSL_RNG_PCG64_set(void *state, unsigned long int seed)\n{\n#pragma unused(state, seed)\n\t// BCH 11/1/2025: This should never be called, because gsl_rng_set() should never be called.  The reason\n\t// is that the pcg64_fast generator is a bit fussy about seeds; we should always seed it through the\n\t// procedure followed in _Eidos_SetOneRNGSeed().  For that reason, we just skip seeding here.\n#if 0\n\tEidosRNG_64_bit *rng_64 = static_cast<EidosRNG_64_bit *>(state);\n\t\n\trng_64->seed(seed);\n#endif\n}\n\nstatic unsigned long int Eidos_GSL_RNG_PCG64_get(void *state)\n{\n\tEidosRNG_64_bit *rng_64 = static_cast<EidosRNG_64_bit *>(state);\n\t\n\treturn (*rng_64)();\n}\n\nstatic double Eidos_GSL_RNG_PCG64_get_double(void *state)\n{\n\tEidosRNG_64_bit *rng_64 = static_cast<EidosRNG_64_bit *>(state);\n\t\n\t// generates a random double in [0,1) -- including 0 but NOT 1\n\t// this is a copy of Eidos_rng_uniform_doubleCO()\n\treturn ((*rng_64)() >> 11) * (1.0/9007199254740992.0);\n}\n\nstatic const gsl_rng_type gEidos_GSL_RNG_PCG64 = {\n\t\"PCG64\",\n\tUINT_MAX,\n\t0,\n\tsizeof(EidosRNG_64_bit),\n\tEidos_GSL_RNG_PCG64_set,\n\tEidos_GSL_RNG_PCG64_get,\n\tEidos_GSL_RNG_PCG64_get_double\n};\n\n\nbool gEidos_RNG_Initialized = false;\n\n#ifndef _OPENMP\nEidos_RNG_State gEidos_RNG_SINGLE;\n#else\nstd::vector<Eidos_RNG_State *> gEidos_RNG_PERTHREAD;\n#endif\n\n\nstatic unsigned long int _Eidos_GenerateRNGSeed(void)\n{\n\tunsigned long int seed;\n\t\n#ifdef _WIN32\n\t// On Windows, use the Cryptography API: Next Generation (CNG) to get a\n\t// cryptographically secure random number for use as a seed.\n\n\t// Ensure this section is thread-safe. If multiple threads request a seed\n\t// simultaneously, they must take turns to avoid corrupting system resources.\n#pragma omp critical (Eidos_GenerateRNGSeed)\n\t{\n\t\t// Ask Windows to fill our seed variable with random bytes.\n\t\tNTSTATUS status = BCryptGenRandom(NULL, (PBYTE)&seed, sizeof(seed), BCRYPT_USE_SYSTEM_PREFERRED_RNG);\n\n\t\t// A failure here indicates a system-level problem with Windows. \n\t\tif (!BCRYPT_SUCCESS(status))\n\t\t{\n\t\t\tfprintf(stderr, \"ERROR: Failed to generate a random seed using BCryptGenRandom. Status: 0x%X\\n\", (unsigned int)status);\n\t\t\texit(EXIT_FAILURE);\n\t\t}\t\n\t}\n#else\n\t// On other platforms, we now use /dev/urandom as a source of seeds, which is more reliably random.\n\t// Thanks to https://security.stackexchange.com/a/184211/288172 for the basis of this code.\n\t// I chose urandom rather than random to avoid stalls if the random pool's entropy is low;\n\t// semi-pseudorandom seeds should be good enough for our purposes here.\n\t\n\t// Ensure this section is thread-safe. If multiple threads request a seed\n\t// simultaneously, they must take turns to avoid corrupting system resources.\n#pragma omp critical (Eidos_GenerateRNGSeed)\n\t{\n\t\tint fd = open(\"/dev/urandom\", O_RDONLY);\n\t\t(void)(read(fd, &seed, sizeof(seed)) + 1);\t// ignore the result without a warning, ugh; see https://stackoverflow.com/a/13999461\n\t\tclose(fd);\n\t}\n#endif\n\t\n\t// Our new pcg32_fast and pcg64_fast generators have a quirk: they ignore the lowest two bits of\n\t// the seed, and thus in _Eidos_SetOneRNGSeed() we shift the given seed left two places.  We want\n\t// to make room for that without overflow, so we shift right here.  I've chosen to shift right\n\t// by three places here, in fact, so that we have some extra headroom for the user to increment\n\t// the generated seed a couple of times without risking overflow.\n\tseed >>= 3;\n\t\n\treturn seed;\n}\n\nunsigned long int Eidos_GenerateRNGSeed(void)\n{\n\t// We impose an extra restriction that _Eidos_GenerateRNGSeed() does not worry about: we require\n\t// that the seed be greater than zero, as an int64_t.  We achieve that by just forcing it to be\n\t// true; if _Eidos_GenerateRNGSeed() is generating cryptographically secure seeds, that ought\n\t// to be harmless.  We do this so that the seed reported to the user always matches the seed\n\t// value generated (otherwise a discrepancy is visible in SLiMgui).\n\t// BCH 11/1/2025: Avoiding zero was needed for the old taus2 RNG in the GSL.  This is not really\n\t// needed any more, I think; but maybe avoiding zero is good anyway?\n\tint64_t seed_i64;\n\t\n\tdo\n\t{\n\t\tunsigned long int seed = _Eidos_GenerateRNGSeed();\n\t\tunsigned long int clipped_seed = (seed & INT64_MAX);\t// shave off the top bit\n\t\t\n\t\tseed_i64 = (int64_t)clipped_seed;\n\t} while (seed_i64 == 0);\n\t\n\treturn (unsigned long int)seed_i64;\n}\n\nvoid _Eidos_InitializeOneRNG(Eidos_RNG_State &r)\n{\n\t// Note that this is now called from each thread, when running parallel\n\tr.rng_last_seed_ = 0;\n\t\n\tr.pcg32_rng_.seed(0);\n\tr.pcg64_rng_.seed(0);\n\t\n\t// we do not call gsl_rng_alloc(), because our gsl_rng instance is inline; the GSL unfortunately\n\t// does not cater to this possibility, so we've got a bit of copied init code here from the GSL\n\tr.gsl_rng_.type = &gEidos_GSL_RNG_PCG64;\n\tr.gsl_rng_.state = &r.pcg64_rng_;\t// the \"state\" pointer points to our 64-bit PCG generator\n\t//gsl_rng_set(&r.gsl_rng_, 0);      // the generator was already seeded above through pcg64_rng_\n\t\n\tr.random_bool_bit_counter_ = 0;\n\tr.random_bool_bit_buffer_ = 0;\n}\n\nvoid Eidos_InitializeRNG(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Eidos_InitializeRNG(): RNG change\");\n\t\n\t// Allocate the RNG if needed\n\tif (gEidos_RNG_Initialized)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_InitializeRNG): (internal error) the Eidos random number generator has already been allocated.\" << EidosTerminate(nullptr);\n\t\n#ifndef _OPENMP\n\t//std::cout << \"***** Initializing one single-threaded RNG\" << std::endl;\n\t\n\t_Eidos_InitializeOneRNG(gEidos_RNG_SINGLE);\n#else\n\t//std::cout << \"***** Initializing \" << gEidosMaxThreads << \" independent RNGs\" << std::endl;\n\t\n\tgEidos_RNG_PERTHREAD.resize(gEidosMaxThreads);\n\t\n\t// Check that each RNG was initialized by a different thread, as intended below;\n\t// this is not required, but it improves memory locality throughout the run\n\tbool threadObserved[gEidosMaxThreads];\n\t\n#pragma omp parallel default(none) shared(gEidos_RNG_PERTHREAD, threadObserved) num_threads(gEidosMaxThreads)\n\t{\n\t\t// Each thread allocates and initializes its own Eidos_RNG_State, for \"first touch\" optimization\n\t\tint threadnum = omp_get_thread_num();\n\t\tEidos_RNG_State *rng_state = (Eidos_RNG_State *)calloc(1, sizeof(Eidos_RNG_State));\n\t\t_Eidos_InitializeOneRNG(*rng_state);\n\t\tgEidos_RNG_PERTHREAD[threadnum] = rng_state;\n\t\tthreadObserved[threadnum] = true;\n\t}\t// end omp parallel\n\t\n\tfor (int threadnum = 0; threadnum < gEidosMaxThreads; ++threadnum)\n\t\tif (!threadObserved[threadnum])\n\t\t\tstd::cerr << \"WARNING: parallel RNGs were not correctly initialized on their corresponding threads; this may cause slower random number generation.\" << std::endl;\n#endif\t// end _OPENMP\n\t\n\tgEidos_RNG_Initialized = true;\n}\n\nvoid _Eidos_FreeOneRNG(Eidos_RNG_State &r)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"_Eidos_FreeOneRNG(): RNG change\");\n\t\n\tr.gsl_rng_.type = NULL;\t\t// not owned\n\tr.gsl_rng_.state = NULL;\t// not owned\n\t\n\tr.random_bool_bit_buffer_ = 0;\n\tr.random_bool_bit_counter_ = 0;\n}\n\nvoid Eidos_FreeRNG(void)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Eidos_FreeRNG(): RNG change\");\n\t\t\n\tif (!gEidos_RNG_Initialized)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_FreeRNG): (internal error) the Eidos random number generator has not been allocated.\" << EidosTerminate(nullptr);\n\t\n#ifndef _OPENMP\n\t//std::cout << \"***** Freeing one single-threaded RNG\" << std::endl;\n\t\n\t_Eidos_FreeOneRNG(gEidos_RNG_SINGLE);\n#else\n\t//std::cout << \"***** Freeing \" << gEidosMaxThreads << \" independent RNGs\" << std::endl;\n\t\n\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t{\n\t\tEidos_RNG_State *rng_state = gEidos_RNG_PERTHREAD[threadIndex];\n\t\t_Eidos_FreeOneRNG(*rng_state);\n\t\tgEidos_RNG_PERTHREAD[threadIndex] = nullptr;\n\t\tfree(rng_state);\n\t}\n\t\n\tgEidos_RNG_PERTHREAD.resize(0);\n#endif\n\t\n\tgEidos_RNG_Initialized = false;\n}\n\nvoid _Eidos_SetOneRNGSeed(Eidos_RNG_State &r, unsigned long int p_seed)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"_Eidos_SetOneRNGSeed(): RNG change\");\n\t\n\t//std::cout << \"***** Setting seed \" << p_seed << \" on RNG\" << std::endl;\n\t\n\t// pcg32_rng_ and pcg64_rng_ need the seed to be shifted left by two; the lowest two bits don't matter\n\t// see https://github.com/imneme/pcg-cpp/issues/79 for details on this, which seems to be a bug\n\tr.pcg32_rng_.seed(p_seed << 2);\n\tr.pcg64_rng_.seed(p_seed << 2);\n\t\n\t// we seem to need to re-point gsl_rng_ to pcg64_rng_; I don't really understand quite why...\n\tr.gsl_rng_.state = &r.pcg64_rng_;\n\t//gsl_rng_set(&r.gsl_rng_, p_seed);      // the generator was already seeded above through pcg64_rng_\n\t\n\t// remember the original user-supplied seed as part of the RNG state\n\tr.rng_last_seed_ = p_seed;\n\t\n\t// The random bit buffer state needs to be zeroed out, too; it is part of our RNG state\n\tr.random_bool_bit_counter_ = 0;\n\tr.random_bool_bit_buffer_ = 0;\n}\n\nvoid Eidos_SetRNGSeed(unsigned long int p_seed)\n{\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"Eidos_SetRNGSeed(): RNG change\");\n\t\n\tif (!gEidos_RNG_Initialized)\n\t\tEIDOS_TERMINATION << \"ERROR (Eidos_SetRNGSeed): (internal error) the Eidos random number generator has not been allocated.\" << EidosTerminate(nullptr);\n\t\n#ifndef _OPENMP\n\t_Eidos_SetOneRNGSeed(gEidos_RNG_SINGLE, p_seed);\n#else\n\t// Each thread's RNG gets a different seed.  We use the user-supplied seed for thread 0, so that non-parallel\n\t// code continues to reproduce the same random number sequence.  For other threads, we use system-generated seed\n\t// values.  This is non-reproducible, but parallel code involving the RNG is non-reproducible anyway.\n\tfor (int threadIndex = 0; threadIndex < gEidosMaxThreads; ++threadIndex)\n\t{\n\t\tunsigned long int thread_seed = (threadIndex == 0 ? p_seed : Eidos_GenerateRNGSeed());\n\t\t\n\t\t_Eidos_SetOneRNGSeed(*gEidos_RNG_PERTHREAD[threadIndex], thread_seed);\n\t}\n#endif\n}\n\n#ifndef USE_GSL_POISSON\ndouble Eidos_FastRandomPoisson_PRECALCULATE(double p_mu)\n{\n\t// OK, so where does 720 come from?  Primarily, values much greater than that cause an underflow in the algorithm\n\t// we're using to do fast Poisson draws, so that's a showstopper.  Devroye cites Atkinson 1979 as using lookup tables\n\t// for mu >= 2, but my testing indicates that that is unnecessary for our purposes (see poisson_test.R).  Presumably\n\t// Atkinson is trying to avoid any numerical error whatsoever, within the limits of double precision, but we are not\n\t// that strict; as long as the Poisson draw distribution is close enough to give basically the right mutation and\n\t// recombination rates, tiny numerical errors are not important to us.  My testing with poisson_test.R indicates that\n\t// our error is very small even at the largest values of p_mu that we allow.\n\t\n\t// We no longer raise for mu > 720.  Instead, we defer to the GSL in that case, when the draw actually occurs.\n\t//\n\t//if (p_mu > 720)\n\t//\tEIDOS_TERMINATION << \"ERROR (Eidos_FastRandomPoisson_PRECALCULATE): rate for Poisson draws is too large; please compile SLiM with -D USE_GSL_POISSON if you really want to use a mutation or recombination rate this high.\" << EidosTerminate(nullptr);\n\t\n\treturn exp(-p_mu);\n}\n#endif\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_rng.h",
    "content": "//\n//  eidos_rng.h\n//  Eidos\n//\n//  Created by Ben Haller on 12/13/14.\n//  Copyright (c) 2014-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n Eidos uses a globally shared random number generator.  This file defines that global and relevant helper\n functions.  Internally, it actually maintains a separate 32-bit and 64-bit generator seeded with the same\n value, for maximum speed when only 32 bits are needed.  When running multithreaded, there is one such\n generator setup per thread.\n \n */\n\n#ifndef __Eidos__eidos_rng__\n#define __Eidos__eidos_rng__\n\n\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n// BCH 1 November 2025: We now use the PCG random number generator.  See https://www.pcg-random.org.  This\n// is licensed under the Apache License, Version 2.0, which is GPL 3.0 compatible, so we have included it in\n// the project.  This was downloaded from the PCG website at https://www.pcg-random.org.  The original paper\n// on the PCG generator is at https://www.cs.hmc.edu/tr/hmc-cs-2014-0905.pdf and can be cited as:\n//\n//\tO’Neill, M. E. (2014). PCG: A family of simple fast space-efficient statistically good algorithms for\n//\t\trandom number generation. Harvey Mudd College, Claremont, CA: HMC-CS-2014-0905.\n//\n#include \"pcg_random.hpp\"\n\n#include <stdint.h>\n#include <cmath>\n#include <vector>\n#include \"eidos_globals.h\"\n\n\n// OK, so.  This header defines the Eidos random number generator, which is now a bit of a weird hybrid.\n// We need to use the GSL's RNG for most purposes, because we want to use its random distributions and so\n// forth.  However, we also want access to the RNG more directly, for greater speed; and we want to be\n// able to generate both 32-bit draws (for maximum speed) and 64-bit draws (for greater range/precision).\n// So we keep separate 32-bit and 64-bit generators seeded in the same way, and wrap the 64-bit generator\n// with a GSL generator so that we can use it through GSL calls as well.  These typedefs should be used:\ntypedef pcg32_fast EidosRNG_32_bit;\ntypedef pcg64_fast EidosRNG_64_bit;\n\n// This struct defines all of the variables associated with both RNGs; this is the complete Eidos RNG state.\ntypedef struct Eidos_RNG_State\n{\n\tunsigned long int rng_last_seed_;\t\t// unsigned long int is the type used for seeds in the GSL\n\t\n\t// We now use the pcg32_fast generator to get 32-bit random numbers for a few applications\n\tEidosRNG_32_bit pcg32_rng_;\n\t\n\t// We now use the pcg64_fast generator to get 64-bit random numbers for most purposes\n\tEidosRNG_64_bit pcg64_rng_;\n\t\n\t// Our GSL RNG simply wraps the pcg64_rng_ generator above, and contains an UNOWNED pointer to it\n\tgsl_rng gsl_rng_;\n\t\n\t// random coin-flip generator; this is based on the pcg64_rng_ generator now\n\tint random_bool_bit_counter_;\n\tuint64_t random_bool_bit_buffer_;\n} Eidos_RNG_State;\n\n\n// This is the globally shared random number generator.  Note that the globals for random bit generation below\n// are also considered to be part of the RNG state; if the Context plays games with swapping different RNGs in\n// and out, those globals need to get swapped as well.  Likewise for the last seed value; this is part of the\n// RNG state in Eidos.\n// BCH 11/5/2022: We now keep a single Eidos_RNG_State when running single-threaded, but when running\n// multithreaded we keep one Eidos_RNG_State per thread.  This allows threads to get random numbers without\n// any locking.  This means that each thread will have its own independent random number sequence, and makes\n// the concept of a \"seed\" a bit nebulous; in fact, each thread's RNG will be seeded with a different value so\n// that they do not all follow the same sequence.  The random number sequence when running multithreaded will\n// not be reproducible; but it really can't be, since multithreading will divide tasks up unpredictably and\n// execute out of linear sequence.\n// BCH 12/26/2022: The per-thread RNGs are now allocated separately, on the thread that will use them, so they\n// get kept in the best place in memory for that thread (\"first touch\").\nextern bool gEidos_RNG_Initialized;\n\n#ifndef _OPENMP\nextern Eidos_RNG_State gEidos_RNG_SINGLE;\n#else\nextern std::vector<Eidos_RNG_State *> gEidos_RNG_PERTHREAD;\n#endif\n\n// Calls to the GSL should use these macros to get the RNG state they need, whether single- or multi-threaded.\n// BCH 11/5/2022: The thread number must now be supplied.  It will be zero when single-threaded, and so is\n// ignored.  Since this is now a bit more heavyweight, the RNG for a thread should be obtained outside of any\n// core loops.  The most important thing is that when there is a parallel region, the RNG is obtained INSIDE\n// that region!  These can be used as follows:\n//\n//\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\n//\tEidosRNG_32_bit &rng_32 = EIDOS_32BIT_RNG(omp_get_thread_num());\n//\tEidosRNG_64_bit &rng_64 = EIDOS_64BIT_RNG(omp_get_thread_num());\n//\tEidos_RNG_State *rng_state = EIDOS_STATE_RNG(omp_get_thread_num());\n//\n#ifndef _OPENMP\n#define EIDOS_GSL_RNG(threadnum)\t(&gEidos_RNG_SINGLE.gsl_rng_)\n#define EIDOS_32BIT_RNG(threadnum)\t(gEidos_RNG_SINGLE.pcg32_rng_)\n#define EIDOS_64BIT_RNG(threadnum)\t(gEidos_RNG_SINGLE.pcg64_rng_)\n#define EIDOS_STATE_RNG(threadnum)\t(&gEidos_RNG_SINGLE)\n#else\n#define EIDOS_GSL_RNG(threadnum)\t(&gEidos_RNG_PERTHREAD[threadnum]->gsl_rng_)\n#define EIDOS_32BIT_RNG(threadnum)\t(gEidos_RNG_PERTHREAD[threadnum]->pcg32_rng_)\n#define EIDOS_64BIT_RNG(threadnum)\t(gEidos_RNG_PERTHREAD[threadnum]->pcg64_rng_)\n#define EIDOS_STATE_RNG(threadnum)\t(gEidos_RNG_PERTHREAD[threadnum])\n#endif\n\n#if DEBUG\n#define RNG_INIT_CHECK() if (!gEidos_RNG_Initialized) EIDOS_TERMINATION << \"ERROR (RNG_INIT_CHECK): (internal error) the Eidos random number generator is not initialized.\" << EidosTerminate(nullptr)\n#else\n#define RNG_INIT_CHECK()\n#endif\n\n// generate a new random number seed from the system - from /dev/random, or from PID and clock time, etc.\nunsigned long int Eidos_GenerateRNGSeed(void);\n\n// set up the random number generator with a given seed\n// these first three functions are only for code that creates its own local temporary RNG\nvoid _Eidos_InitializeOneRNG(Eidos_RNG_State &r);\nvoid _Eidos_FreeOneRNG(Eidos_RNG_State &r);\nvoid _Eidos_SetOneRNGSeed(Eidos_RNG_State &r, unsigned long int p_seed);\n\n// these next three functions set up the shared RNG used by most clients, and handle separate RNGs per-thread\nvoid Eidos_InitializeRNG(void);\nvoid Eidos_FreeRNG(void);\nvoid Eidos_SetRNGSeed(unsigned long int p_seed);\n\n// generates an unsigned 32-bit integer -- uint32_t\ninline __attribute__((always_inline)) uint32_t Eidos_rng_uniform_uint32(EidosRNG_32_bit &rng_32)\n{\n\tRNG_INIT_CHECK();\n\treturn rng_32();\n}\n\n// generates a signed 32-bit integer -- int32_t\ninline __attribute__((always_inline)) int32_t Eidos_rng_uniform_int32(EidosRNG_32_bit &rng_32)\n{\n\tRNG_INIT_CHECK();\n\treturn static_cast<int32_t>(rng_32());\n}\n\n// generates an unsigned 64-bit integer -- uint64_t\ninline __attribute__((always_inline)) uint64_t Eidos_rng_uniform_uint64(EidosRNG_64_bit &rng_64)\n{\n\tRNG_INIT_CHECK();\n\treturn rng_64();\n}\n\n// generates a signed 64-bit integer -- int64_t\ninline __attribute__((always_inline)) int64_t Eidos_rng_uniform_int64(EidosRNG_64_bit &rng_64)\n{\n\tRNG_INIT_CHECK();\n\treturn static_cast<int64_t>(rng_64());\n}\n\n// generates a random double in [0,1] -- including 0 and 1 (Closed-Closed)\ninline __attribute__((always_inline)) double Eidos_rng_uniform_doubleCC(EidosRNG_64_bit &rng_64)\n{\n\tRNG_INIT_CHECK();\n\treturn (rng_64() >> 11) * (1.0/9007199254740991.0);\n}\n\n// generates a random double in [0,1) -- including 0 but NOT 1 (Closed-Open)\ninline __attribute__((always_inline)) double Eidos_rng_uniform_doubleCO(EidosRNG_64_bit &rng_64)\n{\n\tRNG_INIT_CHECK();\n\treturn (rng_64() >> 11) * (1.0/9007199254740992.0);\n}\n\n// generates a random double in (0,1) -- including NEITHER 0 nor 1 (Open-Open)\ninline __attribute__((always_inline)) double Eidos_rng_uniform_doubleOO(EidosRNG_64_bit &rng_64)\n{\n\tRNG_INIT_CHECK();\n\treturn ((rng_64() >> 12) + 0.5) * (1.0/4503599627370496.0);\n}\n\n\n// generates a random unsigned 32-bit integer in the interval [0, p_n - 1]\ninline __attribute__((always_inline)) uint32_t Eidos_rng_interval_uint32(EidosRNG_32_bit &rng_32, uint32_t p_n)\n{\n\t// The gsl_rng_uniform_int() function is very slow, so this is a customized version that should be faster.\n\t// Basically it is faster because (1) the range of the generator is hard-coded, (2) the range check is done\n\t// only on #if DEBUG, and (3) it calls the generator directly, not through the GSL's pointer; otherwise the\n\t// logic is the same.\n\tuint32_t scale = UINT32_MAX / p_n;\n\tuint32_t k;\n\t\n#if DEBUG\n\tif ((p_n > INT32_MAX) || (p_n <= 0)) \n\t{\n\t\tGSL_ERROR_VAL(\"invalid n, either 0 or exceeds maximum value of generator\", GSL_EINVAL, 0);\n\t}\n#endif\n\t\n\tdo\n\t{\n\t\tk = rng_32() / scale;\n\t}\n\twhile (k >= p_n);\n\t\n\treturn k;\n}\n\n// generates a random unsigned 64-bit integer in the interval [0, p_n - 1]\ninline __attribute__((always_inline)) uint64_t Eidos_rng_interval_uint64(EidosRNG_64_bit &rng_64, uint64_t p_n)\n{\n\t// The gsl_rng_uniform_int() function is very slow, so this is a customized version that should be faster.\n\t// Basically it is faster because (1) the range of the generator is hard-coded, (2) the range check is done\n\t// only on #if DEBUG, and (3) it calls the generator directly, not through the GSL's pointer; otherwise the\n\t// logic is the same.\n\tuint64_t scale = UINT64_MAX / p_n;\n\tuint64_t k;\n\t\n#if DEBUG\n\tif ((p_n > INT64_MAX) || (p_n <= 0)) \n\t{\n\t\tGSL_ERROR_VAL(\"invalid n, either 0 or exceeds maximum value of generator\", GSL_EINVAL, 0);\n\t}\n#endif\n\t\n\tdo\n\t{\n\t\tk = rng_64() / scale;\n\t}\n\twhile (k >= p_n);\n\t\n\treturn k;\n}\n\n// generates a random unsigned 64-bit integer in the interval [0, p_n - 1] using a fast but slightly biased\n// algorithm; this should only be used for p_n << UINT32_MAX so that the bias is undetectable\ninline __attribute__((always_inline)) uint64_t Eidos_rng_interval_uint64_FAST(EidosRNG_64_bit &rng_64, uint64_t p_n)\n{\n\t// OK, so.  The GSL's uniform int method, which we replicate in Eidos_rng_interval_uint64(), makes sure\n\t// that the probability of each integer is exactly equal by figuring out a scaling, and then looping on\n\t// generated draws, with that scaling applied, until it gets one that is in range.  Here we skip that extra\n\t// work and just use modulo.  This technically means our draws will be biased toward the low end, unless\n\t// p_n is an exact divisor of UINT64_MAX, I guess; but UINT64_MAX is so vastly large compared to the uses\n\t// we will put this generator to that the bias should be utterly undetectable.  We are not drawing values\n\t// in anywhere near the full range of the generator.  BCH 12 May 2018\n\treturn rng_64() % p_n;\n}\n\n\n// The gsl_ran_shuffle() function leans very heavily on gsl_rng_uniform_int(), which is very slow\n// as mentioned above.  This is the same code as gsl_ran_shuffle(), but calls Eidos_rng_interval_uint32().\n// It is also templated, to take advantage of std::swap(), which is faster than the GSL's generalized\n// swap() function.  This uses the Fisher-Yates algorithm.  BCH 12/30/2022: I tried using a different\n// algorithm called MergeShuffle (https://arxiv.org/abs/1508.03167), which is a parallelizable algorithm\n// with code available on GitHub; the authors claim that it is faster than Fisher-Yates.  For me it was\n// about twice as slow, in the sequential case, and with the speedup from parallelization it was still\n// a little slower.  It looks like their observed speed was due to cache locality (less of a win now,\n// as caches get ever bigger) and hand-tuned assembly code (not an option for us), and maybe also a\n// custom fast RNG optimized for generating single random bits.  So, Fisher-Yates it is.\ntemplate <class T> inline void Eidos_ran_shuffle_uint32(EidosRNG_32_bit &rng_32, T *base, uint32_t n)\n{\n\tfor (uint32_t i = n - 1; i > 0; i--)\n\t{\n\t\tuint32_t j = Eidos_rng_interval_uint32(rng_32, i + 1);\n\t\t\n\t\tstd::swap(base[i], base[j]);\n\t}\n}\n\ntemplate <class T> inline void Eidos_ran_shuffle_uint64(EidosRNG_64_bit &rng_64, T *base, uint64_t n)\n{\n\tfor (uint64_t i = n - 1; i > 0; i--)\n\t{\n\t\tuint64_t j = Eidos_rng_interval_uint64(rng_64, i + 1);\n\t\t\n\t\tstd::swap(base[i], base[j]);\n\t}\n}\n\n\n// Fast Poisson drawing, usable when mu is small; algorithm from Wikipedia, referenced to Luc Devroye,\n// Non-Uniform Random Variate Generation (Springer-Verlag, New York, 1986), chapter 10, page 505.\n// The GSL Poisson code does not allow us to precalculate the exp() value, it is more than three times\n// slower for some mu values, it doesn't let us force a non-zero draw, and it is not inlined (without\n// modifying the GSL code), so there are good reasons for us to roll our own.  However, our version is\n// safe only for mu < ~720, and the GSL's version is faster for mu > 250 anyway, so we cross over\n// to using the GSL for mu > 250.  This is done on a per-draw basis.\n\n// If someone does not trust our Poisson code, they can define USE_GSL_POISSON at compile time\n// (i.e., -D USE_GSL_POISSON) to use the gsl_ran_poisson() instead.  It does make a substantial\n// speed difference, though, so that option is turned off by default.  Note that at present the\n// rpois() Eidos function always uses the GSL in any case.\n\n//#define USE_GSL_POISSON\n\n#ifndef USE_GSL_POISSON\n\ninline __attribute__((always_inline)) unsigned int Eidos_FastRandomPoisson(Eidos_RNG_State *rng_state, double p_mu)\n{\n\tRNG_INIT_CHECK();\n\t\n\t// Defer to the GSL for large values of mu; see comments above.\n\tif (p_mu > 250)\n\t\treturn gsl_ran_poisson(&rng_state->gsl_rng_, p_mu);\n\t\n\tunsigned int x = 0;\n\tdouble p = exp(-p_mu);\n\tdouble s = p;\n\tdouble u = Eidos_rng_uniform_doubleCO(rng_state->pcg64_rng_);\n\t\n\twhile (u > s)\n\t{\n\t\t++x;\n\t\tp *= (p_mu / x);\n\t\ts += p;\n\t\t\n\t\t// If p_mu is too large (> ~720), this loop can hang as p underflows to zero.\n\t}\n\t\n\treturn x;\n}\n\n// This version allows the caller to supply a precalculated exp(-mu) value\ninline __attribute__((always_inline)) unsigned int Eidos_FastRandomPoisson(Eidos_RNG_State *rng_state, double p_mu, double p_exp_neg_mu)\n{\n\tRNG_INIT_CHECK();\n\t\n\t// Defer to the GSL for large values of mu; see comments above.\n\tif (p_mu > 250)\n\t\treturn gsl_ran_poisson(&rng_state->gsl_rng_, p_mu);\n\t\n\t// Test consistency; normally this is commented out\n\t//if (p_exp_neg_mu != exp(-p_mu))\n\t//\tEIDOS_TERMINATION << \"ERROR (Eidos_FastRandomPoisson): p_exp_neg_mu incorrect.\" << EidosTerminate(nullptr);\n\t\n\tunsigned int x = 0;\n\tdouble p = p_exp_neg_mu;\n\tdouble s = p;\n\tdouble u = Eidos_rng_uniform_doubleCO(rng_state->pcg64_rng_);\n\t\n\twhile (u > s)\n\t{\n\t\t++x;\n\t\tp *= (p_mu / x);\n\t\ts += p;\n\t\t\n\t\t// If p_mu is too large (> ~720), this loop can hang as p underflows to zero.\n\t}\n\t\n\treturn x;\n}\n\n// This version specifies that the count is guaranteed not to be zero; zero has been ruled out by a previous test\n// The GSL declares gsl_rng* parameters as const, which seems wrong and confuses cppcheck...\n// cppcheck-suppress constParameterPointer\ninline __attribute__((always_inline)) unsigned int Eidos_FastRandomPoisson_NONZERO(Eidos_RNG_State *rng_state, double p_mu, double p_exp_neg_mu)\n{\n\tRNG_INIT_CHECK();\n\t\n\t// Defer to the GSL for large values of mu; see comments above.\n\tif (p_mu > 250)\n\t{\n\t\tunsigned int result;\n\t\t\n\t\tdo\n\t\t{\n\t\t\tresult = gsl_ran_poisson(&rng_state->gsl_rng_, p_mu);\n\t\t}\n\t\twhile (result == 0);\n\t\t\n\t\treturn result;\n\t}\n\t\n\t// Test consistency; normally this is commented out\n\t//if (p_exp_neg_mu != exp(-p_mu))\n\t//\tEIDOS_TERMINATION << \"ERROR (Eidos_FastRandomPoisson_NONZERO): p_exp_neg_mu incorrect.\" << EidosTerminate(nullptr);\n\t\n\tunsigned int x = 0;\n\tdouble p = p_exp_neg_mu;\n\tdouble s = p;\n\tdouble u = Eidos_rng_uniform_doubleOO(rng_state->pcg64_rng_);\t// exclude 0.0 so u != s after rescaling\n\t\n\t// rescale u so that (u > s) is true in the first round\n\tu = u * (1.0 - s) + s;\n\t\n\t// do the first round, since we now know u > s\n\t++x;\n\tp *= p_mu;\t// divided by x, but x is now 1\n\ts += p;\n\t\n\twhile (u > s)\n\t{\n\t\t++x;\n\t\tp *= (p_mu / x);\n\t\ts += p;\n\t\t\n\t\t// If p_mu is too large (> ~720), this loop can hang as p underflows to zero.\n\t}\n\t\n\treturn x;\n}\n\ndouble Eidos_FastRandomPoisson_PRECALCULATE(double p_mu);\t// exp(-mu); can underflow to zero, in which case the GSL will be used\n\n\n#endif // USE_GSL_POISSON\n\n\n#pragma mark -\n#pragma mark Random coin-flips\n#pragma mark -\n\n// get a random bool from a random number generator\n//inline bool Eidos_RandomBool(gsl_rng *p_r) { return (bool)(taus_get(p_r->state) & 0x01); }\n\n// optimization of this is possible assuming each bit returned by the RNG is independent and usable as a random boolean.\n// the independence of all 64 bits seems to be a solid assumption for the MT64 generator, as far as I can tell.\ninline __attribute__((always_inline)) bool Eidos_RandomBool(Eidos_RNG_State *rng_state)\n{\n\tRNG_INIT_CHECK();\n\t\n#if 0\n\t// This method gets one uint64_t at a time, and uses all 64 of its bits as random bools.  This is\n\t// aesthetically nice, but does have overhead for the branch, and for reading and writing the state.\n\tbool retval;\n\t\n\tif (rng_state->random_bool_bit_counter_ > 0)\n\t{\n\t\trng_state->random_bool_bit_counter_--;\n\t\trng_state->random_bool_bit_buffer_ >>= 1;\n\t\tretval = rng_state->random_bool_bit_buffer_ & 0x01;\n\t}\n\telse\n\t{\n\t\trng_state->random_bool_bit_buffer_ = rng_state->pcg64_rng_();\t// pcg64 provides 64 independent bits\n\t\trng_state->random_bool_bit_counter_ = 63;\t\t\t\t\t\t// 64 good bits originally, and we're about to use one\n\t\t\n\t\tretval = rng_state->random_bool_bit_buffer_ & 0x01;\n\t}\n\t\n\treturn retval;\n#elif 1\n\t// BCH 11/1/2025: This is an optimized version of the version above.  Rather than shifting the bit buffer\n\t// down by 1 and writing it out again, it shifts down by the count each time, so it doesn't need to write it.\n\tint bit_counter = rng_state->random_bool_bit_counter_;\n\t\n\tif (bit_counter > 0)\n\t{\n\t\trng_state->random_bool_bit_counter_ = --bit_counter;\n\t\t\n\t\treturn (rng_state->random_bool_bit_buffer_ >> bit_counter) & 0x01;\n\t}\n\telse\n\t{\n\t\tuint64_t next_uint64 = rng_state->pcg64_rng_();\t\t\t\t\t// pcg64 provides 64 independent bits\n\t\t\n\t\trng_state->random_bool_bit_buffer_ = next_uint64;\n\t\trng_state->random_bool_bit_counter_ = 63;\t\t\t\t\t\t// 64 good bits originally, and we're about to use one\n\t\t\n\t\treturn (next_uint64 >> 63);\n\t}\n#else\n\t// This version simply generates a new uint32 each time and uses its lowest-order bit; I was curious to\n\t// see whether, with the pcg32_fast generator, this might actually be faster (no branches), but it isn't.\n\tuint32_t next_uint32 = rng_state->pcg32_rng_();\t\t\t\t\t// pcg32 provides a good low-order bit\n\t\n\treturn (next_uint32 & 0x01);\n#endif\n}\n\n\n#endif /* defined(__Eidos__eidos_rng__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_script.cpp",
    "content": "//\n//  eidos_script.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_script.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_value.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_ast_node.h\"\n\n#include <iostream>\n#include <sstream>\n#include <utility>\n\n\n// set these to true to get logging of tokens / AST / evaluation\nbool gEidosLogTokens = false;\nbool gEidosLogAST = false;\nbool gEidosLogEvaluation = false;\n\n\n// From stack overflow http://stackoverflow.com/questions/15038616/how-to-convert-between-character-and-byte-position-in-objective-c-c-c\n// by Dietrich Epp.  This function converts a \"character\" position in, e.g., std::string, which uses UTF-8, to a \"character\"\n// position in, e.g., NSString/QString, which use UTF-16.  We don't use Eidos_utf8_utf16width(), but we use BYTE_WIDTHS,\n// so I've kept Eidos_utf8_utf16width() here as a sort of documentation for what BYTE_WIDTHS means.\nstatic const unsigned char BYTE_WIDTHS[256] = {\n\t// 1-byte: 0xxxxxxx\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n\t// Trailing: 10xxxxxx\n\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t// 2-byte leading: 110xxxxx\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n\t// 3-byte leading: 1110xxxx\n\t// 4-byte leading: 11110xxx\n\t// invalid: 11111xxx\n\t1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0\n};\n\n/*\nstatic size_t Eidos_utf8_utf16width(const unsigned char *string, size_t len)\n{\n\tsize_t i, utf16len = 0;\n\tfor (i = 0; i < len; i++)\n\t\tutf16len += BYTE_WIDTHS[string[i]];\n\treturn utf16len;\n}\n*/\n\n\n//\n//\tScript\n//\n#pragma mark -\n#pragma mark EidosScript\n#pragma mark -\n\n// This constructor is for a script that is unmoored from the user script, like a lambda.  There is no way\n// to correlate error positions in it back to the user script, no way to set debug points in it, etc.\nEidosScript::EidosScript(std::string p_script_string) : script_string_(std::move(p_script_string))\n{\n}\n\n// This constructor locates the script within in the context of the user's script, allowing things like debug\n// points and error tracking to be correlated between this derived script and the original user script.  For\n// the user script itself, the user script pointer should be nullptr and the offsets should be zero; the fact\n// that they are not -1 implies that they are valid offsets, and the fact the user script pointer is nullptr\n// says \"I *am* the user script\".\nEidosScript::EidosScript(std::string p_script_string, EidosScript *p_user_script, int32_t p_user_script_line_offset, int32_t p_user_script_char_offset, int32_t p_user_script_UTF16_offset) :\n\tscript_string_(std::move(p_script_string)), user_script_(p_user_script), user_script_line_offset_(p_user_script_line_offset), user_script_offset_(p_user_script_char_offset), user_script_offset_UTF16_(p_user_script_UTF16_offset)\n{\n}\n\nEidosScript::~EidosScript(void)\n{\n\t// destroy the parse root and return it to the pool; the tree must be allocated out of gEidosASTNodePool!\n\tif (parse_root_)\n\t{\n\t\tparse_root_->~EidosASTNode();\n\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(parse_root_));\n\t\tparse_root_ = nullptr;\n\t}\n}\n\nvoid EidosScript::Tokenize(bool p_make_bad_tokens, bool p_keep_nonsignificant)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosScript::Tokenize():  token_stream_ change\");\n\t\n\t// set up error tracking for this script\n\t// Note: Here and elsewhere in this method, if p_make_bad_tokens is set we do not do error tracking.  This\n\t// is so that we don't overwrite valid error tracking info when we're tokenizing for internal purposes.\n\tEidosScript *current_script_save = gEidosErrorContext.currentScript;\n\tif (!p_make_bad_tokens)\n\t\tgEidosErrorContext.currentScript = this;\n\t\n\t// delete all existing tokens\n\ttoken_stream_.clear();\n\t\n\t// destroy the parse root and return it to the pool; the tree must be allocated out of gEidosASTNodePool!\n\tif (parse_root_)\n\t{\n\t\tparse_root_->~EidosASTNode();\n\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(parse_root_));\n\t\tparse_root_ = nullptr;\n\t}\n\t\n\t// chew off one token at a time from script_string_, make a Token object, and add it\n\tint32_t pos = 0, len = (int)script_string_.length();\n\tint32_t pos_UTF16 = 0;\n\tint32_t pos_line = user_script_line_offset_;\t// could be -1, or a line number in the full user script\n\tbool saw_unicode = false;\t// set when a Unicode character is seen, to trigger extra checks\n\t\n\twhile (pos < len)\n\t{\n\t\tint32_t token_start = pos;\t\t\t\t\t\t\t\t\t\t\t\t\t// the first character position in the current token\n\t\tint32_t token_end = pos;\t\t\t\t\t\t\t\t\t\t\t\t\t// the last character position in the current token\n\t\tint ch = (unsigned char)script_string_[pos];\t\t\t\t\t\t\t\t// the current character\n\t\tint ch2 = ((pos >= len) ? 0 : (unsigned char)script_string_[pos + 1]);\t\t// look ahead one character (assuming ch is a single-byte character)\n\t\tbool skip = false;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// set to true to skip creating/adding this token\n\t\tEidosTokenType token_type = EidosTokenType::kTokenNone;\n\t\tstd::string token_string;\n\t\tint32_t token_UTF16_start = pos_UTF16;\n\t\tint32_t token_UTF16_end = pos_UTF16;\n\t\tint32_t token_line = pos_line;\t\t\t\t\t\t\t\t\t\t\t\t// the line for a token is the first line it contains\n\t\t\n\t\tswitch (ch)\n\t\t{\n\t\t\t// cases that require just a single character to match\n\t\t\tcase ';': token_type = EidosTokenType::kTokenSemicolon; break;\n\t\t\tcase ':': token_type = EidosTokenType::kTokenColon; break;\n\t\t\tcase ',': token_type = EidosTokenType::kTokenComma; break;\n\t\t\tcase '{': token_type = EidosTokenType::kTokenLBrace; break;\n\t\t\tcase '}': token_type = EidosTokenType::kTokenRBrace; break;\n\t\t\tcase '(': token_type = EidosTokenType::kTokenLParen; break;\n\t\t\tcase ')': token_type = EidosTokenType::kTokenRParen; break;\n\t\t\tcase '[': token_type = EidosTokenType::kTokenLBracket; break;\n\t\t\tcase ']': token_type = EidosTokenType::kTokenRBracket; break;\n\t\t\tcase '.': token_type = EidosTokenType::kTokenDot; break;\n\t\t\tcase '+': token_type = EidosTokenType::kTokenPlus; break;\n\t\t\tcase '-': token_type = EidosTokenType::kTokenMinus; break;\n\t\t\tcase '*': token_type = EidosTokenType::kTokenMult; break;\n\t\t\tcase '^': token_type = EidosTokenType::kTokenExp; break;\n\t\t\tcase '%': token_type = EidosTokenType::kTokenMod; break;\n\t\t\tcase '&': token_type = EidosTokenType::kTokenAnd; break;\n\t\t\tcase '|': token_type = EidosTokenType::kTokenOr; break;\n\t\t\tcase '?': token_type = EidosTokenType::kTokenConditional; break;\n\t\t\tcase '$': token_type = EidosTokenType::kTokenSingleton; break;\n\t\t\t\n\t\t\t// cases that require lookahead due to ambiguity: =, <, >, !, /\n\t\t\tcase '=':\n\t\t\t\tif (ch2 == '=') { token_type = EidosTokenType::kTokenEq; token_end++; token_UTF16_end++; }\n\t\t\t\telse { token_type = EidosTokenType::kTokenAssign; }\n\t\t\t\tbreak;\n\t\t\tcase '<':\t// <<DELIM \"here document\"-style string, or <= or <- or <\n\t\t\t\tif (ch2 == '<')\n\t\t\t\t{\n\t\t\t\t\t// A \"here document\" string literal; starts with <<DELIM and ends with >>DELIM, where DELIM is any\n\t\t\t\t\t// character sequence (including no delim) followed by a newline that is not part of DELIM.\n\t\t\t\t\t// This style of string literal has no escape sequences, and allows newlines.\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenString;\n\t\t\t\t\t\n\t\t\t\t\t// find the delimiter; it may be any characters at all, or none, followed by a newline or EOF\n\t\t\t\t\t// there is always at least a zero-length delimiter, so this cannot fail\n\t\t\t\t\tint32_t delim_start_pos = pos + 2;\n\t\t\t\t\tint32_t delim_end_pos = pos + 1;\n\t\t\t\t\tint32_t delim_end_pos_UTF16 = pos_UTF16 + 1;\n\t\t\t\t\tint32_t delim_length_UTF16 = 0;\n\t\t\t\t\t\n\t\t\t\t\twhile (delim_end_pos + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned char chn = (unsigned char)script_string_[delim_end_pos + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((chn == '\\n') || (chn == '\\r'))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\tdelim_end_pos++;\n\t\t\t\t\t\tdelim_end_pos_UTF16 += BYTE_WIDTHS[chn];\n\t\t\t\t\t\tdelim_length_UTF16 += BYTE_WIDTHS[chn];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// now move characters into the string literal until we find a newline followed by the end-delimiter\n\t\t\t\t\tint delim_length = delim_end_pos - delim_start_pos + 1;\n\t\t\t\t\t\n\t\t\t\t\ttoken_end = delim_end_pos + 1;\t// skip the initial newline, which is not part of the string literal\n\t\t\t\t\ttoken_UTF16_end = delim_end_pos_UTF16 + 1;\n\t\t\t\t\tif (pos_line != -1)\n\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (token_end + 1 >= len)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): unexpected EOF in custom-delimited string literal.\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tunsigned char chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (((chn == '\\n') || (chn == '\\r')) && (token_end + 1 + delim_length + 2 < len))\t// +1 for the newlines, +2 for \">>\", plus the delimiter itself, must all fit before the EOF\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((script_string_[token_end + 2] == '>') && (script_string_[token_end + 3] == '>'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint delim_index;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (delim_index = 0; delim_index < delim_length; ++delim_index)\n\t\t\t\t\t\t\t\t\tif (script_string_[token_end + 4 + delim_index] != script_string_[delim_start_pos + delim_index])\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (delim_index == delim_length)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// the full delimiter matched, so we are done; advance by newline + '>' + '>' + delimiter\n\t\t\t\t\t\t\t\t\ttoken_end = token_end + 3 + delim_length;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end = token_UTF16_end + 3 + delim_length_UTF16;\n\t\t\t\t\t\t\t\t\tif ((pos_line != -1) && (chn == '\\n'))\n\t\t\t\t\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// the current character is not the start of an end-delimiter, so it is part of the token's string\n\t\t\t\t\t\ttoken_string += chn;\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\tif ((pos_line != -1) && (chn == '\\n'))\n\t\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (ch2 == '=') { token_type = EidosTokenType::kTokenLtEq; token_end++; token_UTF16_end++; }\n\t\t\t\t\telse if (ch2 == '-') { token_type = EidosTokenType::kTokenAssign_R; token_end++; token_UTF16_end++; }\n\t\t\t\t\telse { token_type = EidosTokenType::kTokenLt; }\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '>':\t// >= or >\n\t\t\t\tif (ch2 == '=') { token_type = EidosTokenType::kTokenGtEq; token_end++; token_UTF16_end++; }\n\t\t\t\telse { token_type = EidosTokenType::kTokenGt; }\n\t\t\t\tbreak;\n\t\t\tcase '!':\t// != or !\n\t\t\t\tif (ch2 == '=') { token_type = EidosTokenType::kTokenNotEq; token_end++; token_UTF16_end++; }\n\t\t\t\telse { token_type = EidosTokenType::kTokenNot; }\n\t\t\t\tbreak;\n\t\t\tcase '/':\t// // or /* or /\n\t\t\t\tif (ch2 == '/') {\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenComment;\n\t\t\t\t\tskip = true;\n\t\t\t\t\t\n\t\t\t\t\t// stop at the end of the input string, unless we see a newline first\n\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned char chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\t// stop short of eating the newline\n\t\t\t\t\t\tif ((chn == '\\n') || (chn == '\\r'))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (ch2 == '*') {\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenCommentLong;\n\t\t\t\t\tskip = true;\n\t\t\t\t\t\n\t\t\t\t\t// eat the asterisk\n\t\t\t\t\ttoken_end++;\n\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[ch2];\n\t\t\t\t\t\n\t\t\t\t\tint nest_count = 1;\t\t// /* */ comments in Eidos nest properly, so we keep a count\n\t\t\t\t\t\n\t\t\t\t\t// stop at the end of the input string, unless we see a terminator first\n\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned char chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (chn == '*')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (token_end + 2 < len)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tunsigned char chnn = (unsigned char)script_string_[token_end + 2];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (chnn == '/')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// We see a */, so eat it\n\t\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chnn];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (--nest_count == 0)\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (chn == '/')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (token_end + 2 < len)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tunsigned char chnn = (unsigned char)script_string_[token_end + 2];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif (chnn == '*')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// We see a /*, so eat it\n\t\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chnn];\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t++nest_count;\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\tif ((pos_line != -1) && (chn == '\\n'))\n\t\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse { token_type = EidosTokenType::kTokenDiv; }\n\t\t\t\tbreak;\n\t\t\t\n\t\t\t// cases that require advancement: numbers, strings, identifiers, identifier-like tokens, whitespace\n\t\t\tdefault:\n\t\t\t\tif ((ch == ' ') || (ch == '\\t') || (ch == '\\n') || (ch == '\\r'))\n\t\t\t\t{\n\t\t\t\t\t// whitespace; any nonzero-length sequence of space, tab, \\n, \\r\n\t\t\t\t\tif ((pos_line != -1) && (ch == '\\n'))\n\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t\n\t\t\t\t\t// FIXME it would be nice for &nbsp; to be considered whitespace too, but that gets bogged down\n\t\t\t\t\t// in encoding issues I guess; we are not very Unicode-friendly right now.  BCH 2 Nov. 2017\n\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((chn == ' ') || (chn == '\\t') || (chn == '\\n') || (chn == '\\r'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\tif ((pos_line != -1) && (chn == '\\n'))\n\t\t\t\t\t\t\t\tpos_line++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenWhitespace;\n\t\t\t\t\tskip = true;\n\t\t\t\t}\n\t\t\t\telse if ((ch >= '0') && (ch <= '9'))\n\t\t\t\t{\n\t\t\t\t\t// number: regex something like this, off the top of my head: [0-9]+(\\.[0-9]*)?([e|E][-|+]?[0-9]+)?\n\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((chn >= '0') && (chn <= '9'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// optional decimal sequence\n\t\t\t\t\tif ((token_end + 1 < len) && (script_string_[token_end + 1] == '.'))\n\t\t\t\t\t{\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((chn >= '0') && (chn <= '9'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// optional exponent sequence\n\t\t\t\t\tif ((token_end + 1 < len) && ((script_string_[token_end + 1] == 'e') || (script_string_[token_end + 1] == 'E')))\n\t\t\t\t\t{\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// optional sign\n\t\t\t\t\t\tif ((token_end + 1 < len) && ((script_string_[token_end + 1] == '+') || (script_string_[token_end + 1] == '-')))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// mandatory exponent value; if this is missing, we drop through and token_type == EidosTokenType::kTokenNone\n\t\t\t\t\t\tif ((token_end + 1 < len) && ((script_string_[token_end + 1] >= '0') && (script_string_[token_end + 1] <= '9')))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((chn >= '0') && (chn <= '9'))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenNumber;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenNumber;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || (ch == '_') || (ch & 0x0080))\n\t\t\t\t{\n\t\t\t\t\t// BCH: extending this to allow non-ASCII Unicode characters in identifiers.  We just assume that\n\t\t\t\t\t// all UTF-8 sequences starting with 0x80 or greater are usable in identifiers, for simplicity.\n\t\t\t\t\t// Note that EidosConsoleWindowController has some useful debugging code; search for @\"<EOF>\"\n\t\t\t\t\t// BCH 09/28/2021: Note that we will now scan identifiers for illegal Unicode characters below.\n\t\t\t\t\t\n\t\t\t\t\t// If the high bit is set, this is the start of a UTF-8 multi-byte sequence; eat the whole sequence\n\t\t\t\t\t// The design of this code assumes that UTF-8 sequences are compliant and EOF does not occur inside them\n\t\t\t\t\tif (ch & 0x0080)\n\t\t\t\t\t{\n\t\t\t\t\t\t// We already include the current character; now advance over the characters following it.  Note\n\t\t\t\t\t\t// that this does the full advance for UTF-16 (trailing bytes will have BYTE_WIDTHS == 0), but\n\t\t\t\t\t\t// only one character advance for UTF-8; the remaining UTF-8 characters will be eaten below.\n\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[ch];\n\t\t\t\t\t\tsaw_unicode = true;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile (token_end < len)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((chn & 0x00C0) == 0x00C0)\t// start of a new Unicode multi-byte sequence; stop\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (chn & 0x0080)\t\t\t// trailing byte of the current Unicode multi-byte sequence; eat it\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoken_end++; token_UTF16_end += BYTE_WIDTHS[chn];\t// BYTE_WIDTHS will be 0\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\t\t\t\t\t\t\t// an ordinary character following the Unicode sequence; stop\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// At this point, we have advanced into the next character, which may not be part of the identifier.  We want\n\t\t\t\t\t\t// to move backwards so the end of the token is correctly defined.  We have gone one UTF-8 character too\n\t\t\t\t\t\t// far now, and we have also gone one UTF-16 character too far (we want token_UTF16_end to be the last\n\t\t\t\t\t\t// UTF-16 character in the multi-byte sequence, not the first UTF-16 character of the next).\n\t\t\t\t\t\ttoken_end--;\n\t\t\t\t\t\ttoken_UTF16_end--;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// identifier: regex something like this: [a-zA-Z_][a-zA-Z0-9_]*\n\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tint chx = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (((chx >= 'a') && (chx <= 'z')) || ((chx >= 'A') && (chx <= 'Z')) || ((chx >= '0') && (chx <= '9')) || (chx == '_'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Advance to include the current character.\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (chx & 0x0080)\t// start of a UTF-8 sequence, as above\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Advance to include the current character.  Note that the design here is a little different from\n\t\t\t\t\t\t\t// above; here we do a lookahead, confirm that the character is edible, and then eat it.  Above\n\t\t\t\t\t\t\t// we already included the current character (because each new token automatically includes the\n\t\t\t\t\t\t\t// current character), and were advancing to the *next* character, and then ultimately backing up.\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chx];\n\t\t\t\t\t\t\tsaw_unicode = true;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\twhile (token_end + 1 < len)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tif ((chn & 0x00C0) == 0x00C0)\t// start of a new Unicode multi-byte sequence; stop\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse if (chn & 0x0080)\t\t\t// trailing byte of the current Unicode multi-byte sequence; eat it\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttoken_end++; token_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\t\t\t\t\t\t\t// an ordinary character following the Unicode sequence; stop\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// We do not back up here, the way we did above, because this loop is based on lookahead.\n\t\t\t\t\t\t\t//token_end--;\n\t\t\t\t\t\t\t//token_UTF16_end--;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenIdentifier;\n\t\t\t\t}\n\t\t\t\telse if ((ch == '\"') || (ch == '\\''))\n\t\t\t\t{\n\t\t\t\t\tbool double_quoted = (ch == '\"');\n\t\t\t\t\t\n\t\t\t\t\t// string literal: bounded by double quotes, with escapes (\\t, \\r, \\n, \\\", \\', \\\\), newlines not allowed\n\t\t\t\t\ttoken_type = EidosTokenType::kTokenString;\n\t\t\t\t\t\n\t\t\t\t\tdo \n\t\t\t\t\t{\n\t\t\t\t\t\t// unlike most other tokens, string literals do not terminate automatically at EOF or an illegal character\n\t\t\t\t\t\tif (token_end + 1 == len)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): unexpected EOF in string literal \" << (double_quoted ? \"\\\"\" : \"'\") << token_string << (double_quoted ? \"\\\"\" : \"'\") << \".\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tunsigned char chn = (unsigned char)script_string_[token_end + 1];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (chn == (double_quoted ? '\"' : '\\''))\t// NOLINT(*-signed-char-misuse) : using unsigned char to make BYTE_WIDTHS accesses safe\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// end of string\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (chn == '\\\\')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// escape sequence; another character must exist\n\t\t\t\t\t\t\tif (token_end + 2 == len)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): unexpected EOF in string literal \" << (double_quoted ? \"\\\"\" : \"'\") << token_string << (double_quoted ? \"\\\"\" : \"'\") << \".\" << EidosTerminate();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tunsigned char ch_esq = (unsigned char)script_string_[token_end + 2];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ((ch_esq == 't') || (ch_esq == 'r') || (ch_esq == 'n') || (ch_esq == '\"') || (ch_esq == '\\'') || (ch_esq == '\\\\'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// a legal escape, so replace it with the escaped character here\n\t\t\t\t\t\t\t\tif (ch_esq == 't')\t\t\ttoken_string += '\\t';\n\t\t\t\t\t\t\t\telse if (ch_esq == 'r')\t\ttoken_string += '\\r';\n\t\t\t\t\t\t\t\telse if (ch_esq == 'n')\t\ttoken_string += '\\n';\n\t\t\t\t\t\t\t\telse if (ch_esq == '\"')\t\ttoken_string += '\"';\n\t\t\t\t\t\t\t\telse if (ch_esq == '\\'')\ttoken_string += '\\'';\n\t\t\t\t\t\t\t\telse if (ch_esq == '\\\\')\ttoken_string += '\\\\';\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\ttoken_end += 2;\n\t\t\t\t\t\t\t\ttoken_UTF16_end += 2;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// an illegal escape; if we are making bad tokens, we tolerate the error and continue\n\t\t\t\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttoken_string += ch_esq;\n\t\t\t\t\t\t\t\t\ttoken_end += 2;\n\t\t\t\t\t\t\t\t\ttoken_UTF16_end += 1 + BYTE_WIDTHS[ch_esq];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_end + 1, token_end + 2, token_UTF16_end + 1, token_UTF16_end + 1 + BYTE_WIDTHS[ch_esq]};\n\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): illegal escape \\\\\" << (char)ch_esq << \" in string literal \" << (double_quoted ? \"\\\"\" : \"'\") << token_string << (double_quoted ? \"\\\"\" : \"'\") << \".\" << EidosTerminate();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ((chn == '\\n') || (chn == '\\r'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// literal newlines are not allowed within string literals at present\n\t\t\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): illegal newline in string literal \" << (double_quoted ? \"\\\"\" : \"'\") << token_string << (double_quoted ? \"\\\"\" : \"'\") << \".\" << EidosTerminate();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// all other characters get eaten up as part of the string literal\n\t\t\t\t\t\t\ttoken_string += chn;\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\twhile (true);\n\t\t\t\t}\n\t\t\t\telse if (ch & 0x0080)\n\t\t\t\t{\n\t\t\t\t\t// Note that this code is no longer hit; all high-bit characters now go through the kTokenIdentifier path above.\n\t\t\t\t\t// The high bit is set, so this is some sort of Unicode special byte, initiating a multi-byte sequence comprising an\n\t\t\t\t\t// illegal non-ASCII character; encompass the whole thing into the token so errors, bad tokens, etc. work correctly\n\t\t\t\t\t// The design of this code assumes that UTF-8 sequences are compliant and EOF does not occur inside them\n\n\t\t\t\t\t// Advance over the current character to include the character following it; note that this\n\t\t\t\t\t// does the full advance for UTF-16 (trailing bytes will have BYTE_WIDTHS == 0), but only\n\t\t\t\t\t// one character advance for UTF-8; the remaining UTF-8 characters will be eaten below.\n\t\t\t\t\ttoken_end++;\n\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[ch];\n\t\t\t\t\t\n\t\t\t\t\twhile (token_end < len)\n\t\t\t\t\t{\n\t\t\t\t\t\tint chn = (unsigned char)script_string_[token_end];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((chn & 0x00C0) == 0x00C0)\t\t// NOLINTNEXTLINE(*-branch-clone) : intentional branch clones\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the two high bits are both set, so this is the beginning of a successive Unicode multi-byte sequence, which we don't want to run into\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (chn & 0x0080)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the high bit is set, so this is a trailing byte of the current Unicode multi-byte sequence, so eat it\n\t\t\t\t\t\t\ttoken_end++;\n\t\t\t\t\t\t\ttoken_UTF16_end += BYTE_WIDTHS[chn];\t// BYTE_WIDTHS will be 0\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the high bit is not set, so this is an ordinary character following the Unicode sequence, which we don't want to run into\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// At this point, we have advanced into the next character, which is not part of the bad token.  We want\n\t\t\t\t\t// to move backwards so the end of the token is correctly defined.  We have gone one UTF-8 character too\n\t\t\t\t\t// far now, and we have also gone one UTF-16 character too far (we want token_UTF16_end to be the last\n\t\t\t\t\t// UTF-16 character in the multi-byte sequence, not the first UTF-16 character of the next).\n\t\t\t\t\ttoken_end--;\n\t\t\t\t\ttoken_UTF16_end--;\n\t\t\t\t}\n\t\t\t\t// else: ch is an ASCII-range single character that does not match any possible token, so it will be handled by the token_type == EidosTokenType::kTokenNone case directly below\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\tif (saw_unicode)\n\t\t{\n\t\t\t// Look for illegal Unicode characters in identifiers.  If we find one, we throw an error or make a bad token.\n\t\t\t// This answer is helpful: https://stackoverflow.com/a/69024306/2752221; it suggests that a regex-style list is\n\t\t\t// [\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F\\u2000-\\u200F\\u2028-\\u202F\\u205F-\\u206F\\u3000\\uFEFF].  We look for a\n\t\t\t// subset of those here, since I don't want to get into doing regex, etc.\n\t\t\tif (token_type == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tstd::string identifierString = script_string_.substr(token_start, token_end - token_start + 1);\n\t\t\t\t\n\t\t\t\tif (Eidos_ContainsIllegalUnicode(identifierString))\n\t\t\t\t{\n\t\t\t\t\tif (p_make_bad_tokens)\n\t\t\t\t\t{\n\t\t\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// during tokenization we don't treat the error position as a stack\n\t\t\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): illegal Unicode character in token '\" << script_string_.substr(token_start, token_end - token_start + 1) << \"' (note the illegal character may not print visibly).  Deleting it is recommended; if it is not visible, you might select across it and retype the text it is contained within.\" << EidosTerminate();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tsaw_unicode = false;\n\t\t}\n\t\t\n\t\tif (token_type == EidosTokenType::kTokenNone)\n\t\t{\n\t\t\t// failed to find a match; this causes either a syntax error raise or a bad token\n\t\t\tif (p_make_bad_tokens)\n\t\t\t{\n\t\t\t\ttoken_type = EidosTokenType::kTokenBad;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// during tokenization we don't treat the error position as a stack\n\t\t\t\tgEidosErrorContext.errorPosition = EidosErrorPosition{token_start, token_end, token_UTF16_start, token_UTF16_end};\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Tokenize): unrecognized token at '\" << script_string_.substr(token_start, token_end - token_start + 1) << \"'.\" << EidosTerminate();\n\t\t\t}\n\t\t}\n\t\t\n\t\t// if skip == true, we just discard the token and continue, as for whitespace and comments\n\t\tif (p_keep_nonsignificant || !skip)\n\t\t{\n\t\t\t// construct the token string from the range, if it has not already been set; the exception is\n\t\t\t// string tokens, which may be zero length at this point, and are already set up\n\t\t\tif ((token_type != EidosTokenType::kTokenString) && !token_string.size())\n\t\t\t\ttoken_string = script_string_.substr(token_start, token_end - token_start + 1);\n\t\t\t\n\t\t\t// figure out identifier-like tokens, which all get tokenized as kTokenIdentifier above\n\t\t\tif (token_type == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tif (token_string.compare(gEidosStr_if) == 0) token_type = EidosTokenType::kTokenIf;\n\t\t\t\telse if (token_string.compare(gEidosStr_else) == 0) token_type = EidosTokenType::kTokenElse;\n\t\t\t\telse if (token_string.compare(gEidosStr_do) == 0) token_type = EidosTokenType::kTokenDo;\n\t\t\t\telse if (token_string.compare(gEidosStr_while) == 0) token_type = EidosTokenType::kTokenWhile;\n\t\t\t\telse if (token_string.compare(gEidosStr_for) == 0) token_type = EidosTokenType::kTokenFor;\n\t\t\t\telse if (token_string.compare(gEidosStr_in) == 0) token_type = EidosTokenType::kTokenIn;\n\t\t\t\telse if (token_string.compare(gEidosStr_next) == 0) token_type = EidosTokenType::kTokenNext;\n\t\t\t\telse if (token_string.compare(gEidosStr_break) == 0) token_type = EidosTokenType::kTokenBreak;\n\t\t\t\telse if (token_string.compare(gEidosStr_return) == 0) token_type = EidosTokenType::kTokenReturn;\n\t\t\t\telse if (token_string.compare(gEidosStr_function) == 0) token_type = EidosTokenType::kTokenFunction;\n\t\t\t\t\n\t\t\t\t// We used to modify the token string here for language keywords; we don't do that any more because it messed\n\t\t\t\t// up code completion, which assumes that the token string is a faithful copy of what matched the token.\n\t\t\t\t//if (token_type > EidosTokenType::kFirstIdentifierLikeToken)\n\t\t\t\t//\ttoken_string = \"<\" + token_string + \">\";\n\t\t\t}\n\t\t\t\n\t\t\t// make the token and push it\n\t\t\ttoken_stream_.emplace_back(token_type, token_string, token_start, token_end, token_UTF16_start, token_UTF16_end, token_line);\n\t\t}\n\t\t\n\t\t// advance to the character immediately past the end of this token\n\t\tpos = token_end + 1;\n\t\tpos_UTF16 = token_UTF16_end + 1;\n\t}\n\t\n\t// add an EOF token at the end\n\ttoken_stream_.emplace_back(EidosTokenType::kTokenEOF, \"EOF\", pos, pos, pos_UTF16, pos_UTF16, pos_line);\n\t\n\t// if logging of tokens is requested, do that\n\tif (gEidosLogTokens)\n\t{\n\t\tstd::cout << \"Tokens : \";\n\t\tthis->PrintTokens(std::cout);\n\t}\n\t\n\t// restore error tracking\n\tif (!p_make_bad_tokens)\n\t\tgEidosErrorContext.currentScript = current_script_save;\n}\n\nvoid EidosScript::Consume(void)\n{\n\t// consume the token unless it is an EOF; we effectively have an infinite number of EOF tokens at the end\n\tif (current_token_type_ != EidosTokenType::kTokenEOF)\n\t{\n\t\t++parse_index_;\n\t\tcurrent_token_ = &token_stream_.at(parse_index_);\n\t\tcurrent_token_type_ = current_token_->token_type_;\n\t}\n}\n\nvoid EidosScript::Match(EidosTokenType p_token_type, const char *p_context_cstr)\n{\n\tif (current_token_type_ == p_token_type)\n\t{\n\t\t// consume the token unless it is an EOF; we effectively have an infinite number of EOF tokens at the end\n\t\tif (current_token_type_ != EidosTokenType::kTokenEOF)\n\t\t{\n\t\t\t++parse_index_;\n\t\t\tcurrent_token_ = &token_stream_.at(parse_index_);\n\t\t\tcurrent_token_type_ = current_token_->token_type_;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// if we are doing a fault-tolerant parse, just pretend we saw the token; otherwise, not finding the right token type is fatal\n\t\tif (!parse_make_bad_nodes_)\n\t\t{\n\t\t\t// We give a special error message if the token encountered is an R-style assignment, <-, to help the user understand\n\t\t\tif (current_token_->token_type_ == EidosTokenType::kTokenAssign_R)\n\t\t\t\tEIDOS_TERMINATION << R\"V0G0N(ERROR (EidosScript::Match): the R-style assignment operator <- is not legal in Eidos.  For assignment, use operator =, like \"a = b;\".  For comparison to a negative quantity, use spaces to fix the tokenization, like \"a < -b;\".)V0G0N\" << EidosTerminate(current_token_);\n\t\t\telse\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Match): unexpected token '\" << *current_token_ << \"' in \" << std::string(p_context_cstr) << \"; expected '\" << p_token_type << \"'.\" << EidosTerminate(current_token_);\n\t\t}\n\t}\n}\n\nEidosASTNode *EidosScript::Parse_InterpreterBlock(bool p_allow_functions)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosScript::Parse_InterpreterBlock(): parse_root_ change\");\n\t\n\tEidosToken temp_token(EidosTokenType::kTokenInterpreterBlock, gEidosStr_empty_string, 0, 0, 0, 0, 0);\n\t\n\tEidosASTNode *node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(&temp_token);\t// the stack-local token is replaced below\n\t\n\ttry\n\t{\n\t\tint32_t token_start = current_token_->token_start_;\n\t\tint32_t token_UTF16_start = current_token_->token_UTF16_start_;\n\t\tint32_t token_line = current_token_->token_line_;\t// we use the line of our starting token\n\t\t\n\t\twhile (current_token_type_ != EidosTokenType::kTokenEOF)\n\t\t{\n\t\t\tEidosASTNode *child;\n\t\t\t\n\t\t\t// If p_allow_functions==T we're parsing a top-level interpreter block and function declarations are thus allowed.\n\t\t\t// If it is F, we are parsing something that is not a top-level block, and function declarations are not allowed.\n\t\t\tif (p_allow_functions && (current_token_type_ == EidosTokenType::kTokenFunction))\n\t\t\t\tchild = Parse_FunctionDecl();\n\t\t\telse\n\t\t\t\tchild = Parse_Statement();\n\t\t\t\n\t\t\tnode->AddChild(child);\n\t\t}\n\t\t\n\t\tint32_t token_end = current_token_->token_start_ - 1;\n\t\tint32_t token_UTF16_end = current_token_->token_UTF16_start_ - 1;\n\t\t\n\t\tMatch(EidosTokenType::kTokenEOF, \"interpreter block\");\n\t\t\n\t\t// swap in a new virtual token that encompasses all our children\n\t\tstd::string &&token_string = script_string_.substr(token_start, token_end - token_start + 1);\n\t\t\n\t\tnode->ReplaceTokenWithToken(new EidosToken(EidosTokenType::kTokenInterpreterBlock, token_string, token_start, token_end, token_UTF16_start, token_UTF16_end, token_line));\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_CompoundStatement(void)\n{\n\tEidosASTNode *node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\n\ttry\n\t{\n\t\tint32_t token_start = current_token_->token_start_;\n\t\tint32_t token_UTF16_start = current_token_->token_UTF16_start_;\n\t\tint32_t token_line = current_token_->token_line_;\t// we use the line of our starting token\n\t\t\n\t\tMatch(EidosTokenType::kTokenLBrace, \"compound statement\");\n\t\t\n\t\twhile ((current_token_type_ != EidosTokenType::kTokenRBrace) && (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t{\n\t\t\tEidosASTNode *child = Parse_Statement();\n\t\t\t\n\t\t\tnode->AddChild(child);\n\t\t}\n\t\t\n\t\tint token_end = current_token_->token_start_;\n\t\tint32_t token_UTF16_end = current_token_->token_UTF16_start_;\n\t\t\n\t\t// We remember, with a flag, if we hit the EOF before seeing our end brace; this is used by EidosTypeInterpreter to know\n\t\t// what scope was active at the point when the parse ended, so it can leave the correct type table in place\n\t\tif (current_token_type_ == EidosTokenType::kTokenEOF)\n\t\t\tnode->hit_eof_in_tolerant_parse_ = true;\n\t\t\n\t\tMatch(EidosTokenType::kTokenRBrace, \"compound statement\");\n\t\t\n\t\t// swap in a new virtual token that encompasses all our children\n\t\tstd::string &&token_string = script_string_.substr(token_start, token_end - token_start + 1);\n\t\t\n\t\tnode->ReplaceTokenWithToken(new EidosToken(node->token_->token_type_, token_string, token_start, token_end, token_UTF16_start, token_UTF16_end, token_line));\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_Statement(void)\n{\n\tif (current_token_type_ == EidosTokenType::kTokenLBrace)\n\t\treturn Parse_CompoundStatement();\n\telse if (current_token_type_ == EidosTokenType::kTokenIf)\n\t\treturn Parse_SelectionStatement();\n\telse if (current_token_type_ == EidosTokenType::kTokenDo)\n\t\treturn Parse_DoWhileStatement();\n\telse if (current_token_type_ == EidosTokenType::kTokenWhile)\n\t\treturn Parse_WhileStatement();\n\telse if (current_token_type_ == EidosTokenType::kTokenFor)\n\t\treturn Parse_ForStatement();\n\telse if ((current_token_type_ == EidosTokenType::kTokenNext) || (current_token_type_ == EidosTokenType::kTokenBreak) || (current_token_type_ == EidosTokenType::kTokenReturn))\n\t\treturn Parse_JumpStatement();\n\telse\n\t{\n\t\tif (parse_make_bad_nodes_)\n\t\t{\n\t\t\t// If we are doing a fault-tolerant parse, we need to guarantee that we don't get stuck in an infinite loop.\n\t\t\t// Various functions, such as Parse_InterpreterBlock() and Parse_CompoundStatement(), call this function\n\t\t\t// inside a loop and expect it to always advance the current token.  In the cases above, that is guaranteed;\n\t\t\t// the current token is some special token that will be matched.  In this case, however, it is not guaranteed;\n\t\t\t// a bad token like ',' will fail to be processed, we will get a bad node, and we will not advance.  In this\n\t\t\t// circumstance, we Consume() one token and return the bad token.  This method thus guarantees that it advances.\n\t\t\t\n\t\t\t// Note that all other loops in this parser loop conditional on the current token being of a particular type,\n\t\t\t// and then consume the current token because the loop knows that it matches.  All other loops besides the\n\t\t\t// loops that call Parse_Statement() are therefore guaranteed to terminate on bad input.  Many of the parsing\n\t\t\t// methods are not guaranteed to advance on bad input; many of them will end up generating a bad node and\n\t\t\t// not advancing.  That is OK – that is great – because somebody above them in the call stack *is* guaranteed\n\t\t\t// to advance, or at least to terminate, because of the above logic.  We may generate weird garbage, but we\n\t\t\t// will not hang, and for fault-tolerant parsing, that's about as much as you can reasonably expect.\n\t\t\tEidosToken *old_current_token = current_token_;\n\t\t\tEidosASTNode *expr_statement_node = Parse_ExprStatement();\n\t\t\t\n\t\t\tif (current_token_ == old_current_token)\n\t\t\t\tConsume();\n\t\t\t\n\t\t\treturn expr_statement_node;\n\t\t}\n\t\telse\n\t\t\treturn Parse_ExprStatement();\n\t}\n}\n\nEidosASTNode *EidosScript::Parse_ExprStatement(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif (current_token_type_ == EidosTokenType::kTokenSemicolon)\n\t\t{\n\t\t\t// an empty statement is represented by a semicolon token; note that EOF cannot\n\t\t\t// substitute for this semicolon even when final_semicolon_optional_ is true\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tConsume();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnode = Parse_AssignmentExpr();\n\t\t\t\n\t\t\t// match the terminating semicolon unless it is optional and we're at the EOF\n\t\t\tif (!final_semicolon_optional_ || (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t\t\tMatch(EidosTokenType::kTokenSemicolon, \"expression statement\");\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_SelectionStatement(void)\n{\n\tEidosASTNode *node = nullptr, *test_expr, *true_statement, *false_statement;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenIf, \"if statement\");\n\t\tMatch(EidosTokenType::kTokenLParen, \"if statement\");\n\t\t\n\t\ttest_expr = Parse_Expr();\n\t\tnode->AddChild(test_expr);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"if statement\");\n\t\t\n\t\ttrue_statement = Parse_Statement();\n\t\tnode->AddChild(true_statement);\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenElse)\n\t\t{\n\t\t\tConsume();\n\t\t\t\n\t\t\tfalse_statement = Parse_Statement();\n\t\t\tnode->AddChild(false_statement);\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_DoWhileStatement(void)\n{\n\tEidosASTNode *node = nullptr, *test_expr, *statement;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\n\t\tMatch(EidosTokenType::kTokenDo, \"do/while statement\");\n\t\t\n\t\tstatement = Parse_Statement();\n\t\tnode->AddChild(statement);\n\t\t\n\t\tMatch(EidosTokenType::kTokenWhile, \"do/while statement\");\n\t\tMatch(EidosTokenType::kTokenLParen, \"do/while statement\");\n\t\t\n\t\ttest_expr = Parse_Expr();\n\t\tnode->AddChild(test_expr);\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"do/while statement\");\n\t\t\n\t\t// match the terminating semicolon unless it is optional and we're at the EOF\n\t\tif (!final_semicolon_optional_ || (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t\tMatch(EidosTokenType::kTokenSemicolon, \"do/while statement\");\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_WhileStatement(void)\n{\n\tEidosASTNode *node = nullptr, *test_expr, *statement;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenWhile, \"while statement\");\n\t\tMatch(EidosTokenType::kTokenLParen, \"while statement\");\n\t\t\n\t\ttest_expr = Parse_Expr();\n\t\tnode->AddChild(test_expr);\n\t\t\n#if (SLIMPROFILING == 1)\n\t\t// PROFILING\n\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"while statement\");\n\t\t\n\t\tstatement = Parse_Statement();\n\t\tnode->AddChild(statement);\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_ForStatement(void)\n{\n\tEidosASTNode *node = nullptr, *identifier, *range_expr, *statement;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenFor, \"for statement\");\n\t\tMatch(EidosTokenType::kTokenLParen, \"for statement\");\n\t\t\n\t\t// in Eidos 3.2 (SLiM 4.2) we allow for loops with multiple \"in\" clause\n\t\t// each \"in\" clause becomes a pair of children: identifier and expression\n\t\tdo\n\t\t{\n\t\t\tidentifier = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tnode->AddChild(identifier);\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"for statement\");\n\t\t\tMatch(EidosTokenType::kTokenIn, \"for statement\");\n\t\t\t\n\t\t\trange_expr = Parse_Expr();\n\t\t\tnode->AddChild(range_expr);\n\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t// PROFILING\n\t\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\t\n\t\t\t// look for a comma, indicating another \"in\" clause\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\tMatch(EidosTokenType::kTokenComma, \"parameter list\");\n\t\t\telse\n\t\t\t\tbreak;\t\t// not a comma, so we're done\n\t\t}\n\t\twhile (true);\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"for statement\");\n\t\t\n\t\tstatement = Parse_Statement();\n\t\tnode->AddChild(statement);\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_JumpStatement(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif ((current_token_type_ == EidosTokenType::kTokenNext) || (current_token_type_ == EidosTokenType::kTokenBreak))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tConsume();\n\t\t\t\n\t\t\t// match the terminating semicolon unless it is optional and we're at the EOF\n\t\t\tif (!final_semicolon_optional_ || (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t\t\tMatch(EidosTokenType::kTokenSemicolon, \"next/break statement\");\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenReturn)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tConsume();\n\t\t\t\n\t\t\tif ((current_token_type_ == EidosTokenType::kTokenSemicolon) || (current_token_type_ == EidosTokenType::kTokenEOF))\n\t\t\t{\n\t\t\t\t// match the terminating semicolon unless it is optional and we're at the EOF\n\t\t\t\tif (!final_semicolon_optional_ || (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t\t\t\tMatch(EidosTokenType::kTokenSemicolon, \"return statement\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEidosASTNode *value_expr = Parse_Expr();\n\t\t\t\tnode->AddChild(value_expr);\n\t\t\t\t\n\t\t\t\t// match the terminating semicolon unless it is optional and we're at the EOF\n\t\t\t\tif (!final_semicolon_optional_ || (current_token_type_ != EidosTokenType::kTokenEOF))\n\t\t\t\t\tMatch(EidosTokenType::kTokenSemicolon, \"return statement\");\n\t\t\t}\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_Expr(void)\n{\n\treturn Parse_ConditionalExpr();\n}\n\nEidosASTNode *EidosScript::Parse_AssignmentExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_ConditionalExpr();\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenAssign)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_ConditionalExpr());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_ConditionalExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_LogicalOrExpr();\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenConditional)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_ConditionalExpr());\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenElse, \"ternary conditional expression\");\n\t\t\t\n\t\t\tnode->AddChild(Parse_ConditionalExpr());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_LogicalOrExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_LogicalAndExpr();\n\t\t\n\t\twhile (current_token_type_ == EidosTokenType::kTokenOr)\n\t\t{\n\t\t\tif (!node)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t}\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_LogicalAndExpr());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_LogicalAndExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_EqualityExpr();\n\t\t\n\t\twhile (current_token_type_ == EidosTokenType::kTokenAnd)\n\t\t{\n\t\t\tif (!node)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t}\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_EqualityExpr());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_EqualityExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_RelationalExpr();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenEq) || (current_token_type_ == EidosTokenType::kTokenNotEq))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_RelationalExpr());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_RelationalExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_AddExpr();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenLt) || (current_token_type_ == EidosTokenType::kTokenGt) || (current_token_type_ == EidosTokenType::kTokenLtEq) || (current_token_type_ == EidosTokenType::kTokenGtEq))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_AddExpr());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_AddExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_MultExpr();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenPlus) || (current_token_type_ == EidosTokenType::kTokenMinus))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_MultExpr());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_MultExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_SeqExpr();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenMult) || (current_token_type_ == EidosTokenType::kTokenDiv) || (current_token_type_ == EidosTokenType::kTokenMod))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_SeqExpr());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_SeqExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_UnaryExpExpr();\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenColon)\n\t\t{\n\t\t\tif (!node)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t}\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_UnaryExpExpr());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_UnaryExpExpr(void)\n{\n\t// this merge of unary_expr and exp_expr was suggested by https://stackoverflow.com/a/53615462/2752221\n\t// it fixes a precedence problem with ^ and unary -, where -2^2 should be -(2^2) == -4 but came out as (-2)^2 == 4\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif ((current_token_type_ == EidosTokenType::kTokenPlus) || (current_token_type_ == EidosTokenType::kTokenMinus) || (current_token_type_ == EidosTokenType::kTokenNot))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_UnaryExpExpr());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tleft_expr = Parse_PostfixExpr();\n\t\t\t\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenExp)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t\t\n\t\t\t\tConsume();\n\t\t\t\t\n\t\t\t\tnode->AddChild(Parse_UnaryExpExpr());\t\t// note right-associativity\n\t\t\t}\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_PostfixExpr(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_PrimaryExpr();\n\t\t\n\t\twhile (true)\n\t\t{\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenLBracket)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t\t\n\t\t\t\tConsume();\n\t\t\t\t\n\t\t\t\t// in Eidos 1.6 and later, we allow comma-separated sequences of subset expressions; we make dummy nodes for missing expressions\n\t\t\t\t// at the top of this loop, we are always expecting a subset expression, and need to make a dummy node if one is not present\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenRBracket)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosASTNode *missing_expr_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\tnode->AddChild(missing_expr_node);\t\t// add a node representing the skipped expression; we use the ']' token for it\n\t\t\t\t\t\t\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosASTNode *missing_expr_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\t\t\t\n\t\t\t\t\t\tnode->AddChild(missing_expr_node);\t\t// add a node representing the skipped expression; we use the ',' token for it\n\t\t\t\t\t\t\n\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"postfix subset expression\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnode->AddChild(Parse_Expr());\n\t\t\t\t\t\t\n\t\t\t\t\t\t// after a subset expression, we need to either finish the subset node, or get back to expecting an expression\n\t\t\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"postfix subset expression\");\n\t\t\t\t\t\telse if (current_token_type_ == EidosTokenType::kTokenRBracket)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// If we're not fault-tolerant, we have an error.  If we are, we have to break out, because\n\t\t\t\t\t\t\t// we can't assume that the Parse_Expr() call above ends up consuming any tokens at all\n\t\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_PostfixExpr): unexpected token '\" << *current_token_ << \"'.\" << EidosTerminate(current_token_);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twhile (current_token_type_ != EidosTokenType::kTokenEOF);\n\t\t\t\t\n\t\t\t\t// now we have reached our end bracket and can close up\n\t\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t\t// PROFILING\n\t\t\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\t\t\n\t\t\t\tMatch(EidosTokenType::kTokenRBracket, \"postfix subset expression\");\n\t\t\t\t\n\t\t\t\tleft_expr = node;\n\t\t\t\tnode = nullptr;\n\t\t\t}\n\t\t\telse if (current_token_type_ == EidosTokenType::kTokenLParen)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t\t\n\t\t\t\tConsume();\n\t\t\t\t\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenRParen)\n\t\t\t\t{\n#if (SLIMPROFILING == 1)\n\t\t\t\t\t// PROFILING\n\t\t\t\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tConsume();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tParse_ArgumentExprList(node);\t// Parse_ArgumentExprList() adds the arguments directly to the function call node\n\t\t\t\t\t\n#if (SLIMPROFILING == 1)\n\t\t\t\t\t// PROFILING\n\t\t\t\t\tnode->full_range_end_token_ = current_token_;\n#endif\n\t\t\t\t\t\n\t\t\t\t\tMatch(EidosTokenType::kTokenRParen, \"postfix function call expression\");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tleft_expr = node;\n\t\t\t\tnode = nullptr;\n\t\t\t}\n\t\t\telse if (current_token_type_ == EidosTokenType::kTokenDot)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t\t\n\t\t\t\tConsume();\n\t\t\t\t\n\t\t\t\tEidosASTNode *identifier = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\tnode->AddChild(identifier);\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"postfix member expression\");\n\t\t\t\t\n\t\t\t\tleft_expr = node;\n\t\t\t\tnode = nullptr;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_PrimaryExpr(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif ((current_token_type_ == EidosTokenType::kTokenNumber) || (current_token_type_ == EidosTokenType::kTokenString))\n\t\t{\n\t\t\tnode = Parse_Constant();\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenLParen)\n\t\t{\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode = Parse_Expr();\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenRParen, \"primary parenthesized expression\");\n\t\t\t\n\t\t\t// we mark nodes that were parenthesized with a flag; this is for the benefit of range expression\n\t\t\t// evaluation in SLiM, which needs to know this; see EvaluateScriptBlockTickRanges()\n\t\t\tnode->was_parenthesized_ = true;\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"primary identifier expression\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t{\n\t\t\t\t// Give a good error message if the user is using <function> as an identifier\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenFunction)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_PrimaryExpr): unexpected token '\" << *current_token_ << \"'.  Note that <function> is now an Eidos language keyword and can no longer be used as an identifier.  User-defined functions may only be declared at the top level, not inside blocks.  The parameter to doCall() is now named 'functionName', and the built-in function previously named 'function' is now named 'functionSignature'.\" << EidosTerminate(current_token_);\n\t\t\t\telse\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_PrimaryExpr): unexpected token '\" << *current_token_ << \"'.\" << EidosTerminate(current_token_);\n\t\t\t}\n\t\t\t\n\t\t\t// We're doing an error-tolerant parse, so we introduce a bad node here as a placeholder for a missing primary expression\n\t\t\t// BCH 5/29/2018: changing to use the position of current_token_, so the bad token has a known position here; this allows code completion\n\t\t\t// to suggest argument names inside functions and methods from an empty base.  See EidosTypeInterpreter::_ProcessArgumentListTypes().\n\t\t\t// BCH 4/6/2019: changing to take the full range of current_token here, so that completing off of a language keyword – really an identifier\n\t\t\t// that happens to match a language keyword – works properly in code completion.\n\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, current_token_->token_start_, current_token_->token_end_, current_token_->token_UTF16_start_, current_token_->token_UTF16_end_, current_token_->token_line_);\n\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\n\t\t\tnode = bad_node;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nvoid EidosScript::Parse_ArgumentExprList(EidosASTNode *p_parent_node)\n{\n\tp_parent_node->AddChild(Parse_ArgumentExpr());\n\t\n\twhile (current_token_type_ == EidosTokenType::kTokenComma)\n\t{\n\t\tConsume();\t// note that we no longer use EidosTokenType::kTokenComma in the AST to group call arguments\n\t\t\n\t\tp_parent_node->AddChild(Parse_ArgumentExpr());\n\t}\n}\n\nEidosASTNode *EidosScript::Parse_ArgumentExpr(void)\n{\n\tEidosASTNode *identifier = nullptr, *node = nullptr;\n\t\n\ttry {\n\t\t// Look ahead one token for the IDENTIFIER '=' pattern.  The token at parse_index_ + 1 will always be defined,\n\t\t// at least as an EOF; looking ahead two tokens would require a bounds check, but one token does not.\n\t\tif ((current_token_type_ == EidosTokenType::kTokenIdentifier) && (token_stream_.at(parse_index_ + 1).token_type_ == EidosTokenType::kTokenAssign))\n\t\t{\n\t\t\tidentifier = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"argument expression identifier\");\n\t\t\t\n\t\t\tif (current_token_type_ == EidosTokenType::kTokenAssign)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, identifier);\n\t\t\t\tidentifier = nullptr;\n\t\t\t\tConsume();\n\t\t\t\t\n\t\t\t\tnode->AddChild(Parse_ConditionalExpr());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn Parse_ConditionalExpr();\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (identifier)\n\t\t{\n\t\t\tidentifier->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(identifier));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : identifier);\n}\n\nEidosASTNode *EidosScript::Parse_Constant(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tMatch(EidosTokenType::kTokenNumber, \"number literal expression\");\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenString)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tMatch(EidosTokenType::kTokenString, \"string literal expression\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This case should actually never be hit, since Parse_Constant() is only called when we have already seen a number or string token\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_Constant): unexpected token '\" << *current_token_ << \"'.\" << EidosTerminate(current_token_);\n\t\t\t\n\t\t\t// We're doing an error-tolerant parse, so we introduce a bad node here as a placeholder for a missing constant\n\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\n\t\t\tnode = bad_node;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_FunctionDecl(void)\n{\n\tEidosASTNode *node = nullptr, *return_type, *identifier, *param_list, *body;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenFunction, \"function declaration\");\n\t\t\n\t\treturn_type = Parse_ReturnTypeSpec();\n\t\tnode->AddChild(return_type);\n\t\t\n\t\t// If we're doing a fault-tolerant parse and the next token is not an identifier, avoid putting garbage into the tree\n\t\tif (!parse_make_bad_nodes_ || (current_token_->token_type_ == EidosTokenType::kTokenIdentifier))\n\t\t{\n\t\t\tidentifier = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tnode->AddChild(identifier);\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"function declaration\");\n\t\t}\n\t\t\n\t\tparam_list = Parse_ParamList();\n\t\tnode->AddChild(param_list);\n\t\t\n\t\tbody = Parse_CompoundStatement();\n\t\tnode->AddChild(body);\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_ReturnTypeSpec()\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tMatch(EidosTokenType::kTokenLParen, \"return-type specifier\");\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenRParen)\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_ReturnTypeSpec): unexpected token '\" << *current_token_ << \"' in return-type specifier; perhaps 'void' is missing?  Note that function() has been renamed to functionSignature().\" << EidosTerminate(current_token_);\n\t\t\n\t\t// create a node for the type-specifier\n\t\tnode = Parse_TypeSpec();\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"return-type specifier\");\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_TypeSpec(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tnode->typespec_.type_mask = kEidosValueMaskNone;\n\t\tnode->typespec_.object_class = nullptr;\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\t// Note that as a matter of syntax, this method will parse \"void\" and type-specifiers containing \"v\" as pertaining\n\t\t\t// to the \"void\" type in Eidos.  If the caller does not allow void to be used in a specific context, that is a\n\t\t\t// matter of semantics; the caller should check and raise if void is used, in that case.\n\t\t\tconst std::string &type = current_token_->token_string_;\n\t\t\t\n\t\t\tif (type == \"void\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskVOID;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"NULL\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskNULL;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"logical\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskLogical;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"integer\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskInt;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"float\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskFloat;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"string\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskString;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse if (type == \"object\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskObject;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t\t\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenLt)\n\t\t\t\t\tParse_ObjectClassSpec(node);\n\t\t\t}\n\t\t\telse if (type == \"numeric\")\n\t\t\t{\n\t\t\t\tnode->typespec_.type_mask = kEidosValueMaskNumeric;\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Check for a type composed of (vNlifso)*\n\t\t\t\tbool seen_v = false, seen_N = false, seen_l = false, seen_i = false, seen_f = false, seen_s = false, seen_o = false;\n\t\t\t\tbool saw_double = false;\n\t\t\t\t\n\t\t\t\tfor (const char &c : type)\n\t\t\t\t{\n\t\t\t\t\tswitch (c)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'v':\tif (seen_v) saw_double = true; else seen_v = true; break;\n\t\t\t\t\t\tcase 'N':\tif (seen_N) saw_double = true; else seen_N = true; break;\n\t\t\t\t\t\tcase 'l':\tif (seen_l) saw_double = true; else seen_l = true; break;\n\t\t\t\t\t\tcase 'i':\tif (seen_i) saw_double = true; else seen_i = true; break;\n\t\t\t\t\t\tcase 'f':\tif (seen_f) saw_double = true; else seen_f = true; break;\n\t\t\t\t\t\tcase 's':\tif (seen_s) saw_double = true; else seen_s = true; break;\n\t\t\t\t\t\tcase 'o':\tif (seen_o) saw_double = true; else seen_o = true; break;\n\t\t\t\t\t\tdefault:\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_TypeSpec): illegal type-specifier '\" << type << \"' (illegal character '\" << c << \"').\" << EidosTerminate(current_token_);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif (saw_double)\n\t\t\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_TypeSpec): illegal type-specifier '\" << type << \"' (doubly specified type '\" << c << \"').\" << EidosTerminate(current_token_);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (seen_v)\t\tnode->typespec_.type_mask |= kEidosValueMaskVOID;\n\t\t\t\tif (seen_N)\t\tnode->typespec_.type_mask |= kEidosValueMaskNULL;\n\t\t\t\tif (seen_l)\t\tnode->typespec_.type_mask |= kEidosValueMaskLogical;\n\t\t\t\tif (seen_i)\t\tnode->typespec_.type_mask |= kEidosValueMaskInt;\n\t\t\t\tif (seen_f)\t\tnode->typespec_.type_mask |= kEidosValueMaskFloat;\n\t\t\t\tif (seen_s)\t\tnode->typespec_.type_mask |= kEidosValueMaskString;\n\t\t\t\tif (seen_o)\t\tnode->typespec_.type_mask |= kEidosValueMaskObject;\n\t\t\t\t\n\t\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"type specifier\");\n\t\t\t\t\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenLt)\n\t\t\t\t\tParse_ObjectClassSpec(node);\n\t\t\t}\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenPlus)\n\t\t{\n\t\t\t// We just return a + node in this case; note it is different from a normal + node!\n\t\t\tnode->typespec_.type_mask = kEidosValueMaskAnyBase;\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenPlus, \"type specifier\");\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenMult)\n\t\t{\n\t\t\t// We just return a * node in this case; note it is different from a normal * node!\n\t\t\tnode->typespec_.type_mask = kEidosValueMaskAny;\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenMult, \"type specifier\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_TypeSpec): unexpected token '\" << *current_token_ << \"' in type specifier; expected a type identifier, +, or *.\" << EidosTerminate(current_token_);\n\t\t}\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenSingleton)\n\t\t{\n\t\t\t// Check for some illegal cases, where (semantically) the type may not be declared as singleton\n\t\t\tif ((node->typespec_.type_mask == kEidosValueMaskVOID) ||\n\t\t\t\t(node->typespec_.type_mask == kEidosValueMaskNULL) ||\n\t\t\t\t(node->typespec_.type_mask == (kEidosValueMaskNULL | kEidosValueMaskVOID)))\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_TypeSpec): type-specifiers that consist only of void and/or NULL may not be declared to be singleton.\" << EidosTerminate(current_token_);\n\t\t\t\n\t\t\t// Mark the node as representing a singleton\n\t\t\tnode->typespec_.type_mask |= kEidosValueMaskSingleton;\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenSingleton, \"type specifier\");\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_ObjectClassSpec(EidosASTNode *p_type_node)\n{\n\ttry\n\t{\n\t\tMatch(EidosTokenType::kTokenLt, \"object-class specifier\");\n\t\t\n\t\tconst std::string &object_class = current_token_->token_string_;\n\t\t\n\t\tfor (EidosClass *eidos_class : EidosClass::RegisteredClasses(true, true))\n\t\t{\n\t\t\tif (eidos_class->ClassName() == object_class)\n\t\t\t{\n\t\t\t\tp_type_node->typespec_.object_class = eidos_class;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (!p_type_node->typespec_.object_class)\n\t\t{\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t{\n\t\t\t\t// A little concession to SLiM compatibility here; if you try to use a SLiM class name in pure Eidos, you get a more helpful error message\n\t\t\t\tif ((object_class == \"Chromosome\") || (object_class == \"Community\") || (object_class == \"Haplosome\") || (object_class == \"GenomicElement\") || (object_class == \"GenomicElementType\") || (object_class == \"Individual\") || (object_class == \"InteractionType\") || (object_class == \"LogFile\") || (object_class == \"Mutation\") || (object_class == \"MutationType\") || (object_class == \"Plot\") || (object_class == \"SLiMEidosBlock\") || (object_class == \"SLiMgui\") || (object_class == \"SpatialMap\") || (object_class == \"Species\") || (object_class == \"Subpopulation\") || (object_class == \"Substitution\"))\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_ObjectClassSpec): could not find an Eidos class named '\" << object_class << \"'.  Note that \" << object_class << \" is the name of a class in SLiM, but you are coding in pure Eidos; SLiM classes are not defined.\" << EidosTerminate(current_token_);\n\t\t\t\t\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_ObjectClassSpec): could not find an Eidos class named '\" << object_class << \"'.\" << EidosTerminate(current_token_);\n\t\t\t}\n\t\t}\n\t\t\n\t\tMatch(EidosTokenType::kTokenIdentifier, \"object-class specifier\");\n\t\tMatch(EidosTokenType::kTokenGt, \"object-class specifier\");\n\t}\n\tcatch (...)\n\t{\n\t\tthrow;\n\t}\n\t\n\treturn p_type_node;\n}\n\nEidosASTNode *EidosScript::Parse_ParamList(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tMatch(EidosTokenType::kTokenLParen, \"parameter list\");\n\t\t\n\t\t// Look ahead one token for the 'void' ')' pattern.  The token at parse_index_ + 1 will always be defined,\n\t\t// at least as an EOF; looking ahead two tokens would require a bounds check, but one token does not.\n\t\tif ((current_token_type_ == EidosTokenType::kTokenIdentifier) &&\n\t\t\t(current_token_->token_string_ == \"void\") &&\n\t\t\t(token_stream_.at(parse_index_ + 1).token_type_ == EidosTokenType::kTokenRParen))\n\t\t{\n\t\t\t// A void parameter list is represented by no children of the param-list node\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"parameter list\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, each child represents one param-spec\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tEidosASTNode *param_spec = Parse_ParamSpec();\n\t\t\t\t\n\t\t\t\tnode->AddChild(param_spec);\n\t\t\t\t\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenComma)\n\t\t\t\t{\n\t\t\t\t\tMatch(EidosTokenType::kTokenComma, \"parameter list\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tMatch(EidosTokenType::kTokenRParen, \"parameter list\");\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_ParamSpec(void)\n{\n\tEidosASTNode *node = nullptr, *type_node, *parameter_id, *default_value;\n\t\n\ttry\n\t{\n\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenLBracket)\n\t\t{\n\t\t\t// This is an optional argument of the form \"[ type-spec ID = default-value ]\"\n\t\t\t// It is stored as a node with three children: type-spec, ID, default-value\n\t\t\t// In this case the parent node is of type EidosTokenType::kTokenLBracket\n\t\t\tMatch(EidosTokenType::kTokenLBracket, \"parameter specifier\");\n\t\t\t\n\t\t\tEidosToken *type_specifier_token = current_token_;\n\t\t\t\n\t\t\ttype_node = Parse_TypeSpec();\n\t\t\t\n\t\t\tif (type_node->typespec_.type_mask & kEidosValueMaskVOID)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_ParamSpec): void is not allowed in parameter type-specifiers; function parameters may not accept void arguments.\" << EidosTerminate(type_specifier_token);\n\t\t\t\n\t\t\ttype_node->typespec_.type_mask |= kEidosValueMaskOptional;\n\t\t\tnode->AddChild(type_node);\n\t\t\t\n\t\t\tparameter_id = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tnode->AddChild(parameter_id);\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"parameter specifier\");\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenAssign, \"parameter specifier\");\n\t\t\t\n\t\t\tdefault_value = Parse_DefaultValue();\n\t\t\tnode->AddChild(default_value);\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenRBracket, \"parameter specifier\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a required argument of the form \"type-spec ID\"\n\t\t\t// It is stored as a node with two children: type-spec, ID\n\t\t\t// In this case the parent node is of type EidosTokenType::kTokenIdentifier\n\t\t\tEidosToken *type_specifier_token = current_token_;\n\t\t\t\n\t\t\ttype_node = Parse_TypeSpec();\n\t\t\t\n\t\t\tif (type_node->typespec_.type_mask & kEidosValueMaskVOID)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_ParamSpec): void is not allowed in parameter type-specifiers; function parameters may not accept void arguments.\" << EidosTerminate(type_specifier_token);\n\t\t\t\n\t\t\tnode->AddChild(type_node);\n\t\t\t\n\t\t\tparameter_id = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tnode->AddChild(parameter_id);\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"parameter specifier\");\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_DefaultValue(void)\n{\n\tEidosASTNode *node = nullptr;\n\t\n\ttry\n\t{\n\t\tif (current_token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tMatch(EidosTokenType::kTokenIdentifier, \"default value\");\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tMatch(EidosTokenType::kTokenNumber, \"default value\");\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenMinus)\n\t\t{\n\t\t\t// We allow a unary minus to precede a numeric constant; we make a minus node\n\t\t\t// with the numeric constant below it, and we cache its numeric value right\n\t\t\t// here since EidosASTNode::_OptimizeConstants() isn't smart enough to do it.\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tConsume();\n\t\t\t\n\t\t\t// attempt to figure out the numeric value; this can throw an EIDOS_TERMINATION\n\t\t\t// exception, and we might be doing an error-tolerant parse, so be careful\n\t\t\tEidosValue_SP negated_value;\n\t\t\t\n\t\t\tbool oldTerminateThrows = gEidosTerminateThrows;\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif (current_token_type_ == EidosTokenType::kTokenNumber)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP numeric_value = EidosInterpreter::NumericValueForString(current_token_->token_string_, current_token_);\t// can raise\n\t\t\t\t\t\n\t\t\t\t\tif (numeric_value->Type() == EidosValueType::kValueFloat)\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble float_value = numeric_value->FloatAtIndex_NOCAST(0, current_token_);\n\t\t\t\t\t\tnegated_value = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(-float_value));\n\t\t\t\t\t}\n\t\t\t\t\telse if (numeric_value->Type() == EidosValueType::kValueInt)\n\t\t\t\t\t{\n\t\t\t\t\t\tint64_t int_value = numeric_value->IntAtIndex_NOCAST(0, current_token_);\n\t\t\t\t\t\tnegated_value = EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(-int_value));\t// note that overflow is not possible\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_DefaultValue): (internal error) numeric token has unexpected Eidos type.\" << EidosTerminate(current_token_);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (...)\t\t// NOLINT(*-empty-catch) : intentional empty catch\n\t\t\t{\n\t\t\t\t// negated_value remains nullptr; no need to do anything else here\n\t\t\t}\n\t\t\t\n\t\t\tgEidosTerminateThrows = oldTerminateThrows;\n\t\t\t\n\t\t\tif (negated_value)\n\t\t\t{\n\t\t\t\tEidosASTNode *numeric_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\t\tMatch(EidosTokenType::kTokenNumber, \"default value\");\n\t\t\t\t\n\t\t\t\tnode->AddChild(numeric_node);\n\t\t\t\tnode->cached_literal_value_ = negated_value;\t// cache the negated value for fast default argument processing\n\t\t\t\tnode->cached_literal_value_->MarkAsConstant();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// unary minus preceded something other than a numeric constant; error\n\t\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_DefaultValue): unexpected token '\" << *current_token_ << \"'.\" << EidosTerminate(current_token_);\n\t\t\t\t\n\t\t\t\t// We're doing an error-tolerant parse, so we introduce a bad node here as a placeholder for a missing constant\n\t\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\t\n\t\t\t\tnode->AddChild(bad_node);\n\t\t\t}\n\t\t}\n\t\telse if (current_token_type_ == EidosTokenType::kTokenString)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_);\n\t\t\tMatch(EidosTokenType::kTokenString, \"default value\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// malformed default value\n\t\t\tif (!parse_make_bad_nodes_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosScript::Parse_DefaultValue): unexpected token '\" << *current_token_ << \"'.\" << EidosTerminate(current_token_);\n\t\t\t\n\t\t\t// We're doing an error-tolerant parse, so we introduce a bad node here as a placeholder for a missing constant\n\t\t\tEidosToken *bad_token = new EidosToken(EidosTokenType::kTokenBad, gEidosStr_empty_string, 0, 0, 0, 0, -1);\n\t\t\tEidosASTNode *bad_node = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(bad_token, true);\n\t\t\t\n\t\t\tnode = bad_node;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn node;\n}\n\nEidosASTNode *EidosScript::Parse_ConditionalExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_LogicalOrExpr_NOSEQ();\n\t\t\n\t\tif (current_token_type_ == EidosTokenType::kTokenConditional)\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_ConditionalExpr_NOSEQ());\t// arguably should be Parse_ConditionalExpr()\n\t\t\t\n\t\t\tMatch(EidosTokenType::kTokenElse, \"ternary conditional expression\");\n\t\t\t\n\t\t\tnode->AddChild(Parse_ConditionalExpr_NOSEQ());\t// arguably should be Parse_ConditionalExpr()\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_LogicalOrExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_LogicalAndExpr_NOSEQ();\n\t\t\n\t\twhile (current_token_type_ == EidosTokenType::kTokenOr)\n\t\t{\n\t\t\tif (!node)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t}\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_LogicalAndExpr_NOSEQ());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_LogicalAndExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_EqualityExpr_NOSEQ();\n\t\t\n\t\twhile (current_token_type_ == EidosTokenType::kTokenAnd)\n\t\t{\n\t\t\tif (!node)\n\t\t\t{\n\t\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\t\tleft_expr = nullptr;\n\t\t\t}\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_EqualityExpr_NOSEQ());\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_EqualityExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_RelationalExpr_NOSEQ();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenEq) || (current_token_type_ == EidosTokenType::kTokenNotEq))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_RelationalExpr_NOSEQ());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_RelationalExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_AddExpr_NOSEQ();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenLt) || (current_token_type_ == EidosTokenType::kTokenGt) || (current_token_type_ == EidosTokenType::kTokenLtEq) || (current_token_type_ == EidosTokenType::kTokenGtEq))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_AddExpr_NOSEQ());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_AddExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_MultExpr_NOSEQ();\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenPlus) || (current_token_type_ == EidosTokenType::kTokenMinus))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_MultExpr_NOSEQ());\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nEidosASTNode *EidosScript::Parse_MultExpr_NOSEQ(void)\n{\n\tEidosASTNode *left_expr = nullptr, *node = nullptr;\n\t\n\ttry\n\t{\n\t\tleft_expr = Parse_UnaryExpExpr();\t\t\t// instead of Parse_SeqExpr()\n\t\t\n\t\twhile ((current_token_type_ == EidosTokenType::kTokenMult) || (current_token_type_ == EidosTokenType::kTokenDiv) || (current_token_type_ == EidosTokenType::kTokenMod))\n\t\t{\n\t\t\tnode = new (gEidosASTNodePool->AllocateChunk()) EidosASTNode(current_token_, left_expr);\n\t\t\tleft_expr = nullptr;\n\t\t\t\n\t\t\tConsume();\n\t\t\t\n\t\t\tnode->AddChild(Parse_UnaryExpExpr());\t// instead of Parse_SeqExpr()\n\t\t\t\n\t\t\tleft_expr = node;\n\t\t\tnode = nullptr;\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tif (left_expr)\n\t\t{\n\t\t\tleft_expr->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(left_expr));\n\t\t}\n\t\t\n\t\tif (node)\n\t\t{\n\t\t\tnode->~EidosASTNode();\n\t\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(node));\n\t\t}\n\t\t\n\t\tthrow;\n\t}\n\t\n\treturn (node ? node : left_expr);\n}\n\nvoid EidosScript::ParseInterpreterBlockToAST(bool p_allow_functions, bool p_make_bad_nodes)\n{\n\t// destroy the parse root and return it to the pool; the tree must be allocated out of gEidosASTNodePool!\n\tif (parse_root_)\n\t{\n\t\tparse_root_->~EidosASTNode();\n\t\tgEidosASTNodePool->DisposeChunk(const_cast<EidosASTNode*>(parse_root_));\n\t\tparse_root_ = nullptr;\n\t}\n\t\n\t// set up parse state\n\tparse_index_ = 0;\n\tcurrent_token_ = &token_stream_.at(parse_index_);\t\t// should always have at least an EOF\n\tcurrent_token_type_ = current_token_->token_type_;\n\tparse_make_bad_nodes_ = p_make_bad_nodes;\n\t\n\t// set up error tracking for this script\n\tEidosScript *current_script_save = gEidosErrorContext.currentScript;\n\tgEidosErrorContext.currentScript = this;\n\t\n\t// parse a new AST from our start token\n\tparse_root_ = Parse_InterpreterBlock(p_allow_functions);\n\t\n\tparse_root_->OptimizeTree();\n\t\n\t// if logging of the AST is requested, do that\n\tif (gEidosLogAST)\n\t{\n\t\tstd::cout << \"AST : \\n\";\n\t\tthis->PrintAST(std::cout);\n\t}\n\t\n\t// restore error tracking\n\tgEidosErrorContext.currentScript = current_script_save;\n\tparse_make_bad_nodes_ = false;\n}\n\nvoid EidosScript::PrintTokens(std::ostream &p_outstream) const\n{\n\tif (token_stream_.size())\n\t{\n\t\tfor (auto &token : token_stream_)\n\t\t\tp_outstream << token << \" \";\n\t\t\n\t\tp_outstream << std::endl;\n\t}\n}\n\nvoid EidosScript::PrintAST(std::ostream &p_outstream) const\n{\n\tif (parse_root_)\n\t{\n\t\tparse_root_->PrintTreeWithIndent(p_outstream, 0);\n\t\t\n\t\tp_outstream << std::endl;\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_script.h",
    "content": "//\n//  eidos_script.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/1/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosScript represents a script written in the Eidos language.  It handles its tokenizing and parsing itself.\n \n */\n\n#ifndef __Eidos__eidos_script__\n#define __Eidos__eidos_script__\n\n#include <vector>\n#include <string>\n\n#include \"eidos_token.h\"\n\n\nclass EidosValue;\nclass EidosASTNode;\n\n\n// set these to true to get logging of tokens / AST / evaluation\nextern bool gEidosLogTokens;\nextern bool gEidosLogAST;\nextern bool gEidosLogEvaluation;\n\n\n// A class representing an entire script and all associated tokenization and parsing baggage\nclass EidosScript\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprotected:\n\t\n\tconst std::string script_string_;\t\t// the full string for the script, from start-brace to the end of the end-brace line\n\t\n\t// These variables orient this script object within the user-level script; if this script is not derived from\n\t// the user's script, these variables will have the default values given here.  See the constructors below.\n\tEidosScript *user_script_ = nullptr;\t// NOT OWNED: a pointer to the user script that this script is derived from\n\tint32_t user_script_line_offset_ = -1;\t// the initial position (lines) in the user's script\n\tint32_t user_script_offset_ = -1;\t\t// the initial position (chars) in the user's script\n\tint32_t user_script_offset_UTF16_ = -1;\t// the initial position (UTF-16) in the user's script\n\t\n\tstd::vector<EidosToken> token_stream_;\n\tEidosASTNode *parse_root_ = nullptr;\t\t\t\t\t\t// OWNED POINTER\n\t\n\tbool final_semicolon_optional_ = false;\n\t\n\t// parsing ivars, valid only during parsing\n\tint parse_index_;\t\t\t\t\t\t// index into token_stream_ of the current token\n\tEidosToken *current_token_;\t\t\t\t// token_stream_[parse_index_]; owned indirectly\n\tEidosTokenType current_token_type_;\t\t// token_stream_[parse_index_]->token_type_\n\tbool parse_make_bad_nodes_ = false;\t\t// if true, do error-tolerant parsing and introduce dummy nodes as needed\n\t\npublic:\n\t\n\tEidosScript(const EidosScript&) = delete;\t\t\t\t\t\t\t\t// no copying\n\tEidosScript& operator=(const EidosScript&) = delete;\t\t\t\t\t// no copying\n\tEidosScript(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t// no null construction\n\t\n\t// This constructor is for a script that is unmoored from the user script, like a lambda.  There is no way\n\t// to correlate error positions in it back to the user script, no way to set debug points in it, etc.\n\texplicit EidosScript(std::string p_script_string);\n\t\n\t// This constructor locates the script within in the context of the user's script, allowing things like debug\n\t// points and error tracking to be correlated between this derived script and the original user script.  For\n\t// the user script itself, the user script pointer should be nullptr and the offsets should be zero; the fact\n\t// that they are not -1 implies that they are valid offsets, and the fact the user script pointer is nullptr\n\t// says \"I *am* the user script\".\n\tEidosScript(std::string p_script_string, EidosScript *p_user_script, int32_t p_user_script_line_offset, int32_t p_user_script_char_offset, int32_t p_user_script_UTF16_offset);\n\t\n\tvirtual ~EidosScript(void);\n\t\n\tvoid SetFinalSemicolonOptional(bool p_optional_semicolon)\t\t{ final_semicolon_optional_ = p_optional_semicolon; }\n\t\n\tinline EidosScript *UserScript(void) const { return user_script_; }\n\tinline int32_t UserScriptLineOffset(void) const { return user_script_line_offset_; }\n\tinline int32_t UserScriptCharOffset(void) const { return user_script_offset_; }\n\tinline int32_t UserScriptUTF16Offset(void) const { return user_script_offset_UTF16_; }\n\t\n\t// generate token stream from script string; if p_make_bad_tokens == true this function will not raise or fail\n\tvoid Tokenize(bool p_make_bad_tokens = false, bool p_keep_nonsignificant = false);\n\t\n\t// generate AST from token stream for an interpreter block ( statement* EOF )\n\tvoid ParseInterpreterBlockToAST(bool p_allow_functions, bool p_make_bad_nodes = false);\n\t\n\tvoid PrintTokens(std::ostream &p_outstream) const;\n\tvoid PrintAST(std::ostream &p_outstream) const;\n\t\n\tinline __attribute__((always_inline)) const std::string &String(void) const\t\t\t\t\t{ return script_string_; }\n\tinline __attribute__((always_inline)) const std::vector<EidosToken> &Tokens(void) const\t\t{ return token_stream_; }\n\tinline __attribute__((always_inline)) const EidosASTNode *AST(void) const\t\t\t\t\t{ return parse_root_; }\n\t\n\t// Parsing methods; see grammar for definitions\n\tvoid Consume(void);\n\tvoid Match(EidosTokenType p_token_type, const char *p_context_cstr);\n\t\n\t// Top-level parse method for the Eidos interpreter and other contexts\n\tEidosASTNode *Parse_InterpreterBlock(bool p_allow_functions);\n\t\n\t// Lower-level parsing\n\tEidosASTNode *Parse_CompoundStatement(void);\n\tEidosASTNode *Parse_Statement(void);\n\tEidosASTNode *Parse_ExprStatement(void);\n\tEidosASTNode *Parse_SelectionStatement(void);\n\tEidosASTNode *Parse_DoWhileStatement(void);\n\tEidosASTNode *Parse_WhileStatement(void);\n\tEidosASTNode *Parse_ForStatement(void);\n\tEidosASTNode *Parse_JumpStatement(void);\n\tEidosASTNode *Parse_Expr(void);\n\tEidosASTNode *Parse_AssignmentExpr(void);\n\tEidosASTNode *Parse_ConditionalExpr(void);\n\tEidosASTNode *Parse_LogicalOrExpr(void);\n\tEidosASTNode *Parse_LogicalAndExpr(void);\n\tEidosASTNode *Parse_EqualityExpr(void);\n\tEidosASTNode *Parse_RelationalExpr(void);\n\tEidosASTNode *Parse_AddExpr(void);\n\tEidosASTNode *Parse_MultExpr(void);\n\tEidosASTNode *Parse_SeqExpr(void);\n\tEidosASTNode *Parse_UnaryExpExpr(void);\n\tEidosASTNode *Parse_PostfixExpr(void);\n\tEidosASTNode *Parse_PrimaryExpr(void);\n\tvoid Parse_ArgumentExprList(EidosASTNode *p_parent_node);\t// adds to the parent node\n\tEidosASTNode *Parse_ArgumentExpr(void);\n\tEidosASTNode *Parse_Constant(void);\n\t\n\tEidosASTNode *Parse_FunctionDecl(void);\n\tEidosASTNode *Parse_ReturnTypeSpec();\n\tEidosASTNode *Parse_TypeSpec(void);\n\tEidosASTNode *Parse_ObjectClassSpec(EidosASTNode *p_type_node);\t// adds to type node\n\tEidosASTNode *Parse_ParamList(void);\n\tEidosASTNode *Parse_ParamSpec(void);\n\tEidosASTNode *Parse_DefaultValue(void);\n\t\n\t// These alternative parsing methods are provided for use by SLiM.  They represent\n\t// an expression syntax that does not include the sequence operator at the top level;\n\t// so \"sum(1:10)\" is legal, but \"1:10\" stops at \"1\" and leaves the colon.  This is\n\t// used for parsing tick range expressions, such as \"1:10 early()\"; that should\n\t// not produce the sequence 1:10 (since 1: and :10 are also legal), but rather just\n\t// \"1\", \":\", and \"10\".  See SLiMEidosScript::Parse_SLiMEidosBlock().\n\tEidosASTNode *Parse_ConditionalExpr_NOSEQ(void);\n\tEidosASTNode *Parse_LogicalOrExpr_NOSEQ(void);\n\tEidosASTNode *Parse_LogicalAndExpr_NOSEQ(void);\n\tEidosASTNode *Parse_EqualityExpr_NOSEQ(void);\n\tEidosASTNode *Parse_RelationalExpr_NOSEQ(void);\n\tEidosASTNode *Parse_AddExpr_NOSEQ(void);\n\tEidosASTNode *Parse_MultExpr_NOSEQ(void);\n};\n\n\n#endif /* defined(__Eidos__eidos_script__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_simd.h",
    "content": "//\n//  eidos_simd.h\n//  Eidos\n//\n//  Created by Andrew Kern on 11/26/2025.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n\n SIMD acceleration for Eidos math operations, independent of OpenMP.\n\n This header provides vectorized implementations of common math operations\n using platform-specific SIMD intrinsics when available:\n   - x86_64: SSE4.2 or AVX2 via <immintrin.h>\n   - ARM64: NEON via <arm_neon.h>\n Falls back to scalar code when no SIMD is available.\n\n */\n\n#ifndef eidos_simd_h\n#define eidos_simd_h\n\n#include <cstdint>\n#include <cmath>\n\n// Determine SIMD capability level\n#if defined(EIDOS_HAS_AVX2)\n    #include <immintrin.h>\n    #define EIDOS_SIMD_WIDTH 4          // 4 doubles per AVX register\n    #define EIDOS_SIMD_FLOAT_WIDTH 8    // 8 floats per AVX register\n#elif defined(EIDOS_HAS_SSE42)\n    #include <emmintrin.h>\n    #include <smmintrin.h>\n    #define EIDOS_SIMD_WIDTH 2          // 2 doubles per SSE register\n    #define EIDOS_SIMD_FLOAT_WIDTH 4    // 4 floats per SSE register\n#elif defined(EIDOS_HAS_NEON)\n    #include <arm_neon.h>\n    #define EIDOS_SIMD_WIDTH 2          // 2 doubles per NEON register\n    #define EIDOS_SIMD_FLOAT_WIDTH 4    // 4 floats per NEON register\n#else\n    #define EIDOS_SIMD_WIDTH 1          // Scalar fallback\n    #define EIDOS_SIMD_FLOAT_WIDTH 1\n#endif\n\n// Include SLEEF for vectorized transcendental functions (exp, log, log10, log2)\n// SLEEF is only used when AVX2+FMA or NEON is available\n// BCH 12/31/2025: SLEEF generates tons of shadowed variable warnings for some reason; disable them\n#if defined(EIDOS_HAS_AVX2) || defined(EIDOS_HAS_NEON)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wshadow\"\n#pragma GCC diagnostic ignored \"-Wdouble-promotion\"\n#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n#pragma GCC diagnostic ignored \"-Wunused-function\"\n#pragma GCC diagnostic ignored \"-Wimplicit-float-conversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wshadow\"\n#pragma clang diagnostic ignored \"-Wdouble-promotion\"\n#pragma clang diagnostic ignored \"-Wunused-parameter\"\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#pragma clang diagnostic ignored \"-Wimplicit-float-conversion\"\n#include \"sleef/sleef_config.h\"\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n#endif\n\n// Disable certain warnings for the remainder of this file\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Waggressive-loop-optimizations\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Waggressive-loop-optimizations\"\n\n\n// ================================\n// SIMD Vector Math Operations\n// ================================\n// These functions apply an operation to arrays of doubles.\n// They handle the loop, SIMD processing, and scalar remainder.\n\nnamespace Eidos_SIMD {\n\n// ---------------------\n// Square Root: sqrt(x)\n// ---------------------\ninline void sqrt_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    // Process 4 doubles at a time\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_sqrt_pd(v);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    // Process 2 doubles at a time\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_sqrt_pd(v);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    // Process 2 doubles at a time\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vsqrtq_f64(v);\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::sqrt(input[i]);\n}\n\n// ---------------------\n// Absolute Value: abs(x)\n// ---------------------\ninline void abs_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    // Create sign mask (all bits except sign bit)\n    __m256d sign_mask = _mm256_set1_pd(-0.0);\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_andnot_pd(sign_mask, v);  // Clear sign bit\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    __m128d sign_mask = _mm_set1_pd(-0.0);\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_andnot_pd(sign_mask, v);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vabsq_f64(v);\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    for (; i < count; i++)\n        output[i] = std::fabs(input[i]);\n}\n\n// ---------------------\n// Floor: floor(x)\n// ---------------------\ninline void floor_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_floor_pd(v);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_floor_pd(v);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vrndmq_f64(v);  // Round toward minus infinity (floor)\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    for (; i < count; i++)\n        output[i] = std::floor(input[i]);\n}\n\n// ---------------------\n// Ceil: ceil(x)\n// ---------------------\ninline void ceil_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_ceil_pd(v);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_ceil_pd(v);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vrndpq_f64(v);  // Round toward plus infinity (ceil)\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    for (; i < count; i++)\n        output[i] = std::ceil(input[i]);\n}\n\n// ---------------------\n// Truncate: trunc(x)\n// ---------------------\ninline void trunc_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_round_pd(v, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_round_pd(v, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vrndq_f64(v);  // Round toward zero (truncate)\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    for (; i < count; i++)\n        output[i] = std::trunc(input[i]);\n}\n\n// ---------------------\n// Round: round(x)\n// ---------------------\ninline void round_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        __m256d r = _mm256_round_pd(v, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_SSE42)\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        __m128d r = _mm_round_pd(v, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);\n        _mm_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        float64x2_t r = vrndaq_f64(v);  // Round to nearest, ties away from zero\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    for (; i < count; i++)\n        output[i] = std::round(input[i]);\n}\n\n// ---------------------\n// Exponential: exp(x)\n// ---------------------\ninline void exp_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_EXP_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::exp(input[i]);\n}\n\n// ---------------------\n// Natural Log: log(x)\n// ---------------------\ninline void log_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_LOG_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::log(input[i]);\n}\n\n// ---------------------\n// Log base 10: log10(x)\n// ---------------------\ninline void log10_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_LOG10_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::log10(input[i]);\n}\n\n// ---------------------\n// Log base 2: log2(x)\n// ---------------------\ninline void log2_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_LOG2_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::log2(input[i]);\n}\n\n// ---------------------\n// Sine: sin(x)\n// ---------------------\ninline void sin_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_SIN_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::sin(input[i]);\n}\n\n// ---------------------\n// Cosine: cos(x)\n// ---------------------\ninline void cos_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_COS_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::cos(input[i]);\n}\n\n// ---------------------\n// Tangent: tan(x)\n// ---------------------\ninline void tan_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_TAN_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::tan(input[i]);\n}\n\n// ---------------------\n// Arc Sine: asin(x)\n// ---------------------\ninline void asin_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_ASIN_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::asin(input[i]);\n}\n\n// ---------------------\n// Arc Cosine: acos(x)\n// ---------------------\ninline void acos_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_ACOS_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::acos(input[i]);\n}\n\n// ---------------------\n// Arc Tangent: atan(x)\n// ---------------------\ninline void atan_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_ATAN_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::atan(input[i]);\n}\n\n// ---------------------\n// Arc Tangent 2: atan2(y, x)\n// ---------------------\ninline void atan2_float64(const double *y, const double *x, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D vy = EIDOS_SLEEF_LOAD_D(&y[i]);\n        EIDOS_SLEEF_TYPE_D vx = EIDOS_SLEEF_LOAD_D(&x[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_ATAN2_D(vy, vx);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::atan2(y[i], x[i]);\n}\n\n// ---------------------\n// Power: pow(x, y) = x^y\n// ---------------------\ninline void pow_float64(const double *base, const double *exp, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D vb = EIDOS_SLEEF_LOAD_D(&base[i]);\n        EIDOS_SLEEF_TYPE_D ve = EIDOS_SLEEF_LOAD_D(&exp[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_POW_D(vb, ve);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::pow(base[i], exp[i]);\n}\n\n// Broadcast version: all elements raised to same power (base_array ^ scalar_exp)\ninline void pow_float64_scalar_exp(const double *base, double exp_scalar, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    __m256d ve_broadcast = _mm256_set1_pd(exp_scalar);\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d vb = _mm256_loadu_pd(&base[i]);\n        __m256d r = Sleef_powd4_u10avx2(vb, ve_broadcast);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t ve_broadcast = vdupq_n_f64(exp_scalar);\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t vb = vld1q_f64(&base[i]);\n        float64x2_t r = Sleef_powd2_u10advsimd(vb, ve_broadcast);\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::pow(base[i], exp_scalar);\n}\n\n// Broadcast version: scalar base raised to array of powers (scalar_base ^ exp_array)\ninline void pow_float64_scalar_base(double base_scalar, const double *exp, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    __m256d vb_broadcast = _mm256_set1_pd(base_scalar);\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d ve = _mm256_loadu_pd(&exp[i]);\n        __m256d r = Sleef_powd4_u10avx2(vb_broadcast, ve);\n        _mm256_storeu_pd(&output[i], r);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t vb_broadcast = vdupq_n_f64(base_scalar);\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t ve = vld1q_f64(&exp[i]);\n        float64x2_t r = Sleef_powd2_u10advsimd(vb_broadcast, ve);\n        vst1q_f64(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::pow(base_scalar, exp[i]);\n}\n\n// ================================\n// Reductions\n// ================================\n\n// ---------------------\n// Sum: sum(x)\n// ---------------------\ninline double sum_float64(const double *input, int64_t count)\n{\n    double sum = 0.0;\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    __m256d vsum = _mm256_setzero_pd();\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        vsum = _mm256_add_pd(vsum, v);\n    }\n    // Horizontal sum of 4 doubles\n    __m128d vlow  = _mm256_castpd256_pd128(vsum);\n    __m128d vhigh = _mm256_extractf128_pd(vsum, 1);\n    vlow  = _mm_add_pd(vlow, vhigh);     // 2 doubles\n    __m128d shuf = _mm_shuffle_pd(vlow, vlow, 1);\n    vlow = _mm_add_sd(vlow, shuf);       // 1 double\n    sum = _mm_cvtsd_f64(vlow);\n#elif defined(EIDOS_HAS_SSE42)\n    __m128d vsum = _mm_setzero_pd();\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        vsum = _mm_add_pd(vsum, v);\n    }\n    // Horizontal sum of 2 doubles\n    __m128d shuf = _mm_shuffle_pd(vsum, vsum, 1);\n    vsum = _mm_add_sd(vsum, shuf);\n    sum = _mm_cvtsd_f64(vsum);\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t vsum = vdupq_n_f64(0.0);\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        vsum = vaddq_f64(vsum, v);\n    }\n    // Horizontal sum of 2 doubles\n    sum = vaddvq_f64(vsum);\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        sum += input[i];\n\n    return sum;\n}\n\n// ---------------------\n// Product: product(x)\n// ---------------------\ninline double product_float64(const double *input, int64_t count)\n{\n    double prod = 1.0;\n    int64_t i = 0;\n\n#if defined(EIDOS_HAS_AVX2)\n    __m256d vprod = _mm256_set1_pd(1.0);\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v = _mm256_loadu_pd(&input[i]);\n        vprod = _mm256_mul_pd(vprod, v);\n    }\n    // Horizontal product of 4 doubles\n    __m128d vlow  = _mm256_castpd256_pd128(vprod);\n    __m128d vhigh = _mm256_extractf128_pd(vprod, 1);\n    vlow  = _mm_mul_pd(vlow, vhigh);\n    __m128d shuf = _mm_shuffle_pd(vlow, vlow, 1);\n    vlow = _mm_mul_sd(vlow, shuf);\n    prod = _mm_cvtsd_f64(vlow);\n#elif defined(EIDOS_HAS_SSE42)\n    __m128d vprod = _mm_set1_pd(1.0);\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v = _mm_loadu_pd(&input[i]);\n        vprod = _mm_mul_pd(vprod, v);\n    }\n    __m128d shuf = _mm_shuffle_pd(vprod, vprod, 1);\n    vprod = _mm_mul_sd(vprod, shuf);\n    prod = _mm_cvtsd_f64(vprod);\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t vprod = vdupq_n_f64(1.0);\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v = vld1q_f64(&input[i]);\n        vprod = vmulq_f64(vprod, v);\n    }\n    // Horizontal product of 2 doubles\n    prod = vgetq_lane_f64(vprod, 0) * vgetq_lane_f64(vprod, 1);\n#endif\n\n    for (; i < count; i++)\n        prod *= input[i];\n\n    return prod;\n}\n\n// ================================\n// Float (Single-Precision) SIMD Operations\n// ================================\n// These functions operate on arrays of floats, used by spatial interaction kernels.\n\n// ---------------------\n// Exponential: exp(x) for floats\n// ---------------------\ninline void exp_float32(const float *input, float *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_FLOAT_AVAILABLE\n    for (; i + EIDOS_SLEEF_VEC_SIZE_F <= count; i += EIDOS_SLEEF_VEC_SIZE_F)\n    {\n        EIDOS_SLEEF_TYPE_F v = EIDOS_SLEEF_LOAD_F(&input[i]);\n        EIDOS_SLEEF_TYPE_F r = EIDOS_SLEEF_EXP_F(v);\n        EIDOS_SLEEF_STORE_F(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        output[i] = std::exp(input[i]);\n}\n\n// ---------------------\n// Exponential Kernel: strength = fmax * exp(-lambda * distance)\n// ---------------------\n// Operates in-place on a distance array, transforming distances to strengths.\n// This is optimized for the spatial interaction kernel calculation.\ninline void exp_kernel_float32(float *distances, int64_t count, float fmax, float lambda)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_FLOAT_AVAILABLE\n    // We need to compute: fmax * exp(-lambda * distance)\n    // First, compute -lambda * distance for all values, then exp, then multiply by fmax\n    EIDOS_SLEEF_TYPE_F v_fmax =\n#if defined(EIDOS_HAS_AVX2)\n        _mm256_set1_ps(fmax);\n    EIDOS_SLEEF_TYPE_F v_neg_lambda = _mm256_set1_ps(-lambda);\n#elif defined(EIDOS_HAS_NEON)\n        vdupq_n_f32(fmax);\n    EIDOS_SLEEF_TYPE_F v_neg_lambda = vdupq_n_f32(-lambda);\n#endif\n\n    for (; i + EIDOS_SLEEF_VEC_SIZE_F <= count; i += EIDOS_SLEEF_VEC_SIZE_F)\n    {\n        EIDOS_SLEEF_TYPE_F v_dist = EIDOS_SLEEF_LOAD_F(&distances[i]);\n\n        // Compute -lambda * distance\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_arg = _mm256_mul_ps(v_neg_lambda, v_dist);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_arg = vmulq_f32(v_neg_lambda, v_dist);\n#endif\n\n        // Compute exp(-lambda * distance)\n        EIDOS_SLEEF_TYPE_F v_exp = EIDOS_SLEEF_EXP_F(v_arg);\n\n        // Compute fmax * exp(...)\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_result = _mm256_mul_ps(v_fmax, v_exp);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_result = vmulq_f32(v_fmax, v_exp);\n#endif\n\n        EIDOS_SLEEF_STORE_F(&distances[i], v_result);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n        distances[i] = fmax * std::exp(-lambda * distances[i]);\n}\n\n// ---------------------\n// Normal (Gaussian) Kernel: strength = fmax * exp(-distance^2 / 2sigma^2)\n// ---------------------\n// Operates in-place on a distance array, transforming distances to strengths.\n// The two_sigma_sq parameter is pre-computed as 2 * sigma^2 for efficiency.\ninline void normal_kernel_float32(float *distances, int64_t count, float fmax, float two_sigma_sq)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_FLOAT_AVAILABLE\n    // We need to compute: fmax * exp(-distance^2 / two_sigma_sq)\n    EIDOS_SLEEF_TYPE_F v_fmax =\n#if defined(EIDOS_HAS_AVX2)\n        _mm256_set1_ps(fmax);\n    EIDOS_SLEEF_TYPE_F v_neg_inv_2sigsq = _mm256_set1_ps(-1.0f / two_sigma_sq);\n#elif defined(EIDOS_HAS_NEON)\n        vdupq_n_f32(fmax);\n    EIDOS_SLEEF_TYPE_F v_neg_inv_2sigsq = vdupq_n_f32(-1.0f / two_sigma_sq);\n#endif\n\n    for (; i + EIDOS_SLEEF_VEC_SIZE_F <= count; i += EIDOS_SLEEF_VEC_SIZE_F)\n    {\n        EIDOS_SLEEF_TYPE_F v_dist = EIDOS_SLEEF_LOAD_F(&distances[i]);\n\n        // Compute distance^2\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_dist_sq = _mm256_mul_ps(v_dist, v_dist);\n        // Compute -distance^2 / 2sigma^2\n        EIDOS_SLEEF_TYPE_F v_arg = _mm256_mul_ps(v_dist_sq, v_neg_inv_2sigsq);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_dist_sq = vmulq_f32(v_dist, v_dist);\n        // Compute -distance^2 / 2sigma^2\n        EIDOS_SLEEF_TYPE_F v_arg = vmulq_f32(v_dist_sq, v_neg_inv_2sigsq);\n#endif\n\n        // Compute exp(-distance^2 / 2sigma^2)\n        EIDOS_SLEEF_TYPE_F v_exp = EIDOS_SLEEF_EXP_F(v_arg);\n\n        // Compute fmax * exp(...)\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_result = _mm256_mul_ps(v_fmax, v_exp);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_result = vmulq_f32(v_fmax, v_exp);\n#endif\n\n        EIDOS_SLEEF_STORE_F(&distances[i], v_result);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n    {\n        float d = distances[i];\n        distances[i] = fmax * std::exp(-(d * d) / two_sigma_sq);\n    }\n}\n\n// ---------------------\n// Student's T Kernel: strength = fmax / pow(1 + (d/tau)^2 / nu, (nu+1)/2)\n// ---------------------\n// Operates in-place on a distance array, transforming distances to strengths.\n// Parameters: fmax = maximum strength, nu = degrees of freedom, tau = scale\ninline void tdist_kernel_float32(float *distances, int64_t count, float fmax, float nu, float tau)\n{\n    int64_t i = 0;\n\n    // Pre-compute constants\n    float inv_tau = 1.0f / tau;\n    float inv_nu = 1.0f / nu;\n    float exponent = (nu + 1.0f) / 2.0f;\n\n#if EIDOS_SLEEF_FLOAT_AVAILABLE\n    EIDOS_SLEEF_TYPE_F v_fmax, v_inv_tau, v_inv_nu, v_exponent, v_one;\n#if defined(EIDOS_HAS_AVX2)\n    v_fmax = _mm256_set1_ps(fmax);\n    v_inv_tau = _mm256_set1_ps(inv_tau);\n    v_inv_nu = _mm256_set1_ps(inv_nu);\n    v_exponent = _mm256_set1_ps(-exponent);\n    v_one = _mm256_set1_ps(1.0f);\n#elif defined(EIDOS_HAS_NEON)\n    v_fmax = vdupq_n_f32(fmax);\n    v_inv_tau = vdupq_n_f32(inv_tau);\n    v_inv_nu = vdupq_n_f32(inv_nu);\n    v_exponent = vdupq_n_f32(-exponent);\n    v_one = vdupq_n_f32(1.0f);\n#endif\n\n    for (; i + EIDOS_SLEEF_VEC_SIZE_F <= count; i += EIDOS_SLEEF_VEC_SIZE_F)\n    {\n        EIDOS_SLEEF_TYPE_F v_dist = EIDOS_SLEEF_LOAD_F(&distances[i]);\n\n        // Compute (d / tau)\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_d_over_tau = _mm256_mul_ps(v_dist, v_inv_tau);\n        // Compute (d/tau)^2\n        EIDOS_SLEEF_TYPE_F v_d_over_tau_sq = _mm256_mul_ps(v_d_over_tau, v_d_over_tau);\n        // Compute (d/tau)^2 / nu\n        EIDOS_SLEEF_TYPE_F v_term = _mm256_mul_ps(v_d_over_tau_sq, v_inv_nu);\n        // Compute 1 + (d/tau)^2 / nu\n        EIDOS_SLEEF_TYPE_F v_base = _mm256_add_ps(v_one, v_term);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_d_over_tau = vmulq_f32(v_dist, v_inv_tau);\n        EIDOS_SLEEF_TYPE_F v_d_over_tau_sq = vmulq_f32(v_d_over_tau, v_d_over_tau);\n        EIDOS_SLEEF_TYPE_F v_term = vmulq_f32(v_d_over_tau_sq, v_inv_nu);\n        EIDOS_SLEEF_TYPE_F v_base = vaddq_f32(v_one, v_term);\n#endif\n\n        // Compute pow(base, -exponent) = 1 / pow(base, exponent)\n        EIDOS_SLEEF_TYPE_F v_pow = EIDOS_SLEEF_POW_F(v_base, v_exponent);\n\n        // Compute fmax * pow(...)\n#if defined(EIDOS_HAS_AVX2)\n        EIDOS_SLEEF_TYPE_F v_result = _mm256_mul_ps(v_fmax, v_pow);\n#elif defined(EIDOS_HAS_NEON)\n        EIDOS_SLEEF_TYPE_F v_result = vmulq_f32(v_fmax, v_pow);\n#endif\n\n        EIDOS_SLEEF_STORE_F(&distances[i], v_result);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n    {\n        float d = distances[i];\n        float d_over_tau = d * inv_tau;\n        distances[i] = fmax * std::pow(1.0f + d_over_tau * d_over_tau * inv_nu, -exponent);\n    }\n}\n\n// ---------------------\n// Cauchy Kernel: strength = fmax / (1 + (d/lambda)^2)\n// ---------------------\n// Operates in-place on a distance array, transforming distances to strengths.\n// Parameters: fmax = maximum strength, lambda = scale parameter\ninline void cauchy_kernel_float32(float *distances, int64_t count, float fmax, float lambda)\n{\n    int64_t i = 0;\n    float inv_lambda = 1.0f / lambda;\n\n#if defined(EIDOS_HAS_AVX2)\n    __m256 v_fmax = _mm256_set1_ps(fmax);\n    __m256 v_inv_lambda = _mm256_set1_ps(inv_lambda);\n    __m256 v_one = _mm256_set1_ps(1.0f);\n\n    for (; i + 8 <= count; i += 8)\n    {\n        __m256 v_dist = _mm256_loadu_ps(&distances[i]);\n        __m256 v_temp = _mm256_mul_ps(v_dist, v_inv_lambda);      // d/lambda\n        __m256 v_temp_sq = _mm256_mul_ps(v_temp, v_temp);         // (d/lambda)^2\n        __m256 v_denom = _mm256_add_ps(v_one, v_temp_sq);         // 1 + (d/lambda)^2\n        __m256 v_result = _mm256_div_ps(v_fmax, v_denom);         // fmax / denom\n        _mm256_storeu_ps(&distances[i], v_result);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    float32x4_t v_fmax = vdupq_n_f32(fmax);\n    float32x4_t v_inv_lambda = vdupq_n_f32(inv_lambda);\n    float32x4_t v_one = vdupq_n_f32(1.0f);\n\n    for (; i + 4 <= count; i += 4)\n    {\n        float32x4_t v_dist = vld1q_f32(&distances[i]);\n        float32x4_t v_temp = vmulq_f32(v_dist, v_inv_lambda);\n        float32x4_t v_temp_sq = vmulq_f32(v_temp, v_temp);\n        float32x4_t v_denom = vaddq_f32(v_one, v_temp_sq);\n        float32x4_t v_result = vdivq_f32(v_fmax, v_denom);\n        vst1q_f32(&distances[i], v_result);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n    {\n        float d = distances[i];\n        float temp = d * inv_lambda;\n        distances[i] = fmax / (1.0f + temp * temp);\n    }\n}\n\n// ---------------------\n// Linear Kernel: strength = fmax * (1 - d / max_distance)\n// ---------------------\n// Operates in-place on a distance array, transforming distances to strengths.\n// Parameters: fmax = maximum strength, max_distance = interaction max distance\ninline void linear_kernel_float32(float *distances, int64_t count, float fmax, float max_distance)\n{\n    int64_t i = 0;\n    float fmax_over_maxdist = fmax / max_distance;\n\n#if defined(EIDOS_HAS_AVX2)\n    __m256 v_fmax = _mm256_set1_ps(fmax);\n    __m256 v_fmax_over_maxdist = _mm256_set1_ps(fmax_over_maxdist);\n\n    for (; i + 8 <= count; i += 8)\n    {\n        __m256 v_dist = _mm256_loadu_ps(&distances[i]);\n        // fmax - d * (fmax / max_distance) = fmax * (1 - d/max_distance)\n        __m256 v_term = _mm256_mul_ps(v_dist, v_fmax_over_maxdist);\n        __m256 v_result = _mm256_sub_ps(v_fmax, v_term);\n        _mm256_storeu_ps(&distances[i], v_result);\n    }\n#elif defined(EIDOS_HAS_NEON)\n    float32x4_t v_fmax = vdupq_n_f32(fmax);\n    float32x4_t v_fmax_over_maxdist = vdupq_n_f32(fmax_over_maxdist);\n\n    for (; i + 4 <= count; i += 4)\n    {\n        float32x4_t v_dist = vld1q_f32(&distances[i]);\n        float32x4_t v_term = vmulq_f32(v_dist, v_fmax_over_maxdist);\n        float32x4_t v_result = vsubq_f32(v_fmax, v_term);\n        vst1q_f32(&distances[i], v_result);\n    }\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n    {\n        distances[i] = fmax - distances[i] * fmax_over_maxdist;\n    }\n}\n\n// ================================\n// Convolution Helpers for SpatialMap::smooth()\n// ================================\n// These functions compute vectorized dot products for convolution operations.\n// They accumulate both kernel_sum and conv_sum (weighted sum) in a single pass.\n\n// ---------------------\n// Convolution dot product: accumulates kernel_sum and kernel*values sum\n// ---------------------\n// Computes: kernel_sum += sum(kernel), conv_sum += sum(kernel * values)\n// Used by SpatialMap convolution when all values are valid (no edge handling needed)\ninline void convolve_dot_product_float64(\n    const double *kernel_ptr, const double *pixel_ptr,\n    int64_t count, double &kernel_sum, double &conv_sum)\n{\n    int64_t i = 0;\n    double local_ksum = 0.0;\n    double local_csum = 0.0;\n\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    __m256d v_ksum = _mm256_setzero_pd();\n    __m256d v_csum = _mm256_setzero_pd();\n\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v_kernel = _mm256_loadu_pd(&kernel_ptr[i]);\n        __m256d v_pixel = _mm256_loadu_pd(&pixel_ptr[i]);\n\n        v_ksum = _mm256_add_pd(v_ksum, v_kernel);\n        v_csum = _mm256_fmadd_pd(v_kernel, v_pixel, v_csum);\n    }\n\n    // Horizontal sum\n    __m128d ksum_low = _mm256_castpd256_pd128(v_ksum);\n    __m128d ksum_high = _mm256_extractf128_pd(v_ksum, 1);\n    ksum_low = _mm_add_pd(ksum_low, ksum_high);\n    __m128d ksum_shuf = _mm_shuffle_pd(ksum_low, ksum_low, 1);\n    ksum_low = _mm_add_sd(ksum_low, ksum_shuf);\n    local_ksum = _mm_cvtsd_f64(ksum_low);\n\n    __m128d csum_low = _mm256_castpd256_pd128(v_csum);\n    __m128d csum_high = _mm256_extractf128_pd(v_csum, 1);\n    csum_low = _mm_add_pd(csum_low, csum_high);\n    __m128d csum_shuf = _mm_shuffle_pd(csum_low, csum_low, 1);\n    csum_low = _mm_add_sd(csum_low, csum_shuf);\n    local_csum = _mm_cvtsd_f64(csum_low);\n\n#elif defined(EIDOS_HAS_SSE42)\n    __m128d v_ksum = _mm_setzero_pd();\n    __m128d v_csum = _mm_setzero_pd();\n\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v_kernel = _mm_loadu_pd(&kernel_ptr[i]);\n        __m128d v_pixel = _mm_loadu_pd(&pixel_ptr[i]);\n\n        v_ksum = _mm_add_pd(v_ksum, v_kernel);\n        __m128d v_prod = _mm_mul_pd(v_kernel, v_pixel);\n        v_csum = _mm_add_pd(v_csum, v_prod);\n    }\n\n    // Horizontal sum\n    __m128d ksum_shuf = _mm_shuffle_pd(v_ksum, v_ksum, 1);\n    v_ksum = _mm_add_sd(v_ksum, ksum_shuf);\n    local_ksum = _mm_cvtsd_f64(v_ksum);\n\n    __m128d csum_shuf = _mm_shuffle_pd(v_csum, v_csum, 1);\n    v_csum = _mm_add_sd(v_csum, csum_shuf);\n    local_csum = _mm_cvtsd_f64(v_csum);\n\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t v_ksum = vdupq_n_f64(0.0);\n    float64x2_t v_csum = vdupq_n_f64(0.0);\n\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v_kernel = vld1q_f64(&kernel_ptr[i]);\n        float64x2_t v_pixel = vld1q_f64(&pixel_ptr[i]);\n\n        v_ksum = vaddq_f64(v_ksum, v_kernel);\n        v_csum = vfmaq_f64(v_csum, v_kernel, v_pixel);\n    }\n\n    local_ksum = vaddvq_f64(v_ksum);\n    local_csum = vaddvq_f64(v_csum);\n#endif\n\n    // Scalar remainder\n    for (; i < count; i++)\n    {\n        local_ksum += kernel_ptr[i];\n        local_csum += kernel_ptr[i] * pixel_ptr[i];\n    }\n\n    kernel_sum += local_ksum;\n    conv_sum += local_csum;\n}\n\n// ---------------------\n// Scaled convolution dot product for edge handling\n// ---------------------\n// Like convolve_dot_product_float64 but scales kernel values by coverage factor.\n// Used when handling edges where some kernel positions are out of bounds.\ninline void convolve_dot_product_scaled_float64(\n    const double *kernel_ptr, const double *pixel_ptr,\n    int64_t count, double coverage,\n    double &kernel_sum, double &conv_sum)\n{\n    int64_t i = 0;\n    double local_ksum = 0.0;\n    double local_csum = 0.0;\n\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    __m256d v_coverage = _mm256_set1_pd(coverage);\n    __m256d v_ksum = _mm256_setzero_pd();\n    __m256d v_csum = _mm256_setzero_pd();\n\n    for (; i + 4 <= count; i += 4)\n    {\n        __m256d v_kernel = _mm256_loadu_pd(&kernel_ptr[i]);\n        __m256d v_pixel = _mm256_loadu_pd(&pixel_ptr[i]);\n        __m256d v_scaled_kernel = _mm256_mul_pd(v_kernel, v_coverage);\n\n        v_ksum = _mm256_add_pd(v_ksum, v_scaled_kernel);\n        v_csum = _mm256_fmadd_pd(v_scaled_kernel, v_pixel, v_csum);\n    }\n\n    // Horizontal sum\n    __m128d ksum_low = _mm256_castpd256_pd128(v_ksum);\n    __m128d ksum_high = _mm256_extractf128_pd(v_ksum, 1);\n    ksum_low = _mm_add_pd(ksum_low, ksum_high);\n    __m128d ksum_shuf = _mm_shuffle_pd(ksum_low, ksum_low, 1);\n    ksum_low = _mm_add_sd(ksum_low, ksum_shuf);\n    local_ksum = _mm_cvtsd_f64(ksum_low);\n\n    __m128d csum_low = _mm256_castpd256_pd128(v_csum);\n    __m128d csum_high = _mm256_extractf128_pd(v_csum, 1);\n    csum_low = _mm_add_pd(csum_low, csum_high);\n    __m128d csum_shuf = _mm_shuffle_pd(csum_low, csum_low, 1);\n    csum_low = _mm_add_sd(csum_low, csum_shuf);\n    local_csum = _mm_cvtsd_f64(csum_low);\n\n#elif defined(EIDOS_HAS_SSE42)\n    __m128d v_coverage = _mm_set1_pd(coverage);\n    __m128d v_ksum = _mm_setzero_pd();\n    __m128d v_csum = _mm_setzero_pd();\n\n    for (; i + 2 <= count; i += 2)\n    {\n        __m128d v_kernel = _mm_loadu_pd(&kernel_ptr[i]);\n        __m128d v_pixel = _mm_loadu_pd(&pixel_ptr[i]);\n        __m128d v_scaled_kernel = _mm_mul_pd(v_kernel, v_coverage);\n\n        v_ksum = _mm_add_pd(v_ksum, v_scaled_kernel);\n        __m128d v_prod = _mm_mul_pd(v_scaled_kernel, v_pixel);\n        v_csum = _mm_add_pd(v_csum, v_prod);\n    }\n\n    // Horizontal sum\n    __m128d ksum_shuf = _mm_shuffle_pd(v_ksum, v_ksum, 1);\n    v_ksum = _mm_add_sd(v_ksum, ksum_shuf);\n    local_ksum = _mm_cvtsd_f64(v_ksum);\n\n    __m128d csum_shuf = _mm_shuffle_pd(v_csum, v_csum, 1);\n    v_csum = _mm_add_sd(v_csum, csum_shuf);\n    local_csum = _mm_cvtsd_f64(v_csum);\n\n#elif defined(EIDOS_HAS_NEON)\n    float64x2_t v_coverage = vdupq_n_f64(coverage);\n    float64x2_t v_ksum = vdupq_n_f64(0.0);\n    float64x2_t v_csum = vdupq_n_f64(0.0);\n\n    for (; i + 2 <= count; i += 2)\n    {\n        float64x2_t v_kernel = vld1q_f64(&kernel_ptr[i]);\n        float64x2_t v_pixel = vld1q_f64(&pixel_ptr[i]);\n        float64x2_t v_scaled_kernel = vmulq_f64(v_kernel, v_coverage);\n\n        v_ksum = vaddq_f64(v_ksum, v_scaled_kernel);\n        v_csum = vfmaq_f64(v_csum, v_scaled_kernel, v_pixel);\n    }\n\n    local_ksum = vaddvq_f64(v_ksum);\n    local_csum = vaddvq_f64(v_csum);\n#endif\n\n    // Scalar remainder with scaling\n    for (; i < count; i++)\n    {\n        double scaled_k = kernel_ptr[i] * coverage;\n        local_ksum += scaled_k;\n        local_csum += scaled_k * pixel_ptr[i];\n    }\n\n    kernel_sum += local_ksum;\n    conv_sum += local_csum;\n}\n\n} // namespace Eidos_SIMD\n\n\n// stop suppressing warnings\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\n\n#endif /* eidos_simd_h */\n"
  },
  {
    "path": "eidos/eidos_sorting.cpp",
    "content": "//\n//  eidos_sorting.cpp\n//  SLiM\n//\n//  Created by Ben Haller on 8/12/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <vector>\n#include <algorithm>\n#include <numeric>\n#include <cstdint>\n#include <string>\n#include <cmath>\n\n#include \"eidos_sorting.h\"\n\n\n// Generate the code for our sorting variants\n\n#define SORTTYPE\t\t\tint64_t\n#define EIDOS_SORT_CUTOFF\tEIDOS_OMPMIN_SORT_INT\n#define EIDOS_SORT_THREADS\tgEidos_OMP_threads_SORT_INT\n#include \"eidos_sorting.inc\"\n\n#define SORTTYPE\t\t\tdouble\n#define EIDOS_SORT_CUTOFF\tEIDOS_OMPMIN_SORT_FLOAT\n#define EIDOS_SORT_THREADS\tgEidos_OMP_threads_SORT_FLOAT\n#include \"eidos_sorting.inc\"\n\n#define SORTTYPE\t\t\tstd::string\n#define EIDOS_SORT_CUTOFF\tEIDOS_OMPMIN_SORT_STRING\n#define EIDOS_SORT_THREADS\tgEidos_OMP_threads_SORT_STRING\n#include \"eidos_sorting.inc\"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_sorting.h",
    "content": "//\n//  eidos_sorting.h\n//  Eidos\n//\n//  Created by Ben Haller on 8/12/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This file contains an assortment of sorting algorithms used for various purposes.\n \n */\n\n\n#ifndef __Eidos__eidos_sorting_h\n#define __Eidos__eidos_sorting_h\n\n#include \"eidos_openmp.h\"\n\n#include <vector>\n#include <algorithm>\n#include <numeric>\n#include <cstdint>\n#include <string>\n#include <cmath>\n\n\n//\n//\tParallel sorting; these use std::sort when we are not running parallel, or for small jobs\n//\n\n// Here are some early explorations into parallelizing sorting.  The speedups\n// here are not particularly impressive.  Parallel sorting is a very deep and\n// complex rabbit hole to go down; see, e.g., Victor Duvanenko's work at\n// https://github.com/DragonSpit/ParallelAlgorithms.  But those algorithms\n// use TBB instead of OpenMP, and require C++17, so they're not easily usable.\n// Wikipedia at https://en.wikipedia.org/wiki/Merge_sort#Parallel_merge_sort\n// also has some very interesting commentary about parallelization of sorting.\n// The code here is also very primitive - integer only, no templates, no\n// client-suppliable comparator, etc. – so it would be hard to integrate into\n// all the ways Eidos presently uses std::sort.  Improving this looks like a\n// good project for somebody in CS.\n\nvoid Eidos_ParallelSort(int64_t *values, int64_t nelements, bool p_ascending);\nvoid Eidos_ParallelSort(float *values, int64_t nelements, bool p_ascending);\nvoid Eidos_ParallelSort(double *values, int64_t nelements, bool p_ascending);\nvoid Eidos_ParallelSort(std::string *values, int64_t nelements, bool p_ascending);\n\n// This constant basically determines how much a sorting task will get subdivided\n// before the small chunks get turned over to std::sort() to single-threaded sort.\n// The optimum (probably hardware-dependent) was determined by trial and error.\n#define EIDOS_FALLTHROUGH_FACTOR\t10\n\n// This template-based version should be equivalent to the above include-based\n// version, but unfortunately it runs a little slower; I can't figure out why.\n#ifdef _OPENMP\ntemplate <typename T, typename Compare>\nstatic void _Eidos_ParallelQuicksort_Comparator(T *values, int64_t lo, int64_t hi, const Compare &comparator, int64_t fallthrough)\n{\n\tif (lo >= hi)\n\t\treturn;\n\t\n\tif (hi - lo + 1 <= fallthrough) {\n\t\t// fall through to sorting with std::sort() below our threshold size\n\t\tstd::sort(values + lo, values + hi + 1, comparator);\n\t} else {\n\t\t// choose the middle of three pivots, in an attempt to avoid really bad pivots\n\t\tT &pivot1 = *(values + lo);\n\t\tT &pivot2 = *(values + hi);\n\t\tT &pivot3 = *(values + ((lo + hi) >> 1));\n\t\tT pivot;\n\t\t\n\t\tif (pivot1 > pivot2)\n\t\t{\n\t\t\tif (pivot2 > pivot3)\t\tpivot = pivot2;\n\t\t\telse if (pivot1 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (pivot1 > pivot3)\t\tpivot = pivot1;\n\t\t\telse if (pivot2 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot2;\n\t\t}\n\t\t\n\t\t// note that std::partition is not guaranteed to leave the pivot value in position\n\t\t// we do a second partition to exclude all duplicate pivot values, which seems to be one standard strategy\n\t\t// this works particularly well when duplicate values are very common; it helps avoid O(n^2) performance\n\t\t// note the partition is not parallelized; that is apparently a difficult problem for parallel quicksort\n\t\tT *middle1 = std::partition(values + lo, values + hi + 1, [&, pivot, comparator](const T& em) { return comparator(em, pivot); });\n\t\tT *middle2 = std::partition(middle1, values + hi + 1, [&, pivot, comparator](const T& em) { return !comparator(pivot, em); });\n\t\tint64_t mid1 = middle1 - values;\n\t\tint64_t mid2 = middle2 - values;\n\t\t#pragma omp task default(none) firstprivate(values, lo, mid1) shared(comparator, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_Comparator(values, lo, mid1 - 1, comparator, fallthrough); }\t// Left branch\n\t\t#pragma omp task default(none) firstprivate(values, hi, mid2) shared(comparator, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_Comparator(values, mid2, hi, comparator, fallthrough); }\t\t// Right branch\n\t}\n}\n#endif\n\ntemplate <typename T, typename Compare>\nvoid Eidos_ParallelSort_Comparator(T *values, int64_t nelements, const Compare &comparator)\n{\n\t// This wrapper just ensures that we use std::sort for small vectors,\n\t// or when not parallel, andhandles ascending vs. descending\n#ifdef _OPENMP\n\tif (nelements >= EIDOS_OMPMIN_SORT_INT) {\t\t\t\t// we use the integer cutoff here; it's the common case\n\t\tEIDOS_THREAD_COUNT(gEidos_OMP_threads_SORT_INT);\t// we use the integer cutoff here; it's the common case\n#pragma omp parallel default(none) shared(values, nelements, comparator) num_threads(thread_count)\n\t\t{\n\t\t\t// We fall through to using std::sort when below a threshold interval size.\n\t\t\t// The larger the threshold, the less time we spend thrashing tasks on small\n\t\t\t// intervals, which is good; but it also sets a limit on how many threads we\n\t\t\t// we bring to bear on relatively small sorts, which is bad.  We try to\n\t\t\t// calculate the optimal fall-through heuristically here; basically we want\n\t\t\t// to subdivide with tasks enough that the workload is shared well, and then\n\t\t\t// do the rest of the work with std::sort().  The more threads there are,\n\t\t\t// the smaller we want to subdivide.\n\t\t\tint64_t fallthrough = nelements / (EIDOS_FALLTHROUGH_FACTOR * omp_get_num_threads());\n\t\t\t\n\t\t\tif (fallthrough < 1000)\n\t\t\t\tfallthrough = 1000;\n\t\t\t\n#pragma omp single nowait\n\t\t\t{\n\t\t\t\t_Eidos_ParallelQuicksort_Comparator(values, 0, nelements - 1, comparator, fallthrough);\n\t\t\t}\n\t\t} // End of parallel region\n\t}\n\telse\n\t{\n\t\tstd::sort(values, values + nelements, comparator);\n\t}\n#else\n\tstd::sort(values, values + nelements, comparator);\n#endif\n}\n\n\n//\n//\tSriram's parallel sort\n//\n\ntemplate <typename T, typename Compare>\nvoid Sriram_parallel_omp_sort(std::vector<T> &data, Compare comparator)\n{\n\tint num_threads = omp_get_max_threads();\n\tsize_t size = data.size();\n\tsize_t chunk_size = size / num_threads;\t\t// chunk size per thread\n\t\n#pragma omp parallel\n\t{\n\t\tint tid = omp_get_thread_num();\n\t\t// cout << omp_get_thread_num() << std::endl;\n\t\t\n\t\tsize_t start = tid * chunk_size;\n\t\tsize_t end = (tid + 1) * chunk_size;\n\t\t\n\t\t// cppcheck is confused here when building single-threaded\n\t\tif (tid == num_threads - 1)\t\t// cppcheck-suppress knownConditionTrueFalse\n\t\t\tend = size;\t\t\t\t\t// cppcheck-suppress redundantAssignment\n\t\t\n\t\t// sort sub-array using comparator\n\t\tstd::sort(data.begin() + start, data.begin() + end, comparator);\n\t}\n\t\n\tstd::sort(data.begin(), data.end(), comparator);\n}\n\n\n//\n//\tGet indexes that would result in sorted ordering of a vector.\n//\tThis rather nice code is adapted from http://stackoverflow.com/a/12399290/2752221\n//\n\ntemplate <typename T>\nstd::vector<int64_t> EidosSortIndexes(const std::vector<T> &p_v, bool p_ascending = true)\n{\n\t// initialize original index locations\n\tstd::vector<int64_t> idx(p_v.size());\n\tstd::iota(idx.begin(), idx.end(), 0);\n\t\n\t// sort indexes based on comparing values in v\n\tif (p_ascending)\n\t\tstd::sort(idx.begin(), idx.end(), [&p_v](int64_t i1, int64_t i2) {return p_v[i1] < p_v[i2];});\n\telse\n\t\tstd::sort(idx.begin(), idx.end(), [&p_v](int64_t i1, int64_t i2) {return p_v[i1] > p_v[i2];});\n\t\n\treturn idx;\n}\n\ntemplate <>\ninline std::vector<int64_t> EidosSortIndexes<double>(const std::vector<double> &p_v, bool p_ascending)\n{\n\t// initialize original index locations\n\tstd::vector<int64_t> idx(p_v.size());\n\tstd::iota(idx.begin(), idx.end(), 0);\n\t\n\t// sort indexes based on comparing values in v\n\t// this specialization for type double sorts NaNs to the end\n\tif (p_ascending)\n\t\tstd::sort(idx.begin(), idx.end(), [&p_v](int64_t i1, int64_t i2) {return std::isnan(p_v[i2]) || (p_v[i1] < p_v[i2]);});\n\telse\n\t\tstd::sort(idx.begin(), idx.end(), [&p_v](int64_t i1, int64_t i2) {return std::isnan(p_v[i2]) || (p_v[i1] > p_v[i2]);});\n\t\n\treturn idx;\n}\n\ntemplate <typename T>\nstd::vector<int64_t> EidosSortIndexes(const T *p_v, size_t p_size, bool p_ascending = true)\n{\n\t// initialize original index locations\n\tstd::vector<int64_t> idx(p_size);\n\tstd::iota(idx.begin(), idx.end(), 0);\n\t\n\t// sort indexes based on comparing values in v\n\tif (p_ascending)\n\t\tstd::sort(idx.begin(), idx.end(), [p_v](int64_t i1, int64_t i2) {return p_v[i1] < p_v[i2];});\n\telse\n\t\tstd::sort(idx.begin(), idx.end(), [p_v](int64_t i1, int64_t i2) {return p_v[i1] > p_v[i2];});\n\t\n\treturn idx;\n}\n\ntemplate <>\ninline std::vector<int64_t> EidosSortIndexes<double>(const double *p_v, size_t p_size, bool p_ascending)\n{\n\t// initialize original index locations\n\tstd::vector<int64_t> idx(p_size);\n\tstd::iota(idx.begin(), idx.end(), 0);\n\t\n\t// sort indexes based on comparing values in v\n\t// this specialization for type double sorts NaNs to the end\n\tif (p_ascending)\n\t\tstd::sort(idx.begin(), idx.end(), [p_v](int64_t i1, int64_t i2) {\n\t\t\tdouble a = p_v[i1];\n\t\t\tdouble b = p_v[i2];\n\t\t\t\n\t\t\t// If a is NaN and b is not NaN, a should come after b\n\t\t\tif (std::isnan(a) && !std::isnan(b))\n\t\t\t\treturn false;\n\t\t\t\n\t\t\t// If b is NaN and a is not NaN, b should come after a\n\t\t\tif (!std::isnan(a) && std::isnan(b))\n\t\t\t\treturn true;\n\t\t\t\n\t\t\t// If both are NaN or both are non-NaN, sort numerically (ascending)\n\t\t\treturn a < b;\n\t\t});\n\telse\n\t\tstd::sort(idx.begin(), idx.end(), [p_v](int64_t i1, int64_t i2) {\n\t\t\tdouble a = p_v[i1];\n\t\t\tdouble b = p_v[i2];\n\t\t\t\n\t\t\t// If a is NaN and b is not NaN, a should come after b\n\t\t\tif (std::isnan(a) && !std::isnan(b))\n\t\t\t\treturn false;\n\t\t\t\n\t\t\t// If b is NaN and a is not NaN, b should come after a\n\t\t\tif (!std::isnan(a) && std::isnan(b))\n\t\t\t\treturn true;\n\t\t\t\n\t\t\t// If both are NaN or both are non-NaN, sort numerically (descending)\n\t\t\treturn a > b;\n\t\t});\n\t\n\treturn idx;\n}\n\n\n#endif /* __Eidos__eidos_sorting_h */\n"
  },
  {
    "path": "eidos/eidos_sorting.inc",
    "content": "//\n//  eidos_sorting.inc\n//  SLiM\n//\n//  Created by Ben Haller on 8/12/23.\n//  Copyright (c) 2023-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n// This file is intended to be #included to generate code.  This would be cleaner if we could use\n// C++ templates, but that seems to kill performance, in my tests; the compiler does not seem to\n// be smart enough, or (very possibly) I'm doing it wrong.  Anyhow, define SORTTYPE and then include.\n\n#ifndef SORTTYPE\n#error SORTTYPE must be defined before including this file\n#endif\n\n\n// This parallel quicksort code is thanks to Ruud van der Pas, modified from\n// https://www.openmp.org/wp-content/uploads/sc16-openmp-booth-tasking-ruud.pdf\n#ifdef _OPENMP\nstatic void _Eidos_ParallelQuicksort_ASCENDING(SORTTYPE *values, int64_t lo, int64_t hi, int64_t fallthrough)\n{\n\tif (lo >= hi)\n\t\treturn;\n\t\n\tif (hi - lo + 1 <= fallthrough) {\n\t\t// fall through to sorting with std::sort() below our threshold size\n\t\tstd::sort(values + lo, values + hi + 1);\n\t} else {\n\t\t// choose the middle of three pivots, in an attempt to avoid really bad pivots\n\t\tSORTTYPE &pivot1 = *(values + lo);\n\t\tSORTTYPE &pivot2 = *(values + hi);\n\t\tSORTTYPE &pivot3 = *(values + ((lo + hi) >> 1));\n\t\tSORTTYPE pivot;\n\t\t\n\t\tif (pivot1 > pivot2)\n\t\t{\n\t\t\tif (pivot2 > pivot3)\t\tpivot = pivot2;\n\t\t\telse if (pivot1 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (pivot1 > pivot3)\t\tpivot = pivot1;\n\t\t\telse if (pivot2 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot2;\n\t\t}\n\t\t\n\t\t// note that std::partition is not guaranteed to leave the pivot value in position\n\t\t// we do a second partition to exclude all duplicate pivot values, which seems to be one standard strategy\n\t\t// this works particularly well when duplicate values are very common; it helps avoid O(n^2) performance\n\t\t// note the partition is not parallelized; that is apparently a difficult problem for parallel quicksort\n\t\tSORTTYPE *middle1 = std::partition(values + lo, values + hi + 1, [pivot](const SORTTYPE& em) { return em < pivot; });\n\t\tSORTTYPE *middle2 = std::partition(middle1, values + hi + 1, [pivot](const SORTTYPE& em) { return !(pivot < em); });\n\t\tint64_t mid1 = middle1 - values;\n\t\tint64_t mid2 = middle2 - values;\n\t\t#pragma omp task default(none) firstprivate(values, lo, mid1, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_ASCENDING(values, lo, mid1 - 1, fallthrough); }\t// Left branch\n\t\t#pragma omp task default(none) firstprivate(values, hi, mid2, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_ASCENDING(values, mid2, hi, fallthrough); }\t\t// Right branch\n\t}\n}\n\nstatic void _Eidos_ParallelQuicksort_DESCENDING(SORTTYPE *values, int64_t lo, int64_t hi, int64_t fallthrough)\n{\n\tif (lo >= hi)\n\t\treturn;\n\t\n\tif (hi - lo + 1 <= fallthrough) {\n\t\t// fall through to sorting with std::sort() below our threshold size\n\t\t// note that descending sorts are slower because this STL usage pattern is slower!\n\t\tstd::sort(values + lo, values + hi + 1, std::greater<SORTTYPE>());\n\t} else {\n\t\t// choose the middle of three pivots, in an attempt to avoid really bad pivots\n\t\tSORTTYPE &pivot1 = *(values + lo);\n\t\tSORTTYPE &pivot2 = *(values + hi);\n\t\tSORTTYPE &pivot3 = *(values + ((lo + hi) >> 1));\n\t\tSORTTYPE pivot;\n\t\t\n\t\tif (pivot1 > pivot2)\n\t\t{\n\t\t\tif (pivot2 > pivot3)\t\tpivot = pivot2;\n\t\t\telse if (pivot1 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (pivot1 > pivot3)\t\tpivot = pivot1;\n\t\t\telse if (pivot2 > pivot3)\tpivot = pivot3;\n\t\t\telse\t\t\t\t\t\tpivot = pivot2;\n\t\t}\n\t\t\n\t\t// note that std::partition is not guaranteed to leave the pivot value in position\n\t\t// we do a second partition to exclude all duplicate pivot values, which seems to be one standard strategy\n\t\t// this works particularly well when duplicate values are very common; it helps avoid O(n^2) performance\n\t\t// note the partition is not parallelized; that is apparently a difficult problem for parallel quicksort\n\t\tSORTTYPE *middle1 = std::partition(values + lo, values + hi + 1, [pivot](const SORTTYPE& em) { return em > pivot; });\n\t\tSORTTYPE *middle2 = std::partition(middle1, values + hi + 1, [pivot](const SORTTYPE& em) { return !(pivot > em); });\n\t\tint64_t mid1 = middle1 - values;\n\t\tint64_t mid2 = middle2 - values;\n\t\t#pragma omp task default(none) firstprivate(values, lo, mid1, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_DESCENDING(values, lo, mid1 - 1, fallthrough); }\t// Left branch\n\t\t#pragma omp task default(none) firstprivate(values, hi, mid2, fallthrough)\n\t\t{ _Eidos_ParallelQuicksort_DESCENDING(values, mid2, hi, fallthrough); }\t\t// Right branch\n\t}\n}\n#endif\n\nvoid Eidos_ParallelSort(SORTTYPE *values, int64_t nelements, bool p_ascending)\n{\n\t// This wrapper just ensures that we use std::sort for small vectors,\n\t// or when not parallel, andhandles ascending vs. descending\n#ifdef _OPENMP\n\tif (nelements >= EIDOS_SORT_CUTOFF) {\n\t\tEIDOS_THREAD_COUNT(EIDOS_SORT_THREADS);\n#pragma omp parallel default(none) shared(values, nelements, p_ascending) num_threads(thread_count)\n\t\t{\n\t\t\t// We fall through to using std::sort when below a threshold interval size.\n\t\t\t// The larger the threshold, the less time we spend thrashing tasks on small\n\t\t\t// intervals, which is good; but it also sets a limit on how many threads we\n\t\t\t// we bring to bear on relatively small sorts, which is bad.  We try to\n\t\t\t// calculate the optimal fall-through heuristically here; basically we want\n\t\t\t// to subdivide with tasks enough that the workload is shared well, and then\n\t\t\t// do the rest of the work with std::sort().  The more threads there are,\n\t\t\t// the smaller we want to subdivide.\n\t\t\tint64_t fallthrough = nelements / (EIDOS_FALLTHROUGH_FACTOR * omp_get_num_threads());\n\t\t\t\n\t\t\tif (fallthrough < 1000)\n\t\t\t\tfallthrough = 1000;\n\t\t\t\n\t\t\tif (p_ascending)\n\t\t\t{\n#pragma omp single nowait\n\t\t\t\t{\n\t\t\t\t\t_Eidos_ParallelQuicksort_ASCENDING(values, 0, nelements - 1, fallthrough);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#pragma omp single nowait\n\t\t\t\t{\n\t\t\t\t\t_Eidos_ParallelQuicksort_DESCENDING(values, 0, nelements - 1, fallthrough);\n\t\t\t\t}\n\t\t\t}\n\t\t} // End of parallel region\n\t}\n\telse\n\t{\n\t\tif (p_ascending)\n\t\t\tstd::sort(values, values + nelements);\n\t\telse\n\t\t\tstd::sort(values, values + nelements, std::greater<SORTTYPE>());\n\t}\n#else\n\tif (p_ascending)\n\t\tstd::sort(values, values + nelements);\n\telse\n\t\tstd::sort(values, values + nelements, std::greater<SORTTYPE>());\n#endif\n}\n\n// Leave the includer with SORTTYPE undefined, to avoid accidents\n#undef SORTTYPE\n#undef EIDOS_SORT_CUTOFF\n#undef EIDOS_SORT_THREADS\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_symbol_table.cpp",
    "content": "//\n//  eidos_symbol_table.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/12/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_symbol_table.h\"\n#include \"eidos_value.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_token.h\"\n#include \"eidos_type_table.h\"\n\n#include <algorithm>\n#include <utility>\n#include <limits>\n#include <cmath>\n\n\n//\n//\tShared pools of reusable objects for EidosSymbolTable\n//\n#pragma mark -\n#pragma mark pool management\n#pragma mark -\n\nstd::vector<EidosSymbolTableSlot *> gEidosSymbolTable_TablePool;\nuint32_t gEidosSymbolTable_TablePool_table_capacity = 1024;\t\t// adequate for most scripts; can increase dynamically\n\nsize_t MemoryUsageForSymbolTables(EidosSymbolTable *p_currentTable)\n{\n\tsize_t usage = 0;\n\t\n\tusage = gEidosSymbolTable_TablePool.size() * gEidosSymbolTable_TablePool_table_capacity * sizeof(EidosSymbolTableSlot);\n\t\n\twhile (p_currentTable)\n\t{\n\t\tusage += p_currentTable->capacity_ * sizeof(EidosSymbolTableSlot);\n\t\tp_currentTable = p_currentTable->parent_symbol_table_;\n\t}\n\t\n\treturn usage;\n}\n\nstatic inline __attribute__((always_inline)) EidosSymbolTableSlot *GetZeroedTableFromPool(uint32_t *p_capacity)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"GetZeroedTableFromPool(): gEidosSymbolTable_TablePool change\");\n\t\n\t// Get a zeroed table from the pool, or make a new one\n\t*p_capacity = gEidosSymbolTable_TablePool_table_capacity;\n\t\n\tif (gEidosSymbolTable_TablePool.size())\n\t{\n\t\tEidosSymbolTableSlot *ret = gEidosSymbolTable_TablePool.back();\n\t\tgEidosSymbolTable_TablePool.pop_back();\n\t\treturn ret;\n\t}\n\t\n\tEidosSymbolTableSlot *ret = (EidosSymbolTableSlot *)calloc(gEidosSymbolTable_TablePool_table_capacity, sizeof(EidosSymbolTableSlot));\n\tif (!ret)\n\t\tEIDOS_TERMINATION << \"ERROR (GetZeroedTableFromPool): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\treturn ret;\n}\n\nstatic inline __attribute__((always_inline)) void FreeZeroedTableToPool(EidosSymbolTableSlot *p_table, uint32_t p_capacity)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"FreeZeroedTableToPool(): gEidosSymbolTable_TablePool change\");\n\t\n\tif (p_capacity > gEidosSymbolTable_TablePool_table_capacity)\n\t{\n\t\t// If the returning table is bigger than those in the pool, we want to increase the pool capacity\n\t\t// to match; free all tables in the pool, then do the capacity increase for the pool\n\t\tfor (EidosSymbolTableSlot *table : gEidosSymbolTable_TablePool)\n\t\t\tfree(table);\n\t\t\n\t\tgEidosSymbolTable_TablePool.resize(0);\n\t\t\n\t\t//std::cout << \"old symbol table pool's table capacity of \" << gEidosSymbolTable_TablePool_table_capacity << \" increasing to \" << p_capacity << std::endl;\n\t\tgEidosSymbolTable_TablePool_table_capacity = p_capacity;\n\t}\n\telse if (p_capacity < gEidosSymbolTable_TablePool_table_capacity)\n\t{\n\t\t// If the returning table is smaller than those in the pool, it is worthless; it's probably\n\t\t// faster to free it and calloc() a new one than to realloc() and zero the old one\n\t\tfree(p_table);\n\t\treturn;\n\t}\n\t\n\t// Free the zeroed table back to the pool\n\tgEidosSymbolTable_TablePool.emplace_back(p_table);\n}\n\nvoid FreeSymbolTablePool(void)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"FreeSymbolTablePool(): gEidosSymbolTable_TablePool change\");\n\t\n    // Clean up our symbol table slot pool to avoid confusing Valgrind\n    while (gEidosSymbolTable_TablePool.size())\n\t{\n\t\tEidosSymbolTableSlot *ret = gEidosSymbolTable_TablePool.back();\n\t\tgEidosSymbolTable_TablePool.pop_back();\n\t\tfree(ret);\n\t}\n}\n\n\n//\n//\tEidosSymbolTable\n//\n#pragma mark -\n#pragma mark EidosSymbolTable\n#pragma mark -\n\nEidosSymbolTable::EidosSymbolTable(EidosSymbolTableType p_table_type, EidosSymbolTable *p_parent_table) : table_type_(p_table_type),\n\ttable_type_is_constant_((p_table_type != EidosSymbolTableType::kGlobalVariablesTable) && (p_table_type != EidosSymbolTableType::kLocalVariablesTable))\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::EidosSymbolTable(): usage of statics\");\n\t\n\t// allocate the lookup table\n\tslots_ = GetZeroedTableFromPool(&capacity_);\n\t\n\tif (!p_parent_table)\n\t{\n\t\t// If no parent table is given, then we construct a base table for Eidos containing the standard constants.\n\t\t// We statically allocate our base symbols for fast setup / teardown.\n\t\tif (table_type_ != EidosSymbolTableType::kEidosIntrinsicConstantsTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::EidosSymbolTable): (internal error) symbol tables must have a parent table, except the Eidos intrinsic constants table.\" << EidosTerminate(nullptr);\n\t\t\n\t\tstatic EidosSymbolTableEntry *trueConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *falseConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *nullConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *piConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *eConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *infConstant = nullptr;\n\t\tstatic EidosSymbolTableEntry *nanConstant = nullptr;\n\t\t\n\t\tif (!trueConstant)\n\t\t{\n\t\t\ttrueConstant = new EidosSymbolTableEntry(gEidosID_T, gStaticEidosValue_LogicalT);\n\t\t\tfalseConstant = new EidosSymbolTableEntry(gEidosID_F, gStaticEidosValue_LogicalF);\n\t\t\tnullConstant = new EidosSymbolTableEntry(gEidosID_NULL, gStaticEidosValueNULL);\n\t\t\tpiConstant = new EidosSymbolTableEntry(gEidosID_PI, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(M_PI)));\n\t\t\teConstant = new EidosSymbolTableEntry(gEidosID_E, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(M_E)));\n\t\t\tinfConstant = new EidosSymbolTableEntry(gEidosID_INF, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(std::numeric_limits<double>::infinity())));\n\t\t\tnanConstant = new EidosSymbolTableEntry(gEidosID_NAN, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(std::numeric_limits<double>::quiet_NaN())));\n\t\t\t\n\t\t\t// ensure that the constant_ flag is set on all of these values, to prevent modification in all code paths\n\t\t\t// note that gStaticEidosValue_LogicalT, gStaticEidosValue_LogicalF, and gStaticEidosValueNULL are already marked as constant\n\t\t\tpiConstant->second->MarkAsConstant();\n\t\t\teConstant->second->MarkAsConstant();\n\t\t\tinfConstant->second->MarkAsConstant();\n\t\t\tnanConstant->second->MarkAsConstant();\n\t\t}\n\t\t\n\t\t// We can use InitializeConstantSymbolEntry() here since we obey its requirements (see header)\n\t\tInitializeConstantSymbolEntry(*nanConstant);\n\t\tInitializeConstantSymbolEntry(*infConstant);\n\t\tInitializeConstantSymbolEntry(*piConstant);\n\t\tInitializeConstantSymbolEntry(*eConstant);\n\t\tInitializeConstantSymbolEntry(*nullConstant);\n\t\tInitializeConstantSymbolEntry(*falseConstant);\n\t\tInitializeConstantSymbolEntry(*trueConstant);\n\t}\n\telse\n\t{\n\t\t// If a parent table is given, we adopt it and do not add Eidos constants; they will be in the search chain\n\t\tparent_symbol_table_ = p_parent_table;\n\t\tparent_symbol_table_owned_ = false;\n\t\t\n\t\t// If the parent table is a constants table of some kind, then it is the next table in the search chain;\n\t\t// if it is a local variables table, however, then it is our caller, and is not in scope for us, so we skip\n\t\t// over it and use whatever it chains onward to (which may be a constants table or a global variables table).\n\t\t// BCH 10/27/2020: Now the global variables table is kept in the chain as well, if it exists.\n\t\tif (parent_symbol_table_->table_type_ == EidosSymbolTableType::kLocalVariablesTable)\n\t\t\tchain_symbol_table_ = parent_symbol_table_->chain_symbol_table_;\n\t\telse\n\t\t\tchain_symbol_table_ = parent_symbol_table_;\n\t\t\n#if DEBUG\n\t\tif (table_type_ == EidosSymbolTableType::kEidosIntrinsicConstantsTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::EidosSymbolTable): (internal error) the Eidos intrinsic constants table cannot have a parent.\" << EidosTerminate(nullptr);\n\t\tif (chain_symbol_table_->table_type_ == EidosSymbolTableType::kLocalVariablesTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::EidosSymbolTable): (internal error) the chained symbol table must not be a local variables table, in the current design.\" << EidosTerminate(nullptr);\n\t\tif (parent_symbol_table_->table_type_ == EidosSymbolTableType::kINVALID_TABLE_TYPE)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::EidosSymbolTable): (internal error) zombie symbol table re-used as parent table.\" << EidosTerminate(nullptr);\n#endif\n\t}\n}\n\nEidosSymbolTable::~EidosSymbolTable(void)\n{\n\t// We do a little bit of zombie-fication here to try to catch problematic table usage patterns\n\tif (table_type_ == EidosSymbolTableType::kINVALID_TABLE_TYPE)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::~EidosSymbolTable): (internal error) zombie symbol table being destructed.\" << EidosTerminate(nullptr);\n\t\n\ttable_type_ = EidosSymbolTableType::kINVALID_TABLE_TYPE;\n\t\n\t// slots_ may have symbols defined in it, so we need to zero out the used slots for re-use.  Remember that\n\t// the slot at index 0 never has a value defined, and its next_ value is the start of the linked list.\n\tEidosSymbolTableSlot *slot = slots_;\n\t\n\tfor (uint32_t index = slot->next_; index != 0; index = slot->next_)\n\t{\n\t\tslot->next_ = 0;\n\t\tslot = slots_ + index;\n\t\tslot->symbol_value_SP_.reset();\n\t}\n\t\n\t// then return the table to the pools for reuse\n\tFreeZeroedTableToPool(slots_, capacity_);\n\t\n\t// In general, every symbol table has its own lifetime, and a single table might be the parent table for many other\n\t// symbol tables (in the way that the intrinsic constants table is used as the root parent for all symbol table\n\t// chains in Eidos).  The exception to this is defined constants tables, which are added and inserted into the\n\t// symbol table chain dynamically by DefineConstantForSymbol().  They need to be freed, so the policy we have is\n\t// that they are owned by their child table, which has a pointer up to them.  That means that unlike other types\n\t// of tables, DEFINED CONSTANTS TABLES MUST NEVER BE DIRECTLY REFERENCED BY MORE THAN ONE CHILD TABLE.\n\tif (parent_symbol_table_owned_)\n\t{\n\t\tif (!parent_symbol_table_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::~EidosSymbolTable): (internal error) owned parent symbol table was already freed.\" << EidosTerminate(nullptr);\n\t\tif (parent_symbol_table_->table_type_ != EidosSymbolTableType::kEidosDefinedConstantsTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::~EidosSymbolTable): (internal error) owned parent symbol table is of unexpected type.\" << EidosTerminate(nullptr);\n\t\t\n\t\tdelete parent_symbol_table_;\n\t\tparent_symbol_table_ = nullptr;\n\t\tparent_symbol_table_owned_ = false;\n\t}\n}\n\nstd::vector<std::string> EidosSymbolTable::_SymbolNames(bool p_include_constants, bool p_include_variables) const\n{\n\tstd::vector<std::string> symbol_names;\n\t\n\t// recurse to get the symbols from our chained symbol table\n\tif (chain_symbol_table_)\n\t\tsymbol_names = chain_symbol_table_->_SymbolNames(p_include_constants, p_include_variables);\n\t\n\tif ((p_include_constants && table_type_is_constant_) ||\n\t\t(p_include_variables && !table_type_is_constant_))\n\t{\n\t\tfor (EidosGlobalStringID symbol = slots_->next_; symbol != 0; symbol = (slots_ + symbol)->next_)\n\t\t\tsymbol_names.emplace_back(EidosStringRegistry::StringForGlobalStringID(symbol));\n\t}\n\t\n\treturn symbol_names;\n}\n\nbool EidosSymbolTable::ContainsSymbol(EidosGlobalStringID p_symbol_name) const\n{\n\t// Conceptually, this is a recursive function that walks up the symbol table chain.  Doing the recursive calls\n\t// is a bit slow, though, so I have unwrapped the recursion.\n\t\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif ((p_symbol_name < current_table->capacity_) && (current_table->slots_[p_symbol_name].symbol_value_SP_))\n\t\t\treturn true;\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\treturn false;\n}\n\nbool EidosSymbolTable::ContainsSymbol_IsConstant(EidosGlobalStringID p_symbol_name, bool *p_is_const) const\n{\n\t// This follows ContainsSymbol() but adds a flag indicating whether the symbol is defined as a constant.\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif ((p_symbol_name < current_table->capacity_) && (current_table->slots_[p_symbol_name].symbol_value_SP_))\n\t\t{\n\t\t\t*p_is_const = current_table->table_type_is_constant_;\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\t*p_is_const = false;\n\treturn false;\n}\n\nbool EidosSymbolTable::SymbolDefinedAnywhere(EidosGlobalStringID p_symbol_name) const\n{\n\t// This follows ContainsSymbol() but follows parent_symbol_table_ instead of chain_symbol_table_.\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif ((p_symbol_name < current_table->capacity_) && (current_table->slots_[p_symbol_name].symbol_value_SP_))\n\t\t\treturn true;\n\t\t\n\t\t// We didn't get a hit, so try our parent table\n\t\tcurrent_table = current_table->parent_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\treturn false;\n}\n\nbool EidosSymbolTable::SymbolDefinedAnywhere_IsConstant(EidosGlobalStringID p_symbol_name, bool *p_is_const) const\n{\n\t// This follows ContainsSymbol_IsConstant() but follows parent_symbol_table_ instead of chain_symbol_table_.\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif ((p_symbol_name < current_table->capacity_) && (current_table->slots_[p_symbol_name].symbol_value_SP_))\n\t\t{\n\t\t\t*p_is_const = current_table->table_type_is_constant_;\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our parent table\n\t\tcurrent_table = current_table->parent_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\t*p_is_const = false;\n\treturn false;\n}\n\nEidosValue_SP EidosSymbolTable::_GetValue(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const\n{\n\t// Conceptually, this is a recursive function that walks up the symbol table chain.  Doing the recursive calls\n\t// is a bit slow, though, so I have unwrapped the recursion.\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif (p_symbol_name < current_table->capacity_)\n\t\t{\n\t\t\tEidosValue_SP slot_value(current_table->slots_[p_symbol_name].symbol_value_SP_);\n\t\t\t\n\t\t\tif (slot_value)\n\t\t\t\treturn slot_value;\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_GetValue): undefined identifier \" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \".\" << EidosTerminate(p_symbol_token);\n}\n\nEidosValue_SP EidosSymbolTable::_GetValue_SpecialRaise(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const\n{\n\t// Conceptually, this is a recursive function that walks up the symbol table chain.  Doing the recursive calls\n\t// is a bit slow, though, so I have unwrapped the recursion.\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif (p_symbol_name < current_table->capacity_)\n\t\t{\n\t\t\tEidosValue_SP slot_value(current_table->slots_[p_symbol_name].symbol_value_SP_);\n\t\t\t\n\t\t\tif (slot_value)\n\t\t\t\treturn slot_value;\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\t// This \"SpecialRaise\" version of _GetValue() raises a special type of exception that can be\n\t// caught and ignored.  This facility is used by Community::_EvaluateTickRangeNode() to\n\t// implement tolerant evaluation of tick range expressions.  We have to set up the error\n\t// info manually here, since \"<< EidosTerminate(p_symbol_token)' is not doing it for us.\n\tPushErrorPositionFromToken(p_symbol_token);\n\t\n\tthrow SLiMUndefinedIdentifierException(EidosStringRegistry::StringForGlobalStringID(p_symbol_name));\n}\n\nEidosValue *EidosSymbolTable::_GetValue_RAW(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const\n{\n\t// This follows _GetValue() but returns a raw EidosValue * for temporary use\n\tconst EidosSymbolTable *current_table = this;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif (p_symbol_name < current_table->capacity_)\n\t\t{\n\t\t\tEidosValue *slot_value = current_table->slots_[p_symbol_name].symbol_value_SP_.get();\n\t\t\t\n\t\t\tif (slot_value)\n\t\t\t\treturn slot_value;\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t}\n\twhile (current_table);\n\t\n\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_GetValue_RAW): undefined identifier \" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \".\" << EidosTerminate(p_symbol_token);\n}\n\nEidosValue_SP EidosSymbolTable::_GetValue_IsConstIsLocal(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token, bool *p_is_const, bool *p_is_local) const\n{\n\t// This follows _GetValue() but provides the p_is_const and p_is_global flags\n\tconst EidosSymbolTable *current_table = this;\n\t\n\t*p_is_local = true;\n\t\n\tdo\n\t{\n\t\t// try the current table, if the symbol is within its capacity\n\t\tif (p_symbol_name < current_table->capacity_)\n\t\t{\n\t\t\tEidosValue_SP slot_value(current_table->slots_[p_symbol_name].symbol_value_SP_);\n\t\t\t\n\t\t\tif (slot_value)\n\t\t\t{\n\t\t\t\t*p_is_const = current_table->table_type_is_constant_;\n\t\t\t\treturn slot_value;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// We didn't get a hit, so try our chained table\n\t\tcurrent_table = current_table->chain_symbol_table_;\n\t\t*p_is_local = false;\n\t}\n\twhile (current_table);\n\t\n\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_GetValue_IsConstIsLocal): undefined identifier \" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \".\" << EidosTerminate(p_symbol_token);\n}\n\nvoid EidosSymbolTable::_ResizeToFitSymbol(EidosGlobalStringID p_symbol_name)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::_ResizeToFitSymbol(): symbol table change\");\n\t\n\tuint32_t new_capacity = capacity_;\n\t\n\twhile (p_symbol_name >= new_capacity)\n\t\tnew_capacity <<= 1;\n\t\n\tif (new_capacity > capacity_)\n\t{\n\t\t// BCH 11 May 2020: the realloc() and EIDOS_BZERO() here are technically problematic because\n\t\t// EidosSymbolTableSlot is non-trivially copyable according to C++.  But they are safe, so\n\t\t// I have added casts to void* in the hopes of suppressing the compiler warning.\n\t\tslots_ = (EidosSymbolTableSlot *)realloc((void *)slots_, new_capacity * sizeof(EidosSymbolTableSlot));\n\t\tif (!slots_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_ResizeToFitSymbol): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEIDOS_BZERO((void *)(slots_ + capacity_), (new_capacity - capacity_) * sizeof(EidosSymbolTableSlot));\n\t\tcapacity_ = new_capacity;\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_ResizeToFitSymbol): (internal error) unnecessary resize.\" << EidosTerminate();\n}\n\nvoid EidosSymbolTable::SetValueForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::SetValueForSymbol(): symbol table change\");\n\t\n\t// If we have the only reference to the value, we don't need to copy it; otherwise we copy, since we don't want to hold\n\t// onto a reference that somebody else might modify under us (or that we might modify under them, with syntaxes like\n\t// x[2]=...; and x=x+1;). If the value is invisible then we copy it, since the symbol table never stores invisible values.\n\tif ((p_value->UseCount() != 1) || p_value->Invisible())\n\t\tp_value = p_value->CopyValues();\n\t\n\t// Make sure we have capacity\n\tif (p_symbol_name >= capacity_)\n\t\t_ResizeToFitSymbol(p_symbol_name);\n\t\n\t// Define the symbol if it is not already defined above us\n\tif (!slots_[p_symbol_name].symbol_value_SP_)\n\t{\n\t\t// The symbol is not already defined in this table.  Before we can define it, we need to check that it is not a constant in a chained table.\n\t\tbool is_const;\n\t\t\n\t\tif (chain_symbol_table_ && chain_symbol_table_->ContainsSymbol_IsConstant(p_symbol_name, &is_const))\n\t\t\tif (is_const)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::SetValueForSymbol): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// set the value into the unused slot and add it to the front of the linked list\n\t\tslots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t\tslots_[p_symbol_name].next_ = slots_[0].next_;\n\t\tslots_[0].next_ = p_symbol_name;\n\t}\n\telse\n\t{\n\t\t// set the value into the already used slot; no linked list maintenance needed\n\t\tslots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t}\n}\n\nvoid EidosSymbolTable::SetValueForSymbolNoCopy(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::SetValueForSymbolNoCopy(): symbol table change\");\n\t\n\t// So, this is a little weird.  SetValueForSymbol() copies the passed value, as explained in its comment above.\n\t// If a few cases, however, we want to play funny games and prevent that copy from occurring so that we can munge\n\t// values directly inside a value we just set in the symbol table.  Evaluate_For() is the worst offender in this\n\t// because it wants to set up an index variable once and then munge its value directly each time through the loop,\n\t// for speed.  For that special purpose, this function is provided.\n\t//\n\t// DO NOT USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!  It can lead to seriously weird behavior if used incorrectly.\n\tif (p_value->Invisible())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::SetValueForSymbolNoCopy): (internal) no copy requested with invisible value.\" << EidosTerminate(nullptr);\n\t\n\t// Make sure we have capacity\n\tif (p_symbol_name >= capacity_)\n\t\t_ResizeToFitSymbol(p_symbol_name);\n\t\n\t// Define the symbol if it is not already defined above us\n\tif (!slots_[p_symbol_name].symbol_value_SP_)\n\t{\n\t\t// The symbol is not already defined in this table.  Before we can define it, we need to check that it is not defined in a chained table.\n\t\t// At present, we assume that if it is defined in a chained table it is a constant, which is true for now.\n\t\tbool is_const;\n\t\t\n\t\tif (chain_symbol_table_ && chain_symbol_table_->ContainsSymbol_IsConstant(p_symbol_name, &is_const))\n\t\t\tif (is_const)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::SetValueForSymbolNoCopy): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// set the value into the unused slot and add it to the front of the linked list\n\t\tslots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t\tslots_[p_symbol_name].next_ = slots_[0].next_;\n\t\tslots_[0].next_ = p_symbol_name;\n\t}\n\telse\n\t{\n\t\t// set the value into the already used slot; no linked list maintenance needed\n\t\tslots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t}\n}\n\nvoid EidosSymbolTable::DefineConstantForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::DefineConstantForSymbol(): symbol table change\");\n\t\n\t// First make sure this symbol is not in use as either a variable or a constant\n\t// We use SymbolDefinedAnywhere() because defined constants cannot conflict with any symbol defined anywhere, whether\n\t// currently in scope or not – as soon as the conflicting scope comes into scope, the conflict will be manifest.\n\tstd::string symbol_string = EidosStringRegistry::StringForGlobalStringID(p_symbol_name);\n\t\n\tif (SymbolDefinedAnywhere(p_symbol_name))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbol): identifier '\" << symbol_string << \"' is already defined.\" << EidosTerminate(nullptr);\n\tif (!Eidos_GoodSymbolForDefine(symbol_string))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbol): identifier '\" << symbol_string << \"' is reserved, and cannot be used for a global constant.\" << EidosTerminate(nullptr);\n\t\n\t// Search through our chain for a defined constants table; if we don't find one, add one\n\tEidosSymbolTable *definedConstantsTable;\n\t\n\tfor (definedConstantsTable = this; definedConstantsTable != nullptr; definedConstantsTable = definedConstantsTable->chain_symbol_table_)\n\t\tif (definedConstantsTable->table_type_ == EidosSymbolTableType::kEidosDefinedConstantsTable)\n\t\t\tbreak;\n\t\n\tif (!definedConstantsTable)\n\t{\n\t\t// Find the child of the intrinsic constants table, which should be a global variables table; it should not be a local variables table, because there should\n\t\t// always be a global variables table above any local variables table; this is important, because local variables tables are transient, and we need the child\n\t\t// of the intrinsic constants table to end up being the owner of the defined constants table\n\t\tEidosSymbolTable *childTable;\n\t\t\n\t\tfor (childTable = this; childTable != nullptr; childTable = childTable->parent_symbol_table_)\n\t\t\tif (childTable->parent_symbol_table_ && childTable->parent_symbol_table_->table_type_ == EidosSymbolTableType::kEidosIntrinsicConstantsTable)\n\t\t\t\tbreak;\n\t\t\n\t\tif (!childTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbol): (internal) could not find child symbol table of the intrinsic constants table.\" << EidosTerminate(nullptr);\n\t\tif (childTable->table_type_ != EidosSymbolTableType::kGlobalVariablesTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbol): (internal) the child symbol table of the intrinsic constants table must be a global variables table.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosSymbolTable *intrinsicConstantsTable = childTable->parent_symbol_table_;\n\t\t\n\t\t// Make a defined constants table and insert it in between; this table will be\n\t\t// owned by childTable, which will free it whenever childTable is destructed\n\t\tdefinedConstantsTable = new EidosSymbolTable(EidosSymbolTableType::kEidosDefinedConstantsTable, intrinsicConstantsTable);\n\t\tchildTable->parent_symbol_table_ = definedConstantsTable;\n\t\tchildTable->parent_symbol_table_owned_ = true;\n\t\tchildTable->chain_symbol_table_ = definedConstantsTable;\n\t\t\n\t\t// There may be intervening tables that chain up to the intrinsic constants table;\n\t\t// they need to be fixed to now chain up to the defined constants table instead.\n\t\tEidosSymbolTable *patchTable;\n\t\t\n\t\tfor (patchTable = this; patchTable != definedConstantsTable; patchTable = patchTable->parent_symbol_table_)\n\t\t\tif (patchTable->chain_symbol_table_ == intrinsicConstantsTable)\n\t\t\t\tpatchTable->chain_symbol_table_ = definedConstantsTable;\n\t}\n\t\n\t// If we have the only reference to the value, we don't need to copy it; otherwise we copy, since we don't want to hold\n\t// onto a reference that somebody else might modify under us (or that we might modify under them, with syntaxes like\n\t// x[2]=...; and x=x+1;). If the value is invisible then we copy it, since the symbol table never stores invisible values.\n\tif ((p_value->UseCount() != 1) || p_value->Invisible())\n\t\tp_value = p_value->CopyValues();\n\t\n\t// Now we have a private value, which we can mark as constant\n\tp_value->MarkAsConstant();\n\t\n\t// Then ask the defined constants table to add the constant\n\tdefinedConstantsTable->InitializeConstantSymbolEntry(p_symbol_name, std::move(p_value));\n}\n\nvoid EidosSymbolTable::DefineConstantForSymbolNoCopy(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::DefineConstantForSymbolNoCopy(): symbol table change\");\n\t\n\t// So, this is a little weird.  DefineConstantForSymbol() copies the passed value, as explained in its comment above.\n\t// If a few cases, however, we want to play funny games and prevent that copy from occurring so that we can munge\n\t// values directly inside a value we just set in the symbol table.  Evaluate_For() is the worst offender in this\n\t// because it wants to set up an index variable once and then munge its value directly each time through the loop,\n\t// for speed.  For that special purpose, this function is provided.\n\t//\n\t// DO NOT USE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!  It can lead to seriously weird behavior if used incorrectly.\n\tif (p_value->Invisible())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbolNoCopy): (internal) no copy requested with invisible value.\" << EidosTerminate(nullptr);\n\t\n\t// First make sure this symbol is not in use as either a variable or a constant\n\t// We use SymbolDefinedAnywhere() because defined constants cannot conflict with any symbol defined anywhere, whether\n\t// currently in scope or not – as soon as the conflicting scope comes into scope, the conflict will be manifest.\n\tstd::string symbol_string = EidosStringRegistry::StringForGlobalStringID(p_symbol_name);\n\t\n\tif (SymbolDefinedAnywhere(p_symbol_name))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbolNoCopy): identifier '\" << symbol_string << \"' is already defined.\" << EidosTerminate(nullptr);\n\tif (!Eidos_GoodSymbolForDefine(symbol_string))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbolNoCopy): identifier '\" << symbol_string << \"' is reserved, and cannot be used for a global constant.\" << EidosTerminate(nullptr);\n\t\n\t// Search through our chain for a defined constants table; if we don't find one, add one\n\tEidosSymbolTable *definedConstantsTable;\n\t\n\tfor (definedConstantsTable = this; definedConstantsTable != nullptr; definedConstantsTable = definedConstantsTable->chain_symbol_table_)\n\t\tif (definedConstantsTable->table_type_ == EidosSymbolTableType::kEidosDefinedConstantsTable)\n\t\t\tbreak;\n\t\n\tif (!definedConstantsTable)\n\t{\n\t\t// Find the child of the intrinsic constants table, which should be a global variables table; it should not be a local variables table, because there should\n\t\t// always be a global variables table above any local variables table; this is important, because local variables tables are transient, and we need the child\n\t\t// of the intrinsic constants table to end up being the owner of the defined constants table\n\t\tEidosSymbolTable *childTable;\n\t\t\n\t\tfor (childTable = this; childTable != nullptr; childTable = childTable->parent_symbol_table_)\n\t\t\tif (childTable->parent_symbol_table_ && childTable->parent_symbol_table_->table_type_ == EidosSymbolTableType::kEidosIntrinsicConstantsTable)\n\t\t\t\tbreak;\n\t\t\n\t\tif (!childTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbolNoCopy): (internal) could not find child symbol table of the intrinsic constants table.\" << EidosTerminate(nullptr);\n\t\tif (childTable->table_type_ != EidosSymbolTableType::kGlobalVariablesTable)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineConstantForSymbolNoCopy): (internal) the child symbol table of the intrinsic constants table must be a global variables table.\" << EidosTerminate(nullptr);\n\t\t\n\t\tEidosSymbolTable *intrinsicConstantsTable = childTable->parent_symbol_table_;\n\t\t\n\t\t// Make a defined constants table and insert it in between; this table will be\n\t\t// owned by childTable, which will free it whenever childTable is destructed\n\t\tdefinedConstantsTable = new EidosSymbolTable(EidosSymbolTableType::kEidosDefinedConstantsTable, intrinsicConstantsTable);\n\t\tchildTable->parent_symbol_table_ = definedConstantsTable;\n\t\tchildTable->parent_symbol_table_owned_ = true;\n\t\tchildTable->chain_symbol_table_ = definedConstantsTable;\n\t\t\n\t\t// There may be intervening tables that chain up to the intrinsic constants table;\n\t\t// they need to be fixed to now chain up to the defined constants table instead.\n\t\tEidosSymbolTable *patchTable;\n\t\t\n\t\tfor (patchTable = this; patchTable != definedConstantsTable; patchTable = patchTable->parent_symbol_table_)\n\t\t\tif (patchTable->chain_symbol_table_ == intrinsicConstantsTable)\n\t\t\t\tpatchTable->chain_symbol_table_ = definedConstantsTable;\n\t}\n\t\n\t// Now we have a private value, which we can mark as constant\n\tp_value->MarkAsConstant();\n\t\n\t// Then ask the defined constants table to add the constant\n\tdefinedConstantsTable->InitializeConstantSymbolEntry(p_symbol_name, std::move(p_value));\n}\n\nvoid EidosSymbolTable::DefineGlobalForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::DefineGlobalForSymbol(): symbol table change\");\n\t\n\tstd::string symbol_string = EidosStringRegistry::StringForGlobalStringID(p_symbol_name);\n\tbool is_constant = false;\n\t\n\tif (SymbolDefinedAnywhere_IsConstant(p_symbol_name, &is_constant))\n\t\tif (is_constant)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineGlobalForSymbol): identifier '\" << symbol_string << \"' is already defined as a constant.\" << EidosTerminate(nullptr);\n\tif (!Eidos_GoodSymbolForDefine(symbol_string))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineGlobalForSymbol): identifier '\" << symbol_string << \"' is reserved, and cannot be used for a global variable.\" << EidosTerminate(nullptr);\n\t\n\t// First find the global variables table\n\tEidosSymbolTable *global_variables_table = this;\n\t\n\twhile (global_variables_table && (global_variables_table->table_type_ != EidosSymbolTableType::kGlobalVariablesTable))\n\t\tglobal_variables_table = global_variables_table->chain_symbol_table_;\n\t\n\tif (!global_variables_table)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineGlobalForSymbol): (internal error) a global variables symbol table does not exist.\" << EidosTerminate(nullptr);\n\t\n\t// If we have the only reference to the value, we don't need to copy it; otherwise we copy, since we don't want to hold\n\t// onto a reference that somebody else might modify under us (or that we might modify under them, with syntaxes like\n\t// x[2]=...; and x=x+1;). If the value is invisible then we copy it, since the symbol table never stores invisible values.\n\tif ((p_value->UseCount() != 1) || p_value->Invisible())\n\t\tp_value = p_value->CopyValues();\n\t\n\t// Make sure we have capacity; note this acts on global_variables_table, not this\n\tif (p_symbol_name >= global_variables_table->capacity_)\n\t\tglobal_variables_table->_ResizeToFitSymbol(p_symbol_name);\n\t\n\t// Define the symbol if it is not already defined above us\n\tif (!global_variables_table->slots_[p_symbol_name].symbol_value_SP_)\n\t{\n\t\t// The symbol is not already defined in global_variables_table.  Before we can define it, we need to check that it is\n\t\t// not a constant in a chained table (from this, not from global_variables_table, since constants tables might intervene).\n\t\tbool is_const;\n\t\t\n\t\tif (chain_symbol_table_ && chain_symbol_table_->ContainsSymbol_IsConstant(p_symbol_name, &is_const))\n\t\t\tif (is_const)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineGlobalForSymbol): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// set the value into the unused slot and add it to the front of the linked list; note this acts on global_variables_table, not this\n\t\tglobal_variables_table->slots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t\tglobal_variables_table->slots_[p_symbol_name].next_ = global_variables_table->slots_[0].next_;\n\t\tglobal_variables_table->slots_[0].next_ = p_symbol_name;\n\t}\n\telse\n\t{\n\t\t// set the value into the already used slot; no linked list maintenance needed\n\t\t\n\t\t// this is the one place where SymbolTable is aware of the IsIteratorVariable() flag, because\n\t\t// we need to prevent a conflict at the global level, which is hard to do in external code.\n\t\t// Consider this check to have been done by the caller, in terms of API semantics.\n\t\tif (global_variables_table->slots_[p_symbol_name].symbol_value_SP_->IsIteratorVariable())\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::DefineGlobalForSymbol): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' cannot be redefined because it is a constant.\" << EidosTerminate(nullptr);\n\t\t\n\t\tglobal_variables_table->slots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\t}\n}\n\nvoid EidosSymbolTable::_RemoveSymbol(EidosGlobalStringID p_symbol_name, bool p_remove_constant)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::_RemoveSymbol(): symbol table change\");\n\t\n\tif (p_symbol_name < capacity_)\n\t{\n\t\tEidosSymbolTableSlot *slot = slots_ + p_symbol_name;\n\t\t\n\t\tif (slot->symbol_value_SP_)\n\t\t{\n\t\t\t// We found the symbol in ourselves, so remove it unless we are a constant table\n\t\t\tif (table_type_is_constant_)\n\t\t\t{\n\t\t\t\tif (table_type_ == EidosSymbolTableType::kEidosIntrinsicConstantsTable)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_RemoveSymbol): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' is an intrinsic Eidos constant and thus cannot be removed.\" << EidosTerminate(nullptr);\n\t\t\t\tif (!p_remove_constant)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_RemoveSymbol): identifier '\" << EidosStringRegistry::StringForGlobalStringID(p_symbol_name) << \"' is a constant and thus cannot be removed.\" << EidosTerminate(nullptr);\n\t\t\t}\n\t\t\t\n\t\t\tslot->symbol_value_SP_.reset();\n\t\t\t\n\t\t\t// Now we need to fix the linked list, which is O(n): we have to find the previous entry that points to this entry\n\t\t\tEidosGlobalStringID index = 0;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tEidosSymbolTableSlot *search_slot = slots_ + index;\n\t\t\t\tEidosGlobalStringID search_next = search_slot->next_;\n\t\t\t\t\n\t\t\t\tif (search_next == p_symbol_name)\n\t\t\t\t{\n\t\t\t\t\tsearch_slot->next_ = slot->next_;\n\t\t\t\t\tslot->next_ = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tindex = search_next;\n\t\t\t}\n\t\t\twhile (index != 0);\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t}\n\t\n\t// If it wasn't defined in us, then it might be defined in the chain\n\tif (chain_symbol_table_)\n\t\tchain_symbol_table_->_RemoveSymbol(p_symbol_name, p_remove_constant);\n}\n\nvoid EidosSymbolTable::_InitializeConstantSymbolEntry(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosSymbolTable::_InitializeConstantSymbolEntry(): symbol table change\");\n\t\n#if DEBUG\n\tif (p_value->Invisible())\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_InitializeConstantSymbolEntry): (internal error) this method should be called only for non-invisible objects.\" << EidosTerminate(nullptr);\n\tif (!table_type_is_constant_)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::_InitializeConstantSymbolEntry): (internal error) this method should be called only on constant symbol tables.\" << EidosTerminate(nullptr);\n#endif\n\t\n\t// Make sure we have capacity\n\tif (p_symbol_name >= capacity_)\n\t\t_ResizeToFitSymbol(p_symbol_name);\n\t\n\t// We assume that this symbol is not yet defined, for maximal set-up speed\n\tslots_[p_symbol_name].symbol_value_SP_ = std::move(p_value);\n\tslots_[p_symbol_name].next_ = slots_[0].next_;\n\tslots_[0].next_ = p_symbol_name;\n}\n\nvoid EidosSymbolTable::PrintSymbolTable(std::ostream &p_outstream)\n{\n\tp_outstream << \"EidosSymbolTable \" << this << \" : \";\n\t\n\tswitch (table_type_)\n\t{\n\t\tcase EidosSymbolTableType::kEidosIntrinsicConstantsTable: p_outstream << \"kEidosIntrinsicConstantsTable\"; break;\n\t\tcase EidosSymbolTableType::kEidosDefinedConstantsTable: p_outstream << \"kEidosDefinedConstantsTable\"; break;\n\t\tcase EidosSymbolTableType::kGlobalVariablesTable: p_outstream << \"kGlobalVariablesTable\"; break;\n\t\tcase EidosSymbolTableType::kContextConstantsTable: p_outstream << \"kContextConstantsTable\"; break;\n\t\tcase EidosSymbolTableType::kLocalVariablesTable: p_outstream << \"kLocalVariablesTable\"; break;\n\t\tcase EidosSymbolTableType::kINVALID_TABLE_TYPE:\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosSymbolTable::PrintSymbolTable): (internal error) invalid table type.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tp_outstream << (table_type_is_constant_ ? \" (constant)\" : \" (not constant)\") << std::endl;\n\t\n\tfor (EidosGlobalStringID symbol = slots_->next_; symbol != 0; symbol = (slots_ + symbol)->next_)\n\t{\n\t\tconst std::string &symbol_name = EidosStringRegistry::StringForGlobalStringID(symbol);\n\t\tEidosValue *symbol_value = (slots_ + symbol)->symbol_value_SP_.get();\n\t\tint symbol_count = symbol_value->Count();\n\t\t\n\t\tif (symbol_count <= 2)\n\t\t\tp_outstream << \"   \" << symbol_name << (table_type_is_constant_ ? \" => (\" : \" -> (\") << symbol_value->Type() << \") \" << *symbol_value << std::endl;\n\t\telse\n\t\t{\n\t\t\tEidosValue_SP first_value = symbol_value->GetValueAtIndex(0, nullptr);\n\t\t\tEidosValue_SP second_value = symbol_value->GetValueAtIndex(1, nullptr);\n\t\t\t\n\t\t\tp_outstream << \"   \" << symbol_name << (table_type_is_constant_ ? \" => (\" : \" -> (\") << symbol_value->Type() << \") \" << *first_value << \" \" << *second_value << \" ... (\" << symbol_count << \" values)\" << std::endl;\n\t\t}\n\t}\n}\n\nvoid EidosSymbolTable::PrintSymbolTableChain(std::ostream &p_outstream)\n{\n\tp_outstream << \"================================================\" << std::endl;\n\tthis->PrintSymbolTable(p_outstream);\n\t\n\tEidosSymbolTable *next_in_chain = chain_symbol_table_;\n\t\n\twhile (next_in_chain)\n\t{\n\t\tp_outstream << \"------------------------------------------------\" << std::endl;\n\t\tnext_in_chain->PrintSymbolTable(p_outstream);\n\t\t\n\t\tnext_in_chain = next_in_chain->chain_symbol_table_;\n\t}\n\t\n\tp_outstream << \"------------------------------------------------\" << std::endl;\n\tp_outstream << \"END OF CHAIN\" << std::endl;\n\tp_outstream << \"================================================\" << std::endl;\n}\n\nvoid EidosSymbolTable::AddSymbolsToTypeTable(EidosTypeTable *p_type_table) const\n{\n\t// recurse to get the symbols from our chained symbol table\n\tif (chain_symbol_table_)\n\t\tchain_symbol_table_->AddSymbolsToTypeTable(p_type_table);\n\t\n\tfor (EidosGlobalStringID symbol = slots_->next_; symbol != 0; )\n\t{\n\t\tEidosSymbolTableSlot *slot = slots_ + symbol;\n\t\tEidosValue *symbol_value = slot->symbol_value_SP_.get();\n\t\tEidosValueType symbol_type = symbol_value->Type();\n\t\tEidosValueMask symbol_type_mask = (1 << (int)symbol_type);\n\t\tconst EidosClass *symbol_class = ((symbol_type == EidosValueType::kValueObject) ? ((EidosValue_Object *)symbol_value)->Class() : nullptr);\n\t\tEidosTypeSpecifier symbol_type_specifier = EidosTypeSpecifier{symbol_type_mask, symbol_class};\n\t\t\n\t\tp_type_table->SetTypeForSymbol(symbol, symbol_type_specifier);\n\t\tsymbol = slot->next_;\n\t}\n}\n\n// This stream output method for EidosSymbolTable dumps all available symbols\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosSymbolTable &p_symbols)\n{\n\tstd::vector<std::string> read_only_symbol_names = p_symbols.ReadOnlySymbols();\n\tstd::vector<std::string> read_write_symbol_names = p_symbols.ReadWriteSymbols();\n\tstd::vector<std::string> symbol_names;\n\t\n\tsymbol_names.insert(symbol_names.end(), read_only_symbol_names.begin(), read_only_symbol_names.end());\n\tsymbol_names.insert(symbol_names.end(), read_write_symbol_names.begin(), read_write_symbol_names.end());\n\tstd::sort(symbol_names.begin(), symbol_names.end());\n\t\n\tfor (const std::string &symbol_name : symbol_names)\n\t{\n\t\tEidosValue_SP symbol_value = p_symbols.GetValueOrRaiseForSymbol(EidosStringRegistry::GlobalStringIDForString(symbol_name));\n\t\tint symbol_count = symbol_value->Count();\n\t\tbool is_const = std::find(read_only_symbol_names.begin(), read_only_symbol_names.end(), symbol_name) != read_only_symbol_names.end();\n\t\t\n\t\tif (symbol_count <= 2)\n\t\t\tp_outstream << symbol_name << (is_const ? \" => (\" : \" -> (\") << symbol_value->Type() << \") \" << *symbol_value << std::endl;\n\t\telse\n\t\t{\n\t\t\tEidosValue_SP first_value = symbol_value->GetValueAtIndex(0, nullptr);\n\t\t\tEidosValue_SP second_value = symbol_value->GetValueAtIndex(1, nullptr);\n\t\t\t\n\t\t\tp_outstream << symbol_name << (is_const ? \" => (\" : \" -> (\") << symbol_value->Type() << \") \" << *first_value << \" \" << *second_value << \" ... (\" << symbol_count << \" values)\" << std::endl;\n\t\t}\n\t}\n\t\n\treturn p_outstream;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_symbol_table.h",
    "content": "//\n//  eidos_symbol_table.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/12/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n A symbol table is basically just a map of identifiers to EidosValue objects.  However, there are some additional smarts,\n particularly where speed is concerned.  The goal is to be able to both add symbols and look up symbols as fast as\n possible.  EidosValue objects are tracked with smart pointers for refcounting.  There are also optimizations for\n setting up a symbol table with standard constants and variables using globally allocated strings for speed.\n \n As per the recommendations at http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/ I have\n designed the API to take EidosValue_SP parameters when setting the value of a symbol.  This creates a new smart pointer,\n which takes shared ownership of the object at the point of the call.  These functions then use std::move internally\n to move the smart pointer into the symbol table's internal data structures.  If a caller wishes to surrender a temporary\n object to the symbol table, they should use std::move in their call, and if I understand C++11 correctly, move semantics\n will be used the whole way along and a refcount increment/decrement will not happen at all.  EidosValue_SP values are\n returned, too, rather than references, since the caller will be taking their shared ownership of the object.\n \n EidosSymbolTable does not use strings to identify symbols in practice, although conceptually it does.  In practice, it\n uses EidosGlobalStringID, which is an integer type that represents a uniqued string.  This allows greater speed, since\n strings get uniqued only once, and an integer key can be used from then onward.\n\n EidosSymbolTable stores symbols internally in a lookup table by uniqued string id, allowing O(1) lookup.  Setting values\n is also O(1) thanks to the lookup table; we just need to set the value in the right slot, plus a bit of bookkeeping to\n track which indices have been set so that we can clear them later.\n \n */\n\n#ifndef __Eidos__eidos_symbol_table__\n#define __Eidos__eidos_symbol_table__\n\n#include <iostream>\n#include <vector>\n#include <string>\n\n#include \"eidos_value.h\"\n#include \"eidos_ast_node.h\"\n\nclass EidosSymbolTable;\nclass EidosTypeTable;\n\n\n// This is a shared global symbol table containing the standard Eidos constants; it should be linked to as a parent symbol table\nextern EidosSymbolTable *gEidosConstantsSymbolTable;\n\n\n// This is used by InitializeConstantSymbolEntry() for fast setup / teardown\ntypedef std::pair<EidosGlobalStringID, EidosValue_SP> EidosSymbolTableEntry;\n\n\n// Used by EidosSymbolTable for the slots in its lookup table.  The lookup table is a data structure that as\n// far as I know doesn't have a name; it was designed to fit the symbol table's purpose here.  Basically, we\n// want a reuseable table that can be quickly set up with values, quickly cleared back to an empty state, and\n// quickly queried.  The solution is to keep defined values in slots in the lookup table, indexed by the id\n// of the uniqued symbol name, *and* to keep a linked list running through the used slots so we can find them\n// quickly.  The result is a very sparsely populated table, with zeros at all undefined slots, that we can\n// set a new value into in O(1), query a value in O(1), and clear back to an unused state in O(n) where n is\n// the number of defined slots.  Slot 0 of the table, corresponding to gEidosID_none (which should never have\n// a value associated with it), provides the index of the first defined entry (or 0 if the table is empty).\n// New entries are added at the beginning of the list.  The only slow operation is removing a single defined\n// value, which is O(n) because we don't have a prev_ pointer, but that is a rare operation.\ntypedef struct {\n\tEidosValue_SP symbol_value_SP_;\t\t\t// our shared pointer to the EidosValue for the symbol\n\tuint32_t next_;\t\t\t\t\t\t\t// the index of the next symbol that has been defined\n} EidosSymbolTableSlot;\n\n\n// Symbol tables can come in various types.  This is mostly hidden from clients of this class.  The intrinsic\n// constants table holds Eidos constants like T, F, INF, and NAN.  The defined constants table, which should be\n// the direct child of the intrinsic table, holds constants defined by the user with DefineConstantForSymbol().\n// The context constants table is used by the Context for its own constants; SLiM uses it for constants like\n// sim, p1, g1, m1, s1, etc.  Finally, the variables tables contain all user-defined variables.  This linked-list\n// design for the symbol table makes it easy to throw out variables while keeping constants, to differentiate\n// between different responsibilities for constants without having to keep a tag for each defined symbol, etc.\n// Clients of this class can just use the symbol table they have a reference to, which will generally be a\n// variables table at the end of the chain.  Only clients that are constructing or destructing a symbol table\n// setup need to know about these types and how they are supposed to interact.\n\n// BCH 9/10/2017: Note that now, in Eidos 1.5, it is legal to have more than one variables table at the end.\n// These represent nested function calls; when a new function call starts, a new table is added to the top, and\n// when a function call ends that table is removed.  The outer variable scopes are hidden; searches for values\n// will go from the bottommost variables table directly up to the first constants table in the chain.\n\n// BCH 10/27/2020: Now, in Eidos 2.5, the scoping rules have changed a bit: there is now a \"global variables\"\n// scope that contains any globals that are defined.  In Eidos you are normally in the global scope, and so\n// there will generally be one of these, in place of the kVariablesTable that would have existed before.  In\n// SLiM you are generally inside some sub-scope, and the global variables table exists above you, but is often\n// empty.\nenum class EidosSymbolTableType\n{\n\tkEidosIntrinsicConstantsTable = 0,\t// just one of these\n\tkEidosDefinedConstantsTable,\t\t// and just one of these\n\tkGlobalVariablesTable,\t\t\t\t// and zero or one of these; can be in among the context constants tables\n\tkContextConstantsTable,\t\t\t\t// then there can be any number of these\n\tkLocalVariablesTable,\t\t\t\t// and finally, any number of these, for nested function calls\n\tkINVALID_TABLE_TYPE\t\t\t\t\t// used as a sort of zombie marker in an attempt to increase code safety\n};\n\n\nclass EidosSymbolTable\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\nprivate:\n\t\n\tEidosSymbolTableType table_type_;\n\tbool table_type_is_constant_;\t\t// based on table_type_\n\t\n\tEidosSymbolTableSlot *slots_;\t\t// a lookup table indexed by EidosGlobalStringID (uint32_t); see EidosSymbolTableSlot\n\tuint32_t capacity_;\t\t\t\t\t// the capacity of the lookup table (max id value, not max number of variables)\n\t\n\t// Symbol tables can be chained.  This is invisible to the user; there appears to be a single global symbol table for a given\n\t// interpreter, which responds to all requests.  Behind the scenes, however, requests get passed up the symbol table chain\n\t// until a hit is found or the last symbol table declares a miss.  Adds go in the symbol table that receives the request.\n\t// BCH 10 Sept 2017: With the addition of user-defined functions, this gets a little more complex.  The chain_symbol_table_\n\t// ivar represents the next symbol table in the search chain from this table (skipping over the variables tables belonging\n\t// to callers up the chain, since they are not in scope).  The parent_symbol_table_ ivar is the next symbol table upward –\n\t// either the caller or the first constants table – but it is not used for much since scoped searching is usually desired.\n\tEidosSymbolTable *chain_symbol_table_ = nullptr;\t// NOT OWNED\n\tEidosSymbolTable *parent_symbol_table_ = nullptr;\t// NOT OWNED unless the parent_symbol_table_owned_ flag is set\n\tbool parent_symbol_table_owned_ = false;\t\t\t// set to true if we own our parent table, which would be a defined-constants table\n\t\n\t// Utility methods called by the public methods to do the real work\n\tstd::vector<std::string> _SymbolNames(bool p_include_constants, bool p_include_variables) const;\n\tEidosValue_SP _GetValue(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const;\n\tEidosValue_SP _GetValue_SpecialRaise(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const;\n\tEidosValue *_GetValue_RAW(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token) const;\n\tEidosValue_SP _GetValue_IsConstIsLocal(EidosGlobalStringID p_symbol_name, const EidosToken *p_symbol_token, bool *p_is_const, bool *p_is_local) const;\n\tvoid _RemoveSymbol(EidosGlobalStringID p_symbol_name, bool p_remove_constant);\n\tvoid _InitializeConstantSymbolEntry(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\n\tvoid _ResizeToFitSymbol(EidosGlobalStringID p_symbol_name);\n\t\npublic:\n\t\n\tEidosSymbolTable(const EidosSymbolTable&) = delete;\t\t\t\t\t\t\t\t\t\t\t\t\t// no copying\n\tEidosSymbolTable& operator=(const EidosSymbolTable&) = delete;\t\t\t\t\t\t\t\t\t\t// no copying\n\texplicit EidosSymbolTable(EidosSymbolTableType p_table_type, EidosSymbolTable *p_parent_table);\t\t// standard constructor\n\t~EidosSymbolTable(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// destructor\n\t\n\t// symbol access; these are variables defined in the global namespace\n\tinline __attribute__((always_inline)) std::vector<std::string> ReadOnlySymbols(void) const { return _SymbolNames(true, false); }\n\tinline __attribute__((always_inline)) std::vector<std::string> ReadWriteSymbols(void) const { return _SymbolNames(false, true); }\n\tinline __attribute__((always_inline)) std::vector<std::string> AllSymbols(void) const { return _SymbolNames(true, true); }\n\t\n\t// Test for containing a value for a symbol; ContainsSymbol() searches through the chain of symbol tables that are in scope, whereas\n\t// SymbolDefinedAnywhere() looks through all parent tables regardless of scope.\n\tbool ContainsSymbol(EidosGlobalStringID p_symbol_name) const;\n\tbool ContainsSymbol_IsConstant(EidosGlobalStringID p_symbol_name, bool *p_is_const) const;\n\tbool SymbolDefinedAnywhere(EidosGlobalStringID p_symbol_name) const;\n\tbool SymbolDefinedAnywhere_IsConstant(EidosGlobalStringID p_symbol_name, bool *p_is_const) const;\n\t\n\t// Set as a variable (raises if already defined as a constant)\n\tvoid SetValueForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\n\tvoid SetValueForSymbolNoCopy(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\t\t\t// *not* what you want, almost certainly\n\t\n\t// Set as a constant (raises if already defined as a variable or a constant); adds to the kEidosDefinedConstantsTable, creating it if necessary\n\tvoid DefineConstantForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\n\tvoid DefineConstantForSymbolNoCopy(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\t// *not* what you want, almost certainly\n\t\n\t// Set as a global (raises if already defined as a constant); adds to the kGlobalVariablesTable, or raises if that does not exist\n\tvoid DefineGlobalForSymbol(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value);\n\t\n\t// Remove symbols; RemoveValueForSymbol() will raise if the symbol is a constant.  RemoveConstantForSymbol() is\n\t// not used in Eidos itself, but SLiM uses it when script blocks, subpopulations, species, etc. cease to exist.\n\tinline __attribute__((always_inline)) void RemoveValueForSymbol(EidosGlobalStringID p_symbol_name) { _RemoveSymbol(p_symbol_name, false); }\n\tinline __attribute__((always_inline)) void RemoveConstantForSymbol(EidosGlobalStringID p_symbol_name) { _RemoveSymbol(p_symbol_name, true); }\n\t\n\t// Get a value, with an optional token used if the call raises due to an undefined symbol\n\tinline __attribute__((always_inline)) EidosValue_SP GetValueOrRaiseForASTNode(const EidosASTNode *p_symbol_node) const { return _GetValue(p_symbol_node->cached_stringID_, p_symbol_node->token_); }\n\tinline __attribute__((always_inline)) EidosValue_SP GetValueOrRaiseForASTNode_SpecialRaise(const EidosASTNode *p_symbol_node) const { return _GetValue_SpecialRaise(p_symbol_node->cached_stringID_, p_symbol_node->token_); }\n\tinline __attribute__((always_inline)) EidosValue_SP GetValueOrRaiseForSymbol(EidosGlobalStringID p_symbol_name) const { return _GetValue(p_symbol_name, nullptr); }\n\t\n\t// Get a value, with an optional token used if the call raises due to an undefined symbol; these variants return an unwrapped EidosValue *\n\t// These should be used only when the caller needs the symbol for temporary use and will be able to know not to free the value after use\n\tinline __attribute__((always_inline)) EidosValue *GetValueRawOrRaiseForASTNode(const EidosASTNode *p_symbol_node) const { return _GetValue_RAW(p_symbol_node->cached_stringID_, p_symbol_node->token_); }\n\tinline __attribute__((always_inline)) EidosValue *GetValueRawOrRaiseForSymbol(EidosGlobalStringID p_symbol_name) const { return _GetValue_RAW(p_symbol_name, nullptr); }\n\t\n\t// Special getters that return a boolean flag, true if the fetched symbol is a constant\n\tinline __attribute__((always_inline)) EidosValue_SP GetValueOrRaiseForASTNode_IsConstIsLocal(const EidosASTNode *p_symbol_node, bool *p_is_const, bool *p_is_local) const { return _GetValue_IsConstIsLocal(p_symbol_node->cached_stringID_, p_symbol_node->token_, p_is_const, p_is_local); }\n\tinline __attribute__((always_inline)) EidosValue_SP GetValueOrRaiseForSymbol_IsConstIsLocal(EidosGlobalStringID p_symbol_name, bool *p_is_const, bool *p_is_local) const { return _GetValue_IsConstIsLocal(p_symbol_name, nullptr, p_is_const, p_is_local); }\n\t\n\t// Special-purpose methods used for fast setup of new symbol tables with constants.\n\t//\n\t// These methods assume (1) that the name string is a global constant that does not need to be copied and\n\t// has infinite lifespan, and (2) that the EidosValue passed in is not invisible and is thus suitable for\n\t// direct use in the symbol table; no copy will be made of the value.  These are not general-purpose methods,\n\t// they are specifically for the very specialized init case of setting up a table with standard entries.\n\t//\n\t// Note that this method does *not* require that the value itself is marked as a constant, nor does this\n\t// method mark it as such; this mechanism relies upon the table's designation as a constants table to\n\t// enforce constness.  This provides a small window through which the user could potentially modify a value\n\t// in a constants table, if (a) the value is not marked as a constant, and (b) it is set directly in the\n\t// table through these methods, rather than through DefineConstantForSymbol().  If it is possible to do,\n\t// I have not yet found the way to do it, though, because assignment and subset-assignment both check that\n\t// the symbol table for the variable being modified is not a constants table.  If new methods are added\n\t// that are also capable of modifying values in place, however, they will need to check the table type,\n\t// not just the IsConstant() property of the value, which is not guaranteed to be set in all cases!  See\n\t// eidos_value.h for further discussion of how EidosValue constness is managed internally.\n\tinline __attribute__((always_inline)) void InitializeConstantSymbolEntry(EidosSymbolTableEntry &p_new_entry) { _InitializeConstantSymbolEntry(p_new_entry.first, p_new_entry.second); }\n\tinline __attribute__((always_inline)) void InitializeConstantSymbolEntry(EidosGlobalStringID p_symbol_name, EidosValue_SP p_value) { _InitializeConstantSymbolEntry(p_symbol_name, std::move(p_value)); }\n\t\n\t// Utility methods for printing a symbol table and, for PrintSymbolTableChain(), its parents; note these are different from operator<<\n\tvoid PrintSymbolTable(std::ostream &p_outstream);\n\tvoid PrintSymbolTableChain(std::ostream &p_outstream);\n\t\n\t// A utility method to add entries for defined symbols into an EidosTypeTable\n\tvoid AddSymbolsToTypeTable(EidosTypeTable *p_type_table) const;\n\t\n\t// Direct access to the symbol table chain.  This should only be necessary for clients that are manipulating\n\t// the symbol table chain themselves in some way, since normally the chain is encapsulated by this class.\n\tinline __attribute__((always_inline)) EidosSymbolTable *ChainSymbolTable(void) { return chain_symbol_table_; }\n\tinline __attribute__((always_inline)) EidosSymbolTable *ParentSymbolTable(void) { return parent_symbol_table_; }\n\tinline __attribute__((always_inline)) EidosSymbolTableType TableType(void) { return table_type_; }\n\n\tfriend size_t MemoryUsageForSymbolTables(EidosSymbolTable *p_currentTable);\n};\n\n// Print all symbols available from a given table (and its parents), in sorted form\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosSymbolTable &p_symbols);\n\n// Memory usage tallying, for outputUsage()\nsize_t MemoryUsageForSymbolTables(EidosSymbolTable *p_currentTable);\n\n// Cleanup for Valgrind\nvoid FreeSymbolTablePool(void);\n\n\n#endif /* defined(__Eidos__eidos_symbol_table__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test.cpp",
    "content": "//\n//  eidos_test.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n#include \"eidos_script.h\"\n#include \"eidos_value.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_globals.h\"\n#include \"eidos_rng.h\"\n#include \"eidos_sorting.h\"\n\n#include <stdlib.h>\n#include <iostream>\n#include <string>\n#include <vector>\n#include <stdexcept>\n#include <limits>\n#include <random>\n#include <ctime>\n#include <algorithm>\n\n#if 0\n// includes for the timing code in RunEidosTests(), which is normally #if 0\n#include \"sys/time.h\"\t// for gettimeofday()\n#include <chrono>\n#if defined(__APPLE__) && defined(__MACH__)\n#include <mach/mach_time.h>\n#endif\n#endif\n\n\n// Keeping records of test success / failure\nint gEidosTestSuccessCount = 0;\nint gEidosTestFailureCount = 0;\n\n\n// Instantiates and runs the script, and prints an error if the result does not match expectations\nvoid EidosAssertScriptSuccess(const std::string &p_script_string, const EidosValue_SP &p_correct_result)\n{\n\t{\n\tEidosScript script(p_script_string);\n\tEidosValue_SP result;\n\tEidosSymbolTable symbol_table(EidosSymbolTableType::kGlobalVariablesTable, gEidosConstantsSymbolTable);\n\t\n\tgEidosErrorContext.currentScript = &script;\n\t\n\tgEidosTestFailureCount++;\t// assume failure; we will fix this at the end if we succeed\n\t\n\ttry {\n\t\tscript.Tokenize();\n\t}\n\tcatch (...)\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during Tokenize(): \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\n\t\tClearErrorContext();\n\t\treturn;\n\t}\n\t\n\ttry {\n\t\tscript.ParseInterpreterBlockToAST(true);\n\t}\n\tcatch (...)\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during ParseToAST(): \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\n\t\tClearErrorContext();\n\t\treturn;\n\t}\n\t\n\ttry {\n\t\tEidosFunctionMap function_map(*EidosInterpreter::BuiltInFunctionMap());\n\t\tstd::ostringstream black_hole;\n\t\tEidosInterpreter interpreter(script, symbol_table, function_map, nullptr, black_hole, black_hole\n#ifdef SLIMGUI\n\t\t\t, true\n#endif\n\t\t\t);\n\t\t\n\t\tresult = interpreter.EvaluateInterpreterBlock(true, true);\t\t// print output, return the last statement value\n\t}\n\tcatch (...)\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during EvaluateInterpreterBlock(): \" << Eidos_GetTrimmedRaiseMessage() << std::endl;\n\t\t\n\t\tClearErrorContext();\n\t\treturn;\n\t}\n\t\n\t// Check that the result is actually what we want it to be\n\tif (!result)\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : return value is nullptr\" << std::endl;\n\t}\n\telse if (result->Type() != p_correct_result->Type())\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : unexpected return type (\" << result->Type() << \", expected \" << p_correct_result->Type() << \")\" << std::endl;\n\t}\n\telse if (result->ElementType() != p_correct_result->ElementType())\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : unexpected return element type (\" << result->ElementType() << \", expected \" << p_correct_result->ElementType() << \")\" << std::endl;\n\t}\n\telse if (result->Count() != p_correct_result->Count())\n\t{\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : unexpected return length (\" << result->Count() << \", expected \" << p_correct_result->Count() << \")\" << std::endl;\n\t}\n\t//else if (result->DimensionCount() != 1)\n\t//{\n\t//\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : matrix or array returned, which is not tested; use identical()\" << std::endl;\n\t//}\n\telse\n\t{\n\t\tif (!IdenticalEidosValues(result.get(), p_correct_result.get(), false))\t\t// don't compare dimensions; we have no easy way to specify matrix/array results\n\t\t{\n\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : mismatched values (\" << *result << \"), expected (\" << *p_correct_result << \")\" << std::endl;\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tgEidosTestFailureCount--;\t// correct for our assumption of failure above\n\t\tgEidosTestSuccessCount++;\n\t\t\n\t\t//std::cerr << p_script_string << \" == \" << p_correct_result->Type() << \"(\" << *p_correct_result << \") : \" << EIDOS_OUTPUT_SUCCESS_TAG << endl;\n\t}\n\t\n\tClearErrorContext();\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\tstd::cerr << \"WARNING (EidosAssertScriptSuccess): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\nvoid EidosAssertScriptSuccess_L(const std::string &p_script_string, eidos_logical_t p_logical)\n{\n\tEidosAssertScriptSuccess(p_script_string, p_logical == true ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n}\n\nvoid EidosAssertScriptSuccess_VOID(const std::string &p_script_string)\n{\n\tEidosAssertScriptSuccess(p_script_string, gStaticEidosValueVOID);\n}\n\nvoid EidosAssertScriptSuccess_NULL(const std::string &p_script_string)\n{\n\tEidosAssertScriptSuccess(p_script_string, gStaticEidosValueNULL);\n}\n\nvoid EidosAssertScriptSuccess_LV(const std::string &p_script_string, std::initializer_list<eidos_logical_t> p_logical_vec)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical(p_logical_vec)));\n}\n\nvoid EidosAssertScriptSuccess_I(const std::string &p_script_string, int64_t p_integer)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(p_integer)));\n}\n\nvoid EidosAssertScriptSuccess_IV(const std::string &p_script_string, std::initializer_list<int64_t> p_integer_vec)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(p_integer_vec)));\n}\n\nvoid EidosAssertScriptSuccess_F(const std::string &p_script_string, double p_float)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(p_float)));\n}\n\nvoid EidosAssertScriptSuccess_FV(const std::string &p_script_string, std::initializer_list<double> p_float_vec)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(p_float_vec)));\n}\n\nvoid EidosAssertScriptSuccess_S(const std::string &p_script_string, const char *p_string)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(p_string)));\n}\n\nvoid EidosAssertScriptSuccess_SV(const std::string &p_script_string, std::initializer_list<const char *> p_string_vec)\n{\n\tEidosAssertScriptSuccess(p_script_string, EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(p_string_vec)));\n}\n\n// Instantiates and runs the script, and prints an error if the script does not cause an exception to be raised\nvoid EidosAssertScriptRaise(const std::string &p_script_string, const int p_bad_position, const char *p_reason_snip)\n{\n\t{\n\tstd::string reason_snip(p_reason_snip);\n\tEidosScript script(p_script_string);\n\tEidosSymbolTable symbol_table(EidosSymbolTableType::kGlobalVariablesTable, gEidosConstantsSymbolTable);\n\tEidosFunctionMap function_map(*EidosInterpreter::BuiltInFunctionMap());\n\t\n\tgEidosErrorContext.currentScript = &script;\n\t\n\ttry {\n\t\tscript.Tokenize();\n\t\tscript.ParseInterpreterBlockToAST(true);\n\t\t\n\t\tstd::ostringstream black_hole;\n\t\tEidosInterpreter interpreter(script, symbol_table, function_map, nullptr, black_hole, black_hole\n#ifdef SLIMGUI\n\t\t\t, true\n#endif\n\t\t\t);\n\t\t\n\t\tEidosValue_SP result = interpreter.EvaluateInterpreterBlock(true, true);\t\t// print output, return the last statement value\n\t\t\n\t\tgEidosTestFailureCount++;\n\t\t\n\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : no raise during EvaluateInterpreterBlock().\" << std::endl;\n\t}\n\tcatch (...)\n\t{\n\t\t// We need to call Eidos_GetTrimmedRaiseMessage() here to empty the error stringstream, even if we don't log the error\n\t\tstd::string raise_message = Eidos_GetTrimmedRaiseMessage();\n\t\t\n\t\tif (raise_message.find(reason_snip) != std::string::npos)\n\t\t{\n\t\t\tif ((gEidosErrorContext.errorPosition.characterStartOfError == -1) ||\n\t\t\t\t(gEidosErrorContext.errorPosition.characterEndOfError == -1))\n\t\t\t{\n\t\t\t\tgEidosTestFailureCount++;\n\t\t\t\t\n\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise expected, but no error info set\" << std::endl;\n\t\t\t\tstd::cerr << p_script_string << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t}\n\t\t\telse if (gEidosErrorContext.errorPosition.characterStartOfError != p_bad_position)\n\t\t\t{\n\t\t\t\tgEidosTestFailureCount++;\n\t\t\t\t\n\t\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise expected, but error position unexpected\" << std::endl;\n\t\t\t\tstd::cerr << p_script_string << \"   raise message: \" << raise_message << std::endl;\n\t\t\t\tEidos_LogScriptError(std::cerr, gEidosErrorContext);\n\t\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tgEidosTestSuccessCount++;\n\t\t\t\t\n\t\t\t\t//std::cerr << p_script_string << \" == (expected raise) \" << raise_message << \" : \" << EIDOS_OUTPUT_SUCCESS_TAG << endl;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\t\n\t\t\tstd::cerr << p_script_string << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise message mismatch (expected \\\"\" << reason_snip << \"\\\").\" << std::endl;\n\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t\tstd::cerr << \"--------------------\" << std::endl << std::endl;\n\t\t}\n\t\t\n\t\t// Error messages that say (internal error) should not be possible to trigger in script\n\t\tif (raise_message.find(\"(internal error)\") != std::string::npos)\n\t\t{\n\t\t\tstd::cerr << p_script_string << \" : error message contains (internal error) erroneously\" << std::endl;\n\t\t\tstd::cerr << \"   raise message: \" << raise_message << std::endl;\n\t\t}\n\t}\n\t\n\tClearErrorContext();\n\t\n\tif (gEidos_DictionaryNonRetainReleaseReferenceCounter > 0)\n\t\tstd::cerr << \"WARNING (EidosAssertScriptRaise): gEidos_DictionaryNonRetainReleaseReferenceCounter == \" << gEidos_DictionaryNonRetainReleaseReferenceCounter << \" at end of test!\" << std::endl;\n\t}\n\t\n\tgEidos_DictionaryNonRetainReleaseReferenceCounter = 0;\n}\n\nint RunEidosTests(void)\n{\n\t// This function should never be called when parallel, but individual tests are allowed to go parallel internally\n\tTHREAD_SAFETY_IN_ANY_PARALLEL(\"RunEidosTests(): illegal when parallel\");\n\t\n\t// Reset error counts\n\tgEidosTestSuccessCount = 0;\n\tgEidosTestFailureCount = 0;\n\t\n#if (!EIDOS_HAS_OVERFLOW_BUILTINS)\n\tstd::cout << \"WARNING: This build of Eidos does not detect integer arithmetic overflows.  Compiling Eidos with GCC version 5.0 or later, or Clang version 3.9 or later, is required for this feature.  This means that integer addition, subtraction, or multiplication that overflows the 64-bit range of Eidos (\" << INT64_MIN << \" to \" << INT64_MAX << \") will not be detected.\" << std::endl;\n#endif\n\t\n\tif (!Eidos_TemporaryDirectoryExists())\n\t\tstd::cout << \"WARNING: This system does not appear to have a writeable temporary directory.  Filesystem tests are disabled, and functions such as writeTempFile() and system() that depend upon the existence of the temporary directory will raise an exception if called (and are therefore also not tested).  Other self-tests that rely on writing temporary files, such as of readCSV() and Image, will also be disabled.  If this is surprising, contact the system administrator for details.\" << std::endl;\n\t\n\t// We want to run the self-test inside a new temporary directory, to prevent collisions with other self-test runs\n\tstd::string prefix = Eidos_TemporaryDirectory() + \"eidosTest_\";\n\tstd::string temp_path_template = prefix + \"XXXXXX\";\n\tchar *temp_path_cstr = strdup(temp_path_template.c_str());\n\t\n\tif (Eidos_mkstemps_directory(temp_path_cstr, 0) == 0)\n\t{\n\t\t//std::cout << \"Running Eidos self-tests in \" << temp_path_cstr << \" ...\" << std::endl;\n\t}\n\telse\n\t{\n\t\tstd::cout << \"A folder within the temporary directory could not be created; there may be a permissions problem with the temporary directory.  The self-test could not be run.\" << std::endl;\n\t\treturn 1;\n\t}\n\t\n\tstd::string temp_path(temp_path_cstr);\t// the final random path generated by Eidos_mkstemps_directory\n\tfree(temp_path_cstr);\n\t\n\t// Run tests\n\t_RunFloatOutputTests();\n\t_RunInternalFilesystemTests();\n\t_RunLiteralsIdentifiersAndTokenizationTests();\n\t_RunSymbolsAndVariablesTests();\n\t_RunParsingTests();\n\t_RunFunctionDispatchTests();\n\t_RunRuntimeErrorTests();\n\t_RunVectorsAndSingletonsTests();\n\t_RunOperatorPlusTests1();\n\t_RunOperatorPlusTests2();\n\t_RunOperatorMinusTests();\n\t_RunOperatorMultTests();\n\t_RunOperatorDivTests();\n\t_RunOperatorModTests();\n\t_RunOperatorSubsetTests();\n\t_RunOperatorAssignTests();\n\t_RunOperatorGtTests();\n\t_RunOperatorLtTests();\n\t_RunOperatorGtEqTests();\n\t_RunOperatorLtEqTests();\n\t_RunOperatorEqTests();\n\t_RunOperatorNotEqTests();\n\t_RunOperatorRangeTests();\n\t_RunOperatorExpTests();\n\t_RunOperatorLogicalAndTests();\n\t_RunOperatorLogicalOrTests();\n\t_RunOperatorLogicalNotTests();\n\t_RunOperatorTernaryConditionalTests();\n\t_RunKeywordIfTests();\n\t_RunKeywordDoTests();\n\t_RunKeywordWhileTests();\n\t_RunKeywordForInTests();\n\t_RunKeywordNextTests();\n\t_RunKeywordBreakTests();\n\t_RunKeywordReturnTests();\n\t_RunFunctionMathTests_a_through_f();\n\t_RunFunctionMathTests_g_through_r();\n\t_RunFunctionMathTests_setUnionIntersection();\n\t_RunFunctionMathTests_setDifferenceSymmetricDifference();\n\t_RunFunctionMathTests_s_through_z();\n\t_RunSIMDMathTests();\n\t_RunFunctionMatrixArrayTests();\n\t_RunFunctionStatisticsTests_a_through_p();\n\t_RunFunctionStatisticsTests_q_through_z();\n\t_RunFunctionDistributionTests();\n\t_RunFunctionVectorConstructionTests_a_through_r();\n\t_RunFunctionVectorConstructionTests_s_through_z();\n\t_RunFunctionValueInspectionManipulationTests_a_through_f();\n\t_RunFunctionValueInspectionManipulationTests_g_through_l();\n\t_RunFunctionValueInspectionManipulationTests_m_through_r();\n\t_RunFunctionValueInspectionManipulationTests_s_through_z();\n\t_RunStringManipulationTests();\n\t_RunFunctionValueTestingCoercionTests();\n\t_RunFunctionFilesystemTests(temp_path);\n\t_RunColorManipulationTests();\n\t_RunFunctionMiscTests_apply_sapply();\n\t_RunFunctionMiscTests(temp_path);\n\t_RunClassTests(temp_path);\n\t_RunCodeExampleTests();\n\t_RunUserDefinedFunctionTests();\n\t_RunVoidEidosValueTests();\n\t\n\t// ************************************************************************************\n\t//\n\t//\tPrint a summary of test results\n\t//\n\tstd::cerr << std::endl;\n\tif (gEidosTestFailureCount)\n\t\tstd::cerr << \"\" << EIDOS_OUTPUT_FAILURE_TAG << \" count: \" << gEidosTestFailureCount << std::endl;\n\tstd::cerr << EIDOS_OUTPUT_SUCCESS_TAG << \" count: \" << gEidosTestSuccessCount << std::endl;\n\t\n\t// If we are tracking allocations, print a count\n#ifdef EIDOS_TRACK_VALUE_ALLOCATION\n\tstd::cerr << \"EidosValue allocation count: \" << EidosValue::valueTrackingCount << std::endl;\n\tfor (EidosValue *value : EidosValue::valueTrackingVector)\n\t\tstd::cerr << *value << endl;\n#endif\n\t\n\t// Do some tests of our custom math functions\n#if 0\n\tEidos_SetRNGSeed(Eidos_GenerateRNGSeed());\n\t\n\tint64_t totals[17];\t\t// note 17 is prime\n\t\n\tfor (int i = 0; i < 17; ++i)\n\t\ttotals[i] = 0;\n\t\n\tfor (int i = 0; i < 100000000; ++i)\n\t\ttotals[Eidos_rng_uniform_int(EIDOS_GSL_RNG, 17)]++;\n\t\n\tfor (int i = 0; i < 17; ++i)\n\t\tstd::cout << \"totals[\" << i << \"] == \" << totals[i] << std::endl;\n#endif\n\t\n#if 0\n\t//#ifndef USE_GSL_POISSON\n\tEidos_SetRNGSeed(Eidos_GenerateRNGSeed());\n\t\n\tdouble total;\n\tint i;\n\t\n\tstd::cout << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(1.0);\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(1.0): mean = \" << (total / 1000000) << \", expected 1.0\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 1.0);\n\t\n\tstd::cout << \"gsl_ran_poisson(1.0): mean = \" << (total / 1000000) << \", expected 1.0\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(0.001);\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(0.001): mean = \" << (total / 1000000) << \", expected 0.001\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 0.001);\n\t\n\tstd::cout << \"gsl_ran_poisson(0.001): mean = \" << (total / 1000000) << \", expected 0.001\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(0.00001);\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(0.00001): mean = \" << (total / 1000000) << \", expected 0.00001\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 0.00001);\n\t\n\tstd::cout << \"gsl_ran_poisson(0.00001): mean = \" << (total / 1000000) << \", expected 0.00001\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(100);\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(100): mean = \" << (total / 100000) << \", expected 100\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 100);\n\t\n\tstd::cout << \"gsl_ran_poisson(100): mean = \" << (total / 100000) << \", expected 100\" << std::endl << std::endl;\n\t\n\t\n\tstd::cout << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(1.0, exp(-1.0));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(1.0): mean = \" << (total / 1000000) << \", expected 1.0\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 1.0);\n\t\n\tstd::cout << \"gsl_ran_poisson(1.0): mean = \" << (total / 1000000) << \", expected 1.0\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(0.001, exp(-0.001));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(0.001): mean = \" << (total / 1000000) << \", expected 0.001\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 0.001);\n\t\n\tstd::cout << \"gsl_ran_poisson(0.001): mean = \" << (total / 1000000) << \", expected 0.001\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(0.00001, exp(-0.00001));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(0.00001): mean = \" << (total / 1000000) << \", expected 0.00001\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 0.00001);\n\t\n\tstd::cout << \"gsl_ran_poisson(0.00001): mean = \" << (total / 1000000) << \", expected 0.00001\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t\ttotal += Eidos_FastRandomPoisson(100, exp(-100));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(100): mean = \" << (total / 100000) << \", expected 100\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, 100);\n\t\n\tstd::cout << \"gsl_ran_poisson(100): mean = \" << (total / 100000) << \", expected 100\" << std::endl << std::endl;\n\t\n\t\n\tstd::cout << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson_NONZERO(1.0, exp(-1.0));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(1.0): mean = \" << (total / 1000000) << \", expected ~1.58\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t{\n\t\tunsigned int x;\n\t\t\n\t\tdo {\n\t\t\tx = gsl_ran_poisson(EIDOS_GSL_RNG, 1.0);\n\t\t} while (x == 0);\n\t\t\n\t\ttotal += x;\n\t}\n\t\n\tstd::cout << \"gsl_ran_poisson(1.0): mean = \" << (total / 1000000) << \", expected ~1.58\" << std::endl << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson_NONZERO(0.001, exp(-0.001));\n\t\n\tstd::cout << \"Eidos_FastRandomPoisson(0.001): mean = \" << (total / 1000000) << \", expected ~1.0005\" << std::endl;\n\t\n\t//\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t//\t{\n\t//\t\tunsigned int x;\n\t//\t\t\n\t//\t\tdo {\n\t//\t\t\tx = gsl_ran_poisson(EIDOS_GSL_RNG, 0.001);\n\t//\t\t} while (x == 0);\n\t//\t\t\n\t//\t\ttotal += x;\n\t//\t}\n\t//\t\n\t//\tstd::cout << \"gsl_ran_poisson(0.001): mean = \" << (total / 1000000) << \", expected ~1.0005\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t\ttotal += Eidos_FastRandomPoisson_NONZERO(0.00001, exp(-0.00001));\n\t\n\tstd::cout << std::endl << \"Eidos_FastRandomPoisson(0.00001): mean = \" << (total / 1000000) << \", expected ~1.00001\" << std::endl;\n\t\n\t//\tfor (total = 0.0, i = 0; i < 1000000; i++)\n\t//\t{\n\t//\t\tunsigned int x;\n\t//\t\t\n\t//\t\tdo {\n\t//\t\t\tx = gsl_ran_poisson(EIDOS_GSL_RNG, 0.00001);\n\t//\t\t} while (x == 0);\n\t//\t\t\n\t//\t\ttotal += x;\n\t//\t}\n\t//\t\n\t//\tstd::cout << \"gsl_ran_poisson(0.00001): mean = \" << (total / 1000000) << \", expected ~1.00001\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t\ttotal += Eidos_FastRandomPoisson_NONZERO(100, exp(-100));\n\t\n\tstd::cout << std::endl << \"Eidos_FastRandomPoisson(100): mean = \" << (total / 100000) << \", expected ~100\" << std::endl;\n\t\n\tfor (total = 0.0, i = 0; i < 100000; i++)\n\t{\n\t\tunsigned int x;\n\t\t\n\t\tdo {\n\t\t\tx = gsl_ran_poisson(EIDOS_GSL_RNG, 100);\n\t\t} while (x == 0);\n\t\t\n\t\ttotal += x;\n\t}\n\t\n\tstd::cout << \"gsl_ran_poisson(100): mean = \" << (total / 100000) << \", expected ~100\" << std::endl << std::endl;\n\t\n#endif\n\t\n#if 0\n\t// Speed tests of gsl_ran_poisson() vs. Eidos_FastRandomPoisson()\n\t// When built with optimization, this indicates that (on my present machine) the GSL's method\n\t// starts to be faster at about mu > 250, so we will cross over at that point.\n\tfor (int iteration = 0; iteration <= 19; ++iteration)\n\t{\n\t\tdouble mu = 0, exp_neg_mu;\n\t\t\n\t\tif (iteration == 0) mu = 0.1;\n\t\tif (iteration == 1) mu = 0.4;\n\t\tif (iteration == 2) mu = 1.0;\n\t\tif (iteration == 3) mu = 4.0;\n\t\tif (iteration == 4) mu = 10.0;\n\t\tif (iteration == 5) mu = 40.0;\n\t\tif (iteration == 6) mu = 100.0;\n\t\tif (iteration == 7) mu = 200.0;\n\t\tif (iteration == 8) mu = 220.0;\n\t\tif (iteration == 9) mu = 240.0;\n\t\tif (iteration == 10) mu = 260.0;\n\t\tif (iteration == 11) mu = 280.0;\n\t\tif (iteration == 12) mu = 300.0;\n\t\tif (iteration == 13) mu = 400.0;\n\t\tif (iteration == 14) mu = 500.0;\n\t\tif (iteration == 15) mu = 600.0;\n\t\tif (iteration == 16) mu = 700.0;\n\t\tif (iteration == 17) mu = 1000.0;\n\t\tif (iteration == 18) mu = 10000.0;\n\t\tif (iteration == 19) mu = 100000.0;\n\t\t\n\t\texp_neg_mu = Eidos_FastRandomPoisson_PRECALCULATE(mu);\n\t\t\n\t\tfor (int type = 0; type <= 2; ++type)\n\t\t{\n\t\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\tdouble total = 0.0;\n\t\t\t\n\t\t\tif (type == 0)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < 1000000; i++)\n\t\t\t\t\ttotal += Eidos_FastRandomPoisson(mu);\n\t\t\t}\n\t\t\telse if (type == 1)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < 1000000; i++)\n\t\t\t\t\ttotal += Eidos_FastRandomPoisson(mu, exp_neg_mu);\n\t\t\t}\n\t\t\telse if (type == 2)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < 1000000; i++)\n\t\t\t\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, mu);\n\t\t\t}\n\t\t\t\n\t\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\t\n\t\t\tstd::cout << \"mu \" << mu << \" T \" << type << \": total = \" << total << \", time == \" << (end_time - start_time) << std::endl;\n\t\t}\n\t}\n#endif\n\t\n#if 0\n\t// Speed tests of gsl_rng_uniform_int() / Eidos_rng_uniform_int() / Eidos_rng_uniform_int_MT64 / C++'s MT64\n\t// The use of total here is a thunk to force the compiler not to optimize away any work\n\t// Results (12 May 2018, Release build):\n\t//\n\t//\t\tgsl_rng_uniform_int(): time == 18.5712, total == 249506669929\n\t//\t\tEidos_rng_uniform_int(): time == 2.83272, total == 249504929021\n\t//\t\tEidos_rng_uniform_int_MT64(): time == 3.28454, total == 249512506686\n\t//\t\tstd::mt19937_64: time == 16.9182, total == 249496346730\n\t//\n\t// So Eidos_rng_uniform_int_MT64() is only marginally slower than Eidos_rng_uniform_int(), whereas the\n\t// straight GSL and C++ RNGs are much slower.  The straight GSL is not inlined; I'm not sure why the C++\n\t// MT64 is so slow.\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tint64_t total = 0;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 1000000000; ++iteration)\n\t\t\ttotal += gsl_rng_uniform_int(EIDOS_GSL_RNG, 500);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << std::endl << \"gsl_rng_uniform_int(): time == \" << (end_time - start_time) << \", total == \" << total << std::endl;\n\t}\n\t\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tint64_t total = 0;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 1000000000; ++iteration)\n\t\t\ttotal += Eidos_rng_uniform_int(EIDOS_GSL_RNG, 500);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"Eidos_rng_uniform_int(): time == \" << (end_time - start_time) << \", total == \" << total << std::endl;\n\t}\n\t\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tint64_t total = 0;\n\t\tinit_genrand64(0);\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 1000000000; ++iteration)\n\t\t\ttotal += Eidos_rng_uniform_int_MT64(500);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"Eidos_rng_uniform_int_MT64(): time == \" << (end_time - start_time) << \", total == \" << total << std::endl;\n\t}\n\t\n\t{\n\t\tstd::random_device rd;\n\t\tstd::mt19937_64 e2(rd());\n\t\tstd::uniform_int_distribution<long long int> dist(0, 499);\n\t\tint64_t total = 0;\n\t\t\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 1000000000; ++iteration)\n\t\t\ttotal += dist(e2);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"std::mt19937_64: time == \" << (end_time - start_time) << \", total == \" << total << std::endl;\n\t}\n#endif\n\t\n#if 0\n\t// Speed tests of gsl_rng_uniform() versus Eidos_rng_uniform()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 100000000; ++iteration)\n\t\t\tgsl_rng_uniform(EIDOS_GSL_RNG);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << std::endl << \"gsl_rng_uniform(): time == \" << (end_time - start_time) << std::endl;\n\t}\n\t\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 100000000; ++iteration)\n\t\t\tEidos_rng_uniform(EIDOS_GSL_RNG);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"Eidos_rng_uniform(): time == \" << (end_time - start_time) << std::endl;\n\t}\n#endif\n\t\n#if 0\n\t// Speed tests of gsl_rng_uniform_pos() versus Eidos_rng_uniform_pos()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 100000000; ++iteration)\n\t\t\tgsl_rng_uniform_pos(EIDOS_GSL_RNG);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << std::endl << \"gsl_rng_uniform_pos(): time == \" << (end_time - start_time) << std::endl;\n\t}\n\t\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tfor (int64_t iteration = 0; iteration < 100000000; ++iteration)\n\t\t\tEidos_rng_uniform_pos(EIDOS_GSL_RNG);\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"Eidos_rng_uniform_pos(): time == \" << (end_time - start_time) << std::endl;\n\t}\n#endif\n\t\n#if 0\n\t{\n\t\t// Test that our inline, modified version of taus_get() is equivalent to the GSL's taus_get()\n\t\tunsigned long int *gsl_taus, *eidos_taus, *mixed_taus;\n\t\tint iter;\n\t\t\n\t\tgsl_taus = (unsigned long int *)malloc(100000 * sizeof(unsigned long int));\n\t\teidos_taus = (unsigned long int *)malloc(100000 * sizeof(unsigned long int));\n\t\tmixed_taus = (unsigned long int *)malloc(100000 * sizeof(unsigned long int));\n\t\t\n\t\tEidos_SetRNGSeed(10);\n\t\t\n\t\tfor (iter = 0; iter < 100000; ++iter)\n\t\t\tgsl_taus[iter] = gsl_rng_get(EIDOS_GSL_RNG);\n\t\t\n\t\tEidos_SetRNGSeed(10);\n\t\t\n\t\tfor (iter = 0; iter < 100000; ++iter)\n\t\t\teidos_taus[iter] = taus_get_inline(EIDOS_GSL_RNG->state);\n\t\t\n\t\tEidos_SetRNGSeed(10);\n\t\t\n\t\tfor (iter = 0; iter < 50000; ++iter)\n\t\t{\n\t\t\tmixed_taus[iter * 2] = gsl_rng_get(EIDOS_GSL_RNG);\n\t\t\tmixed_taus[iter * 2 + 1] = taus_get_inline(EIDOS_GSL_RNG->state);\n\t\t}\n\t\t\n\t\tfor (iter = 0; iter < 50000; ++iter)\n\t\t{\n\t\t\tunsigned long int a = gsl_taus[iter];\n\t\t\tunsigned long int b = eidos_taus[iter];\n\t\t\tunsigned long int c = mixed_taus[iter];\n\t\t\t\n\t\t\tif ((a != b) || (b != c))\n\t\t\t{\n\t\t\t\tstd::cout << std::endl << \"RNG mismatch: a == \" << a << \", b == \" << b << \", c == \" << c << \".\" << std::endl;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (iter == 50000)\n\t\t\tstd::cout << std::endl << \"RNGs match.\" << std::endl;\n\t\t\n\t\tfree(gsl_taus);\n\t\tfree(eidos_taus);\n\t\tfree(mixed_taus);\n\t}\n#endif\n\t\n#if 0\n\t// Speed tests of different timing methods; we need a very fast method for profiling\n\t// Note that the total_time variables are meaningless; they are just thunks to force the code to include the overhead of understanding the results of the calls\n\t\n\t// clock()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t\ttotal_time += std::clock();\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to std::clock(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / CLOCKS_PER_SEC) << std::endl;\n\t}\n\t\n\t// gettimeofday()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timeval timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tgettimeofday(&timer, NULL);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000 + timer.tv_usec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to gettimeofday(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime(CLOCK_REALTIME, ...)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timespec timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tclock_gettime(CLOCK_REALTIME, &timer);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000000 + timer.tv_nsec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime(CLOCK_REALTIME, ...): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime(CLOCK_MONOTONIC_RAW, ...)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timespec timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tclock_gettime(CLOCK_MONOTONIC_RAW, &timer);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000000 + timer.tv_nsec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime(CLOCK_MONOTONIC_RAW, ...): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime(CLOCK_UPTIME_RAW, ...)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timespec timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tclock_gettime(CLOCK_UPTIME_RAW, &timer);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000000 + timer.tv_nsec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime(CLOCK_UPTIME_RAW, ...): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timespec timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tclock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timer);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000000 + timer.tv_nsec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tstruct timespec timer;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\tclock_gettime(CLOCK_THREAD_CPUTIME_ID, &timer);\n\t\t\t\n\t\t\ttotal_time += ((int64_t)timer.tv_sec) * 1000000000 + timer.tv_nsec;\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// std::chrono::high_resolution_clock::now()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\t__attribute__((unused)) auto timer = std::chrono::high_resolution_clock::now();\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to std::chrono::high_resolution_clock::now(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime_nsec_np(CLOCK_REALTIME)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += clock_gettime_nsec_np(CLOCK_REALTIME);\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime_nsec_np(CLOCK_REALTIME): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime_nsec_np(CLOCK_UPTIME_RAW)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += clock_gettime_nsec_np(CLOCK_UPTIME_RAW);\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime_nsec_np(CLOCK_UPTIME_RAW): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID);\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID)\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID);\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n#if defined(__APPLE__) && defined(__MACH__)\n\t// mach_absolute_time()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += mach_absolute_time();\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to mach_absolute_time(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t// mach_continuous_time()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += mach_continuous_time();\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to mach_continuous_time(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n#endif\n\t\n\t// Eidos_ProfileTime()\n\t{\n\t\tdouble start_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\tuint64_t total_time = 0;\n\t\t\n\t\tfor (int i = 0; i < 10000000; ++i)\n\t\t{\n\t\t\ttotal_time += Eidos_ProfileTime();\n\t\t}\n\t\t\n\t\tdouble end_time = static_cast<double>(std::clock()) / CLOCKS_PER_SEC;\n\t\t\n\t\tstd::cout << \"10000000 calls to Eidos_ProfileTime(): time == \" << (end_time - start_time) << \", total_time == \" << (total_time / 1000000000.0) << std::endl;\n\t}\n\t\n\t/*\n\t \n\t Results:\n\t \n\t 10000000 calls to clock(): time == 3.69977, total_time == 22539996\n\t 10000000 calls to gettimeofday(): time == 0.427816, total_time == 5.16001e+12\n\t 10000000 calls to clock_gettime(CLOCK_REALTIME, ...): time == 0.434227, total_time == -5.07085e+09\n\t 10000000 calls to clock_gettime(CLOCK_MONOTONIC_RAW, ...): time == 0.46535, total_time == -8.45659e+09\n\t 10000000 calls to clock_gettime(CLOCK_UPTIME_RAW, ...): time == 0.41903, total_time == -8.45214e+09\n\t 10000000 calls to clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...): time == 3.53099, total_time == 7.62471e+07\n\t 10000000 calls to clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...): time == 1.66773, total_time == 1.01822e+08\n\t 10000000 calls to std::chrono::high_resolution_clock::now(): time == 0.423068, total_time == 0\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_REALTIME): time == 0.424018, total_time == 1.34453e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW): time == 0.415543, total_time == 1.00593e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_UPTIME_RAW): time == 0.357498, total_time == 1.00631e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID): time == 3.51726, total_time == 1.44264e+08\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID): time == 1.62355, total_time == 1.69689e+08\n\t 10000000 calls to mach_absolute_time(): time == 0.203174, total_time == 1.01174e+10\n\t 10000000 calls to mach_continuous_time(): time == 0.2646, total_time == 1.01197e+10\n\t 10000000 calls to Eidos_ProfileTime(): time == 0.20364, total_time == 1.0122e+10\n\n\t 10000000 calls to clock(): time == 3.6669, total_time == 21594595\n\t 10000000 calls to gettimeofday(): time == 0.420807, total_time == 5.16038e+12\n\t 10000000 calls to clock_gettime(CLOCK_REALTIME, ...): time == 0.4383, total_time == -4.70372e+09\n\t 10000000 calls to clock_gettime(CLOCK_MONOTONIC_RAW, ...): time == 0.46461, total_time == -8.08945e+09\n\t 10000000 calls to clock_gettime(CLOCK_UPTIME_RAW, ...): time == 0.413183, total_time == -8.08511e+09\n\t 10000000 calls to clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...): time == 3.49895, total_time == 7.45271e+07\n\t 10000000 calls to clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...): time == 1.66718, total_time == 1.00431e+08\n\t 10000000 calls to std::chrono::high_resolution_clock::now(): time == 0.419601, total_time == 0\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_REALTIME): time == 0.437738, total_time == 1.3812e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW): time == 0.416851, total_time == 1.04261e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_UPTIME_RAW): time == 0.355363, total_time == 1.043e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID): time == 3.53823, total_time == 1.42916e+08\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID): time == 1.64254, total_time == 1.68505e+08\n\t 10000000 calls to mach_absolute_time(): time == 0.203185, total_time == 1.04846e+10\n\t 10000000 calls to mach_continuous_time(): time == 0.248343, total_time == 1.04869e+10\n\t 10000000 calls to Eidos_ProfileTime(): time == 0.208794, total_time == 1.04892e+10\n\t \n\t 10000000 calls to clock(): time == 3.7723, total_time == 22027941\n\t 10000000 calls to gettimeofday(): time == 0.402914, total_time == 5.16072e+12\n\t 10000000 calls to clock_gettime(CLOCK_REALTIME, ...): time == 0.439594, total_time == -4.36005e+09\n\t 10000000 calls to clock_gettime(CLOCK_MONOTONIC_RAW, ...): time == 0.468783, total_time == -7.74572e+09\n\t 10000000 calls to clock_gettime(CLOCK_UPTIME_RAW, ...): time == 0.423101, total_time == -7.74128e+09\n\t 10000000 calls to clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...): time == 3.59922, total_time == 7.61285e+07\n\t 10000000 calls to clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...): time == 1.68519, total_time == 1.02508e+08\n\t 10000000 calls to std::chrono::high_resolution_clock::now(): time == 0.408809, total_time == 0\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_REALTIME): time == 0.431629, total_time == 1.41569e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW): time == 0.419269, total_time == 1.0771e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_UPTIME_RAW): time == 0.357072, total_time == 1.07748e+10\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID): time == 3.50717, total_time == 1.44766e+08\n\t 10000000 calls to clock_gettime_nsec_np(CLOCK_THREAD_CPUTIME_ID): time == 1.61161, total_time == 1.70191e+08\n\t 10000000 calls to mach_absolute_time(): time == 0.203799, total_time == 1.08289e+10\n\t 10000000 calls to mach_continuous_time(): time == 0.262729, total_time == 1.08312e+10\n\t 10000000 calls to Eidos_ProfileTime(): time == 0.201686, total_time == 1.08335e+10\n\n\t So mach_absolute_time() is the fastest, and also gives us the information in a convenient form.  It is only\n\t available on OS X, of course, but that is fine since we only offer profiling in SLiMgui.  I have therefore\n\t defined Eidos_ProfileTime() as using mach_absolute_time() in eidos_globals.h.\n\t \n\t */\n#endif\n\t\n#if 0\n\t{\n\t\t// Test Eidos_ExactSum() for correctness.  Seems to work; what do I know.  There is more rigorous test\n\t\t// code at http://code.activestate.com/recipes/393090/ but it assumes the existence of a correct\n\t\t// function to compare against, which we don't have.\n\t\tdouble *values = (double *)malloc(10000 * sizeof(double) * 4);\n\t\tdouble *vptr = values;\n\t\t\n\t\tfor (int64_t rep = 0; rep < 10000; rep++)\n\t\t{\n\t\t\t*(vptr++) = 1.0;\n\t\t\t*(vptr++) = 1.0e100;\n\t\t\t*(vptr++) = 1.0;\n\t\t\t*(vptr++) = -1.0e100;\n\t\t}\n\t\t\n\t\tdouble exact_sum = Eidos_ExactSum(values, 10000 * 4);\n\t\tdouble inexact_sum = 0.0;\n\t\t\n\t\tvptr = values;\n\t\tfor (int64_t index = 0; index < 10000 * 4; ++index)\n\t\t\tinexact_sum += *(vptr++);\n\t\t\n\t\tstd::cout << \"Inexact sum: \" << inexact_sum << std::endl;\n\t\tstd::cout << \"Exact sum: \" << exact_sum << std::endl;\n\t\t\n\t\tfree(values);\n\t}\n#endif\n\t\n#if 0\n\t// Speed comparison between Poisson and binomial draws in various parameter regimes, using the GSL's own code.\n\t// For doing things like drawing the number of recombination or mutation events that happen across a haplosome,\n\t// the binomial distribution is technically correct (# trials, probability per trial), but we have been using\n\t// the Poisson distribution because it is an extremely good approximation for the binomial in the regimes we\n\t// normally run in (e.g., chromosomes longer than ~100 sites, per-site probabilities less than 1e-3).  And\n\t// that is fine.  However, some people are using SLiM with parameters where the Poisson poorly approximates\n\t// the binomial (10 independent loci, i.e. 9 trials, 0.5 probability per trial), so we should switch.  The\n\t// question is: how big is the price of switching?  Poisson is nice because it is simple and fast; binomial\n\t// is complex and slow.  If the price is substantial, we might continue to use Poisson in the parameter\n\t// regime where it is safe, and switch to binomial only when necessary; but if the price is small, we'll just\n\t// switch to binomial always, for simplicity.\n\t\n\t// Regarding the Poisson approximation, https://www.itl.nist.gov/div898/handbook/pmc/section3/pmc331.htm says:\n\t// The sample size n should be equal to or larger than 20 and the probability of a single success, p, should\n\t// be smaller than or equal to 0.05. If n >= 100, the approximation is excellent if np is also <= 10.\n\t\n\t// The GSL, in binomial_tpe.c, has the following comment:\n\t//\n\t//\tNote, Bruce Schmeiser (personal communication) points out that if\n\t//\tyou want very fast binomial deviates, and you are happy with\n\t//\tapproximate results, and/or n and n*p are both large, then you can\n\t//\tjust use gaussian estimates: mean=n*p, variance=n*p*(1-p).\n\t//\n\t// And it turns out that the Gaussian approxiamtion is indeed as much as twice as fast as either of the other\n\t// methods, and is quite accurate under Schmeiser's stated conditions.  So we may want to use it; testing it.\n\t// Regarding this approximation, Wikipedia recommends that it be used when n > 9*(1-p)/p and n > 9*p/(1-p).\n\t\n\t// Upshot: I have encoded our rules for which distribution to prefer in the code below; the preference is\n\t// shown with asterisks.  Happily, this often coincides with the fastest version.  BCH 7 April 2018.\n\t{\n\t\tfor (int trial = 0; trial < 8*11; ++trial)\n\t\t{\n\t\t\tdouble p = 0.0;\n\t\t\tunsigned int n = 0;\n\t\t\t\n\t\t\tswitch (trial % 8)\n\t\t\t{\n\t\t\t\tcase 0: p = 0.5; break;\n\t\t\t\tcase 1: p = 0.1; break;\n\t\t\t\tcase 2: p = 0.01; break;\n\t\t\t\tcase 3: p = 0.001; break;\n\t\t\t\tcase 4: p = 0.0001; break;\n\t\t\t\tcase 5: p = 0.000001; break;\n\t\t\t\tcase 6: p = 0.00000001; break;\n\t\t\t\tcase 7: p = 0.0000000001; break;\n\t\t\t}\n\t\t\t\n\t\t\tswitch (trial / 8)\n\t\t\t{\n\t\t\t\tcase 0: n = 10; break;\n\t\t\t\tcase 1: n = 15; break;\n\t\t\t\tcase 2: n = 20; break;\n\t\t\t\tcase 3: n = 25; break;\n\t\t\t\tcase 4: n = 50; break;\n\t\t\t\tcase 5: n = 100; break;\n\t\t\t\tcase 6: n = 200; break;\n\t\t\t\tcase 7: n = 1000; break;\n\t\t\t\tcase 8: n = 10000; break;\n\t\t\t\tcase 9: n = 10000000; break;\n\t\t\t\tcase 10: n = 1000000000; break;\n\t\t\t}\n\t\t\t\n\t\t\tstd::cout << \"Case #\" << trial << \" (\" << n << \" trials, \" << p << \" probability):\" << std::endl;\n\t\t\t\n\t\t\t// decide which version will be used in SLiM\n\t\t\tint pref = 0;\n\t\t\tbool gaussian_allowed = ((n > 9 * (1-p) / p) && (n > 9 * p / (1-p)));\n\t\t\tbool poisson_allowed = ((p <= 0.01) && (n > 50));\n\t\t\t\n\t\t\tgaussian_allowed = false;\n\t\t\t\n\t\t\tif ((n >= 20) && gaussian_allowed)\t\t\t// Gaussian; (n >= 20) is because binomial is faster before then anyway\n\t\t\t\tpref = 3;\n\t\t\telse if ((n * p <= 1.0) && poisson_allowed)\t// Poisson; (n * p > 1.0) because binomial is faster before then anyway\n\t\t\t\tpref = 2;\n\t\t\telse\t\t\t\t\t\t\t\t\t\t// binomial\n\t\t\t\tpref = 1;\n\t\t\t\n\t\t\t{\n\t\t\t\tstd::clock_t begin = std::clock();\n\t\t\t\tint64_t total = 0;\n\t\t\t\t\n\t\t\t\tfor (int64_t i = 0; i < 20000000; i++)\n\t\t\t\t\ttotal += gsl_ran_binomial(EIDOS_GSL_RNG, p, n);\n\t\t\t\t\n\t\t\t\tdouble time_spent = static_cast<double>(clock() - begin) / CLOCKS_PER_SEC;\n\t\t\t\tstd::cout << ((pref == 1) ? \"***\" : \"   \");\n\t\t\t\tstd::cout << \"time for 20000000 calls to gsl_ran_binomial(): \" << time_spent << \" (total == \" << total << \")\" << std::endl;\n\t\t\t}\n\t\t\tif (poisson_allowed)\n\t\t\t{\n\t\t\t\tstd::clock_t begin = std::clock();\n\t\t\t\tint64_t total = 0;\n\t\t\t\t\n\t\t\t\tfor (int64_t i = 0; i < 20000000; i++)\n\t\t\t\t\ttotal += gsl_ran_poisson(EIDOS_GSL_RNG, p * n);\n\t\t\t\t\n\t\t\t\tdouble time_spent = static_cast<double>(clock() - begin) / CLOCKS_PER_SEC;\n\t\t\t\tstd::cout << ((pref == 2) ? \"***\" : \"   \");\n\t\t\t\tstd::cout << \"time for 20000000 calls to gsl_ran_poisson(): \" << time_spent << \" (total == \" << total << \")\" << std::endl;\n\t\t\t}\n\t\t\tif (gaussian_allowed)\n\t\t\t{\n\t\t\t\tstd::clock_t begin = std::clock();\n\t\t\t\tint64_t total = 0;\n\t\t\t\tdouble sd = sqrt(n * p * (1 - p));\n\t\t\t\t\n\t\t\t\tfor (int64_t i = 0; i < 20000000; i++)\n\t\t\t\t\ttotal += (int)round(gsl_ran_gaussian(EIDOS_GSL_RNG, sd) + p * n);\n\t\t\t\t\n\t\t\t\tdouble time_spent = static_cast<double>(clock() - begin) / CLOCKS_PER_SEC;\n\t\t\t\tstd::cout << ((pref == 3) ? \"***\" : \"   \");\n\t\t\t\tstd::cout << \"time for 20000000 calls to gsl_ran_gaussian(): \" << time_spent << \" (total == \" << total << \")\" << std::endl;\n\t\t\t}\n\t\t\tstd::cout << std::endl;\n\t\t}\n\t}\n#endif\n\t\n#if 0\n\t// Speed and correctness tests of various parallel sorting algorithms\n\t{\n\t\tstd::cout << std::endl << \"SORTING TESTS:\" << std::endl;\n\t\t\n\t\tgsl_rng *rng_gsl = EIDOS_GSL_RNG(omp_get_thread_num());\t\t// the single-threaded RNG\n\t\ttypedef std::string SORT_TYPE;\n\t\t\n\t\t{\n\t\t\t// use the appropriate comparator for the sort type, in the code below\n\t\t\t// note that Eidos_ParallelSort_Comparator() and Sriram_parallel_omp_sort() require a comparator,\n\t\t\t// whereas std::sort() defaults to ascending (op <) by default, and Eidos_ParallelSort() doesn't take one.\n\t\t\t//auto comparator_scalar = [](SORT_TYPE a, SORT_TYPE b) { return a < b; };\n\t\t\tauto comparator_string = [](const std::string &a, const std::string &b) { return a < b; };\n\t\t\t//auto comparator_double = [](const double& a, const double& b) { return std::isnan(b) || (a < b); };\t// needs fixing to induce a strict weak ordering\n\t\t\tconst std::size_t test_size = 10000000;\n\t\t\tconst int reps = 5;\n\t\t\tdouble time_sum;\n\t\t\tstd::vector<SORT_TYPE> data_original;\n\t\t\tdata_original.resize(test_size);\n\t\t\t\n\t\t\tfor (std::size_t i = 0; i < test_size; ++i)\n\t\t\t{\n\t\t\t\t//data_original[i] = Eidos_rng_uniform_int(rng, test_size);\n\t\t\t\tdata_original[i] = std::to_string(Eidos_rng_uniform_int(rng, test_size));\n\t\t\t}\n\t\t\t\n\t\t\tstd::vector<SORT_TYPE> data_stdsort;\n\t\t\t\n\t\t\tstd::cout << \"time (std::sort): \";\n\t\t\ttime_sum = 0.0;\n\t\t\tfor (int rep = 0; rep < reps; ++rep)\n\t\t\t{\n\t\t\t\tdata_stdsort = data_original;\n\t\t\t\teidos_profile_t begin = Eidos_BenchmarkTime();\n\t\t\t\t\n\t\t\t\tstd::sort(data_stdsort.begin(), data_stdsort.end());\n\t\t\t\t\n\t\t\t\teidos_profile_t end = Eidos_BenchmarkTime();\n\t\t\t\tdouble time_spent = Eidos_ElapsedProfileTime(end - begin);\n\t\t\t\tstd::cout << time_spent << \" \";\n\t\t\t\ttime_sum += time_spent;\n\t\t\t}\n\t\t\tstd::cout << \" : mean \" << time_sum / reps << std::endl;\n\t\t\t\n#ifdef _OPENMP\n\t\t\tstd::cout << \"time (PQUICK): \";\n\t\t\ttime_sum = 0.0;\n\t\t\tfor (int rep = 0; rep < reps; ++rep)\n\t\t\t{\n\t\t\t\tstd::vector<SORT_TYPE> data_PQUICK = data_original;\n\t\t\t\teidos_profile_t begin = Eidos_BenchmarkTime();\n\t\t\t\t\n\t\t\t\tEidos_ParallelSort(data_PQUICK.data(), data_PQUICK.size(), true);\n\t\t\t\t\n\t\t\t\teidos_profile_t end = Eidos_BenchmarkTime();\n\t\t\t\tdouble time_spent = Eidos_ElapsedProfileTime(end - begin);\n\t\t\t\tbool correct = (data_PQUICK == data_stdsort);\n\t\t\t\tstd::cout << time_spent << \" \" << (!correct ? \"(INCORRECT) \" : \"\");\n\t\t\t\ttime_sum += time_spent;\n\t\t\t}\n\t\t\tstd::cout << \" : mean \" << time_sum / reps << std::endl;\n\t\t\t\n\t\t\tstd::cout << \"time (PQUICKCOMP): \";\n\t\t\ttime_sum = 0.0;\n\t\t\tfor (int rep = 0; rep < reps; ++rep)\n\t\t\t{\n\t\t\t\tstd::vector<SORT_TYPE> data_PQUICKCOMP = data_original;\n\t\t\t\teidos_profile_t begin = Eidos_BenchmarkTime();\n\t\t\t\t\n\t\t\t\tEidos_ParallelSort_Comparator(data_PQUICKCOMP.data(), data_PQUICKCOMP.size(), comparator_string);\n\t\t\t\t\n\t\t\t\teidos_profile_t end = Eidos_BenchmarkTime();\n\t\t\t\tdouble time_spent = Eidos_ElapsedProfileTime(end - begin);\n\t\t\t\tbool correct = (data_PQUICKCOMP == data_stdsort);\n\t\t\t\tstd::cout << time_spent << \" \" << (!correct ? \"(INCORRECT) \" : \"\");\n\t\t\t\ttime_sum += time_spent;\n\t\t\t}\n\t\t\tstd::cout << \" : mean \" << time_sum / reps << std::endl;\n\t\t\t\n\t\t\tstd::cout << \"time (PSRIRAM): \";\n\t\t\ttime_sum = 0.0;\n\t\t\tfor (int rep = 0; rep < reps; ++rep)\n\t\t\t{\n\t\t\t\tstd::vector<SORT_TYPE> data_PSRIRAM = data_original;\n\t\t\t\teidos_profile_t begin = Eidos_BenchmarkTime();\n\t\t\t\t\n\t\t\t\tSriram_parallel_omp_sort(data_PSRIRAM, comparator_string);\n\t\t\t\t\n\t\t\t\teidos_profile_t end = Eidos_BenchmarkTime();\n\t\t\t\tdouble time_spent = Eidos_ElapsedProfileTime(end - begin);\n\t\t\t\tbool correct = (data_PSRIRAM == data_stdsort);\n\t\t\t\tstd::cout << time_spent << \" \" << (!correct ? \"(INCORRECT) \" : \"\");\n\t\t\t\ttime_sum += time_spent;\n\t\t\t}\n\t\t\tstd::cout << \" : mean \" << time_sum / reps << std::endl;\n#endif\n\t\t}\n\t\t\n\t\tstd::cout << std::endl << std::endl;\n\t}\n#endif\n\t\n\t// If we ran tests, the random number seed has been set; let's set it back to a good seed value\n\tEidos_SetRNGSeed(Eidos_GenerateRNGSeed());\n\t\n\t// return a standard Unix result code indicating success (0) or failure (1);\n\treturn (gEidosTestFailureCount > 0) ? EXIT_FAILURE : EXIT_SUCCESS;\n}\n\n#pragma mark float output tests\nstatic void _TestFloatOutput(double value, std::string expectation)\n{\n\tstd::string result1 = EidosStringForFloat(value);\n\t\n\tif (result1 == expectation)\n\t\tgEidosTestSuccessCount++;\n\telse\n\t{\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"double value \" << value << \" output as \" << result1 << \" (\" << expectation << \" expected)\" << std::endl;\n\t}\n}\n\nvoid _RunFloatOutputTests(void)\n{\n\t// I added these tests after I discovered that Eidos was sometimes printing \".0\" at the end of floats\n\t// erroneously.  It is surprisingly difficult to get floats to output the way I want them to output!\n\t// There are basically three stakes: I generally want gEidosFloatOutputPrecision digits of precision\n\t// (but that is not an absolute stake; see other points); I always want a decimal point with a digit\n\t// after it, to differentiate float output from integer output (unlike in R); and I want unnecessary\n\t// zeros at the end to be suppressed, *except* for a zero immediately following the decimal point.\n\t//\n\t// This test code is predicated upon gEidosFloatOutputPrecision == 6.\n\t_TestFloatOutput(std::numeric_limits<double>::infinity(), \"INF\");\n\t_TestFloatOutput(-std::numeric_limits<double>::infinity(), \"-INF\");\n\t_TestFloatOutput(-std::numeric_limits<double>::quiet_NaN(), \"NAN\");\n\t_TestFloatOutput(0.0, \"0.0\");\n\t\n\t_TestFloatOutput(0.01, \"0.01\");\n\t_TestFloatOutput(0.1, \"0.1\");\n\t_TestFloatOutput(1.0, \"1.0\");\n\t_TestFloatOutput(12.0, \"12.0\");\n\t_TestFloatOutput(123.0, \"123.0\");\n\t_TestFloatOutput(1234.0, \"1234.0\");\n\t_TestFloatOutput(12345.0, \"12345.0\");\n\t_TestFloatOutput(123456.0, \"123456.0\");\n\t_TestFloatOutput(1234567.0, \"1.23457e+06\");\n\t\n\t_TestFloatOutput(-0.01, \"-0.01\");\n\t_TestFloatOutput(-0.1, \"-0.1\");\n\t_TestFloatOutput(-1.0, \"-1.0\");\n\t_TestFloatOutput(-12.0, \"-12.0\");\n\t_TestFloatOutput(-123.0, \"-123.0\");\n\t_TestFloatOutput(-1234.0, \"-1234.0\");\n\t_TestFloatOutput(-12345.0, \"-12345.0\");\n\t_TestFloatOutput(-123456.0, \"-123456.0\");\n\t_TestFloatOutput(-1234567.0, \"-1.23457e+06\");\n\t\n\t_TestFloatOutput(0.012, \"0.012\");\n\t_TestFloatOutput(0.12, \"0.12\");\n\t_TestFloatOutput(1.1, \"1.1\");\n\t_TestFloatOutput(12.1, \"12.1\");\n\t_TestFloatOutput(123.1, \"123.1\");\n\t_TestFloatOutput(1234.1, \"1234.1\");\n\t_TestFloatOutput(12345.1, \"12345.1\");\n\t_TestFloatOutput(123456.1, \"123456.1\");\n\t_TestFloatOutput(1234567.1, \"1.23457e+06\");\n\t\n\t_TestFloatOutput(-0.012, \"-0.012\");\n\t_TestFloatOutput(-0.12, \"-0.12\");\n\t_TestFloatOutput(-1.1, \"-1.1\");\n\t_TestFloatOutput(-12.1, \"-12.1\");\n\t_TestFloatOutput(-123.1, \"-123.1\");\n\t_TestFloatOutput(-1234.1, \"-1234.1\");\n\t_TestFloatOutput(-12345.1, \"-12345.1\");\n\t_TestFloatOutput(-123456.1, \"-123456.1\");\n\t_TestFloatOutput(-1234567.1, \"-1.23457e+06\");\n\t\n\t_TestFloatOutput(1.0e0, \"1.0\");\n\t_TestFloatOutput(1.0e1, \"10.0\");\n\t_TestFloatOutput(1.0e2, \"100.0\");\n\t_TestFloatOutput(1.0e3, \"1000.0\");\n\t_TestFloatOutput(1.0e4, \"10000.0\");\n\t_TestFloatOutput(1.0e5, \"100000.0\");\n\t_TestFloatOutput(1.0e6, \"1.0e+06\");\n\t\n\t_TestFloatOutput(-1.0e0, \"-1.0\");\n\t_TestFloatOutput(-1.0e1, \"-10.0\");\n\t_TestFloatOutput(-1.0e2, \"-100.0\");\n\t_TestFloatOutput(-1.0e3, \"-1000.0\");\n\t_TestFloatOutput(-1.0e4, \"-10000.0\");\n\t_TestFloatOutput(-1.0e5, \"-100000.0\");\n\t_TestFloatOutput(-1.0e6, \"-1.0e+06\");\n\t\n\t_TestFloatOutput(1.1e0, \"1.1\");\n\t_TestFloatOutput(1.1e1, \"11.0\");\n\t_TestFloatOutput(1.1e2, \"110.0\");\n\t_TestFloatOutput(1.1e3, \"1100.0\");\n\t_TestFloatOutput(1.1e4, \"11000.0\");\n\t_TestFloatOutput(1.1e5, \"110000.0\");\n\t_TestFloatOutput(1.1e6, \"1.1e+06\");\n\t\n\t_TestFloatOutput(-1.1e0, \"-1.1\");\n\t_TestFloatOutput(-1.1e1, \"-11.0\");\n\t_TestFloatOutput(-1.1e2, \"-110.0\");\n\t_TestFloatOutput(-1.1e3, \"-1100.0\");\n\t_TestFloatOutput(-1.1e4, \"-11000.0\");\n\t_TestFloatOutput(-1.1e5, \"-110000.0\");\n\t_TestFloatOutput(-1.1e6, \"-1.1e+06\");\n\t\n\t_TestFloatOutput(125604.390423, \"125604.4\");\t// this was the value for which I noticed the bug; it was output as \"125604.0\", whoops!\n}\n\n#pragma mark internal filesystem tests\nvoid _RunInternalFilesystemTests(void)\n{\n\t// test some of the core Eidos C++ filesystem functions directly for correct behavior\n\t// the behaviors are quite different on Windows, so that is handled entirely separately\n#ifndef _WIN32\n\t// Eidos_ResolvedPath(): look for replacement of a leading ~, pass-through of the rest\n\ttry {\n\t\tstd::string result = Eidos_ResolvedPath(\"foo/bar.baz\");\n\t\tif (result == \"foo/bar.baz\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_ResolvedPath(\"~/foo/bar.baz\");\n\t\tif ((result.length() > 0) && (result[0] != '~') && Eidos_string_hasSuffix(result, \"/foo/bar.baz\"))\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"~/foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"~/foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\t// Eidos_AbsolutePath(): the current working directory should be prepended\n\ttry {\n\t\tstd::string result = Eidos_AbsolutePath(\"foo/bar.baz\");\n\t\tif (Eidos_string_hasSuffix(result, \"/foo/bar.baz\"))\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_AbsolutePath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_AbsolutePath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\t// Eidos_StripTrailingSlash(): remove a / at the end of a path, pass everything else through\n\ttry {\n\t\tstd::string result = Eidos_StripTrailingSlash(\"~/foo/foobar/\");\n\t\tif (result == \"~/foo/foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_StripTrailingSlash(\"~/foo/foobar\");\n\t\tif (result == \"~/foo/foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\t// Eidos_LastPathComponent(): extract the last component of the path using / as the separator\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo/foobar/bar.baz\");\n\t\tif (result == \"bar.baz\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo/foobar/\");\n\t\tif (result == \"foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n#else\n\t// Eidos_ResolvedPath(): on Windows this is not supported, and should raise if a leading ~ is present\n\ttry {\n\t\tstd::string result = Eidos_ResolvedPath(\"foo/bar.baz\");\n\t\tif (result == \"foo/bar.baz\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_ResolvedPath(\"~/foo/bar.baz\");\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_ResolvedPath(\\\"~/foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << \" (raise expected)\" << std::endl;\n\t} catch (...) {\n\t\tgEidosTestSuccessCount++;\n\t}\n\t\n\t// Eidos_AbsolutePath(): the current working directory should be prepended; it might end in \\ or in /\n\ttry {\n\t\tstd::string result = Eidos_AbsolutePath(\"foo/bar.baz\");\n\t\tif ((Eidos_string_hasSuffix(result, \"/foo/bar.baz\")) || (Eidos_string_hasSuffix(result, \"\\\\foo/bar.baz\")))\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_AbsolutePath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_AbsolutePath(\\\"foo/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\t// Eidos_StripTrailingSlash(): remove a / or \\\\ at the end of a path, pass everything else through\n\ttry {\n\t\tstd::string result = Eidos_StripTrailingSlash(\"~/foo/foobar/\");\n\t\tif (result == \"~/foo/foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_StripTrailingSlash(\"~\\\\foo\\\\foobar\\\\\");\n\t\tif (result == \"~\\\\foo\\\\foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~\\\\foo\\\\foobar\\\\\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~\\\\foo\\\\foobar\\\\\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_StripTrailingSlash(\"~/foo/foobar\");\n\t\tif (result == \"~/foo/foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_StripTrailingSlash(\\\"~/foo/foobar\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\t// Eidos_LastPathComponent(): extract the last component of the path using / and \\ as the separators\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo/foobar/bar.baz\");\n\t\tif (result == \"bar.baz\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\t\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo\\\\foobar\\\\bar.baz\");\n\t\tif (result == \"bar.baz\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo\\\\foobar\\\\bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo\\\\foobar\\\\bar.baz\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo/foobar/\");\n\t\tif (result == \"foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo/foobar/\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n\n\ttry {\n\t\tstd::string result = Eidos_LastPathComponent(\"foo\\\\foobar\\\\\");\n\t\tif (result == \"foobar\")\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo\\\\foobar\\\\\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : incorrect result \" << result << std::endl;\n\t\t}\n\t} catch (...) {\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << \"Eidos_LastPathComponent(\\\"foo\\\\foobar\\\\\\\")\" << \" : \" << EIDOS_OUTPUT_FAILURE_TAG << \" : raise during execution\" << std::endl;\n\t}\n#endif\n}\n\n#pragma mark literals & identifiers\nvoid _RunLiteralsIdentifiersAndTokenizationTests(void)\n{\n\t// test literals, built-in identifiers, and tokenization\n\t// NOLINTBEGIN(*-raw-string-literal) : these strings are fine\n\tEidosAssertScriptSuccess_VOID(\";\");\n\tEidosAssertScriptSuccess_I(\"3;\", 3);\n\tEidosAssertScriptSuccess_I(\"3e2;\", 300);\n\tEidosAssertScriptSuccess_F(\"3.1;\", 3.1);\n\tEidosAssertScriptSuccess_F(\"3.1e2;\", 3.1e2);\n\tEidosAssertScriptSuccess_F(\"3.1e-2;\", 3.1e-2);\n\tEidosAssertScriptSuccess_F(\"3.1e+2;\", 3.1e+2);\n\tEidosAssertScriptSuccess_S(\"'foo';\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"'foo\\\\tbar';\", \"foo\\tbar\");\n\tEidosAssertScriptSuccess_S(\"'\\\\'foo\\\\'\\\\t\\\\\\\"bar\\\"';\", \"'foo'\\t\\\"bar\\\"\");\n\tEidosAssertScriptSuccess_S(\"\\\"foo\\\";\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"\\\"foo\\\\tbar\\\";\", \"foo\\tbar\");\n\tEidosAssertScriptSuccess_S(\"\\\"\\\\'foo'\\\\t\\\\\\\"bar\\\\\\\"\\\";\", \"'foo'\\t\\\"bar\\\"\");\n\tEidosAssertScriptSuccess_S(\"<<\\n'foo'\\n\\\"bar\\\"\\n>>;\", \"'foo'\\n\\\"bar\\\"\");\n\tEidosAssertScriptSuccess_S(\"<<---\\n'foo'\\n\\\"bar\\\"\\n>>---;\", \"'foo'\\n\\\"bar\\\"\");\n\tEidosAssertScriptSuccess_S(\"<<<<\\n'foo'\\n\\\"bar\\\"\\n>><<;\", \"'foo'\\n\\\"bar\\\"\");\n\tEidosAssertScriptSuccess_S(\"<<<<\\n'foo'\\n\\\"bar>><\\\"\\n>><<;\", \"'foo'\\n\\\"bar>><\\\"\");\n\tEidosAssertScriptSuccess_L(\"T;\", true);\n\tEidosAssertScriptSuccess_L(\"F;\", false);\n\tEidosAssertScriptSuccess_NULL(\"NULL;\");\n\tEidosAssertScriptSuccess(\"INF;\", gStaticEidosValue_FloatINF);\n\tEidosAssertScriptSuccess_F(\"-INF;\", (-std::numeric_limits<double>::infinity()));\n\tEidosAssertScriptSuccess(\"NAN;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_L(\"E - exp(1) < 0.0000001;\", true);\n\tEidosAssertScriptSuccess_L(\"PI - asin(1)*2 < 0.0000001;\", true);\n\tEidosAssertScriptRaise(\"foo$foo;\", 3, \"unexpected token '$'\");\n\tEidosAssertScriptRaise(\"foo#foo;\", 3, \"unrecognized token\");\n\tEidosAssertScriptRaise(\"3..5;\", 3, \"unexpected token\");\t\t// second period is a dot operator!\n\tEidosAssertScriptRaise(\"3ee5;\", 0, \"unrecognized token\");\n\tEidosAssertScriptRaise(\"3e-+5;\", 0, \"unrecognized token\");\n\tEidosAssertScriptRaise(\"3e-;\", 0, \"unrecognized token\");\n\tEidosAssertScriptRaise(\"3e;\", 0, \"unrecognized token\");\n\tEidosAssertScriptRaise(\"'foo' + 'foo;\", 8, \"unexpected EOF\");\n\tEidosAssertScriptRaise(\"'foo' + 'foo\\\\q';\", 12, \"illegal escape\");\n\tEidosAssertScriptRaise(\"'foo' + 'foo\\\\\", 8, \"unexpected EOF\");\n\tEidosAssertScriptRaise(\"'foo' + 'foo\\n';\", 8, \"illegal newline\");\n\tEidosAssertScriptRaise(\"1e100;\", 0, \"could not be represented\");\t\t\t\t\t\t\t// out of range for integer\n\tEidosAssertScriptRaise(\"1000000000000000000000000000;\", 0, \"could not be represented\");\t\t// out of range for integer\n\tEidosAssertScriptRaise(\"1.0e100000000000;\", 0, \"could not be represented\");\t\t\t\t\t// out of range for double\n\tEidosAssertScriptRaise(\"T = 5;\", 2, \"is a constant\");\n\tEidosAssertScriptRaise(\"F = 5;\", 2, \"is a constant\");\n\tEidosAssertScriptRaise(\"NULL = 5;\", 5, \"is a constant\");\n\tEidosAssertScriptRaise(\"INF = 5;\", 4, \"is a constant\");\n\tEidosAssertScriptRaise(\"NAN = 5;\", 4, \"is a constant\");\n\tEidosAssertScriptRaise(\"E = 5;\", 2, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = 5;\", 3, \"is a constant\");\n\t// NOLINTEND(*-raw-string-literal)\n\t\n\t// tests related to the R-style assignment operator, <-, which is explicitly illegal in Eidos to prevent mistakes (\"a <- b;\" meaning \"a < -b;\")\n\tEidosAssertScriptSuccess_L(\"x = -9; x < -8;\", true);\n\tEidosAssertScriptRaise(\"x = -9; x <- 8;\", 10, \"<- is not legal\");\n\tEidosAssertScriptRaise(\"x = -9; x<-8;\", 9, \"<- is not legal\");\n\t\n\t// try harder to overwrite a constant\n\tEidosAssertScriptRaise(\"T = F;\", 2, \"is a constant\");\n\tEidosAssertScriptRaise(\"T[0] = F;\", 5, \"is a constant\");\n\tEidosAssertScriptRaise(\"T[0][0] = F;\", 8, \"is a constant\");\n\tEidosAssertScriptRaise(\"T = !T;\", 2, \"is a constant\");\n\tEidosAssertScriptRaise(\"for (T in c(F, F)) 5;\", 5, \"is a constant\");\n\t\n\tEidosAssertScriptRaise(\"PI = 3;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = 3.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI[0] = 3;\", 6, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI[0] = 3.0;\", 6, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI[0][0] = 3;\", 9, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI[0][0] = 3.0;\", 9, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI + 1;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI + 1.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI - 1;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI - 1.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI * 2;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI * 2.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI / 2;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI / 2.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI % 2;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI % 2.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI ^ 2;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = PI ^ 2.0;\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = c(PI, 2);\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"PI = c(PI, 2.0);\", 3, \"is a constant\");\n\tEidosAssertScriptRaise(\"for (PI in c(3, 4)) 5;\", 5, \"is a constant\");\n\tEidosAssertScriptRaise(\"for (PI in c(3.0, 4.0)) 5;\", 5, \"is a constant\");\n\t\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = 3;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = 3.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q[0] = 3;\", 29, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q[0] = 3.0;\", 29, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q[0][0] = 3;\", 32, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q[0][0] = 3.0;\", 32, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q + 1;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q + 1.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q - 1;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q - 1.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q * 2;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q * 2.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q / 2;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q / 2.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q % 2;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q % 2.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q ^ 2;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = Q ^ 2.0;\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = c(Q, 2);\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); Q = c(Q, 2.0);\", 26, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); for (Q in c(3, 4)) 5;\", 29, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('Q', 7); for (Q in c(3.0, 4.0)) 5;\", 29, \"is a constant\");\n}\n\n#pragma mark symbol table\nvoid _RunSymbolsAndVariablesTests(void)\n{\n\t// test symbol table and variable dynamics\n\tEidosAssertScriptSuccess_I(\"x = 3; x;\", 3);\n\tEidosAssertScriptSuccess_F(\"x = 3.1; x;\", 3.1);\n\tEidosAssertScriptSuccess_S(\"x = 'foo'; x;\", \"foo\");\n\tEidosAssertScriptSuccess_L(\"x = T; x;\", true);\n\tEidosAssertScriptSuccess_NULL(\"x = NULL; x;\");\n\tEidosAssertScriptSuccess_I(\"x = 'first'; x = 3; x;\", 3);\n\tEidosAssertScriptSuccess_F(\"x = 'first'; x = 3.1; x;\", 3.1);\n\tEidosAssertScriptSuccess_S(\"x = 'first'; x = 'foo'; x;\", \"foo\");\n\tEidosAssertScriptSuccess_L(\"x = 'first'; x = T; x;\", true);\n\tEidosAssertScriptSuccess_NULL(\"x = 'first'; x = NULL; x;\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x + 1; x;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x + 1; y;\", {2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x + 1; x = x + 1; x;\", {2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x + 1; x = x + 1; y;\", {2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x = x + 1; x;\", {2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x = x + 1; y;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x = x + x; x;\", {2, 4, 6, 8, 10});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x = x + x; y;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x[1] = 0; x;\", {1, 0, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; x[1] = 0; y;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; y[1] = 0; x;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; y = x; y[1] = 0; y;\", {1, 0, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"for (i in 1:3) { x = 1:5; x[1] = x[1] + 1; } x;\", {1, 3, 3, 4, 5});\n\t\n\t// some tests for Unicode in symbol names; both accented characters and emoji should be legal (and all other Unicode above 7-bit ASCII)\n\t// note that \"\\u00E9\" is &eacute; and \"\\u1F603\" is a grinning face emoji\n\tEidosAssertScriptSuccess_I(\"\\u00E9 = 3; \\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"\\u00E9e = 3; \\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"e\\u00E9 = 3; e\\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"e\\u00E9\\u00E9e = 3; e\\u00E9\\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"\\u1F603 = 3; \\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"\\u1F603e = 3; \\u1F603e;\", 3);\n\tEidosAssertScriptSuccess_I(\"e\\u1F603 = 3; e\\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"e\\u1F603\\u1F603e = 3; e\\u1F603\\u1F603e;\", 3);\n\t\n\t// test defineGlobal() and defineConstant() for correctly checking identifier syntax\n\tEidosAssertScriptSuccess_I(\"defineConstant('Q', 7); Q;\", 7);\n\tEidosAssertScriptSuccess_I(\"defineConstant('_Qixx_14850_', 7); _Qixx_14850_;\", 7);\n\tEidosAssertScriptRaise(\"defineConstant('_Qixx 14850_', 7);\", 0, \"valid Eidos identifier\");\n\tEidosAssertScriptRaise(\"defineConstant('_Qixx.14850_', 7);\", 0, \"valid Eidos identifier\");\n\t\n\tEidosAssertScriptSuccess_I(\"defineConstant('\\u00E9', 3); \\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('\\u00E9e', 3); \\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('e\\u00E9', 3); e\\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('e\\u00E9\\u00E9e', 3); e\\u00E9\\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('\\u1F603', 3); \\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('\\u1F603e', 3); \\u1F603e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('e\\u1F603', 3); e\\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineConstant('e\\u1F603\\u1F603e', 3); e\\u1F603\\u1F603e;\", 3);\n\t\n\tEidosAssertScriptSuccess_I(\"defineGlobal('Q', 7); Q;\", 7);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('_Qixx_14850_', 7); _Qixx_14850_;\", 7);\n\tEidosAssertScriptRaise(\"defineGlobal('_Qixx 14850_', 7);\", 0, \"valid Eidos identifier\");\n\tEidosAssertScriptRaise(\"defineGlobal('_Qixx.14850_', 7);\", 0, \"valid Eidos identifier\");\n\t\n\tEidosAssertScriptSuccess_I(\"defineGlobal('\\u00E9', 3); \\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('\\u00E9e', 3); \\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('e\\u00E9', 3); e\\u00E9;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('e\\u00E9\\u00E9e', 3); e\\u00E9\\u00E9e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('\\u1F603', 3); \\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('\\u1F603e', 3); \\u1F603e;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('e\\u1F603', 3); e\\u1F603;\", 3);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('e\\u1F603\\u1F603e', 3); e\\u1F603\\u1F603e;\", 3);\n}\n\n#pragma mark parsing\nvoid _RunParsingTests(void)\n{\n\t// test some simple parsing errors\n\tEidosAssertScriptRaise(\"5 + 5\", 5, \"unexpected token\");\t\t\t\t\t// missing ;\n\tEidosAssertScriptRaise(\"{ 5;\", 4, \"unexpected token\");\t\t\t\t\t// missing }\n\tEidosAssertScriptRaise(\"5 };\", 2, \"unexpected token\");\t\t\t\t\t// missing {\n\tEidosAssertScriptRaise(\"(5 + 7;\", 6, \"unexpected token\");\t\t\t\t// missing )\n\tEidosAssertScriptRaise(\"5 + 7);\", 5, \"unexpected token\");\t\t\t\t// missing (\n\tEidosAssertScriptRaise(\"a[5;\", 3, \"unexpected token\");\t\t\t\t\t// missing ]\n\tEidosAssertScriptRaise(\"a 5];\", 2, \"unexpected token\");\t\t\t\t\t// missing ]\n\tEidosAssertScriptRaise(\"a(5;\", 3, \"unexpected token\");\t\t\t\t\t// missing )\n\tEidosAssertScriptRaise(\"a 5);\", 2, \"unexpected token\");\t\t\t\t\t// missing (\n\tEidosAssertScriptRaise(\"a.;\", 2, \"unexpected token\");\t\t\t\t\t// missing identifier\n\tEidosAssertScriptRaise(\"if (5 T;\", 6, \"unexpected token\");\t\t\t\t// missing )\n\tEidosAssertScriptRaise(\"if 5) T;\", 3, \"unexpected token\");\t\t\t\t// missing (\n\tEidosAssertScriptRaise(\"if (5) else 5;\", 7, \"unexpected token\");\t\t// missing statement\n\tEidosAssertScriptRaise(\"do ; (T);\", 5, \"unexpected token\");\t\t\t\t// missing while\n\tEidosAssertScriptRaise(\"do ; while T);\", 11, \"unexpected token\");\t\t// missing (\n\tEidosAssertScriptRaise(\"do ; while (T;\", 13, \"unexpected token\");\t\t// missing )\n\tEidosAssertScriptRaise(\"while T);\", 6, \"unexpected token\");\t\t\t\t// missing (\n\tEidosAssertScriptRaise(\"while (T;\", 8, \"unexpected token\");\t\t\t\t// missing )\n\tEidosAssertScriptRaise(\"for;\", 3, \"unexpected token\");\t\t\t\t\t// missing range\n\tEidosAssertScriptRaise(\"for (x);\", 6, \"unexpected token\");\t\t\t\t// missing in\n\tEidosAssertScriptRaise(\"for (x in);\", 9, \"unexpected token\");\t\t\t// missing range\n\tEidosAssertScriptRaise(\"for (in 3:5);\", 5, \"unexpected token\");\t\t\t// missing range variable\n\tEidosAssertScriptRaise(\"for (x in 3:5;\", 13, \"unexpected token\");\t\t// missing )\n\tEidosAssertScriptRaise(\"for x in 3:5) ;\", 4, \"unexpected token\");\t\t// missing (\n\tEidosAssertScriptRaise(\"next 5;\", 5, \"unexpected token\");\t\t\t\t// missing ;\n\tEidosAssertScriptRaise(\"break 5;\", 6, \"unexpected token\");\t\t\t\t// missing ;\n}\n\n#pragma mark dispatch\nvoid _RunFunctionDispatchTests(void)\n{\n\t// test function dispatch, default arguments, and named arguments\n\tEidosAssertScriptSuccess_I(\"abs(-10);\", 10);\n\tEidosAssertScriptRaise(\"abs();\", 0, \"missing required argument 'x'\");\n\tEidosAssertScriptRaise(\"abs(-10, -10);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"abs(x=-10, -10);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptSuccess_I(\"abs(x=-10);\", 10);\n\tEidosAssertScriptRaise(\"abs(y=-10);\", 0, \"skipped over required argument\");\n\tEidosAssertScriptRaise(\"abs(x=-10, x=-10);\", 0, \"supplied more than once\");\n\tEidosAssertScriptRaise(\"abs(x=-10, y=-10);\", 0, \"unrecognized named argument 'y'\");\n\tEidosAssertScriptRaise(\"abs(y=-10, x=-10);\", 0, \"skipped over required argument\");\n\t\n\tEidosAssertScriptSuccess_I(\"integerDiv(6, 3);\", 2);\n\tEidosAssertScriptRaise(\"integerDiv(6, 3, 3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"integerDiv(x=6, y=3, 3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"integerDiv(6);\", 0, \"missing required argument 'y'\");\n\tEidosAssertScriptSuccess_I(\"integerDiv(x=6, y=3);\", 2);\n\tEidosAssertScriptRaise(\"integerDiv(y=6, 3);\", 0, \"skipped over required argument\");\n\tEidosAssertScriptRaise(\"integerDiv(y=6, x=3);\", 0, \"skipped over required argument\");\n\tEidosAssertScriptRaise(\"integerDiv(x=6, 3);\", 0, \"unnamed argument may not follow after named arguments\");\n\tEidosAssertScriptSuccess_I(\"integerDiv(6, y=3);\", 2);\n\t\n\tEidosAssertScriptSuccess_IV(\"seq(1, 3, 1);\", {1, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"seq(1, 3, NULL);\", {1, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"seq(1, 3, by=1);\", {1, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"seq(1, 3, by=NULL);\", {1, 2, 3});\n\tEidosAssertScriptRaise(\"seq(10, to=20, from=10);\", 0, \"supplied twice in the argument list\");\n\tEidosAssertScriptRaise(\"seq(10, 20, foo=20);\", 0, \"no parameter with that name\");\n\tEidosAssertScriptRaise(\"rainbow(10, v=0.5, s=0.5);\", 0, \"supplied out of order\");\n\tEidosAssertScriptRaise(\"seq(1, 3, by=1, length=1, by=1);\", 0, \"supplied more than once\");\n\tEidosAssertScriptRaise(\"seq(1, 3, length=1, by=1);\", 0, \"supplied out of order\");\n\tEidosAssertScriptSuccess_IV(\"seq(1, 3);\", {1, 2, 3});\n\tEidosAssertScriptRaise(\"seq(by=1, 1, 3);\", 0, \"named argument 'by' skipped over required argument\");\n\tEidosAssertScriptRaise(\"seq(by=NULL, 1, 3);\", 0, \"named argument 'by' skipped over required argument\");\n\t\n\tEidosAssertScriptSuccess_NULL(\"c();\");\n\tEidosAssertScriptSuccess_NULL(\"c(NULL);\");\n\tEidosAssertScriptSuccess_I(\"c(2);\", 2);\n\tEidosAssertScriptSuccess_IV(\"c(1, 2, 3);\", {1, 2, 3});\n\tEidosAssertScriptRaise(\"c(x=2);\", 0, \"unrecognized named argument 'x'\");\n\tEidosAssertScriptRaise(\"c(x=1, 2, 3);\", 0, \"unrecognized named argument 'x'\");\n\tEidosAssertScriptRaise(\"c(1, x=2, 3);\", 0, \"unrecognized named argument 'x'\");\n\tEidosAssertScriptRaise(\"c(1, 2, x=3);\", 0, \"unrecognized named argument 'x'\");\n\t\n\tEidosAssertScriptSuccess_I(\"doCall('abs', -10);\", 10);\n\tEidosAssertScriptSuccess_I(\"doCall(functionName='abs', -10);\", 10);\n\tEidosAssertScriptRaise(\"doCall(x='abs', -10);\", 0, \"skipped over required argument\");\n\tEidosAssertScriptRaise(\"doCall('abs', x=-10);\", 0, \"unrecognized named argument 'x'\");\n\tEidosAssertScriptRaise(\"doCall('abs', functionName=-10);\", 0, \"could not be matched\");\n\tEidosAssertScriptRaise(\"doCall(x='abs');\", 0, \"skipped over required argument\");\n\tEidosAssertScriptRaise(\"doCall(functionName='abs');\", 0, \"requires 1 argument(s), but 0 are supplied\");\n\t\n\tEidosAssertScriptRaise(\"foobaz();\", 0, \"unrecognized function name\");\n\tEidosAssertScriptRaise(\"_Test(7).foobaz();\", 9, \"method foobaz() is not defined\");\n}\n\n#pragma mark runtime\nvoid _RunRuntimeErrorTests(void)\n{\n\t// test some simple runtime errors\n\tEidosAssertScriptRaise(\"x = y * 3;\", 4, \"undefined identifier\");\t\t\t\t\t\t\t\t\t// undefined variable referenced\n\tEidosAssertScriptRaise(\"print(y * 3);\", 6, \"undefined identifier\");\t\t\t\t\t\t\t\t\t// undefined variable referenced as function argument\n\t\n\tEidosAssertScriptRaise(\"x = T; x[1];\", 8, \"out of range\");\t\t\t\t\t\t\t\t\t// subscript out of range (singleton logical)\n\tEidosAssertScriptRaise(\"x = T; x[-1];\", 8, \"out of range\");\t\t\t\t\t\t\t\t\t// subscript out of range (singleton logical)\n\tEidosAssertScriptRaise(\"x = T; x[1] = T;\", 8, \"out-of-range index\");\t\t\t\t\t\t\t\t// subscript out of range in assignment (singleton logical)\n\tEidosAssertScriptRaise(\"x = T; x[-1] = T;\", 8, \"out-of-range index\");\t\t\t\t\t\t\t\t// subscript out of range in assignment (singleton logical)\n\tEidosAssertScriptRaise(\"x = c(T,F); x[2];\", 13, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (vector logical)\n\tEidosAssertScriptRaise(\"x = c(T,F); x[-1];\", 13, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (vector logical)\n\tEidosAssertScriptRaise(\"x = c(T,F); x[2] = F;\", 13, \"out-of-range index\");\t\t\t\t\t\t// subscript out of range in assignment (vector logical)\n\tEidosAssertScriptRaise(\"x = c(T,F); x[-1] = F;\", 13, \"out-of-range index\");\t\t\t\t\t\t// subscript out of range in assignment (vector logical)\n\n\tEidosAssertScriptRaise(\"x = 8; x[1];\", 8, \"out of range\");\t\t\t\t\t\t\t\t\t// subscript out of range (singleton int)\n\tEidosAssertScriptRaise(\"x = 8; x[-1];\", 8, \"out of range\");\t\t\t\t\t\t\t\t\t// subscript out of range (singleton int)\n\tEidosAssertScriptRaise(\"x = 8; x[1] = 7;\", 8, \"out-of-range index\");\t\t\t\t\t\t\t\t// subscript out of range in assignment (singleton int)\n\tEidosAssertScriptRaise(\"x = 8; x[-1] = 7;\", 8, \"out-of-range index\");\t\t\t\t\t\t\t\t// subscript out of range in assignment (singleton int)\n\tEidosAssertScriptRaise(\"x = 7:9; x[3];\", 10, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (vector int)\n\tEidosAssertScriptRaise(\"x = 7:9; x[-1];\", 10, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (vector int)\n\tEidosAssertScriptRaise(\"x = 7:9; x[3] = 12;\", 10, \"out-of-range index\");\t\t\t\t\t\t\t// subscript out of range in assignment (vector int)\n\tEidosAssertScriptRaise(\"x = 7:9; x[-1] = 12;\", 10, \"out-of-range index\");\t\t\t\t\t\t\t// subscript out of range in assignment (vector int)\n\n\tEidosAssertScriptRaise(\"x = 8.0; x[1];\", 10, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (singleton float)\n\tEidosAssertScriptRaise(\"x = 8.0; x[-1];\", 10, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (singleton float)\n\tEidosAssertScriptRaise(\"x = 8.0; x[1] = 7.0;\", 10, \"out-of-range index\");\t\t\t\t\t\t\t// subscript out of range in assignment (singleton float)\n\tEidosAssertScriptRaise(\"x = 8.0; x[-1] = 7.0;\", 10, \"out-of-range index\");\t\t\t\t\t\t// subscript out of range in assignment (singleton float)\n\tEidosAssertScriptRaise(\"x = 7.0:9; x[3];\", 12, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (vector float)\n\tEidosAssertScriptRaise(\"x = 7.0:9; x[-1];\", 12, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (vector float)\n\tEidosAssertScriptRaise(\"x = 7.0:9; x[3] = 12.0;\", 12, \"out-of-range index\");\t\t\t\t\t\t// subscript out of range in assignment (vector float)\n\tEidosAssertScriptRaise(\"x = 7.0:9; x[-1] = 12.0;\", 12, \"out-of-range index\");\t\t\t\t\t\t// subscript out of range in assignment (vector float)\n\n\tEidosAssertScriptRaise(\"x = 'foo'; x[1];\", 12, \"out of range\");\t\t\t\t\t\t\t\t// subscript out of range (singleton string)\n\tEidosAssertScriptRaise(\"x = 'foo'; x[-1];\", 12, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (singleton string)\n\tEidosAssertScriptRaise(\"x = 'foo'; x[1] = _Test(6);\", 12, \"out-of-range index\");\t\t\t\t\t// subscript out of range in assignment (singleton string)\n\tEidosAssertScriptRaise(\"x = 'foo'; x[-1] = _Test(6);\", 12, \"out-of-range index\");\t\t\t\t\t// subscript out of range in assignment (singleton string)\n\tEidosAssertScriptRaise(\"x = c('foo', 'bar'); x[2];\", 22, \"out of range\");\t\t\t\t\t// subscript out of range (vector string)\n\tEidosAssertScriptRaise(\"x = c('foo', 'bar'); x[-1];\", 22, \"out of range\");\t\t\t\t\t// subscript out of range (vector string)\n\tEidosAssertScriptRaise(\"x = c('foo', 'bar'); x[2] = _Test(6);\", 22, \"out-of-range index\");\t\t// subscript out of range in assignment (vector string)\n\tEidosAssertScriptRaise(\"x = c('foo', 'bar'); x[-1] = _Test(6);\", 22, \"out-of-range index\");\t\t// subscript out of range in assignment (vector string)\n\n\tEidosAssertScriptRaise(\"x = _Test(8); x[1];\", 15, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (singleton object)\n\tEidosAssertScriptRaise(\"x = _Test(8); x[-1];\", 15, \"out of range\");\t\t\t\t\t\t\t// subscript out of range (singleton object)\n\tEidosAssertScriptRaise(\"x = _Test(8); x[1] = _Test(6);\", 15, \"out-of-range index\");\t\t\t\t// subscript out of range in assignment (singleton object)\n\tEidosAssertScriptRaise(\"x = _Test(8); x[-1] = _Test(6);\", 15, \"out-of-range index\");\t\t\t\t// subscript out of range in assignment (singleton object)\n\tEidosAssertScriptRaise(\"x = rep(_Test(8), 2); x[2];\", 23, \"out of range\");\t\t\t\t\t// subscript out of range (vector object)\n\tEidosAssertScriptRaise(\"x = rep(_Test(8), 2); x[-1];\", 23, \"out of range\");\t\t\t\t\t// subscript out of range (vector object)\n\tEidosAssertScriptRaise(\"x = rep(_Test(8), 2); x[2] = _Test(6);\", 23, \"out-of-range index\");\t\t// subscript out of range in assignment (vector object)\n\tEidosAssertScriptRaise(\"x = rep(_Test(8), 2); x[-1] = _Test(6);\", 23, \"out-of-range index\");\t\t// subscript out of range in assignment (vector object)\n}\n\n#pragma mark vectors & singletons\nvoid _RunVectorsAndSingletonsTests(void)\n{\t\n\t// test vector-to-singleton comparisons for integers, and multiplexing of methods and properties declared as singleton\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) == 2;\", {false, true, false, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) != 2;\", {true, false, true, true, false, true});\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) < 2;\", {true, false, false, true, false, false});\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) <= 2;\", {true, true, false, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) > 2;\", {false, false, true, false, false, true});\n\tEidosAssertScriptSuccess_LV(\"rep(1:3, 2) >= 2;\", {false, true, true, false, true, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"2 == rep(1:3, 2);\", {false, true, false, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"2 != rep(1:3, 2);\", {true, false, true, true, false, true});\n\tEidosAssertScriptSuccess_LV(\"2 > rep(1:3, 2);\", {true, false, false, true, false, false});\n\tEidosAssertScriptSuccess_LV(\"2 >= rep(1:3, 2);\", {true, true, false, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"2 < rep(1:3, 2);\", {false, false, true, false, false, true});\n\tEidosAssertScriptSuccess_LV(\"2 <= rep(1:3, 2);\", {false, true, true, false, true, true});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._yolk;\", 2);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._yolk;\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._yolk;\", {});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._cubicYolk();\", 8);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._cubicYolk();\", {8, 27});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._cubicYolk();\", {});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._increment._yolk;\", 3);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._increment._yolk;\", {3, 4});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._increment._yolk;\", {});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._increment._cubicYolk();\", 27);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._increment._cubicYolk();\", {27, 64});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._increment._cubicYolk();\", {});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._squareTest()._yolk;\", 4);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._squareTest()._yolk;\", {4, 9});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._squareTest()._yolk;\", {});\n\t\n\tEidosAssertScriptSuccess_I(\"_Test(2)._squareTest()._cubicYolk();\", 64);\n\tEidosAssertScriptSuccess_IV(\"c(_Test(2),_Test(3))._squareTest()._cubicYolk();\", {64, 729});\n\tEidosAssertScriptSuccess_IV(\"_Test(2)[F]._squareTest()._cubicYolk();\", {});\n}\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test.h",
    "content": "//\n//  eidos_test.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n This file contains code to test Eidos.\n \n */\n\n#ifndef __Eidos__eidos_test__\n#define __Eidos__eidos_test__\n\n#include <string>\n#include <initializer_list>\n\n#include \"eidos_value.h\"\n\n\nint RunEidosTests(void);\n\n// Test success/failure counters (used by C++-level tests)\nextern int gEidosTestSuccessCount;\nextern int gEidosTestFailureCount;\n\n// Can turn on escape sequences to color test output; at present we turn these on for the command-line\n// tools and off for the GUI tools, since Terminal supports these codes but Xcode does not.\n#ifdef EIDOS_GUI\n\n#define EIDOS_OUTPUT_FAILURE_TAG\t\"FAILURE\"\n#define EIDOS_OUTPUT_SUCCESS_TAG\t\"SUCCESS\"\n\n#else\n\n#define EIDOS_OUTPUT_FAILURE_TAG\t\"\\e[31mFAILURE\\e[0m\"\n#define EIDOS_OUTPUT_SUCCESS_TAG\t\"\\e[32mSUCCESS\\e[0m\"\n\n#endif\n\n\n// Conceptually, all the eidos_test_X.cpp stuff is a single source file, and all the details below are private.\n// It is split into multiple files to improve compile performance; the single source file took more than a minute to compile\n\n\n// Helper functions for testing\nextern void EidosAssertScriptSuccess(const std::string &p_script_string, const EidosValue_SP &p_correct_result);\nextern void EidosAssertScriptSuccess_VOID(const std::string &p_script_string);\nextern void EidosAssertScriptSuccess_NULL(const std::string &p_script_string);\nextern void EidosAssertScriptSuccess_L(const std::string &p_script_string, eidos_logical_t p_logical);\nextern void EidosAssertScriptSuccess_LV(const std::string &p_script_string, std::initializer_list<eidos_logical_t> p_logical_vec);\nextern void EidosAssertScriptSuccess_I(const std::string &p_script_string, int64_t p_integer);\nextern void EidosAssertScriptSuccess_IV(const std::string &p_script_string, std::initializer_list<int64_t> p_integer_vec);\nextern void EidosAssertScriptSuccess_F(const std::string &p_script_string, double p_float);\nextern void EidosAssertScriptSuccess_FV(const std::string &p_script_string, std::initializer_list<double> p_float_vec);\nextern void EidosAssertScriptSuccess_S(const std::string &p_script_string, const char *p_string);\nextern void EidosAssertScriptSuccess_SV(const std::string &p_script_string, std::initializer_list<const char *> p_string_vec);\n\nextern void EidosAssertScriptRaise(const std::string &p_script_string, const int p_bad_position, const char *p_reason_snip);\n\n\n// Test subfunction prototypes\nextern void _RunFloatOutputTests(void);\nextern void _RunInternalFilesystemTests(void);\nextern void _RunLiteralsIdentifiersAndTokenizationTests(void);\nextern void _RunSymbolsAndVariablesTests(void);\nextern void _RunParsingTests(void);\nextern void _RunFunctionDispatchTests(void);\nextern void _RunRuntimeErrorTests(void);\nextern void _RunVectorsAndSingletonsTests(void);\nextern void _RunOperatorPlusTests1(void);\nextern void _RunOperatorPlusTests2(void);\nextern void _RunOperatorMinusTests(void);\nextern void _RunOperatorMultTests(void);\nextern void _RunOperatorDivTests(void);\nextern void _RunOperatorModTests(void);\nextern void _RunOperatorSubsetTests(void);\nextern void _RunOperatorAssignTests(void);\nextern void _RunOperatorGtTests(void);\nextern void _RunOperatorLtTests(void);\nextern void _RunOperatorGtEqTests(void);\nextern void _RunOperatorLtEqTests(void);\nextern void _RunOperatorEqTests(void);\nextern void _RunOperatorNotEqTests(void);\nextern void _RunOperatorRangeTests(void);\nextern void _RunOperatorExpTests(void);\nextern void _RunOperatorLogicalAndTests(void);\nextern void _RunOperatorLogicalOrTests(void);\nextern void _RunOperatorLogicalNotTests(void);\nextern void _RunOperatorTernaryConditionalTests(void);\nextern void _RunKeywordIfTests(void);\nextern void _RunKeywordDoTests(void);\nextern void _RunKeywordWhileTests(void);\nextern void _RunKeywordForInTests(void);\nextern void _RunKeywordNextTests(void);\nextern void _RunKeywordBreakTests(void);\nextern void _RunKeywordReturnTests(void);\nextern void _RunFunctionMathTests_a_through_f(void);\nextern void _RunFunctionMathTests_g_through_r(void);\nextern void _RunFunctionMathTests_setUnionIntersection(void);\nextern void _RunFunctionMathTests_setDifferenceSymmetricDifference(void);\nextern void _RunFunctionMathTests_s_through_z(void);\nextern void _RunSIMDMathTests(void);\nextern void _RunFunctionMatrixArrayTests(void);\nextern void _RunFunctionStatisticsTests_a_through_p(void);\nextern void _RunFunctionStatisticsTests_q_through_z(void);\nextern void _RunFunctionDistributionTests(void);\nextern void _RunFunctionVectorConstructionTests_a_through_r(void);\nextern void _RunFunctionVectorConstructionTests_s_through_z(void);\nextern void _RunFunctionValueInspectionManipulationTests_a_through_f(void);\nextern void _RunFunctionValueInspectionManipulationTests_g_through_l(void);\nextern void _RunFunctionValueInspectionManipulationTests_m_through_r(void);\nextern void _RunFunctionValueInspectionManipulationTests_s_through_z(void);\nextern void _RunStringManipulationTests(void);\nextern void _RunFunctionValueTestingCoercionTests(void);\nextern void _RunFunctionFilesystemTests(const std::string &temp_path);\nextern void _RunColorManipulationTests(void);\nextern void _RunFunctionMiscTests_apply_sapply(void);\nextern void _RunFunctionMiscTests(const std::string &temp_path);\nextern void _RunClassTests(const std::string &temp_path);\nextern void _RunCodeExampleTests(void);\nextern void _RunUserDefinedFunctionTests(void);\nextern void _RunVoidEidosValueTests(void);\n\n\n#endif /* defined(__Eidos__eidos_test__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_builtins.h",
    "content": "R\"V0G0N(\n\n\n// This file is actually Eidos code!  It is run by _RunUserDefinedFunctionTests() in eidos_test.cpp.\n// The purpose of it is to test the correctness of the built-in Eidos functions by mimicking them\n// with equivalent Eidos user-defined functions, and then compare the two using random data.  The\n// reason to make this a separate file is mostly because otherwise Xcode's indenting algorithm gets\n// very confused.  Note this whole thing is one big C++ string literal.\n\n// Note that the Eidos versions of the built-in functions here are not necessarily as general or\n// robust as the built-in functions.  The user-defined functions here are intended only for testing\n// the cases that are exercised by the test code here, and may fail in other cases.  The goal here\n// is not so much checking for robustness in all cases, with all types of arguments, etc. (which is\n// tested in eidos_test.cpp), as testing for algorithmic correctness using repeated tests with\n// random data.  These tests are thus complementary to those in eidos_test.cpp.\n\n// Note that this test file gets subdivided and run in chunks; this improves error reporting.  See\n// _RunUserDefinedFunctionTests() in eidos_test_functions_other.cpp.\n\n// ***********************************************************************************************\n\n// (numeric)abs(numeric x)\nfunction (numeric)abs_func(numeric x)\n{\n\treturn sapply(x, 'if (applyValue < 0) -applyValue; else applyValue;');\n}\n\nx = sample(-1000:1000, 10000, T);\t// integer\nxbuiltin = abs(x);\nxuserdef = abs_func(x);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of abs(i)');\n\nx = rnorm(10000);\t// float\nxbuiltin = abs(x);\nxuserdef = abs_func(x);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of abs(f)');\n\n// ***********************************************************************************************\n\n// (logical$)all(logical x, ...)\nfunction (l$)all_func(l x)\n{\n\treturn sum(x) == size(x);\n}\n\nfor (iter in 1:10000)\n{\n\tx = asLogical(rbinom(10, 1, 0.5));\n\txbuiltin = all(x);\n\txuserdef = all_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of all()');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx2 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx3 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx = c(x1, x2, x3);\n\txbuiltin = all(x1, x2, x3);\n\txuserdef = all_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of all(l, l, l)');\n}\n\n// ***********************************************************************************************\n\n// (logical$)any(logical x, ...)\nfunction (l$)any_func(l x)\n{\n\treturn sum(x) > 0;\n}\n\nfor (iter in 1:10000)\n{\n\tx = asLogical(rbinom(10, 1, 0.5));\n\txbuiltin = any(x);\n\txuserdef = any_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of any()');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx2 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx3 = asLogical(rbinom(rdunif(1, 0, 3), 1, 0.5));\n\tx = c(x1, x2, x3);\n\txbuiltin = any(x1, x2, x3);\n\txuserdef = any_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of any(l, l, l)');\n}\n\n// ***********************************************************************************************\n\n// (numeric)cumProduct(numeric x)\nfunction (numeric)cumProduct_func(numeric x)\n{\n\treturn sapply(seqAlong(x), 'product(x[0:applyValue]);');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 5, T);\t// integer\n\txbuiltin = cumProduct(x);\n\txuserdef = cumProduct_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of cumProduct(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = cumProduct(x);\n\txuserdef = cumProduct_func(x);\n\t// tolerance because product() can get a little roundoff error due to SIMD\n\tif (!allClose(xbuiltin, xuserdef)) stop('Mismatch in test of cumProduct(f)');\n}\n\n// ***********************************************************************************************\n\n// (numeric)cumSum(numeric x)\nfunction (numeric)cumSum_func(numeric x)\n{\n\treturn sapply(seqAlong(x), 'sum(x[0:applyValue]);');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-1000:1000, 10, T);\t// integer\n\txbuiltin = cumSum(x);\n\txuserdef = cumSum_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of cumSum(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = cumSum(x);\n\txuserdef = cumSum_func(x);\n\t// tolerance because sum() can get a little roundoff error due to SIMD\n\tif (!allClose(xbuiltin, xuserdef)) stop('Mismatch in test of cumSum(f)');\n}\n\n// ***********************************************************************************************\n\n// (float)exp(numeric x)\nfunction (f)exp_func(numeric x)\n{\n\treturn E ^ x;\t// this uses pow(), which may produce slightly different results than exp()\n}\n\nx = sample(-100:100, 10000, T);\t// integer\nxbuiltin = exp(x);\nxuserdef = exp_func(x);\nif (any(abs(xbuiltin / xuserdef - 1.0) > 1e-10)) stop('Mismatch in test of exp(i)');\n\nx = rnorm(10000);\t// float\nxbuiltin = exp(x);\nxuserdef = exp_func(x);\nif (any(abs(xbuiltin / xuserdef - 1.0) > 1e-10)) stop('Mismatch in test of exp(f)');\n\n// ***********************************************************************************************\n\n// (*)ifelse(logical test, * trueValues, * falseValues)\nfunction (*)ifelse_func(l test, * tvals, * fvals)\n{\n\treturn sapply(seqAlong(test), \"test[applyValue] ? tvals[applyValue] else fvals[applyValue];\");\n}\n\nfor (iter in 1:10000)\n{\n\tx = asLogical(rbinom(10, 1, 0.5));\n\ttvals = rnorm(10);\n\tfvals = rnorm(10);\n\txbuiltin = ifelse(x, tvals, fvals);\n\txuserdef = ifelse_func(x, tvals, fvals);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of ifelse()');\n}\n\n// ***********************************************************************************************\n\n// (+$)max(+ x, ...)\nfunction (+$)max_func(+ x)\n{\n\tif (size(x) == 0)\n\t\treturn NULL;\n\treturn sort(x)[size(x) - 1];\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = max(x);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx2 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx3 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = max(x1, x2, x3);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(l, l, l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = max(x);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx2 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx3 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = max(x1, x2, x3);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(i, i, i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = max(x);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(f)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx2 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx3 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = max(x1, x2, x3);\n\txuserdef = max_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of max(f, f, f)');\n}\n\n// ***********************************************************************************************\n\n// (float$)mean(lif x)\nfunction (f$)mean_func(lif x)\n{\n\treturn sum(x) / size(x);\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(T, F), 10, T);\t// logical\n\txbuiltin = mean(x);\n\txuserdef = mean_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of mean(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = mean(x);\n\txuserdef = mean_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of mean(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = mean(x);\n\txuserdef = mean_func(x);\n\t// tolerance because sum() can get a little roundoff error due to SIMD\n\tif (!allClose(xbuiltin, xuserdef)) stop('Mismatch in test of mean(f)');\n}\n\n// ***********************************************************************************************\n\n// (+$)min(+ x, ...)\nfunction (+$)min_func(+ x)\n{\n\tif (size(x) == 0)\n\t\treturn NULL;\n\treturn sort(x)[0];\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = min(x);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx2 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx3 = sample(c(F,T), rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = min(x1, x2, x3);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(l, l, l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = min(x);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx2 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx3 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = min(x1, x2, x3);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(i, i, i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = min(x);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(f)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx2 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx3 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = min(x1, x2, x3);\n\txuserdef = min_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of min(f, f, f)');\n}\n\n// ***********************************************************************************************\n\n// (+)pmax(+ x, + y)\nfunction (+)pmax_func(+x, +y)\n{\n\treturn ifelse(x > y, x, y);\n}\n\nx = sample(c(F,T), 10000, T);\t// logical\ny = sample(c(F,T), 10000, T);\nxbuiltin = pmax(x, y);\nxuserdef = pmax_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmax(l)');\n\nx = sample(-100:100, 10000, T);\t// integer\ny = sample(-100:100, 10000, T);\nxbuiltin = pmax(x, y);\nxuserdef = pmax_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmax(i)');\n\nx = rnorm(10000);\t// float\ny = rnorm(10000);\nxbuiltin = pmax(x, y);\nxuserdef = pmax_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmax(f)');\n\n// ***********************************************************************************************\n\n// (+)pmin(+ x, + y)\nfunction (+)pmin_func(+x, +y)\n{\n\treturn ifelse(x < y, x, y);\n}\n\nx = sample(c(F,T), 10000, T);\t// logical\ny = sample(c(F,T), 10000, T);\nxbuiltin = pmin(x, y);\nxuserdef = pmin_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmin(l)');\n\nx = sample(-100:100, 10000, T);\t// integer\ny = sample(-100:100, 10000, T);\nxbuiltin = pmin(x, y);\nxuserdef = pmin_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmin(i)');\n\nx = rnorm(10000);\t// float\ny = rnorm(10000);\nxbuiltin = pmin(x, y);\nxuserdef = pmin_func(x, y);\nif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of pmin(f)');\n\n// ***********************************************************************************************\n\n// (numeric$)product(numeric x)\nfunction (numeric$)product_func(numeric x)\n{\n\tp = 1;\n\t\n\tsapply(x, 'p = p * applyValue; NULL;');\n\t\n\treturn p;\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 5, T);\t// integer\n\txbuiltin = product(x);\n\txuserdef = product_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of product(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = product(x);\n\txuserdef = product_func(x);\n\t// tolerance because product() can get a little roundoff error due to SIMD\n\tif (!allClose(xbuiltin, xuserdef)) stop('Mismatch in test of product(f)');\n}\n\n// ***********************************************************************************************\n\n// (numeric)range(numeric x, ...)\nfunction (numeric)range_func(numeric x)\n{\n\tif (size(x) == 0)\n\t\treturn NULL;\n\tsx = sort(x);\n\treturn c(sx[0], sx[size(x) - 1]);\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = range(x);\n\txuserdef = range_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of range(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx2 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx3 = sample(-10:10, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = range(x1, x2, x3);\n\txuserdef = range_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of range(i, i, i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = range(x);\n\txuserdef = range_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of range(f)');\n}\n\nfor (iter in 1:100)\n{\n\tx1 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx2 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx3 = sample(-10.0:10.0, rdunif(1, 0, 3), T);\n\tx = c(x1, x2, x3);\n\txbuiltin = range(x1, x2, x3);\n\txuserdef = range_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of range(f, f, f)');\n}\n\n// ***********************************************************************************************\n\n// (*)rep(* x, integer$ count)\nfunction (*)rep_func(* x, i$ count)\n{\n\tr = NULL;\n\t\n\tfor (i in 1:count)\n\t\tr = c(r, x);\n\t\n\treturn r;\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = rep(x, 5);\n\txuserdef = rep_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rep(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = rep(x, 5);\n\txuserdef = rep_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rep(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = rep(x, 5);\n\txuserdef = rep_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rep(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)repEach(* x, integer count)\nfunction (*)repEach_func(* x, i$ count)\n{\n\tr = NULL;\n\t\n\tfor (i in seqAlong(x))\n\t\tr = c(r, rep(x[i], count));\n\t\n\treturn r;\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = repEach(x, 5);\n\txuserdef = repEach_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of repEach(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = repEach(x, 5);\n\txuserdef = repEach_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of repEach(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = repEach(x, 5);\n\txuserdef = repEach_func(x, 5);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of repEach(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)rev(* x)\nfunction (*)rev_func(* x)\n{\n\treturn x[(size(x) - 1):0];\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = rev(x);\n\txuserdef = rev_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rev(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = rev(x);\n\txuserdef = rev_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rev(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = rev(x);\n\txuserdef = rev_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of rev(f)');\n}\n\n// ***********************************************************************************************\n\n// (float$)sd(numeric x)\nfunction (f$)sd_func(numeric x)\n{\n\tss = sum((x - mean(x)) ^ 2);\n\treturn sqrt(ss / (size(x) - 1));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = sd(x);\n\txuserdef = sd_func(x);\n\tif (abs(xbuiltin - xuserdef) > 1e-10) stop('Mismatch in test of sd(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = sd(x);\n\txuserdef = sd_func(x);\n\tif (abs(xbuiltin - xuserdef) > 1e-10) stop('Mismatch in test of sd(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)setDifference(* x, * y)\nfunction (*)setDifference_func(* x, * y)\n{\n\treturn setSymmetricDifference(x, setIntersection(x, y));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\ty = sample(c(F,T), 10, T);\n\txbuiltin = setDifference(x, y);\n\txuserdef = setDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setDifference(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, F);\t// integer\n\ty = sample(-100:100, 10, F);\n\txbuiltin = setDifference(x, y);\n\txuserdef = setDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setDifference(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 10, F);\t// float\n\ty = sample(-100.0:100.0, 10, F);\n\txbuiltin = setDifference(x, y);\n\txuserdef = setDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setDifference(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)setIntersection(* x, * y)\nfunction (*)setIntersection_func(* x, * y)\n{\n\treturn setDifference(setUnion(x, y), setSymmetricDifference(x, y));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\ty = sample(c(F,T), 10, T);\n\txbuiltin = setIntersection(x, y);\n\txuserdef = setIntersection_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setIntersection(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, F);\t// integer\n\ty = sample(-100:100, 10, F);\n\txbuiltin = setIntersection(x, y);\n\txuserdef = setIntersection_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setIntersection(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 10, F);\t// float\n\ty = sample(-100.0:100.0, 10, F);\n\txbuiltin = setIntersection(x, y);\n\txuserdef = setIntersection_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setIntersection(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)setSymmetricDifference(* x, * y)\nfunction (*)setSymmetricDifference_func(* x, * y)\n{\n\treturn setDifference(setUnion(x, y), setIntersection(x, y));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\ty = sample(c(F,T), 10, T);\n\txbuiltin = setSymmetricDifference(x, y);\n\txuserdef = setSymmetricDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setSymmetricDifference(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, F);\t// integer\n\ty = sample(-100:100, 10, F);\n\txbuiltin = setSymmetricDifference(x, y);\n\txuserdef = setSymmetricDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setSymmetricDifference(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 10, F);\t// float\n\ty = sample(-100.0:100.0, 10, F);\n\txbuiltin = setSymmetricDifference(x, y);\n\txuserdef = setSymmetricDifference_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setSymmetricDifference(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)setUnion(* x, * y)\nfunction (*)setUnion_func(* x, * y)\n{\n\treturn unique(c(x, y));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\ty = sample(c(F,T), 10, T);\n\txbuiltin = sort(setUnion(x, y));\n\txuserdef = sort(setUnion_func(x, y));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setUnion(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, F);\t// integer\n\ty = sample(-100:100, 10, F);\n\txbuiltin = setUnion(x, y);\n\txuserdef = setUnion_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setUnion(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 10, F);\t// float\n\ty = sample(-100.0:100.0, 10, F);\n\txbuiltin = setUnion(x, y);\n\txuserdef = setUnion_func(x, y);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of setUnion(f)');\n}\n\n// ***********************************************************************************************\n\n// (float)sqrt(numeric x)\nfunction (f)sqrt_func(numeric x)\n{\n\treturn x ^ 0.5;\t// this uses pow(), which may produce slightly different results than sqrt()\n}\n\nx = sample(1:100, 10000, T);\t// integer\nxbuiltin = sqrt(x);\nxuserdef = sqrt_func(x);\nif (any(abs(xbuiltin / xuserdef - 1.0) > 1e-10)) stop('Mismatch in test of sqrt(i)');\n\nx = runif(10000, 0.0001, 100000);\t// float\nxbuiltin = sqrt(x);\nxuserdef = sqrt_func(x);\nif (any(abs(xbuiltin / xuserdef - 1.0) > 1e-10)) stop('Mismatch in test of sqrt(f)');\n\n// ***********************************************************************************************\n\n// (numeric$)sum(lif x)\nfunction (numeric$)sum_func(numeric x)\n{\n\ts = 0;\n\t\n\tsapply(x, 's = s + applyValue; NULL;');\n\t\n\treturn s;\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = sum(x);\n\txuserdef = size(which(x));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of sum(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = sum(x);\n\txuserdef = sum_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of sum(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = sum(x);\n\txuserdef = sum_func(x);\n\t// tolerance because sum() can get a little roundoff error due to SIMD\n\tif (!allClose(xbuiltin, xuserdef)) stop('Mismatch in test of sum(f)');\n}\n\n// ***********************************************************************************************\n\n// (float$)sumExact(float x)\nfunction (f$)sumExact_func(f x)\n{\n\ts = 0;\n\t\n\tsapply(x, 's = s + applyValue; NULL;');\t// no attempt to sum exactly, just using tolerance limits below\n\t\n\treturn s;\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\n\txbuiltin = sumExact(x);\n\txuserdef = sumExact_func(x);\n\tif (abs(xbuiltin / xuserdef - 1.0) > 1e-10) stop('Mismatch in test of sumExact(f)');\n}\n\n// ***********************************************************************************************\n\n// (*)unique(* x, [logical$ preserveOrder = T])\nfunction (*)unique_func(* x)\n{\n\ts = sort(x);\t// this implementation does not preserve order!\n\tr = s[0];\n\tp = r;\n\tfor (i in 1:(size(x) - 1))\n\t{\n\t\tv = s[i];\n\t\tif (v == p) next;\n\t\tr = c(r, v);\n\t\tp = v;\n\t}\n\treturn r;\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 5, T);\t// logical\n\txbuiltin = sort(unique(x, F));\n\txuserdef = sort(unique_func(x));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(l, F)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 5, T);\t// logical\n\txbuiltin = sort(unique(x, T));\n\txuserdef = sort(unique_func(x));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(l, T)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 100, T);\t// integer\n\txbuiltin = unique(x, F);\n\txuserdef = unique_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(i, F)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 100, T);\t// integer\n\txbuiltin = sort(unique(x, T));\n\txuserdef = sort(unique_func(x));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(i, T)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 100, T);\t// float\n\txbuiltin = unique(x, F);\n\txuserdef = unique_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(f, F)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100.0:100.0, 100, T);\t// float\n\txbuiltin = sort(unique(x, T));\n\txuserdef = sort(unique_func(x));\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of unique(f, T)');\n}\n\n// ***********************************************************************************************\n\n// (integer)which(logical x)\nfunction (i)which_func(l x)\n{\n\tw = sapply(seqAlong(x), 'x[applyValue] ? applyValue else NULL;');\n\t\n\treturn isNULL(w) ? integer(0) else w;\n}\n\nfor (iter in 1:10000)\n{\n\tx = asLogical(rbinom(10, 1, 0.5));\n\txbuiltin = which(x);\n\txuserdef = which_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of which()');\n}\n\n// ***********************************************************************************************\n\n// (integer$)whichMax(+ x)\nfunction (integer$)whichMax_func(+ x)\n{\n\treturn min(which(x == max(x)));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = whichMax(x);\n\txuserdef = whichMax_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMax(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = whichMax(x);\n\txuserdef = whichMax_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMax(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = whichMax(x);\n\txuserdef = whichMax_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMax(f)');\n}\n\n// ***********************************************************************************************\n\n// (integer$)whichMin(+ x)\nfunction (integer$)whichMin_func(+ x)\n{\n\treturn min(which(x == min(x)));\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(c(F,T), 10, T);\t// logical\n\txbuiltin = whichMin(x);\n\txuserdef = whichMin_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMin(l)');\n}\n\nfor (iter in 1:100)\n{\n\tx = sample(-100:100, 10, T);\t// integer\n\txbuiltin = whichMin(x);\n\txuserdef = whichMin_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMin(i)');\n}\n\nfor (iter in 1:100)\n{\n\tx = rnorm(10);\t\t// float\n\txbuiltin = whichMin(x);\n\txuserdef = whichMin_func(x);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of whichMin(f)');\n}\n\n// ***********************************************************************************************\n\n// (integer)integer(integer$ length, [integer$ fill1 = 0], [integer$ fill2 = 1], [Ni fill2Indices = NULL])\nfunction (integer)integer_func(integer$ length, integer$ fill1, integer$ fill2, i fill2Indices)\n{\n\tx = rep(fill1, length);\n\tx[fill2Indices] = fill2;\n\treturn x;\n}\n\nfor (iter in 1:1000)\n{\n\tindices = sample(0:999, rdunif(1, 0, 100));\n\txbuiltin = integer(1000, 5, 8, indices);\n\txuserdef = integer_func(1000, 5, 8, indices);\n\tif (!identical(xbuiltin, xuserdef)) stop('Mismatch in test of integer()');\n}\n\n// ***********************************************************************************************\n\n// The functions above are the ones that seemed simple and worthwhile to test by replication.\n// Since we're in a groove, let's test some other Eidos functions, not by replication since\n// it is more difficult in these cases, but by testing them against each other.\n\n// ***********************************************************************************************\n\n// (float)acos(numeric x)\n// (float)cos(numeric x)\nx = runif(10000, 0.0, PI);\nxtest = acos(cos(x));\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of acos() vs. cos()');\n\n// ***********************************************************************************************\n\n// (float)asin(numeric x)\n// (float)sin(numeric x)\nx = runif(10000, -PI/2, PI/2);\nxtest = asin(sin(x));\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of asin() vs. sin()');\n\n// ***********************************************************************************************\n\n// (float)atan(numeric x)\n// (float)tan(numeric x)\nx = runif(10000, -PI/2, PI/2);\nxtest = atan(tan(x));\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of atan() vs. tan()');\n\n// ***********************************************************************************************\n\n// (float)cos(numeric x)\n// (float)sin(numeric x)\nx = runif(10000, -100, 100);\nxtest = sin(x)^2 + cos(x)^2;\nif (any(abs(xtest - 1.0) > 1e-5)) stop('Mismatch in test of sin() vs. cos()');\n\n// ***********************************************************************************************\n\n// (float)atan2(numeric x, numeric y)\n// (float)cos(numeric x)\n// (float)sin(numeric x)\nx = runif(10000, -PI, PI);\nxtest = atan2(sin(x), cos(x));\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of atan2() vs. sin() and cos()');\n\n// ***********************************************************************************************\n\n// (float)log(numeric x)\n// (float)exp(numeric x)\nx = runif(10000, 0.1, 100);\nxtest = log(exp(x));\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of log() vs. exp()');\n\n// ***********************************************************************************************\n\n// (float)log10(numeric x)\n// operator ^\nx = runif(10000, 0.1, 100);\nxtest = log10(10^x);\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of log10() vs. operator ^');\n\n// ***********************************************************************************************\n\n// (float)log2(numeric x)\n// operator ^\nx = runif(10000, 0.1, 100);\nxtest = log2(2^x);\nif (any(abs(xtest / x - 1.0) > 1e-5)) stop('Mismatch in test of log2() vs. operator ^');\n\n// ***********************************************************************************************\n\n// (integer)order(+ x, [logical$ ascending = T])\n// (+)sort(+ x, [logical$ ascending = T])\nx = sample(-1000:1000, 10000, T);\t\t// integer\nif (!identical(x[order(x)], sort(x))) stop('Mismatch in test of order(i) vs. sort(i)');\nif (!identical(x[order(x, ascending=F)], sort(x, ascending=F))) stop('Mismatch in test of order(i) vs. sort(i) (ascending=F)');\n\nx = runif(10000, 0.1, 100);\t\t// float\nif (!identical(x[order(x)], sort(x))) stop('Mismatch in test of order(f) vs. sort(f)');\nif (!identical(x[order(x, ascending=F)], sort(x, ascending=F))) stop('Mismatch in test of order(f) vs. sort(f) (ascending=F)');\n\n// ***********************************************************************************************\n\n// (integer)match(* x, * table)\n// operator []\ntable = -1000:1000;\t\t// integer\nx = sample(table, 10000, T);\nif (!identical(table[match(x, table)], x)) stop('Mismatch in test of match(i) vs. operator []');\n\ntable = -1000.0:1000.0;\t\t// float\nx = sample(table, 10000, T);\nif (!identical(table[match(x, table)], x)) stop('Mismatch in test of match(f) vs. operator []');\n\n// ***********************************************************************************************\n\n// (float)ceil(float x)\n// (float)floor(float x)\n// (float)trunc(float x)\n// (float)round(float x)\nx = runif(10000, -100000.0, 100000.0);\nx = x[trunc(x) != x];\t\t\t\t// eliminate numbers with no fractional part\nx = x[trunc(x * 2.0) != x * 2.0];\t// eliminate numbers with a fractional part of 0.5\nif (any(ceil(x) != floor(x) + 1)) stop('Mismatch in test of floor() vs. ceil()');\nx = abs(x);\nif (any(round(x) != ifelse(x - trunc(x) < 0.5, floor(x), ceil(x)))) stop('Mismatch in test of round() vs. trunc()');\n\n// ***********************************************************************************************\n\n// Test random distributions against expect means; these tests aim for a fail rate of less than about 1 in 10,000\n// That expected failure rate is based upon trial and error with the current Eidos, so it assumes that the present code\n// is correct; it would be nice to use the theoretical variance formulas here.  But if the mean is close to the\n// expected mean, the logic in Eidos is almost certainly correct, so any bug would probably be in the GSL – unlikely.\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rbinom(100000, 5, 0.3));\t// expectation is np, 5 * 0.3\nif (abs(m - (5 * 0.3)) > 0.02) stop('Mismatch in expectation vs. realization of rbinom() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\n// not sure how to test rcauchy() this way, since its mean, variance, etc. are undefined...\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nx = rdunif(210000, -10, 10);\nx = sapply(-10:10, \"sum(x == applyValue);\");\nif (any(abs(x - 10000) > 500)) stop('Mismatch in expectation vs. realization of rdunif() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rbeta(10000, 2, 3));\t// expectation is 0.4\nif (abs(m - 0.4) > 0.008) stop('Mismatch in expectation vs. realization of rbeta() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rexp(100000, 5));\t// expectation is 5\nif (abs(m - 5) > 0.07) stop('Mismatch in expectation vs. realization of rexp() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rf(10000, 4, 6));\t// expectation is 1.5\nif (abs(m - 1.5) > 0.15) stop('Mismatch in expectation vs. realization of rf() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rgamma(10000, 5, 0.3));\t// expectation is 5\nif (abs(m - 5) > 0.4) stop('Mismatch in expectation vs. realization of rgamma() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rgeom(10000, 0.1));\t// expectation is 9\nif (abs(m - 9) > 0.4) stop('Mismatch in expectation vs. realization of rgeom() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rlaplace(100000, 5));\t// expectation is 0.0\nif (abs(m) > 0.08) stop('Mismatch in expectation vs. realization of rlaplace() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(log(rlnorm(10000, 5, 0.3)));\t// expectation is 5\nif (abs(m - 5) > 0.02) stop('Mismatch in expectation vs. realization of rlnorm() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nx = rmultinom(10, 1000000000, c(0.1, 0.5, 0.1, 5.0, 0.25));\nif (!identical(colSums(x), rep(1000000000, 10))) stop('ERROR (rmultinom): (internal error) colSums incorrect');\nr = rowSums(x);\nnorm = c(0.1, 0.5, 0.1, 5.0, 0.25) / sum(c(0.1, 0.5, 0.1, 5.0, 0.25));\nexpected = 1000000000 * norm * 10;\nif (sum(abs(r - expected)) > 300000) stop('Mismatch in expectation vs. realization of rmultinom() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nx = rmvnorm(100000, c(-1, 5), matrix(c(1, 0.2, 0.2, 2), nrow=2));\nm1 = mean(x[,0]);\nm2 = mean(x[,1]);\ncov = mean((x[,0] - m1) * (x[,1] - m2));\nif (abs(m1 - -1.0) > 0.05) stop('Mismatch in expectation vs. realization of rmvnorm() - could be random chance (but very unlikely), rerun test');\nif (abs(m2 - 5.0) > 0.07) stop('Mismatch in expectation vs. realization of rmvnorm() - could be random chance (but very unlikely), rerun test');\nif (abs(cov - 0.2) > 0.03) stop('Mismatch in expectation vs. realization of rmvnorm() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rnbinom(100000, 5, 0.3));\t// expectation is (1-p)r/p, 0.7*5/0.3 == 11.66667, for our parameterization (different from Wikipedia)\nif (abs(m - 11.66667) > 0.08) stop('Mismatch in expectation vs. realization of rnbinom() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rnorm(10000, 5, 0.3));\t// expectation is 5\nif (abs(m - 5) > 0.02) stop('Mismatch in expectation vs. realization of rnorm() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rpois(10000, 5));\t// expectation is 5\nif (abs(m - 5) > 0.09) stop('Mismatch in expectation vs. realization of rpois() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nx = round(runif(210000, -10.4999, 10.4999));\nx = sapply(-10:10, \"sum(x == applyValue);\");\nif (any(abs(x - 10000) > 500)) stop('Mismatch in expectation vs. realization of runif() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rweibull(10000, 5, 0.5));\t// expectation is lambda * Gamma(1 + 1/k), and for positive integers Gamma(x) = (x-1)!, so here it is 5 * 2\nif (abs(m - (5 * 2)) > 1.0) stop('Mismatch in expectation vs. realization of rweibull() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nx = sample(-10:10, 210000, replace=T);\nx = sapply(-10:10, \"sum(x == applyValue);\");\nif (any(abs(x - 10000) > 500)) stop('Mismatch in expectation vs. realization of sample() - could be random chance (but very unlikely), rerun test');\n\n// ***********************************************************************************************\n\nsetSeed(asInteger(clock() * 100000));\nm = mean(rztpois(10000, 3));\nexpected = 3 / (1 - exp(-3));\t// ~= 3.15719\nif (abs(m - expected) > 0.07) stop('Mismatch in expectation vs. realization of rztpois() - could be random chance (but very unlikely), rerun test');\n\n)V0G0N\"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_functions_math.cpp",
    "content": "//\n//  eidos_test_functions_math.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n#include <cmath>\n#include <limits>\n#include <algorithm>\n#include <vector>\n\n\n#pragma mark math\nvoid _RunFunctionMathTests_a_through_f(void)\n{\n\t// abs()\n\tEidosAssertScriptSuccess_I(\"abs(5);\", 5);\n\tEidosAssertScriptSuccess_I(\"abs(-5);\", 5);\n\tEidosAssertScriptSuccess_IV(\"abs(c(-2, 7, -18, 12));\", {2, 7, 18, 12});\n\tEidosAssertScriptSuccess_F(\"abs(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"abs(-5.5);\", 5.5);\n\tEidosAssertScriptSuccess_FV(\"abs(c(-2.0, 7.0, -18.0, 12.0));\", {2, 7, 18, 12});\n\tEidosAssertScriptRaise(\"abs(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"abs('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"abs(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"abs(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"abs(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"abs(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"abs(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"abs(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_I(\"-9223372036854775807 - 1;\", INT64_MIN);\n\tEidosAssertScriptRaise(\"abs(-9223372036854775807 - 1);\", 0, \"most negative integer\");\n\tEidosAssertScriptRaise(\"abs(c(17, -9223372036854775807 - 1));\", 0, \"most negative integer\");\n\tEidosAssertScriptSuccess(\"abs(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"abs(c(-2.0, 7.0, -18.0, NAN, 12.0));\", {2, 7, 18, std::numeric_limits<double>::quiet_NaN(), 12});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(abs(matrix(5)), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(matrix(-5)), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(matrix(5:7)), matrix(5:7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(matrix(-5:-7)), matrix(5:7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(array(5, c(1,1,1))), array(5, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(array(-5, c(1,1,1))), array(5, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(array(5:7, c(3,1,1))), array(5:7, c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(abs(array(-5:-7, c(1,3,1))), array(5:7, c(1,3,1)));\", true);\n\t\n\t// acos()\n\tEidosAssertScriptSuccess_L(\"abs(acos(0) - PI/2) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(acos(1) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(acos(c(0, 1, -1)) - c(PI/2, 0, PI))) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(acos(0.0) - PI/2) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(acos(1.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(acos(c(0.0, 1.0, -1.0)) - c(PI/2, 0, PI))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"acos(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"acos('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"acos(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"acos(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"acos(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"acos(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"acos(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"acos(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"acos(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"acos(c(1, NAN, 1));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(acos(matrix(0.5)), matrix(acos(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(acos(matrix(c(0.1, 0.2, 0.3))), matrix(acos(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// asin()\n\tEidosAssertScriptSuccess_L(\"abs(asin(0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(asin(1) - PI/2) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(asin(c(0, 1, -1)) - c(0, PI/2, -PI/2))) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(asin(0.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(asin(1.0) - PI/2) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(asin(c(0.0, 1.0, -1.0)) - c(0, PI/2, -PI/2))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"asin(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"asin('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"asin(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"asin(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"asin(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"asin(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"asin(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"asin(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"asin(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"asin(c(0, NAN, 0));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(asin(matrix(0.5)), matrix(asin(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(asin(matrix(c(0.1, 0.2, 0.3))), matrix(asin(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// atan()\n\tEidosAssertScriptSuccess_L(\"abs(atan(0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan(1) - PI/4) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(atan(c(0, 1, -1)) - c(0, PI/4, -PI/4))) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan(0.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan(1.0) - PI/4) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(atan(c(0.0, 1.0, -1.0)) - c(0, PI/4, -PI/4))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"atan(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"atan(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"atan(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"atan(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"atan(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"atan(c(0, NAN, 0));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(atan(matrix(0.5)), matrix(atan(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan(matrix(c(0.1, 0.2, 0.3))), matrix(atan(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// atan2()\n\tEidosAssertScriptSuccess_L(\"abs(atan2(0, 1) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan2(0, -1) - PI) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(atan2(c(0, 0, -1), c(1, -1, 0)) - c(0, PI, -PI/2))) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan2(0.0, 1.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(atan2(0.0, -1.0) - PI) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(atan2(c(0.0, 0.0, -1.0), c(1.0, -1.0, 0.0)) - c(0, PI, -PI/2))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"atan2(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(_Test(7));\", 0, \"missing required argument\");\n\tEidosAssertScriptRaise(\"atan2(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(0, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(0, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(0, _Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(0, NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(logical(0), logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"atan2(integer(0), integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"atan2(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"atan2(string(0), string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"atan2(0.0, c(0.0, 1.0));\", 0, \"requires arguments of equal length\");\t\t// argument count mismatch\n\tEidosAssertScriptSuccess(\"atan2(0.5, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"atan2(NAN, 0.5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"atan2(c(0, NAN, 0, 0), c(1, 1, NAN, 1));\", {0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(atan2(matrix(0.5), matrix(0.25)), matrix(atan2(0.5, 0.25)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan2(matrix(0.5), 0.25), matrix(atan2(0.5, 0.25)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan2(0.5, matrix(0.25)), matrix(atan2(0.5, 0.25)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan2(matrix(c(0.1, 0.2, 0.3)), matrix(c(0.3, 0.2, 0.1))), matrix(atan2(c(0.1, 0.2, 0.3), c(0.3, 0.2, 0.1))));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan2(matrix(c(0.1, 0.2, 0.3)), c(0.3, 0.2, 0.1)), matrix(atan2(c(0.1, 0.2, 0.3), c(0.3, 0.2, 0.1))));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(atan2(c(0.1, 0.2, 0.3), matrix(c(0.3, 0.2, 0.1))), matrix(atan2(c(0.1, 0.2, 0.3), c(0.3, 0.2, 0.1))));\", true);\n\t\n\t// ceil()\n\tEidosAssertScriptSuccess_F(\"ceil(5.1);\", 6.0);\n\tEidosAssertScriptSuccess_F(\"ceil(-5.1);\", -5.0);\n\tEidosAssertScriptSuccess_FV(\"ceil(c(-2.1, 7.1, -18.8, 12.8));\", {-2.0, 8, -18, 13});\n\tEidosAssertScriptRaise(\"ceil(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ceil(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"ceil(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"ceil(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"ceil(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"ceil(c(-2.1, 7.1, -18.8, NAN, 12.8));\", {-2.0, 8, -18, std::numeric_limits<double>::quiet_NaN(), 13});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(ceil(matrix(0.3)), matrix(ceil(0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ceil(matrix(0.6)), matrix(ceil(0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ceil(matrix(-0.3)), matrix(ceil(-0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ceil(matrix(-0.6)), matrix(ceil(-0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ceil(matrix(c(0.1, 5.7, -0.3))), matrix(ceil(c(0.1, 5.7, -0.3))));\", true);\n\t\n\t// cos()\n\tEidosAssertScriptSuccess_L(\"abs(cos(0) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cos(0.0) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cos(PI/2) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(cos(c(0, PI/2, PI)) - c(1, 0, -1))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"cos(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cos('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cos(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cos(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cos(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cos(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"cos(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"cos(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cos(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"cos(c(0, NAN, 0));\", {1, std::numeric_limits<double>::quiet_NaN(), 1});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(cos(matrix(0.5)), matrix(cos(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cos(matrix(c(0.1, 0.2, 0.3))), matrix(cos(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// cumProduct()\n\tEidosAssertScriptSuccess_I(\"cumProduct(5);\", 5);\n\tEidosAssertScriptSuccess_I(\"cumProduct(-5);\", -5);\n\tEidosAssertScriptSuccess_IV(\"cumProduct(c(-2, 7, -18, 12));\", {-2, -14, 252, 3024});\n\tEidosAssertScriptSuccess_F(\"cumProduct(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"cumProduct(-5.5);\", -5.5);\n\tEidosAssertScriptSuccess_FV(\"cumProduct(c(-2.0, 7.0, -18.0, 12.0));\", {-2.0, -14.0, 252.0, 3024.0});\n\tEidosAssertScriptRaise(\"cumProduct(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumProduct('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumProduct(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumProduct(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumProduct(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cumProduct(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"cumProduct(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"cumProduct(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_I(\"-9223372036854775807 - 1;\", INT64_MIN);\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"-9223372036854775807 - 2;\", 21, \"subtraction overflow\");\n\tEidosAssertScriptRaise(\"cumProduct(c(-922337203685477581, 10));\", 0, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"cumProduct(c(922337203685477581, 10));\", 0, \"multiplication overflow\");\n#endif\n\tEidosAssertScriptSuccess_FV(\"cumProduct(c(5, 5, 3.0, NAN, 2.0));\", {5.0, 25.0, 75.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(cumProduct(matrix(0.5)), matrix(cumProduct(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cumProduct(matrix(c(0.1, 0.2, 0.3))), matrix(cumProduct(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// cumSum()\n\tEidosAssertScriptSuccess_I(\"cumSum(5);\", 5);\n\tEidosAssertScriptSuccess_I(\"cumSum(-5);\", -5);\n\tEidosAssertScriptSuccess_IV(\"cumSum(c(-2, 7, -18, 12));\", {-2, 5, -13, -1});\n\tEidosAssertScriptSuccess_F(\"cumSum(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"cumSum(-5.5);\", -5.5);\n\tEidosAssertScriptSuccess_FV(\"cumSum(c(-2.0, 7.0, -18.0, 12.0));\", {-2.0, 5.0, -13.0, -1.0});\n\tEidosAssertScriptRaise(\"cumSum(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumSum('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumSum(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumSum(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cumSum(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cumSum(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"cumSum(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"cumSum(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_I(\"-9223372036854775807 - 1;\", INT64_MIN);\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"-9223372036854775807 - 2;\", 21, \"subtraction overflow\");\n\tEidosAssertScriptRaise(\"cumSum(c(-9223372036854775807, -1, -1));\", 0, \"addition overflow\");\n\tEidosAssertScriptRaise(\"cumSum(c(9223372036854775807, 1, 1));\", 0, \"addition overflow\");\n#endif\n\tEidosAssertScriptSuccess_FV(\"cumSum(c(5, 5, 3.0, NAN, 2.0));\", {5.0, 10.0, 13.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(cumSum(matrix(0.5)), matrix(cumSum(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cumSum(matrix(c(0.1, 0.2, 0.3))), matrix(cumSum(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// exp()\n\tEidosAssertScriptSuccess_L(\"abs(exp(0) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(exp(0.0) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(exp(1.0) - E) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(exp(c(0, 1.0, -1)) - c(1, E, 0.3678794))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"exp(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"exp('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"exp(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"exp(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"exp(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"exp(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"exp(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"exp(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"exp(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"exp(c(0, NAN, 0));\", {1, std::numeric_limits<double>::quiet_NaN(), 1});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(exp(matrix(0.5)), matrix(exp(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(exp(matrix(c(0.1, 0.2, 0.3))), matrix(exp(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// floor()\n\tEidosAssertScriptSuccess_F(\"floor(5.1);\", 5.0);\n\tEidosAssertScriptSuccess_F(\"floor(-5.1);\", -6.0);\n\tEidosAssertScriptSuccess_FV(\"floor(c(-2.1, 7.1, -18.8, 12.8));\", {-3.0, 7, -19, 12});\n\tEidosAssertScriptRaise(\"floor(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"floor(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"floor(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"floor(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"floor(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"floor(c(-2.1, 7.1, -18.8, NAN, 12.8));\", {-3.0, 7, -19, std::numeric_limits<double>::quiet_NaN(), 12});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(floor(matrix(0.3)), matrix(floor(0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(floor(matrix(0.6)), matrix(floor(0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(floor(matrix(-0.3)), matrix(floor(-0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(floor(matrix(-0.6)), matrix(floor(-0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(floor(matrix(c(0.1, 5.7, -0.3))), matrix(floor(c(0.1, 5.7, -0.3))));\", true);\n}\n\nvoid _RunFunctionMathTests_g_through_r(void)\n{\n\t// integerDiv()\n\tEidosAssertScriptSuccess_I(\"integerDiv(6, 3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(7, 3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(8, 3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(9, 3);\", 3);\n\tEidosAssertScriptSuccess_IV(\"integerDiv(6:9, 3);\", {2, 2, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"integerDiv(6:9, 2);\", {3, 3, 4, 4});\n\tEidosAssertScriptSuccess_IV(\"integerDiv(-6:-9, 3);\", {-2, -2, -2, -3});\n\tEidosAssertScriptSuccess_IV(\"integerDiv(-6:-9, 2);\", {-3, -3, -4, -4});\n\tEidosAssertScriptSuccess_IV(\"integerDiv(6, 2:6);\", {3, 2, 1, 1, 1});\n\tEidosAssertScriptSuccess_IV(\"integerDiv(8:12, 2:6);\", {4, 3, 2, 2, 2});\n\tEidosAssertScriptSuccess_I(\"integerDiv(-6, 3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-7, 3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-8, 3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-9, 3);\", -3);\n\tEidosAssertScriptSuccess_I(\"integerDiv(6, -3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(7, -3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(8, -3);\", -2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(9, -3);\", -3);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-6, -3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-7, -3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-8, -3);\", 2);\n\tEidosAssertScriptSuccess_I(\"integerDiv(-9, -3);\", 3);\n\tEidosAssertScriptRaise(\"integerDiv(10, 0);\", 0, \"division by 0\");\n\tEidosAssertScriptRaise(\"integerDiv(9:10, 0:1);\", 0, \"division by 0\");\n\tEidosAssertScriptRaise(\"integerDiv(9, 0:1);\", 0, \"division by 0\");\n\tEidosAssertScriptRaise(\"integerDiv(9:10, 0);\", 0, \"division by 0\");\n\tEidosAssertScriptRaise(\"integerDiv(9:10, 1:3);\", 0, \"requires that either\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(5, matrix(2)), matrix(2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(12, matrix(1:3)), matrix(c(12,6,4)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(1:3, matrix(2)), c(0,1,1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(4:6, matrix(1:3)), matrix(c(4,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(matrix(5), matrix(2)), matrix(2));\", true);\n\tEidosAssertScriptRaise(\"identical(integerDiv(matrix(1:3), matrix(2)), matrix(c(0,1,1)));\", 10, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(integerDiv(matrix(4:6,nrow=1), matrix(1:3,ncol=1)), matrix(c(4,2,2)));\", 10, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(integerDiv(matrix(7:9), matrix(1:3)), matrix(c(7,4,3)));\", true);\n\t\n\t// integerMod()\n\tEidosAssertScriptSuccess(\"integerMod(6, 3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"integerMod(7, 3);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"integerMod(8, 3);\", 2);\n\tEidosAssertScriptSuccess(\"integerMod(9, 3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_IV(\"integerMod(6:9, 3);\", {0, 1, 2, 0});\n\tEidosAssertScriptSuccess_IV(\"integerMod(6:9, 2);\", {0, 1, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"integerMod(-6:-9, 3);\", {0, -1, -2, 0});\n\tEidosAssertScriptSuccess_IV(\"integerMod(-6:-9, 2);\", {0, -1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"integerMod(6, 2:6);\", {0, 0, 2, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"integerMod(8:12, 2:6);\", {0, 0, 2, 1, 0});\n\tEidosAssertScriptSuccess(\"integerMod(-6, 3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"integerMod(-7, 3);\", -1);\n\tEidosAssertScriptSuccess_I(\"integerMod(-8, 3);\", -2);\n\tEidosAssertScriptSuccess(\"integerMod(-9, 3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"integerMod(6, -3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"integerMod(7, -3);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"integerMod(8, -3);\", 2);\n\tEidosAssertScriptSuccess(\"integerMod(9, -3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"integerMod(-6, -3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"integerMod(-7, -3);\", -1);\n\tEidosAssertScriptSuccess_I(\"integerMod(-8, -3);\", -2);\n\tEidosAssertScriptSuccess(\"integerMod(-9, -3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptRaise(\"integerMod(10, 0);\", 0, \"modulo by 0\");\n\tEidosAssertScriptRaise(\"integerMod(9:10, 0:1);\", 0, \"modulo by 0\");\n\tEidosAssertScriptRaise(\"integerMod(9, 0:1);\", 0, \"modulo by 0\");\n\tEidosAssertScriptRaise(\"integerMod(9:10, 0);\", 0, \"modulo by 0\");\n\tEidosAssertScriptRaise(\"integerMod(9:10, 1:3);\", 0, \"requires that either\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(5, matrix(2)), matrix(1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(5, matrix(1:3)), matrix(c(0,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(1:3, matrix(2)), c(1,0,1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(4:6, matrix(1:3)), matrix(c(0,1,0)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(matrix(5), matrix(2)), matrix(1));\", true);\n\tEidosAssertScriptRaise(\"identical(integerMod(matrix(1:3), matrix(2)), matrix(c(1,0,1)));\", 10, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(integerMod(matrix(4:6,nrow=1), matrix(1:3,ncol=1)), matrix(c(0,1,0)));\", 10, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(integerMod(matrix(6:8), matrix(1:3)), matrix(c(0,1,2)));\", true);\n\t\n\t// isFinite()\n\tEidosAssertScriptSuccess_L(\"isFinite(0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isFinite(0.05);\", true);\n\tEidosAssertScriptSuccess_L(\"isFinite(INF);\", false);\n\tEidosAssertScriptSuccess_L(\"isFinite(NAN);\", false);\n\tEidosAssertScriptSuccess_LV(\"isFinite(c(5/0, 0/0, 17.0));\", {false, false, true});\t// INF, NAN, normal\n\tEidosAssertScriptRaise(\"isFinite(1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isFinite(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"isFinite(float(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptRaise(\"isFinite(string(0));\", 0, \"cannot be type\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(isFinite(5.0), T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(isFinite(c(5.0, INF, NAN)), c(T,F,F));\", true);\n\tEidosAssertScriptSuccess(\"identical(isFinite(matrix(5.0)), matrix(T));\",gStaticEidosValue_LogicalT);\n\tEidosAssertScriptSuccess_L(\"identical(isFinite(matrix(c(5.0, INF, NAN))), matrix(c(T,F,F)));\", true);\n\t\n\t// isInfinite()\n\tEidosAssertScriptSuccess_L(\"isInfinite(0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isInfinite(0.05);\", false);\n\tEidosAssertScriptSuccess_L(\"isInfinite(INF);\", true);\n\tEidosAssertScriptSuccess_L(\"isInfinite(NAN);\", false);\n\tEidosAssertScriptSuccess_LV(\"isInfinite(c(5/0, 0/0, 17.0));\", {true, false, false});\t// INF, NAN, normal\n\tEidosAssertScriptRaise(\"isInfinite(1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isInfinite(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"isInfinite(float(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptRaise(\"isInfinite(string(0));\", 0, \"cannot be type\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(isInfinite(5.0), F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(isInfinite(c(5.0, INF, NAN)), c(F,T,F));\", true);\n\tEidosAssertScriptSuccess(\"identical(isInfinite(matrix(5.0)), matrix(F));\",gStaticEidosValue_LogicalT);\n\tEidosAssertScriptSuccess_L(\"identical(isInfinite(matrix(c(5.0, INF, NAN))), matrix(c(F,T,F)));\", true);\n\t\n\t// isNAN()\n\tEidosAssertScriptSuccess_L(\"isNAN(0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isNAN(0.05);\", false);\n\tEidosAssertScriptSuccess_L(\"isNAN(INF);\", false);\n\tEidosAssertScriptSuccess_L(\"isNAN(NAN);\", true);\n\tEidosAssertScriptSuccess_LV(\"isNAN(c(5/0, 0/0, 17.0));\", {false, true, false});\t// INF, NAN, normal\n\tEidosAssertScriptRaise(\"isNAN(1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"isNAN(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"isNAN(float(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptRaise(\"isNAN(string(0));\", 0, \"cannot be type\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(isNAN(5.0), F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(isNAN(c(5.0, INF, NAN)), c(F,F,T));\", true);\n\tEidosAssertScriptSuccess(\"identical(isNAN(matrix(5.0)), matrix(F));\",gStaticEidosValue_LogicalT);\n\tEidosAssertScriptSuccess_L(\"identical(isNAN(matrix(c(5.0, INF, NAN))), matrix(c(F,F,T)));\", true);\n\t\n\t// log()\n\tEidosAssertScriptSuccess_L(\"abs(log(1) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log(E) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log(E^3.5) - 3.5) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(log(c(1, E, E^3.5)) - c(0, 1, 3.5))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"log(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"log(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"log(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"log(c(1, NAN, 1));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\tEidosAssertScriptSuccess_FV(\"log(c(1, 1, 1));\", {0, 0, 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(log(matrix(0.5)), matrix(log(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(log(matrix(c(0.1, 0.2, 0.3))), matrix(log(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// log10()\n\tEidosAssertScriptSuccess_L(\"abs(log10(1) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log10(10) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log10(0.001) - -3) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(log10(c(1, 10, 0.001)) - c(0, 1, -3))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"log10(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log10('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log10(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log10(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log10(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log10(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"log10(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"log10(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log10(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"log10(c(1, NAN, 1));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\tEidosAssertScriptSuccess_FV(\"log10(c(1, 1, 1));\", {0, 0, 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(log10(matrix(0.5)), matrix(log10(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(log10(matrix(c(0.1, 0.2, 0.3))), matrix(log10(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// log2()\n\tEidosAssertScriptSuccess_L(\"abs(log2(1) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log2(2) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(log2(0.125) - -3) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(log2(c(1, 2, 0.125)) - c(0, 1, -3))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"log2(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log2('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log2(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log2(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"log2(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log2(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"log2(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"log2(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"log2(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"log2(c(1, NAN, 1));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\tEidosAssertScriptSuccess_FV(\"log2(c(1, 1, 1));\", {0, 0, 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(log2(matrix(0.5)), matrix(log2(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(log2(matrix(c(0.1, 0.2, 0.3))), matrix(log2(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// product()\n\tEidosAssertScriptSuccess_I(\"product(5);\", 5);\n\tEidosAssertScriptSuccess_I(\"product(-5);\", -5);\n\tEidosAssertScriptSuccess_I(\"product(c(-2, 7, -18, 12));\", 3024);\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptSuccess_F(\"product(c(200000000, 3000000000000, 1000));\", 6e23);\n#endif\n\tEidosAssertScriptSuccess_F(\"product(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"product(-5.5);\", -5.5);\n\tEidosAssertScriptSuccess_F(\"product(c(-2.5, 7.5, -18.5, 12.5));\", (-2.5*7.5*-18.5*12.5));\n\tEidosAssertScriptRaise(\"product(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"product('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"product(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"product(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"product(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"product(integer(0));\", gStaticEidosValue_Integer1);\t// product of no elements is 1 (as in R)\n\tEidosAssertScriptSuccess(\"product(float(0));\", gStaticEidosValue_Float1);\n\tEidosAssertScriptRaise(\"product(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"product(c(5.0, 2.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\tEidosAssertScriptSuccess_I(\"product(matrix(5));\", 5);\n\tEidosAssertScriptSuccess_I(\"product(matrix(c(5, -5)));\", -25);\n\tEidosAssertScriptSuccess_I(\"product(array(c(5, -5, 3), c(1,3,1)));\", -75);\n\t\n\t// round()\n\tEidosAssertScriptSuccess_F(\"round(5.1);\", 5.0);\n\tEidosAssertScriptSuccess_F(\"round(-5.1);\", -5.0);\n\tEidosAssertScriptSuccess_FV(\"round(c(-2.1, 7.1, -18.8, 12.8));\", {-2.0, 7, -19, 13});\n\tEidosAssertScriptRaise(\"round(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"round(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"round(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"round(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"round(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"round(c(-2.1, 7.1, -18.8, NAN, 12.8));\", {-2.0, 7, -19, std::numeric_limits<double>::quiet_NaN(), 13});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(round(matrix(0.3)), matrix(round(0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(round(matrix(0.6)), matrix(round(0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(round(matrix(-0.3)), matrix(round(-0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(round(matrix(-0.6)), matrix(round(-0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(round(matrix(c(0.1, 5.7, -0.3))), matrix(round(c(0.1, 5.7, -0.3))));\", true);\n}\n\nvoid _RunFunctionMathTests_setUnionIntersection(void)\n{\n\t// setUnion()\n\tEidosAssertScriptSuccess_NULL(\"setUnion(NULL, NULL);\");\n\tEidosAssertScriptSuccess(\"setUnion(logical(0), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setUnion(integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setUnion(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setUnion(string(0), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setUnion(object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess(\"size(setUnion(_Test(7)[F], object()));\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"size(setUnion(object(), _Test(7)[F]));\", gStaticEidosValue_Integer0);\n\t\n\tEidosAssertScriptRaise(\"setUnion(NULL, logical(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setUnion(logical(0), integer(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setUnion(integer(0), float(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setUnion(float(0), string(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setUnion(string(0), object());\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setUnion(object(), NULL);\", 0, \"requires that both operands\");\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(T, logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"setUnion(logical(0), T);\", true);\n\tEidosAssertScriptSuccess_L(\"setUnion(F, logical(0));\", false);\n\tEidosAssertScriptSuccess_L(\"setUnion(logical(0), F);\", false);\n\tEidosAssertScriptSuccess_I(\"setUnion(7, integer(0));\", 7);\n\tEidosAssertScriptSuccess_I(\"setUnion(integer(0), 7);\", 7);\n\tEidosAssertScriptSuccess_F(\"setUnion(3.2, float(0));\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setUnion(float(0), 3.2);\", 3.2);\n\tEidosAssertScriptSuccess_S(\"setUnion('foo', string(0));\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setUnion(string(0), 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"setUnion(_Test(7), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"setUnion(object(), _Test(7))._yolk;\", 7);\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(c(T, T, T), logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"setUnion(logical(0), c(F, F, F));\", false);\n\tEidosAssertScriptSuccess_LV(\"setUnion(c(F, F, T), logical(0));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setUnion(logical(0), c(F, F, T));\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setUnion(c(7, 7, 7), integer(0));\", 7);\n\tEidosAssertScriptSuccess_I(\"setUnion(integer(0), c(7, 7, 7));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setUnion(c(7, 8, 7), integer(0));\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setUnion(integer(0), c(7, 7, 8));\", {7, 8});\n\tEidosAssertScriptSuccess_F(\"setUnion(c(3.2, 3.2, 3.2), float(0));\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setUnion(float(0), c(3.2, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(4.2, 3.2, 3.2), float(0));\", {4.2, 3.2});\n\tEidosAssertScriptSuccess_FV(\"setUnion(float(0), c(3.2, 4.2, 3.2));\", {3.2, 4.2});\n\tEidosAssertScriptSuccess_S(\"setUnion(c('foo', 'foo', 'foo'), string(0));\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setUnion(string(0), c('foo', 'foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setUnion(c('foo', 'bar', 'foo'), string(0));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setUnion(string(0), c('foo', 'foo', 'bar'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(c(x, x, x), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(object(), c(x, x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(c(y, x, x), object())._yolk;\", {9, 7});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(object(), c(x, x, y))._yolk;\", {7, 9});\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(T, T);\", true);\n\tEidosAssertScriptSuccess_LV(\"setUnion(F, T);\", {false, true});\n\tEidosAssertScriptSuccess_L(\"setUnion(F, F);\", false);\n\tEidosAssertScriptSuccess_LV(\"setUnion(T, F);\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setUnion(7, 7);\", 7);\n\tEidosAssertScriptSuccess_IV(\"setUnion(8, 7);\", {8, 7});\n\tEidosAssertScriptSuccess_F(\"setUnion(3.2, 3.2);\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setUnion(2.3, 3.2);\", {2.3, 3.2});\n\tEidosAssertScriptSuccess_S(\"setUnion('foo', 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setUnion('bar', 'foo');\", {\"bar\", \"foo\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(x, x)._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(x, y)._yolk;\", {7, 9});\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(T, c(T, T));\", true);\n\tEidosAssertScriptSuccess_LV(\"setUnion(F, c(T, T));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setUnion(F, c(F, T));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setUnion(T, c(F, F));\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setUnion(7, c(7, 7));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setUnion(8, c(7, 7));\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setUnion(8, c(7, 8));\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setUnion(8, c(7, 9));\", {7, 9, 8});\n\tEidosAssertScriptSuccess_F(\"setUnion(3.2, c(3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setUnion(2.3, c(3.2, 3.2));\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_FV(\"setUnion(2.3, c(3.2, 2.3));\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_FV(\"setUnion(2.3, c(3.2, 7.6));\", {3.2, 7.6, 2.3});\n\tEidosAssertScriptSuccess_S(\"setUnion('foo', c('foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setUnion('bar', c('foo', 'foo'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setUnion('bar', c('foo', 'bar'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setUnion('bar', c('foo', 'baz'));\", {\"foo\", \"baz\", \"bar\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(x, c(x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(y, c(x, x))._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(y, c(x, y))._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); setUnion(y, c(x, z))._yolk;\", {7, -5, 9});\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(c(T, T), T);\", true);\n\tEidosAssertScriptSuccess_LV(\"setUnion(c(T, T), F);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setUnion(c(F, T), F);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setUnion(c(F, F), T);\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setUnion(c(7, 7), 7);\", 7);\n\tEidosAssertScriptSuccess_IV(\"setUnion(c(7, 7), 8);\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setUnion(c(7, 8), 8);\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setUnion(c(7, 9), 8);\", {7, 9, 8});\n\tEidosAssertScriptSuccess_F(\"setUnion(c(3.2, 3.2), 3.2);\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 3.2), 2.3);\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 2.3), 2.3);\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 7.6), 2.3);\", {3.2, 7.6, 2.3});\n\tEidosAssertScriptSuccess_S(\"setUnion(c('foo', 'foo'), 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setUnion(c('foo', 'foo'), 'bar');\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setUnion(c('foo', 'bar'), 'bar');\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setUnion(c('foo', 'baz'), 'bar');\", {\"foo\", \"baz\", \"bar\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(c(x, x), x)._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(c(x, x), y)._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setUnion(c(x, y), y)._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); setUnion(c(x, z), y)._yolk;\", {7, -5, 9});\n\t\n\tEidosAssertScriptSuccess_L(\"setUnion(c(T, T, T, T), c(T, T, T, T));\", true);\n\tEidosAssertScriptSuccess_LV(\"setUnion(c(T, T, T, T), c(T, T, T, F));\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setUnion(c(7, 7, 7, 7), c(7, 7, 7, 7));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setUnion(c(7, 10, 7, 8), c(7, 9, 7, 7));\", {7, 10, 8, 9});\n\tEidosAssertScriptSuccess_F(\"setUnion(c(3.2, 3.2, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 6.0, 7.9, 3.2), c(5.5, 6.0, 3.2, 3.2));\", {3.2, 6.0, 7.9, 5.5});\n\tEidosAssertScriptSuccess_S(\"setUnion(c('foo', 'foo', 'foo', 'foo'), c('foo', 'foo', 'foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setUnion(c('foo', 'bar', 'foo', 'foobaz'), c('foo', 'foo', 'baz', 'foo'));\", {\"foo\", \"bar\", \"foobaz\", \"baz\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setUnion(c(x, x, x, x), c(x, x, x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); q = _Test(26); setUnion(c(x, y, x, q), c(x, x, z, x))._yolk;\", {7, 9, 26, -5});\n\t\n\tEidosAssertScriptSuccess_FV(\"setUnion(NAN, NAN);\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, NAN, NAN, 3.2), NAN);\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, NAN, NAN, 3.2), 3.2);\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(NAN, c(3.2, NAN, NAN, 3.2));\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(3.2, c(3.2, NAN, NAN, 3.2));\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, NAN, 3.2, 3.2, 3.2));\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 6.0, NAN, NAN, 7.9, 3.2), c(5.5, 6.0, 3.2, 3.2));\", {3.2, 6.0, std::numeric_limits<double>::quiet_NaN(), 7.9, 5.5});\n\tEidosAssertScriptSuccess_FV(\"setUnion(c(3.2, 6.0, NAN, NAN, 7.9, 3.2), c(5.5, NAN, 6.0, 3.2, 3.2));\", {3.2, 6.0, std::numeric_limits<double>::quiet_NaN(), 7.9, 5.5});\n\t\n\t// setIntersection()\n\tEidosAssertScriptSuccess_NULL(\"setIntersection(NULL, NULL);\");\n\tEidosAssertScriptSuccess(\"setIntersection(logical(0), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(string(0), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\t\n\tEidosAssertScriptRaise(\"setIntersection(NULL, logical(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setIntersection(logical(0), integer(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setIntersection(integer(0), float(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setIntersection(float(0), string(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setIntersection(string(0), object());\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setIntersection(object(), NULL);\", 0, \"requires that both operands\");\n\t\n\tEidosAssertScriptSuccess(\"setIntersection(T, logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(logical(0), T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(F, logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(logical(0), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(7, integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(integer(0), 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(3.2, float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(float(0), 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection('foo', string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(string(0), 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(_Test(7), object())._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(object(), _Test(7))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess(\"setIntersection(c(T, T, T), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(logical(0), c(F, F, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c(F, F, T), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(logical(0), c(F, F, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c(7, 7, 7), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(integer(0), c(7, 7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c(7, 8, 7), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(integer(0), c(7, 7, 8));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c(3.2, 3.2, 3.2), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(float(0), c(3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c(4.2, 3.2, 3.2), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(float(0), c(3.2, 4.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c('foo', 'foo', 'foo'), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(string(0), c('foo', 'foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(c('foo', 'bar', 'foo'), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setIntersection(string(0), c('foo', 'foo', 'bar'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(c(x, x, x), object())._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(object(), c(x, x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(c(y, x, x), object())._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(object(), c(x, x, y))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess_L(\"setIntersection(T, T);\", true);\n\tEidosAssertScriptSuccess(\"setIntersection(F, T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setIntersection(F, F);\", false);\n\tEidosAssertScriptSuccess(\"setIntersection(T, F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setIntersection(7, 7);\", 7);\n\tEidosAssertScriptSuccess(\"setIntersection(8, 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setIntersection(3.2, 3.2);\", 3.2);\n\tEidosAssertScriptSuccess(\"setIntersection(2.3, 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setIntersection('foo', 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess(\"setIntersection('bar', 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(x, x)._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(x, y)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess_L(\"setIntersection(T, c(T, T));\", true);\n\tEidosAssertScriptSuccess(\"setIntersection(F, c(T, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setIntersection(F, c(F, T));\", false);\n\tEidosAssertScriptSuccess(\"setIntersection(T, c(F, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setIntersection(7, c(7, 7));\", 7);\n\tEidosAssertScriptSuccess(\"setIntersection(8, c(7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setIntersection(8, c(7, 8));\", 8);\n\tEidosAssertScriptSuccess(\"setIntersection(8, c(7, 9));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setIntersection(3.2, c(3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess(\"setIntersection(2.3, c(3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setIntersection(2.3, c(3.2, 2.3));\", 2.3);\n\tEidosAssertScriptSuccess(\"setIntersection(2.3, c(3.2, 7.6));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setIntersection('foo', c('foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess(\"setIntersection('bar', c('foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setIntersection('bar', c('foo', 'bar'));\", \"bar\");\n\tEidosAssertScriptSuccess(\"setIntersection('bar', c('foo', 'baz'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(x, c(x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(y, c(x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(y, c(x, y))._yolk;\", 9);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); z = _Test(-5); setIntersection(y, c(x, z))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess_L(\"setIntersection(c(T, T), T);\", true);\n\tEidosAssertScriptSuccess(\"setIntersection(c(T, T), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setIntersection(c(F, T), F);\", false);\n\tEidosAssertScriptSuccess(\"setIntersection(c(F, F), T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setIntersection(c(7, 7), 7);\", 7);\n\tEidosAssertScriptSuccess(\"setIntersection(c(7, 7), 8);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setIntersection(c(7, 8), 8);\", 8);\n\tEidosAssertScriptSuccess(\"setIntersection(c(7, 9), 8);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setIntersection(c(3.2, 3.2), 3.2);\", 3.2);\n\tEidosAssertScriptSuccess(\"setIntersection(c(3.2, 3.2), 2.3);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setIntersection(c(3.2, 2.3), 2.3);\", 2.3);\n\tEidosAssertScriptSuccess(\"setIntersection(c(3.2, 7.6), 2.3);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setIntersection(c('foo', 'foo'), 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess(\"setIntersection(c('foo', 'foo'), 'bar');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setIntersection(c('foo', 'bar'), 'bar');\", \"bar\");\n\tEidosAssertScriptSuccess(\"setIntersection(c('foo', 'baz'), 'bar');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(c(x, x), x)._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setIntersection(c(x, x), y)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(c(x, y), y)._yolk;\", 9);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); z = _Test(-5); setIntersection(c(x, z), y)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess_L(\"setIntersection(c(T, T, T, T), c(T, T, T, T));\", true);\n\tEidosAssertScriptSuccess_L(\"setIntersection(c(T, T, T, T), c(T, T, T, F));\", true);\n\tEidosAssertScriptSuccess_LV(\"setIntersection(c(T, T, F, T), c(T, T, T, F));\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setIntersection(c(7, 7, 7, 7), c(7, 7, 7, 7));\", 7);\n\tEidosAssertScriptSuccess_I(\"setIntersection(c(7, 10, 7, 8), c(7, 9, 7, 7));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setIntersection(c(7, 10, 7, 8), c(7, 9, 8, 7));\", {7, 8});\n\tEidosAssertScriptSuccess_F(\"setIntersection(c(3.2, 3.2, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setIntersection(c(3.2, 6.0, 7.9, 3.2), c(5.5, 1.3, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, 6.0, 7.9, 3.2), c(5.5, 6.0, 3.2, 3.2));\", {3.2, 6.0});\n\tEidosAssertScriptSuccess_S(\"setIntersection(c('foo', 'foo', 'foo', 'foo'), c('foo', 'foo', 'foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setIntersection(c('foo', 'bar', 'foo', 'foobaz'), c('foo', 'foo', 'baz', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setIntersection(c('foo', 'bar', 'foo', 'foobaz'), c('bar', 'foo', 'baz', 'foo'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setIntersection(c(x, x, x, x), c(x, x, x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); z = _Test(-5); q = _Test(26); setIntersection(c(x, y, x, q), c(x, x, z, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); q = _Test(26); setIntersection(c(x, y, x, q), c(y, x, z, x))._yolk;\", {7, 9});\n\t\n\tEidosAssertScriptSuccess_FV(\"setIntersection(NAN, NAN);\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, NAN, NAN, 3.2), NAN);\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, NAN, NAN, 3.2), 3.2);\", {3.2});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(NAN, c(3.2, NAN, NAN, 3.2));\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(3.2, c(3.2, NAN, NAN, 3.2));\", {3.2});\n\tEidosAssertScriptSuccess_F(\"setIntersection(c(3.2, 3.2, 3.2, NAN, NAN, 3.2), c(3.2, 3.2, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, 3.2, 3.2, NAN, NAN, 3.2), c(3.2, NAN, 3.2, 3.2, 3.2));\", {3.2, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, 6.0, 7.9, NAN, NAN, 3.2), c(5.5, 6.0, 3.2, 3.2));\", {3.2, 6.0});\n\tEidosAssertScriptSuccess_FV(\"setIntersection(c(3.2, 6.0, 7.9, NAN, NAN, 3.2), c(5.5, NAN, 6.0, 3.2, 3.2));\", {3.2, 6.0, std::numeric_limits<double>::quiet_NaN()});\n}\n\nvoid _RunFunctionMathTests_setDifferenceSymmetricDifference(void)\n{\n\t// setDifference()\n\tEidosAssertScriptSuccess_NULL(\"setDifference(NULL, NULL);\");\n\tEidosAssertScriptSuccess(\"setDifference(logical(0), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(string(0), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\t\n\tEidosAssertScriptRaise(\"setDifference(NULL, logical(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setDifference(logical(0), integer(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setDifference(integer(0), float(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setDifference(float(0), string(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setDifference(string(0), object());\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setDifference(object(), NULL);\", 0, \"requires that both operands\");\n\t\n\tEidosAssertScriptSuccess_L(\"setDifference(T, logical(0));\", true);\n\tEidosAssertScriptSuccess(\"setDifference(logical(0), T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(F, logical(0));\", false);\n\tEidosAssertScriptSuccess(\"setDifference(logical(0), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(7, integer(0));\", 7);\n\tEidosAssertScriptSuccess(\"setDifference(integer(0), 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(3.2, float(0));\", 3.2);\n\tEidosAssertScriptSuccess(\"setDifference(float(0), 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference('foo', string(0));\", \"foo\");\n\tEidosAssertScriptSuccess(\"setDifference(string(0), 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(_Test(7), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"setDifference(object(), _Test(7))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess_L(\"setDifference(c(T, T, T), logical(0));\", true);\n\tEidosAssertScriptSuccess(\"setDifference(logical(0), c(F, F, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setDifference(c(F, F, T), logical(0));\", {false, true});\n\tEidosAssertScriptSuccess(\"setDifference(logical(0), c(F, F, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(c(7, 7, 7), integer(0));\", 7);\n\tEidosAssertScriptSuccess(\"setDifference(integer(0), c(7, 7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setDifference(c(7, 8, 7), integer(0));\", {7, 8});\n\tEidosAssertScriptSuccess(\"setDifference(integer(0), c(7, 7, 8));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(c(3.2, 3.2, 3.2), float(0));\", 3.2);\n\tEidosAssertScriptSuccess(\"setDifference(float(0), c(3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setDifference(c(4.2, 3.2, 3.2), float(0));\", {4.2, 3.2});\n\tEidosAssertScriptSuccess(\"setDifference(float(0), c(3.2, 4.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference(c('foo', 'foo', 'foo'), string(0));\", \"foo\");\n\tEidosAssertScriptSuccess(\"setDifference(string(0), c('foo', 'foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setDifference(c('foo', 'bar', 'foo'), string(0));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess(\"setDifference(string(0), c('foo', 'foo', 'bar'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setDifference(c(x, x, x), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(object(), c(x, x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setDifference(c(y, x, x), object())._yolk;\", {9, 7});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(object(), c(x, x, y))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\t\n\tEidosAssertScriptSuccess(\"setDifference(T, T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(F, T);\", false);\n\tEidosAssertScriptSuccess(\"setDifference(F, F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(T, F);\", true);\n\tEidosAssertScriptSuccess(\"setDifference(7, 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(8, 7);\", 8);\n\tEidosAssertScriptSuccess(\"setDifference(3.2, 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(2.3, 3.2);\", 2.3);\n\tEidosAssertScriptSuccess(\"setDifference('foo', 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference('bar', 'foo');\", \"bar\");\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(x, x)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setDifference(x, y)._yolk;\", 7);\n\t\n\tEidosAssertScriptSuccess(\"setDifference(T, c(T, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(F, c(T, T));\", false);\n\tEidosAssertScriptSuccess(\"setDifference(F, c(F, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(T, c(F, F));\", true);\n\tEidosAssertScriptSuccess(\"setDifference(7, c(7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(8, c(7, 7));\", 8);\n\tEidosAssertScriptSuccess(\"setDifference(8, c(7, 8));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(8, c(7, 9));\", 8);\n\tEidosAssertScriptSuccess(\"setDifference(3.2, c(3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(2.3, c(3.2, 3.2));\", 2.3);\n\tEidosAssertScriptSuccess(\"setDifference(2.3, c(3.2, 2.3));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(2.3, c(3.2, 7.6));\", 2.3);\n\tEidosAssertScriptSuccess(\"setDifference('foo', c('foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference('bar', c('foo', 'foo'));\", \"bar\");\n\tEidosAssertScriptSuccess(\"setDifference('bar', c('foo', 'bar'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference('bar', c('foo', 'baz'));\", \"bar\");\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(x, c(x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setDifference(y, c(x, x))._yolk;\", 9);\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(y, c(x, y))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); z = _Test(-5); setDifference(y, c(x, z))._yolk;\", 9);\n\t\n\tEidosAssertScriptSuccess(\"setDifference(c(T, T), T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setDifference(c(T, T), F);\", true);\n\tEidosAssertScriptSuccess_L(\"setDifference(c(F, T), F);\", true);\n\tEidosAssertScriptSuccess_L(\"setDifference(c(F, F), T);\", false);\n\tEidosAssertScriptSuccess(\"setDifference(c(7, 7), 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"setDifference(c(7, 7), 8);\", 7);\n\tEidosAssertScriptSuccess_I(\"setDifference(c(7, 8), 8);\", 7);\n\tEidosAssertScriptSuccess_IV(\"setDifference(c(7, 9), 8);\", {7, 9});\n\tEidosAssertScriptSuccess(\"setDifference(c(3.2, 3.2), 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(c(3.2, 3.2), 2.3);\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setDifference(c(3.2, 2.3), 2.3);\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setDifference(c(3.2, 7.6), 2.3);\", {3.2, 7.6});\n\tEidosAssertScriptSuccess(\"setDifference(c('foo', 'foo'), 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"setDifference(c('foo', 'foo'), 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setDifference(c('foo', 'bar'), 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setDifference(c('foo', 'baz'), 'bar');\", {\"foo\", \"baz\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(c(x, x), x)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setDifference(c(x, x), y)._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setDifference(c(x, y), y)._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); setDifference(c(x, z), y)._yolk;\", {7, -5});\n\t\n\tEidosAssertScriptSuccess(\"setDifference(c(T, T, T, T), c(T, T, T, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(c(T, T, T, T), c(T, T, T, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(c(T, T, F, F), c(T, T, T, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(c(7, 7, 7, 7), c(7, 7, 7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setDifference(c(7, 10, 7, 10, 8), c(7, 9, 7, 7));\", {10, 8});\n\tEidosAssertScriptSuccess(\"setDifference(c(3.2, 3.2, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"setDifference(c(3.2, 6.0, 7.9, 3.2, 7.9), c(5.5, 6.0, 3.2, 3.2));\", 7.9);\n\tEidosAssertScriptSuccess(\"setDifference(c('foo', 'foo', 'foo', 'foo'), c('foo', 'foo', 'foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setDifference(c('foo', 'bar', 'foobaz', 'foo', 'foobaz'), c('foo', 'foo', 'baz', 'foo'));\", {\"bar\", \"foobaz\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setDifference(c(x, x, x, x), c(x, x, x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); q = _Test(26); setDifference(c(x, y, q, x, q), c(x, x, z, x))._yolk;\", {9, 26});\n\t\n\tEidosAssertScriptSuccess(\"setDifference(NAN, NAN);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setDifference(c(3.2, NAN, NAN, 3.2), NAN);\", {3.2});\n\tEidosAssertScriptSuccess_FV(\"setDifference(c(3.2, NAN, NAN, 3.2), 3.2);\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess(\"setDifference(NAN, c(3.2, NAN, NAN, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(3.2, c(3.2, NAN, NAN, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setDifference(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"setDifference(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, NAN, 3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setDifference(c(3.2, 6.0, NAN, NAN, 7.9, 3.2, 7.9), c(5.5, 6.0, 3.2, 3.2));\", {std::numeric_limits<double>::quiet_NaN(), 7.9});\n\tEidosAssertScriptSuccess_F(\"setDifference(c(3.2, 6.0, NAN, NAN, 7.9, 3.2, 7.9), c(5.5, NAN, 6.0, 3.2, 3.2));\", 7.9);\n\t\n\t// setSymmetricDifference()\n\tEidosAssertScriptSuccess_NULL(\"setSymmetricDifference(NULL, NULL);\");\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(logical(0), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(string(0), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess(\"size(setSymmetricDifference(_Test(7)[F], object()));\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"size(setSymmetricDifference(object(), _Test(7)[F]));\", gStaticEidosValue_Integer0);\n\t\n\tEidosAssertScriptRaise(\"setSymmetricDifference(NULL, logical(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setSymmetricDifference(logical(0), integer(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setSymmetricDifference(integer(0), float(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setSymmetricDifference(float(0), string(0));\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setSymmetricDifference(string(0), object());\", 0, \"requires that both operands\");\n\tEidosAssertScriptRaise(\"setSymmetricDifference(object(), NULL);\", 0, \"requires that both operands\");\n\t\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(T, logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(logical(0), T);\", true);\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(F, logical(0));\", false);\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(logical(0), F);\", false);\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(7, integer(0));\", 7);\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(integer(0), 7);\", 7);\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(3.2, float(0));\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(float(0), 3.2);\", 3.2);\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference('foo', string(0));\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference(string(0), 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(_Test(7), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(object(), _Test(7))._yolk;\", 7);\n\t\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(c(T, T, T), logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(logical(0), c(F, F, F));\", false);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(c(F, F, T), logical(0));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(logical(0), c(F, F, T));\", {false, true});\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(c(7, 7, 7), integer(0));\", 7);\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(integer(0), c(7, 7, 7));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(c(7, 8, 7), integer(0));\", {7, 8});\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(integer(0), c(7, 7, 8));\", {7, 8});\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(c(3.2, 3.2, 3.2), float(0));\", 3.2);\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(float(0), c(3.2, 3.2, 3.2));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(4.2, 3.2, 3.2), float(0));\", {4.2, 3.2});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(float(0), c(3.2, 4.2, 3.2));\", {3.2, 4.2});\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference(c('foo', 'foo', 'foo'), string(0));\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference(string(0), c('foo', 'foo', 'foo'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference(c('foo', 'bar', 'foo'), string(0));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference(string(0), c('foo', 'foo', 'bar'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(x, x, x), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setSymmetricDifference(object(), c(x, x, x))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(y, x, x), object())._yolk;\", {9, 7});\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setSymmetricDifference(object(), c(x, x, y))._yolk;\", {7, 9});\n\t\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(T, T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(F, T);\", {false, true});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(F, F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(T, F);\", {false, true});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(7, 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(8, 7);\", {8, 7});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(3.2, 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(2.3, 3.2);\", {2.3, 3.2});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference('foo', 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference('bar', 'foo');\", {\"bar\", \"foo\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setSymmetricDifference(x, x)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setSymmetricDifference(x, y)._yolk;\", {7, 9});\n\t\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(T, c(T, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(F, c(T, T));\", {false, true});\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(F, c(F, T));\", true);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(T, c(F, F));\", {false, true});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(7, c(7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(8, c(7, 7));\", {7, 8});\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(8, c(7, 8));\", 7);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(8, c(7, 9));\", {7, 9, 8});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(3.2, c(3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(2.3, c(3.2, 3.2));\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(2.3, c(3.2, 2.3));\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(2.3, c(3.2, 7.6));\", {3.2, 7.6, 2.3});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference('foo', c('foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference('bar', c('foo', 'foo'));\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference('bar', c('foo', 'bar'));\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference('bar', c('foo', 'baz'));\", {\"foo\", \"baz\", \"bar\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setSymmetricDifference(x, c(x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setSymmetricDifference(y, c(x, x))._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setSymmetricDifference(y, c(x, y))._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); setSymmetricDifference(y, c(x, z))._yolk;\", {7, -5, 9});\n\t\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(T, T), T);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(c(T, T), F);\", {false, true});\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(c(F, T), F);\", true);\n\tEidosAssertScriptSuccess_LV(\"setSymmetricDifference(c(F, F), T);\", {false, true});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(7, 7), 7);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(c(7, 7), 8);\", {7, 8});\n\tEidosAssertScriptSuccess_I(\"setSymmetricDifference(c(7, 8), 8);\", 7);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(c(7, 9), 8);\", {7, 9, 8});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(3.2, 3.2), 3.2);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(3.2, 3.2), 2.3);\", {3.2, 2.3});\n\tEidosAssertScriptSuccess_F(\"setSymmetricDifference(c(3.2, 2.3), 2.3);\", 3.2);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(3.2, 7.6), 2.3);\", {3.2, 7.6, 2.3});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c('foo', 'foo'), 'foo');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference(c('foo', 'foo'), 'bar');\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_S(\"setSymmetricDifference(c('foo', 'bar'), 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference(c('foo', 'baz'), 'bar');\", {\"foo\", \"baz\", \"bar\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(x, x), x)._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(x, x), y)._yolk;\", {7, 9});\n\tEidosAssertScriptSuccess_I(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(x, y), y)._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); setSymmetricDifference(c(x, z), y)._yolk;\", {7, -5, 9});\n\t\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(T, T, T, T), c(T, T, T, T));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSymmetricDifference(c(T, T, T, T), c(T, T, T, F));\", false);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(T, T, F, T), c(T, T, T, F));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(7, 7, 7, 7), c(7, 7, 7, 7));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSymmetricDifference(c(7, 10, 7, 10, 8), c(7, 9, 7, 9, 7));\", {10, 8, 9});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(3.2, 3.2, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(7.3, 10.5, 7.3, 10.5, 8.9), c(7.3, 9.7, 7.3, 9.7, 7.3));\", {10.5, 8.9, 9.7});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c('foo', 'foo', 'foo', 'foo'), c('foo', 'foo', 'foo', 'foo'));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"setSymmetricDifference(c('foo', 'bar', 'foo', 'bar', 'foobaz'), c('foo', 'baz', 'foo', 'baz', 'foo'));\", {\"bar\", \"foobaz\", \"baz\"});\n\tEidosAssertScriptSuccess(\"x = _Test(7); y = _Test(9); setSymmetricDifference(c(x, x, x, x), c(x, x, x, x))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"x = _Test(7); y = _Test(9); z = _Test(-5); q = _Test(26); setSymmetricDifference(c(x, y, x, y, z), c(x, q, x, q, x))._yolk;\", {9, -5, 26});\n\t\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(NAN, NAN);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(3.2, NAN, NAN, 3.2), NAN);\", {3.2});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(3.2, NAN, NAN, 3.2), 3.2);\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(NAN, c(3.2, NAN, NAN, 3.2));\", {3.2});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(3.2, c(3.2, NAN, NAN, 3.2));\", {std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, 3.2, 3.2, 3.2));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(3.2, 3.2, NAN, NAN, 3.2, 3.2), c(3.2, NAN, 3.2, 3.2, 3.2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"setSymmetricDifference(c(3.2, 3.2, 3.2, 3.2), c(3.2, NAN, NAN, 3.2, 3.2, 3.2));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(7.3, 10.5, NAN, NAN, 7.3, 10.5, 8.9), c(7.3, 9.7, 7.3, 9.7, 7.3));\", {10.5, std::numeric_limits<double>::quiet_NaN(), 8.9, 9.7});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(7.3, 10.5, NAN, NAN, 7.3, 10.5, 8.9), c(7.3, NAN, 9.7, 7.3, 9.7, 7.3));\", {10.5, 8.9, 9.7});\n\tEidosAssertScriptSuccess_FV(\"setSymmetricDifference(c(7.3, 10.5, 7.3, 10.5, 8.9), c(7.3, NAN, NAN, 9.7, 7.3, 9.7, 7.3));\", {10.5, 8.9, std::numeric_limits<double>::quiet_NaN(), 9.7});\n}\n\nvoid _RunFunctionMathTests_s_through_z(void)\n{\n\t// sign()\n\tEidosAssertScriptSuccess_L(\"identical(sign(-10), -1);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(10), 1);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(0), 0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(-10.0), -1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(10.0), 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(0.0), 0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(NAN), NAN);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(INF), 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sign(-INF), -1.0);\", true);\n\t\n\t// sin()\n\tEidosAssertScriptSuccess_L(\"abs(sin(0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(sin(0.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(sin(PI/2) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(sin(c(0, PI/2, PI)) - c(0, 1, 0))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"sin(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sin('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sin(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sin(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sin(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sin(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"sin(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"sin(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sin(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"sin(c(0, NAN, 0));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sin(matrix(0.5)), matrix(sin(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sin(matrix(c(0.1, 0.2, 0.3))), matrix(sin(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// sqrt()\n\tEidosAssertScriptSuccess_F(\"sqrt(64);\", 8);\n\tEidosAssertScriptSuccess_L(\"isNAN(sqrt(-64));\", true);\n\tEidosAssertScriptSuccess_FV(\"sqrt(c(4, -16, 9, 1024));\", {2, NAN, 3, 32});\n\tEidosAssertScriptSuccess_F(\"sqrt(64.0);\", 8);\n\tEidosAssertScriptSuccess_L(\"isNAN(sqrt(-64.0));\", true);\n\tEidosAssertScriptSuccess_FV(\"sqrt(c(4.0, -16.0, 9.0, 1024.0));\", {2, NAN, 3, 32});\n\tEidosAssertScriptRaise(\"sqrt(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sqrt('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sqrt(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sqrt(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sqrt(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sqrt(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"sqrt(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"sqrt(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sqrt(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"sqrt(c(64, NAN, 9));\", {8, std::numeric_limits<double>::quiet_NaN(), 3});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sqrt(matrix(0.5)), matrix(sqrt(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sqrt(matrix(c(0.1, 0.2, 0.3))), matrix(sqrt(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// sum()\n\tEidosAssertScriptSuccess_I(\"sum(5);\", 5);\n\tEidosAssertScriptSuccess_I(\"sum(-5);\", -5);\n\tEidosAssertScriptSuccess_I(\"sum(c(-2, 7, -18, 12));\", -1);\n\tEidosAssertScriptSuccess_I(\"sum(c(200000000, 3000000000000));\", 3000200000000);\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptSuccess_F(\"sum(rep(3000000000000000000, 100));\", 3e20);\n#endif\n\tEidosAssertScriptSuccess_F(\"sum(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"sum(-5.5);\", -5.5);\n\tEidosAssertScriptSuccess_F(\"sum(c(-2.5, 7.5, -18.5, 12.5));\", -1);\n\tEidosAssertScriptSuccess(\"sum(T);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"sum(c(T,F,T,F,T,T,T,F));\", 5);\n\tEidosAssertScriptRaise(\"sum('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sum(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sum(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sum(logical(0));\", gStaticEidosValue_Integer0);\t// sum of no elements is 0 (as in R)\n\tEidosAssertScriptSuccess(\"sum(integer(0));\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"sum(float(0));\", gStaticEidosValue_Float0);\n\tEidosAssertScriptRaise(\"sum(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sum(c(5.0, 2.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\tEidosAssertScriptSuccess_I(\"sum(matrix(5));\", 5);\n\tEidosAssertScriptSuccess_I(\"sum(matrix(c(5, -5)));\", 0);\n\tEidosAssertScriptSuccess_I(\"sum(array(c(5, -5, 3), c(1,3,1)));\", 3);\n\t\n\t// sumExact()\n\tEidosAssertScriptSuccess_F(\"sumExact(5.5);\", 5.5);\n\tEidosAssertScriptSuccess_F(\"sumExact(-5.5);\", -5.5);\n\tEidosAssertScriptSuccess_F(\"sumExact(c(-2.5, 7.5, -18.5, 12.5));\", -1);\n\tEidosAssertScriptRaise(\"sumExact(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sumExact(1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sumExact('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sumExact(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sumExact(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sumExact(float(0));\", gStaticEidosValue_Float0);\n\tEidosAssertScriptSuccess_F(\"v = c(1, 1.0e100, 1, -1.0e100); v = rep(v, 10000); sumExact(v);\", 20000);\n\tEidosAssertScriptSuccess_F(\"v = c(-1, 1.0e100, -1, -1.0e100); v = rep(v, 10000); sumExact(v);\", -20000);\n\tEidosAssertScriptSuccess_F(\"v = c(-1, 1.0e100, 1, -1.0e100); v = rep(v, 10000); sumExact(v);\", 0);\n\tEidosAssertScriptSuccess(\"sumExact(c(5.0, 2.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\tEidosAssertScriptSuccess_F(\"sumExact(matrix(5.0));\", 5.0);\n\tEidosAssertScriptSuccess_F(\"sumExact(matrix(c(5.0, -5)));\", 0.0);\n\tEidosAssertScriptSuccess_F(\"sumExact(array(c(5.0, -5, 3), c(1,3,1)));\", 3.0);\n\t\n\t// tan()\n\tEidosAssertScriptSuccess_L(\"abs(tan(0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(tan(0.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(tan(PI/4) - 1) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(tan(c(0, PI/4, -PI/4)) - c(0, 1, -1))) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"tan(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"tan('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"tan(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"tan(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"tan(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"tan(integer(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"tan(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"tan(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"tan(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"tan(c(0, NAN, 0));\", {0, std::numeric_limits<double>::quiet_NaN(), 0});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(tan(matrix(0.5)), matrix(tan(0.5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(tan(matrix(c(0.1, 0.2, 0.3))), matrix(tan(c(0.1, 0.2, 0.3))));\", true);\n\t\n\t// trunc()\n\tEidosAssertScriptSuccess_F(\"trunc(5.1);\", 5.0);\n\tEidosAssertScriptSuccess_F(\"trunc(-5.1);\", -5.0);\n\tEidosAssertScriptSuccess_FV(\"trunc(c(-2.1, 7.1, -18.8, 12.8));\", {-2.0, 7, -18, 12});\n\tEidosAssertScriptRaise(\"trunc(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"trunc(integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"trunc(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"trunc(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"trunc(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"trunc(c(-2.1, 7.1, -18.8, NAN, 12.8));\", {-2.0, 7, -18, std::numeric_limits<double>::quiet_NaN(), 12});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(trunc(matrix(0.3)), matrix(trunc(0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(trunc(matrix(0.6)), matrix(trunc(0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(trunc(matrix(-0.3)), matrix(trunc(-0.3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(trunc(matrix(-0.6)), matrix(trunc(-0.6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(trunc(matrix(c(0.1, 5.7, -0.3))), matrix(trunc(c(0.1, 5.7, -0.3))));\", true);\n}\n\n\n#pragma mark -\n#pragma mark SIMD math wrapper tests\n#pragma mark -\n\n// SIMD wrapper tests - verify that SLEEF-accelerated functions produce\n// results equivalent to scalar std:: functions\n\n#include \"eidos_simd.h\"\n#include \"eidos_globals.h\"\n\n// Test a unary SIMD function against its scalar equivalent\n// Template for functions like sin, cos, exp, etc.\ntemplate<typename ScalarFunc, typename SimdFunc>\nstatic void _TestUnarySimdFunction(const char *name, ScalarFunc scalar_func, SimdFunc simd_func,\n\t\t\t\t\t\t\t\t   const double *test_values, int num_values, double tolerance = 1e-14)\n{\n\t// Allocate output arrays\n\tstd::vector<double> scalar_output(num_values);\n\tstd::vector<double> simd_output(num_values);\n\n\t// Compute scalar results\n\tfor (int i = 0; i < num_values; i++)\n\t\tscalar_output[i] = scalar_func(test_values[i]);\n\n\t// Compute SIMD results\n\tsimd_func(test_values, simd_output.data(), num_values);\n\n\t// Compare results\n\tbool all_match = true;\n\tfor (int i = 0; i < num_values; i++)\n\t{\n\t\tdouble diff = std::abs(simd_output[i] - scalar_output[i]);\n\t\t// Handle NaN comparisons\n\t\tif (std::isnan(scalar_output[i]) && std::isnan(simd_output[i]))\n\t\t\tcontinue;\n\t\t// Handle Inf comparisons\n\t\tif (std::isinf(scalar_output[i]) && std::isinf(simd_output[i]) &&\n\t\t\t(scalar_output[i] > 0) == (simd_output[i] > 0))\n\t\t\tcontinue;\n\t\t// Compare with relative tolerance for large values\n\t\tdouble max_val = std::max(std::abs(scalar_output[i]), std::abs(simd_output[i]));\n\t\tif (max_val > 1.0)\n\t\t\tdiff /= max_val;\n\t\tif (diff > tolerance)\n\t\t{\n\t\t\tall_match = false;\n\t\t\tstd::cerr << \"SIMD \" << name << \" mismatch at index \" << i << \": input=\" << test_values[i]\n\t\t\t\t\t  << \", scalar=\" << scalar_output[i] << \", simd=\" << simd_output[i]\n\t\t\t\t\t  << \", diff=\" << diff << std::endl;\n\t\t}\n\t}\n\n\tif (all_match)\n\t{\n\t\tgEidosTestSuccessCount++;\n\t}\n\telse\n\t{\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << EIDOS_OUTPUT_FAILURE_TAG << \" : SIMD \" << name << \"() test failed\" << std::endl;\n\t}\n}\n\n// Test atan2 SIMD function (binary operation)\nstatic void _TestAtan2SimdFunction(const double *y_values, const double *x_values,\n\t\t\t\t\t\t\t\t   int num_values, double tolerance = 1e-14)\n{\n\tstd::vector<double> scalar_output(num_values);\n\tstd::vector<double> simd_output(num_values);\n\n\t// Compute scalar results\n\tfor (int i = 0; i < num_values; i++)\n\t\tscalar_output[i] = std::atan2(y_values[i], x_values[i]);\n\n\t// Compute SIMD results\n\tEidos_SIMD::atan2_float64(y_values, x_values, simd_output.data(), num_values);\n\n\t// Compare results\n\tbool all_match = true;\n\tfor (int i = 0; i < num_values; i++)\n\t{\n\t\tdouble diff = std::abs(simd_output[i] - scalar_output[i]);\n\t\tif (std::isnan(scalar_output[i]) && std::isnan(simd_output[i]))\n\t\t\tcontinue;\n\t\tdouble max_val = std::max(std::abs(scalar_output[i]), std::abs(simd_output[i]));\n\t\tif (max_val > 1.0)\n\t\t\tdiff /= max_val;\n\t\tif (diff > tolerance)\n\t\t{\n\t\t\tall_match = false;\n\t\t\tstd::cerr << \"SIMD atan2 mismatch at index \" << i << \": y=\" << y_values[i]\n\t\t\t\t\t  << \", x=\" << x_values[i] << \", scalar=\" << scalar_output[i]\n\t\t\t\t\t  << \", simd=\" << simd_output[i] << \", diff=\" << diff << std::endl;\n\t\t}\n\t}\n\n\tif (all_match)\n\t{\n\t\tgEidosTestSuccessCount++;\n\t}\n\telse\n\t{\n\t\tgEidosTestFailureCount++;\n\t\tstd::cerr << EIDOS_OUTPUT_FAILURE_TAG << \" : SIMD atan2() test failed\" << std::endl;\n\t}\n}\n\nvoid _RunSIMDMathTests(void)\n{\n#if !defined(EIDOS_SLEEF_AVAILABLE) || !EIDOS_SLEEF_AVAILABLE\n\tstd::cout << \"NOTE: SLEEF is not available in this build; SIMD math tests will compare scalar fallback against std:: (trivially identical).\" << std::endl;\n#endif\n\n\t// Test values for trigonometric functions (in radians)\n\t// Include various edge cases and values that span multiple SIMD vector widths\n\tconst double trig_test_values[] = {\n\t\t// Basic values\n\t\t0.0, 0.1, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0,\n\t\t// Negative values\n\t\t-0.1, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0,\n\t\t// Special angles (multiples of pi/4, pi/2, pi)\n\t\tM_PI/6, M_PI/4, M_PI/3, M_PI/2, 2*M_PI/3, 3*M_PI/4, M_PI,\n\t\t-M_PI/6, -M_PI/4, -M_PI/3, -M_PI/2, -2*M_PI/3, -3*M_PI/4, -M_PI,\n\t\t// Larger values to test range reduction\n\t\t5.0, 10.0, 100.0, -5.0, -10.0, -100.0,\n\t\t// Values near boundaries\n\t\t1e-10, 1e-5, -1e-10, -1e-5,\n\t\t// More values to ensure we test vector remainder handling (test odd counts)\n\t\t0.123, 0.456, 0.789, 1.234, 1.567, 1.890, 2.345\n\t};\n\tconst int num_trig_values = sizeof(trig_test_values) / sizeof(double);\n\n\t// Test values for inverse trig functions (domain: [-1, 1] for asin/acos)\n\tconst double inv_trig_test_values[] = {\n\t\t0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,\n\t\t-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0,\n\t\t0.99, 0.999, -0.99, -0.999,\n\t\t0.01, 0.001, -0.01, -0.001\n\t};\n\tconst int num_inv_trig_values = sizeof(inv_trig_test_values) / sizeof(double);\n\n\t// Test values for exp/log functions\n\tconst double exp_test_values[] = {\n\t\t0.0, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0,\n\t\t-0.1, -0.5, -1.0, -2.0, -5.0, -10.0,\n\t\t0.001, 0.01, -0.001, -0.01,\n\t\t700.0, -700.0  // Near overflow/underflow for exp\n\t};\n\tconst int num_exp_values = sizeof(exp_test_values) / sizeof(double);\n\n\tconst double log_test_values[] = {\n\t\t0.001, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 100.0, 1000.0,\n\t\tM_E, M_E * M_E, 1.0/M_E,\n\t\t1e-10, 1e10\n\t};\n\tconst int num_log_values = sizeof(log_test_values) / sizeof(double);\n\n\t// Test y,x pairs for atan2\n\tconst double atan2_y_values[] = {\n\t\t0.0, 1.0, 1.0, 0.0, -1.0, -1.0, -1.0, 0.0, 1.0,\n\t\t0.5, 0.5, -0.5, -0.5, 3.0, -3.0, 4.0, -4.0\n\t};\n\tconst double atan2_x_values[] = {\n\t\t1.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 1.0, -1.0,\n\t\t0.5, -0.5, 0.5, -0.5, 4.0, 4.0, -3.0, -3.0\n\t};\n\tconst int num_atan2_values = sizeof(atan2_y_values) / sizeof(double);\n\n\t// Run tests for each SIMD function\n\t// Trigonometric functions\n\t_TestUnarySimdFunction(\"sin\", [](double x) { return std::sin(x); },\n\t\t\t\t\t\t   Eidos_SIMD::sin_float64, trig_test_values, num_trig_values);\n\n\t_TestUnarySimdFunction(\"cos\", [](double x) { return std::cos(x); },\n\t\t\t\t\t\t   Eidos_SIMD::cos_float64, trig_test_values, num_trig_values);\n\n\t_TestUnarySimdFunction(\"tan\", [](double x) { return std::tan(x); },\n\t\t\t\t\t\t   Eidos_SIMD::tan_float64, trig_test_values, num_trig_values, 1e-12);  // tan needs more tolerance near poles\n\n\t// Inverse trigonometric functions\n\t_TestUnarySimdFunction(\"asin\", [](double x) { return std::asin(x); },\n\t\t\t\t\t\t   Eidos_SIMD::asin_float64, inv_trig_test_values, num_inv_trig_values);\n\n\t_TestUnarySimdFunction(\"acos\", [](double x) { return std::acos(x); },\n\t\t\t\t\t\t   Eidos_SIMD::acos_float64, inv_trig_test_values, num_inv_trig_values);\n\n\t_TestUnarySimdFunction(\"atan\", [](double x) { return std::atan(x); },\n\t\t\t\t\t\t   Eidos_SIMD::atan_float64, trig_test_values, num_trig_values);  // atan accepts any real value\n\n\t// atan2 (binary function)\n\t_TestAtan2SimdFunction(atan2_y_values, atan2_x_values, num_atan2_values);\n\n\t// Exponential and logarithmic functions (these were already implemented, test them too)\n\t_TestUnarySimdFunction(\"exp\", [](double x) { return std::exp(x); },\n\t\t\t\t\t\t   Eidos_SIMD::exp_float64, exp_test_values, num_exp_values);\n\n\t_TestUnarySimdFunction(\"log\", [](double x) { return std::log(x); },\n\t\t\t\t\t\t   Eidos_SIMD::log_float64, log_test_values, num_log_values);\n\n\t_TestUnarySimdFunction(\"log10\", [](double x) { return std::log10(x); },\n\t\t\t\t\t\t   Eidos_SIMD::log10_float64, log_test_values, num_log_values);\n\n\t_TestUnarySimdFunction(\"log2\", [](double x) { return std::log2(x); },\n\t\t\t\t\t\t   Eidos_SIMD::log2_float64, log_test_values, num_log_values);\n\n\t// Test pow() function (binary operation: base^exp)\n\t// Test values for base and exponent\n\tconst double pow_base_values[] = {\n\t\t0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0,\n\t\t0.1, 0.2, 0.9, 1.5, 2.5,\n\t\t100.0, 0.01\n\t};\n\tconst double pow_exp_values[] = {\n\t\t0.0, 0.5, 1.0, 2.0, 3.0, -1.0, -2.0,\n\t\t0.25, 0.333, 1.5, 2.5, -0.5,\n\t\t0.1, 10.0\n\t};\n\tconst int num_pow_values = sizeof(pow_base_values) / sizeof(double);\n\n\t// Test pow_float64 (both arrays)\n\t{\n\t\tstd::vector<double> scalar_output(num_pow_values);\n\t\tstd::vector<double> simd_output(num_pow_values);\n\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t\tscalar_output[i] = std::pow(pow_base_values[i], pow_exp_values[i]);\n\n\t\tEidos_SIMD::pow_float64(pow_base_values, pow_exp_values, simd_output.data(), num_pow_values);\n\n\t\tbool all_match = true;\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t{\n\t\t\tdouble diff = std::abs(simd_output[i] - scalar_output[i]);\n\t\t\tif (std::isnan(scalar_output[i]) && std::isnan(simd_output[i]))\n\t\t\t\tcontinue;\n\t\t\tif (std::isinf(scalar_output[i]) && std::isinf(simd_output[i]) &&\n\t\t\t\t(scalar_output[i] > 0) == (simd_output[i] > 0))\n\t\t\t\tcontinue;\n\t\t\tdouble max_val = std::max(std::abs(scalar_output[i]), std::abs(simd_output[i]));\n\t\t\tif (max_val > 1.0)\n\t\t\t\tdiff /= max_val;\n\t\t\tif (diff > 1e-14)\n\t\t\t{\n\t\t\t\tall_match = false;\n\t\t\t\tstd::cerr << \"SIMD pow mismatch at index \" << i << \": base=\" << pow_base_values[i]\n\t\t\t\t\t\t  << \", exp=\" << pow_exp_values[i] << \", scalar=\" << scalar_output[i]\n\t\t\t\t\t\t  << \", simd=\" << simd_output[i] << \", diff=\" << diff << std::endl;\n\t\t\t}\n\t\t}\n\n\t\tif (all_match)\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << EIDOS_OUTPUT_FAILURE_TAG << \" : SIMD pow() test failed\" << std::endl;\n\t\t}\n\t}\n\n\t// Test pow_float64_scalar_exp (base_array ^ scalar_exponent)\n\t{\n\t\tconst double scalar_exp = 2.5;\n\t\tstd::vector<double> scalar_output(num_pow_values);\n\t\tstd::vector<double> simd_output(num_pow_values);\n\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t\tscalar_output[i] = std::pow(pow_base_values[i], scalar_exp);\n\n\t\tEidos_SIMD::pow_float64_scalar_exp(pow_base_values, scalar_exp, simd_output.data(), num_pow_values);\n\n\t\tbool all_match = true;\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t{\n\t\t\tdouble diff = std::abs(simd_output[i] - scalar_output[i]);\n\t\t\tif (std::isnan(scalar_output[i]) && std::isnan(simd_output[i]))\n\t\t\t\tcontinue;\n\t\t\tdouble max_val = std::max(std::abs(scalar_output[i]), std::abs(simd_output[i]));\n\t\t\tif (max_val > 1.0)\n\t\t\t\tdiff /= max_val;\n\t\t\tif (diff > 1e-14)\n\t\t\t{\n\t\t\t\tall_match = false;\n\t\t\t\tstd::cerr << \"SIMD pow_scalar_exp mismatch at index \" << i << \": base=\" << pow_base_values[i]\n\t\t\t\t\t\t  << \", exp=\" << scalar_exp << \", scalar=\" << scalar_output[i]\n\t\t\t\t\t\t  << \", simd=\" << simd_output[i] << \", diff=\" << diff << std::endl;\n\t\t\t}\n\t\t}\n\n\t\tif (all_match)\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << EIDOS_OUTPUT_FAILURE_TAG << \" : SIMD pow_scalar_exp() test failed\" << std::endl;\n\t\t}\n\t}\n\n\t// Test pow_float64_scalar_base (scalar_base ^ exp_array)\n\t{\n\t\tconst double scalar_base = 2.0;\n\t\tstd::vector<double> scalar_output(num_pow_values);\n\t\tstd::vector<double> simd_output(num_pow_values);\n\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t\tscalar_output[i] = std::pow(scalar_base, pow_exp_values[i]);\n\n\t\tEidos_SIMD::pow_float64_scalar_base(scalar_base, pow_exp_values, simd_output.data(), num_pow_values);\n\n\t\tbool all_match = true;\n\t\tfor (int i = 0; i < num_pow_values; i++)\n\t\t{\n\t\t\tdouble diff = std::abs(simd_output[i] - scalar_output[i]);\n\t\t\tif (std::isnan(scalar_output[i]) && std::isnan(simd_output[i]))\n\t\t\t\tcontinue;\n\t\t\tdouble max_val = std::max(std::abs(scalar_output[i]), std::abs(simd_output[i]));\n\t\t\tif (max_val > 1.0)\n\t\t\t\tdiff /= max_val;\n\t\t\tif (diff > 1e-14)\n\t\t\t{\n\t\t\t\tall_match = false;\n\t\t\t\tstd::cerr << \"SIMD pow_scalar_base mismatch at index \" << i << \": base=\" << scalar_base\n\t\t\t\t\t\t  << \", exp=\" << pow_exp_values[i] << \", scalar=\" << scalar_output[i]\n\t\t\t\t\t\t  << \", simd=\" << simd_output[i] << \", diff=\" << diff << std::endl;\n\t\t\t}\n\t\t}\n\n\t\tif (all_match)\n\t\t\tgEidosTestSuccessCount++;\n\t\telse\n\t\t{\n\t\t\tgEidosTestFailureCount++;\n\t\t\tstd::cerr << EIDOS_OUTPUT_FAILURE_TAG << \" : SIMD pow_scalar_base() test failed\" << std::endl;\n\t\t}\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_functions_other.cpp",
    "content": "//\n//  eidos_test_functions_other.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n#include <string>\n#include <vector>\n\n\n#pragma mark matrix and array\nvoid _RunFunctionMatrixArrayTests(void)\n{\n\t// array()\n\tEidosAssertScriptRaise(\"array(5, integer(0));\", 0, \"at least a matrix\");\n\tEidosAssertScriptRaise(\"array(5, 1);\", 0, \"at least a matrix\");\n\tEidosAssertScriptRaise(\"array(5, c(1,2));\", 0, \"product of the proposed dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(array(5, c(1,1)), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6, c(2,3)), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6, c(3,2)), matrix(1:6, nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"size(array(1:12, c(3,2,2))) == 12;\", true);\t\t// FIXME not sure how to test higher-dimensional arrays right now...\n\t\n\t// cbind()\n\tEidosAssertScriptRaise(\"cbind(5, 5.5);\", 0, \"be the same type\");\n\tEidosAssertScriptRaise(\"cbind(5, array(5, c(1,1,1)));\", 0, \"all arguments be vectors or matrices\");\n\tEidosAssertScriptRaise(\"cbind(matrix(1:4, nrow=2), matrix(1:4, nrow=4));\", 0, \"number of row\");\n\tEidosAssertScriptSuccess_L(\"identical(cbind(5), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(1:5), matrix(1:5, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(1:5, 6:10), matrix(1:10, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(1:5, 6:10, NULL, integer(0), 11:15), matrix(1:15, ncol=3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(matrix(1:6, nrow=2), matrix(7:12, nrow=2)), matrix(1:12, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(matrix(1:6, ncol=2), matrix(7:12, ncol=2)), matrix(1:12, nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cbind(matrix(1:6, nrow=1), matrix(7:12, nrow=1)), matrix(1:12, nrow=1));\", true);\n\t\n\t// det()\n\tEidosAssertScriptRaise(\"det(1);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"det(1.5);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"det(matrix(1:6, ncol=2));\", 0, \"must be a square matrix\");\n\tEidosAssertScriptSuccess_I(\"det(matrix(7, ncol=1));\", 7);\n\tEidosAssertScriptSuccess_F(\"det(matrix(7.0, ncol=1));\", 7.0);\n\tEidosAssertScriptSuccess_I(\"det(matrix(1:4, ncol=2));\", -2);\n\tEidosAssertScriptSuccess_F(\"det(matrix(1.0:4, ncol=2));\", -2.0);\n\tEidosAssertScriptSuccess_I(\"det(matrix(1:9, ncol=3));\", 0);\n\tEidosAssertScriptSuccess_F(\"det(matrix(1.0:9, ncol=3));\", 0.0);\n\tEidosAssertScriptSuccess_I(\"det(matrix(c(1, 2, 3, 6, 5, 4, 8, 9, 7), nrow=3));\", 21);\n\tEidosAssertScriptSuccess_L(\"abs(det(matrix(c(1.0, 2, 3, 6, 5, 4, 8, 9, 7), nrow=3)) - 21.0) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(rdunif(4, -100, 100), ncol=2); identical(det(x), drop(x[0,0]*x[1,1] - x[0,1]*x[1,0]));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(runif(4, -100, 100), ncol=2); abs(det(x) - drop(x[0,0]*x[1,1] - x[0,1]*x[1,0])) < 1e-9;\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(rdunif(9, -100, 100), ncol=3); identical(det(x), drop(x[0,0]*x[1,1]*x[2,2] + x[0,1]*x[1,2]*x[2,0] + x[0,2]*x[1,0]*x[2,1] - x[0,2]*x[1,1]*x[2,0] - x[0,1]*x[1,0]*x[2,2] - x[0,0]*x[1,2]*x[2,1]));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(runif(9, -100, 100), ncol=3); abs(det(x) - drop(x[0,0]*x[1,1]*x[2,2] + x[0,1]*x[1,2]*x[2,0] + x[0,2]*x[1,0]*x[2,1] - x[0,2]*x[1,1]*x[2,0] - x[0,1]*x[1,0]*x[2,2] - x[0,0]*x[1,2]*x[2,1])) < 1e-9;\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(rdunif(16, -100, 100), ncol=4); det(x); T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(runif(16, -100, 100), ncol=4); det(x); T;\", true);\n\t\n\t// diag()\n\tEidosAssertScriptRaise(\"diag(array(5, c(1, 1, 1)));\", 0, \"a vector or a matrix\");\n\tEidosAssertScriptRaise(\"diag(matrix(5), nrow=1);\", 0, \"must be NULL\");\n\tEidosAssertScriptRaise(\"diag(matrix(5), ncol=1);\", 0, \"must be NULL\");\n\tEidosAssertScriptSuccess_IV(\"diag(matrix(5));\", {5});\n\tEidosAssertScriptSuccess_IV(\"diag(matrix(1:10, ncol=5));\", {1, 4});\n\tEidosAssertScriptSuccess_IV(\"diag(t(matrix(1:10, ncol=5)));\", {1, 4});\n\tEidosAssertScriptSuccess_IV(\"diag(matrix(1:16, ncol=4));\", {1, 6, 11, 16});\n\tEidosAssertScriptSuccess_IV(\"diag(t(matrix(1:16, ncol=4)));\", {1, 6, 11, 16});\n\t\n\tEidosAssertScriptRaise(\"diag(ncol=3);\", 0, \"one of four specific\");\n\tEidosAssertScriptRaise(\"diag(nrow=0);\", 0, \"matrix must be >= 1\");\n\tEidosAssertScriptRaise(\"diag(nrow=1, ncol=0);\", 0, \"matrix must be >= 1\");\n\tEidosAssertScriptSuccess_L(\"d = diag(nrow=1); identical(d, matrix(1));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(nrow=3); identical(d, matrix(c(1, 0, 0, 0, 1, 0, 0, 0, 1), nrow=3, ncol=3));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(nrow=3, ncol=2); identical(d, matrix(c(1, 0, 0, 0, 1, 0), nrow=3, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(nrow=2, ncol=3); identical(d, matrix(c(1, 0, 0, 1, 0, 0), nrow=2, ncol=3));\", true);\n\t\n\tEidosAssertScriptRaise(\"diag(T);\", 0, \"one of four specific\");\n\tEidosAssertScriptRaise(\"diag(F);\", 0, \"one of four specific\");\n\tEidosAssertScriptRaise(\"diag(1.5);\", 0, \"one of four specific\");\n\tEidosAssertScriptRaise(\"diag('foo');\", 0, \"one of four specific\");\n\tEidosAssertScriptRaise(\"diag(0);\", 0, \"size must be >= 1\");\n\tEidosAssertScriptSuccess_L(\"d = diag(1); identical(d, matrix(1));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(3); identical(d, matrix(c(1, 0, 0, 0, 1, 0, 0, 0, 1), nrow=3, ncol=3));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1,4)); identical(d, matrix(c(1, 0, 0, 4), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1,4), ncol=3); identical(d, matrix(c(1, 0, 0, 4, 0, 0), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"diag(c(1,4), nrow=3);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1,4), nrow=3, ncol=2); identical(d, matrix(c(1, 0, 0, 0, 4, 0), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1,4), nrow=2, ncol=3); identical(d, matrix(c(1, 0, 0, 4, 0, 0), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"diag(c(1,4), nrow=3, ncol=3);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptRaise(\"diag(c(1,4), nrow=1);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptRaise(\"diag(c(1,4), ncol=1);\", 0, \"truncated or recycled\");\n\t\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1.0,4)); identical(d, matrix(c(1.0, 0, 0, 4), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1.0,4), ncol=3); identical(d, matrix(c(1.0, 0, 0, 4, 0, 0), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"diag(c(1.0,4), nrow=3);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1.0,4), nrow=3, ncol=2); identical(d, matrix(c(1.0, 0, 0, 0, 4, 0), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"d = diag(c(1.0,4), nrow=2, ncol=3); identical(d, matrix(c(1.0, 0, 0, 4, 0, 0), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"diag(c(1.0,4), nrow=3, ncol=3);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptRaise(\"diag(c(1.0,4), nrow=1);\", 0, \"truncated or recycled\");\n\tEidosAssertScriptRaise(\"diag(c(1.0,4), ncol=1);\", 0, \"truncated or recycled\");\n\t\n\t// dim()\n\tEidosAssertScriptSuccess_NULL(\"dim(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"dim(T);\");\n\tEidosAssertScriptSuccess_NULL(\"dim(1);\");\n\tEidosAssertScriptSuccess_NULL(\"dim(1.5);\");\n\tEidosAssertScriptSuccess_NULL(\"dim('foo');\");\n\tEidosAssertScriptSuccess_NULL(\"dim(c(T, F));\");\n\tEidosAssertScriptSuccess_NULL(\"dim(c(1, 2));\");\n\tEidosAssertScriptSuccess_NULL(\"dim(c(1.5, 2.0));\");\n\tEidosAssertScriptSuccess_NULL(\"dim(c('foo', 'bar'));\");\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(3));\", {1, 1});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1:6, nrow=2));\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1:6, nrow=2, byrow=T));\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1:6, ncol=2));\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1:6, ncol=2, byrow=T));\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"dim(array(1:24, c(2,3,4)));\", {2, 3, 4});\n\tEidosAssertScriptSuccess_IV(\"dim(array(1:48, c(2,3,4,2)));\", {2, 3, 4, 2});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(3.0));\", {1, 1});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1.0:6, nrow=2));\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1.0:6, nrow=2, byrow=T));\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1.0:6, ncol=2));\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"dim(matrix(1.0:6, ncol=2, byrow=T));\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"dim(array(1.0:24, c(2,3,4)));\", {2, 3, 4});\n\tEidosAssertScriptSuccess_IV(\"dim(array(1.0:48, c(2,3,4,2)));\", {2, 3, 4, 2});\n\t\n\t// drop()\n\tEidosAssertScriptSuccess_NULL(\"drop(NULL);\");\n\tEidosAssertScriptSuccess_L(\"identical(drop(integer(0)), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(5), 5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(5:9), 5:9);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(matrix(5)), 5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(matrix(5:9)), 5:9);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(matrix(1:6, ncol=1)), 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(matrix(1:6, nrow=1)), 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(matrix(1:6, nrow=2)), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(5, c(1,1,1))), 5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(6,1,1))), 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(1,6,1))), 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(1,1,6))), 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(2,3,1))), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(1,2,3))), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:6, c(2,1,3))), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:12, c(12,1,1))), 1:12);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(drop(array(1:12, c(2,3,2))), array(1:12, c(2,3,2)));\", true);\n\t\n\t// inverse()\n\tEidosAssertScriptRaise(\"inverse(1);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"inverse(1.5);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"inverse(matrix(1:6, ncol=2));\", 0, \"must be a square matrix\");\n\tEidosAssertScriptSuccess_F(\"inverse(matrix(2, ncol=1));\", 0.5);\n\tEidosAssertScriptSuccess_F(\"inverse(matrix(2.0, ncol=1));\", 0.5);\n\tEidosAssertScriptRaise(\"inverse(matrix(1:9, ncol=3));\", 0, \"must not be singular\");\n\tEidosAssertScriptRaise(\"inverse(matrix(1.0:9, ncol=3));\", 0, \"must not be singular\");\n\tEidosAssertScriptSuccess_L(\"A = matrix(c(3, 2, 5, 2, 3, 2, 5, 2, 4), ncol=3); B = inverse(A); prod = matrixMult(asFloat(A), B); identity = diag(nrow=3); diff = sum(abs(prod - identity)); diff < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(c(3.0, 2, 5, 2, 3, 2, 5, 2, 4), ncol=3); B = inverse(A); prod = matrixMult(A, B); identity = diag(nrow=3); diff = sum(abs(prod - identity)); diff < 1e-10;\", true);\n\t\n\t// lowerTri()\n\tEidosAssertScriptRaise(\"ut = lowerTri(0);\", 5, \"is not a matrix\");\n\tEidosAssertScriptSuccess_L(\"ut = lowerTri(matrix(5)); identical(ut, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"ut = lowerTri(matrix(5), T); identical(ut, matrix(T));\", true);\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:16, 4); ut = lowerTri(x); x[c(ut)];\", {2, 3, 4, 7, 8, 12});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:16, 4); ut = lowerTri(x, T); x[c(ut)];\", {1, 2, 3, 4, 6, 7, 8, 11, 12, 16});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 3); ut = lowerTri(x); x[c(ut)];\", {2, 3, 6});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 3); ut = lowerTri(x, T); x[c(ut)];\", {1, 2, 3, 5, 6, 9});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 4); ut = lowerTri(x); x[c(ut)];\", {2, 3, 4, 7, 8, 12});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 4); ut = lowerTri(x, T); x[c(ut)];\", {1, 2, 3, 4, 6, 7, 8, 11, 12});\n\t\n\t// matrix()\n\tEidosAssertScriptSuccess_IV(\"matrix(3);\", {3});\n\tEidosAssertScriptSuccess_IV(\"matrix(3, nrow=1);\", {3});\n\tEidosAssertScriptSuccess_IV(\"matrix(3, ncol=1);\", {3});\n\tEidosAssertScriptSuccess_IV(\"matrix(3, nrow=1, ncol=1);\", {3});\n\tEidosAssertScriptSuccess_IV(\"matrix(1:6, nrow=1);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"matrix(1:6, ncol=1);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"matrix(1:6, ncol=2);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_IV(\"matrix(1:6, ncol=2, byrow=T);\", {1, 3, 5, 2, 4, 6});\n\tEidosAssertScriptSuccess_IV(\"matrix(1:6, ncol=3, byrow=T);\", {1, 4, 2, 5, 3, 6});\n\tEidosAssertScriptRaise(\"matrix(1:5, ncol=2);\", 0, \"not a multiple of the supplied column count\");\n\tEidosAssertScriptRaise(\"matrix(1:5, nrow=2);\", 0, \"not a multiple of the supplied row count\");\n\tEidosAssertScriptRaise(\"matrix(1:5, nrow=2, ncol=2);\", 0, \"length equal to the product\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6, ncol=2), matrix(c(1, 4, 2, 5, 3, 6), ncol=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6, ncol=3), matrix(c(1, 3, 5, 2, 4, 6), ncol=3, byrow=T));\", true);\n\tEidosAssertScriptSuccess_FV(\"matrix(3.0);\", {3});\n\tEidosAssertScriptSuccess_FV(\"matrix(3.0, nrow=1);\", {3});\n\tEidosAssertScriptSuccess_FV(\"matrix(3.0, ncol=1);\", {3});\n\tEidosAssertScriptSuccess_FV(\"matrix(3.0, nrow=1, ncol=1);\", {3});\n\tEidosAssertScriptSuccess_FV(\"matrix(1.0:6, nrow=1);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_FV(\"matrix(1.0:6, ncol=1);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_FV(\"matrix(1.0:6, ncol=2);\", {1, 2, 3, 4, 5, 6});\n\tEidosAssertScriptSuccess_FV(\"matrix(1.0:6, ncol=2, byrow=T);\", {1, 3, 5, 2, 4, 6});\n\tEidosAssertScriptSuccess_FV(\"matrix(1.0:6, ncol=3, byrow=T);\", {1, 4, 2, 5, 3, 6});\n\tEidosAssertScriptRaise(\"matrix(1.0:5, ncol=2);\", 0, \"not a multiple of the supplied column count\");\n\tEidosAssertScriptRaise(\"matrix(1.0:5, nrow=2);\", 0, \"not a multiple of the supplied row count\");\n\tEidosAssertScriptRaise(\"matrix(1.0:5, nrow=2, ncol=2);\", 0, \"length equal to the product\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1.0:6, ncol=2), matrix(c(1.0, 4, 2, 5, 3, 6), ncol=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1.0:6, ncol=3), matrix(c(1.0, 3, 5, 2, 4, 6), ncol=3, byrow=T));\", true);\n\tEidosAssertScriptRaise(\"matrix(integer(0), nrow=0);\", 0, \"dimension <= 0\");\n\tEidosAssertScriptRaise(\"matrix(integer(0), ncol=0);\", 0, \"dimension <= 0\");\n\tEidosAssertScriptRaise(\"matrix(integer(0));\", 0, \"matrix with zero elements\");\n\t\n\t// matrixMult()\n\tEidosAssertScriptRaise(\"matrixMult(matrix(5), 5);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"matrixMult(5, matrix(5));\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"matrixMult(matrix(5), matrix(5.5));\", 0, \"are the same type\");\n\tEidosAssertScriptRaise(\"matrixMult(matrix(1:5), matrix(1:5));\", 0, \"not conformable\");\n\tEidosAssertScriptSuccess_L(\"A = matrix(2); B = matrix(5); identical(matrixMult(A, B), matrix(10));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(2); B = matrix(1:5, nrow=1); identical(matrixMult(A, B), matrix(c(2,4,6,8,10), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:5, ncol=1); B = matrix(2); identical(matrixMult(A, B), matrix(c(2,4,6,8,10), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:5, ncol=1); B = matrix(1:5, nrow=1); identical(matrixMult(A, B), matrix(c(1:5, (1:5)*2, (1:5)*3, (1:5)*4, (1:5)*5), ncol=5));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:5, nrow=1); B = matrix(1:5, ncol=1); identical(matrixMult(A, B), matrix(55));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:6, nrow=2); B = matrix(1:6, ncol=2); identical(matrixMult(A, B), matrix(c(22, 28, 49, 64), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:6, ncol=2); B = matrix(1:6, nrow=2); identical(matrixMult(A, B), matrix(c(9, 12, 15, 19, 26, 33, 29, 40, 51), nrow=3));\", true);\n\t\n\tEidosAssertScriptRaise(\"matrixMult(matrix(5.0), 5.0);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"matrixMult(5.0, matrix(5.0));\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"matrixMult(matrix(5.0), matrix(5));\", 0, \"are the same type\");\n\tEidosAssertScriptRaise(\"matrixMult(matrix(1.0:5.0), matrix(1.0:5.0));\", 0, \"not conformable\");\n\tEidosAssertScriptSuccess_L(\"A = matrix(2.0); B = matrix(5.0); identical(matrixMult(A, B), matrix(10.0));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(2.0); B = matrix(1.0:5.0, nrow=1); identical(matrixMult(A, B), matrix(c(2.0,4.0,6.0,8.0,10.0), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1.0:5.0, ncol=1); B = matrix(2.0); identical(matrixMult(A, B), matrix(c(2.0,4.0,6.0,8.0,10.0), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1.0:5.0, ncol=1); B = matrix(1.0:5.0, nrow=1); identical(matrixMult(A, B), matrix(c(1.0:5.0, (1.0:5.0)*2, (1.0:5.0)*3, (1.0:5.0)*4, (1.0:5.0)*5), ncol=5));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1.0:5.0, nrow=1); B = matrix(1.0:5.0, ncol=1); identical(matrixMult(A, B), matrix(55.0));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1.0:6.0, nrow=2); B = matrix(1.0:6.0, ncol=2); identical(matrixMult(A, B), matrix(c(22.0, 28.0, 49.0, 64.0), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1.0:6.0, ncol=2); B = matrix(1.0:6.0, nrow=2); identical(matrixMult(A, B), matrix(c(9.0, 12.0, 15.0, 19.0, 26.0, 33.0, 29.0, 40.0, 51.0), nrow=3));\", true);\n\t\n\t// matrixPow()\n\tEidosAssertScriptRaise(\"matrixPow(5.0, 3);\", 0, \"requires x to be a matrix\");\n\tEidosAssertScriptRaise(\"matrixPow(matrix(1:6, nrow=2), 3);\", 0, \"requires x to be a square matrix\");\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:9, nrow=3); B = matrixPow(A, 0); identical(B, diag(3));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:9, nrow=3); B = matrixPow(A, 1); identical(B, A);\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:9, nrow=3); B = matrixPow(A, 2); identical(B, matrix(c(30, 36, 42, 66, 81, 96, 102, 126, 150), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(1:9, nrow=3); B = matrixPow(A, 3); identical(B, matrix(c(468, 576, 684, 1062, 1305, 1548, 1656, 2034, 2412), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"A = matrix(1:9, nrow=3); B = matrixPow(A, -1);\", 29, \"singular and thus non-invertible\");\n\tEidosAssertScriptSuccess_L(\"A = matrix(c(1, 3, 2, 6, 4, 5, 10, 2, 7), nrow=3); B = matrixPow(A, -1); identical(B, inverse(A));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(c(1, 3, 2, 6, 4, 5, 10, 2, 7), nrow=3); B = matrixPow(A, -2); identical(B, matrixPow(inverse(A), 2));\", true);\n\tEidosAssertScriptSuccess_L(\"A = matrix(c(1, 3, 2, 6, 4, 5, 10, 2, 7), nrow=3); B = matrixPow(A, -3); identical(B, matrixPow(inverse(A), 3));\", true);\n\t\n\t// ncol()\n\tEidosAssertScriptSuccess_NULL(\"ncol(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(T);\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(1);\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(1.5);\");\n\tEidosAssertScriptSuccess_NULL(\"ncol('foo');\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(c(T, F));\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(c(1, 2));\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(c(1.5, 2.0));\");\n\tEidosAssertScriptSuccess_NULL(\"ncol(c('foo', 'bar'));\");\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(3));\", {1});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1:6, nrow=2));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1:6, nrow=2, byrow=T));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1:6, ncol=2));\", {2});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1:6, ncol=2, byrow=T));\", {2});\n\tEidosAssertScriptSuccess_IV(\"ncol(array(1:24, c(2,3,4)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(array(1:48, c(2,3,4,2)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(3.0));\", {1});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1.0:6, nrow=2));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1.0:6, nrow=2, byrow=T));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1.0:6, ncol=2));\", {2});\n\tEidosAssertScriptSuccess_IV(\"ncol(matrix(1.0:6, ncol=2, byrow=T));\", {2});\n\tEidosAssertScriptSuccess_IV(\"ncol(array(1.0:24, c(2,3,4)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"ncol(array(1.0:48, c(2,3,4,2)));\", {3});\n\t\n\t// nrow()\n\tEidosAssertScriptSuccess_NULL(\"nrow(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(T);\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(1);\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(1.5);\");\n\tEidosAssertScriptSuccess_NULL(\"nrow('foo');\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(c(T, F));\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(c(1, 2));\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(c(1.5, 2.0));\");\n\tEidosAssertScriptSuccess_NULL(\"nrow(c('foo', 'bar'));\");\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(3));\", {1});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1:6, nrow=2));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1:6, nrow=2, byrow=T));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1:6, ncol=2));\", {3});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1:6, ncol=2, byrow=T));\", {3});\n\tEidosAssertScriptSuccess_IV(\"nrow(array(1:24, c(2,3,4)));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(array(1:48, c(2,3,4,2)));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(3.0));\", {1});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1.0:6, nrow=2));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1.0:6, nrow=2, byrow=T));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1.0:6, ncol=2));\", {3});\n\tEidosAssertScriptSuccess_IV(\"nrow(matrix(1.0:6, ncol=2, byrow=T));\", {3});\n\tEidosAssertScriptSuccess_IV(\"nrow(array(1.0:24, c(2,3,4)));\", {2});\n\tEidosAssertScriptSuccess_IV(\"nrow(array(1.0:48, c(2,3,4,2)));\", {2});\n\t\n\t// outerProduct()\n\tEidosAssertScriptRaise(\"outerProduct(1:3, integer(0));\", 0, \"dimensions equal to zero\");\n\tEidosAssertScriptRaise(\"outerProduct(integer(0), 1:3);\", 0, \"dimensions equal to zero\");\n\tEidosAssertScriptSuccess_L(\"x = 1:3; y = 5:6; identical(outerProduct(x, y), matrix(c(5, 10, 15, 6, 12, 18), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:2; y = 5:7; identical(outerProduct(x, y), matrix(c(5, 10, 6, 12, 7, 14), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:3; y = 5:7; identical(outerProduct(x, y), matrix(c(5, 10, 15, 6, 12, 18, 7, 14, 21), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:3; y = 5.0:6; identical(outerProduct(x, y), matrix(c(5.0, 10, 15, 6, 12, 18), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:2; y = 5.0:7; identical(outerProduct(x, y), matrix(c(5.0, 10, 6, 12, 7, 14), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:3; y = 5.0:7; identical(outerProduct(x, y), matrix(c(5.0, 10, 15, 6, 12, 18, 7, 14, 21), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"outerProduct(1.0:3, 5:7);\", 0, \"the same type\");\n\tEidosAssertScriptRaise(\"x = matrix(1:3); outerProduct(x, x);\", 17, \"requires x and y to be vectors\");\n\t\n\t// rbind()\n\tEidosAssertScriptRaise(\"rbind(5, 5.5);\", 0, \"be the same type\");\n\tEidosAssertScriptRaise(\"rbind(5, array(5, c(1,1,1)));\", 0, \"all arguments be vectors or matrices\");\n\tEidosAssertScriptRaise(\"rbind(matrix(1:4, nrow=2), matrix(1:4, nrow=4));\", 0, \"number of columns\");\n\tEidosAssertScriptSuccess_L(\"identical(rbind(5), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(1:5), matrix(1:5, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(1:5, 6:10), matrix(1:10, nrow=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(1:5, 6:10, NULL, integer(0), 11:15), matrix(1:15, nrow=3, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(matrix(1:6, nrow=2), matrix(7:12, nrow=2)), matrix(c(1,2,7,8,3,4,9,10,5,6,11,12), nrow=4));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(matrix(1:6, ncol=2), matrix(7:12, ncol=2)), matrix(c(1,2,3,7,8,9,4,5,6,10,11,12), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rbind(matrix(1:6, ncol=1), matrix(7:12, ncol=1)), matrix(1:12, ncol=1));\", true);\n\t\n\t// t()\n\tEidosAssertScriptRaise(\"t(NULL);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"t(T);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"t(1);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"t(1.5);\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"t('foo');\", 0, \"is not a matrix\");\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(3)), matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1:6, nrow=2)), matrix(1:6, ncol=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1:6, nrow=2, byrow=T)), matrix(1:6, ncol=2, byrow=F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1:6, ncol=2)), matrix(1:6, nrow=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1:6, ncol=2, byrow=T)), matrix(1:6, nrow=2, byrow=F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(3.0)), matrix(3.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1.0:6, nrow=2)), matrix(1.0:6, ncol=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1.0:6, nrow=2, byrow=T)), matrix(1.0:6, ncol=2, byrow=F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1.0:6, ncol=2)), matrix(1.0:6, nrow=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(t(matrix(1.0:6, ncol=2, byrow=T)), matrix(1.0:6, nrow=2, byrow=F));\", true);\n\tEidosAssertScriptRaise(\"t(array(1:24, c(2,3,4)));\", 0, \"is not a matrix\");\n\tEidosAssertScriptRaise(\"t(array(1:48, c(2,3,4,2)));\", 0, \"is not a matrix\");\n\t\n\t// tr()\n\tEidosAssertScriptRaise(\"tr(1);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"tr(1.5);\", 0, \"must be a matrix\");\n\tEidosAssertScriptRaise(\"tr(matrix(1:6, ncol=2));\", 0, \"must be a square matrix\");\n\tEidosAssertScriptSuccess_I(\"tr(matrix(7, ncol=1));\", 7);\n\tEidosAssertScriptSuccess_F(\"tr(matrix(7.0, ncol=1));\", 7.0);\n\tEidosAssertScriptSuccess_I(\"tr(matrix(1:9, ncol=3));\", 1 + 5 + 9);\n\tEidosAssertScriptSuccess_F(\"tr(matrix(1.0:9, ncol=3));\", 1 + 5 + 9);\n\tEidosAssertScriptSuccess_F(\"tr(matrix(c(1.25, -7.8, 3.4, 6.1, 4.75, 8.2, -0.3, 8.6, -1.5), ncol=3));\", 1.25 + 4.75 + -1.5);\n\tEidosAssertScriptSuccess_L(\"x = matrix(runif(100), ncol=10); allClose(tr(x), sum(diag(x)));\", true);  // tolerance for SIMD\n\tEidosAssertScriptSuccess_L(\"x = matrix(rdunif(100, -1000, 1000), ncol=10); identical(tr(x), sum(diag(x)));\", true);\n\t\n\t// upperTri()\n\tEidosAssertScriptRaise(\"ut = upperTri(0);\", 5, \"is not a matrix\");\n\tEidosAssertScriptSuccess_L(\"ut = upperTri(matrix(5)); identical(ut, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"ut = upperTri(matrix(5), T); identical(ut, matrix(T));\", true);\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:16, 4); ut = upperTri(x); x[c(ut)];\", {5, 9, 10, 13, 14, 15});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:16, 4); ut = upperTri(x, T); x[c(ut)];\", {1, 5, 6, 9, 10, 11, 13, 14, 15, 16});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 3); ut = upperTri(x); x[c(ut)];\", {4, 7, 8, 10, 11, 12});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 3); ut = upperTri(x, T); x[c(ut)];\", {1, 4, 5, 7, 8, 9, 10, 11, 12});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 4); ut = upperTri(x); x[c(ut)];\", {5, 9, 10});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, 4); ut = upperTri(x, T); x[c(ut)];\", {1, 5, 6, 9, 10, 11});\n\t\n\t// asVector()\n\tEidosAssertScriptRaise(\"x = NULL; y = matrix(x); identical(asVector(y), x);\", 14, \"zero elements\");\n\tEidosAssertScriptSuccess_L(\"x = 1:12; y = matrix(x, nrow=3); identical(asVector(y), x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:12; y = matrix(x, nrow=3); identical(asVector(y), x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = (rbinom(12, 1, 0.5) == 1); y = matrix(x, nrow=3); identical(asVector(y), x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = c('a','b','c','d','e','f','g','h','i','j','k','l'); y = matrix(x, nrow=3); identical(asVector(y), x);\", true);\n\t\n\t// rowSums()\n\tEidosAssertScriptSuccess_L(\"x = c(T,T,F,F,T,F,F,T,T,F,F,T); y = matrix(x, nrow=3); identical(rowSums(y), c(1, 3, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:12; y = matrix(x, nrow=3); identical(rowSums(y), c(22, 26, 30));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:12; y = matrix(x, nrow=3); identical(rowSums(y), c(22.0, 26, 30));\", true);\n\tEidosAssertScriptSuccess_L(\"x = (rbinom(100, 1, 0.4) == 1); y = matrix(x, nrow=10); identical(rowSums(y), apply(y, 0, 'sum(applyValue);'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rdunif(100, -1000, 1000); y = matrix(x, nrow=10); identical(rowSums(y), apply(y, 0, 'sum(applyValue);'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = runif(100); y = matrix(x, nrow=10); allClose(rowSums(y), apply(y, 0, 'sum(applyValue);'));\", true);  // tolerance for SIMD\n\t\n\t// colSums()\n\tEidosAssertScriptSuccess_L(\"x = c(T,T,F,F,T,F,F,T,T,F,F,T); y = matrix(x, nrow=3); identical(colSums(y), c(2, 1, 2, 1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:12; y = matrix(x, nrow=3); identical(colSums(y), c(6, 15, 24, 33));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1.0:12; y = matrix(x, nrow=3); identical(colSums(y), c(6.0, 15, 24, 33));\", true);\n\tEidosAssertScriptSuccess_L(\"x = (rbinom(100, 1, 0.4) == 1); y = matrix(x, nrow=10); identical(colSums(y), apply(y, 1, 'sum(applyValue);'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rdunif(100, -1000, 1000); y = matrix(x, nrow=10); identical(colSums(y), apply(y, 1, 'sum(applyValue);'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = runif(100); y = matrix(x, nrow=10); allClose(colSums(y), apply(y, 1, 'sum(applyValue);'));\", true);  // tolerance for SIMD\n}\n\n#pragma mark filesystem access\nvoid _RunFunctionFilesystemTests(const std::string &temp_path)\n{\n\tif (!Eidos_TemporaryDirectoryExists())\n\t\treturn;\n\t\n\t// filesAtPath() – hard to know how to test this!  These tests should be true on Un*x machines, anyway – but might be disallowed by file permissions.\n\tEidosAssertScriptSuccess_L(\"type(filesAtPath(tempdir())) == 'string';\", true);\n\t// these always fail on Windows and I can't think of any good easy replacement\n\t#ifndef _WIN32\n\tEidosAssertScriptSuccess_L(\"type(filesAtPath('/tmp/')) == 'string';\", true);\n\tEidosAssertScriptSuccess(\"sum(filesAtPath('/') == 'bin');\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess(\"sum(filesAtPath('/', T) == '/bin');\", gStaticEidosValue_Integer1);\n\t#endif\n\tEidosAssertScriptSuccess_NULL(\"filesAtPath('foo_is_a_bad_path');\");\n\t\n\t// writeFile()\n\tEidosAssertScriptSuccess_L(\"writeFile('\" + temp_path + \"/EidosTest.txt', c(paste(0:4), paste(5:9)));\", true);\n\t\n\t// readFile() – note that the readFile() tests depend on the previous writeFile() test\n\tEidosAssertScriptSuccess_LV(\"readFile('\" + temp_path + \"/EidosTest.txt') == c(paste(0:4), paste(5:9));\", {true, true});\n\tEidosAssertScriptSuccess_L(\"all(asInteger(strsplit(paste(readFile('\" + temp_path + \"/EidosTest.txt')))) == 0:9);\", true);\n\tEidosAssertScriptSuccess_NULL(\"readFile('foo_is_a_bad_path.txt');\");\n\t\n\t// writeFile() with append\n\tEidosAssertScriptSuccess_L(\"writeFile('\" + temp_path + \"/EidosTest.txt', 'foo', T);\", true);\n\t\n\t// readFile() – note that the readFile() tests depend on the previous writeFile() test\n\tEidosAssertScriptSuccess_LV(\"readFile('\" + temp_path + \"/EidosTest.txt') == c(paste(0:4), paste(5:9), 'foo');\", {true, true, true});\n\t\n\t// fileExists() – note that the fileExists() tests depend on the previous writeFile() test\n\tEidosAssertScriptSuccess_L(\"fileExists('\" + temp_path + \"/EidosTest.txt');\", true);\n\t\n\t// deleteFile() – note that the deleteFile() tests depend on the previous writeFile() test\n\tEidosAssertScriptSuccess_L(\"deleteFile('\" + temp_path + \"/EidosTest.txt');\", true);\n\tEidosAssertScriptSuccess_L(\"deleteFile('\" + temp_path + \"/EidosTest.txt');\", false);\n\t\n\t// fileExists() – note that the fileExists() tests depend on the previous writeFile() and deleteFile() tests\n\tEidosAssertScriptSuccess_L(\"fileExists('\" + temp_path + \"/EidosTest.txt');\", false);\n\t\n\t// tempdir() - we don't try to write to it, we just call it\n\tEidosAssertScriptSuccess_L(\"d = tempdir(); length(d) > 0;\", true);\n\t\n\t// writeTempFile()\n\tEidosAssertScriptRaise(\"file = writeTempFile('eidos_test_~', '.txt', '');\", 7, \"may not contain\");\n\tEidosAssertScriptRaise(\"file = writeTempFile('eidos_test_/', '.txt', '');\", 7, \"may not contain\");\n\tEidosAssertScriptRaise(\"file = writeTempFile('eidos_test_', 'foo~.txt', '');\", 7, \"may not contain\");\n\tEidosAssertScriptRaise(\"file = writeTempFile('eidos_test_', 'foo/.txt', '');\", 7, \"may not contain\");\n\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_', '.txt', ''); identical(readFile(file), string(0));\", true);\n\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_', '.txt', 'foo'); identical(readFile(file), 'foo');\", true);\n\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_', '.txt', c(paste(0:4), paste(5:9))); identical(readFile(file), c('0 1 2 3 4', '5 6 7 8 9'));\", true);\n\t\n\t// writeFile() and writeTempFile() with compression – we don't decompress to verify, but we check for success and file existence\n\tEidosAssertScriptSuccess_L(\"writeFile('\" + temp_path + \"/EidosTest.txt', c(paste(0:4), paste(5:9)), compress=T);\", true);\n\tEidosAssertScriptSuccess_L(\"fileExists('\" + temp_path + \"/EidosTest.txt.gz');\", true);\n\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_', '.txt', 'foo'); fileExists(file);\", true);\n\t\n\t// createDirectory() – we rely on writeTempFile() to give us a file path that isn't in use, from which we derive a directory path that also shouldn't be in use\n\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_dir', '.txt', ''); dir = substr(file, 0, nchar(file) - 5); createDirectory(dir);\", true);\n\t\n\t// getwd() / setwd()\n\tEidosAssertScriptSuccess_L(\"path1 = getwd(); path2 = setwd(path1); path1 == path2;\", true);\n}\n\n#pragma mark color manipulation\nvoid _RunColorManipulationTests(void)\n{\n\t// cmColors()\n\tEidosAssertScriptRaise(\"cmColors(-1);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptRaise(\"cmColors(10000000);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptSuccess(\"cmColors(0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"cmColors(1);\", {\"#80FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"cmColors(2);\", {\"#80FFFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"cmColors(3);\", {\"#80FFFF\", \"#FFFFFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"cmColors(4);\", {\"#80FFFF\", \"#D4FFFF\", \"#FFD5FF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"cmColors(7);\", {\"#80FFFF\", \"#AAFFFF\", \"#D4FFFF\", \"#FFFFFF\", \"#FFD5FF\", \"#FFAAFF\", \"#FF80FF\"});\n\t\n\t// colors() (only palettes 'cm', 'heat', and 'terrain' get checked for their specific values)\n\tEidosAssertScriptRaise(\"colors(-1, 'cm');\", 0, \"requires 0 <= x <= 100000\");\n\tEidosAssertScriptRaise(\"colors(10000000, 'cm');\", 0, \"requires 0 <= x <= 100000\");\n\tEidosAssertScriptRaise(\"colors(5, 'foo');\", 0, \"unrecognized color palette name\");\n\tEidosAssertScriptRaise(\"colors(c(0, 1), 'cm');\", 0, \"to be singleton\");\n\tEidosAssertScriptSuccess(\"colors(0, 'cm');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"colors(1, 'cm');\", {\"#80FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(2, 'cm');\", {\"#80FFFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(3, 'cm');\", {\"#80FFFF\", \"#FFFFFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(4, 'cm');\", {\"#80FFFF\", \"#D4FFFF\", \"#FFD5FF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(7, 'cm');\", {\"#80FFFF\", \"#AAFFFF\", \"#D4FFFF\", \"#FFFFFF\", \"#FFD5FF\", \"#FFAAFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(0.0, 'cm');\", {\"#80FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(-100.0, 'cm');\", {\"#80FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(1.0, 'cm');\", {\"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(100.0, 'cm');\", {\"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(c(0.0,0.5,1.0), 'cm');\", {\"#80FFFF\", \"#FFFFFF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(c(0.5,1.0,0.0), 'cm');\", {\"#FFFFFF\", \"#FF80FF\", \"#80FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(1, 'heat');\", {\"#FF0000\"});\n\tEidosAssertScriptSuccess_SV(\"colors(5, 'heat');\", {\"#FF0000\", \"#FF5500\", \"#FFAA00\", \"#FFFF00\", \"#FFFFFF\"});\n\tEidosAssertScriptSuccess_SV(\"colors(1, 'terrain');\", {\"#00A600\"});\n\tEidosAssertScriptSuccess_SV(\"colors(5, 'terrain');\", {\"#00A600\", \"#63C600\", \"#E6E600\", \"#ECB176\", \"#F2F2F2\"});\n\tEidosAssertScriptSuccess_L(\"colors(5, 'parula'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'hot'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'jet'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'turbo'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'gray'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'magma'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'inferno'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'plasma'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'viridis'); T;\", true);\n\tEidosAssertScriptSuccess_L(\"colors(5, 'cividis'); T;\", true);\n\t\n\t// heatColors()\n\tEidosAssertScriptRaise(\"heatColors(-1);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptRaise(\"heatColors(10000000);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptSuccess(\"heatColors(0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"heatColors(1);\", {\"#FF0000\"});\n\tEidosAssertScriptSuccess_SV(\"heatColors(2);\", {\"#FF0000\", \"#FFFFFF\"});\n\tEidosAssertScriptSuccess_SV(\"heatColors(5);\", {\"#FF0000\", \"#FF5500\", \"#FFAA00\", \"#FFFF00\", \"#FFFFFF\"});\n\t\n\t// terrainColors()\n\tEidosAssertScriptRaise(\"terrainColors(-1);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptRaise(\"terrainColors(10000000);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptSuccess(\"terrainColors(0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"terrainColors(1);\", {\"#00A600\"});\n\tEidosAssertScriptSuccess_SV(\"terrainColors(2);\", {\"#00A600\", \"#F2F2F2\"});\n\tEidosAssertScriptSuccess_SV(\"terrainColors(5);\", {\"#00A600\", \"#63C600\", \"#E6E600\", \"#ECB176\", \"#F2F2F2\"});\n\t\n\t// rainbow()\n\tEidosAssertScriptRaise(\"rainbow(-1);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptRaise(\"rainbow(10000000);\", 0, \"requires 0 <= n <= 100000\");\n\tEidosAssertScriptSuccess(\"rainbow(0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"rainbow(1);\", {\"#FF0000\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(2);\", {\"#FF0000\", \"#00FFFF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(3);\", {\"#FF0000\", \"#00FF00\", \"#0000FF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(4);\", {\"#FF0000\", \"#80FF00\", \"#00FFFF\", \"#8000FF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(12);\", {\"#FF0000\", \"#FF8000\", \"#FFFF00\", \"#80FF00\", \"#00FF00\", \"#00FF80\", \"#00FFFF\", \"#0080FF\", \"#0000FF\", \"#8000FF\", \"#FF00FF\", \"#FF0080\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(6, s=0.5);\", {\"#FF8080\", \"#FFFF80\", \"#80FF80\", \"#80FFFF\", \"#8080FF\", \"#FF80FF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(6, v=0.5);\", {\"#800000\", \"#808000\", \"#008000\", \"#008080\", \"#000080\", \"#800080\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(6, s=0.5, v=0.5);\", {\"#804040\", \"#808040\", \"#408040\", \"#408080\", \"#404080\", \"#804080\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(4, start=1.0/6, end=4.0/6, ccw=T);\", {\"#FFFF00\", \"#00FF00\", \"#00FFFF\", \"#0000FF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(4, start=1.0/6, end=4.0/6, ccw=F);\", {\"#FFFF00\", \"#FF0000\", \"#FF00FF\", \"#0000FF\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(4, start=4.0/6, end=1.0/6, ccw=T);\", {\"#0000FF\", \"#FF00FF\", \"#FF0000\", \"#FFFF00\"});\n\tEidosAssertScriptSuccess_SV(\"rainbow(4, start=4.0/6, end=1.0/6, ccw=F);\", {\"#0000FF\", \"#00FFFF\", \"#00FF00\", \"#FFFF00\"});\n\tEidosAssertScriptRaise(\"rainbow(4, start=NAN, end=1.0/6, ccw=F);\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"rainbow(4, start=4.0/6, end=NAN, ccw=F);\", 0, \"color component with value NAN\");\n\t\n\t// hsv2rgb()\n\tEidosAssertScriptRaise(\"hsv2rgb(c(0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"hsv2rgb(c(0.0, 0.0, 0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"hsv2rgb(c(NAN, 0.0, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"hsv2rgb(c(0.0, NAN, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"hsv2rgb(c(0.0, 0.0, NAN));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.0, -0.5)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.0, 0.0)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.0, 0.5)), c(0.5, 0.5, 0.5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.0, 1.0)), c(1.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.0, 1.5)), c(1.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, -0.5, 1.0)), c(1.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.25, 1.0)), c(1.0, 0.75, 0.75));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.5, 1.0)), c(1.0, 0.5, 0.5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 0.75, 1.0)), c(1.0, 0.25, 0.25));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 1.0, 1.0)), c(1.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(0.0, 1.5, 1.0)), c(1.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(-0.5, 1.0, 1.0)), c(1.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(1/6, 1.0, 1.0)), c(1.0, 1.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(2/6, 1.0, 1.0)), c(0.0, 1.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(3/6, 1.0, 1.0)), c(0.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(4/6, 1.0, 1.0)), c(0.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(5/6, 1.0, 1.0)), c(1.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(6/6, 1.0, 1.0)), c(1.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(c(7/6, 1.0, 1.0)), c(1.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(hsv2rgb(matrix(c(1/6, 1.0, 1.0, 0.0, 0.25, 1.0), ncol=3, byrow=T)), matrix(c(1.0, 1.0, 0.0, 1.0, 0.75, 0.75), ncol=3, byrow=T));\", true);\n\t\n\t// rgb2hsv()\n\tEidosAssertScriptRaise(\"rgb2hsv(c(0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"rgb2hsv(c(0.0, 0.0, 0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"rgb2hsv(c(NAN, 0.0, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"rgb2hsv(c(0.0, NAN, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"rgb2hsv(c(0.0, 0.0, NAN));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(-1.0, 0.0, 0.0)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, -1.0, 0.0)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 0.0, -1.0)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 0.0, 0.0)), c(0.0, 0.0, 0.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.5, 0.5, 0.5)), c(0.0, 0.0, 0.5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 1.0, 1.0)), c(0.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.5, 1.0, 1.0)), c(0.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 1.5, 1.0)), c(0.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 1.0, 1.5)), c(0.0, 0.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 0.75, 0.75)), c(0.0, 0.25, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 0.5, 0.5)), c(0.0, 0.5, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 0.25, 0.25)), c(0.0, 0.75, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 0.0, 0.0)), c(0.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.0, 1.0, 0.0)), c(1/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 1.0, 0.0)), c(2/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 1.0, 1.0)), c(3/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 0.0, 1.0)), c(4/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(rgb2hsv(c(1.0, 0.0, 1.0)) - c(5/6, 1.0, 1.0))) < 1e-7;\", true);\t// roundoff with 5/6\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(1.5, -0.5, 0.0)), c(0.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(0.0, 1.5, -0.5)), c(2/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(c(-0.5, 0.0, 1.5)), c(4/6, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2hsv(matrix(c(1.0, 1.0, 0.0, 1.0, 0.75, 0.75), ncol=3, byrow=T)), matrix(c(1/6, 1.0, 1.0, 0.0, 0.25, 1.0), ncol=3, byrow=T));\", true);\n\t\n\t// rgb2color()\n\tEidosAssertScriptRaise(\"rgb2color(c(0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"rgb2color(c(0.0, 0.0, 0.0, 0.0));\", 0, \"must contain exactly three\");\n\tEidosAssertScriptRaise(\"rgb2color(c(NAN, 0.0, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"rgb2color(c(0.0, NAN, 0.0));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptRaise(\"rgb2color(c(0.0, 0.0, NAN));\", 0, \"color component with value NAN\");\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(-0.5, -0.5, -0.5)) == '#000000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 0.0)) == '#000000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(1.0, 1.0, 1.0)) == '#FFFFFF';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(1.5, 1.5, 1.5)) == '#FFFFFF';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(1.0, 0.0, 0.0)) == '#FF0000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 1.0, 0.0)) == '#00FF00';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 1.0)) == '#0000FF';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.25, 0.0, 0.0)) == '#400000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.25, 0.0)) == '#004000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 0.25)) == '#000040';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.5, 0.0, 0.0)) == '#800000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.5, 0.0)) == '#008000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 0.5)) == '#000080';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.75, 0.0, 0.0)) == '#BF0000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.75, 0.0)) == '#00BF00';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 0.75)) == '#0000BF';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(1.0, 0.0, 0.0)) == '#FF0000';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 1.0, 0.0)) == '#00FF00';\", true);\n\tEidosAssertScriptSuccess_L(\"rgb2color(c(0.0, 0.0, 1.0)) == '#0000FF';\", true);\n\tEidosAssertScriptSuccess_L(\"identical(rgb2color(matrix(c(0.25, 0.0, 0.0, 0.0, 0.75, 0.0, 0.0, 0.0, 1.0), ncol=3, byrow=T)), c('#400000', '#00BF00', '#0000FF'));\", true);\n\t\n\t// color2rgb()\n\tEidosAssertScriptRaise(\"identical(color2rgb('foo'), c(0.0, 0.0, 0.0));\", 10, \"could not be found\");\n\tEidosAssertScriptRaise(\"identical(color2rgb('#00000'), c(0.0, 0.0, 0.0));\", 10, \"could not be found\");\n\tEidosAssertScriptRaise(\"identical(color2rgb('#0000000'), c(0.0, 0.0, 0.0));\", 10, \"could not be found\");\n\tEidosAssertScriptRaise(\"identical(color2rgb('#0000g0'), c(0.0, 0.0, 0.0));\", 10, \"is malformed\");\n\tEidosAssertScriptSuccess_L(\"identical(color2rgb('white'), c(1.0, 1.0, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(color2rgb(c('#000000', 'red', 'green', 'blue', '#FFFFFF')), matrix(c(0.0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1), ncol=3, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('chocolate1') - c(1.0, 127/255, 36/255))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#000000') - c(0.0, 0.0, 0.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#7F0000') - c(127/255, 0.0, 0.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#FF0000') - c(1.0, 0.0, 0.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#007F00') - c(0.0, 127/255, 0.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#00FF00') - c(0.0, 1.0, 0.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#00007F') - c(0.0, 0.0, 127/255))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#0000FF') - c(0.0, 0.0, 1.0))) < 1e-7;\", true);\n\tEidosAssertScriptSuccess_L(\"sum(abs(color2rgb('#0000ff') - c(0.0, 0.0, 1.0))) < 1e-7;\", true);\n}\n\n#pragma mark miscellaneous\nvoid _RunFunctionMiscTests_apply_sapply(void)\n{\n\t// apply()\n\tEidosAssertScriptRaise(\"x=integer(0); apply(x, 0, 'applyValue^2;');\", 14, \"matrix or array\");\n\tEidosAssertScriptRaise(\"x=5; apply(x, 0, 'applyValue^2;');\", 5, \"matrix or array\");\n\tEidosAssertScriptRaise(\"x=5:9; apply(x, 0, 'applyValue^2;');\", 7, \"matrix or array\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, -1, 'applyValue^2;');\", 23, \"out of range\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, 2, 'applyValue^2;');\", 23, \"out of range\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, c(0,0), 'applyValue^2;');\", 23, \"already specified\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, integer(0), 'applyValue^2;');\", 23, \"requires that margins be specified\");\n\t\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, 0, 'setSeed(5);');\", 23, \"must return a non-void value\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, 0, 'semanticError;');\", 23, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=matrix(1:6, nrow=2); apply(x, 0, 'syntax Error;');\", 23, \"unexpected token '@Error'\");\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'sum(applyValue);'), c(9,12));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'sum(applyValue);'), c(3,7,11));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'sum(applyValue);'), matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'sum(applyValue);'), t(matrix(1:6, nrow=2)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'applyValue^2;'), matrix(c(1.0,9,25,4,16,36), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'applyValue^2;'), matrix(c(1.0,4,9,16,25,36), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'applyValue^2;'), matrix(c(1.0,4,9,16,25,36), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'applyValue^2;'), t(matrix(c(1.0,4,9,16,25,36), nrow=2)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'c(applyValue, applyValue^2);'), matrix(c(1.0,3,5,1,9,25,2,4,6,4,16,36), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'c(applyValue, applyValue^2);'), matrix(c(1.0,2,1,4,3,4,9,16,5,6,25,36), ncol=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'c(applyValue, applyValue^2);'), array(c(1.0,1,2,4,3,9,4,16,5,25,6,36), c(2,2,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'c(applyValue, applyValue^2);'), array(c(1.0,1,3,9,5,25,2,4,4,16,6,36), c(2,3,2)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'if (applyValue[0] % 2) sum(applyValue); else NULL;'), 9);\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'if (applyValue[0] % 3) sum(applyValue); else NULL;'), c(3,11));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'if (applyValue[0] % 2) sum(applyValue); else NULL;'), c(1,3,5));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'if (applyValue[0] % 2) sum(applyValue); else NULL;'), c(1,3,5));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'if (applyValue[0] % 2) applyValue^2; else NULL;'), c(1.0,9,25));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'if (applyValue[0] % 3) applyValue^2; else NULL;'), c(1.0,4,25,36));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'if (applyValue[0] % 2) applyValue^2; else NULL;'), c(1.0,9,25));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'if (applyValue[0] % 2) applyValue^2; else NULL;'), c(1.0,9,25));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 0, 'if (applyValue[0] % 2) c(applyValue, applyValue^2); else NULL;'), c(1.0,3,5,1,9,25));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, 1, 'if (applyValue[0] % 3) c(applyValue, applyValue^2); else NULL;'), c(1.0,2,1,4,5,6,25,36));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(0,1), 'if (applyValue[0] % 2) c(applyValue, applyValue^2); else NULL;'), c(1.0,1,3,9,5,25));\", true);\n\tEidosAssertScriptSuccess_L(\"x=matrix(1:6, nrow=2); identical(apply(x, c(1,0), 'if (applyValue[0] % 2) c(applyValue, applyValue^2); else NULL;'), c(1.0,1,3,9,5,25));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 0, 'sum(applyValue);'), c(36,42));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 1, 'sum(applyValue);'), c(18,26,34));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 2, 'sum(applyValue);'), c(21,57));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,1), 'sum(applyValue);'), matrix(c(8,10,12,14,16,18), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(1,2), 'sum(applyValue);'), matrix(c(3,7,11,15,19,23), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,2), 'sum(applyValue);'), matrix(c(9,12,27,30), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,1,2), 'sum(applyValue);'), array(1:12, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(2,1,0), 'sum(applyValue);'), array(c(1,7,3,9,5,11,2,8,4,10,6,12), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(2,0,1), 'sum(applyValue);'), array(c(1,7,2,8,3,9,4,10,5,11,6,12), c(2,2,3)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 0, 'applyValue^2;'), matrix(c(1.0,9,25,49,81,121,4,16,36,64,100,144), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 1, 'applyValue^2;'), matrix(c(1.0,4,49,64,9,16,81,100,25,36,121,144), ncol=3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, 2, 'applyValue^2;'), matrix(c(1.0,4,9,16,25,36,49,64,81,100,121,144), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,1), 'applyValue^2;'), array(c(1.0,49,4,64,9,81,16,100,25,121,36,144), c(2,2,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(1,2), 'applyValue^2;'), array(c(1.0,4,9,16,25,36,49,64,81,100,121,144), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,2), 'applyValue^2;'), array(c(1.0,9,25,4,16,36,49,81,121,64,100,144), c(3,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(0,1,2), 'applyValue^2;'), array((1.0:12)^2, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(2,1,0), 'applyValue^2;'), array(c(1.0,49,9,81,25,121,4,64,16,100,36,144), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = array(1:12, c(2,3,2)); identical(apply(y, c(2,0,1), 'applyValue^2;'), array(c(1.0,49,4,64,9,81,16,100,25,121,36,144), c(2,2,3)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, 0, 'sum(applyValue);'), c(144,156));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, 1, 'sum(applyValue);'), c(84,100,116));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, 2, 'sum(applyValue);'), c(114,186));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, 3, 'sum(applyValue);'), c(78,222));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(0,1), 'sum(applyValue);'), matrix(c(40,44,48,52,56,60), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(0,2), 'sum(applyValue);'), matrix(c(54,60,90,96), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(0,3), 'sum(applyValue);'), matrix(c(36,42,108,114), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(1,0), 'sum(applyValue);'), matrix(c(40,48,56,44,52,60), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(1,2), 'sum(applyValue);'), matrix(c(30,38,46,54,62,70), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(1,3), 'sum(applyValue);'), matrix(c(18,26,34,66,74,82), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(2,0), 'sum(applyValue);'), matrix(c(54,90,60,96), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(2,1), 'sum(applyValue);'), matrix(c(30,54,38,62,46,70), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(2,3), 'sum(applyValue);'), matrix(c(21,57,93,129), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(3,0), 'sum(applyValue);'), matrix(c(36,108,42,114), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(3,1), 'sum(applyValue);'), matrix(c(18,66,26,74,34,82), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(3,2), 'sum(applyValue);'), matrix(c(21,93,57,129), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(0,1,2), 'sum(applyValue);'), array(c(14,16,18,20,22,24,26,28,30,32,34,36), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(3,1,0), 'sum(applyValue);'), array(c(8,32,12,36,16,40,10,34,14,38,18,42), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"z = array(1:24, c(2,3,2,2)); identical(apply(z, c(2,3,0,1), 'sum(applyValue);'), array(c(1,7,13,19,2,8,14,20,3,9,15,21,4,10,16,22,5,11,17,23,6,12,18,24), c(2,2,2,3)));\", true);\n\t\n\t// sapply()\n\tEidosAssertScriptSuccess_NULL(\"x=integer(0); sapply(x, 'applyValue^2;');\");\n\tEidosAssertScriptSuccess_FV(\"x=1:5; sapply(x, 'applyValue^2;');\", {1, 4, 9, 16, 25});\n\tEidosAssertScriptSuccess_IV(\"x=1:5; sapply(x, 'product(1:applyValue);');\", {1, 2, 6, 24, 120});\n\tEidosAssertScriptSuccess_SV(\"x=1:3; sapply(x, \\\"rep(''+applyValue, applyValue);\\\");\", {\"1\", \"2\", \"2\", \"3\", \"3\", \"3\"});\n\tEidosAssertScriptSuccess_SV(\"x=1:5; sapply(x, \\\"paste(rep(''+applyValue, applyValue), sep='');\\\");\", {\"1\", \"22\", \"333\", \"4444\", \"55555\"});\n\tEidosAssertScriptSuccess_IV(\"x=1:10; sapply(x, 'if (applyValue % 2) applyValue; else NULL;');\", {1, 3, 5, 7, 9});\n\tEidosAssertScriptSuccess_I(\"x=1:5; sapply(x, 'y=applyValue; NULL;'); y;\", 5);\n\tEidosAssertScriptSuccess_IV(\"x=1:5; sapply(x, 'y=applyValue; y;');\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_F(\"x=2; for (i in 1:2) x=sapply(x, 'applyValue^2;'); x;\", 16.0);\n\tEidosAssertScriptRaise(\"x=2; sapply(x, 'semanticError;');\", 5, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; sapply(x, y);\", 25, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; sapply(x, y[T]);\", 25, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; sapply(x, 'syntax Error;');\", 5, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; sapply(x, y);\", 24, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; sapply(x, y[T]);\", 24, \"unexpected token '@Error'\");\n\tEidosAssertScriptSuccess_I(\"x=2; y='x;'; sapply(x, y[T]);\", 2);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'integer(0);'), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'integer(0);', simplify='vector'), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'integer(0);', simplify='matrix'), integer(0));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(1:6, 'integer(0);', simplify='match'), 2:7);\", 10, \"not all singletons\");\n\tEidosAssertScriptRaise(\"identical(sapply(1:6, 'integer(0);', simplify='foo'), integer(0));\", 10, \"unrecognized simplify option\");\n\tEidosAssertScriptRaise(\"identical(sapply(1:6, 'setSeed(5);'), integer(0));\", 10, \"must return a non-void value\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'applyValue+1;'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'applyValue+1;', simplify='vector'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'applyValue+1;', simplify='matrix'), matrix(2:7, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'applyValue+1;', simplify='match'), 2:7);\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'applyValue+1;'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'applyValue+1;', simplify='vector'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'applyValue+1;', simplify='matrix'), matrix(2:7, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'applyValue+1;', simplify='match'), matrix(2:7, nrow=1));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'applyValue+1;'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'applyValue+1;', simplify='vector'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'applyValue+1;', simplify='matrix'), matrix(2:7, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'applyValue+1;', simplify='match'), matrix(2:7, ncol=1));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'applyValue+1;'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'applyValue+1;', simplify='vector'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'applyValue+1;', simplify='matrix'), matrix(2:7, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'applyValue+1;', simplify='match'), matrix(2:7, ncol=2));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'c(applyValue, applyValue+1);'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'c(applyValue, applyValue+1);', simplify='vector'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'c(applyValue, applyValue+1);', simplify='matrix'), matrix(c(1,2,2,3,3,4,4,5,5,6,6,7), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(matrix(1:6, ncol=2), 'c(applyValue, applyValue+1);', simplify='match'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", 10, \"not all singletons\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'applyValue+1;'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'applyValue+1;', simplify='vector'), 2:7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'applyValue+1;', simplify='matrix'), matrix(2:7, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'applyValue+1;', simplify='match'), array(2:7, c(2,1,3)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'c(applyValue, applyValue+1);'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'c(applyValue, applyValue+1);', simplify='vector'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'c(applyValue, applyValue+1);', simplify='matrix'), matrix(c(1,2,2,3,3,4,4,5,5,6,6,7), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(array(1:6, c(2,1,3)), 'c(applyValue, applyValue+1);', simplify='match'), c(1,2,2,3,3,4,4,5,5,6,6,7));\", 10, \"not all singletons\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'if (applyValue % 2) applyValue+1; else NULL;'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'if (applyValue % 2) applyValue+1; else NULL;', simplify='vector'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(1:6, 'if (applyValue % 2) applyValue+1; else NULL;', simplify='matrix'), matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(1:6, 'if (applyValue % 2) applyValue+1; else NULL;', simplify='match'), c(2,4,6));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'if (applyValue % 2) applyValue+1; else NULL;'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='vector'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, nrow=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='matrix'), matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(matrix(1:6, nrow=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='match'), matrix(c(2,4,6), nrow=1));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'if (applyValue % 2) applyValue+1; else NULL;'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='vector'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='matrix'), matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(matrix(1:6, ncol=1), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='match'), matrix(c(2,4,6), ncol=1));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) applyValue+1; else NULL;'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='vector'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='matrix'), matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='match'), matrix(c(2,4,6), ncol=2));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;'), c(1,3,3,5,5,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='vector'), c(1,3,3,5,5,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='matrix'), matrix(c(1,3,3,5,5,7), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(matrix(1:6, ncol=2), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='match'), c(1,3,3,5,5,7));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) applyValue+1; else NULL;'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='vector'), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='matrix'), matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) applyValue+1; else NULL;', simplify='match'), array(c(2,4,6), c(2,1,3)));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;'), c(1,3,3,5,5,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='vector'), c(1,3,3,5,5,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='matrix'), matrix(c(1,3,3,5,5,7), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else NULL;', simplify='match'), c(1,3,3,5,5,7));\", 10, \"included NULL\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else applyValue;'), c(1,3,2,3,5,4,5,7,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else applyValue;', simplify='vector'), c(1,3,2,3,5,4,5,7,6));\", true);\n\tEidosAssertScriptRaise(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else applyValue;', simplify='matrix'), matrix(c(1,3,2,3,5,4,5,7,6), nrow=2));\", 10, \"not of a consistent length\");\n\tEidosAssertScriptRaise(\"identical(sapply(array(1:6, c(2,1,3)), 'if (applyValue % 2) c(applyValue, applyValue+2); else applyValue;', simplify='match'), c(1,3,2,3,5,4,5,7,6));\", 10, \"not all singletons\");\n}\n\nvoid _RunFunctionMiscTests(const std::string &temp_path)\n{\n\t// assert()\n\tEidosAssertScriptRaise(\"assert();\", 0, \"missing required argument 'assertions'\");\n\tEidosAssertScriptSuccess_VOID(\"assert(T);\");\n\tEidosAssertScriptRaise(\"assert(F);\", 0, \"assertion failed\");\n\tEidosAssertScriptSuccess_VOID(\"assert(c(T, T, T, T, T));\");\n\tEidosAssertScriptRaise(\"assert(c(F, F, F, T, F));\", 0, \"assertion failed\");\n\tEidosAssertScriptRaise(\"assert(c(F, F, F, F, F));\", 0, \"assertion failed\");\n\tEidosAssertScriptSuccess_VOID(\"assert(T, 'foo bar!');\");\n\tEidosAssertScriptRaise(\"assert(F, 'foo bar!');\", 0, \"foo bar!\");\n\n\t// beep() – this is commented out by default since it would confuse people if the Eidos self-test beeped...\n\t//EidosAssertScriptSuccess_NULL(\"beep();\");\n\t//EidosAssertScriptSuccess_NULL(\"beep('Submarine');\");\n\t\n\t// citation()\n\tEidosAssertScriptSuccess_VOID(\"citation();\");\n\tEidosAssertScriptRaise(\"citation(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"citation(T);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"citation(3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"citation(3.5);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"citation('foo');\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"citation(_Test(7));\", 0, \"too many arguments supplied\");\n\t\n\t// clock()\n\tEidosAssertScriptSuccess_L(\"c = clock(); isFloat(c);\", true);\n\tEidosAssertScriptSuccess_L(\"c = clock('cpu'); isFloat(c);\", true);\n\tEidosAssertScriptSuccess_L(\"c = clock('mono'); isFloat(c);\", true);\n\tEidosAssertScriptRaise(\"clock('foo');\", 0, \"unrecognized clock type\");\n\t\n\t// date()\n\tEidosAssertScriptSuccess_I(\"size(strsplit(date(), '-'));\", 3);\n\tEidosAssertScriptRaise(\"date(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"date(T);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"date(3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"date(3.5);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"date('foo');\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"date(_Test(7));\", 0, \"too many arguments supplied\");\n\t\n\t// defineConstant()\n\tEidosAssertScriptSuccess_I(\"defineConstant('foo', 5:10); sum(foo);\", 45);\n\tEidosAssertScriptRaise(\"defineConstant('T', 5:10);\", 0, \"is already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('foo', 5:10); defineConstant('foo', 5:10); sum(foo);\", 29, \"is already defined\");\n\tEidosAssertScriptRaise(\"foo = 5:10; defineConstant('foo', 5:10); sum(foo);\", 12, \"is already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('foo', 5:10); rm('foo');\", 29, \"cannot be removed\");\n\tEidosAssertScriptSuccess_I(\"defineConstant('foo', _Test(5)); foo._yolk;\", 5);\n\tEidosAssertScriptRaise(\"defineConstant('foo', _TestNRR(5)); foo._yolk;\", 0, \"retain/release\");\t// leaks due to _TestNRR, not a bug\n\t\n\t// defineGlobal()\n\tEidosAssertScriptSuccess_I(\"defineGlobal('foo', 5:10); sum(foo);\", 45);\n\tEidosAssertScriptRaise(\"defineGlobal('T', 5:10);\", 0, \"is already defined as a constant\");\n\tEidosAssertScriptSuccess_I(\"defineGlobal('foo', 5:11); defineGlobal('foo', 5:10); sum(foo);\", 45);\n\tEidosAssertScriptSuccess_I(\"foo = 5:11; defineGlobal('foo', 5:10); sum(foo);\", 45);\t\t// we're in the global namespace anyway\n\tEidosAssertScriptRaise(\"defineGlobal('foo', 5:10); rm('foo'); sum(foo);\", 42, \"undefined identifier\");\n\tEidosAssertScriptSuccess_I(\"defineGlobal('foo', _Test(5)); foo._yolk;\", 5);\n\tEidosAssertScriptRaise(\"defineGlobal('foo', _TestNRR(5)); foo._yolk;\", 0, \"retain/release\");\t// leaks due to _TestNRR, not a bug\n\t\n\t// doCall()\n\tEidosAssertScriptSuccess_L(\"abs(doCall('sin', 0.0) - 0) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(doCall('sin', PI/2) - 1) < 0.000001;\", true);\n\tEidosAssertScriptRaise(\"doCall('sin');\", 0, \"requires 1 argument(s), but 0 are supplied\");\n\tEidosAssertScriptRaise(\"doCall('sin', 'bar');\", 0, \"cannot be type string\");\n\tEidosAssertScriptRaise(\"doCall('sin', 0, 1);\", 0, \"requires at most 1 argument\");\n\tEidosAssertScriptRaise(\"doCall('si', 0, 1);\", 0, \"unrecognized function name\");\n\t\n\t// executeLambda()\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x^2;');\", 49);\n\tEidosAssertScriptRaise(\"x=7; executeLambda('x^2');\", 5, \"unexpected token\");\n\tEidosAssertScriptRaise(\"x=7; executeLambda(c('x^2;', '5;'));\", 5, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"x=7; executeLambda(string(0));\", 5, \"must be a singleton\");\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x=x^2+4;'); x;\", 53);\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x=x^2+4;', timed=T); x;\", 53);\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x=x^2+4;', timed='cpu'); x;\", 53);\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x=x^2+4;', timed='mono'); x;\", 53);\n\t//EidosAssertScriptRaise(\"x=7; executeLambda('x=x^2+4;', timed='foo'); x;\", 5, \"clock type\");\t// FIXME raise doesn't come through correctly!\n\tEidosAssertScriptRaise(\"executeLambda(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(3);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(3.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"x=2; for (i in 1:2) executeLambda('semanticError;'); x;\", 20, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; for (i in 1:2) executeLambda(y); x;\", 40, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; for (i in 1:2) executeLambda(y[T]); x;\", 40, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; for (i in 1:2) executeLambda('syntax Error;'); x;\", 20, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; for (i in 1:2) executeLambda(y); x;\", 39, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; for (i in 1:2) executeLambda(y[T]); x;\", 39, \"unexpected token '@Error'\");\n\tEidosAssertScriptSuccess_F(\"x=2; for (i in 1:2) executeLambda('x=x^2;'); x;\", 16);\n\tEidosAssertScriptSuccess_F(\"x=2; y='x=x^2;'; for (i in 1:2) executeLambda(y); x;\", 16);\n\tEidosAssertScriptSuccess_F(\"x=2; y='x=x^2;'; for (i in 1:2) executeLambda(y[T]); x;\", 16);\n\t\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x^2;', T);\", 49);\n\tEidosAssertScriptRaise(\"x=7; executeLambda('x^2', T);\", 5, \"unexpected token\");\n\tEidosAssertScriptRaise(\"x=7; executeLambda(c('x^2;', '5;'), T);\", 5, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"x=7; executeLambda(string(0), T);\", 5, \"must be a singleton\");\n\tEidosAssertScriptSuccess_F(\"x=7; executeLambda('x=x^2+4;', T); x;\", 53);\n\tEidosAssertScriptRaise(\"executeLambda(NULL, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(T, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(3, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(3.5, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"executeLambda(_Test(7), T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"x=2; for (i in 1:2) executeLambda('semanticError;', T); x;\", 20, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; for (i in 1:2) executeLambda(y, T); x;\", 40, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; y='semanticError;'; for (i in 1:2) executeLambda(y[T], T); x;\", 40, \"undefined identifier semanticError\");\n\tEidosAssertScriptRaise(\"x=2; for (i in 1:2) executeLambda('syntax Error;', T); x;\", 20, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; for (i in 1:2) executeLambda(y, T); x;\", 39, \"unexpected token '@Error'\");\n\tEidosAssertScriptRaise(\"x=2; y='syntax Error;'; for (i in 1:2) executeLambda(y[T], T); x;\", 39, \"unexpected token '@Error'\");\n\tEidosAssertScriptSuccess_F(\"x=2; for (i in 1:2) executeLambda('x=x^2;', T); x;\", 16);\n\tEidosAssertScriptSuccess_F(\"x=2; y='x=x^2;'; for (i in 1:2) executeLambda(y, T); x;\", 16);\n\tEidosAssertScriptSuccess_F(\"x=2; y='x=x^2;'; for (i in 1:2) executeLambda(y[T], T); x;\", 16);\n\n\t// exists()\n\tEidosAssertScriptSuccess_L(\"exists('T');\", true);\n\tEidosAssertScriptSuccess_L(\"exists('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"foo = 5:10; exists('foo');\", true);\n\tEidosAssertScriptSuccess_L(\"foo = 5:10; rm('foo'); exists('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"defineConstant('foo', 5:10); exists('foo');\", true);\n\tEidosAssertScriptSuccess_LV(\"a=5; c=7.0; g='foo'; exists(c('a', 'b', 'c', 'd', 'e', 'f', 'g'));\", {true, false, true, false, false, false, true});\n\tEidosAssertScriptSuccess_LV(\"exists(c('T', 'Q', 'F', 'PW', 'PI', 'D', 'E'));\", {true, false, true, false, true, false, true});\n\t\n\t// functionSignature()\n\tEidosAssertScriptSuccess_VOID(\"functionSignature();\");\n\tEidosAssertScriptSuccess_VOID(\"functionSignature('functionSignature');\");\n\tEidosAssertScriptSuccess_VOID(\"functionSignature('foo');\");\t// does not throw at present\n\tEidosAssertScriptRaise(\"functionSignature(string(0));\", 0, \"must be a singleton\");\n\tEidosAssertScriptSuccess_VOID(\"functionSignature(NULL);\");\t\t// same as omitting the parameter\n\tEidosAssertScriptRaise(\"functionSignature(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"functionSignature(3);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"functionSignature(3.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"functionSignature(_Test(7));\", 0, \"cannot be type\");\n\t\n\t// functionSource()\n\tEidosAssertScriptSuccess_VOID(\"functionSource('foo');\");\t // does not throw at present\n\tEidosAssertScriptSuccess_VOID(\"functionSource('mean');\");\n\tEidosAssertScriptSuccess_VOID(\"functionSource('source');\");\n\t\n\t// ls()\n\tEidosAssertScriptSuccess_VOID(\"ls();\");\n\tEidosAssertScriptSuccess_VOID(\"ls(F);\");\n\tEidosAssertScriptSuccess_VOID(\"ls(T);\");\n\t\n\t// license()\n\tEidosAssertScriptSuccess_VOID(\"license();\");\n\tEidosAssertScriptRaise(\"license(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"license(T);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"license(3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"license(3.5);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"license('foo');\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"license(_Test(7));\", 0, \"too many arguments supplied\");\n\t\n\t// rm()\n\tEidosAssertScriptSuccess_VOID(\"rm();\");\n\tEidosAssertScriptRaise(\"x=37; rm('x'); x;\", 15, \"undefined identifier\");\n\tEidosAssertScriptSuccess_I(\"x=37; rm('y'); x;\", 37);\n\tEidosAssertScriptRaise(\"x=37; rm(); x;\", 12, \"undefined identifier\");\n\tEidosAssertScriptRaise(\"rm(3);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(3.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(F);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_VOID(\"rm(NULL);\");\t\t// same as omitting the parameter\n\tEidosAssertScriptRaise(\"rm(INF);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(NAN);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(E);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm(PI);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"rm('PI');\", 0, \"intrinsic Eidos constant\");\n\tEidosAssertScriptRaise(\"defineConstant('foo', 1:10); rm('foo'); foo;\", 29, \"is a constant\");\n\t\n\t// setSeed()\n\tEidosAssertScriptSuccess_L(\"setSeed(5); x=runif(10); setSeed(5); y=runif(10); all(x==y);\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(5); x=runif(10); setSeed(6); y=runif(10); all(x==y);\", false);\n\tEidosAssertScriptRaise(\"setSeed(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"setSeed(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"setSeed(3.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"setSeed('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"setSeed(_Test(7));\", 0, \"cannot be type\");\n\t\n\t// getSeed()\n\tEidosAssertScriptSuccess_I(\"setSeed(13); getSeed();\", 13);\n\tEidosAssertScriptSuccess_I(\"setSeed(13); setSeed(7); getSeed();\", 7);\n\tEidosAssertScriptRaise(\"getSeed(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"getSeed(T);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"getSeed(3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"getSeed(3.5);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"getSeed('foo');\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"getSeed(_Test(7));\", 0, \"too many arguments supplied\");\n\t\n\t// source()\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tEidosAssertScriptSuccess_I(\"path = '\" + temp_path + \"'; file = path + '/EidosSourceTest.txt'; writeFile(file, 'x=9*9;'); source(file); x;\", 81);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// finds the file and executes it correctly\n\t\tEidosAssertScriptSuccess_L(\"path = '\" + temp_path + \"'; file = path + '/EidosSourceTest2.txt'; writeFile(file, 'x = getwd();'); d = getwd(); source(file, chdir=F); x == d;\", true);\t\t\t\t\t// doesn't change the wd with chdir=F\n\t\tEidosAssertScriptSuccess_L(\"path = '\" + temp_path + \"'; file = path + '/EidosSourceTest3.txt'; writeFile(file, 'x = getwd();'); d = getwd(); source(file, chdir=T); d == getwd();\", true);\t\t\t\t// any change is temporary with chdir=T\n\t\tEidosAssertScriptSuccess_L(\"path = '\" + temp_path + \"'; file = path + '/EidosSourceTest3.txt'; writeFile(file, 'x = getwd();'); source(file, chdir=T); setwd(path); d = getwd(); x == d;\", true);\t\t// change is correct with chdir=T; might not match temp_path due to symlinks\n\t}\n\tEidosAssertScriptRaise(\"source('/this/path/presumably/does/not/exist/foo_bar_baz_12345.eidos');\", 0, \"file not found at path\");\n\t\n\t// stop()\n\tEidosAssertScriptRaise(\"stop();\", 0, \"stop() called\");\n\tEidosAssertScriptRaise(\"stop('Error');\", 0, \"stop() called with error message:\");\n\tEidosAssertScriptRaise(\"stop(NULL);\", 0, \"stop() called\");\t\t// same as omitting the parameter\n\tEidosAssertScriptRaise(\"stop(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"stop(3);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"stop(3.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"stop(_Test(7));\", 0, \"cannot be type\");\n\t\n\t// suppressWarnings()\n\tEidosAssertScriptSuccess_L(\"suppressWarnings(F);\", false);\n\tEidosAssertScriptSuccess_L(\"suppressWarnings(T);\", false);\n\tEidosAssertScriptSuccess_L(\"suppressWarnings(T); suppressWarnings(F);\", true);\n\t\n\t// sysinfo()\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('os'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('sysname'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('release'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('version'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('nodename'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('machine'); length(x) > 0;\", true);\n\t// These two keys are not yet supported due to problems on Windows and Ubuntu 18.04\n\t//EidosAssertScriptSuccess_L(\"x = sysinfo('login'); length(x) > 0;\", true);\n\t//EidosAssertScriptSuccess_L(\"x = sysinfo('user'); length(x) > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"x = sysinfo('foo'); x == 'unknown';\", true);\n\t\n\t// system()\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tEidosAssertScriptRaise(\"system('');\", 0, \"non-empty command string\");\n\t\t// sadly none of the original tests work in Windows, including the echo one, \n\t\t// because Windows does not understand ;\n\t\t// here I just make Windows versions of each original test (see the #else below)\n\t\t#ifdef _WIN32\n\t\tEidosAssertScriptSuccess_S(\"system('set /a 5 + 5');\", \"10\");\n\t\tEidosAssertScriptSuccess_S(\"system('set', args=c('/a', '5', '+', '5'));\", \"10\");\n\t\t// BCH 2/16/2024: This is a continuing source of confusion since the \"Divide by zero error\" is localization-specific.  Commenting out; not worth it.\n\t\t//EidosAssertScriptSuccess_S(\"system('set /a 5 / 0', stderr=T);\", \"Divide by zero error.\");\n\t\tEidosAssertScriptSuccess_S(\"system('echo foo');\", \"foo\");\n\t\t// input doesn't currently work because ofstream() fails\n\t\tEidosAssertScriptSuccess_SV(\"system('echo foo&echo bar&echo baz');\", {\"foo\", \"bar\", \"baz\"});\n\t\t#else\n\t\tEidosAssertScriptSuccess_S(\"system('expr 5 + 5');\", \"10\");\n\t\tEidosAssertScriptSuccess_S(\"system('expr', args=c('5', '+', '5'));\", \"10\");\n\t\t// BCH 2/16/2024: This is a continuing source of confusion since the \"Divide by zero error\" is localization-specific.  Commenting out; not worth it.\n\t\t//EidosAssertScriptSuccess_L(\"err = system('expr 5 / 0', stderr=T); (err == 'expr: division by zero') | (err == 'expr: división por cero') | (err == 'expr: division par zéro') | (substr(err, 0, 5) == 'expr: ');\", true);\n\t\tEidosAssertScriptSuccess_S(\"system('printf foo');\", \"foo\");\n\t\tEidosAssertScriptSuccess_S(\"system(\\\"printf 'foo bar baz' | wc -m | sed 's/ //g'\\\");\", \"11\");\n\t\tEidosAssertScriptSuccess_S(\"system(\\\"(wc -l | sed 's/ //g')\\\", input='foo\\\\nbar\\\\nbaz\\\\n');\", \"3\");\n\t\tEidosAssertScriptSuccess_S(\"system(\\\"(wc -l | sed 's/ //g')\\\", input=c('foo', 'bar', 'baz'));\", \"3\");\n\t\tEidosAssertScriptSuccess_SV(\"system(\\\"echo foo; echo bar; echo baz;\\\");\", {\"foo\", \"bar\", \"baz\"});\n\t\t#endif\n\t}\n\t\n\t// time()\n\tEidosAssertScriptSuccess_I(\"size(strsplit(time(), ':'));\", 3);\n\tEidosAssertScriptRaise(\"time(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"time(T);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"time(3);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"time(3.5);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"time('foo');\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"time(_Test(7));\", 0, \"too many arguments supplied\");\n\t\n\t// usage(); allow zero since this call returns zero on some less-supported platforms\n\tEidosAssertScriptSuccess_L(\"usage() >= 0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"usage(F) >= 0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"usage(T) >= 0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"usage('rss') >= 0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"usage('rss_peak') >= 0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"usage('vm') >= 0.0;\", true);\n\tEidosAssertScriptRaise(\"usage('foo') >= 0.0;\", 0, \"type should be\");\n\t\n\t// version()\n\tEidosAssertScriptSuccess_L(\"type(version(T)) == 'float';\", true);\n\tEidosAssertScriptSuccess_L(\"type(version(F)) == 'float';\", true);\n\tEidosAssertScriptRaise(\"version(NULL);\", 0, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"version(3);\", 0, \"cannot be type integer\");\n\tEidosAssertScriptRaise(\"version(3.5);\", 0, \"cannot be type float\");\n\tEidosAssertScriptRaise(\"version('foo');\", 0, \"cannot be type string\");\n\tEidosAssertScriptRaise(\"version(_Test(7));\", 0, \"cannot be type object\");\n}\n\n#pragma mark classes\nvoid _RunClassTests(const std::string &temp_path)\n{\n\t// Test EidosObject methods, using EidosTestElement since EidosObject is an abstract base class\n\t\n\t// methodSignature()\n\tEidosAssertScriptSuccess_VOID(\"_Test(7).methodSignature();\");\n\tEidosAssertScriptSuccess_VOID(\"_Test(7).methodSignature('methodSignature');\");\n\tEidosAssertScriptSuccess_VOID(\"matrix(_Test(7)).methodSignature('methodSignature');\");\n\t\n\t// propertySignature()\n\tEidosAssertScriptSuccess_VOID(\"_Test(7).propertySignature();\");\n\tEidosAssertScriptSuccess_VOID(\"_Test(7).propertySignature('_yolk');\");\n\tEidosAssertScriptSuccess_VOID(\"matrix(_Test(7)).propertySignature('_yolk');\");\n\t\n\t// size() / length()\n\tEidosAssertScriptSuccess(\"_Test(7).size();\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"rep(_Test(7), 5).size();\", 5);\n\tEidosAssertScriptSuccess_I(\"matrix(rep(_Test(7), 5)).size();\", 5);\n\t\n\tEidosAssertScriptSuccess(\"_Test(7).length();\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"rep(_Test(7), 5).length();\", 5);\n\tEidosAssertScriptSuccess_I(\"matrix(rep(_Test(7), 5)).length();\", 5);\n\t\n\t// str()\n\tEidosAssertScriptSuccess_VOID(\"_Test(7).str();\");\n\tEidosAssertScriptSuccess_VOID(\"c(_Test(7), _Test(8), _Test(9)).str();\");\n\tEidosAssertScriptSuccess_VOID(\"matrix(_Test(7)).str();\");\n\tEidosAssertScriptSuccess_VOID(\"matrix(c(_Test(7), _Test(8), _Test(9))).str();\");\n\t\n\t// stringRepresentation()\n\tEidosAssertScriptSuccess_SV(\"matrix(rep(_Test(7), 3)).stringRepresentation();\", {\"_TestElement\", \"_TestElement\", \"_TestElement\"});\n\tEidosAssertScriptSuccess_S(\"Dictionary('a', 1:3, 'b', 5:6).stringRepresentation();\", R\"V0G0N({\"a\"=1 2 3;\"b\"=5 6;})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"Dictionary('b', 5:6, 'a', 1:3).stringRepresentation();\", R\"V0G0N({\"a\"=1 2 3;\"b\"=5 6;})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"Dictionary(10, 1:3, 15, 5:6).stringRepresentation();\", \"{10=1 2 3;15=5 6;}\");\n\tEidosAssertScriptSuccess_S(\"Dictionary(15, 5:6, 10, 1:3).stringRepresentation();\", \"{10=1 2 3;15=5 6;}\");\n\t\n\t// Test EidosDictionaryUnretained properties and methods, using EidosDictionaryRetained\n\t// since there's no way to instantiate an EidosDictionaryUnretained directly\n\t\n\t// setValue() / getValue()\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); x.getValue('a');\");\n\tEidosAssertScriptSuccess_LV(\"x = Dictionary(); x.setValue('a', c(T,F,T)); x.getValue('a');\", {true,false,true});\n\tEidosAssertScriptSuccess_IV(\"x = Dictionary(); x.setValue('a', 7:9); x.getValue('a');\", {7,8,9});\n\tEidosAssertScriptSuccess_FV(\"x = Dictionary(); x.setValue('a', 7.0:9); x.getValue('a');\", {7,8,9});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('baz', c('foo', 'bar')); x.getValue('baz');\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); y = Dictionary(); y.setValue('foo', 'bar'); x.setValue('a', y); x.getValue('a').getValue('foo');\", \"bar\");\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); x.setValue('a', 7:9); x.setValue('a', NULL); x.getValue('a');\");\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); y = Dictionary(); y.setValue('foo', 'bar'); x.setValue('a', y); x.getValue('a').setValue('foo', NULL); x.getValue('a').getValue('foo');\");\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('a', 7:9); x.setValue(5, 5:8);\", 42, \"integer key\");\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('a', 7:9); x.getValue(5);\", 42, \"integer key\");\n\t\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); x.getValue(5);\");\n\tEidosAssertScriptSuccess_LV(\"x = Dictionary(); x.setValue(5, c(T,F,T)); x.getValue(5);\", {true,false,true});\n\tEidosAssertScriptSuccess_IV(\"x = Dictionary(); x.setValue(5, 7:9); x.getValue(5);\", {7,8,9});\n\tEidosAssertScriptSuccess_FV(\"x = Dictionary(); x.setValue(5, 7.0:9); x.getValue(5);\", {7,8,9});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, c('foo', 'bar')); x.getValue(5);\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); y = Dictionary(); y.setValue(5, 'bar'); x.setValue(7, y); x.getValue(7).getValue(5);\", \"bar\");\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); x.setValue(5, 7:9); x.setValue(5, NULL); x.getValue(5);\");\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); y = Dictionary(); y.setValue(5, 'bar'); x.setValue(7, y); x.getValue(7).setValue(5, NULL); x.getValue(7).getValue(5);\");\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 7:9); x.setValue('a', 5:8);\", 40, \"string key\");\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 7:9); x.getValue('a');\", 40, \"string key\");\n\t\n\t// allKeys\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.allKeys;\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('bar', c(T,F,T)); x.allKeys;\", \"bar\");\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', c(T,F,T)); x.setValue('foo', 7:9); x.setValue('baz', 7.0:9); x.allKeys;\", {\"bar\", \"baz\", \"foo\"});\n\t\n\tEidosAssertScriptSuccess_I(\"x = Dictionary(); x.setValue(5, c(T,F,T)); x.allKeys;\", 5);\n\tEidosAssertScriptSuccess_IV(\"x = Dictionary(); x.setValue(1, c(T,F,T)); x.setValue(5, 7:9); x.setValue(3, 7.0:9); x.allKeys;\", {1, 3, 5});\n\t\n\t// addKeysAndValuesFrom()\n\tEidosAssertScriptSuccess(\"x = Dictionary(); y = x; x.setValue('bar', 2); y.getValue('bar');\", gStaticEidosValue_Integer2);\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue('bar', 2); y.getValue('bar');\");\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue('bar', 2); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue('bar', 1); y.getValue('bar');\", gStaticEidosValue_Integer2);\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue('bar', 2); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue('bar', 1); x.getValue('bar');\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 2); x.setValue('baz', 'foo'); y = Dictionary(); y.addKeysAndValuesFrom(x); y.setValue('xyzzy', 17); sort(y.allKeys);\", {\"bar\", \"baz\", \"xyzzy\"});\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('bar', 2); x.setValue('baz', 'foo'); y = Dictionary(); y.addKeysAndValuesFrom(x); y.setValue('baz', NULL); y.allKeys;\", \"bar\");\n\t\n\tEidosAssertScriptSuccess(\"x = Dictionary(); y = x; x.setValue(5, 2); y.getValue(5);\", gStaticEidosValue_Integer2);\n\tEidosAssertScriptSuccess_NULL(\"x = Dictionary(); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue(5, 2); y.getValue(5);\");\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue(5, 2); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue(5, 1); y.getValue(5);\", gStaticEidosValue_Integer2);\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue(5, 2); y = Dictionary(); y.addKeysAndValuesFrom(x); x.setValue(5, 1); x.getValue(5);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_IV(\"x = Dictionary(); x.setValue(5, 2); x.setValue(7, 'foo'); y = Dictionary(); y.addKeysAndValuesFrom(x); y.setValue(9, 17); sort(y.allKeys);\", {5, 7, 9});\n\tEidosAssertScriptSuccess_I(\"x = Dictionary(); x.setValue(5, 2); x.setValue(7, 'foo'); y = Dictionary(); y.addKeysAndValuesFrom(x); y.setValue(7, NULL); y.allKeys;\", 5);\n\t\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 2); y = Dictionary(); y.setValue('a', 'foo'); y.addKeysAndValuesFrom(x);\", 80, \"integer key\");\n\t\n\t// Dictionary(...)\n\t// identicalContents()\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'e', c(1.1, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.15, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3, 4.4)); y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3, 4.4)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary(x); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"Dictionary(5);\", 0, \"be a singleton Dictionary\");\n\tEidosAssertScriptRaise(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3, 4.4)); Dictionary(c(y,y));\", 100, \"be a singleton\");\n\tEidosAssertScriptRaise(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3, 4.4)); Dictionary(y, y);\", 100, \"keys be of type string or integer\");\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 13, c(1.1, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.15, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3, 4.4)); y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3, 4.4)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(x); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 0:2); x.setValue(7, c('foo', 'bar', 'baz')); x.setValue(9, c(T, F, T)); x.setValue(11, c(1.1, 2.2, 3.3)); y = Dictionary(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"Dictionary(5);\", 0, \"be a singleton Dictionary\");\n\tEidosAssertScriptRaise(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3, 4.4)); Dictionary(c(y,y));\", 93, \"be a singleton\");\n\tEidosAssertScriptRaise(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3, 4.4)); Dictionary(y, y);\", 93, \"keys be of type string or integer\");\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue(5, 2); y = Dictionary(); y.setValue('a', 'foo'); x.identicalContents(y);\", false);\n\tEidosAssertScriptRaise(\"x = Dictionary(5, 1:10, 'a', 1:10);\", 4, \"string key\");\n\tEidosAssertScriptRaise(\"x = Dictionary('a', 1:10, 5, 1:10);\", 4, \"integer key\");\n\t\n\t// appendKeysAndValuesFrom()\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'b', 9:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary('a', 0:4, 'b', 2:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'c', 9:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary('a', 0:4, 'b', 2:8, 'c', 9:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'b', 9.0:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary('a', 0:4, 'b', 2:10));\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'b', 9.0:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary('a', 0:4, 'b', 2.0:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'b', 9:10); x.appendKeysAndValuesFrom(c(y, y)); x.identicalContents(Dictionary('a', c(0:4, 4), 'b', c(2:10, 9:10)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'c', 9:10); x.appendKeysAndValuesFrom(c(y, y)); x.identicalContents(Dictionary('a', c(0:4, 4), 'b', 2:8, 'c', c(9:10, 9:10)));\", true);\n\tEidosAssertScriptRaise(\"x = Dictionary('a', 0:3, 'b', 2:8); y = Dictionary('a', 4, 'c', 9:10); x.appendKeysAndValuesFrom(x);\", 73, \"cannot append a Dictionary to itself\");\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 7, 9:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary(5, 0:4, 7, 2:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 9, 9:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary(5, 0:4, 7, 2:8, 9, 9:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 7, 9.0:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary(5, 0:4, 7, 2:10));\", false);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 7, 9.0:10); x.appendKeysAndValuesFrom(y); x.identicalContents(Dictionary(5, 0:4, 7, 2.0:10));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 7, 9:10); x.appendKeysAndValuesFrom(c(y, y)); x.identicalContents(Dictionary(5, c(0:4, 4), 7, c(2:10, 9:10)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 9, 9:10); x.appendKeysAndValuesFrom(c(y, y)); x.identicalContents(Dictionary(5, c(0:4, 4), 7, 2:8, 9, c(9:10, 9:10)));\", true);\n\tEidosAssertScriptRaise(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary(5, 4, 9, 9:10); x.appendKeysAndValuesFrom(x);\", 65, \"cannot append a Dictionary to itself\");\n\t\n\tEidosAssertScriptRaise(\"x = Dictionary(5, 0:3, 7, 2:8); y = Dictionary('a', 4, 'b', 9:10); x.appendKeysAndValuesFrom(y);\", 69, \"string key\");\n\t\n\t// getRowValues()\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(0); y.identicalContents(Dictionary('a', 0, 'b', 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(1); y.identicalContents(Dictionary('a', 1, 'b', 3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(4); y.identicalContents(Dictionary('a', integer(0), 'b', 6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(4, drop=T); y.identicalContents(Dictionary('b', 6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(c(T, F, T, T)); y.identicalContents(Dictionary('a', c(0, 2, 3), 'b', c(2, 4, 5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(F); y.identicalContents(Dictionary('a', integer(0), 'b', integer(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(c(F, F)); y.identicalContents(Dictionary('a', integer(0), 'b', integer(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(F, drop=T); y.identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 0:3, 'b', 2:8); y = x.getRowValues(c(F, F), drop=T); y.identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(0).identicalContents(Dictionary('a', 0, 'b', 'foo', 'c', T, 'd', 1.1));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(1).identicalContents(Dictionary('a', 1, 'b', 'bar', 'c', F, 'd', 2.2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(2).identicalContents(Dictionary('a', 2, 'b', 'baz', 'c', T, 'd', 3.3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(3).identicalContents(Dictionary('a', integer(0), 'b', string(0), 'c', logical(0), 'd', float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(3, drop=T).identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(-1).identicalContents(Dictionary('a', integer(0), 'b', string(0), 'c', logical(0), 'd', float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(-1, drop=T).identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(0:1).identicalContents(Dictionary('a', 0:1, 'b', c('foo', 'bar'), 'c', c(T, F), 'd', c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(1:0).identicalContents(Dictionary('a', 1:0, 'b', c('bar', 'foo'), 'c', c(F, T), 'd', c(2.2, 1.1)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F, F)).identicalContents(Dictionary('a', integer(0), 'b', string(0), 'c', logical(0), 'd', float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(T, F, F)).identicalContents(Dictionary('a', 0, 'b', 'foo', 'c', T, 'd', 1.1));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(F, T, F)).identicalContents(Dictionary('a', 1, 'b', 'bar', 'c', F, 'd', 2.2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F, T)).identicalContents(Dictionary('a', 2, 'b', 'baz', 'c', T, 'd', 3.3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T, F)).identicalContents(Dictionary('a', 0:1, 'b', c('foo', 'bar'), 'c', c(T, F), 'd', c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T, F, T)).identicalContents(Dictionary('a', 0:1, 'b', c('foo', 'bar'), 'c', c(T, F), 'd', c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T)).identicalContents(Dictionary('a', 0:1, 'b', c('foo', 'bar'), 'c', c(T, F), 'd', c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F)).identicalContents(Dictionary('a', integer(0), 'b', string(0), 'c', logical(0), 'd', float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F), drop=T).identicalContents(Dictionary());\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(0); y.identicalContents(Dictionary(5, 0, 7, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(1); y.identicalContents(Dictionary(5, 1, 7, 3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(4); y.identicalContents(Dictionary(5, integer(0), 7, 6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(4, drop=T); y.identicalContents(Dictionary(7, 6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(c(T, F, T, T)); y.identicalContents(Dictionary(5, c(0, 2, 3), 7, c(2, 4, 5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(F); y.identicalContents(Dictionary(5, integer(0), 7, integer(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(c(F, F)); y.identicalContents(Dictionary(5, integer(0), 7, integer(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(F, drop=T); y.identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(5, 0:3, 7, 2:8); y = x.getRowValues(c(F, F), drop=T); y.identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(0).identicalContents(Dictionary(5, 0, 7, 'foo', 9, T, 11, 1.1));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(1).identicalContents(Dictionary(5, 1, 7, 'bar', 9, F, 11, 2.2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(2).identicalContents(Dictionary(5, 2, 7, 'baz', 9, T, 11, 3.3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(3).identicalContents(Dictionary(5, integer(0), 7, string(0), 9, logical(0), 11, float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(3, drop=T).identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(-1).identicalContents(Dictionary(5, integer(0), 7, string(0), 9, logical(0), 11, float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(-1, drop=T).identicalContents(Dictionary());\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(0:1).identicalContents(Dictionary(5, 0:1, 7, c('foo', 'bar'), 9, c(T, F), 11, c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(1:0).identicalContents(Dictionary(5, 1:0, 7, c('bar', 'foo'), 9, c(F, T), 11, c(2.2, 1.1)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F, F)).identicalContents(Dictionary(5, integer(0), 7, string(0), 9, logical(0), 11, float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(T, F, F)).identicalContents(Dictionary(5, 0, 7, 'foo', 9, T, 11, 1.1));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(F, T, F)).identicalContents(Dictionary(5, 1, 7, 'bar', 9, F, 11, 2.2));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F, T)).identicalContents(Dictionary(5, 2, 7, 'baz', 9, T, 11, 3.3));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T, F)).identicalContents(Dictionary(5, 0:1, 7, c('foo', 'bar'), 9, c(T, F), 11, c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T, F, T)).identicalContents(Dictionary(5, 0:1, 7, c('foo', 'bar'), 9, c(T, F), 11, c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(T, T)).identicalContents(Dictionary(5, 0:1, 7, c('foo', 'bar'), 9, c(T, F), 11, c(1.1, 2.2)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F)).identicalContents(Dictionary(5, integer(0), 7, string(0), 9, logical(0), 11, float(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"y = Dictionary(5, 0:2, 7, c('foo', 'bar', 'baz'), 9, c(T, F, T), 11, c(1.1, 2.2, 3.3)); y.getRowValues(c(F, F), drop=T).identicalContents(Dictionary());\", true);\n\t\n\t// clearKeysAndValues()\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue('bar', 2); x.setValue('baz', 'foo'); x.clearKeysAndValues(); x.allKeys;\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('bar', 2); x.setValue('baz', 'foo'); x.clearKeysAndValues(); x.setValue('foo', 'baz'); x.allKeys;\", \"foo\");\n\t\n\tEidosAssertScriptSuccess(\"x = Dictionary(); x.setValue(5, 2); x.setValue(7, 'foo'); x.clearKeysAndValues(); x.allKeys;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = Dictionary(); x.setValue(5, 2); x.setValue(7, 'foo'); x.clearKeysAndValues(); x.setValue(9, 'baz'); x.allKeys;\", 9);\n\t\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 2); x.setValue(7, 'foo'); x.clearKeysAndValues(); x.setValue('foo', 'baz'); x.allKeys;\", 84, \"string key\");\n\t\n\t// compactIndices()\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.compactIndices(); x.identicalContents(Dictionary());\", true);\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('foo', 5:7); x.compactIndices();\", 44, \"integer keys\");\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(53,'c', 17,'b', 80,'d', 5,'a', 85,'e'); x.compactIndices(preserveOrder=F); values=sapply(x.allKeys, 'x.getValue(applyValue);'); identical(x.allKeys, 0:4) & identical(sort(values), c('a','b','c','d','e'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(53,'c', 17,'b', 80,'d', 5,'a', 85,'e'); x.compactIndices(preserveOrder=T); x.identicalContents(Dictionary(0,'a', 1,'b', 2,'c', 3,'d', 4,'e'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(53,'c', 7,integer(0), 17,'b', 80,'d', 83,string(0), 5,'a', 35,object(), 85,'e'); x.compactIndices(preserveOrder=F); values=sapply(x.allKeys, 'x.getValue(applyValue);'); identical(x.allKeys, 0:4) & identical(sort(values), c('a','b','c','d','e'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(53,'c', 7,integer(0), 17,'b', 80,'d', 83,string(0), 5,'a', 35,object(), 85,'e'); x.compactIndices(preserveOrder=T); x.identicalContents(Dictionary(0,'a', 1,'b', 2,'c', 3,'d', 4,'e'));\", true);\n\t\n\t// serialize()\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize();\", \"\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize();\", \"\\\"foo\\\"=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize();\", R\"V0G0N(\"bar\"=\"baz\";\"foo\"=1 2 3;)V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); y.setValue('a', 1.5); y.setValue('b', T); x.setValue('xyzzy', y); x.serialize();\", R\"V0G0N(\"foo\"=1 2 3;\"xyzzy\"={\"a\"=1.5;\"b\"=T;};)V0G0N\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize();\", \"\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize();\", \"5=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.setValue(3, 'baz'); x.serialize();\", \"3=\\\"baz\\\";5=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); y = Dictionary(); y.setValue(20, 1.5); y.setValue(30, T); x.setValue(11, y); x.serialize();\", \"5=1 2 3;11={20=1.5;30=T;};\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('slim');\", \"\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize('slim');\", \"\\\"foo\\\"=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize('slim');\", R\"V0G0N(\"bar\"=\"baz\";\"foo\"=1 2 3;)V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); y.setValue('a', 1.5); y.setValue('b', T); x.setValue('xyzzy', y); x.serialize('slim');\", R\"V0G0N(\"foo\"=1 2 3;\"xyzzy\"={\"a\"=1.5;\"b\"=T;};)V0G0N\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('slim');\", \"\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize('slim');\", \"5=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.setValue(3, 'baz'); x.serialize('slim');\", \"3=\\\"baz\\\";5=1 2 3;\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); y = Dictionary(); y.setValue(20, 1.5); y.setValue(30, T); x.setValue(11, y); x.serialize('slim');\", \"5=1 2 3;11={20=1.5;30=T;};\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('pretty');\", \"{}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize('pretty');\", R\"V0G0N({\n\t\"foo\" = 1 2 3\n})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize('pretty');\", R\"V0G0N({\n\t\"bar\" = \"baz\"\n\t\"foo\" = 1 2 3\n})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); y.setValue('a', 1.5); y.setValue('b', T); x.setValue('xyzzy', y); x.serialize('pretty');\", R\"V0G0N({\n\t\"foo\" = 1 2 3\n\t\"xyzzy\" = {\n\t\t\"a\" = 1.5\n\t\t\"b\" = T\n\t}\n})V0G0N\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('pretty');\", \"{}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize('pretty');\", R\"V0G0N({\n\t5 = 1 2 3\n})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); x.setValue(3, 'baz'); x.serialize('pretty');\", R\"V0G0N({\n\t3 = \"baz\"\n\t5 = 1 2 3\n})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue(5, 1:3); y = Dictionary(); y.setValue(20, 1.5); y.setValue(30, T); x.setValue(11, y); x.serialize('pretty');\", R\"V0G0N({\n\t5 = 1 2 3\n\t11 = {\n\t\t20 = 1.5\n\t\t30 = T\n\t}\n})V0G0N\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('json');\", \"{}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize('json');\", \"{\\\"foo\\\":[1,2,3]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize('json');\", R\"V0G0N({\"bar\":[\"baz\"],\"foo\":[1,2,3]})V0G0N\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); y.setValue('a', 1.5); y.setValue('b', T); x.setValue('xyzzy', y); x.serialize('json');\", R\"V0G0N({\"foo\":[1,2,3],\"xyzzy\":[{\"a\":[1.5],\"b\":[true]}]})V0G0N\");\n\t\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize('json');\", 40, \"integer keys\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('csv');\", \"\");\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize('csv');\", {\"\\\"foo\\\"\", \"1\", \"2\", \"3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize('csv');\", {R\"V0G0N(\"bar\",\"foo\")V0G0N\", \"\\\"baz\\\",1\", \",2\", \",3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', 'baz'); x.serialize('csv');\", {R\"V0G0N(\"bar\",\"foo\")V0G0N\", \"1,\\\"baz\\\"\", \"2,\", \"3,\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', c(T,F)); x.serialize('csv');\", {R\"V0G0N(\"bar\",\"foo\")V0G0N\", \"1,TRUE\", \"2,FALSE\", \"3,\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', c(1.0, 2.1, 3.2)); x.serialize('csv');\", {R\"V0G0N(\"bar\",\"foo\")V0G0N\", \"1,1.0\", \"2,2.1\", \"3,3.2\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', c(INF, -INF, NAN)); x.serialize('csv');\", {\"\\\"foo\\\"\", \"INF\", \"-INF\", \"NAN\"});\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); x.setValue('xyzzy', y); x.serialize('csv');\", 86, \"object to CSV/TSV\");\n\t\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize('csv');\", {\"5\", \"1\", \"2\", \"3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, 1:3); x.setValue(3, 'baz'); x.serialize('csv');\", {\"3,5\", \"\\\"baz\\\",1\", \",2\", \",3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, 'baz'); x.serialize('csv');\", {\"3,5\", \"1,\\\"baz\\\"\", \"2,\", \"3,\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, c(T,F)); x.serialize('csv');\", {\"3,5\", \"1,TRUE\", \"2,FALSE\", \"3,\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, c(1.0, 2.1, 3.2)); x.serialize('csv');\", {\"3,5\", \"1,1.0\", \"2,2.1\", \"3,3.2\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, c(INF, -INF, NAN)); x.serialize('csv');\", {\"5\", \"INF\", \"-INF\", \"NAN\"});\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 1:3); y = Dictionary(); x.setValue(11, y); x.serialize('csv');\", 77, \"object to CSV/TSV\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('tsv');\", \"\");\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', 1:3); x.serialize('tsv');\", {\"\\\"foo\\\"\", \"1\", \"2\", \"3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', 1:3); x.setValue('bar', 'baz'); x.serialize('tsv');\", {\"\\\"bar\\\"\\t\\\"foo\\\"\", \"\\\"baz\\\"\\t1\", \"\\t2\", \"\\t3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', 'baz'); x.serialize('tsv');\", {\"\\\"bar\\\"\\t\\\"foo\\\"\", \"1\\t\\\"baz\\\"\", \"2\\t\", \"3\\t\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', c(T,F)); x.serialize('tsv');\", {\"\\\"bar\\\"\\t\\\"foo\\\"\", \"1\\tTRUE\", \"2\\tFALSE\", \"3\\t\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('bar', 1:3); x.setValue('foo', c(1.0, 2.1, 3.2)); x.serialize('tsv');\", {\"\\\"bar\\\"\\t\\\"foo\\\"\", \"1\\t1.0\", \"2\\t2.1\", \"3\\t3.2\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue('foo', c(INF, -INF, NAN)); x.serialize('tsv');\", {\"\\\"foo\\\"\", \"INF\", \"-INF\", \"NAN\"});\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('foo', 1:3); y = Dictionary(); x.setValue('xyzzy', y); x.serialize('tsv');\", 86, \"object to CSV/TSV\");\n\t\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, 1:3); x.serialize('tsv');\", {\"5\", \"1\", \"2\", \"3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, 1:3); x.setValue(3, 'baz'); x.serialize('tsv');\", {\"3\\t5\", \"\\\"baz\\\"\\t1\", \"\\t2\", \"\\t3\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, 'baz'); x.serialize('tsv');\", {\"3\\t5\", \"1\\t\\\"baz\\\"\", \"2\\t\", \"3\\t\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, c(T,F)); x.serialize('tsv');\", {\"3\\t5\", \"1\\tTRUE\", \"2\\tFALSE\", \"3\\t\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(3, 1:3); x.setValue(5, c(1.0, 2.1, 3.2)); x.serialize('tsv');\", {\"3\\t5\", \"1\\t1.0\", \"2\\t2.1\", \"3\\t3.2\"});\n\tEidosAssertScriptSuccess_SV(\"x = Dictionary(); x.setValue(5, c(INF, -INF, NAN)); x.serialize('tsv');\", {\"5\", \"INF\", \"-INF\", \"NAN\"});\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue(5, 1:3); y = Dictionary(); x.setValue(11, y); x.serialize('tsv');\", 77, \"object to CSV/TSV\");\n\t\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.serialize('foo');\", 20, \"does not recognize the format\");\n\t\n\t// serialize(format='json') exact tests\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.serialize('json');\", \"{}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', logical(0)); x.serialize('json');\", \"{\\\"b\\\":[]}\");\t// indistinguishable\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', T); x.serialize('json');\", \"{\\\"b\\\":[true]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', F); x.serialize('json');\", \"{\\\"b\\\":[false]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', c(T,F,T,F)); x.serialize('json');\", \"{\\\"b\\\":[true,false,true,false]}\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', integer(0)); x.serialize('json');\", \"{\\\"b\\\":[]}\");\t// indistinguishable\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', -5); x.serialize('json');\", \"{\\\"b\\\":[-5]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', 5); x.serialize('json');\", \"{\\\"b\\\":[5]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', c(-5,5,10,-172)); x.serialize('json');\", \"{\\\"b\\\":[-5,5,10,-172]}\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', float(0)); x.serialize('json');\", \"{\\\"b\\\":[]}\");\t// indistinguishable\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', -5.0); x.serialize('json');\", \"{\\\"b\\\":[-5.0]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', 5.7); x.serialize('json');\", \"{\\\"b\\\":[5.7]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', c(-5.0,5.7,10,-172)); x.serialize('json');\", \"{\\\"b\\\":[-5.0,5.7,10.0,-172.0]}\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', string(0)); x.serialize('json');\", \"{\\\"b\\\":[]}\");\t// indistinguishable\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', \\\"foo\\\"); x.serialize('json');\", R\"V0G0N({\"b\":[\"foo\"]})V0G0N\");\n\tEidosAssertScriptSuccess_S(R\"V0G0N(x = Dictionary(); x.setValue('b', \"foo'\\\"bar\"); x.serialize('json');)V0G0N\", R\"V0G0N({\"b\":[\"foo'\\\"bar\"]})V0G0N\");\n\tEidosAssertScriptSuccess_S(R\"V0G0N(x = Dictionary(); x.setValue('b', c('foo','bar',\"foo'\\\"bar\")); x.serialize('json');)V0G0N\", R\"V0G0N({\"b\":[\"foo\",\"bar\",\"foo'\\\"bar\"]})V0G0N\");\n\t\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', Dictionary()); x.serialize('json');\", \"{\\\"b\\\":[{}]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', c(Dictionary(),Dictionary())); x.serialize('json');\", \"{\\\"b\\\":[{},{}]}\");\n\tEidosAssertScriptSuccess_S(\"x = Dictionary(); x.setValue('b', c(Dictionary('x',1:3),Dictionary(),Dictionary('y','foo','z',1.73))); x.serialize('json');\", R\"V0G0N({\"b\":[{\"x\":[1,2,3]},{},{\"y\":[\"foo\"],\"z\":[1.73]}]})V0G0N\");\n\t\n\t// Dictionary(x=\"JSON_string\")\n\tEidosAssertScriptRaise(\"Dictionary('invalid');\", 0, \"valid JSON string\");\n\tEidosAssertScriptRaise(\"Dictionary('{invalid}');\", 0, \"valid JSON string\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": null}'); a.serialize('json');\", \"{\\\"a\\\":[{}]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": {}}'); a.serialize('json');\", \"{\\\"a\\\":[{}]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": true}'); a.serialize('json');\", \"{\\\"a\\\":[true]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": [true]}'); a.serialize('json');\", \"{\\\"a\\\":[true]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": false}'); a.serialize('json');\", \"{\\\"a\\\":[false]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": [false]}'); a.serialize('json');\", \"{\\\"a\\\":[false]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": 5}'); a.serialize('json');\", \"{\\\"a\\\":[5]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": [5]}'); a.serialize('json');\", \"{\\\"a\\\":[5]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": 5.5}'); a.serialize('json');\", \"{\\\"a\\\":[5.5]}\");\n\tEidosAssertScriptSuccess_S(\"a = Dictionary('{\\\"a\\\": [5.5]}'); a.serialize('json');\", \"{\\\"a\\\":[5.5]}\");\n\tEidosAssertScriptSuccess_S(R\"V0G0N(a = Dictionary('{\"a\": \"b\"}'); a.serialize('json');)V0G0N\", R\"V0G0N({\"a\":[\"b\"]})V0G0N\");\n\tEidosAssertScriptSuccess_S(R\"V0G0N(a = Dictionary('{\"a\": [\"b\"]}'); a.serialize('json');)V0G0N\", R\"V0G0N({\"a\":[\"b\"]})V0G0N\");\n\tEidosAssertScriptSuccess_L(\"a = Dictionary(); a.setValue('logical_empty', logical(0)); a.setValue('logical_T', T); a.setValue('logical_F', F); a.setValue('logical_vector', c(T, F, T, F)); a.setValue('int_empty', integer(0)); a.setValue('int_singleton', 1); a.setValue('int_vector', 1:3); a.setValue('float_empty', float(0)); a.setValue('float_singleton', 1.0); a.setValue('float_vector', 1.0:3); a.setValue('string_empty', string(0)); a.setValue('string_singleton', 'foo'); a.setValue('string_vector', c('foo', 'bar', 'baz')); sa_json = a.serialize('json'); b = Dictionary(sa_json); sb_json = b.serialize('json'); identical(sa_json,sb_json);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 5:7, 'b', 'foo'); x.setValue('c', Dictionary('d', 18)); y = x.serialize('json'); z = Dictionary(y); z = z.serialize('json'); identical(y, z);\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 1:3, 'b', 2:4); z = Dictionary('{\\\"a\\\":[1,2,3],\\\"b\\\":[2,3,4]}'); x.identicalContents(z);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 1:3, 'b', c('foo', 'bar')); z = Dictionary('{\\\"a\\\":[1,2,3],\\\"b\\\":[\\\"foo\\\",\\\"bar\\\"]}'); x.identicalContents(z);\", true);\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 1:3, 'b', c('foo', 'bar')); z = Dictionary('{\\\\n   \\\"a\\\":[1,2,3],\\\\n   \\\"b\\\":[\\\"foo\\\",\\\"bar\\\"]\\\\n}'); x.identicalContents(z);\", true);\t\t\t\t// multiline string singleton\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 1:3, 'b', c('foo', 'bar')); z = Dictionary(c('{', '   \\\"a\\\":[1,2,3],', '   \\\"b\\\":[\\\"foo\\\",\\\"bar\\\"]', '}')); x.identicalContents(z);\", true);\t\t// string vector, as from readFile()\n\tEidosAssertScriptRaise(\"Dictionary(c('{', '   \\\"a\\\":[1,2,3],', '   \\\"b\\\":[\\\"fo', 'o\\\",\\\"bar\\\"]', '}'));\", 0, \"valid JSON string\");\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// line break inside a JSON string value -- illegal\n\t\n\t// DataFrame(...)\n\t// identicalContents()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'e', c(1.1, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.15, 2.2, 3.3)); x.identicalContents(y);\", false);\n\tEidosAssertScriptRaise(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3, 4.4));\", 111, \"inconsistent column sizes\");\n\tEidosAssertScriptRaise(\"y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3, 4.4));\", 4, \"inconsistent column sizes\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame(x); x.identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"DataFrame(5);\", 0, \"be a singleton Dictionary\");\n\tEidosAssertScriptRaise(\"y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); DataFrame(c(y,y));\", 94, \"be a singleton\");\n\tEidosAssertScriptRaise(\"y = DataFrame('a', 0:2, 'b', c('foo', 'bar', 'baz'), 'c', c(T, F, T), 'd', c(1.1, 2.2, 3.3)); DataFrame(y, y);\", 94, \"keys be of type string or integer\");\n\tEidosAssertScriptRaise(\"x = DataFrame(5, 1:10, 'a', 1:10);\", 4, \"always uses string keys\");\n\tEidosAssertScriptRaise(\"x = DataFrame('a', 1:10, 5, 1:10);\", 4, \"always uses string keys\");\n\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 1:10); y = DataFrame(x); z = DataFrame('a', 1:10); y.identicalContents(z);\", true);\n\tEidosAssertScriptRaise(\"x = Dictionary(5, 1:10); y = DataFrame(x);\", 29, \"always uses string keys\");\n\t\n\tEidosAssertScriptSuccess_L(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = DataFrame(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3)); y = Dictionary(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = Dictionary(); x.setValue('a', 0:2); x.setValue('b', c('foo', 'bar', 'baz')); x.setValue('c', c(T, F, T)); x.setValue('d', c(1.1, 2.2, 3.3, 4.4)); y = DataFrame(x); y.identicalContents(x);\", 154, \"inconsistent column sizes\");\n\t\n\t// DataFrame test column length check after Dictionary operations\n\tEidosAssertScriptRaise(\"x = DataFrame(); x.setValue('bar', 2); x.setValue('foo', 2:3);\", 41, \"inconsistent column sizes\");\n\tEidosAssertScriptRaise(\"x = DataFrame('a', 2:4, 'b', 3:5); y = Dictionary('c', 4:7); x.appendKeysAndValuesFrom(y);\", 63, \"inconsistent column sizes\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 2:4, 'b', 2:4); y = Dictionary('a', 5, 'b', 5, 'c', 4:7); x.appendKeysAndValuesFrom(y); x.identicalContents(DataFrame('a', 2:5, 'b', 2:5, 'c', 4:7));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 2:4, 'b', 2:4); y = Dictionary('b', 5, 'a', 5, 'c', 4:7); x.appendKeysAndValuesFrom(y); x.identicalContents(DataFrame('a', 2:5, 'b', 2:5, 'c', 4:7));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 2:4, 'a', 2:4); y = Dictionary('a', 5, 'b', 5, 'c', 4:7); x.appendKeysAndValuesFrom(y); x.identicalContents(DataFrame('b', 2:5, 'a', 2:5, 'c', 4:7));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 2:4, 'b', 2:4); y = Dictionary('a', 5, 'b', 5, 'c', 4:7); x.appendKeysAndValuesFrom(y); x.identicalContents(DataFrame('b', 2:5, 'a', 2:5, 'c', 4:7));\", false);\n\t\n\t// DataFrame properties: colnames, dim, ncol, nrow\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); identical(x.colNames, string(0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); identical(x.dim, c(0, 0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); identical(x.ncol, 0);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame(); identical(x.nrow, 0);\", true);\n\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', integer(0), 'b', logical(0)); identical(x.colNames, c('a', 'b'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', integer(0), 'b', logical(0)); identical(x.colNames, c('b', 'a'));\", false);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', integer(0), 'a', logical(0)); identical(x.colNames, c('b', 'a'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', integer(0), 'b', logical(0)); identical(x.dim, c(0, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', integer(0), 'b', logical(0)); identical(x.ncol, 2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', integer(0), 'b', logical(0)); identical(x.nrow, 0);\", true);\n\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); identical(x.colNames, c('a', 'b'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); identical(x.colNames, c('b', 'a'));\", false);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); identical(x.colNames, c('b', 'a'));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); identical(x.dim, c(3, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); identical(x.ncol, 2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); identical(x.nrow, 3);\", true);\n\t\n\t// DataFrame asMatrix()\n\tEidosAssertScriptRaise(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); x.asMatrix();\", 42, \"is the same type (logical != integer)\");\n\tEidosAssertScriptRaise(\"x = DataFrame('a', DataFrame(), 'b', Dictionary()); x.asMatrix();\", 54, \"is the same class (Dictionary != DataFrame)\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:5, 'b', 11:15); m1 = x.asMatrix(); m2 = matrix(c(1:5, 11:15), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:5, 'a', 11:15); m1 = x.asMatrix(); m2 = matrix(c(1:5, 11:15), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 11:15, 'a', 1:5); m1 = x.asMatrix(); m2 = matrix(c(11:15, 1:5), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 11:15, 'b', 1:5); m1 = x.asMatrix(); m2 = matrix(c(11:15, 1:5), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 11.0:15, 'a', 1.0:5); m1 = x.asMatrix(); m2 = matrix(c(11.0:15, 1.0:5), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', c('foo','bar'), 'a', c('baz','barbaz')); m1 = x.asMatrix(); m2 = matrix(c('foo','bar','baz','barbaz'), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', c(T,T,F), 'a', c(F,T,F)); m1 = x.asMatrix(); m2 = matrix(c(T,T,F,F,T,F), ncol=2, byrow=F); identical(m1, m2);\", true);\n\tEidosAssertScriptSuccess_L(\"d1 = Dictionary('foo', 1:8); d2 = Dictionary('baz', 11:18); x = DataFrame('b', d1, 'a', d2); m1 = x.asMatrix(); m2 = matrix(c(d1, d2), ncol=2, byrow=F); identical(m1, m2);\", true);\n\t\n\t// DataFrame cbind()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame(); y.cbind(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('c', 2.0:4); y.cbind(x); DataFrame('c', 2.0:4, 'b', 1:3, 'a', c(T,F,T)).identicalContents(y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('c', 2.0:4); x.cbind(y); DataFrame('b', 1:3, 'a', c(T,F,T), 'c', 2.0:4).identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('c', 2.0:5); x.cbind(y);\", 69, \"inconsistent column sizes\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.cbind(x);\", 42, \"already exists\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('a', 2.0:4); x.cbind(y);\", 69, \"already exists\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3); y = DataFrame('c', 2.0:4); z = DataFrame('a', c(T,F,T)); x.cbind(y, z); DataFrame('b', 1:3, 'c', 2.0:4, 'a', c(T,F,T)).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3); y = DataFrame('c', 2.0:4); z = DataFrame('a', c(T,F,T)); x.cbind(c(y, z)); DataFrame('b', 1:3, 'c', 2.0:4, 'a', c(T,F,T)).identicalContents(x);\", true);\n\t\n\t// DataFrame rbind()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame(); y.rbind(x); y.identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('b', 4:5, 'a', c(T,F)); x.rbind(y); DataFrame('b', 1:5, 'a', c(T,F,T,T,F)).identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = Dictionary('b', 4:5, 'a', c(T,F)); x.rbind(y);\", 81, \"do not match the columns\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('a', 4:5, 'b', c(T,F)); x.rbind(y);\", 80, \"do not match the columns\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); y = Dictionary('a', 4:5, 'b', c(T,F)); x.rbind(y); DataFrame('a', 1:5, 'b', c(T,F,T,T,F)).identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); y = Dictionary('a', 4:5, 'b', F); x.rbind(y);\", 76, \"inconsistent column sizes\");\n\tEidosAssertScriptRaise(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); x.rbind(x);\", 42, \"to itself\");\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); y = DataFrame(x); x.rbind(y); DataFrame('a', c(1:3,1:3), 'b', c(T,F,T,T,F,T)).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3, 'b', c(T,F,T)); y = DataFrame(x); x.rbind(c(y, y), y); DataFrame('a', c(1:3,1:3,1:3,1:3), 'b', c(T,F,T,T,F,T,T,F,T,T,F,T)).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('b', 4.0:5, 'a', c(T,F)); x.rbind(y); DataFrame('b', 1.0:5, 'a', c(T,F,T,T,F)).identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); y = DataFrame('b', Dictionary(), 'a', T); x.rbind(y);\", 84, \"cannot be mixed\");\n\t\n\t// DataFrame subset()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset().identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(rows=0).identicalContents(DataFrame('b', 1, 'a', T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(rows=1).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(rows=2).identicalContents(DataFrame('b', 3, 'a', T));\", true);\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(cols=0);\", {1, 2, 3});\n\tEidosAssertScriptSuccess_LV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(cols=1);\", {true, false, true});\n\t\n\tEidosAssertScriptSuccess_I(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(0, 0);\", 1);\n\tEidosAssertScriptSuccess_I(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 0);\", 2);\n\tEidosAssertScriptSuccess_I(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(0, 'b');\", 1);\n\tEidosAssertScriptSuccess_I(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 'b');\", 2);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 1);\", false);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(2, 1);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 'a');\", false);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(2, 'a');\", true);\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1:2, 0);\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(2:1, 0);\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(c(F, T, T), 0);\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(c(T, T, T), 0);\", {1, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(c(F, F, F), 0);\", {});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(integer(0), 0);\", {});\n\tEidosAssertScriptSuccess_IV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1:2, c(T, F));\", {2, 3});\n\tEidosAssertScriptSuccess_LV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1:2, c(F, T));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(2:1, c(F, T));\", {true, false});\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(2:1, integer(0)).identicalContents(DataFrame());\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 0:1).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, 1:0).identicalContents(DataFrame('a', F, 'b', 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, c(T, T)).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, c('b', 'a')).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(1, c('a', 'b')).identicalContents(DataFrame('a', F, 'b', 2));\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(4, 0);\", 42, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(0, 4);\", 42, \"out of range\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(T, 0);\", 42, \"logical index operand must match\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(0, T);\", 42, \"logical index vector length does not match\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subset(0, 'c');\", 42, \"key c is not defined\");\n\t\n\t// DataFrame subsetColumns()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(integer(0)).identicalContents(DataFrame());\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c(F,F)).identicalContents(DataFrame());\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(string(0)).identicalContents(DataFrame());\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(0).identicalContents(DataFrame('b', 1:3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(1).identicalContents(DataFrame('a', c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c(T,F)).identicalContents(DataFrame('b', 1:3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c(F,T)).identicalContents(DataFrame('a', c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns('b').identicalContents(DataFrame('b', 1:3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns('a').identicalContents(DataFrame('a', c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(0:1).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c(T,T)).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c('b','a')).identicalContents(x);\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(1:0).identicalContents(DataFrame('a', c(T,F,T), 'b', 1:3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(c('a','b')).identicalContents(DataFrame('a', c(T,F,T), 'b', 1:3));\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(4);\", 42, \"out of range\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns(T);\", 42, \"logical index vector length does not match\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetColumns('c');\", 42, \"key c is not defined\");\n\t\n\t// DataFrame subsetRows()\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(integer(0)).identicalContents(DataFrame('b', integer(0), 'a', logical(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(c(F,F,F)).identicalContents(DataFrame('b', integer(0), 'a', logical(0)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(0).identicalContents(DataFrame('b', 1, 'a', T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(1).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(2).identicalContents(DataFrame('b', 3, 'a', T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(c(T,F,F)).identicalContents(DataFrame('b', 1, 'a', T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(c(F,T,F)).identicalContents(DataFrame('b', 2, 'a', F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(c(F,F,T)).identicalContents(DataFrame('b', 3, 'a', T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(0:1).identicalContents(DataFrame('b', 1:2, 'a', c(T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(c(T,T,F)).identicalContents(DataFrame('b', 1:2, 'a', c(T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(1:0).identicalContents(DataFrame('b', 2:1, 'a', c(F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(0:2).identicalContents(x);\", true);\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(4);\", 42, \"out-of-range\");\n\tEidosAssertScriptRaise(\"x = DataFrame('b', 1:3, 'a', c(T,F,T)); x.subsetRows(T);\", 42, \"logical index operand must match\");\n\t\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\t// DataFrame serialize and readCSV() round-trip; tests that specify column types explicitly work without <regex>, the rest don't run if it is broken\n\t\tEidosAssertScriptRaise(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='li');\", 112, \"could not be represented\");\n\t\t\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='i'); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='f'); DataFrame('a', 3.0:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='s'); DataFrame('a', asString(3:5)).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 3:5, 'b', 3:4); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='i_'); Dictionary('a', 3:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 3:5, 'b', 3:4); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='i-'); Dictionary('a', 3:5).identicalContents(y);\", true);\n\t\t\n\t\tEidosAssertScriptRaise(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='li', sep='\\t');\", 112, \"could not be represented\");\n\t\t\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='i', sep='\\t'); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='f', sep='\\t'); DataFrame('a', 3.0:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='s', sep='\\t'); DataFrame('a', asString(3:5)).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 3:5, 'b', 3:4); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='i_', sep='\\t'); Dictionary('a', 3:5).identicalContents(y);\", true);\n\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', 3:5, 'b', 3:4); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='i-', sep='\\t'); Dictionary('a', 3:5).identicalContents(y);\", true);\n\n\t\tif (!Eidos_RegexWorks())\n\t\t{\n\t\t\t// already warned about this in _RunStringManipulationTests()\n\t\t\t//std::cout << \"WARNING: This build of Eidos does not have a working <regex> library, due to a bug in the underlying C++ standard library provided by the system.  This may cause problems with the Eidos functions grep() and readCSV(); if you do not use those functions, it should not affect you.  If a case where a problem does occur is encountered, an error will result.  This problem might be resolved by updating your compiler or toolchain, or by upgrading to a more recent version of your operating system.\" << std::endl;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1.0:3); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar', 'baz')); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c(T, T, F)); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c(T, T, F), 'b', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', c(T, T, F), 'a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); x.identicalContents(y);\", false);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); Dictionary('a', c(T, T, F), 'b', c('3','4','')).identicalContents(y);\", true);\n\t\t\t\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar')); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colNames=F); DataFrame('X1', c('a', 'foo', 'bar')).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar')); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colNames='b'); DataFrame('b', c('a', 'foo', 'bar')).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, colTypes='?'); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\t\t\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1:3); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 1.0:3); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar', 'baz')); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c(T, T, F)); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c(T, T, F), 'b', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('b', c(T, T, F), 'a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); x.identicalContents(y);\", false);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c(T, T, F), 'b', 3:4); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); Dictionary('a', c(T, T, F), 'b', c('3','4','')).identicalContents(y);\", true);\n\t\t\t\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar')); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colNames=F, sep='\\t'); DataFrame('X1', c('a', 'foo', 'bar')).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', c('foo', 'bar')); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colNames='b', sep='\\t'); DataFrame('b', c('a', 'foo', 'bar')).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, sep='\\t'); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = DataFrame('a', 3:5); file = writeTempFile('eidos_test_', '.tsv', x.serialize('tsv')); y = readCSV(file, colTypes='?', sep='\\t'); DataFrame('a', 3:5).identicalContents(y);\", true);\n\t\t\t\n\t\t\tEidosAssertScriptSuccess_L(R\"V0G0N(x = Dictionary('a', 3:6, 'b', c(121,131,141,141141)); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, quote='1'); Dictionary('\"a\"', 3:6, '\"b\"', c(2:4, 414)).identicalContents(y);)V0G0N\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('b', c('10$25', '10$0', '10$')); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, dec='$'); Dictionary('b', c(10.25, 10, 10)).identicalContents(y);\", true);\n\t\t\tEidosAssertScriptSuccess_L(\"x = Dictionary('a', c('foo', 'bar'), 'b', c(10.5, 10.25)); file = writeTempFile('eidos_test_', '.csv', x.serialize('csv')); y = readCSV(file, dec='$', comment='.'); Dictionary('a', c('foo', 'bar'), 'b', c(10, 10)).identicalContents(y);\", true);\n\t\t\t\n\t\t\t// test sep=\"\" whitespace separator)\n\t\t\tEidosAssertScriptSuccess_L(\"file = writeTempFile('eidos_test_', '.csv', c('  a   b   c   d   e', '   1   2   3   4   5   ', ' 10  20  30  40  50', '100 200 300 400 500')); y = readCSV(file, sep=''); Dictionary('a', c(1,10,100), 'b', c(2,20,200), 'c', c(3,30,300), 'd', c(4,40,400), 'e', c(5,50,500)).identicalContents(y);\", true);\n\t\t}\n\t}\n\t\n\t// Test EidosDictionary's interaction with retain-released and non-retain-released objects using EidosTestElement and EidosTestElementNRR\n\t// Note that these tests will leak instances of EidosTestElementNRR; since it is not under retain-release there is no way to know when to release it!\n\t// They will also cause warning to be emitted to the console, so they are disabled by default; but they worked last time I checked\n#if 0\n\tEidosAssertScriptSuccess_L(\"_Test(5000); T;\", true);\n\tEidosAssertScriptSuccess_L(\"_TestNRR(5001); T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(5002); T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5003); T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(5004); x = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5005); x = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(5006); y = Dictionary('a', x); T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5007); y = Dictionary('a', x); T;\", true);\t\t\t\t\t\t\t\t\t\t\t// logs - y references x\n\tEidosAssertScriptSuccess_L(\"x = _Test(5008); y = Dictionary('a', x); y = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5009); y = Dictionary('a', x); y = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(5010); y = Dictionary('a', x); z = Dictionary(y); y = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5011); y = Dictionary('a', x); z = Dictionary(y); y = 5; T;\", true);\t\t\t\t// logs - z references x (copied from y)\n\tEidosAssertScriptSuccess_L(\"x = _Test(5011); y = Dictionary('a', x); z = Dictionary(y); y = 5; z = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5012); y = Dictionary('a', x); z = Dictionary(y); y = 5; z = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(5013); y = Dictionary('a', x); z = Dictionary('b', y); y = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5014); y = Dictionary('a', x); z = Dictionary('b', y); y = 5; T;\", true);\t\t\t// logs - z retains y, which references x\n\tEidosAssertScriptSuccess_L(\"x = _Test(5015); y = Dictionary('a', x); z = Dictionary('b', y); y = 5; z = 5; T;\", true);\n\tEidosAssertScriptSuccess_L(\"x = _TestNRR(5016); y = Dictionary('a', x); z = Dictionary('b', y); y = 5; z = 5; T;\", true);\n#endif\n\t\n\t// Test EidosImage properties and methods – but how?  If it were possible to construct an Image from a matrix, that would provide an avenue for testing...\n\t// That is what we do here now, but we can only test grayscale images since we can only generate grayscale images, at present... FIXME\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.bitsPerChannel == 8;\", true);\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.height == 3;\", true);\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.width == 5;\", true);\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.isGrayscale == T;\", true);\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); identical(i.integerK, m);\", true);\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.integerR;\", 50, \"from a grayscale\");\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.integerG;\", 50, \"from a grayscale\");\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.integerB;\", 50, \"from a grayscale\");\n\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); identical(i.floatK, m/255);\", true);\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.floatR;\", 50, \"from a grayscale\");\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.floatG;\", 50, \"from a grayscale\");\n\tEidosAssertScriptRaise(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); i.floatB;\", 50, \"from a grayscale\");\n\t\n\tif (Eidos_TemporaryDirectoryExists())\n\t{\n\t\tEidosAssertScriptSuccess_L(\"m = matrix(0:14, nrow=3, ncol=5); i = Image(m); path = '\" + temp_path + \"/image_write.png'; i.write(path); i2 = Image(path); identical(m, i2.integerK);\", true);\n\t}\n}\n\n#pragma mark code examples\nvoid _RunCodeExampleTests(void)\n{\n\t// Fibonacci sequence; see Eidos manual section 2.6.1-ish\n\tEidosAssertScriptSuccess(\t\"fib = c(1, 1);\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\twhile (size(fib) < 20)\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\tnext_fib = fib[size(fib) - 1] + fib[size(fib) - 2];\t\t\\\n\t\t\t\t\t\t\t\t\tfib = c(fib, next_fib);\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\tfib;\",\n\t\t\t\t\t\t\t EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765}));\n\t\n\tEidosAssertScriptSuccess(\t\"counter = 12;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\tfactorial = 1;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\tdo\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t{\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\tfactorial = factorial * counter;\t\\\n\t\t\t\t\t\t\t\t\tcounter = counter - 1;\t\t\t\t\\\n\t\t\t\t\t\t\t\t}\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\twhile (counter > 0);\t\t\t\t\t\\\n\t\t\t\t\t\t\t\tfactorial;\",\n\t\t\t\t\t\t\t EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(479001600)));\n\t\n\tEidosAssertScriptSuccess(\t\"last = 200;\t\t\t\t\\\n\t\t\t\t\t\t\t\tp = integer(0);\t\t\t\t\\\n\t\t\t\t\t\t\t\tx = 2:last;\t\t\t\t\t\\\n\t\t\t\t\t\t\t\tlim = last^0.5;\t\t\t\t\\\n\t\t\t\t\t\t\t\tdo {\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\tv = x[0];\t\t\t\t\\\n\t\t\t\t\t\t\t\t\tif (v > lim)\t\t\t\\\n\t\t\t\t\t\t\t\t\t\tbreak;\t\t\t\t\\\n\t\t\t\t\t\t\t\t\tp = c(p, v);\t\t\t\\\n\t\t\t\t\t\t\t\t\tx = x[x % v != 0];\t\t\\\n\t\t\t\t\t\t\t\t} while (T);\t\t\t\t\\\n\t\t\t\t\t\t\t\tc(p, x);\",\n\t\t\t\t\t\t\t EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199}));\n}\n\n#pragma mark user-defined functions\nvoid _RunUserDefinedFunctionTests(void)\n{\n\t// Basic functionality\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i x) { return x + 1; } plus(5);\", 6);\n\tEidosAssertScriptSuccess_F(\"function (f)plus(f x) { return x + 1; } plus(5.0);\", 6.0);\n\tEidosAssertScriptSuccess_I(\"function (fi)plus(fi x) { return x + 1; } plus(5);\", 6);\n\tEidosAssertScriptSuccess_F(\"function (fi)plus(fi x) { return x + 1; } plus(5.0);\", 6.0);\n\tEidosAssertScriptSuccess_IV(\"function (fi)plus(fi x) { return x + 1; } plus(c(5, 6, 7));\", {6, 7, 8});\n\tEidosAssertScriptSuccess_FV(\"function (fi)plus(fi x) { return x + 1; } plus(c(5.0, 6.0, 7.0));\", {6.0, 7.0, 8.0});\n\t\n\tEidosAssertScriptSuccess_L(\"function (l$)nor(l$ x, l$ y) { return !(x | y); } nor(F, F);\", true);\n\tEidosAssertScriptSuccess_L(\"function (l$)nor(l$ x, l$ y) { return !(x | y); } nor(T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"function (l$)nor(l$ x, l$ y) { return !(x | y); } nor(F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"function (l$)nor(l$ x, l$ y) { return !(x | y); } nor(T, T);\", false);\n\t\n\tEidosAssertScriptSuccess_S(\"function (s)append(s x, s y) { return x + ',' + y; } append('foo', 'bar');\", \"foo,bar\");\n\tEidosAssertScriptSuccess_SV(\"function (s)append(s x, s y) { return x + ',' + y; } append('foo', c('bar','baz'));\", {\"foo,bar\", \"foo,baz\"});\n\t\n\t// Default arguments\n\tEidosAssertScriptSuccess_IV(\"function (fi)plus([fi x = 2]) { return x + 1; } plus(c(5, 6, 7));\", {6, 7, 8});\n\tEidosAssertScriptSuccess_I(\"function (fi)plus([fi x = 2]) { return x + 1; } plus();\", 3);\n\tEidosAssertScriptSuccess_IV(\"function (fi)plus([fi x = -2]) { return x + 1; } plus(c(5, 6, 7));\", {6, 7, 8});\n\tEidosAssertScriptSuccess_I(\"function (fi)plus([fi x = -2]) { return x + 1; } plus();\", -1);\n\t\n\tEidosAssertScriptSuccess_FV(\"function (fi)plus([fi x = 2.0]) { return x + 1; } plus(c(5.0, 6.0, 7.0));\", {6.0, 7.0, 8.0});\n\tEidosAssertScriptSuccess_F(\"function (fi)plus([fi x = 2.0]) { return x + 1; } plus();\", 3.0);\n\tEidosAssertScriptSuccess_FV(\"function (fi)plus([fi x = -2.0]) { return x + 1; } plus(c(5.0, 6.0, 7.0));\", {6.0, 7.0, 8.0});\n\tEidosAssertScriptSuccess_F(\"function (fi)plus([fi x = -2.0]) { return x + 1; } plus();\", -1.0);\n\t\n\tEidosAssertScriptSuccess_SV(\"function (s)append(s x, [s y = 'foo']) { return x + ',' + y; } append('foo', c('bar','baz'));\", {\"foo,bar\", \"foo,baz\"});\n\tEidosAssertScriptSuccess_SV(\"function (s)append(s x, [s y = 'foo']) { return x + ',' + y; } append('bar');\", {\"bar,foo\"});\n\t\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = T]) { return x | y; } or(c(T, F, T, F), T);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = T]) { return x | y; } or(c(T, F, T, F), F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = T]) { return x | y; } or(c(T, F, T, F));\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = F]) { return x | y; } or(c(T, F, T, F), T);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = F]) { return x | y; } or(c(T, F, T, F), F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"function (l)or(l x, [l y = F]) { return x | y; } or(c(T, F, T, F));\", {true, false, true, false});\n\t\n\tEidosAssertScriptRaise(\"function (fi)plus([fi x = FOO]) { return x + 1; } plus();\", 26, \"default value must be\");\n\tEidosAssertScriptRaise(\"function (fi)plus([fi x = 9223372036854775808]) { return x + 1; } plus();\", 26, \"could not be represented\");\n\tEidosAssertScriptRaise(\"function (fi)plus([fi x = -FOO]) { return x + 1; } plus();\", 27, \"unexpected token\");\n\t\n\t// Recursion\n\tEidosAssertScriptSuccess_I(\"function (i)fac([i b=10]) { if (b <= 1) return 1; else return b*fac(b-1); } fac(3); \", 6);\n\tEidosAssertScriptSuccess_I(\"function (i)fac([i b=10]) { if (b <= 1) return 1; else return b*fac(b-1); } fac(5); \", 120);\n\tEidosAssertScriptSuccess_I(\"function (i)fac([i b=10]) { if (b <= 1) return 1; else return b*fac(b-1); } fac(); \", 3628800);\n\t\n\tEidosAssertScriptSuccess_S(\"function (s)star(i x) { if (x <= 0) return ''; else return '*' + star(x - 1); } star(5); \", \"*****\");\n\tEidosAssertScriptSuccess_S(\"function (s)star(i x) { if (x <= 0) return ''; else return '*' + star(x - 1); } star(10); \", \"**********\");\n\tEidosAssertScriptSuccess_S(\"function (s)star(i x) { if (x <= 0) return ''; else return '*' + star(x - 1); } star(0); \", \"\");\n\t\n\tEidosAssertScriptSuccess_I(\"function (i)fib(i x) { if (x <= 1) return x; else return fib(x - 1) + fib(x - 2); } fib(10);\", 55);\n\t\n\t// Type-checking\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(NULL);\", 35, \"argument 1 (x) cannot be type NULL\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(T);\", 35, \"argument 1 (x) cannot be type logical\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(5);\", 35, \"return value cannot be type integer\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(5.0);\", 35, \"argument 1 (x) cannot be type float\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo('foo');\", 35, \"argument 1 (x) cannot be type string\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(_Test(7));\", 35, \"argument 1 (x) cannot be type object\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo();\", 35, \"missing required argument 'x'\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(5, 6);\", 35, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(x=5);\", 35, \"return value cannot be type integer\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(y=5);\", 35, \"named argument 'y' skipped over required argument 'x'\");\n\tEidosAssertScriptRaise(\"function (s)foo(i x) { return x; } foo(x=5, y=5);\", 35, \"unrecognized named argument 'y'\");\n\t\n\t// Mutual recursion\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return foo(x - 1); } foo(5); \", 16);\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return foo(x - 1); } foo(10); \", 56);\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return foo(x - 1); } foo(-10); \", -9);\n\t\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return baz(x - 1); } function (i)baz(i x) { return x * foo(x); } foo(5); \", 153);\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return baz(x - 1); } function (i)baz(i x) { return x * foo(x); } foo(10); \", 2335699);\n\tEidosAssertScriptSuccess_I(\"function (i)foo(i x) { return x + bar(x); } function (i)bar(i x) { if (x <= 1) return 1; else return baz(x - 1); } function (i)baz(i x) { return x * foo(x); } foo(-10); \", -9);\n\t\n\t// Scoping, defineConstant(), and defineGlobal()\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); function (i)plus(i x) { return x + 1; } plus(5);\", 65, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); function (i)plus(i y) { x = y + 1; return x; } plus(5);\", 72, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptSuccess_I(\"defineConstant('x', 10); function (i)plus(i y) { return x + y; } plus(5);\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 10; function (i)plus(i y) { return x + y; } plus(5);\", 15);\n\tEidosAssertScriptSuccess_I(\"defineConstant('x', 10); y = 1; function (i)plus(i y) { return x + y; } plus(5);\", 15);\n\tEidosAssertScriptSuccess_I(\"defineConstant('x', 10); y = 1; function (i)plus(i y) { return x + y; } plus(5); y; \", 1);\n\tEidosAssertScriptSuccess_I(\"defineConstant('x', 10); y = 1; function (i)plus(i y) { y = y + 1; return x + y; } plus(5); \", 16);\n\tEidosAssertScriptSuccess_I(\"defineConstant('x', 10); y = 1; function (i)plus(i y) { y = y + 1; return x + y; } plus(5); y; \", 1);\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i y) { defineConstant('x', 10); y = y + 1; return y; } plus(5); \", 6);\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i y) { defineConstant('x', 10); y = y + 1; return y; } plus(5); x; \", 10);\n\tEidosAssertScriptRaise(\"function (i)plus(i y) { defineConstant('x', 10); y = y + 1; return y; } plus(5); y; \", 81, \"undefined identifier y\");\n\tEidosAssertScriptRaise(\"function (i)plus(i y) { defineConstant('x', 10); y = y + 1; return y; } plus(5); plus(5); \", 81, \"identifier 'x' is already defined\");\n\tEidosAssertScriptRaise(\"x = 3; function (i)plus(i y) { defineConstant('x', 10); y = y + 1; return y; } plus(5); x; \", 79, \"identifier 'x' is already defined\");\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i y) { foo(); y = y + 1; return y; } function (void)foo(void) { defineConstant('x', 10); } plus(5); x; \", 10);\n\tEidosAssertScriptRaise(\"function (i)plus(i x) { foo(); x = x + 1; return x; } function (void)foo(void) { defineConstant('x', 10); } plus(5); x; \", 108, \"identifier 'x' is already defined\");\n\tEidosAssertScriptRaise(\"x = 3; function (i)plus(i y) { foo(); y = y + 1; return y; } function (void)foo(void) { defineConstant('x', 10); } plus(5); x; \", 115, \"identifier 'x' is already defined\");\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i y) { foo(y); y = y + 1; return y; } function (void)foo(i y) { y = 12; } plus(5); \", 6);\n\tEidosAssertScriptRaise(\"function (i)plus(i y) { foo(y); y = y + 1; return y; } function (void)foo(i y) { y = 12; } plus(5); y; \", 100, \"undefined identifier y\");\n\tEidosAssertScriptSuccess_I(\"function (i)plus(i y) { foo(y); y = y + 1; return y; } function (void)foo(i x) { y = 12; } plus(5); \", 6);\n\tEidosAssertScriptRaise(\"function (i)plus(i y) { foo(y); y = y + 1; return y; } function (void)foo(i x) { y = 12; } plus(5); y; \", 100, \"undefined identifier y\");\n\t\n\tEidosAssertScriptSuccess_I(\"x = 15; x;\", 15);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('x', 15); x;\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 5; defineGlobal('x', 15); x;\", 15);\n\tEidosAssertScriptSuccess_I(\"defineGlobal('x', 15); x = 5; x;\", 5);\n\tEidosAssertScriptSuccess_I(\"x = 5; defineGlobal('x', 15); defineGlobal('x', 25); x;\", 25);\n\tEidosAssertScriptSuccess_I(\"x = 5; defineGlobal('x', 15); x = 3; defineGlobal('x', 25); x;\", 25);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { return x; } foo();\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { x = 5; return x; } foo();\", 5);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { x = 5; return x; } foo(); x;\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { defineGlobal('x', 5); return 25; } foo();\", 25);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { defineGlobal('x', 5); return x; } foo();\", 5);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { defineGlobal('x', 5); return 25; } foo(); x;\", 5);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { y = x; defineGlobal('x', 5); return y; } foo();\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { y = x; defineGlobal('y', 25); return y; } foo();\", 15);\n\tEidosAssertScriptSuccess_I(\"x = 15; function (i)foo(void) { y = x; defineGlobal('y', 25); return y; } foo(); y;\", 25);\n\tEidosAssertScriptRaise(\"x = 15; function (i)foo(void) { y = x; return y; } foo(); y;\", 58, \"undefined identifier y\");\n\t\n\tEidosAssertScriptRaise(\"x = 5; defineConstant('x', 10);\", 7, \"already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); x = 5;\", 27, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); defineConstant('x', 5);\", 25, \"already defined\");\n\tEidosAssertScriptRaise(\"x = 5; function(void)foo(void) { defineConstant('x', 10); } foo();\", 60, \"already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); function(void)foo(void) { x = 5; } foo();\", 60, \"is a constant\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); function(void)foo(void) { defineConstant('x', 5); } foo();\", 77, \"already defined\");\n\tEidosAssertScriptRaise(\"function(void)foo(void) { defineConstant('x', 10); } foo(); x = 5;\", 62, \"is a constant\");\n\tEidosAssertScriptRaise(\"function(void)foo(void) { x = 5; } foo(); defineConstant('x', 10); foo();\", 67, \"is a constant\");\n\tEidosAssertScriptRaise(\"function(void)foo(void) { defineConstant('x', 5); } foo(); defineConstant('x', 10);\", 59, \"already defined\");\n\t\n\tEidosAssertScriptRaise(\"defineGlobal('x', 5); defineConstant('x', 10);\", 22, \"already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); defineGlobal('x', 5);\", 25, \"is already defined as a constant\");\n\tEidosAssertScriptRaise(\"defineGlobal('x', 5); function(void)foo(void) { defineConstant('x', 10); } foo();\", 75, \"already defined\");\n\tEidosAssertScriptRaise(\"defineConstant('x', 10); function(void)foo(void) { defineGlobal('x', 5); } foo();\", 75, \"is already defined as a constant\");\n\tEidosAssertScriptRaise(\"function(void)foo(void) { defineConstant('x', 10); } foo(); defineGlobal('x', 5);\", 60, \"is already defined as a constant\");\n\tEidosAssertScriptRaise(\"function(void)foo(void) { defineGlobal('x', 5); } foo(); defineConstant('x', 10); foo();\", 57, \"already defined\");\n\t\n\t// Mutual recursion with lambdas\n\t\n\t\n\t// Tests mimicking built-in Eidos functions; these are good for testing user-defined functions, but also good for testing our built-ins!\n\tconst std::string &builtins_test_string =\n#include \"eidos_test_builtins.h\"\n\t;\n\t{\n\t\tstd::vector<std::string> test_strings = Eidos_string_split(builtins_test_string, \"// ***********************************************************************************************\");\n\t\t\n\t\t//for (int testidx = 0; testidx < 100; testidx++)\t// uncomment this for a more thorough stress test\n\t\t{\n\t\t\tfor (std::string &test_string : test_strings)\n\t\t\t{\n\t\t\t\tstd::string test_string_fixed = test_string + \"\\nreturn T;\\n\";\n\t\t\t\t\n\t\t\t\tEidosAssertScriptSuccess_L(test_string_fixed, true);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Tests of parallelization of Eidos functions; this is here just because the above test is here\n#ifdef _OPENMP\n\tconst std::string &parallelization_test_string =\n#include \"eidos_test_parallel.h\"\n\t;\n\t{\n\t\tstd::vector<std::string> test_strings = Eidos_string_split(parallelization_test_string, \"// ***********************************************************************************************\");\n\t\t\n\t\t//for (int testidx = 0; testidx < 100; testidx++)\t// uncomment this for a more thorough stress test\n\t\t{\n\t\t\tfor (std::string &test_string : test_strings)\n\t\t\t{\n\t\t\t\tstd::string test_string_fixed = test_string + \"\\nreturn T;\\n\";\n\t\t\t\t\n\t\t\t\t// Note that we ensure that we are using the maximum number of threads at start & end\n\t\t\t\tgEidosNumThreads = gEidosMaxThreads;\n\t\t\t\tgEidosNumThreadsOverride = false;\n\t\t\t\tomp_set_num_threads(gEidosMaxThreads);\n\t\t\t\t\n\t\t\t\tEidosAssertScriptSuccess_L(test_string_fixed, true);\n\t\t\t\t\n\t\t\t\tgEidosNumThreads = gEidosMaxThreads;\n\t\t\t\tgEidosNumThreadsOverride = false;\n\t\t\t\tomp_set_num_threads(gEidosMaxThreads);\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n#pragma mark void EidosValue\nvoid _RunVoidEidosValueTests(void)\n{\n\t// void$ or NULL$ as a type-specifier is not legal, semantically; likewise with similar locutions\n\tEidosAssertScriptRaise(\"function (void$)foo(void) { return; } foo();\", 14, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (void)foo(void$) { return; } foo();\", 23, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (NULL$)foo(void) { return NULL; } foo();\", 14, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (void)foo(NULL$) { return; } foo(NULL);\", 23, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (v$)foo(void) { return NULL; } foo();\", 11, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (void)foo(v$) { return; } foo(NULL);\", 20, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (N$)foo(void) { return NULL; } foo();\", 11, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (void)foo(N$) { return; } foo(NULL);\", 20, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (vN$)foo(void) { return NULL; } foo();\", 12, \"may not be declared to be singleton\");\n\tEidosAssertScriptRaise(\"function (void)foo(vN$) { return; } foo(NULL);\", 21, \"may not be declared to be singleton\");\n\t\n\t// functions declared to return void must return void\n\tEidosAssertScriptSuccess_VOID(\"function (void)foo(void) { 5; } foo();\");\n\tEidosAssertScriptSuccess_VOID(\"function (void)foo(void) { 5; return; } foo();\");\n\tEidosAssertScriptRaise(\"function (void)foo(void) { return 5; } foo();\", 39, \"return value must be void\");\n\tEidosAssertScriptRaise(\"function (void)foo(void) { return NULL; } foo();\", 42, \"return value must be void\");\n\t\n\t// functions declared to return NULL must return NULL\n\tEidosAssertScriptRaise(\"function (NULL)foo(void) { 5; } foo();\", 32, \"return value cannot be void\");\n\tEidosAssertScriptRaise(\"function (NULL)foo(void) { 5; return; } foo();\", 40, \"return value cannot be void\");\n\tEidosAssertScriptRaise(\"function (NULL)foo(void) { return 5; } foo();\", 39, \"return value cannot be type integer\");\n\tEidosAssertScriptSuccess_NULL(\"function (NULL)foo(void) { return NULL; } foo();\");\n\t\n\t// functions declared to return * may return anything but void\n\tEidosAssertScriptRaise(\"function (*)foo(void) { 5; } foo();\", 29, \"return value cannot be void\");\n\tEidosAssertScriptRaise(\"function (*)foo(void) { 5; return; } foo();\", 37, \"return value cannot be void\");\n\tEidosAssertScriptSuccess_I(\"function (*)foo(void) { return 5; } foo();\", 5);\n\tEidosAssertScriptSuccess_NULL(\"function (*)foo(void) { return NULL; } foo();\");\n\t\n\t// functions declared to return vNlifso may return anything at all\n\tEidosAssertScriptSuccess_VOID(\"function (vNlifso)foo(void) { 5; } foo();\");\n\tEidosAssertScriptSuccess_VOID(\"function (vNlifso)foo(void) { 5; return; } foo();\");\n\tEidosAssertScriptSuccess_I(\"function (vNlifso)foo(void) { return 5; } foo();\", 5);\n\tEidosAssertScriptSuccess_NULL(\"function (vNlifso)foo(void) { return NULL; } foo();\");\n\t\n\t// functions may not be declared as taking a parameter of type void\n\tEidosAssertScriptRaise(\"function (void)foo(void x) { return; } foo();\", 19, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(void x) { return; } foo(citation());\", 19, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo([void x]) { return; } foo(citation());\", 20, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(vNlifso x) { return; } foo();\", 19, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(vNlifso x) { return; } foo(citation());\", 19, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo([vNlifso x = 5]) { return; } foo(citation());\", 20, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, void y) { return; } foo(5);\", 30, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, void y) { return; } foo(5, citation());\", 30, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, [void y]) { return; } foo(5, citation());\", 31, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, vNlifso y) { return; } foo(5);\", 30, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, vNlifso y) { return; } foo(5, citation());\", 30, \"void is not allowed\");\n\tEidosAssertScriptRaise(\"function (void)foo(integer x, [vNlifso y = 5]) { return; } foo(5, citation());\", 31, \"void is not allowed\");\n\t\n\t// functions *may* be declared as taking a parameter of type NULL, or returning NULL; this is new, with the new void support\n\t// not sure why anybody would want to do this, of course, but hey, ours not to reason why...\n\tEidosAssertScriptSuccess_VOID(\"function (void)foo(NULL x) { return; } foo(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"function (void)bar([NULL x = NULL]) { return; } bar(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"function (void)bar([NULL x = NULL]) { return; } bar();\");\n\tEidosAssertScriptSuccess_NULL(\"function (NULL)foo(NULL x) { return x; } foo(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"function (NULL)bar([NULL x = NULL]) { return x; } bar(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"function (NULL)bar([NULL x = NULL]) { return x; } bar();\");\n\t\n\t// functions may not be passed void arguments\n\tEidosAssertScriptRaise(\"function (void)foo(void) { return; } foo(citation());\", 37, \"too many arguments\");\n\tEidosAssertScriptRaise(\"function (void)foo(* x) { return; } foo();\", 36, \"missing required argument\");\n\tEidosAssertScriptRaise(\"function (void)foo(* x) { return; } foo(citation());\", 36, \"cannot be type void\");\n\tEidosAssertScriptRaise(\"function (void)foo(* x) { return; } foo(x = citation());\", 36, \"cannot be type void\");\n\tEidosAssertScriptRaise(\"function (void)foo([* x = 5]) { return; } foo(x = citation());\", 42, \"cannot be type void\");\n\tEidosAssertScriptRaise(\"function (void)foo([* x = 5]) { return; } foo(citation());\", 42, \"cannot be type void\");\n\t\n\t// same again, with isNULL(* x)\n\tEidosAssertScriptRaise(\"isNULL();\", 0, \"missing required argument\");\n\tEidosAssertScriptRaise(\"isNULL(citation());\", 0, \"cannot be type void\");\n\t\n\t// same again, with c(...)\n\tEidosAssertScriptRaise(\"c(citation());\", 0, \"cannot be type void\");\n\tEidosAssertScriptRaise(\"c(5, citation(), 10);\", 0, \"cannot be type void\");\n\t\n\t// void may not participate in any operator: [], (), ., + (unary), - (unary), !, ^, :, *, /, %, +, -, <, >, <=, >=, ==, !=, &, |, ?else, =\n\t// we do not comprehensively test all operand types here, but I think the interpreter code is written such that these tests should suffice\n\tEidosAssertScriptRaise(\"citation()[0];\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation()[logical(0)];\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"(1:5)[citation()];\", 5, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation()();\", 8, \"illegal operand for a function call\");\n\tEidosAssertScriptRaise(\"(citation())();\", 9, \"illegal operand for a function call\");\n\tEidosAssertScriptSuccess_VOID(\"(citation());\");\t\t\t\t// about the only thing that is legal with void!\n\t\n\tEidosAssertScriptRaise(\"citation().test();\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation().test = 5;\", 16, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"+citation();\", 0, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"-citation();\", 0, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"!citation();\", 0, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation()^5;\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"5^citation();\", 1, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation()^citation();\", 10, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation():5;\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"5:citation();\", 1, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation():citation();\", 10, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation()*5;\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"5*citation();\", 1, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation()*citation();\", 10, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation()/5;\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"5/citation();\", 1, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation()/citation();\", 10, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"citation()%5;\", 10, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"5%citation();\", 1, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation()%citation();\", 10, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 + citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() + 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() + citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 - citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() - 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() - citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 < citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() < 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() < citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 > citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() > 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() > citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 <= citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() <= 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() <= citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 >= citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() >= 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() >= citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 == citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() == 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() == citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"5 != citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() != 5;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() != citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"T & citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() & T;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() & citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptRaise(\"T | citation();\", 2, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() | T;\", 11, \"type void is not supported\");\n\tEidosAssertScriptRaise(\"citation() | citation();\", 11, \"type void is not supported\");\n\t\n\tEidosAssertScriptSuccess_VOID(\"T ? citation() else F;\");\t\t// also legal with void, as long as you don't try to use the result...\n\tEidosAssertScriptSuccess_L(\"F ? citation() else F;\", false);\n\tEidosAssertScriptSuccess_L(\"T ? F else citation();\", false);\n\tEidosAssertScriptSuccess_VOID(\"F ? F else citation();\");\n\tEidosAssertScriptSuccess_VOID(\"T ? citation() else citation();\");\n\tEidosAssertScriptSuccess_VOID(\"F ? citation() else citation();\");\n\tEidosAssertScriptRaise(\"citation() ? T else F;\", 11, \"size() != 1\");\n\t\n\tEidosAssertScriptRaise(\"x = citation();\", 2, \"void may never be assigned\");\n\t\n\t// void may not be used in while, do-while, for, etc.\n\tEidosAssertScriptRaise(\"if (citation()) T;\", 0, \"size() != 1\");\n\tEidosAssertScriptRaise(\"if (citation()) T; else F;\", 0, \"size() != 1\");\n\tEidosAssertScriptSuccess_VOID(\"if (T) citation(); else citation();\");\n\tEidosAssertScriptSuccess_VOID(\"if (F) citation(); else citation();\");\n\t\n\tEidosAssertScriptRaise(\"while (citation()) F;\", 0, \"size() != 1\");\n\t\n\tEidosAssertScriptRaise(\"do F; while (citation());\", 0, \"size() != 1\");\n\t\n\tEidosAssertScriptRaise(\"for (x in citation()) T;\", 0, \"does not allow void\");\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_functions_statistics.cpp",
    "content": "//\n//  eidos_test_functions_statistics.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n#include <limits>\n#include <string>\n\n\n#pragma mark statistics\nvoid _RunFunctionStatisticsTests_a_through_p(void)\n{\n\t// cor()\n\tEidosAssertScriptRaise(\"cor(T, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cor(3, 3);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cor(3.5, 3.5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cor('foo', 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cor(c(F, F, T, F, T), c(F, F, T, F, T));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_L(\"abs(cor(1:5, 1:5) - 1) < 1e-10;\", true);\n\tEidosAssertScriptRaise(\"cor(1:5, 1:4);\", 0, \"the same size\");\n\tEidosAssertScriptSuccess_L(\"abs(cor(1:11, 1:11) - 1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1:5, 5:1) - -1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1:11, 11:1) - -1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1.0:5, 1:5) - 1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1:11, 1.0:11) - 1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1.0:5, 5.0:1) - -1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cor(1.0:11, 11.0:1) - -1) < 1e-10;\", true);\n\tEidosAssertScriptSuccess(\"cor(c(1.0, 2.0, NAN), c(8.0, 9.0, 10.0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cor(c(1.0, 2.0, 3.0), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cor(c(1.0, 2.0, NAN), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cor(c('foo', 'bar', 'baz'), c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cor(_Test(7), _Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cor(NULL, NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cor(logical(0), logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cor(integer(0), integer(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cor(float(0), float(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cor(string(0), string(0));\", 0, \"cannot be type\");\n\t\n\tstd::string matrices = \"a = c(1,2,3,4); b = c(1,2,4,5); c = c(1,3,4,5); d = c(5,3,2,1); m1 = cbind(a,b); m2 = cbind(c,d); m3 = cbind(a,b,c,d); \";\n\t\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(m1); all(abs(r - matrix(c(1, 0.9899495, 0.9899495, 1), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(m2); all(abs(r - matrix(c(1, -1, -1, 1), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(m1, m2); all(abs(r - matrix(c(0.9827076, 0.9621405, -0.9827076, -0.9621405), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptRaise(matrices + \"r = cor(m1, t(m2));\", 123, \"incompatible dimensions\");\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(m1, c); (nrow(r) == 2) & all(abs(r - matrix(c(0.9827076, 0.9621405), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(c, m1); (nrow(r) == 1) & all(abs(r - matrix(c(0.9827076, 0.9621405), ncol=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cor(m3); all(abs(r - matrix(c(1, 0.9899495, 0.9827076, -0.9827076, 0.9899495, 1, 0.9621405, -0.9621405, 0.9827076, 0.9621405, 1, -1, -0.9827076, -0.9621405, -1, 1), nrow=4)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(\"m4 = matrix(runif(36), nrow=6); r = cor(m4); identical(r, t(r));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cor(matrix(3), matrix(3)), matrix(NAN));\", true);\n\tEidosAssertScriptRaise(\"cor(matrix(3), matrix(c(3,5), ncol=1));\", 0, \"incompatible dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(cor(matrix(3), matrix(c(3,5), nrow=1)), matrix(c(NAN,NAN), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cor(matrix(c(3,5), nrow=1), matrix(3)), matrix(c(NAN,NAN), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"r = cor(matrix(c(3,5), ncol=1), matrix(c(3,5), ncol=1)); (nrow(r) == 1) & (ncol(r) == 1) & all(abs(r - matrix(1)) < 1e-14);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cor(matrix(c(3,5), nrow=1), matrix(c(3,5), nrow=1)), matrix(rep(NAN, 4), nrow=2));\", true);\n\t\n\t// cov()\n\tEidosAssertScriptRaise(\"cov(T, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cov(3, 3);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cov(3.5, 3.5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cov('foo', 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cov(c(F, F, T, F, T), c(F, F, T, F, T));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_L(\"abs(cov(1:5, 1:5) - 2.5) < 1e-10;\", true);\n\tEidosAssertScriptRaise(\"cov(1:5, 1:4);\", 0, \"the same size\");\n\tEidosAssertScriptSuccess_L(\"abs(cov(1:11, 1:11) - 11) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1:5, 5:1) - -2.5) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1:11, 11:1) - -11) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1.0:5, 1:5) - 2.5) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1:11, 1.0:11) - 11) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1.0:5, 5.0:1) - -2.5) < 1e-10;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(cov(1.0:11, 11.0:1) - -11) < 1e-10;\", true);\n\tEidosAssertScriptSuccess(\"cov(c(1.0, 2.0, NAN), c(8.0, 9.0, 10.0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cov(c(1.0, 2.0, 3.0), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cov(c(1.0, 2.0, NAN), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cov(c('foo', 'bar', 'baz'), c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cov(_Test(7), _Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cov(NULL, NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"cov(logical(0), logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"cov(integer(0), integer(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"cov(float(0), float(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"cov(string(0), string(0));\", 0, \"cannot be type\");\n\t\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(m1); all(abs(r - matrix(c(1.666667, 2.333333, 2.333333, 3.333333), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(m2); all(abs(r - matrix(c(2.916667, -2.916667, -2.916667, 2.916667), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(m1, m2); all(abs(r - matrix(c(2.166667, 3.000000, -2.166667, -3.000000), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptRaise(matrices + \"r = cov(m1, t(m2));\", 123, \"incompatible dimensions\");\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(m1, c); (nrow(r) == 2) & all(abs(r - matrix(c(2.166667, 3.000000), nrow=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(c, m1); (nrow(r) == 1) & all(abs(r - matrix(c(2.166667, 3.000000), ncol=2)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(matrices + \"r = cov(m3); all(abs(r - matrix(c(1.666667, 2.333333, 2.166667, -2.166667, 2.333333, 3.333333, 3.000000, -3.000000, 2.166667, 3.000000, 2.916667, -2.916667, -2.166667, -3.000000, -2.916667, 2.916667), nrow=4)) < 1e-5);\", true);\n\tEidosAssertScriptSuccess_L(\"m4 = matrix(runif(36), nrow=6); r = cov(m4); identical(r, t(r));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cov(matrix(3), matrix(3)), matrix(NAN));\", true);\n\tEidosAssertScriptRaise(\"cov(matrix(3), matrix(c(3,5), ncol=1));\", 0, \"incompatible dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(cov(matrix(3), matrix(c(3,5), nrow=1)), matrix(c(NAN,NAN), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cov(matrix(c(3,5), nrow=1), matrix(3)), matrix(c(NAN,NAN), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"r = cov(matrix(c(3,5), ncol=1), matrix(c(3,5), ncol=1)); (nrow(r) == 1) & (ncol(r) == 1) & all(abs(r - matrix(2.0)) < 1e-14);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(cov(matrix(c(3,5), nrow=1), matrix(c(3,5), nrow=1)), matrix(rep(NAN, 4), nrow=2));\", true);\n\t\n\t// filter()\n\tEidosAssertScriptRaise(\"filter(1.0:10, float(0));\", 0, \"within the interval [1,\");\n\tEidosAssertScriptRaise(\"filter(1.0:10, 1.0:2);\", 0, \"length that is odd\");\n\tEidosAssertScriptSuccess_L(\"x = runif(100); identical(x, filter(x, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = runif(100); identical(x * 2.0, filter(x, 2.0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = runif(100); identical(x * -2.5, filter(x, -2.5));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rep(NAN, 10); identical(x, filter(x, 1.0));\", true);\n\tEidosAssertScriptSuccess_FV(\"filter(1.0:10, rep(1/3, 3));\", {std::numeric_limits<double>::quiet_NaN(), 2, 3, 4, 5, 6, 7, 8, 9, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"filter(1.0:10, rep(1/5, 5));\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), 3, 4, 5, 6, 7, 8, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"filter(1.0:10, rep(1.0, 5));\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), 15, 20, 25, 30, 35, 40, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\tEidosAssertScriptSuccess_L(\"r = filter(1.0:10, rep(1/5, 5), outside=T); sum(abs(r - c(2, 2.5, 3, 4, 5, 6, 7, 8, 8.5, 9))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(1.0:10, rep(1/5, 5), outside=97); sum(abs(r - c(40, 21.4, 3, 4, 5, 6, 7, 8, 26.2, 44.2))) < 1e-12;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(1.0, 2, 9, 10), rep(1/5, 5), outside=T); sum(abs(r - c(4, 5.5, 5.5, 7.0))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(1.0, 2, 9, 10), rep(1/5, 5), outside=97); sum(abs(r - c(41.2, 23.8, 23.8, 43.0))) < 1e-12;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(9.0), rep(1/5, 5), outside=T); sum(abs(r - c(9.0))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(9.0), rep(1/5, 5), outside=97); sum(abs(r - c(79.4))) < 1e-12;\", true);\n\t\n\tEidosAssertScriptRaise(\"filter(1:10, float(0));\", 0, \"within the interval [1,\");\n\tEidosAssertScriptRaise(\"filter(1:10, 1.0:2);\", 0, \"length that is odd\");\n\tEidosAssertScriptSuccess_L(\"x = rdunif(100, -100, 100); identical(x * 1.0, filter(x, 1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rdunif(100, -100, 100); identical(x * 2.0, filter(x, 2.0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rdunif(100); identical(x * -2.5, filter(x, -2.5));\", true);\n\tEidosAssertScriptSuccess_FV(\"filter(1:10, rep(1/3, 3));\", {std::numeric_limits<double>::quiet_NaN(), 2, 3, 4, 5, 6, 7, 8, 9, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"filter(1:10, rep(1/5, 5));\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), 3, 4, 5, 6, 7, 8, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"filter(1:10, rep(1.0, 5));\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), 15, 20, 25, 30, 35, 40, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\tEidosAssertScriptSuccess_L(\"r = filter(1:10, rep(1/5, 5), outside=T); sum(abs(r - c(2, 2.5, 3, 4, 5, 6, 7, 8, 8.5, 9))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(1:10, rep(1/5, 5), outside=97); sum(abs(r - c(40, 21.4, 3, 4, 5, 6, 7, 8, 26.2, 44.2))) < 1e-12;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(1, 2, 9, 10), rep(1/5, 5), outside=T); sum(abs(r - c(4, 5.5, 5.5, 7.0))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(1, 2, 9, 10), rep(1/5, 5), outside=97); sum(abs(r - c(41.2, 23.8, 23.8, 43.0))) < 1e-12;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(9), rep(1/5, 5), outside=T); sum(abs(r - c(9.0))) < 1e-15;\", true);\n\tEidosAssertScriptSuccess_L(\"r = filter(c(9), rep(1/5, 5), outside=97); sum(abs(r - c(79.4))) < 1e-12;\", true);\n\t\n\t// max()\n\tEidosAssertScriptSuccess_L(\"max(T);\", true);\n\tEidosAssertScriptSuccess_I(\"max(3);\", 3);\n\tEidosAssertScriptSuccess_F(\"max(3.5);\", 3.5);\n\tEidosAssertScriptSuccess(\"max(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_S(\"max('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_L(\"max(c(F, F, F, F, F));\", false);\n\tEidosAssertScriptSuccess_L(\"max(c(F, F, T, F, T));\", true);\n\tEidosAssertScriptSuccess_I(\"max(c(3, 7, 19, -5, 9));\", 19);\n\tEidosAssertScriptSuccess_F(\"max(c(3.3, 7.7, 19.1, -5.8, 9.0));\", 19.1);\n\tEidosAssertScriptSuccess_S(\"max(c('bar', 'foo', 'baz'));\", \"foo\");\n\tEidosAssertScriptRaise(\"max(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_NULL(\"max(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"max(logical(0));\");\n\tEidosAssertScriptSuccess_NULL(\"max(integer(0));\");\n\tEidosAssertScriptSuccess_NULL(\"max(float(0));\");\n\tEidosAssertScriptSuccess_NULL(\"max(string(0));\");\n\tEidosAssertScriptSuccess(\"max(c(1.0, 5.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\tEidosAssertScriptSuccess_L(\"max(F, T);\", true);\n\tEidosAssertScriptSuccess_L(\"max(T, F);\", true);\n\tEidosAssertScriptSuccess_L(\"max(F, c(F,F), logical(0), c(F,F,F,F,F));\", false);\n\tEidosAssertScriptSuccess_L(\"max(F, c(F,F), logical(0), c(T,F,F,F,F));\", true);\n\tEidosAssertScriptSuccess_I(\"max(1, 2);\", 2);\n\tEidosAssertScriptSuccess_I(\"max(2, 1);\", 2);\n\tEidosAssertScriptSuccess_I(\"max(integer(0), c(3,7,-8,0), 0, c(-10,10));\", 10);\n\tEidosAssertScriptSuccess_F(\"max(1.0, 2.0);\", 2.0);\n\tEidosAssertScriptSuccess_F(\"max(2.0, 1.0);\", 2.0);\n\tEidosAssertScriptSuccess_F(\"max(c(3.,7.,-8.,0.), 0., c(-10.,0.), float(0));\", 7);\n\tEidosAssertScriptRaise(\"max(c(3,7,-8,0), c(-10.,10.));\", 0, \"the same type\");\n\tEidosAssertScriptSuccess_S(\"max('foo', 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"max('bar', 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"max('foo', string(0), c('baz','bar'), 'xyzzy', c('foobar', 'barbaz'));\", \"xyzzy\");\n\t\n\t// mean()\n\tEidosAssertScriptSuccess_F(\"mean(T);\", 1);\n\tEidosAssertScriptSuccess_F(\"mean(3);\", 3);\n\tEidosAssertScriptSuccess_F(\"mean(3.5);\", 3.5);\n\tEidosAssertScriptRaise(\"mean('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_F(\"mean(c(F, F, T, F, T));\", 0.4);\n\tEidosAssertScriptSuccess_F(\"mean(c(3, 7, 19, -5, 16));\", 8);\n\tEidosAssertScriptSuccess_F(\"mean(c(3.5, 7.25, 19.125, -5.5, 18.125));\", 8.5);\n\tEidosAssertScriptRaise(\"mean(c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"mean(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"mean(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_F(\"mean(logical(0));\", std::numeric_limits<double>::quiet_NaN());\t// BCH 1/11/2026: changed from NULL to NAN after SLiM 5.1\n\tEidosAssertScriptSuccess_F(\"mean(integer(0));\", std::numeric_limits<double>::quiet_NaN());\t// BCH 1/11/2026: changed from NULL to NAN after SLiM 5.1\n\tEidosAssertScriptSuccess_F(\"mean(float(0));\", std::numeric_limits<double>::quiet_NaN());\t// BCH 1/11/2026: changed from NULL to NAN after SLiM 5.1\n\tEidosAssertScriptRaise(\"mean(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_F(\"mean(rep(1e18, 9));\", 1e18);\t// stays in integer internally\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptSuccess_F(\"mean(rep(1e18, 10));\", 1e18);\t// overflows to float internally\n#endif\n\tEidosAssertScriptSuccess(\"mean(c(1.0, 5.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\t// min()\n\tEidosAssertScriptSuccess_L(\"min(T);\", true);\n\tEidosAssertScriptSuccess_I(\"min(3);\", 3);\n\tEidosAssertScriptSuccess_F(\"min(3.5);\", 3.5);\n\tEidosAssertScriptSuccess(\"min(NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_S(\"min('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_L(\"min(c(T, F, T, F, T));\", false);\n\tEidosAssertScriptSuccess_I(\"min(c(3, 7, 19, -5, 9));\", -5);\n\tEidosAssertScriptSuccess_F(\"min(c(3.3, 7.7, 19.1, -5.8, 9.0));\", -5.8);\n\tEidosAssertScriptSuccess_S(\"min(c('foo', 'bar', 'baz'));\", \"bar\");\n\tEidosAssertScriptRaise(\"min(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_NULL(\"min(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"min(logical(0));\");\n\tEidosAssertScriptSuccess_NULL(\"min(integer(0));\");\n\tEidosAssertScriptSuccess_NULL(\"min(float(0));\");\n\tEidosAssertScriptSuccess_NULL(\"min(string(0));\");\n\tEidosAssertScriptSuccess(\"min(c(1.0, 5.0, NAN, 2.0));\", gStaticEidosValue_FloatNAN);\n\t\n\tEidosAssertScriptSuccess_L(\"min(T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"min(F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"min(T, c(T,T), logical(0), c(T,T,T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"min(F, c(T,T), logical(0), c(T,T,T,T,T));\", false);\n\tEidosAssertScriptSuccess_I(\"min(1, 2);\", 1);\n\tEidosAssertScriptSuccess_I(\"min(2, 1);\", 1);\n\tEidosAssertScriptSuccess_I(\"min(integer(0), c(3,7,-8,0), 0, c(-10,10));\", -10);\n\tEidosAssertScriptSuccess_F(\"min(1.0, 2.0);\", 1.0);\n\tEidosAssertScriptSuccess_F(\"min(2.0, 1.0);\", 1.0);\n\tEidosAssertScriptSuccess_F(\"min(c(3.,7.,-8.,0.), 0., c(0.,10.), float(0));\", -8);\n\tEidosAssertScriptRaise(\"min(c(3,7,-8,0), c(-10.,10.));\", 0, \"the same type\");\n\tEidosAssertScriptSuccess_S(\"min('foo', 'bar');\", \"bar\");\n\tEidosAssertScriptSuccess_S(\"min('bar', 'foo');\", \"bar\");\n\tEidosAssertScriptSuccess_S(\"min('foo', string(0), c('baz','bar'), 'xyzzy', c('foobar', 'barbaz'));\", \"bar\");\n\t\n\t// pmax()\n\tEidosAssertScriptRaise(\"pmax(c(T,T), logical(0));\", 0, \"of equal length\");\n\tEidosAssertScriptRaise(\"pmax(logical(0), c(F,F));\", 0, \"of equal length\");\n\tEidosAssertScriptSuccess(\"pmax(T, logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"pmax(logical(0), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptRaise(\"pmax(T, 1);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"pmax(0, F);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess_NULL(\"pmax(NULL, NULL);\");\n\tEidosAssertScriptSuccess_L(\"pmax(T, T);\", true);\n\tEidosAssertScriptSuccess_L(\"pmax(F, T);\", true);\n\tEidosAssertScriptSuccess_L(\"pmax(T, F);\", true);\n\tEidosAssertScriptSuccess_L(\"pmax(F, F);\", false);\n\tEidosAssertScriptSuccess_LV(\"pmax(c(T,F,T,F), c(T,T,F,F));\", {true, true, true, false});\n\tEidosAssertScriptSuccess_I(\"pmax(1, 5);\", 5);\n\tEidosAssertScriptSuccess_I(\"pmax(-8, 6);\", 6);\n\tEidosAssertScriptSuccess_I(\"pmax(7, 1);\", 7);\n\tEidosAssertScriptSuccess_I(\"pmax(8, -8);\", 8);\n\tEidosAssertScriptSuccess_IV(\"pmax(c(1,-8,7,8), c(5,6,1,-8));\", {5, 6, 7, 8});\n\tEidosAssertScriptSuccess_F(\"pmax(1., 5.);\", 5);\n\tEidosAssertScriptSuccess_F(\"pmax(-INF, 6.);\", 6);\n\tEidosAssertScriptSuccess_F(\"pmax(7., 1.);\", 7);\n\tEidosAssertScriptSuccess(\"pmax(INF, -8.);\", gStaticEidosValue_FloatINF);\n\tEidosAssertScriptSuccess(\"pmax(NAN, -8.);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmax(-8., NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmax(NAN, INF);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmax(INF, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"pmax(c(1.,-INF,7.,INF,NAN,-8.,NAN), c(5.,6.,1.,-8.,-8.,NAN,INF));\", {5, 6, 7, std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_S(\"pmax('foo', 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"pmax('bar', 'baz');\", \"baz\");\n\tEidosAssertScriptSuccess_S(\"pmax('xyzzy', 'xyzzy');\", \"xyzzy\");\n\tEidosAssertScriptSuccess_S(\"pmax('', 'bar');\", \"bar\");\n\tEidosAssertScriptSuccess_SV(\"pmax(c('foo','bar','xyzzy',''), c('bar','baz','xyzzy','bar'));\", {\"foo\", \"baz\", \"xyzzy\", \"bar\"});\n\t\n\tEidosAssertScriptSuccess_LV(\"pmax(F, c(T,T,F,F));\", {true, true, false, false});\n\tEidosAssertScriptSuccess_LV(\"pmax(c(T,F,T,F), T);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_IV(\"pmax(4, c(5,6,1,-8));\", {5, 6, 4, 4});\n\tEidosAssertScriptSuccess_IV(\"pmax(c(1,-8,7,8), -2);\", {1, -2, 7, 8});\n\tEidosAssertScriptSuccess_FV(\"pmax(4., c(5.,6.,1.,-8.,-8.,INF));\", {5, 6, 4, 4, 4, std::numeric_limits<double>::infinity()});\n\tEidosAssertScriptSuccess_FV(\"pmax(c(1.,-INF,7.,INF, NAN, NAN), 5.);\", {5, 5, 7, std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_SV(\"pmax('baz', c('bar','baz','xyzzy','bar'));\", {\"baz\", \"baz\", \"xyzzy\", \"baz\"});\n\tEidosAssertScriptSuccess_SV(\"pmax(c('foo','bar','xyzzy',''), 'baz');\", {\"foo\", \"baz\", \"xyzzy\", \"baz\"});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(pmax(5, 3:7), c(5,5,5,6,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmax(3:7, 5), c(5,5,5,6,7));\", true);\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(5), 3:7), c(5,5,5,6,7));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(3:7, matrix(5)), c(5,5,5,6,7));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(array(5, c(1,1,1)), 3:7), c(5,5,5,6,7));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(3:7, array(5, c(1,1,1))), c(5,5,5,6,7));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptSuccess_L(\"identical(pmax(5, matrix(3:7)), matrix(c(5,5,5,6,7)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmax(matrix(3:7), 5), matrix(c(5,5,5,6,7)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmax(5, array(3:7, c(1,5,1))), array(c(5,5,5,6,7), c(1,5,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmax(array(3:7, c(1,5,1)), 5), array(c(5,5,5,6,7), c(1,5,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(pmax(1:5, matrix(3:7)), matrix(c(5,5,5,6,7)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(3:7), 1:5), matrix(c(5,5,5,6,7)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmax(1:5, array(3:7, c(1,5,1))), array(c(5,5,5,6,7), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmax(array(3:7, c(1,5,1)), 1:5), array(c(5,5,5,6,7), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(5), matrix(3:7)), matrix(c(5,5,5,6,7)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(3:7), matrix(5)), matrix(c(5,5,5,6,7)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(5), array(3:7, c(1,5,1))), array(c(5,5,5,6,7), c(1,5,1)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(array(3:7, c(1,5,1)), matrix(5)), array(c(5,5,5,6,7), c(1,5,1)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(5:1, nrow=1), matrix(1:5, ncol=1)), matrix(c(5,4,3,4,5)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(pmax(matrix(5:1, nrow=1), matrix(1:5, nrow=1)), matrix(c(5,4,3,4,5), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(pmax(matrix(1:5), array(3:7, c(1,5,1))), array(c(5,5,5,6,7), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(pmax(array(5:1, c(1,5,1)), array(1:5, c(1,5,1))), array(c(5,4,3,4,5), c(1,5,1)));\", true);\n\t\n\t// pmin()\n\tEidosAssertScriptRaise(\"pmin(c(T,T), logical(0));\", 0, \"of equal length\");\n\tEidosAssertScriptRaise(\"pmin(logical(0), c(F,F));\", 0, \"of equal length\");\n\tEidosAssertScriptSuccess(\"pmin(T, logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"pmin(logical(0), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptRaise(\"pmin(T, 1);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"pmin(0, F);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess_NULL(\"pmin(NULL, NULL);\");\n\tEidosAssertScriptSuccess_L(\"pmin(T, T);\", true);\n\tEidosAssertScriptSuccess_L(\"pmin(F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"pmin(T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"pmin(F, F);\", false);\n\tEidosAssertScriptSuccess_LV(\"pmin(c(T,F,T,F), c(T,T,F,F));\", {true, false, false, false});\n\tEidosAssertScriptSuccess(\"pmin(1, 5);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"pmin(-8, 6);\", -8);\n\tEidosAssertScriptSuccess(\"pmin(7, 1);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"pmin(8, -8);\", -8);\n\tEidosAssertScriptSuccess_IV(\"pmin(c(1,-8,7,8), c(5,6,1,-8));\", {1, -8, 1, -8});\n\tEidosAssertScriptSuccess_F(\"pmin(1., 5.);\", 1);\n\tEidosAssertScriptSuccess_F(\"pmin(-INF, 6.);\", (-std::numeric_limits<double>::infinity()));\n\tEidosAssertScriptSuccess_F(\"pmin(7., 1.);\", 1);\n\tEidosAssertScriptSuccess_F(\"pmin(INF, -8.);\", -8);\n\tEidosAssertScriptSuccess(\"pmin(NAN, -8.);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmin(-8., NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmin(NAN, INF);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"pmin(INF, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"pmin(c(1.,-INF,7.,INF,NAN,-8.,NAN), c(5.,6.,1.,-8.,-8.,NAN,INF));\", {1, -std::numeric_limits<double>::infinity(), 1, -8, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_S(\"pmin('foo', 'bar');\", \"bar\");\n\tEidosAssertScriptSuccess_S(\"pmin('bar', 'baz');\", \"bar\");\n\tEidosAssertScriptSuccess_S(\"pmin('xyzzy', 'xyzzy');\", \"xyzzy\");\n\tEidosAssertScriptSuccess(\"pmin('', 'bar');\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_SV(\"pmin(c('foo','bar','xyzzy',''), c('bar','baz','xyzzy','bar'));\", {\"bar\", \"bar\", \"xyzzy\", \"\"});\n\t\n\tEidosAssertScriptSuccess_LV(\"pmin(F, c(T,T,F,F));\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"pmin(c(T,F,T,F), T);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_IV(\"pmin(4, c(5,6,1,-8));\", {4, 4, 1, -8});\n\tEidosAssertScriptSuccess_IV(\"pmin(c(1,-8,7,8), -2);\", {-2, -8, -2, -2});\n\tEidosAssertScriptSuccess_FV(\"pmin(4., c(5.,6.,1.,-8.,-8.,INF));\", {4, 4, 1, -8, -8, 4});\n\tEidosAssertScriptSuccess_FV(\"pmin(c(1.,-INF,7.,INF, NAN, NAN), 5.);\", {1, -std::numeric_limits<double>::infinity(), 5, 5, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_SV(\"pmin('baz', c('bar','baz','xyzzy','bar'));\", {\"bar\", \"baz\", \"baz\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"pmin(c('foo','bar','xyzzy',''), 'baz');\", {\"baz\", \"bar\", \"baz\", \"\"});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(pmin(5, 3:7), c(3,4,5,5,5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmin(3:7, 5), c(3,4,5,5,5));\", true);\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(5), 3:7), c(3,4,5,5,5));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(3:7, matrix(5)), c(3,4,5,5,5));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(array(5, c(1,1,1)), 3:7), c(3,4,5,5,5));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(3:7, array(5, c(1,1,1))), c(3,4,5,5,5));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptSuccess_L(\"identical(pmin(5, matrix(3:7)), matrix(c(3,4,5,5,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmin(matrix(3:7), 5), matrix(c(3,4,5,5,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmin(5, array(3:7, c(1,5,1))), array(c(3,4,5,5,5), c(1,5,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(pmin(array(3:7, c(1,5,1)), 5), array(c(3,4,5,5,5), c(1,5,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(pmin(1:5, matrix(3:7)), matrix(c(3,4,5,5,5)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(3:7), 1:5), matrix(c(3,4,5,5,5)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmin(1:5, array(3:7, c(1,5,1))), array(c(3,4,5,5,5), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmin(array(3:7, c(1,5,1)), 1:5), array(c(3,4,5,5,5), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(5), matrix(3:7)), matrix(c(3,4,5,5,5)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(3:7), matrix(5)), matrix(c(3,4,5,5,5)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(5), array(3:7, c(1,5,1))), array(c(3,4,5,5,5), c(1,5,1)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(array(3:7, c(1,5,1)), matrix(5)), array(c(3,4,5,5,5), c(1,5,1)));\", 10, \"the singleton is a vector\");\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(5:1, nrow=1), matrix(1:5, ncol=1)), matrix(c(1,2,3,2,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(pmin(matrix(5:1, nrow=1), matrix(1:5, nrow=1)), matrix(c(1,2,3,2,1), nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(pmin(matrix(1:5), array(3:7, c(1,5,1))), array(c(3,4,5,5,5), c(1,5,1)));\", 10, \"same vector/matrix/array dimensions\");\n\tEidosAssertScriptSuccess_L(\"identical(pmin(array(5:1, c(1,5,1)), array(1:5, c(1,5,1))), array(c(1,2,3,2,1), c(1,5,1)));\", true);\n}\n\nvoid _RunFunctionStatisticsTests_q_through_z(void)\n{\n\t// quantile()\n\tEidosAssertScriptRaise(\"quantile(integer(0));\", 0, \"x to have length greater than 0\");\n\tEidosAssertScriptRaise(\"quantile(float(0));\", 0, \"x to have length greater than 0\");\n\tEidosAssertScriptSuccess_F(\"quantile(INF, 0.5);\", (std::numeric_limits<double>::infinity()));\n\tEidosAssertScriptSuccess_F(\"quantile(-INF, 0.5);\", (-std::numeric_limits<double>::infinity()));\n\tEidosAssertScriptSuccess_FV(\"quantile(0);\", {0.0, 0.0, 0.0, 0.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"quantile(1);\", {1.0, 1.0, 1.0, 1.0, 1.0});\n\tEidosAssertScriptRaise(\"quantile(integer(0), float(0));\", 0, \"x to have length greater than 0\");\n\tEidosAssertScriptSuccess(\"quantile(0, float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"quantile(1, float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"quantile(1, -0.0000001);\", 0, \"requires probabilities to be in [0, 1]\");\n\tEidosAssertScriptRaise(\"quantile(1, 1.0000001);\", 0, \"requires probabilities to be in [0, 1]\");\n\tEidosAssertScriptRaise(\"quantile(NAN);\", 0, \"quantiles of NAN are undefined\");\n\tEidosAssertScriptRaise(\"quantile(c(-5, 7, 2, NAN, 9));\", 0, \"quantiles of NAN are undefined\");\n\tEidosAssertScriptRaise(\"quantile(c(-5, 7, 2, 8, 9), -0.0000001);\", 0, \"requires probabilities to be in [0, 1]\");\n\tEidosAssertScriptRaise(\"quantile(c(-5, 7, 2, 8, 9), 1.0000001);\", 0, \"requires probabilities to be in [0, 1]\");\n\tEidosAssertScriptSuccess_FV(\"quantile(0:100);\", {0, 25, 50, 75, 100});\n\tEidosAssertScriptSuccess_F(\"quantile(0:100, 0.27);\", 27);\n\tEidosAssertScriptSuccess_FV(\"quantile(0:100, c(0.8, 0.3, 0.72, 0.0, 0.67));\", {80, 30, 72, 0, 67});\n\tEidosAssertScriptSuccess_FV(\"quantile(0:10, c(0.15, 0.25, 0.5, 0.82));\", {1.5, 2.5, 5.0, 8.2});\n\tEidosAssertScriptSuccess_FV(\"quantile(10:0, c(0.15, 0.25, 0.5, 0.82));\", {1.5, 2.5, 5.0, 8.2});\n\tEidosAssertScriptSuccess_FV(\"quantile(c(17, 12, 4, 87, 3, 1081, 273));\", {3, 8, 17, 180, 1081});\n\tEidosAssertScriptSuccess_FV(\"quantile(0.0:100);\", {0, 25, 50, 75, 100});\n\tEidosAssertScriptSuccess_F(\"quantile(0.0:100, 0.27);\", 27);\n\t\n\t// range()\n\tEidosAssertScriptRaise(\"range(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_IV(\"range(3);\", {3, 3});\n\tEidosAssertScriptSuccess_FV(\"range(3.5);\", {3.5, 3.5});\n\tEidosAssertScriptRaise(\"range('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"range(c(F, F, T, F, T));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_IV(\"range(c(3, 7, 19, -5, 9));\", {-5, 19});\n\tEidosAssertScriptSuccess_FV(\"range(c(3.3, 7.7, 19.1, -5.8, 9.0));\", {-5.8, 19.1});\n\tEidosAssertScriptRaise(\"range(c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"range(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"range(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"range(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_NULL(\"range(integer(0));\");\n\tEidosAssertScriptSuccess_NULL(\"range(float(0));\");\n\tEidosAssertScriptRaise(\"range(string(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_FV(\"range(NAN);\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"range(c(1.0, 5.0, NAN, 2.0));\", {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\tEidosAssertScriptSuccess_IV(\"range(integer(0), c(3,7,-8,0), 0, c(-10,10));\", {-10,10});\n\tEidosAssertScriptSuccess_FV(\"range(c(3.,7.,-8.,0.), 0., c(0.,10.), float(0));\", {-8,10});\n\tEidosAssertScriptRaise(\"range(c(3,7,-8,0), c(-10.,10.));\", 0, \"the same type\");\n\t\n\t// rank()\n\tEidosAssertScriptSuccess(\"rank(integer(0));\", gStaticEidosValue_Float_ZeroVec);\t\t// 'average' is the default\n\tEidosAssertScriptSuccess(\"rank(integer(0), 'average');\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(integer(0), 'first');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(integer(0), 'last');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"rank(integer(0), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess(\"rank(integer(0), 'max');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(integer(0), 'min');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"rank(integer(0), 'invalid');\", 0, \"requires tiesMethod to be\");\n\t\n\tEidosAssertScriptSuccess(\"rank(float(0));\", gStaticEidosValue_Float_ZeroVec);\t\t// 'average' is the default\n\tEidosAssertScriptSuccess(\"rank(float(0), 'average');\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(float(0), 'first');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(float(0), 'last');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"rank(float(0), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess(\"rank(float(0), 'max');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rank(float(0), 'min');\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"rank(float(0), 'invalid');\", 0, \"requires tiesMethod to be\");\n\t\n\tEidosAssertScriptSuccess_F(\"rank(3);\", 1.0);\n\tEidosAssertScriptSuccess_F(\"rank(3, 'average');\", 1.0);\n\tEidosAssertScriptSuccess_I(\"rank(3, 'first');\", 1);\n\tEidosAssertScriptSuccess_I(\"rank(3, 'last');\", 1);\n\tEidosAssertScriptRaise(\"rank(3, 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_I(\"rank(3, 'max');\", 1);\n\tEidosAssertScriptSuccess_I(\"rank(3, 'min');\", 1);\n\t\n\tEidosAssertScriptSuccess_F(\"rank(3.5);\", 1.0);\n\tEidosAssertScriptSuccess_F(\"rank(3.5, 'average');\", 1.0);\n\tEidosAssertScriptSuccess_I(\"rank(3.5, 'first');\", 1);\n\tEidosAssertScriptSuccess_I(\"rank(3.5, 'last');\", 1);\n\tEidosAssertScriptRaise(\"rank(3.5, 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_I(\"rank(3.5, 'max');\", 1);\n\tEidosAssertScriptSuccess_I(\"rank(3.5, 'min');\", 1);\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(0, 20, 10, 15));\", {1.0, 4.0, 2.0, 3.0});\n\tEidosAssertScriptSuccess_FV(\"rank(c(0, 20, 10, 15), 'average');\", {1.0, 4.0, 2.0, 3.0});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0, 20, 10, 15), 'first');\", {1, 4, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0, 20, 10, 15), 'last');\", {1, 4, 2, 3});\n\tEidosAssertScriptRaise(\"rank(c(0, 20, 10, 15), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(0, 20, 10, 15), 'max');\", {1, 4, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0, 20, 10, 15), 'min');\", {1, 4, 2, 3});\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(0.5, 20.5, 10.5, 15.5));\", {1.0, 4.0, 2.0, 3.0});\n\tEidosAssertScriptSuccess_FV(\"rank(c(0.5, 20.5, 10.5, 15.5), 'average');\", {1.0, 4.0, 2.0, 3.0});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0.5, 20.5, 10.5, 15.5), 'first');\", {1, 4, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0.5, 20.5, 10.5, 15.5), 'last');\", {1, 4, 2, 3});\n\tEidosAssertScriptRaise(\"rank(c(0.5, 20.5, 10.5, 15.5), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(0.5, 20.5, 10.5, 15.5), 'max');\", {1, 4, 2, 3});\n\tEidosAssertScriptSuccess_IV(\"rank(c(0.5, 20.5, 10.5, 15.5), 'min');\", {1, 4, 2, 3});\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(10, 12, 15, 12, 10, 25, 12));\", {1.5, 4.0, 6.0, 4.0, 1.5, 7.0, 4.0});\n\tEidosAssertScriptSuccess_FV(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'average');\", {1.5, 4.0, 6.0, 4.0, 1.5, 7.0, 4.0});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'first');\", {1, 3, 6, 4, 2, 7, 5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'last');\", {2, 5, 6, 4, 1, 7, 3});\n\tEidosAssertScriptRaise(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'max');\", {2, 5, 6, 5, 2, 7, 5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10, 12, 15, 12, 10, 25, 12), 'min');\", {1, 3, 6, 3, 1, 7, 3});\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5));\", {1.5, 4.0, 6.0, 4.0, 1.5, 7.0, 4.0});\n\tEidosAssertScriptSuccess_FV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'average');\", {1.5, 4.0, 6.0, 4.0, 1.5, 7.0, 4.0});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'first');\", {1, 3, 6, 4, 2, 7, 5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'last');\", {2, 5, 6, 4, 1, 7, 3});\n\tEidosAssertScriptRaise(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'max');\", {2, 5, 6, 5, 2, 7, 5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(10.5, 12.5, 15.5, 12.5, 10.5, 25.5, 12.5), 'min');\", {1, 3, 6, 3, 1, 7, 3});\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3));\", {14.0, 5.0, 14.0, 9.5, 19.0, 9.5, 9.5, 9.5, 2.5, 9.5, 17.5, 5.0, 16.0, 5.0, 2.5, 17.5, 14.0, 1.0, 20.0, 9.5});\n\tEidosAssertScriptSuccess_FV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'average');\", {14.0, 5.0, 14.0, 9.5, 19.0, 9.5, 9.5, 9.5, 2.5, 9.5, 17.5, 5.0, 16.0, 5.0, 2.5, 17.5, 14.0, 1.0, 20.0, 9.5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'first');\", {13, 4, 14, 7, 19, 8, 9, 10, 2, 11, 17, 5, 16, 6, 3, 18, 15, 1, 20, 12});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'last');\", {15, 6, 14, 12, 19, 11, 10, 9, 3, 8, 18, 5, 16, 4, 2, 17, 13, 1, 20, 7});\n\tEidosAssertScriptRaise(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'max');\", {15, 6, 15, 12, 19, 12, 12, 12, 3, 12, 18, 6, 16, 6, 3, 18, 15, 1, 20, 12});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'min');\", {13, 4, 13, 7, 19, 7, 7, 7, 2, 7, 17, 4, 16, 4, 2, 17, 13, 1, 20, 7});\n\t\n\tEidosAssertScriptSuccess_FV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3));\", {14.0, 5.0, 14.0, 9.5, 19.0, 9.5, 9.5, 9.5, 2.5, 9.5, 17.5, 5.0, 16.0, 5.0, 2.5, 17.5, 14.0, 1.0, 20.0, 9.5});\n\tEidosAssertScriptSuccess_FV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'average');\", {14.0, 5.0, 14.0, 9.5, 19.0, 9.5, 9.5, 9.5, 2.5, 9.5, 17.5, 5.0, 16.0, 5.0, 2.5, 17.5, 14.0, 1.0, 20.0, 9.5});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'first');\", {13, 4, 14, 7, 19, 8, 9, 10, 2, 11, 17, 5, 16, 6, 3, 18, 15, 1, 20, 12});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'last');\", {15, 6, 14, 12, 19, 11, 10, 9, 3, 8, 18, 5, 16, 4, 2, 17, 13, 1, 20, 7});\n\tEidosAssertScriptRaise(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'random');\", 0, \"not currently supported\");\n\tEidosAssertScriptSuccess_IV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'max');\", {15, 6, 15, 12, 19, 12, 12, 12, 3, 12, 18, 6, 16, 6, 3, 18, 15, 1, 20, 12});\n\tEidosAssertScriptSuccess_IV(\"rank(c(4.0, 2, 4, 3, 7, 3, 3, 3, 1, 3, 6, 2, 5, 2, 1, 6, 4, 0, 9, 3), 'min');\", {13, 4, 13, 7, 19, 7, 7, 7, 2, 7, 17, 4, 16, 4, 2, 17, 13, 1, 20, 7});\n\t\n\tEidosAssertScriptRaise(\"rank(c(T, F));\", 0, \"cannot be type logical\");\t\t\t\t\t\t// logical not supported, unlike R\n\tEidosAssertScriptRaise(\"rank(c('a', 'q', 'm', 'f', 'w'));\", 0, \"cannot be type string\");\t// string not supported, unlike R\n\t\n\t/*EidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = rank(x); identical(o, c(5, 1, 0, 3, 2, 4)) | identical(o, c(5, 1, 0, 3, 4, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = rank(x, ascending=T); identical(o, c(5, 1, 0, 3, 2, 4)) | identical(o, c(5, 1, 0, 3, 4, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = rank(x, ascending=F); identical(o, c(3, 0, 1, 5, 2, 4)) | identical(o, c(3, 0, 1, 5, 4, 2));\", true);*/\n\t\n\t// sd()\n\tEidosAssertScriptRaise(\"sd(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sd(3);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"sd(3.5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"sd('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sd(c(F, F, T, F, T));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_F(\"sd(c(2, 3, 2, 8, 0));\", 3);\n\tEidosAssertScriptSuccess_F(\"sd(c(9.1, 5.1, 5.1, 4.1, 7.1));\", 2.0);\n\tEidosAssertScriptSuccess(\"sd(c(9.1, 5.1, 5.1, NAN, 7.1));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"sd(c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sd(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sd(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sd(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sd(integer(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"sd(float(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"sd(string(0));\", 0, \"cannot be type\");\n\t\n\t// ttest()\n\tEidosAssertScriptRaise(\"ttest(1:5.0);\", 0, \"either y or mu to be non-NULL\");\n\tEidosAssertScriptRaise(\"ttest(1:5.0, 1:5.0, 5.0);\", 0, \"either y or mu to be NULL\");\n\tEidosAssertScriptRaise(\"ttest(5.0, 1:5.0);\", 0, \"enough elements in x\");\n\tEidosAssertScriptRaise(\"ttest(1:5.0, 5.0);\", 0, \"enough elements in y\");\n\tEidosAssertScriptRaise(\"ttest(5.0, mu=6.0);\", 0, \"enough elements in x\");\n\tEidosAssertScriptSuccess_L(\"abs(ttest(1:50.0, 1:50.0) - 1.0) < 0.001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(ttest(1:50.0, 1:60.0) - 0.101496) < 0.001;\", true);\t\t\t// R gives 0.1046, not sure why but I suspect corrected vs. uncorrected standard deviations\n\tEidosAssertScriptSuccess_L(\"abs(ttest(1:50.0, 10.0:60.0) - 0.00145575) < 0.001;\", true);\t// R gives 0.001615\n\tEidosAssertScriptSuccess_L(\"abs(ttest(1:50.0, mu=25.0) - 0.807481) < 0.001;\", true);\t\t// R gives 0.8094\n\tEidosAssertScriptSuccess_L(\"abs(ttest(1:50.0, mu=30.0) - 0.0321796) < 0.001;\", true);\t\t// R gives 0.03387\n\tEidosAssertScriptSuccess(\"ttest(c(1.0, 2.0, NAN), mu=25.0);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"ttest(c(1.0, 2.0, NAN), c(8.0, 9.0, 10.0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"ttest(c(1.0, 2.0, 3,0), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"ttest(c(1.0, 2.0, NAN), c(8.0, 9.0, NAN));\", gStaticEidosValue_FloatNAN);\n\t\n\t// var()\n\tEidosAssertScriptRaise(\"var(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"var(3);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"var(3.5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"var('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"var(c(F, F, T, F, T));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_F(\"var(c(2, 3, 2, 8, 0));\", 9);\n\tEidosAssertScriptSuccess_F(\"var(c(9.1, 5.1, 5.1, 4.1, 7.1));\", 4.0);\n\tEidosAssertScriptSuccess(\"var(c(9.1, 5.1, 5.1, NAN, 7.1));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"var(c('foo', 'bar', 'baz'));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"var(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"var(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"var(logical(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"var(integer(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"var(float(0));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"var(string(0));\", 0, \"cannot be type\");\n}\n\n#pragma mark distributions\nvoid _RunFunctionDistributionTests(void)\n{\n\t// findInterval() - note results are 1 less than in R, due to zero-basing vs. 1-basing of indices\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), integer(0));\", 0, \"vec to be of length > 0\");\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), float(0));\", 0, \"vec to be of length > 0\");\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), c(0:10,9));\", 0, \"non-decreasing order\");\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), c(1,0:10));\", 0, \"non-decreasing order\");\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), c(0:10.0,9));\", 0, \"non-decreasing order\");\n\tEidosAssertScriptRaise(\"findInterval(c(-1,0,1,9,10,11), c(1.0,0:10));\", 0, \"non-decreasing order\");\n\t\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3);\", 0);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3, rightmostClosed=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3, rightmostClosed=T, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3);\", {-1, -1, -1, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3, rightmostClosed=T);\", {-1, -1, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3, rightmostClosed=T, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\t\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3);\", 0);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3, rightmostClosed=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3, rightmostClosed=T, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3);\", {-1, -1, -1, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3, rightmostClosed=T);\", {-1, -1, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3, rightmostClosed=T, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\t\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3.0);\", 0);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3.0, rightmostClosed=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3.0, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3, 3.0, rightmostClosed=T, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3.0);\", {-1, -1, -1, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3.0, rightmostClosed=T);\", {-1, -1, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3.0, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0:5, 3.0, rightmostClosed=T, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\t\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3.0);\", 0);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3.0, rightmostClosed=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3.0, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_I(\"findInterval(3.0, 3.0, rightmostClosed=T, allInside=T);\", -1);\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3.0);\", {-1, -1, -1, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3.0, rightmostClosed=T);\", {-1, -1, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3.0, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(0.0:5, 3.0, rightmostClosed=T, allInside=T);\", {0, 0, 0, -1, -1, -1});\n\t\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10);\", {-1, 0, 1, 9, 10, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10, rightmostClosed=T);\", {-1, 0, 1, 9, 9, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10, rightmostClosed=T, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), repEach(0:10, 2));\", {-1, 1, 3, 19, 21, 21});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10);\", {10, 10, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10, rightmostClosed=T);\", {10, 9, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10, rightmostClosed=T, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), repEach(0:10, 2));\", {21, 21, 19, 3, 1, -1});\n\t\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10.0);\", {-1, 0, 1, 9, 10, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10.0, rightmostClosed=T);\", {-1, 0, 1, 9, 9, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10.0, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10.0, rightmostClosed=T, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), repEach(0:10.0, 2));\", {-1, 1, 3, 19, 21, 21});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10.0);\", {10, 10, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10.0, rightmostClosed=T);\", {10, 9, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10.0, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10.0, rightmostClosed=T, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), repEach(0:10.0, 2));\", {21, 21, 19, 3, 1, -1});\n\t\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10);\", {-1, 0, 1, 9, 10, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10, rightmostClosed=T);\", {-1, 0, 1, 9, 9, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), 0:10, rightmostClosed=T, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11.0), repEach(0:10, 2));\", {-1, 1, 3, 19, 21, 21});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10);\", {10, 10, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10, rightmostClosed=T);\", {10, 9, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), 0:10, rightmostClosed=T, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1.0), repEach(0:10, 2));\", {21, 21, 19, 3, 1, -1});\n\t\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10.0);\", {-1, 0, 1, 9, 10, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10.0, rightmostClosed=T);\", {-1, 0, 1, 9, 9, 10});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10.0, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), 0:10.0, rightmostClosed=T, allInside=T);\", {0, 0, 1, 9, 9, 9});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(-1,0,1,9,10,11), repEach(0:10.0, 2));\", {-1, 1, 3, 19, 21, 21});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10.0);\", {10, 10, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10.0, rightmostClosed=T);\", {10, 9, 9, 1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10.0, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), 0:10.0, rightmostClosed=T, allInside=T);\", {9, 9, 9, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"findInterval(c(11,10,9,1,0,-1), repEach(0:10.0, 2));\", {21, 21, 19, 3, 1, -1});\n\t\n\t// dmvnorm()\n\tEidosAssertScriptRaise(\"dmvnorm(array(c(1.0,2,3,2,1), c(1,5,1)), c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2));\", 0, \"requires x to be\");\n\tEidosAssertScriptSuccess(\"dmvnorm(float(0), c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"dmvnorm(3.0, c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2));\", 0, \"dimensionality of >= 2\");\n\tEidosAssertScriptRaise(\"dmvnorm(1.0:3.0, c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2));\", 0, \"matching the dimensionality\");\n\tEidosAssertScriptRaise(\"dmvnorm(c(0.0, 2.0), c(0.0, 2.0), c(10,3,3,2));\", 0, \"sigma to be a matrix\");\n\tEidosAssertScriptRaise(\"dmvnorm(c(0.0, 2.0), c(0.0, 2.0, 3.0), matrix(c(10,3,3,2), nrow=2));\", 0, \"matching the dimensionality\");\n\tEidosAssertScriptRaise(\"dmvnorm(c(0.0, 2.0), c(0.0, 2.0), matrix(c(10,3,3,2,4,8), nrow=3));\", 0, \"matching the dimensionality\");\n\tEidosAssertScriptRaise(\"abs(dmvnorm(c(0.0, 2.0), c(0.0, 2.0), matrix(c(0,0,0,0), nrow=2)) - 0.047987) < 0.00001;\", 4, \"positive-definite\");\n\tEidosAssertScriptSuccess_L(\"abs(dmvnorm(c(0.0, 2.0), c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2)) - 0.047987) < 0.00001;\", true);\n\tEidosAssertScriptSuccess(\"dmvnorm(c(NAN, 2.0), c(0.0, 2.0), matrix(c(10,3,3,2), nrow=2));\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"dmvnorm(c(0.0, 2.0), c(0.0, 2.0), matrix(c(10,3,NAN,2), nrow=2));\", 0, \"to contain NANs\");\n\t\n\t// dnorm()\n\tEidosAssertScriptSuccess(\"dnorm(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"dnorm(float(0), float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"dnorm(0.0, 0, 1) - 0.3989423 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"dnorm(1.0, 1.0, 1.0) - 0.3989423 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_LV(\"dnorm(c(0.0,0.0), c(0,0), 1) - 0.3989423 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"dnorm(c(0.0,1.0), c(0.0,1.0), 1.0) - 0.3989423 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"dnorm(c(0.0,0.0), 0.0, c(1.0,1.0)) - 0.3989423 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"dnorm(c(-1.0,0.0,1.0)) - c(0.2419707,0.3989423,0.2419707) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"dnorm(1.0, 0, 0);\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"dnorm(1.0, 0.0, -1.0);\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"dnorm(c(0.5, 1.0), 0.0, c(5, -1.0));\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"dnorm(1.0, c(-10, 10, 1), 100.0);\", 0, \"requires mean to be\");\n\tEidosAssertScriptRaise(\"dnorm(1.0, 10.0, c(0.1, 10, 1));\", 0, \"requires sd to be\");\n\tEidosAssertScriptSuccess(\"dnorm(NAN, 0, 1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"dnorm(1.0, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"dnorm(1.0, 0, NAN);\", gStaticEidosValue_FloatNAN);\n\t\t\n\t// qnorm()\n\tEidosAssertScriptSuccess(\"-qnorm(0.0);\", gStaticEidosValue_FloatINF);\n\tEidosAssertScriptSuccess(\"qnorm(1.0);\", gStaticEidosValue_FloatINF);\n\tEidosAssertScriptSuccess_L(\"qnorm(0.05) + 1.644854 < 0.00001 ;\", true);\n\tEidosAssertScriptSuccess_L(\"qnorm(0.95) - 1.644854 < 0.00001 ;\", true);\n\tEidosAssertScriptSuccess_L(\"qnorm(0.05, 0, 1) + 1.644854 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"qnorm(0.05, 5.5, 3.4) + 0.09250233 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"qnorm(0.05, 0, 1.0) + 1.644854 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_LV(\"qnorm(c(0.05,0.05), c(0, 0), 1) + 1.644854 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c(2, 1)*qnorm(c(0.05, 0.05), 0., c(1, 2)) + 3.289707 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"qnorm(c(0.25, 0.5, 0.75)) - c(-0.6744898, 0.0000000, 0.6744898) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"qnorm(0.5, 0, 0);\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"qnorm(-0.1);\", 0, \"requires 0.0 <= p <= 1.0\");\n\tEidosAssertScriptRaise(\"qnorm(1.1);\", 0, \"requires 0.0 <= p <= 1.0\");\n\tEidosAssertScriptRaise(\"qnorm(c(0.05, 1.1));\", 0, \"requires 0.0 <= p <= 1.0\");\n\tEidosAssertScriptRaise(\"qnorm(c(0.05, 1.1), c(0.0, 0.1));\", 0, \"requires 0.0 <= p <= 1.0\");\n\tEidosAssertScriptRaise(\"qnorm(c(0.05, 1.1), c(0.0, 0.1), c(0.1, 0.5));\", 0, \"requires 0.0 <= p <= 1.0\");\n\tEidosAssertScriptRaise(\"qnorm(c(0.05, 0.95), 0.0, c(5, -1.0));\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"qnorm(0.1, c(-10, 10, 1), 100.0);\", 0, \"requires mean to be\");\n\tEidosAssertScriptRaise(\"qnorm(0.1, 10.0, c(0.1, 10, 1));\", 0, \"requires sd to be\");\n\tEidosAssertScriptSuccess(\"qnorm(NAN);\", gStaticEidosValue_FloatNAN);\n\n\t// pnorm()\n\tEidosAssertScriptSuccess(\"pnorm(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"pnorm(float(0), float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"pnorm(0.0, 0, 1) - 0.5 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"pnorm(1.0, 1.0, 1.0) - 0.5 < 0.00001;\", true);\n\tEidosAssertScriptSuccess_LV(\"pnorm(c(0.0,0.0), c(0,0), 1) - 0.5 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"pnorm(c(0.0,1.0), c(0.0,1.0), 1.0) - 0.5 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"pnorm(c(0.0,0.0), 0.0, c(1.0,1.0)) - 0.5 < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"pnorm(c(-1.0,0.0,1.0)) - c(0.1586553,0.5,0.8413447) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"pnorm(c(-1.0,0.0,1.0), mean=0.5, sd=10) - c(0.4403823,0.4800612,0.5199388) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"pnorm(1.0, 0, 0);\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"pnorm(1.0, 0.0, -1.0);\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"pnorm(c(0.5, 1.0), 0.0, c(5, -1.0));\", 0, \"requires sd > 0.0\");\n\tEidosAssertScriptRaise(\"pnorm(1.0, c(-10, 10, 1), 100.0);\", 0, \"requires mean to be\");\n\tEidosAssertScriptRaise(\"pnorm(1.0, 10.0, c(0.1, 10, 1));\", 0, \"requires sd to be\");\n\tEidosAssertScriptSuccess(\"pnorm(NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// dbeta()\n\tEidosAssertScriptSuccess(\"dbeta(float(0), 1, 1000);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"dbeta(float(0), float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"abs(dbeta(0.0, 1, 5) - c(5)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dbeta(0.5, 1, 5) - c(0.3125)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dbeta(1.0, 1, 5) - c(0)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"abs(dbeta(c(0, 0.5, 1), 1, 5) - c(5, 0.3125, 0)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"abs(dbeta(c(0, 0.5, 1), 1, c(10, 4, 1)) - c(10, 0.5, 1)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"abs(dbeta(c(0, 0.5, 1), c(1, 2, 3), c(10, 4, 1)) - c(10, 1.25, 3)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), 0, 1);\", 0, \"requires alpha > 0.0\");\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), c(1,0), 1);\", 0, \"requires alpha > 0.0\");\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), 1, 0);\", 0, \"requires beta > 0.0\");\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), 1, c(1,0));\", 0, \"requires beta > 0.0\");\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), c(0.1, 10, 1), 10.0);\", 0, \"requires alpha to be of length\");\n\tEidosAssertScriptRaise(\"dbeta(c(0.0, 0), 10.0, c(0.1, 10, 1));\", 0, \"requires beta to be of length\");\n\tEidosAssertScriptSuccess(\"dbeta(NAN, 1, 5);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"dbeta(0.5, NAN, 5);\", 0, \"requires alpha > 0.0\");\n\tEidosAssertScriptRaise(\"dbeta(0.5, 1, NAN);\", 0, \"requires beta > 0.0\");\n\t\n\t// rbeta()\n\tEidosAssertScriptSuccess(\"rbeta(0, 1, 1000);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rbeta(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rbeta(1, 1, 5) - c(0.192527)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rbeta(3, 1, 5) - c(0.192527, 0.235423, 0.365635)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rbeta(-1, 1, 1000);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rbeta(2, 0, 1);\", 0, \"requires alpha > 0.0\");\n\tEidosAssertScriptRaise(\"rbeta(2, c(1,0), 1);\", 0, \"requires alpha > 0.0\");\n\tEidosAssertScriptRaise(\"rbeta(2, 1, 0);\", 0, \"requires beta > 0.0\");\n\tEidosAssertScriptRaise(\"rbeta(2, 1, c(1,0));\", 0, \"requires beta > 0.0\");\n\tEidosAssertScriptRaise(\"rbeta(2, c(0.1, 10, 1), 10.0);\", 0, \"requires alpha to be of length\");\n\tEidosAssertScriptRaise(\"rbeta(2, 10.0, c(0.1, 10, 1));\", 0, \"requires beta to be of length\");\n\tEidosAssertScriptSuccess(\"rbeta(1, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rbeta(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rbinom()\n\tEidosAssertScriptSuccess(\"rbinom(0, 10, 0.5);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"rbinom(1, 10, 0.0);\", {0});\n\tEidosAssertScriptSuccess_IV(\"rbinom(3, 10, 0.0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"rbinom(3, 10, 1.0);\", {10, 10, 10});\n\tEidosAssertScriptSuccess_IV(\"rbinom(3, 0, 0.0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"rbinom(3, 0, 1.0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rbinom(10, 1, 0.5);\", {0, 0, 0, 0, 1, 1, 0, 1, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rbinom(10, 1, 0.5000001);\", {1, 1, 1, 1, 1, 1, 0, 1, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rbinom(5, 10, 0.5);\", {2, 3, 4, 4, 3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rbinom(5, 10, 0.5);\", {5, 5, 7, 4, 8});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rbinom(5, 1000, 0.01);\", {8, 8, 11, 7, 6});\n\tEidosAssertScriptSuccess_IV(\"setSeed(3); rbinom(5, 1000, 0.99);\", {992, 996, 989, 988, 990});\n\tEidosAssertScriptSuccess_IV(\"setSeed(4); rbinom(3, 100, c(0.1, 0.5, 0.9));\", {6, 59, 89});\n\tEidosAssertScriptSuccess_IV(\"setSeed(5); rbinom(3, c(10, 30, 50), 0.5);\", {4, 13, 22});\n\tEidosAssertScriptRaise(\"rbinom(-1, 10, 0.5);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rbinom(3, -1, 0.5);\", 0, \"requires size >= 0\");\n\tEidosAssertScriptRaise(\"rbinom(3, 10, -0.1);\", 0, \"in [0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rbinom(3, 10, 1.1);\", 0, \"in [0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rbinom(3, 10, c(0.1, 0.2));\", 0, \"to be of length 1 or n\");\n\tEidosAssertScriptRaise(\"rbinom(3, c(10, 12), 0.5);\", 0, \"to be of length 1 or n\");\n\tEidosAssertScriptRaise(\"rbinom(2, -1, c(0.5,0.5));\", 0, \"requires size >= 0\");\n\tEidosAssertScriptRaise(\"rbinom(2, c(10,10), -0.1);\", 0, \"in [0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rbinom(2, 10, NAN);\", 0, \"in [0.0, 1.0]\");\n\t\n\t// rcauchy()\n\tEidosAssertScriptSuccess(\"rcauchy(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rcauchy(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rcauchy(2) - c(0.16713, 0.595204)) < 0.00001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rcauchy(2, 10.0) - c(10.1671, 10.5952)) < 0.001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(2); abs(rcauchy(2, 10.0, 100.0) - c(110.349, 122.822)) < 0.001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(3); abs(rcauchy(2, c(-10, 10), 100.0) - c(133.494, 14.8875)) < 0.01;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(4); abs(rcauchy(2, 10.0, c(0.1, 10)) - c(10.0284, 8.47099)) < 0.001;\", {true, true});\n\tEidosAssertScriptRaise(\"rcauchy(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rcauchy(1, 0, 0);\", 0, \"requires scale > 0.0\");\n\tEidosAssertScriptRaise(\"rcauchy(2, c(0,0), -1);\", 0, \"requires scale > 0.0\");\n\tEidosAssertScriptRaise(\"rcauchy(2, c(-10, 10, 1), 100.0);\", 0, \"requires location to be\");\n\tEidosAssertScriptRaise(\"rcauchy(2, 10.0, c(0.1, 10, 1));\", 0, \"requires scale to be\");\n\tEidosAssertScriptSuccess(\"rcauchy(1, NAN, 100.0);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rcauchy(1, 10.0, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rdirichlet()\n\tEidosAssertScriptSuccess(\"rdirichlet(0, c(1,1,1));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptRaise(\"rdirichlet(1, 1);\", 0, \"alpha to have length >= 2\");\n\tEidosAssertScriptRaise(\"rdirichlet(1, c(-1, -1, -1));\", 0, \"alpha value to be positive and finite\");\n\tEidosAssertScriptRaise(\"rdirichlet(1, c(INF, INF, INF));\", 0, \"alpha value to be positive and finite\");\n\tEidosAssertScriptSuccess_L(\"isClose(sum(rdirichlet(1, c(1, 1, 1))), 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(sum(rdirichlet(1, c(2, 8, 5))), 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(rowSums(rdirichlet(20, c(1, 1, 1))), 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(rowSums(rdirichlet(20, c(2, 8, 5))), 1.0);\", true);\n\t\n\t// rdunif()\n\tEidosAssertScriptSuccess(\"rdunif(0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rdunif(0, integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"rdunif(1, 0, 0);\", {0});\n\tEidosAssertScriptSuccess_IV(\"rdunif(3, 0, 0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"rdunif(1, 1, 1);\", {1});\n\tEidosAssertScriptSuccess_IV(\"rdunif(3, 1, 1);\", {1, 1, 1});\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(1), 0);\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(10), c(0, 0, 0, 0, 1, 1, 0, 1, 0, 1));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(10, 10, 11), c(10, 10, 10, 10, 11, 11, 10, 11, 10, 11));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(10, 10, 15), c(10, 11, 11, 11, 10, 11, 14, 11, 14, 11));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(10, -10, 15), c(-9, -6, -4, -2, -8, -3, 9, -2, 10, -2));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(5, 1000000, 2000000), c(1052712, 1170896, 1269062, 1323101, 1105484));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(5, 1000000000, 2000000000), c(1052712017, 1170896080, 1269062279, 1323101491, 1105484052));\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif(5, 10000000000, 20000000000), c(10527120177, 11708960806, 12690622795, 13231014907, 11054840521));\", true);\t// 64-bit range\n\tEidosAssertScriptRaise(\"rdunif(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rdunif(1, 0, -1);\", 0, \"requires min <= max\");\n\tEidosAssertScriptRaise(\"rdunif(2, 0, c(7, -1));\", 0, \"requires min <= max\");\n\tEidosAssertScriptRaise(\"rdunif(2, c(7, -1), 0);\", 0, \"requires min <= max\");\n\tEidosAssertScriptRaise(\"rdunif(2, c(-10, 10, 1), 100);\", 0, \"requires min\");\n\tEidosAssertScriptRaise(\"rdunif(2, -10, c(1, 10, 1));\", 0, \"requires max\");\n\t\n\t// rdunif64()\n\tEidosAssertScriptSuccess(\"rdunif64(0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"rdunif64(1); T;\", true);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); identical(rdunif64(1), 972365100324636832);\", true);\n\tEidosAssertScriptRaise(\"rdunif64(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptSuccess_L(\"x = mean(rdunif64(1000000) >= 0); abs(0.5 - x) < 0.005;\", true);\t// check for a roughly equal number of positive and negative\n\tEidosAssertScriptSuccess_L(\"x = mean(rdunif64(1000000) / 1e16); abs(0.0 - x) < 2.0;\", true);\t// check the mean is roughly zero (but note the SD is huge)\n\t\n\t// dexp()\n\tEidosAssertScriptSuccess(\"dexp(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"dexp(float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"abs(dexp(1.0) - 0.3678794) < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dexp(0.01) - 0.9900498) < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"all(abs(dexp(c(1.0, 0.01)) - c(0.3678794, 0.9900498)) < 0.00001);\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dexp(0.01, 0.1) - 9.048374) < 0.00001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dexp(0.01, 0.01) - 36.78794) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"abs(dexp(c(0.01, 0.01, 0.01), c(1, 0.1, 0.01)) - c(0.9900498, 9.048374, 36.78794)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"dexp(3.0, c(10, 5));\", 0, \"requires mu to be\");\n\tEidosAssertScriptSuccess(\"dexp(NAN, 0.1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"dexp(0.01, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rexp()\n\tEidosAssertScriptSuccess(\"rexp(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rexp(0, float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rexp(1) - c(0.0541521)) < 0.00001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rexp(3) - c(0.0541521, 0.18741, 0.313427)) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(1); abs(rexp(3, 10) - c(6.36062, 6.28821, 19.0056)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(2); abs(rexp(3, 100000) - c(28842.1, 31355.3, 102831.0)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(3); abs(rexp(3, c(10, 100, 1000)) - c(3.65665, 1.5667, 948.946)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rexp(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptSuccess_F(\"rexp(1, 0);\", 0.0);\n\tEidosAssertScriptSuccess_FV(\"rexp(2, 0);\", {0.0, 0.0});\n\tEidosAssertScriptRaise(\"rexp(2, -0.001);\", 0, \"requires mu >= 0.0\");\n\tEidosAssertScriptRaise(\"rexp(2, c(1.0, -0.001));\", 0, \"requires mu >= 0.0\");\n\tEidosAssertScriptRaise(\"rexp(3, c(10, 5));\", 0, \"requires mu to be\");\n\tEidosAssertScriptSuccess(\"rexp(1, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// dgamma()\n\tEidosAssertScriptSuccess(\"dgamma(float(0), 0, 1000);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"dgamma(float(0), float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"dgamma(3.0, 0, 1000);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_L(\"abs(dgamma(0.1, 1/100, 1) - 0.004539993) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dgamma(0.01, 1/100, 1) - 36.78794) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_L(\"abs(dgamma(0.001, 1/100, 1) - 90.48374) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"abs(dgamma(c(0.1, 0.01, 0.001), 1/100, 1) - c(0.004539993, 36.78794, 90.48374)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"dgamma(2.0, 0, 0);\", 0, \"requires shape > 0.0\");\n\tEidosAssertScriptRaise(\"dgamma(c(1.0, 2.0), 0, c(1.0, 0));\", 0, \"requires shape > 0.0\");\n\tEidosAssertScriptRaise(\"dgamma(2.0, c(0.1, 10, 1), 10.0);\", 0, \"requires mean to be of length\");\n\tEidosAssertScriptRaise(\"dgamma(2.0, 10.0, c(0.1, 10, 1));\", 0, \"requires shape to be of length\");\n\tEidosAssertScriptSuccess(\"dgamma(NAN, 1/100, 1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"dgamma(0.1, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptRaise(\"dgamma(0.1, 1/100, NAN);\", 0, \"requires shape > 0.0\");\n\t\n\t// rf()\n\tEidosAssertScriptSuccess(\"rf(0, 10, 15);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rf(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rf(1, 2, 3) - c(1.95702)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rf(3, 2, 3) - c(1.95702, 2.85093, 2.42374)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rf(3, 2, 4) - c(1.64284, 2.29314, 2.52913)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rf(3, c(2,2,2), 4) - c(1.64284, 2.29314, 2.52913)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rf(3, 2, c(4,4,4)) - c(1.64284, 2.29314, 2.52913)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rf(-1, 10, 15);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rf(2, 0, 15);\", 0, \"requires d1 > 0.0\");\n\tEidosAssertScriptRaise(\"rf(2, 10, 0);\", 0, \"requires d2 > 0.0\");\n\tEidosAssertScriptRaise(\"rf(2, c(10,0), 15);\", 0, \"requires d1 > 0.0\");\n\tEidosAssertScriptRaise(\"rf(2, 10, c(15,0));\", 0, \"requires d2 > 0.0\");\n\tEidosAssertScriptRaise(\"rf(2, c(0.1, 10, 1), 10.0);\", 0, \"requires d1 to be of length\");\n\tEidosAssertScriptRaise(\"rf(2, 10.0, c(0.1, 10, 1));\", 0, \"requires d2 to be of length\");\n\tEidosAssertScriptSuccess(\"rf(1, NAN, 15);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rf(1, 10, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rgamma()\n\tEidosAssertScriptSuccess(\"rgamma(0, 0, 1000);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rgamma(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"rgamma(3, 0, 1000);\", {0.0, 0.0, 0.0});\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rgamma(1, 1, 100) - c(1.01615)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rgamma(3, 1, 100) - c(1.01615, 0.939423, 1.03091)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rgamma(3, -1, 100) - c(-1.01615, -0.939423, -1.03091)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rgamma(3, c(-1,-1,-1), 100) - c(-1.01615, -0.939423, -1.03091)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rgamma(3, -1, c(100,100,100)) - c(-1.01615, -0.939423, -1.03091)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rgamma(-1, 0, 1000);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rgamma(2, 0, 0);\", 0, \"requires shape > 0.0\");\n\tEidosAssertScriptRaise(\"rgamma(2, c(0,0), 0);\", 0, \"requires shape > 0.0\");\n\tEidosAssertScriptRaise(\"rgamma(2, c(0.1, 10, 1), 10.0);\", 0, \"requires mean to be of length\");\n\tEidosAssertScriptRaise(\"rgamma(2, 10.0, c(0.1, 10, 1));\", 0, \"requires shape to be of length\");\n\tEidosAssertScriptSuccess(\"rgamma(1, NAN, 100);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rgamma(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rgeom()\n\tEidosAssertScriptSuccess(\"rgeom(0, 1.0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"rgeom(1, 1.0);\", {0});\n\tEidosAssertScriptSuccess_IV(\"rgeom(5, 1.0);\", {0, 0, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rgeom(5, 0.2);\", {3, 3, 0, 6, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rgeom(5, 0.4);\", {1, 1, 0, 2, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(5); rgeom(5, 0.01);\", {140, 18, 201, 107, 368});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rgeom(1, 0.0001);\", {13840});\n\tEidosAssertScriptSuccess_IV(\"setSeed(3); rgeom(6, c(1, 0.1, 0.01, 0.001, 0.0001, 0.00001));\", {0, 11, 414, 489, 3479, 62929});\n\tEidosAssertScriptRaise(\"rgeom(-1, 1.0);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rgeom(0, 0.0);\", 0, \"requires 0.0 < p <= 1.0\");\n\tEidosAssertScriptRaise(\"rgeom(0, 1.1);\", 0, \"requires 0.0 < p <= 1.0\");\n\tEidosAssertScriptRaise(\"rgeom(2, c(0.1, 0.1, 0.1));\", 0, \"requires p to be of length 1 or n\");\n\tEidosAssertScriptRaise(\"rgeom(2, c(0.0, 0.0));\", 0, \"requires 0.0 < p <= 1.0\");\n\tEidosAssertScriptRaise(\"rgeom(2, c(0.5, 1.1));\", 0, \"requires 0.0 < p <= 1.0\");\n\tEidosAssertScriptRaise(\"rgeom(2, NAN);\", 0, \"requires 0.0 < p <= 1.0\");\n\t\n\t// rlaplace()\n\tEidosAssertScriptSuccess(\"rlaplace(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rlaplace(0, float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rlaplace(1) - c(-0.111405)) < 0.00001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rlaplace(3) - c(-0.111405, -0.418235, -0.77246)) < 0.00001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(1); abs(rlaplace(3, 10) - c(-28.3454, -27.1145, 3.55203)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(2); abs(rlaplace(3, 100000) - c(-69536.44, -77285.89, 125604.39)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(3); abs(rlaplace(3, c(10, 100, 1000)) - c(-9.48116, -3.15833, 1488.54)) < 0.1;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rlaplace(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rlaplace(2, -0.001);\", 0, \"requires b > 0.0\");\n\tEidosAssertScriptRaise(\"rlaplace(2, 0.0);\", 0, \"requires b > 0.0\");\n\tEidosAssertScriptRaise(\"rlaplace(2, c(1.0, -0.001));\", 0, \"requires b > 0.0\");\n\tEidosAssertScriptRaise(\"rlaplace(2, c(1.0, 0.0));\", 0, \"requires b > 0.0\");\n\tEidosAssertScriptRaise(\"rlaplace(3, c(10, 5));\", 0, \"requires b to be\");\n\tEidosAssertScriptSuccess(\"rlaplace(1, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rlnorm()\n\tEidosAssertScriptSuccess(\"rlnorm(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rlnorm(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"rlnorm(1, 0, 0);\", {1.0});\n\tEidosAssertScriptSuccess_FV(\"rlnorm(3, 0, 0);\", {1.0, 1.0, 1.0});\n\tEidosAssertScriptSuccess_LV(\"abs(rlnorm(3, 1, 0) - E) < 0.000001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"abs(rlnorm(3, c(1,1,1), 0) - E) < 0.000001;\", {true, true, true});\n\tEidosAssertScriptSuccess_LV(\"abs(rlnorm(3, 1, c(0,0,0)) - E) < 0.000001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rlnorm(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rlnorm(1, 0, -1);\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rlnorm(2, c(0,0), -1);\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rlnorm(2, 0, c(-1, -1));\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rlnorm(2, c(0,0), c(-1, -1));\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rlnorm(2, c(-10, 10, 1), 100.0);\", 0, \"requires meanlog to be\");\n\tEidosAssertScriptRaise(\"rlnorm(2, 10.0, c(0.1, 10, 1));\", 0, \"requires sdlog to be\");\n\tEidosAssertScriptSuccess(\"rlnorm(1, NAN, 100);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rlnorm(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rmultinom()\n\tEidosAssertScriptRaise(\"rmultinom(0, 10, c(0.1, 1.0, 10.0));\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, -1, c(0.1, 1.0, 10.0));\", 0, \"requires size to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, 10, float(0));\", 0, \"requires prob to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, 10, c(-0.1, 1.0, 10.0));\", 0, \"requires all probabilities in prob to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, 10, c(INF, 1.0, 10.0));\", 0, \"requires all probabilities in prob to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, 10, c(NAN, 1.0, 10.0));\", 0, \"requires all probabilities in prob to be\");\n\tEidosAssertScriptRaise(\"rmultinom(5, 10, c(0.0, 0.0, 0.0));\", 0, \"requires the sum of prob\");\n\tEidosAssertScriptSuccess_L(\"x = rmultinom(5, 10, c(0.1)); identical(x, matrix(rep(10, 5*1), ncol=5));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rmultinom(5, 0, c(0.1, 1.0, 10.0)); identical(x, matrix(rep(0, 5*3), ncol=5));\", true);\n\t\n\t// rmvnorm()\n\tEidosAssertScriptRaise(\"rmvnorm(0, c(0,2), matrix(c(10,3), nrow=2));\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, matrix(c(0,0)), matrix(c(10,3,3,2), nrow=2));\", 0, \"plain vector of length k\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, c(0,0), c(10,3,3,2));\", 0, \"sigma to be a matrix\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, 0, matrix(c(10,3,3,2), nrow=2));\", 0, \"k must be >= 2\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, c(0,2), matrix(c(10,3), nrow=2));\", 0, \"sigma to be a k x k matrix\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, c(0,2), matrix(c(10,3,3,2), nrow=1)); NULL;\", 0, \"sigma to be a k x k matrix\");\n\tEidosAssertScriptRaise(\"rmvnorm(5, c(0,2), matrix(c(0,0,0,0), nrow=2));\", 0, \"positive-definite\");\n\tEidosAssertScriptSuccess_L(\"x = rmvnorm(5, c(0,2), matrix(c(10,3,3,2), nrow=2)); identical(dim(x), c(5,2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = rmvnorm(5, c(0,NAN), matrix(c(10,3,3,2), nrow=2)); all(!isNAN(x[,0])) & all(isNAN(x[,1]));\", true);\n\tEidosAssertScriptRaise(\"rmvnorm(5, c(0,2), matrix(c(10,3,NAN,2), nrow=2));\", 0, \"to contain NANs\");\n\t\n\t// rnbinom()\n\tEidosAssertScriptSuccess(\"rnbinom(0, 10, 0.5);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"rnbinom(1, 10, 1.0);\", {0});\n\tEidosAssertScriptSuccess_IV(\"rnbinom(1, 10.0, 1.0);\", {0});\n\tEidosAssertScriptSuccess_IV(\"rnbinom(3, 10, 1.0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"rnbinom(3, 10.0, 1.0);\", {0, 0, 0});\n\tEidosAssertScriptRaise(\"rnbinom(3, 0, 0.0);\", 0, \"probability in (0.0, 1.0]\");\n\tEidosAssertScriptSuccess_IV(\"rnbinom(3, 0, 1.0);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rnbinom(10, 1, 0.5);\", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rnbinom(10, 1, 0.5000001);\", {0, 0, 0, 0, 0, 0, 0, 0, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rnbinom(5, 10, 0.5);\", {9, 6, 4, 8, 8});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rnbinom(5, 10, 0.5);\", {15, 12, 6, 9, 2});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rnbinom(5, 1000, 0.01);\", {95823, 100000, 100280, 104485, 99476});\n\tEidosAssertScriptSuccess_IV(\"setSeed(3); rnbinom(5, 1000, 0.99);\", {10, 7, 18, 2, 8});\n\tEidosAssertScriptSuccess_IV(\"setSeed(4); rnbinom(3, 100, c(0.1, 0.5, 0.9));\", {933, 75, 13});\n\tEidosAssertScriptSuccess_IV(\"setSeed(5); rnbinom(3, c(10, 30, 50), 0.5);\", {5, 34, 50});\n\tEidosAssertScriptRaise(\"rnbinom(-1, 10, 0.5);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rnbinom(3, -1, 0.5);\", 0, \"requires size >= 0\");\n\tEidosAssertScriptRaise(\"rnbinom(3, 10, -0.1);\", 0, \"in (0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rnbinom(3, 10, 1.1);\", 0, \"in (0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rnbinom(3, 10, c(0.1, 0.2));\", 0, \"to be of length 1 or n\");\n\tEidosAssertScriptRaise(\"rnbinom(3, c(10, 12), 0.5);\", 0, \"to be of length 1 or n\");\n\tEidosAssertScriptRaise(\"rnbinom(2, -1, c(0.5,0.5));\", 0, \"requires size >= 0\");\n\tEidosAssertScriptRaise(\"rnbinom(2, c(10,10), -0.1);\", 0, \"in (0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rnbinom(2, 10, NAN);\", 0, \"in (0.0, 1.0]\");\n\tEidosAssertScriptRaise(\"rnbinom(2, NAN, 0.5);\", 0, \"requires size >= 0\");\n\t\n\t// rnorm()\n\tEidosAssertScriptSuccess(\"rnorm(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rnorm(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"rnorm(1, 0, 0);\", {0.0});\n\tEidosAssertScriptSuccess_FV(\"rnorm(3, 0, 0);\", {0.0, 0.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"rnorm(1, 1, 0);\", {1.0});\n\tEidosAssertScriptSuccess_FV(\"rnorm(3, 1, 0);\", {1.0, 1.0, 1.0});\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rnorm(2) - c(-0.895053, -0.315753)) < 0.000001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(1); abs(rnorm(2, 10.0) - c(7.6679, 9.5468)) < 0.01;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(2); abs(rnorm(2, 10.0, 100.0) - c(-74.4017, -107.421)) < 0.01;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(3); abs(rnorm(2, c(-10, 10), 100.0) - c(142.441, 121.46)) < 0.01;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(4); abs(rnorm(2, 10.0, c(0.1, 10)) - c(10.0681, 12.2818)) < 0.01;\", {true, true});\n\tEidosAssertScriptRaise(\"rnorm(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rnorm(1, 0, -1);\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rnorm(2, c(0,0), -1);\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rnorm(2, 0, c(-1, -1));\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rnorm(2, c(0,0), c(-1, -1));\", 0, \"requires sd >= 0.0\");\n\tEidosAssertScriptRaise(\"rnorm(2, c(-10, 10, 1), 100.0);\", 0, \"requires mean to be\");\n\tEidosAssertScriptRaise(\"rnorm(2, 10.0, c(0.1, 10, 1));\", 0, \"requires sd to be\");\n\tEidosAssertScriptSuccess(\"rnorm(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rnorm(1, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rpois()\n\tEidosAssertScriptSuccess(\"rpois(0, 1.0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rpois(10, 1.0);\", {0, 0, 0, 0, 0, 0, 1, 1, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rpois(5, 0.2);\", {0, 0, 1, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rpois(5, 10000);\", {9854, 10025, 9953, 10049, 9917});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rpois(1, 10000);\", {9854});\n\tEidosAssertScriptSuccess_IV(\"setSeed(3); rpois(5, c(1, 10, 100, 1000, 10000));\", {0, 8, 109, 1014, 10020});\n\tEidosAssertScriptRaise(\"rpois(-1, 1.0);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rpois(0, 0.0);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rpois(0, NAN);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rpois(2, c(0.0, 0.0));\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rpois(2, c(1.5, NAN));\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"setSeed(4); rpois(5, c(1, 10, 100, 1000));\", 12, \"requires lambda\");\n\t\n\t// runif()\n\tEidosAssertScriptSuccess(\"runif(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"runif(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_FV(\"runif(1, 0, 0);\", {0.0});\n\tEidosAssertScriptSuccess_FV(\"runif(3, 0, 0);\", {0.0, 0.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"runif(1, 1, 1);\", {1.0});\n\tEidosAssertScriptSuccess_FV(\"runif(3, 1, 1);\", {1.0, 1.0, 1.0});\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(runif(1) - c(0.052712)) < 0.000001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(runif(2) - c(0.052712, 0.170896)) < 0.000001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(1); abs(runif(2, 0.5) - c(0.735314, 0.73339)) < 0.0001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(2); abs(runif(2, 10.0, 100.0) - c(32.5498, 34.2239)) < 0.0001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(3); abs(runif(2, c(-100, 1), 10.0) - c(-66.3109, 1.1399)) < 0.0001;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"setSeed(4); abs(runif(2, -10.0, c(1, 1000)) - c(-9.03193, 951.221)) < 0.001;\", {true, true});\n\tEidosAssertScriptRaise(\"runif(-1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"runif(1, 0, -1);\", 0, \"requires min < max\");\n\tEidosAssertScriptRaise(\"runif(2, 0, c(7,-1));\", 0, \"requires min < max\");\n\tEidosAssertScriptRaise(\"runif(2, c(-10, 10, 1), 100.0);\", 0, \"requires min\");\n\tEidosAssertScriptRaise(\"runif(2, -10.0, c(0.1, 10, 1));\", 0, \"requires max\");\n\tEidosAssertScriptSuccess(\"runif(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"runif(1, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rweibull()\n\tEidosAssertScriptSuccess(\"rweibull(0, 1, 1);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rweibull(0, float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"setSeed(0); abs(rweibull(1, 1, 1) - c(2.94291)) < 0.0001;\", true);\n\tEidosAssertScriptSuccess_LV(\"setSeed(0); abs(rweibull(3, 1, 1) - c(2.94291, 1.7667, 1.31281)) < 0.0001;\", {true, true, true});\n\tEidosAssertScriptRaise(\"rweibull(1, 0, 1);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rweibull(1, 1, 0);\", 0, \"requires k > 0.0\");\n\tEidosAssertScriptRaise(\"rweibull(3, c(1,1,0), 1);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rweibull(3, 1, c(1,1,0));\", 0, \"requires k > 0.0\");\n\tEidosAssertScriptRaise(\"rweibull(-1, 1, 1);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rweibull(2, c(10, 0, 1), 100.0);\", 0, \"requires lambda to be\");\n\tEidosAssertScriptRaise(\"rweibull(2, 10.0, c(0.1, 0, 1));\", 0, \"requires k to be\");\n\tEidosAssertScriptSuccess(\"rweibull(1, 1, NAN);\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess(\"rweibull(1, NAN, 1);\", gStaticEidosValue_FloatNAN);\n\t\n\t// rztpois()\n\tEidosAssertScriptSuccess(\"rztpois(0, 1.0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); rztpois(10, 1.0);\", {1, 1, 1, 1, 1, 1, 2, 1, 2, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(1); rztpois(5, 0.2);\", {1, 1, 1, 1, 2});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rztpois(5, 10000);\", {9854, 10025, 9953, 10049, 9917});\n\tEidosAssertScriptSuccess_IV(\"setSeed(2); rztpois(1, 10000);\", {9854});\n\tEidosAssertScriptSuccess_IV(\"setSeed(3); rztpois(5, c(1, 10, 100, 1000, 10000));\", {1, 4, 103, 1011, 10091});\n\tEidosAssertScriptRaise(\"rztpois(-1, 1.0);\", 0, \"requires n to be\");\n\tEidosAssertScriptRaise(\"rztpois(0, 0.0);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rztpois(0, NAN);\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rztpois(2, c(0.0, 0.0));\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"rztpois(2, c(1.5, NAN));\", 0, \"requires lambda > 0.0\");\n\tEidosAssertScriptRaise(\"setSeed(4); rztpois(5, c(1, 10, 100, 1000));\", 12, \"requires lambda\");\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_functions_vector.cpp",
    "content": "//\n//  eidos_test_functions_vector.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n#include \"eidos_class_TestElement.h\"\n\n#include <limits>\n#include <regex>\n\n\n#pragma mark vector construction\nvoid _RunFunctionVectorConstructionTests_a_through_r(void)\n{\n\t// c()\n\tEidosAssertScriptSuccess_NULL(\"c();\");\n\tEidosAssertScriptSuccess_NULL(\"c(NULL);\");\n\tEidosAssertScriptSuccess_L(\"c(T);\", true);\n\tEidosAssertScriptSuccess_I(\"c(3);\", 3);\n\tEidosAssertScriptSuccess_F(\"c(3.1);\", 3.1);\n\tEidosAssertScriptSuccess_S(\"c('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"c(_Test(7))._yolk;\", 7);\n\tEidosAssertScriptSuccess_NULL(\"c(NULL, NULL);\");\n\tEidosAssertScriptSuccess_LV(\"c(T, F, T, T, T, F);\", {true, false, true, true, true, false});\n\tEidosAssertScriptSuccess_IV(\"c(3, 7, 19, -5, 9);\", {3, 7, 19, -5, 9});\n\tEidosAssertScriptSuccess_FV(\"c(3.3, 7.7, 19.1, -5.8, 9.0);\", {3.3, 7.7, 19.1, -5.8, 9.0});\n\tEidosAssertScriptSuccess_SV(\"c('foo', 'bar', 'baz');\", {\"foo\", \"bar\", \"baz\"});\n\tEidosAssertScriptSuccess_IV(\"c(_Test(7), _Test(3), _Test(-9))._yolk;\", {7, 3, -9});\n\tEidosAssertScriptSuccess_LV(\"c(T, c(T, F, F), T, F);\", {true, true, false, false, true, false});\n\tEidosAssertScriptSuccess_IV(\"c(3, 7, c(17, -2), -5, 9);\", {3, 7, 17, -2, -5, 9});\n\tEidosAssertScriptSuccess_FV(\"c(3.3, 7.7, c(17.1, -2.9), -5.8, 9.0);\", {3.3, 7.7, 17.1, -2.9, -5.8, 9.0});\n\tEidosAssertScriptSuccess_SV(\"c('foo', c('bar', 'bar2', 'bar3'), 'baz');\", {\"foo\", \"bar\", \"bar2\", \"bar3\", \"baz\"});\n\tEidosAssertScriptSuccess_IV(\"c(T, 3, c(F, T), 7);\", {1, 3, 0, 1, 7});\n\tEidosAssertScriptSuccess_FV(\"c(T, 3, c(F, T), 7.1);\", {1, 3, 0, 1, 7.1});\n\tEidosAssertScriptSuccess_SV(\"c(T, c(3, 6), 'bar', 7.1);\", {\"T\", \"3\", \"6\", \"bar\", \"7.1\"});\n\tEidosAssertScriptSuccess_L(\"c(T, NULL);\", true);\n\tEidosAssertScriptSuccess_I(\"c(3, NULL);\", 3);\n\tEidosAssertScriptSuccess_F(\"c(3.1, NULL);\", 3.1);\n\tEidosAssertScriptSuccess_S(\"c('foo', NULL);\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"c(_Test(7), NULL)._yolk;\", 7);\n\tEidosAssertScriptSuccess_L(\"c(NULL, T);\", true);\n\tEidosAssertScriptSuccess_I(\"c(NULL, 3);\", 3);\n\tEidosAssertScriptSuccess_F(\"c(NULL, 3.1);\", 3.1);\n\tEidosAssertScriptSuccess_S(\"c(NULL, 'foo');\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"c(NULL, _Test(7))._yolk;\", 7);\n\tEidosAssertScriptRaise(\"c(T, _Test(7));\", 0, \"cannot be mixed\");\n\tEidosAssertScriptRaise(\"c(3, _Test(7));\", 0, \"cannot be mixed\");\n\tEidosAssertScriptRaise(\"c(3.1, _Test(7));\", 0, \"cannot be mixed\");\n\tEidosAssertScriptRaise(\"c('foo', _Test(7));\", 0, \"cannot be mixed\");\n\tEidosAssertScriptSuccess_I(\"c(object(), _Test(7))._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"c(_Test(7), object())._yolk;\", 7);\n\tEidosAssertScriptSuccess(\"c(object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\t//EidosAssertScriptSuccess(\"c(object(), object());\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosTestElement_Class)));\t\t// should fail\n\tEidosAssertScriptSuccess(\"c(object(), _Test(7)[F]);\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosTestElement_Class)));\n\tEidosAssertScriptSuccess(\"c(_Test(7)[F], object());\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosTestElement_Class)));\n\t\n\t// float()\n\tEidosAssertScriptSuccess(\"float(0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"float(1);\", gStaticEidosValue_Float0);\n\tEidosAssertScriptSuccess_FV(\"float(2);\", {0.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"float(5);\", {0.0, 0.0, 0.0, 0.0, 0.0});\n\tEidosAssertScriptRaise(\"float(-1);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"float(-10000);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"float(NULL);\", 0, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"float(integer(0));\", 0, \"must be a singleton\");\n\t\n\t// integer()\n\tEidosAssertScriptSuccess(\"integer(0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"integer(1);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_IV(\"integer(2);\", {0, 0});\n\tEidosAssertScriptSuccess_IV(\"integer(5);\", {0, 0, 0, 0, 0});\n\tEidosAssertScriptRaise(\"integer(-1);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"integer(-10000);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"integer(NULL);\", 0, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"integer(integer(0));\", 0, \"must be a singleton\");\n\t\n\tEidosAssertScriptSuccess_IV(\"integer(10, 0, 1, 3);\", {0, 0, 0, 1, 0, 0, 0, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 1, 0, 3);\", {1, 1, 1, 0, 1, 1, 1, 1, 1, 1});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 8, -3, 3);\", {8, 8, 8, -3, 8, 8, 8, 8, 8, 8});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 0, 1, c(3, 7, 1));\", {0, 1, 0, 1, 0, 0, 0, 1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 1, 0, c(3, 7, 1));\", {1, 0, 1, 0, 1, 1, 1, 0, 1, 1});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 8, -3, c(3, 7, 1));\", {8, -3, 8, -3, 8, 8, 8, -3, 8, 8});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 8, -3, integer(0));\", {8, 8, 8, 8, 8, 8, 8, 8, 8, 8});\n\tEidosAssertScriptSuccess_IV(\"integer(10, 8);\", {8, 8, 8, 8, 8, 8, 8, 8, 8, 8});\n\tEidosAssertScriptRaise(\"integer(10, 0, 1, -7);\", 0, \"requires positions in fill2Indices to be\");\n\tEidosAssertScriptRaise(\"integer(10, 0, 1, c(1, 2, -7, 9));\", 0, \"requires positions in fill2Indices to be\");\n\t\n\t// logical()\n\tEidosAssertScriptSuccess(\"logical(0);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"logical(1);\", false);\n\tEidosAssertScriptSuccess_LV(\"logical(2);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"logical(5);\", {false, false, false, false, false});\n\tEidosAssertScriptRaise(\"logical(-1);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"logical(-10000);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"logical(NULL);\", 0, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"logical(integer(0));\", 0, \"must be a singleton\");\n\t\n\t// object()\n\tEidosAssertScriptSuccess(\"object();\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptRaise(\"object(NULL);\", 0, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"object(integer(0));\", 0, \"too many arguments supplied\");\n\t\n\t// rep()\n\tEidosAssertScriptRaise(\"rep(NULL, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"rep(T, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"rep(3, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"rep(3.5, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"rep('foo', -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"rep(_Test(7), -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptSuccess_NULL(\"rep(NULL, 0);\");\n\tEidosAssertScriptSuccess(\"rep(T, 0);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(3, 0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(3.5, 0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep('foo', 0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(_Test(7), 0);\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosTestElement_Class)));\n\tEidosAssertScriptSuccess_NULL(\"rep(NULL, 2);\");\n\tEidosAssertScriptSuccess_LV(\"rep(T, 2);\", {true, true});\n\tEidosAssertScriptSuccess_IV(\"rep(3, 2);\", {3, 3});\n\tEidosAssertScriptSuccess_FV(\"rep(3.5, 2);\", {3.5, 3.5});\n\tEidosAssertScriptSuccess_SV(\"rep('foo', 2);\", {\"foo\", \"foo\"});\n\tEidosAssertScriptSuccess_IV(\"rep(_Test(7), 2)._yolk;\", {7, 7});\n\tEidosAssertScriptSuccess_LV(\"rep(c(T, F), 2);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_IV(\"rep(c(3, 7), 2);\", {3, 7, 3, 7});\n\tEidosAssertScriptSuccess_FV(\"rep(c(3.5, 9.1), 2);\", {3.5, 9.1, 3.5, 9.1});\n\tEidosAssertScriptSuccess_SV(\"rep(c('foo', 'bar'), 2);\", {\"foo\", \"bar\", \"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_IV(\"rep(c(_Test(7), _Test(2)), 2)._yolk;\", {7, 2, 7, 2});\n\tEidosAssertScriptSuccess(\"rep(logical(0), 5);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(integer(0), 5);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(float(0), 5);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(string(0), 5);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"rep(object(), 5);\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptRaise(\"rep(object(), c(5, 3));\", 0, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"rep(object(), integer(0));\", 0, \"must be a singleton\");\n\t\n\t// repEach()\n\tEidosAssertScriptRaise(\"repEach(NULL, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"repEach(T, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"repEach(3, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"repEach(3.5, -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"repEach('foo', -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptRaise(\"repEach(_Test(7), -1);\", 0, \"count to be greater than or equal to 0\");\n\tEidosAssertScriptSuccess_NULL(\"repEach(NULL, 0);\");\n\tEidosAssertScriptSuccess(\"repEach(T, 0);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(3, 0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(3.5, 0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach('foo', 0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(_Test(7), 0);\", EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(gEidosTestElement_Class)));\n\tEidosAssertScriptSuccess_NULL(\"repEach(NULL, 2);\");\n\tEidosAssertScriptSuccess_LV(\"repEach(T, 2);\", {true, true});\n\tEidosAssertScriptSuccess_IV(\"repEach(3, 2);\", {3, 3});\n\tEidosAssertScriptSuccess_FV(\"repEach(3.5, 2);\", {3.5, 3.5});\n\tEidosAssertScriptSuccess_SV(\"repEach('foo', 2);\", {\"foo\", \"foo\"});\n\tEidosAssertScriptSuccess_IV(\"repEach(_Test(7), 2)._yolk;\", {7, 7});\n\tEidosAssertScriptSuccess_LV(\"repEach(c(T, F), 2);\", {true, true, false, false});\n\tEidosAssertScriptSuccess_IV(\"repEach(c(3, 7), 2);\", {3, 3, 7, 7});\n\tEidosAssertScriptSuccess_FV(\"repEach(c(3.5, 9.1), 2);\", {3.5, 3.5, 9.1, 9.1});\n\tEidosAssertScriptSuccess_SV(\"repEach(c('foo', 'bar'), 2);\", {\"foo\", \"foo\", \"bar\", \"bar\"});\n\tEidosAssertScriptSuccess_IV(\"repEach(c(_Test(7), _Test(2)), 2)._yolk;\", {7, 7, 2, 2});\n\tEidosAssertScriptRaise(\"repEach(NULL, c(2,3));\", 0, \"requires that parameter\");\n\tEidosAssertScriptSuccess_LV(\"repEach(c(T, F), c(2,3));\", {true, true, false, false, false});\n\tEidosAssertScriptSuccess_IV(\"repEach(c(3, 7), c(2,3));\", {3, 3, 7, 7, 7});\n\tEidosAssertScriptSuccess_FV(\"repEach(c(3.5, 9.1), c(2,3));\", {3.5, 3.5, 9.1, 9.1, 9.1});\n\tEidosAssertScriptSuccess_SV(\"repEach(c('foo', 'bar'), c(2,3));\", {\"foo\", \"foo\", \"bar\", \"bar\", \"bar\"});\n\tEidosAssertScriptSuccess_IV(\"repEach(c(_Test(7), _Test(2)), c(2,3))._yolk;\", {7, 7, 2, 2, 2});\n\tEidosAssertScriptRaise(\"repEach(NULL, c(2,-1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c(T, F), c(2,-1));\", 0, \"requires all elements of\");\n\tEidosAssertScriptRaise(\"repEach(c(3, 7), c(2,-1));\", 0, \"requires all elements of\");\n\tEidosAssertScriptRaise(\"repEach(c(3.5, 9.1), c(2,-1));\", 0, \"requires all elements of\");\n\tEidosAssertScriptRaise(\"repEach(c('foo', 'bar'), c(2,-1));\", 0, \"requires all elements of\");\n\tEidosAssertScriptRaise(\"repEach(c(_Test(7), _Test(2)), c(2,-1))._yolk;\", 0, \"requires all elements of\");\n\tEidosAssertScriptRaise(\"repEach(NULL, c(2,3,1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c(T, F), c(2,3,1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c(3, 7), c(2,3,1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c(3.5, 9.1), c(2,3,1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c('foo', 'bar'), c(2,3,1));\", 0, \"requires that parameter\");\n\tEidosAssertScriptRaise(\"repEach(c(_Test(7), _Test(2)), c(2,3,1))._yolk;\", 0, \"requires that parameter\");\n\tEidosAssertScriptSuccess(\"repEach(logical(0), 5);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(integer(0), 5);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(float(0), 5);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(string(0), 5);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"repEach(object(), 5);\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptRaise(\"repEach(object(), c(5, 3));\", 0, \"requires that parameter\");\n\tEidosAssertScriptSuccess(\"repEach(object(), integer(0));\", gStaticEidosValue_Object_ZeroVec);\n}\n\nvoid _RunFunctionVectorConstructionTests_s_through_z(void)\n{\n\t// sample() – since this function treats parameter x type-agnostically, we'll test integers only (and NULL a little bit)\n\tEidosAssertScriptSuccess_NULL(\"sample(NULL, 0, T);\");\n\tEidosAssertScriptSuccess_NULL(\"sample(NULL, 0, F);\");\n\tEidosAssertScriptRaise(\"sample(NULL, 1, T);\", 0, \"insufficient elements\");\n\tEidosAssertScriptRaise(\"sample(NULL, 1, F);\", 0, \"insufficient elements\");\n\tEidosAssertScriptRaise(\"sample(1:5, -1, T);\", 0, \"requires a sample size\");\n\tEidosAssertScriptRaise(\"sample(1:5, -1, F);\", 0, \"requires a sample size\");\n\tEidosAssertScriptSuccess(\"sample(integer(0), 0, T);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"sample(integer(0), 0, F);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"sample(integer(0), 1, T);\", 0, \"insufficient elements\");\n\tEidosAssertScriptRaise(\"sample(integer(0), 1, F);\", 0, \"insufficient elements\");\n\tEidosAssertScriptSuccess_I(\"sample(5, 1, T);\", 5);\n\tEidosAssertScriptSuccess_I(\"sample(5, 1, F);\", 5);\n\tEidosAssertScriptSuccess_IV(\"sample(5, 2, T);\", {5, 5});\n\tEidosAssertScriptSuccess_IV(\"sample(5, 2, T, 1);\", {5, 5});\n\tEidosAssertScriptRaise(\"sample(5, 2, T, -1);\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(1:5, 2, T, c(1,2,-1,4,5));\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(5, 2, T, 0);\", 0, \"summing to <= 0\");\n\tEidosAssertScriptRaise(\"sample(1:5, 2, T, c(0,0,0,0,0));\", 0, \"summing to <= 0\");\n\tEidosAssertScriptSuccess_IV(\"sample(5, 2, T, 1.0);\", {5, 5});\n\tEidosAssertScriptRaise(\"sample(5, 2, T, -1.0);\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(1:5, 2, T, c(1,2,-1.0,4,5));\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(5, 2, T, 0.0);\", 0, \"summing to <= 0\");\n\tEidosAssertScriptRaise(\"sample(1:5, 2, T, c(0.0,0,0,0,0));\", 0, \"summing to <= 0\");\n\tEidosAssertScriptRaise(\"sample(5, 2, T, NAN);\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(1:5, 2, T, c(1,2,NAN,4,5));\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(5, 2, F);\", 0, \"insufficient elements\");\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, T);\", {1, 5, 2, 1, 3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, F);\", {2, 3, 5, 4, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 6, T);\", {1, 5, 2, 1, 3, 3});\n\tEidosAssertScriptRaise(\"setSeed(0); sample(1:5, 6, F);\", 12, \"insufficient elements\");\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, (1:5)*(1:5)*(1:5));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, (1.0:5.0)^3);\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, F, (1:5)*(1:5)*(1:5));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, F, (1.0:5.0)^3);\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, (0:4)*(0:4)*(0:4));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, (0.0:4.0)^3);\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, c(0,0,1,0,0));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, T, c(0,0,1.0,0,0));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, F, c(0,0,1,0,0));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 1, F, c(0,0,1.0,0,0));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 1, T, c(1,0,100,0,0)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 1, T, c(1.0,0,100.0,0,0)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 1, F, c(1,0,100,0,0)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 1, F, c(1.0,0,100.0,0,0)));\", {3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 2, T, c(1,0,100,0,0)));\", {6});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 2, T, c(1.0,0,100.0,0,0)));\", {6});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 2, F, c(1,0,100,0,0)));\", {4});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 2, F, c(1.0,0,100.0,0,0)));\", {4});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 100, T, c(1,0,100,0,0)));\", {292});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sum(sample(1:5, 100, T, c(1.0,0,100.0,0,0)));\", {292});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, T, (1:5)*(1:5)*(1:5));\", {3, 4, 4, 4, 3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, T, (1.0:5.0)^3);\", {3, 4, 4, 4, 3});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, F, (1:5)*(1:5)*(1:5));\", {3, 4, 5, 2, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, F, (1.0:5.0)^3);\", {3, 4, 5, 2, 1});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, T, (0:4)*(0:4)*(0:4));\", {3, 4, 4, 4, 4});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); sample(1:5, 5, T, (0.0:4.0)^3);\", {3, 4, 4, 4, 4});\n\tEidosAssertScriptSuccess_IV(\"setSeed(0); tabulate(sample(1:5, 10000, T, (0:4)*(0:4)*(0:4)));\", {0, 0, 93, 820, 2714, 6373});\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:3, 3, F, c(2.0, 3.0, NAN));\", 12, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:5, 5, F, (0:4)^3);\", 12, \"weights summing to\");\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:5, 5, F, asInteger((0:4)^3));\", 12, \"weights summing to\");\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:5, 5, T, -1:3);\", 12, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:5, 5, T, 1:6);\", 12, \"to be the same length\");\n\tEidosAssertScriptRaise(\"setSeed(1); sample(1:5, 5, T, 1);\", 12, \"to be the same length\");\n\t\n\tEidosAssertScriptSuccess_L(\"sample(1:1000, 10, replace=T, weights=runif(1000)); T;\", true);\t\t\t\t// code path only\n\tEidosAssertScriptSuccess_L(\"sample(1:1000, 10, replace=T, weights=rdunif(1000, 0, 1000)); T;\", true);\t// code path only\n\tEidosAssertScriptSuccess_L(\"sample(1.0:1000, 10, replace=T, weights=runif(1000)); T;\", true);\t\t\t// code path only\n\tEidosAssertScriptSuccess_L(\"sample(1.0:1000, 10, replace=T, weights=rdunif(1000, 0, 1000)); T;\", true);\t// code path only\n\tEidosAssertScriptSuccess_L(\"sample(((1:1000) % 2) == 1, 10, replace=T, weights=runif(1000)); T;\", true);\t// code path only\n\tEidosAssertScriptSuccess_L(\"sample(((1:1000) % 2) == 1, 10, replace=T, weights=rdunif(1000, 0, 1000)); T;\", true);\t// code path only\n\tEidosAssertScriptRaise(\"sample(1:1000, 10, replace=T, weights=c(runif(999), -1));\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(1:1000, 10, replace=T, weights=c(rdunif(999, 0, 1000), -1));\", 0, \"requires all weights to be\");\n\tEidosAssertScriptRaise(\"sample(1:1000, 10, replace=T, weights=rep(0, 1000));\", 0, \"weights summing to\");\n\tEidosAssertScriptRaise(\"sample(1:1000, 10, replace=T, weights=rep(0.0, 1000));\", 0, \"weights summing to\");\n\t\n\tEidosAssertScriptSuccess_I(\"sum(sample(((0:100) % 2) == 1, 101, replace=F));\", 50);\n\tEidosAssertScriptSuccess_I(\"sum(sample(((0:100) % 2) == 0, 101, replace=F));\", 51);\n\tEidosAssertScriptSuccess_I(\"sum(sample(0:100, 101, replace=F));\", 5050);\n\tEidosAssertScriptSuccess_F(\"sum(sample(0.0:100, 101, replace=F));\", 5050);\n\t\n\t// seq()\n\tEidosAssertScriptSuccess_IV(\"seq(1, 5);\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"seq(5, 1);\", {5, 4, 3, 2, 1});\n\tEidosAssertScriptRaise(\"seq(5, 1, 0);\", 0, \"requires by != 0\");\n\tEidosAssertScriptSuccess_FV(\"seq(1.1, 5);\", {1.1, 2.1, 3.1, 4.1});\n\tEidosAssertScriptSuccess_FV(\"seq(1, 5.1);\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_FV(\"seq(5.5, 1);\", {5.5, 4.5, 3.5, 2.5, 1.5});\n\tEidosAssertScriptRaise(\"seq(5.1, 1, 0);\", 0, \"requires by != 0\");\n\tEidosAssertScriptSuccess_IV(\"seq(1, 10, 2);\", {1, 3, 5, 7, 9});\n\tEidosAssertScriptRaise(\"seq(1, 10, -2);\", 0, \"has incorrect sign\");\n\tEidosAssertScriptSuccess_IV(\"seq(10, 1, -2);\", {10, 8, 6, 4, 2});\n\tEidosAssertScriptSuccess_LV(\"(seq(1, 2, 0.2) - c(1, 1.2, 1.4, 1.6, 1.8, 2.0)) < 0.000000001;\", {true, true, true, true, true, true});\n\tEidosAssertScriptRaise(\"seq(1, 2, -0.2);\", 0, \"has incorrect sign\");\n\tEidosAssertScriptSuccess_LV(\"(seq(2, 1, -0.2) - c(2.0, 1.8, 1.6, 1.4, 1.2, 1)) < 0.000000001;\", {true, true, true, true, true, true});\n\tEidosAssertScriptRaise(\"seq('foo', 2, 1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(1, 'foo', 2);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(2, 1, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(T, 2, 1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(1, T, 2);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(2, 1, T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(NULL, 2, 1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"seq(1, NULL, 2);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_IV(\"seq(2, 1, NULL);\", {2, 1}); // NULL uses the default by\n\t\n\tEidosAssertScriptRaise(\"seq(2, 3, 1, 2);\", 0, \"may be supplied with either\");\n\tEidosAssertScriptRaise(\"seq(2, 3, by=1, length=2);\", 0, \"may be supplied with either\");\n\tEidosAssertScriptRaise(\"seq(2, 3, length=-2);\", 0, \"must be > 0\");\n\tEidosAssertScriptRaise(\"seq(2, 3, length=0);\", 0, \"must be > 0\");\n\tEidosAssertScriptSuccess_I(\"seq(2, 3, length=1);\", 2);\n\tEidosAssertScriptSuccess_IV(\"seq(2, 3, length=2);\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"seq(2, 2, length=5);\", {2, 2, 2, 2, 2});\n\tEidosAssertScriptSuccess_IV(\"seq(2, 10, length=5);\", {2, 4, 6, 8, 10});\n\tEidosAssertScriptSuccess_FV(\"seq(2, 4, length=5);\", {2.0, 2.5, 3.0, 3.5, 4.0});\n\tEidosAssertScriptSuccess_IV(\"seq(3, 2, length=2);\", {3, 2});\n\tEidosAssertScriptSuccess_IV(\"seq(10, 2, length=5);\", {10, 8, 6, 4, 2});\n\tEidosAssertScriptSuccess_FV(\"seq(4, 2, length=5);\", {4.0, 3.5, 3.0, 2.5, 2.0});\n\t\n\tEidosAssertScriptRaise(\"seq(2., 3, 1, 2);\", 0, \"may be supplied with either\");\n\tEidosAssertScriptRaise(\"seq(2., 3, by=1, length=2);\", 0, \"may be supplied with either\");\n\tEidosAssertScriptRaise(\"seq(2., 3, length=-2);\", 0, \"must be > 0\");\n\tEidosAssertScriptRaise(\"seq(2., 3, length=0);\", 0, \"must be > 0\");\n\tEidosAssertScriptSuccess_F(\"seq(2., 3, length=1);\", 2);\n\tEidosAssertScriptSuccess_FV(\"seq(2., 3, length=2);\", {2, 3});\n\tEidosAssertScriptSuccess_FV(\"seq(2., 2, length=5);\", {2, 2, 2, 2, 2});\n\tEidosAssertScriptSuccess_FV(\"seq(2., 10, length=5);\", {2, 4, 6, 8, 10});\n\tEidosAssertScriptSuccess_FV(\"seq(2., 4, length=5);\", {2.0, 2.5, 3.0, 3.5, 4.0});\n\tEidosAssertScriptSuccess_FV(\"seq(3., 2, length=2);\", {3, 2});\n\tEidosAssertScriptSuccess_FV(\"seq(10., 2, length=5);\", {10, 8, 6, 4, 2});\n\tEidosAssertScriptSuccess_FV(\"seq(4., 2, length=5);\", {4.0, 3.5, 3.0, 2.5, 2.0});\n\t\n\tEidosAssertScriptRaise(\"seq(NAN, 3.0, by=1.0);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(NAN, 3.0, length=2);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(2.0, NAN, by=1.0);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(2.0, NAN, length=2);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(2, 3, by=NAN);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(2.0, 3.0, by=NAN);\", 0, \"requires a finite value\");\n\tEidosAssertScriptRaise(\"seq(2.0, 3.0, length=10000001);\", 0, \"more than 10000000 entries\");\n\t\n\t// seqAlong()\n\tEidosAssertScriptSuccess(\"seqAlong(NULL);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"seqAlong(logical(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"seqAlong(object());\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"seqAlong(5);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"seqAlong(5.1);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"seqAlong('foo');\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_IV(\"seqAlong(5:9);\", {0, 1, 2, 3, 4});\n\tEidosAssertScriptSuccess_IV(\"seqAlong(5.1:9.5);\", {0, 1, 2, 3, 4});\n\tEidosAssertScriptSuccess_IV(\"seqAlong(c('foo', 'bar', 'baz'));\", {0, 1, 2});\n\tEidosAssertScriptSuccess_IV(\"seqAlong(matrix(5));\", {0});\n\tEidosAssertScriptSuccess_IV(\"seqAlong(matrix(5:9));\", {0, 1, 2, 3, 4});\n\t\n\t// seqLen()\n\tEidosAssertScriptSuccess_IV(\"seqLen(5);\", {0, 1, 2, 3, 4});\n\tEidosAssertScriptSuccess_I(\"seqLen(1);\", 0);\n\tEidosAssertScriptSuccess(\"seqLen(0);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"seqLen(-1);\", 0, \"requires length to be\");\n\tEidosAssertScriptRaise(\"seqLen(5:6);\", 0, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"seqLen('f');\", 0, \"cannot be type\");\n\t\n\t// string()\n\tEidosAssertScriptSuccess(\"string(0);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"string(1);\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_SV(\"string(2);\", {\"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"string(5);\", {\"\", \"\", \"\", \"\", \"\"});\n\tEidosAssertScriptRaise(\"string(-1);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"string(-10000);\", 0, \"to be greater than or equal to\");\n\tEidosAssertScriptRaise(\"string(NULL);\", 0, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"string(integer(0));\", 0, \"must be a singleton\");\n}\n\n#pragma mark value inspection / manipulation\nvoid _RunFunctionValueInspectionManipulationTests_a_through_f(void)\n{\n\t// all()\n\tEidosAssertScriptRaise(\"all(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"all(0);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"all(0.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"all('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"all(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_L(\"all(logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"all(T);\", true);\n\tEidosAssertScriptSuccess_L(\"all(F);\", false);\n\tEidosAssertScriptSuccess_L(\"all(c(T,T,T,T,T,T,T,T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"all(c(T,T,T,T,T,T,T,F,T,T));\", false);\n\tEidosAssertScriptSuccess_L(\"all(c(F,F,F,F,F,F,F,F,F,F));\", false);\n\t\n\tEidosAssertScriptRaise(\"all(T, NULL);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"all(T, 0);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"all(T, 0.5);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"all(T, 'foo');\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"all(T, _Test(7));\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptSuccess_L(\"all(T, logical(0));\", true);\n\tEidosAssertScriptSuccess_L(\"all(T, T);\", true);\n\tEidosAssertScriptSuccess_L(\"all(T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"all(T,T,T,T,T,T,T,T,T,T);\", true);\n\tEidosAssertScriptSuccess_L(\"all(T,T,T,T,T,T,T,F,T,T);\", false);\n\tEidosAssertScriptSuccess_L(\"all(F,F,F,F,F,F,F,F,F,F);\", false);\n\tEidosAssertScriptSuccess_L(\"all(T,T,c(T,T,T,T),c(T,T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"all(T,T,c(T,T,T,T),c(T,F,T,T));\", false);\n\tEidosAssertScriptSuccess_L(\"all(F,F,c(F,F,F,F),c(F,F,F,F));\", false);\n\t\n\t// allClose()\n\tEidosAssertScriptRaise(\"allClose(float(0), 1.0:3);\", 0, \"requires the lengths of x and y\");\n\tEidosAssertScriptRaise(\"allClose(1.0:2, 1.0:3);\", 0, \"requires the lengths of x and y\");\n\tEidosAssertScriptRaise(\"allClose(1.0, 1.0, rtol=-1.0);\", 0, \"requires rtol\");\n\tEidosAssertScriptRaise(\"allClose(1.0, 1.0, atol=-1.0);\", 0, \"requires atol\");\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(INF, -INF);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(INF, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(INF, INF);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(INF, c(-INF, 0.0, INF));\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(-INF, 0.0, INF), INF);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(INF, INF, INF), c(-INF, 0.0, INF));\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-INF, INF);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-INF, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-INF, -INF);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(-INF, c(INF, 0.0, -INF));\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(INF, 0.0, -INF), -INF);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(-INF, -INF, -INF), c(INF, 0.0, -INF));\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, 0.0, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, 0.0, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, INF, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, INF, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(0.0, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(0.0, NAN, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(INF, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(INF, NAN, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, NAN, equalNAN=T);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, c(0.0, INF, NAN), equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(NAN, c(0.0, INF, NAN), equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(NAN, NAN, NAN), c(0.0, INF, NAN), equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(NAN, NAN, NAN), c(0.0, INF, NAN), equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(0.0, INF, NAN), NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(0.0, INF, NAN), NAN, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(0.0, INF, NAN), c(NAN, NAN, NAN), equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(0.0, INF, NAN), c(NAN, NAN, NAN), equalNAN=T);\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(1.0, 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(0.0, 0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(-1.0, -1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(1.0, -1.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-1.0, 1.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(1.0, 0.0, -1.0, 1.0, -1.0), c(1.0, 0.0, -1.0, -1.0, 1.0));\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(1.0, 1.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(1.0, 1.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(100.0, 100.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(100.0, 100.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-100.0, -100.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(-100.0, -100.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(c(1.0, 1.0, 100.0, 100.0, -100.0, -100.0), c(1.0 + 0.9e-8, 1.0 + 1.1e-8, 100.0 + 0.9e-8, 100.0 + 1.1e-8, -100.0 + 0.9e-8, -100.0 + 1.1e-8), rtol=0.0);\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(1.0 + 0.9e-5, 1.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(1.0 + 1.1e-5, 1.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(10.0 + 0.9e-4, 10.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(10.0 + 1.1e-4, 10.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(100.0 + 0.9e-3, 100.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(100.0 + 1.1e-3, 100.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"allClose(-100.0 + 0.9e-3, -100.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"allClose(-100.0 + 1.1e-3, -100.0, atol=0.0);\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"allClose(c(INF, -INF, NAN, 1.0, -1.0, 1.0), c(INF, -INF, NAN, 1.0, -1.0, 1.0 + 0.9e-8), equalNAN=T);\", true);\n\t\n\t// any()\n\tEidosAssertScriptRaise(\"any(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"any(0);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"any(0.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"any('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"any(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_L(\"any(logical(0));\", false);\n\tEidosAssertScriptSuccess_L(\"any(T);\", true);\n\tEidosAssertScriptSuccess_L(\"any(F);\", false);\n\tEidosAssertScriptSuccess_L(\"any(c(T,T,T,T,T,T,T,T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"any(c(T,T,T,T,T,T,T,F,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"any(c(F,F,F,F,F,F,F,F,F,F));\", false);\n\t\n\tEidosAssertScriptRaise(\"any(F, NULL);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"any(F, 0);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"any(F, 0.5);\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"any(F, 'foo');\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptRaise(\"any(F, _Test(7));\", 0, \"all arguments be of type logical\");\n\tEidosAssertScriptSuccess_L(\"any(F, logical(0));\", false);\n\tEidosAssertScriptSuccess_L(\"any(F, T);\", true);\n\tEidosAssertScriptSuccess_L(\"any(F, F);\", false);\n\tEidosAssertScriptSuccess_L(\"any(T,T,T,T,T,T,T,T,T,T);\", true);\n\tEidosAssertScriptSuccess_L(\"any(T,T,T,T,T,T,T,F,T,T);\", true);\n\tEidosAssertScriptSuccess_L(\"any(F,F,F,F,F,F,F,F,F,F);\", false);\n\tEidosAssertScriptSuccess_L(\"any(T,T,c(T,T,T,T),c(T,F,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"any(F,F,c(F,F,F,F),c(F,T,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"any(F,F,c(F,F,F,F),c(F,F,F,F));\", false);\n\t\n\t// cat() – can't test the actual output, but we can make sure it executes...\n\tEidosAssertScriptRaise(\"cat();\", 0, \"missing required argument 'x'\");\n\tEidosAssertScriptSuccess_VOID(\"cat(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"cat(T);\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5);\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5.5);\");\n\tEidosAssertScriptSuccess_VOID(\"cat('foo');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(_Test(7));\");\n\tEidosAssertScriptSuccess_VOID(\"cat(NULL, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(T, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5.5, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat('foo', '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(_Test(7), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(c(T,T,F,T), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5:9, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(5.5:8.9, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(c('foo', 'bar', 'baz'), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"cat(c(_Test(7), _Test(7), _Test(7)), '$$');\");\n\t\n\t// catn() – can't test the actual output, but we can make sure it executes...\n\tEidosAssertScriptSuccess_VOID(\"catn();\");\n\tEidosAssertScriptSuccess_VOID(\"catn(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"catn(T);\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5);\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5.5);\");\n\tEidosAssertScriptSuccess_VOID(\"catn('foo');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(_Test(7));\");\n\tEidosAssertScriptSuccess_VOID(\"catn(NULL, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(T, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5.5, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn('foo', '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(_Test(7), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(c(T,T,F,T), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5:9, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(5.5:8.9, '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(c('foo', 'bar', 'baz'), '$$');\");\n\tEidosAssertScriptSuccess_VOID(\"catn(c(_Test(7), _Test(7), _Test(7)), '$$');\");\n\t\n\t// format()\n\tEidosAssertScriptRaise(\"format('%d', NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"format('%d', T);\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_S(\"format('%d', 0);\", \"0\");\n\tEidosAssertScriptSuccess_S(\"format('%f', 0.5);\", \"0.500000\");\n\tEidosAssertScriptRaise(\"format('%d', 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"format('%d', _Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"format('%d', 0.5);\", 0, \"requires an argument of type integer\");\n\tEidosAssertScriptRaise(\"format('%f', 5);\", 0, \"requires an argument of type float\");\n\tEidosAssertScriptSuccess_S(\"format('foo == %d', 0);\", \"foo == 0\");\n\tEidosAssertScriptRaise(\"format('%++d', 8:12);\", 0, \"flag '+' specified\");\n\tEidosAssertScriptRaise(\"format('%--d', 8:12);\", 0, \"flag '-' specified\");\n\tEidosAssertScriptRaise(\"format('%  d', 8:12);\", 0, \"flag ' ' specified\");\n\tEidosAssertScriptRaise(\"format('%00d', 8:12);\", 0, \"flag '0' specified\");\n\tEidosAssertScriptRaise(\"format('%##d', 8:12);\", 0, \"flag '#' specified\");\n\tEidosAssertScriptSuccess_SV(\"format('%d', 8:12);\", {\"8\",\"9\",\"10\",\"11\",\"12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%3d', 8:12);\", {\"  8\",\"  9\",\" 10\",\" 11\",\" 12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%10d', 8:12);\", {\"         8\",\"         9\",\"        10\",\"        11\",\"        12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%-3d', 8:12);\", {\"8  \",\"9  \",\"10 \",\"11 \",\"12 \"});\n\tEidosAssertScriptSuccess_SV(\"format('%- 3d', 8:12);\", {\" 8 \",\" 9 \",\" 10\",\" 11\",\" 12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%+3d', 8:12);\", {\" +8\",\" +9\",\"+10\",\"+11\",\"+12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%+-3d', 8:12);\", {\"+8 \",\"+9 \",\"+10\",\"+11\",\"+12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%+03d', 8:12);\", {\"+08\",\"+09\",\"+10\",\"+11\",\"+12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%i', 8:12);\", {\"8\",\"9\",\"10\",\"11\",\"12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%o', 8:12);\", {\"10\",\"11\",\"12\",\"13\",\"14\"});\n\tEidosAssertScriptSuccess_SV(\"format('%x', 8:12);\", {\"8\",\"9\",\"a\",\"b\",\"c\"});\n\tEidosAssertScriptSuccess_SV(\"format('%X', 8:12);\", {\"8\",\"9\",\"A\",\"B\",\"C\"});\n\tEidosAssertScriptRaise(\"format('%#d', 8:12);\", 0, \"the flag '#' may not be used with\");\n\tEidosAssertScriptRaise(\"format('%n', 8:12);\", 0, \"conversion specifier 'n' not supported\");\n\tEidosAssertScriptRaise(\"format('%', 8:12);\", 0, \"missing conversion specifier after '%'\");\n\tEidosAssertScriptRaise(\"format('%d%d', 8:12);\", 0, \"only one % escape is allowed\");\n\tEidosAssertScriptRaise(\"format('%d%', 8:12);\", 0, \"only one % escape is allowed\");\n\tEidosAssertScriptSuccess_SV(\"format('%%%d%%', 8:12);\", {\"%8%\",\"%9%\",\"%10%\",\"%11%\",\"%12%\"});\n\tEidosAssertScriptSuccess_SV(\"format('%f', 8.0:12);\", {\"8.000000\",\"9.000000\",\"10.000000\",\"11.000000\",\"12.000000\"});\n\tEidosAssertScriptSuccess_SV(\"format('%.2f', 8.0:12);\", {\"8.00\",\"9.00\",\"10.00\",\"11.00\",\"12.00\"});\n\tEidosAssertScriptSuccess_SV(\"format('%8.2f', 8.0:12);\", {\"    8.00\",\"    9.00\",\"   10.00\",\"   11.00\",\"   12.00\"});\n\tEidosAssertScriptSuccess_SV(\"format('%+8.2f', 8.0:12);\", {\"   +8.00\",\"   +9.00\",\"  +10.00\",\"  +11.00\",\"  +12.00\"});\n\tEidosAssertScriptSuccess_SV(\"format('%+08.2f', 8.0:12);\", {\"+0008.00\",\"+0009.00\",\"+0010.00\",\"+0011.00\",\"+0012.00\"});\n\tEidosAssertScriptSuccess_SV(\"format('%-8.2f', 8.0:12);\", {\"8.00    \",\"9.00    \",\"10.00   \",\"11.00   \",\"12.00   \"});\n\tEidosAssertScriptSuccess_SV(\"format('%- 8.2f', 8.0:12);\", {\" 8.00   \",\" 9.00   \",\" 10.00  \",\" 11.00  \",\" 12.00  \"});\n\tEidosAssertScriptSuccess_SV(\"format('%8.2F', 8.0:12);\", {\"    8.00\",\"    9.00\",\"   10.00\",\"   11.00\",\"   12.00\"});\n\tEidosAssertScriptSuccess_SV(\"format('%8.2e', 8.0:12);\", {\"8.00e+00\", \"9.00e+00\", \"1.00e+01\", \"1.10e+01\", \"1.20e+01\"});\n\tEidosAssertScriptSuccess_SV(\"format('%8.2E', 8.0:12);\", {\"8.00E+00\", \"9.00E+00\", \"1.00E+01\", \"1.10E+01\", \"1.20E+01\"});\n\tEidosAssertScriptSuccess_SV(\"format('%8.2g', 8.0:12);\", {\"       8\",\"       9\",\"      10\",\"      11\",\"      12\"});\n\tEidosAssertScriptSuccess_SV(\"format('%#8.2g', 8.0:12);\", {\"     8.0\",\"     9.0\",\"     10.\",\"     11.\",\"     12.\"});\n}\n\nvoid _RunFunctionValueInspectionManipulationTests_g_through_l(void)\n{\n\t// identical()\n\tEidosAssertScriptSuccess_L(\"identical(NULL, NULL);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, 0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, '');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, _Test(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, 0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, '');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, _Test(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, 0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(0, 1);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, '');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0, _Test(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, 0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, 0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, 0.1);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.1, NAN);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NAN, 0.1);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NAN, NAN);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, '');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(0.0, _Test(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', 0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', '');\", true);\n\tEidosAssertScriptSuccess_L(\"identical('', 'x');\", false);\n\tEidosAssertScriptSuccess_L(\"identical('', _Test(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), 0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), '');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(0), _Test(0));\", false);\t// object elements not equal\n\tEidosAssertScriptSuccess_L(\"identical(F, c(F,F));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,F), F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,F), c(F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,T,F,T,T), c(F,T,F,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,T,T,T,T), c(F,T,F,T,T));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(3, c(3,3));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3,3), 3);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3,3), c(3,3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(3,7,3,7,7), c(3,7,3,7,7));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(3,7,7,7,7), c(3,7,3,7,7));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(3.1, c(3.1,3.1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,3.1), 3.1);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,3.1), c(3.1,3.1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,NAN), c(3.1,3.1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,3.1), c(3.1,NAN));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,NAN), c(3.1,NAN));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,7.1,3.1,7.1,7.1), c(3.1,7.1,3.1,7.1,7.1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(3.1,7.1,7.1,7.1,7.1), c(3.1,7.1,3.1,7.1,7.1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical('bar', c('bar','bar'));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c('bar','bar'), 'bar');\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c('bar','bar'), c('bar','bar'));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c('bar','baz','bar','baz','baz'), c('bar','baz','bar','baz','baz'));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c('bar','baz','baz','baz','baz'), c('bar','baz','bar','baz','baz'));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(_Test(3), c(_Test(3),_Test(3)));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(_Test(3),_Test(3)), _Test(3));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(_Test(3),_Test(3)), c(_Test(3),_Test(3)));\", false);\t// object elements not equal\n\tEidosAssertScriptSuccess_L(\"x = c(_Test(3),_Test(3)); y = x; identical(x, y);\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(3); y = _Test(7); identical(c(x, y, x, x), c(x, y, x, x));\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(3); y = _Test(7); identical(c(x, y, x, x), c(x, y, y, x));\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F), matrix(F, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F)), matrix(c(F,T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F)), matrix(c(F,T,F,F), byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), byrow=T), matrix(c(F,T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), byrow=T), matrix(c(F,T,F,F), byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=1), matrix(c(F,T,F,F), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), ncol=1), matrix(c(F,T,F,F), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=2), matrix(c(F,T,F,F), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), ncol=2), matrix(c(F,T,F,F), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), ncol=2), matrix(c(F,T,F,F), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=2), matrix(c(F,T,F,F), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=2, byrow=T), matrix(c(F,T,F,F), nrow=2));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=2), matrix(c(F,T,F,F), nrow=2, byrow=T));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=2, byrow=T), matrix(c(F,T,F,F), nrow=2, byrow=T));\", true);\n \tEidosAssertScriptSuccess_L(\"identical(F, matrix(F));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, matrix(F, byrow=T));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F), F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F, byrow=T), F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,T,F,F), matrix(c(F,T,F,F)));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,T,F,F), matrix(c(F,T,F,F), nrow=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(F,T,F,F), matrix(c(F,T,F,F), ncol=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F)), c(F,T,F,F));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=1), c(F,T,F,F));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), ncol=1), c(F,T,F,F));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), nrow=1), matrix(c(F,T,F,F), ncol=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F,F), ncol=1), matrix(c(F,T,F,F), nrow=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6), matrix(6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6), matrix(6, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6)), matrix(c(6,8,6,6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6)), matrix(c(6,8,6,6), byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), byrow=T), matrix(c(6,8,6,6)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), byrow=T), matrix(c(6,8,6,6), byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=1), matrix(c(6,8,6,6), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), ncol=1), matrix(c(6,8,6,6), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=2), matrix(c(6,8,6,6), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), ncol=2), matrix(c(6,8,6,6), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), ncol=2), matrix(c(6,8,6,6), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=2), matrix(c(6,8,6,6), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=2, byrow=T), matrix(c(6,8,6,6), nrow=2));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=2), matrix(c(6,8,6,6), nrow=2, byrow=T));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=2, byrow=T), matrix(c(6,8,6,6), nrow=2, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6, matrix(6));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(6, matrix(6, byrow=T));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6), 6);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6, byrow=T), 6);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(6,8,6,6), matrix(c(6,8,6,6)));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(6,8,6,6), matrix(c(6,8,6,6), nrow=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(c(6,8,6,6), matrix(c(6,8,6,6), ncol=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6)), c(6,8,6,6));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=1), c(6,8,6,6));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), ncol=1), c(6,8,6,6));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), nrow=1), matrix(c(6,8,6,6), ncol=1));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(6,8,6,6), ncol=1), matrix(c(6,8,6,6), nrow=1));\", false);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(NULL, NULL, NULL);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F, F, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T, T, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5, 5, 5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5.7, 5.7, 5.7);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(NAN, NAN, NAN);\", true);\n\tEidosAssertScriptSuccess_L(\"identical('foo', 'foo', 'foo');\", true);\n\tEidosAssertScriptSuccess_L(\"x = _Test(3); y = _Test(7); identical(x, x, x);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(NULL, NULL, integer(0));\", false);\n\tEidosAssertScriptSuccess_L(\"identical(F, F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(T, T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(5, 5, 6);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(5.7, 5.7, 6.8);\", false);\n\tEidosAssertScriptSuccess_L(\"identical(NAN, NAN, INF);\", false);\n\tEidosAssertScriptSuccess_L(\"identical('foo', 'foo', 'bar');\", false);\n\tEidosAssertScriptSuccess_L(\"x = _Test(3); y = _Test(7); identical(x, x, y);\", false);\n\t\n\t// ifelse()\n\tEidosAssertScriptRaise(\"ifelse(NULL, integer(0), integer(0));\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"ifelse(logical(0), NULL, integer(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"ifelse(logical(0), integer(0), NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), logical(0), logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), integer(0), integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), float(0), float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), string(0), string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), object(), object());\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), T, F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 0, 1);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 0.0, 1.0);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 'foo', 'bar');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), _Test(0), _Test(1))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"ifelse(logical(0), 5:6, 2);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(logical(0), 5, 2:3);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(T, integer(0), integer(0));\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(T, 5, 2:3);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(T, 5:6, 2);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(c(T,T), 5:7, 2);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(c(T,T), 5, 2:4);\", 0, \"trueValues and falseValues each be either\");\n\tEidosAssertScriptRaise(\"ifelse(c(T,T), 5:7, 2:4);\", 0, \"trueValues and falseValues each be either\");\n\t\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), T, F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"ifelse(T, T, F);\", true);\n\tEidosAssertScriptSuccess_L(\"ifelse(F, T, F);\", false);\n\tEidosAssertScriptSuccess_L(\"ifelse(T, F, T);\", false);\n\tEidosAssertScriptSuccess_L(\"ifelse(F, F, T);\", true);\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,T), T, F);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,F), T, F);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,F), F, T);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,T), F, T);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,T), c(T,F), T);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,T), F, c(T,F));\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,F), c(T,F), T);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,F), T, c(T,F));\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,T), c(T,F), c(F,T));\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,F), c(T,F), c(F,T));\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,F), c(T,F), c(F,T));\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(F,T), c(T,F), c(F,T));\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,F,F,T,F,T), rep(T,6), rep(F,6));\", {true, false, false, true, false, true});\n\tEidosAssertScriptSuccess_LV(\"ifelse(c(T,F,F,T,F,T), rep(F,6), rep(T,6));\", {false, true, true, false, true, false});\n\t\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 5, 2);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"ifelse(T, 5, 2);\", 5);\n\tEidosAssertScriptSuccess_I(\"ifelse(F, 5, 2);\", 2);\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), 5, 2);\", {5, 5});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), 5, 2);\", {2, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F), 5, 2);\", {5, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), 5:6, 2);\", {5, 6});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), 5, 2:3);\", {5, 5});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), 5:6, 2);\", {2, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), 5, 2:3);\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), 5:6, 2:3);\", {5, 6});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), 5:6, 2:3);\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F), 5:6, 2:3);\", {5, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F,F,T,F,T), 1:6, -6:-1);\", {1, -5, -4, 4, -2, 6});\n\t\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 5.3, 2.1);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess_F(\"ifelse(T, 5.3, 2.1);\", 5.3);\n\tEidosAssertScriptSuccess_F(\"ifelse(F, 5.3, 2.1);\", 2.1);\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,T), 5.3, 2.1);\", {5.3, 5.3});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(F,F), 5.3, 2.1);\", {2.1, 2.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,F), 5.3, 2.1);\", {5.3, 2.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,T), c(5.3, 6.3), 2.1);\", {5.3, 6.3});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,T), 5.3, c(2.1, 3.1));\", {5.3, 5.3});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(F,F), c(5.3, 6.3), 2.1);\", {2.1, 2.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(F,F), 5.3, c(2.1, 3.1));\", {2.1, 3.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,T), c(5.3, 6.3), c(2.1, 3.1));\", {5.3, 6.3});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(F,F), c(5.3, 6.3), c(2.1, 3.1));\", {2.1, 3.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,F), c(5.3, 6.3), c(2.1, 3.1));\", {5.3, 3.1});\n\tEidosAssertScriptSuccess_FV(\"ifelse(c(T,F,F,T,F,T), 1.0:6.0, -6.0:-1.0);\", {1.0, -5.0, -4.0, 4.0, -2.0, 6.0});\n\t\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), 'foo', 'bar');\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_S(\"ifelse(T, 'foo', 'bar');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"ifelse(F, 'foo', 'bar');\", \"bar\");\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,T), 'foo', 'bar');\", {\"foo\", \"foo\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(F,F), 'foo', 'bar');\", {\"bar\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,F), 'foo', 'bar');\", {\"foo\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,T), c('foo', 'baz'), 'bar');\", {\"foo\", \"baz\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,T), 'foo', c('bar', 'xyzzy'));\", {\"foo\", \"foo\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(F,F), c('foo', 'baz'), 'bar');\", {\"bar\", \"bar\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(F,F), 'foo', c('bar', 'xyzzy'));\", {\"bar\", \"xyzzy\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,T), c('foo', 'baz'), c('bar', 'xyzzy'));\", {\"foo\", \"baz\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(F,F), c('foo', 'baz'), c('bar', 'xyzzy'));\", {\"bar\", \"xyzzy\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,F), c('foo', 'baz'), c('bar', 'xyzzy'));\", {\"foo\", \"xyzzy\"});\n\tEidosAssertScriptSuccess_SV(\"ifelse(c(T,F,F,T,F,T), c('a','b','c','d','e','f'), c('A','B','C','D','E','F'));\", {\"a\", \"B\", \"C\", \"d\", \"E\", \"f\"});\n\t\n\tEidosAssertScriptSuccess(\"ifelse(logical(0), _Test(5), _Test(2))._yolk;\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"ifelse(T, _Test(5), _Test(2))._yolk;\", 5);\n\tEidosAssertScriptSuccess_I(\"ifelse(F, _Test(5), _Test(2))._yolk;\", 2);\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), _Test(5), _Test(2))._yolk;\", {5, 5});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), _Test(5), _Test(2))._yolk;\", {2, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F), _Test(5), _Test(2))._yolk;\", {5, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), c(_Test(5),_Test(6)), _Test(2))._yolk;\", {5, 6});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), _Test(5), c(_Test(2),_Test(3)))._yolk;\", {5, 5});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), c(_Test(5),_Test(6)), _Test(2))._yolk;\", {2, 2});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), _Test(5), c(_Test(2),_Test(3)))._yolk;\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,T), c(_Test(5),_Test(6)), c(_Test(2),_Test(3)))._yolk;\", {5, 6});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(F,F), c(_Test(5),_Test(6)), c(_Test(2),_Test(3)))._yolk;\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F), c(_Test(5),_Test(6)), c(_Test(2),_Test(3)))._yolk;\", {5, 3});\n\tEidosAssertScriptSuccess_IV(\"ifelse(c(T,F,F,T,F,T), c(_Test(1), _Test(2), _Test(3), _Test(4), _Test(5), _Test(6)), c(_Test(-6), _Test(-5), _Test(-4), _Test(-3), _Test(-2), _Test(-1)))._yolk;\", {1, -5, -4, 4, -2, 6});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(T), 5, 2), matrix(5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(F), 5, 2), matrix(2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(T,T), nrow=1), 5, 2), matrix(c(5,5), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(F,F), ncol=1), 5, 2), matrix(c(2,2), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(array(c(T,F), c(1,2,1)), 5, 2), array(c(5,2), c(1,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(T,T), nrow=1), 5:6, 2), matrix(c(5,6), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(T,T), ncol=1), 5, 2:3), matrix(c(5,5), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(array(c(F,F), c(2,1,1)), 5:6, 2), array(c(2,2), c(2,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(array(c(F,F), c(1,1,2)), 5, 2:3), array(c(2,3), c(1,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(T,T), nrow=1), 5:6, 2:3), matrix(c(5,6), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(F,F), ncol=1), 5:6, 2:3), matrix(c(2,3), ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(array(c(T,F), c(1,2,1)), 5:6, 2:3), array(c(5,3), c(1,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(ifelse(matrix(c(T,F,F,T,F,T), nrow=2), 1:6, -6:-1), matrix(c(1,-5,-4,4,-2,6), nrow=2));\", true);\n\t\n\t// isClose()\n\tEidosAssertScriptRaise(\"isClose(float(0), 1.0:3);\", 0, \"requires the lengths of x and y\");\n\tEidosAssertScriptRaise(\"isClose(1.0:2, 1.0:3);\", 0, \"requires the lengths of x and y\");\n\tEidosAssertScriptRaise(\"isClose(1.0, 1.0, rtol=-1.0);\", 0, \"requires rtol\");\n\tEidosAssertScriptRaise(\"isClose(1.0, 1.0, atol=-1.0);\", 0, \"requires atol\");\n\t\n\tEidosAssertScriptSuccess_L(\"isClose(INF, -INF);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(INF, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(INF, INF);\", true);\n\tEidosAssertScriptSuccess_LV(\"isClose(INF, c(-INF, 0.0, INF));\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(-INF, 0.0, INF), INF);\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(INF, INF, INF), c(-INF, 0.0, INF));\", {false, false, true});\n\tEidosAssertScriptSuccess_L(\"isClose(-INF, INF);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(-INF, 0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(-INF, -INF);\", true);\n\tEidosAssertScriptSuccess_LV(\"isClose(-INF, c(INF, 0.0, -INF));\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(INF, 0.0, -INF), -INF);\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(-INF, -INF, -INF), c(INF, 0.0, -INF));\", {false, false, true});\n\t\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, 0.0, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, 0.0, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, INF, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, INF, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(0.0, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(0.0, NAN, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(INF, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(INF, NAN, equalNAN=T);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, NAN, equalNAN=F);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(NAN, NAN, equalNAN=T);\", true);\n\tEidosAssertScriptSuccess_LV(\"isClose(NAN, c(0.0, INF, NAN), equalNAN=F);\", {false, false, false});\n\tEidosAssertScriptSuccess_LV(\"isClose(NAN, c(0.0, INF, NAN), equalNAN=T);\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(NAN, NAN, NAN), c(0.0, INF, NAN), equalNAN=F);\", {false, false, false});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(NAN, NAN, NAN), c(0.0, INF, NAN), equalNAN=T);\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(0.0, INF, NAN), NAN, equalNAN=F);\", {false, false, false});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(0.0, INF, NAN), NAN, equalNAN=T);\", {false, false, true});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(0.0, INF, NAN), c(NAN, NAN, NAN), equalNAN=F);\", {false, false, false});\n\tEidosAssertScriptSuccess_LV(\"isClose(c(0.0, INF, NAN), c(NAN, NAN, NAN), equalNAN=T);\", {false, false, true});\n\t\n\tEidosAssertScriptSuccess_L(\"isClose(1.0, 1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(0.0, 0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(-1.0, -1.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(1.0, -1.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(-1.0, 1.0);\", false);\n\tEidosAssertScriptSuccess_LV(\"isClose(c(1.0, 0.0, -1.0, 1.0, -1.0), c(1.0, 0.0, -1.0, -1.0, 1.0));\", {true, true, true, false, false});\n\t\n\tEidosAssertScriptSuccess_L(\"isClose(1.0, 1.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(1.0, 1.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(100.0, 100.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(100.0, 100.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(-100.0, -100.0 + 0.9e-8, rtol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(-100.0, -100.0 + 1.1e-8, rtol=0.0);\", false);\n\tEidosAssertScriptSuccess_LV(\"isClose(c(1.0, 1.0, 100.0, 100.0, -100.0, -100.0), c(1.0 + 0.9e-8, 1.0 + 1.1e-8, 100.0 + 0.9e-8, 100.0 + 1.1e-8, -100.0 + 0.9e-8, -100.0 + 1.1e-8), rtol=0.0);\", {true, false, true, false, true, false});\n\t\n\tEidosAssertScriptSuccess_L(\"isClose(1.0 + 0.9e-5, 1.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(1.0 + 1.1e-5, 1.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(10.0 + 0.9e-4, 10.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(10.0 + 1.1e-4, 10.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(100.0 + 0.9e-3, 100.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(100.0 + 1.1e-3, 100.0, atol=0.0);\", false);\n\tEidosAssertScriptSuccess_L(\"isClose(-100.0 + 0.9e-3, -100.0, atol=0.0);\", true);\n\tEidosAssertScriptSuccess_L(\"isClose(-100.0 + 1.1e-3, -100.0, atol=0.0);\", false);\n}\n\nvoid _RunFunctionValueInspectionManipulationTests_m_through_r(void)\n{\n\t// match()\n\tEidosAssertScriptSuccess(\"match(NULL, NULL);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptRaise(\"match(NULL, F);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(NULL, 0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(NULL, 0.0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(NULL, '');\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(NULL, _Test(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(F, NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess(\"match(F, F);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"match(F, T);\", -1);\n\tEidosAssertScriptRaise(\"match(F, 0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(F, 0.0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(F, '');\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(F, _Test(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0, NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0, F);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess(\"match(0, 0);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"match(0, 1);\", -1);\n\tEidosAssertScriptRaise(\"match(0, 0.0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0, '');\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0, _Test(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0.0, NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0.0, F);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0.0, 0);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess(\"match(0.0, 0.0);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"match(0.0, 0.1);\", -1);\n\tEidosAssertScriptRaise(\"match(0.0, '');\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(0.0, _Test(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match('', NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match('', F);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match('', 0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match('', 0.0);\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess(\"match('', '');\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"match('', 'f');\", -1);\n\tEidosAssertScriptRaise(\"match('', _Test(0));\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(_Test(0), NULL);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(_Test(0), F);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(_Test(0), 0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(_Test(0), 0.0);\", 0, \"to be the same type\");\n\tEidosAssertScriptRaise(\"match(_Test(0), '');\", 0, \"to be the same type\");\n\tEidosAssertScriptSuccess_I(\"match(_Test(0), _Test(0));\", -1);\t\t\t\t\t\t\t// different elements\n\tEidosAssertScriptSuccess(\"x = _Test(0); match(x, x);\", gStaticEidosValue_Integer0);\n\t\n\tEidosAssertScriptSuccess_IV(\"match(c(F,T,F,F,T,T), T);\", {-1, 0, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,9,5,1), 5);\", {-1, -1, -1, -1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,9,5,1.), 5.);\", {-1, -1, -1, -1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"match(c('bar','q','f','baz','foo','bar'), 'foo');\", {-1, -1, -1, -1, 0, -1});\n\tEidosAssertScriptSuccess_IV(\"match(c(_Test(0), _Test(1)), _Test(0));\", {-1, -1});\t\t\t\t// different elements\n\tEidosAssertScriptSuccess_IV(\"x1 = _Test(1); x2 = _Test(2); x9 = _Test(9); x5 = _Test(5); match(c(x1,x2,x2,x9,x5,x1), x5);\", {-1, -1, -1, -1, 0, -1});\n\t\n\tEidosAssertScriptSuccess(\"match(F, c(T,F));\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"match(9, c(5,1,9));\", 2);\n\tEidosAssertScriptSuccess_I(\"match(9., c(5,1,9.));\", 2);\n\tEidosAssertScriptSuccess_I(\"match('baz', c('foo','bar','baz'));\", 2);\n\tEidosAssertScriptSuccess_I(\"match(_Test(0), c(_Test(0), _Test(1)));\", -1);\t// different elements\n\tEidosAssertScriptSuccess_I(\"x1 = _Test(1); x2 = _Test(2); x9 = _Test(9); x5 = _Test(5); match(c(x9), c(x5,x1,x9));\", 2);\n\t\n\tEidosAssertScriptSuccess_I(\"match(F, c(T,T));\", -1);\n\tEidosAssertScriptSuccess_I(\"match(7, c(5,1,9));\", -1);\n\tEidosAssertScriptSuccess_I(\"match(7., c(5,1,9.));\", -1);\n\tEidosAssertScriptSuccess_I(\"match('zip', c('foo','bar','baz'));\", -1);\n\tEidosAssertScriptSuccess_I(\"match(_Test(7), c(_Test(0), _Test(1)));\", -1);\t// different elements\n\tEidosAssertScriptSuccess_I(\"x1 = _Test(1); x2 = _Test(2); x9 = _Test(9); x5 = _Test(5); match(c(x2), c(x5,x1,x9));\", -1);\n\t\n\tEidosAssertScriptSuccess_IV(\"match(c(F,T,F,F,T,T), c(T,T));\", {-1, 0, -1, -1, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,9,5,1), c(5,1,9));\", {1, -1, -1, 2, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,9,5,1.), c(5,1,9.));\", {1, -1, -1, 2, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,NAN,9,5,1.), c(5,1,9.));\", {1, -1, -1, 2, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,9,5,1.), c(5,1,NAN));\", {1, -1, -1, -1, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c(1,2,2,NAN,5,1.), c(5,1,NAN));\", {1, -1, -1, 2, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c('bar','q','f','baz','foo','bar'), c('foo','bar','baz'));\", {1, -1, -1, 2, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"match(c(_Test(0), _Test(1)), c(_Test(0), _Test(1)));\", {-1, -1});\t// different elements\n\tEidosAssertScriptSuccess_IV(\"x1 = _Test(1); x2 = _Test(2); x9 = _Test(9); x5 = _Test(5); match(c(x1,x2,x2,x9,x5,x1), c(x5,x1,x9));\", {1, -1, -1, 2, 0, 1});\n\t\n\t// check the hash-table-based versions of match(), based on the fact that the crossover between algorithms is x_count >= 500\n\tEidosAssertScriptSuccess_L(\"x = rdunif(499, 0, 1000); t = rdunif(500, 0, 1000); m1 = match(x, t); m2 = match(c(x, 2000), t); identical(c(m1, -1), m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = asFloat(rdunif(499, 0, 1000)); t = asFloat(rdunif(500, 0, 1000)); m1 = match(x, t); m2 = match(c(x, 2000), t); identical(c(m1, -1), m2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = asString(rdunif(499, 0, 1000)); t = asString(rdunif(500, 0, 1000)); m1 = match(x, t); m2 = match(c(x, 2000), t); identical(c(m1, -1), m2);\", true);\n\tEidosAssertScriptSuccess_L(\"o = sapply(0:1001, '_Test(applyValue);'); x = o[rdunif(499, 0, 1000)]; t = o[rdunif(500, 0, 1000)]; m1 = match(x, t); m2 = match(c(x, o[1001]), t); identical(c(m1, -1), m2);\", true);\n\t\n\t// order()\n\tEidosAssertScriptSuccess(\"order(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"order(integer(0), T);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"order(integer(0), F);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"order(3);\", 0);\n\tEidosAssertScriptSuccess_I(\"order(3, T);\", 0);\n\tEidosAssertScriptSuccess_I(\"order(3, F);\", 0);\n\tEidosAssertScriptSuccess_IV(\"order(c(6, 19, -3, 5, 2));\", {2, 4, 3, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"order(c(6, 19, -3, 5, 2), T);\", {2, 4, 3, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"order(c(2, 5, -3, 19, 6), T);\", {2, 0, 1, 4, 3});\n\tEidosAssertScriptSuccess_IV(\"order(c(6, 19, -3, 5, 2), F);\", {1, 0, 3, 4, 2});\n\tEidosAssertScriptSuccess_IV(\"order(c(2, 5, -3, 19, 6), F);\", {3, 4, 1, 0, 2});\n\tEidosAssertScriptSuccess_IV(\"order(c(T, F));\", {1, 0});\n\tEidosAssertScriptSuccess_IV(\"order(c(6.1, 19.3, -3.7, 5.2, 2.3));\", {2, 4, 3, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"order(c(6.1, 19.3, -3.7, 5.2, 2.3), T);\", {2, 4, 3, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"order(c(6.1, 19.3, -3.7, 5.2, 2.3), F);\", {1, 0, 3, 4, 2});\n\tEidosAssertScriptSuccess_IV(\"order(c('a', 'q', 'm', 'f', 'w'));\", {0, 3, 2, 1, 4});\n\tEidosAssertScriptSuccess_IV(\"order(c('a', 'q', 'm', 'f', 'w'), T);\", {0, 3, 2, 1, 4});\n\tEidosAssertScriptSuccess_IV(\"order(c('a', 'q', 'm', 'f', 'w'), F);\", {4, 1, 2, 3, 0});\n\tEidosAssertScriptRaise(\"order(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = order(x); identical(o, c(5, 1, 0, 3, 2, 4)) | identical(o, c(5, 1, 0, 3, 4, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = order(x, ascending=T); identical(o, c(5, 1, 0, 3, 2, 4)) | identical(o, c(5, 1, 0, 3, 4, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = c(5, 0, NAN, 17, NAN, -17); o = order(x, ascending=F); identical(o, c(3, 0, 1, 5, 2, 4)) | identical(o, c(3, 0, 1, 5, 4, 2));\", true);\n\t\n\t// paste()\n\tEidosAssertScriptSuccess(\"paste(NULL);\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_S(\"paste(T);\", \"T\");\n\tEidosAssertScriptSuccess_S(\"paste(5);\", \"5\");\n\tEidosAssertScriptSuccess_S(\"paste(5.5);\", \"5.5\");\n\tEidosAssertScriptSuccess_S(\"paste('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"paste(_Test(7));\", \"_TestElement\");\n\tEidosAssertScriptSuccess(\"paste(NULL, sep='$$');\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_S(\"paste(T, sep='$$');\", \"T\");\n\tEidosAssertScriptSuccess_S(\"paste(5, sep='$$');\", \"5\");\n\tEidosAssertScriptSuccess_S(\"paste(5.5, sep='$$');\", \"5.5\");\n\tEidosAssertScriptSuccess_S(\"paste('foo', sep='$$');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"paste(_Test(7), sep='$$');\", \"_TestElement\");\n\tEidosAssertScriptSuccess_S(\"paste(c(T,T,F,T), sep='$$');\", \"T$$T$$F$$T\");\n\tEidosAssertScriptSuccess_S(\"paste(5:9, sep='$$');\", \"5$$6$$7$$8$$9\");\n\tEidosAssertScriptSuccess_S(\"paste(5.5:8.9, sep='$$');\", \"5.5$$6.5$$7.5$$8.5\");\n\tEidosAssertScriptSuccess_S(\"paste(c('foo', 'bar', 'baz'), sep='$$');\", \"foo$$bar$$baz\");\n\tEidosAssertScriptSuccess_S(\"paste(c(_Test(7), _Test(7), _Test(7)), sep='$$');\", \"_TestElement$$_TestElement$$_TestElement\");\n\tEidosAssertScriptSuccess_S(\"paste(c(T,T,F), 4, NULL, 'foo', 5.5:7.9, 'bar', c(_Test(7), _Test(7)), 5:8);\", \"T T F 4 foo 5.5 6.5 7.5 bar _TestElement _TestElement 5 6 7 8\");\n\tEidosAssertScriptSuccess_S(\"paste(c(T,T,F), 4, NULL, 'foo', 5.5:7.9, 'bar', c(_Test(7), _Test(7)), 5:8, sep='$');\", \"T$T$F$4$foo$5.5$6.5$7.5$bar$_TestElement$_TestElement$5$6$7$8\");\n\t\n\t// paste0()\n\tEidosAssertScriptSuccess(\"paste0(NULL);\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_S(\"paste0(T);\", \"T\");\n\tEidosAssertScriptSuccess_S(\"paste0(5);\", \"5\");\n\tEidosAssertScriptSuccess_S(\"paste0(5.5);\", \"5.5\");\n\tEidosAssertScriptSuccess_S(\"paste0('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"paste0(_Test(7));\", \"_TestElement\");\n\tEidosAssertScriptSuccess(\"paste0(NULL);\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_S(\"paste0(T);\", \"T\");\n\tEidosAssertScriptSuccess_S(\"paste0(5);\", \"5\");\n\tEidosAssertScriptSuccess_S(\"paste0(5.5);\", \"5.5\");\n\tEidosAssertScriptSuccess_S(\"paste0('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_S(\"paste0(_Test(7));\", \"_TestElement\");\n\tEidosAssertScriptSuccess_S(\"paste0(c(T,T,F,T));\", \"TTFT\");\n\tEidosAssertScriptSuccess_S(\"paste0(5:9);\", \"56789\");\n\tEidosAssertScriptSuccess_S(\"paste0(5.5:8.9);\", \"5.56.57.58.5\");\n\tEidosAssertScriptSuccess_S(\"paste0(c('foo', 'bar', 'baz'));\", \"foobarbaz\");\n\tEidosAssertScriptSuccess_S(\"paste0(c(_Test(7), _Test(7), _Test(7)));\", \"_TestElement_TestElement_TestElement\");\n\tEidosAssertScriptSuccess_S(\"paste0(c(T,T,F), 4, NULL, 'foo', 5.5:7.9, 'bar', c(_Test(7), _Test(7)), 5:8);\", \"TTF4foo5.56.57.5bar_TestElement_TestElement5678\");\n\t\n\t// print()\n\tEidosAssertScriptSuccess_VOID(\"print(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"print(T);\");\n\tEidosAssertScriptSuccess_VOID(\"print(5);\");\n\tEidosAssertScriptSuccess_VOID(\"print(5.5);\");\n\tEidosAssertScriptSuccess_VOID(\"print('foo');\");\n\tEidosAssertScriptSuccess_VOID(\"print(_Test(7));\");\n\tEidosAssertScriptSuccess_VOID(\"print(c(T,T,F,T));\");\n\tEidosAssertScriptSuccess_VOID(\"print(5:9);\");\n\tEidosAssertScriptSuccess_VOID(\"print(5.5:8.9);\");\n\tEidosAssertScriptSuccess_VOID(\"print(c('foo', 'bar', 'baz'));\");\n\tEidosAssertScriptSuccess_VOID(\"print(c(_Test(7), _Test(7), _Test(7)));\");\n\t\n\t// rev()\n\tEidosAssertScriptSuccess_IV(\"rev(6:10);\", {10,9,8,7,6});\n\tEidosAssertScriptSuccess_IV(\"rev(-(6:10));\", {-10,-9,-8,-7,-6});\n\tEidosAssertScriptSuccess_SV(\"rev(c('foo','bar','baz'));\", {\"baz\",\"bar\",\"foo\"});\n\tEidosAssertScriptSuccess_I(\"rev(-1);\", -1);\n\tEidosAssertScriptSuccess_F(\"rev(1.0);\", 1);\n\tEidosAssertScriptSuccess_S(\"rev('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_FV(\"rev(6.0:10);\", {10,9,8,7,6});\n\tEidosAssertScriptSuccess_LV(\"rev(c(T,T,T,F));\", {false, true, true, true});\n}\n\nvoid _RunFunctionValueInspectionManipulationTests_s_through_z(void)\n{\n\t// size() / length()\n\tEidosAssertScriptSuccess(\"size(NULL);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"size(logical(0));\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"size(5);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"size(c(5.5, 8.7));\", 2);\n\tEidosAssertScriptSuccess_I(\"size(c('foo', 'bar', 'baz'));\", 3);\n\tEidosAssertScriptSuccess_I(\"size(rep(_Test(7), 4));\", 4);\n\t\n\tEidosAssertScriptSuccess(\"length(NULL);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"length(logical(0));\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"length(5);\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"length(c(5.5, 8.7));\", 2);\n\tEidosAssertScriptSuccess_I(\"length(c('foo', 'bar', 'baz'));\", 3);\n\tEidosAssertScriptSuccess_I(\"length(rep(_Test(7), 4));\", 4);\n\t\n\t// sort()\n\tEidosAssertScriptSuccess(\"sort(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"sort(integer(0), T);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"sort(integer(0), F);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"sort(3);\", 3);\n\tEidosAssertScriptSuccess_I(\"sort(3, T);\", 3);\n\tEidosAssertScriptSuccess_I(\"sort(3, F);\", 3);\n\tEidosAssertScriptSuccess_IV(\"sort(c(6, 19, -3, 5, 2));\", {-3, 2, 5, 6, 19});\n\tEidosAssertScriptSuccess_IV(\"sort(c(6, 19, -3, 5, 2), T);\", {-3, 2, 5, 6, 19});\n\tEidosAssertScriptSuccess_IV(\"sort(c(6, 19, -3, 5, 2), F);\", {19, 6, 5, 2, -3});\n\tEidosAssertScriptSuccess_LV(\"sort(c(T, F, T, T, F));\", {false, false, true, true, true});\n\tEidosAssertScriptSuccess_FV(\"sort(c(6.1, 19.3, -3.7, 5.2, 2.3));\", {-3.7, 2.3, 5.2, 6.1, 19.3});\n\tEidosAssertScriptSuccess_FV(\"sort(c(6.1, 19.3, -3.7, 5.2, 2.3), T);\", {-3.7, 2.3, 5.2, 6.1, 19.3});\n\tEidosAssertScriptSuccess_FV(\"sort(c(6.1, 19.3, -3.7, 5.2, 2.3), F);\", {19.3, 6.1, 5.2, 2.3, -3.7});\n\tEidosAssertScriptSuccess_SV(\"sort(c('a', 'q', 'm', 'f', 'w'));\", {\"a\", \"f\", \"m\", \"q\", \"w\"});\n\tEidosAssertScriptSuccess_SV(\"sort(c('a', 'q', 'm', 'f', 'w'), T);\", {\"a\", \"f\", \"m\", \"q\", \"w\"});\n\tEidosAssertScriptSuccess_SV(\"sort(c('a', 'q', 'm', 'f', 'w'), F);\", {\"w\", \"q\", \"m\", \"f\", \"a\"});\n\tEidosAssertScriptRaise(\"sort(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_FV(\"x = c(5, 0, NAN, 17, NAN, -17); sort(x);\", {-17, 0, 5, 17, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"x = c(5, 0, NAN, 17, NAN, -17); sort(x, ascending=T);\", {-17, 0, 5, 17, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"x = c(5, 0, NAN, 17, NAN, -17); sort(x, ascending=F);\", {17, 5, 0, -17, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// sortBy()\n\tEidosAssertScriptRaise(\"sortBy(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(9.1);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(NULL, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(T, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(5, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy(9.1, 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"sortBy('foo', 'foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"sortBy(object(), 'foo');\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess_IV(\"sortBy(c(_Test(7), _Test(2), _Test(-8), _Test(3), _Test(75)), '_yolk')._yolk;\", {-8, 2, 3, 7, 75});\n\tEidosAssertScriptSuccess_IV(\"sortBy(c(_Test(7), _Test(2), _Test(-8), _Test(3), _Test(75)), '_yolk', T)._yolk;\", {-8, 2, 3, 7, 75});\n\tEidosAssertScriptSuccess_IV(\"sortBy(c(_Test(7), _Test(2), _Test(-8), _Test(3), _Test(75)), '_yolk', F)._yolk;\", {75, 7, 3, 2, -8});\n\tEidosAssertScriptRaise(\"sortBy(c(_Test(7), _Test(2), _Test(-8), _Test(3), _Test(75)), '_foo')._yolk;\", 0, \"attempt to get a value\");\n\t\n\t// str() – can't test the actual output, but we can make sure it executes...\n\tEidosAssertScriptSuccess_VOID(\"str(NULL);\");\n\tEidosAssertScriptSuccess_VOID(\"str(logical(0));\");\n\tEidosAssertScriptSuccess_VOID(\"str(T);\");\n\tEidosAssertScriptSuccess_VOID(\"str(c(T,F,F,T));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(T));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(c(T,F,F,T)));\");\n\tEidosAssertScriptSuccess_VOID(\"str(integer(0));\");\n\tEidosAssertScriptSuccess_VOID(\"str(5);\");\n\tEidosAssertScriptSuccess_VOID(\"str(5:8);\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(5));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(5:8));\");\n\tEidosAssertScriptSuccess_VOID(\"str(float(0));\");\n\tEidosAssertScriptSuccess_VOID(\"str(5.9);\");\n\tEidosAssertScriptSuccess_VOID(\"str(5.9:8);\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(5.9));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(5.9:8));\");\n\tEidosAssertScriptSuccess_VOID(\"str(string(0));\");\n\tEidosAssertScriptSuccess_VOID(\"str('foo');\");\n\tEidosAssertScriptSuccess_VOID(\"str(c('foo', 'bar', 'baz'));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix('foo'));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(c('foo', 'bar', 'baz')));\");\n\tEidosAssertScriptSuccess_VOID(\"str(object());\");\n\tEidosAssertScriptSuccess_VOID(\"str(_Test(7));\");\n\tEidosAssertScriptSuccess_VOID(\"str(c(_Test(7), _Test(8), _Test(9)));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(_Test(7)));\");\n\tEidosAssertScriptSuccess_VOID(\"str(matrix(c(_Test(7), _Test(8), _Test(9))));\");\n\t\n\t// tabulate()\n\tEidosAssertScriptSuccess_I(\"tabulate(integer(0));\", 0);\n\tEidosAssertScriptSuccess_I(\"tabulate(integer(0), 0);\", 0);\n\tEidosAssertScriptSuccess_IV(\"tabulate(integer(0), 4);\", {0, 0, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"tabulate(3);\", {0, 0, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"tabulate(3, 4);\", {0, 0, 0, 1, 0});\n\tEidosAssertScriptSuccess_IV(\"tabulate(3, 2);\", {0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"tabulate(c(0, -1, 0, -5, 5, 3, 3, 3, 0, 3, 4, 5));\", {3, 0, 0, 4, 1, 2});\n\tEidosAssertScriptSuccess_IV(\"tabulate(c(0, -1, 0, -5, 5, 3, 3, 3, 0, 3, 4, 5), 8);\", {3, 0, 0, 4, 1, 2, 0, 0, 0});\n\tEidosAssertScriptSuccess_IV(\"tabulate(c(0, -1, 0, -5, 5, 3, 3, 3, 0, 3, 4, 5), 3);\", {3, 0, 0, 4});\n\tEidosAssertScriptSuccess_I(\"sum(tabulate(rdunif(100, 5, 15)));\", 100);\n\tEidosAssertScriptSuccess_I(\"sum(tabulate(rdunif(100, 5, 15), 25));\", 100);\n\tEidosAssertScriptRaise(\"tabulate(c(0, -1, 0, -5, 5, 3, 3, 3, 0, 3, 4, 5), -1);\", 0, \"to be greater than or equal to 0\");\n\t\n\t// unique()\n\tEidosAssertScriptSuccess_NULL(\"unique(NULL);\");\n\tEidosAssertScriptSuccess(\"unique(logical(0));\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(integer(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(float(0));\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(string(0));\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(object());\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"unique(T);\", true);\n\tEidosAssertScriptSuccess_I(\"unique(5);\", 5);\n\tEidosAssertScriptSuccess_F(\"unique(3.5);\", 3.5);\n\tEidosAssertScriptSuccess_S(\"unique('foo');\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"unique(_Test(7))._yolk;\", 7);\n\tEidosAssertScriptSuccess_LV(\"unique(c(T,T,T,T,F,T,T));\", {true, false});\n\tEidosAssertScriptSuccess_IV(\"unique(c(3,5,3,9,2,3,3,7,5));\", {3, 5, 9, 2, 7});\n\tEidosAssertScriptSuccess_FV(\"unique(c(3.5,1.2,9.3,-1.0,1.2,-1.0,1.2,7.6,3.5));\", {3.5, 1.2, 9.3, -1, 7.6});\n\tEidosAssertScriptSuccess_FV(\"unique(c(3.5,1.2,9.3,-1.0,NAN,1.2,-1.0,1.2,7.6,3.5));\", {3.5, 1.2, 9.3, -1, std::numeric_limits<double>::quiet_NaN(), 7.6});\n\tEidosAssertScriptSuccess_FV(\"unique(c(3.5,1.2,9.3,-1.0,NAN,1.2,-1.0,1.2,NAN, 7.6,3.5));\", {3.5, 1.2, 9.3, -1, std::numeric_limits<double>::quiet_NaN(), 7.6});\n\tEidosAssertScriptSuccess_SV(\"unique(c('foo', 'bar', 'foo', 'baz', 'baz', 'bar', 'foo'));\", {\"foo\", \"bar\", \"baz\"});\n\tEidosAssertScriptSuccess_IV(\"unique(c(_Test(7), _Test(7), _Test(2), _Test(7), _Test(2)))._yolk;\", {7, 7, 2, 7, 2});\n\t\n\tEidosAssertScriptSuccess_NULL(\"unique(NULL, F);\");\n\tEidosAssertScriptSuccess(\"unique(logical(0), F);\", gStaticEidosValue_Logical_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(integer(0), F);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(float(0), F);\", gStaticEidosValue_Float_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(string(0), F);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"unique(object(), F);\", gStaticEidosValue_Object_ZeroVec);\n\tEidosAssertScriptSuccess_L(\"unique(T, F);\", true);\n\tEidosAssertScriptSuccess_I(\"unique(5, F);\", 5);\n\tEidosAssertScriptSuccess_F(\"unique(3.5, F);\", 3.5);\n\tEidosAssertScriptSuccess_S(\"unique('foo', F);\", \"foo\");\n\tEidosAssertScriptSuccess_I(\"unique(_Test(7), F)._yolk;\", 7);\n\tEidosAssertScriptSuccess_LV(\"unique(c(T,T,T,T,F,T,T), F);\", {true, false});\n\tEidosAssertScriptSuccess_IV(\"sort(unique(c(3,5,3,9,2,3,3,7,5), F));\", {2, 3, 5, 7, 9});\n\tEidosAssertScriptSuccess_FV(\"sort(unique(c(3.5,1.2,9.3,-1.0,1.2,-1.0,1.2,7.6,3.5), F));\", {-1, 1.2, 3.5, 7.6, 9.3});\n\tEidosAssertScriptSuccess_FV(\"sort(unique(c(3.5,1.2,9.3,-1.0,NAN,1.2,-1.0,1.2,7.6,3.5), F));\", {-1, 1.2, 3.5, 7.6, 9.3, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_FV(\"sort(unique(c(3.5,1.2,9.3,-1.0,NAN,1.2,-1.0,1.2,NAN,7.6,3.5), F));\", {-1, 1.2, 3.5, 7.6, 9.3, std::numeric_limits<double>::quiet_NaN()});\n\tEidosAssertScriptSuccess_SV(\"sort(unique(c('foo', 'bar', 'foo', 'baz', 'baz', 'bar', 'foo'), F));\", {\"bar\", \"baz\", \"foo\"});\n\tEidosAssertScriptSuccess_IV(\"sort(unique(c(_Test(7), _Test(7), _Test(2), _Test(7), _Test(2)), F)._yolk);\", {2, 2, 7, 7, 7});\n\t\n\tEidosAssertScriptSuccess_L(\"x = asInteger(runif(10000, 0, 10000)); size(unique(x)) == size(unique(x, F));\", true);\n\tEidosAssertScriptSuccess_L(\"x = runif(10000, 0, 1); size(unique(x)) == size(unique(x, F));\", true);\n\t\n\t// which()\n\tEidosAssertScriptRaise(\"which(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"which(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"which(5.7);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"which('foo');\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"which(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"which(logical(0));\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"which(F);\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess(\"which(T);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_IV(\"which(c(T,F,F,T,F,T,F,F,T));\", {0, 3, 5, 8});\n\t\n\t// whichMax()\n\tEidosAssertScriptSuccess(\"whichMax(T);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMax(3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMax(3.5);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMax('foo');\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"whichMax(c(F, F, T, F, T));\", 2);\n\tEidosAssertScriptSuccess_I(\"whichMax(c(3, 7, 19, -5, 9));\", 2);\n\tEidosAssertScriptSuccess_I(\"whichMax(c(3.3, 7.7, 19.1, -5.8, 9.0));\", 2);\n\tEidosAssertScriptSuccess_I(\"whichMax(c(3.3, 7.7, 19.1, NAN, -5.8, 9.0));\", 2);\n\tEidosAssertScriptSuccess(\"whichMax(c('bar', 'foo', 'baz'));\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptRaise(\"whichMax(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_NULL(\"whichMax(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"whichMax(logical(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMax(integer(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMax(float(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMax(string(0));\");\n\t\n\t// whichMin()\n\tEidosAssertScriptSuccess(\"whichMin(T);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMin(3);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMin(3.5);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMin('foo');\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"whichMin(c(T, F, T, F, T));\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"whichMin(c(3, 7, 19, -5, 9));\", 3);\n\tEidosAssertScriptSuccess_I(\"whichMin(c(3.3, 7.7, 19.1, -5.8, 9.0));\", 3);\n\tEidosAssertScriptSuccess_I(\"whichMin(c(3.3, 7.7, 19.1, NAN, -5.8, 9.0));\", 4);\n\tEidosAssertScriptSuccess(\"whichMin(c('foo', 'bar', 'baz'));\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptRaise(\"whichMin(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess_NULL(\"whichMin(NULL);\");\n\tEidosAssertScriptSuccess_NULL(\"whichMin(logical(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMin(integer(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMin(float(0));\");\n\tEidosAssertScriptSuccess_NULL(\"whichMin(string(0));\");\n}\n\n#pragma mark value type testing / coercion\nvoid _RunStringManipulationTests(void)\n{\n\t// grep() - we test only ECMAScript\n\tif (!Eidos_RegexWorks())\n\t{\n\t\tstd::cout << \"WARNING: This build of Eidos does not have a working <regex> library, due to a bug in the underlying C++ standard library provided by the system.  This may cause problems with the Eidos functions grep() and readCSV(); if you do not use those functions, it should not affect you.  If a case where a problem does occur is encountered, an error will result.  This problem might be resolved by updating your compiler or toolchain, or by upgrading to a more recent version of your operating system.\" << std::endl;\n\t}\n\telse\n\t{\n\t\tEidosAssertScriptRaise(\"grep('', c('abc', 'bcd', 'cde', 'def', 'ecDf'));\", 0, \"pattern to be of length >= 1\");\n\t\tEidosAssertScriptRaise(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), grammar='fooScript');\", 0, \"requires grammar to be one of\");\n\t\tEidosAssertScriptRaise(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), value='objects');\", 0, \"requires value to be one of\");\n\t\tEidosAssertScriptRaise(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), value='matches', invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptSuccess_IV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=T, invert=F);\", {1, 2});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=T, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=T, invert=F);\", {1, 2, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=T, invert=T);\", {0, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=T, invert=T);\", {0, 1, 2, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=T, invert=T);\", {0, 3});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=T, invert=F);\", {\"bcd\", \"cde\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=T, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=T, invert=F);\", {\"bcd\", \"cde\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=T, invert=T);\", {\"abc\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=T, invert=T);\", {\"abc\", \"bcd\", \"cde\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=T, invert=T);\", {\"abc\", \"def\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=T, invert=F);\", {\"cd\", \"cd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=T, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=T, invert=F);\", {\"cd\", \"cd\", \"cD\"});\n\t\tEidosAssertScriptRaise(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=T, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=T, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=T, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptSuccess_LV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=T, invert=F);\", {false, true, true, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=T, invert=F);\", {false, false, false, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=T, invert=F);\", {false, true, true, false, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=T, invert=T);\", {true, false, false, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=T, invert=T);\", {true, true, true, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=T, invert=T);\", {true, false, false, true, false});\n\t\t\n\t\tEidosAssertScriptSuccess_IV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1, 2});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1, 2, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 1, 2, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 3});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\", \"cde\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\", \"cde\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"bcd\", \"cde\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"def\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\", \"cd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\", \"cd\", \"cD\"});\n\t\tEidosAssertScriptRaise(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptSuccess_LV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, true, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, false, false, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, true, false, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, false, false, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, true, true, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('Cd', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, false, false, true, false});\n\n\t\tEidosAssertScriptSuccess_IV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1, 2});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1, 2, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 1, 2, 3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='indices', fixed=F, invert=T);\", {0, 3});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\", \"cde\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\", \"cde\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"bcd\", \"cde\", \"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='elements', fixed=F, invert=T);\", {\"abc\", \"def\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\", \"cd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\", \"cd\", \"cD\"});\n\t\tEidosAssertScriptRaise(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptRaise(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='matches', fixed=F, invert=T);\", 0, \"does not allow value=\");\n\t\tEidosAssertScriptSuccess_LV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, true, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, false, false, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, true, false, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, false, false, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, true, true, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[Cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=T, grammar='ECMAScript', value='logical', fixed=F, invert=T);\", {true, false, false, true, false});\n\t\t\n\t\tEidosAssertScriptSuccess_IV(\"grep('^[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {2});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[cd]{2}$', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1});\n\t\tEidosAssertScriptSuccess_IV(\"grep('(cd)|(cD)', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {1, 2, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('.f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {3, 4});\n\t\tEidosAssertScriptSuccess_IV(\"grep('[[:alpha:]]f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='indices', fixed=F, invert=F);\", {3, 4});\n\t\tEidosAssertScriptSuccess_SV(\"grep('^[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"cde\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[cd]{2}$', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('(cd)|(cD)', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"bcd\", \"cde\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('.f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[[:alpha:]]f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='elements', fixed=F, invert=F);\", {\"def\", \"ecDf\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('^[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[cd]{2}$', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('(cd)|(cD)', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"cd\", \"cd\", \"cD\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('.f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"ef\", \"Df\"});\n\t\tEidosAssertScriptSuccess_SV(\"grep('[[:alpha:]]f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='matches', fixed=F, invert=F);\", {\"ef\", \"Df\"});\n\t\tEidosAssertScriptSuccess_LV(\"grep('^[cd]{2}', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, false, true, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[cd]{2}$', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, false, false, false});\n\t\tEidosAssertScriptSuccess_LV(\"grep('(cd)|(cD)', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, true, true, false, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('.f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, false, false, true, true});\n\t\tEidosAssertScriptSuccess_LV(\"grep('[[:alpha:]]f', c('abc', 'bcd', 'cde', 'def', 'ecDf'), ignoreCase=F, grammar='ECMAScript', value='logical', fixed=F, invert=F);\", {false, false, false, true, true});\n\t}\n\t\n\t// nchar()\n\tEidosAssertScriptRaise(\"nchar(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"nchar(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"nchar(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"nchar(5.5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"nchar(_Test(7));\", 0, \"cannot be type\");\n\tEidosAssertScriptSuccess(\"nchar('');\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"nchar(' ');\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"nchar('abcde');\", 5);\n\tEidosAssertScriptSuccess_I(\"nchar('abc\\tde');\", 6);\n\tEidosAssertScriptSuccess_IV(\"nchar(c('', 'abcde', '', 'wumpus'));\", {0, 5, 0, 6});\n\t\n\tEidosAssertScriptSuccess_L(\"identical(nchar(matrix('abc\\tde')), matrix(nchar('abc\\tde')));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(nchar(matrix(c('', 'abcde', '', 'wumpus'), nrow=2)), matrix(nchar(c('', 'abcde', '', 'wumpus')), nrow=2));\", true);\n\t\n\t// strcontains()\n\tEidosAssertScriptRaise(\"strcontains('foobarbazxyzzy', '');\", 0, \"to be of length >= 1\");\n\tEidosAssertScriptRaise(\"strcontains('foobarbazxyzzy', 'foo', pos=-1);\", 0, \"to be >= 0\");\n\tEidosAssertScriptSuccess_L(\"strcontains('', 'a');\", false);\n\tEidosAssertScriptSuccess_L(\"strcontains('', 'a', pos=1000000);\", false);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'foo', pos=0);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'foo', pos=1);\", false);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=0);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=1);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=3);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=4);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=6);\", true);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'ba', pos=7);\", false);\n\tEidosAssertScriptSuccess_L(\"strcontains('foobarbazxyzzy', 'wumpus');\", false);\n\tEidosAssertScriptSuccess_LV(\"strcontains(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo');\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"strcontains(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo', pos=1);\", {false, true, true, false});\n\t\n\t// strfind()\n\tEidosAssertScriptRaise(\"strfind('foobarbazxyzzy', '');\", 0, \"to be of length >= 1\");\n\tEidosAssertScriptRaise(\"strfind('foobarbazxyzzy', 'foo', pos=-1);\", 0, \"to be >= 0\");\n\tEidosAssertScriptSuccess_I(\"strfind('', 'a');\", -1);\n\tEidosAssertScriptSuccess_I(\"strfind('', 'a', pos=1000000);\", -1);\n\tEidosAssertScriptSuccess(\"strfind('foobarbazxyzzy', 'foo', pos=0);\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"strfind('foobarbazxyzzy', 'foo', pos=1);\", -1);\n\tEidosAssertScriptSuccess(\"strfind('foobarbazxyzzy', 'ba', pos=0);\", gStaticEidosValue_Integer3);\n\tEidosAssertScriptSuccess(\"strfind('foobarbazxyzzy', 'ba', pos=1);\", gStaticEidosValue_Integer3);\n\tEidosAssertScriptSuccess(\"strfind('foobarbazxyzzy', 'ba', pos=3);\", gStaticEidosValue_Integer3);\n\tEidosAssertScriptSuccess_I(\"strfind('foobarbazxyzzy', 'ba', pos=4);\", 6);\n\tEidosAssertScriptSuccess_I(\"strfind('foobarbazxyzzy', 'ba', pos=6);\", 6);\n\tEidosAssertScriptSuccess_I(\"strfind('foobarbazxyzzy', 'ba', pos=7);\", -1);\n\tEidosAssertScriptSuccess_I(\"strfind('foobarbazxyzzy', 'wumpus');\", -1);\n\tEidosAssertScriptSuccess_IV(\"strfind(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo');\", {0, 3, 5, -1});\n\tEidosAssertScriptSuccess_IV(\"strfind(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo', pos=1);\", {-1, 3, 5, -1});\n\t\n\t// strprefix()\n\tEidosAssertScriptRaise(\"strprefix('foobarbazxyzzy', '');\", 0, \"to be of length >= 1\");\n\tEidosAssertScriptSuccess_L(\"strprefix('', 'a');\", false);\n\tEidosAssertScriptSuccess_L(\"strprefix('foobarbazxyzzy', 'foo');\", true);\n\tEidosAssertScriptSuccess_L(\"strprefix('foobarbazxyzzy', 'oob');\", false);\n\tEidosAssertScriptSuccess_L(\"strprefix('foobarbazxyzzy', 'f');\", true);\n\tEidosAssertScriptSuccess_L(\"strprefix('foobarbazxyzzy', 'o');\", false);\n\tEidosAssertScriptSuccess_LV(\"strprefix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo');\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"strprefix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'bar');\", {false, true, false, false});\n\tEidosAssertScriptSuccess_LV(\"strprefix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'x');\", {false, false, true, true});\n\tEidosAssertScriptSuccess_LV(\"strprefix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'xyzzyf');\", {false, false, true, false});\n\t\n\t// strsplit()\n\tEidosAssertScriptRaise(\"strsplit(NULL);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"strsplit(T);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"strsplit(5);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"strsplit(5.6);\", 0, \"cannot be type\");\n\tEidosAssertScriptRaise(\"strsplit(string(0));\", 0, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"strsplit(string(0), '$$');\", 0, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"strsplit(c('foo', 'bar'));\", 0, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"strsplit(c('foo', 'bar'), '$$');\", 0, \"must be a singleton\");\n\tEidosAssertScriptSuccess(\"strsplit('');\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess(\"strsplit('', '$$');\", gStaticEidosValue_StringEmpty);\n\tEidosAssertScriptSuccess_SV(\"strsplit(' ');\", {\"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('$$', '$$');\", {\"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('  ');\", {\"\", \"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('$$$$', '$$');\", {\"\", \"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('$$$$', '');\", {\"$\", \"$\", \"$\", \"$\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('This is a test.');\", {\"This\", \"is\", \"a\", \"test.\"});\n\tEidosAssertScriptSuccess_S(\"strsplit('This is a test.', '$$');\", \"This is a test.\");\n\tEidosAssertScriptSuccess_SV(\"strsplit('This is a test.', 'i');\", {\"Th\", \"s \", \"s a test.\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('This is a test.', 's');\", {\"Thi\", \" i\", \" a te\", \"t.\"});\n\tEidosAssertScriptSuccess_SV(\"strsplit('This is a test.', '');\", {\"T\", \"h\", \"i\", \"s\", \" \", \"i\", \"s\", \" \", \"a\", \" \", \"t\", \"e\", \"s\", \"t\", \".\"});\n\t\n\t// strsuffix()\n\tEidosAssertScriptRaise(\"strsuffix('foobarbazxyzzy', '');\", 0, \"to be of length >= 1\");\n\tEidosAssertScriptSuccess_L(\"strsuffix('', 'a');\", false);\n\tEidosAssertScriptSuccess_L(\"strsuffix('foobarbazxyzzy', 'zzy');\", true);\n\tEidosAssertScriptSuccess_L(\"strsuffix('foobarbazxyzzy', 'yzz');\", false);\n\tEidosAssertScriptSuccess_L(\"strsuffix('foobarbazxyzzy', 'y');\", true);\n\tEidosAssertScriptSuccess_L(\"strsuffix('foobarbazxyzzy', 'z');\", false);\n\tEidosAssertScriptSuccess_LV(\"strsuffix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'foo');\", {false, true, false, false});\n\tEidosAssertScriptSuccess_LV(\"strsuffix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'baz');\", {false, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"strsuffix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'y');\", {true, false, false, true});\n\tEidosAssertScriptSuccess_LV(\"strsuffix(c('foobarbazxyzzy', 'barfoo', 'xyzzyfoobaz', 'xyzzy'), 'zxyzzy');\", {true, false, false, false});\n\t\n\t// substr()\n\tEidosAssertScriptSuccess(\"substr(string(0), 1);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess(\"substr(string(0), 1, 2);\", gStaticEidosValue_String_ZeroVec);\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1);\", {\"oo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1, 10000);\", {\"oo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1, 1);\", {\"o\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1, 2);\", {\"oo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1, 3);\", {\"oo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 1, 0);\", {\"\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, 8);\", {\"\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, -100);\", {\"foo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo'); substr(x, -100, 1);\", {\"fo\"});\n\tEidosAssertScriptRaise(\"x=c('foo'); substr(x, 1, c(2, 4));\", 12, \"requires the size of\");\n\tEidosAssertScriptRaise(\"x=c('foo'); substr(x, c(1, 2), 4);\", 12, \"requires the size of\");\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1);\", {\"oo\", \"ar\", \"oobaz\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, 10000);\", {\"oo\", \"ar\", \"oobaz\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, 1);\", {\"o\", \"a\", \"o\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, 2);\", {\"oo\", \"ar\", \"oo\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, 3);\", {\"oo\", \"ar\", \"oob\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, c(1, 2, 3));\", {\"oo\", \"r\", \"baz\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, c(1, 2, 3));\", {\"o\", \"ar\", \"oob\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, c(1, 2, 3), c(1, 2, 3));\", {\"o\", \"r\", \"b\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, c(1, 2, 3), c(2, 4, 6));\", {\"oo\", \"r\", \"baz\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 1, 0);\", {\"\", \"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, 8);\", {\"\", \"\", \"\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, -100);\", {\"foo\", \"bar\", \"foobaz\"});\n\tEidosAssertScriptSuccess_SV(\"x=c('foo','bar','foobaz'); substr(x, -100, 1);\", {\"fo\", \"ba\", \"fo\"});\n\tEidosAssertScriptRaise(\"x=c('foo','bar','foobaz'); substr(x, 1, c(2, 4));\", 27, \"requires the size of\");\n\tEidosAssertScriptRaise(\"x=c('foo','bar','foobaz'); substr(x, c(1, 2), 4);\", 27, \"requires the size of\");\n}\n\n#pragma mark value type testing / coercion\nvoid _RunFunctionValueTestingCoercionTests(void)\n{\n\t// asFloat()\n\tEidosAssertScriptSuccess_FV(\"asFloat(-1:3);\", {-1,0,1,2,3});\n\tEidosAssertScriptSuccess_FV(\"asFloat(-1.0:3);\", {-1,0,1,2,3});\n\tEidosAssertScriptSuccess_FV(\"asFloat(c(T,F,T,F));\", {1,0,1,0});\n\tEidosAssertScriptSuccess_FV(\"asFloat(c('1','2','3'));\", {1,2,3});\n\tEidosAssertScriptRaise(\"asFloat('foo');\", 0, \"could not be represented\");\n\tEidosAssertScriptSuccess_L(\"identical(asFloat(matrix(c('1','2','3'))), matrix(1.0:3.0));\", true);\n\t\n\t// asInteger()\n\tEidosAssertScriptSuccess_IV(\"asInteger(-1:3);\", {-1,0,1,2,3});\n\tEidosAssertScriptSuccess_IV(\"asInteger(-1.0:3);\", {-1,0,1,2,3});\n\tEidosAssertScriptSuccess_IV(\"asInteger(c(T,F,T,F));\", {1,0,1,0});\n\tEidosAssertScriptSuccess_IV(\"asInteger(c('1','2','3'));\", {1,2,3});\n\tEidosAssertScriptRaise(\"asInteger('foo');\", 0, \"could not be represented\");\n\tEidosAssertScriptRaise(\"asInteger(NAN);\", 0, \"cannot be converted\");\n\tEidosAssertScriptSuccess_L(\"identical(asInteger(matrix(c('1','2','3'))), matrix(1:3));\", true);\n\t\n\t// asInteger() overflow tests; these may be somewhat platform-dependent but I doubt it will bite us\n\tEidosAssertScriptRaise(\"asInteger(asFloat(9223372036854775807));\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// the double representation is larger than INT64_MAX\n\tEidosAssertScriptRaise(\"asInteger(asFloat(9223372036854775807-511));\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// the same double representation as previous\n\tEidosAssertScriptSuccess_I(\"asInteger(asFloat(9223372036854775807-512));\", 9223372036854774784);\t// 9223372036854774784 == 9223372036854775807-1023, the closest value to INT64_MAX that double can represent\n\tEidosAssertScriptSuccess_I(\"asInteger(asFloat(-9223372036854775807 - 1));\", INT64_MIN);\t\t\t// the double representation is exact\n\tEidosAssertScriptSuccess_I(\"asInteger(asFloat(-9223372036854775807 - 1) - 1024);\", INT64_MIN);\t// the same double representation as previous; the closest value to INT64_MIN that double can represent\n\tEidosAssertScriptRaise(\"asInteger(asFloat(-9223372036854775807 - 1) - 1025);\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t// overflow on cast\n\tEidosAssertScriptRaise(\"asInteger(asFloat(c(9223372036854775807, 0)));\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// the double representation is larger than INT64_MAX\n\tEidosAssertScriptRaise(\"asInteger(asFloat(c(9223372036854775807, 0)-511));\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// the same double representation as previous\n\tEidosAssertScriptSuccess_IV(\"asInteger(asFloat(c(9223372036854775807, 0)-512));\", {9223372036854774784, -512});\t// 9223372036854774784 == 9223372036854775807-1023, the closest value to INT64_MAX that double can represent\n\tEidosAssertScriptSuccess_IV(\"asInteger(asFloat(c(-9223372036854775807, 0) - 1));\", {INT64_MIN, -1});\t\t\t// the double representation is exact\n\tEidosAssertScriptSuccess_IV(\"asInteger(asFloat(c(-9223372036854775807, 0) - 1) - 1024);\", {INT64_MIN, -1025});\t// the same double representation as previous; the closest value to INT64_MIN that double can represent\n\tEidosAssertScriptRaise(\"asInteger(asFloat(c(-9223372036854775807, 0) - 1) - 1025);\", 0, \"too large to be converted\");\t\t\t\t\t\t\t\t\t\t\t\t\t// overflow on cast\n\t\n\t// asLogical()\n\tEidosAssertScriptSuccess_L(\"asLogical(1);\", true);\n\tEidosAssertScriptSuccess_L(\"asLogical(0);\", false);\n\tEidosAssertScriptSuccess_LV(\"asLogical(-1:3);\", {true,false,true,true,true});\n\tEidosAssertScriptSuccess_LV(\"asLogical(-1.0:3);\", {true,false,true,true,true});\n\tEidosAssertScriptRaise(\"asLogical(NAN);\", 0, \"cannot be converted\");\n\tEidosAssertScriptSuccess_LV(\"asLogical(c(T,F,T,F));\", {true,false,true,false});\n\tEidosAssertScriptSuccess_LV(\"asLogical(c('foo','bar',''));\", {true,true,false});\n\tEidosAssertScriptSuccess_L(\"identical(asLogical(matrix(-1:3)), matrix(c(T,F,T,T,T)));\", true);\n\t\n\t// asString()\n\tEidosAssertScriptSuccess_SV(\"asString(NULL);\", {\"NULL\"});\n\tEidosAssertScriptSuccess_SV(\"asString(-1);\", {\"-1\"});\n\tEidosAssertScriptSuccess_SV(\"asString(3);\", {\"3\"});\n\tEidosAssertScriptSuccess_SV(\"asString(-1:3);\", {\"-1\",\"0\",\"1\",\"2\",\"3\"});\n\tEidosAssertScriptSuccess_SV(\"asString(-1.0:3);\", {\"-1.0\",\"0.0\",\"1.0\",\"2.0\",\"3.0\"});\n\tEidosAssertScriptSuccess_SV(\"asString(c(1.0, NAN, -2.0));\", {\"1.0\",\"NAN\",\"-2.0\"});\n\tEidosAssertScriptSuccess_SV(\"asString(c(T,F,T,F));\", {\"T\",\"F\",\"T\",\"F\"});\n\tEidosAssertScriptSuccess_SV(\"asString(c('1','2','3'));\", {\"1\",\"2\",\"3\"});\n\tEidosAssertScriptSuccess_L(\"identical(asString(matrix(-1:3)), matrix(c('-1','0','1','2','3')));\", true);\n\t\n\t// elementType()\n\tEidosAssertScriptSuccess_S(\"elementType(NULL);\", \"NULL\");\n\tEidosAssertScriptSuccess_S(\"elementType(T);\", \"logical\");\n\tEidosAssertScriptSuccess_S(\"elementType(3);\", \"integer\");\n\tEidosAssertScriptSuccess_S(\"elementType(3.5);\", \"float\");\n\tEidosAssertScriptSuccess_S(\"elementType('foo');\", \"string\");\n\tEidosAssertScriptSuccess_S(\"elementType(_Test(7));\", \"_TestElement\");\n\tEidosAssertScriptSuccess_S(\"elementType(object());\", \"Object\");\n\tEidosAssertScriptSuccess_S(\"elementType(c(object(), object()));\", \"Object\");\n\tEidosAssertScriptSuccess_S(\"elementType(c(_Test(7), object()));\", \"_TestElement\");\n\tEidosAssertScriptSuccess_S(\"elementType(c(object(), _Test(7)));\", \"_TestElement\");\n\tEidosAssertScriptSuccess_S(\"elementType(_Test(7)[F]);\", \"_TestElement\");\n\t\n\t// isFloat()\n\tEidosAssertScriptSuccess_L(\"isFloat(NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"isFloat(T);\", false);\n\tEidosAssertScriptSuccess_L(\"isFloat(3);\", false);\n\tEidosAssertScriptSuccess_L(\"isFloat(3.5);\", true);\n\tEidosAssertScriptSuccess_L(\"isFloat('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"isFloat(_Test(7));\", false);\n\tEidosAssertScriptSuccess_L(\"isFloat(object());\", false);\n\t\n\t// isInteger()\n\tEidosAssertScriptSuccess_L(\"isInteger(NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"isInteger(T);\", false);\n\tEidosAssertScriptSuccess_L(\"isInteger(3);\", true);\n\tEidosAssertScriptSuccess_L(\"isInteger(3.5);\", false);\n\tEidosAssertScriptSuccess_L(\"isInteger('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"isInteger(_Test(7));\", false);\n\tEidosAssertScriptSuccess_L(\"isInteger(object());\", false);\n\t\n\t// isLogical()\n\tEidosAssertScriptSuccess_L(\"isLogical(NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"isLogical(T);\", true);\n\tEidosAssertScriptSuccess_L(\"isLogical(3);\", false);\n\tEidosAssertScriptSuccess_L(\"isLogical(3.5);\", false);\n\tEidosAssertScriptSuccess_L(\"isLogical('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"isLogical(_Test(7));\", false);\n\tEidosAssertScriptSuccess_L(\"isLogical(object());\", false);\n\t\n\t// isNULL()\n\tEidosAssertScriptSuccess_L(\"isNULL(NULL);\", true);\n\tEidosAssertScriptSuccess_L(\"isNULL(T);\", false);\n\tEidosAssertScriptSuccess_L(\"isNULL(3);\", false);\n\tEidosAssertScriptSuccess_L(\"isNULL(3.5);\", false);\n\tEidosAssertScriptSuccess_L(\"isNULL('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"isNULL(_Test(7));\", false);\n\tEidosAssertScriptSuccess_L(\"isNULL(object());\", false);\n\t\n\t// isObject()\n\tEidosAssertScriptSuccess_L(\"isObject(NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"isObject(T);\", false);\n\tEidosAssertScriptSuccess_L(\"isObject(3);\", false);\n\tEidosAssertScriptSuccess_L(\"isObject(3.5);\", false);\n\tEidosAssertScriptSuccess_L(\"isObject('foo');\", false);\n\tEidosAssertScriptSuccess_L(\"isObject(_Test(7));\", true);\n\tEidosAssertScriptSuccess_L(\"isObject(object());\", true);\n\t\n\t// isString()\n\tEidosAssertScriptSuccess_L(\"isString(NULL);\", false);\n\tEidosAssertScriptSuccess_L(\"isString(T);\", false);\n\tEidosAssertScriptSuccess_L(\"isString(3);\", false);\n\tEidosAssertScriptSuccess_L(\"isString(3.5);\", false);\n\tEidosAssertScriptSuccess_L(\"isString('foo');\", true);\n\tEidosAssertScriptSuccess_L(\"isString(_Test(7));\", false);\n\tEidosAssertScriptSuccess_L(\"isString(object());\", false);\n\t\n\t// type()\n\tEidosAssertScriptSuccess_S(\"type(NULL);\", \"NULL\");\n\tEidosAssertScriptSuccess_S(\"type(T);\", \"logical\");\n\tEidosAssertScriptSuccess_S(\"type(3);\", \"integer\");\n\tEidosAssertScriptSuccess_S(\"type(3.5);\", \"float\");\n\tEidosAssertScriptSuccess_S(\"type('foo');\", \"string\");\n\tEidosAssertScriptSuccess_S(\"type(_Test(7));\", \"object\");\n\tEidosAssertScriptSuccess_S(\"type(object());\", \"object\");\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_operators_arithmetic.cpp",
    "content": "//\n//  eidos_test_operators_arithmetic.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n#include <limits>\n\n\n#pragma mark operator +\nvoid _RunOperatorPlusTests1(void)\n{\n\t// operator +\n\tEidosAssertScriptRaise(\"NULL+T;\", 4, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"NULL+0;\", 4, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"NULL+0.5;\", 4, \"combination of operand types\");\n\tEidosAssertScriptSuccess_S(\"NULL+'foo';\", \"NULLfoo\");\n\tEidosAssertScriptRaise(\"NULL+_Test(7);\", 4, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"NULL+(0:2);\", 4, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"T+NULL;\", 1, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"0+NULL;\", 1, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"0.5+NULL;\", 3, \"combination of operand types\");\n\tEidosAssertScriptSuccess_S(\"'foo'+NULL;\", \"fooNULL\");\n\tEidosAssertScriptRaise(\"_Test(7)+NULL;\", 8, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"(0:2)+NULL;\", 5, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"+NULL;\", 0, \"operand type NULL is not supported\");\n\tEidosAssertScriptSuccess_I(\"1+1;\", 2);\n\tEidosAssertScriptSuccess(\"1+-1;\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_IV(\"(0:2)+10;\", {10, 11, 12});\n\tEidosAssertScriptSuccess_IV(\"10+(0:2);\", {10, 11, 12});\n\tEidosAssertScriptSuccess_IV(\"(15:13)+(0:2);\", {15, 15, 15});\n\tEidosAssertScriptRaise(\"(15:12)+(0:2);\", 7, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"1+1.0;\", 2);\n\tEidosAssertScriptSuccess_F(\"1.0+1;\", 2);\n\tEidosAssertScriptSuccess_F(\"1.0+-1.0;\", 0);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)+10;\", {10, 11, 12});\n\tEidosAssertScriptSuccess_FV(\"10.0+(0:2);\", {10, 11, 12});\n\tEidosAssertScriptSuccess_FV(\"10+(0.0:2);\", {10, 11, 12});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)+(0:2.0);\", {15, 15, 15});\n\tEidosAssertScriptRaise(\"(15:12.0)+(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptSuccess_S(\"'foo'+5;\", \"foo5\");\n\tEidosAssertScriptSuccess_S(\"'foo'+5.0;\", \"foo5.0\");\n\tEidosAssertScriptSuccess_S(\"'foo'+5.1;\", \"foo5.1\");\n\tEidosAssertScriptSuccess_S(\"5+'foo';\", \"5foo\");\n\tEidosAssertScriptSuccess_S(\"5.0+'foo';\", \"5.0foo\");\n\tEidosAssertScriptSuccess_S(\"5.1+'foo';\", \"5.1foo\");\n\tEidosAssertScriptSuccess_SV(\"'foo'+1:3;\", {\"foo1\", \"foo2\", \"foo3\"});\n\tEidosAssertScriptSuccess_SV(\"1:3+'foo';\", {\"1foo\", \"2foo\", \"3foo\"});\n\tEidosAssertScriptSuccess_S(\"'foo'+'bar';\", \"foobar\");\n\tEidosAssertScriptSuccess_SV(\"'foo'+c('bar', 'baz');\", {\"foobar\", \"foobaz\"});\n\tEidosAssertScriptSuccess_SV(\"c('bar', 'baz')+'foo';\", {\"barfoo\", \"bazfoo\"});\n\tEidosAssertScriptSuccess_SV(\"c('bar', 'baz')+c('foo', 'biz');\", {\"barfoo\", \"bazbiz\"});\n\tEidosAssertScriptRaise(\"c('bar', 'baz')+c('foo', 'biz', 'boz');\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_SV(\"c('bar', 'baz')+T;\", {\"barT\", \"bazT\"});\n\tEidosAssertScriptSuccess_SV(\"F+c('bar', 'baz');\", {\"Fbar\", \"Fbaz\"});\n\tEidosAssertScriptRaise(\"T+F;\", 1, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"T+T;\", 1, \"combination of operand types\");\n\tEidosAssertScriptRaise(\"F+F;\", 1, \"combination of operand types\");\n\tEidosAssertScriptSuccess_I(\"+5;\", 5);\n\tEidosAssertScriptSuccess_F(\"+5.0;\", 5);\n\tEidosAssertScriptRaise(\"+'foo';\", 0, \"is not supported by\");\n\tEidosAssertScriptRaise(\"+T;\", 0, \"is not supported by\");\n\tEidosAssertScriptSuccess_I(\"3+4+5;\", 12);\n\tEidosAssertScriptSuccess(\"3.2+NAN+4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"3.5+c(5.5,NAN,2.5);\", {9.0, std::numeric_limits<double>::quiet_NaN(), 6.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)+3.5;\", {9.0, std::numeric_limits<double>::quiet_NaN(), 6.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)+c(5.5,3.5,NAN);\", {11.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator +: raise on integer addition overflow for all code paths\n\tEidosAssertScriptSuccess_I(\"5e18;\", 5000000000000000000LL);\n\tEidosAssertScriptRaise(\"1e19;\", 0, \"could not be represented\");\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"5e18 + 5e18;\", 5, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"5e18 + c(0, 0, 5e18, 0);\", 5, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"c(0, 0, 5e18, 0) + 5e18;\", 17, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"c(0, 0, 5e18, 0) + c(0, 0, 5e18, 0);\", 17, \"overflow with the binary\");\n#endif\n\t\n\t// operator +: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\t// this is the only place where we test the binary operators with matrices and arrays so comprehensively; the same machinery is used for all, so it should suffice\n\tEidosAssertScriptSuccess_L(\"identical(1 + integer(0), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + 2, 3);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + 1:3, 2:4);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + matrix(2), matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(2,c(1,1,1)), array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + matrix(1:3,nrow=1), matrix(2:4, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + matrix(1:3,ncol=1), matrix(2:4, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + matrix(1:6,ncol=2), matrix(2:7, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1 + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", true);\n\t\n\tEidosAssertScriptRaise(\"identical(1:3 + integer(0), integer(0));\", 14, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + 2, 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + 1:3, (1:3)*2);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(2), 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + array(2,c(1,1,1)), 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(1:3,nrow=1), matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(1:3,ncol=1), matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + matrix(1:6,ncol=2), matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + array(1:3,c(3,1,1)), array((1:3)*2, c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + array(1:3,c(1,3,1)), array((1:3)*2, c(1,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + array(1:3,c(1,1,3)), array((1:3)*2, c(1,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(3,2,1)), array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(3,1,2)), array((1:6)*2, c(3,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(2,3,1)), array((1:6)*2, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(1,3,2)), array((1:6)*2, c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(2,1,3)), array((1:6)*2, c(2,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(1,2,3)), array((1:6)*2, c(1,2,3)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1) + integer(0), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1) + 2, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1) + 1:3, 2:4);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1) + matrix(2), matrix(3));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + matrix(1:3,nrow=1), matrix(2:4, nrow=1));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + matrix(1:3,ncol=1), matrix(2:4, ncol=1));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + matrix(1:6,ncol=2), matrix(2:7, ncol=2));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 20, \"non-conformable\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(array(1,c(1,1,1)) + integer(0), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1,c(1,1,1)) + 2, array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1,c(1,1,1)) + 1:3, 2:4);\", true);\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + matrix(2), matrix(3));\", 28, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(array(1,c(1,1,1)) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + matrix(1:3,nrow=1), matrix(2:4, nrow=1));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + matrix(1:3,ncol=1), matrix(2:4, ncol=1));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + matrix(1:6,ncol=2), matrix(2:7, ncol=2));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1,c(1,1,1)) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 28, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + integer(0), integer(0));\", 29, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + 2, matrix(3:5, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + 1:3, matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + matrix(2), matrix(3));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + matrix(1:3,nrow=1), matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + matrix(1:3,ncol=1), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + matrix(1:6,ncol=2), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 29, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + integer(0), integer(0));\", 29, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + 2, matrix(3:5, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + 1:3, matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + matrix(2), matrix(3));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + matrix(1:3,nrow=1), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + matrix(1:3,ncol=1), matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + matrix(1:6,ncol=2), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 29, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + integer(0), integer(0));\", 29, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + 2, matrix(3:8, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + 1:6, matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(2), matrix(3));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(1:6,nrow=1), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(1:6,ncol=1), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + matrix(1:6,ncol=2), matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(3,2,1)), array(2:7, c(3,2,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 29, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + integer(0), integer(0));\", 30, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + 2, array(3:8, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + 1:6, array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(2), matrix(3));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(2,c(1,1,1)), array(3, c(1,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:6,nrow=1), matrix(2:4, nrow=1));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:6,ncol=1), matrix(2:4, ncol=1));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:6,ncol=2), matrix((1:6)*2, ncol=2));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:3,c(3,1,1)), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:3,c(1,3,1)), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:3,c(1,1,3)), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(3,2,1)), array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(3,1,2)), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(2,3,1)), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(1,3,2)), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(2,1,3)), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(1,2,3)), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n}\n\nvoid _RunOperatorPlusTests2(void)\n{\n\t// operator +: identical to the previous tests, but with the order of the operands switched; should behave identically,\n\t// except that the error positions change, unfortunately.  Xcode search-replace to generate this from the above:\n\t// identical\\(([A-Za-z0-9:(),=]+) \\+ ([A-Za-z0-9:(),=]+), \n\t// identical\\($2 + $1, \n\tEidosAssertScriptSuccess_L(\"identical(integer(0) + 1, integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 + 1, 3);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + 1, 2:4);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(2) + 1, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(2,c(1,1,1)) + 1, array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + 1, matrix(2:4, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + 1, matrix(2:4, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + 1, matrix(2:7, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(3,1,1)) + 1, array(2:4, c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(1,3,1)) + 1, array(2:4, c(1,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(1,1,3)) + 1, array(2:4, c(1,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + 1, array(2:7, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,1,2)) + 1, array(2:7, c(3,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(2,3,1)) + 1, array(2:7, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(1,3,2)) + 1, array(2:7, c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(2,1,3)) + 1, array(2:7, c(2,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(1,2,3)) + 1, array(2:7, c(1,2,3)));\", true);\n\t\n\tEidosAssertScriptRaise(\"identical(integer(0) + 1:3, integer(0));\", 21, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(2 + 1:3, 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + 1:3, (1:3)*2);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(2) + 1:3, 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(2,c(1,1,1)) + 1:3, 3:5);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + 1:3, matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + 1:3, matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + 1:6, matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(3,1,1)) + 1:3, array((1:3)*2, c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(1,3,1)) + 1:3, array((1:3)*2, c(1,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:3,c(1,1,3)) + 1:3, array((1:3)*2, c(1,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + 1:6, array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,1,2)) + 1:6, array((1:6)*2, c(3,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(2,3,1)) + 1:6, array((1:6)*2, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(1,3,2)) + 1:6, array((1:6)*2, c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(2,1,3)) + 1:6, array((1:6)*2, c(2,1,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(1,2,3)) + 1:6, array((1:6)*2, c(1,2,3)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(integer(0) + matrix(1), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 + matrix(1), matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(1), 2:4);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(2) + matrix(1), matrix(3));\", true);\n\tEidosAssertScriptRaise(\"identical(array(2,c(1,1,1)) + matrix(1), array(3, c(1,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + matrix(1), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + matrix(1), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(1), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + matrix(1), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + matrix(1), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + matrix(1), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1), array(2:7, c(3,2,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + matrix(1), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + matrix(1), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + matrix(1), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + matrix(1), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + matrix(1), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n\t\n\tEidosAssertScriptSuccess_L(\"identical(integer(0) + array(1,c(1,1,1)), integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 + array(1,c(1,1,1)), array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + array(1,c(1,1,1)), 2:4);\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(2) + array(1,c(1,1,1)), matrix(3));\", 20, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(array(2,c(1,1,1)) + array(1,c(1,1,1)), array(3, c(1,1,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + array(1,c(1,1,1)), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + array(1,c(1,1,1)), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1,c(1,1,1)), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + array(1,c(1,1,1)), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + array(1,c(1,1,1)), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + array(1,c(1,1,1)), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + array(1,c(1,1,1)), array(2:7, c(3,2,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + array(1,c(1,1,1)), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + array(1,c(1,1,1)), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + array(1,c(1,1,1)), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + array(1,c(1,1,1)), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + array(1,c(1,1,1)), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(integer(0) + matrix(1:3,nrow=1), integer(0));\", 21, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(2 + matrix(1:3,nrow=1), matrix(3:5, nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(1:3,nrow=1), matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(2) + matrix(1:3,nrow=1), matrix(3));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(2,c(1,1,1)) + matrix(1:3,nrow=1), array(3, c(1,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,nrow=1) + matrix(1:3,nrow=1), matrix((1:3)*2, nrow=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,ncol=1) + matrix(1:3,nrow=1), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(1:3,nrow=1), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + matrix(1:3,nrow=1), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + matrix(1:3,nrow=1), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + matrix(1:3,nrow=1), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:3,nrow=1), array(2:7, c(3,2,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + matrix(1:3,nrow=1), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + matrix(1:3,nrow=1), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + matrix(1:3,nrow=1), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + matrix(1:3,nrow=1), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + matrix(1:3,nrow=1), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(integer(0) + matrix(1:3,ncol=1), integer(0));\", 21, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(2 + matrix(1:3,ncol=1), matrix(3:5, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 + matrix(1:3,ncol=1), matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(2) + matrix(1:3,ncol=1), matrix(3));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(2,c(1,1,1)) + matrix(1:3,ncol=1), array(3, c(1,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) + matrix(1:3,ncol=1), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3,ncol=1) + matrix(1:3,ncol=1), matrix((1:3)*2, ncol=1));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + matrix(1:3,ncol=1), matrix(2:7, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + matrix(1:3,ncol=1), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + matrix(1:3,ncol=1), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + matrix(1:3,ncol=1), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:3,ncol=1), array(2:7, c(3,2,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + matrix(1:3,ncol=1), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + matrix(1:3,ncol=1), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + matrix(1:3,ncol=1), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + matrix(1:3,ncol=1), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + matrix(1:3,ncol=1), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(integer(0) + matrix(1:6,ncol=2), integer(0));\", 21, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(2 + matrix(1:6,ncol=2), matrix(3:8, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + matrix(1:6,ncol=2), matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(2) + matrix(1:6,ncol=2), matrix(3));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(2,c(1,1,1)) + matrix(1:6,ncol=2), array(3, c(1,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,nrow=1) + matrix(1:6,ncol=2), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=1) + matrix(1:6,ncol=2), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:6,ncol=2) + matrix(1:6,ncol=2), matrix((1:6)*2, ncol=2));\", true);\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + matrix(1:6,ncol=2), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + matrix(1:6,ncol=2), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + matrix(1:6,ncol=2), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,2,1)) + matrix(1:6,ncol=2), array(2:7, c(3,2,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + matrix(1:6,ncol=2), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + matrix(1:6,ncol=2), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + matrix(1:6,ncol=2), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + matrix(1:6,ncol=2), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + matrix(1:6,ncol=2), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n\t\n\tEidosAssertScriptRaise(\"identical(integer(0) + array(1:6,c(3,2,1)), integer(0));\", 21, \"requires that either\");\n\tEidosAssertScriptSuccess_L(\"identical(2 + array(1:6,c(3,2,1)), array(3:8, c(3,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:6 + array(1:6,c(3,2,1)), array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(2) + array(1:6,c(3,2,1)), matrix(3));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(2,c(1,1,1)) + array(1:6,c(3,2,1)), array(3, c(1,1,1)));\", 28, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,nrow=1) + array(1:6,c(3,2,1)), matrix(2:4, nrow=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=1) + array(1:6,c(3,2,1)), matrix(2:4, ncol=1));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:6,ncol=2) + array(1:6,c(3,2,1)), matrix((1:6)*2, ncol=2));\", 29, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(3,1,1)) + array(1:6,c(3,2,1)), array(2:4, c(3,1,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,3,1)) + array(1:6,c(3,2,1)), array(2:4, c(1,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:3,c(1,1,3)) + array(1:6,c(3,2,1)), array(2:4, c(1,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(array(1:6,c(3,2,1)) + array(1:6,c(3,2,1)), array((1:6)*2, c(3,2,1)));\", true);\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(3,1,2)) + array(1:6,c(3,2,1)), array(2:7, c(3,1,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,3,1)) + array(1:6,c(3,2,1)), array(2:7, c(2,3,1)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,3,2)) + array(1:6,c(3,2,1)), array(2:7, c(1,3,2)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(2,1,3)) + array(1:6,c(3,2,1)), array(2:7, c(2,1,3)));\", 30, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(array(1:6,c(1,2,3)) + array(1:6,c(3,2,1)), array(2:7, c(1,2,3)));\", 30, \"non-conformable\");\n}\n\n#pragma mark operator -\nvoid _RunOperatorMinusTests(void)\n{\n\t// operator -\n\tEidosAssertScriptRaise(\"NULL-T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL-0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL-0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL-'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL-_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL-(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T-NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0-NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5-NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'-NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)-NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)-NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"-NULL;\", 0, \"is not supported by\");\n\tEidosAssertScriptSuccess(\"1-1;\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"1--1;\", 2);\n\tEidosAssertScriptSuccess_IV(\"(0:2)-10;\", {-10, -9, -8});\n\tEidosAssertScriptSuccess_IV(\"10-(0:2);\", {10, 9, 8});\n\tEidosAssertScriptSuccess_IV(\"(15:13)-(0:2);\", {15, 13, 11});\n\tEidosAssertScriptRaise(\"(15:12)-(0:2);\", 7, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"1-1.0;\", 0);\n\tEidosAssertScriptSuccess_F(\"1.0-1;\", 0);\n\tEidosAssertScriptSuccess_F(\"1.0--1.0;\", 2);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)-10;\", {-10, -9, -8});\n\tEidosAssertScriptSuccess_FV(\"10.0-(0:2);\", {10, 9, 8});\n\tEidosAssertScriptSuccess_FV(\"10-(0.0:2);\", {10, 9, 8});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)-(0:2.0);\", {15, 13, 11});\n\tEidosAssertScriptRaise(\"(15:12.0)-(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"'foo'-1;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T-F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T-T;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F-F;\", 1, \"is not supported by\");\n\tEidosAssertScriptSuccess_I(\"-5;\", -5);\n\tEidosAssertScriptSuccess_F(\"-5.0;\", -5);\n\tEidosAssertScriptSuccess_IV(\"-c(5, -6);\", {-5, 6});\n\tEidosAssertScriptSuccess_FV(\"-c(5.0, -6.0);\", {-5, 6});\n\tEidosAssertScriptRaise(\"-'foo';\", 0, \"is not supported by\");\n\tEidosAssertScriptRaise(\"-T;\", 0, \"is not supported by\");\n\tEidosAssertScriptSuccess_I(\"3-4-5;\", -6);\n\tEidosAssertScriptSuccess(\"3.2-NAN-4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"3.5-c(5.5,NAN,2.5);\", {-2.0, std::numeric_limits<double>::quiet_NaN(), 1.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)-3.5;\", {2.0, std::numeric_limits<double>::quiet_NaN(), -1.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)-c(5.5,3.5,NAN);\", {0.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator -: raise on integer subtraction overflow for all code paths\n\tEidosAssertScriptSuccess_I(\"9223372036854775807;\", INT64_MAX);\n\tEidosAssertScriptSuccess_I(\"-9223372036854775807 - 1;\", INT64_MIN);\n\tEidosAssertScriptSuccess_I(\"-5e18;\", -5000000000000000000LL);\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"-(-9223372036854775807 - 1);\", 0, \"overflow with the unary\");\n\tEidosAssertScriptRaise(\"-c(-9223372036854775807 - 1, 10);\", 0, \"overflow with the unary\");\n\tEidosAssertScriptRaise(\"-5e18 - 5e18;\", 6, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"-5e18 - c(0, 0, 5e18, 0);\", 6, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"c(0, 0, -5e18, 0) - 5e18;\", 18, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"c(0, 0, -5e18, 0) - c(0, 0, 5e18, 0);\", 18, \"overflow with the binary\");\n#endif\n\t\n\t// operator -: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(-matrix(2), matrix(-2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(-matrix(1:3), matrix(-1:-3));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(-array(2, c(1,1,1)), array(-2, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(-array(1:6, c(3,1,2)), array(-1:-6, c(3,1,2)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"identical(1-matrix(2), matrix(-1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1-matrix(1:3), matrix(0:-2));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3-matrix(2), -1:1);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4:6-matrix(1:3), matrix(c(3,3,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5)-matrix(2), matrix(3));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3)-matrix(2), matrix(3));\", 21, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1)-matrix(1:3,ncol=1), matrix(3));\", 28, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(7:9)-matrix(1:3), matrix(c(6,6,6)));\", true);\n}\n\n#pragma mark operator *\nvoid _RunOperatorMultTests(void)\n{\n    // operator *\n\tEidosAssertScriptRaise(\"NULL*T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL*0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL*0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL*'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL*_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL*(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T*NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0*NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5*NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'*NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)*NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)*NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"*NULL;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess(\"1*1;\", gStaticEidosValue_Integer1);\n    EidosAssertScriptSuccess_I(\"1*-1;\", -1);\n\tEidosAssertScriptSuccess_IV(\"(0:2)*10;\", {0, 10, 20});\n\tEidosAssertScriptSuccess_IV(\"10*(0:2);\", {0, 10, 20});\n\tEidosAssertScriptSuccess_IV(\"(15:13)*(0:2);\", {0, 14, 26});\n\tEidosAssertScriptRaise(\"(15:12)*(0:2);\", 7, \"operator requires that either\");\n    EidosAssertScriptSuccess_F(\"1*1.0;\", 1);\n    EidosAssertScriptSuccess_F(\"1.0*1;\", 1);\n    EidosAssertScriptSuccess_F(\"1.0*-1.0;\", -1);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)*10;\", {0, 10, 20});\n\tEidosAssertScriptSuccess_FV(\"10.0*(0:2);\", {0, 10, 20});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)*(0:2.0);\", {0, 14, 26});\n\tEidosAssertScriptRaise(\"(15:12.0)*(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"'foo'*5;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T*F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T*T;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F*F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"*5;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"*5.0;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"*'foo';\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"*T;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess_I(\"3*4*5;\", 60);\n\tEidosAssertScriptSuccess(\"3.0*NAN*4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"3.0*c(5.5,NAN,2.5);\", {16.5, std::numeric_limits<double>::quiet_NaN(), 7.5});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)*3.0;\", {16.5, std::numeric_limits<double>::quiet_NaN(), 7.5});\n\tEidosAssertScriptSuccess_FV(\"c(5.5,NAN,2.5)*c(5.0,3.5,NAN);\", {27.5, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator *: raise on integer multiplication overflow for all code paths\n\tEidosAssertScriptSuccess_I(\"5e18;\", 5000000000000000000LL);\n\tEidosAssertScriptRaise(\"1e19;\", 0, \"could not be represented\");\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"5e18 * 2;\", 5, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"5e18 * c(0, 0, 2, 0);\", 5, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"c(0, 0, 2, 0) * 5e18;\", 14, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"c(0, 0, 2, 0) * c(0, 0, 5e18, 0);\", 14, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"c(0, 0, 5e18, 0) * c(0, 0, 2, 0);\", 17, \"multiplication overflow\");\n#endif\n\t\n\t// operator *: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 * matrix(2), matrix(10));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 * matrix(1:3), matrix(c(5,10,15)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 * matrix(2), c(2,4,6));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4:6 * matrix(1:3), matrix(c(4,10,18)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) * matrix(2), matrix(10));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) * matrix(2), matrix(c(2,4,6)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(4:6,nrow=1) * matrix(1:3,ncol=1), matrix(c(4,10,18)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6:8) * matrix(1:3), matrix(c(6,14,24)));\", true);\n}\n\n#pragma mark operator /\nvoid _RunOperatorDivTests(void)\n{\n    // operator /\n\tEidosAssertScriptRaise(\"NULL/T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL/0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL/0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL/'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL/_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL/(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T/NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0/NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5/NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'/NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)/NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)/NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"/NULL;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess_F(\"1/1;\", 1);\n    EidosAssertScriptSuccess_F(\"1/-1;\", -1);\n\tEidosAssertScriptSuccess_FV(\"(0:2)/10;\", {0, 0.1, 0.2});\n\tEidosAssertScriptRaise(\"(15:12)/(0:2);\", 7, \"operator requires that either\");\n    EidosAssertScriptSuccess_F(\"1/1.0;\", 1);\n    EidosAssertScriptSuccess_F(\"1.0/1;\", 1);\n    EidosAssertScriptSuccess_F(\"1.0/-1.0;\", -1);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)/10;\", {0, 0.1, 0.2});\n\tEidosAssertScriptSuccess_FV(\"10.0/(0:2);\", {std::numeric_limits<double>::infinity(), 10, 5});\n\tEidosAssertScriptSuccess_FV(\"10/(0.0:2);\", {std::numeric_limits<double>::infinity(), 10, 5});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)/(0:2.0);\", {std::numeric_limits<double>::infinity(), 14, 6.5});\n\tEidosAssertScriptSuccess_F(\"1.0/0.0;\", std::numeric_limits<double>::infinity());\n\tEidosAssertScriptSuccess_F(\"1.0/-0.0;\", -std::numeric_limits<double>::infinity());\t// signed zeros as per IEEE 754\n\tEidosAssertScriptSuccess_F(\"0.0/0.0;\", std::numeric_limits<double>::quiet_NaN());\n\tEidosAssertScriptSuccess_F(\"INF/INF;\", std::numeric_limits<double>::quiet_NaN());\n\tEidosAssertScriptRaise(\"(15:12.0)/(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"'foo'/5;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T/F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T/T;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F/F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"/5;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"/5.0;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"/'foo';\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"/T;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess_F(\"3/4/5;\", 0.15);\n\tEidosAssertScriptSuccess(\"6/0;\", gStaticEidosValue_FloatINF);\n\tEidosAssertScriptSuccess(\"3.0/NAN/4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"2.0/c(5.0,NAN,2.5);\", {0.4, std::numeric_limits<double>::quiet_NaN(), 0.8});\n\tEidosAssertScriptSuccess_FV(\"c(5.0,NAN,2.5)/2.0;\", {2.5, std::numeric_limits<double>::quiet_NaN(), 1.25});\n\tEidosAssertScriptSuccess_FV(\"c(5.0,NAN,2.5)/c(5.0,3.5,NAN);\", {1.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator /: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 / matrix(2), matrix(2.5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(12 / matrix(1:3), matrix(c(12.0,6,4)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 / matrix(2), c(0.5,1,1.5));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4:6 / matrix(1:3), matrix(c(4,2.5,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) / matrix(2), matrix(2.5));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) / matrix(2), matrix(c(0.5,1,1.5)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(4:6,nrow=1) / matrix(1:3,ncol=1), matrix(c(4,2.5,2)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(7:9) / matrix(1:3), matrix(c(7.0,4,3)));\", true);\n}\n\n#pragma mark operator %\nvoid _RunOperatorModTests(void)\n{\n    // operator %\n\tEidosAssertScriptRaise(\"NULL%T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL%0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL%0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL%'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL%_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL%(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T%NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0%NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5%NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'%NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)%NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)%NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"%NULL;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess_F(\"1%1;\", 0);\n    EidosAssertScriptSuccess_F(\"1%-1;\", 0);\n\tEidosAssertScriptSuccess_FV(\"(0:2)%10;\", {0, 1, 2});\n\tEidosAssertScriptRaise(\"(15:12)%(0:2);\", 7, \"operator requires that either\");\n    EidosAssertScriptSuccess_F(\"1%1.0;\", 0);\n    EidosAssertScriptSuccess_F(\"1.0%1;\", 0);\n    EidosAssertScriptSuccess_F(\"1.0%-1.0;\", 0);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)%10;\", {0, 1, 2});\n\tEidosAssertScriptSuccess_FV(\"10.0%(0:4);\", {std::numeric_limits<double>::quiet_NaN(), 0, 0, 1, 2});\n\tEidosAssertScriptSuccess_FV(\"10%(0.0:4);\", {std::numeric_limits<double>::quiet_NaN(), 0, 0, 1, 2});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)%(0:2.0);\", {std::numeric_limits<double>::quiet_NaN(), 0, 1});\n\tEidosAssertScriptRaise(\"(15:12.0)%(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"'foo'%5;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T%F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T%T;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F%F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"%5;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"%5.0;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"%'foo';\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"%T;\", 0, \"unexpected token\");\n    EidosAssertScriptSuccess_F(\"3%4%5;\", 3);\n\tEidosAssertScriptSuccess(\"3.0%NAN%4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"2.0%c(5.0,NAN,2.5);\", {2.0, std::numeric_limits<double>::quiet_NaN(), 2.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.0,NAN,2.5)%2.0;\", {1.0, std::numeric_limits<double>::quiet_NaN(), 0.5});\n\tEidosAssertScriptSuccess_FV(\"c(6.0,NAN,2.5)%c(5.0,3.5,NAN);\", {1.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator %: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 % matrix(2), matrix(1.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 % matrix(1:3), matrix(c(0.0,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(1:3 % matrix(2), c(1.0,0,1));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4:6 % matrix(1:3), matrix(c(0.0,1,0)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) % matrix(2), matrix(1.0));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) % matrix(2), matrix(c(1.0,0,1)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(4:6,nrow=1) % matrix(1:3,ncol=1), matrix(c(0.0,1,0)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6:8) % matrix(1:3), matrix(c(0.0,1,2)));\", true);\n}\n\n#pragma mark operator :\nvoid _RunOperatorRangeTests(void)\n{\n\t// operator :\n\tEidosAssertScriptRaise(\"NULL:T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL:0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL:0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL:'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL:_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL:(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T:NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0:NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5:NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo':NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7):NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2):NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\":NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_IV(\"1:5;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"5:1;\", {5, 4, 3, 2, 1});\n\tEidosAssertScriptSuccess_IV(\"-2:1;\", {-2, -1, 0, 1});\n\tEidosAssertScriptSuccess_IV(\"1:-2;\", {1, 0, -1, -2});\n\tEidosAssertScriptSuccess(\"1:1;\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_FV(\"1.0:5;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_FV(\"5.0:1;\", {5, 4, 3, 2, 1});\n\tEidosAssertScriptSuccess_FV(\"-2.0:1;\", {-2, -1, 0, 1});\n\tEidosAssertScriptSuccess_FV(\"1.0:-2;\", {1, 0, -1, -2});\n\tEidosAssertScriptSuccess_F(\"1.0:1;\", 1);\n\tEidosAssertScriptSuccess_FV(\"1:5.0;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_FV(\"5:1.0;\", {5, 4, 3, 2, 1});\n\tEidosAssertScriptSuccess_FV(\"-2:1.0;\", {-2, -1, 0, 1});\n\tEidosAssertScriptSuccess_FV(\"1:-2.0;\", {1, 0, -1, -2});\n\tEidosAssertScriptSuccess_F(\"1:1.0;\", 1);\n\tEidosAssertScriptRaise(\"1:F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F:1;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T:F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'a':'z';\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"1:(2:3);\", 1, \"operator must have size()\");\n\tEidosAssertScriptRaise(\"(1:2):3;\", 5, \"operator must have size()\");\n\tEidosAssertScriptSuccess_FV(\"1.5:4.7;\", {1.5, 2.5, 3.5, 4.5});\n\tEidosAssertScriptSuccess_FV(\"1.5:-2.7;\", {1.5, 0.5, -0.5, -1.5, -2.5});\n\tEidosAssertScriptRaise(\"1.5:INF;\", 3, \"range with more than\");\n\tEidosAssertScriptRaise(\"1.5:NAN;\", 3, \"must not be NAN\");\n\tEidosAssertScriptRaise(\"INF:1.5;\", 3, \"range with more than\");\n\tEidosAssertScriptRaise(\"NAN:1.5;\", 3, \"must not be NAN\");\n\tEidosAssertScriptRaise(\"1:100000010;\", 1, \"more than 100000000 entries\");\n\tEidosAssertScriptRaise(\"100000010:1;\", 9, \"more than 100000000 entries\");\n\t\n\tEidosAssertScriptRaise(\"matrix(5):9;\", 9, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"1:matrix(5);\", 1, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"matrix(3):matrix(5);\", 9, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"matrix(5:8):9;\", 11, \"must have size() == 1\");\n\tEidosAssertScriptRaise(\"1:matrix(5:8);\", 1, \"must have size() == 1\");\n\tEidosAssertScriptRaise(\"matrix(1:3):matrix(5:7);\", 11, \"must have size() == 1\");\n}\n\n#pragma mark operator ^\nvoid _RunOperatorExpTests(void)\n{\n\t// operator ^\n\tEidosAssertScriptRaise(\"NULL^T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL^0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL^0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL^'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL^_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL^(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T^NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0^NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5^NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'^NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)^NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)^NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"^NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_F(\"1^1;\", 1);\n\tEidosAssertScriptSuccess_F(\"1^-1;\", 1);\n\tEidosAssertScriptSuccess_FV(\"(0:2)^10;\", {0, 1, 1024});\n\tEidosAssertScriptSuccess_FV(\"10^(0:2);\", {1, 10, 100});\n\tEidosAssertScriptSuccess_FV(\"(15:13)^(0:2);\", {1, 14, 169});\n\tEidosAssertScriptRaise(\"(15:12)^(0:2);\", 7, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"NULL^(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptSuccess_F(\"1^1.0;\", 1);\n\tEidosAssertScriptSuccess_F(\"1.0^1;\", 1);\n\tEidosAssertScriptSuccess_F(\"1.0^-1.0;\", 1);\n\tEidosAssertScriptSuccess_FV(\"(0:2.0)^10;\", {0, 1, 1024});\n\tEidosAssertScriptSuccess_FV(\"10.0^(0:2);\", {1, 10, 100});\n\tEidosAssertScriptSuccess_FV(\"10^(0.0:2);\", {1, 10, 100});\n\tEidosAssertScriptSuccess_FV(\"(15.0:13)^(0:2.0);\", {1, 14, 169});\n\tEidosAssertScriptRaise(\"(15:12.0)^(0:2);\", 9, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"NULL^(0:2.0);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'^5;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T^F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T^T;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"F^F;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"^5;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"^5.0;\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"^'foo';\", 0, \"unexpected token\");\n\tEidosAssertScriptRaise(\"^T;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_F(\"4^(3^2);\", 262144);\t\t// right-associative!\n\tEidosAssertScriptSuccess_F(\"4^3^2;\", 262144);\t\t// right-associative!\n\tEidosAssertScriptSuccess(\"3.0^NAN^4.5;\", gStaticEidosValue_FloatNAN);\n\tEidosAssertScriptSuccess_FV(\"4.0^c(5.0,NAN,2.5);\", {1024.0, std::numeric_limits<double>::quiet_NaN(), 32.0});\n\tEidosAssertScriptSuccess_FV(\"c(5.0,NAN,2.5)^2.0;\", {25.0, std::numeric_limits<double>::quiet_NaN(), 6.25});\n\tEidosAssertScriptSuccess_FV(\"c(6.0,NAN,2.5)^c(5.0,3.5,NAN);\", {7776.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()});\n\t\n\t// operator ^: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 ^ matrix(2), matrix(25.0));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 ^ matrix(1:3), matrix(c(2.0,4,8)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) ^ matrix(2), c(1.0,4,9));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((2:4) ^ matrix(1:3), matrix(c(2.0,9,64)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) ^ matrix(2), matrix(25.0));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) ^ matrix(2), matrix(c(1.0,4,9)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(2:4,nrow=1) ^ matrix(1:3,ncol=1), matrix(c(2.0,9,64)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(2:4) ^ matrix(1:3), matrix(c(2.0,9,64)));\", true);\n\t\n\t// operator ^ precedence and associativity tests\n\tEidosAssertScriptSuccess_F(\"-2^2;\", -4);\n\tEidosAssertScriptSuccess_FV(\"x=1:3; y=1:3; -x^y;\", {-1, -4, -27});\n\tEidosAssertScriptSuccess_F(\"-2.0^2;\", -4);\n\tEidosAssertScriptSuccess_F(\"-2^2.0;\", -4);\n\tEidosAssertScriptSuccess_F(\"-2.0^2.0;\", -4);\n\tEidosAssertScriptSuccess_FV(\"x=1.0:3; y=1:3; -x^y;\", {-1, -4, -27});\n\tEidosAssertScriptSuccess_FV(\"x=1:3; y=1.0:3; -x^y;\", {-1, -4, -27});\n\tEidosAssertScriptSuccess_FV(\"x=1.0:3; y=1.0:3; -x^y;\", {-1, -4, -27});\n\tEidosAssertScriptSuccess_F(\"2^2^4;\", 65536);\n\tEidosAssertScriptSuccess_F(\"1/(2^-2^4);\", 65536);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_operators_comparison.cpp",
    "content": "//\n//  eidos_test_operators_comparison.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n\n#pragma mark operator >\nvoid _RunOperatorGtTests(void)\n{\n\t// operator >\n\tEidosAssertScriptRaise(\"NULL>T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>'foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>_Test(7);\", 4, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"NULL>(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T>NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0>NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5>NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'>NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)>NULL;\", 8, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"(0:2)>NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\">NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T > F;\", true);\n\tEidosAssertScriptSuccess_L(\"T > T;\", false);\n\tEidosAssertScriptSuccess_L(\"F > T;\", false);\n\tEidosAssertScriptSuccess_L(\"F > F;\", false);\n\tEidosAssertScriptSuccess_L(\"T > 0;\", true);\n\tEidosAssertScriptSuccess_L(\"T > 1;\", false);\n\tEidosAssertScriptSuccess_L(\"F > 0;\", false);\n\tEidosAssertScriptSuccess_L(\"F > 1;\", false);\n\tEidosAssertScriptSuccess_L(\"T > -5;\", true);\n\tEidosAssertScriptSuccess_L(\"-5 > T;\", false);\n\tEidosAssertScriptSuccess_L(\"T > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 > T;\", true);\n\tEidosAssertScriptSuccess_L(\"T > -5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-5.0 > T;\", false);\n\tEidosAssertScriptSuccess_L(\"T > 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 > T;\", true);\n\tEidosAssertScriptSuccess_L(\"T > 'FOO';\", true);\n\tEidosAssertScriptSuccess_L(\"'FOO' > T;\", false);\n\tEidosAssertScriptSuccess_L(\"T > 'XYZZY';\", false);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' > T;\", true);\n\tEidosAssertScriptSuccess_L(\"5 > -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 > -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 > 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 > -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' > 'bar';\", true);\n\tEidosAssertScriptSuccess_L(\"'bar' > 'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"120 > '10';\", true);\n\tEidosAssertScriptSuccess_L(\"10 > '120';\", false);\n\tEidosAssertScriptSuccess_L(\"120 > '15';\", false);\n\tEidosAssertScriptSuccess_L(\"15 > '120';\", true);\n\tEidosAssertScriptRaise(\"_Test(9) > 5;\", 9, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"5 > _Test(9);\", 2, \"cannot be used with type\");\n\tEidosAssertScriptSuccess_L(\"5 > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 > -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 > 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 > '5';\", false);\n\tEidosAssertScriptSuccess_L(\"'5' > 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' > 'foo';\", false);\n\tEidosAssertScriptRaise(\"_Test(9) > _Test(9);\", 9, \"cannot be used with type\");\n\t\n\tEidosAssertScriptSuccess_LV(\"T > c(T, F);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"5 > c(5, 6);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"5.0 > c(5.0, 6.0);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"'foo' > c('foo', 'bar');\", {false, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) > T;\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) > 5;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) > 5.0;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') > 'foo';\", {false, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) > c(T, T);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) > c(5, 8);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) > c(5.0, 8.0);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') > c('foo', 'baz');\", {false, false});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN > NAN;\", false);\n\tEidosAssertScriptSuccess_L(\"NAN > 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 > NAN;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) > c(5.0, 5.0, 5.0);\", {false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) > c(5.0, 5.0, NAN);\", {false, true, false});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) > c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator >: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(4 > 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 > 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 > 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4 > matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 > matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 > matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 > matrix(1:3), matrix(c(T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) > matrix(2), c(F,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) > matrix(3:1), matrix(c(F,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(4) > matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) > matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6) > matrix(5), matrix(T));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) > matrix(2), matrix(c(F,F,T)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) > matrix(3:1,ncol=1), matrix(c(F,F,T)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) > matrix(3:1), matrix(c(F,F,T)));\", true);\n}\n\n#pragma mark operator <\nvoid _RunOperatorLtTests(void)\n{\n\t// operator <\n\tEidosAssertScriptRaise(\"NULL<T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<'foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<_Test(7);\", 4, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"NULL<(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T<NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0<NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5<NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'<NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)<NULL;\", 8, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"(0:2)<NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"<NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T < F;\", false);\n\tEidosAssertScriptSuccess_L(\"T < T;\", false);\n\tEidosAssertScriptSuccess_L(\"F < T;\", true);\n\tEidosAssertScriptSuccess_L(\"F < F;\", false);\n\tEidosAssertScriptSuccess_L(\"T < 0;\", false);\n\tEidosAssertScriptSuccess_L(\"T < 1;\", false);\n\tEidosAssertScriptSuccess_L(\"F < 0;\", false);\n\tEidosAssertScriptSuccess_L(\"F < 1;\", true);\n\tEidosAssertScriptSuccess_L(\"T < -5;\", false);\n\tEidosAssertScriptSuccess_L(\"-5 < T;\", true);\n\tEidosAssertScriptSuccess_L(\"T < 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 < T;\", false);\n\tEidosAssertScriptSuccess_L(\"T < -5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-5.0 < T;\", true);\n\tEidosAssertScriptSuccess_L(\"T < 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 < T;\", false);\n\tEidosAssertScriptSuccess_L(\"T < 'FOO';\", false);\n\tEidosAssertScriptSuccess_L(\"'FOO' < T;\", true);\n\tEidosAssertScriptSuccess_L(\"T < 'XYZZY';\", true);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' < T;\", false);\n\tEidosAssertScriptSuccess_L(\"5 < -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 < 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 < -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 < 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 < -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 < 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' < 'bar';\", false);\n\tEidosAssertScriptSuccess_L(\"'bar' < 'foo';\", true);\n\tEidosAssertScriptSuccess_L(\"120 < '10';\", false);\n\tEidosAssertScriptSuccess_L(\"10 < '120';\", true);\n\tEidosAssertScriptSuccess_L(\"120 < '15';\", true);\n\tEidosAssertScriptSuccess_L(\"15 < '120';\", false);\n\tEidosAssertScriptRaise(\"_Test(9) < 5;\", 9, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"5 < _Test(9);\", 2, \"cannot be used with type\");\n\tEidosAssertScriptSuccess_L(\"5 < 5;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 < -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 < 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 < 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 < '5';\", false);\n\tEidosAssertScriptSuccess_L(\"'5' < 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' < 'foo';\", false);\n\tEidosAssertScriptRaise(\"_Test(9) < _Test(9);\", 9, \"cannot be used with type\");\n\t\n\tEidosAssertScriptSuccess_LV(\"T < c(T, F);\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"5 < c(5, 6);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"5.0 < c(5.0, 6.0);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"'foo' < c('foo', 'bar');\", {false, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) < T;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) < 5;\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) < 5.0;\", {false, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') < 'foo';\", {false, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) < c(T, T);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) < c(5, 8);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) < c(5.0, 8.0);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') < c('foo', 'baz');\", {false, true});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN < NAN;\", false);\n\tEidosAssertScriptSuccess_L(\"NAN < 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 < NAN;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) < c(5.0, 5.0, 5.0);\", {false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) < c(5.0, 5.0, NAN);\", {false, false, false});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) < c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator <: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(4 < 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 < 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 < 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4 < matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 < matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 < matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 < matrix(1:3), matrix(c(F,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) < matrix(2), c(T,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) < matrix(3:1), matrix(c(T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(4) < matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) < matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6) < matrix(5), matrix(F));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) < matrix(2), matrix(c(T,F,F)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) < matrix(3:1,ncol=1), matrix(c(T,F,F)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) < matrix(3:1), matrix(c(T,F,F)));\", true);\n}\n\n#pragma mark operator >=\nvoid _RunOperatorGtEqTests(void)\n{\n\t// operator >=\n\tEidosAssertScriptRaise(\"NULL>=T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>=0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>=0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>='foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL>=_Test(7);\", 4, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"NULL>=(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T>=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0>=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5>=NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'>=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)>=NULL;\", 8, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"(0:2)>=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\">=NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T >= F;\", true);\n\tEidosAssertScriptSuccess_L(\"T >= T;\", true);\n\tEidosAssertScriptSuccess_L(\"F >= T;\", false);\n\tEidosAssertScriptSuccess_L(\"F >= F;\", true);\n\tEidosAssertScriptSuccess_L(\"T >= 0;\", true);\n\tEidosAssertScriptSuccess_L(\"T >= 1;\", true);\n\tEidosAssertScriptSuccess_L(\"F >= 0;\", true);\n\tEidosAssertScriptSuccess_L(\"F >= 1;\", false);\n\tEidosAssertScriptSuccess_L(\"T >= -5;\", true);\n\tEidosAssertScriptSuccess_L(\"-5 >= T;\", false);\n\tEidosAssertScriptSuccess_L(\"T >= 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 >= T;\", true);\n\tEidosAssertScriptSuccess_L(\"T >= -5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-5.0 >= T;\", false);\n\tEidosAssertScriptSuccess_L(\"T >= 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 >= T;\", true);\n\tEidosAssertScriptSuccess_L(\"T >= 'FOO';\", true);\n\tEidosAssertScriptSuccess_L(\"'FOO' >= T;\", false);\n\tEidosAssertScriptSuccess_L(\"T >= 'XYZZY';\", false);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' >= T;\", true);\n\tEidosAssertScriptSuccess_L(\"5 >= -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 >= 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 >= -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 >= 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 >= -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 >= 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' >= 'bar';\", true);\n\tEidosAssertScriptSuccess_L(\"'bar' >= 'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"120 >= '10';\", true);\n\tEidosAssertScriptSuccess_L(\"10 >= '120';\", false);\n\tEidosAssertScriptSuccess_L(\"120 >= '15';\", false);\n\tEidosAssertScriptSuccess_L(\"15 >= '120';\", true);\n\tEidosAssertScriptRaise(\"_Test(9) >= 5;\", 9, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"5 >= _Test(9);\", 2, \"cannot be used with type\");\n\tEidosAssertScriptSuccess_L(\"5 >= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 >= -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 >= 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 >= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 >= '5';\", true);\n\tEidosAssertScriptSuccess_L(\"'5' >= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' >= 'foo';\", true);\n\tEidosAssertScriptRaise(\"_Test(9) >= _Test(9);\", 9, \"cannot be used with type\");\n\t\n\tEidosAssertScriptSuccess_LV(\"T >= c(T, F);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"5 >= c(5, 6);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"5.0 >= c(5.0, 6.0);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"'foo' >= c('foo', 'bar');\", {true, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) >= T;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) >= 5;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) >= 5.0;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') >= 'foo';\", {true, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) >= c(T, T);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) >= c(5, 8);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) >= c(5.0, 8.0);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') >= c('foo', 'baz');\", {true, false});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN >= NAN;\", false);\n\tEidosAssertScriptSuccess_L(\"NAN >= 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 >= NAN;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) >= c(5.0, 5.0, 5.0);\", {true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) >= c(5.0, 5.0, NAN);\", {true, true, false});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) >= c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator >=: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(4 >= 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 >= 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 >= 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4 >= matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 >= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 >= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 >= matrix(1:3), matrix(c(T,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) >= matrix(2), c(F,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) >= matrix(3:1), matrix(c(F,T,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(4) >= matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) >= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6) >= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) >= matrix(2), matrix(c(F,T,T)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) >= matrix(3:1,ncol=1), matrix(c(F,T,T)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) >= matrix(3:1), matrix(c(F,T,T)));\", true);\n}\n\n#pragma mark operator <=\nvoid _RunOperatorLtEqTests(void)\n{\n\t// operator <=\n\tEidosAssertScriptRaise(\"NULL<=T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<=0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<=0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<='foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL<=_Test(7);\", 4, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"NULL<=(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T<=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0<=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5<=NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'<=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)<=NULL;\", 8, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"(0:2)<=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"<=NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T <= F;\", false);\n\tEidosAssertScriptSuccess_L(\"T <= T;\", true);\n\tEidosAssertScriptSuccess_L(\"F <= T;\", true);\n\tEidosAssertScriptSuccess_L(\"F <= F;\", true);\n\tEidosAssertScriptSuccess_L(\"T <= 0;\", false);\n\tEidosAssertScriptSuccess_L(\"T <= 1;\", true);\n\tEidosAssertScriptSuccess_L(\"F <= 0;\", true);\n\tEidosAssertScriptSuccess_L(\"F <= 1;\", true);\n\tEidosAssertScriptSuccess_L(\"T <= -5;\", false);\n\tEidosAssertScriptSuccess_L(\"-5 <= T;\", true);\n\tEidosAssertScriptSuccess_L(\"T <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 <= T;\", false);\n\tEidosAssertScriptSuccess_L(\"T <= -5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-5.0 <= T;\", true);\n\tEidosAssertScriptSuccess_L(\"T <= 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 <= T;\", false);\n\tEidosAssertScriptSuccess_L(\"T <= 'FOO';\", false);\n\tEidosAssertScriptSuccess_L(\"'FOO' <= T;\", true);\n\tEidosAssertScriptSuccess_L(\"T <= 'XYZZY';\", true);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' <= T;\", false);\n\tEidosAssertScriptSuccess_L(\"5 <= -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 <= -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 <= 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 <= -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' <= 'bar';\", false);\n\tEidosAssertScriptSuccess_L(\"'bar' <= 'foo';\", true);\n\tEidosAssertScriptSuccess_L(\"120 <= '10';\", false);\n\tEidosAssertScriptSuccess_L(\"10 <= '120';\", true);\n\tEidosAssertScriptSuccess_L(\"120 <= '15';\", true);\n\tEidosAssertScriptSuccess_L(\"15 <= '120';\", false);\n\tEidosAssertScriptRaise(\"_Test(9) <= 5;\", 9, \"cannot be used with type\");\n\tEidosAssertScriptRaise(\"5 <= _Test(9);\", 2, \"cannot be used with type\");\n\tEidosAssertScriptSuccess_L(\"5 <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 <= -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 <= 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 <= '5';\", true);\n\tEidosAssertScriptSuccess_L(\"'5' <= 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' <= 'foo';\", true);\n\tEidosAssertScriptRaise(\"_Test(9) <= _Test(9);\", 9, \"cannot be used with type\");\n\t\n\tEidosAssertScriptSuccess_LV(\"T <= c(T, F);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"5 <= c(5, 6);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"5.0 <= c(5.0, 6.0);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"'foo' <= c('foo', 'bar');\", {true, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) <= T;\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) <= 5;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) <= 5.0;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') <= 'foo';\", {true, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) <= c(T, T);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) <= c(5, 8);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) <= c(5.0, 8.0);\", {true, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') <= c('foo', 'baz');\", {true, true});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN <= NAN;\", false);\n\tEidosAssertScriptSuccess_L(\"NAN <= 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 <= NAN;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) <= c(5.0, 5.0, 5.0);\", {true, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) <= c(5.0, 5.0, NAN);\", {true, false, false});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) <= c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator <=: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(4 <= 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 <= 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 <= 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(4 <= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 <= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(6 <= matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 <= matrix(1:3), matrix(c(F,T,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) <= matrix(2), c(T,T,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) <= matrix(3:1), matrix(c(T,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(4) <= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) <= matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(6) <= matrix(5), matrix(F));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) <= matrix(2), matrix(c(T,T,F)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(1:3,nrow=1) <= matrix(3:1,ncol=1), matrix(c(T,T,F)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) <= matrix(3:1), matrix(c(T,T,F)));\", true);\n}\n\n#pragma mark operator ==\nvoid _RunOperatorEqTests(void)\n{\n\t// operator ==\n\tEidosAssertScriptRaise(\"NULL==T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL==0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL==0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL=='foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL==_Test(7);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL==(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T==NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0==NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5==NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'==NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)==NULL;\", 8, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"(0:2)==NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"==NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T == F;\", false);\n\tEidosAssertScriptSuccess_L(\"T == T;\", true);\n\tEidosAssertScriptSuccess_L(\"F == T;\", false);\n\tEidosAssertScriptSuccess_L(\"F == F;\", true);\n\tEidosAssertScriptSuccess_L(\"T == 0;\", false);\n\tEidosAssertScriptSuccess_L(\"T == 1;\", true);\n\tEidosAssertScriptSuccess_L(\"F == 0;\", true);\n\tEidosAssertScriptSuccess_L(\"F == 1;\", false);\n\tEidosAssertScriptSuccess_L(\"T == -5;\", false);\n\tEidosAssertScriptSuccess_L(\"-5 == T;\", false);\n\tEidosAssertScriptSuccess_L(\"T == 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 == T;\", false);\n\tEidosAssertScriptSuccess_L(\"T == -5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-5.0 == T;\", false);\n\tEidosAssertScriptSuccess_L(\"T == 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 == T;\", false);\n\tEidosAssertScriptSuccess_L(\"T == 'FOO';\", false);\n\tEidosAssertScriptSuccess_L(\"'FOO' == T;\", false);\n\tEidosAssertScriptSuccess_L(\"T == 'XYZZY';\", false);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' == T;\", false);\n\tEidosAssertScriptSuccess_L(\"5 == -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 == 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 == -10;\", false);\n\tEidosAssertScriptSuccess_L(\"-10 == 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 == -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 == 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' == 'bar';\", false);\n\tEidosAssertScriptSuccess_L(\"'bar' == 'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"120 == '10';\", false);\n\tEidosAssertScriptSuccess_L(\"10 == '120';\", false);\n\tEidosAssertScriptSuccess_L(\"120 == '15';\", false);\n\tEidosAssertScriptSuccess_L(\"15 == '120';\", false);\n\tEidosAssertScriptRaise(\"_Test(9) == 5;\", 9, \"cannot be converted to\");\n\tEidosAssertScriptRaise(\"5 == _Test(9);\", 2, \"cannot be converted to\");\n\tEidosAssertScriptSuccess_L(\"5 == 5;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 == -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 == 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 == 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 == '5';\", true);\n\tEidosAssertScriptSuccess_L(\"'5' == 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' == 'foo';\", true);\n\tEidosAssertScriptSuccess_L(\"_Test(9) == _Test(9);\", false);\t// not the same object\n\t\n\tEidosAssertScriptSuccess_LV(\"T == c(T, F);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"5 == c(5, 6);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"5.0 == c(5.0, 6.0);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"'foo' == c('foo', 'bar');\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); x == c(x, _Test(9));\", {true, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) == T;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) == 5;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) == 5.0;\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') == 'foo';\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); c(x, _Test(9)) == x;\", {true, false});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) == c(T, T);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) == c(5, 8);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) == c(5.0, 8.0);\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') == c('foo', 'baz');\", {true, false});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); c(x, _Test(9)) == c(x, x);\", {true, false});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN == NAN;\", false);\n\tEidosAssertScriptSuccess_L(\"NAN == 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 == NAN;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) == c(5.0, 5.0, 5.0);\", {true, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) == c(5.0, 5.0, NAN);\", {true, false, false});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) == c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator ==: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 == 5, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 == matrix(2), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 == matrix(5), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 == matrix(1:3), matrix(c(F,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) == matrix(2), c(F,T,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) == matrix(3:1), matrix(c(F,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) == matrix(2), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) == matrix(5), matrix(T));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) == matrix(2), matrix(c(1.0,4,9)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(2:4,nrow=1) == matrix(1:3,ncol=1), matrix(c(2.0,9,64)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) == matrix(3:1), matrix(c(F,T,F)));\", true);\n}\n\n#pragma mark operator !=\nvoid _RunOperatorNotEqTests(void)\n{\n\t// operator !=\n\tEidosAssertScriptRaise(\"NULL!=T;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL!=0;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL!=0.5;\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL!='foo';\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL!=_Test(7);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"NULL!=(0:2);\", 4, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"T!=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0!=NULL;\", 1, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"0.5!=NULL;\", 3, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"'foo'!=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"_Test(7)!=NULL;\", 8, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"(0:2)!=NULL;\", 5, \"testing NULL with\");\n\tEidosAssertScriptRaise(\"!=NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T != F;\", true);\n\tEidosAssertScriptSuccess_L(\"T != T;\", false);\n\tEidosAssertScriptSuccess_L(\"F != T;\", true);\n\tEidosAssertScriptSuccess_L(\"F != F;\", false);\n\tEidosAssertScriptSuccess_L(\"T != 0;\", true);\n\tEidosAssertScriptSuccess_L(\"T != 1;\", false);\n\tEidosAssertScriptSuccess_L(\"F != 0;\", false);\n\tEidosAssertScriptSuccess_L(\"F != 1;\", true);\n\tEidosAssertScriptSuccess_L(\"T != -5;\", true);\n\tEidosAssertScriptSuccess_L(\"-5 != T;\", true);\n\tEidosAssertScriptSuccess_L(\"T != 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5 != T;\", true);\n\tEidosAssertScriptSuccess_L(\"T != -5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-5.0 != T;\", true);\n\tEidosAssertScriptSuccess_L(\"T != 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 != T;\", true);\n\tEidosAssertScriptSuccess_L(\"T != 'FOO';\", true);\n\tEidosAssertScriptSuccess_L(\"'FOO' != T;\", true);\n\tEidosAssertScriptSuccess_L(\"T != 'XYZZY';\", true);\n\tEidosAssertScriptSuccess_L(\"'XYZZY' != T;\", true);\n\tEidosAssertScriptSuccess_L(\"5 != -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 != 5;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 != -10;\", true);\n\tEidosAssertScriptSuccess_L(\"-10 != 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5 != -10.0;\", true);\n\tEidosAssertScriptSuccess_L(\"-10.0 != 5;\", true);\n\tEidosAssertScriptSuccess_L(\"'foo' != 'bar';\", true);\n\tEidosAssertScriptSuccess_L(\"'bar' != 'foo';\", true);\n\tEidosAssertScriptSuccess_L(\"120 != '10';\", true);\n\tEidosAssertScriptSuccess_L(\"10 != '120';\", true);\n\tEidosAssertScriptSuccess_L(\"120 != '15';\", true);\n\tEidosAssertScriptSuccess_L(\"15 != '120';\", true);\n\tEidosAssertScriptRaise(\"_Test(9) != 5;\", 9, \"cannot be converted to\");\n\tEidosAssertScriptRaise(\"5 != _Test(9);\", 2, \"cannot be converted to\");\n\tEidosAssertScriptSuccess_L(\"5 != 5;\", false);\n\tEidosAssertScriptSuccess_L(\"-10.0 != -10.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5 != 5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0 != 5;\", false);\n\tEidosAssertScriptSuccess_L(\"5 != '5';\", false);\n\tEidosAssertScriptSuccess_L(\"'5' != 5;\", false);\n\tEidosAssertScriptSuccess_L(\"'foo' != 'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"_Test(9) != _Test(9);\", true);\t// not the same object\n\t\n\tEidosAssertScriptSuccess_LV(\"T != c(T, F);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"5 != c(5, 6);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"5.0 != c(5.0, 6.0);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"'foo' != c('foo', 'bar');\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); x != c(x, _Test(9));\", {false, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) != T;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) != 5;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) != 5.0;\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') != 'foo';\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); c(x, _Test(9)) != x;\", {false, true});\n\t\n\tEidosAssertScriptSuccess_LV(\"c(T, F) != c(T, T);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5, 6) != c(5, 8);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0) != c(5.0, 8.0);\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo', 'bar') != c('foo', 'baz');\", {false, true});\n\tEidosAssertScriptSuccess_LV(\"x = _Test(9); c(x, _Test(9)) != c(x, x);\", {false, true});\n\t\n\tEidosAssertScriptSuccess_L(\"NAN != NAN;\", true);\n\tEidosAssertScriptSuccess_L(\"NAN != 5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0 != NAN;\", true);\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, NAN) != c(5.0, 5.0, 5.0);\", {false, true, true});\n\tEidosAssertScriptSuccess_LV(\"c(5.0, 6.0, 8.0) != c(5.0, 5.0, NAN);\", {false, true, true});\n\t\n\tEidosAssertScriptRaise(\"c(5,6) != c(5,6,7);\", 7, \"operator requires that either\");\n\t\n\t// operator !=: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with integer should suffice\n\tEidosAssertScriptSuccess_L(\"identical(5 != 5, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 != matrix(2), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(5 != matrix(5), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(2 != matrix(1:3), matrix(c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) != matrix(2), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical((1:3) != matrix(3:1), matrix(c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) != matrix(2), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(5) != matrix(5), matrix(F));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(1:3) != matrix(2), matrix(c(1.0,4,9)));\", 22, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(2:4,nrow=1) != matrix(1:3,ncol=1), matrix(c(2.0,9,64)));\", 29, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(1:3) != matrix(3:1), matrix(c(T,F,T)));\", true);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_operators_other.cpp",
    "content": "//\n//  eidos_test_operators_other.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/11/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_test.h\"\n\n\n#pragma mark operator []\nvoid _RunOperatorSubsetTests(void)\n{\n\t// operator []\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[NULL];\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_NULL(\"x = 1:5; NULL[x];\");\n\tEidosAssertScriptSuccess_NULL(\"x = 1:5; NULL[NULL];\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[];\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess(\"x = 1:5; x[integer(0)];\", gStaticEidosValue_Integer_ZeroVec);\n\tEidosAssertScriptSuccess_I(\"x = 1:5; x[2];\", 3);\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[2:3];\", {3, 4});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(0, 2, 4)];\", {1, 3, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[0:4];\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptRaise(\"x = 1:5; x[float(0)];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[2.0];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[2.0:3];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(0.0, 2, 4)];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[0.0:4];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(7,8)];\", 10, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[logical(0)];\", 10, \"operator requires that the size()\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[T];\", 10, \"operator requires that the size()\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(T, T)];\", 10, \"operator requires that the size()\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(T, F, T)];\", 10, \"operator requires that the size()\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[NAN];\", 10, \"float indices\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(0.0, 2, NAN)];\", 10, \"float indices\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(T, F, T, F, T)];\", {1, 3, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(T, T, T, T, T)];\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess(\"x = 1:5; x[c(F, F, F, F, F)];\", gStaticEidosValue_Integer_ZeroVec);\n\n\tEidosAssertScriptSuccess_LV(\"x = c(T,T,F,T,F); x[c(T, F, T, F, T)];\", {true, false, false});\n\tEidosAssertScriptSuccess_FV(\"x = 1.0:5; x[c(T, F, T, F, T)];\", {1.0, 3.0, 5.0});\n\tEidosAssertScriptSuccess_SV(\"x = c('foo', 'bar', 'foobaz', 'baz', 'xyzzy'); x[c(T, F, T, F, T)];\", {\"foo\", \"foobaz\", \"xyzzy\"});\n\t\n\tEidosAssertScriptSuccess_LV(\"x = c(T,T,F,T,F); x[c(2,3)];\", {false, true});\n\tEidosAssertScriptRaise(\"x = c(T,T,F,T,F); x[c(2,3,7)];\", 19, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(2,3)];\", {3, 4});\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(2,3,7)];\", 10, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_FV(\"x = 1.0:5; x[c(2,3)];\", {3.0, 4.0});\n\tEidosAssertScriptRaise(\"x = 1.0:5; x[c(2,3,7)];\", 12, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_SV(\"x = c('foo', 'bar', 'foobaz', 'baz', 'xyzzy'); x[c(2,3)];\", {\"foobaz\", \"baz\"});\n\tEidosAssertScriptRaise(\"x = c('foo', 'bar', 'foobaz', 'baz', 'xyzzy'); x[c(2,3,7)];\", 48, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_IV(\"x = c(_Test(1), _Test(2), _Test(3), _Test(4), _Test(5)); x = x[c(2,3)]; x._yolk;\", {3, 4});\n\tEidosAssertScriptRaise(\"x = c(_Test(1), _Test(2), _Test(3), _Test(4), _Test(5)); x = x[c(2,3,7)]; x._yolk;\", 62, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_I(\"x = 5; x[T];\", 5);\n\tEidosAssertScriptSuccess_IV(\"x = 5; x[F];\", {});\n\tEidosAssertScriptRaise(\"x = 5; x[logical(0)];\", 8, \"must match the size()\");\n\tEidosAssertScriptSuccess_I(\"x = 5; x[0];\", 5);\n\tEidosAssertScriptRaise(\"x = 5; x[1];\", 8, \"out of range\");\n\tEidosAssertScriptRaise(\"x = 5; x[-1];\", 8, \"out of range\");\n\tEidosAssertScriptSuccess_IV(\"x = 5; x[integer(0)];\", {});\n\t\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(0)];\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(0:2)];\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(T)];\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(c(T,T,F,T,F))];\", 10, \"matrix or array index operand is not supported\");\n\t\n\t// matrix/array subsets, without dropping\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[], 1:6);\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,], matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[NULL,NULL], matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[0,], matrix(c(1,3,5), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[1,], matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[1,NULL], matrix(c(2,4,6), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[0:1,], matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[NULL,], matrix(1:6, nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,0], matrix(1:2, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,1], matrix(3:4, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,2], matrix(5:6, ncol=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,0:1], matrix(1:4, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,1:2], matrix(3:6, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,c(0,2)], matrix(c(1,2,5,6), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[NULL,c(0,2)], matrix(c(1,2,5,6), ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[0,1], matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[1,2], matrix(6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[0,c(T,F,T)], matrix(c(1,5), nrow=1));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(F,T),c(F,F,T)], matrix(6));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(F,F),c(F,F,F)], integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(F,F),c(F,T,T)], integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(T,T),c(T,T,F)], matrix(1:4, ncol=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(0,0,1,0),], matrix(c(1,3,5,1,3,5,2,4,6,1,3,5), ncol=3, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[c(0,0,1,0),c(1,2,1)], matrix(c(3,5,3,3,5,3,4,6,4,3,5,3), ncol=3, byrow=T));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); identical(x[,c(1,2,1)], matrix(c(3,4,5,6,3,4), nrow=2));\", true);\n\t\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[c(T),c(T,T,F)];\", 26, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[c(T,T,T),c(T,T,F)];\", 26, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[c(T,T),c(T,T)];\", 26, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[c(T,T),c(T,T,F,T)];\", 26, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[-1,];\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[2,];\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[,-1];\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[,3];\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[0,0,0];\", 26, \"too many subset arguments\");\n\t\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[], 1:12);\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,,], array(1:12, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[NULL,NULL,NULL], array(1:12, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[0,,], array(c(1,3,5,7,9,11), c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[1,,], array(c(2,4,6,8,10,12), c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[1,NULL,NULL], array(c(2,4,6,8,10,12), c(1,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[0:1,,], array(1:12, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[NULL,,], array(1:12, c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,0,], array(c(1,2,7,8), c(2,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,1,], array(c(3,4,9,10), c(2,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,2,], array(c(5,6,11,12), c(2,1,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,c(0,2),], array(c(1,2,5,6,7,8,11,12), c(2,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[,,0], array(1:6, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[NULL,NULL,1], array(7:12, c(2,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[1,2,0], array(6, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[0,1,1], array(9, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[1,1:2,], array(c(4,6,10,12), c(1,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[0,c(T,F,T),], array(c(1,5,7,11), c(1,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(T,F),c(T,F,T),], array(c(1,5,7,11), c(1,2,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(T,F),c(T,F,T),c(F,T)], array(c(7,11), c(1,2,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(T,F),c(F,F,T),c(F,T)], array(11, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(F,F),c(F,F,F),c(F,T)], integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(F,F),c(T,F,T),c(F,T)], integer(0));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(0,0,1,0),,], array(c(1,1,2,1,3,3,4,3,5,5,6,5,7,7,8,7,9,9,10,9,11,11,12,11), c(4,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); identical(x[c(0,0,1,0),c(2,1),0], array(c(5,5,6,5,3,3,4,3), c(4,2,1)));\", true);\n\t\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T), c(T,T,T), c(T,T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,T,T), c(T,T,T), c(T,T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,T), c(T,T), c(T,T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,T), c(T,T,T,T), c(T,T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,T), c(T,T,T), c(T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,T), c(T,T,T), c(T,T,T)];\", 28, \"match the corresponding dimension\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[-1, 0, 0];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[2, 0, 0];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, -1, 0];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, 3, 0];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, 0, -1];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, 0, 2];\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, 0];\", 28, \"too few subset arguments\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0, 0, 0, 0];\", 28, \"too many subset arguments\");\n\t\n\t// BCH new 9/11/2025: subsetting a matrix/array with a logical matrix/array\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T), nrow=3); x[y];\", 69, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,T,T,F,F,T), nrow=3); x[y];\", 81, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T), nrow=2); x[y];\", 67, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,T,F,T,T,F,F,T), nrow=4); x[y];\", 83, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[t(y)];\", 75, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = array(rep(T,24), c(3,4,2)); x[y];\", 59, \"non-conformable\");\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, nrow=3); y = matrix(rep(F,12), nrow=3); x[y];\", {});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, nrow=3); y = matrix(rep(T,12), nrow=3); x[y];\", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[y];\", {1, 3, 4, 7, 8, 9, 12});\n\tEidosAssertScriptSuccess_L(\"x = matrix(rdunif(110, -1000, 1000), nrow=10); y = matrix(rbinom(110, 1, 0.5)==1, nrow=10); identical(x[y], c(x)[c(y)]);\", true);\n\t\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T), nrow=3); x[y];\", 71, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,T,T,F,F,T), nrow=3); x[y];\", 83, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T), nrow=2); x[y];\", 69, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,T,F,T,T,F,F,T), nrow=4); x[y];\", 85, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[t(y)];\", 77, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = array(rep(T,24), c(3,4,2)); x[y];\", 61, \"non-conformable\");\n\tEidosAssertScriptSuccess_FV(\"x = matrix(1.0:12, nrow=3); y = matrix(rep(F,12), nrow=3); x[y];\", {});\n\tEidosAssertScriptSuccess_FV(\"x = matrix(1.0:12, nrow=3); y = matrix(rep(T,12), nrow=3); x[y];\", {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});\n\tEidosAssertScriptSuccess_FV(\"x = matrix(1.0:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[y];\", {1, 3, 4, 7, 8, 9, 12});\n\tEidosAssertScriptSuccess_L(\"x = matrix(runif(110, -1000, 1000), nrow=10); y = matrix(rbinom(110, 1, 0.5)==1, nrow=10); identical(x[y], c(x)[c(y)]);\", true);\n\t\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(4,3,2)); x[y];\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,4,3)); x[y];\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(3,2,4)); x[y];\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F), c(2,3,3)); x[y];\", 89, \"non-conformable\");\n\tEidosAssertScriptSuccess_IV(\"x = array(1:24, c(2,3,4)); y = array(rep(F,24), c(2,3,4)); x[y];\", {});\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = array(rep(T,24), c(2,3,4)); identical(x[y], 1:24);\", true);\n\tEidosAssertScriptSuccess_IV(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,3,4)); x[y];\", {1, 3, 4, 5, 6, 9, 13, 20, 22, 23, 24});\n\tEidosAssertScriptSuccess_L(\"x = array(runif(210, -1000, 1000), c(5,6,7)); y = array(rbinom(210, 1, 0.5)==1, c(5,6,7)); identical(x[y], c(x)[c(y)]);\", true);\n\t\n\t// BCH new 9/11/2025: subsetting a matrix/array with an integer matrix of coordinates\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(1:6, ncol=1); x[y];\", 52, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(1:6, ncol=3); x[y];\", 52, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = array(1:18, c(3,2,3)); x[y];\", 54, \"with an integer array\");\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, nrow=3); y = matrix(c(1,2), ncol=2, byrow=T); x[y];\", {8});\n\tEidosAssertScriptSuccess_IV(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y];\", {8, 12, 1, 3, 10});\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2), nrow=1); x[y];\", 56, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3,4), nrow=1); x[y];\", 60, \"column count equal\");\n\tEidosAssertScriptSuccess_IV(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3), nrow=1); x[y];\", {24});\n\tEidosAssertScriptSuccess_IV(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2), nrow=1); x[y];\", {14});\n\tEidosAssertScriptSuccess_IV(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2, 1,2,3, 0,0,0, 0,1,1), ncol=3, byrow=T); x[y];\", {14, 24, 1, 9});\n\t\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(1:6, ncol=1); x[y];\", 54, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = matrix(1:6, ncol=3); x[y];\", 54, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1.0:12, nrow=3); y = array(1:18, c(3,2,3)); x[y];\", 56, \"with an integer array\");\n\tEidosAssertScriptSuccess_FV(\"x = matrix(1.0:12, nrow=3); y = matrix(c(1,2), ncol=2, byrow=T); x[y];\", {8});\n\tEidosAssertScriptSuccess_FV(\"x = matrix(1.0:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y];\", {8, 12, 1, 3, 10});\n\tEidosAssertScriptRaise(\"x = array(1.0:24, c(2,3,4)); y = matrix(c(1,2), nrow=1); x[y];\", 58, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = array(1.0:24, c(2,3,4)); y = matrix(c(1,2,3,4), nrow=1); x[y];\", 62, \"column count equal\");\n\tEidosAssertScriptSuccess_FV(\"x = array(1.0:24, c(2,3,4)); y = matrix(c(1,2,3), nrow=1); x[y];\", {24});\n\tEidosAssertScriptSuccess_FV(\"x = array(1.0:24, c(2,3,4)); y = matrix(c(1,0,2), nrow=1); x[y];\", {14});\n\tEidosAssertScriptSuccess_FV(\"x = array(1.0:24, c(2,3,4)); y = matrix(c(1,0,2, 1,2,3, 0,0,0, 0,1,1), ncol=3, byrow=T); x[y];\", {14, 24, 1, 9});\n}\n\n#pragma mark operator = with []\nvoid _RunOperatorAssignTests(void)\n{\n\t// operator =\n\tEidosAssertScriptRaise(\"E = 7;\", 2, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptRaise(\"E = E + 7;\", 2, \"cannot be redefined because it is a constant\");\n\t\n\t// operator = (especially in conjunction with operator [])\n\tEidosAssertScriptSuccess_I(\"x = 5; x;\", 5);\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x;\", {1, 2, 3, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[x % 2 == 1] = 10; x;\", {10, 2, 10, 4, 10});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[x % 2 == 1][1:2] = 10; x;\", {1, 2, 10, 4, 10});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[1:3*2 - 2] = 10; x;\", {10, 2, 10, 4, 10});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[1:3*2 - 2][0:1] = 10; x;\", {10, 2, 10, 4, 5});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[x % 2 == 1] = 11:13; x;\", {11, 2, 12, 4, 13});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[x % 2 == 1][1:2] = 11:12; x;\", {1, 2, 11, 4, 12});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[1:3*2 - 2] = 11:13; x;\", {11, 2, 12, 4, 13});\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[1:3*2 - 2][0:1] = 11:12; x;\", {11, 2, 12, 4, 5});\n\tEidosAssertScriptRaise(\"x = 1:5; x[1:3*2 - 2][0:1] = 11:13; x;\", 27, \"assignment to a subscript requires\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[NULL] = NULL; x;\", 17, \"assignment to a subscript requires an rvalue that is\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[NULL] = 10; x;\", {10, 10, 10, 10, 10});\t// assigns 10 to all indices, legal in Eidos 1.6 and later\n\tEidosAssertScriptRaise(\"x = 1:5; x[3] = NULL; x;\", 14, \"assignment to a subscript requires\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[integer(0)] = NULL; x;\", 23, \"type mismatch\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[integer(0)] = 10; x;\", {1, 2, 3, 4, 5}); // assigns 10 to no indices, perfectly legal\n\tEidosAssertScriptRaise(\"x = 1:5; x[3] = integer(0); x;\", 14, \"assignment to a subscript requires\");\n\tEidosAssertScriptSuccess_FV(\"x = 1.0:5; x[3] = 1; x;\", {1, 2, 3, 1, 5});\n\tEidosAssertScriptSuccess_SV(\"x = c('a', 'b', 'c'); x[1] = 1; x;\", {\"a\", \"1\", \"c\"});\n\tEidosAssertScriptRaise(\"x = 1:5; x[3] = 1.5; x;\", 14, \"type mismatch\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[3] = 'foo'; x;\", 14, \"type mismatch\");\n\tEidosAssertScriptSuccess_I(\"x = 5; x[0] = 10; x;\", 10);\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x[0] = 10.0; x;\", 10);\n\tEidosAssertScriptRaise(\"x = 5; x[0] = 10.0; x;\", 12, \"type mismatch\");\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x[0] = 10; x;\", 10);\n\tEidosAssertScriptSuccess_L(\"x = T; x[0] = F; x;\", false);\n\tEidosAssertScriptSuccess_S(\"x = 'foo'; x[0] = 'bar'; x;\", \"bar\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(T,T,F,T,F)] = 7:9; x;\", {7, 8, 3, 9, 5});\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(T,T,F,T,F,T)] = 7:9; x;\", 10, \"must match the size()\");\n\tEidosAssertScriptSuccess_IV(\"x = 1:5; x[c(2,3)] = c(9, 5); x;\", {1, 2, 9, 5, 5});\n\tEidosAssertScriptRaise(\"x = 1:5; x[c(7,8)] = 7; x;\", 10, \"out-of-range index\");\n\t\n\tEidosAssertScriptSuccess_I(\"x = _Test(9); x = _Test(7); x._yolk;\", 7);\n\tEidosAssertScriptSuccess_I(\"x = _Test(9); x[0] = _Test(7); x._yolk;\", 7);\n\tEidosAssertScriptSuccess_IV(\"x = c(_Test(9), _Test(5)); x[0] = _Test(7); x._yolk;\", {7, 5});\n\tEidosAssertScriptSuccess_IV(\"x = c(_Test(9), _Test(5)); x[1] = _Test(7); x._yolk;\", {9, 7});\n\t\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(0)] = 3;\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(0:2)] = 3;\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(T)] = 3;\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptRaise(\"x = 5:9; x[matrix(c(T,T,F,T,F))] = 3;\", 10, \"matrix or array index operand is not supported\");\n\tEidosAssertScriptSuccess_L(\"x = 1; x[] = 2; identical(x, 2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1; x[NULL] = 2; identical(x, 2);\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:5; x[] = 2; identical(x, rep(2,5));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 1:5; x[NULL] = 2; identical(x, rep(2,5));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5); x[] = 3; identical(x, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5); x[NULL] = 3; identical(x, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5); x[0] = 3; identical(x, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5:9); x[] = 3; identical(x, matrix(c(3,3,3,3,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5:9); x[NULL] = 3; identical(x, matrix(c(3,3,3,3,3)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5:9); x[0] = 3; identical(x, matrix(c(3,6,7,8,9)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5); x[T] = 3; identical(x, matrix(3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(5:9); x[c(T,F,T,T,F)] = 3; identical(x, matrix(c(3,6,3,3,9)));\", true);\n\t\n\t// operator = (especially in conjunction with matrix/array-style subsetting with operator [])\n\tEidosAssertScriptRaise(\"NULL[logical(0)] = NULL;\", 17, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptRaise(\"NULL[logical(0),] = NULL;\", 18, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptRaise(\"NULL[logical(0),logical(0)] = NULL;\", 28, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptRaise(\"NULL[,] = NULL;\", 8, \"cannot be redefined because it is a constant\");\n\tEidosAssertScriptSuccess_VOID(\"x = NULL; x[logical(0)] = NULL;\");\t// technically legal, as no assignment is done\n\tEidosAssertScriptRaise(\"x = NULL; x[logical(0),] = NULL;\", 11, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = NULL; x[logical(0),logical(0)] = NULL;\", 11, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = NULL; x[,] = NULL;\", 11, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = 1; x[,] = 2; x;\", 8, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = 1; x[0,0] = 2; x;\", 8, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[,] = 2; x;\", 10, \"too many subset arguments\");\n\tEidosAssertScriptRaise(\"x = 1:5; x[0,0] = 2; x;\", 10, \"too many subset arguments\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[,] = 2; identical(x, matrix(rep(2,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[NULL,NULL] = 2; identical(x, matrix(rep(2,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[0,0] = 2; identical(x, matrix(c(2,2,3,4,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[3,0] = 2; identical(x, matrix(c(1,2,3,2,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[1:3,0] = 7; identical(x, matrix(c(1,7,7,7,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[c(1,3),0] = 7; identical(x, matrix(c(1,7,3,7,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[c(1,3),0] = 6:7; identical(x, matrix(c(1,6,3,7,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[c(T,F,F,T,F),0] = 7; identical(x, matrix(c(7,2,3,7,5)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:5); x[c(T,F,F,T,F),0] = 6:7; identical(x, matrix(c(6,2,3,7,5)));\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:5); x[-1,0] = 2;\", 18, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:5); x[5,0] = 2;\", 18, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:5); x[0,-1] = 2;\", 18, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:5); x[0,1] = 2;\", 18, \"out-of-range index\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[1,1] = 2; identical(x, matrix(c(1,2,3,2,5,6), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[0:1,1] = 7; identical(x, matrix(c(1,2,7,7,5,6), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[1, c(T,F,T)] = 7; identical(x, matrix(c(1,7,3,4,5,7), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[0:1, c(T,F,T)] = 7; identical(x, matrix(c(7,7,3,4,7,7), nrow=2));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[c(T,T), c(T,F,T)] = 6:9; identical(x, matrix(c(6,7,3,4,8,9), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[-1,0] = 2;\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[2,0] = 2;\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[0,-1] = 2;\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[0,3] = 2;\", 26, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[c(T,F,T),0] = 2;\", 26, \"size() of a logical\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[T,0] = 2;\", 26, \"size() of a logical\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[0:4][,0] = 2;\", 31, \"chaining of matrix/array-style subsets\");\n\tEidosAssertScriptRaise(\"x = matrix(1:6, nrow=2); x[0,1:2][,0] = 2;\", 33, \"chaining of matrix/array-style subsets\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[0,1:2][1] = 2; identical(x, c(1,2,3,4,2,6));\", false);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:6, nrow=2); x[0,1:2][1] = 2; identical(x, matrix(c(1,2,3,4,2,6), nrow=2));\", true);\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=matrix(c(x,y,x,y), nrow=2); z._yolk[,1]=6.5;\", 61, \"subset of a property\");\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=matrix(c(x,y,x,y), nrow=2); z[,1]._yolk[1]=6.5;\", 68, \"subset of a property\");\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=matrix(x); identical(z._yolk, matrix(9));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=array(x, c(1,1,1,1)); identical(z._yolk, array(9, c(1,1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=matrix(x); z[0]._yolk = 6; identical(z._yolk, matrix(6));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=array(x, c(1,1,1,1)); z[0]._yolk = 6; identical(z._yolk, array(6, c(1,1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=matrix(x); z[0,0]._yolk = 6; identical(z._yolk, matrix(6));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); z=array(x, c(1,1,1,1)); z[0,0,0,0]._yolk = 6; identical(z._yolk, array(6, c(1,1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"x=_Test(9); y=_Test(7); z=matrix(c(x,y,x,y), nrow=2); z[,1]._yolk=6; identical(z._yolk, matrix(c(6,6,6,6), nrow=2));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[,,] = 2; identical(x, array(rep(2,12), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[1,0,1] = -1; identical(x, array(c(1,2,3,4,5,6,7,-1,9,10,11,12), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[1,c(T,F,T),1] = 7; identical(x, array(c(1,2,3,4,5,6,7,7,9,10,11,7), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[1,c(T,F,T),1] = -1:-2; identical(x, array(c(1,2,3,4,5,6,7,-1,9,10,11,-2), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[0:1,c(T,F,T),1] = 15; identical(x, array(c(1,2,3,4,5,6,15,15,9,10,15,15), c(2,3,2)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[0:1,c(T,F,T),1] = 15:18; identical(x, array(c(1,2,3,4,5,6,15,16,9,10,17,18), c(2,3,2)));\", true);\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0:1,c(T,F,T),1] = 15:17; identical(x, array(c(1,2,3,4,5,6,15,16,9,10,17,18), c(2,3,2)));\", 45, \".size() matching the .size\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0:1,c(T,F,T),1] = 15:19; identical(x, array(c(1,2,3,4,5,6,15,16,9,10,17,18), c(2,3,2)));\", 45, \".size() matching the .size\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[-1,0,0] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[2,0,0] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0,-1,0] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0,3,0] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0,0,-1] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0,0,2] = 2;\", 28, \"out-of-range index\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[c(T,F,T),0,0] = 2;\", 28, \"size() of a logical\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[T,0,0] = 2;\", 28, \"size() of a logical\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0:4][,0,] = 2;\", 33, \"chaining of matrix/array-style subsets\");\n\tEidosAssertScriptRaise(\"x = array(1:12, c(2,3,2)); x[0,1:2,][,0,] = 2;\", 36, \"chaining of matrix/array-style subsets\");\n\tEidosAssertScriptSuccess_L(\"x = array(1:12, c(2,3,2)); x[0,1:2,][1:2] = 2; identical(x, array(c(1,2,3,4,2,6,7,8,2,10,11,12), c(2,3,2)));\", true);\n\t\n\t// BCH new 9/11/2025: operator = in conjunction with subsetting a matrix/array with a logical matrix/array\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T), nrow=3); x[y] = 5;\", 69, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,T,T,F,F,T), nrow=3); x[y] = 5;\", 81, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T), nrow=2); x[y] = 5;\", 67, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,T,F,T,T,F,F,T), nrow=4); x[y] = 5;\", 83, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[t(y)] = 5;\", 75, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = array(rep(T,24), c(3,4,2)); x[y] = 5;\", 59, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); x_ = x; y = matrix(rep(F,12), nrow=3); x[y] = 100; identical(x, x_);\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(rep(T,12), nrow=3); x[y] = 100; identical(x, matrix(rep(100,12), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[y] = 100; identical(x, matrix(c(100,2,100,100,5,6,100,100,100,10,11,100), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(rep(F,12), nrow=3); x[y] = 1:12;\", 62, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); x_ = x; y = matrix(rep(F,12), nrow=3); x[y] = integer(0); identical(x, x_);\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); x_ = x; y = matrix(rep(T,12), nrow=3); x[y] = 1:12; identical(x, x_);\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[y] = 100:107;\", 79, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(T,F,T,T,F,F,T,T,T,F,F,T), nrow=3); x[y] = 100:106; identical(x, matrix(c(100,2,101,102,5,6,103,104,105,10,11,106), nrow=3));\", true);\n\t\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(4,3,2)); x[y] = 5;\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,4,3)); x[y] = 5;\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(3,2,4)); x[y] = 5;\", 101, \"non-conformable\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F), c(2,3,3)); x[y] = 5;\", 89, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); x_ = x; y = array(rep(F,24), c(2,3,4)); x[y] = 100; identical(x, x_);\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = array(rep(T,24), c(2,3,4)); x[y] = 100; identical(x, array(rep(100,24), c(2,3,4)));\", true);\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,3,4)); x[y] = 100:111;\", 105, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,3,4)); x[y] = 100; identical(x, array(c(100,2,100,100,100,100,7,8,100,10,11,12,100,14,15,16,17,18,19,100,21,100,100,100), c(2,3,4)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = array(c(T,F,T,T,T,T,F,F,T,F,F,F,T,F,F,F,F,F,F,T,F,T,T,T), c(2,3,4)); x[y] = 100:110; identical(x, array(c(100,2,101,102,103,104,7,8,105,10,11,12,106,14,15,16,17,18,19,107,21,108,109,110), c(2,3,4)));\", true);\n\t\n\t// BCH new 9/11/2025: operator = in conjunction with subsetting a matrix/array with an integer matrix of coordinates\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(1:6, ncol=1); x[y] = 5;\", 52, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(1:6, ncol=3); x[y] = 5;\", 52, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = array(1:18, c(3,2,3)); x[y] = 5;\", 54, \"with an integer array\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(1,2), ncol=2, byrow=T); x[y] = integer(0);\", 68, \"size() matching\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(1,2), ncol=2, byrow=T); x[y] = 100:101;\", 68, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(1,2), ncol=2, byrow=T); x[y] = 100; identical(x, matrix(c(1,2,3,4,5,6,7,100,9,10,11,12), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y] = integer(0);\", 92, \"size() matching\");\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y] = 100:101;\", 92, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y] = 100; identical(x, matrix(c(100,2,100,4,5,6,7,100,9,100,11,100), nrow=3));\", true);\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y] = 100:104; identical(x, matrix(c(102,2,103,4,5,6,7,100,9,104,11,101), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2), nrow=1); x[y] = 100;\", 56, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3,4), nrow=1); x[y] = 100;\", 60, \"column count equal\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3), nrow=1); x[y] = integer(0);\", 62, \"size() matching\");\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3), nrow=1); x[y] = 100:101;\", 62, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,2,3), nrow=1); x[y] = 100; identical(x, array(c(1:23,100), c(2,3,4)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2), nrow=1); x[y] = 100; identical(x, array(c(1:13,100,15:24), c(2,3,4)));\", true);\n\tEidosAssertScriptRaise(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2, 1,2,3, 0,0,0, 0,1,1), ncol=3, byrow=T); x[y] = 100:101;\", 92, \"size() matching\");\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2, 1,2,3, 0,0,0, 0,1,1), ncol=3, byrow=T); x[y] = 100; identical(x, array(c(100,2,3,4,5,6,7,8,100,10,11,12,13,100,15,16,17,18,19,20,21,22,23,100), c(2,3,4)));\", true);\n\tEidosAssertScriptSuccess_L(\"x = array(1:24, c(2,3,4)); y = matrix(c(1,0,2, 1,2,3, 0,0,0, 0,1,1), ncol=3, byrow=T); x[y] = 100:103; identical(x, array(c(102,2,3,4,5,6,7,8,103,10,11,12,13,100,15,16,17,18,19,20,21,22,23,101), c(2,3,4)));\", true);\n\t\n\tEidosAssertScriptSuccess_L(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y][2] = 100; identical(x, matrix(c(100,2,3,4,5,6,7,8,9,10,11,12), nrow=3));\", true);\n\tEidosAssertScriptRaise(\"x = matrix(1:12, nrow=3); y = matrix(c(2,3, 3,4, 1,1, 3,1, 1,4), ncol=2, byrow=T) - 1; x[y][5] = 100;\", 91, \"out-of-range index\");\n\t\n\t// operator = (especially in conjunction with operator .)\n\tEidosAssertScriptSuccess_I(\"x=_Test(9); x._yolk;\", 9);\n\tEidosAssertScriptRaise(\"x=_Test(NULL);\", 2, \"cannot be type NULL\");\n\tEidosAssertScriptRaise(\"x=_Test(9); x._yolk = NULL;\", 20, \"value cannot be type\");\n\tEidosAssertScriptSuccess_IV(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z._yolk;\", {9, 7, 9, 7});\n\tEidosAssertScriptSuccess_IV(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z[3]._yolk=2; z._yolk;\", {9, 2, 9, 2});\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z._yolk[3]=2; z._yolk;\", 48, \"not an lvalue\");\t\t\t\t// used to be legal, now a policy error\n\tEidosAssertScriptSuccess_IV(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z[c(1,0)]._yolk=c(2, 5); z._yolk;\", {5, 2, 5, 2});\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z._yolk[c(1,0)]=c(3, 6); z._yolk;\", 53, \"not an lvalue\");\t// used to be legal, now a policy error\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z[3]._yolk=6.5; z._yolk;\", 48, \"value cannot be type\");\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z._yolk[3]=6.5; z._yolk;\", 48, \"not an lvalue\");\t\t\t// used to be a type error, now a policy error\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z[2:3]._yolk=6.5; z._yolk;\", 50, \"value cannot be type\");\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z._yolk[2:3]=6.5; z._yolk;\", 50, \"not an lvalue\");\t\t\t// used to be a type error, now a policy error\n\tEidosAssertScriptRaise(\"x=_Test(9); y=_Test(7); z=c(x,y,x,y); z[2]=6.5; z._yolk;\", 42, \"type mismatch\");\n\tEidosAssertScriptRaise(\"x = 1:5; x.foo[5] = 7;\", 10, \"operand type integer is not supported\");\n\t\n\t// operator = (with compound-operator optimizations)\n\tEidosAssertScriptSuccess_I(\"x = 5; x = x + 3; x;\", 8);\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x + 3; x;\", {8, 9});\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x + 3:4; x;\", {8, 10});\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x + 3.5; x;\", 8.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x + 3.5; x;\", {8.5, 9.5});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x + 3.5:4.5; x;\", {8.5, 10.5});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x + 3:4; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x + 3:5; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"x = 5.5; x = x + 3.5; x;\", 9);\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x + 3.5; x;\", {9, 10});\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x + 3.5:4.5; x;\", {9, 11});\n\tEidosAssertScriptSuccess_F(\"x = 5.5; x = x + 3; x;\", 8.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x + 3; x;\", {8.5, 9.5});\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x + 3:4; x;\", {8.5, 10.5});\n\tEidosAssertScriptRaise(\"x = 5.5:7.5; x = x + 3.5:4.5; x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.5:6.5; x = x + 3.5:5.5; x;\", 19, \"operator requires that either\");\n\t\n\tEidosAssertScriptSuccess_I(\"x = 5; x = x - 3; x;\", 2);\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x - 3; x;\", {2, 3});\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x - 3:4; x;\", {2, 2});\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x - 3.5; x;\", 1.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x - 3.5; x;\", {1.5, 2.5});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x - 3.5:4.5; x;\", {1.5, 1.5});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x - 3:4; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x - 3:5; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"x = 5.5; x = x - 3.5; x;\", 2);\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x - 3.5; x;\", {2, 3});\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x - 3.5:4.5; x;\", {2, 2});\n\tEidosAssertScriptSuccess_F(\"x = 5.5; x = x - 3; x;\", 2.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x - 3; x;\", {2.5, 3.5});\n\tEidosAssertScriptSuccess_FV(\"x = 5.5:6.5; x = x - 3:4; x;\", {2.5, 2.5});\n\tEidosAssertScriptRaise(\"x = 5.5:7.5; x = x - 3.5:4.5; x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.5:6.5; x = x - 3.5:5.5; x;\", 19, \"operator requires that either\");\n\t\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x / 2; x;\", 2.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x / 2; x;\", {2.5, 3.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x / c(2,4); x;\", {2.5, 1.5});\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x / 2.0; x;\", 2.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x / 2.0; x;\", {2.5, 3.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x / c(2.0,4.0); x;\", {2.5, 1.5});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x / 3:4; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x / 3:5; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x / 2.0; x;\", 2.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x / 2.0; x;\", {2.5, 3.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x / c(2.0,4.0); x;\", {2.5, 1.5});\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x / 2; x;\", 2.5);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x / 2; x;\", {2.5, 3.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x / c(2,4); x;\", {2.5, 1.5});\n\tEidosAssertScriptRaise(\"x = 5.0:7.0; x = x / 3.0:4.0; x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.0:6.0; x = x / 3.0:5.0; x;\", 19, \"operator requires that either\");\n\t\n\tEidosAssertScriptSuccess(\"x = 5; x = x % 2; x;\", gStaticEidosValue_Float1);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x % 2; x;\", {1.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x % c(2,4); x;\", {1.0, 2.0});\n\tEidosAssertScriptSuccess(\"x = 5; x = x % 2.0; x;\", gStaticEidosValue_Float1);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x % 2.0; x;\", {1.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x % c(2.0,4.0); x;\", {1.0, 2.0});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x % 3:4; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x % 3:5; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess(\"x = 5.0; x = x % 2.0; x;\", gStaticEidosValue_Float1);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x % 2.0; x;\", {1.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x % c(2.0,4.0); x;\", {1.0, 2.0});\n\tEidosAssertScriptSuccess(\"x = 5.0; x = x % 2; x;\", gStaticEidosValue_Float1);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x % 2; x;\", {1.0, 0.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x % c(2,4); x;\", {1.0, 2.0});\n\tEidosAssertScriptRaise(\"x = 5.0:7.0; x = x % 3.0:4.0; x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.0:6.0; x = x % 3.0:5.0; x;\", 19, \"operator requires that either\");\n\t\n\tEidosAssertScriptSuccess_I(\"x = 5; x = x * 2; x;\", 10);\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x * 2; x;\", {10, 12});\n\tEidosAssertScriptSuccess_IV(\"x = 5:6; x = x * c(2,4); x;\", {10, 24});\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x * 2.0; x;\", 10.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x * 2.0; x;\", {10.0, 12.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x * c(2.0,4.0); x;\", {10.0, 24.0});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x * 3:4; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x * 3:5; x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x * 2.0; x;\", 10.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x * 2.0; x;\", {10.0, 12.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x * c(2.0,4.0); x;\", {10.0, 24.0});\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x * 2; x;\", 10.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x * 2; x;\", {10.0, 12.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x * c(2,4); x;\", {10.0, 24.0});\n\tEidosAssertScriptRaise(\"x = 5.0:7.0; x = x * 3.0:4.0; x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.0:6.0; x = x * 3.0:5.0; x;\", 19, \"operator requires that either\");\n\t\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x ^ 2; x;\", 25.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x ^ 2; x;\", {25.0, 36.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x ^ c(2,3); x;\", {25.0, 216.0});\n\tEidosAssertScriptSuccess_F(\"x = 5; x = x ^ 2.0; x;\", 25.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x ^ 2.0; x;\", {25.0, 36.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5:6; x = x ^ c(2.0,3.0); x;\", {25.0, 216.0});\n\tEidosAssertScriptRaise(\"x = 5:7; x = x ^ (3:4); x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5:6; x = x ^ (3:5); x;\", 15, \"operator requires that either\");\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x ^ 2.0; x;\", 25.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x ^ 2.0; x;\", {25.0, 36.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x ^ c(2.0,3.0); x;\", {25.0, 216.0});\n\tEidosAssertScriptSuccess_F(\"x = 5.0; x = x ^ 2; x;\", 25.0);\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x ^ 2; x;\", {25.0, 36.0});\n\tEidosAssertScriptSuccess_FV(\"x = 5.0:6.0; x = x ^ c(2,3); x;\", {25.0, 216.0});\n\tEidosAssertScriptRaise(\"x = 5.0:7.0; x = x ^ (3.0:4.0); x;\", 19, \"operator requires that either\");\n\tEidosAssertScriptRaise(\"x = 5.0:6.0; x = x ^ (3.0:5.0); x;\", 19, \"operator requires that either\");\n\t\n\t// scoped compound assignment (see https://github.com/MesserLab/SLiM/issues/430)\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { x = x + 1; } x = 1; mod(); x;\", 1);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { x = x + 1; } x = 1.0; mod(); x;\", 1.0);\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { defineGlobal('x', x + 1); } x = 1; mod(); x;\", 2);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { defineGlobal('x', x + 1); } x = 1.0; mod(); x;\", 2.0);\n\t\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { x = x - 1; } x = 1; mod(); x;\", 1);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { x = x - 1; } x = 1.0; mod(); x;\", 1.0);\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { defineGlobal('x', x - 1); } x = 1; mod(); x;\", 0);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { defineGlobal('x', x - 1); } x = 1.0; mod(); x;\", 0.0);\n\t\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { x = c(x, 2); } x = 1; mod(); x;\", 1);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { x = c(x, 2); } x = 1.0; mod(); x;\", 1.0);\n\tEidosAssertScriptSuccess_IV(\"function (void)mod(void) { defineGlobal('x', c(x, 2)); } x = 1; mod(); x;\", {1, 2});\n\tEidosAssertScriptSuccess_FV(\"function (void)mod(void) { defineGlobal('x', c(x, 2)); } x = 1.0; mod(); x;\", {1.0, 2.0});\n\t\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { x = cbind(x, 2); } x = 1; mod(); x;\", 1);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { x = cbind(x, 2.0); } x = 1.0; mod(); x;\", 1.0);\n\tEidosAssertScriptSuccess_L(\"function (void)mod(void) { defineGlobal('x', cbind(x, 2)); } x = 1; mod(); identical(x, cbind(1, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"function (void)mod(void) { defineGlobal('x', cbind(x, 2.0)); } x = 1.0; mod(); identical(x, cbind(1.0, 2.0));\", true);\n\t\n\tEidosAssertScriptSuccess_I(\"function (void)mod(void) { x = rbind(x, 2); } x = 1; mod(); x;\", 1);\n\tEidosAssertScriptSuccess_F(\"function (void)mod(void) { x = rbind(x, 2.0); } x = 1.0; mod(); x;\", 1.0);\n\tEidosAssertScriptSuccess_L(\"function (void)mod(void) { defineGlobal('x', rbind(x, 2)); } x = 1; mod(); identical(x, rbind(1, 2));\", true);\n\tEidosAssertScriptSuccess_L(\"function (void)mod(void) { defineGlobal('x', rbind(x, 2.0)); } x = 1.0; mod(); identical(x, rbind(1.0, 2.0));\", true);\n\t\n#if EIDOS_HAS_OVERFLOW_BUILTINS\n\tEidosAssertScriptRaise(\"x = 5e18; x = x + 5e18;\", 16, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"x = c(5e18, 0); x = x + 5e18;\", 22, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"x = -5e18; x = x - 5e18;\", 17, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"x = c(-5e18, 0); x = x - 5e18;\", 23, \"overflow with the binary\");\n\tEidosAssertScriptRaise(\"x = 5e18; x = x * 2;\", 16, \"multiplication overflow\");\n\tEidosAssertScriptRaise(\"x = c(5e18, 0); x = x * 2;\", 22, \"multiplication overflow\");\n#endif\n}\n\n#pragma mark operator &\nvoid _RunOperatorLogicalAndTests(void)\n{\n\t// operator &\n\tEidosAssertScriptRaise(\"NULL&T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL&0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL&0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL&'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL&_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL&(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T&NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0&NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5&NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'&NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)&NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)&NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"&NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T&T&T;\", true);\n\tEidosAssertScriptSuccess_L(\"T&T&F;\", false);\n\tEidosAssertScriptSuccess_L(\"T&F&T;\", false);\n\tEidosAssertScriptSuccess_L(\"T&F&F;\", false);\n\tEidosAssertScriptSuccess_L(\"F&T&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&T&F;\", false);\n\tEidosAssertScriptSuccess_L(\"F&F&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&F&F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & F;\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & T;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"F & c(T,F,T,F);\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"T & c(T,F,T,F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & c(T,T,F,F);\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & c(F,F,T,T);\", {false, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,T,F,F) & c(T,F,T,F);\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(F,F,T,T) & c(T,F,T,F);\", {false, false, true, false});\n\tEidosAssertScriptRaise(\"c(T,F,T,F) & c(F,F);\", 11, \"not compatible in size()\");\n\tEidosAssertScriptRaise(\"c(T,T) & c(T,F,T,F);\", 7, \"not compatible in size()\");\n\tEidosAssertScriptRaise(\"c(T,F,T,F) & _Test(3);\", 11, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(3) & c(T,F,T,F);\", 9, \"is not supported by\");\n\tEidosAssertScriptSuccess_L(\"5&T&T;\", true);\n\tEidosAssertScriptSuccess_L(\"T&5&F;\", false);\n\tEidosAssertScriptSuccess_L(\"T&F&5;\", false);\n\tEidosAssertScriptSuccess_L(\"5&F&F;\", false);\n\tEidosAssertScriptSuccess_L(\"0&T&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&T&0;\", false);\n\tEidosAssertScriptSuccess_L(\"F&0&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&0&F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & 0;\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(7,0,5,0) & T;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"F & c(5,0,7,0);\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"9 & c(T,F,T,F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(7,0,5,0) & c(T,T,F,F);\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & c(0,0,5,7);\", {false, false, true, false});\n\tEidosAssertScriptSuccess_L(\"5.0&T&T;\", true);\n\tEidosAssertScriptSuccess_L(\"T&5.0&F;\", false);\n\tEidosAssertScriptSuccess_L(\"T&F&5.0;\", false);\n\tEidosAssertScriptSuccess_L(\"5.0&F&F;\", false);\n\tEidosAssertScriptSuccess_L(\"0.0&T&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&T&0.0;\", false);\n\tEidosAssertScriptSuccess_L(\"F&0.0&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&0.0&F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & 0.0;\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(7.0,0.0,5.0,0.0) & T;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"F & c(5.0,0.0,7.0,0.0);\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"9.0 & c(T,F,T,F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(7.0,0.0,5.0,0.0) & c(T,T,F,F);\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & c(0.0,0.0,5.0,7.0);\", {false, false, true, false});\n\tEidosAssertScriptSuccess_L(\"INF&T&T;\", true);\n\tEidosAssertScriptSuccess_L(\"T&INF&F;\", false);\n\tEidosAssertScriptRaise(\"T&NAN&F;\", 1, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"NAN&T&T;\", 3, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"c(7.0,0.0,5.0,0.0) & c(T,T,NAN,F);\", 19, \"cannot be converted\");\n\tEidosAssertScriptSuccess_L(\"'foo'&T&T;\", true);\n\tEidosAssertScriptSuccess_L(\"T&'foo'&F;\", false);\n\tEidosAssertScriptSuccess_L(\"T&F&'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"'foo'&F&F;\", false);\n\tEidosAssertScriptSuccess_L(\"''&T&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&T&'';\", false);\n\tEidosAssertScriptSuccess_L(\"F&''&T;\", false);\n\tEidosAssertScriptSuccess_L(\"F&''&F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & '';\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo','','foo','') & T;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"F & c('foo','','foo','');\", {false, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"'foo' & c(T,F,T,F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo','','foo','') & c(T,T,F,F);\", {true, false, false, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) & c('','','foo','foo');\", {false, false, true, false});\n\t\n\t// operator &: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with logical should suffice\n\tEidosAssertScriptSuccess_L(\"identical(T & T, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & F, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & F & matrix(T), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T) & F, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T) & matrix(T) & T, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T) & matrix(F) & T, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T) & matrix(F) & c(T,F,T), c(F,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T & matrix(T) & matrix(T) & c(T,F,T), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) & T & matrix(T) & matrix(F), c(F,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) & T & matrix(T) & matrix(T), c(T,F,T));\", true);\n\tEidosAssertScriptRaise(\"identical(c(T,F,T) & T & matrix(c(T,T,F)) & matrix(F), c(T,F,F));\", 19, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) & T & matrix(c(T,T,F)) & matrix(c(T,F,T)), matrix(c(T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & T, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & T & F, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & matrix(T) & T & T, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & matrix(F) & T & T, matrix(F));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(T) & matrix(c(T,F)) & T & T, matrix(F));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(c(T,F)) & matrix(F) & T & T, matrix(F));\", 25, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(T,T)) & matrix(c(T,T)) & T & T, matrix(c(T,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(T,T)) & matrix(c(T,F)) & T & T, matrix(c(T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(T,T,T)) & matrix(c(T,F,F)) & c(T,F,T) & T, matrix(c(T,F,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,T)) & matrix(c(T,T,F)) & c(F,T,T) & T, matrix(c(F,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & T & matrix(F) & c(T,F,T), c(F,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & T & matrix(T) & c(T,F,T), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & c(T,F,T) & T & matrix(F), c(F,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & c(T,F,T) & T & matrix(T), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) & matrix(T), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) & matrix(F), matrix(F));\", true);\n}\n\n#pragma mark operator |\nvoid _RunOperatorLogicalOrTests(void)\n{\n\t// operator |\n\tEidosAssertScriptRaise(\"NULL|T;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL|0;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL|0.5;\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL|'foo';\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL|_Test(7);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"NULL|(0:2);\", 4, \"is not supported by\");\n\tEidosAssertScriptRaise(\"T|NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0|NULL;\", 1, \"is not supported by\");\n\tEidosAssertScriptRaise(\"0.5|NULL;\", 3, \"is not supported by\");\n\tEidosAssertScriptRaise(\"'foo'|NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(7)|NULL;\", 8, \"is not supported by\");\n\tEidosAssertScriptRaise(\"(0:2)|NULL;\", 5, \"is not supported by\");\n\tEidosAssertScriptRaise(\"|NULL;\", 0, \"unexpected token\");\n\tEidosAssertScriptSuccess_L(\"T|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|T|F;\", true);\n\tEidosAssertScriptSuccess_L(\"T|F|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|F|F;\", true);\n\tEidosAssertScriptSuccess_L(\"F|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|T|F;\", true);\n\tEidosAssertScriptSuccess_L(\"F|F|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|F|F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | F;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | T;\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"F | c(T,F,T,F);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"T | c(T,F,T,F);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | c(T,T,F,F);\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | c(F,F,T,T);\", {true, false, true, true});\n\tEidosAssertScriptSuccess_LV(\"c(T,T,F,F) | c(T,F,T,F);\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(F,F,T,T) | c(T,F,T,F);\", {true, false, true, true});\n\tEidosAssertScriptRaise(\"c(T,F,T,F) | c(F,F);\", 11, \"not compatible in size()\");\n\tEidosAssertScriptRaise(\"c(T,T) | c(T,F,T,F);\", 7, \"not compatible in size()\");\n\tEidosAssertScriptRaise(\"c(T,F,T,F) | _Test(3);\", 11, \"is not supported by\");\n\tEidosAssertScriptRaise(\"_Test(3) | c(T,F,T,F);\", 9, \"is not supported by\");\n\tEidosAssertScriptSuccess_L(\"5|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|5|F;\", true);\n\tEidosAssertScriptSuccess_L(\"T|F|5;\", true);\n\tEidosAssertScriptSuccess_L(\"5|F|F;\", true);\n\tEidosAssertScriptSuccess_L(\"0|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|T|0;\", true);\n\tEidosAssertScriptSuccess_L(\"F|0|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|0|F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | 0;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(7,0,5,0) | T;\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"F | c(5,0,7,0);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"9 | c(T,F,T,F);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"c(7,0,5,0) | c(T,T,F,F);\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | c(0,0,5,7);\", {true, false, true, true});\n\tEidosAssertScriptSuccess_L(\"5.0|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|5.0|F;\", true);\n\tEidosAssertScriptSuccess_L(\"T|F|5.0;\", true);\n\tEidosAssertScriptSuccess_L(\"5.0|F|F;\", true);\n\tEidosAssertScriptSuccess_L(\"0.0|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|T|0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"F|0.0|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|0.0|F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | 0.0;\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(7.0,0.0,5.0,0.0) | T;\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"F | c(5.0,0.0,7.0,0.0);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"9.0 | c(T,F,T,F);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"c(7.0,0.0,5.0,0.0) | c(T,T,F,F);\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | c(0.0,0.0,5.0,7.0);\", {true, false, true, true});\n\tEidosAssertScriptSuccess_L(\"INF|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|INF|F;\", true);\n\tEidosAssertScriptRaise(\"T|NAN|F;\", 1, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"NAN|T|T;\", 3, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"c(7.0,0.0,5.0,0.0) | c(T,T,NAN,F);\", 19, \"cannot be converted\");\n\tEidosAssertScriptSuccess_L(\"'foo'|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"T|'foo'|F;\", true);\n\tEidosAssertScriptSuccess_L(\"T|F|'foo';\", true);\n\tEidosAssertScriptSuccess_L(\"'foo'|F|F;\", true);\n\tEidosAssertScriptSuccess_L(\"''|T|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|T|'';\", true);\n\tEidosAssertScriptSuccess_L(\"F|''|T;\", true);\n\tEidosAssertScriptSuccess_L(\"F|''|F;\", false);\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | '';\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"c('foo','','foo','') | T;\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"F | c('foo','','foo','');\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"'foo' | c(T,F,T,F);\", {true, true, true, true});\n\tEidosAssertScriptSuccess_LV(\"c('foo','','foo','') | c(T,T,F,F);\", {true, true, true, false});\n\tEidosAssertScriptSuccess_LV(\"c(T,F,T,F) | c('','','foo','foo');\", {true, false, true, true});\n\t\n\t// operator |: test with mixed singletons, vectors, matrices, and arrays; the dimensionality code is shared across all operand types, so testing it with logical should suffice\n\tEidosAssertScriptSuccess_L(\"identical(T | F, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | F, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(T | matrix(F), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | F | matrix(T), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | matrix(F) | F, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | matrix(F) | matrix(T) | F, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | matrix(F) | matrix(F) | T, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | matrix(T) | matrix(F) | c(T,F,T), c(T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(F | matrix(F) | matrix(F) | c(T,F,T), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) | T | matrix(F) | matrix(F), c(T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) | F | matrix(T) | matrix(F), c(T,T,T));\", true);\n\tEidosAssertScriptRaise(\"identical(c(T,F,T) | F | matrix(c(T,T,F)) | matrix(F), c(T,T,F));\", 19, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(c(T,F,T) | F | matrix(c(T,F,F)) | matrix(c(T,F,T)), matrix(c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) | F, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | F | F, matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | matrix(F) | T | F, matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) | matrix(F) | F | F, matrix(T));\", true);\n\tEidosAssertScriptRaise(\"identical(matrix(T) | matrix(c(T,F)) | T | T, matrix(F));\", 20, \"non-conformable\");\n\tEidosAssertScriptRaise(\"identical(matrix(c(T,F)) | matrix(F) | T | T, matrix(F));\", 25, \"non-conformable\");\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(T,F)) | matrix(c(F,F)) | F | F, matrix(c(T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T)) | matrix(c(F,F)) | F | T, matrix(c(T,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,F)) | matrix(c(T,F,F)) | c(F,F,F) | F, matrix(c(T,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(c(F,T,T)) | matrix(c(F,T,F)) | c(F,F,F) | T, matrix(c(T,T,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) | F | matrix(F) | c(T,F,T), c(T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | F | matrix(F) | c(T,F,T), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | c(T,F,T) | T | matrix(F), c(T,T,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | c(T,F,F) | F | matrix(F), c(T,F,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(T) | matrix(T), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(matrix(F) | matrix(F), matrix(F));\", true);\n}\n\n#pragma mark operator !\nvoid _RunOperatorLogicalNotTests(void)\n{\n\t// operator !\n\tEidosAssertScriptRaise(\"!NULL;\", 0, \"is not supported by\");\n\tEidosAssertScriptSuccess_L(\"!T;\", false);\n\tEidosAssertScriptSuccess_L(\"!F;\", true);\n\tEidosAssertScriptSuccess_L(\"!7;\", false);\n\tEidosAssertScriptSuccess_L(\"!0;\", true);\n\tEidosAssertScriptSuccess_L(\"!7.1;\", false);\n\tEidosAssertScriptSuccess_L(\"!0.0;\", true);\n\tEidosAssertScriptSuccess_L(\"!INF;\", false);\n\tEidosAssertScriptRaise(\"!NAN;\", 0, \"cannot be converted\");\n\tEidosAssertScriptSuccess_L(\"!'foo';\", false);\n\tEidosAssertScriptSuccess_L(\"!'';\", true);\n\tEidosAssertScriptSuccess_LV(\"!logical(0);\", {});\n\tEidosAssertScriptSuccess_LV(\"!integer(0);\", {});\n\tEidosAssertScriptSuccess_LV(\"!float(0);\", {});\n\tEidosAssertScriptSuccess_LV(\"!string(0);\", {});\n\tEidosAssertScriptRaise(\"!object();\", 0, \"is not supported by\");\n\tEidosAssertScriptSuccess_LV(\"!c(F,T,F,T);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"!c(0,5,0,1);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"!c(0,5.0,0,1.0);\", {true, false, true, false});\n\tEidosAssertScriptRaise(\"!c(0,NAN,0,1.0);\", 0, \"cannot be converted\");\n\tEidosAssertScriptSuccess_LV(\"!c(0,INF,0,1.0);\", {true, false, true, false});\n\tEidosAssertScriptSuccess_LV(\"!c('','foo','','bar');\", {true, false, true, false});\n\tEidosAssertScriptRaise(\"!_Test(5);\", 0, \"is not supported by\");\n\t\n\t// operator |: test with matrices and arrays; the dimensionality code is shared across all operand types, so testing it with logical should suffice\n\tEidosAssertScriptSuccess_L(\"identical(!T, F);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!F, T);\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!c(T,F,T), c(F,T,F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!c(F,T,F), c(T,F,T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!matrix(T), matrix(F));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!matrix(F), matrix(T));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!matrix(c(T,F,T)), matrix(c(F,T,F)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!matrix(c(F,T,F)), matrix(c(T,F,T)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!array(T, c(1,1,1)), array(F, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!array(F, c(1,1,1)), array(T, c(1,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!array(c(T,F,T), c(3,1,1)), array(c(F,T,F), c(3,1,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!array(c(F,T,F), c(1,3,1)), array(c(T,F,T), c(1,3,1)));\", true);\n\tEidosAssertScriptSuccess_L(\"identical(!array(c(T,F,T), c(1,1,3)), array(c(F,T,F), c(1,1,3)));\", true);\n}\n\n#pragma mark operator ?\nvoid _RunOperatorTernaryConditionalTests(void)\n{\n\t// operator ?-else\n\tEidosAssertScriptSuccess_I(\"T ? 23 else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"F ? 23 else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"9 ? 23 else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"0 ? 23 else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"6 > 5 ? 23 else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"6 < 5 ? 23 else 42;\", 42);\n\tEidosAssertScriptRaise(\"6 == 6:9 ? 23 else 42;\", 9, \"condition for ternary conditional has size()\");\n\tEidosAssertScriptSuccess_I(\"(6 == (6:9))[0] ? 23 else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"(6 == (6:9))[1] ? 23 else 42;\", 42);\n\tEidosAssertScriptRaise(\"NAN ? 23 else 42;\", 4, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"_Test(6) ? 23 else 42;\", 9, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"NULL ? 23 else 42;\", 5, \"condition for ternary conditional has size()\");\n\tEidosAssertScriptRaise(\"T ? 23; else 42;\", 6, \"expected 'else'\");\n\tEidosAssertScriptRaise(\"T ? 23; x = 10;\", 6, \"expected 'else'\");\n\tEidosAssertScriptRaise(\"(T ? x else y) = 10;\", 15, \"lvalue required\");\n\tEidosAssertScriptSuccess_I(\"x = T ? 23 else 42; x;\", 23);\n\tEidosAssertScriptSuccess_I(\"x = F ? 23 else 42; x;\", 42);\n\t\n\t// test right-associativity; this produces 2 if ? else is left-associative since the left half would then evaluate to 1, which is T\n\tEidosAssertScriptSuccess_I(\"a = 0; a == 0 ? 1 else a == 1 ? 2 else 4;\", 1);\n}\n\t\n\t// ************************************************************************************\n\t//\n\t//\tKeyword tests\n\t//\n\t\n#pragma mark if\nvoid _RunKeywordIfTests(void)\n{\n\t// if\n\tEidosAssertScriptSuccess_I(\"if (T) 23;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if (F) 23;\");\n\tEidosAssertScriptSuccess_I(\"if (9) 23;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if (0) 23;\");\n\tEidosAssertScriptSuccess_I(\"if (6 > 5) 23;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if (6 < 5) 23;\");\n\tEidosAssertScriptRaise(\"if (6 == (6:9)) 23;\", 0, \"condition for if statement has size()\");\n\tEidosAssertScriptSuccess_I(\"if ((6 == (6:9))[0]) 23;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if ((6 == (6:9))[1]) 23;\");\n\tEidosAssertScriptRaise(\"if (NAN) 23;\", 0, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"if (_Test(6)) 23;\", 0, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"if (NULL) 23;\", 0, \"condition for if statement has size()\");\n\tEidosAssertScriptSuccess_I(\"if (matrix(1)) 23;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if (matrix(0)) 23;\");\n\tEidosAssertScriptRaise(\"if (matrix(1:3)) 23;\", 0, \"condition for if statement has size()\");\n\t\n\t// if-else\n\tEidosAssertScriptSuccess_I(\"if (T) 23; else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"if (F) 23; else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (9) 23; else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"if (0) 23; else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (6 > 5) 23; else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"if (6 < 5) 23; else 42;\", 42);\n\tEidosAssertScriptRaise(\"if (6 == (6:9)) 23; else 42;\", 0, \"condition for if statement has size()\");\n\tEidosAssertScriptSuccess_I(\"if ((6 == (6:9))[0]) 23; else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"if ((6 == (6:9))[1]) 23; else 42;\", 42);\n\tEidosAssertScriptRaise(\"if (NAN) 23; else 42;\", 0, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"if (_Test(6)) 23; else 42;\", 0, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"if (NULL) 23; else 42;\", 0, \"condition for if statement has size()\");\n\tEidosAssertScriptSuccess_I(\"if (matrix(1)) 23; else 42;\", 23);\n\tEidosAssertScriptSuccess_I(\"if (matrix(0)) 23; else 42;\", 42);\n\tEidosAssertScriptRaise(\"if (matrix(1:3)) 23; else 42;\", 0, \"condition for if statement has size()\");\n}\n\n#pragma mark do\nvoid _RunKeywordDoTests(void)\n{\n\t// do\n\tEidosAssertScriptSuccess_I(\"x=1; do x=x*2; while (x<100); x;\", 128);\n\tEidosAssertScriptSuccess_I(\"x=200; do x=x*2; while (x<100); x;\", 400);\n\tEidosAssertScriptSuccess_I(\"x=1; do { x=x*2; x=x+1; } while (x<100); x;\", 127);\n\tEidosAssertScriptSuccess_I(\"x=200; do { x=x*2; x=x+1; } while (x<100); x;\", 401);\n\tEidosAssertScriptRaise(\"x=1; do x=x*2; while (x < 100:102); x;\", 5, \"condition for do-while loop has size()\");\n\tEidosAssertScriptRaise(\"x=200; do x=x*2; while (x < 100:102); x;\", 7, \"condition for do-while loop has size()\");\n\tEidosAssertScriptSuccess_I(\"x=1; do x=x*2; while ((x < 100:102)[0]); x;\", 128);\n\tEidosAssertScriptSuccess_I(\"x=200; do x=x*2; while ((x < 100:102)[0]); x;\", 400);\n\tEidosAssertScriptRaise(\"x=200; do x=x*2; while (NAN); x;\", 7, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"x=200; do x=x*2; while (_Test(6)); x;\", 7, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"x=200; do x=x*2; while (NULL); x;\", 7, \"condition for do-while loop has size()\");\n\tEidosAssertScriptSuccess_I(\"x=10; do x=x-1; while (x); x;\", 0);\n}\n\n#pragma mark while\nvoid _RunKeywordWhileTests(void)\n{\n\t// while\n\tEidosAssertScriptSuccess_I(\"x=1; while (x<100) x=x*2; x;\", 128);\n\tEidosAssertScriptSuccess_I(\"x=200; while (x<100) x=x*2; x;\", 200);\n\tEidosAssertScriptSuccess_I(\"x=1; while (x<100) { x=x*2; x=x+1; } x;\", 127);\n\tEidosAssertScriptSuccess_I(\"x=200; while (x<100) { x=x*2; x=x+1; } x;\", 200);\n\tEidosAssertScriptRaise(\"x=1; while (x < 100:102) x=x*2; x;\", 5, \"condition for while loop has size()\");\n\tEidosAssertScriptRaise(\"x=200; while (x < 100:102) x=x*2; x;\", 7, \"condition for while loop has size()\");\n\tEidosAssertScriptSuccess_I(\"x=1; while ((x < 100:102)[0]) x=x*2; x;\", 128);\n\tEidosAssertScriptSuccess_I(\"x=200; while ((x < 100:102)[0]) x=x*2; x;\", 200);\n\tEidosAssertScriptRaise(\"x=200; while (NAN) x=x*2; x;\", 7, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"x=200; while (_Test(6)) x=x*2; x;\", 7, \"cannot be converted\");\n\tEidosAssertScriptRaise(\"x=200; while (NULL) x=x*2; x;\", 7, \"condition for while loop has size()\");\n\tEidosAssertScriptSuccess_I(\"x=10; while (x) x=x-1; x;\", 0);\n}\n\n#pragma mark for / in\nvoid _RunKeywordForInTests(void)\n{\n\t// for and in\n\tEidosAssertScriptSuccess(\"x=0; for (y in integer(0)) x=x+1; x;\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess(\"x=0; for (y in float(0)) x=x+1; x;\", gStaticEidosValue_Integer0);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 33) x=x+y; x;\", 33);\n\tEidosAssertScriptSuccess(\"x=0; for (y in 33) x=x+1; x;\", gStaticEidosValue_Integer1);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 0:0) x=x+1; x;\", 1);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 0:1) x=x+1; x;\", 2);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:0) x=x+1; x;\", 2);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 0:4) x=x+1; x;\", 5);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 4:0) x=x+1; x;\", 5);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) x=x+1; x;\", 10);\n\tEidosAssertScriptRaise(\"x=0; for (y in 1:10) { x=x+y; y = 7; } x;\", 32, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"x=0; for (y in 1:10) { x=x+1; y = 7; } x;\", 32, \"cannot be redefined\");\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 10:1) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 10:1) x=x+1; x;\", 10);\n\tEidosAssertScriptSuccess_F(\"x=0; for (y in 1.0:10) x=x+y; x;\", 55.0);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1.0:10) x=x+1; x;\", 10);\n\tEidosAssertScriptSuccess_F(\"x=0; for (y in 1:10.0) x=x+y; x;\", 55.0);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10.0) x=x+1; x;\", 10);\n\tEidosAssertScriptSuccess_S(\"x=0; for (y in c('foo', 'bar')) x=x+y; x;\", \"0foobar\");\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in c(T,T,F,F,T,F)) x=x+asInteger(y); x;\", 3);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in _Test(7)) x=x+y._yolk; x;\", 7);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in rep(_Test(7),3)) x=x+y._yolk; x;\", 21);\n\tEidosAssertScriptRaise(\"x=0; y=0:2; for (y[0] in 2:4) x=x+sum(y); x;\", 18, \"unexpected token\");\t// lvalue must be an identifier, at present\n\tEidosAssertScriptRaise(\"x=0; y=0:2; for (y.z in 2:4) x=x+sum(y); x;\", 18, \"unexpected token\");\t// lvalue must be an identifier, at present\n\tEidosAssertScriptRaise(\"x=0; for (y in NULL) x;\", 5, \"does not allow NULL\");\n\tEidosAssertScriptSuccess_I(\"x=0; q=integer(0); for (y in seqAlong(q)) x=x+1; x;\", 0);\n\tEidosAssertScriptSuccess_I(\"x=0; q=float(0); for (y in seqAlong(q)) x=x+1; x;\", 0);\n\tEidosAssertScriptSuccess_I(\"x=0; q=11:20; for (y in seqAlong(q)) x=x+y; x;\", 45);\n\tEidosAssertScriptSuccess_I(\"x=0; q=11:20; for (y in seqAlong(q)) x=x+1; x;\", 10);\n\tEidosAssertScriptRaise(\"x=0; q=11:20; for (y in seqAlong(q, 5)) x=x+y; x;\", 24, \"too many arguments supplied\");\n\tEidosAssertScriptRaise(\"x=0; q=11:20; for (y in seqAlong()) x=x+y; x;\", 24, \"missing required\");\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in seq(1,10)) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in seq(1,10)) x=x+1; x;\", 10);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in seqLen(5)) x=x+y+2; x;\", 20);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in seqLen(1)) x=x+y+2; x;\", 2);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in seqLen(0)) x=x+y+2; x;\", 0);\n\tEidosAssertScriptRaise(\"x=0; for (y in seqLen(-1)) x=x+y+2; x;\", 15, \"requires length to be\");\n\tEidosAssertScriptRaise(\"x=0; for (y in seqLen(5:6)) x=x+y+2; x;\", 15, \"must be a singleton\");\n\tEidosAssertScriptRaise(\"x=0; for (y in seqLen('f')) x=x+y+2; x;\", 15, \"cannot be type\");\n\t\n\t// additional tests for zero-length ranges; seqAlong() is treated separately in the for() code, so it is tested separately here\n\tEidosAssertScriptSuccess_I(\"i=10; for (i in integer(0)) ; i;\", 10);\n\tEidosAssertScriptSuccess_I(\"i=10; for (i in seqAlong(integer(0))) ; i;\", 10);\n\tEidosAssertScriptSuccess_I(\"i=10; b=13; for (i in integer(0)) b=i; i;\", 10);\n\tEidosAssertScriptSuccess_I(\"i=10; b=13; for (i in seqAlong(integer(0))) b=i; i;\", 10);\n\tEidosAssertScriptSuccess_I(\"i=10; b=13; for (i in integer(0)) b=i; b;\", 13);\n\tEidosAssertScriptSuccess_I(\"i=10; b=13; for (i in seqAlong(integer(0))) b=i; b;\", 13);\n\t\n\tEidosAssertScriptRaise(\"for (i in matrix(5):9) i;\", 19, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"for (i in 1:matrix(5)) i;\", 11, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"for (i in matrix(3):matrix(5)) i;\", 19, \"must not be matrices or arrays\");\n\tEidosAssertScriptRaise(\"for (i in matrix(5:8):9) i;\", 21, \"must have size() == 1\");\n\tEidosAssertScriptRaise(\"for (i in 1:matrix(5:8)) i;\", 11, \"must have size() == 1\");\n\tEidosAssertScriptRaise(\"for (i in matrix(1:3):matrix(5:7)) i;\", 21, \"must have size() == 1\");\n\tEidosAssertScriptSuccess_I(\"x = 0; for (i in seqAlong(matrix(1))) x=x+i; x;\", 0);\n\tEidosAssertScriptSuccess_I(\"x = 0; for (i in seqAlong(matrix(1:3))) x=x+i; x;\", 3);\n\t\n\t// protection against changing loop index variables\n\tEidosAssertScriptRaise(\"for (x in 1:10) x = 5;\", 18, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"for (x in 1:10) x[0] = 5;\", 21, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"for (x in 1:10) x = c(x, 5);\", 18, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"for (x in 1:10) x = x + 1;\", 18, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"for (x in 1:10) defineGlobal('x', 75);\", 16, \"cannot be redefined\");\n\tEidosAssertScriptRaise(\"for (x in 1:10) for (x in 2:5) y = 1;\", 21, \"cannot be redefined\");\n\t\n\t// interaction between the loop index variable and outside code\n\tEidosAssertScriptSuccess_I(\"x=0; y=100; for (y in 1:10) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"x=0; y=10:20; for (y in 1:10) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) x=x+y; y=100; x;\", 55);\n\tEidosAssertScriptSuccess_L(\"x=0; for (y in 1:10) x=x+y; y==10;\", true);\n\tEidosAssertScriptRaise(\"x=0; defineConstant('y', 100); for (y in 1:10) x=x+y; x;\", 36, \"cannot be redefined\");\n\tEidosAssertScriptSuccess_I(\"x=0; defineGlobal('y', 100); for (y in 1:10) x=x+y; x;\", 55);\n\tEidosAssertScriptSuccess_I(\"function (integer$)foo(integer$ i) { return i+1; } x=0; for (i in 1:5) x = x + foo(i); x;\", 20);\n\t\n\t// multiple 'in' clauses\n\tEidosAssertScriptSuccess_L(\"x = 0; y = 0; for (i in 1:10, j in 11:20) { x=x+i; y=y+j; } ((x == 55) & (y == 155));\", true);\n\tEidosAssertScriptSuccess_L(\"x = 0; y = 0; for (i in integer(0), j in float(0)) { x=x+i; y=y+j; } ((x == 0) & (y == 0));\", true);\n\tEidosAssertScriptRaise(\"x = 0; y = 0; for (i in 1:10, j in 11:21) ;\", 14, \"same number of iterations\");\n\tEidosAssertScriptSuccess_L(\"for (i in 1:3, j in c(_Test(1), _Test(2), _Test(3))) ; T;\", true);\n}\n\n#pragma mark next\nvoid _RunKeywordNextTests(void)\n{\n\t// next\n\tEidosAssertScriptRaise(\"next;\", 0, \"encountered with no enclosing loop\");\n\tEidosAssertScriptRaise(\"if (T) next;\", 7, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_VOID(\"if (F) next;\");\n\tEidosAssertScriptRaise(\"if (T) next; else 42;\", 7, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_I(\"if (F) next; else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (T) 23; else next;\", 23);\n\tEidosAssertScriptRaise(\"if (F) 23; else next;\", 16, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_I(\"x=1; do { x=x*2; if (x>50) next; x=x+1; } while (x<100); x;\", 124);\n\tEidosAssertScriptSuccess_I(\"x=1; while (x<100) { x=x*2; if (x>50) next; x=x+1; } x;\", 124);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) { if (y==5) next; x=x+y; } x;\", 50);\n}\n\n#pragma mark break\nvoid _RunKeywordBreakTests(void)\n{\n\t// break\n\tEidosAssertScriptRaise(\"break;\", 0, \"encountered with no enclosing loop\");\n\tEidosAssertScriptRaise(\"if (T) break;\", 7, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_VOID(\"if (F) break;\");\n\tEidosAssertScriptRaise(\"if (T) break; else 42;\", 7, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_I(\"if (F) break; else 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (T) 23; else break;\", 23);\n\tEidosAssertScriptRaise(\"if (F) 23; else break;\", 16, \"encountered with no enclosing loop\");\n\tEidosAssertScriptSuccess_I(\"x=1; do { x=x*2; if (x>50) break; x=x+1; } while (x<100); x;\", 62);\n\tEidosAssertScriptSuccess_I(\"x=1; while (x<100) { x=x*2; if (x>50) break; x=x+1; } x;\", 62);\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) { if (y==5) break; x=x+y; } x;\", 10);\n}\n\n#pragma mark return\nvoid _RunKeywordReturnTests(void)\n{\n\t// return\n\tEidosAssertScriptSuccess_VOID(\"return;\");\n\tEidosAssertScriptSuccess_NULL(\"return NULL;\");\n\tEidosAssertScriptSuccess_I(\"return -13;\", -13);\n\tEidosAssertScriptSuccess_VOID(\"if (T) return;\");\n\tEidosAssertScriptSuccess_NULL(\"if (T) return NULL;\");\n\tEidosAssertScriptSuccess_I(\"if (T) return -13;\", -13);\n\tEidosAssertScriptSuccess_VOID(\"if (F) return;\");\n\tEidosAssertScriptSuccess_VOID(\"if (F) return NULL;\");\n\tEidosAssertScriptSuccess_VOID(\"if (F) return -13;\");\n\tEidosAssertScriptSuccess_VOID(\"if (T) return; else return 42;\");\n\tEidosAssertScriptSuccess_NULL(\"if (T) return NULL; else return 42;\");\n\tEidosAssertScriptSuccess_I(\"if (T) return -13; else return 42;\", -13);\n\tEidosAssertScriptSuccess_I(\"if (F) return; else return 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (F) return -13; else return 42;\", 42);\n\tEidosAssertScriptSuccess_I(\"if (T) return 23; else return;\", 23);\n\tEidosAssertScriptSuccess_I(\"if (T) return 23; else return -13;\", 23);\n\tEidosAssertScriptSuccess_VOID(\"if (F) return 23; else return;\");\n\tEidosAssertScriptSuccess_NULL(\"if (F) return 23; else return NULL;\");\n\tEidosAssertScriptSuccess_I(\"if (F) return 23; else return -13;\", -13);\n\tEidosAssertScriptSuccess_VOID(\"x=1; do { x=x*2; if (x>50) return; x=x+1; } while (x<100); x;\");\n\tEidosAssertScriptSuccess_I(\"x=1; do { x=x*2; if (x>50) return x-5; x=x+1; } while (x<100); x;\", 57);\n\tEidosAssertScriptSuccess_VOID(\"x=1; while (x<100) { x=x*2; if (x>50) return; x=x+1; } x;\");\n\tEidosAssertScriptSuccess_I(\"x=1; while (x<100) { x=x*2; if (x>50) return x-5; x=x+1; } x;\", 57);\n\tEidosAssertScriptSuccess_VOID(\"x=0; for (y in 1:10) { if (y==5) return; x=x+y; } x;\");\n\tEidosAssertScriptSuccess_I(\"x=0; for (y in 1:10) { if (y==5) return x-5; x=x+y; } x;\", 5);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_test_parallel.h",
    "content": "R\"V0G0N(\n\n\n// This file is actually Eidos code!  It is run by _RunUserDefinedFunctionTests() in eidos_test.cpp.\n// The purpose of it is to test Eidos functions when run in parallel against the same functions run\n// single-threaded, to ensure that parallelization preserves results (to the extent possible).  The\n// reason to make this a separate file is mostly because otherwise Xcode's indenting algorithm gets\n// very confused.  Note this whole thing is one big C++ string literal.\n\n// Note that this test file gets subdivided and run in chunks; this improves error reporting.  See\n// _RunUserDefinedFunctionTests() in eidos_test_functions_other.cpp.\n\n// ***********************************************************************************************\n\n// test that the number of threads is working properly\n\nif (parallelGetNumThreads() <= 1) stop('running single-threaded in eidos_test_parallel');\n\nparallelSetNumThreads(1);\n\nif (parallelGetNumThreads() != 1) stop('failed to switch to single-threaded in eidos_test_parallel');\n\n// ***********************************************************************************************\n\n// test that the number of threads does not persist across tests\n\nif (parallelGetNumThreads() <= 1) stop('number of threads did not reset in eidos_test_parallel');\n\n// ***********************************************************************************************\n\n// (float)abs(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_ABS_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = abs(x);\nparallelSetNumThreads(1);\ny1 = abs(x);\nif (!identical(y1, yN)) stop('parallel abs(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)ceil(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_CEIL\n\nx = runif(1000000, -100, 100);\nyN = ceil(x);\nparallelSetNumThreads(1);\ny1 = ceil(x);\nif (!identical(y1, yN)) stop('parallel ceil(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)exp(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_EXP_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = exp(x);\nparallelSetNumThreads(1);\ny1 = exp(x);\nif (!identical(y1, yN)) stop('parallel exp(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)floor(float x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_FLOOR\n\nx = runif(1000000, -100, 100);\nyN = floor(x);\nparallelSetNumThreads(1);\ny1 = floor(x);\nif (!identical(y1, yN)) stop('parallel floor(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)log(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_LOG_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = log(x);\nparallelSetNumThreads(1);\ny1 = log(x);\nif (!identical(y1, yN)) stop('parallel log(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)log10(float x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_LOG10_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = log10(x);\nparallelSetNumThreads(1);\ny1 = log10(x);\nif (!identical(y1, yN)) stop('parallel log10(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)log2(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_LOG2_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = log2(x);\nparallelSetNumThreads(1);\ny1 = log2(x);\nif (!identical(y1, yN)) stop('parallel log2(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)match(integer x, integer table)\t\t\t\t\t\t// EIDOS_OMPMIN_MATCH_INT\n\ntable = sample(0:999, 500, replace=F);\nx = rdunif(1000000, 0, 999);\nyN = match(x, table);\nparallelSetNumThreads(1);\ny1 = match(x, table);\nif (!identical(y1, yN)) stop('parallel match(integer x, integer table) failed test');\n\n// ***********************************************************************************************\n\n// (integer)match(float x, float table)\t\t\t\t\t\t\t// EIDOS_OMPMIN_MATCH_FLOAT\n\ntable = sample(0.0:999, 500, replace=F);\nx = sample(table, 1000000, replace=T);\nyN = match(x, table);\nparallelSetNumThreads(1);\ny1 = match(x, table);\nif (!identical(y1, yN)) stop('parallel match(float x, float table) failed test');\n\n// ***********************************************************************************************\n\n// (integer)match(string x, string table)\t\t\t\t\t\t// EIDOS_OMPMIN_MATCH_STRING\n\ntable = asString(sample(0:999, 500, replace=F));\nx = asString(rdunif(1000000, 0, 999));\nyN = match(x, table);\nparallelSetNumThreads(1);\ny1 = match(x, table);\nif (!identical(y1, yN)) stop('parallel match(string x, string table) failed test');\n\n// ***********************************************************************************************\n\n// (integer)match(object x, object table)\t\t\t\t\t\t// EIDOS_OMPMIN_MATCH_OBJECT\n\ntable = sapply(0:499, \"Dictionary('a', applyValue);\");\nx = sample(table, 1000000, replace=T);\nyN = match(x, table);\nparallelSetNumThreads(1);\ny1 = match(x, table);\nif (!identical(y1, yN)) stop('parallel match(object x, object table) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(integer x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_R_INT\n\nx = 0:1000;\nyN = sample(x, 10000000, replace=T);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T);\nif (abs(mean(yN) - mean(y1)) > 0.5) stop('parallel sample(integer x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(float x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_R_FLOAT\n\nx = 0.0:1000;\nyN = sample(x, 10000000, replace=T);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T);\nif (abs(mean(yN) - mean(y1)) > 0.5) stop('parallel sample(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(object x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_R_OBJECT\n\nx = sapply(0:1000, \"Dictionary('a', applyValue);\");\nyN = sample(x, 10000000, replace=T);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T);\nif (abs(mean(yN.getValue(\"a\")) - mean(y1.getValue(\"a\"))) > 0.5) stop('parallel sample(object x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(integer x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_WR_INT\n\nx = 0:1000;\nw = runif(length(x), min=0.999, max=1.001);\nyN = sample(x, 10000000, replace=T, weights=w);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T, weights=w);\nif (abs(mean(yN) - mean(y1)) > 0.5) stop('parallel sample(integer x, weights=) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(float x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_WR_FLOAT\n\nx = 0.0:1000;\nw = runif(length(x), min=0.999, max=1.001);\nyN = sample(x, 10000000, replace=T, weights=w);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T, weights=w);\nif (abs(mean(yN) - mean(y1)) > 0.5) stop('parallel sample(float x, weights=) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sample(object x, replace=T, weights=NULL)\t\t\t// EIDOS_OMPMIN_SAMPLE_WR_OBJECT\n\nx = sapply(0:1000, \"Dictionary('a', applyValue);\");\nw = runif(length(x), min=0.999, max=1.001);\nyN = sample(x, 10000000, replace=T, weights=w);\nparallelSetNumThreads(1);\ny1 = sample(x, 10000000, replace=T, weights=w);\nif (abs(mean(yN.getValue(\"a\")) - mean(y1.getValue(\"a\"))) > 0.5) stop('parallel sample(object x, weights=) failed test');\n\n// ***********************************************************************************************\n\n// (integer)tabulate(integer bin)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_TABULATE\n\nvalues = rdunif(10000000, min=0, max=10000);\nyN = tabulate(values);\nparallelSetNumThreads(1);\ny1 = tabulate(values);\nif (!identical(y1, yN)) stop('parallel tabulate(integer bin) failed test');\n\n// ***********************************************************************************************\n\n// (integer)max(integer x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_MAX_INT\n\nx = rdunif(1000000, -100000000, 100000000);\nyN = max(x);\nparallelSetNumThreads(1);\ny1 = max(x);\nif (!identical(y1, yN)) stop('parallel max(integer x) failed test');\n\n// ***********************************************************************************************\n\n// (float)max(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_MAX_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = max(x);\nparallelSetNumThreads(1);\ny1 = max(x);\nif (!identical(y1, yN)) stop('parallel max(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)min(integer x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_MIN_INT\n\nx = rdunif(1000000, -100000000, 100000000);\nyN = min(x);\nparallelSetNumThreads(1);\ny1 = min(x);\nif (!identical(y1, yN)) stop('parallel min(integer x) failed test');\n\n// ***********************************************************************************************\n\n// (float)min(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_MIN_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = min(x);\nparallelSetNumThreads(1);\ny1 = min(x);\nif (!identical(y1, yN)) stop('parallel min(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)pmax(integer x, integer$ y)\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMAX_INT_1\n\nx = rdunif(1000000, -100000000, 100000000);\nyN = pmax(x, 1703);\nparallelSetNumThreads(1);\ny1 = pmax(x, 1703);\nif (!identical(y1, yN)) stop('parallel max(integer x, integer$ y) failed test');\n\n// ***********************************************************************************************\n\n// (integer)pmax(integer x, integer y)\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMAX_INT_2\n\na = rdunif(1000000, -100000000, 100000000);\nb = rdunif(1000000, -100000000, 100000000);\nyN = pmax(a, b);\nparallelSetNumThreads(1);\ny1 = pmax(a, b);\nif (!identical(y1, yN)) stop('parallel max(integer x, integer y) failed test');\n\n// ***********************************************************************************************\n\n// (float)pmax(float x, float$ y)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMAX_FLOAT_1\n\nx = runif(1000000, -100000000, 100000000);\nyN = pmax(x, 1703.0);\nparallelSetNumThreads(1);\ny1 = pmax(x, 1703.0);\nif (!identical(y1, yN)) stop('parallel max(float x, float$ y) failed test');\n\n// ***********************************************************************************************\n\n// (float)pmax(float x, float y)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMAX_FLOAT_2\n\na = runif(1000000, -100000000, 100000000);\nb = runif(1000000, -100000000, 100000000);\nyN = pmax(a, b);\nparallelSetNumThreads(1);\ny1 = pmax(a, b);\nif (!identical(y1, yN)) stop('parallel max(float x, float y) failed test');\n\n// ***********************************************************************************************\n\n// (integer)pmin(integer x, integer$ y)\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMIN_INT_1\n\nx = rdunif(1000000, -100000000, 100000000);\nyN = pmin(x, 1703);\nparallelSetNumThreads(1);\ny1 = pmin(x, 1703);\nif (!identical(y1, yN)) stop('parallel max(integer x, integer$ y) failed test');\n\n// ***********************************************************************************************\n\n// (integer)pmin(integer x, integer y)\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMIN_INT_2\n\na = rdunif(1000000, -100000000, 100000000);\nb = rdunif(1000000, -100000000, 100000000);\nyN = pmin(a, b);\nparallelSetNumThreads(1);\ny1 = pmin(a, b);\nif (!identical(y1, yN)) stop('parallel max(integer x, integer y) failed test');\n\n// ***********************************************************************************************\n\n// (float)pmin(float x, float$ y)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMIN_FLOAT_1\n\nx = runif(1000000, -100000000, 100000000);\nyN = pmin(x, 1703.0);\nparallelSetNumThreads(1);\ny1 = pmin(x, 1703.0);\nif (!identical(y1, yN)) stop('parallel max(float x, float$ y) failed test');\n\n// ***********************************************************************************************\n\n// (float)pmin(float x, float y)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_PMIN_FLOAT_2\n\na = runif(1000000, -100000000, 100000000);\nb = runif(1000000, -100000000, 100000000);\nyN = pmin(a, b);\nparallelSetNumThreads(1);\ny1 = pmin(a, b);\nif (!identical(y1, yN)) stop('parallel max(float x, float y) failed test');\n\n// ***********************************************************************************************\n\n// (float)round(float x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_ROUND\n\nx = runif(1000000, -100, 100);\nyN = round(x);\nparallelSetNumThreads(1);\ny1 = round(x);\nif (!identical(y1, yN)) stop('parallel round(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)sqrt(float x)\t\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_SQRT\n\nx = runif(1000000, -100, 100);\nyN = sqrt(x);\nparallelSetNumThreads(1);\ny1 = sqrt(x);\nif (!identical(y1, yN)) stop('parallel sqrt(float x) failed test');\n\n// ***********************************************************************************************\n\n// (float)trunc(float x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_TRUNC\n\nx = runif(1000000, -100, 100);\nyN = trunc(x);\nparallelSetNumThreads(1);\ny1 = trunc(x);\nif (!identical(y1, yN)) stop('parallel trunc(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer$)sum(logical x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_SUM_LOGICAL\n\nx = asLogical(rdunif(1000000, 0, 1));\nyN = sum(x);\nparallelSetNumThreads(1);\ny1 = sum(x);\nif (!identical(y1, yN)) stop('parallel sum(logical x) failed test');\n\n// ***********************************************************************************************\n\n// (integer$)sum(integer x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_SUM_INTEGER\n\nx = rdunif(1000000, -100, 100);\nyN = sum(x);\nparallelSetNumThreads(1);\ny1 = sum(x);\nif (!identical(y1, yN)) stop('parallel sum(integer x) failed test');\n\n// ***********************************************************************************************\n\n// (integer$)sum(float x)\t\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_SUM_FLOAT\n\nx = runif(1000000, -100, 100);\nyN = sum(x);\nparallelSetNumThreads(1);\ny1 = sum(x);\nif (abs(y1 - yN) > 1e-10) stop('parallel sum(float x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sort(logical x)\n\nx = asLogical(rdunif(1000000, 0, 1));\nyN = sort(x);\nzN = sort(x, ascending=F);\nparallelSetNumThreads(1);\ny1 = sort(x);\nz1 = sort(x, ascending=F);\nif (!identical(y1, yN) | !identical(z1, zN)) stop('parallel sort(logical x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sort(integer x)\n\nx = rdunif(1000000, -100, 100);\nyN = sort(x);\nzN = sort(x, ascending=F);\nparallelSetNumThreads(1);\ny1 = sort(x);\nz1 = sort(x, ascending=F);\nif (!identical(y1, yN) | !identical(z1, zN)) stop('parallel sort(integer x) failed test');\n\n// ***********************************************************************************************\n\n// (integer)sort(float x)\n\nx = runif(1000000, -100, 100);\nyN = sort(x);\nzN = sort(x, ascending=F);\nparallelSetNumThreads(1);\ny1 = sort(x);\nz1 = sort(x, ascending=F);\nif (!identical(y1, yN) | !identical(z1, zN)) stop('parallel sort(float x) failed test');\n\n// ***********************************************************************************************\n\n// (string)sort(string x)\n\nx = asString(runif(1000000, -100, 100));\nyN = sort(x);\nzN = sort(x, ascending=F);\nparallelSetNumThreads(1);\ny1 = sort(x);\nz1 = sort(x, ascending=F);\nif (!identical(y1, yN) | !identical(z1, zN)) stop('parallel sort(string x) failed test');\n\n// ***********************************************************************************************\n\n//\t(float)dnorm(float x, numeric$ mean, numeric$ sd)\t\t\t// EIDOS_OMPMIN_DNORM_1\n\nx = runif(1000000, -100, 100);\naN = dnorm(x, 12.5, 10.3);\nparallelSetNumThreads(1);\na1 = dnorm(x, 12.5, 10.3);\nif (!identical(a1, aN)) stop('parallel dnorm() failed test');\n\n// ***********************************************************************************************\n\n//\t(float)dnorm(float x, numeric mean, numeric sd)\t\t\t\t// EIDOS_OMPMIN_DNORM_2\n\nx = runif(1000000, -100, 100);\nmu = runif(1000000, -100, 100);\nsigma = runif(1000000, 1.0, 100.0);\nbN = dnorm(x, mu, sigma);\nparallelSetNumThreads(1);\nb1 = dnorm(x, mu, sigma);\nif (!identical(b1, bN)) stop('parallel dnorm() failed test');\n\n// ***********************************************************************************************\n\n/*\n\nThe above tests can look for identical results, because the functions they are testing\nare deterministic (modulo floating point roundoff effects and such).  Below are tests\nof functions whose results are stochastic; we test them for correctness using their mean\nand variance, and these tests can occasionally fail.  They are calibrated to fail less\nthan 1 in 1000 runs, with the following (example) R code:\n\nmean_diffs <- rep(0, 1000);\nsd_diffs <- rep(0, 1000);\n\nfor (i in 1:1000)\n{\n\tx1 = rnorm(1000000, 12.5, 0.1);\n\tx2 = rnorm(1000000, 12.5, 0.1);\n\tmean_diffs[i] <- abs(mean(x1)-mean(x2));\n\tsd_diffs[i] <- abs(sd(x1)-sd(x2));\n}\n\nmax(mean_diffs)\nmax(sd_diffs)\n\n*/\n\n// ***********************************************************************************************\n\n//\t(integer)rbinom(integer$ n, integer$ size = 1, float$ prob = 0.5)\t// EIDOS_OMPMIN_RBINOM_1\n\naN = rbinom(1000000, 1, 0.5);\nparallelSetNumThreads(1);\na1 = rbinom(1000000, 1, 0.5);\nif (abs(mean(aN)-mean(a1)) > 0.003) stop('parallel rbinom() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.000003) stop('parallel rbinom() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rbinom(integer$ n, integer$ size, float$ prob)\t\t\t\t// EIDOS_OMPMIN_RBINOM_2\n\naN = rbinom(1000000, 3, 0.1);\nparallelSetNumThreads(1);\na1 = rbinom(1000000, 3, 0.1);\nif (abs(mean(aN)-mean(a1)) > 0.003) stop('parallel rbinom() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.003) stop('parallel rbinom() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rbinom(integer$ n, integer size, float prob)\t\t\t\t// EIDOS_OMPMIN_RBINOM_3\n\nsize = rep(3, 1000000);\nprob = rep(0.1, 1000000);\naN = rbinom(1000000, size, prob);\nparallelSetNumThreads(1);\na1 = rbinom(1000000, size, prob);\nif (abs(mean(aN)-mean(a1)) > 0.003) stop('parallel rbinom() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.003) stop('parallel rbinom() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rdunif(integer$ n, integer$ min = 0, integer$ max = 1)\t\t// EIDOS_OMPMIN_RDUNIF_1\n\naN = rdunif(1000000, 3, 4);\nparallelSetNumThreads(1);\na1 = rdunif(1000000, 3, 4);\nif (abs(mean(aN)-mean(a1)) > 0.003) stop('parallel rdunif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.000003) stop('parallel rdunif() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rdunif(integer$ n, integer$ min, integer$ max)\t\t\t\t// EIDOS_OMPMIN_RDUNIF_2\n\naN = rdunif(1000000, 3, 17);\nparallelSetNumThreads(1);\na1 = rdunif(1000000, 3, 17);\nif (abs(mean(aN)-mean(a1)) > 0.025) stop('parallel rdunif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.011) stop('parallel rdunif() failed sd test');\n\n\n// ***********************************************************************************************\n\n//\t(integer)rdunif(integer$ n, integer min, integer max)\t\t\t\t// EIDOS_OMPMIN_RDUNIF_3\n\nmin = rep(3, 1000000);\nmax = rep(17, 1000000);\naN = rdunif(1000000, min, max);\nparallelSetNumThreads(1);\na1 = rdunif(1000000, min, max);\nif (abs(mean(aN)-mean(a1)) > 0.025) stop('parallel rdunif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.011) stop('parallel rdunif() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)rexp(integer$ n, numeric$ mu)\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_REXP_1\naN = rexp(1000000, 0.2);\nparallelSetNumThreads(1);\na1 = rexp(1000000, 0.2);\nif (abs(mean(aN)-mean(a1)) > 0.0015) stop('parallel rexp() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0015) stop('parallel rexp() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)rexp(integer$ n, numeric mu)\t\t\t\t\t\t\t\t\t// EIDOS_OMPMIN_REXP_2\n\nmu = rep(0.2, 1000000);\naN = rexp(1000000, 0.2);\nparallelSetNumThreads(1);\na1 = rexp(1000000, 0.2);\nif (abs(mean(aN)-mean(a1)) > 0.0015) stop('parallel rexp() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0015) stop('parallel rexp() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)rnorm(integer$ n, numeric$ mean, numeric$ sd)\t\t\t\t// EIDOS_OMPMIN_RNORM_1\n\naN = rnorm(1000000, 12.5, 0.1);\nparallelSetNumThreads(1);\na1 = rnorm(1000000, 12.5, 0.1);\nif (abs(mean(aN)-mean(a1)) > 0.0005) stop('parallel rnorm() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0005) stop('parallel rnorm() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)rnorm(integer$ n, numeric mean, numeric$ sd)\t\t\t\t\t// EIDOS_OMPMIN_RNORM_2\n\nmu = rep(12.5, 1000000);\naN = rnorm(1000000, mu, 0.1);\nparallelSetNumThreads(1);\na1 = rnorm(1000000, mu, 0.1);\nif (abs(mean(aN)-mean(a1)) > 0.0005) stop('parallel rnorm() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0005) stop('parallel rnorm() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)rnorm(integer$ n, numeric mean, numeric sd)\t\t\t\t\t// EIDOS_OMPMIN_RNORM_3\n\nmu = rep(12.5, 1000000);\nsigma = rep(0.1, 1000000);\naN = rnorm(1000000, mu, sigma);\nparallelSetNumThreads(1);\na1 = rnorm(1000000, mu, sigma);\nif (abs(mean(aN)-mean(a1)) > 0.0005) stop('parallel rnorm() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0005) stop('parallel rnorm() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rpois(integer$ n, numeric$ lambda)\t\t\t\t\t\t\t// EIDOS_OMPMIN_RPOIS_1\n\naN = rpois(1000000, 15);\nparallelSetNumThreads(1);\na1 = rpois(1000000, 15);\nif (abs(mean(aN)-mean(a1)) > 0.02) stop('parallel rpois() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.02) stop('parallel rpois() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(integer)rpois(integer$ n, numeric lambda)\t\t\t\t\t\t\t// EIDOS_OMPMIN_RPOIS_2\n\nlambda = rep(15, 1000000);\naN = rpois(1000000, lambda);\nparallelSetNumThreads(1);\na1 = rpois(1000000, lambda);\nif (abs(mean(aN)-mean(a1)) > 0.02) stop('parallel rpois() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.02) stop('parallel rpois() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)runif(integer$ n, numeric$ min = 0], numeric$ max = 1)\t\t// EIDOS_OMPMIN_RUNIF_1\n\naN = runif(1000000, 0, 1);\nparallelSetNumThreads(1);\na1 = runif(1000000, 0, 1);\nif (abs(mean(aN)-mean(a1)) > 0.0015) stop('parallel runif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.0006) stop('parallel runif() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)runif(integer$ n, numeric$ min, numeric$ max)\t\t\t\t// EIDOS_OMPMIN_RUNIF_2\n\naN = runif(1000000, 3, 17);\nparallelSetNumThreads(1);\na1 = runif(1000000, 3, 17);\nif (abs(mean(aN)-mean(a1)) > 0.02) stop('parallel runif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.01) stop('parallel runif() failed sd test');\n\n// ***********************************************************************************************\n\n//\t(float)runif(integer$ n, numeric min, numeric max)\t\t\t\t\t// EIDOS_OMPMIN_RUNIF_3\n\nmin = rep(3.0, 1000000);\nmax = rep(17.0, 1000000);\naN = runif(1000000, 3, 17);\nparallelSetNumThreads(1);\na1 = runif(1000000, 3, 17);\nif (abs(mean(aN)-mean(a1)) > 0.02) stop('parallel runif() failed mean test');\nif (abs(sd(aN)-sd(a1)) > 0.01) stop('parallel runif() failed sd test');\n\n)V0G0N\"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_tinycolormap.h",
    "content": "//\n//  eidos_tinycolormap.h\n//  SLiM\n//\n//  Created by Ben Haller on 8/23/20.\n//  Copyright (c) 2020-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n\n This is a modified version of a class written by Yuki Koyama, available at\n https://github.com/yuki-koyama/tinycolormap .  His code is published under\n the MIT license, which is compatible with the GPL 3.0.  His edition of the\n MIT license is posted here:\n \n MIT License\n\n Copyright (c) 2018 Yuki Koyama\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n\n -------------------------------------------\n \n I have modified this code by merging in a pull request written by Shot511\n (Tomasz Gałaj), available at https://github.com/yuki-koyama/tinycolormap/pull/27 .\n This PR, available at https://github.com/yuki-koyama/tinycolormap/pull/27 ,\n adds the Turbo colormap.  The original code from which this PR is derived is\n released by Anton Mikhailov under the Apache 2.0 license, and is available at \n https://gist.github.com/mikhailov-work/6a308c20e494d9e0ccc29036b28faa7a .\n That license is compatible with the GPL 3.0 that we are licensed under, \n according to https://www.apache.org/licenses/GPL-compatibility.html .  The\n license notice for Anton's code is posted here:\n \n Copyright 2019 Google LLC.\n \n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n\t http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n -------------------------------------------\n \n Apart from that merge, and changes needed to integrate the code into Eidos,\n this code is unmodified from the original sources.\n \n*/\n\n\n#ifndef eidos_tinycolormap_h\n#define eidos_tinycolormap_h\n\n\n#include <cmath>\n#include <array>\n\n#if defined(TINYCOLORMAP_WITH_EIGEN)\n#include <Eigen/Core>\n#endif\n\n#if defined(TINYCOLORMAP_WITH_QT5)\n#include <QColor>\n#endif\n\n#if defined(TINYCOLORMAP_WITH_QT5) and defined(TINYCOLORMAP_WITH_EIGEN)\n#include <QImage>\n#include <QString>\n#endif\n\n#if defined(TINYCOLORMAP_WITH_GLM)\n#include <glm/vec3.hpp>\n#endif\n\nnamespace tinycolormap\n{\n    //////////////////////////////////////////////////////////////////////////////////\n    // Interface\n    //////////////////////////////////////////////////////////////////////////////////\n\n    enum class ColormapType\n    {\n        Parula, Heat, Jet, Turbo, Hot, Gray, Magma, Inferno, Plasma, Viridis, Cividis, Github\n    };\n\n    struct Color\n    {\n        constexpr Color(double p_r, double p_g, double p_b) : data({{ p_r, p_g, p_b }}) {}\n\n        std::array<double, 3> data;\n\n        double& r() { return data[0]; }\n        double& g() { return data[1]; }\n        double& b() { return data[2]; }\n        const double& r() const { return data[0]; }\n        const double& g() const { return data[1]; }\n        const double& b() const { return data[2]; }\n\n        uint8_t ri() const { return static_cast<uint8_t>(data[0] * 255.0); }\n        uint8_t gi() const { return static_cast<uint8_t>(data[1] * 255.0); }\n        uint8_t bi() const { return static_cast<uint8_t>(data[2] * 255.0); }\n\n        double& operator[](size_t n) { return data[n]; }\n        const double& operator[](size_t n) const { return data[n]; }\n        double& operator()(size_t n) { return data[n]; }\n        const double& operator()(size_t n) const { return data[n]; }\n\n#if defined(TINYCOLORMAP_WITH_QT5)\n        QColor ConvertToQColor() const { return QColor(data[0] * 255.0, data[1] * 255.0, data[2] * 255.0); }\n#endif\n#if defined(TINYCOLORMAP_WITH_EIGEN)\n        Eigen::Vector3d ConvertToEigen() const { return Eigen::Vector3d(data[0], data[1], data[2]); }\n#endif\n#if defined(TINYCOLORMAP_WITH_GLM)\n        glm::vec3 ConvertToGLM() const { return glm::vec3(data[0], data[1], data[2]); }\n#endif\n    };\n\n    inline Color GetColor(double x, ColormapType type = ColormapType::Viridis);\n    inline Color GetParulaColor(double x);\n    inline Color GetHeatColor(double x);\n    inline Color GetJetColor(double x);\n    inline Color GetTurboColor(double x);\n    inline Color GetHotColor(double x);\n    inline Color GetGrayColor(double x);\n    inline Color GetMagmaColor(double x);\n    inline Color GetInfernoColor(double x);\n    inline Color GetPlasmaColor(double x);\n    inline Color GetViridisColor(double x);\n    inline Color GetCividisColor(double x);\n    inline Color GetGithubColor(double x);\n\n#if defined(TINYCOLORMAP_WITH_QT5) and defined(TINYCOLORMAP_WITH_EIGEN)\n    inline QImage CreateMatrixVisualization(const Eigen::MatrixXd& matrix);\n    inline void ExportMatrixVisualization(const Eigen::MatrixXd& matrix, const std::string& path);\n#endif\n\n    //////////////////////////////////////////////////////////////////////////////////\n    // Implementation\n    //////////////////////////////////////////////////////////////////////////////////\n\n    inline Color operator+(const Color& c0, const Color& c1)\n    {\n        return { c0[0] + c1[0], c0[1] + c1[1], c0[2] + c1[2] };\n    }\n\n    inline Color operator*(double s, const Color& c)\n    {\n        return { s * c[0], s * c[1], s * c[2] };\n    }\n\n    inline Color GetColor(double x, ColormapType type)\n    {\n        switch (type)\n        {\n            case ColormapType::Parula:\n                return GetParulaColor(x);\n            case ColormapType::Heat:\n                return GetHeatColor(x);\n            case ColormapType::Jet:\n                return GetJetColor(x);\n            case ColormapType::Turbo:\n                return GetTurboColor(x);\n            case ColormapType::Hot:\n                return GetHotColor(x);\n            case ColormapType::Gray:\n                return GetGrayColor(x);\n            case ColormapType::Magma:\n                return GetMagmaColor(x);\n            case ColormapType::Inferno:\n                return GetInfernoColor(x);\n            case ColormapType::Plasma:\n                return GetPlasmaColor(x);\n            case ColormapType::Viridis:\n                return GetViridisColor(x);\n            case ColormapType::Cividis:\n                return GetCividisColor(x);\n            case ColormapType::Github:\n                return GetGithubColor(x);\n            default:\n                break;\n        }\n        \n        return GetViridisColor(x);\n    }\n\n    inline Color GetParulaColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.2081, 0.1663, 0.5292 },\n            { 0.2091, 0.1721, 0.5411 },\n            { 0.2101, 0.1779, 0.553   },\n            { 0.2109, 0.1837, 0.565   },\n            { 0.2116, 0.1895, 0.5771 },\n            { 0.2121, 0.1954, 0.5892 },\n            { 0.2124, 0.2013, 0.6013 },\n            { 0.2125, 0.2072, 0.6135 },\n            { 0.2123, 0.2132, 0.6258 },\n            { 0.2118, 0.2192, 0.6381 },\n            { 0.2111, 0.2253, 0.6505 },\n            { 0.2099, 0.2315, 0.6629 },\n            { 0.2084, 0.2377, 0.6753 },\n            { 0.2063, 0.244, 0.6878   },\n            { 0.2038, 0.2503, 0.7003 },\n            { 0.2006, 0.2568, 0.7129 },\n            { 0.1968, 0.2632, 0.7255 },\n            { 0.1921, 0.2698, 0.7381 },\n            { 0.1867, 0.2764, 0.7507 },\n            { 0.1802, 0.2832, 0.7634 },\n            { 0.1728, 0.2902, 0.7762 },\n            { 0.1641, 0.2975, 0.789   },\n            { 0.1541, 0.3052, 0.8017 },\n            { 0.1427, 0.3132, 0.8145 },\n            { 0.1295, 0.3217, 0.8269 },\n            { 0.1147, 0.3306, 0.8387 },\n            { 0.0986, 0.3397, 0.8495 },\n            { 0.0816, 0.3486, 0.8588 },\n            { 0.0646, 0.3572, 0.8664 },\n            { 0.0482, 0.3651, 0.8722 },\n            { 0.0329, 0.3724, 0.8765 },\n            { 0.0213, 0.3792, 0.8796 },\n            { 0.0136, 0.3853, 0.8815 },\n            { 0.0086, 0.3911, 0.8827 },\n            { 0.006,  0.3965, 0.8833 },\n            { 0.0051, 0.4017, 0.8834 },\n            { 0.0054, 0.4066, 0.8831 },\n            { 0.0067, 0.4113, 0.8825 },\n            { 0.0089, 0.4159, 0.8816 },\n            { 0.0116, 0.4203, 0.8805 },\n            { 0.0148, 0.4246, 0.8793 },\n            { 0.0184, 0.4288, 0.8779 },\n            { 0.0223, 0.4329, 0.8763 },\n            { 0.0264, 0.437, 0.8747   },\n            { 0.0306, 0.441, 0.8729   },\n            { 0.0349, 0.4449, 0.8711 },\n            { 0.0394, 0.4488, 0.8692 },\n            { 0.0437, 0.4526, 0.8672 },\n            { 0.0477, 0.4564, 0.8652 },\n            { 0.0514, 0.4602, 0.8632 },\n            { 0.0549, 0.464, 0.8611   },\n            { 0.0582, 0.4677, 0.8589 },\n            { 0.0612, 0.4714, 0.8568 },\n            { 0.064,  0.4751, 0.8546 },\n            { 0.0666, 0.4788, 0.8525 },\n            { 0.0689, 0.4825, 0.8503 },\n            { 0.071,  0.4862, 0.8481 },\n            { 0.0729, 0.4899, 0.846   },\n            { 0.0746, 0.4937, 0.8439 },\n            { 0.0761, 0.4974, 0.8418 },\n            { 0.0773, 0.5012, 0.8398 },\n            { 0.0782, 0.5051, 0.8378 },\n            { 0.0789, 0.5089, 0.8359 },\n            { 0.0794, 0.5129, 0.8341 },\n            { 0.0795, 0.5169, 0.8324 },\n            { 0.0793, 0.521, 0.8308   },\n            { 0.0788, 0.5251, 0.8293 },\n            { 0.0778, 0.5295, 0.828   },\n            { 0.0764, 0.5339, 0.827   },\n            { 0.0746, 0.5384, 0.8261 },\n            { 0.0724, 0.5431, 0.8253 },\n            { 0.0698, 0.5479, 0.8247 },\n            { 0.0668, 0.5527, 0.8243 },\n            { 0.0636, 0.5577, 0.8239 },\n            { 0.06,   0.5627, 0.8237 },\n            { 0.0562, 0.5677, 0.8234 },\n            { 0.0523, 0.5727, 0.8231 },\n            { 0.0484, 0.5777, 0.8228 },\n            { 0.0445, 0.5826, 0.8223 },\n            { 0.0408, 0.5874, 0.8217 },\n            { 0.0372, 0.5922, 0.8209 },\n            { 0.0342, 0.5968, 0.8198 },\n            { 0.0317, 0.6012, 0.8186 },\n            { 0.0296, 0.6055, 0.8171 },\n            { 0.0279, 0.6097, 0.8154 },\n            { 0.0265, 0.6137, 0.8135 },\n            { 0.0255, 0.6176, 0.8114 },\n            { 0.0248, 0.6214, 0.8091 },\n            { 0.0243, 0.625, 0.8066   },\n            { 0.0239, 0.6285, 0.8039 },\n            { 0.0237, 0.6319, 0.801   },\n            { 0.0235, 0.6352, 0.798   },\n            { 0.0233, 0.6384, 0.7948 },\n            { 0.0231, 0.6415, 0.7916 },\n            { 0.023,  0.6445, 0.7881 },\n            { 0.0229, 0.6474, 0.7846 },\n            { 0.0227, 0.6503, 0.781, },\n            { 0.0227, 0.6531, 0.7773 },\n            { 0.0232, 0.6558, 0.7735 },\n            { 0.0238, 0.6585, 0.7696 },\n            { 0.0246, 0.6611, 0.7656 },\n            { 0.0263, 0.6637, 0.7615 },\n            { 0.0282, 0.6663, 0.7574 },\n            { 0.0306, 0.6688, 0.7532 },\n            { 0.0338, 0.6712, 0.749   },\n            { 0.0373, 0.6737, 0.7446 },\n            { 0.0418, 0.6761, 0.7402 },\n            { 0.0467, 0.6784, 0.7358 },\n            { 0.0516, 0.6808, 0.7313 },\n            { 0.0574, 0.6831, 0.7267 },\n            { 0.0629, 0.6854, 0.7221 },\n            { 0.0692, 0.6877, 0.7173 },\n            { 0.0755, 0.6899, 0.7126 },\n            { 0.082,  0.6921, 0.7078 },\n            { 0.0889, 0.6943, 0.7029 },\n            { 0.0956, 0.6965, 0.6979 },\n            { 0.1031, 0.6986, 0.6929 },\n            { 0.1104, 0.7007, 0.6878 },\n            { 0.118,  0.7028, 0.6827 },\n            { 0.1258, 0.7049, 0.6775 },\n            { 0.1335, 0.7069, 0.6723 },\n            { 0.1418, 0.7089, 0.6669 },\n            { 0.1499, 0.7109, 0.6616 },\n            { 0.1585, 0.7129, 0.6561 },\n            { 0.1671, 0.7148, 0.6507 },\n            { 0.1758, 0.7168, 0.6451 },\n            { 0.1849, 0.7186, 0.6395 },\n            { 0.1938, 0.7205, 0.6338 },\n            { 0.2033, 0.7223, 0.6281 },\n            { 0.2128, 0.7241, 0.6223 },\n            { 0.2224, 0.7259, 0.6165 },\n            { 0.2324, 0.7275, 0.6107 },\n            { 0.2423, 0.7292, 0.6048 },\n            { 0.2527, 0.7308, 0.5988 },\n            { 0.2631, 0.7324, 0.5929 },\n            { 0.2735, 0.7339, 0.5869 },\n            { 0.2845, 0.7354, 0.5809 },\n            { 0.2953, 0.7368, 0.5749 },\n            { 0.3064, 0.7381, 0.5689 },\n            { 0.3177, 0.7394, 0.563   },\n            { 0.3289, 0.7406, 0.557   },\n            { 0.3405, 0.7417, 0.5512 },\n            { 0.352,  0.7428, 0.5453 },\n            { 0.3635, 0.7438, 0.5396 },\n            { 0.3753, 0.7446, 0.5339 },\n            { 0.3869, 0.7454, 0.5283 },\n            { 0.3986, 0.7461, 0.5229 },\n            { 0.4103, 0.7467, 0.5175 },\n            { 0.4218, 0.7473, 0.5123 },\n            { 0.4334, 0.7477, 0.5072 },\n            { 0.4447, 0.7482, 0.5021 },\n            { 0.4561, 0.7485, 0.4972 },\n            { 0.4672, 0.7487, 0.4924 },\n            { 0.4783, 0.7489, 0.4877 },\n            { 0.4892, 0.7491, 0.4831 },\n            { 0.5,    0.7491, 0.4786 },\n            { 0.5106, 0.7492, 0.4741 },\n            { 0.5212, 0.7492, 0.4698 },\n            { 0.5315, 0.7491, 0.4655 },\n            { 0.5418, 0.749, 0.4613   },\n            { 0.5519, 0.7489, 0.4571 },\n            { 0.5619, 0.7487, 0.4531 },\n            { 0.5718, 0.7485, 0.449   },\n            { 0.5816, 0.7482, 0.4451 },\n            { 0.5913, 0.7479, 0.4412 },\n            { 0.6009, 0.7476, 0.4374 },\n            { 0.6103, 0.7473, 0.4335 },\n            { 0.6197, 0.7469, 0.4298 },\n            { 0.629,  0.7465, 0.4261 },\n            { 0.6382, 0.746, 0.4224   },\n            { 0.6473, 0.7456, 0.4188 },\n            { 0.6564, 0.7451, 0.4152 },\n            { 0.6653, 0.7446, 0.4116 },\n            { 0.6742, 0.7441, 0.4081 },\n            { 0.683,  0.7435, 0.4046 },\n            { 0.6918, 0.743, 0.4011   },\n            { 0.7004, 0.7424, 0.3976 },\n            { 0.7091, 0.7418, 0.3942 },\n            { 0.7176, 0.7412, 0.3908 },\n            { 0.7261, 0.7405, 0.3874 },\n            { 0.7346, 0.7399, 0.384   },\n            { 0.743,  0.7392, 0.3806 },\n            { 0.7513, 0.7385, 0.3773 },\n            { 0.7596, 0.7378, 0.3739 },\n            { 0.7679, 0.7372, 0.3706 },\n            { 0.7761, 0.7364, 0.3673 },\n            { 0.7843, 0.7357, 0.3639 },\n            { 0.7924, 0.735, 0.3606   },\n            { 0.8005, 0.7343, 0.3573 },\n            { 0.8085, 0.7336, 0.3539 },\n            { 0.8166, 0.7329, 0.3506 },\n            { 0.8246, 0.7322, 0.3472 },\n            { 0.8325, 0.7315, 0.3438 },\n            { 0.8405, 0.7308, 0.3404 },\n            { 0.8484, 0.7301, 0.337   },\n            { 0.8563, 0.7294, 0.3336 },\n            { 0.8642, 0.7288, 0.33    },\n            { 0.872,  0.7282, 0.3265 },\n            { 0.8798, 0.7276, 0.3229 },\n            { 0.8877, 0.7271, 0.3193 },\n            { 0.8954, 0.7266, 0.3156 },\n            { 0.9032, 0.7262, 0.3117 },\n            { 0.911,  0.7259, 0.3078 },\n            { 0.9187, 0.7256, 0.3038 },\n            { 0.9264, 0.7256, 0.2996 },\n            { 0.9341, 0.7256, 0.2953 },\n            { 0.9417, 0.7259, 0.2907 },\n            { 0.9493, 0.7264, 0.2859 },\n            { 0.9567, 0.7273, 0.2808 },\n            { 0.9639, 0.7285, 0.2754 },\n            { 0.9708, 0.7303, 0.2696 },\n            { 0.9773, 0.7326, 0.2634 },\n            { 0.9831, 0.7355, 0.257   },\n            { 0.9882, 0.739, 0.2504   },\n            { 0.9922, 0.7431, 0.2437 },\n            { 0.9952, 0.7476, 0.2373 },\n            { 0.9973, 0.7524, 0.231   },\n            { 0.9986, 0.7573, 0.2251 },\n            { 0.9991, 0.7624, 0.2195 },\n            { 0.999,  0.7675, 0.2141 },\n            { 0.9985, 0.7726, 0.209   },\n            { 0.9976, 0.7778, 0.2042 },\n            { 0.9964, 0.7829, 0.1995 },\n            { 0.995,  0.788, 0.1949   },\n            { 0.9933, 0.7931, 0.1905 },\n            { 0.9914, 0.7981, 0.1863 },\n            { 0.9894, 0.8032, 0.1821 },\n            { 0.9873, 0.8083, 0.178   },\n            { 0.9851, 0.8133, 0.174   },\n            { 0.9828, 0.8184, 0.17    },\n            { 0.9805, 0.8235, 0.1661 },\n            { 0.9782, 0.8286, 0.1622 },\n            { 0.9759, 0.8337, 0.1583 },\n            { 0.9736, 0.8389, 0.1544 },\n            { 0.9713, 0.8441, 0.1505 },\n            { 0.9692, 0.8494, 0.1465 },\n            { 0.9672, 0.8548, 0.1425 },\n            { 0.9654, 0.8603, 0.1385 },\n            { 0.9638, 0.8659, 0.1343 },\n            { 0.9623, 0.8716, 0.1301 },\n            { 0.9611, 0.8774, 0.1258 },\n            { 0.96,   0.8834, 0.1215 },\n            { 0.9593, 0.8895, 0.1171 },\n            { 0.9588, 0.8958, 0.1126 },\n            { 0.9586, 0.9022, 0.1082 },\n            { 0.9587, 0.9088, 0.1036 },\n            { 0.9591, 0.9155, 0.099   },\n            { 0.9599, 0.9225, 0.0944 },\n            { 0.961,  0.9296, 0.0897 },\n            { 0.9624, 0.9368, 0.085   },\n            { 0.9641, 0.9443, 0.0802 },\n            { 0.9662, 0.9518, 0.0753 },\n            { 0.9685, 0.9595, 0.0703 },\n            { 0.971,  0.9673, 0.0651 },\n            { 0.9736, 0.9752, 0.0597 },\n            { 0.9763, 0.9831, 0.0538 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetHeatColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.0, 0.0, 1.0 },\n            { 0.0, 1.0, 1.0 },\n            { 0.0, 1.0, 0.0 },\n            { 1.0, 1.0, 0.0 },\n            { 1.0, 0.0, 0.0 }\n        };\n\n        const double a  = x * ((sizeof(data) / sizeof(Color)) - 1);\n        const double t  = a - std::floor(a);\n        const Color  c0 = data[static_cast<size_t>(std::floor(a))];\n        const Color  c1 = data[static_cast<size_t>(std::ceil (a))];\n\n        return (1.0 - t) * c0 + t * c1;\n    }\n\n    inline Color GetJetColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.0, 0.0, 0.5 },\n            { 0.0, 0.0, 1.0 },\n            { 0.0, 0.5, 1.0 },\n            { 0.0, 1.0, 1.0 },\n            { 0.5, 1.0, 0.5 },\n            { 1.0, 1.0, 0.0 },\n            { 1.0, 0.5, 0.0 },\n            { 1.0, 0.0, 0.0 },\n            { 0.5, 0.0, 0.0 }\n        };\n\n        const double a  = x * ((sizeof(data) / sizeof(Color)) - 1);\n        const double t  = a - std::floor(a);\n        const Color  c0 = data[static_cast<size_t>(std::floor(a))];\n        const Color  c1 = data[static_cast<size_t>(std::ceil (a))];\n\n        return (1.0 - t) * c0 + t * c1;\n    }\n\n\tinline Color GetTurboColor(double x)\n\t{\n\t\tx = std::max(0.0, std::min(1.0, x));\n\n\t\tconstexpr Color data[] =\n\t\t{\n\t\t\t{ 0.18995, 0.07176, 0.23217 },\n\t\t\t{ 0.19483, 0.08339, 0.26149 },\n\t\t\t{ 0.19956, 0.09498, 0.29024 },\n\t\t\t{ 0.20415, 0.10652, 0.31844 },\n\t\t\t{ 0.20860, 0.11802, 0.34607 },\n\t\t\t{ 0.21291, 0.12947, 0.37314 },\n\t\t\t{ 0.21708, 0.14087, 0.39964 },\n\t\t\t{ 0.22111, 0.15223, 0.42558 },\n\t\t\t{ 0.22500, 0.16354, 0.45096 },\n\t\t\t{ 0.22875, 0.17481, 0.47578 },\n\t\t\t{ 0.23236, 0.18603, 0.50004 },\n\t\t\t{ 0.23582, 0.19720, 0.52373 },\n\t\t\t{ 0.23915, 0.20833, 0.54686 },\n\t\t\t{ 0.24234, 0.21941, 0.56942 },\n\t\t\t{ 0.24539, 0.23044, 0.59142 },\n\t\t\t{ 0.24830, 0.24143, 0.61286 },\n\t\t\t{ 0.25107, 0.25237, 0.63374 },\n\t\t\t{ 0.25369, 0.26327, 0.65406 },\n\t\t\t{ 0.25618, 0.27412, 0.67381 },\n\t\t\t{ 0.25853, 0.28492, 0.69300 },\n\t\t\t{ 0.26074, 0.29568, 0.71162 },\n\t\t\t{ 0.26280, 0.30639, 0.72968 },\n\t\t\t{ 0.26473, 0.31706, 0.74718 },\n\t\t\t{ 0.26652, 0.32768, 0.76412 },\n\t\t\t{ 0.26816, 0.33825, 0.78050 },\n\t\t\t{ 0.26967, 0.34878, 0.79631 },\n\t\t\t{ 0.27103, 0.35926, 0.81156 },\n\t\t\t{ 0.27226, 0.36970, 0.82624 },\n\t\t\t{ 0.27334, 0.38008, 0.84037 },\n\t\t\t{ 0.27429, 0.39043, 0.85393 },\n\t\t\t{ 0.27509, 0.40072, 0.86692 },\n\t\t\t{ 0.27576, 0.41097, 0.87936 },\n\t\t\t{ 0.27628, 0.42118, 0.89123 },\n\t\t\t{ 0.27667, 0.43134, 0.90254 },\n\t\t\t{ 0.27691, 0.44145, 0.91328 },\n\t\t\t{ 0.27701, 0.45152, 0.92347 },\n\t\t\t{ 0.27698, 0.46153, 0.93309 },\n\t\t\t{ 0.27680, 0.47151, 0.94214 },\n\t\t\t{ 0.27648, 0.48144, 0.95064 },\n\t\t\t{ 0.27603, 0.49132, 0.95857 },\n\t\t\t{ 0.27543, 0.50115, 0.96594 },\n\t\t\t{ 0.27469, 0.51094, 0.97275 },\n\t\t\t{ 0.27381, 0.52069, 0.97899 },\n\t\t\t{ 0.27273, 0.53040, 0.98461 },\n\t\t\t{ 0.27106, 0.54015, 0.98930 },\n\t\t\t{ 0.26878, 0.54995, 0.99303 },\n\t\t\t{ 0.26592, 0.55979, 0.99583 },\n\t\t\t{ 0.26252, 0.56967, 0.99773 },\n\t\t\t{ 0.25862, 0.57958, 0.99876 },\n\t\t\t{ 0.25425, 0.58950, 0.99896 },\n\t\t\t{ 0.24946, 0.59943, 0.99835 },\n\t\t\t{ 0.24427, 0.60937, 0.99697 },\n\t\t\t{ 0.23874, 0.61931, 0.99485 },\n\t\t\t{ 0.23288, 0.62923, 0.99202 },\n\t\t\t{ 0.22676, 0.63913, 0.98851 },\n\t\t\t{ 0.22039, 0.64901, 0.98436 },\n\t\t\t{ 0.21382, 0.65886, 0.97959 },\n\t\t\t{ 0.20708, 0.66866, 0.97423 },\n\t\t\t{ 0.20021, 0.67842, 0.96833 },\n\t\t\t{ 0.19326, 0.68812, 0.96190 },\n\t\t\t{ 0.18625, 0.69775, 0.95498 },\n\t\t\t{ 0.17923, 0.70732, 0.94761 },\n\t\t\t{ 0.17223, 0.71680, 0.93981 },\n\t\t\t{ 0.16529, 0.72620, 0.93161 },\n\t\t\t{ 0.15844, 0.73551, 0.92305 },\n\t\t\t{ 0.15173, 0.74472, 0.91416 },\n\t\t\t{ 0.14519, 0.75381, 0.90496 },\n\t\t\t{ 0.13886, 0.76279, 0.89550 },\n\t\t\t{ 0.13278, 0.77165, 0.88580 },\n\t\t\t{ 0.12698, 0.78037, 0.87590 },\n\t\t\t{ 0.12151, 0.78896, 0.86581 },\n\t\t\t{ 0.11639, 0.79740, 0.85559 },\n\t\t\t{ 0.11167, 0.80569, 0.84525 },\n\t\t\t{ 0.10738, 0.81381, 0.83484 },\n\t\t\t{ 0.10357, 0.82177, 0.82437 },\n\t\t\t{ 0.10026, 0.82955, 0.81389 },\n\t\t\t{ 0.09750, 0.83714, 0.80342 },\n\t\t\t{ 0.09532, 0.84455, 0.79299 },\n\t\t\t{ 0.09377, 0.85175, 0.78264 },\n\t\t\t{ 0.09287, 0.85875, 0.77240 },\n\t\t\t{ 0.09267, 0.86554, 0.76230 },\n\t\t\t{ 0.09320, 0.87211, 0.75237 },\n\t\t\t{ 0.09451, 0.87844, 0.74265 },\n\t\t\t{ 0.09662, 0.88454, 0.73316 },\n\t\t\t{ 0.09958, 0.89040, 0.72393 },\n\t\t\t{ 0.10342, 0.89600, 0.71500 },\n\t\t\t{ 0.10815, 0.90142, 0.70599 },\n\t\t\t{ 0.11374, 0.90673, 0.69651 },\n\t\t\t{ 0.12014, 0.91193, 0.68660 },\n\t\t\t{ 0.12733, 0.91701, 0.67627 },\n\t\t\t{ 0.13526, 0.92197, 0.66556 },\n\t\t\t{ 0.14391, 0.92680, 0.65448 },\n\t\t\t{ 0.15323, 0.93151, 0.64308 },\n\t\t\t{ 0.16319, 0.93609, 0.63137 },\n\t\t\t{ 0.17377, 0.94053, 0.61938 },\n\t\t\t{ 0.18491, 0.94484, 0.60713 },\n\t\t\t{ 0.19659, 0.94901, 0.59466 },\n\t\t\t{ 0.20877, 0.95304, 0.58199 },\n\t\t\t{ 0.22142, 0.95692, 0.56914 },\n\t\t\t{ 0.23449, 0.96065, 0.55614 },\n\t\t\t{ 0.24797, 0.96423, 0.54303 },\n\t\t\t{ 0.26180, 0.96765, 0.52981 },\n\t\t\t{ 0.27597, 0.97092, 0.51653 },\n\t\t\t{ 0.29042, 0.97403, 0.50321 },\n\t\t\t{ 0.30513, 0.97697, 0.48987 },\n\t\t\t{ 0.32006, 0.97974, 0.47654 },\n\t\t\t{ 0.33517, 0.98234, 0.46325 },\n\t\t\t{ 0.35043, 0.98477, 0.45002 },\n\t\t\t{ 0.36581, 0.98702, 0.43688 },\n\t\t\t{ 0.38127, 0.98909, 0.42386 },\n\t\t\t{ 0.39678, 0.99098, 0.41098 },\n\t\t\t{ 0.41229, 0.99268, 0.39826 },\n\t\t\t{ 0.42778, 0.99419, 0.38575 },\n\t\t\t{ 0.44321, 0.99551, 0.37345 },\n\t\t\t{ 0.45854, 0.99663, 0.36140 },\n\t\t\t{ 0.47375, 0.99755, 0.34963 },\n\t\t\t{ 0.48879, 0.99828, 0.33816 },\n\t\t\t{ 0.50362, 0.99879, 0.32701 },\n\t\t\t{ 0.51822, 0.99910, 0.31622 },\n\t\t\t{ 0.53255, 0.99919, 0.30581 },\n\t\t\t{ 0.54658, 0.99907, 0.29581 },\n\t\t\t{ 0.56026, 0.99873, 0.28623 },\n\t\t\t{ 0.57357, 0.99817, 0.27712 },\n\t\t\t{ 0.58646, 0.99739, 0.26849 },\n\t\t\t{ 0.59891, 0.99638, 0.26038 },\n\t\t\t{ 0.61088, 0.99514, 0.25280 },\n\t\t\t{ 0.62233, 0.99366, 0.24579 },\n\t\t\t{ 0.63323, 0.99195, 0.23937 },\n\t\t\t{ 0.64362, 0.98999, 0.23356 },\n\t\t\t{ 0.65394, 0.98775, 0.22835 },\n\t\t\t{ 0.66428, 0.98524, 0.22370 },\n\t\t\t{ 0.67462, 0.98246, 0.21960 },\n\t\t\t{ 0.68494, 0.97941, 0.21602 },\n\t\t\t{ 0.69525, 0.97610, 0.21294 },\n\t\t\t{ 0.70553, 0.97255, 0.21032 },\n\t\t\t{ 0.71577, 0.96875, 0.20815 },\n\t\t\t{ 0.72596, 0.96470, 0.20640 },\n\t\t\t{ 0.73610, 0.96043, 0.20504 },\n\t\t\t{ 0.74617, 0.95593, 0.20406 },\n\t\t\t{ 0.75617, 0.95121, 0.20343 },\n\t\t\t{ 0.76608, 0.94627, 0.20311 },\n\t\t\t{ 0.77591, 0.94113, 0.20310 },\n\t\t\t{ 0.78563, 0.93579, 0.20336 },\n\t\t\t{ 0.79524, 0.93025, 0.20386 },\n\t\t\t{ 0.80473, 0.92452, 0.20459 },\n\t\t\t{ 0.81410, 0.91861, 0.20552 },\n\t\t\t{ 0.82333, 0.91253, 0.20663 },\n\t\t\t{ 0.83241, 0.90627, 0.20788 },\n\t\t\t{ 0.84133, 0.89986, 0.20926 },\n\t\t\t{ 0.85010, 0.89328, 0.21074 },\n\t\t\t{ 0.85868, 0.88655, 0.21230 },\n\t\t\t{ 0.86709, 0.87968, 0.21391 },\n\t\t\t{ 0.87530, 0.87267, 0.21555 },\n\t\t\t{ 0.88331, 0.86553, 0.21719 },\n\t\t\t{ 0.89112, 0.85826, 0.21880 },\n\t\t\t{ 0.89870, 0.85087, 0.22038 },\n\t\t\t{ 0.90605, 0.84337, 0.22188 },\n\t\t\t{ 0.91317, 0.83576, 0.22328 },\n\t\t\t{ 0.92004, 0.82806, 0.22456 },\n\t\t\t{ 0.92666, 0.82025, 0.22570 },\n\t\t\t{ 0.93301, 0.81236, 0.22667 },\n\t\t\t{ 0.93909, 0.80439, 0.22744 },\n\t\t\t{ 0.94489, 0.79634, 0.22800 },\n\t\t\t{ 0.95039, 0.78823, 0.22831 },\n\t\t\t{ 0.95560, 0.78005, 0.22836 },\n\t\t\t{ 0.96049, 0.77181, 0.22811 },\n\t\t\t{ 0.96507, 0.76352, 0.22754 },\n\t\t\t{ 0.96931, 0.75519, 0.22663 },\n\t\t\t{ 0.97323, 0.74682, 0.22536 },\n\t\t\t{ 0.97679, 0.73842, 0.22369 },\n\t\t\t{ 0.98000, 0.73000, 0.22161 },\n\t\t\t{ 0.98289, 0.72140, 0.21918 },\n\t\t\t{ 0.98549, 0.71250, 0.21650 },\n\t\t\t{ 0.98781, 0.70330, 0.21358 },\n\t\t\t{ 0.98986, 0.69382, 0.21043 },\n\t\t\t{ 0.99163, 0.68408, 0.20706 },\n\t\t\t{ 0.99314, 0.67408, 0.20348 },\n\t\t\t{ 0.99438, 0.66386, 0.19971 },\n\t\t\t{ 0.99535, 0.65341, 0.19577 },\n\t\t\t{ 0.99607, 0.64277, 0.19165 },\n\t\t\t{ 0.99654, 0.63193, 0.18738 },\n\t\t\t{ 0.99675, 0.62093, 0.18297 },\n\t\t\t{ 0.99672, 0.60977, 0.17842 },\n\t\t\t{ 0.99644, 0.59846, 0.17376 },\n\t\t\t{ 0.99593, 0.58703, 0.16899 },\n\t\t\t{ 0.99517, 0.57549, 0.16412 },\n\t\t\t{ 0.99419, 0.56386, 0.15918 },\n\t\t\t{ 0.99297, 0.55214, 0.15417 },\n\t\t\t{ 0.99153, 0.54036, 0.14910 },\n\t\t\t{ 0.98987, 0.52854, 0.14398 },\n\t\t\t{ 0.98799, 0.51667, 0.13883 },\n\t\t\t{ 0.98590, 0.50479, 0.13367 },\n\t\t\t{ 0.98360, 0.49291, 0.12849 },\n\t\t\t{ 0.98108, 0.48104, 0.12332 },\n\t\t\t{ 0.97837, 0.46920, 0.11817 },\n\t\t\t{ 0.97545, 0.45740, 0.11305 },\n\t\t\t{ 0.97234, 0.44565, 0.10797 },\n\t\t\t{ 0.96904, 0.43399, 0.10294 },\n\t\t\t{ 0.96555, 0.42241, 0.09798 },\n\t\t\t{ 0.96187, 0.41093, 0.09310 },\n\t\t\t{ 0.95801, 0.39958, 0.08831 },\n\t\t\t{ 0.95398, 0.38836, 0.08362 },\n\t\t\t{ 0.94977, 0.37729, 0.07905 },\n\t\t\t{ 0.94538, 0.36638, 0.07461 },\n\t\t\t{ 0.94084, 0.35566, 0.07031 },\n\t\t\t{ 0.93612, 0.34513, 0.06616 },\n\t\t\t{ 0.93125, 0.33482, 0.06218 },\n\t\t\t{ 0.92623, 0.32473, 0.05837 },\n\t\t\t{ 0.92105, 0.31489, 0.05475 },\n\t\t\t{ 0.91572, 0.30530, 0.05134 },\n\t\t\t{ 0.91024, 0.29599, 0.04814 },\n\t\t\t{ 0.90463, 0.28696, 0.04516 },\n\t\t\t{ 0.89888, 0.27824, 0.04243 },\n\t\t\t{ 0.89298, 0.26981, 0.03993 },\n\t\t\t{ 0.88691, 0.26152, 0.03753 },\n\t\t\t{ 0.88066, 0.25334, 0.03521 },\n\t\t\t{ 0.87422, 0.24526, 0.03297 },\n\t\t\t{ 0.86760, 0.23730, 0.03082 },\n\t\t\t{ 0.86079, 0.22945, 0.02875 },\n\t\t\t{ 0.85380, 0.22170, 0.02677 },\n\t\t\t{ 0.84662, 0.21407, 0.02487 },\n\t\t\t{ 0.83926, 0.20654, 0.02305 },\n\t\t\t{ 0.83172, 0.19912, 0.02131 },\n\t\t\t{ 0.82399, 0.19182, 0.01966 },\n\t\t\t{ 0.81608, 0.18462, 0.01809 },\n\t\t\t{ 0.80799, 0.17753, 0.01660 },\n\t\t\t{ 0.79971, 0.17055, 0.01520 },\n\t\t\t{ 0.79125, 0.16368, 0.01387 },\n\t\t\t{ 0.78260, 0.15693, 0.01264 },\n\t\t\t{ 0.77377, 0.15028, 0.01148 },\n\t\t\t{ 0.76476, 0.14374, 0.01041 },\n\t\t\t{ 0.75556, 0.13731, 0.00942 },\n\t\t\t{ 0.74617, 0.13098, 0.00851 },\n\t\t\t{ 0.73661, 0.12477, 0.00769 },\n\t\t\t{ 0.72686, 0.11867, 0.00695 },\n\t\t\t{ 0.71692, 0.11268, 0.00629 },\n\t\t\t{ 0.70680, 0.10680, 0.00571 },\n\t\t\t{ 0.69650, 0.10102, 0.00522 },\n\t\t\t{ 0.68602, 0.09536, 0.00481 },\n\t\t\t{ 0.67535, 0.08980, 0.00449 },\n\t\t\t{ 0.66449, 0.08436, 0.00424 },\n\t\t\t{ 0.65345, 0.07902, 0.00408 },\n\t\t\t{ 0.64223, 0.07380, 0.00401 },\n\t\t\t{ 0.63082, 0.06868, 0.00401 },\n\t\t\t{ 0.61923, 0.06367, 0.00410 },\n\t\t\t{ 0.60746, 0.05878, 0.00427 },\n\t\t\t{ 0.59550, 0.05399, 0.00453 },\n\t\t\t{ 0.58336, 0.04931, 0.00486 },\n\t\t\t{ 0.57103, 0.04474, 0.00529 },\n\t\t\t{ 0.55852, 0.04028, 0.00579 },\n\t\t\t{ 0.54583, 0.03593, 0.00638 },\n\t\t\t{ 0.53295, 0.03169, 0.00705 },\n\t\t\t{ 0.51989, 0.02756, 0.00780 },\n\t\t\t{ 0.50664, 0.02354, 0.00863 },\n\t\t\t{ 0.49321, 0.01963, 0.00955 },\n\t\t\t{ 0.47960, 0.01583, 0.01055 }\n\t\t};\n\n\t\treturn data[static_cast<size_t>(std::round(x * 255.0))];\n\t}\n\n    inline Color GetHotColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color r{ 1.0, 0.0, 0.0 };\n        constexpr Color g{ 0.0, 1.0, 0.0 };\n        constexpr Color b{ 0.0, 0.0, 1.0 };\n\n        if (x < 0.4)\n        {\n            const double t = x / 0.4;\n            return t * r;\n        }\n        else if (x < 0.8)\n        {\n            const double t = (x - 0.4) / (0.8 - 0.4);\n            return r + t * g;\n        }\n        else\n        {\n            const double t = (x - 0.8) / (1.0 - 0.8);\n            return r + g + t * b;\n        }\n    }\n\n    inline Color GetGrayColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        return (1.0 - x) * Color{ 1.0, 1.0, 1.0 };\n    }\n\n    inline Color GetMagmaColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.001462, 0.000466, 0.013866 },\n            { 0.002258, 0.001295, 0.018331 },\n            { 0.003279, 0.002305, 0.023708 },\n            { 0.004512, 0.003490, 0.029965 },\n            { 0.005950, 0.004843, 0.037130 },\n            { 0.007588, 0.006356, 0.044973 },\n            { 0.009426, 0.008022, 0.052844 },\n            { 0.011465, 0.009828, 0.060750 },\n            { 0.013708, 0.011771, 0.068667 },\n            { 0.016156, 0.013840, 0.076603 },\n            { 0.018815, 0.016026, 0.084584 },\n            { 0.021692, 0.018320, 0.092610 },\n            { 0.024792, 0.020715, 0.100676 },\n            { 0.028123, 0.023201, 0.108787 },\n            { 0.031696, 0.025765, 0.116965 },\n            { 0.035520, 0.028397, 0.125209 },\n            { 0.039608, 0.031090, 0.133515 },\n            { 0.043830, 0.033830, 0.141886 },\n            { 0.048062, 0.036607, 0.150327 },\n            { 0.052320, 0.039407, 0.158841 },\n            { 0.056615, 0.042160, 0.167446 },\n            { 0.060949, 0.044794, 0.176129 },\n            { 0.065330, 0.047318, 0.184892 },\n            { 0.069764, 0.049726, 0.193735 },\n            { 0.074257, 0.052017, 0.202660 },\n            { 0.078815, 0.054184, 0.211667 },\n            { 0.083446, 0.056225, 0.220755 },\n            { 0.088155, 0.058133, 0.229922 },\n            { 0.092949, 0.059904, 0.239164 },\n            { 0.097833, 0.061531, 0.248477 },\n            { 0.102815, 0.063010, 0.257854 },\n            { 0.107899, 0.064335, 0.267289 },\n            { 0.113094, 0.065492, 0.276784 },\n            { 0.118405, 0.066479, 0.286321 },\n            { 0.123833, 0.067295, 0.295879 },\n            { 0.129380, 0.067935, 0.305443 },\n            { 0.135053, 0.068391, 0.315000 },\n            { 0.140858, 0.068654, 0.324538 },\n            { 0.146785, 0.068738, 0.334011 },\n            { 0.152839, 0.068637, 0.343404 },\n            { 0.159018, 0.068354, 0.352688 },\n            { 0.165308, 0.067911, 0.361816 },\n            { 0.171713, 0.067305, 0.370771 },\n            { 0.178212, 0.066576, 0.379497 },\n            { 0.184801, 0.065732, 0.387973 },\n            { 0.191460, 0.064818, 0.396152 },\n            { 0.198177, 0.063862, 0.404009 },\n            { 0.204935, 0.062907, 0.411514 },\n            { 0.211718, 0.061992, 0.418647 },\n            { 0.218512, 0.061158, 0.425392 },\n            { 0.225302, 0.060445, 0.431742 },\n            { 0.232077, 0.059889, 0.437695 },\n            { 0.238826, 0.059517, 0.443256 },\n            { 0.245543, 0.059352, 0.448436 },\n            { 0.252220, 0.059415, 0.453248 },\n            { 0.258857, 0.059706, 0.457710 },\n            { 0.265447, 0.060237, 0.461840 },\n            { 0.271994, 0.060994, 0.465660 },\n            { 0.278493, 0.061978, 0.469190 },\n            { 0.284951, 0.063168, 0.472451 },\n            { 0.291366, 0.064553, 0.475462 },\n            { 0.297740, 0.066117, 0.478243 },\n            { 0.304081, 0.067835, 0.480812 },\n            { 0.310382, 0.069702, 0.483186 },\n            { 0.316654, 0.071690, 0.485380 },\n            { 0.322899, 0.073782, 0.487408 },\n            { 0.329114, 0.075972, 0.489287 },\n            { 0.335308, 0.078236, 0.491024 },\n            { 0.341482, 0.080564, 0.492631 },\n            { 0.347636, 0.082946, 0.494121 },\n            { 0.353773, 0.085373, 0.495501 },\n            { 0.359898, 0.087831, 0.496778 },\n            { 0.366012, 0.090314, 0.497960 },\n            { 0.372116, 0.092816, 0.499053 },\n            { 0.378211, 0.095332, 0.500067 },\n            { 0.384299, 0.097855, 0.501002 },\n            { 0.390384, 0.100379, 0.501864 },\n            { 0.396467, 0.102902, 0.502658 },\n            { 0.402548, 0.105420, 0.503386 },\n            { 0.408629, 0.107930, 0.504052 },\n            { 0.414709, 0.110431, 0.504662 },\n            { 0.420791, 0.112920, 0.505215 },\n            { 0.426877, 0.115395, 0.505714 },\n            { 0.432967, 0.117855, 0.506160 },\n            { 0.439062, 0.120298, 0.506555 },\n            { 0.445163, 0.122724, 0.506901 },\n            { 0.451271, 0.125132, 0.507198 },\n            { 0.457386, 0.127522, 0.507448 },\n            { 0.463508, 0.129893, 0.507652 },\n            { 0.469640, 0.132245, 0.507809 },\n            { 0.475780, 0.134577, 0.507921 },\n            { 0.481929, 0.136891, 0.507989 },\n            { 0.488088, 0.139186, 0.508011 },\n            { 0.494258, 0.141462, 0.507988 },\n            { 0.500438, 0.143719, 0.507920 },\n            { 0.506629, 0.145958, 0.507806 },\n            { 0.512831, 0.148179, 0.507648 },\n            { 0.519045, 0.150383, 0.507443 },\n            { 0.525270, 0.152569, 0.507192 },\n            { 0.531507, 0.154739, 0.506895 },\n            { 0.537755, 0.156894, 0.506551 },\n            { 0.544015, 0.159033, 0.506159 },\n            { 0.550287, 0.161158, 0.505719 },\n            { 0.556571, 0.163269, 0.505230 },\n            { 0.562866, 0.165368, 0.504692 },\n            { 0.569172, 0.167454, 0.504105 },\n            { 0.575490, 0.169530, 0.503466 },\n            { 0.581819, 0.171596, 0.502777 },\n            { 0.588158, 0.173652, 0.502035 },\n            { 0.594508, 0.175701, 0.501241 },\n            { 0.600868, 0.177743, 0.500394 },\n            { 0.607238, 0.179779, 0.499492 },\n            { 0.613617, 0.181811, 0.498536 },\n            { 0.620005, 0.183840, 0.497524 },\n            { 0.626401, 0.185867, 0.496456 },\n            { 0.632805, 0.187893, 0.495332 },\n            { 0.639216, 0.189921, 0.494150 },\n            { 0.645633, 0.191952, 0.492910 },\n            { 0.652056, 0.193986, 0.491611 },\n            { 0.658483, 0.196027, 0.490253 },\n            { 0.664915, 0.198075, 0.488836 },\n            { 0.671349, 0.200133, 0.487358 },\n            { 0.677786, 0.202203, 0.485819 },\n            { 0.684224, 0.204286, 0.484219 },\n            { 0.690661, 0.206384, 0.482558 },\n            { 0.697098, 0.208501, 0.480835 },\n            { 0.703532, 0.210638, 0.479049 },\n            { 0.709962, 0.212797, 0.477201 },\n            { 0.716387, 0.214982, 0.475290 },\n            { 0.722805, 0.217194, 0.473316 },\n            { 0.729216, 0.219437, 0.471279 },\n            { 0.735616, 0.221713, 0.469180 },\n            { 0.742004, 0.224025, 0.467018 },\n            { 0.748378, 0.226377, 0.464794 },\n            { 0.754737, 0.228772, 0.462509 },\n            { 0.761077, 0.231214, 0.460162 },\n            { 0.767398, 0.233705, 0.457755 },\n            { 0.773695, 0.236249, 0.455289 },\n            { 0.779968, 0.238851, 0.452765 },\n            { 0.786212, 0.241514, 0.450184 },\n            { 0.792427, 0.244242, 0.447543 },\n            { 0.798608, 0.247040, 0.444848 },\n            { 0.804752, 0.249911, 0.442102 },\n            { 0.810855, 0.252861, 0.439305 },\n            { 0.816914, 0.255895, 0.436461 },\n            { 0.822926, 0.259016, 0.433573 },\n            { 0.828886, 0.262229, 0.430644 },\n            { 0.834791, 0.265540, 0.427671 },\n            { 0.840636, 0.268953, 0.424666 },\n            { 0.846416, 0.272473, 0.421631 },\n            { 0.852126, 0.276106, 0.418573 },\n            { 0.857763, 0.279857, 0.415496 },\n            { 0.863320, 0.283729, 0.412403 },\n            { 0.868793, 0.287728, 0.409303 },\n            { 0.874176, 0.291859, 0.406205 },\n            { 0.879464, 0.296125, 0.403118 },\n            { 0.884651, 0.300530, 0.400047 },\n            { 0.889731, 0.305079, 0.397002 },\n            { 0.894700, 0.309773, 0.393995 },\n            { 0.899552, 0.314616, 0.391037 },\n            { 0.904281, 0.319610, 0.388137 },\n            { 0.908884, 0.324755, 0.385308 },\n            { 0.913354, 0.330052, 0.382563 },\n            { 0.917689, 0.335500, 0.379915 },\n            { 0.921884, 0.341098, 0.377376 },\n            { 0.925937, 0.346844, 0.374959 },\n            { 0.929845, 0.352734, 0.372677 },\n            { 0.933606, 0.358764, 0.370541 },\n            { 0.937221, 0.364929, 0.368567 },\n            { 0.940687, 0.371224, 0.366762 },\n            { 0.944006, 0.377643, 0.365136 },\n            { 0.947180, 0.384178, 0.363701 },\n            { 0.950210, 0.390820, 0.362468 },\n            { 0.953099, 0.397563, 0.361438 },\n            { 0.955849, 0.404400, 0.360619 },\n            { 0.958464, 0.411324, 0.360014 },\n            { 0.960949, 0.418323, 0.359630 },\n            { 0.963310, 0.425390, 0.359469 },\n            { 0.965549, 0.432519, 0.359529 },\n            { 0.967671, 0.439703, 0.359810 },\n            { 0.969680, 0.446936, 0.360311 },\n            { 0.971582, 0.454210, 0.361030 },\n            { 0.973381, 0.461520, 0.361965 },\n            { 0.975082, 0.468861, 0.363111 },\n            { 0.976690, 0.476226, 0.364466 },\n            { 0.978210, 0.483612, 0.366025 },\n            { 0.979645, 0.491014, 0.367783 },\n            { 0.981000, 0.498428, 0.369734 },\n            { 0.982279, 0.505851, 0.371874 },\n            { 0.983485, 0.513280, 0.374198 },\n            { 0.984622, 0.520713, 0.376698 },\n            { 0.985693, 0.528148, 0.379371 },\n            { 0.986700, 0.535582, 0.382210 },\n            { 0.987646, 0.543015, 0.385210 },\n            { 0.988533, 0.550446, 0.388365 },\n            { 0.989363, 0.557873, 0.391671 },\n            { 0.990138, 0.565296, 0.395122 },\n            { 0.990871, 0.572706, 0.398714 },\n            { 0.991558, 0.580107, 0.402441 },\n            { 0.992196, 0.587502, 0.406299 },\n            { 0.992785, 0.594891, 0.410283 },\n            { 0.993326, 0.602275, 0.414390 },\n            { 0.993834, 0.609644, 0.418613 },\n            { 0.994309, 0.616999, 0.422950 },\n            { 0.994738, 0.624350, 0.427397 },\n            { 0.995122, 0.631696, 0.431951 },\n            { 0.995480, 0.639027, 0.436607 },\n            { 0.995810, 0.646344, 0.441361 },\n            { 0.996096, 0.653659, 0.446213 },\n            { 0.996341, 0.660969, 0.451160 },\n            { 0.996580, 0.668256, 0.456192 },\n            { 0.996775, 0.675541, 0.461314 },\n            { 0.996925, 0.682828, 0.466526 },\n            { 0.997077, 0.690088, 0.471811 },\n            { 0.997186, 0.697349, 0.477182 },\n            { 0.997254, 0.704611, 0.482635 },\n            { 0.997325, 0.711848, 0.488154 },\n            { 0.997351, 0.719089, 0.493755 },\n            { 0.997351, 0.726324, 0.499428 },\n            { 0.997341, 0.733545, 0.505167 },\n            { 0.997285, 0.740772, 0.510983 },\n            { 0.997228, 0.747981, 0.516859 },\n            { 0.997138, 0.755190, 0.522806 },\n            { 0.997019, 0.762398, 0.528821 },\n            { 0.996898, 0.769591, 0.534892 },\n            { 0.996727, 0.776795, 0.541039 },\n            { 0.996571, 0.783977, 0.547233 },\n            { 0.996369, 0.791167, 0.553499 },\n            { 0.996162, 0.798348, 0.559820 },\n            { 0.995932, 0.805527, 0.566202 },\n            { 0.995680, 0.812706, 0.572645 },\n            { 0.995424, 0.819875, 0.579140 },\n            { 0.995131, 0.827052, 0.585701 },\n            { 0.994851, 0.834213, 0.592307 },\n            { 0.994524, 0.841387, 0.598983 },\n            { 0.994222, 0.848540, 0.605696 },\n            { 0.993866, 0.855711, 0.612482 },\n            { 0.993545, 0.862859, 0.619299 },\n            { 0.993170, 0.870024, 0.626189 },\n            { 0.992831, 0.877168, 0.633109 },\n            { 0.992440, 0.884330, 0.640099 },\n            { 0.992089, 0.891470, 0.647116 },\n            { 0.991688, 0.898627, 0.654202 },\n            { 0.991332, 0.905763, 0.661309 },\n            { 0.990930, 0.912915, 0.668481 },\n            { 0.990570, 0.920049, 0.675675 },\n            { 0.990175, 0.927196, 0.682926 },\n            { 0.989815, 0.934329, 0.690198 },\n            { 0.989434, 0.941470, 0.697519 },\n            { 0.989077, 0.948604, 0.704863 },\n            { 0.988717, 0.955742, 0.712242 },\n            { 0.988367, 0.962878, 0.719649 },\n            { 0.988033, 0.970012, 0.727077 },\n            { 0.987691, 0.977154, 0.734536 },\n            { 0.987387, 0.984288, 0.742002 },\n            { 0.987053, 0.991438, 0.749504 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetInfernoColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.001462, 0.000466, 0.013866 },\n            { 0.002267, 0.001270, 0.018570 },\n            { 0.003299, 0.002249, 0.024239 },\n            { 0.004547, 0.003392, 0.030909 },\n            { 0.006006, 0.004692, 0.038558 },\n            { 0.007676, 0.006136, 0.046836 },\n            { 0.009561, 0.007713, 0.055143 },\n            { 0.011663, 0.009417, 0.063460 },\n            { 0.013995, 0.011225, 0.071862 },\n            { 0.016561, 0.013136, 0.080282 },\n            { 0.019373, 0.015133, 0.088767 },\n            { 0.022447, 0.017199, 0.097327 },\n            { 0.025793, 0.019331, 0.105930 },\n            { 0.029432, 0.021503, 0.114621 },\n            { 0.033385, 0.023702, 0.123397 },\n            { 0.037668, 0.025921, 0.132232 },\n            { 0.042253, 0.028139, 0.141141 },\n            { 0.046915, 0.030324, 0.150164 },\n            { 0.051644, 0.032474, 0.159254 },\n            { 0.056449, 0.034569, 0.168414 },\n            { 0.061340, 0.036590, 0.177642 },\n            { 0.066331, 0.038504, 0.186962 },\n            { 0.071429, 0.040294, 0.196354 },\n            { 0.076637, 0.041905, 0.205799 },\n            { 0.081962, 0.043328, 0.215289 },\n            { 0.087411, 0.044556, 0.224813 },\n            { 0.092990, 0.045583, 0.234358 },\n            { 0.098702, 0.046402, 0.243904 },\n            { 0.104551, 0.047008, 0.253430 },\n            { 0.110536, 0.047399, 0.262912 },\n            { 0.116656, 0.047574, 0.272321 },\n            { 0.122908, 0.047536, 0.281624 },\n            { 0.129285, 0.047293, 0.290788 },\n            { 0.135778, 0.046856, 0.299776 },\n            { 0.142378, 0.046242, 0.308553 },\n            { 0.149073, 0.045468, 0.317085 },\n            { 0.155850, 0.044559, 0.325338 },\n            { 0.162689, 0.043554, 0.333277 },\n            { 0.169575, 0.042489, 0.340874 },\n            { 0.176493, 0.041402, 0.348111 },\n            { 0.183429, 0.040329, 0.354971 },\n            { 0.190367, 0.039309, 0.361447 },\n            { 0.197297, 0.038400, 0.367535 },\n            { 0.204209, 0.037632, 0.373238 },\n            { 0.211095, 0.037030, 0.378563 },\n            { 0.217949, 0.036615, 0.383522 },\n            { 0.224763, 0.036405, 0.388129 },\n            { 0.231538, 0.036405, 0.392400 },\n            { 0.238273, 0.036621, 0.396353 },\n            { 0.244967, 0.037055, 0.400007 },\n            { 0.251620, 0.037705, 0.403378 },\n            { 0.258234, 0.038571, 0.406485 },\n            { 0.264810, 0.039647, 0.409345 },\n            { 0.271347, 0.040922, 0.411976 },\n            { 0.277850, 0.042353, 0.414392 },\n            { 0.284321, 0.043933, 0.416608 },\n            { 0.290763, 0.045644, 0.418637 },\n            { 0.297178, 0.047470, 0.420491 },\n            { 0.303568, 0.049396, 0.422182 },\n            { 0.309935, 0.051407, 0.423721 },\n            { 0.316282, 0.053490, 0.425116 },\n            { 0.322610, 0.055634, 0.426377 },\n            { 0.328921, 0.057827, 0.427511 },\n            { 0.335217, 0.060060, 0.428524 },\n            { 0.341500, 0.062325, 0.429425 },\n            { 0.347771, 0.064616, 0.430217 },\n            { 0.354032, 0.066925, 0.430906 },\n            { 0.360284, 0.069247, 0.431497 },\n            { 0.366529, 0.071579, 0.431994 },\n            { 0.372768, 0.073915, 0.432400 },\n            { 0.379001, 0.076253, 0.432719 },\n            { 0.385228, 0.078591, 0.432955 },\n            { 0.391453, 0.080927, 0.433109 },\n            { 0.397674, 0.083257, 0.433183 },\n            { 0.403894, 0.085580, 0.433179 },\n            { 0.410113, 0.087896, 0.433098 },\n            { 0.416331, 0.090203, 0.432943 },\n            { 0.422549, 0.092501, 0.432714 },\n            { 0.428768, 0.094790, 0.432412 },\n            { 0.434987, 0.097069, 0.432039 },\n            { 0.441207, 0.099338, 0.431594 },\n            { 0.447428, 0.101597, 0.431080 },\n            { 0.453651, 0.103848, 0.430498 },\n            { 0.459875, 0.106089, 0.429846 },\n            { 0.466100, 0.108322, 0.429125 },\n            { 0.472328, 0.110547, 0.428334 },\n            { 0.478558, 0.112764, 0.427475 },\n            { 0.484789, 0.114974, 0.426548 },\n            { 0.491022, 0.117179, 0.425552 },\n            { 0.497257, 0.119379, 0.424488 },\n            { 0.503493, 0.121575, 0.423356 },\n            { 0.509730, 0.123769, 0.422156 },\n            { 0.515967, 0.125960, 0.420887 },\n            { 0.522206, 0.128150, 0.419549 },\n            { 0.528444, 0.130341, 0.418142 },\n            { 0.534683, 0.132534, 0.416667 },\n            { 0.540920, 0.134729, 0.415123 },\n            { 0.547157, 0.136929, 0.413511 },\n            { 0.553392, 0.139134, 0.411829 },\n            { 0.559624, 0.141346, 0.410078 },\n            { 0.565854, 0.143567, 0.408258 },\n            { 0.572081, 0.145797, 0.406369 },\n            { 0.578304, 0.148039, 0.404411 },\n            { 0.584521, 0.150294, 0.402385 },\n            { 0.590734, 0.152563, 0.400290 },\n            { 0.596940, 0.154848, 0.398125 },\n            { 0.603139, 0.157151, 0.395891 },\n            { 0.609330, 0.159474, 0.393589 },\n            { 0.615513, 0.161817, 0.391219 },\n            { 0.621685, 0.164184, 0.388781 },\n            { 0.627847, 0.166575, 0.386276 },\n            { 0.633998, 0.168992, 0.383704 },\n            { 0.640135, 0.171438, 0.381065 },\n            { 0.646260, 0.173914, 0.378359 },\n            { 0.652369, 0.176421, 0.375586 },\n            { 0.658463, 0.178962, 0.372748 },\n            { 0.664540, 0.181539, 0.369846 },\n            { 0.670599, 0.184153, 0.366879 },\n            { 0.676638, 0.186807, 0.363849 },\n            { 0.682656, 0.189501, 0.360757 },\n            { 0.688653, 0.192239, 0.357603 },\n            { 0.694627, 0.195021, 0.354388 },\n            { 0.700576, 0.197851, 0.351113 },\n            { 0.706500, 0.200728, 0.347777 },\n            { 0.712396, 0.203656, 0.344383 },\n            { 0.718264, 0.206636, 0.340931 },\n            { 0.724103, 0.209670, 0.337424 },\n            { 0.729909, 0.212759, 0.333861 },\n            { 0.735683, 0.215906, 0.330245 },\n            { 0.741423, 0.219112, 0.326576 },\n            { 0.747127, 0.222378, 0.322856 },\n            { 0.752794, 0.225706, 0.319085 },\n            { 0.758422, 0.229097, 0.315266 },\n            { 0.764010, 0.232554, 0.311399 },\n            { 0.769556, 0.236077, 0.307485 },\n            { 0.775059, 0.239667, 0.303526 },\n            { 0.780517, 0.243327, 0.299523 },\n            { 0.785929, 0.247056, 0.295477 },\n            { 0.791293, 0.250856, 0.291390 },\n            { 0.796607, 0.254728, 0.287264 },\n            { 0.801871, 0.258674, 0.283099 },\n            { 0.807082, 0.262692, 0.278898 },\n            { 0.812239, 0.266786, 0.274661 },\n            { 0.817341, 0.270954, 0.270390 },\n            { 0.822386, 0.275197, 0.266085 },\n            { 0.827372, 0.279517, 0.261750 },\n            { 0.832299, 0.283913, 0.257383 },\n            { 0.837165, 0.288385, 0.252988 },\n            { 0.841969, 0.292933, 0.248564 },\n            { 0.846709, 0.297559, 0.244113 },\n            { 0.851384, 0.302260, 0.239636 },\n            { 0.855992, 0.307038, 0.235133 },\n            { 0.860533, 0.311892, 0.230606 },\n            { 0.865006, 0.316822, 0.226055 },\n            { 0.869409, 0.321827, 0.221482 },\n            { 0.873741, 0.326906, 0.216886 },\n            { 0.878001, 0.332060, 0.212268 },\n            { 0.882188, 0.337287, 0.207628 },\n            { 0.886302, 0.342586, 0.202968 },\n            { 0.890341, 0.347957, 0.198286 },\n            { 0.894305, 0.353399, 0.193584 },\n            { 0.898192, 0.358911, 0.188860 },\n            { 0.902003, 0.364492, 0.184116 },\n            { 0.905735, 0.370140, 0.179350 },\n            { 0.909390, 0.375856, 0.174563 },\n            { 0.912966, 0.381636, 0.169755 },\n            { 0.916462, 0.387481, 0.164924 },\n            { 0.919879, 0.393389, 0.160070 },\n            { 0.923215, 0.399359, 0.155193 },\n            { 0.926470, 0.405389, 0.150292 },\n            { 0.929644, 0.411479, 0.145367 },\n            { 0.932737, 0.417627, 0.140417 },\n            { 0.935747, 0.423831, 0.135440 },\n            { 0.938675, 0.430091, 0.130438 },\n            { 0.941521, 0.436405, 0.125409 },\n            { 0.944285, 0.442772, 0.120354 },\n            { 0.946965, 0.449191, 0.115272 },\n            { 0.949562, 0.455660, 0.110164 },\n            { 0.952075, 0.462178, 0.105031 },\n            { 0.954506, 0.468744, 0.099874 },\n            { 0.956852, 0.475356, 0.094695 },\n            { 0.959114, 0.482014, 0.089499 },\n            { 0.961293, 0.488716, 0.084289 },\n            { 0.963387, 0.495462, 0.079073 },\n            { 0.965397, 0.502249, 0.073859 },\n            { 0.967322, 0.509078, 0.068659 },\n            { 0.969163, 0.515946, 0.063488 },\n            { 0.970919, 0.522853, 0.058367 },\n            { 0.972590, 0.529798, 0.053324 },\n            { 0.974176, 0.536780, 0.048392 },\n            { 0.975677, 0.543798, 0.043618 },\n            { 0.977092, 0.550850, 0.039050 },\n            { 0.978422, 0.557937, 0.034931 },\n            { 0.979666, 0.565057, 0.031409 },\n            { 0.980824, 0.572209, 0.028508 },\n            { 0.981895, 0.579392, 0.026250 },\n            { 0.982881, 0.586606, 0.024661 },\n            { 0.983779, 0.593849, 0.023770 },\n            { 0.984591, 0.601122, 0.023606 },\n            { 0.985315, 0.608422, 0.024202 },\n            { 0.985952, 0.615750, 0.025592 },\n            { 0.986502, 0.623105, 0.027814 },\n            { 0.986964, 0.630485, 0.030908 },\n            { 0.987337, 0.637890, 0.034916 },\n            { 0.987622, 0.645320, 0.039886 },\n            { 0.987819, 0.652773, 0.045581 },\n            { 0.987926, 0.660250, 0.051750 },\n            { 0.987945, 0.667748, 0.058329 },\n            { 0.987874, 0.675267, 0.065257 },\n            { 0.987714, 0.682807, 0.072489 },\n            { 0.987464, 0.690366, 0.079990 },\n            { 0.987124, 0.697944, 0.087731 },\n            { 0.986694, 0.705540, 0.095694 },\n            { 0.986175, 0.713153, 0.103863 },\n            { 0.985566, 0.720782, 0.112229 },\n            { 0.984865, 0.728427, 0.120785 },\n            { 0.984075, 0.736087, 0.129527 },\n            { 0.983196, 0.743758, 0.138453 },\n            { 0.982228, 0.751442, 0.147565 },\n            { 0.981173, 0.759135, 0.156863 },\n            { 0.980032, 0.766837, 0.166353 },\n            { 0.978806, 0.774545, 0.176037 },\n            { 0.977497, 0.782258, 0.185923 },\n            { 0.976108, 0.789974, 0.196018 },\n            { 0.974638, 0.797692, 0.206332 },\n            { 0.973088, 0.805409, 0.216877 },\n            { 0.971468, 0.813122, 0.227658 },\n            { 0.969783, 0.820825, 0.238686 },\n            { 0.968041, 0.828515, 0.249972 },\n            { 0.966243, 0.836191, 0.261534 },\n            { 0.964394, 0.843848, 0.273391 },\n            { 0.962517, 0.851476, 0.285546 },\n            { 0.960626, 0.859069, 0.298010 },\n            { 0.958720, 0.866624, 0.310820 },\n            { 0.956834, 0.874129, 0.323974 },\n            { 0.954997, 0.881569, 0.337475 },\n            { 0.953215, 0.888942, 0.351369 },\n            { 0.951546, 0.896226, 0.365627 },\n            { 0.950018, 0.903409, 0.380271 },\n            { 0.948683, 0.910473, 0.395289 },\n            { 0.947594, 0.917399, 0.410665 },\n            { 0.946809, 0.924168, 0.426373 },\n            { 0.946392, 0.930761, 0.442367 },\n            { 0.946403, 0.937159, 0.458592 },\n            { 0.946903, 0.943348, 0.474970 },\n            { 0.947937, 0.949318, 0.491426 },\n            { 0.949545, 0.955063, 0.507860 },\n            { 0.951740, 0.960587, 0.524203 },\n            { 0.954529, 0.965896, 0.540361 },\n            { 0.957896, 0.971003, 0.556275 },\n            { 0.961812, 0.975924, 0.571925 },\n            { 0.966249, 0.980678, 0.587206 },\n            { 0.971162, 0.985282, 0.602154 },\n            { 0.976511, 0.989753, 0.616760 },\n            { 0.982257, 0.994109, 0.631017 },\n            { 0.988362, 0.998364, 0.644924 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetPlasmaColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.050383, 0.029803, 0.527975 },\n            { 0.063536, 0.028426, 0.533124 },\n            { 0.075353, 0.027206, 0.538007 },\n            { 0.086222, 0.026125, 0.542658 },\n            { 0.096379, 0.025165, 0.547103 },\n            { 0.105980, 0.024309, 0.551368 },\n            { 0.115124, 0.023556, 0.555468 },\n            { 0.123903, 0.022878, 0.559423 },\n            { 0.132381, 0.022258, 0.563250 },\n            { 0.140603, 0.021687, 0.566959 },\n            { 0.148607, 0.021154, 0.570562 },\n            { 0.156421, 0.020651, 0.574065 },\n            { 0.164070, 0.020171, 0.577478 },\n            { 0.171574, 0.019706, 0.580806 },\n            { 0.178950, 0.019252, 0.584054 },\n            { 0.186213, 0.018803, 0.587228 },\n            { 0.193374, 0.018354, 0.590330 },\n            { 0.200445, 0.017902, 0.593364 },\n            { 0.207435, 0.017442, 0.596333 },\n            { 0.214350, 0.016973, 0.599239 },\n            { 0.221197, 0.016497, 0.602083 },\n            { 0.227983, 0.016007, 0.604867 },\n            { 0.234715, 0.015502, 0.607592 },\n            { 0.241396, 0.014979, 0.610259 },\n            { 0.248032, 0.014439, 0.612868 },\n            { 0.254627, 0.013882, 0.615419 },\n            { 0.261183, 0.013308, 0.617911 },\n            { 0.267703, 0.012716, 0.620346 },\n            { 0.274191, 0.012109, 0.622722 },\n            { 0.280648, 0.011488, 0.625038 },\n            { 0.287076, 0.010855, 0.627295 },\n            { 0.293478, 0.010213, 0.629490 },\n            { 0.299855, 0.009561, 0.631624 },\n            { 0.306210, 0.008902, 0.633694 },\n            { 0.312543, 0.008239, 0.635700 },\n            { 0.318856, 0.007576, 0.637640 },\n            { 0.325150, 0.006915, 0.639512 },\n            { 0.331426, 0.006261, 0.641316 },\n            { 0.337683, 0.005618, 0.643049 },\n            { 0.343925, 0.004991, 0.644710 },\n            { 0.350150, 0.004382, 0.646298 },\n            { 0.356359, 0.003798, 0.647810 },\n            { 0.362553, 0.003243, 0.649245 },\n            { 0.368733, 0.002724, 0.650601 },\n            { 0.374897, 0.002245, 0.651876 },\n            { 0.381047, 0.001814, 0.653068 },\n            { 0.387183, 0.001434, 0.654177 },\n            { 0.393304, 0.001114, 0.655199 },\n            { 0.399411, 0.000859, 0.656133 },\n            { 0.405503, 0.000678, 0.656977 },\n            { 0.411580, 0.000577, 0.657730 },\n            { 0.417642, 0.000564, 0.658390 },\n            { 0.423689, 0.000646, 0.658956 },\n            { 0.429719, 0.000831, 0.659425 },\n            { 0.435734, 0.001127, 0.659797 },\n            { 0.441732, 0.001540, 0.660069 },\n            { 0.447714, 0.002080, 0.660240 },\n            { 0.453677, 0.002755, 0.660310 },\n            { 0.459623, 0.003574, 0.660277 },\n            { 0.465550, 0.004545, 0.660139 },\n            { 0.471457, 0.005678, 0.659897 },\n            { 0.477344, 0.006980, 0.659549 },\n            { 0.483210, 0.008460, 0.659095 },\n            { 0.489055, 0.010127, 0.658534 },\n            { 0.494877, 0.011990, 0.657865 },\n            { 0.500678, 0.014055, 0.657088 },\n            { 0.506454, 0.016333, 0.656202 },\n            { 0.512206, 0.018833, 0.655209 },\n            { 0.517933, 0.021563, 0.654109 },\n            { 0.523633, 0.024532, 0.652901 },\n            { 0.529306, 0.027747, 0.651586 },\n            { 0.534952, 0.031217, 0.650165 },\n            { 0.540570, 0.034950, 0.648640 },\n            { 0.546157, 0.038954, 0.647010 },\n            { 0.551715, 0.043136, 0.645277 },\n            { 0.557243, 0.047331, 0.643443 },\n            { 0.562738, 0.051545, 0.641509 },\n            { 0.568201, 0.055778, 0.639477 },\n            { 0.573632, 0.060028, 0.637349 },\n            { 0.579029, 0.064296, 0.635126 },\n            { 0.584391, 0.068579, 0.632812 },\n            { 0.589719, 0.072878, 0.630408 },\n            { 0.595011, 0.077190, 0.627917 },\n            { 0.600266, 0.081516, 0.625342 },\n            { 0.605485, 0.085854, 0.622686 },\n            { 0.610667, 0.090204, 0.619951 },\n            { 0.615812, 0.094564, 0.617140 },\n            { 0.620919, 0.098934, 0.614257 },\n            { 0.625987, 0.103312, 0.611305 },\n            { 0.631017, 0.107699, 0.608287 },\n            { 0.636008, 0.112092, 0.605205 },\n            { 0.640959, 0.116492, 0.602065 },\n            { 0.645872, 0.120898, 0.598867 },\n            { 0.650746, 0.125309, 0.595617 },\n            { 0.655580, 0.129725, 0.592317 },\n            { 0.660374, 0.134144, 0.588971 },\n            { 0.665129, 0.138566, 0.585582 },\n            { 0.669845, 0.142992, 0.582154 },\n            { 0.674522, 0.147419, 0.578688 },\n            { 0.679160, 0.151848, 0.575189 },\n            { 0.683758, 0.156278, 0.571660 },\n            { 0.688318, 0.160709, 0.568103 },\n            { 0.692840, 0.165141, 0.564522 },\n            { 0.697324, 0.169573, 0.560919 },\n            { 0.701769, 0.174005, 0.557296 },\n            { 0.706178, 0.178437, 0.553657 },\n            { 0.710549, 0.182868, 0.550004 },\n            { 0.714883, 0.187299, 0.546338 },\n            { 0.719181, 0.191729, 0.542663 },\n            { 0.723444, 0.196158, 0.538981 },\n            { 0.727670, 0.200586, 0.535293 },\n            { 0.731862, 0.205013, 0.531601 },\n            { 0.736019, 0.209439, 0.527908 },\n            { 0.740143, 0.213864, 0.524216 },\n            { 0.744232, 0.218288, 0.520524 },\n            { 0.748289, 0.222711, 0.516834 },\n            { 0.752312, 0.227133, 0.513149 },\n            { 0.756304, 0.231555, 0.509468 },\n            { 0.760264, 0.235976, 0.505794 },\n            { 0.764193, 0.240396, 0.502126 },\n            { 0.768090, 0.244817, 0.498465 },\n            { 0.771958, 0.249237, 0.494813 },\n            { 0.775796, 0.253658, 0.491171 },\n            { 0.779604, 0.258078, 0.487539 },\n            { 0.783383, 0.262500, 0.483918 },\n            { 0.787133, 0.266922, 0.480307 },\n            { 0.790855, 0.271345, 0.476706 },\n            { 0.794549, 0.275770, 0.473117 },\n            { 0.798216, 0.280197, 0.469538 },\n            { 0.801855, 0.284626, 0.465971 },\n            { 0.805467, 0.289057, 0.462415 },\n            { 0.809052, 0.293491, 0.458870 },\n            { 0.812612, 0.297928, 0.455338 },\n            { 0.816144, 0.302368, 0.451816 },\n            { 0.819651, 0.306812, 0.448306 },\n            { 0.823132, 0.311261, 0.444806 },\n            { 0.826588, 0.315714, 0.441316 },\n            { 0.830018, 0.320172, 0.437836 },\n            { 0.833422, 0.324635, 0.434366 },\n            { 0.836801, 0.329105, 0.430905 },\n            { 0.840155, 0.333580, 0.427455 },\n            { 0.843484, 0.338062, 0.424013 },\n            { 0.846788, 0.342551, 0.420579 },\n            { 0.850066, 0.347048, 0.417153 },\n            { 0.853319, 0.351553, 0.413734 },\n            { 0.856547, 0.356066, 0.410322 },\n            { 0.859750, 0.360588, 0.406917 },\n            { 0.862927, 0.365119, 0.403519 },\n            { 0.866078, 0.369660, 0.400126 },\n            { 0.869203, 0.374212, 0.396738 },\n            { 0.872303, 0.378774, 0.393355 },\n            { 0.875376, 0.383347, 0.389976 },\n            { 0.878423, 0.387932, 0.386600 },\n            { 0.881443, 0.392529, 0.383229 },\n            { 0.884436, 0.397139, 0.379860 },\n            { 0.887402, 0.401762, 0.376494 },\n            { 0.890340, 0.406398, 0.373130 },\n            { 0.893250, 0.411048, 0.369768 },\n            { 0.896131, 0.415712, 0.366407 },\n            { 0.898984, 0.420392, 0.363047 },\n            { 0.901807, 0.425087, 0.359688 },\n            { 0.904601, 0.429797, 0.356329 },\n            { 0.907365, 0.434524, 0.352970 },\n            { 0.910098, 0.439268, 0.349610 },\n            { 0.912800, 0.444029, 0.346251 },\n            { 0.915471, 0.448807, 0.342890 },\n            { 0.918109, 0.453603, 0.339529 },\n            { 0.920714, 0.458417, 0.336166 },\n            { 0.923287, 0.463251, 0.332801 },\n            { 0.925825, 0.468103, 0.329435 },\n            { 0.928329, 0.472975, 0.326067 },\n            { 0.930798, 0.477867, 0.322697 },\n            { 0.933232, 0.482780, 0.319325 },\n            { 0.935630, 0.487712, 0.315952 },\n            { 0.937990, 0.492667, 0.312575 },\n            { 0.940313, 0.497642, 0.309197 },\n            { 0.942598, 0.502639, 0.305816 },\n            { 0.944844, 0.507658, 0.302433 },\n            { 0.947051, 0.512699, 0.299049 },\n            { 0.949217, 0.517763, 0.295662 },\n            { 0.951344, 0.522850, 0.292275 },\n            { 0.953428, 0.527960, 0.288883 },\n            { 0.955470, 0.533093, 0.285490 },\n            { 0.957469, 0.538250, 0.282096 },\n            { 0.959424, 0.543431, 0.278701 },\n            { 0.961336, 0.548636, 0.275305 },\n            { 0.963203, 0.553865, 0.271909 },\n            { 0.965024, 0.559118, 0.268513 },\n            { 0.966798, 0.564396, 0.265118 },\n            { 0.968526, 0.569700, 0.261721 },\n            { 0.970205, 0.575028, 0.258325 },\n            { 0.971835, 0.580382, 0.254931 },\n            { 0.973416, 0.585761, 0.251540 },\n            { 0.974947, 0.591165, 0.248151 },\n            { 0.976428, 0.596595, 0.244767 },\n            { 0.977856, 0.602051, 0.241387 },\n            { 0.979233, 0.607532, 0.238013 },\n            { 0.980556, 0.613039, 0.234646 },\n            { 0.981826, 0.618572, 0.231287 },\n            { 0.983041, 0.624131, 0.227937 },\n            { 0.984199, 0.629718, 0.224595 },\n            { 0.985301, 0.635330, 0.221265 },\n            { 0.986345, 0.640969, 0.217948 },\n            { 0.987332, 0.646633, 0.214648 },\n            { 0.988260, 0.652325, 0.211364 },\n            { 0.989128, 0.658043, 0.208100 },\n            { 0.989935, 0.663787, 0.204859 },\n            { 0.990681, 0.669558, 0.201642 },\n            { 0.991365, 0.675355, 0.198453 },\n            { 0.991985, 0.681179, 0.195295 },\n            { 0.992541, 0.687030, 0.192170 },\n            { 0.993032, 0.692907, 0.189084 },\n            { 0.993456, 0.698810, 0.186041 },\n            { 0.993814, 0.704741, 0.183043 },\n            { 0.994103, 0.710698, 0.180097 },\n            { 0.994324, 0.716681, 0.177208 },\n            { 0.994474, 0.722691, 0.174381 },\n            { 0.994553, 0.728728, 0.171622 },\n            { 0.994561, 0.734791, 0.168938 },\n            { 0.994495, 0.740880, 0.166335 },\n            { 0.994355, 0.746995, 0.163821 },\n            { 0.994141, 0.753137, 0.161404 },\n            { 0.993851, 0.759304, 0.159092 },\n            { 0.993482, 0.765499, 0.156891 },\n            { 0.993033, 0.771720, 0.154808 },\n            { 0.992505, 0.777967, 0.152855 },\n            { 0.991897, 0.784239, 0.151042 },\n            { 0.991209, 0.790537, 0.149377 },\n            { 0.990439, 0.796859, 0.147870 },\n            { 0.989587, 0.803205, 0.146529 },\n            { 0.988648, 0.809579, 0.145357 },\n            { 0.987621, 0.815978, 0.144363 },\n            { 0.986509, 0.822401, 0.143557 },\n            { 0.985314, 0.828846, 0.142945 },\n            { 0.984031, 0.835315, 0.142528 },\n            { 0.982653, 0.841812, 0.142303 },\n            { 0.981190, 0.848329, 0.142279 },\n            { 0.979644, 0.854866, 0.142453 },\n            { 0.977995, 0.861432, 0.142808 },\n            { 0.976265, 0.868016, 0.143351 },\n            { 0.974443, 0.874622, 0.144061 },\n            { 0.972530, 0.881250, 0.144923 },\n            { 0.970533, 0.887896, 0.145919 },\n            { 0.968443, 0.894564, 0.147014 },\n            { 0.966271, 0.901249, 0.148180 },\n            { 0.964021, 0.907950, 0.149370 },\n            { 0.961681, 0.914672, 0.150520 },\n            { 0.959276, 0.921407, 0.151566 },\n            { 0.956808, 0.928152, 0.152409 },\n            { 0.954287, 0.934908, 0.152921 },\n            { 0.951726, 0.941671, 0.152925 },\n            { 0.949151, 0.948435, 0.152178 },\n            { 0.946602, 0.955190, 0.150328 },\n            { 0.944152, 0.961916, 0.146861 },\n            { 0.941896, 0.968590, 0.140956 },\n            { 0.940015, 0.975158, 0.131326 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetViridisColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.267004, 0.004874, 0.329415 },\n            { 0.268510, 0.009605, 0.335427 },\n            { 0.269944, 0.014625, 0.341379 },\n            { 0.271305, 0.019942, 0.347269 },\n            { 0.272594, 0.025563, 0.353093 },\n            { 0.273809, 0.031497, 0.358853 },\n            { 0.274952, 0.037752, 0.364543 },\n            { 0.276022, 0.044167, 0.370164 },\n            { 0.277018, 0.050344, 0.375715 },\n            { 0.277941, 0.056324, 0.381191 },\n            { 0.278791, 0.062145, 0.386592 },\n            { 0.279566, 0.067836, 0.391917 },\n            { 0.280267, 0.073417, 0.397163 },\n            { 0.280894, 0.078907, 0.402329 },\n            { 0.281446, 0.084320, 0.407414 },\n            { 0.281924, 0.089666, 0.412415 },\n            { 0.282327, 0.094955, 0.417331 },\n            { 0.282656, 0.100196, 0.422160 },\n            { 0.282910, 0.105393, 0.426902 },\n            { 0.283091, 0.110553, 0.431554 },\n            { 0.283197, 0.115680, 0.436115 },\n            { 0.283229, 0.120777, 0.440584 },\n            { 0.283187, 0.125848, 0.444960 },\n            { 0.283072, 0.130895, 0.449241 },\n            { 0.282884, 0.135920, 0.453427 },\n            { 0.282623, 0.140926, 0.457517 },\n            { 0.282290, 0.145912, 0.461510 },\n            { 0.281887, 0.150881, 0.465405 },\n            { 0.281412, 0.155834, 0.469201 },\n            { 0.280868, 0.160771, 0.472899 },\n            { 0.280255, 0.165693, 0.476498 },\n            { 0.279574, 0.170599, 0.479997 },\n            { 0.278826, 0.175490, 0.483397 },\n            { 0.278012, 0.180367, 0.486697 },\n            { 0.277134, 0.185228, 0.489898 },\n            { 0.276194, 0.190074, 0.493001 },\n            { 0.275191, 0.194905, 0.496005 },\n            { 0.274128, 0.199721, 0.498911 },\n            { 0.273006, 0.204520, 0.501721 },\n            { 0.271828, 0.209303, 0.504434 },\n            { 0.270595, 0.214069, 0.507052 },\n            { 0.269308, 0.218818, 0.509577 },\n            { 0.267968, 0.223549, 0.512008 },\n            { 0.266580, 0.228262, 0.514349 },\n            { 0.265145, 0.232956, 0.516599 },\n            { 0.263663, 0.237631, 0.518762 },\n            { 0.262138, 0.242286, 0.520837 },\n            { 0.260571, 0.246922, 0.522828 },\n            { 0.258965, 0.251537, 0.524736 },\n            { 0.257322, 0.256130, 0.526563 },\n            { 0.255645, 0.260703, 0.528312 },\n            { 0.253935, 0.265254, 0.529983 },\n            { 0.252194, 0.269783, 0.531579 },\n            { 0.250425, 0.274290, 0.533103 },\n            { 0.248629, 0.278775, 0.534556 },\n            { 0.246811, 0.283237, 0.535941 },\n            { 0.244972, 0.287675, 0.537260 },\n            { 0.243113, 0.292092, 0.538516 },\n            { 0.241237, 0.296485, 0.539709 },\n            { 0.239346, 0.300855, 0.540844 },\n            { 0.237441, 0.305202, 0.541921 },\n            { 0.235526, 0.309527, 0.542944 },\n            { 0.233603, 0.313828, 0.543914 },\n            { 0.231674, 0.318106, 0.544834 },\n            { 0.229739, 0.322361, 0.545706 },\n            { 0.227802, 0.326594, 0.546532 },\n            { 0.225863, 0.330805, 0.547314 },\n            { 0.223925, 0.334994, 0.548053 },\n            { 0.221989, 0.339161, 0.548752 },\n            { 0.220057, 0.343307, 0.549413 },\n            { 0.218130, 0.347432, 0.550038 },\n            { 0.216210, 0.351535, 0.550627 },\n            { 0.214298, 0.355619, 0.551184 },\n            { 0.212395, 0.359683, 0.551710 },\n            { 0.210503, 0.363727, 0.552206 },\n            { 0.208623, 0.367752, 0.552675 },\n            { 0.206756, 0.371758, 0.553117 },\n            { 0.204903, 0.375746, 0.553533 },\n            { 0.203063, 0.379716, 0.553925 },\n            { 0.201239, 0.383670, 0.554294 },\n            { 0.199430, 0.387607, 0.554642 },\n            { 0.197636, 0.391528, 0.554969 },\n            { 0.195860, 0.395433, 0.555276 },\n            { 0.194100, 0.399323, 0.555565 },\n            { 0.192357, 0.403199, 0.555836 },\n            { 0.190631, 0.407061, 0.556089 },\n            { 0.188923, 0.410910, 0.556326 },\n            { 0.187231, 0.414746, 0.556547 },\n            { 0.185556, 0.418570, 0.556753 },\n            { 0.183898, 0.422383, 0.556944 },\n            { 0.182256, 0.426184, 0.557120 },\n            { 0.180629, 0.429975, 0.557282 },\n            { 0.179019, 0.433756, 0.557430 },\n            { 0.177423, 0.437527, 0.557565 },\n            { 0.175841, 0.441290, 0.557685 },\n            { 0.174274, 0.445044, 0.557792 },\n            { 0.172719, 0.448791, 0.557885 },\n            { 0.171176, 0.452530, 0.557965 },\n            { 0.169646, 0.456262, 0.558030 },\n            { 0.168126, 0.459988, 0.558082 },\n            { 0.166617, 0.463708, 0.558119 },\n            { 0.165117, 0.467423, 0.558141 },\n            { 0.163625, 0.471133, 0.558148 },\n            { 0.162142, 0.474838, 0.558140 },\n            { 0.160665, 0.478540, 0.558115 },\n            { 0.159194, 0.482237, 0.558073 },\n            { 0.157729, 0.485932, 0.558013 },\n            { 0.156270, 0.489624, 0.557936 },\n            { 0.154815, 0.493313, 0.557840 },\n            { 0.153364, 0.497000, 0.557724 },\n            { 0.151918, 0.500685, 0.557587 },\n            { 0.150476, 0.504369, 0.557430 },\n            { 0.149039, 0.508051, 0.557250 },\n            { 0.147607, 0.511733, 0.557049 },\n            { 0.146180, 0.515413, 0.556823 },\n            { 0.144759, 0.519093, 0.556572 },\n            { 0.143343, 0.522773, 0.556295 },\n            { 0.141935, 0.526453, 0.555991 },\n            { 0.140536, 0.530132, 0.555659 },\n            { 0.139147, 0.533812, 0.555298 },\n            { 0.137770, 0.537492, 0.554906 },\n            { 0.136408, 0.541173, 0.554483 },\n            { 0.135066, 0.544853, 0.554029 },\n            { 0.133743, 0.548535, 0.553541 },\n            { 0.132444, 0.552216, 0.553018 },\n            { 0.131172, 0.555899, 0.552459 },\n            { 0.129933, 0.559582, 0.551864 },\n            { 0.128729, 0.563265, 0.551229 },\n            { 0.127568, 0.566949, 0.550556 },\n            { 0.126453, 0.570633, 0.549841 },\n            { 0.125394, 0.574318, 0.549086 },\n            { 0.124395, 0.578002, 0.548287 },\n            { 0.123463, 0.581687, 0.547445 },\n            { 0.122606, 0.585371, 0.546557 },\n            { 0.121831, 0.589055, 0.545623 },\n            { 0.121148, 0.592739, 0.544641 },\n            { 0.120565, 0.596422, 0.543611 },\n            { 0.120092, 0.600104, 0.542530 },\n            { 0.119738, 0.603785, 0.541400 },\n            { 0.119512, 0.607464, 0.540218 },\n            { 0.119423, 0.611141, 0.538982 },\n            { 0.119483, 0.614817, 0.537692 },\n            { 0.119699, 0.618490, 0.536347 },\n            { 0.120081, 0.622161, 0.534946 },\n            { 0.120638, 0.625828, 0.533488 },\n            { 0.121380, 0.629492, 0.531973 },\n            { 0.122312, 0.633153, 0.530398 },\n            { 0.123444, 0.636809, 0.528763 },\n            { 0.124780, 0.640461, 0.527068 },\n            { 0.126326, 0.644107, 0.525311 },\n            { 0.128087, 0.647749, 0.523491 },\n            { 0.130067, 0.651384, 0.521608 },\n            { 0.132268, 0.655014, 0.519661 },\n            { 0.134692, 0.658636, 0.517649 },\n            { 0.137339, 0.662252, 0.515571 },\n            { 0.140210, 0.665859, 0.513427 },\n            { 0.143303, 0.669459, 0.511215 },\n            { 0.146616, 0.673050, 0.508936 },\n            { 0.150148, 0.676631, 0.506589 },\n            { 0.153894, 0.680203, 0.504172 },\n            { 0.157851, 0.683765, 0.501686 },\n            { 0.162016, 0.687316, 0.499129 },\n            { 0.166383, 0.690856, 0.496502 },\n            { 0.170948, 0.694384, 0.493803 },\n            { 0.175707, 0.697900, 0.491033 },\n            { 0.180653, 0.701402, 0.488189 },\n            { 0.185783, 0.704891, 0.485273 },\n            { 0.191090, 0.708366, 0.482284 },\n            { 0.196571, 0.711827, 0.479221 },\n            { 0.202219, 0.715272, 0.476084 },\n            { 0.208030, 0.718701, 0.472873 },\n            { 0.214000, 0.722114, 0.469588 },\n            { 0.220124, 0.725509, 0.466226 },\n            { 0.226397, 0.728888, 0.462789 },\n            { 0.232815, 0.732247, 0.459277 },\n            { 0.239374, 0.735588, 0.455688 },\n            { 0.246070, 0.738910, 0.452024 },\n            { 0.252899, 0.742211, 0.448284 },\n            { 0.259857, 0.745492, 0.444467 },\n            { 0.266941, 0.748751, 0.440573 },\n            { 0.274149, 0.751988, 0.436601 },\n            { 0.281477, 0.755203, 0.432552 },\n            { 0.288921, 0.758394, 0.428426 },\n            { 0.296479, 0.761561, 0.424223 },\n            { 0.304148, 0.764704, 0.419943 },\n            { 0.311925, 0.767822, 0.415586 },\n            { 0.319809, 0.770914, 0.411152 },\n            { 0.327796, 0.773980, 0.406640 },\n            { 0.335885, 0.777018, 0.402049 },\n            { 0.344074, 0.780029, 0.397381 },\n            { 0.352360, 0.783011, 0.392636 },\n            { 0.360741, 0.785964, 0.387814 },\n            { 0.369214, 0.788888, 0.382914 },\n            { 0.377779, 0.791781, 0.377939 },\n            { 0.386433, 0.794644, 0.372886 },\n            { 0.395174, 0.797475, 0.367757 },\n            { 0.404001, 0.800275, 0.362552 },\n            { 0.412913, 0.803041, 0.357269 },\n            { 0.421908, 0.805774, 0.351910 },\n            { 0.430983, 0.808473, 0.346476 },\n            { 0.440137, 0.811138, 0.340967 },\n            { 0.449368, 0.813768, 0.335384 },\n            { 0.458674, 0.816363, 0.329727 },\n            { 0.468053, 0.818921, 0.323998 },\n            { 0.477504, 0.821444, 0.318195 },\n            { 0.487026, 0.823929, 0.312321 },\n            { 0.496615, 0.826376, 0.306377 },\n            { 0.506271, 0.828786, 0.300362 },\n            { 0.515992, 0.831158, 0.294279 },\n            { 0.525776, 0.833491, 0.288127 },\n            { 0.535621, 0.835785, 0.281908 },\n            { 0.545524, 0.838039, 0.275626 },\n            { 0.555484, 0.840254, 0.269281 },\n            { 0.565498, 0.842430, 0.262877 },\n            { 0.575563, 0.844566, 0.256415 },\n            { 0.585678, 0.846661, 0.249897 },\n            { 0.595839, 0.848717, 0.243329 },\n            { 0.606045, 0.850733, 0.236712 },\n            { 0.616293, 0.852709, 0.230052 },\n            { 0.626579, 0.854645, 0.223353 },\n            { 0.636902, 0.856542, 0.216620 },\n            { 0.647257, 0.858400, 0.209861 },\n            { 0.657642, 0.860219, 0.203082 },\n            { 0.668054, 0.861999, 0.196293 },\n            { 0.678489, 0.863742, 0.189503 },\n            { 0.688944, 0.865448, 0.182725 },\n            { 0.699415, 0.867117, 0.175971 },\n            { 0.709898, 0.868751, 0.169257 },\n            { 0.720391, 0.870350, 0.162603 },\n            { 0.730889, 0.871916, 0.156029 },\n            { 0.741388, 0.873449, 0.149561 },\n            { 0.751884, 0.874951, 0.143228 },\n            { 0.762373, 0.876424, 0.137064 },\n            { 0.772852, 0.877868, 0.131109 },\n            { 0.783315, 0.879285, 0.125405 },\n            { 0.793760, 0.880678, 0.120005 },\n            { 0.804182, 0.882046, 0.114965 },\n            { 0.814576, 0.883393, 0.110347 },\n            { 0.824940, 0.884720, 0.106217 },\n            { 0.835270, 0.886029, 0.102646 },\n            { 0.845561, 0.887322, 0.099702 },\n            { 0.855810, 0.888601, 0.097452 },\n            { 0.866013, 0.889868, 0.095953 },\n            { 0.876168, 0.891125, 0.095250 },\n            { 0.886271, 0.892374, 0.095374 },\n            { 0.896320, 0.893616, 0.096335 },\n            { 0.906311, 0.894855, 0.098125 },\n            { 0.916242, 0.896091, 0.100717 },\n            { 0.926106, 0.897330, 0.104071 },\n            { 0.935904, 0.898570, 0.108131 },\n            { 0.945636, 0.899815, 0.112838 },\n            { 0.955300, 0.901065, 0.118128 },\n            { 0.964894, 0.902323, 0.123941 },\n            { 0.974417, 0.903590, 0.130215 },\n            { 0.983868, 0.904867, 0.136897 },\n            { 0.993248, 0.906157, 0.143936 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetCividisColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.0000, 0.1262, 0.3015 },\n            { 0.0000, 0.1292, 0.3077 },\n            { 0.0000, 0.1321, 0.3142 },\n            { 0.0000, 0.1350, 0.3205 },\n            { 0.0000, 0.1379, 0.3269 },\n            { 0.0000, 0.1408, 0.3334 },\n            { 0.0000, 0.1437, 0.3400 },\n            { 0.0000, 0.1465, 0.3467 },\n            { 0.0000, 0.1492, 0.3537 },\n            { 0.0000, 0.1519, 0.3606 },\n            { 0.0000, 0.1546, 0.3676 },\n            { 0.0000, 0.1574, 0.3746 },\n            { 0.0000, 0.1601, 0.3817 },\n            { 0.0000, 0.1629, 0.3888 },\n            { 0.0000, 0.1657, 0.3960 },\n            { 0.0000, 0.1685, 0.4031 },\n            { 0.0000, 0.1714, 0.4102 },\n            { 0.0000, 0.1743, 0.4172 },\n            { 0.0000, 0.1773, 0.4241 },\n            { 0.0000, 0.1798, 0.4307 },\n            { 0.0000, 0.1817, 0.4347 },\n            { 0.0000, 0.1834, 0.4363 },\n            { 0.0000, 0.1852, 0.4368 },\n            { 0.0000, 0.1872, 0.4368 },\n            { 0.0000, 0.1901, 0.4365 },\n            { 0.0000, 0.1930, 0.4361 },\n            { 0.0000, 0.1958, 0.4356 },\n            { 0.0000, 0.1987, 0.4349 },\n            { 0.0000, 0.2015, 0.4343 },\n            { 0.0000, 0.2044, 0.4336 },\n            { 0.0000, 0.2073, 0.4329 },\n            { 0.0055, 0.2101, 0.4322 },\n            { 0.0236, 0.2130, 0.4314 },\n            { 0.0416, 0.2158, 0.4308 },\n            { 0.0576, 0.2187, 0.4301 },\n            { 0.0710, 0.2215, 0.4293 },\n            { 0.0827, 0.2244, 0.4287 },\n            { 0.0932, 0.2272, 0.4280 },\n            { 0.1030, 0.2300, 0.4274 },\n            { 0.1120, 0.2329, 0.4268 },\n            { 0.1204, 0.2357, 0.4262 },\n            { 0.1283, 0.2385, 0.4256 },\n            { 0.1359, 0.2414, 0.4251 },\n            { 0.1431, 0.2442, 0.4245 },\n            { 0.1500, 0.2470, 0.4241 },\n            { 0.1566, 0.2498, 0.4236 },\n            { 0.1630, 0.2526, 0.4232 },\n            { 0.1692, 0.2555, 0.4228 },\n            { 0.1752, 0.2583, 0.4224 },\n            { 0.1811, 0.2611, 0.4220 },\n            { 0.1868, 0.2639, 0.4217 },\n            { 0.1923, 0.2667, 0.4214 },\n            { 0.1977, 0.2695, 0.4212 },\n            { 0.2030, 0.2723, 0.4209 },\n            { 0.2082, 0.2751, 0.4207 },\n            { 0.2133, 0.2780, 0.4205 },\n            { 0.2183, 0.2808, 0.4204 },\n            { 0.2232, 0.2836, 0.4203 },\n            { 0.2281, 0.2864, 0.4202 },\n            { 0.2328, 0.2892, 0.4201 },\n            { 0.2375, 0.2920, 0.4200 },\n            { 0.2421, 0.2948, 0.4200 },\n            { 0.2466, 0.2976, 0.4200 },\n            { 0.2511, 0.3004, 0.4201 },\n            { 0.2556, 0.3032, 0.4201 },\n            { 0.2599, 0.3060, 0.4202 },\n            { 0.2643, 0.3088, 0.4203 },\n            { 0.2686, 0.3116, 0.4205 },\n            { 0.2728, 0.3144, 0.4206 },\n            { 0.2770, 0.3172, 0.4208 },\n            { 0.2811, 0.3200, 0.4210 },\n            { 0.2853, 0.3228, 0.4212 },\n            { 0.2894, 0.3256, 0.4215 },\n            { 0.2934, 0.3284, 0.4218 },\n            { 0.2974, 0.3312, 0.4221 },\n            { 0.3014, 0.3340, 0.4224 },\n            { 0.3054, 0.3368, 0.4227 },\n            { 0.3093, 0.3396, 0.4231 },\n            { 0.3132, 0.3424, 0.4236 },\n            { 0.3170, 0.3453, 0.4240 },\n            { 0.3209, 0.3481, 0.4244 },\n            { 0.3247, 0.3509, 0.4249 },\n            { 0.3285, 0.3537, 0.4254 },\n            { 0.3323, 0.3565, 0.4259 },\n            { 0.3361, 0.3593, 0.4264 },\n            { 0.3398, 0.3622, 0.4270 },\n            { 0.3435, 0.3650, 0.4276 },\n            { 0.3472, 0.3678, 0.4282 },\n            { 0.3509, 0.3706, 0.4288 },\n            { 0.3546, 0.3734, 0.4294 },\n            { 0.3582, 0.3763, 0.4302 },\n            { 0.3619, 0.3791, 0.4308 },\n            { 0.3655, 0.3819, 0.4316 },\n            { 0.3691, 0.3848, 0.4322 },\n            { 0.3727, 0.3876, 0.4331 },\n            { 0.3763, 0.3904, 0.4338 },\n            { 0.3798, 0.3933, 0.4346 },\n            { 0.3834, 0.3961, 0.4355 },\n            { 0.3869, 0.3990, 0.4364 },\n            { 0.3905, 0.4018, 0.4372 },\n            { 0.3940, 0.4047, 0.4381 },\n            { 0.3975, 0.4075, 0.4390 },\n            { 0.4010, 0.4104, 0.4400 },\n            { 0.4045, 0.4132, 0.4409 },\n            { 0.4080, 0.4161, 0.4419 },\n            { 0.4114, 0.4189, 0.4430 },\n            { 0.4149, 0.4218, 0.4440 },\n            { 0.4183, 0.4247, 0.4450 },\n            { 0.4218, 0.4275, 0.4462 },\n            { 0.4252, 0.4304, 0.4473 },\n            { 0.4286, 0.4333, 0.4485 },\n            { 0.4320, 0.4362, 0.4496 },\n            { 0.4354, 0.4390, 0.4508 },\n            { 0.4388, 0.4419, 0.4521 },\n            { 0.4422, 0.4448, 0.4534 },\n            { 0.4456, 0.4477, 0.4547 },\n            { 0.4489, 0.4506, 0.4561 },\n            { 0.4523, 0.4535, 0.4575 },\n            { 0.4556, 0.4564, 0.4589 },\n            { 0.4589, 0.4593, 0.4604 },\n            { 0.4622, 0.4622, 0.4620 },\n            { 0.4656, 0.4651, 0.4635 },\n            { 0.4689, 0.4680, 0.4650 },\n            { 0.4722, 0.4709, 0.4665 },\n            { 0.4756, 0.4738, 0.4679 },\n            { 0.4790, 0.4767, 0.4691 },\n            { 0.4825, 0.4797, 0.4701 },\n            { 0.4861, 0.4826, 0.4707 },\n            { 0.4897, 0.4856, 0.4714 },\n            { 0.4934, 0.4886, 0.4719 },\n            { 0.4971, 0.4915, 0.4723 },\n            { 0.5008, 0.4945, 0.4727 },\n            { 0.5045, 0.4975, 0.4730 },\n            { 0.5083, 0.5005, 0.4732 },\n            { 0.5121, 0.5035, 0.4734 },\n            { 0.5158, 0.5065, 0.4736 },\n            { 0.5196, 0.5095, 0.4737 },\n            { 0.5234, 0.5125, 0.4738 },\n            { 0.5272, 0.5155, 0.4739 },\n            { 0.5310, 0.5186, 0.4739 },\n            { 0.5349, 0.5216, 0.4738 },\n            { 0.5387, 0.5246, 0.4739 },\n            { 0.5425, 0.5277, 0.4738 },\n            { 0.5464, 0.5307, 0.4736 },\n            { 0.5502, 0.5338, 0.4735 },\n            { 0.5541, 0.5368, 0.4733 },\n            { 0.5579, 0.5399, 0.4732 },\n            { 0.5618, 0.5430, 0.4729 },\n            { 0.5657, 0.5461, 0.4727 },\n            { 0.5696, 0.5491, 0.4723 },\n            { 0.5735, 0.5522, 0.4720 },\n            { 0.5774, 0.5553, 0.4717 },\n            { 0.5813, 0.5584, 0.4714 },\n            { 0.5852, 0.5615, 0.4709 },\n            { 0.5892, 0.5646, 0.4705 },\n            { 0.5931, 0.5678, 0.4701 },\n            { 0.5970, 0.5709, 0.4696 },\n            { 0.6010, 0.5740, 0.4691 },\n            { 0.6050, 0.5772, 0.4685 },\n            { 0.6089, 0.5803, 0.4680 },\n            { 0.6129, 0.5835, 0.4673 },\n            { 0.6168, 0.5866, 0.4668 },\n            { 0.6208, 0.5898, 0.4662 },\n            { 0.6248, 0.5929, 0.4655 },\n            { 0.6288, 0.5961, 0.4649 },\n            { 0.6328, 0.5993, 0.4641 },\n            { 0.6368, 0.6025, 0.4632 },\n            { 0.6408, 0.6057, 0.4625 },\n            { 0.6449, 0.6089, 0.4617 },\n            { 0.6489, 0.6121, 0.4609 },\n            { 0.6529, 0.6153, 0.4600 },\n            { 0.6570, 0.6185, 0.4591 },\n            { 0.6610, 0.6217, 0.4583 },\n            { 0.6651, 0.6250, 0.4573 },\n            { 0.6691, 0.6282, 0.4562 },\n            { 0.6732, 0.6315, 0.4553 },\n            { 0.6773, 0.6347, 0.4543 },\n            { 0.6813, 0.6380, 0.4532 },\n            { 0.6854, 0.6412, 0.4521 },\n            { 0.6895, 0.6445, 0.4511 },\n            { 0.6936, 0.6478, 0.4499 },\n            { 0.6977, 0.6511, 0.4487 },\n            { 0.7018, 0.6544, 0.4475 },\n            { 0.7060, 0.6577, 0.4463 },\n            { 0.7101, 0.6610, 0.4450 },\n            { 0.7142, 0.6643, 0.4437 },\n            { 0.7184, 0.6676, 0.4424 },\n            { 0.7225, 0.6710, 0.4409 },\n            { 0.7267, 0.6743, 0.4396 },\n            { 0.7308, 0.6776, 0.4382 },\n            { 0.7350, 0.6810, 0.4368 },\n            { 0.7392, 0.6844, 0.4352 },\n            { 0.7434, 0.6877, 0.4338 },\n            { 0.7476, 0.6911, 0.4322 },\n            { 0.7518, 0.6945, 0.4307 },\n            { 0.7560, 0.6979, 0.4290 },\n            { 0.7602, 0.7013, 0.4273 },\n            { 0.7644, 0.7047, 0.4258 },\n            { 0.7686, 0.7081, 0.4241 },\n            { 0.7729, 0.7115, 0.4223 },\n            { 0.7771, 0.7150, 0.4205 },\n            { 0.7814, 0.7184, 0.4188 },\n            { 0.7856, 0.7218, 0.4168 },\n            { 0.7899, 0.7253, 0.4150 },\n            { 0.7942, 0.7288, 0.4129 },\n            { 0.7985, 0.7322, 0.4111 },\n            { 0.8027, 0.7357, 0.4090 },\n            { 0.8070, 0.7392, 0.4070 },\n            { 0.8114, 0.7427, 0.4049 },\n            { 0.8157, 0.7462, 0.4028 },\n            { 0.8200, 0.7497, 0.4007 },\n            { 0.8243, 0.7532, 0.3984 },\n            { 0.8287, 0.7568, 0.3961 },\n            { 0.8330, 0.7603, 0.3938 },\n            { 0.8374, 0.7639, 0.3915 },\n            { 0.8417, 0.7674, 0.3892 },\n            { 0.8461, 0.7710, 0.3869 },\n            { 0.8505, 0.7745, 0.3843 },\n            { 0.8548, 0.7781, 0.3818 },\n            { 0.8592, 0.7817, 0.3793 },\n            { 0.8636, 0.7853, 0.3766 },\n            { 0.8681, 0.7889, 0.3739 },\n            { 0.8725, 0.7926, 0.3712 },\n            { 0.8769, 0.7962, 0.3684 },\n            { 0.8813, 0.7998, 0.3657 },\n            { 0.8858, 0.8035, 0.3627 },\n            { 0.8902, 0.8071, 0.3599 },\n            { 0.8947, 0.8108, 0.3569 },\n            { 0.8992, 0.8145, 0.3538 },\n            { 0.9037, 0.8182, 0.3507 },\n            { 0.9082, 0.8219, 0.3474 },\n            { 0.9127, 0.8256, 0.3442 },\n            { 0.9172, 0.8293, 0.3409 },\n            { 0.9217, 0.8330, 0.3374 },\n            { 0.9262, 0.8367, 0.3340 },\n            { 0.9308, 0.8405, 0.3306 },\n            { 0.9353, 0.8442, 0.3268 },\n            { 0.9399, 0.8480, 0.3232 },\n            { 0.9444, 0.8518, 0.3195 },\n            { 0.9490, 0.8556, 0.3155 },\n            { 0.9536, 0.8593, 0.3116 },\n            { 0.9582, 0.8632, 0.3076 },\n            { 0.9628, 0.8670, 0.3034 },\n            { 0.9674, 0.8708, 0.2990 },\n            { 0.9721, 0.8746, 0.2947 },\n            { 0.9767, 0.8785, 0.2901 },\n            { 0.9814, 0.8823, 0.2856 },\n            { 0.9860, 0.8862, 0.2807 },\n            { 0.9907, 0.8901, 0.2759 },\n            { 0.9954, 0.8940, 0.2708 },\n            { 1.0000, 0.8979, 0.2655 },\n            { 1.0000, 0.9018, 0.2600 },\n            { 1.0000, 0.9057, 0.2593 },\n            { 1.0000, 0.9094, 0.2634 },\n            { 1.0000, 0.9131, 0.2680 },\n            { 1.0000, 0.9169, 0.2731 }\n        };\n\n        return data[static_cast<size_t>(std::round(x * 255.0))];\n    }\n\n    inline Color GetGithubColor(double x)\n    {\n        x = std::max(0.0, std::min(1.0, x));\n\n        constexpr Color data[] =\n        {\n            { 0.933333, 0.933333, 0.933333 },\n            { 0.776470, 0.894117, 0.545098 },\n            { 0.482352, 0.788235, 0.435294 },\n            { 0.137254, 0.603921, 0.231372 },\n            { 0.098039, 0.380392, 0.152941 }\n        };\n\n        const double a  = x * ((sizeof(data) / sizeof(Color)) - 1);\n        const double t  = a - std::floor(a);\n        const Color  c0 = data[static_cast<size_t>(std::floor(a))];\n        const Color  c1 = data[static_cast<size_t>(std::ceil (a))];\n\n        return (1.0 - t) * c0 + t * c1;\n    }\n\n#if defined(TINYCOLORMAP_WITH_QT5) and defined(TINYCOLORMAP_WITH_EIGEN)\n    inline QImage CreateMatrixVisualization(const Eigen::MatrixXd& matrix)\n    {\n        const int w = matrix.cols();\n        const int h = matrix.rows();\n        const double max_coeff = matrix.maxCoeff();\n        const double min_coeff = matrix.minCoeff();\n        const Eigen::MatrixXd normalized = (1.0 / (max_coeff - min_coeff)) * (matrix - Eigen::MatrixXd::Constant(h, w, min_coeff));\n\n        QImage image(w, h, QImage::Format_ARGB32);\n        for (int x = 0; x < w; ++ x)\n        {\n            for (int y = 0; y < h; ++ y)\n            {\n                const QColor color = tinycolormap::GetColor(normalized(y, x)).ConvertToQColor();\n                image.setPixel(x, y, color.rgb());\n            }\n        }\n\n        return image;\n    }\n\n    inline void ExportMatrixVisualization(const Eigen::MatrixXd& matrix, const std::string& path)\n    {\n        CreateMatrixVisualization(matrix).save(QString::fromStdString(path));\n    }\n#endif\n}\n\n\n#endif /* eidos_tinycolormap_h */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_token.cpp",
    "content": "//\n//  eidos_token.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 7/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_token.h\"\n\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosTokenType p_token_type)\n{\n\tswitch (p_token_type)\n\t{\n\t\tcase EidosTokenType::kTokenNone:\t\t\t\tp_outstream << \"NO_TOKEN\";\t\tbreak;\n\t\tcase EidosTokenType::kTokenBad:\t\t\t\t\tp_outstream << \"BAD_TOKEN\";\t\tbreak;\n\t\tcase EidosTokenType::kTokenEOF:\t\t\t\t\tp_outstream << \"EOF\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenWhitespace:\t\t\tp_outstream << \"WS\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenSemicolon:\t\t\tp_outstream << \";\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenColon:\t\t\t\tp_outstream << \":\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenComma:\t\t\t\tp_outstream << \",\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLBrace:\t\t\t\tp_outstream << \"{\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenRBrace:\t\t\t\tp_outstream << \"}\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLParen:\t\t\t\tp_outstream << \"(\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenRParen:\t\t\t\tp_outstream << \")\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLBracket:\t\t\tp_outstream << \"[\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenRBracket:\t\t\tp_outstream << \"]\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenDot:\t\t\t\t\tp_outstream << \".\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenPlus:\t\t\t\tp_outstream << \"+\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMinus:\t\t\t\tp_outstream << \"-\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMod:\t\t\t\t\tp_outstream << \"%\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenMult:\t\t\t\tp_outstream << \"*\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenExp:\t\t\t\t\tp_outstream << \"^\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenAnd:\t\t\t\t\tp_outstream << \"&\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenOr:\t\t\t\t\tp_outstream << \"|\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenDiv:\t\t\t\t\tp_outstream << \"/\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenConditional:\t\t\tp_outstream << \"?\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenComment:\t\t\t\tp_outstream << \"COMMENT\";\t\tbreak;\n\t\tcase EidosTokenType::kTokenCommentLong:\t\t\tp_outstream << \"COMMENT_LONG\";\tbreak;\n\t\tcase EidosTokenType::kTokenAssign:\t\t\t\tp_outstream << \"=\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenAssign_R:\t\t\tp_outstream << \"<-\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenEq:\t\t\t\t\tp_outstream << \"==\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLt:\t\t\t\t\tp_outstream << \"<\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenLtEq:\t\t\t\tp_outstream << \"<=\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenGt:\t\t\t\t\tp_outstream << \">\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenGtEq:\t\t\t\tp_outstream << \">=\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNot:\t\t\t\t\tp_outstream << \"!\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNotEq:\t\t\t\tp_outstream << \"!=\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenSingleton:\t\t\tp_outstream << \"$\";\t\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenNumber:\t\t\t\tp_outstream << \"NUMBER\";\t\tbreak;\n\t\tcase EidosTokenType::kTokenString:\t\t\t\tp_outstream << \"STRING\";\t\tbreak;\n\t\tcase EidosTokenType::kTokenIdentifier:\t\t\tp_outstream << \"IDENTIFIER\";\tbreak;\n\t\tcase EidosTokenType::kTokenIf:\t\t\t\t\tp_outstream << gEidosStr_if;\t\tbreak;\n\t\tcase EidosTokenType::kTokenElse:\t\t\t\tp_outstream << gEidosStr_else;\t\tbreak;\n\t\tcase EidosTokenType::kTokenDo:\t\t\t\t\tp_outstream << gEidosStr_do;\t\tbreak;\n\t\tcase EidosTokenType::kTokenWhile:\t\t\t\tp_outstream << gEidosStr_while;\t\tbreak;\n\t\tcase EidosTokenType::kTokenFor:\t\t\t\t\tp_outstream << gEidosStr_for;\t\tbreak;\n\t\tcase EidosTokenType::kTokenIn:\t\t\t\t\tp_outstream << gEidosStr_in;\t\tbreak;\n\t\tcase EidosTokenType::kTokenNext:\t\t\t\tp_outstream << gEidosStr_next;\t\tbreak;\n\t\tcase EidosTokenType::kTokenBreak:\t\t\t\tp_outstream << gEidosStr_break;\t\tbreak;\n\t\tcase EidosTokenType::kTokenReturn:\t\t\t\tp_outstream << gEidosStr_return;\tbreak;\n\t\tcase EidosTokenType::kTokenFunction:\t\t\tp_outstream << gEidosStr_function;\tbreak;\n\t\t\t\n\t\tcase EidosTokenType::kTokenInterpreterBlock:\tp_outstream << \"$>\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenContextFile:\t\t\tp_outstream << \"###\";\t\t\tbreak;\n\t\tcase EidosTokenType::kTokenContextEidosBlock:\tp_outstream << \"#>\";\t\t\tbreak;\n\t\tcase EidosTokenType::kFirstIdentifierLikeToken:\tp_outstream << \"???\";\t\t\tbreak;\n\t}\n\t\n\treturn p_outstream;\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosToken &p_token)\n{\n\t// print strings, identifiers, numbers, and keywords with identifying marks; apart from that, print tokens as is\n\tif (p_token.token_type_ == EidosTokenType::kTokenString)\n\t\tp_outstream << \"\\\"\" << p_token.token_string_ << \"\\\"\";\n\telse if (p_token.token_type_ == EidosTokenType::kTokenIdentifier)\n\t\tp_outstream << \"@\" << p_token.token_string_;\n\telse if (p_token.token_type_ == EidosTokenType::kTokenNumber)\n\t\tp_outstream << \"#\" << p_token.token_string_;\n\telse if (p_token.token_type_ > EidosTokenType::kFirstIdentifierLikeToken)\n\t\tp_outstream << \"<\" << p_token.token_string_ << \">\";\t// <> delimiters help distinguish keywords from identifiers\n\telse\n\t\tp_outstream << p_token.token_type_;\n\t\n\treturn p_outstream;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_token.h",
    "content": "//\n//  eidos_token.h\n//  Eidos\n//\n//  Created by Ben Haller on 7/27/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef __Eidos__eidos_token__\n#define __Eidos__eidos_token__\n\n#include <stdio.h>\n\n#include <string>\n#include <ostream>\n\n#include \"eidos_globals.h\"\n\n\n// An enumeration for all token types, whether real or virtual\nenum class EidosTokenType : int16_t {\n\tkTokenNone = 0,\t\t//\t\t\tno token; this type should not be in the final token stream\n\tkTokenBad,\t\t\t//\t\t\tbad token; produced if Tokenize() is instructed not to raise\n\tkTokenEOF,\t\t\t//\t\t\tend of file; an EOF token is produced explicitly\n\tkTokenWhitespace,\t//\t\t\tspaces, tabs, newlines\n\t\n\tkTokenSemicolon,\t// ;\t\tstatement terminator\n\tkTokenColon,\t\t// :\t\trange operator, as in R\n\tkTokenComma,\t\t// ,\t\tpresently used for separating function parameters only\n\tkTokenLBrace,\t\t// {\t\tblock delimiter\n\tkTokenRBrace,\t\t// }\t\tblock delimiter\n\tkTokenLParen,\t\t// (\t\tsubexpression delimiter (also used in type specifiers)\n\tkTokenRParen,\t\t// )\t\tsubexpression delimiter\n\tkTokenLBracket,\t\t// [\t\tsubset operator\n\tkTokenRBracket,\t\t// ]\t\tsubset operator\n\tkTokenDot,\t\t\t// .\t\tmember operator\n\tkTokenPlus,\t\t\t// +\t\taddition operator (also used in type specifiers)\n\tkTokenMinus,\t\t// -\t\tsubtraction operator (unary or binary)\n\tkTokenMod,\t\t\t// %\t\tmodulo operator\n\tkTokenMult,\t\t\t// *\t\tmultiplication operator (also used in type specifiers)\n\tkTokenExp,\t\t\t// ^\t\texponentiation operator\n\tkTokenAnd,\t\t\t// &\t\tboolean AND\n\tkTokenOr,\t\t\t// |\t\tboolean OR\n\tkTokenDiv,\t\t\t// /\t\tdivision operator\n\tkTokenConditional,\t// ?\t\tternary conditional, with 'else'\n\t\n\tkTokenComment,\t\t// //\t\tcomment\n\tkTokenCommentLong,\t// /*\t\tcomment\n\tkTokenAssign,\t\t// =\t\tassignment\n\tkTokenAssign_R,\t\t// <-\t\tassignment in the R style, which is an illegal token in Eidos to avoid errors\n\tkTokenEq,\t\t\t// ==\t\tequality test\n\tkTokenLt,\t\t\t// <\t\tless than test (also used in type specifiers)\n\tkTokenLtEq,\t\t\t// <=\t\tless than or equals test\n\tkTokenGt,\t\t\t// >\t\tgreater than test (also used in type specifiers)\n\tkTokenGtEq,\t\t\t// >=\t\tgreater than or equals test\n\tkTokenNot,\t\t\t// !\t\tboolean NOT\n\tkTokenNotEq,\t\t// !=\t\tnot equals test\n\t\n\tkTokenSingleton,\t// $\t\tused to indicate a singleton type in type-specifiers\n\t\n\tkTokenNumber,\t\t//\t\t\tthere is a single numeric token type for both ints and floats, for now at least\n\tkTokenString,\t\t//\t\t\tstring literals are bounded by double quotes only, and recognize some escapes\n\tkTokenIdentifier,\t//\t\t\tall valid identifiers that are not keywords or operators\n\t\n\t// ----- VIRTUAL TOKENS; THESE WILL HAVE A STRING OF \"\" AND A LENGTH OF 0\n\t\n\tkTokenInterpreterBlock,\t\t\t// a block of statements executed as a unit in the interpreter\n\t\n\t// these virtual token types are not used by Eidos itself; they are provided as a convenience for\n\t// Contexts that embed Eidos within larger script files in a Context-defined format\n\t\n\tkTokenContextFile,\t\t\t\t// an Eidos-based input file containing zero or more Eidos blocks in a Context-defined format\n\tkTokenContextEidosBlock,\t\t// an Eidos-based script block with additional tokens in a Context-defined format\n\t\n\t// ----- ALL TOKENS AFTER THIS POINT SHOULD BE KEYWORDS MATCHED BY kTokenIdentifier\n\t\n\tkFirstIdentifierLikeToken,\n\tkTokenIf,\t\t\t// if\t\tconditional\n\tkTokenElse,\t\t\t// else\t\tconditional (and ternary conditional)\n\tkTokenDo,\t\t\t// do\t\tloop while condition true\n\tkTokenWhile,\t\t// while\tloop while condition true\n\tkTokenFor,\t\t\t// for\t\tloop over set\n\tkTokenIn,\t\t\t// in\t\tloop over set\n\tkTokenNext,\t\t\t// next\t\tloop jump to end\n\tkTokenBreak,\t\t// break\tloop jump to completion\n\tkTokenReturn,\t\t// return\treturn a value from the enclosing block\n\tkTokenFunction,\t\t// function\tdefine a user-defined function\n};\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosTokenType p_token_type);\n\n\n// A class representing a single token read from a script string\nclass EidosToken\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\npublic:\n\t\n\tconst std::string token_string_;\t\t\t// extracted string object for the token\n\tconst EidosTokenType token_type_;\t\t\t// the type of the token; one of the enumeration above\n\tconst int32_t token_start_;\t\t\t\t\t// character position within script_string_\n\tconst int32_t token_end_;\t\t\t\t\t// character position within script_string_\n\t\n\t// These are only used in the GUI environment, where we need token positions in terms of NSString's character indices.\n\t// They are calculated in all compile environments, though, since the overhead is small.\n\tconst int32_t token_UTF16_start_;\t\t\t// the same as token_start_ but in UTF-16 code units, as NSString uses\n\tconst int32_t token_UTF16_end_;\t\t\t\t// the same as token_end_ but in UTF-16 code units, as NSString uses\n\t\n\t// This is presently used only for debug points in SLiMgui, but may prove useful in some other contexts.\n\t// It keeps the line position of the token within the full user script string, or -1 if this token does not live\n\t// in the user's script string.  Note that this may not correspond to lines in the owning EidosScript, if that\n\t// EidosScript was constructed with non-zero base line number (i.e., represents a snippet from the full script).\n\tconst int32_t token_line_;\n\t\n\tEidosToken(const EidosToken&) = default;\t\t\t\t// default copy-construction, for std::vector\n\tEidosToken& operator=(const EidosToken&) = delete;\t\t// no copying\n\tEidosToken(void) = delete;\t\t\t\t\t\t\t\t// no null construction\n\t\n\tinline EidosToken(EidosTokenType p_token_type, const std::string &p_token_string, int32_t p_token_start, int32_t p_token_end, int32_t p_token_UTF16_start, int32_t p_token_UTF16_end, int32_t p_token_line) :\n\ttoken_string_(p_token_string), token_type_(p_token_type), token_start_(p_token_start), token_end_(p_token_end), token_UTF16_start_(p_token_UTF16_start), token_UTF16_end_(p_token_UTF16_end), token_line_(p_token_line)\n\t{\n\t}\n};\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosToken &p_token);\n\n\n// Setting the error position; call just before you throw, or better, pass the token to EidosTerminate()\ninline __attribute__((always_inline)) EidosErrorPosition PushErrorPositionFromToken(const EidosToken *p_naughty_token_)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"PushErrorPositionFromToken(): gEidosErrorContext change\");\n\t\n\tEidosErrorPosition old_position = gEidosErrorContext.errorPosition;\n\t\n\tgEidosErrorContext.errorPosition.characterStartOfError = p_naughty_token_->token_start_;\n\tgEidosErrorContext.errorPosition.characterEndOfError = p_naughty_token_->token_end_;\n\tgEidosErrorContext.errorPosition.characterStartOfErrorUTF16 = p_naughty_token_->token_UTF16_start_;\n\tgEidosErrorContext.errorPosition.characterEndOfErrorUTF16 = p_naughty_token_->token_UTF16_end_;\n\t\n\treturn old_position;\n}\n\n\n#endif /* defined(__Eidos__eidos_token__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_type_interpreter.cpp",
    "content": "//\n//  eidos_type_interpreter.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 5/8/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_type_interpreter.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n\n#include <sstream>\n#include <string>\n#include <vector>\n#include <algorithm>\n\n\n//\n//\tEidosTypeInterpreter\n//\n#pragma mark -\n#pragma mark EidosTypeInterpreter\n#pragma mark -\n\nEidosTypeInterpreter::EidosTypeInterpreter(const EidosScript &p_script, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types)\n: root_node_(p_script.AST()), global_symbols_(&p_symbols), function_map_(p_functions), call_type_map_(p_call_types)\n{\n}\n\nEidosTypeInterpreter::EidosTypeInterpreter(const EidosASTNode *p_root_node_, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types)\n: root_node_(p_root_node_), global_symbols_(&p_symbols), function_map_(p_functions), call_type_map_(p_call_types)\n{\n}\n\nEidosTypeInterpreter::~EidosTypeInterpreter(void)\n{\n}\n\n// the starting point for script blocks in Eidos, which do not require braces; this is not really a \"block\" but a series of\n// independent statements grouped only by virtue of having been executed together as a unit in the interpreter\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluateInterpreterBlock()\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tfor (EidosASTNode *child_node : root_node_->children_)\n\t\tresult_type = TypeEvaluateNode(child_node);\n\t\n\treturn result_type;\n}\n\n// this is a front end for TypeEvaluateInterpreterBlock() that supports autocompletion of argument names in functions and\n// method calls; it just needs to know the position of the end of the script string (where completion is occurring)\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluateInterpreterBlock_AddArgumentCompletions(std::vector<std::string> *p_argument_completions, size_t p_script_length)\n{\n\targument_completions_ = p_argument_completions;\n\tscript_length_ = p_script_length;\n\t\n\tEidosTypeSpecifier ret = TypeEvaluateInterpreterBlock();\n\t\n\targument_completions_ = nullptr;\n\tscript_length_ = 0;\n\t\n\treturn ret;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluateNode(const EidosASTNode *p_node)\n{\n\tif (p_node)\n\t{\n\t\tswitch (p_node->token_->token_type_)\n\t\t{\n\t\t\tcase EidosTokenType::kTokenBad:\t\t\treturn EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\t\tcase EidosTokenType::kTokenSemicolon:\treturn TypeEvaluate_NullStatement(p_node);\n\t\t\tcase EidosTokenType::kTokenColon:\t\treturn TypeEvaluate_RangeExpr(p_node);\n\t\t\tcase EidosTokenType::kTokenLBrace:\t\treturn TypeEvaluate_CompoundStatement(p_node);\n\t\t\tcase EidosTokenType::kTokenLParen:\t\treturn TypeEvaluate_Call(p_node);\n\t\t\tcase EidosTokenType::kTokenLBracket:\treturn TypeEvaluate_Subset(p_node);\n\t\t\tcase EidosTokenType::kTokenDot:\t\t\treturn TypeEvaluate_MemberRef(p_node);\n\t\t\tcase EidosTokenType::kTokenPlus:\t\treturn TypeEvaluate_Plus(p_node);\n\t\t\tcase EidosTokenType::kTokenMinus:\t\treturn TypeEvaluate_Minus(p_node);\n\t\t\tcase EidosTokenType::kTokenMod:\t\t\treturn TypeEvaluate_Mod(p_node);\n\t\t\tcase EidosTokenType::kTokenMult:\t\treturn TypeEvaluate_Mult(p_node);\n\t\t\tcase EidosTokenType::kTokenExp:\t\t\treturn TypeEvaluate_Exp(p_node);\n\t\t\tcase EidosTokenType::kTokenAnd:\t\t\treturn TypeEvaluate_And(p_node);\n\t\t\tcase EidosTokenType::kTokenOr:\t\t\treturn TypeEvaluate_Or(p_node);\n\t\t\tcase EidosTokenType::kTokenDiv:\t\t\treturn TypeEvaluate_Div(p_node);\n\t\t\tcase EidosTokenType::kTokenConditional:\treturn TypeEvaluate_Conditional(p_node);\n\t\t\tcase EidosTokenType::kTokenAssign:\t\treturn TypeEvaluate_Assign(p_node);\n\t\t\tcase EidosTokenType::kTokenAssign_R:\treturn TypeEvaluate_Assign_R(p_node);\n\t\t\tcase EidosTokenType::kTokenEq:\t\t\treturn TypeEvaluate_Eq(p_node);\n\t\t\tcase EidosTokenType::kTokenLt:\t\t\treturn TypeEvaluate_Lt(p_node);\n\t\t\tcase EidosTokenType::kTokenLtEq:\t\treturn TypeEvaluate_LtEq(p_node);\n\t\t\tcase EidosTokenType::kTokenGt:\t\t\treturn TypeEvaluate_Gt(p_node);\n\t\t\tcase EidosTokenType::kTokenGtEq:\t\treturn TypeEvaluate_GtEq(p_node);\n\t\t\tcase EidosTokenType::kTokenNot:\t\t\treturn TypeEvaluate_Not(p_node);\n\t\t\tcase EidosTokenType::kTokenNotEq:\t\treturn TypeEvaluate_NotEq(p_node);\n\t\t\tcase EidosTokenType::kTokenNumber:\t\treturn TypeEvaluate_Number(p_node);\n\t\t\tcase EidosTokenType::kTokenString:\t\treturn TypeEvaluate_String(p_node);\n\t\t\tcase EidosTokenType::kTokenIdentifier:\treturn TypeEvaluate_Identifier(p_node);\n\t\t\tcase EidosTokenType::kTokenIf:\t\t\treturn TypeEvaluate_If(p_node);\n\t\t\tcase EidosTokenType::kTokenDo:\t\t\treturn TypeEvaluate_Do(p_node);\n\t\t\tcase EidosTokenType::kTokenWhile:\t\treturn TypeEvaluate_While(p_node);\n\t\t\tcase EidosTokenType::kTokenFor:\t\t\treturn TypeEvaluate_For(p_node);\n\t\t\tcase EidosTokenType::kTokenNext:\t\treturn TypeEvaluate_Next(p_node);\n\t\t\tcase EidosTokenType::kTokenBreak:\t\treturn TypeEvaluate_Break(p_node);\n\t\t\tcase EidosTokenType::kTokenReturn:\t\treturn TypeEvaluate_Return(p_node);\n\t\t\tcase EidosTokenType::kTokenFunction:\treturn TypeEvaluate_FunctionDecl(p_node);\n\t\t\tdefault:\n\t\t\t\tstd::cout << \"ERROR (EidosTypeInterpreter::TypeEvaluateNode): unexpected node token type \" << p_node->token_->token_type_ << \".\" << EidosTerminate(p_node->token_);\n\t\t}\n\t}\n\t\n\treturn EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_NullStatement(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\treturn EidosTypeSpecifier{kEidosValueMaskNULL, nullptr};\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_CompoundStatement(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNULL, nullptr};\n\t\n\tfor (EidosASTNode *child_node : p_node->children_)\n\t\tresult_type = TypeEvaluateNode(child_node);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_RangeExpr(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\tconst EidosASTNode *child0 = p_node->children_[0];\n\t\tconst EidosASTNode *child1 = p_node->children_[1];\n\t\t\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(child0);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(child1);\n\t\t\n\t\t// If both operands are definitely integer, not float, then the return type is integer.  Otherwise,\n\t\t// if both are numeric then the return type is guessed to be float.  Otherwise, none.\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 && !float1) && (integer2 && !float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if ((!integer1 && float1) || (!integer2 && float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\telse if ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::_TypeEvaluate_FunctionCall_Internal(std::string const &p_function_name, const EidosFunctionSignature *p_function_signature, const std::vector<EidosASTNode *> &p_arguments)\n{\n#pragma unused(p_function_name)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\tint argument_count = (int)p_arguments.size();\n\tstd::vector<EidosTypeSpecifier> argument_types;\n\t\n\t// BCH 31 May 2018: We used to not bother doing type-evaluation on arguments, except for the specific cases below where\n\t// it influences the return type of a function/method, since such evaluation was unlikely to have side effects important\n\t// for type-evaluation (such as defining new symbols).  Now, however, type-evaluation can define completion symbols for\n\t// the named arguments of a function/method in argument_completions_ ; see _ProcessArgumentListTypes().  So that this\n\t// works even doing completion inside nested function/method calls, we have to descend into each argument.  This also\n\t// makes it so that any other type-evaluation side effects of arguments will occur correctly; it was always a bit of\n\t// an assumption that no such side effects would exist.  Note that TypeEvaluateNode() is safe to call with nullptr,\n\t// which is important since p_arguments can contain nullptr for missing/bad arguments.\n\targument_types.reserve(argument_count);\n\t\n\tfor (int argument_index = 0; argument_index < argument_count; ++argument_index)\n\t\targument_types.emplace_back(TypeEvaluateNode(p_arguments[argument_index]));\n\t\n\tif (p_function_signature)\n\t{\n\t\t// Look up the result type from the function signature, if there is one\n\t\tresult_type.type_mask = p_function_signature->return_mask_;\n\t\tresult_type.object_class = p_function_signature->return_class_;\n\t\t\n\t\t// We don't call out to functions, but we do have special knowledge of the side effects of built-in Eidos functions.\n\t\t// In figuring this stuff out, we need to be careful about the fact that the p_arguments vector can contain nullptr\n\t\t// values if there were missing arguments, etc.; we try to be error-tolerant, so we allow cases that would raise\n\t\t// in EidosInterpreter.\n\t\tEidosInternalFunctionPtr function_ptr = p_function_signature->internal_function_;\n\t\t\n\t\tif (((function_ptr == &Eidos_ExecuteFunction_defineConstant) || (function_ptr == &Eidos_ExecuteFunction_defineGlobal)) && (argument_count == 2))\n\t\t{\n\t\t\t// We know that defineConstant() and defineGlobal() have the side effect of adding a new symbol,\n\t\t\t// and we want to reflect that in our type table so that defined constants are always available.\n\t\t\tif (p_arguments[0])\n\t\t\t{\n\t\t\t\tif (p_arguments[0]->token_->token_type_ == EidosTokenType::kTokenString)\n\t\t\t\t{\n\t\t\t\t\tconst std::string &constant_name = p_arguments[0]->token_->token_string_;\n\t\t\t\t\tEidosGlobalStringID constant_id = EidosStringRegistry::GlobalStringIDForString(constant_name);\n\t\t\t\t\tEidosTypeSpecifier &constant_type = argument_types[1];\n\t\t\t\t\t\n\t\t\t\t\tglobal_symbols_->SetTypeForSymbol(constant_id, constant_type);\n\t\t\t\t\t\n\t\t\t\t\t// When a global constant or variable is defined, we want to record it not only in our local\n\t\t\t\t\t// scope (confusingly named global_symbols_), but also in the global scope (external_symbols_).\n\t\t\t\t\t// We never consult external_symbols_ at all; we just tell it about global definitions.\n\t\t\t\t\tif (external_type_table_)\n\t\t\t\t\t\texternal_type_table_->SetTypeForSymbol(constant_id, constant_type);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ((argument_count >= 1) && ((function_ptr == &Eidos_ExecuteFunction_rep) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_repEach) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_rev) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_sample) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_sortBy) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_unique) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_setUnion) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_setIntersection) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_setDifference) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_setSymmetricDifference) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_array) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_cbind) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_matrix) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_matrixMult) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_rbind) ||\n\t\t\t\t\t\t\t\t\t\t   (function_ptr == &Eidos_ExecuteFunction_t)))\n\t\t{\n\t\t\t// These functions are all defined as returning *, but in fact return the same type/class as their first argument.\n\t\t\tresult_type = argument_types[0];\n\t\t}\n\t\telse if ((function_ptr == &Eidos_ExecuteFunction_ifelse) && (argument_count >= 2))\n\t\t{\n\t\t\t// These functions are all defined as returning *, but in fact return the same type/class as their second argument.\n\t\t\tresult_type = argument_types[1];\n\t\t}\n\t\telse if ((function_ptr == &Eidos_ExecuteFunction_c) && (argument_count >= 1))\n\t\t{\n\t\t\t// The c() function returns the highest type it is passed (in the sense of promotion order).  This is not\n\t\t\t// important to us, except that if any argument is an object type, we assume the return will mirror that.\n\t\t\tfor (int argument_index = 0; argument_index < argument_count; ++argument_index)\n\t\t\t{\n\t\t\t\tEidosTypeSpecifier &argument_type = argument_types[argument_index];\n\t\t\t\t\n\t\t\t\tif ((argument_type.type_mask & kEidosValueMaskObject) == kEidosValueMaskObject)\n\t\t\t\t{\n\t\t\t\t\tresult_type = argument_type;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::_TypeEvaluate_MethodCall_Internal(const EidosClass *p_target, const EidosMethodSignature *p_method_signature, const std::vector<EidosASTNode *> &p_arguments)\n{\n#pragma unused(p_target, p_arguments)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\tint argument_count = (int)p_arguments.size();\n\tstd::vector<EidosTypeSpecifier> argument_types;\n\t\n\t// BCH 31 May 2018: We used to not bother doing type-evaluation on arguments, except for the specific cases below where\n\t// it influences the return type of a function/method, since such evaluation was unlikely to have side effects important\n\t// for type-evaluation (such as defining new symbols).  Now, however, type-evaluation can define completion symbols for\n\t// the named arguments of a function/method in argument_completions_ ; see _ProcessArgumentListTypes().  So that this\n\t// works even doing completion inside nested function/method calls, we have to descend into each argument.  This also\n\t// makes it so that any other type-evaluation side effects of arguments will occur correctly; it was always a bit of\n\t// an assumption that no such side effects would exist.  Note that TypeEvaluateNode() is safe to call with nullptr,\n\t// which is important since p_arguments can contain nullptr for missing/bad arguments.\n\targument_types.reserve(argument_count);\n\t\n\tfor (int argument_index = 0; argument_index < argument_count; ++argument_index)\n\t\targument_types.emplace_back(TypeEvaluateNode(p_arguments[argument_index]));\n\t\n\tif (p_method_signature)\n\t{\n\t\t// Look up the result type from the method signature, if there is one\n\t\tresult_type.type_mask = p_method_signature->return_mask_;\n\t\tresult_type.object_class = p_method_signature->return_class_;\n\t}\n\t\n\treturn result_type;\n}\n\nvoid EidosTypeInterpreter::_ProcessArgumentListTypes(const EidosASTNode *p_node, const EidosCallSignature *p_call_signature, std::vector<EidosASTNode *> &p_arguments)\n{\n\tconst std::vector<EidosASTNode *> &node_children = p_node->children_;\n\t\n\t// BCH 9/12/2020: This is no longer very parallel to _ProcessArgumentList(), because it doesn't involve the argument buffer\n\t// cache.  It could be brought back up to date, with its own private argument buffer, if necessary, but it seems to work.\n\t\n\t// Run through the argument nodes, evaluate them, and put the resulting pointers into the arguments buffer,\n\t// interleaving default arguments and handling named arguments as we go.\n\tauto node_children_end = node_children.end();\n\tint sig_arg_index = 0;\n\tint sig_arg_count = (int)p_call_signature->arg_name_IDs_.size();\n\t//bool had_named_argument = false;\n\t\n\tfor (auto child_iter = node_children.begin() + 1; child_iter != node_children_end; ++child_iter)\n\t{\n\t\tEidosASTNode *child = *child_iter;\n\t\t\n\t\tif (sig_arg_index < sig_arg_count)\n\t\t{\n\t\t\tif (child->token_->token_type_ != EidosTokenType::kTokenAssign)\n\t\t\t{\n\t\t\t\t// We have a non-named argument; it will go into the next argument slot from the signature\n\t\t\t\t// In EidosInterpreter it is an error if had_named_argument is set here; here, we ignore that\n\t\t\t\t\n\t\t\t\t// If this argument is the very last thing in the script string, then the user is trying to complete on it;\n\t\t\t\t// in that case, we add potential matches to the completion list, providing autocompletion of argument names.\n\t\t\t\t// We may be completing off an identifier (with partial typing), or off a bad token (with no typing).\n\t\t\t\t// That token should be at or after the script end (if it is a bad token it may be immediately after, since\n\t\t\t\t// it may have gotten its position from an EOF at the end of the token stream).\n\t\t\t\t// BCH 6 April 2019: We may also be completing off of what appears to be a language keyword, such as \"for\"\n\t\t\t\t// trying to complete to \"format=\".  We want to treat language keywords like identifiers here.\n\t\t\t\tif (argument_completions_ && (script_length_ <= (size_t)child->token_->token_end_ + 1))\n\t\t\t\t{\n\t\t\t\t\tif ((child->token_->token_type_ == EidosTokenType::kTokenIdentifier) || (child->token_->token_type_ == EidosTokenType::kTokenBad) || (child->token_->token_type_ >= EidosTokenType::kFirstIdentifierLikeToken))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check each argument in the signature as a possibility for completion\n\t\t\t\t\t\tfor (int sig_arg_match_index = sig_arg_index; sig_arg_match_index < sig_arg_count; ++sig_arg_match_index)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tconst std::string &arg_name = p_call_signature->arg_names_[sig_arg_match_index];\n\t\t\t\t\t\t\tbool is_ellipsis = (arg_name == \"...\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// To be a completion match, the name must not be private API ('_' prefix) or an ellipsis ('...')\n\t\t\t\t\t\t\t// Whether it is an acceptable completion in other respects will be checked by the completion engine\n\t\t\t\t\t\t\tif ((arg_name[0] != '_') && !is_ellipsis)\n\t\t\t\t\t\t\t\targument_completions_->emplace_back(arg_name);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// If the argument we just examined is non-optional, we don't want to offer any further suggestions\n\t\t\t\t\t\t\t// since they would not be legal to supply in this position in the function/method call.\n\t\t\t\t\t\t\t// The exception is an ellipsis, which should be treated as optional since it can be skipped over.\n\t\t\t\t\t\t\tif (!(p_call_signature->arg_masks_[sig_arg_match_index] & kEidosValueMaskOptional) && !is_ellipsis)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Advance to the next argument slot unless we're in the ellipsis; only a named argument pops us out of the ellipsis\n\t\t\t\tif (p_call_signature->arg_name_IDs_[sig_arg_index] != gEidosID_ELLIPSIS)\n\t\t\t\t\tsig_arg_index++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// We have a named argument; get information on it from its children\n\t\t\t\tconst std::vector<EidosASTNode *> &child_children = child->children_;\n\t\t\t\t\n\t\t\t\tif (child_children.size() == 2)\t// other than 2 should never happen; raises in EidosInterpreter\n\t\t\t\t{\n\t\t\t\t\tEidosASTNode *named_arg_name_node = child_children[0];\n\t\t\t\t\tEidosASTNode *named_arg_value_node = child_children[1];\n\t\t\t\t\t\n\t\t\t\t\t// Get the identifier for the argument name\n\t\t\t\t\tEidosGlobalStringID named_arg_nameID = named_arg_name_node->cached_stringID_;\n\t\t\t\t\t\n\t\t\t\t\t// Now re-point child at the value node\n\t\t\t\t\tchild = named_arg_value_node;\n\t\t\t\t\t\n\t\t\t\t\t// While this argument's name doesn't match the expected argument, insert default values for optional arguments\n\t\t\t\t\tdo \n\t\t\t\t\t{\n\t\t\t\t\t\tEidosGlobalStringID arg_name_ID = p_call_signature->arg_name_IDs_[sig_arg_index];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (named_arg_nameID == arg_name_ID)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsig_arg_index++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// In EidosInterpreter it is an error if a named argument skips over a required argument; here we ignore that\n\t\t\t\t\t\t// In EidosInterpreter it is an error if an optional argument has no default; here we ignore that\n\t\t\t\t\t\t\n\t\t\t\t\t\t// arguments that receive the default value are represented in the argument list here with nullptr, since we have no node for them\n\t\t\t\t\t\t// if the signature argument is an ellipsis, however, skip over it with no default value\n\t\t\t\t\t\tif (arg_name_ID != gEidosID_ELLIPSIS)\n\t\t\t\t\t\t\tp_arguments.emplace_back(nullptr);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Move to the next signature argument\n\t\t\t\t\t\tsig_arg_index++;\n\t\t\t\t\t\tif (sig_arg_index == sig_arg_count)\n\t\t\t\t\t\t\tbreak;\t\t// this is an error in EidosInterpreter; here we just break out to add the named argument after all the signature args\n\t\t\t\t\t}\n\t\t\t\t\twhile (true);\n\t\t\t\t\t\n\t\t\t\t\t//had_named_argument = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We're beyond the end of the signature's arguments; in EidosInterpreter this is complicated because of ellipsis args, here we just let it go\n\t\t}\n\t\t\n\t\t// The child pointer is an argument node, so remember it\n\t\tp_arguments.emplace_back(child);\n\t}\n\t\n\t// Handle any remaining arguments in the signature\n\twhile (sig_arg_index < sig_arg_count)\n\t{\n\t\t// In EidosInterpreter it is an error if a non-optional argument remains unmatched; here we ignore that\n\t\t// In EidosInterpreter it is an error if an optional argument has no default; here we ignore that\n\t\t\n\t\t// arguments that receive the default value are represented in the argument list here with nullptr, since we have no node for them\n\t\t// if the signature argument is an ellipsis, however, skip over it with no default value\n\t\tEidosGlobalStringID arg_name_ID = p_call_signature->arg_name_IDs_[sig_arg_index];\n\t\t\n\t\tif (arg_name_ID != gEidosID_ELLIPSIS)\n\t\t\tp_arguments.emplace_back(nullptr);\n\t\t\n\t\tsig_arg_index++;\n\t}\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Call(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\t// We do not evaluate the call name node (our first child) to get a function/method object; there is no such type\n\t// in Eidos for now.  Instead, we extract the identifier name directly from the node and work with it.  If the\n\t// node is an identifier, it is a function call; if it is a dot operator, it is a method call; other constructs\n\t// are illegal since expressions cannot evaluate to function/method objects.\n\tconst std::vector<EidosASTNode *> &node_children = p_node->children_;\n\tEidosASTNode *call_name_node = node_children[0];\n\tEidosTokenType call_name_token_type = call_name_node->token_->token_type_;\n\tEidosToken *call_identifier_token = nullptr;\n\t\n\tif (call_name_token_type == EidosTokenType::kTokenIdentifier)\n\t{\n\t\t//\n\t\t//\tFUNCTION CALL DISPATCH\n\t\t//\n\t\tcall_identifier_token = call_name_node->token_;\n\t\t\n\t\t// OK, we have <identifier>(...); that's a well-formed function call\n\t\tconst std::string *function_name = &(call_identifier_token->token_string_);\n\t\tconst EidosFunctionSignature *function_signature = call_name_node->cached_signature_.get();\n\t\t\n\t\t// If the function call is a built-in Eidos function, we might already have a pointer to its signature cached; if not, we'll have to look it up\n\t\tif (!function_signature)\n\t\t{\n\t\t\t// Get the function signature\n\t\t\tauto signature_iter = function_map_.find(*function_name);\n\t\t\t\n\t\t\tif (signature_iter != function_map_.end())\n\t\t\t\tfunction_signature = signature_iter->second.get();\n\t\t}\n\t\t\n\t\tif (function_signature)\n\t\t{\n\t\t\t// Argument processing\n\t\t\tstd::vector<EidosASTNode *> arguments;\n\t\t\t\n\t\t\t_ProcessArgumentListTypes(p_node, function_signature, arguments);\n\t\t\t\n\t\t\t// Dispatch to determine the return type\n\t\t\tresult_type = _TypeEvaluate_FunctionCall_Internal(*function_name, function_signature, arguments);\n\t\t\t\n\t\t\t// Remember the class returned by function calls, for later use by code completion in cases of ambiguity.\n\t\t\t// See -[EidosTextView completionsForKeyPathEndingInTokenIndex:...] for more background on this.\n\t\t\tif (result_type.object_class)\n\t\t\t\tcall_type_map_.emplace(EidosCallTypeEntry(call_name_node->token_->token_start_, result_type.object_class));\n\t\t}\n\t}\n\telse if (call_name_token_type == EidosTokenType::kTokenDot)\n\t{\n\t\t//\n\t\t//\tMETHOD CALL DISPATCH\n\t\t//\n\t\tif (call_name_node->children_.size() >= 2)\n\t\t{\n\t\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(call_name_node->children_[0]);\n\t\t\tconst EidosClass *method_class = first_child_type.object_class;\n\t\t\t\n\t\t\tif (method_class)\n\t\t\t{\n\t\t\t\tEidosASTNode *second_child_node = call_name_node->children_[1];\n\t\t\t\t\n\t\t\t\tif (second_child_node->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t\t{\n\t\t\t\t\t// OK, we have <object type>.<identifier>(...); that's a well-formed method call\n\t\t\t\t\tcall_identifier_token = second_child_node->token_;\n\t\t\t\t\t(void)call_identifier_token;\t\t// tell the static analyzer that we know we just did a dead store\n\t\t\t\t\t\n\t\t\t\t\tEidosGlobalStringID method_id = second_child_node->cached_stringID_;\n\t\t\t\t\tconst EidosMethodSignature *method_signature = method_class->SignatureForMethod(method_id);\n\t\t\t\t\t\n\t\t\t\t\tif (method_signature)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Argument processing\n\t\t\t\t\t\tstd::vector<EidosASTNode *> arguments;\n\t\t\t\t\t\t\n\t\t\t\t\t\t_ProcessArgumentListTypes(p_node, method_signature, arguments);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Dispatch; note that we don't treat class and instance methods differently here the way we do in EidosInterpreter\n\t\t\t\t\t\tresult_type = _TypeEvaluate_MethodCall_Internal(method_class, method_signature, arguments);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Subset(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 1)\n\t{\n\t\tresult_type = TypeEvaluateNode(p_node->children_[0]);\n\t\t\n\t\t// No need to evaluate the subset index argument(s), since they cannot define new variables\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_MemberRef(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\t\n\t\tif (first_child_type.object_class)\n\t\t{\n\t\t\tEidosASTNode *second_child_node = p_node->children_[1];\n\t\t\tEidosToken *second_child_token = second_child_node->token_;\n\t\t\t\n\t\t\tif (second_child_token->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID property_string_ID = second_child_node->cached_stringID_;\n\t\t\t\tconst EidosPropertySignature *property_signature = first_child_type.object_class->SignatureForProperty(property_string_ID);\n\t\t\t\t\n\t\t\t\tif (property_signature)\n\t\t\t\t{\n\t\t\t\t\tresult_type.type_mask = property_signature->value_mask_;\n\t\t\t\t\tresult_type.object_class = property_signature->value_class_;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Plus(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() == 1)\n\t{\n\t\t// unary plus is a no-op, but legal only for numeric types\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif (integer1 && !float1)\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if (float1 && !integer1)\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\telse if (integer1 && float1)\n\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t}\n\telse if (p_node->children_.size() >= 2)\n\t{\n\t\t// binary plus is legal either between two numeric types, or between a string and any other non-NULL operand\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tif ((first_child_type.type_mask == kEidosValueMaskString) || (second_child_type.type_mask == kEidosValueMaskString))\n\t\t{\n\t\t\tresult_type.type_mask = kEidosValueMaskString;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\t\n\t\t\tif ((integer1 && !float1) && (integer2 && !float2))\n\t\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\t\telse if ((!integer1 && float1) || (!integer2 && float2))\n\t\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\t\telse if ((integer1 || float1) && (integer2 || float2))\n\t\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Minus(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() == 1)\n\t{\n\t\t// unary minus is a no-op, but legal only for numeric types\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif (integer1 && !float1)\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if (float1 && !integer1)\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\telse if (integer1 && float1)\n\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t}\n\telse if (p_node->children_.size() >= 2)\n\t{\n\t\t// binary minus is legal between two numeric types\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 && !float1) && (integer2 && !float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if ((!integer1 && float1) || (!integer2 && float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\telse if ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Mod(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\t// modulo is legal between two numeric types, and always produces float\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Mult(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\t// multiplication is legal between two numeric types\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 && !float1) && (integer2 && !float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if ((!integer1 && float1) || (!integer2 && float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t\telse if ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskNumeric;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Div(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\t// division is legal between two numeric types, and always produces float\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Conditional(const EidosASTNode *p_node)\n{\n\tauto children_size = p_node->children_.size();\n\t\n\t// In general, the type of a ternary conditional can't be predicted, because the true and\n\t// false clauses do not have to result in the same type in Eidos, so this is the default\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (children_size == 3)\n\t{\n\t\tEidosASTNode *true_node = p_node->children_[1];\n\t\tEidosASTNode *false_node = p_node->children_[2];\n\t\tEidosTypeSpecifier true_type = TypeEvaluateNode(true_node);\n\t\tEidosTypeSpecifier false_type = TypeEvaluateNode(false_node);\n\t\t\n\t\t// Try to merge the types of the true and false clauses if possible\n\t\tif ((true_type.type_mask == false_type.type_mask) && (true_type.object_class == false_type.object_class))\n\t\t{\n\t\t\t// Their types are identical, so that's easy\n\t\t\treturn true_type;\n\t\t}\n\t\telse if (((true_type.type_mask & kEidosValueMaskObject) == kEidosValueMaskObject) && ((false_type.type_mask & kEidosValueMaskObject) == kEidosValueMaskObject))\n\t\t{\n\t\t\t// Both types include object, so we can merge them if their object classes match\n\t\t\tresult_type.type_mask = (true_type.type_mask | false_type.type_mask);\n\t\t\t\n\t\t\tif (true_type.object_class == false_type.object_class)\n\t\t\t\tresult_type.object_class = true_type.object_class;\n\t\t\telse\n\t\t\t\tresult_type.object_class = nullptr;\t\t// object is included in our type, but we don't know the class\n\t\t}\n\t\telse if (((true_type.type_mask & kEidosValueMaskObject) == kEidosValueMaskNone) && ((false_type.type_mask & kEidosValueMaskObject) == kEidosValueMaskNone))\n\t\t{\n\t\t\t// Neither type includes object, so we can just merge them\n\t\t\tresult_type.type_mask = (true_type.type_mask | false_type.type_mask);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We have a mix of object and non-object, so we exclude the object type as part of our result;\n\t\t\t// we don't want to guarantee that object is included if it is only present sometimes\n\t\t\tresult_type.type_mask = (true_type.type_mask | false_type.type_mask);\n\t\t\tresult_type.type_mask &= (~kEidosValueMaskObject);\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Exp(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\t// exponentiation is legal between two numeric types, and always produces float\n\t\tEidosTypeSpecifier first_child_type = TypeEvaluateNode(p_node->children_[0]);\n\t\tEidosTypeSpecifier second_child_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\tbool integer1 = !!(first_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float1 = !!(first_child_type.type_mask & kEidosValueMaskFloat);\n\t\tbool integer2 = !!(second_child_type.type_mask & kEidosValueMaskInt);\n\t\tbool float2 = !!(second_child_type.type_mask & kEidosValueMaskFloat);\n\t\t\n\t\tif ((integer1 || float1) && (integer2 || float2))\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_And(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Or(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Not(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Assign(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\tEidosASTNode *lvalue_node = p_node->children_[0];\n\t\tEidosTypeSpecifier rvalue_type = TypeEvaluateNode(p_node->children_[1]);\n\t\t\n\t\t// We are only interested in assignments in simple identifier lvalues; other assignments do not alter the type table\n\t\tif (lvalue_node->token_->token_type_ != EidosTokenType::kTokenIdentifier)\n\t\t\treturn result_type;\n\t\t\n\t\tEidosGlobalStringID identifier_name = lvalue_node->cached_stringID_;\n\t\t\n\t\tglobal_symbols_->SetTypeForSymbol(identifier_name, rvalue_type);\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Assign_R(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Eq(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Lt(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_LtEq(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Gt(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_GtEq(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_NotEq(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskLogical, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Number(const EidosASTNode *p_node)\n{\n\t// use a cached value from EidosASTNode::_OptimizeConstants() if present; this should always be hit now!\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNumeric, nullptr};\n\tEidosValue_SP result_SP = p_node->cached_literal_value_;\n\t\n\tif (result_SP)\n\t{\n\t\tEidosValueType type = result_SP->Type();\n\t\t\n\t\tif (type == EidosValueType::kValueInt)\n\t\t\tresult_type.type_mask = kEidosValueMaskInt;\n\t\telse if (type == EidosValueType::kValueFloat)\n\t\t\tresult_type.type_mask = kEidosValueMaskFloat;\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_String(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskString, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Identifier(const EidosASTNode *p_node)\n{\n\t// a cached value might be present, from EidosASTNode::_OptimizeConstants(), but at present we don't look\n\tEidosTypeSpecifier result_type = global_symbols_->GetTypeForSymbol(p_node->cached_stringID_);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_If(const EidosASTNode *p_node)\n{\n\tauto children_size = p_node->children_.size();\n\t\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (children_size > 1)\n\t{\n\t\tEidosASTNode *true_node = p_node->children_[1];\n\t\tTypeEvaluateNode(true_node);\n\t}\n\t\n\tif (children_size > 2)\n\t{\n\t\tEidosASTNode *false_node = p_node->children_[2];\n\t\tTypeEvaluateNode(false_node);\n\t}\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Do(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 1)\n\t\tTypeEvaluateNode(p_node->children_[0]);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_While(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t\tTypeEvaluateNode(p_node->children_[1]);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_For(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 2)\n\t{\n\t\tint in_clause_count = (int)((p_node->children_.size() - 1) / 2);\n\t\t\n\t\tfor (int in_clause_index = 0; in_clause_index < in_clause_count; ++in_clause_index)\n\t\t{\n\t\t\tEidosASTNode *identifier_child = p_node->children_[in_clause_index * 2];\n\t\t\tconst EidosASTNode *range_node = p_node->children_[in_clause_index * 2 + 1];\n\t\t\tEidosTypeSpecifier range_type = TypeEvaluateNode(range_node);\n\t\t\t\n\t\t\tif (identifier_child->token_->token_type_ == EidosTokenType::kTokenIdentifier)\n\t\t\t{\n\t\t\t\tEidosGlobalStringID identifier_name = identifier_child->cached_stringID_;\n\t\t\t\t\n\t\t\t\tglobal_symbols_->SetTypeForSymbol(identifier_name, range_type);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (p_node->children_.size() % 2 == 1)\n\t\tTypeEvaluateNode(p_node->children_[p_node->children_.size() - 1]);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Next(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Break(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_Return(const EidosASTNode *p_node)\n{\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNULL, nullptr};\n\t\n\tif (p_node->children_.size() >= 1)\n\t\tresult_type = TypeEvaluateNode(p_node->children_[0]);\n\t\n\treturn result_type;\n}\n\nEidosTypeSpecifier EidosTypeInterpreter::TypeEvaluate_FunctionDecl(const EidosASTNode *p_node)\n{\n#pragma unused(p_node)\n\tEidosTypeSpecifier result_type = EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n\t\n\tif (p_node->children_.size() >= 4)\n\t{\n\t\t// We have two jobs to do.  One is to build a function signature for the declared function, so that calls to that function\n\t\t// then return the correct type when type-interpreted, just like built-in functions.  We will do that first, so that\n\t\t// recursive functions are type-interpreted correctly.\n\t\tconst EidosASTNode *return_type_node = p_node->children_[0];\n\t\tconst EidosASTNode *function_name_node = p_node->children_[1];\n\t\tconst EidosASTNode *param_list_node = p_node->children_[2];\n\t\tconst EidosASTNode *body_node = p_node->children_[3];\n\t\t\n\t\t// If we don't have enough of the function declaration to build a signature, don't do anything\n\t\tif ((return_type_node->token_->token_type_ == EidosTokenType::kTokenEOF) ||\n\t\t\t(function_name_node->token_->token_type_ == EidosTokenType::kTokenEOF) ||\n\t\t\t(param_list_node->token_->token_type_ == EidosTokenType::kTokenEOF))\n\t\t\treturn result_type;\n\t\t\n\t\t// Build a signature object for this function\n\t\tEidosTypeSpecifier &return_type = return_type_node->typespec_;\n\t\tconst std::string &function_name = function_name_node->token_->token_string_;\n\t\tconst std::vector<EidosASTNode *> &param_nodes = param_list_node->children_;\n\t\tstd::vector<std::string> used_param_names;\n\t\t\n\t\t{\n\t\t\tEidosFunctionSignature *sig;\n\t\t\t\n\t\t\tif (return_type.object_class == nullptr)\n\t\t\t\tsig = (EidosFunctionSignature *)(new EidosFunctionSignature(function_name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullptr,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.type_mask));\n\t\t\telse\n\t\t\t\tsig = (EidosFunctionSignature *)(new EidosFunctionSignature(function_name,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullptr,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.type_mask,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn_type.object_class));\n\t\t\t\n\t\t\tfor (EidosASTNode *param_node : param_nodes)\n\t\t\t{\n\t\t\t\tconst std::vector<EidosASTNode *> &param_children = param_node->children_;\n\t\t\t\tint param_children_count = (int)param_children.size();\n\t\t\t\t\n\t\t\t\tif ((param_children_count == 2) || (param_children_count == 3))\n\t\t\t\t{\n\t\t\t\t\tEidosTypeSpecifier &param_type = param_children[0]->typespec_;\n\t\t\t\t\tconst std::string &param_name = param_children[1]->token_->token_string_;\n\t\t\t\t\t\n\t\t\t\t\t// Check param_name; it needs to not be used by another parameter\n\t\t\t\t\tif (std::find(used_param_names.begin(), used_param_names.end(), param_name) != used_param_names.end())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\n\t\t\t\t\tif (param_children_count >= 2)\n\t\t\t\t\t{\n\t\t\t\t\t\t// param_node has 2 or 3 children (type, identifier, [default]); we don't care about default values\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Note that we really can't easily deal with default values, because we would have to actually parse the\n\t\t\t\t\t\t// defualt-value node to get a value, if it is an identifier, and then once we have the value we can't\n\t\t\t\t\t\t// easily represent it symbolically any more anyway.  This means function signature previews in the\n\t\t\t\t\t\t// status bar won't show default arguments for user-defined functions; the information to do that will\n\t\t\t\t\t\t// not be gathered here.  Maybe this can be improved at some point.  FIXME BCH 23 October 2017\n\t\t\t\t\t\t\n\t\t\t\t\t\t// we call AddArgWithDefault() so we can specify fault-tolerance; we're not allowed to raise!\n\t\t\t\t\t\t// note this means that erroneous function prototypes will lead to faulty signatures in our function map,\n\t\t\t\t\t\t// but that is fine, it may just mean that an incorrect signature gets previewed to the user\n\t\t\t\t\t\tsig->AddArgWithDefault(param_type.type_mask, param_name, param_type.object_class, EidosValue_SP(nullptr), true);\t// true is fault-tolerant\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tused_param_names.emplace_back(param_name);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tsig->user_defined_ = true;\n\t\t\t\n\t\t\t//std::cout << *sig << std::endl;\n\t\t\t\n\t\t\t// Check that a built-in function is not already defined with this name; no replacing the built-ins.\n\t\t\tauto signature_iter = function_map_.find(function_name);\n\t\t\tbool can_redefine = true;\n\t\t\t\n\t\t\tif (signature_iter != function_map_.end())\n\t\t\t{\n\t\t\t\tconst EidosFunctionSignature *prior_sig = signature_iter->second.get();\n\t\t\t\t\n\t\t\t\tif (prior_sig->internal_function_ || !prior_sig->delegate_name_.empty() || !prior_sig->user_defined_)\n\t\t\t\t\tcan_redefine = false;\n\t\t\t}\n\t\t\t\n\t\t\tif (can_redefine)\n\t\t\t{\n\t\t\t\t// Add the user-defined function to our function map (possibly replacing a previous version)\n\t\t\t\tauto found_iter = function_map_.find(sig->call_name_);\n\t\t\t\t\n\t\t\t\tif (found_iter != function_map_.end())\n\t\t\t\t\tfunction_map_.erase(found_iter);\n\t\t\t\t\n\t\t\t\tfunction_map_.insert(EidosFunctionMapPair(sig->call_name_, EidosFunctionSignature_CSP(sig)));\t// could raise, but I've never seen it happen here\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdelete sig;\n\t\t\t}\n\t\t\t\n\t\t\t// the signature is now under shared_ptr, or deleted, and so variable sig falls out of scope here\n\t\t}\n\t\t\n\t\t// Our other job is to type-interpret inside the body node of the declared function, with the correct scoping set up so\n\t\t// that the parameters of the function are defined inside the body, outer variables are not in scope, etc.  This is\n\t\t// different from EidosInterpreter; it is as if the declared function is getting called as it is declared, in a way.\n\t\t// This custom type scope for the function lasts only to the end of the declared function, and then we want to forget\n\t\t// the custom scope and go back to the type table we were using before, as long as the declaration is complete.\n\t\tif (body_node->token_->token_type_ != EidosTokenType::kTokenEOF)\n\t\t{\n\t\t\tif (body_node->hit_eof_in_tolerant_parse_)\n\t\t\t{\n\t\t\t\t// The EOF was hit while parsing the function body, so we're supposed to leave the type table reflecting the scope\n\t\t\t\t// inside the function.  To do this, we don't create a sub-type-interpreter, we just repurpose our type table.\n\t\t\t\tglobal_symbols_->RemoveAllSymbols();\n\t\t\t\t\n\t\t\t\tgEidosConstantsSymbolTable->AddSymbolsToTypeTable(global_symbols_);\n\t\t\t\t\n\t\t\t\tfor (EidosASTNode *param_node : param_nodes)\n\t\t\t\t{\n\t\t\t\t\tconst std::vector<EidosASTNode *> &param_children = param_node->children_;\n\t\t\t\t\tint param_children_count = (int)param_children.size();\n\t\t\t\t\t\n\t\t\t\t\tif ((param_children_count == 2) || (param_children_count == 3))\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosTypeSpecifier &param_type = param_children[0]->typespec_;\n\t\t\t\t\t\tconst std::string &param_name = param_children[1]->token_->token_string_;\n\t\t\t\t\t\t\n\t\t\t\t\t\tglobal_symbols_->SetTypeForSymbol(EidosStringRegistry::GlobalStringIDForString(param_name), param_type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tTypeEvaluateNode(body_node);\t// result not used\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The EOF was not hit while parsing the function body, so we're supposed to leave the type table alone in the end.\n\t\t\t\t// We do this by creating a separate type table that we just use temporarily, inside the function body.  We could\n\t\t\t\t// almost skip type-interpreting the function body entirely, except that it might define a constant.  We base our\n\t\t\t\t// local table on our global table, and give the scoped type interpreter a pointer to the global table; that way,\n\t\t\t\t// define constants and globals will make it to the outside scope.\n\t\t\t\tEidosTypeTable typeTable(*global_symbols_);\n\t\t\t\tEidosCallTypeTable callTypeTable;\n\t\t\t\t\n\t\t\t\tfor (EidosASTNode *param_node : param_nodes)\n\t\t\t\t{\n\t\t\t\t\tconst std::vector<EidosASTNode *> &param_children = param_node->children_;\n\t\t\t\t\tint param_children_count = (int)param_children.size();\n\t\t\t\t\t\n\t\t\t\t\tif ((param_children_count == 2) || (param_children_count == 3))\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosTypeSpecifier &param_type = param_children[0]->typespec_;\n\t\t\t\t\t\tconst std::string &param_name = param_children[1]->token_->token_string_;\n\t\t\t\t\t\t\n\t\t\t\t\t\ttypeTable.SetTypeForSymbol(EidosStringRegistry::GlobalStringIDForString(param_name), param_type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tEidosTypeInterpreter typeInterpreter(body_node, typeTable, function_map_, callTypeTable);\n\t\t\t\t\n\t\t\t\ttypeInterpreter.SetExternalTypeTable(global_symbols_);\t\t// defined constants/variables should also go into the global scope\n\t\t\t\ttypeInterpreter.TypeEvaluateNode(body_node);\t\t\t\t// result not used\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn result_type;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_type_interpreter.h",
    "content": "//\n//  eidos_type_interpreter.h\n//  Eidos\n//\n//  Created by Ben Haller on 5/8/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosTypeInterpreter interprets a script solely for the purpose of producing type information about variables defined\n by the script, for code completion.  It is parallel to EidosInterpreter in many ways, and uses EidosTypeTable in place of\n EidosSymbolTable.  Unlike EidosInterpreter, it is designed not to raise with malformed scripts; it is error-tolerant and just\n does the best it can.  The worst that happens is that code completion has incorrect or missing information about some variables.\n \n */\n\n#ifndef __Eidos__eidos_type_interpreter__\n#define __Eidos__eidos_type_interpreter__\n\n#include \"eidos_script.h\"\n#include \"eidos_type_table.h\"\n#include \"eidos_ast_node.h\"\n#include \"eidos_interpreter.h\"\n\n\n// This is used to record the object class returned by function calls encountered during type interpreting.  This is used to recall\n// the return type of a function at the beginning of a key path for code completion, in cases where the function signature is not\n// sufficient to determine that, such as sample(), rep(), etc.  See -[EidosTextView completionsForKeyPathEndingInTokenIndex:...].\ntypedef std::pair<int32_t, const EidosClass *> EidosCallTypeEntry;\ntypedef std::map<int32_t, const EidosClass *> EidosCallTypeTable;\n\n\nclass EidosTypeInterpreter\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\n\t\nprotected:\n\tconst EidosASTNode *root_node_;\t\t\t\t\t\t// not owned\n\tEidosTypeTable *global_symbols_;\t\t\t\t\t// NOT OWNED: whoever creates us must give us a reference to a type table, which we use\n\tEidosTypeTable *external_type_table_ = nullptr;\t\t// NOT OWNED: a global-scope table, our parent, given to us with SetExternalTypeTable()\n\t\n\tEidosFunctionMap &function_map_;\t\t\t\t\t// NOT OWNED: a map table of EidosFunctionSignature objects, keyed by function name\n\n\tEidosCallTypeTable &call_type_map_;\t\t\t\t\t// NOT OWNED: a map table of types for function calls encountered, keyed by position\n\t\n\t// for autocompletion of argument names, set up by TypeEvaluateInterpreterBlock_AddArgumentCompletions()\n\tstd::vector<std::string> *argument_completions_ = nullptr;\n\tsize_t script_length_ = 0;\n\t\npublic:\n\t\n\tEidosTypeInterpreter(const EidosTypeInterpreter&) = delete;\t\t\t\t\t// no copying\n\tEidosTypeInterpreter& operator=(const EidosTypeInterpreter&) = delete;\t\t// no copying\n\tEidosTypeInterpreter(void) = delete;\t\t\t\t\t\t\t\t\t\t// no null construction\n\t\n\tEidosTypeInterpreter(const EidosScript &p_script, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types);\t\t\t// we use the passed symbol table but do not own it\n\tEidosTypeInterpreter(const EidosASTNode *p_root_node_, EidosTypeTable &p_symbols, EidosFunctionMap &p_functions, EidosCallTypeTable &p_call_types);\t\t// we use the passed symbol table but do not own it\n\t\n\tvirtual ~EidosTypeInterpreter(void);\n\t\n\tinline void SetExternalTypeTable(EidosTypeTable *p_external_type_table) { external_type_table_ = p_external_type_table; }\t// to support local-scope type tables that are nested in the global scope\n\t\n\tinline __attribute__((always_inline)) EidosTypeTable &SymbolTable(void) { return *global_symbols_; };\t// the returned reference is to the symbol table that the interpreter has borrowed\n\tinline __attribute__((always_inline)) EidosFunctionMap &FunctionMap(void) { return function_map_; };\t// the returned reference is to the function map that the interpreter has borrowed\n\tinline __attribute__((always_inline)) EidosCallTypeTable &CallTypeMap(void) { return call_type_map_; };\t// the returned reference is to the call type map that the interpreter has borrowed\n\t\n\t// Evaluation methods; the caller owns the returned EidosValue object\n\tEidosTypeSpecifier TypeEvaluateInterpreterBlock();\t// the starting point for executed blocks in Eidos, which do not require braces\n\tEidosTypeSpecifier TypeEvaluateInterpreterBlock_AddArgumentCompletions(std::vector<std::string> *p_argument_completions, size_t p_script_length);\t// for autocompletion of argument names\n\t\n\tEidosTypeSpecifier TypeEvaluateNode(const EidosASTNode *p_node);\n\t\n\tEidosTypeSpecifier TypeEvaluate_NullStatement(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_CompoundStatement(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_RangeExpr(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Call(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Subset(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_MemberRef(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Plus(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Minus(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Mod(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Mult(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Div(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Conditional(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Exp(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_And(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Or(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Assign(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Assign_R(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Eq(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Lt(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_LtEq(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Gt(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_GtEq(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Not(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_NotEq(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Number(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_String(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Identifier(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_If(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Do(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_While(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_For(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Next(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Break(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_Return(const EidosASTNode *p_node);\n\tEidosTypeSpecifier TypeEvaluate_FunctionDecl(const EidosASTNode *p_node);\n\t\n\t// Function/method processing.  These can implement type-defining side effects of calls; for example,\n\t// defineConstant() has the side effect of defining a new symbol of a particular type.  These are\n\t// virtual so the Context can subclass this class to define additional functions/methods with such\n\t// side effects.\n\tvirtual EidosTypeSpecifier _TypeEvaluate_FunctionCall_Internal(std::string const &p_function_name, const EidosFunctionSignature *p_function_signature, const std::vector<EidosASTNode *> &p_arguments);\n\t\n\tvirtual EidosTypeSpecifier _TypeEvaluate_MethodCall_Internal(const EidosClass *p_target, const EidosMethodSignature *p_method_signature, const std::vector<EidosASTNode *> &p_arguments);\n\t\n\t// Argument processing; handles default arguments and named arguments\n\tvoid _ProcessArgumentListTypes(const EidosASTNode *p_node, const EidosCallSignature *p_call_signature, std::vector<EidosASTNode *> &p_arguments);\n};\n\n\n#endif /* __Eidos__eidos_type_interpreter__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_type_table.cpp",
    "content": "//\n//  eidos_type_table.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 5/8/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"eidos_type_table.h\"\n\n#include <algorithm>\n#include <utility>\n\n\nEidosTypeTable::EidosTypeTable(const EidosTypeTable &originalTable)\n{\n\t// Construct a derived table that copies all symbols from an original table\n\t// This is useful for setting up scoping, where the local scope's type table is based on the global scope\n\thash_symbols_ = originalTable.hash_symbols_;\n}\n\nEidosTypeTable::EidosTypeTable(void)\n{\n\t// Construct a base table for Eidos containing the standard constants\n\tSetTypeForSymbol(gEidosID_T, EidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\tSetTypeForSymbol(gEidosID_F, EidosTypeSpecifier{kEidosValueMaskLogical, nullptr});\n\tSetTypeForSymbol(gEidosID_NULL, EidosTypeSpecifier{kEidosValueMaskNULL, nullptr});\n\tSetTypeForSymbol(gEidosID_PI, EidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\tSetTypeForSymbol(gEidosID_E, EidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\tSetTypeForSymbol(gEidosID_INF, EidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n\tSetTypeForSymbol(gEidosID_NAN, EidosTypeSpecifier{kEidosValueMaskFloat, nullptr});\n}\n\nEidosTypeTable::~EidosTypeTable(void)\n{\n}\n\nstd::vector<std::string> EidosTypeTable::AllSymbols(void) const\n{\n\tstd::vector<std::string> symbol_names;\n\t\n\tfor (auto symbol_slot_iter : hash_symbols_)\n\t{\n\t\tEidosGlobalStringID string_id = symbol_slot_iter.first;\n\t\tconst std::string &string_ref = EidosStringRegistry::StringForGlobalStringID(string_id);\n\t\t\n\t\tsymbol_names.emplace_back(string_ref);\n\t}\n\t\n\treturn symbol_names;\n}\n\nstd::vector<EidosGlobalStringID> EidosTypeTable::AllSymbolIDs(void) const\n{\n\tstd::vector<EidosGlobalStringID> symbol_ids;\n\t\n\tfor (auto symbol_slot_iter : hash_symbols_)\n\t{\n\t\tEidosGlobalStringID string_id = symbol_slot_iter.first;\n\t\t\n\t\tsymbol_ids.emplace_back(string_id);\n\t}\n\t\n\treturn symbol_ids;\n}\n\nbool EidosTypeTable::ContainsSymbol(EidosGlobalStringID p_symbol_name) const\n{\n\tif (hash_symbols_.find(p_symbol_name) != hash_symbols_.end())\n\t\treturn true;\n\t\n\treturn false;\n}\n\nvoid EidosTypeTable::SetTypeForSymbol(EidosGlobalStringID p_symbol_name, EidosTypeSpecifier p_type)\n{\n\t// We decline to track variables if their type is \"none\".  This prevents some sorts of parsing garbage from getting\n\t// into the table, and it also prevents \"z\" from being visible as a completion option when the user has typed \"z =\"\n\t// and then hit escape; that produces \"z = <bad node>\", which results in a call to us to define z with the type\n\t// kEidosValueMaskNone, providing the user with the option of completing the statement as \"z = z\", which is dumb.\n\t// Note that we do this whether the variable has been previously defined or not, so that we don't replace useful\n\t// type information with useless garbage information; for example, in \"x = sim; x = \" we want to know that x is\n\t// of type Species, not replace that knowledge with junk.  This means that variables will retain their previous\n\t// type whenever they are set to kEidosValueMaskNone, even when that might be legitimate; that's OK, I think,\n\t// particularly since there presently really aren't any \"legitimate\" uses of kEidosValueMaskNone – it always\n\t// represents some kind of parse error, misuse of operators, unknown functions/methods, etc.\n\tif (p_type.type_mask != kEidosValueMaskNone)\n\t{\n\t\tauto existing_symbol_slot_iter = hash_symbols_.find(p_symbol_name);\n\t\t\n\t\tif (existing_symbol_slot_iter == hash_symbols_.end())\n\t\t{\n\t\t\thash_symbols_.insert(EidosTypeTableEntry(p_symbol_name, p_type));\t// could raise, but I've never seen it happen here\n\t\t}\n\t\telse\n\t\t{\n\t\t\texisting_symbol_slot_iter->second = p_type;\n\t\t}\n\t}\n}\n\nvoid EidosTypeTable::RemoveTypeForSymbol(EidosGlobalStringID p_symbol_name)\n{\n\tauto remove_iter = hash_symbols_.find(p_symbol_name);\n\t\n\tif (remove_iter != hash_symbols_.end())\n\t\thash_symbols_.erase(remove_iter);\n}\n\nvoid EidosTypeTable::RemoveSymbolsOfClass(const EidosClass *p_object_class)\n{\n\tstd::vector<EidosGlobalStringID> symbolIDs = AllSymbolIDs();\n\t\n\tfor (EidosGlobalStringID symbolID : symbolIDs)\n\t{\n\t\tEidosTypeSpecifier type = GetTypeForSymbol(symbolID);\n\t\t\n\t\tif ((type.type_mask & kEidosValueMaskObject) && (type.object_class == p_object_class))\n\t\t\tRemoveTypeForSymbol(symbolID);\n\t}\n}\n\nvoid EidosTypeTable::RemoveAllSymbols(void)\n{\n\thash_symbols_.clear();\n}\n\nEidosTypeSpecifier EidosTypeTable::GetTypeForSymbol(EidosGlobalStringID p_symbol_name) const\n{\n\tauto symbol_slot_iter = hash_symbols_.find(p_symbol_name);\n\t\n\tif (symbol_slot_iter != hash_symbols_.end())\n\t\treturn symbol_slot_iter->second;\n\t\n\t// Since we don't allow kEidosValueMaskNone to be set in SetTypeForSymbol(), it is a reliable \"not found\" marker\n\treturn EidosTypeSpecifier{kEidosValueMaskNone, nullptr};\n}\n\n// This is unused except by debugging code and in the debugger itself\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosTypeTable &p_symbols)\n{\n\tstd::vector<std::string> symbol_names = p_symbols.AllSymbols();\n\t\n\tstd::sort(symbol_names.begin(), symbol_names.end());\n\t\n\tfor (const std::string &symbol_name : symbol_names)\n\t{\n\t\tEidosTypeSpecifier symbol_type = p_symbols.GetTypeForSymbol(EidosStringRegistry::GlobalStringIDForString(symbol_name));\n\t\t\n\t\tp_outstream << symbol_name << \" ~> (\" << StringForEidosValueMask(symbol_type.type_mask, symbol_type.object_class, \"\", nullptr) << \") \" << std::endl;\n\t}\n\t\n\treturn p_outstream;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_type_table.h",
    "content": "//\n//  eidos_type_table.h\n//  Eidos\n//\n//  Created by Ben Haller on 5/8/16.\n//  Copyright (c) 2016-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n A type table is very much like a symbol table, except that it does not keep values for its symbols, just type information.\n This is used for type-smart code completion in EidosScribe and SLiMgui.  At present EidosTypeTable is implemented with\n a hash table, since we need no additional functionality from it.\n \n */\n\n#ifndef __Eidos__eidos_type_table__\n#define __Eidos__eidos_type_table__\n\n#include <iostream>\n#include <vector>\n#include <string>\n\n#include \"eidos_value.h\"\n\n\n#include \"eidos_globals.h\"\n#if EIDOS_ROBIN_HOOD_HASHING\n#include \"robin_hood.h\"\ntypedef robin_hood::unordered_flat_map<EidosGlobalStringID, EidosTypeSpecifier> EidosTypeTableSymbols;\ntypedef robin_hood::pair<EidosGlobalStringID, EidosTypeSpecifier> EidosTypeTableEntry;\n#elif STD_UNORDERED_MAP_HASHING\n#include <unordered_map>\ntypedef std::unordered_map<EidosGlobalStringID, EidosTypeSpecifier> EidosTypeTableSymbols;\ntypedef std::pair<EidosGlobalStringID, EidosTypeSpecifier> EidosTypeTableEntry;\n#endif\n\n\nclass EidosTypeTable\n{\n\t//\tThis class has its copy constructor and assignment operator disabled, to prevent accidental copying.\nprivate:\n\t\n\tEidosTypeTableSymbols hash_symbols_;\n\t\npublic:\n\t\n\tEidosTypeTable(const EidosTypeTable &originalTable);\t\t\t\t\t\t\t\t// copy all defined symbols from an original table to a derived table\n\tEidosTypeTable& operator=(const EidosTypeTable&) = delete;\t\t\t\t\t\t\t// no copying\n\texplicit EidosTypeTable(void);\t\t\t\t\t\t\t\t\t\t\t\t\t\t// standard constructor\n\tvirtual ~EidosTypeTable(void);\n\t\n\t// symbol access; these are variables defined in the global namespace\n\tstd::vector<std::string> AllSymbols(void) const;\n\tstd::vector<EidosGlobalStringID> AllSymbolIDs(void) const;\n\t\n\t// Test for containing a value for a symbol\n\tvirtual bool ContainsSymbol(EidosGlobalStringID p_symbol_name) const;\n\t\n\t// Set as a variable\n\tvoid SetTypeForSymbol(EidosGlobalStringID p_symbol_name, EidosTypeSpecifier p_type);\n\t\n\t// Remove symbols\n\tvoid RemoveTypeForSymbol(EidosGlobalStringID p_symbol_name);\n\tvoid RemoveSymbolsOfClass(const EidosClass *p_object_class);\n\tvoid RemoveAllSymbols(void);\n\t\n\t// Get the type for a symbol\n\tvirtual EidosTypeSpecifier GetTypeForSymbol(EidosGlobalStringID p_symbol_name) const;\n};\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosTypeTable &p_symbols);\n\n\n#endif /* __Eidos__eidos_type_table__ */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_value.cpp",
    "content": "//\n//  eidos_value.cpp\n//  Eidos\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"eidos_value.h\"\n#include \"eidos_functions.h\"\n#include \"eidos_sorting.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_property_signature.h\"\n#include \"json.hpp\"\n\n#include <algorithm>\n#include <utility>\n#include <functional>\n#include <cmath>\n#include \"string.h\"\n\n\n// The global object pool for EidosValue, initialized in Eidos_WarmUp()\nEidosObjectPool *gEidosValuePool = nullptr;\n\n\n//\n//\tGlobal static EidosValue objects; these are effectively const, although EidosValues can't be declared as const.\n//\tInternally, these are implemented as subclasses that terminate if they are dealloced or modified.\n//\n\nEidosValue_VOID_SP gStaticEidosValueVOID;\n\nEidosValue_NULL_SP gStaticEidosValueNULL;\nEidosValue_NULL_SP gStaticEidosValueNULLInvisible;\n\nEidosValue_Logical_SP gStaticEidosValue_Logical_ZeroVec;\nEidosValue_Int_SP gStaticEidosValue_Integer_ZeroVec;\nEidosValue_Float_SP gStaticEidosValue_Float_ZeroVec;\nEidosValue_String_SP gStaticEidosValue_String_ZeroVec;\nEidosValue_Object_SP gStaticEidosValue_Object_ZeroVec;\n\nEidosValue_Logical_SP gStaticEidosValue_LogicalT;\nEidosValue_Logical_SP gStaticEidosValue_LogicalF;\n\nEidosValue_Int_SP gStaticEidosValue_Integer0;\nEidosValue_Int_SP gStaticEidosValue_Integer1;\nEidosValue_Int_SP gStaticEidosValue_Integer2;\nEidosValue_Int_SP gStaticEidosValue_Integer3;\n\nEidosValue_Float_SP gStaticEidosValue_Float0;\nEidosValue_Float_SP gStaticEidosValue_Float0Point5;\nEidosValue_Float_SP gStaticEidosValue_Float1;\nEidosValue_Float_SP gStaticEidosValue_Float10;\nEidosValue_Float_SP gStaticEidosValue_FloatINF;\nEidosValue_Float_SP gStaticEidosValue_FloatNAN;\nEidosValue_Float_SP gStaticEidosValue_FloatE;\nEidosValue_Float_SP gStaticEidosValue_FloatPI;\n\nEidosValue_String_SP gStaticEidosValue_StringEmpty;\nEidosValue_String_SP gStaticEidosValue_StringSpace;\nEidosValue_String_SP gStaticEidosValue_StringAsterisk;\nEidosValue_String_SP gStaticEidosValue_StringDoubleAsterisk;\nEidosValue_String_SP gStaticEidosValue_StringComma;\nEidosValue_String_SP gStaticEidosValue_StringTab;\nEidosValue_String_SP gStaticEidosValue_StringPeriod;\nEidosValue_String_SP gStaticEidosValue_StringDoubleQuote;\nEidosValue_String_SP gStaticEidosValue_String_ECMAScript;\nEidosValue_String_SP gStaticEidosValue_String_indices;\nEidosValue_String_SP gStaticEidosValue_String_average;\n\nEidosClass *gEidosObject_Class = nullptr;\n\n\nstd::string StringForEidosValueType(const EidosValueType p_type)\n{\n\tswitch (p_type)\n\t{\n\t\tcase EidosValueType::kValueVOID:\t\treturn gEidosStr_void;\n\t\tcase EidosValueType::kValueNULL:\t\treturn gEidosStr_NULL;\n\t\tcase EidosValueType::kValueLogical:\t\treturn gEidosStr_logical;\n\t\tcase EidosValueType::kValueString:\t\treturn gEidosStr_string;\n\t\tcase EidosValueType::kValueInt:\t\t\treturn gEidosStr_integer;\n\t\tcase EidosValueType::kValueFloat:\t\treturn gEidosStr_float;\n\t\tcase EidosValueType::kValueObject:\t\treturn gEidosStr_object;\n\t}\n\tEIDOS_TERMINATION << \"ERROR (StringForEidosValueType): (internal error) unrecognized EidosValueType.\" << EidosTerminate();\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosValueType p_type)\n{\n\tp_outstream << StringForEidosValueType(p_type);\n\t\n\treturn p_outstream;\n}\n\nstd::string StringForEidosValueMask(const EidosValueMask p_mask, const EidosClass *p_object_class, const std::string &p_name, EidosValue *p_default)\n{\n\t//\n\t//\tNote this logic is paralleled in +[NSAttributedString eidosAttributedStringForCallSignature:].\n\t//\tThese two should be kept in synch so the user-visible format of signatures is consistent.\n\t//\n\t\n\tif (p_name == gEidosStr_ELLIPSIS)\n\t\treturn gEidosStr_ELLIPSIS;\n\t\n\tstd::string out_string;\n\tbool is_optional = !!(p_mask & kEidosValueMaskOptional);\n\tbool requires_singleton = !!(p_mask & kEidosValueMaskSingleton);\n\tEidosValueMask stripped_mask = p_mask & kEidosValueMaskFlagStrip;\n\t\n\tif (is_optional)\n\t\tout_string += \"[\";\n\t\n\tif (stripped_mask == kEidosValueMaskNone)\t\t\tout_string += \"?\";\n\telse if (stripped_mask == kEidosValueMaskAny)\t\tout_string += \"*\";\n\telse if (stripped_mask == kEidosValueMaskAnyBase)\tout_string += \"+\";\n\telse if (stripped_mask == kEidosValueMaskVOID)\t\tout_string += gEidosStr_void;\n\telse if (stripped_mask == kEidosValueMaskNULL)\t\tout_string += gEidosStr_NULL;\n\telse if (stripped_mask == kEidosValueMaskLogical)\tout_string += gEidosStr_logical;\n\telse if (stripped_mask == kEidosValueMaskString)\tout_string += gEidosStr_string;\n\telse if (stripped_mask == kEidosValueMaskInt)\t\tout_string += gEidosStr_integer;\n\telse if (stripped_mask == kEidosValueMaskFloat)\t\tout_string += gEidosStr_float;\n\telse if (stripped_mask == kEidosValueMaskObject)\tout_string += gEidosStr_object;\n\telse if (stripped_mask == kEidosValueMaskNumeric)\tout_string += gEidosStr_numeric;\n\telse\n\t{\n\t\tif (stripped_mask & kEidosValueMaskVOID)\t\tout_string += \"v\";\n\t\tif (stripped_mask & kEidosValueMaskNULL)\t\tout_string += \"N\";\n\t\tif (stripped_mask & kEidosValueMaskLogical)\t\tout_string += \"l\";\n\t\tif (stripped_mask & kEidosValueMaskInt)\t\t\tout_string += \"i\";\n\t\tif (stripped_mask & kEidosValueMaskFloat)\t\tout_string += \"f\";\n\t\tif (stripped_mask & kEidosValueMaskString)\t\tout_string += \"s\";\n\t\tif (stripped_mask & kEidosValueMaskObject)\t\tout_string += \"o\";\n\t}\n\t\n\tif (p_object_class && (stripped_mask & kEidosValueMaskObject))\n\t{\n\t\tout_string += \"<\";\n\t\tout_string += p_object_class->ClassNameForDisplay();\n\t\tout_string += \">\";\n\t}\n\t\n\tif (requires_singleton)\n\t\tout_string += \"$\";\n\t\n\tif (p_name.length() > 0)\n\t{\n\t\tout_string += \"\\u00A0\";\t// non-breaking space\n\t\tout_string += p_name;\n\t}\n\t\n\tif (is_optional)\n\t{\n\t\tif (p_default && (p_default != gStaticEidosValueNULLInvisible.get()))\n\t\t{\n\t\t\tout_string += \"\\u00A0=\\u00A0\";\n\t\t\t\n\t\t\tstd::ostringstream default_string_stream;\n\t\t\t\n\t\t\tp_default->Print(default_string_stream);\n\t\t\t\n\t\t\tout_string += default_string_stream.str();\n\t\t}\n\t\t\n\t\tout_string += \"]\";\n\t}\n\t\n\treturn out_string;\n}\n\n\n#pragma mark -\n#pragma mark Comparing EidosValues\n#pragma mark -\n\nEidosValueType EidosTypeForPromotion(EidosValueType p_type1, EidosValueType p_type2, const EidosToken *p_blame_token)\n{\n\tif ((p_type1 == EidosValueType::kValueVOID) || (p_type2 == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosTypeForPromotion): (internal error) comparison with void is illegal.\" << EidosTerminate(p_blame_token);\n\tif ((p_type1 == EidosValueType::kValueNULL) || (p_type2 == EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosTypeForPromotion): (internal error) comparison with NULL is illegal.\" << EidosTerminate(p_blame_token);\n\t\n\t// comparing one object to another is legal, but objects cannot be compared to other types\n\t// note that comparisons between objects and non-objects are not flagged here;\n\t// they error out later, when the object operand is cast to the other type\n\tif ((p_type1 == EidosValueType::kValueObject) && (p_type2 == EidosValueType::kValueObject))\n\t\treturn EidosValueType::kValueObject;\n\t\n\t// string is the highest type, so we promote to string if either operand is a string\n\tif ((p_type1 == EidosValueType::kValueString) || (p_type2 == EidosValueType::kValueString))\n\t\treturn EidosValueType::kValueString;\n\t\n\t// float is the next highest type, so we promote to float if either operand is a float\n\tif ((p_type1 == EidosValueType::kValueFloat) || (p_type2 == EidosValueType::kValueFloat))\n\t\treturn EidosValueType::kValueFloat;\n\t\n\t// int is the next highest type, so we promote to int if either operand is a int\n\tif ((p_type1 == EidosValueType::kValueInt) || (p_type2 == EidosValueType::kValueInt))\n\t\treturn EidosValueType::kValueInt;\n\t\n\t// logical is the next highest type, so we promote to logical if either operand is a logical\n\tif ((p_type1 == EidosValueType::kValueLogical) || (p_type2 == EidosValueType::kValueLogical))\n\t\treturn EidosValueType::kValueLogical;\n\t\n\t// that's the end of the road; we should never reach this point\n\tEIDOS_TERMINATION << \"ERROR (EidosTypeForPromotion): (internal error) promotion involving type \" << p_type1 << \" and type \" << p_type2 << \" is undefined.\" << EidosTerminate(p_blame_token);\n}\n\nbool CompareEidosValues(const EidosValue &p_value1, int p_index1, const EidosValue &p_value2, int p_index2, EidosComparisonOperator p_operator, const EidosToken *p_blame_token)\n{\n\tEidosValueType type1 = p_value1.Type(), type2 = p_value2.Type();\n\t\n\tif ((type1 == EidosValueType::kValueVOID) || (type2 == EidosValueType::kValueVOID))\n\t\tEIDOS_TERMINATION << \"ERROR (CompareEidosValues): (internal error) comparison with void is illegal.\" << EidosTerminate(p_blame_token);\n\tif ((type1 == EidosValueType::kValueNULL) || (type2 == EidosValueType::kValueNULL))\n\t\tEIDOS_TERMINATION << \"ERROR (CompareEidosValues): (internal error) comparison with NULL is illegal.\" << EidosTerminate(p_blame_token);\n\t\n\t// comparing one object to another is legal, but objects cannot be compared to other types\n\tif ((type1 == EidosValueType::kValueObject) && (type2 == EidosValueType::kValueObject))\n\t{\n\t\tEidosObject *element1 = p_value1.ObjectElementAtIndex_NOCAST(p_index1, p_blame_token);\n\t\tEidosObject *element2 = p_value2.ObjectElementAtIndex_NOCAST(p_index2, p_blame_token);\n\t\t\n\t\tif (p_operator == EidosComparisonOperator::kEqual)\t\t\treturn (element1 == element2);\n\t\telse if (p_operator == EidosComparisonOperator::kNotEqual)\treturn (element1 != element2);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (CompareEidosValues): (internal error) objects may only be compared with == and !=.\" << EidosTerminate(p_blame_token);\n\t}\n\t\n\t// string is the highest type, so we promote to string if either operand is a string\n\tif ((type1 == EidosValueType::kValueString) || (type2 == EidosValueType::kValueString))\n\t{\n\t\tstd::string string1 = p_value1.StringAtIndex_CAST(p_index1, p_blame_token);\n\t\tstd::string string2 = p_value2.StringAtIndex_CAST(p_index2, p_blame_token);\n\t\tint compare_result = string1.compare(string2);\t\t// not guaranteed to be -1 / 0 / +1, just negative / 0 / positive\n\t\t\n\t\tswitch (p_operator) {\n\t\t\tcase EidosComparisonOperator::kLess:\t\t\treturn (compare_result < 0);\n\t\t\tcase EidosComparisonOperator::kLessOrEqual:\t\treturn (compare_result <= 0);\n\t\t\tcase EidosComparisonOperator::kEqual:\t\t\treturn (compare_result == 0);\n\t\t\tcase EidosComparisonOperator::kGreaterOrEqual:\treturn (compare_result >= 0);\n\t\t\tcase EidosComparisonOperator::kGreater:\t\t\treturn (compare_result > 0);\n\t\t\tcase EidosComparisonOperator::kNotEqual:\t\treturn (compare_result != 0);\n\t\t}\n\t}\n\t\n\t// float is the next highest type, so we promote to float if either operand is a float\n\tif ((type1 == EidosValueType::kValueFloat) || (type2 == EidosValueType::kValueFloat))\n\t{\n\t\tdouble float1 = p_value1.FloatAtIndex_CAST(p_index1, p_blame_token);\n\t\tdouble float2 = p_value2.FloatAtIndex_CAST(p_index2, p_blame_token);\n\t\t\n\t\tswitch (p_operator) {\n\t\t\tcase EidosComparisonOperator::kLess:\t\t\treturn (float1 < float2);\n\t\t\tcase EidosComparisonOperator::kLessOrEqual:\t\treturn (float1 <= float2);\n\t\t\tcase EidosComparisonOperator::kEqual:\t\t\treturn (float1 == float2);\n\t\t\tcase EidosComparisonOperator::kGreaterOrEqual:\treturn (float1 >= float2);\n\t\t\tcase EidosComparisonOperator::kGreater:\t\t\treturn (float1 > float2);\n\t\t\tcase EidosComparisonOperator::kNotEqual:\t\treturn (float1 != float2);\n\t\t}\n\t}\n\t\n\t// int is the next highest type, so we promote to int if either operand is a int\n\tif ((type1 == EidosValueType::kValueInt) || (type2 == EidosValueType::kValueInt))\n\t{\n\t\tint64_t int1 = p_value1.IntAtIndex_CAST(p_index1, p_blame_token);\n\t\tint64_t int2 = p_value2.IntAtIndex_CAST(p_index2, p_blame_token);\n\t\t\n\t\tswitch (p_operator) {\n\t\t\tcase EidosComparisonOperator::kLess:\t\t\treturn (int1 < int2);\n\t\t\tcase EidosComparisonOperator::kLessOrEqual:\t\treturn (int1 <= int2);\n\t\t\tcase EidosComparisonOperator::kEqual:\t\t\treturn (int1 == int2);\n\t\t\tcase EidosComparisonOperator::kGreaterOrEqual:\treturn (int1 >= int2);\n\t\t\tcase EidosComparisonOperator::kGreater:\t\t\treturn (int1 > int2);\n\t\t\tcase EidosComparisonOperator::kNotEqual:\t\treturn (int1 != int2);\n\t\t}\n\t}\n\t\n\t// logical is the next highest type, so we promote to logical if either operand is a logical\n\tif ((type1 == EidosValueType::kValueLogical) || (type2 == EidosValueType::kValueLogical))\n\t{\n\t\teidos_logical_t logical1 = p_value1.LogicalAtIndex_CAST(p_index1, p_blame_token);\n\t\teidos_logical_t logical2 = p_value2.LogicalAtIndex_CAST(p_index2, p_blame_token);\n\t\t\n\t\tswitch (p_operator) {\n\t\t\tcase EidosComparisonOperator::kLess:\t\t\treturn (logical1 < logical2);\n\t\t\tcase EidosComparisonOperator::kLessOrEqual:\t\treturn (logical1 <= logical2);\n\t\t\tcase EidosComparisonOperator::kEqual:\t\t\treturn (logical1 == logical2);\n\t\t\tcase EidosComparisonOperator::kGreaterOrEqual:\treturn (logical1 >= logical2);\n\t\t\tcase EidosComparisonOperator::kGreater:\t\t\treturn (logical1 > logical2);\n\t\t\tcase EidosComparisonOperator::kNotEqual:\t\treturn (logical1 != logical2);\n\t\t}\n\t}\n\t\n\t// that's the end of the road; we should never reach this point\n\tEIDOS_TERMINATION << \"ERROR (CompareEidosValues): (internal error) comparison involving type \" << type1 << \" and type \" << type2 << \" is undefined.\" << EidosTerminate(p_blame_token);\n}\n\n\n//\n//\tEidosValue\n//\n#pragma mark -\n#pragma mark EidosValue\n#pragma mark -\n\n#ifdef EIDOS_TRACK_VALUE_ALLOCATION\nint EidosValue::valueTrackingCount;\nstd::vector<EidosValue *> EidosValue::valueTrackingVector;\n#endif\n\neidos_logical_t EidosValue::LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::LogicalAtIndex_CAST): operand type \" << this->Type() << \" cannot be converted to type logical.\" << EidosTerminate(p_blame_token);\n}\n\nstd::string EidosValue::StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::StringAtIndex_CAST): operand type \" << this->Type() << \" cannot be converted to type string.\" << EidosTerminate(p_blame_token);\n}\n\nint64_t EidosValue::IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::IntAtIndex_CAST): operand type \" << this->Type() << \" cannot be converted to type integer.\" << EidosTerminate(p_blame_token);\n}\n\ndouble EidosValue::FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::FloatAtIndex_CAST): operand type \" << this->Type() << \" cannot be converted to type float.\" << EidosTerminate(p_blame_token);\n}\n\nEidosObject *EidosValue::ObjectElementAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::ObjectElementAtIndex_CAST): operand type \" << this->Type() << \" cannot be converted to type object.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue::RaiseForIncorrectTypeCall(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::RaiseForIncorrectTypeCall): (internal error) direct vector access attempted on an EidosValue type of the incorrect type.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosValue::RaiseForImmutabilityCall(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::RaiseForImmutabilityCall): (internal error) mutable direct vector access attempted on an immutable EidosValue.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosValue::RaiseForCapacityViolation(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::RaiseForCapacityViolation): (internal error) access violated the current capacity of an EidosValue.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosValue::RaiseForRangeViolation(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::RaiseForRangeViolation): (internal error) access violated the current size of an EidosValue.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosValue::RaiseForRetainReleaseViolation(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue::RaiseForRetainReleaseViolation): (internal error) access violated the retain/release policy of an EidosValue.\" << EidosTerminate(nullptr);\n}\n\nbool EidosValue::MatchingDimensions(const EidosValue *p_value1, const EidosValue *p_value2)\n{\n\tint x_dimcount = p_value1->DimensionCount();\n\tint y_dimcount = p_value2->DimensionCount();\n\t\n\tif (x_dimcount != y_dimcount)\n\t\treturn false;\n\t\n\tconst int64_t *x_dims = p_value1->Dimensions();\n\tconst int64_t *y_dims = p_value2->Dimensions();\n\t\n\tif ((x_dims && !y_dims) || (!x_dims && y_dims))\t\t// should never happen\n\t\treturn false;\n\t\n\tif (x_dims && y_dims)\n\t{\n\t\tfor (int dim_index = 0; dim_index < x_dimcount; ++dim_index)\n\t\t\tif (x_dims[dim_index] != y_dims[dim_index])\n\t\t\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\nvoid EidosValue::_CopyDimensionsFromValue(const EidosValue *p_value)\n{\n\tWILL_MODIFY(this);\n\t\n\tint64_t *source_dims = p_value->dim_;\n\t\n\t// First check that the source's dimensions will work for us; we assume they work for the source, so rather than\n\t// multiplying them out we can just compare total sizes.  We only need to check this if the source is an array.\n\tif (source_dims)\n\t{\n\t\tint count = Count();\n\t\tint source_count = p_value->Count();\n\t\t\n\t\tif (count != source_count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::_CopyDimensionsFromValue): mismatch between vector length and requested dimensions.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// OK, the source's dimensions work; assume that we need to throw out our existing dimensions (virtually\n\t\t// always true, since this is generally called on new EidosValues), and malloc and copy a new dim_ buffer.\n\t\tfree(dim_);\n\t\tdim_ = nullptr;\n\t\t\n\t\tint64_t dim_count = *source_dims;\n\t\t\n\t\tdim_ = (int64_t *)malloc((dim_count + 1) * sizeof(int64_t));\n\t\tif (!dim_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::_CopyDimensionsFromValue): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tmemcpy(dim_, source_dims, (dim_count + 1) * sizeof(int64_t));\n\t}\n\telse\n\t{\n\t\t// The source has no dimensions, so we just need to throw out any dimensions we have.\n\t\tfree(dim_);\n\t\tdim_ = nullptr;\n\t}\n}\n\nvoid EidosValue::SetDimensions(int64_t p_dim_count, const int64_t *p_dim_buffer)\n{\n\tWILL_MODIFY(this);\n\t\n\tif ((p_dim_count == 1) && !p_dim_buffer)\n\t{\n\t\t// Make the value a plain vector; throw out any dimensions we have.\n\t\tfree(dim_);\n\t\tdim_ = nullptr;\n\t}\n\telse if ((p_dim_count >= 2) && p_dim_buffer)\n\t{\n\t\t// A matrix or array is requested; first check that our size fits the request\n\t\tint64_t dim_product = 1;\n\t\t\n\t\tfor (int dim_index = 0; dim_index < p_dim_count; ++dim_index)\n\t\t{\n\t\t\tint64_t dim = p_dim_buffer[dim_index];\n\t\t\t\n\t\t\tif (dim <= 0)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::SetDimensions): dimension <= 0 requested, which is not allowed.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tint64_t old_product = dim_product;\n\t\t\t\n\t\t\tdim_product *= dim;\n\t\t\tif (dim_product / dim != old_product)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::SetDimensions): dimension overflow; product of dimensions exceeds maximum capacity.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tint count = Count();\n\t\t\n\t\tif (dim_product != count)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::SetDimensions): mismatch between vector length and requested dimensions.\" << EidosTerminate(nullptr);\n\t\t\n\t\t// OK, the size works and the individual dimensions check out, so make our dim_ buffer\n\t\tfree(dim_);\n\t\tdim_ = nullptr;\n\t\t\n\t\tdim_ = (int64_t *)malloc((p_dim_count + 1) * sizeof(int64_t));\n\t\tif (!dim_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::SetDimensions): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\n\t\tdim_[0] = p_dim_count;\n\t\tmemcpy(dim_ + 1, p_dim_buffer, p_dim_count * sizeof(int64_t));\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::SetDimensions): nonsensical requested dimensions.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosValue::Subset(std::vector<std::vector<int64_t>> &p_inclusion_indices, bool p_drop, const EidosToken *p_blame_token)\n{\n\tEidosValue_SP result_SP;\n\t\n\tint dimcount = DimensionCount();\n\tconst int64_t *dims = Dimensions();\n\tstd::vector<int> inclusion_counts;\n\tbool empty_dimension = false;\n\t\n\tif ((int)p_inclusion_indices.size() != dimcount)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::Subset): (internal error) size of p_inclusion_indices does not match dimension count of value.\" << EidosTerminate(nullptr);\n\t\n\tfor (int dim_index = 0; dim_index < dimcount; ++dim_index)\n\t{\n\t\tint dim_size = (int)p_inclusion_indices[dim_index].size();\n\t\t\n\t\tif (dim_size == 0)\n\t\t\tempty_dimension = true;\n\t\t\n\t\tinclusion_counts.emplace_back(dim_size);\n\t}\n\t\n\tif (empty_dimension)\n\t{\n\t\t// If there was a dimension where no index was included, the result is an empty vector of the right type\n\t\tresult_SP = NewMatchingType();\n\t}\n\telse\n\t{\n\t\t// We have tabulated the subsets; now copy the included values into the result.  To do this, we count up in the base\n\t\t// system established by inclusion_counts, and add the referenced value at each step along the way.\n\t\tresult_SP = NewMatchingType();\n\t\t\n\t\tstd::vector<int> generating_counter(dimcount, 0);\n\t\t\n\t\tdo\n\t\t{\n\t\t\t// add the value referenced by generating_counter in inclusion_indices\n\t\t\tint64_t referenced_index = 0;\n\t\t\tint64_t dim_skip = 1;\n\t\t\t\n\t\t\tfor (int counter_index = 0; counter_index < dimcount; ++counter_index)\n\t\t\t{\n\t\t\t\tint counter_value = generating_counter[counter_index];\n\t\t\t\tint64_t inclusion_index_value = p_inclusion_indices[counter_index][counter_value];\n\t\t\t\t\n\t\t\t\treferenced_index += inclusion_index_value * dim_skip;\n\t\t\t\t\n\t\t\t\tdim_skip *= dims[counter_index];\n\t\t\t}\n\t\t\t\n\t\t\tresult_SP->PushValueFromIndexOfEidosValue((int)referenced_index, *this, p_blame_token);\n\t\t\t\n\t\t\t// increment generating_counter in the base system of inclusion_counts\n\t\t\tint generating_counter_index = 0;\n\t\t\t\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (++generating_counter[generating_counter_index] == inclusion_counts[generating_counter_index])\n\t\t\t\t{\n\t\t\t\t\tgenerating_counter[generating_counter_index] = 0;\n\t\t\t\t\tgenerating_counter_index++;\t\t// carry\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\twhile (generating_counter_index < dimcount);\n\t\t\t\n\t\t\t// if we carried out off the top, we are done adding included values\n\t\t\tif (generating_counter_index == dimcount)\n\t\t\t\tbreak;\n\t\t}\n\t\twhile (true);\n\t\t\n\t\t// Finally, set the dimensionality of the result, considering dropped dimensions.  This basically follows the structure\n\t\t// of the indexed operand's dimensions, but (a) resizes to match the size of p_inclusion_indices for the given dimension,\n\t\t// and (b) omits any dimension that has a count of exactly 1, if dropping is requested.\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosValue::Subset(): usage of statics\");\n\t\t\n\t\tstatic int64_t *static_dim_buffer = nullptr;\n\t\tstatic int static_dim_buffer_size = -1;\n\t\t\n\t\tif (dimcount > static_dim_buffer_size)\n\t\t{\n\t\t\tstatic_dim_buffer = (int64_t *)realloc(static_dim_buffer, (dimcount + 1) * sizeof(int64_t));\t// +1 so the zero case doesn't result in a zero-size allocation\t\t// NOLINT(*-realloc-usage) : realloc failure is a fatal error anyway\n\t\t\tif (!static_dim_buffer)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::Subset): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tstatic_dim_buffer_size = dimcount;\n\t\t}\n\t\t\n\t\tint final_dim_count = 0;\n\t\t\n\t\tfor (int subset_index = 0; subset_index < dimcount; ++subset_index)\n\t\t{\n\t\t\tint dim_size = inclusion_counts[subset_index];\n\t\t\t\n\t\t\tif (!p_drop || (dim_size > 1))\n\t\t\t\tstatic_dim_buffer[final_dim_count++] = dim_size;\n\t\t}\n\t\t\n\t\tif (final_dim_count > 1)\n\t\t\tresult_SP->SetDimensions(final_dim_count, static_dim_buffer);\n\t}\n\t\n\treturn result_SP;\n}\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosValue &p_value)\n{\n\tp_value.Print(p_outstream);\t\t// get dynamic dispatch\n\t\n\treturn p_outstream;\n}\n\nvoid EidosValue::PrintMatrixFromIndex(int64_t p_ncol, int64_t p_nrow, int64_t p_start_index, std::ostream &p_ostream, const std::string &p_indent) const\n{\n\tint64_t element_count = p_ncol * p_nrow;\n\t\n\t// assemble all of the value strings, for printing with alignment\n\tstd::vector<std::string> element_strings;\n\t\n\tfor (int64_t element_index = 0; element_index < element_count; ++element_index)\n\t{\n\t\tstd::ostringstream oss;\n\t\t\n\t\tPrintValueAtIndex((int)(element_index + p_start_index), oss);\n\t\telement_strings.emplace_back(oss.str());\n\t}\n\t\n\t// find the widest element, including column headers\n\tint max_element_width = 0;\n\t\n\tfor (int64_t element_index = 0; element_index < element_count; ++element_index)\n\t\tmax_element_width = std::max(max_element_width, (int)element_strings[element_index].length());\n\t\n\tmax_element_width = std::max(max_element_width, (p_ncol == 1) ? 4 : ((int)floor(log10(p_ncol - 1)) + 4));\n\t\n\tint max_rowcol_width = (p_nrow == 1) ? 4 : ((int)floor(log10(p_nrow - 1)) + 4);\n\t\n\t// print the upper left corner padding\n\tp_ostream << p_indent << std::string(max_rowcol_width, ' ');\n\t\n\t// print the column headers\n\tfor (int col_index = 0; col_index < p_ncol; ++col_index)\n\t{\n\t\t// pad before column header\n\t\t{\n\t\t\tint element_width = (col_index == 0) ? 4 : ((int)floor(log10(col_index)) + 4);\n\t\t\t\n\t\t\tp_ostream << std::string((max_element_width - element_width) + 1, ' ');\n\t\t}\n\t\t\n\t\t// column header\n\t\tp_ostream << \"[,\" << col_index << \"]\";\n\t}\n\t\n\t// print each row\n\tfor (int row_index = 0; row_index < p_nrow; ++row_index)\n\t{\n\t\tp_ostream << std::endl << p_indent;\n\t\t\n\t\t// pad before row index\n\t\t{\n\t\t\tint element_width = (row_index == 0) ? 4 : ((int)floor(log10(row_index)) + 4);\n\t\t\t\n\t\t\tp_ostream << std::string(max_rowcol_width - element_width, ' ');\n\t\t}\n\t\t\n\t\t// row index\n\t\tp_ostream << '[' << row_index << \",]\";\n\t\t\n\t\t// row contents\n\t\tfor (int col_index = 0; col_index < p_ncol; ++col_index)\n\t\t{\n\t\t\tstd::string &element_string = element_strings[row_index + col_index * p_nrow];\n\t\t\tint element_width = (int)element_string.length();\n\t\t\t\n\t\t\tp_ostream << std::string((max_element_width - element_width) + 1, ' ') << element_string;\n\t\t}\n\t}\n}\n\nvoid EidosValue::Print(std::ostream &p_ostream, const std::string &p_indent) const\n{\n\tint count = Count();\n\t\n\tif (count == 0)\n\t{\n\t\t// standard format for zero-length vectors\n\t\tEidosValueType type = Type();\n\t\t\n\t\tp_ostream << p_indent;\n\t\t\n\t\tswitch (type)\n\t\t{\n\t\t\tcase EidosValueType::kValueVOID:\tp_ostream << gEidosStr_void; break;\n\t\t\tcase EidosValueType::kValueNULL:\tp_ostream << gEidosStr_NULL; break;\n\t\t\tcase EidosValueType::kValueLogical:\n\t\t\tcase EidosValueType::kValueInt:\n\t\t\tcase EidosValueType::kValueFloat:\n\t\t\tcase EidosValueType::kValueString:\tp_ostream << ElementType() << \"(0)\"; break;\n\t\t\tcase EidosValueType::kValueObject:\tp_ostream << \"object()<\" << ElementType() << \">\"; break;\n\t\t}\n\t}\n\telse if (!dim_)\n\t{\n\t\t// print vectors by just spewing out individual values\n\t\tp_ostream << p_indent;\n\t\t\n\t\tfor (int value_index = 0; value_index < count; ++value_index)\n\t\t{\n\t\t\tif (value_index > 0)\n\t\t\t\tp_ostream << ' ';\n\t\t\t\n\t\t\tPrintValueAtIndex(value_index, p_ostream);\n\t\t}\n\t}\n\telse if (dim_[0] == 2)\n\t{\n\t\tPrintMatrixFromIndex(dim_[2], dim_[1], 0, p_ostream, p_indent);\n\t}\n\telse if (dim_[0] > 2)\n\t{\n\t\t// print arrays by looping over dimensions\n\t\tint64_t dim_count = dim_[0];\n\t\tint64_t matrix_skip = dim_[1] * dim_[2];\t// number of elements in each nxm matrix slice\n\t\tint64_t array_dim_count = dim_count - 2;\t// this many additional dimensions of nxm matrix slices\n\t\tint64_t *array_dim_indices = (int64_t *)calloc(array_dim_count, sizeof(int64_t));\n\t\tint64_t *array_dim_skip = (int64_t *)calloc(array_dim_count, sizeof(int64_t));\n\t\t\n\t\tif (!array_dim_indices || !array_dim_skip)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::Print): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tarray_dim_skip[0] = matrix_skip;\n\t\tfor (int array_dim_index = 1; array_dim_index < array_dim_count; ++array_dim_index)\n\t\t\tarray_dim_skip[array_dim_index] = array_dim_skip[array_dim_index - 1] * dim_[array_dim_index + 2];\n\t\t\n\t\tdo\n\t\t{\n\t\t\t// print an index line before the matrix\n\t\t\tp_ostream << p_indent << \", \";\n\t\t\t\n\t\t\tfor (int idx = 0; idx < array_dim_count; ++idx)\n\t\t\t\tp_ostream << \", \" << array_dim_indices[idx];\n\t\t\t\n\t\t\tp_ostream << std::endl << p_indent << std::endl;\n\t\t\t\n\t\t\t// print out the matrix for this slice\n\t\t\tint slice_offset = 0;\n\t\t\t\n\t\t\tfor (int idx = 0; idx < array_dim_count; ++idx)\n\t\t\t\tslice_offset += array_dim_skip[idx] * array_dim_indices[idx];\n\t\t\t\n\t\t\tPrintMatrixFromIndex(dim_[2], dim_[1], slice_offset, p_ostream, p_indent);\n\t\t\t\n\t\t\t// increment dim_indices; this is counting up in a weird mixed-base system\n\t\t\tint count_index;\n\t\t\t\n\t\t\tfor (count_index = 0; count_index < array_dim_count; ++count_index)\n\t\t\t{\n\t\t\t\tif (++(array_dim_indices[count_index]) == dim_[count_index + 3])\n\t\t\t\t\tarray_dim_indices[count_index] = 0;\t\t// carry\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tif (count_index == array_dim_count)\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tp_ostream << std::endl << p_indent << std::endl;\n\t\t}\n\t\twhile (true);\n\t\t\n\t\tfree(array_dim_indices);\n\t\tfree(array_dim_skip);\n\t}\n\telse\n\t{\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue::Print): (internal error) illegal dimension count \" << dim_[0] << \".\" << EidosTerminate(nullptr);\n\t}\n}\n\nvoid EidosValue::PrintStructure(std::ostream &p_ostream, int max_values) const\n{\n\tEidosValueType x_type = Type();\n\tint x_count = Count();\n\tint x_dimcount = DimensionCount();\n\tconst int64_t *x_dims = Dimensions();\n\t\n\tif (x_count == 0)\n\t{\n\t\t// zero-length vectors get printed according to the standard code in EidosValue\n\t\tPrint(p_ostream);\n\t}\n\telse\n\t{\n\t\t// start with the type, and then the class for object-type values\n\t\tp_ostream << x_type;\n\t\t\n\t\tif (x_type == EidosValueType::kValueObject)\n\t\t\tp_ostream << \"<\" << ElementType() << \">\";\n\t\t\n\t\t// then print the ranges for each dimension\n\t\tp_ostream << \" [\";\n\t\t\n\t\tif (x_dimcount == 1)\n\t\t\tp_ostream << \"0:\" << (x_count - 1) << \"]\";\n\t\telse\n\t\t{\n\t\t\tfor (int dim_index = 0; dim_index < x_dimcount; ++dim_index)\n\t\t\t{\n\t\t\t\tif (dim_index > 0)\n\t\t\t\t\tp_ostream << \", \";\n\t\t\t\tp_ostream << \"0:\" << (x_dims[dim_index] - 1);\n\t\t\t}\n\t\t\t\n\t\t\tp_ostream << \"]\";\n\t\t}\n\t\t\n\t\t// finally, print up to max_values values, if available, followed by an ellipsis if not all values were printed\n\t\tif (max_values > 0)\n\t\t{\n\t\t\tp_ostream << \" \";\n\t\t\t\n\t\t\tint output_count = std::min(max_values, x_count);\n\t\t\t\n\t\t\tfor (int output_index = 0; output_index < output_count; ++output_index)\n\t\t\t{\n\t\t\t\tEidosValue_SP value = GetValueAtIndex(output_index, nullptr);\n\t\t\t\t\n\t\t\t\tif (output_index > 0)\n\t\t\t\t\tp_ostream << gEidosStr_space_string;\n\t\t\t\t\n\t\t\t\tp_ostream << *value;\n\t\t\t}\n\t\t\t\n\t\t\tif (x_count > output_count)\n\t\t\t\tp_ostream << \" ...\";\n\t\t}\n\t}\n}\n\n\n//\n//\tEidosValue_VOID\n//\n#pragma mark -\n#pragma mark EidosValue_VOID\n#pragma mark -\n\nconst std::string &EidosValue_VOID::ElementType(void) const\n{\n\treturn gEidosStr_void;\n}\n\nvoid EidosValue_VOID::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n#pragma unused(p_idx)\n\tp_ostream << gEidosStr_void;\n}\n\nnlohmann::json EidosValue_VOID::JSONRepresentation(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::JSONRepresentation): (internal error) illegal on void.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosValue_VOID::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx, p_blame_token)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::GetValueAtIndex): (internal error) illegal on void.\" << EidosTerminate(p_blame_token);\n}\n\nEidosValue_SP EidosValue_VOID::CopyValues(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::CopyValues): (internal error) illegal on void.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosValue_VOID::NewMatchingType(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::NewMatchingType): (internal error) illegal on void.\" << EidosTerminate(nullptr);\n}\n\nvoid EidosValue_VOID::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n#pragma unused(p_idx, p_source_script_value)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::PushValueFromIndexOfEidosValue): (internal error) illegal on void.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_VOID::Sort(bool p_ascending)\n{\n#pragma unused(p_ascending)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_VOID::Sort): (internal error) illegal on void.\" << EidosTerminate(nullptr);\n}\n\n\n//\n//\tEidosValue_NULL\n//\n#pragma mark -\n#pragma mark EidosValue_NULL\n#pragma mark -\n\nconst std::string &EidosValue_NULL::ElementType(void) const\n{\n\treturn gEidosStr_NULL;\n}\n\nvoid EidosValue_NULL::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n#pragma unused(p_idx)\n\tp_ostream << gEidosStr_NULL;\n}\n\nnlohmann::json EidosValue_NULL::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object;\t\t// this will come out as a JSON \"null\"\n\t\n\treturn json_object;\n}\n\nEidosValue_SP EidosValue_NULL::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n#pragma unused(p_idx, p_blame_token)\n\treturn gStaticEidosValueNULL;\n}\n\nEidosValue_SP EidosValue_NULL::CopyValues(void) const\n{\n\treturn gStaticEidosValueNULL;\n}\n\nEidosValue_SP EidosValue_NULL::NewMatchingType(void) const\n{\n\treturn gStaticEidosValueNULL;\n}\n\nvoid EidosValue_NULL::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n#pragma unused(p_idx)\n\tWILL_MODIFY(this);\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueNULL)\n\t\t;\t// NULL doesn't have values or indices, so this is a no-op\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_NULL::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_NULL::Sort(bool p_ascending)\n{\n#pragma unused(p_ascending)\n\tWILL_MODIFY(this);\n\t\n\t// nothing to do\n}\n\n\n//\n//\tEidosValue_Logical\n//\n#pragma mark -\n#pragma mark EidosValue_Logical\n#pragma mark -\n\nEidosValue_Logical::EidosValue_Logical(const std::vector<eidos_logical_t> &p_logicalvec) : EidosValue(EidosValueType::kValueLogical)\n{\n\tsize_t count = p_logicalvec.size();\n\tconst eidos_logical_t *values = p_logicalvec.data();\n\t\n\tresize_no_initialize(count);\n\t\n\tfor (size_t index = 0; index < count; ++index)\n\t\tset_logical_no_check(values[index], index);\n}\n\nEidosValue_Logical::EidosValue_Logical(eidos_logical_t p_logical1) : EidosValue(EidosValueType::kValueLogical)\t// protected\n{\n\tpush_logical(p_logical1);\n}\n\nEidosValue_Logical::EidosValue_Logical(std::initializer_list<eidos_logical_t> p_init_list) : EidosValue(EidosValueType::kValueLogical)\n{\n\treserve(p_init_list.size());\n\t\n\tfor (auto init_item : p_init_list)\n\t\tpush_logical_no_check(init_item);\n}\n\nEidosValue_Logical::EidosValue_Logical(const eidos_logical_t *p_values, size_t p_count) : EidosValue(EidosValueType::kValueLogical)\n{\n\tresize_no_initialize(p_count);\n\t\n\tfor (size_t index = 0; index < p_count; ++index)\n\t\tset_logical_no_check(p_values[index], index);\n}\n\nconst std::string &EidosValue_Logical::ElementType(void) const\n{\n\treturn gEidosStr_logical;\n}\n\nvoid EidosValue_Logical::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n\teidos_logical_t value = values_[p_idx];\n\t\n\tp_ostream << (value ? gEidosStr_T : gEidosStr_F);\n}\n\nnlohmann::json EidosValue_Logical::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object = nlohmann::json::array();\t// always write as an array, for consistency; makes automated parsing easier\n\tint count = Count();\n\t\n\tfor (int i = 0; i < count; ++i)\n\t\tjson_object.emplace_back(values_[i] ? true : false);\n\t\n\treturn json_object;\n}\n\neidos_logical_t EidosValue_Logical::LogicalAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::LogicalAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\neidos_logical_t EidosValue_Logical::LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::LogicalAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nstd::string EidosValue_Logical::StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::StringAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx] ? gEidosStr_T : gEidosStr_F);\n}\n\nint64_t EidosValue_Logical::IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::IntAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx] ? 1 : 0);\n}\n\ndouble EidosValue_Logical::FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::FloatAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx] ? 1.0 : 0.0);\n}\n\nEidosValue_SP EidosValue_Logical::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::GetValueAtIndex): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx] ? gStaticEidosValue_LogicalT : gStaticEidosValue_LogicalF);\n}\n\nEidosValue_SP EidosValue_Logical::CopyValues(void) const\n{\n\t// note that constness, invisibility, etc. do not get copied\n\treturn EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Logical(values_, count_))->CopyDimensionsFromValue(this));\n}\n\nEidosValue_SP EidosValue_Logical::NewMatchingType(void) const\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Logical());\n}\n\nvoid EidosValue_Logical::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueLogical)\n\t\tpush_logical(p_source_script_value.LogicalAtIndex_NOCAST(p_idx, p_blame_token));\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_Logical::Sort(bool p_ascending)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_ascending)\n\t\tstd::sort(values_, values_ + count_);\n\telse\n\t\tstd::sort(values_, values_ + count_, std::greater<eidos_logical_t>());\n}\n\nEidosValue_Logical *EidosValue_Logical::reserve(size_t p_reserved_size)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_reserved_size > capacity_)\n\t{\n\t\tvalues_ = (eidos_logical_t *)realloc(values_, p_reserved_size * sizeof(eidos_logical_t));\n\t\tif (!values_)\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Logical::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\n\t\tcapacity_ = p_reserved_size;\n\t}\n\t\n\treturn this;\n}\n\nvoid EidosValue_Logical::erase_index(size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_index >= count_)\n\t\tRaiseForRangeViolation();\n\t\n\tif (p_index == count_ - 1)\n\t\t--count_;\n\telse\n\t{\n\t\teidos_logical_t *element_ptr = values_ + p_index;\n\t\teidos_logical_t *next_element_ptr = values_ + p_index + 1;\n\t\teidos_logical_t *past_end_element_ptr = values_ + count_;\n\t\tsize_t element_copy_count = past_end_element_ptr - next_element_ptr;\n\t\t\n\t\tmemmove(element_ptr, next_element_ptr, element_copy_count * sizeof(eidos_logical_t));\n\t\t\n\t\t--count_;\n\t}\n}\n\n\n//\n//\tEidosValue_String\n//\n#pragma mark -\n#pragma mark EidosValue_String\n#pragma mark -\n\nEidosValue_String::EidosValue_String(const std::vector<std::string> &p_stringvec) : EidosValue(EidosValueType::kValueString), values_(p_stringvec)\n{\n}\n\nEidosValue_String::EidosValue_String(std::initializer_list<const std::string> p_init_list) : EidosValue(EidosValueType::kValueString)\n{\n\tfor (const auto &init_item : p_init_list)\n\t\tvalues_.emplace_back(init_item);\n}\n\nEidosValue_String::EidosValue_String(std::initializer_list<const char *> p_init_list) : EidosValue(EidosValueType::kValueString)\n{\n\tfor (const auto &init_item : p_init_list)\n\t\tvalues_.emplace_back(init_item);\n}\n\nconst std::string &EidosValue_String::ElementType(void) const\n{\n\treturn gEidosStr_string;\n}\n\nEidosValue_SP EidosValue_String::NewMatchingType(void) const\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String());\n}\n\nvoid EidosValue_String::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n\tconst std::string &value = StringRefAtIndex_NOCAST(p_idx, nullptr);\n\t\n\t// Emit a quoted string with backslash escapes as needed\n\tp_ostream << Eidos_string_escaped(value, EidosStringQuoting::kChooseQuotes);\n}\n\nnlohmann::json EidosValue_String::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object = nlohmann::json::array();\t// always write as an array, for consistency; makes automated parsing easier\n\tint count = Count();\n\t\n\tfor (int i = 0; i < count; ++i)\n\t\tjson_object.emplace_back(StringAtIndex_NOCAST(i, nullptr));\n\t\n\treturn json_object;\n}\n\nstd::string EidosValue_String::StringAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::StringAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nconst std::string &EidosValue_String::StringRefAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::StringRefAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\neidos_logical_t EidosValue_String::LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::LogicalAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx].length() > 0);\n}\n\nstd::string EidosValue_String::StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::StringAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nint64_t EidosValue_String::IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::IntAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\t// We don't use IntForString because an integer has been specifically requested, so even if the string appears to contain a\n\t// float value we want to force it into being an int; the way to do that is to use FloatForString and then convert to int64_t\n\tdouble converted_value = EidosInterpreter::FloatForString(values_[p_idx], p_blame_token);\n\t\n\t// nwellnhof on stackoverflow points out that the >= here is correct even though it looks wrong, because reasons...\n\tif ((converted_value < (double)INT64_MIN) || (converted_value >= (double)INT64_MAX))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::IntAtIndex_CAST): '\" << values_[p_idx] << \"' could not be represented as an integer (out of range).\" << EidosTerminate(p_blame_token);\n\t\n\treturn static_cast<int64_t>(converted_value);\n}\n\ndouble EidosValue_String::FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::FloatAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosInterpreter::FloatForString(values_[p_idx], p_blame_token);\n}\n\nEidosValue_SP EidosValue_String::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)values_.size()))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::GetValueAtIndex): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_String(values_[p_idx]));\n}\n\nEidosValue_SP EidosValue_String::CopyValues(void) const\n{\n\t// note that constness, invisibility, etc. do not get copied\n\treturn EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_String(values_))->CopyDimensionsFromValue(this));\n}\n\nvoid EidosValue_String::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n\tWILL_MODIFY(this);\n\tUncacheScript();\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueString)\n\t\tvalues_.emplace_back(p_source_script_value.StringAtIndex_NOCAST(p_idx, p_blame_token));\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_String::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_String::Sort(bool p_ascending)\n{\n\tWILL_MODIFY(this);\n\tUncacheScript();\n\t\n\tif (values_.size() < 2)\n\t\treturn;\n\t\n\t// This will sort in parallel if the task is large enough (and we're running parallel)\n\tEidos_ParallelSort(values_.data(), values_.size(), p_ascending);\n}\n\n\n//\n//\tEidosValue_Int\n//\n#pragma mark -\n#pragma mark EidosValue_Int\n#pragma mark -\n\nEidosValue_Int::EidosValue_Int(const std::vector<int16_t> &p_intvec) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tsize_t count = p_intvec.size();\n\tconst int16_t *values = p_intvec.data();\n\t\n\tresize_no_initialize(count);\n\t\n\tfor (size_t index = 0; index < count; ++index)\n\t\tset_int_no_check(values[index], index);\n}\n\nEidosValue_Int::EidosValue_Int(const std::vector<int32_t> &p_intvec) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tsize_t count = p_intvec.size();\n\tconst int32_t *values = p_intvec.data();\n\t\n\tresize_no_initialize(count);\n\t\n\tfor (size_t index = 0; index < count; ++index)\n\t\tset_int_no_check(values[index], index);\n}\n\nEidosValue_Int::EidosValue_Int(const std::vector<int64_t> &p_intvec) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tsize_t count = p_intvec.size();\n\tconst int64_t *values = p_intvec.data();\n\t\n\tresize_no_initialize(count);\n\t\n\tfor (size_t index = 0; index < count; ++index)\n\t\tset_int_no_check(values[index], index);\n}\n\nEidosValue_Int::EidosValue_Int(std::initializer_list<int64_t> p_init_list) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\treserve(p_init_list.size());\n\t\n\tfor (auto init_item : p_init_list)\n\t\tpush_int_no_check(init_item);\n}\n\nEidosValue_Int::EidosValue_Int(const int64_t *p_values, size_t p_count) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tresize_no_initialize(p_count);\n\t\n\tfor (size_t index = 0; index < p_count; ++index)\n\t\tset_int_no_check(p_values[index], index);\n}\n\nconst std::string &EidosValue_Int::ElementType(void) const\n{\n\treturn gEidosStr_integer;\n}\n\nEidosValue_SP EidosValue_Int::NewMatchingType(void) const\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int());\n}\n\nvoid EidosValue_Int::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n\tint64_t value = IntAtIndex_NOCAST(p_idx, nullptr);\n\t\n\tp_ostream << value;\n}\n\nnlohmann::json EidosValue_Int::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object = nlohmann::json::array();\t// always write as an array, for consistency; makes automated parsing easier\n\tint count = Count();\n\t\n\tfor (int i = 0; i < count; ++i)\n\t\tjson_object.emplace_back(IntAtIndex_NOCAST(i, nullptr));\n\t\n\treturn json_object;\n}\n\nint64_t EidosValue_Int::IntAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::IntAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\ndouble EidosValue_Int::NumericAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\t// casts integer to float, otherwise does not cast; considered _NOCAST\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::NumericAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\neidos_logical_t EidosValue_Int::LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::LogicalAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (values_[p_idx] == 0 ? false : true);\n}\n\nstd::string EidosValue_Int::StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::StringAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn std::to_string(values_[p_idx]);\t\t// way faster than std::ostringstream\n}\n\nint64_t EidosValue_Int::IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::IntAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\ndouble EidosValue_Int::FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::FloatAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nEidosValue_SP EidosValue_Int::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::GetValueAtIndex): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Int(values_[p_idx]));\n}\n\nEidosValue_SP EidosValue_Int::CopyValues(void) const\n{\n\t// note that constness, invisibility, etc. do not get copied\n\treturn EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Int(values_, count_))->CopyDimensionsFromValue(this));\n}\n\nvoid EidosValue_Int::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueInt)\n\t\tpush_int(p_source_script_value.IntAtIndex_NOCAST(p_idx, p_blame_token));\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_Int::Sort(bool p_ascending)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (count_ < 2)\n\t\treturn;\n\t\n\t// This will sort in parallel if the task is large enough (and we're running parallel)\n\tEidos_ParallelSort(values_, count_, p_ascending);\n}\n\nEidosValue_Int *EidosValue_Int::reserve(size_t p_reserved_size)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_reserved_size > capacity_)\n\t{\n\t\t// this is a reservation for an explicit size, so we give that size exactly, to avoid wasting space\n\t\t\n\t\tif (values_ == &singleton_value_)\n\t\t{\n\t\t\tvalues_ = (int64_t *)malloc(p_reserved_size * sizeof(int64_t));\n\t\t\t\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tvalues_[0] = singleton_value_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalues_ = (int64_t *)realloc(values_, p_reserved_size * sizeof(int64_t));\n\t\t\t\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Int::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tcapacity_ = p_reserved_size;\n\t}\n\t\n\treturn this;\n}\n\nvoid EidosValue_Int::erase_index(size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_index >= count_)\n\t\tRaiseForRangeViolation();\n\t\n\tif (p_index == count_ - 1)\n\t\t--count_;\n\telse\n\t{\n\t\tint64_t *element_ptr = values_ + p_index;\n\t\tint64_t *next_element_ptr = values_ + p_index + 1;\n\t\tint64_t *past_end_element_ptr = values_ + count_;\n\t\tsize_t element_copy_count = past_end_element_ptr - next_element_ptr;\n\t\t\n\t\tmemmove(element_ptr, next_element_ptr, element_copy_count * sizeof(int64_t));\n\t\t\n\t\t--count_;\n\t}\n}\n\n\n//\n//\tEidosValue_Float\n//\n#pragma mark -\n#pragma mark EidosValue_Float\n#pragma mark -\n\nEidosValue_Float::EidosValue_Float(const std::vector<double> &p_doublevec) : EidosValue(EidosValueType::kValueFloat), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tsize_t count = p_doublevec.size();\n\tconst double *values = p_doublevec.data();\n\t\n\tresize_no_initialize(count);\n\t\n\tfor (size_t index = 0; index < count; ++index)\n\t\tset_float_no_check(values[index], index);\n}\n\nEidosValue_Float::EidosValue_Float(std::initializer_list<double> p_init_list) : EidosValue(EidosValueType::kValueFloat), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\treserve(p_init_list.size());\n\t\n\tfor (auto init_item : p_init_list)\n\t\tpush_float_no_check(init_item);\n}\n\nEidosValue_Float::EidosValue_Float(const double *p_values, size_t p_count) : EidosValue(EidosValueType::kValueFloat), values_(&singleton_value_), count_(0), capacity_(1)\n{\n\tresize_no_initialize(p_count);\n\t\n\tfor (size_t index = 0; index < p_count; ++index)\n\t\tset_float_no_check(p_values[index], index);\n}\n\nconst std::string &EidosValue_Float::ElementType(void) const\n{\n\treturn gEidosStr_float;\n}\n\nEidosValue_SP EidosValue_Float::NewMatchingType(void) const\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float());\n}\n\nvoid EidosValue_Float::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n\tp_ostream << EidosStringForFloat(FloatAtIndex_NOCAST(p_idx, nullptr));\n}\n\nnlohmann::json EidosValue_Float::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object = nlohmann::json::array();\t// always write as an array, for consistency; makes automated parsing easier\n\tint count = Count();\n\t\n\tfor (int i = 0; i < count; ++i)\n\t\tjson_object.emplace_back(FloatAtIndex_NOCAST(i, nullptr));\n\t\n\treturn json_object;\n}\n\ndouble EidosValue_Float::FloatAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::FloatAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\ndouble EidosValue_Float::NumericAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\t// casts integer to float, otherwise does not cast; considered _NOCAST\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::NumericAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\neidos_logical_t EidosValue_Float::LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::LogicalAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\tdouble value = values_[p_idx];\n\t\n\tif (std::isnan(value))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::LogicalAtIndex_CAST): NAN cannot be converted to logical type.\" << EidosTerminate(p_blame_token);\n\t\n\treturn (value == 0 ? false : true);\n}\n\nstd::string EidosValue_Float::StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::StringAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosStringForFloat(values_[p_idx]);\n}\n\nint64_t EidosValue_Float::IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::IntAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\tdouble value = values_[p_idx];\n\t\n\tif (std::isnan(value))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::IntAtIndex_CAST): NAN cannot be converted to integer type.\" << EidosTerminate(p_blame_token);\n\tif (std::isinf(value))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::IntAtIndex_CAST): INF cannot be converted to integer type.\" << EidosTerminate(p_blame_token);\n\t\n\t// nwellnhof on stackoverflow points out that the >= here is correct even though it looks wrong, because reasons...\n\tif ((value < (double)INT64_MIN) || (value >= (double)INT64_MAX))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::IntAtIndex_CAST): float value \" << value << \" is too large to be converted to integer type.\" << EidosTerminate(p_blame_token);\n\t\n\treturn static_cast<int64_t>(value);\n}\n\ndouble EidosValue_Float::FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::FloatAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nEidosValue_SP EidosValue_Float::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::GetValueAtIndex): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Float(values_[p_idx]));\n}\n\nEidosValue_SP EidosValue_Float::CopyValues(void) const\n{\n\t// note that constness, invisibility, etc. do not get copied\n\treturn EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Float(values_, count_))->CopyDimensionsFromValue(this));\n}\n\nvoid EidosValue_Float::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueFloat)\n\t\tpush_float(p_source_script_value.FloatAtIndex_NOCAST(p_idx, p_blame_token));\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_Float::Sort(bool p_ascending)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (count_ < 2)\n\t\treturn;\n\t\n\t// Unfortunately a custom comparator is needed to make the sort order with NANs match that of R\n\tif (p_ascending)\n\t\tEidos_ParallelSort_Comparator(values_, count_, [](const double& a, const double& b) {\n\t\t\t// If a is NaN and b is not NaN, a should come after b\n\t\t\tif (std::isnan(a) && !std::isnan(b))\n\t\t\t\treturn false;\n\t\t\t\n\t\t\t// If b is NaN and a is not NaN, b should come after a\n\t\t\tif (!std::isnan(a) && std::isnan(b))\n\t\t\t\treturn true;\n\t\t\t\n\t\t\t// If both are NaN or both are non-NaN, sort numerically (ascending)\n\t\t\treturn a < b;\n\t\t});\n\telse\n\t\tEidos_ParallelSort_Comparator(values_, count_, [](const double& a, const double& b) {\n\t\t\t// If a is NaN and b is not NaN, a should come after b\n\t\t\tif (std::isnan(a) && !std::isnan(b))\n\t\t\t\treturn false;\n\t\t\t\n\t\t\t// If b is NaN and a is not NaN, b should come after a\n\t\t\tif (!std::isnan(a) && std::isnan(b))\n\t\t\t\treturn true;\n\t\t\t\n\t\t\t// If both are NaN or both are non-NaN, sort numerically (descending)\n\t\t\treturn a > b;\n\t\t});\n}\n\nEidosValue_Float *EidosValue_Float::reserve(size_t p_reserved_size)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_reserved_size > capacity_)\n\t{\n\t\t// this is a reservation for an explicit size, so we give that size exactly, to avoid wasting space\n\t\t\n\t\tif (values_ == &singleton_value_)\n\t\t{\n\t\t\tvalues_ = (double *)malloc(p_reserved_size * sizeof(double));\n\t\t\t\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tvalues_[0] = singleton_value_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalues_ = (double *)realloc(values_, p_reserved_size * sizeof(double));\n\t\t\t\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Float::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tcapacity_ = p_reserved_size;\n\t}\n\t\n\treturn this;\n}\n\nvoid EidosValue_Float::erase_index(size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_index >= count_)\n\t\tRaiseForRangeViolation();\n\t\n\tif (p_index == count_ - 1)\n\t\t--count_;\n\telse\n\t{\n\t\tdouble *element_ptr = values_ + p_index;\n\t\tdouble *next_element_ptr = values_ + p_index + 1;\n\t\tdouble *past_end_element_ptr = values_ + count_;\n\t\tsize_t element_copy_count = past_end_element_ptr - next_element_ptr;\n\t\t\n\t\tmemmove(element_ptr, next_element_ptr, element_copy_count * sizeof(double));\n\t\t\n\t\t--count_;\n\t}\n}\n\n\n//\n//\tEidosValue_Object\n//\n#pragma mark -\n#pragma mark EidosValue_Object\n#pragma mark -\n\n// See comments on EidosValue_Object::EidosValue_Object() below.  Note this is shared by all species.\nstd::vector<EidosValue_Object *> gEidosValue_Object_Mutation_Registry;\n\nEidosValue_Object::EidosValue_Object(const EidosClass *p_class) : EidosValue(EidosValueType::kValueObject),\n\tvalues_(&singleton_value_), count_(0), capacity_(1), class_(p_class)\n{\n\tclass_uses_retain_release_ = (class_ == gEidosObject_Class ? true : class_->UsesRetainRelease());\n\t\n\t// BCH 7 May 2017: OK, so, this is a hack of breathtaking disgustingness.  Here is the problem.  In SLiM we\n\t// need to reallocate the block in which all Mutation objects live, which invalidates all their pointers.\n\t// SLiM can mostly handle that for itself, but there is a big problem when it comes to EidosValue_Object\n\t// instances, which can contain Mutation * elements that must be updated.  So we need to find every single\n\t// EidosValue_Object in existence which has a class of Mutation.  To that end, we here register this object\n\t// in a global list if it is of class Mutation; in ~EidosValue_Object we will deregister it.  Maybe there\n\t// is some way to do this without pushing the hack down into Eidos, but at the moment I'm not seeing it.\n\t// On the bright side, this scheme actually seems pretty robust; the only way it fails is if somebody avoids\n\t// using the constructor or the destructor for EidosValue_Object, I think, which seems unlikely.\n\t// Note this is shared by all species, since the mutation block itself is shared by all species.\n\tconst std::string *element_type = &(class_->ClassName());\n\t\t\t\t\t\t\t\t\t\t\n\tif (element_type == &gEidosStr_Mutation)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosValue_Object::EidosValue_Object(): gEidosValue_Object_Mutation_Registry change\");\n\t\t\n\t\tgEidosValue_Object_Mutation_Registry.emplace_back(this);\n\t\tregistered_for_patching_ = true;\n\t\t\n\t\t//std::cout << \"pushed Mutation EidosValue_Object, count == \" << gEidosValue_Object_Mutation_Registry.size() << std::endl;\n\t}\n\telse\n\t{\n\t\tregistered_for_patching_ = false;\n\t}\n}\n\nEidosValue_Object::EidosValue_Object(EidosObject *p_element1, const EidosClass *p_class) : EidosValue_Object(p_class)\n{\n\t// we want to allow nullptr as a momentary placeholder, although in general a value should exist\n\t// this is a bit gross; I think it is only in EidosInterpreter::Evaluate_For(), which wants to\n\t// set up the loop index variable and *then* put the first value into it; could probably be cleaned up.\n\tif (p_element1)\n\t\tpush_object_element_CRR(p_element1);\n\telse\n\t{\n\t\t// this puts nullptr into singleton_value_, but does it following the standard procedure\n\t\tif (count_ == capacity_)\n\t\t\texpand();\n\t\t\n\t\tvalues_[count_++] = nullptr;\n\t}\n}\n\nEidosValue_Object::EidosValue_Object(const EidosValue_Object &p_original) : EidosValue_Object(p_original.Class())\n{\n\tsize_t count = p_original.Count();\n\tEidosObject * const *values = p_original.data();\n\t\n\tresize_no_initialize_RR(count);\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (size_t index = 0; index < count; ++index)\n\t\t\tset_object_element_no_check_no_previous_RR(values[index], index);\n\t}\n\telse\n\t{\n\t\tfor (size_t index = 0; index < count; ++index)\n\t\t\tset_object_element_no_check_NORR(values[index], index);\n\t}\n}\n\nEidosValue_Object::EidosValue_Object(const std::vector<EidosObject *> &p_elementvec, const EidosClass *p_class) : EidosValue_Object(p_class)\n{\n\tsize_t count = p_elementvec.size();\n\tEidosObject * const *values = p_elementvec.data();\n\t\n\tresize_no_initialize_RR(count);\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (size_t index = 0; index < count; ++index)\n\t\t\tset_object_element_no_check_no_previous_RR(values[index], index);\n\t}\n\telse\n\t{\n\t\tfor (size_t index = 0; index < count; ++index)\n\t\t\tset_object_element_no_check_NORR(values[index], index);\n\t}\n}\n\nEidosValue_Object::EidosValue_Object(std::initializer_list<EidosObject *> p_init_list, const EidosClass *p_class) : EidosValue_Object(p_class)\n{\n\treserve(p_init_list.size());\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (auto init_item : p_init_list)\n\t\t\tpush_object_element_no_check_RR(init_item);\n\t}\n\telse\n\t{\n\t\tfor (auto init_item : p_init_list)\n\t\t\tpush_object_element_no_check_NORR(init_item);\n\t}\n}\n\nEidosValue_Object::EidosValue_Object(EidosObject **p_values, size_t p_count, const EidosClass *p_class) : EidosValue_Object(p_class)\n{\n\tresize_no_initialize_RR(p_count);\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (size_t index = 0; index < p_count; ++index)\n\t\t\tset_object_element_no_check_no_previous_RR(p_values[index], index);\n\t}\n\telse\n\t{\n\t\tfor (size_t index = 0; index < p_count; ++index)\n\t\t\tset_object_element_no_check_NORR(p_values[index], index);\n\t}\n}\n\nEidosValue_Object::~EidosValue_Object(void)\n{\n\t// See comment on EidosValue_Object::EidosValue_Object() above\n\tif (registered_for_patching_)\n\t{\n\t\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"EidosValue_Object::~EidosValue_Object(): gEidosValue_Object_Mutation_Registry change\");\n\t\t\n\t\tauto erase_iter = std::find(gEidosValue_Object_Mutation_Registry.begin(), gEidosValue_Object_Mutation_Registry.end(), this);\n\t\t\n\t\tif (erase_iter != gEidosValue_Object_Mutation_Registry.end())\n\t\t\tgEidosValue_Object_Mutation_Registry.erase(erase_iter);\n\t\telse\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::~EidosValue_Object): (internal error) unregistered EidosValue_Object of class Mutation.\" << EidosTerminate(nullptr);\n\t\t\n\t\t//std::cout << \"popped Mutation EidosValue_Object, count == \" << gEidosValue_Object_Mutation_Registry.size() << std::endl;\n\t}\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (size_t index = 0; index < count_; ++index)\n\t\t{\n\t\t\tEidosObject *value = values_[index];\n\t\t\t\n\t\t\tif (value)\n\t\t\t\tstatic_cast<EidosDictionaryRetained *>(value)->Release();\t\t// unsafe cast to avoid virtual function overhead\n\t\t}\n\t}\n\t\n\tif (values_ != &singleton_value_)\n\t\tfree(values_);\n}\n\n// Provided to SLiM for the Mutation-pointer hack; see EidosValue_Object::EidosValue_Object() for comments\nvoid EidosValue_Object::PatchPointersByAdding(std::uintptr_t p_pointer_difference)\n{\n\tfor (size_t i = 0; i < count_; ++i)\n\t{\n\t\tstd::uintptr_t old_element_ptr = reinterpret_cast<std::uintptr_t>(values_[i]);\n\t\tstd::uintptr_t new_element_ptr = old_element_ptr + p_pointer_difference;\n\t\t\n\t\tvalues_[i] = reinterpret_cast<EidosObject *>(new_element_ptr);\t\t\t\t// NOLINT(*-no-int-to-ptr)\n\t}\n}\n\n// Provided to SLiM for the Mutation-pointer hack; see EidosValue_Object::EidosValue_Object() for comments\nvoid EidosValue_Object::PatchPointersBySubtracting(std::uintptr_t p_pointer_difference)\n{\n\tfor (size_t i = 0; i < count_; ++i)\n\t{\n\t\tstd::uintptr_t old_element_ptr = reinterpret_cast<std::uintptr_t>(values_[i]);\n\t\tstd::uintptr_t new_element_ptr = old_element_ptr - p_pointer_difference;\n\t\t\n\t\tvalues_[i] = reinterpret_cast<EidosObject *>(new_element_ptr);\t\t\t\t// NOLINT(*-no-int-to-ptr)\n\t}\n}\n\nvoid EidosValue_Object::RaiseForClassMismatch(void) const\n{\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::RaiseForClassMismatch): the type of an object cannot be changed.\" << EidosTerminate(nullptr);\n}\n\nconst std::string &EidosValue_Object::ElementType(void) const\n{\n\treturn Class()->ClassNameForDisplay();\n}\n\nEidosValue_SP EidosValue_Object::NewMatchingType(void) const\n{\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(Class()));\n}\n\nvoid EidosValue_Object::PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const\n{\n\tEidosObject *value = ObjectElementAtIndex_NOCAST(p_idx, nullptr);\n\t\n\tp_ostream << *value;\n}\n\nnlohmann::json EidosValue_Object::JSONRepresentation(void) const\n{\n\tnlohmann::json json_object = nlohmann::json::array();\t// always write as an array, for consistency; makes automated parsing easier\n\tint count = Count();\n\t\n\tfor (int i = 0; i < count; ++i)\n\t\tjson_object.emplace_back(ObjectElementAtIndex_NOCAST(i, nullptr)->JSONRepresentation());\n\t\n\treturn json_object;\n}\n\nEidosObject *EidosValue_Object::ObjectElementAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::ObjectElementAtIndex_NOCAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nEidosObject *EidosValue_Object::ObjectElementAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::ObjectElementAtIndex_CAST): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn values_[p_idx];\n}\n\nEidosValue_SP EidosValue_Object::GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const\n{\n\tif ((p_idx < 0) || (p_idx >= (int)count_))\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::GetValueAtIndex): subscript \" << p_idx << \" out of range.\" << EidosTerminate(p_blame_token);\n\t\n\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(values_[p_idx], Class()));\n}\n\nEidosValue_SP EidosValue_Object::CopyValues(void) const\n{\n\t// note that constness, invisibility, etc. do not get copied\n\treturn EidosValue_SP((new (gEidosValuePool->AllocateChunk()) EidosValue_Object(*this))->CopyDimensionsFromValue(this));\n}\n\nvoid EidosValue_Object::PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_source_script_value.Type() == EidosValueType::kValueObject)\n\t\tpush_object_element_CRR(p_source_script_value.ObjectElementAtIndex_NOCAST(p_idx, p_blame_token));\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::PushValueFromIndexOfEidosValue): type mismatch.\" << EidosTerminate(p_blame_token);\n}\n\nvoid EidosValue_Object::Sort(bool p_ascending)\n{\n#pragma unused(p_ascending)\n\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::Sort): Sort() is not defined for type object.\" << EidosTerminate(nullptr);\n}\n\nstatic bool CompareLogicalObjectSortPairsAscending(std::pair<eidos_logical_t, EidosObject*> i, std::pair<eidos_logical_t, EidosObject*> j)\t{ return (i.first < j.first); }\nstatic bool CompareLogicalObjectSortPairsDescending(std::pair<eidos_logical_t, EidosObject*> i, std::pair<eidos_logical_t, EidosObject*> j)\t{ return (i.first > j.first); }\n\nstatic bool CompareIntObjectSortPairsAscending(std::pair<int64_t, EidosObject*> i, std::pair<int64_t, EidosObject*> j)\t\t\t\t{ return (i.first < j.first); }\nstatic bool CompareIntObjectSortPairsDescending(std::pair<int64_t, EidosObject*> i, std::pair<int64_t, EidosObject*> j)\t\t\t\t{ return (i.first > j.first); }\n\nstatic bool CompareFloatObjectSortPairsAscending(std::pair<double, EidosObject*> i, std::pair<double, EidosObject*> j)\t\t\t\t{ return (i.first < j.first); }\nstatic bool CompareFloatObjectSortPairsDescending(std::pair<double, EidosObject*> i, std::pair<double, EidosObject*> j)\t\t\t\t{ return (i.first > j.first); }\n\nstatic bool CompareStringObjectSortPairsAscending(const std::pair<std::string, EidosObject*> &i, const std::pair<std::string, EidosObject*> &j)\t\t{ return (i.first < j.first); }\nstatic bool CompareStringObjectSortPairsDescending(const std::pair<std::string, EidosObject*> &i, const std::pair<std::string, EidosObject*> &j)\t{ return (i.first > j.first); }\n\nvoid EidosValue_Object::SortBy(const std::string &p_property, bool p_ascending)\n{\n\tWILL_MODIFY(this);\n\t\n\t// At present this is called only by the sortBy() Eidos function, so we do not need a\n\t// blame token; all errors will be attributed to that function automatically.\n\t\n\t// length 0 or 1 is already sorted\n\tif (count_ <= 1)\n\t\treturn;\n\t\n\t// figure out what type the property returns\n\tEidosGlobalStringID property_string_id = EidosStringRegistry::GlobalStringIDForString(p_property);\n\tEidosValue_SP first_result = values_[0]->GetProperty(property_string_id);\n\tEidosValueType property_type = first_result->Type();\n\t\n\t// switch on the property type for efficiency\n\tswitch (property_type)\n\t{\n\t\tcase EidosValueType::kValueVOID:\n\t\tcase EidosValueType::kValueNULL:\n\t\tcase EidosValueType::kValueObject:\n\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" returned \" << property_type << \"; a property that evaluates to logical, int, float, or string is required.\" << EidosTerminate(nullptr);\n\t\t\tbreak;\n\t\t\t\n\t\tcase EidosValueType::kValueLogical:\n\t\t{\n\t\t\t// make a vector of pairs: first is the value returned for the sorting property, second is the object element\n\t\t\tstd::vector<std::pair<eidos_logical_t, EidosObject*>> sortable_pairs;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < count_; value_index++)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(property_string_id);\n\t\t\t\t\n\t\t\t\tif (temp_result->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" produced \" << temp_result->Count() << \" values for a single element; a property that produces one value per element is required for sorting.\" << EidosTerminate(nullptr);\n\t\t\t\tif (temp_result->Type() != property_type)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" did not produce a consistent result type; a single type is required for a sorting key.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tsortable_pairs.emplace_back(temp_result->LogicalAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\t\n\t\t\t// sort the vector of pairs\n\t\t\tif (p_ascending)\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareLogicalObjectSortPairsAscending);\n\t\t\telse\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareLogicalObjectSortPairsDescending);\n\t\t\t\n\t\t\t// read out our new element vector; the elements are already retained, if they are under retain/release\n\t\t\tresize_no_initialize_RR(0);\n\t\t\t\n\t\t\tfor (auto sorted_pair : sortable_pairs)\n\t\t\t\tpush_object_element_no_check_already_retained(sorted_pair.second);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase EidosValueType::kValueInt:\n\t\t{\n\t\t\t// make a vector of pairs: first is the value returned for the sorting property, second is the object element\n\t\t\tstd::vector<std::pair<int64_t, EidosObject*>> sortable_pairs;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < count_; value_index++)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(property_string_id);\n\t\t\t\t\n\t\t\t\tif (temp_result->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" produced \" << temp_result->Count() << \" values for a single element; a property that produces one value per element is required for sorting.\" << EidosTerminate(nullptr);\n\t\t\t\tif (temp_result->Type() != property_type)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" did not produce a consistent result type; a single type is required for a sorting key.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tsortable_pairs.emplace_back(temp_result->IntAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\t\n\t\t\t// sort the vector of pairs\n\t\t\tif (p_ascending)\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareIntObjectSortPairsAscending);\n\t\t\telse\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareIntObjectSortPairsDescending);\n\t\t\t\n\t\t\t// read out our new element vector; the elements are already retained, if they are under retain/release\n\t\t\tresize_no_initialize_RR(0);\n\t\t\t\n\t\t\tfor (auto sorted_pair : sortable_pairs)\n\t\t\t\tpush_object_element_no_check_already_retained(sorted_pair.second);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase EidosValueType::kValueFloat:\n\t\t{\n\t\t\t// make a vector of pairs: first is the value returned for the sorting property, second is the object element\n\t\t\tstd::vector<std::pair<double, EidosObject*>> sortable_pairs;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < count_; value_index++)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(property_string_id);\n\t\t\t\t\n\t\t\t\tif (temp_result->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" produced \" << temp_result->Count() << \" values for a single element; a property that produces one value per element is required for sorting.\" << EidosTerminate(nullptr);\n\t\t\t\tif (temp_result->Type() != property_type)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" did not produce a consistent result type; a single type is required for a sorting key.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tsortable_pairs.emplace_back(temp_result->FloatAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\t\n\t\t\t// sort the vector of pairs\n\t\t\tif (p_ascending)\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareFloatObjectSortPairsAscending);\n\t\t\telse\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareFloatObjectSortPairsDescending);\n\t\t\t\n\t\t\t// read out our new element vector; the elements are already retained, if they are under retain/release\n\t\t\tresize_no_initialize_RR(0);\n\t\t\t\n\t\t\tfor (auto sorted_pair : sortable_pairs)\n\t\t\t\tpush_object_element_no_check_already_retained(sorted_pair.second);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tcase EidosValueType::kValueString:\n\t\t{\n\t\t\t// make a vector of pairs: first is the value returned for the sorting property, second is the object element\n\t\t\tstd::vector<std::pair<std::string, EidosObject*>> sortable_pairs;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < count_; value_index++)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(property_string_id);\n\t\t\t\t\n\t\t\t\tif (temp_result->Count() != 1)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" produced \" << temp_result->Count() << \" values for a single element; a property that produces one value per element is required for sorting.\" << EidosTerminate(nullptr);\n\t\t\t\tif (temp_result->Type() != property_type)\n\t\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SortBy): sorting property \" << p_property << \" did not produce a consistent result type; a single type is required for a sorting key.\" << EidosTerminate(nullptr);\n\t\t\t\t\n\t\t\t\tsortable_pairs.emplace_back(temp_result->StringAtIndex_NOCAST(0, nullptr), value);\n\t\t\t}\n\t\t\t\n\t\t\t// sort the vector of pairs\n\t\t\tif (p_ascending)\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareStringObjectSortPairsAscending);\n\t\t\telse\n\t\t\t\tstd::sort(sortable_pairs.begin(), sortable_pairs.end(), CompareStringObjectSortPairsDescending);\n\t\t\t\n\t\t\t// read out our new element vector; the elements are already retained, if they are under retain/release\n\t\t\tresize_no_initialize_RR(0);\n\t\t\t\n\t\t\tfor (const auto &sorted_pair : sortable_pairs)\n\t\t\t\tpush_object_element_no_check_already_retained(sorted_pair.second);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nEidosValue_SP EidosValue_Object::GetPropertyOfElements(EidosGlobalStringID p_property_id) const\n{\n\tsize_t values_size = count_;\n\tconst EidosPropertySignature *signature = class_->SignatureForProperty(p_property_id);\n\t\n\tif (!signature)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::GetPropertyOfElements): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" is not defined for object element type \" << ElementType() << \".\" << EidosTerminate(nullptr);\n\t\n\tif (values_size == 0)\n\t{\n\t\t// With a zero-length vector, the return is a zero-length vector of the type specified by the property signature.  This\n\t\t// allows code to proceed without errors without having to check for the zero-length case, by simply propagating the\n\t\t// zero-length-ness forward while preserving the expected type for the expression.  If multiple return types are possible,\n\t\t// we return a zero-length vector for the simplest type supported.\n\t\t// BCH 24 March 2018: Decided this policy is a bit unsafe; now we only propagate a zero-length result forward if the\n\t\t// return type is unambiguous, otherwise it is an error.\n\t\tEidosValueMask sig_mask = (signature->value_mask_ & kEidosValueMaskFlagStrip);\n\t\t\n\t\tif (sig_mask == kEidosValueMaskVOID) return gStaticEidosValueVOID;\t// (not legal for properties anyway)\n\t\tif (sig_mask == kEidosValueMaskNULL) return gStaticEidosValueNULL;\t// (not legal for properties anyway)\n\t\tif (sig_mask == kEidosValueMaskLogical) return gStaticEidosValue_Logical_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskInt) return gStaticEidosValue_Integer_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskFloat) return gStaticEidosValue_Float_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskString) return gStaticEidosValue_String_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskObject)\n\t\t{\n\t\t\tconst EidosClass *value_class = signature->value_class_;\n\t\t\t\n\t\t\tif (value_class)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(value_class));\n\t\t\telse\n\t\t\t\treturn gStaticEidosValue_Object_ZeroVec;\n\t\t}\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::GetPropertyOfElements): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" does not specify an unambiguous value type, and thus cannot be accessed on a zero-length vector.\" << EidosTerminate(nullptr);\n\t}\n\t\n\tif (values_size == 1)\n\t{\n\t\t// The singleton case is very common, so it should be special-cased for speed\n\t\tEidosObject *value = values_[0];\n\t\tEidosValue_SP result = value->GetProperty(p_property_id);\n\t\t\n\t\t// Access of singleton properties retains the matrix/array structure of the target\n\t\tif (signature->value_mask_ & kEidosValueMaskSingleton)\n\t\t\tresult->CopyDimensionsFromValue(this);\n\t\t\n#if DEBUG\n\t\t// This is time-consuming, and will fail only due to internal bugs, so we should do it only in DEBUG\n\t\tsignature->CheckResultValue(*result);\n#endif\n\t\treturn result;\n\t}\n\t\n\tif (signature->accelerated_get_)\n\t{\n\t\t// Accelerated property access is enabled for this property, so the class will do all the work for us\n\t\t// We put this case below the (values_size == 1) case so the accelerated getter can focus on the vectorized case\n\t\tEidosValue_SP result = EidosValue_SP(signature->accelerated_getter(values_, values_size));\n\t\t\n\t\t// BCH 4/16/2025: New in SLiM 5, an accelerated getter can return nullptr to say \"I don't want to\n\t\t// handle this case, send it down to GetProperty() and do it the slow way\", so we fall through.\n\t\tif (result)\n\t\t{\n\t\t\t// Access of singleton properties retains the matrix/array structure of the target\n\t\t\tif (signature->value_mask_ & kEidosValueMaskSingleton)\n\t\t\t\tresult->CopyDimensionsFromValue(this);\n\t\t\t\n#if DEBUG\n\t\t\t// This is time-consuming, and will fail only due to internal bugs, so we should do it only in DEBUG\n\t\t\tsignature->CheckAggregateResultValue(*result, values_size);\n#endif\n\t\t\treturn result;\n\t\t}\n\t\t\n\t\t// FALL THROUGH\n\t}\n\t\n\t// Fall-through: this is reached for all cases not handled above, including if\n\t// an accelerated getter returns nullptr to indicate it cannot handle the case\n\t{\n\t\t// get the value from all properties and collect the results\n\t\tstd::vector<EidosValue_SP> results;\n\t\t\n#if DEBUG\n\t\tif (values_size < 10)\n\t\t{\n#endif\n\t\t\t// with small objects, we check every value\n\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(p_property_id);\n\t\t\t\t\n#if DEBUG\n\t\t\t\t// This is time-consuming, and will fail only due to internal bugs, so we should do it only in DEBUG\n\t\t\t\tsignature->CheckResultValue(*temp_result);\n#endif\n\t\t\t\tresults.emplace_back(temp_result);\n\t\t\t}\n#if DEBUG\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// with large objects, we just spot-check the first value, for speed\n\t\t\tbool checked_multivalued = false;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[value_index];\n\t\t\t\tEidosValue_SP temp_result = value->GetProperty(p_property_id);\n\t\t\t\t\n\t\t\t\tif (!checked_multivalued)\n\t\t\t\t{\n\t\t\t\t\tsignature->CheckResultValue(*temp_result);\n\t\t\t\t\tchecked_multivalued = true;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tresults.emplace_back(temp_result);\n\t\t\t}\n\t\t}\n#endif\n\t\t\n\t\t// concatenate the results using ConcatenateEidosValues()\n\t\tEidosValue_SP result = ConcatenateEidosValues(results, true, false);\t// allow NULL, don't allow VOID\n\t\t\n\t\t// Access of singleton properties retains the matrix/array structure of the target\n\t\tif (signature->value_mask_ & kEidosValueMaskSingleton)\n\t\t\tresult->CopyDimensionsFromValue(this);\n\t\t\n\t\treturn result;\n\t}\n}\n\nvoid EidosValue_Object::SetPropertyOfElements(EidosGlobalStringID p_property_id, const EidosValue &p_value, EidosToken *p_property_token)\n{\n\tconst EidosPropertySignature *signature = Class()->SignatureForProperty(p_property_id);\n\t\n\t// BCH 9 Sept. 2022: if the property does not exist, raise an error on the token for the property name.\n\t// Note that other errors stemming from this call will refer to whatever the current error range is.\n\tif (!signature)\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SetPropertyOfElements): property \" << EidosStringRegistry::StringForGlobalStringID(p_property_id) << \" is not defined for object element type \" << ElementType() << \".\" << EidosTerminate(p_property_token);\n\t\n\tsignature->CheckAssignedValue(p_value);\t\t// will raise if the type being assigned in is not an exact match\n\t\n\t// We have to check the count ourselves; the signature does not do that for us\n\tsize_t p_value_count = p_value.Count();\n\tsize_t values_size = count_;\n\t\n\tif (p_value_count == 1)\n\t{\n\t\t// we have a multiplex assignment of one value to (maybe) more than one element: x.foo = 10\n\t\t// Here (unlike the accelerated getter), the accelerated version is probably a win so we always use it\n\t\tif (signature->accelerated_set_)\n\t\t{\n\t\t\t// Accelerated property writing is enabled for this property, so we call the setter directly\n\t\t\tsignature->accelerated_setter(values_, values_size, p_value, p_value_count);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\tvalues_[value_index]->SetProperty(p_property_id, p_value);\n\t\t}\n\t}\n\telse if (p_value_count == values_size)\n\t{\n\t\tif (p_value_count)\n\t\t{\n\t\t\tif (signature->accelerated_set_)\n\t\t\t{\n\t\t\t\t// Accelerated property writing is enabled for this property, so we call the setter directly\n\t\t\t\tsignature->accelerated_setter(values_, values_size, p_value, p_value_count);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// we have a one-to-one assignment of values to elements: x.foo = 1:5 (where x has 5 elements)\n\t\t\t\tfor (size_t value_idx = 0; value_idx < p_value_count; value_idx++)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_rvalue = p_value.GetValueAtIndex((int)value_idx, nullptr);\n\t\t\t\t\t\n\t\t\t\t\tvalues_[value_idx]->SetProperty(p_property_id, *temp_rvalue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::SetPropertyOfElements): assignment to a property requires an rvalue that is a singleton (multiplex assignment) or that has a .size() matching the .size of the lvalue.\" << EidosTerminate(nullptr);\n}\n\nEidosValue_SP EidosValue_Object::ExecuteMethodCall(EidosGlobalStringID p_method_id, const EidosInstanceMethodSignature *p_method_signature, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)\n{\n\t// This is an instance method, so it gets dispatched to all of our elements\n\tauto values_size = count_;\n\t\n\tif (values_size == 0)\n\t{\n\t\t// With a zero-length vector, the return is a zero-length vector of the type specified by the method signature.  This\n\t\t// allows code to proceed without errors without having to check for the zero-length case, by simply propagating the\n\t\t// zero-length-ness forward while preserving the expected type for the expression.  If multiple return types are possible,\n\t\t// we return a zero-length vector for the simplest type supported.\n\t\t// BCH 24 March 2018: Decided this policy is a bit unsafe; now we only propagate a zero-length result forward if the\n\t\t// return type is unambiguous, otherwise it is an error.\n\t\tEidosValueMask sig_mask = (p_method_signature->return_mask_ & kEidosValueMaskFlagStrip);\n\t\t\n\t\tif (sig_mask == kEidosValueMaskVOID) return gStaticEidosValueVOID;\n\t\tif (sig_mask == kEidosValueMaskNULL) return gStaticEidosValueNULL;\t// we assume visible NULL is the NULL desired, to avoid masking errors\n\t\tif (sig_mask == kEidosValueMaskLogical) return gStaticEidosValue_Logical_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskInt) return gStaticEidosValue_Integer_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskFloat) return gStaticEidosValue_Float_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskString) return gStaticEidosValue_String_ZeroVec;\n\t\tif (sig_mask == kEidosValueMaskObject)\n\t\t{\n\t\t\tconst EidosClass *return_class = p_method_signature->return_class_;\n\t\t\t\n\t\t\tif (return_class)\n\t\t\t\treturn EidosValue_SP(new (gEidosValuePool->AllocateChunk()) EidosValue_Object(return_class));\n\t\t\telse\n\t\t\t\treturn gStaticEidosValue_Object_ZeroVec;\n\t\t}\n\t\t\n\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::ExecuteMethodCall): method \" << EidosStringRegistry::StringForGlobalStringID(p_method_id) << \" does not specify an unambiguous return type, and thus cannot be called on a zero-length vector.\" << EidosTerminate(nullptr);\n\t}\n\telse if (p_method_signature->accelerated_imp_)\n\t{\n\t\t// the method is accelerated, so call through its accelerated imp; note we do this for singletons too,\n\t\t// because accelerated methods have no non-accelerated implementation, unlike accelerated properties\n\t\tEidosValue_SP result = p_method_signature->accelerated_imper_(values_, values_size, p_method_id, p_arguments, p_interpreter);\n\t\t\n\t\tp_method_signature->CheckAggregateReturn(*result, values_size);\n\t\treturn result;\n\t}\n\telse if (values_size == 1)\n\t{\n\t\t// The singleton case is very common, so it should be special-cased for speed\n\t\tEidosObject *value = values_[0];\n\t\tEidosValue_SP result = value->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t\t\n\t\tp_method_signature->CheckReturn(*result);\n\t\treturn result;\n\t}\n\telse\n\t{\n\t\t// Call the method on all elements and collect the results.  This is a huge bottleneck for Eidos in many cases,\n\t\t// so it is worthwhile to try to be smart about it.  If the signature indicates that only one return type is\n\t\t// allowed, then we will use a special-case branch optimized for that one return type, avoiding quite a bit\n\t\t// of work.  In these single-return-type special-cases we will check the returns only when in DEBUG mode; if\n\t\t// a method fails to comply with its sole declared return type, that's not a bug that will escape notice.  :->\n\t\t// We do, however, have to deal with the fact that methods are allowed to return NULL without stating it in\n\t\t// their signature (see CheckReturn()), so we do have to do some minimal type-checking to elide NULLs.\n\t\t// When a single-return-type method is declared as returning singleton, we special-case that even further, by\n\t\t// reserving a buffer size equal to the size of the target vector and then using push_X_no_check(); if a lot\n\t\t// of NULLs are returned we will waste some memory, but the payoff of avoiding reallocs is worth it overall,\n\t\t// I imagine.  Yes, I have timed all of this, and it really does make a difference; calling a method on a\n\t\t// large object vector is very common, and these optimizations make a substantial difference.  In fact, I'm\n\t\t// tempted to go even further, down the road I went down with accelerated properties, but I will hold off on\n\t\t// that for now.  :->\n\t\t// BCH 12/20/2023: the XData() methods now allow us to avoid IsSingleton() and treat the cases jointly.\n\t\tEidosValueMask sig_mask = (p_method_signature->return_mask_ & kEidosValueMaskFlagStrip);\n\t\tbool return_is_singleton = (p_method_signature->return_mask_ & kEidosValueMaskSingleton);\n\t\t\n\t\tif (sig_mask == kEidosValueMaskVOID)\n\t\t{\n\t\t\t// No need to gather results at all, since they should all be void.\n\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t{\n\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t}\n\t\t\t\n\t\t\treturn gStaticEidosValueVOID;\n\t\t}\n\t\telse if (sig_mask == kEidosValueMaskNULL)\n\t\t{\n\t\t\t// We still need to make the method calls, but we don't need to gather results at all, except to note the invisible flag\n\t\t\t// ConcatenateEidosValues() returns invisible NULL only when all values concatenated are invisible; we mirror that.\n\t\t\tbool all_invisible = true;\n\t\t\t\n\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t{\n\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\tif (!temp_result->Invisible())\n\t\t\t\t\tall_invisible = false;\n\t\t\t}\n\t\t\t\n\t\t\treturn (all_invisible ? gStaticEidosValueNULLInvisible : gStaticEidosValueNULL);\n\t\t}\n\t\telse if (sig_mask == kEidosValueMaskLogical)\n\t\t{\n\t\t\tEidosValue_Logical *logical_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Logical();\n\t\t\t\n\t\t\tif (return_is_singleton)\n\t\t\t{\n\t\t\t\tlogical_result->reserve(values_size);\n\t\t\t\t\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result == gStaticEidosValue_LogicalF)\n\t\t\t\t\t\tlogical_result->push_logical_no_check(false);\n\t\t\t\t\telse if (temp_result == gStaticEidosValue_LogicalT)\n\t\t\t\t\t\tlogical_result->push_logical_no_check(true);\n\t\t\t\t\telse if (temp_result->Type() == EidosValueType::kValueLogical)\n\t\t\t\t\t\tlogical_result->push_logical_no_check(((EidosValue_Logical *)temp_result.get())->data()[0]);\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result == gStaticEidosValue_LogicalF)\n\t\t\t\t\t\tlogical_result->push_logical(false);\n\t\t\t\t\telse if (temp_result == gStaticEidosValue_LogicalT)\n\t\t\t\t\t\tlogical_result->push_logical(true);\n\t\t\t\t\telse if (temp_result->Type() == EidosValueType::kValueLogical)\n\t\t\t\t\t{\n\t\t\t\t\t\t// No singleton special-case for logical; EidosValue_Logical is always a vector\n\t\t\t\t\t\tint return_count = temp_result->Count();\n\t\t\t\t\t\tconst eidos_logical_t *return_data = temp_result->LogicalData();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int return_index = 0; return_index < return_count; return_index++)\n\t\t\t\t\t\t\tlogical_result->push_logical(return_data[return_index]);\n\t\t\t\t\t}\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(logical_result);\n\t\t}\n\t\telse if (sig_mask == kEidosValueMaskInt)\n\t\t{\n\t\t\tEidosValue_Int *integer_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Int();\n\t\t\t\n\t\t\tif (return_is_singleton)\n\t\t\t{\n\t\t\t\tinteger_result->reserve(values_size);\n\t\t\t\t\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueInt)\n\t\t\t\t\t\tinteger_result->push_int_no_check(temp_result->IntData()[0]);\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueInt)\n\t\t\t\t\t{\n\t\t\t\t\t\tint return_count = temp_result->Count();\n\t\t\t\t\t\tconst int64_t *return_data = temp_result->IntData();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int return_index = 0; return_index < return_count; return_index++)\n\t\t\t\t\t\t\tinteger_result->push_int(return_data[return_index]);\n\t\t\t\t\t}\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(integer_result);\n\t\t}\n\t\telse if (sig_mask == kEidosValueMaskFloat)\n\t\t{\n\t\t\tEidosValue_Float *float_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Float();\n\t\t\t\n\t\t\tif (return_is_singleton)\n\t\t\t{\n\t\t\t\tfloat_result->reserve(values_size);\n\t\t\t\t\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueFloat)\n\t\t\t\t\t\tfloat_result->push_float_no_check(temp_result->FloatData()[0]);\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueFloat)\n\t\t\t\t\t{\n\t\t\t\t\t\tint return_count = temp_result->Count();\n\t\t\t\t\t\tconst double *return_data = temp_result->FloatData();\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int return_index = 0; return_index < return_count; return_index++)\n\t\t\t\t\t\t\tfloat_result->push_float(return_data[return_index]);\n\t\t\t\t\t}\n\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(float_result);\n\t\t}\n\t\t//else if (sig_mask == kEidosValueMaskString)\t// no special-case for string for now, since EidosValue_String_vector is different from the others...\n\t\t//{\n\t\t//}\n\t\telse if (sig_mask == kEidosValueMaskObject && p_method_signature->return_class_)\n\t\t{\n\t\t\tconst EidosClass *return_class = p_method_signature->return_class_;\n\t\t\tEidosValue_Object *object_result = new (gEidosValuePool->AllocateChunk()) EidosValue_Object(return_class);\n\t\t\t\n\t\t\tif (return_is_singleton)\n\t\t\t{\n\t\t\t\tobject_result->reserve(values_size);\n\t\t\t\t\n\t\t\t\tif (return_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueObject)\n\t\t\t\t\t\t\tobject_result->push_object_element_no_check_RR(temp_result->ObjectData()[0]);\n\t\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueObject)\n\t\t\t\t\t\t\tobject_result->push_object_element_no_check_NORR(temp_result->ObjectData()[0]);\n\t\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (return_class->UsesRetainRelease())\n\t\t\t\t{\n\t\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueObject)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint return_count = temp_result->Count();\n\t\t\t\t\t\t\tEidosObject * const *return_data = temp_result->ObjectData();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int return_index = 0; return_index < return_count; return_index++)\n\t\t\t\t\t\t\t\tobject_result->push_object_element_RR(return_data[return_index]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t\t{\n\t\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n#if DEBUG\n\t\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n#endif\n\t\t\t\t\t\tif (temp_result->Type() == EidosValueType::kValueObject)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint return_count = temp_result->Count();\n\t\t\t\t\t\t\tEidosObject * const *return_data = temp_result->ObjectData();\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int return_index = 0; return_index < return_count; return_index++)\n\t\t\t\t\t\t\t\tobject_result->push_object_element_NORR(return_data[return_index]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// else it is a NULL, discard it\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn EidosValue_SP(object_result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::vector<EidosValue_SP> results;\n\t\t\t\n\t\t\tif (values_size < 10)\n\t\t\t{\n\t\t\t\t// with small objects, we check every value\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t\t\t\t\t\n\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n\t\t\t\t\tresults.emplace_back(temp_result);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// with large objects, we just spot-check the first value, for speed\n\t\t\t\tbool checked_multivalued = false;\n\t\t\t\t\n\t\t\t\tfor (size_t value_index = 0; value_index < values_size; ++value_index)\n\t\t\t\t{\n\t\t\t\t\tEidosValue_SP temp_result = values_[value_index]->ExecuteInstanceMethod(p_method_id, p_arguments, p_interpreter);\n\t\t\t\t\t\n\t\t\t\t\tif (!checked_multivalued)\n\t\t\t\t\t{\n\t\t\t\t\t\tp_method_signature->CheckReturn(*temp_result);\n\t\t\t\t\t\tchecked_multivalued = true;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tresults.emplace_back(temp_result);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t// concatenate the results using ConcatenateEidosValues()\n\t\t\tEidosValue_SP result = ConcatenateEidosValues(results, true, false);\t// allow NULL, don't allow VOID\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t}\n}\n\nvoid EidosValue_Object::clear(void)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tfor (size_t index = 0; index < count_; ++index)\n\t\t{\n\t\t\tEidosObject *value = values_[index];\n\t\t\t\n\t\t\tif (value)\n\t\t\t\tstatic_cast<EidosDictionaryRetained *>(value)->Release();\t\t// unsafe cast to avoid virtual function overhead\n\t\t}\n\t}\n\t\n\tcount_ = 0;\n}\n\nEidosValue_Object *EidosValue_Object::reserve(size_t p_reserved_size)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_reserved_size > capacity_)\n\t{\n\t\t// this is a reservation for an explicit size, so we give that size exactly, to avoid wasting space\n\t\t\n\t\tif (values_ == &singleton_value_)\n\t\t{\n\t\t\tvalues_ = (EidosObject **)malloc(p_reserved_size * sizeof(EidosObject *));\n\t\t\t\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t\t\n\t\t\tvalues_[0] = singleton_value_;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalues_ = (EidosObject **)realloc(values_, p_reserved_size * sizeof(EidosObject *));\n\t\t\tif (!values_)\n\t\t\t\tEIDOS_TERMINATION << \"ERROR (EidosValue_Object::reserve): allocation failed; you may need to raise the memory limit for SLiM.\" << EidosTerminate(nullptr);\n\t\t}\n\t\t\n\t\tcapacity_ = p_reserved_size;\n\t}\n\t\n\treturn this;\n}\n\nEidosValue_Object *EidosValue_Object::resize_no_initialize(size_t p_new_size)\n{\n\tWILL_MODIFY(this);\n\t\n\treserve(p_new_size);\t// might set a capacity greater than p_new_size; no guarantees\n\t\n\t// deal with retain/release\n\tif (class_uses_retain_release_)\n\t{\n\t\tif (p_new_size < count_)\n\t\t{\n\t\t\t// shrinking; need to release the elements made redundant\n\t\t\tfor (size_t element_index = p_new_size; element_index < count_; ++element_index)\n\t\t\t{\n\t\t\t\tEidosObject *value = values_[element_index];\n\t\t\t\t\n\t\t\t\tif (value)\n\t\t\t\t\tstatic_cast<EidosDictionaryRetained *>(value)->Release();\t\t// unsafe cast to avoid virtual function overhead\n\t\t\t}\n\t\t}\n\t\telse if (p_new_size > count_)\n\t\t{\n\t\t\t// expanding; need to zero out the new slots, despite our name (but only with class_uses_retain_release_!)\n\t\t\tfor (size_t element_index = count_; element_index < p_new_size; ++element_index)\n\t\t\t\tvalues_[element_index] = nullptr;\n\t\t}\n\t}\n\t\n\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t\n\treturn this;\n}\n\nvoid EidosValue_Object::erase_index(size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (p_index >= count_)\n\t\tRaiseForRangeViolation();\n\t\n\tif (class_uses_retain_release_)\n\t\tif (values_[p_index])\n\t\t\tstatic_cast<EidosDictionaryRetained *>(values_[p_index])->Release();\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tif (p_index == count_ - 1)\n\t\t--count_;\n\telse\n\t{\n\t\tEidosObject **element_ptr = values_ + p_index;\n\t\tEidosObject **next_element_ptr = values_ + p_index + 1;\n\t\tEidosObject **past_end_element_ptr = values_ + count_;\n\t\tsize_t element_copy_count = past_end_element_ptr - next_element_ptr;\n\t\t\n\t\tmemmove(element_ptr, next_element_ptr, element_copy_count * sizeof(EidosObject *));\n\t\t\n\t\t--count_;\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/eidos_value.h",
    "content": "//\n//  eidos_value.h\n//  Eidos\n//\n//  Created by Ben Haller on 4/7/15.\n//  Copyright (c) 2015-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n \n The class EidosValue represents any variable value in a EidosInterpreter context.  EidosValue itself is an abstract base class.\n Subclasses define types for NULL, logical, string, integer, and float types.  EidosValue types are generally vectors (although\n null is an exception); there are no scalar types in Eidos.\n \n */\n\n#ifndef __Eidos__eidos_value__\n#define __Eidos__eidos_value__\n\n\n#include <iostream>\n#include <vector>\n#include <string>\n#include <initializer_list>\n#include <unordered_map>\n#include <memory>\n\n#include \"eidos_globals.h\"\n#include \"eidos_intrusive_ptr.h\"\n#include \"eidos_object_pool.h\"\n#include \"eidos_script.h\"\n#include \"eidos_property_signature.h\"\n#include \"eidos_call_signature.h\"\n#include \"eidos_class_Object.h\"\n#include \"eidos_class_Dictionary.h\"\n#include \"json_fwd.hpp\"\n\n\n// EidosValues must be allocated out of the global pool, for speed.  See eidos_object_pool.h.  When Eidos disposes of an object,\n// it will assume that it was allocated from this pool, so its use is mandatory except for stack-allocated objects.\nextern EidosObjectPool *gEidosValuePool;\n\n\n// Global EidosValues that are defined at Eidos_WarmUp() time and are never deallocated.\nextern EidosValue_VOID_SP gStaticEidosValueVOID;\n\nextern EidosValue_NULL_SP gStaticEidosValueNULL;\nextern EidosValue_NULL_SP gStaticEidosValueNULLInvisible;\n\nextern EidosValue_Logical_SP gStaticEidosValue_Logical_ZeroVec;\nextern EidosValue_Int_SP gStaticEidosValue_Integer_ZeroVec;\nextern EidosValue_Float_SP gStaticEidosValue_Float_ZeroVec;\nextern EidosValue_String_SP gStaticEidosValue_String_ZeroVec;\nextern EidosValue_Object_SP gStaticEidosValue_Object_ZeroVec;\n\nextern EidosValue_Logical_SP gStaticEidosValue_LogicalT;\nextern EidosValue_Logical_SP gStaticEidosValue_LogicalF;\n\nextern EidosValue_Int_SP gStaticEidosValue_Integer0;\nextern EidosValue_Int_SP gStaticEidosValue_Integer1;\nextern EidosValue_Int_SP gStaticEidosValue_Integer2;\nextern EidosValue_Int_SP gStaticEidosValue_Integer3;\n\nextern EidosValue_Float_SP gStaticEidosValue_Float0;\nextern EidosValue_Float_SP gStaticEidosValue_Float0Point5;\nextern EidosValue_Float_SP gStaticEidosValue_Float1;\nextern EidosValue_Float_SP gStaticEidosValue_Float10;\nextern EidosValue_Float_SP gStaticEidosValue_FloatINF;\nextern EidosValue_Float_SP gStaticEidosValue_FloatNAN;\nextern EidosValue_Float_SP gStaticEidosValue_FloatE;\nextern EidosValue_Float_SP gStaticEidosValue_FloatPI;\n\nextern EidosValue_String_SP gStaticEidosValue_StringEmpty;\nextern EidosValue_String_SP gStaticEidosValue_StringSpace;\nextern EidosValue_String_SP gStaticEidosValue_StringAsterisk;\nextern EidosValue_String_SP gStaticEidosValue_StringDoubleAsterisk;\nextern EidosValue_String_SP gStaticEidosValue_StringComma;\nextern EidosValue_String_SP gStaticEidosValue_StringTab;\nextern EidosValue_String_SP gStaticEidosValue_StringPeriod;\nextern EidosValue_String_SP gStaticEidosValue_StringDoubleQuote;\nextern EidosValue_String_SP gStaticEidosValue_String_ECMAScript;\nextern EidosValue_String_SP gStaticEidosValue_String_indices;\nextern EidosValue_String_SP gStaticEidosValue_String_average;\n\n\n#pragma mark -\n#pragma mark Comparing EidosValues\n#pragma mark -\n\n// Comparing values is a bit complex, because we want it to be as fast as possible, but there are issues involved,\n// particularly type promotion; you can compare a string to integer, or less extremely, a float to an integer, and\n// the appropriate promotion of values needs to happen.  The other issue is orderability; we used to use a scheme\n// here with comparison functions that returned -1/0/+1 for less-than/equal/greater-than, as is common is C++, but\n// the problem is that NAN values are unorderable according to the IEEE spec; NAN < x is false, but NAN > x is also\n// false, and NAN == x is also false.  So the old design was fundamentally flawed because it couldn't return the\n// correct IEEE values for NAN values.  Now we provide a general-purpose comparison function that takes an operator\n// enum so it can do the correct comparison, and we also provide a promotion function that tells the caller what\n// type the operands in a comparison would be promoted to, so the caller can do the comparisons themselves.  The\n// type-specific comparison functions are now gone.\nenum class EidosComparisonOperator : uint8_t\n{\n\tkLess = 0,\n\tkLessOrEqual,\n\tkEqual,\n\tkGreaterOrEqual,\n\tkGreater,\n\tkNotEqual\n};\n\nEidosValueType EidosTypeForPromotion(EidosValueType p_type1, EidosValueType p_type2, const EidosToken *p_blame_token);\nbool CompareEidosValues(const EidosValue &p_value1, int p_index1, const EidosValue &p_value2, int p_index2, EidosComparisonOperator p_operator, const EidosToken *p_blame_token);\n\n\n#pragma mark -\n#pragma mark EidosValue\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tA class representing a value resulting from script evaluation.  Eidos is quite dynamically typed;\n//\tproblems cause runtime exceptions.  EidosValue is the abstract base class for all value classes.\n//\n\n// BCH 11/27/2017: I am converting some of the EidosValue implementations that used a std::vector internally\n// to use a malloc'ed pointer instead.  This buys us several concrete speed benefits:\n//\n//\t-\tWhen generating a new vector value, we can allocate the EidosValue object, set its size to a known N,\n//\t\tand then set the values inside it without needing to either zero-initialize the buffer first or set\n//\t\tthe count after each value added.  In contrast, std::vector does not allow this mode of operation;\n//\t\tyou can either resize the vector first (which zero-initializes), or you can reserve but not resize\n//\t\t(avoiding the zero-initialize) and then emplace_back() values, but that writes a new count value out to\n//\t\tmemory on every push.  Since this sort of large-N result generation is very common, this is a big win.\n//\n//\t-\tWhen adding new values, it lets us skip both bounds-checking and capacity-checking when we know we\n//\t\thave allocated a sufficiently big buffer to hold the push.  This is sometimes worthwhile as well;\n//\t\tsometimes the checks done by std::vector end up taking zero time due to pipelining, but sometimes not.\n//\n//\t-\tWe no longer rely on the compiler being super-smart to optimize things for us.  In practice modern\n//\t\tC++ compilers *are* super-smart, but only when their optimization level is set high.  In practice,\n//\t\tthis means that we see a significant speedup compared to std::vector when running an unoptimized\n//\t\tdebugging build, which is a nice benefit for me, albeit with no impact for end users.\n\n\n// BCH 12/22/2023: Adding \"constness\" as a property of EidosValue, in preparation for other work that will\n// need this.  Note that the internal state of object elements is NOT const, just the EidosValue containing\n// the object elements!  There is no concept of \"constness\" for object elements themselves.  Also, note that\n// EidosSymbolTable has its own concept of \"constness\", in the form of tables that are considered constant;\n// that is distinct from the constness of EidosValues, although there is often overlap.  Yes, this is a bit\n// confusing.  We want to be able to set up things like pseudo-parameters as rapidly as possible (thus the\n// concept of a \"constants table\"), but we also want EidosValue itself to have a concept of constness so\n// that constant values like T, F, NULL, NAN, etc. are blocked from modification even if those values are\n// found in a \"variables table\".  Basically, if *either* condition is met - living in a constants table, or\n// being marked as constant in the EidosValue - modification should be blocked in all code paths.\n//\n// BCH 1/14/2024: And now there is a third kind of constness, for maximal confusion.  Being in a constant\n// symbol table means that the value for the symbol cannot be changed; you can't do \"PI = 3;\" because PI is\n// in a constants table.  Having the constant_ flag set in the EidosValue does not prevent that kind of\n// replacement, but only prevents modification of the value itself, such as by \"x[0] = 3\" or \"x = x + 1\"\n// or \"x = c(x, y)\" and similar constructs that Eidos implements rapidly by modifying the existing value.\n// Lots of pre-made and built-in constants in Eidos are marked with constant_ == true to make sure they\n// don't get munged, as well as signature default values, cached constant values, self symbols for objects,\n// etc.  The new third type of constant-ness is the iterator_var_ flag.  This is set for iterator variables\n// in for loops, which we want to be constant in the \"symbol table\" sense: you can't replace their value\n// with a new value, inside the for loop body.  But they can't be in a constants table, because they can't\n// have global scope; otherwise an iterator variable x would conflict with, e.g., a parameter named x to\n// a user-defined function called within the loop body.  If iterator_var_ == true, that value cannot be\n// replaced with a new value, but its scope is still local; it's a local constant, not a global constant,\n// which is something Eidos does not otherwise support.\n//\n// This macro checks for modification of a constant EidosValue.  It is active only in DEBUG builds, because\n// it represents an internal error -- modification of a constant value should be blocked prior to this check\n// in all code paths, so this is like an assert(), not the front-line defense.\n#if DEBUG\n#define WILL_MODIFY(x)\tif ((x)->constant_) RaiseForImmutabilityCall();\n#else\n#define WILL_MODIFY(x)\t//if ((x)->constant_) RaiseForImmutabilityCall();\n#endif\n\n\nclass EidosValue\n{\n\t//\tThis class has its assignment operator disabled, to prevent accidental copying.\nprotected:\n\t\n\tmutable uint32_t intrusive_ref_count_;\t\t\t\t\t// used by Eidos_intrusive_ptr\n\t\n\tconst EidosValueType cached_type_;\t\t\t\t\t\t// allows Type() to be an inline function; cached at construction (uint8_t)\n\tunsigned int constant_ : 1;\t\t\t\t\t\t\t\t// if set, this EidosValue is a constant and cannot be modified\n\tunsigned int iterator_var_ : 1;\t\t\t\t\t\t\t// if set, this EidosValue cannot be replaced by a different value in a variable\n\tunsigned int invisible_ : 1;\t\t\t\t\t\t\t// as in R; if true, the value will not normally be printed to the console\n\tunsigned int registered_for_patching_ : 1;\t\t\t\t// used by EidosValue_Object, otherwise UNINITIALIZED; declared here for reasons of memory packing\n\tunsigned int class_uses_retain_release_ : 1;\t\t\t// used by EidosValue_Object, otherwise UNINITIALIZED; cached from UsesRetainRelease() of class_; true until class_ is set\n\t\n\tint64_t *dim_;\t\t\t\t\t\t\t\t\t\t\t// nullptr for vectors; points to a malloced, OWNED array of dimensions for matrices and arrays\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//    when allocated, the first value in the buffer is a count of the dimensions that follow\n\tvirtual void _CopyDimensionsFromValue(const EidosValue *p_value);\t\t\t\t\t\t\t\t\t\t\t// do not call directly; called by CopyDimensionsFromValue()\n\tvoid PrintMatrixFromIndex(int64_t p_ncol, int64_t p_nrow, int64_t p_start_index, std::ostream &p_ostream, const std::string &p_indent = std::string()) const;\n\t\npublic:\n\t\n\tEidosValue(const EidosValue &p_original) = delete;\t\t// no copy-construct\n\tEidosValue& operator=(const EidosValue&) = delete;\t\t// no copying\n\tEidosValue(void) = delete;\t\t\t\t\t\t\t\t// no null constructor\n\t\n\tinline EidosValue(EidosValueType p_value_type) : intrusive_ref_count_(0), cached_type_(p_value_type), constant_(false), iterator_var_(false), invisible_(false), dim_(nullptr)\n\t{\n#ifdef EIDOS_TRACK_VALUE_ALLOCATION\n\t\tvalueTrackingCount++;\n\t\tvalueTrackingVector.emplace_back(this);\n#endif\n\t}\n\t\n\tinline virtual ~EidosValue(void)\n\t{\n#ifdef EIDOS_TRACK_VALUE_ALLOCATION\n\t\tvalueTrackingVector.erase(std::remove(valueTrackingVector.begin(), valueTrackingVector.end(), this), valueTrackingVector.end());\n\t\tvalueTrackingCount--;\n#endif\n\t\tfree(dim_);\n\t}\n\t\n\t// methods that raise due to various causes, used to avoid duplication and allow efficient inlining\n\tvoid RaiseForIncorrectTypeCall(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\tvoid RaiseForImmutabilityCall(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\tvoid RaiseForCapacityViolation(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\tvoid RaiseForRangeViolation(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\tvoid RaiseForRetainReleaseViolation(void) const __attribute__((__noreturn__)) __attribute__((analyzer_noreturn));\n\t\n\t// basic methods\n\tinline __attribute__((always_inline)) EidosValueType Type(void) const { return cached_type_; }\t// the type of the vector, cached at construction\n\t\n\t// constness; note that the internal state of object elements is NOT const, just the EidosValue containing the object elements\n\tinline __attribute__((always_inline)) void MarkAsConstant(void) { constant_ = true; }\n\tinline __attribute__((always_inline)) void MarkAsMutable(void) { constant_ = false; }\t\t// very dangerous, do not use\n\tinline __attribute__((always_inline)) bool IsConstant(void) const { return constant_; }\n\t\n\t// iterator-variable-ness; this is used by for loops to prevent the values in iterator variables from being replaced\n\tinline __attribute__((always_inline)) void MarkAsIteratorVariable(void) { iterator_var_ = true; }\n\tinline __attribute__((always_inline)) void MarkAsNonIteratorVariable(void) { iterator_var_ = false; }\n\tinline __attribute__((always_inline)) bool IsIteratorVariable(void) const { return iterator_var_; }\n\t\n\tvirtual int Count(void) const = 0;\t\t\t// the only real casualty of removing the singleton/vector distinction: this is now a virtual function\n\tvirtual const std::string &ElementType(void) const = 0;\t// the type of the elements contained by the vector\n\tvoid Print(std::ostream &p_ostream, const std::string &p_indent = std::string()) const;\t\t\t\t// standard printing; same as operator<<\n\tvoid PrintStructure(std::ostream &p_ostream, int max_values) const;\t// print structure; no newline\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const = 0;\n\tvirtual nlohmann::json JSONRepresentation(void) const = 0;\n\t\n\t// object invisibility; note invisibility should only be changed on uniquely owned objects, to avoid side effects\n\tinline __attribute__((always_inline)) bool Invisible(void) const\t\t\t\t\t\t\t{ return invisible_; }\n\tinline __attribute__((always_inline)) void SetInvisible(bool p_invisible)\t\t\t\t\t{ WILL_MODIFY(this); invisible_ = p_invisible; }\n\t\n\t// basic subscript access; abstract here since we want to force subclasses to define this\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const = 0;\n\t\n\t// fetching individual values WITHOUT casting; the base class behavior is to raise if the type does not match\n\t// these are convenience accessors; to get values across a large vector, the XData() methods below are preferred\n\t// note that NumericAtIndex_NOCAST() accesses \"numeric\" values (integer or float), casting them to float,\n\t// so it is technically a casting method, but \"numeric\" is privileged and is not considered full casting\n\tvirtual eidos_logical_t LogicalAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\n\tvirtual std::string StringAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\n\tvirtual int64_t IntAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\n\tvirtual double FloatAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\n\tvirtual double NumericAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\t// casts integer to float, otherwise does not cast; considered _NOCAST\n\tvirtual EidosObject *ObjectElementAtIndex_NOCAST(__attribute__((unused)) int p_idx, __attribute__((unused)) const EidosToken *p_blame_token) const { RaiseForIncorrectTypeCall(); }\n\t\n\t// fetching individual values WITH a cast to the requested type; this is not general-purpose\n\t// behavior for Eidos, but is limited to specific places in the language:\n\t//\n\t//\t -- CompareEidosValues(), which is now used only by pmax()/pmin() and only for identical types\n\t//\t -- _AssignRValueToLValue() to put a value of one type into a specific index in an existing vector that might be a different type\n\t//\t -- string + in EvaluatePlus(), which coerces everything that isn't a string into a string, and cat() / catn() / paste() / paste0() / print()\n\t//\t -- Evaluate_Conditional() / Evaluate_If() / Evaluate_Do() / Evaluate_While() to cast their condition to logical\n\t//\t -- Evaluate_And() / Evaluate_Or() / Evaluate_Not() to cast values used with operators & | ^ to logical\n\t//\t -- Evaluate_Eq() and the other comparison operators, == < <= > >= !=, which compare on the basis of promoting up to a common type\n\t//\t -- ConcatenateEidosValues() for c() / apply() / sapply() / AppendKeysAndValuesFrom(), and property accesses / method calls\n\t//\t -- the asLogical() / asInteger() / asFloat() / asString() methods, which explicitly coerce one type into another\n\t//\n\tvirtual eidos_logical_t LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const;\n\tvirtual std::string StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const;\n\tvirtual int64_t IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const;\n\tvirtual double FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const;\n\tvirtual EidosObject *ObjectElementAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const;\n\t\n\t// methods to allow type-agnostic manipulation of EidosValues\n\tvirtual EidosValue_SP CopyValues(void) const = 0;\t\t\t\t// a deep copy of the receiver with invisible_ == false\n\tvirtual EidosValue_SP NewMatchingType(void) const = 0;\t\t\t// a new EidosValue instance of the same type as the receiver\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) = 0;\t// copy a value\n\tvirtual void Sort(bool p_ascending) = 0;\n\t\n\t// Methods to get a type-specific pointer directly to the data of the EidosValue.  This is generally good for either\n\t// accessing the values without changing them, or changing them but not changing the length of the vector.  You must\n\t// explicitly request mutability.  If you want to change the length of the vector, you will want to actually get the\n\t// type-specific vector subclass using dynamic_cast, but it is rare not to already have that pointer in such cases.\n\tvirtual const eidos_logical_t *LogicalData(void) const { RaiseForIncorrectTypeCall(); }\n\tvirtual eidos_logical_t *LogicalData_Mutable(void) { RaiseForIncorrectTypeCall(); }\n\tvirtual const std::string *StringData(void) const { RaiseForIncorrectTypeCall(); }\n\tvirtual std::string *StringData_Mutable(void) { RaiseForIncorrectTypeCall(); }\n\tvirtual const int64_t *IntData(void) const { RaiseForIncorrectTypeCall(); }\n\tvirtual int64_t *IntData_Mutable(void) { RaiseForIncorrectTypeCall(); }\n\tvirtual const double *FloatData(void) const { RaiseForIncorrectTypeCall(); }\n\tvirtual double *FloatData_Mutable(void) { RaiseForIncorrectTypeCall(); }\n\tvirtual EidosObject * const *ObjectData(void) const { RaiseForIncorrectTypeCall(); }\n\tvirtual EidosObject **ObjectData_Mutable(void) { RaiseForIncorrectTypeCall(); }\n\t\n\t// Dimension support, for matrices and arrays\n\tinline __attribute__((always_inline)) bool IsMatrixOrArray(void) const { return !!dim_; }\t\t\t\t\t// true if we have a dimensions buffer\n\tinline __attribute__((always_inline)) int DimensionCount(void) const { return (!dim_) ? 1 : (int)*dim_; }\t// 1 for vectors, 2 for matrices, 2...n for arrays (1 not allowed for arrays)\n\tinline __attribute__((always_inline)) const int64_t *Dimensions(void) const { return (!dim_) ? nullptr : dim_ + 1; }\t// nullptr or a pointer into the dim_ buffer\n\t\n\tinline __attribute__((always_inline)) EidosValue *CopyDimensionsFromValue(const EidosValue *p_value)\t\t// copy dimensions from another value; checks for validity, can raise\n\t{\n\t\tif ((p_value && p_value->dim_) || dim_)\n\t\t\t_CopyDimensionsFromValue(p_value);\n\t\treturn this;\n\t}\n\t\n\tvoid SetDimensions(int64_t p_dim_count, const int64_t *p_dim_buffer);\t\t\t\t\t\t\t\t\t\t// can be 1/nullptr to make the value a vector; 0 is not allowed\n\t\n\tstatic bool MatchingDimensions(const EidosValue *p_value1, const EidosValue *p_value2);\t\t\t\t\t\t// true if dimensionalities are identical; works for vectors as well as matrices/arrays\n\tstatic inline __attribute__((always_inline)) EidosValue *BinaryOperationDimensionSource(EidosValue *p_value1, EidosValue *p_value2)\t// chooses which value's dimensionality will carry through a binary op\n\t{\n\t\tint dim1 = p_value1->DimensionCount();\n\t\tint dim2 = p_value2->DimensionCount();\n\t\t\n\t\tif ((dim1 == 1) && (dim2 == 1))\n\t\t\treturn nullptr;\t\t\t\t\t\t\t// neither is a matrix/array, so it doesn't matter; avoid the EidosValue_SP overhead\n\t\t\n\t\tint count1 = p_value1->Count();\n\t\tint count2 = p_value2->Count();\n\t\t\n\t\tif (dim2 == 1)\n\t\t{\n\t\t\t// p_value1 is a matrix/array, p_value2 is not; prefer the matrix, except that we won't promote a non-singleton vector to be a matrix\n\t\t\tif ((count1 == 1) && (count2 != 1))\n\t\t\t\treturn p_value2;\n\t\t\treturn p_value1;\n\t\t}\n\t\telse if (dim1 == 1)\n\t\t{\n\t\t\t// p_value2 is a matrix/array, p_value1 is not; prefer the matrix, except that we won't promote a non-singleton vector to be a matrix\n\t\t\tif ((count2 == 1) && (count1 != 1))\n\t\t\t\treturn p_value1;\n\t\t\treturn p_value2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn p_value1;\t\t\t\t\t\t\t// both are a matrix/array, so it doesn't matter (either they are conformable, or there's an error anyway)\n\t\t}\n\t}\n\t\n\tEidosValue_SP Subset(std::vector<std::vector<int64_t>> &p_inclusion_indices, bool p_drop, const EidosToken *p_blame_token);\n\t\n\t// Eidos_intrusive_ptr support; we use Eidos_intrusive_ptr as a fast smart pointer to EidosValue.\n\tinline __attribute__((always_inline)) uint32_t UseCount() const { return intrusive_ref_count_; }\n\tinline __attribute__((always_inline)) void StackAllocated() { intrusive_ref_count_++; }\t\t\t// used with stack-allocated EidosValues that have to be put under Eidos_intrusive_ptr\n\t\n\tfriend void Eidos_intrusive_ptr_add_ref(const EidosValue *p_value);\n\tfriend void Eidos_intrusive_ptr_release(const EidosValue *p_value);\n\t\n\t// This is a hack scheme to track EidosValue allocations and deallocations, as a way to help debug leaks\n\t// To enable it, change the #undef to #define.  When you run Eidos tests, a summary of persistent EidosValues will print.\n\t// The standard global values should be persistent (T, F, INF, NAN, NULL, NULL-invisible, E, PI); all others should be freed.\n#undef EIDOS_TRACK_VALUE_ALLOCATION\n\t\n#ifdef EIDOS_TRACK_VALUE_ALLOCATION\n\tstatic int valueTrackingCount;\n\tstatic std::vector<EidosValue *> valueTrackingVector;\n#endif\n};\n\nstd::ostream &operator<<(std::ostream &p_outstream, const EidosValue &p_value);\n\n// Eidos_intrusive_ptr support\ninline __attribute__((always_inline)) void Eidos_intrusive_ptr_add_ref(const EidosValue *p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_intrusive_ptr_add_ref(): EidosValue intrusive_ref_count_ change\");\n\t\n\t++(p_value->intrusive_ref_count_);\n}\n\ninline __attribute__((always_inline)) void Eidos_intrusive_ptr_release(const EidosValue *p_value)\n{\n\tTHREAD_SAFETY_IN_ACTIVE_PARALLEL(\"Eidos_intrusive_ptr_release(): EidosValue intrusive_ref_count_ change\");\n\t\n\tif ((--(p_value->intrusive_ref_count_)) == 0)\n\t{\n\t\t// We no longer delete; all EidosValues under Eidos_intrusive_ptr should have been allocated out of gEidosValuePool, so it handles the free\n\t\t//delete p_value;\n\t\tp_value->~EidosValue();\n\t\tgEidosValuePool->DisposeChunk(const_cast<EidosValue*>(p_value));\n\t}\n}\n\n\n#pragma mark -\n#pragma mark EidosValue_VOID\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_VOID represents void values in Eidos.  We have one static global EidosValue_VOID instance,\n//\twhich should be used for all void values.\n//\n\nclass EidosValue_VOID final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\t\npublic:\n\tEidosValue_VOID(const EidosValue_VOID &p_original) = delete;\t// no copy-construct\n\tEidosValue_VOID& operator=(const EidosValue_VOID&) = delete;\t// no copying\n\t\n\tinline EidosValue_VOID(void) : EidosValue(EidosValueType::kValueVOID) { }\n\tinline virtual ~EidosValue_VOID(void) override { }\n\t\n\tvirtual int Count(void) const override { return 0; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_NULL\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_NULL represents NULL values in Eidos.  We have two static global EidosValue_NULL instances,\n//\trepresenting invisible versus non-invisible NULL.\n//\n\nclass EidosValue_NULL final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\npublic:\n\tEidosValue_NULL(const EidosValue_NULL &p_original) = delete;\t// no copy-construct\n\tEidosValue_NULL& operator=(const EidosValue_NULL&) = delete;\t// no copying\n\t\n\tinline EidosValue_NULL(void) : EidosValue(EidosValueType::kValueNULL) { }\n\tinline virtual ~EidosValue_NULL(void) override { }\n\t\n\tvirtual int Count(void) const override { return 0; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_Logical\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_Logical represents logical (bool) values in Eidos.  Unlike other EidosValue types, for\n//\tlogical the EidosValue_Logical class itself is a non-abstract class that models a vector of logical\n//\tvalues; there is no singleton version.  This is because there are only two possible singleton values,\n//\tT and F, represented by the global constants gStaticEidosValue_LogicalT and gStaticEidosValue_LogicalF;\n//\tthose should be used for singleton values when possible.\n//\n\nclass EidosValue_Logical final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\nprotected:\n\teidos_logical_t *values_ = nullptr;\n\tsize_t count_ = 0, capacity_ = 0;\n\t\nprotected:\n\t// protected to encourage use of gStaticEidosValue_LogicalT / gStaticEidosValue_LogicalF\n\texplicit EidosValue_Logical(eidos_logical_t p_logical1);\n\t\npublic:\n\tEidosValue_Logical(const EidosValue_Logical &p_original) = delete;\t// no copy-construct\n\tEidosValue_Logical& operator=(const EidosValue_Logical&) = delete;\t// no copying\n\t\n\tinline EidosValue_Logical(void) : EidosValue(EidosValueType::kValueLogical) { }\n\texplicit EidosValue_Logical(const std::vector<eidos_logical_t> &p_logicalvec);\n\texplicit EidosValue_Logical(std::initializer_list<eidos_logical_t> p_init_list);\n\texplicit EidosValue_Logical(const eidos_logical_t *p_values, size_t p_count);\n\tinline virtual ~EidosValue_Logical(void) override { free(values_); }\n\t\n\tvirtual int Count(void) const override { return (int)count_; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual const eidos_logical_t *LogicalData(void) const override { return values_; }\n\tvirtual eidos_logical_t *LogicalData_Mutable(void) override { WILL_MODIFY(this); return values_; }\n\t\n\tvirtual eidos_logical_t LogicalAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual eidos_logical_t LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual std::string StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual int64_t IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n\t\n\t// vector lookalike methods; not virtual, only for clients with a EidosValue_Logical*\n\tEidosValue_Logical *reserve(size_t p_reserved_size);\t\t\t\t// as in std::vector\n\t\n\tinline EidosValue_Logical *resize_no_initialize(size_t p_new_size)\n\t{\n\t\t// does not zero-initialize, unlike std::vector!\n\t\tWILL_MODIFY(this);\n\t\t\n\t\treserve(p_new_size);\t// might set a capacity greater than p_new_size; no guarantees\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t\t\n\t\treturn this;\n\t}\n\n\tinline void resize_by_expanding_no_initialize(size_t p_new_size)\n\t{\n\t\t// resizes up to exactly p_new_size; if new capacity is needed, doubles to achieve that\n\t\t// this avoids doing a realloc with every resize, with repeated resize operations\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ < p_new_size)\n\t\t{\n\t\t\tsize_t new_capacity = (capacity_ < 16 ? 16 : capacity_);\n\t\t\t\n\t\t\twhile (new_capacity < p_new_size)\n\t\t\t\tnew_capacity <<= 1;\n\t\t\t\n\t\t\treserve(new_capacity);\n\t\t}\n\t\t\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t}\n\t\n\tinline void expand(void)\n\t{\n\t\t// expand to fit (at least) one new value\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ == 0)\n\t\t\treserve(16);\t\t// if no reserve() call was made, start out with a bit of room\n\t\telse\n\t\t\treserve(capacity_ << 1);\n\t}\n\t\n\tvoid erase_index(size_t p_index);\t\t\t\t\t\t\t\t\t// a weak substitute for erase()\n\t\n\tinline __attribute__((always_inline)) eidos_logical_t *data_mutable(void) { WILL_MODIFY(this); return values_; }\n\tinline __attribute__((always_inline)) const eidos_logical_t *data(void) const { return values_; }\n\tinline __attribute__((always_inline)) void push_logical(eidos_logical_t p_logical)\n\t{\n\t\tWILL_MODIFY(this);\n\t\tif (count_ == capacity_) expand();\n\t\tvalues_[count_++] = p_logical;\n\t}\n\tinline __attribute__((always_inline)) void push_logical_no_check(eidos_logical_t p_logical) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (count_ == capacity_) RaiseForCapacityViolation();\n#endif\n\t\tvalues_[count_++] = p_logical;\n\t}\n\tinline __attribute__((always_inline)) void set_logical_no_check(eidos_logical_t p_logical, size_t p_index) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (p_index >= count_) RaiseForRangeViolation();\n#endif\n\t\tvalues_[p_index] = p_logical;\n\t}\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_String\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_String represents string (C++ std::string) values in Eidos.  The subclass\n//\tEidosValue_String_vector is the standard instance class, used to hold vectors of strings.\n//\tEidosValue_String_singleton is used for speed, to represent single values.\n//\n\nclass EidosValue_String final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\nprotected:\n\t// this is not converted to a malloced buffer because unlike the other types, we can't get away with\n\t// not initializing the memory belonging to a std::string, so the malloc strategy doesn't work\n\t// for the same reason, we do not use the singleton/vector design here; string is not a bottleneck anyway\n\tstd::vector<std::string> values_;\n\t\n\tEidosScript *cached_script_ = nullptr;\t// cached by executeLambda(), apply(), and sapply() to avoid multiple tokenize/parse overhead\n\t\n\tinline void UncacheScript(void) { if (cached_script_) { delete cached_script_; cached_script_ = nullptr; } }\n\t\npublic:\n\tEidosValue_String(const EidosValue_String &p_original) = delete;\t// no copy-construct\n\tEidosValue_String& operator=(const EidosValue_String&) = delete;\t// no copying\n\tinline EidosValue_String(void) : EidosValue(EidosValueType::kValueString) { }\n\texplicit EidosValue_String(const std::string &p_string1) : EidosValue(EidosValueType::kValueString), values_({p_string1}) { }\n\texplicit EidosValue_String(const std::vector<std::string> &p_stringvec);\n\texplicit EidosValue_String(std::initializer_list<const std::string> p_init_list);\n\texplicit EidosValue_String(std::initializer_list<const char *> p_init_list);\n\tinline virtual ~EidosValue_String(void) override { delete cached_script_; }\n\t\n\tvirtual const std::string *StringData(void) const override { return values_.data(); }\n\tvirtual std::string *StringData_Mutable(void) override { WILL_MODIFY(this); UncacheScript(); return values_.data(); }\n\tstd::vector<std::string> &StringVectorData(void) { WILL_MODIFY(this); UncacheScript(); return values_; }\t// to get the std::vector for direct modification\n\t\n\tvirtual int Count(void) const override { return (int)values_.size(); }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tinline __attribute__((always_inline)) void PushString(const std::string &p_string) { WILL_MODIFY(this); UncacheScript(); values_.push_back(p_string); }\n\tinline __attribute__((always_inline)) EidosValue_String *Reserve(int p_reserved_size) { WILL_MODIFY(this); values_.reserve(p_reserved_size); return this; }\n\t\n\tvirtual std::string StringAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual const std::string &StringRefAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const;\n\t\n\tvirtual eidos_logical_t LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual std::string StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual int64_t IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n\t\n\t// script caching; this is used only for singleton strings that are used as lambdas\n\tinline __attribute__((always_inline)) EidosScript *CachedScript(void) { return cached_script_; }\n\tinline __attribute__((always_inline)) void SetCachedScript(EidosScript *p_script) { cached_script_ = p_script; }\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_Int\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_Int represents integer (C++ int64_t) values in Eidos.\n//\n\nclass EidosValue_Int final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\nprotected:\n\t// singleton/vector design: values_ will either point to singleton_value_, or to a malloced buffer; it will never be nullptr\n\t// in the case of a zero-length vector, note that values_ will point to singleton_value_ with count_ == 0 but capacity_ == 1\n\tint64_t singleton_value_;\n\tint64_t *values_ = nullptr;\n\tsize_t count_, capacity_;\n\t\npublic:\n\tEidosValue_Int(const EidosValue_Int &p_original) = delete;\t\t\t// no copy-construct\n\tEidosValue_Int& operator=(const EidosValue_Int&) = delete;\t\t\t// no copying\n\t\n\texplicit inline EidosValue_Int(void) : EidosValue(EidosValueType::kValueInt), values_(&singleton_value_), count_(0), capacity_(1) { }\n\texplicit inline EidosValue_Int(int64_t p_int1) : EidosValue(EidosValueType::kValueInt), singleton_value_(p_int1), values_(&singleton_value_), count_(1), capacity_(1) { }\n\texplicit EidosValue_Int(const std::vector<int16_t> &p_intvec);\n\texplicit EidosValue_Int(const std::vector<int32_t> &p_intvec);\n\texplicit EidosValue_Int(const std::vector<int64_t> &p_intvec);\n\texplicit EidosValue_Int(std::initializer_list<int64_t> p_init_list);\n\texplicit EidosValue_Int(const int64_t *p_values, size_t p_count);\n\tinline virtual ~EidosValue_Int(void) override { if (values_ != &singleton_value_) free(values_); }\n\t\n\tvirtual const int64_t *IntData(void) const override { return values_; }\n\tvirtual int64_t *IntData_Mutable(void) override { WILL_MODIFY(this); return values_; }\n\t\n\tvirtual int Count(void) const override { return (int)count_; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual int64_t IntAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double NumericAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\t// casts integer to float, otherwise does not cast\n\t\n\tvirtual eidos_logical_t LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual std::string StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual int64_t IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n\t\n\t// vector lookalike methods for speed; not virtual, only for clients with an EidosValue_Int*\n\tEidosValue_Int *reserve(size_t p_reserved_size);\t\t\t\t\t// as in std::vector\n\tvoid erase_index(size_t p_index);\t\t\t\t\t\t\t\t\t// a weak substitute for erase()\n\t\n\tinline void expand(void)\n\t{\n\t\t// expand to fit (at least) one new value\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ <= 8)\n\t\t\treserve(16);\n\t\telse\n\t\t\treserve(capacity_ << 1);\n\t}\n\t\n\tinline EidosValue_Int *resize_no_initialize(size_t p_new_size)\n\t{\n\t\t// resizes but does not zero-initialize, unlike std::vector!\n\t\tWILL_MODIFY(this);\n\t\t\n\t\treserve(p_new_size);\t// might set a capacity greater than p_new_size; no guarantees\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t\t\n\t\treturn this;\n\t}\n\t\n\tinline void resize_by_expanding_no_initialize(size_t p_new_size)\n\t{\n\t\t// resizes up to exactly p_new_size; if new capacity is needed, doubles to achieve that\n\t\t// this avoids doing a realloc with every resize, with repeated resize operations\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ < p_new_size)\n\t\t{\n\t\t\tsize_t new_capacity = (capacity_ < 16 ? 16 : capacity_);\n\t\t\t\n\t\t\twhile (new_capacity < p_new_size)\n\t\t\t\tnew_capacity <<= 1;\n\t\t\t\n\t\t\treserve(new_capacity);\n\t\t}\n\t\t\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t}\n\t\n\tinline __attribute__((always_inline)) int64_t *data_mutable(void) { WILL_MODIFY(this); return values_; }\n\tinline __attribute__((always_inline)) const int64_t *data(void) const { return values_; }\n\tinline __attribute__((always_inline)) void push_int(int64_t p_int)\n\t{\n\t\tWILL_MODIFY(this);\n\t\tif (count_ == capacity_) expand();\n\t\tvalues_[count_++] = p_int;\n\t}\n\tinline __attribute__((always_inline)) void push_int_no_check(int64_t p_int) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (count_ == capacity_) RaiseForCapacityViolation();\n#endif\n\t\tvalues_[count_++] = p_int;\n\t}\n\tinline __attribute__((always_inline)) void set_int_no_check(int64_t p_int, size_t p_index) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (p_index >= count_) RaiseForRangeViolation();\n#endif\n\t\tvalues_[p_index] = p_int;\n\t}\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_Float\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_Float represents floating-point (C++ double) values in Eidos.\n//\n\nclass EidosValue_Float final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\nprotected:\n\t// singleton/vector design: values_ will either point to singleton_value_, or to a malloced buffer; it will never be nullptr\n\t// in the case of a zero-length vector, note that values_ will point to singleton_value_ with count_ == 0 but capacity_ == 1\n\tdouble singleton_value_;\n\tdouble *values_;\n\tsize_t count_, capacity_;\n\t\npublic:\n\tEidosValue_Float(const EidosValue_Float &p_original) = delete;\t\t\t// no copy-construct\n\tEidosValue_Float& operator=(const EidosValue_Float&) = delete;\t\t\t// no copying\n\t\n\texplicit inline EidosValue_Float(void) : EidosValue(EidosValueType::kValueFloat), values_(&singleton_value_), count_(0), capacity_(1) { }\n\texplicit inline EidosValue_Float(double p_float1) : EidosValue(EidosValueType::kValueFloat), singleton_value_(p_float1), values_(&singleton_value_), count_(1), capacity_(1) { }\n\texplicit EidosValue_Float(const std::vector<double> &p_doublevec);\n\texplicit EidosValue_Float(std::initializer_list<double> p_init_list);\n\texplicit EidosValue_Float(const double *p_values, size_t p_count);\n\tinline virtual ~EidosValue_Float(void) override { if (values_ != &singleton_value_) free(values_); }\n\t\n\tvirtual const double *FloatData(void) const override { return values_; }\n\tvirtual double *FloatData_Mutable(void) override { WILL_MODIFY(this); return values_; }\n\t\n\tvirtual int Count(void) const override { return (int)count_; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual double FloatAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double NumericAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\t// casts integer to float, otherwise does not cast\n\t\n\tvirtual eidos_logical_t LogicalAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual std::string StringAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual int64_t IntAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual double FloatAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n\n\t// vector lookalike methods for speed; not virtual, only for clients with an EidosValue_Float*\n\tEidosValue_Float *reserve(size_t p_reserved_size);\t\t\t\t// as in std::vector\n\tvoid erase_index(size_t p_index);\t\t\t\t\t\t\t\t// a weak substitute for erase()\n\t\n\tinline void expand(void)\n\t{\n\t\t// expand to fit (at least) one new value\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ <= 8)\n\t\t\treserve(16);\n\t\telse\n\t\t\treserve(capacity_ << 1);\n\t}\n\t\n\tinline EidosValue_Float *resize_no_initialize(size_t p_new_size)\n\t{\n\t\t// resizes but does not zero-initialize, unlike std::vector!\n\t\tWILL_MODIFY(this);\n\t\t\n\t\treserve(p_new_size);\t// might set a capacity greater than p_new_size; no guarantees\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t\t\n\t\treturn this;\n\t}\n\t\n\tinline void resize_by_expanding_no_initialize(size_t p_new_size)\n\t{\n\t\t// resizes up to exactly p_new_size; if new capacity is needed, doubles to achieve that\n\t\t// this avoids doing a realloc with every resize, with repeated resize operations\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ < p_new_size)\n\t\t{\n\t\t\tsize_t new_capacity = (capacity_ < 16 ? 16 : capacity_);\n\t\t\t\n\t\t\twhile (new_capacity < p_new_size)\n\t\t\t\tnew_capacity <<= 1;\n\t\t\t\n\t\t\treserve(new_capacity);\n\t\t}\n\t\t\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t}\n\t\n\tinline __attribute__((always_inline)) double *data_mutable(void) { WILL_MODIFY(this); return values_; }\n\tinline __attribute__((always_inline)) const double *data(void) const { return values_; }\n\tinline __attribute__((always_inline)) void push_float(double p_float)\n\t{\n\t\tWILL_MODIFY(this);\n\t\tif (count_ == capacity_) expand();\n\t\tvalues_[count_++] = p_float;\n\t}\n\tinline __attribute__((always_inline)) void push_float_no_check(double p_float) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (count_ == capacity_) RaiseForCapacityViolation();\n#endif\n\t\tvalues_[count_++] = p_float;\n\t}\n\tinline __attribute__((always_inline)) void set_float_no_check(double p_float, size_t p_index) {\n\t\tWILL_MODIFY(this);\n#if DEBUG\n\t\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\t\tif (p_index >= count_) RaiseForRangeViolation();\n#endif\n\t\tvalues_[p_index] = p_float;\n\t}\n};\n\n\n#pragma mark -\n#pragma mark EidosValue_Object\n#pragma mark -\n\n//\t*********************************************************************************************************\n//\n//\tEidosValue_Object represents objects in Eidos: entities that have properties and can respond to\n//\tmethods.  The value type for it is EidosObject (or a subclass thereof).\n//\n\n// EidosObject supports a retain/release mechanism that disposes of objects when no longer\n// referenced, which client code can get by subclassing EidosDictionaryRetained instead of\n// EidosObject and subclassing EidosDictionaryRetained_Class instead of EidosClass.\n// Note that most SLiM objects have managed lifetimes, and are not under retain/release,\n// but Mutation uses retain/release so that those objects can be kept permanently by the user's\n// script.  Note that if you inherit from EidosDictionaryRetained you *must* subclass from\n// EidosDictionaryRetained_Class, and vice versa; each is considered a guarantee of the other.\n\nclass EidosValue_Object final : public EidosValue\n{\nprivate:\n\ttypedef EidosValue super;\n\nprotected:\n\t// singleton/vector design: values_ will either point to singleton_value_, or to a malloced buffer; it will never be nullptr\n\t// in the case of a zero-length vector, note that values_ will point to singleton_value_ with count_ == 0 but capacity_ == 1\n\tEidosObject *singleton_value_;\n\tEidosObject **values_;\t\t\t\t// these may use a retain/release system of ownership; see below\n\tsize_t count_, capacity_;\n\t\n\tconst EidosClass *class_;\t\t\t// can be gEidosObject_Class if the vector is empty\n\t\n\t// declared by EidosValue for our benefit, to pack bytes\n\t//unsigned int registered_for_patching_ : 1;\t\t\t// for mutation pointer patching; see EidosValue_Object::EidosValue_Object()\n\t//unsigned int class_uses_retain_release_ : 1;\t\t\t// cached from UsesRetainRelease() of class_; true until class_ is set\n\t\n\t// check the type of a new element being added to an EidosValue_Object, and update class_uses_retain_release_\n\tinline __attribute__((always_inline)) void DeclareClassFromElement(const EidosObject *p_element, bool p_undeclared_is_error = false)\n\t{\n\t\tWILL_MODIFY(this);\n\t\t\n\t\t// no check that p_element is non-null; that should always be the case, and we don't\n\t\t// want to waste the time - a crash is fine if this invariant is not satisfied\n\t\tconst EidosClass *element_class = p_element->Class();\n\t\t\n\t\tif (element_class != class_)\n\t\t{\n\t\t\tif (!p_undeclared_is_error && (class_ == gEidosObject_Class))\n\t\t\t{\n\t\t\t\tclass_ = element_class;\n\t\t\t\tclass_uses_retain_release_ = class_->UsesRetainRelease();\n\t\t\t}\n\t\t\telse\n\t\t\t\tRaiseForClassMismatch();\n\t\t}\n\t}\n\tvoid RaiseForClassMismatch(void) const;\n\t\n\t// Provided to SLiM for the Mutation-pointer hack; see EidosValue_Object::EidosValue_Object() for comments\n\tvoid PatchPointersByAdding(std::uintptr_t p_pointer_difference);\n\tvoid PatchPointersBySubtracting(std::uintptr_t p_pointer_difference);\n\t\npublic:\n\tEidosValue_Object(void) = delete;\t\t\t\t\t\t\t\t\t\t\t\t// no default constructor\n\tEidosValue_Object& operator=(const EidosValue_Object&) = delete;\t\t\t\t// no copying\n\texplicit EidosValue_Object(const EidosClass *p_class);\t\t\t\t\t\t\t// funnel initializer; allows gEidosObject_Class\n\t\n\texplicit EidosValue_Object(EidosObject *p_element1, const EidosClass *p_class);\n\texplicit EidosValue_Object(const EidosValue_Object &p_original);\n\texplicit EidosValue_Object(const std::vector<EidosObject *> &p_elementvec, const EidosClass *p_class);\n\texplicit EidosValue_Object(std::initializer_list<EidosObject *> p_init_list, const EidosClass *p_class);\n\texplicit EidosValue_Object(EidosObject **p_values, size_t p_count, const EidosClass *p_class);\n\tvirtual ~EidosValue_Object(void) override;\n\t\n\tvirtual EidosObject * const *ObjectData(void) const override { return values_; }\n\tvirtual EidosObject **ObjectData_Mutable(void) override { WILL_MODIFY(this); return values_; }\n\t\n\tinline __attribute__((always_inline)) const EidosClass *Class(void) const { return class_; }\n\tinline __attribute__((always_inline)) bool UsesRetainRelease(void) const { return class_uses_retain_release_; }\n\t\n\tvirtual int Count(void) const override { return (int)count_; }\n\tvirtual const std::string &ElementType(void) const override;\n\tvirtual EidosValue_SP NewMatchingType(void) const override;\n\tvirtual void PrintValueAtIndex(const int p_idx, std::ostream &p_ostream) const override;\n\tvirtual nlohmann::json JSONRepresentation(void) const override;\n\t\n\tvirtual EidosObject *ObjectElementAtIndex_NOCAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosObject *ObjectElementAtIndex_CAST(int p_idx, const EidosToken *p_blame_token) const override;\n\t\n\tvirtual EidosValue_SP GetValueAtIndex(const int p_idx, const EidosToken *p_blame_token) const override;\n\tvirtual EidosValue_SP CopyValues(void) const override;\n\tvirtual void PushValueFromIndexOfEidosValue(int p_idx, const EidosValue &p_source_script_value, const EidosToken *p_blame_token) override;\n\tvirtual void Sort(bool p_ascending) override;\n\tvoid SortBy(const std::string &p_property, bool p_ascending);\n\t\n\t// Property and method support; defined only on EidosValue_Object, not EidosValue.  The methods that a\n\t// EidosValue_Object instance defines depend upon the type of the EidosObject objects it contains.\n\tEidosValue_SP GetPropertyOfElements(EidosGlobalStringID p_property_id) const;\n\tvoid SetPropertyOfElements(EidosGlobalStringID p_property_id, const EidosValue &p_value, EidosToken *p_property_token);\n\t\n\tEidosValue_SP ExecuteMethodCall(EidosGlobalStringID p_method_id, const EidosInstanceMethodSignature *p_call_signature, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter);\n\t\n\t// vector lookalike methods for speed; not virtual, only for clients with a EidosValue_Object*\n\tvoid clear(void);\t\t\t\t\t\t\t\t\t\t\t\t\t// as in std::vector\n\tEidosValue_Object *reserve(size_t p_reserved_size);\t\t\t\t\t// as in std::vector\n\tEidosValue_Object *resize_no_initialize(size_t p_new_size);\t\t\t// does not zero-initialize, unlike std::vector!\n\t\n\tinline EidosValue_Object *resize_no_initialize_RR(size_t p_new_size)\n\t{\n\t\t// doesn't zero-initialize even for the RR case (set_object_element_no_check_RR may not be used, use set_object_element_no_check_no_previous_RR)\n\t\tWILL_MODIFY(this);\n\t\t\n\t\treserve(p_new_size);\t// might set a capacity greater than p_new_size; no guarantees\n\t\t\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t\t\n\t\treturn this;\n\t}\n\t\n\t//inline void resize_by_expanding_no_initialize(size_t p_new_size)\n\t// not implemented: would, like EidosValue_Object::resize_no_initialize(),\n\t// zero out new slots in the RR case to avoid having pointers in a bad state\n\t\n\tinline void resize_by_expanding_no_initialize_RR(size_t p_new_size)\n\t{\n\t\t// resizes up to exactly p_new_size; if new capacity is needed, doubles to achieve that\n\t\t// this avoids doing a realloc with every resize, with repeated resize operations\n\t\t// this version does not zero-initialize the new entries even in the RR case;\n\t\t// use set_object_element_no_check_no_previous_RR() after this call\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ < p_new_size)\n\t\t{\n\t\t\tsize_t new_capacity = (capacity_ < 16 ? 16 : capacity_);\n\t\t\t\n\t\t\twhile (new_capacity < p_new_size)\n\t\t\t\tnew_capacity <<= 1;\n\t\t\t\n\t\t\treserve(new_capacity);\n\t\t}\n\t\t\n\t\tcount_ = p_new_size;\t// regardless of the capacity set, set the size to exactly p_new_size\n\t}\n\t\n\tinline void expand(void)\n\t{\n\t\tWILL_MODIFY(this);\n\t\t\n\t\tif (capacity_ == 0)\n\t\t\treserve(16);\t\t// if no reserve() call was made, start out with a bit of room\n\t\telse\n\t\t\treserve(capacity_ << 1);\n\t}\n\n\tvoid erase_index(size_t p_index);\t\t\t\t\t\t\t\t\t// a weak substitute for erase()\n\t\n\tinline __attribute__((always_inline)) EidosObject **data_mutable(void) { WILL_MODIFY(this); return values_; }\t\t// the accessors below should be used to modify, since they handle Retain()/Release()\n\tinline __attribute__((always_inline)) EidosObject * const *data(void) const { return values_; }\n\t\n\t// fast accessors; you can use the _RR or _NORR versions in a tight loop to avoid overhead, when you know\n\t// whether the EidosObject subclass you are using inherits from EidosDictionaryRetained or not;\n\t// you can call UsesRetainRelease() to find that out if you don't know or want to assert() for safety\n\tvoid push_object_element_CRR(EidosObject *p_object);\t\t\t\t\t\t\t\t// checks for retain/release\n\tvoid push_object_element_RR(EidosObject *p_object);\t\t\t\t\t\t\t\t// specifies retain/release\n\tvoid push_object_element_NORR(EidosObject *p_object);\t\t\t\t\t\t\t// specifies no retain/release\n\t\n\tvoid push_object_element_capcheck_NORR(EidosObject *p_object);\t\t\t\t\t// specifies no retain/release; capacity check only\n\t\n\tvoid push_object_element_no_check_CRR(EidosObject *p_object);\t\t\t\t\t// checks for retain/release\n\tvoid push_object_element_no_check_RR(EidosObject *p_object);\t\t\t\t\t\t// specifies retain/release\n\tvoid push_object_element_no_check_NORR(EidosObject *p_object);\t\t\t\t\t// specifies no retain/release\n\tvoid push_object_element_no_check_already_retained(EidosObject *p_object);\t\t// specifies retain/release is IGNORED\n\t\n\tvoid set_object_element_no_check_CRR(EidosObject *p_object, size_t p_index);\t\t// checks for retain/release\n\tvoid set_object_element_no_check_RR(EidosObject *p_object, size_t p_index);\t\t// specifies retain/release\n\tvoid set_object_element_no_check_no_previous_RR(EidosObject *p_object, size_t p_index);\t\t// specifies retain/release, previous value assumed invalid from resize_no_initialize_RR\n\tvoid set_object_element_no_check_NORR(EidosObject *p_object, size_t p_index);\t// specifies no retain/release\n\t\n\tfriend void SLiM_IncreaseMutationBlockCapacity(void);\t// for PatchPointersByAdding() / PatchPointersBySubtracting()\n};\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_CRR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n\tif (count_ == capacity_)\n\t\texpand();\n\t\n\tDeclareClassFromElement(p_object);\n\t\n\tif (class_uses_retain_release_)\n\t\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_RR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (!class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\t\n\tif (count_ == capacity_)\n\t\texpand();\n\t\n\tDeclareClassFromElement(p_object);\n\t\n\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_NORR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\t\n\tif (count_ == capacity_)\n\t\texpand();\n\t\n\tDeclareClassFromElement(p_object);\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_capcheck_NORR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\t\n\tif (count_ == capacity_)\n\t\texpand();\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_no_check_CRR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (count_ == capacity_) RaiseForCapacityViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n#endif\n\t\n\tif (class_uses_retain_release_)\n\t\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_no_check_RR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (count_ == capacity_) RaiseForCapacityViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (!class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\t\n\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_no_check_NORR(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (count_ == capacity_) RaiseForCapacityViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::push_object_element_no_check_already_retained(EidosObject *p_object)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (count_ == capacity_) RaiseForCapacityViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\t// no retain/release check even in DEBUG; the caller says they know what they are doing\n#endif\n\t\n\tvalues_[count_++] = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::set_object_element_no_check_CRR(EidosObject *p_object, size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (p_index >= count_) RaiseForRangeViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n#endif\n\tEidosObject *&value_slot_to_replace = values_[p_index];\n\t\n\tif (class_uses_retain_release_)\n\t{\n\t\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t\t\t\t\t// unsafe cast to avoid virtual function overhead\n\t\tif (value_slot_to_replace)\n\t\t\tstatic_cast<EidosDictionaryRetained *>(value_slot_to_replace)->Release();\t// unsafe cast to avoid virtual function overhead\n\t}\n\t\n\tvalue_slot_to_replace = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::set_object_element_no_check_RR(EidosObject *p_object, size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (p_index >= count_) RaiseForRangeViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (!class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\tEidosObject *&value_slot_to_replace = values_[p_index];\n\t\n\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t\t\t\t\t// unsafe cast to avoid virtual function overhead\n\tif (value_slot_to_replace)\n\t\tstatic_cast<EidosDictionaryRetained *>(value_slot_to_replace)->Release();\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalue_slot_to_replace = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::set_object_element_no_check_no_previous_RR(EidosObject *p_object, size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (p_index >= count_) RaiseForRangeViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (!class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\tEidosObject *&value_slot_to_replace = values_[p_index];\n\t\n\tstatic_cast<EidosDictionaryRetained *>(p_object)->Retain();\t\t\t\t\t\t// unsafe cast to avoid virtual function overhead\n\t\n\tvalue_slot_to_replace = p_object;\n}\n\ninline __attribute__((always_inline)) void EidosValue_Object::set_object_element_no_check_NORR(EidosObject *p_object, size_t p_index)\n{\n\tWILL_MODIFY(this);\n\t\n#if DEBUG\n\t// do checks only in DEBUG mode, for speed; the user should never be able to trigger these errors\n\tif (p_index >= count_) RaiseForRangeViolation();\n\tDeclareClassFromElement(p_object, true);\t\t\t\t// require a prior matching declaration\n\tif (class_uses_retain_release_) RaiseForRetainReleaseViolation();\n#endif\n\tEidosObject *&value_slot_to_replace = values_[p_index];\n\t\n\tvalue_slot_to_replace = p_object;\n}\n\n\n#endif /* defined(__Eidos__eidos_value__) */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "eidos/json.hpp",
    "content": "/*\n    __ _____ _____ _____\n __|  |   __|     |   | |  JSON for Modern C++\n|  |  |__   |  |  | | | |  version 3.9.1\n|_____|_____|_____|_|___|  https://github.com/nlohmann/json\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.\n\nPermission is hereby  granted, free of charge, to any  person obtaining a copy\nof this software and associated  documentation files (the \"Software\"), to deal\nin the Software  without restriction, including without  limitation the rights\nto  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell\ncopies  of  the Software,  and  to  permit persons  to  whom  the Software  is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE  IS PROVIDED \"AS  IS\", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR\nIMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,\nFITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE\nAUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER\nLIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef INCLUDE_NLOHMANN_JSON_HPP_\n#define INCLUDE_NLOHMANN_JSON_HPP_\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3\n#define NLOHMANN_JSON_VERSION_MINOR 9\n#define NLOHMANN_JSON_VERSION_PATCH 1\n\n#include <algorithm> // all_of, find, for_each\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#include <iosfwd> // istream, ostream\n#include <iterator> // random_access_iterator_tag\n#include <memory> // unique_ptr\n#include <numeric> // accumulate\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n#include <vector> // vector\n\n// #include <nlohmann/adl_serializer.hpp>\n\n\n#include <utility>\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n\n#include <algorithm> // transform\n#include <array> // array\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n\n#include <exception> // exception\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n\n#include <cstddef> // size_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// struct to capture the start position of the current token\nstruct position_t\n{\n    /// the total number of characters read\n    std::size_t chars_read_total = 0;\n    /// the number of characters read in the current line\n    std::size_t chars_read_current_line = 0;\n    /// the number of lines read\n    std::size_t lines_read = 0;\n\n    /// conversion to size_t to preserve SAX interface\n    constexpr operator size_t() const\n    {\n        return chars_read_total;\n    }\n};\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n#include <utility> // pair\n// #include <nlohmann/thirdparty/hedley/hedley.hpp>\n/* Hedley - https://nemequ.github.io/hedley\n * Created by Evan Nemerson <evan@nemerson.com>\n *\n * To the extent possible under law, the author(s) have dedicated all\n * copyright and related and neighboring rights to this software to\n * the public domain worldwide. This software is distributed without\n * any warranty.\n *\n * For details, see <http://creativecommons.org/publicdomain/zero/1.0/>.\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 14)\n#if defined(JSON_HEDLEY_VERSION)\n    #undef JSON_HEDLEY_VERSION\n#endif\n#define JSON_HEDLEY_VERSION 14\n\n#if defined(JSON_HEDLEY_STRINGIFY_EX)\n    #undef JSON_HEDLEY_STRINGIFY_EX\n#endif\n#define JSON_HEDLEY_STRINGIFY_EX(x) #x\n\n#if defined(JSON_HEDLEY_STRINGIFY)\n    #undef JSON_HEDLEY_STRINGIFY\n#endif\n#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)\n\n#if defined(JSON_HEDLEY_CONCAT_EX)\n    #undef JSON_HEDLEY_CONCAT_EX\n#endif\n#define JSON_HEDLEY_CONCAT_EX(a,b) a##b\n\n#if defined(JSON_HEDLEY_CONCAT)\n    #undef JSON_HEDLEY_CONCAT\n#endif\n#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)\n\n#if defined(JSON_HEDLEY_CONCAT3_EX)\n    #undef JSON_HEDLEY_CONCAT3_EX\n#endif\n#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c\n\n#if defined(JSON_HEDLEY_CONCAT3)\n    #undef JSON_HEDLEY_CONCAT3\n#endif\n#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)\n\n#if defined(JSON_HEDLEY_VERSION_ENCODE)\n    #undef JSON_HEDLEY_VERSION_ENCODE\n#endif\n#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)\n    #undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)\n\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #undef JSON_HEDLEY_GNUC_VERSION\n#endif\n#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#elif defined(__GNUC__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION)\n    #undef JSON_HEDLEY_MSVC_VERSION\n#endif\n#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)\n#elif defined(_MSC_FULL_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)\n#elif defined(_MSC_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)\n    #undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#endif\n#if !defined(JSON_HEDLEY_MSVC_VERSION)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)\n#elif defined(_MSC_VER) && (_MSC_VER >= 1400)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))\n#elif defined(_MSC_VER) && (_MSC_VER >= 1200)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))\n#else\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #undef JSON_HEDLEY_INTEL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)\n#elif defined(__INTEL_COMPILER) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)\n    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #undef JSON_HEDLEY_PGI_VERSION\n#endif\n#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)\n    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)\n    #undef JSON_HEDLEY_PGI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #undef JSON_HEDLEY_SUNPRO_VERSION\n#endif\n#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)\n#elif defined(__SUNPRO_C)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)\n#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)\n#elif defined(__SUNPRO_CC)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)\n    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#endif\n#if defined(__EMSCRIPTEN__)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #undef JSON_HEDLEY_ARM_VERSION\n#endif\n#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)\n#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)\n    #undef JSON_HEDLEY_ARM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #undef JSON_HEDLEY_IBM_VERSION\n#endif\n#if defined(__ibmxl__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)\n#elif defined(__xlC__) && defined(__xlC_ver__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)\n#elif defined(__xlC__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)\n    #undef JSON_HEDLEY_IBM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #undef JSON_HEDLEY_TI_VERSION\n#endif\n#if \\\n    defined(__TI_COMPILER_VERSION__) && \\\n    ( \\\n      defined(__TMS470__) || defined(__TI_ARM__) || \\\n      defined(__MSP430__) || \\\n      defined(__TMS320C2000__) \\\n    )\n#if (__TI_COMPILER_VERSION__ >= 16000000)\n    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)\n    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #undef JSON_HEDLEY_TI_CL430_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)\n    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))\n    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)\n    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)\n    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #undef JSON_HEDLEY_CRAY_VERSION\n#endif\n#if defined(_CRAYC)\n    #if defined(_RELEASE_PATCHLEVEL)\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)\n    #else\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)\n    #undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #undef JSON_HEDLEY_IAR_VERSION\n#endif\n#if defined(__IAR_SYSTEMS_ICC__)\n    #if __VER__ > 1000\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))\n    #else\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)\n    #undef JSON_HEDLEY_IAR_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #undef JSON_HEDLEY_TINYC_VERSION\n#endif\n#if defined(__TINYC__)\n    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)\n    #undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #undef JSON_HEDLEY_DMC_VERSION\n#endif\n#if defined(__DMC__)\n    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)\n    #undef JSON_HEDLEY_DMC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #undef JSON_HEDLEY_COMPCERT_VERSION\n#endif\n#if defined(__COMPCERT_VERSION__)\n    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)\n    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #undef JSON_HEDLEY_PELLES_VERSION\n#endif\n#if defined(__POCC__)\n    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)\n    #undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #undef JSON_HEDLEY_GCC_VERSION\n#endif\n#if \\\n    defined(JSON_HEDLEY_GNUC_VERSION) && \\\n    !defined(__clang__) && \\\n    !defined(JSON_HEDLEY_INTEL_VERSION) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_ARM_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \\\n    !defined(__COMPCERT__)\n    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#endif\n#if \\\n    defined(__has_cpp_attribute) && \\\n    defined(__cplusplus) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#endif\n#if !defined(__cplusplus) || !defined(__has_cpp_attribute)\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#elif \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_IAR_VERSION) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \\\n    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_BUILTIN)\n    #undef JSON_HEDLEY_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_FEATURE)\n    #undef JSON_HEDLEY_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GCC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_EXTENSION)\n    #undef JSON_HEDLEY_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_WARNING)\n    #undef JSON_HEDLEY_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_HAS_WARNING(warning) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)\n    #undef JSON_HEDLEY_GNUC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_WARNING)\n    #undef JSON_HEDLEY_GCC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    defined(__clang__) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \\\n    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))\n    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)\n#else\n    #define JSON_HEDLEY_PRAGMA(value)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)\n    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#endif\n#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)\n    #undef JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"clang diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"clang diagnostic pop\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"GCC diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"GCC diagnostic pop\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))\n    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))\n#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"pop\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"diag_push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"diag_pop\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH\n    #define JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n\n/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat\")\n#    if JSON_HEDLEY_HAS_WARNING(\"-Wc++17-extensions\")\n#      if JSON_HEDLEY_HAS_WARNING(\"-Wc++1z-extensions\")\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++1z-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      else\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      endif\n#    else\n#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    endif\n#  endif\n#endif\n#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x\n#endif\n\n#if defined(JSON_HEDLEY_CONST_CAST)\n    #undef JSON_HEDLEY_CONST_CAST\n#endif\n#if defined(__cplusplus)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))\n#elif \\\n  JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\") || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_REINTERPRET_CAST)\n    #undef JSON_HEDLEY_REINTERPRET_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_CAST)\n    #undef JSON_HEDLEY_STATIC_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_CPP_CAST)\n    #undef JSON_HEDLEY_CPP_CAST\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wold-style-cast\")\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wold-style-cast\\\"\") \\\n    ((T) (expr)) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"diag_suppress=Pe137\") \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))\n#  endif\n#else\n#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wdeprecated-declarations\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"clang diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warning(disable:1478 1786)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1216,1444,1445\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1291,1718\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,symdeprecated,symdeprecated2)\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress=Pe1444,Pe1215\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warn(disable:2241)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"clang diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"warning(disable:161)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 1675\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"GCC diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress=Pe161\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-attributes\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"clang diagnostic ignored \\\"-Wunknown-attributes\\\"\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"warning(disable:1292)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097,1098\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"error_messages(off,attrskipunsup)\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1173\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress=Pe1097\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"clang diagnostic ignored \\\"-Wcast-qual\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"warning(disable:2203 2331)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"GCC diagnostic ignored \\\"-Wcast-qual\\\"\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n\n#if defined(JSON_HEDLEY_DEPRECATED)\n    #undef JSON_HEDLEY_DEPRECATED\n#endif\n#if defined(JSON_HEDLEY_DEPRECATED_FOR)\n    #undef JSON_HEDLEY_DEPRECATED_FOR\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated(\"Since \" # since))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated(\"Since \" #since \"; use \" #replacement))\n#elif \\\n    JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__(\"Since \" #since)))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__(\"Since \" #since \"; use \" #replacement)))\n#elif defined(__cplusplus) && (__cplusplus >= 201402L)\n    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since)]])\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since \"; use \" #replacement)]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DEPRECATED(since) _Pragma(\"deprecated\")\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma(\"deprecated\")\n#else\n    #define JSON_HEDLEY_DEPRECATED(since)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)\n#endif\n\n#if defined(JSON_HEDLEY_UNAVAILABLE)\n    #undef JSON_HEDLEY_UNAVAILABLE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__(\"Not available until \" #available_since)))\n#else\n    #define JSON_HEDLEY_UNAVAILABLE(available_since)\n#endif\n\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#endif\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))\n#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n#elif defined(_Check_return_) /* SAL */\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_\n#else\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)\n#endif\n\n#if defined(JSON_HEDLEY_SENTINEL)\n    #undef JSON_HEDLEY_SENTINEL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0)\n    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))\n#else\n    #define JSON_HEDLEY_SENTINEL(position)\n#endif\n\n#if defined(JSON_HEDLEY_NO_RETURN)\n    #undef JSON_HEDLEY_NO_RETURN\n#endif\n#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NO_RETURN __noreturn\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L\n    #define JSON_HEDLEY_NO_RETURN _Noreturn\n#elif defined(__cplusplus) && (__cplusplus >= 201103L)\n    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"does_not_return\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"FUNC_NEVER_RETURNS;\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#else\n    #define JSON_HEDLEY_NO_RETURN\n#endif\n\n#if defined(JSON_HEDLEY_NO_ESCAPE)\n    #undef JSON_HEDLEY_NO_ESCAPE\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)\n    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))\n#else\n    #define JSON_HEDLEY_NO_ESCAPE\n#endif\n\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #undef JSON_HEDLEY_UNREACHABLE\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)\n    #undef JSON_HEDLEY_UNREACHABLE_RETURN\n#endif\n#if defined(JSON_HEDLEY_ASSUME)\n    #undef JSON_HEDLEY_ASSUME\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)\n#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)\n    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)\n#elif \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n    #if defined(__cplusplus)\n        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)\n    #endif\n#endif\n#if \\\n    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5)\n    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()\n#elif defined(JSON_HEDLEY_ASSUME)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n#if !defined(JSON_HEDLEY_ASSUME)\n    #if defined(JSON_HEDLEY_UNREACHABLE)\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)\n    #endif\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #if  \\\n        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))\n    #else\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()\n    #endif\n#else\n    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)\n#endif\n#if !defined(JSON_HEDLEY_UNREACHABLE)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n\nJSON_HEDLEY_DIAGNOSTIC_PUSH\n#if JSON_HEDLEY_HAS_WARNING(\"-Wpedantic\")\n    #pragma clang diagnostic ignored \"-Wpedantic\"\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat-pedantic\") && defined(__cplusplus)\n    #pragma clang diagnostic ignored \"-Wc++98-compat-pedantic\"\n#endif\n#if JSON_HEDLEY_GCC_HAS_WARNING(\"-Wvariadic-macros\",4,0,0)\n    #if defined(__clang__)\n        #pragma clang diagnostic ignored \"-Wvariadic-macros\"\n    #elif defined(JSON_HEDLEY_GCC_VERSION)\n        #pragma GCC diagnostic ignored \"-Wvariadic-macros\"\n    #endif\n#endif\n#if defined(JSON_HEDLEY_NON_NULL)\n    #undef JSON_HEDLEY_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))\n#else\n    #define JSON_HEDLEY_NON_NULL(...)\n#endif\nJSON_HEDLEY_DIAGNOSTIC_POP\n\n#if defined(JSON_HEDLEY_PRINTF_FORMAT)\n    #undef JSON_HEDLEY_PRINTF_FORMAT\n#endif\n#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))\n#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))\n#else\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)\n#endif\n\n#if defined(JSON_HEDLEY_CONSTEXPR)\n    #undef JSON_HEDLEY_CONSTEXPR\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)\n    #endif\n#endif\n#if !defined(JSON_HEDLEY_CONSTEXPR)\n    #define JSON_HEDLEY_CONSTEXPR\n#endif\n\n#if defined(JSON_HEDLEY_PREDICT)\n    #undef JSON_HEDLEY_PREDICT\n#endif\n#if defined(JSON_HEDLEY_LIKELY)\n    #undef JSON_HEDLEY_LIKELY\n#endif\n#if defined(JSON_HEDLEY_UNLIKELY)\n    #undef JSON_HEDLEY_UNLIKELY\n#endif\n#if defined(JSON_HEDLEY_UNPREDICTABLE)\n    #undef JSON_HEDLEY_UNPREDICTABLE\n#endif\n#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))\n#endif\n#if \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0)\n#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))\n#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )\n#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )\n#elif \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \\\n  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0)\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \\\n    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)\n#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)\n#else\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))\n#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))\n#endif\n#if !defined(JSON_HEDLEY_UNPREDICTABLE)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)\n#endif\n\n#if defined(JSON_HEDLEY_MALLOC)\n    #undef JSON_HEDLEY_MALLOC\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_MALLOC _Pragma(\"returns_new_memory\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_MALLOC __declspec(restrict)\n#else\n    #define JSON_HEDLEY_MALLOC\n#endif\n\n#if defined(JSON_HEDLEY_PURE)\n    #undef JSON_HEDLEY_PURE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define JSON_HEDLEY_PURE __attribute__((__pure__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n#  define JSON_HEDLEY_PURE _Pragma(\"does_not_write_global_data\")\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \\\n    )\n#  define JSON_HEDLEY_PURE _Pragma(\"FUNC_IS_PURE;\")\n#else\n#  define JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_CONST)\n    #undef JSON_HEDLEY_CONST\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_CONST __attribute__((__const__))\n#elif \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_CONST _Pragma(\"no_side_effect\")\n#else\n    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_RESTRICT)\n    #undef JSON_HEDLEY_RESTRICT\n#endif\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT restrict\n#elif \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    defined(__clang__)\n    #define JSON_HEDLEY_RESTRICT __restrict\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT _Restrict\n#else\n    #define JSON_HEDLEY_RESTRICT\n#endif\n\n#if defined(JSON_HEDLEY_INLINE)\n    #undef JSON_HEDLEY_INLINE\n#endif\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    (defined(__cplusplus) && (__cplusplus >= 199711L))\n    #define JSON_HEDLEY_INLINE inline\n#elif \\\n    defined(JSON_HEDLEY_GCC_VERSION) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)\n    #define JSON_HEDLEY_INLINE __inline__\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_INLINE __inline\n#else\n    #define JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_ALWAYS_INLINE)\n    #undef JSON_HEDLEY_ALWAYS_INLINE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \\\n    )\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"FUNC_ALWAYS_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"inline=forced\")\n#else\n#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_NEVER_INLINE)\n    #undef JSON_HEDLEY_NEVER_INLINE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"noinline\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"FUNC_CANNOT_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"inline=never\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#else\n    #define JSON_HEDLEY_NEVER_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_PRIVATE)\n    #undef JSON_HEDLEY_PRIVATE\n#endif\n#if defined(JSON_HEDLEY_PUBLIC)\n    #undef JSON_HEDLEY_PUBLIC\n#endif\n#if defined(JSON_HEDLEY_IMPORT)\n    #undef JSON_HEDLEY_IMPORT\n#endif\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define JSON_HEDLEY_PRIVATE\n#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)\n#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)\n#else\n#  if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    ( \\\n      defined(__TI_EABI__) && \\\n      ( \\\n        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \\\n      ) \\\n    )\n#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__(\"hidden\")))\n#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__(\"default\")))\n#  else\n#    define JSON_HEDLEY_PRIVATE\n#    define JSON_HEDLEY_PUBLIC\n#  endif\n#  define JSON_HEDLEY_IMPORT    extern\n#endif\n\n#if defined(JSON_HEDLEY_NO_THROW)\n    #undef JSON_HEDLEY_NO_THROW\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)\n#else\n    #define JSON_HEDLEY_NO_THROW\n#endif\n\n#if defined(JSON_HEDLEY_FALL_THROUGH)\n    #undef JSON_HEDLEY_FALL_THROUGH\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0)\n    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])\n#elif defined(__fallthrough) /* SAL */\n    #define JSON_HEDLEY_FALL_THROUGH __fallthrough\n#else\n    #define JSON_HEDLEY_FALL_THROUGH\n#endif\n\n#if defined(JSON_HEDLEY_RETURNS_NON_NULL)\n    #undef JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)\n    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))\n#elif defined(_Ret_notnull_) /* SAL */\n    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_\n#else\n    #define JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n\n#if defined(JSON_HEDLEY_ARRAY_PARAM)\n    #undef JSON_HEDLEY_ARRAY_PARAM\n#endif\n#if \\\n    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \\\n    !defined(__STDC_NO_VLA__) && \\\n    !defined(__cplusplus) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)\n#else\n    #define JSON_HEDLEY_ARRAY_PARAM(name)\n#endif\n\n#if defined(JSON_HEDLEY_IS_CONSTANT)\n    #undef JSON_HEDLEY_IS_CONSTANT\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)\n    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#endif\n/* JSON_HEDLEY_IS_CONSTEXPR_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #undef JSON_HEDLEY_IS_CONSTEXPR_\n#endif\n#if \\\n    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0)\n    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)\n#endif\n#if !defined(__cplusplus)\n#  if \\\n       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)\n#endif\n#  elif \\\n       ( \\\n          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \\\n          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \\\n          !defined(JSON_HEDLEY_PGI_VERSION) && \\\n          !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n       JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)\n#endif\n#  elif \\\n       defined(JSON_HEDLEY_GCC_VERSION) || \\\n       defined(JSON_HEDLEY_INTEL_VERSION) || \\\n       defined(JSON_HEDLEY_TINYC_VERSION) || \\\n       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \\\n       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \\\n       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \\\n       defined(__clang__)\n#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \\\n        sizeof(void) != \\\n        sizeof(*( \\\n                  1 ? \\\n                  ((void*) ((expr) * 0L) ) : \\\n((struct { char v[sizeof(void) * 2]; } *) 1) \\\n                ) \\\n              ) \\\n                                            )\n#  endif\n#endif\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))\n#else\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_BEGIN_C_DECLS)\n    #undef JSON_HEDLEY_BEGIN_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_END_C_DECLS)\n    #undef JSON_HEDLEY_END_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_C_DECL)\n    #undef JSON_HEDLEY_C_DECL\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_BEGIN_C_DECLS extern \"C\" {\n    #define JSON_HEDLEY_END_C_DECLS }\n    #define JSON_HEDLEY_C_DECL extern \"C\"\n#else\n    #define JSON_HEDLEY_BEGIN_C_DECLS\n    #define JSON_HEDLEY_END_C_DECLS\n    #define JSON_HEDLEY_C_DECL\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_ASSERT)\n    #undef JSON_HEDLEY_STATIC_ASSERT\n#endif\n#if \\\n  !defined(__cplusplus) && ( \\\n      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \\\n      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \\\n      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n      defined(_Static_assert) \\\n    )\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)\n#elif \\\n  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))\n#else\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)\n#endif\n\n#if defined(JSON_HEDLEY_NULL)\n    #undef JSON_HEDLEY_NULL\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)\n    #elif defined(NULL)\n        #define JSON_HEDLEY_NULL NULL\n    #else\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)\n    #endif\n#elif defined(NULL)\n    #define JSON_HEDLEY_NULL NULL\n#else\n    #define JSON_HEDLEY_NULL ((void*) 0)\n#endif\n\n#if defined(JSON_HEDLEY_MESSAGE)\n    #undef JSON_HEDLEY_MESSAGE\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_MESSAGE(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(message msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)\n#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_WARNING)\n    #undef JSON_HEDLEY_WARNING\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_WARNING(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(clang warning msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_REQUIRE)\n    #undef JSON_HEDLEY_REQUIRE\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_MSG)\n    #undef JSON_HEDLEY_REQUIRE_MSG\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wgcc-compat\")\n#    define JSON_HEDLEY_REQUIRE(expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), #expr, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), msg, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, \"error\")))\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, \"error\")))\n#  endif\n#else\n#  define JSON_HEDLEY_REQUIRE(expr)\n#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS)\n    #undef JSON_HEDLEY_FLAGS\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum)\n    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))\n#else\n    #define JSON_HEDLEY_FLAGS\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS_CAST)\n    #undef JSON_HEDLEY_FLAGS_CAST\n#endif\n#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        _Pragma(\"warning(disable:188)\") \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)\n#endif\n\n#if defined(JSON_HEDLEY_EMPTY_BASES)\n    #undef JSON_HEDLEY_EMPTY_BASES\n#endif\n#if \\\n    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)\n#else\n    #define JSON_HEDLEY_EMPTY_BASES\n#endif\n\n/* Remaining macros are deprecated. */\n\n#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)\n#else\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)\n    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#endif\n#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)\n    #undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)\n    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#endif\n#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)\n    #undef JSON_HEDLEY_CLANG_HAS_WARNING\n#endif\n#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)\n\n#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */\n\n\n// This file contains all internal macro definitions\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n    #if defined(__clang__)\n        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n            #error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n            #error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #endif\n#endif\n\n// C++ language standard detection\n#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)\n    #define JSON_HAS_CPP_20\n    #define JSON_HAS_CPP_17\n    #define JSON_HAS_CPP_14\n#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n    #define JSON_HAS_CPP_17\n    #define JSON_HAS_CPP_14\n#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n    #define JSON_HAS_CPP_14\n#endif\n\n// disable float-equal warnings on GCC/clang\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wdocumentation\"\n#endif\n\n// allow to disable exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n    #define JSON_THROW(exception) throw exception\n    #define JSON_TRY try\n    #define JSON_CATCH(exception) catch(exception)\n    #define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n    #include <cstdlib>\n    #define JSON_THROW(exception) std::abort()\n    #define JSON_TRY if(true)\n    #define JSON_CATCH(exception) if(false)\n    #define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n    #undef JSON_THROW\n    #define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n    #undef JSON_TRY\n    #define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n    #undef JSON_CATCH\n    #define JSON_CATCH JSON_CATCH_USER\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// allow to override assert\n#if !defined(JSON_ASSERT)\n    #include <cassert> // assert\n    #define JSON_ASSERT(x) assert(x)\n#endif\n\n// allow to access some private functions (needed by the test suite)\n#if defined(JSON_TESTS_PRIVATE)\n    #define JSON_PRIVATE_UNLESS_TESTED public\n#else\n    #define JSON_PRIVATE_UNLESS_TESTED private\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \\\n    template<typename BasicJsonType>                                                            \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \\\n    {                                                                                           \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool  \\\n        {                                                                                       \\\n            return ej_pair.first == e;                                                          \\\n        });                                                                                     \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \\\n    }                                                                                           \\\n    template<typename BasicJsonType>                                                            \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \\\n    {                                                                                           \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                       \\\n            return ej_pair.second == j;                                                         \\\n        });                                                                                     \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer,     \\\n             class BinaryType>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer, BinaryType>\n\n// Macros to simplify conversion from/to types\n\n#define NLOHMANN_JSON_EXPAND( x ) x\n#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME\n#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\\n        NLOHMANN_JSON_PASTE64, \\\n        NLOHMANN_JSON_PASTE63, \\\n        NLOHMANN_JSON_PASTE62, \\\n        NLOHMANN_JSON_PASTE61, \\\n        NLOHMANN_JSON_PASTE60, \\\n        NLOHMANN_JSON_PASTE59, \\\n        NLOHMANN_JSON_PASTE58, \\\n        NLOHMANN_JSON_PASTE57, \\\n        NLOHMANN_JSON_PASTE56, \\\n        NLOHMANN_JSON_PASTE55, \\\n        NLOHMANN_JSON_PASTE54, \\\n        NLOHMANN_JSON_PASTE53, \\\n        NLOHMANN_JSON_PASTE52, \\\n        NLOHMANN_JSON_PASTE51, \\\n        NLOHMANN_JSON_PASTE50, \\\n        NLOHMANN_JSON_PASTE49, \\\n        NLOHMANN_JSON_PASTE48, \\\n        NLOHMANN_JSON_PASTE47, \\\n        NLOHMANN_JSON_PASTE46, \\\n        NLOHMANN_JSON_PASTE45, \\\n        NLOHMANN_JSON_PASTE44, \\\n        NLOHMANN_JSON_PASTE43, \\\n        NLOHMANN_JSON_PASTE42, \\\n        NLOHMANN_JSON_PASTE41, \\\n        NLOHMANN_JSON_PASTE40, \\\n        NLOHMANN_JSON_PASTE39, \\\n        NLOHMANN_JSON_PASTE38, \\\n        NLOHMANN_JSON_PASTE37, \\\n        NLOHMANN_JSON_PASTE36, \\\n        NLOHMANN_JSON_PASTE35, \\\n        NLOHMANN_JSON_PASTE34, \\\n        NLOHMANN_JSON_PASTE33, \\\n        NLOHMANN_JSON_PASTE32, \\\n        NLOHMANN_JSON_PASTE31, \\\n        NLOHMANN_JSON_PASTE30, \\\n        NLOHMANN_JSON_PASTE29, \\\n        NLOHMANN_JSON_PASTE28, \\\n        NLOHMANN_JSON_PASTE27, \\\n        NLOHMANN_JSON_PASTE26, \\\n        NLOHMANN_JSON_PASTE25, \\\n        NLOHMANN_JSON_PASTE24, \\\n        NLOHMANN_JSON_PASTE23, \\\n        NLOHMANN_JSON_PASTE22, \\\n        NLOHMANN_JSON_PASTE21, \\\n        NLOHMANN_JSON_PASTE20, \\\n        NLOHMANN_JSON_PASTE19, \\\n        NLOHMANN_JSON_PASTE18, \\\n        NLOHMANN_JSON_PASTE17, \\\n        NLOHMANN_JSON_PASTE16, \\\n        NLOHMANN_JSON_PASTE15, \\\n        NLOHMANN_JSON_PASTE14, \\\n        NLOHMANN_JSON_PASTE13, \\\n        NLOHMANN_JSON_PASTE12, \\\n        NLOHMANN_JSON_PASTE11, \\\n        NLOHMANN_JSON_PASTE10, \\\n        NLOHMANN_JSON_PASTE9, \\\n        NLOHMANN_JSON_PASTE8, \\\n        NLOHMANN_JSON_PASTE7, \\\n        NLOHMANN_JSON_PASTE6, \\\n        NLOHMANN_JSON_PASTE5, \\\n        NLOHMANN_JSON_PASTE4, \\\n        NLOHMANN_JSON_PASTE3, \\\n        NLOHMANN_JSON_PASTE2, \\\n        NLOHMANN_JSON_PASTE1)(__VA_ARGS__))\n#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)\n#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)\n#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)\n#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)\n#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)\n#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)\n#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)\n#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)\n#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)\n#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)\n#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)\n#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)\n#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)\n#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)\n#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)\n#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)\n#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)\n#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)\n#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)\n#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)\n#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)\n#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)\n#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)\n#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)\n#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)\n#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)\n#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)\n#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)\n#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)\n#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)\n#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)\n#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)\n#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)\n#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)\n#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)\n#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)\n#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)\n#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)\n#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)\n#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)\n#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)\n#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)\n#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)\n#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)\n#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)\n#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)\n#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)\n#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)\n#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)\n#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)\n#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)\n#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)\n#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)\n#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)\n#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)\n#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)\n#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)\n#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)\n#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)\n#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)\n#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)\n#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)\n#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)\n\n#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;\n#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_INTRUSIVE\n@since version 3.9.0\n*/\n#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \\\n    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE\n@since version 3.9.0\n*/\n#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \\\n    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n#ifndef JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_USE_IMPLICIT_CONVERSIONS 1\n#endif\n\n#if JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_EXPLICIT\n#else\n    #define JSON_EXPLICIT explicit\n#endif\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////////\n// exceptions //\n////////////////\n\n/*!\n@brief general exception of the @ref basic_json class\n\nThis class is an extension of `std::exception` objects with a member @a id for\nexception ids. It is used as the base class for all exceptions thrown by the\n@ref basic_json class. This class can hence be used as \"wildcard\" to catch\nexceptions.\n\nSubclasses:\n- @ref parse_error for exceptions indicating a parse error\n- @ref invalid_iterator for exceptions indicating errors with iterators\n- @ref type_error for exceptions indicating executing a member function with\n                  a wrong type\n- @ref out_of_range for exceptions indicating access out of the defined range\n- @ref other_error for exceptions indicating other library errors\n\n@internal\n@note To have nothrow-copy-constructible exceptions, we internally use\n      `std::runtime_error` which can cope with arbitrary-length error messages.\n      Intermediate strings are built with static functions and then passed to\n      the actual constructor.\n@endinternal\n\n@liveexample{The following code shows how arbitrary library exceptions can be\ncaught.,exception}\n\n@since version 3.0.0\n*/\nclass exception : public std::exception\n{\n  public:\n    /// returns the explanatory string\n    JSON_HEDLEY_RETURNS_NON_NULL\n    const char* what() const noexcept override\n    {\n        return m.what();\n    }\n\n    /// the id of the exception\n    const int id;\n\n  protected:\n    JSON_HEDLEY_NON_NULL(3)\n    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}\n\n    static std::string name(const std::string& ename, int id_)\n    {\n        return \"[json.exception.\" + ename + \".\" + std::to_string(id_) + \"] \";\n    }\n\n  private:\n    /// an exception object as storage for error messages\n    std::runtime_error m;\n};\n\n/*!\n@brief exception indicating a parse error\n\nThis exception is thrown by the library when a parse error occurs. Parse errors\ncan occur during the deserialization of JSON text, CBOR, MessagePack, as well\nas when using JSON Patch.\n\nMember @a byte holds the byte index of the last read character in the input\nfile.\n\nExceptions have ids 1xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.\njson.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\\uxxxx` entries (\"surrogate pairs\"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.\njson.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.\njson.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.\njson.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one \"op\" member, whose value indicates the operation to perform. Its value must be one of \"add\", \"remove\", \"replace\", \"move\", \"copy\", or \"test\"; other values are errors.\njson.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.\njson.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.\njson.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.\njson.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.\njson.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.\njson.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.\njson.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.\njson.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).\njson.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed.\n\n@note For an input with n bytes, 1 is the index of the first character and n+1\n      is the index of the terminating null byte or the end of file. This also\n      holds true when reading a byte vector (CBOR or MessagePack).\n\n@liveexample{The following code shows how a `parse_error` exception can be\ncaught.,parse_error}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass parse_error : public exception\n{\n  public:\n    /*!\n    @brief create a parse error exception\n    @param[in] id_       the id of the exception\n    @param[in] pos       the position where the error occurred (or with\n                         chars_read_total=0 if the position cannot be\n                         determined)\n    @param[in] what_arg  the explanatory string\n    @return parse_error object\n    */\n    static parse_error create(int id_, const position_t& pos, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        position_string(pos) + \": \" + what_arg;\n        return parse_error(id_, pos.chars_read_total, w.c_str());\n    }\n\n    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        (byte_ != 0 ? (\" at byte \" + std::to_string(byte_)) : \"\") +\n                        \": \" + what_arg;\n        return parse_error(id_, byte_, w.c_str());\n    }\n\n    /*!\n    @brief byte index of the parse error\n\n    The byte index of the last read character in the input file.\n\n    @note For an input with n bytes, 1 is the index of the first character and\n          n+1 is the index of the terminating null byte or the end of file.\n          This also holds true when reading a byte vector (CBOR or MessagePack).\n    */\n    const std::size_t byte;\n\n  private:\n    parse_error(int id_, std::size_t byte_, const char* what_arg)\n        : exception(id_, what_arg), byte(byte_) {}\n\n    static std::string position_string(const position_t& pos)\n    {\n        return \" at line \" + std::to_string(pos.lines_read + 1) +\n               \", column \" + std::to_string(pos.chars_read_current_line);\n    }\n};\n\n/*!\n@brief exception indicating errors with iterators\n\nThis exception is thrown if iterators passed to a library function do not match\nthe expected semantics.\n\nExceptions have ids 2xx.\n\nname / id                           | example message | description\n----------------------------------- | --------------- | -------------------------\njson.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.\njson.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.\njson.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.\njson.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.\njson.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.\njson.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.\njson.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.\njson.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.\njson.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.\njson.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().\n\n@liveexample{The following code shows how an `invalid_iterator` exception can be\ncaught.,invalid_iterator}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass invalid_iterator : public exception\n{\n  public:\n    static invalid_iterator create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"invalid_iterator\", id_) + what_arg;\n        return invalid_iterator(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    invalid_iterator(int id_, const char* what_arg)\n        : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating executing a member function with a wrong type\n\nThis exception is thrown in case of a type error; that is, a library function is\nexecuted on a JSON value whose type does not match the expected semantics.\n\nExceptions have ids 3xx.\n\nname / id                     | example message | description\n----------------------------- | --------------- | -------------------------\njson.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.\njson.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.\njson.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.\njson.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.\njson.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.\njson.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.\njson.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.\njson.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.\njson.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.\njson.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.\njson.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.\njson.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.\njson.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.\njson.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.\njson.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.\njson.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |\njson.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |\n\n@liveexample{The following code shows how a `type_error` exception can be\ncaught.,type_error}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass type_error : public exception\n{\n  public:\n    static type_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"type_error\", id_) + what_arg;\n        return type_error(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating access out of the defined range\n\nThis exception is thrown in case a library function is called on an input\nparameter that exceeds the expected range, for instance in case of array\nindices or nonexisting object keys.\n\nExceptions have ids 4xx.\n\nname / id                       | example message | description\n------------------------------- | --------------- | -------------------------\njson.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.\njson.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.\njson.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.\njson.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.\njson.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.\njson.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.\njson.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) |\njson.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |\njson.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |\n\n@liveexample{The following code shows how an `out_of_range` exception can be\ncaught.,out_of_range}\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass out_of_range : public exception\n{\n  public:\n    static out_of_range create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"out_of_range\", id_) + what_arg;\n        return out_of_range(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating other library errors\n\nThis exception is thrown in case of errors that cannot be classified with the\nother exception types.\n\nExceptions have ids 5xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.other_error.501 | unsuccessful: {\"op\":\"test\",\"path\":\"/baz\", \"value\":\"bar\"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.\n\n@sa - @ref exception for the base class of the library exceptions\n@sa - @ref parse_error for exceptions indicating a parse error\n@sa - @ref invalid_iterator for exceptions indicating errors with iterators\n@sa - @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa - @ref out_of_range for exceptions indicating access out of the defined range\n\n@liveexample{The following code shows how an `other_error` exception can be\ncaught.,other_error}\n\n@since version 3.0.0\n*/\nclass other_error : public exception\n{\n  public:\n    static other_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"other_error\", id_) + what_arg;\n        return other_error(id_, w.c_str());\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n#include <utility> // index_sequence, make_index_sequence, index_sequence_for\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\ntemplate<typename T>\nusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n#ifdef JSON_HAS_CPP_14\n\n// the following utilities are natively available in C++14\nusing std::enable_if_t;\nusing std::index_sequence;\nusing std::make_index_sequence;\nusing std::index_sequence_for;\n\n#else\n\n// alias templates to reduce boilerplate\ntemplate<bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\n// source: https://stackoverflow.com/a/32223343\ntemplate<std::size_t... Ints>\nstruct index_sequence\n{\n    using type = index_sequence;\n    using value_type = std::size_t;\n    static constexpr std::size_t size() noexcept\n    {\n        return sizeof...(Ints);\n    }\n};\n\ntemplate<class Sequence1, class Sequence2>\nstruct merge_and_renumber;\n\ntemplate<std::size_t... I1, std::size_t... I2>\nstruct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>\n        : index_sequence < I1..., (sizeof...(I1) + I2)... > {};\n\ntemplate<std::size_t N>\nstruct make_index_sequence\n    : merge_and_renumber < typename make_index_sequence < N / 2 >::type,\n      typename make_index_sequence < N - N / 2 >::type > {};\n\ntemplate<> struct make_index_sequence<0> : index_sequence<> {};\ntemplate<> struct make_index_sequence<1> : index_sequence<0> {};\n\ntemplate<typename... Ts>\nusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n#endif\n\n// dispatch utility (taken from ranges-v3)\ntemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\ntemplate<> struct priority_tag<0> {};\n\n// taken from ranges-v3\ntemplate<typename T>\nstruct static_const\n{\n    static constexpr T value{};\n};\n\ntemplate<typename T>\nconstexpr T static_const<T>::value;\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\n#include <limits> // numeric_limits\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n#include <tuple> // tuple\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n\n#include <iterator> // random_access_iterator_tag\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename ...Ts> struct make_void\n{\n    using type = void;\n};\ntemplate<typename ...Ts> using void_t = typename make_void<Ts...>::type;\n} // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename It, typename = void>\nstruct iterator_types {};\n\ntemplate<typename It>\nstruct iterator_types <\n    It,\n    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n    typename It::reference, typename It::iterator_category >>\n{\n    using difference_type = typename It::difference_type;\n    using value_type = typename It::value_type;\n    using pointer = typename It::pointer;\n    using reference = typename It::reference;\n    using iterator_category = typename It::iterator_category;\n};\n\n// This is required as some compilers implement std::iterator_traits in a way that\n// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\ntemplate<typename T, typename = void>\nstruct iterator_traits\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>\n            : iterator_types<T>\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>\n{\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = T;\n    using difference_type = ptrdiff_t;\n    using pointer = T*;\n    using reference = T&;\n};\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n\n#include <type_traits>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\n// https://en.cppreference.com/w/cpp/experimental/is_detected\nnamespace nlohmann\n{\nnamespace detail\n{\nstruct nonesuch\n{\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(nonesuch const&) = delete;\n    nonesuch(nonesuch const&&) = delete;\n    void operator=(nonesuch const&) = delete;\n    void operator=(nonesuch&&) = delete;\n};\n\ntemplate<class Default,\n         class AlwaysVoid,\n         template<class...> class Op,\n         class... Args>\nstruct detector\n{\n    using value_t = std::false_type;\n    using type = Default;\n};\n\ntemplate<class Default, template<class...> class Op, class... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n{\n    using value_t = std::true_type;\n    using type = Op<Args...>;\n};\n\ntemplate<template<class...> class Op, class... Args>\nusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\ntemplate<template<class...> class Op, class... Args>\nusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or = detector<Default, void, Op, Args...>;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\ntemplate<class Expected, template<class...> class Op, class... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\ntemplate<class To, template<class...> class Op, class... Args>\nusing is_detected_convertible =\n    std::is_convertible<detected_t<Op, Args...>, To>;\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/json_fwd.hpp>\n#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n#define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer,\n         class BinaryType = std::vector<std::uint8_t>>\nclass basic_json;\n\n/*!\n@brief JSON Pointer\n\nA JSON pointer defines a string syntax for identifying a specific value\nwithin a JSON document. It can be used with functions `at` and\n`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n@since version 2.0.0\n*/\ntemplate<typename BasicJsonType>\nclass json_pointer;\n\n/*!\n@brief default JSON class\n\nThis type is the default specialization of the @ref basic_json class which\nuses the standard template types.\n\n@since version 1.0.0\n*/\nusing json = basic_json<>;\n\ntemplate<class Key, class T, class IgnoredLess, class Allocator>\nstruct ordered_map;\n\n/*!\n@brief ordered JSON class\n\nThis type preserves the insertion order of object keys.\n\n@since version 3.9.0\n*/\nusing ordered_json = basic_json<nlohmann::ordered_map>;\n\n}  // namespace nlohmann\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n\nnamespace nlohmann\n{\n/*!\n@brief detail namespace with internal helper functions\n\nThis namespace collects functions that should not be exposed,\nimplementations of some @ref basic_json methods, and meta-programming helpers.\n\n@since version 2.1.0\n*/\nnamespace detail\n{\n/////////////\n// helpers //\n/////////////\n\n// Note to maintainers:\n//\n// Every trait in this file expects a non CV-qualified type.\n// The only exceptions are in the 'aliases for detected' section\n// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n//\n// In this case, T has to be properly CV-qualified to constraint the function arguments\n// (e.g. to_json(BasicJsonType&, const T&))\n\ntemplate<typename> struct is_basic_json : std::false_type {};\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n//////////////////////\n// json_ref helpers //\n//////////////////////\n\ntemplate<typename>\nclass json_ref;\n\ntemplate<typename>\nstruct is_json_ref : std::false_type {};\n\ntemplate<typename T>\nstruct is_json_ref<json_ref<T>> : std::true_type {};\n\n//////////////////////////\n// aliases for detected //\n//////////////////////////\n\ntemplate<typename T>\nusing mapped_type_t = typename T::mapped_type;\n\ntemplate<typename T>\nusing key_type_t = typename T::key_type;\n\ntemplate<typename T>\nusing value_type_t = typename T::value_type;\n\ntemplate<typename T>\nusing difference_type_t = typename T::difference_type;\n\ntemplate<typename T>\nusing pointer_t = typename T::pointer;\n\ntemplate<typename T>\nusing reference_t = typename T::reference;\n\ntemplate<typename T>\nusing iterator_category_t = typename T::iterator_category;\n\ntemplate<typename T>\nusing iterator_t = typename T::iterator;\n\ntemplate<typename T, typename... Args>\nusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\ntemplate<typename T, typename... Args>\nusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\ntemplate<typename T, typename U>\nusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_from_json : std::false_type {};\n\n// trait checking if j.get<T> is valid\n// use this trait instead of std::is_constructible or std::is_convertible,\n// both rely on, or make use of implicit conversions, and thus fail when T\n// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)\ntemplate <typename BasicJsonType, typename T>\nstruct is_getable\n{\n    static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;\n};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_from_json < BasicJsonType, T,\n           enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, from_json_function, serializer,\n        const BasicJsonType&, T&>::value;\n};\n\n// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n// this overload is used for non-default-constructible user-defined-types\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_non_default_from_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<T, from_json_function, serializer,\n        const BasicJsonType&>::value;\n};\n\n// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_to_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n        T>::value;\n};\n\n\n///////////////////\n// is_ functions //\n///////////////////\n\ntemplate<typename T, typename = void>\nstruct is_iterator_traits : std::false_type {};\n\ntemplate<typename T>\nstruct is_iterator_traits<iterator_traits<T>>\n{\n  private:\n    using traits = iterator_traits<T>;\n\n  public:\n    static constexpr auto value =\n        is_detected<value_type_t, traits>::value &&\n        is_detected<difference_type_t, traits>::value &&\n        is_detected<pointer_t, traits>::value &&\n        is_detected<iterator_category_t, traits>::value &&\n        is_detected<reference_t, traits>::value;\n};\n\n// The following implementation of is_complete_type is taken from\n// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/\n// and is written by Xiang Fan who agreed to using it in this library.\n\ntemplate<typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\ntemplate<typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType,\n         typename = void>\nstruct is_compatible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type_impl <\n    BasicJsonType, CompatibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&\n    is_detected<key_type_t, CompatibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    // macOS's is_constructible does not play well with nonesuch...\n    static constexpr bool value =\n        std::is_constructible<typename object_t::key_type,\n        typename CompatibleObjectType::key_type>::value &&\n        std::is_constructible<typename object_t::mapped_type,\n        typename CompatibleObjectType::mapped_type>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type\n    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         typename = void>\nstruct is_constructible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type_impl <\n    BasicJsonType, ConstructibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&\n    is_detected<key_type_t, ConstructibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    static constexpr bool value =\n        (std::is_default_constructible<ConstructibleObjectType>::value &&\n         (std::is_move_assignable<ConstructibleObjectType>::value ||\n          std::is_copy_assignable<ConstructibleObjectType>::value) &&\n         (std::is_constructible<typename ConstructibleObjectType::key_type,\n          typename object_t::key_type>::value &&\n          std::is_same <\n          typename object_t::mapped_type,\n          typename ConstructibleObjectType::mapped_type >::value)) ||\n        (has_from_json<BasicJsonType,\n         typename ConstructibleObjectType::mapped_type>::value ||\n         has_non_default_from_json <\n         BasicJsonType,\n         typename ConstructibleObjectType::mapped_type >::value);\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type\n    : is_constructible_object_type_impl<BasicJsonType,\n      ConstructibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleStringType,\n         typename = void>\nstruct is_compatible_string_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleStringType>\nstruct is_compatible_string_type_impl <\n    BasicJsonType, CompatibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, CompatibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType>\nstruct is_compatible_string_type\n    : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType,\n         typename = void>\nstruct is_constructible_string_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type_impl <\n    BasicJsonType, ConstructibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, ConstructibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<ConstructibleStringType,\n        typename BasicJsonType::string_t>::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type\n    : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType, typename = void>\nstruct is_compatible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type_impl <\n    BasicJsonType, CompatibleArrayType,\n    enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&&\n    is_detected<iterator_t, CompatibleArrayType>::value&&\n// This is needed because json_reverse_iterator has a ::iterator type...\n// Therefore it is detected as a CompatibleArrayType.\n// The real fix would be to have an Iterable concept.\n    !is_iterator_traits <\n    iterator_traits<CompatibleArrayType >>::value >>\n{\n    static constexpr bool value =\n        std::is_constructible<BasicJsonType,\n        typename CompatibleArrayType::value_type>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type\n    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType, typename = void>\nstruct is_constructible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value >>\n            : std::true_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t < !std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value&&\n    std::is_default_constructible<ConstructibleArrayType>::value&&\n(std::is_move_assignable<ConstructibleArrayType>::value ||\n std::is_copy_assignable<ConstructibleArrayType>::value)&&\nis_detected<value_type_t, ConstructibleArrayType>::value&&\nis_detected<iterator_t, ConstructibleArrayType>::value&&\nis_complete_type <\ndetected_t<value_type_t, ConstructibleArrayType >>::value >>\n{\n    static constexpr bool value =\n        // This is needed because json_reverse_iterator has a ::iterator type,\n        // furthermore, std::back_insert_iterator (and other iterators) have a\n        // base class `iterator`... Therefore it is detected as a\n        // ConstructibleArrayType. The real fix would be to have an Iterable\n        // concept.\n        !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value &&\n\n        (std::is_same<typename ConstructibleArrayType::value_type,\n         typename BasicJsonType::array_t::value_type>::value ||\n         has_from_json<BasicJsonType,\n         typename ConstructibleArrayType::value_type>::value ||\n         has_non_default_from_json <\n         BasicJsonType, typename ConstructibleArrayType::value_type >::value);\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type\n    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType,\n         typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type_impl <\n    RealIntegerType, CompatibleNumberIntegerType,\n    enable_if_t < std::is_integral<RealIntegerType>::value&&\n    std::is_integral<CompatibleNumberIntegerType>::value&&\n    !std::is_same<bool, CompatibleNumberIntegerType>::value >>\n{\n    // is there an assert somewhere on overflows?\n    using RealLimits = std::numeric_limits<RealIntegerType>;\n    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n    static constexpr auto value =\n        std::is_constructible<RealIntegerType,\n        CompatibleNumberIntegerType>::value &&\n        CompatibleLimits::is_integer &&\n        RealLimits::is_signed == CompatibleLimits::is_signed;\n};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type\n    : is_compatible_integer_type_impl<RealIntegerType,\n      CompatibleNumberIntegerType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleType, typename = void>\nstruct is_compatible_type_impl: std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type_impl <\n    BasicJsonType, CompatibleType,\n    enable_if_t<is_complete_type<CompatibleType>::value >>\n{\n    static constexpr bool value =\n        has_to_json<BasicJsonType, CompatibleType>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type\n    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n\n// https://en.cppreference.com/w/cpp/types/conjunction\ntemplate<class...> struct conjunction : std::true_type { };\ntemplate<class B1> struct conjunction<B1> : B1 { };\ntemplate<class B1, class... Bn>\nstruct conjunction<B1, Bn...>\n: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};\n\ntemplate<typename T1, typename T2>\nstruct is_constructible_tuple : std::false_type {};\n\ntemplate<typename T1, typename... Args>\nstruct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n#include <string> // string\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////////////\n// JSON type enumeration //\n///////////////////////////\n\n/*!\n@brief the JSON type enumeration\n\nThis enumeration collects the different JSON types. It is internally used to\ndistinguish the stored values, and the functions @ref basic_json::is_null(),\n@ref basic_json::is_object(), @ref basic_json::is_array(),\n@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n@ref basic_json::is_structured() rely on it.\n\n@note There are three enumeration entries (number_integer, number_unsigned, and\nnumber_float), because the library distinguishes these three types for numbers:\n@ref basic_json::number_unsigned_t is used for unsigned integers,\n@ref basic_json::number_integer_t is used for signed integers, and\n@ref basic_json::number_float_t is used for floating-point numbers or to\napproximate integers which do not fit in the limits of their respective type.\n\n@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON\nvalue with the default value for a given type\n\n@since version 1.0.0\n*/\nenum class value_t : std::uint8_t\n{\n    null,             ///< null value\n    object,           ///< object (unordered set of name/value pairs)\n    array,            ///< array (ordered collection of values)\n    string,           ///< string value\n    boolean,          ///< boolean value\n    number_integer,   ///< number value (signed integer)\n    number_unsigned,  ///< number value (unsigned integer)\n    number_float,     ///< number value (floating-point)\n    binary,           ///< binary array (ordered collection of bytes)\n    discarded         ///< discarded by the parser callback function\n};\n\n/*!\n@brief comparison operator for JSON types\n\nReturns an ordering that is similar to Python:\n- order: null < boolean < number < object < array < string < binary\n- furthermore, each type is not smaller than itself\n- discarded values are not comparable\n- binary is represented as a b\"\" string in python and directly comparable to a\n  string; however, making a binary array directly comparable with a string would\n  be surprising behavior in a JSON file.\n\n@since version 1.0.0\n*/\ninline bool operator<(const value_t lhs, const value_t rhs) noexcept\n{\n    static constexpr std::array<std::uint8_t, 9> order = {{\n            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,\n            6 /* binary */\n        }\n    };\n\n    const auto l_index = static_cast<std::size_t>(lhs);\n    const auto r_index = static_cast<std::size_t>(rhs);\n    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_null()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be null, but is \" + std::string(j.type_name())));\n    }\n    n = nullptr;\n}\n\n// overloads for basic_json template parameters\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t < std::is_arithmetic<ArithmeticType>::value&&\n                         !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n                         int > = 0 >\nvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(j.type_name())));\n    }\n    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate <\n    typename BasicJsonType, typename ConstructibleStringType,\n    enable_if_t <\n        is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&\n        !std::is_same<typename BasicJsonType::string_t,\n                      ConstructibleStringType>::value,\n        int > = 0 >\nvoid from_json(const BasicJsonType& j, ConstructibleStringType& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, EnumType& e)\n{\n    typename std::underlying_type<EnumType>::type val;\n    get_arithmetic_value(j, val);\n    e = static_cast<EnumType>(val);\n}\n\n// forward_list doesn't have an insert method\ntemplate<typename BasicJsonType, typename T, typename Allocator,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    l.clear();\n    std::transform(j.rbegin(), j.rend(),\n                   std::front_inserter(l), [](const BasicJsonType & i)\n    {\n        return i.template get<T>();\n    });\n}\n\n// valarray doesn't have an insert method\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::valarray<T>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    l.resize(j.size());\n    std::transform(j.begin(), j.end(), std::begin(l),\n                   [](const BasicJsonType & elem)\n    {\n        return elem.template get<T>();\n    });\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json(const BasicJsonType& j, T (&arr)[N])\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n{\n    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n                          priority_tag<2> /*unused*/)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n-> decltype(\n    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n    j.template get<typename ConstructibleArrayType::value_type>(),\n    void())\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    ret.reserve(j.size());\n    std::transform(j.begin(), j.end(),\n                   std::inserter(ret, end(ret)), [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nvoid from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n                          priority_tag<0> /*unused*/)\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    std::transform(\n        j.begin(), j.end(), std::inserter(ret, end(ret)),\n        [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate < typename BasicJsonType, typename ConstructibleArrayType,\n           enable_if_t <\n               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&\n               !is_basic_json<ConstructibleArrayType>::value,\n               int > = 0 >\nauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\nj.template get<typename ConstructibleArrayType::value_type>(),\nvoid())\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" +\n                                      std::string(j.type_name())));\n    }\n\n    from_json_array_impl(j, arr, priority_tag<3> {});\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(j.type_name())));\n    }\n\n    bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_object()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be object, but is \" + std::string(j.type_name())));\n    }\n\n    ConstructibleObjectType ret;\n    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n    using value_type = typename ConstructibleObjectType::value_type;\n    std::transform(\n        inner_object->begin(), inner_object->end(),\n        std::inserter(ret, ret.begin()),\n        [](typename BasicJsonType::object_t::value_type const & p)\n    {\n        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n    });\n    obj = std::move(ret);\n}\n\n// overload for arithmetic types, not chosen for basic_json template arguments\n// (BooleanType, etc..); note: Is it really necessary to provide explicit\n// overloads for boolean_t etc. in case of a custom BooleanType which is not\n// an arithmetic type?\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t <\n               std::is_arithmetic<ArithmeticType>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n               int > = 0 >\nvoid from_json(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n        case value_t::boolean:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType, typename A1, typename A2>\nvoid from_json(const BasicJsonType& j, std::pair<A1, A2>& p)\n{\n    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid from_json(const BasicJsonType& j, std::tuple<Args...>& t)\n{\n    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\nvoid from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\nvoid from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\nstruct from_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(const BasicJsonType& j, T& val) const\n    noexcept(noexcept(from_json(j, val)))\n    -> decltype(from_json(j, val), void())\n    {\n        return from_json(j, val);\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `from_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace\n{\nconstexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;\n} // namespace\n} // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n\n#include <algorithm> // copy\n#include <iterator> // begin, end\n#include <string> // string\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n\n#include <cstddef> // size_t\n#include <iterator> // input_iterator_tag\n#include <string> // string, to_string\n#include <tuple> // tuple_size, get, tuple_element\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename string_type>\nvoid int_to_string( string_type& target, std::size_t value )\n{\n    // For ADL\n    using std::to_string;\n    target = to_string(value);\n}\ntemplate<typename IteratorType> class iteration_proxy_value\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    using value_type = iteration_proxy_value;\n    using pointer = value_type * ;\n    using reference = value_type & ;\n    using iterator_category = std::input_iterator_tag;\n    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;\n\n  private:\n    /// the iterator\n    IteratorType anchor;\n    /// an index for arrays (used to create key names)\n    std::size_t array_index = 0;\n    /// last stringified array index\n    mutable std::size_t array_index_last = 0;\n    /// a string representation of the array index\n    mutable string_type array_index_str = \"0\";\n    /// an empty string (to return a reference for primitive values)\n    const string_type empty_str = \"\";\n\n  public:\n    explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}\n\n    /// dereference operator (needed for range-based for)\n    iteration_proxy_value& operator*()\n    {\n        return *this;\n    }\n\n    /// increment operator (needed for range-based for)\n    iteration_proxy_value& operator++()\n    {\n        ++anchor;\n        ++array_index;\n\n        return *this;\n    }\n\n    /// equality operator (needed for InputIterator)\n    bool operator==(const iteration_proxy_value& o) const\n    {\n        return anchor == o.anchor;\n    }\n\n    /// inequality operator (needed for range-based for)\n    bool operator!=(const iteration_proxy_value& o) const\n    {\n        return anchor != o.anchor;\n    }\n\n    /// return key of the iterator\n    const string_type& key() const\n    {\n        JSON_ASSERT(anchor.m_object != nullptr);\n\n        switch (anchor.m_object->type())\n        {\n            // use integer array index as key\n            case value_t::array:\n            {\n                if (array_index != array_index_last)\n                {\n                    int_to_string( array_index_str, array_index );\n                    array_index_last = array_index;\n                }\n                return array_index_str;\n            }\n\n            // use key from the object\n            case value_t::object:\n                return anchor.key();\n\n            // use an empty key for all primitive types\n            default:\n                return empty_str;\n        }\n    }\n\n    /// return value of the iterator\n    typename IteratorType::reference value() const\n    {\n        return anchor.value();\n    }\n};\n\n/// proxy class for the items() function\ntemplate<typename IteratorType> class iteration_proxy\n{\n  private:\n    /// the container to iterate\n    typename IteratorType::reference container;\n\n  public:\n    /// construct iteration proxy from a container\n    explicit iteration_proxy(typename IteratorType::reference cont) noexcept\n        : container(cont) {}\n\n    /// return iterator begin (needed for range-based for)\n    iteration_proxy_value<IteratorType> begin() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.begin());\n    }\n\n    /// return iterator end (needed for range-based for)\n    iteration_proxy_value<IteratorType> end() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.end());\n    }\n};\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n{\n    return i.key();\n}\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n{\n    return i.value();\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\n#if defined(__clang__)\n    // Fix: https://github.com/nlohmann/json/issues/1401\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wmismatched-tags\"\n#endif\ntemplate<typename IteratorType>\nclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>\n            : public std::integral_constant<std::size_t, 2> {};\n\ntemplate<std::size_t N, typename IteratorType>\nclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>\n{\n  public:\n    using type = decltype(\n                     get<N>(std::declval <\n                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n};\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n} // namespace std\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////\n// constructors //\n//////////////////\n\ntemplate<value_t> struct external_constructor;\n\ntemplate<>\nstruct external_constructor<value_t::boolean>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n    {\n        j.m_type = value_t::boolean;\n        j.m_value = b;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::string>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = s;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = std::move(s);\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleStringType,\n               enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleStringType& str)\n    {\n        j.m_type = value_t::string;\n        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::binary>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)\n    {\n        j.m_type = value_t::binary;\n        typename BasicJsonType::binary_t value{b};\n        j.m_value = value;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)\n    {\n        j.m_type = value_t::binary;\n        typename BasicJsonType::binary_t value{std::move(b)};\n        j.m_value = value;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_float>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n    {\n        j.m_type = value_t::number_float;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_unsigned>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n    {\n        j.m_type = value_t::number_unsigned;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_integer>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n    {\n        j.m_type = value_t::number_integer;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::array>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = arr;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = std::move(arr);\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleArrayType,\n               enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n    {\n        using std::begin;\n        using std::end;\n        j.m_type = value_t::array;\n        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const std::vector<bool>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->reserve(arr.size());\n        for (const bool x : arr)\n        {\n            j.m_value.array->push_back(x);\n        }\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename T,\n             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n    static void construct(BasicJsonType& j, const std::valarray<T>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->resize(arr.size());\n        if (arr.size() > 0)\n        {\n            std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());\n        }\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::object>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = obj;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = std::move(obj);\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleObjectType,\n               enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_type = value_t::object;\n        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n        j.assert_invariant();\n    }\n};\n\n/////////////\n// to_json //\n/////////////\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\nvoid to_json(BasicJsonType& j, T b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, b);\n}\n\ntemplate<typename BasicJsonType, typename CompatibleString,\n         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleString& s)\n{\n    external_constructor<value_t::string>::construct(j, s);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n{\n    external_constructor<value_t::string>::construct(j, std::move(s));\n}\n\ntemplate<typename BasicJsonType, typename FloatType,\n         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, FloatType val) noexcept\n{\n    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n{\n    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n{\n    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, EnumType e) noexcept\n{\n    using underlying_type = typename std::underlying_type<EnumType>::type;\n    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const std::vector<bool>& e)\n{\n    external_constructor<value_t::array>::construct(j, e);\n}\n\ntemplate < typename BasicJsonType, typename CompatibleArrayType,\n           enable_if_t < is_compatible_array_type<BasicJsonType,\n                         CompatibleArrayType>::value&&\n                         !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&\n                         !is_basic_json<CompatibleArrayType>::value,\n                         int > = 0 >\nvoid to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)\n{\n    external_constructor<value_t::binary>::construct(j, bin);\n}\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const std::valarray<T>& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate < typename BasicJsonType, typename CompatibleObjectType,\n           enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >\nvoid to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n{\n    external_constructor<value_t::object>::construct(j, obj);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n{\n    external_constructor<value_t::object>::construct(j, std::move(obj));\n}\n\ntemplate <\n    typename BasicJsonType, typename T, std::size_t N,\n    enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,\n                  const T(&)[N]>::value,\n                  int > = 0 >\nvoid to_json(BasicJsonType& j, const T(&arr)[N])\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >\nvoid to_json(BasicJsonType& j, const std::pair<T1, T2>& p)\n{\n    j = { p.first, p.second };\n}\n\n// for https://github.com/nlohmann/json/pull/1134\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const T& b)\n{\n    j = { {b.key(), b.value()} };\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    j = { std::get<Idx>(t)... };\n}\n\ntemplate<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>\nvoid to_json(BasicJsonType& j, const T& t)\n{\n    to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});\n}\n\nstruct to_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n    -> decltype(to_json(j, std::forward<T>(val)), void())\n    {\n        return to_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `to_json` function\nnamespace\n{\nconstexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;\n} // namespace\n} // namespace nlohmann\n\n\nnamespace nlohmann\n{\n\ntemplate<typename, typename>\nstruct adl_serializer\n{\n    /*!\n    @brief convert a JSON value to any value type\n\n    This function is usually called by the `get()` function of the\n    @ref basic_json class (either explicit or via conversion operators).\n\n    @param[in] j        JSON value to read from\n    @param[in,out] val  value to write to\n    */\n    template<typename BasicJsonType, typename ValueType>\n    static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(\n        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n    {\n        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n    }\n\n    /*!\n    @brief convert any value type to a JSON value\n\n    This function is usually called by the constructors of the @ref basic_json\n    class.\n\n    @param[in,out] j  JSON value to write to\n    @param[in] val    value to read from\n    */\n    template<typename BasicJsonType, typename ValueType>\n    static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(\n        noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))\n    -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())\n    {\n        ::nlohmann::to_json(j, std::forward<ValueType>(val));\n    }\n};\n\n}  // namespace nlohmann\n\n// #include <nlohmann/byte_container_with_subtype.hpp>\n\n\n#include <cstdint> // uint8_t\n#include <tuple> // tie\n#include <utility> // move\n\nnamespace nlohmann\n{\n\n/*!\n@brief an internal type for a backed binary type\n\nThis type extends the template parameter @a BinaryType provided to `basic_json`\nwith a subtype used by BSON and MessagePack. This type exists so that the user\ndoes not have to specify a type themselves with a specific naming scheme in\norder to override the binary type.\n\n@tparam BinaryType container to store bytes (`std::vector<std::uint8_t>` by\n                   default)\n\n@since version 3.8.0\n*/\ntemplate<typename BinaryType>\nclass byte_container_with_subtype : public BinaryType\n{\n  public:\n    /// the type of the underlying container\n    using container_type = BinaryType;\n\n    byte_container_with_subtype() noexcept(noexcept(container_type()))\n        : container_type()\n    {}\n\n    byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n    {}\n\n    byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n    {}\n\n    byte_container_with_subtype(const container_type& b, std::uint8_t subtype_) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    byte_container_with_subtype(container_type&& b, std::uint8_t subtype_) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    bool operator==(const byte_container_with_subtype& rhs) const\n    {\n        return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==\n               std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);\n    }\n\n    bool operator!=(const byte_container_with_subtype& rhs) const\n    {\n        return !(rhs == *this);\n    }\n\n    /*!\n    @brief sets the binary subtype\n\n    Sets the binary subtype of the value, also flags a binary JSON value as\n    having a subtype, which has implications for serialization.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa @ref subtype() -- return the binary subtype\n    @sa @ref clear_subtype() -- clears the binary subtype\n    @sa @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0\n    */\n    void set_subtype(std::uint8_t subtype_) noexcept\n    {\n        m_subtype = subtype_;\n        m_has_subtype = true;\n    }\n\n    /*!\n    @brief return the binary subtype\n\n    Returns the numerical subtype of the value if it has a subtype. If it does\n    not have a subtype, this function will return size_t(-1) as a sentinel\n    value.\n\n    @return the numerical subtype of the binary value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa @ref set_subtype() -- sets the binary subtype\n    @sa @ref clear_subtype() -- clears the binary subtype\n    @sa @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0\n    */\n    constexpr std::uint8_t subtype() const noexcept\n    {\n        return m_subtype;\n    }\n\n    /*!\n    @brief return whether the value has a subtype\n\n    @return whether the value has a subtype\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa @ref subtype() -- return the binary subtype\n    @sa @ref set_subtype() -- sets the binary subtype\n    @sa @ref clear_subtype() -- clears the binary subtype\n\n    @since version 3.8.0\n    */\n    constexpr bool has_subtype() const noexcept\n    {\n        return m_has_subtype;\n    }\n\n    /*!\n    @brief clears the binary subtype\n\n    Clears the binary subtype and flags the value as not having a subtype, which\n    has implications for serialization; for instance MessagePack will prefer the\n    bin family over the ext family.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @sa @ref subtype() -- return the binary subtype\n    @sa @ref set_subtype() -- sets the binary subtype\n    @sa @ref has_subtype() -- returns whether or not the binary value has a\n    subtype\n\n    @since version 3.8.0\n    */\n    void clear_subtype() noexcept\n    {\n        m_subtype = 0;\n        m_has_subtype = false;\n    }\n\n  private:\n    std::uint8_t m_subtype = 0;\n    bool m_has_subtype = false;\n};\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/hash.hpp>\n\n\n#include <cstddef> // size_t, uint8_t\n#include <functional> // hash\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n// boost::hash_combine\ninline std::size_t combine(std::size_t seed, std::size_t h) noexcept\n{\n    seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);\n    return seed;\n}\n\n/*!\n@brief hash a JSON value\n\nThe hash function tries to rely on std::hash where possible. Furthermore, the\ntype of the JSON value is taken into account to have different hash values for\nnull, 0, 0U, and false, etc.\n\n@tparam BasicJsonType basic_json specialization\n@param j JSON value to hash\n@return hash value of j\n*/\ntemplate<typename BasicJsonType>\nstd::size_t hash(const BasicJsonType& j)\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n    const auto type = static_cast<std::size_t>(j.type());\n    switch (j.type())\n    {\n        case BasicJsonType::value_t::null:\n        case BasicJsonType::value_t::discarded:\n        {\n            return combine(type, 0);\n        }\n\n        case BasicJsonType::value_t::object:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j.items())\n            {\n                const auto h = std::hash<string_t> {}(element.key());\n                seed = combine(seed, h);\n                seed = combine(seed, hash(element.value()));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::array:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j)\n            {\n                seed = combine(seed, hash(element));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::string:\n        {\n            const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::boolean:\n        {\n            const auto h = std::hash<bool> {}(j.template get<bool>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_integer:\n        {\n            const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_unsigned:\n        {\n            const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_float:\n        {\n            const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::binary:\n        {\n            auto seed = combine(type, j.get_binary().size());\n            const auto h = std::hash<bool> {}(j.get_binary().has_subtype());\n            seed = combine(seed, h);\n            seed = combine(seed, j.get_binary().subtype());\n            for (const auto byte : j.get_binary())\n            {\n                seed = combine(seed, std::hash<std::uint8_t> {}(byte));\n            }\n            return seed;\n        }\n\n        default:                   // LCOV_EXCL_LINE\n            JSON_ASSERT(false);    // LCOV_EXCL_LINE\n            return 0;              // LCOV_EXCL_LINE\n    }\n}\n\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstdio> //FILE *\n#include <cstring> // strlen\n#include <istream> // istream\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// the supported input formats\nenum class input_format_t { json, cbor, msgpack, ubjson, bson };\n\n////////////////////\n// input adapters //\n////////////////////\n\n/*!\nInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n buffer. This adapter is a very low level adapter.\n*/\nclass file_input_adapter\n{\n  public:\n    using char_type = char;\n\n    JSON_HEDLEY_NON_NULL(2)\n    explicit file_input_adapter(std::FILE* f) noexcept\n        : m_file(f)\n    {}\n\n    // make class move-only\n    file_input_adapter(const file_input_adapter&) = delete;\n    file_input_adapter(file_input_adapter&&) = default;\n    file_input_adapter& operator=(const file_input_adapter&) = delete;\n    file_input_adapter& operator=(file_input_adapter&&) = delete;\n\n    std::char_traits<char>::int_type get_character() noexcept\n    {\n        return std::fgetc(m_file);\n    }\n\n  private:\n    /// the file pointer to read from\n    std::FILE* m_file;\n};\n\n\n/*!\nInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\nbeginning of input. Does not support changing the underlying std::streambuf\nin mid-input. Maintains underlying std::istream and std::streambuf to support\nsubsequent use of standard std::istream operations to process any input\ncharacters following those used in parsing the JSON input.  Clears the\nstd::istream flags; any input errors (e.g., EOF) will be detected by the first\nsubsequent call for input from the std::istream.\n*/\nclass input_stream_adapter\n{\n  public:\n    using char_type = char;\n\n    ~input_stream_adapter()\n    {\n        // clear stream flags; we use underlying streambuf I/O, do not\n        // maintain ifstream flags, except eof\n        if (is != nullptr)\n        {\n            is->clear(is->rdstate() & std::ios::eofbit);\n        }\n    }\n\n    explicit input_stream_adapter(std::istream& i)\n        : is(&i), sb(i.rdbuf())\n    {}\n\n    // delete because of pointer members\n    input_stream_adapter(const input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete;\n\n    input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb)\n    {\n        rhs.is = nullptr;\n        rhs.sb = nullptr;\n    }\n\n    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n    // ensure that std::char_traits<char>::eof() and the character 0xFF do not\n    // end up as the same value, eg. 0xFFFFFFFF.\n    std::char_traits<char>::int_type get_character()\n    {\n        auto res = sb->sbumpc();\n        // set eof manually, as we don't use the istream interface.\n        if (JSON_HEDLEY_UNLIKELY(res == EOF))\n        {\n            is->clear(is->rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n  private:\n    /// the associated input stream\n    std::istream* is = nullptr;\n    std::streambuf* sb = nullptr;\n};\n\n// General-purpose iterator-based adapter. It might not be as fast as\n// theoretically possible for some containers, but it is extremely versatile.\ntemplate<typename IteratorType>\nclass iterator_input_adapter\n{\n  public:\n    using char_type = typename std::iterator_traits<IteratorType>::value_type;\n\n    iterator_input_adapter(IteratorType first, IteratorType last)\n        : current(std::move(first)), end(std::move(last)) {}\n\n    typename std::char_traits<char_type>::int_type get_character()\n    {\n        if (JSON_HEDLEY_LIKELY(current != end))\n        {\n            auto result = std::char_traits<char_type>::to_int_type(*current);\n            std::advance(current, 1);\n            return result;\n        }\n        else\n        {\n            return std::char_traits<char_type>::eof();\n        }\n    }\n\n  private:\n    IteratorType current;\n    IteratorType end;\n\n    template<typename BaseInputAdapter, size_t T>\n    friend struct wide_string_input_helper;\n\n    bool empty() const\n    {\n        return current == end;\n    }\n\n};\n\n\ntemplate<typename BaseInputAdapter, size_t T>\nstruct wide_string_input_helper;\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 4>\n{\n    // UTF-32\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-32 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (wc <= 0xFFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else if (wc <= 0x10FFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 4;\n            }\n            else\n            {\n                // unknown character\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n        }\n    }\n};\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 2>\n{\n    // UTF-16\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-16 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (0xD800 > wc || wc >= 0xE000)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else\n            {\n                if (JSON_HEDLEY_UNLIKELY(!input.empty()))\n                {\n                    const auto wc2 = static_cast<unsigned int>(input.get_character());\n                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));\n                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));\n                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));\n                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));\n                    utf8_bytes_filled = 4;\n                }\n                else\n                {\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                    utf8_bytes_filled = 1;\n                }\n            }\n        }\n    }\n};\n\n// Wraps another input apdater to convert wide character types into individual bytes.\ntemplate<typename BaseInputAdapter, typename WideCharType>\nclass wide_string_input_adapter\n{\n  public:\n    using char_type = char;\n\n    wide_string_input_adapter(BaseInputAdapter base)\n        : base_adapter(base) {}\n\n    typename std::char_traits<char>::int_type get_character() noexcept\n    {\n        // check if buffer needs to be filled\n        if (utf8_bytes_index == utf8_bytes_filled)\n        {\n            fill_buffer<sizeof(WideCharType)>();\n\n            JSON_ASSERT(utf8_bytes_filled > 0);\n            JSON_ASSERT(utf8_bytes_index == 0);\n        }\n\n        // use buffer\n        JSON_ASSERT(utf8_bytes_filled > 0);\n        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);\n        return utf8_bytes[utf8_bytes_index++];\n    }\n\n  private:\n    BaseInputAdapter base_adapter;\n\n    template<size_t T>\n    void fill_buffer()\n    {\n        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n    }\n\n    /// a buffer for UTF-8 bytes\n    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};\n\n    /// index to the utf8_codes array for the next valid byte\n    std::size_t utf8_bytes_index = 0;\n    /// number of valid bytes in the utf8_codes array\n    std::size_t utf8_bytes_filled = 0;\n};\n\n\ntemplate<typename IteratorType, typename Enable = void>\nstruct iterator_input_adapter_factory\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using adapter_type = iterator_input_adapter<iterator_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(std::move(first), std::move(last));\n    }\n};\n\ntemplate<typename T>\nstruct is_iterator_of_multibyte\n{\n    using value_type = typename std::iterator_traits<T>::value_type;\n    enum\n    {\n        value = sizeof(value_type) > 1\n    };\n};\n\ntemplate<typename IteratorType>\nstruct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using base_adapter_type = iterator_input_adapter<iterator_type>;\n    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(base_adapter_type(std::move(first), std::move(last)));\n    }\n};\n\n// General purpose iterator-based input\ntemplate<typename IteratorType>\ntypename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)\n{\n    using factory_type = iterator_input_adapter_factory<IteratorType>;\n    return factory_type::create(first, last);\n}\n\n// Convenience shorthand from container to iterator\n// Enables ADL on begin(container) and end(container)\n// Encloses the using declarations in namespace for not to leak them to outside scope\n\nnamespace container_input_adapter_factory_impl\n{\n\nusing std::begin;\nusing std::end;\n\ntemplate<typename ContainerType, typename Enable = void>\nstruct container_input_adapter_factory {};\n\ntemplate<typename ContainerType>\nstruct container_input_adapter_factory< ContainerType,\n       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>\n       {\n           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));\n\n           static adapter_type create(const ContainerType& container)\n{\n    return input_adapter(begin(container), end(container));\n}\n       };\n\n}\n\ntemplate<typename ContainerType>\ntypename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)\n{\n    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);\n}\n\n// Special cases with fast paths\ninline file_input_adapter input_adapter(std::FILE* file)\n{\n    return file_input_adapter(file);\n}\n\ninline input_stream_adapter input_adapter(std::istream& stream)\n{\n    return input_stream_adapter(stream);\n}\n\ninline input_stream_adapter input_adapter(std::istream&& stream)\n{\n    return input_stream_adapter(stream);\n}\n\nusing contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));\n\n// Null-delimited strings, and the like.\ntemplate < typename CharT,\n           typename std::enable_if <\n               std::is_pointer<CharT>::value&&\n               !std::is_array<CharT>::value&&\n               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n               sizeof(typename std::remove_pointer<CharT>::type) == 1,\n               int >::type = 0 >\ncontiguous_bytes_input_adapter input_adapter(CharT b)\n{\n    auto length = std::strlen(reinterpret_cast<const char*>(b));\n    const auto* ptr = reinterpret_cast<const char*>(b);\n    return input_adapter(ptr, ptr + length);\n}\n\ntemplate<typename T, std::size_t N>\nauto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N))\n{\n    return input_adapter(array, array + N);\n}\n\n// This class only handles inputs of input_buffer_adapter type.\n// It's required so that expressions like {ptr, len} can be implicitely casted\n// to the correct adapter.\nclass span_input_adapter\n{\n  public:\n    template < typename CharT,\n               typename std::enable_if <\n                   std::is_pointer<CharT>::value&&\n                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n                   sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                   int >::type = 0 >\n    span_input_adapter(CharT b, std::size_t l)\n        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}\n\n    template<class IteratorType,\n             typename std::enable_if<\n                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n                 int>::type = 0>\n    span_input_adapter(IteratorType first, IteratorType last)\n        : ia(input_adapter(first, last)) {}\n\n    contiguous_bytes_input_adapter&& get()\n    {\n        return std::move(ia);\n    }\n\n  private:\n    contiguous_bytes_input_adapter ia;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n\n#include <cstddef>\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\n/*!\n@brief SAX interface\n\nThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\nEach function is called in different situations while the input is parsed. The\nboolean return value informs the parser whether to continue processing the\ninput.\n*/\ntemplate<typename BasicJsonType>\nstruct json_sax\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    /*!\n    @brief a null value was read\n    @return whether parsing should proceed\n    */\n    virtual bool null() = 0;\n\n    /*!\n    @brief a boolean value was read\n    @param[in] val  boolean value\n    @return whether parsing should proceed\n    */\n    virtual bool boolean(bool val) = 0;\n\n    /*!\n    @brief an integer number was read\n    @param[in] val  integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_integer(number_integer_t val) = 0;\n\n    /*!\n    @brief an unsigned integer number was read\n    @param[in] val  unsigned integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_unsigned(number_unsigned_t val) = 0;\n\n    /*!\n    @brief an floating-point number was read\n    @param[in] val  floating-point value\n    @param[in] s    raw token value\n    @return whether parsing should proceed\n    */\n    virtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n    /*!\n    @brief a string was read\n    @param[in] val  string value\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool string(string_t& val) = 0;\n\n    /*!\n    @brief a binary string was read\n    @param[in] val  binary value\n    @return whether parsing should proceed\n    @note It is safe to move the passed binary.\n    */\n    virtual bool binary(binary_t& val) = 0;\n\n    /*!\n    @brief the beginning of an object was read\n    @param[in] elements  number of object elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_object(std::size_t elements) = 0;\n\n    /*!\n    @brief an object key was read\n    @param[in] val  object key\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool key(string_t& val) = 0;\n\n    /*!\n    @brief the end of an object was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_object() = 0;\n\n    /*!\n    @brief the beginning of an array was read\n    @param[in] elements  number of array elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_array(std::size_t elements) = 0;\n\n    /*!\n    @brief the end of an array was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_array() = 0;\n\n    /*!\n    @brief a parse error occurred\n    @param[in] position    the position in the input where the error occurs\n    @param[in] last_token  the last read token\n    @param[in] ex          an exception object describing the error\n    @return whether parsing should proceed (must return false)\n    */\n    virtual bool parse_error(std::size_t position,\n                             const std::string& last_token,\n                             const detail::exception& ex) = 0;\n\n    virtual ~json_sax() = default;\n};\n\n\nnamespace detail\n{\n/*!\n@brief SAX implementation to create a JSON value from SAX events\n\nThis class implements the @ref json_sax interface and processes the SAX events\nto create a JSON value which makes it basically a DOM parser. The structure or\nhierarchy of the JSON value is managed by the stack `ref_stack` which contains\na pointer to the respective array or object for each recursion depth.\n\nAfter successful parsing, the value that is passed by reference to the\nconstructor contains the parsed value.\n\n@tparam BasicJsonType  the JSON type\n*/\ntemplate<typename BasicJsonType>\nclass json_sax_dom_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    /*!\n    @param[in, out] r  reference to a JSON value that is manipulated while\n                       parsing\n    @param[in] allow_exceptions_  whether parse errors yield exceptions\n    */\n    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)\n        : root(r), allow_exceptions(allow_exceptions_)\n    {}\n\n    // make class move-only\n    json_sax_dom_parser(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser(json_sax_dom_parser&&) = default;\n    json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;\n    ~json_sax_dom_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n        if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive object size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        // add null at given key and store the reference for later\n        object_element = &(ref_stack.back()->m_value.object->operator[](val));\n        return true;\n    }\n\n    bool end_object()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n        if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive array size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n    */\n    template<typename Value>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    BasicJsonType* handle_value(Value&& v)\n    {\n        if (ref_stack.empty())\n        {\n            root = BasicJsonType(std::forward<Value>(v));\n            return &root;\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));\n            return &(ref_stack.back()->m_value.array->back());\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_object());\n        JSON_ASSERT(object_element);\n        *object_element = BasicJsonType(std::forward<Value>(v));\n        return object_element;\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_dom_callback_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using parser_callback_t = typename BasicJsonType::parser_callback_t;\n    using parse_event_t = typename BasicJsonType::parse_event_t;\n\n    json_sax_dom_callback_parser(BasicJsonType& r,\n                                 const parser_callback_t cb,\n                                 const bool allow_exceptions_ = true)\n        : root(r), callback(cb), allow_exceptions(allow_exceptions_)\n    {\n        keep_stack.push_back(true);\n    }\n\n    // make class move-only\n    json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;\n    json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;\n    ~json_sax_dom_callback_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        // check callback for object start\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::object, true);\n        ref_stack.push_back(val.second);\n\n        // check object limit\n        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive object size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        BasicJsonType k = BasicJsonType(val);\n\n        // check callback for key\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n        key_keep_stack.push_back(keep);\n\n        // add discarded value at given key and store the reference for later\n        if (keep && ref_stack.back())\n        {\n            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);\n        }\n\n        return true;\n    }\n\n    bool end_object()\n    {\n        if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n        {\n            // discard object\n            *ref_stack.back() = discarded;\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())\n        {\n            // remove discarded value\n            for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n            {\n                if (it->is_discarded())\n                {\n                    ref_stack.back()->erase(it);\n                    break;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::array, true);\n        ref_stack.push_back(val.second);\n\n        // check array limit\n        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, \"excessive array size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        bool keep = true;\n\n        if (ref_stack.back())\n        {\n            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n            if (!keep)\n            {\n                // discard array\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        // remove discarded value\n        if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->pop_back();\n        }\n\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @param[in] v  value to add to the JSON value we build during parsing\n    @param[in] skip_callback  whether we should skip calling the callback\n               function; this is required after start_array() and\n               start_object() SAX events, because otherwise we would call the\n               callback function with an empty array or object, respectively.\n\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n\n    @return pair of boolean (whether value should be kept) and pointer (to the\n            passed value in the ref_stack hierarchy; nullptr if not kept)\n    */\n    template<typename Value>\n    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n    {\n        JSON_ASSERT(!keep_stack.empty());\n\n        // do not handle this value if we know it would be added to a discarded\n        // container\n        if (!keep_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // create value\n        auto value = BasicJsonType(std::forward<Value>(v));\n\n        // check callback\n        const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n        // do not handle this value if we just learnt it shall be discarded\n        if (!keep)\n        {\n            return {false, nullptr};\n        }\n\n        if (ref_stack.empty())\n        {\n            root = std::move(value);\n            return {true, &root};\n        }\n\n        // skip this value if we already decided to skip the parent\n        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n        if (!ref_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // we now only expect arrays and objects\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        // array\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->push_back(std::move(value));\n            return {true, &(ref_stack.back()->m_value.array->back())};\n        }\n\n        // object\n        JSON_ASSERT(ref_stack.back()->is_object());\n        // check if we should store an element for the current key\n        JSON_ASSERT(!key_keep_stack.empty());\n        const bool store_element = key_keep_stack.back();\n        key_keep_stack.pop_back();\n\n        if (!store_element)\n        {\n            return {false, nullptr};\n        }\n\n        JSON_ASSERT(object_element);\n        *object_element = std::move(value);\n        return {true, object_element};\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// stack to manage which values to keep\n    std::vector<bool> keep_stack {};\n    /// stack to manage which object keys to keep\n    std::vector<bool> key_keep_stack {};\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// a discarded value for the callback\n    BasicJsonType discarded = BasicJsonType::value_t::discarded;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_acceptor\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    bool null()\n    {\n        return true;\n    }\n\n    bool boolean(bool /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_integer(number_integer_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool string(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool binary(binary_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool start_object(std::size_t /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool key(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool end_object()\n    {\n        return true;\n    }\n\n    bool start_array(std::size_t /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool end_array()\n    {\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n    {\n        return false;\n    }\n};\n}  // namespace detail\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n\n#include <array> // array\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdio> // snprintf\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////\n// lexer //\n///////////\n\ntemplate<typename BasicJsonType>\nclass lexer_base\n{\n  public:\n    /// token types for the parser\n    enum class token_type\n    {\n        uninitialized,    ///< indicating the scanner is uninitialized\n        literal_true,     ///< the `true` literal\n        literal_false,    ///< the `false` literal\n        literal_null,     ///< the `null` literal\n        value_string,     ///< a string -- use get_string() for actual value\n        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n        value_integer,    ///< a signed integer -- use get_number_integer() for actual value\n        value_float,      ///< an floating point number -- use get_number_float() for actual value\n        begin_array,      ///< the character for array begin `[`\n        begin_object,     ///< the character for object begin `{`\n        end_array,        ///< the character for array end `]`\n        end_object,       ///< the character for object end `}`\n        name_separator,   ///< the name separator `:`\n        value_separator,  ///< the value separator `,`\n        parse_error,      ///< indicating a parse error\n        end_of_input,     ///< indicating the end of the input buffer\n        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)\n    };\n\n    /// return name of values of type token_type (only used for errors)\n    JSON_HEDLEY_RETURNS_NON_NULL\n    JSON_HEDLEY_CONST\n    static const char* token_type_name(const token_type t) noexcept\n    {\n        switch (t)\n        {\n            case token_type::uninitialized:\n                return \"<uninitialized>\";\n            case token_type::literal_true:\n                return \"true literal\";\n            case token_type::literal_false:\n                return \"false literal\";\n            case token_type::literal_null:\n                return \"null literal\";\n            case token_type::value_string:\n                return \"string literal\";\n            case token_type::value_unsigned:\n            case token_type::value_integer:\n            case token_type::value_float:\n                return \"number literal\";\n            case token_type::begin_array:\n                return \"'['\";\n            case token_type::begin_object:\n                return \"'{'\";\n            case token_type::end_array:\n                return \"']'\";\n            case token_type::end_object:\n                return \"'}'\";\n            case token_type::name_separator:\n                return \"':'\";\n            case token_type::value_separator:\n                return \"','\";\n            case token_type::parse_error:\n                return \"<parse error>\";\n            case token_type::end_of_input:\n                return \"end of input\";\n            case token_type::literal_or_value:\n                return \"'[', '{', or a literal\";\n            // LCOV_EXCL_START\n            default: // catch non-enum values\n                return \"unknown token\";\n                // LCOV_EXCL_STOP\n        }\n    }\n};\n/*!\n@brief lexical analysis\n\nThis class organizes the lexical analysis during JSON deserialization.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass lexer : public lexer_base<BasicJsonType>\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename std::char_traits<char_type>::int_type;\n\n  public:\n    using token_type = typename lexer_base<BasicJsonType>::token_type;\n\n    explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false)\n        : ia(std::move(adapter))\n        , ignore_comments(ignore_comments_)\n        , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))\n    {}\n\n    // delete because of pointer members\n    lexer(const lexer&) = delete;\n    lexer(lexer&&) = default;\n    lexer& operator=(lexer&) = delete;\n    lexer& operator=(lexer&&) = default;\n    ~lexer() = default;\n\n  private:\n    /////////////////////\n    // locales\n    /////////////////////\n\n    /// return the locale-dependent decimal point\n    JSON_HEDLEY_PURE\n    static char get_decimal_point() noexcept\n    {\n        const auto* loc = localeconv();\n        JSON_ASSERT(loc != nullptr);\n        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n    }\n\n    /////////////////////\n    // scan functions\n    /////////////////////\n\n    /*!\n    @brief get codepoint from 4 hex characters following `\\u`\n\n    For input \"\\u c1 c2 c3 c4\" the codepoint is:\n      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n    between the ASCII value of the character and the desired integer value.\n\n    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n            non-hex character)\n    */\n    int get_codepoint()\n    {\n        // this function only makes sense after reading `\\u`\n        JSON_ASSERT(current == 'u');\n        int codepoint = 0;\n\n        const auto factors = { 12u, 8u, 4u, 0u };\n        for (const auto factor : factors)\n        {\n            get();\n\n            if (current >= '0' && current <= '9')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);\n            }\n            else if (current >= 'A' && current <= 'F')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);\n            }\n            else if (current >= 'a' && current <= 'f')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);\n            }\n            else\n            {\n                return -1;\n            }\n        }\n\n        JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);\n        return codepoint;\n    }\n\n    /*!\n    @brief check if the next byte(s) are inside a given range\n\n    Adds the current byte and, for each passed range, reads a new byte and\n    checks if it is inside the range. If a violation was detected, set up an\n    error message and return false. Otherwise, return true.\n\n    @param[in] ranges  list of integers; interpreted as list of pairs of\n                       inclusive lower and upper bound, respectively\n\n    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n         1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n    @return true if and only if no range violation was detected\n    */\n    bool next_byte_in_range(std::initializer_list<char_int_type> ranges)\n    {\n        JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);\n        add(current);\n\n        for (auto range = ranges.begin(); range != ranges.end(); ++range)\n        {\n            get();\n            if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))\n            {\n                add(current);\n            }\n            else\n            {\n                error_message = \"invalid string: ill-formed UTF-8 byte\";\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief scan a string literal\n\n    This function scans a string according to Sect. 7 of RFC 7159. While\n    scanning, bytes are escaped and copied into buffer token_buffer. Then the\n    function returns successfully, token_buffer is *not* null-terminated (as it\n    may contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n    string.\n\n    @return token_type::value_string if string could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note In case of errors, variable error_message contains a textual\n          description.\n    */\n    token_type scan_string()\n    {\n        // reset token_buffer (ignore opening quote)\n        reset();\n\n        // we entered the function by reading an open quote\n        JSON_ASSERT(current == '\\\"');\n\n        while (true)\n        {\n            // get next character\n            switch (get())\n            {\n                // end of file while parsing string\n                case std::char_traits<char_type>::eof():\n                {\n                    error_message = \"invalid string: missing closing quote\";\n                    return token_type::parse_error;\n                }\n\n                // closing quote\n                case '\\\"':\n                {\n                    return token_type::value_string;\n                }\n\n                // escapes\n                case '\\\\':\n                {\n                    switch (get())\n                    {\n                        // quotation mark\n                        case '\\\"':\n                            add('\\\"');\n                            break;\n                        // reverse solidus\n                        case '\\\\':\n                            add('\\\\');\n                            break;\n                        // solidus\n                        case '/':\n                            add('/');\n                            break;\n                        // backspace\n                        case 'b':\n                            add('\\b');\n                            break;\n                        // form feed\n                        case 'f':\n                            add('\\f');\n                            break;\n                        // line feed\n                        case 'n':\n                            add('\\n');\n                            break;\n                        // carriage return\n                        case 'r':\n                            add('\\r');\n                            break;\n                        // tab\n                        case 't':\n                            add('\\t');\n                            break;\n\n                        // unicode escapes\n                        case 'u':\n                        {\n                            const int codepoint1 = get_codepoint();\n                            int codepoint = codepoint1; // start with codepoint1\n\n                            if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))\n                            {\n                                error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                return token_type::parse_error;\n                            }\n\n                            // check if code point is a high surrogate\n                            if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)\n                            {\n                                // expect next \\uxxxx entry\n                                if (JSON_HEDLEY_LIKELY(get() == '\\\\' && get() == 'u'))\n                                {\n                                    const int codepoint2 = get_codepoint();\n\n                                    if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))\n                                    {\n                                        error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                        return token_type::parse_error;\n                                    }\n\n                                    // check if codepoint2 is a low surrogate\n                                    if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))\n                                    {\n                                        // overwrite codepoint\n                                        codepoint = static_cast<int>(\n                                                        // high surrogate occupies the most significant 22 bits\n                                                        (static_cast<unsigned int>(codepoint1) << 10u)\n                                                        // low surrogate occupies the least significant 15 bits\n                                                        + static_cast<unsigned int>(codepoint2)\n                                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise\n                                                        // in the result so we have to subtract with:\n                                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n                                                        - 0x35FDC00u);\n                                    }\n                                    else\n                                    {\n                                        error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                        return token_type::parse_error;\n                                    }\n                                }\n                                else\n                                {\n                                    error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n                            else\n                            {\n                                if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n\n                            // result of the above calculation yields a proper codepoint\n                            JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);\n\n                            // translate codepoint into bytes\n                            if (codepoint < 0x80)\n                            {\n                                // 1-byte characters: 0xxxxxxx (ASCII)\n                                add(static_cast<char_int_type>(codepoint));\n                            }\n                            else if (codepoint <= 0x7FF)\n                            {\n                                // 2-byte characters: 110xxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else if (codepoint <= 0xFFFF)\n                            {\n                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else\n                            {\n                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n\n                            break;\n                        }\n\n                        // other characters after escape\n                        default:\n                            error_message = \"invalid string: forbidden character after backslash\";\n                            return token_type::parse_error;\n                    }\n\n                    break;\n                }\n\n                // invalid control characters\n                case 0x00:\n                {\n                    error_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n                    return token_type::parse_error;\n                }\n\n                case 0x01:\n                {\n                    error_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n                    return token_type::parse_error;\n                }\n\n                case 0x02:\n                {\n                    error_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n                    return token_type::parse_error;\n                }\n\n                case 0x03:\n                {\n                    error_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n                    return token_type::parse_error;\n                }\n\n                case 0x04:\n                {\n                    error_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n                    return token_type::parse_error;\n                }\n\n                case 0x05:\n                {\n                    error_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n                    return token_type::parse_error;\n                }\n\n                case 0x06:\n                {\n                    error_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n                    return token_type::parse_error;\n                }\n\n                case 0x07:\n                {\n                    error_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n                    return token_type::parse_error;\n                }\n\n                case 0x08:\n                {\n                    error_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n                    return token_type::parse_error;\n                }\n\n                case 0x09:\n                {\n                    error_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0A:\n                {\n                    error_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0B:\n                {\n                    error_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0C:\n                {\n                    error_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0D:\n                {\n                    error_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0E:\n                {\n                    error_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0F:\n                {\n                    error_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n                    return token_type::parse_error;\n                }\n\n                case 0x10:\n                {\n                    error_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n                    return token_type::parse_error;\n                }\n\n                case 0x11:\n                {\n                    error_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n                    return token_type::parse_error;\n                }\n\n                case 0x12:\n                {\n                    error_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n                    return token_type::parse_error;\n                }\n\n                case 0x13:\n                {\n                    error_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n                    return token_type::parse_error;\n                }\n\n                case 0x14:\n                {\n                    error_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n                    return token_type::parse_error;\n                }\n\n                case 0x15:\n                {\n                    error_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n                    return token_type::parse_error;\n                }\n\n                case 0x16:\n                {\n                    error_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n                    return token_type::parse_error;\n                }\n\n                case 0x17:\n                {\n                    error_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n                    return token_type::parse_error;\n                }\n\n                case 0x18:\n                {\n                    error_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n                    return token_type::parse_error;\n                }\n\n                case 0x19:\n                {\n                    error_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1A:\n                {\n                    error_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1B:\n                {\n                    error_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1C:\n                {\n                    error_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1D:\n                {\n                    error_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1E:\n                {\n                    error_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1F:\n                {\n                    error_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n                    return token_type::parse_error;\n                }\n\n                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n                case 0x20:\n                case 0x21:\n                case 0x23:\n                case 0x24:\n                case 0x25:\n                case 0x26:\n                case 0x27:\n                case 0x28:\n                case 0x29:\n                case 0x2A:\n                case 0x2B:\n                case 0x2C:\n                case 0x2D:\n                case 0x2E:\n                case 0x2F:\n                case 0x30:\n                case 0x31:\n                case 0x32:\n                case 0x33:\n                case 0x34:\n                case 0x35:\n                case 0x36:\n                case 0x37:\n                case 0x38:\n                case 0x39:\n                case 0x3A:\n                case 0x3B:\n                case 0x3C:\n                case 0x3D:\n                case 0x3E:\n                case 0x3F:\n                case 0x40:\n                case 0x41:\n                case 0x42:\n                case 0x43:\n                case 0x44:\n                case 0x45:\n                case 0x46:\n                case 0x47:\n                case 0x48:\n                case 0x49:\n                case 0x4A:\n                case 0x4B:\n                case 0x4C:\n                case 0x4D:\n                case 0x4E:\n                case 0x4F:\n                case 0x50:\n                case 0x51:\n                case 0x52:\n                case 0x53:\n                case 0x54:\n                case 0x55:\n                case 0x56:\n                case 0x57:\n                case 0x58:\n                case 0x59:\n                case 0x5A:\n                case 0x5B:\n                case 0x5D:\n                case 0x5E:\n                case 0x5F:\n                case 0x60:\n                case 0x61:\n                case 0x62:\n                case 0x63:\n                case 0x64:\n                case 0x65:\n                case 0x66:\n                case 0x67:\n                case 0x68:\n                case 0x69:\n                case 0x6A:\n                case 0x6B:\n                case 0x6C:\n                case 0x6D:\n                case 0x6E:\n                case 0x6F:\n                case 0x70:\n                case 0x71:\n                case 0x72:\n                case 0x73:\n                case 0x74:\n                case 0x75:\n                case 0x76:\n                case 0x77:\n                case 0x78:\n                case 0x79:\n                case 0x7A:\n                case 0x7B:\n                case 0x7C:\n                case 0x7D:\n                case 0x7E:\n                case 0x7F:\n                {\n                    add(current);\n                    break;\n                }\n\n                // U+0080..U+07FF: bytes C2..DF 80..BF\n                case 0xC2:\n                case 0xC3:\n                case 0xC4:\n                case 0xC5:\n                case 0xC6:\n                case 0xC7:\n                case 0xC8:\n                case 0xC9:\n                case 0xCA:\n                case 0xCB:\n                case 0xCC:\n                case 0xCD:\n                case 0xCE:\n                case 0xCF:\n                case 0xD0:\n                case 0xD1:\n                case 0xD2:\n                case 0xD3:\n                case 0xD4:\n                case 0xD5:\n                case 0xD6:\n                case 0xD7:\n                case 0xD8:\n                case 0xD9:\n                case 0xDA:\n                case 0xDB:\n                case 0xDC:\n                case 0xDD:\n                case 0xDE:\n                case 0xDF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n                case 0xE0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n                case 0xE1:\n                case 0xE2:\n                case 0xE3:\n                case 0xE4:\n                case 0xE5:\n                case 0xE6:\n                case 0xE7:\n                case 0xE8:\n                case 0xE9:\n                case 0xEA:\n                case 0xEB:\n                case 0xEC:\n                case 0xEE:\n                case 0xEF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+D000..U+D7FF: bytes ED 80..9F 80..BF\n                case 0xED:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n                case 0xF0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n                case 0xF1:\n                case 0xF2:\n                case 0xF3:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n                case 0xF4:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // remaining bytes (80..C1 and F5..FF) are ill-formed\n                default:\n                {\n                    error_message = \"invalid string: ill-formed UTF-8 byte\";\n                    return token_type::parse_error;\n                }\n            }\n        }\n    }\n\n    /*!\n     * @brief scan a comment\n     * @return whether comment could be scanned successfully\n     */\n    bool scan_comment()\n    {\n        switch (get())\n        {\n            // single-line comments skip input until a newline or EOF is read\n            case '/':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case '\\n':\n                        case '\\r':\n                        case std::char_traits<char_type>::eof():\n                        case '\\0':\n                            return true;\n\n                        default:\n                            break;\n                    }\n                }\n            }\n\n            // multi-line comments skip input until */ is read\n            case '*':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case std::char_traits<char_type>::eof():\n                        case '\\0':\n                        {\n                            error_message = \"invalid comment; missing closing '*/'\";\n                            return false;\n                        }\n\n                        case '*':\n                        {\n                            switch (get())\n                            {\n                                case '/':\n                                    return true;\n\n                                default:\n                                {\n                                    unget();\n                                    continue;\n                                }\n                            }\n                        }\n\n                        default:\n                            continue;\n                    }\n                }\n            }\n\n            // unexpected character after reading '/'\n            default:\n            {\n                error_message = \"invalid comment; expecting '/' or '*' after '/'\";\n                return false;\n            }\n        }\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(float& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtof(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtod(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(long double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtold(str, endptr);\n    }\n\n    /*!\n    @brief scan a number literal\n\n    This function scans a string according to Sect. 6 of RFC 7159.\n\n    The function is realized with a deterministic finite state machine derived\n    from the grammar described in RFC 7159. Starting in state \"init\", the\n    input is read and used to determined the next state. Only state \"done\"\n    accepts the number. State \"error\" is a trap state to model errors. In the\n    table below, \"anything\" means any character but the ones listed before.\n\n    state    | 0        | 1-9      | e E      | +       | -       | .        | anything\n    ---------|----------|----------|----------|---------|---------|----------|-----------\n    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n    zero     | done     | done     | exponent | done    | done    | decimal1 | done\n    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n    decimal1 | decimal2 | decimal2 | [error]  | [error] | [error] | [error]  | [error]\n    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n    any2     | any2     | any2     | done     | done    | done    | done     | done\n\n    The state machine is realized with one label per state (prefixed with\n    \"scan_number_\") and `goto` statements between them. The state machine\n    contains cycles, but any cycle can be left when EOF is read. Therefore,\n    the function is guaranteed to terminate.\n\n    During scanning, the read bytes are stored in token_buffer. This string is\n    then converted to a signed integer, an unsigned integer, or a\n    floating-point number.\n\n    @return token_type::value_unsigned, token_type::value_integer, or\n            token_type::value_float if number could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note The scanner is independent of the current locale. Internally, the\n          locale's decimal point is used instead of `.` to work with the\n          locale-dependent converters.\n    */\n    token_type scan_number()  // lgtm [cpp/use-of-goto]\n    {\n        // reset token_buffer to store the number's bytes\n        reset();\n\n        // the type of the parsed number; initially set to unsigned; will be\n        // changed if minus sign, decimal point or exponent is read\n        token_type number_type = token_type::value_unsigned;\n\n        // state (init): we just found out we need to scan a number\n        switch (current)\n        {\n            case '-':\n            {\n                add(current);\n                goto scan_number_minus;\n            }\n\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            // all other characters are rejected outside scan_number()\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n\nscan_number_minus:\n        // state: we just parsed a leading minus sign\n        number_type = token_type::value_integer;\n        switch (get())\n        {\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '-'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_zero:\n        // state: we just parse a zero (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_any1:\n        // state: we just parsed a number 0-9 (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_decimal1:\n        // state: we just parsed a decimal point\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '.'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_decimal2:\n        // we just parsed at least one number after a decimal point\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_exponent:\n        // we just parsed an exponent\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '+':\n            case '-':\n            {\n                add(current);\n                goto scan_number_sign;\n            }\n\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message =\n                    \"invalid number; expected '+', '-', or digit after exponent\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_sign:\n        // we just parsed an exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after exponent sign\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_any2:\n        // we just parsed a number after the exponent or exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_done:\n        // unget the character after the number (we only read it to know that\n        // we are done scanning a number)\n        unget();\n\n        char* endptr = nullptr;\n        errno = 0;\n\n        // try to parse integers first and fall back to floats\n        if (number_type == token_type::value_unsigned)\n        {\n            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_unsigned = static_cast<number_unsigned_t>(x);\n                if (value_unsigned == x)\n                {\n                    return token_type::value_unsigned;\n                }\n            }\n        }\n        else if (number_type == token_type::value_integer)\n        {\n            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_integer = static_cast<number_integer_t>(x);\n                if (value_integer == x)\n                {\n                    return token_type::value_integer;\n                }\n            }\n        }\n\n        // this code is reached if we parse a floating-point number or if an\n        // integer conversion above failed\n        strtof(value_float, token_buffer.data(), &endptr);\n\n        // we checked the number format before\n        JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n        return token_type::value_float;\n    }\n\n    /*!\n    @param[in] literal_text  the literal text to expect\n    @param[in] length        the length of the passed literal text\n    @param[in] return_type   the token type to return on success\n    */\n    JSON_HEDLEY_NON_NULL(2)\n    token_type scan_literal(const char_type* literal_text, const std::size_t length,\n                            token_type return_type)\n    {\n        JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);\n        for (std::size_t i = 1; i < length; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))\n            {\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n            }\n        }\n        return return_type;\n    }\n\n    /////////////////////\n    // input management\n    /////////////////////\n\n    /// reset token_buffer; current character is beginning of token\n    void reset() noexcept\n    {\n        token_buffer.clear();\n        token_string.clear();\n        token_string.push_back(std::char_traits<char_type>::to_char_type(current));\n    }\n\n    /*\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a\n    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters\n    for use in error messages.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++position.chars_read_total;\n        ++position.chars_read_current_line;\n\n        if (next_unget)\n        {\n            // just reset the next_unget variable and work with current\n            next_unget = false;\n        }\n        else\n        {\n            current = ia.get_character();\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))\n        {\n            token_string.push_back(std::char_traits<char_type>::to_char_type(current));\n        }\n\n        if (current == '\\n')\n        {\n            ++position.lines_read;\n            position.chars_read_current_line = 0;\n        }\n\n        return current;\n    }\n\n    /*!\n    @brief unget current character (read it again on next get)\n\n    We implement unget by setting variable next_unget to true. The input is not\n    changed - we just simulate ungetting by modifying chars_read_total,\n    chars_read_current_line, and token_string. The next call to get() will\n    behave as if the unget character is read again.\n    */\n    void unget()\n    {\n        next_unget = true;\n\n        --position.chars_read_total;\n\n        // in case we \"unget\" a newline, we have to also decrement the lines_read\n        if (position.chars_read_current_line == 0)\n        {\n            if (position.lines_read > 0)\n            {\n                --position.lines_read;\n            }\n        }\n        else\n        {\n            --position.chars_read_current_line;\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))\n        {\n            JSON_ASSERT(!token_string.empty());\n            token_string.pop_back();\n        }\n    }\n\n    /// add a character to token_buffer\n    void add(char_int_type c)\n    {\n        token_buffer.push_back(static_cast<typename string_t::value_type>(c));\n    }\n\n  public:\n    /////////////////////\n    // value getters\n    /////////////////////\n\n    /// return integer value\n    constexpr number_integer_t get_number_integer() const noexcept\n    {\n        return value_integer;\n    }\n\n    /// return unsigned integer value\n    constexpr number_unsigned_t get_number_unsigned() const noexcept\n    {\n        return value_unsigned;\n    }\n\n    /// return floating-point value\n    constexpr number_float_t get_number_float() const noexcept\n    {\n        return value_float;\n    }\n\n    /// return current string value (implicitly resets the token; useful only once)\n    string_t& get_string()\n    {\n        return token_buffer;\n    }\n\n    /////////////////////\n    // diagnostics\n    /////////////////////\n\n    /// return position of last read token\n    constexpr position_t get_position() const noexcept\n    {\n        return position;\n    }\n\n    /// return the last read token (for errors only).  Will never contain EOF\n    /// (an arbitrary value that is not a valid char value, often -1), because\n    /// 255 may legitimately occur.  May contain NUL, which should be escaped.\n    std::string get_token_string() const\n    {\n        // escape control characters\n        std::string result;\n        for (const auto c : token_string)\n        {\n            if (static_cast<unsigned char>(c) <= '\\x1F')\n            {\n                // escape control characters\n                std::array<char, 9> cs{{}};\n                (std::snprintf)(cs.data(), cs.size(), \"<U+%.4X>\", static_cast<unsigned char>(c));\n                result += cs.data();\n            }\n            else\n            {\n                // add character as is\n                result.push_back(static_cast<std::string::value_type>(c));\n            }\n        }\n\n        return result;\n    }\n\n    /// return syntax error message\n    JSON_HEDLEY_RETURNS_NON_NULL\n    constexpr const char* get_error_message() const noexcept\n    {\n        return error_message;\n    }\n\n    /////////////////////\n    // actual scanner\n    /////////////////////\n\n    /*!\n    @brief skip the UTF-8 byte order mark\n    @return true iff there is no BOM or the correct BOM has been skipped\n    */\n    bool skip_bom()\n    {\n        if (get() == 0xEF)\n        {\n            // check if we completely parse the BOM\n            return get() == 0xBB && get() == 0xBF;\n        }\n\n        // the first character is not the beginning of the BOM; unget it to\n        // process is later\n        unget();\n        return true;\n    }\n\n    void skip_whitespace()\n    {\n        do\n        {\n            get();\n        }\n        while (current == ' ' || current == '\\t' || current == '\\n' || current == '\\r');\n    }\n\n    token_type scan()\n    {\n        // initially, skip the BOM\n        if (position.chars_read_total == 0 && !skip_bom())\n        {\n            error_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n            return token_type::parse_error;\n        }\n\n        // read next character and ignore whitespace\n        skip_whitespace();\n\n        // ignore comments\n        while (ignore_comments && current == '/')\n        {\n            if (!scan_comment())\n            {\n                return token_type::parse_error;\n            }\n\n            // skip following whitespace\n            skip_whitespace();\n        }\n\n        switch (current)\n        {\n            // structural characters\n            case '[':\n                return token_type::begin_array;\n            case ']':\n                return token_type::end_array;\n            case '{':\n                return token_type::begin_object;\n            case '}':\n                return token_type::end_object;\n            case ':':\n                return token_type::name_separator;\n            case ',':\n                return token_type::value_separator;\n\n            // literals\n            case 't':\n            {\n                std::array<char_type, 4> true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}};\n                return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);\n            }\n            case 'f':\n            {\n                std::array<char_type, 5> false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}};\n                return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);\n            }\n            case 'n':\n            {\n                std::array<char_type, 4> null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}};\n                return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);\n            }\n\n            // string\n            case '\\\"':\n                return scan_string();\n\n            // number\n            case '-':\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                return scan_number();\n\n            // end of input (the null byte is needed when parsing from\n            // string literals)\n            case '\\0':\n            case std::char_traits<char_type>::eof():\n                return token_type::end_of_input;\n\n            // error\n            default:\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n        }\n    }\n\n  private:\n    /// input adapter\n    InputAdapterType ia;\n\n    /// whether comments should be ignored (true) or signaled as errors (false)\n    const bool ignore_comments = false;\n\n    /// the current character\n    char_int_type current = std::char_traits<char_type>::eof();\n\n    /// whether the next get() call should just return current\n    bool next_unget = false;\n\n    /// the start position of the current token\n    position_t position {};\n\n    /// raw input token string (for error messages)\n    std::vector<char_type> token_string {};\n\n    /// buffer for variable-length tokens (numbers, strings)\n    string_t token_buffer {};\n\n    /// a description of occurred lexer errors\n    const char* error_message = \"\";\n\n    // number values\n    number_integer_t value_integer = 0;\n    number_unsigned_t value_unsigned = 0;\n    number_float_t value_float = 0;\n\n    /// the decimal point\n    const char_int_type decimal_point_char = '.';\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n\n#include <cstdint> // size_t\n#include <utility> // declval\n#include <string> // string\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename T>\nusing null_function_t = decltype(std::declval<T&>().null());\n\ntemplate<typename T>\nusing boolean_function_t =\n    decltype(std::declval<T&>().boolean(std::declval<bool>()));\n\ntemplate<typename T, typename Integer>\nusing number_integer_function_t =\n    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\ntemplate<typename T, typename Unsigned>\nusing number_unsigned_function_t =\n    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));\n\ntemplate<typename T, typename Float, typename String>\nusing number_float_function_t = decltype(std::declval<T&>().number_float(\n                                    std::declval<Float>(), std::declval<const String&>()));\n\ntemplate<typename T, typename String>\nusing string_function_t =\n    decltype(std::declval<T&>().string(std::declval<String&>()));\n\ntemplate<typename T, typename Binary>\nusing binary_function_t =\n    decltype(std::declval<T&>().binary(std::declval<Binary&>()));\n\ntemplate<typename T>\nusing start_object_function_t =\n    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));\n\ntemplate<typename T, typename String>\nusing key_function_t =\n    decltype(std::declval<T&>().key(std::declval<String&>()));\n\ntemplate<typename T>\nusing end_object_function_t = decltype(std::declval<T&>().end_object());\n\ntemplate<typename T>\nusing start_array_function_t =\n    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));\n\ntemplate<typename T>\nusing end_array_function_t = decltype(std::declval<T&>().end_array());\n\ntemplate<typename T, typename Exception>\nusing parse_error_function_t = decltype(std::declval<T&>().parse_error(\n        std::declval<std::size_t>(), std::declval<const std::string&>(),\n        std::declval<const Exception&>()));\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static constexpr bool value =\n        is_detected_exact<bool, null_function_t, SAX>::value &&\n        is_detected_exact<bool, boolean_function_t, SAX>::value &&\n        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&\n        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&\n        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&\n        is_detected_exact<bool, start_object_function_t, SAX>::value &&\n        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, end_object_function_t, SAX>::value &&\n        is_detected_exact<bool, start_array_function_t, SAX>::value &&\n        is_detected_exact<bool, end_array_function_t, SAX>::value &&\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n};\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax_static_asserts\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n                  \"Missing/invalid function: bool null()\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(\n        is_detected_exact<bool, number_integer_function_t, SAX,\n        number_integer_t>::value,\n        \"Missing/invalid function: bool number_integer(number_integer_t)\");\n    static_assert(\n        is_detected_exact<bool, number_unsigned_function_t, SAX,\n        number_unsigned_t>::value,\n        \"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n    static_assert(is_detected_exact<bool, number_float_function_t, SAX,\n                  number_float_t, string_t>::value,\n                  \"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n    static_assert(\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value,\n        \"Missing/invalid function: bool string(string_t&)\");\n    static_assert(\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,\n        \"Missing/invalid function: bool binary(binary_t&)\");\n    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_object(std::size_t)\");\n    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n                  \"Missing/invalid function: bool key(string_t&)\");\n    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_object()\");\n    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_array(std::size_t)\");\n    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_array()\");\n    static_assert(\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n        \"Missing/invalid function: bool parse_error(std::size_t, const \"\n        \"std::string&, const exception&)\");\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/// how to treat CBOR tags\nenum class cbor_tag_handler_t\n{\n    error,  ///< throw a parse_error exception in case of a tag\n    ignore   ///< ignore tags\n};\n\n/*!\n@brief determine system byte order\n\n@return true if and only if system's byte order is little endian\n\n@note from https://stackoverflow.com/a/1001328/266378\n*/\nstatic inline bool little_endianess(int num = 1) noexcept\n{\n    return *reinterpret_cast<char*>(&num) == 1;\n}\n\n\n///////////////////\n// binary reader //\n///////////////////\n\n/*!\n@brief deserialization of CBOR, MessagePack, and UBJSON values\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>\nclass binary_reader\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using json_sax_t = SAX;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename std::char_traits<char_type>::int_type;\n\n  public:\n    /*!\n    @brief create a binary reader\n\n    @param[in] adapter  input adapter to read from\n    */\n    explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter))\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n    }\n\n    // make class move-only\n    binary_reader(const binary_reader&) = delete;\n    binary_reader(binary_reader&&) = default;\n    binary_reader& operator=(const binary_reader&) = delete;\n    binary_reader& operator=(binary_reader&&) = default;\n    ~binary_reader() = default;\n\n    /*!\n    @param[in] format  the binary format to parse\n    @param[in] sax_    a SAX event processor\n    @param[in] strict  whether to expect the input to be consumed completed\n    @param[in] tag_handler  how to treat CBOR tags\n\n    @return\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool sax_parse(const input_format_t format,\n                   json_sax_t* sax_,\n                   const bool strict = true,\n                   const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        sax = sax_;\n        bool result = false;\n\n        switch (format)\n        {\n            case input_format_t::bson:\n                result = parse_bson_internal();\n                break;\n\n            case input_format_t::cbor:\n                result = parse_cbor_internal(true, tag_handler);\n                break;\n\n            case input_format_t::msgpack:\n                result = parse_msgpack_internal();\n                break;\n\n            case input_format_t::ubjson:\n                result = parse_ubjson_internal();\n                break;\n\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n\n        // strict mode: next byte must be EOF\n        if (result && strict)\n        {\n            if (format == input_format_t::ubjson)\n            {\n                get_ignore_noop();\n            }\n            else\n            {\n                get();\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))\n            {\n                return sax->parse_error(chars_read, get_token_string(),\n                                        parse_error::create(110, chars_read, exception_message(format, \"expected end of input; last byte: 0x\" + get_token_string(), \"value\")));\n            }\n        }\n\n        return result;\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @brief Reads in a BSON-object and passes it to the SAX-parser.\n    @return whether a valid BSON-value was passed to the SAX parser\n    */\n    bool parse_bson_internal()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))\n        {\n            return false;\n        }\n\n        return sax->end_object();\n    }\n\n    /*!\n    @brief Parses a C-style string from the BSON input.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @return `true` if the \\x00-byte indicating the end of the string was\n             encountered before the EOF; false` indicates an unexpected EOF.\n    */\n    bool get_bson_cstr(string_t& result)\n    {\n        auto out = std::back_inserter(result);\n        while (true)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"cstring\")))\n            {\n                return false;\n            }\n            if (current == 0x00)\n            {\n                return true;\n            }\n            *out++ = static_cast<typename string_t::value_type>(current);\n        }\n    }\n\n    /*!\n    @brief Parses a zero-terminated string of length @a len from the BSON\n           input.\n    @param[in] len  The length (including the zero-byte at the end) of the\n                    string to be read.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 1\n    @return `true` if the string was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_string(const NumberType len, string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 1))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"string length must be at least 1, is \" + std::to_string(len), \"string\")));\n        }\n\n        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();\n    }\n\n    /*!\n    @brief Parses a byte array input of length @a len from the BSON input.\n    @param[in] len  The length of the byte array to be read.\n    @param[in, out] result  A reference to the binary variable where the read\n                            array is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 0\n    @return `true` if the byte array was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_binary(const NumberType len, binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 0))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"byte array length cannot be negative, is \" + std::to_string(len), \"binary\")));\n        }\n\n        // All BSON binary values have a subtype\n        std::uint8_t subtype{};\n        get_number<std::uint8_t>(input_format_t::bson, subtype);\n        result.set_subtype(subtype);\n\n        return get_binary(input_format_t::bson, len, result);\n    }\n\n    /*!\n    @brief Read a BSON document element of the given @a element_type.\n    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n    @param[in] element_type_parse_position The position in the input stream,\n               where the `element_type` was read.\n    @warning Not all BSON element types are supported yet. An unsupported\n             @a element_type will give rise to a parse_error.114:\n             Unsupported BSON record type 0x...\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_internal(const char_int_type element_type,\n                                     const std::size_t element_type_parse_position)\n    {\n        switch (element_type)\n        {\n            case 0x01: // double\n            {\n                double number{};\n                return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0x02: // string\n            {\n                std::int32_t len{};\n                string_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);\n            }\n\n            case 0x03: // object\n            {\n                return parse_bson_internal();\n            }\n\n            case 0x04: // array\n            {\n                return parse_bson_array();\n            }\n\n            case 0x05: // binary\n            {\n                std::int32_t len{};\n                binary_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);\n            }\n\n            case 0x08: // boolean\n            {\n                return sax->boolean(get() != 0);\n            }\n\n            case 0x0A: // null\n            {\n                return sax->null();\n            }\n\n            case 0x10: // int32\n            {\n                std::int32_t value{};\n                return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            case 0x12: // int64\n            {\n                std::int64_t value{};\n                return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            default: // anything else not supported (yet)\n            {\n                std::array<char, 3> cr{{}};\n                (std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(element_type));\n                return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, \"Unsupported BSON record type 0x\" + std::string(cr.data())));\n            }\n        }\n    }\n\n    /*!\n    @brief Read a BSON element list (as specified in the BSON-spec)\n\n    The same binary layout is used for objects and arrays, hence it must be\n    indicated with the argument @a is_array which one is expected\n    (true --> array, false --> object).\n\n    @param[in] is_array Determines if the element list being read is to be\n                        treated as an object (@a is_array == false), or as an\n                        array (@a is_array == true).\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_list(const bool is_array)\n    {\n        string_t key;\n\n        while (auto element_type = get())\n        {\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"element list\")))\n            {\n                return false;\n            }\n\n            const std::size_t element_type_parse_position = chars_read;\n            if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))\n            {\n                return false;\n            }\n\n            if (!is_array && !sax->key(key))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))\n            {\n                return false;\n            }\n\n            // get_bson_cstr only appends\n            key.clear();\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Reads an array from the BSON input and passes it to the SAX-parser.\n    @return whether a valid BSON-array was passed to the SAX parser\n    */\n    bool parse_bson_array()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))\n        {\n            return false;\n        }\n\n        return sax->end_array();\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true) or whether the last read character should\n                         be considered instead (false)\n    @param[in] tag_handler how CBOR tags should be treated\n\n    @return whether a valid CBOR value was passed to the SAX parser\n    */\n    bool parse_cbor_internal(const bool get_char,\n                             const cbor_tag_handler_t tag_handler)\n    {\n        switch (get_char ? get() : current)\n        {\n            // EOF\n            case std::char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::cbor, \"value\");\n\n            // Integer 0x00..0x17 (0..23)\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            case 0x18: // Unsigned integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x19: // Unsigned integer (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1A: // Unsigned integer (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            // Negative integer -1-0x00..-1-0x17 (-1..-24)\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n                return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));\n\n            case 0x38: // Negative integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)\n                        - static_cast<number_integer_t>(number));\n            }\n\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            case 0x5F: // Binary data (indefinite length)\n            {\n                binary_t b;\n                return get_cbor_binary(b) && sax->binary(b);\n            }\n\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                string_t s;\n                return get_cbor_string(s) && sax->string(s);\n            }\n\n            // array (0x00..0x17 data items follow)\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n                return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0x98: // array (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x99: // array (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9A: // array (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9B: // array (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9F: // array (indefinite length)\n                return get_cbor_array(std::size_t(-1), tag_handler);\n\n            // map (0x00..0x17 pairs of data items follow)\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n                return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0xB8: // map (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xB9: // map (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBA: // map (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBB: // map (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBF: // map (indefinite length)\n                return get_cbor_object(std::size_t(-1), tag_handler);\n\n            case 0xC6: // tagged item\n            case 0xC7:\n            case 0xC8:\n            case 0xC9:\n            case 0xCA:\n            case 0xCB:\n            case 0xCC:\n            case 0xCD:\n            case 0xCE:\n            case 0xCF:\n            case 0xD0:\n            case 0xD1:\n            case 0xD2:\n            case 0xD3:\n            case 0xD4:\n            case 0xD8: // tagged item (1 bytes follow)\n            case 0xD9: // tagged item (2 bytes follow)\n            case 0xDA: // tagged item (4 bytes follow)\n            case 0xDB: // tagged item (8 bytes follow)\n            {\n                switch (tag_handler)\n                {\n                    case cbor_tag_handler_t::error:\n                    {\n                        auto last_token = get_token_string();\n                        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\")));\n                    }\n\n                    case cbor_tag_handler_t::ignore:\n                    {\n                        switch (current)\n                        {\n                            case 0xD8:\n                            {\n                                std::uint8_t len{};\n                                get_number(input_format_t::cbor, len);\n                                break;\n                            }\n                            case 0xD9:\n                            {\n                                std::uint16_t len{};\n                                get_number(input_format_t::cbor, len);\n                                break;\n                            }\n                            case 0xDA:\n                            {\n                                std::uint32_t len{};\n                                get_number(input_format_t::cbor, len);\n                                break;\n                            }\n                            case 0xDB:\n                            {\n                                std::uint64_t len{};\n                                get_number(input_format_t::cbor, len);\n                                break;\n                            }\n                            default:\n                                break;\n                        }\n                        return parse_cbor_internal(true, tag_handler);\n                    }\n\n                    default:                 // LCOV_EXCL_LINE\n                        JSON_ASSERT(false);  // LCOV_EXCL_LINE\n                        return false;        // LCOV_EXCL_LINE\n                }\n            }\n\n            case 0xF4: // false\n                return sax->boolean(false);\n\n            case 0xF5: // true\n                return sax->boolean(true);\n\n            case 0xF6: // null\n                return sax->null();\n\n            case 0xF9: // Half-Precision Float (two-byte IEEE 754)\n            {\n                const auto byte1_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n                const auto byte2_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10u) & 0x1Fu;\n                    const unsigned int mant = half & 0x3FFu;\n                    JSON_ASSERT(0 <= exp&& exp <= 32);\n                    JSON_ASSERT(mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000u) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 0xFA: // Single-Precision Float (four-byte IEEE 754)\n            {\n                float number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n            {\n                double number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            default: // anything else (0xFF is handled inside the other types)\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n    Additionally, CBOR's strings with indefinite lengths are supported.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_cbor_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            {\n                return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    string_t chunk;\n                    if (!get_cbor_string(chunk))\n                    {\n                        return false;\n                    }\n                    result.append(chunk);\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into the byte array.\n    Additionally, CBOR's byte arrays with indefinite lengths are supported.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_cbor_binary(binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"binary\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            {\n                return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5F: // Binary data (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    binary_t chunk;\n                    if (!get_cbor_binary(chunk))\n                    {\n                        return false;\n                    }\n                    result.insert(result.end(), chunk.begin(), chunk.end());\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x\" + last_token, \"binary\")));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array or std::size_t(-1) for an\n                    array of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether array creation completed\n    */\n    bool get_cbor_array(const std::size_t len,\n                        const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object or std::size_t(-1) for an\n                    object of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether object creation completed\n    */\n    bool get_cbor_object(const std::size_t len,\n                         const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                get();\n                if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    /*!\n    @return whether a valid MessagePack value was passed to the SAX parser\n    */\n    bool parse_msgpack_internal()\n    {\n        switch (get())\n        {\n            // EOF\n            case std::char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::msgpack, \"value\");\n\n            // positive fixint\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n            case 0x18:\n            case 0x19:\n            case 0x1A:\n            case 0x1B:\n            case 0x1C:\n            case 0x1D:\n            case 0x1E:\n            case 0x1F:\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n            case 0x38:\n            case 0x39:\n            case 0x3A:\n            case 0x3B:\n            case 0x3C:\n            case 0x3D:\n            case 0x3E:\n            case 0x3F:\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58:\n            case 0x59:\n            case 0x5A:\n            case 0x5B:\n            case 0x5C:\n            case 0x5D:\n            case 0x5E:\n            case 0x5F:\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78:\n            case 0x79:\n            case 0x7A:\n            case 0x7B:\n            case 0x7C:\n            case 0x7D:\n            case 0x7E:\n            case 0x7F:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            // fixmap\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n                return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixarray\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n            case 0x98:\n            case 0x99:\n            case 0x9A:\n            case 0x9B:\n            case 0x9C:\n            case 0x9D:\n            case 0x9E:\n            case 0x9F:\n                return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            case 0xD9: // str 8\n            case 0xDA: // str 16\n            case 0xDB: // str 32\n            {\n                string_t s;\n                return get_msgpack_string(s) && sax->string(s);\n            }\n\n            case 0xC0: // nil\n                return sax->null();\n\n            case 0xC2: // false\n                return sax->boolean(false);\n\n            case 0xC3: // true\n                return sax->boolean(true);\n\n            case 0xC4: // bin 8\n            case 0xC5: // bin 16\n            case 0xC6: // bin 32\n            case 0xC7: // ext 8\n            case 0xC8: // ext 16\n            case 0xC9: // ext 32\n            case 0xD4: // fixext 1\n            case 0xD5: // fixext 2\n            case 0xD6: // fixext 4\n            case 0xD7: // fixext 8\n            case 0xD8: // fixext 16\n            {\n                binary_t b;\n                return get_msgpack_binary(b) && sax->binary(b);\n            }\n\n            case 0xCA: // float 32\n            {\n                float number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCB: // float 64\n            {\n                double number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCC: // uint 8\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCD: // uint 16\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCE: // uint 32\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCF: // uint 64\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xD0: // int 8\n            {\n                std::int8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD1: // int 16\n            {\n                std::int16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD2: // int 32\n            {\n                std::int32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD3: // int 64\n            {\n                std::int64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xDC: // array 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDD: // array 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDE: // map 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xDF: // map 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            // negative fixint\n            case 0xE0:\n            case 0xE1:\n            case 0xE2:\n            case 0xE3:\n            case 0xE4:\n            case 0xE5:\n            case 0xE6:\n            case 0xE7:\n            case 0xE8:\n            case 0xE9:\n            case 0xEA:\n            case 0xEB:\n            case 0xEC:\n            case 0xED:\n            case 0xEE:\n            case 0xEF:\n            case 0xF0:\n            case 0xF1:\n            case 0xF2:\n            case 0xF3:\n            case 0xF4:\n            case 0xF5:\n            case 0xF6:\n            case 0xF7:\n            case 0xF8:\n            case 0xF9:\n            case 0xFA:\n            case 0xFB:\n            case 0xFC:\n            case 0xFD:\n            case 0xFE:\n            case 0xFF:\n                return sax->number_integer(static_cast<std::int8_t>(current));\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_msgpack_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0xD9: // str 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDA: // str 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDB: // str 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, \"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into a byte array.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_msgpack_binary(binary_t& result)\n    {\n        // helper function to set the subtype\n        auto assign_and_return_true = [&result](std::int8_t subtype)\n        {\n            result.set_subtype(static_cast<std::uint8_t>(subtype));\n            return true;\n        };\n\n        switch (current)\n        {\n            case 0xC4: // bin 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC5: // bin 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC6: // bin 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC7: // ext 8\n            {\n                std::uint8_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC8: // ext 16\n            {\n                std::uint16_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC9: // ext 32\n            {\n                std::uint32_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD4: // fixext 1\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 1, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD5: // fixext 2\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 2, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD6: // fixext 4\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 4, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD7: // fixext 8\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 8, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD8: // fixext 16\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 16, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            default:           // LCOV_EXCL_LINE\n                return false;  // LCOV_EXCL_LINE\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array\n    @return whether array creation completed\n    */\n    bool get_msgpack_array(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object\n    @return whether object creation completed\n    */\n    bool get_msgpack_object(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n            key.clear();\n        }\n\n        return sax->end_object();\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid UBJSON value was passed to the SAX parser\n    */\n    bool parse_ubjson_internal(const bool get_char = true)\n    {\n        return get_ubjson_value(get_char ? get_ignore_noop() : current);\n    }\n\n    /*!\n    @brief reads a UBJSON string\n\n    This function is either called after reading the 'S' byte explicitly\n    indicating a string, or in case of an object key where the 'S' byte can be\n    left out.\n\n    @param[out] result   created string\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether string creation completed\n    */\n    bool get_ubjson_string(string_t& result, const bool get_char = true)\n    {\n        if (get_char)\n        {\n            get();  // TODO(niels): may we ignore N here?\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"value\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            case 'U':\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'i':\n            {\n                std::int8_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'I':\n            {\n                std::int16_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'l':\n            {\n                std::int32_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'L':\n            {\n                std::int64_t len{};\n                return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result);\n            }\n\n            default:\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token, \"string\")));\n        }\n    }\n\n    /*!\n    @param[out] result  determined size\n    @return whether size determination completed\n    */\n    bool get_ubjson_size_value(std::size_t& result)\n    {\n        switch (get_ignore_noop())\n        {\n            case 'U':\n            {\n                std::uint8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token, \"size\")));\n            }\n        }\n    }\n\n    /*!\n    @brief determine the type and size for a container\n\n    In the optimized UBJSON format, a type and a size can be provided to allow\n    for a more compact representation.\n\n    @param[out] result  pair of the size and the type\n\n    @return whether pair creation completed\n    */\n    bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result)\n    {\n        result.first = string_t::npos; // size\n        result.second = 0; // type\n\n        get_ignore_noop();\n\n        if (current == '$')\n        {\n            result.second = get();  // must not ignore 'N', because 'N' maybe the type\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"type\")))\n            {\n                return false;\n            }\n\n            get_ignore_noop();\n            if (JSON_HEDLEY_UNLIKELY(current != '#'))\n            {\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"value\")))\n                {\n                    return false;\n                }\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"expected '#' after type information; last byte: 0x\" + last_token, \"size\")));\n            }\n\n            return get_ubjson_size_value(result.first);\n        }\n\n        if (current == '#')\n        {\n            return get_ubjson_size_value(result.first);\n        }\n\n        return true;\n    }\n\n    /*!\n    @param prefix  the previously read or set type prefix\n    @return whether value creation completed\n    */\n    bool get_ubjson_value(const char_int_type prefix)\n    {\n        switch (prefix)\n        {\n            case std::char_traits<char_type>::eof():  // EOF\n                return unexpect_eof(input_format_t::ubjson, \"value\");\n\n            case 'T':  // true\n                return sax->boolean(true);\n            case 'F':  // false\n                return sax->boolean(false);\n\n            case 'Z':  // null\n                return sax->null();\n\n            case 'U':\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number);\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_integer(number);\n            }\n\n            case 'd':\n            {\n                float number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'D':\n            {\n                double number{};\n                return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'H':\n            {\n                return get_ubjson_high_precision_number();\n            }\n\n            case 'C':  // char\n            {\n                get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"char\")))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(current > 127))\n                {\n                    auto last_token = get_token_string();\n                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\" + last_token, \"char\")));\n                }\n                string_t s(1, static_cast<typename string_t::value_type>(current));\n                return sax->string(s);\n            }\n\n            case 'S':  // string\n            {\n                string_t s;\n                return get_ubjson_string(s) && sax->string(s);\n            }\n\n            case '[':  // array\n                return get_ubjson_array();\n\n            case '{':  // object\n                return get_ubjson_object();\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @return whether array creation completed\n    */\n    bool get_ubjson_array()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                        {\n                            return false;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != ']')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @return whether object creation completed\n    */\n    bool get_ubjson_object()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != '}')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    // Note, no reader for UBJSON binary types is implemented because they do\n    // not exist\n\n    bool get_ubjson_high_precision_number()\n    {\n        // get size of following number string\n        std::size_t size{};\n        auto res = get_ubjson_size_value(size);\n        if (JSON_HEDLEY_UNLIKELY(!res))\n        {\n            return res;\n        }\n\n        // get number string\n        std::vector<char> number_vector;\n        for (std::size_t i = 0; i < size; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, \"number\")))\n            {\n                return false;\n            }\n            number_vector.push_back(static_cast<char>(current));\n        }\n\n        // parse number string\n        auto number_ia = detail::input_adapter(std::forward<decltype(number_vector)>(number_vector));\n        auto number_lexer = detail::lexer<BasicJsonType, decltype(number_ia)>(std::move(number_ia), false);\n        const auto result_number = number_lexer.scan();\n        const auto number_string = number_lexer.get_token_string();\n        const auto result_remainder = number_lexer.scan();\n\n        using token_type = typename detail::lexer_base<BasicJsonType>::token_type;\n\n        if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))\n        {\n            return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, \"invalid number text: \" + number_lexer.get_token_string(), \"high-precision number\")));\n        }\n\n        switch (result_number)\n        {\n            case token_type::value_integer:\n                return sax->number_integer(number_lexer.get_number_integer());\n            case token_type::value_unsigned:\n                return sax->number_unsigned(number_lexer.get_number_unsigned());\n            case token_type::value_float:\n                return sax->number_float(number_lexer.get_number_float(), std::move(number_string));\n            default:\n                return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, \"invalid number text: \" + number_lexer.get_token_string(), \"high-precision number\")));\n        }\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*!\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a -'ve valued\n    `std::char_traits<char_type>::eof()` in that case.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++chars_read;\n        return current = ia.get_character();\n    }\n\n    /*!\n    @return character read from the input after ignoring all 'N' entries\n    */\n    char_int_type get_ignore_noop()\n    {\n        do\n        {\n            get();\n        }\n        while (current == 'N');\n\n        return current;\n    }\n\n    /*\n    @brief read a number from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format   the current format (for diagnostics)\n    @param[out] result  number of type @a NumberType\n\n    @return whether conversion completed\n\n    @note This function needs to respect the system's endianess, because\n          bytes in CBOR, MessagePack, and UBJSON are stored in network order\n          (big endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool InputIsLittleEndian = false>\n    bool get_number(const input_format_t format, NumberType& result)\n    {\n        // step 1: read input into array with system's byte order\n        std::array<std::uint8_t, sizeof(NumberType)> vec;\n        for (std::size_t i = 0; i < sizeof(NumberType); ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"number\")))\n            {\n                return false;\n            }\n\n            // reverse byte order prior to conversion if necessary\n            if (is_little_endian != InputIsLittleEndian)\n            {\n                vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);\n            }\n            else\n            {\n                vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE\n            }\n        }\n\n        // step 2: convert array into number of type T and return\n        std::memcpy(&result, vec.data(), sizeof(NumberType));\n        return true;\n    }\n\n    /*!\n    @brief create a string by reading characters from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of characters to read\n    @param[out] result string created by reading @a len bytes\n\n    @return whether string creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of string memory.\n    */\n    template<typename NumberType>\n    bool get_string(const input_format_t format,\n                    const NumberType len,\n                    string_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"string\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<typename string_t::value_type>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @brief create a byte array by reading bytes from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of bytes to read\n    @param[out] result byte array created by reading @a len bytes\n\n    @return whether byte array creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of memory.\n    */\n    template<typename NumberType>\n    bool get_binary(const input_format_t format,\n                    const NumberType len,\n                    binary_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"binary\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<std::uint8_t>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @param[in] format   the current format (for diagnostics)\n    @param[in] context  further context information (for diagnostics)\n    @return whether the last read character is not EOF\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool unexpect_eof(const input_format_t format, const char* context) const\n    {\n        if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))\n        {\n            return sax->parse_error(chars_read, \"<end of file>\",\n                                    parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context)));\n        }\n        return true;\n    }\n\n    /*!\n    @return a string representation of the last read byte\n    */\n    std::string get_token_string() const\n    {\n        std::array<char, 3> cr{{}};\n        (std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(current));\n        return std::string{cr.data()};\n    }\n\n    /*!\n    @param[in] format   the current format\n    @param[in] detail   a detailed error message\n    @param[in] context  further context information\n    @return a message string to use in the parse_error exceptions\n    */\n    std::string exception_message(const input_format_t format,\n                                  const std::string& detail,\n                                  const std::string& context) const\n    {\n        std::string error_msg = \"syntax error while parsing \";\n\n        switch (format)\n        {\n            case input_format_t::cbor:\n                error_msg += \"CBOR\";\n                break;\n\n            case input_format_t::msgpack:\n                error_msg += \"MessagePack\";\n                break;\n\n            case input_format_t::ubjson:\n                error_msg += \"UBJSON\";\n                break;\n\n            case input_format_t::bson:\n                error_msg += \"BSON\";\n                break;\n\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n\n        return error_msg + \" \" + context + \": \" + detail;\n    }\n\n  private:\n    /// input adapter\n    InputAdapterType ia;\n\n    /// the current character\n    char_int_type current = std::char_traits<char_type>::eof();\n\n    /// the number of characters read\n    std::size_t chars_read = 0;\n\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the SAX parser\n    json_sax_t* sax = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/input/parser.hpp>\n\n\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////\n// parser //\n////////////\n\nenum class parse_event_t : uint8_t\n{\n    /// the parser read `{` and started to process a JSON object\n    object_start,\n    /// the parser read `}` and finished processing a JSON object\n    object_end,\n    /// the parser read `[` and started to process a JSON array\n    array_start,\n    /// the parser read `]` and finished processing a JSON array\n    array_end,\n    /// the parser read a key of a value in an object\n    key,\n    /// the parser finished reading a JSON value\n    value\n};\n\ntemplate<typename BasicJsonType>\nusing parser_callback_t =\n    std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;\n\n/*!\n@brief syntax analysis\n\nThis class implements a recursive descent parser.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass parser\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using lexer_t = lexer<BasicJsonType, InputAdapterType>;\n    using token_type = typename lexer_t::token_type;\n\n  public:\n    /// a parser reading from an input adapter\n    explicit parser(InputAdapterType&& adapter,\n                    const parser_callback_t<BasicJsonType> cb = nullptr,\n                    const bool allow_exceptions_ = true,\n                    const bool skip_comments = false)\n        : callback(cb)\n        , m_lexer(std::move(adapter), skip_comments)\n        , allow_exceptions(allow_exceptions_)\n    {\n        // read first token\n        get_token();\n    }\n\n    /*!\n    @brief public parser interface\n\n    @param[in] strict      whether to expect the last token to be EOF\n    @param[in,out] result  parsed JSON value\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    void parse(const bool strict, BasicJsonType& result)\n    {\n        if (callback)\n        {\n            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n\n            // set top-level value to null if it was discarded by the callback\n            // function\n            if (result.is_discarded())\n            {\n                result = nullptr;\n            }\n        }\n        else\n        {\n            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n        }\n    }\n\n    /*!\n    @brief public accept interface\n\n    @param[in] strict  whether to expect the last token to be EOF\n    @return whether the input is a proper JSON text\n    */\n    bool accept(const bool strict = true)\n    {\n        json_sax_acceptor<BasicJsonType> sax_acceptor;\n        return sax_parse(&sax_acceptor, strict);\n    }\n\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse(SAX* sax, const bool strict = true)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        const bool result = sax_parse_internal(sax);\n\n        // strict mode: next byte must be EOF\n        if (result && strict && (get_token() != token_type::end_of_input))\n        {\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(),\n                                            exception_message(token_type::end_of_input, \"value\")));\n        }\n\n        return result;\n    }\n\n  private:\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse_internal(SAX* sax)\n    {\n        // stack to remember the hierarchy of structured values we are parsing\n        // true = array; false = object\n        std::vector<bool> states;\n        // value to avoid a goto (see comment where set to true)\n        bool skip_to_state_evaluation = false;\n\n        while (true)\n        {\n            if (!skip_to_state_evaluation)\n            {\n                // invariant: get_token() was called before each iteration\n                switch (last_token)\n                {\n                    case token_type::begin_object:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing } -> we are done\n                        if (get_token() == token_type::end_object)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // parse key\n                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::value_string, \"object key\")));\n                        }\n                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        // parse separator (:)\n                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::name_separator, \"object separator\")));\n                        }\n\n                        // remember we are now inside an object\n                        states.push_back(false);\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    case token_type::begin_array:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing ] -> we are done\n                        if (get_token() == token_type::end_array)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // remember we are now inside an array\n                        states.push_back(true);\n\n                        // parse values (no need to call get_token)\n                        continue;\n                    }\n\n                    case token_type::value_float:\n                    {\n                        const auto res = m_lexer.get_number_float();\n\n                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    out_of_range::create(406, \"number overflow parsing '\" + m_lexer.get_token_string() + \"'\"));\n                        }\n\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        break;\n                    }\n\n                    case token_type::literal_false:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_null:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_true:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_integer:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_string:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_unsigned:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::parse_error:\n                    {\n                        // using \"uninitialized\" to avoid \"expected\" message\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::uninitialized, \"value\")));\n                    }\n\n                    default: // the last token was unexpected\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::literal_or_value, \"value\")));\n                    }\n                }\n            }\n            else\n            {\n                skip_to_state_evaluation = false;\n            }\n\n            // we reached this line after we successfully parsed a value\n            if (states.empty())\n            {\n                // empty stack: we reached the end of the hierarchy: done\n                return true;\n            }\n\n            if (states.back())  // array\n            {\n                // comma -> next value\n                if (get_token() == token_type::value_separator)\n                {\n                    // parse a new value\n                    get_token();\n                    continue;\n                }\n\n                // closing ]\n                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                    {\n                        return false;\n                    }\n\n                    // We are done with this array. Before we can parse a\n                    // new value, we need to evaluate the new state first.\n                    // By setting skip_to_state_evaluation to false, we\n                    // are effectively jumping to the beginning of this if.\n                    JSON_ASSERT(!states.empty());\n                    states.pop_back();\n                    skip_to_state_evaluation = true;\n                    continue;\n                }\n\n                return sax->parse_error(m_lexer.get_position(),\n                                        m_lexer.get_token_string(),\n                                        parse_error::create(101, m_lexer.get_position(),\n                                                exception_message(token_type::end_array, \"array\")));\n            }\n            else  // object\n            {\n                // comma -> next value\n                if (get_token() == token_type::value_separator)\n                {\n                    // parse key\n                    if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::value_string, \"object key\")));\n                    }\n\n                    if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                    {\n                        return false;\n                    }\n\n                    // parse separator (:)\n                    if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::name_separator, \"object separator\")));\n                    }\n\n                    // parse values\n                    get_token();\n                    continue;\n                }\n\n                // closing }\n                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                    {\n                        return false;\n                    }\n\n                    // We are done with this object. Before we can parse a\n                    // new value, we need to evaluate the new state first.\n                    // By setting skip_to_state_evaluation to false, we\n                    // are effectively jumping to the beginning of this if.\n                    JSON_ASSERT(!states.empty());\n                    states.pop_back();\n                    skip_to_state_evaluation = true;\n                    continue;\n                }\n\n                return sax->parse_error(m_lexer.get_position(),\n                                        m_lexer.get_token_string(),\n                                        parse_error::create(101, m_lexer.get_position(),\n                                                exception_message(token_type::end_object, \"object\")));\n            }\n        }\n    }\n\n    /// get next token from lexer\n    token_type get_token()\n    {\n        return last_token = m_lexer.scan();\n    }\n\n    std::string exception_message(const token_type expected, const std::string& context)\n    {\n        std::string error_msg = \"syntax error \";\n\n        if (!context.empty())\n        {\n            error_msg += \"while parsing \" + context + \" \";\n        }\n\n        error_msg += \"- \";\n\n        if (last_token == token_type::parse_error)\n        {\n            error_msg += std::string(m_lexer.get_error_message()) + \"; last read: '\" +\n                         m_lexer.get_token_string() + \"'\";\n        }\n        else\n        {\n            error_msg += \"unexpected \" + std::string(lexer_t::token_type_name(last_token));\n        }\n\n        if (expected != token_type::uninitialized)\n        {\n            error_msg += \"; expected \" + std::string(lexer_t::token_type_name(expected));\n        }\n\n        return error_msg;\n    }\n\n  private:\n    /// callback function\n    const parser_callback_t<BasicJsonType> callback = nullptr;\n    /// the type of the last read token\n    token_type last_token = token_type::uninitialized;\n    /// the lexer\n    lexer_t m_lexer;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*\n@brief an iterator for primitive JSON types\n\nThis class models an iterator for primitive JSON types (boolean, number,\nstring). It's only purpose is to allow the iterator/const_iterator classes\nto \"iterate\" over primitive values. Internally, the iterator is modeled by\na `difference_type` variable. Value begin_value (`0`) models the begin,\nend_value (`1`) models past the end.\n*/\nclass primitive_iterator_t\n{\n  private:\n    using difference_type = std::ptrdiff_t;\n    static constexpr difference_type begin_value = 0;\n    static constexpr difference_type end_value = begin_value + 1;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// iterator as signed integer type\n    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n  public:\n    constexpr difference_type get_value() const noexcept\n    {\n        return m_it;\n    }\n\n    /// set iterator to a defined beginning\n    void set_begin() noexcept\n    {\n        m_it = begin_value;\n    }\n\n    /// set iterator to a defined past the end\n    void set_end() noexcept\n    {\n        m_it = end_value;\n    }\n\n    /// return whether the iterator can be dereferenced\n    constexpr bool is_begin() const noexcept\n    {\n        return m_it == begin_value;\n    }\n\n    /// return whether the iterator is at end\n    constexpr bool is_end() const noexcept\n    {\n        return m_it == end_value;\n    }\n\n    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it == rhs.m_it;\n    }\n\n    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it < rhs.m_it;\n    }\n\n    primitive_iterator_t operator+(difference_type n) noexcept\n    {\n        auto result = *this;\n        result += n;\n        return result;\n    }\n\n    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it - rhs.m_it;\n    }\n\n    primitive_iterator_t& operator++() noexcept\n    {\n        ++m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator++(int) noexcept\n    {\n        auto result = *this;\n        ++m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator--() noexcept\n    {\n        --m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator--(int) noexcept\n    {\n        auto result = *this;\n        --m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator+=(difference_type n) noexcept\n    {\n        m_it += n;\n        return *this;\n    }\n\n    primitive_iterator_t& operator-=(difference_type n) noexcept\n    {\n        m_it -= n;\n        return *this;\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*!\n@brief an iterator value\n\n@note This structure could easily be a union, but MSVC currently does not allow\nunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n*/\ntemplate<typename BasicJsonType> struct internal_iterator\n{\n    /// iterator for JSON objects\n    typename BasicJsonType::object_t::iterator object_iterator {};\n    /// iterator for JSON arrays\n    typename BasicJsonType::array_t::iterator array_iterator {};\n    /// generic iterator for all other types\n    primitive_iterator_t primitive_iterator {};\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iter_impl.hpp>\n\n\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// forward declare, to be able to friend it later on\ntemplate<typename IteratorType> class iteration_proxy;\ntemplate<typename IteratorType> class iteration_proxy_value;\n\n/*!\n@brief a template for a bidirectional iterator for the @ref basic_json class\nThis class implements a both iterators (iterator and const_iterator) for the\n@ref basic_json class.\n@note An iterator is called *initialized* when a pointer to a JSON value has\n      been set (e.g., by a constructor or a copy assignment). If the iterator is\n      default-constructed, it is *uninitialized* and most methods are undefined.\n      **The library uses assertions to detect calls on uninitialized iterators.**\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n*/\ntemplate<typename BasicJsonType>\nclass iter_impl\n{\n    /// the iterator with BasicJsonType of different const-ness\n    using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n    /// allow basic_json to access private members\n    friend other_iter_impl;\n    friend BasicJsonType;\n    friend iteration_proxy<iter_impl>;\n    friend iteration_proxy_value<iter_impl>;\n\n    using object_t = typename BasicJsonType::object_t;\n    using array_t = typename BasicJsonType::array_t;\n    // make sure BasicJsonType is basic_json or const basic_json\n    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n                  \"iter_impl only accepts (const) basic_json\");\n\n  public:\n\n    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n    /// A user-defined iterator should provide publicly accessible typedefs named\n    /// iterator_category, value_type, difference_type, pointer, and reference.\n    /// Note that value_type is required to be non-const, even for constant iterators.\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    /// the type of the values when the iterator is dereferenced\n    using value_type = typename BasicJsonType::value_type;\n    /// a type to represent differences between iterators\n    using difference_type = typename BasicJsonType::difference_type;\n    /// defines a pointer to the type iterated over (value_type)\n    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n          typename BasicJsonType::const_pointer,\n          typename BasicJsonType::pointer>::type;\n    /// defines a reference to the type iterated over (value_type)\n    using reference =\n        typename std::conditional<std::is_const<BasicJsonType>::value,\n        typename BasicJsonType::const_reference,\n        typename BasicJsonType::reference>::type;\n\n    /// default constructor\n    iter_impl() = default;\n\n    /*!\n    @brief constructor for a given JSON instance\n    @param[in] object  pointer to a JSON object for this iterator\n    @pre object != nullptr\n    @post The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    explicit iter_impl(pointer object) noexcept : m_object(object)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = typename object_t::iterator();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = typename array_t::iterator();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator = primitive_iterator_t();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @note The conventional copy constructor and copy assignment are implicitly\n          defined. Combined with the following converting constructor and\n          assignment, they support: (1) copy from iterator to iterator, (2)\n          copy from const iterator to const iterator, and (3) conversion from\n          iterator to const iterator. However conversion from const iterator\n          to iterator is not defined.\n    */\n\n    /*!\n    @brief const copy constructor\n    @param[in] other const iterator to copy from\n    @note This copy constructor had to be defined explicitly to circumvent a bug\n          occurring on msvc v19.0 compiler (VS 2015) debug build. For more\n          information refer to: https://github.com/nlohmann/json/issues/1608\n    */\n    iter_impl(const iter_impl<const BasicJsonType>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n    /*!\n    @brief converting constructor\n    @param[in] other  non-const iterator to copy from\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other  non-const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief set the iterator to the first value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_begin() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->begin();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->begin();\n                break;\n            }\n\n            case value_t::null:\n            {\n                // set to end so begin()==end() is true: null is empty\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_begin();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @brief set the iterator past the last value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_end() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->end();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n        }\n    }\n\n  public:\n    /*!\n    @brief return a reference to the value pointed to by the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator*() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());\n                return m_it.object_iterator->second;\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());\n                return *m_it.array_iterator;\n            }\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief dereference the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    pointer operator->() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());\n                return &(m_it.object_iterator->second);\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());\n                return &*m_it.array_iterator;\n            }\n\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief post-increment (it++)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator++(int)\n    {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-increment (++it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator++()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, 1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, 1);\n                break;\n            }\n\n            default:\n            {\n                ++m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief post-decrement (it--)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator--(int)\n    {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-decrement (--it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator--()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, -1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, -1);\n                break;\n            }\n\n            default:\n            {\n                --m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief comparison: equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator==(const IterImpl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                return (m_it.object_iterator == other.m_it.object_iterator);\n\n            case value_t::array:\n                return (m_it.array_iterator == other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator == other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: not equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator!=(const IterImpl& other) const\n    {\n        return !operator==(other);\n    }\n\n    /*!\n    @brief comparison: smaller\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\"));\n\n            case value_t::array:\n                return (m_it.array_iterator < other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator < other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<=(const iter_impl& other) const\n    {\n        return !other.operator < (*this);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>(const iter_impl& other) const\n    {\n        return !operator<=(other);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>=(const iter_impl& other) const\n    {\n        return !operator<(other);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator+=(difference_type i)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, i);\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator += i;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator-=(difference_type i)\n    {\n        return operator+=(-i);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator+(difference_type i) const\n    {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief addition of distance and iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    friend iter_impl operator+(difference_type i, const iter_impl& it)\n    {\n        auto result = it;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator-(difference_type i) const\n    {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /*!\n    @brief return difference\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    difference_type operator-(const iter_impl& other) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n                return m_it.array_iterator - other.m_it.array_iterator;\n\n            default:\n                return m_it.primitive_iterator - other.m_it.primitive_iterator;\n        }\n    }\n\n    /*!\n    @brief access to successor\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator[](difference_type n) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\"));\n\n            case value_t::array:\n                return *std::next(m_it.array_iterator, n);\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief return the key of an object iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    const typename object_t::key_type& key() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        if (JSON_HEDLEY_LIKELY(m_object->is_object()))\n        {\n            return m_it.object_iterator->first;\n        }\n\n        JSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\"));\n    }\n\n    /*!\n    @brief return the value of an iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference value() const\n    {\n        return operator*();\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// associated JSON instance\n    pointer m_object = nullptr;\n    /// the actual iterator of the associated instance\n    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};\n};\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////////\n// reverse_iterator //\n//////////////////////\n\n/*!\n@brief a template for a reverse iterator class\n\n@tparam Base the base iterator type to reverse. Valid types are @ref\niterator (to create @ref reverse_iterator) and @ref const_iterator (to\ncreate @ref const_reverse_iterator).\n\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n  It is possible to write to the pointed-to element (only if @a Base is\n  @ref iterator).\n\n@since version 1.0.0\n*/\ntemplate<typename Base>\nclass json_reverse_iterator : public std::reverse_iterator<Base>\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    /// shortcut to the reverse iterator adapter\n    using base_iterator = std::reverse_iterator<Base>;\n    /// the reference type for the pointed-to element\n    using reference = typename Base::reference;\n\n    /// create reverse iterator from iterator\n    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n        : base_iterator(it) {}\n\n    /// create reverse iterator from base class\n    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n    /// post-increment (it++)\n    json_reverse_iterator const operator++(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n    }\n\n    /// pre-increment (++it)\n    json_reverse_iterator& operator++()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator++());\n    }\n\n    /// post-decrement (it--)\n    json_reverse_iterator const operator--(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n    }\n\n    /// pre-decrement (--it)\n    json_reverse_iterator& operator--()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator--());\n    }\n\n    /// add to iterator\n    json_reverse_iterator& operator+=(difference_type i)\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n    }\n\n    /// add to iterator\n    json_reverse_iterator operator+(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n    }\n\n    /// subtract from iterator\n    json_reverse_iterator operator-(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n    }\n\n    /// return difference\n    difference_type operator-(const json_reverse_iterator& other) const\n    {\n        return base_iterator(*this) - base_iterator(other);\n    }\n\n    /// access to successor\n    reference operator[](difference_type n) const\n    {\n        return *(this->operator+(n));\n    }\n\n    /// return the key of an object iterator\n    auto key() const -> decltype(std::declval<Base>().key())\n    {\n        auto it = --this->base();\n        return it.key();\n    }\n\n    /// return the value of an iterator\n    reference value() const\n    {\n        auto it = --this->base();\n        return it.operator * ();\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/json_pointer.hpp>\n\n\n#include <algorithm> // all_of\n#include <cctype> // isdigit\n#include <limits> // max\n#include <numeric> // accumulate\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\ntemplate<typename BasicJsonType>\nclass json_pointer\n{\n    // allow basic_json to access private members\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    friend class basic_json;\n\n  public:\n    /*!\n    @brief create JSON pointer\n\n    Create a JSON pointer according to the syntax described in\n    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).\n\n    @param[in] s  string representing the JSON pointer; if omitted, the empty\n                  string is assumed which references the whole JSON value\n\n    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does\n                           not begin with a slash (`/`); see example below\n\n    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is\n    not followed by `0` (representing `~`) or `1` (representing `/`); see\n    example below\n\n    @liveexample{The example shows the construction several valid JSON pointers\n    as well as the exceptional behavior.,json_pointer}\n\n    @since version 2.0.0\n    */\n    explicit json_pointer(const std::string& s = \"\")\n        : reference_tokens(split(s))\n    {}\n\n    /*!\n    @brief return a string representation of the JSON pointer\n\n    @invariant For each JSON pointer `ptr`, it holds:\n    @code {.cpp}\n    ptr == json_pointer(ptr.to_string());\n    @endcode\n\n    @return a string representation of the JSON pointer\n\n    @liveexample{The example shows the result of `to_string`.,json_pointer__to_string}\n\n    @since version 2.0.0\n    */\n    std::string to_string() const\n    {\n        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n                               std::string{},\n                               [](const std::string & a, const std::string & b)\n        {\n            return a + \"/\" + escape(b);\n        });\n    }\n\n    /// @copydoc to_string()\n    operator std::string() const\n    {\n        return to_string();\n    }\n\n    /*!\n    @brief append another JSON pointer at the end of this JSON pointer\n\n    @param[in] ptr  JSON pointer to append\n    @return JSON pointer with @a ptr appended\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa @ref operator/=(std::string) to append a reference token\n    @sa @ref operator/=(std::size_t) to append an array index\n    @sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(const json_pointer& ptr)\n    {\n        reference_tokens.insert(reference_tokens.end(),\n                                ptr.reference_tokens.begin(),\n                                ptr.reference_tokens.end());\n        return *this;\n    }\n\n    /*!\n    @brief append an unescaped reference token at the end of this JSON pointer\n\n    @param[in] token  reference token to append\n    @return JSON pointer with @a token appended without escaping @a token\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Amortized constant.\n\n    @sa @ref operator/=(const json_pointer&) to append a JSON pointer\n    @sa @ref operator/=(std::size_t) to append an array index\n    @sa @ref operator/(const json_pointer&, std::size_t) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(std::string token)\n    {\n        push_back(std::move(token));\n        return *this;\n    }\n\n    /*!\n    @brief append an array index at the end of this JSON pointer\n\n    @param[in] array_idx  array index to append\n    @return JSON pointer with @a array_idx appended\n\n    @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}\n\n    @complexity Amortized constant.\n\n    @sa @ref operator/=(const json_pointer&) to append a JSON pointer\n    @sa @ref operator/=(std::string) to append a reference token\n    @sa @ref operator/(const json_pointer&, std::string) for a binary operator\n\n    @since version 3.6.0\n    */\n    json_pointer& operator/=(std::size_t array_idx)\n    {\n        return *this /= std::to_string(array_idx);\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer\n\n    @param[in] lhs  JSON pointer\n    @param[in] rhs  JSON pointer\n    @return a new JSON pointer with @a rhs appended to @a lhs\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a lhs and @a rhs.\n\n    @sa @ref operator/=(const json_pointer&) to append a JSON pointer\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& lhs,\n                                  const json_pointer& rhs)\n    {\n        return json_pointer(lhs) /= rhs;\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer\n\n    @param[in] ptr  JSON pointer\n    @param[in] token  reference token\n    @return a new JSON pointer with unescaped @a token appended to @a ptr\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa @ref operator/=(std::string) to append a reference token\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& ptr, std::string token)\n    {\n        return json_pointer(ptr) /= std::move(token);\n    }\n\n    /*!\n    @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer\n\n    @param[in] ptr  JSON pointer\n    @param[in] array_idx  array index\n    @return a new JSON pointer with @a array_idx appended to @a ptr\n\n    @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}\n\n    @complexity Linear in the length of @a ptr.\n\n    @sa @ref operator/=(std::size_t) to append an array index\n\n    @since version 3.6.0\n    */\n    friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx)\n    {\n        return json_pointer(ptr) /= array_idx;\n    }\n\n    /*!\n    @brief returns the parent of this JSON pointer\n\n    @return parent of this JSON pointer; in case this JSON pointer is the root,\n            the root itself is returned\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @liveexample{The example shows the result of `parent_pointer` for different\n    JSON Pointers.,json_pointer__parent_pointer}\n\n    @since version 3.6.0\n    */\n    json_pointer parent_pointer() const\n    {\n        if (empty())\n        {\n            return *this;\n        }\n\n        json_pointer res = *this;\n        res.pop_back();\n        return res;\n    }\n\n    /*!\n    @brief remove last reference token\n\n    @pre not `empty()`\n\n    @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}\n\n    @complexity Constant.\n\n    @throw out_of_range.405 if JSON pointer has no parent\n\n    @since version 3.6.0\n    */\n    void pop_back()\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        reference_tokens.pop_back();\n    }\n\n    /*!\n    @brief return last reference token\n\n    @pre not `empty()`\n    @return last reference token\n\n    @liveexample{The example shows the usage of `back`.,json_pointer__back}\n\n    @complexity Constant.\n\n    @throw out_of_range.405 if JSON pointer has no parent\n\n    @since version 3.6.0\n    */\n    const std::string& back() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        return reference_tokens.back();\n    }\n\n    /*!\n    @brief append an unescaped token at the end of the reference pointer\n\n    @param[in] token  token to add\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows the result of `push_back` for different\n    JSON Pointers.,json_pointer__push_back}\n\n    @since version 3.6.0\n    */\n    void push_back(const std::string& token)\n    {\n        reference_tokens.push_back(token);\n    }\n\n    /// @copydoc push_back(const std::string&)\n    void push_back(std::string&& token)\n    {\n        reference_tokens.push_back(std::move(token));\n    }\n\n    /*!\n    @brief return whether pointer points to the root document\n\n    @return true iff the JSON pointer points to the root document\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example shows the result of `empty` for different JSON\n    Pointers.,json_pointer__empty}\n\n    @since version 3.6.0\n    */\n    bool empty() const noexcept\n    {\n        return reference_tokens.empty();\n    }\n\n  private:\n    /*!\n    @param[in] s  reference token to be converted into an array index\n\n    @return integer representation of @a s\n\n    @throw parse_error.106  if an array index begins with '0'\n    @throw parse_error.109  if an array index begins not with a digit\n    @throw out_of_range.404 if string @a s could not be converted to an integer\n    @throw out_of_range.410 if an array index exceeds size_type\n    */\n    static typename BasicJsonType::size_type array_index(const std::string& s)\n    {\n        using size_type = typename BasicJsonType::size_type;\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))\n        {\n            JSON_THROW(detail::parse_error::create(106, 0,\n                                                   \"array index '\" + s +\n                                                   \"' must not begin with '0'\"));\n        }\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))\n        {\n            JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + s + \"' is not a number\"));\n        }\n\n        std::size_t processed_chars = 0;\n        unsigned long long res = 0;\n        JSON_TRY\n        {\n            res = std::stoull(s, &processed_chars);\n        }\n        JSON_CATCH(std::out_of_range&)\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\"));\n        }\n\n        // check if the string was completely read\n        if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\"));\n        }\n\n        // only triggered on special platforms (like 32bit), see also\n        // https://github.com/nlohmann/json/pull/2203\n        if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))\n        {\n            JSON_THROW(detail::out_of_range::create(410, \"array index \" + s + \" exceeds size_type\")); // LCOV_EXCL_LINE\n        }\n\n        return static_cast<size_type>(res);\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    json_pointer top() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        json_pointer result = *this;\n        result.reference_tokens = {reference_tokens[0]};\n        return result;\n    }\n\n  private:\n    /*!\n    @brief create and return a reference to the pointed to value\n\n    @complexity Linear in the number of reference tokens.\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.313 if value cannot be unflattened\n    */\n    BasicJsonType& get_and_create(BasicJsonType& j) const\n    {\n        auto result = &j;\n\n        // in case no reference tokens exist, return a reference to the JSON value\n        // j which will be overwritten by a primitive value\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (result->type())\n            {\n                case detail::value_t::null:\n                {\n                    if (reference_token == \"0\")\n                    {\n                        // start a new array if reference token is 0\n                        result = &result->operator[](0);\n                    }\n                    else\n                    {\n                        // start a new object otherwise\n                        result = &result->operator[](reference_token);\n                    }\n                    break;\n                }\n\n                case detail::value_t::object:\n                {\n                    // create an entry in the object\n                    result = &result->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // create an entry in the array\n                    result = &result->operator[](array_index(reference_token));\n                    break;\n                }\n\n                /*\n                The following code is only reached if there exists a reference\n                token _and_ the current value is primitive. In this case, we have\n                an error situation, because primitive values may only occur as\n                single value; that is, with an empty list of reference tokens.\n                */\n                default:\n                    JSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\"));\n            }\n        }\n\n        return *result;\n    }\n\n    /*!\n    @brief return a reference to the pointed to value\n\n    @note This version does not throw if a value is not present, but tries to\n          create nested values instead. For instance, calling this function\n          with pointer `\"/this/that\"` on a null value is equivalent to calling\n          `operator[](\"this\").operator[](\"that\")` on that value, effectively\n          changing the null value to an object.\n\n    @param[in] ptr  a JSON value\n\n    @return reference to the JSON value pointed to by the JSON pointer\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_unchecked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            // convert null values to arrays or objects before continuing\n            if (ptr->is_null())\n            {\n                // check if reference token is a number\n                const bool nums =\n                    std::all_of(reference_token.begin(), reference_token.end(),\n                                [](const unsigned char x)\n                {\n                    return std::isdigit(x);\n                });\n\n                // change value to array for numbers or \"-\" or to object otherwise\n                *ptr = (nums || reference_token == \"-\")\n                       ? detail::value_t::array\n                       : detail::value_t::object;\n            }\n\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (reference_token == \"-\")\n                    {\n                        // explicitly treat \"-\" as index beyond the end\n                        ptr = &ptr->operator[](ptr->m_value.array->size());\n                    }\n                    else\n                    {\n                        // convert array index to number; unchecked access\n                        ptr = &ptr->operator[](array_index(reference_token));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_checked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index(reference_token));\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief return a const reference to the pointed to value\n\n    @param[in] ptr  a JSON value\n\n    @return const reference to the JSON value pointed to by the JSON\n    pointer\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" cannot be used for const access\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // use unchecked array access\n                    ptr = &ptr->operator[](array_index(reference_token));\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_checked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index(reference_token));\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    */\n    bool contains(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    if (!ptr->contains(reference_token))\n                    {\n                        // we did not find the key in the object\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !(\"0\" <= reference_token && reference_token <= \"9\")))\n                    {\n                        // invalid char\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))\n                        {\n                            // first char should be between '1' and '9'\n                            return false;\n                        }\n                        for (std::size_t i = 1; i < reference_token.size(); i++)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))\n                            {\n                                // other char should be between '0' and '9'\n                                return false;\n                            }\n                        }\n                    }\n\n                    const auto idx = array_index(reference_token);\n                    if (idx >= ptr->size())\n                    {\n                        // index out of range\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](idx);\n                    break;\n                }\n\n                default:\n                {\n                    // we do not expect primitive values if there is still a\n                    // reference token to process\n                    return false;\n                }\n            }\n        }\n\n        // no reference token left means we found a primitive value\n        return true;\n    }\n\n    /*!\n    @brief split the string input to reference tokens\n\n    @note This function is only called by the json_pointer constructor.\n          All exceptions below are documented there.\n\n    @throw parse_error.107  if the pointer is not empty or begins with '/'\n    @throw parse_error.108  if character '~' is not followed by '0' or '1'\n    */\n    static std::vector<std::string> split(const std::string& reference_string)\n    {\n        std::vector<std::string> result;\n\n        // special case: empty reference string -> no reference tokens\n        if (reference_string.empty())\n        {\n            return result;\n        }\n\n        // check if nonempty reference string begins with slash\n        if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))\n        {\n            JSON_THROW(detail::parse_error::create(107, 1,\n                                                   \"JSON pointer must be empty or begin with '/' - was: '\" +\n                                                   reference_string + \"'\"));\n        }\n\n        // extract the reference tokens:\n        // - slash: position of the last read slash (or end of string)\n        // - start: position after the previous slash\n        for (\n            // search for the first slash after the first character\n            std::size_t slash = reference_string.find_first_of('/', 1),\n            // set the beginning of the first reference token\n            start = 1;\n            // we can stop if start == 0 (if slash == std::string::npos)\n            start != 0;\n            // set the beginning of the next reference token\n            // (will eventually be 0 if slash == std::string::npos)\n            start = (slash == std::string::npos) ? 0 : slash + 1,\n            // find next slash\n            slash = reference_string.find_first_of('/', start))\n        {\n            // use the text between the beginning of the reference token\n            // (start) and the last slash (slash).\n            auto reference_token = reference_string.substr(start, slash - start);\n\n            // check reference tokens are properly escaped\n            for (std::size_t pos = reference_token.find_first_of('~');\n                    pos != std::string::npos;\n                    pos = reference_token.find_first_of('~', pos + 1))\n            {\n                JSON_ASSERT(reference_token[pos] == '~');\n\n                // ~ must be followed by 0 or 1\n                if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||\n                                         (reference_token[pos + 1] != '0' &&\n                                          reference_token[pos + 1] != '1')))\n                {\n                    JSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\"));\n                }\n            }\n\n            // finally, store the reference token\n            unescape(reference_token);\n            result.push_back(reference_token);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief replace all occurrences of a substring by another string\n\n    @param[in,out] s  the string to manipulate; changed so that all\n                   occurrences of @a f are replaced with @a t\n    @param[in]     f  the substring to replace with @a t\n    @param[in]     t  the string to replace @a f\n\n    @pre The search string @a f must not be empty. **This precondition is\n    enforced with an assertion.**\n\n    @since version 2.0.0\n    */\n    static void replace_substring(std::string& s, const std::string& f,\n                                  const std::string& t)\n    {\n        JSON_ASSERT(!f.empty());\n        for (auto pos = s.find(f);                // find first occurrence of f\n                pos != std::string::npos;         // make sure f was found\n                s.replace(pos, f.size(), t),      // replace with t, and\n                pos = s.find(f, pos + t.size()))  // find next occurrence of f\n        {}\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// escape \"~\" to \"~0\" and \"/\" to \"~1\"\n    static std::string escape(std::string s)\n    {\n        replace_substring(s, \"~\", \"~0\");\n        replace_substring(s, \"/\", \"~1\");\n        return s;\n    }\n\n    /// unescape \"~1\" to tilde and \"~0\" to slash (order is important!)\n    static void unescape(std::string& s)\n    {\n        replace_substring(s, \"~1\", \"/\");\n        replace_substring(s, \"~0\", \"~\");\n    }\n\n  private:\n    /*!\n    @param[in] reference_string  the reference string to the current value\n    @param[in] value             the value to consider\n    @param[in,out] result        the result object to insert values to\n\n    @note Empty objects or arrays are flattened to `null`.\n    */\n    static void flatten(const std::string& reference_string,\n                        const BasicJsonType& value,\n                        BasicJsonType& result)\n    {\n        switch (value.type())\n        {\n            case detail::value_t::array:\n            {\n                if (value.m_value.array->empty())\n                {\n                    // flatten empty array as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate array and use index as reference string\n                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)\n                    {\n                        flatten(reference_string + \"/\" + std::to_string(i),\n                                value.m_value.array->operator[](i), result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::object:\n            {\n                if (value.m_value.object->empty())\n                {\n                    // flatten empty object as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate object and use keys as reference string\n                    for (const auto& element : *value.m_value.object)\n                    {\n                        flatten(reference_string + \"/\" + escape(element.first), element.second, result);\n                    }\n                }\n                break;\n            }\n\n            default:\n            {\n                // add primitive value with its reference string\n                result[reference_string] = value;\n                break;\n            }\n        }\n    }\n\n    /*!\n    @param[in] value  flattened JSON\n\n    @return unflattened JSON\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n    @throw type_error.313  if value cannot be unflattened\n    */\n    static BasicJsonType\n    unflatten(const BasicJsonType& value)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!value.is_object()))\n        {\n            JSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\"));\n        }\n\n        BasicJsonType result;\n\n        // iterate the JSON object values\n        for (const auto& element : *value.m_value.object)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))\n            {\n                JSON_THROW(detail::type_error::create(315, \"values in object must be primitive\"));\n            }\n\n            // assign value to reference pointed to by JSON pointer; Note that if\n            // the JSON pointer is \"\" (i.e., points to the whole value), function\n            // get_and_create returns a reference to result itself. An assignment\n            // will then create a primitive value.\n            json_pointer(element.first).get_and_create(result) = element.second;\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief compares two JSON pointers for equality\n\n    @param[in] lhs  JSON pointer to compare\n    @param[in] rhs  JSON pointer to compare\n    @return whether @a lhs is equal to @a rhs\n\n    @complexity Linear in the length of the JSON pointer\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n    */\n    friend bool operator==(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return lhs.reference_tokens == rhs.reference_tokens;\n    }\n\n    /*!\n    @brief compares two JSON pointers for inequality\n\n    @param[in] lhs  JSON pointer to compare\n    @param[in] rhs  JSON pointer to compare\n    @return whether @a lhs is not equal @a rhs\n\n    @complexity Linear in the length of the JSON pointer\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n    */\n    friend bool operator!=(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return !(lhs == rhs);\n    }\n\n    /// the reference tokens\n    std::vector<std::string> reference_tokens;\n};\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/json_ref.hpp>\n\n\n#include <initializer_list>\n#include <utility>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nclass json_ref\n{\n  public:\n    using value_type = BasicJsonType;\n\n    json_ref(value_type&& value)\n        : owned_value(std::move(value))\n    {}\n\n    json_ref(const value_type& value)\n        : value_ref(&value)\n    {}\n\n    json_ref(std::initializer_list<json_ref> init)\n        : owned_value(init)\n    {}\n\n    template <\n        class... Args,\n        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n    json_ref(Args && ... args)\n        : owned_value(std::forward<Args>(args)...)\n    {}\n\n    // class should be movable only\n    json_ref(json_ref&&) = default;\n    json_ref(const json_ref&) = delete;\n    json_ref& operator=(const json_ref&) = delete;\n    json_ref& operator=(json_ref&&) = delete;\n    ~json_ref() = default;\n\n    value_type moved_or_copied() const\n    {\n        if (value_ref == nullptr)\n        {\n            return std::move(owned_value);\n        }\n        return *value_ref;\n    }\n\n    value_type const& operator*() const\n    {\n        return value_ref ? *value_ref : owned_value;\n    }\n\n    value_type const* operator->() const\n    {\n        return &** this;\n    }\n\n  private:\n    mutable value_type owned_value = nullptr;\n    value_type const* value_ref = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n#include <string> // string\n#include <cmath> // isnan, isinf\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <ios> // streamsize\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <ostream> // basic_ostream\n#include <string> // basic_string\n#include <vector> // vector\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// abstract output adapter interface\ntemplate<typename CharType> struct output_adapter_protocol\n{\n    virtual void write_character(CharType c) = 0;\n    virtual void write_characters(const CharType* s, std::size_t length) = 0;\n    virtual ~output_adapter_protocol() = default;\n};\n\n/// a type to simplify interfaces\ntemplate<typename CharType>\nusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n/// output adapter for byte vectors\ntemplate<typename CharType>\nclass output_vector_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_vector_adapter(std::vector<CharType>& vec) noexcept\n        : v(vec)\n    {}\n\n    void write_character(CharType c) override\n    {\n        v.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        std::copy(s, s + length, std::back_inserter(v));\n    }\n\n  private:\n    std::vector<CharType>& v;\n};\n\n/// output adapter for output streams\ntemplate<typename CharType>\nclass output_stream_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n        : stream(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        stream.put(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        stream.write(s, static_cast<std::streamsize>(length));\n    }\n\n  private:\n    std::basic_ostream<CharType>& stream;\n};\n\n/// output adapter for basic_string\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_string_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_string_adapter(StringType& s) noexcept\n        : str(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        str.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        str.append(s, length);\n    }\n\n  private:\n    StringType& str;\n};\n\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_adapter\n{\n  public:\n    output_adapter(std::vector<CharType>& vec)\n        : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}\n\n    output_adapter(std::basic_ostream<CharType>& s)\n        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n\n    output_adapter(StringType& s)\n        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n    operator output_adapter_t<CharType>()\n    {\n        return oa;\n    }\n\n  private:\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary writer //\n///////////////////\n\n/*!\n@brief serialization to CBOR and MessagePack values\n*/\ntemplate<typename BasicJsonType, typename CharType>\nclass binary_writer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n  public:\n    /*!\n    @brief create a binary writer\n\n    @param[in] adapter  output adapter to write to\n    */\n    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)\n    {\n        JSON_ASSERT(oa);\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n            {\n                write_bson_object(*j.m_value.object);\n                break;\n            }\n\n            default:\n            {\n                JSON_THROW(type_error::create(317, \"to serialize to BSON, top-level type must be object, but is \" + std::string(j.type_name())));\n            }\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_cbor(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                oa->write_character(to_char_type(0xF6));\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xF5)\n                                    : to_char_type(0xF4));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // CBOR does not differentiate between positive signed\n                    // integers and unsigned integers. Therefore, we used the\n                    // code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_integer <= 0x17)\n                    {\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x18));\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x19));\n                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x1A));\n                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x1B));\n                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    // The conversions below encode the sign in the first\n                    // byte, and the value is converted to a positive number.\n                    const auto positive_number = -1 - j.m_value.number_integer;\n                    if (j.m_value.number_integer >= -24)\n                    {\n                        write_number(static_cast<std::uint8_t>(0x20 + positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x38));\n                        write_number(static_cast<std::uint8_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x39));\n                        write_number(static_cast<std::uint16_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x3A));\n                        write_number(static_cast<std::uint32_t>(positive_number));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x3B));\n                        write_number(static_cast<std::uint64_t>(positive_number));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x18));\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x19));\n                    write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x1A));\n                    write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));\n                }\n                else\n                {\n                    oa->write_character(to_char_type(0x1B));\n                    write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                if (std::isnan(j.m_value.number_float))\n                {\n                    // NaN is 0xf97e00 in CBOR\n                    oa->write_character(to_char_type(0xF9));\n                    oa->write_character(to_char_type(0x7E));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else if (std::isinf(j.m_value.number_float))\n                {\n                    // Infinity is 0xf97c00, -Infinity is 0xf9fc00\n                    oa->write_character(to_char_type(0xf9));\n                    oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else\n                {\n                    write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);\n                }\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x60 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x78));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x79));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x80 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x98));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x99));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_cbor(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (j.m_value.binary->has_subtype())\n                {\n                    write_number(static_cast<std::uint8_t>(0xd8));\n                    write_number(j.m_value.binary->subtype());\n                }\n\n                // step 1: write control byte and the binary array size\n                const auto N = j.m_value.binary->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x40 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x58));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x59));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0xA0 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB8));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB9));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBA));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBB));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_cbor(el.first);\n                    write_cbor(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_msgpack(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null: // nil\n            {\n                oa->write_character(to_char_type(0xC0));\n                break;\n            }\n\n            case value_t::boolean: // true and false\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xC3)\n                                    : to_char_type(0xC2));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // MessagePack does not differentiate between positive\n                    // signed integers and unsigned integers. Therefore, we used\n                    // the code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_unsigned < 128)\n                    {\n                        // positive fixnum\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        // uint 8\n                        oa->write_character(to_char_type(0xCC));\n                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        // uint 16\n                        oa->write_character(to_char_type(0xCD));\n                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        // uint 32\n                        oa->write_character(to_char_type(0xCE));\n                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                    {\n                        // uint 64\n                        oa->write_character(to_char_type(0xCF));\n                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    if (j.m_value.number_integer >= -32)\n                    {\n                        // negative fixnum\n                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                    {\n                        // int 8\n                        oa->write_character(to_char_type(0xD0));\n                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                    {\n                        // int 16\n                        oa->write_character(to_char_type(0xD1));\n                        write_number(static_cast<std::int16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                    {\n                        // int 32\n                        oa->write_character(to_char_type(0xD2));\n                        write_number(static_cast<std::int32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&\n                             j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                    {\n                        // int 64\n                        oa->write_character(to_char_type(0xD3));\n                        write_number(static_cast<std::int64_t>(j.m_value.number_integer));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned < 128)\n                {\n                    // positive fixnum\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // uint 8\n                    oa->write_character(to_char_type(0xCC));\n                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // uint 16\n                    oa->write_character(to_char_type(0xCD));\n                    write_number(static_cast<std::uint16_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // uint 32\n                    oa->write_character(to_char_type(0xCE));\n                    write_number(static_cast<std::uint32_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    // uint 64\n                    oa->write_character(to_char_type(0xCF));\n                    write_number(static_cast<std::uint64_t>(j.m_value.number_integer));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 31)\n                {\n                    // fixstr\n                    write_number(static_cast<std::uint8_t>(0xA0 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // str 8\n                    oa->write_character(to_char_type(0xD9));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // str 16\n                    oa->write_character(to_char_type(0xDA));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // str 32\n                    oa->write_character(to_char_type(0xDB));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 15)\n                {\n                    // fixarray\n                    write_number(static_cast<std::uint8_t>(0x90 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // array 16\n                    oa->write_character(to_char_type(0xDC));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // array 32\n                    oa->write_character(to_char_type(0xDD));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_msgpack(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                // step 0: determine if the binary type has a set subtype to\n                // determine whether or not to use the ext or fixext types\n                const bool use_ext = j.m_value.binary->has_subtype();\n\n                // step 1: write control byte and the byte string length\n                const auto N = j.m_value.binary->size();\n                if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    std::uint8_t output_type{};\n                    bool fixed = true;\n                    if (use_ext)\n                    {\n                        switch (N)\n                        {\n                            case 1:\n                                output_type = 0xD4; // fixext 1\n                                break;\n                            case 2:\n                                output_type = 0xD5; // fixext 2\n                                break;\n                            case 4:\n                                output_type = 0xD6; // fixext 4\n                                break;\n                            case 8:\n                                output_type = 0xD7; // fixext 8\n                                break;\n                            case 16:\n                                output_type = 0xD8; // fixext 16\n                                break;\n                            default:\n                                output_type = 0xC7; // ext 8\n                                fixed = false;\n                                break;\n                        }\n\n                    }\n                    else\n                    {\n                        output_type = 0xC4; // bin 8\n                        fixed = false;\n                    }\n\n                    oa->write_character(to_char_type(output_type));\n                    if (!fixed)\n                    {\n                        write_number(static_cast<std::uint8_t>(N));\n                    }\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    std::uint8_t output_type = use_ext\n                                               ? 0xC8 // ext 16\n                                               : 0xC5; // bin 16\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    std::uint8_t output_type = use_ext\n                                               ? 0xC9 // ext 32\n                                               : 0xC6; // bin 32\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 1.5: if this is an ext type, write the subtype\n                if (use_ext)\n                {\n                    write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));\n                }\n\n                // step 2: write the byte string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 15)\n                {\n                    // fixmap\n                    write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // map 16\n                    oa->write_character(to_char_type(0xDE));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // map 32\n                    oa->write_character(to_char_type(0xDF));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_msgpack(el.first);\n                    write_msgpack(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @param[in] use_count   whether to use '#' prefixes (optimized format)\n    @param[in] use_type    whether to use '$' prefixes (optimized format)\n    @param[in] add_prefix  whether prefixes need to be used for this value\n    */\n    void write_ubjson(const BasicJsonType& j, const bool use_count,\n                      const bool use_type, const bool add_prefix = true)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('Z'));\n                }\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(j.m_value.boolean\n                                        ? to_char_type('T')\n                                        : to_char_type('F'));\n                }\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);\n                break;\n            }\n\n            case value_t::string:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('S'));\n                }\n                write_number_with_ubjson_prefix(j.m_value.string->size(), true);\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_value.array->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_ubjson(el, use_count, use_type, prefix_required);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                if (use_type && !j.m_value.binary->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    oa->write_character(to_char_type('$'));\n                    oa->write_character('U');\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.binary->size(), true);\n                }\n\n                if (use_type)\n                {\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(j.m_value.binary->data()),\n                        j.m_value.binary->size());\n                }\n                else\n                {\n                    for (size_t i = 0; i < j.m_value.binary->size(); ++i)\n                    {\n                        oa->write_character(to_char_type('U'));\n                        oa->write_character(j.m_value.binary->data()[i]);\n                    }\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('{'));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_value.object->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin(), j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_number_with_ubjson_prefix(el.first.size(), true);\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(el.first.c_str()),\n                        el.first.size());\n                    write_ubjson(el.second, use_count, use_type, prefix_required);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type('}'));\n                }\n\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @return The size of a BSON document entry header, including the id marker\n            and the entry name size (and its null-terminator).\n    */\n    static std::size_t calc_bson_entry_header_size(const string_t& name)\n    {\n        const auto it = name.find(static_cast<typename string_t::value_type>(0));\n        if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))\n        {\n            JSON_THROW(out_of_range::create(409,\n                                            \"BSON key cannot contain code point U+0000 (at byte \" + std::to_string(it) + \")\"));\n        }\n\n        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n    }\n\n    /*!\n    @brief Writes the given @a element_type and @a name to the output adapter\n    */\n    void write_bson_entry_header(const string_t& name,\n                                 const std::uint8_t element_type)\n    {\n        oa->write_character(to_char_type(element_type)); // boolean\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(name.c_str()),\n            name.size() + 1u);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and boolean value @a value\n    */\n    void write_bson_boolean(const string_t& name,\n                            const bool value)\n    {\n        write_bson_entry_header(name, 0x08);\n        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and double value @a value\n    */\n    void write_bson_double(const string_t& name,\n                           const double value)\n    {\n        write_bson_entry_header(name, 0x01);\n        write_number<double, true>(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded string in @a value\n    */\n    static std::size_t calc_bson_string_size(const string_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and string value @a value\n    */\n    void write_bson_string(const string_t& name,\n                           const string_t& value)\n    {\n        write_bson_entry_header(name, 0x02);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(value.c_str()),\n            value.size() + 1);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and null value\n    */\n    void write_bson_null(const string_t& name)\n    {\n        write_bson_entry_header(name, 0x0A);\n    }\n\n    /*!\n    @return The size of the BSON-encoded integer @a value\n    */\n    static std::size_t calc_bson_integer_size(const std::int64_t value)\n    {\n        return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and integer @a value\n    */\n    void write_bson_integer(const string_t& name,\n                            const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            write_bson_entry_header(name, 0x10); // int32\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x12); // int64\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n    }\n\n    /*!\n    @return The size of the BSON-encoded unsigned integer in @a j\n    */\n    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n    {\n        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and unsigned @a value\n    */\n    void write_bson_unsigned(const string_t& name,\n                             const std::uint64_t value)\n    {\n        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x10 /* int32 */);\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x12 /* int64 */);\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(value) + \" cannot be represented by BSON as it does not fit int64\"));\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and object @a value\n    */\n    void write_bson_object_entry(const string_t& name,\n                                 const typename BasicJsonType::object_t& value)\n    {\n        write_bson_entry_header(name, 0x03); // object\n        write_bson_object(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded array @a value\n    */\n    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n    {\n        std::size_t array_index = 0ul;\n\n        const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)\n        {\n            return result + calc_bson_element_size(std::to_string(array_index++), el);\n        });\n\n        return sizeof(std::int32_t) + embedded_document_size + 1ul;\n    }\n\n    /*!\n    @return The size of the BSON-encoded binary array @a value\n    */\n    static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and array @a value\n    */\n    void write_bson_array(const string_t& name,\n                          const typename BasicJsonType::array_t& value)\n    {\n        write_bson_entry_header(name, 0x04); // array\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));\n\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            write_bson_element(std::to_string(array_index++), el);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and binary value @a value\n    */\n    void write_bson_binary(const string_t& name,\n                           const binary_t& value)\n    {\n        write_bson_entry_header(name, 0x05);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));\n        write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00));\n\n        oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());\n    }\n\n    /*!\n    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n    @return The calculated size for the BSON document entry for @a j with the given @a name.\n    */\n    static std::size_t calc_bson_element_size(const string_t& name,\n            const BasicJsonType& j)\n    {\n        const auto header_size = calc_bson_entry_header_size(name);\n        switch (j.type())\n        {\n            case value_t::object:\n                return header_size + calc_bson_object_size(*j.m_value.object);\n\n            case value_t::array:\n                return header_size + calc_bson_array_size(*j.m_value.array);\n\n            case value_t::binary:\n                return header_size + calc_bson_binary_size(*j.m_value.binary);\n\n            case value_t::boolean:\n                return header_size + 1ul;\n\n            case value_t::number_float:\n                return header_size + 8ul;\n\n            case value_t::number_integer:\n                return header_size + calc_bson_integer_size(j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);\n\n            case value_t::string:\n                return header_size + calc_bson_string_size(*j.m_value.string);\n\n            case value_t::null:\n                return header_size + 0ul;\n\n            // LCOV_EXCL_START\n            default:\n                JSON_ASSERT(false);\n                return 0ul;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Serializes the JSON value @a j to BSON and associates it with the\n           key @a name.\n    @param name The name to associate with the JSON entity @a j within the\n                current BSON document\n    @return The size of the BSON entry\n    */\n    void write_bson_element(const string_t& name,\n                            const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n                return write_bson_object_entry(name, *j.m_value.object);\n\n            case value_t::array:\n                return write_bson_array(name, *j.m_value.array);\n\n            case value_t::binary:\n                return write_bson_binary(name, *j.m_value.binary);\n\n            case value_t::boolean:\n                return write_bson_boolean(name, j.m_value.boolean);\n\n            case value_t::number_float:\n                return write_bson_double(name, j.m_value.number_float);\n\n            case value_t::number_integer:\n                return write_bson_integer(name, j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return write_bson_unsigned(name, j.m_value.number_unsigned);\n\n            case value_t::string:\n                return write_bson_string(name, *j.m_value.string);\n\n            case value_t::null:\n                return write_bson_null(name);\n\n            // LCOV_EXCL_START\n            default:\n                JSON_ASSERT(false);\n                return;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Calculates the size of the BSON serialization of the given\n           JSON-object @a j.\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n    {\n        std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0),\n                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)\n        {\n            return result += calc_bson_element_size(el.first, el.second);\n        });\n\n        return sizeof(std::int32_t) + document_size + 1ul;\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson_object(const typename BasicJsonType::object_t& value)\n    {\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));\n\n        for (const auto& el : value)\n        {\n            write_bson_element(el.first, el.second);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    static constexpr CharType get_cbor_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xFA);  // Single-Precision Float\n    }\n\n    static constexpr CharType get_cbor_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xFB);  // Double-Precision Float\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xCA);  // float 32\n    }\n\n    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xCB);  // float 64\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    // UBJSON: write number (floating point)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (add_prefix)\n        {\n            oa->write_character(get_ubjson_float_prefix(n));\n        }\n        write_number(n);\n    }\n\n    // UBJSON: write number (unsigned integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_unsigned<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if (n <= (std::numeric_limits<std::uint8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n));\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n));\n        }\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n    }\n\n    // UBJSON: write number (signed integer)\n    template < typename NumberType, typename std::enable_if <\n                   std::is_signed<NumberType>::value&&\n                   !std::is_floating_point<NumberType>::value, int >::type = 0 >\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::int8_t>(n));\n        }\n        else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n));\n        }\n        else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n));\n        }\n        else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n));\n        }\n        else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n));\n        }\n        // LCOV_EXCL_START\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n        // LCOV_EXCL_STOP\n    }\n\n    /*!\n    @brief determine the type prefix of container values\n    */\n    CharType ubjson_prefix(const BasicJsonType& j) const noexcept\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n                return 'Z';\n\n            case value_t::boolean:\n                return j.m_value.boolean ? 'T' : 'F';\n\n            case value_t::number_integer:\n            {\n                if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                {\n                    return 'l';\n                }\n                if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                {\n                    return 'L';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n                {\n                    return 'i';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))\n                {\n                    return 'U';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n                {\n                    return 'I';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n                {\n                    return 'l';\n                }\n                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n                {\n                    return 'L';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_float:\n                return get_ubjson_float_prefix(j.m_value.number_float);\n\n            case value_t::string:\n                return 'S';\n\n            case value_t::array: // fallthrough\n            case value_t::binary:\n                return '[';\n\n            case value_t::object:\n                return '{';\n\n            default:  // discarded values\n                return 'N';\n        }\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n    {\n        return 'd';  // float 32\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n    {\n        return 'D';  // float 64\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*\n    @brief write a number to output input\n    @param[in] n number of type @a NumberType\n    @tparam NumberType the type of the number\n    @tparam OutputIsLittleEndian Set to true if output data is\n                                 required to be little endian\n\n    @note This function needs to respect the system's endianess, because bytes\n          in CBOR, MessagePack, and UBJSON are stored in network order (big\n          endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool OutputIsLittleEndian = false>\n    void write_number(const NumberType n)\n    {\n        // step 1: write number to array of length NumberType\n        std::array<CharType, sizeof(NumberType)> vec;\n        std::memcpy(vec.data(), &n, sizeof(NumberType));\n\n        // step 2: write array to output (with possible reordering)\n        if (is_little_endian != OutputIsLittleEndian)\n        {\n            // reverse byte order prior to conversion if necessary\n            std::reverse(vec.begin(), vec.end());\n        }\n\n        oa->write_characters(vec.data(), sizeof(NumberType));\n    }\n\n    void write_compact_float(const number_float_t n, detail::input_format_t format)\n    {\n        if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&\n                static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&\n                static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(static_cast<float>(n))\n                                : get_msgpack_float_prefix(static_cast<float>(n)));\n            write_number(static_cast<float>(n));\n        }\n        else\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(n)\n                                : get_msgpack_float_prefix(n));\n            write_number(n);\n        }\n    }\n\n  public:\n    // The following to_char_type functions are implement the conversion\n    // between uint8_t and CharType. In case CharType is not unsigned,\n    // such a conversion is required to allow values greater than 128.\n    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return *reinterpret_cast<char*>(&x);\n    }\n\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >\n    static CharType to_char_type(std::uint8_t x) noexcept\n    {\n        static_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n        static_assert(std::is_trivial<CharType>::value, \"CharType must be trivial\");\n        CharType result;\n        std::memcpy(&result, &x, sizeof(x));\n        return result;\n    }\n\n    template<typename C = CharType,\n             enable_if_t<std::is_unsigned<C>::value>* = nullptr>\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return x;\n    }\n\n    template < typename InputCharType, typename C = CharType,\n               enable_if_t <\n                   std::is_signed<C>::value &&\n                   std::is_signed<char>::value &&\n                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n                   > * = nullptr >\n    static constexpr CharType to_char_type(InputCharType x) noexcept\n    {\n        return x;\n    }\n\n  private:\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the output\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/output/serializer.hpp>\n\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string, char_traits\n#include <type_traits> // is_same\n#include <utility> // move\n\n// #include <nlohmann/detail/conversions/to_chars.hpp>\n\n\n#include <array> // array\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n#include <limits> // numeric_limits\n#include <type_traits> // conditional\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/*!\n@brief implements the Grisu2 algorithm for binary to decimal floating-point\nconversion.\n\nThis implementation is a slightly modified version of the reference\nimplementation which may be obtained from\nhttp://florian.loitsch.com/publications (bench.tar.gz).\n\nThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\nFor a detailed description of the algorithm see:\n\n[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n    Integers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n    Language Design and Implementation, PLDI 2010\n[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n    Design and Implementation, PLDI 1996\n*/\nnamespace dtoa_impl\n{\n\ntemplate<typename Target, typename Source>\nTarget reinterpret_bits(const Source source)\n{\n    static_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n    Target target;\n    std::memcpy(&target, &source, sizeof(Source));\n    return target;\n}\n\nstruct diyfp // f * 2^e\n{\n    static constexpr int kPrecision = 64; // = q\n\n    std::uint64_t f = 0;\n    int e = 0;\n\n    constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n    /*!\n    @brief returns x - y\n    @pre x.e == y.e and x.f >= y.f\n    */\n    static diyfp sub(const diyfp& x, const diyfp& y) noexcept\n    {\n        JSON_ASSERT(x.e == y.e);\n        JSON_ASSERT(x.f >= y.f);\n\n        return {x.f - y.f, x.e};\n    }\n\n    /*!\n    @brief returns x * y\n    @note The result is rounded. (Only the upper q bits are returned.)\n    */\n    static diyfp mul(const diyfp& x, const diyfp& y) noexcept\n    {\n        static_assert(kPrecision == 64, \"internal error\");\n\n        // Computes:\n        //  f = round((x.f * y.f) / 2^q)\n        //  e = x.e + y.e + q\n\n        // Emulate the 64-bit * 64-bit multiplication:\n        //\n        // p = u * v\n        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n        //\n        // (Since Q might be larger than 2^32 - 1)\n        //\n        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n        //\n        // (Q_hi + H does not overflow a 64-bit int)\n        //\n        //   = p_lo + 2^64 p_hi\n\n        const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;\n        const std::uint64_t u_hi = x.f >> 32u;\n        const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;\n        const std::uint64_t v_hi = y.f >> 32u;\n\n        const std::uint64_t p0 = u_lo * v_lo;\n        const std::uint64_t p1 = u_lo * v_hi;\n        const std::uint64_t p2 = u_hi * v_lo;\n        const std::uint64_t p3 = u_hi * v_hi;\n\n        const std::uint64_t p0_hi = p0 >> 32u;\n        const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;\n        const std::uint64_t p1_hi = p1 >> 32u;\n        const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;\n        const std::uint64_t p2_hi = p2 >> 32u;\n\n        std::uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n        // The full product might now be computed as\n        //\n        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n        // p_lo = p0_lo + (Q << 32)\n        //\n        // But in this particular case here, the full p_lo is not required.\n        // Effectively we only need to add the highest bit in p_lo to p_hi (and\n        // Q_hi + 1 does not overflow).\n\n        Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up\n\n        const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);\n\n        return {h, x.e + y.e + 64};\n    }\n\n    /*!\n    @brief normalize x such that the significand is >= 2^(q-1)\n    @pre x.f != 0\n    */\n    static diyfp normalize(diyfp x) noexcept\n    {\n        JSON_ASSERT(x.f != 0);\n\n        while ((x.f >> 63u) == 0)\n        {\n            x.f <<= 1u;\n            x.e--;\n        }\n\n        return x;\n    }\n\n    /*!\n    @brief normalize x such that the result has the exponent E\n    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n    */\n    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n    {\n        const int delta = x.e - target_exponent;\n\n        JSON_ASSERT(delta >= 0);\n        JSON_ASSERT(((x.f << delta) >> delta) == x.f);\n\n        return {x.f << delta, target_exponent};\n    }\n};\n\nstruct boundaries\n{\n    diyfp w;\n    diyfp minus;\n    diyfp plus;\n};\n\n/*!\nCompute the (normalized) diyfp representing the input number 'value' and its\nboundaries.\n\n@pre value must be finite and positive\n*/\ntemplate<typename FloatType>\nboundaries compute_boundaries(FloatType value)\n{\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // Convert the IEEE representation into a diyfp.\n    //\n    // If v is denormal:\n    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n    // If v is normalized:\n    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n    static_assert(std::numeric_limits<FloatType>::is_iec559,\n                  \"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n    constexpr int      kMinExp    = 1 - kBias;\n    constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)\n\n    using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;\n\n    const std::uint64_t bits = reinterpret_bits<bits_type>(value);\n    const std::uint64_t E = bits >> (kPrecision - 1);\n    const std::uint64_t F = bits & (kHiddenBit - 1);\n\n    const bool is_denormal = E == 0;\n    const diyfp v = is_denormal\n                    ? diyfp(F, kMinExp)\n                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n    // Compute the boundaries m- and m+ of the floating-point value\n    // v = f * 2^e.\n    //\n    // Determine v- and v+, the floating-point predecessor and successor if v,\n    // respectively.\n    //\n    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n    //\n    //      v+ = v + 2^e\n    //\n    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n    // between m- and m+ round to v, regardless of how the input rounding\n    // algorithm breaks ties.\n    //\n    //      ---+-------------+-------------+-------------+-------------+---  (A)\n    //         v-            m-            v             m+            v+\n    //\n    //      -----------------+------+------+-------------+-------------+---  (B)\n    //                       v-     m-     v             m+            v+\n\n    const bool lower_boundary_is_closer = F == 0 && E > 1;\n    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);\n    const diyfp m_minus = lower_boundary_is_closer\n                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)\n                          : diyfp(2 * v.f - 1, v.e - 1); // (A)\n\n    // Determine the normalized w+ = m+.\n    const diyfp w_plus = diyfp::normalize(m_plus);\n\n    // Determine w- = m- such that e_(w-) = e_(w+).\n    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n    return {diyfp::normalize(v), w_minus, w_plus};\n}\n\n// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n//\n//      alpha <= e = e_c + e_w + q <= gamma\n//\n// or\n//\n//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n//                          <= f_c * f_w * 2^gamma\n//\n// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n//\n//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n//\n// or\n//\n//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n//\n// The choice of (alpha,gamma) determines the size of the table and the form of\n// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n// in practice:\n//\n// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n// processed independently: An integral part p1, and a fractional part p2:\n//\n//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n//              = p1 + p2 * 2^e\n//\n// The conversion of p1 into decimal form requires a series of divisions and\n// modulos by (a power of) 10. These operations are faster for 32-bit than for\n// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n// achieved by choosing\n//\n//      -e >= 32   or   e <= -32 := gamma\n//\n// In order to convert the fractional part\n//\n//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n//\n// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n// d[-i] are extracted in order:\n//\n//      (10 * p2) div 2^-e = d[-1]\n//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n//\n// The multiplication by 10 must not overflow. It is sufficient to choose\n//\n//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n//\n// Since p2 = f mod 2^-e < 2^-e,\n//\n//      -e <= 60   or   e >= -60 := alpha\n\nconstexpr int kAlpha = -60;\nconstexpr int kGamma = -32;\n\nstruct cached_power // c = f * 2^e ~= 10^k\n{\n    std::uint64_t f;\n    int e;\n    int k;\n};\n\n/*!\nFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\npower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\nsatisfies (Definition 3.2 from [1])\n\n     alpha <= e_c + e + q <= gamma.\n*/\ninline cached_power get_cached_power_for_binary_exponent(int e)\n{\n    // Now\n    //\n    //      alpha <= e_c + e + q <= gamma                                    (1)\n    //      ==> f_c * 2^alpha <= c * 2^e * 2^q\n    //\n    // and since the c's are normalized, 2^(q-1) <= f_c,\n    //\n    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n    //      ==> 2^(alpha - e - 1) <= c\n    //\n    // If c were an exact power of ten, i.e. c = 10^k, one may determine k as\n    //\n    //      k = ceil( log_10( 2^(alpha - e - 1) ) )\n    //        = ceil( (alpha - e - 1) * log_10(2) )\n    //\n    // From the paper:\n    // \"In theory the result of the procedure could be wrong since c is rounded,\n    //  and the computation itself is approximated [...]. In practice, however,\n    //  this simple function is sufficient.\"\n    //\n    // For IEEE double precision floating-point numbers converted into\n    // normalized diyfp's w = f * 2^e, with q = 64,\n    //\n    //      e >= -1022      (min IEEE exponent)\n    //           -52        (p - 1)\n    //           -52        (p - 1, possibly normalize denormal IEEE numbers)\n    //           -11        (normalize the diyfp)\n    //         = -1137\n    //\n    // and\n    //\n    //      e <= +1023      (max IEEE exponent)\n    //           -52        (p - 1)\n    //           -11        (normalize the diyfp)\n    //         = 960\n    //\n    // This binary exponent range [-1137,960] results in a decimal exponent\n    // range [-307,324]. One does not need to store a cached power for each\n    // k in this range. For each such k it suffices to find a cached power\n    // such that the exponent of the product lies in [alpha,gamma].\n    // This implies that the difference of the decimal exponents of adjacent\n    // table entries must be less than or equal to\n    //\n    //      floor( (gamma - alpha) * log_10(2) ) = 8.\n    //\n    // (A smaller distance gamma-alpha would require a larger table.)\n\n    // NB:\n    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n    constexpr int kCachedPowersMinDecExp = -300;\n    constexpr int kCachedPowersDecStep = 8;\n\n    static constexpr std::array<cached_power, 79> kCachedPowers =\n    {\n        {\n            { 0xAB70FE17C79AC6CA, -1060, -300 },\n            { 0xFF77B1FCBEBCDC4F, -1034, -292 },\n            { 0xBE5691EF416BD60C, -1007, -284 },\n            { 0x8DD01FAD907FFC3C,  -980, -276 },\n            { 0xD3515C2831559A83,  -954, -268 },\n            { 0x9D71AC8FADA6C9B5,  -927, -260 },\n            { 0xEA9C227723EE8BCB,  -901, -252 },\n            { 0xAECC49914078536D,  -874, -244 },\n            { 0x823C12795DB6CE57,  -847, -236 },\n            { 0xC21094364DFB5637,  -821, -228 },\n            { 0x9096EA6F3848984F,  -794, -220 },\n            { 0xD77485CB25823AC7,  -768, -212 },\n            { 0xA086CFCD97BF97F4,  -741, -204 },\n            { 0xEF340A98172AACE5,  -715, -196 },\n            { 0xB23867FB2A35B28E,  -688, -188 },\n            { 0x84C8D4DFD2C63F3B,  -661, -180 },\n            { 0xC5DD44271AD3CDBA,  -635, -172 },\n            { 0x936B9FCEBB25C996,  -608, -164 },\n            { 0xDBAC6C247D62A584,  -582, -156 },\n            { 0xA3AB66580D5FDAF6,  -555, -148 },\n            { 0xF3E2F893DEC3F126,  -529, -140 },\n            { 0xB5B5ADA8AAFF80B8,  -502, -132 },\n            { 0x87625F056C7C4A8B,  -475, -124 },\n            { 0xC9BCFF6034C13053,  -449, -116 },\n            { 0x964E858C91BA2655,  -422, -108 },\n            { 0xDFF9772470297EBD,  -396, -100 },\n            { 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n            { 0xF8A95FCF88747D94,  -343,  -84 },\n            { 0xB94470938FA89BCF,  -316,  -76 },\n            { 0x8A08F0F8BF0F156B,  -289,  -68 },\n            { 0xCDB02555653131B6,  -263,  -60 },\n            { 0x993FE2C6D07B7FAC,  -236,  -52 },\n            { 0xE45C10C42A2B3B06,  -210,  -44 },\n            { 0xAA242499697392D3,  -183,  -36 },\n            { 0xFD87B5F28300CA0E,  -157,  -28 },\n            { 0xBCE5086492111AEB,  -130,  -20 },\n            { 0x8CBCCC096F5088CC,  -103,  -12 },\n            { 0xD1B71758E219652C,   -77,   -4 },\n            { 0x9C40000000000000,   -50,    4 },\n            { 0xE8D4A51000000000,   -24,   12 },\n            { 0xAD78EBC5AC620000,     3,   20 },\n            { 0x813F3978F8940984,    30,   28 },\n            { 0xC097CE7BC90715B3,    56,   36 },\n            { 0x8F7E32CE7BEA5C70,    83,   44 },\n            { 0xD5D238A4ABE98068,   109,   52 },\n            { 0x9F4F2726179A2245,   136,   60 },\n            { 0xED63A231D4C4FB27,   162,   68 },\n            { 0xB0DE65388CC8ADA8,   189,   76 },\n            { 0x83C7088E1AAB65DB,   216,   84 },\n            { 0xC45D1DF942711D9A,   242,   92 },\n            { 0x924D692CA61BE758,   269,  100 },\n            { 0xDA01EE641A708DEA,   295,  108 },\n            { 0xA26DA3999AEF774A,   322,  116 },\n            { 0xF209787BB47D6B85,   348,  124 },\n            { 0xB454E4A179DD1877,   375,  132 },\n            { 0x865B86925B9BC5C2,   402,  140 },\n            { 0xC83553C5C8965D3D,   428,  148 },\n            { 0x952AB45CFA97A0B3,   455,  156 },\n            { 0xDE469FBD99A05FE3,   481,  164 },\n            { 0xA59BC234DB398C25,   508,  172 },\n            { 0xF6C69A72A3989F5C,   534,  180 },\n            { 0xB7DCBF5354E9BECE,   561,  188 },\n            { 0x88FCF317F22241E2,   588,  196 },\n            { 0xCC20CE9BD35C78A5,   614,  204 },\n            { 0x98165AF37B2153DF,   641,  212 },\n            { 0xE2A0B5DC971F303A,   667,  220 },\n            { 0xA8D9D1535CE3B396,   694,  228 },\n            { 0xFB9B7CD9A4A7443C,   720,  236 },\n            { 0xBB764C4CA7A44410,   747,  244 },\n            { 0x8BAB8EEFB6409C1A,   774,  252 },\n            { 0xD01FEF10A657842C,   800,  260 },\n            { 0x9B10A4E5E9913129,   827,  268 },\n            { 0xE7109BFBA19C0C9D,   853,  276 },\n            { 0xAC2820D9623BF429,   880,  284 },\n            { 0x80444B5E7AA7CF85,   907,  292 },\n            { 0xBF21E44003ACDD2D,   933,  300 },\n            { 0x8E679C2F5E44FF8F,   960,  308 },\n            { 0xD433179D9C8CB841,   986,  316 },\n            { 0x9E19DB92B4E31BA9,  1013,  324 },\n        }\n    };\n\n    // This computation gives exactly the same results for k as\n    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n    // for |e| <= 1500, but doesn't require floating-point operations.\n    // NB: log_10(2) ~= 78913 / 2^18\n    JSON_ASSERT(e >= -1500);\n    JSON_ASSERT(e <=  1500);\n    const int f = kAlpha - e - 1;\n    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);\n\n    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n    JSON_ASSERT(index >= 0);\n    JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());\n\n    const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];\n    JSON_ASSERT(kAlpha <= cached.e + e + 64);\n    JSON_ASSERT(kGamma >= cached.e + e + 64);\n\n    return cached;\n}\n\n/*!\nFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\nFor n == 0, returns 1 and sets pow10 := 1.\n*/\ninline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)\n{\n    // LCOV_EXCL_START\n    if (n >= 1000000000)\n    {\n        pow10 = 1000000000;\n        return 10;\n    }\n    // LCOV_EXCL_STOP\n    else if (n >= 100000000)\n    {\n        pow10 = 100000000;\n        return  9;\n    }\n    else if (n >= 10000000)\n    {\n        pow10 = 10000000;\n        return  8;\n    }\n    else if (n >= 1000000)\n    {\n        pow10 = 1000000;\n        return  7;\n    }\n    else if (n >= 100000)\n    {\n        pow10 = 100000;\n        return  6;\n    }\n    else if (n >= 10000)\n    {\n        pow10 = 10000;\n        return  5;\n    }\n    else if (n >= 1000)\n    {\n        pow10 = 1000;\n        return  4;\n    }\n    else if (n >= 100)\n    {\n        pow10 = 100;\n        return  3;\n    }\n    else if (n >= 10)\n    {\n        pow10 = 10;\n        return  2;\n    }\n    else\n    {\n        pow10 = 1;\n        return 1;\n    }\n}\n\ninline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,\n                         std::uint64_t rest, std::uint64_t ten_k)\n{\n    JSON_ASSERT(len >= 1);\n    JSON_ASSERT(dist <= delta);\n    JSON_ASSERT(rest <= delta);\n    JSON_ASSERT(ten_k > 0);\n\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    //                                  ten_k\n    //                                <------>\n    //                                       <---- rest ---->\n    // --------------[------------------+----+--------------]--------------\n    //                                  w    V\n    //                                       = buf * 10^k\n    //\n    // ten_k represents a unit-in-the-last-place in the decimal representation\n    // stored in buf.\n    // Decrement buf by ten_k while this takes buf closer to w.\n\n    // The tests are written in this order to avoid overflow in unsigned\n    // integer arithmetic.\n\n    while (rest < dist\n            && delta - rest >= ten_k\n            && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))\n    {\n        JSON_ASSERT(buf[len - 1] != '0');\n        buf[len - 1]--;\n        rest += ten_k;\n    }\n}\n\n/*!\nGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\nM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n*/\ninline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n                             diyfp M_minus, diyfp w, diyfp M_plus)\n{\n    static_assert(kAlpha >= -60, \"internal error\");\n    static_assert(kGamma <= -32, \"internal error\");\n\n    // Generates the digits (and the exponent) of a decimal floating-point\n    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n    //\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    // Grisu2 generates the digits of M+ from left to right and stops as soon as\n    // V is in [M-,M+].\n\n    JSON_ASSERT(M_plus.e >= kAlpha);\n    JSON_ASSERT(M_plus.e <= kGamma);\n\n    std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n    std::uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)\n\n    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n    //\n    //      M+ = f * 2^e\n    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n    //         = ((p1        ) * 2^-e + (p2        )) * 2^e\n    //         = p1 + p2 * 2^e\n\n    const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);\n\n    auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n    std::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n    // 1)\n    //\n    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n    JSON_ASSERT(p1 > 0);\n\n    std::uint32_t pow10;\n    const int k = find_largest_pow10(p1, pow10);\n\n    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n    //\n    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n    //\n    //      M+ = p1                                             + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n    //\n    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n    //\n    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n    //\n    // but stop as soon as\n    //\n    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n    int n = k;\n    while (n > 0)\n    {\n        // Invariants:\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        //\n        const std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n        const std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n        //\n        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n        //\n        p1 = r;\n        n--;\n        //\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n        //      pow10 = 10^n\n        //\n\n        // Now check if enough digits have been generated.\n        // Compute\n        //\n        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n        //\n        // Note:\n        // Since rest and delta share the same exponent e, it suffices to\n        // compare the significands.\n        const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;\n        if (rest <= delta)\n        {\n            // V = buffer * 10^n, with M- <= V <= M+.\n\n            decimal_exponent += n;\n\n            // We may now just stop. But instead look if the buffer could be\n            // decremented to bring V closer to w.\n            //\n            // pow10 = 10^n is now 1 ulp in the decimal representation V.\n            // The rounding procedure works with diyfp's with an implicit\n            // exponent of e.\n            //\n            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n            //\n            const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;\n            grisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n            return;\n        }\n\n        pow10 /= 10;\n        //\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        // Invariants restored.\n    }\n\n    // 2)\n    //\n    // The digits of the integral part have been generated:\n    //\n    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n    //         = buffer            + p2 * 2^e\n    //\n    // Now generate the digits of the fractional part p2 * 2^e.\n    //\n    // Note:\n    // No decimal point is generated: the exponent is adjusted instead.\n    //\n    // p2 actually represents the fraction\n    //\n    //      p2 * 2^e\n    //          = p2 / 2^-e\n    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n    //\n    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n    //\n    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n    //\n    // using\n    //\n    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n    //                = (                   d) * 2^-e + (                   r)\n    //\n    // or\n    //      10^m * p2 * 2^e = d + r * 2^e\n    //\n    // i.e.\n    //\n    //      M+ = buffer + p2 * 2^e\n    //         = buffer + 10^-m * (d + r * 2^e)\n    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n    //\n    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n    JSON_ASSERT(p2 > delta);\n\n    int m = 0;\n    for (;;)\n    {\n        // Invariant:\n        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n        //\n        JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);\n        p2 *= 10;\n        const std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n        const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n        //\n        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        p2 = r;\n        m++;\n        //\n        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n        // Invariant restored.\n\n        // Check if enough digits have been generated.\n        //\n        //      10^-m * p2 * 2^e <= delta * 2^e\n        //              p2 * 2^e <= 10^m * delta * 2^e\n        //                    p2 <= 10^m * delta\n        delta *= 10;\n        dist  *= 10;\n        if (p2 <= delta)\n        {\n            break;\n        }\n    }\n\n    // V = buffer * 10^-m, with M- <= V <= M+.\n\n    decimal_exponent -= m;\n\n    // 1 ulp in the decimal representation is now 10^-m.\n    // Since delta and dist are now scaled by 10^m, we need to do the\n    // same with ulp in order to keep the units in sync.\n    //\n    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n    //\n    const std::uint64_t ten_m = one.f;\n    grisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n    // By construction this algorithm generates the shortest possible decimal\n    // number (Loitsch, Theorem 6.2) which rounds back to w.\n    // For an input number of precision p, at least\n    //\n    //      N = 1 + ceil(p * log_10(2))\n    //\n    // decimal digits are sufficient to identify all binary floating-point\n    // numbers (Matula, \"In-and-Out conversions\").\n    // This implies that the algorithm does not produce more than N decimal\n    // digits.\n    //\n    //      N = 17 for p = 53 (IEEE double precision)\n    //      N = 9  for p = 24 (IEEE single precision)\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline void grisu2(char* buf, int& len, int& decimal_exponent,\n                   diyfp m_minus, diyfp v, diyfp m_plus)\n{\n    JSON_ASSERT(m_plus.e == m_minus.e);\n    JSON_ASSERT(m_plus.e == v.e);\n\n    //  --------(-----------------------+-----------------------)--------    (A)\n    //          m-                      v                       m+\n    //\n    //  --------------------(-----------+-----------------------)--------    (B)\n    //                      m-          v                       m+\n    //\n    // First scale v (and m- and m+) such that the exponent is in the range\n    // [alpha, gamma].\n\n    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n    const diyfp w       = diyfp::mul(v,       c_minus_k);\n    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);\n\n    //  ----(---+---)---------------(---+---)---------------(---+---)----\n    //          w-                      w                       w+\n    //          = c*m-                  = c*v                   = c*m+\n    //\n    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n    // w+ are now off by a small amount.\n    // In fact:\n    //\n    //      w - v * 10^k < 1 ulp\n    //\n    // To account for this inaccuracy, add resp. subtract 1 ulp.\n    //\n    //  --------+---[---------------(---+---)---------------]---+--------\n    //          w-  M-                  w                   M+  w+\n    //\n    // Now any number in [M-, M+] (bounds included) will round to w when input,\n    // regardless of how the input rounding algorithm breaks ties.\n    //\n    // And digit_gen generates the shortest possible such number in [M-, M+].\n    // Note that this does not mean that Grisu2 always generates the shortest\n    // possible number in the interval (m-, m+).\n    const diyfp M_minus(w_minus.f + 1, w_minus.e);\n    const diyfp M_plus (w_plus.f  - 1, w_plus.e );\n\n    decimal_exponent = -cached.k; // = -(-k) = k\n\n    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1)\nvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n{\n    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n                  \"internal error: not enough precision\");\n\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // If the neighbors (and boundaries) of 'value' are always computed for double-precision\n    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n    // decimal representations are not exactly \"short\".\n    //\n    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n    // says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'\n    // does.\n    // On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n    // representation using the corresponding std::from_chars function recovers value exactly\". That\n    // indicates that single precision floating-point numbers should be recovered using\n    // 'std::strtof'.\n    //\n    // NB: If the neighbors are computed for single-precision numbers, there is a single float\n    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n    //     value is off by 1 ulp.\n#if 0\n    const boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n    const boundaries w = compute_boundaries(value);\n#endif\n\n    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n}\n\n/*!\n@brief appends a decimal representation of e to buf\n@return a pointer to the element following the exponent.\n@pre -1000 < e < 1000\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* append_exponent(char* buf, int e)\n{\n    JSON_ASSERT(e > -1000);\n    JSON_ASSERT(e <  1000);\n\n    if (e < 0)\n    {\n        e = -e;\n        *buf++ = '-';\n    }\n    else\n    {\n        *buf++ = '+';\n    }\n\n    auto k = static_cast<std::uint32_t>(e);\n    if (k < 10)\n    {\n        // Always print at least two digits in the exponent.\n        // This is for compatibility with printf(\"%g\").\n        *buf++ = '0';\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else if (k < 100)\n    {\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else\n    {\n        *buf++ = static_cast<char>('0' + k / 100);\n        k %= 100;\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n\n    return buf;\n}\n\n/*!\n@brief prettify v = buf * 10^decimal_exponent\n\nIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\nnotation. Otherwise it will be printed in exponential notation.\n\n@pre min_exp < 0\n@pre max_exp > 0\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* format_buffer(char* buf, int len, int decimal_exponent,\n                           int min_exp, int max_exp)\n{\n    JSON_ASSERT(min_exp < 0);\n    JSON_ASSERT(max_exp > 0);\n\n    const int k = len;\n    const int n = len + decimal_exponent;\n\n    // v = buf * 10^(n-k)\n    // k is the length of the buffer (number of decimal digits)\n    // n is the position of the decimal point relative to the start of the buffer.\n\n    if (k <= n && n <= max_exp)\n    {\n        // digits[000]\n        // len <= max_exp + 2\n\n        std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));\n        // Make it look like a floating-point number (#362, #378)\n        buf[n + 0] = '.';\n        buf[n + 1] = '0';\n        return buf + (static_cast<size_t>(n) + 2);\n    }\n\n    if (0 < n && n <= max_exp)\n    {\n        // dig.its\n        // len <= max_digits10 + 1\n\n        JSON_ASSERT(k > n);\n\n        std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));\n        buf[n] = '.';\n        return buf + (static_cast<size_t>(k) + 1U);\n    }\n\n    if (min_exp < n && n <= 0)\n    {\n        // 0.[000]digits\n        // len <= 2 + (-min_exp - 1) + max_digits10\n\n        std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));\n        buf[0] = '0';\n        buf[1] = '.';\n        std::memset(buf + 2, '0', static_cast<size_t>(-n));\n        return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));\n    }\n\n    if (k == 1)\n    {\n        // dE+123\n        // len <= 1 + 5\n\n        buf += 1;\n    }\n    else\n    {\n        // d.igitsE+123\n        // len <= max_digits10 + 1 + 5\n\n        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);\n        buf[1] = '.';\n        buf += 1 + static_cast<size_t>(k);\n    }\n\n    *buf++ = 'e';\n    return append_exponent(buf, n - 1);\n}\n\n} // namespace dtoa_impl\n\n/*!\n@brief generates a decimal representation of the floating-point number value in [first, last).\n\nThe format of the resulting decimal representation is similar to printf's %g\nformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n@note The buffer must be large enough.\n@note The result is NOT null-terminated.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1, 2)\nJSON_HEDLEY_RETURNS_NON_NULL\nchar* to_chars(char* first, const char* last, FloatType value)\n{\n    static_cast<void>(last); // maybe unused - fix warning\n    JSON_ASSERT(std::isfinite(value));\n\n    // Use signbit(value) instead of (value < 0) since signbit works for -0.\n    if (std::signbit(value))\n    {\n        value = -value;\n        *first++ = '-';\n    }\n\n    if (value == 0) // +-0\n    {\n        *first++ = '0';\n        // Make it look like a floating-point number (#362, #378)\n        *first++ = '.';\n        *first++ = '0';\n        return first;\n    }\n\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n    // Compute v = buffer * 10^decimal_exponent.\n    // The decimal digits are stored in the buffer, which needs to be interpreted\n    // as an unsigned decimal integer.\n    // len is the length of the buffer, i.e. the number of decimal digits.\n    int len = 0;\n    int decimal_exponent = 0;\n    dtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n    JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);\n\n    // Format the buffer like printf(\"%.*g\", prec, value)\n    constexpr int kMinExp = -4;\n    // Use digits10 here to increase compatibility with version 2.\n    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n    JSON_ASSERT(last - first >= kMaxExp + 2);\n    JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n}\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// serialization //\n///////////////////\n\n/// how to treat decoding errors\nenum class error_handler_t\n{\n    strict,  ///< throw a type_error exception in case of invalid UTF-8\n    replace, ///< replace invalid UTF-8 sequences with U+FFFD\n    ignore   ///< ignore invalid UTF-8 sequences\n};\n\ntemplate<typename BasicJsonType>\nclass serializer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using binary_char_t = typename BasicJsonType::binary_t::value_type;\n    static constexpr std::uint8_t UTF8_ACCEPT = 0;\n    static constexpr std::uint8_t UTF8_REJECT = 1;\n\n  public:\n    /*!\n    @param[in] s  output stream to serialize to\n    @param[in] ichar  indentation character to use\n    @param[in] error_handler_  how to react on decoding errors\n    */\n    serializer(output_adapter_t<char> s, const char ichar,\n               error_handler_t error_handler_ = error_handler_t::strict)\n        : o(std::move(s))\n        , loc(std::localeconv())\n        , thousands_sep(loc->thousands_sep == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))\n        , decimal_point(loc->decimal_point == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))\n        , indent_char(ichar)\n        , indent_string(512, indent_char)\n        , error_handler(error_handler_)\n    {}\n\n    // delete because of pointer members\n    serializer(const serializer&) = delete;\n    serializer& operator=(const serializer&) = delete;\n    serializer(serializer&&) = delete;\n    serializer& operator=(serializer&&) = delete;\n    ~serializer() = default;\n\n    /*!\n    @brief internal implementation of the serialization function\n\n    This function is called by the public member function dump and organizes\n    the serialization internally. The indentation level is propagated as\n    additional parameter. In case of arrays and objects, the function is\n    called recursively.\n\n    - strings and object keys are escaped using `escape_string()`\n    - integer numbers are converted implicitly via `operator<<`\n    - floating-point numbers are converted to a string using `\"%g\"` format\n    - binary values are serialized as objects containing the subtype and the\n      byte array\n\n    @param[in] val               value to serialize\n    @param[in] pretty_print      whether the output shall be pretty-printed\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] indent_step       the indent level\n    @param[in] current_indent    the current indent level (only used internally)\n    */\n    void dump(const BasicJsonType& val,\n              const bool pretty_print,\n              const bool ensure_ascii,\n              const unsigned int indent_step,\n              const unsigned int current_indent = 0)\n    {\n        switch (val.m_type)\n        {\n            case value_t::object:\n            {\n                if (val.m_value.object->empty())\n                {\n                    o->write_characters(\"{}\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\": \", 3);\n                        dump(i->second, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\": \", 3);\n                    dump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_character('{');\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\":\", 2);\n                        dump(i->second, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\":\", 2);\n                    dump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character('}');\n                }\n\n                return;\n            }\n\n            case value_t::array:\n            {\n                if (val.m_value.array->empty())\n                {\n                    o->write_characters(\"[]\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"[\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        dump(*i, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_value.array->empty());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character(']');\n                }\n                else\n                {\n                    o->write_character('[');\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        dump(*i, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_value.array->empty());\n                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character(']');\n                }\n\n                return;\n            }\n\n            case value_t::string:\n            {\n                o->write_character('\\\"');\n                dump_escaped(*val.m_value.string, ensure_ascii);\n                o->write_character('\\\"');\n                return;\n            }\n\n            case value_t::binary:\n            {\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"bytes\\\": [\", 10);\n\n                    if (!val.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_value.binary->cbegin();\n                                i != val.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_characters(\", \", 2);\n                        }\n                        dump_integer(val.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\n\", 3);\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"subtype\\\": \", 11);\n                    if (val.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_value.binary->subtype());\n                    }\n                    else\n                    {\n                        o->write_characters(\"null\", 4);\n                    }\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_characters(\"{\\\"bytes\\\":[\", 10);\n\n                    if (!val.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_value.binary->cbegin();\n                                i != val.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_character(',');\n                        }\n                        dump_integer(val.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\\"subtype\\\":\", 12);\n                    if (val.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_value.binary->subtype());\n                        o->write_character('}');\n                    }\n                    else\n                    {\n                        o->write_characters(\"null}\", 5);\n                    }\n                }\n                return;\n            }\n\n            case value_t::boolean:\n            {\n                if (val.m_value.boolean)\n                {\n                    o->write_characters(\"true\", 4);\n                }\n                else\n                {\n                    o->write_characters(\"false\", 5);\n                }\n                return;\n            }\n\n            case value_t::number_integer:\n            {\n                dump_integer(val.m_value.number_integer);\n                return;\n            }\n\n            case value_t::number_unsigned:\n            {\n                dump_integer(val.m_value.number_unsigned);\n                return;\n            }\n\n            case value_t::number_float:\n            {\n                dump_float(val.m_value.number_float);\n                return;\n            }\n\n            case value_t::discarded:\n            {\n                o->write_characters(\"<discarded>\", 11);\n                return;\n            }\n\n            case value_t::null:\n            {\n                o->write_characters(\"null\", 4);\n                return;\n            }\n\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief dump escaped string\n\n    Escape a string by replacing certain special characters by a sequence of an\n    escape character (backslash) and another character and other control\n    characters by a sequence of \"\\u\" followed by a four-digit hex\n    representation. The escaped string is written to output stream @a o.\n\n    @param[in] s  the string to escape\n    @param[in] ensure_ascii  whether to escape non-ASCII characters with\n                             \\uXXXX sequences\n\n    @complexity Linear in the length of string @a s.\n    */\n    void dump_escaped(const string_t& s, const bool ensure_ascii)\n    {\n        std::uint32_t codepoint;\n        std::uint8_t state = UTF8_ACCEPT;\n        std::size_t bytes = 0;  // number of bytes written to string_buffer\n\n        // number of bytes written at the point of the last valid byte\n        std::size_t bytes_after_last_accept = 0;\n        std::size_t undumped_chars = 0;\n\n        for (std::size_t i = 0; i < s.size(); ++i)\n        {\n            const auto byte = static_cast<uint8_t>(s[i]);\n\n            switch (decode(state, codepoint, byte))\n            {\n                case UTF8_ACCEPT:  // decode found a new code point\n                {\n                    switch (codepoint)\n                    {\n                        case 0x08: // backspace\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'b';\n                            break;\n                        }\n\n                        case 0x09: // horizontal tab\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 't';\n                            break;\n                        }\n\n                        case 0x0A: // newline\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'n';\n                            break;\n                        }\n\n                        case 0x0C: // formfeed\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'f';\n                            break;\n                        }\n\n                        case 0x0D: // carriage return\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'r';\n                            break;\n                        }\n\n                        case 0x22: // quotation mark\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\"';\n                            break;\n                        }\n\n                        case 0x5C: // reverse solidus\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\\';\n                            break;\n                        }\n\n                        default:\n                        {\n                            // escape control characters (0x00..0x1F) or, if\n                            // ensure_ascii parameter is used, non-ASCII characters\n                            if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))\n                            {\n                                if (codepoint <= 0xFFFF)\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n                                                    static_cast<std::uint16_t>(codepoint));\n                                    bytes += 6;\n                                }\n                                else\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n                                                    static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),\n                                                    static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));\n                                    bytes += 12;\n                                }\n                            }\n                            else\n                            {\n                                // copy byte to buffer (all previous bytes\n                                // been copied have in default case above)\n                                string_buffer[bytes++] = s[i];\n                            }\n                            break;\n                        }\n                    }\n\n                    // write buffer and reset index; there must be 13 bytes\n                    // left, as this is the maximal number of bytes to be\n                    // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                    if (string_buffer.size() - bytes < 13)\n                    {\n                        o->write_characters(string_buffer.data(), bytes);\n                        bytes = 0;\n                    }\n\n                    // remember the byte position of this accept\n                    bytes_after_last_accept = bytes;\n                    undumped_chars = 0;\n                    break;\n                }\n\n                case UTF8_REJECT:  // decode found invalid UTF-8 byte\n                {\n                    switch (error_handler)\n                    {\n                        case error_handler_t::strict:\n                        {\n                            std::string sn(3, '\\0');\n                            (std::snprintf)(&sn[0], sn.size(), \"%.2X\", byte);\n                            JSON_THROW(type_error::create(316, \"invalid UTF-8 byte at index \" + std::to_string(i) + \": 0x\" + sn));\n                        }\n\n                        case error_handler_t::ignore:\n                        case error_handler_t::replace:\n                        {\n                            // in case we saw this character the first time, we\n                            // would like to read it again, because the byte\n                            // may be OK for itself, but just not OK for the\n                            // previous sequence\n                            if (undumped_chars > 0)\n                            {\n                                --i;\n                            }\n\n                            // reset length buffer to the last accepted index;\n                            // thus removing/ignoring the invalid characters\n                            bytes = bytes_after_last_accept;\n\n                            if (error_handler == error_handler_t::replace)\n                            {\n                                // add a replacement character\n                                if (ensure_ascii)\n                                {\n                                    string_buffer[bytes++] = '\\\\';\n                                    string_buffer[bytes++] = 'u';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'd';\n                                }\n                                else\n                                {\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n                                }\n\n                                // write buffer and reset index; there must be 13 bytes\n                                // left, as this is the maximal number of bytes to be\n                                // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                                if (string_buffer.size() - bytes < 13)\n                                {\n                                    o->write_characters(string_buffer.data(), bytes);\n                                    bytes = 0;\n                                }\n\n                                bytes_after_last_accept = bytes;\n                            }\n\n                            undumped_chars = 0;\n\n                            // continue processing the string\n                            state = UTF8_ACCEPT;\n                            break;\n                        }\n\n                        default:            // LCOV_EXCL_LINE\n                            JSON_ASSERT(false);  // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n\n                default:  // decode found yet incomplete multi-byte code point\n                {\n                    if (!ensure_ascii)\n                    {\n                        // code point will not be escaped - copy byte to buffer\n                        string_buffer[bytes++] = s[i];\n                    }\n                    ++undumped_chars;\n                    break;\n                }\n            }\n        }\n\n        // we finished processing the string\n        if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))\n        {\n            // write buffer\n            if (bytes > 0)\n            {\n                o->write_characters(string_buffer.data(), bytes);\n            }\n        }\n        else\n        {\n            // we finish reading, but do not accept: string was incomplete\n            switch (error_handler)\n            {\n                case error_handler_t::strict:\n                {\n                    std::string sn(3, '\\0');\n                    (std::snprintf)(&sn[0], sn.size(), \"%.2X\", static_cast<std::uint8_t>(s.back()));\n                    JSON_THROW(type_error::create(316, \"incomplete UTF-8 string; last byte: 0x\" + sn));\n                }\n\n                case error_handler_t::ignore:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    break;\n                }\n\n                case error_handler_t::replace:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    // add a replacement character\n                    if (ensure_ascii)\n                    {\n                        o->write_characters(\"\\\\ufffd\", 6);\n                    }\n                    else\n                    {\n                        o->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n                    }\n                    break;\n                }\n\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false);  // LCOV_EXCL_LINE\n            }\n        }\n    }\n\n  private:\n    /*!\n    @brief count digits\n\n    Count the number of decimal (base 10) digits for an input unsigned integer.\n\n    @param[in] x  unsigned integer number to count its digits\n    @return    number of decimal digits\n    */\n    inline unsigned int count_digits(number_unsigned_t x) noexcept\n    {\n        unsigned int n_digits = 1;\n        for (;;)\n        {\n            if (x < 10)\n            {\n                return n_digits;\n            }\n            if (x < 100)\n            {\n                return n_digits + 1;\n            }\n            if (x < 1000)\n            {\n                return n_digits + 2;\n            }\n            if (x < 10000)\n            {\n                return n_digits + 3;\n            }\n            x = x / 10000u;\n            n_digits += 4;\n        }\n    }\n\n    /*!\n    @brief dump an integer\n\n    Dump a given integer to output stream @a o. Works internally with\n    @a number_buffer.\n\n    @param[in] x  integer number (signed or unsigned) to dump\n    @tparam NumberType either @a number_integer_t or @a number_unsigned_t\n    */\n    template < typename NumberType, detail::enable_if_t <\n                   std::is_same<NumberType, number_unsigned_t>::value ||\n                   std::is_same<NumberType, number_integer_t>::value ||\n                   std::is_same<NumberType, binary_char_t>::value,\n                   int > = 0 >\n    void dump_integer(NumberType x)\n    {\n        static constexpr std::array<std::array<char, 2>, 100> digits_to_99\n        {\n            {\n                {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},\n                {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},\n                {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},\n                {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},\n                {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},\n                {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},\n                {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},\n                {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},\n                {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},\n                {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},\n            }\n        };\n\n        // special case for \"0\"\n        if (x == 0)\n        {\n            o->write_character('0');\n            return;\n        }\n\n        // use a pointer to fill the buffer\n        auto buffer_ptr = number_buffer.begin();\n\n        const bool is_negative = std::is_same<NumberType, number_integer_t>::value && !(x >= 0); // see issue #755\n        number_unsigned_t abs_value;\n\n        unsigned int n_chars;\n\n        if (is_negative)\n        {\n            *buffer_ptr = '-';\n            abs_value = remove_sign(static_cast<number_integer_t>(x));\n\n            // account one more byte for the minus sign\n            n_chars = 1 + count_digits(abs_value);\n        }\n        else\n        {\n            abs_value = static_cast<number_unsigned_t>(x);\n            n_chars = count_digits(abs_value);\n        }\n\n        // spare 1 byte for '\\0'\n        JSON_ASSERT(n_chars < number_buffer.size() - 1);\n\n        // jump to the end to generate the string from backward\n        // so we later avoid reversing the result\n        buffer_ptr += n_chars;\n\n        // Fast int2ascii implementation inspired by \"Fastware\" talk by Andrei Alexandrescu\n        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg\n        while (abs_value >= 100)\n        {\n            const auto digits_index = static_cast<unsigned>((abs_value % 100));\n            abs_value /= 100;\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n\n        if (abs_value >= 10)\n        {\n            const auto digits_index = static_cast<unsigned>(abs_value);\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n        else\n        {\n            *(--buffer_ptr) = static_cast<char>('0' + abs_value);\n        }\n\n        o->write_characters(number_buffer.data(), n_chars);\n    }\n\n    /*!\n    @brief dump a floating-point number\n\n    Dump a given floating-point number to output stream @a o. Works internally\n    with @a number_buffer.\n\n    @param[in] x  floating-point number to dump\n    */\n    void dump_float(number_float_t x)\n    {\n        // NaN / inf\n        if (!std::isfinite(x))\n        {\n            o->write_characters(\"null\", 4);\n            return;\n        }\n\n        // If number_float_t is an IEEE-754 single or double precision number,\n        // use the Grisu2 algorithm to produce short numbers which are\n        // guaranteed to round-trip, using strtof and strtod, resp.\n        //\n        // NB: The test below works if <long double> == <double>.\n        static constexpr bool is_ieee_single_or_double\n            = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||\n              (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n    }\n\n    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n    {\n        char* begin = number_buffer.data();\n        char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n        o->write_characters(begin, static_cast<size_t>(end - begin));\n    }\n\n    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n    {\n        // get number of digits for a float -> text -> float round-trip\n        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n        // the actual conversion\n        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n        // negative value indicates an error\n        JSON_ASSERT(len > 0);\n        // check if buffer was large enough\n        JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());\n\n        // erase thousands separator\n        if (thousands_sep != '\\0')\n        {\n            const auto end = std::remove(number_buffer.begin(),\n                                         number_buffer.begin() + len, thousands_sep);\n            std::fill(end, number_buffer.end(), '\\0');\n            JSON_ASSERT((end - number_buffer.begin()) <= len);\n            len = (end - number_buffer.begin());\n        }\n\n        // convert decimal point to '.'\n        if (decimal_point != '\\0' && decimal_point != '.')\n        {\n            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n            if (dec_pos != number_buffer.end())\n            {\n                *dec_pos = '.';\n            }\n        }\n\n        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n        // determine if need to append \".0\"\n        const bool value_is_int_like =\n            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n                         [](char c)\n        {\n            return c == '.' || c == 'e';\n        });\n\n        if (value_is_int_like)\n        {\n            o->write_characters(\".0\", 2);\n        }\n    }\n\n    /*!\n    @brief check whether a string is UTF-8 encoded\n\n    The function checks each byte of a string whether it is UTF-8 encoded. The\n    result of the check is stored in the @a state parameter. The function must\n    be called initially with state 0 (accept). State 1 means the string must\n    be rejected, because the current byte is not allowed. If the string is\n    completely processed, but the state is non-zero, the string ended\n    prematurely; that is, the last byte indicated more bytes should have\n    followed.\n\n    @param[in,out] state  the state of the decoding\n    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n    @param[in] byte       next byte to decode\n    @return               new state\n\n    @note The function has been edited: a std::array is used.\n\n    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n    */\n    static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept\n    {\n        static const std::array<std::uint8_t, 400> utf8d =\n        {\n            {\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n            }\n        };\n\n        JSON_ASSERT(byte < utf8d.size());\n        const std::uint8_t type = utf8d[byte];\n\n        codep = (state != UTF8_ACCEPT)\n                ? (byte & 0x3fu) | (codep << 6u)\n                : (0xFFu >> type) & (byte);\n\n        std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);\n        JSON_ASSERT(index < 400);\n        state = utf8d[index];\n        return state;\n    }\n\n    /*\n     * Overload to make the compiler happy while it is instantiating\n     * dump_integer for number_unsigned_t.\n     * Must never be called.\n     */\n    number_unsigned_t remove_sign(number_unsigned_t x)\n    {\n        JSON_ASSERT(false); // LCOV_EXCL_LINE\n        return x; // LCOV_EXCL_LINE\n    }\n\n    /*\n     * Helper function for dump_integer\n     *\n     * This function takes a negative signed integer and returns its absolute\n     * value as unsigned integer. The plus/minus shuffling is necessary as we can\n     * not directly remove the sign of an arbitrary signed integer as the\n     * absolute values of INT_MIN and INT_MAX are usually not the same. See\n     * #1708 for details.\n     */\n    inline number_unsigned_t remove_sign(number_integer_t x) noexcept\n    {\n        JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());\n        return static_cast<number_unsigned_t>(-(x + 1)) + 1;\n    }\n\n  private:\n    /// the output of the serializer\n    output_adapter_t<char> o = nullptr;\n\n    /// a (hopefully) large enough character buffer\n    std::array<char, 64> number_buffer{{}};\n\n    /// the locale\n    const std::lconv* loc = nullptr;\n    /// the locale's thousand separator character\n    const char thousands_sep = '\\0';\n    /// the locale's decimal point character\n    const char decimal_point = '\\0';\n\n    /// string buffer\n    std::array<char, 512> string_buffer{{}};\n\n    /// the indentation character\n    const char indent_char;\n    /// the indentation string\n    string_t indent_string;\n\n    /// error_handler how to react on decoding errors\n    const error_handler_t error_handler;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n\n// #include <nlohmann/ordered_map.hpp>\n\n\n#include <functional> // less\n#include <memory> // allocator\n#include <utility> // pair\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n\n/// ordered_map: a minimal map-like container that preserves insertion order\n/// for use within nlohmann::basic_json<ordered_map>\ntemplate <class Key, class T, class IgnoredLess = std::less<Key>,\n          class Allocator = std::allocator<std::pair<const Key, T>>>\n                  struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>\n{\n    using key_type = Key;\n    using mapped_type = T;\n    using Container = std::vector<std::pair<const Key, T>, Allocator>;\n    using typename Container::iterator;\n    using typename Container::const_iterator;\n    using typename Container::size_type;\n    using typename Container::value_type;\n\n    // Explicit constructors instead of `using Container::Container`\n    // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)\n    ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}\n    template <class It>\n    ordered_map(It first, It last, const Allocator& alloc = Allocator())\n        : Container{first, last, alloc} {}\n    ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )\n        : Container{init, alloc} {}\n\n    std::pair<iterator, bool> emplace(const key_type& key, T&& t)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return {it, false};\n            }\n        }\n        Container::emplace_back(key, t);\n        return {--this->end(), true};\n    }\n\n    T& operator[](const Key& key)\n    {\n        return emplace(key, T{}).first->second;\n    }\n\n    const T& operator[](const Key& key) const\n    {\n        return at(key);\n    }\n\n    T& at(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    const T& at(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    size_type erase(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                // Since we cannot move const Keys, re-construct them in place\n                for (auto next = it; ++next != this->end(); ++it)\n                {\n                    it->~value_type(); // Destroy but keep allocation\n                    new (&*it) value_type{std::move(*next)};\n                }\n                Container::pop_back();\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator erase(iterator pos)\n    {\n        auto it = pos;\n\n        // Since we cannot move const Keys, re-construct them in place\n        for (auto next = it; ++next != this->end(); ++it)\n        {\n            it->~value_type(); // Destroy but keep allocation\n            new (&*it) value_type{std::move(*next)};\n        }\n        Container::pop_back();\n        return pos;\n    }\n\n    size_type count(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator find(const Key& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    const_iterator find(const Key& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == key)\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    std::pair<iterator, bool> insert( value_type&& value )\n    {\n        return emplace(value.first, std::move(value.second));\n    }\n\n    std::pair<iterator, bool> insert( const value_type& value )\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (it->first == value.first)\n            {\n                return {it, false};\n            }\n        }\n        Container::push_back(value);\n        return {--this->end(), true};\n    }\n\n    template<typename InputIt>\n    using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,\n            std::input_iterator_tag>::value>::type;\n\n    template<typename InputIt, typename = require_input_iter<InputIt>>\n    void insert(InputIt first, InputIt last)\n    {\n        for (auto it = first; it != last; ++it)\n        {\n            insert(*it);\n        }\n    }\n};\n\n}  // namespace nlohmann\n\n\n#if defined(JSON_HAS_CPP_17)\n    #include <string_view>\n#endif\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\n/*!\n@brief a class to store JSON values\n\n@tparam ObjectType type for JSON objects (`std::map` by default; will be used\nin @ref object_t)\n@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used\nin @ref array_t)\n@tparam StringType type for JSON strings and object keys (`std::string` by\ndefault; will be used in @ref string_t)\n@tparam BooleanType type for JSON booleans (`bool` by default; will be used\nin @ref boolean_t)\n@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by\ndefault; will be used in @ref number_integer_t)\n@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c\n`uint64_t` by default; will be used in @ref number_unsigned_t)\n@tparam NumberFloatType type for JSON floating-point numbers (`double` by\ndefault; will be used in @ref number_float_t)\n@tparam BinaryType type for packed binary data for compatibility with binary\nserialization formats (`std::vector<std::uint8_t>` by default; will be used in\n@ref binary_t)\n@tparam AllocatorType type of the allocator to use (`std::allocator` by\ndefault)\n@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`\nand `from_json()` (@ref adl_serializer by default)\n\n@requirement The class satisfies the following concept requirements:\n- Basic\n - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n   JSON values can be default constructed. The result will be a JSON null\n   value.\n - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):\n   A JSON value can be constructed from an rvalue argument.\n - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):\n   A JSON value can be copy-constructed from an lvalue expression.\n - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):\n   A JSON value van be assigned from an rvalue argument.\n - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):\n   A JSON value can be copy-assigned from an lvalue expression.\n - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):\n   JSON values can be destructed.\n- Layout\n - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):\n   JSON values have\n   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):\n   All non-static data members are private and standard layout types, the\n   class has no virtual functions or (virtual) base classes.\n- Library-wide\n - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):\n   JSON values can be compared with `==`, see @ref\n   operator==(const_reference,const_reference).\n - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n   JSON values can be compared with `<`, see @ref\n   operator<(const_reference,const_reference).\n - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):\n   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of\n   other compatible types, using unqualified function call @ref swap().\n - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):\n   JSON values can be compared against `std::nullptr_t` objects which are used\n   to model the `null` value.\n- Container\n - [Container](https://en.cppreference.com/w/cpp/named_req/Container):\n   JSON values can be used like STL containers and provide iterator access.\n - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);\n   JSON values can be used like STL containers and provide reverse iterator\n   access.\n\n@invariant The member variables @a m_value and @a m_type have the following\nrelationship:\n- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n- If `m_type == value_t::string`, then `m_value.string != nullptr`.\nThe invariants are checked by member function assert_invariant().\n\n@internal\n@note ObjectType trick from https://stackoverflow.com/a/9860911\n@endinternal\n\n@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange\nFormat](http://rfc7159.net/rfc7159)\n\n@since version 1.0.0\n\n@nosubgrouping\n*/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nclass basic_json\n{\n  private:\n    template<detail::value_t> friend struct detail::external_constructor;\n    friend ::nlohmann::json_pointer<basic_json>;\n\n    template<typename BasicJsonType, typename InputType>\n    friend class ::nlohmann::detail::parser;\n    friend ::nlohmann::detail::serializer<basic_json>;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::iter_impl;\n    template<typename BasicJsonType, typename CharType>\n    friend class ::nlohmann::detail::binary_writer;\n    template<typename BasicJsonType, typename InputType, typename SAX>\n    friend class ::nlohmann::detail::binary_reader;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_parser;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_callback_parser;\n\n    /// workaround type for MSVC\n    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    // convenience aliases for types residing in namespace detail;\n    using lexer = ::nlohmann::detail::lexer_base<basic_json>;\n\n    template<typename InputAdapterType>\n    static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(\n        InputAdapterType adapter,\n        detail::parser_callback_t<basic_json>cb = nullptr,\n        const bool allow_exceptions = true,\n        const bool ignore_comments = false\n                                 )\n    {\n        return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),\n                std::move(cb), allow_exceptions, ignore_comments);\n    }\n\n  private:\n    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n    template<typename BasicJsonType>\n    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n    template<typename BasicJsonType>\n    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n    template<typename Iterator>\n    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n    template<typename CharType>\n    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n    template<typename InputType>\n    using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;\n    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    using serializer = ::nlohmann::detail::serializer<basic_json>;\n\n  public:\n    using value_t = detail::value_t;\n    /// JSON Pointer, see @ref nlohmann::json_pointer\n    using json_pointer = ::nlohmann::json_pointer<basic_json>;\n    template<typename T, typename SFINAE>\n    using json_serializer = JSONSerializer<T, SFINAE>;\n    /// how to treat decoding errors\n    using error_handler_t = detail::error_handler_t;\n    /// how to treat CBOR tags\n    using cbor_tag_handler_t = detail::cbor_tag_handler_t;\n    /// helper type for initializer lists of basic_json values\n    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n    using input_format_t = detail::input_format_t;\n    /// SAX interface type, see @ref nlohmann::json_sax\n    using json_sax_t = json_sax<basic_json>;\n\n    ////////////////\n    // exceptions //\n    ////////////////\n\n    /// @name exceptions\n    /// Classes to implement user-defined exceptions.\n    /// @{\n\n    /// @copydoc detail::exception\n    using exception = detail::exception;\n    /// @copydoc detail::parse_error\n    using parse_error = detail::parse_error;\n    /// @copydoc detail::invalid_iterator\n    using invalid_iterator = detail::invalid_iterator;\n    /// @copydoc detail::type_error\n    using type_error = detail::type_error;\n    /// @copydoc detail::out_of_range\n    using out_of_range = detail::out_of_range;\n    /// @copydoc detail::other_error\n    using other_error = detail::other_error;\n\n    /// @}\n\n\n    /////////////////////\n    // container types //\n    /////////////////////\n\n    /// @name container types\n    /// The canonic container types to use @ref basic_json like any other STL\n    /// container.\n    /// @{\n\n    /// the type of elements in a basic_json container\n    using value_type = basic_json;\n\n    /// the type of an element reference\n    using reference = value_type&;\n    /// the type of an element const reference\n    using const_reference = const value_type&;\n\n    /// a type to represent differences between iterators\n    using difference_type = std::ptrdiff_t;\n    /// a type to represent container sizes\n    using size_type = std::size_t;\n\n    /// the allocator type\n    using allocator_type = AllocatorType<basic_json>;\n\n    /// the type of an element pointer\n    using pointer = typename std::allocator_traits<allocator_type>::pointer;\n    /// the type of an element const pointer\n    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n    /// an iterator for a basic_json container\n    using iterator = iter_impl<basic_json>;\n    /// a const iterator for a basic_json container\n    using const_iterator = iter_impl<const basic_json>;\n    /// a reverse iterator for a basic_json container\n    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n    /// a const reverse iterator for a basic_json container\n    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n    /// @}\n\n\n    /*!\n    @brief returns the allocator associated with the container\n    */\n    static allocator_type get_allocator()\n    {\n        return allocator_type();\n    }\n\n    /*!\n    @brief returns version information on the library\n\n    This function returns a JSON object with information about the library,\n    including the version number and information on the platform and compiler.\n\n    @return JSON object holding version information\n    key         | description\n    ----------- | ---------------\n    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).\n    `copyright` | The copyright line for the library as string.\n    `name`      | The name of the library as string.\n    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.\n    `url`       | The URL of the project as string.\n    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).\n\n    @liveexample{The following code shows an example output of the `meta()`\n    function.,meta}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @complexity Constant.\n\n    @since 2.1.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json meta()\n    {\n        basic_json result;\n\n        result[\"copyright\"] = \"(C) 2013-2021 Niels Lohmann\";\n        result[\"name\"] = \"JSON for Modern C++\";\n        result[\"url\"] = \"https://github.com/nlohmann/json\";\n        result[\"version\"][\"string\"] =\n            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_PATCH);\n        result[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n        result[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n        result[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n        result[\"platform\"] = \"win32\";\n#elif defined __linux__\n        result[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n        result[\"platform\"] = \"apple\";\n#elif defined __unix__\n        result[\"platform\"] = \"unix\";\n#else\n        result[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n        result[\"compiler\"] = {{\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER}};\n#elif defined(__clang__)\n        result[\"compiler\"] = {{\"family\", \"clang\"}, {\"version\", __clang_version__}};\n#elif defined(__GNUC__) || defined(__GNUG__)\n        result[\"compiler\"] = {{\"family\", \"gcc\"}, {\"version\", std::to_string(__GNUC__) + \".\" + std::to_string(__GNUC_MINOR__) + \".\" + std::to_string(__GNUC_PATCHLEVEL__)}};\n#elif defined(__HP_cc) || defined(__HP_aCC)\n        result[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n        result[\"compiler\"] = {{\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__}};\n#elif defined(_MSC_VER)\n        result[\"compiler\"] = {{\"family\", \"msvc\"}, {\"version\", _MSC_VER}};\n#elif defined(__PGI)\n        result[\"compiler\"] = {{\"family\", \"pgcpp\"}, {\"version\", __PGI}};\n#elif defined(__SUNPRO_CC)\n        result[\"compiler\"] = {{\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC}};\n#else\n        result[\"compiler\"] = {{\"family\", \"unknown\"}, {\"version\", \"unknown\"}};\n#endif\n\n#ifdef __cplusplus\n        result[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n        result[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n        return result;\n    }\n\n\n    ///////////////////////////\n    // JSON value data types //\n    ///////////////////////////\n\n    /// @name JSON value data types\n    /// The data types to store a JSON value. These types are derived from\n    /// the template arguments passed to class @ref basic_json.\n    /// @{\n\n#if defined(JSON_HAS_CPP_14)\n    // Use transparent comparator if possible, combined with perfect forwarding\n    // on find() and count() calls prevents unnecessary string construction.\n    using object_comparator_t = std::less<>;\n#else\n    using object_comparator_t = std::less<StringType>;\n#endif\n\n    /*!\n    @brief a type for an object\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:\n    > An object is an unordered collection of zero or more name/value pairs,\n    > where a name is a string and a value is a string, number, boolean, null,\n    > object, or array.\n\n    To store objects in C++, a type is defined by the template parameters\n    described below.\n\n    @tparam ObjectType  the container to store objects (e.g., `std::map` or\n    `std::unordered_map`)\n    @tparam StringType the type of the keys or names (e.g., `std::string`).\n    The comparison function `std::less<StringType>` is used to order elements\n    inside the container.\n    @tparam AllocatorType the allocator to use for objects (e.g.,\n    `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ObjectType (`std::map`), @a StringType\n    (`std::string`), and @a AllocatorType (`std::allocator`), the default\n    value for @a object_t is:\n\n    @code {.cpp}\n    std::map<\n      std::string, // key_type\n      basic_json, // value_type\n      std::less<std::string>, // key_compare\n      std::allocator<std::pair<const std::string, basic_json>> // allocator_type\n    >\n    @endcode\n\n    #### Behavior\n\n    The choice of @a object_t influences the behavior of the JSON class. With\n    the default type, objects have the following behavior:\n\n    - When all names are unique, objects will be interoperable in the sense\n      that all software implementations receiving that object will agree on\n      the name-value mappings.\n    - When the names within an object are not unique, it is unspecified which\n      one of the values for a given key will be chosen. For instance,\n      `{\"key\": 2, \"key\": 1}` could be equal to either `{\"key\": 1}` or\n      `{\"key\": 2}`.\n    - Internally, name/value pairs are stored in lexicographical order of the\n      names. Objects will also be serialized (see @ref dump) in this order.\n      For instance, `{\"b\": 1, \"a\": 2}` and `{\"a\": 2, \"b\": 1}` will be stored\n      and serialized as `{\"a\": 2, \"b\": 1}`.\n    - When comparing objects, the order of the name/value pairs is irrelevant.\n      This makes objects interoperable in the sense that they will not be\n      affected by these differences. For instance, `{\"b\": 1, \"a\": 2}` and\n      `{\"a\": 2, \"b\": 1}` will be treated as equal.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the object's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON object.\n\n    #### Storage\n\n    Objects are stored as pointers in a @ref basic_json type. That is, for any\n    access to object values, a pointer of type `object_t*` must be\n    dereferenced.\n\n    @sa @ref array_t -- type for an array value\n\n    @since version 1.0.0\n\n    @note The order name/value pairs are added to the object is *not*\n    preserved by the library. Therefore, iterating an object may return\n    name/value pairs in a different order than they were originally stored. In\n    fact, keys will be traversed in alphabetical order as `std::map` with\n    `std::less` is used by default. Please note this behavior conforms to [RFC\n    7159](http://rfc7159.net/rfc7159), because any order implements the\n    specified \"unordered\" nature of JSON objects.\n    */\n    using object_t = ObjectType<StringType,\n          basic_json,\n          object_comparator_t,\n          AllocatorType<std::pair<const StringType,\n          basic_json>>>;\n\n    /*!\n    @brief a type for an array\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:\n    > An array is an ordered sequence of zero or more values.\n\n    To store objects in C++, a type is defined by the template parameters\n    explained below.\n\n    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or\n    `std::list`)\n    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ArrayType (`std::vector`) and @a\n    AllocatorType (`std::allocator`), the default value for @a array_t is:\n\n    @code {.cpp}\n    std::vector<\n      basic_json, // value_type\n      std::allocator<basic_json> // allocator_type\n    >\n    @endcode\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the array's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON array.\n\n    #### Storage\n\n    Arrays are stored as pointers in a @ref basic_json type. That is, for any\n    access to array values, a pointer of type `array_t*` must be dereferenced.\n\n    @sa @ref object_t -- type for an object value\n\n    @since version 1.0.0\n    */\n    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n    /*!\n    @brief a type for a string\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:\n    > A string is a sequence of zero or more Unicode characters.\n\n    To store objects in C++, a type is defined by the template parameter\n    described below. Unicode values are split by the JSON class into\n    byte-sized characters during deserialization.\n\n    @tparam StringType  the container to store strings (e.g., `std::string`).\n    Note this container is used for keys/names in objects, see @ref object_t.\n\n    #### Default type\n\n    With the default values for @a StringType (`std::string`), the default\n    value for @a string_t is:\n\n    @code {.cpp}\n    std::string\n    @endcode\n\n    #### Encoding\n\n    Strings are stored in UTF-8 encoding. Therefore, functions like\n    `std::string::size()` or `std::string::length()` return the number of\n    bytes in the string rather than the number of characters or glyphs.\n\n    #### String comparison\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > Software implementations are typically required to test names of object\n    > members for equality. Implementations that transform the textual\n    > representation into sequences of Unicode code units and then perform the\n    > comparison numerically, code unit by code unit, are interoperable in the\n    > sense that implementations will agree in all cases on equality or\n    > inequality of two strings. For example, implementations that compare\n    > strings with escaped characters unconverted may incorrectly find that\n    > `\"a\\\\b\"` and `\"a\\u005Cb\"` are not equal.\n\n    This implementation is interoperable as it does compare strings code unit\n    by code unit.\n\n    #### Storage\n\n    String values are stored as pointers in a @ref basic_json type. That is,\n    for any access to string values, a pointer of type `string_t*` must be\n    dereferenced.\n\n    @since version 1.0.0\n    */\n    using string_t = StringType;\n\n    /*!\n    @brief a type for a boolean\n\n    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a\n    type which differentiates the two literals `true` and `false`.\n\n    To store objects in C++, a type is defined by the template parameter @a\n    BooleanType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a BooleanType (`bool`), the default value for\n    @a boolean_t is:\n\n    @code {.cpp}\n    bool\n    @endcode\n\n    #### Storage\n\n    Boolean values are stored directly inside a @ref basic_json type.\n\n    @since version 1.0.0\n    */\n    using boolean_t = BooleanType;\n\n    /*!\n    @brief a type for a number (integer)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store integer numbers in C++, a type is defined by the template\n    parameter @a NumberIntegerType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberIntegerType (`int64_t`), the default\n    value for @a number_integer_t is:\n\n    @code {.cpp}\n    int64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number\n    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers\n    that are out of range will yield over/underflow when used in a\n    constructor. During deserialization, too large or small integer numbers\n    will be automatically be stored as @ref number_unsigned_t or @ref\n    number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange of the exactly supported range [INT64_MIN,\n    INT64_MAX], this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_integer_t = NumberIntegerType;\n\n    /*!\n    @brief a type for a number (unsigned)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store unsigned integer numbers in C++, a type is defined by the\n    template parameter @a NumberUnsignedType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberUnsignedType (`uint64_t`), the\n    default value for @a number_unsigned_t is:\n\n    @code {.cpp}\n    uint64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer\n    number that can be stored is `0`. Integer numbers that are out of range\n    will yield over/underflow when used in a constructor. During\n    deserialization, too large or small integer numbers will be automatically\n    be stored as @ref number_integer_t or @ref number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange (when considered in conjunction with the\n    number_integer_t type) of the exactly supported range [0, UINT64_MAX],\n    this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @since version 2.0.0\n    */\n    using number_unsigned_t = NumberUnsignedType;\n\n    /*!\n    @brief a type for a number (floating-point)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store floating-point numbers in C++, a type is defined by the template\n    parameter @a NumberFloatType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberFloatType (`double`), the default\n    value for @a number_float_t is:\n\n    @code {.cpp}\n    double\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in floating-point literals will be ignored. Internally,\n      the value will be stored as decimal number. For instance, the C++\n      floating-point literal `01.2` will be serialized to `1.2`. During\n      deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > This specification allows implementations to set limits on the range and\n    > precision of numbers accepted. Since software that implements IEEE\n    > 754-2008 binary64 (double precision) numbers is generally available and\n    > widely used, good interoperability can be achieved by implementations\n    > that expect no more precision or range than these provide, in the sense\n    > that implementations will approximate JSON numbers within the expected\n    > precision.\n\n    This implementation does exactly follow this approach, as it uses double\n    precision floating-point numbers. Note values smaller than\n    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`\n    will be stored as NaN internally and be serialized to `null`.\n\n    #### Storage\n\n    Floating-point number values are stored directly inside a @ref basic_json\n    type.\n\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_float_t = NumberFloatType;\n\n    /*!\n    @brief a type for a packed binary type\n\n    This type is a type designed to carry binary data that appears in various\n    serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and\n    BSON's generic binary subtype. This type is NOT a part of standard JSON and\n    exists solely for compatibility with these binary types. As such, it is\n    simply defined as an ordered sequence of zero or more byte values.\n\n    Additionally, as an implementation detail, the subtype of the binary data is\n    carried around as a `std::uint8_t`, which is compatible with both of the\n    binary data formats that use binary subtyping, (though the specific\n    numbering is incompatible with each other, and it is up to the user to\n    translate between them).\n\n    [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type\n    as:\n    > Major type 2: a byte string. The string's length in bytes is represented\n    > following the rules for positive integers (major type 0).\n\n    [MessagePack's documentation on the bin type\n    family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family)\n    describes this type as:\n    > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes\n    > in addition to the size of the byte array.\n\n    [BSON's specifications](http://bsonspec.org/spec.html) describe several\n    binary types; however, this type is intended to represent the generic binary\n    type which has the description:\n    > Generic binary subtype - This is the most commonly used binary subtype and\n    > should be the 'default' for drivers and tools.\n\n    None of these impose any limitations on the internal representation other\n    than the basic unit of storage be some type of array whose parts are\n    decomposable into bytes.\n\n    The default representation of this binary format is a\n    `std::vector<std::uint8_t>`, which is a very common way to represent a byte\n    array in modern C++.\n\n    #### Default type\n\n    The default values for @a BinaryType is `std::vector<std::uint8_t>`\n\n    #### Storage\n\n    Binary Arrays are stored as pointers in a @ref basic_json type. That is,\n    for any access to array values, a pointer of the type `binary_t*` must be\n    dereferenced.\n\n    #### Notes on subtypes\n\n    - CBOR\n       - Binary values are represented as byte strings. No subtypes are\n         supported and will be ignored when CBOR is written.\n    - MessagePack\n       - If a subtype is given and the binary array contains exactly 1, 2, 4, 8,\n         or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8)\n         is used. For other sizes, the ext family (ext8, ext16, ext32) is used.\n         The subtype is then added as singed 8-bit integer.\n       - If no subtype is given, the bin family (bin8, bin16, bin32) is used.\n    - BSON\n       - If a subtype is given, it is used and added as unsigned 8-bit integer.\n       - If no subtype is given, the generic binary subtype 0x00 is used.\n\n    @sa @ref binary -- create a binary array\n\n    @since version 3.8.0\n    */\n    using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;\n    /// @}\n\n  private:\n\n    /// helper for exception-safe object creation\n    template<typename T, typename... Args>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    static T* create(Args&& ... args)\n    {\n        AllocatorType<T> alloc;\n        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n        auto deleter = [&](T * obj)\n        {\n            AllocatorTraits::deallocate(alloc, obj, 1);\n        };\n        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);\n        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);\n        JSON_ASSERT(obj != nullptr);\n        return obj.release();\n    }\n\n    ////////////////////////\n    // JSON value storage //\n    ////////////////////////\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief a JSON value\n\n    The actual storage for a JSON value of the @ref basic_json class. This\n    union combines the different storage types for the JSON value types\n    defined in @ref value_t.\n\n    JSON type | value_t type    | used type\n    --------- | --------------- | ------------------------\n    object    | object          | pointer to @ref object_t\n    array     | array           | pointer to @ref array_t\n    string    | string          | pointer to @ref string_t\n    boolean   | boolean         | @ref boolean_t\n    number    | number_integer  | @ref number_integer_t\n    number    | number_unsigned | @ref number_unsigned_t\n    number    | number_float    | @ref number_float_t\n    binary    | binary          | pointer to @ref binary_t\n    null      | null            | *no value is stored*\n\n    @note Variable-length types (objects, arrays, and strings) are stored as\n    pointers. The size of the union should not exceed 64 bits if the default\n    value types are used.\n\n    @since version 1.0.0\n    */\n    union json_value\n    {\n        /// object (stored with pointer to save storage)\n        object_t* object;\n        /// array (stored with pointer to save storage)\n        array_t* array;\n        /// string (stored with pointer to save storage)\n        string_t* string;\n        /// binary (stored with pointer to save storage)\n        binary_t* binary;\n        /// boolean\n        boolean_t boolean;\n        /// number (integer)\n        number_integer_t number_integer;\n        /// number (unsigned integer)\n        number_unsigned_t number_unsigned;\n        /// number (floating-point)\n        number_float_t number_float;\n\n        /// default constructor (for null values)\n        json_value() = default;\n        /// constructor for booleans\n        json_value(boolean_t v) noexcept : boolean(v) {}\n        /// constructor for numbers (integer)\n        json_value(number_integer_t v) noexcept : number_integer(v) {}\n        /// constructor for numbers (unsigned)\n        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n        /// constructor for numbers (floating-point)\n        json_value(number_float_t v) noexcept : number_float(v) {}\n        /// constructor for empty values of a given type\n        json_value(value_t t)\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    object = create<object_t>();\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    array = create<array_t>();\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    string = create<string_t>(\"\");\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    binary = create<binary_t>();\n                    break;\n                }\n\n                case value_t::boolean:\n                {\n                    boolean = boolean_t(false);\n                    break;\n                }\n\n                case value_t::number_integer:\n                {\n                    number_integer = number_integer_t(0);\n                    break;\n                }\n\n                case value_t::number_unsigned:\n                {\n                    number_unsigned = number_unsigned_t(0);\n                    break;\n                }\n\n                case value_t::number_float:\n                {\n                    number_float = number_float_t(0.0);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    break;\n                }\n\n                default:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))\n                    {\n                        JSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.9.1\")); // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// constructor for strings\n        json_value(const string_t& value)\n        {\n            string = create<string_t>(value);\n        }\n\n        /// constructor for rvalue strings\n        json_value(string_t&& value)\n        {\n            string = create<string_t>(std::move(value));\n        }\n\n        /// constructor for objects\n        json_value(const object_t& value)\n        {\n            object = create<object_t>(value);\n        }\n\n        /// constructor for rvalue objects\n        json_value(object_t&& value)\n        {\n            object = create<object_t>(std::move(value));\n        }\n\n        /// constructor for arrays\n        json_value(const array_t& value)\n        {\n            array = create<array_t>(value);\n        }\n\n        /// constructor for rvalue arrays\n        json_value(array_t&& value)\n        {\n            array = create<array_t>(std::move(value));\n        }\n\n        /// constructor for binary arrays\n        json_value(const typename binary_t::container_type& value)\n        {\n            binary = create<binary_t>(value);\n        }\n\n        /// constructor for rvalue binary arrays\n        json_value(typename binary_t::container_type&& value)\n        {\n            binary = create<binary_t>(std::move(value));\n        }\n\n        /// constructor for binary arrays (internal type)\n        json_value(const binary_t& value)\n        {\n            binary = create<binary_t>(value);\n        }\n\n        /// constructor for rvalue binary arrays (internal type)\n        json_value(binary_t&& value)\n        {\n            binary = create<binary_t>(std::move(value));\n        }\n\n        void destroy(value_t t) noexcept\n        {\n            // flatten the current json_value to a heap-allocated stack\n            std::vector<basic_json> stack;\n\n            // move the top-level items to stack\n            if (t == value_t::array)\n            {\n                stack.reserve(array->size());\n                std::move(array->begin(), array->end(), std::back_inserter(stack));\n            }\n            else if (t == value_t::object)\n            {\n                stack.reserve(object->size());\n                for (auto&& it : *object)\n                {\n                    stack.push_back(std::move(it.second));\n                }\n            }\n\n            while (!stack.empty())\n            {\n                // move the last item to local variable to be processed\n                basic_json current_item(std::move(stack.back()));\n                stack.pop_back();\n\n                // if current_item is array/object, move\n                // its children to the stack to be processed later\n                if (current_item.is_array())\n                {\n                    std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(),\n                              std::back_inserter(stack));\n\n                    current_item.m_value.array->clear();\n                }\n                else if (current_item.is_object())\n                {\n                    for (auto&& it : *current_item.m_value.object)\n                    {\n                        stack.push_back(std::move(it.second));\n                    }\n\n                    current_item.m_value.object->clear();\n                }\n\n                // it's now safe that current_item get destructed\n                // since it doesn't have any children\n            }\n\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    AllocatorType<object_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    AllocatorType<array_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);\n                    break;\n                }\n\n                default:\n                {\n                    break;\n                }\n            }\n        }\n    };\n\n  private:\n    /*!\n    @brief checks the class invariants\n\n    This function asserts the class invariants. It needs to be called at the\n    end of every constructor to make sure that created objects respect the\n    invariant. Furthermore, it has to be called each time the type of a JSON\n    value is changed, because the invariant expresses a relationship between\n    @a m_type and @a m_value.\n    */\n    void assert_invariant() const noexcept\n    {\n        JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);\n        JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);\n        JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);\n        JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);\n    }\n\n  public:\n    //////////////////////////\n    // JSON parser callback //\n    //////////////////////////\n\n    /*!\n    @brief parser event types\n\n    The parser callback distinguishes the following events:\n    - `object_start`: the parser read `{` and started to process a JSON object\n    - `key`: the parser read a key of a value in an object\n    - `object_end`: the parser read `}` and finished processing a JSON object\n    - `array_start`: the parser read `[` and started to process a JSON array\n    - `array_end`: the parser read `]` and finished processing a JSON array\n    - `value`: the parser finished reading a JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    @sa @ref parser_callback_t for more information and examples\n    */\n    using parse_event_t = detail::parse_event_t;\n\n    /*!\n    @brief per-element parser callback type\n\n    With a parser callback function, the result of parsing a JSON text can be\n    influenced. When passed to @ref parse, it is called on certain events\n    (passed as @ref parse_event_t via parameter @a event) with a set recursion\n    depth @a depth and context JSON value @a parsed. The return value of the\n    callback function is a boolean indicating whether the element that emitted\n    the callback shall be kept or not.\n\n    We distinguish six scenarios (determined by the event type) in which the\n    callback function can be called. The following table describes the values\n    of the parameters @a depth, @a event, and @a parsed.\n\n    parameter @a event | description | parameter @a depth | parameter @a parsed\n    ------------------ | ----------- | ------------------ | -------------------\n    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded\n    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key\n    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object\n    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded\n    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array\n    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    Discarding a value (i.e., returning `false`) has different effects\n    depending on the context in which function was called:\n\n    - Discarded values in structured types are skipped. That is, the parser\n      will behave as if the discarded value was never read.\n    - In case a value outside a structured type is skipped, it is replaced\n      with `null`. This case happens if the top-level element is skipped.\n\n    @param[in] depth  the depth of the recursion during parsing\n\n    @param[in] event  an event of type parse_event_t indicating the context in\n    the callback function has been called\n\n    @param[in,out] parsed  the current intermediate parse result; note that\n    writing to this value has no effect for parse_event_t::key events\n\n    @return Whether the JSON value which called the function during parsing\n    should be kept (`true`) or not (`false`). In the latter case, it is either\n    skipped completely or replaced by an empty discarded object.\n\n    @sa @ref parse for examples\n\n    @since version 1.0.0\n    */\n    using parser_callback_t = detail::parser_callback_t<basic_json>;\n\n    //////////////////\n    // constructors //\n    //////////////////\n\n    /// @name constructors and destructors\n    /// Constructors of class @ref basic_json, copy/move constructor, copy\n    /// assignment, static functions creating objects, and the destructor.\n    /// @{\n\n    /*!\n    @brief create an empty value with a given type\n\n    Create an empty JSON value with a given type. The value will be default\n    initialized with an empty value which depends on the type:\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n    binary      | empty array\n\n    @param[in] v  the type of the value to create\n\n    @complexity Constant.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows the constructor for different @ref\n    value_t values,basic_json__value_t}\n\n    @sa @ref clear() -- restores the postcondition of this constructor\n\n    @since version 1.0.0\n    */\n    basic_json(const value_t v)\n        : m_type(v), m_value(v)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a null object\n\n    Create a `null` JSON value. It either takes a null pointer as parameter\n    (explicitly creating `null`) or no parameter (implicitly creating `null`).\n    The passed null pointer itself is not read -- it is only used to choose\n    the right constructor.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @liveexample{The following code shows the constructor with and without a\n    null pointer parameter.,basic_json__nullptr_t}\n\n    @since version 1.0.0\n    */\n    basic_json(std::nullptr_t = nullptr) noexcept\n        : basic_json(value_t::null)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value\n\n    This is a \"catch all\" constructor for all compatible JSON types; that is,\n    types for which a `to_json()` method exists. The constructor forwards the\n    parameter @a val to that method (to `json_serializer<U>::to_json` method\n    with `U = uncvref_t<CompatibleType>`, to be exact).\n\n    Template type @a CompatibleType includes, but is not limited to, the\n    following types:\n    - **arrays**: @ref array_t and all kinds of compatible containers such as\n      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,\n      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,\n      `std::multiset`, and `std::unordered_multiset` with a `value_type` from\n      which a @ref basic_json value can be constructed.\n    - **objects**: @ref object_t and all kinds of compatible associative\n      containers such as `std::map`, `std::unordered_map`, `std::multimap`,\n      and `std::unordered_multimap` with a `key_type` compatible to\n      @ref string_t and a `value_type` from which a @ref basic_json value can\n      be constructed.\n    - **strings**: @ref string_t, string literals, and all compatible string\n      containers can be used.\n    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,\n      @ref number_float_t, and all convertible number types such as `int`,\n      `size_t`, `int64_t`, `float` or `double` can be used.\n    - **boolean**: @ref boolean_t / `bool` can be used.\n    - **binary**: @ref binary_t / `std::vector<uint8_t>` may be used,\n      unfortunately because string literals cannot be distinguished from binary\n      character arrays by the C++ type system, all types compatible with `const\n      char*` will be directed to the string constructor instead.  This is both\n      for backwards compatibility, and due to the fact that a binary type is not\n      a standard JSON type.\n\n    See the examples below.\n\n    @tparam CompatibleType a type such that:\n    - @a CompatibleType is not derived from `std::istream`,\n    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move\n         constructors),\n    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)\n    - @a CompatibleType is not a @ref basic_json nested type (e.g.,\n         @ref json_pointer, @ref iterator, etc ...)\n    - @ref @ref json_serializer<U> has a\n         `to_json(basic_json_t&, CompatibleType&&)` method\n\n    @tparam U = `uncvref_t<CompatibleType>`\n\n    @param[in] val the value to be forwarded to the respective constructor\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @liveexample{The following code shows the constructor with several\n    compatible types.,basic_json__CompatibleType}\n\n    @since version 2.1.0\n    */\n    template < typename CompatibleType,\n               typename U = detail::uncvref_t<CompatibleType>,\n               detail::enable_if_t <\n                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >\n    basic_json(CompatibleType && val) noexcept(noexcept(\n                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n                                           std::forward<CompatibleType>(val))))\n    {\n        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value from an existing one\n\n    This is a constructor for existing @ref basic_json types.\n    It does not hijack copy/move constructors, since the parameter has different\n    template arguments than the current ones.\n\n    The constructor tries to convert the internal @ref m_value of the parameter.\n\n    @tparam BasicJsonType a type such that:\n    - @a BasicJsonType is a @ref basic_json type.\n    - @a BasicJsonType has different template arguments than @ref basic_json_t.\n\n    @param[in] val the @ref basic_json value to be converted.\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @since version 3.2.0\n    */\n    template < typename BasicJsonType,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >\n    basic_json(const BasicJsonType& val)\n    {\n        using other_boolean_t = typename BasicJsonType::boolean_t;\n        using other_number_float_t = typename BasicJsonType::number_float_t;\n        using other_number_integer_t = typename BasicJsonType::number_integer_t;\n        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n        using other_string_t = typename BasicJsonType::string_t;\n        using other_object_t = typename BasicJsonType::object_t;\n        using other_array_t = typename BasicJsonType::array_t;\n        using other_binary_t = typename BasicJsonType::binary_t;\n\n        switch (val.type())\n        {\n            case value_t::boolean:\n                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n                break;\n            case value_t::number_float:\n                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n                break;\n            case value_t::number_integer:\n                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n                break;\n            case value_t::number_unsigned:\n                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n                break;\n            case value_t::string:\n                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n                break;\n            case value_t::object:\n                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n                break;\n            case value_t::array:\n                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n                break;\n            case value_t::binary:\n                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());\n                break;\n            case value_t::null:\n                *this = nullptr;\n                break;\n            case value_t::discarded:\n                m_type = value_t::discarded;\n                break;\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a container (array or object) from an initializer list\n\n    Creates a JSON value of type array or object from the passed initializer\n    list @a init. In case @a type_deduction is `true` (default), the type of\n    the JSON value to be created is deducted from the initializer list @a init\n    according to the following rules:\n\n    1. If the list is empty, an empty JSON object value `{}` is created.\n    2. If the list consists of pairs whose first element is a string, a JSON\n       object value is created where the first elements of the pairs are\n       treated as keys and the second elements are as values.\n    3. In all other cases, an array is created.\n\n    The rules aim to create the best fit between a C++ initializer list and\n    JSON values. The rationale is as follows:\n\n    1. The empty initializer list is written as `{}` which is exactly an empty\n       JSON object.\n    2. C++ has no way of describing mapped types other than to list a list of\n       pairs. As JSON requires that keys must be of type string, rule 2 is the\n       weakest constraint one can pose on initializer lists to interpret them\n       as an object.\n    3. In all other cases, the initializer list could not be interpreted as\n       JSON object type, so interpreting it as JSON array type is safe.\n\n    With the rules described above, the following JSON values cannot be\n    expressed by an initializer list:\n\n    - the empty array (`[]`): use @ref array(initializer_list_t)\n      with an empty initializer list in this case\n    - arrays whose elements satisfy rule 2: use @ref\n      array(initializer_list_t) with the same initializer list\n      in this case\n\n    @note When used without parentheses around an empty initializer list, @ref\n    basic_json() is called instead of this function, yielding the JSON null\n    value.\n\n    @param[in] init  initializer list with JSON values\n\n    @param[in] type_deduction internal parameter; when set to `true`, the type\n    of the JSON value is deducted from the initializer list @a init; when set\n    to `false`, the type provided via @a manual_type is forced. This mode is\n    used by the functions @ref array(initializer_list_t) and\n    @ref object(initializer_list_t).\n\n    @param[in] manual_type internal parameter; when @a type_deduction is set\n    to `false`, the created JSON value will use the provided type (only @ref\n    value_t::array and @ref value_t::object are valid); when @a type_deduction\n    is set to `true`, this parameter has no effect\n\n    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is\n    `value_t::object`, but @a init contains an element which is not a pair\n    whose first element is a string. In this case, the constructor could not\n    create an object. If @a type_deduction would have be `true`, an array\n    would have been created. See @ref object(initializer_list_t)\n    for an example.\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows how JSON values are created from\n    initializer lists.,basic_json__list_init_t}\n\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    basic_json(initializer_list_t init,\n               bool type_deduction = true,\n               value_t manual_type = value_t::array)\n    {\n        // check if each element is an array with two elements whose first\n        // element is a string\n        bool is_an_object = std::all_of(init.begin(), init.end(),\n                                        [](const detail::json_ref<basic_json>& element_ref)\n        {\n            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();\n        });\n\n        // adjust type if type deduction is not wanted\n        if (!type_deduction)\n        {\n            // if array is wanted, do not create an object though possible\n            if (manual_type == value_t::array)\n            {\n                is_an_object = false;\n            }\n\n            // if object is wanted but impossible, throw an exception\n            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))\n            {\n                JSON_THROW(type_error::create(301, \"cannot create object from initializer list\"));\n            }\n        }\n\n        if (is_an_object)\n        {\n            // the initializer list is a list of pairs -> create object\n            m_type = value_t::object;\n            m_value = value_t::object;\n\n            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)\n            {\n                auto element = element_ref.moved_or_copied();\n                m_value.object->emplace(\n                    std::move(*((*element.m_value.array)[0].m_value.string)),\n                    std::move((*element.m_value.array)[1]));\n            });\n        }\n        else\n        {\n            // the initializer list describes an array -> create array\n            m_type = value_t::array;\n            m_value.array = create<array_t>(init.begin(), init.end());\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief explicitly create a binary array (without subtype)\n\n    Creates a JSON binary array value from a given binary container. Binary\n    values are part of various binary formats, such as CBOR, MessagePack, and\n    BSON. This constructor is used to create a value for serialization to those\n    formats.\n\n    @note Note, this function exists because of the difficulty in correctly\n    specifying the correct template overload in the standard value ctor, as both\n    JSON arrays and JSON binary arrays are backed with some form of a\n    `std::vector`. Because JSON binary arrays are a non-standard extension it\n    was decided that it would be best to prevent automatic initialization of a\n    binary array type, for backwards compatibility and so it does not happen on\n    accident.\n\n    @param[in] init container containing bytes to use as binary type\n\n    @return JSON binary array value\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @since version 3.8.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = init;\n        return res;\n    }\n\n    /*!\n    @brief explicitly create a binary array (with subtype)\n\n    Creates a JSON binary array value from a given binary container. Binary\n    values are part of various binary formats, such as CBOR, MessagePack, and\n    BSON. This constructor is used to create a value for serialization to those\n    formats.\n\n    @note Note, this function exists because of the difficulty in correctly\n    specifying the correct template overload in the standard value ctor, as both\n    JSON arrays and JSON binary arrays are backed with some form of a\n    `std::vector`. Because JSON binary arrays are a non-standard extension it\n    was decided that it would be best to prevent automatic initialization of a\n    binary array type, for backwards compatibility and so it does not happen on\n    accident.\n\n    @param[in] init container containing bytes to use as binary type\n    @param[in] subtype subtype to use in MessagePack and BSON\n\n    @return JSON binary array value\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @since version 3.8.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = binary_t(init, subtype);\n        return res;\n    }\n\n    /// @copydoc binary(const typename binary_t::container_type&)\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = std::move(init);\n        return res;\n    }\n\n    /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t)\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype)\n    {\n        auto res = basic_json();\n        res.m_type = value_t::binary;\n        res.m_value = binary_t(std::move(init), subtype);\n        return res;\n    }\n\n    /*!\n    @brief explicitly create an array from an initializer list\n\n    Creates a JSON array value from a given initializer list. That is, given a\n    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the\n    initializer list is empty, the empty array `[]` is created.\n\n    @note This function is only needed to express two edge cases that cannot\n    be realized with the initializer list constructor (@ref\n    basic_json(initializer_list_t, bool, value_t)). These cases\n    are:\n    1. creating an array whose elements are all pairs whose first element is a\n    string -- in this case, the initializer list constructor would create an\n    object, taking the first elements as keys\n    2. creating an empty array -- passing the empty initializer list to the\n    initializer list constructor yields an empty object\n\n    @param[in] init  initializer list with JSON values to create an array from\n    (optional)\n\n    @return JSON array value\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `array`\n    function.,array}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json array(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::array);\n    }\n\n    /*!\n    @brief explicitly create an object from an initializer list\n\n    Creates a JSON object value from a given initializer list. The initializer\n    lists elements must be pairs, and their first elements must be strings. If\n    the initializer list is empty, the empty object `{}` is created.\n\n    @note This function is only added for symmetry reasons. In contrast to the\n    related function @ref array(initializer_list_t), there are\n    no cases which can only be expressed by this function. That is, any\n    initializer list @a init can also be passed to the initializer list\n    constructor @ref basic_json(initializer_list_t, bool, value_t).\n\n    @param[in] init  initializer list to create an object from (optional)\n\n    @return JSON object value\n\n    @throw type_error.301 if @a init is not a list of pairs whose first\n    elements are strings. In this case, no object can be created. When such a\n    value is passed to @ref basic_json(initializer_list_t, bool, value_t),\n    an array would have been created from the passed initializer list @a init.\n    See example below.\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `object`\n    function.,object}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json object(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::object);\n    }\n\n    /*!\n    @brief construct an array with count copies of given value\n\n    Constructs a JSON array value by creating @a cnt copies of a passed value.\n    In case @a cnt is `0`, an empty array is created.\n\n    @param[in] cnt  the number of JSON copies of @a val to create\n    @param[in] val  the JSON value to copy\n\n    @post `std::distance(begin(),end()) == cnt` holds.\n\n    @complexity Linear in @a cnt.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows examples for the @ref\n    basic_json(size_type\\, const basic_json&)\n    constructor.,basic_json__size_type_basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(size_type cnt, const basic_json& val)\n        : m_type(value_t::array)\n    {\n        m_value.array = create<array_t>(cnt, val);\n        assert_invariant();\n    }\n\n    /*!\n    @brief construct a JSON container given an iterator range\n\n    Constructs the JSON value with the contents of the range `[first, last)`.\n    The semantics depends on the different types a JSON value can have:\n    - In case of a null type, invalid_iterator.206 is thrown.\n    - In case of other primitive types (number, boolean, or string), @a first\n      must be `begin()` and @a last must be `end()`. In this case, the value is\n      copied. Otherwise, invalid_iterator.204 is thrown.\n    - In case of structured types (array, object), the constructor behaves as\n      similar versions for `std::vector` or `std::map`; that is, a JSON array\n      or object is constructed from the values in the range.\n\n    @tparam InputIT an input iterator type (@ref iterator or @ref\n    const_iterator)\n\n    @param[in] first begin of the range to copy from (included)\n    @param[in] last end of the range to copy from (excluded)\n\n    @pre Iterators @a first and @a last must be initialized. **This\n         precondition is enforced with an assertion (see warning).** If\n         assertions are switched off, a violation of this precondition yields\n         undefined behavior.\n\n    @pre Range `[first, last)` is valid. Usually, this precondition cannot be\n         checked efficiently. Only certain edge cases are detected; see the\n         description of the exceptions below. A violation of this precondition\n         yields undefined behavior.\n\n    @warning A precondition is enforced with a runtime assertion that will\n             result in calling `std::abort` if this precondition is not met.\n             Assertions can be disabled by defining `NDEBUG` at compile time.\n             See https://en.cppreference.com/w/cpp/error/assert for more\n             information.\n\n    @throw invalid_iterator.201 if iterators @a first and @a last are not\n    compatible (i.e., do not belong to the same JSON value). In this case,\n    the range `[first, last)` is undefined.\n    @throw invalid_iterator.204 if iterators @a first and @a last belong to a\n    primitive type (number, boolean, or string), but @a first does not point\n    to the first element any more. In this case, the range `[first, last)` is\n    undefined. See example code below.\n    @throw invalid_iterator.206 if iterators @a first and @a last belong to a\n    null value. In this case, the range `[first, last)` is undefined.\n\n    @complexity Linear in distance between @a first and @a last.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows several ways to create JSON values by\n    specifying a subrange with iterators.,basic_json__InputIt_InputIt}\n\n    @since version 1.0.0\n    */\n    template < class InputIT, typename std::enable_if <\n                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||\n                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >\n    basic_json(InputIT first, InputIT last)\n    {\n        JSON_ASSERT(first.m_object != nullptr);\n        JSON_ASSERT(last.m_object != nullptr);\n\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\"));\n        }\n\n        // copy type from first iterator\n        m_type = first.m_object->m_type;\n\n        // check if iterator range is complete for primitive values\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()\n                                         || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = first.m_object->m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = first.m_object->m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = first.m_object->m_value.number_float;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = first.m_object->m_value.boolean;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *first.m_object->m_value.string;\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object = create<object_t>(first.m_it.object_iterator,\n                                                  last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array = create<array_t>(first.m_it.array_iterator,\n                                                last.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value = *first.m_object->m_value.binary;\n                break;\n            }\n\n            default:\n                JSON_THROW(invalid_iterator::create(206, \"cannot construct with iterators from \" +\n                                                    std::string(first.m_object->type_name())));\n        }\n\n        assert_invariant();\n    }\n\n\n    ///////////////////////////////////////\n    // other constructors and destructor //\n    ///////////////////////////////////////\n\n    template<typename JsonRef,\n             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,\n                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >\n    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}\n\n    /*!\n    @brief copy constructor\n\n    Creates a copy of a given JSON value.\n\n    @param[in] other  the JSON value to copy\n\n    @post `*this == other`\n\n    @complexity Linear in the size of @a other.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - As postcondition, it holds: `other == basic_json(other)`.\n\n    @liveexample{The following code shows an example for the copy\n    constructor.,basic_json__basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(const basic_json& other)\n        : m_type(other.m_type)\n    {\n        // check of passed value is valid\n        other.assert_invariant();\n\n        switch (m_type)\n        {\n            case value_t::object:\n            {\n                m_value = *other.m_value.object;\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value = *other.m_value.array;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *other.m_value.string;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value = other.m_value.boolean;\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                m_value = other.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value = other.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value = other.m_value.number_float;\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value = *other.m_value.binary;\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief move constructor\n\n    Move constructor. Constructs a JSON value with the contents of the given\n    value @a other using move semantics. It \"steals\" the resources from @a\n    other and leaves it as JSON null value.\n\n    @param[in,out] other  value to move to this object\n\n    @post `*this` has the same value as @a other before the call.\n    @post @a other is a JSON null value.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)\n    requirements.\n\n    @liveexample{The code below shows the move constructor explicitly called\n    via std::move.,basic_json__moveconstructor}\n\n    @since version 1.0.0\n    */\n    basic_json(basic_json&& other) noexcept\n        : m_type(std::move(other.m_type)),\n          m_value(std::move(other.m_value))\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        // invalidate payload\n        other.m_type = value_t::null;\n        other.m_value = {};\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief copy assignment\n\n    Copy assignment operator. Copies a JSON value via the \"copy and swap\"\n    strategy: It is expressed in terms of the copy constructor, destructor,\n    and the `swap()` member function.\n\n    @param[in] other  value to copy from\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n\n    @liveexample{The code below shows and example for the copy assignment. It\n    creates a copy of value `a` which is then swapped with `b`. Finally\\, the\n    copy of `a` (which is the null value after the swap) is\n    destroyed.,basic_json__copyassignment}\n\n    @since version 1.0.0\n    */\n    basic_json& operator=(basic_json other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        using std::swap;\n        swap(m_type, other.m_type);\n        swap(m_value, other.m_value);\n\n        assert_invariant();\n        return *this;\n    }\n\n    /*!\n    @brief destructor\n\n    Destroys the JSON value and frees all allocated memory.\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - All stored elements are destroyed and all memory is freed.\n\n    @since version 1.0.0\n    */\n    ~basic_json() noexcept\n    {\n        assert_invariant();\n        m_value.destroy(m_type);\n    }\n\n    /// @}\n\n  public:\n    ///////////////////////\n    // object inspection //\n    ///////////////////////\n\n    /// @name object inspection\n    /// Functions to inspect the type of a JSON value.\n    /// @{\n\n    /*!\n    @brief serialization\n\n    Serialization function for JSON values. The function tries to mimic\n    Python's `json.dumps()` function, and currently supports its @a indent\n    and @a ensure_ascii parameters.\n\n    @param[in] indent If indent is nonnegative, then array elements and object\n    members will be pretty-printed with that indent level. An indent level of\n    `0` will only insert newlines. `-1` (the default) selects the most compact\n    representation.\n    @param[in] indent_char The character to use for indentation if @a indent is\n    greater than `0`. The default is ` ` (space).\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] error_handler  how to react on decoding errors; there are three\n    possible values: `strict` (throws and exception in case a decoding error\n    occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),\n    and `ignore` (ignore invalid UTF-8 sequences during serialization; all\n    bytes are copied to the output unchanged).\n\n    @return string containing the serialization of the JSON value\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded and @a error_handler is set to strict\n\n    @note Binary values are serialized as object containing two keys:\n      - \"bytes\": an array of bytes as integers\n      - \"subtype\": the subtype as integer or \"null\" if the binary has no subtype\n\n    @complexity Linear.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @liveexample{The following example shows the effect of different @a indent\\,\n    @a indent_char\\, and @a ensure_ascii parameters to the result of the\n    serialization.,dump}\n\n    @see https://docs.python.org/2/library/json.html#json.dump\n\n    @since version 1.0.0; indentation character @a indent_char, option\n           @a ensure_ascii and exceptions added in version 3.0.0; error\n           handlers added in version 3.4.0; serialization of binary values added\n           in version 3.8.0.\n    */\n    string_t dump(const int indent = -1,\n                  const char indent_char = ' ',\n                  const bool ensure_ascii = false,\n                  const error_handler_t error_handler = error_handler_t::strict) const\n    {\n        string_t result;\n        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n        if (indent >= 0)\n        {\n            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n        }\n        else\n        {\n            s.dump(*this, false, ensure_ascii, 0);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief return the type of the JSON value (explicit)\n\n    Return the type of the JSON value as a value from the @ref value_t\n    enumeration.\n\n    @return the type of the JSON value\n            Value type                | return value\n            ------------------------- | -------------------------\n            null                      | value_t::null\n            boolean                   | value_t::boolean\n            string                    | value_t::string\n            number (integer)          | value_t::number_integer\n            number (unsigned integer) | value_t::number_unsigned\n            number (floating-point)   | value_t::number_float\n            object                    | value_t::object\n            array                     | value_t::array\n            binary                    | value_t::binary\n            discarded                 | value_t::discarded\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `type()` for all JSON\n    types.,type}\n\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr value_t type() const noexcept\n    {\n        return m_type;\n    }\n\n    /*!\n    @brief return whether type is primitive\n\n    This function returns true if and only if the JSON type is primitive\n    (string, number, boolean, or null).\n\n    @return `true` if type is primitive (string, number, boolean, or null),\n    `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_primitive()` for all JSON\n    types.,is_primitive}\n\n    @sa @ref is_structured() -- returns whether JSON value is structured\n    @sa @ref is_null() -- returns whether JSON value is `null`\n    @sa @ref is_string() -- returns whether JSON value is a string\n    @sa @ref is_boolean() -- returns whether JSON value is a boolean\n    @sa @ref is_number() -- returns whether JSON value is a number\n    @sa @ref is_binary() -- returns whether JSON value is a binary array\n\n    @since version 1.0.0\n    */\n    constexpr bool is_primitive() const noexcept\n    {\n        return is_null() || is_string() || is_boolean() || is_number() || is_binary();\n    }\n\n    /*!\n    @brief return whether type is structured\n\n    This function returns true if and only if the JSON type is structured\n    (array or object).\n\n    @return `true` if type is structured (array or object), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_structured()` for all JSON\n    types.,is_structured}\n\n    @sa @ref is_primitive() -- returns whether value is primitive\n    @sa @ref is_array() -- returns whether value is an array\n    @sa @ref is_object() -- returns whether value is an object\n\n    @since version 1.0.0\n    */\n    constexpr bool is_structured() const noexcept\n    {\n        return is_array() || is_object();\n    }\n\n    /*!\n    @brief return whether value is null\n\n    This function returns true if and only if the JSON value is null.\n\n    @return `true` if type is null, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_null()` for all JSON\n    types.,is_null}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_null() const noexcept\n    {\n        return m_type == value_t::null;\n    }\n\n    /*!\n    @brief return whether value is a boolean\n\n    This function returns true if and only if the JSON value is a boolean.\n\n    @return `true` if type is boolean, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_boolean()` for all JSON\n    types.,is_boolean}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_boolean() const noexcept\n    {\n        return m_type == value_t::boolean;\n    }\n\n    /*!\n    @brief return whether value is a number\n\n    This function returns true if and only if the JSON value is a number. This\n    includes both integer (signed and unsigned) and floating-point values.\n\n    @return `true` if type is number (regardless whether integer, unsigned\n    integer or floating-type), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number()` for all JSON\n    types.,is_number}\n\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number() const noexcept\n    {\n        return is_number_integer() || is_number_float();\n    }\n\n    /*!\n    @brief return whether value is an integer number\n\n    This function returns true if and only if the JSON value is a signed or\n    unsigned integer number. This excludes floating-point values.\n\n    @return `true` if type is an integer or unsigned integer number, `false`\n    otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_integer()` for all\n    JSON types.,is_number_integer}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_integer() const noexcept\n    {\n        return m_type == value_t::number_integer || m_type == value_t::number_unsigned;\n    }\n\n    /*!\n    @brief return whether value is an unsigned integer number\n\n    This function returns true if and only if the JSON value is an unsigned\n    integer number. This excludes floating-point and signed integer values.\n\n    @return `true` if type is an unsigned integer number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_unsigned()` for all\n    JSON types.,is_number_unsigned}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 2.0.0\n    */\n    constexpr bool is_number_unsigned() const noexcept\n    {\n        return m_type == value_t::number_unsigned;\n    }\n\n    /*!\n    @brief return whether value is a floating-point number\n\n    This function returns true if and only if the JSON value is a\n    floating-point number. This excludes signed and unsigned integer values.\n\n    @return `true` if type is a floating-point number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_float()` for all\n    JSON types.,is_number_float}\n\n    @sa @ref is_number() -- check if value is number\n    @sa @ref is_number_integer() -- check if value is an integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_float() const noexcept\n    {\n        return m_type == value_t::number_float;\n    }\n\n    /*!\n    @brief return whether value is an object\n\n    This function returns true if and only if the JSON value is an object.\n\n    @return `true` if type is object, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_object()` for all JSON\n    types.,is_object}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_object() const noexcept\n    {\n        return m_type == value_t::object;\n    }\n\n    /*!\n    @brief return whether value is an array\n\n    This function returns true if and only if the JSON value is an array.\n\n    @return `true` if type is array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_array()` for all JSON\n    types.,is_array}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_array() const noexcept\n    {\n        return m_type == value_t::array;\n    }\n\n    /*!\n    @brief return whether value is a string\n\n    This function returns true if and only if the JSON value is a string.\n\n    @return `true` if type is string, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_string()` for all JSON\n    types.,is_string}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_string() const noexcept\n    {\n        return m_type == value_t::string;\n    }\n\n    /*!\n    @brief return whether value is a binary array\n\n    This function returns true if and only if the JSON value is a binary array.\n\n    @return `true` if type is binary array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_binary()` for all JSON\n    types.,is_binary}\n\n    @since version 3.8.0\n    */\n    constexpr bool is_binary() const noexcept\n    {\n        return m_type == value_t::binary;\n    }\n\n    /*!\n    @brief return whether value is discarded\n\n    This function returns true if and only if the JSON value was discarded\n    during parsing with a callback function (see @ref parser_callback_t).\n\n    @note This function will always be `false` for JSON values after parsing.\n    That is, discarded values can only occur during parsing, but will be\n    removed when inside a structured value or replaced by null in other cases.\n\n    @return `true` if type is discarded, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_discarded()` for all JSON\n    types.,is_discarded}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_discarded() const noexcept\n    {\n        return m_type == value_t::discarded;\n    }\n\n    /*!\n    @brief return the type of the JSON value (implicit)\n\n    Implicitly return the type of the JSON value as a value from the @ref\n    value_t enumeration.\n\n    @return the type of the JSON value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies the @ref value_t operator for\n    all JSON types.,operator__value_t}\n\n    @sa @ref type() -- return the type of the JSON value (explicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr operator value_t() const noexcept\n    {\n        return m_type;\n    }\n\n    /// @}\n\n  private:\n    //////////////////\n    // value access //\n    //////////////////\n\n    /// get a boolean (explicit)\n    boolean_t get_impl(boolean_t* /*unused*/) const\n    {\n        if (JSON_HEDLEY_LIKELY(is_boolean()))\n        {\n            return m_value.boolean;\n        }\n\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(type_name())));\n    }\n\n    /// get a pointer to the value (object)\n    object_t* get_impl_ptr(object_t* /*unused*/) noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (object)\n    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    array_t* get_impl_ptr(array_t* /*unused*/) noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    string_t* get_impl_ptr(string_t* /*unused*/) noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept\n    {\n        return is_binary() ? m_value.binary : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept\n    {\n        return is_binary() ? m_value.binary : nullptr;\n    }\n\n    /*!\n    @brief helper function to implement get_ref()\n\n    This function helps to implement get_ref() without code duplication for\n    const and non-const overloads\n\n    @tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n    @throw type_error.303 if ReferenceType does not match underlying value\n    type of the current JSON\n    */\n    template<typename ReferenceType, typename ThisType>\n    static ReferenceType get_ref_impl(ThisType& obj)\n    {\n        // delegate the call to get_ptr<>()\n        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n        if (JSON_HEDLEY_LIKELY(ptr != nullptr))\n        {\n            return *ptr;\n        }\n\n        JSON_THROW(type_error::create(303, \"incompatible ReferenceType for get_ref, actual type is \" + std::string(obj.type_name())));\n    }\n\n  public:\n    /// @name value access\n    /// Direct access to the stored value of a JSON value.\n    /// @{\n\n    /*!\n    @brief get special-case overload\n\n    This overloads avoids a lot of template boilerplate, it can be seen as the\n    identity method\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this\n\n    @complexity Constant.\n\n    @since version 2.1.0\n    */\n    template<typename BasicJsonType, detail::enable_if_t<\n                 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,\n                 int> = 0>\n    basic_json get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads converts the current @ref basic_json in a different\n    @ref basic_json type\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this, converted into @tparam BasicJsonType\n\n    @complexity Depending on the implementation of the called `from_json()`\n                method.\n\n    @since version 3.2.0\n    */\n    template < typename BasicJsonType, detail::enable_if_t <\n                   !std::is_same<BasicJsonType, basic_json>::value&&\n                   detail::is_basic_json<BasicJsonType>::value, int > = 0 >\n    BasicJsonType get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType ret;\n    JSONSerializer<ValueType>::from_json(*this, ret);\n    return ret;\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n    - @ref json_serializer<ValueType> does not have a `from_json()` method of\n      the form `ValueType from_json(const basic_json&)`\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get__ValueType_const}\n\n    @since version 2.1.0\n    */\n    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n               detail::enable_if_t <\n                   !detail::is_basic_json<ValueType>::value &&\n                   detail::has_from_json<basic_json_t, ValueType>::value &&\n                   !detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n    {\n        // we cannot static_assert on ValueTypeCV being non-const, because\n        // there is support for get<const basic_json_t>(), which is why we\n        // still need the uncvref\n        static_assert(!std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        static_assert(std::is_default_constructible<ValueType>::value,\n                      \"types must be DefaultConstructible when used with get()\");\n\n        ValueType ret;\n        JSONSerializer<ValueType>::from_json(*this, ret);\n        return ret;\n    }\n\n    /*!\n    @brief get a value (explicit); special case\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    return JSONSerializer<ValueTypeCV>::from_json(*this);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json and\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `ValueType from_json(const basic_json&)`\n\n    @note If @ref json_serializer<ValueType> has both overloads of\n    `from_json()`, this one is chosen.\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @since version 2.1.0\n    */\n    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n               detail::enable_if_t < !std::is_same<basic_json_t, ValueType>::value &&\n                                     detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                                     int > = 0 >\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))\n    {\n        static_assert(!std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        return JSONSerializer<ValueType>::from_json(*this);\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value.\n    The value is filled into the input parameter by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType v;\n    JSONSerializer<ValueType>::from_json(*this, v);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n\n    @tparam ValueType the input parameter type.\n\n    @return the input parameter, allowing chaining calls.\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get_to}\n\n    @since version 3.3.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   !detail::is_basic_json<ValueType>::value&&\n                   detail::has_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType & get_to(ValueType& v) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<ValueType>::from_json(*this, v);\n        return v;\n    }\n\n    // specialization to allow to call get_to with a basic_json value\n    // see https://github.com/nlohmann/json/issues/2175\n    template<typename ValueType,\n             detail::enable_if_t <\n                 detail::is_basic_json<ValueType>::value,\n                 int> = 0>\n    ValueType & get_to(ValueType& v) const\n    {\n        v = *this;\n        return v;\n    }\n\n    template <\n        typename T, std::size_t N,\n        typename Array = T (&)[N],\n        detail::enable_if_t <\n            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >\n    Array get_to(T (&v)[N]) const\n    noexcept(noexcept(JSONSerializer<Array>::from_json(\n                          std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<Array>::from_json(*this, v);\n        return v;\n    }\n\n\n    /*!\n    @brief get a pointer value (implicit)\n\n    Implicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning Writing data to the pointee of the result yields an undefined\n    state.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static\n    assertion.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get_ptr}\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>()\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (implicit)\n    @copydoc get_ptr()\n    */\n    template < typename PointerType, typename std::enable_if <\n                   std::is_pointer<PointerType>::value&&\n                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >\n    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>() const\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n\n    Explicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning The pointer becomes invalid if the underlying JSON object\n    changes.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get__PointerType}\n\n    @sa @ref get_ptr() for explicit pointer-member access\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n    @copydoc get()\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n\n    Implicit reference access to the internally stored JSON value. No copies\n    are made.\n\n    @warning Writing data to the referee of the result yields an undefined\n    state.\n\n    @tparam ReferenceType reference type; must be a reference to @ref array_t,\n    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or\n    @ref number_float_t. Enforced by static assertion.\n\n    @return reference to the internally stored JSON value if the requested\n    reference type @a ReferenceType fits to the JSON value; throws\n    type_error.303 otherwise\n\n    @throw type_error.303 in case passed type @a ReferenceType is incompatible\n    with the stored JSON value; see example below\n\n    @complexity Constant.\n\n    @liveexample{The example shows several calls to `get_ref()`.,get_ref}\n\n    @since version 1.1.0\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value, int>::type = 0>\n    ReferenceType get_ref()\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n    @copydoc get_ref()\n    */\n    template < typename ReferenceType, typename std::enable_if <\n                   std::is_reference<ReferenceType>::value&&\n                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >\n    ReferenceType get_ref() const\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a value (implicit)\n\n    Implicit type conversion between the JSON value and a compatible value.\n    The call is realized by calling @ref get() const.\n\n    @tparam ValueType non-pointer type compatible to the JSON value, for\n    instance `int` for JSON integer numbers, `bool` for JSON booleans, or\n    `std::vector` types for JSON arrays. The character type of @ref string_t\n    as well as an initializer list of this type is excluded to avoid\n    ambiguities as these types implicitly convert to `std::string`.\n\n    @return copy of the JSON value, converted to type @a ValueType\n\n    @throw type_error.302 in case passed type @a ValueType is incompatible\n    to the JSON value type (e.g., the JSON value is of type boolean, but a\n    string is requested); see example below\n\n    @complexity Linear in the size of the JSON value.\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,operator__ValueType}\n\n    @since version 1.0.0\n    */\n    template < typename ValueType, typename std::enable_if <\n                   !std::is_pointer<ValueType>::value&&\n                   !std::is_same<ValueType, detail::json_ref<basic_json>>::value&&\n                   !std::is_same<ValueType, typename string_t::value_type>::value&&\n                   !detail::is_basic_json<ValueType>::value\n                   && !std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value\n#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))\n                   && !std::is_same<ValueType, typename std::string_view>::value\n#endif\n                   && detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value\n                   , int >::type = 0 >\n    JSON_EXPLICIT operator ValueType() const\n    {\n        // delegate the call to get<>() const\n        return get<ValueType>();\n    }\n\n    /*!\n    @return reference to the binary value\n\n    @throw type_error.302 if the value is not binary\n\n    @sa @ref is_binary() to check if the value is binary\n\n    @since version 3.8.0\n    */\n    binary_t& get_binary()\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(type_name())));\n        }\n\n        return *get_ptr<binary_t*>();\n    }\n\n    /// @copydoc get_binary()\n    const binary_t& get_binary() const\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, \"type must be binary, but is \" + std::string(type_name())));\n        }\n\n        return *get_ptr<const binary_t*>();\n    }\n\n    /// @}\n\n\n    ////////////////////\n    // element access //\n    ////////////////////\n\n    /// @name element access\n    /// Access to the JSON value.\n    /// @{\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a reference to the element at specified location @a idx, with\n    bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__size_type}\n    */\n    reference at(size_type idx)\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a const reference to the element at specified location @a idx,\n    with bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__size_type_const}\n    */\n    const_reference at(size_type idx) const\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a reference to the element at with specified key @a key, with\n    bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__object_t_key_type}\n    */\n    reference at(const typename object_t::key_type& key)\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a const reference to the element at with specified key @a key,\n    with bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__object_t_key_type_const}\n    */\n    const_reference at(const typename object_t::key_type& key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a reference to the element at specified location @a idx.\n\n    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),\n    then the array is silently filled up with `null` values to make `idx` a\n    valid reference to the last stored element.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array or null; in that\n    cases, using the [] operator with an index makes no sense.\n\n    @complexity Constant if @a idx is in the range of the array. Otherwise\n    linear in `idx - size()`.\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `[]` operator. Note the addition of `null`\n    values.,operatorarray__size_type}\n\n    @since version 1.0.0\n    */\n    reference operator[](size_type idx)\n    {\n        // implicitly convert null value to an empty array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value.array = create<array_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // fill up array with null values if given idx is outside range\n            if (idx >= m_value.array->size())\n            {\n                m_value.array->insert(m_value.array->end(),\n                                      idx - m_value.array->size() + 1,\n                                      basic_json());\n            }\n\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a const reference to the element at specified location @a idx.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array; in that case,\n    using the [] operator with an index makes no sense.\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how array elements can be read using\n    the `[]` operator.,operatorarray__size_type_const}\n\n    @since version 1.0.0\n    */\n    const_reference operator[](size_type idx) const\n    {\n        // const operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    reference operator[](const typename object_t::key_type& key)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    const_reference operator[](const typename object_t::key_type& key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_ASSERT(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    JSON_HEDLEY_NON_NULL(2)\n    reference operator[](T* key)\n    {\n        // implicitly convert null to object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    JSON_HEDLEY_NON_NULL(2)\n    const_reference operator[](T* key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            JSON_ASSERT(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(key);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const typename object_t::key_type&), this function\n    does not throw if the given key @a key was not found.\n\n    @note Unlike @ref operator[](const typename object_t::key_type& key), this\n    function does not implicitly add an element to the position defined by @a\n    key. This function is furthermore also applicable to const objects.\n\n    @param[in] key  key of the element to access\n    @param[in] default_value  the value to return if @a key is not found\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.302 if @a default_value does not match the type of the\n    value at @a key\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n\n    @since version 1.0.0\n    */\n    // using std::is_convertible in a std::enable_if will fail when using explicit conversions\n    template < class ValueType, typename std::enable_if <\n                   detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, ValueType>::value, int >::type = 0 >\n    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return it->template get<ValueType>();\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const\n    */\n    string_t value(const typename object_t::key_type& key, const char* default_value) const\n    {\n        return value(key, string_t(default_value));\n    }\n\n    /*!\n    @brief access specified object element via JSON Pointer with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(ptr);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const json_pointer&), this function does not throw\n    if the given key @a key was not found.\n\n    @param[in] ptr  a JSON pointer to the element to access\n    @param[in] default_value  the value to return if @a ptr found no value\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.302 if @a default_value does not match the type of the\n    value at @a ptr\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value_ptr}\n\n    @sa @ref operator[](const json_pointer&) for unchecked access by reference\n\n    @since version 2.0.2\n    */\n    template<class ValueType, typename std::enable_if<\n                 detail::is_getable<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const json_pointer& ptr, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this).template get<ValueType>();\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return default_value;\n            }\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const json_pointer&, ValueType) const\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    string_t value(const json_pointer& ptr, const char* default_value) const\n    {\n        return value(ptr, string_t(default_value));\n    }\n\n    /*!\n    @brief access the first element\n\n    Returns a reference to the first element in the container. For a JSON\n    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.\n\n    @return In case of a structured type (array or object), a reference to the\n    first element is returned. In case of number, string, boolean, or binary\n    values, a reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on `null` value\n\n    @liveexample{The following code shows an example for `front()`.,front}\n\n    @sa @ref back() -- access the last element\n\n    @since version 1.0.0\n    */\n    reference front()\n    {\n        return *begin();\n    }\n\n    /*!\n    @copydoc basic_json::front()\n    */\n    const_reference front() const\n    {\n        return *cbegin();\n    }\n\n    /*!\n    @brief access the last element\n\n    Returns a reference to the last element in the container. For a JSON\n    container `c`, the expression `c.back()` is equivalent to\n    @code {.cpp}\n    auto tmp = c.end();\n    --tmp;\n    return *tmp;\n    @endcode\n\n    @return In case of a structured type (array or object), a reference to the\n    last element is returned. In case of number, string, boolean, or binary\n    values, a reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on a `null` value. See example\n    below.\n\n    @liveexample{The following code shows an example for `back()`.,back}\n\n    @sa @ref front() -- access the first element\n\n    @since version 1.0.0\n    */\n    reference back()\n    {\n        auto tmp = end();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @copydoc basic_json::back()\n    */\n    const_reference back() const\n    {\n        auto tmp = cend();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @brief remove element given an iterator\n\n    Removes the element specified by iterator @a pos. The iterator @a pos must\n    be valid and dereferenceable. Thus the `end()` iterator (which is valid,\n    but is not dereferenceable) cannot be used as a value for @a pos.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] pos iterator to the element to remove\n    @return Iterator following the last removed element. If the iterator @a\n    pos refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.202 if called on an iterator which does not belong\n    to the current JSON value; example: `\"iterator does not fit current\n    value\"`\n    @throw invalid_iterator.205 if called on a primitive type with invalid\n    iterator (i.e., any iterator which is not `begin()`); example: `\"iterator\n    out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: amortized constant\n    - arrays: linear in distance between @a pos and the end of the container\n    - strings and binary: linear in the length of the member\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType}\n\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template < class IteratorType, typename std::enable_if <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type\n               = 0 >\n    IteratorType erase(IteratorType pos)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))\n                {\n                    JSON_THROW(invalid_iterator::create(205, \"iterator out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);\n                    m_value.binary = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove elements given an iterator range\n\n    Removes the element specified by the range `[first; last)`. The iterator\n    @a first does not need to be dereferenceable if `first == last`: erasing\n    an empty range is a no-op.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] first iterator to the beginning of the range to remove\n    @param[in] last iterator past the end of the range to remove\n    @return Iterator following the last removed element. If the iterator @a\n    second refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.203 if called on iterators which does not belong\n    to the current JSON value; example: `\"iterators do not fit current value\"`\n    @throw invalid_iterator.204 if called on a primitive type with invalid\n    iterators (i.e., if `first != begin()` and `last != end()`); example:\n    `\"iterators out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: `log(size()) + std::distance(first, last)`\n    - arrays: linear in the distance between @a first and @a last, plus linear\n      in the distance between @a last and end of the container\n    - strings and binary: linear in the length of the member\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType_IteratorType}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template < class IteratorType, typename std::enable_if <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type\n               = 0 >\n    IteratorType erase(IteratorType first, IteratorType last)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()\n                                       || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);\n                    m_value.binary = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,\n                                              last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,\n                                             last.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove element from a JSON object given a key\n\n    Removes elements from a JSON object with the key value @a key.\n\n    @param[in] key value of the elements to remove\n\n    @return Number of elements removed. If @a ObjectType is the default\n    `std::map` type, the return value will always be `0` (@a key was not\n    found) or `1` (@a key was found).\n\n    @post References and iterators to the erased elements are invalidated.\n    Other references and iterators are not affected.\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n\n    @complexity `log(size()) + count(key)`\n\n    @liveexample{The example shows the effect of `erase()`.,erase__key_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    size_type erase(const typename object_t::key_type& key)\n    {\n        // this erase only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            return m_value.object->erase(key);\n        }\n\n        JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief remove element from a JSON array given an index\n\n    Removes element from a JSON array at the index @a idx.\n\n    @param[in] idx index of the element to remove\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n    @throw out_of_range.401 when `idx >= size()`; example: `\"array index 17\n    is out of range\"`\n\n    @complexity Linear in distance between @a idx and the end of the container.\n\n    @liveexample{The example shows the effect of `erase()`.,erase__size_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n\n    @since version 1.0.0\n    */\n    void erase(const size_type idx)\n    {\n        // this erase only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            if (JSON_HEDLEY_UNLIKELY(idx >= size()))\n            {\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n\n            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));\n        }\n        else\n        {\n            JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n\n    ////////////\n    // lookup //\n    ////////////\n\n    /// @name lookup\n    /// @{\n\n    /*!\n    @brief find an element in a JSON object\n\n    Finds an element in a JSON object with key equivalent to @a key. If the\n    element is not found or the JSON value is not an object, end() is\n    returned.\n\n    @note This method always returns @ref end() when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value of the element to search for.\n\n    @return Iterator to an element with key equivalent to @a key. If no such\n    element is found or the JSON value is not an object, past-the-end (see\n    @ref end()) iterator is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `find()` is used.,find__key_type}\n\n    @sa @ref contains(KeyT&&) const -- checks whether a key exists\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    iterator find(KeyT&& key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief find an element in a JSON object\n    @copydoc find(KeyT&&)\n    */\n    template<typename KeyT>\n    const_iterator find(KeyT&& key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief returns the number of occurrences of a key in a JSON object\n\n    Returns the number of elements with key @a key. If ObjectType is the\n    default `std::map` type, the return value will always be `0` (@a key was\n    not found) or `1` (@a key was found).\n\n    @note This method always returns `0` when executed on a JSON type that is\n          not an object.\n\n    @param[in] key key value of the element to count\n\n    @return Number of elements with key @a key. If the JSON value is not an\n    object, the return value will be `0`.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `count()` is used.,count}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    size_type count(KeyT&& key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;\n    }\n\n    /*!\n    @brief check the existence of an element in a JSON object\n\n    Check whether an element exists in a JSON object with key equivalent to\n    @a key. If the element is not found or the JSON value is not an object,\n    false is returned.\n\n    @note This method always returns false when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value to check its existence.\n\n    @return true if an element with specified @a key exists. If no such\n    element with such key is found or the JSON value is not an object,\n    false is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The following code shows an example for `contains()`.,contains}\n\n    @sa @ref find(KeyT&&) -- returns an iterator to an object element\n    @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer\n\n    @since version 3.6.0\n    */\n    template < typename KeyT, typename std::enable_if <\n                   !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int >::type = 0 >\n    bool contains(KeyT && key) const\n    {\n        return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();\n    }\n\n    /*!\n    @brief check the existence of an element in a JSON object given a JSON pointer\n\n    Check whether the given JSON pointer @a ptr can be resolved in the current\n    JSON value.\n\n    @note This method can be executed on any JSON value type.\n\n    @param[in] ptr JSON pointer to check its existence.\n\n    @return true if the JSON pointer can be resolved to a stored value, false\n    otherwise.\n\n    @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The following code shows an example for `contains()`.,contains_json_pointer}\n\n    @sa @ref contains(KeyT &&) const -- checks the existence of a key\n\n    @since version 3.7.0\n    */\n    bool contains(const json_pointer& ptr) const\n    {\n        return ptr.contains(this);\n    }\n\n    /// @}\n\n\n    ///////////////\n    // iterators //\n    ///////////////\n\n    /// @name iterators\n    /// @{\n\n    /*!\n    @brief returns an iterator to the first element\n\n    Returns an iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `begin()`.,begin}\n\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    iterator begin() noexcept\n    {\n        iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cbegin()\n    */\n    const_iterator begin() const noexcept\n    {\n        return cbegin();\n    }\n\n    /*!\n    @brief returns a const iterator to the first element\n\n    Returns a const iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.\n\n    @liveexample{The following code shows an example for `cbegin()`.,cbegin}\n\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    const_iterator cbegin() const noexcept\n    {\n        const_iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to one past the last element\n\n    Returns an iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `end()`.,end}\n\n    @sa @ref cend() -- returns a const iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    iterator end() noexcept\n    {\n        iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cend()\n    */\n    const_iterator end() const noexcept\n    {\n        return cend();\n    }\n\n    /*!\n    @brief returns a const iterator to one past the last element\n\n    Returns a const iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.\n\n    @liveexample{The following code shows an example for `cend()`.,cend}\n\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_iterator cend() const noexcept\n    {\n        const_iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-beginning\n\n    Returns an iterator to the reverse-beginning; that is, the last element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(end())`.\n\n    @liveexample{The following code shows an example for `rbegin()`.,rbegin}\n\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    reverse_iterator rbegin() noexcept\n    {\n        return reverse_iterator(end());\n    }\n\n    /*!\n    @copydoc basic_json::crbegin()\n    */\n    const_reverse_iterator rbegin() const noexcept\n    {\n        return crbegin();\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-end\n\n    Returns an iterator to the reverse-end; that is, one before the first\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(begin())`.\n\n    @liveexample{The following code shows an example for `rend()`.,rend}\n\n    @sa @ref crend() -- returns a const reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    reverse_iterator rend() noexcept\n    {\n        return reverse_iterator(begin());\n    }\n\n    /*!\n    @copydoc basic_json::crend()\n    */\n    const_reverse_iterator rend() const noexcept\n    {\n        return crend();\n    }\n\n    /*!\n    @brief returns a const reverse iterator to the last element\n\n    Returns a const iterator to the reverse-beginning; that is, the last\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.\n\n    @liveexample{The following code shows an example for `crbegin()`.,crbegin}\n\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crbegin() const noexcept\n    {\n        return const_reverse_iterator(cend());\n    }\n\n    /*!\n    @brief returns a const reverse iterator to one before the first\n\n    Returns a const reverse iterator to the reverse-end; that is, one before\n    the first element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.\n\n    @liveexample{The following code shows an example for `crend()`.,crend}\n\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crend() const noexcept\n    {\n        return const_reverse_iterator(cbegin());\n    }\n\n  public:\n    /*!\n    @brief wrapper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without iterator_wrapper:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without iterator proxy:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with iterator proxy:\n\n    @code{cpp}\n    for (auto it : json::iterator_wrapper(j_object))\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example).\n\n    @param[in] ref  reference to a JSON value\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @note The name of this function is not yet final and may change in the\n    future.\n\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use @ref items() instead;\n                that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @copydoc iterator_wrapper(reference)\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @brief helper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without `items()` function:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without `items()` function:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with `items()` function:\n\n    @code{cpp}\n    for (auto& el : j_object.items())\n    {\n        std::cout << \"key: \" << el.key() << \", value:\" << el.value() << '\\n';\n    }\n    @endcode\n\n    The `items()` function also allows to use\n    [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)\n    (C++17):\n\n    @code{cpp}\n    for (auto& [key, val] : j_object.items())\n    {\n        std::cout << \"key: \" << key << \", value:\" << val << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example). For primitive types (e.g., numbers),\n          `key()` returns an empty string.\n\n    @warning Using `items()` on temporary objects is dangerous. Make sure the\n             object's lifetime exeeds the iteration. See\n             <https://github.com/nlohmann/json/issues/2040> for more\n             information.\n\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the function is used.,items}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 3.1.0, structured bindings support since 3.5.0.\n    */\n    iteration_proxy<iterator> items() noexcept\n    {\n        return iteration_proxy<iterator>(*this);\n    }\n\n    /*!\n    @copydoc items()\n    */\n    iteration_proxy<const_iterator> items() const noexcept\n    {\n        return iteration_proxy<const_iterator>(*this);\n    }\n\n    /// @}\n\n\n    //////////////\n    // capacity //\n    //////////////\n\n    /// @name capacity\n    /// @{\n\n    /*!\n    @brief checks whether the container is empty.\n\n    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `true`\n            boolean     | `false`\n            string      | `false`\n            number      | `false`\n            binary      | `false`\n            object      | result of function `object_t::empty()`\n            array       | result of function `array_t::empty()`\n\n    @liveexample{The following code uses `empty()` to check if a JSON\n    object contains any elements.,empty}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `empty()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return whether a string stored as JSON value\n    is empty - it returns whether the JSON container itself is empty which is\n    false in the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `begin() == end()`.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    bool empty() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return true;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::empty()\n                return m_value.array->empty();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::empty()\n                return m_value.object->empty();\n            }\n\n            default:\n            {\n                // all other types are nonempty\n                return false;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the number of elements\n\n    Returns the number of elements in a JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0`\n            boolean     | `1`\n            string      | `1`\n            number      | `1`\n            binary      | `1`\n            object      | result of function object_t::size()\n            array       | result of function array_t::size()\n\n    @liveexample{The following code calls `size()` on the different value\n    types.,size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their size() functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return the length of a string stored as JSON\n    value - it returns the number of elements in the JSON value which is 1 in\n    the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `std::distance(begin(), end())`.\n\n    @sa @ref empty() -- checks whether the container is empty\n    @sa @ref max_size() -- returns the maximal number of elements\n\n    @since version 1.0.0\n    */\n    size_type size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return 0;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::size()\n                return m_value.array->size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::size()\n                return m_value.object->size();\n            }\n\n            default:\n            {\n                // all other types have size 1\n                return 1;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the maximum possible number of elements\n\n    Returns the maximum number of elements a JSON value is able to hold due to\n    system or library implementation limitations, i.e. `std::distance(begin(),\n    end())` for the JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0` (same as `size()`)\n            boolean     | `1` (same as `size()`)\n            string      | `1` (same as `size()`)\n            number      | `1` (same as `size()`)\n            binary      | `1` (same as `size()`)\n            object      | result of function `object_t::max_size()`\n            array       | result of function `array_t::max_size()`\n\n    @liveexample{The following code calls `max_size()` on the different value\n    types. Note the output is implementation specific.,max_size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `max_size()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of returning `b.size()` where `b` is the largest\n      possible JSON value.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    size_type max_size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::array:\n            {\n                // delegate call to array_t::max_size()\n                return m_value.array->max_size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::max_size()\n                return m_value.object->max_size();\n            }\n\n            default:\n            {\n                // all other types have max_size() == size()\n                return size();\n            }\n        }\n    }\n\n    /// @}\n\n\n    ///////////////\n    // modifiers //\n    ///////////////\n\n    /// @name modifiers\n    /// @{\n\n    /*!\n    @brief clears the contents\n\n    Clears the content of a JSON value and resets it to the default value as\n    if @ref basic_json(value_t) would have been called with the current value\n    type from @ref type():\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    binary      | An empty byte vector\n    object      | `{}`\n    array       | `[]`\n\n    @post Has the same effect as calling\n    @code {.cpp}\n    *this = basic_json(type());\n    @endcode\n\n    @liveexample{The example below shows the effect of `clear()` to different\n    JSON types.,clear}\n\n    @complexity Linear in the size of the JSON value.\n\n    @iterators All iterators, pointers and references related to this container\n               are invalidated.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @sa @ref basic_json(value_t) -- constructor that creates an object with the\n        same value than calling `clear()`\n\n    @since version 1.0.0\n    */\n    void clear() noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = 0;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = 0;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = 0.0;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = false;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value.string->clear();\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_value.binary->clear();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array->clear();\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object->clear();\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Appends the given element @a val to the end of the JSON value. If the\n    function is called on a JSON null value, an empty array is created before\n    appending @a val.\n\n    @param[in] val the value to add to the JSON array\n\n    @throw type_error.308 when called on a type other than JSON array or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON array. Note how the `null` value was silently\n    converted to a JSON array.,push_back}\n\n    @since version 1.0.0\n    */\n    void push_back(basic_json&& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (move semantics)\n        m_value.array->push_back(std::move(val));\n        // if val is moved from, basic_json move constructor marks it null so we do not call the destructor\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(basic_json&& val)\n    {\n        push_back(std::move(val));\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    void push_back(const basic_json& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.array->push_back(val);\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(const basic_json& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    Inserts the given element @a val to the JSON object. If the function is\n    called on a JSON null value, an empty object is created before inserting\n    @a val.\n\n    @param[in] val the value to add to the JSON object\n\n    @throw type_error.308 when called on a type other than JSON object or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON object. Note how the `null` value was silently\n    converted to a JSON object.,push_back__object_t__value}\n\n    @since version 1.0.0\n    */\n    void push_back(const typename object_t::value_type& val)\n    {\n        // push_back only works for null objects or objects\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.object->insert(val);\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(const typename object_t::value_type&)\n    */\n    reference operator+=(const typename object_t::value_type& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    This function allows to use `push_back` with an initializer list. In case\n\n    1. the current value is an object,\n    2. the initializer list @a init contains only two elements, and\n    3. the first element of @a init is a string,\n\n    @a init is converted into an object element and added using\n    @ref push_back(const typename object_t::value_type&). Otherwise, @a init\n    is converted to a JSON value and added using @ref push_back(basic_json&&).\n\n    @param[in] init  an initializer list\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @note This function is required to resolve an ambiguous overload error,\n          because pairs like `{\"key\", \"value\"}` can be both interpreted as\n          `object_t::value_type` or `std::initializer_list<basic_json>`, see\n          https://github.com/nlohmann/json/issues/235 for more information.\n\n    @liveexample{The example shows how initializer lists are treated as\n    objects when possible.,push_back__initializer_list}\n    */\n    void push_back(initializer_list_t init)\n    {\n        if (is_object() && init.size() == 2 && (*init.begin())->is_string())\n        {\n            basic_json&& key = init.begin()->moved_or_copied();\n            push_back(typename object_t::value_type(\n                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n        }\n        else\n        {\n            push_back(basic_json(init));\n        }\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(initializer_list_t)\n    */\n    reference operator+=(initializer_list_t init)\n    {\n        push_back(init);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Creates a JSON value from the passed parameters @a args to the end of the\n    JSON value. If the function is called on a JSON null value, an empty array\n    is created before appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return reference to the inserted element\n\n    @throw type_error.311 when called on a type other than JSON array or\n    null; example: `\"cannot use emplace_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` can be used to add\n    elements to a JSON array. Note how the `null` value was silently converted\n    to a JSON array.,emplace_back}\n\n    @since version 2.0.8, returns reference since 3.7.0\n    */\n    template<class... Args>\n    reference emplace_back(Args&& ... args)\n    {\n        // emplace_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n#ifdef JSON_HAS_CPP_17\n        return m_value.array->emplace_back(std::forward<Args>(args)...);\n#else\n        m_value.array->emplace_back(std::forward<Args>(args)...);\n        return m_value.array->back();\n#endif\n    }\n\n    /*!\n    @brief add an object to an object if key does not exist\n\n    Inserts a new element into a JSON object constructed in-place with the\n    given @a args if there is no element with the key in the container. If the\n    function is called on a JSON null value, an empty object is created before\n    appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return a pair consisting of an iterator to the inserted element, or the\n            already-existing element if no insertion happened, and a bool\n            denoting whether the insertion took place.\n\n    @throw type_error.311 when called on a type other than JSON object or\n    null; example: `\"cannot use emplace() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `emplace()` can be used to add elements\n    to a JSON object. Note how the `null` value was silently converted to a\n    JSON object. Further note how no value is added if there was already one\n    value stored with the same key.,emplace}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&& ... args)\n    {\n        // emplace only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        auto res = m_value.object->emplace(std::forward<Args>(args)...);\n        // create result iterator and set iterator to the result of emplace\n        auto it = begin();\n        it.m_it.object_iterator = res.first;\n\n        // return pair of iterator and boolean\n        return {it, res.second};\n    }\n\n    /// Helper for insertion of an iterator\n    /// @note: This uses std::distance to support GCC 4.8,\n    ///        see https://github.com/nlohmann/json/pull/1257\n    template<typename... Args>\n    iterator insert_iterator(const_iterator pos, Args&& ... args)\n    {\n        iterator result(this);\n        JSON_ASSERT(m_value.array != nullptr);\n\n        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);\n        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n        result.m_it.array_iterator = m_value.array->begin() + insert_pos;\n\n        // This could have been written as:\n        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n        return result;\n    }\n\n    /*!\n    @brief inserts element\n\n    Inserts element @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] val element to insert\n    @return iterator pointing to the inserted @a val.\n\n    @throw type_error.309 if called on JSON values other than arrays;\n    example: `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Constant plus linear in the distance between @a pos and end of\n    the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts element\n    @copydoc insert(const_iterator, const basic_json&)\n    */\n    iterator insert(const_iterator pos, basic_json&& val)\n    {\n        return insert(pos, val);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts @a cnt copies of @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] cnt number of copies of @a val to insert\n    @param[in] val element to insert\n    @return iterator pointing to the first element inserted, or @a pos if\n    `cnt==0`\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Linear in @a cnt plus linear in the distance between @a pos\n    and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__count}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, cnt, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)` before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n    @throw invalid_iterator.211 if @a first or @a last are iterators into\n    container for which insert is called; example: `\"passed iterators may not\n    belong to container\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `first==last`\n\n    @complexity Linear in `std::distance(first, last)` plus linear in the\n    distance between @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const_iterator first, const_iterator last)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))\n        {\n            JSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from initializer list @a ilist before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] ilist initializer list to insert the values from\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `ilist` is empty\n\n    @complexity Linear in `ilist.size()` plus linear in the distance between\n    @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__ilist}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, initializer_list_t ilist)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, ilist.begin(), ilist.end());\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)`.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than objects; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number\n    of elements to insert.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range_object}\n\n    @since version 3.0.0\n    */\n    void insert(const_iterator first, const_iterator last)\n    {\n        // insert only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from JSON object @a j and overwrites existing keys.\n\n    @param[in] j  JSON object to read values from\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_reference j)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n        if (JSON_HEDLEY_UNLIKELY(!j.is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(j.type_name())));\n        }\n\n        for (auto it = j.cbegin(); it != j.cend(); ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from from range `[first, last)` and overwrites existing\n    keys.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used__range.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_iterator first, const_iterator last)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()\n                                 || !last.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        for (auto it = first; it != last; ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    void swap(reference other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        std::swap(m_type, other.m_type);\n        std::swap(m_value, other.m_value);\n        assert_invariant();\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value from @a left with those of @a right. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated. implemented as a friend function callable via ADL.\n\n    @param[in,out] left JSON value to exchange the contents with\n    @param[in,out] right JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    friend void swap(reference left, reference right) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        left.swap(right);\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON array with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other array to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an array; example: `\"cannot\n    use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how arrays can be swapped with\n    `swap()`.,swap__array_t}\n\n    @since version 1.0.0\n    */\n    void swap(array_t& other)\n    {\n        // swap only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            std::swap(*(m_value.array), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON object with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other object to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an object; example:\n    `\"cannot use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how objects can be swapped with\n    `swap()`.,swap__object_t}\n\n    @since version 1.0.0\n    */\n    void swap(object_t& other)\n    {\n        // swap only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            std::swap(*(m_value.object), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other string to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__string_t}\n\n    @since version 1.0.0\n    */\n    void swap(string_t& other)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_string()))\n        {\n            std::swap(*(m_value.string), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other binary to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__binary_t}\n\n    @since version 3.8.0\n    */\n    void swap(binary_t& other)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            std::swap(*(m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @copydoc swap(binary_t)\n    void swap(typename binary_t::container_type& other)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            std::swap(*(m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n  public:\n    //////////////////////////////////////////\n    // lexicographical comparison operators //\n    //////////////////////////////////////////\n\n    /// @name lexicographical comparison operators\n    /// @{\n\n    /*!\n    @brief comparison: equal\n\n    Compares two JSON values for equality according to the following rules:\n    - Two JSON values are equal if (1) they are from the same type and (2)\n      their stored values are the same according to their respective\n      `operator==`.\n    - Integer and floating-point numbers are automatically converted before\n      comparison. Note that two NaN values are always treated as unequal.\n    - Two JSON null values are equal.\n\n    @note Floating-point inside JSON values numbers are compared with\n    `json::number_float_t::operator==` which is `double::operator==` by\n    default. To compare floating-point while respecting an epsilon, an alternative\n    [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39)\n    could be used, for instance\n    @code {.cpp}\n    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>\n    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept\n    {\n        return std::abs(a - b) <= epsilon;\n    }\n    @endcode\n    Or you can self-defined operator equal function like this:\n    @code {.cpp}\n    bool my_equal(const_reference lhs, const_reference rhs) {\n    const auto lhs_type lhs.type();\n    const auto rhs_type rhs.type();\n    if (lhs_type == rhs_type) {\n        switch(lhs_type)\n            // self_defined case\n            case value_t::number_float:\n                return std::abs(lhs - rhs) <= std::numeric_limits<float>::epsilon();\n            // other cases remain the same with the original\n            ...\n    }\n    ...\n    }\n    @endcode\n\n    @note NaN values never compare equal to themselves or to other NaN values.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are equal\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Linear.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__equal}\n\n    @since version 1.0.0\n    */\n    friend bool operator==(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return *lhs.m_value.array == *rhs.m_value.array;\n\n                case value_t::object:\n                    return *lhs.m_value.object == *rhs.m_value.object;\n\n                case value_t::null:\n                    return true;\n\n                case value_t::string:\n                    return *lhs.m_value.string == *rhs.m_value.string;\n\n                case value_t::boolean:\n                    return lhs.m_value.boolean == rhs.m_value.boolean;\n\n                case value_t::number_integer:\n                    return lhs.m_value.number_integer == rhs.m_value.number_integer;\n\n                case value_t::number_unsigned:\n                    return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;\n\n                case value_t::number_float:\n                    return lhs.m_value.number_float == rhs.m_value.number_float;\n\n                case value_t::binary:\n                    return *lhs.m_value.binary == *rhs.m_value.binary;\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n\n        return false;\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs == basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) == rhs;\n    }\n\n    /*!\n    @brief comparison: not equal\n\n    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are not equal\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__notequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs != basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) != rhs;\n    }\n\n    /*!\n    @brief comparison: less than\n\n    Compares whether one JSON value @a lhs is less than another JSON value @a\n    rhs according to the following rules:\n    - If @a lhs and @a rhs have the same type, the values are compared using\n      the default `<` operator.\n    - Integer and floating-point numbers are automatically converted before\n      comparison\n    - In case @a lhs and @a rhs have different types, the values are ignored\n      and the order of the types is considered, see\n      @ref operator<(const value_t, const value_t).\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__less}\n\n    @since version 1.0.0\n    */\n    friend bool operator<(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    // note parentheses are necessary, see\n                    // https://github.com/nlohmann/json/issues/1530\n                    return (*lhs.m_value.array) < (*rhs.m_value.array);\n\n                case value_t::object:\n                    return (*lhs.m_value.object) < (*rhs.m_value.object);\n\n                case value_t::null:\n                    return false;\n\n                case value_t::string:\n                    return (*lhs.m_value.string) < (*rhs.m_value.string);\n\n                case value_t::boolean:\n                    return (lhs.m_value.boolean) < (rhs.m_value.boolean);\n\n                case value_t::number_integer:\n                    return (lhs.m_value.number_integer) < (rhs.m_value.number_integer);\n\n                case value_t::number_unsigned:\n                    return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned);\n\n                case value_t::number_float:\n                    return (lhs.m_value.number_float) < (rhs.m_value.number_float);\n\n                case value_t::binary:\n                    return (*lhs.m_value.binary) < (*rhs.m_value.binary);\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;\n        }\n\n        // We only reach this line if we cannot compare values. In that case,\n        // we compare types. Note we have to call the operator explicitly,\n        // because MSVC has problems otherwise.\n        return operator<(lhs_type, rhs_type);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs < basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) < rhs;\n    }\n\n    /*!\n    @brief comparison: less than or equal\n\n    Compares whether one JSON value @a lhs is less than or equal to another\n    JSON value by calculating `not (rhs < lhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greater}\n\n    @since version 1.0.0\n    */\n    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(rhs < lhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs <= basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) <= rhs;\n    }\n\n    /*!\n    @brief comparison: greater than\n\n    Compares whether one JSON value @a lhs is greater than another\n    JSON value by calculating `not (lhs <= rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__lessequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs > basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) > rhs;\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n\n    Compares whether one JSON value @a lhs is greater than or equal to another\n    JSON value by calculating `not (lhs < rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greaterequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return !(lhs < rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return lhs >= basic_json(rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) >= rhs;\n    }\n\n    /// @}\n\n    ///////////////////\n    // serialization //\n    ///////////////////\n\n    /// @name serialization\n    /// @{\n\n    /*!\n    @brief serialize to stream\n\n    Serialize the given JSON value @a j to the output stream @a o. The JSON\n    value will be serialized using the @ref dump member function.\n\n    - The indentation of the output can be controlled with the member variable\n      `width` of the output stream @a o. For instance, using the manipulator\n      `std::setw(4)` on @a o sets the indentation level to `4` and the\n      serialization result is the same as calling `dump(4)`.\n\n    - The indentation character can be controlled with the member variable\n      `fill` of the output stream @a o. For instance, the manipulator\n      `std::setfill('\\\\t')` sets indentation to use a tab character rather than\n      the default space character.\n\n    @param[in,out] o  stream to serialize to\n    @param[in] j  JSON value to serialize\n\n    @return the stream @a o\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @liveexample{The example below shows the serialization with different\n    parameters to `width` to adjust the indentation level.,operator_serialize}\n\n    @since version 1.0.0; indentation character added in version 3.0.0\n    */\n    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n    {\n        // read width member and use it as indentation parameter if nonzero\n        const bool pretty_print = o.width() > 0;\n        const auto indentation = pretty_print ? o.width() : 0;\n\n        // reset width to 0 for subsequent calls to this stream\n        o.width(0);\n\n        // do the actual serialization\n        serializer s(detail::output_adapter<char>(o), o.fill());\n        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n        return o;\n    }\n\n    /*!\n    @brief serialize to stream\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use\n                @ref operator<<(std::ostream&, const basic_json&)\n                instead; that is, replace calls like `j >> o;` with `o << j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))\n    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n    {\n        return o << j;\n    }\n\n    /// @}\n\n\n    /////////////////////\n    // deserialization //\n    /////////////////////\n\n    /// @name deserialization\n    /// @{\n\n    /*!\n    @brief deserialize from a compatible input\n\n    @tparam InputType A compatible input, for instance\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i  input to read from\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb or reading from the input @a i has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an array.,parse__array__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__string__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__istream__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}\n\n    @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to\n    ignore comments.\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(InputType&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    /*!\n    @brief deserialize from a pair of character iterators\n\n    The value_type of the iterator must be a integral type with size of 1, 2 or\n    4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32.\n\n    @param[in] first iterator to start of character range\n    @param[in] last  iterator to end of character range\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(IteratorType first,\n                            IteratorType last,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))\n    static basic_json parse(detail::span_input_adapter&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);\n        return result;\n    }\n\n    /*!\n    @brief check if the input is valid JSON\n\n    Unlike the @ref parse(InputType&&, const parser_callback_t,const bool)\n    function, this function neither throws an exception in case of invalid JSON\n    input (i.e., a parse error) nor creates diagnostic information.\n\n    @tparam InputType A compatible input, for instance\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i input to read from\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default)\n\n    @return Whether the input read from @a i is valid JSON.\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `accept()` function reading\n    from a string.,accept__string}\n    */\n    template<typename InputType>\n    static bool accept(InputType&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    template<typename IteratorType>\n    static bool accept(IteratorType first, IteratorType last,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))\n    static bool accept(detail::span_input_adapter&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(i.get(), nullptr, false, ignore_comments).accept(true);\n    }\n\n    /*!\n    @brief generate SAX events\n\n    The SAX event lister must follow the interface of @ref json_sax.\n\n    This function reads from a compatible input. Examples are:\n    - an std::istream object\n    - a FILE pointer\n    - a C-style array of characters\n    - a pointer to a null-terminated string of single byte characters\n    - an object obj for which begin(obj) and end(obj) produces a valid pair of\n      iterators.\n\n    @param[in] i  input to read from\n    @param[in,out] sax  SAX event listener\n    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)\n    @param[in] strict  whether the input has to be consumed completely\n    @param[in] ignore_comments  whether comments should be ignored and treated\n    like whitespace (true) or yield a parse error (true); (optional, false by\n    default); only applies to the JSON file format.\n\n    @return return value of the last processed SAX event\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has\n    a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `sax_parse()` function\n    reading from string and processing the events with a user-defined SAX\n    event consumer.,sax_parse}\n\n    @since version 3.2.0\n    */\n    template <typename InputType, typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(InputType&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n\n    template<class IteratorType, class SAX>\n    JSON_HEDLEY_NON_NULL(3)\n    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n\n    template <typename SAX>\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = i.get();\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);\n    }\n\n    /*!\n    @brief deserialize from stream\n    @deprecated This stream operator is deprecated and will be removed in\n                version 4.0.0 of the library. Please use\n                @ref operator>>(std::istream&, basic_json&)\n                instead; that is, replace calls like `j << i;` with `i >> j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))\n    friend std::istream& operator<<(basic_json& j, std::istream& i)\n    {\n        return operator>>(i, j);\n    }\n\n    /*!\n    @brief deserialize from stream\n\n    Deserializes an input stream to a JSON value.\n\n    @param[in,out] i  input stream to read a serialized JSON value from\n    @param[in,out] j  JSON value to write the deserialized input to\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below shows how a JSON value is constructed by\n    reading a serialization from a stream.,operator_deserialize}\n\n    @sa parse(std::istream&, const parser_callback_t) for a variant with a\n    parser callback function to filter values while parsing\n\n    @since version 1.0.0\n    */\n    friend std::istream& operator>>(std::istream& i, basic_json& j)\n    {\n        parser(detail::input_adapter(i)).parse(false, j);\n        return i;\n    }\n\n    /// @}\n\n    ///////////////////////////\n    // convenience functions //\n    ///////////////////////////\n\n    /*!\n    @brief return the type as string\n\n    Returns the type name as string to be used in error messages - usually to\n    indicate that a function was called on a wrong JSON type.\n\n    @return a string representation of a the @a m_type member:\n            Value type  | return value\n            ----------- | -------------\n            null        | `\"null\"`\n            boolean     | `\"boolean\"`\n            string      | `\"string\"`\n            number      | `\"number\"` (for all number types)\n            object      | `\"object\"`\n            array       | `\"array\"`\n            binary      | `\"binary\"`\n            discarded   | `\"discarded\"`\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Constant.\n\n    @liveexample{The following code exemplifies `type_name()` for all JSON\n    types.,type_name}\n\n    @sa @ref type() -- return the type of the JSON value\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n\n    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`\n    since 3.0.0\n    */\n    JSON_HEDLEY_RETURNS_NON_NULL\n    const char* type_name() const noexcept\n    {\n        {\n            switch (m_type)\n            {\n                case value_t::null:\n                    return \"null\";\n                case value_t::object:\n                    return \"object\";\n                case value_t::array:\n                    return \"array\";\n                case value_t::string:\n                    return \"string\";\n                case value_t::boolean:\n                    return \"boolean\";\n                case value_t::binary:\n                    return \"binary\";\n                case value_t::discarded:\n                    return \"discarded\";\n                default:\n                    return \"number\";\n            }\n        }\n    }\n\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    //////////////////////\n    // member variables //\n    //////////////////////\n\n    /// the type of the current element\n    value_t m_type = value_t::null;\n\n    /// the value of the current element\n    json_value m_value = {};\n\n    //////////////////////////////////////////\n    // binary serialization/deserialization //\n    //////////////////////////////////////////\n\n    /// @name binary serialization/deserialization support\n    /// @{\n\n  public:\n    /*!\n    @brief create a CBOR serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise\n    Binary Object Representation) serialization format. CBOR is a binary\n    serialization format which aims to be more compact than JSON itself, yet\n    more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    CBOR types according to the CBOR specification (RFC 7049):\n\n    JSON value type | value/range                                | CBOR type                          | first byte\n    --------------- | ------------------------------------------ | ---------------------------------- | ---------------\n    null            | `null`                                     | Null                               | 0xF6\n    boolean         | `true`                                     | True                               | 0xF5\n    boolean         | `false`                                    | False                              | 0xF4\n    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B\n    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A\n    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39\n    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38\n    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37\n    number_integer  | 0..23                                      | Integer                            | 0x00..0x17\n    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17\n    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_float    | *any value representable by a float*       | Single-Precision Float             | 0xFA\n    number_float    | *any value NOT representable by a float*   | Double-Precision Float             | 0xFB\n    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77\n    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78\n    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79\n    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A\n    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B\n    array           | *size*: 0..23                              | array                              | 0x80..0x97\n    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98\n    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99\n    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A\n    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B\n    object          | *size*: 0..23                              | map                                | 0xA0..0xB7\n    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8\n    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9\n    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA\n    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB\n    binary          | *size*: 0..23                              | byte string                        | 0x40..0x57\n    binary          | *size*: 23..255                            | byte string (1 byte follow)        | 0x58\n    binary          | *size*: 256..65535                         | byte string (2 bytes follow)       | 0x59\n    binary          | *size*: 65536..4294967295                  | byte string (4 bytes follow)       | 0x5A\n    binary          | *size*: 4294967296..18446744073709551615   | byte string (8 bytes follow)       | 0x5B\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a CBOR value.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The following CBOR types are not used in the conversion:\n          - UTF-8 strings terminated by \"break\" (0x7F)\n          - arrays terminated by \"break\" (0x9F)\n          - maps terminated by \"break\" (0xBF)\n          - byte strings terminated by \"break\" (0x5F)\n          - date/time (0xC0..0xC1)\n          - bignum (0xC2..0xC3)\n          - decimal fraction (0xC4)\n          - bigfloat (0xC5)\n          - expected conversions (0xD5..0xD7)\n          - simple values (0xE0..0xF3, 0xF8)\n          - undefined (0xF7)\n          - half-precision floats (0xF9)\n          - break (0xFF)\n\n    @param[in] j  JSON value to serialize\n    @return CBOR serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in CBOR format.,to_cbor}\n\n    @sa http://cbor.io\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the\n        analogous deserialization\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9; compact representation of floating-point numbers\n           since version 3.8.0\n    */\n    static std::vector<uint8_t> to_cbor(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_cbor(j, result);\n        return result;\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_cbor(j);\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_cbor(j);\n    }\n\n    /*!\n    @brief create a MessagePack serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the MessagePack\n    serialization format. MessagePack is a binary serialization format which\n    aims to be more compact than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    MessagePack types according to the MessagePack specification:\n\n    JSON value type | value/range                       | MessagePack type | first byte\n    --------------- | --------------------------------- | ---------------- | ----------\n    null            | `null`                            | nil              | 0xC0\n    boolean         | `true`                            | true             | 0xC3\n    boolean         | `false`                           | false            | 0xC2\n    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3\n    number_integer  | -2147483648..-32769               | int32            | 0xD2\n    number_integer  | -32768..-129                      | int16            | 0xD1\n    number_integer  | -128..-33                         | int8             | 0xD0\n    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF\n    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F\n    number_integer  | 128..255                          | uint 8           | 0xCC\n    number_integer  | 256..65535                        | uint 16          | 0xCD\n    number_integer  | 65536..4294967295                 | uint 32          | 0xCE\n    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F\n    number_unsigned | 128..255                          | uint 8           | 0xCC\n    number_unsigned | 256..65535                        | uint 16          | 0xCD\n    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE\n    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_float    | *any value representable by a float*     | float 32 | 0xCA\n    number_float    | *any value NOT representable by a float* | float 64 | 0xCB\n    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF\n    string          | *length*: 32..255                 | str 8            | 0xD9\n    string          | *length*: 256..65535              | str 16           | 0xDA\n    string          | *length*: 65536..4294967295       | str 32           | 0xDB\n    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F\n    array           | *size*: 16..65535                 | array 16         | 0xDC\n    array           | *size*: 65536..4294967295         | array 32         | 0xDD\n    object          | *size*: 0..15                     | fix map          | 0x80..0x8F\n    object          | *size*: 16..65535                 | map 16           | 0xDE\n    object          | *size*: 65536..4294967295         | map 32           | 0xDF\n    binary          | *size*: 0..255                    | bin 8            | 0xC4\n    binary          | *size*: 256..65535                | bin 16           | 0xC5\n    binary          | *size*: 65536..4294967295         | bin 32           | 0xC6\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a MessagePack value.\n\n    @note The following values can **not** be converted to a MessagePack value:\n          - strings with more than 4294967295 bytes\n          - byte strings with more than 4294967295 bytes\n          - arrays with more than 4294967295 elements\n          - objects with more than 4294967295 elements\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in MessagePack format.,to_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref from_msgpack for the analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<uint8_t> to_msgpack(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_msgpack(j, result);\n        return result;\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_msgpack(j);\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_msgpack(j);\n    }\n\n    /*!\n    @brief create a UBJSON serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the UBJSON\n    (Universal Binary JSON) serialization format. UBJSON aims to be more compact\n    than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    UBJSON types according to the UBJSON specification:\n\n    JSON value type | value/range                       | UBJSON type | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | `Z`\n    boolean         | `true`                            | true        | `T`\n    boolean         | `false`                           | false       | `F`\n    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`\n    number_integer  | -2147483648..-32769               | int32       | `l`\n    number_integer  | -32768..-129                      | int16       | `I`\n    number_integer  | -128..127                         | int8        | `i`\n    number_integer  | 128..255                          | uint8       | `U`\n    number_integer  | 256..32767                        | int16       | `I`\n    number_integer  | 32768..2147483647                 | int32       | `l`\n    number_integer  | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 0..127                            | int8        | `i`\n    number_unsigned | 128..255                          | uint8       | `U`\n    number_unsigned | 256..32767                        | int16       | `I`\n    number_unsigned | 32768..2147483647                 | int32       | `l`\n    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 2147483649..18446744073709551615  | high-precision | `H`\n    number_float    | *any value*                       | float64     | `D`\n    string          | *with shortest length indicator*  | string      | `S`\n    array           | *see notes on optimized format*   | array       | `[`\n    object          | *see notes on optimized format*   | map         | `{`\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a UBJSON value.\n\n    @note The following values can **not** be converted to a UBJSON value:\n          - strings with more than 9223372036854775807 bytes (theoretical)\n\n    @note The following markers are not used in the conversion:\n          - `Z`: no-op values are not created.\n          - `C`: single-byte strings are serialized with `S` markers.\n\n    @note Any UBJSON output created @ref to_ubjson can be successfully parsed\n          by @ref from_ubjson.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The optimized formats for containers are supported: Parameter\n          @a use_size adds size information to the beginning of a container and\n          removes the closing marker. Parameter @a use_type further checks\n          whether all elements of a container have the same type and adds the\n          type marker to the beginning of the container. The @a use_type\n          parameter must only be used together with @a use_size = true. Note\n          that @a use_size = true alone may result in larger representations -\n          the benefit of this parameter is that the receiving side is\n          immediately informed on the number of elements of the container.\n\n    @note If the JSON data contains the binary type, the value stored is a list\n          of integers, as suggested by the UBJSON documentation.  In particular,\n          this means that serialization and the deserialization of a JSON\n          containing binary values into UBJSON and back will result in a\n          different JSON object.\n\n    @param[in] j  JSON value to serialize\n    @param[in] use_size  whether to add size annotations to container types\n    @param[in] use_type  whether to add type annotations to container types\n                         (must be combined with @a use_size = true)\n    @return UBJSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in UBJSON format.,to_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\n    @since version 3.1.0\n    */\n    static std::vector<uint8_t> to_ubjson(const basic_json& j,\n                                          const bool use_size = false,\n                                          const bool use_type = false)\n    {\n        std::vector<uint8_t> result;\n        to_ubjson(j, result, use_size, use_type);\n        return result;\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type);\n    }\n\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and returns a vector\n           containing the corresponding BSON-representation.\n\n    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are\n    stored as a single entity (a so-called document).\n\n    The library uses the following mapping from JSON values types to BSON types:\n\n    JSON value type | value/range                       | BSON type   | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | 0x0A\n    boolean         | `true`, `false`                   | boolean     | 0x08\n    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12\n    number_integer  | -2147483648..2147483647           | int32       | 0x10\n    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 0..2147483647                     | int32       | 0x10\n    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 9223372036854775808..18446744073709551615| --   | --\n    number_float    | *any value*                       | double      | 0x01\n    string          | *any value*                       | string      | 0x02\n    array           | *any value*                       | document    | 0x04\n    object          | *any value*                       | document    | 0x03\n    binary          | *any value*                       | binary      | 0x05\n\n    @warning The mapping is **incomplete**, since only JSON-objects (and things\n    contained therein) can be serialized to BSON.\n    Also, integers larger than 9223372036854775807 cannot be serialized to BSON,\n    and the keys may not contain U+0000, since they are serialized a\n    zero-terminated c-strings.\n\n    @throw out_of_range.407  if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`\n    @throw out_of_range.409  if a key in `j` contains a NULL (U+0000)\n    @throw type_error.317    if `!j.is_object()`\n\n    @pre The input `j` is required to be an object: `j.is_object() == true`.\n\n    @note Any BSON output created via @ref to_bson can be successfully parsed\n          by @ref from_bson.\n\n    @param[in] j  JSON value to serialize\n    @return BSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in BSON format.,to_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the\n        analogous deserialization\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n    @sa @ref to_cbor(const basic_json&) for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    */\n    static std::vector<uint8_t> to_bson(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_bson(j, result);\n        return result;\n    }\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and forwards the\n           corresponding BSON-representation to the given output_adapter `o`.\n    @param j The JSON object to convert to BSON.\n    @param o The output adapter that receives the binary BSON representation.\n    @pre The input `j` shall be an object: `j.is_object() == true`\n    @sa @ref to_bson(const basic_json&)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_bson(j);\n    }\n\n    /*!\n    @copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_bson(j);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in CBOR format\n\n    Deserializes a given input @a i to a JSON value using the CBOR (Concise\n    Binary Object Representation) serialization format.\n\n    The library maps CBOR types to JSON value types as follows:\n\n    CBOR type              | JSON value type | first byte\n    ---------------------- | --------------- | ----------\n    Integer                | number_unsigned | 0x00..0x17\n    Unsigned integer       | number_unsigned | 0x18\n    Unsigned integer       | number_unsigned | 0x19\n    Unsigned integer       | number_unsigned | 0x1A\n    Unsigned integer       | number_unsigned | 0x1B\n    Negative integer       | number_integer  | 0x20..0x37\n    Negative integer       | number_integer  | 0x38\n    Negative integer       | number_integer  | 0x39\n    Negative integer       | number_integer  | 0x3A\n    Negative integer       | number_integer  | 0x3B\n    Byte string            | binary          | 0x40..0x57\n    Byte string            | binary          | 0x58\n    Byte string            | binary          | 0x59\n    Byte string            | binary          | 0x5A\n    Byte string            | binary          | 0x5B\n    UTF-8 string           | string          | 0x60..0x77\n    UTF-8 string           | string          | 0x78\n    UTF-8 string           | string          | 0x79\n    UTF-8 string           | string          | 0x7A\n    UTF-8 string           | string          | 0x7B\n    UTF-8 string           | string          | 0x7F\n    array                  | array           | 0x80..0x97\n    array                  | array           | 0x98\n    array                  | array           | 0x99\n    array                  | array           | 0x9A\n    array                  | array           | 0x9B\n    array                  | array           | 0x9F\n    map                    | object          | 0xA0..0xB7\n    map                    | object          | 0xB8\n    map                    | object          | 0xB9\n    map                    | object          | 0xBA\n    map                    | object          | 0xBB\n    map                    | object          | 0xBF\n    False                  | `false`         | 0xF4\n    True                   | `true`          | 0xF5\n    Null                   | `null`          | 0xF6\n    Half-Precision Float   | number_float    | 0xF9\n    Single-Precision Float | number_float    | 0xFA\n    Double-Precision Float | number_float    | 0xFB\n\n    @warning The mapping is **incomplete** in the sense that not all CBOR\n             types can be converted to a JSON value. The following CBOR types\n             are not supported and will yield parse errors (parse_error.112):\n             - date/time (0xC0..0xC1)\n             - bignum (0xC2..0xC3)\n             - decimal fraction (0xC4)\n             - bigfloat (0xC5)\n             - expected conversions (0xD5..0xD7)\n             - simple values (0xE0..0xF3, 0xF8)\n             - undefined (0xF7)\n\n    @warning CBOR allows map keys of any type, whereas JSON only allows\n             strings as keys in object values. Therefore, CBOR maps with keys\n             other than UTF-8 strings are rejected (parse_error.113).\n\n    @note Any CBOR output created @ref to_cbor can be successfully parsed by\n          @ref from_cbor.\n\n    @param[in] i  an input in CBOR format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n    @param[in] tag_handler how to treat CBOR tags (optional, error by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from CBOR were\n    used in the given input @a v or if the input is not valid CBOR\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in CBOR\n    format to a JSON value.,from_cbor}\n\n    @sa http://cbor.io\n    @sa @ref to_cbor(const basic_json&) for the analogous serialization\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the\n        related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0; added @a tag_handler parameter since 3.9.0.\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);\n    }\n\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in MessagePack format\n\n    Deserializes a given input @a i to a JSON value using the MessagePack\n    serialization format.\n\n    The library maps MessagePack types to JSON value types as follows:\n\n    MessagePack type | JSON value type | first byte\n    ---------------- | --------------- | ----------\n    positive fixint  | number_unsigned | 0x00..0x7F\n    fixmap           | object          | 0x80..0x8F\n    fixarray         | array           | 0x90..0x9F\n    fixstr           | string          | 0xA0..0xBF\n    nil              | `null`          | 0xC0\n    false            | `false`         | 0xC2\n    true             | `true`          | 0xC3\n    float 32         | number_float    | 0xCA\n    float 64         | number_float    | 0xCB\n    uint 8           | number_unsigned | 0xCC\n    uint 16          | number_unsigned | 0xCD\n    uint 32          | number_unsigned | 0xCE\n    uint 64          | number_unsigned | 0xCF\n    int 8            | number_integer  | 0xD0\n    int 16           | number_integer  | 0xD1\n    int 32           | number_integer  | 0xD2\n    int 64           | number_integer  | 0xD3\n    str 8            | string          | 0xD9\n    str 16           | string          | 0xDA\n    str 32           | string          | 0xDB\n    array 16         | array           | 0xDC\n    array 32         | array           | 0xDD\n    map 16           | object          | 0xDE\n    map 32           | object          | 0xDF\n    bin 8            | binary          | 0xC4\n    bin 16           | binary          | 0xC5\n    bin 32           | binary          | 0xC6\n    ext 8            | binary          | 0xC7\n    ext 16           | binary          | 0xC8\n    ext 32           | binary          | 0xC9\n    fixext 1         | binary          | 0xD4\n    fixext 2         | binary          | 0xD5\n    fixext 4         | binary          | 0xD6\n    fixext 8         | binary          | 0xD7\n    fixext 16        | binary          | 0xD8\n    negative fixint  | number_integer  | 0xE0-0xFF\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @param[in] i  an input in MessagePack format convertible to an input\n                  adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from MessagePack were\n    used in the given input @a i or if the input is not valid MessagePack\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    MessagePack format to a JSON value.,from_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref to_msgpack(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for\n        the related UBJSON format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(InputType&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(IteratorType first, IteratorType last,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(const T* ptr, std::size_t len,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(detail::span_input_adapter&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in UBJSON format\n\n    Deserializes a given input @a i to a JSON value using the UBJSON (Universal\n    Binary JSON) serialization format.\n\n    The library maps UBJSON types to JSON value types as follows:\n\n    UBJSON type | JSON value type                         | marker\n    ----------- | --------------------------------------- | ------\n    no-op       | *no value, next value is read*          | `N`\n    null        | `null`                                  | `Z`\n    false       | `false`                                 | `F`\n    true        | `true`                                  | `T`\n    float32     | number_float                            | `d`\n    float64     | number_float                            | `D`\n    uint8       | number_unsigned                         | `U`\n    int8        | number_integer                          | `i`\n    int16       | number_integer                          | `I`\n    int32       | number_integer                          | `l`\n    int64       | number_integer                          | `L`\n    high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H'\n    string      | string                                  | `S`\n    char        | string                                  | `C`\n    array       | array (optimized values are supported)  | `[`\n    object      | object (optimized values are supported) | `{`\n\n    @note The mapping is **complete** in the sense that any UBJSON value can\n          be converted to a JSON value.\n\n    @param[in] i  an input in UBJSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if a parse error occurs\n    @throw parse_error.113 if a string could not be parsed successfully\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    UBJSON format to a JSON value.,from_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(InputType&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(IteratorType first, IteratorType last,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(const T* ptr, std::size_t len,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(detail::span_input_adapter&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n    /*!\n    @brief Create a JSON value from an input in BSON format\n\n    Deserializes a given input @a i to a JSON value using the BSON (Binary JSON)\n    serialization format.\n\n    The library maps BSON record types to JSON value types as follows:\n\n    BSON type       | BSON marker byte | JSON value type\n    --------------- | ---------------- | ---------------------------\n    double          | 0x01             | number_float\n    string          | 0x02             | string\n    document        | 0x03             | object\n    array           | 0x04             | array\n    binary          | 0x05             | binary\n    undefined       | 0x06             | still unsupported\n    ObjectId        | 0x07             | still unsupported\n    boolean         | 0x08             | boolean\n    UTC Date-Time   | 0x09             | still unsupported\n    null            | 0x0A             | null\n    Regular Expr.   | 0x0B             | still unsupported\n    DB Pointer      | 0x0C             | still unsupported\n    JavaScript Code | 0x0D             | still unsupported\n    Symbol          | 0x0E             | still unsupported\n    JavaScript Code | 0x0F             | still unsupported\n    int32           | 0x10             | number_integer\n    Timestamp       | 0x11             | still unsupported\n    128-bit decimal float | 0x13       | still unsupported\n    Max Key         | 0x7F             | still unsupported\n    Min Key         | 0xFF             | still unsupported\n\n    @warning The mapping is **incomplete**. The unsupported mappings\n             are indicated in the table above.\n\n    @param[in] i  an input in BSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value; in case of a parse error and\n            @a allow_exceptions set to `false`, the return value will be\n            value_t::discarded.\n\n    @throw parse_error.114 if an unsupported BSON record type is encountered\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    BSON format to a JSON value.,from_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref to_bson(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool, const cbor_tag_handler_t) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n    */\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_bson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        return from_bson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        auto ia = i.get();\n        const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n    /// @}\n\n    //////////////////////////\n    // JSON Pointer support //\n    //////////////////////////\n\n    /// @name JSON Pointer functions\n    /// @{\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. Similar to @ref operator[](const typename\n    object_t::key_type&), `null` values are created in arrays and objects if\n    necessary.\n\n    In particular:\n    - If the JSON pointer points to an object key that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned.\n    - If the JSON pointer points to an array index that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned. All indices between the current maximum and the given\n      index are also filled with `null`.\n    - The special value `-` is treated as a synonym for the index past the\n      end.\n\n    @param[in] ptr  a JSON pointer\n\n    @return reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer}\n\n    @since version 2.0.0\n    */\n    reference operator[](const json_pointer& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. The function does not change the JSON\n    value; no `null` values are created. In particular, the special value\n    `-` yields an exception.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return const reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}\n\n    @since version 2.0.0\n    */\n    const_reference operator[](const json_pointer& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a reference to the element at with specified JSON pointer @a ptr,\n    with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer}\n    */\n    reference at(const json_pointer& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a const reference to the element at with specified JSON pointer @a\n    ptr, with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer_const}\n    */\n    const_reference at(const json_pointer& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief return flattened JSON value\n\n    The function creates a JSON object whose keys are JSON pointers (see [RFC\n    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all\n    primitive. The original JSON value can be restored using the @ref\n    unflatten() function.\n\n    @return an object that maps JSON pointers to primitive values\n\n    @note Empty objects and arrays are flattened to `null` and will not be\n          reconstructed correctly by the @ref unflatten() function.\n\n    @complexity Linear in the size the JSON value.\n\n    @liveexample{The following code shows how a JSON object is flattened to an\n    object whose keys consist of JSON pointers.,flatten}\n\n    @sa @ref unflatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json flatten() const\n    {\n        basic_json result(value_t::object);\n        json_pointer::flatten(\"\", *this, result);\n        return result;\n    }\n\n    /*!\n    @brief unflatten a previously flattened JSON value\n\n    The function restores the arbitrary nesting of a JSON value that has been\n    flattened before using the @ref flatten() function. The JSON value must\n    meet certain constraints:\n    1. The value must be an object.\n    2. The keys must be JSON pointers (see\n       [RFC 6901](https://tools.ietf.org/html/rfc6901))\n    3. The mapped values must be primitive JSON types.\n\n    @return the original JSON from a flattened version\n\n    @note Empty objects and arrays are flattened by @ref flatten() to `null`\n          values and can not unflattened to their original type. Apart from\n          this example, for a JSON value `j`, the following is always true:\n          `j == j.flatten().unflatten()`.\n\n    @complexity Linear in the size the JSON value.\n\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n\n    @liveexample{The following code shows how a flattened JSON object is\n    unflattened into the original nested JSON object.,unflatten}\n\n    @sa @ref flatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json unflatten() const\n    {\n        return json_pointer::unflatten(*this);\n    }\n\n    /// @}\n\n    //////////////////////////\n    // JSON Patch functions //\n    //////////////////////////\n\n    /// @name JSON Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON patch\n\n    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for\n    expressing a sequence of operations to apply to a JSON) document. With\n    this function, a JSON Patch is applied to the current JSON value by\n    executing all operations from the patch.\n\n    @param[in] json_patch  JSON patch document\n    @return patched document\n\n    @note The application of a patch is atomic: Either all operations succeed\n          and the patched document is returned or an exception is thrown. In\n          any case, the original value is not changed: the patch is applied\n          to a copy of the value.\n\n    @throw parse_error.104 if the JSON patch does not consist of an array of\n    objects\n\n    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory\n    attributes are missing); example: `\"operation add must have member path\"`\n\n    @throw out_of_range.401 if an array index is out of range.\n\n    @throw out_of_range.403 if a JSON pointer inside the patch could not be\n    resolved successfully in the current JSON value; example: `\"key baz not\n    found\"`\n\n    @throw out_of_range.405 if JSON pointer has no parent (\"add\", \"remove\",\n    \"move\")\n\n    @throw other_error.501 if \"test\" operation was unsuccessful\n\n    @complexity Linear in the size of the JSON value and the length of the\n    JSON patch. As usually only a fraction of the JSON value is affected by\n    the patch, the complexity can usually be neglected.\n\n    @liveexample{The following code shows how a JSON patch is applied to a\n    value.,patch}\n\n    @sa @ref diff -- create a JSON patch by comparing two JSON values\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)\n\n    @since version 2.0.0\n    */\n    basic_json patch(const basic_json& json_patch) const\n    {\n        // make a working copy to apply the patch to\n        basic_json result = *this;\n\n        // the valid JSON Patch operations\n        enum class patch_operations {add, remove, replace, move, copy, test, invalid};\n\n        const auto get_op = [](const std::string & op)\n        {\n            if (op == \"add\")\n            {\n                return patch_operations::add;\n            }\n            if (op == \"remove\")\n            {\n                return patch_operations::remove;\n            }\n            if (op == \"replace\")\n            {\n                return patch_operations::replace;\n            }\n            if (op == \"move\")\n            {\n                return patch_operations::move;\n            }\n            if (op == \"copy\")\n            {\n                return patch_operations::copy;\n            }\n            if (op == \"test\")\n            {\n                return patch_operations::test;\n            }\n\n            return patch_operations::invalid;\n        };\n\n        // wrapper for \"add\" operation; add value at ptr\n        const auto operation_add = [&result](json_pointer & ptr, basic_json val)\n        {\n            // adding to the root of the target document means replacing it\n            if (ptr.empty())\n            {\n                result = val;\n                return;\n            }\n\n            // make sure the top element of the pointer exists\n            json_pointer top_pointer = ptr.top();\n            if (top_pointer != ptr)\n            {\n                result.at(top_pointer);\n            }\n\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            basic_json& parent = result[ptr];\n\n            switch (parent.m_type)\n            {\n                case value_t::null:\n                case value_t::object:\n                {\n                    // use operator[] to add value\n                    parent[last_path] = val;\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    if (last_path == \"-\")\n                    {\n                        // special case: append to back\n                        parent.push_back(val);\n                    }\n                    else\n                    {\n                        const auto idx = json_pointer::array_index(last_path);\n                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))\n                        {\n                            // avoid undefined behavior\n                            JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n                        }\n\n                        // default case: insert add offset\n                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n                    }\n                    break;\n                }\n\n                // if there exists a parent it cannot be primitive\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false);  // LCOV_EXCL_LINE\n            }\n        };\n\n        // wrapper for \"remove\" operation; remove value at ptr\n        const auto operation_remove = [&result](json_pointer & ptr)\n        {\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            basic_json& parent = result.at(ptr);\n\n            // remove child\n            if (parent.is_object())\n            {\n                // perform range check\n                auto it = parent.find(last_path);\n                if (JSON_HEDLEY_LIKELY(it != parent.end()))\n                {\n                    parent.erase(it);\n                }\n                else\n                {\n                    JSON_THROW(out_of_range::create(403, \"key '\" + last_path + \"' not found\"));\n                }\n            }\n            else if (parent.is_array())\n            {\n                // note erase performs range check\n                parent.erase(json_pointer::array_index(last_path));\n            }\n        };\n\n        // type check: top level value must be an array\n        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))\n        {\n            JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n        }\n\n        // iterate and apply the operations\n        for (const auto& val : json_patch)\n        {\n            // wrapper to get a value for an operation\n            const auto get_value = [&val](const std::string & op,\n                                          const std::string & member,\n                                          bool string_type) -> basic_json &\n            {\n                // find value\n                auto it = val.m_value.object->find(member);\n\n                // context-sensitive error message\n                const auto error_msg = (op == \"op\") ? \"operation\" : \"operation '\" + op + \"'\";\n\n                // check if desired value is present\n                if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have member '\" + member + \"'\"));\n                }\n\n                // check if result is of type string\n                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have string member '\" + member + \"'\"));\n                }\n\n                // no error: return value\n                return it->second;\n            };\n\n            // type check: every element of the array must be an object\n            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))\n            {\n                JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n            }\n\n            // collect mandatory members\n            const auto op = get_value(\"op\", \"op\", true).template get<std::string>();\n            const auto path = get_value(op, \"path\", true).template get<std::string>();\n            json_pointer ptr(path);\n\n            switch (get_op(op))\n            {\n                case patch_operations::add:\n                {\n                    operation_add(ptr, get_value(\"add\", \"value\", false));\n                    break;\n                }\n\n                case patch_operations::remove:\n                {\n                    operation_remove(ptr);\n                    break;\n                }\n\n                case patch_operations::replace:\n                {\n                    // the \"path\" location must exist - use at()\n                    result.at(ptr) = get_value(\"replace\", \"value\", false);\n                    break;\n                }\n\n                case patch_operations::move:\n                {\n                    const auto from_path = get_value(\"move\", \"from\", true).template get<std::string>();\n                    json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The move operation is functionally identical to a\n                    // \"remove\" operation on the \"from\" location, followed\n                    // immediately by an \"add\" operation at the target\n                    // location with the value that was just removed.\n                    operation_remove(from_ptr);\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::copy:\n                {\n                    const auto from_path = get_value(\"copy\", \"from\", true).template get<std::string>();\n                    const json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The copy is functionally identical to an \"add\"\n                    // operation at the target location using the value\n                    // specified in the \"from\" member.\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::test:\n                {\n                    bool success = false;\n                    JSON_TRY\n                    {\n                        // check if \"value\" matches the one at \"path\"\n                        // the \"path\" location must exist - use at()\n                        success = (result.at(ptr) == get_value(\"test\", \"value\", false));\n                    }\n                    JSON_INTERNAL_CATCH (out_of_range&)\n                    {\n                        // ignore out of range errors: success remains false\n                    }\n\n                    // throw an exception if test fails\n                    if (JSON_HEDLEY_UNLIKELY(!success))\n                    {\n                        JSON_THROW(other_error::create(501, \"unsuccessful: \" + val.dump()));\n                    }\n\n                    break;\n                }\n\n                default:\n                {\n                    // op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n                    // \"test\"\n                    JSON_THROW(parse_error::create(105, 0, \"operation value '\" + op + \"' is invalid\"));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief creates a diff as a JSON patch\n\n    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can\n    be changed into the value @a target by calling @ref patch function.\n\n    @invariant For two JSON values @a source and @a target, the following code\n    yields always `true`:\n    @code {.cpp}\n    source.patch(diff(source, target)) == target;\n    @endcode\n\n    @note Currently, only `remove`, `add`, and `replace` operations are\n          generated.\n\n    @param[in] source  JSON value to compare from\n    @param[in] target  JSON value to compare against\n    @param[in] path    helper value to create JSON pointers\n\n    @return a JSON patch to convert the @a source to @a target\n\n    @complexity Linear in the lengths of @a source and @a target.\n\n    @liveexample{The following code shows how a JSON patch is created as a\n    diff for two JSON values.,diff}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa @ref merge_patch -- apply a JSON Merge Patch\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\n    @since version 2.0.0\n    */\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json diff(const basic_json& source, const basic_json& target,\n                           const std::string& path = \"\")\n    {\n        // the patch\n        basic_json result(value_t::array);\n\n        // if the values are the same, return empty patch\n        if (source == target)\n        {\n            return result;\n        }\n\n        if (source.type() != target.type())\n        {\n            // different types: replace value\n            result.push_back(\n            {\n                {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n            });\n            return result;\n        }\n\n        switch (source.type())\n        {\n            case value_t::array:\n            {\n                // first pass: traverse common elements\n                std::size_t i = 0;\n                while (i < source.size() && i < target.size())\n                {\n                    // recursive call to compare array values at index i\n                    auto temp_diff = diff(source[i], target[i], path + \"/\" + std::to_string(i));\n                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    ++i;\n                }\n\n                // i now reached the end of at least one array\n                // in a second pass, traverse the remaining elements\n\n                // remove my remaining elements\n                const auto end_index = static_cast<difference_type>(result.size());\n                while (i < source.size())\n                {\n                    // add operations in reverse order to avoid invalid\n                    // indices\n                    result.insert(result.begin() + end_index, object(\n                    {\n                        {\"op\", \"remove\"},\n                        {\"path\", path + \"/\" + std::to_string(i)}\n                    }));\n                    ++i;\n                }\n\n                // add other remaining elements\n                while (i < target.size())\n                {\n                    result.push_back(\n                    {\n                        {\"op\", \"add\"},\n                        {\"path\", path + \"/-\"},\n                        {\"value\", target[i]}\n                    });\n                    ++i;\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // first pass: traverse this object's elements\n                for (auto it = source.cbegin(); it != source.cend(); ++it)\n                {\n                    // escape the key name to be used in a JSON patch\n                    const auto key = json_pointer::escape(it.key());\n\n                    if (target.find(it.key()) != target.end())\n                    {\n                        // recursive call to compare object values at key it\n                        auto temp_diff = diff(it.value(), target[it.key()], path + \"/\" + key);\n                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    }\n                    else\n                    {\n                        // found a key that is not in o -> remove it\n                        result.push_back(object(\n                        {\n                            {\"op\", \"remove\"}, {\"path\", path + \"/\" + key}\n                        }));\n                    }\n                }\n\n                // second pass: traverse other object's elements\n                for (auto it = target.cbegin(); it != target.cend(); ++it)\n                {\n                    if (source.find(it.key()) == source.end())\n                    {\n                        // found a key that is not in this -> add it\n                        const auto key = json_pointer::escape(it.key());\n                        result.push_back(\n                        {\n                            {\"op\", \"add\"}, {\"path\", path + \"/\" + key},\n                            {\"value\", it.value()}\n                        });\n                    }\n                }\n\n                break;\n            }\n\n            default:\n            {\n                // both primitive type: replace value\n                result.push_back(\n                {\n                    {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n                });\n                break;\n            }\n        }\n\n        return result;\n    }\n\n    /// @}\n\n    ////////////////////////////////\n    // JSON Merge Patch functions //\n    ////////////////////////////////\n\n    /// @name JSON Merge Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON Merge Patch\n\n    The merge patch format is primarily intended for use with the HTTP PATCH\n    method as a means of describing a set of modifications to a target\n    resource's content. This function applies a merge patch to the current\n    JSON value.\n\n    The function implements the following algorithm from Section 2 of\n    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):\n\n    ```\n    define MergePatch(Target, Patch):\n      if Patch is an Object:\n        if Target is not an Object:\n          Target = {} // Ignore the contents and set it to an empty Object\n        for each Name/Value pair in Patch:\n          if Value is null:\n            if Name exists in Target:\n              remove the Name/Value pair from Target\n          else:\n            Target[Name] = MergePatch(Target[Name], Value)\n        return Target\n      else:\n        return Patch\n    ```\n\n    Thereby, `Target` is the current object; that is, the patch is applied to\n    the current value.\n\n    @param[in] apply_patch  the patch to apply\n\n    @complexity Linear in the lengths of @a patch.\n\n    @liveexample{The following code shows how a JSON Merge Patch is applied to\n    a JSON document.,merge_patch}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)\n\n    @since version 3.0.0\n    */\n    void merge_patch(const basic_json& apply_patch)\n    {\n        if (apply_patch.is_object())\n        {\n            if (!is_object())\n            {\n                *this = object();\n            }\n            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n            {\n                if (it.value().is_null())\n                {\n                    erase(it.key());\n                }\n                else\n                {\n                    operator[](it.key()).merge_patch(it.value());\n                }\n            }\n        }\n        else\n        {\n            *this = apply_patch;\n        }\n    }\n\n    /// @}\n};\n\n/*!\n@brief user-defined to_string function for JSON values\n\nThis function implements a user-defined to_string  for JSON objects.\n\n@param[in] j  a JSON object\n@return a std::string object\n*/\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstd::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)\n{\n    return j.dump();\n}\n} // namespace nlohmann\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\n// specialization of std::swap, and std::hash\nnamespace std\n{\n\n/// hash value for JSON objects\ntemplate<>\nstruct hash<nlohmann::json>\n{\n    /*!\n    @brief return a hash value for a JSON object\n\n    @since version 1.0.0\n    */\n    std::size_t operator()(const nlohmann::json& j) const\n    {\n        return nlohmann::detail::hash(j);\n    }\n};\n\n/// specialization for std::less<value_t>\n/// @note: do not remove the space after '<',\n///        see https://github.com/nlohmann/json/pull/679\ntemplate<>\nstruct less<::nlohmann::detail::value_t>\n{\n    /*!\n    @brief compare two value_t enum values\n    @since version 3.0.0\n    */\n    bool operator()(nlohmann::detail::value_t lhs,\n                    nlohmann::detail::value_t rhs) const noexcept\n    {\n        return nlohmann::detail::operator<(lhs, rhs);\n    }\n};\n\n// C++20 prohibit function specialization in the std namespace.\n#ifndef JSON_HAS_CPP_20\n\n/*!\n@brief exchanges the values of two JSON objects\n\n@since version 1.0.0\n*/\ntemplate<>\ninline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(\n    is_nothrow_move_constructible<nlohmann::json>::value&&\n    is_nothrow_move_assignable<nlohmann::json>::value\n                              )\n{\n    j1.swap(j2);\n}\n\n#endif\n\n} // namespace std\n\n/*!\n@brief user-defined string literal for JSON values\n\nThis operator implements a user-defined string literal for JSON objects. It\ncan be used by adding `\"_json\"` to a string literal and returns a JSON object\nif no parse error occurred.\n\n@param[in] s  a string representation of a JSON object\n@param[in] n  the length of string @a s\n@return a JSON object\n\n@since version 1.0.0\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n{\n    return nlohmann::json::parse(s, s + n);\n}\n\n/*!\n@brief user-defined string literal for JSON pointer\n\nThis operator implements a user-defined string literal for JSON Pointers. It\ncan be used by adding `\"_json_pointer\"` to a string literal and returns a JSON pointer\nobject if no parse error occurred.\n\n@param[in] s  a string representation of a JSON Pointer\n@param[in] n  the length of string @a s\n@return a JSON pointer object\n\n@since version 2.0.0\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n{\n    return nlohmann::json::json_pointer(std::string(s, n));\n}\n\n// #include <nlohmann/detail/macro_unscope.hpp>\n\n\n// restore GCC/clang diagnostic settings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic pop\n#endif\n#if defined(__clang__)\n    #pragma GCC diagnostic pop\n#endif\n\n// clean up\n#undef JSON_ASSERT\n#undef JSON_INTERNAL_CATCH\n#undef JSON_CATCH\n#undef JSON_THROW\n#undef JSON_TRY\n#undef JSON_PRIVATE_UNLESS_TESTED\n#undef JSON_HAS_CPP_14\n#undef JSON_HAS_CPP_17\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n#undef JSON_EXPLICIT\n\n// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>\n\n\n#undef JSON_HEDLEY_ALWAYS_INLINE\n#undef JSON_HEDLEY_ARM_VERSION\n#undef JSON_HEDLEY_ARM_VERSION_CHECK\n#undef JSON_HEDLEY_ARRAY_PARAM\n#undef JSON_HEDLEY_ASSUME\n#undef JSON_HEDLEY_BEGIN_C_DECLS\n#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#undef JSON_HEDLEY_CLANG_HAS_WARNING\n#undef JSON_HEDLEY_COMPCERT_VERSION\n#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#undef JSON_HEDLEY_CONCAT\n#undef JSON_HEDLEY_CONCAT3\n#undef JSON_HEDLEY_CONCAT3_EX\n#undef JSON_HEDLEY_CONCAT_EX\n#undef JSON_HEDLEY_CONST\n#undef JSON_HEDLEY_CONSTEXPR\n#undef JSON_HEDLEY_CONST_CAST\n#undef JSON_HEDLEY_CPP_CAST\n#undef JSON_HEDLEY_CRAY_VERSION\n#undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#undef JSON_HEDLEY_C_DECL\n#undef JSON_HEDLEY_DEPRECATED\n#undef JSON_HEDLEY_DEPRECATED_FOR\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#undef JSON_HEDLEY_DIAGNOSTIC_POP\n#undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#undef JSON_HEDLEY_DMC_VERSION\n#undef JSON_HEDLEY_DMC_VERSION_CHECK\n#undef JSON_HEDLEY_EMPTY_BASES\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#undef JSON_HEDLEY_END_C_DECLS\n#undef JSON_HEDLEY_FLAGS\n#undef JSON_HEDLEY_FLAGS_CAST\n#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#undef JSON_HEDLEY_GCC_HAS_FEATURE\n#undef JSON_HEDLEY_GCC_HAS_WARNING\n#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#undef JSON_HEDLEY_GCC_VERSION\n#undef JSON_HEDLEY_GCC_VERSION_CHECK\n#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#undef JSON_HEDLEY_GNUC_HAS_WARNING\n#undef JSON_HEDLEY_GNUC_VERSION\n#undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#undef JSON_HEDLEY_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_BUILTIN\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_EXTENSION\n#undef JSON_HEDLEY_HAS_FEATURE\n#undef JSON_HEDLEY_HAS_WARNING\n#undef JSON_HEDLEY_IAR_VERSION\n#undef JSON_HEDLEY_IAR_VERSION_CHECK\n#undef JSON_HEDLEY_IBM_VERSION\n#undef JSON_HEDLEY_IBM_VERSION_CHECK\n#undef JSON_HEDLEY_IMPORT\n#undef JSON_HEDLEY_INLINE\n#undef JSON_HEDLEY_INTEL_CL_VERSION\n#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#undef JSON_HEDLEY_INTEL_VERSION\n#undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#undef JSON_HEDLEY_IS_CONSTANT\n#undef JSON_HEDLEY_IS_CONSTEXPR_\n#undef JSON_HEDLEY_LIKELY\n#undef JSON_HEDLEY_MALLOC\n#undef JSON_HEDLEY_MESSAGE\n#undef JSON_HEDLEY_MSVC_VERSION\n#undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#undef JSON_HEDLEY_NEVER_INLINE\n#undef JSON_HEDLEY_NON_NULL\n#undef JSON_HEDLEY_NO_ESCAPE\n#undef JSON_HEDLEY_NO_RETURN\n#undef JSON_HEDLEY_NO_THROW\n#undef JSON_HEDLEY_NULL\n#undef JSON_HEDLEY_PELLES_VERSION\n#undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#undef JSON_HEDLEY_PGI_VERSION\n#undef JSON_HEDLEY_PGI_VERSION_CHECK\n#undef JSON_HEDLEY_PREDICT\n#undef JSON_HEDLEY_PRINTF_FORMAT\n#undef JSON_HEDLEY_PRIVATE\n#undef JSON_HEDLEY_PUBLIC\n#undef JSON_HEDLEY_PURE\n#undef JSON_HEDLEY_REINTERPRET_CAST\n#undef JSON_HEDLEY_REQUIRE\n#undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#undef JSON_HEDLEY_REQUIRE_MSG\n#undef JSON_HEDLEY_RESTRICT\n#undef JSON_HEDLEY_RETURNS_NON_NULL\n#undef JSON_HEDLEY_SENTINEL\n#undef JSON_HEDLEY_STATIC_ASSERT\n#undef JSON_HEDLEY_STATIC_CAST\n#undef JSON_HEDLEY_STRINGIFY\n#undef JSON_HEDLEY_STRINGIFY_EX\n#undef JSON_HEDLEY_SUNPRO_VERSION\n#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#undef JSON_HEDLEY_TINYC_VERSION\n#undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#undef JSON_HEDLEY_TI_ARMCL_VERSION\n#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL2000_VERSION\n#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL430_VERSION\n#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL6X_VERSION\n#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL7X_VERSION\n#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CLPRU_VERSION\n#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#undef JSON_HEDLEY_TI_VERSION\n#undef JSON_HEDLEY_TI_VERSION_CHECK\n#undef JSON_HEDLEY_UNAVAILABLE\n#undef JSON_HEDLEY_UNLIKELY\n#undef JSON_HEDLEY_UNPREDICTABLE\n#undef JSON_HEDLEY_UNREACHABLE\n#undef JSON_HEDLEY_UNREACHABLE_RETURN\n#undef JSON_HEDLEY_VERSION\n#undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#undef JSON_HEDLEY_VERSION_ENCODE\n#undef JSON_HEDLEY_WARNING\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#undef JSON_HEDLEY_FALL_THROUGH\n\n\n\n#endif  // INCLUDE_NLOHMANN_JSON_HPP_"
  },
  {
    "path": "eidos/json_fwd.hpp",
    "content": "#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n#define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer,\n         class BinaryType = std::vector<std::uint8_t>>\nclass basic_json;\n\n/*!\n@brief JSON Pointer\n\nA JSON pointer defines a string syntax for identifying a specific value\nwithin a JSON document. It can be used with functions `at` and\n`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n@since version 2.0.0\n*/\ntemplate<typename BasicJsonType>\nclass json_pointer;\n\n/*!\n@brief default JSON class\n\nThis type is the default specialization of the @ref basic_json class which\nuses the standard template types.\n\n@since version 1.0.0\n*/\nusing json = basic_json<>;\n\ntemplate<class Key, class T, class IgnoredLess, class Allocator>\nstruct ordered_map;\n\n/*!\n@brief ordered JSON class\n\nThis type preserves the insertion order of object keys.\n\n@since version 3.9.0\n*/\nusing ordered_json = basic_json<nlohmann::ordered_map>;\n\n}  // namespace nlohmann\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n"
  },
  {
    "path": "eidos/lodepng.cpp",
    "content": "/*\nLodePNG version 20200306\n\nCopyright (c) 2005-2020 Lode Vandevenne\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n    1. The origin of this software must not be misrepresented; you must not\n    claim that you wrote the original software. If you use this software\n    in a product, an acknowledgment in the product documentation would be\n    appreciated but is not required.\n\n    2. Altered source versions must be plainly marked as such, and must not be\n    misrepresented as being the original software.\n\n    3. This notice may not be removed or altered from any source\n    distribution.\n*/\n\n// BCH 11 Oct. 2020 : The source code here is slightly modified to get rid of compile warnings\n// Also there is one bug fix at line 4951 introduced by me, to generate an error for RGB->grayscale\n// following what the documentation and the error codes seem to indicate should occur.\n// All such changes are marked with BCH.  This code is based on a git clone from 8 Oct. 2020.\n// NOLINTBEGIN : lodepng has lots of linting problems, which are within a somebody else's problem field\n\n/*\nThe manual and changelog are in the header file \"lodepng.h\"\nRename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C.\n*/\n\n#include \"lodepng.h\"\n\n#ifdef LODEPNG_COMPILE_DISK\n#include <limits.h> /* LONG_MAX */\n#include <stdio.h> /* file handling */\n#endif /* LODEPNG_COMPILE_DISK */\n\n#ifdef LODEPNG_COMPILE_ALLOCATORS\n#include <stdlib.h> /* allocations */\n#endif /* LODEPNG_COMPILE_ALLOCATORS */\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/\n#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/\n#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/\n#endif /*_MSC_VER */\n\n// BCH 8 Oct. 2020 : adding this warning disable for Xcode 11.4.1\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\nconst char* LODEPNG_VERSION_STRING = \"20200306\";\n\n/*\nThis source file is built up in the following large parts. The code sections\nwith the \"LODEPNG_COMPILE_\" #defines divide this up further in an intermixed way.\n-Tools for C and common code for PNG and Zlib\n-C Code for Zlib (huffman, deflate, ...)\n-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...)\n-The C++ wrapper around all of the above\n*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* // Tools for C, and common code for PNG and Zlib.                       // */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*The malloc, realloc and free functions defined here with \"lodepng_\" in front\nof the name, so that you can easily change them to others related to your\nplatform if needed. Everything else in the code calls these. Pass\n-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out\n#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and\ndefine them in your own project's source files without needing to change\nlodepng source code. Don't forget to remove \"static\" if you copypaste them\nfrom here.*/\n\n#ifdef LODEPNG_COMPILE_ALLOCATORS\nstatic void* lodepng_malloc(size_t size) {\n#ifdef LODEPNG_MAX_ALLOC\n  if(size > LODEPNG_MAX_ALLOC) return 0;\n#endif\n  return malloc(size);\n}\n\n/* NOTE: when realloc returns NULL, it leaves the original memory untouched */\nstatic void* lodepng_realloc(void* ptr, size_t new_size) {\n#ifdef LODEPNG_MAX_ALLOC\n  if(new_size > LODEPNG_MAX_ALLOC) return 0;\n#endif\n  return realloc(ptr, new_size);\n}\n\nstatic void lodepng_free(void* ptr) {\n  free(ptr);\n}\n#else /*LODEPNG_COMPILE_ALLOCATORS*/\n/* TODO: support giving additional void* payload to the custom allocators */\nvoid* lodepng_malloc(size_t size);\nvoid* lodepng_realloc(void* ptr, size_t new_size);\nvoid lodepng_free(void* ptr);\n#endif /*LODEPNG_COMPILE_ALLOCATORS*/\n\n/* convince the compiler to inline a function, for use when this measurably improves performance */\n/* inline is not available in C90, but use it when supported by the compiler */\n#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L))\n#define LODEPNG_INLINE inline\n#else\n#define LODEPNG_INLINE /* not available */\n#endif\n\n/* restrict is not available in C90, but use it when supported by the compiler */\n#if (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) ||\\\n    (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \\\n    (defined(__WATCOMC__) && (__WATCOMC__ >= 1250) && !defined(__cplusplus))\n#define LODEPNG_RESTRICT __restrict\n#else\n#define LODEPNG_RESTRICT /* not available */\n#endif\n\n/* Replacements for C library functions such as memcpy and strlen, to support platforms\nwhere a full C library is not available. The compiler can recognize them and compile\nto something as fast. */\n\nstatic void lodepng_memcpy(void* LODEPNG_RESTRICT dst,\n                           const void* LODEPNG_RESTRICT src, size_t size) {\n  size_t i;\n  for(i = 0; i < size; i++) ((char*)dst)[i] = ((const char*)src)[i];\n}\n\nstatic void lodepng_memset(void* LODEPNG_RESTRICT dst,\n                           int value, size_t num) {\n  size_t i;\n  for(i = 0; i < num; i++) ((char*)dst)[i] = (char)value;\n}\n\n/* does not check memory out of bounds, do not use on untrusted data */\nstatic size_t lodepng_strlen(const char* a) {\n  const char* orig = a;\n  /* avoid warning about unused function in case of disabled COMPILE... macros */\n  (void)(&lodepng_strlen);\n  while(*a) a++;\n  return (size_t)(a - orig);\n}\n\n#define LODEPNG_MAX(a, b) (((a) > (b)) ? (a) : (b))\n#define LODEPNG_MIN(a, b) (((a) < (b)) ? (a) : (b))\n#define LODEPNG_ABS(x) ((x) < 0 ? -(x) : (x))\n\n#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER)\n/* Safely check if adding two integers will overflow (no undefined\nbehavior, compiler removing the code, etc...) and output result. */\nstatic int lodepng_addofl(size_t a, size_t b, size_t* result) {\n  *result = a + b; /* Unsigned addition is well defined and safe in C90 */\n  return *result < a;\n}\n#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER)*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n/* Safely check if multiplying two integers will overflow (no undefined\nbehavior, compiler removing the code, etc...) and output result. */\nstatic int lodepng_mulofl(size_t a, size_t b, size_t* result) {\n  *result = a * b; /* Unsigned multiplication is well defined and safe in C90 */\n  return (a != 0 && *result / a != b);\n}\n\n#ifdef LODEPNG_COMPILE_ZLIB\n/* Safely check if a + b > c, even if overflow could happen. */\nstatic int lodepng_gtofl(size_t a, size_t b, size_t c) {\n  size_t d;\n  if(lodepng_addofl(a, b, &d)) return 1;\n  return d > c;\n}\n#endif /*LODEPNG_COMPILE_ZLIB*/\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n\n/*\nOften in case of an error a value is assigned to a variable and then it breaks\nout of a loop (to go to the cleanup phase of a function). This macro does that.\nIt makes the error handling code shorter and more readable.\n\nExample: if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83);\n*/\n#define CERROR_BREAK(errorvar, code){\\\n  errorvar = code;\\\n  break;\\\n}\n\n/*version of CERROR_BREAK that assumes the common case where the error variable is named \"error\"*/\n#define ERROR_BREAK(code) CERROR_BREAK(error, code)\n\n/*Set error var to the error code, and return it.*/\n#define CERROR_RETURN_ERROR(errorvar, code){\\\n  errorvar = code;\\\n  return code;\\\n}\n\n/*Try the code, if it returns error, also return the error.*/\n#define CERROR_TRY_RETURN(call){\\\n  unsigned error = call;\\\n  if(error) return error;\\\n}\n\n/*Set error var to the error code, and return from the void function.*/\n#define CERROR_RETURN(errorvar, code){\\\n  errorvar = code;\\\n  return;\\\n}\n\n/*\nAbout uivector, ucvector and string:\n-All of them wrap dynamic arrays or text strings in a similar way.\n-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version.\n-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated.\n-They're not used in the interface, only internally in this file as static functions.\n-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor.\n*/\n\n#ifdef LODEPNG_COMPILE_ZLIB\n#ifdef LODEPNG_COMPILE_ENCODER\n/*dynamic vector of unsigned ints*/\ntypedef struct uivector {\n  unsigned* data;\n  size_t size; /*size in number of unsigned longs*/\n  size_t allocsize; /*allocated size in bytes*/\n} uivector;\n\nstatic void uivector_cleanup(void* p) {\n  ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;\n  lodepng_free(((uivector*)p)->data);\n  ((uivector*)p)->data = NULL;\n}\n\n/*returns 1 if success, 0 if failure ==> nothing done*/\nstatic unsigned uivector_resize(uivector* p, size_t size) {\n  size_t allocsize = size * sizeof(unsigned);\n  if(allocsize > p->allocsize) {\n    size_t newsize = allocsize + (p->allocsize >> 1u);\n    void* data = lodepng_realloc(p->data, newsize);\n    if(data) {\n      p->allocsize = newsize;\n      p->data = (unsigned*)data;\n    }\n    else return 0; /*error: not enough memory*/\n  }\n  p->size = size;\n  return 1; /*success*/\n}\n\nstatic void uivector_init(uivector* p) {\n  p->data = NULL;\n  p->size = p->allocsize = 0;\n}\n\n/*returns 1 if success, 0 if failure ==> nothing done*/\nstatic unsigned uivector_push_back(uivector* p, unsigned c) {\n  if(!uivector_resize(p, p->size + 1)) return 0;\n  p->data[p->size - 1] = c;\n  return 1;\n}\n#endif /*LODEPNG_COMPILE_ENCODER*/\n#endif /*LODEPNG_COMPILE_ZLIB*/\n\n/* /////////////////////////////////////////////////////////////////////////// */\n\n/*dynamic vector of unsigned chars*/\ntypedef struct ucvector {\n  unsigned char* data;\n  size_t size; /*used size*/\n  size_t allocsize; /*allocated size*/\n} ucvector;\n\n/*returns 1 if success, 0 if failure ==> nothing done*/\nstatic unsigned ucvector_resize(ucvector* p, size_t size) {\n  if(size > p->allocsize) {\n    size_t newsize = size + (p->allocsize >> 1u);\n    void* data = lodepng_realloc(p->data, newsize);\n    if(data) {\n      p->allocsize = newsize;\n      p->data = (unsigned char*)data;\n    }\n    else return 0; /*error: not enough memory*/\n  }\n  p->size = size;\n  return 1; /*success*/\n}\n\nstatic ucvector ucvector_init(unsigned char* buffer, size_t size) {\n  ucvector v;\n  v.data = buffer;\n  v.allocsize = v.size = size;\n  return v;\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_PNG\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n\n/*free string pointer and set it to NULL*/\nstatic void string_cleanup(char** out) {\n  lodepng_free(*out);\n  *out = NULL;\n}\n\nstatic char* alloc_string_sized(const char* in, size_t insize) {\n  char* out = (char*)lodepng_malloc(insize + 1);\n  if(out) {\n    lodepng_memcpy(out, in, insize);\n    out[insize] = 0;\n  }\n  return out;\n}\n\n/* dynamically allocates a new string with a copy of the null terminated input text */\nstatic char* alloc_string(const char* in) {\n  return alloc_string_sized(in, lodepng_strlen(in));\n}\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n#endif /*LODEPNG_COMPILE_PNG*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG)\nstatic unsigned lodepng_read32bitInt(const unsigned char* buffer) {\n  return (((unsigned)buffer[0] << 24u) | ((unsigned)buffer[1] << 16u) |\n         ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]);\n}\n#endif /*defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG)*/\n\n#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)\n/*buffer must have at least 4 allocated bytes available*/\nstatic void lodepng_set32bitInt(unsigned char* buffer, unsigned value) {\n  buffer[0] = (unsigned char)((value >> 24) & 0xff);\n  buffer[1] = (unsigned char)((value >> 16) & 0xff);\n  buffer[2] = (unsigned char)((value >>  8) & 0xff);\n  buffer[3] = (unsigned char)((value      ) & 0xff);\n}\n#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / File IO                                                                / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_DISK\n\n/* returns negative value on error. This should be pure C compatible, so no fstat. */\nstatic long lodepng_filesize(const char* filename) {\n  FILE* file;\n  long size;\n  file = fopen(filename, \"rb\");\n  if(!file) return -1;\n\n  if(fseek(file, 0, SEEK_END) != 0) {\n    fclose(file);\n    return -1;\n  }\n\n  size = ftell(file);\n  /* It may give LONG_MAX as directory size, this is invalid for us. */\n  if(size == LONG_MAX) size = -1;\n\n  fclose(file);\n  return size;\n}\n\n/* load file into buffer that already has the correct allocated size. Returns error code.*/\nstatic unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) {\n  FILE* file;\n  size_t readsize;\n  file = fopen(filename, \"rb\");\n  if(!file) return 78;\n\n  readsize = fread(out, 1, size, file);\n  fclose(file);\n\n  if(readsize != size) return 78;\n  return 0;\n}\n\nunsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) {\n  long size = lodepng_filesize(filename);\n  if(size < 0) return 78;\n  *outsize = (size_t)size;\n\n  *out = (unsigned char*)lodepng_malloc((size_t)size);\n  if(!(*out) && size > 0) return 83; /*the above malloc failed*/\n\n  return lodepng_buffer_file(*out, (size_t)size, filename);\n}\n\n/*write given buffer to the file, overwriting the file, it doesn't append to it.*/\nunsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) {\n  FILE* file;\n  file = fopen(filename, \"wb\" );\n  if(!file) return 79;\n  fwrite(buffer, 1, buffersize, file);\n  fclose(file);\n  return 0;\n}\n\n#endif /*LODEPNG_COMPILE_DISK*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* // End of common code and tools. Begin of Zlib related code.            // */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_ZLIB\n#ifdef LODEPNG_COMPILE_ENCODER\n\ntypedef struct {\n  ucvector* data;\n  unsigned char bp; /*ok to overflow, indicates bit pos inside byte*/\n} LodePNGBitWriter;\n\nstatic void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) {\n  writer->data = data;\n  writer->bp = 0;\n}\n\n/*TODO: this ignores potential out of memory errors*/\n#define WRITEBIT(writer, bit){\\\n  /* append new byte */\\\n  if(((writer->bp) & 7u) == 0) {\\\n    if(!ucvector_resize(writer->data, writer->data->size + 1)) return;\\\n    writer->data->data[writer->data->size - 1] = 0;\\\n  }\\\n  (writer->data->data[writer->data->size - 1]) |= (bit << ((writer->bp) & 7u));\\\n  ++writer->bp;\\\n}\n\n/* LSB of value is written first, and LSB of bytes is used first */\nstatic void writeBits(LodePNGBitWriter* writer, unsigned value, size_t nbits) {\n  if(nbits == 1) { /* compiler should statically compile this case if nbits == 1 */\n    WRITEBIT(writer, value);\n  } else {\n    /* TODO: increase output size only once here rather than in each WRITEBIT */\n    size_t i;\n    for(i = 0; i != nbits; ++i) {\n      WRITEBIT(writer, (unsigned char)((value >> i) & 1));\n    }\n  }\n}\n\n/* This one is to use for adding huffman symbol, the value bits are written MSB first */\nstatic void writeBitsReversed(LodePNGBitWriter* writer, unsigned value, size_t nbits) {\n  size_t i;\n  for(i = 0; i != nbits; ++i) {\n    /* TODO: increase output size only once here rather than in each WRITEBIT */\n    WRITEBIT(writer, (unsigned char)((value >> (nbits - 1u - i)) & 1u));\n  }\n}\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n\ntypedef struct {\n  const unsigned char* data;\n  size_t size; /*size of data in bytes*/\n  size_t bitsize; /*size of data in bits, end of valid bp values, should be 8*size*/\n  size_t bp;\n  unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at least 32 bits*/\n} LodePNGBitReader;\n\n/* data size argument is in bytes. Returns error if size too large causing overflow */\nstatic unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned char* data, size_t size) {\n  size_t temp;\n  reader->data = data;\n  reader->size = size;\n  /* size in bits, return error if overflow (if size_t is 32 bit this supports up to 500MB)  */\n  if(lodepng_mulofl(size, 8u, &reader->bitsize)) return 105;\n  /*ensure incremented bp can be compared to bitsize without overflow even when it would be incremented 32 too much and\n  trying to ensure 32 more bits*/\n  if(lodepng_addofl(reader->bitsize, 64u, &temp)) return 105;\n  reader->bp = 0;\n  reader->buffer = 0;\n  return 0; /*ok*/\n}\n\n/*\nensureBits functions:\nEnsures the reader can at least read nbits bits in one or more readBits calls,\nsafely even if not enough bits are available.\nReturns 1 if there are enough bits available, 0 if not.\n*/\n\n/*See ensureBits documentation above. This one ensures exactly 1 bit */\n/*static unsigned ensureBits1(LodePNGBitReader* reader) {\n  if(reader->bp >= reader->bitsize) return 0;\n  reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u);\n  return 1;\n}*/\n\n/*See ensureBits documentation above. This one ensures up to 9 bits */\nstatic unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) {\n  size_t start = reader->bp >> 3u;\n  size_t size = reader->size;\n  if(start + 1u < size) {\n    reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);\n    reader->buffer >>= (reader->bp & 7u);\n    return 1;\n  } else {\n    reader->buffer = 0;\n    if(start + 0u < size) reader->buffer |= reader->data[start + 0];\n    reader->buffer >>= (reader->bp & 7u);\n    return reader->bp + nbits <= reader->bitsize;\n  }\n}\n\n/*See ensureBits documentation above. This one ensures up to 17 bits */\nstatic unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) {\n  size_t start = reader->bp >> 3u;\n  size_t size = reader->size;\n  if(start + 2u < size) {\n    reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |\n                     ((unsigned)reader->data[start + 2] << 16u);\n    reader->buffer >>= (reader->bp & 7u);\n    return 1;\n  } else {\n    reader->buffer = 0;\n    if(start + 0u < size) reader->buffer |= reader->data[start + 0];\n    if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);\n    reader->buffer >>= (reader->bp & 7u);\n    return reader->bp + nbits <= reader->bitsize;\n  }\n}\n\n/*See ensureBits documentation above. This one ensures up to 25 bits */\nstatic LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) {\n  size_t start = reader->bp >> 3u;\n  size_t size = reader->size;\n  if(start + 3u < size) {\n    reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |\n                     ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);\n    reader->buffer >>= (reader->bp & 7u);\n    return 1;\n  } else {\n    reader->buffer = 0;\n    if(start + 0u < size) reader->buffer |= reader->data[start + 0];\n    if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);\n    if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);\n    reader->buffer >>= (reader->bp & 7u);\n    return reader->bp + nbits <= reader->bitsize;\n  }\n}\n\n/*See ensureBits documentation above. This one ensures up to 32 bits */\nstatic LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) {\n  size_t start = reader->bp >> 3u;\n  size_t size = reader->size;\n  if(start + 4u < size) {\n    reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) |\n                     ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);\n    reader->buffer >>= (reader->bp & 7u);\n    reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));\n    return 1;\n  } else {\n    reader->buffer = 0;\n    if(start + 0u < size) reader->buffer |= reader->data[start + 0];\n    if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);\n    if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);\n    if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);\n    reader->buffer >>= (reader->bp & 7u);\n    return reader->bp + nbits <= reader->bitsize;\n  }\n}\n\n/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */\nstatic unsigned peekBits(LodePNGBitReader* reader, size_t nbits) {\n  /* The shift allows nbits to be only up to 31. */\n  return reader->buffer & ((1u << nbits) - 1u);\n}\n\n/* Must have enough bits available with ensureBits */\nstatic void advanceBits(LodePNGBitReader* reader, size_t nbits) {\n  reader->buffer >>= nbits;\n  reader->bp += nbits;\n}\n\n/* Must have enough bits available with ensureBits */\nstatic unsigned readBits(LodePNGBitReader* reader, size_t nbits) {\n  unsigned result = peekBits(reader, nbits);\n  advanceBits(reader, nbits);\n  return result;\n}\n\n/* Public for testing only. steps and result must have numsteps values. */\n// BCH 8 Oct. 2020 : commenting this out to get rid of warnings\n/*unsigned lode_png_test_bitreader(const unsigned char* data, size_t size,\n                                 size_t numsteps, const size_t* steps, unsigned* result) {\n  size_t i;\n  LodePNGBitReader reader;\n  unsigned error = LodePNGBitReader_init(&reader, data, size);\n  if(error) return 0;\n  for(i = 0; i < numsteps; i++) {\n    size_t step = steps[i];\n    unsigned ok;\n    if(step > 25) ok = ensureBits32(&reader, step);\n    else if(step > 17) ok = ensureBits25(&reader, step);\n    else if(step > 9) ok = ensureBits17(&reader, step);\n    else ok = ensureBits9(&reader, step);\n    if(!ok) return 0;\n    result[i] = readBits(&reader, step);\n  }\n  return 1;\n}*/\n#endif /*LODEPNG_COMPILE_DECODER*/\n\nstatic unsigned reverseBits(unsigned bits, unsigned num) {\n  /*TODO: implement faster lookup table based version when needed*/\n  unsigned i, result = 0;\n  for(i = 0; i < num; i++) result |= ((bits >> (num - i - 1u)) & 1u) << i;\n  return result;\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Deflate - Huffman                                                      / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#define FIRST_LENGTH_CODE_INDEX 257\n#define LAST_LENGTH_CODE_INDEX 285\n/*256 literals, the end code, some length codes, and 2 unused codes*/\n#define NUM_DEFLATE_CODE_SYMBOLS 288\n/*the distance codes have their own symbols, 30 used, 2 unused*/\n#define NUM_DISTANCE_SYMBOLS 32\n/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/\n#define NUM_CODE_LENGTH_CODES 19\n\n/*the base lengths represented by codes 257-285*/\nstatic const unsigned LENGTHBASE[29]\n  = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,\n     67, 83, 99, 115, 131, 163, 195, 227, 258};\n\n/*the extra bits used by codes 257-285 (added to base length)*/\nstatic const unsigned LENGTHEXTRA[29]\n  = {0, 0, 0, 0, 0, 0, 0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,\n      4,  4,  4,   4,   5,   5,   5,   5,   0};\n\n/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/\nstatic const unsigned DISTANCEBASE[30]\n  = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,\n     769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};\n\n/*the extra bits of backwards distances (added to base)*/\nstatic const unsigned DISTANCEEXTRA[30]\n  = {0, 0, 0, 0, 1, 1, 2,  2,  3,  3,  4,  4,  5,  5,   6,   6,   7,   7,   8,\n       8,    9,    9,   10,   10,   11,   11,   12,    12,    13,    13};\n\n/*the order in which \"code length alphabet code lengths\" are stored as specified by deflate, out of this the huffman\ntree of the dynamic huffman tree lengths is generated*/\nstatic const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]\n  = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*\nHuffman tree struct, containing multiple representations of the tree\n*/\ntypedef struct HuffmanTree {\n  unsigned* codes; /*the huffman codes (bit patterns representing the symbols)*/\n  unsigned* lengths; /*the lengths of the huffman codes*/\n  unsigned maxbitlen; /*maximum number of bits a single code can get*/\n  unsigned numcodes; /*number of symbols in the alphabet = number of codes*/\n  /* for reading only */\n  unsigned char* table_len; /*length of symbol from lookup table, or max length if secondary lookup needed*/\n  unsigned short* table_value; /*value of symbol from lookup table, or pointer to secondary table if needed*/\n} HuffmanTree;\n\nstatic void HuffmanTree_init(HuffmanTree* tree) {\n  tree->codes = 0;\n  tree->lengths = 0;\n  tree->table_len = 0;\n  tree->table_value = 0;\n}\n\nstatic void HuffmanTree_cleanup(HuffmanTree* tree) {\n  lodepng_free(tree->codes);\n  lodepng_free(tree->lengths);\n  lodepng_free(tree->table_len);\n  lodepng_free(tree->table_value);\n}\n\n/* amount of bits for first huffman table lookup (aka root bits), see HuffmanTree_makeTable and huffmanDecodeSymbol.*/\n/* values 8u and 9u work the fastest */\n#define FIRSTBITS 9u\n\n/* a symbol value too big to represent any valid symbol, to indicate reading disallowed huffman bits combination,\nwhich is possible in case of only 0 or 1 present symbols. */\n#define INVALIDSYMBOL 65535u\n\n/* make table for huffman decoding */\nstatic unsigned HuffmanTree_makeTable(HuffmanTree* tree) {\n  static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/\n  static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u;\n  size_t i, numpresent, pointer, size; /*total table size*/\n  unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned));\n  if(!maxlens) return 83; /*alloc fail*/\n\n  /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/\n  lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens));\n  for(i = 0; i < tree->numcodes; i++) {\n    unsigned symbol = tree->codes[i];\n    unsigned l = tree->lengths[i];\n    unsigned index;\n    if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/\n    /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/\n    index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS);\n    maxlens[index] = LODEPNG_MAX(maxlens[index], l);\n  }\n  /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */\n  size = headsize;\n  for(i = 0; i < headsize; ++i) {\n    unsigned l = maxlens[i];\n    if(l > FIRSTBITS) size += (1u << (l - FIRSTBITS));\n  }\n  tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len));\n  tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value));\n  if(!tree->table_len || !tree->table_value) {\n    lodepng_free(maxlens);\n    /* freeing tree->table values is done at a higher scope */\n    return 83; /*alloc fail*/\n  }\n  /*initialize with an invalid length to indicate unused entries*/\n  for(i = 0; i < size; ++i) tree->table_len[i] = 16;\n\n  /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/\n  pointer = headsize;\n  for(i = 0; i < headsize; ++i) {\n    unsigned l = maxlens[i];\n    if(l <= FIRSTBITS) continue;\n    tree->table_len[i] = l;\n    tree->table_value[i] = pointer;\n    pointer += (1u << (l - FIRSTBITS));\n  }\n  lodepng_free(maxlens);\n\n  /*fill in the first table for short symbols, or secondary table for long symbols*/\n  numpresent = 0;\n  for(i = 0; i < tree->numcodes; ++i) {\n    unsigned l = tree->lengths[i];\n    unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/\n    /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/\n    unsigned reverse = reverseBits(symbol, l);\n    if(l == 0) continue;\n    numpresent++;\n\n    if(l <= FIRSTBITS) {\n      /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/\n      unsigned num = 1u << (FIRSTBITS - l);\n      unsigned j;\n      for(j = 0; j < num; ++j) {\n        /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/\n        unsigned index = reverse | (j << l);\n        if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/\n        tree->table_len[index] = l;\n        tree->table_value[index] = i;\n      }\n    } else {\n      /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/\n      /*the FIRSTBITS MSBs of the symbol are the first table index*/\n      unsigned index = reverse & mask;\n      unsigned maxlen = tree->table_len[index];\n      /*log2 of secondary table length, should be >= l - FIRSTBITS*/\n      unsigned tablelen = maxlen - FIRSTBITS;\n      unsigned start = tree->table_value[index]; /*starting index in secondary table*/\n      unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/\n      unsigned j;\n      if(maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/\n      for(j = 0; j < num; ++j) {\n        unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */\n        unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));\n        tree->table_len[index2] = l;\n        tree->table_value[index2] = i;\n      }\n    }\n  }\n\n  if(numpresent < 2) {\n    /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits,\n    but deflate uses 1 bit instead. In case of 0 symbols, no symbols can\n    appear at all, but such huffman tree could still exist (e.g. if distance\n    codes are never used). In both cases, not all symbols of the table will be\n    filled in. Fill them in with an invalid symbol value so returning them from\n    huffmanDecodeSymbol will cause error. */\n    for(i = 0; i < size; ++i) {\n      if(tree->table_len[i] == 16) {\n        /* As length, use a value smaller than FIRSTBITS for the head table,\n        and a value larger than FIRSTBITS for the secondary table, to ensure\n        valid behavior for advanceBits when reading this symbol. */\n        tree->table_len[i] = (i < headsize) ? 1 : (FIRSTBITS + 1);\n        tree->table_value[i] = INVALIDSYMBOL;\n      }\n    }\n  } else {\n    /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.\n    If that is not the case (due to too long length codes), the table will not\n    have been fully used, and this is an error (not all bit combinations can be\n    decoded): an oversubscribed huffman tree, indicated by error 55. */\n    for(i = 0; i < size; ++i) {\n      if(tree->table_len[i] == 16) return 55;\n    }\n  }\n\n  return 0;\n}\n\n/*\nSecond step for the ...makeFromLengths and ...makeFromFrequencies functions.\nnumcodes, lengths and maxbitlen must already be filled in correctly. return\nvalue is error.\n*/\nstatic unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) {\n  unsigned* blcount;\n  unsigned* nextcode;\n  unsigned error = 0;\n  unsigned bits, n;\n\n  tree->codes = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned));\n  blcount = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned));\n  nextcode = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned));\n  if(!tree->codes || !blcount || !nextcode) error = 83; /*alloc fail*/\n\n  if(!error) {\n    for(n = 0; n != tree->maxbitlen + 1; n++) blcount[n] = nextcode[n] = 0;\n    /*step 1: count number of instances of each code length*/\n    for(bits = 0; bits != tree->numcodes; ++bits) ++blcount[tree->lengths[bits]];\n    /*step 2: generate the nextcode values*/\n    for(bits = 1; bits <= tree->maxbitlen; ++bits) {\n      nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1u;\n    }\n    /*step 3: generate all the codes*/\n    for(n = 0; n != tree->numcodes; ++n) {\n      if(tree->lengths[n] != 0) {\n        tree->codes[n] = nextcode[tree->lengths[n]]++;\n        /*remove superfluous bits from the code*/\n        tree->codes[n] &= ((1u << tree->lengths[n]) - 1u);\n      }\n    }\n  }\n\n  lodepng_free(blcount);\n  lodepng_free(nextcode);\n\n  if(!error) error = HuffmanTree_makeTable(tree);\n  return error;\n}\n\n/*\ngiven the code lengths (as stored in the PNG file), generate the tree as defined\nby Deflate. maxbitlen is the maximum bits that a code in the tree can have.\nreturn value is error.\n*/\nstatic unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen,\n                                            size_t numcodes, unsigned maxbitlen) {\n  unsigned i;\n  tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned));\n  if(!tree->lengths) return 83; /*alloc fail*/\n  for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i];\n  tree->numcodes = (unsigned)numcodes; /*number of symbols*/\n  tree->maxbitlen = maxbitlen;\n  return HuffmanTree_makeFromLengths2(tree);\n}\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\n/*BPM: Boundary Package Merge, see \"A Fast and Space-Economical Algorithm for Length-Limited Coding\",\nJyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/\n\n/*chain node for boundary package merge*/\ntypedef struct BPMNode {\n  int weight; /*the sum of all weights in this chain*/\n  unsigned index; /*index of this leaf node (called \"count\" in the paper)*/\n  struct BPMNode* tail; /*the next nodes in this chain (null if last)*/\n  int in_use;\n} BPMNode;\n\n/*lists of chains*/\ntypedef struct BPMLists {\n  /*memory pool*/\n  unsigned memsize;\n  BPMNode* memory;\n  unsigned numfree;\n  unsigned nextfree;\n  BPMNode** freelist;\n  /*two heads of lookahead chains per list*/\n  unsigned listsize;\n  BPMNode** chains0;\n  BPMNode** chains1;\n} BPMLists;\n\n/*creates a new chain node with the given parameters, from the memory in the lists */\nstatic BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) {\n  unsigned i;\n  BPMNode* result;\n\n  /*memory full, so garbage collect*/\n  if(lists->nextfree >= lists->numfree) {\n    /*mark only those that are in use*/\n    for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0;\n    for(i = 0; i != lists->listsize; ++i) {\n      BPMNode* node;\n      for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1;\n      for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1;\n    }\n    /*collect those that are free*/\n    lists->numfree = 0;\n    for(i = 0; i != lists->memsize; ++i) {\n      if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i];\n    }\n    lists->nextfree = 0;\n  }\n\n  result = lists->freelist[lists->nextfree++];\n  result->weight = weight;\n  result->index = index;\n  result->tail = tail;\n  return result;\n}\n\n/*sort the leaves with stable mergesort*/\nstatic void bpmnode_sort(BPMNode* leaves, size_t num) {\n  BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num);\n  size_t width, counter = 0;\n  for(width = 1; width < num; width *= 2) {\n    BPMNode* a = (counter & 1) ? mem : leaves;\n    BPMNode* b = (counter & 1) ? leaves : mem;\n    size_t p;\n    for(p = 0; p < num; p += 2 * width) {\n      size_t q = (p + width > num) ? num : (p + width);\n      size_t r = (p + 2 * width > num) ? num : (p + 2 * width);\n      size_t i = p, j = q, k;\n      for(k = p; k < r; k++) {\n        if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++];\n        else b[k] = a[j++];\n      }\n    }\n    counter++;\n  }\n  if(counter & 1) lodepng_memcpy(leaves, mem, sizeof(*leaves) * num);\n  lodepng_free(mem);\n}\n\n/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/\nstatic void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) {\n  unsigned lastindex = lists->chains1[c]->index;\n\n  if(c == 0) {\n    if(lastindex >= numpresent) return;\n    lists->chains0[c] = lists->chains1[c];\n    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0);\n  } else {\n    /*sum of the weights of the head nodes of the previous lookahead chains.*/\n    int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight;\n    lists->chains0[c] = lists->chains1[c];\n    if(lastindex < numpresent && sum > leaves[lastindex].weight) {\n      lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail);\n      return;\n    }\n    lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]);\n    /*in the end we are only interested in the chain of the last list, so no\n    need to recurse if we're at the last one (this gives measurable speedup)*/\n    if(num + 1 < (int)(2 * numpresent - 2)) {\n      boundaryPM(lists, leaves, numpresent, c - 1, num);\n      boundaryPM(lists, leaves, numpresent, c - 1, num);\n    }\n  }\n}\n\nunsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,\n                                      size_t numcodes, unsigned maxbitlen) {\n  unsigned error = 0;\n  unsigned i;\n  size_t numpresent = 0; /*number of symbols with non-zero frequency*/\n  BPMNode* leaves; /*the symbols, only those with > 0 frequency*/\n\n  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/\n  if((1u << maxbitlen) < (unsigned)numcodes) return 80; /*error: represent all symbols*/\n\n  leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves));\n  if(!leaves) return 83; /*alloc fail*/\n\n  for(i = 0; i != numcodes; ++i) {\n    if(frequencies[i] > 0) {\n      leaves[numpresent].weight = (int)frequencies[i];\n      leaves[numpresent].index = i;\n      ++numpresent;\n    }\n  }\n\n  lodepng_memset(lengths, 0, numcodes * sizeof(*lengths));\n\n  /*ensure at least two present symbols. There should be at least one symbol\n  according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To\n  make these work as well ensure there are at least two symbols. The\n  Package-Merge code below also doesn't work correctly if there's only one\n  symbol, it'd give it the theoretical 0 bits but in practice zlib wants 1 bit*/\n  if(numpresent == 0) {\n    lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/\n  } else if(numpresent == 1) {\n    lengths[leaves[0].index] = 1;\n    lengths[leaves[0].index == 0 ? 1 : 0] = 1;\n  } else {\n    BPMLists lists;\n    BPMNode* node;\n\n    bpmnode_sort(leaves, numpresent);\n\n    lists.listsize = maxbitlen;\n    lists.memsize = 2 * maxbitlen * (maxbitlen + 1);\n    lists.nextfree = 0;\n    lists.numfree = lists.memsize;\n    lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory));\n    lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*));\n    lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));\n    lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));\n    if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/\n\n    if(!error) {\n      for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];\n\n      bpmnode_create(&lists, leaves[0].weight, 1, 0);\n      bpmnode_create(&lists, leaves[1].weight, 2, 0);\n\n      for(i = 0; i != lists.listsize; ++i) {\n        lists.chains0[i] = &lists.memory[0];\n        lists.chains1[i] = &lists.memory[1];\n      }\n\n      /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/\n      for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i);\n\n      for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) {\n        for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index];\n      }\n    }\n\n    lodepng_free(lists.memory);\n    lodepng_free(lists.freelist);\n    lodepng_free(lists.chains0);\n    lodepng_free(lists.chains1);\n  }\n\n  lodepng_free(leaves);\n  return error;\n}\n\n/*Create the Huffman tree given the symbol frequencies*/\nstatic unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies,\n                                                size_t mincodes, size_t numcodes, unsigned maxbitlen) {\n  unsigned error = 0;\n  while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/\n  tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned));\n  if(!tree->lengths) return 83; /*alloc fail*/\n  tree->maxbitlen = maxbitlen;\n  tree->numcodes = (unsigned)numcodes; /*number of symbols*/\n\n  error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen);\n  if(!error) error = HuffmanTree_makeFromLengths2(tree);\n  return error;\n}\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/\nstatic unsigned generateFixedLitLenTree(HuffmanTree* tree) {\n  unsigned i, error = 0;\n  unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));\n  if(!bitlen) return 83; /*alloc fail*/\n\n  /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/\n  for(i =   0; i <= 143; ++i) bitlen[i] = 8;\n  for(i = 144; i <= 255; ++i) bitlen[i] = 9;\n  for(i = 256; i <= 279; ++i) bitlen[i] = 7;\n  for(i = 280; i <= 287; ++i) bitlen[i] = 8;\n\n  error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);\n\n  lodepng_free(bitlen);\n  return error;\n}\n\n/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/\nstatic unsigned generateFixedDistanceTree(HuffmanTree* tree) {\n  unsigned i, error = 0;\n  unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));\n  if(!bitlen) return 83; /*alloc fail*/\n\n  /*there are 32 distance codes, but 30-31 are unused*/\n  for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5;\n  error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);\n\n  lodepng_free(bitlen);\n  return error;\n}\n\n#ifdef LODEPNG_COMPILE_DECODER\n\n/*\nreturns the code. The bit reader must already have been ensured at least 15 bits\n*/\nstatic unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* codetree) {\n  unsigned short code = peekBits(reader, FIRSTBITS);\n  unsigned short l = codetree->table_len[code];\n  unsigned short value = codetree->table_value[code];\n  if(l <= FIRSTBITS) {\n    advanceBits(reader, l);\n    return value;\n  } else {\n    unsigned index2;\n    advanceBits(reader, FIRSTBITS);\n    index2 = value + peekBits(reader, l - FIRSTBITS);\n    advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);\n    return codetree->table_value[index2];\n  }\n}\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Inflator (Decompressor)                                                / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*get the tree of a deflated block with fixed tree, as specified in the deflate specification\nReturns error code.*/\nstatic unsigned getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) {\n  unsigned error = generateFixedLitLenTree(tree_ll);\n  if(error) return error;\n  return generateFixedDistanceTree(tree_d);\n}\n\n/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/\nstatic unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,\n                                      LodePNGBitReader* reader) {\n  /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/\n  unsigned error = 0;\n  unsigned n, HLIT, HDIST, HCLEN, i;\n\n  /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/\n  unsigned* bitlen_ll = 0; /*lit,len code lengths*/\n  unsigned* bitlen_d = 0; /*dist code lengths*/\n  /*code length code lengths (\"clcl\"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/\n  unsigned* bitlen_cl = 0;\n  HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/\n\n  if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/\n\n  /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/\n  HLIT =  readBits(reader, 5) + 257;\n  /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/\n  HDIST = readBits(reader, 5) + 1;\n  /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/\n  HCLEN = readBits(reader, 4) + 4;\n\n  bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));\n  if(!bitlen_cl) return 83 /*alloc fail*/;\n\n  HuffmanTree_init(&tree_cl);\n\n  while(!error) {\n    /*read the code length codes out of 3 * (amount of code length codes) bits*/\n    if(lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) {\n      ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/\n    }\n    for(i = 0; i != HCLEN; ++i) {\n      ensureBits9(reader, 3); /*out of bounds already checked above */\n      bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3);\n    }\n    for(i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) {\n      bitlen_cl[CLCL_ORDER[i]] = 0;\n    }\n\n    error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);\n    if(error) break;\n\n    /*now we can use this tree to read the lengths for the tree that this function will return*/\n    bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));\n    bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));\n    if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);\n    lodepng_memset(bitlen_ll, 0, NUM_DEFLATE_CODE_SYMBOLS * sizeof(*bitlen_ll));\n    lodepng_memset(bitlen_d, 0, NUM_DISTANCE_SYMBOLS * sizeof(*bitlen_d));\n\n    /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/\n    i = 0;\n    while(i < HLIT + HDIST) {\n      unsigned code;\n      ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/\n      code = huffmanDecodeSymbol(reader, &tree_cl);\n      if(code <= 15) /*a length code*/ {\n        if(i < HLIT) bitlen_ll[i] = code;\n        else bitlen_d[i - HLIT] = code;\n        ++i;\n      } else if(code == 16) /*repeat previous*/ {\n        unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/\n        unsigned value; /*set value to the previous code*/\n\n        if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/\n\n        replength += readBits(reader, 2);\n\n        if(i < HLIT + 1) value = bitlen_ll[i - 1];\n        else value = bitlen_d[i - HLIT - 1];\n        /*repeat this value in the next lengths*/\n        for(n = 0; n < replength; ++n) {\n          if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/\n          if(i < HLIT) bitlen_ll[i] = value;\n          else bitlen_d[i - HLIT] = value;\n          ++i;\n        }\n      } else if(code == 17) /*repeat \"0\" 3-10 times*/ {\n        unsigned replength = 3; /*read in the bits that indicate repeat length*/\n        replength += readBits(reader, 3);\n\n        /*repeat this value in the next lengths*/\n        for(n = 0; n < replength; ++n) {\n          if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/\n\n          if(i < HLIT) bitlen_ll[i] = 0;\n          else bitlen_d[i - HLIT] = 0;\n          ++i;\n        }\n      } else if(code == 18) /*repeat \"0\" 11-138 times*/ {\n        unsigned replength = 11; /*read in the bits that indicate repeat length*/\n        replength += readBits(reader, 7);\n\n        /*repeat this value in the next lengths*/\n        for(n = 0; n < replength; ++n) {\n          if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/\n\n          if(i < HLIT) bitlen_ll[i] = 0;\n          else bitlen_d[i - HLIT] = 0;\n          ++i;\n        }\n      } else /*if(code == INVALIDSYMBOL)*/ {\n        ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/\n      }\n      /*check if any of the ensureBits above went out of bounds*/\n      if(reader->bp > reader->bitsize) {\n        /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol\n        (10=no endcode, 11=wrong jump outside of tree)*/\n        /* TODO: revise error codes 10,11,50: the above comment is no longer valid */\n        ERROR_BREAK(50); /*error, bit pointer jumps past memory*/\n      }\n    }\n    if(error) break;\n\n    if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/\n\n    /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/\n    error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);\n    if(error) break;\n    error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);\n\n    break; /*end of error-while*/\n  }\n\n  lodepng_free(bitlen_cl);\n  lodepng_free(bitlen_ll);\n  lodepng_free(bitlen_d);\n  HuffmanTree_cleanup(&tree_cl);\n\n  return error;\n}\n\n/*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/\nstatic unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,\n                                    unsigned btype) {\n  unsigned error = 0;\n  HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/\n  HuffmanTree tree_d; /*the huffman tree for distance codes*/\n\n  HuffmanTree_init(&tree_ll);\n  HuffmanTree_init(&tree_d);\n\n  if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);\n  else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);\n\n  while(!error) /*decode all symbols until end reached, breaks at end code*/ {\n    /*code_ll is literal, length or end code*/\n    unsigned code_ll;\n    ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */\n    code_ll = huffmanDecodeSymbol(reader, &tree_ll);\n    if(code_ll <= 255) /*literal symbol*/ {\n      if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/);\n      out->data[out->size - 1] = (unsigned char)code_ll;\n    } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {\n      unsigned code_d, distance;\n      unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/\n      size_t start, backward, length;\n\n      /*part 1: get length base*/\n      length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];\n\n      /*part 2: get extra bits and add the value of that to length*/\n      numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];\n      if(numextrabits_l != 0) {\n        /* bits already ensured above */\n        length += readBits(reader, numextrabits_l);\n      }\n\n      /*part 3: get distance code*/\n      ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */\n      code_d = huffmanDecodeSymbol(reader, &tree_d);\n      if(code_d > 29) {\n        if(code_d <= 31) {\n          ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/\n        } else /* if(code_d == INVALIDSYMBOL) */{\n          ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/\n        }\n      }\n      distance = DISTANCEBASE[code_d];\n\n      /*part 4: get extra bits from distance*/\n      numextrabits_d = DISTANCEEXTRA[code_d];\n      if(numextrabits_d != 0) {\n        /* bits already ensured above */\n        distance += readBits(reader, numextrabits_d);\n      }\n\n      /*part 5: fill in all the out[n] values based on the length and dist*/\n      start = out->size;\n      if(distance > start) ERROR_BREAK(52); /*too long backward distance*/\n      backward = start - distance;\n\n      if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/);\n      if(distance < length) {\n        size_t forward;\n        lodepng_memcpy(out->data + start, out->data + backward, distance);\n        start += distance;\n        for(forward = distance; forward < length; ++forward) {\n          out->data[start++] = out->data[backward++];\n        }\n      } else {\n        lodepng_memcpy(out->data + start, out->data + backward, length);\n      }\n    } else if(code_ll == 256) {\n      break; /*end code, break the loop*/\n    } else /*if(code_ll == INVALIDSYMBOL)*/ {\n      ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/\n    }\n    /*check if any of the ensureBits above went out of bounds*/\n    if(reader->bp > reader->bitsize) {\n      /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol\n      (10=no endcode, 11=wrong jump outside of tree)*/\n      /* TODO: revise error codes 10,11,50: the above comment is no longer valid */\n      ERROR_BREAK(51); /*error, bit pointer jumps past memory*/\n    }\n  }\n\n  HuffmanTree_cleanup(&tree_ll);\n  HuffmanTree_cleanup(&tree_d);\n\n  return error;\n}\n\nstatic unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader,\n                                     const LodePNGDecompressSettings* settings) {\n  size_t bytepos;\n  size_t size = reader->size;\n  unsigned LEN, NLEN, error = 0;\n\n  /*go to first boundary of byte*/\n  bytepos = (reader->bp + 7u) >> 3u;\n\n  /*read LEN (2 bytes) and NLEN (2 bytes)*/\n  if(bytepos + 4 >= size) return 52; /*error, bit pointer will jump past memory*/\n  LEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2;\n  NLEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2;\n\n  /*check if 16-bit NLEN is really the one's complement of LEN*/\n  if(!settings->ignore_nlen && LEN + NLEN != 65535) {\n    return 21; /*error: NLEN is not one's complement of LEN*/\n  }\n\n  if(!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/\n\n  /*read the literal data: LEN bytes are now stored in the out buffer*/\n  if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/\n\n  lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);\n  bytepos += LEN;\n\n  reader->bp = bytepos << 3u;\n\n  return error;\n}\n\nstatic unsigned lodepng_inflatev(ucvector* out,\n                                 const unsigned char* in, size_t insize,\n                                 const LodePNGDecompressSettings* settings) {\n  unsigned BFINAL = 0;\n  LodePNGBitReader reader;\n  unsigned error = LodePNGBitReader_init(&reader, in, insize);\n\n  if(error) return error;\n\n  while(!BFINAL) {\n    unsigned BTYPE;\n    if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/\n    BFINAL = readBits(&reader, 1);\n    BTYPE = readBits(&reader, 2);\n\n    if(BTYPE == 3) return 20; /*error: invalid BTYPE*/\n    else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/\n    else error = inflateHuffmanBlock(out, &reader, BTYPE); /*compression, BTYPE 01 or 10*/\n\n    if(error) return error;\n  }\n\n  return error;\n}\n\nunsigned lodepng_inflate(unsigned char** out, size_t* outsize,\n                         const unsigned char* in, size_t insize,\n                         const LodePNGDecompressSettings* settings) {\n  ucvector v = ucvector_init(*out, *outsize);\n  unsigned error = lodepng_inflatev(&v, in, insize, settings);\n  *out = v.data;\n  *outsize = v.size;\n  return error;\n}\n\nstatic unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize,\n                        const LodePNGDecompressSettings* settings) {\n  if(settings->custom_inflate) {\n    unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings);\n    out->allocsize = out->size;\n    return error;\n  } else {\n    return lodepng_inflatev(out, in, insize, settings);\n  }\n}\n\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Deflator (Compressor)                                                  / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\nstatic const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258;\n\n/*search the index in the array, that has the largest value smaller than or equal to the given value,\ngiven array must be sorted (if no value is smaller, it returns the size of the given array)*/\nstatic size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) {\n  /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/\n  size_t left = 1;\n  size_t right = array_size - 1;\n\n  while(left <= right) {\n    size_t mid = (left + right) >> 1;\n    if(array[mid] >= value) right = mid - 1;\n    else left = mid + 1;\n  }\n  if(left >= array_size || array[left] > value) left--;\n  return left;\n}\n\nstatic void addLengthDistance(uivector* values, size_t length, size_t distance) {\n  /*values in encoded vector are those used by deflate:\n  0-255: literal bytes\n  256: end\n  257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits)\n  286-287: invalid*/\n\n  unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length);\n  unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]);\n  unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance);\n  unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]);\n\n  size_t pos = values->size;\n  /*TODO: return error when this fails (out of memory)*/\n  unsigned ok = uivector_resize(values, values->size + 4);\n  if(ok) {\n    values->data[pos + 0] = length_code + FIRST_LENGTH_CODE_INDEX;\n    values->data[pos + 1] = extra_length;\n    values->data[pos + 2] = dist_code;\n    values->data[pos + 3] = extra_distance;\n  }\n}\n\n/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3\nbytes as input because 3 is the minimum match length for deflate*/\nstatic const unsigned HASH_NUM_VALUES = 65536;\nstatic const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/\n\ntypedef struct Hash {\n  int* head; /*hash value to head circular pos - can be outdated if went around window*/\n  /*circular pos to prev circular pos*/\n  unsigned short* chain;\n  int* val; /*circular pos to hash value*/\n\n  /*TODO: do this not only for zeros but for any repeated byte. However for PNG\n  it's always going to be the zeros that dominate, so not important for PNG*/\n  int* headz; /*similar to head, but for chainz*/\n  unsigned short* chainz; /*those with same amount of zeros*/\n  unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/\n} Hash;\n\nstatic unsigned hash_init(Hash* hash, unsigned windowsize) {\n  unsigned i;\n  hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES);\n  hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize);\n  hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);\n\n  hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);\n  hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1));\n  hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize);\n\n  if(!hash->head || !hash->chain || !hash->val  || !hash->headz|| !hash->chainz || !hash->zeros) {\n    return 83; /*alloc fail*/\n  }\n\n  /*initialize hash table*/\n  for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1;\n  for(i = 0; i != windowsize; ++i) hash->val[i] = -1;\n  for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/\n\n  for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1;\n  for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/\n\n  return 0;\n}\n\nstatic void hash_cleanup(Hash* hash) {\n  lodepng_free(hash->head);\n  lodepng_free(hash->val);\n  lodepng_free(hash->chain);\n\n  lodepng_free(hash->zeros);\n  lodepng_free(hash->headz);\n  lodepng_free(hash->chainz);\n}\n\n\n\nstatic unsigned getHash(const unsigned char* data, size_t size, size_t pos) {\n  unsigned result = 0;\n  if(pos + 2 < size) {\n    /*A simple shift and xor hash is used. Since the data of PNGs is dominated\n    by zeroes due to the filters, a better hash does not have a significant\n    effect on speed in traversing the chain, and causes more time spend on\n    calculating the hash.*/\n    result ^= ((unsigned)data[pos + 0] << 0u);\n    result ^= ((unsigned)data[pos + 1] << 4u);\n    result ^= ((unsigned)data[pos + 2] << 8u);\n  } else {\n    size_t amount, i;\n    if(pos >= size) return 0;\n    amount = size - pos;\n    for(i = 0; i != amount; ++i) result ^= ((unsigned)data[pos + i] << (i * 8u));\n  }\n  return result & HASH_BIT_MASK;\n}\n\nstatic unsigned countZeros(const unsigned char* data, size_t size, size_t pos) {\n  const unsigned char* start = data + pos;\n  const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH;\n  if(end > data + size) end = data + size;\n  data = start;\n  while(data != end && *data == 0) ++data;\n  /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/\n  return (unsigned)(data - start);\n}\n\n/*wpos = pos & (windowsize - 1)*/\nstatic void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) {\n  hash->val[wpos] = (int)hashval;\n  if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval];\n  hash->head[hashval] = (int)wpos;\n\n  hash->zeros[wpos] = numzeros;\n  if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros];\n  hash->headz[numzeros] = (int)wpos;\n}\n\n/*\nLZ77-encode the data. Return value is error code. The input are raw bytes, the output\nis in the form of unsigned integers with codes representing for example literal bytes, or\nlength/distance pairs.\nIt uses a hash table technique to let it encode faster. When doing LZ77 encoding, a\nsliding window (of windowsize) is used, and all past bytes in that window can be used as\nthe \"dictionary\". A brute force search through all possible distances would be slow, and\nthis hash technique is one out of several ways to speed this up.\n*/\nstatic unsigned encodeLZ77(uivector* out, Hash* hash,\n                           const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize,\n                           unsigned minmatch, unsigned nicematch, unsigned lazymatching) {\n  size_t pos;\n  unsigned i, error = 0;\n  /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/\n  unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8u;\n  unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64;\n\n  unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/\n  unsigned numzeros = 0;\n\n  unsigned offset; /*the offset represents the distance in LZ77 terminology*/\n  unsigned length;\n  unsigned lazy = 0;\n  unsigned lazylength = 0, lazyoffset = 0;\n  unsigned hashval;\n  unsigned current_offset, current_length;\n  unsigned prev_offset;\n  const unsigned char *lastptr, *foreptr, *backptr;\n  unsigned hashpos;\n\n  if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/\n  if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/\n\n  if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH;\n\n  for(pos = inpos; pos < insize; ++pos) {\n    size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/\n    unsigned chainlength = 0;\n\n    hashval = getHash(in, insize, pos);\n\n    if(usezeros && hashval == 0) {\n      if(numzeros == 0) numzeros = countZeros(in, insize, pos);\n      else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;\n    } else {\n      numzeros = 0;\n    }\n\n    updateHashChain(hash, wpos, hashval, numzeros);\n\n    /*the length and offset found for the current position*/\n    length = 0;\n    offset = 0;\n\n    hashpos = hash->chain[wpos];\n\n    lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];\n\n    /*search for the longest string*/\n    prev_offset = 0;\n    for(;;) {\n      if(chainlength++ >= maxchainlength) break;\n      current_offset = (unsigned)(hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize);\n\n      if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/\n      prev_offset = current_offset;\n      if(current_offset > 0) {\n        /*test the next characters*/\n        foreptr = &in[pos];\n        backptr = &in[pos - current_offset];\n\n        /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/\n        if(numzeros >= 3) {\n          unsigned skip = hash->zeros[hashpos];\n          if(skip > numzeros) skip = numzeros;\n          backptr += skip;\n          foreptr += skip;\n        }\n\n        while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ {\n          ++backptr;\n          ++foreptr;\n        }\n        current_length = (unsigned)(foreptr - &in[pos]);\n\n        if(current_length > length) {\n          length = current_length; /*the longest length*/\n          offset = current_offset; /*the offset that is related to this longest length*/\n          /*jump out once a length of max length is found (speed gain). This also jumps\n          out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/\n          if(current_length >= nicematch) break;\n        }\n      }\n\n      if(hashpos == hash->chain[hashpos]) break;\n\n      if(numzeros >= 3 && length > numzeros) {\n        hashpos = hash->chainz[hashpos];\n        if(hash->zeros[hashpos] != numzeros) break;\n      } else {\n        hashpos = hash->chain[hashpos];\n        /*outdated hash value, happens if particular value was not encountered in whole last window*/\n        if(hash->val[hashpos] != (int)hashval) break;\n      }\n    }\n\n    if(lazymatching) {\n      if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) {\n        lazy = 1;\n        lazylength = length;\n        lazyoffset = offset;\n        continue; /*try the next byte*/\n      }\n      if(lazy) {\n        lazy = 0;\n        if(pos == 0) ERROR_BREAK(81);\n        if(length > lazylength + 1) {\n          /*push the previous character as literal*/\n          if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);\n        } else {\n          length = lazylength;\n          offset = lazyoffset;\n          hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/\n          hash->headz[numzeros] = -1; /*idem*/\n          --pos;\n        }\n      }\n    }\n    if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);\n\n    /*encode it as length/distance pair or literal value*/\n    if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ {\n      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);\n    } else if(length < minmatch || (length == 3 && offset > 4096)) {\n      /*compensate for the fact that longer offsets have more extra bits, a\n      length of only 3 may be not worth it then*/\n      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);\n    } else {\n      addLengthDistance(out, length, offset);\n      for(i = 1; i < length; ++i) {\n        ++pos;\n        wpos = pos & (windowsize - 1);\n        hashval = getHash(in, insize, pos);\n        if(usezeros && hashval == 0) {\n          if(numzeros == 0) numzeros = countZeros(in, insize, pos);\n          else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;\n        } else {\n          numzeros = 0;\n        }\n        updateHashChain(hash, wpos, hashval, numzeros);\n      }\n    }\n  } /*end of the loop through each character of input*/\n\n  return error;\n}\n\n/* /////////////////////////////////////////////////////////////////////////// */\n\nstatic unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) {\n  /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte,\n  2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/\n\n  size_t i, numdeflateblocks = (datasize + 65534u) / 65535u;\n  unsigned datapos = 0;\n  for(i = 0; i != numdeflateblocks; ++i) {\n    unsigned BFINAL, BTYPE, LEN, NLEN;\n    unsigned char firstbyte;\n    size_t pos = out->size;\n\n    BFINAL = (i == numdeflateblocks - 1);\n    BTYPE = 0;\n\n    LEN = 65535;\n    if(datasize - datapos < 65535u) LEN = (unsigned)datasize - datapos;\n    NLEN = 65535 - LEN;\n\n    if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/\n\n    firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u));\n    out->data[pos + 0] = firstbyte;\n    out->data[pos + 1] = (unsigned char)(LEN & 255);\n    out->data[pos + 2] = (unsigned char)(LEN >> 8u);\n    out->data[pos + 3] = (unsigned char)(NLEN & 255);\n    out->data[pos + 4] = (unsigned char)(NLEN >> 8u);\n    lodepng_memcpy(out->data + pos + 5, data + datapos, LEN);\n    datapos += LEN;\n  }\n\n  return 0;\n}\n\n/*\nwrite the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees.\ntree_ll: the tree for lit and len codes.\ntree_d: the tree for distance codes.\n*/\nstatic void writeLZ77data(LodePNGBitWriter* writer, const uivector* lz77_encoded,\n                          const HuffmanTree* tree_ll, const HuffmanTree* tree_d) {\n  size_t i = 0;\n  for(i = 0; i != lz77_encoded->size; ++i) {\n    unsigned val = lz77_encoded->data[i];\n    writeBitsReversed(writer, tree_ll->codes[val], tree_ll->lengths[val]);\n    if(val > 256) /*for a length code, 3 more things have to be added*/ {\n      unsigned length_index = val - FIRST_LENGTH_CODE_INDEX;\n      unsigned n_length_extra_bits = LENGTHEXTRA[length_index];\n      unsigned length_extra_bits = lz77_encoded->data[++i];\n\n      unsigned distance_code = lz77_encoded->data[++i];\n\n      unsigned distance_index = distance_code;\n      unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index];\n      unsigned distance_extra_bits = lz77_encoded->data[++i];\n\n      writeBits(writer, length_extra_bits, n_length_extra_bits);\n      writeBitsReversed(writer, tree_d->codes[distance_code], tree_d->lengths[distance_code]);\n      writeBits(writer, distance_extra_bits, n_distance_extra_bits);\n    }\n  }\n}\n\n/*Deflate for a block of type \"dynamic\", that is, with freely, optimally, created huffman trees*/\nstatic unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash,\n                               const unsigned char* data, size_t datapos, size_t dataend,\n                               const LodePNGCompressSettings* settings, unsigned final) {\n  unsigned error = 0;\n\n  /*\n  A block is compressed as follows: The PNG data is lz77 encoded, resulting in\n  literal bytes and length/distance pairs. This is then huffman compressed with\n  two huffman trees. One huffman tree is used for the lit and len values (\"ll\"),\n  another huffman tree is used for the dist values (\"d\"). These two trees are\n  stored using their code lengths, and to compress even more these code lengths\n  are also run-length encoded and huffman compressed. This gives a huffman tree\n  of code lengths \"cl\". The code lengths used to describe this third tree are\n  the code length code lengths (\"clcl\").\n  */\n\n  /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/\n  uivector lz77_encoded;\n  HuffmanTree tree_ll; /*tree for lit,len values*/\n  HuffmanTree tree_d; /*tree for distance codes*/\n  HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/\n  unsigned* frequencies_ll = 0; /*frequency of lit,len codes*/\n  unsigned* frequencies_d = 0; /*frequency of dist codes*/\n  unsigned* frequencies_cl = 0; /*frequency of code length codes*/\n  unsigned* bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/\n  unsigned* bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/\n  size_t datasize = dataend - datapos;\n\n  /*\n  If we could call \"bitlen_cl\" the the code length code lengths (\"clcl\"), that is the bit lengths of codes to represent\n  tree_cl in CLCL_ORDER, then due to the huffman compression of huffman tree representations (\"two levels\"), there are\n  some analogies:\n  bitlen_lld is to tree_cl what data is to tree_ll and tree_d.\n  bitlen_lld_e is to bitlen_lld what lz77_encoded is to data.\n  bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded.\n  */\n\n  unsigned BFINAL = final;\n  size_t i;\n  size_t numcodes_ll, numcodes_d, numcodes_lld, numcodes_lld_e, numcodes_cl;\n  unsigned HLIT, HDIST, HCLEN;\n\n  uivector_init(&lz77_encoded);\n  HuffmanTree_init(&tree_ll);\n  HuffmanTree_init(&tree_d);\n  HuffmanTree_init(&tree_cl);\n  /* could fit on stack, but >1KB is on the larger side so allocate instead */\n  frequencies_ll = (unsigned*)lodepng_malloc(286 * sizeof(*frequencies_ll));\n  frequencies_d = (unsigned*)lodepng_malloc(30 * sizeof(*frequencies_d));\n  frequencies_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl));\n\n  if(!frequencies_ll || !frequencies_d || !frequencies_cl) error = 83; /*alloc fail*/\n\n  /*This while loop never loops due to a break at the end, it is here to\n  allow breaking out of it to the cleanup phase on error conditions.*/\n  while(!error) {\n    lodepng_memset(frequencies_ll, 0, 286 * sizeof(*frequencies_ll));\n    lodepng_memset(frequencies_d, 0, 30 * sizeof(*frequencies_d));\n    lodepng_memset(frequencies_cl, 0, NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl));\n\n    if(settings->use_lz77) {\n      error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,\n                         settings->minmatch, settings->nicematch, settings->lazymatching);\n      if(error) break;\n    } else {\n      if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/);\n      for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/\n    }\n\n    /*Count the frequencies of lit, len and dist codes*/\n    for(i = 0; i != lz77_encoded.size; ++i) {\n      unsigned symbol = lz77_encoded.data[i];\n      ++frequencies_ll[symbol];\n      if(symbol > 256) {\n        unsigned dist = lz77_encoded.data[i + 2];\n        ++frequencies_d[dist];\n        i += 3;\n      }\n    }\n    frequencies_ll[256] = 1; /*there will be exactly 1 end code, at the end of the block*/\n\n    /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/\n    error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll, 257, 286, 15);\n    if(error) break;\n    /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/\n    error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d, 2, 30, 15);\n    if(error) break;\n\n    numcodes_ll = LODEPNG_MIN(tree_ll.numcodes, 286);\n    numcodes_d = LODEPNG_MIN(tree_d.numcodes, 30);\n    /*store the code lengths of both generated trees in bitlen_lld*/\n    numcodes_lld = numcodes_ll + numcodes_d;\n    bitlen_lld = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld));\n    /*numcodes_lld_e never needs more size than bitlen_lld*/\n    bitlen_lld_e = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld_e));\n    if(!bitlen_lld || !bitlen_lld_e) ERROR_BREAK(83); /*alloc fail*/\n    numcodes_lld_e = 0;\n\n    for(i = 0; i != numcodes_ll; ++i) bitlen_lld[i] = tree_ll.lengths[i];\n    for(i = 0; i != numcodes_d; ++i) bitlen_lld[numcodes_ll + i] = tree_d.lengths[i];\n\n    /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times),\n    17 (3-10 zeroes), 18 (11-138 zeroes)*/\n    for(i = 0; i != numcodes_lld; ++i) {\n      unsigned j = 0; /*amount of repetitions*/\n      while(i + j + 1 < numcodes_lld && bitlen_lld[i + j + 1] == bitlen_lld[i]) ++j;\n\n      if(bitlen_lld[i] == 0 && j >= 2) /*repeat code for zeroes*/ {\n        ++j; /*include the first zero*/\n        if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ {\n          bitlen_lld_e[numcodes_lld_e++] = 17;\n          bitlen_lld_e[numcodes_lld_e++] = j - 3;\n        } else /*repeat code 18 supports max 138 zeroes*/ {\n          if(j > 138) j = 138;\n          bitlen_lld_e[numcodes_lld_e++] = 18;\n          bitlen_lld_e[numcodes_lld_e++] = j - 11;\n        }\n        i += (j - 1);\n      } else if(j >= 3) /*repeat code for value other than zero*/ {\n        size_t k;\n        unsigned num = j / 6u, rest = j % 6u;\n        bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i];\n        for(k = 0; k < num; ++k) {\n          bitlen_lld_e[numcodes_lld_e++] = 16;\n          bitlen_lld_e[numcodes_lld_e++] = 6 - 3;\n        }\n        if(rest >= 3) {\n          bitlen_lld_e[numcodes_lld_e++] = 16;\n          bitlen_lld_e[numcodes_lld_e++] = rest - 3;\n        }\n        else j -= rest;\n        i += j;\n      } else /*too short to benefit from repeat code*/ {\n        bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i];\n      }\n    }\n\n    /*generate tree_cl, the huffmantree of huffmantrees*/\n    for(i = 0; i != numcodes_lld_e; ++i) {\n      ++frequencies_cl[bitlen_lld_e[i]];\n      /*after a repeat code come the bits that specify the number of repetitions,\n      those don't need to be in the frequencies_cl calculation*/\n      if(bitlen_lld_e[i] >= 16) ++i;\n    }\n\n    error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl,\n                                            NUM_CODE_LENGTH_CODES, NUM_CODE_LENGTH_CODES, 7);\n    if(error) break;\n\n    /*compute amount of code-length-code-lengths to output*/\n    numcodes_cl = NUM_CODE_LENGTH_CODES;\n    /*trim zeros at the end (using CLCL_ORDER), but minimum size must be 4 (see HCLEN below)*/\n    while(numcodes_cl > 4u && tree_cl.lengths[CLCL_ORDER[numcodes_cl - 1u]] == 0) {\n      numcodes_cl--;\n    }\n\n    /*\n    Write everything into the output\n\n    After the BFINAL and BTYPE, the dynamic block consists out of the following:\n    - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN\n    - (HCLEN+4)*3 bits code lengths of code length alphabet\n    - HLIT + 257 code lengths of lit/length alphabet (encoded using the code length\n      alphabet, + possible repetition codes 16, 17, 18)\n    - HDIST + 1 code lengths of distance alphabet (encoded using the code length\n      alphabet, + possible repetition codes 16, 17, 18)\n    - compressed data\n    - 256 (end code)\n    */\n\n    /*Write block type*/\n    writeBits(writer, BFINAL, 1);\n    writeBits(writer, 0, 1); /*first bit of BTYPE \"dynamic\"*/\n    writeBits(writer, 1, 1); /*second bit of BTYPE \"dynamic\"*/\n\n    /*write the HLIT, HDIST and HCLEN values*/\n    /*all three sizes take trimmed ending zeroes into account, done either by HuffmanTree_makeFromFrequencies\n    or in the loop for numcodes_cl above, which saves space. */\n    HLIT = (unsigned)(numcodes_ll - 257);\n    HDIST = (unsigned)(numcodes_d - 1);\n    HCLEN = (unsigned)(numcodes_cl - 4);\n    writeBits(writer, HLIT, 5);\n    writeBits(writer, HDIST, 5);\n    writeBits(writer, HCLEN, 4);\n\n    /*write the code lengths of the code length alphabet (\"bitlen_cl\")*/\n    for(i = 0; i != numcodes_cl; ++i) writeBits(writer, tree_cl.lengths[CLCL_ORDER[i]], 3);\n\n    /*write the lengths of the lit/len AND the dist alphabet*/\n    for(i = 0; i != numcodes_lld_e; ++i) {\n      writeBitsReversed(writer, tree_cl.codes[bitlen_lld_e[i]], tree_cl.lengths[bitlen_lld_e[i]]);\n      /*extra bits of repeat codes*/\n      if(bitlen_lld_e[i] == 16) writeBits(writer, bitlen_lld_e[++i], 2);\n      else if(bitlen_lld_e[i] == 17) writeBits(writer, bitlen_lld_e[++i], 3);\n      else if(bitlen_lld_e[i] == 18) writeBits(writer, bitlen_lld_e[++i], 7);\n    }\n\n    /*write the compressed data symbols*/\n    writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d);\n    /*error: the length of the end code 256 must be larger than 0*/\n    if(tree_ll.lengths[256] == 0) ERROR_BREAK(64);\n\n    /*write the end code*/\n    writeBitsReversed(writer, tree_ll.codes[256], tree_ll.lengths[256]);\n\n    break; /*end of error-while*/\n  }\n\n  /*cleanup*/\n  uivector_cleanup(&lz77_encoded);\n  HuffmanTree_cleanup(&tree_ll);\n  HuffmanTree_cleanup(&tree_d);\n  HuffmanTree_cleanup(&tree_cl);\n  lodepng_free(frequencies_ll);\n  lodepng_free(frequencies_d);\n  lodepng_free(frequencies_cl);\n  lodepng_free(bitlen_lld);\n  lodepng_free(bitlen_lld_e);\n\n  return error;\n}\n\nstatic unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash,\n                             const unsigned char* data,\n                             size_t datapos, size_t dataend,\n                             const LodePNGCompressSettings* settings, unsigned final) {\n  HuffmanTree tree_ll; /*tree for literal values and length codes*/\n  HuffmanTree tree_d; /*tree for distance codes*/\n\n  unsigned BFINAL = final;\n  unsigned error = 0;\n  size_t i;\n\n  HuffmanTree_init(&tree_ll);\n  HuffmanTree_init(&tree_d);\n\n  error = generateFixedLitLenTree(&tree_ll);\n  if(!error) error = generateFixedDistanceTree(&tree_d);\n\n  if(!error) {\n    writeBits(writer, BFINAL, 1);\n    writeBits(writer, 1, 1); /*first bit of BTYPE*/\n    writeBits(writer, 0, 1); /*second bit of BTYPE*/\n\n    if(settings->use_lz77) /*LZ77 encoded*/ {\n      uivector lz77_encoded;\n      uivector_init(&lz77_encoded);\n      error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize,\n                         settings->minmatch, settings->nicematch, settings->lazymatching);\n      if(!error) writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d);\n      uivector_cleanup(&lz77_encoded);\n    } else /*no LZ77, but still will be Huffman compressed*/ {\n      for(i = datapos; i < dataend; ++i) {\n        writeBitsReversed(writer, tree_ll.codes[data[i]], tree_ll.lengths[data[i]]);\n      }\n    }\n    /*add END code*/\n    if(!error) writeBitsReversed(writer,tree_ll.codes[256], tree_ll.lengths[256]);\n  }\n\n  /*cleanup*/\n  HuffmanTree_cleanup(&tree_ll);\n  HuffmanTree_cleanup(&tree_d);\n\n  return error;\n}\n\nstatic unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize,\n                                 const LodePNGCompressSettings* settings) {\n  unsigned error = 0;\n  size_t i, blocksize, numdeflateblocks;\n  Hash hash;\n  LodePNGBitWriter writer;\n\n  LodePNGBitWriter_init(&writer, out);\n\n  if(settings->btype > 2) return 61;\n  else if(settings->btype == 0) return deflateNoCompression(out, in, insize);\n  else if(settings->btype == 1) blocksize = insize;\n  else /*if(settings->btype == 2)*/ {\n    /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/\n    blocksize = insize / 8u + 8;\n    if(blocksize < 65536) blocksize = 65536;\n    if(blocksize > 262144) blocksize = 262144;\n  }\n\n  numdeflateblocks = (insize + blocksize - 1) / blocksize;\n  if(numdeflateblocks == 0) numdeflateblocks = 1;\n\n  error = hash_init(&hash, settings->windowsize);\n\n  if(!error) {\n    for(i = 0; i != numdeflateblocks && !error; ++i) {\n      unsigned final = (i == numdeflateblocks - 1);\n      size_t start = i * blocksize;\n      size_t end = start + blocksize;\n      if(end > insize) end = insize;\n\n      if(settings->btype == 1) error = deflateFixed(&writer, &hash, in, start, end, settings, final);\n      else if(settings->btype == 2) error = deflateDynamic(&writer, &hash, in, start, end, settings, final);\n    }\n  }\n\n  hash_cleanup(&hash);\n\n  return error;\n}\n\nunsigned lodepng_deflate(unsigned char** out, size_t* outsize,\n                         const unsigned char* in, size_t insize,\n                         const LodePNGCompressSettings* settings) {\n  ucvector v = ucvector_init(*out, *outsize);\n  unsigned error = lodepng_deflatev(&v, in, insize, settings);\n  *out = v.data;\n  *outsize = v.size;\n  return error;\n}\n\nstatic unsigned deflate(unsigned char** out, size_t* outsize,\n                        const unsigned char* in, size_t insize,\n                        const LodePNGCompressSettings* settings) {\n  if(settings->custom_deflate) {\n    return settings->custom_deflate(out, outsize, in, insize, settings);\n  } else {\n    return lodepng_deflate(out, outsize, in, insize, settings);\n  }\n}\n\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Adler32                                                                / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\nstatic unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) {\n  unsigned s1 = adler & 0xffffu;\n  unsigned s2 = (adler >> 16u) & 0xffffu;\n\n  while(len != 0u) {\n    unsigned i;\n    /*at least 5552 sums can be done before the sums overflow, saving a lot of module divisions*/\n    unsigned amount = len > 5552u ? 5552u : len;\n    len -= amount;\n    for(i = 0; i != amount; ++i) {\n      s1 += (*data++);\n      s2 += s1;\n    }\n    s1 %= 65521u;\n    s2 %= 65521u;\n  }\n\n  return (s2 << 16u) | s1;\n}\n\n/*Return the adler32 of the bytes data[0..len-1]*/\nstatic unsigned adler32(const unsigned char* data, unsigned len) {\n  return update_adler32(1u, data, len);\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Zlib                                                                   / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_DECODER\n\nstatic unsigned lodepng_zlib_decompressv(ucvector* out,\n                                         const unsigned char* in, size_t insize,\n                                         const LodePNGDecompressSettings* settings) {\n  unsigned error = 0;\n  unsigned CM, CINFO, FDICT;\n\n  if(insize < 2) return 53; /*error, size of zlib data too small*/\n  /*read information from zlib header*/\n  if((in[0] * 256 + in[1]) % 31 != 0) {\n    /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/\n    return 24;\n  }\n\n  CM = in[0] & 15;\n  CINFO = (in[0] >> 4) & 15;\n  /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/\n  FDICT = (in[1] >> 5) & 1;\n  /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/\n\n  if(CM != 8 || CINFO > 7) {\n    /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/\n    return 25;\n  }\n  if(FDICT != 0) {\n    /*error: the specification of PNG says about the zlib stream:\n      \"The additional flags shall not specify a preset dictionary.\"*/\n    return 26;\n  }\n\n  error = inflatev(out, in + 2, insize - 2, settings);\n  if(error) return error;\n\n  if(!settings->ignore_adler32) {\n    unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]);\n    unsigned checksum = adler32(out->data, (unsigned)(out->size));\n    if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/\n  }\n\n  return 0; /*no error*/\n}\n\n\nunsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,\n                                 size_t insize, const LodePNGDecompressSettings* settings) {\n  ucvector v = ucvector_init(*out, *outsize);\n  unsigned error = lodepng_zlib_decompressv(&v, in, insize, settings);\n  *out = v.data;\n  *outsize = v.size;\n  return error;\n}\n\n/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */\nstatic unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size,\n                                const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) {\n  if(settings->custom_zlib) {\n    return settings->custom_zlib(out, outsize, in, insize, settings);\n  } else {\n    unsigned error;\n    ucvector v = ucvector_init(*out, *outsize);\n    if(expected_size) {\n      /*reserve the memory to avoid intermediate reallocations*/\n      ucvector_resize(&v, *outsize + expected_size);\n      v.size = *outsize;\n    }\n    error = lodepng_zlib_decompressv(&v, in, insize, settings);\n    *out = v.data;\n    *outsize = v.size;\n    return error;\n  }\n}\n\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\nunsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,\n                               size_t insize, const LodePNGCompressSettings* settings) {\n  size_t i;\n  unsigned error;\n  unsigned char* deflatedata = 0;\n  size_t deflatesize = 0;\n\n  error = deflate(&deflatedata, &deflatesize, in, insize, settings);\n\n  *out = NULL;\n  *outsize = 0;\n  if(!error) {\n    *outsize = deflatesize + 6;\n    *out = (unsigned char*)lodepng_malloc(*outsize);\n    if(!*out) error = 83; /*alloc fail*/\n  }\n\n  if(!error) {\n    unsigned ADLER32 = adler32(in, (unsigned)insize);\n    /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/\n    unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/\n    unsigned FLEVEL = 0;\n    unsigned FDICT = 0;\n    unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64;\n    unsigned FCHECK = 31 - CMFFLG % 31;\n    CMFFLG += FCHECK;\n\n    (*out)[0] = (unsigned char)(CMFFLG >> 8);\n    (*out)[1] = (unsigned char)(CMFFLG & 255);\n    for(i = 0; i != deflatesize; ++i) (*out)[i + 2] = deflatedata[i];\n    lodepng_set32bitInt(&(*out)[*outsize - 4], ADLER32);\n  }\n\n  lodepng_free(deflatedata);\n  return error;\n}\n\n/* compress using the default or custom zlib function */\nstatic unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,\n                              size_t insize, const LodePNGCompressSettings* settings) {\n  if(settings->custom_zlib) {\n    return settings->custom_zlib(out, outsize, in, insize, settings);\n  } else {\n    return lodepng_zlib_compress(out, outsize, in, insize, settings);\n  }\n}\n\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#else /*no LODEPNG_COMPILE_ZLIB*/\n\n#ifdef LODEPNG_COMPILE_DECODER\nstatic unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size,\n                                const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) {\n  if(!settings->custom_zlib) return 87; /*no custom zlib function provided */\n  (void)expected_size;\n  return settings->custom_zlib(out, outsize, in, insize, settings);\n}\n#endif /*LODEPNG_COMPILE_DECODER*/\n#ifdef LODEPNG_COMPILE_ENCODER\nstatic unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,\n                              size_t insize, const LodePNGCompressSettings* settings) {\n  if(!settings->custom_zlib) return 87; /*no custom zlib function provided */\n  return settings->custom_zlib(out, outsize, in, insize, settings);\n}\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#endif /*LODEPNG_COMPILE_ZLIB*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\n/*this is a good tradeoff between speed and compression ratio*/\n#define DEFAULT_WINDOWSIZE 2048\n\nvoid lodepng_compress_settings_init(LodePNGCompressSettings* settings) {\n  /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/\n  settings->btype = 2;\n  settings->use_lz77 = 1;\n  settings->windowsize = DEFAULT_WINDOWSIZE;\n  settings->minmatch = 3;\n  settings->nicematch = 128;\n  settings->lazymatching = 1;\n\n  settings->custom_zlib = 0;\n  settings->custom_deflate = 0;\n  settings->custom_context = 0;\n}\n\nconst LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0};\n\n\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n\nvoid lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) {\n  settings->ignore_adler32 = 0;\n  settings->ignore_nlen = 0;\n\n  settings->custom_zlib = 0;\n  settings->custom_inflate = 0;\n  settings->custom_context = 0;\n}\n\nconst LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0};\n\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* // End of Zlib related code. Begin of PNG related code.                 // */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_PNG\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / CRC32                                                                  / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n\n#ifndef LODEPNG_NO_COMPILE_CRC\n/* CRC polynomial: 0xedb88320 */\nstatic unsigned lodepng_crc32_table[256] = {\n           0u, 1996959894u, 3993919788u, 2567524794u,  124634137u, 1886057615u, 3915621685u, 2657392035u,\n   249268274u, 2044508324u, 3772115230u, 2547177864u,  162941995u, 2125561021u, 3887607047u, 2428444049u,\n   498536548u, 1789927666u, 4089016648u, 2227061214u,  450548861u, 1843258603u, 4107580753u, 2211677639u,\n   325883990u, 1684777152u, 4251122042u, 2321926636u,  335633487u, 1661365465u, 4195302755u, 2366115317u,\n   997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,\n   901097722u, 1119000684u, 3686517206u, 2898065728u,  853044451u, 1172266101u, 3705015759u, 2882616665u,\n   651767980u, 1373503546u, 3369554304u, 3218104598u,  565507253u, 1454621731u, 3485111705u, 3099436303u,\n   671266974u, 1594198024u, 3322730930u, 2970347812u,  795835527u, 1483230225u, 3244367275u, 3060149565u,\n  1994146192u,   31158534u, 2563907772u, 4023717930u, 1907459465u,  112637215u, 2680153253u, 3904427059u,\n  2013776290u,  251722036u, 2517215374u, 3775830040u, 2137656763u,  141376813u, 2439277719u, 3865271297u,\n  1802195444u,  476864866u, 2238001368u, 4066508878u, 1812370925u,  453092731u, 2181625025u, 4111451223u,\n  1706088902u,  314042704u, 2344532202u, 4240017532u, 1658658271u,  366619977u, 2362670323u, 4224994405u,\n  1303535960u,  984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u,\n  1131014506u,  879679996u, 2909243462u, 3663771856u, 1141124467u,  855842277u, 2852801631u, 3708648649u,\n  1342533948u,  654459306u, 3188396048u, 3373015174u, 1466479909u,  544179635u, 3110523913u, 3462522015u,\n  1591671054u,  702138776u, 2966460450u, 3352799412u, 1504918807u,  783551873u, 3082640443u, 3233442989u,\n  3988292384u, 2596254646u,   62317068u, 1957810842u, 3939845945u, 2647816111u,   81470997u, 1943803523u,\n  3814918930u, 2489596804u,  225274430u, 2053790376u, 3826175755u, 2466906013u,  167816743u, 2097651377u,\n  4027552580u, 2265490386u,  503444072u, 1762050814u, 4150417245u, 2154129355u,  426522225u, 1852507879u,\n  4275313526u, 2312317920u,  282753626u, 1742555852u, 4189708143u, 2394877945u,  397917763u, 1622183637u,\n  3604390888u, 2714866558u,  953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,\n  3624741850u, 2936675148u,  906185462u, 1090812512u, 3747672003u, 2825379669u,  829329135u, 1181335161u,\n  3412177804u, 3160834842u,  628085408u, 1382605366u, 3423369109u, 3138078467u,  570562233u, 1426400815u,\n  3317316542u, 2998733608u,  733239954u, 1555261956u, 3268935591u, 3050360625u,  752459403u, 1541320221u,\n  2607071920u, 3965973030u, 1969922972u,   40735498u, 2617837225u, 3943577151u, 1913087877u,   83908371u,\n  2512341634u, 3803740692u, 2075208622u,  213261112u, 2463272603u, 3855990285u, 2094854071u,  198958881u,\n  2262029012u, 4057260610u, 1759359992u,  534414190u, 2176718541u, 4139329115u, 1873836001u,  414664567u,\n  2282248934u, 4279200368u, 1711684554u,  285281116u, 2405801727u, 4167216745u, 1634467795u,  376229701u,\n  2685067896u, 3608007406u, 1308918612u,  956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u,\n  2932959818u, 3654703836u, 1088359270u,  936918000u, 2847714899u, 3736837829u, 1202900863u,  817233897u,\n  3183342108u, 3401237130u, 1404277552u,  615818150u, 3134207493u, 3453421203u, 1423857449u,  601450431u,\n  3009837614u, 3294710456u, 1567103746u,  711928724u, 3020668471u, 3272380065u, 1510334235u,  755167117u\n};\n\n/*Return the CRC of the bytes buf[0..len-1].*/\nunsigned lodepng_crc32(const unsigned char* data, size_t length) {\n  unsigned r = 0xffffffffu;\n  size_t i;\n  for(i = 0; i < length; ++i) {\n    r = lodepng_crc32_table[(r ^ data[i]) & 0xffu] ^ (r >> 8u);\n  }\n  return r ^ 0xffffffffu;\n}\n#else /* !LODEPNG_NO_COMPILE_CRC */\nunsigned lodepng_crc32(const unsigned char* data, size_t length);\n#endif /* !LODEPNG_NO_COMPILE_CRC */\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Reading and writing PNG color channel bits                             / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/* The color channel bits of less-than-8-bit pixels are read with the MSB of bytes first,\nso LodePNGBitWriter and LodePNGBitReader can't be used for those. */\n\nstatic unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) {\n  unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);\n  ++(*bitpointer);\n  return result;\n}\n\n/* TODO: make this faster */\nstatic unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) {\n  unsigned result = 0;\n  size_t i;\n  for(i = 0 ; i < nbits; ++i) {\n    result <<= 1u;\n    result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream);\n  }\n  return result;\n}\n\nstatic void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) {\n  /*the current bit in bitstream may be 0 or 1 for this to work*/\n  if(bit == 0) bitstream[(*bitpointer) >> 3u] &=  (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u))));\n  else         bitstream[(*bitpointer) >> 3u] |=  (1u << (7u - ((*bitpointer) & 7u)));\n  ++(*bitpointer);\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / PNG chunks                                                             / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\nunsigned lodepng_chunk_length(const unsigned char* chunk) {\n  return lodepng_read32bitInt(&chunk[0]);\n}\n\nvoid lodepng_chunk_type(char type[5], const unsigned char* chunk) {\n  unsigned i;\n  for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i];\n  type[4] = 0; /*null termination char*/\n}\n\nunsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) {\n  if(lodepng_strlen(type) != 4) return 0;\n  return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);\n}\n\nunsigned char lodepng_chunk_ancillary(const unsigned char* chunk) {\n  return((chunk[4] & 32) != 0);\n}\n\nunsigned char lodepng_chunk_private(const unsigned char* chunk) {\n  return((chunk[6] & 32) != 0);\n}\n\nunsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) {\n  return((chunk[7] & 32) != 0);\n}\n\nunsigned char* lodepng_chunk_data(unsigned char* chunk) {\n  return &chunk[8];\n}\n\nconst unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) {\n  return &chunk[8];\n}\n\nunsigned lodepng_chunk_check_crc(const unsigned char* chunk) {\n  unsigned length = lodepng_chunk_length(chunk);\n  unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]);\n  /*the CRC is taken of the data and the 4 chunk type letters, not the length*/\n  unsigned checksum = lodepng_crc32(&chunk[4], length + 4);\n  if(CRC != checksum) return 1;\n  else return 0;\n}\n\nvoid lodepng_chunk_generate_crc(unsigned char* chunk) {\n  unsigned length = lodepng_chunk_length(chunk);\n  unsigned CRC = lodepng_crc32(&chunk[4], length + 4);\n  lodepng_set32bitInt(chunk + 8 + length, CRC);\n}\n\nunsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) {\n  if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/\n  if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47\n    && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {\n    /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */\n    return chunk + 8;\n  } else {\n    size_t total_chunk_length;\n    unsigned char* result;\n    if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;\n    result = chunk + total_chunk_length;\n    if(result < chunk) return end; /*pointer overflow*/\n    return result;\n  }\n}\n\nconst unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) {\n  if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/\n  if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47\n    && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {\n    /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */\n    return chunk + 8;\n  } else {\n    size_t total_chunk_length;\n    const unsigned char* result;\n    if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;\n    result = chunk + total_chunk_length;\n    if(result < chunk) return end; /*pointer overflow*/\n    return result;\n  }\n}\n\nunsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]) {\n  for(;;) {\n    if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */\n    if(lodepng_chunk_type_equals(chunk, type)) return chunk;\n    chunk = lodepng_chunk_next(chunk, end);\n  }\n}\n\nconst unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]) {\n  for(;;) {\n    if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */\n    if(lodepng_chunk_type_equals(chunk, type)) return chunk;\n    chunk = lodepng_chunk_next_const(chunk, end);\n  }\n}\n\nunsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk) {\n  unsigned i;\n  size_t total_chunk_length, new_length;\n  unsigned char *chunk_start, *new_buffer;\n\n  if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77;\n  if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77;\n\n  new_buffer = (unsigned char*)lodepng_realloc(*out, new_length);\n  if(!new_buffer) return 83; /*alloc fail*/\n  (*out) = new_buffer;\n  (*outsize) = new_length;\n  chunk_start = &(*out)[new_length - total_chunk_length];\n\n  for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i];\n\n  return 0;\n}\n\n/*Sets length and name and allocates the space for data and crc but does not\nset data or crc yet. Returns the start of the chunk in chunk. The start of\nthe data is at chunk + 8. To finalize chunk, add the data, then use\nlodepng_chunk_generate_crc */\nstatic unsigned lodepng_chunk_init(unsigned char** chunk,\n                                   ucvector* out,\n                                   unsigned length, const char* type) {\n  size_t new_length = out->size;\n  if(lodepng_addofl(new_length, length, &new_length)) return 77;\n  if(lodepng_addofl(new_length, 12, &new_length)) return 77;\n  if(!ucvector_resize(out, new_length)) return 83; /*alloc fail*/\n  *chunk = out->data + new_length - length - 12u;\n\n  /*1: length*/\n  lodepng_set32bitInt(*chunk, length);\n\n  /*2: chunk name (4 letters)*/\n  lodepng_memcpy(*chunk + 4, type, 4);\n\n  return 0;\n}\n\n/* like lodepng_chunk_create but with custom allocsize */\nstatic unsigned lodepng_chunk_createv(ucvector* out,\n                                      unsigned length, const char* type, const unsigned char* data) {\n  unsigned char* chunk;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type));\n\n  /*3: the data*/\n  lodepng_memcpy(chunk + 8, data, length);\n\n  /*4: CRC (of the chunkname characters and the data)*/\n  lodepng_chunk_generate_crc(chunk);\n\n  return 0;\n}\n\nunsigned lodepng_chunk_create(unsigned char** out, size_t* outsize,\n                              unsigned length, const char* type, const unsigned char* data) {\n  ucvector v = ucvector_init(*out, *outsize);\n  unsigned error = lodepng_chunk_createv(&v, length, type, data);\n  *out = v.data;\n  *outsize = v.size;\n  return error;\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / Color types, channels, bits                                            / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*checks if the colortype is valid and the bitdepth bd is allowed for this colortype.\nReturn value is a LodePNG error code.*/\nstatic unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) {\n  switch(colortype) {\n    case LCT_GREY:       if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break;\n    case LCT_RGB:        if(!(                                 bd == 8 || bd == 16)) return 37; break;\n    case LCT_PALETTE:    if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8            )) return 37; break;\n    case LCT_GREY_ALPHA: if(!(                                 bd == 8 || bd == 16)) return 37; break;\n    case LCT_RGBA:       if(!(                                 bd == 8 || bd == 16)) return 37; break;\n    case LCT_MAX_OCTET_VALUE: return 31; /* invalid color type */\n    default: return 31; /* invalid color type */\n  }\n  return 0; /*allowed color type / bits combination*/\n}\n\nstatic unsigned getNumColorChannels(LodePNGColorType colortype) {\n  switch(colortype) {\n    case LCT_GREY: return 1;\n    case LCT_RGB: return 3;\n    case LCT_PALETTE: return 1;\n    case LCT_GREY_ALPHA: return 2;\n    case LCT_RGBA: return 4;\n    case LCT_MAX_OCTET_VALUE: return 0; /* invalid color type */\n    default: return 0; /*invalid color type*/\n  }\n}\n\nstatic unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) {\n  /*bits per pixel is amount of channels * bits per channel*/\n  return getNumColorChannels(colortype) * bitdepth;\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\nvoid lodepng_color_mode_init(LodePNGColorMode* info) {\n  info->key_defined = 0;\n  info->key_r = info->key_g = info->key_b = 0;\n  info->colortype = LCT_RGBA;\n  info->bitdepth = 8;\n  info->palette = 0;\n  info->palettesize = 0;\n}\n\n/*allocates palette memory if needed, and initializes all colors to black*/\nstatic void lodepng_color_mode_alloc_palette(LodePNGColorMode* info) {\n  size_t i;\n  /*if the palette is already allocated, it will have size 1024 so no reallocation needed in that case*/\n  /*the palette must have room for up to 256 colors with 4 bytes each.*/\n  if(!info->palette) info->palette = (unsigned char*)lodepng_malloc(1024);\n  if(!info->palette) return; /*alloc fail*/\n  for(i = 0; i != 256; ++i) {\n    /*Initialize all unused colors with black, the value used for invalid palette indices.\n    This is an error according to the PNG spec, but common PNG decoders make it black instead.\n    That makes color conversion slightly faster due to no error handling needed.*/\n    info->palette[i * 4 + 0] = 0;\n    info->palette[i * 4 + 1] = 0;\n    info->palette[i * 4 + 2] = 0;\n    info->palette[i * 4 + 3] = 255;\n  }\n}\n\nvoid lodepng_color_mode_cleanup(LodePNGColorMode* info) {\n  lodepng_palette_clear(info);\n}\n\nunsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) {\n  lodepng_color_mode_cleanup(dest);\n  lodepng_memcpy(dest, source, sizeof(LodePNGColorMode));\n  if(source->palette) {\n    dest->palette = (unsigned char*)lodepng_malloc(1024);\n    if(!dest->palette && source->palettesize) return 83; /*alloc fail*/\n    lodepng_memcpy(dest->palette, source->palette, source->palettesize * 4);\n  }\n  return 0;\n}\n\nLodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth) {\n  LodePNGColorMode result;\n  lodepng_color_mode_init(&result);\n  result.colortype = colortype;\n  result.bitdepth = bitdepth;\n  return result;\n}\n\nstatic int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) {\n  size_t i;\n  if(a->colortype != b->colortype) return 0;\n  if(a->bitdepth != b->bitdepth) return 0;\n  if(a->key_defined != b->key_defined) return 0;\n  if(a->key_defined) {\n    if(a->key_r != b->key_r) return 0;\n    if(a->key_g != b->key_g) return 0;\n    if(a->key_b != b->key_b) return 0;\n  }\n  if(a->palettesize != b->palettesize) return 0;\n  for(i = 0; i != a->palettesize * 4; ++i) {\n    if(a->palette[i] != b->palette[i]) return 0;\n  }\n  return 1;\n}\n\nvoid lodepng_palette_clear(LodePNGColorMode* info) {\n  if(info->palette) lodepng_free(info->palette);\n  info->palette = 0;\n  info->palettesize = 0;\n}\n\nunsigned lodepng_palette_add(LodePNGColorMode* info,\n                             unsigned char r, unsigned char g, unsigned char b, unsigned char a) {\n  if(!info->palette) /*allocate palette if empty*/ {\n    lodepng_color_mode_alloc_palette(info);\n    if(!info->palette) return 83; /*alloc fail*/\n  }\n  if(info->palettesize >= 256) {\n    return 108; /*too many palette values*/\n  }\n  info->palette[4 * info->palettesize + 0] = r;\n  info->palette[4 * info->palettesize + 1] = g;\n  info->palette[4 * info->palettesize + 2] = b;\n  info->palette[4 * info->palettesize + 3] = a;\n  ++info->palettesize;\n  return 0;\n}\n\n/*calculate bits per pixel out of colortype and bitdepth*/\nunsigned lodepng_get_bpp(const LodePNGColorMode* info) {\n  return lodepng_get_bpp_lct(info->colortype, info->bitdepth);\n}\n\nunsigned lodepng_get_channels(const LodePNGColorMode* info) {\n  return getNumColorChannels(info->colortype);\n}\n\nunsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) {\n  return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA;\n}\n\nunsigned lodepng_is_alpha_type(const LodePNGColorMode* info) {\n  return (info->colortype & 4) != 0; /*4 or 6*/\n}\n\nunsigned lodepng_is_palette_type(const LodePNGColorMode* info) {\n  return info->colortype == LCT_PALETTE;\n}\n\nunsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) {\n  size_t i;\n  for(i = 0; i != info->palettesize; ++i) {\n    if(info->palette[i * 4 + 3] < 255) return 1;\n  }\n  return 0;\n}\n\nunsigned lodepng_can_have_alpha(const LodePNGColorMode* info) {\n  return info->key_defined\n      || lodepng_is_alpha_type(info)\n      || lodepng_has_palette_alpha(info);\n}\n\nstatic size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) {\n  size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth);\n  size_t n = (size_t)w * (size_t)h;\n  return ((n / 8u) * bpp) + ((n & 7u) * bpp + 7u) / 8u;\n}\n\nsize_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) {\n  return lodepng_get_raw_size_lct(w, h, color->colortype, color->bitdepth);\n}\n\n\n#ifdef LODEPNG_COMPILE_PNG\n\n/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer,\nand in addition has one extra byte per line: the filter byte. So this gives a larger\nresult than lodepng_get_raw_size. Set h to 1 to get the size of 1 row including filter byte. */\nstatic size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, unsigned bpp) {\n  /* + 1 for the filter byte, and possibly plus padding bits per line. */\n  /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but avoids overflow of w * bpp */\n  size_t line = ((size_t)(w / 8u) * bpp) + 1u + ((w & 7u) * bpp + 7u) / 8u;\n  return (size_t)h * line;\n}\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*Safely checks whether size_t overflow can be caused due to amount of pixels.\nThis check is overcautious rather than precise. If this check indicates no overflow,\nyou can safely compute in a size_t (but not an unsigned):\n-(size_t)w * (size_t)h * 8\n-amount of bytes in IDAT (including filter, padding and Adam7 bytes)\n-amount of bytes in raw color model\nReturns 1 if overflow possible, 0 if not.\n*/\nstatic int lodepng_pixel_overflow(unsigned w, unsigned h,\n                                  const LodePNGColorMode* pngcolor, const LodePNGColorMode* rawcolor) {\n  size_t bpp = LODEPNG_MAX(lodepng_get_bpp(pngcolor), lodepng_get_bpp(rawcolor));\n  size_t numpixels, total;\n  size_t line; /* bytes per line in worst case */\n\n  if(lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) return 1;\n  if(lodepng_mulofl(numpixels, 8, &total)) return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */\n\n  /* Bytes per scanline with the expression \"(w / 8u) * bpp) + ((w & 7u) * bpp + 7u) / 8u\" */\n  if(lodepng_mulofl((size_t)(w / 8u), bpp, &line)) return 1;\n  if(lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) return 1;\n\n  if(lodepng_addofl(line, 5, &line)) return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case */\n  if(lodepng_mulofl(line, h, &total)) return 1; /* Total bytes in worst case */\n\n  return 0; /* no overflow */\n}\n#endif /*LODEPNG_COMPILE_DECODER*/\n#endif /*LODEPNG_COMPILE_PNG*/\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n\nstatic void LodePNGUnknownChunks_init(LodePNGInfo* info) {\n  unsigned i;\n  for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0;\n  for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0;\n}\n\nstatic void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) {\n  unsigned i;\n  for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]);\n}\n\nstatic unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) {\n  unsigned i;\n\n  LodePNGUnknownChunks_cleanup(dest);\n\n  for(i = 0; i != 3; ++i) {\n    size_t j;\n    dest->unknown_chunks_size[i] = src->unknown_chunks_size[i];\n    dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]);\n    if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/\n    for(j = 0; j < src->unknown_chunks_size[i]; ++j) {\n      dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j];\n    }\n  }\n\n  return 0;\n}\n\n/******************************************************************************/\n\nstatic void LodePNGText_init(LodePNGInfo* info) {\n  info->text_num = 0;\n  info->text_keys = NULL;\n  info->text_strings = NULL;\n}\n\nstatic void LodePNGText_cleanup(LodePNGInfo* info) {\n  size_t i;\n  for(i = 0; i != info->text_num; ++i) {\n    string_cleanup(&info->text_keys[i]);\n    string_cleanup(&info->text_strings[i]);\n  }\n  lodepng_free(info->text_keys);\n  lodepng_free(info->text_strings);\n}\n\nstatic unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {\n  size_t i = 0;\n  dest->text_keys = 0;\n  dest->text_strings = 0;\n  dest->text_num = 0;\n  for(i = 0; i != source->text_num; ++i) {\n    CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));\n  }\n  return 0;\n}\n\nstatic unsigned lodepng_add_text_sized(LodePNGInfo* info, const char* key, const char* str, size_t size) {\n  char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1)));\n  char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1)));\n\n  if(new_keys) info->text_keys = new_keys;\n  if(new_strings) info->text_strings = new_strings;\n\n  if(!new_keys || !new_strings) return 83; /*alloc fail*/\n\n  ++info->text_num;\n  info->text_keys[info->text_num - 1] = alloc_string(key);\n  info->text_strings[info->text_num - 1] = alloc_string_sized(str, size);\n  if(!info->text_keys[info->text_num - 1] || !info->text_strings[info->text_num - 1]) return 83; /*alloc fail*/\n\n  return 0;\n}\n\nunsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) {\n  return lodepng_add_text_sized(info, key, str, lodepng_strlen(str));\n}\n\nvoid lodepng_clear_text(LodePNGInfo* info) {\n  LodePNGText_cleanup(info);\n}\n\n/******************************************************************************/\n\nstatic void LodePNGIText_init(LodePNGInfo* info) {\n  info->itext_num = 0;\n  info->itext_keys = NULL;\n  info->itext_langtags = NULL;\n  info->itext_transkeys = NULL;\n  info->itext_strings = NULL;\n}\n\nstatic void LodePNGIText_cleanup(LodePNGInfo* info) {\n  size_t i;\n  for(i = 0; i != info->itext_num; ++i) {\n    string_cleanup(&info->itext_keys[i]);\n    string_cleanup(&info->itext_langtags[i]);\n    string_cleanup(&info->itext_transkeys[i]);\n    string_cleanup(&info->itext_strings[i]);\n  }\n  lodepng_free(info->itext_keys);\n  lodepng_free(info->itext_langtags);\n  lodepng_free(info->itext_transkeys);\n  lodepng_free(info->itext_strings);\n}\n\nstatic unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) {\n  size_t i = 0;\n  dest->itext_keys = 0;\n  dest->itext_langtags = 0;\n  dest->itext_transkeys = 0;\n  dest->itext_strings = 0;\n  dest->itext_num = 0;\n  for(i = 0; i != source->itext_num; ++i) {\n    CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],\n                                        source->itext_transkeys[i], source->itext_strings[i]));\n  }\n  return 0;\n}\n\nvoid lodepng_clear_itext(LodePNGInfo* info) {\n  LodePNGIText_cleanup(info);\n}\n\nstatic unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, const char* langtag,\n                                        const char* transkey, const char* str, size_t size) {\n  char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1)));\n  char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1)));\n  char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1)));\n  char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1)));\n\n  if(new_keys) info->itext_keys = new_keys;\n  if(new_langtags) info->itext_langtags = new_langtags;\n  if(new_transkeys) info->itext_transkeys = new_transkeys;\n  if(new_strings) info->itext_strings = new_strings;\n\n  if(!new_keys || !new_langtags || !new_transkeys || !new_strings) return 83; /*alloc fail*/\n\n  ++info->itext_num;\n\n  info->itext_keys[info->itext_num - 1] = alloc_string(key);\n  info->itext_langtags[info->itext_num - 1] = alloc_string(langtag);\n  info->itext_transkeys[info->itext_num - 1] = alloc_string(transkey);\n  info->itext_strings[info->itext_num - 1] = alloc_string_sized(str, size);\n\n  return 0;\n}\n\nunsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,\n                           const char* transkey, const char* str) {\n  return lodepng_add_itext_sized(info, key, langtag, transkey, str, lodepng_strlen(str));\n}\n\n/* same as set but does not delete */\nstatic unsigned lodepng_assign_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) {\n  if(profile_size == 0) return 100; /*invalid ICC profile size*/\n\n  info->iccp_name = alloc_string(name);\n  info->iccp_profile = (unsigned char*)lodepng_malloc(profile_size);\n\n  if(!info->iccp_name || !info->iccp_profile) return 83; /*alloc fail*/\n\n  lodepng_memcpy(info->iccp_profile, profile, profile_size);\n  info->iccp_profile_size = profile_size;\n\n  return 0; /*ok*/\n}\n\nunsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) {\n  if(info->iccp_name) lodepng_clear_icc(info);\n  info->iccp_defined = 1;\n\n  return lodepng_assign_icc(info, name, profile, profile_size);\n}\n\nvoid lodepng_clear_icc(LodePNGInfo* info) {\n  string_cleanup(&info->iccp_name);\n  lodepng_free(info->iccp_profile);\n  info->iccp_profile = NULL;\n  info->iccp_profile_size = 0;\n  info->iccp_defined = 0;\n}\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\nvoid lodepng_info_init(LodePNGInfo* info) {\n  lodepng_color_mode_init(&info->color);\n  info->interlace_method = 0;\n  info->compression_method = 0;\n  info->filter_method = 0;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  info->background_defined = 0;\n  info->background_r = info->background_g = info->background_b = 0;\n\n  LodePNGText_init(info);\n  LodePNGIText_init(info);\n\n  info->time_defined = 0;\n  info->phys_defined = 0;\n\n  info->gama_defined = 0;\n  info->chrm_defined = 0;\n  info->srgb_defined = 0;\n  info->iccp_defined = 0;\n  info->iccp_name = NULL;\n  info->iccp_profile = NULL;\n\n  LodePNGUnknownChunks_init(info);\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n}\n\nvoid lodepng_info_cleanup(LodePNGInfo* info) {\n  lodepng_color_mode_cleanup(&info->color);\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  LodePNGText_cleanup(info);\n  LodePNGIText_cleanup(info);\n\n  lodepng_clear_icc(info);\n\n  LodePNGUnknownChunks_cleanup(info);\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n}\n\nunsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) {\n  lodepng_info_cleanup(dest);\n  lodepng_memcpy(dest, source, sizeof(LodePNGInfo));\n  lodepng_color_mode_init(&dest->color);\n  CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color));\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  CERROR_TRY_RETURN(LodePNGText_copy(dest, source));\n  CERROR_TRY_RETURN(LodePNGIText_copy(dest, source));\n  if(source->iccp_defined) {\n    CERROR_TRY_RETURN(lodepng_assign_icc(dest, source->iccp_name, source->iccp_profile, source->iccp_profile_size));\n  }\n\n  LodePNGUnknownChunks_init(dest);\n  CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source));\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n  return 0;\n}\n\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/\nstatic void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) {\n  unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/\n  /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/\n  unsigned p = index & m;\n  in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/\n  in = in << (bits * (m - p));\n  if(p == 0) out[index * bits / 8u] = in;\n  else out[index * bits / 8u] |= in;\n}\n\ntypedef struct ColorTree ColorTree;\n\n/*\nOne node of a color tree\nThis is the data structure used to count the number of unique colors and to get a palette\nindex for a color. It's like an octree, but because the alpha channel is used too, each\nnode has 16 instead of 8 children.\n*/\nstruct ColorTree {\n  ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/\n  int index; /*the payload. Only has a meaningful value if this is in the last level*/\n};\n\nstatic void color_tree_init(ColorTree* tree) {\n  lodepng_memset(tree->children, 0, 16 * sizeof(*tree->children));\n  tree->index = -1;\n}\n\nstatic void color_tree_cleanup(ColorTree* tree) {\n  int i;\n  for(i = 0; i != 16; ++i) {\n    if(tree->children[i]) {\n      color_tree_cleanup(tree->children[i]);\n      lodepng_free(tree->children[i]);\n    }\n  }\n}\n\n/*returns -1 if color not present, its index otherwise*/\nstatic int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {\n  int bit = 0;\n  for(bit = 0; bit < 8; ++bit) {\n    int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);\n    if(!tree->children[i]) return -1;\n    else tree = tree->children[i];\n  }\n  return tree ? tree->index : -1;\n}\n\n#ifdef LODEPNG_COMPILE_ENCODER\nstatic int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {\n  return color_tree_get(tree, r, g, b, a) >= 0;\n}\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n/*color is not allowed to already exist.\nIndex should be >= 0 (it's signed to be compatible with using -1 for \"doesn't exist\")\nReturns error code, or 0 if ok*/\nstatic unsigned color_tree_add(ColorTree* tree,\n                               unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) {\n  int bit;\n  for(bit = 0; bit < 8; ++bit) {\n    int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);\n    if(!tree->children[i]) {\n      tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree));\n      if(!tree->children[i]) return 83; /*alloc fail*/\n      color_tree_init(tree->children[i]);\n    }\n    tree = tree->children[i];\n  }\n  tree->index = (int)index;\n  return 0;\n}\n\n/*put a pixel, given its RGBA color, into image of any color type*/\nstatic unsigned rgba8ToPixel(unsigned char* out, size_t i,\n                             const LodePNGColorMode* mode, ColorTree* tree /*for palette*/,\n                             unsigned char r, unsigned char g, unsigned char b, unsigned char a) {\n  if(mode->colortype == LCT_GREY) {\n    unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/\n    if(mode->bitdepth == 8) out[i] = gray;\n    else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = gray;\n    else {\n      /*take the most significant bits of gray*/\n      gray = ((unsigned)gray >> (8u - mode->bitdepth)) & ((1u << mode->bitdepth) - 1u);\n      addColorBits(out, i, mode->bitdepth, gray);\n    }\n  } else if(mode->colortype == LCT_RGB) {\n    if(mode->bitdepth == 8) {\n      out[i * 3 + 0] = r;\n      out[i * 3 + 1] = g;\n      out[i * 3 + 2] = b;\n    } else {\n      out[i * 6 + 0] = out[i * 6 + 1] = r;\n      out[i * 6 + 2] = out[i * 6 + 3] = g;\n      out[i * 6 + 4] = out[i * 6 + 5] = b;\n    }\n  } else if(mode->colortype == LCT_PALETTE) {\n    int index = color_tree_get(tree, r, g, b, a);\n    if(index < 0) return 82; /*color not in palette*/\n    if(mode->bitdepth == 8) out[i] = index;\n    else addColorBits(out, i, mode->bitdepth, (unsigned)index);\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/\n    if(mode->bitdepth == 8) {\n      out[i * 2 + 0] = gray;\n      out[i * 2 + 1] = a;\n    } else if(mode->bitdepth == 16) {\n      out[i * 4 + 0] = out[i * 4 + 1] = gray;\n      out[i * 4 + 2] = out[i * 4 + 3] = a;\n    }\n  } else if(mode->colortype == LCT_RGBA) {\n    if(mode->bitdepth == 8) {\n      out[i * 4 + 0] = r;\n      out[i * 4 + 1] = g;\n      out[i * 4 + 2] = b;\n      out[i * 4 + 3] = a;\n    } else {\n      out[i * 8 + 0] = out[i * 8 + 1] = r;\n      out[i * 8 + 2] = out[i * 8 + 3] = g;\n      out[i * 8 + 4] = out[i * 8 + 5] = b;\n      out[i * 8 + 6] = out[i * 8 + 7] = a;\n    }\n  }\n\n  return 0; /*no error*/\n}\n\n/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/\nstatic void rgba16ToPixel(unsigned char* out, size_t i,\n                         const LodePNGColorMode* mode,\n                         unsigned short r, unsigned short g, unsigned short b, unsigned short a) {\n  if(mode->colortype == LCT_GREY) {\n    unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/\n    out[i * 2 + 0] = (gray >> 8) & 255;\n    out[i * 2 + 1] = gray & 255;\n  } else if(mode->colortype == LCT_RGB) {\n    out[i * 6 + 0] = (r >> 8) & 255;\n    out[i * 6 + 1] = r & 255;\n    out[i * 6 + 2] = (g >> 8) & 255;\n    out[i * 6 + 3] = g & 255;\n    out[i * 6 + 4] = (b >> 8) & 255;\n    out[i * 6 + 5] = b & 255;\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/\n    out[i * 4 + 0] = (gray >> 8) & 255;\n    out[i * 4 + 1] = gray & 255;\n    out[i * 4 + 2] = (a >> 8) & 255;\n    out[i * 4 + 3] = a & 255;\n  } else if(mode->colortype == LCT_RGBA) {\n    out[i * 8 + 0] = (r >> 8) & 255;\n    out[i * 8 + 1] = r & 255;\n    out[i * 8 + 2] = (g >> 8) & 255;\n    out[i * 8 + 3] = g & 255;\n    out[i * 8 + 4] = (b >> 8) & 255;\n    out[i * 8 + 5] = b & 255;\n    out[i * 8 + 6] = (a >> 8) & 255;\n    out[i * 8 + 7] = a & 255;\n  }\n}\n\n/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/\nstatic void getPixelColorRGBA8(unsigned char* r, unsigned char* g,\n                               unsigned char* b, unsigned char* a,\n                               const unsigned char* in, size_t i,\n                               const LodePNGColorMode* mode) {\n  if(mode->colortype == LCT_GREY) {\n    if(mode->bitdepth == 8) {\n      *r = *g = *b = in[i];\n      if(mode->key_defined && *r == mode->key_r) *a = 0;\n      else *a = 255;\n    } else if(mode->bitdepth == 16) {\n      *r = *g = *b = in[i * 2 + 0];\n      if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;\n      else *a = 255;\n    } else {\n      unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/\n      size_t j = i * mode->bitdepth;\n      unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);\n      *r = *g = *b = (value * 255) / highest;\n      if(mode->key_defined && value == mode->key_r) *a = 0;\n      else *a = 255;\n    }\n  } else if(mode->colortype == LCT_RGB) {\n    if(mode->bitdepth == 8) {\n      *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2];\n      if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0;\n      else *a = 255;\n    } else {\n      *r = in[i * 6 + 0];\n      *g = in[i * 6 + 2];\n      *b = in[i * 6 + 4];\n      if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r\n         && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g\n         && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;\n      else *a = 255;\n    }\n  } else if(mode->colortype == LCT_PALETTE) {\n    unsigned index;\n    if(mode->bitdepth == 8) index = in[i];\n    else {\n      size_t j = i * mode->bitdepth;\n      index = readBitsFromReversedStream(&j, in, mode->bitdepth);\n    }\n    /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/\n    *r = mode->palette[index * 4 + 0];\n    *g = mode->palette[index * 4 + 1];\n    *b = mode->palette[index * 4 + 2];\n    *a = mode->palette[index * 4 + 3];\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    if(mode->bitdepth == 8) {\n      *r = *g = *b = in[i * 2 + 0];\n      *a = in[i * 2 + 1];\n    } else {\n      *r = *g = *b = in[i * 4 + 0];\n      *a = in[i * 4 + 2];\n    }\n  } else if(mode->colortype == LCT_RGBA) {\n    if(mode->bitdepth == 8) {\n      *r = in[i * 4 + 0];\n      *g = in[i * 4 + 1];\n      *b = in[i * 4 + 2];\n      *a = in[i * 4 + 3];\n    } else {\n      *r = in[i * 8 + 0];\n      *g = in[i * 8 + 2];\n      *b = in[i * 8 + 4];\n      *a = in[i * 8 + 6];\n    }\n  }\n}\n\n/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color\nmode test cases, optimized to convert the colors much faster, when converting\nto the common case of RGBA with 8 bit per channel. buffer must be RGBA with\nenough memory.*/\nstatic void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels,\n                                const unsigned char* LODEPNG_RESTRICT in,\n                                const LodePNGColorMode* mode) {\n  unsigned num_channels = 4;\n  size_t i;\n  if(mode->colortype == LCT_GREY) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i];\n        buffer[3] = 255;\n      }\n      if(mode->key_defined) {\n        buffer -= numpixels * num_channels;\n        for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n          if(buffer[0] == mode->key_r) buffer[3] = 0;\n        }\n      }\n    } else if(mode->bitdepth == 16) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 2];\n        buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255;\n      }\n    } else {\n      unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/\n      size_t j = 0;\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);\n        buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;\n        buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255;\n      }\n    }\n  } else if(mode->colortype == LCT_RGB) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        lodepng_memcpy(buffer, &in[i * 3], 3);\n        buffer[3] = 255;\n      }\n      if(mode->key_defined) {\n        buffer -= numpixels * num_channels;\n        for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n          if(buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b) buffer[3] = 0;\n        }\n      }\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = in[i * 6 + 0];\n        buffer[1] = in[i * 6 + 2];\n        buffer[2] = in[i * 6 + 4];\n        buffer[3] = mode->key_defined\n           && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r\n           && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g\n           && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255;\n      }\n    }\n  } else if(mode->colortype == LCT_PALETTE) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned index = in[i];\n        /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/\n        lodepng_memcpy(buffer, &mode->palette[index * 4], 4);\n      }\n    } else {\n      size_t j = 0;\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth);\n        /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/\n        lodepng_memcpy(buffer, &mode->palette[index * 4], 4);\n      }\n    }\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];\n        buffer[3] = in[i * 2 + 1];\n      }\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];\n        buffer[3] = in[i * 4 + 2];\n      }\n    }\n  } else if(mode->colortype == LCT_RGBA) {\n    if(mode->bitdepth == 8) {\n      lodepng_memcpy(buffer, in, numpixels * 4);\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = in[i * 8 + 0];\n        buffer[1] = in[i * 8 + 2];\n        buffer[2] = in[i * 8 + 4];\n        buffer[3] = in[i * 8 + 6];\n      }\n    }\n  }\n}\n\n/*Similar to getPixelColorsRGBA8, but with 3-channel RGB output.*/\nstatic void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels,\n                               const unsigned char* LODEPNG_RESTRICT in,\n                               const LodePNGColorMode* mode) {\n  const unsigned num_channels = 3;\n  size_t i;\n  if(mode->colortype == LCT_GREY) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i];\n      }\n    } else if(mode->bitdepth == 16) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 2];\n      }\n    } else {\n      unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/\n      size_t j = 0;\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);\n        buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;\n      }\n    }\n  } else if(mode->colortype == LCT_RGB) {\n    if(mode->bitdepth == 8) {\n      lodepng_memcpy(buffer, in, numpixels * 3);\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = in[i * 6 + 0];\n        buffer[1] = in[i * 6 + 2];\n        buffer[2] = in[i * 6 + 4];\n      }\n    }\n  } else if(mode->colortype == LCT_PALETTE) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned index = in[i];\n        /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/\n        lodepng_memcpy(buffer, &mode->palette[index * 4], 3);\n      }\n    } else {\n      size_t j = 0;\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth);\n        /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/\n        lodepng_memcpy(buffer, &mode->palette[index * 4], 3);\n      }\n    }\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];\n      }\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];\n      }\n    }\n  } else if(mode->colortype == LCT_RGBA) {\n    if(mode->bitdepth == 8) {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        lodepng_memcpy(buffer, &in[i * 4], 3);\n      }\n    } else {\n      for(i = 0; i != numpixels; ++i, buffer += num_channels) {\n        buffer[0] = in[i * 8 + 0];\n        buffer[1] = in[i * 8 + 2];\n        buffer[2] = in[i * 8 + 4];\n      }\n    }\n  }\n}\n\n/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with\ngiven color type, but the given color type must be 16-bit itself.*/\nstatic void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a,\n                                const unsigned char* in, size_t i, const LodePNGColorMode* mode) {\n  if(mode->colortype == LCT_GREY) {\n    *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1];\n    if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;\n    else *a = 65535;\n  } else if(mode->colortype == LCT_RGB) {\n    *r = 256u * in[i * 6 + 0] + in[i * 6 + 1];\n    *g = 256u * in[i * 6 + 2] + in[i * 6 + 3];\n    *b = 256u * in[i * 6 + 4] + in[i * 6 + 5];\n    if(mode->key_defined\n       && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r\n       && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g\n       && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;\n    else *a = 65535;\n  } else if(mode->colortype == LCT_GREY_ALPHA) {\n    *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1];\n    *a = 256u * in[i * 4 + 2] + in[i * 4 + 3];\n  } else if(mode->colortype == LCT_RGBA) {\n    *r = 256u * in[i * 8 + 0] + in[i * 8 + 1];\n    *g = 256u * in[i * 8 + 2] + in[i * 8 + 3];\n    *b = 256u * in[i * 8 + 4] + in[i * 8 + 5];\n    *a = 256u * in[i * 8 + 6] + in[i * 8 + 7];\n  }\n}\n\nunsigned lodepng_convert(unsigned char* out, const unsigned char* in,\n                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,\n                         unsigned w, unsigned h) {\n  size_t i;\n  ColorTree tree;\n  size_t numpixels = (size_t)w * (size_t)h;\n  unsigned error = 0;\n\n  if(mode_in->colortype == LCT_PALETTE && !mode_in->palette) {\n    return 107; /* error: must provide palette if input mode is palette */\n  }\n\n  if(lodepng_color_mode_equal(mode_out, mode_in)) {\n    size_t numbytes = lodepng_get_raw_size(w, h, mode_in);\n    lodepng_memcpy(out, in, numbytes);\n    return 0;\n  }\n\n  if(mode_out->colortype == LCT_PALETTE) {\n    size_t palettesize = mode_out->palettesize;\n    const unsigned char* palette = mode_out->palette;\n    size_t palsize = (size_t)1u << mode_out->bitdepth;\n    /*if the user specified output palette but did not give the values, assume\n    they want the values of the input color type (assuming that one is palette).\n    Note that we never create a new palette ourselves.*/\n    if(palettesize == 0) {\n      palettesize = mode_in->palettesize;\n      palette = mode_in->palette;\n      /*if the input was also palette with same bitdepth, then the color types are also\n      equal, so copy literally. This to preserve the exact indices that were in the PNG\n      even in case there are duplicate colors in the palette.*/\n      if(mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) {\n        size_t numbytes = lodepng_get_raw_size(w, h, mode_in);\n        lodepng_memcpy(out, in, numbytes);\n        return 0;\n      }\n    }\n    if(palettesize < palsize) palsize = palettesize;\n    color_tree_init(&tree);\n    for(i = 0; i != palsize; ++i) {\n      const unsigned char* p = &palette[i * 4];\n      error = color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i);\n      if(error) break;\n    }\n  }\n\n  if(!error) {\n    if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) {\n      for(i = 0; i != numpixels; ++i) {\n        unsigned short r = 0, g = 0, b = 0, a = 0;\n        getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);\n        rgba16ToPixel(out, i, mode_out, r, g, b, a);\n      }\n    } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) {\n      getPixelColorsRGBA8(out, numpixels, in, mode_in);\n    } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) {\n      getPixelColorsRGB8(out, numpixels, in, mode_in);\n    } else {\n      unsigned char r = 0, g = 0, b = 0, a = 0;\n      for(i = 0; i != numpixels; ++i) {\n        getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);\n        error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a);\n        if(error) break;\n      }\n    }\n  }\n\n  if(mode_out->colortype == LCT_PALETTE) {\n    color_tree_cleanup(&tree);\n  }\n\n  return error;\n}\n\n\n/* Converts a single rgb color without alpha from one type to another, color bits truncated to\ntheir bitdepth. In case of single channel (gray or palette), only the r channel is used. Slow\nfunction, do not use to process all pixels of an image. Alpha channel not supported on purpose:\nthis is for bKGD, supporting alpha may prevent it from finding a color in the palette, from the\nspecification it looks like bKGD should ignore the alpha values of the palette since it can use\nany palette index but doesn't have an alpha channel. Idem with ignoring color key. */\n// BCH 8 Oct. 2020 : Made this static to avoid warnings\nstatic unsigned lodepng_convert_rgb(\n    unsigned* r_out, unsigned* g_out, unsigned* b_out,\n    unsigned r_in, unsigned g_in, unsigned b_in,\n    const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in) {\n  unsigned r = 0, g = 0, b = 0;\n  unsigned mul = 65535 / ((1u << mode_in->bitdepth) - 1u); /*65535, 21845, 4369, 257, 1*/\n  unsigned shift = 16 - mode_out->bitdepth;\n\n  if(mode_in->colortype == LCT_GREY || mode_in->colortype == LCT_GREY_ALPHA) {\n    r = g = b = r_in * mul;\n  } else if(mode_in->colortype == LCT_RGB || mode_in->colortype == LCT_RGBA) {\n    r = r_in * mul;\n    g = g_in * mul;\n    b = b_in * mul;\n  } else if(mode_in->colortype == LCT_PALETTE) {\n    if(r_in >= mode_in->palettesize) return 82;\n    r = mode_in->palette[r_in * 4 + 0] * 257u;\n    g = mode_in->palette[r_in * 4 + 1] * 257u;\n    b = mode_in->palette[r_in * 4 + 2] * 257u;\n  } else {\n    return 31;\n  }\n\n  /* now convert to output format */\n  if(mode_out->colortype == LCT_GREY || mode_out->colortype == LCT_GREY_ALPHA) {\n    *r_out = r >> shift ;\n  } else if(mode_out->colortype == LCT_RGB || mode_out->colortype == LCT_RGBA) {\n    *r_out = r >> shift ;\n    *g_out = g >> shift ;\n    *b_out = b >> shift ;\n  } else if(mode_out->colortype == LCT_PALETTE) {\n    unsigned i;\n    /* a 16-bit color cannot be in the palette */\n    if((r >> 8) != (r & 255) || (g >> 8) != (g & 255) || (b >> 8) != (b & 255)) return 82;\n    for(i = 0; i < mode_out->palettesize; i++) {\n      unsigned j = i * 4;\n      if((r >> 8) == mode_out->palette[j + 0] && (g >> 8) == mode_out->palette[j + 1] &&\n          (b >> 8) == mode_out->palette[j + 2]) {\n        *r_out = i;\n        return 0;\n      }\n    }\n    return 82;\n  } else {\n    return 31;\n  }\n\n  return 0;\n}\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\nvoid lodepng_color_stats_init(LodePNGColorStats* stats) {\n  /*stats*/\n  stats->colored = 0;\n  stats->key = 0;\n  stats->key_r = stats->key_g = stats->key_b = 0;\n  stats->alpha = 0;\n  stats->numcolors = 0;\n  stats->bits = 1;\n  stats->numpixels = 0;\n  /*settings*/\n  stats->allow_palette = 1;\n  stats->allow_greyscale = 1;\n}\n\n/*function used for debug purposes with C++*/\n/*void printColorStats(LodePNGColorStats* p) {\n  std::cout << \"colored: \" << (int)p->colored << \", \";\n  std::cout << \"key: \" << (int)p->key << \", \";\n  std::cout << \"key_r: \" << (int)p->key_r << \", \";\n  std::cout << \"key_g: \" << (int)p->key_g << \", \";\n  std::cout << \"key_b: \" << (int)p->key_b << \", \";\n  std::cout << \"alpha: \" << (int)p->alpha << \", \";\n  std::cout << \"numcolors: \" << (int)p->numcolors << \", \";\n  std::cout << \"bits: \" << (int)p->bits << std::endl;\n}*/\n\n/*Returns how many bits needed to represent given value (max 8 bit)*/\nstatic unsigned getValueRequiredBits(unsigned char value) {\n  if(value == 0 || value == 255) return 1;\n  /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/\n  if(value % 17 == 0) return value % 85 == 0 ? 2 : 4;\n  return 8;\n}\n\n/*stats must already have been inited. */\nunsigned lodepng_compute_color_stats(LodePNGColorStats* stats,\n                                     const unsigned char* in, unsigned w, unsigned h,\n                                     const LodePNGColorMode* mode_in) {\n  size_t i;\n  ColorTree tree;\n  size_t numpixels = (size_t)w * (size_t)h;\n  unsigned error = 0;\n\n  /* mark things as done already if it would be impossible to have a more expensive case */\n  unsigned colored_done = lodepng_is_greyscale_type(mode_in) ? 1 : 0;\n  unsigned alpha_done = lodepng_can_have_alpha(mode_in) ? 0 : 1;\n  unsigned numcolors_done = 0;\n  unsigned bpp = lodepng_get_bpp(mode_in);\n  unsigned bits_done = (stats->bits == 1 && bpp == 1) ? 1 : 0;\n  unsigned sixteen = 0; /* whether the input image is 16 bit */\n  unsigned maxnumcolors = 257;\n  if(bpp <= 8) maxnumcolors = LODEPNG_MIN(257, stats->numcolors + (1u << bpp));\n\n  stats->numpixels += numpixels;\n\n  /*if palette not allowed, no need to compute numcolors*/\n  if(!stats->allow_palette) numcolors_done = 1;\n\n  color_tree_init(&tree);\n\n  /*If the stats was already filled in from previous data, fill its palette in tree\n  and mark things as done already if we know they are the most expensive case already*/\n  if(stats->alpha) alpha_done = 1;\n  if(stats->colored) colored_done = 1;\n  if(stats->bits == 16) numcolors_done = 1;\n  if(stats->bits >= bpp) bits_done = 1;\n  if(stats->numcolors >= maxnumcolors) numcolors_done = 1;\n\n  if(!numcolors_done) {\n    for(i = 0; i < stats->numcolors; i++) {\n      const unsigned char* color = &stats->palette[i * 4];\n      error = color_tree_add(&tree, color[0], color[1], color[2], color[3], i);\n      if(error) goto cleanup;\n    }\n  }\n\n  /*Check if the 16-bit input is truly 16-bit*/\n  if(mode_in->bitdepth == 16 && !sixteen) {\n    unsigned short r = 0, g = 0, b = 0, a = 0;\n    for(i = 0; i != numpixels; ++i) {\n      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);\n      if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) ||\n         (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ {\n        stats->bits = 16;\n        sixteen = 1;\n        bits_done = 1;\n        numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/\n        break;\n      }\n    }\n  }\n\n  if(sixteen) {\n    unsigned short r = 0, g = 0, b = 0, a = 0;\n\n    for(i = 0; i != numpixels; ++i) {\n      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);\n\n      if(!colored_done && (r != g || r != b)) {\n        stats->colored = 1;\n        colored_done = 1;\n      }\n\n      if(!alpha_done) {\n        unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b);\n        if(a != 65535 && (a != 0 || (stats->key && !matchkey))) {\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n        } else if(a == 0 && !stats->alpha && !stats->key) {\n          stats->key = 1;\n          stats->key_r = r;\n          stats->key_g = g;\n          stats->key_b = b;\n        } else if(a == 65535 && stats->key && matchkey) {\n          /* Color key cannot be used if an opaque pixel also has that RGB color. */\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n        }\n      }\n      if(alpha_done && numcolors_done && colored_done && bits_done) break;\n    }\n\n    if(stats->key && !stats->alpha) {\n      for(i = 0; i != numpixels; ++i) {\n        getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);\n        if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) {\n          /* Color key cannot be used if an opaque pixel also has that RGB color. */\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n        }\n      }\n    }\n  } else /* < 16-bit */ {\n    unsigned char r = 0, g = 0, b = 0, a = 0;\n    for(i = 0; i != numpixels; ++i) {\n      getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);\n\n      if(!bits_done && stats->bits < 8) {\n        /*only r is checked, < 8 bits is only relevant for grayscale*/\n        unsigned bits = getValueRequiredBits(r);\n        if(bits > stats->bits) stats->bits = bits;\n      }\n      bits_done = (stats->bits >= bpp);\n\n      if(!colored_done && (r != g || r != b)) {\n        stats->colored = 1;\n        colored_done = 1;\n        if(stats->bits < 8) stats->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/\n      }\n\n      if(!alpha_done) {\n        unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b);\n        if(a != 255 && (a != 0 || (stats->key && !matchkey))) {\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n          if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/\n        } else if(a == 0 && !stats->alpha && !stats->key) {\n          stats->key = 1;\n          stats->key_r = r;\n          stats->key_g = g;\n          stats->key_b = b;\n        } else if(a == 255 && stats->key && matchkey) {\n          /* Color key cannot be used if an opaque pixel also has that RGB color. */\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n          if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/\n        }\n      }\n\n      if(!numcolors_done) {\n        if(!color_tree_has(&tree, r, g, b, a)) {\n          error = color_tree_add(&tree, r, g, b, a, stats->numcolors);\n          if(error) goto cleanup;\n          if(stats->numcolors < 256) {\n            unsigned char* p = stats->palette;\n            unsigned n = stats->numcolors;\n            p[n * 4 + 0] = r;\n            p[n * 4 + 1] = g;\n            p[n * 4 + 2] = b;\n            p[n * 4 + 3] = a;\n          }\n          ++stats->numcolors;\n          numcolors_done = stats->numcolors >= maxnumcolors;\n        }\n      }\n\n      if(alpha_done && numcolors_done && colored_done && bits_done) break;\n    }\n\n    if(stats->key && !stats->alpha) {\n      for(i = 0; i != numpixels; ++i) {\n        getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);\n        if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) {\n          /* Color key cannot be used if an opaque pixel also has that RGB color. */\n          stats->alpha = 1;\n          stats->key = 0;\n          alpha_done = 1;\n          if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/\n        }\n      }\n    }\n\n    /*make the stats's key always 16-bit for consistency - repeat each byte twice*/\n    stats->key_r += (stats->key_r << 8);\n    stats->key_g += (stats->key_g << 8);\n    stats->key_b += (stats->key_b << 8);\n  }\n\ncleanup:\n  color_tree_cleanup(&tree);\n  return error;\n}\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n/*Adds a single color to the color stats. The stats must already have been inited. The color must be given as 16-bit\n(with 2 bytes repeating for 8-bit and 65535 for opaque alpha channel). This function is expensive, do not call it for\nall pixels of an image but only for a few additional values. */\nstatic unsigned lodepng_color_stats_add(LodePNGColorStats* stats,\n                                        unsigned r, unsigned g, unsigned b, unsigned a) {\n  unsigned error = 0;\n  unsigned char image[8];\n  LodePNGColorMode mode;\n  lodepng_color_mode_init(&mode);\n  image[0] = r >> 8; image[1] = r; image[2] = g >> 8; image[3] = g;\n  image[4] = b >> 8; image[5] = b; image[6] = a >> 8; image[7] = a;\n  mode.bitdepth = 16;\n  mode.colortype = LCT_RGBA;\n  error = lodepng_compute_color_stats(stats, image, 1, 1, &mode);\n  lodepng_color_mode_cleanup(&mode);\n  return error;\n}\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\n/*Computes a minimal PNG color model that can contain all colors as indicated by the stats.\nThe stats should be computed with lodepng_compute_color_stats.\nmode_in is raw color profile of the image the stats were computed on, to copy palette order from when relevant.\nMinimal PNG color model means the color type and bit depth that gives smallest amount of bits in the output image,\ne.g. gray if only grayscale pixels, palette if less than 256 colors, color key if only single transparent color, ...\nThis is used if auto_convert is enabled (it is by default).\n*/\nstatic unsigned auto_choose_color(LodePNGColorMode* mode_out,\n                                  const LodePNGColorMode* mode_in,\n                                  const LodePNGColorStats* stats) {\n  unsigned error = 0;\n  unsigned palettebits;\n  size_t i, n;\n  size_t numpixels = stats->numpixels;\n  unsigned palette_ok, gray_ok;\n\n  unsigned alpha = stats->alpha;\n  unsigned key = stats->key;\n  unsigned bits = stats->bits;\n\n  mode_out->key_defined = 0;\n\n  if(key && numpixels <= 16) {\n    alpha = 1; /*too few pixels to justify tRNS chunk overhead*/\n    key = 0;\n    if(bits < 8) bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/\n  }\n\n  gray_ok = !stats->colored;\n  if(!stats->allow_greyscale) gray_ok = 0;\n  if(!gray_ok && bits < 8) bits = 8;\n\n  n = stats->numcolors;\n  palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8));\n  palette_ok = n <= 256 && bits <= 8 && n != 0; /*n==0 means likely numcolors wasn't computed*/\n  if(numpixels < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/\n  if(gray_ok && !alpha && bits <= palettebits) palette_ok = 0; /*gray is less overhead*/\n  if(!stats->allow_palette) palette_ok = 0;\n\n  if(palette_ok) {\n    const unsigned char* p = stats->palette;\n    lodepng_palette_clear(mode_out); /*remove potential earlier palette*/\n    for(i = 0; i != stats->numcolors; ++i) {\n      error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]);\n      if(error) break;\n    }\n\n    mode_out->colortype = LCT_PALETTE;\n    mode_out->bitdepth = palettebits;\n\n    if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize\n        && mode_in->bitdepth == mode_out->bitdepth) {\n      /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/\n      lodepng_color_mode_cleanup(mode_out);\n      lodepng_color_mode_copy(mode_out, mode_in);\n    }\n  } else /*8-bit or 16-bit per channel*/ {\n    mode_out->bitdepth = bits;\n    mode_out->colortype = alpha ? (gray_ok ? LCT_GREY_ALPHA : LCT_RGBA)\n                                : (gray_ok ? LCT_GREY : LCT_RGB);\n    if(key) {\n      unsigned mask = (1u << mode_out->bitdepth) - 1u; /*stats always uses 16-bit, mask converts it*/\n      mode_out->key_r = stats->key_r & mask;\n      mode_out->key_g = stats->key_g & mask;\n      mode_out->key_b = stats->key_b & mask;\n      mode_out->key_defined = 1;\n    }\n  }\n\n  return error;\n}\n\n#endif /* #ifdef LODEPNG_COMPILE_ENCODER */\n\n/*\nPaeth predictor, used by PNG filter type 4\nThe parameters are of type short, but should come from unsigned chars, the shorts\nare only needed to make the paeth calculation correct.\n*/\nstatic unsigned char paethPredictor(short a, short b, short c) {\n  short pa = LODEPNG_ABS(b - c);\n  short pb = LODEPNG_ABS(a - c);\n  short pc = LODEPNG_ABS(a + b - c - c);\n  /* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */\n  if(pb < pa) { a = b; pa = pb; }\n  return (pc < pa) ? c : a;\n}\n\n/*shared values used by multiple Adam7 related functions*/\n\nstatic const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/\nstatic const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/\nstatic const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/\nstatic const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/\n\n/*\nOutputs various dimensions and positions in the image related to the Adam7 reduced images.\npassw: output containing the width of the 7 passes\npassh: output containing the height of the 7 passes\nfilter_passstart: output containing the index of the start and end of each\n reduced image with filter bytes\npadded_passstart output containing the index of the start and end of each\n reduced image when without filter bytes but with padded scanlines\npassstart: output containing the index of the start and end of each reduced\n image without padding between scanlines, but still padding between the images\nw, h: width and height of non-interlaced image\nbpp: bits per pixel\n\"padded\" is only relevant if bpp is less than 8 and a scanline or image does not\n end at a full byte\n*/\nstatic void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8],\n                                size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) {\n  /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/\n  unsigned i;\n\n  /*calculate width and height in pixels of each pass*/\n  for(i = 0; i != 7; ++i) {\n    passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];\n    passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];\n    if(passw[i] == 0) passh[i] = 0;\n    if(passh[i] == 0) passw[i] = 0;\n  }\n\n  filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;\n  for(i = 0; i != 7; ++i) {\n    /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/\n    filter_passstart[i + 1] = filter_passstart[i]\n                            + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) : 0);\n    /*bits padded if needed to fill full byte at end of each scanline*/\n    padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u);\n    /*only padded at end of reduced image*/\n    passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7u) / 8u;\n  }\n}\n\n#ifdef LODEPNG_COMPILE_DECODER\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / PNG Decoder                                                            / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n/*read the information from the header and store it in the LodePNGInfo. return value is error*/\nunsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state,\n                         const unsigned char* in, size_t insize) {\n  unsigned width, height;\n  LodePNGInfo* info = &state->info_png;\n  if(insize == 0 || in == 0) {\n    CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/\n  }\n  if(insize < 33) {\n    CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/\n  }\n\n  /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/\n  /* TODO: remove this. One should use a new LodePNGState for new sessions */\n  lodepng_info_cleanup(info);\n  lodepng_info_init(info);\n\n  if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71\n     || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) {\n    CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/\n  }\n  if(lodepng_chunk_length(in + 8) != 13) {\n    CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/\n  }\n  if(!lodepng_chunk_type_equals(in + 8, \"IHDR\")) {\n    CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/\n  }\n\n  /*read the values given in the header*/\n  width = lodepng_read32bitInt(&in[16]);\n  height = lodepng_read32bitInt(&in[20]);\n  /*TODO: remove the undocumented feature that allows to give null pointers to width or height*/\n  if(w) *w = width;\n  if(h) *h = height;\n  info->color.bitdepth = in[24];\n  info->color.colortype = (LodePNGColorType)in[25];\n  info->compression_method = in[26];\n  info->filter_method = in[27];\n  info->interlace_method = in[28];\n\n  /*errors returned only after the parsing so other values are still output*/\n\n  /*error: invalid image size*/\n  if(width == 0 || height == 0) CERROR_RETURN_ERROR(state->error, 93);\n  /*error: invalid colortype or bitdepth combination*/\n  state->error = checkColorValidity(info->color.colortype, info->color.bitdepth);\n  if(state->error) return state->error;\n  /*error: only compression method 0 is allowed in the specification*/\n  if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32);\n  /*error: only filter method 0 is allowed in the specification*/\n  if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33);\n  /*error: only interlace methods 0 and 1 exist in the specification*/\n  if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34);\n\n  if(!state->decoder.ignore_crc) {\n    unsigned CRC = lodepng_read32bitInt(&in[29]);\n    unsigned checksum = lodepng_crc32(&in[12], 17);\n    if(CRC != checksum) {\n      CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/\n    }\n  }\n\n  return state->error;\n}\n\nstatic unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon,\n                                 size_t bytewidth, unsigned char filterType, size_t length) {\n  /*\n  For PNG filter method 0\n  unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte,\n  the filter works byte per byte (bytewidth = 1)\n  precon is the previous unfiltered scanline, recon the result, scanline the current one\n  the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead\n  recon and scanline MAY be the same memory address! precon must be disjoint.\n  */\n\n  size_t i;\n  switch(filterType) {\n    case 0:\n      for(i = 0; i != length; ++i) recon[i] = scanline[i];\n      break;\n    case 1:\n      for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];\n      for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth];\n      break;\n    case 2:\n      if(precon) {\n        for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i];\n      } else {\n        for(i = 0; i != length; ++i) recon[i] = scanline[i];\n      }\n      break;\n    case 3:\n      if(precon) {\n        for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u);\n        for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u);\n      } else {\n        for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i];\n        for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u);\n      }\n      break;\n    case 4:\n      if(precon) {\n        for(i = 0; i != bytewidth; ++i) {\n          recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/\n        }\n\n        /* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that\n        adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */\n        if(bytewidth >= 4) {\n          for(; i + 3 < length; i += 4) {\n            size_t j = i - bytewidth;\n            unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3];\n            unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3];\n            unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3];\n            unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2], q3 = precon[j + 3];\n            recon[i + 0] = s0 + paethPredictor(r0, p0, q0);\n            recon[i + 1] = s1 + paethPredictor(r1, p1, q1);\n            recon[i + 2] = s2 + paethPredictor(r2, p2, q2);\n            recon[i + 3] = s3 + paethPredictor(r3, p3, q3);\n          }\n        } else if(bytewidth >= 3) {\n          for(; i + 2 < length; i += 3) {\n            size_t j = i - bytewidth;\n            unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2];\n            unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2];\n            unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2];\n            unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2];\n            recon[i + 0] = s0 + paethPredictor(r0, p0, q0);\n            recon[i + 1] = s1 + paethPredictor(r1, p1, q1);\n            recon[i + 2] = s2 + paethPredictor(r2, p2, q2);\n          }\n        } else if(bytewidth >= 2) {\n          for(; i + 1 < length; i += 2) {\n            size_t j = i - bytewidth;\n            unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1];\n            unsigned char r0 = recon[j + 0], r1 = recon[j + 1];\n            unsigned char p0 = precon[i + 0], p1 = precon[i + 1];\n            unsigned char q0 = precon[j + 0], q1 = precon[j + 1];\n            recon[i + 0] = s0 + paethPredictor(r0, p0, q0);\n            recon[i + 1] = s1 + paethPredictor(r1, p1, q1);\n          }\n        }\n\n        for(; i != length; ++i) {\n          recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));\n        }\n      } else {\n        for(i = 0; i != bytewidth; ++i) {\n          recon[i] = scanline[i];\n        }\n        for(i = bytewidth; i < length; ++i) {\n          /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/\n          recon[i] = (scanline[i] + recon[i - bytewidth]);\n        }\n      }\n      break;\n    default: return 36; /*error: invalid filter type given*/\n  }\n  return 0;\n}\n\nstatic unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) {\n  /*\n  For PNG filter method 0\n  this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times)\n  out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline\n  w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel\n  in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes)\n  */\n\n  unsigned y;\n  unsigned char* prevline = 0;\n\n  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/\n  size_t bytewidth = (bpp + 7u) / 8u;\n  /*the width of a scanline in bytes, not including the filter type*/\n  size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u;\n\n  for(y = 0; y < h; ++y) {\n    size_t outindex = linebytes * y;\n    size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/\n    unsigned char filterType = in[inindex];\n\n    CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes));\n\n    prevline = &out[outindex];\n  }\n\n  return 0;\n}\n\n/*\nin: Adam7 interlaced image, with no padding bits between scanlines, but between\n reduced images so that each reduced image starts at a byte.\nout: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h\nbpp: bits per pixel\nout has the following size in bits: w * h * bpp.\nin is possibly bigger due to padding bits between reduced images.\nout must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation\n(because that's likely a little bit faster)\nNOTE: comments about padding bits are only relevant if bpp < 8\n*/\nstatic void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) {\n  unsigned passw[7], passh[7];\n  size_t filter_passstart[8], padded_passstart[8], passstart[8];\n  unsigned i;\n\n  Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);\n\n  if(bpp >= 8) {\n    for(i = 0; i != 7; ++i) {\n      unsigned x, y, b;\n      size_t bytewidth = bpp / 8u;\n      for(y = 0; y < passh[i]; ++y)\n      for(x = 0; x < passw[i]; ++x) {\n        size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;\n        size_t pixeloutstart = ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w\n                             + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bytewidth;\n        for(b = 0; b < bytewidth; ++b) {\n          out[pixeloutstart + b] = in[pixelinstart + b];\n        }\n      }\n    }\n  } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ {\n    for(i = 0; i != 7; ++i) {\n      unsigned x, y, b;\n      unsigned ilinebits = bpp * passw[i];\n      unsigned olinebits = bpp * w;\n      size_t obp, ibp; /*bit pointers (for out and in buffer)*/\n      for(y = 0; y < passh[i]; ++y)\n      for(x = 0; x < passw[i]; ++x) {\n        ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);\n        obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp;\n        for(b = 0; b < bpp; ++b) {\n          unsigned char bit = readBitFromReversedStream(&ibp, in);\n          setBitOfReversedStream(&obp, out, bit);\n        }\n      }\n    }\n  }\n}\n\nstatic void removePaddingBits(unsigned char* out, const unsigned char* in,\n                              size_t olinebits, size_t ilinebits, unsigned h) {\n  /*\n  After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need\n  to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers\n  for the Adam7 code, the color convert code and the output to the user.\n  in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must\n  have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits\n  also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7\n  only useful if (ilinebits - olinebits) is a value in the range 1..7\n  */\n  unsigned y;\n  size_t diff = ilinebits - olinebits;\n  size_t ibp = 0, obp = 0; /*input and output bit pointers*/\n  for(y = 0; y < h; ++y) {\n    size_t x;\n    for(x = 0; x < olinebits; ++x) {\n      unsigned char bit = readBitFromReversedStream(&ibp, in);\n      setBitOfReversedStream(&obp, out, bit);\n    }\n    ibp += diff;\n  }\n}\n\n/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from\nthe IDAT chunks (with filter index bytes and possible padding bits)\nreturn value is error*/\nstatic unsigned postProcessScanlines(unsigned char* out, unsigned char* in,\n                                     unsigned w, unsigned h, const LodePNGInfo* info_png) {\n  /*\n  This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype.\n  Steps:\n  *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8)\n  *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace\n  NOTE: the in buffer will be overwritten with intermediate data!\n  */\n  unsigned bpp = lodepng_get_bpp(&info_png->color);\n  if(bpp == 0) return 31; /*error: invalid colortype*/\n\n  if(info_png->interlace_method == 0) {\n    if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) {\n      CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));\n      removePaddingBits(out, in, w * bpp, ((w * bpp + 7u) / 8u) * 8u, h);\n    }\n    /*we can immediately filter into the out buffer, no other steps needed*/\n    else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));\n  } else /*interlace_method is 1 (Adam7)*/ {\n    unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];\n    unsigned i;\n\n    Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);\n\n    for(i = 0; i != 7; ++i) {\n      CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp));\n      /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline,\n      move bytes instead of bits or move not at all*/\n      if(bpp < 8) {\n        /*remove padding bits in scanlines; after this there still may be padding\n        bits between the different reduced images: each reduced image still starts nicely at a byte*/\n        removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp,\n                          ((passw[i] * bpp + 7u) / 8u) * 8u, passh[i]);\n      }\n    }\n\n    Adam7_deinterlace(out, in, w, h, bpp);\n  }\n\n  return 0;\n}\n\nstatic unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) {\n  unsigned pos = 0, i;\n  color->palettesize = chunkLength / 3u;\n  if(color->palettesize == 0 || color->palettesize > 256) return 38; /*error: palette too small or big*/\n  lodepng_color_mode_alloc_palette(color);\n  if(!color->palette && color->palettesize) {\n    color->palettesize = 0;\n    return 83; /*alloc fail*/\n  }\n\n  for(i = 0; i != color->palettesize; ++i) {\n    color->palette[4 * i + 0] = data[pos++]; /*R*/\n    color->palette[4 * i + 1] = data[pos++]; /*G*/\n    color->palette[4 * i + 2] = data[pos++]; /*B*/\n    color->palette[4 * i + 3] = 255; /*alpha*/\n  }\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) {\n  unsigned i;\n  if(color->colortype == LCT_PALETTE) {\n    /*error: more alpha values given than there are palette entries*/\n    if(chunkLength > color->palettesize) return 39;\n\n    for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i];\n  } else if(color->colortype == LCT_GREY) {\n    /*error: this chunk must be 2 bytes for grayscale image*/\n    if(chunkLength != 2) return 30;\n\n    color->key_defined = 1;\n    color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1];\n  } else if(color->colortype == LCT_RGB) {\n    /*error: this chunk must be 6 bytes for RGB image*/\n    if(chunkLength != 6) return 41;\n\n    color->key_defined = 1;\n    color->key_r = 256u * data[0] + data[1];\n    color->key_g = 256u * data[2] + data[3];\n    color->key_b = 256u * data[4] + data[5];\n  }\n  else return 42; /*error: tRNS chunk not allowed for other color models*/\n\n  return 0; /* OK */\n}\n\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n/*background color chunk (bKGD)*/\nstatic unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(info->color.colortype == LCT_PALETTE) {\n    /*error: this chunk must be 1 byte for indexed color image*/\n    if(chunkLength != 1) return 43;\n\n    /*error: invalid palette index, or maybe this chunk appeared before PLTE*/\n    if(data[0] >= info->color.palettesize) return 103;\n\n    info->background_defined = 1;\n    info->background_r = info->background_g = info->background_b = data[0];\n  } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) {\n    /*error: this chunk must be 2 bytes for grayscale image*/\n    if(chunkLength != 2) return 44;\n\n    /*the values are truncated to bitdepth in the PNG file*/\n    info->background_defined = 1;\n    info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1];\n  } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) {\n    /*error: this chunk must be 6 bytes for grayscale image*/\n    if(chunkLength != 6) return 45;\n\n    /*the values are truncated to bitdepth in the PNG file*/\n    info->background_defined = 1;\n    info->background_r = 256u * data[0] + data[1];\n    info->background_g = 256u * data[2] + data[3];\n    info->background_b = 256u * data[4] + data[5];\n  }\n\n  return 0; /* OK */\n}\n\n/*text chunk (tEXt)*/\nstatic unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  unsigned error = 0;\n  char *key = 0, *str = 0;\n\n  while(!error) /*not really a while loop, only used to break on error*/ {\n    unsigned length, string2_begin;\n\n    length = 0;\n    while(length < chunkLength && data[length] != 0) ++length;\n    /*even though it's not allowed by the standard, no error is thrown if\n    there's no null termination char, if the text is empty*/\n    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/\n\n    key = (char*)lodepng_malloc(length + 1);\n    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(key, data, length);\n    key[length] = 0;\n\n    string2_begin = length + 1; /*skip keyword null terminator*/\n\n    length = (unsigned)(chunkLength < string2_begin ? 0 : chunkLength - string2_begin);\n    str = (char*)lodepng_malloc(length + 1);\n    if(!str) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(str, data + string2_begin, length);\n    str[length] = 0;\n\n    error = lodepng_add_text(info, key, str);\n\n    break;\n  }\n\n  lodepng_free(key);\n  lodepng_free(str);\n\n  return error;\n}\n\n/*compressed text chunk (zTXt)*/\nstatic unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,\n                               const unsigned char* data, size_t chunkLength) {\n  unsigned error = 0;\n\n  unsigned length, string2_begin;\n  char *key = 0;\n  unsigned char* str = 0;\n  size_t size = 0;\n\n  while(!error) /*not really a while loop, only used to break on error*/ {\n    for(length = 0; length < chunkLength && data[length] != 0; ++length) ;\n    if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/\n    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/\n\n    key = (char*)lodepng_malloc(length + 1);\n    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(key, data, length);\n    key[length] = 0;\n\n    if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/\n\n    string2_begin = length + 2;\n    if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/\n\n    length = (unsigned)chunkLength - string2_begin;\n    /*will fail if zlib error, e.g. if length is too small*/\n    error = zlib_decompress(&str, &size, 0, &data[string2_begin],\n                            length, zlibsettings);\n    if(error) break;\n    error = lodepng_add_text_sized(info, key, (char*)str, size);\n\n    break;\n  }\n\n  lodepng_free(key);\n  lodepng_free(str);\n\n  return error;\n}\n\n/*international text chunk (iTXt)*/\nstatic unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,\n                               const unsigned char* data, size_t chunkLength) {\n  unsigned error = 0;\n  unsigned i;\n\n  unsigned length, begin, compressed;\n  char *key = 0, *langtag = 0, *transkey = 0;\n\n  while(!error) /*not really a while loop, only used to break on error*/ {\n    /*Quick check if the chunk length isn't too small. Even without check\n    it'd still fail with other error checks below if it's too short. This just gives a different error code.*/\n    if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/\n\n    /*read the key*/\n    for(length = 0; length < chunkLength && data[length] != 0; ++length) ;\n    if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/\n    if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/\n\n    key = (char*)lodepng_malloc(length + 1);\n    if(!key) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(key, data, length);\n    key[length] = 0;\n\n    /*read the compression method*/\n    compressed = data[length + 1];\n    if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/\n\n    /*even though it's not allowed by the standard, no error is thrown if\n    there's no null termination char, if the text is empty for the next 3 texts*/\n\n    /*read the langtag*/\n    begin = length + 3;\n    length = 0;\n    for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;\n\n    langtag = (char*)lodepng_malloc(length + 1);\n    if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(langtag, data + begin, length);\n    langtag[length] = 0;\n\n    /*read the transkey*/\n    begin += length + 1;\n    length = 0;\n    for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;\n\n    transkey = (char*)lodepng_malloc(length + 1);\n    if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/\n\n    lodepng_memcpy(transkey, data + begin, length);\n    transkey[length] = 0;\n\n    /*read the actual text*/\n    begin += length + 1;\n\n    length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin;\n\n    if(compressed) {\n      unsigned char* str = 0;\n      size_t size = 0;\n      /*will fail if zlib error, e.g. if length is too small*/\n      error = zlib_decompress(&str, &size, 0, &data[begin],\n                              length, zlibsettings);\n      if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size);\n      lodepng_free(str);\n    } else {\n      error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)(data + begin), length);\n    }\n\n    break;\n  }\n\n  lodepng_free(key);\n  lodepng_free(langtag);\n  lodepng_free(transkey);\n\n  return error;\n}\n\nstatic unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(chunkLength != 7) return 73; /*invalid tIME chunk size*/\n\n  info->time_defined = 1;\n  info->time.year = 256u * data[0] + data[1];\n  info->time.month = data[2];\n  info->time.day = data[3];\n  info->time.hour = data[4];\n  info->time.minute = data[5];\n  info->time.second = data[6];\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/\n\n  info->phys_defined = 1;\n  info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3];\n  info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7];\n  info->phys_unit = data[8];\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_gAMA(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(chunkLength != 4) return 96; /*invalid gAMA chunk size*/\n\n  info->gama_defined = 1;\n  info->gama_gamma = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3];\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_cHRM(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(chunkLength != 32) return 97; /*invalid cHRM chunk size*/\n\n  info->chrm_defined = 1;\n  info->chrm_white_x = 16777216u * data[ 0] + 65536u * data[ 1] + 256u * data[ 2] + data[ 3];\n  info->chrm_white_y = 16777216u * data[ 4] + 65536u * data[ 5] + 256u * data[ 6] + data[ 7];\n  info->chrm_red_x   = 16777216u * data[ 8] + 65536u * data[ 9] + 256u * data[10] + data[11];\n  info->chrm_red_y   = 16777216u * data[12] + 65536u * data[13] + 256u * data[14] + data[15];\n  info->chrm_green_x = 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19];\n  info->chrm_green_y = 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23];\n  info->chrm_blue_x  = 16777216u * data[24] + 65536u * data[25] + 256u * data[26] + data[27];\n  info->chrm_blue_y  = 16777216u * data[28] + 65536u * data[29] + 256u * data[30] + data[31];\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {\n  if(chunkLength != 1) return 98; /*invalid sRGB chunk size (this one is never ignored)*/\n\n  info->srgb_defined = 1;\n  info->srgb_intent = data[0];\n\n  return 0; /* OK */\n}\n\nstatic unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,\n                               const unsigned char* data, size_t chunkLength) {\n  unsigned error = 0;\n  unsigned i;\n  size_t size = 0;\n\n  unsigned length, string2_begin;\n\n  info->iccp_defined = 1;\n  if(info->iccp_name) lodepng_clear_icc(info);\n\n  for(length = 0; length < chunkLength && data[length] != 0; ++length) ;\n  if(length + 2 >= chunkLength) return 75; /*no null termination, corrupt?*/\n  if(length < 1 || length > 79) return 89; /*keyword too short or long*/\n\n  info->iccp_name = (char*)lodepng_malloc(length + 1);\n  if(!info->iccp_name) return 83; /*alloc fail*/\n\n  info->iccp_name[length] = 0;\n  for(i = 0; i != length; ++i) info->iccp_name[i] = (char)data[i];\n\n  if(data[length + 1] != 0) return 72; /*the 0 byte indicating compression must be 0*/\n\n  string2_begin = length + 2;\n  if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/\n\n  length = (unsigned)chunkLength - string2_begin;\n  error = zlib_decompress(&info->iccp_profile, &size, 0,\n                          &data[string2_begin],\n                          length, zlibsettings);\n  info->iccp_profile_size = size;\n  if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/\n  return error;\n}\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\nunsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,\n                               const unsigned char* in, size_t insize) {\n  const unsigned char* chunk = in + pos;\n  unsigned chunkLength;\n  const unsigned char* data;\n  unsigned unhandled = 0;\n  unsigned error = 0;\n\n  if(pos + 4 > insize) return 30;\n  chunkLength = lodepng_chunk_length(chunk);\n  if(chunkLength > 2147483647) return 63;\n  data = lodepng_chunk_data_const(chunk);\n  if(data + chunkLength + 4 > in + insize) return 30;\n\n  if(lodepng_chunk_type_equals(chunk, \"PLTE\")) {\n    error = readChunk_PLTE(&state->info_png.color, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"tRNS\")) {\n    error = readChunk_tRNS(&state->info_png.color, data, chunkLength);\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  } else if(lodepng_chunk_type_equals(chunk, \"bKGD\")) {\n    error = readChunk_bKGD(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"tEXt\")) {\n    error = readChunk_tEXt(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"zTXt\")) {\n    error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"iTXt\")) {\n    error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"tIME\")) {\n    error = readChunk_tIME(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"pHYs\")) {\n    error = readChunk_pHYs(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"gAMA\")) {\n    error = readChunk_gAMA(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"cHRM\")) {\n    error = readChunk_cHRM(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"sRGB\")) {\n    error = readChunk_sRGB(&state->info_png, data, chunkLength);\n  } else if(lodepng_chunk_type_equals(chunk, \"iCCP\")) {\n    error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n  } else {\n    /* unhandled chunk is ok (is not an error) */\n    unhandled = 1;\n  }\n\n  if(!error && !unhandled && !state->decoder.ignore_crc) {\n    if(lodepng_chunk_check_crc(chunk)) return 57; /*invalid CRC*/\n  }\n\n  return error;\n}\n\n/*read a PNG, the result will be in the same color type as the PNG (hence \"generic\")*/\nstatic void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,\n                          LodePNGState* state,\n                          const unsigned char* in, size_t insize) {\n  unsigned char IEND = 0;\n  const unsigned char* chunk;\n  unsigned char* idat; /*the data from idat chunks, zlib compressed*/\n  size_t idatsize = 0;\n  unsigned char* scanlines = 0;\n  size_t scanlines_size = 0, expected_size = 0;\n  size_t outsize = 0;\n\n  /*for unknown chunk order*/\n  unsigned unknown = 0;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\n\n  /* safe output values in case error happens */\n  *out = 0;\n  *w = *h = 0;\n\n  state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/\n  if(state->error) return;\n\n  if(lodepng_pixel_overflow(*w, *h, &state->info_png.color, &state->info_raw)) {\n    CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/\n  }\n\n  /*the input filesize is a safe upper bound for the sum of idat chunks size*/\n  idat = (unsigned char*)lodepng_malloc(insize);\n  if(!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/\n\n  chunk = &in[33]; /*first byte of the first chunk after the header*/\n\n  /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.\n  IDAT data is put at the start of the in buffer*/\n  while(!IEND && !state->error) {\n    unsigned chunkLength;\n    const unsigned char* data; /*the data in the chunk*/\n\n    /*error: size of the in buffer too small to contain next chunk*/\n    if((size_t)((chunk - in) + 12) > insize || chunk < in) {\n      if(state->decoder.ignore_end) break; /*other errors may still happen though*/\n      CERROR_BREAK(state->error, 30);\n    }\n\n    /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/\n    chunkLength = lodepng_chunk_length(chunk);\n    /*error: chunk length larger than the max PNG chunk size*/\n    if(chunkLength > 2147483647) {\n      if(state->decoder.ignore_end) break; /*other errors may still happen though*/\n      CERROR_BREAK(state->error, 63);\n    }\n\n    if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) {\n      CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/\n    }\n\n    data = lodepng_chunk_data_const(chunk);\n\n    unknown = 0;\n\n    /*IDAT chunk, containing compressed image data*/\n    if(lodepng_chunk_type_equals(chunk, \"IDAT\")) {\n      size_t newsize;\n      if(lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95);\n      if(newsize > insize) CERROR_BREAK(state->error, 95);\n      lodepng_memcpy(idat + idatsize, data, chunkLength);\n      idatsize += chunkLength;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n      critical_pos = 3;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    } else if(lodepng_chunk_type_equals(chunk, \"IEND\")) {\n      /*IEND chunk*/\n      IEND = 1;\n    } else if(lodepng_chunk_type_equals(chunk, \"PLTE\")) {\n      /*palette chunk (PLTE)*/\n      state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength);\n      if(state->error) break;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n      critical_pos = 2;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    } else if(lodepng_chunk_type_equals(chunk, \"tRNS\")) {\n      /*palette transparency chunk (tRNS). Even though this one is an ancillary chunk , it is still compiled\n      in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' because it contains essential color information that\n      affects the alpha channel of pixels. */\n      state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength);\n      if(state->error) break;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n      /*background color chunk (bKGD)*/\n    } else if(lodepng_chunk_type_equals(chunk, \"bKGD\")) {\n      state->error = readChunk_bKGD(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"tEXt\")) {\n      /*text chunk (tEXt)*/\n      if(state->decoder.read_text_chunks) {\n        state->error = readChunk_tEXt(&state->info_png, data, chunkLength);\n        if(state->error) break;\n      }\n    } else if(lodepng_chunk_type_equals(chunk, \"zTXt\")) {\n      /*compressed text chunk (zTXt)*/\n      if(state->decoder.read_text_chunks) {\n        state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n        if(state->error) break;\n      }\n    } else if(lodepng_chunk_type_equals(chunk, \"iTXt\")) {\n      /*international text chunk (iTXt)*/\n      if(state->decoder.read_text_chunks) {\n        state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n        if(state->error) break;\n      }\n    } else if(lodepng_chunk_type_equals(chunk, \"tIME\")) {\n      state->error = readChunk_tIME(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"pHYs\")) {\n      state->error = readChunk_pHYs(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"gAMA\")) {\n      state->error = readChunk_gAMA(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"cHRM\")) {\n      state->error = readChunk_cHRM(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"sRGB\")) {\n      state->error = readChunk_sRGB(&state->info_png, data, chunkLength);\n      if(state->error) break;\n    } else if(lodepng_chunk_type_equals(chunk, \"iCCP\")) {\n      state->error = readChunk_iCCP(&state->info_png, &state->decoder.zlibsettings, data, chunkLength);\n      if(state->error) break;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ {\n      /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/\n      if(!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) {\n        CERROR_BREAK(state->error, 69);\n      }\n\n      unknown = 1;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n      if(state->decoder.remember_unknown_chunks) {\n        state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1],\n                                            &state->info_png.unknown_chunks_size[critical_pos - 1], chunk);\n        if(state->error) break;\n      }\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    }\n\n    if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ {\n      if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/\n    }\n\n    if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize);\n  }\n\n  if(state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) {\n    state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */\n  }\n\n  if(!state->error) {\n    /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation.\n    If the decompressed size does not match the prediction, the image must be corrupt.*/\n    if(state->info_png.interlace_method == 0) {\n      size_t bpp = lodepng_get_bpp(&state->info_png.color);\n      expected_size = lodepng_get_raw_size_idat(*w, *h, bpp);\n    } else {\n      size_t bpp = lodepng_get_bpp(&state->info_png.color);\n      /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/\n      expected_size = 0;\n      expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp);\n      if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp);\n      expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp);\n      if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp);\n      expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp);\n      if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp);\n      expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp);\n    }\n\n    state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings);\n  }\n  if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/\n  lodepng_free(idat);\n\n  if(!state->error) {\n    outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color);\n    *out = (unsigned char*)lodepng_malloc(outsize);\n    if(!*out) state->error = 83; /*alloc fail*/\n  }\n  if(!state->error) {\n    lodepng_memset(*out, 0, outsize);\n    state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png);\n  }\n  lodepng_free(scanlines);\n}\n\nunsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,\n                        LodePNGState* state,\n                        const unsigned char* in, size_t insize) {\n  *out = 0;\n  decodeGeneric(out, w, h, state, in, insize);\n  if(state->error) return state->error;\n  if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) {\n    /*same color type, no copying or converting of data needed*/\n    /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype\n    the raw image has to the end user*/\n    if(!state->decoder.color_convert) {\n      state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color);\n      if(state->error) return state->error;\n    }\n  } else { /*color conversion needed*/\n    unsigned char* data = *out;\n    size_t outsize;\n\n    /*TODO: check if this works according to the statement in the documentation: \"The converter can convert\n    from grayscale input color type, to 8-bit grayscale or grayscale with alpha\"*/\n    if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA)\n       && !(state->info_raw.bitdepth == 8)) {\n      return 56; /*unsupported color mode conversion*/\n    }\n\t/* BCH 11 Oct. 2020: check for conversion from color to grayscale, and refuse to do it */\n\t/* the documentation implies that this should happen, but error 62 is not thrown anywhere in the code */\n\tif ((state->info_raw.colortype == LCT_GREY || state->info_raw.colortype == LCT_GREY_ALPHA)\n\t\t&& (state->info_png.color.colortype == LCT_RGB || state->info_png.color.colortype == LCT_RGBA)) {\n\t\treturn 62; /*conversion from color to grayscale not supported*/\n\t}\n\n    outsize = lodepng_get_raw_size(*w, *h, &state->info_raw);\n    *out = (unsigned char*)lodepng_malloc(outsize);\n    if(!(*out)) {\n      state->error = 83; /*alloc fail*/\n    }\n    else state->error = lodepng_convert(*out, data, &state->info_raw,\n                                        &state->info_png.color, *w, *h);\n    lodepng_free(data);\n  }\n  return state->error;\n}\n\nunsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in,\n                               size_t insize, LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned error;\n  LodePNGState state;\n  lodepng_state_init(&state);\n  state.info_raw.colortype = colortype;\n  state.info_raw.bitdepth = bitdepth;\n  error = lodepng_decode(out, w, h, &state, in, insize);\n  lodepng_state_cleanup(&state);\n  return error;\n}\n\nunsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) {\n  return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8);\n}\n\nunsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) {\n  return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8);\n}\n\n#ifdef LODEPNG_COMPILE_DISK\nunsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename,\n                             LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned char* buffer = 0;\n  size_t buffersize;\n  unsigned error;\n  /* safe output values in case error happens */\n  *out = 0;\n  *w = *h = 0;\n  error = lodepng_load_file(&buffer, &buffersize, filename);\n  if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth);\n  lodepng_free(buffer);\n  return error;\n}\n\nunsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) {\n  return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8);\n}\n\nunsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) {\n  return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8);\n}\n#endif /*LODEPNG_COMPILE_DISK*/\n\nvoid lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) {\n  settings->color_convert = 1;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  settings->read_text_chunks = 1;\n  settings->remember_unknown_chunks = 0;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n  settings->ignore_crc = 0;\n  settings->ignore_critical = 0;\n  settings->ignore_end = 0;\n  lodepng_decompress_settings_init(&settings->zlibsettings);\n}\n\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)\n\nvoid lodepng_state_init(LodePNGState* state) {\n#ifdef LODEPNG_COMPILE_DECODER\n  lodepng_decoder_settings_init(&state->decoder);\n#endif /*LODEPNG_COMPILE_DECODER*/\n#ifdef LODEPNG_COMPILE_ENCODER\n  lodepng_encoder_settings_init(&state->encoder);\n#endif /*LODEPNG_COMPILE_ENCODER*/\n  lodepng_color_mode_init(&state->info_raw);\n  lodepng_info_init(&state->info_png);\n  state->error = 1;\n}\n\nvoid lodepng_state_cleanup(LodePNGState* state) {\n  lodepng_color_mode_cleanup(&state->info_raw);\n  lodepng_info_cleanup(&state->info_png);\n}\n\nvoid lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) {\n  lodepng_state_cleanup(dest);\n  *dest = *source;\n  lodepng_color_mode_init(&dest->info_raw);\n  lodepng_info_init(&dest->info_png);\n  dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return;\n  dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return;\n}\n\n#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */\n\n#ifdef LODEPNG_COMPILE_ENCODER\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* / PNG Encoder                                                            / */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n\nstatic unsigned writeSignature(ucvector* out) {\n  size_t pos = out->size;\n  const unsigned char signature[] = {137, 80, 78, 71, 13, 10, 26, 10};\n  /*8 bytes PNG signature, aka the magic bytes*/\n  if(!ucvector_resize(out, out->size + 8)) return 83; /*alloc fail*/\n  lodepng_memcpy(out->data + pos, signature, 8);\n  return 0;\n}\n\nstatic unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h,\n                              LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) {\n  unsigned char *chunk, *data;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, \"IHDR\"));\n  data = chunk + 8;\n\n  lodepng_set32bitInt(data + 0, w); /*width*/\n  lodepng_set32bitInt(data + 4, h); /*height*/\n  data[8] = (unsigned char)bitdepth; /*bit depth*/\n  data[9] = (unsigned char)colortype; /*color type*/\n  data[10] = 0; /*compression method*/\n  data[11] = 0; /*filter method*/\n  data[12] = interlace_method; /*interlace method*/\n\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\n/* only adds the chunk if needed (there is a key or palette with alpha) */\nstatic unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) {\n  unsigned char* chunk;\n  size_t i, j = 8;\n\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, \"PLTE\"));\n\n  for(i = 0; i != info->palettesize; ++i) {\n    /*add all channels except alpha channel*/\n    chunk[j++] = info->palette[i * 4 + 0];\n    chunk[j++] = info->palette[i * 4 + 1];\n    chunk[j++] = info->palette[i * 4 + 2];\n  }\n\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) {\n  unsigned char* chunk = 0;\n\n  if(info->colortype == LCT_PALETTE) {\n    size_t i, amount = info->palettesize;\n    /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/\n    for(i = info->palettesize; i != 0; --i) {\n      if(info->palette[4 * (i - 1) + 3] != 255) break;\n      --amount;\n    }\n    if(amount) {\n      CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, \"tRNS\"));\n      /*add the alpha channel values from the palette*/\n      for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3];\n    }\n  } else if(info->colortype == LCT_GREY) {\n    if(info->key_defined) {\n      CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, \"tRNS\"));\n      chunk[8] = (unsigned char)(info->key_r >> 8);\n      chunk[9] = (unsigned char)(info->key_r & 255);\n    }\n  } else if(info->colortype == LCT_RGB) {\n    if(info->key_defined) {\n      CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, \"tRNS\"));\n      chunk[8] = (unsigned char)(info->key_r >> 8);\n      chunk[9] = (unsigned char)(info->key_r & 255);\n      chunk[10] = (unsigned char)(info->key_g >> 8);\n      chunk[11] = (unsigned char)(info->key_g & 255);\n      chunk[12] = (unsigned char)(info->key_b >> 8);\n      chunk[13] = (unsigned char)(info->key_b & 255);\n    }\n  }\n\n  if(chunk) lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize,\n                              LodePNGCompressSettings* zlibsettings) {\n  unsigned error = 0;\n  unsigned char* zlib = 0;\n  size_t zlibsize = 0;\n\n  error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings);\n  if(!error) {\n    error = lodepng_chunk_createv(out, zlibsize, \"IDAT\", zlib);\n  }\n  lodepng_free(zlib);\n  return error;\n}\n\nstatic unsigned addChunk_IEND(ucvector* out) {\n  return lodepng_chunk_createv(out, 0, \"IEND\", 0);\n}\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n\nstatic unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) {\n  unsigned char* chunk = 0;\n  size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring);\n  size_t size = keysize + 1 + textsize;\n  if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, \"tEXt\"));\n  lodepng_memcpy(chunk + 8, keyword, keysize);\n  chunk[8 + keysize] = 0; /*null termination char*/\n  lodepng_memcpy(chunk + 9 + keysize, textstring, textsize);\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring,\n                              LodePNGCompressSettings* zlibsettings) {\n  unsigned error = 0;\n  unsigned char* chunk = 0;\n  unsigned char* compressed = 0;\n  size_t compressedsize = 0;\n  size_t textsize = lodepng_strlen(textstring);\n  size_t keysize = lodepng_strlen(keyword);\n  if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/\n\n  error = zlib_compress(&compressed, &compressedsize,\n                        (const unsigned char*)textstring, textsize, zlibsettings);\n  if(!error) {\n    size_t size = keysize + 2 + compressedsize;\n    error = lodepng_chunk_init(&chunk, out, size, \"zTXt\");\n  }\n  if(!error) {\n    lodepng_memcpy(chunk + 8, keyword, keysize);\n    chunk[8 + keysize] = 0; /*null termination char*/\n    chunk[9 + keysize] = 0; /*compression method: 0*/\n    lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize);\n    lodepng_chunk_generate_crc(chunk);\n  }\n\n  lodepng_free(compressed);\n  return error;\n}\n\nstatic unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag,\n                              const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) {\n  unsigned error = 0;\n  unsigned char* chunk = 0;\n  unsigned char* compressed = 0;\n  size_t compressedsize = 0;\n  size_t textsize = lodepng_strlen(textstring);\n  size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey);\n\n  if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/\n\n  if(compress) {\n    error = zlib_compress(&compressed, &compressedsize,\n                          (const unsigned char*)textstring, textsize, zlibsettings);\n  }\n  if(!error) {\n    size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize);\n    error = lodepng_chunk_init(&chunk, out, size, \"iTXt\");\n  }\n  if(!error) {\n    size_t pos = 8;\n    lodepng_memcpy(chunk + pos, keyword, keysize);\n    pos += keysize;\n    chunk[pos++] = 0; /*null termination char*/\n    chunk[pos++] = (compress ? 1 : 0); /*compression flag*/\n    chunk[pos++] = 0; /*compression method: 0*/\n    lodepng_memcpy(chunk + pos, langtag, langsize);\n    pos += langsize;\n    chunk[pos++] = 0; /*null termination char*/\n    lodepng_memcpy(chunk + pos, transkey, transsize);\n    pos += transsize;\n    chunk[pos++] = 0; /*null termination char*/\n    if(compress) {\n      lodepng_memcpy(chunk + pos, compressed, compressedsize);\n    } else {\n      lodepng_memcpy(chunk + pos, textstring, textsize);\n    }\n    lodepng_chunk_generate_crc(chunk);\n  }\n\n  lodepng_free(compressed);\n  return error;\n}\n\nstatic unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) {\n  unsigned char* chunk = 0;\n  if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) {\n    CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, \"bKGD\"));\n    chunk[8] = (unsigned char)(info->background_r >> 8);\n    chunk[9] = (unsigned char)(info->background_r & 255);\n  } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) {\n    CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, \"bKGD\"));\n    chunk[8] = (unsigned char)(info->background_r >> 8);\n    chunk[9] = (unsigned char)(info->background_r & 255);\n    chunk[10] = (unsigned char)(info->background_g >> 8);\n    chunk[11] = (unsigned char)(info->background_g & 255);\n    chunk[12] = (unsigned char)(info->background_b >> 8);\n    chunk[13] = (unsigned char)(info->background_b & 255);\n  } else if(info->color.colortype == LCT_PALETTE) {\n    CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, \"bKGD\"));\n    chunk[8] = (unsigned char)(info->background_r & 255); /*palette index*/\n  }\n  if(chunk) lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) {\n  unsigned char* chunk;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 7, \"tIME\"));\n  chunk[8] = (unsigned char)(time->year >> 8);\n  chunk[9] = (unsigned char)(time->year & 255);\n  chunk[10] = (unsigned char)time->month;\n  chunk[11] = (unsigned char)time->day;\n  chunk[12] = (unsigned char)time->hour;\n  chunk[13] = (unsigned char)time->minute;\n  chunk[14] = (unsigned char)time->second;\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) {\n  unsigned char* chunk;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 9, \"pHYs\"));\n  lodepng_set32bitInt(chunk + 8, info->phys_x);\n  lodepng_set32bitInt(chunk + 12, info->phys_y);\n  chunk[16] = info->phys_unit;\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_gAMA(ucvector* out, const LodePNGInfo* info) {\n  unsigned char* chunk;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, \"gAMA\"));\n  lodepng_set32bitInt(chunk + 8, info->gama_gamma);\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) {\n  unsigned char* chunk;\n  CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 32, \"cHRM\"));\n  lodepng_set32bitInt(chunk + 8, info->chrm_white_x);\n  lodepng_set32bitInt(chunk + 12, info->chrm_white_y);\n  lodepng_set32bitInt(chunk + 16, info->chrm_red_x);\n  lodepng_set32bitInt(chunk + 20, info->chrm_red_y);\n  lodepng_set32bitInt(chunk + 24, info->chrm_green_x);\n  lodepng_set32bitInt(chunk + 28, info->chrm_green_y);\n  lodepng_set32bitInt(chunk + 32, info->chrm_blue_x);\n  lodepng_set32bitInt(chunk + 36, info->chrm_blue_y);\n  lodepng_chunk_generate_crc(chunk);\n  return 0;\n}\n\nstatic unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) {\n  unsigned char data = info->srgb_intent;\n  return lodepng_chunk_createv(out, 1, \"sRGB\", &data);\n}\n\nstatic unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCompressSettings* zlibsettings) {\n  unsigned error = 0;\n  unsigned char* chunk = 0;\n  unsigned char* compressed = 0;\n  size_t compressedsize = 0;\n  size_t keysize = lodepng_strlen(info->iccp_name);\n\n  if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/\n  error = zlib_compress(&compressed, &compressedsize,\n                        info->iccp_profile, info->iccp_profile_size, zlibsettings);\n  if(!error) {\n    size_t size = keysize + 2 + compressedsize;\n    error = lodepng_chunk_init(&chunk, out, size, \"iCCP\");\n  }\n  if(!error) {\n    lodepng_memcpy(chunk + 8, info->iccp_name, keysize);\n    chunk[8 + keysize] = 0; /*null termination char*/\n    chunk[9 + keysize] = 0; /*compression method: 0*/\n    lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize);\n    lodepng_chunk_generate_crc(chunk);\n  }\n\n  lodepng_free(compressed);\n  return error;\n}\n\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\nstatic void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,\n                           size_t length, size_t bytewidth, unsigned char filterType) {\n  size_t i;\n  switch(filterType) {\n    case 0: /*None*/\n      for(i = 0; i != length; ++i) out[i] = scanline[i];\n      break;\n    case 1: /*Sub*/\n      for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];\n      for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth];\n      break;\n    case 2: /*Up*/\n      if(prevline) {\n        for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i];\n      } else {\n        for(i = 0; i != length; ++i) out[i] = scanline[i];\n      }\n      break;\n    case 3: /*Average*/\n      if(prevline) {\n        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1);\n        for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1);\n      } else {\n        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];\n        for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1);\n      }\n      break;\n    case 4: /*Paeth*/\n      if(prevline) {\n        /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/\n        for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]);\n        for(i = bytewidth; i < length; ++i) {\n          out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth]));\n        }\n      } else {\n        for(i = 0; i != bytewidth; ++i) out[i] = scanline[i];\n        /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/\n        for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]);\n      }\n      break;\n    default: return; /*invalid filter type given*/\n  }\n}\n\n/* integer binary logarithm, max return value is 31 */\nstatic size_t ilog2(size_t i) {\n  size_t result = 0;\n  if(i >= 65536) { result += 16; i >>= 16; }\n  if(i >= 256) { result += 8; i >>= 8; }\n  if(i >= 16) { result += 4; i >>= 4; }\n  if(i >= 4) { result += 2; i >>= 2; }\n  if(i >= 2) { result += 1; /*i >>= 1;*/ }\n  return result;\n}\n\n/* integer approximation for i * log2(i), helper function for LFS_ENTROPY */\nstatic size_t ilog2i(size_t i) {\n  size_t l;\n  if(i == 0) return 0;\n  l = ilog2(i);\n  /* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u)\n  linearly approximates the missing fractional part multiplied by i */\n  return i * l + ((i - (1u << l)) << 1u);\n}\n\nstatic unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,\n                       const LodePNGColorMode* color, const LodePNGEncoderSettings* settings) {\n  /*\n  For PNG filter method 0\n  out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are\n  the scanlines with 1 extra byte per scanline\n  */\n\n  unsigned bpp = lodepng_get_bpp(color);\n  /*the width of a scanline in bytes, not including the filter type*/\n  size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u;\n\n  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/\n  size_t bytewidth = (bpp + 7u) / 8u;\n  const unsigned char* prevline = 0;\n  unsigned x, y;\n  unsigned error = 0;\n  LodePNGFilterStrategy strategy = settings->filter_strategy;\n\n  /*\n  There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:\n   *  If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.\n      use fixed filtering, with the filter None).\n   * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is\n     not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply\n     all five filters and select the filter that produces the smallest sum of absolute values per row.\n  This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true.\n\n  If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,\n  but for \"the other case\", whatever strategy filter_strategy is set to instead of the minimum sum\n  heuristic is used.\n  */\n  if(settings->filter_palette_zero &&\n     (color->colortype == LCT_PALETTE || color->bitdepth < 8)) strategy = LFS_ZERO;\n\n  if(bpp == 0) return 31; /*error: invalid color type*/\n\n  if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) {\n    unsigned char type = (unsigned char)strategy;\n    for(y = 0; y != h; ++y) {\n      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/\n      size_t inindex = linebytes * y;\n      out[outindex] = type; /*filter type byte*/\n      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);\n      prevline = &in[inindex];\n    }\n  } else if(strategy == LFS_MINSUM) {\n    /*adaptive filtering*/\n    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/\n    size_t smallest = 0;\n    unsigned char type, bestType = 0;\n\n    for(type = 0; type != 5; ++type) {\n      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);\n      if(!attempt[type]) error = 83; /*alloc fail*/\n    }\n\n    if(!error) {\n      for(y = 0; y != h; ++y) {\n        /*try the 5 filter types*/\n        for(type = 0; type != 5; ++type) {\n          size_t sum = 0;\n          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);\n\n          /*calculate the sum of the result*/\n          if(type == 0) {\n            for(x = 0; x != linebytes; ++x) sum += (unsigned char)(attempt[type][x]);\n          } else {\n            for(x = 0; x != linebytes; ++x) {\n              /*For differences, each byte should be treated as signed, values above 127 are negative\n              (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.\n              This means filtertype 0 is almost never chosen, but that is justified.*/\n              unsigned char s = attempt[type][x];\n              sum += s < 128 ? s : (255U - s);\n            }\n          }\n\n          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/\n          if(type == 0 || sum < smallest) {\n            bestType = type;\n            smallest = sum;\n          }\n        }\n\n        prevline = &in[y * linebytes];\n\n        /*now fill the out values*/\n        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/\n        for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];\n      }\n    }\n\n    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);\n  } else if(strategy == LFS_ENTROPY) {\n    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/\n    size_t bestSum = 0;\n    unsigned type, bestType = 0;\n    unsigned count[256];\n\n    for(type = 0; type != 5; ++type) {\n      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);\n      if(!attempt[type]) error = 83; /*alloc fail*/\n    }\n\n    if(!error) {\n      for(y = 0; y != h; ++y) {\n        /*try the 5 filter types*/\n        for(type = 0; type != 5; ++type) {\n          size_t sum = 0;\n          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);\n          lodepng_memset(count, 0, 256 * sizeof(*count));\n          for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];\n          ++count[type]; /*the filter type itself is part of the scanline*/\n          for(x = 0; x != 256; ++x) {\n            sum += ilog2i(count[x]);\n          }\n          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/\n          if(type == 0 || sum > bestSum) {\n            bestType = type;\n            bestSum = sum;\n          }\n        }\n\n        prevline = &in[y * linebytes];\n\n        /*now fill the out values*/\n        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/\n        for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];\n      }\n    }\n\n    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);\n  } else if(strategy == LFS_PREDEFINED) {\n    for(y = 0; y != h; ++y) {\n      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/\n      size_t inindex = linebytes * y;\n      unsigned char type = settings->predefined_filters[y];\n      out[outindex] = type; /*filter type byte*/\n      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);\n      prevline = &in[inindex];\n    }\n  } else if(strategy == LFS_BRUTE_FORCE) {\n    /*brute force filter chooser.\n    deflate the scanline after every filter attempt to see which one deflates best.\n    This is very slow and gives only slightly smaller, sometimes even larger, result*/\n    size_t size[5];\n    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/\n    size_t smallest = 0;\n    unsigned type = 0, bestType = 0;\n    unsigned char* dummy;\n    LodePNGCompressSettings zlibsettings;\n    lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings));\n    /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,\n    to simulate the true case where the tree is the same for the whole image. Sometimes it gives\n    better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare\n    cases better compression. It does make this a bit less slow, so it's worth doing this.*/\n    zlibsettings.btype = 1;\n    /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG\n    images only, so disable it*/\n    zlibsettings.custom_zlib = 0;\n    zlibsettings.custom_deflate = 0;\n    for(type = 0; type != 5; ++type) {\n      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);\n      if(!attempt[type]) error = 83; /*alloc fail*/\n    }\n    if(!error) {\n      for(y = 0; y != h; ++y) /*try the 5 filter types*/ {\n        for(type = 0; type != 5; ++type) {\n          unsigned testsize = (unsigned)linebytes;\n          /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/\n\n          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);\n          size[type] = 0;\n          dummy = 0;\n          zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings);\n          lodepng_free(dummy);\n          /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/\n          if(type == 0 || size[type] < smallest) {\n            bestType = type;\n            smallest = size[type];\n          }\n        }\n        prevline = &in[y * linebytes];\n        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/\n        for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];\n      }\n    }\n    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);\n  }\n  else return 88; /* unknown filter strategy */\n\n  return error;\n}\n\nstatic void addPaddingBits(unsigned char* out, const unsigned char* in,\n                           size_t olinebits, size_t ilinebits, unsigned h) {\n  /*The opposite of the removePaddingBits function\n  olinebits must be >= ilinebits*/\n  unsigned y;\n  size_t diff = olinebits - ilinebits;\n  size_t obp = 0, ibp = 0; /*bit pointers*/\n  for(y = 0; y != h; ++y) {\n    size_t x;\n    for(x = 0; x < ilinebits; ++x) {\n      unsigned char bit = readBitFromReversedStream(&ibp, in);\n      setBitOfReversedStream(&obp, out, bit);\n    }\n    /*obp += diff; --> no, fill in some value in the padding bits too, to avoid\n    \"Use of uninitialised value of size ###\" warning from valgrind*/\n    for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0);\n  }\n}\n\n/*\nin: non-interlaced image with size w*h\nout: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with\n no padding bits between scanlines, but between reduced images so that each\n reduced image starts at a byte.\nbpp: bits per pixel\nthere are no padding bits, not between scanlines, not between reduced images\nin has the following size in bits: w * h * bpp.\nout is possibly bigger due to padding bits between reduced images\nNOTE: comments about padding bits are only relevant if bpp < 8\n*/\nstatic void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) {\n  unsigned passw[7], passh[7];\n  size_t filter_passstart[8], padded_passstart[8], passstart[8];\n  unsigned i;\n\n  Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);\n\n  if(bpp >= 8) {\n    for(i = 0; i != 7; ++i) {\n      unsigned x, y, b;\n      size_t bytewidth = bpp / 8u;\n      for(y = 0; y < passh[i]; ++y)\n      for(x = 0; x < passw[i]; ++x) {\n        size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;\n        size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth;\n        for(b = 0; b < bytewidth; ++b) {\n          out[pixeloutstart + b] = in[pixelinstart + b];\n        }\n      }\n    }\n  } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ {\n    for(i = 0; i != 7; ++i) {\n      unsigned x, y, b;\n      unsigned ilinebits = bpp * passw[i];\n      unsigned olinebits = bpp * w;\n      size_t obp, ibp; /*bit pointers (for out and in buffer)*/\n      for(y = 0; y < passh[i]; ++y)\n      for(x = 0; x < passw[i]; ++x) {\n        ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;\n        obp = (8 * passstart[i]) + (y * ilinebits + x * bpp);\n        for(b = 0; b < bpp; ++b) {\n          unsigned char bit = readBitFromReversedStream(&ibp, in);\n          setBitOfReversedStream(&obp, out, bit);\n        }\n      }\n    }\n  }\n}\n\n/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image.\nreturn value is error**/\nstatic unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in,\n                                    unsigned w, unsigned h,\n                                    const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) {\n  /*\n  This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps:\n  *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp < 8) 2) filter\n  *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter\n  */\n  unsigned bpp = lodepng_get_bpp(&info_png->color);\n  unsigned error = 0;\n\n  if(info_png->interlace_method == 0) {\n    *outsize = h + (h * ((w * bpp + 7u) / 8u)); /*image size plus an extra byte per scanline + possible padding bits*/\n    *out = (unsigned char*)lodepng_malloc(*outsize);\n    if(!(*out) && (*outsize)) error = 83; /*alloc fail*/\n\n    if(!error) {\n      /*non multiple of 8 bits per scanline, padding bits needed per scanline*/\n      if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) {\n        unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7u) / 8u));\n        if(!padded) error = 83; /*alloc fail*/\n        if(!error) {\n          addPaddingBits(padded, in, ((w * bpp + 7u) / 8u) * 8u, w * bpp, h);\n          error = filter(*out, padded, w, h, &info_png->color, settings);\n        }\n        lodepng_free(padded);\n      } else {\n        /*we can immediately filter into the out buffer, no other steps needed*/\n        error = filter(*out, in, w, h, &info_png->color, settings);\n      }\n    }\n  } else /*interlace_method is 1 (Adam7)*/ {\n    unsigned passw[7], passh[7];\n    size_t filter_passstart[8], padded_passstart[8], passstart[8];\n    unsigned char* adam7;\n\n    Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);\n\n    *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/\n    *out = (unsigned char*)lodepng_malloc(*outsize);\n    if(!(*out)) error = 83; /*alloc fail*/\n\n    adam7 = (unsigned char*)lodepng_malloc(passstart[7]);\n    if(!adam7 && passstart[7]) error = 83; /*alloc fail*/\n\n    if(!error) {\n      unsigned i;\n\n      Adam7_interlace(adam7, in, w, h, bpp);\n      for(i = 0; i != 7; ++i) {\n        if(bpp < 8) {\n          unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]);\n          if(!padded) ERROR_BREAK(83); /*alloc fail*/\n          addPaddingBits(padded, &adam7[passstart[i]],\n                         ((passw[i] * bpp + 7u) / 8u) * 8u, passw[i] * bpp, passh[i]);\n          error = filter(&(*out)[filter_passstart[i]], padded,\n                         passw[i], passh[i], &info_png->color, settings);\n          lodepng_free(padded);\n        } else {\n          error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]],\n                         passw[i], passh[i], &info_png->color, settings);\n        }\n\n        if(error) break;\n      }\n    }\n\n    lodepng_free(adam7);\n  }\n\n  return error;\n}\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\nstatic unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) {\n  unsigned char* inchunk = data;\n  while((size_t)(inchunk - data) < datasize) {\n    CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk));\n    out->allocsize = out->size; /*fix the allocsize again*/\n    inchunk = lodepng_chunk_next(inchunk, data + datasize);\n  }\n  return 0;\n}\n\nstatic unsigned isGrayICCProfile(const unsigned char* profile, unsigned size) {\n  /*\n  It is a gray profile if bytes 16-19 are \"GRAY\", rgb profile if bytes 16-19\n  are \"RGB \". We do not perform any full parsing of the ICC profile here, other\n  than check those 4 bytes to grayscale profile. Other than that, validity of\n  the profile is not checked. This is needed only because the PNG specification\n  requires using a non-gray color model if there is an ICC profile with \"RGB \"\n  (sadly limiting compression opportunities if the input data is grayscale RGB\n  data), and requires using a gray color model if it is \"GRAY\".\n  */\n  if(size < 20) return 0;\n  return profile[16] == 'G' &&  profile[17] == 'R' &&  profile[18] == 'A' &&  profile[19] == 'Y';\n}\n\nstatic unsigned isRGBICCProfile(const unsigned char* profile, unsigned size) {\n  /* See comment in isGrayICCProfile*/\n  if(size < 20) return 0;\n  return profile[16] == 'R' &&  profile[17] == 'G' &&  profile[18] == 'B' &&  profile[19] == ' ';\n}\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\nunsigned lodepng_encode(unsigned char** out, size_t* outsize,\n                        const unsigned char* image, unsigned w, unsigned h,\n                        LodePNGState* state) {\n  unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/\n  size_t datasize = 0;\n  ucvector outv = ucvector_init(NULL, 0);\n  LodePNGInfo info;\n  const LodePNGInfo* info_png = &state->info_png;\n\n  lodepng_info_init(&info);\n\n  /*provide some proper output values if error will happen*/\n  *out = 0;\n  *outsize = 0;\n  state->error = 0;\n\n  /*check input values validity*/\n  if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette)\n      && (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) {\n    state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/\n    goto cleanup;\n  }\n  if(state->encoder.zlibsettings.btype > 2) {\n    state->error = 61; /*error: invalid btype*/\n    goto cleanup;\n  }\n  if(info_png->interlace_method > 1) {\n    state->error = 71; /*error: invalid interlace mode*/\n    goto cleanup;\n  }\n  state->error = checkColorValidity(info_png->color.colortype, info_png->color.bitdepth);\n  if(state->error) goto cleanup; /*error: invalid color type given*/\n  state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth);\n  if(state->error) goto cleanup; /*error: invalid color type given*/\n\n  /* color convert and compute scanline filter types */\n  lodepng_info_copy(&info, &state->info_png);\n  if(state->encoder.auto_convert) {\n    LodePNGColorStats stats;\n    lodepng_color_stats_init(&stats);\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    if(info_png->iccp_defined &&\n        isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) {\n      /*the PNG specification does not allow to use palette with a GRAY ICC profile, even\n      if the palette has only gray colors, so disallow it.*/\n      stats.allow_palette = 0;\n    }\n    if(info_png->iccp_defined &&\n        isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) {\n      /*the PNG specification does not allow to use grayscale color with RGB ICC profile, so disallow gray.*/\n      stats.allow_greyscale = 0;\n    }\n#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */\n    state->error = lodepng_compute_color_stats(&stats, image, w, h, &state->info_raw);\n    if(state->error) goto cleanup;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    if(info_png->background_defined) {\n      /*the background chunk's color must be taken into account as well*/\n      unsigned r = 0, g = 0, b = 0;\n      LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16);\n      lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color);\n      state->error = lodepng_color_stats_add(&stats, r, g, b, 65535);\n      if(state->error) goto cleanup;\n    }\n#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */\n    state->error = auto_choose_color(&info.color, &state->info_raw, &stats);\n    if(state->error) goto cleanup;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    /*also convert the background chunk*/\n    if(info_png->background_defined) {\n      if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b,\n          info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) {\n        state->error = 104;\n        goto cleanup;\n      }\n    }\n#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */\n  }\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  if(info_png->iccp_defined) {\n    unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size);\n    unsigned rgb_icc = isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size);\n    unsigned gray_png = info.color.colortype == LCT_GREY || info.color.colortype == LCT_GREY_ALPHA;\n    if(!gray_icc && !rgb_icc) {\n      state->error = 100; /* Disallowed profile color type for PNG */\n      goto cleanup;\n    }\n    if(gray_icc != gray_png) {\n      /*Not allowed to use RGB/RGBA/palette with GRAY ICC profile or vice versa,\n      or in case of auto_convert, it wasn't possible to find appropriate model*/\n      state->error = state->encoder.auto_convert ? 102 : 101;\n      goto cleanup;\n    }\n  }\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n  if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) {\n    unsigned char* converted;\n    size_t size = ((size_t)w * (size_t)h * (size_t)lodepng_get_bpp(&info.color) + 7u) / 8u;\n\n    converted = (unsigned char*)lodepng_malloc(size);\n    if(!converted && size) state->error = 83; /*alloc fail*/\n    if(!state->error) {\n      state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h);\n    }\n    if(!state->error) {\n      state->error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder);\n    }\n    lodepng_free(converted);\n    if(state->error) goto cleanup;\n  } else {\n    state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder);\n    if(state->error) goto cleanup;\n  }\n\n  /* output all PNG chunks */ {\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    size_t i;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    /*write signature and chunks*/\n    state->error = writeSignature(&outv);\n    if(state->error) goto cleanup;\n    /*IHDR*/\n    state->error = addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method);\n    if(state->error) goto cleanup;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    /*unknown chunks between IHDR and PLTE*/\n    if(info.unknown_chunks_data[0]) {\n      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]);\n      if(state->error) goto cleanup;\n    }\n    /*color profile chunks must come before PLTE */\n    if(info.iccp_defined) {\n      state->error = addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings);\n      if(state->error) goto cleanup;\n    }\n    if(info.srgb_defined) {\n      state->error = addChunk_sRGB(&outv, &info);\n      if(state->error) goto cleanup;\n    }\n    if(info.gama_defined) {\n      state->error = addChunk_gAMA(&outv, &info);\n      if(state->error) goto cleanup;\n    }\n    if(info.chrm_defined) {\n      state->error = addChunk_cHRM(&outv, &info);\n      if(state->error) goto cleanup;\n    }\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    /*PLTE*/\n    if(info.color.colortype == LCT_PALETTE) {\n      state->error = addChunk_PLTE(&outv, &info.color);\n      if(state->error) goto cleanup;\n    }\n    if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) {\n      /*force_palette means: write suggested palette for truecolor in PLTE chunk*/\n      state->error = addChunk_PLTE(&outv, &info.color);\n      if(state->error) goto cleanup;\n    }\n    /*tRNS (this will only add if when necessary) */\n    state->error = addChunk_tRNS(&outv, &info.color);\n    if(state->error) goto cleanup;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    /*bKGD (must come between PLTE and the IDAt chunks*/\n    if(info.background_defined) {\n      state->error = addChunk_bKGD(&outv, &info);\n      if(state->error) goto cleanup;\n    }\n    /*pHYs (must come before the IDAT chunks)*/\n    if(info.phys_defined) {\n      state->error = addChunk_pHYs(&outv, &info);\n      if(state->error) goto cleanup;\n    }\n\n    /*unknown chunks between PLTE and IDAT*/\n    if(info.unknown_chunks_data[1]) {\n      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]);\n      if(state->error) goto cleanup;\n    }\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    /*IDAT (multiple IDAT chunks must be consecutive)*/\n    state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings);\n    if(state->error) goto cleanup;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n    /*tIME*/\n    if(info.time_defined) {\n      state->error = addChunk_tIME(&outv, &info.time);\n      if(state->error) goto cleanup;\n    }\n    /*tEXt and/or zTXt*/\n    for(i = 0; i != info.text_num; ++i) {\n      if(lodepng_strlen(info.text_keys[i]) > 79) {\n        state->error = 66; /*text chunk too large*/\n        goto cleanup;\n      }\n      if(lodepng_strlen(info.text_keys[i]) < 1) {\n        state->error = 67; /*text chunk too small*/\n        goto cleanup;\n      }\n      if(state->encoder.text_compression) {\n        state->error = addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings);\n        if(state->error) goto cleanup;\n      } else {\n        state->error = addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]);\n        if(state->error) goto cleanup;\n      }\n    }\n    /*LodePNG version id in text chunk*/\n    if(state->encoder.add_id) {\n      unsigned already_added_id_text = 0;\n      for(i = 0; i != info.text_num; ++i) {\n        const char* k = info.text_keys[i];\n        /* Could use strcmp, but we're not calling or reimplementing this C library function for this use only */\n        if(k[0] == 'L' && k[1] == 'o' && k[2] == 'd' && k[3] == 'e' &&\n           k[4] == 'P' && k[5] == 'N' && k[6] == 'G' && k[7] == '\\0') {\n          already_added_id_text = 1;\n          break;\n        }\n      }\n      if(already_added_id_text == 0) {\n        state->error = addChunk_tEXt(&outv, \"LodePNG\", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/\n        if(state->error) goto cleanup;\n      }\n    }\n    /*iTXt*/\n    for(i = 0; i != info.itext_num; ++i) {\n      if(lodepng_strlen(info.itext_keys[i]) > 79) {\n        state->error = 66; /*text chunk too large*/\n        goto cleanup;\n      }\n      if(lodepng_strlen(info.itext_keys[i]) < 1) {\n        state->error = 67; /*text chunk too small*/\n        goto cleanup;\n      }\n      state->error = addChunk_iTXt(\n          &outv, state->encoder.text_compression,\n          info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i],\n          &state->encoder.zlibsettings);\n      if(state->error) goto cleanup;\n    }\n\n    /*unknown chunks between IDAT and IEND*/\n    if(info.unknown_chunks_data[2]) {\n      state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]);\n      if(state->error) goto cleanup;\n    }\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n    state->error = addChunk_IEND(&outv);\n    if(state->error) goto cleanup;\n  }\n\ncleanup:\n  lodepng_info_cleanup(&info);\n  lodepng_free(data);\n\n  /*instead of cleaning the vector up, give it to the output*/\n  *out = outv.data;\n  *outsize = outv.size;\n\n  return state->error;\n}\n\nunsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image,\n                               unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned error;\n  LodePNGState state;\n  lodepng_state_init(&state);\n  state.info_raw.colortype = colortype;\n  state.info_raw.bitdepth = bitdepth;\n  state.info_png.color.colortype = colortype;\n  state.info_png.color.bitdepth = bitdepth;\n  lodepng_encode(out, outsize, image, w, h, &state);\n  error = state.error;\n  lodepng_state_cleanup(&state);\n  return error;\n}\n\nunsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) {\n  return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8);\n}\n\nunsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) {\n  return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8);\n}\n\n#ifdef LODEPNG_COMPILE_DISK\nunsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h,\n                             LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned char* buffer;\n  size_t buffersize;\n  unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth);\n  if(!error) error = lodepng_save_file(buffer, buffersize, filename);\n  lodepng_free(buffer);\n  return error;\n}\n\nunsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) {\n  return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8);\n}\n\nunsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) {\n  return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8);\n}\n#endif /*LODEPNG_COMPILE_DISK*/\n\nvoid lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) {\n  lodepng_compress_settings_init(&settings->zlibsettings);\n  settings->filter_palette_zero = 1;\n  settings->filter_strategy = LFS_MINSUM;\n  settings->auto_convert = 1;\n  settings->force_palette = 0;\n  settings->predefined_filters = 0;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  settings->add_id = 0;\n  settings->text_compression = 1;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n}\n\n#endif /*LODEPNG_COMPILE_ENCODER*/\n#endif /*LODEPNG_COMPILE_PNG*/\n\n#ifdef LODEPNG_COMPILE_ERROR_TEXT\n/*\nThis returns the description of a numerical error code in English. This is also\nthe documentation of all the error codes.\n*/\nconst char* lodepng_error_text(unsigned code) {\n  switch(code) {\n    case 0: return \"no error, everything went ok\";\n    case 1: return \"nothing done yet\"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/\n    case 10: return \"end of input memory reached without huffman end code\"; /*while huffman decoding*/\n    case 11: return \"error in code tree made it jump outside of huffman tree\"; /*while huffman decoding*/\n    case 13: return \"problem while processing dynamic deflate block\";\n    case 14: return \"problem while processing dynamic deflate block\";\n    case 15: return \"problem while processing dynamic deflate block\";\n    /*this error could happen if there are only 0 or 1 symbols present in the huffman code:*/\n    case 16: return \"invalid code while processing dynamic deflate block\";\n    case 17: return \"end of out buffer memory reached while inflating\";\n    case 18: return \"invalid distance code while inflating\";\n    case 19: return \"end of out buffer memory reached while inflating\";\n    case 20: return \"invalid deflate block BTYPE encountered while decoding\";\n    case 21: return \"NLEN is not ones complement of LEN in a deflate block\";\n\n    /*end of out buffer memory reached while inflating:\n    This can happen if the inflated deflate data is longer than the amount of bytes required to fill up\n    all the pixels of the image, given the color depth and image dimensions. Something that doesn't\n    happen in a normal, well encoded, PNG image.*/\n    case 22: return \"end of out buffer memory reached while inflating\";\n    case 23: return \"end of in buffer memory reached while inflating\";\n    case 24: return \"invalid FCHECK in zlib header\";\n    case 25: return \"invalid compression method in zlib header\";\n    case 26: return \"FDICT encountered in zlib header while it's not used for PNG\";\n    case 27: return \"PNG file is smaller than a PNG header\";\n    /*Checks the magic file header, the first 8 bytes of the PNG file*/\n    case 28: return \"incorrect PNG signature, it's no PNG or corrupted\";\n    case 29: return \"first chunk is not the header chunk\";\n    case 30: return \"chunk length too large, chunk broken off at end of file\";\n    case 31: return \"illegal PNG color type or bpp\";\n    case 32: return \"illegal PNG compression method\";\n    case 33: return \"illegal PNG filter method\";\n    case 34: return \"illegal PNG interlace method\";\n    case 35: return \"chunk length of a chunk is too large or the chunk too small\";\n    case 36: return \"illegal PNG filter type encountered\";\n    case 37: return \"illegal bit depth for this color type given\";\n    case 38: return \"the palette is too small or too big\"; /*0, or more than 256 colors*/\n    case 39: return \"tRNS chunk before PLTE or has more entries than palette size\";\n    case 40: return \"tRNS chunk has wrong size for grayscale image\";\n    case 41: return \"tRNS chunk has wrong size for RGB image\";\n    case 42: return \"tRNS chunk appeared while it was not allowed for this color type\";\n    case 43: return \"bKGD chunk has wrong size for palette image\";\n    case 44: return \"bKGD chunk has wrong size for grayscale image\";\n    case 45: return \"bKGD chunk has wrong size for RGB image\";\n    case 48: return \"empty input buffer given to decoder. Maybe caused by non-existing file?\";\n    case 49: return \"jumped past memory while generating dynamic huffman tree\";\n    case 50: return \"jumped past memory while generating dynamic huffman tree\";\n    case 51: return \"jumped past memory while inflating huffman block\";\n    case 52: return \"jumped past memory while inflating\";\n    case 53: return \"size of zlib data too small\";\n    case 54: return \"repeat symbol in tree while there was no value symbol yet\";\n    /*jumped past tree while generating huffman tree, this could be when the\n    tree will have more leaves than symbols after generating it out of the\n    given lengths. They call this an oversubscribed dynamic bit lengths tree in zlib.*/\n    case 55: return \"jumped past tree while generating huffman tree\";\n    case 56: return \"given output image colortype or bitdepth not supported for color conversion\";\n    case 57: return \"invalid CRC encountered (checking CRC can be disabled)\";\n    case 58: return \"invalid ADLER32 encountered (checking ADLER32 can be disabled)\";\n    case 59: return \"requested color conversion not supported\";\n    case 60: return \"invalid window size given in the settings of the encoder (must be 0-32768)\";\n    case 61: return \"invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)\";\n    /*LodePNG leaves the choice of RGB to grayscale conversion formula to the user.*/\n    case 62: return \"conversion from color to grayscale not supported\";\n    /*(2^31-1)*/\n    case 63: return \"length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk\";\n    /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/\n    case 64: return \"the length of the END symbol 256 in the Huffman tree is 0\";\n    case 66: return \"the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes\";\n    case 67: return \"the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte\";\n    case 68: return \"tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors\";\n    case 69: return \"unknown chunk type with 'critical' flag encountered by the decoder\";\n    case 71: return \"invalid interlace mode given to encoder (must be 0 or 1)\";\n    case 72: return \"while decoding, invalid compression method encountering in zTXt or iTXt chunk (it must be 0)\";\n    case 73: return \"invalid tIME chunk size\";\n    case 74: return \"invalid pHYs chunk size\";\n    /*length could be wrong, or data chopped off*/\n    case 75: return \"no null termination char found while decoding text chunk\";\n    case 76: return \"iTXt chunk too short to contain required bytes\";\n    case 77: return \"integer overflow in buffer size\";\n    case 78: return \"failed to open file for reading\"; /*file doesn't exist or couldn't be opened for reading*/\n    case 79: return \"failed to open file for writing\";\n    case 80: return \"tried creating a tree of 0 symbols\";\n    case 81: return \"lazy matching at pos 0 is impossible\";\n    case 82: return \"color conversion to palette requested while a color isn't in palette, or index out of bounds\";\n    case 83: return \"memory allocation failed\";\n    case 84: return \"given image too small to contain all pixels to be encoded\";\n    case 86: return \"impossible offset in lz77 encoding (internal bug)\";\n    case 87: return \"must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined\";\n    case 88: return \"invalid filter strategy given for LodePNGEncoderSettings.filter_strategy\";\n    case 89: return \"text chunk keyword too short or long: must have size 1-79\";\n    /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/\n    case 90: return \"windowsize must be a power of two\";\n    case 91: return \"invalid decompressed idat size\";\n    case 92: return \"integer overflow due to too many pixels\";\n    case 93: return \"zero width or height is invalid\";\n    case 94: return \"header chunk must have a size of 13 bytes\";\n    case 95: return \"integer overflow with combined idat chunk size\";\n    case 96: return \"invalid gAMA chunk size\";\n    case 97: return \"invalid cHRM chunk size\";\n    case 98: return \"invalid sRGB chunk size\";\n    case 99: return \"invalid sRGB rendering intent\";\n    case 100: return \"invalid ICC profile color type, the PNG specification only allows RGB or GRAY\";\n    case 101: return \"PNG specification does not allow RGB ICC profile on gray color types and vice versa\";\n    case 102: return \"not allowed to set grayscale ICC profile with colored pixels by PNG specification\";\n    case 103: return \"invalid palette index in bKGD chunk. Maybe it came before PLTE chunk?\";\n    case 104: return \"invalid bKGD color while encoding (e.g. palette index out of range)\";\n    case 105: return \"integer overflow of bitsize\";\n    case 106: return \"PNG file must have PLTE chunk if color type is palette\";\n    case 107: return \"color convert from palette mode requested without setting the palette data in it\";\n    case 108: return \"tried to add more than 256 values to a palette\";\n  }\n  return \"unknown error code\";\n}\n#endif /*LODEPNG_COMPILE_ERROR_TEXT*/\n\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* // C++ Wrapper                                                          // */\n/* ////////////////////////////////////////////////////////////////////////// */\n/* ////////////////////////////////////////////////////////////////////////// */\n\n#ifdef LODEPNG_COMPILE_CPP\nnamespace lodepng {\n\n#ifdef LODEPNG_COMPILE_DISK\nunsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename) {\n  long size = lodepng_filesize(filename.c_str());\n  if(size < 0) return 78;\n  buffer.resize((size_t)size);\n  return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str());\n}\n\n/*write given buffer to the file, overwriting the file, it doesn't append to it.*/\nunsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename) {\n  return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str());\n}\n#endif /* LODEPNG_COMPILE_DISK */\n\n#ifdef LODEPNG_COMPILE_ZLIB\n#ifdef LODEPNG_COMPILE_DECODER\nunsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,\n                    const LodePNGDecompressSettings& settings) {\n  unsigned char* buffer = 0;\n  size_t buffersize = 0;\n  unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);\n  if(buffer) {\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n    lodepng_free(buffer);\n  }\n  return error;\n}\n\nunsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,\n                    const LodePNGDecompressSettings& settings) {\n  return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);\n}\n#endif /* LODEPNG_COMPILE_DECODER */\n\n#ifdef LODEPNG_COMPILE_ENCODER\nunsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,\n                  const LodePNGCompressSettings& settings) {\n  unsigned char* buffer = 0;\n  size_t buffersize = 0;\n  unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);\n  if(buffer) {\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n    lodepng_free(buffer);\n  }\n  return error;\n}\n\nunsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,\n                  const LodePNGCompressSettings& settings) {\n  return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);\n}\n#endif /* LODEPNG_COMPILE_ENCODER */\n#endif /* LODEPNG_COMPILE_ZLIB */\n\n\n#ifdef LODEPNG_COMPILE_PNG\n\nState::State() {\n  lodepng_state_init(this);\n}\n\nState::State(const State& other) {\n  lodepng_state_init(this);\n  lodepng_state_copy(this, &other);\n}\n\nState::~State() {\n  lodepng_state_cleanup(this);\n}\n\nState& State::operator=(const State& other) {\n  lodepng_state_copy(this, &other);\n  return *this;\n}\n\n#ifdef LODEPNG_COMPILE_DECODER\n\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in,\n                size_t insize, LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned char* buffer = 0;\n  unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth);\n  if(buffer && !error) {\n    State state;\n    state.info_raw.colortype = colortype;\n    state.info_raw.bitdepth = bitdepth;\n    size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n  }\n  lodepng_free(buffer);\n  return error;\n}\n\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth) {\n  return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth);\n}\n\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                State& state,\n                const unsigned char* in, size_t insize) {\n  unsigned char* buffer = NULL;\n  unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);\n  if(buffer && !error) {\n    size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n  }\n  lodepng_free(buffer);\n  return error;\n}\n\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                State& state,\n                const std::vector<unsigned char>& in) {\n  return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size());\n}\n\n#ifdef LODEPNG_COMPILE_DISK\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename,\n                LodePNGColorType colortype, unsigned bitdepth) {\n  std::vector<unsigned char> buffer;\n  /* safe output values in case error happens */\n  w = h = 0;\n  unsigned error = load_file(buffer, filename);\n  if(error) return error;\n  return decode(out, w, h, buffer, colortype, bitdepth);\n}\n#endif /* LODEPNG_COMPILE_DECODER */\n#endif /* LODEPNG_COMPILE_DISK */\n\n#ifdef LODEPNG_COMPILE_ENCODER\nunsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h,\n                LodePNGColorType colortype, unsigned bitdepth) {\n  unsigned char* buffer;\n  size_t buffersize;\n  unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);\n  if(buffer) {\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n    lodepng_free(buffer);\n  }\n  return error;\n}\n\nunsigned encode(std::vector<unsigned char>& out,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                LodePNGColorType colortype, unsigned bitdepth) {\n  if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;\n  return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);\n}\n\nunsigned encode(std::vector<unsigned char>& out,\n                const unsigned char* in, unsigned w, unsigned h,\n                State& state) {\n  unsigned char* buffer;\n  size_t buffersize;\n  unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);\n  if(buffer) {\n    out.insert(out.end(), &buffer[0], &buffer[buffersize]);\n    lodepng_free(buffer);\n  }\n  return error;\n}\n\nunsigned encode(std::vector<unsigned char>& out,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                State& state) {\n  if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84;\n  return encode(out, in.empty() ? 0 : &in[0], w, h, state);\n}\n\n#ifdef LODEPNG_COMPILE_DISK\nunsigned encode(const std::string& filename,\n                const unsigned char* in, unsigned w, unsigned h,\n                LodePNGColorType colortype, unsigned bitdepth) {\n  std::vector<unsigned char> buffer;\n  unsigned error = encode(buffer, in, w, h, colortype, bitdepth);\n  if(!error) error = save_file(buffer, filename);\n  return error;\n}\n\nunsigned encode(const std::string& filename,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                LodePNGColorType colortype, unsigned bitdepth) {\n  if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;\n  return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);\n}\n#endif /* LODEPNG_COMPILE_DISK */\n#endif /* LODEPNG_COMPILE_ENCODER */\n#endif /* LODEPNG_COMPILE_PNG */\n} /* namespace lodepng */\n#endif /*LODEPNG_COMPILE_CPP*/\n\n// BCH 8 Oct. 2020 : terminating diagnostic pushes to avoid warnings\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n// NOLINTEND\n"
  },
  {
    "path": "eidos/lodepng.h",
    "content": "/*\nLodePNG version 20200306\n\nCopyright (c) 2005-2020 Lode Vandevenne\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n    1. The origin of this software must not be misrepresented; you must not\n    claim that you wrote the original software. If you use this software\n    in a product, an acknowledgment in the product documentation would be\n    appreciated but is not required.\n\n    2. Altered source versions must be plainly marked as such, and must not be\n    misrepresented as being the original software.\n\n    3. This notice may not be removed or altered from any source\n    distribution.\n*/\n\n// BCH 11 Oct. 2020 : The source code here is slightly modified to get rid of compile warnings\n// Also there is one bug fix at line 4951 introduced by me, to generate an error for RGB->grayscale\n// following what the documentation and the error codes seem to indicate should occur.\n// All such changes are marked with BCH.  This code is based on a git clone from 8 Oct. 2020.\n\n#ifndef LODEPNG_H\n#define LODEPNG_H\n\n#include <string.h> /*for size_t*/\n\nextern const char* LODEPNG_VERSION_STRING;\n\n/*\nThe following #defines are used to create code sections. They can be disabled\nto disable code sections, which can give faster compile time and smaller binary.\nThe \"NO_COMPILE\" defines are designed to be used to pass as defines to the\ncompiler command to disable them without modifying this header, e.g.\n-DLODEPNG_NO_COMPILE_ZLIB for gcc.\nIn addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to\nallow implementing a custom lodepng_crc32.\n*/\n/*deflate & zlib. If disabled, you must specify alternative zlib functions in\nthe custom_zlib field of the compress and decompress settings*/\n#ifndef LODEPNG_NO_COMPILE_ZLIB\n#define LODEPNG_COMPILE_ZLIB\n#endif\n\n/*png encoder and png decoder*/\n#ifndef LODEPNG_NO_COMPILE_PNG\n#define LODEPNG_COMPILE_PNG\n#endif\n\n/*deflate&zlib decoder and png decoder*/\n#ifndef LODEPNG_NO_COMPILE_DECODER\n#define LODEPNG_COMPILE_DECODER\n#endif\n\n/*deflate&zlib encoder and png encoder*/\n#ifndef LODEPNG_NO_COMPILE_ENCODER\n#define LODEPNG_COMPILE_ENCODER\n#endif\n\n/*the optional built in harddisk file loading and saving functions*/\n#ifndef LODEPNG_NO_COMPILE_DISK\n#define LODEPNG_COMPILE_DISK\n#endif\n\n/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/\n#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS\n#define LODEPNG_COMPILE_ANCILLARY_CHUNKS\n#endif\n\n/*ability to convert error numerical codes to English text string*/\n#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT\n#define LODEPNG_COMPILE_ERROR_TEXT\n#endif\n\n/*Compile the default allocators (C's free, malloc and realloc). If you disable this,\nyou can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your\nsource files with custom allocators.*/\n#ifndef LODEPNG_NO_COMPILE_ALLOCATORS\n#define LODEPNG_COMPILE_ALLOCATORS\n#endif\n\n/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/\n#ifdef __cplusplus\n#ifndef LODEPNG_NO_COMPILE_CPP\n#define LODEPNG_COMPILE_CPP\n#endif\n#endif\n\n#ifdef LODEPNG_COMPILE_CPP\n#include <vector>\n#include <string>\n#endif /*LODEPNG_COMPILE_CPP*/\n\n#ifdef LODEPNG_COMPILE_PNG\n/*The PNG color types (also used for raw image).*/\ntypedef enum LodePNGColorType {\n  LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/\n  LCT_RGB = 2, /*RGB: 8,16 bit*/\n  LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/\n  LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/\n  LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/\n  /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid\n  byte value from 0 to 255 that could be present in an invalid PNG file header. Do\n  not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use\n  the valid color type names above, or numeric values like 1 or 7 when checking for\n  particular disallowed color type byte values, or cast to integer to print it.*/\n  LCT_MAX_OCTET_VALUE = 255\n} LodePNGColorType;\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*\nConverts PNG data in memory to raw pixel data.\nout: Output parameter. Pointer to buffer that will contain the raw pixel data.\n     After decoding, its size is w * h * (bytes per pixel) bytes larger than\n     initially. Bytes per pixel depends on colortype and bitdepth.\n     Must be freed after usage with free(*out).\n     Note: for 16-bit per channel colors, uses big endian format like PNG does.\nw: Output parameter. Pointer to width of pixel data.\nh: Output parameter. Pointer to height of pixel data.\nin: Memory buffer with the PNG file.\ninsize: size of the in buffer.\ncolortype: the desired color type for the raw output image. See explanation on PNG color types.\nbitdepth: the desired bit depth for the raw output image. See explanation on PNG color types.\nReturn value: LodePNG error code (0 means no error).\n*/\nunsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h,\n                               const unsigned char* in, size_t insize,\n                               LodePNGColorType colortype, unsigned bitdepth);\n\n/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/\nunsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h,\n                          const unsigned char* in, size_t insize);\n\n/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/\nunsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h,\n                          const unsigned char* in, size_t insize);\n\n#ifdef LODEPNG_COMPILE_DISK\n/*\nLoad PNG from disk, from file with given name.\nSame as the other decode functions, but instead takes a filename as input.\n*/\nunsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h,\n                             const char* filename,\n                             LodePNGColorType colortype, unsigned bitdepth);\n\n/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/\nunsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h,\n                               const char* filename);\n\n/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/\nunsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,\n                               const char* filename);\n#endif /*LODEPNG_COMPILE_DISK*/\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*\nConverts raw pixel data into a PNG image in memory. The colortype and bitdepth\n  of the output PNG image cannot be chosen, they are automatically determined\n  by the colortype, bitdepth and content of the input pixel data.\n  Note: for 16-bit per channel colors, needs big endian format like PNG does.\nout: Output parameter. Pointer to buffer that will contain the PNG image data.\n     Must be freed after usage with free(*out).\noutsize: Output parameter. Pointer to the size in bytes of the out buffer.\nimage: The raw pixel data to encode. The size of this buffer should be\n       w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth.\nw: width of the raw pixel data in pixels.\nh: height of the raw pixel data in pixels.\ncolortype: the color type of the raw input image. See explanation on PNG color types.\nbitdepth: the bit depth of the raw input image. See explanation on PNG color types.\nReturn value: LodePNG error code (0 means no error).\n*/\nunsigned lodepng_encode_memory(unsigned char** out, size_t* outsize,\n                               const unsigned char* image, unsigned w, unsigned h,\n                               LodePNGColorType colortype, unsigned bitdepth);\n\n/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/\nunsigned lodepng_encode32(unsigned char** out, size_t* outsize,\n                          const unsigned char* image, unsigned w, unsigned h);\n\n/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/\nunsigned lodepng_encode24(unsigned char** out, size_t* outsize,\n                          const unsigned char* image, unsigned w, unsigned h);\n\n#ifdef LODEPNG_COMPILE_DISK\n/*\nConverts raw pixel data into a PNG file on disk.\nSame as the other encode functions, but instead takes a filename as output.\nNOTE: This overwrites existing files without warning!\n*/\nunsigned lodepng_encode_file(const char* filename,\n                             const unsigned char* image, unsigned w, unsigned h,\n                             LodePNGColorType colortype, unsigned bitdepth);\n\n/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/\nunsigned lodepng_encode32_file(const char* filename,\n                               const unsigned char* image, unsigned w, unsigned h);\n\n/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/\nunsigned lodepng_encode24_file(const char* filename,\n                               const unsigned char* image, unsigned w, unsigned h);\n#endif /*LODEPNG_COMPILE_DISK*/\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n\n#ifdef LODEPNG_COMPILE_CPP\nnamespace lodepng {\n#ifdef LODEPNG_COMPILE_DECODER\n/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype\nis the format to output the pixels to. Default is RGBA 8-bit per channel.*/\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                const unsigned char* in, size_t insize,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                const std::vector<unsigned char>& in,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\n#ifdef LODEPNG_COMPILE_DISK\n/*\nConverts PNG file from disk to raw pixel data in memory.\nSame as the other decode functions, but instead takes a filename as input.\n*/\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                const std::string& filename,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\n#endif /* LODEPNG_COMPILE_DISK */\n#endif /* LODEPNG_COMPILE_DECODER */\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype\nis that of the raw input data. The output PNG color type will be auto chosen.*/\nunsigned encode(std::vector<unsigned char>& out,\n                const unsigned char* in, unsigned w, unsigned h,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\nunsigned encode(std::vector<unsigned char>& out,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\n#ifdef LODEPNG_COMPILE_DISK\n/*\nConverts 32-bit RGBA raw pixel data into a PNG file on disk.\nSame as the other encode functions, but instead takes a filename as output.\nNOTE: This overwrites existing files without warning!\n*/\nunsigned encode(const std::string& filename,\n                const unsigned char* in, unsigned w, unsigned h,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\nunsigned encode(const std::string& filename,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);\n#endif /* LODEPNG_COMPILE_DISK */\n#endif /* LODEPNG_COMPILE_ENCODER */\n} /* namespace lodepng */\n#endif /*LODEPNG_COMPILE_CPP*/\n#endif /*LODEPNG_COMPILE_PNG*/\n\n#ifdef LODEPNG_COMPILE_ERROR_TEXT\n/*Returns an English description of the numerical error code.*/\nconst char* lodepng_error_text(unsigned code);\n#endif /*LODEPNG_COMPILE_ERROR_TEXT*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*Settings for zlib decompression*/\ntypedef struct LodePNGDecompressSettings LodePNGDecompressSettings;\nstruct LodePNGDecompressSettings {\n  /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */\n  unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/\n  unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/\n\n  /*use custom zlib decoder instead of built in one (default: null)*/\n  unsigned (*custom_zlib)(unsigned char**, size_t*,\n                          const unsigned char*, size_t,\n                          const LodePNGDecompressSettings*);\n  /*use custom deflate decoder instead of built in one (default: null)\n  if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/\n  unsigned (*custom_inflate)(unsigned char**, size_t*,\n                             const unsigned char*, size_t,\n                             const LodePNGDecompressSettings*);\n\n  const void* custom_context; /*optional custom settings for custom functions*/\n};\n\nextern const LodePNGDecompressSettings lodepng_default_decompress_settings;\nvoid lodepng_decompress_settings_init(LodePNGDecompressSettings* settings);\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*\nSettings for zlib compression. Tweaking these settings tweaks the balance\nbetween speed and compression ratio.\n*/\ntypedef struct LodePNGCompressSettings LodePNGCompressSettings;\nstruct LodePNGCompressSettings /*deflate = compress*/ {\n  /*LZ77 related settings*/\n  unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/\n  unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/\n  unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/\n  unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/\n  unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/\n  unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/\n\n  /*use custom zlib encoder instead of built in one (default: null)*/\n  unsigned (*custom_zlib)(unsigned char**, size_t*,\n                          const unsigned char*, size_t,\n                          const LodePNGCompressSettings*);\n  /*use custom deflate encoder instead of built in one (default: null)\n  if custom_zlib is used, custom_deflate is ignored since only the built in\n  zlib function will call custom_deflate*/\n  unsigned (*custom_deflate)(unsigned char**, size_t*,\n                             const unsigned char*, size_t,\n                             const LodePNGCompressSettings*);\n\n  const void* custom_context; /*optional custom settings for custom functions*/\n};\n\nextern const LodePNGCompressSettings lodepng_default_compress_settings;\nvoid lodepng_compress_settings_init(LodePNGCompressSettings* settings);\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#ifdef LODEPNG_COMPILE_PNG\n/*\nColor mode of an image. Contains all information required to decode the pixel\nbits to RGBA colors. This information is the same as used in the PNG file\nformat, and is used both for PNG and raw image data in LodePNG.\n*/\ntypedef struct LodePNGColorMode {\n  /*header (IHDR)*/\n  LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/\n  unsigned bitdepth;  /*bits per sample, see PNG standard or documentation further in this header file*/\n\n  /*\n  palette (PLTE and tRNS)\n\n  Dynamically allocated with the colors of the palette, including alpha.\n  This field may not be allocated directly, use lodepng_color_mode_init first,\n  then lodepng_palette_add per color to correctly initialize it (to ensure size\n  of exactly 1024 bytes).\n\n  The alpha channels must be set as well, set them to 255 for opaque images.\n\n  When decoding, by default you can ignore this palette, since LodePNG already\n  fills the palette colors in the pixels of the raw RGBA output.\n\n  The palette is only supported for color type 3.\n  */\n  unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/\n  size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/\n\n  /*\n  transparent color key (tRNS)\n\n  This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.\n  For grayscale PNGs, r, g and b will all 3 be set to the same.\n\n  When decoding, by default you can ignore this information, since LodePNG sets\n  pixels with this key to transparent already in the raw RGBA output.\n\n  The color key is only supported for color types 0 and 2.\n  */\n  unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/\n  unsigned key_r;       /*red/grayscale component of color key*/\n  unsigned key_g;       /*green component of color key*/\n  unsigned key_b;       /*blue component of color key*/\n} LodePNGColorMode;\n\n/*init, cleanup and copy functions to use with this struct*/\nvoid lodepng_color_mode_init(LodePNGColorMode* info);\nvoid lodepng_color_mode_cleanup(LodePNGColorMode* info);\n/*return value is error code (0 means no error)*/\nunsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source);\n/* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */\nLodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth);\n\nvoid lodepng_palette_clear(LodePNGColorMode* info);\n/*add 1 color to the palette*/\nunsigned lodepng_palette_add(LodePNGColorMode* info,\n                             unsigned char r, unsigned char g, unsigned char b, unsigned char a);\n\n/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/\nunsigned lodepng_get_bpp(const LodePNGColorMode* info);\n/*get the amount of color channels used, based on colortype in the struct.\nIf a palette is used, it counts as 1 channel.*/\nunsigned lodepng_get_channels(const LodePNGColorMode* info);\n/*is it a grayscale type? (only colortype 0 or 4)*/\nunsigned lodepng_is_greyscale_type(const LodePNGColorMode* info);\n/*has it got an alpha channel? (only colortype 2 or 6)*/\nunsigned lodepng_is_alpha_type(const LodePNGColorMode* info);\n/*has it got a palette? (only colortype 3)*/\nunsigned lodepng_is_palette_type(const LodePNGColorMode* info);\n/*only returns true if there is a palette and there is a value in the palette with alpha < 255.\nLoops through the palette to check this.*/\nunsigned lodepng_has_palette_alpha(const LodePNGColorMode* info);\n/*\nCheck if the given color info indicates the possibility of having non-opaque pixels in the PNG image.\nReturns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels).\nReturns false if the image can only have opaque pixels.\nIn detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values,\nor if \"key_defined\" is true.\n*/\nunsigned lodepng_can_have_alpha(const LodePNGColorMode* info);\n/*Returns the byte size of a raw image buffer with given width, height and color mode*/\nsize_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color);\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n/*The information of a Time chunk in PNG.*/\ntypedef struct LodePNGTime {\n  unsigned year;    /*2 bytes used (0-65535)*/\n  unsigned month;   /*1-12*/\n  unsigned day;     /*1-31*/\n  unsigned hour;    /*0-23*/\n  unsigned minute;  /*0-59*/\n  unsigned second;  /*0-60 (to allow for leap seconds)*/\n} LodePNGTime;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\n/*Information about the PNG image, except pixels, width and height.*/\ntypedef struct LodePNGInfo {\n  /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/\n  unsigned compression_method;/*compression method of the original file. Always 0.*/\n  unsigned filter_method;     /*filter method of the original file*/\n  unsigned interlace_method;  /*interlace method of the original file: 0=none, 1=Adam7*/\n  LodePNGColorMode color;     /*color type and bits, palette and transparency of the PNG file*/\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  /*\n  Suggested background color chunk (bKGD)\n\n  This uses the same color mode and bit depth as the PNG (except no alpha channel),\n  with values truncated to the bit depth in the unsigned integer.\n\n  For grayscale and palette PNGs, the value is stored in background_r. The values\n  in background_g and background_b are then unused.\n\n  So when decoding, you may get these in a different color mode than the one you requested\n  for the raw pixels.\n\n  When encoding with auto_convert, you must use the color model defined in info_png.color for\n  these values. The encoder normally ignores info_png.color when auto_convert is on, but will\n  use it to interpret these values (and convert copies of them to its chosen color model).\n\n  When encoding, avoid setting this to an expensive color, such as a non-gray value\n  when the image is gray, or the compression will be worse since it will be forced to\n  write the PNG with a more expensive color mode (when auto_convert is on).\n\n  The decoder does not use this background color to edit the color of pixels. This is a\n  completely optional metadata feature.\n  */\n  unsigned background_defined; /*is a suggested background color given?*/\n  unsigned background_r;       /*red/gray/palette component of suggested background color*/\n  unsigned background_g;       /*green component of suggested background color*/\n  unsigned background_b;       /*blue component of suggested background color*/\n\n  /*\n  non-international text chunks (tEXt and zTXt)\n\n  The char** arrays each contain num strings. The actual messages are in\n  text_strings, while text_keys are keywords that give a short description what\n  the actual text represents, e.g. Title, Author, Description, or anything else.\n\n  All the string fields below including keys, names and language tags are null terminated.\n  The PNG specification uses null characters for the keys, names and tags, and forbids null\n  characters to appear in the main text which is why we can use null termination everywhere here.\n\n  A keyword is minimum 1 character and maximum 79 characters long. It's\n  discouraged to use a single line length longer than 79 characters for texts.\n\n  Don't allocate these text buffers yourself. Use the init/cleanup functions\n  correctly and use lodepng_add_text and lodepng_clear_text.\n  */\n  size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/\n  char** text_keys; /*the keyword of a text chunk (e.g. \"Comment\")*/\n  char** text_strings; /*the actual text*/\n\n  /*\n  international text chunks (iTXt)\n  Similar to the non-international text chunks, but with additional strings\n  \"langtags\" and \"transkeys\".\n  */\n  size_t itext_num; /*the amount of international texts in this PNG*/\n  char** itext_keys; /*the English keyword of the text chunk (e.g. \"Comment\")*/\n  char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/\n  char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/\n  char** itext_strings; /*the actual international text - UTF-8 string*/\n\n  /*time chunk (tIME)*/\n  unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/\n  LodePNGTime time;\n\n  /*phys chunk (pHYs)*/\n  unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/\n  unsigned phys_x; /*pixels per unit in x direction*/\n  unsigned phys_y; /*pixels per unit in y direction*/\n  unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/\n\n  /*\n  Color profile related chunks: gAMA, cHRM, sRGB, iCPP\n\n  LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color\n  profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please\n  use these values with a color management library.\n\n  See the PNG, ICC and sRGB specifications for more information about the meaning of these values.\n  */\n\n  /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */\n  unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */\n  unsigned gama_gamma;   /* Gamma exponent times 100000 */\n\n  /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */\n  unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */\n  unsigned chrm_white_x; /* White Point x times 100000 */\n  unsigned chrm_white_y; /* White Point y times 100000 */\n  unsigned chrm_red_x;   /* Red x times 100000 */\n  unsigned chrm_red_y;   /* Red y times 100000 */\n  unsigned chrm_green_x; /* Green x times 100000 */\n  unsigned chrm_green_y; /* Green y times 100000 */\n  unsigned chrm_blue_x;  /* Blue x times 100000 */\n  unsigned chrm_blue_y;  /* Blue y times 100000 */\n\n  /*\n  sRGB chunk: optional. May not appear at the same time as iCCP.\n  If gAMA is also present gAMA must contain value 45455.\n  If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000.\n  */\n  unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */\n  unsigned srgb_intent;  /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */\n\n  /*\n  iCCP chunk: optional. May not appear at the same time as sRGB.\n\n  LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a\n  separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color\n  management and conversions.\n\n  For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC\n  profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and\n  enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile.\n\n  For encoding, the ICC profile is required by the PNG specification to be an \"RGB\" profile for non-gray\n  PNG color types and a \"GRAY\" profile for gray PNG color types. If you disable auto_convert, you must ensure\n  the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is\n  enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder\n  error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel\n  data if the pixels could be encoded as grayscale but the ICC profile is RGB.\n\n  To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so\n  make sure you compute it carefully to avoid the above problems.\n  */\n  unsigned iccp_defined;      /* Whether an iCCP chunk is present (0 = not present, 1 = present). */\n  char* iccp_name;            /* Null terminated string with profile name, 1-79 bytes */\n  /*\n  The ICC profile in iccp_profile_size bytes.\n  Don't allocate this buffer yourself. Use the init/cleanup functions\n  correctly and use lodepng_set_icc and lodepng_clear_icc.\n  */\n  unsigned char* iccp_profile;\n  unsigned iccp_profile_size; /* The size of iccp_profile in bytes */\n\n  /* End of color profile related chunks */\n\n\n  /*\n  unknown chunks: chunks not known by LodePNG, passed on byte for byte.\n\n  There are 3 buffers, one for each position in the PNG where unknown chunks can appear.\n  Each buffer contains all unknown chunks for that position consecutively.\n  The 3 positions are:\n  0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND.\n\n  For encoding, do not store critical chunks or known chunks that are enabled with a \"_defined\" flag\n  above in here, since the encoder will blindly follow this and could then encode an invalid PNG file\n  (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use\n  this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST),\n  or any non-standard PNG chunk.\n\n  Do not allocate or traverse this data yourself. Use the chunk traversing functions declared\n  later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct.\n  */\n  unsigned char* unknown_chunks_data[3];\n  size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n} LodePNGInfo;\n\n/*init, cleanup and copy functions to use with this struct*/\nvoid lodepng_info_init(LodePNGInfo* info);\nvoid lodepng_info_cleanup(LodePNGInfo* info);\n/*return value is error code (0 means no error)*/\nunsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source);\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\nunsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/\nvoid lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/\n\nunsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,\n                           const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/\nvoid lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/\n\n/*replaces if exists*/\nunsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size);\nvoid lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n\n/*\nConverts raw buffer from one color type to another color type, based on\nLodePNGColorMode structs to describe the input and output color type.\nSee the reference manual at the end of this header file to see which color conversions are supported.\nreturn value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported)\nThe out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel\nof the output color type (lodepng_get_bpp).\nFor < 8 bpp images, there should not be padding bits at the end of scanlines.\nFor 16-bit per channel colors, uses big endian format like PNG does.\nReturn value is LodePNG error code\n*/\nunsigned lodepng_convert(unsigned char* out, const unsigned char* in,\n                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,\n                         unsigned w, unsigned h);\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*\nSettings for the decoder. This contains settings for the PNG and the Zlib\ndecoder, but not the Info settings from the Info structs.\n*/\ntypedef struct LodePNGDecoderSettings {\n  LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/\n\n  /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */\n  unsigned ignore_crc; /*ignore CRC checksums*/\n  unsigned ignore_critical; /*ignore unknown critical chunks*/\n  unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/\n  /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable\n     errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some\n     strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters\n     in string keys, etc... */\n\n  unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/\n\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/\n  /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/\n  unsigned remember_unknown_chunks;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n} LodePNGDecoderSettings;\n\nvoid lodepng_decoder_settings_init(LodePNGDecoderSettings* settings);\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/\ntypedef enum LodePNGFilterStrategy {\n  /*every filter at zero*/\n  LFS_ZERO = 0,\n  /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/\n  LFS_ONE = 1,\n  LFS_TWO = 2,\n  LFS_THREE = 3,\n  LFS_FOUR = 4,\n  /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/\n  LFS_MINSUM,\n  /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending\n  on the image, this is better or worse than minsum.*/\n  LFS_ENTROPY,\n  /*\n  Brute-force-search PNG filters by compressing each filter for each scanline.\n  Experimental, very slow, and only rarely gives better compression than MINSUM.\n  */\n  LFS_BRUTE_FORCE,\n  /*use predefined_filters buffer: you specify the filter type for each scanline*/\n  LFS_PREDEFINED\n} LodePNGFilterStrategy;\n\n/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...),\nwhich helps decide which color model to use for encoding.\nUsed internally by default if \"auto_convert\" is enabled. Public because it's useful for custom algorithms.*/\ntypedef struct LodePNGColorStats {\n  unsigned colored; /*not grayscale*/\n  unsigned key; /*image is not opaque and color key is possible instead of full alpha*/\n  unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/\n  unsigned short key_g;\n  unsigned short key_b;\n  unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/\n  unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/\n  unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/\n  unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/\n  size_t numpixels;\n\n  /*user settings for computing/using the stats*/\n  unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/\n  unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/\n} LodePNGColorStats;\n\nvoid lodepng_color_stats_init(LodePNGColorStats* stats);\n\n/*Get a LodePNGColorStats of the image. The stats must already have been inited.\nReturns error code (e.g. alloc fail) or 0 if ok.*/\nunsigned lodepng_compute_color_stats(LodePNGColorStats* stats,\n                                     const unsigned char* image, unsigned w, unsigned h,\n                                     const LodePNGColorMode* mode_in);\n\n/*Settings for the encoder.*/\ntypedef struct LodePNGEncoderSettings {\n  LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/\n\n  unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/\n\n  /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than\n  8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to\n  completely follow the official PNG heuristic, filter_palette_zero must be true and\n  filter_strategy must be LFS_MINSUM*/\n  unsigned filter_palette_zero;\n  /*Which filter strategy to use when not using zeroes due to filter_palette_zero.\n  Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/\n  LodePNGFilterStrategy filter_strategy;\n  /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with\n  the same length as the amount of scanlines in the image, and each value must <= 5. You\n  have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero\n  must be set to 0 to ensure this is also used on palette or low bitdepth images.*/\n  const unsigned char* predefined_filters;\n\n  /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).\n  If colortype is 3, PLTE is _always_ created.*/\n  unsigned force_palette;\n#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS\n  /*add LodePNG identifier and version as a text chunk, for debugging*/\n  unsigned add_id;\n  /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/\n  unsigned text_compression;\n#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/\n} LodePNGEncoderSettings;\n\nvoid lodepng_encoder_settings_init(LodePNGEncoderSettings* settings);\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n\n#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)\n/*The settings, state and information for extended encoding and decoding.*/\ntypedef struct LodePNGState {\n#ifdef LODEPNG_COMPILE_DECODER\n  LodePNGDecoderSettings decoder; /*the decoding settings*/\n#endif /*LODEPNG_COMPILE_DECODER*/\n#ifdef LODEPNG_COMPILE_ENCODER\n  LodePNGEncoderSettings encoder; /*the encoding settings*/\n#endif /*LODEPNG_COMPILE_ENCODER*/\n  LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/\n  LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/\n  unsigned error;\n} LodePNGState;\n\n/*init, cleanup and copy functions to use with this struct*/\nvoid lodepng_state_init(LodePNGState* state);\nvoid lodepng_state_cleanup(LodePNGState* state);\nvoid lodepng_state_copy(LodePNGState* dest, const LodePNGState* source);\n#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*\nSame as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and\ngetting much more information about the PNG image and color mode.\n*/\nunsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,\n                        LodePNGState* state,\n                        const unsigned char* in, size_t insize);\n\n/*\nRead the PNG header, but not the actual data. This returns only the information\nthat is in the IHDR chunk of the PNG, such as width, height and color type. The\ninformation is placed in the info_png field of the LodePNGState.\n*/\nunsigned lodepng_inspect(unsigned* w, unsigned* h,\n                         LodePNGState* state,\n                         const unsigned char* in, size_t insize);\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n/*\nReads one metadata chunk (other than IHDR) of the PNG file and outputs what it\nread in the state. Returns error code on failure.\nUse lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const\nto find the desired chunk type, and if non null use lodepng_inspect_chunk (with\nchunk_pointer - start_of_file as pos).\nSupports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...).\nIgnores unsupported, unknown, non-metadata or IHDR chunks (without error).\nRequirements: &in[pos] must point to start of a chunk, must use regular\nlodepng_inspect first since format of most other chunks depends on IHDR, and if\nthere is a PLTE chunk, that one must be inspected before tRNS or bKGD.\n*/\nunsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,\n                               const unsigned char* in, size_t insize);\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/\nunsigned lodepng_encode(unsigned char** out, size_t* outsize,\n                        const unsigned char* image, unsigned w, unsigned h,\n                        LodePNGState* state);\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n/*\nThe lodepng_chunk functions are normally not needed, except to traverse the\nunknown chunks stored in the LodePNGInfo struct, or add new ones to it.\nIt also allows traversing the chunks of an encoded PNG file yourself.\n\nThe chunk pointer always points to the beginning of the chunk itself, that is\nthe first byte of the 4 length bytes.\n\nIn the PNG file format, chunks have the following format:\n-4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer)\n-4 bytes chunk type (ASCII a-z,A-Z only, see below)\n-length bytes of data (may be 0 bytes if length was 0)\n-4 bytes of CRC, computed on chunk name + data\n\nThe first chunk starts at the 8th byte of the PNG file, the entire rest of the file\nexists out of concatenated chunks with the above format.\n\nPNG standard chunk ASCII naming conventions:\n-First byte: uppercase = critical, lowercase = ancillary\n-Second byte: uppercase = public, lowercase = private\n-Third byte: must be uppercase\n-Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy\n*/\n\n/*\nGets the length of the data of the chunk. Total chunk length has 12 bytes more.\nThere must be at least 4 bytes to read from. If the result value is too large,\nit may be corrupt data.\n*/\nunsigned lodepng_chunk_length(const unsigned char* chunk);\n\n/*puts the 4-byte type in null terminated string*/\nvoid lodepng_chunk_type(char type[5], const unsigned char* chunk);\n\n/*check if the type is the given type*/\nunsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type);\n\n/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/\nunsigned char lodepng_chunk_ancillary(const unsigned char* chunk);\n\n/*0: public, 1: private (see PNG standard)*/\nunsigned char lodepng_chunk_private(const unsigned char* chunk);\n\n/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/\nunsigned char lodepng_chunk_safetocopy(const unsigned char* chunk);\n\n/*get pointer to the data of the chunk, where the input points to the header of the chunk*/\nunsigned char* lodepng_chunk_data(unsigned char* chunk);\nconst unsigned char* lodepng_chunk_data_const(const unsigned char* chunk);\n\n/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/\nunsigned lodepng_chunk_check_crc(const unsigned char* chunk);\n\n/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/\nvoid lodepng_chunk_generate_crc(unsigned char* chunk);\n\n/*\nIterate to next chunks, allows iterating through all chunks of the PNG file.\nInput must be at the beginning of a chunk (result of a previous lodepng_chunk_next call,\nor the 8th byte of a PNG file which always has the first chunk), or alternatively may\npoint to the first byte of the PNG file (which is not a chunk but the magic header, the\nfunction will then skip over it and return the first real chunk).\nWill output pointer to the start of the next chunk, or at or beyond end of the file if there\nis no more chunk after this or possibly if the chunk is corrupt.\nStart this process at the 8th byte of the PNG file.\nIn a non-corrupt PNG file, the last chunk should have name \"IEND\".\n*/\nunsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end);\nconst unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end);\n\n/*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/\nunsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]);\nconst unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]);\n\n/*\nAppends chunk to the data in out. The given chunk should already have its chunk header.\nThe out variable and outsize are updated to reflect the new reallocated buffer.\nReturns error code (0 if it went ok)\n*/\nunsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk);\n\n/*\nAppends new chunk to out. The chunk to append is given by giving its length, type\nand data separately. The type is a 4-letter string.\nThe out variable and outsize are updated to reflect the new reallocated buffer.\nReturne error code (0 if it went ok)\n*/\nunsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length,\n                              const char* type, const unsigned char* data);\n\n\n/*Calculate CRC32 of buffer*/\nunsigned lodepng_crc32(const unsigned char* buf, size_t len);\n#endif /*LODEPNG_COMPILE_PNG*/\n\n\n#ifdef LODEPNG_COMPILE_ZLIB\n/*\nThis zlib part can be used independently to zlib compress and decompress a\nbuffer. It cannot be used to create gzip files however, and it only supports the\npart of zlib that is required for PNG, it does not support dictionaries.\n*/\n\n#ifdef LODEPNG_COMPILE_DECODER\n/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/\nunsigned lodepng_inflate(unsigned char** out, size_t* outsize,\n                         const unsigned char* in, size_t insize,\n                         const LodePNGDecompressSettings* settings);\n\n/*\nDecompresses Zlib data. Reallocates the out buffer and appends the data. The\ndata must be according to the zlib specification.\nEither, *out must be NULL and *outsize must be 0, or, *out must be a valid\nbuffer and *outsize its size in bytes. out must be freed by user after usage.\n*/\nunsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize,\n                                 const unsigned char* in, size_t insize,\n                                 const LodePNGDecompressSettings* settings);\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/*\nCompresses data with Zlib. Reallocates the out buffer and appends the data.\nZlib adds a small header and trailer around the deflate data.\nThe data is output in the format of the zlib specification.\nEither, *out must be NULL and *outsize must be 0, or, *out must be a valid\nbuffer and *outsize its size in bytes. out must be freed by user after usage.\n*/\nunsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize,\n                               const unsigned char* in, size_t insize,\n                               const LodePNGCompressSettings* settings);\n\n/*\nFind length-limited Huffman code for given frequencies. This function is in the\npublic interface only for tests, it's used internally by lodepng_deflate.\n*/\nunsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,\n                                      size_t numcodes, unsigned maxbitlen);\n\n/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/\nunsigned lodepng_deflate(unsigned char** out, size_t* outsize,\n                         const unsigned char* in, size_t insize,\n                         const LodePNGCompressSettings* settings);\n\n#endif /*LODEPNG_COMPILE_ENCODER*/\n#endif /*LODEPNG_COMPILE_ZLIB*/\n\n#ifdef LODEPNG_COMPILE_DISK\n/*\nLoad a file from disk into buffer. The function allocates the out buffer, and\nafter usage you should free it.\nout: output parameter, contains pointer to loaded buffer.\noutsize: output parameter, size of the allocated out buffer\nfilename: the path to the file to load\nreturn value: error code (0 means ok)\n*/\nunsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename);\n\n/*\nSave a file from buffer to disk. Warning, if it exists, this function overwrites\nthe file without warning!\nbuffer: the buffer to write\nbuffersize: size of the buffer to write\nfilename: the path to the file to save to\nreturn value: error code (0 means ok)\n*/\nunsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);\n#endif /*LODEPNG_COMPILE_DISK*/\n\n#ifdef LODEPNG_COMPILE_CPP\n/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */\nnamespace lodepng {\n#ifdef LODEPNG_COMPILE_PNG\nclass State : public LodePNGState {\n  public:\n    State();\n    State(const State& other);\n    ~State();\n    State& operator=(const State& other);\n};\n\n#ifdef LODEPNG_COMPILE_DECODER\n/* Same as other lodepng::decode, but using a State for more settings and information. */\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                State& state,\n                const unsigned char* in, size_t insize);\nunsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,\n                State& state,\n                const std::vector<unsigned char>& in);\n#endif /*LODEPNG_COMPILE_DECODER*/\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/* Same as other lodepng::encode, but using a State for more settings and information. */\nunsigned encode(std::vector<unsigned char>& out,\n                const unsigned char* in, unsigned w, unsigned h,\n                State& state);\nunsigned encode(std::vector<unsigned char>& out,\n                const std::vector<unsigned char>& in, unsigned w, unsigned h,\n                State& state);\n#endif /*LODEPNG_COMPILE_ENCODER*/\n\n#ifdef LODEPNG_COMPILE_DISK\n/*\nLoad a file from disk into an std::vector.\nreturn value: error code (0 means ok)\n*/\nunsigned load_file(std::vector<unsigned char>& buffer, const std::string& filename);\n\n/*\nSave the binary data in an std::vector to a file on disk. The file is overwritten\nwithout warning.\n*/\nunsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename);\n#endif /* LODEPNG_COMPILE_DISK */\n#endif /* LODEPNG_COMPILE_PNG */\n\n#ifdef LODEPNG_COMPILE_ZLIB\n#ifdef LODEPNG_COMPILE_DECODER\n/* Zlib-decompress an unsigned char buffer */\nunsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,\n                    const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);\n\n/* Zlib-decompress an std::vector */\nunsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,\n                    const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);\n#endif /* LODEPNG_COMPILE_DECODER */\n\n#ifdef LODEPNG_COMPILE_ENCODER\n/* Zlib-compress an unsigned char buffer */\nunsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,\n                  const LodePNGCompressSettings& settings = lodepng_default_compress_settings);\n\n/* Zlib-compress an std::vector */\nunsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,\n                  const LodePNGCompressSettings& settings = lodepng_default_compress_settings);\n#endif /* LODEPNG_COMPILE_ENCODER */\n#endif /* LODEPNG_COMPILE_ZLIB */\n} /* namespace lodepng */\n#endif /*LODEPNG_COMPILE_CPP*/\n\n/*\nTODO:\n[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often\n[.] check compatibility with various compilers  - done but needs to be redone for every newer version\n[X] converting color to 16-bit per channel types\n[X] support color profile chunk types (but never let them touch RGB values by default)\n[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST)\n[ ] make sure encoder generates no chunks with size > (2^31)-1\n[ ] partial decoding (stream processing)\n[X] let the \"isFullyOpaque\" function check color keys and transparent palettes too\n[X] better name for the variables \"codes\", \"codesD\", \"codelengthcodes\", \"clcl\" and \"lldl\"\n[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58)\n[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ...\n[ ] error messages with line numbers (and version)\n[ ] errors in state instead of as return code?\n[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk\n[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes\n[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ...\n[ ] allow user to give data (void*) to custom allocator\n[X] provide alternatives for C library functions not present on some platforms (memcpy, ...)\n*/\n\n#endif /*LODEPNG_H inclusion guard*/\n\n/*\nLodePNG Documentation\n---------------------\n\n0. table of contents\n--------------------\n\n  1. about\n   1.1. supported features\n   1.2. features not supported\n  2. C and C++ version\n  3. security\n  4. decoding\n  5. encoding\n  6. color conversions\n    6.1. PNG color types\n    6.2. color conversions\n    6.3. padding bits\n    6.4. A note about 16-bits per channel and endianness\n  7. error values\n  8. chunks and PNG editing\n  9. compiler support\n  10. examples\n   10.1. decoder C++ example\n   10.2. decoder C example\n  11. state settings reference\n  12. changes\n  13. contact information\n\n\n1. about\n--------\n\nPNG is a file format to store raster images losslessly with good compression,\nsupporting different color types and alpha channel.\n\nLodePNG is a PNG codec according to the Portable Network Graphics (PNG)\nSpecification (Second Edition) - W3C Recommendation 10 November 2003.\n\nThe specifications used are:\n\n*) Portable Network Graphics (PNG) Specification (Second Edition):\n     http://www.w3.org/TR/2003/REC-PNG-20031110\n*) RFC 1950 ZLIB Compressed Data Format version 3.3:\n     http://www.gzip.org/zlib/rfc-zlib.html\n*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3:\n     http://www.gzip.org/zlib/rfc-deflate.html\n\nThe most recent version of LodePNG can currently be found at\nhttp://lodev.org/lodepng/\n\nLodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds\nextra functionality.\n\nLodePNG exists out of two files:\n-lodepng.h: the header file for both C and C++\n-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage\n\nIf you want to start using LodePNG right away without reading this doc, get the\nexamples from the LodePNG website to see how to use it in code, or check the\nsmaller examples in chapter 13 here.\n\nLodePNG is simple but only supports the basic requirements. To achieve\nsimplicity, the following design choices were made: There are no dependencies\non any external library. There are functions to decode and encode a PNG with\na single function call, and extended versions of these functions taking a\nLodePNGState struct allowing to specify or get more information. By default\nthe colors of the raw image are always RGB or RGBA, no matter what color type\nthe PNG file uses. To read and write files, there are simple functions to\nconvert the files to/from buffers in memory.\n\nThis all makes LodePNG suitable for loading textures in games, demos and small\nprograms, ... It's less suitable for full fledged image editors, loading PNGs\nover network (it requires all the image data to be available before decoding can\nbegin), life-critical systems, ...\n\n1.1. supported features\n-----------------------\n\nThe following features are supported by the decoder:\n\n*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image,\n   or the same color type as the PNG\n*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image\n*) Adam7 interlace and deinterlace for any color type\n*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk\n*) support for alpha channels, including RGBA color model, translucent palettes and color keying\n*) zlib decompression (inflate)\n*) zlib compression (deflate)\n*) CRC32 and ADLER32 checksums\n*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only,\n   plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system.\n*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks.\n*) the following chunks are supported by both encoder and decoder:\n    IHDR: header information\n    PLTE: color palette\n    IDAT: pixel data\n    IEND: the final chunk\n    tRNS: transparency for palettized images\n    tEXt: textual information\n    zTXt: compressed textual information\n    iTXt: international textual information\n    bKGD: suggested background color\n    pHYs: physical dimensions\n    tIME: modification time\n    cHRM: RGB chromaticities\n    gAMA: RGB gamma correction\n    iCCP: ICC color profile\n    sRGB: rendering intent\n\n1.2. features not supported\n---------------------------\n\nThe following features are _not_ supported:\n\n*) some features needed to make a conformant PNG-Editor might be still missing.\n*) partial loading/stream processing. All data must be available and is processed in one call.\n*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG:\n    sBIT\n    hIST\n    sPLT\n\n\n2. C and C++ version\n--------------------\n\nThe C version uses buffers allocated with alloc that you need to free()\nyourself. You need to use init and cleanup functions for each struct whenever\nusing a struct from the C version to avoid exploits and memory leaks.\n\nThe C++ version has extra functions with std::vectors in the interface and the\nlodepng::State class which is a LodePNGState with constructor and destructor.\n\nThese files work without modification for both C and C++ compilers because all\nthe additional C++ code is in \"#ifdef __cplusplus\" blocks that make C-compilers\nignore it, and the C code is made to compile both with strict ISO C90 and C++.\n\nTo use the C++ version, you need to rename the source file to lodepng.cpp\n(instead of lodepng.c), and compile it with a C++ compiler.\n\nTo use the C version, you need to rename the source file to lodepng.c (instead\nof lodepng.cpp), and compile it with a C compiler.\n\n\n3. Security\n-----------\n\nEven if carefully designed, it's always possible that LodePNG contains possible\nexploits. If you discover one, please let me know, and it will be fixed.\n\nWhen using LodePNG, care has to be taken with the C version of LodePNG, as well\nas the C-style structs when working with C++. The following conventions are used\nfor all C-style structs:\n\n-if a struct has a corresponding init function, always call the init function when making a new one\n-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks\n-if a struct has a corresponding copy function, use the copy function instead of \"=\".\n The destination must also be inited already.\n\n\n4. Decoding\n-----------\n\nDecoding converts a PNG compressed image to a raw pixel buffer.\n\nMost documentation on using the decoder is at its declarations in the header\nabove. For C, simple decoding can be done with functions such as\nlodepng_decode32, and more advanced decoding can be done with the struct\nLodePNGState and lodepng_decode. For C++, all decoding can be done with the\nvarious lodepng::decode functions, and lodepng::State can be used for advanced\nfeatures.\n\nWhen using the LodePNGState, it uses the following fields for decoding:\n*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here\n*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get\n*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use\n\nLodePNGInfo info_png\n--------------------\n\nAfter decoding, this contains extra information of the PNG image, except the actual\npixels, width and height because these are already gotten directly from the decoder\nfunctions.\n\nIt contains for example the original color type of the PNG image, text comments,\nsuggested background color, etc... More details about the LodePNGInfo struct are\nat its declaration documentation.\n\nLodePNGColorMode info_raw\n-------------------------\n\nWhen decoding, here you can specify which color type you want\nthe resulting raw image to be. If this is different from the colortype of the\nPNG, then the decoder will automatically convert the result. This conversion\nalways works, except if you want it to convert a color PNG to grayscale or to\na palette with missing colors.\n\nBy default, 32-bit color is used for the result.\n\nLodePNGDecoderSettings decoder\n------------------------------\n\nThe settings can be used to ignore the errors created by invalid CRC and Adler32\nchunks, and to disable the decoding of tEXt chunks.\n\nThere's also a setting color_convert, true by default. If false, no conversion\nis done, the resulting data will be as it was in the PNG (after decompression)\nand you'll have to puzzle the colors of the pixels together yourself using the\ncolor type information in the LodePNGInfo.\n\n\n5. Encoding\n-----------\n\nEncoding converts a raw pixel buffer to a PNG compressed image.\n\nMost documentation on using the encoder is at its declarations in the header\nabove. For C, simple encoding can be done with functions such as\nlodepng_encode32, and more advanced decoding can be done with the struct\nLodePNGState and lodepng_encode. For C++, all encoding can be done with the\nvarious lodepng::encode functions, and lodepng::State can be used for advanced\nfeatures.\n\nLike the decoder, the encoder can also give errors. However it gives less errors\nsince the encoder input is trusted, the decoder input (a PNG image that could\nbe forged by anyone) is not trusted.\n\nWhen using the LodePNGState, it uses the following fields for encoding:\n*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be.\n*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has\n*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use\n\nLodePNGInfo info_png\n--------------------\n\nWhen encoding, you use this the opposite way as when decoding: for encoding,\nyou fill in the values you want the PNG to have before encoding. By default it's\nnot needed to specify a color type for the PNG since it's automatically chosen,\nbut it's possible to choose it yourself given the right settings.\n\nThe encoder will not always exactly match the LodePNGInfo struct you give,\nit tries as close as possible. Some things are ignored by the encoder. The\nencoder uses, for example, the following settings from it when applicable:\ncolortype and bitdepth, text chunks, time chunk, the color key, the palette, the\nbackground color, the interlace method, unknown chunks, ...\n\nWhen encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk.\nIf the palette contains any colors for which the alpha channel is not 255 (so\nthere are translucent colors in the palette), it'll add a tRNS chunk.\n\nLodePNGColorMode info_raw\n-------------------------\n\nYou specify the color type of the raw image that you give to the input here,\nincluding a possible transparent color key and palette you happen to be using in\nyour raw image data.\n\nBy default, 32-bit color is assumed, meaning your input has to be in RGBA\nformat with 4 bytes (unsigned chars) per pixel.\n\nLodePNGEncoderSettings encoder\n------------------------------\n\nThe following settings are supported (some are in sub-structs):\n*) auto_convert: when this option is enabled, the encoder will\nautomatically choose the smallest possible color mode (including color key) that\ncan encode the colors of all pixels without information loss.\n*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree,\n   2 = dynamic huffman tree (best compression). Should be 2 for proper\n   compression.\n*) use_lz77: whether or not to use LZ77 for compressed block types. Should be\n   true for proper compression.\n*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value\n   2048 by default, but can be set to 32768 for better, but slow, compression.\n*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE\n   chunk if force_palette is true. This can used as suggested palette to convert\n   to by viewers that don't support more than 256 colors (if those still exist)\n*) add_id: add text chunk \"Encoder: LodePNG <version>\" to the image.\n*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks.\n  zTXt chunks use zlib compression on the text. This gives a smaller result on\n  large texts but a larger result on small texts (such as a single program name).\n  It's all tEXt or all zTXt though, there's no separate setting per text yet.\n\n\n6. color conversions\n--------------------\n\nAn important thing to note about LodePNG, is that the color type of the PNG, and\nthe color type of the raw image, are completely independent. By default, when\nyou decode a PNG, you get the result as a raw image in the color type you want,\nno matter whether the PNG was encoded with a palette, grayscale or RGBA color.\nAnd if you encode an image, by default LodePNG will automatically choose the PNG\ncolor type that gives good compression based on the values of colors and amount\nof colors in the image. It can be configured to let you control it instead as\nwell, though.\n\nTo be able to do this, LodePNG does conversions from one color mode to another.\nIt can convert from almost any color type to any other color type, except the\nfollowing conversions: RGB to grayscale is not supported, and converting to a\npalette when the palette doesn't have a required color is not supported. This is\nnot supported on purpose: this is information loss which requires a color\nreduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray\nis easy, but there are multiple ways if you want to give some channels more\nweight).\n\nBy default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB\ncolor, no matter what color type the PNG has. And by default when encoding,\nLodePNG automatically picks the best color model for the output PNG, and expects\nthe input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control\nthe color format of the images yourself, you can skip this chapter.\n\n6.1. PNG color types\n--------------------\n\nA PNG image can have many color types, ranging from 1-bit color to 64-bit color,\nas well as palettized color modes. After the zlib decompression and unfiltering\nin the PNG image is done, the raw pixel data will have that color type and thus\na certain amount of bits per pixel. If you want the output raw image after\ndecoding to have another color type, a conversion is done by LodePNG.\n\nThe PNG specification gives the following color types:\n\n0: grayscale, bit depths 1, 2, 4, 8, 16\n2: RGB, bit depths 8 and 16\n3: palette, bit depths 1, 2, 4 and 8\n4: grayscale with alpha, bit depths 8 and 16\n6: RGBA, bit depths 8 and 16\n\nBit depth is the amount of bits per pixel per color channel. So the total amount\nof bits per pixel is: amount of channels * bitdepth.\n\n6.2. color conversions\n----------------------\n\nAs explained in the sections about the encoder and decoder, you can specify\ncolor types and bit depths in info_png and info_raw to change the default\nbehaviour.\n\nIf, when decoding, you want the raw image to be something else than the default,\nyou need to set the color type and bit depth you want in the LodePNGColorMode,\nor the parameters colortype and bitdepth of the simple decoding function.\n\nIf, when encoding, you use another color type than the default in the raw input\nimage, you need to specify its color type and bit depth in the LodePNGColorMode\nof the raw image, or use the parameters colortype and bitdepth of the simple\nencoding function.\n\nIf, when encoding, you don't want LodePNG to choose the output PNG color type\nbut control it yourself, you need to set auto_convert in the encoder settings\nto false, and specify the color type you want in the LodePNGInfo of the\nencoder (including palette: it can generate a palette if auto_convert is true,\notherwise not).\n\nIf the input and output color type differ (whether user chosen or auto chosen),\nLodePNG will do a color conversion, which follows the rules below, and may\nsometimes result in an error.\n\nTo avoid some confusion:\n-the decoder converts from PNG to raw image\n-the encoder converts from raw image to PNG\n-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image\n-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG\n-when encoding, the color type in LodePNGInfo is ignored if auto_convert\n is enabled, it is automatically generated instead\n-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original\n PNG image, but it can be ignored since the raw image has the color type you requested instead\n-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion\n between the color types is done if the color types are supported. If it is not\n supported, an error is returned. If the types are the same, no conversion is done.\n-even though some conversions aren't supported, LodePNG supports loading PNGs from any\n colortype and saving PNGs to any colortype, sometimes it just requires preparing\n the raw image correctly before encoding.\n-both encoder and decoder use the same color converter.\n\nThe function lodepng_convert does the color conversion. It is available in the\ninterface but normally isn't needed since the encoder and decoder already call\nit.\n\nNon supported color conversions:\n-color to grayscale when non-gray pixels are present: no error is thrown, but\nthe result will look ugly because only the red channel is taken (it assumes all\nthree channels are the same in this case so ignores green and blue). The reason\nno error is given is to allow converting from three-channel grayscale images to\none-channel even if there are numerical imprecisions.\n-anything to palette when the palette does not have an exact match for a from-color\nin it: in this case an error is thrown\n\nSupported color conversions:\n-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA\n-any gray or gray+alpha, to gray or gray+alpha\n-anything to a palette, as long as the palette has the requested colors in it\n-removing alpha channel\n-higher to smaller bitdepth, and vice versa\n\nIf you want no color conversion to be done (e.g. for speed or control):\n-In the encoder, you can make it save a PNG with any color type by giving the\nraw color mode and LodePNGInfo the same color mode, and setting auto_convert to\nfalse.\n-In the decoder, you can make it store the pixel data in the same color type\nas the PNG has, by setting the color_convert setting to false. Settings in\ninfo_raw are then ignored.\n\n6.3. padding bits\n-----------------\n\nIn the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines\nhave a bit amount that isn't a multiple of 8, then padding bits are used so that each\nscanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output.\nThe raw input image you give to the encoder, and the raw output image you get from the decoder\nwill NOT have these padding bits, e.g. in the case of a 1-bit image with a width\nof 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte,\nnot the first bit of a new byte.\n\n6.4. A note about 16-bits per channel and endianness\n----------------------------------------------------\n\nLodePNG uses unsigned char arrays for 16-bit per channel colors too, just like\nfor any other color format. The 16-bit values are stored in big endian (most\nsignificant byte first) in these arrays. This is the opposite order of the\nlittle endian used by x86 CPU's.\n\nLodePNG always uses big endian because the PNG file format does so internally.\nConversions to other formats than PNG uses internally are not supported by\nLodePNG on purpose, there are myriads of formats, including endianness of 16-bit\ncolors, the order in which you store R, G, B and A, and so on. Supporting and\nconverting to/from all that is outside the scope of LodePNG.\n\nThis may mean that, depending on your use case, you may want to convert the big\nendian output of LodePNG to little endian with a for loop. This is certainly not\nalways needed, many applications and libraries support big endian 16-bit colors\nanyway, but it means you cannot simply cast the unsigned char* buffer to an\nunsigned short* buffer on x86 CPUs.\n\n\n7. error values\n---------------\n\nAll functions in LodePNG that return an error code, return 0 if everything went\nOK, or a non-zero code if there was an error.\n\nThe meaning of the LodePNG error values can be retrieved with the function\nlodepng_error_text: given the numerical error code, it returns a description\nof the error in English as a string.\n\nCheck the implementation of lodepng_error_text to see the meaning of each code.\n\n\n8. chunks and PNG editing\n-------------------------\n\nIf you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG\neditor that should follow the rules about handling of unknown chunks, or if your\nprogram is able to read other types of chunks than the ones handled by LodePNG,\nthen that's possible with the chunk functions of LodePNG.\n\nA PNG chunk has the following layout:\n\n4 bytes length\n4 bytes type name\nlength bytes data\n4 bytes CRC\n\n8.1. iterating through chunks\n-----------------------------\n\nIf you have a buffer containing the PNG image data, then the first chunk (the\nIHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the\nsignature of the PNG and are not part of a chunk. But if you start at byte 8\nthen you have a chunk, and can check the following things of it.\n\nNOTE: none of these functions check for memory buffer boundaries. To avoid\nexploits, always make sure the buffer contains all the data of the chunks.\nWhen using lodepng_chunk_next, make sure the returned value is within the\nallocated memory.\n\nunsigned lodepng_chunk_length(const unsigned char* chunk):\n\nGet the length of the chunk's data. The total chunk length is this length + 12.\n\nvoid lodepng_chunk_type(char type[5], const unsigned char* chunk):\nunsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type):\n\nGet the type of the chunk or compare if it's a certain type\n\nunsigned char lodepng_chunk_critical(const unsigned char* chunk):\nunsigned char lodepng_chunk_private(const unsigned char* chunk):\nunsigned char lodepng_chunk_safetocopy(const unsigned char* chunk):\n\nCheck if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are).\nCheck if the chunk is private (public chunks are part of the standard, private ones not).\nCheck if the chunk is safe to copy. If it's not, then, when modifying data in a critical\nchunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your\nprogram doesn't handle that type of unknown chunk.\n\nunsigned char* lodepng_chunk_data(unsigned char* chunk):\nconst unsigned char* lodepng_chunk_data_const(const unsigned char* chunk):\n\nGet a pointer to the start of the data of the chunk.\n\nunsigned lodepng_chunk_check_crc(const unsigned char* chunk):\nvoid lodepng_chunk_generate_crc(unsigned char* chunk):\n\nCheck if the crc is correct or generate a correct one.\n\nunsigned char* lodepng_chunk_next(unsigned char* chunk):\nconst unsigned char* lodepng_chunk_next_const(const unsigned char* chunk):\n\nIterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these\nfunctions do no boundary checking of the allocated data whatsoever, so make sure there is enough\ndata available in the buffer to be able to go to the next chunk.\n\nunsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk):\nunsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length,\n                              const char* type, const unsigned char* data):\n\nThese functions are used to create new chunks that are appended to the data in *out that has\nlength *outsize. The append function appends an existing chunk to the new data. The create\nfunction creates a new chunk with the given parameters and appends it. Type is the 4-letter\nname of the chunk.\n\n8.2. chunks in info_png\n-----------------------\n\nThe LodePNGInfo struct contains fields with the unknown chunk in it. It has 3\nbuffers (each with size) to contain 3 types of unknown chunks:\nthe ones that come before the PLTE chunk, the ones that come between the PLTE\nand the IDAT chunks, and the ones that come after the IDAT chunks.\nIt's necessary to make the distinction between these 3 cases because the PNG\nstandard forces to keep the ordering of unknown chunks compared to the critical\nchunks, but does not force any other ordering rules.\n\ninfo_png.unknown_chunks_data[0] is the chunks before PLTE\ninfo_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT\ninfo_png.unknown_chunks_data[2] is the chunks after IDAT\n\nThe chunks in these 3 buffers can be iterated through and read by using the same\nway described in the previous subchapter.\n\nWhen using the decoder to decode a PNG, you can make it store all unknown chunks\nif you set the option settings.remember_unknown_chunks to 1. By default, this\noption is off (0).\n\nThe encoder will always encode unknown chunks that are stored in the info_png.\nIf you need it to add a particular chunk that isn't known by LodePNG, you can\nuse lodepng_chunk_append or lodepng_chunk_create to the chunk data in\ninfo_png.unknown_chunks_data[x].\n\nChunks that are known by LodePNG should not be added in that way. E.g. to make\nLodePNG add a bKGD chunk, set background_defined to true and add the correct\nparameters there instead.\n\n\n9. compiler support\n-------------------\n\nNo libraries other than the current standard C library are needed to compile\nLodePNG. For the C++ version, only the standard C++ library is needed on top.\nAdd the files lodepng.c(pp) and lodepng.h to your project, include\nlodepng.h where needed, and your program can read/write PNG files.\n\nIt is compatible with C90 and up, and C++03 and up.\n\nIf performance is important, use optimization when compiling! For both the\nencoder and decoder, this makes a large difference.\n\nMake sure that LodePNG is compiled with the same compiler of the same version\nand with the same settings as the rest of the program, or the interfaces with\nstd::vectors and std::strings in C++ can be incompatible.\n\nCHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets.\n\n*) gcc and g++\n\nLodePNG is developed in gcc so this compiler is natively supported. It gives no\nwarnings with compiler options \"-Wall -Wextra -pedantic -ansi\", with gcc and g++\nversion 4.7.1 on Linux, 32-bit and 64-bit.\n\n*) Clang\n\nFully supported and warning-free.\n\n*) Mingw\n\nThe Mingw compiler (a port of gcc for Windows) should be fully supported by\nLodePNG.\n\n*) Visual Studio and Visual C++ Express Edition\n\nLodePNG should be warning-free with warning level W4. Two warnings were disabled\nwith pragmas though: warning 4244 about implicit conversions, and warning 4996\nwhere it wants to use a non-standard function fopen_s instead of the standard C\nfopen.\n\nVisual Studio may want \"stdafx.h\" files to be included in each source file and\ngive an error \"unexpected end of file while looking for precompiled header\".\nThis is not standard C++ and will not be added to the stock LodePNG. You can\ndisable it for lodepng.cpp only by right clicking it, Properties, C/C++,\nPrecompiled Headers, and set it to Not Using Precompiled Headers there.\n\nNOTE: Modern versions of VS should be fully supported, but old versions, e.g.\nVS6, are not guaranteed to work.\n\n*) Compilers on Macintosh\n\nLodePNG has been reported to work both with gcc and LLVM for Macintosh, both for\nC and C++.\n\n*) Other Compilers\n\nIf you encounter problems on any compilers, feel free to let me know and I may\ntry to fix it if the compiler is modern and standards compliant.\n\n\n10. examples\n------------\n\nThis decoder example shows the most basic usage of LodePNG. More complex\nexamples can be found on the LodePNG website.\n\n10.1. decoder C++ example\n-------------------------\n\n#include \"lodepng.h\"\n#include <iostream>\n\nint main(int argc, char *argv[]) {\n  const char* filename = argc > 1 ? argv[1] : \"test.png\";\n\n  //load and decode\n  std::vector<unsigned char> image;\n  unsigned width, height;\n  unsigned error = lodepng::decode(image, width, height, filename);\n\n  //if there's an error, display it\n  if(error) std::cout << \"decoder error \" << error << \": \" << lodepng_error_text(error) << std::endl;\n\n  //the pixels are now in the vector \"image\", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...\n}\n\n10.2. decoder C example\n-----------------------\n\n#include \"lodepng.h\"\n\nint main(int argc, char *argv[]) {\n  unsigned error;\n  unsigned char* image;\n  size_t width, height;\n  const char* filename = argc > 1 ? argv[1] : \"test.png\";\n\n  error = lodepng_decode32_file(&image, &width, &height, filename);\n\n  if(error) printf(\"decoder error %u: %s\\n\", error, lodepng_error_text(error));\n\n  / * use image here * /\n\n  free(image);\n  return 0;\n}\n\n11. state settings reference\n----------------------------\n\nA quick reference of some settings to set on the LodePNGState\n\nFor decoding:\n\nstate.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums\nstate.decoder.zlibsettings.custom_...: use custom inflate function\nstate.decoder.ignore_crc: ignore CRC checksums\nstate.decoder.ignore_critical: ignore unknown critical chunks\nstate.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors\nstate.decoder.color_convert: convert internal PNG color to chosen one\nstate.decoder.read_text_chunks: whether to read in text metadata chunks\nstate.decoder.remember_unknown_chunks: whether to read in unknown chunks\nstate.info_raw.colortype: desired color type for decoded image\nstate.info_raw.bitdepth: desired bit depth for decoded image\nstate.info_raw....: more color settings, see struct LodePNGColorMode\nstate.info_png....: no settings for decoder but ouput, see struct LodePNGInfo\n\nFor encoding:\n\nstate.encoder.zlibsettings.btype: disable compression by setting it to 0\nstate.encoder.zlibsettings.use_lz77: use LZ77 in compression\nstate.encoder.zlibsettings.windowsize: tweak LZ77 windowsize\nstate.encoder.zlibsettings.minmatch: tweak min LZ77 length to match\nstate.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching\nstate.encoder.zlibsettings.lazymatching: try one more LZ77 matching\nstate.encoder.zlibsettings.custom_...: use custom deflate function\nstate.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png\nstate.encoder.filter_palette_zero: PNG filter strategy for palette\nstate.encoder.filter_strategy: PNG filter strategy to encode with\nstate.encoder.force_palette: add palette even if not encoding to one\nstate.encoder.add_id: add LodePNG identifier and version as a text chunk\nstate.encoder.text_compression: use compressed text chunks for metadata\nstate.info_raw.colortype: color type of raw input image you provide\nstate.info_raw.bitdepth: bit depth of raw input image you provide\nstate.info_raw: more color settings, see struct LodePNGColorMode\nstate.info_png.color.colortype: desired color type if auto_convert is false\nstate.info_png.color.bitdepth: desired bit depth if auto_convert is false\nstate.info_png.color....: more color settings, see struct LodePNGColorMode\nstate.info_png....: more PNG related settings, see struct LodePNGInfo\n\n\n12. changes\n-----------\n\nThe version number of LodePNG is the date of the change given in the format\nyyyymmdd.\n\nSome changes aren't backwards compatible. Those are indicated with a (!)\nsymbol.\n\nNot all changes are listed here, the commit history in github lists more:\nhttps://github.com/lvandeve/lodepng\n\n*) 06 mar 2020: simplified some of the dynamic memory allocations.\n*) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct\n   overflow checks.\n*) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables.\n*) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette\n   if gray ICC profile) and non-ICC LodePNGColorProfile renamed to\n   LodePNGColorStats.\n*) 30 dec 2018: code style changes only: removed newlines before opening braces.\n*) 10 sep 2018: added way to inspect metadata chunks without full decoding.\n*) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use\n   palette index in case of palette.\n*) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This\n   change is backwards compatible unless you relied on unknown_chunks for those.\n*) 11 jun 2018: less restrictive check for pixel size integer overflow\n*) 14 jan 2018: allow optionally ignoring a few more recoverable errors\n*) 17 sep 2017: fix memory leak for some encoder input error cases\n*) 27 nov 2016: grey+alpha auto color model detection bugfix\n*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort).\n*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within\n   the limits of pure C90).\n*) 08 dec 2015: Made load_file function return error if file can't be opened.\n*) 24 okt 2015: Bugfix with decoding to palette output.\n*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding.\n*) 24 aug 2014: Moved to github\n*) 23 aug 2014: Reduced needless memory usage of decoder.\n*) 28 jun 2014: Removed fix_png setting, always support palette OOB for\n    simplicity. Made ColorProfile public.\n*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization.\n*) 22 dec 2013: Power of two windowsize required for optimization.\n*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key.\n*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png).\n*) 11 mar 2013: (!) Bugfix with custom free. Changed from \"my\" to \"lodepng_\"\n    prefix for the custom allocators and made it possible with a new #define to\n    use custom ones in your project without needing to change lodepng's code.\n*) 28 jan 2013: Bugfix with color key.\n*) 27 okt 2012: Tweaks in text chunk keyword length error handling.\n*) 8 okt 2012: (!) Added new filter strategy (entropy) and new auto color mode.\n    (no palette). Better deflate tree encoding. New compression tweak settings.\n    Faster color conversions while decoding. Some internal cleanups.\n*) 23 sep 2012: Reduced warnings in Visual Studio a little bit.\n*) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions\n    and made it work with function pointers instead.\n*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc\n    and free functions and toggle #defines from compiler flags. Small fixes.\n*) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible.\n*) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed\n    redundant C++ codec classes. Reduced amount of structs. Everything changed,\n    but it is cleaner now imho and functionality remains the same. Also fixed\n    several bugs and shrunk the implementation code. Made new samples.\n*) 6 nov 2011: (!) By default, the encoder now automatically chooses the best\n    PNG color model and bit depth, based on the amount and type of colors of the\n    raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color.\n*) 9 okt 2011: simpler hash chain implementation for the encoder.\n*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching.\n*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking.\n    A bug with the PNG filtertype heuristic was fixed, so that it chooses much\n    better ones (it's quite significant). A setting to do an experimental, slow,\n    brute force search for PNG filter types is added.\n*) 17 aug 2011: (!) changed some C zlib related function names.\n*) 16 aug 2011: made the code less wide (max 120 characters per line).\n*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors.\n*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled.\n*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman\n    to optimize long sequences of zeros.\n*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and\n    LodePNG_InfoColor_canHaveAlpha functions for convenience.\n*) 7 nov 2010: added LodePNG_error_text function to get error code description.\n*) 30 okt 2010: made decoding slightly faster\n*) 26 okt 2010: (!) changed some C function and struct names (more consistent).\n     Reorganized the documentation and the declaration order in the header.\n*) 08 aug 2010: only changed some comments and external samples.\n*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version.\n*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers.\n*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could\n    read by ignoring the problem but windows apps couldn't.\n*) 06 jun 2008: added more error checks for out of memory cases.\n*) 26 apr 2008: added a few more checks here and there to ensure more safety.\n*) 06 mar 2008: crash with encoding of strings fixed\n*) 02 feb 2008: support for international text chunks added (iTXt)\n*) 23 jan 2008: small cleanups, and #defines to divide code in sections\n*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor.\n*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder.\n*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added\n    Also various fixes, such as in the deflate and the padding bits code.\n*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved\n    filtering code of encoder.\n*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A\n    C++ wrapper around this provides an interface almost identical to before.\n    Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code\n    are together in these files but it works both for C and C++ compilers.\n*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks\n*) 30 aug 2007: bug fixed which makes this Borland C++ compatible\n*) 09 aug 2007: some VS2005 warnings removed again\n*) 21 jul 2007: deflate code placed in new namespace separate from zlib code\n*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images\n*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing\n    invalid std::vector element [0] fixed, and level 3 and 4 warnings removed\n*) 02 jun 2007: made the encoder add a tag with version by default\n*) 27 may 2007: zlib and png code separated (but still in the same file),\n    simple encoder/decoder functions added for more simple usage cases\n*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69),\n    moved some examples from here to lodepng_examples.cpp\n*) 12 may 2007: palette decoding bug fixed\n*) 24 apr 2007: changed the license from BSD to the zlib license\n*) 11 mar 2007: very simple addition: ability to encode bKGD chunks.\n*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding\n    palettized PNG images. Plus little interface change with palette and texts.\n*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes.\n    Fixed a bug where the end code of a block had length 0 in the Huffman tree.\n*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented\n    and supported by the encoder, resulting in smaller PNGs at the output.\n*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone.\n*) 24 jan 2007: gave encoder an error interface. Added color conversion from any\n    greyscale type to 8-bit greyscale with or without alpha.\n*) 21 jan 2007: (!) Totally changed the interface. It allows more color types\n    to convert to and is more uniform. See the manual for how it works now.\n*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days:\n    encode/decode custom tEXt chunks, separate classes for zlib & deflate, and\n    at last made the decoder give errors for incorrect Adler32 or Crc.\n*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel.\n*) 29 dec 2006: Added support for encoding images without alpha channel, and\n    cleaned out code as well as making certain parts faster.\n*) 28 dec 2006: Added \"Settings\" to the encoder.\n*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now.\n    Removed some code duplication in the decoder. Fixed little bug in an example.\n*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter.\n    Fixed a bug of the decoder with 16-bit per color.\n*) 15 okt 2006: Changed documentation structure\n*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the\n    given image buffer, however for now it's not compressed.\n*) 08 sep 2006: (!) Changed to interface with a Decoder class\n*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different\n    way. Renamed decodePNG to decodePNGGeneric.\n*) 29 jul 2006: (!) Changed the interface: image info is now returned as a\n    struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy.\n*) 28 jul 2006: Cleaned the code and added new error checks.\n    Corrected terminology \"deflate\" into \"inflate\".\n*) 23 jun 2006: Added SDL example in the documentation in the header, this\n    example allows easy debugging by displaying the PNG and its transparency.\n*) 22 jun 2006: (!) Changed way to obtain error value. Added\n    loadFile function for convenience. Made decodePNG32 faster.\n*) 21 jun 2006: (!) Changed type of info vector to unsigned.\n    Changed position of palette in info vector. Fixed an important bug that\n    happened on PNGs with an uncompressed block.\n*) 16 jun 2006: Internally changed unsigned into unsigned where\n    needed, and performed some optimizations.\n*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them\n    in LodePNG namespace. Changed the order of the parameters. Rewrote the\n    documentation in the header. Renamed files to lodepng.cpp and lodepng.h\n*) 22 apr 2006: Optimized and improved some code\n*) 07 sep 2005: (!) Changed to std::vector interface\n*) 12 aug 2005: Initial release (C++, decoder only)\n\n\n13. contact information\n-----------------------\n\nFeel free to contact me with suggestions, problems, comments, ... concerning\nLodePNG. If you encounter a PNG image that doesn't work properly with this\ndecoder, feel free to send it and I'll use it to find and fix the problem.\n\nMy email address is (puzzle the account and domain together with an @ symbol):\nDomain: gmail dot com.\nAccount: lode dot vandevenne.\n\n\nCopyright (c) 2005-2020 Lode Vandevenne\n*/\n"
  },
  {
    "path": "eidos/pcg_extras.hpp",
    "content": "/*\n * PCG Random Number Generation for C++\n *\n * Copyright 2014-2017 Melissa O'Neill <oneill@pcg-random.org>,\n *                     and the PCG Project contributors.\n *\n * SPDX-License-Identifier: (Apache-2.0 OR MIT)\n *\n * Licensed under the Apache License, Version 2.0 (provided in\n * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)\n * or under the MIT license (provided in LICENSE-MIT.txt and at\n * http://opensource.org/licenses/MIT), at your option. This file may not\n * be copied, modified, or distributed except according to those terms.\n *\n * Distributed on an \"AS IS\" BASIS, WITHOUT WARRANTY OF ANY KIND, either\n * express or implied.  See your chosen license for details.\n *\n * For additional information about the PCG random number generation scheme,\n * visit http://www.pcg-random.org/.\n */\n\n/*\n * This file provides support code that is useful for random-number generation\n * but not specific to the PCG generation scheme, including:\n *      - 128-bit int support for platforms where it isn't available natively\n *      - bit twiddling operations\n *      - I/O of 128-bit and 8-bit integers\n *      - Handling the evilness of SeedSeq\n *      - Support for efficiently producing random numbers less than a given\n *        bound\n */\n\n#ifndef PCG_EXTRAS_HPP_INCLUDED\n#define PCG_EXTRAS_HPP_INCLUDED 1\n\n#include <cinttypes>\n#include <cstddef>\n#include <cstdlib>\n#include <cstring>\n#include <cassert>\n#include <limits>\n#include <iostream>\n#include <type_traits>\n#include <utility>\n#include <locale>\n#include <iterator>\n\n#ifdef __GNUC__\n    #include <cxxabi.h>\n#endif\n\n/*\n * Abstractions for compiler-specific directives\n */\n\n#ifdef __GNUC__\n    #define PCG_NOINLINE __attribute__((noinline))\n#elif defined(_MSC_VER)\n    #define PCG_NOINLINE __declspec(noinline)\n    #pragma warning(disable:4127) // conditional expression is constant\n#else\n    #define PCG_NOINLINE\n#endif\n\n/*\n * Some members of the PCG library use 128-bit math.  When compiling on 64-bit\n * platforms, both GCC and Clang provide 128-bit integer types that are ideal\n * for the job.\n *\n * On 32-bit platforms (or with other compilers), we fall back to a C++\n * class that provides 128-bit unsigned integers instead.  It may seem\n * like we're reinventing the wheel here, because libraries already exist\n * that support large integers, but most existing libraries provide a very\n * generic multiprecision code, but here we're operating at a fixed size.\n * Also, most other libraries are fairly heavyweight.  So we use a direct\n * implementation.  Sadly, it's much slower than hand-coded assembly or\n * direct CPU support.\n *\n */\n#if __SIZEOF_INT128__ && !PCG_FORCE_EMULATED_128BIT_MATH\n    namespace pcg_extras {\n        typedef __uint128_t pcg128_t;\n    }\n    #define PCG_128BIT_CONSTANT(high,low) \\\n            ((pcg_extras::pcg128_t(high) << 64) + low)\n#else\n    #include \"pcg_uint128.hpp\"\n    namespace pcg_extras {\n        typedef pcg_extras::uint_x4<uint32_t,uint64_t> pcg128_t;\n    }\n    #define PCG_128BIT_CONSTANT(high,low) \\\n            pcg_extras::pcg128_t(high,low)\n    #define PCG_EMULATED_128BIT_MATH 1\n#endif\n\n\nnamespace pcg_extras {\n\n/*\n * We often need to represent a \"number of bits\".  When used normally, these\n * numbers are never greater than 128, so an unsigned char is plenty.\n * If you're using a nonstandard generator of a larger size, you can set\n * PCG_BITCOUNT_T to have it define it as a larger size.  (Some compilers\n * might produce faster code if you set it to an unsigned int.)\n */\n\n#ifndef PCG_BITCOUNT_T\n    typedef uint8_t bitcount_t;\n#else\n    typedef PCG_BITCOUNT_T bitcount_t;\n#endif\n\n/*\n * C++ requires us to be able to serialize RNG state by printing or reading\n * it from a stream.  Because we use 128-bit ints, we also need to be able\n * ot print them, so here is code to do so.\n *\n * This code provides enough functionality to print 128-bit ints in decimal\n * and zero-padded in hex.  It's not a full-featured implementation.\n */\n\ntemplate <typename CharT, typename Traits>\nstd::basic_ostream<CharT,Traits>&\noperator<<(std::basic_ostream<CharT,Traits>& out, pcg128_t value)\n{\n    auto desired_base = out.flags() & out.basefield;\n    bool want_hex = desired_base == out.hex;\n\n    if (want_hex) {\n        uint64_t highpart = uint64_t(value >> 64);\n        uint64_t lowpart  = uint64_t(value);\n        auto desired_width = out.width();\n        if (desired_width > 16) {\n            out.width(desired_width - 16);\n        }\n        if (highpart != 0 || desired_width > 16)\n            out << highpart;\n        CharT oldfill = '\\0';\n        if (highpart != 0) {\n            out.width(16);\n            oldfill = out.fill('0');\n        }\n        auto oldflags = out.setf(decltype(desired_base){}, out.showbase);\n        out << lowpart;\n        out.setf(oldflags);\n        if (highpart != 0) {\n            out.fill(oldfill);\n        }\n        return out;\n    }\n    constexpr size_t MAX_CHARS_128BIT = 40;\n\n    char buffer[MAX_CHARS_128BIT];\n    char* pos = buffer+sizeof(buffer);\n    *(--pos) = '\\0';\n    constexpr auto BASE = pcg128_t(10ULL);\n    do {\n        auto div = value / BASE;\n        auto mod = uint32_t(value - (div * BASE));\n        *(--pos) = '0' + char(mod);\n        value = div;\n    } while(value != pcg128_t(0ULL));\n    return out << pos;\n}\n\ntemplate <typename CharT, typename Traits>\nstd::basic_istream<CharT,Traits>&\noperator>>(std::basic_istream<CharT,Traits>& in, pcg128_t& value)\n{\n    typename std::basic_istream<CharT,Traits>::sentry s(in);\n\n    if (!s)\n         return in;\n\n    constexpr auto BASE = pcg128_t(10ULL);\n    pcg128_t current(0ULL);\n    bool did_nothing = true;\n    bool overflow = false;\n    for(;;) {\n        CharT wide_ch = in.get();\n        if (!in.good()) {\n            in.clear(std::ios::eofbit);\n            break;\n        }\n        auto ch = in.narrow(wide_ch, '\\0');\n        if (ch < '0' || ch > '9') {\n            in.unget();\n            break;\n        }\n        did_nothing = false;\n        pcg128_t digit(uint32_t(ch - '0'));\n        pcg128_t timesbase = current*BASE;\n        overflow = overflow || timesbase < current;\n        current = timesbase + digit;\n        overflow = overflow || current < digit;\n    }\n\n    if (did_nothing || overflow) {\n        in.setstate(std::ios::failbit);\n        if (overflow)\n            current = ~pcg128_t(0ULL);\n    }\n\n    value = current;\n\n    return in;\n}\n\n/*\n * Likewise, if people use tiny rngs, we'll be serializing uint8_t.\n * If we just used the provided IO operators, they'd read/write chars,\n * not ints, so we need to define our own.  We *can* redefine this operator\n * here because we're in our own namespace.\n */\n\ntemplate <typename CharT, typename Traits>\nstd::basic_ostream<CharT,Traits>&\noperator<<(std::basic_ostream<CharT,Traits>&out, uint8_t value)\n{\n    return out << uint32_t(value);\n}\n\ntemplate <typename CharT, typename Traits>\nstd::basic_istream<CharT,Traits>&\noperator>>(std::basic_istream<CharT,Traits>& in, uint8_t& target)\n{\n    uint32_t value = 0xdecea5edU;\n    in >> value;\n    if (!in && value == 0xdecea5edU)\n        return in;\n    if (value > uint8_t(~0)) {\n        in.setstate(std::ios::failbit);\n        value = ~0U;\n    }\n    target = uint8_t(value);\n    return in;\n}\n\n/* Unfortunately, the above functions don't get found in preference to the\n * built in ones, so we create some more specific overloads that will.\n * Ugh.\n */\n\ninline std::ostream& operator<<(std::ostream& out, uint8_t value)\n{\n    return pcg_extras::operator<< <char>(out, value);\n}\n\ninline std::istream& operator>>(std::istream& in, uint8_t& value)\n{\n    return pcg_extras::operator>> <char>(in, value);\n}\n\n\n\n/*\n * Useful bitwise operations.\n */\n\n/*\n * XorShifts are invertable, but they are someting of a pain to invert.\n * This function backs them out.  It's used by the whacky \"inside out\"\n * generator defined later.\n */\n\ntemplate <typename itype>\ninline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift)\n{\n    do {\n        x ^= x >> shift;\n        shift *= 2u;\n    } while(shift < bits);\n    return x;\n}\n\n/*\n * Rotate left and right.\n *\n * In ideal world, compilers would spot idiomatic rotate code and convert it\n * to a rotate instruction.  Of course, opinions vary on what the correct\n * idiom is and how to spot it.  For clang, sometimes it generates better\n * (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM.\n */\n\ntemplate <typename itype>\ninline itype rotl(itype value, bitcount_t rot)\n{\n    constexpr bitcount_t bits = sizeof(itype) * 8;\n    constexpr bitcount_t mask = bits - 1;\n#if PCG_USE_ZEROCHECK_ROTATE_IDIOM\n    return rot ? (value << rot) | (value >> (bits - rot)) : value;\n#else\n    return (value << rot) | (value >> ((- rot) & mask));\n#endif\n}\n\ntemplate <typename itype>\ninline itype rotr(itype value, bitcount_t rot)\n{\n    constexpr bitcount_t bits = sizeof(itype) * 8;\n    constexpr bitcount_t mask = bits - 1;\n#if PCG_USE_ZEROCHECK_ROTATE_IDIOM\n    return rot ? (value >> rot) | (value << (bits - rot)) : value;\n#else\n    return (value >> rot) | (value << ((- rot) & mask));\n#endif\n}\n\n/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes\n * to properly recognizing idiomatic rotate code, so for we also provide\n * assembler directives (enabled with PCG_USE_INLINE_ASM).  Boo, hiss.\n * (I hope that these compilers get better so that this code can die.)\n *\n * These overloads will be preferred over the general template code above.\n */\n#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__  || __i386__)\n\ninline uint8_t rotr(uint8_t value, bitcount_t rot)\n{\n    asm (\"rorb   %%cl, %0\" : \"=r\" (value) : \"0\" (value), \"c\" (rot));\n    return value;\n}\n\ninline uint16_t rotr(uint16_t value, bitcount_t rot)\n{\n    asm (\"rorw   %%cl, %0\" : \"=r\" (value) : \"0\" (value), \"c\" (rot));\n    return value;\n}\n\ninline uint32_t rotr(uint32_t value, bitcount_t rot)\n{\n    asm (\"rorl   %%cl, %0\" : \"=r\" (value) : \"0\" (value), \"c\" (rot));\n    return value;\n}\n\n#if __x86_64__\ninline uint64_t rotr(uint64_t value, bitcount_t rot)\n{\n    asm (\"rorq   %%cl, %0\" : \"=r\" (value) : \"0\" (value), \"c\" (rot));\n    return value;\n}\n#endif // __x86_64__\n\n#elif defined(_MSC_VER)\n  // Use MSVC++ bit rotation intrinsics\n\n#pragma intrinsic(_rotr, _rotr64, _rotr8, _rotr16)\n\ninline uint8_t rotr(uint8_t value, bitcount_t rot)\n{\n    return _rotr8(value, rot);\n}\n\ninline uint16_t rotr(uint16_t value, bitcount_t rot)\n{\n    return _rotr16(value, rot);\n}\n\ninline uint32_t rotr(uint32_t value, bitcount_t rot)\n{\n    return _rotr(value, rot);\n}\n\ninline uint64_t rotr(uint64_t value, bitcount_t rot)\n{\n    return _rotr64(value, rot);\n}\n\n#endif // PCG_USE_INLINE_ASM\n\n\n/*\n * The C++ SeedSeq concept (modelled by seed_seq) can fill an array of\n * 32-bit integers with seed data, but sometimes we want to produce\n * larger or smaller integers.\n *\n * The following code handles this annoyance.\n *\n * uneven_copy will copy an array of 32-bit ints to an array of larger or\n * smaller ints (actually, the code is general it only needing forward\n * iterators).  The copy is identical to the one that would be performed if\n * we just did memcpy on a standard little-endian machine, but works\n * regardless of the endian of the machine (or the weirdness of the ints\n * involved).\n *\n * generate_to initializes an array of integers using a SeedSeq\n * object.  It is given the size as a static constant at compile time and\n * tries to avoid memory allocation.  If we're filling in 32-bit constants\n * we just do it directly.  If we need a separate buffer and it's small,\n * we allocate it on the stack.  Otherwise, we fall back to heap allocation.\n * Ugh.\n *\n * generate_one produces a single value of some integral type using a\n * SeedSeq object.\n */\n\n /* uneven_copy helper, case where destination ints are less than 32 bit. */\n\ntemplate<class SrcIter, class DestIter>\nSrcIter uneven_copy_impl(\n    SrcIter src_first, DestIter dest_first, DestIter dest_last,\n    std::true_type)\n{\n    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;\n    typedef typename std::iterator_traits<DestIter>::value_type dest_t;\n\n    constexpr size_t SRC_SIZE  = sizeof(src_t);\n    constexpr size_t DEST_SIZE = sizeof(dest_t);\n    constexpr bitcount_t DEST_BITS = bitcount_t(DEST_SIZE * 8);\n    constexpr size_t SCALE     = SRC_SIZE / DEST_SIZE;\n\n    size_t count = 0;\n    src_t value = 0;\n\n    while (dest_first != dest_last) {\n        if ((count++ % SCALE) == 0)\n            value = *src_first++;       // Get more bits\n        else\n            value >>= DEST_BITS;        // Move down bits\n\n        *dest_first++ = dest_t(value);  // Truncates, ignores high bits.\n    }\n    return src_first;\n}\n\n /* uneven_copy helper, case where destination ints are more than 32 bit. */\n\ntemplate<class SrcIter, class DestIter>\nSrcIter uneven_copy_impl(\n    SrcIter src_first, DestIter dest_first, DestIter dest_last,\n    std::false_type)\n{\n    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;\n    typedef typename std::iterator_traits<DestIter>::value_type dest_t;\n\n    constexpr auto SRC_SIZE  = sizeof(src_t);\n    constexpr auto SRC_BITS  = SRC_SIZE * 8;\n    constexpr auto DEST_SIZE = sizeof(dest_t);\n    constexpr auto SCALE     = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE;\n\n    while (dest_first != dest_last) {\n        dest_t value(0UL);\n        size_t shift = 0;\n\n        for (size_t i = 0; i < SCALE; ++i) {\n            value |= dest_t(*src_first++) << bitcount_t(shift);\n            shift += SRC_BITS;\n        }\n\n        *dest_first++ = value;\n    }\n    return src_first;\n}\n\n/* uneven_copy, call the right code for larger vs. smaller */\n\ntemplate<class SrcIter, class DestIter>\ninline SrcIter uneven_copy(SrcIter src_first,\n                           DestIter dest_first, DestIter dest_last)\n{\n    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;\n    typedef typename std::iterator_traits<DestIter>::value_type dest_t;\n\n    constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t);\n\n    return uneven_copy_impl(src_first, dest_first, dest_last,\n                            std::integral_constant<bool, DEST_IS_SMALLER>{});\n}\n\n/* generate_to, fill in a fixed-size array of integral type using a SeedSeq\n * (actually works for any random-access iterator)\n */\n\ntemplate <size_t size, typename SeedSeq, typename DestIter>\ninline void generate_to_impl(SeedSeq&& generator, DestIter dest,\n                             std::true_type)\n{\n    generator.generate(dest, dest+size);\n}\n\ntemplate <size_t size, typename SeedSeq, typename DestIter>\nvoid generate_to_impl(SeedSeq&& generator, DestIter dest,\n                      std::false_type)\n{\n    typedef typename std::iterator_traits<DestIter>::value_type dest_t;\n    constexpr auto DEST_SIZE = sizeof(dest_t);\n    constexpr auto GEN_SIZE  = sizeof(uint32_t);\n\n    constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE;\n    constexpr size_t FROM_ELEMS =\n        GEN_IS_SMALLER\n            ? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE)\n            : (size + (GEN_SIZE / DEST_SIZE) - 1)\n                / ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER);\n                        //  this odd code ^^^^^^^^^^^^^^^^^ is work-around for\n                        //  a bug: http://llvm.org/bugs/show_bug.cgi?id=21287\n\n    if (FROM_ELEMS <= 1024) {\n        uint32_t buffer[FROM_ELEMS];\n        generator.generate(buffer, buffer+FROM_ELEMS);\n        uneven_copy(buffer, dest, dest+size);\n    } else {\n        uint32_t* buffer = static_cast<uint32_t*>(malloc(GEN_SIZE * FROM_ELEMS));\n        generator.generate(buffer, buffer+FROM_ELEMS);\n        uneven_copy(buffer, dest, dest+size);\n        free(static_cast<void*>(buffer));\n    }\n}\n\ntemplate <size_t size, typename SeedSeq, typename DestIter>\ninline void generate_to(SeedSeq&& generator, DestIter dest)\n{\n    typedef typename std::iterator_traits<DestIter>::value_type dest_t;\n    constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t);\n\n    generate_to_impl<size>(std::forward<SeedSeq>(generator), dest,\n                           std::integral_constant<bool, IS_32BIT>{});\n}\n\n/* generate_one, produce a value of integral type using a SeedSeq\n * (optionally, we can have it produce more than one and pick which one\n * we want)\n */\n\ntemplate <typename UInt, size_t i = 0UL, size_t N = i+1UL, typename SeedSeq>\ninline UInt generate_one(SeedSeq&& generator)\n{\n    UInt result[N];\n    generate_to<N>(std::forward<SeedSeq>(generator), result);\n    return result[i];\n}\n\ntemplate <typename RngType>\nauto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)\n        -> typename RngType::result_type\n{\n    typedef typename RngType::result_type rtype;\n    rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)\n                    % upper_bound;\n    for (;;) {\n        rtype r = rng() - RngType::min();\n        if (r >= threshold)\n            return r % upper_bound;\n    }\n}\n\ntemplate <typename Iter, typename RandType>\nvoid shuffle(Iter from, Iter to, RandType&& rng)\n{\n    typedef typename std::iterator_traits<Iter>::difference_type delta_t;\n    typedef typename std::remove_reference<RandType>::type::result_type result_t;\n    auto count = to - from;\n    while (count > 1) {\n        delta_t chosen = delta_t(bounded_rand(rng, result_t(count)));\n        --count;\n        --to;\n        using std::swap;\n        swap(*(from + chosen), *to);\n    }\n}\n\n/*\n * Although std::seed_seq is useful, it isn't everything.  Often we want to\n * initialize a random-number generator some other way, such as from a random\n * device.\n *\n * Technically, it does not meet the requirements of a SeedSequence because\n * it lacks some of the rarely-used member functions (some of which would\n * be impossible to provide).  However the C++ standard is quite specific\n * that actual engines only called the generate method, so it ought not to be\n * a problem in practice.\n */\n\ntemplate <typename RngType>\nclass seed_seq_from {\nprivate:\n    RngType rng_;\n\npublic:\n    typedef uint_least32_t result_type;\n\n    template<typename... Args>\n    seed_seq_from(Args&&... args) :\n        rng_(std::forward<Args>(args)...)\n    {\n        // Nothing (else) to do...\n    }\n\n    template<typename Iter>\n    void generate(Iter start, Iter finish)\n    {\n        for (auto i = start; i != finish; ++i)\n            *i = result_type(rng_());\n    }\n\n    constexpr size_t size() const\n    {\n        return (sizeof(typename RngType::result_type) > sizeof(result_type)\n                && RngType::max() > ~size_t(0UL))\n             ? ~size_t(0UL)\n             : size_t(RngType::max());\n    }\n};\n\n/*\n * Sometimes you might want a distinct seed based on when the program\n * was compiled.  That way, a particular instance of the program will\n * behave the same way, but when recompiled it'll produce a different\n * value.\n */\n\ntemplate <typename IntType>\nstruct static_arbitrary_seed {\nprivate:\n    static constexpr IntType fnv(IntType hash, const char* pos) {\n        return *pos == '\\0'\n             ? hash\n             : fnv((hash * IntType(16777619U)) ^ *pos, (pos+1));\n    }\n\npublic:\n    static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)),\n                        __DATE__ __TIME__ __FILE__);\n\n    //Prevent creation, while keeping GCC from giving a warning\n    static_arbitrary_seed() = delete;\n};\n\n// Sometimes, when debugging or testing, it's handy to be able print the name\n// of a (in human-readable form).  This code allows the idiom:\n//\n//      cout << printable_typename<my_foo_type_t>()\n//\n// to print out my_foo_type_t (or its concrete type if it is a synonym)\n\n#if __cpp_rtti || __GXX_RTTI\n\ntemplate <typename T>\nstruct printable_typename {};\n\ntemplate <typename T>\nstd::ostream& operator<<(std::ostream& out, printable_typename<T>) {\n    const char *implementation_typename = typeid(T).name();\n#ifdef __GNUC__\n    int status;\n    char* pretty_name =\n        abi::__cxa_demangle(implementation_typename, nullptr, nullptr, &status);\n    if (status == 0)\n        out << pretty_name;\n    free(static_cast<void*>(pretty_name));\n    if (status == 0)\n        return out;\n#endif\n    out << implementation_typename;\n    return out;\n}\n\n#endif  // __cpp_rtti || __GXX_RTTI\n\n} // namespace pcg_extras\n\n#endif // PCG_EXTRAS_HPP_INCLUDED\n"
  },
  {
    "path": "eidos/pcg_random.hpp",
    "content": "/*\n * PCG Random Number Generation for C++\n *\n * Copyright 2014-2022 Melissa O'Neill <oneill@pcg-random.org>,\n *                     and the PCG Project contributors.\n *\n * SPDX-License-Identifier: (Apache-2.0 OR MIT)\n *\n * Licensed under the Apache License, Version 2.0 (provided in\n * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)\n * or under the MIT license (provided in LICENSE-MIT.txt and at\n * http://opensource.org/licenses/MIT), at your option. This file may not\n * be copied, modified, or distributed except according to those terms.\n *\n * Distributed on an \"AS IS\" BASIS, WITHOUT WARRANTY OF ANY KIND, either\n * express or implied.  See your chosen license for details.\n *\n * For additional information about the PCG random number generation scheme,\n * visit http://www.pcg-random.org/.\n */\n\n/*\n * This code provides the reference implementation of the PCG family of\n * random number generators.  The code is complex because it implements\n *\n *      - several members of the PCG family, specifically members corresponding\n *        to the output functions:\n *             - XSH RR         (good for 64-bit state, 32-bit output)\n *             - XSH RS         (good for 64-bit state, 32-bit output)\n *             - XSL RR         (good for 128-bit state, 64-bit output)\n *             - RXS M XS       (statistically most powerful generator)\n *             - XSL RR RR      (good for 128-bit state, 128-bit output)\n *             - and RXS, RXS M, XSH, XSL       (mostly for testing)\n *      - at potentially *arbitrary* bit sizes\n *      - with four different techniques for random streams (MCG, one-stream\n *        LCG, settable-stream LCG, unique-stream LCG)\n *      - and the extended generation schemes allowing arbitrary periods\n *      - with all features of C++11 random number generation (and more),\n *        some of which are somewhat painful, including\n *            - initializing with a SeedSequence which writes 32-bit values\n *              to memory, even though the state of the generator may not\n *              use 32-bit values (it might use smaller or larger integers)\n *            - I/O for RNGs and a prescribed format, which needs to handle\n *              the issue that 8-bit and 128-bit integers don't have working\n *              I/O routines (e.g., normally 8-bit = char, not integer)\n *            - equality and inequality for RNGs\n *      - and a number of convenience typedefs to mask all the complexity\n *\n * The code employees a fairly heavy level of abstraction, and has to deal\n * with various C++ minutia.  If you're looking to learn about how the PCG\n * scheme works, you're probably best of starting with one of the other\n * codebases (see www.pcg-random.org).  But if you're curious about the\n * constants for the various output functions used in those other, simpler,\n * codebases, this code shows how they are calculated.\n *\n * On the positive side, at least there are convenience typedefs so that you\n * can say\n *\n *      pcg32 myRNG;\n *\n * rather than:\n *\n *      pcg_detail::engine<\n *          uint32_t,                                           // Output Type\n *          uint64_t,                                           // State Type\n *          pcg_detail::xsh_rr_mixin<uint32_t, uint64_t>, true, // Output Func\n *          pcg_detail::specific_stream<uint64_t>,              // Stream Kind\n *          pcg_detail::default_multiplier<uint64_t>            // LCG Mult\n *      > myRNG;\n *\n */\n\n#ifndef PCG_RAND_HPP_INCLUDED\n#define PCG_RAND_HPP_INCLUDED 1\n\n#include <algorithm>\n#include <cinttypes>\n#include <cstddef>\n#include <cstdlib>\n#include <cstring>\n#include <cassert>\n#include <limits>\n#include <iostream>\n#include <iterator>\n#include <type_traits>\n#include <utility>\n#include <locale>\n#include <new>\n#include <stdexcept>\n\n#ifdef _MSC_VER\n    #pragma warning(disable:4146)\n    #pragma warning(disable:4127) // conditional expression is constant\n#endif\n\n#ifdef _MSC_VER\n    #define PCG_ALWAYS_INLINE __forceinline\n    #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190024210\n        // available since VS 2015 Update 2/3\n        #define PCG_EBO __declspec(empty_bases)\n    #else\n        #define PCG_EBO\n    #endif\n#elif __GNUC__\n    #define PCG_ALWAYS_INLINE __attribute__((always_inline))\n    #define PCG_EBO\n#else\n    #define PCG_ALWAYS_INLINE inline\n    #define PCG_EBO\n#endif\n\n/*\n * The pcg_extras namespace contains some support code that is likely to\n * be useful for a variety of RNGs, including:\n *      - 128-bit int support for platforms where it isn't available natively\n *      - bit twiddling operations\n *      - I/O of 128-bit and 8-bit integers\n *      - Handling the evilness of SeedSeq\n *      - Support for efficiently producing random numbers less than a given\n *        bound\n */\n\n#include \"pcg_extras.hpp\"\n\nnamespace pcg_detail {\n\nusing namespace pcg_extras;\n\n/*\n * The LCG generators need some constants to function.  This code lets you\n * look up the constant by *type*.  For example\n *\n *      default_multiplier<uint32_t>::multiplier()\n *\n * gives you the default multiplier for 32-bit integers.  We use the name\n * of the constant and not a generic word like value to allow these classes\n * to be used as mixins.\n */\n\ntemplate <typename T>\nstruct default_multiplier {\n    // Not defined for an arbitrary type\n};\n\ntemplate <typename T>\nstruct default_increment {\n    // Not defined for an arbitrary type\n};\n\n#define PCG_DEFINE_CONSTANT(type, what, kind, constant) \\\n        template <>                                     \\\n        struct what ## _ ## kind<type> {                \\\n            static constexpr type kind() {              \\\n                return constant;                        \\\n            }                                           \\\n        };\n\nPCG_DEFINE_CONSTANT(uint8_t,  default, multiplier, 141U)\nPCG_DEFINE_CONSTANT(uint8_t,  default, increment,  77U)\n\nPCG_DEFINE_CONSTANT(uint16_t, default, multiplier, 12829U)\nPCG_DEFINE_CONSTANT(uint16_t, default, increment,  47989U)\n\nPCG_DEFINE_CONSTANT(uint32_t, default, multiplier, 747796405U)\nPCG_DEFINE_CONSTANT(uint32_t, default, increment,  2891336453U)\n\nPCG_DEFINE_CONSTANT(uint64_t, default, multiplier, 6364136223846793005ULL)\nPCG_DEFINE_CONSTANT(uint64_t, default, increment,  1442695040888963407ULL)\n\nPCG_DEFINE_CONSTANT(pcg128_t, default, multiplier,\n        PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL))\nPCG_DEFINE_CONSTANT(pcg128_t, default, increment,\n        PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL))\n\n/* Alternative (cheaper) multipliers for 128-bit */\n\ntemplate <typename T>\nstruct cheap_multiplier : public default_multiplier<T> {\n    // For most types just use the default.\n};\n\ntemplate <>\nstruct cheap_multiplier<pcg128_t> {\n    static constexpr uint64_t multiplier() {\n        return 0xda942042e4dd58b5ULL;\n    }\n};\n\n\n/*\n * Each PCG generator is available in four variants, based on how it applies\n * the additive constant for its underlying LCG; the variations are:\n *\n *     single stream   - all instances use the same fixed constant, thus\n *                       the RNG always somewhere in same sequence\n *     mcg             - adds zero, resulting in a single stream and reduced\n *                       period\n *     specific stream - the constant can be changed at any time, selecting\n *                       a different random sequence\n *     unique stream   - the constant is based on the memory address of the\n *                       object, thus every RNG has its own unique sequence\n *\n * This variation is provided though mixin classes which define a function\n * value called increment() that returns the necessary additive constant.\n */\n\n\n\n/*\n * unique stream\n */\n\n\ntemplate <typename itype>\nclass unique_stream {\nprotected:\n    static constexpr bool is_mcg = false;\n\n    // Is never called, but is provided for symmetry with specific_stream\n    void set_stream(...)\n    {\n        abort();\n    }\n\npublic:\n    typedef itype state_type;\n\n    constexpr itype increment() const {\n        return itype(reinterpret_cast<uintptr_t>(this) | 1);\n    }\n\n    constexpr itype stream() const\n    {\n         return increment() >> 1;\n    }\n\n    static constexpr bool can_specify_stream = false;\n\n    static constexpr size_t streams_pow2()\n    {\n        return (sizeof(itype) < sizeof(size_t) ? sizeof(itype)\n                                               : sizeof(size_t))*8 - 1u;\n    }\n\nprotected:\n    constexpr unique_stream() = default;\n};\n\n\n/*\n * no stream (mcg)\n */\n\ntemplate <typename itype>\nclass no_stream {\nprotected:\n    static constexpr bool is_mcg = true;\n\n    // Is never called, but is provided for symmetry with specific_stream\n    void set_stream(...)\n    {\n        abort();\n    }\n\npublic:\n    typedef itype state_type;\n\n    static constexpr itype increment() {\n        return 0;\n    }\n\n    static constexpr bool can_specify_stream = false;\n\n    static constexpr size_t streams_pow2()\n    {\n        return 0u;\n    }\n\nprotected:\n    constexpr no_stream() = default;\n};\n\n\n/*\n * single stream/sequence (oneseq)\n */\n\ntemplate <typename itype>\nclass oneseq_stream : public default_increment<itype> {\nprotected:\n    static constexpr bool is_mcg = false;\n\n    // Is never called, but is provided for symmetry with specific_stream\n    void set_stream(...)\n    {\n        abort();\n    }\n\npublic:\n    typedef itype state_type;\n\n    static constexpr itype stream()\n    {\n         return default_increment<itype>::increment() >> 1;\n    }\n\n    static constexpr bool can_specify_stream = false;\n\n    static constexpr size_t streams_pow2()\n    {\n        return 0u;\n    }\n\nprotected:\n    constexpr oneseq_stream() = default;\n};\n\n\n/*\n * specific stream\n */\n\ntemplate <typename itype>\nclass specific_stream {\nprotected:\n    static constexpr bool is_mcg = false;\n\n    itype inc_ = default_increment<itype>::increment();\n\npublic:\n    typedef itype state_type;\n    typedef itype stream_state;\n\n    constexpr itype increment() const {\n        return inc_;\n    }\n\n    itype stream()\n    {\n         return inc_ >> 1;\n    }\n\n    void set_stream(itype specific_seq)\n    {\n         inc_ = (specific_seq << 1) | itype(1U);\n    }\n\n    static constexpr bool can_specify_stream = true;\n\n    static constexpr size_t streams_pow2()\n    {\n        return (sizeof(itype)*8) - 1u;\n    }\n\nprotected:\n    specific_stream() = default;\n\n    specific_stream(itype specific_seq)\n        : inc_(itype(specific_seq << 1) | itype(1U))\n    {\n        // Nothing (else) to do.\n    }\n};\n\n\n/*\n * This is where it all comes together.  This function joins together three\n * mixin classes which define\n *    - the LCG additive constant (the stream)\n *    - the LCG multiplier\n *    - the output function\n * in addition, we specify the type of the LCG state, and the result type,\n * and whether to use the pre-advance version of the state for the output\n * (increasing instruction-level parallelism) or the post-advance version\n * (reducing register pressure).\n *\n * Given the high level of parameterization, the code has to use some\n * template-metaprogramming tricks to handle some of the subtle variations\n * involved.\n */\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin,\n          bool output_previous = true,\n          typename stream_mixin = oneseq_stream<itype>,\n          typename multiplier_mixin = default_multiplier<itype> >\nclass PCG_EBO engine : protected output_mixin,\n               public stream_mixin,\n               protected multiplier_mixin {\nprotected:\n    itype state_;\n\n    struct can_specify_stream_tag {};\n    struct no_specifiable_stream_tag {};\n\n    using stream_mixin::increment;\n    using multiplier_mixin::multiplier;\n\npublic:\n    typedef xtype result_type;\n    typedef itype state_type;\n\n    static constexpr size_t period_pow2()\n    {\n        return sizeof(state_type)*8 - 2*stream_mixin::is_mcg;\n    }\n\n    // It would be nice to use std::numeric_limits for these, but\n    // we can't be sure that it'd be defined for the 128-bit types.\n\n    static constexpr result_type min()\n    {\n        return result_type(0UL);\n    }\n\n    static constexpr result_type max()\n    {\n        return result_type(~result_type(0UL));\n    }\n\nprotected:\n    itype bump(itype state)\n    {\n        return state * multiplier() + increment();\n    }\n\n    itype base_generate()\n    {\n        return state_ = bump(state_);\n    }\n\n    itype base_generate0()\n    {\n        itype old_state = state_;\n        state_ = bump(state_);\n        return old_state;\n    }\n\npublic:\n    result_type operator()()\n    {\n        if (output_previous)\n            return this->output(base_generate0());\n        else\n            return this->output(base_generate());\n    }\n\n    result_type operator()(result_type upper_bound)\n    {\n        return bounded_rand(*this, upper_bound);\n    }\n\nprotected:\n    static itype advance(itype state, itype delta,\n                         itype cur_mult, itype cur_plus);\n\n    static itype distance(itype cur_state, itype newstate, itype cur_mult,\n                          itype cur_plus, itype mask = ~itype(0U));\n\n    itype distance(itype newstate, itype mask = itype(~itype(0U))) const\n    {\n        return distance(state_, newstate, multiplier(), increment(), mask);\n    }\n\npublic:\n    void advance(itype delta)\n    {\n        state_ = advance(state_, delta, this->multiplier(), this->increment());\n    }\n\n    void backstep(itype delta)\n    {\n        advance(-delta);\n    }\n\n    void discard(itype delta)\n    {\n        advance(delta);\n    }\n\n    bool wrapped()\n    {\n        if (stream_mixin::is_mcg) {\n            // For MCGs, the low order two bits never change. In this\n            // implementation, we keep them fixed at 3 to make this test\n            // easier.\n            return state_ == 3;\n        } else {\n            return state_ == 0;\n        }\n    }\n\n    engine(itype state = itype(0xcafef00dd15ea5e5ULL))\n        : state_(this->is_mcg ? state|state_type(3U)\n                              : bump(state + this->increment()))\n    {\n        // Nothing else to do.\n    }\n\n    // This function may or may not exist.  It thus has to be a template\n    // to use SFINAE; users don't have to worry about its template-ness.\n\n    template <typename sm = stream_mixin>\n    engine(itype state, typename sm::stream_state stream_seed)\n        : stream_mixin(stream_seed),\n          state_(this->is_mcg ? state|state_type(3U)\n                              : bump(state + this->increment()))\n    {\n        // Nothing else to do.\n    }\n\n    template<typename SeedSeq>\n    engine(SeedSeq&& seedSeq, typename std::enable_if<\n                  !stream_mixin::can_specify_stream\n               && !std::is_convertible<SeedSeq, itype>::value\n               && !std::is_convertible<SeedSeq, engine>::value,\n               no_specifiable_stream_tag>::type = {})\n        : engine(generate_one<itype>(std::forward<SeedSeq>(seedSeq)))\n    {\n        // Nothing else to do.\n    }\n\n    template<typename SeedSeq>\n    engine(SeedSeq&& seedSeq, typename std::enable_if<\n                   stream_mixin::can_specify_stream\n               && !std::is_convertible<SeedSeq, itype>::value\n               && !std::is_convertible<SeedSeq, engine>::value,\n        can_specify_stream_tag>::type = {})\n    {\n        itype seeddata[2];\n        generate_to<2>(std::forward<SeedSeq>(seedSeq), seeddata);\n        seed(seeddata[1], seeddata[0]);\n    }\n\n\n    template<typename... Args>\n    void seed(Args&&... args)\n    {\n        new (this) engine(std::forward<Args>(args)...);\n    }\n\n    template <typename xtype1, typename itype1,\n              typename output_mixin1, bool output_previous1,\n              typename stream_mixin_lhs, typename multiplier_mixin_lhs,\n              typename stream_mixin_rhs, typename multiplier_mixin_rhs>\n    friend bool operator==(const engine<xtype1,itype1,\n                                     output_mixin1,output_previous1,\n                                     stream_mixin_lhs, multiplier_mixin_lhs>&,\n                           const engine<xtype1,itype1,\n                                     output_mixin1,output_previous1,\n                                     stream_mixin_rhs, multiplier_mixin_rhs>&);\n\n    template <typename xtype1, typename itype1,\n              typename output_mixin1, bool output_previous1,\n              typename stream_mixin_lhs, typename multiplier_mixin_lhs,\n              typename stream_mixin_rhs, typename multiplier_mixin_rhs>\n    friend itype1 operator-(const engine<xtype1,itype1,\n                                     output_mixin1,output_previous1,\n                                     stream_mixin_lhs, multiplier_mixin_lhs>&,\n                            const engine<xtype1,itype1,\n                                     output_mixin1,output_previous1,\n                                     stream_mixin_rhs, multiplier_mixin_rhs>&);\n\n    template <typename CharT, typename Traits,\n              typename xtype1, typename itype1,\n              typename output_mixin1, bool output_previous1,\n              typename stream_mixin1, typename multiplier_mixin1>\n    friend std::basic_ostream<CharT,Traits>&\n    operator<<(std::basic_ostream<CharT,Traits>& out,\n               const engine<xtype1,itype1,\n                              output_mixin1,output_previous1,\n                              stream_mixin1, multiplier_mixin1>&);\n\n    template <typename CharT, typename Traits,\n              typename xtype1, typename itype1,\n              typename output_mixin1, bool output_previous1,\n              typename stream_mixin1, typename multiplier_mixin1>\n    friend std::basic_istream<CharT,Traits>&\n    operator>>(std::basic_istream<CharT,Traits>& in,\n               engine<xtype1, itype1,\n                        output_mixin1, output_previous1,\n                        stream_mixin1, multiplier_mixin1>& rng);\n};\n\ntemplate <typename CharT, typename Traits,\n          typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin, typename multiplier_mixin>\nstd::basic_ostream<CharT,Traits>&\noperator<<(std::basic_ostream<CharT,Traits>& out,\n           const engine<xtype,itype,\n                          output_mixin,output_previous,\n                          stream_mixin, multiplier_mixin>& rng)\n{\n    using pcg_extras::operator<<;\n\n    auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left);\n    auto space = out.widen(' ');\n    auto orig_fill = out.fill();\n\n    out << rng.multiplier() << space\n        << rng.increment() << space\n        << rng.state_;\n\n    out.flags(orig_flags);\n    out.fill(orig_fill);\n    return out;\n}\n\n\ntemplate <typename CharT, typename Traits,\n          typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin, typename multiplier_mixin>\nstd::basic_istream<CharT,Traits>&\noperator>>(std::basic_istream<CharT,Traits>& in,\n           engine<xtype,itype,\n                    output_mixin,output_previous,\n                    stream_mixin, multiplier_mixin>& rng)\n{\n    using pcg_extras::operator>>;\n\n    auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws);\n\n    itype multiplier, increment, state;\n    in >> multiplier >> increment >> state;\n\n    if (!in.fail()) {\n        bool good = true;\n        if (multiplier != itype(rng.multiplier())) {\n           good = false;\n        } else if (rng.can_specify_stream) {\n           rng.set_stream(increment >> 1);\n        } else if (increment != rng.increment()) {\n           good = false;\n        }\n        if (good) {\n            rng.state_ = state;\n        } else {\n            in.clear(std::ios::failbit);\n        }\n    }\n\n    in.flags(orig_flags);\n    return in;\n}\n\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin, typename multiplier_mixin>\nitype engine<xtype,itype,output_mixin,output_previous,stream_mixin,\n             multiplier_mixin>::advance(\n    itype state, itype delta, itype cur_mult, itype cur_plus)\n{\n    // The method used here is based on Brown, \"Random Number Generation\n    // with Arbitrary Stride,\", Transactions of the American Nuclear\n    // Society (Nov. 1994).  The algorithm is very similar to fast\n    // exponentiation.\n    //\n    // Even though delta is an unsigned integer, we can pass a\n    // signed integer to go backwards, it just goes \"the long way round\".\n\n    constexpr itype ZERO = 0u;  // itype may be a non-trivial types, so\n    constexpr itype ONE  = 1u;  // we define some ugly constants.\n    itype acc_mult = 1;\n    itype acc_plus = 0;\n    while (delta > ZERO) {\n       if (delta & ONE) {\n          acc_mult *= cur_mult;\n          acc_plus = acc_plus*cur_mult + cur_plus;\n       }\n       cur_plus = (cur_mult+ONE)*cur_plus;\n       cur_mult *= cur_mult;\n       delta >>= 1;\n    }\n    return acc_mult * state + acc_plus;\n}\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin, typename multiplier_mixin>\nitype engine<xtype,itype,output_mixin,output_previous,stream_mixin,\n               multiplier_mixin>::distance(\n    itype cur_state, itype newstate, itype cur_mult, itype cur_plus, itype mask)\n{\n    constexpr itype ONE  = 1u;  // itype could be weird, so use constant\n    bool is_mcg_internal = cur_plus == itype(0);\n    itype the_bit = is_mcg_internal ? itype(4u) : itype(1u);\n    itype distance = 0u;\n    while ((cur_state & mask) != (newstate & mask)) {\n       if ((cur_state & the_bit) != (newstate & the_bit)) {\n           cur_state = cur_state * cur_mult + cur_plus;\n           distance |= the_bit;\n       }\n       assert((cur_state & the_bit) == (newstate & the_bit));\n       the_bit <<= 1;\n       cur_plus = (cur_mult+ONE)*cur_plus;\n       cur_mult *= cur_mult;\n    }\n    return is_mcg_internal ? distance >> 2 : distance;\n}\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin_lhs, typename multiplier_mixin_lhs,\n          typename stream_mixin_rhs, typename multiplier_mixin_rhs>\nitype operator-(const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,\n               const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)\n{\n    static_assert(\n        std::is_same<stream_mixin_lhs, stream_mixin_rhs>::value &&\n            std::is_same<multiplier_mixin_lhs, multiplier_mixin_rhs>::value,\n        \"Incomparable generators\");\n    if (lhs.increment() == rhs.increment()) {\n       return rhs.distance(lhs.state_);\n    } else  {\n       constexpr itype ONE = 1u;\n       itype lhs_diff = lhs.increment() + (lhs.multiplier()-ONE) * lhs.state_;\n       itype rhs_diff = rhs.increment() + (rhs.multiplier()-ONE) * rhs.state_;\n       if ((lhs_diff & itype(3u)) != (rhs_diff & itype(3u))) {\n           rhs_diff = -rhs_diff;\n       }\n       return rhs.distance(rhs_diff, lhs_diff, rhs.multiplier(), itype(0u));\n    }\n}\n\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin_lhs, typename multiplier_mixin_lhs,\n          typename stream_mixin_rhs, typename multiplier_mixin_rhs>\nbool operator==(const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,\n                const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)\n{\n    return    (lhs.multiplier() == rhs.multiplier())\n           && (lhs.increment()  == rhs.increment())\n           && (lhs.state_       == rhs.state_);\n}\n\ntemplate <typename xtype, typename itype,\n          typename output_mixin, bool output_previous,\n          typename stream_mixin_lhs, typename multiplier_mixin_lhs,\n          typename stream_mixin_rhs, typename multiplier_mixin_rhs>\ninline bool operator!=(const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,\n                       const engine<xtype,itype,\n                               output_mixin,output_previous,\n                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)\n{\n    return !operator==(lhs,rhs);\n}\n\n\ntemplate <typename xtype, typename itype,\n         template<typename XT,typename IT> class output_mixin,\n         bool output_previous = (sizeof(itype) <= 8),\n         template<typename IT> class multiplier_mixin = default_multiplier>\nusing oneseq_base  = engine<xtype, itype,\n                        output_mixin<xtype, itype>, output_previous,\n                        oneseq_stream<itype>,\n                        multiplier_mixin<itype> >;\n\ntemplate <typename xtype, typename itype,\n         template<typename XT,typename IT> class output_mixin,\n         bool output_previous = (sizeof(itype) <= 8),\n         template<typename IT> class multiplier_mixin = default_multiplier>\nusing unique_base = engine<xtype, itype,\n                         output_mixin<xtype, itype>, output_previous,\n                         unique_stream<itype>,\n                         multiplier_mixin<itype> >;\n\ntemplate <typename xtype, typename itype,\n         template<typename XT,typename IT> class output_mixin,\n         bool output_previous = (sizeof(itype) <= 8),\n         template<typename IT> class multiplier_mixin = default_multiplier>\nusing setseq_base = engine<xtype, itype,\n                         output_mixin<xtype, itype>, output_previous,\n                         specific_stream<itype>,\n                         multiplier_mixin<itype> >;\n\ntemplate <typename xtype, typename itype,\n         template<typename XT,typename IT> class output_mixin,\n         bool output_previous = (sizeof(itype) <= 8),\n         template<typename IT> class multiplier_mixin = default_multiplier>\nusing mcg_base = engine<xtype, itype,\n                      output_mixin<xtype, itype>, output_previous,\n                      no_stream<itype>,\n                      multiplier_mixin<itype> >;\n\n/*\n * OUTPUT FUNCTIONS.\n *\n * These are the core of the PCG generation scheme.  They specify how to\n * turn the base LCG's internal state into the output value of the final\n * generator.\n *\n * They're implemented as mixin classes.\n *\n * All of the classes have code that is written to allow it to be applied\n * at *arbitrary* bit sizes, although in practice they'll only be used at\n * standard sizes supported by C++.\n */\n\n/*\n * XSH RS -- high xorshift, followed by a random shift\n *\n * Fast.  A good performer.\n */\n\ntemplate <typename xtype, typename itype>\nstruct xsh_rs_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t sparebits   = bits - xtypebits;\n        constexpr bitcount_t opbits =\n                              sparebits-5 >= 64 ? 5\n                            : sparebits-4 >= 32 ? 4\n                            : sparebits-3 >= 16 ? 3\n                            : sparebits-2 >= 4  ? 2\n                            : sparebits-1 >= 1  ? 1\n                            :                     0;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        constexpr bitcount_t maxrandshift  = mask;\n        constexpr bitcount_t topspare     = opbits;\n        constexpr bitcount_t bottomspare = sparebits - topspare;\n        constexpr bitcount_t xshift     = topspare + (xtypebits+maxrandshift)/2;\n        bitcount_t rshift =\n            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;\n        internal ^= internal >> xshift;\n        xtype result = xtype(internal >> (bottomspare - maxrandshift + rshift));\n        return result;\n    }\n};\n\n/*\n * XSH RR -- high xorshift, followed by a random rotate\n *\n * Fast.  A good performer.  Slightly better statistically than XSH RS.\n */\n\ntemplate <typename xtype, typename itype>\nstruct xsh_rr_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype)*8);\n        constexpr bitcount_t sparebits   = bits - xtypebits;\n        constexpr bitcount_t wantedopbits =\n                              xtypebits >= 128 ? 7\n                            : xtypebits >=  64 ? 6\n                            : xtypebits >=  32 ? 5\n                            : xtypebits >=  16 ? 4\n                            :                    3;\n        constexpr bitcount_t opbits =\n                              sparebits >= wantedopbits ? wantedopbits\n                                                        : sparebits;\n        constexpr bitcount_t amplifier = wantedopbits - opbits;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        constexpr bitcount_t topspare    = opbits;\n        constexpr bitcount_t bottomspare = sparebits - topspare;\n        constexpr bitcount_t xshift      = (topspare + xtypebits)/2;\n        bitcount_t rot = opbits ? bitcount_t(internal >> (bits - opbits)) & mask\n                                : 0;\n        bitcount_t amprot = (rot << amplifier) & mask;\n        internal ^= internal >> xshift;\n        xtype result = xtype(internal >> bottomspare);\n        result = rotr(result, amprot);\n        return result;\n    }\n};\n\n/*\n * RXS -- random xorshift\n */\n\ntemplate <typename xtype, typename itype>\nstruct rxs_mixin {\nstatic xtype output_rxs(itype internal)\n    {\n        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype)*8);\n        constexpr bitcount_t shift       = bits - xtypebits;\n        constexpr bitcount_t extrashift  = (xtypebits - shift)/2;\n        bitcount_t rshift = shift > 64+8 ? (internal >> (bits - 6)) & 63\n                       : shift > 32+4 ? (internal >> (bits - 5)) & 31\n                       : shift > 16+2 ? (internal >> (bits - 4)) & 15\n                       : shift >  8+1 ? (internal >> (bits - 3)) & 7\n                       : shift >  4+1 ? (internal >> (bits - 2)) & 3\n                       : shift >  2+1 ? (internal >> (bits - 1)) & 1\n                       :              0;\n        internal ^= internal >> (shift + extrashift - rshift);\n        xtype result = internal >> rshift;\n        return result;\n    }\n};\n\n/*\n * RXS M XS -- random xorshift, mcg multiply, fixed xorshift\n *\n * The most statistically powerful generator, but all those steps\n * make it slower than some of the others.  We give it the rottenest jobs.\n *\n * Because it's usually used in contexts where the state type and the\n * result type are the same, it is a permutation and is thus invertable.\n * We thus provide a function to invert it.  This function is used to\n * for the \"inside out\" generator used by the extended generator.\n */\n\n/* Defined type-based concepts for the multiplication step.  They're actually\n * all derived by truncating the 128-bit, which was computed to be a good\n * \"universal\" constant.\n */\n\ntemplate <typename T>\nstruct mcg_multiplier {\n    // Not defined for an arbitrary type\n};\n\ntemplate <typename T>\nstruct mcg_unmultiplier {\n    // Not defined for an arbitrary type\n};\n\nPCG_DEFINE_CONSTANT(uint8_t,  mcg, multiplier,   217U)\nPCG_DEFINE_CONSTANT(uint8_t,  mcg, unmultiplier, 105U)\n\nPCG_DEFINE_CONSTANT(uint16_t, mcg, multiplier,   62169U)\nPCG_DEFINE_CONSTANT(uint16_t, mcg, unmultiplier, 28009U)\n\nPCG_DEFINE_CONSTANT(uint32_t, mcg, multiplier,   277803737U)\nPCG_DEFINE_CONSTANT(uint32_t, mcg, unmultiplier, 2897767785U)\n\nPCG_DEFINE_CONSTANT(uint64_t, mcg, multiplier,   12605985483714917081ULL)\nPCG_DEFINE_CONSTANT(uint64_t, mcg, unmultiplier, 15009553638781119849ULL)\n\nPCG_DEFINE_CONSTANT(pcg128_t, mcg, multiplier,\n        PCG_128BIT_CONSTANT(17766728186571221404ULL, 12605985483714917081ULL))\nPCG_DEFINE_CONSTANT(pcg128_t, mcg, unmultiplier,\n        PCG_128BIT_CONSTANT(14422606686972528997ULL, 15009553638781119849ULL))\n\n\ntemplate <typename xtype, typename itype>\nstruct rxs_m_xs_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t opbits = xtypebits >= 128 ? 6\n                                 : xtypebits >=  64 ? 5\n                                 : xtypebits >=  32 ? 4\n                                 : xtypebits >=  16 ? 3\n                                 :                    2;\n        constexpr bitcount_t shift = bits - xtypebits;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        bitcount_t rshift =\n            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;\n        internal ^= internal >> (opbits + rshift);\n        internal *= mcg_multiplier<itype>::multiplier();\n        xtype result = internal >> shift;\n        result ^= result >> ((2U*xtypebits+2U)/3U);\n        return result;\n    }\n\n    static itype unoutput(itype internal)\n    {\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t opbits = bits >= 128 ? 6\n                                 : bits >=  64 ? 5\n                                 : bits >=  32 ? 4\n                                 : bits >=  16 ? 3\n                                 :               2;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n\n        internal = unxorshift(internal, bits, (2U*bits+2U)/3U);\n\n        internal *= mcg_unmultiplier<itype>::unmultiplier();\n\n        bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;\n        internal = unxorshift(internal, bits, opbits + rshift);\n\n        return internal;\n    }\n};\n\n\n/*\n * RXS M -- random xorshift, mcg multiply\n */\n\ntemplate <typename xtype, typename itype>\nstruct rxs_m_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t opbits = xtypebits >= 128 ? 6\n                                 : xtypebits >=  64 ? 5\n                                 : xtypebits >=  32 ? 4\n                                 : xtypebits >=  16 ? 3\n                                 :                    2;\n        constexpr bitcount_t shift = bits - xtypebits;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;\n        internal ^= internal >> (opbits + rshift);\n        internal *= mcg_multiplier<itype>::multiplier();\n        xtype result = internal >> shift;\n        return result;\n    }\n};\n\n\n/*\n * DXSM -- double xorshift multiply\n *\n * This is a new, more powerful output permutation (added in 2019).  It's\n * a more comprehensive scrambling than RXS M, but runs faster on 128-bit\n * types.  Although primarily intended for use at large sizes, also works\n * at smaller sizes as well.\n *\n * This permutation is similar to xorshift multiply hash functions, except\n * that one of the multipliers is the LCG multiplier (to avoid needing to\n * have a second constant) and the other is based on the low-order bits.\n * This latter aspect means that the scrambling applied to the high bits\n * depends on the low bits, and makes it (to my eye) impractical to back\n * out the permutation without having the low-order bits.\n */\n\ntemplate <typename xtype, typename itype>\nstruct dxsm_mixin {\n    inline xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t itypebits = bitcount_t(sizeof(itype) * 8);\n        static_assert(xtypebits <= itypebits/2,\n                      \"Output type must be half the size of the state type.\");\n        \n        xtype hi = xtype(internal >> (itypebits - xtypebits));\n        xtype lo = xtype(internal);\n\n        lo |= 1;\n        hi ^= hi >> (xtypebits/2);\n\thi *= xtype(cheap_multiplier<itype>::multiplier());\n\thi ^= hi >> (3*(xtypebits/4));\n\thi *= lo;\n\treturn hi;\n    }\n};\n\n\n/*\n * XSL RR -- fixed xorshift (to low bits), random rotate\n *\n * Useful for 128-bit types that are split across two CPU registers.\n */\n\ntemplate <typename xtype, typename itype>\nstruct xsl_rr_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t sparebits = bits - xtypebits;\n        constexpr bitcount_t wantedopbits = xtypebits >= 128 ? 7\n                                       : xtypebits >=  64 ? 6\n                                       : xtypebits >=  32 ? 5\n                                       : xtypebits >=  16 ? 4\n                                       :                    3;\n        constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits\n                                                             : sparebits;\n        constexpr bitcount_t amplifier = wantedopbits - opbits;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        constexpr bitcount_t topspare = sparebits;\n        constexpr bitcount_t bottomspare = sparebits - topspare;\n        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;\n\n        bitcount_t rot =\n            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;\n        bitcount_t amprot = (rot << amplifier) & mask;\n        internal ^= internal >> xshift;\n        xtype result = xtype(internal >> bottomspare);\n        result = rotr(result, amprot);\n        return result;\n    }\n};\n\n\n/*\n * XSL RR RR -- fixed xorshift (to low bits), random rotate (both parts)\n *\n * Useful for 128-bit types that are split across two CPU registers.\n * If you really want an invertable 128-bit RNG, I guess this is the one.\n */\n\ntemplate <typename T> struct halfsize_trait {};\ntemplate <> struct halfsize_trait<pcg128_t>  { typedef uint64_t type; };\ntemplate <> struct halfsize_trait<uint64_t>  { typedef uint32_t type; };\ntemplate <> struct halfsize_trait<uint32_t>  { typedef uint16_t type; };\ntemplate <> struct halfsize_trait<uint16_t>  { typedef uint8_t type;  };\n\ntemplate <typename xtype, typename itype>\nstruct xsl_rr_rr_mixin {\n    typedef typename halfsize_trait<itype>::type htype;\n\n    static itype output(itype internal)\n    {\n        constexpr bitcount_t htypebits = bitcount_t(sizeof(htype) * 8);\n        constexpr bitcount_t bits      = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t sparebits = bits - htypebits;\n        constexpr bitcount_t wantedopbits = htypebits >= 128 ? 7\n                                       : htypebits >=  64 ? 6\n                                       : htypebits >=  32 ? 5\n                                       : htypebits >=  16 ? 4\n                                       :                    3;\n        constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits\n                                                                : sparebits;\n        constexpr bitcount_t amplifier = wantedopbits - opbits;\n        constexpr bitcount_t mask = (1 << opbits) - 1;\n        constexpr bitcount_t topspare = sparebits;\n        constexpr bitcount_t xshift = (topspare + htypebits) / 2;\n\n        bitcount_t rot =\n            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;\n        bitcount_t amprot = (rot << amplifier) & mask;\n        internal ^= internal >> xshift;\n        htype lowbits = htype(internal);\n        lowbits = rotr(lowbits, amprot);\n        htype highbits = htype(internal >> topspare);\n        bitcount_t rot2 = lowbits & mask;\n        bitcount_t amprot2 = (rot2 << amplifier) & mask;\n        highbits = rotr(highbits, amprot2);\n        return (itype(highbits) << topspare) ^ itype(lowbits);\n    }\n};\n\n\n/*\n * XSH -- fixed xorshift (to high bits)\n *\n * You shouldn't use this at 64-bits or less.\n */\n\ntemplate <typename xtype, typename itype>\nstruct xsh_mixin {\n    static xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t sparebits = bits - xtypebits;\n        constexpr bitcount_t topspare = 0;\n        constexpr bitcount_t bottomspare = sparebits - topspare;\n        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;\n\n        internal ^= internal >> xshift;\n        xtype result = internal >> bottomspare;\n        return result;\n    }\n};\n\n/*\n * XSL -- fixed xorshift (to low bits)\n *\n * You shouldn't use this at 64-bits or less.\n */\n\ntemplate <typename xtype, typename itype>\nstruct xsl_mixin {\n    inline xtype output(itype internal)\n    {\n        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);\n        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);\n        constexpr bitcount_t sparebits = bits - xtypebits;\n        constexpr bitcount_t topspare = sparebits;\n        constexpr bitcount_t bottomspare = sparebits - topspare;\n        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;\n\n        internal ^= internal >> xshift;\n        xtype result = internal >> bottomspare;\n        return result;\n    }\n};\n\n\n/* ---- End of Output Functions ---- */\n\n\ntemplate <typename baseclass>\nstruct PCG_EBO inside_out : private baseclass {\n    inside_out() = delete;\n\n    typedef typename baseclass::result_type result_type;\n    typedef typename baseclass::state_type  state_type;\n    static_assert(sizeof(result_type) == sizeof(state_type),\n                  \"Require a RNG whose output function is a permutation\");\n\n    static bool external_step(result_type& randval, size_t i)\n    {\n        state_type state = baseclass::unoutput(randval);\n        state = state * baseclass::multiplier() + baseclass::increment()\n                + state_type(i*2);\n        result_type result = baseclass::output(state);\n        randval = result;\n        state_type zero =\n            baseclass::is_mcg ? state & state_type(3U) : state_type(0U);\n        return result == zero;\n    }\n\n    static bool external_advance(result_type& randval, size_t i,\n                                 result_type delta, bool forwards = true)\n    {\n        state_type state = baseclass::unoutput(randval);\n        state_type mult  = baseclass::multiplier();\n        state_type inc   = baseclass::increment() + state_type(i*2);\n        state_type zero =\n            baseclass::is_mcg ? state & state_type(3U) : state_type(0U);\n        state_type dist_to_zero = baseclass::distance(state, zero, mult, inc);\n        bool crosses_zero =\n            forwards ? dist_to_zero <= delta\n                     : (-dist_to_zero) <= delta;\n        if (!forwards)\n            delta = -delta;\n        state = baseclass::advance(state, delta, mult, inc);\n        randval = baseclass::output(state);\n        return crosses_zero;\n    }\n};\n\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, typename baseclass, typename extvalclass, bool kdd = true>\nclass PCG_EBO extended : public baseclass {\npublic:\n    typedef typename baseclass::state_type  state_type;\n    typedef typename baseclass::result_type result_type;\n    typedef inside_out<extvalclass> insideout;\n\nprivate:\n    static constexpr bitcount_t rtypebits = sizeof(result_type)*8;\n    static constexpr bitcount_t stypebits = sizeof(state_type)*8;\n\n    static constexpr bitcount_t tick_limit_pow2 = 64U;\n\n    static constexpr size_t table_size  = 1UL << table_pow2;\n    static constexpr size_t table_shift = stypebits - table_pow2;\n    static constexpr state_type table_mask =\n        (state_type(1U) << table_pow2) - state_type(1U);\n\n    static constexpr bool   may_tick  =\n        (advance_pow2 < stypebits) && (advance_pow2 < tick_limit_pow2);\n    static constexpr size_t tick_shift = stypebits - advance_pow2;\n    static constexpr state_type tick_mask  =\n        may_tick ? state_type(\n                       (uint64_t(1) << (advance_pow2*may_tick)) - 1)\n                                        // ^-- stupidity to appease GCC warnings\n                 : ~state_type(0U);\n\n    static constexpr bool may_tock = stypebits < tick_limit_pow2;\n\n    result_type data_[table_size];\n\n    PCG_NOINLINE void advance_table();\n\n    PCG_NOINLINE void advance_table(state_type delta, bool isForwards = true);\n\n    result_type& get_extended_value()\n    {\n        state_type state = this->state_;\n        if (kdd && baseclass::is_mcg) {\n            // The low order bits of an MCG are constant, so drop them.\n            state >>= 2;\n        }\n        size_t index       = kdd ? state &  table_mask\n                                 : state >> table_shift;\n\n        if (may_tick) {\n            bool tick = kdd ? (state & tick_mask) == state_type(0u)\n                            : (state >> tick_shift) == state_type(0u);\n            if (tick)\n                    advance_table();\n        }\n        if (may_tock) {\n            bool tock = state == state_type(0u);\n            if (tock)\n                advance_table();\n        }\n        return data_[index];\n    }\n\npublic:\n    static constexpr size_t period_pow2()\n    {\n        return baseclass::period_pow2() + table_size*extvalclass::period_pow2();\n    }\n\n    PCG_ALWAYS_INLINE result_type operator()()\n    {\n        result_type rhs = get_extended_value();\n        result_type lhs = this->baseclass::operator()();\n        return lhs ^ rhs;\n    }\n\n    result_type operator()(result_type upper_bound)\n    {\n        return bounded_rand(*this, upper_bound);\n    }\n\n    void set(result_type wanted)\n    {\n        result_type& rhs = get_extended_value();\n        result_type lhs = this->baseclass::operator()();\n        rhs = lhs ^ wanted;\n    }\n\n    void advance(state_type distance, bool forwards = true);\n\n    void backstep(state_type distance)\n    {\n        advance(distance, false);\n    }\n\n    extended(const result_type* data)\n        : baseclass()\n    {\n        datainit(data);\n    }\n\n    extended(const result_type* data, state_type seed)\n        : baseclass(seed)\n    {\n        datainit(data);\n    }\n\n    // This function may or may not exist.  It thus has to be a template\n    // to use SFINAE; users don't have to worry about its template-ness.\n\n    template <typename bc = baseclass>\n    extended(const result_type* data, state_type seed,\n            typename bc::stream_state stream_seed)\n        : baseclass(seed, stream_seed)\n    {\n        datainit(data);\n    }\n\n    extended()\n        : baseclass()\n    {\n        selfinit();\n    }\n\n    extended(state_type seed)\n        : baseclass(seed)\n    {\n        selfinit();\n    }\n\n    // This function may or may not exist.  It thus has to be a template\n    // to use SFINAE; users don't have to worry about its template-ness.\n\n    template <typename bc = baseclass>\n    extended(state_type seed, typename bc::stream_state stream_seed)\n        : baseclass(seed, stream_seed)\n    {\n        selfinit();\n    }\n\nprivate:\n    void selfinit();\n    void datainit(const result_type* data);\n\npublic:\n\n    template<typename SeedSeq, typename = typename std::enable_if<\n           !std::is_convertible<SeedSeq, result_type>::value\n        && !std::is_convertible<SeedSeq, extended>::value>::type>\n    extended(SeedSeq&& seedSeq)\n        : baseclass(seedSeq)\n    {\n        generate_to<table_size>(seedSeq, data_);\n    }\n\n    template<typename... Args>\n    void seed(Args&&... args)\n    {\n        new (this) extended(std::forward<Args>(args)...);\n    }\n\n    template <bitcount_t table_pow2_, bitcount_t advance_pow2_,\n              typename baseclass_, typename extvalclass_, bool kdd_>\n    friend bool operator==(const extended<table_pow2_, advance_pow2_,\n                                              baseclass_, extvalclass_, kdd_>&,\n                           const extended<table_pow2_, advance_pow2_,\n                                              baseclass_, extvalclass_, kdd_>&);\n\n    template <typename CharT, typename Traits,\n              bitcount_t table_pow2_, bitcount_t advance_pow2_,\n              typename baseclass_, typename extvalclass_, bool kdd_>\n    friend std::basic_ostream<CharT,Traits>&\n    operator<<(std::basic_ostream<CharT,Traits>& out,\n               const extended<table_pow2_, advance_pow2_,\n                              baseclass_, extvalclass_, kdd_>&);\n\n    template <typename CharT, typename Traits,\n              bitcount_t table_pow2_, bitcount_t advance_pow2_,\n              typename baseclass_, typename extvalclass_, bool kdd_>\n    friend std::basic_istream<CharT,Traits>&\n    operator>>(std::basic_istream<CharT,Traits>& in,\n               extended<table_pow2_, advance_pow2_,\n                        baseclass_, extvalclass_, kdd_>&);\n\n};\n\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nvoid extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::datainit(\n         const result_type* data)\n{\n    for (size_t i = 0; i < table_size; ++i)\n        data_[i] = data[i];\n}\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nvoid extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::selfinit()\n{\n    // We need to fill the extended table with something, and we have\n    // very little provided data, so we use the base generator to\n    // produce values.  Although not ideal (use a seed sequence, folks!),\n    // unexpected correlations are mitigated by\n    //      - using XOR differences rather than the number directly\n    //      - the way the table is accessed, its values *won't* be accessed\n    //        in the same order the were written.\n    //      - any strange correlations would only be apparent if we\n    //        were to backstep the generator so that the base generator\n    //        was generating the same values again\n    result_type lhs = baseclass::operator()();\n    result_type rhs = baseclass::operator()();\n    result_type xdiff = lhs - rhs;\n    for (size_t i = 0; i < table_size; ++i) {\n        data_[i] = baseclass::operator()() ^ xdiff;\n    }\n}\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nbool operator==(const extended<table_pow2, advance_pow2,\n                               baseclass, extvalclass, kdd>& lhs,\n                const extended<table_pow2, advance_pow2,\n                               baseclass, extvalclass, kdd>& rhs)\n{\n    auto& base_lhs = static_cast<const baseclass&>(lhs);\n    auto& base_rhs = static_cast<const baseclass&>(rhs);\n    return base_lhs == base_rhs\n        && std::equal(\n               std::begin(lhs.data_), std::end(lhs.data_),\n               std::begin(rhs.data_)\n           );\n}\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\ninline bool operator!=(const extended<table_pow2, advance_pow2,\n                                      baseclass, extvalclass, kdd>& lhs,\n                       const extended<table_pow2, advance_pow2,\n                                      baseclass, extvalclass, kdd>& rhs)\n{\n    return !operator==(lhs, rhs);\n}\n\ntemplate <typename CharT, typename Traits,\n          bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nstd::basic_ostream<CharT,Traits>&\noperator<<(std::basic_ostream<CharT,Traits>& out,\n           const extended<table_pow2, advance_pow2,\n                          baseclass, extvalclass, kdd>& rng)\n{\n    using pcg_extras::operator<<;\n\n    auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left);\n    auto space = out.widen(' ');\n    auto orig_fill = out.fill();\n\n    out << rng.multiplier() << space\n        << rng.increment() << space\n        << rng.state_;\n\n    for (const auto& datum : rng.data_)\n        out << space << datum;\n\n    out.flags(orig_flags);\n    out.fill(orig_fill);\n    return out;\n}\n\ntemplate <typename CharT, typename Traits,\n          bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nstd::basic_istream<CharT,Traits>&\noperator>>(std::basic_istream<CharT,Traits>& in,\n           extended<table_pow2, advance_pow2,\n                    baseclass, extvalclass, kdd>& rng)\n{\n    extended<table_pow2, advance_pow2, baseclass, extvalclass> new_rng;\n    auto& base_rng = static_cast<baseclass&>(new_rng);\n    in >> base_rng;\n\n    if (in.fail())\n        return in;\n\n    using pcg_extras::operator>>;\n\n    auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws);\n\n    for (auto& datum : new_rng.data_) {\n        in >> datum;\n        if (in.fail())\n            goto bail;\n    }\n\n    rng = new_rng;\n\nbail:\n    in.flags(orig_flags);\n    return in;\n}\n\n\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nvoid\nextended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table()\n{\n    bool carry = false;\n    for (size_t i = 0; i < table_size; ++i) {\n        if (carry) {\n            carry = insideout::external_step(data_[i],i+1);\n        }\n        bool carry2 = insideout::external_step(data_[i],i+1);\n        carry = carry || carry2;\n    }\n}\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nvoid\nextended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table(\n        state_type delta, bool isForwards)\n{\n    typedef typename baseclass::state_type   base_state_t;\n    typedef typename extvalclass::state_type ext_state_t;\n    constexpr bitcount_t basebits = sizeof(base_state_t)*8;\n    constexpr bitcount_t extbits  = sizeof(ext_state_t)*8;\n    static_assert(basebits <= extbits || advance_pow2 > 0,\n                  \"Current implementation might overflow its carry\");\n\n    base_state_t carry = 0;\n    for (size_t i = 0; i < table_size; ++i) {\n        base_state_t total_delta = carry + delta;\n        ext_state_t  trunc_delta = ext_state_t(total_delta);\n        if (basebits > extbits) {\n            carry = total_delta >> extbits;\n        } else {\n            carry = 0;\n        }\n        carry +=\n            insideout::external_advance(data_[i],i+1, trunc_delta, isForwards);\n    }\n}\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename baseclass, typename extvalclass, bool kdd>\nvoid extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance(\n    state_type distance, bool forwards)\n{\n    static_assert(kdd,\n        \"Efficient advance is too hard for non-kdd extension. \"\n        \"For a weak advance, cast to base class\");\n    state_type zero =\n        baseclass::is_mcg ? this->state_ & state_type(3U) : state_type(0U);\n    if (may_tick) {\n        state_type ticks = distance >> (advance_pow2*may_tick);\n                                        // ^-- stupidity to appease GCC\n                                        // warnings\n        state_type adv_mask =\n            baseclass::is_mcg ? tick_mask << 2 : tick_mask;\n        state_type next_advance_distance = this->distance(zero, adv_mask);\n        if (!forwards)\n            next_advance_distance = (-next_advance_distance) & tick_mask;\n        if (next_advance_distance < (distance & tick_mask)) {\n            ++ticks;\n        }\n        if (ticks)\n            advance_table(ticks, forwards);\n    }\n    if (forwards) {\n        if (may_tock && this->distance(zero) <= distance)\n            advance_table();\n        baseclass::advance(distance);\n    } else {\n        if (may_tock && -(this->distance(zero)) <= distance)\n            advance_table(state_type(1U), false);\n        baseclass::advance(-distance);\n    }\n}\n\n} // namespace pcg_detail\n\nnamespace pcg_engines {\n\nusing namespace pcg_detail;\n\n/* Predefined types for XSH RS */\n\ntypedef oneseq_base<uint8_t,  uint16_t, xsh_rs_mixin>  oneseq_xsh_rs_16_8;\ntypedef oneseq_base<uint16_t, uint32_t, xsh_rs_mixin>  oneseq_xsh_rs_32_16;\ntypedef oneseq_base<uint32_t, uint64_t, xsh_rs_mixin>  oneseq_xsh_rs_64_32;\ntypedef oneseq_base<uint64_t, pcg128_t, xsh_rs_mixin>  oneseq_xsh_rs_128_64;\ntypedef oneseq_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>\n                                                       cm_oneseq_xsh_rs_128_64;\n\ntypedef unique_base<uint8_t,  uint16_t, xsh_rs_mixin>  unique_xsh_rs_16_8;\ntypedef unique_base<uint16_t, uint32_t, xsh_rs_mixin>  unique_xsh_rs_32_16;\ntypedef unique_base<uint32_t, uint64_t, xsh_rs_mixin>  unique_xsh_rs_64_32;\ntypedef unique_base<uint64_t, pcg128_t, xsh_rs_mixin>  unique_xsh_rs_128_64;\ntypedef unique_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>\n                                                       cm_unique_xsh_rs_128_64;\n\ntypedef setseq_base<uint8_t,  uint16_t, xsh_rs_mixin>  setseq_xsh_rs_16_8;\ntypedef setseq_base<uint16_t, uint32_t, xsh_rs_mixin>  setseq_xsh_rs_32_16;\ntypedef setseq_base<uint32_t, uint64_t, xsh_rs_mixin>  setseq_xsh_rs_64_32;\ntypedef setseq_base<uint64_t, pcg128_t, xsh_rs_mixin>  setseq_xsh_rs_128_64;\ntypedef setseq_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>\n                                                       cm_setseq_xsh_rs_128_64;\n\ntypedef mcg_base<uint8_t,  uint16_t, xsh_rs_mixin>  mcg_xsh_rs_16_8;\ntypedef mcg_base<uint16_t, uint32_t, xsh_rs_mixin>  mcg_xsh_rs_32_16;\ntypedef mcg_base<uint32_t, uint64_t, xsh_rs_mixin>  mcg_xsh_rs_64_32;\ntypedef mcg_base<uint64_t, pcg128_t, xsh_rs_mixin>  mcg_xsh_rs_128_64;\ntypedef mcg_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>\n                                                    cm_mcg_xsh_rs_128_64;\n\n/* Predefined types for XSH RR */\n\ntypedef oneseq_base<uint8_t,  uint16_t, xsh_rr_mixin>  oneseq_xsh_rr_16_8;\ntypedef oneseq_base<uint16_t, uint32_t, xsh_rr_mixin>  oneseq_xsh_rr_32_16;\ntypedef oneseq_base<uint32_t, uint64_t, xsh_rr_mixin>  oneseq_xsh_rr_64_32;\ntypedef oneseq_base<uint64_t, pcg128_t, xsh_rr_mixin>  oneseq_xsh_rr_128_64;\ntypedef oneseq_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>\n                                                       cm_oneseq_xsh_rr_128_64;\n\ntypedef unique_base<uint8_t,  uint16_t, xsh_rr_mixin>  unique_xsh_rr_16_8;\ntypedef unique_base<uint16_t, uint32_t, xsh_rr_mixin>  unique_xsh_rr_32_16;\ntypedef unique_base<uint32_t, uint64_t, xsh_rr_mixin>  unique_xsh_rr_64_32;\ntypedef unique_base<uint64_t, pcg128_t, xsh_rr_mixin>  unique_xsh_rr_128_64;\ntypedef unique_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>\n                                                       cm_unique_xsh_rr_128_64;\n\ntypedef setseq_base<uint8_t,  uint16_t, xsh_rr_mixin>  setseq_xsh_rr_16_8;\ntypedef setseq_base<uint16_t, uint32_t, xsh_rr_mixin>  setseq_xsh_rr_32_16;\ntypedef setseq_base<uint32_t, uint64_t, xsh_rr_mixin>  setseq_xsh_rr_64_32;\ntypedef setseq_base<uint64_t, pcg128_t, xsh_rr_mixin>  setseq_xsh_rr_128_64;\ntypedef setseq_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>\n                                                       cm_setseq_xsh_rr_128_64;\n\ntypedef mcg_base<uint8_t,  uint16_t, xsh_rr_mixin>  mcg_xsh_rr_16_8;\ntypedef mcg_base<uint16_t, uint32_t, xsh_rr_mixin>  mcg_xsh_rr_32_16;\ntypedef mcg_base<uint32_t, uint64_t, xsh_rr_mixin>  mcg_xsh_rr_64_32;\ntypedef mcg_base<uint64_t, pcg128_t, xsh_rr_mixin>  mcg_xsh_rr_128_64;\ntypedef mcg_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>\n                                                    cm_mcg_xsh_rr_128_64;\n\n\n/* Predefined types for RXS M XS */\n\ntypedef oneseq_base<uint8_t,  uint8_t, rxs_m_xs_mixin>   oneseq_rxs_m_xs_8_8;\ntypedef oneseq_base<uint16_t, uint16_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_16_16;\ntypedef oneseq_base<uint32_t, uint32_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_32_32;\ntypedef oneseq_base<uint64_t, uint64_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_64_64;\ntypedef oneseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin>\n                                                        oneseq_rxs_m_xs_128_128;\ntypedef oneseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>\n                                                     cm_oneseq_rxs_m_xs_128_128;\n\ntypedef unique_base<uint8_t,  uint8_t, rxs_m_xs_mixin>  unique_rxs_m_xs_8_8;\ntypedef unique_base<uint16_t, uint16_t, rxs_m_xs_mixin> unique_rxs_m_xs_16_16;\ntypedef unique_base<uint32_t, uint32_t, rxs_m_xs_mixin> unique_rxs_m_xs_32_32;\ntypedef unique_base<uint64_t, uint64_t, rxs_m_xs_mixin> unique_rxs_m_xs_64_64;\ntypedef unique_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> unique_rxs_m_xs_128_128;\ntypedef unique_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>\n                                                     cm_unique_rxs_m_xs_128_128;\n\ntypedef setseq_base<uint8_t,  uint8_t, rxs_m_xs_mixin>  setseq_rxs_m_xs_8_8;\ntypedef setseq_base<uint16_t, uint16_t, rxs_m_xs_mixin> setseq_rxs_m_xs_16_16;\ntypedef setseq_base<uint32_t, uint32_t, rxs_m_xs_mixin> setseq_rxs_m_xs_32_32;\ntypedef setseq_base<uint64_t, uint64_t, rxs_m_xs_mixin> setseq_rxs_m_xs_64_64;\ntypedef setseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> setseq_rxs_m_xs_128_128;\ntypedef setseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>\n                                                     cm_setseq_rxs_m_xs_128_128;\n\n                // MCG versions don't make sense here, so aren't defined.\n\n/* Predefined types for RXS M */\n\ntypedef oneseq_base<uint8_t,  uint16_t, rxs_m_mixin>  oneseq_rxs_m_16_8;\ntypedef oneseq_base<uint16_t, uint32_t, rxs_m_mixin>  oneseq_rxs_m_32_16;\ntypedef oneseq_base<uint32_t, uint64_t, rxs_m_mixin>  oneseq_rxs_m_64_32;\ntypedef oneseq_base<uint64_t, pcg128_t, rxs_m_mixin>  oneseq_rxs_m_128_64;\ntypedef oneseq_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>\n                                                      cm_oneseq_rxs_m_128_64;\n\ntypedef unique_base<uint8_t,  uint16_t, rxs_m_mixin>  unique_rxs_m_16_8;\ntypedef unique_base<uint16_t, uint32_t, rxs_m_mixin>  unique_rxs_m_32_16;\ntypedef unique_base<uint32_t, uint64_t, rxs_m_mixin>  unique_rxs_m_64_32;\ntypedef unique_base<uint64_t, pcg128_t, rxs_m_mixin>  unique_rxs_m_128_64;\ntypedef unique_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>\n                                                      cm_unique_rxs_m_128_64;\n\ntypedef setseq_base<uint8_t,  uint16_t, rxs_m_mixin>  setseq_rxs_m_16_8;\ntypedef setseq_base<uint16_t, uint32_t, rxs_m_mixin>  setseq_rxs_m_32_16;\ntypedef setseq_base<uint32_t, uint64_t, rxs_m_mixin>  setseq_rxs_m_64_32;\ntypedef setseq_base<uint64_t, pcg128_t, rxs_m_mixin>  setseq_rxs_m_128_64;\ntypedef setseq_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>\n                                                      cm_setseq_rxs_m_128_64;\n\ntypedef mcg_base<uint8_t,  uint16_t, rxs_m_mixin>  mcg_rxs_m_16_8;\ntypedef mcg_base<uint16_t, uint32_t, rxs_m_mixin>  mcg_rxs_m_32_16;\ntypedef mcg_base<uint32_t, uint64_t, rxs_m_mixin>  mcg_rxs_m_64_32;\ntypedef mcg_base<uint64_t, pcg128_t, rxs_m_mixin>  mcg_rxs_m_128_64;\ntypedef mcg_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>\n                                                   cm_mcg_rxs_m_128_64;\n\n/* Predefined types for DXSM */\n\ntypedef oneseq_base<uint8_t,  uint16_t, dxsm_mixin>  oneseq_dxsm_16_8;\ntypedef oneseq_base<uint16_t, uint32_t, dxsm_mixin>  oneseq_dxsm_32_16;\ntypedef oneseq_base<uint32_t, uint64_t, dxsm_mixin>  oneseq_dxsm_64_32;\ntypedef oneseq_base<uint64_t, pcg128_t, dxsm_mixin>  oneseq_dxsm_128_64;\ntypedef oneseq_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>\n                                                     cm_oneseq_dxsm_128_64;\n\ntypedef unique_base<uint8_t,  uint16_t, dxsm_mixin>  unique_dxsm_16_8;\ntypedef unique_base<uint16_t, uint32_t, dxsm_mixin>  unique_dxsm_32_16;\ntypedef unique_base<uint32_t, uint64_t, dxsm_mixin>  unique_dxsm_64_32;\ntypedef unique_base<uint64_t, pcg128_t, dxsm_mixin>  unique_dxsm_128_64;\ntypedef unique_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>\n                                                     cm_unique_dxsm_128_64;\n\ntypedef setseq_base<uint8_t,  uint16_t, dxsm_mixin>  setseq_dxsm_16_8;\ntypedef setseq_base<uint16_t, uint32_t, dxsm_mixin>  setseq_dxsm_32_16;\ntypedef setseq_base<uint32_t, uint64_t, dxsm_mixin>  setseq_dxsm_64_32;\ntypedef setseq_base<uint64_t, pcg128_t, dxsm_mixin>  setseq_dxsm_128_64;\ntypedef setseq_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>\n                                                     cm_setseq_dxsm_128_64;\n\ntypedef mcg_base<uint8_t,  uint16_t, dxsm_mixin>  mcg_dxsm_16_8;\ntypedef mcg_base<uint16_t, uint32_t, dxsm_mixin>  mcg_dxsm_32_16;\ntypedef mcg_base<uint32_t, uint64_t, dxsm_mixin>  mcg_dxsm_64_32;\ntypedef mcg_base<uint64_t, pcg128_t, dxsm_mixin>  mcg_dxsm_128_64;\ntypedef mcg_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>\n                                                  cm_mcg_dxsm_128_64;\n\n/* Predefined types for XSL RR (only defined for \"large\" types) */\n\ntypedef oneseq_base<uint32_t, uint64_t, xsl_rr_mixin>  oneseq_xsl_rr_64_32;\ntypedef oneseq_base<uint64_t, pcg128_t, xsl_rr_mixin>  oneseq_xsl_rr_128_64;\ntypedef oneseq_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>\n                                                       cm_oneseq_xsl_rr_128_64;\n\ntypedef unique_base<uint32_t, uint64_t, xsl_rr_mixin>  unique_xsl_rr_64_32;\ntypedef unique_base<uint64_t, pcg128_t, xsl_rr_mixin>  unique_xsl_rr_128_64;\ntypedef unique_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>\n                                                       cm_unique_xsl_rr_128_64;\n\ntypedef setseq_base<uint32_t, uint64_t, xsl_rr_mixin>  setseq_xsl_rr_64_32;\ntypedef setseq_base<uint64_t, pcg128_t, xsl_rr_mixin>  setseq_xsl_rr_128_64;\ntypedef setseq_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>\n                                                       cm_setseq_xsl_rr_128_64;\n\ntypedef mcg_base<uint32_t, uint64_t, xsl_rr_mixin>  mcg_xsl_rr_64_32;\ntypedef mcg_base<uint64_t, pcg128_t, xsl_rr_mixin>  mcg_xsl_rr_128_64;\ntypedef mcg_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>\n                                                    cm_mcg_xsl_rr_128_64;\n\n\n/* Predefined types for XSL RR RR (only defined for \"large\" types) */\n\ntypedef oneseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin>\n    oneseq_xsl_rr_rr_64_64;\ntypedef oneseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>\n    oneseq_xsl_rr_rr_128_128;\ntypedef oneseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>\n    cm_oneseq_xsl_rr_rr_128_128;\n\ntypedef unique_base<uint64_t, uint64_t, xsl_rr_rr_mixin>\n    unique_xsl_rr_rr_64_64;\ntypedef unique_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>\n    unique_xsl_rr_rr_128_128;\ntypedef unique_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>\n    cm_unique_xsl_rr_rr_128_128;\n\ntypedef setseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin>\n    setseq_xsl_rr_rr_64_64;\ntypedef setseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>\n    setseq_xsl_rr_rr_128_128;\ntypedef setseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>\n    cm_setseq_xsl_rr_rr_128_128;\n\n                // MCG versions don't make sense here, so aren't defined.\n\n/* Extended generators */\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename BaseRNG, bool kdd = true>\nusing ext_std8 = extended<table_pow2, advance_pow2, BaseRNG,\n                          oneseq_rxs_m_xs_8_8, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename BaseRNG, bool kdd = true>\nusing ext_std16 = extended<table_pow2, advance_pow2, BaseRNG,\n                           oneseq_rxs_m_xs_16_16, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename BaseRNG, bool kdd = true>\nusing ext_std32 = extended<table_pow2, advance_pow2, BaseRNG,\n                           oneseq_rxs_m_xs_32_32, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2,\n          typename BaseRNG, bool kdd = true>\nusing ext_std64 = extended<table_pow2, advance_pow2, BaseRNG,\n                           oneseq_rxs_m_xs_64_64, kdd>;\n\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_oneseq_rxs_m_xs_32_32 =\n          ext_std32<table_pow2, advance_pow2, oneseq_rxs_m_xs_32_32, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_mcg_xsh_rs_64_32 =\n          ext_std32<table_pow2, advance_pow2, mcg_xsh_rs_64_32, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_oneseq_xsh_rs_64_32 =\n          ext_std32<table_pow2, advance_pow2, oneseq_xsh_rs_64_32, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_setseq_xsh_rr_64_32 =\n          ext_std32<table_pow2, advance_pow2, setseq_xsh_rr_64_32, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_mcg_xsl_rr_128_64 =\n          ext_std64<table_pow2, advance_pow2, mcg_xsl_rr_128_64, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_oneseq_xsl_rr_128_64 =\n          ext_std64<table_pow2, advance_pow2, oneseq_xsl_rr_128_64, kdd>;\n\ntemplate <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>\nusing ext_setseq_xsl_rr_128_64 =\n          ext_std64<table_pow2, advance_pow2, setseq_xsl_rr_128_64, kdd>;\n\n} // namespace pcg_engines\n\ntypedef pcg_engines::setseq_xsh_rr_64_32        pcg32;\ntypedef pcg_engines::oneseq_xsh_rr_64_32        pcg32_oneseq;\ntypedef pcg_engines::unique_xsh_rr_64_32        pcg32_unique;\ntypedef pcg_engines::mcg_xsh_rs_64_32           pcg32_fast;\n\ntypedef pcg_engines::setseq_xsl_rr_128_64       pcg64;\ntypedef pcg_engines::oneseq_xsl_rr_128_64       pcg64_oneseq;\ntypedef pcg_engines::unique_xsl_rr_128_64       pcg64_unique;\ntypedef pcg_engines::mcg_xsl_rr_128_64          pcg64_fast;\n\ntypedef pcg_engines::setseq_rxs_m_xs_8_8        pcg8_once_insecure;\ntypedef pcg_engines::setseq_rxs_m_xs_16_16      pcg16_once_insecure;\ntypedef pcg_engines::setseq_rxs_m_xs_32_32      pcg32_once_insecure;\ntypedef pcg_engines::setseq_rxs_m_xs_64_64      pcg64_once_insecure;\ntypedef pcg_engines::setseq_xsl_rr_rr_128_128   pcg128_once_insecure;\n\ntypedef pcg_engines::oneseq_rxs_m_xs_8_8        pcg8_oneseq_once_insecure;\ntypedef pcg_engines::oneseq_rxs_m_xs_16_16      pcg16_oneseq_once_insecure;\ntypedef pcg_engines::oneseq_rxs_m_xs_32_32      pcg32_oneseq_once_insecure;\ntypedef pcg_engines::oneseq_rxs_m_xs_64_64      pcg64_oneseq_once_insecure;\ntypedef pcg_engines::oneseq_xsl_rr_rr_128_128   pcg128_oneseq_once_insecure;\n\n\n// These two extended RNGs provide two-dimensionally equidistributed\n// 32-bit generators.  pcg32_k2_fast occupies the same space as pcg64,\n// and can be called twice to generate 64 bits, but does not required\n// 128-bit math; on 32-bit systems, it's faster than pcg64 as well.\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<1,16,true>     pcg32_k2;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<1,32,true>     pcg32_k2_fast;\n\n// These eight extended RNGs have about as much state as arc4random\n//\n//  - the k variants are k-dimensionally equidistributed\n//  - the c variants offer are intended to be harder to predict\n//\n// (neither is intended for use in cryptographic applications)\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true>     pcg32_k64;\ntypedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,true>        pcg32_k64_oneseq;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true>     pcg32_k64_fast;\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,false>    pcg32_c64;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,false>    pcg32_c64_oneseq;\ntypedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,false>       pcg32_c64_fast;\n\ntypedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,true>    pcg64_k32;\ntypedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,true>   pcg64_k32_oneseq;\ntypedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,true>      pcg64_k32_fast;\n\ntypedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,false>   pcg64_c32;\ntypedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,false>  pcg64_c32_oneseq;\ntypedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,false>     pcg64_c32_fast;\n\n// These eight extended RNGs have more state than the Mersenne twister\n//\n//  - the k variants are k-dimensionally equidistributed\n//  - the c variants offer are intended to be harder to predict\n//\n// (neither is intended for use in cryptographic applications)\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,true>    pcg32_k1024;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,true>    pcg32_k1024_fast;\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,false>   pcg32_c1024;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,false>   pcg32_c1024_fast;\n\ntypedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,true>   pcg64_k1024;\ntypedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,true>  pcg64_k1024_fast;\n\ntypedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,false>  pcg64_c1024;\ntypedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,false> pcg64_c1024_fast;\n\n// These generators have an insanely huge period (2^524352), and is suitable\n// for silly party tricks, such as dumping out 64 KB ZIP files at an arbitrary\n// point in the future.   [Actually, over the full period of the generator, it\n// will produce every 64 KB ZIP file 2^64 times!]\n\ntypedef pcg_engines::ext_setseq_xsh_rr_64_32<14,16,true>    pcg32_k16384;\ntypedef pcg_engines::ext_oneseq_xsh_rs_64_32<14,32,true>    pcg32_k16384_fast;\n\n#ifdef _MSC_VER\n    #pragma warning(default:4146)\n#endif\n\n#endif // PCG_RAND_HPP_INCLUDED\n"
  },
  {
    "path": "eidos/robin_hood.h",
    "content": "//                 ______  _____                 ______                _________\n//  ______________ ___  /_ ___(_)_______         ___  /_ ______ ______ ______  /\n//  __  ___/_  __ \\__  __ \\__  / __  __ \\        __  __ \\_  __ \\_  __ \\_  __  /\n//  _  /    / /_/ /_  /_/ /_  /  _  / / /        _  / / // /_/ // /_/ // /_/ /\n//  /_/     \\____/ /_.___/ /_/   /_/ /_/ ________/_/ /_/ \\____/ \\____/ \\__,_/\n//                                      _/_____/\n//\n// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20\n// https://github.com/martinus/robin-hood-hashing\n//\n// Licensed under the MIT License <http://opensource.org/licenses/MIT>.\n// SPDX-License-Identifier: MIT\n// Copyright (c) 2018-2021 Martin Ankerl <http://martin.ankerl.com>\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n#ifndef ROBIN_HOOD_H_INCLUDED\n#define ROBIN_HOOD_H_INCLUDED\n\n// see https://semver.org/\n#define ROBIN_HOOD_VERSION_MAJOR 3  // for incompatible API changes\n#define ROBIN_HOOD_VERSION_MINOR 11 // for adding functionality in a backwards-compatible manner\n#define ROBIN_HOOD_VERSION_PATCH 5  // for backwards-compatible bug fixes\n\n#include <algorithm>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <limits>\n#include <memory> // only to support hash of smart pointers\n#include <stdexcept>\n#include <string>\n#include <type_traits>\n#include <utility>\n#if __cplusplus >= 201703L\n#    include <string_view>\n#endif\n\n// #define ROBIN_HOOD_LOG_ENABLED\n#ifdef ROBIN_HOOD_LOG_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_LOG(...) \\\n        std::cout << __FUNCTION__ << \"@\" << __LINE__ << \": \" << __VA_ARGS__ << std::endl;\n#else\n#    define ROBIN_HOOD_LOG(x)\n#endif\n\n// #define ROBIN_HOOD_TRACE_ENABLED\n#ifdef ROBIN_HOOD_TRACE_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_TRACE(...) \\\n        std::cout << __FUNCTION__ << \"@\" << __LINE__ << \": \" << __VA_ARGS__ << std::endl;\n#else\n#    define ROBIN_HOOD_TRACE(x)\n#endif\n\n// #define ROBIN_HOOD_COUNT_ENABLED\n#ifdef ROBIN_HOOD_COUNT_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_COUNT(x) ++counts().x;\nnamespace robin_hood {\nstruct Counts {\n    uint64_t shiftUp{};\n    uint64_t shiftDown{};\n};\ninline std::ostream& operator<<(std::ostream& os, Counts const& c) {\n    return os << c.shiftUp << \" shiftUp\" << std::endl << c.shiftDown << \" shiftDown\" << std::endl;\n}\n\nstatic Counts& counts() {\n    static Counts counts{};\n    return counts;\n}\n} // namespace robin_hood\n#else\n#    define ROBIN_HOOD_COUNT(x)\n#endif\n\n// all non-argument macros should use this facility. See\n// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/\n#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()\n\n// mark unused members with this macro\n#define ROBIN_HOOD_UNUSED(identifier)\n\n// bitness\n#if SIZE_MAX == UINT32_MAX\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32\n#elif SIZE_MAX == UINT64_MAX\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64\n#else\n#    error Unsupported bitness\n#endif\n\n// endianess\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \\\n        (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#endif\n\n// inline\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))\n#endif\n\n// exceptions\n#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1\n#endif\n\n// count leading/trailing bits\n#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)\n#    ifdef _MSC_VER\n#        if ROBIN_HOOD(BITNESS) == 32\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward\n#        else\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64\n#        endif\n#        include <intrin.h>\n#        pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))\n#        define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x)                                       \\\n            [](size_t mask) noexcept -> int {                                             \\\n                unsigned long index;                                                      \\\n                return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \\\n                                                                : ROBIN_HOOD(BITNESS);    \\\n            }(x)\n#    else\n#        if ROBIN_HOOD(BITNESS) == 32\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl\n#        else\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll\n#        endif\n#        define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))\n#        define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))\n#    endif\n#endif\n\n// fallthrough\n#ifndef __has_cpp_attribute // For backwards compatibility\n#    define __has_cpp_attribute(x) 0\n#endif\n#if __has_cpp_attribute(clang::fallthrough)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]\n#elif __has_cpp_attribute(gnu::fallthrough)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()\n#endif\n\n// likely/unlikely\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_LIKELY(condition) condition\n#    define ROBIN_HOOD_UNLIKELY(condition) condition\n#else\n#    define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)\n#    define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)\n#endif\n\n// detect if native wchar_t type is availiable in MSVC\n#ifdef _MSC_VER\n#    ifdef _NATIVE_WCHAR_T_DEFINED\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1\n#    else\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0\n#    endif\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1\n#endif\n\n// detect if MSVC supports the pair(std::piecewise_construct_t,...) consructor being constexpr\n#ifdef _MSC_VER\n#    if _MSC_VER <= 1900\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1\n#    else\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0\n#    endif\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0\n#endif\n\n// workaround missing \"is_trivially_copyable\" in g++ < 5.0\n// See https://stackoverflow.com/a/31798726/48181\n#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)\n#    define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)\n#else\n#    define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value\n#endif\n\n// helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()\n#endif\n\nnamespace robin_hood {\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)\n#    define ROBIN_HOOD_STD std\n#else\n\n// c++11 compatibility layer\nnamespace ROBIN_HOOD_STD {\ntemplate <class T>\nstruct alignment_of\n    : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};\n\ntemplate <class T, T... Ints>\nclass integer_sequence {\npublic:\n    using value_type = T;\n    static_assert(std::is_integral<value_type>::value, \"not integral type\");\n    static constexpr std::size_t size() noexcept {\n        return sizeof...(Ints);\n    }\n};\ntemplate <std::size_t... Inds>\nusing index_sequence = integer_sequence<std::size_t, Inds...>;\n\nnamespace detail_ {\ntemplate <class T, T Begin, T End, bool>\nstruct IntSeqImpl {\n    using TValue = T;\n    static_assert(std::is_integral<TValue>::value, \"not integral type\");\n    static_assert(Begin >= 0 && Begin < End, \"unexpected argument (Begin<0 || Begin<=End)\");\n\n    template <class, class>\n    struct IntSeqCombiner;\n\n    template <TValue... Inds0, TValue... Inds1>\n    struct IntSeqCombiner<integer_sequence<TValue, Inds0...>, integer_sequence<TValue, Inds1...>> {\n        using TResult = integer_sequence<TValue, Inds0..., Inds1...>;\n    };\n\n    using TResult =\n        typename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,\n                                                    (End - Begin) / 2 == 1>::TResult,\n                                typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,\n                                                    (End - Begin + 1) / 2 == 1>::TResult>::TResult;\n};\n\ntemplate <class T, T Begin>\nstruct IntSeqImpl<T, Begin, Begin, false> {\n    using TValue = T;\n    static_assert(std::is_integral<TValue>::value, \"not integral type\");\n    static_assert(Begin >= 0, \"unexpected argument (Begin<0)\");\n    using TResult = integer_sequence<TValue>;\n};\n\ntemplate <class T, T Begin, T End>\nstruct IntSeqImpl<T, Begin, End, true> {\n    using TValue = T;\n    static_assert(std::is_integral<TValue>::value, \"not integral type\");\n    static_assert(Begin >= 0, \"unexpected argument (Begin<0)\");\n    using TResult = integer_sequence<TValue, Begin>;\n};\n} // namespace detail_\n\ntemplate <class T, T N>\nusing make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;\n\ntemplate <std::size_t N>\nusing make_index_sequence = make_integer_sequence<std::size_t, N>;\n\ntemplate <class... T>\nusing index_sequence_for = make_index_sequence<sizeof...(T)>;\n\n} // namespace ROBIN_HOOD_STD\n\n#endif\n\nnamespace detail {\n\n// make sure we static_cast to the correct type for hash_int\n#if ROBIN_HOOD(BITNESS) == 64\nusing SizeT = uint64_t;\n#else\nusing SizeT = uint32_t;\n#endif\n\ntemplate <typename T>\nT rotr(T x, unsigned k) {\n    return (x >> k) | (x << (8U * sizeof(T) - k));\n}\n\n// This cast gets rid of warnings like \"cast from 'uint8_t*' {aka 'unsigned char*'} to\n// 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type\". Use with\n// care!\ntemplate <typename T>\ninline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept {\n    return reinterpret_cast<T>(ptr);\n}\n\ntemplate <typename T>\ninline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept {\n    return reinterpret_cast<T>(ptr);\n}\n\n// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other\n// inlinings more difficult. Throws are also generally the slow path.\ntemplate <typename E, typename... Args>\n[[noreturn]] ROBIN_HOOD(NOINLINE)\n#if ROBIN_HOOD(HAS_EXCEPTIONS)\n    void doThrow(Args&&... args) {\n    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)\n    throw E(std::forward<Args>(args)...);\n}\n#else\n    void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {\n    abort();\n}\n#endif\n\ntemplate <typename E, typename T, typename... Args>\nT* assertNotNull(T* t, Args&&... args) {\n    if (ROBIN_HOOD_UNLIKELY(nullptr == t)) {\n        doThrow<E>(std::forward<Args>(args)...);\n    }\n    return t;\n}\n\ntemplate <typename T>\ninline T unaligned_load(void const* ptr) noexcept {\n    // using memcpy so we don't get into unaligned load problems.\n    // compiler should optimize this very well anyways.\n    T t;\n    std::memcpy(&t, ptr, sizeof(T));\n    return t;\n}\n\n// Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor,\n// and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a\n// pointer.\ntemplate <typename T, size_t MinNumAllocs = 4, size_t MaxNumAllocs = 256>\nclass BulkPoolAllocator {\npublic:\n    BulkPoolAllocator() noexcept = default;\n\n    // does not copy anything, just creates a new allocator.\n    BulkPoolAllocator(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept\n        : mHead(nullptr)\n        , mListForFree(nullptr) {}\n\n    BulkPoolAllocator(BulkPoolAllocator&& o) noexcept\n        : mHead(o.mHead)\n        , mListForFree(o.mListForFree) {\n        o.mListForFree = nullptr;\n        o.mHead = nullptr;\n    }\n\n    BulkPoolAllocator& operator=(BulkPoolAllocator&& o) noexcept {\n        reset();\n        mHead = o.mHead;\n        mListForFree = o.mListForFree;\n        o.mListForFree = nullptr;\n        o.mHead = nullptr;\n        return *this;\n    }\n\n    BulkPoolAllocator&\n    // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)\n    operator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept {\n        // does not do anything\n        return *this;\n    }\n\n    ~BulkPoolAllocator() noexcept {\n        reset();\n    }\n\n    // Deallocates all allocated memory.\n    void reset() noexcept {\n        while (mListForFree) {\n            T* tmp = *mListForFree;\n            ROBIN_HOOD_LOG(\"std::free\")\n            std::free(mListForFree);\n            mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);\n        }\n        mHead = nullptr;\n    }\n\n    // allocates, but does NOT initialize. Use in-place new constructor, e.g.\n    //   T* obj = pool.allocate();\n    //   ::new (static_cast<void*>(obj)) T();\n    T* allocate() {\n        T* tmp = mHead;\n        if (!tmp) {\n            tmp = performAllocation();\n        }\n\n        mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);\n        return tmp;\n    }\n\n    // does not actually deallocate but puts it in store.\n    // make sure you have already called the destructor! e.g. with\n    //  obj->~T();\n    //  pool.deallocate(obj);\n    void deallocate(T* obj) noexcept {\n        *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;\n        mHead = obj;\n    }\n\n    // Adds an already allocated block of memory to the allocator. This allocator is from now on\n    // responsible for freeing the data (with free()). If the provided data is not large enough to\n    // make use of, it is immediately freed. Otherwise it is reused and freed in the destructor.\n    void addOrFree(void* ptr, const size_t numBytes) noexcept {\n        // calculate number of available elements in ptr\n        if (numBytes < ALIGNMENT + ALIGNED_SIZE) {\n            // not enough data for at least one element. Free and return.\n            ROBIN_HOOD_LOG(\"std::free\")\n            std::free(ptr);\n        } else {\n            ROBIN_HOOD_LOG(\"add to buffer\")\n            add(ptr, numBytes);\n        }\n    }\n\n    void swap(BulkPoolAllocator<T, MinNumAllocs, MaxNumAllocs>& other) noexcept {\n        using std::swap;\n        swap(mHead, other.mHead);\n        swap(mListForFree, other.mListForFree);\n    }\n\nprivate:\n    // iterates the list of allocated memory to calculate how many to alloc next.\n    // Recalculating this each time saves us a size_t member.\n    // This ignores the fact that memory blocks might have been added manually with addOrFree. In\n    // practice, this should not matter much.\n    ROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept {\n        auto tmp = mListForFree;\n        size_t numAllocs = MinNumAllocs;\n\n        while (numAllocs * 2 <= MaxNumAllocs && tmp) {\n            auto x = reinterpret_cast<T***>(tmp);\n            tmp = *x;\n            numAllocs *= 2;\n        }\n\n        return numAllocs;\n    }\n\n    // WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree().\n    void add(void* ptr, const size_t numBytes) noexcept {\n        const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;\n\n        auto data = reinterpret_cast<T**>(ptr);\n\n        // link free list\n        auto x = reinterpret_cast<T***>(data);\n        *x = mListForFree;\n        mListForFree = data;\n\n        // create linked list for newly allocated data\n        auto* const headT =\n            reinterpret_cast_no_cast_align_warning<T*>(reinterpret_cast<char*>(ptr) + ALIGNMENT);\n\n        auto* const head = reinterpret_cast<char*>(headT);\n\n        // Visual Studio compiler automatically unrolls this loop, which is pretty cool\n        for (size_t i = 0; i < numElements; ++i) {\n            *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =\n                head + (i + 1) * ALIGNED_SIZE;\n        }\n\n        // last one points to 0\n        *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =\n            mHead;\n        mHead = headT;\n    }\n\n    // Called when no memory is available (mHead == 0).\n    // Don't inline this slow path.\n    ROBIN_HOOD(NOINLINE) T* performAllocation() {\n        size_t const numElementsToAlloc = calcNumElementsToAlloc();\n\n        // alloc new memory: [prev |T, T, ... T]\n        size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;\n        ROBIN_HOOD_LOG(\"std::malloc \" << bytes << \" = \" << ALIGNMENT << \" + \" << ALIGNED_SIZE\n                                      << \" * \" << numElementsToAlloc)\n        add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);\n        return mHead;\n    }\n\n    // enforce byte alignment of the T's\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)\n    static constexpr size_t ALIGNMENT =\n        (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);\n#else\n    static const size_t ALIGNMENT =\n        (ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)\n            ? ROBIN_HOOD_STD::alignment_of<T>::value\n            : +ROBIN_HOOD_STD::alignment_of<T*>::value; // the + is for walkarround\n#endif\n\n    static constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;\n\n    static_assert(MinNumAllocs >= 1, \"MinNumAllocs\");\n    static_assert(MaxNumAllocs >= MinNumAllocs, \"MaxNumAllocs\");\n    static_assert(ALIGNED_SIZE >= sizeof(T*), \"ALIGNED_SIZE\");\n    static_assert(0 == (ALIGNED_SIZE % sizeof(T*)), \"ALIGNED_SIZE mod\");\n    static_assert(ALIGNMENT >= sizeof(T*), \"ALIGNMENT\");\n\n    T* mHead{nullptr};\n    T** mListForFree{nullptr};\n};\n\ntemplate <typename T, size_t MinSize, size_t MaxSize, bool IsFlat>\nstruct NodeAllocator;\n\n// dummy allocator that does nothing\ntemplate <typename T, size_t MinSize, size_t MaxSize>\nstruct NodeAllocator<T, MinSize, MaxSize, true> {\n\n    // we are not using the data, so just free it.\n    void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept {\n        ROBIN_HOOD_LOG(\"std::free\")\n        std::free(ptr);\n    }\n};\n\ntemplate <typename T, size_t MinSize, size_t MaxSize>\nstruct NodeAllocator<T, MinSize, MaxSize, false> : public BulkPoolAllocator<T, MinSize, MaxSize> {};\n\n// c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making\n// my own here.\nnamespace swappable {\n#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)\nusing std::swap;\ntemplate <typename T>\nstruct nothrow {\n    static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));\n};\n#else\ntemplate <typename T>\nstruct nothrow {\n    static const bool value = std::is_nothrow_swappable<T>::value;\n};\n#endif\n} // namespace swappable\n\n} // namespace detail\n\nstruct is_transparent_tag {};\n\n// A custom pair implementation is used in the map because std::pair is not is_trivially_copyable,\n// which means it would  not be allowed to be used in std::memcpy. This struct is copyable, which is\n// also tested.\ntemplate <typename T1, typename T2>\nstruct pair {\n    using first_type = T1;\n    using second_type = T2;\n\n    template <typename U1 = T1, typename U2 = T2,\n              typename = typename std::enable_if<std::is_default_constructible<U1>::value &&\n                                                 std::is_default_constructible<U2>::value>::type>\n    constexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))\n        : first()\n        , second() {}\n\n    // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.\n    explicit constexpr pair(std::pair<T1, T2> const& o) noexcept(\n        noexcept(T1(std::declval<T1 const&>())) && noexcept(T2(std::declval<T2 const&>())))\n        : first(o.first)\n        , second(o.second) {}\n\n    // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.\n    explicit constexpr pair(std::pair<T1, T2>&& o) noexcept(noexcept(\n        T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))\n        : first(std::move(o.first))\n        , second(std::move(o.second)) {}\n\n    constexpr pair(T1&& a, T2&& b) noexcept(noexcept(\n        T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))\n        : first(std::move(a))\n        , second(std::move(b)) {}\n\n    template <typename U1, typename U2>\n    constexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward<U1>(\n        std::declval<U1&&>()))) && noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))\n        : first(std::forward<U1>(a))\n        , second(std::forward<U2>(b)) {}\n\n    template <typename... U1, typename... U2>\n    // MSVC 2015 produces error \"C2476: ‘constexpr’ constructor does not initialize all members\"\n    // if this constructor is constexpr\n#if !ROBIN_HOOD(BROKEN_CONSTEXPR)\n    constexpr\n#endif\n        pair(std::piecewise_construct_t /*unused*/, std::tuple<U1...> a,\n             std::tuple<U2...>\n                 b) noexcept(noexcept(pair(std::declval<std::tuple<U1...>&>(),\n                                           std::declval<std::tuple<U2...>&>(),\n                                           ROBIN_HOOD_STD::index_sequence_for<U1...>(),\n                                           ROBIN_HOOD_STD::index_sequence_for<U2...>())))\n        : pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),\n               ROBIN_HOOD_STD::index_sequence_for<U2...>()) {\n    }\n\n    // constructor called from the std::piecewise_construct_t ctor\n    template <typename... U1, size_t... I1, typename... U2, size_t... I2>\n    pair(std::tuple<U1...>& a, std::tuple<U2...>& b, ROBIN_HOOD_STD::index_sequence<I1...> /*unused*/, ROBIN_HOOD_STD::index_sequence<I2...> /*unused*/) noexcept(\n        noexcept(T1(std::forward<U1>(std::get<I1>(\n            std::declval<std::tuple<\n                U1...>&>()))...)) && noexcept(T2(std::\n                                                     forward<U2>(std::get<I2>(\n                                                         std::declval<std::tuple<U2...>&>()))...)))\n        : first(std::forward<U1>(std::get<I1>(a))...)\n        , second(std::forward<U2>(std::get<I2>(b))...) {\n        // make visual studio compiler happy about warning about unused a & b.\n        // Visual studio's pair implementation disables warning 4100.\n        (void)a;\n        (void)b;\n    }\n\n    void swap(pair<T1, T2>& o) noexcept((detail::swappable::nothrow<T1>::value) &&\n                                        (detail::swappable::nothrow<T2>::value)) {\n        using std::swap;\n        swap(first, o.first);\n        swap(second, o.second);\n    }\n\n    T1 first;  // NOLINT(misc-non-private-member-variables-in-classes)\n    T2 second; // NOLINT(misc-non-private-member-variables-in-classes)\n};\n\ntemplate <typename A, typename B>\ninline void swap(pair<A, B>& a, pair<A, B>& b) noexcept(\n    noexcept(std::declval<pair<A, B>&>().swap(std::declval<pair<A, B>&>()))) {\n    a.swap(b);\n}\n\ntemplate <typename A, typename B>\ninline constexpr bool operator==(pair<A, B> const& x, pair<A, B> const& y) {\n    return (x.first == y.first) && (x.second == y.second);\n}\ntemplate <typename A, typename B>\ninline constexpr bool operator!=(pair<A, B> const& x, pair<A, B> const& y) {\n    return !(x == y);\n}\ntemplate <typename A, typename B>\ninline constexpr bool operator<(pair<A, B> const& x, pair<A, B> const& y) noexcept(noexcept(\n    std::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <\n                                                                     std::declval<B const&>())) {\n    return x.first < y.first || (!(y.first < x.first) && x.second < y.second);\n}\ntemplate <typename A, typename B>\ninline constexpr bool operator>(pair<A, B> const& x, pair<A, B> const& y) {\n    return y < x;\n}\ntemplate <typename A, typename B>\ninline constexpr bool operator<=(pair<A, B> const& x, pair<A, B> const& y) {\n    return !(x > y);\n}\ntemplate <typename A, typename B>\ninline constexpr bool operator>=(pair<A, B> const& x, pair<A, B> const& y) {\n    return !(x < y);\n}\n\ninline size_t hash_bytes(void const* ptr, size_t len) noexcept {\n    static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);\n    static constexpr uint64_t seed = UINT64_C(0xe17a1465);\n    static constexpr unsigned int r = 47;\n\n    auto const* const data64 = static_cast<uint64_t const*>(ptr);\n    uint64_t h = seed ^ (len * m);\n\n    size_t const n_blocks = len / 8;\n    for (size_t i = 0; i < n_blocks; ++i) {\n        auto k = detail::unaligned_load<uint64_t>(data64 + i);\n\n        k *= m;\n        k ^= k >> r;\n        k *= m;\n\n        h ^= k;\n        h *= m;\n    }\n\n    auto const* const data8 = reinterpret_cast<uint8_t const*>(data64 + n_blocks);\n    switch (len & 7U) {\n    case 7:\n        h ^= static_cast<uint64_t>(data8[6]) << 48U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 6:\n        h ^= static_cast<uint64_t>(data8[5]) << 40U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 5:\n        h ^= static_cast<uint64_t>(data8[4]) << 32U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 4:\n        h ^= static_cast<uint64_t>(data8[3]) << 24U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 3:\n        h ^= static_cast<uint64_t>(data8[2]) << 16U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 2:\n        h ^= static_cast<uint64_t>(data8[1]) << 8U;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    case 1:\n        h ^= static_cast<uint64_t>(data8[0]);\n        h *= m;\n        ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n    default:\n        break;\n    }\n\n    h ^= h >> r;\n\n    // not doing the final step here, because this will be done by keyToIdx anyways\n    // h *= m;\n    // h ^= h >> r;\n    return static_cast<size_t>(h);\n}\n\ninline size_t hash_int(uint64_t x) noexcept {\n    // tried lots of different hashes, let's stick with murmurhash3. It's simple, fast, well tested,\n    // and doesn't need any special 128bit operations.\n    x ^= x >> 33U;\n    x *= UINT64_C(0xff51afd7ed558ccd);\n    x ^= x >> 33U;\n\n    // not doing the final step here, because this will be done by keyToIdx anyways\n    // x *= UINT64_C(0xc4ceb9fe1a85ec53);\n    // x ^= x >> 33U;\n    return static_cast<size_t>(x);\n}\n\n// A thin wrapper around std::hash, performing an additional simple mixing step of the result.\ntemplate <typename T, typename Enable = void>\nstruct hash : public std::hash<T> {\n    size_t operator()(T const& obj) const\n        noexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>()))) {\n        // call base hash\n        auto result = std::hash<T>::operator()(obj);\n        // return mixed of that, to be save against identity has\n        return hash_int(static_cast<detail::SizeT>(result));\n    }\n};\n\ntemplate <typename CharT>\nstruct hash<std::basic_string<CharT>> {\n    size_t operator()(std::basic_string<CharT> const& str) const noexcept {\n        return hash_bytes(str.data(), sizeof(CharT) * str.size());\n    }\n};\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)\ntemplate <typename CharT>\nstruct hash<std::basic_string_view<CharT>> {\n    size_t operator()(std::basic_string_view<CharT> const& sv) const noexcept {\n        return hash_bytes(sv.data(), sizeof(CharT) * sv.size());\n    }\n};\n#endif\n\ntemplate <class T>\nstruct hash<T*> {\n    size_t operator()(T* ptr) const noexcept {\n        return hash_int(reinterpret_cast<detail::SizeT>(ptr));\n    }\n};\n\ntemplate <class T>\nstruct hash<std::unique_ptr<T>> {\n    size_t operator()(std::unique_ptr<T> const& ptr) const noexcept {\n        return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));\n    }\n};\n\ntemplate <class T>\nstruct hash<std::shared_ptr<T>> {\n    size_t operator()(std::shared_ptr<T> const& ptr) const noexcept {\n        return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));\n    }\n};\n\ntemplate <typename Enum>\nstruct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {\n    size_t operator()(Enum e) const noexcept {\n        using Underlying = typename std::underlying_type<Enum>::type;\n        return hash<Underlying>{}(static_cast<Underlying>(e));\n    }\n};\n\n#define ROBIN_HOOD_HASH_INT(T)                           \\\n    template <>                                          \\\n    struct hash<T> {                                     \\\n        size_t operator()(T const& obj) const noexcept { \\\n            return hash_int(static_cast<uint64_t>(obj)); \\\n        }                                                \\\n    }\n\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic push\n#    pragma GCC diagnostic ignored \"-Wuseless-cast\"\n#endif\n// see https://en.cppreference.com/w/cpp/utility/hash\nROBIN_HOOD_HASH_INT(bool);\nROBIN_HOOD_HASH_INT(char);\nROBIN_HOOD_HASH_INT(signed char);\nROBIN_HOOD_HASH_INT(unsigned char);\nROBIN_HOOD_HASH_INT(char16_t);\nROBIN_HOOD_HASH_INT(char32_t);\n#if ROBIN_HOOD(HAS_NATIVE_WCHART)\nROBIN_HOOD_HASH_INT(wchar_t);\n#endif\nROBIN_HOOD_HASH_INT(short);\nROBIN_HOOD_HASH_INT(unsigned short);\nROBIN_HOOD_HASH_INT(int);\nROBIN_HOOD_HASH_INT(unsigned int);\nROBIN_HOOD_HASH_INT(long);\nROBIN_HOOD_HASH_INT(long long);\nROBIN_HOOD_HASH_INT(unsigned long);\nROBIN_HOOD_HASH_INT(unsigned long long);\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic pop\n#endif\nnamespace detail {\n\ntemplate <typename T>\nstruct void_type {\n    using type = void;\n};\n\ntemplate <typename T, typename = void>\nstruct has_is_transparent : public std::false_type {};\n\ntemplate <typename T>\nstruct has_is_transparent<T, typename void_type<typename T::is_transparent>::type>\n    : public std::true_type {};\n\n// using wrapper classes for hash and key_equal prevents the diamond problem when the same type\n// is used. see https://stackoverflow.com/a/28771920/48181\ntemplate <typename T>\nstruct WrapHash : public T {\n    WrapHash() = default;\n    explicit WrapHash(T const& o) noexcept(noexcept(T(std::declval<T const&>())))\n        : T(o) {}\n};\n\ntemplate <typename T>\nstruct WrapKeyEqual : public T {\n    WrapKeyEqual() = default;\n    explicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval<T const&>())))\n        : T(o) {}\n};\n\n// A highly optimized hashmap implementation, using the Robin Hood algorithm.\n//\n// In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but\n// be about 2x faster in most cases and require much less allocations.\n//\n// This implementation uses the following memory layout:\n//\n// [Node, Node, ... Node | info, info, ... infoSentinel ]\n//\n// * Node: either a DataNode that directly has the std::pair<key, val> as member,\n//   or a DataNode with a pointer to std::pair<key,val>. Which DataNode representation to use\n//   depends on how fast the swap() operation is. Heuristically, this is automatically choosen\n//   based on sizeof(). there are always 2^n Nodes.\n//\n// * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes.\n//   Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the\n//   corresponding node contains data. Set to 2 means the corresponding Node is filled, but it\n//   actually belongs to the previous position and was pushed out because that place is already\n//   taken.\n//\n// * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the\n//   need for a idx variable.\n//\n// According to STL, order of templates has effect on throughput. That's why I've moved the\n// boolean to the front.\n// https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/\ntemplate <bool IsFlat, size_t MaxLoadFactor100, typename Key, typename T, typename Hash,\n          typename KeyEqual>\nclass Table\n    : public WrapHash<Hash>,\n      public WrapKeyEqual<KeyEqual>,\n      detail::NodeAllocator<\n          typename std::conditional<\n              std::is_void<T>::value, Key,\n              robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,\n          4, 16384, IsFlat> {\npublic:\n    static constexpr bool is_flat = IsFlat;\n    static constexpr bool is_map = !std::is_void<T>::value;\n    static constexpr bool is_set = !is_map;\n    static constexpr bool is_transparent =\n        has_is_transparent<Hash>::value && has_is_transparent<KeyEqual>::value;\n\n    using key_type = Key;\n    using mapped_type = T;\n    using value_type = typename std::conditional<\n        is_set, Key,\n        robin_hood::pair<typename std::conditional<is_flat, Key, Key const>::type, T>>::type;\n    using size_type = size_t;\n    using hasher = Hash;\n    using key_equal = KeyEqual;\n    using Self = Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;\n\nprivate:\n    static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,\n                  \"MaxLoadFactor100 needs to be >10 && < 100\");\n\n    using WHash = WrapHash<Hash>;\n    using WKeyEqual = WrapKeyEqual<KeyEqual>;\n\n    // configuration defaults\n\n    // make sure we have 8 elements, needed to quickly rehash mInfo\n    static constexpr size_t InitialNumElements = sizeof(uint64_t);\n    static constexpr uint32_t InitialInfoNumBits = 5;\n    static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;\n    static constexpr size_t InfoMask = InitialInfoInc - 1U;\n    static constexpr uint8_t InitialInfoHashShift = 0;\n    using DataPool = detail::NodeAllocator<value_type, 4, 16384, IsFlat>;\n\n    // type needs to be wider than uint8_t.\n    using InfoType = uint32_t;\n\n    // DataNode ////////////////////////////////////////////////////////\n\n    // Primary template for the data node. We have special implementations for small and big\n    // objects. For large objects it is assumed that swap() is fairly slow, so we allocate these\n    // on the heap so swap merely swaps a pointer.\n    template <typename M, bool>\n    class DataNode {};\n\n    // Small: just allocate on the stack.\n    template <typename M>\n    class DataNode<M, true> final {\n    public:\n        template <typename... Args>\n        explicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept(\n            noexcept(value_type(std::forward<Args>(args)...)))\n            : mData(std::forward<Args>(args)...) {}\n\n        DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, true>&& n) noexcept(\n            std::is_nothrow_move_constructible<value_type>::value)\n            : mData(std::move(n.mData)) {}\n\n        // doesn't do anything\n        void destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {}\n        void destroyDoNotDeallocate() noexcept {}\n\n        value_type const* operator->() const noexcept {\n            return &mData;\n        }\n        value_type* operator->() noexcept {\n            return &mData;\n        }\n\n        const value_type& operator*() const noexcept {\n            return mData;\n        }\n\n        value_type& operator*() noexcept {\n            return mData;\n        }\n\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {\n            return mData.first;\n        }\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_set, VT&>::type getFirst() noexcept {\n            return mData;\n        }\n\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, typename VT::first_type const&>::type\n            getFirst() const noexcept {\n            return mData.first;\n        }\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {\n            return mData;\n        }\n\n        template <typename MT = mapped_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, MT&>::type getSecond() noexcept {\n            return mData.second;\n        }\n\n        template <typename MT = mapped_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {\n            return mData.second;\n        }\n\n        void swap(DataNode<M, true>& o) noexcept(\n            noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {\n            mData.swap(o.mData);\n        }\n\n    private:\n        value_type mData;\n    };\n\n    // big object: allocate on heap.\n    template <typename M>\n    class DataNode<M, false> {\n    public:\n        template <typename... Args>\n        explicit DataNode(M& map, Args&&... args)\n            : mData(map.allocate()) {\n            ::new (static_cast<void*>(mData)) value_type(std::forward<Args>(args)...);\n        }\n\n        DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, false>&& n) noexcept\n            : mData(std::move(n.mData)) {}\n\n        void destroy(M& map) noexcept {\n            // don't deallocate, just put it into list of datapool.\n            mData->~value_type();\n            map.deallocate(mData);\n        }\n\n        void destroyDoNotDeallocate() noexcept {\n            mData->~value_type();\n        }\n\n        value_type const* operator->() const noexcept {\n            return mData;\n        }\n\n        value_type* operator->() noexcept {\n            return mData;\n        }\n\n        const value_type& operator*() const {\n            return *mData;\n        }\n\n        value_type& operator*() {\n            return *mData;\n        }\n\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {\n            return mData->first;\n        }\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_set, VT&>::type getFirst() noexcept {\n            return *mData;\n        }\n\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, typename VT::first_type const&>::type\n            getFirst() const noexcept {\n            return mData->first;\n        }\n        template <typename VT = value_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {\n            return *mData;\n        }\n\n        template <typename MT = mapped_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, MT&>::type getSecond() noexcept {\n            return mData->second;\n        }\n\n        template <typename MT = mapped_type>\n        ROBIN_HOOD(NODISCARD)\n        typename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {\n            return mData->second;\n        }\n\n        void swap(DataNode<M, false>& o) noexcept {\n            using std::swap;\n            swap(mData, o.mData);\n        }\n\n    private:\n        value_type* mData;\n    };\n\n    using Node = DataNode<Self, IsFlat>;\n\n    // helpers for insertKeyPrepareEmptySpot: extract first entry (only const required)\n    ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept {\n        return n.getFirst();\n    }\n\n    // in case we have void mapped_type, we are not using a pair, thus we just route k through.\n    // No need to disable this because it's just not used if not applicable.\n    ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept {\n        return k;\n    }\n\n    // in case we have non-void mapped_type, we have a standard robin_hood::pair\n    template <typename Q = mapped_type>\n    ROBIN_HOOD(NODISCARD)\n    typename std::enable_if<!std::is_void<Q>::value, key_type const&>::type\n        getFirstConst(value_type const& vt) const noexcept {\n        return vt.first;\n    }\n\n    // Cloner //////////////////////////////////////////////////////////\n\n    template <typename M, bool UseMemcpy>\n    struct Cloner;\n\n    // fast path: Just copy data, without allocating anything.\n    template <typename M>\n    struct Cloner<M, true> {\n        void operator()(M const& source, M& target) const {\n            auto const* const src = reinterpret_cast<char const*>(source.mKeyVals);\n            auto* tgt = reinterpret_cast<char*>(target.mKeyVals);\n            auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);\n            std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);\n        }\n    };\n\n    template <typename M>\n    struct Cloner<M, false> {\n        void operator()(M const& s, M& t) const {\n            auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);\n            std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);\n\n            for (size_t i = 0; i < numElementsWithBuffer; ++i) {\n                if (t.mInfo[i]) {\n                    ::new (static_cast<void*>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);\n                }\n            }\n        }\n    };\n\n    // Destroyer ///////////////////////////////////////////////////////\n\n    template <typename M, bool IsFlatAndTrivial>\n    struct Destroyer {};\n\n    template <typename M>\n    struct Destroyer<M, true> {\n        void nodes(M& m) const noexcept {\n            m.mNumElements = 0;\n        }\n\n        void nodesDoNotDeallocate(M& m) const noexcept {\n            m.mNumElements = 0;\n        }\n    };\n\n    template <typename M>\n    struct Destroyer<M, false> {\n        void nodes(M& m) const noexcept {\n            m.mNumElements = 0;\n            // clear also resets mInfo to 0, that's sometimes not necessary.\n            auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);\n\n            for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {\n                if (0 != m.mInfo[idx]) {\n                    Node& n = m.mKeyVals[idx];\n                    n.destroy(m);\n                    n.~Node();\n                }\n            }\n        }\n\n        void nodesDoNotDeallocate(M& m) const noexcept {\n            m.mNumElements = 0;\n            // clear also resets mInfo to 0, that's sometimes not necessary.\n            auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);\n            for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {\n                if (0 != m.mInfo[idx]) {\n                    Node& n = m.mKeyVals[idx];\n                    n.destroyDoNotDeallocate();\n                    n.~Node();\n                }\n            }\n        }\n    };\n\n    // Iter ////////////////////////////////////////////////////////////\n\n    struct fast_forward_tag {};\n\n    // generic iterator for both const_iterator and iterator.\n    template <bool IsConst>\n    // NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions)\n    class Iter {\n    private:\n        using NodePtr = typename std::conditional<IsConst, Node const*, Node*>::type;\n\n    public:\n        using difference_type = std::ptrdiff_t;\n        using value_type = typename Self::value_type;\n        using reference = typename std::conditional<IsConst, value_type const&, value_type&>::type;\n        using pointer = typename std::conditional<IsConst, value_type const*, value_type*>::type;\n        using iterator_category = std::forward_iterator_tag;\n\n        // default constructed iterator can be compared to itself, but WON'T return true when\n        // compared to end().\n        Iter() = default;\n\n        // Rule of zero: nothing specified. The conversion constructor is only enabled for\n        // iterator to const_iterator, so it doesn't accidentally work as a copy ctor.\n\n        // Conversion constructor from iterator to const_iterator.\n        template <bool OtherIsConst,\n                  typename = typename std::enable_if<IsConst && !OtherIsConst>::type>\n        // NOLINTNEXTLINE(hicpp-explicit-conversions)\n        Iter(Iter<OtherIsConst> const& other) noexcept\n            : mKeyVals(other.mKeyVals)\n            , mInfo(other.mInfo) {}\n\n        Iter(NodePtr valPtr, uint8_t const* infoPtr) noexcept\n            : mKeyVals(valPtr)\n            , mInfo(infoPtr) {}\n\n        Iter(NodePtr valPtr, uint8_t const* infoPtr,\n             fast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept\n            : mKeyVals(valPtr)\n            , mInfo(infoPtr) {\n            fastForward();\n        }\n\n        template <bool OtherIsConst,\n                  typename = typename std::enable_if<IsConst && !OtherIsConst>::type>\n        Iter& operator=(Iter<OtherIsConst> const& other) noexcept {\n            mKeyVals = other.mKeyVals;\n            mInfo = other.mInfo;\n            return *this;\n        }\n\n        // prefix increment. Undefined behavior if we are at end()!\n        Iter& operator++() noexcept {\n            mInfo++;\n            mKeyVals++;\n            fastForward();\n            return *this;\n        }\n\n        Iter operator++(int) noexcept {\n            Iter tmp = *this;\n            ++(*this);\n            return tmp;\n        }\n\n        reference operator*() const {\n            return **mKeyVals;\n        }\n\n        pointer operator->() const {\n            return &**mKeyVals;\n        }\n\n        template <bool O>\n        bool operator==(Iter<O> const& o) const noexcept {\n            return mKeyVals == o.mKeyVals;\n        }\n\n        template <bool O>\n        bool operator!=(Iter<O> const& o) const noexcept {\n            return mKeyVals != o.mKeyVals;\n        }\n\n    private:\n        // fast forward to the next non-free info byte\n        // I've tried a few variants that don't depend on intrinsics, but unfortunately they are\n        // quite a bit slower than this one. So I've reverted that change again. See map_benchmark.\n        void fastForward() noexcept {\n            size_t n = 0;\n            while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {\n                mInfo += sizeof(size_t);\n                mKeyVals += sizeof(size_t);\n            }\n#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)\n            // we know for certain that within the next 8 bytes we'll find a non-zero one.\n            if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {\n                mInfo += 4;\n                mKeyVals += 4;\n            }\n            if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {\n                mInfo += 2;\n                mKeyVals += 2;\n            }\n            if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {\n                mInfo += 1;\n                mKeyVals += 1;\n            }\n#else\n#    if ROBIN_HOOD(LITTLE_ENDIAN)\n            auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;\n#    else\n            auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;\n#    endif\n            mInfo += inc;\n            mKeyVals += inc;\n#endif\n        }\n\n        friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;\n        NodePtr mKeyVals{nullptr};\n        uint8_t const* mInfo{nullptr};\n    };\n\n    ////////////////////////////////////////////////////////////////////\n\n    // highly performance relevant code.\n    // Lower bits are used for indexing into the array (2^n size)\n    // The upper 1-5 bits need to be a reasonable good hash, to save comparisons.\n    template <typename HashKey>\n    void keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const {\n        // In addition to whatever hash is used, add another mul & shift so we get better hashing.\n        // This serves as a bad hash prevention, if the given data is\n        // badly mixed.\n        auto h = static_cast<uint64_t>(WHash::operator()(key));\n\n        h *= mHashMultiplier;\n        h ^= h >> 33U;\n\n        // the lower InitialInfoNumBits are reserved for info.\n        *info = mInfoInc + static_cast<InfoType>((h & InfoMask) >> mInfoHashShift);\n        *idx = (static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;\n    }\n\n    // forwards the index by one, wrapping around at the end\n    void next(InfoType* info, size_t* idx) const noexcept {\n        *idx = *idx + 1;\n        *info += mInfoInc;\n    }\n\n    void nextWhileLess(InfoType* info, size_t* idx) const noexcept {\n        // unrolling this by hand did not bring any speedups.\n        while (*info < mInfo[*idx]) {\n            next(info, idx);\n        }\n    }\n\n    // Shift everything up by one element. Tries to move stuff around.\n    void\n    shiftUp(size_t startIdx,\n            size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {\n        auto idx = startIdx;\n        ::new (static_cast<void*>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));\n        while (--idx != insertion_idx) {\n            mKeyVals[idx] = std::move(mKeyVals[idx - 1]);\n        }\n\n        idx = startIdx;\n        while (idx != insertion_idx) {\n            ROBIN_HOOD_COUNT(shiftUp)\n            mInfo[idx] = static_cast<uint8_t>(mInfo[idx - 1] + mInfoInc);\n            if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {\n                mMaxNumElementsAllowed = 0;\n            }\n            --idx;\n        }\n    }\n\n    void shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {\n        // until we find one that is either empty or has zero offset.\n        // TODO(martinus) we don't need to move everything, just the last one for the same\n        // bucket.\n        mKeyVals[idx].destroy(*this);\n\n        // until we find one that is either empty or has zero offset.\n        while (mInfo[idx + 1] >= 2 * mInfoInc) {\n            ROBIN_HOOD_COUNT(shiftDown)\n            mInfo[idx] = static_cast<uint8_t>(mInfo[idx + 1] - mInfoInc);\n            mKeyVals[idx] = std::move(mKeyVals[idx + 1]);\n            ++idx;\n        }\n\n        mInfo[idx] = 0;\n        // don't destroy, we've moved it\n        // mKeyVals[idx].destroy(*this);\n        mKeyVals[idx].~Node();\n    }\n\n    // copy of find(), except that it returns iterator instead of const_iterator.\n    template <typename Other>\n    ROBIN_HOOD(NODISCARD)\n    size_t findIdx(Other const& key) const {\n        size_t idx{};\n        InfoType info{};\n        keyToIdx(key, &idx, &info);\n\n        do {\n            // unrolling this twice gives a bit of a speedup. More unrolling did not help.\n            if (info == mInfo[idx] &&\n                ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {\n                return idx;\n            }\n            next(&info, &idx);\n            if (info == mInfo[idx] &&\n                ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {\n                return idx;\n            }\n            next(&info, &idx);\n        } while (info <= mInfo[idx]);\n\n        // nothing found!\n        return mMask == 0 ? 0\n                          : static_cast<size_t>(std::distance(\n                                mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));\n    }\n\n    void cloneData(const Table& o) {\n        Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *this);\n    }\n\n    // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized.\n    // @return True on success, false if something went wrong\n    void insert_move(Node&& keyval) {\n        // we don't retry, fail if overflowing\n        // don't need to check max num elements\n        if (0 == mMaxNumElementsAllowed && !try_increase_info()) {\n            throwOverflowError();\n        }\n\n        size_t idx{};\n        InfoType info{};\n        keyToIdx(keyval.getFirst(), &idx, &info);\n\n        // skip forward. Use <= because we are certain that the element is not there.\n        while (info <= mInfo[idx]) {\n            idx = idx + 1;\n            info += mInfoInc;\n        }\n\n        // key not found, so we are now exactly where we want to insert it.\n        auto const insertion_idx = idx;\n        auto const insertion_info = static_cast<uint8_t>(info);\n        if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {\n            mMaxNumElementsAllowed = 0;\n        }\n\n        // find an empty spot\n        while (0 != mInfo[idx]) {\n            next(&info, &idx);\n        }\n\n        auto& l = mKeyVals[insertion_idx];\n        if (idx == insertion_idx) {\n            ::new (static_cast<void*>(&l)) Node(std::move(keyval));\n        } else {\n            shiftUp(idx, insertion_idx);\n            l = std::move(keyval);\n        }\n\n        // put at empty spot\n        mInfo[insertion_idx] = insertion_info;\n\n        ++mNumElements;\n    }\n\npublic:\n    using iterator = Iter<false>;\n    using const_iterator = Iter<true>;\n\n    Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))\n        : WHash()\n        , WKeyEqual() {\n        ROBIN_HOOD_TRACE(this)\n    }\n\n    // Creates an empty hash map. Nothing is allocated yet, this happens at the first insert.\n    // This tremendously speeds up ctor & dtor of a map that never receives an element. The\n    // penalty is payed at the first insert, and not before. Lookup of this empty map works\n    // because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the\n    // standard, but we can ignore it.\n    explicit Table(\n        size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{},\n        const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))\n        : WHash(h)\n        , WKeyEqual(equal) {\n        ROBIN_HOOD_TRACE(this)\n    }\n\n    template <typename Iter>\n    Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0,\n          const Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{})\n        : WHash(h)\n        , WKeyEqual(equal) {\n        ROBIN_HOOD_TRACE(this)\n        insert(first, last);\n    }\n\n    Table(std::initializer_list<value_type> initlist,\n          size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{},\n          const KeyEqual& equal = KeyEqual{})\n        : WHash(h)\n        , WKeyEqual(equal) {\n        ROBIN_HOOD_TRACE(this)\n        insert(initlist.begin(), initlist.end());\n    }\n\n    Table(Table&& o) noexcept\n        : WHash(std::move(static_cast<WHash&>(o)))\n        , WKeyEqual(std::move(static_cast<WKeyEqual&>(o)))\n        , DataPool(std::move(static_cast<DataPool&>(o))) {\n        ROBIN_HOOD_TRACE(this)\n        if (o.mMask) {\n            mHashMultiplier = std::move(o.mHashMultiplier);\n            mKeyVals = std::move(o.mKeyVals);\n            mInfo = std::move(o.mInfo);\n            mNumElements = std::move(o.mNumElements);\n            mMask = std::move(o.mMask);\n            mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);\n            mInfoInc = std::move(o.mInfoInc);\n            mInfoHashShift = std::move(o.mInfoHashShift);\n            // set other's mask to 0 so its destructor won't do anything\n            o.init();\n        }\n    }\n\n    Table& operator=(Table&& o) noexcept {\n        ROBIN_HOOD_TRACE(this)\n        if (&o != this) {\n            if (o.mMask) {\n                // only move stuff if the other map actually has some data\n                destroy();\n                mHashMultiplier = std::move(o.mHashMultiplier);\n                mKeyVals = std::move(o.mKeyVals);\n                mInfo = std::move(o.mInfo);\n                mNumElements = std::move(o.mNumElements);\n                mMask = std::move(o.mMask);\n                mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);\n                mInfoInc = std::move(o.mInfoInc);\n                mInfoHashShift = std::move(o.mInfoHashShift);\n                WHash::operator=(std::move(static_cast<WHash&>(o)));\n                WKeyEqual::operator=(std::move(static_cast<WKeyEqual&>(o)));\n                DataPool::operator=(std::move(static_cast<DataPool&>(o)));\n\n                o.init();\n\n            } else {\n                // nothing in the other map => just clear us.\n                clear();\n            }\n        }\n        return *this;\n    }\n\n    Table(const Table& o)\n        : WHash(static_cast<const WHash&>(o))\n        , WKeyEqual(static_cast<const WKeyEqual&>(o))\n        , DataPool(static_cast<const DataPool&>(o)) {\n        ROBIN_HOOD_TRACE(this)\n        if (!o.empty()) {\n            // not empty: create an exact copy. it is also possible to just iterate through all\n            // elements and insert them, but copying is probably faster.\n\n            auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);\n            auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n\n            ROBIN_HOOD_LOG(\"std::malloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n                                          << numElementsWithBuffer << \")\")\n            mHashMultiplier = o.mHashMultiplier;\n            mKeyVals = static_cast<Node*>(\n                detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));\n            // no need for calloc because clonData does memcpy\n            mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n            mNumElements = o.mNumElements;\n            mMask = o.mMask;\n            mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;\n            mInfoInc = o.mInfoInc;\n            mInfoHashShift = o.mInfoHashShift;\n            cloneData(o);\n        }\n    }\n\n    // Creates a copy of the given map. Copy constructor of each entry is used.\n    // Not sure why clang-tidy thinks this doesn't handle self assignment, it does\n    // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)\n    Table& operator=(Table const& o) {\n        ROBIN_HOOD_TRACE(this)\n        if (&o == this) {\n            // prevent assigning of itself\n            return *this;\n        }\n\n        // we keep using the old allocator and not assign the new one, because we want to keep\n        // the memory available. when it is the same size.\n        if (o.empty()) {\n            if (0 == mMask) {\n                // nothing to do, we are empty too\n                return *this;\n            }\n\n            // not empty: destroy what we have there\n            // clear also resets mInfo to 0, that's sometimes not necessary.\n            destroy();\n            init();\n            WHash::operator=(static_cast<const WHash&>(o));\n            WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));\n            DataPool::operator=(static_cast<DataPool const&>(o));\n\n            return *this;\n        }\n\n        // clean up old stuff\n        Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);\n\n        if (mMask != o.mMask) {\n            // no luck: we don't have the same array size allocated, so we need to realloc.\n            if (0 != mMask) {\n                // only deallocate if we actually have data!\n                ROBIN_HOOD_LOG(\"std::free\")\n                std::free(mKeyVals);\n            }\n\n            auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);\n            auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n            ROBIN_HOOD_LOG(\"std::malloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n                                          << numElementsWithBuffer << \")\")\n            mKeyVals = static_cast<Node*>(\n                detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));\n\n            // no need for calloc here because cloneData performs a memcpy.\n            mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n            // sentinel is set in cloneData\n        }\n        WHash::operator=(static_cast<const WHash&>(o));\n        WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));\n        DataPool::operator=(static_cast<DataPool const&>(o));\n        mHashMultiplier = o.mHashMultiplier;\n        mNumElements = o.mNumElements;\n        mMask = o.mMask;\n        mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;\n        mInfoInc = o.mInfoInc;\n        mInfoHashShift = o.mInfoHashShift;\n        cloneData(o);\n\n        return *this;\n    }\n\n    // Swaps everything between the two maps.\n    void swap(Table& o) {\n        ROBIN_HOOD_TRACE(this)\n        using std::swap;\n        swap(o, *this);\n    }\n\n    // Clears all data, without resizing.\n    void clear() {\n        ROBIN_HOOD_TRACE(this)\n        if (empty()) {\n            // don't do anything! also important because we don't want to write to\n            // DummyInfoByte::b, even though we would just write 0 to it.\n            return;\n        }\n\n        Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);\n\n        auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n        // clear everything, then set the sentinel again\n        uint8_t const z = 0;\n        std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);\n        mInfo[numElementsWithBuffer] = 1;\n\n        mInfoInc = InitialInfoInc;\n        mInfoHashShift = InitialInfoHashShift;\n    }\n\n    // Destroys the map and all it's contents.\n    ~Table() {\n        ROBIN_HOOD_TRACE(this)\n        destroy();\n    }\n\n    // Checks if both tables contain the same entries. Order is irrelevant.\n    bool operator==(const Table& other) const {\n        ROBIN_HOOD_TRACE(this)\n        if (other.size() != size()) {\n            return false;\n        }\n        for (auto const& otherEntry : other) {\n            if (!has(otherEntry)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    bool operator!=(const Table& other) const {\n        ROBIN_HOOD_TRACE(this)\n        return !operator==(other);\n    }\n\n    template <typename Q = mapped_type>\n    typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](const key_type& key) {\n        ROBIN_HOOD_TRACE(this)\n        auto idxAndState = insertKeyPrepareEmptySpot(key);\n        switch (idxAndState.second) {\n        case InsertionState::key_found:\n            break;\n\n        case InsertionState::new_node:\n            ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))\n                Node(*this, std::piecewise_construct, std::forward_as_tuple(key),\n                     std::forward_as_tuple());\n            break;\n\n        case InsertionState::overwrite_node:\n            mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,\n                                               std::forward_as_tuple(key), std::forward_as_tuple());\n            break;\n\n        case InsertionState::overflow_error:\n            throwOverflowError();\n        }\n\n        return mKeyVals[idxAndState.first].getSecond();\n    }\n\n    template <typename Q = mapped_type>\n    typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {\n        ROBIN_HOOD_TRACE(this)\n        auto idxAndState = insertKeyPrepareEmptySpot(key);\n        switch (idxAndState.second) {\n        case InsertionState::key_found:\n            break;\n\n        case InsertionState::new_node:\n            ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))\n                Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),\n                     std::forward_as_tuple());\n            break;\n\n        case InsertionState::overwrite_node:\n            mKeyVals[idxAndState.first] =\n                Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),\n                     std::forward_as_tuple());\n            break;\n\n        case InsertionState::overflow_error:\n            throwOverflowError();\n        }\n\n        return mKeyVals[idxAndState.first].getSecond();\n    }\n\n    template <typename Iter>\n    void insert(Iter first, Iter last) {\n        for (; first != last; ++first) {\n            // value_type ctor needed because this might be called with std::pair's\n            insert(value_type(*first));\n        }\n    }\n\n    void insert(std::initializer_list<value_type> ilist) {\n        for (auto&& vt : ilist) {\n            insert(std::move(vt));\n        }\n    }\n\n    template <typename... Args>\n    std::pair<iterator, bool> emplace(Args&&... args) {\n        ROBIN_HOOD_TRACE(this)\n        Node n{*this, std::forward<Args>(args)...};\n        auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));\n        switch (idxAndState.second) {\n        case InsertionState::key_found:\n            n.destroy(*this);\n            break;\n\n        case InsertionState::new_node:\n            ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(*this, std::move(n));\n            break;\n\n        case InsertionState::overwrite_node:\n            mKeyVals[idxAndState.first] = std::move(n);\n            break;\n\n        case InsertionState::overflow_error:\n            n.destroy(*this);\n            throwOverflowError();\n            break;\n        }\n\n        return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),\n                              InsertionState::key_found != idxAndState.second);\n    }\n\n    template <typename... Args>\n    iterator emplace_hint(const_iterator position, Args&&... args) {\n        (void)position;\n        return emplace(std::forward<Args>(args)...).first;\n    }\n\n    template <typename... Args>\n    std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {\n        return try_emplace_impl(key, std::forward<Args>(args)...);\n    }\n\n    template <typename... Args>\n    std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {\n        return try_emplace_impl(std::move(key), std::forward<Args>(args)...);\n    }\n\n    template <typename... Args>\n    iterator try_emplace(const_iterator hint, const key_type& key, Args&&... args) {\n        (void)hint;\n        return try_emplace_impl(key, std::forward<Args>(args)...).first;\n    }\n\n    template <typename... Args>\n    iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) {\n        (void)hint;\n        return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;\n    }\n\n    template <typename Mapped>\n    std::pair<iterator, bool> insert_or_assign(const key_type& key, Mapped&& obj) {\n        return insertOrAssignImpl(key, std::forward<Mapped>(obj));\n    }\n\n    template <typename Mapped>\n    std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {\n        return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));\n    }\n\n    template <typename Mapped>\n    iterator insert_or_assign(const_iterator hint, const key_type& key, Mapped&& obj) {\n        (void)hint;\n        return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;\n    }\n\n    template <typename Mapped>\n    iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {\n        (void)hint;\n        return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;\n    }\n\n    std::pair<iterator, bool> insert(const value_type& keyval) {\n        ROBIN_HOOD_TRACE(this)\n        return emplace(keyval);\n    }\n\n    iterator insert(const_iterator hint, const value_type& keyval) {\n        (void)hint;\n        return emplace(keyval).first;\n    }\n\n    std::pair<iterator, bool> insert(value_type&& keyval) {\n        return emplace(std::move(keyval));\n    }\n\n    iterator insert(const_iterator hint, value_type&& keyval) {\n        (void)hint;\n        return emplace(std::move(keyval)).first;\n    }\n\n    // Returns 1 if key is found, 0 otherwise.\n    size_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        auto kv = mKeyVals + findIdx(key);\n        if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n            return 1;\n        }\n        return 0;\n    }\n\n    template <typename OtherKey, typename Self_ = Self>\n    // NOLINTNEXTLINE(modernize-use-nodiscard)\n    typename std::enable_if<Self_::is_transparent, size_t>::type count(const OtherKey& key) const {\n        ROBIN_HOOD_TRACE(this)\n        auto kv = mKeyVals + findIdx(key);\n        if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n            return 1;\n        }\n        return 0;\n    }\n\n    bool contains(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n        return 1U == count(key);\n    }\n\n    template <typename OtherKey, typename Self_ = Self>\n    // NOLINTNEXTLINE(modernize-use-nodiscard)\n    typename std::enable_if<Self_::is_transparent, bool>::type contains(const OtherKey& key) const {\n        return 1U == count(key);\n    }\n\n    // Returns a reference to the value found for key.\n    // Throws std::out_of_range if element cannot be found\n    template <typename Q = mapped_type>\n    // NOLINTNEXTLINE(modernize-use-nodiscard)\n    typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type const& key) {\n        ROBIN_HOOD_TRACE(this)\n        auto kv = mKeyVals + findIdx(key);\n        if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n            doThrow<std::out_of_range>(\"key not found\");\n        }\n        return kv->getSecond();\n    }\n\n    // Returns a reference to the value found for key.\n    // Throws std::out_of_range if element cannot be found\n    template <typename Q = mapped_type>\n    // NOLINTNEXTLINE(modernize-use-nodiscard)\n    typename std::enable_if<!std::is_void<Q>::value, Q const&>::type at(key_type const& key) const {\n        ROBIN_HOOD_TRACE(this)\n        auto kv = mKeyVals + findIdx(key);\n        if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n            doThrow<std::out_of_range>(\"key not found\");\n        }\n        return kv->getSecond();\n    }\n\n    const_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return const_iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    template <typename OtherKey>\n    const_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const {\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return const_iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    template <typename OtherKey, typename Self_ = Self>\n    typename std::enable_if<Self_::is_transparent, // NOLINT(modernize-use-nodiscard)\n                            const_iterator>::type  // NOLINT(modernize-use-nodiscard)\n    find(const OtherKey& key) const {              // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return const_iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    iterator find(const key_type& key) {\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    template <typename OtherKey>\n    iterator find(const OtherKey& key, is_transparent_tag /*unused*/) {\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    template <typename OtherKey, typename Self_ = Self>\n    typename std::enable_if<Self_::is_transparent, iterator>::type find(const OtherKey& key) {\n        ROBIN_HOOD_TRACE(this)\n        const size_t idx = findIdx(key);\n        return iterator{mKeyVals + idx, mInfo + idx};\n    }\n\n    iterator begin() {\n        ROBIN_HOOD_TRACE(this)\n        if (empty()) {\n            return end();\n        }\n        return iterator(mKeyVals, mInfo, fast_forward_tag{});\n    }\n    const_iterator begin() const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return cbegin();\n    }\n    const_iterator cbegin() const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        if (empty()) {\n            return cend();\n        }\n        return const_iterator(mKeyVals, mInfo, fast_forward_tag{});\n    }\n\n    iterator end() {\n        ROBIN_HOOD_TRACE(this)\n        // no need to supply valid info pointer: end() must not be dereferenced, and only node\n        // pointer is compared.\n        return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};\n    }\n    const_iterator end() const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return cend();\n    }\n    const_iterator cend() const { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};\n    }\n\n    iterator erase(const_iterator pos) {\n        ROBIN_HOOD_TRACE(this)\n        // its safe to perform const cast here\n        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)\n        return erase(iterator{const_cast<Node*>(pos.mKeyVals), const_cast<uint8_t*>(pos.mInfo)});\n    }\n\n    // Erases element at pos, returns iterator to the next element.\n    iterator erase(iterator pos) {\n        ROBIN_HOOD_TRACE(this)\n        // we assume that pos always points to a valid entry, and not end().\n        auto const idx = static_cast<size_t>(pos.mKeyVals - mKeyVals);\n\n        shiftDown(idx);\n        --mNumElements;\n\n        if (*pos.mInfo) {\n            // we've backward shifted, return this again\n            return pos;\n        }\n\n        // no backward shift, return next element\n        return ++pos;\n    }\n\n    size_t erase(const key_type& key) {\n        ROBIN_HOOD_TRACE(this)\n        size_t idx{};\n        InfoType info{};\n        keyToIdx(key, &idx, &info);\n\n        // check while info matches with the source idx\n        do {\n            if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {\n                shiftDown(idx);\n                --mNumElements;\n                return 1;\n            }\n            next(&info, &idx);\n        } while (info <= mInfo[idx]);\n\n        // nothing found to delete\n        return 0;\n    }\n\n    // reserves space for the specified number of elements. Makes sure the old data fits.\n    // exactly the same as reserve(c).\n    void rehash(size_t c) {\n        // forces a reserve\n        reserve(c, true);\n    }\n\n    // reserves space for the specified number of elements. Makes sure the old data fits.\n    // Exactly the same as rehash(c). Use rehash(0) to shrink to fit.\n    void reserve(size_t c) {\n        // reserve, but don't force rehash\n        reserve(c, false);\n    }\n\n    // If possible reallocates the map to a smaller one. This frees the underlying table.\n    // Does not do anything if load_factor is too large for decreasing the table's size.\n    void compact() {\n        ROBIN_HOOD_TRACE(this)\n        auto newSize = InitialNumElements;\n        while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {\n            newSize *= 2;\n        }\n        if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {\n            throwOverflowError();\n        }\n\n        ROBIN_HOOD_LOG(\"newSize > mMask + 1: \" << newSize << \" > \" << mMask << \" + 1\")\n\n        // only actually do anything when the new size is bigger than the old one. This prevents to\n        // continuously allocate for each reserve() call.\n        if (newSize < mMask + 1) {\n            rehashPowerOfTwo(newSize, true);\n        }\n    }\n\n    size_type size() const noexcept { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return mNumElements;\n    }\n\n    size_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return static_cast<size_type>(-1);\n    }\n\n    ROBIN_HOOD(NODISCARD) bool empty() const noexcept {\n        ROBIN_HOOD_TRACE(this)\n        return 0 == mNumElements;\n    }\n\n    float max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return MaxLoadFactor100 / 100.0F;\n    }\n\n    // Average number of elements per bucket. Since we allow only 1 per bucket\n    float load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)\n        ROBIN_HOOD_TRACE(this)\n        return static_cast<float>(size()) / static_cast<float>(mMask + 1);\n    }\n\n    ROBIN_HOOD(NODISCARD) size_t mask() const noexcept {\n        ROBIN_HOOD_TRACE(this)\n        return mMask;\n    }\n\n    ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept {\n        if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {\n            return maxElements * MaxLoadFactor100 / 100;\n        }\n\n        // we might be a bit inprecise, but since maxElements is quite large that doesn't matter\n        return (maxElements / 100) * MaxLoadFactor100;\n    }\n\n    ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept {\n        // we add a uint64_t, which houses the sentinel (first byte) and padding so we can load\n        // 64bit types.\n        return numElements + sizeof(uint64_t);\n    }\n\n    ROBIN_HOOD(NODISCARD)\n    size_t calcNumElementsWithBuffer(size_t numElements) const noexcept {\n        auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);\n        return numElements + (std::min)(maxNumElementsAllowed, (static_cast<size_t>(0xFF)));\n    }\n\n    // calculation only allowed for 2^n values\n    ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const {\n#if ROBIN_HOOD(BITNESS) == 64\n        return numElements * sizeof(Node) + calcNumBytesInfo(numElements);\n#else\n        // make sure we're doing 64bit operations, so we are at least safe against 32bit overflows.\n        auto const ne = static_cast<uint64_t>(numElements);\n        auto const s = static_cast<uint64_t>(sizeof(Node));\n        auto const infos = static_cast<uint64_t>(calcNumBytesInfo(numElements));\n\n        auto const total64 = ne * s + infos;\n        auto const total = static_cast<size_t>(total64);\n\n        if (ROBIN_HOOD_UNLIKELY(static_cast<uint64_t>(total) != total64)) {\n            throwOverflowError();\n        }\n        return total;\n#endif\n    }\n\nprivate:\n    template <typename Q = mapped_type>\n    ROBIN_HOOD(NODISCARD)\n    typename std::enable_if<!std::is_void<Q>::value, bool>::type has(const value_type& e) const {\n        ROBIN_HOOD_TRACE(this)\n        auto it = find(e.first);\n        return it != end() && it->second == e.second;\n    }\n\n    template <typename Q = mapped_type>\n    ROBIN_HOOD(NODISCARD)\n    typename std::enable_if<std::is_void<Q>::value, bool>::type has(const value_type& e) const {\n        ROBIN_HOOD_TRACE(this)\n        return find(e) != end();\n    }\n\n    void reserve(size_t c, bool forceRehash) {\n        ROBIN_HOOD_TRACE(this)\n        auto const minElementsAllowed = (std::max)(c, mNumElements);\n        auto newSize = InitialNumElements;\n        while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {\n            newSize *= 2;\n        }\n        if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {\n            throwOverflowError();\n        }\n\n        ROBIN_HOOD_LOG(\"newSize > mMask + 1: \" << newSize << \" > \" << mMask << \" + 1\")\n\n        // only actually do anything when the new size is bigger than the old one. This prevents to\n        // continuously allocate for each reserve() call.\n        if (forceRehash || newSize > mMask + 1) {\n            rehashPowerOfTwo(newSize, false);\n        }\n    }\n\n    // reserves space for at least the specified number of elements.\n    // only works if numBuckets if power of two\n    // True on success, false otherwise\n    void rehashPowerOfTwo(size_t numBuckets, bool forceFree) {\n        ROBIN_HOOD_TRACE(this)\n\n        Node* const oldKeyVals = mKeyVals;\n        uint8_t const* const oldInfo = mInfo;\n\n        const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n\n        // resize operation: move stuff\n        initData(numBuckets);\n        if (oldMaxElementsWithBuffer > 1) {\n            for (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {\n                if (oldInfo[i] != 0) {\n                    // might throw an exception, which is really bad since we are in the middle of\n                    // moving stuff.\n                    insert_move(std::move(oldKeyVals[i]));\n                    // destroy the node but DON'T destroy the data.\n                    oldKeyVals[i].~Node();\n                }\n            }\n\n            // this check is not necessary as it's guarded by the previous if, but it helps\n            // silence g++'s overeager \"attempt to free a non-heap object 'map'\n            // [-Werror=free-nonheap-object]\" warning.\n            if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {\n                // don't destroy old data: put it into the pool instead\n                if (forceFree) {\n                    std::free(oldKeyVals);\n                } else {\n                    DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));\n                }\n            }\n        }\n    }\n\n    ROBIN_HOOD(NOINLINE) void throwOverflowError() const {\n#if ROBIN_HOOD(HAS_EXCEPTIONS)\n        throw std::overflow_error(\"robin_hood::map overflow\");\n#else\n        abort();\n#endif\n    }\n\n    template <typename OtherKey, typename... Args>\n    std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {\n        ROBIN_HOOD_TRACE(this)\n        auto idxAndState = insertKeyPrepareEmptySpot(key);\n        switch (idxAndState.second) {\n        case InsertionState::key_found:\n            break;\n\n        case InsertionState::new_node:\n            ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(\n                *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),\n                std::forward_as_tuple(std::forward<Args>(args)...));\n            break;\n\n        case InsertionState::overwrite_node:\n            mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,\n                                               std::forward_as_tuple(std::forward<OtherKey>(key)),\n                                               std::forward_as_tuple(std::forward<Args>(args)...));\n            break;\n\n        case InsertionState::overflow_error:\n            throwOverflowError();\n            break;\n        }\n\n        return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),\n                              InsertionState::key_found != idxAndState.second);\n    }\n\n    template <typename OtherKey, typename Mapped>\n    std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {\n        ROBIN_HOOD_TRACE(this)\n        auto idxAndState = insertKeyPrepareEmptySpot(key);\n        switch (idxAndState.second) {\n        case InsertionState::key_found:\n            mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);\n            break;\n\n        case InsertionState::new_node:\n            ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(\n                *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),\n                std::forward_as_tuple(std::forward<Mapped>(obj)));\n            break;\n\n        case InsertionState::overwrite_node:\n            mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,\n                                               std::forward_as_tuple(std::forward<OtherKey>(key)),\n                                               std::forward_as_tuple(std::forward<Mapped>(obj)));\n            break;\n\n        case InsertionState::overflow_error:\n            throwOverflowError();\n            break;\n        }\n\n        return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),\n                              InsertionState::key_found != idxAndState.second);\n    }\n\n    void initData(size_t max_elements) {\n        mNumElements = 0;\n        mMask = max_elements - 1;\n        mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);\n\n        auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);\n\n        // malloc & zero mInfo. Faster than calloc everything.\n        auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n        ROBIN_HOOD_LOG(\"std::calloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n                                      << numElementsWithBuffer << \")\")\n        mKeyVals = reinterpret_cast<Node*>(\n            detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));\n        mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n        std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer * sizeof(Node));\n\n        // set sentinel\n        mInfo[numElementsWithBuffer] = 1;\n\n        mInfoInc = InitialInfoInc;\n        mInfoHashShift = InitialInfoHashShift;\n    }\n\n    enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };\n\n    // Finds key, and if not already present prepares a spot where to pot the key & value.\n    // This potentially shifts nodes out of the way, updates mInfo and number of inserted\n    // elements, so the only operation left to do is create/assign a new node at that spot.\n    template <typename OtherKey>\n    std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {\n        for (int i = 0; i < 256; ++i) {\n            size_t idx{};\n            InfoType info{};\n            keyToIdx(key, &idx, &info);\n            nextWhileLess(&info, &idx);\n\n            // while we potentially have a match\n            while (info == mInfo[idx]) {\n                if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {\n                    // key already exists, do NOT insert.\n                    // see http://en.cppreference.com/w/cpp/container/unordered_map/insert\n                    return std::make_pair(idx, InsertionState::key_found);\n                }\n                next(&info, &idx);\n            }\n\n            // unlikely that this evaluates to true\n            if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {\n                if (!increase_size()) {\n                    return std::make_pair(size_t(0), InsertionState::overflow_error);\n                }\n                continue;\n            }\n\n            // key not found, so we are now exactly where we want to insert it.\n            auto const insertion_idx = idx;\n            auto const insertion_info = info;\n            if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {\n                mMaxNumElementsAllowed = 0;\n            }\n\n            // find an empty spot\n            while (0 != mInfo[idx]) {\n                next(&info, &idx);\n            }\n\n            if (idx != insertion_idx) {\n                shiftUp(idx, insertion_idx);\n            }\n            // put at empty spot\n            mInfo[insertion_idx] = static_cast<uint8_t>(insertion_info);\n            ++mNumElements;\n            return std::make_pair(insertion_idx, idx == insertion_idx\n                                                     ? InsertionState::new_node\n                                                     : InsertionState::overwrite_node);\n        }\n\n        // enough attempts failed, so finally give up.\n        return std::make_pair(size_t(0), InsertionState::overflow_error);\n    }\n\n    bool try_increase_info() {\n        ROBIN_HOOD_LOG(\"mInfoInc=\" << mInfoInc << \", numElements=\" << mNumElements\n                                   << \", maxNumElementsAllowed=\"\n                                   << calcMaxNumElementsAllowed(mMask + 1))\n        if (mInfoInc <= 2) {\n            // need to be > 2 so that shift works (otherwise undefined behavior!)\n            return false;\n        }\n        // we got space left, try to make info smaller\n        mInfoInc = static_cast<uint8_t>(mInfoInc >> 1U);\n\n        // remove one bit of the hash, leaving more space for the distance info.\n        // This is extremely fast because we can operate on 8 bytes at once.\n        ++mInfoHashShift;\n        auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n\n        for (size_t i = 0; i < numElementsWithBuffer; i += 8) {\n            auto val = unaligned_load<uint64_t>(mInfo + i);\n            val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);\n            std::memcpy(mInfo + i, &val, sizeof(val));\n        }\n        // update sentinel, which might have been cleared out!\n        mInfo[numElementsWithBuffer] = 1;\n\n        mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);\n        return true;\n    }\n\n    // True if resize was possible, false otherwise\n    bool increase_size() {\n        // nothing allocated yet? just allocate InitialNumElements\n        if (0 == mMask) {\n            initData(InitialNumElements);\n            return true;\n        }\n\n        auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);\n        if (mNumElements < maxNumElementsAllowed && try_increase_info()) {\n            return true;\n        }\n\n        ROBIN_HOOD_LOG(\"mNumElements=\" << mNumElements << \", maxNumElementsAllowed=\"\n                                       << maxNumElementsAllowed << \", load=\"\n                                       << (static_cast<double>(mNumElements) * 100.0 /\n                                           (static_cast<double>(mMask) + 1)))\n\n        if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {\n            // we have to resize, even though there would still be plenty of space left!\n            // Try to rehash instead. Delete freed memory so we don't steadyily increase mem in case\n            // we have to rehash a few times\n            nextHashMultiplier();\n            rehashPowerOfTwo(mMask + 1, true);\n        } else {\n            // we've reached the capacity of the map, so the hash seems to work nice. Keep using it.\n            rehashPowerOfTwo((mMask + 1) * 2, false);\n        }\n        return true;\n    }\n\n    void nextHashMultiplier() {\n        // adding an *even* number, so that the multiplier will always stay odd. This is necessary\n        // so that the hash stays a mixing function (and thus doesn't have any information loss).\n        mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);\n    }\n\n    void destroy() {\n        if (0 == mMask) {\n            // don't deallocate!\n            return;\n        }\n\n        Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}\n            .nodesDoNotDeallocate(*this);\n\n        // This protection against not deleting mMask shouldn't be needed as it's sufficiently\n        // protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise\n        // reports a compile error: attempt to free a non-heap object 'fm'\n        // [-Werror=free-nonheap-object]\n        if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {\n            ROBIN_HOOD_LOG(\"std::free\")\n            std::free(mKeyVals);\n        }\n    }\n\n    void init() noexcept {\n        mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);\n        mInfo = reinterpret_cast<uint8_t*>(&mMask);\n        mNumElements = 0;\n        mMask = 0;\n        mMaxNumElementsAllowed = 0;\n        mInfoInc = InitialInfoInc;\n        mInfoHashShift = InitialInfoHashShift;\n    }\n\n    // members are sorted so no padding occurs\n    uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53);                // 8 byte  8\n    Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask); // 8 byte 16\n    uint8_t* mInfo = reinterpret_cast<uint8_t*>(&mMask);                    // 8 byte 24\n    size_t mNumElements = 0;                                                // 8 byte 32\n    size_t mMask = 0;                                                       // 8 byte 40\n    size_t mMaxNumElementsAllowed = 0;                                      // 8 byte 48\n    InfoType mInfoInc = InitialInfoInc;                                     // 4 byte 52\n    InfoType mInfoHashShift = InitialInfoHashShift;                         // 4 byte 56\n                                                    // 16 byte 56 if NodeAllocator\n};\n\n} // namespace detail\n\n// map\n\ntemplate <typename Key, typename T, typename Hash = hash<Key>,\n          typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\nusing unordered_flat_map = detail::Table<true, MaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\ntemplate <typename Key, typename T, typename Hash = hash<Key>,\n          typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\nusing unordered_node_map = detail::Table<false, MaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\ntemplate <typename Key, typename T, typename Hash = hash<Key>,\n          typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\nusing unordered_map =\n    detail::Table<sizeof(robin_hood::pair<Key, T>) <= sizeof(size_t) * 6 &&\n                      std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&\n                      std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,\n                  MaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\n// set\n\ntemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n          size_t MaxLoadFactor100 = 80>\nusing unordered_flat_set = detail::Table<true, MaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\ntemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n          size_t MaxLoadFactor100 = 80>\nusing unordered_node_set = detail::Table<false, MaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\ntemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n          size_t MaxLoadFactor100 = 80>\nusing unordered_set = detail::Table<sizeof(Key) <= sizeof(size_t) * 6 &&\n                                        std::is_nothrow_move_constructible<Key>::value &&\n                                        std::is_nothrow_move_assignable<Key>::value,\n                                    MaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\n} // namespace robin_hood\n\n#endif\n"
  },
  {
    "path": "eidos/sleef/LICENSE",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "eidos/sleef/SLEEF_HEADER_GENERATION.md",
    "content": "# SLEEF Header Generation and Patching\n\nThis document explains how to regenerate the SLEEF inline headers if needed.\n\n## Author\nThese flags and configurations were developed by Andrew Kern as part of SIMD optimization work for SLiM.\n\n## Background\n\n[SLEEF](https://github.com/shibatch/sleef) (SIMD Library for Evaluating Elementary Functions) provides vectorized implementations of transcendental math functions (exp, log, sin, cos, etc.) with guaranteed accuracy.\n\nWe use SLEEF's **inline headers** which are self-contained header files that can be vendored directly into a project without linking to an external library. This avoids runtime dependencies and allows the compiler to inline the SIMD code.\n\n## Current Headers\n\n| File | Architecture | Vector Width | Source |\n|------|--------------|--------------|--------|\n| `eidos/sleef/sleefinline_avx2.h` | x86_64 AVX2+FMA | 4 doubles | Generated on x86_64 Linux |\n| `eidos/sleef/sleefinline_advsimd.h` | ARM64 NEON | 2 doubles | Generated on ARM64 macOS |\n\nBoth headers are from **SLEEF 4.0.0** (generated December 2024).\n\n## Patching is Required\n\nI have to do a bit of patching here of the generated headers because\nSLEEF's generated headers use **C99 hexadecimal floating-point literals** like:\n\n```c\n0x1p-1022      // 2.22507385850720138e-308 (DBL_MIN)\n0x1p-126       // 1.17549435082228751e-38  (FLT_MIN)\n0x1.62e42fefa39efp+9  // 709.78... (log overflow threshold)\n```\n\nThese are valid in C99/C11 and C++17, but **not in C++11/C++14**. Since SLiM uses C++11 (C++17 only when building with Qt6), we must convert these to decimal equivalents.\n\n## Generating the AVX2 Header (x86_64)\n\nRun on any x86_64 Linux or macOS machine. There's a helper script in this directory:\n\n```bash\n# Run directly on an x86_64 machine:\n./eidos/sleef/generate_avx2_sleef.sh > eidos/sleef/sleefinline_avx2.h\n```\n\nThe script (`eidos/sleef/generate_avx2_sleef.sh`) handles:\n1. Cloning SLEEF\n2. Building the inline headers\n3. Patching hex float literals\n4. Outputting the patched header to stdout\n\n## Generating the ARM NEON Header (ARM64)\n\nMust be run on an ARM64 machine (Apple Silicon Mac or ARM64 Linux). There's a helper script in this directory:\n\n```bash\n# From an x86_64 machine, run on a remote ARM64 machine:\nssh arm-machine \"bash -s\" < eidos/sleef/generate_arm_sleef.sh > eidos/sleef/sleefinline_advsimd.h\n\n# Or run directly on an ARM64 machine:\n./eidos/sleef/generate_arm_sleef.sh > eidos/sleef/sleefinline_advsimd.h\n```\n\nThe script (`eidos/sleef/generate_arm_sleef.sh`) handles:\n1. Cloning SLEEF\n2. Building with `-DCMAKE_OSX_ARCHITECTURES=arm64` (for Apple Silicon)\n3. Patching hex float literals\n4. Outputting the patched header to stdout\n\n## Hex Float Patch Reference\n\nThese are the known hex float literals that need patching:\n\n| Hex Literal | Decimal Equivalent | Meaning |\n|-------------|-------------------|---------|\n| `0x1p-1022` | `2.22507385850720138e-308` | DBL_MIN (smallest normal double) |\n| `0x1p-126` | `1.17549435082228751e-38` | FLT_MIN (smallest normal float) |\n| `0x1.62e42fefa39efp+9` | `7.09782712893383973e+02` | ln(DBL_MAX), exp overflow threshold |\n| `0x1.2ced32p+126` | `9.99999968028569247e+37` | Float overflow constant |\n| `0x1.c7b1f3cac7433p+1019` | `9.99999999999999986e+306` | Double overflow constant |\n\nTo find any new hex floats in a generated header:\n\n```bash\ngrep -oE '0x[0-9a-fA-F.]+p[+-]?[0-9]+' sleefinline_avx2.h | sort -u\n```\n\nTo convert a hex float to decimal (Python):\n\n```python\n>>> float.fromhex('0x1p-1022')\n2.2250738585072014e-308\n>>> f'{float.fromhex(\"0x1.62e42fefa39efp+9\"):.17g}'\n'709.78271289338397'\n```\n\n## __float128 Compatibility Patch\n\nSLEEF headers generated on Linux/GCC unconditionally define `SLEEF_FLOAT128_IS_IEEEQP`, which causes the header to use `__float128` for the `Sleef_quad` type. However, `__float128` is a GCC extension not supported by Clang/AppleClang on macOS.\n\nThe generation scripts patch this by replacing:\n```c\n#define SLEEF_FLOAT128_IS_IEEEQP\n```\n\nwith:\n```c\n// Only define SLEEF_FLOAT128_IS_IEEEQP on compilers that support __float128\n#if defined(__GNUC__) && !defined(__clang__) && defined(__SIZEOF_FLOAT128__)\n#define SLEEF_FLOAT128_IS_IEEEQP\n#endif\n```\n\nThis allows the header to fall back to a struct-based `Sleef_quad` type on compilers without `__float128` support. Since SLiM doesn't use quad-precision SLEEF functions, this fallback is safe.\n\n## Verifying the Patched Headers\n\nAfter patching, verify the headers compile with C++11:\n\n```bash\n# Test AVX2 header\necho '#include \"eidos/sleef/sleefinline_avx2.h\"' | \\\n    g++ -std=c++11 -mavx2 -mfma -x c++ -c - -o /dev/null\n\n# Test ARM NEON header (on ARM64)\necho '#include \"eidos/sleef/sleefinline_advsimd.h\"' | \\\n    g++ -std=c++11 -x c++ -c - -o /dev/null\n```\n\n## SLEEF License\n\nSLEEF is distributed under the **Boost Software License 1.0**, which permits:\n- Commercial and non-commercial use\n- Modification and redistribution\n- No attribution required in binary distributions\n\nThe license file is included at `eidos/sleef/LICENSE`.\n\n## Updating to a New SLEEF Version\n\n1. Generate new headers using the scripts above\n2. Check for new hex float literals: `grep -oE '0x[0-9a-fA-F.]+p[+-]?[0-9]+' header.h`\n3. Add any new literals to the sed patch commands\n4. Verify compilation with C++11\n5. Run tests: `./slim -testEidos && ./slim -testSLiM`\n6. Benchmark to verify performance: `./slim simd_benchmarks/sleef_benchmark.slim`\n\n## Files\n\n| File | Purpose |\n|------|---------|\n| `eidos/sleef/sleefinline_avx2.h` | Patched SLEEF AVX2 header (~6700 lines) |\n| `eidos/sleef/sleefinline_advsimd.h` | Patched SLEEF ARM NEON header (~6900 lines) |\n| `eidos/sleef/sleef_config.h` | Architecture selection macros |\n| `eidos/sleef/LICENSE` | Boost Software License |\n| `eidos/sleef/generate_avx2_sleef.sh` | Script to generate AVX2 header |\n| `eidos/sleef/generate_arm_sleef.sh` | Script to generate ARM header on remote machine |\n"
  },
  {
    "path": "eidos/sleef/generate_arm_sleef.sh",
    "content": "#!/bin/bash\n# generate_arm_sleef.sh - Run this on an ARM64 machine to generate SLEEF NEON header\n# Usage: ssh arm-machine \"bash -s\" < eidos/sleef/generate_arm_sleef.sh > eidos/sleef/sleefinline_advsimd.h\n\nset -e\n\n# Add Homebrew and Xcode command line tools to PATH (for macOS)\nexport PATH=\"/opt/homebrew/bin:/usr/local/bin:/Library/Developer/CommandLineTools/usr/bin:$PATH\"\n\nTMPDIR=$(mktemp -d)\ncd \"$TMPDIR\"\n\n# Clone and build SLEEF with inline headers\ngit clone --depth 1 https://github.com/shibatch/sleef.git sleef >&2\ncd sleef\nmkdir build && cd build\ncmake .. -DSLEEF_BUILD_INLINE_HEADERS=TRUE -DCMAKE_INSTALL_PREFIX=\"$TMPDIR/install\" -DCMAKE_OSX_ARCHITECTURES=arm64 -DSLEEF_BUILD_TESTS=OFF -DSLEEF_BUILD_LIBM=OFF -DSLEEF_BUILD_DFT=OFF -DSLEEF_BUILD_QUAD=OFF >&2\nmake inline_headers >&2 || make >&2 || true\n\n# Check if file exists\nif [ ! -f include/sleefinline_advsimd.h ]; then\n    echo \"ERROR: sleefinline_advsimd.h not found. Contents of include/:\" >&2\n    ls -la include/ >&2\n    exit 1\nfi\n\n# Patch hex float literals for C++11 compatibility and output to stdout\nsed \\\n    -e 's/0x1\\.2ced32p+126/9.99999968028569247e+37/g' \\\n    -e 's/0x1\\.62e42fefa39efp+9/7.09782712893383973e+02/g' \\\n    -e 's/0x1\\.c7b1f3cac7433p+1019/9.99999999999999986e+306/g' \\\n    -e 's/0x1p-1022/2.22507385850720138e-308/g' \\\n    -e 's/0x1p-126/1.17549435082228751e-38/g' \\\n    include/sleefinline_advsimd.h\n\n# Cleanup\ncd /\nrm -rf \"$TMPDIR\"\n"
  },
  {
    "path": "eidos/sleef/generate_avx2_sleef.sh",
    "content": "#!/bin/bash\n# generate_avx2_sleef.sh - Run this on an x86_64 machine to generate SLEEF AVX2 header\n# Usage: ./eidos/sleef/generate_avx2_sleef.sh > eidos/sleef/sleefinline_avx2.h\n\nset -e\n\nTMPDIR=$(mktemp -d)\ncd \"$TMPDIR\"\n\n# Clone and build SLEEF with inline headers\ngit clone --depth 1 https://github.com/shibatch/sleef.git sleef >&2\ncd sleef\nmkdir build && cd build\ncmake .. \\\n    -DSLEEF_BUILD_INLINE_HEADERS=TRUE \\\n    -DSLEEF_BUILD_TESTS=OFF \\\n    -DSLEEF_BUILD_LIBM=OFF \\\n    -DSLEEF_BUILD_DFT=OFF \\\n    -DSLEEF_BUILD_QUAD=OFF \\\n    -DCMAKE_INSTALL_PREFIX=\"$TMPDIR/install\" >&2\nmake inline_headers >&2 || make >&2 || true\n\n# Check if file exists\nif [ ! -f include/sleefinline_avx2.h ]; then\n    echo \"ERROR: sleefinline_avx2.h not found. Contents of include/:\" >&2\n    ls -la include/ >&2\n    exit 1\nfi\n\n# Patch hex float literals for C++11 compatibility and output to stdout\n# Also fix __float128 compatibility (not supported by Clang/AppleClang)\nsed \\\n    -e 's/0x1\\.2ced32p+126/9.99999968028569247e+37/g' \\\n    -e 's/0x1\\.62e42fefa39efp+9/7.09782712893383973e+02/g' \\\n    -e 's/0x1\\.c7b1f3cac7433p+1019/9.99999999999999986e+306/g' \\\n    -e 's/0x1p-1022/2.22507385850720138e-308/g' \\\n    -e 's/0x1p-126/1.17549435082228751e-38/g' \\\n    -e 's/^#define SLEEF_FLOAT128_IS_IEEEQP$/\\/\\/ Only define SLEEF_FLOAT128_IS_IEEEQP on compilers that support __float128\\n#if defined(__GNUC__) \\&\\& !defined(__clang__) \\&\\& defined(__SIZEOF_FLOAT128__)\\n#define SLEEF_FLOAT128_IS_IEEEQP\\n#endif/' \\\n    include/sleefinline_avx2.h\n\n# Cleanup\ncd /\nrm -rf \"$TMPDIR\"\n"
  },
  {
    "path": "eidos/sleef/sleef_config.h",
    "content": "//\n//  sleef_config.h\n//  Eidos\n//\n//  Created by Andrew Kern on 12/14/2025.\n//  Copyright (c) 2024-2025 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n//\tThis file is part of Eidos.\n//\n//\tEidos is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by\n//\tthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n//\n//\tEidos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n//\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\n//\n//\tYou should have received a copy of the GNU General Public License along with Eidos.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n\n SLEEF (SIMD Library for Evaluating Elementary Functions) configuration header.\n\n This header provides architecture-specific macros for using SLEEF inline headers\n to vectorize transcendental math functions (exp, log, log10, log2).\n\n SLEEF is used under the Boost Software License - see sleef/LICENSE.\n\n Architecture support:\n   - AVX2+FMA (Intel Haswell+, AMD Zen+): 4-wide double vectorization\n   - ARM NEON (Apple Silicon, ARM64 Linux): 2-wide double vectorization\n   - SSE4.2-only / No SIMD: Falls back to scalar std:: functions\n\n */\n\n#ifndef sleef_config_h\n#define sleef_config_h\n\n// Allow command-line override with -DEIDOS_SLEEF_AVAILABLE=0\n#ifndef EIDOS_SLEEF_AVAILABLE\n\n// ================================\n// AVX2+FMA Configuration (x86_64)\n// ================================\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    #include <immintrin.h>\n    #include \"sleefinline_avx2.h\"\n\n    #define EIDOS_SLEEF_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE 4\n\n    // Type definitions\n    #define EIDOS_SLEEF_TYPE_D __m256d\n\n    // Load/Store operations\n    #define EIDOS_SLEEF_LOAD_D(ptr) _mm256_loadu_pd(ptr)\n    #define EIDOS_SLEEF_STORE_D(ptr, v) _mm256_storeu_pd(ptr, v)\n\n    // Transcendental functions (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_EXP_D(v) Sleef_expd4_u10avx2(v)\n    #define EIDOS_SLEEF_LOG_D(v) Sleef_logd4_u10avx2(v)\n    #define EIDOS_SLEEF_LOG10_D(v) Sleef_log10d4_u10avx2(v)\n    #define EIDOS_SLEEF_LOG2_D(v) Sleef_log2d4_u10avx2(v)\n\n    // Trigonometric functions (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_SIN_D(v)      Sleef_sind4_u10avx2(v)\n    #define EIDOS_SLEEF_COS_D(v)      Sleef_cosd4_u10avx2(v)\n    #define EIDOS_SLEEF_TAN_D(v)      Sleef_tand4_u10avx2(v)\n    #define EIDOS_SLEEF_ASIN_D(v)     Sleef_asind4_u10avx2(v)\n    #define EIDOS_SLEEF_ACOS_D(v)     Sleef_acosd4_u10avx2(v)\n    #define EIDOS_SLEEF_ATAN_D(v)     Sleef_atand4_u10avx2(v)\n    #define EIDOS_SLEEF_ATAN2_D(y,x)  Sleef_atan2d4_u10avx2(y,x)\n\n    // Power function (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_POW_D(x,y)    Sleef_powd4_u10avx2(x,y)\n\n    // Float (single-precision) support - 8 floats per AVX2 register\n    #define EIDOS_SLEEF_FLOAT_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE_F 8\n    #define EIDOS_SLEEF_TYPE_F __m256\n    #define EIDOS_SLEEF_LOAD_F(ptr) _mm256_loadu_ps(ptr)\n    #define EIDOS_SLEEF_STORE_F(ptr, v) _mm256_storeu_ps(ptr, v)\n    #define EIDOS_SLEEF_EXP_F(v) Sleef_expf8_u10avx2(v)\n    #define EIDOS_SLEEF_POW_F(x, y) Sleef_powf8_u10avx2(x, y)\n\n// ================================\n// ARM NEON Configuration (ARM64)\n// ================================\n#elif defined(EIDOS_HAS_NEON)\n    #include <arm_neon.h>\n    #include \"sleefinline_advsimd.h\"\n\n    #define EIDOS_SLEEF_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE 2\n\n    // Type definitions\n    #define EIDOS_SLEEF_TYPE_D float64x2_t\n\n    // Load/Store operations\n    #define EIDOS_SLEEF_LOAD_D(ptr) vld1q_f64(ptr)\n    #define EIDOS_SLEEF_STORE_D(ptr, v) vst1q_f64(ptr, v)\n\n    // Transcendental functions (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_EXP_D(v) Sleef_expd2_u10advsimd(v)\n    #define EIDOS_SLEEF_LOG_D(v) Sleef_logd2_u10advsimd(v)\n    #define EIDOS_SLEEF_LOG10_D(v) Sleef_log10d2_u10advsimd(v)\n    #define EIDOS_SLEEF_LOG2_D(v) Sleef_log2d2_u10advsimd(v)\n\n    // Trigonometric functions (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_SIN_D(v)      Sleef_sind2_u10advsimd(v)\n    #define EIDOS_SLEEF_COS_D(v)      Sleef_cosd2_u10advsimd(v)\n    #define EIDOS_SLEEF_TAN_D(v)      Sleef_tand2_u10advsimd(v)\n    #define EIDOS_SLEEF_ASIN_D(v)     Sleef_asind2_u10advsimd(v)\n    #define EIDOS_SLEEF_ACOS_D(v)     Sleef_acosd2_u10advsimd(v)\n    #define EIDOS_SLEEF_ATAN_D(v)     Sleef_atand2_u10advsimd(v)\n    #define EIDOS_SLEEF_ATAN2_D(y,x)  Sleef_atan2d2_u10advsimd(y,x)\n\n    // Power function (u10 = 1.0 ULP accuracy)\n    #define EIDOS_SLEEF_POW_D(x,y)    Sleef_powd2_u10advsimd(x,y)\n\n    // Float (single-precision) support - 4 floats per NEON register\n    #define EIDOS_SLEEF_FLOAT_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE_F 4\n    #define EIDOS_SLEEF_TYPE_F float32x4_t\n    #define EIDOS_SLEEF_LOAD_F(ptr) vld1q_f32(ptr)\n    #define EIDOS_SLEEF_STORE_F(ptr, v) vst1q_f32(ptr, v)\n    #define EIDOS_SLEEF_EXP_F(v) Sleef_expf4_u10advsimd(v)\n    #define EIDOS_SLEEF_POW_F(x, y) Sleef_powf4_u10advsimd(x, y)\n\n// ================================\n// Scalar Fallback (SSE4.2-only or no SIMD)\n// ================================\n#else\n    #define EIDOS_SLEEF_AVAILABLE 0\n    #define EIDOS_SLEEF_VEC_SIZE 1\n    #define EIDOS_SLEEF_FLOAT_AVAILABLE 0\n    #define EIDOS_SLEEF_VEC_SIZE_F 1\n#endif\n\n#else // EIDOS_SLEEF_AVAILABLE was defined externally\n    // When disabled via command-line -DEIDOS_SLEEF_AVAILABLE=0, set VEC_SIZE to 1\n    #if !EIDOS_SLEEF_AVAILABLE\n        #define EIDOS_SLEEF_VEC_SIZE 1\n    #endif\n#endif // ifndef EIDOS_SLEEF_AVAILABLE\n\n#endif /* sleef_config_h */\n"
  },
  {
    "path": "eidos/sleef/sleefinline_advsimd.h",
    "content": "//   Copyright Naoki Shibata and contributors 2010 - 2025.\n// Distributed under the Boost Software License, Version 1.0.\n//        (See http://www.boost.org/LICENSE_1_0.txt)\n\n// This file is generated by SLEEF 4.0.0\n\n/* #undef SLEEF_FLOAT128_IS_IEEEQP */\n/* #undef SLEEF_LONGDOUBLE_IS_IEEEQP */\n\n#ifndef SLEEF_ALWAYS_INLINE\n#if defined (__GNUC__) || defined (__clang__)\n#define SLEEF_ALWAYS_INLINE inline __attribute__((always_inline))\n#elif defined(_MSC_VER)\n#define SLEEF_ALWAYS_INLINE inline __forceinline\n#else\n#define SLEEF_ALWAYS_INLINE inline\n#endif\n#endif\n\n#ifndef SLEEF_INLINE\n#define SLEEF_INLINE static inline\n#endif\n\n#ifndef SLEEF_CONST\n#define SLEEF_CONST\n#endif\n\n#if defined(_MSC_VER) && !defined (__clang__)\n#pragma fp_contract (off)\n#else\n#pragma STDC FP_CONTRACT OFF\n#endif\n\n#ifndef SLEEF_FP_ILOGB0\n#define SLEEF_FP_ILOGB0 ((int)0x80000000)\n#endif\n\n#ifndef SLEEF_FP_ILOGBNAN\n#define SLEEF_FP_ILOGBNAN ((int)2147483647)\n#endif\n\n#define SLEEFINLINE_ADVSIMD_H_INCLUDED\n\n#ifndef __SLEEF_REMPITAB__\n#define __SLEEF_REMPITAB__\nstatic const double Sleef_rempitabdp[] = {\n  0.15915494309189531785, 1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49,\n  0.03415494309189533173, 4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49,\n  0.03415494309189533173, 4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.00095181809189533563356, 1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762436344e-52,\n  0.00095181809189533563356, 1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762436344e-52,\n  0.00046353684189533574198, 2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.301187206862134399e-54,\n  0.00021939621689533574198, 2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.301187206862134399e-54,\n  9.7325904395335769087e-05, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  3.6290748145335769087e-05, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  1.9584727547107690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  2.1321799510573569745e-08, 1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369025999e-57,\n  6.4206383167259151492e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  6.4206383167259151492e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  2.6953480182640010867e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  8.3270286903304384868e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  8.3270286903304384868e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  3.6704158172530459087e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  1.3421093807143501366e-10, 1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.4247116125875099096e-12, 2.5861333686050385673e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61,\n  5.1521691081458187359e-13, 5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  1.3348904870778067446e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  6.5726412927436632287e-21, 1.0820844071023395684e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  3.1845095037264626247e-21, 3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  1.4904436092178623228e-21, -4.6390169687056261795e-38, -1.1392999419355048437e-54, -4.587677453735884283e-71,\n  6.4341066196356198368e-22, -4.6390169687056261795e-38, -1.1392999419355048437e-54, -4.587677453735884283e-71,\n  2.1989418833641172011e-22, 4.7649378378726728402e-38, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  6.9132600985943383921e-25, 7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  2.7773570358292009361e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57, -3.2399200798614356002e-74,\n  7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  6.317065088957874881e-27, -3.2976062348358281152e-43, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.317065088957874881e-27, -3.2976062348358281152e-43, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  3.0858908211726098086e-27, 3.8770419025072344914e-43, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.4703036872799779898e-27, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.625101203336619011e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  2.5861333686050385673e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  3.0224035688960604996e-30, 2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  1.4446817584540368888e-30, 2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.5582085323302525856e-31, 7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639313137e-79,\n  2.6139040062251944343e-31, -1.7578597149294783985e-47, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  6.4175174317266470186e-32, 4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  6.4175174317266470186e-32, 4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659569668e-65, -7.2335760163150273591e-81,\n  1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659569668e-65, -7.2335760163150273591e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.3430016361024414106e-34, 4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82,\n  2.3430016361024414106e-34, 4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  1.7633044866680145008e-35, 2.8491136916798196016e-51, 4.0680767287898916022e-67, 1.4185069655957361252e-83,\n  5.595982714259923599e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  5.595982714259923599e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  2.5867171761548675786e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  1.0820844071023395684e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  1.4168892644450972904e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  4.7649378378726728402e-38, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  3.2673620808294506214e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  1.1051690039850297894e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  1.1051690039850297894e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  3.8770419025072344914e-43, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.5355611056488084652e-94,\n  7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.5355611056488084652e-94,\n  2.6211979860855749482e-47, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  1.5797802926460750146e-48, 2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  1.8885701952232994665e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  8.1946431118642097069e-51, 1.5937536410989638719e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99,\n  2.8491136916798196016e-51, 4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  4.0809436324633147776e-54, -4.587677453735884283e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103,\n  1.470821845263904967e-54, -4.587677453735884283e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  3.9565608646667614317e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  1.9651959757511960854e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  9.6951353129341363331e-60, 7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108,\n  4.7167230906452229674e-60, 7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108,\n  2.2275169795007668372e-60, 2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108,\n  9.8291392392853877215e-61, -6.5385728340754726503e-77, -1.3520652573660833788e-93, -2.3220403312043059402e-109,\n  3.6061239614242446325e-61, 7.2792968540756372162e-77, 1.3988851821689310822e-92, 1.0451839188820145747e-108,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.535561105648808199e-94, -1.9306041120023063932e-110,\n  1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.535561105648808199e-94, -1.9306041120023063932e-110,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.4679971416497210292e-65, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  3.9676455775389135587e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  1.5937536410989638719e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  1.1007118082399544936e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  1.1007118082399544936e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115,\n  3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115,\n  1.7341027056809927069e-68, 1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418876704e-116,\n  8.0680116800913756637e-69, -2.2809159455312046184e-85, -4.0748824503880445403e-101, -6.3915272253158644628e-117,\n  3.4315039917320989315e-69, -2.2809159455312046184e-85, -4.0748824503880445403e-101, -6.3915272253158644628e-117,\n  1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  5.3368668650755071652e-70, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  2.4390495598509592076e-70, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  9.901409072386855505e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103, -4.6672632026740766185e-119,\n  2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  8.4572999356014273536e-72, 1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  8.4572999356014273536e-72, 1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  3.9294603961880721752e-72, 1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894729832e-121,\n  1.6655406264813940833e-72, 1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894729832e-121,\n  5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  2.5059077041472040156e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  1.0909578480805302081e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  3.8348292004719330442e-74, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  7.2792968540756372162e-77, 1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  1.5445779612272179051e-78, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  4.6505689184041232695e-79, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  4.6505689184041232695e-79, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128,\n  6.0236490820360325022e-80, -3.7424672147304925625e-96, -1.784871512364483542e-112, 6.7095375687163151728e-129,\n  6.0236490820360325022e-80, -3.7424672147304925625e-96, -1.784871512364483542e-112, 6.7095375687163151728e-129,\n  2.6501457402022643213e-80, 3.7482149527770239293e-96, 6.5314563001514349095e-112, 9.9039323746573674262e-128,\n  9.6339406928538097998e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  8.0141992334048515034e-85, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  2.8666416439368237283e-85, 1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  1.3200167453193350837e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  6.3183932821616130831e-93, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  2.4831640123977650651e-93, 1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007823264e-142,\n  5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  1.1238897120284541253e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  3.7482149527770239293e-96, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  1.0450891972142805974e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.0404514546648604359e-103, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  1.0404514546648604359e-103, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  4.8235214251531210473e-104, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  2.0330248644053793915e-104, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  6.3777658403150887343e-105, -2.0152904854894725532e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  6.3777658403150887343e-105, -2.0152904854894725532e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  2.88964513938041089e-105, 5.7298933442091639924e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153,\n  2.7355461367940366859e-106, -7.8994528064813712419e-123, -2.0037599452814940222e-138, 9.1598554579059548847e-155,\n  2.7355461367940366859e-106, -7.8994528064813712419e-123, -2.0037599452814940222e-138, 9.1598554579059548847e-155,\n  5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155,\n  5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  8.7142954880180709975e-110, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  3.3918456880078814158e-110, 6.931443500908017045e-126, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220312367e-159,\n  7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220312367e-159,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  2.3732923938934761454e-112, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  8.2436437080731844263e-116, 1.4726412753514008951e-131, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942429241e-163,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  3.1257546646178208289e-117, -6.6414926959353515111e-134, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  1.5395410162955400644e-117, -6.6414926959353515111e-134, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  7.4643419213439950602e-118, 1.0969016447485317626e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  3.4988078005382940294e-118, 2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166,\n  1.5160407401354430737e-118, 2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166,\n  5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  1.3475077173907800538e-120, -3.156241481857667737e-137, -7.0684085473731388916e-153, -3.3573283875161501977e-170,\n  5.7298933442091639924e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153, -3.3573283875161501977e-170,\n  1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  8.8915345064751572143e-122, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  4.0507946129135104481e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  4.2023969274227456735e-123, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  4.2023969274227456735e-123, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  1.1769344939467164447e-123, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  1.1769344939467164447e-123, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  4.2056888557770896953e-124, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  1.8749656131673758844e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  6.931443500908017045e-126, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  2.8369889610228834887e-127, 4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176,\n  2.8369889610228834887e-127, 4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176,\n  9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657612913e-160, -2.5389576707476506925e-176,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  2.175994780857201024e-130, 1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  2.175994780857201024e-130, 1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  1.4726412753514008951e-131, -3.9681466199873824165e-148, 2.9106774506606941983e-164, 5.1948630316441296498e-180,\n  3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  2.8579525590905986764e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165, -1.0696067158221530218e-181,\n  1.0969016447485317626e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165, -1.0696067158221530218e-181,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  1.0631050543111905033e-134, 1.5490398016102376505e-150, 3.4549185946116918017e-166, 1.3535321672928907047e-182,\n  5.1277664357929471499e-135, 3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182,\n  2.3761243821334675971e-135, 3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182,\n  1.0003033553037281263e-135, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  1.4041521353514076604e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  5.4426399358282049106e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  4.5016298192952031469e-142, -2.8326669474241479263e-158, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  1.9635033141346264592e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  9.3843676940087855824e-144, 1.2626949989038732076e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191,\n  4.2590349703400483539e-144, 1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896458822e-192,\n  1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896458822e-192,\n  4.1503542758849472122e-145, -1.7614040799531193879e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  4.1503542758849472122e-145, -1.7614040799531193879e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  2.105789206980137775e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  2.2883630524598079723e-148, 2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091032843e-196,\n  2.2883630524598079723e-148, 2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091032843e-196,\n  7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.1067843414450286726e-196,\n  7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.1067843414450286726e-196,\n  3.3320377982006123631e-149, 3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198,\n  1.3768785255608653665e-149, 3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198,\n  3.9929888924099219388e-150, -1.9717385086233606481e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.9929888924099219388e-150, -1.9717385086233606481e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  1.5490398016102376505e-150, 3.4549185946116918017e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  7.6922213530572229852e-156, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188, -3.2905064432040069127e-204,\n  7.0002691755702864582e-157, 6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205,\n  7.0002691755702864582e-157, 6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  4.4508689228885539715e-158, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  3.5387999583765925506e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.3321093418096261919e-207,\n  1.2626949989038732076e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.3321093418096261919e-207,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  5.3514239183991277695e-161, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.8567941091539589297e-193, -1.8074851186411640793e-209,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756583552e-212,\n  3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  8.8815756978467430465e-166, 1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  8.8815756978467430465e-166, 1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  3.4549185946116918017e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  2.0862146470760309789e-168, -1.146150630053972131e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  2.0862146470760309789e-168, -1.146150630053972131e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  1.026320681600434562e-168, 1.2072867382105631402e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  4.9637369886263658882e-169, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  2.3140020749373754342e-169, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  9.8913461809288020723e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.2670088967063259373e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.2670088967063259373e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  1.6109245756507072713e-170, -6.2044048008378732802e-187, -5.4322544592823556944e-203, 4.2491789852161138683e-219,\n  7.8288241512289757055e-171, 1.2181824638728806485e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.6886133485899290404e-171, 2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161138683e-219,\n  1.6185079472704052482e-171, 2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161138683e-219,\n  5.8345524661064358191e-172, 6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.0095962991602958391e-175, -6.2404128071707654958e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  3.7785026604276538491e-176, -6.2404128071707654958e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  2.2493122414154495675e-177, 2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  1.2906606599973359683e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189355449e-211, 1.6821693549018732055e-227,\n  1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756578275e-212, 6.2685154049107876715e-228,\n  1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756578275e-212, 6.2685154049107876715e-228,\n  3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  6.0043220944823941786e-183, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  2.2388223052591377446e-183, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  1.2072867382105631402e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  1.2181824638728806485e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161132393e-219, 7.4467067939231424594e-235,\n  2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161132393e-219, 7.4467067939231424594e-235,\n  6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  4.4040360264865697732e-189, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  3.6409303439428119063e-190, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.3965175705582071936e-190, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.3403538552936701153e-191, 1.7826390804083638359e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  6.389748636109812983e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  2.8828536776963681193e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225, 4.2560351759808952526e-241,\n  2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225, 4.2560351759808952526e-241,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  2.6792050150137250131e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  9.6685396110091013832e-196, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  1.9005753194802080146e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  1.9005753194802080146e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  9.3660737343905436753e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  4.5462340041847754398e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  2.1363141390818913221e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  9.3135420653044926323e-182, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  3.2887424025472810002e-182, 7.185309278132283136e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  8.806758170751374203e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  8.806758170751374203e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  4.0998834342223036605e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  1.7464460659577689118e-184, 2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749095611e-233,\n  5.697273818255015375e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  5.697273818255015375e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  2.755477107924346286e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.2845787527590117414e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  5.4912957517634446918e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.8140498638501083305e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.8140498638501083305e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  8.9473839187177424013e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  4.3508265588260719497e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  2.0525478788802367239e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  9.0340853890731911095e-188, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  3.288388689208603045e-188, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  1.1546040067079994973e-190, 1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239,\n  1.1546040067079994973e-190, 1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  1.4863145223629928288e-192, -7.9038076992129241506e-209, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224, -1.8313007053436627876e-240,\n  1.712289129579509076e-193, 1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  1.712289129579509076e-193, 1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  6.1638445507530779946e-194, -6.0361608463951204924e-210, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  3.418509674495068119e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  1.7061586205822532442e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  8.499830936258458068e-196, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  4.218953301476420881e-196, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  2.0785144840854027628e-196, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  1.008295075389893466e-196, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  4.7318537104213881764e-197, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  2.0563051886826149345e-197, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  7.185309278132283136e-198, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  1.306250843215349634e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  6.5304075490021959302e-201, 6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249,\n  3.2643571074265457254e-201, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  1.6313318866387202604e-201, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  8.1481927624480752786e-202, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  4.0656297104785107096e-202, 4.8431832608149701961e-218, 8.3111403472061145651e-234, 1.6001805286092554504e-249,\n  2.0243481844937293316e-202, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  1.0037074215013384159e-202, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  4.9338704000514295811e-203, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  2.3822684925704522921e-203, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  1.1064675388299639308e-203, 2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608782288e-251,\n  4.6856706195971960852e-204, 2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608782288e-251,\n  1.4961682352459748279e-204, -8.0675475439086544798e-221, -3.6970842501441777651e-237, -5.7032870362481275794e-253,\n  1.4961682352459748279e-204, -8.0675475439086544798e-221, -3.6970842501441777651e-237, -5.7032870362481275794e-253,\n  6.9879263915816924805e-205, 9.6377473771091526132e-221, 1.5959741828948633012e-236, 2.7031904319843495713e-252,\n  3.0010484111426663515e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254,\n  1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  1.156336993964950812e-208, 2.7126166236326293347e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  6.1308251778939023781e-210, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  2.3568521170701555846e-212, -7.7818310317651142243e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  1.1686698881356804311e-212, 1.8601114328504743806e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  5.7457877366844311816e-213, 5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  2.7753321643482446169e-213, -1.1860946916976500828e-229, 6.3146909508553973881e-246, 1.2573885592501532045e-261,\n  1.290104378180150675e-213, 2.1117734783360818049e-229, 4.2928382696354204061e-245, -2.8075477999879273582e-261,\n  5.4749048509610403382e-214, 4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501532045e-261,\n  1.7618353855408067201e-214, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  1.7618353855408067201e-214, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  8.3356801918574821257e-215, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  3.6943433600821895879e-215, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  3.2038516259498326923e-217, -1.1817449557784924788e-233, -6.3454186796659920093e-250, -2.6436684620390282645e-267,\n  1.3908294260376086421e-217, 2.8439730252197153919e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  4.8431832608149701961e-218, 8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  9.6377473771091526132e-221, 1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844372114e-268,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  2.318094503184431479e-222, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.318094503184431479e-222, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  9.3486833747991514629e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  7.0351983914592419146e-224, 7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  7.0351983914592419146e-224, 7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.7126166236326293347e-224, -1.8313007053436625212e-240, -2.3341145329525056675e-256, -2.0046830753539155726e-272,\n  5.5132573971932232487e-225, 5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273,\n  5.5132573971932232487e-225, 5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  2.560476225709334075e-227, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  2.560476225709334075e-227, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  1.8601114328504743806e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  2.1117734783360818049e-229, 4.2928382696354204061e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277,\n  4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  2.4841276986611042098e-231, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  1.1958979447416775482e-231, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  5.5178306778196421733e-232, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  2.2972562930210755192e-232, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  2.8439730252197153919e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  3.2789928709583552854e-234, 4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267, -4.3807022524130141006e-284,\n  1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284,\n  1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284,\n  6.1313287894022281692e-237, 5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006739096e-285,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  6.0284645465737476297e-238, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  2.9570854717154947523e-238, 4.3456134301905148502e-254, 6.3684349745470443788e-270, -9.5347405022956042207e-287,\n  1.4213959342863689955e-238, 9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956042207e-287,\n  6.5355116557180594664e-239, 9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956042207e-287,\n  2.6962878121452450746e-239, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  2.9677290991223565342e-240, -2.3341145329525056675e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  2.6827483411022054912e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  1.1830515272065748694e-241, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  4.3320312025875939195e-242, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  5.5552006713333735927e-244, 7.8491179384773690214e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  2.6261053316934700345e-244, 1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997740506e-292,\n  1.1615576618735179302e-244, 1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997740506e-292,\n  4.2928382696354204061e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  1.7379794826680480784e-246, 2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294,\n  1.7379794826680480784e-246, 2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294,\n  5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580810531e-280, 8.8634899828990930877e-296,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  6.3808880963355377617e-251, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  6.3808880963355377617e-251, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.8891343516857640937e-251, 5.1095823452235464813e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  1.1432574793608780349e-251, 1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300,\n  2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  2.4805108027747776379e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  1.1165444962709601017e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  4.3456134301905148502e-254, 6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  2.9938788518280315834e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  1.6338236616337094706e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  8.0132469526175071002e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  3.850752120757712373e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  1.7695047048278150093e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  7.2888099686286655858e-259, 5.581381609158630475e-275, 6.1155422068568946933e-291, 1.0380272777574237546e-306,\n  2.0856914288039227544e-259, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  2.0856914288039227544e-259, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  7.8491179384773690214e-260, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  5.3223249184882342185e-261, -1.472095602234059958e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.1412520821444306741e-262, -6.1787496089661820348e-279, -3.028042329852615431e-295, -2.182740474438892116e-311,\n  5.0610577601348040988e-263, 7.9243314524777990283e-279, -3.028042329852615431e-295, -2.182740474438892116e-311,\n  1.8853262294800541881e-263, 8.7279092175580810531e-280, 8.8634899828990930877e-296, -9.8167844904532653004e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  9.8977243486757054781e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  9.8977243486757054781e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  4.9356438320276576408e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.4546035737036337221e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  1.2140834445416214873e-265, 1.8893435613692150014e-281, 3.0075895258731974416e-297, -9.8167844904532653004e-314,\n  5.9382337996061564537e-266, 5.1208955146257653156e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.8369334767011265554e-266, 5.1208955146257653156e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  1.2862833152486119506e-266, 1.6777604898591683764e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  5.1095823452235464813e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  6.8978448094652555593e-271, 1.1480487920352081009e-286, 7.5257037990230704094e-303, 3.6369654387311681856e-319,\n  6.8978448094652555593e-271, 1.1480487920352081009e-286, 7.5257037990230704094e-303, 3.6369654387311681856e-319,\n  2.1656360647981577662e-271, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  2.1656360647981577662e-271, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  9.825838786313830552e-272, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  3.9105778554799569972e-272, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  9.5294739006302120482e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  9.5294739006302120482e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306, 6.4228533959362050743e-323,\n  0, 0, 0, 0,\n};\n\nstatic const float Sleef_rempitabsp[] = {\n  0.159154892, 5.112411827e-08, 3.626141271e-15, -2.036222915e-22,\n  0.03415493667, 6.420638243e-09, 7.342738037e-17, 8.135951656e-24,\n  0.03415493667, 6.420638243e-09, 7.342738037e-17, 8.135951656e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.0009518179577, 1.342109202e-10, 1.791623576e-17, 1.518506657e-24,\n  0.0009518179577, 1.342109202e-10, 1.791623576e-17, 1.518506657e-24,\n  0.0004635368241, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  0.0002193961991, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  9.73258866e-05, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  3.62907449e-05, 3.243700447e-12, 5.690024473e-19, 7.09405479e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  1.958472239e-06, 5.152167755e-13, 1.3532163e-19, 1.92417627e-26,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  2.132179588e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  6.420638243e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  6.420638243e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  2.695347945e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  8.327027956e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  8.327027956e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  3.670415083e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  1.342109202e-10, 1.791623576e-17, 1.518506361e-24, 2.613904e-31,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  1.424711477e-12, 1.3532163e-19, 1.924175961e-26, 2.545416018e-33,\n  5.152167755e-13, 1.3532163e-19, 1.924175961e-26, 2.545416018e-33,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  1.791623576e-17, 1.518506361e-24, 2.61390353e-31, 4.764937743e-38,\n  1.791623576e-17, 1.518506361e-24, 2.61390353e-31, 4.764937743e-38,\n  4.038449606e-18, -1.358545683e-25, -3.443243946e-32, 6.296048013e-40,\n  4.038449606e-18, -1.358545683e-25, -3.443243946e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  1.3532163e-19, 1.924175961e-26, 2.545415467e-33, 6.296048013e-40,\n  1.3532163e-19, 1.924175961e-26, 2.545415467e-33, 6.296048013e-40,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  1.334890502e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  6.572641438e-21, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  0.05874381959, 1.222115387e-08, 7.693612965e-16, 1.792054435e-22,\n  0.02749382704, 4.77057327e-09, 7.693612965e-16, 1.792054435e-22,\n  0.01186883077, 1.045283415e-09, 3.252721926e-16, 7.332633139e-23,\n  0.00405633077, 1.045283415e-09, 3.252721926e-16, 7.332633139e-23,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  1.275271279e-05, 1.183823005e-12, 1.161414894e-20, 1.291319272e-27,\n  5.12331826e-06, 1.183823005e-12, 1.161414894e-20, 1.291319272e-27,\n  1.308621904e-06, 2.743283031e-13, 1.161414894e-20, 1.291319272e-27,\n  1.308621904e-06, 2.743283031e-13, 1.161414894e-20, 1.291319272e-27,\n  3.549478151e-07, 4.695462769e-14, 1.161414894e-20, 1.291319272e-27,\n  3.549478151e-07, 4.695462769e-14, 1.161414894e-20, 1.291319272e-27,\n  1.165292645e-07, 1.853292503e-14, 4.837885366e-21, 1.291319272e-27,\n  1.165292645e-07, 1.853292503e-14, 4.837885366e-21, 1.291319272e-27,\n  5.69246339e-08, 4.322073705e-15, 1.449754789e-21, 7.962890365e-29,\n  2.712231151e-08, 4.322073705e-15, 1.449754789e-21, 7.962890365e-29,\n  1.222115387e-08, 7.693612965e-16, 1.792054182e-22, 2.91418027e-29,\n  4.77057327e-09, 7.693612965e-16, 1.792054182e-22, 2.91418027e-29,\n  1.045283415e-09, 3.252721926e-16, 7.332632508e-23, 3.898253736e-30,\n  1.045283415e-09, 3.252721926e-16, 7.332632508e-23, 3.898253736e-30,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  5.575349904e-11, 6.083145782e-18, 5.344349223e-25, 1.511644828e-31,\n  2.664967552e-11, -8.557475018e-19, -8.595036458e-26, -2.139883875e-32,\n  1.209775682e-11, 2.61369883e-18, 5.344349223e-25, 1.511644828e-31,\n  4.821800945e-12, 8.789757674e-19, 1.208447639e-25, 3.253064536e-33,\n  1.183823005e-12, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  1.183823005e-12, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  2.743283031e-13, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  0, 0, 0, 0,\n};\n#endif // #ifndef __SLEEF_REMPITAB__\n\n#if !defined(Sleef_quad_DEFINED)\n#define Sleef_quad_DEFINED\ntypedef struct { uint64_t x, y; } Sleef_uint64_2t;\n#if defined(SLEEF_FLOAT128_IS_IEEEQP)\ntypedef __float128 Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## Q)\n#elif defined(SLEEF_LONGDOUBLE_IS_IEEEQP)\ntypedef long double Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## L)\n#else\ntypedef Sleef_uint64_2t Sleef_quad;\n#endif\n#endif\n\nextern const double Sleef_rempitabdp[];\n\ntypedef uint32x4_t vmask_advsimd_sleef;\ntypedef uint32x4_t vopmask_advsimd_sleef;\n\ntypedef float32x4_t vfloat_advsimd_sleef;\ntypedef int32x4_t vint2_advsimd_sleef;\n\ntypedef float64x2_t vdouble_advsimd_sleef;\ntypedef int32x2_t vint_advsimd_sleef;\n\ntypedef int64x2_t vint64_advsimd_sleef;\ntypedef uint64x2_t vuint64_advsimd_sleef;\n\ntypedef struct {\n  vmask_advsimd_sleef x, y;\n} vquad_advsimd_sleef;\n\ntypedef vquad_advsimd_sleef vargquad_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE int vavailability_i_advsimd_sleef(int name) { return 3; }\n\nstatic SLEEF_ALWAYS_INLINE int vtestallones_i_vo32_advsimd_sleef(vopmask_advsimd_sleef g) {\n  uint32x2_t x0 = vand_u32(vget_low_u32(g), vget_high_u32(g));\n  uint32x2_t x1 = vpmin_u32(x0, x0);\n  return vget_lane_u32(x1, 0);\n}\n\nstatic SLEEF_ALWAYS_INLINE int vtestallones_i_vo64_advsimd_sleef(vopmask_advsimd_sleef g) {\n  uint32x2_t x0 = vand_u32(vget_low_u32(g), vget_high_u32(g));\n  uint32x2_t x1 = vpmin_u32(x0, x0);\n  return vget_lane_u32(x1, 0);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vload_vd_p_advsimd_sleef(const double *ptr) { return vld1q_f64(ptr); }\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vloadu_vd_p_advsimd_sleef(const double *ptr) { return vld1q_f64(ptr); }\nstatic SLEEF_ALWAYS_INLINE void vstore_v_p_vd_advsimd_sleef(double *ptr, vdouble_advsimd_sleef v) { vst1q_f64(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vd_advsimd_sleef(double *ptr, vdouble_advsimd_sleef v) { vst1q_f64(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vload_vf_p_advsimd_sleef(const float *ptr) { return vld1q_f32(ptr); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vloadu_vf_p_advsimd_sleef(const float *ptr) { return vld1q_f32(ptr); }\nstatic SLEEF_ALWAYS_INLINE void vstore_v_p_vf_advsimd_sleef(float *ptr, vfloat_advsimd_sleef v) { vst1q_f32(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vf_advsimd_sleef(float *ptr, vfloat_advsimd_sleef v) { vst1q_f32(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vloadu_vi2_p_advsimd_sleef(int32_t *p) { return vld1q_s32(p); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vi2_advsimd_sleef(int32_t *p, vint2_advsimd_sleef v) { vst1q_s32(p, v); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vloadu_vi_p_advsimd_sleef(int32_t *p) { return vld1_s32(p); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vi_advsimd_sleef(int32_t *p, vint_advsimd_sleef v) { vst1_s32(p, v); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vgather_vd_p_vi_advsimd_sleef(const double *ptr, vint_advsimd_sleef vi) {\n  return ((vdouble_advsimd_sleef) { ptr[vget_lane_s32(vi, 0)], ptr[vget_lane_s32(vi, 1)]} );\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vgather_vf_p_vi2_advsimd_sleef(const float *ptr, vint2_advsimd_sleef vi2) {\n  return ((vfloat_advsimd_sleef) {\n      ptr[vgetq_lane_s32(vi2, 0)],\n      ptr[vgetq_lane_s32(vi2, 1)],\n      ptr[vgetq_lane_s32(vi2, 2)],\n      ptr[vgetq_lane_s32(vi2, 3)]\n    });\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vand_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return vandq_u32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vandnot_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vbicq_u32(y, x);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vor_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return vorrq_u32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vxor_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return veorq_u32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vreinterpret_vm_vf_advsimd_sleef(vfloat_advsimd_sleef vf) {\n  return vreinterpretq_u32_f32(vf);\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vreinterpret_vf_vm_advsimd_sleef(vmask_advsimd_sleef vm) {\n  return vreinterpretq_f32_u32(vm);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vcast_vi2_vm_advsimd_sleef(vmask_advsimd_sleef vm) { return vreinterpretq_s32_u32(vm); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcast_vm_vi2_advsimd_sleef(vint2_advsimd_sleef vi) { return vreinterpretq_u32_s32(vi); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vreinterpret_vm_vd_advsimd_sleef(vdouble_advsimd_sleef vd_advsimd_sleef) {\n  return vreinterpretq_u32_f64(vd_advsimd_sleef);\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vreinterpret_vd_vm_advsimd_sleef(vmask_advsimd_sleef vm) {\n  return vreinterpretq_f64_u32(vm);\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vreinterpret_vf_vi2_advsimd_sleef(vint2_advsimd_sleef vm) {\n  return vreinterpretq_f32_s32(vm);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vreinterpret_vi2_vf_advsimd_sleef(vfloat_advsimd_sleef vf) {\n  return vreinterpretq_s32_f32(vf);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vcast_vf_f_advsimd_sleef(float f) { return vdupq_n_f32(f); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vadd_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vaddq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsub_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vsubq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmul_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vmulq_f32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vabs_vf_vf_advsimd_sleef(vfloat_advsimd_sleef f) { return vabsq_f32(f); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vneg_vf_vf_advsimd_sleef(vfloat_advsimd_sleef f) { return vnegq_f32(f); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmla_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfmaq_f32(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmlanp_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfmsq_f32(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmlapn_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vneg_vf_vf_advsimd_sleef(vfmsq_f32(z, x, y));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vfma_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfmaq_f32(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vfmanp_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfmsq_f32(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vfmapn_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfma_vf_vf_vf_vf_advsimd_sleef(x, y, vneg_vf_vf_advsimd_sleef(z));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vdiv_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef n, vfloat_advsimd_sleef d) {\n\n  return vdivq_f32(n, d);\n\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vrec_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n\n  return vdiv_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsqrt_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n\n  return vsqrtq_f32(d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmax_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vmaxq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmin_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vminq_f32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef veq_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vceqq_f32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vneq_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vmvnq_u32(vceqq_f32(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vlt_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vcltq_f32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vle_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vcleq_f32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vgt_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vcgtq_f32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vge_vm_vf_vf(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vcgeq_f32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsel_vf_vm_vf_vf(vmask_advsimd_sleef mask, vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vbslq_f32(mask, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vtruncate_vi2_vf_advsimd_sleef(vfloat_advsimd_sleef vf) { return vcvtq_s32_f32(vf); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vcast_vf_vi2_advsimd_sleef(vint2_advsimd_sleef vi) { return vcvtq_f32_s32(vi); }\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vcast_vi2_i_advsimd_sleef(int i) { return vdupq_n_s32(i); }\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vrint_vi2_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return vcvtq_s32_f32(vrndnq_f32(d));\n}\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vadd_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vaddq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vsub_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vsubq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vneg_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef e) { return vnegq_s32(e); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vand_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vandq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vandnot_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vbicq_s32(y, x);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vor_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vorrq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vxor_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return veorq_s32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef veq_vm_vi2_vi2(vint2_advsimd_sleef x, vint2_advsimd_sleef y) { return vceqq_s32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vgt_vm_vi2_vi2(vint2_advsimd_sleef x, vint2_advsimd_sleef y) { return vcgeq_s32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vgt_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vreinterpretq_s32_u32(vcgtq_s32(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef veq_vi2_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vreinterpretq_s32_u32(vceqq_s32(x, y));\n}\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vsel_vi2_vm_vi2_vi2(vmask_advsimd_sleef m, vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vbslq_s32(m, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vcast_vd_d_advsimd_sleef(double f) { return vdupq_n_f64(f); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vadd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vaddq_f64(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsub_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vsubq_f64(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmul_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vmulq_f64(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vabs_vd_vd_advsimd_sleef(vdouble_advsimd_sleef f) { return vabsq_f64(f); }\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vneg_vd_vd_advsimd_sleef(vdouble_advsimd_sleef f) { return vnegq_f64(f); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmax_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vmaxq_f64(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmin_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vminq_f64(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmla_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfmaq_f64(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmlanp_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfmsq_f64(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmlapn_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vneg_vd_vd_advsimd_sleef(vfmsq_f64(z, x, y));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vfma_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfmaq_f64(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vfmanp_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfmsq_f64(z, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vfmapn_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfma_vd_vd_vd_vd_advsimd_sleef(x, y, vneg_vd_vd_advsimd_sleef(z));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vdiv_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef n, vdouble_advsimd_sleef d) {\n\n  return vdivq_f64(n, d);\n\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vrec_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n\n  return vdiv_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1.0f), d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsqrt_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n\n  return vsqrtq_f64(d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef veq_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vceqq_f64(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vneq_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vmvnq_u32(vreinterpretq_u32_u64(vceqq_f64(x, y)));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vlt_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vcltq_f64(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vgt_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vcgtq_f64(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vle_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vcleq_f64(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vge_vo_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vcgeq_f64(x, y));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsel_vd_vo_vd_vd_advsimd_sleef(vopmask_advsimd_sleef mask, vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vbslq_f64(vreinterpretq_u64_u32(mask), x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsel_vd_vo_d_d_advsimd_sleef(vopmask_advsimd_sleef o, double v1, double v0) {\n  return vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(v1), vcast_vd_d_advsimd_sleef(v0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsel_vd_vo_vo_d_d_d_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, double d0, double d1, double d2) {\n  return vsel_vd_vo_vd_vd_advsimd_sleef(o0, vcast_vd_d_advsimd_sleef(d0), vsel_vd_vo_d_d_advsimd_sleef(o1, d1, d2));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, vopmask_advsimd_sleef o2, double d0, double d1, double d2, double d3) {\n  return vsel_vd_vo_vd_vd_advsimd_sleef(o0, vcast_vd_d_advsimd_sleef(d0), vsel_vd_vo_vd_vd_advsimd_sleef(o1, vcast_vd_d_advsimd_sleef(d1), vsel_vd_vo_d_d_advsimd_sleef(o2, d2, d3)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vrint_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) { return vrndnq_f64(d); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vrint_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) { return vrndnq_f32(d); }\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vtruncate_vi_vd_advsimd_sleef(vdouble_advsimd_sleef vf) {\n  return vmovn_s64(vcvtq_s64_f64(vf));\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vcast_vd_vi_advsimd_sleef(vint_advsimd_sleef vi) {\n  return vcvtq_f64_s64(vmovl_s32(vi));\n}\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vcast_vi_i_advsimd_sleef(int i) { return vdup_n_s32(i); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vrint_vi_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vqmovn_s64(vcvtq_s64_f64(vrndnq_f64(d)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vadd_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return vadd_s32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vsub_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return vsub_s32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vneg_vi_vi_advsimd_sleef(vint_advsimd_sleef e) { return vneg_s32(e); }\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vand_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return vand_s32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vandnot_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return vbic_s32(y, x); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vor_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return vorr_s32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vxor_vi_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) { return veor_s32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef veq_vo_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vcombine_u32(vceq_s32(x, y), vdup_n_u32(0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vsel_vi_vm_vi_vi(vmask_advsimd_sleef m, vint_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vbsl_s32(vget_low_u32(m), x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visinf_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  const float64x2_t inf = vdupq_n_f64(__builtin_inf());\n  const float64x2_t neg_inf = vdupq_n_f64(-__builtin_inf());\n  uint64x2_t cmp = vorrq_u64(vceqq_f64(d, inf), vceqq_f64(d, neg_inf));\n  return vreinterpretq_u32_u64(cmp);\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visnan_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vmvnq_u32(vreinterpretq_u32_u64(vceqq_f64(d, d)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vispinf_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vreinterpretq_u32_u64(vceqq_f64(d, vdupq_n_f64(__builtin_inf())));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visminf_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vreinterpretq_u32_u64(vceqq_f64(d, vdupq_n_f64(-__builtin_inf())));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsel_vf_vo_vf_vf_advsimd_sleef(vopmask_advsimd_sleef mask, vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vbslq_f32(mask, x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vsel_vf_vo_f_f_advsimd_sleef(vopmask_advsimd_sleef o, float v1, float v0) {\n  return vsel_vf_vo_vf_vf_advsimd_sleef(o, vcast_vf_f_advsimd_sleef(v1), vcast_vf_f_advsimd_sleef(v0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsel_vf_vo_vo_f_f_f_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, float d0, float d1, float d2) {\n  return vsel_vf_vo_vf_vf_advsimd_sleef(o0, vcast_vf_f_advsimd_sleef(d0), vsel_vf_vo_f_f_advsimd_sleef(o1, d1, d2));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, vopmask_advsimd_sleef o2, float d0, float d1, float d2, float d3) {\n  return vsel_vf_vo_vf_vf_advsimd_sleef(o0, vcast_vf_f_advsimd_sleef(d0), vsel_vf_vo_vf_vf_advsimd_sleef(o1, vcast_vf_f_advsimd_sleef(d1), vsel_vf_vo_f_f_advsimd_sleef(o2, d2, d3)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef veq_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vceqq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vneq_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vmvnq_u32(vceqq_f32(x, y));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vlt_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vcltq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vle_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vcleq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vgt_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vcgtq_f32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vge_vo_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vcgeq_f32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef veq_vo_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vceqq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vgt_vo_vi2_vi2_advsimd_sleef(vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vcgtq_s32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vgt_vo_vi_vi_advsimd_sleef(vint_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vcombine_u32(vcgt_s32(x, y), vdup_n_u32(0));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visinf_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return veq_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inff()));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vispinf_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(__builtin_inff()));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visminf_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-__builtin_inff()));\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef visnan_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) { return vneq_vo_vf_vf_advsimd_sleef(d, d); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vcast_vo32_vo64_advsimd_sleef(vopmask_advsimd_sleef m) {\n  return vuzpq_u32(m, m).val[0];\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vcast_vo64_vo32_advsimd_sleef(vopmask_advsimd_sleef m) {\n  return vzipq_u32(m, m).val[0];\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vcast_vo_i_advsimd_sleef(int i) {\n  return vreinterpretq_u32_u64(vdupq_n_u64((uint64_t)(i ? -1 : 0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vand_vo_vo_vo_advsimd_sleef(vopmask_advsimd_sleef x, vopmask_advsimd_sleef y) {\n  return vandq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vandnot_vo_vo_vo_advsimd_sleef(vopmask_advsimd_sleef x, vopmask_advsimd_sleef y) {\n  return vbicq_u32(y, x);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vor_vo_vo_vo_advsimd_sleef(vopmask_advsimd_sleef x, vopmask_advsimd_sleef y) {\n  return vorrq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vxor_vo_vo_vo_advsimd_sleef(vopmask_advsimd_sleef x, vopmask_advsimd_sleef y) {\n  return veorq_u32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vsel_vi2_vo_vi2_vi2_advsimd_sleef(vopmask_advsimd_sleef m, vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vbslq_s32(m, x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vand_vi2_vo_vi2_advsimd_sleef(vopmask_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vandq_s32(vreinterpretq_s32_u32(x), y);\n}\nstatic SLEEF_ALWAYS_INLINE vint2_advsimd_sleef vandnot_vi2_vo_vi2_advsimd_sleef(vopmask_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vbicq_s32(y, vreinterpretq_s32_u32(x));\n}\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vandnot_vi_vo_vi_advsimd_sleef(vopmask_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vbic_s32(y, vget_low_s32(vreinterpretq_s32_u32(x)));\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vand_vm_vo32_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vandq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vand_vm_vo64_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vandq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vandnot_vm_vo32_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vbicq_u32(y, x);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vandnot_vm_vo64_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vbicq_u32(y, x);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vor_vm_vo32_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vorrq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vor_vm_vo64_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vorrq_u32(x, y);\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vxor_vm_vo32_vm_advsimd_sleef(vopmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return veorq_u32(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vtruncate_vf_vf_advsimd_sleef(vfloat_advsimd_sleef vd_advsimd_sleef) { return vrndq_f32(vd_advsimd_sleef); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcast_vm_i_i_advsimd_sleef(int i0, int i1) {\n  return vreinterpretq_u32_u64(vdupq_n_u64((0xffffffff & (uint64_t)i1) | (((uint64_t)i0) << 32)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcast_vm_i64_advsimd_sleef(int64_t i) {\n  return vreinterpretq_u32_u64(vdupq_n_u64((uint64_t)i));\n}\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcast_vm_u64_advsimd_sleef(uint64_t i) {\n  return vreinterpretq_u32_u64(vdupq_n_u64(i));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef veq64_vo_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vceqq_s64(vreinterpretq_s64_u32(x), vreinterpretq_s64_u32(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vadd64_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vreinterpretq_u32_s64(vaddq_s64(vreinterpretq_s64_u32(x), vreinterpretq_s64_u32(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vsel_vi_vo_vi_vi_advsimd_sleef(vopmask_advsimd_sleef m, vint_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vbsl_s32(vget_low_u32(m), x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vand_vi_vo_vi_advsimd_sleef(vopmask_advsimd_sleef x, vint_advsimd_sleef y) {\n  return vand_s32(vreinterpret_s32_u32(vget_low_u32(x)), y);\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcastu_vm_vi_advsimd_sleef(vint_advsimd_sleef vi) {\n  return vrev64q_u32(vreinterpretq_u32_u64(vmovl_u32(vreinterpret_u32_s32(vi))));\n}\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vcastu_vi_vm_advsimd_sleef(vmask_advsimd_sleef vi2) {\n  return vreinterpret_s32_u32(vmovn_u64(vreinterpretq_u64_u32(vrev64q_u32(vi2))));\n}\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vtruncate_vd_vd_advsimd_sleef(vdouble_advsimd_sleef vd_advsimd_sleef) { return vrndq_f64(vd_advsimd_sleef); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vposneg_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) { return vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(((vdouble_advsimd_sleef) { +0.0, -0.0 })))); }\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vnegpos_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) { return vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(((vdouble_advsimd_sleef) { -0.0, +0.0 })))); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vposneg_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) { return (vfloat_advsimd_sleef)vxor_vm_vm_vm_advsimd_sleef((vmask_advsimd_sleef)d, (vmask_advsimd_sleef)((vfloat_advsimd_sleef) { +0.0f, -0.0f, +0.0f, -0.0f })); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vnegpos_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) { return (vfloat_advsimd_sleef)vxor_vm_vm_vm_advsimd_sleef((vmask_advsimd_sleef)d, (vmask_advsimd_sleef)((vfloat_advsimd_sleef) { -0.0f, +0.0f, -0.0f, +0.0f })); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vsubadd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) { return vadd_vd_vd_vd_advsimd_sleef(x, vnegpos_vd_vd_advsimd_sleef(y)); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vsubadd_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d0, vfloat_advsimd_sleef d1) { return vadd_vf_vf_vf_advsimd_sleef(d0, vnegpos_vf_vf_advsimd_sleef(d1)); }\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vmlsubadd_vd_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) { return vsubadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, y), z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vmlsubadd_vf_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) { return vsubadd_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x, y), z); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vrev21_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d0) { return (float64x2_t)vcombine_u64(vget_high_u64((uint64x2_t)d0), vget_low_u64((uint64x2_t)d0)); }\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vreva2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef vd_advsimd_sleef) { return vd_advsimd_sleef; }\n\nstatic SLEEF_ALWAYS_INLINE void vstream_v_p_vd_advsimd_sleef(double *ptr, vdouble_advsimd_sleef v) { vstore_v_p_vd_advsimd_sleef(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vscatter2_v_p_i_i_vd_advsimd_sleef(double *ptr, int offset, int step, vdouble_advsimd_sleef v) { vstore_v_p_vd_advsimd_sleef((double *)(&ptr[2*offset]), v); }\nstatic SLEEF_ALWAYS_INLINE void vsscatter2_v_p_i_i_vd_advsimd_sleef(double *ptr, int offset, int step, vdouble_advsimd_sleef v) { vstore_v_p_vd_advsimd_sleef((double *)(&ptr[2*offset]), v); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vrev21_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d0) { return vrev64q_f32(d0); }\nstatic SLEEF_ALWAYS_INLINE vfloat_advsimd_sleef vreva2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d0) { return vcombine_f32(vget_high_f32(d0), vget_low_f32(d0)); }\n\nstatic SLEEF_ALWAYS_INLINE void vstream_v_p_vf_advsimd_sleef(float *ptr, vfloat_advsimd_sleef v) { vstore_v_p_vf_advsimd_sleef(ptr, v); }\n\nstatic SLEEF_ALWAYS_INLINE void vscatter2_v_p_i_i_vf_advsimd_sleef(float *ptr, int offset, int step, vfloat_advsimd_sleef v) {\n  vst1_f32((float *)(ptr+(offset + step * 0)*2), vget_low_f32(v));\n  vst1_f32((float *)(ptr+(offset + step * 1)*2), vget_high_f32(v));\n}\n\nstatic SLEEF_ALWAYS_INLINE void vsscatter2_v_p_i_i_vf_advsimd_sleef(float *ptr, int offset, int step, vfloat_advsimd_sleef v) {\n  vst1_f32((float *)(ptr+(offset + step * 0)*2), vget_low_f32(v));\n  vst1_f32((float *)(ptr+(offset + step * 1)*2), vget_high_f32(v));\n}\n\nstatic vquad_advsimd_sleef loadu_vq_p_advsimd_sleef(void *p) {\n  vquad_advsimd_sleef vq;\n  memcpy(&vq, p, (1 << 1) * 16);\n  return vq;\n}\n\nstatic SLEEF_ALWAYS_INLINE vquad_advsimd_sleef cast_vq_aq_advsimd_sleef(vargquad_advsimd_sleef aq) {\n  vquad_advsimd_sleef vq;\n  memcpy(&vq, &aq, (1 << 1) * 16);\n  return vq;\n}\n\nstatic SLEEF_ALWAYS_INLINE vargquad_advsimd_sleef cast_aq_vq_advsimd_sleef(vquad_advsimd_sleef vq) {\n  vargquad_advsimd_sleef aq;\n  memcpy(&aq, &vq, (1 << 1) * 16);\n  return aq;\n}\n\nstatic SLEEF_ALWAYS_INLINE int vtestallzeros_i_vo64_advsimd_sleef(vopmask_advsimd_sleef g) {\n  uint32x2_t x0 = vorr_u32(vget_low_u32(g), vget_high_u32(g));\n  uint32x2_t x1 = vpmax_u32(x0, x0);\n  return ~vget_lane_u32(x1, 0);\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vsel_vm_vo64_vm_vm_advsimd_sleef(vopmask_advsimd_sleef m, vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return vbslq_u32(m, x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vsub64_vm_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vreinterpretq_u32_s64(vsubq_s64(vreinterpretq_s64_u32(x), vreinterpretq_s64_u32(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vneg64_vm_vm_advsimd_sleef(vmask_advsimd_sleef x) {\n  return vreinterpretq_u32_s64(vnegq_s64(vreinterpretq_s64_u32(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vgt64_vo_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  return vreinterpretq_u32_u64(vcgtq_s64(vreinterpretq_s64_u32(x), vreinterpretq_s64_u32(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vcast_vm_vi_advsimd_sleef(vint_advsimd_sleef vi) {\n  vmask_advsimd_sleef m = vreinterpretq_u32_u64(vmovl_u32(vreinterpret_u32_s32(vi)));\n  return vor_vm_vm_vm_advsimd_sleef(vcastu_vm_vi_advsimd_sleef(vreinterpret_s32_u32(vget_low_u32(vgt_vo_vi_vi_advsimd_sleef(vcast_vi_i_advsimd_sleef(0), vi)))), m);\n}\nstatic SLEEF_ALWAYS_INLINE vint_advsimd_sleef vcast_vi_vm_advsimd_sleef(vmask_advsimd_sleef vm) { return vreinterpret_s32_u32(vmovn_u64(vreinterpretq_u64_u32(vm))); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vreinterpret_vm_vi64_advsimd_sleef(vint64_advsimd_sleef v) { return vreinterpretq_u32_s64(v); }\nstatic SLEEF_ALWAYS_INLINE vint64_advsimd_sleef vreinterpret_vi64_vm_advsimd_sleef(vmask_advsimd_sleef m) { return vreinterpretq_s64_u32(m); }\nstatic SLEEF_ALWAYS_INLINE vmask_advsimd_sleef vreinterpret_vm_vu64_advsimd_sleef(vuint64_advsimd_sleef v) { return vreinterpretq_u32_u64(v); }\nstatic SLEEF_ALWAYS_INLINE vuint64_advsimd_sleef vreinterpret_vu64_vm_advsimd_sleef(vmask_advsimd_sleef m) { return vreinterpretq_u64_u32(m); }\n\ntypedef struct {\n  vdouble_advsimd_sleef x, y;\n} vdouble2_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vd2getx_vd_vd2_advsimd_sleef(vdouble2_advsimd_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vd2gety_vd_vd2_advsimd_sleef(vdouble2_advsimd_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vd2setxy_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) { vdouble2_advsimd_sleef v; v.x = x; v.y = y; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vd2setx_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef v, vdouble_advsimd_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vd2sety_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef v, vdouble_advsimd_sleef d) { v.y = d; return v; }\n\ntypedef struct {\n  double x, y;\n} double2_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST double2_advsimd_sleef dd_advsimd_sleef(double h, double l) {\n  double2_advsimd_sleef ret = { h, l };\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vupper_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vreinterpret_vd_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vcast_vm_i_i_advsimd_sleef(0xffffffff, 0xf8000000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vcast_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef h, vdouble_advsimd_sleef l) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(h, l);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vcast_vd2_d_d_advsimd_sleef(double h, double l) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(h), vcast_vd_d_advsimd_sleef(l));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vcast_vd2_d2_advsimd_sleef(double2_advsimd_sleef dd_advsimd_sleef) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(dd_advsimd_sleef.x), vcast_vd_d_advsimd_sleef(dd_advsimd_sleef.y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vsel_vd2_vo_vd2_vd2_advsimd_sleef(vopmask_advsimd_sleef m, vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(m, vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y)),\n       vsel_vd_vo_vd_vd_advsimd_sleef(m, vd2gety_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef vsel_vd2_vo_d_d_d_d_advsimd_sleef(vopmask_advsimd_sleef o, double x1, double y1, double x0, double y0) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_d_d_advsimd_sleef(o, x1, x0),\n       vsel_vd_vo_d_d_advsimd_sleef(o, y1, y0));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vadd_vd_3vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2) {\n  return vadd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vadd_vd_4vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3) {\n  return vadd_vd_3vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vadd_vd_5vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3, vdouble_advsimd_sleef v4) {\n  return vadd_vd_4vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vadd_vd_6vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3, vdouble_advsimd_sleef v4, vdouble_advsimd_sleef v5) {\n  return vadd_vd_5vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vadd_vd_7vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3, vdouble_advsimd_sleef v4, vdouble_advsimd_sleef v5, vdouble_advsimd_sleef v6) {\n  return vadd_vd_6vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3, v4, v5, v6);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsub_vd_3vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2) {\n  return vsub_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsub_vd_4vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3) {\n  return vsub_vd_3vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsub_vd_5vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3, vdouble_advsimd_sleef v4) {\n  return vsub_vd_4vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsub_vd_6vd_advsimd_sleef(vdouble_advsimd_sleef v0, vdouble_advsimd_sleef v1, vdouble_advsimd_sleef v2, vdouble_advsimd_sleef v3, vdouble_advsimd_sleef v4, vdouble_advsimd_sleef v5) {\n  return vsub_vd_5vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddneg_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x) {\n  return vcast_vd2_vd_vd_advsimd_sleef(vneg_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)), vneg_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddabs_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x) {\n  return vcast_vd2_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)),\n    vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)),\n         vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)),\n         vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddnormalize_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef t) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), vd2gety_vd_vd2_advsimd_sleef(t));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), s), vd2gety_vd_vd2_advsimd_sleef(t)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddscale_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef d, vdouble_advsimd_sleef s) {\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), s), vmul_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(d), s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddscale_vd2_vd2_d_advsimd_sleef(vdouble2_advsimd_sleef d, double s) { return ddscale_vd2_vd2_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(s)); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd2_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(x, y);\n  vdouble_advsimd_sleef v = vsub_vd_vd_vd_advsimd_sleef(s, x);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, vsub_vd_vd_vd_advsimd_sleef(s, v)), vsub_vd_vd_vd_advsimd_sleef(y, v)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_3vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), s), y, vd2gety_vd_vd2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsub_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), s), y), vd2gety_vd_vd2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd2_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), y);\n  vdouble_advsimd_sleef v = vsub_vd_vd_vd_advsimd_sleef(s, vd2getx_vd_vd2_advsimd_sleef(x));\n  vdouble_advsimd_sleef w = vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vsub_vd_vd_vd_advsimd_sleef(s, v)), vsub_vd_vd_vd_advsimd_sleef(y, v));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(w, vd2gety_vd_vd2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd_vd2_vd_vd2_advsimd_sleef(vdouble_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(x, vd2getx_vd_vd2_advsimd_sleef(y));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_3vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, s), vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd2_vd2_vd_vd2_advsimd_sleef(vdouble_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(x, vd2getx_vd_vd2_advsimd_sleef(y));\n  vdouble_advsimd_sleef v = vsub_vd_vd_vd_advsimd_sleef(s, x);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, vsub_vd_vd_vd_advsimd_sleef(s, v)),\n          vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), v)), vd2gety_vd_vd2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_4vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), s), vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddadd2_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y));\n  vdouble_advsimd_sleef v = vsub_vd_vd_vd_advsimd_sleef(s, vd2getx_vd_vd2_advsimd_sleef(x));\n  vdouble_advsimd_sleef t = vadd_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vsub_vd_vd_vd_advsimd_sleef(s, v)), vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), v));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vadd_vd_vd_vd_advsimd_sleef(t, vadd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsub_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n\n  vdouble_advsimd_sleef s = vsub_vd_vd_vd_advsimd_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vsub_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsub_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n\n  vdouble_advsimd_sleef s = vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y));\n  vdouble_advsimd_sleef t = vsub_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), s);\n  t = vsub_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(y));\n  t = vadd_vd_vd_vd_advsimd_sleef(t, vd2gety_vd_vd2_advsimd_sleef(x));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vsub_vd_vd_vd_advsimd_sleef(t, vd2gety_vd_vd2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef dddiv_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef n, vdouble2_advsimd_sleef d) {\n  vdouble_advsimd_sleef t = vrec_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d));\n  vdouble_advsimd_sleef s = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(n), t);\n  vdouble_advsimd_sleef u = vfmapn_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(n), s);\n  vdouble_advsimd_sleef v = vfmanp_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(d), t, vfmanp_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), t, vcast_vd_d_advsimd_sleef(1)));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vfma_vd_vd_vd_vd_advsimd_sleef(s, v, vfma_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(n), t, u)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddmul_vd2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vmul_vd_vd_vd_advsimd_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vfmapn_vd_vd_vd_vd_advsimd_sleef(x, y, s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsqu_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x) {\n  vdouble_advsimd_sleef s = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vfma_vd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x)), vd2gety_vd_vd2_advsimd_sleef(x), vfmapn_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x), s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddmul_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vfma_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(y), vfma_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y), vfmapn_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y), s))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef ddmul_vd_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y) {\n  return vfma_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y), vfma_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y), vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef ddsqu_vd_vd2_advsimd_sleef(vdouble2_advsimd_sleef x) {\n  return vfma_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x), vadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x)), vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddmul_vd2_vd2_vd_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef s = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vfma_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x), y, vfmapn_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), y, s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddrec_vd2_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef s = vrec_vd_vd_advsimd_sleef(d);\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(s, vfmanp_vd_vd_vd_vd_advsimd_sleef(d, s, vcast_vd_d_advsimd_sleef(1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddrec_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef d) {\n  vdouble_advsimd_sleef s = vrec_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d));\n  return vd2setxy_vd2_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(s, vfmanp_vd_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(d), s, vfmanp_vd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), s, vcast_vd_d_advsimd_sleef(1)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsqrt_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef d) {\n  vdouble_advsimd_sleef t = vsqrt_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)));\n  return ddscale_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd2_advsimd_sleef(d, ddmul_vd2_vd_vd_advsimd_sleef(t, t)), ddrec_vd2_vd_advsimd_sleef(t)), vcast_vd_d_advsimd_sleef(0.5));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddsqrt_vd2_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef t = vsqrt_vd_vd_advsimd_sleef(d);\n  return ddscale_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd2_advsimd_sleef(d, ddmul_vd2_vd_vd_advsimd_sleef(t, t)), ddrec_vd2_vd_advsimd_sleef(t)), vcast_vd_d_advsimd_sleef(0.5));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddmla_vd2_vd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef x, vdouble2_advsimd_sleef y, vdouble2_advsimd_sleef z) {\n  return ddadd_vd2_vd2_vd2_advsimd_sleef(z, ddmul_vd2_vd2_vd2_advsimd_sleef(x, y));\n}\n\ntypedef struct {\n  vdouble_advsimd_sleef x, y, z;\n} vdouble3_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vd3getx_vd_vd3_advsimd_sleef(vdouble3_advsimd_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vd3gety_vd_vd3_advsimd_sleef(vdouble3_advsimd_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vd3getz_vd_vd3_advsimd_sleef(vdouble3_advsimd_sleef v) { return v.z; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef vd3setxyz_vd3_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  vdouble3_advsimd_sleef v = { x, y, z };\n  return v;\n}\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef vd3setx_vd3_vd3_vd_advsimd_sleef(vdouble3_advsimd_sleef v, vdouble_advsimd_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef vd3sety_vd3_vd3_vd_advsimd_sleef(vdouble3_advsimd_sleef v, vdouble_advsimd_sleef d) { v.y = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef vd3setz_vd3_vd3_vd_advsimd_sleef(vdouble3_advsimd_sleef v, vdouble_advsimd_sleef d) { v.z = d; return v; }\n\ntypedef struct {\n  vdouble2_advsimd_sleef a, b;\n} dd2_advsimd_sleef;\n\nstatic dd2_advsimd_sleef dd2setab_dd2_vd2_vd2_advsimd_sleef(vdouble2_advsimd_sleef a, vdouble2_advsimd_sleef b) {\n  dd2_advsimd_sleef r = { a, b };\n  return r;\n}\nstatic vdouble2_advsimd_sleef dd2geta_vd2_dd2_advsimd_sleef(dd2_advsimd_sleef d) { return d.a; }\nstatic vdouble2_advsimd_sleef dd2getb_vd2_dd2_advsimd_sleef(dd2_advsimd_sleef d) { return d.b; }\n\ntypedef struct {\n  vmask_advsimd_sleef e;\n  vdouble3_advsimd_sleef d3;\n} tdx_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef tdxgete_vm_tdx_advsimd_sleef(tdx_advsimd_sleef t) { return t.e; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef tdxgetd3_vd3_tdx_advsimd_sleef(tdx_advsimd_sleef t) { return t.d3; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef tdxgetd3x_vd_tdx_advsimd_sleef(tdx_advsimd_sleef t) { return t.d3.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef tdxgetd3y_vd_tdx_advsimd_sleef(tdx_advsimd_sleef t) { return t.d3.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef tdxgetd3z_vd_tdx_advsimd_sleef(tdx_advsimd_sleef t) { return t.d3.z; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsete_tdx_tdx_vm_advsimd_sleef(tdx_advsimd_sleef t, vmask_advsimd_sleef e) { t.e = e; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsetd3_tdx_tdx_vd3_advsimd_sleef(tdx_advsimd_sleef t, vdouble3_advsimd_sleef d3) { t.d3 = d3; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsetx_tdx_tdx_vd_advsimd_sleef(tdx_advsimd_sleef t, vdouble_advsimd_sleef x) { t.d3.x = x; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsety_tdx_tdx_vd_advsimd_sleef(tdx_advsimd_sleef t, vdouble_advsimd_sleef y) { t.d3.y = y; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsetz_tdx_tdx_vd_advsimd_sleef(tdx_advsimd_sleef t, vdouble_advsimd_sleef z) { t.d3.z = z; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsetxyz_tdx_tdx_vd_vd_vd_advsimd_sleef(tdx_advsimd_sleef t, vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  t.d3 = (vdouble3_advsimd_sleef) { x, y, z };\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxseted3_tdx_vm_vd3_advsimd_sleef(vmask_advsimd_sleef e, vdouble3_advsimd_sleef d3) { return (tdx_advsimd_sleef) { e, d3 }; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_advsimd_sleef tdxsetexyz_tdx_vm_vd_vd_vd_advsimd_sleef(vmask_advsimd_sleef e, vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return (tdx_advsimd_sleef) { e, (vdouble3_advsimd_sleef) { x, y, z } };\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vqgetx_vm_vq_advsimd_sleef(vquad_advsimd_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vqgety_vm_vq_advsimd_sleef(vquad_advsimd_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef vqsetxy_vq_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return (vquad_advsimd_sleef) { x, y }; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef vqsetx_vq_vq_vm_advsimd_sleef(vquad_advsimd_sleef v, vmask_advsimd_sleef x) { v.x = x; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef vqsety_vq_vq_vm_advsimd_sleef(vquad_advsimd_sleef v, vmask_advsimd_sleef y) { v.y = y; return v; }\n\ntypedef struct {\n  vdouble_advsimd_sleef d;\n  vint_advsimd_sleef i;\n} di_t_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef digetd_vd_di_advsimd_sleef(di_t_advsimd_sleef d) { return d.d; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef digeti_vi_di_advsimd_sleef(di_t_advsimd_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST di_t_advsimd_sleef disetdi_di_vd_vi_advsimd_sleef(vdouble_advsimd_sleef d, vint_advsimd_sleef i) {\n  di_t_advsimd_sleef r = { d, i };\n  return r;\n}\n\ntypedef struct {\n  vdouble2_advsimd_sleef dd_advsimd_sleef;\n  vint_advsimd_sleef i;\n} ddi_t_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddigetdd_vd2_ddi_advsimd_sleef(ddi_t_advsimd_sleef d) { return d.dd_advsimd_sleef; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef ddigeti_vi_ddi_advsimd_sleef(ddi_t_advsimd_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_advsimd_sleef ddisetddi_ddi_vd2_vi_advsimd_sleef(vdouble2_advsimd_sleef v, vint_advsimd_sleef i) {\n  ddi_t_advsimd_sleef r = { v, i };\n  return r;\n}\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_advsimd_sleef ddisetdd_ddi_ddi_vd2_advsimd_sleef(ddi_t_advsimd_sleef ddi_advsimd_sleef, vdouble2_advsimd_sleef v) {\n  ddi_advsimd_sleef.dd_advsimd_sleef = v;\n  return ddi_advsimd_sleef;\n}\n\ntypedef struct {\n  vdouble3_advsimd_sleef td_advsimd_sleef;\n  vint_advsimd_sleef i;\n} tdi_t_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_advsimd_sleef tdigettd_vd3_tdi_advsimd_sleef(tdi_t_advsimd_sleef d) { return d.td_advsimd_sleef; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef tdigetx_vd_tdi_advsimd_sleef(tdi_t_advsimd_sleef d) { return d.td_advsimd_sleef.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef tdigeti_vi_tdi_advsimd_sleef(tdi_t_advsimd_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdi_t_advsimd_sleef tdisettdi_tdi_vd3_vi_advsimd_sleef(vdouble3_advsimd_sleef v, vint_advsimd_sleef i) {\n  tdi_t_advsimd_sleef r = { v, i };\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visnegzero_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return veq64_vo_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visnumber_vo_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n  return vandnot_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), veq_vo_vd_vd_advsimd_sleef(x, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visnonfinite_vo_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n  return veq64_vo_vm_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(x), vcast_vm_i64_advsimd_sleef(INT64_C(0x7ff0000000000000))), vcast_vm_i64_advsimd_sleef(INT64_C(0x7ff0000000000000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vsignbit_vm_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef vsignbit_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return veq64_vo_vm_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vclearlsb_vd_vd_i_advsimd_sleef(vdouble_advsimd_sleef d, int n) {\n  return vreinterpret_vd_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vcast_vm_u64_advsimd_sleef((~UINT64_C(0)) << n)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vtoward0_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef t = vreinterpret_vd_vm_advsimd_sleef(vadd64_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(x), vcast_vm_i64_advsimd_sleef(-1)));\n  return vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(0), t);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vmulsign_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(x), vsignbit_vm_vd_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vsign_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1.0), d);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vorsign_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpret_vd_vm_advsimd_sleef(vor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(x), vsignbit_vm_vd_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vcopysign_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  return vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vandnot_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)), vreinterpret_vm_vd_advsimd_sleef(x)),\n       vand_vm_vm_vm_advsimd_sleef (vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)), vreinterpret_vm_vd_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vtruncate2_vd_vd_advsimd_sleef_advsimd_sleef(vdouble_advsimd_sleef x) {\n\n  return vtruncate_vd_vd_advsimd_sleef(x);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vfloor2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef fr = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(INT64_C(1) << 31), vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_advsimd_sleef(fr, vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(0)), vadd_vd_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(1.0)), fr);\n  return vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), vge_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(INT64_C(1) << 52))), x, vcopysign_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, fr), x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vceil2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef fr = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(INT64_C(1) << 31), vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_advsimd_sleef(fr, vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_advsimd_sleef(vle_vo_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(0)), fr, vsub_vd_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(1.0)));\n  return vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), vge_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(INT64_C(1) << 52))), x, vcopysign_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, fr), x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vround2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef x = vadd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.5));\n  vdouble_advsimd_sleef fr = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(INT64_C(1) << 31), vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_advsimd_sleef(fr, vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(fr)));\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vle_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), veq_vo_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(0))), vsub_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0)), x);\n  fr = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(0)), vadd_vd_vd_vd_advsimd_sleef(fr, vcast_vd_d_advsimd_sleef(1.0)), fr);\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.49999999999999994449)), vcast_vd_d_advsimd_sleef(0), x);\n  return vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vge_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(INT64_C(1) << 52))), d, vcopysign_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, fr), d));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vrint2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n\n  return vrint_vd_vd_advsimd_sleef(d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visint_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  return veq_vo_vd_vd_advsimd_sleef(vrint2_vd_vd_advsimd_sleef(d), d);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visodd_vo_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef x = vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.5));\n  return vneq_vo_vd_vd_advsimd_sleef(vrint2_vd_vd_advsimd_sleef(x), x);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef vilogbk_vi_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(4.9090934652977266E-91));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2.037035976334486E90), d), d);\n  vint_advsimd_sleef q = vcastu_vi_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d));\n  q = vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef((int)(((1U << 12) - 1) << 20)));\n  q = vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 20));\n  q = vsub_vi_vi_vi_advsimd_sleef(q, vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vcast_vi_i_advsimd_sleef(300 + 0x3ff), vcast_vi_i_advsimd_sleef(0x3ff)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef vilogb2k_vi_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vint_advsimd_sleef q = vcastu_vi_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d));\n  q = vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 20));\n  q = vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(0x7ff));\n  q = vsub_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(0x3ff));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vilogb2k_vm_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vmask_advsimd_sleef m = vreinterpret_vm_vd_advsimd_sleef(d);\n  m = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(m), 20 + 32));\n  m = vand_vm_vm_vm_advsimd_sleef(m, vcast_vm_i64_advsimd_sleef(0x7ff));\n  m = vsub64_vm_vm_vm_advsimd_sleef(m, vcast_vm_i64_advsimd_sleef(0x3ff));\n  return m;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vilogb3k_vm_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vmask_advsimd_sleef m = vreinterpret_vm_vd_advsimd_sleef(d);\n  m = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(m), 20 + 32));\n  m = vand_vm_vm_vm_advsimd_sleef(m, vcast_vm_i64_advsimd_sleef(0x7ff));\n  return m;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vpow2i_vd_vi_advsimd_sleef(vint_advsimd_sleef q) {\n  q = vadd_vi_vi_vi_advsimd_sleef(vcast_vi_i_advsimd_sleef(0x3ff), q);\n  vmask_advsimd_sleef r = vcastu_vm_vi_advsimd_sleef(vshl_n_s32(q, 20));\n  return vreinterpret_vd_vm_advsimd_sleef(r);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vpow2i_vd_vm_advsimd_sleef(vmask_advsimd_sleef q) {\n  q = vadd64_vm_vm_vm_advsimd_sleef(vcast_vm_i64_advsimd_sleef(0x3ff), q);\n  return vreinterpret_vd_vm_advsimd_sleef(vreinterpretq_u32_u64(vshlq_n_u64(vreinterpretq_u64_u32(q), 52)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp_vd_vd_vi_advsimd_sleef(vdouble_advsimd_sleef x, vint_advsimd_sleef q) {\n  vint_advsimd_sleef m = vshr_n_s32(q, 31);\n  m = vshl_n_s32(vsub_vi_vi_vi_advsimd_sleef(vshr_n_s32(vadd_vi_vi_vi_advsimd_sleef(m, q), 9), m), 7);\n  q = vsub_vi_vi_vi_advsimd_sleef(q, vshl_n_s32(m, 2));\n  m = vadd_vi_vi_vi_advsimd_sleef(vcast_vi_i_advsimd_sleef(0x3ff), m);\n  m = vandnot_vi_vo_vi_advsimd_sleef(vgt_vo_vi_vi_advsimd_sleef(vcast_vi_i_advsimd_sleef(0), m), m);\n  m = vsel_vi_vo_vi_vi_advsimd_sleef(vgt_vo_vi_vi_advsimd_sleef(m, vcast_vi_i_advsimd_sleef(0x7ff)), vcast_vi_i_advsimd_sleef(0x7ff), m);\n  vmask_advsimd_sleef r = vcastu_vm_vi_advsimd_sleef(vshl_n_s32(m, 20));\n  vdouble_advsimd_sleef y = vreinterpret_vd_vm_advsimd_sleef(r);\n  return vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, y), y), y), y), vpow2i_vd_vi_advsimd_sleef(q));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp2_vd_vd_vi_advsimd_sleef(vdouble_advsimd_sleef d, vint_advsimd_sleef e) {\n  return vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vi_advsimd_sleef(vshr_n_s32(e, 1))), vpow2i_vd_vi_advsimd_sleef(vsub_vi_vi_vi_advsimd_sleef(e, vshr_n_s32(e, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp3_vd_vd_vi_advsimd_sleef(vdouble_advsimd_sleef d, vint_advsimd_sleef q) {\n  return vreinterpret_vd_vm_advsimd_sleef(vadd64_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vcastu_vm_vi_advsimd_sleef(vshl_n_s32(q, 20))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp1_vd_vd_vm_advsimd_sleef(vdouble_advsimd_sleef d, vmask_advsimd_sleef e) {\n  vmask_advsimd_sleef m = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(e), 2));\n  e = vsub64_vm_vm_vm_advsimd_sleef(vsub64_vm_vm_vm_advsimd_sleef(vsub64_vm_vm_vm_advsimd_sleef(e, m), m), m);\n  d = vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vm_advsimd_sleef(m));\n  d = vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vm_advsimd_sleef(m));\n  d = vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vm_advsimd_sleef(m));\n  d = vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vm_advsimd_sleef(e));\n  return d;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp2_vd_vd_vm_advsimd_sleef(vdouble_advsimd_sleef d, vmask_advsimd_sleef e) {\n  return vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vpow2i_vd_vm_advsimd_sleef(vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(e), 1)))), vpow2i_vd_vm_advsimd_sleef(vsub64_vm_vm_vm_advsimd_sleef(e, vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(e), 1)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vldexp3_vd_vd_vm_advsimd_sleef(vdouble_advsimd_sleef d, vmask_advsimd_sleef q) {\n  return vreinterpret_vd_vm_advsimd_sleef(vadd64_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpretq_u32_u64(vshlq_n_u64(vreinterpretq_u64_u32(q), 52))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vcast_vd_vm_advsimd_sleef(vmask_advsimd_sleef m) { return vcast_vd_vi_advsimd_sleef(vcast_vi_vm_advsimd_sleef(m)); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vtruncate_vm_vd_advsimd_sleef(vdouble_advsimd_sleef d) { return vcast_vm_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(d)); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef vlt64_vo_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { return vgt64_vo_vm_vm_advsimd_sleef(y, x); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef vnot_vo64_vo64_advsimd_sleef(vopmask_advsimd_sleef x) {\n  return vxor_vo_vo_vo_advsimd_sleef(x, veq64_vo_vm_vm_advsimd_sleef(vcast_vm_i64_advsimd_sleef(0), vcast_vm_i64_advsimd_sleef(0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef vugt64_vo_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) {\n  x = vxor_vm_vm_vm_advsimd_sleef(vcast_vm_u64_advsimd_sleef(UINT64_C(0x8000000000000000)), x);\n  y = vxor_vm_vm_vm_advsimd_sleef(vcast_vm_u64_advsimd_sleef(UINT64_C(0x8000000000000000)), y);\n  return vgt64_vo_vm_vm_advsimd_sleef(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vilogbk_vm_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(4.9090934652977266E-91));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2.037035976334486E90), d), d);\n  vmask_advsimd_sleef q = vreinterpret_vm_vd_advsimd_sleef(d);\n  q = vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(q), 20 + 32));\n  q = vand_vm_vm_vm_advsimd_sleef(q, vcast_vm_i64_advsimd_sleef(0x7ff));\n  q = vsub64_vm_vm_vm_advsimd_sleef(q, vsel_vm_vo64_vm_vm_advsimd_sleef(o, vcast_vm_i64_advsimd_sleef(300 + 0x3ff), vcast_vm_i64_advsimd_sleef(0x3ff)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef sel_vq_vo_vq_vq_advsimd_sleef(vopmask_advsimd_sleef o, vquad_advsimd_sleef x, vquad_advsimd_sleef y) {\n  return vqsetxy_vq_vm_vm_advsimd_sleef(vsel_vm_vo64_vm_vm_advsimd_sleef(o, vqgetx_vm_vq_advsimd_sleef(x), vqgetx_vm_vq_advsimd_sleef(y)), vsel_vm_vo64_vm_vm_advsimd_sleef(o, vqgety_vm_vq_advsimd_sleef(x), vqgety_vm_vq_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef add128_vq_vq_vq_advsimd_sleef(vquad_advsimd_sleef x, vquad_advsimd_sleef y) {\n  vquad_advsimd_sleef r = vqsetxy_vq_vm_vm_advsimd_sleef(vadd64_vm_vm_vm_advsimd_sleef(vqgetx_vm_vq_advsimd_sleef(x), vqgetx_vm_vq_advsimd_sleef(y)), vadd64_vm_vm_vm_advsimd_sleef(vqgety_vm_vq_advsimd_sleef(x), vqgety_vm_vq_advsimd_sleef(y)));\n  r = vqsety_vq_vq_vm_advsimd_sleef(r, vadd64_vm_vm_vm_advsimd_sleef(vqgety_vm_vq_advsimd_sleef(r), vand_vm_vo64_vm_advsimd_sleef(vugt64_vo_vm_vm_advsimd_sleef(vqgetx_vm_vq_advsimd_sleef(x), vqgetx_vm_vq_advsimd_sleef(r)), vcast_vm_i64_advsimd_sleef(1))));\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_advsimd_sleef imdvq_vq_vm_vm_advsimd_sleef(vmask_advsimd_sleef x, vmask_advsimd_sleef y) { vquad_advsimd_sleef r = vqsetxy_vq_vm_vm_advsimd_sleef(x, y); return r; }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST di_t_advsimd_sleef rempisub_advsimd_sleef(vdouble_advsimd_sleef x) {\n\n  vdouble_advsimd_sleef y = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(4)));\n  vint_advsimd_sleef vi = vtruncate_vi_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(y, vmul_vd_vd_vd_advsimd_sleef(vrint_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(4))));\n  return disetdi_di_vd_vi_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0.25))), vi);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef vsel_vi_vd_vd_vi_vi_advsimd_sleef(vdouble_advsimd_sleef d0, vdouble_advsimd_sleef d1, vint_advsimd_sleef x, vint_advsimd_sleef y) { return vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d0, d1)), x, y); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_advsimd_sleef vsel_vi_vd_vi_advsimd_sleef(vdouble_advsimd_sleef d, vint_advsimd_sleef x) { return vand_vi_vo_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(d)), x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_ldexpd2_advsimd(vdouble_advsimd_sleef x, vint_advsimd_sleef q) { return vldexp_vd_vd_vi_advsimd_sleef(x, q); }\n\nSLEEF_INLINE SLEEF_CONST vint_advsimd_sleef Sleef_ilogbd2_advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef e = vcast_vd_vi_advsimd_sleef(vilogbk_vi_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d)));\n  e = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(SLEEF_FP_ILOGB0), e);\n  e = vsel_vd_vo_vd_vd_advsimd_sleef(visnan_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(SLEEF_FP_ILOGBNAN), e);\n  e = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(2147483647), e);\n  return vrint_vi_vd_advsimd_sleef(e);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_advsimd_sleef rempi_advsimd_sleef(vdouble_advsimd_sleef a) {\n  vdouble2_advsimd_sleef x, y;\n  vint_advsimd_sleef ex = vilogb2k_vi_vd_advsimd_sleef(a);\n\n  ex = vsub_vi_vi_vi_advsimd_sleef(ex, vcast_vi_i_advsimd_sleef(55));\n  vint_advsimd_sleef q = vand_vi_vo_vi_advsimd_sleef(vgt_vo_vi_vi_advsimd_sleef(ex, vcast_vi_i_advsimd_sleef(700-55)), vcast_vi_i_advsimd_sleef(-64));\n  a = vldexp3_vd_vd_vi_advsimd_sleef(a, q);\n  ex = vandnot_vi_vi_vi_advsimd_sleef(vshr_n_s32(ex, 31), ex);\n  ex = vshl_n_s32(ex, 2);\n  x = ddmul_vd2_vd_vd_advsimd_sleef(a, vgather_vd_p_vi_advsimd_sleef(Sleef_rempitabdp, ex));\n  di_t_advsimd_sleef di = rempisub_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x));\n  q = digeti_vi_di_advsimd_sleef(di);\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, digetd_vd_di_advsimd_sleef(di));\n  x = ddnormalize_vd2_vd2_advsimd_sleef(x);\n  y = ddmul_vd2_vd_vd_advsimd_sleef(a, vgather_vd_p_vi_advsimd_sleef(Sleef_rempitabdp+1, ex));\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(x, y);\n  di = rempisub_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x));\n  q = vadd_vi_vi_vi_advsimd_sleef(q, digeti_vi_di_advsimd_sleef(di));\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, digetd_vd_di_advsimd_sleef(di));\n  x = ddnormalize_vd2_vd2_advsimd_sleef(x);\n  y = vcast_vd2_vd_vd_advsimd_sleef(vgather_vd_p_vi_advsimd_sleef(Sleef_rempitabdp+2, ex), vgather_vd_p_vi_advsimd_sleef(Sleef_rempitabdp+3, ex));\n  y = ddmul_vd2_vd2_vd_advsimd_sleef(y, a);\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(x, y);\n  x = ddnormalize_vd2_vd2_advsimd_sleef(x);\n  x = ddmul_vd2_vd2_vd2_advsimd_sleef(x, vcast_vd2_d_d_advsimd_sleef(3.141592653589793116*2, 1.2246467991473532072e-16*2));\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(a), vcast_vd_d_advsimd_sleef(0.7));\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vsel_vd_vo_vd_vd_advsimd_sleef(o, a, vd2getx_vd_vd2_advsimd_sleef(x)));\n  x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n  return ddisetddi_ddi_vd2_vi_advsimd_sleef(x, q);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sind2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u, s, r = d;\n  vint_advsimd_sleef ql;\n\n  vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  d = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116), d);\n  d = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16), d);\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(r), vcast_vd_d_advsimd_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(r, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmlapn_vd_vd_vd_vd_advsimd_sleef(r, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724), dqh));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914), r);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24), u);\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    d = vsel_vd_vo_vd_vd_advsimd_sleef(g, d, u);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(r), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(r);\n      vint_advsimd_sleef ql2 = vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(3));\n      ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0))), vcast_vi_i_advsimd_sleef(2), vcast_vi_i_advsimd_sleef(1)));\n      ql2 = vshr_n_s32(ql2, 2);\n      vopmask_advsimd_sleef o = veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1));\n      vdouble2_advsimd_sleef x = vcast_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef))),\n       vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef))));\n      x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef), x);\n      ddi_advsimd_sleef = ddisetdd_ddi_ddi_vd2_advsimd_sleef(ddi_advsimd_sleef, vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(o), x, ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vd2gety_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n      d = vsel_vd_vo_vd_vd_advsimd_sleef(g, d, u);\n      d = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(r), visnan_vo_vd_advsimd_sleef(r)), vreinterpret_vm_vd_advsimd_sleef(d)));\n    }\n  }\n\n  s = vmul_vd_vd_vd_advsimd_sleef(d, d);\n\n  d = vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1))), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(d)));\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-7.97255955009037868891952e-18)), (vcast_vd_d_advsimd_sleef(2.81009972710863200091251e-15)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-7.64712219118158833288484e-13)), (vcast_vd_d_advsimd_sleef(1.60590430605664501629054e-10)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-2.50521083763502045810755e-08)), (vcast_vd_d_advsimd_sleef(2.75573192239198747630416e-06)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-0.000198412698412696162806809)), (vcast_vd_d_advsimd_sleef(0.00833333333333332974823815)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.166666666666666657414808));\n\n  u = vadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(u, d)), d);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(r), r, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sind2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u;\n  vdouble2_advsimd_sleef s, t, x;\n  vint_advsimd_sleef ql;\n\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n  vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116), d);\n  x = ddadd_vd2_vd_vd_advsimd_sleef (u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16)));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    const vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmlapn_vd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724), dqh));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914), d);\n    s = ddadd_vd2_vd_vd_advsimd_sleef (u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16)));\n    s = ddadd_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24)));\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, x, s);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      vint_advsimd_sleef ql2 = vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(3));\n      ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0))), vcast_vi_i_advsimd_sleef(2), vcast_vi_i_advsimd_sleef(1)));\n      ql2 = vshr_n_s32(ql2, 2);\n      vopmask_advsimd_sleef o = veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1));\n      vdouble2_advsimd_sleef t = vcast_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef))),\n       vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef))));\n      t = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef), t);\n      ddi_advsimd_sleef = ddisetdd_ddi_ddi_vd2_advsimd_sleef(ddi_advsimd_sleef, vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(o), t, ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      s = ddnormalize_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef));\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n      x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, x, s);\n      x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d)), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n    }\n  }\n\n  t = x;\n  s = ddsqu_vd2_vd2_advsimd_sleef(x);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2getx_vd_vd2_advsimd_sleef(s)), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.72052416138529567917983e-15)), (vcast_vd_d_advsimd_sleef(-7.6429259411395447190023e-13)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(1.60589370117277896211623e-10)), (vcast_vd_d_advsimd_sleef(-2.5052106814843123359368e-08)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.75573192104428224777379e-06)), (vcast_vd_d_advsimd_sleef(-0.000198412698412046454654947)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(0.00833333333333318056201922));\n\n  x = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.166666666666666657414808), vmul_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s))), s));\n  u = ddmul_vd_vd2_vd2_advsimd_sleef(t, x);\n\n  u = vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1))),\n             vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_cosd2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u, s, r = d;\n  vint_advsimd_sleef ql;\n\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n  vdouble_advsimd_sleef dql = vmla_vd_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2),\n     vrint_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724), vcast_vd_d_advsimd_sleef(-0.5))),\n     vcast_vd_d_advsimd_sleef(1));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  d = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), d);\n  d = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), d);\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(r, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724 / (1 << 23)), vcast_vd_d_advsimd_sleef(-0.318309886183790671537767526745028724 / (1 << 24))));\n    vint_advsimd_sleef ql2 = vrint_vi_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(r, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724)),\n      vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-(1 << 23)), vcast_vd_d_advsimd_sleef(-0.5))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vcast_vi_i_advsimd_sleef(1));\n    vdouble_advsimd_sleef dql = vcast_vd_vi_advsimd_sleef(ql2);\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), r);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n    d = vsel_vd_vo_vd_vd_advsimd_sleef(g, d, u);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(r), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(r);\n      vint_advsimd_sleef ql2 = vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(3));\n      ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0))), vcast_vi_i_advsimd_sleef(8), vcast_vi_i_advsimd_sleef(7)));\n      ql2 = vshr_n_s32(ql2, 1);\n      vopmask_advsimd_sleef o = veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(0));\n      vdouble_advsimd_sleef y = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(0), vcast_vd_d_advsimd_sleef(-1));\n      vdouble2_advsimd_sleef x = vcast_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), y),\n       vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), y));\n      x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef), x);\n      ddi_advsimd_sleef = ddisetdd_ddi_ddi_vd2_advsimd_sleef(ddi_advsimd_sleef, vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(o), x, ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vd2gety_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n      d = vsel_vd_vo_vd_vd_advsimd_sleef(g, d, u);\n      d = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(r), visnan_vo_vd_advsimd_sleef(r)), vreinterpret_vm_vd_advsimd_sleef(d)));\n    }\n  }\n\n  s = vmul_vd_vd_vd_advsimd_sleef(d, d);\n\n  d = vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(0))), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(d)));\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-7.97255955009037868891952e-18)), (vcast_vd_d_advsimd_sleef(2.81009972710863200091251e-15)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-7.64712219118158833288484e-13)), (vcast_vd_d_advsimd_sleef(1.60590430605664501629054e-10)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-2.50521083763502045810755e-08)), (vcast_vd_d_advsimd_sleef(2.75573192239198747630416e-06)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(-0.000198412698412696162806809)), (vcast_vd_d_advsimd_sleef(0.00833333333333332974823815)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.166666666666666657414808));\n\n  u = vadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(u, d)), d);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_cosd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u;\n  vdouble2_advsimd_sleef s, t, x;\n  vint_advsimd_sleef ql;\n\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n  vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724), vcast_vd_d_advsimd_sleef(-0.5)));\n  dql = vmla_vd_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2), dql, vcast_vd_d_advsimd_sleef(1));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  x = ddadd2_vd2_vd_vd_advsimd_sleef(d, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116*0.5)));\n  x = ddadd_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16*0.5)));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724 / (1 << 23)), vcast_vd_d_advsimd_sleef(-0.318309886183790671537767526745028724 / (1 << 24))));\n    vint_advsimd_sleef ql2 = vrint_vi_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.318309886183790671537767526745028724)),\n      vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-(1 << 23)), vcast_vd_d_advsimd_sleef(-0.5))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vcast_vi_i_advsimd_sleef(1));\n    const vdouble_advsimd_sleef dql = vcast_vd_vi_advsimd_sleef(ql2);\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), d);\n    s = ddadd2_vd2_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914*0.5)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5)));\n    s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5)));\n    s = ddadd_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n    x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, x, s);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      vint_advsimd_sleef ql2 = vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(3));\n      ql2 = vadd_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql2, ql2), vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0))), vcast_vi_i_advsimd_sleef(8), vcast_vi_i_advsimd_sleef(7)));\n      ql2 = vshr_n_s32(ql2, 1);\n      vopmask_advsimd_sleef o = veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef), vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(0));\n      vdouble_advsimd_sleef y = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(0), vcast_vd_d_advsimd_sleef(-1));\n      vdouble2_advsimd_sleef t = vcast_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), y),\n       vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), y));\n      t = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef), t);\n      ddi_advsimd_sleef = ddisetdd_ddi_ddi_vd2_advsimd_sleef(ddi_advsimd_sleef, vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(o), t, ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      s = ddnormalize_vd2_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef));\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n      x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, x, s);\n      x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d)), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n    }\n  }\n\n  t = x;\n  s = ddsqu_vd2_vd2_advsimd_sleef(x);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2getx_vd_vd2_advsimd_sleef(s)), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.72052416138529567917983e-15)), (vcast_vd_d_advsimd_sleef(-7.6429259411395447190023e-13)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(1.60589370117277896211623e-10)), (vcast_vd_d_advsimd_sleef(-2.5052106814843123359368e-08)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.75573192104428224777379e-06)), (vcast_vd_d_advsimd_sleef(-0.000198412698412046454654947)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(0.00833333333333318056201922));\n\n  x = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.166666666666666657414808), vmul_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s))), s));\n  u = ddmul_vd_vd2_vd2_advsimd_sleef(t, x);\n\n  u = vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(0))), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE vdouble2_advsimd_sleef Sleef_sincosd2_u35advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, t, rx, ry, s = d;\n  vdouble2_advsimd_sleef r;\n  vint_advsimd_sleef ql;\n\n  vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(s, vcast_vd_d_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), s);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), s);\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), d);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    s = vsel_vd_vo_vd_vd_advsimd_sleef(g, s, u);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vd2gety_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      u = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef));\n      s = vsel_vd_vo_vd_vd_advsimd_sleef(g, s, u);\n    }\n  }\n\n  t = s;\n\n  s = vmul_vd_vd_vd_advsimd_sleef(s, s);\n\n  u = vcast_vd_d_advsimd_sleef(1.58938307283228937328511e-10);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-2.50506943502539773349318e-08));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(2.75573131776846360512547e-06));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.000198412698278911770864914));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(0.0083333333333191845961746));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.166666666666666130709393));\n\n  rx = vmla_vd_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(u, s), t, t);\n  rx = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-0.0), rx);\n\n  u = vcast_vd_d_advsimd_sleef(-1.13615350239097429531523e-11);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(2.08757471207040055479366e-09));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-2.75573144028847567498567e-07));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(2.48015872890001867311915e-05));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.00138888888888714019282329));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(0.0416666666666665519592062));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.5));\n\n  ry = vmla_vd_vd_vd_vd_advsimd_sleef(s, u, vcast_vd_d_advsimd_sleef(1));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(o, rx, ry), vsel_vd_vo_vd_vd_advsimd_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2)));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2)));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_advsimd_sleef Sleef_sincosd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, rx, ry;\n  vdouble2_advsimd_sleef r, s, t, x;\n  vint_advsimd_sleef ql;\n\n  const vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116*0.5), d);\n  s = ddadd_vd2_vd_vd_advsimd_sleef (u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16*0.5)));\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    const vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), d);\n    x = ddadd_vd2_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    s = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, s, x);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      x = ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef);\n      o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d));\n      x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n      x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef));\n      s = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, s, x);\n    }\n  }\n\n  t = s;\n\n  s = vd2setx_vd2_vd2_vd_advsimd_sleef(s, ddsqu_vd_vd2_advsimd_sleef(s));\n\n  u = vcast_vd_d_advsimd_sleef(1.58938307283228937328511e-10);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-2.50506943502539773349318e-08));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(2.75573131776846360512547e-06));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-0.000198412698278911770864914));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(0.0083333333333191845961746));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-0.166666666666666130709393));\n\n  u = vmul_vd_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2getx_vd_vd2_advsimd_sleef(t)));\n\n  x = ddadd_vd2_vd2_vd_advsimd_sleef(t, u);\n  rx = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  rx = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-0.0), rx);\n\n  u = vcast_vd_d_advsimd_sleef(-1.13615350239097429531523e-11);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(2.08757471207040055479366e-09));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-2.75573144028847567498567e-07));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(2.48015872890001867311915e-05));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-0.00138888888888714019282329));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(0.0416666666666665519592062));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(-0.5));\n\n  x = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), ddmul_vd2_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), u));\n  ry = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(o, rx, ry), vsel_vd_vo_vd_vd_advsimd_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2)));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2)));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_advsimd_sleef Sleef_sincospid2_u05advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, s, t, rx, ry;\n  vdouble2_advsimd_sleef r, x, s2;\n\n  u = vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(4.0));\n  vint_advsimd_sleef q = vtruncate_vi_vd_advsimd_sleef(u);\n  q = vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vxor_vi_vi_vi_advsimd_sleef(vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 31)), vcast_vi_i_advsimd_sleef(1))), vcast_vi_i_advsimd_sleef(~1));\n  s = vsub_vd_vd_vd_advsimd_sleef(u, vcast_vd_vi_advsimd_sleef(q));\n\n  t = s;\n  s = vmul_vd_vd_vd_advsimd_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_advsimd_sleef(t, t);\n\n  u = vcast_vd_d_advsimd_sleef(-2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(6.94821830580179461327784e-12));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(3.13361688966868392878422e-07));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-3.6576204182161551920361e-05));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(0.00249039457019271850274356));\n  x = ddadd2_vd2_vd_vd2_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(u, s), vcast_vd2_d_d_advsimd_sleef(-0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s2, x), vcast_vd2_d_d_advsimd_sleef(0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd_advsimd_sleef(x, t);\n  rx = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  rx = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-0.0), rx);\n\n  u = vcast_vd_d_advsimd_sleef(9.94480387626843774090208e-16);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-3.89796226062932799164047e-13));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1.15011582539996035266901e-10));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-2.4611369501044697495359e-08));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(3.59086044859052754005062e-06));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.000325991886927389905997954));\n  x = ddadd2_vd2_vd_vd2_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(u, s), vcast_vd2_d_d_advsimd_sleef(0.0158543442438155018914259, -1.04693272280631521908845e-18));\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s2, x), vcast_vd2_d_d_advsimd_sleef(-0.308425137534042437259529, -1.95698492133633550338345e-17));\n\n  x = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(x, s2), vcast_vd_d_advsimd_sleef(1));\n  ry = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(o, rx, ry), vsel_vd_vo_vd_vd_advsimd_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  o = vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+9/4));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(1), vd2gety_vd_vd2_advsimd_sleef(r)));\n\n  o = visinf_vo_vd_advsimd_sleef(d);\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_advsimd_sleef Sleef_sincospid2_u35advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, s, t, rx, ry;\n  vdouble2_advsimd_sleef r;\n\n  u = vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(4.0));\n  vint_advsimd_sleef q = vtruncate_vi_vd_advsimd_sleef(u);\n  q = vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vxor_vi_vi_vi_advsimd_sleef(vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 31)), vcast_vi_i_advsimd_sleef(1))), vcast_vi_i_advsimd_sleef(~1));\n  s = vsub_vd_vd_vd_advsimd_sleef(u, vcast_vd_vi_advsimd_sleef(q));\n\n  t = s;\n  s = vmul_vd_vd_vd_advsimd_sleef(s, s);\n\n  u = vcast_vd_d_advsimd_sleef(+0.6880638894766060136e-11);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.1757159564542310199e-8));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.3133616327257867311e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.3657620416388486452e-4));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.2490394570189932103e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.8074551218828056320e-1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.7853981633974482790e+0));\n\n  rx = vmul_vd_vd_vd_advsimd_sleef(u, t);\n\n  u = vcast_vd_d_advsimd_sleef(-0.3860141213683794352e-12);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1150057888029681415e-9));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.2461136493006663553e-7));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.3590860446623516713e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.3259918869269435942e-3));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1585434424381541169e-1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(-0.3084251375340424373e+0));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1));\n\n  ry = u;\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(o, rx, ry), vsel_vd_vo_vd_vd_advsimd_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  o = vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+9/4));\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  o = visinf_vo_vd_advsimd_sleef(d);\n  r = vd2setx_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_advsimd_sleef(r, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble2_advsimd_sleef Sleef_modfd2_advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef fr = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(INT64_C(1) << 31), vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_advsimd_sleef(fr, vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(INT64_C(1) << 52)), vcast_vd_d_advsimd_sleef(0), fr);\n\n  vdouble2_advsimd_sleef ret;\n\n  ret = vd2setxy_vd2_vd_vd_advsimd_sleef(vcopysign_vd_vd_vd_advsimd_sleef(fr, x), vcopysign_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(x, fr), x));\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef sinpik_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, s, t;\n  vdouble2_advsimd_sleef x, s2;\n\n  u = vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(4.0));\n  vint_advsimd_sleef q = vtruncate_vi_vd_advsimd_sleef(u);\n  q = vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vxor_vi_vi_vi_advsimd_sleef(vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 31)), vcast_vi_i_advsimd_sleef(1))), vcast_vi_i_advsimd_sleef(~1));\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2)));\n\n  s = vsub_vd_vd_vd_advsimd_sleef(u, vcast_vd_vi_advsimd_sleef(q));\n  t = s;\n  s = vmul_vd_vd_vd_advsimd_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_advsimd_sleef(t, t);\n\n  u = vsel_vd_vo_d_d_advsimd_sleef(o, 9.94480387626843774090208e-16, -2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -3.89796226062932799164047e-13, 6.948218305801794613277840e-12));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, 1.150115825399960352669010e-10, -1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -2.46113695010446974953590e-08, 3.133616889668683928784220e-07));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, 3.590860448590527540050620e-06, -3.65762041821615519203610e-05));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -0.000325991886927389905997954, 0.0024903945701927185027435600));\n  x = ddadd2_vd2_vd_vd2_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(u, s),\n   vsel_vd2_vo_d_d_d_d_advsimd_sleef(o, 0.0158543442438155018914259, -1.04693272280631521908845e-18,\n         -0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s2, x),\n    vsel_vd2_vo_d_d_d_d_advsimd_sleef(o, -0.308425137534042437259529, -1.95698492133633550338345e-17,\n          0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd2_advsimd_sleef(x, vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, s2, vcast_vd2_vd_vd_advsimd_sleef(t, vcast_vd_d_advsimd_sleef(0))));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1)), x);\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sinpid2_u05advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x = sinpik_advsimd_sleef(d);\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-0.0), r);\n  r = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+9/4)), vreinterpret_vm_vd_advsimd_sleef(r)));\n  r = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(r)));\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef cospik_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vdouble_advsimd_sleef u, s, t;\n  vdouble2_advsimd_sleef x, s2;\n\n  u = vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(4.0));\n  vint_advsimd_sleef q = vtruncate_vi_vd_advsimd_sleef(u);\n  q = vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vxor_vi_vi_vi_advsimd_sleef(vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(q), 31)), vcast_vi_i_advsimd_sleef(1))), vcast_vi_i_advsimd_sleef(~1));\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(0)));\n\n  s = vsub_vd_vd_vd_advsimd_sleef(u, vcast_vd_vi_advsimd_sleef(q));\n  t = s;\n  s = vmul_vd_vd_vd_advsimd_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_advsimd_sleef(t, t);\n\n  u = vsel_vd_vo_d_d_advsimd_sleef(o, 9.94480387626843774090208e-16, -2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -3.89796226062932799164047e-13, 6.948218305801794613277840e-12));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, 1.150115825399960352669010e-10, -1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -2.46113695010446974953590e-08, 3.133616889668683928784220e-07));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, 3.590860448590527540050620e-06, -3.65762041821615519203610e-05));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vsel_vd_vo_d_d_advsimd_sleef(o, -0.000325991886927389905997954, 0.0024903945701927185027435600));\n  x = ddadd2_vd2_vd_vd2_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(u, s),\n   vsel_vd2_vo_d_d_d_d_advsimd_sleef(o, 0.0158543442438155018914259, -1.04693272280631521908845e-18,\n         -0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s2, x),\n    vsel_vd2_vo_d_d_d_d_advsimd_sleef(o, -0.308425137534042437259529, -1.95698492133633550338345e-17,\n          0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd2_advsimd_sleef(x, vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, s2, vcast_vd2_vd_vd_advsimd_sleef(t, vcast_vd_d_advsimd_sleef(0))));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1)), x);\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(4)), vcast_vi_i_advsimd_sleef(4)));\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_cospid2_u05advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x = cospik_advsimd_sleef(d);\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+9/4)), vcast_vd_d_advsimd_sleef(1), r);\n  r = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(r)));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_tand2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u, s, x, y;\n  vopmask_advsimd_sleef o;\n  vint_advsimd_sleef ql;\n\n  vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116 * 0.5), d);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16 * 0.5), s);\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), d);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    s = vsel_vd_vo_vd_vd_advsimd_sleef(g, s, u);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+6));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      vint_advsimd_sleef ql2 = ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef);\n      u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)), vd2gety_vd_vd2_advsimd_sleef(ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef)));\n      u = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ql2);\n      s = vsel_vd_vo_vd_vd_advsimd_sleef(g, s, u);\n    }\n  }\n\n  x = vmul_vd_vd_vd_advsimd_sleef(s, vcast_vd_d_advsimd_sleef(0.5));\n  s = vmul_vd_vd_vd_advsimd_sleef(x, x);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.3245098826639276316e-3)), (vcast_vd_d_advsimd_sleef(+0.5619219738114323735e-3)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1460781502402784494e-2)), (vcast_vd_d_advsimd_sleef(+0.3591611540792499519e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.8863268409563113126e-2)), (vcast_vd_d_advsimd_sleef(+0.2186948728185535498e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.5396825399517272970e-1)), (vcast_vd_d_advsimd_sleef(+0.1333333333330500581e+0)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.3333333333333343695e+0));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(u, x), x);\n\n  y = vmla_vd_vd_vd_vd_advsimd_sleef(u, u, vcast_vd_d_advsimd_sleef(-1));\n  x = vmul_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-2));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1)));\n  u = vdiv_vd_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(o, vneg_vd_vd_advsimd_sleef(y), x),\n      vsel_vd_vo_vd_vd_advsimd_sleef(o, x, y));\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_tand2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u;\n  vdouble2_advsimd_sleef s, t, x, y;\n  vopmask_advsimd_sleef o;\n  vint_advsimd_sleef ql;\n\n  const vdouble_advsimd_sleef dql = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_advsimd_sleef(dql);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.141592653589793116*0.5), d);\n  s = ddadd_vd2_vd_vd_advsimd_sleef (u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467991473532072e-16*0.5)));\n  vopmask_advsimd_sleef g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n    vdouble_advsimd_sleef dqh = vtruncate_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(1 << 24));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.63661977236758138243, -3.9357353350364971764e-17), d),\n     vsub_vd_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)),\n        vcast_vd_d_advsimd_sleef(-0.5), vcast_vd_d_advsimd_sleef(0.5)), dqh));\n    const vdouble_advsimd_sleef dql = vtruncate_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x)));\n\n    u = vmla_vd_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1415926218032836914 * 0.5), d);\n    x = ddadd_vd2_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1415926218032836914*0.5 )));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-3.1786509424591713469e-08*0.5 )));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dqh, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd2_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(dql, vcast_vd_d_advsimd_sleef(-1.2246467864107188502e-16*0.5 )));\n    x = ddadd_vd2_vd2_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(dqh, dql), vcast_vd_d_advsimd_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, vrint_vi_vd_advsimd_sleef(dql));\n    s = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, s, x);\n    g = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(g)), 1)) {\n      ddi_t_advsimd_sleef ddi_advsimd_sleef = rempi_advsimd_sleef(d);\n      x = ddigetdd_vd2_ddi_advsimd_sleef(ddi_advsimd_sleef);\n      o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), visnan_vo_vd_advsimd_sleef(d));\n      x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n      x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(o, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n\n      ql = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(g), ql, ddigeti_vi_ddi_advsimd_sleef(ddi_advsimd_sleef));\n      s = vsel_vd2_vo_vd2_vd2_advsimd_sleef(g, s, x);\n    }\n  }\n\n  t = ddscale_vd2_vd2_vd_advsimd_sleef(s, vcast_vd_d_advsimd_sleef(0.5));\n  s = ddsqu_vd2_vd2_advsimd_sleef(t);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2getx_vd_vd2_advsimd_sleef(s)), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.3245098826639276316e-3)), (vcast_vd_d_advsimd_sleef(+0.5619219738114323735e-3)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.1460781502402784494e-2)), (vcast_vd_d_advsimd_sleef(+0.3591611540792499519e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.8863268409563113126e-2)), (vcast_vd_d_advsimd_sleef(+0.2186948728185535498e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.5396825399517272970e-1)), (vcast_vd_d_advsimd_sleef(+0.1333333333330500581e+0)))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(+0.3333333333333343695e+0));\n  x = ddadd_vd2_vd2_vd2_advsimd_sleef(t, ddmul_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s, t), u));\n\n  y = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), ddsqu_vd2_vd2_advsimd_sleef(x));\n  x = ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(-2));\n\n  o = vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(ql, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1)));\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddneg_vd2_vd2_advsimd_sleef(y), x),\n   vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, x, y));\n\n  u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x));\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), d, u);\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef atan2k_advsimd_sleef(vdouble_advsimd_sleef y, vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef s, t, u;\n  vint_advsimd_sleef q;\n  vopmask_advsimd_sleef p;\n\n  q = vsel_vi_vd_vi_advsimd_sleef(x, vcast_vi_i_advsimd_sleef(-2));\n  x = vabs_vd_vd_advsimd_sleef(x);\n\n  q = vsel_vi_vd_vd_vi_vi_advsimd_sleef(x, y, vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(1)), q);\n  p = vlt_vo_vd_vd_advsimd_sleef(x, y);\n  s = vsel_vd_vo_vd_vd_advsimd_sleef(p, vneg_vd_vd_advsimd_sleef(x), y);\n  t = vmax_vd_vd_vd_advsimd_sleef(x, y);\n\n  s = vdiv_vd_vd_vd_advsimd_sleef(s, t);\n  t = vmul_vd_vd_vd_advsimd_sleef(s, s);\n\n  vdouble_advsimd_sleef t2 = vmul_vd_vd_vd_advsimd_sleef(t, t), t4 = vmul_vd_vd_vd_advsimd_sleef(t2, t2), t8 = vmul_vd_vd_vd_advsimd_sleef(t4, t4), t16 = vmul_vd_vd_vd_advsimd_sleef(t8, t8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((t16), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vcast_vd_d_advsimd_sleef(-1.88796008463073496563746e-05)), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.000209850076645816976906797)), (vcast_vd_d_advsimd_sleef(-0.00110611831486672482563471)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t8), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.00370026744188713119232403)), (vcast_vd_d_advsimd_sleef(-0.00889896195887655491740809)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.016599329773529201970117)), (vcast_vd_d_advsimd_sleef(-0.0254517624932312641616861)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0337852580001353069993897)), (vcast_vd_d_advsimd_sleef(-0.0407629191276836500001934)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0466667150077840625632675)), (vcast_vd_d_advsimd_sleef(-0.0523674852303482457616113)))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0587666392926673580854313)), (vcast_vd_d_advsimd_sleef(-0.0666573579361080525984562)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0769219538311769618355029)), (vcast_vd_d_advsimd_sleef(-0.090908995008245008229153)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.111111105648261418443745)), (vcast_vd_d_advsimd_sleef(-0.14285714266771329383765)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.199999999996591265594148)), (vcast_vd_d_advsimd_sleef(-0.333333333333311110369124)))))))))));\n\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(t, u), s);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(vcast_vd_vi_advsimd_sleef(q), vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef atan2k_u1_advsimd_sleef(vdouble2_advsimd_sleef y, vdouble2_advsimd_sleef x) {\n  vdouble_advsimd_sleef u;\n  vdouble2_advsimd_sleef s, t;\n  vint_advsimd_sleef q;\n  vopmask_advsimd_sleef p;\n\n  q = vsel_vi_vd_vi_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vcast_vi_i_advsimd_sleef(-2));\n  p = vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(0));\n  vmask_advsimd_sleef b = vand_vm_vo64_vm_advsimd_sleef(p, vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0)));\n  x = vd2setx_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(b, vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_advsimd_sleef(x, vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(b, vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(x)))));\n\n  q = vsel_vi_vd_vd_vi_vi_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y), vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(1)), q);\n  p = vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(y));\n  s = vsel_vd2_vo_vd2_vd2_advsimd_sleef(p, ddneg_vd2_vd2_advsimd_sleef(x), y);\n  t = vsel_vd2_vo_vd2_vd2_advsimd_sleef(p, y, x);\n\n  s = dddiv_vd2_vd2_vd2_advsimd_sleef(s, t);\n  t = ddsqu_vd2_vd2_advsimd_sleef(s);\n  t = ddnormalize_vd2_vd2_advsimd_sleef(t);\n\n  vdouble_advsimd_sleef t2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), vd2getx_vd_vd2_advsimd_sleef(t)), t4 = vmul_vd_vd_vd_advsimd_sleef(t2, t2), t8 = vmul_vd_vd_vd_advsimd_sleef(t4, t4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((t8), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(1.06298484191448746607415e-05)), (vcast_vd_d_advsimd_sleef(-0.000125620649967286867384336)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.00070557664296393412389774)), (vcast_vd_d_advsimd_sleef(-0.00251865614498713360352999)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.00646262899036991172313504)), (vcast_vd_d_advsimd_sleef(-0.0128281333663399031014274)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.0208024799924145797902497)), (vcast_vd_d_advsimd_sleef(-0.0289002344784740315686289)))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.0359785005035104590853656)), (vcast_vd_d_advsimd_sleef(-0.041848579703592507506027)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.0470843011653283988193763)), (vcast_vd_d_advsimd_sleef(-0.0524914210588448421068719)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.0587946590969581003860434)), (vcast_vd_d_advsimd_sleef(-0.0666620884778795497194182)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(t)), (vcast_vd_d_advsimd_sleef(0.0769225330296203768654095)), (vcast_vd_d_advsimd_sleef(-0.0909090442773387574781907)))))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(t), vcast_vd_d_advsimd_sleef(0.111111108376896236538123));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(t), vcast_vd_d_advsimd_sleef(-0.142857142756268568062339));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(t), vcast_vd_d_advsimd_sleef(0.199999999997977351284817));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(t), vcast_vd_d_advsimd_sleef(-0.333333333333317605173818));\n\n  t = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddmul_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(s, t), u));\n\n  t = ddadd_vd2_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(1.570796326794896557998982, 6.12323399573676603586882e-17), vcast_vd_vi_advsimd_sleef(q)), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef visinf2_vd_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d, vdouble_advsimd_sleef m) {\n  return vreinterpret_vd_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vor_vm_vm_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(d), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(m))));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_atan2d2_u35advsimd(vdouble_advsimd_sleef y, vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef r = atan2k_advsimd_sleef(vabs_vd_vd_advsimd_sleef(y), x);\n\n  r = vmulsign_vd_vd_vd_advsimd_sleef(r, x);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0))), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_advsimd_sleef(x, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(y), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_advsimd_sleef(x, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0.0)), vreinterpret_vd_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vreinterpret_vm_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_atan2d2_u10advsimd(vdouble_advsimd_sleef y, vdouble_advsimd_sleef x) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(5.5626846462680083984e-309));\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 53)), x);\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 53)), y);\n\n  vdouble2_advsimd_sleef d = atan2k_u1_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(y), vcast_vd_d_advsimd_sleef(0)), vcast_vd2_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)));\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d));\n\n  r = vmulsign_vd_vd_vd_advsimd_sleef(r, x);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0))), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_advsimd_sleef(x, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(y), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_advsimd_sleef(x, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0.0)), vreinterpret_vd_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vreinterpret_vm_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_asind2_u35advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0.5));\n  vdouble_advsimd_sleef x2 = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, d), vmul_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vabs_vd_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5)));\n  vdouble_advsimd_sleef x = vsel_vd_vo_vd_vd_advsimd_sleef(o, vabs_vd_vd_advsimd_sleef(d), vsqrt_vd_vd_advsimd_sleef(x2)), u;\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_advsimd_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_advsimd_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_advsimd_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_advsimd_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_advsimd_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_advsimd_sleef(+0.1666666666666497543e+0)))))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(x, x2), x);\n\n  vdouble_advsimd_sleef r = vsel_vd_vo_vd_vd_advsimd_sleef(o, u, vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-2), vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2)));\n  return vmulsign_vd_vd_vd_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_asind2_u10advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0.5));\n  vdouble_advsimd_sleef x2 = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, d), vmul_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vabs_vd_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5))), u;\n  vdouble2_advsimd_sleef x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, vcast_vd2_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0)), ddsqrt_vd2_vd_advsimd_sleef(x2));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1.0)), vcast_vd2_d_d_advsimd_sleef(0, 0), x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_advsimd_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_advsimd_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_advsimd_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_advsimd_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_advsimd_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_advsimd_sleef(+0.1666666666666497543e+0)))))))));\n\n  u = vmul_vd_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)));\n\n  vdouble2_advsimd_sleef y = ddsub_vd2_vd2_vd_advsimd_sleef(ddsub_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(3.141592653589793116/4, 1.2246467991473532072e-16/4), x), u);\n\n  vdouble_advsimd_sleef r = vsel_vd_vo_vd_vd_advsimd_sleef(o, vadd_vd_vd_vd_advsimd_sleef(u, vd2getx_vd_vd2_advsimd_sleef(x)),\n          vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(2)));\n  return vmulsign_vd_vd_vd_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_acosd2_u35advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0.5));\n  vdouble_advsimd_sleef x2 = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, d),\n    vmul_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vabs_vd_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5))), u;\n  vdouble_advsimd_sleef x = vsel_vd_vo_vd_vd_advsimd_sleef(o, vabs_vd_vd_advsimd_sleef(d), vsqrt_vd_vd_advsimd_sleef(x2));\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1.0)), vcast_vd_d_advsimd_sleef(0), x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_advsimd_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_advsimd_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_advsimd_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_advsimd_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_advsimd_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_advsimd_sleef(+0.1666666666666497543e+0)))))))));\n\n  u = vmul_vd_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(x2, x));\n\n  vdouble_advsimd_sleef y = vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), vadd_vd_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(x, d), vmulsign_vd_vd_vd_advsimd_sleef(u, d)));\n  x = vadd_vd_vd_vd_advsimd_sleef(x, u);\n  vdouble_advsimd_sleef r = vsel_vd_vo_vd_vd_advsimd_sleef(o, y, vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n  return vsel_vd_vo_vd_vd_advsimd_sleef(vandnot_vo_vo_vo_advsimd_sleef(o, vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0))),\n     vd2getx_vd_vd2_advsimd_sleef(ddadd_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(3.141592653589793116, 1.2246467991473532072e-16),\n         vneg_vd_vd_advsimd_sleef(r))), r);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_acosd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0.5));\n  vdouble_advsimd_sleef x2 = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, d), vmul_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vabs_vd_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5))), u;\n  vdouble2_advsimd_sleef x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, vcast_vd2_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0)), ddsqrt_vd2_vd_advsimd_sleef(x2));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1.0)), vcast_vd2_d_d_advsimd_sleef(0, 0), x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_advsimd_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_advsimd_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_advsimd_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_advsimd_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_advsimd_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_advsimd_sleef(+0.1666666666666497543e+0)))))))));\n\n  u = vmul_vd_vd_vd_advsimd_sleef(u, vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)));\n\n  vdouble2_advsimd_sleef y = ddsub_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(3.141592653589793116/2, 1.2246467991473532072e-16/2),\n     ddadd_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), d), vmulsign_vd_vd_vd_advsimd_sleef(u, d)));\n  x = ddadd_vd2_vd2_vd_advsimd_sleef(x, u);\n\n  y = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, y, ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n\n  y = vsel_vd2_vo_vd2_vd2_advsimd_sleef(vandnot_vo_vo_vo_advsimd_sleef(o, vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0))),\n     ddsub_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(3.141592653589793116, 1.2246467991473532072e-16), y), y);\n\n  return vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(y));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_atand2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef d2 = atan2k_u1_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(0)), vcast_vd2_d_d_advsimd_sleef(1, 0));\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d2), vd2gety_vd_vd2_advsimd_sleef(d2));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1.570796326794896557998982), r);\n  return vmulsign_vd_vd_vd_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_atand2_u35advsimd(vdouble_advsimd_sleef s) {\n  vdouble_advsimd_sleef t, u;\n  vint_advsimd_sleef q;\n\n  q = vsel_vi_vd_vi_advsimd_sleef(s, vcast_vi_i_advsimd_sleef(2));\n  s = vabs_vd_vd_advsimd_sleef(s);\n\n  q = vsel_vi_vd_vd_vi_vi_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), s, vadd_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(1)), q);\n  s = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), s), vrec_vd_vd_advsimd_sleef(s), s);\n\n  t = vmul_vd_vd_vd_advsimd_sleef(s, s);\n\n  vdouble_advsimd_sleef t2 = vmul_vd_vd_vd_advsimd_sleef(t, t), t4 = vmul_vd_vd_vd_advsimd_sleef(t2, t2), t8 = vmul_vd_vd_vd_advsimd_sleef(t4, t4), t16 = vmul_vd_vd_vd_advsimd_sleef(t8, t8);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((t16), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vcast_vd_d_advsimd_sleef(-1.88796008463073496563746e-05)), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.000209850076645816976906797)), (vcast_vd_d_advsimd_sleef(-0.00110611831486672482563471)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t8), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.00370026744188713119232403)), (vcast_vd_d_advsimd_sleef(-0.00889896195887655491740809)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.016599329773529201970117)), (vcast_vd_d_advsimd_sleef(-0.0254517624932312641616861)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0337852580001353069993897)), (vcast_vd_d_advsimd_sleef(-0.0407629191276836500001934)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0466667150077840625632675)), (vcast_vd_d_advsimd_sleef(-0.0523674852303482457616113)))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t4), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0587666392926673580854313)), (vcast_vd_d_advsimd_sleef(-0.0666573579361080525984562)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.0769219538311769618355029)), (vcast_vd_d_advsimd_sleef(-0.090908995008245008229153)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((t2), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.111111105648261418443745)), (vcast_vd_d_advsimd_sleef(-0.14285714266771329383765)))), (vmla_vd_vd_vd_vd_advsimd_sleef((t), (vcast_vd_d_advsimd_sleef(0.199999999996591265594148)), (vcast_vd_d_advsimd_sleef(-0.333333333333311110369124)))))))))));\n\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(t, u), s);\n\n  t = vsel_vd_vo_vd_vd_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(1)), vcast_vi_i_advsimd_sleef(1))), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3.141592653589793238462643383279502884/2), t), t);\n  t = vreinterpret_vd_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo64_vm_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(2)), vcast_vi_i_advsimd_sleef(2))), vreinterpret_vm_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-0.0))), vreinterpret_vm_vd_advsimd_sleef(t)));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_logd2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef x, x2;\n  vdouble_advsimd_sleef t, m;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = vdiv_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(1)), vadd_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), m));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(x, x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x3 = vmul_vd_vd_vd_advsimd_sleef(x, x2);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(0.153487338491425068243146)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.152519917006351951593857)), (vcast_vd_d_advsimd_sleef(0.181863266251982985677316)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.222221366518767365905163)), (vcast_vd_d_advsimd_sleef(0.285714294746548025383248)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.399999999950799600689777)), (vcast_vd_d_advsimd_sleef(0.6666666666667778740063)))))));\n\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2), vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.693147180559945286226764), vcast_vd_vi_advsimd_sleef(e)));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x3, t, x);\n\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vispinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(__builtin_inf()), x);\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), x);\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), x);\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_expd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931))), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-.69314718055966295651160180568695068359375), d);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-.28235290563031577122588448175013436025525412068e-12), s);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.2081276378237164457e-8)), (vcast_vd_d_advsimd_sleef(+0.2511210703042288022e-7)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.2755762628169491192e-6)), (vcast_vd_d_advsimd_sleef(+0.2755723402025388239e-5)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.2480158687479686264e-4)), (vcast_vd_d_advsimd_sleef(+0.1984126989855865850e-3)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1388888888914497797e-2)), (vcast_vd_d_advsimd_sleef(+0.8333333333314938210e-2)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.4166666666666602598e-1)), (vcast_vd_d_advsimd_sleef(+0.1666666666666669072e+0)))))))));\n\n  u = vfma_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.5000000000000000000e+0));\n  u = vfma_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1000000000000000000e+1));\n  u = vfma_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1000000000000000000e+1));\n\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  vopmask_advsimd_sleef o = vgt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(7.09782712893383973e+02));\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-1000)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef expm1k_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931))), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-.69314718055966295651160180568695068359375), d);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-.28235290563031577122588448175013436025525412068e-12), s);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(2.08860621107283687536341e-09)), (vcast_vd_d_advsimd_sleef(2.51112930892876518610661e-08)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(2.75573911234900471893338e-07)), (vcast_vd_d_advsimd_sleef(2.75572362911928827629423e-06)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(2.4801587159235472998791e-05)), (vcast_vd_d_advsimd_sleef(0.000198412698960509205564975)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(0.00138888888889774492207962)), (vcast_vd_d_advsimd_sleef(0.00833333333331652721664984)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(0.0416666666666665047591422)), (vcast_vd_d_advsimd_sleef(0.166666666666666851703837)))))))));\n\n  u = vadd_vd_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(s2, vcast_vd_d_advsimd_sleef(0.5), vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(s2, s), u)), s);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(q, vcast_vi_i_advsimd_sleef(0))), u,\n         vsub_vd_vd_vd_advsimd_sleef(vldexp2_vd_vd_vi_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(1)), q), vcast_vd_d_advsimd_sleef(1)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef logk_advsimd_sleef(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x, x2, s;\n  vdouble_advsimd_sleef t, m;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), m), ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), m));\n  x2 = ddsqu_vd2_vd2_advsimd_sleef(x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x2), vd2getx_vd_vd2_advsimd_sleef(x2)), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vcast_vd_d_advsimd_sleef(0.116255524079935043668677)), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.103239680901072952701192)), (vcast_vd_d_advsimd_sleef(0.117754809412463995466069)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.13332981086846273921509)), (vcast_vd_d_advsimd_sleef(0.153846227114512262845736)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.181818180850050775676507)), (vcast_vd_d_advsimd_sleef(0.222222222230083560345903)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.285714285714249172087875)), (vcast_vd_d_advsimd_sleef(0.400000000000000077715612)))))))));\n\n  vdouble2_advsimd_sleef c = vcast_vd2_d_d_advsimd_sleef(0.666666666666666629659233, 3.80554962542412056336616e-17);\n\n  s = ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_advsimd_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n  x = ddmul_vd2_vd2_vd2_advsimd_sleef(x2, x);\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddmul_vd2_vd2_vd2_advsimd_sleef(x, c));\n  x = ddmul_vd2_vd2_vd2_advsimd_sleef(x2, x);\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddmul_vd2_vd2_vd_advsimd_sleef(x, t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_logd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x;\n  vdouble_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), m), ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), m));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x));\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(0.1532076988502701353e+0)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.1525629051003428716e+0)), (vcast_vd_d_advsimd_sleef(0.1818605932937785996e+0)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.2222214519839380009e+0)), (vcast_vd_d_advsimd_sleef(0.2857142932794299317e+0)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.3999999999635251990e+0)), (vcast_vd_d_advsimd_sleef(0.6666666666667333541e+0)))))));\n\n  vdouble2_advsimd_sleef s = ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_advsimd_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n  s = ddadd_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)), t));\n\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2gety_vd_vd2_advsimd_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vispinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef expk_advsimd_sleef(vdouble2_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931));\n  vdouble_advsimd_sleef dq = vrint_vd_vd_advsimd_sleef(u);\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(dq);\n  vdouble2_advsimd_sleef s, t;\n\n  s = ddadd2_vd2_vd2_vd_advsimd_sleef(d, vmul_vd_vd_vd_advsimd_sleef(dq, vcast_vd_d_advsimd_sleef(-.69314718055966295651160180568695068359375)));\n  s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dq, vcast_vd_d_advsimd_sleef(-.28235290563031577122588448175013436025525412068e-12)));\n\n  s = ddnormalize_vd2_vd2_advsimd_sleef(s);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2getx_vd_vd2_advsimd_sleef(s)), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.51069683420950419527139e-08)), (vcast_vd_d_advsimd_sleef(2.76286166770270649116855e-07)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(2.75572496725023574143864e-06)), (vcast_vd_d_advsimd_sleef(2.48014973989819794114153e-05)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(0.000198412698809069797676111)), (vcast_vd_d_advsimd_sleef(0.0013888888939977128960529)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(0.00833333333332371417601081)), (vcast_vd_d_advsimd_sleef(0.0416666666665409524128449)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(0.166666666666666740681535)), (vcast_vd_d_advsimd_sleef(0.500000000000000999200722)))))))));\n\n  t = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), s);\n  t = ddadd_vd2_vd2_vd2_advsimd_sleef(t, ddmul_vd2_vd2_vd_advsimd_sleef(ddsqu_vd2_vd2_advsimd_sleef(s), u));\n\n  u = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), vd2gety_vd_vd2_advsimd_sleef(t));\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-1000)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_powd2_u10advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vopmask_advsimd_sleef yisint = visint_vo_vd_advsimd_sleef(y);\n  vopmask_advsimd_sleef yisodd = vand_vo_vo_vo_advsimd_sleef(visodd_vo_vd_advsimd_sleef(y), yisint);\n\n  vdouble2_advsimd_sleef d = ddmul_vd2_vd2_vd_advsimd_sleef(logk_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x)), y);\n  vdouble_advsimd_sleef result = expk_advsimd_sleef(d);\n  vopmask_advsimd_sleef o = vgt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(7.09782712893383973e+02));\n  result = vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(__builtin_inf()), result);\n\n  result = vmul_vd_vd_vd_advsimd_sleef(result,\n    vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)),\n       vcast_vd_d_advsimd_sleef(1),\n       vsel_vd_vo_vd_vd_advsimd_sleef(yisint, vsel_vd_vo_vd_vd_advsimd_sleef(yisodd, vcast_vd_d_advsimd_sleef(-1.0), vcast_vd_d_advsimd_sleef(1)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")))));\n\n  vdouble_advsimd_sleef efx = vmulsign_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(1)), y);\n\n  result = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(y),\n       vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(efx, vcast_vd_d_advsimd_sleef(0.0)),\n          vreinterpret_vm_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(efx, vcast_vd_d_advsimd_sleef(0.0)),\n                  vcast_vd_d_advsimd_sleef(1.0),\n                  vcast_vd_d_advsimd_sleef(__builtin_inf()))))),\n       result);\n\n  result = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0.0))),\n       vmulsign_vd_vd_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(vxor_vo_vo_vo_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(y), veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0.0))),\n              vcast_vd_d_advsimd_sleef(0), vcast_vd_d_advsimd_sleef(__builtin_inf())),\n           vsel_vd_vo_vd_vd_advsimd_sleef(yisodd, x, vcast_vd_d_advsimd_sleef(1))), result);\n\n  result = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vreinterpret_vm_vd_advsimd_sleef(result)));\n\n  result = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0)), veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1))), vcast_vd_d_advsimd_sleef(1), result);\n\n  return result;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef expk2_advsimd_sleef(vdouble2_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931));\n  vdouble_advsimd_sleef dq = vrint_vd_vd_advsimd_sleef(u);\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(dq);\n  vdouble2_advsimd_sleef s, t;\n\n  s = ddadd2_vd2_vd2_vd_advsimd_sleef(d, vmul_vd_vd_vd_advsimd_sleef(dq, vcast_vd_d_advsimd_sleef(-.69314718055966295651160180568695068359375)));\n  s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(dq, vcast_vd_d_advsimd_sleef(-.28235290563031577122588448175013436025525412068e-12)));\n\n  vdouble2_advsimd_sleef s2 = ddsqu_vd2_vd2_advsimd_sleef(s), s4 = ddsqu_vd2_vd2_advsimd_sleef(s2);\n  vdouble_advsimd_sleef s8 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s4), vd2getx_vd_vd2_advsimd_sleef(s4));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.1602472219709932072e-9)), (vcast_vd_d_advsimd_sleef(+0.2092255183563157007e-8)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s4)), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s2)), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.2505230023782644465e-7)), (vcast_vd_d_advsimd_sleef(+0.2755724800902135303e-6)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.2755731892386044373e-5)), (vcast_vd_d_advsimd_sleef(+0.2480158735605815065e-4)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s2)), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.1984126984148071858e-3)), (vcast_vd_d_advsimd_sleef(+0.1388888888886763255e-2)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(s)), (vcast_vd_d_advsimd_sleef(+0.8333333333333347095e-2)), (vcast_vd_d_advsimd_sleef(+0.4166666666666669905e-1)))))))));\n\n  t = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), ddmul_vd2_vd2_vd_advsimd_sleef(s, vcast_vd_d_advsimd_sleef(+0.1666666666666666574e+0)));\n  t = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1.0), ddmul_vd2_vd2_vd2_advsimd_sleef(t, s));\n  t = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1.0), ddmul_vd2_vd2_vd2_advsimd_sleef(t, s));\n  t = ddadd_vd2_vd2_vd2_advsimd_sleef(t, ddmul_vd2_vd2_vd_advsimd_sleef(s4, u));\n\n  t = vd2setx_vd2_vd2_vd_advsimd_sleef(t, vldexp2_vd_vd_vi_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), q));\n  t = vd2sety_vd2_vd2_vd_advsimd_sleef(t, vldexp2_vd_vd_vi_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(t), q));\n\n  t = vd2setx_vd2_vd2_vd_advsimd_sleef(t, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-1000)), vreinterpret_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t)))));\n  t = vd2sety_vd2_vd2_vd_advsimd_sleef(t, vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-1000)), vreinterpret_vm_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(t)))));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sinhd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef y = vabs_vd_vd_advsimd_sleef(x);\n  vdouble2_advsimd_sleef d = expk2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0)));\n  d = ddsub_vd2_vd2_vd2_advsimd_sleef(d, ddrec_vd2_vd2_advsimd_sleef(d));\n  y = vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(710)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_inf()), y);\n  y = vmulsign_vd_vd_vd_advsimd_sleef(y, x);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_coshd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef y = vabs_vd_vd_advsimd_sleef(x);\n  vdouble2_advsimd_sleef d = expk2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0)));\n  d = ddadd_vd2_vd2_vd2_advsimd_sleef(d, ddrec_vd2_vd2_advsimd_sleef(d));\n  y = vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(710)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_tanhd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef y = vabs_vd_vd_advsimd_sleef(x);\n  vdouble2_advsimd_sleef d = expk2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0)));\n  vdouble2_advsimd_sleef e = ddrec_vd2_vd2_advsimd_sleef(d);\n  d = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd2_advsimd_sleef(d, ddneg_vd2_vd2_advsimd_sleef(e)), ddadd2_vd2_vd2_vd2_advsimd_sleef(d, e));\n  y = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(18.714973875)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(1.0), y);\n  y = vmulsign_vd_vd_vd_advsimd_sleef(y, x);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sinhd2_u35advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef e = expm1k_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x));\n\n  vdouble_advsimd_sleef y = vdiv_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(e, vcast_vd_d_advsimd_sleef(2)), vadd_vd_vd_vd_advsimd_sleef(e, vcast_vd_d_advsimd_sleef(1)));\n  y = vmul_vd_vd_vd_advsimd_sleef(y, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), e));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(709)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_inf()), y);\n  y = vmulsign_vd_vd_vd_advsimd_sleef(y, x);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_coshd2_u35advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef e = Sleef_expd2_u10advsimd(vabs_vd_vd_advsimd_sleef(x));\n  vdouble_advsimd_sleef y = vmla_vd_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), e, vdiv_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), e));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(709)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_tanhd2_u35advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef d = expm1k_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2), vabs_vd_vd_advsimd_sleef(x)));\n  vdouble_advsimd_sleef y = vdiv_vd_vd_vd_advsimd_sleef(d, vadd_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2), d));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(18.714973875)), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(1.0), y);\n  y = vmulsign_vd_vd_vd_advsimd_sleef(y, x);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef logk2_advsimd_sleef(vdouble2_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x, x2, m, s;\n  vdouble_advsimd_sleef t;\n  vint_advsimd_sleef e;\n\n  e = vilogbk_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1.0/0.75)));\n\n  m = vd2setxy_vd2_vd_vd_advsimd_sleef(vldexp2_vd_vd_vi_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vneg_vi_vi_advsimd_sleef(e)),\n    vldexp2_vd_vd_vi_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(d), vneg_vi_vi_advsimd_sleef(e)));\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(-1)), ddadd2_vd2_vd2_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(1)));\n  x2 = ddsqu_vd2_vd2_advsimd_sleef(x);\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x2), vd2getx_vd_vd2_advsimd_sleef(x2)), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(0.13860436390467167910856)), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.131699838841615374240845)), (vcast_vd_d_advsimd_sleef(0.153914168346271945653214)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.181816523941564611721589)), (vcast_vd_d_advsimd_sleef(0.22222224632662035403996)))), (vmla_vd_vd_vd_vd_advsimd_sleef((vd2getx_vd_vd2_advsimd_sleef(x2)), (vcast_vd_d_advsimd_sleef(0.285714285511134091777308)), (vcast_vd_d_advsimd_sleef(0.400000000000914013309483)))))));\n\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(x2), vcast_vd_d_advsimd_sleef(0.666666666666664853302393));\n\n  s = ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_advsimd_sleef(e));\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddmul_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(x2, x), t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_asinhd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef y = vabs_vd_vd_advsimd_sleef(x);\n  vopmask_advsimd_sleef o = vgt_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(1));\n  vdouble2_advsimd_sleef d;\n\n  d = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddrec_vd2_vd_advsimd_sleef(x), vcast_vd2_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0)));\n  d = ddsqrt_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(ddsqu_vd2_vd2_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(1)));\n  d = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddmul_vd2_vd2_vd_advsimd_sleef(d, y), d);\n\n  d = logk2_advsimd_sleef(ddnormalize_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(d, x)));\n  y = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(1.3407807929942596355e+154)),\n        visnan_vo_vd_advsimd_sleef(y)),\n         vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(__builtin_inf()), x), y);\n\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(-0.0), y);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_acoshd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble2_advsimd_sleef d = logk2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddsqrt_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1))), ddsqrt_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(-1)))), x));\n  vdouble_advsimd_sleef y = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(1.3407807929942596355e+154)),\n        visnan_vo_vd_advsimd_sleef(y)),\n         vcast_vd_d_advsimd_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0)), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.0)), vreinterpret_vm_vd_advsimd_sleef(y)));\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_atanhd2_u10advsimd(vdouble_advsimd_sleef x) {\n  vdouble_advsimd_sleef y = vabs_vd_vd_advsimd_sleef(x);\n  vdouble2_advsimd_sleef d = logk2_advsimd_sleef(dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), y), ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vneg_vd_vd_advsimd_sleef(y))));\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(1.0)), vreinterpret_vm_vd_advsimd_sleef(vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(1.0)), vcast_vd_d_advsimd_sleef(__builtin_inf()), vmul_vd_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(0.5))))));\n\n  y = vmulsign_vd_vd_vd_advsimd_sleef(y, x);\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vreinterpret_vm_vd_advsimd_sleef(y)));\n  y = vreinterpret_vd_vm_advsimd_sleef(vor_vm_vo64_vm_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), vreinterpret_vm_vd_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_cbrtd2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef x, y, q = vcast_vd_d_advsimd_sleef(1.0);\n  vint_advsimd_sleef e, qu, re;\n  vdouble_advsimd_sleef t;\n\n  e = vadd_vi_vi_vi_advsimd_sleef(vilogbk_vi_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d)), vcast_vi_i_advsimd_sleef(1));\n  d = vldexp2_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n\n  t = vadd_vd_vd_vd_advsimd_sleef(vcast_vd_vi_advsimd_sleef(e), vcast_vd_d_advsimd_sleef(6144));\n  qu = vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(t, vcast_vd_d_advsimd_sleef(1.0/3.0)));\n  re = vtruncate_vi_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(t, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_vi_advsimd_sleef(qu), vcast_vd_d_advsimd_sleef(3))));\n\n  q = vsel_vd_vo_vd_vd_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(re, vcast_vi_i_advsimd_sleef(1))), vcast_vd_d_advsimd_sleef(1.2599210498948731647672106), q);\n  q = vsel_vd_vo_vd_vd_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(re, vcast_vi_i_advsimd_sleef(2))), vcast_vd_d_advsimd_sleef(1.5874010519681994747517056), q);\n  q = vldexp2_vd_vd_vi_advsimd_sleef(q, vsub_vi_vi_vi_advsimd_sleef(qu, vcast_vi_i_advsimd_sleef(2048)));\n\n  q = vmulsign_vd_vd_vd_advsimd_sleef(q, d);\n\n  d = vabs_vd_vd_advsimd_sleef(d);\n\n  x = vcast_vd_d_advsimd_sleef(-0.640245898480692909870982);\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(2.96155103020039511818595));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(-5.73353060922947843636166));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(6.03990368989458747961407));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(-3.85841935510444988821632));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(2.2307275302496609725722));\n\n  y = vmul_vd_vd_vd_advsimd_sleef(x, x); y = vmul_vd_vd_vd_advsimd_sleef(y, y); x = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vmlapn_vd_vd_vd_vd_advsimd_sleef(d, y, x), vcast_vd_d_advsimd_sleef(1.0 / 3.0)));\n  y = vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, x), x);\n  y = vmul_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(y, vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2.0 / 3.0), y), vmla_vd_vd_vd_vd_advsimd_sleef(y, x, vcast_vd_d_advsimd_sleef(-1.0)))), q);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_cbrtd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef x, y, z, t;\n  vdouble2_advsimd_sleef q2 = vcast_vd2_d_d_advsimd_sleef(1, 0), u, v;\n  vint_advsimd_sleef e, qu, re;\n\n  e = vadd_vi_vi_vi_advsimd_sleef(vilogbk_vi_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(d)), vcast_vi_i_advsimd_sleef(1));\n  d = vldexp2_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n\n  t = vadd_vd_vd_vd_advsimd_sleef(vcast_vd_vi_advsimd_sleef(e), vcast_vd_d_advsimd_sleef(6144));\n  qu = vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(t, vcast_vd_d_advsimd_sleef(1.0/3.0)));\n  re = vtruncate_vi_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(t, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_vi_advsimd_sleef(qu), vcast_vd_d_advsimd_sleef(3))));\n\n  q2 = vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(re, vcast_vi_i_advsimd_sleef(1))), vcast_vd2_d_d_advsimd_sleef(1.2599210498948731907, -2.5899333753005069177e-17), q2);\n  q2 = vsel_vd2_vo_vd2_vd2_advsimd_sleef(vcast_vo64_vo32_advsimd_sleef(veq_vo_vi_vi_advsimd_sleef(re, vcast_vi_i_advsimd_sleef(2))), vcast_vd2_d_d_advsimd_sleef(1.5874010519681995834, -1.0869008194197822986e-16), q2);\n\n  q2 = vd2setxy_vd2_vd_vd_advsimd_sleef(vmulsign_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(q2), d), vmulsign_vd_vd_vd_advsimd_sleef(vd2gety_vd_vd2_advsimd_sleef(q2), d));\n  d = vabs_vd_vd_advsimd_sleef(d);\n\n  x = vcast_vd_d_advsimd_sleef(-0.640245898480692909870982);\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(2.96155103020039511818595));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(-5.73353060922947843636166));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(6.03990368989458747961407));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(-3.85841935510444988821632));\n  x = vmla_vd_vd_vd_vd_advsimd_sleef(x, d, vcast_vd_d_advsimd_sleef(2.2307275302496609725722));\n\n  y = vmul_vd_vd_vd_advsimd_sleef(x, x); y = vmul_vd_vd_vd_advsimd_sleef(y, y); x = vsub_vd_vd_vd_advsimd_sleef(x, vmul_vd_vd_vd_advsimd_sleef(vmlapn_vd_vd_vd_vd_advsimd_sleef(d, y, x), vcast_vd_d_advsimd_sleef(1.0 / 3.0)));\n\n  z = x;\n\n  u = ddmul_vd2_vd_vd_advsimd_sleef(x, x);\n  u = ddmul_vd2_vd2_vd2_advsimd_sleef(u, u);\n  u = ddmul_vd2_vd2_vd_advsimd_sleef(u, d);\n  u = ddadd2_vd2_vd2_vd_advsimd_sleef(u, vneg_vd_vd_advsimd_sleef(x));\n  y = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(u), vd2gety_vd_vd2_advsimd_sleef(u));\n\n  y = vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-2.0 / 3.0), y), z);\n  v = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd_vd_advsimd_sleef(z, z), y);\n  v = ddmul_vd2_vd2_vd_advsimd_sleef(v, d);\n  v = ddmul_vd2_vd2_vd2_advsimd_sleef(v, q2);\n  z = vldexp2_vd_vd_vi_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(v), vd2gety_vd_vd2_advsimd_sleef(v)), vsub_vi_vi_vi_advsimd_sleef(qu, vcast_vi_i_advsimd_sleef(2048)));\n\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(d), vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(__builtin_inf()), vd2getx_vd_vd2_advsimd_sleef(q2)), z);\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vreinterpret_vd_vm_advsimd_sleef(vsignbit_vm_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(q2))), z);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_exp2d2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(d), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vsub_vd_vd_vd_advsimd_sleef(d, u);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.4434359082926529454e-9)), (vcast_vd_d_advsimd_sleef(+0.7073164598085707425e-8)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1017819260921760451e-6)), (vcast_vd_d_advsimd_sleef(+0.1321543872511327615e-5)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1525273353517584730e-4)), (vcast_vd_d_advsimd_sleef(+0.1540353045101147808e-3)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1333355814670499073e-2)), (vcast_vd_d_advsimd_sleef(+0.9618129107597600536e-2)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.5550410866482046596e-1)), (vcast_vd_d_advsimd_sleef(+0.2402265069591012214e+0)))))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.6931471805599452862e+0));\n\n  u = vfma_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1));\n\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(vge_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1024)), vcast_vd_d_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-2000)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_exp2d2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(d), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vsub_vd_vd_vd_advsimd_sleef(d, u);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.4434359082926529454e-9)), (vcast_vd_d_advsimd_sleef(+0.7073164598085707425e-8)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1017819260921760451e-6)), (vcast_vd_d_advsimd_sleef(+0.1321543872511327615e-5)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1525273353517584730e-4)), (vcast_vd_d_advsimd_sleef(+0.1540353045101147808e-3)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1333355814670499073e-2)), (vcast_vd_d_advsimd_sleef(+0.9618129107597600536e-2)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.5550410866482046596e-1)), (vcast_vd_d_advsimd_sleef(+0.2402265069591012214e+0)))))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.6931471805599452862e+0));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1));\n\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(vge_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1024)), vcast_vd_d_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-2000)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_exp10d2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-0.30102999566383914498), d);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-1.4205023227266099418e-13), s);\n\n  u = vcast_vd_d_advsimd_sleef(+0.2411463498334267652e-3);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1157488415217187375e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.5013975546789733659e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1959762320720533080e-1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.6808936399446784138e-1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.2069958494722676234e+0));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.5393829292058536229e+0));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.1171255148908541655e+1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.2034678592293432953e+1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.2650949055239205876e+1));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(+0.2302585092994045901e+1));\n\n  u = vfma_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1));\n\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(308.25471555991671)), vcast_vd_d_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-350)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_exp10d2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef u = vrint_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint_advsimd_sleef q = vrint_vi_vd_advsimd_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-0.30102999566383914498), d);\n  s = vmla_vd_vd_vd_vd_advsimd_sleef(u, vcast_vd_d_advsimd_sleef(-1.4205023227266099418e-13), s);\n\n  vdouble_advsimd_sleef s2 = vmul_vd_vd_vd_advsimd_sleef(s, s), s4 = vmul_vd_vd_vd_advsimd_sleef(s2, s2), s8 = vmul_vd_vd_vd_advsimd_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef((s8), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vcast_vd_d_advsimd_sleef(+0.2411463498334267652e-3)), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1157488415217187375e-2)), (vcast_vd_d_advsimd_sleef(+0.5013975546789733659e-2)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s4), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1959762320720533080e-1)), (vcast_vd_d_advsimd_sleef(+0.6808936399446784138e-1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.2069958494722676234e+0)), (vcast_vd_d_advsimd_sleef(+0.5393829292058536229e+0)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((s2), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.1171255148908541655e+1)), (vcast_vd_d_advsimd_sleef(+0.2034678592293432953e+1)))), (vmla_vd_vd_vd_vd_advsimd_sleef((s), (vcast_vd_d_advsimd_sleef(+0.2650949055239205876e+1)), (vcast_vd_d_advsimd_sleef(+0.2302585092994045901e+1)))))))));\n\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, s, vcast_vd_d_advsimd_sleef(1));\n\n  u = vldexp2_vd_vd_vi_advsimd_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(308.25471555991671)), vcast_vd_d_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_advsimd_sleef(vandnot_vm_vo64_vm_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-350)), vreinterpret_vm_vd_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_expm1d2_u10advsimd(vdouble_advsimd_sleef a) {\n  vdouble2_advsimd_sleef d = ddadd2_vd2_vd2_vd_advsimd_sleef(expk2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0))), vcast_vd_d_advsimd_sleef(-1.0));\n  vdouble_advsimd_sleef x = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(d), vd2gety_vd_vd2_advsimd_sleef(d));\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(709.782712893383996732223)), vcast_vd_d_advsimd_sleef(__builtin_inf()), x);\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(-36.736800569677101399113302437)), vcast_vd_d_advsimd_sleef(-1), x);\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(a), vcast_vd_d_advsimd_sleef(-0.0), x);\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_log10d2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x;\n  vdouble_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), m), ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), m));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x));\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(+0.6653725819576758460e-1)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.6625722782820833712e-1)), (vcast_vd_d_advsimd_sleef(+0.7898105214313944078e-1)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.9650955035715275132e-1)), (vcast_vd_d_advsimd_sleef(+0.1240841409721444993e+0)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.1737177927454605086e+0)), (vcast_vd_d_advsimd_sleef(+0.2895296546021972617e+0)))))));\n\n  vdouble2_advsimd_sleef s = ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.30102999566398119802, -2.803728127785170339e-18), vcast_vd_vi_advsimd_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddmul_vd2_vd2_vd2_advsimd_sleef(x, vcast_vd2_d_d_advsimd_sleef(0.86858896380650363334, 1.1430059694096389311e-17)));\n  s = ddadd_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)), t));\n\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2gety_vd_vd2_advsimd_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vispinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_log2d2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x;\n  vdouble_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), m), ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), m));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x));\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(+0.2211941750456081490e+0)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.2200768693152277689e+0)), (vcast_vd_d_advsimd_sleef(+0.2623708057488514656e+0)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.3205977477944495502e+0)), (vcast_vd_d_advsimd_sleef(+0.4121985945485324709e+0)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(+0.5770780162997058982e+0)), (vcast_vd_d_advsimd_sleef(+0.96179669392608091449)))))));\n\n  vdouble2_advsimd_sleef s = ddadd2_vd2_vd_vd2_advsimd_sleef(vcast_vd_vi_advsimd_sleef(e),\n     ddmul_vd2_vd2_vd2_advsimd_sleef(x, vcast_vd2_d_d_advsimd_sleef(2.885390081777926774, 6.0561604995516736434e-18)));\n\n  s = ddadd2_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)), t));\n\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2gety_vd_vd2_advsimd_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vispinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_log2d2_u35advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef m, t, x, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_advsimd_sleef(d, vneg_vi_vi_advsimd_sleef(e));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n\n  x = vdiv_vd_vd_vd_advsimd_sleef(vsub_vd_vd_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(1)), vadd_vd_vd_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(1)));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(x, x);\n\n  t = vcast_vd_d_advsimd_sleef(+0.2211941750456081490e+0);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.2200768693152277689e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.2623708057488514656e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.3205977477944495502e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.4121985945485324709e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.5770780162997058982e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, x2, vcast_vd_d_advsimd_sleef(+0.96179669392608091449 ));\n\n  vdouble2_advsimd_sleef s = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_vi_advsimd_sleef(e),\n    ddmul_vd2_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2.885390081777926774)));\n\n  vdouble_advsimd_sleef r = vmla_vd_vd_vd_vd_advsimd_sleef(t, vmul_vd_vd_vd_advsimd_sleef(x, x2), vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2gety_vd_vd2_advsimd_sleef(s)));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vispinf_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_log1pd2_u10advsimd(vdouble_advsimd_sleef d) {\n  vdouble2_advsimd_sleef x;\n  vdouble_advsimd_sleef t, m, x2;\n\n  vdouble_advsimd_sleef dp1 = vadd_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1));\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(dp1, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  dp1 = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(dp1, vcast_vd_d_advsimd_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), dp1);\n  vint_advsimd_sleef e = vilogb2k_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(dp1, vcast_vd_d_advsimd_sleef(1.0/0.75)));\n  t = vldexp3_vd_vd_vi_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vneg_vi_vi_advsimd_sleef(e));\n  m = vmla_vd_vd_vd_vd_advsimd_sleef(d, t, vsub_vd_vd_vd_advsimd_sleef(t, vcast_vd_d_advsimd_sleef(1)));\n  e = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(o), vsub_vi_vi_vi_advsimd_sleef(e, vcast_vi_i_advsimd_sleef(64)), e);\n  vdouble2_advsimd_sleef s = ddmul_vd2_vd2_vd_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_advsimd_sleef(e));\n\n  x = dddiv_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(m, vcast_vd_d_advsimd_sleef(0)), ddadd_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2), m));\n  x2 = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2getx_vd_vd2_advsimd_sleef(x));\n\n  vdouble_advsimd_sleef x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2), x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(0.1532076988502701353e+0)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.1525629051003428716e+0)), (vcast_vd_d_advsimd_sleef(0.1818605932937785996e+0)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.2222214519839380009e+0)), (vcast_vd_d_advsimd_sleef(0.2857142932794299317e+0)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vcast_vd_d_advsimd_sleef(0.3999999999635251990e+0)), (vcast_vd_d_advsimd_sleef(0.6666666666667333541e+0)))))));\n\n  s = ddadd_vd2_vd2_vd2_advsimd_sleef(s, ddscale_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)));\n  s = ddadd_vd2_vd2_vd_advsimd_sleef(s, vmul_vd_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x2, vd2getx_vd_vd2_advsimd_sleef(x)), t));\n\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(s), vd2gety_vd_vd2_advsimd_sleef(s));\n\n  vopmask_advsimd_sleef ocore = vle_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(9.99999999999999986e+306));\n  if(!__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef (ocore)), 1)) r = vsel_vd_vo_vd_vd_advsimd_sleef(ocore, r, Sleef_logd2_u10advsimd(d));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-1)), visnan_vo_vd_advsimd_sleef(d)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(-1)), vcast_vd_d_advsimd_sleef(-__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visnegzero_vo_vd_advsimd_sleef(d), vcast_vd_d_advsimd_sleef(-0.0), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fabsd2_advsimd(vdouble_advsimd_sleef x) { return vabs_vd_vd_advsimd_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_copysignd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) { return vcopysign_vd_vd_vd_advsimd_sleef(x, y); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fmaxd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n\n  return vsel_vd_vo_vd_vd_advsimd_sleef(visnan_vo_vd_advsimd_sleef(y), x, vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(x, y), x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fmind2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n\n  return vsel_vd_vo_vd_vd_advsimd_sleef(visnan_vo_vd_advsimd_sleef(y), x, vsel_vd_vo_vd_vd_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(y, x), x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fdimd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef ret = vsub_vd_vd_vd_advsimd_sleef(x, y);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(ret, vcast_vd_d_advsimd_sleef(0)), veq_vo_vd_vd_advsimd_sleef(x, y)), vcast_vd_d_advsimd_sleef(0), ret);\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_truncd2_advsimd(vdouble_advsimd_sleef x) { return vtruncate2_vd_vd_advsimd_sleef_advsimd_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_floord2_advsimd(vdouble_advsimd_sleef x) { return vfloor2_vd_vd_advsimd_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_ceild2_advsimd(vdouble_advsimd_sleef x) { return vceil2_vd_vd_advsimd_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_roundd2_advsimd(vdouble_advsimd_sleef x) { return vround2_vd_vd_advsimd_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_rintd2_advsimd(vdouble_advsimd_sleef x) { return vrint2_vd_vd_advsimd_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_nextafterd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0), y), x);\n  vmask_advsimd_sleef xi2 = vreinterpret_vm_vd_advsimd_sleef(x);\n  vopmask_advsimd_sleef c = vxor_vo_vo_vo_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(x), vge_vo_vd_vd_advsimd_sleef(y, x));\n\n  xi2 = vsel_vm_vo64_vm_vm_advsimd_sleef(c, vneg64_vm_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(xi2, vcast_vm_i_i_advsimd_sleef((int)(1U << 31), 0))), xi2);\n\n  xi2 = vsel_vm_vo64_vm_vm_advsimd_sleef(vneq_vo_vd_vd_advsimd_sleef(x, y), vsub64_vm_vm_vm_advsimd_sleef(xi2, vcast_vm_i_i_advsimd_sleef(0, 1)), xi2);\n\n  xi2 = vsel_vm_vo64_vm_vm_advsimd_sleef(c, vneg64_vm_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(xi2, vcast_vm_i_i_advsimd_sleef((int)(1U << 31), 0))), xi2);\n\n  vdouble_advsimd_sleef ret = vreinterpret_vd_vm_advsimd_sleef(xi2);\n\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(ret, vcast_vd_d_advsimd_sleef(0)), vneq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0))),\n    vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0), x), ret);\n\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(0))), y, ret);\n\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_frfrexpd2_advsimd(vdouble_advsimd_sleef x) {\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(2.22507385850720138e-308)), vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 63)), x);\n\n  vmask_advsimd_sleef xm = vreinterpret_vm_vd_advsimd_sleef(x);\n  xm = vand_vm_vm_vm_advsimd_sleef(xm, vcast_vm_i64_advsimd_sleef(~INT64_C(0x7ff0000000000000)));\n  xm = vor_vm_vm_vm_advsimd_sleef (xm, vcast_vm_i64_advsimd_sleef( INT64_C(0x3fe0000000000000)));\n\n  vdouble_advsimd_sleef ret = vreinterpret_vd_vm_advsimd_sleef(xm);\n\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(__builtin_inf()), x), ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), x, ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vint_advsimd_sleef Sleef_expfrexpd2_advsimd(vdouble_advsimd_sleef x) {\n  x = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(2.22507385850720138e-308)), vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 63)), x);\n\n  vint_advsimd_sleef ret = vcastu_vi_vm_advsimd_sleef(vreinterpret_vm_vd_advsimd_sleef(x));\n  ret = vsub_vi_vi_vi_advsimd_sleef(vand_vi_vi_vi_advsimd_sleef(vreinterpret_s32_u32(vshr_n_u32(vreinterpret_u32_s32(ret), 20)), vcast_vi_i_advsimd_sleef(0x7ff)), vcast_vi_i_advsimd_sleef(0x3fe));\n\n  ret = vsel_vi_vo_vi_vi_advsimd_sleef(vcast_vo32_vo64_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(0)), visnan_vo_vd_advsimd_sleef(x)), visinf_vo_vd_advsimd_sleef(x))), vcast_vi_i_advsimd_sleef(0), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fmad2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y, vdouble_advsimd_sleef z) {\n  return vfma_vd_vd_vd_vd_advsimd_sleef(x, y, z);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sqrtd2_u05advsimd(vdouble_advsimd_sleef d) {\n  vdouble_advsimd_sleef q, w, x, y, z;\n\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), d);\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(8.636168555094445E-78));\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.157920892373162E77)), d);\n  q = vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(2.9387358770557188E-39), vcast_vd_d_advsimd_sleef(1));\n\n  y = vreinterpret_vd_vm_advsimd_sleef(vsub64_vm_vm_vm_advsimd_sleef(vcast_vm_i_i_advsimd_sleef(0x5fe6ec85, 0xe7de30da), vreinterpretq_u32_u64(vshrq_n_u64(vreinterpretq_u64_u32(vreinterpret_vm_vd_advsimd_sleef(d)), 1))));\n\n  x = vmul_vd_vd_vd_advsimd_sleef(d, y); w = vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), y);\n  y = vfmanp_vd_vd_vd_vd_advsimd_sleef(x, w, vcast_vd_d_advsimd_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_advsimd_sleef(x, y, x); w = vfma_vd_vd_vd_vd_advsimd_sleef(w, y, w);\n  y = vfmanp_vd_vd_vd_vd_advsimd_sleef(x, w, vcast_vd_d_advsimd_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_advsimd_sleef(x, y, x); w = vfma_vd_vd_vd_vd_advsimd_sleef(w, y, w);\n  y = vfmanp_vd_vd_vd_vd_advsimd_sleef(x, w, vcast_vd_d_advsimd_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_advsimd_sleef(x, y, x); w = vfma_vd_vd_vd_vd_advsimd_sleef(w, y, w);\n\n  y = vfmanp_vd_vd_vd_vd_advsimd_sleef(x, w, vcast_vd_d_advsimd_sleef(1.5)); w = vadd_vd_vd_vd_advsimd_sleef(w, w);\n  w = vmul_vd_vd_vd_advsimd_sleef(w, y);\n  x = vmul_vd_vd_vd_advsimd_sleef(w, d);\n  y = vfmapn_vd_vd_vd_vd_advsimd_sleef(w, d, x); z = vfmanp_vd_vd_vd_vd_advsimd_sleef(w, x, vcast_vd_d_advsimd_sleef(1));\n\n  z = vfmanp_vd_vd_vd_vd_advsimd_sleef(w, y, z); w = vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), x);\n  w = vfma_vd_vd_vd_vd_advsimd_sleef(w, z, y);\n  w = vadd_vd_vd_vd_advsimd_sleef(w, x);\n\n  w = vmul_vd_vd_vd_advsimd_sleef(w, q);\n\n  w = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)),\n        veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(__builtin_inf()))), d, w);\n\n  w = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), w);\n\n  return w;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sqrtd2_advsimd(vdouble_advsimd_sleef d) {\n\n  return vsqrt_vd_vd_advsimd_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_sqrtd2_u35advsimd(vdouble_advsimd_sleef d) { return Sleef_sqrtd2_u05advsimd(d); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_hypotd2_u05advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  x = vabs_vd_vd_advsimd_sleef(x);\n  y = vabs_vd_vd_advsimd_sleef(y);\n  vdouble_advsimd_sleef min = vmin_vd_vd_vd_advsimd_sleef(x, y), n = min;\n  vdouble_advsimd_sleef max = vmax_vd_vd_vd_advsimd_sleef(x, y), d = max;\n\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(max, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  n = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), d);\n\n  vdouble2_advsimd_sleef t = dddiv_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(0)), vcast_vd2_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)));\n  t = ddmul_vd2_vd2_vd_advsimd_sleef(ddsqrt_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(ddsqu_vd2_vd2_advsimd_sleef(t), vcast_vd_d_advsimd_sleef(1))), max);\n  vdouble_advsimd_sleef ret = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t), vd2gety_vd_vd2_advsimd_sleef(t));\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(visnan_vo_vd_advsimd_sleef(ret), vcast_vd_d_advsimd_sleef(__builtin_inf()), ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(min, vcast_vd_d_advsimd_sleef(0)), max, ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(__builtin_inf())), veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(__builtin_inf()))), vcast_vd_d_advsimd_sleef(__builtin_inf()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_hypotd2_u35advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  x = vabs_vd_vd_advsimd_sleef(x);\n  y = vabs_vd_vd_advsimd_sleef(y);\n  vdouble_advsimd_sleef min = vmin_vd_vd_vd_advsimd_sleef(x, y);\n  vdouble_advsimd_sleef max = vmax_vd_vd_vd_advsimd_sleef(x, y);\n\n  vdouble_advsimd_sleef t = vdiv_vd_vd_vd_advsimd_sleef(min, max);\n  vdouble_advsimd_sleef ret = vmul_vd_vd_vd_advsimd_sleef(max, vsqrt_vd_vd_advsimd_sleef(vmla_vd_vd_vd_vd_advsimd_sleef(t, t, vcast_vd_d_advsimd_sleef(1))));\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(min, vcast_vd_d_advsimd_sleef(0)), max, ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vd_advsimd_sleef(x), visnan_vo_vd_advsimd_sleef(y)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(__builtin_inf())), veq_vo_vd_vd_advsimd_sleef(y, vcast_vd_d_advsimd_sleef(__builtin_inf()))), vcast_vd_d_advsimd_sleef(__builtin_inf()), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_advsimd_sleef vptrunc_vd_vd_advsimd_sleef(vdouble_advsimd_sleef x) {\n\n  return vtruncate_vd_vd_advsimd_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_fmodd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef n = vabs_vd_vd_advsimd_sleef(x), d = vabs_vd_vd_advsimd_sleef(y), s = vcast_vd_d_advsimd_sleef(1), q;\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308));\n  n = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), d);\n  s = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(s , vcast_vd_d_advsimd_sleef(1.0 / (UINT64_C(1) << 54))), s);\n  vdouble2_advsimd_sleef r = vcast_vd2_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(0));\n  vdouble_advsimd_sleef rd = vtoward0_vd_vd_advsimd_sleef(vrec_vd_vd_advsimd_sleef(d));\n\n  for(int i=0;i<21;i++) {\n    q = vptrunc_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vtoward0_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)), rd));\n    q = vsel_vd_vo_vd_vd_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(3), d), vd2getx_vd_vd2_advsimd_sleef(r)),\n           vge_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), d)),\n    vcast_vd_d_advsimd_sleef(2), q);\n    q = vsel_vd_vo_vd_vd_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vgt_vo_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(d, d), vd2getx_vd_vd2_advsimd_sleef(r)),\n           vge_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), d)),\n    vcast_vd_d_advsimd_sleef(1), q);\n    r = ddnormalize_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd2_advsimd_sleef(r, ddmul_vd2_vd_vd_advsimd_sleef(q, vneg_vd_vd_advsimd_sleef(d))));\n    if (vtestallones_i_vo64_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), d))) break;\n  }\n\n  vdouble_advsimd_sleef ret = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), s);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), vd2gety_vd_vd2_advsimd_sleef(r)), d), vcast_vd_d_advsimd_sleef(0), ret);\n\n  ret = vmulsign_vd_vd_vd_advsimd_sleef(ret, x);\n\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(n, d), x, ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_advsimd_sleef vrintk2_vd_vd_advsimd_sleef(vdouble_advsimd_sleef d) {\n\n  return vrint_vd_vd_advsimd_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_remainderd2_advsimd(vdouble_advsimd_sleef x, vdouble_advsimd_sleef y) {\n  vdouble_advsimd_sleef n = vabs_vd_vd_advsimd_sleef(x), d = vabs_vd_vd_advsimd_sleef(y), s = vcast_vd_d_advsimd_sleef(1), q;\n  vopmask_advsimd_sleef o = vlt_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(2.22507385850720138e-308*2));\n  n = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(UINT64_C(1) << 54)), d);\n  s = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmul_vd_vd_vd_advsimd_sleef(s , vcast_vd_d_advsimd_sleef(1.0 / (UINT64_C(1) << 54))), s);\n  vdouble_advsimd_sleef rd = vrec_vd_vd_advsimd_sleef(d);\n  vdouble2_advsimd_sleef r = vcast_vd2_vd_vd_advsimd_sleef(n, vcast_vd_d_advsimd_sleef(0));\n  vopmask_advsimd_sleef qisodd = vneq_vo_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0), vcast_vd_d_advsimd_sleef(0));\n\n  for(int i=0;i<21;i++) {\n    q = vrintk2_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), rd));\n    q = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)), vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(1.5))), vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1.0), vd2getx_vd_vd2_advsimd_sleef(r)), q);\n    q = vsel_vd_vo_vd_vd_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)), vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.5))),\n          vandnot_vo_vo_vo_advsimd_sleef(qisodd, veq_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r)), vmul_vd_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0.5))))),\n    vcast_vd_d_advsimd_sleef(0.0), q);\n    if (vtestallones_i_vo64_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(q, vcast_vd_d_advsimd_sleef(0)))) break;\n    q = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(q, vneg_vd_vd_advsimd_sleef(d))), vadd_vd_vd_vd_advsimd_sleef(q, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(-1), vd2getx_vd_vd2_advsimd_sleef(r))), q);\n    qisodd = vxor_vo_vo_vo_advsimd_sleef(qisodd, visodd_vo_vd_advsimd_sleef(q));\n    r = ddnormalize_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd2_advsimd_sleef(r, ddmul_vd2_vd_vd_advsimd_sleef(q, vneg_vd_vd_advsimd_sleef(d))));\n  }\n\n  vdouble_advsimd_sleef ret = vmul_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(r), s);\n  ret = vmulsign_vd_vd_vd_advsimd_sleef(ret, x);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(y), vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), x), ret);\n  ret = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(d, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), ret);\n  return ret;\n}\n\nstatic SLEEF_CONST dd2_advsimd_sleef gammak_advsimd_sleef(vdouble_advsimd_sleef a) {\n  vdouble2_advsimd_sleef clc = vcast_vd2_d_d_advsimd_sleef(0, 0), clln = vcast_vd2_d_d_advsimd_sleef(1, 0), clld = vcast_vd2_d_d_advsimd_sleef(1, 0);\n  vdouble2_advsimd_sleef x, y, z;\n  vdouble_advsimd_sleef t, u;\n\n  vopmask_advsimd_sleef otiny = vlt_vo_vd_vd_advsimd_sleef(vabs_vd_vd_advsimd_sleef(a), vcast_vd_d_advsimd_sleef(1e-306)), oref = vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0.5));\n\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(otiny, vcast_vd2_d_d_advsimd_sleef(0, 0),\n     vsel_vd2_vo_vd2_vd2_advsimd_sleef(oref, ddadd2_vd2_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), vneg_vd_vd_advsimd_sleef(a)),\n           vcast_vd2_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0))));\n\n  vopmask_advsimd_sleef o0 = vand_vo_vo_vo_advsimd_sleef(vle_vo_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(0.5), vd2getx_vd_vd2_advsimd_sleef(x)), vle_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(1.1)));\n  vopmask_advsimd_sleef o2 = vle_vo_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2.3), vd2getx_vd_vd2_advsimd_sleef(x));\n\n  y = ddnormalize_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1)), x));\n  y = ddnormalize_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2)), y));\n  y = ddnormalize_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(3)), y));\n  y = ddnormalize_vd2_vd2_advsimd_sleef(ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(4)), y));\n\n  vopmask_advsimd_sleef o = vand_vo_vo_vo_advsimd_sleef(o2, vle_vo_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vcast_vd_d_advsimd_sleef(7)));\n  clln = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, y, clln);\n\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o, ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(5)), x);\n\n  t = vsel_vd_vo_vd_vd_advsimd_sleef(o2, vrec_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x)), vd2getx_vd_vd2_advsimd_sleef(ddnormalize_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vsel_vd_vo_d_d_advsimd_sleef(o0, -1, -2)))));\n\n  u = vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -156.801412704022726379848862, +0.2947916772827614196e+2, +0.7074816000864609279e-7);\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +1.120804464289911606838558160000, +0.1281459691827820109e+3, +0.4009244333008730443e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +13.39798545514258921833306020000, +0.2617544025784515043e+3, +0.1040114641628246946e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.116546276599463200848033357000, +0.3287022855685790432e+3, +0.1508349150733329167e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -1.391801093265337481495562410000, +0.2818145867730348186e+3, +0.1288143074933901020e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.015056113040026424412918973400, +0.1728670414673559605e+3, +0.4744167749884993937e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.179540117061234856098844714000, +0.7748735764030416817e+2, -0.6554816306542489902e-7));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.002481743600264997730942489280, +0.2512856643080930752e+2, -0.3189252471452599844e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.029527880945699120504851034100, +0.5766792106140076868e+1, +0.1358883821470355377e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.000540164767892604515196325186, +0.7270275473996180571e+0, -0.4343931277157336040e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.006403362833808069794787256200, +0.8396709124579147809e-1, +0.9724785897406779555e-6));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.000162516262783915816896611252, -0.8211558669746804595e-1, -0.2036886057225966011e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.001914438498565477526465972390, +0.6828831828341884458e-1, +0.4373363141819725815e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +7.20489541602001055898311517e-05, -0.7712481339961671511e-1, -0.9439951268304008677e-5));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.000839498720672087279971000786, +0.8337492023017314957e-1, +0.2050727030376389804e-4));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -5.17179090826059219329394422e-05, -0.9094964931456242518e-1, -0.4492620183431184018e-4));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.000592166437353693882857342347, +0.1000996313575929358e+0, +0.9945751236071875931e-4));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +6.97281375836585777403743539e-05, -0.1113342861544207724e+0, -0.2231547599034983196e-3));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.000784039221720066627493314301, +0.1255096673213020875e+0, +0.5096695247101967622e-3));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.000229472093621399176949318732, -0.1440498967843054368e+0, -0.1192753911667886971e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, -0.002681327160493827160473958490, +0.1695571770041949811e+0, +0.2890510330742210310e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.003472222222222222222175164840, -0.2073855510284092762e+0, -0.7385551028674461858e-2));\n  u = vmla_vd_vd_vd_vd_advsimd_sleef(u, t, vsel_vd_vo_vo_d_d_d_advsimd_sleef(o2, o0, +0.083333333333333333335592087900, +0.2705808084277815939e+0, +0.2058080842778455335e-1));\n\n  y = ddmul_vd2_vd2_vd2_advsimd_sleef(ddadd2_vd2_vd2_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(-0.5)), logk2_advsimd_sleef(x));\n  y = ddadd2_vd2_vd2_vd2_advsimd_sleef(y, ddneg_vd2_vd2_advsimd_sleef(x));\n  y = ddadd2_vd2_vd2_vd2_advsimd_sleef(y, vcast_vd2_d_d_advsimd_sleef(0.91893853320467278056, -3.8782941580672414498e-17));\n\n  z = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd_vd_advsimd_sleef (u, t), vsel_vd_vo_d_d_advsimd_sleef(o0, -0.4006856343865314862e+0, -0.6735230105319810201e-1));\n  z = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd_advsimd_sleef(z, t), vsel_vd_vo_d_d_advsimd_sleef(o0, +0.8224670334241132030e+0, +0.3224670334241132030e+0));\n  z = ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd2_vd_advsimd_sleef(z, t), vsel_vd_vo_d_d_advsimd_sleef(o0, -0.5772156649015328655e+0, +0.4227843350984671345e+0));\n  z = ddmul_vd2_vd2_vd_advsimd_sleef(z, t);\n\n  clc = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o2, y, z);\n\n  clld = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o2, ddadd2_vd2_vd2_vd_advsimd_sleef(ddmul_vd2_vd_vd_advsimd_sleef(u, t), vcast_vd_d_advsimd_sleef(1)), clld);\n\n  y = clln;\n\n  clc = vsel_vd2_vo_vd2_vd2_advsimd_sleef(otiny, vcast_vd2_d_d_advsimd_sleef(83.1776616671934334590333, 3.67103459631568507221878e-15),\n       vsel_vd2_vo_vd2_vd2_advsimd_sleef(oref, ddadd2_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(1.1447298858494001639, 1.026595116270782638e-17), ddneg_vd2_vd2_advsimd_sleef(clc)), clc));\n  clln = vsel_vd2_vo_vd2_vd2_advsimd_sleef(otiny, vcast_vd2_d_d_advsimd_sleef(1, 0), vsel_vd2_vo_vd2_vd2_advsimd_sleef(oref, clln, clld));\n\n  if (!vtestallones_i_vo64_advsimd_sleef(vnot_vo64_vo64_advsimd_sleef(oref))) {\n    t = vsub_vd_vd_vd_advsimd_sleef(a, vmul_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(INT64_C(1) << 28), vcast_vd_vi_advsimd_sleef(vtruncate_vi_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(1.0 / (INT64_C(1) << 28)))))));\n    x = ddmul_vd2_vd2_vd2_advsimd_sleef(clld, sinpik_advsimd_sleef(t));\n  }\n\n  clld = vsel_vd2_vo_vd2_vd2_advsimd_sleef(otiny, vcast_vd2_vd_vd_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef((INT64_C(1) << 60)*(double)(INT64_C(1) << 60))), vcast_vd_d_advsimd_sleef(0)),\n        vsel_vd2_vo_vd2_vd2_advsimd_sleef(oref, x, y));\n\n  return dd2setab_dd2_vd2_vd2_advsimd_sleef(clc, dddiv_vd2_vd2_vd2_advsimd_sleef(clln, clld));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_tgammad2_u10advsimd(vdouble_advsimd_sleef a) {\n  dd2_advsimd_sleef d = gammak_advsimd_sleef(a);\n  vdouble2_advsimd_sleef y = ddmul_vd2_vd2_vd2_advsimd_sleef(expk2_advsimd_sleef(dd2geta_vd2_dd2_advsimd_sleef(d)), dd2getb_vd2_dd2_advsimd_sleef(d));\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(y));\n  vopmask_advsimd_sleef o;\n\n  o = vor_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(-__builtin_inf())),\n    vand_vo_vo_vo_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)), visint_vo_vd_advsimd_sleef(a))),\n     vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(visnumber_vo_vd_advsimd_sleef(a), vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0))), visnan_vo_vd_advsimd_sleef(r)));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n\n  o = vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(__builtin_inf())), visnumber_vo_vd_advsimd_sleef(a)),\n      vge_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(-2.22507385850720138e-308))),\n      vor_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)), vgt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(200))), visnan_vo_vd_advsimd_sleef(r)));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(o, vmulsign_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(__builtin_inf()), a), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_lgammad2_u10advsimd(vdouble_advsimd_sleef a) {\n  dd2_advsimd_sleef d = gammak_advsimd_sleef(a);\n  vdouble2_advsimd_sleef y = ddadd2_vd2_vd2_vd2_advsimd_sleef(dd2geta_vd2_dd2_advsimd_sleef(d), logk2_advsimd_sleef(ddabs_vd2_vd2_advsimd_sleef(dd2getb_vd2_dd2_advsimd_sleef(d))));\n  vdouble_advsimd_sleef r = vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(y), vd2gety_vd_vd2_advsimd_sleef(y));\n  vopmask_advsimd_sleef o;\n\n  o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vd_advsimd_sleef(a),\n     vor_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vle_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)), visint_vo_vd_advsimd_sleef(a)),\n    vand_vo_vo_vo_advsimd_sleef(visnumber_vo_vd_advsimd_sleef(a), visnan_vo_vd_advsimd_sleef(r))));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(o, vcast_vd_d_advsimd_sleef(__builtin_inf()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef ddmla_vd2_vd_vd2_vd2_advsimd_sleef(vdouble_advsimd_sleef x, vdouble2_advsimd_sleef y, vdouble2_advsimd_sleef z) {\n  return ddadd_vd2_vd2_vd2_advsimd_sleef(z, ddmul_vd2_vd2_vd_advsimd_sleef(y, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef poly2dd_b_advsimd_sleef(vdouble_advsimd_sleef x, vdouble2_advsimd_sleef c1, vdouble2_advsimd_sleef c0) { return ddmla_vd2_vd_vd2_vd2_advsimd_sleef(x, c1, c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef poly2dd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef c1, vdouble2_advsimd_sleef c0) { return ddmla_vd2_vd_vd2_vd2_advsimd_sleef(x, vcast_vd2_vd_vd_advsimd_sleef(c1, vcast_vd_d_advsimd_sleef(0)), c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_advsimd_sleef poly4dd_advsimd_sleef(vdouble_advsimd_sleef x, vdouble_advsimd_sleef c3, vdouble2_advsimd_sleef c2, vdouble2_advsimd_sleef c1, vdouble2_advsimd_sleef c0) {\n  return ddmla_vd2_vd_vd2_vd2_advsimd_sleef(vmul_vd_vd_vd_advsimd_sleef(x, x), poly2dd_advsimd_sleef(x, c3, c2), poly2dd_b_advsimd_sleef(x, c1, c0));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_erfd2_u10advsimd(vdouble_advsimd_sleef a) {\n  vdouble_advsimd_sleef t, x = vabs_vd_vd_advsimd_sleef(a);\n  vdouble2_advsimd_sleef t2;\n  vdouble_advsimd_sleef x2 = vmul_vd_vd_vd_advsimd_sleef(x, x), x4 = vmul_vd_vd_vd_advsimd_sleef(x2, x2);\n  vdouble_advsimd_sleef x8 = vmul_vd_vd_vd_advsimd_sleef(x4, x4), x16 = vmul_vd_vd_vd_advsimd_sleef(x8, x8);\n  vopmask_advsimd_sleef o25 = vle_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(2.5));\n\n  if (__builtin_expect(!!(vtestallones_i_vo64_advsimd_sleef(o25)), 1)) {\n\n    t = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vcast_vd_d_advsimd_sleef(-0.2083271002525222097e-14)), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.7151909970790897009e-13)), (vcast_vd_d_advsimd_sleef(-0.1162238220110999364e-11)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.1186474230821585259e-10)), (vcast_vd_d_advsimd_sleef(-0.8499973178354613440e-10)))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.4507647462598841629e-9)), (vcast_vd_d_advsimd_sleef(-0.1808044474288848915e-8)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.5435081826716212389e-8)), (vcast_vd_d_advsimd_sleef(-0.1143939895758628484e-7)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.1215442362680889243e-7)), (vcast_vd_d_advsimd_sleef(+0.1669878756181250355e-7)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(-0.9808074602255194288e-7)), (vcast_vd_d_advsimd_sleef(+0.1389000557865837204e-6)))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.2945514529987331866e-6)), (vcast_vd_d_advsimd_sleef(-0.1842918273003998283e-5)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.3417987836115362136e-5)), (vcast_vd_d_advsimd_sleef(+0.3860236356493129101e-5)))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(-0.3309403072749947546e-4)), (vcast_vd_d_advsimd_sleef(+0.1060862922597579532e-3)))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), (vcast_vd_d_advsimd_sleef(+0.2323253155213076174e-3)), (vcast_vd_d_advsimd_sleef(+0.1490149719145544729e-3)))))))))));\n\n    t2 = poly4dd_advsimd_sleef(x, t,\n   vcast_vd2_d_d_advsimd_sleef(0.0092877958392275604405, 7.9287559463961107493e-19),\n   vcast_vd2_d_d_advsimd_sleef(0.042275531758784692937, 1.3785226620501016138e-19),\n   vcast_vd2_d_d_advsimd_sleef(0.07052369794346953491, 9.5846628070792092842e-19));\n    t2 = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), ddmul_vd2_vd2_vd_advsimd_sleef(t2, x));\n    t2 = ddsqu_vd2_vd2_advsimd_sleef(t2);\n    t2 = ddsqu_vd2_vd2_advsimd_sleef(t2);\n    t2 = ddsqu_vd2_vd2_advsimd_sleef(t2);\n    t2 = ddsqu_vd2_vd2_advsimd_sleef(t2);\n    t2 = ddrec_vd2_vd2_advsimd_sleef(t2);\n  } else {\n\n    t = vmla_vd_vd_vd_vd_advsimd_sleef((x16), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.2083271002525222097e-14, -0.4024015130752621932e-18))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.7151909970790897009e-13, +0.3847193332817048172e-16))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.1162238220110999364e-11, -0.1749316241455644088e-14))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1186474230821585259e-10, +0.5029618322872872715e-13))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.8499973178354613440e-10, -0.1025221466851463164e-11))))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x8), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.4507647462598841629e-9, +0.1573695559331945583e-10))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.1808044474288848915e-8, -0.1884658558040203709e-9))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.5435081826716212389e-8, +0.1798167853032159309e-8))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.1143939895758628484e-7, -0.1380745342355033142e-7))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1215442362680889243e-7, +0.8525705726469103499e-7))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1669878756181250355e-7, -0.4160448058101303405e-6))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.9808074602255194288e-7, +0.1517272660008588485e-5))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1389000557865837204e-6, -0.3341634127317201697e-5))))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x4), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.2945514529987331866e-6, -0.2515023395879724513e-5))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.1842918273003998283e-5, +0.6539731269664907554e-4))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.3417987836115362136e-5, -0.3551065097428388658e-3))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.3860236356493129101e-5, +0.1210736097958368864e-2))))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x2), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, -0.3309403072749947546e-4, -0.2605566912579998680e-2))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1060862922597579532e-3, +0.1252823202436093193e-2))))), (vmla_vd_vd_vd_vd_advsimd_sleef((x), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.2323253155213076174e-3, +0.1820191395263313222e-1))), ((vsel_vd_vo_d_d_advsimd_sleef(o25, +0.1490149719145544729e-3, -0.1021557155453465954e+0))))))))))));\n\n    t2 = poly4dd_advsimd_sleef(x, t,\n   vsel_vd2_vo_vd2_vd2_advsimd_sleef(o25, vcast_vd2_d_d_advsimd_sleef(0.0092877958392275604405, 7.9287559463961107493e-19),\n         vcast_vd2_d_d_advsimd_sleef(-0.63691044383641748361, -2.4249477526539431839e-17)),\n   vsel_vd2_vo_vd2_vd2_advsimd_sleef(o25, vcast_vd2_d_d_advsimd_sleef(0.042275531758784692937, 1.3785226620501016138e-19),\n         vcast_vd2_d_d_advsimd_sleef(-1.1282926061803961737, -6.2970338860410996505e-17)),\n   vsel_vd2_vo_vd2_vd2_advsimd_sleef(o25, vcast_vd2_d_d_advsimd_sleef(0.07052369794346953491, 9.5846628070792092842e-19),\n         vcast_vd2_d_d_advsimd_sleef(-1.2261313785184804967e-05, -5.5329707514490107044e-22)));\n    vdouble2_advsimd_sleef s2 = ddadd_vd2_vd_vd2_advsimd_sleef(vcast_vd_d_advsimd_sleef(1), ddmul_vd2_vd2_vd_advsimd_sleef(t2, x));\n    s2 = ddsqu_vd2_vd2_advsimd_sleef(s2);\n    s2 = ddsqu_vd2_vd2_advsimd_sleef(s2);\n    s2 = ddsqu_vd2_vd2_advsimd_sleef(s2);\n    s2 = ddsqu_vd2_vd2_advsimd_sleef(s2);\n    s2 = ddrec_vd2_vd2_advsimd_sleef(s2);\n    t2 = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o25, s2, vcast_vd2_vd_vd_advsimd_sleef(expk_advsimd_sleef(t2), vcast_vd_d_advsimd_sleef(0)));\n  }\n\n  t2 = ddadd2_vd2_vd2_vd_advsimd_sleef(t2, vcast_vd_d_advsimd_sleef(-1));\n\n  vdouble_advsimd_sleef z = vneg_vd_vd_advsimd_sleef(vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(t2), vd2gety_vd_vd2_advsimd_sleef(t2)));\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(vlt_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1e-8)), vmul_vd_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(1.12837916709551262756245475959)), z);\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(vge_vo_vd_vd_advsimd_sleef(x, vcast_vd_d_advsimd_sleef(6)), vcast_vd_d_advsimd_sleef(1), z);\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(visinf_vo_vd_advsimd_sleef(a), vcast_vd_d_advsimd_sleef(1), z);\n  z = vsel_vd_vo_vd_vd_advsimd_sleef(veq_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)), vcast_vd_d_advsimd_sleef(0), z);\n  z = vmulsign_vd_vd_vd_advsimd_sleef(z, a);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_advsimd_sleef Sleef_erfcd2_u15advsimd(vdouble_advsimd_sleef a) {\n  vdouble_advsimd_sleef s = a, r = vcast_vd_d_advsimd_sleef(0), t;\n  vdouble2_advsimd_sleef u, d, x;\n  a = vabs_vd_vd_advsimd_sleef(a);\n  vopmask_advsimd_sleef o0 = vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(1.0));\n  vopmask_advsimd_sleef o1 = vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(2.2));\n  vopmask_advsimd_sleef o2 = vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(4.2));\n  vopmask_advsimd_sleef o3 = vlt_vo_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(27.3));\n\n  u = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o0, ddmul_vd2_vd_vd_advsimd_sleef(a, a), vsel_vd2_vo_vd2_vd2_advsimd_sleef(o1, vcast_vd2_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)), dddiv_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(1, 0), vcast_vd2_vd_vd_advsimd_sleef(a, vcast_vd_d_advsimd_sleef(0)))));\n\n  t = vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.6801072401395386139e-20, +0.3438010341362585303e-12, -0.5757819536420710449e+2, +0.2334249729638701319e+5);\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.2161766247570055669e-18, -0.1237021188160598264e-10, +0.4669289654498104483e+3, -0.4695661044933107769e+5));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.4695919173301595670e-17, +0.2117985839877627852e-09, -0.1796329879461355858e+4, +0.3173403108748643353e+5));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.9049140419888007122e-16, -0.2290560929177369506e-08, +0.4355892193699575728e+4, +0.3242982786959573787e+4));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.1634018903557410728e-14, +0.1748931621698149538e-07, -0.7456258884965764992e+4, -0.2014717999760347811e+5));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.2783485786333451745e-13, -0.9956602606623249195e-07, +0.9553977358167021521e+4, +0.1554006970967118286e+5));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.4463221276786415752e-12, +0.4330010240640327080e-06, -0.9470019905444229153e+4, -0.6150874190563554293e+4));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.6711366622850136563e-11, -0.1435050600991763331e-05, +0.7387344321849855078e+4, +0.1240047765634815732e+4));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.9422759050232662223e-10, +0.3460139479650695662e-05, -0.4557713054166382790e+4, -0.8210325475752699731e+2));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.1229055530100229098e-08, -0.4988908180632898173e-05, +0.2207866967354055305e+4, +0.3242443880839930870e+2));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.1480719281585086512e-07, -0.1308775976326352012e-05, -0.8217975658621754746e+3, -0.2923418863833160586e+2));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.1636584469123399803e-06, +0.2825086540850310103e-04, +0.2268659483507917400e+3, +0.3457461732814383071e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.1646211436588923575e-05, -0.6393913713069986071e-04, -0.4633361260318560682e+2, +0.5489730155952392998e+1));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.1492565035840623511e-04, -0.2566436514695078926e-04, +0.9557380123733945965e+1, +0.1559934132251294134e-2));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.1205533298178967851e-03, +0.5895792375659440364e-03, -0.2958429331939661289e+1, -0.1541741566831520638e+1));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.8548327023450850081e-03, -0.1695715579163588598e-02, +0.1670329508092765480e+0, +0.2823152230558364186e-5));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, +0.5223977625442187932e-02, +0.2089116434918055149e-03, +0.6096615680115419211e+0, +0.6249999184195342838e+0));\n  t = vmla_vd_vd_vd_vd_advsimd_sleef(t, vd2getx_vd_vd2_advsimd_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.2686617064513125222e-01, +0.1912855949584917753e-01, +0.1059212443193543585e-2, +0.1741749416408701288e-8));\n\n  d = ddmul_vd2_vd2_vd_advsimd_sleef(u, t);\n  d = ddadd2_vd2_vd2_vd2_advsimd_sleef(d, vcast_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, 0.11283791670955126141, -0.10277263343147646779, -0.50005180473999022439, -0.5000000000258444377),\n         vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -4.0175691625932118483e-18, -6.2338714083404900225e-18, 2.6362140569041995803e-17, -4.0074044712386992281e-17)));\n  d = ddmul_vd2_vd2_vd2_advsimd_sleef(d, u);\n  d = ddadd2_vd2_vd2_vd2_advsimd_sleef(d, vcast_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.37612638903183753802, -0.63661976742916359662, 1.601106273924963368e-06, 2.3761973137523364792e-13),\n         vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, 1.3391897206042552387e-17, 7.6321019159085724662e-18, 1.1974001857764476775e-23, -1.1670076950531026582e-29)));\n  d = ddmul_vd2_vd2_vd2_advsimd_sleef(d, u);\n  d = ddadd2_vd2_vd2_vd2_advsimd_sleef(d, vcast_vd2_vd_vd_advsimd_sleef(vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, 1.1283791670955125586, -1.1283791674717296161, -0.57236496645145429341, -0.57236494292470108114),\n         vsel_vd_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, 1.5335459613165822674e-17, 8.0896847755965377194e-17, 3.0704553245872027258e-17, -2.3984352208056898003e-17)));\n\n  x = ddmul_vd2_vd2_vd_advsimd_sleef(vsel_vd2_vo_vd2_vd2_advsimd_sleef(o1, d, vcast_vd2_vd_vd_advsimd_sleef(vneg_vd_vd_advsimd_sleef(a), vcast_vd_d_advsimd_sleef(0))), a);\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o1, x, ddadd2_vd2_vd2_vd2_advsimd_sleef(x, d));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o0, ddsub_vd2_vd2_vd2_advsimd_sleef(vcast_vd2_d_d_advsimd_sleef(1, 0), x), expk2_advsimd_sleef(x));\n  x = vsel_vd2_vo_vd2_vd2_advsimd_sleef(o1, x, ddmul_vd2_vd2_vd2_advsimd_sleef(x, u));\n\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(o3, vadd_vd_vd_vd_advsimd_sleef(vd2getx_vd_vd2_advsimd_sleef(x), vd2gety_vd_vd2_advsimd_sleef(x)), vcast_vd_d_advsimd_sleef(0));\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(vsignbit_vo_vd_advsimd_sleef(s), vsub_vd_vd_vd_advsimd_sleef(vcast_vd_d_advsimd_sleef(2), r), r);\n  r = vsel_vd_vo_vd_vd_advsimd_sleef(visnan_vo_vd_advsimd_sleef(s), vcast_vd_d_advsimd_sleef(__builtin_nan(\"\")), r);\n  return r;\n}\n\n#if !defined(Sleef_quad_DEFINED)\n#define Sleef_quad_DEFINED\ntypedef struct { uint64_t x, y; } Sleef_uint64_2t;\n#if defined(SLEEF_FLOAT128_IS_IEEEQP)\ntypedef __float128 Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## Q)\n#elif defined(SLEEF_LONGDOUBLE_IS_IEEEQP)\ntypedef long double Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## L)\n#else\ntypedef Sleef_uint64_2t Sleef_quad;\n#endif\n#endif\n\nextern const float Sleef_rempitabsp[];\n\ntypedef struct {\n  vfloat_advsimd_sleef x, y;\n} vfloat2_advsimd_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vf2getx_vf_vf2_advsimd_sleef(vfloat2_advsimd_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vf2gety_vf_vf2_advsimd_sleef(vfloat2_advsimd_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vf2setxy_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { vfloat2_advsimd_sleef v; v.x = x; v.y = y; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vf2setx_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef v, vfloat_advsimd_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vf2sety_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef v, vfloat_advsimd_sleef d) { v.y = d; return v; }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vupper_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return vreinterpret_vf_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vreinterpret_vi2_vf_advsimd_sleef(d), vcast_vi2_i_advsimd_sleef(0xfffff000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vcast_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef h, vfloat_advsimd_sleef l) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(h, l);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vcast_vf2_f_f_advsimd_sleef(float h, float l) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(h), vcast_vf_f_advsimd_sleef(l));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vcast_vf2_d_advsimd_sleef(double d) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(d - (float)d));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vsel_vf2_vo_vf2_vf2_advsimd_sleef(vopmask_advsimd_sleef m, vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(m, vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y)), vsel_vf_vo_vf_vf_advsimd_sleef(m, vf2gety_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vsel_vf2_vo_f_f_f_f_advsimd_sleef(vopmask_advsimd_sleef o, float x1, float y1, float x0, float y0) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_f_f_advsimd_sleef(o, x1, x0), vsel_vf_vo_f_f_advsimd_sleef(o, y1, y0));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vsel_vf2_vo_vo_d_d_d_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, double d0, double d1, double d2) {\n  return vsel_vf2_vo_vf2_vf2_advsimd_sleef(o0, vcast_vf2_d_advsimd_sleef(d0), vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, vcast_vf2_d_advsimd_sleef(d1), vcast_vf2_d_advsimd_sleef(d2)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vsel_vf2_vo_vo_vo_d_d_d_d_advsimd_sleef(vopmask_advsimd_sleef o0, vopmask_advsimd_sleef o1, vopmask_advsimd_sleef o2, double d0, double d1, double d2, double d3) {\n  return vsel_vf2_vo_vf2_vf2_advsimd_sleef(o0, vcast_vf2_d_advsimd_sleef(d0), vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, vcast_vf2_d_advsimd_sleef(d1), vsel_vf2_vo_vf2_vf2_advsimd_sleef(o2, vcast_vf2_d_advsimd_sleef(d2), vcast_vf2_d_advsimd_sleef(d3))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef vabs_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x) {\n  return vcast_vf2_vf_vf_advsimd_sleef(vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0)), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)))),\n    vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0)), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vadd_vf_3vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2) {\n  return vadd_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vadd_vf_4vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3) {\n  return vadd_vf_3vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vadd_vf_5vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3, vfloat_advsimd_sleef v4) {\n  return vadd_vf_4vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vadd_vf_6vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3, vfloat_advsimd_sleef v4, vfloat_advsimd_sleef v5) {\n  return vadd_vf_5vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vadd_vf_7vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3, vfloat_advsimd_sleef v4, vfloat_advsimd_sleef v5, vfloat_advsimd_sleef v6) {\n  return vadd_vf_6vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3, v4, v5, v6);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vsub_vf_3vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2) {\n  return vsub_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vsub_vf_4vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3) {\n  return vsub_vf_3vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vsub_vf_5vf_advsimd_sleef(vfloat_advsimd_sleef v0, vfloat_advsimd_sleef v1, vfloat_advsimd_sleef v2, vfloat_advsimd_sleef v3, vfloat_advsimd_sleef v4) {\n  return vsub_vf_4vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfneg_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x) {\n  return vcast_vf2_vf_vf_advsimd_sleef(vneg_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)), vneg_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfabs_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x) {\n  return vcast_vf2_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)),\n    vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)), vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfnormalize_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef t) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t), vf2gety_vf_vf2_advsimd_sleef(t));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t), s), vf2gety_vf_vf2_advsimd_sleef(t)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfscale_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef d, vfloat_advsimd_sleef s) {\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), s), vmul_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(d), s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd2_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(x, y);\n  vfloat_advsimd_sleef v = vsub_vf_vf_vf_advsimd_sleef(s, x);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, vsub_vf_vf_vf_advsimd_sleef(s, v)), vsub_vf_vf_vf_advsimd_sleef(y, v)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd2_vf2_vf_vf2_advsimd_sleef(vfloat_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(x, vf2getx_vf_vf2_advsimd_sleef(y));\n  vfloat_advsimd_sleef v = vsub_vf_vf_vf_advsimd_sleef(s, x);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, vsub_vf_vf_vf_advsimd_sleef(s, v)), vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), v)), vf2gety_vf_vf2_advsimd_sleef(y)));\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_3vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), s), y, vf2gety_vf_vf2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsub_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), s), y), vf2gety_vf_vf2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd2_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), y);\n  vfloat_advsimd_sleef v = vsub_vf_vf_vf_advsimd_sleef(s, vf2getx_vf_vf2_advsimd_sleef(x));\n  vfloat_advsimd_sleef t = vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vsub_vf_vf_vf_advsimd_sleef(s, v)), vsub_vf_vf_vf_advsimd_sleef(y, v));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(t, vf2gety_vf_vf2_advsimd_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd_vf2_vf_vf2_advsimd_sleef(vfloat_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(x, vf2getx_vf_vf2_advsimd_sleef(y));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_3vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, s), vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd_vf2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_4vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), s), vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfadd2_vf2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y));\n  vfloat_advsimd_sleef v = vsub_vf_vf_vf_advsimd_sleef(s, vf2getx_vf_vf2_advsimd_sleef(x));\n  vfloat_advsimd_sleef t = vadd_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vsub_vf_vf_vf_advsimd_sleef(s, v)), vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), v));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vadd_vf_vf_vf_advsimd_sleef(t, vadd_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsub_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n\n  vfloat_advsimd_sleef s = vsub_vf_vf_vf_advsimd_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vsub_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsub_vf2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n\n  vfloat_advsimd_sleef s = vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y));\n  vfloat_advsimd_sleef t = vsub_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), s);\n  t = vsub_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(y));\n  t = vadd_vf_vf_vf_advsimd_sleef(t, vf2gety_vf_vf2_advsimd_sleef(x));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vsub_vf_vf_vf_advsimd_sleef(t, vf2gety_vf_vf2_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfdiv_vf2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef n, vfloat2_advsimd_sleef d) {\n  vfloat_advsimd_sleef t = vrec_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d));\n  vfloat_advsimd_sleef s = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(n), t);\n  vfloat_advsimd_sleef u = vfmapn_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(n), s);\n  vfloat_advsimd_sleef v = vfmanp_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(d), t, vfmanp_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), t, vcast_vf_f_advsimd_sleef(1)));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vfma_vf_vf_vf_vf_advsimd_sleef(s, v, vfma_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(n), t, u)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfmul_vf2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vmul_vf_vf_vf_advsimd_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vfmapn_vf_vf_vf_vf_advsimd_sleef(x, y, s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsqu_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x) {\n  vfloat_advsimd_sleef s = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vfma_vf_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x)), vf2gety_vf_vf2_advsimd_sleef(x), vfmapn_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x), s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef dfsqu_vf_vf2_advsimd_sleef(vfloat2_advsimd_sleef x) {\n  return vfma_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x), vadd_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x)), vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfmul_vf2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vfma_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(y), vfma_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y), vfmapn_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y), s))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef dfmul_vf_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat2_advsimd_sleef y) {\n  return vfma_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y), vfma_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y), vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfmul_vf2_vf2_vf_advsimd_sleef(vfloat2_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef s = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vfma_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x), y, vfmapn_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), y, s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfrec_vf2_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef s = vrec_vf_vf_advsimd_sleef(d);\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(s, vfmanp_vf_vf_vf_vf_advsimd_sleef(d, s, vcast_vf_f_advsimd_sleef(1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfrec_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef d) {\n  vfloat_advsimd_sleef s = vrec_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d));\n  return vf2setxy_vf2_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(s, vfmanp_vf_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(d), s, vfmanp_vf_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), s, vcast_vf_f_advsimd_sleef(1)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsqrt_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef d) {\n\n  vfloat_advsimd_sleef t = vsqrt_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)));\n  return dfscale_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf2_advsimd_sleef(d, dfmul_vf2_vf_vf_advsimd_sleef(t, t)), dfrec_vf2_vf_advsimd_sleef(t)), vcast_vf_f_advsimd_sleef(0.5));\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfsqrt_vf2_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef t = vsqrt_vf_vf_advsimd_sleef(d);\n  return dfscale_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf2_advsimd_sleef(d, dfmul_vf2_vf_vf_advsimd_sleef(t, t)), dfrec_vf2_vf_advsimd_sleef(t)), vcast_vf_f_advsimd_sleef(0.5f));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visnegzero_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return veq_vo_vi2_vi2_advsimd_sleef(vreinterpret_vi2_vf_advsimd_sleef(d), vreinterpret_vi2_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_advsimd_sleef vnot_vo32_vo32_advsimd_sleef(vopmask_advsimd_sleef x) {\n  return vxor_vo_vo_vo_advsimd_sleef(x, veq_vo_vi2_vi2_advsimd_sleef(vcast_vi2_i_advsimd_sleef(0), vcast_vi2_i_advsimd_sleef(0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_advsimd_sleef vsignbit_vm_vf_advsimd_sleef(vfloat_advsimd_sleef f) {\n  return vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(f), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vmulsign_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(x), vsignbit_vm_vf_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vcopysign_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vandnot_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f)), vreinterpret_vm_vf_advsimd_sleef(x)),\n       vand_vm_vm_vm_advsimd_sleef (vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f)), vreinterpret_vm_vf_advsimd_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vsign_vf_vf_advsimd_sleef(vfloat_advsimd_sleef f) {\n  return vreinterpret_vf_vm_advsimd_sleef(vor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f)), vand_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f)), vreinterpret_vm_vf_advsimd_sleef(f))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef vsignbit_vo_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  return veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vreinterpret_vi2_vf_advsimd_sleef(d), vcast_vi2_i_advsimd_sleef(0x80000000)), vcast_vi2_i_advsimd_sleef(0x80000000));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_advsimd_sleef vsel_vi2_vf_vf_vi2_vi2_advsimd_sleef(vfloat_advsimd_sleef f0, vfloat_advsimd_sleef f1, vint2_advsimd_sleef x, vint2_advsimd_sleef y) {\n  return vsel_vi2_vo_vi2_vi2_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(f0, f1), x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_advsimd_sleef vsel_vi2_vf_vi2_advsimd_sleef(vfloat_advsimd_sleef d, vint2_advsimd_sleef x) {\n  return vand_vi2_vo_vi2_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(d), x);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visint_vo_vf_advsimd_sleef(vfloat_advsimd_sleef y) { return veq_vo_vf_vf_advsimd_sleef(vtruncate_vf_vf_advsimd_sleef(y), y); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_advsimd_sleef visnumber_vo_vf_advsimd_sleef(vfloat_advsimd_sleef x) { return vnot_vo32_vo32_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(x))); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_advsimd_sleef vilogbk_vi2_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(5.421010862427522E-20f));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.8446744073709552E19f), d), d);\n  vint2_advsimd_sleef q = vand_vi2_vi2_vi2_advsimd_sleef(vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(vreinterpret_vi2_vf_advsimd_sleef(d)), 23)), vcast_vi2_i_advsimd_sleef(0xff));\n  q = vsub_vi2_vi2_vi2_advsimd_sleef(q, vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vcast_vi2_i_advsimd_sleef(64 + 0x7f), vcast_vi2_i_advsimd_sleef(0x7f)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_advsimd_sleef vilogb2k_vi2_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q = vreinterpret_vi2_vf_advsimd_sleef(d);\n  q = vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(q), 23));\n  q = vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(0xff));\n  q = vsub_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(0x7f));\n  return q;\n}\n\nSLEEF_INLINE SLEEF_CONST vint2_advsimd_sleef Sleef_ilogbf4_advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef e = vilogbk_vi2_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.0f)), vcast_vi2_i_advsimd_sleef(SLEEF_FP_ILOGB0), e);\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(visnan_vo_vf_advsimd_sleef(d), vcast_vi2_i_advsimd_sleef(SLEEF_FP_ILOGBNAN), e);\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vcast_vi2_i_advsimd_sleef(2147483647), e);\n  return e;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vpow2i_vf_vi2_advsimd_sleef(vint2_advsimd_sleef q) {\n  return vreinterpret_vf_vi2_advsimd_sleef(vshlq_n_s32(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(0x7f)), 23));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vldexp_vf_vf_vi2_advsimd_sleef(vfloat_advsimd_sleef x, vint2_advsimd_sleef q) {\n  vfloat_advsimd_sleef u;\n  vint2_advsimd_sleef m = vshrq_n_s32(q, 31);\n  m = vshlq_n_s32(vsub_vi2_vi2_vi2_advsimd_sleef(vshrq_n_s32(vadd_vi2_vi2_vi2_advsimd_sleef(m, q), 6), m), 4);\n  q = vsub_vi2_vi2_vi2_advsimd_sleef(q, vshlq_n_s32(m, 2));\n  m = vadd_vi2_vi2_vi2_advsimd_sleef(m, vcast_vi2_i_advsimd_sleef(0x7f));\n  m = vand_vi2_vi2_vi2_advsimd_sleef(vgt_vi2_vi2_vi2_advsimd_sleef(m, vcast_vi2_i_advsimd_sleef(0)), m);\n  vint2_advsimd_sleef n = vgt_vi2_vi2_vi2_advsimd_sleef(m, vcast_vi2_i_advsimd_sleef(0xff));\n  m = vor_vi2_vi2_vi2_advsimd_sleef(vandnot_vi2_vi2_vi2_advsimd_sleef(n, m), vand_vi2_vi2_vi2_advsimd_sleef(n, vcast_vi2_i_advsimd_sleef(0xff)));\n  u = vreinterpret_vf_vi2_advsimd_sleef(vshlq_n_s32(m, 23));\n  x = vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x, u), u), u), u);\n  u = vreinterpret_vf_vi2_advsimd_sleef(vshlq_n_s32(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(0x7f)), 23));\n  return vmul_vf_vf_vf_advsimd_sleef(x, u);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vldexp2_vf_vf_vi2_advsimd_sleef(vfloat_advsimd_sleef d, vint2_advsimd_sleef e) {\n  return vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vpow2i_vf_vi2_advsimd_sleef(vshrq_n_s32(e, 1))), vpow2i_vf_vi2_advsimd_sleef(vsub_vi2_vi2_vi2_advsimd_sleef(e, vshrq_n_s32(e, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vldexp3_vf_vf_vi2_advsimd_sleef(vfloat_advsimd_sleef d, vint2_advsimd_sleef q) {\n  return vreinterpret_vf_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(vreinterpret_vi2_vf_advsimd_sleef(d), vshlq_n_s32(q, 23)));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_ldexpf4_advsimd(vfloat_advsimd_sleef x, vint2_advsimd_sleef q) { return vldexp_vf_vf_vi2_advsimd_sleef(x, q); }\n\ntypedef struct {\n  vfloat_advsimd_sleef d;\n  vint2_advsimd_sleef i;\n} fi_t_advsimd_sleef;\n\nstatic vfloat_advsimd_sleef figetd_vf_di_advsimd_sleef(fi_t_advsimd_sleef d) { return d.d; }\nstatic vint2_advsimd_sleef figeti_vi2_di_advsimd_sleef(fi_t_advsimd_sleef d) { return d.i; }\nstatic fi_t_advsimd_sleef fisetdi_fi_vf_vi2_advsimd_sleef(vfloat_advsimd_sleef d, vint2_advsimd_sleef i) {\n  fi_t_advsimd_sleef r = { d, i };\n  return r;\n}\n\ntypedef struct {\n  vfloat2_advsimd_sleef df_advsimd_sleef;\n  vint2_advsimd_sleef i;\n} dfi_t_advsimd_sleef;\n\nstatic vfloat2_advsimd_sleef dfigetdf_vf2_dfi_advsimd_sleef(dfi_t_advsimd_sleef d) { return d.df_advsimd_sleef; }\nstatic vint2_advsimd_sleef dfigeti_vi2_dfi_advsimd_sleef(dfi_t_advsimd_sleef d) { return d.i; }\nstatic dfi_t_advsimd_sleef dfisetdfi_dfi_vf2_vi2_advsimd_sleef(vfloat2_advsimd_sleef v, vint2_advsimd_sleef i) {\n  dfi_t_advsimd_sleef r = { v, i };\n  return r;\n}\nstatic dfi_t_advsimd_sleef dfisetdf_dfi_dfi_vf2_advsimd_sleef(dfi_t_advsimd_sleef dfi_advsimd_sleef, vfloat2_advsimd_sleef v) {\n  dfi_advsimd_sleef.df_advsimd_sleef = v;\n  return dfi_advsimd_sleef;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vorsign_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  return vreinterpret_vf_vm_advsimd_sleef(vor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(x), vsignbit_vm_vf_advsimd_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST fi_t_advsimd_sleef rempisubf_advsimd_sleef(vfloat_advsimd_sleef x) {\n\n  vfloat_advsimd_sleef y = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(4)));\n  vint2_advsimd_sleef vi = vtruncate_vi2_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(y, vmul_vf_vf_vf_advsimd_sleef(vrint_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(4))));\n  return fisetdi_fi_vf_vi2_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, vmul_vf_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0.25))), vi);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST dfi_t_advsimd_sleef rempif_advsimd_sleef(vfloat_advsimd_sleef a) {\n  vfloat2_advsimd_sleef x, y;\n  vint2_advsimd_sleef ex = vilogb2k_vi2_vf_advsimd_sleef(a);\n\n  ex = vsub_vi2_vi2_vi2_advsimd_sleef(ex, vcast_vi2_i_advsimd_sleef(25));\n  vint2_advsimd_sleef q = vand_vi2_vo_vi2_advsimd_sleef(vgt_vo_vi2_vi2_advsimd_sleef(ex, vcast_vi2_i_advsimd_sleef(90-25)), vcast_vi2_i_advsimd_sleef(-64));\n  a = vldexp3_vf_vf_vi2_advsimd_sleef(a, q);\n  ex = vandnot_vi2_vi2_vi2_advsimd_sleef(vshrq_n_s32(ex, 31), ex);\n  ex = vshlq_n_s32(ex, 2);\n  x = dfmul_vf2_vf_vf_advsimd_sleef(a, vgather_vf_p_vi2_advsimd_sleef(Sleef_rempitabsp, ex));\n  fi_t_advsimd_sleef di = rempisubf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x));\n  q = figeti_vi2_di_advsimd_sleef(di);\n  x = vf2setx_vf2_vf2_vf_advsimd_sleef(x, figetd_vf_di_advsimd_sleef(di));\n  x = dfnormalize_vf2_vf2_advsimd_sleef(x);\n  y = dfmul_vf2_vf_vf_advsimd_sleef(a, vgather_vf_p_vi2_advsimd_sleef(Sleef_rempitabsp+1, ex));\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(x, y);\n  di = rempisubf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x));\n  q = vadd_vi2_vi2_vi2_advsimd_sleef(q, figeti_vi2_di_advsimd_sleef(di));\n  x = vf2setx_vf2_vf2_vf_advsimd_sleef(x, figetd_vf_di_advsimd_sleef(di));\n  x = dfnormalize_vf2_vf2_advsimd_sleef(x);\n  y = vcast_vf2_vf_vf_advsimd_sleef(vgather_vf_p_vi2_advsimd_sleef(Sleef_rempitabsp+2, ex), vgather_vf_p_vi2_advsimd_sleef(Sleef_rempitabsp+3, ex));\n  y = dfmul_vf2_vf2_vf_advsimd_sleef(y, a);\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(x, y);\n  x = dfnormalize_vf2_vf2_advsimd_sleef(x);\n  x = dfmul_vf2_vf2_vf2_advsimd_sleef(x, vcast_vf2_f_f_advsimd_sleef(3.1415927410125732422f*2, -8.7422776573475857731e-08f*2));\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(a), vcast_vf_f_advsimd_sleef(0.7f)), vcast_vf2_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), x);\n  return dfisetdfi_dfi_vf2_vi2_advsimd_sleef(x, q);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sinf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, s, r = d;\n\n  q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.318309886183790671537767526745028724)));\n  u = vcast_vf_vi2_advsimd_sleef(q);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f), d);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f), d);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f), d);\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(r), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    s = vcast_vf_vi2_advsimd_sleef(q);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-3.140625f), r);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-0.0009670257568359375f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-6.2771141529083251953e-07f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-1.2154201256553420762e-10f), u);\n\n    d = vsel_vf_vo_vf_vf_advsimd_sleef(g, d, u);\n    g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(r), vcast_vf_f_advsimd_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n      dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(r);\n      vint2_advsimd_sleef q2 = vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(3));\n      q2 = vadd_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vi2_i_advsimd_sleef(2), vcast_vi2_i_advsimd_sleef(1)));\n      q2 = vshrq_n_s32(q2, 2);\n      vopmask_advsimd_sleef o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1));\n      vfloat2_advsimd_sleef x = vcast_vf2_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.1415927410125732422f*-0.5), vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef))),\n      vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-8.7422776573475857731e-08f*-0.5), vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef))));\n      x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef), x);\n      dfi_advsimd_sleef = dfisetdf_dfi_dfi_vf2_advsimd_sleef(dfi_advsimd_sleef, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, x, dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n      u = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vf2gety_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n\n      u = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(r), visnan_vo_vf_advsimd_sleef(r)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n      q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n      d = vsel_vf_vo_vf_vf_advsimd_sleef(g, d, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_advsimd_sleef(d, d);\n\n  d = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(d)));\n\n  u = vcast_vf_f_advsimd_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00833307858556509017944336f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.166666597127914428710938f));\n\n  u = vadd_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, d)), d);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(r), r, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_cosf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, s, r = d;\n\n  q = vrint_vi2_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.318309886183790671537767526745028724)), vcast_vf_f_advsimd_sleef(0.5f)));\n  q = vadd_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, q), vcast_vi2_i_advsimd_sleef(1));\n  u = vcast_vf_vi2_advsimd_sleef(q);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f), d);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f), d);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f), d);\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(r), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    s = vcast_vf_vi2_advsimd_sleef(q);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-3.140625f*0.5f), r);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-0.0009670257568359375f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-6.2771141529083251953e-07f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-1.2154201256553420762e-10f*0.5f), u);\n\n    d = vsel_vf_vo_vf_vf_advsimd_sleef(g, d, u);\n    g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(r), vcast_vf_f_advsimd_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n      dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(r);\n      vint2_advsimd_sleef q2 = vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(3));\n      q2 = vadd_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vi2_i_advsimd_sleef(8), vcast_vi2_i_advsimd_sleef(7)));\n      q2 = vshrq_n_s32(q2, 1);\n      vopmask_advsimd_sleef o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(0));\n      vfloat_advsimd_sleef y = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(0), vcast_vf_f_advsimd_sleef(-1));\n      vfloat2_advsimd_sleef x = vcast_vf2_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.1415927410125732422f*-0.5), y),\n      vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-8.7422776573475857731e-08f*-0.5), y));\n      x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef), x);\n      dfi_advsimd_sleef = dfisetdf_dfi_dfi_vf2_advsimd_sleef(dfi_advsimd_sleef, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, x, dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n      u = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vf2gety_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n\n      u = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(r), visnan_vo_vf_advsimd_sleef(r)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n      q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n      d = vsel_vf_vo_vf_vf_advsimd_sleef(g, d, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_advsimd_sleef(d, d);\n\n  d = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(0)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(d)));\n\n  u = vcast_vf_f_advsimd_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00833307858556509017944336f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.166666597127914428710938f));\n\n  u = vadd_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, d)), d);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_tanf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, x;\n\n  q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(2 * 0.318309886183790671537767526745028724))));\n  u = vcast_vf_vi2_advsimd_sleef(q);\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f), d);\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f), x);\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f), x);\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f*0.5f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    vint2_advsimd_sleef q2 = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(2 * 0.318309886183790671537767526745028724))));\n    s = vcast_vf_vi2_advsimd_sleef(q);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-3.140625f*0.5f), d);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-0.0009670257568359375f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-6.2771141529083251953e-07f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(-1.2154201256553420762e-10f*0.5f), u);\n\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n    x = vsel_vf_vo_vf_vf_advsimd_sleef(g, x, u);\n    g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n      dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n      u = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vf2gety_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n      u = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d)), vreinterpret_vm_vf_advsimd_sleef(u)));\n      u = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), d, u);\n      q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n      x = vsel_vf_vo_vf_vf_advsimd_sleef(g, x, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_advsimd_sleef(x, x);\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1));\n  x = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(x)));\n\n  vfloat_advsimd_sleef s2 = vmul_vf_vf_vf_advsimd_sleef(s, s), s4 = vmul_vf_vf_vf_advsimd_sleef(s2, s2);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef((s4), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.00927245803177356719970703f)), (vcast_vf_f_advsimd_sleef(0.00331984995864331722259521f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((s2), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.0242998078465461730957031f)), (vcast_vf_f_advsimd_sleef(0.0534495301544666290283203f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.133383005857467651367188f)), (vcast_vf_f_advsimd_sleef(0.333331853151321411132812f)))))));\n\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, x), x);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(o, vrec_vf_vf_advsimd_sleef(u), u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sinf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, v;\n  vfloat2_advsimd_sleef s, t, x;\n\n  u = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_advsimd_sleef(u);\n  v = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f), d);\n  s = dfadd2_vf2_vf_vf_advsimd_sleef(v, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f)));\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n    vint2_advsimd_sleef q2 = vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(3));\n    q2 = vadd_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vi2_i_advsimd_sleef(2), vcast_vi2_i_advsimd_sleef(1)));\n    q2 = vshrq_n_s32(q2, 2);\n    vopmask_advsimd_sleef o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1));\n    vfloat2_advsimd_sleef x = vcast_vf2_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.1415927410125732422f*-0.5), vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef))),\n    vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-8.7422776573475857731e-08f*-0.5), vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef))));\n    x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef), x);\n    dfi_advsimd_sleef = dfisetdf_dfi_dfi_vf2_advsimd_sleef(dfi_advsimd_sleef, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, x, dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n    t = dfnormalize_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n\n    t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d)), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t)))));\n\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n    s = vsel_vf2_vo_vf2_vf2_advsimd_sleef(g, s, t);\n  }\n\n  t = s;\n  s = dfsqu_vf2_vf2_advsimd_sleef(s);\n\n  u = vcast_vf_f_advsimd_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.00833307858556509017944336f));\n\n  x = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.166666597127914428710938f), vmul_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s))), s));\n\n  u = dfmul_vf_vf2_vf2_advsimd_sleef(t, x);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_cosf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u;\n  vfloat2_advsimd_sleef s, t, x;\n\n  vfloat_advsimd_sleef dq = vmla_vf_vf_vf_vf_advsimd_sleef(vrint_vf_vf_advsimd_sleef(vmla_vf_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.318309886183790671537767526745028724), vcast_vf_f_advsimd_sleef(-0.5f))),\n          vcast_vf_f_advsimd_sleef(2), vcast_vf_f_advsimd_sleef(1));\n  q = vrint_vi2_vf_advsimd_sleef(dq);\n  s = dfadd2_vf2_vf_vf_advsimd_sleef (d, vmul_vf_vf_vf_advsimd_sleef(dq, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f)));\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(dq, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(dq, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n    vint2_advsimd_sleef q2 = vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(3));\n    q2 = vadd_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vi2_i_advsimd_sleef(8), vcast_vi2_i_advsimd_sleef(7)));\n    q2 = vshrq_n_s32(q2, 1);\n    vopmask_advsimd_sleef o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(0));\n    vfloat_advsimd_sleef y = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(0), vcast_vf_f_advsimd_sleef(-1));\n    vfloat2_advsimd_sleef x = vcast_vf2_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.1415927410125732422f*-0.5), y),\n    vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-8.7422776573475857731e-08f*-0.5), y));\n    x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef), x);\n    dfi_advsimd_sleef = dfisetdf_dfi_dfi_vf2_advsimd_sleef(dfi_advsimd_sleef, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, x, dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n    t = dfnormalize_vf2_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n\n    t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d)), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t)))));\n\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n    s = vsel_vf2_vo_vf2_vf2_advsimd_sleef(g, s, t);\n  }\n\n  t = s;\n  s = dfsqu_vf2_vf2_advsimd_sleef(s);\n\n  u = vcast_vf_f_advsimd_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.00833307858556509017944336f));\n\n  x = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.166666597127914428710938f), vmul_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s))), s));\n\n  u = dfmul_vf_vf2_vf2_advsimd_sleef(t, x);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(0)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fastsinf4_u3500advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, s, t = d;\n\n  s = vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.318309886183790671537767526745028724));\n  u = vrint_vf_vf_advsimd_sleef(s);\n  q = vrint_vi2_vf_advsimd_sleef(s);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-(float)3.141592653589793238462643383279502884), d);\n\n  s = vmul_vf_vf_vf_advsimd_sleef(d, d);\n\n  u = vcast_vf_f_advsimd_sleef(-0.1881748176e-3);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.8323502727e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.1666651368e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, d), u, d);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(30.0f));\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) return vsel_vf_vo_vf_vf_advsimd_sleef(g, u, Sleef_sinf4_u35advsimd(t));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fastcosf4_u3500advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, s, t = d;\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.318309886183790671537767526745028724), vcast_vf_f_advsimd_sleef(-0.5f));\n  u = vrint_vf_vf_advsimd_sleef(s);\n  q = vrint_vi2_vf_advsimd_sleef(s);\n  d = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-(float)3.141592653589793238462643383279502884), vsub_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)3.141592653589793238462643383279502884 * 0.5f)));\n\n  s = vmul_vf_vf_vf_advsimd_sleef(d, d);\n\n  u = vcast_vf_f_advsimd_sleef(-0.1881748176e-3);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.8323502727e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.1666651368e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, d), u, d);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(0)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(30.0f));\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) return vsel_vf_vo_vf_vf_advsimd_sleef(g, u, Sleef_cosf4_u35advsimd(t));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_advsimd_sleef Sleef_sincosf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, t, rx, ry;\n  vfloat2_advsimd_sleef r;\n\n  q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.636619772367581343075535053490057448)));\n  u = vcast_vf_vi2_advsimd_sleef(q);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f), s);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f), s);\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    vint2_advsimd_sleef q2 = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)0.636619772367581343075535053490057448)));\n    u = vcast_vf_vi2_advsimd_sleef(q2);\n    t = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.140625f*0.5f), d);\n    t = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.0009670257568359375f*0.5f), t);\n    t = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-6.2771141529083251953e-07f*0.5f), t);\n    t = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.2154201256553420762e-10f*0.5f), t);\n\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, q2);\n    s = vsel_vf_vo_vf_vf_advsimd_sleef(g, s, t);\n    g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n      dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n      t = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)), vf2gety_vf_vf2_advsimd_sleef(dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef)));\n      t = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d)), vreinterpret_vm_vf_advsimd_sleef(t)));\n\n      q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n      s = vsel_vf_vo_vf_vf_advsimd_sleef(g, s, t);\n    }\n  }\n\n  t = s;\n\n  s = vmul_vf_vf_vf_advsimd_sleef(s, s);\n\n  u = vcast_vf_f_advsimd_sleef(-0.000195169282960705459117889f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00833215750753879547119141f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.166666537523269653320312f));\n\n  rx = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(u, s), t, t);\n  rx = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_advsimd_sleef(-2.71811842367242206819355e-07f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(2.47990446951007470488548e-05f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.00138888787478208541870117f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.0416666641831398010253906f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.5));\n\n  ry = vmla_vf_vf_vf_vf_advsimd_sleef(s, u, vcast_vf_f_advsimd_sleef(1));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(0));\n  r = vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(o, rx, ry), vsel_vf_vo_vf_vf_advsimd_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_advsimd_sleef Sleef_sincosf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, v, rx, ry;\n  vfloat2_advsimd_sleef r, s, t, x;\n\n  u = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_advsimd_sleef(u);\n  v = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f), d);\n  s = dfadd2_vf2_vf_vf_advsimd_sleef(v, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n    t = dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef);\n    o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d));\n    t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t)))));\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n    s = vsel_vf2_vo_vf2_vf2_advsimd_sleef(g, s, t);\n  }\n\n  t = s;\n\n  s = vf2setx_vf2_vf2_vf_advsimd_sleef(s, dfsqu_vf_vf2_advsimd_sleef(s));\n\n  u = vcast_vf_f_advsimd_sleef(-0.000195169282960705459117889f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.00833215750753879547119141f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-0.166666537523269653320312f));\n\n  u = vmul_vf_vf_vf_advsimd_sleef(u, vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), vf2getx_vf_vf2_advsimd_sleef(t)));\n\n  x = dfadd_vf2_vf2_vf_advsimd_sleef(t, u);\n  rx = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  rx = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_advsimd_sleef(-2.71811842367242206819355e-07f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(2.47990446951007470488548e-05f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-0.00138888787478208541870117f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.0416666641831398010253906f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-0.5));\n\n  x = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), u));\n  ry = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(0));\n  r = vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(o, rx, ry), vsel_vf_vo_vf_vf_advsimd_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_advsimd_sleef Sleef_sincospif4_u05advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, t, rx, ry;\n  vfloat2_advsimd_sleef r, x, s2;\n\n  u = vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(4));\n  vint2_advsimd_sleef q = vtruncate_vi2_vf_advsimd_sleef(u);\n  q = vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vxor_vi2_vi2_vi2_advsimd_sleef(vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(q), 31)), vcast_vi2_i_advsimd_sleef(1))), vcast_vi2_i_advsimd_sleef(~1));\n  s = vsub_vf_vf_vf_advsimd_sleef(u, vcast_vf_vi2_advsimd_sleef(q));\n\n  t = s;\n  s = vmul_vf_vf_vf_advsimd_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_advsimd_sleef(t, t);\n\n  u = vcast_vf_f_advsimd_sleef(+0.3093842054e-6);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.3657307388e-4));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2490393585e-2));\n  x = dfadd2_vf2_vf_vf2_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(u, s), vcast_vf2_f_f_advsimd_sleef(-0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(s2, x), vcast_vf2_f_f_advsimd_sleef(0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf_advsimd_sleef(x, t);\n  rx = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  rx = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_advsimd_sleef(-0.2430611801e-7);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.3590577080e-5));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.3259917721e-3));\n  x = dfadd2_vf2_vf_vf2_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(u, s), vcast_vf2_f_f_advsimd_sleef(0.015854343771934509277, 4.4940051354032242811e-10));\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(s2, x), vcast_vf2_f_f_advsimd_sleef(-0.30842512845993041992, -9.0728339030733922277e-09));\n\n  x = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(x, s2), vcast_vf_f_advsimd_sleef(1));\n  ry = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(0));\n  r = vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(o, rx, ry), vsel_vf_vo_vf_vf_advsimd_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  o = vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1e+7f));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  o = visinf_vo_vf_advsimd_sleef(d);\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_advsimd_sleef Sleef_sincospif4_u35advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, t, rx, ry;\n  vfloat2_advsimd_sleef r;\n\n  u = vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(4));\n  vint2_advsimd_sleef q = vtruncate_vi2_vf_advsimd_sleef(u);\n  q = vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vxor_vi2_vi2_vi2_advsimd_sleef(vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(q), 31)), vcast_vi2_i_advsimd_sleef(1))), vcast_vi2_i_advsimd_sleef(~1));\n  s = vsub_vf_vf_vf_advsimd_sleef(u, vcast_vf_vi2_advsimd_sleef(q));\n\n  t = s;\n  s = vmul_vf_vf_vf_advsimd_sleef(s, s);\n\n  u = vcast_vf_f_advsimd_sleef(-0.3600925265e-4);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2490088111e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.8074551076e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.7853981853e+0));\n\n  rx = vmul_vf_vf_vf_advsimd_sleef(u, t);\n\n  u = vcast_vf_f_advsimd_sleef(+0.3539815225e-5);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.3259574005e-3));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1585431583e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(-0.3084251285e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(1));\n\n  ry = u;\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(0));\n  r = vf2setxy_vf2_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(o, rx, ry), vsel_vf_vo_vf_vf_advsimd_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  o = vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1e+7f));\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  o = visinf_vo_vf_advsimd_sleef(d);\n  r = vf2setx_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_advsimd_sleef(r, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vfloat2_advsimd_sleef Sleef_modff4_advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef fr = vsub_vf_vf_vf_advsimd_sleef(x, vcast_vf_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(INT64_C(1) << 23)), vcast_vf_f_advsimd_sleef(0), fr);\n\n  vfloat2_advsimd_sleef ret;\n\n  ret = vf2setxy_vf2_vf_vf_advsimd_sleef(vcopysign_vf_vf_vf_advsimd_sleef(fr, x), vcopysign_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, fr), x));\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_tanf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q;\n  vfloat_advsimd_sleef u, v;\n  vfloat2_advsimd_sleef s, t, x;\n  vopmask_advsimd_sleef o;\n\n  u = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(2 * 0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_advsimd_sleef(u);\n  v = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-3.1414794921875f*0.5f), d);\n  s = dfadd2_vf2_vf_vf_advsimd_sleef(v, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_advsimd_sleef g = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(g)), 1)) {\n    dfi_t_advsimd_sleef dfi_advsimd_sleef = rempif_advsimd_sleef(d);\n    t = dfigetdf_vf2_dfi_advsimd_sleef(dfi_advsimd_sleef);\n    o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), visnan_vo_vf_advsimd_sleef(d));\n    t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t)))));\n    t = vf2sety_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(t)))));\n    q = vsel_vi2_vo_vi2_vi2_advsimd_sleef(g, q, dfigeti_vi2_dfi_advsimd_sleef(dfi_advsimd_sleef));\n    s = vsel_vf2_vo_vf2_vf2_advsimd_sleef(g, s, t);\n  }\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1));\n  vmask_advsimd_sleef n = vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0)));\n  s = vf2setx_vf2_vf2_vf_advsimd_sleef(s, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s)), n)));\n  s = vf2sety_vf2_vf2_vf_advsimd_sleef(s, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(s)), n)));\n\n  t = s;\n  s = dfsqu_vf2_vf2_advsimd_sleef(s);\n  s = dfnormalize_vf2_vf2_advsimd_sleef(s);\n\n  u = vcast_vf_f_advsimd_sleef(0.00446636462584137916564941f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(-8.3920182078145444393158e-05f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.0109639242291450500488281f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.0212360303848981857299805f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.0540687143802642822265625f));\n\n  x = dfadd_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.133325666189193725585938f), vmul_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s)));\n  x = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.33333361148834228515625f), dfmul_vf2_vf2_vf2_advsimd_sleef(s, x)), s));\n  x = dfmul_vf2_vf2_vf2_advsimd_sleef(t, x);\n\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfrec_vf2_vf2_advsimd_sleef(x), x);\n\n  u = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_atanf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef s, t, u;\n  vint2_advsimd_sleef q;\n\n  q = vsel_vi2_vf_vi2_advsimd_sleef(d, vcast_vi2_i_advsimd_sleef(2));\n  s = vabs_vf_vf_advsimd_sleef(d);\n\n  q = vsel_vi2_vf_vf_vi2_vi2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), s, vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), q);\n  s = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), s), vrec_vf_vf_advsimd_sleef(s), s);\n\n  t = vmul_vf_vf_vf_advsimd_sleef(s, s);\n\n  vfloat_advsimd_sleef t2 = vmul_vf_vf_vf_advsimd_sleef(t, t), t4 = vmul_vf_vf_vf_advsimd_sleef(t2, t2);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef((t4), (vmla_vf_vf_vf_vf_advsimd_sleef((t2), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.00282363896258175373077393f)), (vcast_vf_f_advsimd_sleef(-0.0159569028764963150024414f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.0425049886107444763183594f)), (vcast_vf_f_advsimd_sleef(-0.0748900920152664184570312f)))))), (vmla_vf_vf_vf_vf_advsimd_sleef((t2), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.106347933411598205566406f)), (vcast_vf_f_advsimd_sleef(-0.142027363181114196777344f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.199926957488059997558594f)), (vcast_vf_f_advsimd_sleef(-0.333331018686294555664062f)))))));\n\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(t, u), s);\n\n  t = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/2)), t), t);\n\n  t = vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2)), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0f))), vreinterpret_vm_vf_advsimd_sleef(t)));\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef atan2kf_advsimd_sleef(vfloat_advsimd_sleef y, vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef s, t, u;\n  vint2_advsimd_sleef q;\n  vopmask_advsimd_sleef p;\n\n  q = vsel_vi2_vf_vi2_advsimd_sleef(x, vcast_vi2_i_advsimd_sleef(-2));\n  x = vabs_vf_vf_advsimd_sleef(x);\n\n  q = vsel_vi2_vf_vf_vi2_vi2_advsimd_sleef(x, y, vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), q);\n  p = vlt_vo_vf_vf_advsimd_sleef(x, y);\n  s = vsel_vf_vo_vf_vf_advsimd_sleef(p, vneg_vf_vf_advsimd_sleef(x), y);\n  t = vmax_vf_vf_vf_advsimd_sleef(x, y);\n\n  s = vdiv_vf_vf_vf_advsimd_sleef(s, t);\n  t = vmul_vf_vf_vf_advsimd_sleef(s, s);\n\n  vfloat_advsimd_sleef t2 = vmul_vf_vf_vf_advsimd_sleef(t, t), t4 = vmul_vf_vf_vf_advsimd_sleef(t2, t2);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef((t4), (vmla_vf_vf_vf_vf_advsimd_sleef((t2), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.00282363896258175373077393f)), (vcast_vf_f_advsimd_sleef(-0.0159569028764963150024414f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.0425049886107444763183594f)), (vcast_vf_f_advsimd_sleef(-0.0748900920152664184570312f)))))), (vmla_vf_vf_vf_vf_advsimd_sleef((t2), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.106347933411598205566406f)), (vcast_vf_f_advsimd_sleef(-0.142027363181114196777344f)))), (vmla_vf_vf_vf_vf_advsimd_sleef((t), (vcast_vf_f_advsimd_sleef(0.199926957488059997558594f)), (vcast_vf_f_advsimd_sleef(-0.333331018686294555664062f)))))));\n\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(t, u), s);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/2)), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef visinf2_vf_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d, vfloat_advsimd_sleef m) {\n  return vreinterpret_vf_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vor_vm_vm_vm_advsimd_sleef(vsignbit_vm_vf_advsimd_sleef(d), vreinterpret_vm_vf_advsimd_sleef(m))));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_atan2f4_u35advsimd(vfloat_advsimd_sleef y, vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef r = atan2kf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), x);\n\n  r = vmulsign_vf_vf_vf_advsimd_sleef(r, x);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0.0f))), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/2)), visinf2_vf_vf_vf_advsimd_sleef(x, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/2)), x))), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(y), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/2)), visinf2_vf_vf_vf_advsimd_sleef(x, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)(3.141592653589793238462643383279502884/4)), x))), r);\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0.0f)), vreinterpret_vf_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vreinterpret_vm_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_asinf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0.5f));\n  vfloat_advsimd_sleef x2 = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, d), vmul_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vabs_vf_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5f)));\n  vfloat_advsimd_sleef x = vsel_vf_vo_vf_vf_advsimd_sleef(o, vabs_vf_vf_advsimd_sleef(d), vsqrt_vf_vf_advsimd_sleef(x2)), u;\n\n  u = vcast_vf_f_advsimd_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.1666677296e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vmul_vf_vf_vf_advsimd_sleef(x, x2), x);\n\n  vfloat_advsimd_sleef r = vsel_vf_vo_vf_vf_advsimd_sleef(o, u, vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-2), vcast_vf_f_advsimd_sleef(((float)3.141592653589793238462643383279502884)/2)));\n  return vmulsign_vf_vf_vf_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_acosf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0.5f));\n  vfloat_advsimd_sleef x2 = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, d),\n    vmul_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vabs_vf_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5f))), u;\n  vfloat_advsimd_sleef x = vsel_vf_vo_vf_vf_advsimd_sleef(o, vabs_vf_vf_advsimd_sleef(d), vsqrt_vf_vf_advsimd_sleef(x2));\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1.0f)), vcast_vf_f_advsimd_sleef(0), x);\n\n  u = vcast_vf_f_advsimd_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_advsimd_sleef(u, vmul_vf_vf_vf_advsimd_sleef(x2, x));\n\n  vfloat_advsimd_sleef y = vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.1415926535897932f/2), vadd_vf_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(x, d), vmulsign_vf_vf_vf_advsimd_sleef(u, d)));\n  x = vadd_vf_vf_vf_advsimd_sleef(x, u);\n  vfloat_advsimd_sleef r = vsel_vf_vo_vf_vf_advsimd_sleef(o, y, vmul_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n  return vsel_vf_vo_vf_vf_advsimd_sleef(vandnot_vo_vo_vo_advsimd_sleef(o, vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0))),\n     vf2getx_vf_vf2_advsimd_sleef(dfadd_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(3.1415927410125732422f,-8.7422776573475857731e-08f),\n         vneg_vf_vf_advsimd_sleef(r))), r);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef atan2kf_u1_advsimd_sleef(vfloat2_advsimd_sleef y, vfloat2_advsimd_sleef x) {\n  vfloat_advsimd_sleef u;\n  vfloat2_advsimd_sleef s, t;\n  vint2_advsimd_sleef q;\n  vopmask_advsimd_sleef p;\n  vmask_advsimd_sleef r;\n\n  q = vsel_vi2_vf_vf_vi2_vi2_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(0), vcast_vi2_i_advsimd_sleef(-2), vcast_vi2_i_advsimd_sleef(0));\n  p = vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(0));\n  r = vand_vm_vo32_vm_advsimd_sleef(p, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0)));\n  x = vf2setx_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)), r)));\n  x = vf2sety_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)), r)));\n\n  q = vsel_vi2_vf_vf_vi2_vi2_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y), vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(1)), q);\n  p = vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(y));\n  s = vsel_vf2_vo_vf2_vf2_advsimd_sleef(p, dfneg_vf2_vf2_advsimd_sleef(x), y);\n  t = vsel_vf2_vo_vf2_vf2_advsimd_sleef(p, y, x);\n\n  s = dfdiv_vf2_vf2_vf2_advsimd_sleef(s, t);\n  t = dfsqu_vf2_vf2_advsimd_sleef(s);\n  t = dfnormalize_vf2_vf2_advsimd_sleef(t);\n\n  u = vcast_vf_f_advsimd_sleef(-0.00176397908944636583328247f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(0.0107900900766253471374512f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(-0.0309564601629972457885742f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(0.0577365085482597351074219f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(-0.0838950723409652709960938f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(0.109463557600975036621094f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(-0.142626821994781494140625f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(0.199983194470405578613281f));\n\n  t = dfmul_vf2_vf2_vf2_advsimd_sleef(t, dfadd_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.333332866430282592773438f), vmul_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(t))));\n  t = dfmul_vf2_vf2_vf2_advsimd_sleef(s, dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), t));\n  t = dfadd_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(1.5707963705062866211f, -4.3711388286737928865e-08f), vcast_vf_vi2_advsimd_sleef(q)), t);\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_atan2f4_u10advsimd(vfloat_advsimd_sleef y, vfloat_advsimd_sleef x) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(2.9387372783541830947e-39f));\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1 << 24)), x);\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(1 << 24)), y);\n\n  vfloat2_advsimd_sleef d = atan2kf_u1_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), vcast_vf_f_advsimd_sleef(0)), vcast_vf2_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)));\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d));\n\n  r = vmulsign_vf_vf_vf_advsimd_sleef(r, x);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0))), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vf_vf_vf_advsimd_sleef(x, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(y), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.141592653589793238462643383279502884/2), visinf2_vf_vf_vf_advsimd_sleef(x, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0.0f)), vreinterpret_vf_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef((float)3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vreinterpret_vm_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_asinf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0.5f));\n  vfloat_advsimd_sleef x2 = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, d), vmul_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vabs_vf_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5f))), u;\n  vfloat2_advsimd_sleef x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, vcast_vf2_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0)), dfsqrt_vf2_vf_advsimd_sleef(x2));\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1.0f)), vcast_vf2_f_f_advsimd_sleef(0, 0), x);\n\n  u = vcast_vf_f_advsimd_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_advsimd_sleef(u, vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)));\n\n  vfloat2_advsimd_sleef y = dfsub_vf2_vf2_vf_advsimd_sleef(dfsub_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(3.1415927410125732422f/4,-8.7422776573475857731e-08f/4), x), u);\n\n  vfloat_advsimd_sleef r = vsel_vf_vo_vf_vf_advsimd_sleef(o, vadd_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(x)),\n          vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(2)));\n  return vmulsign_vf_vf_vf_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_acosf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0.5f));\n  vfloat_advsimd_sleef x2 = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, d), vmul_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vabs_vf_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5f))), u;\n  vfloat2_advsimd_sleef x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, vcast_vf2_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0)), dfsqrt_vf2_vf_advsimd_sleef(x2));\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1.0f)), vcast_vf2_f_f_advsimd_sleef(0, 0), x);\n\n  u = vcast_vf_f_advsimd_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, x2, vcast_vf_f_advsimd_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_advsimd_sleef(u, vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)));\n\n  vfloat2_advsimd_sleef y = dfsub_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(3.1415927410125732422f/2, -8.7422776573475857731e-08f/2),\n     dfadd_vf2_vf_vf_advsimd_sleef(vmulsign_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), d), vmulsign_vf_vf_vf_advsimd_sleef(u, d)));\n  x = dfadd_vf2_vf2_vf_advsimd_sleef(x, u);\n\n  y = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, y, dfscale_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n\n  y = vsel_vf2_vo_vf2_vf2_advsimd_sleef(vandnot_vo_vo_vo_advsimd_sleef(o, vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0))),\n     dfsub_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(3.1415927410125732422f, -8.7422776573475857731e-08f), y), y);\n\n  return vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(y));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_atanf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef d2 = atan2kf_u1_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(0)), vcast_vf2_f_f_advsimd_sleef(1, 0));\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d2), vf2gety_vf_vf2_advsimd_sleef(d2));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1.570796326794896557998982), r);\n  return vmulsign_vf_vf_vf_advsimd_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_logf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef x, x2, t, m;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(1.0f)), vadd_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(x, x);\n\n  t = vcast_vf_f_advsimd_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.666666686534881591796875f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(2.0f));\n\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, t, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.693147180559945286226764f), vcast_vf_vi2_advsimd_sleef(e)));\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vispinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inff()), x);\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), visnan_vo_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), x);\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(-__builtin_inff()), x);\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_expf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_advsimd_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-1.428606765330187045e-06f), s);\n\n  u = vcast_vf_f_advsimd_sleef(0.000198527617612853646278381);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00139304355252534151077271));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00833336077630519866943359));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.0416664853692054748535156));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.166666671633720397949219));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.5));\n\n  u = vadd_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, s), u, s));\n\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-104)), vreinterpret_vm_vf_advsimd_sleef(u)));\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(100), d), vcast_vf_f_advsimd_sleef(__builtin_inff()), u);\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef expm1fk_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_advsimd_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-1.428606765330187045e-06f), s);\n\n  vfloat_advsimd_sleef s2 = vmul_vf_vf_vf_advsimd_sleef(s, s), s4 = vmul_vf_vf_vf_advsimd_sleef(s2, s2);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef((s4), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.000198527617612853646278381)), (vcast_vf_f_advsimd_sleef(0.00139304355252534151077271)))), (vmla_vf_vf_vf_vf_advsimd_sleef((s2), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.00833336077630519866943359)), (vcast_vf_f_advsimd_sleef(0.0416664853692054748535156)))), (vmla_vf_vf_vf_vf_advsimd_sleef((s), (vcast_vf_f_advsimd_sleef(0.166666671633720397949219)), (vcast_vf_f_advsimd_sleef(0.5)))))));\n\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, s), u, s);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(0)), u,\n         vsub_vf_vf_vf_advsimd_sleef(vldexp2_vf_vf_vi2_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(1)), q), vcast_vf_f_advsimd_sleef(1)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sqrtf4_u35advsimd(vfloat_advsimd_sleef d) { return vsqrt_vf_vf_advsimd_sleef(d); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_cbrtf4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef x, y, q = vcast_vf_f_advsimd_sleef(1.0), t;\n  vint2_advsimd_sleef e, qu, re;\n\n  e = vadd_vi2_vi2_vi2_advsimd_sleef(vilogbk_vi2_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d)), vcast_vi2_i_advsimd_sleef(1));\n  d = vldexp2_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n\n  t = vadd_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(e), vcast_vf_f_advsimd_sleef(6144));\n  qu = vtruncate_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(t, vcast_vf_f_advsimd_sleef(1.0f/3.0f)));\n  re = vtruncate_vi2_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(t, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(qu), vcast_vf_f_advsimd_sleef(3))));\n\n  q = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(re, vcast_vi2_i_advsimd_sleef(1)), vcast_vf_f_advsimd_sleef(1.2599210498948731647672106f), q);\n  q = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(re, vcast_vi2_i_advsimd_sleef(2)), vcast_vf_f_advsimd_sleef(1.5874010519681994747517056f), q);\n  q = vldexp2_vf_vf_vi2_advsimd_sleef(q, vsub_vi2_vi2_vi2_advsimd_sleef(qu, vcast_vi2_i_advsimd_sleef(2048)));\n\n  q = vmulsign_vf_vf_vf_advsimd_sleef(q, d);\n  d = vabs_vf_vf_advsimd_sleef(d);\n\n  x = vcast_vf_f_advsimd_sleef(-0.601564466953277587890625f);\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(2.8208892345428466796875f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(-5.532182216644287109375f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(5.898262500762939453125f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(-3.8095417022705078125f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(2.2241256237030029296875f));\n\n  y = vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, x), x);\n  y = vmul_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(y, vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2.0f / 3.0f), y), vmla_vf_vf_vf_vf_advsimd_sleef(y, x, vcast_vf_f_advsimd_sleef(-1.0f)))), q);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_cbrtf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef x, y, z, t;\n  vfloat2_advsimd_sleef q2 = vcast_vf2_f_f_advsimd_sleef(1, 0), u, v;\n  vint2_advsimd_sleef e, qu, re;\n\n  e = vadd_vi2_vi2_vi2_advsimd_sleef(vilogbk_vi2_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d)), vcast_vi2_i_advsimd_sleef(1));\n  d = vldexp2_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n\n  t = vadd_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(e), vcast_vf_f_advsimd_sleef(6144));\n  qu = vtruncate_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(t, vcast_vf_f_advsimd_sleef(1.0/3.0)));\n  re = vtruncate_vi2_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(t, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(qu), vcast_vf_f_advsimd_sleef(3))));\n\n  q2 = vsel_vf2_vo_vf2_vf2_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(re, vcast_vi2_i_advsimd_sleef(1)), vcast_vf2_f_f_advsimd_sleef(1.2599210739135742188f, -2.4018701694217270415e-08), q2);\n  q2 = vsel_vf2_vo_vf2_vf2_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(re, vcast_vi2_i_advsimd_sleef(2)), vcast_vf2_f_f_advsimd_sleef(1.5874010324478149414f, 1.9520385308169352356e-08), q2);\n\n  q2 = vf2setx_vf2_vf2_vf_advsimd_sleef(q2, vmulsign_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(q2), d));\n  q2 = vf2sety_vf2_vf2_vf_advsimd_sleef(q2, vmulsign_vf_vf_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(q2), d));\n  d = vabs_vf_vf_advsimd_sleef(d);\n\n  x = vcast_vf_f_advsimd_sleef(-0.601564466953277587890625f);\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(2.8208892345428466796875f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(-5.532182216644287109375f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(5.898262500762939453125f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(-3.8095417022705078125f));\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, d, vcast_vf_f_advsimd_sleef(2.2241256237030029296875f));\n\n  y = vmul_vf_vf_vf_advsimd_sleef(x, x); y = vmul_vf_vf_vf_advsimd_sleef(y, y); x = vsub_vf_vf_vf_advsimd_sleef(x, vmul_vf_vf_vf_advsimd_sleef(vmlanp_vf_vf_vf_vf_advsimd_sleef(d, y, x), vcast_vf_f_advsimd_sleef(-1.0 / 3.0)));\n\n  z = x;\n\n  u = dfmul_vf2_vf_vf_advsimd_sleef(x, x);\n  u = dfmul_vf2_vf2_vf2_advsimd_sleef(u, u);\n  u = dfmul_vf2_vf2_vf_advsimd_sleef(u, d);\n  u = dfadd2_vf2_vf2_vf_advsimd_sleef(u, vneg_vf_vf_advsimd_sleef(x));\n  y = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(u), vf2gety_vf_vf2_advsimd_sleef(u));\n\n  y = vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-2.0 / 3.0), y), z);\n  v = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf_vf_advsimd_sleef(z, z), y);\n  v = dfmul_vf2_vf2_vf_advsimd_sleef(v, d);\n  v = dfmul_vf2_vf2_vf2_advsimd_sleef(v, q2);\n  z = vldexp2_vf_vf_vi2_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(v), vf2gety_vf_vf2_advsimd_sleef(v)), vsub_vi2_vi2_vi2_advsimd_sleef(qu, vcast_vi2_i_advsimd_sleef(2048)));\n\n  z = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(__builtin_inff()), vf2getx_vf_vf2_advsimd_sleef(q2)), z);\n  z = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vreinterpret_vf_vm_advsimd_sleef(vsignbit_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(q2))), z);\n\n  return z;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef logkf_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x, x2;\n  vfloat_advsimd_sleef t, m;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), m), dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), m));\n  x2 = dfsqu_vf2_vf2_advsimd_sleef(x);\n\n  t = vcast_vf_f_advsimd_sleef(0.240320354700088500976562);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(x2), vcast_vf_f_advsimd_sleef(0.285112679004669189453125));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(x2), vcast_vf_f_advsimd_sleef(0.400007992982864379882812));\n  vfloat2_advsimd_sleef c = vcast_vf2_f_f_advsimd_sleef(0.66666662693023681640625f, 3.69183861259614332084311e-09f);\n\n  vfloat2_advsimd_sleef s = dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_advsimd_sleef(e));\n\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfscale_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfmul_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(x2, x),\n          dfadd2_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(x2, t), c)));\n  return s;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef logk3f_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef x, x2, t, m;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(1.0f)), vadd_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(x, x);\n\n  t = vcast_vf_f_advsimd_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(0.666666686534881591796875f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(2.0f));\n\n  x = vmla_vf_vf_vf_vf_advsimd_sleef(x, t, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.693147180559945286226764f), vcast_vf_vi2_advsimd_sleef(e)));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_logf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x;\n  vfloat_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n  vfloat2_advsimd_sleef s = dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_advsimd_sleef(e));\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), m), dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x));\n\n  t = vcast_vf_f_advsimd_sleef(+0.3027294874e+0f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.3996108174e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.6666694880e+0f));\n\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfscale_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)), t));\n\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), vf2gety_vf_vf2_advsimd_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vispinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inff()), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), visnan_vo_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(-__builtin_inff()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef expkf_advsimd_sleef(vfloat2_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f));\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n  vfloat2_advsimd_sleef s, t;\n\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(d, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-0.693145751953125f)));\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-1.428606765330187045e-06f)));\n\n  s = dfnormalize_vf2_vf2_advsimd_sleef(s);\n\n  u = vcast_vf_f_advsimd_sleef(0.00136324646882712841033936f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.00836596917361021041870117f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.0416710823774337768554688f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.166665524244308471679688f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(0.499999850988388061523438f));\n\n  t = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfmul_vf2_vf2_vf_advsimd_sleef(dfsqu_vf2_vf2_advsimd_sleef(s), u));\n\n  t = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), t);\n  u = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t), vf2gety_vf_vf2_advsimd_sleef(t));\n  u = vldexp_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-104)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef expk3f_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_advsimd_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-1.428606765330187045e-06f), s);\n\n  u = vcast_vf_f_advsimd_sleef(0.000198527617612853646278381);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00139304355252534151077271));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.00833336077630519866943359));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.0416664853692054748535156));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.166666671633720397949219));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(0.5));\n\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(s, s), u, vadd_vf_vf_vf_advsimd_sleef(s, vcast_vf_f_advsimd_sleef(1.0f)));\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-104)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_powf4_u10advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n\n  vopmask_advsimd_sleef yisint = vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vtruncate_vf_vf_advsimd_sleef(y), y), vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), vcast_vf_f_advsimd_sleef(1 << 24)));\n  vopmask_advsimd_sleef yisodd = vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(y), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), yisint),\n     vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), vcast_vf_f_advsimd_sleef(1 << 24)));\n\n  vfloat_advsimd_sleef result = expkf_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(logkf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x)), y));\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(visnan_vo_vf_advsimd_sleef(result), vcast_vf_f_advsimd_sleef(__builtin_inff()), result);\n\n  result = vmul_vf_vf_vf_advsimd_sleef(result,\n    vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)),\n       vcast_vf_f_advsimd_sleef(1),\n       vsel_vf_vo_vf_vf_advsimd_sleef(yisint, vsel_vf_vo_vf_vf_advsimd_sleef(yisodd, vcast_vf_f_advsimd_sleef(-1.0f), vcast_vf_f_advsimd_sleef(1)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")))));\n\n  vfloat_advsimd_sleef efx = vmulsign_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(1)), y);\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(y),\n       vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(efx, vcast_vf_f_advsimd_sleef(0.0f)),\n          vreinterpret_vm_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(efx, vcast_vf_f_advsimd_sleef(0.0f)),\n                  vcast_vf_f_advsimd_sleef(1.0f),\n                  vcast_vf_f_advsimd_sleef(__builtin_inff()))))),\n       result);\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0.0))),\n       vmulsign_vf_vf_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(vxor_vo_vo_vo_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(y), veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0.0f))),\n              vcast_vf_f_advsimd_sleef(0), vcast_vf_f_advsimd_sleef(__builtin_inff())),\n           vsel_vf_vo_vf_vf_advsimd_sleef(yisodd, x, vcast_vf_f_advsimd_sleef(1))), result);\n\n  result = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vreinterpret_vm_vf_advsimd_sleef(result)));\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)), veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1))), vcast_vf_f_advsimd_sleef(1), result);\n\n  return result;\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fastpowf4_u3500advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef result = expk3f_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(logk3f_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x)), y));\n  vopmask_advsimd_sleef yisint = vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vtruncate_vf_vf_advsimd_sleef(y), y), vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), vcast_vf_f_advsimd_sleef(1 << 24)));\n  vopmask_advsimd_sleef yisodd = vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(y), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)), yisint),\n     vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(y), vcast_vf_f_advsimd_sleef(1 << 24)));\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(x), yisodd), vneg_vf_vf_advsimd_sleef(result), result);\n\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(0), result);\n  result = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(1), result);\n\n  return result;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef expk2f_advsimd_sleef(vfloat2_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f));\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n  vfloat2_advsimd_sleef s, t;\n\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(d, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-0.693145751953125f)));\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(-1.428606765330187045e-06f)));\n\n  u = vcast_vf_f_advsimd_sleef(+0.1980960224e-3f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(+0.1394256484e-2f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(+0.8333456703e-2f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, vf2getx_vf_vf2_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(+0.4166637361e-1f));\n\n  t = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(s, u), vcast_vf_f_advsimd_sleef(+0.166666659414234244790680580464e+0f));\n  t = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(s, t), vcast_vf_f_advsimd_sleef(0.5));\n  t = dfadd2_vf2_vf2_vf2_advsimd_sleef(s, dfmul_vf2_vf2_vf2_advsimd_sleef(dfsqu_vf2_vf2_advsimd_sleef(s), t));\n\n  t = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), t);\n\n  t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vldexp2_vf_vf_vi2_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t), q));\n  t = vf2sety_vf2_vf2_vf_advsimd_sleef(t, vldexp2_vf_vf_vi2_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(t), q));\n\n  t = vf2setx_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-104)), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t)))));\n  t = vf2sety_vf2_vf2_vf_advsimd_sleef(t, vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-104)), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(t)))));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sinhf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef y = vabs_vf_vf_advsimd_sleef(x);\n  vfloat2_advsimd_sleef d = expk2f_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)));\n  d = dfsub_vf2_vf2_vf2_advsimd_sleef(d, dfrec_vf2_vf2_advsimd_sleef(d));\n  y = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(89)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_inff()), y);\n  y = vmulsign_vf_vf_vf_advsimd_sleef(y, x);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_coshf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef y = vabs_vf_vf_advsimd_sleef(x);\n  vfloat2_advsimd_sleef d = expk2f_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)));\n  d = dfadd_vf2_vf2_vf2_advsimd_sleef(d, dfrec_vf2_vf2_advsimd_sleef(d));\n  y = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(89)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_inff()), y);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_tanhf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef y = vabs_vf_vf_advsimd_sleef(x);\n  vfloat2_advsimd_sleef d = expk2f_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)));\n  vfloat2_advsimd_sleef e = dfrec_vf2_vf2_advsimd_sleef(d);\n  d = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd_vf2_vf2_vf2_advsimd_sleef(d, dfneg_vf2_vf2_advsimd_sleef(e)), dfadd_vf2_vf2_vf2_advsimd_sleef(d, e));\n  y = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(8.664339742f)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(1.0f), y);\n  y = vmulsign_vf_vf_vf_advsimd_sleef(y, x);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sinhf4_u35advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef e = expm1fk_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x));\n  vfloat_advsimd_sleef y = vdiv_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(e, vcast_vf_f_advsimd_sleef(2)), vadd_vf_vf_vf_advsimd_sleef(e, vcast_vf_f_advsimd_sleef(1)));\n  y = vmul_vf_vf_vf_advsimd_sleef(y, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5f), e));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(88)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_inff()), y);\n  y = vmulsign_vf_vf_vf_advsimd_sleef(y, x);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_coshf4_u35advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef e = Sleef_expf4_u10advsimd(vabs_vf_vf_advsimd_sleef(x));\n  vfloat_advsimd_sleef y = vmla_vf_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5f), e, vdiv_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5), e));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(88)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_inff()), y);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_tanhf4_u35advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef d = expm1fk_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2), vabs_vf_vf_advsimd_sleef(x)));\n  vfloat_advsimd_sleef y = vdiv_vf_vf_vf_advsimd_sleef(d, vadd_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2), d));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(8.664339742f)),\n        visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(1.0f), y);\n  y = vmulsign_vf_vf_vf_advsimd_sleef(y, x);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef logk2f_advsimd_sleef(vfloat2_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x, x2, m, s;\n  vfloat_advsimd_sleef t;\n  vint2_advsimd_sleef e;\n\n  e = vilogbk_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n\n  m = dfscale_vf2_vf2_vf_advsimd_sleef(d, vpow2i_vf_vi2_advsimd_sleef(vneg_vi2_vi2_advsimd_sleef(e)));\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(-1)), dfadd2_vf2_vf2_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(1)));\n  x2 = dfsqu_vf2_vf2_advsimd_sleef(x);\n\n  t = vcast_vf_f_advsimd_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(x2), vcast_vf_f_advsimd_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(x2), vcast_vf_f_advsimd_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(x2), vcast_vf_f_advsimd_sleef(0.666666686534881591796875f));\n\n  s = dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.69314718246459960938f), vcast_vf_f_advsimd_sleef(-1.904654323148236017e-09f)), vcast_vf_vi2_advsimd_sleef(e));\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfscale_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfmul_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(x2, x), t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_asinhf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef y = vabs_vf_vf_advsimd_sleef(x);\n  vopmask_advsimd_sleef o = vgt_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(1));\n  vfloat2_advsimd_sleef d;\n\n  d = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfrec_vf2_vf_advsimd_sleef(x), vcast_vf2_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0)));\n  d = dfsqrt_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(dfsqu_vf2_vf2_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(1)));\n  d = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfmul_vf2_vf2_vf_advsimd_sleef(d, y), d);\n\n  d = logk2f_advsimd_sleef(dfnormalize_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(d, x)));\n  y = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(18446743523953729536.0)),\n        visnan_vo_vf_advsimd_sleef(y)),\n         vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(__builtin_inff()), x), y);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(-0.0), y);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_acoshf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat2_advsimd_sleef d = logk2f_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(dfsqrt_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1))), dfsqrt_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(-1)))), x));\n  vfloat_advsimd_sleef y = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(18446743523953729536.0)),\n        visnan_vo_vf_advsimd_sleef(y)),\n         vcast_vf_f_advsimd_sleef(__builtin_inff()), y);\n\n  y = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1.0f)), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1.0f)), vreinterpret_vm_vf_advsimd_sleef(y)));\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_atanhf4_u10advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef y = vabs_vf_vf_advsimd_sleef(x);\n  vfloat2_advsimd_sleef d = logk2f_advsimd_sleef(dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), y), dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vneg_vf_vf_advsimd_sleef(y))));\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(1.0)), vreinterpret_vm_vf_advsimd_sleef(vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(1.0)), vcast_vf_f_advsimd_sleef(__builtin_inff()), vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(0.5))))));\n\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vreinterpret_vm_vf_advsimd_sleef(y)));\n  y = vmulsign_vf_vf_vf_advsimd_sleef(y, x);\n  y = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), vreinterpret_vm_vf_advsimd_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_exp2f4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vrint_vf_vf_advsimd_sleef(d), s;\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n\n  s = vsub_vf_vf_vf_advsimd_sleef(d, u);\n\n  u = vcast_vf_f_advsimd_sleef(+0.1535920892e-3);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1339262701e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.9618384764e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.5550347269e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2402264476e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.6931471825e+0));\n\n  u = vfma_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(1));\n\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(vge_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(128)), vcast_vf_f_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-150)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_exp2f4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vrint_vf_vf_advsimd_sleef(d), s;\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n\n  s = vsub_vf_vf_vf_advsimd_sleef(d, u);\n\n  u = vcast_vf_f_advsimd_sleef(+0.1535920892e-3);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1339262701e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.9618384764e-2));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.5550347269e-1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2402264476e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.6931471825e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1000000000e+1));\n\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(vge_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(128)), vcast_vf_f_advsimd_sleef(__builtin_inf()), u);\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-150)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_exp10f4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.3010253906f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-4.605038981e-06f), s);\n\n  u = vcast_vf_f_advsimd_sleef(+0.6802555919e-1);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2078080326e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.5393903852e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1171245337e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2034678698e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2650949001e+1));\n  vfloat2_advsimd_sleef x = dfadd_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(2.3025851249694824219, -3.1705172516493593157e-08), vmul_vf_vf_vf_advsimd_sleef(u, s));\n  u = vf2getx_vf_vf2_advsimd_sleef(dfnormalize_vf2_vf2_advsimd_sleef(dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf2_vf_advsimd_sleef(x, s))));\n\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(38.5318394191036238941387f)), vcast_vf_f_advsimd_sleef(__builtin_inff()), u);\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-50)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_exp10f4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef u = vrint_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint2_advsimd_sleef q = vrint_vi2_vf_advsimd_sleef(u);\n\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-0.3010253906f), d);\n  s = vmla_vf_vf_vf_vf_advsimd_sleef(u, vcast_vf_f_advsimd_sleef(-4.605038981e-06f), s);\n\n  u = vcast_vf_f_advsimd_sleef(+0.2064004987e+0);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.5417877436e+0));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1171286821e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2034656048e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2650948763e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.2302585125e+1));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vcast_vf_f_advsimd_sleef(+0.1000000000e+1));\n\n  u = vldexp2_vf_vf_vi2_advsimd_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(38.5318394191036238941387f)), vcast_vf_f_advsimd_sleef(__builtin_inff()), u);\n  u = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-50)), vreinterpret_vm_vf_advsimd_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_expm1f4_u10advsimd(vfloat_advsimd_sleef a) {\n  vfloat2_advsimd_sleef d = dfadd2_vf2_vf2_vf_advsimd_sleef(expk2f_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0))), vcast_vf_f_advsimd_sleef(-1.0));\n  vfloat_advsimd_sleef x = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(d), vf2gety_vf_vf2_advsimd_sleef(d));\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(88.72283172607421875f)), vcast_vf_f_advsimd_sleef(__builtin_inff()), x);\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(-16.635532333438687426013570f)), vcast_vf_f_advsimd_sleef(-1), x);\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(a), vcast_vf_f_advsimd_sleef(-0.0f), x);\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_log10f4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x;\n  vfloat_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), m), dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x));\n\n  t = vcast_vf_f_advsimd_sleef(+0.1314289868e+0);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef( +0.1735493541e+0));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef( +0.2895309627e+0));\n\n  vfloat2_advsimd_sleef s = dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(0.30103001, -1.432098889e-08), vcast_vf_vi2_advsimd_sleef(e));\n\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfmul_vf2_vf2_vf2_advsimd_sleef(x, vcast_vf2_f_f_advsimd_sleef(0.868588984, -2.170757285e-08)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)), t));\n\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), vf2gety_vf_vf2_advsimd_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vispinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), visnan_vo_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_log2f4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x;\n  vfloat_advsimd_sleef t, m, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), m), dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x));\n\n  t = vcast_vf_f_advsimd_sleef(+0.4374550283e+0f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.5764790177e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.9618012905120f));\n\n  vfloat2_advsimd_sleef s = dfadd2_vf2_vf_vf2_advsimd_sleef(vcast_vf_vi2_advsimd_sleef(e),\n    dfmul_vf2_vf2_vf2_advsimd_sleef(x, vcast_vf2_f_f_advsimd_sleef(2.8853900432586669922, 3.2734474483568488616e-08)));\n\n  s = dfadd2_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)), t));\n\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), vf2gety_vf_vf2_advsimd_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vispinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), visnan_vo_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_log2f4_u35advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef m, t, x, x2;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_advsimd_sleef(d, vneg_vi2_vi2_advsimd_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(1)), vadd_vf_vf_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(1)));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(x, x);\n\n  t = vcast_vf_f_advsimd_sleef(+0.4374088347e+0);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.5764843822e+0));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.9618024230e+0));\n\n  vfloat_advsimd_sleef r = vmla_vf_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x2, x), t,\n         vmla_vf_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(+0.2885390043e+1), vcast_vf_vi2_advsimd_sleef(e)));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vispinf_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), visnan_vo_vf_advsimd_sleef(d)), vcast_vf_f_advsimd_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_log1pf4_u10advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x;\n  vfloat_advsimd_sleef t, m, x2;\n\n  vfloat_advsimd_sleef dp1 = vadd_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1));\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(dp1, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  dp1 = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(dp1, vcast_vf_f_advsimd_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), dp1);\n  vint2_advsimd_sleef e = vilogb2k_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(dp1, vcast_vf_f_advsimd_sleef(1.0f/0.75f)));\n  t = vldexp3_vf_vf_vi2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vneg_vi2_vi2_advsimd_sleef(e));\n  m = vmla_vf_vf_vf_vf_advsimd_sleef(d, t, vsub_vf_vf_vf_advsimd_sleef(t, vcast_vf_f_advsimd_sleef(1)));\n  e = vsel_vi2_vo_vi2_vi2_advsimd_sleef(o, vsub_vi2_vi2_vi2_advsimd_sleef(e, vcast_vi2_i_advsimd_sleef(64)), e);\n  vfloat2_advsimd_sleef s = dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_advsimd_sleef(e));\n\n  x = dfdiv_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(m, vcast_vf_f_advsimd_sleef(0)), dfadd_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2), m));\n  x2 = vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2getx_vf_vf2_advsimd_sleef(x));\n\n  t = vcast_vf_f_advsimd_sleef(+0.3027294874e+0f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.3996108174e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, x2, vcast_vf_f_advsimd_sleef(+0.6666694880e+0f));\n\n  s = dfadd_vf2_vf2_vf2_advsimd_sleef(s, dfscale_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)));\n  s = dfadd_vf2_vf2_vf_advsimd_sleef(s, vmul_vf_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x2, vf2getx_vf_vf2_advsimd_sleef(x)), t));\n\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(s), vf2gety_vf_vf2_advsimd_sleef(s));\n\n  vopmask_advsimd_sleef ocore = vle_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(9.99999968028569247e+37));\n  if(!__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef (ocore)), 1)) r = vsel_vf_vo_vf_vf_advsimd_sleef(ocore, r, Sleef_logf4_u10advsimd(d));\n  r = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), d), vreinterpret_vm_vf_advsimd_sleef(r)));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(-1)), vcast_vf_f_advsimd_sleef(-__builtin_inff()), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-0.0f), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fabsf4_advsimd(vfloat_advsimd_sleef x) { return vabs_vf_vf_advsimd_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_copysignf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) { return vcopysign_vf_vf_vf_advsimd_sleef(x, y); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fmaxf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n\n  return vsel_vf_vo_vf_vf_advsimd_sleef(visnan_vo_vf_advsimd_sleef(y), x, vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(x, y), x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fminf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n\n  return vsel_vf_vo_vf_vf_advsimd_sleef(visnan_vo_vf_advsimd_sleef(y), x, vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(y, x), x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fdimf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef ret = vsub_vf_vf_vf_advsimd_sleef(x, y);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(ret, vcast_vf_f_advsimd_sleef(0)), veq_vo_vf_vf_advsimd_sleef(x, y)), vcast_vf_f_advsimd_sleef(0), ret);\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_truncf4_advsimd(vfloat_advsimd_sleef x) {\n\n  return vtruncate_vf_vf_advsimd_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_floorf4_advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef fr = vsub_vf_vf_vf_advsimd_sleef(x, vcast_vf_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(0)), vadd_vf_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(1.0f)), fr);\n  return vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), vge_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(INT64_C(1) << 23))), x, vcopysign_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, fr), x));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_ceilf4_advsimd(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef fr = vsub_vf_vf_vf_advsimd_sleef(x, vcast_vf_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_advsimd_sleef(vle_vo_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(0)), fr, vsub_vf_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(1.0f)));\n  return vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), vge_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(INT64_C(1) << 23))), x, vcopysign_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, fr), x));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_roundf4_advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef x = vadd_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.5f));\n  vfloat_advsimd_sleef fr = vsub_vf_vf_vf_advsimd_sleef(x, vcast_vf_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(x)));\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vle_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), veq_vo_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(0))), vsub_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1.0f)), x);\n  fr = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(0)), vadd_vf_vf_vf_advsimd_sleef(fr, vcast_vf_f_advsimd_sleef(1.0f)), fr);\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.4999999701976776123f)), vcast_vf_f_advsimd_sleef(0), x);\n  return vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vge_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(INT64_C(1) << 23))), d, vcopysign_vf_vf_vf_advsimd_sleef(vsub_vf_vf_vf_advsimd_sleef(x, fr), d));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_rintf4_advsimd(vfloat_advsimd_sleef d) {\n\n  return vrint_vf_vf_advsimd_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fmaf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y, vfloat_advsimd_sleef z) {\n  return vfma_vf_vf_vf_vf_advsimd_sleef(x, y, z);\n}\n\nSLEEF_INLINE vfloat_advsimd_sleef Sleef_sqrtf4_u05advsimd(vfloat_advsimd_sleef d) {\n  vfloat_advsimd_sleef q, w, x, y, z;\n\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), d);\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(5.2939559203393770e-23f));\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.8889465931478580e+22f)), d);\n  q = vsel_vf_vo_vf_vf_advsimd_sleef(o, vcast_vf_f_advsimd_sleef(7.2759576141834260e-12f), vcast_vf_f_advsimd_sleef(1.0f));\n\n  y = vreinterpret_vf_vi2_advsimd_sleef(vsub_vi2_vi2_vi2_advsimd_sleef(vcast_vi2_i_advsimd_sleef(0x5f3759df), vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(vreinterpret_vi2_vf_advsimd_sleef(d)), 1))));\n\n  x = vmul_vf_vf_vf_advsimd_sleef(d, y); w = vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5), y);\n  y = vfmanp_vf_vf_vf_vf_advsimd_sleef(x, w, vcast_vf_f_advsimd_sleef(0.5));\n  x = vfma_vf_vf_vf_vf_advsimd_sleef(x, y, x); w = vfma_vf_vf_vf_vf_advsimd_sleef(w, y, w);\n  y = vfmanp_vf_vf_vf_vf_advsimd_sleef(x, w, vcast_vf_f_advsimd_sleef(0.5));\n  x = vfma_vf_vf_vf_vf_advsimd_sleef(x, y, x); w = vfma_vf_vf_vf_vf_advsimd_sleef(w, y, w);\n\n  y = vfmanp_vf_vf_vf_vf_advsimd_sleef(x, w, vcast_vf_f_advsimd_sleef(1.5)); w = vadd_vf_vf_vf_advsimd_sleef(w, w);\n  w = vmul_vf_vf_vf_advsimd_sleef(w, y);\n  x = vmul_vf_vf_vf_advsimd_sleef(w, d);\n  y = vfmapn_vf_vf_vf_vf_advsimd_sleef(w, d, x); z = vfmanp_vf_vf_vf_vf_advsimd_sleef(w, x, vcast_vf_f_advsimd_sleef(1));\n\n  z = vfmanp_vf_vf_vf_vf_advsimd_sleef(w, y, z); w = vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5), x);\n  w = vfma_vf_vf_vf_vf_advsimd_sleef(w, z, y);\n  w = vadd_vf_vf_vf_advsimd_sleef(w, x);\n\n  w = vmul_vf_vf_vf_advsimd_sleef(w, q);\n\n  w = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)),\n        veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(__builtin_inff()))), d, w);\n\n  w = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), w);\n\n  return w;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sqrtf4_advsimd(vfloat_advsimd_sleef d) {\n\n  return vsqrt_vf_vf_advsimd_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_hypotf4_u05advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  x = vabs_vf_vf_advsimd_sleef(x);\n  y = vabs_vf_vf_advsimd_sleef(y);\n  vfloat_advsimd_sleef min = vmin_vf_vf_vf_advsimd_sleef(x, y), n = min;\n  vfloat_advsimd_sleef max = vmax_vf_vf_vf_advsimd_sleef(x, y), d = max;\n\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(max, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  n = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(n, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 24)), n);\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 24)), d);\n\n  vfloat2_advsimd_sleef t = dfdiv_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_vf_vf_advsimd_sleef(n, vcast_vf_f_advsimd_sleef(0)), vcast_vf2_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)));\n  t = dfmul_vf2_vf2_vf_advsimd_sleef(dfsqrt_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(dfsqu_vf2_vf2_advsimd_sleef(t), vcast_vf_f_advsimd_sleef(1))), max);\n  vfloat_advsimd_sleef ret = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t), vf2gety_vf_vf2_advsimd_sleef(t));\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(visnan_vo_vf_advsimd_sleef(ret), vcast_vf_f_advsimd_sleef(__builtin_inff()), ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(min, vcast_vf_f_advsimd_sleef(0)), max, ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(__builtin_inff())), veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(__builtin_inff()))), vcast_vf_f_advsimd_sleef(__builtin_inff()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_hypotf4_u35advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  x = vabs_vf_vf_advsimd_sleef(x);\n  y = vabs_vf_vf_advsimd_sleef(y);\n  vfloat_advsimd_sleef min = vmin_vf_vf_vf_advsimd_sleef(x, y);\n  vfloat_advsimd_sleef max = vmax_vf_vf_vf_advsimd_sleef(x, y);\n\n  vfloat_advsimd_sleef t = vdiv_vf_vf_vf_advsimd_sleef(min, max);\n  vfloat_advsimd_sleef ret = vmul_vf_vf_vf_advsimd_sleef(max, vsqrt_vf_vf_advsimd_sleef(vmla_vf_vf_vf_vf_advsimd_sleef(t, t, vcast_vf_f_advsimd_sleef(1))));\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(min, vcast_vf_f_advsimd_sleef(0)), max, ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(__builtin_inff())), veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(__builtin_inff()))), vcast_vf_f_advsimd_sleef(__builtin_inff()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_nextafterf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0), y), x);\n  vint2_advsimd_sleef xi2 = vreinterpret_vi2_vf_advsimd_sleef(x);\n  vopmask_advsimd_sleef c = vxor_vo_vo_vo_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(x), vge_vo_vf_vf_advsimd_sleef(y, x));\n\n  xi2 = vsel_vi2_vo_vi2_vi2_advsimd_sleef(c, vsub_vi2_vi2_vi2_advsimd_sleef(vcast_vi2_i_advsimd_sleef(0), vxor_vi2_vi2_vi2_advsimd_sleef(xi2, vcast_vi2_i_advsimd_sleef((int)(1U << 31)))), xi2);\n\n  xi2 = vsel_vi2_vo_vi2_vi2_advsimd_sleef(vneq_vo_vf_vf_advsimd_sleef(x, y), vsub_vi2_vi2_vi2_advsimd_sleef(xi2, vcast_vi2_i_advsimd_sleef(1)), xi2);\n\n  xi2 = vsel_vi2_vo_vi2_vi2_advsimd_sleef(c, vsub_vi2_vi2_vi2_advsimd_sleef(vcast_vi2_i_advsimd_sleef(0), vxor_vi2_vi2_vi2_advsimd_sleef(xi2, vcast_vi2_i_advsimd_sleef((int)(1U << 31)))), xi2);\n\n  vfloat_advsimd_sleef ret = vreinterpret_vf_vi2_advsimd_sleef(xi2);\n\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(ret, vcast_vf_f_advsimd_sleef(0)), vneq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0))),\n    vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0), x), ret);\n\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), veq_vo_vf_vf_advsimd_sleef(y, vcast_vf_f_advsimd_sleef(0))), y, ret);\n\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(visnan_vo_vf_advsimd_sleef(x), visnan_vo_vf_advsimd_sleef(y)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_frfrexpf4_advsimd(vfloat_advsimd_sleef x) {\n  x = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(1.17549435082228751e-38)), vmul_vf_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 30)), x);\n\n  vmask_advsimd_sleef xm = vreinterpret_vm_vf_advsimd_sleef(x);\n  xm = vand_vm_vm_vm_advsimd_sleef(xm, vcast_vm_i_i_advsimd_sleef(~0x7f800000U, ~0x7f800000U));\n  xm = vor_vm_vm_vm_advsimd_sleef (xm, vcast_vm_i_i_advsimd_sleef( 0x3f000000U, 0x3f000000U));\n\n  vfloat_advsimd_sleef ret = vreinterpret_vf_vm_advsimd_sleef(xm);\n\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(__builtin_inff()), x), ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), x, ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vint2_advsimd_sleef Sleef_expfrexpf4_advsimd(vfloat_advsimd_sleef x) {\n\n  return vcast_vi2_i_advsimd_sleef(0);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vtoward0_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x) {\n  vfloat_advsimd_sleef t = vreinterpret_vf_vi2_advsimd_sleef(vsub_vi2_vi2_vi2_advsimd_sleef(vreinterpret_vi2_vf_advsimd_sleef(x), vcast_vi2_i_advsimd_sleef(1)));\n  return vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(0), t);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vptrunc_vf_vf_advsimd_sleef(vfloat_advsimd_sleef x) {\n\n  return vtruncate_vf_vf_advsimd_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_fmodf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef nu = vabs_vf_vf_advsimd_sleef(x), de = vabs_vf_vf_advsimd_sleef(y), s = vcast_vf_f_advsimd_sleef(1), q;\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(de, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38));\n  nu = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(nu, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 25)), nu);\n  de = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(de, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 25)), de);\n  s = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(s , vcast_vf_f_advsimd_sleef(1.0f / (UINT64_C(1) << 25))), s);\n  vfloat_advsimd_sleef rde = vtoward0_vf_vf_advsimd_sleef(vrec_vf_vf_advsimd_sleef(de));\n  vfloat2_advsimd_sleef r = vcast_vf2_vf_vf_advsimd_sleef(nu, vcast_vf_f_advsimd_sleef(0));\n\n  for(int i=0;i<8;i++) {\n    q = vptrunc_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vtoward0_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)), rde));\n    q = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(3), de), vf2getx_vf_vf2_advsimd_sleef(r)),\n           vge_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), de)),\n    vcast_vf_f_advsimd_sleef(2), q);\n    q = vsel_vf_vo_vf_vf_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2), de), vf2getx_vf_vf2_advsimd_sleef(r)),\n           vge_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), de)),\n    vcast_vf_f_advsimd_sleef(1), q);\n    r = dfnormalize_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf2_advsimd_sleef(r, dfmul_vf2_vf_vf_advsimd_sleef(vptrunc_vf_vf_advsimd_sleef(q), vneg_vf_vf_advsimd_sleef(de))));\n    if (vtestallones_i_vo32_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), de))) break;\n  }\n\n  vfloat_advsimd_sleef ret = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), vf2gety_vf_vf2_advsimd_sleef(r)), s);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), vf2gety_vf_vf2_advsimd_sleef(r)), de), vcast_vf_f_advsimd_sleef(0), ret);\n\n  ret = vmulsign_vf_vf_vf_advsimd_sleef(ret, x);\n\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(nu, de), x, ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(de, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_advsimd_sleef vrintfk2_vf_vf_advsimd_sleef(vfloat_advsimd_sleef d) {\n\n  return vrint_vf_vf_advsimd_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_remainderf4_advsimd(vfloat_advsimd_sleef x, vfloat_advsimd_sleef y) {\n  vfloat_advsimd_sleef n = vabs_vf_vf_advsimd_sleef(x), d = vabs_vf_vf_advsimd_sleef(y), s = vcast_vf_f_advsimd_sleef(1), q;\n  vopmask_advsimd_sleef o = vlt_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.17549435082228751e-38*2));\n  n = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(n, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 25)), n);\n  d = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(UINT64_C(1) << 25)), d);\n  s = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmul_vf_vf_vf_advsimd_sleef(s , vcast_vf_f_advsimd_sleef(1.0f / (UINT64_C(1) << 25))), s);\n  vfloat2_advsimd_sleef r = vcast_vf2_vf_vf_advsimd_sleef(n, vcast_vf_f_advsimd_sleef(0));\n  vfloat_advsimd_sleef rd = vrec_vf_vf_advsimd_sleef(d);\n  vopmask_advsimd_sleef qisodd = vneq_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0), vcast_vf_f_advsimd_sleef(0));\n\n  for(int i=0;i<8;i++) {\n    q = vrintfk2_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), rd));\n    q = vsel_vf_vo_vf_vf_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)), vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(1.5f))), vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1.0f), vf2getx_vf_vf2_advsimd_sleef(r)), q);\n    q = vsel_vf_vo_vf_vf_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)), vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.5f))),\n          vandnot_vo_vo_vo_advsimd_sleef(qisodd, veq_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r)), vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0.5f))))),\n    vcast_vf_f_advsimd_sleef(0.0), q);\n    if (vtestallones_i_vo32_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(q, vcast_vf_f_advsimd_sleef(0)))) break;\n    q = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(q, vneg_vf_vf_advsimd_sleef(d))), vadd_vf_vf_vf_advsimd_sleef(q, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-1), vf2getx_vf_vf2_advsimd_sleef(r))), q);\n    qisodd = vxor_vo_vo_vo_advsimd_sleef(qisodd, vand_vo_vo_vo_advsimd_sleef(veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(q), vcast_vi2_i_advsimd_sleef(1)), vcast_vi2_i_advsimd_sleef(1)),\n       vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(q), vcast_vf_f_advsimd_sleef(1 << 24))));\n    r = dfnormalize_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf2_advsimd_sleef(r, dfmul_vf2_vf_vf_advsimd_sleef(q, vneg_vf_vf_advsimd_sleef(d))));\n  }\n\n  vfloat_advsimd_sleef ret = vmul_vf_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(r), vf2gety_vf_vf2_advsimd_sleef(r)), s);\n  ret = vmulsign_vf_vf_vf_advsimd_sleef(ret, x);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(y), vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), x), ret);\n  ret = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), ret);\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef sinpifk_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, t;\n  vfloat2_advsimd_sleef x, s2;\n\n  u = vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(4.0));\n  vint2_advsimd_sleef q = vtruncate_vi2_vf_advsimd_sleef(u);\n  q = vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vxor_vi2_vi2_vi2_advsimd_sleef(vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(q), 31)), vcast_vi2_i_advsimd_sleef(1))), vcast_vi2_i_advsimd_sleef(~1));\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(2));\n\n  s = vsub_vf_vf_vf_advsimd_sleef(u, vcast_vf_vi2_advsimd_sleef(q));\n  t = s;\n  s = vmul_vf_vf_vf_advsimd_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_advsimd_sleef(t, t);\n\n  u = vsel_vf_vo_f_f_advsimd_sleef(o, -0.2430611801e-7f, +0.3093842054e-6f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vsel_vf_vo_f_f_advsimd_sleef(o, +0.3590577080e-5f, -0.3657307388e-4f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vsel_vf_vo_f_f_advsimd_sleef(o, -0.3259917721e-3f, +0.2490393585e-2f));\n  x = dfadd2_vf2_vf_vf2_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(u, s),\n   vsel_vf2_vo_f_f_f_f_advsimd_sleef(o, 0.015854343771934509277, 4.4940051354032242811e-10,\n         -0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(s2, x),\n    vsel_vf2_vo_f_f_f_f_advsimd_sleef(o, -0.30842512845993041992, -9.0728339030733922277e-09,\n          0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf2_advsimd_sleef(x, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, s2, vcast_vf2_vf_vf_advsimd_sleef(t, vcast_vf_f_advsimd_sleef(0))));\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1)), x);\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  x = vf2setx_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)))));\n  x = vf2sety_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_sinpif4_u05advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x = sinpifk_advsimd_sleef(d);\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visnegzero_vo_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(-0.0), r);\n  r = vreinterpret_vf_vm_advsimd_sleef(vandnot_vm_vo32_vm_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(8e+6f)), vreinterpret_vm_vf_advsimd_sleef(r)));\n  r = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vreinterpret_vm_vf_advsimd_sleef(r)));\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef cospifk_advsimd_sleef(vfloat_advsimd_sleef d) {\n  vopmask_advsimd_sleef o;\n  vfloat_advsimd_sleef u, s, t;\n  vfloat2_advsimd_sleef x, s2;\n\n  u = vmul_vf_vf_vf_advsimd_sleef(d, vcast_vf_f_advsimd_sleef(4.0));\n  vint2_advsimd_sleef q = vtruncate_vi2_vf_advsimd_sleef(u);\n  q = vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vxor_vi2_vi2_vi2_advsimd_sleef(vreinterpretq_s32_u32(vshrq_n_u32(vreinterpretq_u32_s32(q), 31)), vcast_vi2_i_advsimd_sleef(1))), vcast_vi2_i_advsimd_sleef(~1));\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(0));\n\n  s = vsub_vf_vf_vf_advsimd_sleef(u, vcast_vf_vi2_advsimd_sleef(q));\n  t = s;\n  s = vmul_vf_vf_vf_advsimd_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_advsimd_sleef(t, t);\n\n  u = vsel_vf_vo_f_f_advsimd_sleef(o, -0.2430611801e-7f, +0.3093842054e-6f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vsel_vf_vo_f_f_advsimd_sleef(o, +0.3590577080e-5f, -0.3657307388e-4f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, s, vsel_vf_vo_f_f_advsimd_sleef(o, -0.3259917721e-3f, +0.2490393585e-2f));\n  x = dfadd2_vf2_vf_vf2_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(u, s),\n   vsel_vf2_vo_f_f_f_f_advsimd_sleef(o, 0.015854343771934509277, 4.4940051354032242811e-10,\n         -0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(s2, x),\n    vsel_vf2_vo_f_f_f_f_advsimd_sleef(o, -0.30842512845993041992, -9.0728339030733922277e-09,\n          0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf2_advsimd_sleef(x, vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, s2, vcast_vf2_vf_vf_advsimd_sleef(t, vcast_vf_f_advsimd_sleef(0))));\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1)), x);\n\n  o = veq_vo_vi2_vi2_advsimd_sleef(vand_vi2_vi2_vi2_advsimd_sleef(vadd_vi2_vi2_vi2_advsimd_sleef(q, vcast_vi2_i_advsimd_sleef(2)), vcast_vi2_i_advsimd_sleef(4)), vcast_vi2_i_advsimd_sleef(4));\n  x = vf2setx_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)))));\n  x = vf2sety_vf2_vf2_vf_advsimd_sleef(x, vreinterpret_vf_vm_advsimd_sleef(vxor_vm_vm_vm_advsimd_sleef(vand_vm_vo32_vm_advsimd_sleef(o, vreinterpret_vm_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(-0.0))), vreinterpret_vm_vf_advsimd_sleef(vf2gety_vf_vf2_advsimd_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_cospif4_u05advsimd(vfloat_advsimd_sleef d) {\n  vfloat2_advsimd_sleef x = cospifk_advsimd_sleef(d);\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vgt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(d), vcast_vf_f_advsimd_sleef(8e+6f)), vcast_vf_f_advsimd_sleef(1), r);\n  r = vreinterpret_vf_vm_advsimd_sleef(vor_vm_vo32_vm_advsimd_sleef(visinf_vo_vf_advsimd_sleef(d), vreinterpret_vm_vf_advsimd_sleef(r)));\n\n  return r;\n}\n\n  typedef struct {\n    vfloat2_advsimd_sleef a, b;\n  } df2_advsimd_sleef;\n\nstatic df2_advsimd_sleef df2setab_df2_vf2_vf2_advsimd_sleef(vfloat2_advsimd_sleef a, vfloat2_advsimd_sleef b) {\n  df2_advsimd_sleef r = { a, b };\n  return r;\n}\nstatic vfloat2_advsimd_sleef df2geta_vf2_df2_advsimd_sleef(df2_advsimd_sleef d) { return d.a; }\nstatic vfloat2_advsimd_sleef df2getb_vf2_df2_advsimd_sleef(df2_advsimd_sleef d) { return d.b; }\n\nstatic SLEEF_CONST df2_advsimd_sleef gammafk_advsimd_sleef(vfloat_advsimd_sleef a) {\n  vfloat2_advsimd_sleef clc = vcast_vf2_f_f_advsimd_sleef(0, 0), clln = vcast_vf2_f_f_advsimd_sleef(1, 0), clld = vcast_vf2_f_f_advsimd_sleef(1, 0);\n  vfloat2_advsimd_sleef x, y, z;\n  vfloat_advsimd_sleef t, u;\n\n  vopmask_advsimd_sleef otiny = vlt_vo_vf_vf_advsimd_sleef(vabs_vf_vf_advsimd_sleef(a), vcast_vf_f_advsimd_sleef(1e-30f)), oref = vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0.5));\n\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(otiny, vcast_vf2_f_f_advsimd_sleef(0, 0),\n     vsel_vf2_vo_vf2_vf2_advsimd_sleef(oref, dfadd2_vf2_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), vneg_vf_vf_advsimd_sleef(a)),\n           vcast_vf2_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0))));\n\n  vopmask_advsimd_sleef o0 = vand_vo_vo_vo_advsimd_sleef(vle_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(0.5), vf2getx_vf_vf2_advsimd_sleef(x)), vle_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(1.2)));\n  vopmask_advsimd_sleef o2 = vle_vo_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2.3), vf2getx_vf_vf2_advsimd_sleef(x));\n\n  y = dfnormalize_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1)), x));\n  y = dfnormalize_vf2_vf2_advsimd_sleef(dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2)), y));\n\n  vopmask_advsimd_sleef o = vand_vo_vo_vo_advsimd_sleef(o2, vle_vo_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vcast_vf_f_advsimd_sleef(7)));\n  clln = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, y, clln);\n\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o, dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(3)), x);\n  t = vsel_vf_vo_vf_vf_advsimd_sleef(o2, vrec_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x)), vf2getx_vf_vf2_advsimd_sleef(dfnormalize_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(x, vsel_vf_vo_f_f_advsimd_sleef(o0, -1, -2)))));\n\n  u = vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, +0.000839498720672087279971000786, +0.9435157776e+0f, +0.1102489550e-3f);\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, -5.17179090826059219329394422e-05, +0.8670063615e+0f, +0.8160019934e-4f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, -0.000592166437353693882857342347, +0.4826702476e+0f, +0.1528468856e-3f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, +6.97281375836585777403743539e-05, -0.8855129778e-1f, -0.2355068718e-3f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, +0.000784039221720066627493314301, +0.1013825238e+0f, +0.4962242092e-3f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, -0.000229472093621399176949318732, -0.1493408978e+0f, -0.1193488017e-2f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, -0.002681327160493827160473958490, +0.1697509140e+0f, +0.2891599433e-2f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, +0.003472222222222222222175164840, -0.2072454542e+0f, -0.7385451812e-2f));\n  u = vmla_vf_vf_vf_vf_advsimd_sleef(u, t, vsel_vf_vo_vo_f_f_f_advsimd_sleef(o2, o0, +0.083333333333333333335592087900, +0.2705872357e+0f, +0.2058077045e-1f));\n\n  y = dfmul_vf2_vf2_vf2_advsimd_sleef(dfadd2_vf2_vf2_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(-0.5)), logk2f_advsimd_sleef(x));\n  y = dfadd2_vf2_vf2_vf2_advsimd_sleef(y, dfneg_vf2_vf2_advsimd_sleef(x));\n  y = dfadd2_vf2_vf2_vf2_advsimd_sleef(y, vcast_vf2_d_advsimd_sleef(0.91893853320467278056));\n\n  z = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf_vf_advsimd_sleef (u, t), vsel_vf_vo_f_f_advsimd_sleef(o0, -0.400686534596170958447352690395e+0f, -0.673523028297382446749257758235e-1f));\n  z = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(z, t), vsel_vf_vo_f_f_advsimd_sleef(o0, +0.822466960142643054450325495997e+0f, +0.322467033928981157743538726901e+0f));\n  z = dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf2_vf_advsimd_sleef(z, t), vsel_vf_vo_f_f_advsimd_sleef(o0, -0.577215665946766039837398973297e+0f, +0.422784335087484338986941629852e+0f));\n  z = dfmul_vf2_vf2_vf_advsimd_sleef(z, t);\n\n  clc = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o2, y, z);\n\n  clld = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o2, dfadd2_vf2_vf2_vf_advsimd_sleef(dfmul_vf2_vf_vf_advsimd_sleef(u, t), vcast_vf_f_advsimd_sleef(1)), clld);\n\n  y = clln;\n\n  clc = vsel_vf2_vo_vf2_vf2_advsimd_sleef(otiny, vcast_vf2_d_advsimd_sleef(41.58883083359671856503),\n       vsel_vf2_vo_vf2_vf2_advsimd_sleef(oref, dfadd2_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_d_advsimd_sleef(1.1447298858494001639), dfneg_vf2_vf2_advsimd_sleef(clc)), clc));\n  clln = vsel_vf2_vo_vf2_vf2_advsimd_sleef(otiny, vcast_vf2_f_f_advsimd_sleef(1, 0), vsel_vf2_vo_vf2_vf2_advsimd_sleef(oref, clln, clld));\n\n  if (!vtestallones_i_vo32_advsimd_sleef(vnot_vo32_vo32_advsimd_sleef(oref))) {\n    t = vsub_vf_vf_vf_advsimd_sleef(a, vmul_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(INT64_C(1) << 12), vcast_vf_vi2_advsimd_sleef(vtruncate_vi2_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(1.0 / (INT64_C(1) << 12)))))));\n    x = dfmul_vf2_vf2_vf2_advsimd_sleef(clld, sinpifk_advsimd_sleef(t));\n  }\n\n  clld = vsel_vf2_vo_vf2_vf2_advsimd_sleef(otiny, vcast_vf2_vf_vf_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef((INT64_C(1) << 30)*(float)(INT64_C(1) << 30))), vcast_vf_f_advsimd_sleef(0)),\n        vsel_vf2_vo_vf2_vf2_advsimd_sleef(oref, x, y));\n\n  return df2setab_df2_vf2_vf2_advsimd_sleef(clc, dfdiv_vf2_vf2_vf2_advsimd_sleef(clln, clld));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_tgammaf4_u10advsimd(vfloat_advsimd_sleef a) {\n  df2_advsimd_sleef d = gammafk_advsimd_sleef(a);\n  vfloat2_advsimd_sleef y = dfmul_vf2_vf2_vf2_advsimd_sleef(expk2f_advsimd_sleef(df2geta_vf2_df2_advsimd_sleef(d)), df2getb_vf2_df2_advsimd_sleef(d));\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(y));\n  vopmask_advsimd_sleef o;\n\n  o = vor_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(-__builtin_inff())),\n    vand_vo_vo_vo_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), visint_vo_vf_advsimd_sleef(a))),\n     vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(visnumber_vo_vf_advsimd_sleef(a), vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0))), visnan_vo_vf_advsimd_sleef(r)));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(o, vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), r);\n\n  o = vand_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(__builtin_inff())), visnumber_vo_vf_advsimd_sleef(a)),\n      vge_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(-1.17549435082228751e-38))),\n      vor_vo_vo_vo_advsimd_sleef(vor_vo_vo_vo_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), vgt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(36))), visnan_vo_vf_advsimd_sleef(r)));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(o, vmulsign_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(__builtin_inff()), a), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_lgammaf4_u10advsimd(vfloat_advsimd_sleef a) {\n  df2_advsimd_sleef d = gammafk_advsimd_sleef(a);\n  vfloat2_advsimd_sleef y = dfadd2_vf2_vf2_vf2_advsimd_sleef(df2geta_vf2_df2_advsimd_sleef(d), logk2f_advsimd_sleef(dfabs_vf2_vf2_advsimd_sleef(df2getb_vf2_df2_advsimd_sleef(d))));\n  vfloat_advsimd_sleef r = vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(y), vf2gety_vf_vf2_advsimd_sleef(y));\n  vopmask_advsimd_sleef o;\n\n  o = vor_vo_vo_vo_advsimd_sleef(visinf_vo_vf_advsimd_sleef(a),\n     vor_vo_vo_vo_advsimd_sleef(vand_vo_vo_vo_advsimd_sleef(vle_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), visint_vo_vf_advsimd_sleef(a)),\n    vand_vo_vo_vo_advsimd_sleef(visnumber_vo_vf_advsimd_sleef(a), visnan_vo_vf_advsimd_sleef(r))));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(o, vcast_vf_f_advsimd_sleef(__builtin_inff()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef dfmla_vf2_vf_vf2_vf2_advsimd_sleef(vfloat_advsimd_sleef x, vfloat2_advsimd_sleef y, vfloat2_advsimd_sleef z) {\n  return dfadd_vf2_vf2_vf2_advsimd_sleef(z, dfmul_vf2_vf2_vf_advsimd_sleef(y, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef poly2df_b_advsimd_sleef(vfloat_advsimd_sleef x, vfloat2_advsimd_sleef c1, vfloat2_advsimd_sleef c0) { return dfmla_vf2_vf_vf2_vf2_advsimd_sleef(x, c1, c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef poly2df_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef c1, vfloat2_advsimd_sleef c0) { return dfmla_vf2_vf_vf2_vf2_advsimd_sleef(x, vcast_vf2_vf_vf_advsimd_sleef(c1, vcast_vf_f_advsimd_sleef(0)), c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_advsimd_sleef poly4df_advsimd_sleef(vfloat_advsimd_sleef x, vfloat_advsimd_sleef c3, vfloat2_advsimd_sleef c2, vfloat2_advsimd_sleef c1, vfloat2_advsimd_sleef c0) {\n  return dfmla_vf2_vf_vf2_vf2_advsimd_sleef(vmul_vf_vf_vf_advsimd_sleef(x, x), poly2df_advsimd_sleef(x, c3, c2), poly2df_b_advsimd_sleef(x, c1, c0));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_erff4_u10advsimd(vfloat_advsimd_sleef a) {\n  vfloat_advsimd_sleef t, x = vabs_vf_vf_advsimd_sleef(a);\n  vfloat2_advsimd_sleef t2;\n  vfloat_advsimd_sleef x2 = vmul_vf_vf_vf_advsimd_sleef(x, x), x4 = vmul_vf_vf_vf_advsimd_sleef(x2, x2);\n  vopmask_advsimd_sleef o25 = vle_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(2.5));\n\n  if (__builtin_expect(!!(vtestallones_i_vo32_advsimd_sleef(o25)), 1)) {\n\n    t = vmla_vf_vf_vf_vf_advsimd_sleef((x4), (vmla_vf_vf_vf_vf_advsimd_sleef((x), (vcast_vf_f_advsimd_sleef(-0.4360447008e-6)), (vcast_vf_f_advsimd_sleef(+0.6867515367e-5)))), (vmla_vf_vf_vf_vf_advsimd_sleef((x2), (vmla_vf_vf_vf_vf_advsimd_sleef((x), (vcast_vf_f_advsimd_sleef(-0.3045156700e-4)), (vcast_vf_f_advsimd_sleef(+0.9808536561e-4)))), (vmla_vf_vf_vf_vf_advsimd_sleef((x), (vcast_vf_f_advsimd_sleef(+0.2395523916e-3)), (vcast_vf_f_advsimd_sleef(+0.1459901541e-3)))))));\n\n    t2 = poly4df_advsimd_sleef(x, t,\n   vcast_vf2_f_f_advsimd_sleef(0.0092883445322513580322, -2.7863745897025330755e-11),\n   vcast_vf2_f_f_advsimd_sleef(0.042275499552488327026, 1.3461399289988106057e-09),\n   vcast_vf2_f_f_advsimd_sleef(0.070523701608180999756, -3.6616309318707365163e-09));\n    t2 = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), dfmul_vf2_vf2_vf_advsimd_sleef(t2, x));\n    t2 = dfsqu_vf2_vf2_advsimd_sleef(t2);\n    t2 = dfsqu_vf2_vf2_advsimd_sleef(t2);\n    t2 = dfsqu_vf2_vf2_advsimd_sleef(t2);\n    t2 = dfsqu_vf2_vf2_advsimd_sleef(t2);\n    t2 = dfrec_vf2_vf2_advsimd_sleef(t2);\n  } else {\n\n    t = vmla_vf_vf_vf_vf_advsimd_sleef((x4), (vmla_vf_vf_vf_vf_advsimd_sleef((x), ((vsel_vf_vo_f_f_advsimd_sleef(o25, -0.4360447008e-6, -0.1130012848e-6))), ((vsel_vf_vo_f_f_advsimd_sleef(o25, +0.6867515367e-5, +0.4115272986e-5))))), (vmla_vf_vf_vf_vf_advsimd_sleef((x2), (vmla_vf_vf_vf_vf_advsimd_sleef((x), ((vsel_vf_vo_f_f_advsimd_sleef(o25, -0.3045156700e-4, -0.6928304356e-4))), ((vsel_vf_vo_f_f_advsimd_sleef(o25, +0.9808536561e-4, +0.7172692567e-3))))), (vmla_vf_vf_vf_vf_advsimd_sleef((x), ((vsel_vf_vo_f_f_advsimd_sleef(o25, +0.2395523916e-3, -0.5131045356e-2))), ((vsel_vf_vo_f_f_advsimd_sleef(o25, +0.1459901541e-3, +0.2708637156e-1))))))));\n\n    t2 = poly4df_advsimd_sleef(x, t,\n   vsel_vf2_vo_vf2_vf2_advsimd_sleef(o25, vcast_vf2_f_f_advsimd_sleef(0.0092883445322513580322, -2.7863745897025330755e-11),\n         vcast_vf2_f_f_advsimd_sleef(-0.11064319312572479248, 3.7050452777225283007e-09)),\n   vsel_vf2_vo_vf2_vf2_advsimd_sleef(o25, vcast_vf2_f_f_advsimd_sleef(0.042275499552488327026, 1.3461399289988106057e-09),\n         vcast_vf2_f_f_advsimd_sleef(-0.63192230463027954102, -2.0200432585073177859e-08)),\n   vsel_vf2_vo_vf2_vf2_advsimd_sleef(o25, vcast_vf2_f_f_advsimd_sleef(0.070523701608180999756, -3.6616309318707365163e-09),\n         vcast_vf2_f_f_advsimd_sleef(-1.1296638250350952148, 2.5515120196453259252e-08)));\n    t2 = dfmul_vf2_vf2_vf_advsimd_sleef(t2, x);\n    vfloat2_advsimd_sleef s2 = dfadd_vf2_vf_vf2_advsimd_sleef(vcast_vf_f_advsimd_sleef(1), t2);\n    s2 = dfsqu_vf2_vf2_advsimd_sleef(s2);\n    s2 = dfsqu_vf2_vf2_advsimd_sleef(s2);\n    s2 = dfsqu_vf2_vf2_advsimd_sleef(s2);\n    s2 = dfsqu_vf2_vf2_advsimd_sleef(s2);\n    s2 = dfrec_vf2_vf2_advsimd_sleef(s2);\n    t2 = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o25, s2, vcast_vf2_vf_vf_advsimd_sleef(expkf_advsimd_sleef(t2), vcast_vf_f_advsimd_sleef(0)));\n  }\n\n  t2 = dfadd2_vf2_vf2_vf_advsimd_sleef(t2, vcast_vf_f_advsimd_sleef(-1));\n  t2 = vsel_vf2_vo_vf2_vf2_advsimd_sleef(vlt_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(1e-4)), dfmul_vf2_vf2_vf_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(-1.1283792257308959961, 5.8635383422197591097e-08), x), t2);\n\n  vfloat_advsimd_sleef z = vneg_vf_vf_advsimd_sleef(vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(t2), vf2gety_vf_vf2_advsimd_sleef(t2)));\n  z = vsel_vf_vo_vf_vf_advsimd_sleef(vge_vo_vf_vf_advsimd_sleef(x, vcast_vf_f_advsimd_sleef(6)), vcast_vf_f_advsimd_sleef(1), z);\n  z = vsel_vf_vo_vf_vf_advsimd_sleef(visinf_vo_vf_advsimd_sleef(a), vcast_vf_f_advsimd_sleef(1), z);\n  z = vsel_vf_vo_vf_vf_advsimd_sleef(veq_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), vcast_vf_f_advsimd_sleef(0), z);\n  z = vmulsign_vf_vf_vf_advsimd_sleef(z, a);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_advsimd_sleef Sleef_erfcf4_u15advsimd(vfloat_advsimd_sleef a) {\n  vfloat_advsimd_sleef s = a, r = vcast_vf_f_advsimd_sleef(0), t;\n  vfloat2_advsimd_sleef u, d, x;\n  a = vabs_vf_vf_advsimd_sleef(a);\n  vopmask_advsimd_sleef o0 = vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(1.0));\n  vopmask_advsimd_sleef o1 = vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(2.2));\n  vopmask_advsimd_sleef o2 = vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(4.3));\n  vopmask_advsimd_sleef o3 = vlt_vo_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(10.1));\n\n  u = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, vcast_vf2_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0)), dfdiv_vf2_vf2_vf2_advsimd_sleef(vcast_vf2_f_f_advsimd_sleef(1, 0), vcast_vf2_vf_vf_advsimd_sleef(a, vcast_vf_f_advsimd_sleef(0))));\n\n  t = vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(o0, o1, o2, -0.8638041618e-4f, -0.6236977242e-5f, -0.3869504035e+0f, +0.1115344167e+1f);\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(o0, o1, o2, +0.6000166177e-3f, +0.5749821503e-4f, +0.1288077235e+1f, -0.9454904199e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(o0, o1, o2, -0.1665703603e-2f, +0.6002851478e-5f, -0.1816803217e+1f, -0.3667259514e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(o0, o1, o2, +0.1795156277e-3f, -0.2851036377e-2f, +0.1249150872e+1f, +0.7155663371e+0f));\n  t = vmla_vf_vf_vf_vf_advsimd_sleef(t, vf2getx_vf_vf2_advsimd_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_advsimd_sleef(o0, o1, o2, +0.1914106123e-1f, +0.2260518074e-1f, -0.1328857988e+0f, -0.1262947265e-1f));\n\n  d = dfmul_vf2_vf2_vf_advsimd_sleef(u, t);\n  d = dfadd2_vf2_vf2_vf2_advsimd_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.102775359343930288081655368891e+0, -0.105247583459338632253369014063e+0, -0.482365310333045318680618892669e+0, -0.498961546254537647970305302739e+0));\n  d = dfmul_vf2_vf2_vf2_advsimd_sleef(d, u);\n  d = dfadd2_vf2_vf2_vf2_advsimd_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.636619483208481931303752546439e+0, -0.635609463574589034216723775292e+0, -0.134450203224533979217859332703e-2, -0.471199543422848492080722832666e-4));\n  d = dfmul_vf2_vf2_vf2_advsimd_sleef(d, u);\n  d = dfadd2_vf2_vf2_vf2_advsimd_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_advsimd_sleef(o0, o1, o2, -0.112837917790537404939545770596e+1, -0.112855987376668622084547028949e+1, -0.572319781150472949561786101080e+0, -0.572364030327966044425932623525e+0));\n\n  x = dfmul_vf2_vf2_vf_advsimd_sleef(vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, d, vcast_vf2_vf_vf_advsimd_sleef(vneg_vf_vf_advsimd_sleef(a), vcast_vf_f_advsimd_sleef(0))), a);\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, x, dfadd2_vf2_vf2_vf2_advsimd_sleef(x, d));\n\n  x = expk2f_advsimd_sleef(x);\n  x = vsel_vf2_vo_vf2_vf2_advsimd_sleef(o1, x, dfmul_vf2_vf2_vf2_advsimd_sleef(x, u));\n\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(o3, vadd_vf_vf_vf_advsimd_sleef(vf2getx_vf_vf2_advsimd_sleef(x), vf2gety_vf_vf2_advsimd_sleef(x)), vcast_vf_f_advsimd_sleef(0));\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(vsignbit_vo_vf_advsimd_sleef(s), vsub_vf_vf_vf_advsimd_sleef(vcast_vf_f_advsimd_sleef(2), r), r);\n  r = vsel_vf_vo_vf_vf_advsimd_sleef(visnan_vo_vf_advsimd_sleef(s), vcast_vf_f_advsimd_sleef(__builtin_nanf(\"\")), r);\n  return r;\n}\n"
  },
  {
    "path": "eidos/sleef/sleefinline_avx2.h",
    "content": "//   Copyright Naoki Shibata and contributors 2010 - 2025.\n// Distributed under the Boost Software License, Version 1.0.\n//        (See http://www.boost.org/LICENSE_1_0.txt)\n\n// This file is generated by SLEEF 4.0.0\n\n// Only define SLEEF_FLOAT128_IS_IEEEQP on compilers that actually support __float128\n// (GCC on x86_64 Linux, but not Clang/AppleClang)\n#if defined(__GNUC__) && !defined(__clang__) && defined(__SIZEOF_FLOAT128__)\n#define SLEEF_FLOAT128_IS_IEEEQP\n#endif\n/* #undef SLEEF_LONGDOUBLE_IS_IEEEQP */\n\n#ifndef SLEEF_ALWAYS_INLINE\n#if defined (__GNUC__) || defined (__clang__)\n#define SLEEF_ALWAYS_INLINE inline __attribute__((always_inline))\n#elif defined(_MSC_VER)\n#define SLEEF_ALWAYS_INLINE inline __forceinline\n#else\n#define SLEEF_ALWAYS_INLINE inline\n#endif\n#endif\n\n#ifndef SLEEF_INLINE\n#define SLEEF_INLINE static inline\n#endif\n\n#ifndef SLEEF_CONST\n#define SLEEF_CONST\n#endif\n\n#if defined(_MSC_VER) && !defined (__clang__)\n#pragma fp_contract (off)\n#else\n#pragma STDC FP_CONTRACT OFF\n#endif\n\n#ifndef SLEEF_FP_ILOGB0\n#define SLEEF_FP_ILOGB0 ((int)0x80000000)\n#endif\n\n#ifndef SLEEF_FP_ILOGBNAN\n#define SLEEF_FP_ILOGBNAN ((int)2147483647)\n#endif\n\n#define SLEEFINLINE_AVX2_H_INCLUDED\n\n#ifndef __SLEEF_REMPITAB__\n#define __SLEEF_REMPITAB__\nstatic const double Sleef_rempitabdp[] = {\n  0.15915494309189531785, 1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49,\n  0.03415494309189533173, 4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49,\n  0.03415494309189533173, 4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.0029049430918953351999, 5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.496415728504571394e-51,\n  0.00095181809189533563356, 1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762436344e-52,\n  0.00095181809189533563356, 1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762436344e-52,\n  0.00046353684189533574198, 2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.301187206862134399e-54,\n  0.00021939621689533574198, 2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.301187206862134399e-54,\n  9.7325904395335769087e-05, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  3.6290748145335769087e-05, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.7731700203357690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  1.9584727547107690874e-06, -2.0362228529073840241e-22, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  5.1124121898268875627e-08, 8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369025999e-57,\n  2.1321799510573569745e-08, 1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369025999e-57,\n  6.4206383167259151492e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  6.4206383167259151492e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  2.6953480182640010867e-09, -1.3585460269359374382e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57,\n  8.3270286903304384868e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  8.3270286903304384868e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  3.6704158172530459087e-10, 7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59,\n  1.3421093807143501366e-10, 1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.7795616244500218596e-11, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  3.2437010161333667893e-12, -1.452834466126541428e-28, -1.5869767474823787636e-44, -2.6168913164368963837e-61,\n  1.4247116125875099096e-12, 2.5861333686050385673e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61,\n  5.1521691081458187359e-13, 5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  6.0469559928117805118e-14, 6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  3.6261410673097965595e-15, -1.3304005198798645927e-31, -1.7578597149294783985e-47, 8.4432539107728104262e-64,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  7.3427388509295482183e-17, 1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659578102e-65,\n  1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  1.7916237278037667488e-17, 2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  4.0384494702232122736e-18, 1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188129325e-66,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  5.6900251826959904774e-19, 4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67,\n  1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  1.3532164927539732229e-19, -6.4410794381603004826e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  2.6901432026846872871e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  1.3348904870778067446e-20, -4.2254836195018827479e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  6.5726412927436632287e-21, 1.0820844071023395684e-36, 1.7634898158762432635e-52, 3.5887057810247033998e-68,\n  3.1845095037264626247e-21, 3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  1.4904436092178623228e-21, -4.6390169687056261795e-38, -1.1392999419355048437e-54, -4.587677453735884283e-71,\n  6.4341066196356198368e-22, -4.6390169687056261795e-38, -1.1392999419355048437e-54, -4.587677453735884283e-71,\n  2.1989418833641172011e-22, 4.7649378378726728402e-38, 9.3011872068621332399e-54, 1.113250147552460308e-69,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  8.135951522836682362e-24, 6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  1.5185066224124613304e-24, 2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  6.9132600985943383921e-25, 7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73,\n  2.7773570358292009361e-25, -1.3244127270701094468e-41, -2.4695541513869446866e-57, -3.2399200798614356002e-74,\n  7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  7.0940550444663151936e-26, 9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.9241762160098927996e-26, 3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  6.317065088957874881e-27, -3.2976062348358281152e-43, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.317065088957874881e-27, -3.2976062348358281152e-43, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  3.0858908211726098086e-27, 3.8770419025072344914e-43, 7.9392906424978921242e-59, 2.9745456030524896742e-75,\n  1.4703036872799779898e-27, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.625101203336619011e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  2.5861333686050385673e-28, 2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  5.6664945123924856962e-29, 6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.1778471897801070206e-30, 9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  3.0224035688960604996e-30, 2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  1.4446817584540368888e-30, 2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008290615e-78,\n  6.5582085323302525856e-31, 7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639313137e-79,\n  2.6139040062251944343e-31, -1.7578597149294783985e-47, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  6.4175174317266470186e-32, 4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  6.4175174317266470186e-32, 4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371102229e-79,\n  1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659569668e-65, -7.2335760163150273591e-81,\n  1.4871367740953237822e-32, -1.1571307704883330232e-48, -6.7249112515659569668e-65, -7.2335760163150273591e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.5454160968749269937e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  1.0046721413651383112e-33, 2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81,\n  2.3430016361024414106e-34, 4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82,\n  2.3430016361024414106e-34, 4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  4.1707169171520598517e-35, -2.4964157285045710972e-51, -1.866653112309982615e-67, 1.4185069655957361252e-83,\n  1.7633044866680145008e-35, 2.8491136916798196016e-51, 4.0680767287898916022e-67, 1.4185069655957361252e-83,\n  5.595982714259923599e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  5.595982714259923599e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  2.5867171761548675786e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  1.0820844071023395684e-36, 1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085140685e-84,\n  3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  3.2976802257607573031e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  1.4168892644450972904e-37, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  4.7649378378726728402e-38, 9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280944778e-86,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  6.2960434583523738135e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  2.6226236120327253511e-40, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  7.8591368887290111994e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  3.2673620808294506214e-41, 2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.524218473063975309e-90,\n  9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  9.7147467687967058732e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  3.9750282589222551507e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  1.1051690039850297894e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  1.1051690039850297894e-42, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  3.8770419025072344914e-43, 7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257943935e-91,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.8971783383570358633e-44, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  6.5510079543732854985e-45, -2.6168913164368963837e-61, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  9.4581409707401690366e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  2.451648649116083682e-46, 4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94,\n  7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.5355611056488084652e-94,\n  7.0002556871006273225e-47, 1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.5355611056488084652e-94,\n  2.6211979860855749482e-47, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  4.3166913557804827486e-48, 8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95,\n  1.5797802926460750146e-48, 2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  2.1132476107887107169e-49, 8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  4.0267819632970559834e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  1.8885701952232994665e-50, -7.8013829534098555144e-67, -1.1759240463442418271e-82, 2.8738690232659205689e-99,\n  8.1946431118642097069e-51, 1.5937536410989638719e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99,\n  2.8491136916798196016e-51, 4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  1.7634898158762432635e-52, 3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142808004e-99,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  9.3011872068621332399e-54, 1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102,\n  4.0809436324633147776e-54, -4.587677453735884283e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103,\n  1.470821845263904967e-54, -4.587677453735884283e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  1.6576095166419998917e-55, 2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630537605e-103,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  2.6283399642369020339e-57, 5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.145584788913072936e-105,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  7.9392906424978921242e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  3.9565608646667614317e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  1.9651959757511960854e-59, 2.9745456030524891833e-75, 5.969437008257942845e-91, 5.554706987098633963e-107,\n  9.6951353129341363331e-60, 7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108,\n  4.7167230906452229674e-60, 7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108,\n  2.2275169795007668372e-60, 2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108,\n  9.8291392392853877215e-61, -6.5385728340754726503e-77, -1.3520652573660833788e-93, -2.3220403312043059402e-109,\n  3.6061239614242446325e-61, 7.2792968540756372162e-77, 1.3988851821689310822e-92, 1.0451839188820145747e-108,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  4.9461632249367446986e-62, 3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110,\n  1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.535561105648808199e-94, -1.9306041120023063932e-110,\n  1.0567786762735315635e-62, -6.1446417754639301152e-79, -1.535561105648808199e-94, -1.9306041120023063932e-110,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  8.4432539107728090768e-64, 1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514358328e-112,\n  2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  2.3660905534865399025e-64, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.4679971416497210292e-65, -7.2335760163150273591e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  8.7154294504188118783e-66, 1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  3.9676455775389135587e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  1.5937536410989638719e-66, 1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115,\n  4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  4.0680767287898916022e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  1.1007118082399544936e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  1.1007118082399544936e-67, 1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894110579e-116,\n  3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115,\n  3.588705781024702988e-68, 5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115,\n  1.7341027056809927069e-68, 1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418876704e-116,\n  8.0680116800913756637e-69, -2.2809159455312046184e-85, -4.0748824503880445403e-101, -6.3915272253158644628e-117,\n  3.4315039917320989315e-69, -2.2809159455312046184e-85, -4.0748824503880445403e-101, -6.3915272253158644628e-117,\n  1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  1.113250147552460308e-69, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  5.3368668650755071652e-70, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  2.4390495598509592076e-70, 2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119,\n  9.901409072386855505e-71, -2.8859500138942368532e-87, -5.6567402911297190423e-103, -4.6672632026740766185e-119,\n  2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  2.6568658093254848067e-71, 5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  8.4572999356014273536e-72, 1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  8.4572999356014273536e-72, 1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119,\n  3.9294603961880721752e-72, 1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894729832e-121,\n  1.6655406264813940833e-72, 1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894729832e-121,\n  5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  5.3358074162805516304e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  2.5059077041472040156e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  1.0909578480805302081e-73, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  3.8348292004719330442e-74, 4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598455046e-121,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  2.9745456030524891833e-75, 5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122,\n  7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  7.6368645294831185015e-76, 1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  2.1097166542226745549e-76, 4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  7.2792968540756372162e-77, 1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  3.7036201000008285821e-78, 5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251472933e-126,\n  1.5445779612272179051e-78, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  4.6505689184041232695e-79, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  4.6505689184041232695e-79, 8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251472933e-126,\n  1.9517662449371099233e-79, 2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128,\n  6.0236490820360325022e-80, -3.7424672147304925625e-96, -1.784871512364483542e-112, 6.7095375687163151728e-129,\n  6.0236490820360325022e-80, -3.7424672147304925625e-96, -1.784871512364483542e-112, 6.7095375687163151728e-129,\n  2.6501457402022643213e-80, 3.7482149527770239293e-96, 6.5314563001514349095e-112, 9.9039323746573674262e-128,\n  9.6339406928538097998e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.2001823382693912203e-81, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.459625439463388979e-82, 2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  1.4185069655957361252e-83, -7.8369062883735917115e-100, -1.9081236411894107761e-116, -2.1796760241698337334e-132,\n  5.9489775128085131541e-84, 1.0450891972142805974e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132,\n  1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  1.830931441234090934e-84, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  8.0141992334048515034e-85, 1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247800778e-132,\n  2.8666416439368237283e-85, 1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  2.9286284920280941206e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  1.3200167453193350837e-86, 2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136,\n  5.1571087196495574384e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.1355793528776598461e-87, 3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  1.3019701118468578292e-88, -7.5747169634236195447e-105, -2.0152904854894725532e-121, -3.1562414818576682143e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  4.5242184730639744369e-90, 1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852683481e-137,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  5.969437008257942845e-91, 5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534162772e-139,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.0603435429602168369e-91, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  4.4670685979800101779e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  1.3988851821689310822e-92, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  6.3183932821616130831e-93, 1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591188256e-141,\n  2.4831640123977650651e-93, 1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007823264e-142,\n  5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  5.6554937751584084315e-94, -1.9306041120023063932e-110, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  8.6145718795359707834e-95, 7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142,\n  2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  2.62202614552995759e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  1.1238897120284541253e-95, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  3.7482149527770239293e-96, 6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868987041e-145,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  2.8738690232659205689e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  1.0450891972142805974e-99, 1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.3069928418846076386e-100, 3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.5448727249069983612e-148,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.6400545060233297363e-101, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  2.1132026692048600853e-102, -4.6672632026740766185e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  3.2728487032630532648e-103, 5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435652883e-152,\n  1.0404514546648604359e-103, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  1.0404514546648604359e-103, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  4.8235214251531210473e-104, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  2.0330248644053793915e-104, 2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435652883e-152,\n  6.3777658403150887343e-105, -2.0152904854894725532e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  6.3777658403150887343e-105, -2.0152904854894725532e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  2.88964513938041089e-105, 5.7298933442091639924e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153,\n  1.1455847889130727424e-105, 1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153,\n  2.7355461367940366859e-106, -7.8994528064813712419e-123, -2.0037599452814940222e-138, 9.1598554579059548847e-155,\n  2.7355461367940366859e-106, -7.8994528064813712419e-123, -2.0037599452814940222e-138, 9.1598554579059548847e-155,\n  5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155,\n  5.5547069870986327528e-107, 1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.0451839188820145747e-108, 4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  1.9359195088038447797e-109, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  8.7142954880180709975e-110, -4.8867691298577234423e-126, -2.0587960670007819622e-142, -2.8326669474241479263e-158,\n  3.3918456880078814158e-110, 6.931443500908017045e-126, 1.1062055705591186799e-141, 1.1734404793201255869e-157,\n  7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220312367e-159,\n  7.3062078800278780675e-111, 1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220312367e-159,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  6.5314563001514349095e-112, 9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657616072e-160,\n  2.3732923938934761454e-112, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  2.9421044076449630171e-113, 6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  3.4325196623373878948e-114, 9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  1.8395411057335783574e-115, -7.8150389500644475446e-132, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  8.2436437080731844263e-116, 1.4726412753514008951e-131, -3.9681466199873824165e-148, 2.9106774506606945839e-164,\n  3.1677600334418871069e-116, 3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942429241e-163,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  6.2981819612623816536e-117, 6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254779927e-164,\n  3.1257546646178208289e-117, -6.6414926959353515111e-134, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  1.5395410162955400644e-117, -6.6414926959353515111e-134, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  7.4643419213439950602e-118, 1.0969016447485317626e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165,\n  3.4988078005382940294e-118, 2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166,\n  1.5160407401354430737e-118, 2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166,\n  5.2465720993401781599e-119, -3.755176715260116501e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  2.896544483330507019e-120, 3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168,\n  1.3475077173907800538e-120, -3.156241481857667737e-137, -7.0684085473731388916e-153, -3.3573283875161501977e-170,\n  5.7298933442091639924e-121, -3.156241481857667737e-137, -7.0684085473731388916e-153, -3.3573283875161501977e-170,\n  1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  1.8573014293598452896e-121, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  8.8915345064751572143e-122, 1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170,\n  4.0507946129135104481e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  1.6304246661326865276e-122, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  4.2023969274227456735e-123, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  4.2023969274227456735e-123, 6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911825673e-172,\n  1.1769344939467164447e-123, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  1.1769344939467164447e-123, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  4.2056888557770896953e-124, 1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064369683e-172,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  4.2386081393205242443e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  1.8749656131673758844e-125, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  6.931443500908017045e-126, 1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  1.0223371855251471293e-126, 1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174,\n  2.8369889610228834887e-127, 4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176,\n  2.8369889610228834887e-127, 4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176,\n  9.9039323746573674262e-128, -8.6629775332868972816e-145, -1.5987060076657612913e-160, -2.5389576707476506925e-176,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  6.7095375687163138915e-129, 1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.197724948400014906e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  9.3892593260023063019e-130, 9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691155518e-177,\n  2.175994780857201024e-130, 1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  2.175994780857201024e-130, 1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.7267864457092460442e-131, 4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  1.4726412753514008951e-131, -3.9681466199873824165e-148, 2.9106774506606941983e-164, 5.1948630316441296498e-180,\n  3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  3.4556869017247794521e-132, 8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  6.3800543877747317218e-133, 7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795152755e-180,\n  2.8579525590905986764e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165, -1.0696067158221530218e-181,\n  1.0969016447485317626e-133, -5.7828074707888119584e-150, -1.2825052715093464343e-165, -1.0696067158221530218e-181,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  2.1637618757749825688e-134, -8.9490928918944555247e-151, -1.9717385086233606481e-166, 1.3535321672928907047e-182,\n  1.0631050543111905033e-134, 1.5490398016102376505e-150, 3.4549185946116918017e-166, 1.3535321672928907047e-182,\n  5.1277664357929471499e-135, 3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182,\n  2.3761243821334675971e-135, 3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182,\n  1.0003033553037281263e-135, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  3.1239284188885823808e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  1.4041521353514076604e-136, 2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184,\n  5.4426399358282049106e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  1.1431992269852681095e-137, 2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  6.8339049774534147855e-139, 9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328578981e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1602886988632691941e-140, 3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.1062055705591186799e-141, 1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  4.5016298192952031469e-142, -2.8326669474241479263e-158, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  1.2214168761472102282e-142, 8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191,\n  4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  4.0136364036021218058e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  1.9635033141346264592e-143, -1.0134099605688458828e-159, -2.5389576707476506925e-176, -6.2404128071707654958e-193,\n  9.3843676940087855824e-144, 1.2626949989038732076e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191,\n  4.2590349703400483539e-144, 1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896458822e-192,\n  1.6963686085056791706e-144, 1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896458822e-192,\n  4.1503542758849472122e-145, -1.7614040799531193879e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  4.1503542758849472122e-145, -1.7614040799531193879e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  9.4702132359198537748e-146, 1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.856794109153959173e-193,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  1.4618808551874518553e-146, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  4.6083930759590139305e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  2.105789206980137775e-147, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  8.544872724906996972e-148, 1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196,\n  2.2883630524598079723e-148, 2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091032843e-196,\n  2.2883630524598079723e-148, 2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091032843e-196,\n  7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.1067843414450286726e-196,\n  7.2423563434801054878e-149, 1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.1067843414450286726e-196,\n  3.3320377982006123631e-149, 3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198,\n  1.3768785255608653665e-149, 3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198,\n  3.9929888924099219388e-150, -1.9717385086233606481e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.9929888924099219388e-150, -1.9717385086233606481e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  1.5490398016102376505e-150, 3.4549185946116918017e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  3.2706525621039604902e-151, 7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.1571619860435648643e-152, 6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  2.4782675885631257398e-153, -3.3573283875161501977e-170, 3.0568054078295488291e-186, 1.4980560800565462618e-202,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  9.1598554579059548847e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  1.7015147267057481414e-155, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  7.6922213530572229852e-156, -4.5159745404911819927e-172, -4.5870810097328572602e-188, -3.2905064432040069127e-204,\n  3.0307583960570927356e-156, 5.8345524661064358191e-172, 6.9043123899963188689e-188, -3.2905064432040069127e-204,\n  7.0002691755702864582e-157, 6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205,\n  7.0002691755702864582e-157, 6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  1.1734404793201255869e-157, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  4.4508689228885539715e-158, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  8.0910098773220302259e-159, 1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.3321093418096261919e-207,\n  3.5387999583765925506e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.3321093418096261919e-207,\n  1.2626949989038732076e-159, 2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.3321093418096261919e-207,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.2464251916751375716e-160, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  5.3514239183991277695e-161, 6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208,\n  1.7950099192230045857e-161, -1.6991004655691153326e-177, -1.8567941091539589297e-193, -1.8074851186411640793e-209,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  1.6802919634942426156e-163, 2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  2.9106774506606941983e-164, 5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189357559e-211,\n  1.1741471776254777999e-164, 1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756583552e-212,\n  3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  3.0588204110786950436e-165, 3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  8.8815756978467430465e-166, 1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  8.8815756978467430465e-166, 1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214,\n  3.4549185946116918017e-166, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  7.4159004299416557678e-167, 1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  6.3257905089784152346e-168, 3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  2.0862146470760309789e-168, -1.146150630053972131e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  2.0862146470760309789e-168, -1.146150630053972131e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  1.026320681600434562e-168, 1.2072867382105631402e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218,\n  4.9637369886263658882e-169, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  2.3140020749373754342e-169, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  9.8913461809288020723e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.2670088967063259373e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.2670088967063259373e-170, 3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  1.6109245756507072713e-170, -6.2044048008378732802e-187, -5.4322544592823556944e-203, 4.2491789852161138683e-219,\n  7.8288241512289757055e-171, 1.2181824638728806485e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218,\n  3.6886133485899290404e-171, 2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161138683e-219,\n  1.6185079472704052482e-171, 2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161138683e-219,\n  5.8345524661064358191e-172, 6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  6.5928896280762691321e-173, 1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.2381024895275844856e-174, -8.4789520282639751913e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  2.2730883653953564668e-175, 2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190082842e-224,\n  1.0095962991602958391e-175, -6.2404128071707654958e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  3.7785026604276538491e-176, -6.2404128071707654958e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  6.1977249484000140293e-177, 1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578162463e-225,\n  2.2493122414154495675e-177, 2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.7510588792316711745e-178, 3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450500218e-227,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  2.8330093736631818036e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  1.2906606599973359683e-179, -7.4549709281190454638e-196, -1.4481306607622412036e-212, 9.9192633285681635836e-229,\n  5.1948630316441287936e-180, 9.6685396110091013832e-196, 1.7562785002189355449e-211, 1.6821693549018732055e-227,\n  1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756578275e-212, 6.2685154049107876715e-228,\n  1.3389912474795150614e-180, 1.106784341445028435e-196, 3.3045982549756578275e-212, 6.2685154049107876715e-228,\n  3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  3.7502330143836152136e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  1.3403131492807310959e-181, 3.6564932749519464998e-198, 3.7097125405852507464e-214, 2.5658818466966882188e-231,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  1.3535321672928907047e-182, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  6.0043220944823941786e-183, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  2.2388223052591377446e-183, 3.1205762277848031878e-199, -3.3569248349832580936e-217, -1.0577661142165146927e-233,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.5607241064750984115e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  1.2072867382105631402e-184, -1.4832196127821708615e-201, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  3.0568054078295488291e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  1.2181824638728806485e-186, 1.4980560800565460352e-202, 2.6911956484118910092e-218, -5.1336618966962585332e-235,\n  2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161132393e-219, 7.4467067939231424594e-235,\n  2.9887099189454666024e-187, 4.774153170641553462e-203, 4.2491789852161132393e-219, 7.4467067939231424594e-235,\n  6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  6.9043123899963188689e-188, -3.2905064432040069127e-204, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.1586156901317304854e-188, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  4.4040360264865697732e-189, -1.0100405885278530137e-205, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  8.129755890712020335e-190, 9.8339840169166049336e-206, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  3.6409303439428119063e-190, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.3965175705582071936e-190, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  2.7431118386590483722e-191, -1.332109341809626019e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  1.3403538552936701153e-191, 1.7826390804083638359e-207, -9.1795828160190063645e-224, -2.3569545504732004486e-239,\n  6.389748636109812983e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  2.8828536776963681193e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  1.1294061984896456875e-192, 2.2526486929936882202e-208, -5.3441928036578156465e-225, -7.741539335184153052e-241,\n  2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225, 4.2560351759808952526e-241,\n  2.5268245888628466632e-193, 3.0593092910744445285e-209, 5.4622616159087170031e-225, 4.2560351759808952526e-241,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  3.3501523985444386676e-194, 6.2591208621664049475e-210, 5.9034406125450490845e-227, 1.3186893776791012681e-242,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  6.1039071228393547627e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  2.6792050150137250131e-195, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  9.6685396110091013832e-196, 1.7562785002189355449e-211, 1.6821693549018732055e-227, -8.7276385348052817035e-244,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  2.0416567491425607157e-177, 6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  6.7450395650278649168e-179, 6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  5.756447103644822603e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  1.9005753194802080146e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  1.9005753194802080146e-180, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  9.3660737343905436753e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  4.5462340041847754398e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  2.1363141390818913221e-181, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  9.3135420653044926323e-182, -6.1924333305615830735e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  3.2887424025472810002e-182, 7.185309278132283136e-198, -1.9512340798794268979e-214, -3.6162764918921697356e-230,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  2.7634257116867652192e-183, 4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749095611e-233,\n  8.806758170751374203e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  8.806758170751374203e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  4.0998834342223036605e-184, 7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749095611e-233,\n  1.7464460659577689118e-184, 2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749095611e-233,\n  5.697273818255015375e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  5.697273818255015375e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  2.755477107924346286e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.2845787527590117414e-185, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  5.4912957517634446918e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.8140498638501083305e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  1.8140498638501083305e-186, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  8.9473839187177424013e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  4.3508265588260719497e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  2.0525478788802367239e-187, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  9.0340853890731911095e-188, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  3.288388689208603045e-188, -1.6933341491052464293e-204, -4.3478137385944270631e-220, -2.3353910329236990725e-236,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  4.1554033927630885323e-189, -9.8582956929636044137e-206, -1.4280619485269765742e-221, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  5.643429553477207926e-190, 1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237,\n  1.1546040067079994973e-190, 1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239,\n  1.1546040067079994973e-190, 1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  3.2397620015697148712e-192, 3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  1.4863145223629928288e-192, -7.9038076992129241506e-209, -1.609965144193984205e-224, -1.8313007053436627876e-240,\n  6.0959078275963141821e-193, 1.156336993964950812e-208, 2.7126166236326293347e-224, -1.8313007053436627876e-240,\n  1.712289129579509076e-193, 1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  1.712289129579509076e-193, 1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  6.1638445507530779946e-194, -6.0361608463951204924e-210, 1.1003018740995688645e-226, 5.827891678485165325e-243,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  6.8432117823206978686e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  3.418509674495068119e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  1.7061586205822532442e-195, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  8.499830936258458068e-196, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  4.218953301476420881e-196, 4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.029900079464340522e-245,\n  2.0785144840854027628e-196, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  1.008295075389893466e-196, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  4.7318537104213881764e-197, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  2.0563051886826149345e-197, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  7.185309278132283136e-198, -1.9512340798794268979e-214, -3.6162764918921692779e-230, -2.8387319855193022476e-246,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  4.9643797378534984559e-199, -9.4699347169310243473e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  7.8383517263666503337e-200, 1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  2.612671019845610006e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  1.306250843215349634e-200, 2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421728101e-248,\n  6.5304075490021959302e-201, 6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249,\n  3.2643571074265457254e-201, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  1.6313318866387202604e-201, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  8.1481927624480752786e-202, -4.2219277387461470355e-218, -1.753154605289404553e-234, -7.5861268822635538093e-251,\n  4.0656297104785107096e-202, 4.8431832608149701961e-218, 8.3111403472061145651e-234, 1.6001805286092554504e-249,\n  2.0243481844937293316e-202, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  1.0037074215013384159e-202, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  4.9338704000514295811e-203, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  2.3822684925704522921e-203, 3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250,\n  1.1064675388299639308e-203, 2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608782288e-251,\n  4.6856706195971960852e-204, 2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608782288e-251,\n  1.4961682352459748279e-204, -8.0675475439086544798e-221, -3.6970842501441777651e-237, -5.7032870362481275794e-253,\n  1.4961682352459748279e-204, -8.0675475439086544798e-221, -3.6970842501441777651e-237, -5.7032870362481275794e-253,\n  6.9879263915816924805e-205, 9.6377473771091526132e-221, 1.5959741828948633012e-236, 2.7031904319843495713e-252,\n  3.0010484111426663515e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254,\n  1.0076094209231528444e-205, 7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  1.0889925813396166947e-207, 2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256,\n  3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  3.1030547578511949035e-208, -1.609965144193984205e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  1.156336993964950812e-208, 2.7126166236326293347e-224, -1.8313007053436625212e-240, -2.3341145329525059632e-256,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  1.8297811202182925249e-209, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  6.1308251778939023781e-210, 1.1003018740995688645e-226, 5.827891678485165325e-243, -3.1174271110208206547e-259,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  4.7332165749391048364e-212, 4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  2.3568521170701555846e-212, -7.7818310317651142243e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  1.1686698881356804311e-212, 1.8601114328504743806e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  5.7457877366844311816e-213, 5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261,\n  2.7753321643482446169e-213, -1.1860946916976500828e-229, 6.3146909508553973881e-246, 1.2573885592501532045e-261,\n  1.290104378180150675e-213, 2.1117734783360818049e-229, 4.2928382696354204061e-245, -2.8075477999879273582e-261,\n  5.4749048509610403382e-214, 4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501532045e-261,\n  1.7618353855408067201e-214, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  1.7618353855408067201e-214, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  8.3356801918574821257e-215, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  3.6943433600821895879e-215, 5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263,\n  1.3736749441945438342e-215, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  2.1334073625072069974e-216, -9.2331809177749077733e-233, -1.4042876247421726117e-248, -9.9505977179164858712e-265,\n  6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  6.8298960257742791824e-217, 6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  3.2038516259498326923e-217, -1.1817449557784924788e-233, -6.3454186796659920093e-250, -2.6436684620390282645e-267,\n  1.3908294260376086421e-217, 2.8439730252197153919e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267,\n  4.8431832608149701961e-218, 8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  3.1062776103441183191e-219, 7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  2.7343042298126957741e-220, 5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267,\n  9.6377473771091526132e-221, 1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844372114e-268,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  7.8509991660024955813e-222, 1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270,\n  2.318094503184431479e-222, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.318094503184431479e-222, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  9.3486833747991514629e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.4325525462765697993e-223, -1.1429360314275701698e-239, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  7.0351983914592419146e-224, 7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  7.0351983914592419146e-224, 7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539155726e-272,\n  2.7126166236326293347e-224, -1.8313007053436625212e-240, -2.3341145329525056675e-256, -2.0046830753539155726e-272,\n  5.5132573971932232487e-225, 5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273,\n  5.5132573971932232487e-225, 5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  1.1003018740995688645e-226, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  2.560476225709334075e-227, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  2.560476225709334075e-227, 5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.4984059688774601837e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  1.8601114328504743806e-228, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  5.409641648369814791e-229, -3.0299000794643401155e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  2.1117734783360818049e-229, 4.2928382696354204061e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277,\n  4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277,\n  4.6283939331921604413e-230, 6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  5.060587206499956961e-231, 5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580820317e-280,\n  2.4841276986611042098e-231, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  1.1958979447416775482e-231, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  5.5178306778196421733e-232, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  2.2972562930210755192e-232, 2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282,\n  6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  6.8696910062179237095e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  2.8439730252197153919e-233, 3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  8.3111403472061145651e-234, 1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  3.2789928709583552854e-234, 4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  7.6291913283447536617e-235, 2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  1.3390069830350552605e-235, -6.026193929640082176e-252, -7.0535576022338457803e-268, -4.3807022524130141006e-284,\n  5.5273393987134252385e-236, 1.1432574793608780349e-251, 1.2329569415922591084e-267, -4.3807022524130141006e-284,\n  1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284,\n  1.5959741828948633012e-236, 2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284,\n  6.1313287894022281692e-237, 5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006739096e-285,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  1.2171222696290252021e-237, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  6.0284645465737476297e-238, -2.4742181023285720738e-254, -1.2030990169203137715e-270, -9.5347405022956042207e-287,\n  2.9570854717154947523e-238, 4.3456134301905148502e-254, 6.3684349745470443788e-270, -9.5347405022956042207e-287,\n  1.4213959342863689955e-238, 9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956042207e-287,\n  6.5355116557180594664e-239, 9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956042207e-287,\n  2.6962878121452450746e-239, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  7.766758903588374524e-240, 8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  2.9677290991223565342e-240, -2.3341145329525056675e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  5.6821419688934674008e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  2.6827483411022054912e-241, 3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289,\n  1.1830515272065748694e-241, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  4.3320312025875939195e-242, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  5.827891678485165325e-243, -3.117427111020820077e-259, -5.9718623963762788119e-275, 6.1155422068568954053e-291,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  1.1413391350613183311e-243, -5.1586784110844895013e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  5.5552006713333735927e-244, 7.8491179384773690214e-260, -1.9524039360882352712e-276, -2.9779654517181717279e-292,\n  2.6261053316934700345e-244, 1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997740506e-292,\n  1.1615576618735179302e-244, 1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997740506e-292,\n  4.2928382696354204061e-245, -2.8075477999879273582e-261, -1.472095602234059958e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  6.3146909508553973881e-246, 1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294,\n  1.7379794826680480784e-246, 2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294,\n  1.7379794826680480784e-246, 2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294,\n  5.9380161562121075096e-247, -1.2904053011746964278e-263, 8.7279092175580810531e-280, 8.8634899828990930877e-296,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  2.1712682097791944335e-248, 2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150276549e-299,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  3.8349029251851101018e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  1.6001805286092554504e-249, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  4.8281933032132812475e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.0347903074934629333e-250, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  6.3808880963355377617e-251, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  6.3808880963355377617e-251, -2.6436684620390282645e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.8891343516857640937e-251, 5.1095823452235464813e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  1.1432574793608780349e-251, 1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300,\n  2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300,\n  2.7031904319843490867e-252, 2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  5.2084434157824127104e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  2.4805108027747776379e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  1.1165444962709601017e-253, 2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482777461e-301,\n  4.3456134301905148502e-254, 6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  9.3569766393097138822e-255, 2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  8.3218722366085688343e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  2.9938788518280315834e-256, -2.0046830753539152442e-272, -3.4057806738724185961e-288, 2.3458177946667328156e-304,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  3.2988215943776273615e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  1.6338236616337094706e-257, 2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306,\n  8.0132469526175071002e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  3.850752120757712373e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  1.7695047048278150093e-258, 2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306,\n  7.2888099686286655858e-259, 5.581381609158630475e-275, 6.1155422068568946933e-291, 1.0380272777574237546e-306,\n  2.0856914288039227544e-259, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  2.0856914288039227544e-259, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  7.8491179384773690214e-260, -1.9524039360882352712e-276, -2.9779654517181712829e-292, -3.000817432603284506e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  1.345219763696439399e-260, 1.6579848156414234801e-276, 1.0303712682997738281e-292, 1.4493302844111182601e-308,\n  5.3223249184882342185e-261, -1.472095602234059958e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.2573885592501529789e-261, 3.0408903374280139822e-277, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  2.4115446944063306384e-262, 2.202741251392177696e-278, 2.8287088295287585094e-294, -1.0874435234232647519e-310,\n  1.1412520821444306741e-262, -6.1787496089661820348e-279, -3.028042329852615431e-295, -2.182740474438892116e-311,\n  5.0610577601348040988e-263, 7.9243314524777990283e-279, -3.028042329852615431e-295, -2.182740474438892116e-311,\n  1.8853262294800541881e-263, 8.7279092175580810531e-280, 8.8634899828990930877e-296, -9.8167844904532653004e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.9746046415267896827e-264, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  9.8977243486757054781e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  9.8977243486757054781e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  4.9356438320276576408e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.4546035737036337221e-265, -8.6516445844406224413e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  1.2140834445416214873e-265, 1.8893435613692150014e-281, 3.0075895258731974416e-297, -9.8167844904532653004e-314,\n  5.9382337996061564537e-266, 5.1208955146257653156e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  2.8369334767011265554e-266, 5.1208955146257653156e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  1.2862833152486119506e-266, 1.6777604898591683764e-282, -5.0528699238150265939e-299, -1.3288013265921760399e-314,\n  5.1095823452235464813e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  1.2329569415922591084e-267, -4.3807022524130141006e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.638005906844371576e-268, 6.3790946999826013345e-284, -2.7456019707854725967e-300, -2.5539572388808429997e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  2.1511502957481757317e-269, 3.2670891426006735363e-285, 2.4084160842482773317e-301, 5.7350888195772519812e-317,\n  6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  6.3684349745470443788e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  2.5826679788133653036e-270, -9.5347405022956030541e-287, -1.5805886663557401565e-302, 3.6369654387311681856e-319,\n  6.8978448094652555593e-271, 1.1480487920352081009e-286, 7.5257037990230704094e-303, 3.6369654387311681856e-319,\n  6.8978448094652555593e-271, 1.1480487920352081009e-286, 7.5257037990230704094e-303, 3.6369654387311681856e-319,\n  2.1656360647981577662e-271, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  2.1656360647981577662e-271, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  9.825838786313830552e-272, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  3.9105778554799569972e-272, 9.7287370902823839435e-288, 1.6928061833779524157e-303, 3.6369654387311681856e-319,\n  9.5294739006302120482e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  9.5294739006302120482e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.1353977370878701046e-273, -1.2215123283371736879e-289, 6.7342163555358599277e-306, -5.681754927174335258e-322,\n  2.8687869620228451614e-274, -1.9537812801257956865e-290, 1.0380272777574237546e-306, 6.4228533959362050743e-323,\n  0, 0, 0, 0,\n};\n\nstatic const float Sleef_rempitabsp[] = {\n  0.159154892, 5.112411827e-08, 3.626141271e-15, -2.036222915e-22,\n  0.03415493667, 6.420638243e-09, 7.342738037e-17, 8.135951656e-24,\n  0.03415493667, 6.420638243e-09, 7.342738037e-17, 8.135951656e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.002904943191, -9.861969574e-11, -9.839336547e-18, -1.790215892e-24,\n  0.0009518179577, 1.342109202e-10, 1.791623576e-17, 1.518506657e-24,\n  0.0009518179577, 1.342109202e-10, 1.791623576e-17, 1.518506657e-24,\n  0.0004635368241, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  0.0002193961991, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  9.73258866e-05, 1.779561221e-11, 4.038449606e-18, -1.358546052e-25,\n  3.62907449e-05, 3.243700447e-12, 5.690024473e-19, 7.09405479e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  5.773168596e-06, 1.424711477e-12, 1.3532163e-19, 1.92417627e-26,\n  1.958472239e-06, 5.152167755e-13, 1.3532163e-19, 1.92417627e-26,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  5.112411827e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  2.132179588e-08, 3.626141271e-15, -2.036222915e-22, 6.177847236e-30,\n  6.420638243e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  6.420638243e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  2.695347945e-09, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  8.327027956e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  8.327027956e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  3.670415083e-10, 7.342738037e-17, 8.135951656e-24, -1.330400526e-31,\n  1.342109202e-10, 1.791623576e-17, 1.518506361e-24, 2.613904e-31,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  1.779561221e-11, 4.038449606e-18, -1.358545683e-25, -3.443243946e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  3.243700447e-12, 5.690024473e-19, 7.094053557e-26, 1.487136711e-32,\n  1.424711477e-12, 1.3532163e-19, 1.924175961e-26, 2.545416018e-33,\n  5.152167755e-13, 1.3532163e-19, 1.924175961e-26, 2.545416018e-33,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  6.046956013e-14, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  3.626141271e-15, -2.036222915e-22, 6.177846108e-30, 1.082084378e-36,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  7.342738037e-17, 8.135951656e-24, -1.330400526e-31, 6.296048013e-40,\n  1.791623576e-17, 1.518506361e-24, 2.61390353e-31, 4.764937743e-38,\n  1.791623576e-17, 1.518506361e-24, 2.61390353e-31, 4.764937743e-38,\n  4.038449606e-18, -1.358545683e-25, -3.443243946e-32, 6.296048013e-40,\n  4.038449606e-18, -1.358545683e-25, -3.443243946e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  5.690024473e-19, 7.094053557e-26, 1.487136711e-32, 6.296048013e-40,\n  1.3532163e-19, 1.924175961e-26, 2.545415467e-33, 6.296048013e-40,\n  1.3532163e-19, 1.924175961e-26, 2.545415467e-33, 6.296048013e-40,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  2.690143217e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  1.334890502e-20, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  6.572641438e-21, -1.452834402e-28, -6.441077673e-36, -1.764234767e-42,\n  0.05874381959, 1.222115387e-08, 7.693612965e-16, 1.792054435e-22,\n  0.02749382704, 4.77057327e-09, 7.693612965e-16, 1.792054435e-22,\n  0.01186883077, 1.045283415e-09, 3.252721926e-16, 7.332633139e-23,\n  0.00405633077, 1.045283415e-09, 3.252721926e-16, 7.332633139e-23,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  0.000150081818, -2.454155802e-12, 1.161414894e-20, 1.291319272e-27,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  2.801149822e-05, 4.821800945e-12, 8.789757674e-19, 1.208447639e-25,\n  1.275271279e-05, 1.183823005e-12, 1.161414894e-20, 1.291319272e-27,\n  5.12331826e-06, 1.183823005e-12, 1.161414894e-20, 1.291319272e-27,\n  1.308621904e-06, 2.743283031e-13, 1.161414894e-20, 1.291319272e-27,\n  1.308621904e-06, 2.743283031e-13, 1.161414894e-20, 1.291319272e-27,\n  3.549478151e-07, 4.695462769e-14, 1.161414894e-20, 1.291319272e-27,\n  3.549478151e-07, 4.695462769e-14, 1.161414894e-20, 1.291319272e-27,\n  1.165292645e-07, 1.853292503e-14, 4.837885366e-21, 1.291319272e-27,\n  1.165292645e-07, 1.853292503e-14, 4.837885366e-21, 1.291319272e-27,\n  5.69246339e-08, 4.322073705e-15, 1.449754789e-21, 7.962890365e-29,\n  2.712231151e-08, 4.322073705e-15, 1.449754789e-21, 7.962890365e-29,\n  1.222115387e-08, 7.693612965e-16, 1.792054182e-22, 2.91418027e-29,\n  4.77057327e-09, 7.693612965e-16, 1.792054182e-22, 2.91418027e-29,\n  1.045283415e-09, 3.252721926e-16, 7.332632508e-23, 3.898253736e-30,\n  1.045283415e-09, 3.252721926e-16, 7.332632508e-23, 3.898253736e-30,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  1.139611461e-10, 1.996093359e-17, 5.344349223e-25, 1.511644828e-31,\n  5.575349904e-11, 6.083145782e-18, 5.344349223e-25, 1.511644828e-31,\n  2.664967552e-11, -8.557475018e-19, -8.595036458e-26, -2.139883875e-32,\n  1.209775682e-11, 2.61369883e-18, 5.344349223e-25, 1.511644828e-31,\n  4.821800945e-12, 8.789757674e-19, 1.208447639e-25, 3.253064536e-33,\n  1.183823005e-12, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  1.183823005e-12, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  2.743283031e-13, 1.161414894e-20, 1.29131908e-27, 1.715766248e-34,\n  0, 0, 0, 0,\n};\n#endif // #ifndef __SLEEF_REMPITAB__\n\n#if !defined(Sleef_quad_DEFINED)\n#define Sleef_quad_DEFINED\ntypedef struct { uint64_t x, y; } Sleef_uint64_2t;\n#if defined(SLEEF_FLOAT128_IS_IEEEQP)\ntypedef __float128 Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## Q)\n#elif defined(SLEEF_LONGDOUBLE_IS_IEEEQP)\ntypedef long double Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## L)\n#else\ntypedef Sleef_uint64_2t Sleef_quad;\n#endif\n#endif\n\nextern const double Sleef_rempitabdp[];\n\ntypedef __m256i vmask_avx2_sleef;\ntypedef __m256i vopmask_avx2_sleef;\n\ntypedef __m256d vdouble_avx2_sleef;\ntypedef __m128i vint_avx2_sleef;\n\ntypedef __m256 vfloat_avx2_sleef;\ntypedef __m256i vint2_avx2_sleef;\n\ntypedef __m256i vint64_avx2_sleef;\ntypedef __m256i vuint64_avx2_sleef;\n\ntypedef struct {\n  vmask_avx2_sleef x, y;\n} vquad_avx2_sleef;\n\ntypedef vquad_avx2_sleef vargquad_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE int vtestallones_i_vo32_avx2_sleef(vopmask_avx2_sleef g) {\n  return _mm_test_all_ones(_mm_and_si128(_mm256_extractf128_si256(g, 0), _mm256_extractf128_si256(g, 1)));\n}\n\nstatic SLEEF_ALWAYS_INLINE int vtestallones_i_vo64_avx2_sleef(vopmask_avx2_sleef g) {\n  return _mm_test_all_ones(_mm_and_si128(_mm256_extractf128_si256(g, 0), _mm256_extractf128_si256(g, 1)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vcast_vd_d_avx2_sleef(double d) { return _mm256_set1_pd(d); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vreinterpret_vm_vd_avx2_sleef(vdouble_avx2_sleef vd_avx2_sleef) { return _mm256_castpd_si256(vd_avx2_sleef); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vreinterpret_vd_vm_avx2_sleef(vmask_avx2_sleef vm) { return _mm256_castsi256_pd(vm); }\n\nstatic vint2_avx2_sleef vloadu_vi2_p_avx2_sleef(int32_t *p) { return _mm256_loadu_si256((__m256i const *)p); }\nstatic void vstoreu_v_p_vi2_avx2_sleef(int32_t *p, vint2_avx2_sleef v) { _mm256_storeu_si256((__m256i *)p, v); }\nstatic vint_avx2_sleef vloadu_vi_p_avx2_sleef(int32_t *p) { return _mm_loadu_si128((__m128i *)p); }\nstatic void vstoreu_v_p_vi_avx2_sleef(int32_t *p, vint_avx2_sleef v) { _mm_storeu_si128((__m128i *)p, v); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vand_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_and_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vandnot_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_andnot_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vor_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_or_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vxor_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_xor_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vand_vo_vo_vo_avx2_sleef(vopmask_avx2_sleef x, vopmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_and_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vandnot_vo_vo_vo_avx2_sleef(vopmask_avx2_sleef x, vopmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_andnot_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vor_vo_vo_vo_avx2_sleef(vopmask_avx2_sleef x, vopmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_or_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vxor_vo_vo_vo_avx2_sleef(vopmask_avx2_sleef x, vopmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_xor_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vand_vm_vo64_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_and_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vandnot_vm_vo64_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_andnot_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vor_vm_vo64_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_or_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vxor_vm_vo64_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_xor_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vand_vm_vo32_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_and_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vandnot_vm_vo32_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_andnot_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vor_vm_vo32_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_or_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vxor_vm_vo32_vm_avx2_sleef(vopmask_avx2_sleef x, vmask_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_xor_pd(vreinterpret_vd_vm_avx2_sleef(x), vreinterpret_vd_vm_avx2_sleef(y))); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vcast_vo32_vo64_avx2_sleef(vopmask_avx2_sleef o) {\n  return _mm256_permutevar8x32_epi32(o, _mm256_set_epi32(0, 0, 0, 0, 6, 4, 2, 0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vcast_vo64_vo32_avx2_sleef(vopmask_avx2_sleef o) {\n  return _mm256_permutevar8x32_epi32(o, _mm256_set_epi32(3, 3, 2, 2, 1, 1, 0, 0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vcast_vo_i_avx2_sleef(int i) { return _mm256_set1_epi64x(i ? -1 : 0); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vrint_vi_vd_avx2_sleef(vdouble_avx2_sleef vd_avx2_sleef) { return _mm256_cvtpd_epi32(vd_avx2_sleef); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vtruncate_vi_vd_avx2_sleef(vdouble_avx2_sleef vd_avx2_sleef) { return _mm256_cvttpd_epi32(vd_avx2_sleef); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vrint_vd_vd_avx2_sleef(vdouble_avx2_sleef vd_avx2_sleef) { return _mm256_round_pd(vd_avx2_sleef, _MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vrint_vf_vf_avx2_sleef(vfloat_avx2_sleef vd_avx2_sleef) { return _mm256_round_ps(vd_avx2_sleef, _MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vtruncate_vd_vd_avx2_sleef(vdouble_avx2_sleef vd_avx2_sleef) { return _mm256_round_pd(vd_avx2_sleef, _MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vtruncate_vf_vf_avx2_sleef(vfloat_avx2_sleef vf) { return _mm256_round_ps(vf, _MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vcast_vd_vi_avx2_sleef(vint_avx2_sleef vi) { return _mm256_cvtepi32_pd(vi); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vcast_vi_i_avx2_sleef(int i) { return _mm_set1_epi32(i); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcastu_vm_vi_avx2_sleef(vint_avx2_sleef vi) {\n  return _mm256_slli_epi64(_mm256_cvtepi32_epi64(vi), 32);\n}\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vcastu_vi_vm_avx2_sleef(vmask_avx2_sleef vi) {\n  return _mm_or_si128(_mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(_mm256_castsi256_si128(vi)), _mm_set1_ps(0), 0x0d)),\n          _mm_castps_si128(_mm_shuffle_ps(_mm_set1_ps(0), _mm_castsi128_ps(_mm256_extractf128_si256(vi, 1)), 0xd0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcast_vm_i_i_avx2_sleef(int i0, int i1) {\n  return _mm256_set_epi32(i0, i1, i0, i1, i0, i1, i0, i1);\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcast_vm_i64_avx2_sleef(int64_t i) { return _mm256_set1_epi64x(i); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcast_vm_u64_avx2_sleef(uint64_t i) { return _mm256_set1_epi64x((uint64_t)i); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef veq64_vo_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return _mm256_cmpeq_epi64(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vadd64_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return _mm256_add_epi64(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vadd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_add_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsub_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_sub_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmul_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_mul_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vdiv_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_div_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vrec_vd_vd_avx2_sleef(vdouble_avx2_sleef x) { return _mm256_div_pd(_mm256_set1_pd(1), x); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsqrt_vd_vd_avx2_sleef(vdouble_avx2_sleef x) { return _mm256_sqrt_pd(x); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vabs_vd_vd_avx2_sleef(vdouble_avx2_sleef d) { return _mm256_andnot_pd(_mm256_set1_pd(-0.0), d); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vneg_vd_vd_avx2_sleef(vdouble_avx2_sleef d) { return _mm256_xor_pd(_mm256_set1_pd(-0.0), d); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmla_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fmadd_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmlapn_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fmsub_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmlanp_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fnmadd_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmax_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_max_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmin_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_min_pd(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vfma_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fmadd_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vfmapp_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fmadd_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vfmapn_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fmsub_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vfmanp_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fnmadd_pd(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vfmann_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return _mm256_fnmsub_pd(x, y, z); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef veq_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_EQ_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vneq_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_NEQ_UQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vlt_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_LT_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vle_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_LE_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vgt_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_GT_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vge_vo_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(x, y, _CMP_GE_OQ)); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vadd_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_add_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vsub_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_sub_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vneg_vi_vi_avx2_sleef(vint_avx2_sleef e) { return vsub_vi_vi_vi_avx2_sleef(vcast_vi_i_avx2_sleef(0), e); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vand_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_and_si128(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vandnot_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_andnot_si128(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vor_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_or_si128(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vxor_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_xor_si128(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vandnot_vi_vo_vi_avx2_sleef(vopmask_avx2_sleef m, vint_avx2_sleef y) { return _mm_andnot_si128(_mm256_castsi256_si128(m), y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vand_vi_vo_vi_avx2_sleef(vopmask_avx2_sleef m, vint_avx2_sleef y) { return _mm_and_si128(_mm256_castsi256_si128(m), y); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vsll_vi_vi_i_avx2_sleef(vint_avx2_sleef x, int c) { return _mm_slli_epi32(x, c); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vsrl_vi_vi_i_avx2_sleef(vint_avx2_sleef x, int c) { return _mm_srli_epi32(x, c); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vsra_vi_vi_i_avx2_sleef(vint_avx2_sleef x, int c) { return _mm_srai_epi32(x, c); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef veq_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_cmpeq_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vgt_vi_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_cmpgt_epi32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef veq_vo_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm256_castsi128_si256(_mm_cmpeq_epi32(x, y)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vgt_vo_vi_vi_avx2_sleef(vint_avx2_sleef x, vint_avx2_sleef y) { return _mm256_castsi128_si256(_mm_cmpgt_epi32(x, y)); }\n\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vsel_vi_vo_vi_vi_avx2_sleef(vopmask_avx2_sleef m, vint_avx2_sleef x, vint_avx2_sleef y) { return _mm_blendv_epi8(y, x, _mm256_castsi256_si128(m)); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsel_vd_vo_vd_vd_avx2_sleef(vopmask_avx2_sleef o, vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_blendv_pd(y, x, _mm256_castsi256_pd(o)); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsel_vd_vo_d_d_avx2_sleef(vopmask_avx2_sleef o, double v1, double v0) { return _mm256_permutevar_pd(_mm256_set_pd(v1, v0, v1, v0), o); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, vopmask_avx2_sleef o2, double d0, double d1, double d2, double d3) {\n  __m256i v = _mm256_castpd_si256(vsel_vd_vo_vd_vd_avx2_sleef(o0, _mm256_castsi256_pd(_mm256_set_epi32(1, 0, 1, 0, 1, 0, 1, 0)),\n         vsel_vd_vo_vd_vd_avx2_sleef(o1, _mm256_castsi256_pd(_mm256_set_epi32(3, 2, 3, 2, 3, 2, 3, 2)),\n            vsel_vd_vo_vd_vd_avx2_sleef(o2, _mm256_castsi256_pd(_mm256_set_epi32(5, 4, 5, 4, 5, 4, 5, 4)),\n               _mm256_castsi256_pd(_mm256_set_epi32(7, 6, 7, 6, 7, 6, 7, 6))))));\n  return _mm256_castsi256_pd(_mm256_permutevar8x32_epi32(_mm256_castpd_si256(_mm256_set_pd(d3, d2, d1, d0)), v));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsel_vd_vo_vo_d_d_d_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, double d0, double d1, double d2) {\n  return vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o1, d0, d1, d2, d2);\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visinf_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(vabs_vd_vd_avx2_sleef(d), _mm256_set1_pd(__builtin_inf()), _CMP_EQ_OQ));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vispinf_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(d, _mm256_set1_pd(__builtin_inf()), _CMP_EQ_OQ));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visminf_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(d, _mm256_set1_pd(-__builtin_inf()), _CMP_EQ_OQ));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visnan_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vreinterpret_vm_vd_avx2_sleef(_mm256_cmp_pd(d, d, _CMP_NEQ_UQ));\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vload_vd_p_avx2_sleef(const double *ptr) { return _mm256_load_pd(ptr); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vloadu_vd_p_avx2_sleef(const double *ptr) { return _mm256_loadu_pd(ptr); }\n\nstatic SLEEF_ALWAYS_INLINE void vstore_v_p_vd_avx2_sleef(double *ptr, vdouble_avx2_sleef v) { _mm256_store_pd(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vd_avx2_sleef(double *ptr, vdouble_avx2_sleef v) { _mm256_storeu_pd(ptr, v); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vgather_vd_p_vi_avx2_sleef(const double *ptr, vint_avx2_sleef vi) { return _mm256_i32gather_pd(ptr, vi, 8); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vcast_vi2_vm_avx2_sleef(vmask_avx2_sleef vm) { return vm; }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcast_vm_vi2_avx2_sleef(vint2_avx2_sleef vi) { return vi; }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vrint_vi2_vf_avx2_sleef(vfloat_avx2_sleef vf) { return vcast_vi2_vm_avx2_sleef(_mm256_cvtps_epi32(vf)); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vtruncate_vi2_vf_avx2_sleef(vfloat_avx2_sleef vf) { return vcast_vi2_vm_avx2_sleef(_mm256_cvttps_epi32(vf)); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vcast_vf_vi2_avx2_sleef(vint2_avx2_sleef vi) { return _mm256_cvtepi32_ps(vcast_vm_vi2_avx2_sleef(vi)); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vcast_vf_f_avx2_sleef(float f) { return _mm256_set1_ps(f); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vcast_vi2_i_avx2_sleef(int i) { return _mm256_set1_epi32(i); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vreinterpret_vm_vf_avx2_sleef(vfloat_avx2_sleef vf) { return _mm256_castps_si256(vf); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vreinterpret_vf_vm_avx2_sleef(vmask_avx2_sleef vm) { return _mm256_castsi256_ps(vm); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vreinterpret_vf_vi2_avx2_sleef(vint2_avx2_sleef vi) { return vreinterpret_vf_vm_avx2_sleef(vcast_vm_vi2_avx2_sleef(vi)); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vreinterpret_vi2_vf_avx2_sleef(vfloat_avx2_sleef vf) { return vcast_vi2_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf)); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vadd_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_add_ps(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsub_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_sub_ps(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmul_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_mul_ps(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vdiv_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_div_ps(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vrec_vf_vf_avx2_sleef(vfloat_avx2_sleef x) { return vdiv_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), x); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsqrt_vf_vf_avx2_sleef(vfloat_avx2_sleef x) { return _mm256_sqrt_ps(x); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vabs_vf_vf_avx2_sleef(vfloat_avx2_sleef f) { return vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)), vreinterpret_vm_vf_avx2_sleef(f))); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vneg_vf_vf_avx2_sleef(vfloat_avx2_sleef d) { return vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)), vreinterpret_vm_vf_avx2_sleef(d))); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmla_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fmadd_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmlapn_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fmsub_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmlanp_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fnmadd_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmax_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_max_ps(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmin_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_min_ps(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vfma_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fmadd_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vfmapp_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fmadd_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vfmapn_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fmsub_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vfmanp_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fnmadd_ps(x, y, z); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vfmann_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return _mm256_fnmsub_ps(x, y, z); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef veq_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_EQ_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vneq_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_NEQ_UQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vlt_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_LT_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vle_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_LE_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vgt_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_GT_OQ)); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vge_vo_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vreinterpret_vm_vf_avx2_sleef(_mm256_cmp_ps(x, y, _CMP_GE_OQ)); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vadd_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_add_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vsub_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_sub_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vneg_vi2_vi2_avx2_sleef(vint2_avx2_sleef e) { return vsub_vi2_vi2_vi2_avx2_sleef(vcast_vi2_i_avx2_sleef(0), e); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vand_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_and_si256(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vandnot_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_andnot_si256(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vor_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_or_si256(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vxor_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_xor_si256(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vand_vi2_vo_vi2_avx2_sleef(vopmask_avx2_sleef x, vint2_avx2_sleef y) { return vand_vi2_vi2_vi2_avx2_sleef(vcast_vi2_vm_avx2_sleef(x), y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vandnot_vi2_vo_vi2_avx2_sleef(vopmask_avx2_sleef x, vint2_avx2_sleef y) { return vandnot_vi2_vi2_vi2_avx2_sleef(vcast_vi2_vm_avx2_sleef(x), y); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vsll_vi2_vi2_i_avx2_sleef(vint2_avx2_sleef x, int c) { return _mm256_slli_epi32(x, c); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vsrl_vi2_vi2_i_avx2_sleef(vint2_avx2_sleef x, int c) { return _mm256_srli_epi32(x, c); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vsra_vi2_vi2_i_avx2_sleef(vint2_avx2_sleef x, int c) { return _mm256_srai_epi32(x, c); }\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef veq_vo_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_cmpeq_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vgt_vo_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_cmpgt_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef veq_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_cmpeq_epi32(x, y); }\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vgt_vi2_vi2_vi2_avx2_sleef(vint2_avx2_sleef x, vint2_avx2_sleef y) { return _mm256_cmpgt_epi32(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vint2_avx2_sleef vsel_vi2_vo_vi2_vi2_avx2_sleef(vopmask_avx2_sleef m, vint2_avx2_sleef x, vint2_avx2_sleef y) {\n  return _mm256_blendv_epi8(y, x, m);\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsel_vf_vo_vf_vf_avx2_sleef(vopmask_avx2_sleef o, vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_blendv_ps(y, x, _mm256_castsi256_ps(o)); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vsel_vf_vo_f_f_avx2_sleef(vopmask_avx2_sleef o, float v1, float v0) {\n  return vsel_vf_vo_vf_vf_avx2_sleef(o, vcast_vf_f_avx2_sleef(v1), vcast_vf_f_avx2_sleef(v0));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsel_vf_vo_vo_f_f_f_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, float d0, float d1, float d2) {\n  return vsel_vf_vo_vf_vf_avx2_sleef(o0, vcast_vf_f_avx2_sleef(d0), vsel_vf_vo_f_f_avx2_sleef(o1, d1, d2));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, vopmask_avx2_sleef o2, float d0, float d1, float d2, float d3) {\n  return vsel_vf_vo_vf_vf_avx2_sleef(o0, vcast_vf_f_avx2_sleef(d0), vsel_vf_vo_vf_vf_avx2_sleef(o1, vcast_vf_f_avx2_sleef(d1), vsel_vf_vo_f_f_avx2_sleef(o2, d2, d3)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visinf_vo_vf_avx2_sleef(vfloat_avx2_sleef d) { return veq_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inff())); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vispinf_vo_vf_avx2_sleef(vfloat_avx2_sleef d) { return veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(__builtin_inff())); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visminf_vo_vf_avx2_sleef(vfloat_avx2_sleef d) { return veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-__builtin_inff())); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef visnan_vo_vf_avx2_sleef(vfloat_avx2_sleef d) { return vneq_vo_vf_vf_avx2_sleef(d, d); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vload_vf_p_avx2_sleef(const float *ptr) { return _mm256_load_ps(ptr); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vloadu_vf_p_avx2_sleef(const float *ptr) { return _mm256_loadu_ps(ptr); }\n\nstatic SLEEF_ALWAYS_INLINE void vstore_v_p_vf_avx2_sleef(float *ptr, vfloat_avx2_sleef v) { _mm256_store_ps(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vstoreu_v_p_vf_avx2_sleef(float *ptr, vfloat_avx2_sleef v) { _mm256_storeu_ps(ptr, v); }\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vgather_vf_p_vi2_avx2_sleef(const float *ptr, vint2_avx2_sleef vi2) { return _mm256_i32gather_ps(ptr, vi2, 4); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vposneg_vd_vd_avx2_sleef(vdouble_avx2_sleef d) { return vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(_mm256_set_pd( -0.0, +0.0, -0.0, +0.0 )))); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vnegpos_vd_vd_avx2_sleef(vdouble_avx2_sleef d) { return vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(_mm256_set_pd( +0.0, -0.0, +0.0, -0.0 )))); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vposneg_vf_vf_avx2_sleef(vfloat_avx2_sleef d) { return vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(d), vreinterpret_vm_vf_avx2_sleef(_mm256_set_ps( -0.0f, +0.0f, -0.0f, +0.0f, -0.0f, +0.0f, -0.0f, +0.0f )))); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vnegpos_vf_vf_avx2_sleef(vfloat_avx2_sleef d) { return vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(d), vreinterpret_vm_vf_avx2_sleef(_mm256_set_ps( +0.0f, -0.0f, +0.0f, -0.0f, +0.0f, -0.0f, +0.0f, -0.0f )))); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vsubadd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return _mm256_addsub_pd(x, y); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vsubadd_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return _mm256_addsub_ps(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vmlsubadd_vd_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) { return vmla_vd_vd_vd_vd_avx2_sleef(x, y, vnegpos_vd_vd_avx2_sleef(z)); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vmlsubadd_vf_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) { return vmla_vf_vf_vf_vf_avx2_sleef(x, y, vnegpos_vf_vf_avx2_sleef(z)); }\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vrev21_vd_vd_avx2_sleef(vdouble_avx2_sleef d0) { return _mm256_shuffle_pd(d0, d0, (0 << 3) | (1 << 2) | (0 << 1) | (1 << 0)); }\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vreva2_vd_vd_avx2_sleef(vdouble_avx2_sleef d0) { d0 = _mm256_permute2f128_pd(d0, d0, 1); return _mm256_shuffle_pd(d0, d0, (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0)); }\n\nstatic SLEEF_ALWAYS_INLINE void vstream_v_p_vd_avx2_sleef(double *ptr, vdouble_avx2_sleef v) { _mm256_stream_pd(ptr, v); }\nstatic SLEEF_ALWAYS_INLINE void vscatter2_v_p_i_i_vd_avx2_sleef(double *ptr, int offset, int step, vdouble_avx2_sleef v) {\n  _mm_store_pd(&ptr[(offset + step * 0)*2], _mm256_extractf128_pd(v, 0));\n  _mm_store_pd(&ptr[(offset + step * 1)*2], _mm256_extractf128_pd(v, 1));\n}\n\nstatic SLEEF_ALWAYS_INLINE void vsscatter2_v_p_i_i_vd_avx2_sleef(double *ptr, int offset, int step, vdouble_avx2_sleef v) {\n  _mm_stream_pd(&ptr[(offset + step * 0)*2], _mm256_extractf128_pd(v, 0));\n  _mm_stream_pd(&ptr[(offset + step * 1)*2], _mm256_extractf128_pd(v, 1));\n}\n\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vrev21_vf_vf_avx2_sleef(vfloat_avx2_sleef d0) { return _mm256_shuffle_ps(d0, d0, (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0)); }\nstatic SLEEF_ALWAYS_INLINE vfloat_avx2_sleef vreva2_vf_vf_avx2_sleef(vfloat_avx2_sleef d0) { d0 = _mm256_permute2f128_ps(d0, d0, 1); return _mm256_shuffle_ps(d0, d0, (1 << 6) | (0 << 4) | (3 << 2) | (2 << 0)); }\n\nstatic SLEEF_ALWAYS_INLINE void vstream_v_p_vf_avx2_sleef(float *ptr, vfloat_avx2_sleef v) { _mm256_stream_ps(ptr, v); }\n\nstatic SLEEF_ALWAYS_INLINE void vscatter2_v_p_i_i_vf_avx2_sleef(float *ptr, int offset, int step, vfloat_avx2_sleef v) {\n  _mm_storel_pd((double *)(ptr+(offset + step * 0)*2), _mm_castsi128_pd(_mm_castps_si128(_mm256_extractf128_ps(v, 0))));\n  _mm_storeh_pd((double *)(ptr+(offset + step * 1)*2), _mm_castsi128_pd(_mm_castps_si128(_mm256_extractf128_ps(v, 0))));\n  _mm_storel_pd((double *)(ptr+(offset + step * 2)*2), _mm_castsi128_pd(_mm_castps_si128(_mm256_extractf128_ps(v, 1))));\n  _mm_storeh_pd((double *)(ptr+(offset + step * 3)*2), _mm_castsi128_pd(_mm_castps_si128(_mm256_extractf128_ps(v, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE void vsscatter2_v_p_i_i_vf_avx2_sleef(float *ptr, int offset, int step, vfloat_avx2_sleef v) { vscatter2_v_p_i_i_vf_avx2_sleef(ptr, offset, step, v); }\n\nstatic vquad_avx2_sleef loadu_vq_p_avx2_sleef(void *p) {\n  vquad_avx2_sleef vq;\n  memcpy(&vq, p, (1 << 2) * 16);\n  return vq;\n}\n\nstatic SLEEF_ALWAYS_INLINE vquad_avx2_sleef cast_vq_aq_avx2_sleef(vargquad_avx2_sleef aq) {\n  vquad_avx2_sleef vq;\n  memcpy(&vq, &aq, (1 << 2) * 16);\n  return vq;\n}\n\nstatic SLEEF_ALWAYS_INLINE vargquad_avx2_sleef cast_aq_vq_avx2_sleef(vquad_avx2_sleef vq) {\n  vargquad_avx2_sleef aq;\n  memcpy(&aq, &vq, (1 << 2) * 16);\n  return aq;\n}\n\nstatic SLEEF_ALWAYS_INLINE int vtestallzeros_i_vo64_avx2_sleef(vopmask_avx2_sleef g) {\n  return _mm_movemask_epi8(_mm_or_si128(_mm256_extractf128_si256(g, 0), _mm256_extractf128_si256(g, 1))) == 0;\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vsel_vm_vo64_vm_vm_avx2_sleef(vopmask_avx2_sleef o, vmask_avx2_sleef x, vmask_avx2_sleef y) { return _mm256_blendv_epi8(y, x, o); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vsub64_vm_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return _mm256_sub_epi64(x, y); }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vneg64_vm_vm_avx2_sleef(vmask_avx2_sleef x) { return _mm256_sub_epi64(vcast_vm_i_i_avx2_sleef(0, 0), x); }\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vgt64_vo_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return _mm256_cmpgt_epi64(x, y); }\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vcast_vm_vi_avx2_sleef(vint_avx2_sleef vi) { return _mm256_cvtepi32_epi64(vi); }\nstatic SLEEF_ALWAYS_INLINE vint_avx2_sleef vcast_vi_vm_avx2_sleef(vmask_avx2_sleef vm) {\n  return _mm_or_si128(_mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(_mm256_castsi256_si128(vm)), _mm_set1_ps(0), 0x08)),\n          _mm_castps_si128(_mm_shuffle_ps(_mm_set1_ps(0), _mm_castsi128_ps(_mm256_extractf128_si256(vm, 1)), 0x80)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vreinterpret_vm_vi64_avx2_sleef(vint64_avx2_sleef v) { return v; }\nstatic SLEEF_ALWAYS_INLINE vint64_avx2_sleef vreinterpret_vi64_vm_avx2_sleef(vmask_avx2_sleef m) { return m; }\nstatic SLEEF_ALWAYS_INLINE vmask_avx2_sleef vreinterpret_vm_vu64_avx2_sleef(vuint64_avx2_sleef v) { return v; }\nstatic SLEEF_ALWAYS_INLINE vuint64_avx2_sleef vreinterpret_vu64_vm_avx2_sleef(vmask_avx2_sleef m) { return m; }\n\ntypedef struct {\n  vdouble_avx2_sleef x, y;\n} vdouble2_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vd2getx_vd_vd2_avx2_sleef(vdouble2_avx2_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vd2gety_vd_vd2_avx2_sleef(vdouble2_avx2_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vd2setxy_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { vdouble2_avx2_sleef v; v.x = x; v.y = y; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vd2setx_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef v, vdouble_avx2_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vd2sety_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef v, vdouble_avx2_sleef d) { v.y = d; return v; }\n\ntypedef struct {\n  double x, y;\n} double2_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST double2_avx2_sleef dd_avx2_sleef(double h, double l) {\n  double2_avx2_sleef ret = { h, l };\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vupper_vd_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vreinterpret_vd_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vcast_vm_i_i_avx2_sleef(0xffffffff, 0xf8000000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vcast_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef h, vdouble_avx2_sleef l) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(h, l);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vcast_vd2_d_d_avx2_sleef(double h, double l) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(h), vcast_vd_d_avx2_sleef(l));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vcast_vd2_d2_avx2_sleef(double2_avx2_sleef dd_avx2_sleef) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(dd_avx2_sleef.x), vcast_vd_d_avx2_sleef(dd_avx2_sleef.y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vsel_vd2_vo_vd2_vd2_avx2_sleef(vopmask_avx2_sleef m, vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(m, vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y)),\n       vsel_vd_vo_vd_vd_avx2_sleef(m, vd2gety_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef vsel_vd2_vo_d_d_d_d_avx2_sleef(vopmask_avx2_sleef o, double x1, double y1, double x0, double y0) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_d_d_avx2_sleef(o, x1, x0),\n       vsel_vd_vo_d_d_avx2_sleef(o, y1, y0));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vadd_vd_3vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2) {\n  return vadd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vadd_vd_4vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3) {\n  return vadd_vd_3vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vadd_vd_5vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3, vdouble_avx2_sleef v4) {\n  return vadd_vd_4vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vadd_vd_6vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3, vdouble_avx2_sleef v4, vdouble_avx2_sleef v5) {\n  return vadd_vd_5vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vadd_vd_7vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3, vdouble_avx2_sleef v4, vdouble_avx2_sleef v5, vdouble_avx2_sleef v6) {\n  return vadd_vd_6vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(v0, v1), v2, v3, v4, v5, v6);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vsub_vd_3vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2) {\n  return vsub_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vsub_vd_4vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3) {\n  return vsub_vd_3vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vsub_vd_5vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3, vdouble_avx2_sleef v4) {\n  return vsub_vd_4vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vsub_vd_6vd_avx2_sleef(vdouble_avx2_sleef v0, vdouble_avx2_sleef v1, vdouble_avx2_sleef v2, vdouble_avx2_sleef v3, vdouble_avx2_sleef v4, vdouble_avx2_sleef v5) {\n  return vsub_vd_5vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddneg_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x) {\n  return vcast_vd2_vd_vd_avx2_sleef(vneg_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)), vneg_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddabs_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x) {\n  return vcast_vd2_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)),\n    vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)),\n         vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)),\n         vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddnormalize_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef t) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), vd2gety_vd_vd2_avx2_sleef(t));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), s), vd2gety_vd_vd2_avx2_sleef(t)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddscale_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef d, vdouble_avx2_sleef s) {\n  return vd2setxy_vd2_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), s), vmul_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(d), s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddscale_vd2_vd2_d_avx2_sleef(vdouble2_avx2_sleef d, double s) { return ddscale_vd2_vd2_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(s)); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd2_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(x, y);\n  vdouble_avx2_sleef v = vsub_vd_vd_vd_avx2_sleef(s, x);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, vsub_vd_vd_vd_avx2_sleef(s, v)), vsub_vd_vd_vd_avx2_sleef(y, v)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_3vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), s), y, vd2gety_vd_vd2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsub_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), s), y), vd2gety_vd_vd2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd2_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), y);\n  vdouble_avx2_sleef v = vsub_vd_vd_vd_avx2_sleef(s, vd2getx_vd_vd2_avx2_sleef(x));\n  vdouble_avx2_sleef w = vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vsub_vd_vd_vd_avx2_sleef(s, v)), vsub_vd_vd_vd_avx2_sleef(y, v));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(w, vd2gety_vd_vd2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd_vd2_vd_vd2_avx2_sleef(vdouble_avx2_sleef x, vdouble2_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(x, vd2getx_vd_vd2_avx2_sleef(y));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_3vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, s), vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd2_vd2_vd_vd2_avx2_sleef(vdouble_avx2_sleef x, vdouble2_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(x, vd2getx_vd_vd2_avx2_sleef(y));\n  vdouble_avx2_sleef v = vsub_vd_vd_vd_avx2_sleef(s, x);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, vsub_vd_vd_vd_avx2_sleef(s, v)),\n          vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), v)), vd2gety_vd_vd2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_4vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), s), vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddadd2_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n  vdouble_avx2_sleef s = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y));\n  vdouble_avx2_sleef v = vsub_vd_vd_vd_avx2_sleef(s, vd2getx_vd_vd2_avx2_sleef(x));\n  vdouble_avx2_sleef t = vadd_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vsub_vd_vd_vd_avx2_sleef(s, v)), vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), v));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vadd_vd_vd_vd_avx2_sleef(t, vadd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsub_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n\n  vdouble_avx2_sleef s = vsub_vd_vd_vd_avx2_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vsub_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsub_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n\n  vdouble_avx2_sleef s = vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y));\n  vdouble_avx2_sleef t = vsub_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), s);\n  t = vsub_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(y));\n  t = vadd_vd_vd_vd_avx2_sleef(t, vd2gety_vd_vd2_avx2_sleef(x));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vsub_vd_vd_vd_avx2_sleef(t, vd2gety_vd_vd2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef dddiv_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef n, vdouble2_avx2_sleef d) {\n  vdouble_avx2_sleef t = vrec_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d));\n  vdouble_avx2_sleef s = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(n), t);\n  vdouble_avx2_sleef u = vfmapn_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(n), s);\n  vdouble_avx2_sleef v = vfmanp_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(d), t, vfmanp_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), t, vcast_vd_d_avx2_sleef(1)));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vfma_vd_vd_vd_vd_avx2_sleef(s, v, vfma_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(n), t, u)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddmul_vd2_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vmul_vd_vd_vd_avx2_sleef(x, y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vfmapn_vd_vd_vd_vd_avx2_sleef(x, y, s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsqu_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x) {\n  vdouble_avx2_sleef s = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vfma_vd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x)), vd2gety_vd_vd2_avx2_sleef(x), vfmapn_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x), s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddmul_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n  vdouble_avx2_sleef s = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vfma_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(y), vfma_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y), vfmapn_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y), s))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef ddmul_vd_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y) {\n  return vfma_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y), vfma_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y), vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef ddsqu_vd_vd2_avx2_sleef(vdouble2_avx2_sleef x) {\n  return vfma_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x), vadd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x)), vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddmul_vd2_vd2_vd_avx2_sleef(vdouble2_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef s = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), y);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vfma_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x), y, vfmapn_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), y, s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddrec_vd2_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef s = vrec_vd_vd_avx2_sleef(d);\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(s, vfmanp_vd_vd_vd_vd_avx2_sleef(d, s, vcast_vd_d_avx2_sleef(1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddrec_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef d) {\n  vdouble_avx2_sleef s = vrec_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d));\n  return vd2setxy_vd2_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(s, vfmanp_vd_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(d), s, vfmanp_vd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), s, vcast_vd_d_avx2_sleef(1)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsqrt_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef d) {\n  vdouble_avx2_sleef t = vsqrt_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)));\n  return ddscale_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd2_avx2_sleef(d, ddmul_vd2_vd_vd_avx2_sleef(t, t)), ddrec_vd2_vd_avx2_sleef(t)), vcast_vd_d_avx2_sleef(0.5));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddsqrt_vd2_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef t = vsqrt_vd_vd_avx2_sleef(d);\n  return ddscale_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd2_avx2_sleef(d, ddmul_vd2_vd_vd_avx2_sleef(t, t)), ddrec_vd2_vd_avx2_sleef(t)), vcast_vd_d_avx2_sleef(0.5));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddmla_vd2_vd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef x, vdouble2_avx2_sleef y, vdouble2_avx2_sleef z) {\n  return ddadd_vd2_vd2_vd2_avx2_sleef(z, ddmul_vd2_vd2_vd2_avx2_sleef(x, y));\n}\n\ntypedef struct {\n  vdouble_avx2_sleef x, y, z;\n} vdouble3_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vd3getx_vd_vd3_avx2_sleef(vdouble3_avx2_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vd3gety_vd_vd3_avx2_sleef(vdouble3_avx2_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vd3getz_vd_vd3_avx2_sleef(vdouble3_avx2_sleef v) { return v.z; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef vd3setxyz_vd3_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) {\n  vdouble3_avx2_sleef v = { x, y, z };\n  return v;\n}\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef vd3setx_vd3_vd3_vd_avx2_sleef(vdouble3_avx2_sleef v, vdouble_avx2_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef vd3sety_vd3_vd3_vd_avx2_sleef(vdouble3_avx2_sleef v, vdouble_avx2_sleef d) { v.y = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef vd3setz_vd3_vd3_vd_avx2_sleef(vdouble3_avx2_sleef v, vdouble_avx2_sleef d) { v.z = d; return v; }\n\ntypedef struct {\n  vdouble2_avx2_sleef a, b;\n} dd2_avx2_sleef;\n\nstatic dd2_avx2_sleef dd2setab_dd2_vd2_vd2_avx2_sleef(vdouble2_avx2_sleef a, vdouble2_avx2_sleef b) {\n  dd2_avx2_sleef r = { a, b };\n  return r;\n}\nstatic vdouble2_avx2_sleef dd2geta_vd2_dd2_avx2_sleef(dd2_avx2_sleef d) { return d.a; }\nstatic vdouble2_avx2_sleef dd2getb_vd2_dd2_avx2_sleef(dd2_avx2_sleef d) { return d.b; }\n\ntypedef struct {\n  vmask_avx2_sleef e;\n  vdouble3_avx2_sleef d3;\n} tdx_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef tdxgete_vm_tdx_avx2_sleef(tdx_avx2_sleef t) { return t.e; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef tdxgetd3_vd3_tdx_avx2_sleef(tdx_avx2_sleef t) { return t.d3; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef tdxgetd3x_vd_tdx_avx2_sleef(tdx_avx2_sleef t) { return t.d3.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef tdxgetd3y_vd_tdx_avx2_sleef(tdx_avx2_sleef t) { return t.d3.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef tdxgetd3z_vd_tdx_avx2_sleef(tdx_avx2_sleef t) { return t.d3.z; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsete_tdx_tdx_vm_avx2_sleef(tdx_avx2_sleef t, vmask_avx2_sleef e) { t.e = e; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsetd3_tdx_tdx_vd3_avx2_sleef(tdx_avx2_sleef t, vdouble3_avx2_sleef d3) { t.d3 = d3; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsetx_tdx_tdx_vd_avx2_sleef(tdx_avx2_sleef t, vdouble_avx2_sleef x) { t.d3.x = x; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsety_tdx_tdx_vd_avx2_sleef(tdx_avx2_sleef t, vdouble_avx2_sleef y) { t.d3.y = y; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsetz_tdx_tdx_vd_avx2_sleef(tdx_avx2_sleef t, vdouble_avx2_sleef z) { t.d3.z = z; return t; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsetxyz_tdx_tdx_vd_vd_vd_avx2_sleef(tdx_avx2_sleef t, vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) {\n  t.d3 = (vdouble3_avx2_sleef) { x, y, z };\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxseted3_tdx_vm_vd3_avx2_sleef(vmask_avx2_sleef e, vdouble3_avx2_sleef d3) { return (tdx_avx2_sleef) { e, d3 }; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdx_avx2_sleef tdxsetexyz_tdx_vm_vd_vd_vd_avx2_sleef(vmask_avx2_sleef e, vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) {\n  return (tdx_avx2_sleef) { e, (vdouble3_avx2_sleef) { x, y, z } };\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vqgetx_vm_vq_avx2_sleef(vquad_avx2_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vqgety_vm_vq_avx2_sleef(vquad_avx2_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef vqsetxy_vq_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return (vquad_avx2_sleef) { x, y }; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef vqsetx_vq_vq_vm_avx2_sleef(vquad_avx2_sleef v, vmask_avx2_sleef x) { v.x = x; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef vqsety_vq_vq_vm_avx2_sleef(vquad_avx2_sleef v, vmask_avx2_sleef y) { v.y = y; return v; }\n\ntypedef struct {\n  vdouble_avx2_sleef d;\n  vint_avx2_sleef i;\n} di_t_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef digetd_vd_di_avx2_sleef(di_t_avx2_sleef d) { return d.d; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef digeti_vi_di_avx2_sleef(di_t_avx2_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST di_t_avx2_sleef disetdi_di_vd_vi_avx2_sleef(vdouble_avx2_sleef d, vint_avx2_sleef i) {\n  di_t_avx2_sleef r = { d, i };\n  return r;\n}\n\ntypedef struct {\n  vdouble2_avx2_sleef dd_avx2_sleef;\n  vint_avx2_sleef i;\n} ddi_t_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddigetdd_vd2_ddi_avx2_sleef(ddi_t_avx2_sleef d) { return d.dd_avx2_sleef; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef ddigeti_vi_ddi_avx2_sleef(ddi_t_avx2_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_avx2_sleef ddisetddi_ddi_vd2_vi_avx2_sleef(vdouble2_avx2_sleef v, vint_avx2_sleef i) {\n  ddi_t_avx2_sleef r = { v, i };\n  return r;\n}\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_avx2_sleef ddisetdd_ddi_ddi_vd2_avx2_sleef(ddi_t_avx2_sleef ddi_avx2_sleef, vdouble2_avx2_sleef v) {\n  ddi_avx2_sleef.dd_avx2_sleef = v;\n  return ddi_avx2_sleef;\n}\n\ntypedef struct {\n  vdouble3_avx2_sleef td_avx2_sleef;\n  vint_avx2_sleef i;\n} tdi_t_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble3_avx2_sleef tdigettd_vd3_tdi_avx2_sleef(tdi_t_avx2_sleef d) { return d.td_avx2_sleef; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef tdigetx_vd_tdi_avx2_sleef(tdi_t_avx2_sleef d) { return d.td_avx2_sleef.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef tdigeti_vi_tdi_avx2_sleef(tdi_t_avx2_sleef d) { return d.i; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST tdi_t_avx2_sleef tdisettdi_tdi_vd3_vi_avx2_sleef(vdouble3_avx2_sleef v, vint_avx2_sleef i) {\n  tdi_t_avx2_sleef r = { v, i };\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visnegzero_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return veq64_vo_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visnumber_vo_vd_avx2_sleef(vdouble_avx2_sleef x) {\n  return vandnot_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), veq_vo_vd_vd_avx2_sleef(x, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visnonfinite_vo_vd_avx2_sleef(vdouble_avx2_sleef x) {\n  return veq64_vo_vm_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(x), vcast_vm_i64_avx2_sleef(INT64_C(0x7ff0000000000000))), vcast_vm_i64_avx2_sleef(INT64_C(0x7ff0000000000000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vsignbit_vm_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef vsignbit_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return veq64_vo_vm_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vclearlsb_vd_vd_i_avx2_sleef(vdouble_avx2_sleef d, int n) {\n  return vreinterpret_vd_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vcast_vm_u64_avx2_sleef((~UINT64_C(0)) << n)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vtoward0_vd_vd_avx2_sleef(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef t = vreinterpret_vd_vm_avx2_sleef(vadd64_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(x), vcast_vm_i64_avx2_sleef(-1)));\n  return vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(0), t);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vmulsign_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  return vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(x), vsignbit_vm_vd_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vsign_vd_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1.0), d);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vorsign_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  return vreinterpret_vd_vm_avx2_sleef(vor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(x), vsignbit_vm_vd_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vcopysign_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  return vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vandnot_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)), vreinterpret_vm_vd_avx2_sleef(x)),\n       vand_vm_vm_vm_avx2_sleef (vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)), vreinterpret_vm_vd_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vtruncate2_vd_vd_avx2_sleef_avx2_sleef(vdouble_avx2_sleef x) {\n\n  return vtruncate_vd_vd_avx2_sleef(x);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vfloor2_vd_vd_avx2_sleef(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef fr = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(INT64_C(1) << 31), vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_avx2_sleef(fr, vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(0)), vadd_vd_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(1.0)), fr);\n  return vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), vge_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(INT64_C(1) << 52))), x, vcopysign_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, fr), x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vceil2_vd_vd_avx2_sleef(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef fr = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(INT64_C(1) << 31), vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_avx2_sleef(fr, vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_avx2_sleef(vle_vo_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(0)), fr, vsub_vd_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(1.0)));\n  return vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), vge_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(INT64_C(1) << 52))), x, vcopysign_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, fr), x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vround2_vd_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef x = vadd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.5));\n  vdouble_avx2_sleef fr = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(INT64_C(1) << 31), vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_avx2_sleef(fr, vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(fr)));\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vle_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), veq_vo_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(0))), vsub_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0)), x);\n  fr = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(0)), vadd_vd_vd_vd_avx2_sleef(fr, vcast_vd_d_avx2_sleef(1.0)), fr);\n  x = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.49999999999999994449)), vcast_vd_d_avx2_sleef(0), x);\n  return vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vge_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(INT64_C(1) << 52))), d, vcopysign_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, fr), d));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vrint2_vd_vd_avx2_sleef(vdouble_avx2_sleef d) {\n\n  return vrint_vd_vd_avx2_sleef(d);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visint_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  return veq_vo_vd_vd_avx2_sleef(vrint2_vd_vd_avx2_sleef(d), d);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visodd_vo_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef x = vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.5));\n  return vneq_vo_vd_vd_avx2_sleef(vrint2_vd_vd_avx2_sleef(x), x);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef vilogbk_vi_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(4.9090934652977266E-91));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2.037035976334486E90), d), d);\n  vint_avx2_sleef q = vcastu_vi_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d));\n  q = vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef((int)(((1U << 12) - 1) << 20)));\n  q = vsrl_vi_vi_i_avx2_sleef(q, 20);\n  q = vsub_vi_vi_vi_avx2_sleef(q, vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vcast_vi_i_avx2_sleef(300 + 0x3ff), vcast_vi_i_avx2_sleef(0x3ff)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef vilogb2k_vi_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vint_avx2_sleef q = vcastu_vi_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d));\n  q = vsrl_vi_vi_i_avx2_sleef(q, 20);\n  q = vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(0x7ff));\n  q = vsub_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(0x3ff));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vilogb2k_vm_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vmask_avx2_sleef m = vreinterpret_vm_vd_avx2_sleef(d);\n  m = _mm256_srli_epi64(m, 20 + 32);\n  m = vand_vm_vm_vm_avx2_sleef(m, vcast_vm_i64_avx2_sleef(0x7ff));\n  m = vsub64_vm_vm_vm_avx2_sleef(m, vcast_vm_i64_avx2_sleef(0x3ff));\n  return m;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vilogb3k_vm_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vmask_avx2_sleef m = vreinterpret_vm_vd_avx2_sleef(d);\n  m = _mm256_srli_epi64(m, 20 + 32);\n  m = vand_vm_vm_vm_avx2_sleef(m, vcast_vm_i64_avx2_sleef(0x7ff));\n  return m;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vpow2i_vd_vi_avx2_sleef(vint_avx2_sleef q) {\n  q = vadd_vi_vi_vi_avx2_sleef(vcast_vi_i_avx2_sleef(0x3ff), q);\n  vmask_avx2_sleef r = vcastu_vm_vi_avx2_sleef(vsll_vi_vi_i_avx2_sleef(q, 20));\n  return vreinterpret_vd_vm_avx2_sleef(r);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vpow2i_vd_vm_avx2_sleef(vmask_avx2_sleef q) {\n  q = vadd64_vm_vm_vm_avx2_sleef(vcast_vm_i64_avx2_sleef(0x3ff), q);\n  return vreinterpret_vd_vm_avx2_sleef(_mm256_slli_epi64(q, 52));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp_vd_vd_vi_avx2_sleef(vdouble_avx2_sleef x, vint_avx2_sleef q) {\n  vint_avx2_sleef m = vsra_vi_vi_i_avx2_sleef(q, 31);\n  m = vsll_vi_vi_i_avx2_sleef(vsub_vi_vi_vi_avx2_sleef(vsra_vi_vi_i_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(m, q), 9), m), 7);\n  q = vsub_vi_vi_vi_avx2_sleef(q, vsll_vi_vi_i_avx2_sleef(m, 2));\n  m = vadd_vi_vi_vi_avx2_sleef(vcast_vi_i_avx2_sleef(0x3ff), m);\n  m = vandnot_vi_vo_vi_avx2_sleef(vgt_vo_vi_vi_avx2_sleef(vcast_vi_i_avx2_sleef(0), m), m);\n  m = vsel_vi_vo_vi_vi_avx2_sleef(vgt_vo_vi_vi_avx2_sleef(m, vcast_vi_i_avx2_sleef(0x7ff)), vcast_vi_i_avx2_sleef(0x7ff), m);\n  vmask_avx2_sleef r = vcastu_vm_vi_avx2_sleef(vsll_vi_vi_i_avx2_sleef(m, 20));\n  vdouble_avx2_sleef y = vreinterpret_vd_vm_avx2_sleef(r);\n  return vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, y), y), y), y), vpow2i_vd_vi_avx2_sleef(q));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp2_vd_vd_vi_avx2_sleef(vdouble_avx2_sleef d, vint_avx2_sleef e) {\n  return vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vi_avx2_sleef(vsra_vi_vi_i_avx2_sleef(e, 1))), vpow2i_vd_vi_avx2_sleef(vsub_vi_vi_vi_avx2_sleef(e, vsra_vi_vi_i_avx2_sleef(e, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp3_vd_vd_vi_avx2_sleef(vdouble_avx2_sleef d, vint_avx2_sleef q) {\n  return vreinterpret_vd_vm_avx2_sleef(vadd64_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vcastu_vm_vi_avx2_sleef(vsll_vi_vi_i_avx2_sleef(q, 20))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp1_vd_vd_vm_avx2_sleef(vdouble_avx2_sleef d, vmask_avx2_sleef e) {\n  vmask_avx2_sleef m = _mm256_srli_epi64(e, 2);\n  e = vsub64_vm_vm_vm_avx2_sleef(vsub64_vm_vm_vm_avx2_sleef(vsub64_vm_vm_vm_avx2_sleef(e, m), m), m);\n  d = vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vm_avx2_sleef(m));\n  d = vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vm_avx2_sleef(m));\n  d = vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vm_avx2_sleef(m));\n  d = vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vm_avx2_sleef(e));\n  return d;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp2_vd_vd_vm_avx2_sleef(vdouble_avx2_sleef d, vmask_avx2_sleef e) {\n  return vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vpow2i_vd_vm_avx2_sleef(_mm256_srli_epi64(e, 1))), vpow2i_vd_vm_avx2_sleef(vsub64_vm_vm_vm_avx2_sleef(e, _mm256_srli_epi64(e, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vldexp3_vd_vd_vm_avx2_sleef(vdouble_avx2_sleef d, vmask_avx2_sleef q) {\n  return vreinterpret_vd_vm_avx2_sleef(vadd64_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), _mm256_slli_epi64(q, 52)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vcast_vd_vm_avx2_sleef(vmask_avx2_sleef m) { return vcast_vd_vi_avx2_sleef(vcast_vi_vm_avx2_sleef(m)); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vtruncate_vm_vd_avx2_sleef(vdouble_avx2_sleef d) { return vcast_vm_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(d)); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef vlt64_vo_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { return vgt64_vo_vm_vm_avx2_sleef(y, x); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef vnot_vo64_vo64_avx2_sleef(vopmask_avx2_sleef x) {\n  return vxor_vo_vo_vo_avx2_sleef(x, veq64_vo_vm_vm_avx2_sleef(vcast_vm_i64_avx2_sleef(0), vcast_vm_i64_avx2_sleef(0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef vugt64_vo_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) {\n  x = vxor_vm_vm_vm_avx2_sleef(vcast_vm_u64_avx2_sleef(UINT64_C(0x8000000000000000)), x);\n  y = vxor_vm_vm_vm_avx2_sleef(vcast_vm_u64_avx2_sleef(UINT64_C(0x8000000000000000)), y);\n  return vgt64_vo_vm_vm_avx2_sleef(x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vilogbk_vm_vd_avx2_sleef(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(4.9090934652977266E-91));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2.037035976334486E90), d), d);\n  vmask_avx2_sleef q = vreinterpret_vm_vd_avx2_sleef(d);\n  q = _mm256_srli_epi64(q, 20 + 32);\n  q = vand_vm_vm_vm_avx2_sleef(q, vcast_vm_i64_avx2_sleef(0x7ff));\n  q = vsub64_vm_vm_vm_avx2_sleef(q, vsel_vm_vo64_vm_vm_avx2_sleef(o, vcast_vm_i64_avx2_sleef(300 + 0x3ff), vcast_vm_i64_avx2_sleef(0x3ff)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef sel_vq_vo_vq_vq_avx2_sleef(vopmask_avx2_sleef o, vquad_avx2_sleef x, vquad_avx2_sleef y) {\n  return vqsetxy_vq_vm_vm_avx2_sleef(vsel_vm_vo64_vm_vm_avx2_sleef(o, vqgetx_vm_vq_avx2_sleef(x), vqgetx_vm_vq_avx2_sleef(y)), vsel_vm_vo64_vm_vm_avx2_sleef(o, vqgety_vm_vq_avx2_sleef(x), vqgety_vm_vq_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef add128_vq_vq_vq_avx2_sleef(vquad_avx2_sleef x, vquad_avx2_sleef y) {\n  vquad_avx2_sleef r = vqsetxy_vq_vm_vm_avx2_sleef(vadd64_vm_vm_vm_avx2_sleef(vqgetx_vm_vq_avx2_sleef(x), vqgetx_vm_vq_avx2_sleef(y)), vadd64_vm_vm_vm_avx2_sleef(vqgety_vm_vq_avx2_sleef(x), vqgety_vm_vq_avx2_sleef(y)));\n  r = vqsety_vq_vq_vm_avx2_sleef(r, vadd64_vm_vm_vm_avx2_sleef(vqgety_vm_vq_avx2_sleef(r), vand_vm_vo64_vm_avx2_sleef(vugt64_vo_vm_vm_avx2_sleef(vqgetx_vm_vq_avx2_sleef(x), vqgetx_vm_vq_avx2_sleef(r)), vcast_vm_i64_avx2_sleef(1))));\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vquad_avx2_sleef imdvq_vq_vm_vm_avx2_sleef(vmask_avx2_sleef x, vmask_avx2_sleef y) { vquad_avx2_sleef r = vqsetxy_vq_vm_vm_avx2_sleef(x, y); return r; }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST di_t_avx2_sleef rempisub_avx2_sleef(vdouble_avx2_sleef x) {\n\n  vdouble_avx2_sleef y = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(4)));\n  vint_avx2_sleef vi = vtruncate_vi_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(y, vmul_vd_vd_vd_avx2_sleef(vrint_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(4))));\n  return disetdi_di_vd_vi_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0.25))), vi);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef vsel_vi_vd_vd_vi_vi_avx2_sleef(vdouble_avx2_sleef d0, vdouble_avx2_sleef d1, vint_avx2_sleef x, vint_avx2_sleef y) { return vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d0, d1)), x, y); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint_avx2_sleef vsel_vi_vd_vi_avx2_sleef(vdouble_avx2_sleef d, vint_avx2_sleef x) { return vand_vi_vo_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vsignbit_vo_vd_avx2_sleef(d)), x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_ldexpd4_avx2(vdouble_avx2_sleef x, vint_avx2_sleef q) { return vldexp_vd_vd_vi_avx2_sleef(x, q); }\n\nSLEEF_INLINE SLEEF_CONST vint_avx2_sleef Sleef_ilogbd4_avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef e = vcast_vd_vi_avx2_sleef(vilogbk_vi_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d)));\n  e = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(SLEEF_FP_ILOGB0), e);\n  e = vsel_vd_vo_vd_vd_avx2_sleef(visnan_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(SLEEF_FP_ILOGBNAN), e);\n  e = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(2147483647), e);\n  return vrint_vi_vd_avx2_sleef(e);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST ddi_t_avx2_sleef rempi_avx2_sleef(vdouble_avx2_sleef a) {\n  vdouble2_avx2_sleef x, y;\n  vint_avx2_sleef ex = vilogb2k_vi_vd_avx2_sleef(a);\n\n  ex = vsub_vi_vi_vi_avx2_sleef(ex, vcast_vi_i_avx2_sleef(55));\n  vint_avx2_sleef q = vand_vi_vo_vi_avx2_sleef(vgt_vo_vi_vi_avx2_sleef(ex, vcast_vi_i_avx2_sleef(700-55)), vcast_vi_i_avx2_sleef(-64));\n  a = vldexp3_vd_vd_vi_avx2_sleef(a, q);\n  ex = vandnot_vi_vi_vi_avx2_sleef(vsra_vi_vi_i_avx2_sleef(ex, 31), ex);\n  ex = vsll_vi_vi_i_avx2_sleef(ex, 2);\n  x = ddmul_vd2_vd_vd_avx2_sleef(a, vgather_vd_p_vi_avx2_sleef(Sleef_rempitabdp, ex));\n  di_t_avx2_sleef di = rempisub_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x));\n  q = digeti_vi_di_avx2_sleef(di);\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, digetd_vd_di_avx2_sleef(di));\n  x = ddnormalize_vd2_vd2_avx2_sleef(x);\n  y = ddmul_vd2_vd_vd_avx2_sleef(a, vgather_vd_p_vi_avx2_sleef(Sleef_rempitabdp+1, ex));\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(x, y);\n  di = rempisub_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x));\n  q = vadd_vi_vi_vi_avx2_sleef(q, digeti_vi_di_avx2_sleef(di));\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, digetd_vd_di_avx2_sleef(di));\n  x = ddnormalize_vd2_vd2_avx2_sleef(x);\n  y = vcast_vd2_vd_vd_avx2_sleef(vgather_vd_p_vi_avx2_sleef(Sleef_rempitabdp+2, ex), vgather_vd_p_vi_avx2_sleef(Sleef_rempitabdp+3, ex));\n  y = ddmul_vd2_vd2_vd_avx2_sleef(y, a);\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(x, y);\n  x = ddnormalize_vd2_vd2_avx2_sleef(x);\n  x = ddmul_vd2_vd2_vd2_avx2_sleef(x, vcast_vd2_d_d_avx2_sleef(3.141592653589793116*2, 1.2246467991473532072e-16*2));\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(a), vcast_vd_d_avx2_sleef(0.7));\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vsel_vd_vo_vd_vd_avx2_sleef(o, a, vd2getx_vd_vd2_avx2_sleef(x)));\n  x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n  return ddisetddi_ddi_vd2_vi_avx2_sleef(x, q);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sind4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u, s, r = d;\n  vint_avx2_sleef ql;\n\n  vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  d = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116), d);\n  d = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16), d);\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(r), vcast_vd_d_avx2_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(r, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmlapn_vd_vd_vd_vd_avx2_sleef(r, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724), dqh));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914), r);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24), u);\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    d = vsel_vd_vo_vd_vd_avx2_sleef(g, d, u);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(r), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(r);\n      vint_avx2_sleef ql2 = vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(3));\n      ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0))), vcast_vi_i_avx2_sleef(2), vcast_vi_i_avx2_sleef(1)));\n      ql2 = vsra_vi_vi_i_avx2_sleef(ql2, 2);\n      vopmask_avx2_sleef o = veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1));\n      vdouble2_avx2_sleef x = vcast_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef))),\n       vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef))));\n      x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef), x);\n      ddi_avx2_sleef = ddisetdd_ddi_ddi_vd2_avx2_sleef(ddi_avx2_sleef, vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(o), x, ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vd2gety_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n      d = vsel_vd_vo_vd_vd_avx2_sleef(g, d, u);\n      d = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(r), visnan_vo_vd_avx2_sleef(r)), vreinterpret_vm_vd_avx2_sleef(d)));\n    }\n  }\n\n  s = vmul_vd_vd_vd_avx2_sleef(d, d);\n\n  d = vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1))), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(d)));\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-7.97255955009037868891952e-18)), (vcast_vd_d_avx2_sleef(2.81009972710863200091251e-15)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-7.64712219118158833288484e-13)), (vcast_vd_d_avx2_sleef(1.60590430605664501629054e-10)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-2.50521083763502045810755e-08)), (vcast_vd_d_avx2_sleef(2.75573192239198747630416e-06)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-0.000198412698412696162806809)), (vcast_vd_d_avx2_sleef(0.00833333333333332974823815)))))))\n\n                                  ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.166666666666666657414808));\n\n  u = vadd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(u, d)), d);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(r), r, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sind4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u;\n  vdouble2_avx2_sleef s, t, x;\n  vint_avx2_sleef ql;\n\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n  vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116), d);\n  x = ddadd_vd2_vd_vd_avx2_sleef (u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16)));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    const vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmlapn_vd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724), dqh));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914), d);\n    s = ddadd_vd2_vd_vd_avx2_sleef (u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16)));\n    s = ddadd_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24)));\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    x = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, x, s);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      vint_avx2_sleef ql2 = vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(3));\n      ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0))), vcast_vi_i_avx2_sleef(2), vcast_vi_i_avx2_sleef(1)));\n      ql2 = vsra_vi_vi_i_avx2_sleef(ql2, 2);\n      vopmask_avx2_sleef o = veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1));\n      vdouble2_avx2_sleef t = vcast_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef))),\n       vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef))));\n      t = ddadd2_vd2_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef), t);\n      ddi_avx2_sleef = ddisetdd_ddi_ddi_vd2_avx2_sleef(ddi_avx2_sleef, vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(o), t, ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      s = ddnormalize_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef));\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n      x = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, x, s);\n      x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d)), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n    }\n  }\n\n  t = x;\n  s = ddsqu_vd2_vd2_avx2_sleef(x);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2getx_vd_vd2_avx2_sleef(s)), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.72052416138529567917983e-15)), (vcast_vd_d_avx2_sleef(-7.6429259411395447190023e-13)))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(1.60589370117277896211623e-10)), (vcast_vd_d_avx2_sleef(-2.5052106814843123359368e-08)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.75573192104428224777379e-06)), (vcast_vd_d_avx2_sleef(-0.000198412698412046454654947)))))))\n\n                                    ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(0.00833333333333318056201922));\n\n  x = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), ddmul_vd2_vd2_vd2_avx2_sleef(ddadd_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.166666666666666657414808), vmul_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s))), s));\n  u = ddmul_vd_vd2_vd2_avx2_sleef(t, x);\n\n  u = vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1))),\n             vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_cosd4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u, s, r = d;\n  vint_avx2_sleef ql;\n\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n  vdouble_avx2_sleef dql = vmla_vd_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2),\n     vrint_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724), vcast_vd_d_avx2_sleef(-0.5))),\n     vcast_vd_d_avx2_sleef(1));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  d = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), d);\n  d = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), d);\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(r, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724 / (1 << 23)), vcast_vd_d_avx2_sleef(-0.318309886183790671537767526745028724 / (1 << 24))));\n    vint_avx2_sleef ql2 = vrint_vi_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(r, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724)),\n      vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-(1 << 23)), vcast_vd_d_avx2_sleef(-0.5))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vcast_vi_i_avx2_sleef(1));\n    vdouble_avx2_sleef dql = vcast_vd_vi_avx2_sleef(ql2);\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), r);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n    d = vsel_vd_vo_vd_vd_avx2_sleef(g, d, u);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(r), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(r);\n      vint_avx2_sleef ql2 = vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(3));\n      ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0))), vcast_vi_i_avx2_sleef(8), vcast_vi_i_avx2_sleef(7)));\n      ql2 = vsra_vi_vi_i_avx2_sleef(ql2, 1);\n      vopmask_avx2_sleef o = veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(0));\n      vdouble_avx2_sleef y = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(0), vcast_vd_d_avx2_sleef(-1));\n      vdouble2_avx2_sleef x = vcast_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), y),\n       vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), y));\n      x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef), x);\n      ddi_avx2_sleef = ddisetdd_ddi_ddi_vd2_avx2_sleef(ddi_avx2_sleef, vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(o), x, ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vd2gety_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n      d = vsel_vd_vo_vd_vd_avx2_sleef(g, d, u);\n      d = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(r), visnan_vo_vd_avx2_sleef(r)), vreinterpret_vm_vd_avx2_sleef(d)));\n    }\n  }\n\n  s = vmul_vd_vd_vd_avx2_sleef(d, d);\n\n  d = vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(0))), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(d)));\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-7.97255955009037868891952e-18)), (vcast_vd_d_avx2_sleef(2.81009972710863200091251e-15)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-7.64712219118158833288484e-13)), (vcast_vd_d_avx2_sleef(1.60590430605664501629054e-10)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-2.50521083763502045810755e-08)), (vcast_vd_d_avx2_sleef(2.75573192239198747630416e-06)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(-0.000198412698412696162806809)), (vcast_vd_d_avx2_sleef(0.00833333333333332974823815)))))))\n\n                                  ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.166666666666666657414808));\n\n  u = vadd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(u, d)), d);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_cosd4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u;\n  vdouble2_avx2_sleef s, t, x;\n  vint_avx2_sleef ql;\n\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n  vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724), vcast_vd_d_avx2_sleef(-0.5)));\n  dql = vmla_vd_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2), dql, vcast_vd_d_avx2_sleef(1));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  x = ddadd2_vd2_vd_vd_avx2_sleef(d, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116*0.5)));\n  x = ddadd_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16*0.5)));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724 / (1 << 23)), vcast_vd_d_avx2_sleef(-0.318309886183790671537767526745028724 / (1 << 24))));\n    vint_avx2_sleef ql2 = vrint_vi_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.318309886183790671537767526745028724)),\n      vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-(1 << 23)), vcast_vd_d_avx2_sleef(-0.5))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vcast_vi_i_avx2_sleef(1));\n    const vdouble_avx2_sleef dql = vcast_vd_vi_avx2_sleef(ql2);\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), d);\n    s = ddadd2_vd2_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914*0.5)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5)));\n    s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5)));\n    s = ddadd_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n    x = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, x, s);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      vint_avx2_sleef ql2 = vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(3));\n      ql2 = vadd_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql2, ql2), vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0))), vcast_vi_i_avx2_sleef(8), vcast_vi_i_avx2_sleef(7)));\n      ql2 = vsra_vi_vi_i_avx2_sleef(ql2, 1);\n      vopmask_avx2_sleef o = veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef), vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(0));\n      vdouble_avx2_sleef y = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(0), vcast_vd_d_avx2_sleef(-1));\n      vdouble2_avx2_sleef t = vcast_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), y),\n       vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), y));\n      t = ddadd2_vd2_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef), t);\n      ddi_avx2_sleef = ddisetdd_ddi_ddi_vd2_avx2_sleef(ddi_avx2_sleef, vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(o), t, ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      s = ddnormalize_vd2_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef));\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n      x = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, x, s);\n      x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d)), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n    }\n  }\n\n  t = x;\n  s = ddsqu_vd2_vd2_avx2_sleef(x);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2getx_vd_vd2_avx2_sleef(s)), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.72052416138529567917983e-15)), (vcast_vd_d_avx2_sleef(-7.6429259411395447190023e-13)))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(1.60589370117277896211623e-10)), (vcast_vd_d_avx2_sleef(-2.5052106814843123359368e-08)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.75573192104428224777379e-06)), (vcast_vd_d_avx2_sleef(-0.000198412698412046454654947)))))))\n\n                                    ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(0.00833333333333318056201922));\n\n  x = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), ddmul_vd2_vd2_vd2_avx2_sleef(ddadd_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.166666666666666657414808), vmul_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s))), s));\n  u = ddmul_vd_vd2_vd2_avx2_sleef(t, x);\n\n  u = vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(0))), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE vdouble2_avx2_sleef Sleef_sincosd4_u35avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, t, rx, ry, s = d;\n  vdouble2_avx2_sleef r;\n  vint_avx2_sleef ql;\n\n  vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(s, vcast_vd_d_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), s);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), s);\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), d);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    s = vsel_vd_vo_vd_vd_avx2_sleef(g, s, u);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vd2gety_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      u = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef));\n      s = vsel_vd_vo_vd_vd_avx2_sleef(g, s, u);\n    }\n  }\n\n  t = s;\n\n  s = vmul_vd_vd_vd_avx2_sleef(s, s);\n\n  u = vcast_vd_d_avx2_sleef(1.58938307283228937328511e-10);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-2.50506943502539773349318e-08));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(2.75573131776846360512547e-06));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.000198412698278911770864914));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(0.0083333333333191845961746));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.166666666666666130709393));\n\n  rx = vmla_vd_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(u, s), t, t);\n  rx = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(-0.0), rx);\n\n  u = vcast_vd_d_avx2_sleef(-1.13615350239097429531523e-11);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(2.08757471207040055479366e-09));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-2.75573144028847567498567e-07));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(2.48015872890001867311915e-05));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.00138888888888714019282329));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(0.0416666666666665519592062));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.5));\n\n  ry = vmla_vd_vd_vd_vd_avx2_sleef(s, u, vcast_vd_d_avx2_sleef(1));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(o, rx, ry), vsel_vd_vo_vd_vd_avx2_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2)));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2)));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_avx2_sleef Sleef_sincosd4_u10avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, rx, ry;\n  vdouble2_avx2_sleef r, s, t, x;\n  vint_avx2_sleef ql;\n\n  const vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116*0.5), d);\n  s = ddadd_vd2_vd_vd_avx2_sleef (u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16*0.5)));\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    const vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), d);\n    x = ddadd_vd2_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    s = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, s, x);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      x = ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef);\n      o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d));\n      x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n      x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef));\n      s = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, s, x);\n    }\n  }\n\n  t = s;\n\n  s = vd2setx_vd2_vd2_vd_avx2_sleef(s, ddsqu_vd_vd2_avx2_sleef(s));\n\n  u = vcast_vd_d_avx2_sleef(1.58938307283228937328511e-10);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-2.50506943502539773349318e-08));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(2.75573131776846360512547e-06));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-0.000198412698278911770864914));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(0.0083333333333191845961746));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-0.166666666666666130709393));\n\n  u = vmul_vd_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2getx_vd_vd2_avx2_sleef(t)));\n\n  x = ddadd_vd2_vd2_vd_avx2_sleef(t, u);\n  rx = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  rx = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(-0.0), rx);\n\n  u = vcast_vd_d_avx2_sleef(-1.13615350239097429531523e-11);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(2.08757471207040055479366e-09));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-2.75573144028847567498567e-07));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(2.48015872890001867311915e-05));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-0.00138888888888714019282329));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(0.0416666666666665519592062));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(-0.5));\n\n  x = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), ddmul_vd2_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), u));\n  ry = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(o, rx, ry), vsel_vd_vo_vd_vd_avx2_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2)));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2)));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_avx2_sleef Sleef_sincospid4_u05avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, s, t, rx, ry;\n  vdouble2_avx2_sleef r, x, s2;\n\n  u = vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(4.0));\n  vint_avx2_sleef q = vtruncate_vi_vd_avx2_sleef(u);\n  q = vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vxor_vi_vi_vi_avx2_sleef(vsrl_vi_vi_i_avx2_sleef(q, 31), vcast_vi_i_avx2_sleef(1))), vcast_vi_i_avx2_sleef(~1));\n  s = vsub_vd_vd_vd_avx2_sleef(u, vcast_vd_vi_avx2_sleef(q));\n\n  t = s;\n  s = vmul_vd_vd_vd_avx2_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_avx2_sleef(t, t);\n\n  u = vcast_vd_d_avx2_sleef(-2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(6.94821830580179461327784e-12));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(3.13361688966868392878422e-07));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-3.6576204182161551920361e-05));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(0.00249039457019271850274356));\n  x = ddadd2_vd2_vd_vd2_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(u, s), vcast_vd2_d_d_avx2_sleef(-0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s2, x), vcast_vd2_d_d_avx2_sleef(0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd_avx2_sleef(x, t);\n  rx = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  rx = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(-0.0), rx);\n\n  u = vcast_vd_d_avx2_sleef(9.94480387626843774090208e-16);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-3.89796226062932799164047e-13));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1.15011582539996035266901e-10));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-2.4611369501044697495359e-08));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(3.59086044859052754005062e-06));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.000325991886927389905997954));\n  x = ddadd2_vd2_vd_vd2_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(u, s), vcast_vd2_d_d_avx2_sleef(0.0158543442438155018914259, -1.04693272280631521908845e-18));\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s2, x), vcast_vd2_d_d_avx2_sleef(-0.308425137534042437259529, -1.95698492133633550338345e-17));\n\n  x = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(x, s2), vcast_vd_d_avx2_sleef(1));\n  ry = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(o, rx, ry), vsel_vd_vo_vd_vd_avx2_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  o = vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+9/4));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(1), vd2gety_vd_vd2_avx2_sleef(r)));\n\n  o = visinf_vo_vd_avx2_sleef(d);\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vdouble2_avx2_sleef Sleef_sincospid4_u35avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, s, t, rx, ry;\n  vdouble2_avx2_sleef r;\n\n  u = vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(4.0));\n  vint_avx2_sleef q = vtruncate_vi_vd_avx2_sleef(u);\n  q = vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vxor_vi_vi_vi_avx2_sleef(vsrl_vi_vi_i_avx2_sleef(q, 31), vcast_vi_i_avx2_sleef(1))), vcast_vi_i_avx2_sleef(~1));\n  s = vsub_vd_vd_vd_avx2_sleef(u, vcast_vd_vi_avx2_sleef(q));\n\n  t = s;\n  s = vmul_vd_vd_vd_avx2_sleef(s, s);\n\n  u = vcast_vd_d_avx2_sleef(+0.6880638894766060136e-11);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.1757159564542310199e-8));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.3133616327257867311e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.3657620416388486452e-4));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.2490394570189932103e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.8074551218828056320e-1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.7853981633974482790e+0));\n\n  rx = vmul_vd_vd_vd_avx2_sleef(u, t);\n\n  u = vcast_vd_d_avx2_sleef(-0.3860141213683794352e-12);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1150057888029681415e-9));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.2461136493006663553e-7));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.3590860446623516713e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.3259918869269435942e-3));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1585434424381541169e-1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(-0.3084251375340424373e+0));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1));\n\n  ry = u;\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(0)));\n  r = vd2setxy_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(o, rx, ry), vsel_vd_vo_vd_vd_avx2_sleef(o, ry, rx));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  o = vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+9/4));\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  o = visinf_vo_vd_avx2_sleef(d);\n  r = vd2setx_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)))));\n  r = vd2sety_vd2_vd2_vd_avx2_sleef(r, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble2_avx2_sleef Sleef_modfd4_avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef fr = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(INT64_C(1) << 31), vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0 / (INT64_C(1) << 31)))))));\n  fr = vsub_vd_vd_vd_avx2_sleef(fr, vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(fr)));\n  fr = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(INT64_C(1) << 52)), vcast_vd_d_avx2_sleef(0), fr);\n\n  vdouble2_avx2_sleef ret;\n\n  ret = vd2setxy_vd2_vd_vd_avx2_sleef(vcopysign_vd_vd_vd_avx2_sleef(fr, x), vcopysign_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(x, fr), x));\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef sinpik_avx2_sleef(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, s, t;\n  vdouble2_avx2_sleef x, s2;\n\n  u = vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(4.0));\n  vint_avx2_sleef q = vtruncate_vi_vd_avx2_sleef(u);\n  q = vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vxor_vi_vi_vi_avx2_sleef(vsrl_vi_vi_i_avx2_sleef(q, 31), vcast_vi_i_avx2_sleef(1))), vcast_vi_i_avx2_sleef(~1));\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2)));\n\n  s = vsub_vd_vd_vd_avx2_sleef(u, vcast_vd_vi_avx2_sleef(q));\n  t = s;\n  s = vmul_vd_vd_vd_avx2_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_avx2_sleef(t, t);\n\n  u = vsel_vd_vo_d_d_avx2_sleef(o, 9.94480387626843774090208e-16, -2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -3.89796226062932799164047e-13, 6.948218305801794613277840e-12));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, 1.150115825399960352669010e-10, -1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -2.46113695010446974953590e-08, 3.133616889668683928784220e-07));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, 3.590860448590527540050620e-06, -3.65762041821615519203610e-05));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -0.000325991886927389905997954, 0.0024903945701927185027435600));\n  x = ddadd2_vd2_vd_vd2_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(u, s),\n   vsel_vd2_vo_d_d_d_d_avx2_sleef(o, 0.0158543442438155018914259, -1.04693272280631521908845e-18,\n         -0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s2, x),\n    vsel_vd2_vo_d_d_d_d_avx2_sleef(o, -0.308425137534042437259529, -1.95698492133633550338345e-17,\n          0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd2_avx2_sleef(x, vsel_vd2_vo_vd2_vd2_avx2_sleef(o, s2, vcast_vd2_vd_vd_avx2_sleef(t, vcast_vd_d_avx2_sleef(0))));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1)), x);\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sinpid4_u05avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x = sinpik_avx2_sleef(d);\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(-0.0), r);\n  r = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+9/4)), vreinterpret_vm_vd_avx2_sleef(r)));\n  r = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(r)));\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef cospik_avx2_sleef(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vdouble_avx2_sleef u, s, t;\n  vdouble2_avx2_sleef x, s2;\n\n  u = vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(4.0));\n  vint_avx2_sleef q = vtruncate_vi_vd_avx2_sleef(u);\n  q = vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vxor_vi_vi_vi_avx2_sleef(vsrl_vi_vi_i_avx2_sleef(q, 31), vcast_vi_i_avx2_sleef(1))), vcast_vi_i_avx2_sleef(~1));\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(0)));\n\n  s = vsub_vd_vd_vd_avx2_sleef(u, vcast_vd_vi_avx2_sleef(q));\n  t = s;\n  s = vmul_vd_vd_vd_avx2_sleef(s, s);\n  s2 = ddmul_vd2_vd_vd_avx2_sleef(t, t);\n\n  u = vsel_vd_vo_d_d_avx2_sleef(o, 9.94480387626843774090208e-16, -2.02461120785182399295868e-14);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -3.89796226062932799164047e-13, 6.948218305801794613277840e-12));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, 1.150115825399960352669010e-10, -1.75724749952853179952664e-09));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -2.46113695010446974953590e-08, 3.133616889668683928784220e-07));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, 3.590860448590527540050620e-06, -3.65762041821615519203610e-05));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vsel_vd_vo_d_d_avx2_sleef(o, -0.000325991886927389905997954, 0.0024903945701927185027435600));\n  x = ddadd2_vd2_vd_vd2_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(u, s),\n   vsel_vd2_vo_d_d_d_d_avx2_sleef(o, 0.0158543442438155018914259, -1.04693272280631521908845e-18,\n         -0.0807455121882807852484731, 3.61852475067037104849987e-18));\n  x = ddadd2_vd2_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s2, x),\n    vsel_vd2_vo_d_d_d_d_avx2_sleef(o, -0.308425137534042437259529, -1.95698492133633550338345e-17,\n          0.785398163397448278999491, 3.06287113727155002607105e-17));\n\n  x = ddmul_vd2_vd2_vd2_avx2_sleef(x, vsel_vd2_vo_vd2_vd2_avx2_sleef(o, s2, vcast_vd2_vd_vd_avx2_sleef(t, vcast_vd_d_avx2_sleef(0))));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1)), x);\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(4)), vcast_vi_i_avx2_sleef(4)));\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_cospid4_u05avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x = cospik_avx2_sleef(d);\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+9/4)), vcast_vd_d_avx2_sleef(1), r);\n  r = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(r)));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_tand4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u, s, x, y;\n  vopmask_avx2_sleef o;\n  vint_avx2_sleef ql;\n\n  vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116 * 0.5), d);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16 * 0.5), s);\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724)), dqh));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), d);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16 * 0.5), u);\n    u = vmla_vd_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24 * 0.5), u);\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    s = vsel_vd_vo_vd_vd_avx2_sleef(g, s, u);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+6));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      vint_avx2_sleef ql2 = ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef);\n      u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)), vd2gety_vd_vd2_avx2_sleef(ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef)));\n      u = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ql2);\n      s = vsel_vd_vo_vd_vd_avx2_sleef(g, s, u);\n    }\n  }\n\n  x = vmul_vd_vd_vd_avx2_sleef(s, vcast_vd_d_avx2_sleef(0.5));\n  s = vmul_vd_vd_vd_avx2_sleef(x, x);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.3245098826639276316e-3)), (vcast_vd_d_avx2_sleef(+0.5619219738114323735e-3)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1460781502402784494e-2)), (vcast_vd_d_avx2_sleef(+0.3591611540792499519e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.8863268409563113126e-2)), (vcast_vd_d_avx2_sleef(+0.2186948728185535498e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.5396825399517272970e-1)), (vcast_vd_d_avx2_sleef(+0.1333333333330500581e+0)))))))\n\n                                ;\n\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.3333333333333343695e+0));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(u, x), x);\n\n  y = vmla_vd_vd_vd_vd_avx2_sleef(u, u, vcast_vd_d_avx2_sleef(-1));\n  x = vmul_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-2));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1)));\n  u = vdiv_vd_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(o, vneg_vd_vd_avx2_sleef(y), x),\n      vsel_vd_vo_vd_vd_avx2_sleef(o, x, y));\n  u = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_tand4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u;\n  vdouble2_avx2_sleef s, t, x, y;\n  vopmask_avx2_sleef o;\n  vint_avx2_sleef ql;\n\n  const vdouble_avx2_sleef dql = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  ql = vrint_vi_vd_avx2_sleef(dql);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.141592653589793116*0.5), d);\n  s = ddadd_vd2_vd_vd_avx2_sleef (u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467991473532072e-16*0.5)));\n  vopmask_avx2_sleef g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(15));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n    vdouble_avx2_sleef dqh = vtruncate_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2*0.318309886183790671537767526745028724 / (1 << 24))));\n    dqh = vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(1 << 24));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.63661977236758138243, -3.9357353350364971764e-17), d),\n     vsub_vd_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)),\n        vcast_vd_d_avx2_sleef(-0.5), vcast_vd_d_avx2_sleef(0.5)), dqh));\n    const vdouble_avx2_sleef dql = vtruncate_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x)));\n\n    u = vmla_vd_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1415926218032836914 * 0.5), d);\n    x = ddadd_vd2_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1415926218032836914*0.5 )));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-3.1786509424591713469e-08*0.5 )));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dqh, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5)));\n    x = ddadd2_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(dql, vcast_vd_d_avx2_sleef(-1.2246467864107188502e-16*0.5 )));\n    x = ddadd_vd2_vd2_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(dqh, dql), vcast_vd_d_avx2_sleef(-1.2736634327021899816e-24*0.5)));\n\n    ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, vrint_vi_vd_avx2_sleef(dql));\n    s = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, s, x);\n    g = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1e+14));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(g)), 1)) {\n      ddi_t_avx2_sleef ddi_avx2_sleef = rempi_avx2_sleef(d);\n      x = ddigetdd_vd2_ddi_avx2_sleef(ddi_avx2_sleef);\n      o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(d), visnan_vo_vd_avx2_sleef(d));\n      x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n      x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(o, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n\n      ql = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(g), ql, ddigeti_vi_ddi_avx2_sleef(ddi_avx2_sleef));\n      s = vsel_vd2_vo_vd2_vd2_avx2_sleef(g, s, x);\n    }\n  }\n\n  t = ddscale_vd2_vd2_vd_avx2_sleef(s, vcast_vd_d_avx2_sleef(0.5));\n  s = ddsqu_vd2_vd2_avx2_sleef(t);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2getx_vd_vd2_avx2_sleef(s)), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.3245098826639276316e-3)), (vcast_vd_d_avx2_sleef(+0.5619219738114323735e-3)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.1460781502402784494e-2)), (vcast_vd_d_avx2_sleef(+0.3591611540792499519e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.8863268409563113126e-2)), (vcast_vd_d_avx2_sleef(+0.2186948728185535498e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.5396825399517272970e-1)), (vcast_vd_d_avx2_sleef(+0.1333333333330500581e+0)))))))\n\n                                ;\n\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(s), vcast_vd_d_avx2_sleef(+0.3333333333333343695e+0));\n  x = ddadd_vd2_vd2_vd2_avx2_sleef(t, ddmul_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s, t), u));\n\n  y = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(-1), ddsqu_vd2_vd2_avx2_sleef(x));\n  x = ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(-2));\n\n  o = vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(ql, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1)));\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddneg_vd2_vd2_avx2_sleef(y), x),\n   vsel_vd2_vo_vd2_vd2_avx2_sleef(o, x, y));\n\n  u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x));\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), d, u);\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef atan2k_avx2_sleef(vdouble_avx2_sleef y, vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef s, t, u;\n  vint_avx2_sleef q;\n  vopmask_avx2_sleef p;\n\n  q = vsel_vi_vd_vi_avx2_sleef(x, vcast_vi_i_avx2_sleef(-2));\n  x = vabs_vd_vd_avx2_sleef(x);\n\n  q = vsel_vi_vd_vd_vi_vi_avx2_sleef(x, y, vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(1)), q);\n  p = vlt_vo_vd_vd_avx2_sleef(x, y);\n  s = vsel_vd_vo_vd_vd_avx2_sleef(p, vneg_vd_vd_avx2_sleef(x), y);\n  t = vmax_vd_vd_vd_avx2_sleef(x, y);\n\n  s = vdiv_vd_vd_vd_avx2_sleef(s, t);\n  t = vmul_vd_vd_vd_avx2_sleef(s, s);\n\n  vdouble_avx2_sleef t2 = vmul_vd_vd_vd_avx2_sleef(t, t), t4 = vmul_vd_vd_vd_avx2_sleef(t2, t2), t8 = vmul_vd_vd_vd_avx2_sleef(t4, t4), t16 = vmul_vd_vd_vd_avx2_sleef(t8, t8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((t16), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vcast_vd_d_avx2_sleef(-1.88796008463073496563746e-05)), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.000209850076645816976906797)), (vcast_vd_d_avx2_sleef(-0.00110611831486672482563471)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t8), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.00370026744188713119232403)), (vcast_vd_d_avx2_sleef(-0.00889896195887655491740809)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.016599329773529201970117)), (vcast_vd_d_avx2_sleef(-0.0254517624932312641616861)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0337852580001353069993897)), (vcast_vd_d_avx2_sleef(-0.0407629191276836500001934)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0466667150077840625632675)), (vcast_vd_d_avx2_sleef(-0.0523674852303482457616113)))))))), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0587666392926673580854313)), (vcast_vd_d_avx2_sleef(-0.0666573579361080525984562)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0769219538311769618355029)), (vcast_vd_d_avx2_sleef(-0.090908995008245008229153)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.111111105648261418443745)), (vcast_vd_d_avx2_sleef(-0.14285714266771329383765)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.199999999996591265594148)), (vcast_vd_d_avx2_sleef(-0.333333333333311110369124)))))))))))\n\n                                  ;\n\n  t = vmla_vd_vd_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(t, u), s);\n  t = vmla_vd_vd_vd_vd_avx2_sleef(vcast_vd_vi_avx2_sleef(q), vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef atan2k_u1_avx2_sleef(vdouble2_avx2_sleef y, vdouble2_avx2_sleef x) {\n  vdouble_avx2_sleef u;\n  vdouble2_avx2_sleef s, t;\n  vint_avx2_sleef q;\n  vopmask_avx2_sleef p;\n\n  q = vsel_vi_vd_vi_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vcast_vi_i_avx2_sleef(-2));\n  p = vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vcast_vd_d_avx2_sleef(0));\n  vmask_avx2_sleef b = vand_vm_vo64_vm_avx2_sleef(p, vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0)));\n  x = vd2setx_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(b, vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)))));\n  x = vd2sety_vd2_vd2_vd_avx2_sleef(x, vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(b, vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(x)))));\n\n  q = vsel_vi_vd_vd_vi_vi_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y), vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(1)), q);\n  p = vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(y));\n  s = vsel_vd2_vo_vd2_vd2_avx2_sleef(p, ddneg_vd2_vd2_avx2_sleef(x), y);\n  t = vsel_vd2_vo_vd2_vd2_avx2_sleef(p, y, x);\n\n  s = dddiv_vd2_vd2_vd2_avx2_sleef(s, t);\n  t = ddsqu_vd2_vd2_avx2_sleef(s);\n  t = ddnormalize_vd2_vd2_avx2_sleef(t);\n\n  vdouble_avx2_sleef t2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), vd2getx_vd_vd2_avx2_sleef(t)), t4 = vmul_vd_vd_vd_avx2_sleef(t2, t2), t8 = vmul_vd_vd_vd_avx2_sleef(t4, t4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((t8), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(1.06298484191448746607415e-05)), (vcast_vd_d_avx2_sleef(-0.000125620649967286867384336)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.00070557664296393412389774)), (vcast_vd_d_avx2_sleef(-0.00251865614498713360352999)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.00646262899036991172313504)), (vcast_vd_d_avx2_sleef(-0.0128281333663399031014274)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.0208024799924145797902497)), (vcast_vd_d_avx2_sleef(-0.0289002344784740315686289)))))))), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.0359785005035104590853656)), (vcast_vd_d_avx2_sleef(-0.041848579703592507506027)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.0470843011653283988193763)), (vcast_vd_d_avx2_sleef(-0.0524914210588448421068719)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.0587946590969581003860434)), (vcast_vd_d_avx2_sleef(-0.0666620884778795497194182)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(t)), (vcast_vd_d_avx2_sleef(0.0769225330296203768654095)), (vcast_vd_d_avx2_sleef(-0.0909090442773387574781907)))))))))\n\n                                   ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(t), vcast_vd_d_avx2_sleef(0.111111108376896236538123));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(t), vcast_vd_d_avx2_sleef(-0.142857142756268568062339));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(t), vcast_vd_d_avx2_sleef(0.199999999997977351284817));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(t), vcast_vd_d_avx2_sleef(-0.333333333333317605173818));\n\n  t = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddmul_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(s, t), u));\n\n  t = ddadd_vd2_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(1.570796326794896557998982, 6.12323399573676603586882e-17), vcast_vd_vi_avx2_sleef(q)), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef visinf2_vd_vd_vd_avx2_sleef(vdouble_avx2_sleef d, vdouble_avx2_sleef m) {\n  return vreinterpret_vd_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vor_vm_vm_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(d), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(m))));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_atan2d4_u35avx2(vdouble_avx2_sleef y, vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef r = atan2k_avx2_sleef(vabs_vd_vd_avx2_sleef(y), x);\n\n  r = vmulsign_vd_vd_vd_avx2_sleef(r, x);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0))), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_avx2_sleef(x, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(y), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_avx2_sleef(x, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0.0)), vreinterpret_vd_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vsignbit_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vreinterpret_vm_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_atan2d4_u10avx2(vdouble_avx2_sleef y, vdouble_avx2_sleef x) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(5.5626846462680083984e-309));\n  x = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(UINT64_C(1) << 53)), x);\n  y = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(UINT64_C(1) << 53)), y);\n\n  vdouble2_avx2_sleef d = atan2k_u1_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(y), vcast_vd_d_avx2_sleef(0)), vcast_vd2_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)));\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d));\n\n  r = vmulsign_vd_vd_vd_avx2_sleef(r, x);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0))), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_avx2_sleef(x, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(y), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vd_vd_vd_avx2_sleef(x, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0.0)), vreinterpret_vd_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vsignbit_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vreinterpret_vm_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_asind4_u35avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0.5));\n  vdouble_avx2_sleef x2 = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, d), vmul_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vabs_vd_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5)));\n  vdouble_avx2_sleef x = vsel_vd_vo_vd_vd_avx2_sleef(o, vabs_vd_vd_avx2_sleef(d), vsqrt_vd_vd_avx2_sleef(x2)), u;\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_avx2_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_avx2_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_avx2_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_avx2_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_avx2_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_avx2_sleef(+0.1666666666666497543e+0)))))))))\n\n                                ;\n\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(x, x2), x);\n\n  vdouble_avx2_sleef r = vsel_vd_vo_vd_vd_avx2_sleef(o, u, vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-2), vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2)));\n  return vmulsign_vd_vd_vd_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_asind4_u10avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0.5));\n  vdouble_avx2_sleef x2 = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, d), vmul_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vabs_vd_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5))), u;\n  vdouble2_avx2_sleef x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, vcast_vd2_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0)), ddsqrt_vd2_vd_avx2_sleef(x2));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(veq_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1.0)), vcast_vd2_d_d_avx2_sleef(0, 0), x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_avx2_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_avx2_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_avx2_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_avx2_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_avx2_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_avx2_sleef(+0.1666666666666497543e+0)))))))))\n\n                                ;\n\n  u = vmul_vd_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)));\n\n  vdouble2_avx2_sleef y = ddsub_vd2_vd2_vd_avx2_sleef(ddsub_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(3.141592653589793116/4, 1.2246467991473532072e-16/4), x), u);\n\n  vdouble_avx2_sleef r = vsel_vd_vo_vd_vd_avx2_sleef(o, vadd_vd_vd_vd_avx2_sleef(u, vd2getx_vd_vd2_avx2_sleef(x)),\n          vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(y)), vcast_vd_d_avx2_sleef(2)));\n  return vmulsign_vd_vd_vd_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_acosd4_u35avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0.5));\n  vdouble_avx2_sleef x2 = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, d),\n    vmul_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vabs_vd_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5))), u;\n  vdouble_avx2_sleef x = vsel_vd_vo_vd_vd_avx2_sleef(o, vabs_vd_vd_avx2_sleef(d), vsqrt_vd_vd_avx2_sleef(x2));\n  x = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1.0)), vcast_vd_d_avx2_sleef(0), x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_avx2_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_avx2_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_avx2_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_avx2_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_avx2_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_avx2_sleef(+0.1666666666666497543e+0)))))))))\n\n                                ;\n\n  u = vmul_vd_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(x2, x));\n\n  vdouble_avx2_sleef y = vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), vadd_vd_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(x, d), vmulsign_vd_vd_vd_avx2_sleef(u, d)));\n  x = vadd_vd_vd_vd_avx2_sleef(x, u);\n  vdouble_avx2_sleef r = vsel_vd_vo_vd_vd_avx2_sleef(o, y, vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n  return vsel_vd_vo_vd_vd_avx2_sleef(vandnot_vo_vo_vo_avx2_sleef(o, vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0))),\n     vd2getx_vd_vd2_avx2_sleef(ddadd_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(3.141592653589793116, 1.2246467991473532072e-16),\n         vneg_vd_vd_avx2_sleef(r))), r);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_acosd4_u10avx2(vdouble_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0.5));\n  vdouble_avx2_sleef x2 = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, d), vmul_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vabs_vd_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5))), u;\n  vdouble2_avx2_sleef x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, vcast_vd2_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0)), ddsqrt_vd2_vd_avx2_sleef(x2));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(veq_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1.0)), vcast_vd2_d_d_avx2_sleef(0, 0), x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3161587650653934628e-1)), (vcast_vd_d_avx2_sleef(-0.1581918243329996643e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1929045477267910674e-1)), (vcast_vd_d_avx2_sleef(+0.6606077476277170610e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1215360525577377331e-1)), (vcast_vd_d_avx2_sleef(+0.1388715184501609218e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1735956991223614604e-1)), (vcast_vd_d_avx2_sleef(+0.2237176181932048341e-1)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3038195928038132237e-1)), (vcast_vd_d_avx2_sleef(+0.4464285681377102438e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.7500000000378581611e-1)), (vcast_vd_d_avx2_sleef(+0.1666666666666497543e+0)))))))))\n\n                                ;\n\n  u = vmul_vd_vd_vd_avx2_sleef(u, vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)));\n\n  vdouble2_avx2_sleef y = ddsub_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(3.141592653589793116/2, 1.2246467991473532072e-16/2),\n     ddadd_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), d), vmulsign_vd_vd_vd_avx2_sleef(u, d)));\n  x = ddadd_vd2_vd2_vd_avx2_sleef(x, u);\n\n  y = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, y, ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n\n  y = vsel_vd2_vo_vd2_vd2_avx2_sleef(vandnot_vo_vo_vo_avx2_sleef(o, vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0))),\n     ddsub_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(3.141592653589793116, 1.2246467991473532072e-16), y), y);\n\n  return vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(y));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_atand4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef d2 = atan2k_u1_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(0)), vcast_vd2_d_d_avx2_sleef(1, 0));\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d2), vd2gety_vd_vd2_avx2_sleef(d2));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(1.570796326794896557998982), r);\n  return vmulsign_vd_vd_vd_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_atand4_u35avx2(vdouble_avx2_sleef s) {\n  vdouble_avx2_sleef t, u;\n  vint_avx2_sleef q;\n\n  q = vsel_vi_vd_vi_avx2_sleef(s, vcast_vi_i_avx2_sleef(2));\n  s = vabs_vd_vd_avx2_sleef(s);\n\n  q = vsel_vi_vd_vd_vi_vi_avx2_sleef(vcast_vd_d_avx2_sleef(1), s, vadd_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(1)), q);\n  s = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), s), vrec_vd_vd_avx2_sleef(s), s);\n\n  t = vmul_vd_vd_vd_avx2_sleef(s, s);\n\n  vdouble_avx2_sleef t2 = vmul_vd_vd_vd_avx2_sleef(t, t), t4 = vmul_vd_vd_vd_avx2_sleef(t2, t2), t8 = vmul_vd_vd_vd_avx2_sleef(t4, t4), t16 = vmul_vd_vd_vd_avx2_sleef(t8, t8);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((t16), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vcast_vd_d_avx2_sleef(-1.88796008463073496563746e-05)), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.000209850076645816976906797)), (vcast_vd_d_avx2_sleef(-0.00110611831486672482563471)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t8), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.00370026744188713119232403)), (vcast_vd_d_avx2_sleef(-0.00889896195887655491740809)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.016599329773529201970117)), (vcast_vd_d_avx2_sleef(-0.0254517624932312641616861)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0337852580001353069993897)), (vcast_vd_d_avx2_sleef(-0.0407629191276836500001934)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0466667150077840625632675)), (vcast_vd_d_avx2_sleef(-0.0523674852303482457616113)))))))), (vmla_vd_vd_vd_vd_avx2_sleef((t4), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0587666392926673580854313)), (vcast_vd_d_avx2_sleef(-0.0666573579361080525984562)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.0769219538311769618355029)), (vcast_vd_d_avx2_sleef(-0.090908995008245008229153)))))), (vmla_vd_vd_vd_vd_avx2_sleef((t2), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.111111105648261418443745)), (vcast_vd_d_avx2_sleef(-0.14285714266771329383765)))), (vmla_vd_vd_vd_vd_avx2_sleef((t), (vcast_vd_d_avx2_sleef(0.199999999996591265594148)), (vcast_vd_d_avx2_sleef(-0.333333333333311110369124)))))))))))\n\n                                  ;\n\n  t = vmla_vd_vd_vd_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(t, u), s);\n\n  t = vsel_vd_vo_vd_vd_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(1)), vcast_vi_i_avx2_sleef(1))), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3.141592653589793238462643383279502884/2), t), t);\n  t = vreinterpret_vd_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo64_vm_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(2)), vcast_vi_i_avx2_sleef(2))), vreinterpret_vm_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-0.0))), vreinterpret_vm_vd_avx2_sleef(t)));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_logd4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef x, x2;\n  vdouble_avx2_sleef t, m;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = vdiv_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(1)), vadd_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), m));\n  x2 = vmul_vd_vd_vd_avx2_sleef(x, x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x3 = vmul_vd_vd_vd_avx2_sleef(x, x2);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(0.153487338491425068243146)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.152519917006351951593857)), (vcast_vd_d_avx2_sleef(0.181863266251982985677316)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.222221366518767365905163)), (vcast_vd_d_avx2_sleef(0.285714294746548025383248)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.399999999950799600689777)), (vcast_vd_d_avx2_sleef(0.6666666666667778740063)))))))\n\n                              ;\n\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2), vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.693147180559945286226764), vcast_vd_vi_avx2_sleef(e)));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x3, t, x);\n\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vispinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(__builtin_inf()), x);\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), x);\n  x = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(-__builtin_inf()), x);\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_expd4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931))), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-.69314718055966295651160180568695068359375), d);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-.28235290563031577122588448175013436025525412068e-12), s);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.2081276378237164457e-8)), (vcast_vd_d_avx2_sleef(+0.2511210703042288022e-7)))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.2755762628169491192e-6)), (vcast_vd_d_avx2_sleef(+0.2755723402025388239e-5)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.2480158687479686264e-4)), (vcast_vd_d_avx2_sleef(+0.1984126989855865850e-3)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1388888888914497797e-2)), (vcast_vd_d_avx2_sleef(+0.8333333333314938210e-2)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.4166666666666602598e-1)), (vcast_vd_d_avx2_sleef(+0.1666666666666669072e+0)))))))))\n\n                                ;\n  u = vfma_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.5000000000000000000e+0));\n  u = vfma_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1000000000000000000e+1));\n  u = vfma_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1000000000000000000e+1));\n\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  vopmask_avx2_sleef o = vgt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(7.09782712893383973e+02));\n  u = vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-1000)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef expm1k_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931))), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-.69314718055966295651160180568695068359375), d);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-.28235290563031577122588448175013436025525412068e-12), s);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(2.08860621107283687536341e-09)), (vcast_vd_d_avx2_sleef(2.51112930892876518610661e-08)))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(2.75573911234900471893338e-07)), (vcast_vd_d_avx2_sleef(2.75572362911928827629423e-06)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(2.4801587159235472998791e-05)), (vcast_vd_d_avx2_sleef(0.000198412698960509205564975)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(0.00138888888889774492207962)), (vcast_vd_d_avx2_sleef(0.00833333333331652721664984)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(0.0416666666666665047591422)), (vcast_vd_d_avx2_sleef(0.166666666666666851703837)))))))))\n\n                                 ;\n\n  u = vadd_vd_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(s2, vcast_vd_d_avx2_sleef(0.5), vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(s2, s), u)), s);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(q, vcast_vi_i_avx2_sleef(0))), u,\n         vsub_vd_vd_vd_avx2_sleef(vldexp2_vd_vd_vi_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(1)), q), vcast_vd_d_avx2_sleef(1)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef logk_avx2_sleef(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x, x2, s;\n  vdouble_avx2_sleef t, m;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1), m), ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), m));\n  x2 = ddsqu_vd2_vd2_avx2_sleef(x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x2), vd2getx_vd_vd2_avx2_sleef(x2)), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vcast_vd_d_avx2_sleef(0.116255524079935043668677)), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.103239680901072952701192)), (vcast_vd_d_avx2_sleef(0.117754809412463995466069)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.13332981086846273921509)), (vcast_vd_d_avx2_sleef(0.153846227114512262845736)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.181818180850050775676507)), (vcast_vd_d_avx2_sleef(0.222222222230083560345903)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.285714285714249172087875)), (vcast_vd_d_avx2_sleef(0.400000000000000077715612)))))))))\n\n                                ;\n\n  vdouble2_avx2_sleef c = vcast_vd2_d_d_avx2_sleef(0.666666666666666629659233, 3.80554962542412056336616e-17);\n\n  s = ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_avx2_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n  x = ddmul_vd2_vd2_vd2_avx2_sleef(x2, x);\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddmul_vd2_vd2_vd2_avx2_sleef(x, c));\n  x = ddmul_vd2_vd2_vd2_avx2_sleef(x2, x);\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddmul_vd2_vd2_vd_avx2_sleef(x, t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_logd4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x;\n  vdouble_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1), m), ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), m));\n  x2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x));\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(0.1532076988502701353e+0)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.1525629051003428716e+0)), (vcast_vd_d_avx2_sleef(0.1818605932937785996e+0)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.2222214519839380009e+0)), (vcast_vd_d_avx2_sleef(0.2857142932794299317e+0)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.3999999999635251990e+0)), (vcast_vd_d_avx2_sleef(0.6666666666667333541e+0)))))))\n\n                              ;\n\n  vdouble2_avx2_sleef s = ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_avx2_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n  s = ddadd_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)), t));\n\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2gety_vd_vd2_avx2_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vispinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef expk_avx2_sleef(vdouble2_avx2_sleef d) {\n  vdouble_avx2_sleef u = vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)), vcast_vd_d_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931));\n  vdouble_avx2_sleef dq = vrint_vd_vd_avx2_sleef(u);\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(dq);\n  vdouble2_avx2_sleef s, t;\n\n  s = ddadd2_vd2_vd2_vd_avx2_sleef(d, vmul_vd_vd_vd_avx2_sleef(dq, vcast_vd_d_avx2_sleef(-.69314718055966295651160180568695068359375)));\n  s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dq, vcast_vd_d_avx2_sleef(-.28235290563031577122588448175013436025525412068e-12)));\n\n  s = ddnormalize_vd2_vd2_avx2_sleef(s);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2getx_vd_vd2_avx2_sleef(s)), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.51069683420950419527139e-08)), (vcast_vd_d_avx2_sleef(2.76286166770270649116855e-07)))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(2.75572496725023574143864e-06)), (vcast_vd_d_avx2_sleef(2.48014973989819794114153e-05)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(0.000198412698809069797676111)), (vcast_vd_d_avx2_sleef(0.0013888888939977128960529)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(0.00833333333332371417601081)), (vcast_vd_d_avx2_sleef(0.0416666666665409524128449)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(0.166666666666666740681535)), (vcast_vd_d_avx2_sleef(0.500000000000000999200722)))))))))\n\n                                 ;\n\n  t = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), s);\n  t = ddadd_vd2_vd2_vd2_avx2_sleef(t, ddmul_vd2_vd2_vd_avx2_sleef(ddsqu_vd2_vd2_avx2_sleef(s), u));\n\n  u = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), vd2gety_vd_vd2_avx2_sleef(t));\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(-1000)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_powd4_u10avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vopmask_avx2_sleef yisint = visint_vo_vd_avx2_sleef(y);\n  vopmask_avx2_sleef yisodd = vand_vo_vo_vo_avx2_sleef(visodd_vo_vd_avx2_sleef(y), yisint);\n\n  vdouble2_avx2_sleef d = ddmul_vd2_vd2_vd_avx2_sleef(logk_avx2_sleef(vabs_vd_vd_avx2_sleef(x)), y);\n  vdouble_avx2_sleef result = expk_avx2_sleef(d);\n  vopmask_avx2_sleef o = vgt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(7.09782712893383973e+02));\n  result = vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(__builtin_inf()), result);\n\n  result = vmul_vd_vd_vd_avx2_sleef(result,\n    vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)),\n       vcast_vd_d_avx2_sleef(1),\n       vsel_vd_vo_vd_vd_avx2_sleef(yisint, vsel_vd_vo_vd_vd_avx2_sleef(yisodd, vcast_vd_d_avx2_sleef(-1.0), vcast_vd_d_avx2_sleef(1)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")))));\n\n  vdouble_avx2_sleef efx = vmulsign_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(1)), y);\n\n  result = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(y),\n       vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(efx, vcast_vd_d_avx2_sleef(0.0)),\n          vreinterpret_vm_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(efx, vcast_vd_d_avx2_sleef(0.0)),\n                  vcast_vd_d_avx2_sleef(1.0),\n                  vcast_vd_d_avx2_sleef(__builtin_inf()))))),\n       result);\n\n  result = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0.0))),\n       vmulsign_vd_vd_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(vxor_vo_vo_vo_avx2_sleef(vsignbit_vo_vd_avx2_sleef(y), veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0.0))),\n              vcast_vd_d_avx2_sleef(0), vcast_vd_d_avx2_sleef(__builtin_inf())),\n           vsel_vd_vo_vd_vd_avx2_sleef(yisodd, x, vcast_vd_d_avx2_sleef(1))), result);\n\n  result = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vreinterpret_vm_vd_avx2_sleef(result)));\n\n  result = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0)), veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1))), vcast_vd_d_avx2_sleef(1), result);\n\n  return result;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef expk2_avx2_sleef(vdouble2_avx2_sleef d) {\n  vdouble_avx2_sleef u = vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)), vcast_vd_d_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931));\n  vdouble_avx2_sleef dq = vrint_vd_vd_avx2_sleef(u);\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(dq);\n  vdouble2_avx2_sleef s, t;\n\n  s = ddadd2_vd2_vd2_vd_avx2_sleef(d, vmul_vd_vd_vd_avx2_sleef(dq, vcast_vd_d_avx2_sleef(-.69314718055966295651160180568695068359375)));\n  s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(dq, vcast_vd_d_avx2_sleef(-.28235290563031577122588448175013436025525412068e-12)));\n\n  vdouble2_avx2_sleef s2 = ddsqu_vd2_vd2_avx2_sleef(s), s4 = ddsqu_vd2_vd2_avx2_sleef(s2);\n  vdouble_avx2_sleef s8 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s4), vd2getx_vd_vd2_avx2_sleef(s4));\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.1602472219709932072e-9)), (vcast_vd_d_avx2_sleef(+0.2092255183563157007e-8)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s4)), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s2)), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.2505230023782644465e-7)), (vcast_vd_d_avx2_sleef(+0.2755724800902135303e-6)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.2755731892386044373e-5)), (vcast_vd_d_avx2_sleef(+0.2480158735605815065e-4)))))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s2)), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.1984126984148071858e-3)), (vcast_vd_d_avx2_sleef(+0.1388888888886763255e-2)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(s)), (vcast_vd_d_avx2_sleef(+0.8333333333333347095e-2)), (vcast_vd_d_avx2_sleef(+0.4166666666666669905e-1)))))))))\n\n                                ;\n\n  t = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), ddmul_vd2_vd2_vd_avx2_sleef(s, vcast_vd_d_avx2_sleef(+0.1666666666666666574e+0)));\n  t = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1.0), ddmul_vd2_vd2_vd2_avx2_sleef(t, s));\n  t = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1.0), ddmul_vd2_vd2_vd2_avx2_sleef(t, s));\n  t = ddadd_vd2_vd2_vd2_avx2_sleef(t, ddmul_vd2_vd2_vd_avx2_sleef(s4, u));\n\n  t = vd2setx_vd2_vd2_vd_avx2_sleef(t, vldexp2_vd_vd_vi_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), q));\n  t = vd2sety_vd2_vd2_vd_avx2_sleef(t, vldexp2_vd_vd_vi_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(t), q));\n\n  t = vd2setx_vd2_vd2_vd_avx2_sleef(t, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(-1000)), vreinterpret_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t)))));\n  t = vd2sety_vd2_vd2_vd_avx2_sleef(t, vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(-1000)), vreinterpret_vm_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(t)))));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sinhd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef y = vabs_vd_vd_avx2_sleef(x);\n  vdouble2_avx2_sleef d = expk2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0)));\n  d = ddsub_vd2_vd2_vd2_avx2_sleef(d, ddrec_vd2_vd2_avx2_sleef(d));\n  y = vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(710)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_inf()), y);\n  y = vmulsign_vd_vd_vd_avx2_sleef(y, x);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_coshd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef y = vabs_vd_vd_avx2_sleef(x);\n  vdouble2_avx2_sleef d = expk2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0)));\n  d = ddadd_vd2_vd2_vd2_avx2_sleef(d, ddrec_vd2_vd2_avx2_sleef(d));\n  y = vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(710)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_tanhd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef y = vabs_vd_vd_avx2_sleef(x);\n  vdouble2_avx2_sleef d = expk2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0)));\n  vdouble2_avx2_sleef e = ddrec_vd2_vd2_avx2_sleef(d);\n  d = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd2_avx2_sleef(d, ddneg_vd2_vd2_avx2_sleef(e)), ddadd2_vd2_vd2_vd2_avx2_sleef(d, e));\n  y = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(18.714973875)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(1.0), y);\n  y = vmulsign_vd_vd_vd_avx2_sleef(y, x);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sinhd4_u35avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef e = expm1k_avx2_sleef(vabs_vd_vd_avx2_sleef(x));\n\n  vdouble_avx2_sleef y = vdiv_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(e, vcast_vd_d_avx2_sleef(2)), vadd_vd_vd_vd_avx2_sleef(e, vcast_vd_d_avx2_sleef(1)));\n  y = vmul_vd_vd_vd_avx2_sleef(y, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), e));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(709)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_inf()), y);\n  y = vmulsign_vd_vd_vd_avx2_sleef(y, x);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_coshd4_u35avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef e = Sleef_expd4_u10avx2(vabs_vd_vd_avx2_sleef(x));\n  vdouble_avx2_sleef y = vmla_vd_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), e, vdiv_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), e));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(709)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_tanhd4_u35avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef d = expm1k_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2), vabs_vd_vd_avx2_sleef(x)));\n  vdouble_avx2_sleef y = vdiv_vd_vd_vd_avx2_sleef(d, vadd_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2), d));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(18.714973875)), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(1.0), y);\n  y = vmulsign_vd_vd_vd_avx2_sleef(y, x);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef logk2_avx2_sleef(vdouble2_avx2_sleef d) {\n  vdouble2_avx2_sleef x, x2, m, s;\n  vdouble_avx2_sleef t;\n  vint_avx2_sleef e;\n\n  e = vilogbk_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(1.0/0.75)));\n\n  m = vd2setxy_vd2_vd_vd_avx2_sleef(vldexp2_vd_vd_vi_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vneg_vi_vi_avx2_sleef(e)),\n    vldexp2_vd_vd_vi_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(d), vneg_vi_vi_avx2_sleef(e)));\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(-1)), ddadd2_vd2_vd2_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(1)));\n  x2 = ddsqu_vd2_vd2_avx2_sleef(x);\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x2), vd2getx_vd_vd2_avx2_sleef(x2)), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(0.13860436390467167910856)), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.131699838841615374240845)), (vcast_vd_d_avx2_sleef(0.153914168346271945653214)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.181816523941564611721589)), (vcast_vd_d_avx2_sleef(0.22222224632662035403996)))), (vmla_vd_vd_vd_vd_avx2_sleef((vd2getx_vd_vd2_avx2_sleef(x2)), (vcast_vd_d_avx2_sleef(0.285714285511134091777308)), (vcast_vd_d_avx2_sleef(0.400000000000914013309483)))))))\n\n                                ;\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(x2), vcast_vd_d_avx2_sleef(0.666666666666664853302393));\n\n  s = ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_avx2_sleef(e));\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddmul_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(x2, x), t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_asinhd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef y = vabs_vd_vd_avx2_sleef(x);\n  vopmask_avx2_sleef o = vgt_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(1));\n  vdouble2_avx2_sleef d;\n\n  d = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddrec_vd2_vd_avx2_sleef(x), vcast_vd2_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0)));\n  d = ddsqrt_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(ddsqu_vd2_vd2_avx2_sleef(d), vcast_vd_d_avx2_sleef(1)));\n  d = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddmul_vd2_vd2_vd_avx2_sleef(d, y), d);\n\n  d = logk2_avx2_sleef(ddnormalize_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(d, x)));\n  y = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(1.3407807929942596355e+154)),\n        visnan_vo_vd_avx2_sleef(y)),\n         vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(__builtin_inf()), x), y);\n\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n  y = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(-0.0), y);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_acoshd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble2_avx2_sleef d = logk2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddsqrt_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1))), ddsqrt_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(-1)))), x));\n  vdouble_avx2_sleef y = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d));\n\n  y = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(1.3407807929942596355e+154)),\n        visnan_vo_vd_avx2_sleef(y)),\n         vcast_vd_d_avx2_sleef(__builtin_inf()), y);\n  y = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0)), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.0)), vreinterpret_vm_vd_avx2_sleef(y)));\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_atanhd4_u10avx2(vdouble_avx2_sleef x) {\n  vdouble_avx2_sleef y = vabs_vd_vd_avx2_sleef(x);\n  vdouble2_avx2_sleef d = logk2_avx2_sleef(dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), y), ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vneg_vd_vd_avx2_sleef(y))));\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(1.0)), vreinterpret_vm_vd_avx2_sleef(vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(1.0)), vcast_vd_d_avx2_sleef(__builtin_inf()), vmul_vd_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d)), vcast_vd_d_avx2_sleef(0.5))))));\n\n  y = vmulsign_vd_vd_vd_avx2_sleef(y, x);\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vreinterpret_vm_vd_avx2_sleef(y)));\n  y = vreinterpret_vd_vm_avx2_sleef(vor_vm_vo64_vm_avx2_sleef(visnan_vo_vd_avx2_sleef(x), vreinterpret_vm_vd_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_cbrtd4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef x, y, q = vcast_vd_d_avx2_sleef(1.0);\n  vint_avx2_sleef e, qu, re;\n  vdouble_avx2_sleef t;\n\n  e = vadd_vi_vi_vi_avx2_sleef(vilogbk_vi_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d)), vcast_vi_i_avx2_sleef(1));\n  d = vldexp2_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n\n  t = vadd_vd_vd_vd_avx2_sleef(vcast_vd_vi_avx2_sleef(e), vcast_vd_d_avx2_sleef(6144));\n  qu = vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(t, vcast_vd_d_avx2_sleef(1.0/3.0)));\n  re = vtruncate_vi_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(t, vmul_vd_vd_vd_avx2_sleef(vcast_vd_vi_avx2_sleef(qu), vcast_vd_d_avx2_sleef(3))));\n\n  q = vsel_vd_vo_vd_vd_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(re, vcast_vi_i_avx2_sleef(1))), vcast_vd_d_avx2_sleef(1.2599210498948731647672106), q);\n  q = vsel_vd_vo_vd_vd_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(re, vcast_vi_i_avx2_sleef(2))), vcast_vd_d_avx2_sleef(1.5874010519681994747517056), q);\n  q = vldexp2_vd_vd_vi_avx2_sleef(q, vsub_vi_vi_vi_avx2_sleef(qu, vcast_vi_i_avx2_sleef(2048)));\n\n  q = vmulsign_vd_vd_vd_avx2_sleef(q, d);\n\n  d = vabs_vd_vd_avx2_sleef(d);\n\n  x = vcast_vd_d_avx2_sleef(-0.640245898480692909870982);\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(2.96155103020039511818595));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(-5.73353060922947843636166));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(6.03990368989458747961407));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(-3.85841935510444988821632));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(2.2307275302496609725722));\n\n  y = vmul_vd_vd_vd_avx2_sleef(x, x); y = vmul_vd_vd_vd_avx2_sleef(y, y); x = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vmlapn_vd_vd_vd_vd_avx2_sleef(d, y, x), vcast_vd_d_avx2_sleef(1.0 / 3.0)));\n  y = vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, x), x);\n  y = vmul_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(y, vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2.0 / 3.0), y), vmla_vd_vd_vd_vd_avx2_sleef(y, x, vcast_vd_d_avx2_sleef(-1.0)))), q);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_cbrtd4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef x, y, z, t;\n  vdouble2_avx2_sleef q2 = vcast_vd2_d_d_avx2_sleef(1, 0), u, v;\n  vint_avx2_sleef e, qu, re;\n\n  e = vadd_vi_vi_vi_avx2_sleef(vilogbk_vi_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(d)), vcast_vi_i_avx2_sleef(1));\n  d = vldexp2_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n\n  t = vadd_vd_vd_vd_avx2_sleef(vcast_vd_vi_avx2_sleef(e), vcast_vd_d_avx2_sleef(6144));\n  qu = vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(t, vcast_vd_d_avx2_sleef(1.0/3.0)));\n  re = vtruncate_vi_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(t, vmul_vd_vd_vd_avx2_sleef(vcast_vd_vi_avx2_sleef(qu), vcast_vd_d_avx2_sleef(3))));\n\n  q2 = vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(re, vcast_vi_i_avx2_sleef(1))), vcast_vd2_d_d_avx2_sleef(1.2599210498948731907, -2.5899333753005069177e-17), q2);\n  q2 = vsel_vd2_vo_vd2_vd2_avx2_sleef(vcast_vo64_vo32_avx2_sleef(veq_vo_vi_vi_avx2_sleef(re, vcast_vi_i_avx2_sleef(2))), vcast_vd2_d_d_avx2_sleef(1.5874010519681995834, -1.0869008194197822986e-16), q2);\n\n  q2 = vd2setxy_vd2_vd_vd_avx2_sleef(vmulsign_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(q2), d), vmulsign_vd_vd_vd_avx2_sleef(vd2gety_vd_vd2_avx2_sleef(q2), d));\n  d = vabs_vd_vd_avx2_sleef(d);\n\n  x = vcast_vd_d_avx2_sleef(-0.640245898480692909870982);\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(2.96155103020039511818595));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(-5.73353060922947843636166));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(6.03990368989458747961407));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(-3.85841935510444988821632));\n  x = vmla_vd_vd_vd_vd_avx2_sleef(x, d, vcast_vd_d_avx2_sleef(2.2307275302496609725722));\n\n  y = vmul_vd_vd_vd_avx2_sleef(x, x); y = vmul_vd_vd_vd_avx2_sleef(y, y); x = vsub_vd_vd_vd_avx2_sleef(x, vmul_vd_vd_vd_avx2_sleef(vmlapn_vd_vd_vd_vd_avx2_sleef(d, y, x), vcast_vd_d_avx2_sleef(1.0 / 3.0)));\n\n  z = x;\n\n  u = ddmul_vd2_vd_vd_avx2_sleef(x, x);\n  u = ddmul_vd2_vd2_vd2_avx2_sleef(u, u);\n  u = ddmul_vd2_vd2_vd_avx2_sleef(u, d);\n  u = ddadd2_vd2_vd2_vd_avx2_sleef(u, vneg_vd_vd_avx2_sleef(x));\n  y = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(u), vd2gety_vd_vd2_avx2_sleef(u));\n\n  y = vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-2.0 / 3.0), y), z);\n  v = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd_vd_avx2_sleef(z, z), y);\n  v = ddmul_vd2_vd2_vd_avx2_sleef(v, d);\n  v = ddmul_vd2_vd2_vd2_avx2_sleef(v, q2);\n  z = vldexp2_vd_vd_vi_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(v), vd2gety_vd_vd2_avx2_sleef(v)), vsub_vi_vi_vi_avx2_sleef(qu, vcast_vi_i_avx2_sleef(2048)));\n\n  z = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(d), vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(__builtin_inf()), vd2getx_vd_vd2_avx2_sleef(q2)), z);\n  z = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vreinterpret_vd_vm_avx2_sleef(vsignbit_vm_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(q2))), z);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_exp2d4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(d), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vsub_vd_vd_vd_avx2_sleef(d, u);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.4434359082926529454e-9)), (vcast_vd_d_avx2_sleef(+0.7073164598085707425e-8)))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1017819260921760451e-6)), (vcast_vd_d_avx2_sleef(+0.1321543872511327615e-5)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1525273353517584730e-4)), (vcast_vd_d_avx2_sleef(+0.1540353045101147808e-3)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1333355814670499073e-2)), (vcast_vd_d_avx2_sleef(+0.9618129107597600536e-2)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.5550410866482046596e-1)), (vcast_vd_d_avx2_sleef(+0.2402265069591012214e+0)))))))))\n\n                                ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.6931471805599452862e+0));\n\n  u = vfma_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1));\n\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(vge_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1024)), vcast_vd_d_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-2000)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_exp2d4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(d), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vsub_vd_vd_vd_avx2_sleef(d, u);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.4434359082926529454e-9)), (vcast_vd_d_avx2_sleef(+0.7073164598085707425e-8)))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1017819260921760451e-6)), (vcast_vd_d_avx2_sleef(+0.1321543872511327615e-5)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1525273353517584730e-4)), (vcast_vd_d_avx2_sleef(+0.1540353045101147808e-3)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1333355814670499073e-2)), (vcast_vd_d_avx2_sleef(+0.9618129107597600536e-2)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.5550410866482046596e-1)), (vcast_vd_d_avx2_sleef(+0.2402265069591012214e+0)))))))))\n\n                                ;\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.6931471805599452862e+0));\n\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1));\n\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(vge_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1024)), vcast_vd_d_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-2000)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_exp10d4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-0.30102999566383914498), d);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-1.4205023227266099418e-13), s);\n\n  u = vcast_vd_d_avx2_sleef(+0.2411463498334267652e-3);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1157488415217187375e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.5013975546789733659e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1959762320720533080e-1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.6808936399446784138e-1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.2069958494722676234e+0));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.5393829292058536229e+0));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.1171255148908541655e+1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.2034678592293432953e+1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.2650949055239205876e+1));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(+0.2302585092994045901e+1));\n\n  u = vfma_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1));\n\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(308.25471555991671)), vcast_vd_d_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-350)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_exp10d4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef u = vrint_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint_avx2_sleef q = vrint_vi_vd_avx2_sleef(u);\n\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-0.30102999566383914498), d);\n  s = vmla_vd_vd_vd_vd_avx2_sleef(u, vcast_vd_d_avx2_sleef(-1.4205023227266099418e-13), s);\n\n  vdouble_avx2_sleef s2 = vmul_vd_vd_vd_avx2_sleef(s, s), s4 = vmul_vd_vd_vd_avx2_sleef(s2, s2), s8 = vmul_vd_vd_vd_avx2_sleef(s4, s4);\n  u = vmla_vd_vd_vd_vd_avx2_sleef((s8), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vcast_vd_d_avx2_sleef(+0.2411463498334267652e-3)), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1157488415217187375e-2)), (vcast_vd_d_avx2_sleef(+0.5013975546789733659e-2)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s4), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1959762320720533080e-1)), (vcast_vd_d_avx2_sleef(+0.6808936399446784138e-1)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.2069958494722676234e+0)), (vcast_vd_d_avx2_sleef(+0.5393829292058536229e+0)))))), (vmla_vd_vd_vd_vd_avx2_sleef((s2), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.1171255148908541655e+1)), (vcast_vd_d_avx2_sleef(+0.2034678592293432953e+1)))), (vmla_vd_vd_vd_vd_avx2_sleef((s), (vcast_vd_d_avx2_sleef(+0.2650949055239205876e+1)), (vcast_vd_d_avx2_sleef(+0.2302585092994045901e+1)))))))))\n\n                                ;\n\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, s, vcast_vd_d_avx2_sleef(1));\n\n  u = vldexp2_vd_vd_vi_avx2_sleef(u, q);\n\n  u = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(308.25471555991671)), vcast_vd_d_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vd_vm_avx2_sleef(vandnot_vm_vo64_vm_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-350)), vreinterpret_vm_vd_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_expm1d4_u10avx2(vdouble_avx2_sleef a) {\n  vdouble2_avx2_sleef d = ddadd2_vd2_vd2_vd_avx2_sleef(expk2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0))), vcast_vd_d_avx2_sleef(-1.0));\n  vdouble_avx2_sleef x = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(d), vd2gety_vd_vd2_avx2_sleef(d));\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(709.782712893383996732223)), vcast_vd_d_avx2_sleef(__builtin_inf()), x);\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(-36.736800569677101399113302437)), vcast_vd_d_avx2_sleef(-1), x);\n  x = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(a), vcast_vd_d_avx2_sleef(-0.0), x);\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_log10d4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x;\n  vdouble_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1), m), ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), m));\n  x2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x));\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(+0.6653725819576758460e-1)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.6625722782820833712e-1)), (vcast_vd_d_avx2_sleef(+0.7898105214313944078e-1)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.9650955035715275132e-1)), (vcast_vd_d_avx2_sleef(+0.1240841409721444993e+0)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.1737177927454605086e+0)), (vcast_vd_d_avx2_sleef(+0.2895296546021972617e+0)))))))\n\n                               ;\n\n  vdouble2_avx2_sleef s = ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.30102999566398119802, -2.803728127785170339e-18), vcast_vd_vi_avx2_sleef(e));\n\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddmul_vd2_vd2_vd2_avx2_sleef(x, vcast_vd2_d_d_avx2_sleef(0.86858896380650363334, 1.1430059694096389311e-17)));\n  s = ddadd_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)), t));\n\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2gety_vd_vd2_avx2_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vispinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_log2d4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x;\n  vdouble_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1), m), ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), m));\n  x2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x));\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(+0.2211941750456081490e+0)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.2200768693152277689e+0)), (vcast_vd_d_avx2_sleef(+0.2623708057488514656e+0)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.3205977477944495502e+0)), (vcast_vd_d_avx2_sleef(+0.4121985945485324709e+0)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(+0.5770780162997058982e+0)), (vcast_vd_d_avx2_sleef(+0.96179669392608091449)))))))\n\n                             ;\n\n  vdouble2_avx2_sleef s = ddadd2_vd2_vd_vd2_avx2_sleef(vcast_vd_vi_avx2_sleef(e),\n     ddmul_vd2_vd2_vd2_avx2_sleef(x, vcast_vd2_d_d_avx2_sleef(2.885390081777926774, 6.0561604995516736434e-18)));\n\n  s = ddadd2_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)), t));\n\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2gety_vd_vd2_avx2_sleef(s));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vispinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_log2d4_u35avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef m, t, x, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), d);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vd_vd_vi_avx2_sleef(d, vneg_vi_vi_avx2_sleef(e));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n\n  x = vdiv_vd_vd_vd_avx2_sleef(vsub_vd_vd_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(1)), vadd_vd_vd_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(1)));\n  x2 = vmul_vd_vd_vd_avx2_sleef(x, x);\n\n  t = vcast_vd_d_avx2_sleef(+0.2211941750456081490e+0);\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.2200768693152277689e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.2623708057488514656e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.3205977477944495502e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.4121985945485324709e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.5770780162997058982e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, x2, vcast_vd_d_avx2_sleef(+0.96179669392608091449 ));\n\n  vdouble2_avx2_sleef s = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_vi_avx2_sleef(e),\n    ddmul_vd2_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2.885390081777926774)));\n\n  vdouble_avx2_sleef r = vmla_vd_vd_vd_vd_avx2_sleef(t, vmul_vd_vd_vd_avx2_sleef(x, x2), vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2gety_vd_vd2_avx2_sleef(s)));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vispinf_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_log1pd4_u10avx2(vdouble_avx2_sleef d) {\n  vdouble2_avx2_sleef x;\n  vdouble_avx2_sleef t, m, x2;\n\n  vdouble_avx2_sleef dp1 = vadd_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1));\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(dp1, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  dp1 = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(dp1, vcast_vd_d_avx2_sleef((double)(INT64_C(1) << 32) * (double)(INT64_C(1) << 32))), dp1);\n  vint_avx2_sleef e = vilogb2k_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(dp1, vcast_vd_d_avx2_sleef(1.0/0.75)));\n  t = vldexp3_vd_vd_vi_avx2_sleef(vcast_vd_d_avx2_sleef(1), vneg_vi_vi_avx2_sleef(e));\n  m = vmla_vd_vd_vd_vd_avx2_sleef(d, t, vsub_vd_vd_vd_avx2_sleef(t, vcast_vd_d_avx2_sleef(1)));\n  e = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(o), vsub_vi_vi_vi_avx2_sleef(e, vcast_vi_i_avx2_sleef(64)), e);\n  vdouble2_avx2_sleef s = ddmul_vd2_vd2_vd_avx2_sleef(vcast_vd2_d_d_avx2_sleef(0.693147180559945286226764, 2.319046813846299558417771e-17), vcast_vd_vi_avx2_sleef(e));\n\n  x = dddiv_vd2_vd2_vd2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(m, vcast_vd_d_avx2_sleef(0)), ddadd_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2), m));\n  x2 = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2getx_vd_vd2_avx2_sleef(x));\n\n  vdouble_avx2_sleef x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2), x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4);\n  t = vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(0.1532076988502701353e+0)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.1525629051003428716e+0)), (vcast_vd_d_avx2_sleef(0.1818605932937785996e+0)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.2222214519839380009e+0)), (vcast_vd_d_avx2_sleef(0.2857142932794299317e+0)))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vcast_vd_d_avx2_sleef(0.3999999999635251990e+0)), (vcast_vd_d_avx2_sleef(0.6666666666667333541e+0)))))))\n\n                              ;\n\n  s = ddadd_vd2_vd2_vd2_avx2_sleef(s, ddscale_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)));\n  s = ddadd_vd2_vd2_vd_avx2_sleef(s, vmul_vd_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x2, vd2getx_vd_vd2_avx2_sleef(x)), t));\n\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(s), vd2gety_vd_vd2_avx2_sleef(s));\n\n  vopmask_avx2_sleef ocore = vle_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(9.99999999999999986e+306));\n  if(!__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef (ocore)), 1)) r = vsel_vd_vo_vd_vd_avx2_sleef(ocore, r, Sleef_logd4_u10avx2(d));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-1)), visnan_vo_vd_avx2_sleef(d)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(-1)), vcast_vd_d_avx2_sleef(-__builtin_inf()), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visnegzero_vo_vd_avx2_sleef(d), vcast_vd_d_avx2_sleef(-0.0), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fabsd4_avx2(vdouble_avx2_sleef x) { return vabs_vd_vd_avx2_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_copysignd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) { return vcopysign_vd_vd_vd_avx2_sleef(x, y); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fmaxd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n\n  return vsel_vd_vo_vd_vd_avx2_sleef(visnan_vo_vd_avx2_sleef(y), x, vmax_vd_vd_vd_avx2_sleef(x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fmind4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n\n  return vsel_vd_vo_vd_vd_avx2_sleef(visnan_vo_vd_avx2_sleef(y), x, vmin_vd_vd_vd_avx2_sleef(x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fdimd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef ret = vsub_vd_vd_vd_avx2_sleef(x, y);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(ret, vcast_vd_d_avx2_sleef(0)), veq_vo_vd_vd_avx2_sleef(x, y)), vcast_vd_d_avx2_sleef(0), ret);\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_truncd4_avx2(vdouble_avx2_sleef x) { return vtruncate2_vd_vd_avx2_sleef_avx2_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_floord4_avx2(vdouble_avx2_sleef x) { return vfloor2_vd_vd_avx2_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_ceild4_avx2(vdouble_avx2_sleef x) { return vceil2_vd_vd_avx2_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_roundd4_avx2(vdouble_avx2_sleef x) { return vround2_vd_vd_avx2_sleef(x); }\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_rintd4_avx2(vdouble_avx2_sleef x) { return vrint2_vd_vd_avx2_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_nextafterd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  x = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0), y), x);\n  vmask_avx2_sleef xi2 = vreinterpret_vm_vd_avx2_sleef(x);\n  vopmask_avx2_sleef c = vxor_vo_vo_vo_avx2_sleef(vsignbit_vo_vd_avx2_sleef(x), vge_vo_vd_vd_avx2_sleef(y, x));\n\n  xi2 = vsel_vm_vo64_vm_vm_avx2_sleef(c, vneg64_vm_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(xi2, vcast_vm_i_i_avx2_sleef((int)(1U << 31), 0))), xi2);\n\n  xi2 = vsel_vm_vo64_vm_vm_avx2_sleef(vneq_vo_vd_vd_avx2_sleef(x, y), vsub64_vm_vm_vm_avx2_sleef(xi2, vcast_vm_i_i_avx2_sleef(0, 1)), xi2);\n\n  xi2 = vsel_vm_vo64_vm_vm_avx2_sleef(c, vneg64_vm_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(xi2, vcast_vm_i_i_avx2_sleef((int)(1U << 31), 0))), xi2);\n\n  vdouble_avx2_sleef ret = vreinterpret_vd_vm_avx2_sleef(xi2);\n\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(ret, vcast_vd_d_avx2_sleef(0)), vneq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0))),\n    vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0), x), ret);\n\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(0))), y, ret);\n\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_frfrexpd4_avx2(vdouble_avx2_sleef x) {\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(2.22507385850720138e-308)), vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(UINT64_C(1) << 63)), x);\n\n  vmask_avx2_sleef xm = vreinterpret_vm_vd_avx2_sleef(x);\n  xm = vand_vm_vm_vm_avx2_sleef(xm, vcast_vm_i64_avx2_sleef(~INT64_C(0x7ff0000000000000)));\n  xm = vor_vm_vm_vm_avx2_sleef (xm, vcast_vm_i64_avx2_sleef( INT64_C(0x3fe0000000000000)));\n\n  vdouble_avx2_sleef ret = vreinterpret_vd_vm_avx2_sleef(xm);\n\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(x), vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(__builtin_inf()), x), ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), x, ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vint_avx2_sleef Sleef_expfrexpd4_avx2(vdouble_avx2_sleef x) {\n  x = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(2.22507385850720138e-308)), vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(UINT64_C(1) << 63)), x);\n\n  vint_avx2_sleef ret = vcastu_vi_vm_avx2_sleef(vreinterpret_vm_vd_avx2_sleef(x));\n  ret = vsub_vi_vi_vi_avx2_sleef(vand_vi_vi_vi_avx2_sleef(vsrl_vi_vi_i_avx2_sleef(ret, 20), vcast_vi_i_avx2_sleef(0x7ff)), vcast_vi_i_avx2_sleef(0x3fe));\n\n  ret = vsel_vi_vo_vi_vi_avx2_sleef(vcast_vo32_vo64_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(0)), visnan_vo_vd_avx2_sleef(x)), visinf_vo_vd_avx2_sleef(x))), vcast_vi_i_avx2_sleef(0), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fmad4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y, vdouble_avx2_sleef z) {\n  return vfma_vd_vd_vd_vd_avx2_sleef(x, y, z);\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sqrtd4_u05avx2(vdouble_avx2_sleef d) {\n  vdouble_avx2_sleef q, w, x, y, z;\n\n  d = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), d);\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(8.636168555094445E-78));\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.157920892373162E77)), d);\n  q = vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(2.9387358770557188E-39), vcast_vd_d_avx2_sleef(1));\n\n  y = vreinterpret_vd_vm_avx2_sleef(vsub64_vm_vm_vm_avx2_sleef(vcast_vm_i_i_avx2_sleef(0x5fe6ec85, 0xe7de30da), _mm256_srli_epi64(vreinterpret_vm_vd_avx2_sleef(d), 1)));\n\n  x = vmul_vd_vd_vd_avx2_sleef(d, y); w = vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), y);\n  y = vfmanp_vd_vd_vd_vd_avx2_sleef(x, w, vcast_vd_d_avx2_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_avx2_sleef(x, y, x); w = vfma_vd_vd_vd_vd_avx2_sleef(w, y, w);\n  y = vfmanp_vd_vd_vd_vd_avx2_sleef(x, w, vcast_vd_d_avx2_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_avx2_sleef(x, y, x); w = vfma_vd_vd_vd_vd_avx2_sleef(w, y, w);\n  y = vfmanp_vd_vd_vd_vd_avx2_sleef(x, w, vcast_vd_d_avx2_sleef(0.5));\n  x = vfma_vd_vd_vd_vd_avx2_sleef(x, y, x); w = vfma_vd_vd_vd_vd_avx2_sleef(w, y, w);\n\n  y = vfmanp_vd_vd_vd_vd_avx2_sleef(x, w, vcast_vd_d_avx2_sleef(1.5)); w = vadd_vd_vd_vd_avx2_sleef(w, w);\n  w = vmul_vd_vd_vd_avx2_sleef(w, y);\n  x = vmul_vd_vd_vd_avx2_sleef(w, d);\n  y = vfmapn_vd_vd_vd_vd_avx2_sleef(w, d, x); z = vfmanp_vd_vd_vd_vd_avx2_sleef(w, x, vcast_vd_d_avx2_sleef(1));\n\n  z = vfmanp_vd_vd_vd_vd_avx2_sleef(w, y, z); w = vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), x);\n  w = vfma_vd_vd_vd_vd_avx2_sleef(w, z, y);\n  w = vadd_vd_vd_vd_avx2_sleef(w, x);\n\n  w = vmul_vd_vd_vd_avx2_sleef(w, q);\n\n  w = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)),\n        veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(__builtin_inf()))), d, w);\n\n  w = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), w);\n\n  return w;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sqrtd4_avx2(vdouble_avx2_sleef d) {\n\n  return vsqrt_vd_vd_avx2_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_sqrtd4_u35avx2(vdouble_avx2_sleef d) { return Sleef_sqrtd4_u05avx2(d); }\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_hypotd4_u05avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  x = vabs_vd_vd_avx2_sleef(x);\n  y = vabs_vd_vd_avx2_sleef(y);\n  vdouble_avx2_sleef min = vmin_vd_vd_vd_avx2_sleef(x, y), n = min;\n  vdouble_avx2_sleef max = vmax_vd_vd_vd_avx2_sleef(x, y), d = max;\n\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(max, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  n = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), d);\n\n  vdouble2_avx2_sleef t = dddiv_vd2_vd2_vd2_avx2_sleef(vcast_vd2_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(0)), vcast_vd2_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)));\n  t = ddmul_vd2_vd2_vd_avx2_sleef(ddsqrt_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(ddsqu_vd2_vd2_avx2_sleef(t), vcast_vd_d_avx2_sleef(1))), max);\n  vdouble_avx2_sleef ret = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t), vd2gety_vd_vd2_avx2_sleef(t));\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(visnan_vo_vd_avx2_sleef(ret), vcast_vd_d_avx2_sleef(__builtin_inf()), ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(min, vcast_vd_d_avx2_sleef(0)), max, ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(__builtin_inf())), veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(__builtin_inf()))), vcast_vd_d_avx2_sleef(__builtin_inf()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_hypotd4_u35avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  x = vabs_vd_vd_avx2_sleef(x);\n  y = vabs_vd_vd_avx2_sleef(y);\n  vdouble_avx2_sleef min = vmin_vd_vd_vd_avx2_sleef(x, y);\n  vdouble_avx2_sleef max = vmax_vd_vd_vd_avx2_sleef(x, y);\n\n  vdouble_avx2_sleef t = vdiv_vd_vd_vd_avx2_sleef(min, max);\n  vdouble_avx2_sleef ret = vmul_vd_vd_vd_avx2_sleef(max, vsqrt_vd_vd_avx2_sleef(vmla_vd_vd_vd_vd_avx2_sleef(t, t, vcast_vd_d_avx2_sleef(1))));\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(min, vcast_vd_d_avx2_sleef(0)), max, ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vd_avx2_sleef(x), visnan_vo_vd_avx2_sleef(y)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(__builtin_inf())), veq_vo_vd_vd_avx2_sleef(y, vcast_vd_d_avx2_sleef(__builtin_inf()))), vcast_vd_d_avx2_sleef(__builtin_inf()), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble_avx2_sleef vptrunc_vd_vd_avx2_sleef(vdouble_avx2_sleef x) {\n\n  return vtruncate_vd_vd_avx2_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_fmodd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef n = vabs_vd_vd_avx2_sleef(x), d = vabs_vd_vd_avx2_sleef(y), s = vcast_vd_d_avx2_sleef(1), q;\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308));\n  n = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), d);\n  s = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(s , vcast_vd_d_avx2_sleef(1.0 / (UINT64_C(1) << 54))), s);\n  vdouble2_avx2_sleef r = vcast_vd2_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(0));\n  vdouble_avx2_sleef rd = vtoward0_vd_vd_avx2_sleef(vrec_vd_vd_avx2_sleef(d));\n\n  for(int i=0;i<21;i++) {\n    q = vptrunc_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vtoward0_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)), rd));\n    q = vsel_vd_vo_vd_vd_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(3), d), vd2getx_vd_vd2_avx2_sleef(r)),\n           vge_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), d)),\n    vcast_vd_d_avx2_sleef(2), q);\n    q = vsel_vd_vo_vd_vd_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vgt_vo_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(d, d), vd2getx_vd_vd2_avx2_sleef(r)),\n           vge_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), d)),\n    vcast_vd_d_avx2_sleef(1), q);\n    r = ddnormalize_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd2_avx2_sleef(r, ddmul_vd2_vd_vd_avx2_sleef(q, vneg_vd_vd_avx2_sleef(d))));\n    if (vtestallones_i_vo64_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), d))) break;\n  }\n\n  vdouble_avx2_sleef ret = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), s);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), vd2gety_vd_vd2_avx2_sleef(r)), d), vcast_vd_d_avx2_sleef(0), ret);\n\n  ret = vmulsign_vd_vd_vd_avx2_sleef(ret, x);\n\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(n, d), x, ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE vdouble_avx2_sleef vrintk2_vd_vd_avx2_sleef(vdouble_avx2_sleef d) {\n\n  return vrint_vd_vd_avx2_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_remainderd4_avx2(vdouble_avx2_sleef x, vdouble_avx2_sleef y) {\n  vdouble_avx2_sleef n = vabs_vd_vd_avx2_sleef(x), d = vabs_vd_vd_avx2_sleef(y), s = vcast_vd_d_avx2_sleef(1), q;\n  vopmask_avx2_sleef o = vlt_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(2.22507385850720138e-308*2));\n  n = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), n);\n  d = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(UINT64_C(1) << 54)), d);\n  s = vsel_vd_vo_vd_vd_avx2_sleef(o, vmul_vd_vd_vd_avx2_sleef(s , vcast_vd_d_avx2_sleef(1.0 / (UINT64_C(1) << 54))), s);\n  vdouble_avx2_sleef rd = vrec_vd_vd_avx2_sleef(d);\n  vdouble2_avx2_sleef r = vcast_vd2_vd_vd_avx2_sleef(n, vcast_vd_d_avx2_sleef(0));\n  vopmask_avx2_sleef qisodd = vneq_vo_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0), vcast_vd_d_avx2_sleef(0));\n\n  for(int i=0;i<21;i++) {\n    q = vrintk2_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), rd));\n    q = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)), vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(1.5))), vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1.0), vd2getx_vd_vd2_avx2_sleef(r)), q);\n    q = vsel_vd_vo_vd_vd_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)), vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.5))),\n          vandnot_vo_vo_vo_avx2_sleef(qisodd, veq_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r)), vmul_vd_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0.5))))),\n    vcast_vd_d_avx2_sleef(0.0), q);\n    if (vtestallones_i_vo64_avx2_sleef(veq_vo_vd_vd_avx2_sleef(q, vcast_vd_d_avx2_sleef(0)))) break;\n    q = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(q, vneg_vd_vd_avx2_sleef(d))), vadd_vd_vd_vd_avx2_sleef(q, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(-1), vd2getx_vd_vd2_avx2_sleef(r))), q);\n    qisodd = vxor_vo_vo_vo_avx2_sleef(qisodd, visodd_vo_vd_avx2_sleef(q));\n    r = ddnormalize_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd2_avx2_sleef(r, ddmul_vd2_vd_vd_avx2_sleef(q, vneg_vd_vd_avx2_sleef(d))));\n  }\n\n  vdouble_avx2_sleef ret = vmul_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(r), s);\n  ret = vmulsign_vd_vd_vd_avx2_sleef(ret, x);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(y), vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(x), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), x), ret);\n  ret = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(d, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), ret);\n  return ret;\n}\n\nstatic SLEEF_CONST dd2_avx2_sleef gammak_avx2_sleef(vdouble_avx2_sleef a) {\n  vdouble2_avx2_sleef clc = vcast_vd2_d_d_avx2_sleef(0, 0), clln = vcast_vd2_d_d_avx2_sleef(1, 0), clld = vcast_vd2_d_d_avx2_sleef(1, 0);\n  vdouble2_avx2_sleef x, y, z;\n  vdouble_avx2_sleef t, u;\n\n  vopmask_avx2_sleef otiny = vlt_vo_vd_vd_avx2_sleef(vabs_vd_vd_avx2_sleef(a), vcast_vd_d_avx2_sleef(1e-306)), oref = vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0.5));\n\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(otiny, vcast_vd2_d_d_avx2_sleef(0, 0),\n     vsel_vd2_vo_vd2_vd2_avx2_sleef(oref, ddadd2_vd2_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(1), vneg_vd_vd_avx2_sleef(a)),\n           vcast_vd2_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0))));\n\n  vopmask_avx2_sleef o0 = vand_vo_vo_vo_avx2_sleef(vle_vo_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(0.5), vd2getx_vd_vd2_avx2_sleef(x)), vle_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vcast_vd_d_avx2_sleef(1.1)));\n  vopmask_avx2_sleef o2 = vle_vo_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2.3), vd2getx_vd_vd2_avx2_sleef(x));\n\n  y = ddnormalize_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1)), x));\n  y = ddnormalize_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2)), y));\n  y = ddnormalize_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(3)), y));\n  y = ddnormalize_vd2_vd2_avx2_sleef(ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(4)), y));\n\n  vopmask_avx2_sleef o = vand_vo_vo_vo_avx2_sleef(o2, vle_vo_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vcast_vd_d_avx2_sleef(7)));\n  clln = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, y, clln);\n\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o, ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(5)), x);\n\n  t = vsel_vd_vo_vd_vd_avx2_sleef(o2, vrec_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x)), vd2getx_vd_vd2_avx2_sleef(ddnormalize_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vsel_vd_vo_d_d_avx2_sleef(o0, -1, -2)))));\n\n  u = vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -156.801412704022726379848862, +0.2947916772827614196e+2, +0.7074816000864609279e-7);\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +1.120804464289911606838558160000, +0.1281459691827820109e+3, +0.4009244333008730443e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +13.39798545514258921833306020000, +0.2617544025784515043e+3, +0.1040114641628246946e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.116546276599463200848033357000, +0.3287022855685790432e+3, +0.1508349150733329167e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -1.391801093265337481495562410000, +0.2818145867730348186e+3, +0.1288143074933901020e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.015056113040026424412918973400, +0.1728670414673559605e+3, +0.4744167749884993937e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.179540117061234856098844714000, +0.7748735764030416817e+2, -0.6554816306542489902e-7));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.002481743600264997730942489280, +0.2512856643080930752e+2, -0.3189252471452599844e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.029527880945699120504851034100, +0.5766792106140076868e+1, +0.1358883821470355377e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.000540164767892604515196325186, +0.7270275473996180571e+0, -0.4343931277157336040e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.006403362833808069794787256200, +0.8396709124579147809e-1, +0.9724785897406779555e-6));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.000162516262783915816896611252, -0.8211558669746804595e-1, -0.2036886057225966011e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.001914438498565477526465972390, +0.6828831828341884458e-1, +0.4373363141819725815e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +7.20489541602001055898311517e-05, -0.7712481339961671511e-1, -0.9439951268304008677e-5));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.000839498720672087279971000786, +0.8337492023017314957e-1, +0.2050727030376389804e-4));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -5.17179090826059219329394422e-05, -0.9094964931456242518e-1, -0.4492620183431184018e-4));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.000592166437353693882857342347, +0.1000996313575929358e+0, +0.9945751236071875931e-4));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +6.97281375836585777403743539e-05, -0.1113342861544207724e+0, -0.2231547599034983196e-3));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.000784039221720066627493314301, +0.1255096673213020875e+0, +0.5096695247101967622e-3));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.000229472093621399176949318732, -0.1440498967843054368e+0, -0.1192753911667886971e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, -0.002681327160493827160473958490, +0.1695571770041949811e+0, +0.2890510330742210310e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.003472222222222222222175164840, -0.2073855510284092762e+0, -0.7385551028674461858e-2));\n  u = vmla_vd_vd_vd_vd_avx2_sleef(u, t, vsel_vd_vo_vo_d_d_d_avx2_sleef(o2, o0, +0.083333333333333333335592087900, +0.2705808084277815939e+0, +0.2058080842778455335e-1));\n\n  y = ddmul_vd2_vd2_vd2_avx2_sleef(ddadd2_vd2_vd2_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(-0.5)), logk2_avx2_sleef(x));\n  y = ddadd2_vd2_vd2_vd2_avx2_sleef(y, ddneg_vd2_vd2_avx2_sleef(x));\n  y = ddadd2_vd2_vd2_vd2_avx2_sleef(y, vcast_vd2_d_d_avx2_sleef(0.91893853320467278056, -3.8782941580672414498e-17));\n\n  z = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd_vd_avx2_sleef (u, t), vsel_vd_vo_d_d_avx2_sleef(o0, -0.4006856343865314862e+0, -0.6735230105319810201e-1));\n  z = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd_avx2_sleef(z, t), vsel_vd_vo_d_d_avx2_sleef(o0, +0.8224670334241132030e+0, +0.3224670334241132030e+0));\n  z = ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd2_vd_avx2_sleef(z, t), vsel_vd_vo_d_d_avx2_sleef(o0, -0.5772156649015328655e+0, +0.4227843350984671345e+0));\n  z = ddmul_vd2_vd2_vd_avx2_sleef(z, t);\n\n  clc = vsel_vd2_vo_vd2_vd2_avx2_sleef(o2, y, z);\n\n  clld = vsel_vd2_vo_vd2_vd2_avx2_sleef(o2, ddadd2_vd2_vd2_vd_avx2_sleef(ddmul_vd2_vd_vd_avx2_sleef(u, t), vcast_vd_d_avx2_sleef(1)), clld);\n\n  y = clln;\n\n  clc = vsel_vd2_vo_vd2_vd2_avx2_sleef(otiny, vcast_vd2_d_d_avx2_sleef(83.1776616671934334590333, 3.67103459631568507221878e-15),\n       vsel_vd2_vo_vd2_vd2_avx2_sleef(oref, ddadd2_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(1.1447298858494001639, 1.026595116270782638e-17), ddneg_vd2_vd2_avx2_sleef(clc)), clc));\n  clln = vsel_vd2_vo_vd2_vd2_avx2_sleef(otiny, vcast_vd2_d_d_avx2_sleef(1, 0), vsel_vd2_vo_vd2_vd2_avx2_sleef(oref, clln, clld));\n\n  if (!vtestallones_i_vo64_avx2_sleef(vnot_vo64_vo64_avx2_sleef(oref))) {\n    t = vsub_vd_vd_vd_avx2_sleef(a, vmul_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(INT64_C(1) << 28), vcast_vd_vi_avx2_sleef(vtruncate_vi_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(1.0 / (INT64_C(1) << 28)))))));\n    x = ddmul_vd2_vd2_vd2_avx2_sleef(clld, sinpik_avx2_sleef(t));\n  }\n\n  clld = vsel_vd2_vo_vd2_vd2_avx2_sleef(otiny, vcast_vd2_vd_vd_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef((INT64_C(1) << 60)*(double)(INT64_C(1) << 60))), vcast_vd_d_avx2_sleef(0)),\n        vsel_vd2_vo_vd2_vd2_avx2_sleef(oref, x, y));\n\n  return dd2setab_dd2_vd2_vd2_avx2_sleef(clc, dddiv_vd2_vd2_vd2_avx2_sleef(clln, clld));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_tgammad4_u10avx2(vdouble_avx2_sleef a) {\n  dd2_avx2_sleef d = gammak_avx2_sleef(a);\n  vdouble2_avx2_sleef y = ddmul_vd2_vd2_vd2_avx2_sleef(expk2_avx2_sleef(dd2geta_vd2_dd2_avx2_sleef(d)), dd2getb_vd2_dd2_avx2_sleef(d));\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(y));\n  vopmask_avx2_sleef o;\n\n  o = vor_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(-__builtin_inf())),\n    vand_vo_vo_vo_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)), visint_vo_vd_avx2_sleef(a))),\n     vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(visnumber_vo_vd_avx2_sleef(a), vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0))), visnan_vo_vd_avx2_sleef(r)));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n\n  o = vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(__builtin_inf())), visnumber_vo_vd_avx2_sleef(a)),\n      vge_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(-2.22507385850720138e-308))),\n      vor_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)), vgt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(200))), visnan_vo_vd_avx2_sleef(r)));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(o, vmulsign_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(__builtin_inf()), a), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_lgammad4_u10avx2(vdouble_avx2_sleef a) {\n  dd2_avx2_sleef d = gammak_avx2_sleef(a);\n  vdouble2_avx2_sleef y = ddadd2_vd2_vd2_vd2_avx2_sleef(dd2geta_vd2_dd2_avx2_sleef(d), logk2_avx2_sleef(ddabs_vd2_vd2_avx2_sleef(dd2getb_vd2_dd2_avx2_sleef(d))));\n  vdouble_avx2_sleef r = vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(y), vd2gety_vd_vd2_avx2_sleef(y));\n  vopmask_avx2_sleef o;\n\n  o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vd_avx2_sleef(a),\n     vor_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vle_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)), visint_vo_vd_avx2_sleef(a)),\n    vand_vo_vo_vo_avx2_sleef(visnumber_vo_vd_avx2_sleef(a), visnan_vo_vd_avx2_sleef(r))));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(o, vcast_vd_d_avx2_sleef(__builtin_inf()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef ddmla_vd2_vd_vd2_vd2_avx2_sleef(vdouble_avx2_sleef x, vdouble2_avx2_sleef y, vdouble2_avx2_sleef z) {\n  return ddadd_vd2_vd2_vd2_avx2_sleef(z, ddmul_vd2_vd2_vd_avx2_sleef(y, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef poly2dd_b_avx2_sleef(vdouble_avx2_sleef x, vdouble2_avx2_sleef c1, vdouble2_avx2_sleef c0) { return ddmla_vd2_vd_vd2_vd2_avx2_sleef(x, c1, c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef poly2dd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef c1, vdouble2_avx2_sleef c0) { return ddmla_vd2_vd_vd2_vd2_avx2_sleef(x, vcast_vd2_vd_vd_avx2_sleef(c1, vcast_vd_d_avx2_sleef(0)), c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vdouble2_avx2_sleef poly4dd_avx2_sleef(vdouble_avx2_sleef x, vdouble_avx2_sleef c3, vdouble2_avx2_sleef c2, vdouble2_avx2_sleef c1, vdouble2_avx2_sleef c0) {\n  return ddmla_vd2_vd_vd2_vd2_avx2_sleef(vmul_vd_vd_vd_avx2_sleef(x, x), poly2dd_avx2_sleef(x, c3, c2), poly2dd_b_avx2_sleef(x, c1, c0));\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_erfd4_u10avx2(vdouble_avx2_sleef a) {\n  vdouble_avx2_sleef t, x = vabs_vd_vd_avx2_sleef(a);\n  vdouble2_avx2_sleef t2;\n  vdouble_avx2_sleef x2 = vmul_vd_vd_vd_avx2_sleef(x, x), x4 = vmul_vd_vd_vd_avx2_sleef(x2, x2);\n  vdouble_avx2_sleef x8 = vmul_vd_vd_vd_avx2_sleef(x4, x4), x16 = vmul_vd_vd_vd_avx2_sleef(x8, x8);\n  vopmask_avx2_sleef o25 = vle_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(2.5));\n\n  if (__builtin_expect(!!(vtestallones_i_vo64_avx2_sleef(o25)), 1)) {\n\n    t = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vcast_vd_d_avx2_sleef(-0.2083271002525222097e-14)), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.7151909970790897009e-13)), (vcast_vd_d_avx2_sleef(-0.1162238220110999364e-11)))), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.1186474230821585259e-10)), (vcast_vd_d_avx2_sleef(-0.8499973178354613440e-10)))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.4507647462598841629e-9)), (vcast_vd_d_avx2_sleef(-0.1808044474288848915e-8)))), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.5435081826716212389e-8)), (vcast_vd_d_avx2_sleef(-0.1143939895758628484e-7)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.1215442362680889243e-7)), (vcast_vd_d_avx2_sleef(+0.1669878756181250355e-7)))), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(-0.9808074602255194288e-7)), (vcast_vd_d_avx2_sleef(+0.1389000557865837204e-6)))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.2945514529987331866e-6)), (vcast_vd_d_avx2_sleef(-0.1842918273003998283e-5)))), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.3417987836115362136e-5)), (vcast_vd_d_avx2_sleef(+0.3860236356493129101e-5)))))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(-0.3309403072749947546e-4)), (vcast_vd_d_avx2_sleef(+0.1060862922597579532e-3)))), (vmla_vd_vd_vd_vd_avx2_sleef((x), (vcast_vd_d_avx2_sleef(+0.2323253155213076174e-3)), (vcast_vd_d_avx2_sleef(+0.1490149719145544729e-3)))))))))))\n\n                                  ;\n    t2 = poly4dd_avx2_sleef(x, t,\n   vcast_vd2_d_d_avx2_sleef(0.0092877958392275604405, 7.9287559463961107493e-19),\n   vcast_vd2_d_d_avx2_sleef(0.042275531758784692937, 1.3785226620501016138e-19),\n   vcast_vd2_d_d_avx2_sleef(0.07052369794346953491, 9.5846628070792092842e-19));\n    t2 = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), ddmul_vd2_vd2_vd_avx2_sleef(t2, x));\n    t2 = ddsqu_vd2_vd2_avx2_sleef(t2);\n    t2 = ddsqu_vd2_vd2_avx2_sleef(t2);\n    t2 = ddsqu_vd2_vd2_avx2_sleef(t2);\n    t2 = ddsqu_vd2_vd2_avx2_sleef(t2);\n    t2 = ddrec_vd2_vd2_avx2_sleef(t2);\n  } else {\n\n    t = vmla_vd_vd_vd_vd_avx2_sleef((x16), (vmla_vd_vd_vd_vd_avx2_sleef((x4), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.2083271002525222097e-14, -0.4024015130752621932e-18))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.7151909970790897009e-13, +0.3847193332817048172e-16))), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.1162238220110999364e-11, -0.1749316241455644088e-14))))), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1186474230821585259e-10, +0.5029618322872872715e-13))), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.8499973178354613440e-10, -0.1025221466851463164e-11))))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x8), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.4507647462598841629e-9, +0.1573695559331945583e-10))), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.1808044474288848915e-8, -0.1884658558040203709e-9))))), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.5435081826716212389e-8, +0.1798167853032159309e-8))), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.1143939895758628484e-7, -0.1380745342355033142e-7))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1215442362680889243e-7, +0.8525705726469103499e-7))), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1669878756181250355e-7, -0.4160448058101303405e-6))))), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.9808074602255194288e-7, +0.1517272660008588485e-5))), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1389000557865837204e-6, -0.3341634127317201697e-5))))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x4), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.2945514529987331866e-6, -0.2515023395879724513e-5))), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.1842918273003998283e-5, +0.6539731269664907554e-4))))), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.3417987836115362136e-5, -0.3551065097428388658e-3))), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.3860236356493129101e-5, +0.1210736097958368864e-2))))))), (vmla_vd_vd_vd_vd_avx2_sleef((x2), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, -0.3309403072749947546e-4, -0.2605566912579998680e-2))), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1060862922597579532e-3, +0.1252823202436093193e-2))))), (vmla_vd_vd_vd_vd_avx2_sleef((x), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.2323253155213076174e-3, +0.1820191395263313222e-1))), ((vsel_vd_vo_d_d_avx2_sleef(o25, +0.1490149719145544729e-3, -0.1021557155453465954e+0))))))))))))\n\n                                                                                  ;\n    t2 = poly4dd_avx2_sleef(x, t,\n   vsel_vd2_vo_vd2_vd2_avx2_sleef(o25, vcast_vd2_d_d_avx2_sleef(0.0092877958392275604405, 7.9287559463961107493e-19),\n         vcast_vd2_d_d_avx2_sleef(-0.63691044383641748361, -2.4249477526539431839e-17)),\n   vsel_vd2_vo_vd2_vd2_avx2_sleef(o25, vcast_vd2_d_d_avx2_sleef(0.042275531758784692937, 1.3785226620501016138e-19),\n         vcast_vd2_d_d_avx2_sleef(-1.1282926061803961737, -6.2970338860410996505e-17)),\n   vsel_vd2_vo_vd2_vd2_avx2_sleef(o25, vcast_vd2_d_d_avx2_sleef(0.07052369794346953491, 9.5846628070792092842e-19),\n         vcast_vd2_d_d_avx2_sleef(-1.2261313785184804967e-05, -5.5329707514490107044e-22)));\n    vdouble2_avx2_sleef s2 = ddadd_vd2_vd_vd2_avx2_sleef(vcast_vd_d_avx2_sleef(1), ddmul_vd2_vd2_vd_avx2_sleef(t2, x));\n    s2 = ddsqu_vd2_vd2_avx2_sleef(s2);\n    s2 = ddsqu_vd2_vd2_avx2_sleef(s2);\n    s2 = ddsqu_vd2_vd2_avx2_sleef(s2);\n    s2 = ddsqu_vd2_vd2_avx2_sleef(s2);\n    s2 = ddrec_vd2_vd2_avx2_sleef(s2);\n    t2 = vsel_vd2_vo_vd2_vd2_avx2_sleef(o25, s2, vcast_vd2_vd_vd_avx2_sleef(expk_avx2_sleef(t2), vcast_vd_d_avx2_sleef(0)));\n  }\n\n  t2 = ddadd2_vd2_vd2_vd_avx2_sleef(t2, vcast_vd_d_avx2_sleef(-1));\n\n  vdouble_avx2_sleef z = vneg_vd_vd_avx2_sleef(vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(t2), vd2gety_vd_vd2_avx2_sleef(t2)));\n  z = vsel_vd_vo_vd_vd_avx2_sleef(vlt_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1e-8)), vmul_vd_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(1.12837916709551262756245475959)), z);\n  z = vsel_vd_vo_vd_vd_avx2_sleef(vge_vo_vd_vd_avx2_sleef(x, vcast_vd_d_avx2_sleef(6)), vcast_vd_d_avx2_sleef(1), z);\n  z = vsel_vd_vo_vd_vd_avx2_sleef(visinf_vo_vd_avx2_sleef(a), vcast_vd_d_avx2_sleef(1), z);\n  z = vsel_vd_vo_vd_vd_avx2_sleef(veq_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)), vcast_vd_d_avx2_sleef(0), z);\n  z = vmulsign_vd_vd_vd_avx2_sleef(z, a);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vdouble_avx2_sleef Sleef_erfcd4_u15avx2(vdouble_avx2_sleef a) {\n  vdouble_avx2_sleef s = a, r = vcast_vd_d_avx2_sleef(0), t;\n  vdouble2_avx2_sleef u, d, x;\n  a = vabs_vd_vd_avx2_sleef(a);\n  vopmask_avx2_sleef o0 = vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(1.0));\n  vopmask_avx2_sleef o1 = vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(2.2));\n  vopmask_avx2_sleef o2 = vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(4.2));\n  vopmask_avx2_sleef o3 = vlt_vo_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(27.3));\n\n  u = vsel_vd2_vo_vd2_vd2_avx2_sleef(o0, ddmul_vd2_vd_vd_avx2_sleef(a, a), vsel_vd2_vo_vd2_vd2_avx2_sleef(o1, vcast_vd2_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)), dddiv_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(1, 0), vcast_vd2_vd_vd_avx2_sleef(a, vcast_vd_d_avx2_sleef(0)))));\n\n  t = vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.6801072401395386139e-20, +0.3438010341362585303e-12, -0.5757819536420710449e+2, +0.2334249729638701319e+5);\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.2161766247570055669e-18, -0.1237021188160598264e-10, +0.4669289654498104483e+3, -0.4695661044933107769e+5));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.4695919173301595670e-17, +0.2117985839877627852e-09, -0.1796329879461355858e+4, +0.3173403108748643353e+5));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.9049140419888007122e-16, -0.2290560929177369506e-08, +0.4355892193699575728e+4, +0.3242982786959573787e+4));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.1634018903557410728e-14, +0.1748931621698149538e-07, -0.7456258884965764992e+4, -0.2014717999760347811e+5));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.2783485786333451745e-13, -0.9956602606623249195e-07, +0.9553977358167021521e+4, +0.1554006970967118286e+5));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.4463221276786415752e-12, +0.4330010240640327080e-06, -0.9470019905444229153e+4, -0.6150874190563554293e+4));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.6711366622850136563e-11, -0.1435050600991763331e-05, +0.7387344321849855078e+4, +0.1240047765634815732e+4));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.9422759050232662223e-10, +0.3460139479650695662e-05, -0.4557713054166382790e+4, -0.8210325475752699731e+2));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.1229055530100229098e-08, -0.4988908180632898173e-05, +0.2207866967354055305e+4, +0.3242443880839930870e+2));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.1480719281585086512e-07, -0.1308775976326352012e-05, -0.8217975658621754746e+3, -0.2923418863833160586e+2));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.1636584469123399803e-06, +0.2825086540850310103e-04, +0.2268659483507917400e+3, +0.3457461732814383071e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.1646211436588923575e-05, -0.6393913713069986071e-04, -0.4633361260318560682e+2, +0.5489730155952392998e+1));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.1492565035840623511e-04, -0.2566436514695078926e-04, +0.9557380123733945965e+1, +0.1559934132251294134e-2));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.1205533298178967851e-03, +0.5895792375659440364e-03, -0.2958429331939661289e+1, -0.1541741566831520638e+1));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.8548327023450850081e-03, -0.1695715579163588598e-02, +0.1670329508092765480e+0, +0.2823152230558364186e-5));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, +0.5223977625442187932e-02, +0.2089116434918055149e-03, +0.6096615680115419211e+0, +0.6249999184195342838e+0));\n  t = vmla_vd_vd_vd_vd_avx2_sleef(t, vd2getx_vd_vd2_avx2_sleef(u), vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.2686617064513125222e-01, +0.1912855949584917753e-01, +0.1059212443193543585e-2, +0.1741749416408701288e-8));\n\n  d = ddmul_vd2_vd2_vd_avx2_sleef(u, t);\n  d = ddadd2_vd2_vd2_vd2_avx2_sleef(d, vcast_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, 0.11283791670955126141, -0.10277263343147646779, -0.50005180473999022439, -0.5000000000258444377),\n         vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -4.0175691625932118483e-18, -6.2338714083404900225e-18, 2.6362140569041995803e-17, -4.0074044712386992281e-17)));\n  d = ddmul_vd2_vd2_vd2_avx2_sleef(d, u);\n  d = ddadd2_vd2_vd2_vd2_avx2_sleef(d, vcast_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.37612638903183753802, -0.63661976742916359662, 1.601106273924963368e-06, 2.3761973137523364792e-13),\n         vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, 1.3391897206042552387e-17, 7.6321019159085724662e-18, 1.1974001857764476775e-23, -1.1670076950531026582e-29)));\n  d = ddmul_vd2_vd2_vd2_avx2_sleef(d, u);\n  d = ddadd2_vd2_vd2_vd2_avx2_sleef(d, vcast_vd2_vd_vd_avx2_sleef(vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, 1.1283791670955125586, -1.1283791674717296161, -0.57236496645145429341, -0.57236494292470108114),\n         vsel_vd_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, 1.5335459613165822674e-17, 8.0896847755965377194e-17, 3.0704553245872027258e-17, -2.3984352208056898003e-17)));\n\n  x = ddmul_vd2_vd2_vd_avx2_sleef(vsel_vd2_vo_vd2_vd2_avx2_sleef(o1, d, vcast_vd2_vd_vd_avx2_sleef(vneg_vd_vd_avx2_sleef(a), vcast_vd_d_avx2_sleef(0))), a);\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o1, x, ddadd2_vd2_vd2_vd2_avx2_sleef(x, d));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o0, ddsub_vd2_vd2_vd2_avx2_sleef(vcast_vd2_d_d_avx2_sleef(1, 0), x), expk2_avx2_sleef(x));\n  x = vsel_vd2_vo_vd2_vd2_avx2_sleef(o1, x, ddmul_vd2_vd2_vd2_avx2_sleef(x, u));\n\n  r = vsel_vd_vo_vd_vd_avx2_sleef(o3, vadd_vd_vd_vd_avx2_sleef(vd2getx_vd_vd2_avx2_sleef(x), vd2gety_vd_vd2_avx2_sleef(x)), vcast_vd_d_avx2_sleef(0));\n  r = vsel_vd_vo_vd_vd_avx2_sleef(vsignbit_vo_vd_avx2_sleef(s), vsub_vd_vd_vd_avx2_sleef(vcast_vd_d_avx2_sleef(2), r), r);\n  r = vsel_vd_vo_vd_vd_avx2_sleef(visnan_vo_vd_avx2_sleef(s), vcast_vd_d_avx2_sleef(__builtin_nan(\"\")), r);\n  return r;\n}\n\n#if !defined(Sleef_quad_DEFINED)\n#define Sleef_quad_DEFINED\ntypedef struct { uint64_t x, y; } Sleef_uint64_2t;\n#if defined(SLEEF_FLOAT128_IS_IEEEQP)\ntypedef __float128 Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## Q)\n#elif defined(SLEEF_LONGDOUBLE_IS_IEEEQP)\ntypedef long double Sleef_quad;\n#define SLEEF_QUAD_C(x) (x ## L)\n#else\ntypedef Sleef_uint64_2t Sleef_quad;\n#endif\n#endif\n\nextern const float Sleef_rempitabsp[];\n\ntypedef struct {\n  vfloat_avx2_sleef x, y;\n} vfloat2_avx2_sleef;\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vf2getx_vf_vf2_avx2_sleef(vfloat2_avx2_sleef v) { return v.x; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vf2gety_vf_vf2_avx2_sleef(vfloat2_avx2_sleef v) { return v.y; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vf2setxy_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { vfloat2_avx2_sleef v; v.x = x; v.y = y; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vf2setx_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef v, vfloat_avx2_sleef d) { v.x = d; return v; }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vf2sety_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef v, vfloat_avx2_sleef d) { v.y = d; return v; }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vupper_vf_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  return vreinterpret_vf_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), vcast_vi2_i_avx2_sleef(0xfffff000)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vcast_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef h, vfloat_avx2_sleef l) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(h, l);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vcast_vf2_f_f_avx2_sleef(float h, float l) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(h), vcast_vf_f_avx2_sleef(l));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vcast_vf2_d_avx2_sleef(double d) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(d), vcast_vf_f_avx2_sleef(d - (float)d));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vsel_vf2_vo_vf2_vf2_avx2_sleef(vopmask_avx2_sleef m, vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(m, vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y)), vsel_vf_vo_vf_vf_avx2_sleef(m, vf2gety_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vsel_vf2_vo_f_f_f_f_avx2_sleef(vopmask_avx2_sleef o, float x1, float y1, float x0, float y0) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_f_f_avx2_sleef(o, x1, x0), vsel_vf_vo_f_f_avx2_sleef(o, y1, y0));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vsel_vf2_vo_vo_d_d_d_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, double d0, double d1, double d2) {\n  return vsel_vf2_vo_vf2_vf2_avx2_sleef(o0, vcast_vf2_d_avx2_sleef(d0), vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, vcast_vf2_d_avx2_sleef(d1), vcast_vf2_d_avx2_sleef(d2)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vsel_vf2_vo_vo_vo_d_d_d_d_avx2_sleef(vopmask_avx2_sleef o0, vopmask_avx2_sleef o1, vopmask_avx2_sleef o2, double d0, double d1, double d2, double d3) {\n  return vsel_vf2_vo_vf2_vf2_avx2_sleef(o0, vcast_vf2_d_avx2_sleef(d0), vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, vcast_vf2_d_avx2_sleef(d1), vsel_vf2_vo_vf2_vf2_avx2_sleef(o2, vcast_vf2_d_avx2_sleef(d2), vcast_vf2_d_avx2_sleef(d3))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef vabs_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x) {\n  return vcast_vf2_vf_vf_avx2_sleef(vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0)), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)))),\n    vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0)), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vadd_vf_3vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2) {\n  return vadd_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vadd_vf_4vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3) {\n  return vadd_vf_3vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vadd_vf_5vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3, vfloat_avx2_sleef v4) {\n  return vadd_vf_4vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vadd_vf_6vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3, vfloat_avx2_sleef v4, vfloat_avx2_sleef v5) {\n  return vadd_vf_5vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(v0, v1), v2, v3, v4, v5);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vadd_vf_7vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3, vfloat_avx2_sleef v4, vfloat_avx2_sleef v5, vfloat_avx2_sleef v6) {\n  return vadd_vf_6vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(v0, v1), v2, v3, v4, v5, v6);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vsub_vf_3vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2) {\n  return vsub_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(v0, v1), v2);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vsub_vf_4vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3) {\n  return vsub_vf_3vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(v0, v1), v2, v3);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vsub_vf_5vf_avx2_sleef(vfloat_avx2_sleef v0, vfloat_avx2_sleef v1, vfloat_avx2_sleef v2, vfloat_avx2_sleef v3, vfloat_avx2_sleef v4) {\n  return vsub_vf_4vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(v0, v1), v2, v3, v4);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfneg_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x) {\n  return vcast_vf2_vf_vf_avx2_sleef(vneg_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)), vneg_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfabs_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x) {\n  return vcast_vf2_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)),\n    vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)), vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfnormalize_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef t) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t), vf2gety_vf_vf2_avx2_sleef(t));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t), s), vf2gety_vf_vf2_avx2_sleef(t)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfscale_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef d, vfloat_avx2_sleef s) {\n  return vf2setxy_vf2_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), s), vmul_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(d), s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd2_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(x, y);\n  vfloat_avx2_sleef v = vsub_vf_vf_vf_avx2_sleef(s, x);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, vsub_vf_vf_vf_avx2_sleef(s, v)), vsub_vf_vf_vf_avx2_sleef(y, v)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd2_vf2_vf_vf2_avx2_sleef(vfloat_avx2_sleef x, vfloat2_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(x, vf2getx_vf_vf2_avx2_sleef(y));\n  vfloat_avx2_sleef v = vsub_vf_vf_vf_avx2_sleef(s, x);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, vsub_vf_vf_vf_avx2_sleef(s, v)), vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), v)), vf2gety_vf_vf2_avx2_sleef(y)));\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_3vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), s), y, vf2gety_vf_vf2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsub_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), s), y), vf2gety_vf_vf2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd2_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), y);\n  vfloat_avx2_sleef v = vsub_vf_vf_vf_avx2_sleef(s, vf2getx_vf_vf2_avx2_sleef(x));\n  vfloat_avx2_sleef t = vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vsub_vf_vf_vf_avx2_sleef(s, v)), vsub_vf_vf_vf_avx2_sleef(y, v));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(t, vf2gety_vf_vf2_avx2_sleef(x)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd_vf2_vf_vf2_avx2_sleef(vfloat_avx2_sleef x, vfloat2_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(x, vf2getx_vf_vf2_avx2_sleef(y));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_3vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, s), vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd_vf2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_4vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), s), vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfadd2_vf2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n  vfloat_avx2_sleef s = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y));\n  vfloat_avx2_sleef v = vsub_vf_vf_vf_avx2_sleef(s, vf2getx_vf_vf2_avx2_sleef(x));\n  vfloat_avx2_sleef t = vadd_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vsub_vf_vf_vf_avx2_sleef(s, v)), vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), v));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vadd_vf_vf_vf_avx2_sleef(t, vadd_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsub_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n\n  vfloat_avx2_sleef s = vsub_vf_vf_vf_avx2_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vsub_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, s), y));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsub_vf2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n\n  vfloat_avx2_sleef s = vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y));\n  vfloat_avx2_sleef t = vsub_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), s);\n  t = vsub_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(y));\n  t = vadd_vf_vf_vf_avx2_sleef(t, vf2gety_vf_vf2_avx2_sleef(x));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vsub_vf_vf_vf_avx2_sleef(t, vf2gety_vf_vf2_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfdiv_vf2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef n, vfloat2_avx2_sleef d) {\n  vfloat_avx2_sleef t = vrec_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d));\n  vfloat_avx2_sleef s = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(n), t);\n  vfloat_avx2_sleef u = vfmapn_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(n), s);\n  vfloat_avx2_sleef v = vfmanp_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(d), t, vfmanp_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), t, vcast_vf_f_avx2_sleef(1)));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vfma_vf_vf_vf_vf_avx2_sleef(s, v, vfma_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(n), t, u)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfmul_vf2_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vmul_vf_vf_vf_avx2_sleef(x, y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vfmapn_vf_vf_vf_vf_avx2_sleef(x, y, s));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsqu_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x) {\n  vfloat_avx2_sleef s = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vfma_vf_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x)), vf2gety_vf_vf2_avx2_sleef(x), vfmapn_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x), s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef dfsqu_vf_vf2_avx2_sleef(vfloat2_avx2_sleef x) {\n  return vfma_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x), vadd_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x)), vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfmul_vf2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n  vfloat_avx2_sleef s = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vfma_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(y), vfma_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y), vfmapn_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y), s))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef dfmul_vf_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef x, vfloat2_avx2_sleef y) {\n  return vfma_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y), vfma_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y), vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfmul_vf2_vf2_vf_avx2_sleef(vfloat2_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef s = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), y);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vfma_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x), y, vfmapn_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), y, s)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfrec_vf2_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef s = vrec_vf_vf_avx2_sleef(d);\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(s, vfmanp_vf_vf_vf_vf_avx2_sleef(d, s, vcast_vf_f_avx2_sleef(1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfrec_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef d) {\n  vfloat_avx2_sleef s = vrec_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d));\n  return vf2setxy_vf2_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(s, vfmanp_vf_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(d), s, vfmanp_vf_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), s, vcast_vf_f_avx2_sleef(1)))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsqrt_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef d) {\n\n  vfloat_avx2_sleef t = vsqrt_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)));\n  return dfscale_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf2_avx2_sleef(d, dfmul_vf2_vf_vf_avx2_sleef(t, t)), dfrec_vf2_vf_avx2_sleef(t)), vcast_vf_f_avx2_sleef(0.5));\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfsqrt_vf2_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef t = vsqrt_vf_vf_avx2_sleef(d);\n  return dfscale_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf2_avx2_sleef(d, dfmul_vf2_vf_vf_avx2_sleef(t, t)), dfrec_vf2_vf_avx2_sleef(t)), vcast_vf_f_avx2_sleef(0.5f));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visnegzero_vo_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  return veq_vo_vi2_vi2_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), vreinterpret_vi2_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE vopmask_avx2_sleef vnot_vo32_vo32_avx2_sleef(vopmask_avx2_sleef x) {\n  return vxor_vo_vo_vo_avx2_sleef(x, veq_vo_vi2_vi2_avx2_sleef(vcast_vi2_i_avx2_sleef(0), vcast_vi2_i_avx2_sleef(0)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vmask_avx2_sleef vsignbit_vm_vf_avx2_sleef(vfloat_avx2_sleef f) {\n  return vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(f), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vmulsign_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  return vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(x), vsignbit_vm_vf_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vcopysign_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  return vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vandnot_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)), vreinterpret_vm_vf_avx2_sleef(x)),\n       vand_vm_vm_vm_avx2_sleef (vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)), vreinterpret_vm_vf_avx2_sleef(y))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vsign_vf_vf_avx2_sleef(vfloat_avx2_sleef f) {\n  return vreinterpret_vf_vm_avx2_sleef(vor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f)), vand_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f)), vreinterpret_vm_vf_avx2_sleef(f))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef vsignbit_vo_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  return veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), vcast_vi2_i_avx2_sleef(0x80000000)), vcast_vi2_i_avx2_sleef(0x80000000));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_avx2_sleef vsel_vi2_vf_vf_vi2_vi2_avx2_sleef(vfloat_avx2_sleef f0, vfloat_avx2_sleef f1, vint2_avx2_sleef x, vint2_avx2_sleef y) {\n  return vsel_vi2_vo_vi2_vi2_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(f0, f1), x, y);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_avx2_sleef vsel_vi2_vf_vi2_avx2_sleef(vfloat_avx2_sleef d, vint2_avx2_sleef x) {\n  return vand_vi2_vo_vi2_avx2_sleef(vsignbit_vo_vf_avx2_sleef(d), x);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visint_vo_vf_avx2_sleef(vfloat_avx2_sleef y) { return veq_vo_vf_vf_avx2_sleef(vtruncate_vf_vf_avx2_sleef(y), y); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vopmask_avx2_sleef visnumber_vo_vf_avx2_sleef(vfloat_avx2_sleef x) { return vnot_vo32_vo32_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(x))); }\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_avx2_sleef vilogbk_vi2_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(5.421010862427522E-20f));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.8446744073709552E19f), d), d);\n  vint2_avx2_sleef q = vand_vi2_vi2_vi2_avx2_sleef(vsrl_vi2_vi2_i_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), 23), vcast_vi2_i_avx2_sleef(0xff));\n  q = vsub_vi2_vi2_vi2_avx2_sleef(q, vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vcast_vi2_i_avx2_sleef(64 + 0x7f), vcast_vi2_i_avx2_sleef(0x7f)));\n  return q;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vint2_avx2_sleef vilogb2k_vi2_vf_avx2_sleef(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q = vreinterpret_vi2_vf_avx2_sleef(d);\n  q = vsrl_vi2_vi2_i_avx2_sleef(q, 23);\n  q = vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(0xff));\n  q = vsub_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(0x7f));\n  return q;\n}\n\nSLEEF_INLINE SLEEF_CONST vint2_avx2_sleef Sleef_ilogbf8_avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef e = vilogbk_vi2_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.0f)), vcast_vi2_i_avx2_sleef(SLEEF_FP_ILOGB0), e);\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(visnan_vo_vf_avx2_sleef(d), vcast_vi2_i_avx2_sleef(SLEEF_FP_ILOGBNAN), e);\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vcast_vi2_i_avx2_sleef(2147483647), e);\n  return e;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vpow2i_vf_vi2_avx2_sleef(vint2_avx2_sleef q) {\n  return vreinterpret_vf_vi2_avx2_sleef(vsll_vi2_vi2_i_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(0x7f)), 23));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vldexp_vf_vf_vi2_avx2_sleef(vfloat_avx2_sleef x, vint2_avx2_sleef q) {\n  vfloat_avx2_sleef u;\n  vint2_avx2_sleef m = vsra_vi2_vi2_i_avx2_sleef(q, 31);\n  m = vsll_vi2_vi2_i_avx2_sleef(vsub_vi2_vi2_vi2_avx2_sleef(vsra_vi2_vi2_i_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(m, q), 6), m), 4);\n  q = vsub_vi2_vi2_vi2_avx2_sleef(q, vsll_vi2_vi2_i_avx2_sleef(m, 2));\n  m = vadd_vi2_vi2_vi2_avx2_sleef(m, vcast_vi2_i_avx2_sleef(0x7f));\n  m = vand_vi2_vi2_vi2_avx2_sleef(vgt_vi2_vi2_vi2_avx2_sleef(m, vcast_vi2_i_avx2_sleef(0)), m);\n  vint2_avx2_sleef n = vgt_vi2_vi2_vi2_avx2_sleef(m, vcast_vi2_i_avx2_sleef(0xff));\n  m = vor_vi2_vi2_vi2_avx2_sleef(vandnot_vi2_vi2_vi2_avx2_sleef(n, m), vand_vi2_vi2_vi2_avx2_sleef(n, vcast_vi2_i_avx2_sleef(0xff)));\n  u = vreinterpret_vf_vi2_avx2_sleef(vsll_vi2_vi2_i_avx2_sleef(m, 23));\n  x = vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x, u), u), u), u);\n  u = vreinterpret_vf_vi2_avx2_sleef(vsll_vi2_vi2_i_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(0x7f)), 23));\n  return vmul_vf_vf_vf_avx2_sleef(x, u);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vldexp2_vf_vf_vi2_avx2_sleef(vfloat_avx2_sleef d, vint2_avx2_sleef e) {\n  return vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vpow2i_vf_vi2_avx2_sleef(vsra_vi2_vi2_i_avx2_sleef(e, 1))), vpow2i_vf_vi2_avx2_sleef(vsub_vi2_vi2_vi2_avx2_sleef(e, vsra_vi2_vi2_i_avx2_sleef(e, 1))));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vldexp3_vf_vf_vi2_avx2_sleef(vfloat_avx2_sleef d, vint2_avx2_sleef q) {\n  return vreinterpret_vf_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), vsll_vi2_vi2_i_avx2_sleef(q, 23)));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_ldexpf8_avx2(vfloat_avx2_sleef x, vint2_avx2_sleef q) { return vldexp_vf_vf_vi2_avx2_sleef(x, q); }\n\ntypedef struct {\n  vfloat_avx2_sleef d;\n  vint2_avx2_sleef i;\n} fi_t_avx2_sleef;\n\nstatic vfloat_avx2_sleef figetd_vf_di_avx2_sleef(fi_t_avx2_sleef d) { return d.d; }\nstatic vint2_avx2_sleef figeti_vi2_di_avx2_sleef(fi_t_avx2_sleef d) { return d.i; }\nstatic fi_t_avx2_sleef fisetdi_fi_vf_vi2_avx2_sleef(vfloat_avx2_sleef d, vint2_avx2_sleef i) {\n  fi_t_avx2_sleef r = { d, i };\n  return r;\n}\n\ntypedef struct {\n  vfloat2_avx2_sleef df_avx2_sleef;\n  vint2_avx2_sleef i;\n} dfi_t_avx2_sleef;\n\nstatic vfloat2_avx2_sleef dfigetdf_vf2_dfi_avx2_sleef(dfi_t_avx2_sleef d) { return d.df_avx2_sleef; }\nstatic vint2_avx2_sleef dfigeti_vi2_dfi_avx2_sleef(dfi_t_avx2_sleef d) { return d.i; }\nstatic dfi_t_avx2_sleef dfisetdfi_dfi_vf2_vi2_avx2_sleef(vfloat2_avx2_sleef v, vint2_avx2_sleef i) {\n  dfi_t_avx2_sleef r = { v, i };\n  return r;\n}\nstatic dfi_t_avx2_sleef dfisetdf_dfi_dfi_vf2_avx2_sleef(dfi_t_avx2_sleef dfi_avx2_sleef, vfloat2_avx2_sleef v) {\n  dfi_avx2_sleef.df_avx2_sleef = v;\n  return dfi_avx2_sleef;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vorsign_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  return vreinterpret_vf_vm_avx2_sleef(vor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(x), vsignbit_vm_vf_avx2_sleef(y)));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST fi_t_avx2_sleef rempisubf_avx2_sleef(vfloat_avx2_sleef x) {\n\n  vfloat_avx2_sleef y = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(4)));\n  vint2_avx2_sleef vi = vtruncate_vi2_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(y, vmul_vf_vf_vf_avx2_sleef(vrint_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(4))));\n  return fisetdi_fi_vf_vi2_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, vmul_vf_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0.25))), vi);\n\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST dfi_t_avx2_sleef rempif_avx2_sleef(vfloat_avx2_sleef a) {\n  vfloat2_avx2_sleef x, y;\n  vint2_avx2_sleef ex = vilogb2k_vi2_vf_avx2_sleef(a);\n\n  ex = vsub_vi2_vi2_vi2_avx2_sleef(ex, vcast_vi2_i_avx2_sleef(25));\n  vint2_avx2_sleef q = vand_vi2_vo_vi2_avx2_sleef(vgt_vo_vi2_vi2_avx2_sleef(ex, vcast_vi2_i_avx2_sleef(90-25)), vcast_vi2_i_avx2_sleef(-64));\n  a = vldexp3_vf_vf_vi2_avx2_sleef(a, q);\n  ex = vandnot_vi2_vi2_vi2_avx2_sleef(vsra_vi2_vi2_i_avx2_sleef(ex, 31), ex);\n  ex = vsll_vi2_vi2_i_avx2_sleef(ex, 2);\n  x = dfmul_vf2_vf_vf_avx2_sleef(a, vgather_vf_p_vi2_avx2_sleef(Sleef_rempitabsp, ex));\n  fi_t_avx2_sleef di = rempisubf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x));\n  q = figeti_vi2_di_avx2_sleef(di);\n  x = vf2setx_vf2_vf2_vf_avx2_sleef(x, figetd_vf_di_avx2_sleef(di));\n  x = dfnormalize_vf2_vf2_avx2_sleef(x);\n  y = dfmul_vf2_vf_vf_avx2_sleef(a, vgather_vf_p_vi2_avx2_sleef(Sleef_rempitabsp+1, ex));\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(x, y);\n  di = rempisubf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x));\n  q = vadd_vi2_vi2_vi2_avx2_sleef(q, figeti_vi2_di_avx2_sleef(di));\n  x = vf2setx_vf2_vf2_vf_avx2_sleef(x, figetd_vf_di_avx2_sleef(di));\n  x = dfnormalize_vf2_vf2_avx2_sleef(x);\n  y = vcast_vf2_vf_vf_avx2_sleef(vgather_vf_p_vi2_avx2_sleef(Sleef_rempitabsp+2, ex), vgather_vf_p_vi2_avx2_sleef(Sleef_rempitabsp+3, ex));\n  y = dfmul_vf2_vf2_vf_avx2_sleef(y, a);\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(x, y);\n  x = dfnormalize_vf2_vf2_avx2_sleef(x);\n  x = dfmul_vf2_vf2_vf2_avx2_sleef(x, vcast_vf2_f_f_avx2_sleef(3.1415927410125732422f*2, -8.7422776573475857731e-08f*2));\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(a), vcast_vf_f_avx2_sleef(0.7f)), vcast_vf2_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), x);\n  return dfisetdfi_dfi_vf2_vi2_avx2_sleef(x, q);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sinf8_u35avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, s, r = d;\n\n  q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.318309886183790671537767526745028724)));\n  u = vcast_vf_vi2_avx2_sleef(q);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f), d);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f), d);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f), d);\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(r), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    s = vcast_vf_vi2_avx2_sleef(q);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-3.140625f), r);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-0.0009670257568359375f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-6.2771141529083251953e-07f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-1.2154201256553420762e-10f), u);\n\n    d = vsel_vf_vo_vf_vf_avx2_sleef(g, d, u);\n    g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(r), vcast_vf_f_avx2_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n      dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(r);\n      vint2_avx2_sleef q2 = vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(3));\n      q2 = vadd_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vi2_i_avx2_sleef(2), vcast_vi2_i_avx2_sleef(1)));\n      q2 = vsra_vi2_vi2_i_avx2_sleef(q2, 2);\n      vopmask_avx2_sleef o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1));\n      vfloat2_avx2_sleef x = vcast_vf2_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.1415927410125732422f*-0.5), vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef))),\n      vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-8.7422776573475857731e-08f*-0.5), vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef))));\n      x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef), x);\n      dfi_avx2_sleef = dfisetdf_dfi_dfi_vf2_avx2_sleef(dfi_avx2_sleef, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, x, dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n      u = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vf2gety_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n\n      u = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(r), visnan_vo_vf_avx2_sleef(r)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n      q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n      d = vsel_vf_vo_vf_vf_avx2_sleef(g, d, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_avx2_sleef(d, d);\n\n  d = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(d)));\n\n  u = vcast_vf_f_avx2_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00833307858556509017944336f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.166666597127914428710938f));\n\n  u = vadd_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, d)), d);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(r), r, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_cosf8_u35avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, s, r = d;\n\n  q = vrint_vi2_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.318309886183790671537767526745028724)), vcast_vf_f_avx2_sleef(0.5f)));\n  q = vadd_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, q), vcast_vi2_i_avx2_sleef(1));\n  u = vcast_vf_vi2_avx2_sleef(q);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f), d);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f), d);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f), d);\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(r), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    s = vcast_vf_vi2_avx2_sleef(q);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-3.140625f*0.5f), r);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-0.0009670257568359375f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-6.2771141529083251953e-07f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-1.2154201256553420762e-10f*0.5f), u);\n\n    d = vsel_vf_vo_vf_vf_avx2_sleef(g, d, u);\n    g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(r), vcast_vf_f_avx2_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n      dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(r);\n      vint2_avx2_sleef q2 = vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(3));\n      q2 = vadd_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vi2_i_avx2_sleef(8), vcast_vi2_i_avx2_sleef(7)));\n      q2 = vsra_vi2_vi2_i_avx2_sleef(q2, 1);\n      vopmask_avx2_sleef o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(0));\n      vfloat_avx2_sleef y = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(0), vcast_vf_f_avx2_sleef(-1));\n      vfloat2_avx2_sleef x = vcast_vf2_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.1415927410125732422f*-0.5), y),\n      vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-8.7422776573475857731e-08f*-0.5), y));\n      x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef), x);\n      dfi_avx2_sleef = dfisetdf_dfi_dfi_vf2_avx2_sleef(dfi_avx2_sleef, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, x, dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n      u = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vf2gety_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n\n      u = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(r), visnan_vo_vf_avx2_sleef(r)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n      q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n      d = vsel_vf_vo_vf_vf_avx2_sleef(g, d, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_avx2_sleef(d, d);\n\n  d = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(0)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(d)));\n\n  u = vcast_vf_f_avx2_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00833307858556509017944336f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.166666597127914428710938f));\n\n  u = vadd_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, d)), d);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_tanf8_u35avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, x;\n\n  q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(2 * 0.318309886183790671537767526745028724))));\n  u = vcast_vf_vi2_avx2_sleef(q);\n  x = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f), d);\n  x = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f), x);\n  x = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f), x);\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f*0.5f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    vint2_avx2_sleef q2 = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(2 * 0.318309886183790671537767526745028724))));\n    s = vcast_vf_vi2_avx2_sleef(q);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-3.140625f*0.5f), d);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-0.0009670257568359375f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-6.2771141529083251953e-07f*0.5f), u);\n    u = vmla_vf_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(-1.2154201256553420762e-10f*0.5f), u);\n\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n    x = vsel_vf_vo_vf_vf_avx2_sleef(g, x, u);\n    g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n      dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n      u = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vf2gety_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n      u = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d)), vreinterpret_vm_vf_avx2_sleef(u)));\n      u = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), d, u);\n      q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef));\n      x = vsel_vf_vo_vf_vf_avx2_sleef(g, x, u);\n    }\n  }\n\n  s = vmul_vf_vf_vf_avx2_sleef(x, x);\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1));\n  x = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(x)));\n\n  vfloat_avx2_sleef s2 = vmul_vf_vf_vf_avx2_sleef(s, s), s4 = vmul_vf_vf_vf_avx2_sleef(s2, s2);\n  u = vmla_vf_vf_vf_vf_avx2_sleef((s4), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.00927245803177356719970703f)), (vcast_vf_f_avx2_sleef(0.00331984995864331722259521f)))), (vmla_vf_vf_vf_vf_avx2_sleef((s2), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.0242998078465461730957031f)), (vcast_vf_f_avx2_sleef(0.0534495301544666290283203f)))), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.133383005857467651367188f)), (vcast_vf_f_avx2_sleef(0.333331853151321411132812f)))))))\n\n                                 ;\n\n  u = vmla_vf_vf_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, x), x);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(o, vrec_vf_vf_avx2_sleef(u), u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sinf8_u10avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, v;\n  vfloat2_avx2_sleef s, t, x;\n\n  u = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_avx2_sleef(u);\n  v = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f), d);\n  s = dfadd2_vf2_vf_vf_avx2_sleef(v, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f)));\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n    vint2_avx2_sleef q2 = vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(3));\n    q2 = vadd_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vi2_i_avx2_sleef(2), vcast_vi2_i_avx2_sleef(1)));\n    q2 = vsra_vi2_vi2_i_avx2_sleef(q2, 2);\n    vopmask_avx2_sleef o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1));\n    vfloat2_avx2_sleef x = vcast_vf2_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.1415927410125732422f*-0.5), vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef))),\n    vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-8.7422776573475857731e-08f*-0.5), vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef))));\n    x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef), x);\n    dfi_avx2_sleef = dfisetdf_dfi_dfi_vf2_avx2_sleef(dfi_avx2_sleef, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, x, dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n    t = dfnormalize_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef));\n\n    t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d)), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t)))));\n\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n    s = vsel_vf2_vo_vf2_vf2_avx2_sleef(g, s, t);\n  }\n\n  t = s;\n  s = dfsqu_vf2_vf2_avx2_sleef(s);\n\n  u = vcast_vf_f_avx2_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.00833307858556509017944336f));\n\n  x = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf2_vf2_avx2_sleef(dfadd_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.166666597127914428710938f), vmul_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s))), s));\n\n  u = dfmul_vf_vf2_vf2_avx2_sleef(t, x);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_cosf8_u10avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u;\n  vfloat2_avx2_sleef s, t, x;\n\n  vfloat_avx2_sleef dq = vmla_vf_vf_vf_vf_avx2_sleef(vrint_vf_vf_avx2_sleef(vmla_vf_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.318309886183790671537767526745028724), vcast_vf_f_avx2_sleef(-0.5f))),\n          vcast_vf_f_avx2_sleef(2), vcast_vf_f_avx2_sleef(1));\n  q = vrint_vi2_vf_avx2_sleef(dq);\n  s = dfadd2_vf2_vf_vf_avx2_sleef (d, vmul_vf_vf_vf_avx2_sleef(dq, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f)));\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(dq, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(dq, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n    vint2_avx2_sleef q2 = vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(3));\n    q2 = vadd_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q2, q2), vsel_vi2_vo_vi2_vi2_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vi2_i_avx2_sleef(8), vcast_vi2_i_avx2_sleef(7)));\n    q2 = vsra_vi2_vi2_i_avx2_sleef(q2, 1);\n    vopmask_avx2_sleef o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(0));\n    vfloat_avx2_sleef y = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(0), vcast_vf_f_avx2_sleef(-1));\n    vfloat2_avx2_sleef x = vcast_vf2_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.1415927410125732422f*-0.5), y),\n    vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-8.7422776573475857731e-08f*-0.5), y));\n    x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef), x);\n    dfi_avx2_sleef = dfisetdf_dfi_dfi_vf2_avx2_sleef(dfi_avx2_sleef, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, x, dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n    t = dfnormalize_vf2_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef));\n\n    t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d)), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t)))));\n\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n    s = vsel_vf2_vo_vf2_vf2_avx2_sleef(g, s, t);\n  }\n\n  t = s;\n  s = dfsqu_vf2_vf2_avx2_sleef(s);\n\n  u = vcast_vf_f_avx2_sleef(2.6083159809786593541503e-06f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-0.0001981069071916863322258f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.00833307858556509017944336f));\n\n  x = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf2_vf2_avx2_sleef(dfadd_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.166666597127914428710938f), vmul_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s))), s));\n\n  u = dfmul_vf_vf2_vf2_avx2_sleef(t, x);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(0)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fastsinf8_u3500avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, s, t = d;\n\n  s = vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.318309886183790671537767526745028724));\n  u = vrint_vf_vf_avx2_sleef(s);\n  q = vrint_vi2_vf_avx2_sleef(s);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-(float)3.141592653589793238462643383279502884), d);\n\n  s = vmul_vf_vf_vf_avx2_sleef(d, d);\n\n  u = vcast_vf_f_avx2_sleef(-0.1881748176e-3);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.8323502727e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.1666651368e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, d), u, d);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(t), vcast_vf_f_avx2_sleef(30.0f));\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) return vsel_vf_vo_vf_vf_avx2_sleef(g, u, Sleef_sinf8_u35avx2(t));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fastcosf8_u3500avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, s, t = d;\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.318309886183790671537767526745028724), vcast_vf_f_avx2_sleef(-0.5f));\n  u = vrint_vf_vf_avx2_sleef(s);\n  q = vrint_vi2_vf_avx2_sleef(s);\n  d = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-(float)3.141592653589793238462643383279502884), vsub_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)3.141592653589793238462643383279502884 * 0.5f)));\n\n  s = vmul_vf_vf_vf_avx2_sleef(d, d);\n\n  u = vcast_vf_f_avx2_sleef(-0.1881748176e-3);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.8323502727e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.1666651368e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, d), u, d);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(0)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(t), vcast_vf_f_avx2_sleef(30.0f));\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) return vsel_vf_vo_vf_vf_avx2_sleef(g, u, Sleef_cosf8_u35avx2(t));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_avx2_sleef Sleef_sincosf8_u35avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, t, rx, ry;\n  vfloat2_avx2_sleef r;\n\n  q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.636619772367581343075535053490057448)));\n  u = vcast_vf_vi2_avx2_sleef(q);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f), s);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f), s);\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    vint2_avx2_sleef q2 = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)0.636619772367581343075535053490057448)));\n    u = vcast_vf_vi2_avx2_sleef(q2);\n    t = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.140625f*0.5f), d);\n    t = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.0009670257568359375f*0.5f), t);\n    t = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-6.2771141529083251953e-07f*0.5f), t);\n    t = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.2154201256553420762e-10f*0.5f), t);\n\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, q2);\n    s = vsel_vf_vo_vf_vf_avx2_sleef(g, s, t);\n    g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(39000));\n\n    if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n      dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n      t = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)), vf2gety_vf_vf2_avx2_sleef(dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef)));\n      t = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d)), vreinterpret_vm_vf_avx2_sleef(t)));\n\n      q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef));\n      s = vsel_vf_vo_vf_vf_avx2_sleef(g, s, t);\n    }\n  }\n\n  t = s;\n\n  s = vmul_vf_vf_vf_avx2_sleef(s, s);\n\n  u = vcast_vf_f_avx2_sleef(-0.000195169282960705459117889f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00833215750753879547119141f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.166666537523269653320312f));\n\n  rx = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(u, s), t, t);\n  rx = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_avx2_sleef(-2.71811842367242206819355e-07f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(2.47990446951007470488548e-05f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.00138888787478208541870117f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.0416666641831398010253906f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.5));\n\n  ry = vmla_vf_vf_vf_vf_avx2_sleef(s, u, vcast_vf_f_avx2_sleef(1));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(0));\n  r = vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(o, rx, ry), vsel_vf_vo_vf_vf_avx2_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_avx2_sleef Sleef_sincosf8_u10avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, v, rx, ry;\n  vfloat2_avx2_sleef r, s, t, x;\n\n  u = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_avx2_sleef(u);\n  v = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f), d);\n  s = dfadd2_vf2_vf_vf_avx2_sleef(v, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n    t = dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef);\n    o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d));\n    t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t)))));\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef));\n    s = vsel_vf2_vo_vf2_vf2_avx2_sleef(g, s, t);\n  }\n\n  t = s;\n\n  s = vf2setx_vf2_vf2_vf_avx2_sleef(s, dfsqu_vf_vf2_avx2_sleef(s));\n\n  u = vcast_vf_f_avx2_sleef(-0.000195169282960705459117889f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.00833215750753879547119141f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-0.166666537523269653320312f));\n\n  u = vmul_vf_vf_vf_avx2_sleef(u, vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), vf2getx_vf_vf2_avx2_sleef(t)));\n\n  x = dfadd_vf2_vf2_vf_avx2_sleef(t, u);\n  rx = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  rx = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_avx2_sleef(-2.71811842367242206819355e-07f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(2.47990446951007470488548e-05f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-0.00138888787478208541870117f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.0416666641831398010253906f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-0.5));\n\n  x = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), u));\n  ry = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(0));\n  r = vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(o, rx, ry), vsel_vf_vo_vf_vf_avx2_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_avx2_sleef Sleef_sincospif8_u05avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, t, rx, ry;\n  vfloat2_avx2_sleef r, x, s2;\n\n  u = vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(4));\n  vint2_avx2_sleef q = vtruncate_vi2_vf_avx2_sleef(u);\n  q = vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vxor_vi2_vi2_vi2_avx2_sleef(vsrl_vi2_vi2_i_avx2_sleef(q, 31), vcast_vi2_i_avx2_sleef(1))), vcast_vi2_i_avx2_sleef(~1));\n  s = vsub_vf_vf_vf_avx2_sleef(u, vcast_vf_vi2_avx2_sleef(q));\n\n  t = s;\n  s = vmul_vf_vf_vf_avx2_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_avx2_sleef(t, t);\n\n  u = vcast_vf_f_avx2_sleef(+0.3093842054e-6);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.3657307388e-4));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2490393585e-2));\n  x = dfadd2_vf2_vf_vf2_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(u, s), vcast_vf2_f_f_avx2_sleef(-0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(s2, x), vcast_vf2_f_f_avx2_sleef(0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf_avx2_sleef(x, t);\n  rx = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  rx = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(-0.0f), rx);\n\n  u = vcast_vf_f_avx2_sleef(-0.2430611801e-7);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.3590577080e-5));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.3259917721e-3));\n  x = dfadd2_vf2_vf_vf2_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(u, s), vcast_vf2_f_f_avx2_sleef(0.015854343771934509277, 4.4940051354032242811e-10));\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(s2, x), vcast_vf2_f_f_avx2_sleef(-0.30842512845993041992, -9.0728339030733922277e-09));\n\n  x = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(x, s2), vcast_vf_f_avx2_sleef(1));\n  ry = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(0));\n  r = vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(o, rx, ry), vsel_vf_vo_vf_vf_avx2_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  o = vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1e+7f));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  o = visinf_vo_vf_avx2_sleef(d);\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat2_avx2_sleef Sleef_sincospif8_u35avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, t, rx, ry;\n  vfloat2_avx2_sleef r;\n\n  u = vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(4));\n  vint2_avx2_sleef q = vtruncate_vi2_vf_avx2_sleef(u);\n  q = vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vxor_vi2_vi2_vi2_avx2_sleef(vsrl_vi2_vi2_i_avx2_sleef(q, 31), vcast_vi2_i_avx2_sleef(1))), vcast_vi2_i_avx2_sleef(~1));\n  s = vsub_vf_vf_vf_avx2_sleef(u, vcast_vf_vi2_avx2_sleef(q));\n\n  t = s;\n  s = vmul_vf_vf_vf_avx2_sleef(s, s);\n\n  u = vcast_vf_f_avx2_sleef(-0.3600925265e-4);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2490088111e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.8074551076e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.7853981853e+0));\n\n  rx = vmul_vf_vf_vf_avx2_sleef(u, t);\n\n  u = vcast_vf_f_avx2_sleef(+0.3539815225e-5);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.3259574005e-3));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1585431583e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(-0.3084251285e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(1));\n\n  ry = u;\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(0));\n  r = vf2setxy_vf2_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(o, rx, ry), vsel_vf_vo_vf_vf_avx2_sleef(o, ry, rx));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  o = vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1e+7f));\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  o = visinf_vo_vf_avx2_sleef(d);\n  r = vf2setx_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)))));\n  r = vf2sety_vf2_vf2_vf_avx2_sleef(r, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(r)))));\n\n  return r;\n}\n\nSLEEF_INLINE vfloat2_avx2_sleef Sleef_modff8_avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef fr = vsub_vf_vf_vf_avx2_sleef(x, vcast_vf_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(INT64_C(1) << 23)), vcast_vf_f_avx2_sleef(0), fr);\n\n  vfloat2_avx2_sleef ret;\n\n  ret = vf2setxy_vf2_vf_vf_avx2_sleef(vcopysign_vf_vf_vf_avx2_sleef(fr, x), vcopysign_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, fr), x));\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_tanf8_u10avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q;\n  vfloat_avx2_sleef u, v;\n  vfloat2_avx2_sleef s, t, x;\n  vopmask_avx2_sleef o;\n\n  u = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(2 * 0.318309886183790671537767526745028724)));\n  q = vrint_vi2_vf_avx2_sleef(u);\n  v = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-3.1414794921875f*0.5f), d);\n  s = dfadd2_vf2_vf_vf_avx2_sleef(v, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.00011315941810607910156f*0.5f)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-1.9841872589410058936e-09f*0.5f)));\n  vopmask_avx2_sleef g = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(125.0f));\n\n  if (!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(g)), 1)) {\n    dfi_t_avx2_sleef dfi_avx2_sleef = rempif_avx2_sleef(d);\n    t = dfigetdf_vf2_dfi_avx2_sleef(dfi_avx2_sleef);\n    o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), visnan_vo_vf_avx2_sleef(d));\n    t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t)))));\n    t = vf2sety_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(t)))));\n    q = vsel_vi2_vo_vi2_vi2_avx2_sleef(g, q, dfigeti_vi2_dfi_avx2_sleef(dfi_avx2_sleef));\n    s = vsel_vf2_vo_vf2_vf2_avx2_sleef(g, s, t);\n  }\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1));\n  vmask_avx2_sleef n = vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0)));\n  s = vf2setx_vf2_vf2_vf_avx2_sleef(s, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s)), n)));\n  s = vf2sety_vf2_vf2_vf_avx2_sleef(s, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(s)), n)));\n\n  t = s;\n  s = dfsqu_vf2_vf2_avx2_sleef(s);\n  s = dfnormalize_vf2_vf2_avx2_sleef(s);\n\n  u = vcast_vf_f_avx2_sleef(0.00446636462584137916564941f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(-8.3920182078145444393158e-05f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.0109639242291450500488281f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.0212360303848981857299805f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.0540687143802642822265625f));\n\n  x = dfadd_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.133325666189193725585938f), vmul_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s)));\n  x = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf2_vf2_avx2_sleef(dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(0.33333361148834228515625f), dfmul_vf2_vf2_vf2_avx2_sleef(s, x)), s));\n  x = dfmul_vf2_vf2_vf2_avx2_sleef(t, x);\n\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfrec_vf2_vf2_avx2_sleef(x), x);\n\n  u = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), d, u);\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_atanf8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef s, t, u;\n  vint2_avx2_sleef q;\n\n  q = vsel_vi2_vf_vi2_avx2_sleef(d, vcast_vi2_i_avx2_sleef(2));\n  s = vabs_vf_vf_avx2_sleef(d);\n\n  q = vsel_vi2_vf_vf_vi2_vi2_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), s, vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), q);\n  s = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), s), vrec_vf_vf_avx2_sleef(s), s);\n\n  t = vmul_vf_vf_vf_avx2_sleef(s, s);\n\n  vfloat_avx2_sleef t2 = vmul_vf_vf_vf_avx2_sleef(t, t), t4 = vmul_vf_vf_vf_avx2_sleef(t2, t2);\n  u = vmla_vf_vf_vf_vf_avx2_sleef((t4), (vmla_vf_vf_vf_vf_avx2_sleef((t2), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.00282363896258175373077393f)), (vcast_vf_f_avx2_sleef(-0.0159569028764963150024414f)))), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.0425049886107444763183594f)), (vcast_vf_f_avx2_sleef(-0.0748900920152664184570312f)))))), (vmla_vf_vf_vf_vf_avx2_sleef((t2), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.106347933411598205566406f)), (vcast_vf_f_avx2_sleef(-0.142027363181114196777344f)))), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.199926957488059997558594f)), (vcast_vf_f_avx2_sleef(-0.333331018686294555664062f)))))))\n\n                                  ;\n\n  t = vmla_vf_vf_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(t, u), s);\n\n  t = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/2)), t), t);\n\n  t = vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2)), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0f))), vreinterpret_vm_vf_avx2_sleef(t)));\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef atan2kf_avx2_sleef(vfloat_avx2_sleef y, vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef s, t, u;\n  vint2_avx2_sleef q;\n  vopmask_avx2_sleef p;\n\n  q = vsel_vi2_vf_vi2_avx2_sleef(x, vcast_vi2_i_avx2_sleef(-2));\n  x = vabs_vf_vf_avx2_sleef(x);\n\n  q = vsel_vi2_vf_vf_vi2_vi2_avx2_sleef(x, y, vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), q);\n  p = vlt_vo_vf_vf_avx2_sleef(x, y);\n  s = vsel_vf_vo_vf_vf_avx2_sleef(p, vneg_vf_vf_avx2_sleef(x), y);\n  t = vmax_vf_vf_vf_avx2_sleef(x, y);\n\n  s = vdiv_vf_vf_vf_avx2_sleef(s, t);\n  t = vmul_vf_vf_vf_avx2_sleef(s, s);\n\n  vfloat_avx2_sleef t2 = vmul_vf_vf_vf_avx2_sleef(t, t), t4 = vmul_vf_vf_vf_avx2_sleef(t2, t2);\n  u = vmla_vf_vf_vf_vf_avx2_sleef((t4), (vmla_vf_vf_vf_vf_avx2_sleef((t2), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.00282363896258175373077393f)), (vcast_vf_f_avx2_sleef(-0.0159569028764963150024414f)))), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.0425049886107444763183594f)), (vcast_vf_f_avx2_sleef(-0.0748900920152664184570312f)))))), (vmla_vf_vf_vf_vf_avx2_sleef((t2), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.106347933411598205566406f)), (vcast_vf_f_avx2_sleef(-0.142027363181114196777344f)))), (vmla_vf_vf_vf_vf_avx2_sleef((t), (vcast_vf_f_avx2_sleef(0.199926957488059997558594f)), (vcast_vf_f_avx2_sleef(-0.333331018686294555664062f)))))))\n\n                                  ;\n\n  t = vmla_vf_vf_vf_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(t, u), s);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/2)), t);\n\n  return t;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef visinf2_vf_vf_vf_avx2_sleef(vfloat_avx2_sleef d, vfloat_avx2_sleef m) {\n  return vreinterpret_vf_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vor_vm_vm_vm_avx2_sleef(vsignbit_vm_vf_avx2_sleef(d), vreinterpret_vm_vf_avx2_sleef(m))));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_atan2f8_u35avx2(vfloat_avx2_sleef y, vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef r = atan2kf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), x);\n\n  r = vmulsign_vf_vf_vf_avx2_sleef(r, x);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0.0f))), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/2)), visinf2_vf_vf_vf_avx2_sleef(x, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/2)), x))), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(y), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/2)), visinf2_vf_vf_vf_avx2_sleef(x, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)(3.141592653589793238462643383279502884/4)), x))), r);\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0.0f)), vreinterpret_vf_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(vsignbit_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vreinterpret_vm_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_asinf8_u35avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0.5f));\n  vfloat_avx2_sleef x2 = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, d), vmul_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vabs_vf_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5f)));\n  vfloat_avx2_sleef x = vsel_vf_vo_vf_vf_avx2_sleef(o, vabs_vf_vf_avx2_sleef(d), vsqrt_vf_vf_avx2_sleef(x2)), u;\n\n  u = vcast_vf_f_avx2_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.1666677296e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vmul_vf_vf_vf_avx2_sleef(x, x2), x);\n\n  vfloat_avx2_sleef r = vsel_vf_vo_vf_vf_avx2_sleef(o, u, vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-2), vcast_vf_f_avx2_sleef(((float)3.141592653589793238462643383279502884)/2)));\n  return vmulsign_vf_vf_vf_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_acosf8_u35avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0.5f));\n  vfloat_avx2_sleef x2 = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, d),\n    vmul_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vabs_vf_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5f))), u;\n  vfloat_avx2_sleef x = vsel_vf_vo_vf_vf_avx2_sleef(o, vabs_vf_vf_avx2_sleef(d), vsqrt_vf_vf_avx2_sleef(x2));\n  x = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1.0f)), vcast_vf_f_avx2_sleef(0), x);\n\n  u = vcast_vf_f_avx2_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_avx2_sleef(u, vmul_vf_vf_vf_avx2_sleef(x2, x));\n\n  vfloat_avx2_sleef y = vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.1415926535897932f/2), vadd_vf_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(x, d), vmulsign_vf_vf_vf_avx2_sleef(u, d)));\n  x = vadd_vf_vf_vf_avx2_sleef(x, u);\n  vfloat_avx2_sleef r = vsel_vf_vo_vf_vf_avx2_sleef(o, y, vmul_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n  return vsel_vf_vo_vf_vf_avx2_sleef(vandnot_vo_vo_vo_avx2_sleef(o, vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0))),\n     vf2getx_vf_vf2_avx2_sleef(dfadd_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(3.1415927410125732422f,-8.7422776573475857731e-08f),\n         vneg_vf_vf_avx2_sleef(r))), r);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef atan2kf_u1_avx2_sleef(vfloat2_avx2_sleef y, vfloat2_avx2_sleef x) {\n  vfloat_avx2_sleef u;\n  vfloat2_avx2_sleef s, t;\n  vint2_avx2_sleef q;\n  vopmask_avx2_sleef p;\n  vmask_avx2_sleef r;\n\n  q = vsel_vi2_vf_vf_vi2_vi2_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vcast_vf_f_avx2_sleef(0), vcast_vi2_i_avx2_sleef(-2), vcast_vi2_i_avx2_sleef(0));\n  p = vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vcast_vf_f_avx2_sleef(0));\n  r = vand_vm_vo32_vm_avx2_sleef(p, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0)));\n  x = vf2setx_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)), r)));\n  x = vf2sety_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)), r)));\n\n  q = vsel_vi2_vf_vf_vi2_vi2_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y), vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(1)), q);\n  p = vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(y));\n  s = vsel_vf2_vo_vf2_vf2_avx2_sleef(p, dfneg_vf2_vf2_avx2_sleef(x), y);\n  t = vsel_vf2_vo_vf2_vf2_avx2_sleef(p, y, x);\n\n  s = dfdiv_vf2_vf2_vf2_avx2_sleef(s, t);\n  t = dfsqu_vf2_vf2_avx2_sleef(s);\n  t = dfnormalize_vf2_vf2_avx2_sleef(t);\n\n  u = vcast_vf_f_avx2_sleef(-0.00176397908944636583328247f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(0.0107900900766253471374512f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(-0.0309564601629972457885742f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(0.0577365085482597351074219f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(-0.0838950723409652709960938f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(0.109463557600975036621094f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(-0.142626821994781494140625f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(0.199983194470405578613281f));\n\n  t = dfmul_vf2_vf2_vf2_avx2_sleef(t, dfadd_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.333332866430282592773438f), vmul_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(t))));\n  t = dfmul_vf2_vf2_vf2_avx2_sleef(s, dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), t));\n  t = dfadd_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(1.5707963705062866211f, -4.3711388286737928865e-08f), vcast_vf_vi2_avx2_sleef(q)), t);\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_atan2f8_u10avx2(vfloat_avx2_sleef y, vfloat_avx2_sleef x) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(2.9387372783541830947e-39f));\n  x = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1 << 24)), x);\n  y = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(1 << 24)), y);\n\n  vfloat2_avx2_sleef d = atan2kf_u1_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), vcast_vf_f_avx2_sleef(0)), vcast_vf2_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)));\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d));\n\n  r = vmulsign_vf_vf_vf_avx2_sleef(r, x);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0))), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vf_vf_vf_avx2_sleef(x, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.141592653589793238462643383279502884/2), x))), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(y), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.141592653589793238462643383279502884/2), visinf2_vf_vf_vf_avx2_sleef(x, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3.141592653589793238462643383279502884/4), x))), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0.0f)), vreinterpret_vf_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(vsignbit_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef((float)3.141592653589793238462643383279502884)))), r);\n\n  r = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vreinterpret_vm_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(r, y))));\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_asinf8_u10avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0.5f));\n  vfloat_avx2_sleef x2 = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, d), vmul_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vabs_vf_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5f))), u;\n  vfloat2_avx2_sleef x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, vcast_vf2_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0)), dfsqrt_vf2_vf_avx2_sleef(x2));\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1.0f)), vcast_vf2_f_f_avx2_sleef(0, 0), x);\n\n  u = vcast_vf_f_avx2_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_avx2_sleef(u, vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)));\n\n  vfloat2_avx2_sleef y = dfsub_vf2_vf2_vf_avx2_sleef(dfsub_vf2_vf2_vf2_avx2_sleef(vcast_vf2_f_f_avx2_sleef(3.1415927410125732422f/4,-8.7422776573475857731e-08f/4), x), u);\n\n  vfloat_avx2_sleef r = vsel_vf_vo_vf_vf_avx2_sleef(o, vadd_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(x)),\n          vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(y)), vcast_vf_f_avx2_sleef(2)));\n  return vmulsign_vf_vf_vf_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_acosf8_u10avx2(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0.5f));\n  vfloat_avx2_sleef x2 = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, d), vmul_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vabs_vf_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5f))), u;\n  vfloat2_avx2_sleef x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, vcast_vf2_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0)), dfsqrt_vf2_vf_avx2_sleef(x2));\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1.0f)), vcast_vf2_f_f_avx2_sleef(0, 0), x);\n\n  u = vcast_vf_f_avx2_sleef(+0.4197454825e-1);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.2424046025e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.4547423869e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.7495029271e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, x2, vcast_vf_f_avx2_sleef(+0.1666677296e+0));\n  u = vmul_vf_vf_vf_avx2_sleef(u, vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)));\n\n  vfloat2_avx2_sleef y = dfsub_vf2_vf2_vf2_avx2_sleef(vcast_vf2_f_f_avx2_sleef(3.1415927410125732422f/2, -8.7422776573475857731e-08f/2),\n     dfadd_vf2_vf_vf_avx2_sleef(vmulsign_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), d), vmulsign_vf_vf_vf_avx2_sleef(u, d)));\n  x = dfadd_vf2_vf2_vf_avx2_sleef(x, u);\n\n  y = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, y, dfscale_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n\n  y = vsel_vf2_vo_vf2_vf2_avx2_sleef(vandnot_vo_vo_vo_avx2_sleef(o, vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0))),\n     dfsub_vf2_vf2_vf2_avx2_sleef(vcast_vf2_f_f_avx2_sleef(3.1415927410125732422f, -8.7422776573475857731e-08f), y), y);\n\n  return vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(y));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_atanf8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef d2 = atan2kf_u1_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(0)), vcast_vf2_f_f_avx2_sleef(1, 0));\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d2), vf2gety_vf_vf2_avx2_sleef(d2));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(1.570796326794896557998982), r);\n  return vmulsign_vf_vf_vf_avx2_sleef(r, d);\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_logf8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef x, x2, t, m;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(1.0f)), vadd_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(x, x);\n\n  t = vcast_vf_f_avx2_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.666666686534881591796875f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(2.0f));\n\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, t, vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.693147180559945286226764f), vcast_vf_vi2_avx2_sleef(e)));\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vispinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inff()), x);\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), visnan_vo_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), x);\n  x = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(-__builtin_inff()), x);\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_expf8_u10avx2(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_avx2_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-1.428606765330187045e-06f), s);\n\n  u = vcast_vf_f_avx2_sleef(0.000198527617612853646278381);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00139304355252534151077271));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00833336077630519866943359));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.0416664853692054748535156));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.166666671633720397949219));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.5));\n\n  u = vadd_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, s), u, s));\n\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-104)), vreinterpret_vm_vf_avx2_sleef(u)));\n  u = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(100), d), vcast_vf_f_avx2_sleef(__builtin_inff()), u);\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef expm1fk_avx2_sleef(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_avx2_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-1.428606765330187045e-06f), s);\n\n  vfloat_avx2_sleef s2 = vmul_vf_vf_vf_avx2_sleef(s, s), s4 = vmul_vf_vf_vf_avx2_sleef(s2, s2);\n  u = vmla_vf_vf_vf_vf_avx2_sleef((s4), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.000198527617612853646278381)), (vcast_vf_f_avx2_sleef(0.00139304355252534151077271)))), (vmla_vf_vf_vf_vf_avx2_sleef((s2), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.00833336077630519866943359)), (vcast_vf_f_avx2_sleef(0.0416664853692054748535156)))), (vmla_vf_vf_vf_vf_avx2_sleef((s), (vcast_vf_f_avx2_sleef(0.166666671633720397949219)), (vcast_vf_f_avx2_sleef(0.5)))))))\n\n         ;\n\n  u = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, s), u, s);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(0)), u,\n         vsub_vf_vf_vf_avx2_sleef(vldexp2_vf_vf_vi2_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(1)), q), vcast_vf_f_avx2_sleef(1)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sqrtf8_u35avx2(vfloat_avx2_sleef d) { return vsqrt_vf_vf_avx2_sleef(d); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_cbrtf8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef x, y, q = vcast_vf_f_avx2_sleef(1.0), t;\n  vint2_avx2_sleef e, qu, re;\n\n  e = vadd_vi2_vi2_vi2_avx2_sleef(vilogbk_vi2_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d)), vcast_vi2_i_avx2_sleef(1));\n  d = vldexp2_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n\n  t = vadd_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(e), vcast_vf_f_avx2_sleef(6144));\n  qu = vtruncate_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(t, vcast_vf_f_avx2_sleef(1.0f/3.0f)));\n  re = vtruncate_vi2_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(t, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(qu), vcast_vf_f_avx2_sleef(3))));\n\n  q = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(re, vcast_vi2_i_avx2_sleef(1)), vcast_vf_f_avx2_sleef(1.2599210498948731647672106f), q);\n  q = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(re, vcast_vi2_i_avx2_sleef(2)), vcast_vf_f_avx2_sleef(1.5874010519681994747517056f), q);\n  q = vldexp2_vf_vf_vi2_avx2_sleef(q, vsub_vi2_vi2_vi2_avx2_sleef(qu, vcast_vi2_i_avx2_sleef(2048)));\n\n  q = vmulsign_vf_vf_vf_avx2_sleef(q, d);\n  d = vabs_vf_vf_avx2_sleef(d);\n\n  x = vcast_vf_f_avx2_sleef(-0.601564466953277587890625f);\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(2.8208892345428466796875f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(-5.532182216644287109375f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(5.898262500762939453125f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(-3.8095417022705078125f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(2.2241256237030029296875f));\n\n  y = vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, x), x);\n  y = vmul_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(y, vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2.0f / 3.0f), y), vmla_vf_vf_vf_vf_avx2_sleef(y, x, vcast_vf_f_avx2_sleef(-1.0f)))), q);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_cbrtf8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef x, y, z, t;\n  vfloat2_avx2_sleef q2 = vcast_vf2_f_f_avx2_sleef(1, 0), u, v;\n  vint2_avx2_sleef e, qu, re;\n\n  e = vadd_vi2_vi2_vi2_avx2_sleef(vilogbk_vi2_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d)), vcast_vi2_i_avx2_sleef(1));\n  d = vldexp2_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n\n  t = vadd_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(e), vcast_vf_f_avx2_sleef(6144));\n  qu = vtruncate_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(t, vcast_vf_f_avx2_sleef(1.0/3.0)));\n  re = vtruncate_vi2_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(t, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(qu), vcast_vf_f_avx2_sleef(3))));\n\n  q2 = vsel_vf2_vo_vf2_vf2_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(re, vcast_vi2_i_avx2_sleef(1)), vcast_vf2_f_f_avx2_sleef(1.2599210739135742188f, -2.4018701694217270415e-08), q2);\n  q2 = vsel_vf2_vo_vf2_vf2_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(re, vcast_vi2_i_avx2_sleef(2)), vcast_vf2_f_f_avx2_sleef(1.5874010324478149414f, 1.9520385308169352356e-08), q2);\n\n  q2 = vf2setx_vf2_vf2_vf_avx2_sleef(q2, vmulsign_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(q2), d));\n  q2 = vf2sety_vf2_vf2_vf_avx2_sleef(q2, vmulsign_vf_vf_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(q2), d));\n  d = vabs_vf_vf_avx2_sleef(d);\n\n  x = vcast_vf_f_avx2_sleef(-0.601564466953277587890625f);\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(2.8208892345428466796875f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(-5.532182216644287109375f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(5.898262500762939453125f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(-3.8095417022705078125f));\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, d, vcast_vf_f_avx2_sleef(2.2241256237030029296875f));\n\n  y = vmul_vf_vf_vf_avx2_sleef(x, x); y = vmul_vf_vf_vf_avx2_sleef(y, y); x = vsub_vf_vf_vf_avx2_sleef(x, vmul_vf_vf_vf_avx2_sleef(vmlanp_vf_vf_vf_vf_avx2_sleef(d, y, x), vcast_vf_f_avx2_sleef(-1.0 / 3.0)));\n\n  z = x;\n\n  u = dfmul_vf2_vf_vf_avx2_sleef(x, x);\n  u = dfmul_vf2_vf2_vf2_avx2_sleef(u, u);\n  u = dfmul_vf2_vf2_vf_avx2_sleef(u, d);\n  u = dfadd2_vf2_vf2_vf_avx2_sleef(u, vneg_vf_vf_avx2_sleef(x));\n  y = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(u), vf2gety_vf_vf2_avx2_sleef(u));\n\n  y = vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-2.0 / 3.0), y), z);\n  v = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf_vf_avx2_sleef(z, z), y);\n  v = dfmul_vf2_vf2_vf_avx2_sleef(v, d);\n  v = dfmul_vf2_vf2_vf2_avx2_sleef(v, q2);\n  z = vldexp2_vf_vf_vi2_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(v), vf2gety_vf_vf2_avx2_sleef(v)), vsub_vi2_vi2_vi2_avx2_sleef(qu, vcast_vi2_i_avx2_sleef(2048)));\n\n  z = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(__builtin_inff()), vf2getx_vf_vf2_avx2_sleef(q2)), z);\n  z = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vreinterpret_vf_vm_avx2_sleef(vsignbit_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(q2))), z);\n\n  return z;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef logkf_avx2_sleef(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x, x2;\n  vfloat_avx2_sleef t, m;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), m), dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), m));\n  x2 = dfsqu_vf2_vf2_avx2_sleef(x);\n\n  t = vcast_vf_f_avx2_sleef(0.240320354700088500976562);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(x2), vcast_vf_f_avx2_sleef(0.285112679004669189453125));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(x2), vcast_vf_f_avx2_sleef(0.400007992982864379882812));\n  vfloat2_avx2_sleef c = vcast_vf2_f_f_avx2_sleef(0.66666662693023681640625f, 3.69183861259614332084311e-09f);\n\n  vfloat2_avx2_sleef s = dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_avx2_sleef(e));\n\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfscale_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfmul_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(x2, x),\n          dfadd2_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(x2, t), c)));\n  return s;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef logk3f_avx2_sleef(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef x, x2, t, m;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(1.0f)), vadd_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(x, x);\n\n  t = vcast_vf_f_avx2_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(0.666666686534881591796875f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(2.0f));\n\n  x = vmla_vf_vf_vf_vf_avx2_sleef(x, t, vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.693147180559945286226764f), vcast_vf_vi2_avx2_sleef(e)));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_logf8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x;\n  vfloat_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n  vfloat2_avx2_sleef s = dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_avx2_sleef(e));\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), m), dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x));\n\n  t = vcast_vf_f_avx2_sleef(+0.3027294874e+0f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.3996108174e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.6666694880e+0f));\n\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfscale_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)), t));\n\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), vf2gety_vf_vf2_avx2_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vispinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inff()), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), visnan_vo_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(-__builtin_inff()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef expkf_avx2_sleef(vfloat2_avx2_sleef d) {\n  vfloat_avx2_sleef u = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)), vcast_vf_f_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f));\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n  vfloat2_avx2_sleef s, t;\n\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(d, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-0.693145751953125f)));\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-1.428606765330187045e-06f)));\n\n  s = dfnormalize_vf2_vf2_avx2_sleef(s);\n\n  u = vcast_vf_f_avx2_sleef(0.00136324646882712841033936f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.00836596917361021041870117f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.0416710823774337768554688f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.166665524244308471679688f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(0.499999850988388061523438f));\n\n  t = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfmul_vf2_vf2_vf_avx2_sleef(dfsqu_vf2_vf2_avx2_sleef(s), u));\n\n  t = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), t);\n  u = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t), vf2gety_vf_vf2_avx2_sleef(t));\n  u = vldexp_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vcast_vf_f_avx2_sleef(-104)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef expk3f_avx2_sleef(vfloat_avx2_sleef d) {\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f)));\n  vfloat_avx2_sleef s, u;\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-0.693145751953125f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-1.428606765330187045e-06f), s);\n\n  u = vcast_vf_f_avx2_sleef(0.000198527617612853646278381);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00139304355252534151077271));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.00833336077630519866943359));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.0416664853692054748535156));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.166666671633720397949219));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(0.5));\n\n  u = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(s, s), u, vadd_vf_vf_vf_avx2_sleef(s, vcast_vf_f_avx2_sleef(1.0f)));\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-104)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_powf8_u10avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n\n  vopmask_avx2_sleef yisint = vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vtruncate_vf_vf_avx2_sleef(y), y), vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), vcast_vf_f_avx2_sleef(1 << 24)));\n  vopmask_avx2_sleef yisodd = vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(y), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), yisint),\n     vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), vcast_vf_f_avx2_sleef(1 << 24)));\n\n  vfloat_avx2_sleef result = expkf_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(logkf_avx2_sleef(vabs_vf_vf_avx2_sleef(x)), y));\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(visnan_vo_vf_avx2_sleef(result), vcast_vf_f_avx2_sleef(__builtin_inff()), result);\n\n  result = vmul_vf_vf_vf_avx2_sleef(result,\n    vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)),\n       vcast_vf_f_avx2_sleef(1),\n       vsel_vf_vo_vf_vf_avx2_sleef(yisint, vsel_vf_vo_vf_vf_avx2_sleef(yisodd, vcast_vf_f_avx2_sleef(-1.0f), vcast_vf_f_avx2_sleef(1)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")))));\n\n  vfloat_avx2_sleef efx = vmulsign_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(1)), y);\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(y),\n       vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(efx, vcast_vf_f_avx2_sleef(0.0f)),\n          vreinterpret_vm_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(efx, vcast_vf_f_avx2_sleef(0.0f)),\n                  vcast_vf_f_avx2_sleef(1.0f),\n                  vcast_vf_f_avx2_sleef(__builtin_inff()))))),\n       result);\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0.0))),\n       vmulsign_vf_vf_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(vxor_vo_vo_vo_avx2_sleef(vsignbit_vo_vf_avx2_sleef(y), veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0.0f))),\n              vcast_vf_f_avx2_sleef(0), vcast_vf_f_avx2_sleef(__builtin_inff())),\n           vsel_vf_vo_vf_vf_avx2_sleef(yisodd, x, vcast_vf_f_avx2_sleef(1))), result);\n\n  result = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vreinterpret_vm_vf_avx2_sleef(result)));\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)), veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1))), vcast_vf_f_avx2_sleef(1), result);\n\n  return result;\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fastpowf8_u3500avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef result = expk3f_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(logk3f_avx2_sleef(vabs_vf_vf_avx2_sleef(x)), y));\n  vopmask_avx2_sleef yisint = vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vtruncate_vf_vf_avx2_sleef(y), y), vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), vcast_vf_f_avx2_sleef(1 << 24)));\n  vopmask_avx2_sleef yisodd = vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(y), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)), yisint),\n     vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(y), vcast_vf_f_avx2_sleef(1 << 24)));\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vsignbit_vo_vf_avx2_sleef(x), yisodd), vneg_vf_vf_avx2_sleef(result), result);\n\n  result = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(0), result);\n  result = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(1), result);\n\n  return result;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef expk2f_avx2_sleef(vfloat2_avx2_sleef d) {\n  vfloat_avx2_sleef u = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)), vcast_vf_f_avx2_sleef(1.442695040888963407359924681001892137426645954152985934135449406931f));\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n  vfloat2_avx2_sleef s, t;\n\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(d, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-0.693145751953125f)));\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vcast_vf_vi2_avx2_sleef(q), vcast_vf_f_avx2_sleef(-1.428606765330187045e-06f)));\n\n  u = vcast_vf_f_avx2_sleef(+0.1980960224e-3f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(+0.1394256484e-2f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(+0.8333456703e-2f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, vf2getx_vf_vf2_avx2_sleef(s), vcast_vf_f_avx2_sleef(+0.4166637361e-1f));\n\n  t = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(s, u), vcast_vf_f_avx2_sleef(+0.166666659414234244790680580464e+0f));\n  t = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(s, t), vcast_vf_f_avx2_sleef(0.5));\n  t = dfadd2_vf2_vf2_vf2_avx2_sleef(s, dfmul_vf2_vf2_vf2_avx2_sleef(dfsqu_vf2_vf2_avx2_sleef(s), t));\n\n  t = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), t);\n\n  t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vldexp2_vf_vf_vi2_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t), q));\n  t = vf2sety_vf2_vf2_vf_avx2_sleef(t, vldexp2_vf_vf_vi2_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(t), q));\n\n  t = vf2setx_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vcast_vf_f_avx2_sleef(-104)), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t)))));\n  t = vf2sety_vf2_vf2_vf_avx2_sleef(t, vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vcast_vf_f_avx2_sleef(-104)), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(t)))));\n\n  return t;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sinhf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef y = vabs_vf_vf_avx2_sleef(x);\n  vfloat2_avx2_sleef d = expk2f_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)));\n  d = dfsub_vf2_vf2_vf2_avx2_sleef(d, dfrec_vf2_vf2_avx2_sleef(d));\n  y = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(89)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_inff()), y);\n  y = vmulsign_vf_vf_vf_avx2_sleef(y, x);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_coshf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef y = vabs_vf_vf_avx2_sleef(x);\n  vfloat2_avx2_sleef d = expk2f_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)));\n  d = dfadd_vf2_vf2_vf2_avx2_sleef(d, dfrec_vf2_vf2_avx2_sleef(d));\n  y = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(89)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_inff()), y);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_tanhf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef y = vabs_vf_vf_avx2_sleef(x);\n  vfloat2_avx2_sleef d = expk2f_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)));\n  vfloat2_avx2_sleef e = dfrec_vf2_vf2_avx2_sleef(d);\n  d = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd_vf2_vf2_vf2_avx2_sleef(d, dfneg_vf2_vf2_avx2_sleef(e)), dfadd_vf2_vf2_vf2_avx2_sleef(d, e));\n  y = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(8.664339742f)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(1.0f), y);\n  y = vmulsign_vf_vf_vf_avx2_sleef(y, x);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sinhf8_u35avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef e = expm1fk_avx2_sleef(vabs_vf_vf_avx2_sleef(x));\n  vfloat_avx2_sleef y = vdiv_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(e, vcast_vf_f_avx2_sleef(2)), vadd_vf_vf_vf_avx2_sleef(e, vcast_vf_f_avx2_sleef(1)));\n  y = vmul_vf_vf_vf_avx2_sleef(y, vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5f), e));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(88)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_inff()), y);\n  y = vmulsign_vf_vf_vf_avx2_sleef(y, x);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_coshf8_u35avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef e = Sleef_expf8_u10avx2(vabs_vf_vf_avx2_sleef(x));\n  vfloat_avx2_sleef y = vmla_vf_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5f), e, vdiv_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5), e));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(88)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_inff()), y);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_tanhf8_u35avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef d = expm1fk_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2), vabs_vf_vf_avx2_sleef(x)));\n  vfloat_avx2_sleef y = vdiv_vf_vf_vf_avx2_sleef(d, vadd_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2), d));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(8.664339742f)),\n        visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(1.0f), y);\n  y = vmulsign_vf_vf_vf_avx2_sleef(y, x);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef logk2f_avx2_sleef(vfloat2_avx2_sleef d) {\n  vfloat2_avx2_sleef x, x2, m, s;\n  vfloat_avx2_sleef t;\n  vint2_avx2_sleef e;\n\n  e = vilogbk_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n\n  m = dfscale_vf2_vf2_vf_avx2_sleef(d, vpow2i_vf_vi2_avx2_sleef(vneg_vi2_vi2_avx2_sleef(e)));\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(-1)), dfadd2_vf2_vf2_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(1)));\n  x2 = dfsqu_vf2_vf2_avx2_sleef(x);\n\n  t = vcast_vf_f_avx2_sleef(0.2392828464508056640625f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(x2), vcast_vf_f_avx2_sleef(0.28518211841583251953125f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(x2), vcast_vf_f_avx2_sleef(0.400005877017974853515625f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(x2), vcast_vf_f_avx2_sleef(0.666666686534881591796875f));\n\n  s = dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.69314718246459960938f), vcast_vf_f_avx2_sleef(-1.904654323148236017e-09f)), vcast_vf_vi2_avx2_sleef(e));\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfscale_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfmul_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(x2, x), t));\n\n  return s;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_asinhf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef y = vabs_vf_vf_avx2_sleef(x);\n  vopmask_avx2_sleef o = vgt_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(1));\n  vfloat2_avx2_sleef d;\n\n  d = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfrec_vf2_vf_avx2_sleef(x), vcast_vf2_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0)));\n  d = dfsqrt_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(dfsqu_vf2_vf2_avx2_sleef(d), vcast_vf_f_avx2_sleef(1)));\n  d = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfmul_vf2_vf2_vf_avx2_sleef(d, y), d);\n\n  d = logk2f_avx2_sleef(dfnormalize_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(d, x)));\n  y = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(18446743523953729536.0)),\n        visnan_vo_vf_avx2_sleef(y)),\n         vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(__builtin_inff()), x), y);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n  y = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(-0.0), y);\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_acoshf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat2_avx2_sleef d = logk2f_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(dfsqrt_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1))), dfsqrt_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(-1)))), x));\n  vfloat_avx2_sleef y = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d));\n\n  y = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(18446743523953729536.0)),\n        visnan_vo_vf_avx2_sleef(y)),\n         vcast_vf_f_avx2_sleef(__builtin_inff()), y);\n\n  y = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1.0f)), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1.0f)), vreinterpret_vm_vf_avx2_sleef(y)));\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_atanhf8_u10avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef y = vabs_vf_vf_avx2_sleef(x);\n  vfloat2_avx2_sleef d = logk2f_avx2_sleef(dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), y), dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vneg_vf_vf_avx2_sleef(y))));\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(1.0)), vreinterpret_vm_vf_avx2_sleef(vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(1.0)), vcast_vf_f_avx2_sleef(__builtin_inff()), vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d)), vcast_vf_f_avx2_sleef(0.5))))));\n\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vreinterpret_vm_vf_avx2_sleef(y)));\n  y = vmulsign_vf_vf_vf_avx2_sleef(y, x);\n  y = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visnan_vo_vf_avx2_sleef(x), vreinterpret_vm_vf_avx2_sleef(y)));\n\n  return y;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_exp2f8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef u = vrint_vf_vf_avx2_sleef(d), s;\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n\n  s = vsub_vf_vf_vf_avx2_sleef(d, u);\n\n  u = vcast_vf_f_avx2_sleef(+0.1535920892e-3);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1339262701e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.9618384764e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.5550347269e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2402264476e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.6931471825e+0));\n\n  u = vfma_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(1));\n\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(vge_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(128)), vcast_vf_f_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-150)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_exp2f8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef u = vrint_vf_vf_avx2_sleef(d), s;\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n\n  s = vsub_vf_vf_vf_avx2_sleef(d, u);\n\n  u = vcast_vf_f_avx2_sleef(+0.1535920892e-3);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1339262701e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.9618384764e-2));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.5550347269e-1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2402264476e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.6931471825e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1000000000e+1));\n\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(vge_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(128)), vcast_vf_f_avx2_sleef(__builtin_inf()), u);\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-150)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_exp10f8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef u = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.3010253906f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-4.605038981e-06f), s);\n\n  u = vcast_vf_f_avx2_sleef(+0.6802555919e-1);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2078080326e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.5393903852e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1171245337e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2034678698e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2650949001e+1));\n  vfloat2_avx2_sleef x = dfadd_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(2.3025851249694824219, -3.1705172516493593157e-08), vmul_vf_vf_vf_avx2_sleef(u, s));\n  u = vf2getx_vf_vf2_avx2_sleef(dfnormalize_vf2_vf2_avx2_sleef(dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf2_vf_avx2_sleef(x, s))));\n\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(38.5318394191036238941387f)), vcast_vf_f_avx2_sleef(__builtin_inff()), u);\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-50)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_exp10f8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef u = vrint_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(3.3219280948873623478703194294893901758648313930))), s;\n  vint2_avx2_sleef q = vrint_vi2_vf_avx2_sleef(u);\n\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-0.3010253906f), d);\n  s = vmla_vf_vf_vf_vf_avx2_sleef(u, vcast_vf_f_avx2_sleef(-4.605038981e-06f), s);\n\n  u = vcast_vf_f_avx2_sleef(+0.2064004987e+0);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.5417877436e+0));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1171286821e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2034656048e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2650948763e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.2302585125e+1));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vcast_vf_f_avx2_sleef(+0.1000000000e+1));\n\n  u = vldexp2_vf_vf_vi2_avx2_sleef(u, q);\n\n  u = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(38.5318394191036238941387f)), vcast_vf_f_avx2_sleef(__builtin_inff()), u);\n  u = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-50)), vreinterpret_vm_vf_avx2_sleef(u)));\n\n  return u;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_expm1f8_u10avx2(vfloat_avx2_sleef a) {\n  vfloat2_avx2_sleef d = dfadd2_vf2_vf2_vf_avx2_sleef(expk2f_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0))), vcast_vf_f_avx2_sleef(-1.0));\n  vfloat_avx2_sleef x = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(d), vf2gety_vf_vf2_avx2_sleef(d));\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(88.72283172607421875f)), vcast_vf_f_avx2_sleef(__builtin_inff()), x);\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(-16.635532333438687426013570f)), vcast_vf_f_avx2_sleef(-1), x);\n  x = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(a), vcast_vf_f_avx2_sleef(-0.0f), x);\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_log10f8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x;\n  vfloat_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), m), dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x));\n\n  t = vcast_vf_f_avx2_sleef(+0.1314289868e+0);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef( +0.1735493541e+0));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef( +0.2895309627e+0));\n\n  vfloat2_avx2_sleef s = dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(0.30103001, -1.432098889e-08), vcast_vf_vi2_avx2_sleef(e));\n\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfmul_vf2_vf2_vf2_avx2_sleef(x, vcast_vf2_f_f_avx2_sleef(0.868588984, -2.170757285e-08)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)), t));\n\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), vf2gety_vf_vf2_avx2_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vispinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), visnan_vo_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_log2f8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x;\n  vfloat_avx2_sleef t, m, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), m), dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x));\n\n  t = vcast_vf_f_avx2_sleef(+0.4374550283e+0f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.5764790177e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.9618012905120f));\n\n  vfloat2_avx2_sleef s = dfadd2_vf2_vf_vf2_avx2_sleef(vcast_vf_vi2_avx2_sleef(e),\n    dfmul_vf2_vf2_vf2_avx2_sleef(x, vcast_vf2_f_f_avx2_sleef(2.8853900432586669922, 3.2734474483568488616e-08)));\n\n  s = dfadd2_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)), t));\n\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), vf2gety_vf_vf2_avx2_sleef(s));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vispinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), visnan_vo_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_log2f8_u35avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef m, t, x, x2;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), d);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.0/0.75)));\n  m = vldexp3_vf_vf_vi2_avx2_sleef(d, vneg_vi2_vi2_avx2_sleef(e));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n\n  x = vdiv_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(1)), vadd_vf_vf_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(1)));\n  x2 = vmul_vf_vf_vf_avx2_sleef(x, x);\n\n  t = vcast_vf_f_avx2_sleef(+0.4374088347e+0);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.5764843822e+0));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.9618024230e+0));\n\n  vfloat_avx2_sleef r = vmla_vf_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x2, x), t,\n         vmla_vf_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(+0.2885390043e+1), vcast_vf_vi2_avx2_sleef(e)));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vispinf_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(__builtin_inf()), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), visnan_vo_vf_avx2_sleef(d)), vcast_vf_f_avx2_sleef(__builtin_nan(\"\")), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(-__builtin_inf()), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_log1pf8_u10avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x;\n  vfloat_avx2_sleef t, m, x2;\n\n  vfloat_avx2_sleef dp1 = vadd_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1));\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(dp1, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  dp1 = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(dp1, vcast_vf_f_avx2_sleef((float)(INT64_C(1) << 32) * (float)(INT64_C(1) << 32))), dp1);\n  vint2_avx2_sleef e = vilogb2k_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(dp1, vcast_vf_f_avx2_sleef(1.0f/0.75f)));\n  t = vldexp3_vf_vf_vi2_avx2_sleef(vcast_vf_f_avx2_sleef(1), vneg_vi2_vi2_avx2_sleef(e));\n  m = vmla_vf_vf_vf_vf_avx2_sleef(d, t, vsub_vf_vf_vf_avx2_sleef(t, vcast_vf_f_avx2_sleef(1)));\n  e = vsel_vi2_vo_vi2_vi2_avx2_sleef(o, vsub_vi2_vi2_vi2_avx2_sleef(e, vcast_vi2_i_avx2_sleef(64)), e);\n  vfloat2_avx2_sleef s = dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(0.69314718246459960938f, -1.904654323148236017e-09f), vcast_vf_vi2_avx2_sleef(e));\n\n  x = dfdiv_vf2_vf2_vf2_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(m, vcast_vf_f_avx2_sleef(0)), dfadd_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2), m));\n  x2 = vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2getx_vf_vf2_avx2_sleef(x));\n\n  t = vcast_vf_f_avx2_sleef(+0.3027294874e+0f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.3996108174e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, x2, vcast_vf_f_avx2_sleef(+0.6666694880e+0f));\n\n  s = dfadd_vf2_vf2_vf2_avx2_sleef(s, dfscale_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)));\n  s = dfadd_vf2_vf2_vf_avx2_sleef(s, vmul_vf_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x2, vf2getx_vf_vf2_avx2_sleef(x)), t));\n\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(s), vf2gety_vf_vf2_avx2_sleef(s));\n\n  vopmask_avx2_sleef ocore = vle_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(9.99999968028569247e+37));\n  if(!__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef (ocore)), 1)) r = vsel_vf_vo_vf_vf_avx2_sleef(ocore, r, Sleef_logf8_u10avx2(d));\n  r = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), d), vreinterpret_vm_vf_avx2_sleef(r)));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(-1)), vcast_vf_f_avx2_sleef(-__builtin_inff()), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(-0.0f), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fabsf8_avx2(vfloat_avx2_sleef x) { return vabs_vf_vf_avx2_sleef(x); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_copysignf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) { return vcopysign_vf_vf_vf_avx2_sleef(x, y); }\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fmaxf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n\n  return vsel_vf_vo_vf_vf_avx2_sleef(visnan_vo_vf_avx2_sleef(y), x, vmax_vf_vf_vf_avx2_sleef(x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fminf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n\n  return vsel_vf_vo_vf_vf_avx2_sleef(visnan_vo_vf_avx2_sleef(y), x, vmin_vf_vf_vf_avx2_sleef(x, y));\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fdimf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef ret = vsub_vf_vf_vf_avx2_sleef(x, y);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(ret, vcast_vf_f_avx2_sleef(0)), veq_vo_vf_vf_avx2_sleef(x, y)), vcast_vf_f_avx2_sleef(0), ret);\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_truncf8_avx2(vfloat_avx2_sleef x) {\n\n  return vtruncate_vf_vf_avx2_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_floorf8_avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef fr = vsub_vf_vf_vf_avx2_sleef(x, vcast_vf_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(0)), vadd_vf_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(1.0f)), fr);\n  return vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), vge_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(INT64_C(1) << 23))), x, vcopysign_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, fr), x));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_ceilf8_avx2(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef fr = vsub_vf_vf_vf_avx2_sleef(x, vcast_vf_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(x)));\n  fr = vsel_vf_vo_vf_vf_avx2_sleef(vle_vo_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(0)), fr, vsub_vf_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(1.0f)));\n  return vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(x), vge_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(INT64_C(1) << 23))), x, vcopysign_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, fr), x));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_roundf8_avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef x = vadd_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.5f));\n  vfloat_avx2_sleef fr = vsub_vf_vf_vf_avx2_sleef(x, vcast_vf_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(x)));\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vle_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), veq_vo_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(0))), vsub_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1.0f)), x);\n  fr = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(0)), vadd_vf_vf_vf_avx2_sleef(fr, vcast_vf_f_avx2_sleef(1.0f)), fr);\n  x = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.4999999701976776123f)), vcast_vf_f_avx2_sleef(0), x);\n  return vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vge_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(INT64_C(1) << 23))), d, vcopysign_vf_vf_vf_avx2_sleef(vsub_vf_vf_vf_avx2_sleef(x, fr), d));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_rintf8_avx2(vfloat_avx2_sleef d) {\n\n  return vrint_vf_vf_avx2_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fmaf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y, vfloat_avx2_sleef z) {\n  return vfma_vf_vf_vf_vf_avx2_sleef(x, y, z);\n}\n\nSLEEF_INLINE vfloat_avx2_sleef Sleef_sqrtf8_u05avx2(vfloat_avx2_sleef d) {\n  vfloat_avx2_sleef q, w, x, y, z;\n\n  d = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), d);\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(5.2939559203393770e-23f));\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.8889465931478580e+22f)), d);\n  q = vsel_vf_vo_vf_vf_avx2_sleef(o, vcast_vf_f_avx2_sleef(7.2759576141834260e-12f), vcast_vf_f_avx2_sleef(1.0f));\n\n  y = vreinterpret_vf_vi2_avx2_sleef(vsub_vi2_vi2_vi2_avx2_sleef(vcast_vi2_i_avx2_sleef(0x5f3759df), vsrl_vi2_vi2_i_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(d), 1)));\n\n  x = vmul_vf_vf_vf_avx2_sleef(d, y); w = vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5), y);\n  y = vfmanp_vf_vf_vf_vf_avx2_sleef(x, w, vcast_vf_f_avx2_sleef(0.5));\n  x = vfma_vf_vf_vf_vf_avx2_sleef(x, y, x); w = vfma_vf_vf_vf_vf_avx2_sleef(w, y, w);\n  y = vfmanp_vf_vf_vf_vf_avx2_sleef(x, w, vcast_vf_f_avx2_sleef(0.5));\n  x = vfma_vf_vf_vf_vf_avx2_sleef(x, y, x); w = vfma_vf_vf_vf_vf_avx2_sleef(w, y, w);\n\n  y = vfmanp_vf_vf_vf_vf_avx2_sleef(x, w, vcast_vf_f_avx2_sleef(1.5)); w = vadd_vf_vf_vf_avx2_sleef(w, w);\n  w = vmul_vf_vf_vf_avx2_sleef(w, y);\n  x = vmul_vf_vf_vf_avx2_sleef(w, d);\n  y = vfmapn_vf_vf_vf_vf_avx2_sleef(w, d, x); z = vfmanp_vf_vf_vf_vf_avx2_sleef(w, x, vcast_vf_f_avx2_sleef(1));\n\n  z = vfmanp_vf_vf_vf_vf_avx2_sleef(w, y, z); w = vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5), x);\n  w = vfma_vf_vf_vf_vf_avx2_sleef(w, z, y);\n  w = vadd_vf_vf_vf_avx2_sleef(w, x);\n\n  w = vmul_vf_vf_vf_avx2_sleef(w, q);\n\n  w = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)),\n        veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(__builtin_inff()))), d, w);\n\n  w = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), w);\n\n  return w;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sqrtf8_avx2(vfloat_avx2_sleef d) {\n\n  return vsqrt_vf_vf_avx2_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_hypotf8_u05avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  x = vabs_vf_vf_avx2_sleef(x);\n  y = vabs_vf_vf_avx2_sleef(y);\n  vfloat_avx2_sleef min = vmin_vf_vf_vf_avx2_sleef(x, y), n = min;\n  vfloat_avx2_sleef max = vmax_vf_vf_vf_avx2_sleef(x, y), d = max;\n\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(max, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  n = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(n, vcast_vf_f_avx2_sleef(UINT64_C(1) << 24)), n);\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(UINT64_C(1) << 24)), d);\n\n  vfloat2_avx2_sleef t = dfdiv_vf2_vf2_vf2_avx2_sleef(vcast_vf2_vf_vf_avx2_sleef(n, vcast_vf_f_avx2_sleef(0)), vcast_vf2_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)));\n  t = dfmul_vf2_vf2_vf_avx2_sleef(dfsqrt_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(dfsqu_vf2_vf2_avx2_sleef(t), vcast_vf_f_avx2_sleef(1))), max);\n  vfloat_avx2_sleef ret = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t), vf2gety_vf_vf2_avx2_sleef(t));\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(visnan_vo_vf_avx2_sleef(ret), vcast_vf_f_avx2_sleef(__builtin_inff()), ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(min, vcast_vf_f_avx2_sleef(0)), max, ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(__builtin_inff())), veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(__builtin_inff()))), vcast_vf_f_avx2_sleef(__builtin_inff()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_hypotf8_u35avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  x = vabs_vf_vf_avx2_sleef(x);\n  y = vabs_vf_vf_avx2_sleef(y);\n  vfloat_avx2_sleef min = vmin_vf_vf_vf_avx2_sleef(x, y);\n  vfloat_avx2_sleef max = vmax_vf_vf_vf_avx2_sleef(x, y);\n\n  vfloat_avx2_sleef t = vdiv_vf_vf_vf_avx2_sleef(min, max);\n  vfloat_avx2_sleef ret = vmul_vf_vf_vf_avx2_sleef(max, vsqrt_vf_vf_avx2_sleef(vmla_vf_vf_vf_vf_avx2_sleef(t, t, vcast_vf_f_avx2_sleef(1))));\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(min, vcast_vf_f_avx2_sleef(0)), max, ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(__builtin_inff())), veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(__builtin_inff()))), vcast_vf_f_avx2_sleef(__builtin_inff()), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_nextafterf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  x = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0), y), x);\n  vint2_avx2_sleef xi2 = vreinterpret_vi2_vf_avx2_sleef(x);\n  vopmask_avx2_sleef c = vxor_vo_vo_vo_avx2_sleef(vsignbit_vo_vf_avx2_sleef(x), vge_vo_vf_vf_avx2_sleef(y, x));\n\n  xi2 = vsel_vi2_vo_vi2_vi2_avx2_sleef(c, vsub_vi2_vi2_vi2_avx2_sleef(vcast_vi2_i_avx2_sleef(0), vxor_vi2_vi2_vi2_avx2_sleef(xi2, vcast_vi2_i_avx2_sleef((int)(1U << 31)))), xi2);\n\n  xi2 = vsel_vi2_vo_vi2_vi2_avx2_sleef(vneq_vo_vf_vf_avx2_sleef(x, y), vsub_vi2_vi2_vi2_avx2_sleef(xi2, vcast_vi2_i_avx2_sleef(1)), xi2);\n\n  xi2 = vsel_vi2_vo_vi2_vi2_avx2_sleef(c, vsub_vi2_vi2_vi2_avx2_sleef(vcast_vi2_i_avx2_sleef(0), vxor_vi2_vi2_vi2_avx2_sleef(xi2, vcast_vi2_i_avx2_sleef((int)(1U << 31)))), xi2);\n\n  vfloat_avx2_sleef ret = vreinterpret_vf_vi2_avx2_sleef(xi2);\n\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(ret, vcast_vf_f_avx2_sleef(0)), vneq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0))),\n    vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0), x), ret);\n\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), veq_vo_vf_vf_avx2_sleef(y, vcast_vf_f_avx2_sleef(0))), y, ret);\n\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(visnan_vo_vf_avx2_sleef(x), visnan_vo_vf_avx2_sleef(y)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_frfrexpf8_avx2(vfloat_avx2_sleef x) {\n  x = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(1.17549435082228751e-38)), vmul_vf_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(UINT64_C(1) << 30)), x);\n\n  vmask_avx2_sleef xm = vreinterpret_vm_vf_avx2_sleef(x);\n  xm = vand_vm_vm_vm_avx2_sleef(xm, vcast_vm_i_i_avx2_sleef(~0x7f800000U, ~0x7f800000U));\n  xm = vor_vm_vm_vm_avx2_sleef (xm, vcast_vm_i_i_avx2_sleef( 0x3f000000U, 0x3f000000U));\n\n  vfloat_avx2_sleef ret = vreinterpret_vf_vm_avx2_sleef(xm);\n\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(x), vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(__builtin_inff()), x), ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), x, ret);\n\n  return ret;\n}\n\nSLEEF_INLINE SLEEF_CONST vint2_avx2_sleef Sleef_expfrexpf8_avx2(vfloat_avx2_sleef x) {\n\n  return vcast_vi2_i_avx2_sleef(0);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vtoward0_vf_vf_avx2_sleef(vfloat_avx2_sleef x) {\n  vfloat_avx2_sleef t = vreinterpret_vf_vi2_avx2_sleef(vsub_vi2_vi2_vi2_avx2_sleef(vreinterpret_vi2_vf_avx2_sleef(x), vcast_vi2_i_avx2_sleef(1)));\n  return vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(0), t);\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vptrunc_vf_vf_avx2_sleef(vfloat_avx2_sleef x) {\n\n  return vtruncate_vf_vf_avx2_sleef(x);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_fmodf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef nu = vabs_vf_vf_avx2_sleef(x), de = vabs_vf_vf_avx2_sleef(y), s = vcast_vf_f_avx2_sleef(1), q;\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(de, vcast_vf_f_avx2_sleef(1.17549435082228751e-38));\n  nu = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(nu, vcast_vf_f_avx2_sleef(UINT64_C(1) << 25)), nu);\n  de = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(de, vcast_vf_f_avx2_sleef(UINT64_C(1) << 25)), de);\n  s = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(s , vcast_vf_f_avx2_sleef(1.0f / (UINT64_C(1) << 25))), s);\n  vfloat_avx2_sleef rde = vtoward0_vf_vf_avx2_sleef(vrec_vf_vf_avx2_sleef(de));\n  vfloat2_avx2_sleef r = vcast_vf2_vf_vf_avx2_sleef(nu, vcast_vf_f_avx2_sleef(0));\n\n  for(int i=0;i<8;i++) {\n    q = vptrunc_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vtoward0_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)), rde));\n    q = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(3), de), vf2getx_vf_vf2_avx2_sleef(r)),\n           vge_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), de)),\n    vcast_vf_f_avx2_sleef(2), q);\n    q = vsel_vf_vo_vf_vf_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2), de), vf2getx_vf_vf2_avx2_sleef(r)),\n           vge_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), de)),\n    vcast_vf_f_avx2_sleef(1), q);\n    r = dfnormalize_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf2_avx2_sleef(r, dfmul_vf2_vf_vf_avx2_sleef(vptrunc_vf_vf_avx2_sleef(q), vneg_vf_vf_avx2_sleef(de))));\n    if (vtestallones_i_vo32_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), de))) break;\n  }\n\n  vfloat_avx2_sleef ret = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), vf2gety_vf_vf2_avx2_sleef(r)), s);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), vf2gety_vf_vf2_avx2_sleef(r)), de), vcast_vf_f_avx2_sleef(0), ret);\n\n  ret = vmulsign_vf_vf_vf_avx2_sleef(ret, x);\n\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(nu, de), x, ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(de, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), ret);\n\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat_avx2_sleef vrintfk2_vf_vf_avx2_sleef(vfloat_avx2_sleef d) {\n\n  return vrint_vf_vf_avx2_sleef(d);\n\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_remainderf8_avx2(vfloat_avx2_sleef x, vfloat_avx2_sleef y) {\n  vfloat_avx2_sleef n = vabs_vf_vf_avx2_sleef(x), d = vabs_vf_vf_avx2_sleef(y), s = vcast_vf_f_avx2_sleef(1), q;\n  vopmask_avx2_sleef o = vlt_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.17549435082228751e-38*2));\n  n = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(n, vcast_vf_f_avx2_sleef(UINT64_C(1) << 25)), n);\n  d = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(UINT64_C(1) << 25)), d);\n  s = vsel_vf_vo_vf_vf_avx2_sleef(o, vmul_vf_vf_vf_avx2_sleef(s , vcast_vf_f_avx2_sleef(1.0f / (UINT64_C(1) << 25))), s);\n  vfloat2_avx2_sleef r = vcast_vf2_vf_vf_avx2_sleef(n, vcast_vf_f_avx2_sleef(0));\n  vfloat_avx2_sleef rd = vrec_vf_vf_avx2_sleef(d);\n  vopmask_avx2_sleef qisodd = vneq_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0), vcast_vf_f_avx2_sleef(0));\n\n  for(int i=0;i<8;i++) {\n    q = vrintfk2_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), rd));\n    q = vsel_vf_vo_vf_vf_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)), vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(1.5f))), vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1.0f), vf2getx_vf_vf2_avx2_sleef(r)), q);\n    q = vsel_vf_vo_vf_vf_avx2_sleef(vor_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)), vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.5f))),\n          vandnot_vo_vo_vo_avx2_sleef(qisodd, veq_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r)), vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0.5f))))),\n    vcast_vf_f_avx2_sleef(0.0), q);\n    if (vtestallones_i_vo32_avx2_sleef(veq_vo_vf_vf_avx2_sleef(q, vcast_vf_f_avx2_sleef(0)))) break;\n    q = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(q, vneg_vf_vf_avx2_sleef(d))), vadd_vf_vf_vf_avx2_sleef(q, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-1), vf2getx_vf_vf2_avx2_sleef(r))), q);\n    qisodd = vxor_vo_vo_vo_avx2_sleef(qisodd, vand_vo_vo_vo_avx2_sleef(veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(q), vcast_vi2_i_avx2_sleef(1)), vcast_vi2_i_avx2_sleef(1)),\n       vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(q), vcast_vf_f_avx2_sleef(1 << 24))));\n    r = dfnormalize_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf2_avx2_sleef(r, dfmul_vf2_vf_vf_avx2_sleef(q, vneg_vf_vf_avx2_sleef(d))));\n  }\n\n  vfloat_avx2_sleef ret = vmul_vf_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(r), vf2gety_vf_vf2_avx2_sleef(r)), s);\n  ret = vmulsign_vf_vf_vf_avx2_sleef(ret, x);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(y), vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(x), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), x), ret);\n  ret = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), ret);\n  return ret;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef sinpifk_avx2_sleef(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, t;\n  vfloat2_avx2_sleef x, s2;\n\n  u = vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(4.0));\n  vint2_avx2_sleef q = vtruncate_vi2_vf_avx2_sleef(u);\n  q = vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vxor_vi2_vi2_vi2_avx2_sleef(vsrl_vi2_vi2_i_avx2_sleef(q, 31), vcast_vi2_i_avx2_sleef(1))), vcast_vi2_i_avx2_sleef(~1));\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(2));\n\n  s = vsub_vf_vf_vf_avx2_sleef(u, vcast_vf_vi2_avx2_sleef(q));\n  t = s;\n  s = vmul_vf_vf_vf_avx2_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_avx2_sleef(t, t);\n\n  u = vsel_vf_vo_f_f_avx2_sleef(o, -0.2430611801e-7f, +0.3093842054e-6f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vsel_vf_vo_f_f_avx2_sleef(o, +0.3590577080e-5f, -0.3657307388e-4f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vsel_vf_vo_f_f_avx2_sleef(o, -0.3259917721e-3f, +0.2490393585e-2f));\n  x = dfadd2_vf2_vf_vf2_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(u, s),\n   vsel_vf2_vo_f_f_f_f_avx2_sleef(o, 0.015854343771934509277, 4.4940051354032242811e-10,\n         -0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(s2, x),\n    vsel_vf2_vo_f_f_f_f_avx2_sleef(o, -0.30842512845993041992, -9.0728339030733922277e-09,\n          0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf2_avx2_sleef(x, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, s2, vcast_vf2_vf_vf_avx2_sleef(t, vcast_vf_f_avx2_sleef(0))));\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1)), x);\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  x = vf2setx_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)))));\n  x = vf2sety_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_sinpif8_u05avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x = sinpifk_avx2_sleef(d);\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visnegzero_vo_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(-0.0), r);\n  r = vreinterpret_vf_vm_avx2_sleef(vandnot_vm_vo32_vm_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(8e+6f)), vreinterpret_vm_vf_avx2_sleef(r)));\n  r = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vreinterpret_vm_vf_avx2_sleef(r)));\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef cospifk_avx2_sleef(vfloat_avx2_sleef d) {\n  vopmask_avx2_sleef o;\n  vfloat_avx2_sleef u, s, t;\n  vfloat2_avx2_sleef x, s2;\n\n  u = vmul_vf_vf_vf_avx2_sleef(d, vcast_vf_f_avx2_sleef(4.0));\n  vint2_avx2_sleef q = vtruncate_vi2_vf_avx2_sleef(u);\n  q = vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vxor_vi2_vi2_vi2_avx2_sleef(vsrl_vi2_vi2_i_avx2_sleef(q, 31), vcast_vi2_i_avx2_sleef(1))), vcast_vi2_i_avx2_sleef(~1));\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(0));\n\n  s = vsub_vf_vf_vf_avx2_sleef(u, vcast_vf_vi2_avx2_sleef(q));\n  t = s;\n  s = vmul_vf_vf_vf_avx2_sleef(s, s);\n  s2 = dfmul_vf2_vf_vf_avx2_sleef(t, t);\n\n  u = vsel_vf_vo_f_f_avx2_sleef(o, -0.2430611801e-7f, +0.3093842054e-6f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vsel_vf_vo_f_f_avx2_sleef(o, +0.3590577080e-5f, -0.3657307388e-4f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, s, vsel_vf_vo_f_f_avx2_sleef(o, -0.3259917721e-3f, +0.2490393585e-2f));\n  x = dfadd2_vf2_vf_vf2_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(u, s),\n   vsel_vf2_vo_f_f_f_f_avx2_sleef(o, 0.015854343771934509277, 4.4940051354032242811e-10,\n         -0.080745510756969451904, -1.3373665339076936258e-09));\n  x = dfadd2_vf2_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(s2, x),\n    vsel_vf2_vo_f_f_f_f_avx2_sleef(o, -0.30842512845993041992, -9.0728339030733922277e-09,\n          0.78539818525314331055, -2.1857338617566484855e-08));\n\n  x = dfmul_vf2_vf2_vf2_avx2_sleef(x, vsel_vf2_vo_vf2_vf2_avx2_sleef(o, s2, vcast_vf2_vf_vf_avx2_sleef(t, vcast_vf_f_avx2_sleef(0))));\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1)), x);\n\n  o = veq_vo_vi2_vi2_avx2_sleef(vand_vi2_vi2_vi2_avx2_sleef(vadd_vi2_vi2_vi2_avx2_sleef(q, vcast_vi2_i_avx2_sleef(2)), vcast_vi2_i_avx2_sleef(4)), vcast_vi2_i_avx2_sleef(4));\n  x = vf2setx_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)))));\n  x = vf2sety_vf2_vf2_vf_avx2_sleef(x, vreinterpret_vf_vm_avx2_sleef(vxor_vm_vm_vm_avx2_sleef(vand_vm_vo32_vm_avx2_sleef(o, vreinterpret_vm_vf_avx2_sleef(vcast_vf_f_avx2_sleef(-0.0))), vreinterpret_vm_vf_avx2_sleef(vf2gety_vf_vf2_avx2_sleef(x)))));\n\n  return x;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_cospif8_u05avx2(vfloat_avx2_sleef d) {\n  vfloat2_avx2_sleef x = cospifk_avx2_sleef(d);\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vgt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(d), vcast_vf_f_avx2_sleef(8e+6f)), vcast_vf_f_avx2_sleef(1), r);\n  r = vreinterpret_vf_vm_avx2_sleef(vor_vm_vo32_vm_avx2_sleef(visinf_vo_vf_avx2_sleef(d), vreinterpret_vm_vf_avx2_sleef(r)));\n\n  return r;\n}\n\n  typedef struct {\n    vfloat2_avx2_sleef a, b;\n  } df2_avx2_sleef;\n\nstatic df2_avx2_sleef df2setab_df2_vf2_vf2_avx2_sleef(vfloat2_avx2_sleef a, vfloat2_avx2_sleef b) {\n  df2_avx2_sleef r = { a, b };\n  return r;\n}\nstatic vfloat2_avx2_sleef df2geta_vf2_df2_avx2_sleef(df2_avx2_sleef d) { return d.a; }\nstatic vfloat2_avx2_sleef df2getb_vf2_df2_avx2_sleef(df2_avx2_sleef d) { return d.b; }\n\nstatic SLEEF_CONST df2_avx2_sleef gammafk_avx2_sleef(vfloat_avx2_sleef a) {\n  vfloat2_avx2_sleef clc = vcast_vf2_f_f_avx2_sleef(0, 0), clln = vcast_vf2_f_f_avx2_sleef(1, 0), clld = vcast_vf2_f_f_avx2_sleef(1, 0);\n  vfloat2_avx2_sleef x, y, z;\n  vfloat_avx2_sleef t, u;\n\n  vopmask_avx2_sleef otiny = vlt_vo_vf_vf_avx2_sleef(vabs_vf_vf_avx2_sleef(a), vcast_vf_f_avx2_sleef(1e-30f)), oref = vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0.5));\n\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(otiny, vcast_vf2_f_f_avx2_sleef(0, 0),\n     vsel_vf2_vo_vf2_vf2_avx2_sleef(oref, dfadd2_vf2_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(1), vneg_vf_vf_avx2_sleef(a)),\n           vcast_vf2_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0))));\n\n  vopmask_avx2_sleef o0 = vand_vo_vo_vo_avx2_sleef(vle_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(0.5), vf2getx_vf_vf2_avx2_sleef(x)), vle_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vcast_vf_f_avx2_sleef(1.2)));\n  vopmask_avx2_sleef o2 = vle_vo_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2.3), vf2getx_vf_vf2_avx2_sleef(x));\n\n  y = dfnormalize_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1)), x));\n  y = dfnormalize_vf2_vf2_avx2_sleef(dfmul_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2)), y));\n\n  vopmask_avx2_sleef o = vand_vo_vo_vo_avx2_sleef(o2, vle_vo_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vcast_vf_f_avx2_sleef(7)));\n  clln = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, y, clln);\n\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o, dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(3)), x);\n  t = vsel_vf_vo_vf_vf_avx2_sleef(o2, vrec_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x)), vf2getx_vf_vf2_avx2_sleef(dfnormalize_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(x, vsel_vf_vo_f_f_avx2_sleef(o0, -1, -2)))));\n\n  u = vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, +0.000839498720672087279971000786, +0.9435157776e+0f, +0.1102489550e-3f);\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, -5.17179090826059219329394422e-05, +0.8670063615e+0f, +0.8160019934e-4f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, -0.000592166437353693882857342347, +0.4826702476e+0f, +0.1528468856e-3f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, +6.97281375836585777403743539e-05, -0.8855129778e-1f, -0.2355068718e-3f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, +0.000784039221720066627493314301, +0.1013825238e+0f, +0.4962242092e-3f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, -0.000229472093621399176949318732, -0.1493408978e+0f, -0.1193488017e-2f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, -0.002681327160493827160473958490, +0.1697509140e+0f, +0.2891599433e-2f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, +0.003472222222222222222175164840, -0.2072454542e+0f, -0.7385451812e-2f));\n  u = vmla_vf_vf_vf_vf_avx2_sleef(u, t, vsel_vf_vo_vo_f_f_f_avx2_sleef(o2, o0, +0.083333333333333333335592087900, +0.2705872357e+0f, +0.2058077045e-1f));\n\n  y = dfmul_vf2_vf2_vf2_avx2_sleef(dfadd2_vf2_vf2_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(-0.5)), logk2f_avx2_sleef(x));\n  y = dfadd2_vf2_vf2_vf2_avx2_sleef(y, dfneg_vf2_vf2_avx2_sleef(x));\n  y = dfadd2_vf2_vf2_vf2_avx2_sleef(y, vcast_vf2_d_avx2_sleef(0.91893853320467278056));\n\n  z = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf_vf_avx2_sleef (u, t), vsel_vf_vo_f_f_avx2_sleef(o0, -0.400686534596170958447352690395e+0f, -0.673523028297382446749257758235e-1f));\n  z = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(z, t), vsel_vf_vo_f_f_avx2_sleef(o0, +0.822466960142643054450325495997e+0f, +0.322467033928981157743538726901e+0f));\n  z = dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf2_vf_avx2_sleef(z, t), vsel_vf_vo_f_f_avx2_sleef(o0, -0.577215665946766039837398973297e+0f, +0.422784335087484338986941629852e+0f));\n  z = dfmul_vf2_vf2_vf_avx2_sleef(z, t);\n\n  clc = vsel_vf2_vo_vf2_vf2_avx2_sleef(o2, y, z);\n\n  clld = vsel_vf2_vo_vf2_vf2_avx2_sleef(o2, dfadd2_vf2_vf2_vf_avx2_sleef(dfmul_vf2_vf_vf_avx2_sleef(u, t), vcast_vf_f_avx2_sleef(1)), clld);\n\n  y = clln;\n\n  clc = vsel_vf2_vo_vf2_vf2_avx2_sleef(otiny, vcast_vf2_d_avx2_sleef(41.58883083359671856503),\n       vsel_vf2_vo_vf2_vf2_avx2_sleef(oref, dfadd2_vf2_vf2_vf2_avx2_sleef(vcast_vf2_d_avx2_sleef(1.1447298858494001639), dfneg_vf2_vf2_avx2_sleef(clc)), clc));\n  clln = vsel_vf2_vo_vf2_vf2_avx2_sleef(otiny, vcast_vf2_f_f_avx2_sleef(1, 0), vsel_vf2_vo_vf2_vf2_avx2_sleef(oref, clln, clld));\n\n  if (!vtestallones_i_vo32_avx2_sleef(vnot_vo32_vo32_avx2_sleef(oref))) {\n    t = vsub_vf_vf_vf_avx2_sleef(a, vmul_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(INT64_C(1) << 12), vcast_vf_vi2_avx2_sleef(vtruncate_vi2_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(1.0 / (INT64_C(1) << 12)))))));\n    x = dfmul_vf2_vf2_vf2_avx2_sleef(clld, sinpifk_avx2_sleef(t));\n  }\n\n  clld = vsel_vf2_vo_vf2_vf2_avx2_sleef(otiny, vcast_vf2_vf_vf_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef((INT64_C(1) << 30)*(float)(INT64_C(1) << 30))), vcast_vf_f_avx2_sleef(0)),\n        vsel_vf2_vo_vf2_vf2_avx2_sleef(oref, x, y));\n\n  return df2setab_df2_vf2_vf2_avx2_sleef(clc, dfdiv_vf2_vf2_vf2_avx2_sleef(clln, clld));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_tgammaf8_u10avx2(vfloat_avx2_sleef a) {\n  df2_avx2_sleef d = gammafk_avx2_sleef(a);\n  vfloat2_avx2_sleef y = dfmul_vf2_vf2_vf2_avx2_sleef(expk2f_avx2_sleef(df2geta_vf2_df2_avx2_sleef(d)), df2getb_vf2_df2_avx2_sleef(d));\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(y));\n  vopmask_avx2_sleef o;\n\n  o = vor_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(-__builtin_inff())),\n    vand_vo_vo_vo_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), visint_vo_vf_avx2_sleef(a))),\n     vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(visnumber_vo_vf_avx2_sleef(a), vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0))), visnan_vo_vf_avx2_sleef(r)));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(o, vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), r);\n\n  o = vand_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(__builtin_inff())), visnumber_vo_vf_avx2_sleef(a)),\n      vge_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(-1.17549435082228751e-38))),\n      vor_vo_vo_vo_avx2_sleef(vor_vo_vo_vo_avx2_sleef(veq_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), vgt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(36))), visnan_vo_vf_avx2_sleef(r)));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(o, vmulsign_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(__builtin_inff()), a), r);\n\n  return r;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_lgammaf8_u10avx2(vfloat_avx2_sleef a) {\n  df2_avx2_sleef d = gammafk_avx2_sleef(a);\n  vfloat2_avx2_sleef y = dfadd2_vf2_vf2_vf2_avx2_sleef(df2geta_vf2_df2_avx2_sleef(d), logk2f_avx2_sleef(dfabs_vf2_vf2_avx2_sleef(df2getb_vf2_df2_avx2_sleef(d))));\n  vfloat_avx2_sleef r = vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(y), vf2gety_vf_vf2_avx2_sleef(y));\n  vopmask_avx2_sleef o;\n\n  o = vor_vo_vo_vo_avx2_sleef(visinf_vo_vf_avx2_sleef(a),\n     vor_vo_vo_vo_avx2_sleef(vand_vo_vo_vo_avx2_sleef(vle_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), visint_vo_vf_avx2_sleef(a)),\n    vand_vo_vo_vo_avx2_sleef(visnumber_vo_vf_avx2_sleef(a), visnan_vo_vf_avx2_sleef(r))));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(o, vcast_vf_f_avx2_sleef(__builtin_inff()), r);\n\n  return r;\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef dfmla_vf2_vf_vf2_vf2_avx2_sleef(vfloat_avx2_sleef x, vfloat2_avx2_sleef y, vfloat2_avx2_sleef z) {\n  return dfadd_vf2_vf2_vf2_avx2_sleef(z, dfmul_vf2_vf2_vf_avx2_sleef(y, x));\n}\n\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef poly2df_b_avx2_sleef(vfloat_avx2_sleef x, vfloat2_avx2_sleef c1, vfloat2_avx2_sleef c0) { return dfmla_vf2_vf_vf2_vf2_avx2_sleef(x, c1, c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef poly2df_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef c1, vfloat2_avx2_sleef c0) { return dfmla_vf2_vf_vf2_vf2_avx2_sleef(x, vcast_vf2_vf_vf_avx2_sleef(c1, vcast_vf_f_avx2_sleef(0)), c0); }\nstatic SLEEF_ALWAYS_INLINE SLEEF_CONST vfloat2_avx2_sleef poly4df_avx2_sleef(vfloat_avx2_sleef x, vfloat_avx2_sleef c3, vfloat2_avx2_sleef c2, vfloat2_avx2_sleef c1, vfloat2_avx2_sleef c0) {\n  return dfmla_vf2_vf_vf2_vf2_avx2_sleef(vmul_vf_vf_vf_avx2_sleef(x, x), poly2df_avx2_sleef(x, c3, c2), poly2df_b_avx2_sleef(x, c1, c0));\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_erff8_u10avx2(vfloat_avx2_sleef a) {\n  vfloat_avx2_sleef t, x = vabs_vf_vf_avx2_sleef(a);\n  vfloat2_avx2_sleef t2;\n  vfloat_avx2_sleef x2 = vmul_vf_vf_vf_avx2_sleef(x, x), x4 = vmul_vf_vf_vf_avx2_sleef(x2, x2);\n  vopmask_avx2_sleef o25 = vle_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(2.5));\n\n  if (__builtin_expect(!!(vtestallones_i_vo32_avx2_sleef(o25)), 1)) {\n\n    t = vmla_vf_vf_vf_vf_avx2_sleef((x4), (vmla_vf_vf_vf_vf_avx2_sleef((x), (vcast_vf_f_avx2_sleef(-0.4360447008e-6)), (vcast_vf_f_avx2_sleef(+0.6867515367e-5)))), (vmla_vf_vf_vf_vf_avx2_sleef((x2), (vmla_vf_vf_vf_vf_avx2_sleef((x), (vcast_vf_f_avx2_sleef(-0.3045156700e-4)), (vcast_vf_f_avx2_sleef(+0.9808536561e-4)))), (vmla_vf_vf_vf_vf_avx2_sleef((x), (vcast_vf_f_avx2_sleef(+0.2395523916e-3)), (vcast_vf_f_avx2_sleef(+0.1459901541e-3)))))))\n\n                        ;\n    t2 = poly4df_avx2_sleef(x, t,\n   vcast_vf2_f_f_avx2_sleef(0.0092883445322513580322, -2.7863745897025330755e-11),\n   vcast_vf2_f_f_avx2_sleef(0.042275499552488327026, 1.3461399289988106057e-09),\n   vcast_vf2_f_f_avx2_sleef(0.070523701608180999756, -3.6616309318707365163e-09));\n    t2 = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), dfmul_vf2_vf2_vf_avx2_sleef(t2, x));\n    t2 = dfsqu_vf2_vf2_avx2_sleef(t2);\n    t2 = dfsqu_vf2_vf2_avx2_sleef(t2);\n    t2 = dfsqu_vf2_vf2_avx2_sleef(t2);\n    t2 = dfsqu_vf2_vf2_avx2_sleef(t2);\n    t2 = dfrec_vf2_vf2_avx2_sleef(t2);\n  } else {\n\n    t = vmla_vf_vf_vf_vf_avx2_sleef((x4), (vmla_vf_vf_vf_vf_avx2_sleef((x), ((vsel_vf_vo_f_f_avx2_sleef(o25, -0.4360447008e-6, -0.1130012848e-6))), ((vsel_vf_vo_f_f_avx2_sleef(o25, +0.6867515367e-5, +0.4115272986e-5))))), (vmla_vf_vf_vf_vf_avx2_sleef((x2), (vmla_vf_vf_vf_vf_avx2_sleef((x), ((vsel_vf_vo_f_f_avx2_sleef(o25, -0.3045156700e-4, -0.6928304356e-4))), ((vsel_vf_vo_f_f_avx2_sleef(o25, +0.9808536561e-4, +0.7172692567e-3))))), (vmla_vf_vf_vf_vf_avx2_sleef((x), ((vsel_vf_vo_f_f_avx2_sleef(o25, +0.2395523916e-3, -0.5131045356e-2))), ((vsel_vf_vo_f_f_avx2_sleef(o25, +0.1459901541e-3, +0.2708637156e-1))))))))\n\n                                                                ;\n    t2 = poly4df_avx2_sleef(x, t,\n   vsel_vf2_vo_vf2_vf2_avx2_sleef(o25, vcast_vf2_f_f_avx2_sleef(0.0092883445322513580322, -2.7863745897025330755e-11),\n         vcast_vf2_f_f_avx2_sleef(-0.11064319312572479248, 3.7050452777225283007e-09)),\n   vsel_vf2_vo_vf2_vf2_avx2_sleef(o25, vcast_vf2_f_f_avx2_sleef(0.042275499552488327026, 1.3461399289988106057e-09),\n         vcast_vf2_f_f_avx2_sleef(-0.63192230463027954102, -2.0200432585073177859e-08)),\n   vsel_vf2_vo_vf2_vf2_avx2_sleef(o25, vcast_vf2_f_f_avx2_sleef(0.070523701608180999756, -3.6616309318707365163e-09),\n         vcast_vf2_f_f_avx2_sleef(-1.1296638250350952148, 2.5515120196453259252e-08)));\n    t2 = dfmul_vf2_vf2_vf_avx2_sleef(t2, x);\n    vfloat2_avx2_sleef s2 = dfadd_vf2_vf_vf2_avx2_sleef(vcast_vf_f_avx2_sleef(1), t2);\n    s2 = dfsqu_vf2_vf2_avx2_sleef(s2);\n    s2 = dfsqu_vf2_vf2_avx2_sleef(s2);\n    s2 = dfsqu_vf2_vf2_avx2_sleef(s2);\n    s2 = dfsqu_vf2_vf2_avx2_sleef(s2);\n    s2 = dfrec_vf2_vf2_avx2_sleef(s2);\n    t2 = vsel_vf2_vo_vf2_vf2_avx2_sleef(o25, s2, vcast_vf2_vf_vf_avx2_sleef(expkf_avx2_sleef(t2), vcast_vf_f_avx2_sleef(0)));\n  }\n\n  t2 = dfadd2_vf2_vf2_vf_avx2_sleef(t2, vcast_vf_f_avx2_sleef(-1));\n  t2 = vsel_vf2_vo_vf2_vf2_avx2_sleef(vlt_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(1e-4)), dfmul_vf2_vf2_vf_avx2_sleef(vcast_vf2_f_f_avx2_sleef(-1.1283792257308959961, 5.8635383422197591097e-08), x), t2);\n\n  vfloat_avx2_sleef z = vneg_vf_vf_avx2_sleef(vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(t2), vf2gety_vf_vf2_avx2_sleef(t2)));\n  z = vsel_vf_vo_vf_vf_avx2_sleef(vge_vo_vf_vf_avx2_sleef(x, vcast_vf_f_avx2_sleef(6)), vcast_vf_f_avx2_sleef(1), z);\n  z = vsel_vf_vo_vf_vf_avx2_sleef(visinf_vo_vf_avx2_sleef(a), vcast_vf_f_avx2_sleef(1), z);\n  z = vsel_vf_vo_vf_vf_avx2_sleef(veq_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), vcast_vf_f_avx2_sleef(0), z);\n  z = vmulsign_vf_vf_vf_avx2_sleef(z, a);\n\n  return z;\n}\n\nSLEEF_INLINE SLEEF_CONST vfloat_avx2_sleef Sleef_erfcf8_u15avx2(vfloat_avx2_sleef a) {\n  vfloat_avx2_sleef s = a, r = vcast_vf_f_avx2_sleef(0), t;\n  vfloat2_avx2_sleef u, d, x;\n  a = vabs_vf_vf_avx2_sleef(a);\n  vopmask_avx2_sleef o0 = vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(1.0));\n  vopmask_avx2_sleef o1 = vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(2.2));\n  vopmask_avx2_sleef o2 = vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(4.3));\n  vopmask_avx2_sleef o3 = vlt_vo_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(10.1));\n\n  u = vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, vcast_vf2_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0)), dfdiv_vf2_vf2_vf2_avx2_sleef(vcast_vf2_f_f_avx2_sleef(1, 0), vcast_vf2_vf_vf_avx2_sleef(a, vcast_vf_f_avx2_sleef(0))));\n\n  t = vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(o0, o1, o2, -0.8638041618e-4f, -0.6236977242e-5f, -0.3869504035e+0f, +0.1115344167e+1f);\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(o0, o1, o2, +0.6000166177e-3f, +0.5749821503e-4f, +0.1288077235e+1f, -0.9454904199e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(o0, o1, o2, -0.1665703603e-2f, +0.6002851478e-5f, -0.1816803217e+1f, -0.3667259514e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(o0, o1, o2, +0.1795156277e-3f, -0.2851036377e-2f, +0.1249150872e+1f, +0.7155663371e+0f));\n  t = vmla_vf_vf_vf_vf_avx2_sleef(t, vf2getx_vf_vf2_avx2_sleef(u), vsel_vf_vo_vo_vo_f_f_f_f_avx2_sleef(o0, o1, o2, +0.1914106123e-1f, +0.2260518074e-1f, -0.1328857988e+0f, -0.1262947265e-1f));\n\n  d = dfmul_vf2_vf2_vf_avx2_sleef(u, t);\n  d = dfadd2_vf2_vf2_vf2_avx2_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.102775359343930288081655368891e+0, -0.105247583459338632253369014063e+0, -0.482365310333045318680618892669e+0, -0.498961546254537647970305302739e+0));\n  d = dfmul_vf2_vf2_vf2_avx2_sleef(d, u);\n  d = dfadd2_vf2_vf2_vf2_avx2_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.636619483208481931303752546439e+0, -0.635609463574589034216723775292e+0, -0.134450203224533979217859332703e-2, -0.471199543422848492080722832666e-4));\n  d = dfmul_vf2_vf2_vf2_avx2_sleef(d, u);\n  d = dfadd2_vf2_vf2_vf2_avx2_sleef(d, vsel_vf2_vo_vo_vo_d_d_d_d_avx2_sleef(o0, o1, o2, -0.112837917790537404939545770596e+1, -0.112855987376668622084547028949e+1, -0.572319781150472949561786101080e+0, -0.572364030327966044425932623525e+0));\n\n  x = dfmul_vf2_vf2_vf_avx2_sleef(vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, d, vcast_vf2_vf_vf_avx2_sleef(vneg_vf_vf_avx2_sleef(a), vcast_vf_f_avx2_sleef(0))), a);\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, x, dfadd2_vf2_vf2_vf2_avx2_sleef(x, d));\n\n  x = expk2f_avx2_sleef(x);\n  x = vsel_vf2_vo_vf2_vf2_avx2_sleef(o1, x, dfmul_vf2_vf2_vf2_avx2_sleef(x, u));\n\n  r = vsel_vf_vo_vf_vf_avx2_sleef(o3, vadd_vf_vf_vf_avx2_sleef(vf2getx_vf_vf2_avx2_sleef(x), vf2gety_vf_vf2_avx2_sleef(x)), vcast_vf_f_avx2_sleef(0));\n  r = vsel_vf_vo_vf_vf_avx2_sleef(vsignbit_vo_vf_avx2_sleef(s), vsub_vf_vf_vf_avx2_sleef(vcast_vf_f_avx2_sleef(2), r), r);\n  r = vsel_vf_vo_vf_vf_avx2_sleef(visnan_vo_vf_avx2_sleef(s), vcast_vf_f_avx2_sleef(__builtin_nanf(\"\")), r);\n  return r;\n}\n"
  },
  {
    "path": "eidos_multi.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "eidos_zlib/ChangeLog",
    "content": "\n                ChangeLog file for zlib\n\nChanges in 1.3.1.f-slim (18 Jul 2024)\n- Revised for inclusion in SLiM, by removing unused code\n- Configured with ./configure --zprefix on macOS 10.15.3 (carried over from previous SLiM config run)\n\nChanges in 1.3.1 (22 Jan 2024)\n- Reject overflows of zip header fields in minizip\n- Fix bug in inflateSync() for data held in bit buffer\n- Add LIT_MEM define to use more memory for a small deflate speedup\n- Fix decision on the emission of Zip64 end records in minizip\n- Add bounds checking to ERR_MSG() macro, used by zError()\n- Neutralize zip file traversal attacks in miniunz\n- Fix a bug in ZLIB_DEBUG compiles in check_match()\n- Various portability and appearance improvements\n\nChanges in 1.3 (18 Aug 2023)\n- Remove K&R function definitions and zlib2ansi\n- Fix bug in deflateBound() for level 0 and memLevel 9\n- Fix bug when gzungetc() is used immediately after gzopen()\n- Fix bug when using gzflush() with a very small buffer\n- Fix crash when gzsetparams() attempted for transparent write\n- Fix test/example.c to work with FORCE_STORED\n- Rewrite of zran in examples (see zran.c version history)\n- Fix minizip to allow it to open an empty zip file\n- Fix reading disk number start on zip64 files in minizip\n- Fix logic error in minizip argument processing\n- Add minizip testing to Makefile\n- Read multiple bytes instead of byte-by-byte in minizip unzip.c\n- Add memory sanitizer to configure (--memory)\n- Various portability improvements\n- Various documentation improvements\n- Various spelling and typo corrections\n\nChanges in 1.2.13 (13 Oct 2022)\n- Fix configure issue that discarded provided CC definition\n- Correct incorrect inputs provided to the CRC functions\n- Repair prototypes and exporting of new CRC functions\n- Fix inflateBack to detect invalid input with distances too far\n- Have infback() deliver all of the available output up to any error\n- Fix a bug when getting a gzip header extra field with inflate()\n- Fix bug in block type selection when Z_FIXED used\n- Tighten deflateBound bounds\n- Remove deleted assembler code references\n- Various portability and appearance improvements\n\nChanges in 1.2.12 (27 Mar 2022)\n- Cygwin does not have _wopen(), so do not create gzopen_w() there\n- Permit a deflateParams() parameter change as soon as possible\n- Limit hash table inserts after switch from stored deflate\n- Fix bug when window full in deflate_stored()\n- Fix CLEAR_HASH macro to be usable as a single statement\n- Avoid a conversion error in gzseek when off_t type too small\n- Have Makefile return non-zero error code on test failure\n- Avoid some conversion warnings in gzread.c and gzwrite.c\n- Update use of errno for newer Windows CE versions\n- Small speedup to inflate [psumbera]\n- Return an error if the gzputs string length can't fit in an int\n- Add address checking in clang to -w option of configure\n- Don't compute check value for raw inflate if asked to validate\n- Handle case where inflateSync used when header never processed\n- Avoid the use of ptrdiff_t\n- Avoid an undefined behavior of memcpy() in gzappend()\n- Avoid undefined behaviors of memcpy() in gz*printf()\n- Avoid an undefined behavior of memcpy() in _tr_stored_block()\n- Make the names in functions declarations identical to definitions\n- Remove old assembler code in which bugs have manifested\n- Fix deflateEnd() to not report an error at start of raw deflate\n- Add legal disclaimer to README\n- Emphasize the need to continue decompressing gzip members\n- Correct the initialization requirements for deflateInit2()\n- Fix a bug that can crash deflate on some input when using Z_FIXED\n- Assure that the number of bits for deflatePrime() is valid\n- Use a structure to make globals in enough.c evident\n- Use a macro for the printf format of big_t in enough.c\n- Clean up code style in enough.c, update version\n- Use inline function instead of macro for index in enough.c\n- Clarify that prefix codes are counted in enough.c\n- Show all the codes for the maximum tables size in enough.c\n- Add gznorm.c example, which normalizes gzip files\n- Fix the zran.c example to work on a multiple-member gzip file\n- Add tables for crc32_combine(), to speed it up by a factor of 200\n- Add crc32_combine_gen() and crc32_combine_op() for fast combines\n- Speed up software CRC-32 computation by a factor of 1.5 to 3\n- Use atomic test and set, if available, for dynamic CRC tables\n- Don't bother computing check value after successful inflateSync()\n- Correct comment in crc32.c\n- Add use of the ARMv8 crc32 instructions when requested\n- Use ARM crc32 instructions if the ARM architecture has them\n- Explicitly note that the 32-bit check values are 32 bits\n- Avoid adding empty gzip member after gzflush with Z_FINISH\n- Fix memory leak on error in gzlog.c\n- Fix error in comment on the polynomial representation of a byte\n- Clarify gz* function interfaces, referring to parameter names\n- Change macro name in inflate.c to avoid collision in VxWorks\n- Correct typo in blast.c\n- Improve portability of contrib/minizip\n- Fix indentation in minizip's zip.c\n- Replace black/white with allow/block. (theresa-m)\n- minizip warning fix if MAXU32 already defined. (gvollant)\n- Fix unztell64() in minizip to work past 4GB. (Daniël Hörchner)\n- Clean up minizip to reduce warnings for testing\n- Add fallthrough comments for gcc\n- Eliminate use of ULL constants\n- Separate out address sanitizing from warnings in configure\n- Remove destructive aspects of make distclean\n- Check for cc masquerading as gcc or clang in configure\n- Fix crc32.c to compile local functions only if used\n\nChanges in 1.2.11 (15 Jan 2017)\n- Fix deflate stored bug when pulling last block from window\n- Permit immediate deflateParams changes before any deflate input\n\nChanges in 1.2.10 (2 Jan 2017)\n- Avoid warnings on snprintf() return value\n- Fix bug in deflate_stored() for zero-length input\n- Fix bug in gzwrite.c that produced corrupt gzip files\n- Remove files to be installed before copying them in Makefile.in\n- Add warnings when compiling with assembler code\n\nChanges in 1.2.9 (31 Dec 2016)\n- Fix contrib/minizip to permit unzipping with desktop API [Zouzou]\n- Improve contrib/blast to return unused bytes\n- Assure that gzoffset() is correct when appending\n- Improve compress() and uncompress() to support large lengths\n- Fix bug in test/example.c where error code not saved\n- Remedy Coverity warning [Randers-Pehrson]\n- Improve speed of gzprintf() in transparent mode\n- Fix inflateInit2() bug when windowBits is 16 or 32\n- Change DEBUG macro to ZLIB_DEBUG\n- Avoid uninitialized access by gzclose_w()\n- Allow building zlib outside of the source directory\n- Fix bug that accepted invalid zlib header when windowBits is zero\n- Fix gzseek() problem on MinGW due to buggy _lseeki64 there\n- Loop on write() calls in gzwrite.c in case of non-blocking I/O\n- Add --warn (-w) option to ./configure for more compiler warnings\n- Reject a window size of 256 bytes if not using the zlib wrapper\n- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE\n- Add --debug (-d) option to ./configure to define ZLIB_DEBUG\n- Fix bugs in creating a very large gzip header\n- Add uncompress2() function, which returns the input size used\n- Assure that deflateParams() will not switch functions mid-block\n- Dramatically speed up deflation for level 0 (storing)\n- Add gzfread(), duplicating the interface of fread()\n- Add gzfwrite(), duplicating the interface of fwrite()\n- Add deflateGetDictionary() function\n- Use snprintf() for later versions of Microsoft C\n- Fix *Init macros to use z_ prefix when requested\n- Replace as400 with os400 for OS/400 support [Monnerat]\n- Add crc32_z() and adler32_z() functions with size_t lengths\n- Update Visual Studio project files [AraHaan]\n\nChanges in 1.2.8 (28 Apr 2013)\n- Update contrib/minizip/iowin32.c for Windows RT [Vollant]\n- Do not force Z_CONST for C++\n- Clean up contrib/vstudio [Roß]\n- Correct spelling error in zlib.h\n- Fix mixed line endings in contrib/vstudio\n\nChanges in 1.2.7.3 (13 Apr 2013)\n- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc\n\nChanges in 1.2.7.2 (13 Apr 2013)\n- Change check for a four-byte type back to hexadecimal\n- Fix typo in win32/Makefile.msc\n- Add casts in gzwrite.c for pointer differences\n\nChanges in 1.2.7.1 (24 Mar 2013)\n- Replace use of unsafe string functions with snprintf if available\n- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink]\n- Fix gzgetc undefine when Z_PREFIX set [Turk]\n- Eliminate use of mktemp in Makefile (not always available)\n- Fix bug in 'F' mode for gzopen()\n- Add inflateGetDictionary() function\n- Correct comment in deflate.h\n- Use _snprintf for snprintf in Microsoft C\n- On Darwin, only use /usr/bin/libtool if libtool is not Apple\n- Delete \"--version\" file if created by \"ar --version\" [Richard G.]\n- Fix configure check for veracity of compiler error return codes\n- Fix CMake compilation of static lib for MSVC2010 x64\n- Remove unused variable in infback9.c\n- Fix argument checks in gzlog_compress() and gzlog_write()\n- Clean up the usage of z_const and respect const usage within zlib\n- Clean up examples/gzlog.[ch] comparisons of different types\n- Avoid shift equal to bits in type (caused endless loop)\n- Fix uninitialized value bug in gzputc() introduced by const patches\n- Fix memory allocation error in examples/zran.c [Nor]\n- Fix bug where gzopen(), gzclose() would write an empty file\n- Fix bug in gzclose() when gzwrite() runs out of memory\n- Check for input buffer malloc failure in examples/gzappend.c\n- Add note to contrib/blast to use binary mode in stdio\n- Fix comparisons of differently signed integers in contrib/blast\n- Check for invalid code length codes in contrib/puff\n- Fix serious but very rare decompression bug in inftrees.c\n- Update inflateBack() comments, since inflate() can be faster\n- Use underscored I/O function names for WINAPI_FAMILY\n- Add _tr_flush_bits to the external symbols prefixed by --zprefix\n- Add contrib/vstudio/vc10 pre-build step for static only\n- Quote --version-script argument in CMakeLists.txt\n- Don't specify --version-script on Apple platforms in CMakeLists.txt\n- Fix casting error in contrib/testzlib/testzlib.c\n- Fix types in contrib/minizip to match result of get_crc_table()\n- Simplify contrib/vstudio/vc10 with 'd' suffix\n- Add TOP support to win32/Makefile.msc\n- Support i686 and amd64 assembler builds in CMakeLists.txt\n- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h\n- Add vc11 and vc12 build files to contrib/vstudio\n- Add gzvprintf() as an undocumented function in zlib\n- Fix configure for Sun shell\n- Remove runtime check in configure for four-byte integer type\n- Add casts and consts to ease user conversion to C++\n- Add man pages for minizip and miniunzip\n- In Makefile uninstall, don't rm if preceding cd fails\n- Do not return Z_BUF_ERROR if deflateParam() has nothing to write\n\nChanges in 1.2.7 (2 May 2012)\n- Replace use of memmove() with a simple copy for portability\n- Test for existence of strerror\n- Restore gzgetc_ for backward compatibility with 1.2.6\n- Fix build with non-GNU make on Solaris\n- Require gcc 4.0 or later on Mac OS X to use the hidden attribute\n- Include unistd.h for Watcom C\n- Use __WATCOMC__ instead of __WATCOM__\n- Do not use the visibility attribute if NO_VIZ defined\n- Improve the detection of no hidden visibility attribute\n- Avoid using __int64 for gcc or solo compilation\n- Cast to char * in gzprintf to avoid warnings [Zinser]\n- Fix make_vms.com for VAX [Zinser]\n- Don't use library or built-in byte swaps\n- Simplify test and use of gcc hidden attribute\n- Fix bug in gzclose_w() when gzwrite() fails to allocate memory\n- Add \"x\" (O_EXCL) and \"e\" (O_CLOEXEC) modes support to gzopen()\n- Fix bug in test/minigzip.c for configure --solo\n- Fix contrib/vstudio project link errors [Mohanathas]\n- Add ability to choose the builder in make_vms.com [Schweda]\n- Add DESTDIR support to mingw32 win32/Makefile.gcc\n- Fix comments in win32/Makefile.gcc for proper usage\n- Allow overriding the default install locations for cmake\n- Generate and install the pkg-config file with cmake\n- Build both a static and a shared version of zlib with cmake\n- Include version symbols for cmake builds\n- If using cmake with MSVC, add the source directory to the includes\n- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta]\n- Move obsolete emx makefile to old [Truta]\n- Allow the use of -Wundef when compiling or using zlib\n- Avoid the use of the -u option with mktemp\n- Improve inflate() documentation on the use of Z_FINISH\n- Recognize clang as gcc\n- Add gzopen_w() in Windows for wide character path names\n- Rename zconf.h in CMakeLists.txt to move it out of the way\n- Add source directory in CMakeLists.txt for building examples\n- Look in build directory for zlib.pc in CMakeLists.txt\n- Remove gzflags from zlibvc.def in vc9 and vc10\n- Fix contrib/minizip compilation in the MinGW environment\n- Update ./configure for Solaris, support --64 [Mooney]\n- Remove -R. from Solaris shared build (possible security issue)\n- Avoid race condition for parallel make (-j) running example\n- Fix type mismatch between get_crc_table() and crc_table\n- Fix parsing of version with \"-\" in CMakeLists.txt [Snider, Ziegler]\n- Fix the path to zlib.map in CMakeLists.txt\n- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe]\n- Add instructions to win32/Makefile.gcc for shared install [Torri]\n\nChanges in 1.2.6.1 (12 Feb 2012)\n- Avoid the use of the Objective-C reserved name \"id\"\n- Include io.h in gzguts.h for Microsoft compilers\n- Fix problem with ./configure --prefix and gzgetc macro\n- Include gz_header definition when compiling zlib solo\n- Put gzflags() functionality back in zutil.c\n- Avoid library header include in crc32.c for Z_SOLO\n- Use name in GCC_CLASSIC as C compiler for coverage testing, if set\n- Minor cleanup in contrib/minizip/zip.c [Vollant]\n- Update make_vms.com [Zinser]\n- Remove unnecessary gzgetc_ function\n- Use optimized byte swap operations for Microsoft and GNU [Snyder]\n- Fix minor typo in zlib.h comments [Rzesniowiecki]\n\nChanges in 1.2.6 (29 Jan 2012)\n- Update the Pascal interface in contrib/pascal\n- Fix function numbers for gzgetc_ in zlibvc.def files\n- Fix configure.ac for contrib/minizip [Schiffer]\n- Fix large-entry detection in minizip on 64-bit systems [Schiffer]\n- Have ./configure use the compiler return code for error indication\n- Fix CMakeLists.txt for cross compilation [McClure]\n- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes]\n- Fix compilation of contrib/minizip on FreeBSD [Marquez]\n- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath]\n- Include io.h for Turbo C / Borland C on all platforms [Truta]\n- Make version explicit in contrib/minizip/configure.ac [Bosmans]\n- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant]\n- Minor cleanup up contrib/minizip/unzip.c [Vollant]\n- Fix bug when compiling minizip with C++ [Vollant]\n- Protect for long name and extra fields in contrib/minizip [Vollant]\n- Avoid some warnings in contrib/minizip [Vollant]\n- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip\n- Add missing libs to minizip linker command\n- Add support for VPATH builds in contrib/minizip\n- Add an --enable-demos option to contrib/minizip/configure\n- Add the generation of configure.log by ./configure\n- Exit when required parameters not provided to win32/Makefile.gcc\n- Have gzputc return the character written instead of the argument\n- Use the -m option on ldconfig for BSD systems [Tobias]\n- Correct in zlib.map when deflateResetKeep was added\n\nChanges in 1.2.5.3 (15 Jan 2012)\n- Restore gzgetc function for binary compatibility\n- Do not use _lseeki64 under Borland C++ [Truta]\n- Update win32/Makefile.msc to build test/*.c [Truta]\n- Remove old/visualc6 given CMakefile and other alternatives\n- Update AS400 build files and documentation [Monnerat]\n- Update win32/Makefile.gcc to build test/*.c [Truta]\n- Permit stronger flushes after Z_BLOCK flushes\n- Avoid extraneous empty blocks when doing empty flushes\n- Permit Z_NULL arguments to deflatePending\n- Allow deflatePrime() to insert bits in the middle of a stream\n- Remove second empty static block for Z_PARTIAL_FLUSH\n- Write out all of the available bits when using Z_BLOCK\n- Insert the first two strings in the hash table after a flush\n\nChanges in 1.2.5.2 (17 Dec 2011)\n- fix ld error: unable to find version dependency 'ZLIB_1.2.5'\n- use relative symlinks for shared libs\n- Avoid searching past window for Z_RLE strategy\n- Assure that high-water mark initialization is always applied in deflate\n- Add assertions to fill_window() in deflate.c to match comments\n- Update python link in README\n- Correct spelling error in gzread.c\n- Fix bug in gzgets() for a concatenated empty gzip stream\n- Correct error in comment for gz_make()\n- Change gzread() and related to ignore junk after gzip streams\n- Allow gzread() and related to continue after gzclearerr()\n- Allow gzrewind() and gzseek() after a premature end-of-file\n- Simplify gzseek() now that raw after gzip is ignored\n- Change gzgetc() to a macro for speed (~40% speedup in testing)\n- Fix gzclose() to return the actual error last encountered\n- Always add large file support for windows\n- Include zconf.h for windows large file support\n- Include zconf.h.cmakein for windows large file support\n- Update zconf.h.cmakein on make distclean\n- Merge vestigial vsnprintf determination from zutil.h to gzguts.h\n- Clarify how gzopen() appends in zlib.h comments\n- Correct documentation of gzdirect() since junk at end now ignored\n- Add a transparent write mode to gzopen() when 'T' is in the mode\n- Update python link in zlib man page\n- Get inffixed.h and MAKEFIXED result to match\n- Add a ./config --solo option to make zlib subset with no library use\n- Add undocumented inflateResetKeep() function for CAB file decoding\n- Add --cover option to ./configure for gcc coverage testing\n- Add #define ZLIB_CONST option to use const in the z_stream interface\n- Add comment to gzdopen() in zlib.h to use dup() when using fileno()\n- Note behavior of uncompress() to provide as much data as it can\n- Add files in contrib/minizip to aid in building libminizip\n- Split off AR options in Makefile.in and configure\n- Change ON macro to Z_ARG to avoid application conflicts\n- Facilitate compilation with Borland C++ for pragmas and vsnprintf\n- Include io.h for Turbo C / Borland C++\n- Move example.c and minigzip.c to test/\n- Simplify incomplete code table filling in inflate_table()\n- Remove code from inflate.c and infback.c that is impossible to execute\n- Test the inflate code with full coverage\n- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw)\n- Add deflateResetKeep and fix inflateResetKeep to retain dictionary\n- Fix gzwrite.c to accommodate reduced memory zlib compilation\n- Have inflate() with Z_FINISH avoid the allocation of a window\n- Do not set strm->adler when doing raw inflate\n- Fix gzeof() to behave just like feof() when read is not past end of file\n- Fix bug in gzread.c when end-of-file is reached\n- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF\n- Document gzread() capability to read concurrently written files\n- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo]\n\nChanges in 1.2.5.1 (10 Sep 2011)\n- Update FAQ entry on shared builds (#13)\n- Avoid symbolic argument to chmod in Makefile.in\n- Fix bug and add consts in contrib/puff [Oberhumer]\n- Update contrib/puff/zeros.raw test file to have all block types\n- Add full coverage test for puff in contrib/puff/Makefile\n- Fix static-only-build install in Makefile.in\n- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno]\n- Add libz.a dependency to shared in Makefile.in for parallel builds\n- Spell out \"number\" (instead of \"nb\") in zlib.h for total_in, total_out\n- Replace $(...) with `...` in configure for non-bash sh [Bowler]\n- Add darwin* to Darwin* and solaris* to SunOS\\ 5* in configure [Groffen]\n- Add solaris* to Linux* in configure to allow gcc use [Groffen]\n- Add *bsd* to Linux* case in configure [Bar-Lev]\n- Add inffast.obj to dependencies in win32/Makefile.msc\n- Correct spelling error in deflate.h [Kohler]\n- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc\n- Add test to configure for GNU C looking for gcc in output of $cc -v\n- Add zlib.pc generation to win32/Makefile.gcc [Weigelt]\n- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not\n- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense\n- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser)\n- Make stronger test in zconf.h to include unistd.h for LFS\n- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack]\n- Fix zlib.h LFS support when Z_PREFIX used\n- Add updated as400 support (removed from old) [Monnerat]\n- Avoid deflate sensitivity to volatile input data\n- Avoid division in adler32_combine for NO_DIVIDE\n- Clarify the use of Z_FINISH with deflateBound() amount of space\n- Set binary for output file in puff.c\n- Use u4 type for crc_table to avoid conversion warnings\n- Apply casts in zlib.h to avoid conversion warnings\n- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]\n- Improve inflateSync() documentation to note indeterminacy\n- Add deflatePending() function to return the amount of pending output\n- Correct the spelling of \"specification\" in FAQ [Randers-Pehrson]\n- Add a check in configure for stdarg.h, use for gzprintf()\n- Check that pointers fit in ints when gzprint() compiled old style\n- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]\n- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]\n- Add debug records in assembler code [Londer]\n- Update RFC references to use http://tools.ietf.org/html/... [Li]\n- Add --archs option, use of libtool to configure for Mac OS X [Borstel]\n\nChanges in 1.2.5 (19 Apr 2010)\n- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev]\n- Default to libdir as sharedlibdir in configure [Nieder]\n- Update copyright dates on modified source files\n- Update trees.c to be able to generate modified trees.h\n- Exit configure for MinGW, suggesting win32/Makefile.gcc\n- Check for NULL path in gz_open [Homurlu]\n\nChanges in 1.2.4.5 (18 Apr 2010)\n- Set sharedlibdir in configure [Torok]\n- Set LDFLAGS in Makefile.in [Bar-Lev]\n- Avoid mkdir objs race condition in Makefile.in [Bowler]\n- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays\n- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C\n- Don't use hidden attribute when it is a warning generator (e.g. Solaris)\n\nChanges in 1.2.4.4 (18 Apr 2010)\n- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok]\n- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty\n- Try to use bash or ksh regardless of functionality of /bin/sh\n- Fix configure incompatibility with NetBSD sh\n- Remove attempt to run under bash or ksh since have better NetBSD fix\n- Fix win32/Makefile.gcc for MinGW [Bar-Lev]\n- Add diagnostic messages when using CROSS_PREFIX in configure\n- Added --sharedlibdir option to configure [Weigelt]\n- Use hidden visibility attribute when available [Frysinger]\n\nChanges in 1.2.4.3 (10 Apr 2010)\n- Only use CROSS_PREFIX in configure for ar and ranlib if they exist\n- Use CROSS_PREFIX for nm [Bar-Lev]\n- Assume _LARGEFILE64_SOURCE defined is equivalent to true\n- Avoid use of undefined symbols in #if with && and ||\n- Make *64 prototypes in gzguts.h consistent with functions\n- Add -shared load option for MinGW in configure [Bowler]\n- Move z_off64_t to public interface, use instead of off64_t\n- Remove ! from shell test in configure (not portable to Solaris)\n- Change +0 macro tests to -0 for possibly increased portability\n\nChanges in 1.2.4.2 (9 Apr 2010)\n- Add consistent carriage returns to readme.txt's in masmx86 and masmx64\n- Really provide prototypes for *64 functions when building without LFS\n- Only define unlink() in minigzip.c if unistd.h not included\n- Update README to point to contrib/vstudio project files\n- Move projects/vc6 to old/ and remove projects/\n- Include stdlib.h in minigzip.c for setmode() definition under WinCE\n- Clean up assembler builds in win32/Makefile.msc [Rowe]\n- Include sys/types.h for Microsoft for off_t definition\n- Fix memory leak on error in gz_open()\n- Symbolize nm as $NM in configure [Weigelt]\n- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt]\n- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined\n- Fix bug in gzeof() to take into account unused input data\n- Avoid initialization of structures with variables in puff.c\n- Updated win32/README-WIN32.txt [Rowe]\n\nChanges in 1.2.4.1 (28 Mar 2010)\n- Remove the use of [a-z] constructs for sed in configure [gentoo 310225]\n- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech]\n- Restore \"for debugging\" comment on sprintf() in gzlib.c\n- Remove fdopen for MVS from gzguts.h\n- Put new README-WIN32.txt in win32 [Rowe]\n- Add check for shell to configure and invoke another shell if needed\n- Fix big fat stinking bug in gzseek() on uncompressed files\n- Remove vestigial F_OPEN64 define in zutil.h\n- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE\n- Avoid errors on non-LFS systems when applications define LFS macros\n- Set EXE to \".exe\" in configure for MINGW [Kahle]\n- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill]\n- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev]\n- Add DLL install in win32/makefile.gcc [Bar-Lev]\n- Allow Linux* or linux* from uname in configure [Bar-Lev]\n- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev]\n- Add cross-compilation prefixes to configure [Bar-Lev]\n- Match type exactly in gz_load() invocation in gzread.c\n- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func\n- Provide prototypes for *64 functions when building zlib without LFS\n- Don't use -lc when linking shared library on MinGW\n- Remove errno.h check in configure and vestigial errno code in zutil.h\n\nChanges in 1.2.4 (14 Mar 2010)\n- Fix VER3 extraction in configure for no fourth subversion\n- Update zlib.3, add docs to Makefile.in to make .pdf out of it\n- Add zlib.3.pdf to distribution\n- Don't set error code in gzerror() if passed pointer is NULL\n- Apply destination directory fixes to CMakeLists.txt [Lowman]\n- Move #cmakedefine's to a new zconf.in.cmakein\n- Restore zconf.h for builds that don't use configure or cmake\n- Add distclean to dummy Makefile for convenience\n- Update and improve INDEX, README, and FAQ\n- Update CMakeLists.txt for the return of zconf.h [Lowman]\n- Update contrib/vstudio/vc9 and vc10 [Vollant]\n- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc\n- Apply license and readme changes to contrib/asm686 [Raiter]\n- Check file name lengths and add -c option in minigzip.c [Li]\n- Update contrib/amd64 and contrib/masmx86/ [Vollant]\n- Avoid use of \"eof\" parameter in trees.c to not shadow library variable\n- Update make_vms.com for removal of zlibdefs.h [Zinser]\n- Update assembler code and vstudio projects in contrib [Vollant]\n- Remove outdated assembler code contrib/masm686 and contrib/asm586\n- Remove old vc7 and vc8 from contrib/vstudio\n- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe]\n- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open()\n- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant]\n- Remove *64 functions from win32/zlib.def (they're not 64-bit yet)\n- Fix bug in void-returning vsprintf() case in gzwrite.c\n- Fix name change from inflate.h in contrib/inflate86/inffas86.c\n- Check if temporary file exists before removing in make_vms.com [Zinser]\n- Fix make install and uninstall for --static option\n- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta]\n- Update readme.txt in contrib/masmx64 and masmx86 to assemble\n\nChanges in 1.2.3.9 (21 Feb 2010)\n- Expunge gzio.c\n- Move as400 build information to old\n- Fix updates in contrib/minizip and contrib/vstudio\n- Add const to vsnprintf test in configure to avoid warnings [Weigelt]\n- Delete zconf.h (made by configure) [Weigelt]\n- Change zconf.in.h to zconf.h.in per convention [Weigelt]\n- Check for NULL buf in gzgets()\n- Return empty string for gzgets() with len == 1 (like fgets())\n- Fix description of gzgets() in zlib.h for end-of-file, NULL return\n- Update minizip to 1.1 [Vollant]\n- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c\n- Note in zlib.h that gzerror() should be used to distinguish from EOF\n- Remove use of snprintf() from gzlib.c\n- Fix bug in gzseek()\n- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant]\n- Fix zconf.h generation in CMakeLists.txt [Lowman]\n- Improve comments in zconf.h where modified by configure\n\nChanges in 1.2.3.8 (13 Feb 2010)\n- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer]\n- Use z_off64_t in gz_zero() and gz_skip() to match state->skip\n- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t)\n- Revert to Makefile.in from 1.2.3.6 (live with the clutter)\n- Fix missing error return in gzflush(), add zlib.h note\n- Add *64 functions to zlib.map [Levin]\n- Fix signed/unsigned comparison in gz_comp()\n- Use SFLAGS when testing shared linking in configure\n- Add --64 option to ./configure to use -m64 with gcc\n- Fix ./configure --help to correctly name options\n- Have make fail if a test fails [Levin]\n- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson]\n- Remove assembler object files from contrib\n\nChanges in 1.2.3.7 (24 Jan 2010)\n- Always gzopen() with O_LARGEFILE if available\n- Fix gzdirect() to work immediately after gzopen() or gzdopen()\n- Make gzdirect() more precise when the state changes while reading\n- Improve zlib.h documentation in many places\n- Catch memory allocation failure in gz_open()\n- Complete close operation if seek forward in gzclose_w() fails\n- Return Z_ERRNO from gzclose_r() if close() fails\n- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL\n- Return zero for gzwrite() errors to match zlib.h description\n- Return -1 on gzputs() error to match zlib.h description\n- Add zconf.in.h to allow recovery from configure modification [Weigelt]\n- Fix static library permissions in Makefile.in [Weigelt]\n- Avoid warnings in configure tests that hide functionality [Weigelt]\n- Add *BSD and DragonFly to Linux case in configure [gentoo 123571]\n- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212]\n- Avoid access of uninitialized data for first inflateReset2 call [Gomes]\n- Keep object files in subdirectories to reduce the clutter somewhat\n- Remove default Makefile and zlibdefs.h, add dummy Makefile\n- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_\n- Remove zlibdefs.h completely -- modify zconf.h instead\n\nChanges in 1.2.3.6 (17 Jan 2010)\n- Avoid void * arithmetic in gzread.c and gzwrite.c\n- Make compilers happier with const char * for gz_error message\n- Avoid unused parameter warning in inflate.c\n- Avoid signed-unsigned comparison warning in inflate.c\n- Indent #pragma's for traditional C\n- Fix usage of strwinerror() in glib.c, change to gz_strwinerror()\n- Correct email address in configure for system options\n- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser]\n- Update zlib.map [Brown]\n- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok]\n- Apply various fixes to CMakeLists.txt [Lowman]\n- Add checks on len in gzread() and gzwrite()\n- Add error message for no more room for gzungetc()\n- Remove zlib version check in gzwrite()\n- Defer compression of gzprintf() result until need to\n- Use snprintf() in gzdopen() if available\n- Remove USE_MMAP configuration determination (only used by minigzip)\n- Remove examples/pigz.c (available separately)\n- Update examples/gun.c to 1.6\n\nChanges in 1.2.3.5 (8 Jan 2010)\n- Add space after #if in zutil.h for some compilers\n- Fix relatively harmless bug in deflate_fast() [Exarevsky]\n- Fix same problem in deflate_slow()\n- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown]\n- Add deflate_rle() for faster Z_RLE strategy run-length encoding\n- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding\n- Change name of \"write\" variable in inffast.c to avoid library collisions\n- Fix premature EOF from gzread() in gzio.c [Brown]\n- Use zlib header window size if windowBits is 0 in inflateInit2()\n- Remove compressBound() call in deflate.c to avoid linking compress.o\n- Replace use of errno in gz* with functions, support WinCE [Alves]\n- Provide alternative to perror() in minigzip.c for WinCE [Alves]\n- Don't use _vsnprintf on later versions of MSVC [Lowman]\n- Add CMake build script and input file [Lowman]\n- Update contrib/minizip to 1.1 [Svensson, Vollant]\n- Moved nintendods directory from contrib to root\n- Replace gzio.c with a new set of routines with the same functionality\n- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above\n- Update contrib/minizip to 1.1b\n- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h\n\nChanges in 1.2.3.4 (21 Dec 2009)\n- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility\n- Update comments in configure and Makefile.in for default --shared\n- Fix test -z's in configure [Marquess]\n- Build examplesh and minigzipsh when not testing\n- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h\n- Import LDFLAGS from the environment in configure\n- Fix configure to populate SFLAGS with discovered CFLAGS options\n- Adapt make_vms.com to the new Makefile.in [Zinser]\n- Add zlib2ansi script for C++ compilation [Marquess]\n- Add _FILE_OFFSET_BITS=64 test to make test (when applicable)\n- Add AMD64 assembler code for longest match to contrib [Teterin]\n- Include options from $SFLAGS when doing $LDSHARED\n- Simplify 64-bit file support by introducing z_off64_t type\n- Make shared object files in objs directory to work around old Sun cc\n- Use only three-part version number for Darwin shared compiles\n- Add rc option to ar in Makefile.in for when ./configure not run\n- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4*\n- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile\n- Protect against _FILE_OFFSET_BITS being defined when compiling zlib\n- Rename Makefile.in targets allstatic to static and allshared to shared\n- Fix static and shared Makefile.in targets to be independent\n- Correct error return bug in gz_open() by setting state [Brown]\n- Put spaces before ;;'s in configure for better sh compatibility\n- Add pigz.c (parallel implementation of gzip) to examples/\n- Correct constant in crc32.c to UL [Leventhal]\n- Reject negative lengths in crc32_combine()\n- Add inflateReset2() function to work like inflateEnd()/inflateInit2()\n- Include sys/types.h for _LARGEFILE64_SOURCE [Brown]\n- Correct typo in doc/algorithm.txt [Janik]\n- Fix bug in adler32_combine() [Zhu]\n- Catch missing-end-of-block-code error in all inflates and in puff\n    Assures that random input to inflate eventually results in an error\n- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/\n- Update ENOUGH and its usage to reflect discovered bounds\n- Fix gzerror() error report on empty input file [Brown]\n- Add ush casts in trees.c to avoid pedantic runtime errors\n- Fix typo in zlib.h uncompress() description [Reiss]\n- Correct inflate() comments with regard to automatic header detection\n- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays)\n- Put new version of gzlog (2.0) in examples with interruption recovery\n- Add puff compile option to permit invalid distance-too-far streams\n- Add puff TEST command options, ability to read piped input\n- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but\n  _LARGEFILE64_SOURCE not defined\n- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart\n- Fix deflateSetDictionary() to use all 32K for output consistency\n- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h)\n- Clear bytes after deflate lookahead to avoid use of uninitialized data\n- Change a limit in inftrees.c to be more transparent to Coverity Prevent\n- Update win32/zlib.def with exported symbols from zlib.h\n- Correct spelling errors in zlib.h [Willem, Sobrado]\n- Allow Z_BLOCK for deflate() to force a new block\n- Allow negative bits in inflatePrime() to delete existing bit buffer\n- Add Z_TREES flush option to inflate() to return at end of trees\n- Add inflateMark() to return current state information for random access\n- Add Makefile for NintendoDS to contrib [Costa]\n- Add -w in configure compile tests to avoid spurious warnings [Beucler]\n- Fix typos in zlib.h comments for deflateSetDictionary()\n- Fix EOF detection in transparent gzread() [Maier]\n\nChanges in 1.2.3.3 (2 October 2006)\n- Make --shared the default for configure, add a --static option\n- Add compile option to permit invalid distance-too-far streams\n- Add inflateUndermine() function which is required to enable above\n- Remove use of \"this\" variable name for C++ compatibility [Marquess]\n- Add testing of shared library in make test, if shared library built\n- Use ftello() and fseeko() if available instead of ftell() and fseek()\n- Provide two versions of all functions that use the z_off_t type for\n  binary compatibility -- a normal version and a 64-bit offset version,\n  per the Large File Support Extension when _LARGEFILE64_SOURCE is\n  defined; use the 64-bit versions by default when _FILE_OFFSET_BITS\n  is defined to be 64\n- Add a --uname= option to configure to perhaps help with cross-compiling\n\nChanges in 1.2.3.2 (3 September 2006)\n- Turn off silly Borland warnings [Hay]\n- Use off64_t and define _LARGEFILE64_SOURCE when present\n- Fix missing dependency on inffixed.h in Makefile.in\n- Rig configure --shared to build both shared and static [Teredesai, Truta]\n- Remove zconf.in.h and instead create a new zlibdefs.h file\n- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant]\n- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt]\n\nChanges in 1.2.3.1 (16 August 2006)\n- Add watcom directory with OpenWatcom make files [Daniel]\n- Remove #undef of FAR in zconf.in.h for MVS [Fedtke]\n- Update make_vms.com [Zinser]\n- Use -fPIC for shared build in configure [Teredesai, Nicholson]\n- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen]\n- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bäck]\n- Add some FAQ entries about the contrib directory\n- Update the MVS question in the FAQ\n- Avoid extraneous reads after EOF in gzio.c [Brown]\n- Correct spelling of \"successfully\" in gzio.c [Randers-Pehrson]\n- Add comments to zlib.h about gzerror() usage [Brown]\n- Set extra flags in gzip header in gzopen() like deflate() does\n- Make configure options more compatible with double-dash conventions\n  [Weigelt]\n- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen]\n- Fix uninstall target in Makefile.in [Truta]\n- Add pkgconfig support [Weigelt]\n- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt]\n- Replace set_data_type() with a more accurate detect_data_type() in\n  trees.c, according to the txtvsbin.txt document [Truta]\n- Swap the order of #include <stdio.h> and #include \"zlib.h\" in\n  gzio.c, example.c and minigzip.c [Truta]\n- Shut up annoying VS2005 warnings about standard C deprecation [Rowe,\n  Truta] (where?)\n- Fix target \"clean\" from win32/Makefile.bor [Truta]\n- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe]\n- Update zlib www home address in win32/DLL_FAQ.txt [Truta]\n- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove]\n- Enable browse info in the \"Debug\" and \"ASM Debug\" configurations in\n  the Visual C++ 6 project, and set (non-ASM) \"Debug\" as default [Truta]\n- Add pkgconfig support [Weigelt]\n- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h,\n  for use in win32/zlib1.rc [Polushin, Rowe, Truta]\n- Add a document that explains the new text detection scheme to\n  doc/txtvsbin.txt [Truta]\n- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta]\n- Move algorithm.txt into doc/ [Truta]\n- Synchronize FAQ with website\n- Fix compressBound(), was low for some pathological cases [Fearnley]\n- Take into account wrapper variations in deflateBound()\n- Set examples/zpipe.c input and output to binary mode for Windows\n- Update examples/zlib_how.html with new zpipe.c (also web site)\n- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems\n  that gcc became pickier in 4.0)\n- Add zlib.map for Linux: \"All symbols from zlib-1.1.4 remain\n  un-versioned, the patch adds versioning only for symbols introduced in\n  zlib-1.2.0 or later.  It also declares as local those symbols which are\n  not designed to be exported.\" [Levin]\n- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure\n- Do not initialize global static by default in trees.c, add a response\n  NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess]\n- Don't use strerror() in gzio.c under WinCE [Yakimov]\n- Don't use errno.h in zutil.h under WinCE [Yakimov]\n- Move arguments for AR to its usage to allow replacing ar [Marot]\n- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson]\n- Improve inflateInit() and inflateInit2() documentation\n- Fix structure size comment in inflate.h\n- Change configure help option from --h* to --help [Santos]\n\nChanges in 1.2.3 (18 July 2005)\n- Apply security vulnerability fixes to contrib/infback9 as well\n- Clean up some text files (carriage returns, trailing space)\n- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]\n\nChanges in 1.2.2.4 (11 July 2005)\n- Add inflatePrime() function for starting inflation at bit boundary\n- Avoid some Visual C warnings in deflate.c\n- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit\n  compile\n- Fix some spelling errors in comments [Betts]\n- Correct inflateInit2() error return documentation in zlib.h\n- Add zran.c example of compressed data random access to examples\n  directory, shows use of inflatePrime()\n- Fix cast for assignments to strm->state in inflate.c and infback.c\n- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]\n- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]\n- Add cast in trees.c t avoid a warning [Oberhumer]\n- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]\n- Update make_vms.com [Zinser]\n- Initialize state->write in inflateReset() since copied in inflate_fast()\n- Be more strict on incomplete code sets in inflate_table() and increase\n  ENOUGH and MAXD -- this repairs a possible security vulnerability for\n  invalid inflate input.  Thanks to Tavis Ormandy and Markus Oberhumer for\n  discovering the vulnerability and providing test cases\n- Add ia64 support to configure for HP-UX [Smith]\n- Add error return to gzread() for format or i/o error [Levin]\n- Use malloc.h for OS/2 [Necasek]\n\nChanges in 1.2.2.3 (27 May 2005)\n- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile\n- Typecast fread() return values in gzio.c [Vollant]\n- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)\n- Fix crc check bug in gzread() after gzungetc() [Heiner]\n- Add the deflateTune() function to adjust internal compression parameters\n- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)\n- Remove an incorrect assertion in examples/zpipe.c\n- Add C++ wrapper in infback9.h [Donais]\n- Fix bug in inflateCopy() when decoding fixed codes\n- Note in zlib.h how much deflateSetDictionary() actually uses\n- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)\n- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]\n- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]\n- Add gzdirect() function to indicate transparent reads\n- Update contrib/minizip [Vollant]\n- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]\n- Add casts in crc32.c to avoid warnings [Oberhumer]\n- Add contrib/masmx64 [Vollant]\n- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]\n\nChanges in 1.2.2.2 (30 December 2004)\n- Replace structure assignments in deflate.c and inflate.c with zmemcpy to\n  avoid implicit memcpy calls (portability for no-library compilation)\n- Increase sprintf() buffer size in gzdopen() to allow for large numbers\n- Add INFLATE_STRICT to check distances against zlib header\n- Improve WinCE errno handling and comments [Chang]\n- Remove comment about no gzip header processing in FAQ\n- Add Z_FIXED strategy option to deflateInit2() to force fixed trees\n- Add updated make_vms.com [Coghlan], update README\n- Create a new \"examples\" directory, move gzappend.c there, add zpipe.c,\n  fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html\n- Add FAQ entry and comments in deflate.c on uninitialized memory access\n- Add Solaris 9 make options in configure [Gilbert]\n- Allow strerror() usage in gzio.c for STDC\n- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]\n- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]\n- Use z_off_t for adler32_combine() and crc32_combine() lengths\n- Make adler32() much faster for small len\n- Use OS_CODE in deflate() default gzip header\n\nChanges in 1.2.2.1 (31 October 2004)\n- Allow inflateSetDictionary() call for raw inflate\n- Fix inflate header crc check bug for file names and comments\n- Add deflateSetHeader() and gz_header structure for custom gzip headers\n- Add inflateGetheader() to retrieve gzip headers\n- Add crc32_combine() and adler32_combine() functions\n- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list\n- Use zstreamp consistently in zlib.h (inflate_back functions)\n- Remove GUNZIP condition from definition of inflate_mode in inflate.h\n  and in contrib/inflate86/inffast.S [Truta, Anderson]\n- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]\n- Update projects/README.projects and projects/visualc6 [Truta]\n- Update win32/DLL_FAQ.txt [Truta]\n- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]\n- Deprecate Z_ASCII; use Z_TEXT instead [Truta]\n- Use a new algorithm for setting strm->data_type in trees.c [Truta]\n- Do not define an exit() prototype in zutil.c unless DEBUG defined\n- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]\n- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()\n- Fix Darwin build version identification [Peterson]\n\nChanges in 1.2.2 (3 October 2004)\n- Update zlib.h comments on gzip in-memory processing\n- Set adler to 1 in inflateReset() to support Java test suite [Walles]\n- Add contrib/dotzlib [Ravn]\n- Update win32/DLL_FAQ.txt [Truta]\n- Update contrib/minizip [Vollant]\n- Move contrib/visual-basic.txt to old/ [Truta]\n- Fix assembler builds in projects/visualc6/ [Truta]\n\nChanges in 1.2.1.2 (9 September 2004)\n- Update INDEX file\n- Fix trees.c to update strm->data_type (no one ever noticed!)\n- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]\n- Add \"volatile\" to crc table flag declaration (for DYNAMIC_CRC_TABLE)\n- Add limited multitasking protection to DYNAMIC_CRC_TABLE\n- Add NO_vsnprintf for VMS in zutil.h [Mozilla]\n- Don't declare strerror() under VMS [Mozilla]\n- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize\n- Update contrib/ada [Anisimkov]\n- Update contrib/minizip [Vollant]\n- Fix configure to not hardcode directories for Darwin [Peterson]\n- Fix gzio.c to not return error on empty files [Brown]\n- Fix indentation; update version in contrib/delphi/ZLib.pas and\n  contrib/pascal/zlibpas.pas [Truta]\n- Update mkasm.bat in contrib/masmx86 [Truta]\n- Update contrib/untgz [Truta]\n- Add projects/README.projects [Truta]\n- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]\n- Update win32/DLL_FAQ.txt [Truta]\n- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]\n- Remove an unnecessary assignment to curr in inftrees.c [Truta]\n- Add OS/2 to exe builds in configure [Poltorak]\n- Remove err dummy parameter in zlib.h [Kientzle]\n\nChanges in 1.2.1.1 (9 January 2004)\n- Update email address in README\n- Several FAQ updates\n- Fix a big fat bug in inftrees.c that prevented decoding valid\n  dynamic blocks with only literals and no distance codes --\n  Thanks to \"Hot Emu\" for the bug report and sample file\n- Add a note to puff.c on no distance codes case\n\nChanges in 1.2.1 (17 November 2003)\n- Remove a tab in contrib/gzappend/gzappend.c\n- Update some interfaces in contrib for new zlib functions\n- Update zlib version number in some contrib entries\n- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]\n- Support shared libraries on Hurd and KFreeBSD [Brown]\n- Fix error in NO_DIVIDE option of adler32.c\n\nChanges in 1.2.0.8 (4 November 2003)\n- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas\n- Add experimental NO_DIVIDE #define in adler32.c\n    - Possibly faster on some processors (let me know if it is)\n- Correct Z_BLOCK to not return on first inflate call if no wrap\n- Fix strm->data_type on inflate() return to correctly indicate EOB\n- Add deflatePrime() function for appending in the middle of a byte\n- Add contrib/gzappend for an example of appending to a stream\n- Update win32/DLL_FAQ.txt [Truta]\n- Delete Turbo C comment in README [Truta]\n- Improve some indentation in zconf.h [Truta]\n- Fix infinite loop on bad input in configure script [Church]\n- Fix gzeof() for concatenated gzip files [Johnson]\n- Add example to contrib/visual-basic.txt [Michael B.]\n- Add -p to mkdir's in Makefile.in [vda]\n- Fix configure to properly detect presence or lack of printf functions\n- Add AS400 support [Monnerat]\n- Add a little Cygwin support [Wilson]\n\nChanges in 1.2.0.7 (21 September 2003)\n- Correct some debug formats in contrib/infback9\n- Cast a type in a debug statement in trees.c\n- Change search and replace delimiter in configure from % to # [Beebe]\n- Update contrib/untgz to 0.2 with various fixes [Truta]\n- Add build support for Amiga [Nikl]\n- Remove some directories in old that have been updated to 1.2\n- Add dylib building for Mac OS X in configure and Makefile.in\n- Remove old distribution stuff from Makefile\n- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X\n- Update links in README\n\nChanges in 1.2.0.6 (13 September 2003)\n- Minor FAQ updates\n- Update contrib/minizip to 1.00 [Vollant]\n- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]\n- Update POSTINC comment for 68060 [Nikl]\n- Add contrib/infback9 with deflate64 decoding (unsupported)\n- For MVS define NO_vsnprintf and undefine FAR [van Burik]\n- Add pragma for fdopen on MVS [van Burik]\n\nChanges in 1.2.0.5 (8 September 2003)\n- Add OF to inflateBackEnd() declaration in zlib.h\n- Remember start when using gzdopen in the middle of a file\n- Use internal off_t counters in gz* functions to properly handle seeks\n- Perform more rigorous check for distance-too-far in inffast.c\n- Add Z_BLOCK flush option to return from inflate at block boundary\n- Set strm->data_type on return from inflate\n    - Indicate bits unused, if at block boundary, and if in last block\n- Replace size_t with ptrdiff_t in crc32.c, and check for correct size\n- Add condition so old NO_DEFLATE define still works for compatibility\n- FAQ update regarding the Windows DLL [Truta]\n- INDEX update: add qnx entry, remove aix entry [Truta]\n- Install zlib.3 into mandir [Wilson]\n- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]\n- Adapt the zlib interface to the new DLL convention guidelines [Truta]\n- Introduce ZLIB_WINAPI macro to allow the export of functions using\n  the WINAPI calling convention, for Visual Basic [Vollant, Truta]\n- Update msdos and win32 scripts and makefiles [Truta]\n- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]\n- Add contrib/ada [Anisimkov]\n- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]\n- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]\n- Add contrib/masm686 [Truta]\n- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm\n  [Truta, Vollant]\n- Update contrib/delphi; rename to contrib/pascal; add example [Truta]\n- Remove contrib/delphi2; add a new contrib/delphi [Truta]\n- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,\n  and fix some method prototypes [Truta]\n- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip\n  [Truta]\n- Avoid the use of backslash (\\) in contrib/minizip [Vollant]\n- Fix file time handling in contrib/untgz; update makefiles [Truta]\n- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines\n  [Vollant]\n- Remove contrib/vstudio/vc15_16 [Vollant]\n- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]\n- Update README.contrib [Truta]\n- Invert the assignment order of match_head and s->prev[...] in\n  INSERT_STRING [Truta]\n- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings\n  [Truta]\n- Compare function pointers with 0, not with NULL or Z_NULL [Truta]\n- Fix prototype of syncsearch in inflate.c [Truta]\n- Introduce ASMINF macro to be enabled when using an ASM implementation\n  of inflate_fast [Truta]\n- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]\n- Modify test_gzio in example.c to take a single file name as a\n  parameter [Truta]\n- Exit the example.c program if gzopen fails [Truta]\n- Add type casts around strlen in example.c [Truta]\n- Remove casting to sizeof in minigzip.c; give a proper type\n  to the variable compared with SUFFIX_LEN [Truta]\n- Update definitions of STDC and STDC99 in zconf.h [Truta]\n- Synchronize zconf.h with the new Windows DLL interface [Truta]\n- Use SYS16BIT instead of __32BIT__ to distinguish between\n  16- and 32-bit platforms [Truta]\n- Use far memory allocators in small 16-bit memory models for\n  Turbo C [Truta]\n- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in\n  zlibCompileFlags [Truta]\n- Cygwin has vsnprintf [Wilson]\n- In Windows16, OS_CODE is 0, as in MSDOS [Truta]\n- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]\n\nChanges in 1.2.0.4 (10 August 2003)\n- Minor FAQ updates\n- Be more strict when checking inflateInit2's windowBits parameter\n- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well\n- Add gzip wrapper option to deflateInit2 using windowBits\n- Add updated QNX rule in configure and qnx directory [Bonnefoy]\n- Make inflate distance-too-far checks more rigorous\n- Clean up FAR usage in inflate\n- Add casting to sizeof() in gzio.c and minigzip.c\n\nChanges in 1.2.0.3 (19 July 2003)\n- Fix silly error in gzungetc() implementation [Vollant]\n- Update contrib/minizip and contrib/vstudio [Vollant]\n- Fix printf format in example.c\n- Correct cdecl support in zconf.in.h [Anisimkov]\n- Minor FAQ updates\n\nChanges in 1.2.0.2 (13 July 2003)\n- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons\n- Attempt to avoid warnings in crc32.c for pointer-int conversion\n- Add AIX to configure, remove aix directory [Bakker]\n- Add some casts to minigzip.c\n- Improve checking after insecure sprintf() or vsprintf() calls\n- Remove #elif's from crc32.c\n- Change leave label to inf_leave in inflate.c and infback.c to avoid\n  library conflicts\n- Remove inflate gzip decoding by default--only enable gzip decoding by\n  special request for stricter backward compatibility\n- Add zlibCompileFlags() function to return compilation information\n- More typecasting in deflate.c to avoid warnings\n- Remove leading underscore from _Capital #defines [Truta]\n- Fix configure to link shared library when testing\n- Add some Windows CE target adjustments [Mai]\n- Remove #define ZLIB_DLL in zconf.h [Vollant]\n- Add zlib.3 [Rodgers]\n- Update RFC URL in deflate.c and algorithm.txt [Mai]\n- Add zlib_dll_FAQ.txt to contrib [Truta]\n- Add UL to some constants [Truta]\n- Update minizip and vstudio [Vollant]\n- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h\n- Expand use of NO_DUMMY_DECL to avoid all dummy structures\n- Added iostream3 to contrib [Schwardt]\n- Replace rewind() with fseek() for WinCE [Truta]\n- Improve setting of zlib format compression level flags\n    - Report 0 for huffman and rle strategies and for level == 0 or 1\n    - Report 2 only for level == 6\n- Only deal with 64K limit when necessary at compile time [Truta]\n- Allow TOO_FAR check to be turned off at compile time [Truta]\n- Add gzclearerr() function [Souza]\n- Add gzungetc() function\n\nChanges in 1.2.0.1 (17 March 2003)\n- Add Z_RLE strategy for run-length encoding [Truta]\n    - When Z_RLE requested, restrict matches to distance one\n    - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE\n- Correct FASTEST compilation to allow level == 0\n- Clean up what gets compiled for FASTEST\n- Incorporate changes to zconf.in.h [Vollant]\n    - Refine detection of Turbo C need for dummy returns\n    - Refine ZLIB_DLL compilation\n    - Include additional header file on VMS for off_t typedef\n- Try to use _vsnprintf where it supplants vsprintf [Vollant]\n- Add some casts in inffast.c\n- Enhance comments in zlib.h on what happens if gzprintf() tries to\n  write more than 4095 bytes before compression\n- Remove unused state from inflateBackEnd()\n- Remove exit(0) from minigzip.c, example.c\n- Get rid of all those darn tabs\n- Add \"check\" target to Makefile.in that does the same thing as \"test\"\n- Add \"mostlyclean\" and \"maintainer-clean\" targets to Makefile.in\n- Update contrib/inflate86 [Anderson]\n- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]\n- Add msdos and win32 directories with makefiles [Truta]\n- More additions and improvements to the FAQ\n\nChanges in 1.2.0 (9 March 2003)\n- New and improved inflate code\n    - About 20% faster\n    - Does not allocate 32K window unless and until needed\n    - Automatically detects and decompresses gzip streams\n    - Raw inflate no longer needs an extra dummy byte at end\n    - Added inflateBack functions using a callback interface--even faster\n      than inflate, useful for file utilities (gzip, zip)\n    - Added inflateCopy() function to record state for random access on\n      externally generated deflate streams (e.g. in gzip files)\n    - More readable code (I hope)\n- New and improved crc32()\n    - About 50% faster, thanks to suggestions from Rodney Brown\n- Add deflateBound() and compressBound() functions\n- Fix memory leak in deflateInit2()\n- Permit setting dictionary for raw deflate (for parallel deflate)\n- Fix const declaration for gzwrite()\n- Check for some malloc() failures in gzio.c\n- Fix bug in gzopen() on single-byte file 0x1f\n- Fix bug in gzread() on concatenated file with 0x1f at end of buffer\n  and next buffer doesn't start with 0x8b\n- Fix uncompress() to return Z_DATA_ERROR on truncated input\n- Free memory at end of example.c\n- Remove MAX #define in trees.c (conflicted with some libraries)\n- Fix static const's in deflate.c, gzio.c, and zutil.[ch]\n- Declare malloc() and free() in gzio.c if STDC not defined\n- Use malloc() instead of calloc() in zutil.c if int big enough\n- Define STDC for AIX\n- Add aix/ with approach for compiling shared library on AIX\n- Add HP-UX support for shared libraries in configure\n- Add OpenUNIX support for shared libraries in configure\n- Use $cc instead of gcc to build shared library\n- Make prefix directory if needed when installing\n- Correct Macintosh avoidance of typedef Byte in zconf.h\n- Correct Turbo C memory allocation when under Linux\n- Use libz.a instead of -lz in Makefile (assure use of compiled library)\n- Update configure to check for snprintf or vsnprintf functions and their\n  return value, warn during make if using an insecure function\n- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that\n  is lost when library is used--resolution is to build new zconf.h\n- Documentation improvements (in zlib.h):\n    - Document raw deflate and inflate\n    - Update RFCs URL\n    - Point out that zlib and gzip formats are different\n    - Note that Z_BUF_ERROR is not fatal\n    - Document string limit for gzprintf() and possible buffer overflow\n    - Note requirement on avail_out when flushing\n    - Note permitted values of flush parameter of inflate()\n- Add some FAQs (and even answers) to the FAQ\n- Add contrib/inflate86/ for x86 faster inflate\n- Add contrib/blast/ for PKWare Data Compression Library decompression\n- Add contrib/puff/ simple inflate for deflate format description\n\nChanges in 1.1.4 (11 March 2002)\n- ZFREE was repeated on same allocation on some error conditions\n  This creates a security problem described in\n  http://www.zlib.org/advisory-2002-03-11.txt\n- Returned incorrect error (Z_MEM_ERROR) on some invalid data\n- Avoid accesses before window for invalid distances with inflate window\n  less than 32K\n- force windowBits > 8 to avoid a bug in the encoder for a window size\n  of 256 bytes. (A complete fix will be available in 1.1.5)\n\nChanges in 1.1.3 (9 July 1998)\n- fix \"an inflate input buffer bug that shows up on rare but persistent\n  occasions\" (Mark)\n- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)\n- fix gzseek(..., SEEK_SET) in write mode\n- fix crc check after a gzeek (Frank Faubert)\n- fix miniunzip when the last entry in a zip file is itself a zip file\n  (J Lillge)\n- add contrib/asm586 and contrib/asm686 (Brian Raiter)\n  See http://www.muppetlabs.com/~breadbox/software/assembly.html\n- add support for Delphi 3 in contrib/delphi (Bob Dellaca)\n- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)\n- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)\n- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)\n- added a FAQ file\n\n- Support gzdopen on Mac with Metrowerks (Jason Linhart)\n- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)\n- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)\n- avoid some warnings with Borland C (Tom Tanner)\n- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)\n- emulate utime() for WIN32 in contrib/untgz  (Gilles Vollant)\n- allow several arguments to configure (Tim Mooney, Frodo Looijaard)\n- use libdir and includedir in Makefile.in (Tim Mooney)\n- support shared libraries on OSF1 V4 (Tim Mooney)\n- remove so_locations in \"make clean\"  (Tim Mooney)\n- fix maketree.c compilation error (Glenn, Mark)\n- Python interface to zlib now in Python 1.5 (Jeremy Hylton)\n- new Makefile.riscos (Rich Walker)\n- initialize static descriptors in trees.c for embedded targets (Nick Smith)\n- use \"foo-gz\" in example.c for RISCOS and VMS (Nick Smith)\n- add the OS/2 files in Makefile.in too (Andrew Zabolotny)\n- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)\n- fix maketree.c to allow clean compilation of inffixed.h (Mark)\n- fix parameter check in deflateCopy (Gunther Nikl)\n- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)\n- Many portability patches by Christian Spieler:\n  . zutil.c, zutil.h: added \"const\" for zmem*\n  . Make_vms.com: fixed some typos\n  . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists\n  . msdos/Makefile.msc: remove \"default rtl link library\" info from obj files\n  . msdos/Makefile.*: use model-dependent name for the built zlib library\n  . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:\n     new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)\n- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)\n- replace __far with _far for better portability (Christian Spieler, Tom Lane)\n- fix test for errno.h in configure (Tim Newsham)\n\nChanges in 1.1.2 (19 March 98)\n- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)\n  See http://www.winimage.com/zLibDll/unzip.html\n- preinitialize the inflate tables for fixed codes, to make the code\n  completely thread safe (Mark)\n- some simplifications and slight speed-up to the inflate code (Mark)\n- fix gzeof on non-compressed files (Allan Schrum)\n- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)\n- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)\n- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)\n- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)\n- do not wrap extern \"C\" around system includes (Tom Lane)\n- mention zlib binding for TCL in README (Andreas Kupries)\n- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)\n- allow \"make install prefix=...\" even after configure (Glenn Randers-Pehrson)\n- allow \"configure --prefix $HOME\" (Tim Mooney)\n- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)\n- move Makefile.sas to amiga/Makefile.sas\n\nChanges in 1.1.1 (27 Feb 98)\n- fix macros _tr_tally_* in deflate.h for debug mode  (Glenn Randers-Pehrson)\n- remove block truncation heuristic which had very marginal effect for zlib\n  (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the\n  compression ratio on some files. This also allows inlining _tr_tally for\n  matches in deflate_slow\n- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)\n\nChanges in 1.1.0 (24 Feb 98)\n- do not return STREAM_END prematurely in inflate (John Bowler)\n- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)\n- compile with -DFASTEST to get compression code optimized for speed only\n- in minigzip, try mmap'ing the input file first (Miguel Albrecht)\n- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain\n  on Sun but significant on HP)\n\n- add a pointer to experimental unzip library in README (Gilles Vollant)\n- initialize variable gcc in configure (Chris Herborth)\n\nChanges in 1.0.9 (17 Feb 1998)\n- added gzputs and gzgets functions\n- do not clear eof flag in gzseek (Mark Diekhans)\n- fix gzseek for files in transparent mode (Mark Diekhans)\n- do not assume that vsprintf returns the number of bytes written (Jens Krinke)\n- replace EXPORT with ZEXPORT to avoid conflict with other programs\n- added compress2 in zconf.h, zlib.def, zlib.dnt\n- new asm code from Gilles Vollant in contrib/asm386\n- simplify the inflate code (Mark):\n . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()\n . ZALLOC the length list in inflate_trees_fixed() instead of using stack\n . ZALLOC the value area for huft_build() instead of using stack\n . Simplify Z_FINISH check in inflate()\n\n- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8\n- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)\n- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with\n  the declaration of FAR (Gilles Vollant)\n- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)\n- read_buf buf parameter of type Bytef* instead of charf*\n- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)\n- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)\n- fix check for presence of directories in \"make install\" (Ian Willis)\n\nChanges in 1.0.8 (27 Jan 1998)\n- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)\n- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)\n- added compress2() to allow setting the compression level\n- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)\n- use constant arrays for the static trees in trees.c instead of computing\n  them at run time (thanks to Ken Raeburn for this suggestion). To create\n  trees.h, compile with GEN_TREES_H and run \"make test\"\n- check return code of example in \"make test\" and display result\n- pass minigzip command line options to file_compress\n- simplifying code of inflateSync to avoid gcc 2.8 bug\n\n- support CC=\"gcc -Wall\" in configure -s (QingLong)\n- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)\n- fix test for shared library support to avoid compiler warnings\n- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)\n- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)\n- do not use fdopen for Metrowerks on Mac (Brad Pettit))\n- add checks for gzputc and gzputc in example.c\n- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)\n- use const for the CRC table (Ken Raeburn)\n- fixed \"make uninstall\" for shared libraries\n- use Tracev instead of Trace in infblock.c\n- in example.c use correct compressed length for test_sync\n- suppress +vnocompatwarnings in configure for HPUX (not always supported)\n\nChanges in 1.0.7 (20 Jan 1998)\n- fix gzseek which was broken in write mode\n- return error for gzseek to negative absolute position\n- fix configure for Linux (Chun-Chung Chen)\n- increase stack space for MSC (Tim Wegner)\n- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)\n- define EXPORTVA for gzprintf (Gilles Vollant)\n- added man page zlib.3 (Rick Rodgers)\n- for contrib/untgz, fix makedir() and improve Makefile\n\n- check gzseek in write mode in example.c\n- allocate extra buffer for seeks only if gzseek is actually called\n- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)\n- add inflateSyncPoint in zconf.h\n- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def\n\nChanges in 1.0.6 (19 Jan 1998)\n- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and\n  gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)\n- Fix a deflate bug occurring only with compression level 0 (thanks to\n  Andy Buckler for finding this one)\n- In minigzip, pass transparently also the first byte for .Z files\n- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()\n- check Z_FINISH in inflate (thanks to Marc Schluper)\n- Implement deflateCopy (thanks to Adam Costello)\n- make static libraries by default in configure, add --shared option\n- move MSDOS or Windows specific files to directory msdos\n- suppress the notion of partial flush to simplify the interface\n  (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)\n- suppress history buffer provided by application to simplify the interface\n  (this feature was not implemented anyway in 1.0.4)\n- next_in and avail_in must be initialized before calling inflateInit or\n  inflateInit2\n- add EXPORT in all exported functions (for Windows DLL)\n- added Makefile.nt (thanks to Stephen Williams)\n- added the unsupported \"contrib\" directory:\n   contrib/asm386/ by Gilles Vollant <info@winimage.com>\n        386 asm code replacing longest_match()\n   contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>\n        A C++ I/O streams interface to the zlib gz* functions\n   contrib/iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>\n        Another C++ I/O streams interface\n   contrib/untgz/  by \"Pedro A. Aranda Guti\\irrez\" <paag@tid.es>\n        A very simple tar.gz file extractor using zlib\n   contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>\n        How to use compress(), uncompress() and the gz* functions from VB\n- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression\n  level) in minigzip (thanks to Tom Lane)\n\n- use const for rommable constants in deflate\n- added test for gzseek and gztell in example.c\n- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)\n- add undocumented function zError to convert error code to string\n  (for Tim Smithers)\n- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code\n- Use default memcpy for Symantec MSDOS compiler\n- Add EXPORT keyword for check_func (needed for Windows DLL)\n- add current directory to LD_LIBRARY_PATH for \"make test\"\n- create also a link for libz.so.1\n- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)\n- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)\n- added -soname for Linux in configure (Chun-Chung Chen,\n- assign numbers to the exported functions in zlib.def (for Windows DLL)\n- add advice in zlib.h for best usage of deflateSetDictionary\n- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)\n- allow compilation with ANSI keywords only enabled for TurboC in large model\n- avoid \"versionString\"[0] (Borland bug)\n- add NEED_DUMMY_RETURN for Borland\n- use variable z_verbose for tracing in debug mode (L. Peter Deutsch)\n- allow compilation with CC\n- defined STDC for OS/2 (David Charlap)\n- limit external names to 8 chars for MVS (Thomas Lund)\n- in minigzip.c, use static buffers only for 16-bit systems\n- fix suffix check for \"minigzip -d foo.gz\"\n- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)\n- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)\n- added makelcc.bat for lcc-win32 (Tom St Denis)\n- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)\n- Avoid expanded $Id$. Use \"rcs -kb\" or \"cvs admin -kb\" to avoid Id expansion\n- check for unistd.h in configure (for off_t)\n- remove useless check parameter in inflate_blocks_free\n- avoid useless assignment of s->check to itself in inflate_blocks_new\n- do not flush twice in gzclose (thanks to Ken Raeburn)\n- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h\n- use NO_ERRNO_H instead of enumeration of operating systems with errno.h\n- work around buggy fclose on pipes for HP/UX\n- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)\n- fix configure if CC is already equal to gcc\n\nChanges in 1.0.5 (3 Jan 98)\n- Fix inflate to terminate gracefully when fed corrupted or invalid data\n- Use const for rommable constants in inflate\n- Eliminate memory leaks on error conditions in inflate\n- Removed some vestigial code in inflate\n- Update web address in README\n\nChanges in 1.0.4 (24 Jul 96)\n- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF\n  bit, so the decompressor could decompress all the correct data but went\n  on to attempt decompressing extra garbage data. This affected minigzip too\n- zlibVersion and gzerror return const char* (needed for DLL)\n- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)\n- use z_error only for DEBUG (avoid problem with DLLs)\n\nChanges in 1.0.3 (2 Jul 96)\n- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS\n  small and medium models; this makes the library incompatible with previous\n  versions for these models. (No effect in large model or on other systems.)\n- return OK instead of BUF_ERROR if previous deflate call returned with\n  avail_out as zero but there is nothing to do\n- added memcmp for non STDC compilers\n- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)\n- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)\n- better check for 16-bit mode MSC (avoids problem with Symantec)\n\nChanges in 1.0.2 (23 May 96)\n- added Windows DLL support\n- added a function zlibVersion (for the DLL support)\n- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)\n- Bytef is define's instead of typedef'd only for Borland C\n- avoid reading uninitialized memory in example.c\n- mention in README that the zlib format is now RFC1950\n- updated Makefile.dj2\n- added algorithm.doc\n\nChanges in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]\n- fix array overlay in deflate.c which sometimes caused bad compressed data\n- fix inflate bug with empty stored block\n- fix MSDOS medium model which was broken in 0.99\n- fix deflateParams() which could generate bad compressed data\n- Bytef is define'd instead of typedef'ed (work around Borland bug)\n- added an INDEX file\n- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),\n  Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)\n- speed up adler32 for modern machines without auto-increment\n- added -ansi for IRIX in configure\n- static_init_done in trees.c is an int\n- define unlink as delete for VMS\n- fix configure for QNX\n- add configure branch for SCO and HPUX\n- avoid many warnings (unused variables, dead assignments, etc...)\n- no fdopen for BeOS\n- fix the Watcom fix for 32 bit mode (define FAR as empty)\n- removed redefinition of Byte for MKWERKS\n- work around an MWKERKS bug (incorrect merge of all .h files)\n\nChanges in 0.99 (27 Jan 96)\n- allow preset dictionary shared between compressor and decompressor\n- allow compression level 0 (no compression)\n- add deflateParams in zlib.h: allow dynamic change of compression level\n  and compression strategy\n- test large buffers and deflateParams in example.c\n- add optional \"configure\" to build zlib as a shared library\n- suppress Makefile.qnx, use configure instead\n- fixed deflate for 64-bit systems (detected on Cray)\n- fixed inflate_blocks for 64-bit systems (detected on Alpha)\n- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)\n- always return Z_BUF_ERROR when deflate() has nothing to do\n- deflateInit and inflateInit are now macros to allow version checking\n- prefix all global functions and types with z_ with -DZ_PREFIX\n- make falloc completely reentrant (inftrees.c)\n- fixed very unlikely race condition in ct_static_init\n- free in reverse order of allocation to help memory manager\n- use zlib-1.0/* instead of zlib/* inside the tar.gz\n- make zlib warning-free with \"gcc -O3 -Wall -Wwrite-strings -Wpointer-arith\n  -Wconversion -Wstrict-prototypes -Wmissing-prototypes\"\n- allow gzread on concatenated .gz files\n- deflateEnd now returns Z_DATA_ERROR if it was premature\n- deflate is finally (?) fully deterministic (no matches beyond end of input)\n- Document Z_SYNC_FLUSH\n- add uninstall in Makefile\n- Check for __cpluplus in zlib.h\n- Better test in ct_align for partial flush\n- avoid harmless warnings for Borland C++\n- initialize hash_head in deflate.c\n- avoid warning on fdopen (gzio.c) for HP cc -Aa\n- include stdlib.h for STDC compilers\n- include errno.h for Cray\n- ignore error if ranlib doesn't exist\n- call ranlib twice for NeXTSTEP\n- use exec_prefix instead of prefix for libz.a\n- renamed ct_* as _tr_* to avoid conflict with applications\n- clear z->msg in inflateInit2 before any error return\n- initialize opaque in example.c, gzio.c, deflate.c and inflate.c\n- fixed typo in zconf.h (_GNUC__ => __GNUC__)\n- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)\n- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)\n- in fcalloc, normalize pointer if size > 65520 bytes\n- don't use special fcalloc for 32 bit Borland C++\n- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc.\n- use Z_BINARY instead of BINARY\n- document that gzclose after gzdopen will close the file\n- allow \"a\" as mode in gzopen\n- fix error checking in gzread\n- allow skipping .gz extra-field on pipes\n- added reference to Perl interface in README\n- put the crc table in FAR data (I dislike more and more the medium model :)\n- added get_crc_table\n- added a dimension to all arrays (Borland C can't count)\n- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast\n- guard against multiple inclusion of *.h (for precompiled header on Mac)\n- Watcom C pretends to be Microsoft C small model even in 32 bit mode\n- don't use unsized arrays to avoid silly warnings by Visual C++:\n     warning C4746: 'inflate_mask' : unsized array treated as  '__far'\n     (what's wrong with far data in far model?)\n- define enum out of inflate_blocks_state to allow compilation with C++\n\nChanges in 0.95 (16 Aug 95)\n- fix MSDOS small and medium model (now easier to adapt to any compiler)\n- inlined send_bits\n- fix the final (:-) bug for deflate with flush (output was correct but\n  not completely flushed in rare occasions)\n- default window size is same for compression and decompression\n  (it's now sufficient to set MAX_WBITS in zconf.h)\n- voidp -> voidpf and voidnp -> voidp (for consistency with other\n  typedefs and because voidnp was not near in large model)\n\nChanges in 0.94 (13 Aug 95)\n- support MSDOS medium model\n- fix deflate with flush (could sometimes generate bad output)\n- fix deflateReset (zlib header was incorrectly suppressed)\n- added support for VMS\n- allow a compression level in gzopen()\n- gzflush now calls fflush\n- For deflate with flush, flush even if no more input is provided\n- rename libgz.a as libz.a\n- avoid complex expression in infcodes.c triggering Turbo C bug\n- work around a problem with gcc on Alpha (in INSERT_STRING)\n- don't use inline functions (problem with some gcc versions)\n- allow renaming of Byte, uInt, etc... with #define\n- avoid warning about (unused) pointer before start of array in deflate.c\n- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c\n- avoid reserved word 'new' in trees.c\n\nChanges in 0.93 (25 June 95)\n- temporarily disable inline functions\n- make deflate deterministic\n- give enough lookahead for PARTIAL_FLUSH\n- Set binary mode for stdin/stdout in minigzip.c for OS/2\n- don't even use signed char in inflate (not portable enough)\n- fix inflate memory leak for segmented architectures\n\nChanges in 0.92 (3 May 95)\n- don't assume that char is signed (problem on SGI)\n- Clear bit buffer when starting a stored block\n- no memcpy on Pyramid\n- suppressed inftest.c\n- optimized fill_window, put longest_match inline for gcc\n- optimized inflate on stored blocks\n- untabify all sources to simplify patches\n\nChanges in 0.91 (2 May 95)\n- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h\n- Document the memory requirements in zconf.h\n- added \"make install\"\n- fix sync search logic in inflateSync\n- deflate(Z_FULL_FLUSH) now works even if output buffer too short\n- after inflateSync, don't scare people with just \"lo world\"\n- added support for DJGPP\n\nChanges in 0.9 (1 May 95)\n- don't assume that zalloc clears the allocated memory (the TurboC bug\n  was Mark's bug after all :)\n- let again gzread copy uncompressed data unchanged (was working in 0.71)\n- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented\n- added a test of inflateSync in example.c\n- moved MAX_WBITS to zconf.h because users might want to change that\n- document explicitly that zalloc(64K) on MSDOS must return a normalized\n  pointer (zero offset)\n- added Makefiles for Microsoft C, Turbo C, Borland C++\n- faster crc32()\n\nChanges in 0.8 (29 April 95)\n- added fast inflate (inffast.c)\n- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this\n  is incompatible with previous versions of zlib which returned Z_OK\n- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)\n  (actually that was not a compiler bug, see 0.81 above)\n- gzread no longer reads one extra byte in certain cases\n- In gzio destroy(), don't reference a freed structure\n- avoid many warnings for MSDOS\n- avoid the ERROR symbol which is used by MS Windows\n\nChanges in 0.71 (14 April 95)\n- Fixed more MSDOS compilation problems :( There is still a bug with\n  TurboC large model\n\nChanges in 0.7 (14 April 95)\n- Added full inflate support\n- Simplified the crc32() interface. The pre- and post-conditioning\n  (one's complement) is now done inside crc32(). WARNING: this is\n  incompatible with previous versions; see zlib.h for the new usage\n\nChanges in 0.61 (12 April 95)\n- workaround for a bug in TurboC. example and minigzip now work on MSDOS\n\nChanges in 0.6 (11 April 95)\n- added minigzip.c\n- added gzdopen to reopen a file descriptor as gzFile\n- added transparent reading of non-gziped files in gzread\n- fixed bug in gzread (don't read crc as data)\n- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose)\n- don't allocate big arrays in the stack (for MSDOS)\n- fix some MSDOS compilation problems\n\nChanges in 0.5:\n- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but\n  not yet Z_FULL_FLUSH\n- support decompression but only in a single step (forced Z_FINISH)\n- added opaque object for zalloc and zfree\n- added deflateReset and inflateReset\n- added a variable zlib_version for consistency checking\n- renamed the 'filter' parameter of deflateInit2 as 'strategy'\n  Added Z_FILTERED and Z_HUFFMAN_ONLY constants\n\nChanges in 0.4:\n- avoid \"zip\" everywhere, use zlib instead of ziplib\n- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush\n  if compression method == 8\n- added adler32 and crc32\n- renamed deflateOptions as deflateInit2, call one or the other but not both\n- added the method parameter for deflateInit2\n- added inflateInit2\n- simplified considerably deflateInit and inflateInit by not supporting\n  user-provided history buffer. This is supported only in deflateInit2\n  and inflateInit2\n\nChanges in 0.3:\n- prefix all macro names with Z_\n- use Z_FINISH instead of deflateEnd to finish compression\n- added Z_HUFFMAN_ONLY\n- added gzerror()\n"
  },
  {
    "path": "eidos_zlib/README",
    "content": "ZLIB DATA COMPRESSION LIBRARY\n\nzlib 1.3.1 is a general purpose data compression library.  All the code is\nthread safe.  The data format used by the zlib library is described by RFCs\n(Request for Comments) 1950 to 1952 in the files\nhttp://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and\nrfc1952 (gzip format).\n\nAll functions of the compression library are documented in the file zlib.h\n(volunteer to write man pages welcome, contact zlib@gzip.org).  A usage example\nof the library is given in the file test/example.c which also tests that\nthe library is working correctly.  Another example is given in the file\ntest/minigzip.c.  The compression library itself is composed of all source\nfiles in the root directory.\n\nTo compile all files and run the test program, follow the instructions given at\nthe top of Makefile.in.  In short \"./configure; make test\", and if that goes\nwell, \"make install\" should work for most flavors of Unix.  For Windows, use\none of the special makefiles in win32/ or contrib/vstudio/ .  For VMS, use\nmake_vms.com.\n\nQuestions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant\n<info@winimage.com> for the Windows DLL version.  The zlib home page is\nhttp://zlib.net/ .  Before reporting a problem, please check this site to\nverify that you have the latest version of zlib; otherwise get the latest\nversion and check whether the problem still exists or not.\n\nPLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.\n\nMark Nelson <markn@ieee.org> wrote an article about zlib for the Jan.  1997\nissue of Dr.  Dobb's Journal; a copy of the article is available at\nhttps://marknelson.us/posts/1997/01/01/zlib-engine.html .\n\nThe changes made in version 1.3.1 are documented in the file ChangeLog.\n\nUnsupported third party contributions are provided in directory contrib/ .\n\nzlib is available in Java using the java.util.zip package. Follow the API\nDocumentation link at: https://docs.oracle.com/search/?q=java.util.zip .\n\nA Perl interface to zlib and bzip2 written by Paul Marquess <pmqs@cpan.org>\ncan be found at https://github.com/pmqs/IO-Compress .\n\nA Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is\navailable in Python 1.5 and later versions, see\nhttp://docs.python.org/library/zlib.html .\n\nzlib is built into tcl: http://wiki.tcl.tk/4610 .\n\nAn experimental package to read and write files in .zip format, written on top\nof zlib by Gilles Vollant <info@winimage.com>, is available in the\ncontrib/minizip directory of zlib.\n\n\nNotes for some targets:\n\n- For Windows DLL versions, please see win32/DLL_FAQ.txt\n\n- For 64-bit Irix, deflate.c must be compiled without any optimization. With\n  -O, one libpng test fails. The test works in 32 bit mode (with the -n32\n  compiler flag). The compiler bug has been reported to SGI.\n\n- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works\n  when compiled with cc.\n\n- On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is\n  necessary to get gzprintf working correctly. This is done by configure.\n\n- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with\n  other compilers. Use \"make test\" to check your compiler.\n\n- gzdopen is not supported on RISCOS or BEOS.\n\n- For PalmOs, see http://palmzlib.sourceforge.net/\n\n\nAcknowledgments:\n\n  The deflate format used by zlib was defined by Phil Katz.  The deflate and\n  zlib specifications were written by L.  Peter Deutsch.  Thanks to all the\n  people who reported problems and suggested various improvements in zlib; they\n  are too numerous to cite here.\n\nCopyright notice:\n\n (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\nIf you use the zlib library in a product, we would appreciate *not* receiving\nlengthy legal documents to sign.  The sources are provided for free but without\nwarranty of any kind.  The library has been entirely written by Jean-loup\nGailly and Mark Adler; it does not include third-party code.  We make all\ncontributions to and distributions of this project solely in our personal\ncapacity, and are not conveying any rights to any intellectual property of\nany third parties.\n\nIf you redistribute modified sources, we would appreciate that you include in\nthe file ChangeLog history information documenting your changes.  Please read\nthe FAQ for more information on the distribution of modified source versions.\n"
  },
  {
    "path": "eidos_zlib/adler32.c",
    "content": "/* adler32.c -- compute the Adler-32 checksum of a data stream\n * Copyright (C) 1995-2011, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n\n#define BASE 65521U     /* largest prime smaller than 65536 */\n#define NMAX 5552\n/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */\n\n#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}\n#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);\n#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);\n#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);\n#define DO16(buf)   DO8(buf,0); DO8(buf,8);\n\n/* use NO_DIVIDE if your processor does not do division in hardware --\n   try it both ways to see which is faster */\n#ifdef NO_DIVIDE\n/* note that this assumes BASE is 65521, where 65536 % 65521 == 15\n   (thank you to John Reiser for pointing this out) */\n#  define CHOP(a) \\\n    do { \\\n        unsigned long tmp = a >> 16; \\\n        a &= 0xffffUL; \\\n        a += (tmp << 4) - tmp; \\\n    } while (0)\n#  define MOD28(a) \\\n    do { \\\n        CHOP(a); \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#  define MOD(a) \\\n    do { \\\n        CHOP(a); \\\n        MOD28(a); \\\n    } while (0)\n#  define MOD63(a) \\\n    do { /* this assumes a is not negative */ \\\n        z_off64_t tmp = a >> 32; \\\n        a &= 0xffffffffL; \\\n        a += (tmp << 8) - (tmp << 5) + tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#else\n#  define MOD(a) a %= BASE\n#  define MOD28(a) a %= BASE\n#  define MOD63(a) a %= BASE\n#endif\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {\n    unsigned long sum2;\n    unsigned n;\n\n    /* split Adler-32 into component sums */\n    sum2 = (adler >> 16) & 0xffff;\n    adler &= 0xffff;\n\n    /* in case user likes doing a byte at a time, keep it fast */\n    if (len == 1) {\n        adler += buf[0];\n        if (adler >= BASE)\n            adler -= BASE;\n        sum2 += adler;\n        if (sum2 >= BASE)\n            sum2 -= BASE;\n        return adler | (sum2 << 16);\n    }\n\n    /* initial Adler-32 value (deferred check for len == 1 speed) */\n    if (buf == Z_NULL)\n        return 1L;\n\n    /* in case short lengths are provided, keep it somewhat fast */\n    if (len < 16) {\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        if (adler >= BASE)\n            adler -= BASE;\n        MOD28(sum2);            /* only added so many BASE's */\n        return adler | (sum2 << 16);\n    }\n\n    /* do length NMAX blocks -- requires just one modulo operation */\n    while (len >= NMAX) {\n        len -= NMAX;\n        n = NMAX / 16;          /* NMAX is divisible by 16 */\n        do {\n            DO16(buf);          /* 16 sums unrolled */\n            buf += 16;\n        } while (--n);\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* do remaining bytes (less than NMAX, still just one modulo) */\n    if (len) {                  /* avoid modulos if none remaining */\n        while (len >= 16) {\n            len -= 16;\n            DO16(buf);\n            buf += 16;\n        }\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* return recombined sums */\n    return adler | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {\n    return adler32_z(adler, buf, len);\n}\n\n/* ========================================================================= */\nlocal uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {\n    unsigned long sum1;\n    unsigned long sum2;\n    unsigned rem;\n\n    /* for negative len, return invalid adler32 as a clue for debugging */\n    if (len2 < 0)\n        return 0xffffffffUL;\n\n    /* the derivation of this formula is left as an exercise for the reader */\n    MOD63(len2);                /* assumes len2 >= 0 */\n    rem = (unsigned)len2;\n    sum1 = adler1 & 0xffff;\n    sum2 = rem * sum1;\n    MOD(sum2);\n    sum1 += (adler2 & 0xffff) + BASE - 1;\n    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);\n    if (sum2 >= BASE) sum2 -= BASE;\n    return sum1 | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {\n    return adler32_combine_(adler1, adler2, len2);\n}\n\n// BCH 9/29/2021: This function appears to be unused in this branch of the code,\n// and produces a warning on Windows, so I'm going to just #if it out.\n#if 0\nuLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {\n    return adler32_combine_(adler1, adler2, len2);\n}\n#endif\n\n"
  },
  {
    "path": "eidos_zlib/compress.c",
    "content": "/* compress.c -- compress a memory buffer\n * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#define ZLIB_INTERNAL\n#include \"zlib.h\"\n\n/* ===========================================================================\n     Compresses the source buffer into the destination buffer. The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer. Upon entry, destLen is the total size of the\n   destination buffer, which must be at least 0.1% larger than sourceLen plus\n   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\nint ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,\n                      uLong sourceLen, int level) {\n    z_stream stream;\n    int err;\n    const uInt max = (uInt)-1;\n    uLong left;\n\n    left = *destLen;\n    *destLen = 0;\n\n    stream.zalloc = (alloc_func)0;\n    stream.zfree = (free_func)0;\n    stream.opaque = (voidpf)0;\n\n    err = deflateInit(&stream, level);\n    if (err != Z_OK) return err;\n\n    stream.next_out = dest;\n    stream.avail_out = 0;\n    stream.next_in = (z_const Bytef *)source;\n    stream.avail_in = 0;\n\n    do {\n        if (stream.avail_out == 0) {\n            stream.avail_out = left > (uLong)max ? max : (uInt)left;\n            left -= stream.avail_out;\n        }\n        if (stream.avail_in == 0) {\n            stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;\n            sourceLen -= stream.avail_in;\n        }\n        err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);\n    } while (err == Z_OK);\n\n    *destLen = stream.total_out;\n    deflateEnd(&stream);\n    return err == Z_STREAM_END ? Z_OK : err;\n}\n\n/* ===========================================================================\n */\nint ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,\n                     uLong sourceLen) {\n    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);\n}\n\n/* ===========================================================================\n     If the default memLevel or windowBits for deflateInit() is changed, then\n   this function needs to be updated.\n */\nuLong ZEXPORT compressBound(uLong sourceLen) {\n    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +\n           (sourceLen >> 25) + 13;\n}\n"
  },
  {
    "path": "eidos_zlib/crc32.c",
    "content": "/* crc32.c -- compute the CRC-32 of a data stream\n * Copyright (C) 1995-2022 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n *\n * This interleaved implementation of a CRC makes use of pipelined multiple\n * arithmetic-logic units, commonly found in modern CPU cores. It is due to\n * Kadatch and Jenkins (2010). See doc/crc-doc.1.0.pdf in this distribution.\n */\n\n/* @(#) $Id$ */\n\n/*\n  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore\n  protection on the static variables used to control the first-use generation\n  of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should\n  first call get_crc_table() to initialize the tables before allowing more than\n  one thread to use crc32().\n\n  MAKECRCH can be #defined to write out crc32.h. A main() routine is also\n  produced, so that this one source file can be compiled to an executable.\n */\n\n#ifdef MAKECRCH\n#  include <stdio.h>\n#  ifndef DYNAMIC_CRC_TABLE\n#    define DYNAMIC_CRC_TABLE\n#  endif /* !DYNAMIC_CRC_TABLE */\n#endif /* MAKECRCH */\n\n#include \"zutil.h\"      /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */\n\n// BCH 12 April 2023: adding pragmas to disable spurious warnings\n#pragma GCC diagnostic ignored \"-Wshorten-64-to-32\"\n#pragma clang diagnostic ignored \"-Wshorten-64-to-32\"\n\n /*\n  A CRC of a message is computed on N braids of words in the message, where\n  each word consists of W bytes (4 or 8). If N is 3, for example, then three\n  running sparse CRCs are calculated respectively on each braid, at these\n  indices in the array of words: 0, 3, 6, ..., 1, 4, 7, ..., and 2, 5, 8, ...\n  This is done starting at a word boundary, and continues until as many blocks\n  of N * W bytes as are available have been processed. The results are combined\n  into a single CRC at the end. For this code, N must be in the range 1..6 and\n  W must be 4 or 8. The upper limit on N can be increased if desired by adding\n  more #if blocks, extending the patterns apparent in the code. In addition,\n  crc32.h would need to be regenerated, if the maximum N value is increased.\n\n  N and W are chosen empirically by benchmarking the execution time on a given\n  processor. The choices for N and W below were based on testing on Intel Kaby\n  Lake i7, AMD Ryzen 7, ARM Cortex-A57, Sparc64-VII, PowerPC POWER9, and MIPS64\n  Octeon II processors. The Intel, AMD, and ARM processors were all fastest\n  with N=5, W=8. The Sparc, PowerPC, and MIPS64 were all fastest at N=5, W=4.\n  They were all tested with either gcc or clang, all using the -O3 optimization\n  level. Your mileage may vary.\n */\n\n/* Define N */\n#ifdef Z_TESTN\n#  define N Z_TESTN\n#else\n#  define N 5\n#endif\n#if N < 1 || N > 6\n#  error N must be in 1..6\n#endif\n\n/*\n  z_crc_t must be at least 32 bits. z_word_t must be at least as long as\n  z_crc_t. It is assumed here that z_word_t is either 32 bits or 64 bits, and\n  that bytes are eight bits.\n */\n\n/*\n  Define W and the associated z_word_t type. If W is not defined, then a\n  braided calculation is not used, and the associated tables and code are not\n  compiled.\n */\n#ifdef Z_TESTW\n#  if Z_TESTW-1 != -1\n#    define W Z_TESTW\n#  endif\n#else\n#  ifdef MAKECRCH\n#    define W 8         /* required for MAKECRCH */\n#  else\n#    if defined(__x86_64__) || defined(__aarch64__)\n#      define W 8\n#    else\n#      define W 4\n#    endif\n#  endif\n#endif\n#ifdef W\n#  if W == 8 && defined(Z_U8)\n     typedef Z_U8 z_word_t;\n#  elif defined(Z_U4)\n#    undef W\n#    define W 4\n     typedef Z_U4 z_word_t;\n#  else\n#    undef W\n#  endif\n#endif\n\n/* If available, use the ARM processor CRC32 instruction. */\n#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8\n#  define ARMCRC32\n#endif\n\n#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))\n/*\n  Swap the bytes in a z_word_t to convert between little and big endian. Any\n  self-respecting compiler will optimize this to a single machine byte-swap\n  instruction, if one is available. This assumes that word_t is either 32 bits\n  or 64 bits.\n */\nlocal z_word_t byte_swap(z_word_t word) {\n#  if W == 8\n    return\n        (word & 0xff00000000000000) >> 56 |\n        (word & 0xff000000000000) >> 40 |\n        (word & 0xff0000000000) >> 24 |\n        (word & 0xff00000000) >> 8 |\n        (word & 0xff000000) << 8 |\n        (word & 0xff0000) << 24 |\n        (word & 0xff00) << 40 |\n        (word & 0xff) << 56;\n#  else   /* W == 4 */\n    return\n        (word & 0xff000000) >> 24 |\n        (word & 0xff0000) >> 8 |\n        (word & 0xff00) << 8 |\n        (word & 0xff) << 24;\n#  endif\n}\n#endif\n\n#ifdef DYNAMIC_CRC_TABLE\n/* =========================================================================\n * Table of powers of x for combining CRC-32s, filled in by make_crc_table()\n * below.\n */\n   local z_crc_t FAR x2n_table[32];\n#else\n/* =========================================================================\n * Tables for byte-wise and braided CRC-32 calculations, and a table of powers\n * of x for combining CRC-32s, all made by make_crc_table().\n */\n#  include \"crc32.h\"\n#endif\n\n/* CRC polynomial. */\n#define POLY 0xedb88320         /* p(x) reflected, with x^32 implied */\n\n/*\n  Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,\n  reflected. For speed, this requires that a not be zero.\n */\nlocal z_crc_t multmodp(z_crc_t a, z_crc_t b) {\n    z_crc_t m, p;\n\n    m = (z_crc_t)1 << 31;\n    p = 0;\n    for (;;) {\n        if (a & m) {\n            p ^= b;\n            if ((a & (m - 1)) == 0)\n                break;\n        }\n        m >>= 1;\n        b = b & 1 ? (b >> 1) ^ POLY : b >> 1;\n    }\n    return p;\n}\n\n/*\n  Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been\n  initialized.\n */\nlocal z_crc_t x2nmodp(z_off64_t n, unsigned k) {\n    z_crc_t p;\n\n    p = (z_crc_t)1 << 31;           /* x^0 == 1 */\n    while (n) {\n        if (n & 1)\n            p = multmodp(x2n_table[k & 31], p);\n        n >>= 1;\n        k++;\n    }\n    return p;\n}\n\n#ifdef DYNAMIC_CRC_TABLE\n/* =========================================================================\n * Build the tables for byte-wise and braided CRC-32 calculations, and a table\n * of powers of x for combining CRC-32s.\n */\nlocal z_crc_t FAR crc_table[256];\n#ifdef W\n   local z_word_t FAR crc_big_table[256];\n   local z_crc_t FAR crc_braid_table[W][256];\n   local z_word_t FAR crc_braid_big_table[W][256];\n   local void braid(z_crc_t [][256], z_word_t [][256], int, int);\n#endif\n#ifdef MAKECRCH\n   local void write_table(FILE *, const z_crc_t FAR *, int);\n   local void write_table32hi(FILE *, const z_word_t FAR *, int);\n   local void write_table64(FILE *, const z_word_t FAR *, int);\n#endif /* MAKECRCH */\n\n/*\n  Define a once() function depending on the availability of atomics. If this is\n  compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in\n  multiple threads, and if atomics are not available, then get_crc_table() must\n  be called to initialize the tables and must return before any threads are\n  allowed to compute or combine CRCs.\n */\n\n/* Definition of once functionality. */\ntypedef struct once_s once_t;\n\n/* Check for the availability of atomics. */\n#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \\\n    !defined(__STDC_NO_ATOMICS__)\n\n#include <stdatomic.h>\n\n/* Structure for once(), which must be initialized with ONCE_INIT. */\nstruct once_s {\n    atomic_flag begun;\n    atomic_int done;\n};\n#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}\n\n/*\n  Run the provided init() function exactly once, even if multiple threads\n  invoke once() at the same time. The state must be a once_t initialized with\n  ONCE_INIT.\n */\nlocal void once(once_t *state, void (*init)(void)) {\n    if (!atomic_load(&state->done)) {\n        if (atomic_flag_test_and_set(&state->begun))\n            while (!atomic_load(&state->done))\n                ;\n        else {\n            init();\n            atomic_store(&state->done, 1);\n        }\n    }\n}\n\n#else   /* no atomics */\n\n/* Structure for once(), which must be initialized with ONCE_INIT. */\nstruct once_s {\n    volatile int begun;\n    volatile int done;\n};\n#define ONCE_INIT {0, 0}\n\n/* Test and set. Alas, not atomic, but tries to minimize the period of\n   vulnerability. */\nlocal int test_and_set(int volatile *flag) {\n    int was;\n\n    was = *flag;\n    *flag = 1;\n    return was;\n}\n\n/* Run the provided init() function once. This is not thread-safe. */\nlocal void once(once_t *state, void (*init)(void)) {\n    if (!state->done) {\n        if (test_and_set(&state->begun))\n            while (!state->done)\n                ;\n        else {\n            init();\n            state->done = 1;\n        }\n    }\n}\n\n#endif\n\n/* State for once(). */\nlocal once_t made = ONCE_INIT;\n\n/*\n  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:\n  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.\n\n  Polynomials over GF(2) are represented in binary, one bit per coefficient,\n  with the lowest powers in the most significant bit. Then adding polynomials\n  is just exclusive-or, and multiplying a polynomial by x is a right shift by\n  one. If we call the above polynomial p, and represent a byte as the\n  polynomial q, also with the lowest power in the most significant bit (so the\n  byte 0xb1 is the polynomial x^7+x^3+x^2+1), then the CRC is (q*x^32) mod p,\n  where a mod b means the remainder after dividing a by b.\n\n  This calculation is done using the shift-register method of multiplying and\n  taking the remainder. The register is initialized to zero, and for each\n  incoming bit, x^32 is added mod p to the register if the bit is a one (where\n  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x\n  (which is shifting right by one and adding x^32 mod p if the bit shifted out\n  is a one). We start with the highest power (least significant bit) of q and\n  repeat for all eight bits of q.\n\n  The table is simply the CRC of all possible eight bit values. This is all the\n  information needed to generate CRCs on data a byte at a time for all\n  combinations of CRC register values and incoming bytes.\n */\n\nlocal void make_crc_table(void) {\n    unsigned i, j, n;\n    z_crc_t p;\n\n    /* initialize the CRC of bytes tables */\n    for (i = 0; i < 256; i++) {\n        p = i;\n        for (j = 0; j < 8; j++)\n            p = p & 1 ? (p >> 1) ^ POLY : p >> 1;\n        crc_table[i] = p;\n#ifdef W\n        crc_big_table[i] = byte_swap(p);\n#endif\n    }\n\n    /* initialize the x^2^n mod p(x) table */\n    p = (z_crc_t)1 << 30;         /* x^1 */\n    x2n_table[0] = p;\n    for (n = 1; n < 32; n++)\n        x2n_table[n] = p = multmodp(p, p);\n\n#ifdef W\n    /* initialize the braiding tables -- needs x2n_table[] */\n    braid(crc_braid_table, crc_braid_big_table, N, W);\n#endif\n\n#ifdef MAKECRCH\n    {\n        /*\n          The crc32.h header file contains tables for both 32-bit and 64-bit\n          z_word_t's, and so requires a 64-bit type be available. In that case,\n          z_word_t must be defined to be 64-bits. This code then also generates\n          and writes out the tables for the case that z_word_t is 32 bits.\n         */\n#if !defined(W) || W != 8\n#  error Need a 64-bit integer type in order to generate crc32.h.\n#endif\n        FILE *out;\n        int k, n;\n        z_crc_t ltl[8][256];\n        z_word_t big[8][256];\n\n        out = fopen(\"crc32.h\", \"w\");\n        if (out == NULL) return;\n\n        /* write out little-endian CRC table to crc32.h */\n        fprintf(out,\n            \"/* crc32.h -- tables for rapid CRC calculation\\n\"\n            \" * Generated automatically by crc32.c\\n */\\n\"\n            \"\\n\"\n            \"local const z_crc_t FAR crc_table[] = {\\n\"\n            \"    \");\n        write_table(out, crc_table, 256);\n        fprintf(out,\n            \"};\\n\");\n\n        /* write out big-endian CRC table for 64-bit z_word_t to crc32.h */\n        fprintf(out,\n            \"\\n\"\n            \"#ifdef W\\n\"\n            \"\\n\"\n            \"#if W == 8\\n\"\n            \"\\n\"\n            \"local const z_word_t FAR crc_big_table[] = {\\n\"\n            \"    \");\n        write_table64(out, crc_big_table, 256);\n        fprintf(out,\n            \"};\\n\");\n\n        /* write out big-endian CRC table for 32-bit z_word_t to crc32.h */\n        fprintf(out,\n            \"\\n\"\n            \"#else /* W == 4 */\\n\"\n            \"\\n\"\n            \"local const z_word_t FAR crc_big_table[] = {\\n\"\n            \"    \");\n        write_table32hi(out, crc_big_table, 256);\n        fprintf(out,\n            \"};\\n\"\n            \"\\n\"\n            \"#endif\\n\");\n\n        /* write out braid tables for each value of N */\n        for (n = 1; n <= 6; n++) {\n            fprintf(out,\n            \"\\n\"\n            \"#if N == %d\\n\", n);\n\n            /* compute braid tables for this N and 64-bit word_t */\n            braid(ltl, big, n, 8);\n\n            /* write out braid tables for 64-bit z_word_t to crc32.h */\n            fprintf(out,\n            \"\\n\"\n            \"#if W == 8\\n\"\n            \"\\n\"\n            \"local const z_crc_t FAR crc_braid_table[][256] = {\\n\");\n            for (k = 0; k < 8; k++) {\n                fprintf(out, \"   {\");\n                write_table(out, ltl[k], 256);\n                fprintf(out, \"}%s\", k < 7 ? \",\\n\" : \"\");\n            }\n            fprintf(out,\n            \"};\\n\"\n            \"\\n\"\n            \"local const z_word_t FAR crc_braid_big_table[][256] = {\\n\");\n            for (k = 0; k < 8; k++) {\n                fprintf(out, \"   {\");\n                write_table64(out, big[k], 256);\n                fprintf(out, \"}%s\", k < 7 ? \",\\n\" : \"\");\n            }\n            fprintf(out,\n            \"};\\n\");\n\n            /* compute braid tables for this N and 32-bit word_t */\n            braid(ltl, big, n, 4);\n\n            /* write out braid tables for 32-bit z_word_t to crc32.h */\n            fprintf(out,\n            \"\\n\"\n            \"#else /* W == 4 */\\n\"\n            \"\\n\"\n            \"local const z_crc_t FAR crc_braid_table[][256] = {\\n\");\n            for (k = 0; k < 4; k++) {\n                fprintf(out, \"   {\");\n                write_table(out, ltl[k], 256);\n                fprintf(out, \"}%s\", k < 3 ? \",\\n\" : \"\");\n            }\n            fprintf(out,\n            \"};\\n\"\n            \"\\n\"\n            \"local const z_word_t FAR crc_braid_big_table[][256] = {\\n\");\n            for (k = 0; k < 4; k++) {\n                fprintf(out, \"   {\");\n                write_table32hi(out, big[k], 256);\n                fprintf(out, \"}%s\", k < 3 ? \",\\n\" : \"\");\n            }\n            fprintf(out,\n            \"};\\n\"\n            \"\\n\"\n            \"#endif\\n\"\n            \"\\n\"\n            \"#endif\\n\");\n        }\n        fprintf(out,\n            \"\\n\"\n            \"#endif\\n\");\n\n        /* write out zeros operator table to crc32.h */\n        fprintf(out,\n            \"\\n\"\n            \"local const z_crc_t FAR x2n_table[] = {\\n\"\n            \"    \");\n        write_table(out, x2n_table, 32);\n        fprintf(out,\n            \"};\\n\");\n        fclose(out);\n    }\n#endif /* MAKECRCH */\n}\n\n#ifdef MAKECRCH\n\n/*\n   Write the 32-bit values in table[0..k-1] to out, five per line in\n   hexadecimal separated by commas.\n */\nlocal void write_table(FILE *out, const z_crc_t FAR *table, int k) {\n    int n;\n\n    for (n = 0; n < k; n++)\n        fprintf(out, \"%s0x%08lx%s\", n == 0 || n % 5 ? \"\" : \"    \",\n                (unsigned long)(table[n]),\n                n == k - 1 ? \"\" : (n % 5 == 4 ? \",\\n\" : \", \"));\n}\n\n/*\n   Write the high 32-bits of each value in table[0..k-1] to out, five per line\n   in hexadecimal separated by commas.\n */\nlocal void write_table32hi(FILE *out, const z_word_t FAR *table, int k) {\n    int n;\n\n    for (n = 0; n < k; n++)\n        fprintf(out, \"%s0x%08lx%s\", n == 0 || n % 5 ? \"\" : \"    \",\n                (unsigned long)(table[n] >> 32),\n                n == k - 1 ? \"\" : (n % 5 == 4 ? \",\\n\" : \", \"));\n}\n\n/*\n  Write the 64-bit values in table[0..k-1] to out, three per line in\n  hexadecimal separated by commas. This assumes that if there is a 64-bit\n  type, then there is also a long long integer type, and it is at least 64\n  bits. If not, then the type cast and format string can be adjusted\n  accordingly.\n */\nlocal void write_table64(FILE *out, const z_word_t FAR *table, int k) {\n    int n;\n\n    for (n = 0; n < k; n++)\n        fprintf(out, \"%s0x%016llx%s\", n == 0 || n % 3 ? \"\" : \"    \",\n                (unsigned long long)(table[n]),\n                n == k - 1 ? \"\" : (n % 3 == 2 ? \",\\n\" : \", \"));\n}\n\n/* Actually do the deed. */\nint main(void) {\n    make_crc_table();\n    return 0;\n}\n\n#endif /* MAKECRCH */\n\n#ifdef W\n/*\n  Generate the little and big-endian braid tables for the given n and z_word_t\n  size w. Each array must have room for w blocks of 256 elements.\n */\nlocal void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {\n    int k;\n    z_crc_t i, p, q;\n    for (k = 0; k < w; k++) {\n        p = x2nmodp((n * w + 3 - k) << 3, 0);\n        ltl[k][0] = 0;\n        big[w - 1 - k][0] = 0;\n        for (i = 1; i < 256; i++) {\n            ltl[k][i] = q = multmodp(i << 24, p);\n            big[w - 1 - k][i] = byte_swap(q);\n        }\n    }\n}\n#endif\n\n#endif /* DYNAMIC_CRC_TABLE */\n\n/* =========================================================================\n * This function can be used by asm versions of crc32(), and to force the\n * generation of the CRC tables in a threaded application.\n */\nconst z_crc_t FAR * ZEXPORT get_crc_table(void) {\n#ifdef DYNAMIC_CRC_TABLE\n    once(&made, make_crc_table);\n#endif /* DYNAMIC_CRC_TABLE */\n    return (const z_crc_t FAR *)crc_table;\n}\n\n/* =========================================================================\n * Use ARM machine instructions if available. This will compute the CRC about\n * ten times faster than the braided calculation. This code does not check for\n * the presence of the CRC instruction at run time. __ARM_FEATURE_CRC32 will\n * only be defined if the compilation specifies an ARM processor architecture\n * that has the instructions. For example, compiling with -march=armv8.1-a or\n * -march=armv8-a+crc, or -march=native if the compile machine has the crc32\n * instructions.\n */\n#ifdef ARMCRC32\n\n/*\n   Constants empirically determined to maximize speed. These values are from\n   measurements on a Cortex-A57. Your mileage may vary.\n */\n#define Z_BATCH 3990                /* number of words in a batch */\n#define Z_BATCH_ZEROS 0xa10d3d0c    /* computed from Z_BATCH = 3990 */\n#define Z_BATCH_MIN 800             /* fewest words in a final batch */\n\nunsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,\n                              z_size_t len) {\n    z_crc_t val;\n    z_word_t crc1, crc2;\n    const z_word_t *word;\n    z_word_t val0, val1, val2;\n    z_size_t last, last2, i;\n    z_size_t num;\n\n    /* Return initial CRC, if requested. */\n    if (buf == Z_NULL) return 0;\n\n#ifdef DYNAMIC_CRC_TABLE\n    once(&made, make_crc_table);\n#endif /* DYNAMIC_CRC_TABLE */\n\n    /* Pre-condition the CRC */\n    crc = (~crc) & 0xffffffff;\n\n    /* Compute the CRC up to a word boundary. */\n    while (len && ((z_size_t)buf & 7) != 0) {\n        len--;\n        val = *buf++;\n        __asm__ volatile(\"crc32b %w0, %w0, %w1\" : \"+r\"(crc) : \"r\"(val));\n    }\n\n    /* Prepare to compute the CRC on full 64-bit words word[0..num-1]. */\n    word = (z_word_t const *)buf;\n    num = len >> 3;\n    len &= 7;\n\n    /* Do three interleaved CRCs to realize the throughput of one crc32x\n       instruction per cycle. Each CRC is calculated on Z_BATCH words. The\n       three CRCs are combined into a single CRC after each set of batches. */\n    while (num >= 3 * Z_BATCH) {\n        crc1 = 0;\n        crc2 = 0;\n        for (i = 0; i < Z_BATCH; i++) {\n            val0 = word[i];\n            val1 = word[i + Z_BATCH];\n            val2 = word[i + 2 * Z_BATCH];\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc) : \"r\"(val0));\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc1) : \"r\"(val1));\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc2) : \"r\"(val2));\n        }\n        word += 3 * Z_BATCH;\n        num -= 3 * Z_BATCH;\n        crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc1;\n        crc = multmodp(Z_BATCH_ZEROS, crc) ^ crc2;\n    }\n\n    /* Do one last smaller batch with the remaining words, if there are enough\n       to pay for the combination of CRCs. */\n    last = num / 3;\n    if (last >= Z_BATCH_MIN) {\n        last2 = last << 1;\n        crc1 = 0;\n        crc2 = 0;\n        for (i = 0; i < last; i++) {\n            val0 = word[i];\n            val1 = word[i + last];\n            val2 = word[i + last2];\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc) : \"r\"(val0));\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc1) : \"r\"(val1));\n            __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc2) : \"r\"(val2));\n        }\n        word += 3 * last;\n        num -= 3 * last;\n        val = x2nmodp(last, 6);\n        crc = multmodp(val, crc) ^ crc1;\n        crc = multmodp(val, crc) ^ crc2;\n    }\n\n    /* Compute the CRC on any remaining words. */\n    for (i = 0; i < num; i++) {\n        val0 = word[i];\n        __asm__ volatile(\"crc32x %w0, %w0, %x1\" : \"+r\"(crc) : \"r\"(val0));\n    }\n    word += num;\n\n    /* Complete the CRC on any remaining bytes. */\n    buf = (const unsigned char FAR *)word;\n    while (len) {\n        len--;\n        val = *buf++;\n        __asm__ volatile(\"crc32b %w0, %w0, %w1\" : \"+r\"(crc) : \"r\"(val));\n    }\n\n    /* Return the CRC, post-conditioned. */\n    return crc ^ 0xffffffff;\n}\n\n#else\n\n#ifdef W\n\n/*\n  Return the CRC of the W bytes in the word_t data, taking the\n  least-significant byte of the word as the first byte of data, without any pre\n  or post conditioning. This is used to combine the CRCs of each braid.\n */\nlocal z_crc_t crc_word(z_word_t data) {\n    int k;\n    for (k = 0; k < W; k++)\n        data = (data >> 8) ^ crc_table[data & 0xff];\n    return (z_crc_t)data;\n}\n\nlocal z_word_t crc_word_big(z_word_t data) {\n    int k;\n    for (k = 0; k < W; k++)\n        data = (data << 8) ^\n            crc_big_table[(data >> ((W - 1) << 3)) & 0xff];\n    return data;\n}\n\n#endif\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,\n                              z_size_t len) {\n    /* Return initial CRC, if requested. */\n    if (buf == Z_NULL) return 0;\n\n#ifdef DYNAMIC_CRC_TABLE\n    once(&made, make_crc_table);\n#endif /* DYNAMIC_CRC_TABLE */\n\n    /* Pre-condition the CRC */\n    crc = (~crc) & 0xffffffff;\n\n#ifdef W\n\n    /* If provided enough bytes, do a braided CRC calculation. */\n    if (len >= N * W + W - 1) {\n        z_size_t blks;\n        z_word_t const *words;\n        unsigned endian;\n        int k;\n\n        /* Compute the CRC up to a z_word_t boundary. */\n        while (len && ((z_size_t)buf & (W - 1)) != 0) {\n            len--;\n            crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        }\n\n        /* Compute the CRC on as many N z_word_t blocks as are available. */\n        blks = len / (N * W);\n        len -= blks * N * W;\n        words = (z_word_t const *)buf;\n\n        /* Do endian check at execution time instead of compile time, since ARM\n           processors can change the endianness at execution time. If the\n           compiler knows what the endianness will be, it can optimize out the\n           check and the unused branch. */\n        endian = 1;\n        if (*(unsigned char *)&endian) {\n            /* Little endian. */\n\n            z_crc_t crc0;\n            z_word_t word0;\n#if N > 1\n            z_crc_t crc1;\n            z_word_t word1;\n#if N > 2\n            z_crc_t crc2;\n            z_word_t word2;\n#if N > 3\n            z_crc_t crc3;\n            z_word_t word3;\n#if N > 4\n            z_crc_t crc4;\n            z_word_t word4;\n#if N > 5\n            z_crc_t crc5;\n            z_word_t word5;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n            /* Initialize the CRC for each braid. */\n            crc0 = crc;\n#if N > 1\n            crc1 = 0;\n#if N > 2\n            crc2 = 0;\n#if N > 3\n            crc3 = 0;\n#if N > 4\n            crc4 = 0;\n#if N > 5\n            crc5 = 0;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n            /*\n              Process the first blks-1 blocks, computing the CRCs on each braid\n              independently.\n             */\n            while (--blks) {\n                /* Load the word for each braid into registers. */\n                word0 = crc0 ^ words[0];\n#if N > 1\n                word1 = crc1 ^ words[1];\n#if N > 2\n                word2 = crc2 ^ words[2];\n#if N > 3\n                word3 = crc3 ^ words[3];\n#if N > 4\n                word4 = crc4 ^ words[4];\n#if N > 5\n                word5 = crc5 ^ words[5];\n#endif\n#endif\n#endif\n#endif\n#endif\n                words += N;\n\n                /* Compute and update the CRC for each word. The loop should\n                   get unrolled. */\n                crc0 = crc_braid_table[0][word0 & 0xff];\n#if N > 1\n                crc1 = crc_braid_table[0][word1 & 0xff];\n#if N > 2\n                crc2 = crc_braid_table[0][word2 & 0xff];\n#if N > 3\n                crc3 = crc_braid_table[0][word3 & 0xff];\n#if N > 4\n                crc4 = crc_braid_table[0][word4 & 0xff];\n#if N > 5\n                crc5 = crc_braid_table[0][word5 & 0xff];\n#endif\n#endif\n#endif\n#endif\n#endif\n                for (k = 1; k < W; k++) {\n                    crc0 ^= crc_braid_table[k][(word0 >> (k << 3)) & 0xff];\n#if N > 1\n                    crc1 ^= crc_braid_table[k][(word1 >> (k << 3)) & 0xff];\n#if N > 2\n                    crc2 ^= crc_braid_table[k][(word2 >> (k << 3)) & 0xff];\n#if N > 3\n                    crc3 ^= crc_braid_table[k][(word3 >> (k << 3)) & 0xff];\n#if N > 4\n                    crc4 ^= crc_braid_table[k][(word4 >> (k << 3)) & 0xff];\n#if N > 5\n                    crc5 ^= crc_braid_table[k][(word5 >> (k << 3)) & 0xff];\n#endif\n#endif\n#endif\n#endif\n#endif\n                }\n            }\n\n            /*\n              Process the last block, combining the CRCs of the N braids at the\n              same time.\n             */\n            crc = crc_word(crc0 ^ words[0]);\n#if N > 1\n            crc = crc_word(crc1 ^ words[1] ^ crc);\n#if N > 2\n            crc = crc_word(crc2 ^ words[2] ^ crc);\n#if N > 3\n            crc = crc_word(crc3 ^ words[3] ^ crc);\n#if N > 4\n            crc = crc_word(crc4 ^ words[4] ^ crc);\n#if N > 5\n            crc = crc_word(crc5 ^ words[5] ^ crc);\n#endif\n#endif\n#endif\n#endif\n#endif\n            words += N;\n        }\n        else {\n            /* Big endian. */\n\n            z_word_t crc0, word0, comb;\n#if N > 1\n            z_word_t crc1, word1;\n#if N > 2\n            z_word_t crc2, word2;\n#if N > 3\n            z_word_t crc3, word3;\n#if N > 4\n            z_word_t crc4, word4;\n#if N > 5\n            z_word_t crc5, word5;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n            /* Initialize the CRC for each braid. */\n            crc0 = byte_swap(crc);\n#if N > 1\n            crc1 = 0;\n#if N > 2\n            crc2 = 0;\n#if N > 3\n            crc3 = 0;\n#if N > 4\n            crc4 = 0;\n#if N > 5\n            crc5 = 0;\n#endif\n#endif\n#endif\n#endif\n#endif\n\n            /*\n              Process the first blks-1 blocks, computing the CRCs on each braid\n              independently.\n             */\n            while (--blks) {\n                /* Load the word for each braid into registers. */\n                word0 = crc0 ^ words[0];\n#if N > 1\n                word1 = crc1 ^ words[1];\n#if N > 2\n                word2 = crc2 ^ words[2];\n#if N > 3\n                word3 = crc3 ^ words[3];\n#if N > 4\n                word4 = crc4 ^ words[4];\n#if N > 5\n                word5 = crc5 ^ words[5];\n#endif\n#endif\n#endif\n#endif\n#endif\n                words += N;\n\n                /* Compute and update the CRC for each word. The loop should\n                   get unrolled. */\n                crc0 = crc_braid_big_table[0][word0 & 0xff];\n#if N > 1\n                crc1 = crc_braid_big_table[0][word1 & 0xff];\n#if N > 2\n                crc2 = crc_braid_big_table[0][word2 & 0xff];\n#if N > 3\n                crc3 = crc_braid_big_table[0][word3 & 0xff];\n#if N > 4\n                crc4 = crc_braid_big_table[0][word4 & 0xff];\n#if N > 5\n                crc5 = crc_braid_big_table[0][word5 & 0xff];\n#endif\n#endif\n#endif\n#endif\n#endif\n                for (k = 1; k < W; k++) {\n                    crc0 ^= crc_braid_big_table[k][(word0 >> (k << 3)) & 0xff];\n#if N > 1\n                    crc1 ^= crc_braid_big_table[k][(word1 >> (k << 3)) & 0xff];\n#if N > 2\n                    crc2 ^= crc_braid_big_table[k][(word2 >> (k << 3)) & 0xff];\n#if N > 3\n                    crc3 ^= crc_braid_big_table[k][(word3 >> (k << 3)) & 0xff];\n#if N > 4\n                    crc4 ^= crc_braid_big_table[k][(word4 >> (k << 3)) & 0xff];\n#if N > 5\n                    crc5 ^= crc_braid_big_table[k][(word5 >> (k << 3)) & 0xff];\n#endif\n#endif\n#endif\n#endif\n#endif\n                }\n            }\n\n            /*\n              Process the last block, combining the CRCs of the N braids at the\n              same time.\n             */\n            comb = crc_word_big(crc0 ^ words[0]);\n#if N > 1\n            comb = crc_word_big(crc1 ^ words[1] ^ comb);\n#if N > 2\n            comb = crc_word_big(crc2 ^ words[2] ^ comb);\n#if N > 3\n            comb = crc_word_big(crc3 ^ words[3] ^ comb);\n#if N > 4\n            comb = crc_word_big(crc4 ^ words[4] ^ comb);\n#if N > 5\n            comb = crc_word_big(crc5 ^ words[5] ^ comb);\n#endif\n#endif\n#endif\n#endif\n#endif\n            words += N;\n            crc = byte_swap(comb);\n        }\n\n        /*\n          Update the pointer to the remaining bytes to process.\n         */\n        buf = (unsigned char const *)words;\n    }\n\n#endif /* W */\n\n    /* Complete the computation of the CRC on any remaining bytes. */\n    while (len >= 8) {\n        len -= 8;\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n    }\n    while (len) {\n        len--;\n        crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];\n    }\n\n    /* Return the CRC, post-conditioned. */\n    return crc ^ 0xffffffff;\n}\n\n#endif\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf,\n                            uInt len) {\n    return crc32_z(crc, buf, len);\n}\n\n#if 0\n// BCH 7/18/2024: These don't seem to be used in the way we use zlib, and cause\n// warnings due to missing prototypes; hard to unravel, so I'll just #ifdef out\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {\n#ifdef DYNAMIC_CRC_TABLE\n    once(&made, make_crc_table);\n#endif /* DYNAMIC_CRC_TABLE */\n    return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {\n    return crc32_combine64(crc1, crc2, (z_off64_t)len2);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {\n#ifdef DYNAMIC_CRC_TABLE\n    once(&made, make_crc_table);\n#endif /* DYNAMIC_CRC_TABLE */\n    return x2nmodp(len2, 3);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine_gen(z_off_t len2) {\n    return crc32_combine_gen64((z_off64_t)len2);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {\n    return multmodp(op, crc1) ^ (crc2 & 0xffffffff);\n}\n#endif\n\n"
  },
  {
    "path": "eidos_zlib/crc32.h",
    "content": "/* crc32.h -- tables for rapid CRC calculation\n * Generated automatically by crc32.c\n */\n\nlocal const z_crc_t FAR crc_table[] = {\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,\n    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,\n    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,\n    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,\n    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,\n    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,\n    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,\n    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,\n    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,\n    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,\n    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,\n    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,\n    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,\n    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,\n    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,\n    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,\n    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,\n    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,\n    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,\n    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,\n    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,\n    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,\n    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,\n    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,\n    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,\n    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,\n    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,\n    0x2d02ef8d};\n\n#ifdef W\n\n#if W == 8\n\nlocal const z_word_t FAR crc_big_table[] = {\n    0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000,\n    0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000,\n    0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000,\n    0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000,\n    0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000,\n    0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000,\n    0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000,\n    0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000,\n    0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000,\n    0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000,\n    0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000,\n    0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000,\n    0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000,\n    0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000,\n    0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000,\n    0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000,\n    0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000,\n    0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000,\n    0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000,\n    0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000,\n    0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000,\n    0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000,\n    0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000,\n    0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000,\n    0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000,\n    0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000,\n    0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000,\n    0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000,\n    0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000,\n    0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000,\n    0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000,\n    0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000,\n    0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000,\n    0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000,\n    0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000,\n    0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000,\n    0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000,\n    0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000,\n    0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000,\n    0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000,\n    0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000,\n    0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000,\n    0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000,\n    0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000,\n    0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000,\n    0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000,\n    0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000,\n    0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000,\n    0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000,\n    0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000,\n    0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000,\n    0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000,\n    0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000,\n    0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000,\n    0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000,\n    0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000,\n    0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000,\n    0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000,\n    0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000,\n    0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000,\n    0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000,\n    0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000,\n    0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000,\n    0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000,\n    0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000,\n    0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000,\n    0x8567077200000000, 0x1357000500000000, 0x824abf9500000000,\n    0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000,\n    0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000,\n    0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000,\n    0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000,\n    0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000,\n    0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000,\n    0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000,\n    0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000,\n    0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000,\n    0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000,\n    0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000,\n    0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000,\n    0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000,\n    0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000,\n    0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000,\n    0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000,\n    0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000,\n    0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000,\n    0x8def022d00000000};\n\n#else /* W == 4 */\n\nlocal const z_word_t FAR crc_big_table[] = {\n    0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07,\n    0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79,\n    0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7,\n    0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84,\n    0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13,\n    0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663,\n    0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5,\n    0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5,\n    0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832,\n    0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51,\n    0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf,\n    0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1,\n    0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76,\n    0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606,\n    0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996,\n    0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6,\n    0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c,\n    0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712,\n    0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c,\n    0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4,\n    0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943,\n    0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333,\n    0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe,\n    0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce,\n    0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359,\n    0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a,\n    0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04,\n    0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a,\n    0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0,\n    0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580,\n    0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10,\n    0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060,\n    0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1,\n    0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf,\n    0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31,\n    0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852,\n    0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5,\n    0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5,\n    0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75,\n    0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005,\n    0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292,\n    0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1,\n    0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f,\n    0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111,\n    0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0,\n    0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0,\n    0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40,\n    0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530,\n    0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba,\n    0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4,\n    0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a,\n    0x8def022d};\n\n#endif\n\n#if N == 1\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa,\n    0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b,\n    0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232,\n    0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8,\n    0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e,\n    0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa,\n    0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b,\n    0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f,\n    0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719,\n    0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3,\n    0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa,\n    0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b,\n    0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed,\n    0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89,\n    0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25,\n    0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041,\n    0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c,\n    0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed,\n    0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4,\n    0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758,\n    0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e,\n    0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a,\n    0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed,\n    0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889,\n    0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df,\n    0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544,\n    0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d,\n    0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c,\n    0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1,\n    0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95,\n    0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839,\n    0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d,\n    0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976,\n    0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7,\n    0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be,\n    0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144,\n    0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12,\n    0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376,\n    0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a,\n    0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e,\n    0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278,\n    0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682,\n    0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b,\n    0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a,\n    0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561,\n    0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05,\n    0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9,\n    0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd,\n    0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0,\n    0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61,\n    0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678,\n    0x264b06e6},\n   {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413,\n    0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3,\n    0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d,\n    0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653,\n    0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9,\n    0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e,\n    0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5,\n    0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712,\n    0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8,\n    0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6,\n    0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068,\n    0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8,\n    0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579,\n    0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade,\n    0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37,\n    0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590,\n    0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4,\n    0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64,\n    0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea,\n    0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678,\n    0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282,\n    0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25,\n    0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102,\n    0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5,\n    0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f,\n    0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146,\n    0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8,\n    0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08,\n    0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c,\n    0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b,\n    0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972,\n    0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5,\n    0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d,\n    0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd,\n    0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833,\n    0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d,\n    0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7,\n    0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60,\n    0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2,\n    0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105,\n    0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff,\n    0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1,\n    0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f,\n    0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf,\n    0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617,\n    0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0,\n    0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959,\n    0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe,\n    0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca,\n    0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a,\n    0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184,\n    0x92364a30},\n   {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216,\n    0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8,\n    0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170,\n    0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035,\n    0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6,\n    0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145,\n    0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d,\n    0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e,\n    0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d,\n    0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408,\n    0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0,\n    0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e,\n    0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c,\n    0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf,\n    0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a,\n    0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9,\n    0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1,\n    0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f,\n    0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987,\n    0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4,\n    0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37,\n    0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84,\n    0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca,\n    0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79,\n    0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba,\n    0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d,\n    0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5,\n    0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b,\n    0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643,\n    0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0,\n    0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525,\n    0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496,\n    0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8,\n    0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026,\n    0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e,\n    0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db,\n    0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118,\n    0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab,\n    0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf,\n    0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c,\n    0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf,\n    0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a,\n    0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32,\n    0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec,\n    0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82,\n    0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31,\n    0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4,\n    0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957,\n    0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f,\n    0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1,\n    0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869,\n    0xe4c4abcc},\n   {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0,\n    0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271,\n    0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61,\n    0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52,\n    0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43,\n    0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333,\n    0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64,\n    0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314,\n    0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205,\n    0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136,\n    0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26,\n    0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997,\n    0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849,\n    0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739,\n    0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8,\n    0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98,\n    0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b,\n    0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba,\n    0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa,\n    0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d,\n    0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c,\n    0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc,\n    0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af,\n    0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf,\n    0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce,\n    0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922,\n    0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532,\n    0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183,\n    0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710,\n    0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860,\n    0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1,\n    0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1,\n    0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956,\n    0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7,\n    0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7,\n    0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4,\n    0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5,\n    0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5,\n    0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb,\n    0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb,\n    0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da,\n    0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9,\n    0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9,\n    0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48,\n    0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df,\n    0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af,\n    0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e,\n    0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e,\n    0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d,\n    0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c,\n    0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c,\n    0xca64c78c},\n   {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757,\n    0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a,\n    0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733,\n    0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871,\n    0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70,\n    0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42,\n    0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5,\n    0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,\n    0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086,\n    0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4,\n    0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d,\n    0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0,\n    0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d,\n    0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f,\n    0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859,\n    0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,\n    0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5,\n    0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028,\n    0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891,\n    0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed,\n    0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec,\n    0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde,\n    0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817,\n    0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,\n    0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24,\n    0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e,\n    0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7,\n    0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a,\n    0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4,\n    0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196,\n    0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0,\n    0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,\n    0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52,\n    0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f,\n    0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36,\n    0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174,\n    0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675,\n    0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647,\n    0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d,\n    0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,\n    0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be,\n    0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc,\n    0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645,\n    0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98,\n    0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138,\n    0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a,\n    0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c,\n    0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,\n    0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0,\n    0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d,\n    0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194,\n    0xde0506f1},\n   {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc,\n    0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f,\n    0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a,\n    0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29,\n    0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8,\n    0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023,\n    0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e,\n    0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,\n    0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84,\n    0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7,\n    0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922,\n    0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71,\n    0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0,\n    0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b,\n    0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816,\n    0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,\n    0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c,\n    0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f,\n    0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba,\n    0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579,\n    0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98,\n    0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873,\n    0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e,\n    0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,\n    0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134,\n    0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7,\n    0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732,\n    0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461,\n    0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0,\n    0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b,\n    0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26,\n    0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,\n    0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc,\n    0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef,\n    0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a,\n    0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049,\n    0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8,\n    0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43,\n    0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e,\n    0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,\n    0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24,\n    0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07,\n    0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982,\n    0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1,\n    0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0,\n    0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b,\n    0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576,\n    0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,\n    0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c,\n    0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f,\n    0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda,\n    0xbe9834ed},\n   {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504,\n    0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49,\n    0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e,\n    0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192,\n    0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859,\n    0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c,\n    0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620,\n    0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,\n    0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae,\n    0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2,\n    0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175,\n    0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38,\n    0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05,\n    0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40,\n    0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f,\n    0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,\n    0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850,\n    0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d,\n    0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da,\n    0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864,\n    0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af,\n    0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea,\n    0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74,\n    0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,\n    0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa,\n    0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a,\n    0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd,\n    0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180,\n    0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a,\n    0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f,\n    0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290,\n    0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,\n    0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed,\n    0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0,\n    0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167,\n    0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b,\n    0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0,\n    0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5,\n    0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc,\n    0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,\n    0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842,\n    0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e,\n    0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299,\n    0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4,\n    0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec,\n    0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9,\n    0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66,\n    0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,\n    0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9,\n    0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4,\n    0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33,\n    0x9324fd72},\n   {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,\n    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,\n    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,\n    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,\n    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,\n    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,\n    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,\n    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,\n    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,\n    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,\n    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,\n    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,\n    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,\n    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,\n    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,\n    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,\n    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,\n    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,\n    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,\n    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,\n    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,\n    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,\n    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,\n    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,\n    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,\n    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,\n    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,\n    0x2d02ef8d}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0x9630077700000000, 0x2c610eee00000000,\n    0xba51099900000000, 0x19c46d0700000000, 0x8ff46a7000000000,\n    0x35a563e900000000, 0xa395649e00000000, 0x3288db0e00000000,\n    0xa4b8dc7900000000, 0x1ee9d5e000000000, 0x88d9d29700000000,\n    0x2b4cb60900000000, 0xbd7cb17e00000000, 0x072db8e700000000,\n    0x911dbf9000000000, 0x6410b71d00000000, 0xf220b06a00000000,\n    0x4871b9f300000000, 0xde41be8400000000, 0x7dd4da1a00000000,\n    0xebe4dd6d00000000, 0x51b5d4f400000000, 0xc785d38300000000,\n    0x56986c1300000000, 0xc0a86b6400000000, 0x7af962fd00000000,\n    0xecc9658a00000000, 0x4f5c011400000000, 0xd96c066300000000,\n    0x633d0ffa00000000, 0xf50d088d00000000, 0xc8206e3b00000000,\n    0x5e10694c00000000, 0xe44160d500000000, 0x727167a200000000,\n    0xd1e4033c00000000, 0x47d4044b00000000, 0xfd850dd200000000,\n    0x6bb50aa500000000, 0xfaa8b53500000000, 0x6c98b24200000000,\n    0xd6c9bbdb00000000, 0x40f9bcac00000000, 0xe36cd83200000000,\n    0x755cdf4500000000, 0xcf0dd6dc00000000, 0x593dd1ab00000000,\n    0xac30d92600000000, 0x3a00de5100000000, 0x8051d7c800000000,\n    0x1661d0bf00000000, 0xb5f4b42100000000, 0x23c4b35600000000,\n    0x9995bacf00000000, 0x0fa5bdb800000000, 0x9eb8022800000000,\n    0x0888055f00000000, 0xb2d90cc600000000, 0x24e90bb100000000,\n    0x877c6f2f00000000, 0x114c685800000000, 0xab1d61c100000000,\n    0x3d2d66b600000000, 0x9041dc7600000000, 0x0671db0100000000,\n    0xbc20d29800000000, 0x2a10d5ef00000000, 0x8985b17100000000,\n    0x1fb5b60600000000, 0xa5e4bf9f00000000, 0x33d4b8e800000000,\n    0xa2c9077800000000, 0x34f9000f00000000, 0x8ea8099600000000,\n    0x18980ee100000000, 0xbb0d6a7f00000000, 0x2d3d6d0800000000,\n    0x976c649100000000, 0x015c63e600000000, 0xf4516b6b00000000,\n    0x62616c1c00000000, 0xd830658500000000, 0x4e0062f200000000,\n    0xed95066c00000000, 0x7ba5011b00000000, 0xc1f4088200000000,\n    0x57c40ff500000000, 0xc6d9b06500000000, 0x50e9b71200000000,\n    0xeab8be8b00000000, 0x7c88b9fc00000000, 0xdf1ddd6200000000,\n    0x492dda1500000000, 0xf37cd38c00000000, 0x654cd4fb00000000,\n    0x5861b24d00000000, 0xce51b53a00000000, 0x7400bca300000000,\n    0xe230bbd400000000, 0x41a5df4a00000000, 0xd795d83d00000000,\n    0x6dc4d1a400000000, 0xfbf4d6d300000000, 0x6ae9694300000000,\n    0xfcd96e3400000000, 0x468867ad00000000, 0xd0b860da00000000,\n    0x732d044400000000, 0xe51d033300000000, 0x5f4c0aaa00000000,\n    0xc97c0ddd00000000, 0x3c71055000000000, 0xaa41022700000000,\n    0x10100bbe00000000, 0x86200cc900000000, 0x25b5685700000000,\n    0xb3856f2000000000, 0x09d466b900000000, 0x9fe461ce00000000,\n    0x0ef9de5e00000000, 0x98c9d92900000000, 0x2298d0b000000000,\n    0xb4a8d7c700000000, 0x173db35900000000, 0x810db42e00000000,\n    0x3b5cbdb700000000, 0xad6cbac000000000, 0x2083b8ed00000000,\n    0xb6b3bf9a00000000, 0x0ce2b60300000000, 0x9ad2b17400000000,\n    0x3947d5ea00000000, 0xaf77d29d00000000, 0x1526db0400000000,\n    0x8316dc7300000000, 0x120b63e300000000, 0x843b649400000000,\n    0x3e6a6d0d00000000, 0xa85a6a7a00000000, 0x0bcf0ee400000000,\n    0x9dff099300000000, 0x27ae000a00000000, 0xb19e077d00000000,\n    0x44930ff000000000, 0xd2a3088700000000, 0x68f2011e00000000,\n    0xfec2066900000000, 0x5d5762f700000000, 0xcb67658000000000,\n    0x71366c1900000000, 0xe7066b6e00000000, 0x761bd4fe00000000,\n    0xe02bd38900000000, 0x5a7ada1000000000, 0xcc4add6700000000,\n    0x6fdfb9f900000000, 0xf9efbe8e00000000, 0x43beb71700000000,\n    0xd58eb06000000000, 0xe8a3d6d600000000, 0x7e93d1a100000000,\n    0xc4c2d83800000000, 0x52f2df4f00000000, 0xf167bbd100000000,\n    0x6757bca600000000, 0xdd06b53f00000000, 0x4b36b24800000000,\n    0xda2b0dd800000000, 0x4c1b0aaf00000000, 0xf64a033600000000,\n    0x607a044100000000, 0xc3ef60df00000000, 0x55df67a800000000,\n    0xef8e6e3100000000, 0x79be694600000000, 0x8cb361cb00000000,\n    0x1a8366bc00000000, 0xa0d26f2500000000, 0x36e2685200000000,\n    0x95770ccc00000000, 0x03470bbb00000000, 0xb916022200000000,\n    0x2f26055500000000, 0xbe3bbac500000000, 0x280bbdb200000000,\n    0x925ab42b00000000, 0x046ab35c00000000, 0xa7ffd7c200000000,\n    0x31cfd0b500000000, 0x8b9ed92c00000000, 0x1daede5b00000000,\n    0xb0c2649b00000000, 0x26f263ec00000000, 0x9ca36a7500000000,\n    0x0a936d0200000000, 0xa906099c00000000, 0x3f360eeb00000000,\n    0x8567077200000000, 0x1357000500000000, 0x824abf9500000000,\n    0x147ab8e200000000, 0xae2bb17b00000000, 0x381bb60c00000000,\n    0x9b8ed29200000000, 0x0dbed5e500000000, 0xb7efdc7c00000000,\n    0x21dfdb0b00000000, 0xd4d2d38600000000, 0x42e2d4f100000000,\n    0xf8b3dd6800000000, 0x6e83da1f00000000, 0xcd16be8100000000,\n    0x5b26b9f600000000, 0xe177b06f00000000, 0x7747b71800000000,\n    0xe65a088800000000, 0x706a0fff00000000, 0xca3b066600000000,\n    0x5c0b011100000000, 0xff9e658f00000000, 0x69ae62f800000000,\n    0xd3ff6b6100000000, 0x45cf6c1600000000, 0x78e20aa000000000,\n    0xeed20dd700000000, 0x5483044e00000000, 0xc2b3033900000000,\n    0x612667a700000000, 0xf71660d000000000, 0x4d47694900000000,\n    0xdb776e3e00000000, 0x4a6ad1ae00000000, 0xdc5ad6d900000000,\n    0x660bdf4000000000, 0xf03bd83700000000, 0x53aebca900000000,\n    0xc59ebbde00000000, 0x7fcfb24700000000, 0xe9ffb53000000000,\n    0x1cf2bdbd00000000, 0x8ac2baca00000000, 0x3093b35300000000,\n    0xa6a3b42400000000, 0x0536d0ba00000000, 0x9306d7cd00000000,\n    0x2957de5400000000, 0xbf67d92300000000, 0x2e7a66b300000000,\n    0xb84a61c400000000, 0x021b685d00000000, 0x942b6f2a00000000,\n    0x37be0bb400000000, 0xa18e0cc300000000, 0x1bdf055a00000000,\n    0x8def022d00000000},\n   {0x0000000000000000, 0x41311b1900000000, 0x8262363200000000,\n    0xc3532d2b00000000, 0x04c56c6400000000, 0x45f4777d00000000,\n    0x86a75a5600000000, 0xc796414f00000000, 0x088ad9c800000000,\n    0x49bbc2d100000000, 0x8ae8effa00000000, 0xcbd9f4e300000000,\n    0x0c4fb5ac00000000, 0x4d7eaeb500000000, 0x8e2d839e00000000,\n    0xcf1c988700000000, 0x5112c24a00000000, 0x1023d95300000000,\n    0xd370f47800000000, 0x9241ef6100000000, 0x55d7ae2e00000000,\n    0x14e6b53700000000, 0xd7b5981c00000000, 0x9684830500000000,\n    0x59981b8200000000, 0x18a9009b00000000, 0xdbfa2db000000000,\n    0x9acb36a900000000, 0x5d5d77e600000000, 0x1c6c6cff00000000,\n    0xdf3f41d400000000, 0x9e0e5acd00000000, 0xa224849500000000,\n    0xe3159f8c00000000, 0x2046b2a700000000, 0x6177a9be00000000,\n    0xa6e1e8f100000000, 0xe7d0f3e800000000, 0x2483dec300000000,\n    0x65b2c5da00000000, 0xaaae5d5d00000000, 0xeb9f464400000000,\n    0x28cc6b6f00000000, 0x69fd707600000000, 0xae6b313900000000,\n    0xef5a2a2000000000, 0x2c09070b00000000, 0x6d381c1200000000,\n    0xf33646df00000000, 0xb2075dc600000000, 0x715470ed00000000,\n    0x30656bf400000000, 0xf7f32abb00000000, 0xb6c231a200000000,\n    0x75911c8900000000, 0x34a0079000000000, 0xfbbc9f1700000000,\n    0xba8d840e00000000, 0x79dea92500000000, 0x38efb23c00000000,\n    0xff79f37300000000, 0xbe48e86a00000000, 0x7d1bc54100000000,\n    0x3c2ade5800000000, 0x054f79f000000000, 0x447e62e900000000,\n    0x872d4fc200000000, 0xc61c54db00000000, 0x018a159400000000,\n    0x40bb0e8d00000000, 0x83e823a600000000, 0xc2d938bf00000000,\n    0x0dc5a03800000000, 0x4cf4bb2100000000, 0x8fa7960a00000000,\n    0xce968d1300000000, 0x0900cc5c00000000, 0x4831d74500000000,\n    0x8b62fa6e00000000, 0xca53e17700000000, 0x545dbbba00000000,\n    0x156ca0a300000000, 0xd63f8d8800000000, 0x970e969100000000,\n    0x5098d7de00000000, 0x11a9ccc700000000, 0xd2fae1ec00000000,\n    0x93cbfaf500000000, 0x5cd7627200000000, 0x1de6796b00000000,\n    0xdeb5544000000000, 0x9f844f5900000000, 0x58120e1600000000,\n    0x1923150f00000000, 0xda70382400000000, 0x9b41233d00000000,\n    0xa76bfd6500000000, 0xe65ae67c00000000, 0x2509cb5700000000,\n    0x6438d04e00000000, 0xa3ae910100000000, 0xe29f8a1800000000,\n    0x21cca73300000000, 0x60fdbc2a00000000, 0xafe124ad00000000,\n    0xeed03fb400000000, 0x2d83129f00000000, 0x6cb2098600000000,\n    0xab2448c900000000, 0xea1553d000000000, 0x29467efb00000000,\n    0x687765e200000000, 0xf6793f2f00000000, 0xb748243600000000,\n    0x741b091d00000000, 0x352a120400000000, 0xf2bc534b00000000,\n    0xb38d485200000000, 0x70de657900000000, 0x31ef7e6000000000,\n    0xfef3e6e700000000, 0xbfc2fdfe00000000, 0x7c91d0d500000000,\n    0x3da0cbcc00000000, 0xfa368a8300000000, 0xbb07919a00000000,\n    0x7854bcb100000000, 0x3965a7a800000000, 0x4b98833b00000000,\n    0x0aa9982200000000, 0xc9fab50900000000, 0x88cbae1000000000,\n    0x4f5def5f00000000, 0x0e6cf44600000000, 0xcd3fd96d00000000,\n    0x8c0ec27400000000, 0x43125af300000000, 0x022341ea00000000,\n    0xc1706cc100000000, 0x804177d800000000, 0x47d7369700000000,\n    0x06e62d8e00000000, 0xc5b500a500000000, 0x84841bbc00000000,\n    0x1a8a417100000000, 0x5bbb5a6800000000, 0x98e8774300000000,\n    0xd9d96c5a00000000, 0x1e4f2d1500000000, 0x5f7e360c00000000,\n    0x9c2d1b2700000000, 0xdd1c003e00000000, 0x120098b900000000,\n    0x533183a000000000, 0x9062ae8b00000000, 0xd153b59200000000,\n    0x16c5f4dd00000000, 0x57f4efc400000000, 0x94a7c2ef00000000,\n    0xd596d9f600000000, 0xe9bc07ae00000000, 0xa88d1cb700000000,\n    0x6bde319c00000000, 0x2aef2a8500000000, 0xed796bca00000000,\n    0xac4870d300000000, 0x6f1b5df800000000, 0x2e2a46e100000000,\n    0xe136de6600000000, 0xa007c57f00000000, 0x6354e85400000000,\n    0x2265f34d00000000, 0xe5f3b20200000000, 0xa4c2a91b00000000,\n    0x6791843000000000, 0x26a09f2900000000, 0xb8aec5e400000000,\n    0xf99fdefd00000000, 0x3accf3d600000000, 0x7bfde8cf00000000,\n    0xbc6ba98000000000, 0xfd5ab29900000000, 0x3e099fb200000000,\n    0x7f3884ab00000000, 0xb0241c2c00000000, 0xf115073500000000,\n    0x32462a1e00000000, 0x7377310700000000, 0xb4e1704800000000,\n    0xf5d06b5100000000, 0x3683467a00000000, 0x77b25d6300000000,\n    0x4ed7facb00000000, 0x0fe6e1d200000000, 0xccb5ccf900000000,\n    0x8d84d7e000000000, 0x4a1296af00000000, 0x0b238db600000000,\n    0xc870a09d00000000, 0x8941bb8400000000, 0x465d230300000000,\n    0x076c381a00000000, 0xc43f153100000000, 0x850e0e2800000000,\n    0x42984f6700000000, 0x03a9547e00000000, 0xc0fa795500000000,\n    0x81cb624c00000000, 0x1fc5388100000000, 0x5ef4239800000000,\n    0x9da70eb300000000, 0xdc9615aa00000000, 0x1b0054e500000000,\n    0x5a314ffc00000000, 0x996262d700000000, 0xd85379ce00000000,\n    0x174fe14900000000, 0x567efa5000000000, 0x952dd77b00000000,\n    0xd41ccc6200000000, 0x138a8d2d00000000, 0x52bb963400000000,\n    0x91e8bb1f00000000, 0xd0d9a00600000000, 0xecf37e5e00000000,\n    0xadc2654700000000, 0x6e91486c00000000, 0x2fa0537500000000,\n    0xe836123a00000000, 0xa907092300000000, 0x6a54240800000000,\n    0x2b653f1100000000, 0xe479a79600000000, 0xa548bc8f00000000,\n    0x661b91a400000000, 0x272a8abd00000000, 0xe0bccbf200000000,\n    0xa18dd0eb00000000, 0x62defdc000000000, 0x23efe6d900000000,\n    0xbde1bc1400000000, 0xfcd0a70d00000000, 0x3f838a2600000000,\n    0x7eb2913f00000000, 0xb924d07000000000, 0xf815cb6900000000,\n    0x3b46e64200000000, 0x7a77fd5b00000000, 0xb56b65dc00000000,\n    0xf45a7ec500000000, 0x370953ee00000000, 0x763848f700000000,\n    0xb1ae09b800000000, 0xf09f12a100000000, 0x33cc3f8a00000000,\n    0x72fd249300000000},\n   {0x0000000000000000, 0x376ac20100000000, 0x6ed4840300000000,\n    0x59be460200000000, 0xdca8090700000000, 0xebc2cb0600000000,\n    0xb27c8d0400000000, 0x85164f0500000000, 0xb851130e00000000,\n    0x8f3bd10f00000000, 0xd685970d00000000, 0xe1ef550c00000000,\n    0x64f91a0900000000, 0x5393d80800000000, 0x0a2d9e0a00000000,\n    0x3d475c0b00000000, 0x70a3261c00000000, 0x47c9e41d00000000,\n    0x1e77a21f00000000, 0x291d601e00000000, 0xac0b2f1b00000000,\n    0x9b61ed1a00000000, 0xc2dfab1800000000, 0xf5b5691900000000,\n    0xc8f2351200000000, 0xff98f71300000000, 0xa626b11100000000,\n    0x914c731000000000, 0x145a3c1500000000, 0x2330fe1400000000,\n    0x7a8eb81600000000, 0x4de47a1700000000, 0xe0464d3800000000,\n    0xd72c8f3900000000, 0x8e92c93b00000000, 0xb9f80b3a00000000,\n    0x3cee443f00000000, 0x0b84863e00000000, 0x523ac03c00000000,\n    0x6550023d00000000, 0x58175e3600000000, 0x6f7d9c3700000000,\n    0x36c3da3500000000, 0x01a9183400000000, 0x84bf573100000000,\n    0xb3d5953000000000, 0xea6bd33200000000, 0xdd01113300000000,\n    0x90e56b2400000000, 0xa78fa92500000000, 0xfe31ef2700000000,\n    0xc95b2d2600000000, 0x4c4d622300000000, 0x7b27a02200000000,\n    0x2299e62000000000, 0x15f3242100000000, 0x28b4782a00000000,\n    0x1fdeba2b00000000, 0x4660fc2900000000, 0x710a3e2800000000,\n    0xf41c712d00000000, 0xc376b32c00000000, 0x9ac8f52e00000000,\n    0xada2372f00000000, 0xc08d9a7000000000, 0xf7e7587100000000,\n    0xae591e7300000000, 0x9933dc7200000000, 0x1c25937700000000,\n    0x2b4f517600000000, 0x72f1177400000000, 0x459bd57500000000,\n    0x78dc897e00000000, 0x4fb64b7f00000000, 0x16080d7d00000000,\n    0x2162cf7c00000000, 0xa474807900000000, 0x931e427800000000,\n    0xcaa0047a00000000, 0xfdcac67b00000000, 0xb02ebc6c00000000,\n    0x87447e6d00000000, 0xdefa386f00000000, 0xe990fa6e00000000,\n    0x6c86b56b00000000, 0x5bec776a00000000, 0x0252316800000000,\n    0x3538f36900000000, 0x087faf6200000000, 0x3f156d6300000000,\n    0x66ab2b6100000000, 0x51c1e96000000000, 0xd4d7a66500000000,\n    0xe3bd646400000000, 0xba03226600000000, 0x8d69e06700000000,\n    0x20cbd74800000000, 0x17a1154900000000, 0x4e1f534b00000000,\n    0x7975914a00000000, 0xfc63de4f00000000, 0xcb091c4e00000000,\n    0x92b75a4c00000000, 0xa5dd984d00000000, 0x989ac44600000000,\n    0xaff0064700000000, 0xf64e404500000000, 0xc124824400000000,\n    0x4432cd4100000000, 0x73580f4000000000, 0x2ae6494200000000,\n    0x1d8c8b4300000000, 0x5068f15400000000, 0x6702335500000000,\n    0x3ebc755700000000, 0x09d6b75600000000, 0x8cc0f85300000000,\n    0xbbaa3a5200000000, 0xe2147c5000000000, 0xd57ebe5100000000,\n    0xe839e25a00000000, 0xdf53205b00000000, 0x86ed665900000000,\n    0xb187a45800000000, 0x3491eb5d00000000, 0x03fb295c00000000,\n    0x5a456f5e00000000, 0x6d2fad5f00000000, 0x801b35e100000000,\n    0xb771f7e000000000, 0xeecfb1e200000000, 0xd9a573e300000000,\n    0x5cb33ce600000000, 0x6bd9fee700000000, 0x3267b8e500000000,\n    0x050d7ae400000000, 0x384a26ef00000000, 0x0f20e4ee00000000,\n    0x569ea2ec00000000, 0x61f460ed00000000, 0xe4e22fe800000000,\n    0xd388ede900000000, 0x8a36abeb00000000, 0xbd5c69ea00000000,\n    0xf0b813fd00000000, 0xc7d2d1fc00000000, 0x9e6c97fe00000000,\n    0xa90655ff00000000, 0x2c101afa00000000, 0x1b7ad8fb00000000,\n    0x42c49ef900000000, 0x75ae5cf800000000, 0x48e900f300000000,\n    0x7f83c2f200000000, 0x263d84f000000000, 0x115746f100000000,\n    0x944109f400000000, 0xa32bcbf500000000, 0xfa958df700000000,\n    0xcdff4ff600000000, 0x605d78d900000000, 0x5737bad800000000,\n    0x0e89fcda00000000, 0x39e33edb00000000, 0xbcf571de00000000,\n    0x8b9fb3df00000000, 0xd221f5dd00000000, 0xe54b37dc00000000,\n    0xd80c6bd700000000, 0xef66a9d600000000, 0xb6d8efd400000000,\n    0x81b22dd500000000, 0x04a462d000000000, 0x33cea0d100000000,\n    0x6a70e6d300000000, 0x5d1a24d200000000, 0x10fe5ec500000000,\n    0x27949cc400000000, 0x7e2adac600000000, 0x494018c700000000,\n    0xcc5657c200000000, 0xfb3c95c300000000, 0xa282d3c100000000,\n    0x95e811c000000000, 0xa8af4dcb00000000, 0x9fc58fca00000000,\n    0xc67bc9c800000000, 0xf1110bc900000000, 0x740744cc00000000,\n    0x436d86cd00000000, 0x1ad3c0cf00000000, 0x2db902ce00000000,\n    0x4096af9100000000, 0x77fc6d9000000000, 0x2e422b9200000000,\n    0x1928e99300000000, 0x9c3ea69600000000, 0xab54649700000000,\n    0xf2ea229500000000, 0xc580e09400000000, 0xf8c7bc9f00000000,\n    0xcfad7e9e00000000, 0x9613389c00000000, 0xa179fa9d00000000,\n    0x246fb59800000000, 0x1305779900000000, 0x4abb319b00000000,\n    0x7dd1f39a00000000, 0x3035898d00000000, 0x075f4b8c00000000,\n    0x5ee10d8e00000000, 0x698bcf8f00000000, 0xec9d808a00000000,\n    0xdbf7428b00000000, 0x8249048900000000, 0xb523c68800000000,\n    0x88649a8300000000, 0xbf0e588200000000, 0xe6b01e8000000000,\n    0xd1dadc8100000000, 0x54cc938400000000, 0x63a6518500000000,\n    0x3a18178700000000, 0x0d72d58600000000, 0xa0d0e2a900000000,\n    0x97ba20a800000000, 0xce0466aa00000000, 0xf96ea4ab00000000,\n    0x7c78ebae00000000, 0x4b1229af00000000, 0x12ac6fad00000000,\n    0x25c6adac00000000, 0x1881f1a700000000, 0x2feb33a600000000,\n    0x765575a400000000, 0x413fb7a500000000, 0xc429f8a000000000,\n    0xf3433aa100000000, 0xaafd7ca300000000, 0x9d97bea200000000,\n    0xd073c4b500000000, 0xe71906b400000000, 0xbea740b600000000,\n    0x89cd82b700000000, 0x0cdbcdb200000000, 0x3bb10fb300000000,\n    0x620f49b100000000, 0x55658bb000000000, 0x6822d7bb00000000,\n    0x5f4815ba00000000, 0x06f653b800000000, 0x319c91b900000000,\n    0xb48adebc00000000, 0x83e01cbd00000000, 0xda5e5abf00000000,\n    0xed3498be00000000},\n   {0x0000000000000000, 0x6567bcb800000000, 0x8bc809aa00000000,\n    0xeeafb51200000000, 0x5797628f00000000, 0x32f0de3700000000,\n    0xdc5f6b2500000000, 0xb938d79d00000000, 0xef28b4c500000000,\n    0x8a4f087d00000000, 0x64e0bd6f00000000, 0x018701d700000000,\n    0xb8bfd64a00000000, 0xddd86af200000000, 0x3377dfe000000000,\n    0x5610635800000000, 0x9f57195000000000, 0xfa30a5e800000000,\n    0x149f10fa00000000, 0x71f8ac4200000000, 0xc8c07bdf00000000,\n    0xada7c76700000000, 0x4308727500000000, 0x266fcecd00000000,\n    0x707fad9500000000, 0x1518112d00000000, 0xfbb7a43f00000000,\n    0x9ed0188700000000, 0x27e8cf1a00000000, 0x428f73a200000000,\n    0xac20c6b000000000, 0xc9477a0800000000, 0x3eaf32a000000000,\n    0x5bc88e1800000000, 0xb5673b0a00000000, 0xd00087b200000000,\n    0x6938502f00000000, 0x0c5fec9700000000, 0xe2f0598500000000,\n    0x8797e53d00000000, 0xd187866500000000, 0xb4e03add00000000,\n    0x5a4f8fcf00000000, 0x3f28337700000000, 0x8610e4ea00000000,\n    0xe377585200000000, 0x0dd8ed4000000000, 0x68bf51f800000000,\n    0xa1f82bf000000000, 0xc49f974800000000, 0x2a30225a00000000,\n    0x4f579ee200000000, 0xf66f497f00000000, 0x9308f5c700000000,\n    0x7da740d500000000, 0x18c0fc6d00000000, 0x4ed09f3500000000,\n    0x2bb7238d00000000, 0xc518969f00000000, 0xa07f2a2700000000,\n    0x1947fdba00000000, 0x7c20410200000000, 0x928ff41000000000,\n    0xf7e848a800000000, 0x3d58149b00000000, 0x583fa82300000000,\n    0xb6901d3100000000, 0xd3f7a18900000000, 0x6acf761400000000,\n    0x0fa8caac00000000, 0xe1077fbe00000000, 0x8460c30600000000,\n    0xd270a05e00000000, 0xb7171ce600000000, 0x59b8a9f400000000,\n    0x3cdf154c00000000, 0x85e7c2d100000000, 0xe0807e6900000000,\n    0x0e2fcb7b00000000, 0x6b4877c300000000, 0xa20f0dcb00000000,\n    0xc768b17300000000, 0x29c7046100000000, 0x4ca0b8d900000000,\n    0xf5986f4400000000, 0x90ffd3fc00000000, 0x7e5066ee00000000,\n    0x1b37da5600000000, 0x4d27b90e00000000, 0x284005b600000000,\n    0xc6efb0a400000000, 0xa3880c1c00000000, 0x1ab0db8100000000,\n    0x7fd7673900000000, 0x9178d22b00000000, 0xf41f6e9300000000,\n    0x03f7263b00000000, 0x66909a8300000000, 0x883f2f9100000000,\n    0xed58932900000000, 0x546044b400000000, 0x3107f80c00000000,\n    0xdfa84d1e00000000, 0xbacff1a600000000, 0xecdf92fe00000000,\n    0x89b82e4600000000, 0x67179b5400000000, 0x027027ec00000000,\n    0xbb48f07100000000, 0xde2f4cc900000000, 0x3080f9db00000000,\n    0x55e7456300000000, 0x9ca03f6b00000000, 0xf9c783d300000000,\n    0x176836c100000000, 0x720f8a7900000000, 0xcb375de400000000,\n    0xae50e15c00000000, 0x40ff544e00000000, 0x2598e8f600000000,\n    0x73888bae00000000, 0x16ef371600000000, 0xf840820400000000,\n    0x9d273ebc00000000, 0x241fe92100000000, 0x4178559900000000,\n    0xafd7e08b00000000, 0xcab05c3300000000, 0x3bb659ed00000000,\n    0x5ed1e55500000000, 0xb07e504700000000, 0xd519ecff00000000,\n    0x6c213b6200000000, 0x094687da00000000, 0xe7e932c800000000,\n    0x828e8e7000000000, 0xd49eed2800000000, 0xb1f9519000000000,\n    0x5f56e48200000000, 0x3a31583a00000000, 0x83098fa700000000,\n    0xe66e331f00000000, 0x08c1860d00000000, 0x6da63ab500000000,\n    0xa4e140bd00000000, 0xc186fc0500000000, 0x2f29491700000000,\n    0x4a4ef5af00000000, 0xf376223200000000, 0x96119e8a00000000,\n    0x78be2b9800000000, 0x1dd9972000000000, 0x4bc9f47800000000,\n    0x2eae48c000000000, 0xc001fdd200000000, 0xa566416a00000000,\n    0x1c5e96f700000000, 0x79392a4f00000000, 0x97969f5d00000000,\n    0xf2f123e500000000, 0x05196b4d00000000, 0x607ed7f500000000,\n    0x8ed162e700000000, 0xebb6de5f00000000, 0x528e09c200000000,\n    0x37e9b57a00000000, 0xd946006800000000, 0xbc21bcd000000000,\n    0xea31df8800000000, 0x8f56633000000000, 0x61f9d62200000000,\n    0x049e6a9a00000000, 0xbda6bd0700000000, 0xd8c101bf00000000,\n    0x366eb4ad00000000, 0x5309081500000000, 0x9a4e721d00000000,\n    0xff29cea500000000, 0x11867bb700000000, 0x74e1c70f00000000,\n    0xcdd9109200000000, 0xa8beac2a00000000, 0x4611193800000000,\n    0x2376a58000000000, 0x7566c6d800000000, 0x10017a6000000000,\n    0xfeaecf7200000000, 0x9bc973ca00000000, 0x22f1a45700000000,\n    0x479618ef00000000, 0xa939adfd00000000, 0xcc5e114500000000,\n    0x06ee4d7600000000, 0x6389f1ce00000000, 0x8d2644dc00000000,\n    0xe841f86400000000, 0x51792ff900000000, 0x341e934100000000,\n    0xdab1265300000000, 0xbfd69aeb00000000, 0xe9c6f9b300000000,\n    0x8ca1450b00000000, 0x620ef01900000000, 0x07694ca100000000,\n    0xbe519b3c00000000, 0xdb36278400000000, 0x3599929600000000,\n    0x50fe2e2e00000000, 0x99b9542600000000, 0xfcdee89e00000000,\n    0x12715d8c00000000, 0x7716e13400000000, 0xce2e36a900000000,\n    0xab498a1100000000, 0x45e63f0300000000, 0x208183bb00000000,\n    0x7691e0e300000000, 0x13f65c5b00000000, 0xfd59e94900000000,\n    0x983e55f100000000, 0x2106826c00000000, 0x44613ed400000000,\n    0xaace8bc600000000, 0xcfa9377e00000000, 0x38417fd600000000,\n    0x5d26c36e00000000, 0xb389767c00000000, 0xd6eecac400000000,\n    0x6fd61d5900000000, 0x0ab1a1e100000000, 0xe41e14f300000000,\n    0x8179a84b00000000, 0xd769cb1300000000, 0xb20e77ab00000000,\n    0x5ca1c2b900000000, 0x39c67e0100000000, 0x80fea99c00000000,\n    0xe599152400000000, 0x0b36a03600000000, 0x6e511c8e00000000,\n    0xa716668600000000, 0xc271da3e00000000, 0x2cde6f2c00000000,\n    0x49b9d39400000000, 0xf081040900000000, 0x95e6b8b100000000,\n    0x7b490da300000000, 0x1e2eb11b00000000, 0x483ed24300000000,\n    0x2d596efb00000000, 0xc3f6dbe900000000, 0xa691675100000000,\n    0x1fa9b0cc00000000, 0x7ace0c7400000000, 0x9461b96600000000,\n    0xf10605de00000000},\n   {0x0000000000000000, 0xb029603d00000000, 0x6053c07a00000000,\n    0xd07aa04700000000, 0xc0a680f500000000, 0x708fe0c800000000,\n    0xa0f5408f00000000, 0x10dc20b200000000, 0xc14b703000000000,\n    0x7162100d00000000, 0xa118b04a00000000, 0x1131d07700000000,\n    0x01edf0c500000000, 0xb1c490f800000000, 0x61be30bf00000000,\n    0xd197508200000000, 0x8297e06000000000, 0x32be805d00000000,\n    0xe2c4201a00000000, 0x52ed402700000000, 0x4231609500000000,\n    0xf21800a800000000, 0x2262a0ef00000000, 0x924bc0d200000000,\n    0x43dc905000000000, 0xf3f5f06d00000000, 0x238f502a00000000,\n    0x93a6301700000000, 0x837a10a500000000, 0x3353709800000000,\n    0xe329d0df00000000, 0x5300b0e200000000, 0x042fc1c100000000,\n    0xb406a1fc00000000, 0x647c01bb00000000, 0xd455618600000000,\n    0xc489413400000000, 0x74a0210900000000, 0xa4da814e00000000,\n    0x14f3e17300000000, 0xc564b1f100000000, 0x754dd1cc00000000,\n    0xa537718b00000000, 0x151e11b600000000, 0x05c2310400000000,\n    0xb5eb513900000000, 0x6591f17e00000000, 0xd5b8914300000000,\n    0x86b821a100000000, 0x3691419c00000000, 0xe6ebe1db00000000,\n    0x56c281e600000000, 0x461ea15400000000, 0xf637c16900000000,\n    0x264d612e00000000, 0x9664011300000000, 0x47f3519100000000,\n    0xf7da31ac00000000, 0x27a091eb00000000, 0x9789f1d600000000,\n    0x8755d16400000000, 0x377cb15900000000, 0xe706111e00000000,\n    0x572f712300000000, 0x4958f35800000000, 0xf971936500000000,\n    0x290b332200000000, 0x9922531f00000000, 0x89fe73ad00000000,\n    0x39d7139000000000, 0xe9adb3d700000000, 0x5984d3ea00000000,\n    0x8813836800000000, 0x383ae35500000000, 0xe840431200000000,\n    0x5869232f00000000, 0x48b5039d00000000, 0xf89c63a000000000,\n    0x28e6c3e700000000, 0x98cfa3da00000000, 0xcbcf133800000000,\n    0x7be6730500000000, 0xab9cd34200000000, 0x1bb5b37f00000000,\n    0x0b6993cd00000000, 0xbb40f3f000000000, 0x6b3a53b700000000,\n    0xdb13338a00000000, 0x0a84630800000000, 0xbaad033500000000,\n    0x6ad7a37200000000, 0xdafec34f00000000, 0xca22e3fd00000000,\n    0x7a0b83c000000000, 0xaa71238700000000, 0x1a5843ba00000000,\n    0x4d77329900000000, 0xfd5e52a400000000, 0x2d24f2e300000000,\n    0x9d0d92de00000000, 0x8dd1b26c00000000, 0x3df8d25100000000,\n    0xed82721600000000, 0x5dab122b00000000, 0x8c3c42a900000000,\n    0x3c15229400000000, 0xec6f82d300000000, 0x5c46e2ee00000000,\n    0x4c9ac25c00000000, 0xfcb3a26100000000, 0x2cc9022600000000,\n    0x9ce0621b00000000, 0xcfe0d2f900000000, 0x7fc9b2c400000000,\n    0xafb3128300000000, 0x1f9a72be00000000, 0x0f46520c00000000,\n    0xbf6f323100000000, 0x6f15927600000000, 0xdf3cf24b00000000,\n    0x0eaba2c900000000, 0xbe82c2f400000000, 0x6ef862b300000000,\n    0xded1028e00000000, 0xce0d223c00000000, 0x7e24420100000000,\n    0xae5ee24600000000, 0x1e77827b00000000, 0x92b0e6b100000000,\n    0x2299868c00000000, 0xf2e326cb00000000, 0x42ca46f600000000,\n    0x5216664400000000, 0xe23f067900000000, 0x3245a63e00000000,\n    0x826cc60300000000, 0x53fb968100000000, 0xe3d2f6bc00000000,\n    0x33a856fb00000000, 0x838136c600000000, 0x935d167400000000,\n    0x2374764900000000, 0xf30ed60e00000000, 0x4327b63300000000,\n    0x102706d100000000, 0xa00e66ec00000000, 0x7074c6ab00000000,\n    0xc05da69600000000, 0xd081862400000000, 0x60a8e61900000000,\n    0xb0d2465e00000000, 0x00fb266300000000, 0xd16c76e100000000,\n    0x614516dc00000000, 0xb13fb69b00000000, 0x0116d6a600000000,\n    0x11caf61400000000, 0xa1e3962900000000, 0x7199366e00000000,\n    0xc1b0565300000000, 0x969f277000000000, 0x26b6474d00000000,\n    0xf6cce70a00000000, 0x46e5873700000000, 0x5639a78500000000,\n    0xe610c7b800000000, 0x366a67ff00000000, 0x864307c200000000,\n    0x57d4574000000000, 0xe7fd377d00000000, 0x3787973a00000000,\n    0x87aef70700000000, 0x9772d7b500000000, 0x275bb78800000000,\n    0xf72117cf00000000, 0x470877f200000000, 0x1408c71000000000,\n    0xa421a72d00000000, 0x745b076a00000000, 0xc472675700000000,\n    0xd4ae47e500000000, 0x648727d800000000, 0xb4fd879f00000000,\n    0x04d4e7a200000000, 0xd543b72000000000, 0x656ad71d00000000,\n    0xb510775a00000000, 0x0539176700000000, 0x15e537d500000000,\n    0xa5cc57e800000000, 0x75b6f7af00000000, 0xc59f979200000000,\n    0xdbe815e900000000, 0x6bc175d400000000, 0xbbbbd59300000000,\n    0x0b92b5ae00000000, 0x1b4e951c00000000, 0xab67f52100000000,\n    0x7b1d556600000000, 0xcb34355b00000000, 0x1aa365d900000000,\n    0xaa8a05e400000000, 0x7af0a5a300000000, 0xcad9c59e00000000,\n    0xda05e52c00000000, 0x6a2c851100000000, 0xba56255600000000,\n    0x0a7f456b00000000, 0x597ff58900000000, 0xe95695b400000000,\n    0x392c35f300000000, 0x890555ce00000000, 0x99d9757c00000000,\n    0x29f0154100000000, 0xf98ab50600000000, 0x49a3d53b00000000,\n    0x983485b900000000, 0x281de58400000000, 0xf86745c300000000,\n    0x484e25fe00000000, 0x5892054c00000000, 0xe8bb657100000000,\n    0x38c1c53600000000, 0x88e8a50b00000000, 0xdfc7d42800000000,\n    0x6feeb41500000000, 0xbf94145200000000, 0x0fbd746f00000000,\n    0x1f6154dd00000000, 0xaf4834e000000000, 0x7f3294a700000000,\n    0xcf1bf49a00000000, 0x1e8ca41800000000, 0xaea5c42500000000,\n    0x7edf646200000000, 0xcef6045f00000000, 0xde2a24ed00000000,\n    0x6e0344d000000000, 0xbe79e49700000000, 0x0e5084aa00000000,\n    0x5d50344800000000, 0xed79547500000000, 0x3d03f43200000000,\n    0x8d2a940f00000000, 0x9df6b4bd00000000, 0x2ddfd48000000000,\n    0xfda574c700000000, 0x4d8c14fa00000000, 0x9c1b447800000000,\n    0x2c32244500000000, 0xfc48840200000000, 0x4c61e43f00000000,\n    0x5cbdc48d00000000, 0xec94a4b000000000, 0x3cee04f700000000,\n    0x8cc764ca00000000},\n   {0x0000000000000000, 0xa5d35ccb00000000, 0x0ba1c84d00000000,\n    0xae72948600000000, 0x1642919b00000000, 0xb391cd5000000000,\n    0x1de359d600000000, 0xb830051d00000000, 0x6d8253ec00000000,\n    0xc8510f2700000000, 0x66239ba100000000, 0xc3f0c76a00000000,\n    0x7bc0c27700000000, 0xde139ebc00000000, 0x70610a3a00000000,\n    0xd5b256f100000000, 0x9b02d60300000000, 0x3ed18ac800000000,\n    0x90a31e4e00000000, 0x3570428500000000, 0x8d40479800000000,\n    0x28931b5300000000, 0x86e18fd500000000, 0x2332d31e00000000,\n    0xf68085ef00000000, 0x5353d92400000000, 0xfd214da200000000,\n    0x58f2116900000000, 0xe0c2147400000000, 0x451148bf00000000,\n    0xeb63dc3900000000, 0x4eb080f200000000, 0x3605ac0700000000,\n    0x93d6f0cc00000000, 0x3da4644a00000000, 0x9877388100000000,\n    0x20473d9c00000000, 0x8594615700000000, 0x2be6f5d100000000,\n    0x8e35a91a00000000, 0x5b87ffeb00000000, 0xfe54a32000000000,\n    0x502637a600000000, 0xf5f56b6d00000000, 0x4dc56e7000000000,\n    0xe81632bb00000000, 0x4664a63d00000000, 0xe3b7faf600000000,\n    0xad077a0400000000, 0x08d426cf00000000, 0xa6a6b24900000000,\n    0x0375ee8200000000, 0xbb45eb9f00000000, 0x1e96b75400000000,\n    0xb0e423d200000000, 0x15377f1900000000, 0xc08529e800000000,\n    0x6556752300000000, 0xcb24e1a500000000, 0x6ef7bd6e00000000,\n    0xd6c7b87300000000, 0x7314e4b800000000, 0xdd66703e00000000,\n    0x78b52cf500000000, 0x6c0a580f00000000, 0xc9d904c400000000,\n    0x67ab904200000000, 0xc278cc8900000000, 0x7a48c99400000000,\n    0xdf9b955f00000000, 0x71e901d900000000, 0xd43a5d1200000000,\n    0x01880be300000000, 0xa45b572800000000, 0x0a29c3ae00000000,\n    0xaffa9f6500000000, 0x17ca9a7800000000, 0xb219c6b300000000,\n    0x1c6b523500000000, 0xb9b80efe00000000, 0xf7088e0c00000000,\n    0x52dbd2c700000000, 0xfca9464100000000, 0x597a1a8a00000000,\n    0xe14a1f9700000000, 0x4499435c00000000, 0xeaebd7da00000000,\n    0x4f388b1100000000, 0x9a8adde000000000, 0x3f59812b00000000,\n    0x912b15ad00000000, 0x34f8496600000000, 0x8cc84c7b00000000,\n    0x291b10b000000000, 0x8769843600000000, 0x22bad8fd00000000,\n    0x5a0ff40800000000, 0xffdca8c300000000, 0x51ae3c4500000000,\n    0xf47d608e00000000, 0x4c4d659300000000, 0xe99e395800000000,\n    0x47ecadde00000000, 0xe23ff11500000000, 0x378da7e400000000,\n    0x925efb2f00000000, 0x3c2c6fa900000000, 0x99ff336200000000,\n    0x21cf367f00000000, 0x841c6ab400000000, 0x2a6efe3200000000,\n    0x8fbda2f900000000, 0xc10d220b00000000, 0x64de7ec000000000,\n    0xcaacea4600000000, 0x6f7fb68d00000000, 0xd74fb39000000000,\n    0x729cef5b00000000, 0xdcee7bdd00000000, 0x793d271600000000,\n    0xac8f71e700000000, 0x095c2d2c00000000, 0xa72eb9aa00000000,\n    0x02fde56100000000, 0xbacde07c00000000, 0x1f1ebcb700000000,\n    0xb16c283100000000, 0x14bf74fa00000000, 0xd814b01e00000000,\n    0x7dc7ecd500000000, 0xd3b5785300000000, 0x7666249800000000,\n    0xce56218500000000, 0x6b857d4e00000000, 0xc5f7e9c800000000,\n    0x6024b50300000000, 0xb596e3f200000000, 0x1045bf3900000000,\n    0xbe372bbf00000000, 0x1be4777400000000, 0xa3d4726900000000,\n    0x06072ea200000000, 0xa875ba2400000000, 0x0da6e6ef00000000,\n    0x4316661d00000000, 0xe6c53ad600000000, 0x48b7ae5000000000,\n    0xed64f29b00000000, 0x5554f78600000000, 0xf087ab4d00000000,\n    0x5ef53fcb00000000, 0xfb26630000000000, 0x2e9435f100000000,\n    0x8b47693a00000000, 0x2535fdbc00000000, 0x80e6a17700000000,\n    0x38d6a46a00000000, 0x9d05f8a100000000, 0x33776c2700000000,\n    0x96a430ec00000000, 0xee111c1900000000, 0x4bc240d200000000,\n    0xe5b0d45400000000, 0x4063889f00000000, 0xf8538d8200000000,\n    0x5d80d14900000000, 0xf3f245cf00000000, 0x5621190400000000,\n    0x83934ff500000000, 0x2640133e00000000, 0x883287b800000000,\n    0x2de1db7300000000, 0x95d1de6e00000000, 0x300282a500000000,\n    0x9e70162300000000, 0x3ba34ae800000000, 0x7513ca1a00000000,\n    0xd0c096d100000000, 0x7eb2025700000000, 0xdb615e9c00000000,\n    0x63515b8100000000, 0xc682074a00000000, 0x68f093cc00000000,\n    0xcd23cf0700000000, 0x189199f600000000, 0xbd42c53d00000000,\n    0x133051bb00000000, 0xb6e30d7000000000, 0x0ed3086d00000000,\n    0xab0054a600000000, 0x0572c02000000000, 0xa0a19ceb00000000,\n    0xb41ee81100000000, 0x11cdb4da00000000, 0xbfbf205c00000000,\n    0x1a6c7c9700000000, 0xa25c798a00000000, 0x078f254100000000,\n    0xa9fdb1c700000000, 0x0c2eed0c00000000, 0xd99cbbfd00000000,\n    0x7c4fe73600000000, 0xd23d73b000000000, 0x77ee2f7b00000000,\n    0xcfde2a6600000000, 0x6a0d76ad00000000, 0xc47fe22b00000000,\n    0x61acbee000000000, 0x2f1c3e1200000000, 0x8acf62d900000000,\n    0x24bdf65f00000000, 0x816eaa9400000000, 0x395eaf8900000000,\n    0x9c8df34200000000, 0x32ff67c400000000, 0x972c3b0f00000000,\n    0x429e6dfe00000000, 0xe74d313500000000, 0x493fa5b300000000,\n    0xececf97800000000, 0x54dcfc6500000000, 0xf10fa0ae00000000,\n    0x5f7d342800000000, 0xfaae68e300000000, 0x821b441600000000,\n    0x27c818dd00000000, 0x89ba8c5b00000000, 0x2c69d09000000000,\n    0x9459d58d00000000, 0x318a894600000000, 0x9ff81dc000000000,\n    0x3a2b410b00000000, 0xef9917fa00000000, 0x4a4a4b3100000000,\n    0xe438dfb700000000, 0x41eb837c00000000, 0xf9db866100000000,\n    0x5c08daaa00000000, 0xf27a4e2c00000000, 0x57a912e700000000,\n    0x1919921500000000, 0xbccacede00000000, 0x12b85a5800000000,\n    0xb76b069300000000, 0x0f5b038e00000000, 0xaa885f4500000000,\n    0x04facbc300000000, 0xa129970800000000, 0x749bc1f900000000,\n    0xd1489d3200000000, 0x7f3a09b400000000, 0xdae9557f00000000,\n    0x62d9506200000000, 0xc70a0ca900000000, 0x6978982f00000000,\n    0xccabc4e400000000},\n   {0x0000000000000000, 0xb40b77a600000000, 0x29119f9700000000,\n    0x9d1ae83100000000, 0x13244ff400000000, 0xa72f385200000000,\n    0x3a35d06300000000, 0x8e3ea7c500000000, 0x674eef3300000000,\n    0xd345989500000000, 0x4e5f70a400000000, 0xfa54070200000000,\n    0x746aa0c700000000, 0xc061d76100000000, 0x5d7b3f5000000000,\n    0xe97048f600000000, 0xce9cde6700000000, 0x7a97a9c100000000,\n    0xe78d41f000000000, 0x5386365600000000, 0xddb8919300000000,\n    0x69b3e63500000000, 0xf4a90e0400000000, 0x40a279a200000000,\n    0xa9d2315400000000, 0x1dd946f200000000, 0x80c3aec300000000,\n    0x34c8d96500000000, 0xbaf67ea000000000, 0x0efd090600000000,\n    0x93e7e13700000000, 0x27ec969100000000, 0x9c39bdcf00000000,\n    0x2832ca6900000000, 0xb528225800000000, 0x012355fe00000000,\n    0x8f1df23b00000000, 0x3b16859d00000000, 0xa60c6dac00000000,\n    0x12071a0a00000000, 0xfb7752fc00000000, 0x4f7c255a00000000,\n    0xd266cd6b00000000, 0x666dbacd00000000, 0xe8531d0800000000,\n    0x5c586aae00000000, 0xc142829f00000000, 0x7549f53900000000,\n    0x52a563a800000000, 0xe6ae140e00000000, 0x7bb4fc3f00000000,\n    0xcfbf8b9900000000, 0x41812c5c00000000, 0xf58a5bfa00000000,\n    0x6890b3cb00000000, 0xdc9bc46d00000000, 0x35eb8c9b00000000,\n    0x81e0fb3d00000000, 0x1cfa130c00000000, 0xa8f164aa00000000,\n    0x26cfc36f00000000, 0x92c4b4c900000000, 0x0fde5cf800000000,\n    0xbbd52b5e00000000, 0x79750b4400000000, 0xcd7e7ce200000000,\n    0x506494d300000000, 0xe46fe37500000000, 0x6a5144b000000000,\n    0xde5a331600000000, 0x4340db2700000000, 0xf74bac8100000000,\n    0x1e3be47700000000, 0xaa3093d100000000, 0x372a7be000000000,\n    0x83210c4600000000, 0x0d1fab8300000000, 0xb914dc2500000000,\n    0x240e341400000000, 0x900543b200000000, 0xb7e9d52300000000,\n    0x03e2a28500000000, 0x9ef84ab400000000, 0x2af33d1200000000,\n    0xa4cd9ad700000000, 0x10c6ed7100000000, 0x8ddc054000000000,\n    0x39d772e600000000, 0xd0a73a1000000000, 0x64ac4db600000000,\n    0xf9b6a58700000000, 0x4dbdd22100000000, 0xc38375e400000000,\n    0x7788024200000000, 0xea92ea7300000000, 0x5e999dd500000000,\n    0xe54cb68b00000000, 0x5147c12d00000000, 0xcc5d291c00000000,\n    0x78565eba00000000, 0xf668f97f00000000, 0x42638ed900000000,\n    0xdf7966e800000000, 0x6b72114e00000000, 0x820259b800000000,\n    0x36092e1e00000000, 0xab13c62f00000000, 0x1f18b18900000000,\n    0x9126164c00000000, 0x252d61ea00000000, 0xb83789db00000000,\n    0x0c3cfe7d00000000, 0x2bd068ec00000000, 0x9fdb1f4a00000000,\n    0x02c1f77b00000000, 0xb6ca80dd00000000, 0x38f4271800000000,\n    0x8cff50be00000000, 0x11e5b88f00000000, 0xa5eecf2900000000,\n    0x4c9e87df00000000, 0xf895f07900000000, 0x658f184800000000,\n    0xd1846fee00000000, 0x5fbac82b00000000, 0xebb1bf8d00000000,\n    0x76ab57bc00000000, 0xc2a0201a00000000, 0xf2ea168800000000,\n    0x46e1612e00000000, 0xdbfb891f00000000, 0x6ff0feb900000000,\n    0xe1ce597c00000000, 0x55c52eda00000000, 0xc8dfc6eb00000000,\n    0x7cd4b14d00000000, 0x95a4f9bb00000000, 0x21af8e1d00000000,\n    0xbcb5662c00000000, 0x08be118a00000000, 0x8680b64f00000000,\n    0x328bc1e900000000, 0xaf9129d800000000, 0x1b9a5e7e00000000,\n    0x3c76c8ef00000000, 0x887dbf4900000000, 0x1567577800000000,\n    0xa16c20de00000000, 0x2f52871b00000000, 0x9b59f0bd00000000,\n    0x0643188c00000000, 0xb2486f2a00000000, 0x5b3827dc00000000,\n    0xef33507a00000000, 0x7229b84b00000000, 0xc622cfed00000000,\n    0x481c682800000000, 0xfc171f8e00000000, 0x610df7bf00000000,\n    0xd506801900000000, 0x6ed3ab4700000000, 0xdad8dce100000000,\n    0x47c234d000000000, 0xf3c9437600000000, 0x7df7e4b300000000,\n    0xc9fc931500000000, 0x54e67b2400000000, 0xe0ed0c8200000000,\n    0x099d447400000000, 0xbd9633d200000000, 0x208cdbe300000000,\n    0x9487ac4500000000, 0x1ab90b8000000000, 0xaeb27c2600000000,\n    0x33a8941700000000, 0x87a3e3b100000000, 0xa04f752000000000,\n    0x1444028600000000, 0x895eeab700000000, 0x3d559d1100000000,\n    0xb36b3ad400000000, 0x07604d7200000000, 0x9a7aa54300000000,\n    0x2e71d2e500000000, 0xc7019a1300000000, 0x730aedb500000000,\n    0xee10058400000000, 0x5a1b722200000000, 0xd425d5e700000000,\n    0x602ea24100000000, 0xfd344a7000000000, 0x493f3dd600000000,\n    0x8b9f1dcc00000000, 0x3f946a6a00000000, 0xa28e825b00000000,\n    0x1685f5fd00000000, 0x98bb523800000000, 0x2cb0259e00000000,\n    0xb1aacdaf00000000, 0x05a1ba0900000000, 0xecd1f2ff00000000,\n    0x58da855900000000, 0xc5c06d6800000000, 0x71cb1ace00000000,\n    0xfff5bd0b00000000, 0x4bfecaad00000000, 0xd6e4229c00000000,\n    0x62ef553a00000000, 0x4503c3ab00000000, 0xf108b40d00000000,\n    0x6c125c3c00000000, 0xd8192b9a00000000, 0x56278c5f00000000,\n    0xe22cfbf900000000, 0x7f3613c800000000, 0xcb3d646e00000000,\n    0x224d2c9800000000, 0x96465b3e00000000, 0x0b5cb30f00000000,\n    0xbf57c4a900000000, 0x3169636c00000000, 0x856214ca00000000,\n    0x1878fcfb00000000, 0xac738b5d00000000, 0x17a6a00300000000,\n    0xa3add7a500000000, 0x3eb73f9400000000, 0x8abc483200000000,\n    0x0482eff700000000, 0xb089985100000000, 0x2d93706000000000,\n    0x999807c600000000, 0x70e84f3000000000, 0xc4e3389600000000,\n    0x59f9d0a700000000, 0xedf2a70100000000, 0x63cc00c400000000,\n    0xd7c7776200000000, 0x4add9f5300000000, 0xfed6e8f500000000,\n    0xd93a7e6400000000, 0x6d3109c200000000, 0xf02be1f300000000,\n    0x4420965500000000, 0xca1e319000000000, 0x7e15463600000000,\n    0xe30fae0700000000, 0x5704d9a100000000, 0xbe74915700000000,\n    0x0a7fe6f100000000, 0x97650ec000000000, 0x236e796600000000,\n    0xad50dea300000000, 0x195ba90500000000, 0x8441413400000000,\n    0x304a369200000000},\n   {0x0000000000000000, 0x9e00aacc00000000, 0x7d07254200000000,\n    0xe3078f8e00000000, 0xfa0e4a8400000000, 0x640ee04800000000,\n    0x87096fc600000000, 0x1909c50a00000000, 0xb51be5d300000000,\n    0x2b1b4f1f00000000, 0xc81cc09100000000, 0x561c6a5d00000000,\n    0x4f15af5700000000, 0xd115059b00000000, 0x32128a1500000000,\n    0xac1220d900000000, 0x2b31bb7c00000000, 0xb53111b000000000,\n    0x56369e3e00000000, 0xc83634f200000000, 0xd13ff1f800000000,\n    0x4f3f5b3400000000, 0xac38d4ba00000000, 0x32387e7600000000,\n    0x9e2a5eaf00000000, 0x002af46300000000, 0xe32d7bed00000000,\n    0x7d2dd12100000000, 0x6424142b00000000, 0xfa24bee700000000,\n    0x1923316900000000, 0x87239ba500000000, 0x566276f900000000,\n    0xc862dc3500000000, 0x2b6553bb00000000, 0xb565f97700000000,\n    0xac6c3c7d00000000, 0x326c96b100000000, 0xd16b193f00000000,\n    0x4f6bb3f300000000, 0xe379932a00000000, 0x7d7939e600000000,\n    0x9e7eb66800000000, 0x007e1ca400000000, 0x1977d9ae00000000,\n    0x8777736200000000, 0x6470fcec00000000, 0xfa70562000000000,\n    0x7d53cd8500000000, 0xe353674900000000, 0x0054e8c700000000,\n    0x9e54420b00000000, 0x875d870100000000, 0x195d2dcd00000000,\n    0xfa5aa24300000000, 0x645a088f00000000, 0xc848285600000000,\n    0x5648829a00000000, 0xb54f0d1400000000, 0x2b4fa7d800000000,\n    0x324662d200000000, 0xac46c81e00000000, 0x4f41479000000000,\n    0xd141ed5c00000000, 0xedc29d2900000000, 0x73c237e500000000,\n    0x90c5b86b00000000, 0x0ec512a700000000, 0x17ccd7ad00000000,\n    0x89cc7d6100000000, 0x6acbf2ef00000000, 0xf4cb582300000000,\n    0x58d978fa00000000, 0xc6d9d23600000000, 0x25de5db800000000,\n    0xbbdef77400000000, 0xa2d7327e00000000, 0x3cd798b200000000,\n    0xdfd0173c00000000, 0x41d0bdf000000000, 0xc6f3265500000000,\n    0x58f38c9900000000, 0xbbf4031700000000, 0x25f4a9db00000000,\n    0x3cfd6cd100000000, 0xa2fdc61d00000000, 0x41fa499300000000,\n    0xdffae35f00000000, 0x73e8c38600000000, 0xede8694a00000000,\n    0x0eefe6c400000000, 0x90ef4c0800000000, 0x89e6890200000000,\n    0x17e623ce00000000, 0xf4e1ac4000000000, 0x6ae1068c00000000,\n    0xbba0ebd000000000, 0x25a0411c00000000, 0xc6a7ce9200000000,\n    0x58a7645e00000000, 0x41aea15400000000, 0xdfae0b9800000000,\n    0x3ca9841600000000, 0xa2a92eda00000000, 0x0ebb0e0300000000,\n    0x90bba4cf00000000, 0x73bc2b4100000000, 0xedbc818d00000000,\n    0xf4b5448700000000, 0x6ab5ee4b00000000, 0x89b261c500000000,\n    0x17b2cb0900000000, 0x909150ac00000000, 0x0e91fa6000000000,\n    0xed9675ee00000000, 0x7396df2200000000, 0x6a9f1a2800000000,\n    0xf49fb0e400000000, 0x17983f6a00000000, 0x899895a600000000,\n    0x258ab57f00000000, 0xbb8a1fb300000000, 0x588d903d00000000,\n    0xc68d3af100000000, 0xdf84fffb00000000, 0x4184553700000000,\n    0xa283dab900000000, 0x3c83707500000000, 0xda853b5300000000,\n    0x4485919f00000000, 0xa7821e1100000000, 0x3982b4dd00000000,\n    0x208b71d700000000, 0xbe8bdb1b00000000, 0x5d8c549500000000,\n    0xc38cfe5900000000, 0x6f9ede8000000000, 0xf19e744c00000000,\n    0x1299fbc200000000, 0x8c99510e00000000, 0x9590940400000000,\n    0x0b903ec800000000, 0xe897b14600000000, 0x76971b8a00000000,\n    0xf1b4802f00000000, 0x6fb42ae300000000, 0x8cb3a56d00000000,\n    0x12b30fa100000000, 0x0bbacaab00000000, 0x95ba606700000000,\n    0x76bdefe900000000, 0xe8bd452500000000, 0x44af65fc00000000,\n    0xdaafcf3000000000, 0x39a840be00000000, 0xa7a8ea7200000000,\n    0xbea12f7800000000, 0x20a185b400000000, 0xc3a60a3a00000000,\n    0x5da6a0f600000000, 0x8ce74daa00000000, 0x12e7e76600000000,\n    0xf1e068e800000000, 0x6fe0c22400000000, 0x76e9072e00000000,\n    0xe8e9ade200000000, 0x0bee226c00000000, 0x95ee88a000000000,\n    0x39fca87900000000, 0xa7fc02b500000000, 0x44fb8d3b00000000,\n    0xdafb27f700000000, 0xc3f2e2fd00000000, 0x5df2483100000000,\n    0xbef5c7bf00000000, 0x20f56d7300000000, 0xa7d6f6d600000000,\n    0x39d65c1a00000000, 0xdad1d39400000000, 0x44d1795800000000,\n    0x5dd8bc5200000000, 0xc3d8169e00000000, 0x20df991000000000,\n    0xbedf33dc00000000, 0x12cd130500000000, 0x8ccdb9c900000000,\n    0x6fca364700000000, 0xf1ca9c8b00000000, 0xe8c3598100000000,\n    0x76c3f34d00000000, 0x95c47cc300000000, 0x0bc4d60f00000000,\n    0x3747a67a00000000, 0xa9470cb600000000, 0x4a40833800000000,\n    0xd44029f400000000, 0xcd49ecfe00000000, 0x5349463200000000,\n    0xb04ec9bc00000000, 0x2e4e637000000000, 0x825c43a900000000,\n    0x1c5ce96500000000, 0xff5b66eb00000000, 0x615bcc2700000000,\n    0x7852092d00000000, 0xe652a3e100000000, 0x05552c6f00000000,\n    0x9b5586a300000000, 0x1c761d0600000000, 0x8276b7ca00000000,\n    0x6171384400000000, 0xff71928800000000, 0xe678578200000000,\n    0x7878fd4e00000000, 0x9b7f72c000000000, 0x057fd80c00000000,\n    0xa96df8d500000000, 0x376d521900000000, 0xd46add9700000000,\n    0x4a6a775b00000000, 0x5363b25100000000, 0xcd63189d00000000,\n    0x2e64971300000000, 0xb0643ddf00000000, 0x6125d08300000000,\n    0xff257a4f00000000, 0x1c22f5c100000000, 0x82225f0d00000000,\n    0x9b2b9a0700000000, 0x052b30cb00000000, 0xe62cbf4500000000,\n    0x782c158900000000, 0xd43e355000000000, 0x4a3e9f9c00000000,\n    0xa939101200000000, 0x3739bade00000000, 0x2e307fd400000000,\n    0xb030d51800000000, 0x53375a9600000000, 0xcd37f05a00000000,\n    0x4a146bff00000000, 0xd414c13300000000, 0x37134ebd00000000,\n    0xa913e47100000000, 0xb01a217b00000000, 0x2e1a8bb700000000,\n    0xcd1d043900000000, 0x531daef500000000, 0xff0f8e2c00000000,\n    0x610f24e000000000, 0x8208ab6e00000000, 0x1c0801a200000000,\n    0x0501c4a800000000, 0x9b016e6400000000, 0x7806e1ea00000000,\n    0xe6064b2600000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757,\n    0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a,\n    0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733,\n    0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871,\n    0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70,\n    0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42,\n    0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5,\n    0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,\n    0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086,\n    0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4,\n    0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d,\n    0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0,\n    0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d,\n    0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f,\n    0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859,\n    0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,\n    0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5,\n    0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028,\n    0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891,\n    0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed,\n    0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec,\n    0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde,\n    0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817,\n    0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,\n    0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24,\n    0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e,\n    0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7,\n    0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a,\n    0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4,\n    0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196,\n    0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0,\n    0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,\n    0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52,\n    0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f,\n    0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36,\n    0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174,\n    0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675,\n    0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647,\n    0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d,\n    0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,\n    0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be,\n    0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc,\n    0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645,\n    0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98,\n    0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138,\n    0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a,\n    0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c,\n    0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,\n    0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0,\n    0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d,\n    0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194,\n    0xde0506f1},\n   {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc,\n    0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f,\n    0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a,\n    0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29,\n    0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8,\n    0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023,\n    0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e,\n    0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,\n    0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84,\n    0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7,\n    0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922,\n    0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71,\n    0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0,\n    0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b,\n    0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816,\n    0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,\n    0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c,\n    0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f,\n    0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba,\n    0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579,\n    0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98,\n    0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873,\n    0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e,\n    0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,\n    0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134,\n    0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7,\n    0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732,\n    0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461,\n    0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0,\n    0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b,\n    0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26,\n    0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,\n    0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc,\n    0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef,\n    0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a,\n    0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049,\n    0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8,\n    0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43,\n    0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e,\n    0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,\n    0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24,\n    0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07,\n    0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982,\n    0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1,\n    0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0,\n    0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b,\n    0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576,\n    0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,\n    0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c,\n    0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f,\n    0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda,\n    0xbe9834ed},\n   {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504,\n    0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49,\n    0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e,\n    0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192,\n    0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859,\n    0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c,\n    0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620,\n    0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,\n    0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae,\n    0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2,\n    0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175,\n    0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38,\n    0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05,\n    0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40,\n    0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f,\n    0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,\n    0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850,\n    0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d,\n    0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da,\n    0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864,\n    0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af,\n    0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea,\n    0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74,\n    0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,\n    0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa,\n    0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a,\n    0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd,\n    0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180,\n    0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a,\n    0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f,\n    0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290,\n    0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,\n    0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed,\n    0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0,\n    0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167,\n    0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b,\n    0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0,\n    0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5,\n    0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc,\n    0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,\n    0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842,\n    0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e,\n    0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299,\n    0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4,\n    0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec,\n    0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9,\n    0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66,\n    0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,\n    0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9,\n    0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4,\n    0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33,\n    0x9324fd72},\n   {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,\n    0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,\n    0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,\n    0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,\n    0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n    0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n    0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,\n    0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,\n    0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,\n    0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n    0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,\n    0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,\n    0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,\n    0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n    0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,\n    0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,\n    0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,\n    0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,\n    0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n    0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,\n    0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,\n    0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,\n    0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,\n    0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n    0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,\n    0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,\n    0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,\n    0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,\n    0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,\n    0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n    0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,\n    0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,\n    0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n    0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,\n    0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,\n    0x2d02ef8d}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0x96300777, 0x2c610eee, 0xba510999, 0x19c46d07,\n    0x8ff46a70, 0x35a563e9, 0xa395649e, 0x3288db0e, 0xa4b8dc79,\n    0x1ee9d5e0, 0x88d9d297, 0x2b4cb609, 0xbd7cb17e, 0x072db8e7,\n    0x911dbf90, 0x6410b71d, 0xf220b06a, 0x4871b9f3, 0xde41be84,\n    0x7dd4da1a, 0xebe4dd6d, 0x51b5d4f4, 0xc785d383, 0x56986c13,\n    0xc0a86b64, 0x7af962fd, 0xecc9658a, 0x4f5c0114, 0xd96c0663,\n    0x633d0ffa, 0xf50d088d, 0xc8206e3b, 0x5e10694c, 0xe44160d5,\n    0x727167a2, 0xd1e4033c, 0x47d4044b, 0xfd850dd2, 0x6bb50aa5,\n    0xfaa8b535, 0x6c98b242, 0xd6c9bbdb, 0x40f9bcac, 0xe36cd832,\n    0x755cdf45, 0xcf0dd6dc, 0x593dd1ab, 0xac30d926, 0x3a00de51,\n    0x8051d7c8, 0x1661d0bf, 0xb5f4b421, 0x23c4b356, 0x9995bacf,\n    0x0fa5bdb8, 0x9eb80228, 0x0888055f, 0xb2d90cc6, 0x24e90bb1,\n    0x877c6f2f, 0x114c6858, 0xab1d61c1, 0x3d2d66b6, 0x9041dc76,\n    0x0671db01, 0xbc20d298, 0x2a10d5ef, 0x8985b171, 0x1fb5b606,\n    0xa5e4bf9f, 0x33d4b8e8, 0xa2c90778, 0x34f9000f, 0x8ea80996,\n    0x18980ee1, 0xbb0d6a7f, 0x2d3d6d08, 0x976c6491, 0x015c63e6,\n    0xf4516b6b, 0x62616c1c, 0xd8306585, 0x4e0062f2, 0xed95066c,\n    0x7ba5011b, 0xc1f40882, 0x57c40ff5, 0xc6d9b065, 0x50e9b712,\n    0xeab8be8b, 0x7c88b9fc, 0xdf1ddd62, 0x492dda15, 0xf37cd38c,\n    0x654cd4fb, 0x5861b24d, 0xce51b53a, 0x7400bca3, 0xe230bbd4,\n    0x41a5df4a, 0xd795d83d, 0x6dc4d1a4, 0xfbf4d6d3, 0x6ae96943,\n    0xfcd96e34, 0x468867ad, 0xd0b860da, 0x732d0444, 0xe51d0333,\n    0x5f4c0aaa, 0xc97c0ddd, 0x3c710550, 0xaa410227, 0x10100bbe,\n    0x86200cc9, 0x25b56857, 0xb3856f20, 0x09d466b9, 0x9fe461ce,\n    0x0ef9de5e, 0x98c9d929, 0x2298d0b0, 0xb4a8d7c7, 0x173db359,\n    0x810db42e, 0x3b5cbdb7, 0xad6cbac0, 0x2083b8ed, 0xb6b3bf9a,\n    0x0ce2b603, 0x9ad2b174, 0x3947d5ea, 0xaf77d29d, 0x1526db04,\n    0x8316dc73, 0x120b63e3, 0x843b6494, 0x3e6a6d0d, 0xa85a6a7a,\n    0x0bcf0ee4, 0x9dff0993, 0x27ae000a, 0xb19e077d, 0x44930ff0,\n    0xd2a30887, 0x68f2011e, 0xfec20669, 0x5d5762f7, 0xcb676580,\n    0x71366c19, 0xe7066b6e, 0x761bd4fe, 0xe02bd389, 0x5a7ada10,\n    0xcc4add67, 0x6fdfb9f9, 0xf9efbe8e, 0x43beb717, 0xd58eb060,\n    0xe8a3d6d6, 0x7e93d1a1, 0xc4c2d838, 0x52f2df4f, 0xf167bbd1,\n    0x6757bca6, 0xdd06b53f, 0x4b36b248, 0xda2b0dd8, 0x4c1b0aaf,\n    0xf64a0336, 0x607a0441, 0xc3ef60df, 0x55df67a8, 0xef8e6e31,\n    0x79be6946, 0x8cb361cb, 0x1a8366bc, 0xa0d26f25, 0x36e26852,\n    0x95770ccc, 0x03470bbb, 0xb9160222, 0x2f260555, 0xbe3bbac5,\n    0x280bbdb2, 0x925ab42b, 0x046ab35c, 0xa7ffd7c2, 0x31cfd0b5,\n    0x8b9ed92c, 0x1daede5b, 0xb0c2649b, 0x26f263ec, 0x9ca36a75,\n    0x0a936d02, 0xa906099c, 0x3f360eeb, 0x85670772, 0x13570005,\n    0x824abf95, 0x147ab8e2, 0xae2bb17b, 0x381bb60c, 0x9b8ed292,\n    0x0dbed5e5, 0xb7efdc7c, 0x21dfdb0b, 0xd4d2d386, 0x42e2d4f1,\n    0xf8b3dd68, 0x6e83da1f, 0xcd16be81, 0x5b26b9f6, 0xe177b06f,\n    0x7747b718, 0xe65a0888, 0x706a0fff, 0xca3b0666, 0x5c0b0111,\n    0xff9e658f, 0x69ae62f8, 0xd3ff6b61, 0x45cf6c16, 0x78e20aa0,\n    0xeed20dd7, 0x5483044e, 0xc2b30339, 0x612667a7, 0xf71660d0,\n    0x4d476949, 0xdb776e3e, 0x4a6ad1ae, 0xdc5ad6d9, 0x660bdf40,\n    0xf03bd837, 0x53aebca9, 0xc59ebbde, 0x7fcfb247, 0xe9ffb530,\n    0x1cf2bdbd, 0x8ac2baca, 0x3093b353, 0xa6a3b424, 0x0536d0ba,\n    0x9306d7cd, 0x2957de54, 0xbf67d923, 0x2e7a66b3, 0xb84a61c4,\n    0x021b685d, 0x942b6f2a, 0x37be0bb4, 0xa18e0cc3, 0x1bdf055a,\n    0x8def022d},\n   {0x00000000, 0x41311b19, 0x82623632, 0xc3532d2b, 0x04c56c64,\n    0x45f4777d, 0x86a75a56, 0xc796414f, 0x088ad9c8, 0x49bbc2d1,\n    0x8ae8effa, 0xcbd9f4e3, 0x0c4fb5ac, 0x4d7eaeb5, 0x8e2d839e,\n    0xcf1c9887, 0x5112c24a, 0x1023d953, 0xd370f478, 0x9241ef61,\n    0x55d7ae2e, 0x14e6b537, 0xd7b5981c, 0x96848305, 0x59981b82,\n    0x18a9009b, 0xdbfa2db0, 0x9acb36a9, 0x5d5d77e6, 0x1c6c6cff,\n    0xdf3f41d4, 0x9e0e5acd, 0xa2248495, 0xe3159f8c, 0x2046b2a7,\n    0x6177a9be, 0xa6e1e8f1, 0xe7d0f3e8, 0x2483dec3, 0x65b2c5da,\n    0xaaae5d5d, 0xeb9f4644, 0x28cc6b6f, 0x69fd7076, 0xae6b3139,\n    0xef5a2a20, 0x2c09070b, 0x6d381c12, 0xf33646df, 0xb2075dc6,\n    0x715470ed, 0x30656bf4, 0xf7f32abb, 0xb6c231a2, 0x75911c89,\n    0x34a00790, 0xfbbc9f17, 0xba8d840e, 0x79dea925, 0x38efb23c,\n    0xff79f373, 0xbe48e86a, 0x7d1bc541, 0x3c2ade58, 0x054f79f0,\n    0x447e62e9, 0x872d4fc2, 0xc61c54db, 0x018a1594, 0x40bb0e8d,\n    0x83e823a6, 0xc2d938bf, 0x0dc5a038, 0x4cf4bb21, 0x8fa7960a,\n    0xce968d13, 0x0900cc5c, 0x4831d745, 0x8b62fa6e, 0xca53e177,\n    0x545dbbba, 0x156ca0a3, 0xd63f8d88, 0x970e9691, 0x5098d7de,\n    0x11a9ccc7, 0xd2fae1ec, 0x93cbfaf5, 0x5cd76272, 0x1de6796b,\n    0xdeb55440, 0x9f844f59, 0x58120e16, 0x1923150f, 0xda703824,\n    0x9b41233d, 0xa76bfd65, 0xe65ae67c, 0x2509cb57, 0x6438d04e,\n    0xa3ae9101, 0xe29f8a18, 0x21cca733, 0x60fdbc2a, 0xafe124ad,\n    0xeed03fb4, 0x2d83129f, 0x6cb20986, 0xab2448c9, 0xea1553d0,\n    0x29467efb, 0x687765e2, 0xf6793f2f, 0xb7482436, 0x741b091d,\n    0x352a1204, 0xf2bc534b, 0xb38d4852, 0x70de6579, 0x31ef7e60,\n    0xfef3e6e7, 0xbfc2fdfe, 0x7c91d0d5, 0x3da0cbcc, 0xfa368a83,\n    0xbb07919a, 0x7854bcb1, 0x3965a7a8, 0x4b98833b, 0x0aa99822,\n    0xc9fab509, 0x88cbae10, 0x4f5def5f, 0x0e6cf446, 0xcd3fd96d,\n    0x8c0ec274, 0x43125af3, 0x022341ea, 0xc1706cc1, 0x804177d8,\n    0x47d73697, 0x06e62d8e, 0xc5b500a5, 0x84841bbc, 0x1a8a4171,\n    0x5bbb5a68, 0x98e87743, 0xd9d96c5a, 0x1e4f2d15, 0x5f7e360c,\n    0x9c2d1b27, 0xdd1c003e, 0x120098b9, 0x533183a0, 0x9062ae8b,\n    0xd153b592, 0x16c5f4dd, 0x57f4efc4, 0x94a7c2ef, 0xd596d9f6,\n    0xe9bc07ae, 0xa88d1cb7, 0x6bde319c, 0x2aef2a85, 0xed796bca,\n    0xac4870d3, 0x6f1b5df8, 0x2e2a46e1, 0xe136de66, 0xa007c57f,\n    0x6354e854, 0x2265f34d, 0xe5f3b202, 0xa4c2a91b, 0x67918430,\n    0x26a09f29, 0xb8aec5e4, 0xf99fdefd, 0x3accf3d6, 0x7bfde8cf,\n    0xbc6ba980, 0xfd5ab299, 0x3e099fb2, 0x7f3884ab, 0xb0241c2c,\n    0xf1150735, 0x32462a1e, 0x73773107, 0xb4e17048, 0xf5d06b51,\n    0x3683467a, 0x77b25d63, 0x4ed7facb, 0x0fe6e1d2, 0xccb5ccf9,\n    0x8d84d7e0, 0x4a1296af, 0x0b238db6, 0xc870a09d, 0x8941bb84,\n    0x465d2303, 0x076c381a, 0xc43f1531, 0x850e0e28, 0x42984f67,\n    0x03a9547e, 0xc0fa7955, 0x81cb624c, 0x1fc53881, 0x5ef42398,\n    0x9da70eb3, 0xdc9615aa, 0x1b0054e5, 0x5a314ffc, 0x996262d7,\n    0xd85379ce, 0x174fe149, 0x567efa50, 0x952dd77b, 0xd41ccc62,\n    0x138a8d2d, 0x52bb9634, 0x91e8bb1f, 0xd0d9a006, 0xecf37e5e,\n    0xadc26547, 0x6e91486c, 0x2fa05375, 0xe836123a, 0xa9070923,\n    0x6a542408, 0x2b653f11, 0xe479a796, 0xa548bc8f, 0x661b91a4,\n    0x272a8abd, 0xe0bccbf2, 0xa18dd0eb, 0x62defdc0, 0x23efe6d9,\n    0xbde1bc14, 0xfcd0a70d, 0x3f838a26, 0x7eb2913f, 0xb924d070,\n    0xf815cb69, 0x3b46e642, 0x7a77fd5b, 0xb56b65dc, 0xf45a7ec5,\n    0x370953ee, 0x763848f7, 0xb1ae09b8, 0xf09f12a1, 0x33cc3f8a,\n    0x72fd2493},\n   {0x00000000, 0x376ac201, 0x6ed48403, 0x59be4602, 0xdca80907,\n    0xebc2cb06, 0xb27c8d04, 0x85164f05, 0xb851130e, 0x8f3bd10f,\n    0xd685970d, 0xe1ef550c, 0x64f91a09, 0x5393d808, 0x0a2d9e0a,\n    0x3d475c0b, 0x70a3261c, 0x47c9e41d, 0x1e77a21f, 0x291d601e,\n    0xac0b2f1b, 0x9b61ed1a, 0xc2dfab18, 0xf5b56919, 0xc8f23512,\n    0xff98f713, 0xa626b111, 0x914c7310, 0x145a3c15, 0x2330fe14,\n    0x7a8eb816, 0x4de47a17, 0xe0464d38, 0xd72c8f39, 0x8e92c93b,\n    0xb9f80b3a, 0x3cee443f, 0x0b84863e, 0x523ac03c, 0x6550023d,\n    0x58175e36, 0x6f7d9c37, 0x36c3da35, 0x01a91834, 0x84bf5731,\n    0xb3d59530, 0xea6bd332, 0xdd011133, 0x90e56b24, 0xa78fa925,\n    0xfe31ef27, 0xc95b2d26, 0x4c4d6223, 0x7b27a022, 0x2299e620,\n    0x15f32421, 0x28b4782a, 0x1fdeba2b, 0x4660fc29, 0x710a3e28,\n    0xf41c712d, 0xc376b32c, 0x9ac8f52e, 0xada2372f, 0xc08d9a70,\n    0xf7e75871, 0xae591e73, 0x9933dc72, 0x1c259377, 0x2b4f5176,\n    0x72f11774, 0x459bd575, 0x78dc897e, 0x4fb64b7f, 0x16080d7d,\n    0x2162cf7c, 0xa4748079, 0x931e4278, 0xcaa0047a, 0xfdcac67b,\n    0xb02ebc6c, 0x87447e6d, 0xdefa386f, 0xe990fa6e, 0x6c86b56b,\n    0x5bec776a, 0x02523168, 0x3538f369, 0x087faf62, 0x3f156d63,\n    0x66ab2b61, 0x51c1e960, 0xd4d7a665, 0xe3bd6464, 0xba032266,\n    0x8d69e067, 0x20cbd748, 0x17a11549, 0x4e1f534b, 0x7975914a,\n    0xfc63de4f, 0xcb091c4e, 0x92b75a4c, 0xa5dd984d, 0x989ac446,\n    0xaff00647, 0xf64e4045, 0xc1248244, 0x4432cd41, 0x73580f40,\n    0x2ae64942, 0x1d8c8b43, 0x5068f154, 0x67023355, 0x3ebc7557,\n    0x09d6b756, 0x8cc0f853, 0xbbaa3a52, 0xe2147c50, 0xd57ebe51,\n    0xe839e25a, 0xdf53205b, 0x86ed6659, 0xb187a458, 0x3491eb5d,\n    0x03fb295c, 0x5a456f5e, 0x6d2fad5f, 0x801b35e1, 0xb771f7e0,\n    0xeecfb1e2, 0xd9a573e3, 0x5cb33ce6, 0x6bd9fee7, 0x3267b8e5,\n    0x050d7ae4, 0x384a26ef, 0x0f20e4ee, 0x569ea2ec, 0x61f460ed,\n    0xe4e22fe8, 0xd388ede9, 0x8a36abeb, 0xbd5c69ea, 0xf0b813fd,\n    0xc7d2d1fc, 0x9e6c97fe, 0xa90655ff, 0x2c101afa, 0x1b7ad8fb,\n    0x42c49ef9, 0x75ae5cf8, 0x48e900f3, 0x7f83c2f2, 0x263d84f0,\n    0x115746f1, 0x944109f4, 0xa32bcbf5, 0xfa958df7, 0xcdff4ff6,\n    0x605d78d9, 0x5737bad8, 0x0e89fcda, 0x39e33edb, 0xbcf571de,\n    0x8b9fb3df, 0xd221f5dd, 0xe54b37dc, 0xd80c6bd7, 0xef66a9d6,\n    0xb6d8efd4, 0x81b22dd5, 0x04a462d0, 0x33cea0d1, 0x6a70e6d3,\n    0x5d1a24d2, 0x10fe5ec5, 0x27949cc4, 0x7e2adac6, 0x494018c7,\n    0xcc5657c2, 0xfb3c95c3, 0xa282d3c1, 0x95e811c0, 0xa8af4dcb,\n    0x9fc58fca, 0xc67bc9c8, 0xf1110bc9, 0x740744cc, 0x436d86cd,\n    0x1ad3c0cf, 0x2db902ce, 0x4096af91, 0x77fc6d90, 0x2e422b92,\n    0x1928e993, 0x9c3ea696, 0xab546497, 0xf2ea2295, 0xc580e094,\n    0xf8c7bc9f, 0xcfad7e9e, 0x9613389c, 0xa179fa9d, 0x246fb598,\n    0x13057799, 0x4abb319b, 0x7dd1f39a, 0x3035898d, 0x075f4b8c,\n    0x5ee10d8e, 0x698bcf8f, 0xec9d808a, 0xdbf7428b, 0x82490489,\n    0xb523c688, 0x88649a83, 0xbf0e5882, 0xe6b01e80, 0xd1dadc81,\n    0x54cc9384, 0x63a65185, 0x3a181787, 0x0d72d586, 0xa0d0e2a9,\n    0x97ba20a8, 0xce0466aa, 0xf96ea4ab, 0x7c78ebae, 0x4b1229af,\n    0x12ac6fad, 0x25c6adac, 0x1881f1a7, 0x2feb33a6, 0x765575a4,\n    0x413fb7a5, 0xc429f8a0, 0xf3433aa1, 0xaafd7ca3, 0x9d97bea2,\n    0xd073c4b5, 0xe71906b4, 0xbea740b6, 0x89cd82b7, 0x0cdbcdb2,\n    0x3bb10fb3, 0x620f49b1, 0x55658bb0, 0x6822d7bb, 0x5f4815ba,\n    0x06f653b8, 0x319c91b9, 0xb48adebc, 0x83e01cbd, 0xda5e5abf,\n    0xed3498be},\n   {0x00000000, 0x6567bcb8, 0x8bc809aa, 0xeeafb512, 0x5797628f,\n    0x32f0de37, 0xdc5f6b25, 0xb938d79d, 0xef28b4c5, 0x8a4f087d,\n    0x64e0bd6f, 0x018701d7, 0xb8bfd64a, 0xddd86af2, 0x3377dfe0,\n    0x56106358, 0x9f571950, 0xfa30a5e8, 0x149f10fa, 0x71f8ac42,\n    0xc8c07bdf, 0xada7c767, 0x43087275, 0x266fcecd, 0x707fad95,\n    0x1518112d, 0xfbb7a43f, 0x9ed01887, 0x27e8cf1a, 0x428f73a2,\n    0xac20c6b0, 0xc9477a08, 0x3eaf32a0, 0x5bc88e18, 0xb5673b0a,\n    0xd00087b2, 0x6938502f, 0x0c5fec97, 0xe2f05985, 0x8797e53d,\n    0xd1878665, 0xb4e03add, 0x5a4f8fcf, 0x3f283377, 0x8610e4ea,\n    0xe3775852, 0x0dd8ed40, 0x68bf51f8, 0xa1f82bf0, 0xc49f9748,\n    0x2a30225a, 0x4f579ee2, 0xf66f497f, 0x9308f5c7, 0x7da740d5,\n    0x18c0fc6d, 0x4ed09f35, 0x2bb7238d, 0xc518969f, 0xa07f2a27,\n    0x1947fdba, 0x7c204102, 0x928ff410, 0xf7e848a8, 0x3d58149b,\n    0x583fa823, 0xb6901d31, 0xd3f7a189, 0x6acf7614, 0x0fa8caac,\n    0xe1077fbe, 0x8460c306, 0xd270a05e, 0xb7171ce6, 0x59b8a9f4,\n    0x3cdf154c, 0x85e7c2d1, 0xe0807e69, 0x0e2fcb7b, 0x6b4877c3,\n    0xa20f0dcb, 0xc768b173, 0x29c70461, 0x4ca0b8d9, 0xf5986f44,\n    0x90ffd3fc, 0x7e5066ee, 0x1b37da56, 0x4d27b90e, 0x284005b6,\n    0xc6efb0a4, 0xa3880c1c, 0x1ab0db81, 0x7fd76739, 0x9178d22b,\n    0xf41f6e93, 0x03f7263b, 0x66909a83, 0x883f2f91, 0xed589329,\n    0x546044b4, 0x3107f80c, 0xdfa84d1e, 0xbacff1a6, 0xecdf92fe,\n    0x89b82e46, 0x67179b54, 0x027027ec, 0xbb48f071, 0xde2f4cc9,\n    0x3080f9db, 0x55e74563, 0x9ca03f6b, 0xf9c783d3, 0x176836c1,\n    0x720f8a79, 0xcb375de4, 0xae50e15c, 0x40ff544e, 0x2598e8f6,\n    0x73888bae, 0x16ef3716, 0xf8408204, 0x9d273ebc, 0x241fe921,\n    0x41785599, 0xafd7e08b, 0xcab05c33, 0x3bb659ed, 0x5ed1e555,\n    0xb07e5047, 0xd519ecff, 0x6c213b62, 0x094687da, 0xe7e932c8,\n    0x828e8e70, 0xd49eed28, 0xb1f95190, 0x5f56e482, 0x3a31583a,\n    0x83098fa7, 0xe66e331f, 0x08c1860d, 0x6da63ab5, 0xa4e140bd,\n    0xc186fc05, 0x2f294917, 0x4a4ef5af, 0xf3762232, 0x96119e8a,\n    0x78be2b98, 0x1dd99720, 0x4bc9f478, 0x2eae48c0, 0xc001fdd2,\n    0xa566416a, 0x1c5e96f7, 0x79392a4f, 0x97969f5d, 0xf2f123e5,\n    0x05196b4d, 0x607ed7f5, 0x8ed162e7, 0xebb6de5f, 0x528e09c2,\n    0x37e9b57a, 0xd9460068, 0xbc21bcd0, 0xea31df88, 0x8f566330,\n    0x61f9d622, 0x049e6a9a, 0xbda6bd07, 0xd8c101bf, 0x366eb4ad,\n    0x53090815, 0x9a4e721d, 0xff29cea5, 0x11867bb7, 0x74e1c70f,\n    0xcdd91092, 0xa8beac2a, 0x46111938, 0x2376a580, 0x7566c6d8,\n    0x10017a60, 0xfeaecf72, 0x9bc973ca, 0x22f1a457, 0x479618ef,\n    0xa939adfd, 0xcc5e1145, 0x06ee4d76, 0x6389f1ce, 0x8d2644dc,\n    0xe841f864, 0x51792ff9, 0x341e9341, 0xdab12653, 0xbfd69aeb,\n    0xe9c6f9b3, 0x8ca1450b, 0x620ef019, 0x07694ca1, 0xbe519b3c,\n    0xdb362784, 0x35999296, 0x50fe2e2e, 0x99b95426, 0xfcdee89e,\n    0x12715d8c, 0x7716e134, 0xce2e36a9, 0xab498a11, 0x45e63f03,\n    0x208183bb, 0x7691e0e3, 0x13f65c5b, 0xfd59e949, 0x983e55f1,\n    0x2106826c, 0x44613ed4, 0xaace8bc6, 0xcfa9377e, 0x38417fd6,\n    0x5d26c36e, 0xb389767c, 0xd6eecac4, 0x6fd61d59, 0x0ab1a1e1,\n    0xe41e14f3, 0x8179a84b, 0xd769cb13, 0xb20e77ab, 0x5ca1c2b9,\n    0x39c67e01, 0x80fea99c, 0xe5991524, 0x0b36a036, 0x6e511c8e,\n    0xa7166686, 0xc271da3e, 0x2cde6f2c, 0x49b9d394, 0xf0810409,\n    0x95e6b8b1, 0x7b490da3, 0x1e2eb11b, 0x483ed243, 0x2d596efb,\n    0xc3f6dbe9, 0xa6916751, 0x1fa9b0cc, 0x7ace0c74, 0x9461b966,\n    0xf10605de}};\n\n#endif\n\n#endif\n\n#if N == 2\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87,\n    0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede,\n    0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab,\n    0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c,\n    0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1,\n    0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7,\n    0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e,\n    0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308,\n    0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5,\n    0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472,\n    0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07,\n    0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e,\n    0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa,\n    0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec,\n    0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6,\n    0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0,\n    0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3,\n    0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba,\n    0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf,\n    0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975,\n    0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8,\n    0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde,\n    0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a,\n    0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c,\n    0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1,\n    0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65,\n    0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410,\n    0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649,\n    0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a,\n    0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c,\n    0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946,\n    0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450,\n    0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e,\n    0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857,\n    0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022,\n    0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5,\n    0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758,\n    0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e,\n    0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d,\n    0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b,\n    0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6,\n    0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401,\n    0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74,\n    0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d,\n    0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073,\n    0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65,\n    0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f,\n    0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749,\n    0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a,\n    0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033,\n    0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846,\n    0x0d7139d7},\n   {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563,\n    0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f,\n    0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875,\n    0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536,\n    0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8,\n    0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43,\n    0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f,\n    0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184,\n    0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a,\n    0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39,\n    0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523,\n    0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f,\n    0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d,\n    0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6,\n    0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b,\n    0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0,\n    0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151,\n    0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d,\n    0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47,\n    0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a,\n    0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964,\n    0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef,\n    0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d,\n    0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6,\n    0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348,\n    0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53,\n    0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449,\n    0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645,\n    0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4,\n    0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f,\n    0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2,\n    0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69,\n    0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46,\n    0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a,\n    0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650,\n    0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13,\n    0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded,\n    0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366,\n    0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57,\n    0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc,\n    0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222,\n    0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61,\n    0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b,\n    0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277,\n    0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558,\n    0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3,\n    0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e,\n    0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5,\n    0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74,\n    0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78,\n    0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262,\n    0x1c53e98a},\n   {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b,\n    0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40,\n    0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580,\n    0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7,\n    0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a,\n    0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37,\n    0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75,\n    0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218,\n    0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5,\n    0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2,\n    0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02,\n    0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59,\n    0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1,\n    0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c,\n    0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a,\n    0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307,\n    0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486,\n    0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd,\n    0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d,\n    0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2,\n    0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f,\n    0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72,\n    0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8,\n    0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985,\n    0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268,\n    0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94,\n    0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454,\n    0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f,\n    0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e,\n    0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3,\n    0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915,\n    0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778,\n    0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821,\n    0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a,\n    0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba,\n    0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d,\n    0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560,\n    0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d,\n    0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe,\n    0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3,\n    0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e,\n    0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509,\n    0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9,\n    0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92,\n    0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb,\n    0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6,\n    0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50,\n    0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d,\n    0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc,\n    0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7,\n    0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927,\n    0x3f88e851},\n   {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96,\n    0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8,\n    0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0,\n    0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14,\n    0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7,\n    0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4,\n    0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe,\n    0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad,\n    0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e,\n    0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa,\n    0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2,\n    0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c,\n    0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab,\n    0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8,\n    0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d,\n    0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e,\n    0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7,\n    0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99,\n    0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1,\n    0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690,\n    0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933,\n    0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20,\n    0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf,\n    0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc,\n    0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f,\n    0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92,\n    0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca,\n    0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4,\n    0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd,\n    0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de,\n    0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb,\n    0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8,\n    0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474,\n    0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a,\n    0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252,\n    0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6,\n    0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55,\n    0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846,\n    0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7,\n    0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4,\n    0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47,\n    0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3,\n    0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb,\n    0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5,\n    0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49,\n    0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a,\n    0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f,\n    0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c,\n    0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305,\n    0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b,\n    0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523,\n    0x3dee8ca6},\n   {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f,\n    0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91,\n    0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e,\n    0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c,\n    0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02,\n    0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12,\n    0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567,\n    0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277,\n    0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679,\n    0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b,\n    0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4,\n    0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a,\n    0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0,\n    0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0,\n    0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91,\n    0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881,\n    0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173,\n    0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d,\n    0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912,\n    0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8,\n    0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6,\n    0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6,\n    0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b,\n    0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b,\n    0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75,\n    0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f,\n    0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00,\n    0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee,\n    0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c,\n    0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c,\n    0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d,\n    0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d,\n    0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67,\n    0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89,\n    0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706,\n    0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14,\n    0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a,\n    0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a,\n    0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f,\n    0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f,\n    0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591,\n    0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983,\n    0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c,\n    0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2,\n    0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8,\n    0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8,\n    0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89,\n    0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99,\n    0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b,\n    0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485,\n    0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a,\n    0x36197165},\n   {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382,\n    0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85,\n    0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06,\n    0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca,\n    0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e,\n    0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc,\n    0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616,\n    0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54,\n    0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10,\n    0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc,\n    0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f,\n    0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58,\n    0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef,\n    0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad,\n    0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b,\n    0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29,\n    0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6,\n    0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1,\n    0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622,\n    0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039,\n    0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d,\n    0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f,\n    0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32,\n    0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770,\n    0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034,\n    0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f,\n    0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc,\n    0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db,\n    0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154,\n    0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16,\n    0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0,\n    0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592,\n    0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca,\n    0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd,\n    0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e,\n    0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882,\n    0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6,\n    0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384,\n    0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1,\n    0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3,\n    0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7,\n    0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b,\n    0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8,\n    0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff,\n    0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7,\n    0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5,\n    0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23,\n    0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761,\n    0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee,\n    0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9,\n    0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a,\n    0x1a3b93aa},\n   {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a,\n    0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca,\n    0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3,\n    0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb,\n    0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c,\n    0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58,\n    0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed,\n    0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9,\n    0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e,\n    0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906,\n    0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f,\n    0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf,\n    0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0,\n    0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4,\n    0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769,\n    0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d,\n    0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632,\n    0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82,\n    0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb,\n    0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73,\n    0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484,\n    0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0,\n    0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5,\n    0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1,\n    0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516,\n    0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f,\n    0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946,\n    0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6,\n    0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9,\n    0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad,\n    0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820,\n    0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364,\n    0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab,\n    0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b,\n    0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62,\n    0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a,\n    0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd,\n    0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089,\n    0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c,\n    0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8,\n    0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f,\n    0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477,\n    0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e,\n    0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be,\n    0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71,\n    0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635,\n    0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8,\n    0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc,\n    0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3,\n    0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753,\n    0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a,\n    0xe147d714},\n   {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c,\n    0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b,\n    0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92,\n    0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4,\n    0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069,\n    0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526,\n    0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25,\n    0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a,\n    0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7,\n    0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491,\n    0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958,\n    0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f,\n    0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307,\n    0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648,\n    0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999,\n    0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6,\n    0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a,\n    0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d,\n    0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4,\n    0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61,\n    0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc,\n    0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3,\n    0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53,\n    0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c,\n    0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1,\n    0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c,\n    0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5,\n    0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92,\n    0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e,\n    0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771,\n    0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0,\n    0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def,\n    0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0,\n    0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7,\n    0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e,\n    0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58,\n    0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285,\n    0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca,\n    0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce,\n    0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81,\n    0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c,\n    0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a,\n    0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3,\n    0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4,\n    0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb,\n    0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4,\n    0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75,\n    0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a,\n    0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296,\n    0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1,\n    0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808,\n    0x494f0c4b}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0x43147b1700000000, 0x8628f62e00000000,\n    0xc53c8d3900000000, 0x0c51ec5d00000000, 0x4f45974a00000000,\n    0x8a791a7300000000, 0xc96d616400000000, 0x18a2d8bb00000000,\n    0x5bb6a3ac00000000, 0x9e8a2e9500000000, 0xdd9e558200000000,\n    0x14f334e600000000, 0x57e74ff100000000, 0x92dbc2c800000000,\n    0xd1cfb9df00000000, 0x7142c0ac00000000, 0x3256bbbb00000000,\n    0xf76a368200000000, 0xb47e4d9500000000, 0x7d132cf100000000,\n    0x3e0757e600000000, 0xfb3bdadf00000000, 0xb82fa1c800000000,\n    0x69e0181700000000, 0x2af4630000000000, 0xefc8ee3900000000,\n    0xacdc952e00000000, 0x65b1f44a00000000, 0x26a58f5d00000000,\n    0xe399026400000000, 0xa08d797300000000, 0xa382f18200000000,\n    0xe0968a9500000000, 0x25aa07ac00000000, 0x66be7cbb00000000,\n    0xafd31ddf00000000, 0xecc766c800000000, 0x29fbebf100000000,\n    0x6aef90e600000000, 0xbb20293900000000, 0xf834522e00000000,\n    0x3d08df1700000000, 0x7e1ca40000000000, 0xb771c56400000000,\n    0xf465be7300000000, 0x3159334a00000000, 0x724d485d00000000,\n    0xd2c0312e00000000, 0x91d44a3900000000, 0x54e8c70000000000,\n    0x17fcbc1700000000, 0xde91dd7300000000, 0x9d85a66400000000,\n    0x58b92b5d00000000, 0x1bad504a00000000, 0xca62e99500000000,\n    0x8976928200000000, 0x4c4a1fbb00000000, 0x0f5e64ac00000000,\n    0xc63305c800000000, 0x85277edf00000000, 0x401bf3e600000000,\n    0x030f88f100000000, 0x070392de00000000, 0x4417e9c900000000,\n    0x812b64f000000000, 0xc23f1fe700000000, 0x0b527e8300000000,\n    0x4846059400000000, 0x8d7a88ad00000000, 0xce6ef3ba00000000,\n    0x1fa14a6500000000, 0x5cb5317200000000, 0x9989bc4b00000000,\n    0xda9dc75c00000000, 0x13f0a63800000000, 0x50e4dd2f00000000,\n    0x95d8501600000000, 0xd6cc2b0100000000, 0x7641527200000000,\n    0x3555296500000000, 0xf069a45c00000000, 0xb37ddf4b00000000,\n    0x7a10be2f00000000, 0x3904c53800000000, 0xfc38480100000000,\n    0xbf2c331600000000, 0x6ee38ac900000000, 0x2df7f1de00000000,\n    0xe8cb7ce700000000, 0xabdf07f000000000, 0x62b2669400000000,\n    0x21a61d8300000000, 0xe49a90ba00000000, 0xa78eebad00000000,\n    0xa481635c00000000, 0xe795184b00000000, 0x22a9957200000000,\n    0x61bdee6500000000, 0xa8d08f0100000000, 0xebc4f41600000000,\n    0x2ef8792f00000000, 0x6dec023800000000, 0xbc23bbe700000000,\n    0xff37c0f000000000, 0x3a0b4dc900000000, 0x791f36de00000000,\n    0xb07257ba00000000, 0xf3662cad00000000, 0x365aa19400000000,\n    0x754eda8300000000, 0xd5c3a3f000000000, 0x96d7d8e700000000,\n    0x53eb55de00000000, 0x10ff2ec900000000, 0xd9924fad00000000,\n    0x9a8634ba00000000, 0x5fbab98300000000, 0x1caec29400000000,\n    0xcd617b4b00000000, 0x8e75005c00000000, 0x4b498d6500000000,\n    0x085df67200000000, 0xc130971600000000, 0x8224ec0100000000,\n    0x4718613800000000, 0x040c1a2f00000000, 0x4f00556600000000,\n    0x0c142e7100000000, 0xc928a34800000000, 0x8a3cd85f00000000,\n    0x4351b93b00000000, 0x0045c22c00000000, 0xc5794f1500000000,\n    0x866d340200000000, 0x57a28ddd00000000, 0x14b6f6ca00000000,\n    0xd18a7bf300000000, 0x929e00e400000000, 0x5bf3618000000000,\n    0x18e71a9700000000, 0xdddb97ae00000000, 0x9ecfecb900000000,\n    0x3e4295ca00000000, 0x7d56eedd00000000, 0xb86a63e400000000,\n    0xfb7e18f300000000, 0x3213799700000000, 0x7107028000000000,\n    0xb43b8fb900000000, 0xf72ff4ae00000000, 0x26e04d7100000000,\n    0x65f4366600000000, 0xa0c8bb5f00000000, 0xe3dcc04800000000,\n    0x2ab1a12c00000000, 0x69a5da3b00000000, 0xac99570200000000,\n    0xef8d2c1500000000, 0xec82a4e400000000, 0xaf96dff300000000,\n    0x6aaa52ca00000000, 0x29be29dd00000000, 0xe0d348b900000000,\n    0xa3c733ae00000000, 0x66fbbe9700000000, 0x25efc58000000000,\n    0xf4207c5f00000000, 0xb734074800000000, 0x72088a7100000000,\n    0x311cf16600000000, 0xf871900200000000, 0xbb65eb1500000000,\n    0x7e59662c00000000, 0x3d4d1d3b00000000, 0x9dc0644800000000,\n    0xded41f5f00000000, 0x1be8926600000000, 0x58fce97100000000,\n    0x9191881500000000, 0xd285f30200000000, 0x17b97e3b00000000,\n    0x54ad052c00000000, 0x8562bcf300000000, 0xc676c7e400000000,\n    0x034a4add00000000, 0x405e31ca00000000, 0x893350ae00000000,\n    0xca272bb900000000, 0x0f1ba68000000000, 0x4c0fdd9700000000,\n    0x4803c7b800000000, 0x0b17bcaf00000000, 0xce2b319600000000,\n    0x8d3f4a8100000000, 0x44522be500000000, 0x074650f200000000,\n    0xc27addcb00000000, 0x816ea6dc00000000, 0x50a11f0300000000,\n    0x13b5641400000000, 0xd689e92d00000000, 0x959d923a00000000,\n    0x5cf0f35e00000000, 0x1fe4884900000000, 0xdad8057000000000,\n    0x99cc7e6700000000, 0x3941071400000000, 0x7a557c0300000000,\n    0xbf69f13a00000000, 0xfc7d8a2d00000000, 0x3510eb4900000000,\n    0x7604905e00000000, 0xb3381d6700000000, 0xf02c667000000000,\n    0x21e3dfaf00000000, 0x62f7a4b800000000, 0xa7cb298100000000,\n    0xe4df529600000000, 0x2db233f200000000, 0x6ea648e500000000,\n    0xab9ac5dc00000000, 0xe88ebecb00000000, 0xeb81363a00000000,\n    0xa8954d2d00000000, 0x6da9c01400000000, 0x2ebdbb0300000000,\n    0xe7d0da6700000000, 0xa4c4a17000000000, 0x61f82c4900000000,\n    0x22ec575e00000000, 0xf323ee8100000000, 0xb037959600000000,\n    0x750b18af00000000, 0x361f63b800000000, 0xff7202dc00000000,\n    0xbc6679cb00000000, 0x795af4f200000000, 0x3a4e8fe500000000,\n    0x9ac3f69600000000, 0xd9d78d8100000000, 0x1ceb00b800000000,\n    0x5fff7baf00000000, 0x96921acb00000000, 0xd58661dc00000000,\n    0x10baece500000000, 0x53ae97f200000000, 0x82612e2d00000000,\n    0xc175553a00000000, 0x0449d80300000000, 0x475da31400000000,\n    0x8e30c27000000000, 0xcd24b96700000000, 0x0818345e00000000,\n    0x4b0c4f4900000000},\n   {0x0000000000000000, 0x3e6bc2ef00000000, 0x3dd0f50400000000,\n    0x03bb37eb00000000, 0x7aa0eb0900000000, 0x44cb29e600000000,\n    0x47701e0d00000000, 0x791bdce200000000, 0xf440d71300000000,\n    0xca2b15fc00000000, 0xc990221700000000, 0xf7fbe0f800000000,\n    0x8ee03c1a00000000, 0xb08bfef500000000, 0xb330c91e00000000,\n    0x8d5b0bf100000000, 0xe881ae2700000000, 0xd6ea6cc800000000,\n    0xd5515b2300000000, 0xeb3a99cc00000000, 0x9221452e00000000,\n    0xac4a87c100000000, 0xaff1b02a00000000, 0x919a72c500000000,\n    0x1cc1793400000000, 0x22aabbdb00000000, 0x21118c3000000000,\n    0x1f7a4edf00000000, 0x6661923d00000000, 0x580a50d200000000,\n    0x5bb1673900000000, 0x65daa5d600000000, 0xd0035d4f00000000,\n    0xee689fa000000000, 0xedd3a84b00000000, 0xd3b86aa400000000,\n    0xaaa3b64600000000, 0x94c874a900000000, 0x9773434200000000,\n    0xa91881ad00000000, 0x24438a5c00000000, 0x1a2848b300000000,\n    0x19937f5800000000, 0x27f8bdb700000000, 0x5ee3615500000000,\n    0x6088a3ba00000000, 0x6333945100000000, 0x5d5856be00000000,\n    0x3882f36800000000, 0x06e9318700000000, 0x0552066c00000000,\n    0x3b39c48300000000, 0x4222186100000000, 0x7c49da8e00000000,\n    0x7ff2ed6500000000, 0x41992f8a00000000, 0xccc2247b00000000,\n    0xf2a9e69400000000, 0xf112d17f00000000, 0xcf79139000000000,\n    0xb662cf7200000000, 0x88090d9d00000000, 0x8bb23a7600000000,\n    0xb5d9f89900000000, 0xa007ba9e00000000, 0x9e6c787100000000,\n    0x9dd74f9a00000000, 0xa3bc8d7500000000, 0xdaa7519700000000,\n    0xe4cc937800000000, 0xe777a49300000000, 0xd91c667c00000000,\n    0x54476d8d00000000, 0x6a2caf6200000000, 0x6997988900000000,\n    0x57fc5a6600000000, 0x2ee7868400000000, 0x108c446b00000000,\n    0x1337738000000000, 0x2d5cb16f00000000, 0x488614b900000000,\n    0x76edd65600000000, 0x7556e1bd00000000, 0x4b3d235200000000,\n    0x3226ffb000000000, 0x0c4d3d5f00000000, 0x0ff60ab400000000,\n    0x319dc85b00000000, 0xbcc6c3aa00000000, 0x82ad014500000000,\n    0x811636ae00000000, 0xbf7df44100000000, 0xc66628a300000000,\n    0xf80dea4c00000000, 0xfbb6dda700000000, 0xc5dd1f4800000000,\n    0x7004e7d100000000, 0x4e6f253e00000000, 0x4dd412d500000000,\n    0x73bfd03a00000000, 0x0aa40cd800000000, 0x34cfce3700000000,\n    0x3774f9dc00000000, 0x091f3b3300000000, 0x844430c200000000,\n    0xba2ff22d00000000, 0xb994c5c600000000, 0x87ff072900000000,\n    0xfee4dbcb00000000, 0xc08f192400000000, 0xc3342ecf00000000,\n    0xfd5fec2000000000, 0x988549f600000000, 0xa6ee8b1900000000,\n    0xa555bcf200000000, 0x9b3e7e1d00000000, 0xe225a2ff00000000,\n    0xdc4e601000000000, 0xdff557fb00000000, 0xe19e951400000000,\n    0x6cc59ee500000000, 0x52ae5c0a00000000, 0x51156be100000000,\n    0x6f7ea90e00000000, 0x166575ec00000000, 0x280eb70300000000,\n    0x2bb580e800000000, 0x15de420700000000, 0x010905e600000000,\n    0x3f62c70900000000, 0x3cd9f0e200000000, 0x02b2320d00000000,\n    0x7ba9eeef00000000, 0x45c22c0000000000, 0x46791beb00000000,\n    0x7812d90400000000, 0xf549d2f500000000, 0xcb22101a00000000,\n    0xc89927f100000000, 0xf6f2e51e00000000, 0x8fe939fc00000000,\n    0xb182fb1300000000, 0xb239ccf800000000, 0x8c520e1700000000,\n    0xe988abc100000000, 0xd7e3692e00000000, 0xd4585ec500000000,\n    0xea339c2a00000000, 0x932840c800000000, 0xad43822700000000,\n    0xaef8b5cc00000000, 0x9093772300000000, 0x1dc87cd200000000,\n    0x23a3be3d00000000, 0x201889d600000000, 0x1e734b3900000000,\n    0x676897db00000000, 0x5903553400000000, 0x5ab862df00000000,\n    0x64d3a03000000000, 0xd10a58a900000000, 0xef619a4600000000,\n    0xecdaadad00000000, 0xd2b16f4200000000, 0xabaab3a000000000,\n    0x95c1714f00000000, 0x967a46a400000000, 0xa811844b00000000,\n    0x254a8fba00000000, 0x1b214d5500000000, 0x189a7abe00000000,\n    0x26f1b85100000000, 0x5fea64b300000000, 0x6181a65c00000000,\n    0x623a91b700000000, 0x5c51535800000000, 0x398bf68e00000000,\n    0x07e0346100000000, 0x045b038a00000000, 0x3a30c16500000000,\n    0x432b1d8700000000, 0x7d40df6800000000, 0x7efbe88300000000,\n    0x40902a6c00000000, 0xcdcb219d00000000, 0xf3a0e37200000000,\n    0xf01bd49900000000, 0xce70167600000000, 0xb76bca9400000000,\n    0x8900087b00000000, 0x8abb3f9000000000, 0xb4d0fd7f00000000,\n    0xa10ebf7800000000, 0x9f657d9700000000, 0x9cde4a7c00000000,\n    0xa2b5889300000000, 0xdbae547100000000, 0xe5c5969e00000000,\n    0xe67ea17500000000, 0xd815639a00000000, 0x554e686b00000000,\n    0x6b25aa8400000000, 0x689e9d6f00000000, 0x56f55f8000000000,\n    0x2fee836200000000, 0x1185418d00000000, 0x123e766600000000,\n    0x2c55b48900000000, 0x498f115f00000000, 0x77e4d3b000000000,\n    0x745fe45b00000000, 0x4a3426b400000000, 0x332ffa5600000000,\n    0x0d4438b900000000, 0x0eff0f5200000000, 0x3094cdbd00000000,\n    0xbdcfc64c00000000, 0x83a404a300000000, 0x801f334800000000,\n    0xbe74f1a700000000, 0xc76f2d4500000000, 0xf904efaa00000000,\n    0xfabfd84100000000, 0xc4d41aae00000000, 0x710de23700000000,\n    0x4f6620d800000000, 0x4cdd173300000000, 0x72b6d5dc00000000,\n    0x0bad093e00000000, 0x35c6cbd100000000, 0x367dfc3a00000000,\n    0x08163ed500000000, 0x854d352400000000, 0xbb26f7cb00000000,\n    0xb89dc02000000000, 0x86f602cf00000000, 0xffedde2d00000000,\n    0xc1861cc200000000, 0xc23d2b2900000000, 0xfc56e9c600000000,\n    0x998c4c1000000000, 0xa7e78eff00000000, 0xa45cb91400000000,\n    0x9a377bfb00000000, 0xe32ca71900000000, 0xdd4765f600000000,\n    0xdefc521d00000000, 0xe09790f200000000, 0x6dcc9b0300000000,\n    0x53a759ec00000000, 0x501c6e0700000000, 0x6e77ace800000000,\n    0x176c700a00000000, 0x2907b2e500000000, 0x2abc850e00000000,\n    0x14d747e100000000},\n   {0x0000000000000000, 0xc0df8ec100000000, 0xc1b96c5800000000,\n    0x0166e29900000000, 0x8273d9b000000000, 0x42ac577100000000,\n    0x43cab5e800000000, 0x83153b2900000000, 0x45e1c3ba00000000,\n    0x853e4d7b00000000, 0x8458afe200000000, 0x4487212300000000,\n    0xc7921a0a00000000, 0x074d94cb00000000, 0x062b765200000000,\n    0xc6f4f89300000000, 0xcbc4f6ae00000000, 0x0b1b786f00000000,\n    0x0a7d9af600000000, 0xcaa2143700000000, 0x49b72f1e00000000,\n    0x8968a1df00000000, 0x880e434600000000, 0x48d1cd8700000000,\n    0x8e25351400000000, 0x4efabbd500000000, 0x4f9c594c00000000,\n    0x8f43d78d00000000, 0x0c56eca400000000, 0xcc89626500000000,\n    0xcdef80fc00000000, 0x0d300e3d00000000, 0xd78f9c8600000000,\n    0x1750124700000000, 0x1636f0de00000000, 0xd6e97e1f00000000,\n    0x55fc453600000000, 0x9523cbf700000000, 0x9445296e00000000,\n    0x549aa7af00000000, 0x926e5f3c00000000, 0x52b1d1fd00000000,\n    0x53d7336400000000, 0x9308bda500000000, 0x101d868c00000000,\n    0xd0c2084d00000000, 0xd1a4ead400000000, 0x117b641500000000,\n    0x1c4b6a2800000000, 0xdc94e4e900000000, 0xddf2067000000000,\n    0x1d2d88b100000000, 0x9e38b39800000000, 0x5ee73d5900000000,\n    0x5f81dfc000000000, 0x9f5e510100000000, 0x59aaa99200000000,\n    0x9975275300000000, 0x9813c5ca00000000, 0x58cc4b0b00000000,\n    0xdbd9702200000000, 0x1b06fee300000000, 0x1a601c7a00000000,\n    0xdabf92bb00000000, 0xef1948d600000000, 0x2fc6c61700000000,\n    0x2ea0248e00000000, 0xee7faa4f00000000, 0x6d6a916600000000,\n    0xadb51fa700000000, 0xacd3fd3e00000000, 0x6c0c73ff00000000,\n    0xaaf88b6c00000000, 0x6a2705ad00000000, 0x6b41e73400000000,\n    0xab9e69f500000000, 0x288b52dc00000000, 0xe854dc1d00000000,\n    0xe9323e8400000000, 0x29edb04500000000, 0x24ddbe7800000000,\n    0xe40230b900000000, 0xe564d22000000000, 0x25bb5ce100000000,\n    0xa6ae67c800000000, 0x6671e90900000000, 0x67170b9000000000,\n    0xa7c8855100000000, 0x613c7dc200000000, 0xa1e3f30300000000,\n    0xa085119a00000000, 0x605a9f5b00000000, 0xe34fa47200000000,\n    0x23902ab300000000, 0x22f6c82a00000000, 0xe22946eb00000000,\n    0x3896d45000000000, 0xf8495a9100000000, 0xf92fb80800000000,\n    0x39f036c900000000, 0xbae50de000000000, 0x7a3a832100000000,\n    0x7b5c61b800000000, 0xbb83ef7900000000, 0x7d7717ea00000000,\n    0xbda8992b00000000, 0xbcce7bb200000000, 0x7c11f57300000000,\n    0xff04ce5a00000000, 0x3fdb409b00000000, 0x3ebda20200000000,\n    0xfe622cc300000000, 0xf35222fe00000000, 0x338dac3f00000000,\n    0x32eb4ea600000000, 0xf234c06700000000, 0x7121fb4e00000000,\n    0xb1fe758f00000000, 0xb098971600000000, 0x704719d700000000,\n    0xb6b3e14400000000, 0x766c6f8500000000, 0x770a8d1c00000000,\n    0xb7d503dd00000000, 0x34c038f400000000, 0xf41fb63500000000,\n    0xf57954ac00000000, 0x35a6da6d00000000, 0x9f35e17700000000,\n    0x5fea6fb600000000, 0x5e8c8d2f00000000, 0x9e5303ee00000000,\n    0x1d4638c700000000, 0xdd99b60600000000, 0xdcff549f00000000,\n    0x1c20da5e00000000, 0xdad422cd00000000, 0x1a0bac0c00000000,\n    0x1b6d4e9500000000, 0xdbb2c05400000000, 0x58a7fb7d00000000,\n    0x987875bc00000000, 0x991e972500000000, 0x59c119e400000000,\n    0x54f117d900000000, 0x942e991800000000, 0x95487b8100000000,\n    0x5597f54000000000, 0xd682ce6900000000, 0x165d40a800000000,\n    0x173ba23100000000, 0xd7e42cf000000000, 0x1110d46300000000,\n    0xd1cf5aa200000000, 0xd0a9b83b00000000, 0x107636fa00000000,\n    0x93630dd300000000, 0x53bc831200000000, 0x52da618b00000000,\n    0x9205ef4a00000000, 0x48ba7df100000000, 0x8865f33000000000,\n    0x890311a900000000, 0x49dc9f6800000000, 0xcac9a44100000000,\n    0x0a162a8000000000, 0x0b70c81900000000, 0xcbaf46d800000000,\n    0x0d5bbe4b00000000, 0xcd84308a00000000, 0xcce2d21300000000,\n    0x0c3d5cd200000000, 0x8f2867fb00000000, 0x4ff7e93a00000000,\n    0x4e910ba300000000, 0x8e4e856200000000, 0x837e8b5f00000000,\n    0x43a1059e00000000, 0x42c7e70700000000, 0x821869c600000000,\n    0x010d52ef00000000, 0xc1d2dc2e00000000, 0xc0b43eb700000000,\n    0x006bb07600000000, 0xc69f48e500000000, 0x0640c62400000000,\n    0x072624bd00000000, 0xc7f9aa7c00000000, 0x44ec915500000000,\n    0x84331f9400000000, 0x8555fd0d00000000, 0x458a73cc00000000,\n    0x702ca9a100000000, 0xb0f3276000000000, 0xb195c5f900000000,\n    0x714a4b3800000000, 0xf25f701100000000, 0x3280fed000000000,\n    0x33e61c4900000000, 0xf339928800000000, 0x35cd6a1b00000000,\n    0xf512e4da00000000, 0xf474064300000000, 0x34ab888200000000,\n    0xb7beb3ab00000000, 0x77613d6a00000000, 0x7607dff300000000,\n    0xb6d8513200000000, 0xbbe85f0f00000000, 0x7b37d1ce00000000,\n    0x7a51335700000000, 0xba8ebd9600000000, 0x399b86bf00000000,\n    0xf944087e00000000, 0xf822eae700000000, 0x38fd642600000000,\n    0xfe099cb500000000, 0x3ed6127400000000, 0x3fb0f0ed00000000,\n    0xff6f7e2c00000000, 0x7c7a450500000000, 0xbca5cbc400000000,\n    0xbdc3295d00000000, 0x7d1ca79c00000000, 0xa7a3352700000000,\n    0x677cbbe600000000, 0x661a597f00000000, 0xa6c5d7be00000000,\n    0x25d0ec9700000000, 0xe50f625600000000, 0xe46980cf00000000,\n    0x24b60e0e00000000, 0xe242f69d00000000, 0x229d785c00000000,\n    0x23fb9ac500000000, 0xe324140400000000, 0x60312f2d00000000,\n    0xa0eea1ec00000000, 0xa188437500000000, 0x6157cdb400000000,\n    0x6c67c38900000000, 0xacb84d4800000000, 0xaddeafd100000000,\n    0x6d01211000000000, 0xee141a3900000000, 0x2ecb94f800000000,\n    0x2fad766100000000, 0xef72f8a000000000, 0x2986003300000000,\n    0xe9598ef200000000, 0xe83f6c6b00000000, 0x28e0e2aa00000000,\n    0xabf5d98300000000, 0x6b2a574200000000, 0x6a4cb5db00000000,\n    0xaa933b1a00000000},\n   {0x0000000000000000, 0x6f4ca59b00000000, 0x9f9e3bec00000000,\n    0xf0d29e7700000000, 0x7f3b060300000000, 0x1077a39800000000,\n    0xe0a53def00000000, 0x8fe9987400000000, 0xfe760c0600000000,\n    0x913aa99d00000000, 0x61e837ea00000000, 0x0ea4927100000000,\n    0x814d0a0500000000, 0xee01af9e00000000, 0x1ed331e900000000,\n    0x719f947200000000, 0xfced180c00000000, 0x93a1bd9700000000,\n    0x637323e000000000, 0x0c3f867b00000000, 0x83d61e0f00000000,\n    0xec9abb9400000000, 0x1c4825e300000000, 0x7304807800000000,\n    0x029b140a00000000, 0x6dd7b19100000000, 0x9d052fe600000000,\n    0xf2498a7d00000000, 0x7da0120900000000, 0x12ecb79200000000,\n    0xe23e29e500000000, 0x8d728c7e00000000, 0xf8db311800000000,\n    0x9797948300000000, 0x67450af400000000, 0x0809af6f00000000,\n    0x87e0371b00000000, 0xe8ac928000000000, 0x187e0cf700000000,\n    0x7732a96c00000000, 0x06ad3d1e00000000, 0x69e1988500000000,\n    0x993306f200000000, 0xf67fa36900000000, 0x79963b1d00000000,\n    0x16da9e8600000000, 0xe60800f100000000, 0x8944a56a00000000,\n    0x0436291400000000, 0x6b7a8c8f00000000, 0x9ba812f800000000,\n    0xf4e4b76300000000, 0x7b0d2f1700000000, 0x14418a8c00000000,\n    0xe49314fb00000000, 0x8bdfb16000000000, 0xfa40251200000000,\n    0x950c808900000000, 0x65de1efe00000000, 0x0a92bb6500000000,\n    0x857b231100000000, 0xea37868a00000000, 0x1ae518fd00000000,\n    0x75a9bd6600000000, 0xf0b7633000000000, 0x9ffbc6ab00000000,\n    0x6f2958dc00000000, 0x0065fd4700000000, 0x8f8c653300000000,\n    0xe0c0c0a800000000, 0x10125edf00000000, 0x7f5efb4400000000,\n    0x0ec16f3600000000, 0x618dcaad00000000, 0x915f54da00000000,\n    0xfe13f14100000000, 0x71fa693500000000, 0x1eb6ccae00000000,\n    0xee6452d900000000, 0x8128f74200000000, 0x0c5a7b3c00000000,\n    0x6316dea700000000, 0x93c440d000000000, 0xfc88e54b00000000,\n    0x73617d3f00000000, 0x1c2dd8a400000000, 0xecff46d300000000,\n    0x83b3e34800000000, 0xf22c773a00000000, 0x9d60d2a100000000,\n    0x6db24cd600000000, 0x02fee94d00000000, 0x8d17713900000000,\n    0xe25bd4a200000000, 0x12894ad500000000, 0x7dc5ef4e00000000,\n    0x086c522800000000, 0x6720f7b300000000, 0x97f269c400000000,\n    0xf8becc5f00000000, 0x7757542b00000000, 0x181bf1b000000000,\n    0xe8c96fc700000000, 0x8785ca5c00000000, 0xf61a5e2e00000000,\n    0x9956fbb500000000, 0x698465c200000000, 0x06c8c05900000000,\n    0x8921582d00000000, 0xe66dfdb600000000, 0x16bf63c100000000,\n    0x79f3c65a00000000, 0xf4814a2400000000, 0x9bcdefbf00000000,\n    0x6b1f71c800000000, 0x0453d45300000000, 0x8bba4c2700000000,\n    0xe4f6e9bc00000000, 0x142477cb00000000, 0x7b68d25000000000,\n    0x0af7462200000000, 0x65bbe3b900000000, 0x95697dce00000000,\n    0xfa25d85500000000, 0x75cc402100000000, 0x1a80e5ba00000000,\n    0xea527bcd00000000, 0x851ede5600000000, 0xe06fc76000000000,\n    0x8f2362fb00000000, 0x7ff1fc8c00000000, 0x10bd591700000000,\n    0x9f54c16300000000, 0xf01864f800000000, 0x00cafa8f00000000,\n    0x6f865f1400000000, 0x1e19cb6600000000, 0x71556efd00000000,\n    0x8187f08a00000000, 0xeecb551100000000, 0x6122cd6500000000,\n    0x0e6e68fe00000000, 0xfebcf68900000000, 0x91f0531200000000,\n    0x1c82df6c00000000, 0x73ce7af700000000, 0x831ce48000000000,\n    0xec50411b00000000, 0x63b9d96f00000000, 0x0cf57cf400000000,\n    0xfc27e28300000000, 0x936b471800000000, 0xe2f4d36a00000000,\n    0x8db876f100000000, 0x7d6ae88600000000, 0x12264d1d00000000,\n    0x9dcfd56900000000, 0xf28370f200000000, 0x0251ee8500000000,\n    0x6d1d4b1e00000000, 0x18b4f67800000000, 0x77f853e300000000,\n    0x872acd9400000000, 0xe866680f00000000, 0x678ff07b00000000,\n    0x08c355e000000000, 0xf811cb9700000000, 0x975d6e0c00000000,\n    0xe6c2fa7e00000000, 0x898e5fe500000000, 0x795cc19200000000,\n    0x1610640900000000, 0x99f9fc7d00000000, 0xf6b559e600000000,\n    0x0667c79100000000, 0x692b620a00000000, 0xe459ee7400000000,\n    0x8b154bef00000000, 0x7bc7d59800000000, 0x148b700300000000,\n    0x9b62e87700000000, 0xf42e4dec00000000, 0x04fcd39b00000000,\n    0x6bb0760000000000, 0x1a2fe27200000000, 0x756347e900000000,\n    0x85b1d99e00000000, 0xeafd7c0500000000, 0x6514e47100000000,\n    0x0a5841ea00000000, 0xfa8adf9d00000000, 0x95c67a0600000000,\n    0x10d8a45000000000, 0x7f9401cb00000000, 0x8f469fbc00000000,\n    0xe00a3a2700000000, 0x6fe3a25300000000, 0x00af07c800000000,\n    0xf07d99bf00000000, 0x9f313c2400000000, 0xeeaea85600000000,\n    0x81e20dcd00000000, 0x713093ba00000000, 0x1e7c362100000000,\n    0x9195ae5500000000, 0xfed90bce00000000, 0x0e0b95b900000000,\n    0x6147302200000000, 0xec35bc5c00000000, 0x837919c700000000,\n    0x73ab87b000000000, 0x1ce7222b00000000, 0x930eba5f00000000,\n    0xfc421fc400000000, 0x0c9081b300000000, 0x63dc242800000000,\n    0x1243b05a00000000, 0x7d0f15c100000000, 0x8ddd8bb600000000,\n    0xe2912e2d00000000, 0x6d78b65900000000, 0x023413c200000000,\n    0xf2e68db500000000, 0x9daa282e00000000, 0xe803954800000000,\n    0x874f30d300000000, 0x779daea400000000, 0x18d10b3f00000000,\n    0x9738934b00000000, 0xf87436d000000000, 0x08a6a8a700000000,\n    0x67ea0d3c00000000, 0x1675994e00000000, 0x79393cd500000000,\n    0x89eba2a200000000, 0xe6a7073900000000, 0x694e9f4d00000000,\n    0x06023ad600000000, 0xf6d0a4a100000000, 0x999c013a00000000,\n    0x14ee8d4400000000, 0x7ba228df00000000, 0x8b70b6a800000000,\n    0xe43c133300000000, 0x6bd58b4700000000, 0x04992edc00000000,\n    0xf44bb0ab00000000, 0x9b07153000000000, 0xea98814200000000,\n    0x85d424d900000000, 0x7506baae00000000, 0x1a4a1f3500000000,\n    0x95a3874100000000, 0xfaef22da00000000, 0x0a3dbcad00000000,\n    0x6571193600000000},\n   {0x0000000000000000, 0x85d996dd00000000, 0x4bb55c6000000000,\n    0xce6ccabd00000000, 0x966ab9c000000000, 0x13b32f1d00000000,\n    0xdddfe5a000000000, 0x5806737d00000000, 0x6dd3035a00000000,\n    0xe80a958700000000, 0x26665f3a00000000, 0xa3bfc9e700000000,\n    0xfbb9ba9a00000000, 0x7e602c4700000000, 0xb00ce6fa00000000,\n    0x35d5702700000000, 0xdaa607b400000000, 0x5f7f916900000000,\n    0x91135bd400000000, 0x14cacd0900000000, 0x4cccbe7400000000,\n    0xc91528a900000000, 0x0779e21400000000, 0x82a074c900000000,\n    0xb77504ee00000000, 0x32ac923300000000, 0xfcc0588e00000000,\n    0x7919ce5300000000, 0x211fbd2e00000000, 0xa4c62bf300000000,\n    0x6aaae14e00000000, 0xef73779300000000, 0xf54b7eb300000000,\n    0x7092e86e00000000, 0xbefe22d300000000, 0x3b27b40e00000000,\n    0x6321c77300000000, 0xe6f851ae00000000, 0x28949b1300000000,\n    0xad4d0dce00000000, 0x98987de900000000, 0x1d41eb3400000000,\n    0xd32d218900000000, 0x56f4b75400000000, 0x0ef2c42900000000,\n    0x8b2b52f400000000, 0x4547984900000000, 0xc09e0e9400000000,\n    0x2fed790700000000, 0xaa34efda00000000, 0x6458256700000000,\n    0xe181b3ba00000000, 0xb987c0c700000000, 0x3c5e561a00000000,\n    0xf2329ca700000000, 0x77eb0a7a00000000, 0x423e7a5d00000000,\n    0xc7e7ec8000000000, 0x098b263d00000000, 0x8c52b0e000000000,\n    0xd454c39d00000000, 0x518d554000000000, 0x9fe19ffd00000000,\n    0x1a38092000000000, 0xab918dbd00000000, 0x2e481b6000000000,\n    0xe024d1dd00000000, 0x65fd470000000000, 0x3dfb347d00000000,\n    0xb822a2a000000000, 0x764e681d00000000, 0xf397fec000000000,\n    0xc6428ee700000000, 0x439b183a00000000, 0x8df7d28700000000,\n    0x082e445a00000000, 0x5028372700000000, 0xd5f1a1fa00000000,\n    0x1b9d6b4700000000, 0x9e44fd9a00000000, 0x71378a0900000000,\n    0xf4ee1cd400000000, 0x3a82d66900000000, 0xbf5b40b400000000,\n    0xe75d33c900000000, 0x6284a51400000000, 0xace86fa900000000,\n    0x2931f97400000000, 0x1ce4895300000000, 0x993d1f8e00000000,\n    0x5751d53300000000, 0xd28843ee00000000, 0x8a8e309300000000,\n    0x0f57a64e00000000, 0xc13b6cf300000000, 0x44e2fa2e00000000,\n    0x5edaf30e00000000, 0xdb0365d300000000, 0x156faf6e00000000,\n    0x90b639b300000000, 0xc8b04ace00000000, 0x4d69dc1300000000,\n    0x830516ae00000000, 0x06dc807300000000, 0x3309f05400000000,\n    0xb6d0668900000000, 0x78bcac3400000000, 0xfd653ae900000000,\n    0xa563499400000000, 0x20badf4900000000, 0xeed615f400000000,\n    0x6b0f832900000000, 0x847cf4ba00000000, 0x01a5626700000000,\n    0xcfc9a8da00000000, 0x4a103e0700000000, 0x12164d7a00000000,\n    0x97cfdba700000000, 0x59a3111a00000000, 0xdc7a87c700000000,\n    0xe9aff7e000000000, 0x6c76613d00000000, 0xa21aab8000000000,\n    0x27c33d5d00000000, 0x7fc54e2000000000, 0xfa1cd8fd00000000,\n    0x3470124000000000, 0xb1a9849d00000000, 0x17256aa000000000,\n    0x92fcfc7d00000000, 0x5c9036c000000000, 0xd949a01d00000000,\n    0x814fd36000000000, 0x049645bd00000000, 0xcafa8f0000000000,\n    0x4f2319dd00000000, 0x7af669fa00000000, 0xff2fff2700000000,\n    0x3143359a00000000, 0xb49aa34700000000, 0xec9cd03a00000000,\n    0x694546e700000000, 0xa7298c5a00000000, 0x22f01a8700000000,\n    0xcd836d1400000000, 0x485afbc900000000, 0x8636317400000000,\n    0x03efa7a900000000, 0x5be9d4d400000000, 0xde30420900000000,\n    0x105c88b400000000, 0x95851e6900000000, 0xa0506e4e00000000,\n    0x2589f89300000000, 0xebe5322e00000000, 0x6e3ca4f300000000,\n    0x363ad78e00000000, 0xb3e3415300000000, 0x7d8f8bee00000000,\n    0xf8561d3300000000, 0xe26e141300000000, 0x67b782ce00000000,\n    0xa9db487300000000, 0x2c02deae00000000, 0x7404add300000000,\n    0xf1dd3b0e00000000, 0x3fb1f1b300000000, 0xba68676e00000000,\n    0x8fbd174900000000, 0x0a64819400000000, 0xc4084b2900000000,\n    0x41d1ddf400000000, 0x19d7ae8900000000, 0x9c0e385400000000,\n    0x5262f2e900000000, 0xd7bb643400000000, 0x38c813a700000000,\n    0xbd11857a00000000, 0x737d4fc700000000, 0xf6a4d91a00000000,\n    0xaea2aa6700000000, 0x2b7b3cba00000000, 0xe517f60700000000,\n    0x60ce60da00000000, 0x551b10fd00000000, 0xd0c2862000000000,\n    0x1eae4c9d00000000, 0x9b77da4000000000, 0xc371a93d00000000,\n    0x46a83fe000000000, 0x88c4f55d00000000, 0x0d1d638000000000,\n    0xbcb4e71d00000000, 0x396d71c000000000, 0xf701bb7d00000000,\n    0x72d82da000000000, 0x2ade5edd00000000, 0xaf07c80000000000,\n    0x616b02bd00000000, 0xe4b2946000000000, 0xd167e44700000000,\n    0x54be729a00000000, 0x9ad2b82700000000, 0x1f0b2efa00000000,\n    0x470d5d8700000000, 0xc2d4cb5a00000000, 0x0cb801e700000000,\n    0x8961973a00000000, 0x6612e0a900000000, 0xe3cb767400000000,\n    0x2da7bcc900000000, 0xa87e2a1400000000, 0xf078596900000000,\n    0x75a1cfb400000000, 0xbbcd050900000000, 0x3e1493d400000000,\n    0x0bc1e3f300000000, 0x8e18752e00000000, 0x4074bf9300000000,\n    0xc5ad294e00000000, 0x9dab5a3300000000, 0x1872ccee00000000,\n    0xd61e065300000000, 0x53c7908e00000000, 0x49ff99ae00000000,\n    0xcc260f7300000000, 0x024ac5ce00000000, 0x8793531300000000,\n    0xdf95206e00000000, 0x5a4cb6b300000000, 0x94207c0e00000000,\n    0x11f9ead300000000, 0x242c9af400000000, 0xa1f50c2900000000,\n    0x6f99c69400000000, 0xea40504900000000, 0xb246233400000000,\n    0x379fb5e900000000, 0xf9f37f5400000000, 0x7c2ae98900000000,\n    0x93599e1a00000000, 0x168008c700000000, 0xd8ecc27a00000000,\n    0x5d3554a700000000, 0x053327da00000000, 0x80eab10700000000,\n    0x4e867bba00000000, 0xcb5fed6700000000, 0xfe8a9d4000000000,\n    0x7b530b9d00000000, 0xb53fc12000000000, 0x30e657fd00000000,\n    0x68e0248000000000, 0xed39b25d00000000, 0x235578e000000000,\n    0xa68cee3d00000000},\n   {0x0000000000000000, 0x76e10f9d00000000, 0xadc46ee100000000,\n    0xdb25617c00000000, 0x1b8fac1900000000, 0x6d6ea38400000000,\n    0xb64bc2f800000000, 0xc0aacd6500000000, 0x361e593300000000,\n    0x40ff56ae00000000, 0x9bda37d200000000, 0xed3b384f00000000,\n    0x2d91f52a00000000, 0x5b70fab700000000, 0x80559bcb00000000,\n    0xf6b4945600000000, 0x6c3cb26600000000, 0x1addbdfb00000000,\n    0xc1f8dc8700000000, 0xb719d31a00000000, 0x77b31e7f00000000,\n    0x015211e200000000, 0xda77709e00000000, 0xac967f0300000000,\n    0x5a22eb5500000000, 0x2cc3e4c800000000, 0xf7e685b400000000,\n    0x81078a2900000000, 0x41ad474c00000000, 0x374c48d100000000,\n    0xec6929ad00000000, 0x9a88263000000000, 0xd87864cd00000000,\n    0xae996b5000000000, 0x75bc0a2c00000000, 0x035d05b100000000,\n    0xc3f7c8d400000000, 0xb516c74900000000, 0x6e33a63500000000,\n    0x18d2a9a800000000, 0xee663dfe00000000, 0x9887326300000000,\n    0x43a2531f00000000, 0x35435c8200000000, 0xf5e991e700000000,\n    0x83089e7a00000000, 0x582dff0600000000, 0x2eccf09b00000000,\n    0xb444d6ab00000000, 0xc2a5d93600000000, 0x1980b84a00000000,\n    0x6f61b7d700000000, 0xafcb7ab200000000, 0xd92a752f00000000,\n    0x020f145300000000, 0x74ee1bce00000000, 0x825a8f9800000000,\n    0xf4bb800500000000, 0x2f9ee17900000000, 0x597feee400000000,\n    0x99d5238100000000, 0xef342c1c00000000, 0x34114d6000000000,\n    0x42f042fd00000000, 0xf1f7b94100000000, 0x8716b6dc00000000,\n    0x5c33d7a000000000, 0x2ad2d83d00000000, 0xea78155800000000,\n    0x9c991ac500000000, 0x47bc7bb900000000, 0x315d742400000000,\n    0xc7e9e07200000000, 0xb108efef00000000, 0x6a2d8e9300000000,\n    0x1ccc810e00000000, 0xdc664c6b00000000, 0xaa8743f600000000,\n    0x71a2228a00000000, 0x07432d1700000000, 0x9dcb0b2700000000,\n    0xeb2a04ba00000000, 0x300f65c600000000, 0x46ee6a5b00000000,\n    0x8644a73e00000000, 0xf0a5a8a300000000, 0x2b80c9df00000000,\n    0x5d61c64200000000, 0xabd5521400000000, 0xdd345d8900000000,\n    0x06113cf500000000, 0x70f0336800000000, 0xb05afe0d00000000,\n    0xc6bbf19000000000, 0x1d9e90ec00000000, 0x6b7f9f7100000000,\n    0x298fdd8c00000000, 0x5f6ed21100000000, 0x844bb36d00000000,\n    0xf2aabcf000000000, 0x3200719500000000, 0x44e17e0800000000,\n    0x9fc41f7400000000, 0xe92510e900000000, 0x1f9184bf00000000,\n    0x69708b2200000000, 0xb255ea5e00000000, 0xc4b4e5c300000000,\n    0x041e28a600000000, 0x72ff273b00000000, 0xa9da464700000000,\n    0xdf3b49da00000000, 0x45b36fea00000000, 0x3352607700000000,\n    0xe877010b00000000, 0x9e960e9600000000, 0x5e3cc3f300000000,\n    0x28ddcc6e00000000, 0xf3f8ad1200000000, 0x8519a28f00000000,\n    0x73ad36d900000000, 0x054c394400000000, 0xde69583800000000,\n    0xa88857a500000000, 0x68229ac000000000, 0x1ec3955d00000000,\n    0xc5e6f42100000000, 0xb307fbbc00000000, 0xe2ef738300000000,\n    0x940e7c1e00000000, 0x4f2b1d6200000000, 0x39ca12ff00000000,\n    0xf960df9a00000000, 0x8f81d00700000000, 0x54a4b17b00000000,\n    0x2245bee600000000, 0xd4f12ab000000000, 0xa210252d00000000,\n    0x7935445100000000, 0x0fd44bcc00000000, 0xcf7e86a900000000,\n    0xb99f893400000000, 0x62bae84800000000, 0x145be7d500000000,\n    0x8ed3c1e500000000, 0xf832ce7800000000, 0x2317af0400000000,\n    0x55f6a09900000000, 0x955c6dfc00000000, 0xe3bd626100000000,\n    0x3898031d00000000, 0x4e790c8000000000, 0xb8cd98d600000000,\n    0xce2c974b00000000, 0x1509f63700000000, 0x63e8f9aa00000000,\n    0xa34234cf00000000, 0xd5a33b5200000000, 0x0e865a2e00000000,\n    0x786755b300000000, 0x3a97174e00000000, 0x4c7618d300000000,\n    0x975379af00000000, 0xe1b2763200000000, 0x2118bb5700000000,\n    0x57f9b4ca00000000, 0x8cdcd5b600000000, 0xfa3dda2b00000000,\n    0x0c894e7d00000000, 0x7a6841e000000000, 0xa14d209c00000000,\n    0xd7ac2f0100000000, 0x1706e26400000000, 0x61e7edf900000000,\n    0xbac28c8500000000, 0xcc23831800000000, 0x56aba52800000000,\n    0x204aaab500000000, 0xfb6fcbc900000000, 0x8d8ec45400000000,\n    0x4d24093100000000, 0x3bc506ac00000000, 0xe0e067d000000000,\n    0x9601684d00000000, 0x60b5fc1b00000000, 0x1654f38600000000,\n    0xcd7192fa00000000, 0xbb909d6700000000, 0x7b3a500200000000,\n    0x0ddb5f9f00000000, 0xd6fe3ee300000000, 0xa01f317e00000000,\n    0x1318cac200000000, 0x65f9c55f00000000, 0xbedca42300000000,\n    0xc83dabbe00000000, 0x089766db00000000, 0x7e76694600000000,\n    0xa553083a00000000, 0xd3b207a700000000, 0x250693f100000000,\n    0x53e79c6c00000000, 0x88c2fd1000000000, 0xfe23f28d00000000,\n    0x3e893fe800000000, 0x4868307500000000, 0x934d510900000000,\n    0xe5ac5e9400000000, 0x7f2478a400000000, 0x09c5773900000000,\n    0xd2e0164500000000, 0xa40119d800000000, 0x64abd4bd00000000,\n    0x124adb2000000000, 0xc96fba5c00000000, 0xbf8eb5c100000000,\n    0x493a219700000000, 0x3fdb2e0a00000000, 0xe4fe4f7600000000,\n    0x921f40eb00000000, 0x52b58d8e00000000, 0x2454821300000000,\n    0xff71e36f00000000, 0x8990ecf200000000, 0xcb60ae0f00000000,\n    0xbd81a19200000000, 0x66a4c0ee00000000, 0x1045cf7300000000,\n    0xd0ef021600000000, 0xa60e0d8b00000000, 0x7d2b6cf700000000,\n    0x0bca636a00000000, 0xfd7ef73c00000000, 0x8b9ff8a100000000,\n    0x50ba99dd00000000, 0x265b964000000000, 0xe6f15b2500000000,\n    0x901054b800000000, 0x4b3535c400000000, 0x3dd43a5900000000,\n    0xa75c1c6900000000, 0xd1bd13f400000000, 0x0a98728800000000,\n    0x7c797d1500000000, 0xbcd3b07000000000, 0xca32bfed00000000,\n    0x1117de9100000000, 0x67f6d10c00000000, 0x9142455a00000000,\n    0xe7a34ac700000000, 0x3c862bbb00000000, 0x4a67242600000000,\n    0x8acde94300000000, 0xfc2ce6de00000000, 0x270987a200000000,\n    0x51e8883f00000000},\n   {0x0000000000000000, 0xe8dbfbb900000000, 0x91b186a800000000,\n    0x796a7d1100000000, 0x63657c8a00000000, 0x8bbe873300000000,\n    0xf2d4fa2200000000, 0x1a0f019b00000000, 0x87cc89cf00000000,\n    0x6f17727600000000, 0x167d0f6700000000, 0xfea6f4de00000000,\n    0xe4a9f54500000000, 0x0c720efc00000000, 0x751873ed00000000,\n    0x9dc3885400000000, 0x4f9f624400000000, 0xa74499fd00000000,\n    0xde2ee4ec00000000, 0x36f51f5500000000, 0x2cfa1ece00000000,\n    0xc421e57700000000, 0xbd4b986600000000, 0x559063df00000000,\n    0xc853eb8b00000000, 0x2088103200000000, 0x59e26d2300000000,\n    0xb139969a00000000, 0xab36970100000000, 0x43ed6cb800000000,\n    0x3a8711a900000000, 0xd25cea1000000000, 0x9e3ec58800000000,\n    0x76e53e3100000000, 0x0f8f432000000000, 0xe754b89900000000,\n    0xfd5bb90200000000, 0x158042bb00000000, 0x6cea3faa00000000,\n    0x8431c41300000000, 0x19f24c4700000000, 0xf129b7fe00000000,\n    0x8843caef00000000, 0x6098315600000000, 0x7a9730cd00000000,\n    0x924ccb7400000000, 0xeb26b66500000000, 0x03fd4ddc00000000,\n    0xd1a1a7cc00000000, 0x397a5c7500000000, 0x4010216400000000,\n    0xa8cbdadd00000000, 0xb2c4db4600000000, 0x5a1f20ff00000000,\n    0x23755dee00000000, 0xcbaea65700000000, 0x566d2e0300000000,\n    0xbeb6d5ba00000000, 0xc7dca8ab00000000, 0x2f07531200000000,\n    0x3508528900000000, 0xddd3a93000000000, 0xa4b9d42100000000,\n    0x4c622f9800000000, 0x7d7bfbca00000000, 0x95a0007300000000,\n    0xecca7d6200000000, 0x041186db00000000, 0x1e1e874000000000,\n    0xf6c57cf900000000, 0x8faf01e800000000, 0x6774fa5100000000,\n    0xfab7720500000000, 0x126c89bc00000000, 0x6b06f4ad00000000,\n    0x83dd0f1400000000, 0x99d20e8f00000000, 0x7109f53600000000,\n    0x0863882700000000, 0xe0b8739e00000000, 0x32e4998e00000000,\n    0xda3f623700000000, 0xa3551f2600000000, 0x4b8ee49f00000000,\n    0x5181e50400000000, 0xb95a1ebd00000000, 0xc03063ac00000000,\n    0x28eb981500000000, 0xb528104100000000, 0x5df3ebf800000000,\n    0x249996e900000000, 0xcc426d5000000000, 0xd64d6ccb00000000,\n    0x3e96977200000000, 0x47fcea6300000000, 0xaf2711da00000000,\n    0xe3453e4200000000, 0x0b9ec5fb00000000, 0x72f4b8ea00000000,\n    0x9a2f435300000000, 0x802042c800000000, 0x68fbb97100000000,\n    0x1191c46000000000, 0xf94a3fd900000000, 0x6489b78d00000000,\n    0x8c524c3400000000, 0xf538312500000000, 0x1de3ca9c00000000,\n    0x07eccb0700000000, 0xef3730be00000000, 0x965d4daf00000000,\n    0x7e86b61600000000, 0xacda5c0600000000, 0x4401a7bf00000000,\n    0x3d6bdaae00000000, 0xd5b0211700000000, 0xcfbf208c00000000,\n    0x2764db3500000000, 0x5e0ea62400000000, 0xb6d55d9d00000000,\n    0x2b16d5c900000000, 0xc3cd2e7000000000, 0xbaa7536100000000,\n    0x527ca8d800000000, 0x4873a94300000000, 0xa0a852fa00000000,\n    0xd9c22feb00000000, 0x3119d45200000000, 0xbbf0874e00000000,\n    0x532b7cf700000000, 0x2a4101e600000000, 0xc29afa5f00000000,\n    0xd895fbc400000000, 0x304e007d00000000, 0x49247d6c00000000,\n    0xa1ff86d500000000, 0x3c3c0e8100000000, 0xd4e7f53800000000,\n    0xad8d882900000000, 0x4556739000000000, 0x5f59720b00000000,\n    0xb78289b200000000, 0xcee8f4a300000000, 0x26330f1a00000000,\n    0xf46fe50a00000000, 0x1cb41eb300000000, 0x65de63a200000000,\n    0x8d05981b00000000, 0x970a998000000000, 0x7fd1623900000000,\n    0x06bb1f2800000000, 0xee60e49100000000, 0x73a36cc500000000,\n    0x9b78977c00000000, 0xe212ea6d00000000, 0x0ac911d400000000,\n    0x10c6104f00000000, 0xf81debf600000000, 0x817796e700000000,\n    0x69ac6d5e00000000, 0x25ce42c600000000, 0xcd15b97f00000000,\n    0xb47fc46e00000000, 0x5ca43fd700000000, 0x46ab3e4c00000000,\n    0xae70c5f500000000, 0xd71ab8e400000000, 0x3fc1435d00000000,\n    0xa202cb0900000000, 0x4ad930b000000000, 0x33b34da100000000,\n    0xdb68b61800000000, 0xc167b78300000000, 0x29bc4c3a00000000,\n    0x50d6312b00000000, 0xb80dca9200000000, 0x6a51208200000000,\n    0x828adb3b00000000, 0xfbe0a62a00000000, 0x133b5d9300000000,\n    0x09345c0800000000, 0xe1efa7b100000000, 0x9885daa000000000,\n    0x705e211900000000, 0xed9da94d00000000, 0x054652f400000000,\n    0x7c2c2fe500000000, 0x94f7d45c00000000, 0x8ef8d5c700000000,\n    0x66232e7e00000000, 0x1f49536f00000000, 0xf792a8d600000000,\n    0xc68b7c8400000000, 0x2e50873d00000000, 0x573afa2c00000000,\n    0xbfe1019500000000, 0xa5ee000e00000000, 0x4d35fbb700000000,\n    0x345f86a600000000, 0xdc847d1f00000000, 0x4147f54b00000000,\n    0xa99c0ef200000000, 0xd0f673e300000000, 0x382d885a00000000,\n    0x222289c100000000, 0xcaf9727800000000, 0xb3930f6900000000,\n    0x5b48f4d000000000, 0x89141ec000000000, 0x61cfe57900000000,\n    0x18a5986800000000, 0xf07e63d100000000, 0xea71624a00000000,\n    0x02aa99f300000000, 0x7bc0e4e200000000, 0x931b1f5b00000000,\n    0x0ed8970f00000000, 0xe6036cb600000000, 0x9f6911a700000000,\n    0x77b2ea1e00000000, 0x6dbdeb8500000000, 0x8566103c00000000,\n    0xfc0c6d2d00000000, 0x14d7969400000000, 0x58b5b90c00000000,\n    0xb06e42b500000000, 0xc9043fa400000000, 0x21dfc41d00000000,\n    0x3bd0c58600000000, 0xd30b3e3f00000000, 0xaa61432e00000000,\n    0x42bab89700000000, 0xdf7930c300000000, 0x37a2cb7a00000000,\n    0x4ec8b66b00000000, 0xa6134dd200000000, 0xbc1c4c4900000000,\n    0x54c7b7f000000000, 0x2dadcae100000000, 0xc576315800000000,\n    0x172adb4800000000, 0xfff120f100000000, 0x869b5de000000000,\n    0x6e40a65900000000, 0x744fa7c200000000, 0x9c945c7b00000000,\n    0xe5fe216a00000000, 0x0d25dad300000000, 0x90e6528700000000,\n    0x783da93e00000000, 0x0157d42f00000000, 0xe98c2f9600000000,\n    0xf3832e0d00000000, 0x1b58d5b400000000, 0x6232a8a500000000,\n    0x8ae9531c00000000},\n   {0x0000000000000000, 0x919168ae00000000, 0x6325a08700000000,\n    0xf2b4c82900000000, 0x874c31d400000000, 0x16dd597a00000000,\n    0xe469915300000000, 0x75f8f9fd00000000, 0x4f9f137300000000,\n    0xde0e7bdd00000000, 0x2cbab3f400000000, 0xbd2bdb5a00000000,\n    0xc8d322a700000000, 0x59424a0900000000, 0xabf6822000000000,\n    0x3a67ea8e00000000, 0x9e3e27e600000000, 0x0faf4f4800000000,\n    0xfd1b876100000000, 0x6c8aefcf00000000, 0x1972163200000000,\n    0x88e37e9c00000000, 0x7a57b6b500000000, 0xebc6de1b00000000,\n    0xd1a1349500000000, 0x40305c3b00000000, 0xb284941200000000,\n    0x2315fcbc00000000, 0x56ed054100000000, 0xc77c6def00000000,\n    0x35c8a5c600000000, 0xa459cd6800000000, 0x7d7b3f1700000000,\n    0xecea57b900000000, 0x1e5e9f9000000000, 0x8fcff73e00000000,\n    0xfa370ec300000000, 0x6ba6666d00000000, 0x9912ae4400000000,\n    0x0883c6ea00000000, 0x32e42c6400000000, 0xa37544ca00000000,\n    0x51c18ce300000000, 0xc050e44d00000000, 0xb5a81db000000000,\n    0x2439751e00000000, 0xd68dbd3700000000, 0x471cd59900000000,\n    0xe34518f100000000, 0x72d4705f00000000, 0x8060b87600000000,\n    0x11f1d0d800000000, 0x6409292500000000, 0xf598418b00000000,\n    0x072c89a200000000, 0x96bde10c00000000, 0xacda0b8200000000,\n    0x3d4b632c00000000, 0xcfffab0500000000, 0x5e6ec3ab00000000,\n    0x2b963a5600000000, 0xba0752f800000000, 0x48b39ad100000000,\n    0xd922f27f00000000, 0xfaf67e2e00000000, 0x6b67168000000000,\n    0x99d3dea900000000, 0x0842b60700000000, 0x7dba4ffa00000000,\n    0xec2b275400000000, 0x1e9fef7d00000000, 0x8f0e87d300000000,\n    0xb5696d5d00000000, 0x24f805f300000000, 0xd64ccdda00000000,\n    0x47dda57400000000, 0x32255c8900000000, 0xa3b4342700000000,\n    0x5100fc0e00000000, 0xc09194a000000000, 0x64c859c800000000,\n    0xf559316600000000, 0x07edf94f00000000, 0x967c91e100000000,\n    0xe384681c00000000, 0x721500b200000000, 0x80a1c89b00000000,\n    0x1130a03500000000, 0x2b574abb00000000, 0xbac6221500000000,\n    0x4872ea3c00000000, 0xd9e3829200000000, 0xac1b7b6f00000000,\n    0x3d8a13c100000000, 0xcf3edbe800000000, 0x5eafb34600000000,\n    0x878d413900000000, 0x161c299700000000, 0xe4a8e1be00000000,\n    0x7539891000000000, 0x00c170ed00000000, 0x9150184300000000,\n    0x63e4d06a00000000, 0xf275b8c400000000, 0xc812524a00000000,\n    0x59833ae400000000, 0xab37f2cd00000000, 0x3aa69a6300000000,\n    0x4f5e639e00000000, 0xdecf0b3000000000, 0x2c7bc31900000000,\n    0xbdeaabb700000000, 0x19b366df00000000, 0x88220e7100000000,\n    0x7a96c65800000000, 0xeb07aef600000000, 0x9eff570b00000000,\n    0x0f6e3fa500000000, 0xfddaf78c00000000, 0x6c4b9f2200000000,\n    0x562c75ac00000000, 0xc7bd1d0200000000, 0x3509d52b00000000,\n    0xa498bd8500000000, 0xd160447800000000, 0x40f12cd600000000,\n    0xb245e4ff00000000, 0x23d48c5100000000, 0xf4edfd5c00000000,\n    0x657c95f200000000, 0x97c85ddb00000000, 0x0659357500000000,\n    0x73a1cc8800000000, 0xe230a42600000000, 0x10846c0f00000000,\n    0x811504a100000000, 0xbb72ee2f00000000, 0x2ae3868100000000,\n    0xd8574ea800000000, 0x49c6260600000000, 0x3c3edffb00000000,\n    0xadafb75500000000, 0x5f1b7f7c00000000, 0xce8a17d200000000,\n    0x6ad3daba00000000, 0xfb42b21400000000, 0x09f67a3d00000000,\n    0x9867129300000000, 0xed9feb6e00000000, 0x7c0e83c000000000,\n    0x8eba4be900000000, 0x1f2b234700000000, 0x254cc9c900000000,\n    0xb4dda16700000000, 0x4669694e00000000, 0xd7f801e000000000,\n    0xa200f81d00000000, 0x339190b300000000, 0xc125589a00000000,\n    0x50b4303400000000, 0x8996c24b00000000, 0x1807aae500000000,\n    0xeab362cc00000000, 0x7b220a6200000000, 0x0edaf39f00000000,\n    0x9f4b9b3100000000, 0x6dff531800000000, 0xfc6e3bb600000000,\n    0xc609d13800000000, 0x5798b99600000000, 0xa52c71bf00000000,\n    0x34bd191100000000, 0x4145e0ec00000000, 0xd0d4884200000000,\n    0x2260406b00000000, 0xb3f128c500000000, 0x17a8e5ad00000000,\n    0x86398d0300000000, 0x748d452a00000000, 0xe51c2d8400000000,\n    0x90e4d47900000000, 0x0175bcd700000000, 0xf3c174fe00000000,\n    0x62501c5000000000, 0x5837f6de00000000, 0xc9a69e7000000000,\n    0x3b12565900000000, 0xaa833ef700000000, 0xdf7bc70a00000000,\n    0x4eeaafa400000000, 0xbc5e678d00000000, 0x2dcf0f2300000000,\n    0x0e1b837200000000, 0x9f8aebdc00000000, 0x6d3e23f500000000,\n    0xfcaf4b5b00000000, 0x8957b2a600000000, 0x18c6da0800000000,\n    0xea72122100000000, 0x7be37a8f00000000, 0x4184900100000000,\n    0xd015f8af00000000, 0x22a1308600000000, 0xb330582800000000,\n    0xc6c8a1d500000000, 0x5759c97b00000000, 0xa5ed015200000000,\n    0x347c69fc00000000, 0x9025a49400000000, 0x01b4cc3a00000000,\n    0xf300041300000000, 0x62916cbd00000000, 0x1769954000000000,\n    0x86f8fdee00000000, 0x744c35c700000000, 0xe5dd5d6900000000,\n    0xdfbab7e700000000, 0x4e2bdf4900000000, 0xbc9f176000000000,\n    0x2d0e7fce00000000, 0x58f6863300000000, 0xc967ee9d00000000,\n    0x3bd326b400000000, 0xaa424e1a00000000, 0x7360bc6500000000,\n    0xe2f1d4cb00000000, 0x10451ce200000000, 0x81d4744c00000000,\n    0xf42c8db100000000, 0x65bde51f00000000, 0x97092d3600000000,\n    0x0698459800000000, 0x3cffaf1600000000, 0xad6ec7b800000000,\n    0x5fda0f9100000000, 0xce4b673f00000000, 0xbbb39ec200000000,\n    0x2a22f66c00000000, 0xd8963e4500000000, 0x490756eb00000000,\n    0xed5e9b8300000000, 0x7ccff32d00000000, 0x8e7b3b0400000000,\n    0x1fea53aa00000000, 0x6a12aa5700000000, 0xfb83c2f900000000,\n    0x09370ad000000000, 0x98a6627e00000000, 0xa2c188f000000000,\n    0x3350e05e00000000, 0xc1e4287700000000, 0x507540d900000000,\n    0x258db92400000000, 0xb41cd18a00000000, 0x46a819a300000000,\n    0xd739710d00000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa,\n    0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b,\n    0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232,\n    0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8,\n    0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e,\n    0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa,\n    0x69312319, 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b,\n    0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f,\n    0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719,\n    0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, 0x496753e3,\n    0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa,\n    0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b,\n    0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed,\n    0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89,\n    0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25,\n    0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041,\n    0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c,\n    0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed,\n    0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4,\n    0x8c06e16a, 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758,\n    0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e,\n    0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a,\n    0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed,\n    0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889,\n    0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df,\n    0x37558441, 0xb9da83a2, 0x7570833c, 0x533b85da, 0x9f918544,\n    0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d,\n    0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c,\n    0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1,\n    0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95,\n    0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839,\n    0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d,\n    0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976,\n    0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7,\n    0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be,\n    0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144,\n    0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12,\n    0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376,\n    0xc37cc495, 0x0fd6c40b, 0x7aa64737, 0xb60c47a9, 0x3883404a,\n    0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e,\n    0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278,\n    0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682,\n    0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b,\n    0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a,\n    0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, 0x83d02561,\n    0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05,\n    0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9,\n    0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd,\n    0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0,\n    0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61,\n    0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678,\n    0x264b06e6},\n   {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413,\n    0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3,\n    0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d,\n    0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653,\n    0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9,\n    0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e,\n    0x37e1e793, 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5,\n    0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712,\n    0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8,\n    0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, 0x0e14aee6,\n    0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068,\n    0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8,\n    0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579,\n    0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade,\n    0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37,\n    0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590,\n    0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4,\n    0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64,\n    0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea,\n    0xd59d995e, 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678,\n    0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282,\n    0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25,\n    0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102,\n    0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5,\n    0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f,\n    0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, 0x8816eaf2, 0x2e61e146,\n    0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8,\n    0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08,\n    0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c,\n    0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b,\n    0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972,\n    0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5,\n    0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d,\n    0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd,\n    0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833,\n    0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d,\n    0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7,\n    0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60,\n    0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2,\n    0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105,\n    0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff,\n    0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1,\n    0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f,\n    0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf,\n    0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, 0x03a0a617,\n    0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0,\n    0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959,\n    0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe,\n    0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca,\n    0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a,\n    0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184,\n    0x92364a30},\n   {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216,\n    0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8,\n    0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170,\n    0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035,\n    0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6,\n    0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145,\n    0x39dc63eb, 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d,\n    0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e,\n    0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d,\n    0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, 0xcf26d408,\n    0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0,\n    0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e,\n    0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c,\n    0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf,\n    0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a,\n    0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9,\n    0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1,\n    0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f,\n    0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987,\n    0xfdd8ba22, 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4,\n    0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37,\n    0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84,\n    0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca,\n    0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79,\n    0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba,\n    0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d,\n    0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5,\n    0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b,\n    0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643,\n    0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0,\n    0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525,\n    0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496,\n    0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8,\n    0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026,\n    0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e,\n    0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db,\n    0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118,\n    0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab,\n    0x20c07205, 0xeb9ca1a0, 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf,\n    0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c,\n    0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf,\n    0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a,\n    0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32,\n    0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec,\n    0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, 0x16441b82,\n    0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31,\n    0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4,\n    0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957,\n    0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f,\n    0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1,\n    0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869,\n    0xe4c4abcc},\n   {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0,\n    0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271,\n    0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61,\n    0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52,\n    0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43,\n    0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333,\n    0xdfd029e3, 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64,\n    0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314,\n    0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205,\n    0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, 0x9c419136,\n    0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26,\n    0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997,\n    0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849,\n    0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739,\n    0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8,\n    0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98,\n    0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b,\n    0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba,\n    0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa,\n    0xba43581a, 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d,\n    0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c,\n    0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc,\n    0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af,\n    0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf,\n    0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce,\n    0x0142247e, 0x46e25eae, 0x7b82771e, 0xb1e6b092, 0x8c869922,\n    0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532,\n    0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183,\n    0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710,\n    0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860,\n    0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1,\n    0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1,\n    0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956,\n    0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7,\n    0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7,\n    0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4,\n    0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5,\n    0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5,\n    0xaff7b675, 0x92979fc5, 0xe915e8db, 0xd475c16b, 0x93d5bbbb,\n    0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb,\n    0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da,\n    0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9,\n    0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9,\n    0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48,\n    0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, 0x28d4c7df,\n    0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af,\n    0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e,\n    0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e,\n    0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d,\n    0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c,\n    0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c,\n    0xca64c78c}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0xb029603d, 0x6053c07a, 0xd07aa047, 0xc0a680f5,\n    0x708fe0c8, 0xa0f5408f, 0x10dc20b2, 0xc14b7030, 0x7162100d,\n    0xa118b04a, 0x1131d077, 0x01edf0c5, 0xb1c490f8, 0x61be30bf,\n    0xd1975082, 0x8297e060, 0x32be805d, 0xe2c4201a, 0x52ed4027,\n    0x42316095, 0xf21800a8, 0x2262a0ef, 0x924bc0d2, 0x43dc9050,\n    0xf3f5f06d, 0x238f502a, 0x93a63017, 0x837a10a5, 0x33537098,\n    0xe329d0df, 0x5300b0e2, 0x042fc1c1, 0xb406a1fc, 0x647c01bb,\n    0xd4556186, 0xc4894134, 0x74a02109, 0xa4da814e, 0x14f3e173,\n    0xc564b1f1, 0x754dd1cc, 0xa537718b, 0x151e11b6, 0x05c23104,\n    0xb5eb5139, 0x6591f17e, 0xd5b89143, 0x86b821a1, 0x3691419c,\n    0xe6ebe1db, 0x56c281e6, 0x461ea154, 0xf637c169, 0x264d612e,\n    0x96640113, 0x47f35191, 0xf7da31ac, 0x27a091eb, 0x9789f1d6,\n    0x8755d164, 0x377cb159, 0xe706111e, 0x572f7123, 0x4958f358,\n    0xf9719365, 0x290b3322, 0x9922531f, 0x89fe73ad, 0x39d71390,\n    0xe9adb3d7, 0x5984d3ea, 0x88138368, 0x383ae355, 0xe8404312,\n    0x5869232f, 0x48b5039d, 0xf89c63a0, 0x28e6c3e7, 0x98cfa3da,\n    0xcbcf1338, 0x7be67305, 0xab9cd342, 0x1bb5b37f, 0x0b6993cd,\n    0xbb40f3f0, 0x6b3a53b7, 0xdb13338a, 0x0a846308, 0xbaad0335,\n    0x6ad7a372, 0xdafec34f, 0xca22e3fd, 0x7a0b83c0, 0xaa712387,\n    0x1a5843ba, 0x4d773299, 0xfd5e52a4, 0x2d24f2e3, 0x9d0d92de,\n    0x8dd1b26c, 0x3df8d251, 0xed827216, 0x5dab122b, 0x8c3c42a9,\n    0x3c152294, 0xec6f82d3, 0x5c46e2ee, 0x4c9ac25c, 0xfcb3a261,\n    0x2cc90226, 0x9ce0621b, 0xcfe0d2f9, 0x7fc9b2c4, 0xafb31283,\n    0x1f9a72be, 0x0f46520c, 0xbf6f3231, 0x6f159276, 0xdf3cf24b,\n    0x0eaba2c9, 0xbe82c2f4, 0x6ef862b3, 0xded1028e, 0xce0d223c,\n    0x7e244201, 0xae5ee246, 0x1e77827b, 0x92b0e6b1, 0x2299868c,\n    0xf2e326cb, 0x42ca46f6, 0x52166644, 0xe23f0679, 0x3245a63e,\n    0x826cc603, 0x53fb9681, 0xe3d2f6bc, 0x33a856fb, 0x838136c6,\n    0x935d1674, 0x23747649, 0xf30ed60e, 0x4327b633, 0x102706d1,\n    0xa00e66ec, 0x7074c6ab, 0xc05da696, 0xd0818624, 0x60a8e619,\n    0xb0d2465e, 0x00fb2663, 0xd16c76e1, 0x614516dc, 0xb13fb69b,\n    0x0116d6a6, 0x11caf614, 0xa1e39629, 0x7199366e, 0xc1b05653,\n    0x969f2770, 0x26b6474d, 0xf6cce70a, 0x46e58737, 0x5639a785,\n    0xe610c7b8, 0x366a67ff, 0x864307c2, 0x57d45740, 0xe7fd377d,\n    0x3787973a, 0x87aef707, 0x9772d7b5, 0x275bb788, 0xf72117cf,\n    0x470877f2, 0x1408c710, 0xa421a72d, 0x745b076a, 0xc4726757,\n    0xd4ae47e5, 0x648727d8, 0xb4fd879f, 0x04d4e7a2, 0xd543b720,\n    0x656ad71d, 0xb510775a, 0x05391767, 0x15e537d5, 0xa5cc57e8,\n    0x75b6f7af, 0xc59f9792, 0xdbe815e9, 0x6bc175d4, 0xbbbbd593,\n    0x0b92b5ae, 0x1b4e951c, 0xab67f521, 0x7b1d5566, 0xcb34355b,\n    0x1aa365d9, 0xaa8a05e4, 0x7af0a5a3, 0xcad9c59e, 0xda05e52c,\n    0x6a2c8511, 0xba562556, 0x0a7f456b, 0x597ff589, 0xe95695b4,\n    0x392c35f3, 0x890555ce, 0x99d9757c, 0x29f01541, 0xf98ab506,\n    0x49a3d53b, 0x983485b9, 0x281de584, 0xf86745c3, 0x484e25fe,\n    0x5892054c, 0xe8bb6571, 0x38c1c536, 0x88e8a50b, 0xdfc7d428,\n    0x6feeb415, 0xbf941452, 0x0fbd746f, 0x1f6154dd, 0xaf4834e0,\n    0x7f3294a7, 0xcf1bf49a, 0x1e8ca418, 0xaea5c425, 0x7edf6462,\n    0xcef6045f, 0xde2a24ed, 0x6e0344d0, 0xbe79e497, 0x0e5084aa,\n    0x5d503448, 0xed795475, 0x3d03f432, 0x8d2a940f, 0x9df6b4bd,\n    0x2ddfd480, 0xfda574c7, 0x4d8c14fa, 0x9c1b4478, 0x2c322445,\n    0xfc488402, 0x4c61e43f, 0x5cbdc48d, 0xec94a4b0, 0x3cee04f7,\n    0x8cc764ca},\n   {0x00000000, 0xa5d35ccb, 0x0ba1c84d, 0xae729486, 0x1642919b,\n    0xb391cd50, 0x1de359d6, 0xb830051d, 0x6d8253ec, 0xc8510f27,\n    0x66239ba1, 0xc3f0c76a, 0x7bc0c277, 0xde139ebc, 0x70610a3a,\n    0xd5b256f1, 0x9b02d603, 0x3ed18ac8, 0x90a31e4e, 0x35704285,\n    0x8d404798, 0x28931b53, 0x86e18fd5, 0x2332d31e, 0xf68085ef,\n    0x5353d924, 0xfd214da2, 0x58f21169, 0xe0c21474, 0x451148bf,\n    0xeb63dc39, 0x4eb080f2, 0x3605ac07, 0x93d6f0cc, 0x3da4644a,\n    0x98773881, 0x20473d9c, 0x85946157, 0x2be6f5d1, 0x8e35a91a,\n    0x5b87ffeb, 0xfe54a320, 0x502637a6, 0xf5f56b6d, 0x4dc56e70,\n    0xe81632bb, 0x4664a63d, 0xe3b7faf6, 0xad077a04, 0x08d426cf,\n    0xa6a6b249, 0x0375ee82, 0xbb45eb9f, 0x1e96b754, 0xb0e423d2,\n    0x15377f19, 0xc08529e8, 0x65567523, 0xcb24e1a5, 0x6ef7bd6e,\n    0xd6c7b873, 0x7314e4b8, 0xdd66703e, 0x78b52cf5, 0x6c0a580f,\n    0xc9d904c4, 0x67ab9042, 0xc278cc89, 0x7a48c994, 0xdf9b955f,\n    0x71e901d9, 0xd43a5d12, 0x01880be3, 0xa45b5728, 0x0a29c3ae,\n    0xaffa9f65, 0x17ca9a78, 0xb219c6b3, 0x1c6b5235, 0xb9b80efe,\n    0xf7088e0c, 0x52dbd2c7, 0xfca94641, 0x597a1a8a, 0xe14a1f97,\n    0x4499435c, 0xeaebd7da, 0x4f388b11, 0x9a8adde0, 0x3f59812b,\n    0x912b15ad, 0x34f84966, 0x8cc84c7b, 0x291b10b0, 0x87698436,\n    0x22bad8fd, 0x5a0ff408, 0xffdca8c3, 0x51ae3c45, 0xf47d608e,\n    0x4c4d6593, 0xe99e3958, 0x47ecadde, 0xe23ff115, 0x378da7e4,\n    0x925efb2f, 0x3c2c6fa9, 0x99ff3362, 0x21cf367f, 0x841c6ab4,\n    0x2a6efe32, 0x8fbda2f9, 0xc10d220b, 0x64de7ec0, 0xcaacea46,\n    0x6f7fb68d, 0xd74fb390, 0x729cef5b, 0xdcee7bdd, 0x793d2716,\n    0xac8f71e7, 0x095c2d2c, 0xa72eb9aa, 0x02fde561, 0xbacde07c,\n    0x1f1ebcb7, 0xb16c2831, 0x14bf74fa, 0xd814b01e, 0x7dc7ecd5,\n    0xd3b57853, 0x76662498, 0xce562185, 0x6b857d4e, 0xc5f7e9c8,\n    0x6024b503, 0xb596e3f2, 0x1045bf39, 0xbe372bbf, 0x1be47774,\n    0xa3d47269, 0x06072ea2, 0xa875ba24, 0x0da6e6ef, 0x4316661d,\n    0xe6c53ad6, 0x48b7ae50, 0xed64f29b, 0x5554f786, 0xf087ab4d,\n    0x5ef53fcb, 0xfb266300, 0x2e9435f1, 0x8b47693a, 0x2535fdbc,\n    0x80e6a177, 0x38d6a46a, 0x9d05f8a1, 0x33776c27, 0x96a430ec,\n    0xee111c19, 0x4bc240d2, 0xe5b0d454, 0x4063889f, 0xf8538d82,\n    0x5d80d149, 0xf3f245cf, 0x56211904, 0x83934ff5, 0x2640133e,\n    0x883287b8, 0x2de1db73, 0x95d1de6e, 0x300282a5, 0x9e701623,\n    0x3ba34ae8, 0x7513ca1a, 0xd0c096d1, 0x7eb20257, 0xdb615e9c,\n    0x63515b81, 0xc682074a, 0x68f093cc, 0xcd23cf07, 0x189199f6,\n    0xbd42c53d, 0x133051bb, 0xb6e30d70, 0x0ed3086d, 0xab0054a6,\n    0x0572c020, 0xa0a19ceb, 0xb41ee811, 0x11cdb4da, 0xbfbf205c,\n    0x1a6c7c97, 0xa25c798a, 0x078f2541, 0xa9fdb1c7, 0x0c2eed0c,\n    0xd99cbbfd, 0x7c4fe736, 0xd23d73b0, 0x77ee2f7b, 0xcfde2a66,\n    0x6a0d76ad, 0xc47fe22b, 0x61acbee0, 0x2f1c3e12, 0x8acf62d9,\n    0x24bdf65f, 0x816eaa94, 0x395eaf89, 0x9c8df342, 0x32ff67c4,\n    0x972c3b0f, 0x429e6dfe, 0xe74d3135, 0x493fa5b3, 0xececf978,\n    0x54dcfc65, 0xf10fa0ae, 0x5f7d3428, 0xfaae68e3, 0x821b4416,\n    0x27c818dd, 0x89ba8c5b, 0x2c69d090, 0x9459d58d, 0x318a8946,\n    0x9ff81dc0, 0x3a2b410b, 0xef9917fa, 0x4a4a4b31, 0xe438dfb7,\n    0x41eb837c, 0xf9db8661, 0x5c08daaa, 0xf27a4e2c, 0x57a912e7,\n    0x19199215, 0xbccacede, 0x12b85a58, 0xb76b0693, 0x0f5b038e,\n    0xaa885f45, 0x04facbc3, 0xa1299708, 0x749bc1f9, 0xd1489d32,\n    0x7f3a09b4, 0xdae9557f, 0x62d95062, 0xc70a0ca9, 0x6978982f,\n    0xccabc4e4},\n   {0x00000000, 0xb40b77a6, 0x29119f97, 0x9d1ae831, 0x13244ff4,\n    0xa72f3852, 0x3a35d063, 0x8e3ea7c5, 0x674eef33, 0xd3459895,\n    0x4e5f70a4, 0xfa540702, 0x746aa0c7, 0xc061d761, 0x5d7b3f50,\n    0xe97048f6, 0xce9cde67, 0x7a97a9c1, 0xe78d41f0, 0x53863656,\n    0xddb89193, 0x69b3e635, 0xf4a90e04, 0x40a279a2, 0xa9d23154,\n    0x1dd946f2, 0x80c3aec3, 0x34c8d965, 0xbaf67ea0, 0x0efd0906,\n    0x93e7e137, 0x27ec9691, 0x9c39bdcf, 0x2832ca69, 0xb5282258,\n    0x012355fe, 0x8f1df23b, 0x3b16859d, 0xa60c6dac, 0x12071a0a,\n    0xfb7752fc, 0x4f7c255a, 0xd266cd6b, 0x666dbacd, 0xe8531d08,\n    0x5c586aae, 0xc142829f, 0x7549f539, 0x52a563a8, 0xe6ae140e,\n    0x7bb4fc3f, 0xcfbf8b99, 0x41812c5c, 0xf58a5bfa, 0x6890b3cb,\n    0xdc9bc46d, 0x35eb8c9b, 0x81e0fb3d, 0x1cfa130c, 0xa8f164aa,\n    0x26cfc36f, 0x92c4b4c9, 0x0fde5cf8, 0xbbd52b5e, 0x79750b44,\n    0xcd7e7ce2, 0x506494d3, 0xe46fe375, 0x6a5144b0, 0xde5a3316,\n    0x4340db27, 0xf74bac81, 0x1e3be477, 0xaa3093d1, 0x372a7be0,\n    0x83210c46, 0x0d1fab83, 0xb914dc25, 0x240e3414, 0x900543b2,\n    0xb7e9d523, 0x03e2a285, 0x9ef84ab4, 0x2af33d12, 0xa4cd9ad7,\n    0x10c6ed71, 0x8ddc0540, 0x39d772e6, 0xd0a73a10, 0x64ac4db6,\n    0xf9b6a587, 0x4dbdd221, 0xc38375e4, 0x77880242, 0xea92ea73,\n    0x5e999dd5, 0xe54cb68b, 0x5147c12d, 0xcc5d291c, 0x78565eba,\n    0xf668f97f, 0x42638ed9, 0xdf7966e8, 0x6b72114e, 0x820259b8,\n    0x36092e1e, 0xab13c62f, 0x1f18b189, 0x9126164c, 0x252d61ea,\n    0xb83789db, 0x0c3cfe7d, 0x2bd068ec, 0x9fdb1f4a, 0x02c1f77b,\n    0xb6ca80dd, 0x38f42718, 0x8cff50be, 0x11e5b88f, 0xa5eecf29,\n    0x4c9e87df, 0xf895f079, 0x658f1848, 0xd1846fee, 0x5fbac82b,\n    0xebb1bf8d, 0x76ab57bc, 0xc2a0201a, 0xf2ea1688, 0x46e1612e,\n    0xdbfb891f, 0x6ff0feb9, 0xe1ce597c, 0x55c52eda, 0xc8dfc6eb,\n    0x7cd4b14d, 0x95a4f9bb, 0x21af8e1d, 0xbcb5662c, 0x08be118a,\n    0x8680b64f, 0x328bc1e9, 0xaf9129d8, 0x1b9a5e7e, 0x3c76c8ef,\n    0x887dbf49, 0x15675778, 0xa16c20de, 0x2f52871b, 0x9b59f0bd,\n    0x0643188c, 0xb2486f2a, 0x5b3827dc, 0xef33507a, 0x7229b84b,\n    0xc622cfed, 0x481c6828, 0xfc171f8e, 0x610df7bf, 0xd5068019,\n    0x6ed3ab47, 0xdad8dce1, 0x47c234d0, 0xf3c94376, 0x7df7e4b3,\n    0xc9fc9315, 0x54e67b24, 0xe0ed0c82, 0x099d4474, 0xbd9633d2,\n    0x208cdbe3, 0x9487ac45, 0x1ab90b80, 0xaeb27c26, 0x33a89417,\n    0x87a3e3b1, 0xa04f7520, 0x14440286, 0x895eeab7, 0x3d559d11,\n    0xb36b3ad4, 0x07604d72, 0x9a7aa543, 0x2e71d2e5, 0xc7019a13,\n    0x730aedb5, 0xee100584, 0x5a1b7222, 0xd425d5e7, 0x602ea241,\n    0xfd344a70, 0x493f3dd6, 0x8b9f1dcc, 0x3f946a6a, 0xa28e825b,\n    0x1685f5fd, 0x98bb5238, 0x2cb0259e, 0xb1aacdaf, 0x05a1ba09,\n    0xecd1f2ff, 0x58da8559, 0xc5c06d68, 0x71cb1ace, 0xfff5bd0b,\n    0x4bfecaad, 0xd6e4229c, 0x62ef553a, 0x4503c3ab, 0xf108b40d,\n    0x6c125c3c, 0xd8192b9a, 0x56278c5f, 0xe22cfbf9, 0x7f3613c8,\n    0xcb3d646e, 0x224d2c98, 0x96465b3e, 0x0b5cb30f, 0xbf57c4a9,\n    0x3169636c, 0x856214ca, 0x1878fcfb, 0xac738b5d, 0x17a6a003,\n    0xa3add7a5, 0x3eb73f94, 0x8abc4832, 0x0482eff7, 0xb0899851,\n    0x2d937060, 0x999807c6, 0x70e84f30, 0xc4e33896, 0x59f9d0a7,\n    0xedf2a701, 0x63cc00c4, 0xd7c77762, 0x4add9f53, 0xfed6e8f5,\n    0xd93a7e64, 0x6d3109c2, 0xf02be1f3, 0x44209655, 0xca1e3190,\n    0x7e154636, 0xe30fae07, 0x5704d9a1, 0xbe749157, 0x0a7fe6f1,\n    0x97650ec0, 0x236e7966, 0xad50dea3, 0x195ba905, 0x84414134,\n    0x304a3692},\n   {0x00000000, 0x9e00aacc, 0x7d072542, 0xe3078f8e, 0xfa0e4a84,\n    0x640ee048, 0x87096fc6, 0x1909c50a, 0xb51be5d3, 0x2b1b4f1f,\n    0xc81cc091, 0x561c6a5d, 0x4f15af57, 0xd115059b, 0x32128a15,\n    0xac1220d9, 0x2b31bb7c, 0xb53111b0, 0x56369e3e, 0xc83634f2,\n    0xd13ff1f8, 0x4f3f5b34, 0xac38d4ba, 0x32387e76, 0x9e2a5eaf,\n    0x002af463, 0xe32d7bed, 0x7d2dd121, 0x6424142b, 0xfa24bee7,\n    0x19233169, 0x87239ba5, 0x566276f9, 0xc862dc35, 0x2b6553bb,\n    0xb565f977, 0xac6c3c7d, 0x326c96b1, 0xd16b193f, 0x4f6bb3f3,\n    0xe379932a, 0x7d7939e6, 0x9e7eb668, 0x007e1ca4, 0x1977d9ae,\n    0x87777362, 0x6470fcec, 0xfa705620, 0x7d53cd85, 0xe3536749,\n    0x0054e8c7, 0x9e54420b, 0x875d8701, 0x195d2dcd, 0xfa5aa243,\n    0x645a088f, 0xc8482856, 0x5648829a, 0xb54f0d14, 0x2b4fa7d8,\n    0x324662d2, 0xac46c81e, 0x4f414790, 0xd141ed5c, 0xedc29d29,\n    0x73c237e5, 0x90c5b86b, 0x0ec512a7, 0x17ccd7ad, 0x89cc7d61,\n    0x6acbf2ef, 0xf4cb5823, 0x58d978fa, 0xc6d9d236, 0x25de5db8,\n    0xbbdef774, 0xa2d7327e, 0x3cd798b2, 0xdfd0173c, 0x41d0bdf0,\n    0xc6f32655, 0x58f38c99, 0xbbf40317, 0x25f4a9db, 0x3cfd6cd1,\n    0xa2fdc61d, 0x41fa4993, 0xdffae35f, 0x73e8c386, 0xede8694a,\n    0x0eefe6c4, 0x90ef4c08, 0x89e68902, 0x17e623ce, 0xf4e1ac40,\n    0x6ae1068c, 0xbba0ebd0, 0x25a0411c, 0xc6a7ce92, 0x58a7645e,\n    0x41aea154, 0xdfae0b98, 0x3ca98416, 0xa2a92eda, 0x0ebb0e03,\n    0x90bba4cf, 0x73bc2b41, 0xedbc818d, 0xf4b54487, 0x6ab5ee4b,\n    0x89b261c5, 0x17b2cb09, 0x909150ac, 0x0e91fa60, 0xed9675ee,\n    0x7396df22, 0x6a9f1a28, 0xf49fb0e4, 0x17983f6a, 0x899895a6,\n    0x258ab57f, 0xbb8a1fb3, 0x588d903d, 0xc68d3af1, 0xdf84fffb,\n    0x41845537, 0xa283dab9, 0x3c837075, 0xda853b53, 0x4485919f,\n    0xa7821e11, 0x3982b4dd, 0x208b71d7, 0xbe8bdb1b, 0x5d8c5495,\n    0xc38cfe59, 0x6f9ede80, 0xf19e744c, 0x1299fbc2, 0x8c99510e,\n    0x95909404, 0x0b903ec8, 0xe897b146, 0x76971b8a, 0xf1b4802f,\n    0x6fb42ae3, 0x8cb3a56d, 0x12b30fa1, 0x0bbacaab, 0x95ba6067,\n    0x76bdefe9, 0xe8bd4525, 0x44af65fc, 0xdaafcf30, 0x39a840be,\n    0xa7a8ea72, 0xbea12f78, 0x20a185b4, 0xc3a60a3a, 0x5da6a0f6,\n    0x8ce74daa, 0x12e7e766, 0xf1e068e8, 0x6fe0c224, 0x76e9072e,\n    0xe8e9ade2, 0x0bee226c, 0x95ee88a0, 0x39fca879, 0xa7fc02b5,\n    0x44fb8d3b, 0xdafb27f7, 0xc3f2e2fd, 0x5df24831, 0xbef5c7bf,\n    0x20f56d73, 0xa7d6f6d6, 0x39d65c1a, 0xdad1d394, 0x44d17958,\n    0x5dd8bc52, 0xc3d8169e, 0x20df9910, 0xbedf33dc, 0x12cd1305,\n    0x8ccdb9c9, 0x6fca3647, 0xf1ca9c8b, 0xe8c35981, 0x76c3f34d,\n    0x95c47cc3, 0x0bc4d60f, 0x3747a67a, 0xa9470cb6, 0x4a408338,\n    0xd44029f4, 0xcd49ecfe, 0x53494632, 0xb04ec9bc, 0x2e4e6370,\n    0x825c43a9, 0x1c5ce965, 0xff5b66eb, 0x615bcc27, 0x7852092d,\n    0xe652a3e1, 0x05552c6f, 0x9b5586a3, 0x1c761d06, 0x8276b7ca,\n    0x61713844, 0xff719288, 0xe6785782, 0x7878fd4e, 0x9b7f72c0,\n    0x057fd80c, 0xa96df8d5, 0x376d5219, 0xd46add97, 0x4a6a775b,\n    0x5363b251, 0xcd63189d, 0x2e649713, 0xb0643ddf, 0x6125d083,\n    0xff257a4f, 0x1c22f5c1, 0x82225f0d, 0x9b2b9a07, 0x052b30cb,\n    0xe62cbf45, 0x782c1589, 0xd43e3550, 0x4a3e9f9c, 0xa9391012,\n    0x3739bade, 0x2e307fd4, 0xb030d518, 0x53375a96, 0xcd37f05a,\n    0x4a146bff, 0xd414c133, 0x37134ebd, 0xa913e471, 0xb01a217b,\n    0x2e1a8bb7, 0xcd1d0439, 0x531daef5, 0xff0f8e2c, 0x610f24e0,\n    0x8208ab6e, 0x1c0801a2, 0x0501c4a8, 0x9b016e64, 0x7806e1ea,\n    0xe6064b26}};\n\n#endif\n\n#endif\n\n#if N == 3\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f,\n    0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999,\n    0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee,\n    0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615,\n    0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383,\n    0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb,\n    0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275,\n    0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d,\n    0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b,\n    0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460,\n    0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317,\n    0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1,\n    0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5,\n    0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd,\n    0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04,\n    0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c,\n    0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7,\n    0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11,\n    0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66,\n    0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7,\n    0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871,\n    0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309,\n    0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd,\n    0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85,\n    0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913,\n    0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d,\n    0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a,\n    0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc,\n    0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57,\n    0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f,\n    0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6,\n    0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e,\n    0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f,\n    0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289,\n    0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe,\n    0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05,\n    0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893,\n    0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb,\n    0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0,\n    0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8,\n    0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e,\n    0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5,\n    0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2,\n    0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574,\n    0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5,\n    0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add,\n    0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114,\n    0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c,\n    0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7,\n    0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701,\n    0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076,\n    0x09cd8551},\n   {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193,\n    0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2,\n    0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c,\n    0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71,\n    0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a,\n    0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d,\n    0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71,\n    0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436,\n    0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d,\n    0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000,\n    0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae,\n    0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf,\n    0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930,\n    0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277,\n    0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff,\n    0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8,\n    0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef,\n    0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e,\n    0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20,\n    0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95,\n    0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e,\n    0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9,\n    0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d,\n    0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a,\n    0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151,\n    0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4,\n    0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a,\n    0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b,\n    0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c,\n    0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b,\n    0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3,\n    0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4,\n    0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b,\n    0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a,\n    0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4,\n    0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189,\n    0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92,\n    0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5,\n    0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9,\n    0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe,\n    0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5,\n    0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8,\n    0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66,\n    0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707,\n    0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8,\n    0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f,\n    0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707,\n    0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40,\n    0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017,\n    0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876,\n    0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8,\n    0x7bc97a0c},\n   {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300,\n    0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0,\n    0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80,\n    0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701,\n    0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41,\n    0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81,\n    0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43,\n    0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83,\n    0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3,\n    0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42,\n    0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202,\n    0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2,\n    0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7,\n    0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407,\n    0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47,\n    0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87,\n    0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86,\n    0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46,\n    0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506,\n    0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44,\n    0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704,\n    0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4,\n    0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5,\n    0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505,\n    0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45,\n    0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f,\n    0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f,\n    0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f,\n    0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e,\n    0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e,\n    0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e,\n    0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce,\n    0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c,\n    0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc,\n    0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c,\n    0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d,\n    0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d,\n    0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d,\n    0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88,\n    0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48,\n    0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708,\n    0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89,\n    0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9,\n    0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309,\n    0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb,\n    0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b,\n    0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b,\n    0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b,\n    0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a,\n    0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a,\n    0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a,\n    0x7851a2ca},\n   {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb,\n    0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8,\n    0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0,\n    0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f,\n    0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a,\n    0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf,\n    0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5,\n    0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380,\n    0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815,\n    0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa,\n    0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2,\n    0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1,\n    0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1,\n    0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4,\n    0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa,\n    0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df,\n    0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6,\n    0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5,\n    0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad,\n    0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca,\n    0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f,\n    0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a,\n    0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8,\n    0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d,\n    0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708,\n    0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d,\n    0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865,\n    0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636,\n    0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f,\n    0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a,\n    0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744,\n    0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061,\n    0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0,\n    0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293,\n    0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb,\n    0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874,\n    0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1,\n    0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4,\n    0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f,\n    0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a,\n    0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f,\n    0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120,\n    0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778,\n    0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b,\n    0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a,\n    0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af,\n    0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81,\n    0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4,\n    0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd,\n    0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e,\n    0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6,\n    0x566b6848},\n   {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59,\n    0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4,\n    0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67,\n    0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef,\n    0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97,\n    0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88,\n    0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687,\n    0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698,\n    0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0,\n    0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068,\n    0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb,\n    0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056,\n    0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016,\n    0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009,\n    0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028,\n    0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037,\n    0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a,\n    0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7,\n    0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054,\n    0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7,\n    0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af,\n    0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0,\n    0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4,\n    0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab,\n    0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3,\n    0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a,\n    0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9,\n    0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54,\n    0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09,\n    0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16,\n    0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37,\n    0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28,\n    0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e,\n    0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3,\n    0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40,\n    0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8,\n    0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0,\n    0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf,\n    0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6,\n    0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9,\n    0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1,\n    0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059,\n    0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca,\n    0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067,\n    0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031,\n    0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e,\n    0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f,\n    0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010,\n    0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d,\n    0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0,\n    0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073,\n    0xd8ac6b35},\n   {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2,\n    0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd,\n    0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696,\n    0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3,\n    0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f,\n    0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35,\n    0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5,\n    0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f,\n    0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673,\n    0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46,\n    0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d,\n    0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632,\n    0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28,\n    0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192,\n    0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c,\n    0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6,\n    0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0,\n    0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff,\n    0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4,\n    0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95,\n    0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9,\n    0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03,\n    0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7,\n    0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d,\n    0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151,\n    0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808,\n    0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343,\n    0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c,\n    0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a,\n    0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0,\n    0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e,\n    0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594,\n    0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6,\n    0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399,\n    0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2,\n    0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7,\n    0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb,\n    0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571,\n    0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289,\n    0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33,\n    0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f,\n    0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a,\n    0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461,\n    0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e,\n    0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c,\n    0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6,\n    0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918,\n    0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2,\n    0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484,\n    0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb,\n    0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0,\n    0xa140efa8},\n   {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706,\n    0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed,\n    0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289,\n    0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a,\n    0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214,\n    0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3,\n    0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3,\n    0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254,\n    0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a,\n    0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9,\n    0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad,\n    0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746,\n    0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060,\n    0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187,\n    0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef,\n    0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408,\n    0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e,\n    0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495,\n    0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1,\n    0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532,\n    0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c,\n    0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb,\n    0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb,\n    0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c,\n    0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42,\n    0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060,\n    0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04,\n    0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef,\n    0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99,\n    0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e,\n    0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16,\n    0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1,\n    0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7,\n    0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c,\n    0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38,\n    0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb,\n    0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5,\n    0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42,\n    0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62,\n    0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85,\n    0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb,\n    0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18,\n    0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c,\n    0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997,\n    0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1,\n    0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36,\n    0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e,\n    0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9,\n    0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf,\n    0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24,\n    0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040,\n    0x917cd6a1},\n   {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf,\n    0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd,\n    0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896,\n    0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9,\n    0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3,\n    0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f,\n    0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d,\n    0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1,\n    0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab,\n    0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4,\n    0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f,\n    0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d,\n    0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4,\n    0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978,\n    0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad,\n    0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621,\n    0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46,\n    0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854,\n    0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f,\n    0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a,\n    0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890,\n    0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c,\n    0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4,\n    0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238,\n    0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622,\n    0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab,\n    0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0,\n    0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2,\n    0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295,\n    0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19,\n    0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc,\n    0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140,\n    0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd,\n    0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf,\n    0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184,\n    0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb,\n    0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1,\n    0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d,\n    0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb,\n    0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257,\n    0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d,\n    0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22,\n    0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069,\n    0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b,\n    0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6,\n    0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a,\n    0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf,\n    0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33,\n    0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254,\n    0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146,\n    0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d,\n    0x18ba364e}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0x43cba68700000000, 0xc7903cd400000000,\n    0x845b9a5300000000, 0xcf27087300000000, 0x8cecaef400000000,\n    0x08b734a700000000, 0x4b7c922000000000, 0x9e4f10e600000000,\n    0xdd84b66100000000, 0x59df2c3200000000, 0x1a148ab500000000,\n    0x5168189500000000, 0x12a3be1200000000, 0x96f8244100000000,\n    0xd53382c600000000, 0x7d99511700000000, 0x3e52f79000000000,\n    0xba096dc300000000, 0xf9c2cb4400000000, 0xb2be596400000000,\n    0xf175ffe300000000, 0x752e65b000000000, 0x36e5c33700000000,\n    0xe3d641f100000000, 0xa01de77600000000, 0x24467d2500000000,\n    0x678ddba200000000, 0x2cf1498200000000, 0x6f3aef0500000000,\n    0xeb61755600000000, 0xa8aad3d100000000, 0xfa32a32e00000000,\n    0xb9f905a900000000, 0x3da29ffa00000000, 0x7e69397d00000000,\n    0x3515ab5d00000000, 0x76de0dda00000000, 0xf285978900000000,\n    0xb14e310e00000000, 0x647db3c800000000, 0x27b6154f00000000,\n    0xa3ed8f1c00000000, 0xe026299b00000000, 0xab5abbbb00000000,\n    0xe8911d3c00000000, 0x6cca876f00000000, 0x2f0121e800000000,\n    0x87abf23900000000, 0xc46054be00000000, 0x403bceed00000000,\n    0x03f0686a00000000, 0x488cfa4a00000000, 0x0b475ccd00000000,\n    0x8f1cc69e00000000, 0xccd7601900000000, 0x19e4e2df00000000,\n    0x5a2f445800000000, 0xde74de0b00000000, 0x9dbf788c00000000,\n    0xd6c3eaac00000000, 0x95084c2b00000000, 0x1153d67800000000,\n    0x529870ff00000000, 0xf465465d00000000, 0xb7aee0da00000000,\n    0x33f57a8900000000, 0x703edc0e00000000, 0x3b424e2e00000000,\n    0x7889e8a900000000, 0xfcd272fa00000000, 0xbf19d47d00000000,\n    0x6a2a56bb00000000, 0x29e1f03c00000000, 0xadba6a6f00000000,\n    0xee71cce800000000, 0xa50d5ec800000000, 0xe6c6f84f00000000,\n    0x629d621c00000000, 0x2156c49b00000000, 0x89fc174a00000000,\n    0xca37b1cd00000000, 0x4e6c2b9e00000000, 0x0da78d1900000000,\n    0x46db1f3900000000, 0x0510b9be00000000, 0x814b23ed00000000,\n    0xc280856a00000000, 0x17b307ac00000000, 0x5478a12b00000000,\n    0xd0233b7800000000, 0x93e89dff00000000, 0xd8940fdf00000000,\n    0x9b5fa95800000000, 0x1f04330b00000000, 0x5ccf958c00000000,\n    0x0e57e57300000000, 0x4d9c43f400000000, 0xc9c7d9a700000000,\n    0x8a0c7f2000000000, 0xc170ed0000000000, 0x82bb4b8700000000,\n    0x06e0d1d400000000, 0x452b775300000000, 0x9018f59500000000,\n    0xd3d3531200000000, 0x5788c94100000000, 0x14436fc600000000,\n    0x5f3ffde600000000, 0x1cf45b6100000000, 0x98afc13200000000,\n    0xdb6467b500000000, 0x73ceb46400000000, 0x300512e300000000,\n    0xb45e88b000000000, 0xf7952e3700000000, 0xbce9bc1700000000,\n    0xff221a9000000000, 0x7b7980c300000000, 0x38b2264400000000,\n    0xed81a48200000000, 0xae4a020500000000, 0x2a11985600000000,\n    0x69da3ed100000000, 0x22a6acf100000000, 0x616d0a7600000000,\n    0xe536902500000000, 0xa6fd36a200000000, 0xe8cb8cba00000000,\n    0xab002a3d00000000, 0x2f5bb06e00000000, 0x6c9016e900000000,\n    0x27ec84c900000000, 0x6427224e00000000, 0xe07cb81d00000000,\n    0xa3b71e9a00000000, 0x76849c5c00000000, 0x354f3adb00000000,\n    0xb114a08800000000, 0xf2df060f00000000, 0xb9a3942f00000000,\n    0xfa6832a800000000, 0x7e33a8fb00000000, 0x3df80e7c00000000,\n    0x9552ddad00000000, 0xd6997b2a00000000, 0x52c2e17900000000,\n    0x110947fe00000000, 0x5a75d5de00000000, 0x19be735900000000,\n    0x9de5e90a00000000, 0xde2e4f8d00000000, 0x0b1dcd4b00000000,\n    0x48d66bcc00000000, 0xcc8df19f00000000, 0x8f46571800000000,\n    0xc43ac53800000000, 0x87f163bf00000000, 0x03aaf9ec00000000,\n    0x40615f6b00000000, 0x12f92f9400000000, 0x5132891300000000,\n    0xd569134000000000, 0x96a2b5c700000000, 0xddde27e700000000,\n    0x9e15816000000000, 0x1a4e1b3300000000, 0x5985bdb400000000,\n    0x8cb63f7200000000, 0xcf7d99f500000000, 0x4b2603a600000000,\n    0x08eda52100000000, 0x4391370100000000, 0x005a918600000000,\n    0x84010bd500000000, 0xc7caad5200000000, 0x6f607e8300000000,\n    0x2cabd80400000000, 0xa8f0425700000000, 0xeb3be4d000000000,\n    0xa04776f000000000, 0xe38cd07700000000, 0x67d74a2400000000,\n    0x241ceca300000000, 0xf12f6e6500000000, 0xb2e4c8e200000000,\n    0x36bf52b100000000, 0x7574f43600000000, 0x3e08661600000000,\n    0x7dc3c09100000000, 0xf9985ac200000000, 0xba53fc4500000000,\n    0x1caecae700000000, 0x5f656c6000000000, 0xdb3ef63300000000,\n    0x98f550b400000000, 0xd389c29400000000, 0x9042641300000000,\n    0x1419fe4000000000, 0x57d258c700000000, 0x82e1da0100000000,\n    0xc12a7c8600000000, 0x4571e6d500000000, 0x06ba405200000000,\n    0x4dc6d27200000000, 0x0e0d74f500000000, 0x8a56eea600000000,\n    0xc99d482100000000, 0x61379bf000000000, 0x22fc3d7700000000,\n    0xa6a7a72400000000, 0xe56c01a300000000, 0xae10938300000000,\n    0xeddb350400000000, 0x6980af5700000000, 0x2a4b09d000000000,\n    0xff788b1600000000, 0xbcb32d9100000000, 0x38e8b7c200000000,\n    0x7b23114500000000, 0x305f836500000000, 0x739425e200000000,\n    0xf7cfbfb100000000, 0xb404193600000000, 0xe69c69c900000000,\n    0xa557cf4e00000000, 0x210c551d00000000, 0x62c7f39a00000000,\n    0x29bb61ba00000000, 0x6a70c73d00000000, 0xee2b5d6e00000000,\n    0xade0fbe900000000, 0x78d3792f00000000, 0x3b18dfa800000000,\n    0xbf4345fb00000000, 0xfc88e37c00000000, 0xb7f4715c00000000,\n    0xf43fd7db00000000, 0x70644d8800000000, 0x33afeb0f00000000,\n    0x9b0538de00000000, 0xd8ce9e5900000000, 0x5c95040a00000000,\n    0x1f5ea28d00000000, 0x542230ad00000000, 0x17e9962a00000000,\n    0x93b20c7900000000, 0xd079aafe00000000, 0x054a283800000000,\n    0x46818ebf00000000, 0xc2da14ec00000000, 0x8111b26b00000000,\n    0xca6d204b00000000, 0x89a686cc00000000, 0x0dfd1c9f00000000,\n    0x4e36ba1800000000},\n   {0x0000000000000000, 0xe1b652ef00000000, 0x836bd40500000000,\n    0x62dd86ea00000000, 0x06d7a80b00000000, 0xe761fae400000000,\n    0x85bc7c0e00000000, 0x640a2ee100000000, 0x0cae511700000000,\n    0xed1803f800000000, 0x8fc5851200000000, 0x6e73d7fd00000000,\n    0x0a79f91c00000000, 0xebcfabf300000000, 0x89122d1900000000,\n    0x68a47ff600000000, 0x185ca32e00000000, 0xf9eaf1c100000000,\n    0x9b37772b00000000, 0x7a8125c400000000, 0x1e8b0b2500000000,\n    0xff3d59ca00000000, 0x9de0df2000000000, 0x7c568dcf00000000,\n    0x14f2f23900000000, 0xf544a0d600000000, 0x9799263c00000000,\n    0x762f74d300000000, 0x12255a3200000000, 0xf39308dd00000000,\n    0x914e8e3700000000, 0x70f8dcd800000000, 0x30b8465d00000000,\n    0xd10e14b200000000, 0xb3d3925800000000, 0x5265c0b700000000,\n    0x366fee5600000000, 0xd7d9bcb900000000, 0xb5043a5300000000,\n    0x54b268bc00000000, 0x3c16174a00000000, 0xdda045a500000000,\n    0xbf7dc34f00000000, 0x5ecb91a000000000, 0x3ac1bf4100000000,\n    0xdb77edae00000000, 0xb9aa6b4400000000, 0x581c39ab00000000,\n    0x28e4e57300000000, 0xc952b79c00000000, 0xab8f317600000000,\n    0x4a39639900000000, 0x2e334d7800000000, 0xcf851f9700000000,\n    0xad58997d00000000, 0x4ceecb9200000000, 0x244ab46400000000,\n    0xc5fce68b00000000, 0xa721606100000000, 0x4697328e00000000,\n    0x229d1c6f00000000, 0xc32b4e8000000000, 0xa1f6c86a00000000,\n    0x40409a8500000000, 0x60708dba00000000, 0x81c6df5500000000,\n    0xe31b59bf00000000, 0x02ad0b5000000000, 0x66a725b100000000,\n    0x8711775e00000000, 0xe5ccf1b400000000, 0x047aa35b00000000,\n    0x6cdedcad00000000, 0x8d688e4200000000, 0xefb508a800000000,\n    0x0e035a4700000000, 0x6a0974a600000000, 0x8bbf264900000000,\n    0xe962a0a300000000, 0x08d4f24c00000000, 0x782c2e9400000000,\n    0x999a7c7b00000000, 0xfb47fa9100000000, 0x1af1a87e00000000,\n    0x7efb869f00000000, 0x9f4dd47000000000, 0xfd90529a00000000,\n    0x1c26007500000000, 0x74827f8300000000, 0x95342d6c00000000,\n    0xf7e9ab8600000000, 0x165ff96900000000, 0x7255d78800000000,\n    0x93e3856700000000, 0xf13e038d00000000, 0x1088516200000000,\n    0x50c8cbe700000000, 0xb17e990800000000, 0xd3a31fe200000000,\n    0x32154d0d00000000, 0x561f63ec00000000, 0xb7a9310300000000,\n    0xd574b7e900000000, 0x34c2e50600000000, 0x5c669af000000000,\n    0xbdd0c81f00000000, 0xdf0d4ef500000000, 0x3ebb1c1a00000000,\n    0x5ab132fb00000000, 0xbb07601400000000, 0xd9dae6fe00000000,\n    0x386cb41100000000, 0x489468c900000000, 0xa9223a2600000000,\n    0xcbffbccc00000000, 0x2a49ee2300000000, 0x4e43c0c200000000,\n    0xaff5922d00000000, 0xcd2814c700000000, 0x2c9e462800000000,\n    0x443a39de00000000, 0xa58c6b3100000000, 0xc751eddb00000000,\n    0x26e7bf3400000000, 0x42ed91d500000000, 0xa35bc33a00000000,\n    0xc18645d000000000, 0x2030173f00000000, 0x81e66bae00000000,\n    0x6050394100000000, 0x028dbfab00000000, 0xe33bed4400000000,\n    0x8731c3a500000000, 0x6687914a00000000, 0x045a17a000000000,\n    0xe5ec454f00000000, 0x8d483ab900000000, 0x6cfe685600000000,\n    0x0e23eebc00000000, 0xef95bc5300000000, 0x8b9f92b200000000,\n    0x6a29c05d00000000, 0x08f446b700000000, 0xe942145800000000,\n    0x99bac88000000000, 0x780c9a6f00000000, 0x1ad11c8500000000,\n    0xfb674e6a00000000, 0x9f6d608b00000000, 0x7edb326400000000,\n    0x1c06b48e00000000, 0xfdb0e66100000000, 0x9514999700000000,\n    0x74a2cb7800000000, 0x167f4d9200000000, 0xf7c91f7d00000000,\n    0x93c3319c00000000, 0x7275637300000000, 0x10a8e59900000000,\n    0xf11eb77600000000, 0xb15e2df300000000, 0x50e87f1c00000000,\n    0x3235f9f600000000, 0xd383ab1900000000, 0xb78985f800000000,\n    0x563fd71700000000, 0x34e251fd00000000, 0xd554031200000000,\n    0xbdf07ce400000000, 0x5c462e0b00000000, 0x3e9ba8e100000000,\n    0xdf2dfa0e00000000, 0xbb27d4ef00000000, 0x5a91860000000000,\n    0x384c00ea00000000, 0xd9fa520500000000, 0xa9028edd00000000,\n    0x48b4dc3200000000, 0x2a695ad800000000, 0xcbdf083700000000,\n    0xafd526d600000000, 0x4e63743900000000, 0x2cbef2d300000000,\n    0xcd08a03c00000000, 0xa5acdfca00000000, 0x441a8d2500000000,\n    0x26c70bcf00000000, 0xc771592000000000, 0xa37b77c100000000,\n    0x42cd252e00000000, 0x2010a3c400000000, 0xc1a6f12b00000000,\n    0xe196e61400000000, 0x0020b4fb00000000, 0x62fd321100000000,\n    0x834b60fe00000000, 0xe7414e1f00000000, 0x06f71cf000000000,\n    0x642a9a1a00000000, 0x859cc8f500000000, 0xed38b70300000000,\n    0x0c8ee5ec00000000, 0x6e53630600000000, 0x8fe531e900000000,\n    0xebef1f0800000000, 0x0a594de700000000, 0x6884cb0d00000000,\n    0x893299e200000000, 0xf9ca453a00000000, 0x187c17d500000000,\n    0x7aa1913f00000000, 0x9b17c3d000000000, 0xff1ded3100000000,\n    0x1eabbfde00000000, 0x7c76393400000000, 0x9dc06bdb00000000,\n    0xf564142d00000000, 0x14d246c200000000, 0x760fc02800000000,\n    0x97b992c700000000, 0xf3b3bc2600000000, 0x1205eec900000000,\n    0x70d8682300000000, 0x916e3acc00000000, 0xd12ea04900000000,\n    0x3098f2a600000000, 0x5245744c00000000, 0xb3f326a300000000,\n    0xd7f9084200000000, 0x364f5aad00000000, 0x5492dc4700000000,\n    0xb5248ea800000000, 0xdd80f15e00000000, 0x3c36a3b100000000,\n    0x5eeb255b00000000, 0xbf5d77b400000000, 0xdb57595500000000,\n    0x3ae10bba00000000, 0x583c8d5000000000, 0xb98adfbf00000000,\n    0xc972036700000000, 0x28c4518800000000, 0x4a19d76200000000,\n    0xabaf858d00000000, 0xcfa5ab6c00000000, 0x2e13f98300000000,\n    0x4cce7f6900000000, 0xad782d8600000000, 0xc5dc527000000000,\n    0x246a009f00000000, 0x46b7867500000000, 0xa701d49a00000000,\n    0xc30bfa7b00000000, 0x22bda89400000000, 0x40602e7e00000000,\n    0xa1d67c9100000000},\n   {0x0000000000000000, 0x5880e2d700000000, 0xf106b47400000000,\n    0xa98656a300000000, 0xe20d68e900000000, 0xba8d8a3e00000000,\n    0x130bdc9d00000000, 0x4b8b3e4a00000000, 0x851da10900000000,\n    0xdd9d43de00000000, 0x741b157d00000000, 0x2c9bf7aa00000000,\n    0x6710c9e000000000, 0x3f902b3700000000, 0x96167d9400000000,\n    0xce969f4300000000, 0x0a3b421300000000, 0x52bba0c400000000,\n    0xfb3df66700000000, 0xa3bd14b000000000, 0xe8362afa00000000,\n    0xb0b6c82d00000000, 0x19309e8e00000000, 0x41b07c5900000000,\n    0x8f26e31a00000000, 0xd7a601cd00000000, 0x7e20576e00000000,\n    0x26a0b5b900000000, 0x6d2b8bf300000000, 0x35ab692400000000,\n    0x9c2d3f8700000000, 0xc4addd5000000000, 0x1476842600000000,\n    0x4cf666f100000000, 0xe570305200000000, 0xbdf0d28500000000,\n    0xf67beccf00000000, 0xaefb0e1800000000, 0x077d58bb00000000,\n    0x5ffdba6c00000000, 0x916b252f00000000, 0xc9ebc7f800000000,\n    0x606d915b00000000, 0x38ed738c00000000, 0x73664dc600000000,\n    0x2be6af1100000000, 0x8260f9b200000000, 0xdae01b6500000000,\n    0x1e4dc63500000000, 0x46cd24e200000000, 0xef4b724100000000,\n    0xb7cb909600000000, 0xfc40aedc00000000, 0xa4c04c0b00000000,\n    0x0d461aa800000000, 0x55c6f87f00000000, 0x9b50673c00000000,\n    0xc3d085eb00000000, 0x6a56d34800000000, 0x32d6319f00000000,\n    0x795d0fd500000000, 0x21dded0200000000, 0x885bbba100000000,\n    0xd0db597600000000, 0x28ec084d00000000, 0x706cea9a00000000,\n    0xd9eabc3900000000, 0x816a5eee00000000, 0xcae160a400000000,\n    0x9261827300000000, 0x3be7d4d000000000, 0x6367360700000000,\n    0xadf1a94400000000, 0xf5714b9300000000, 0x5cf71d3000000000,\n    0x0477ffe700000000, 0x4ffcc1ad00000000, 0x177c237a00000000,\n    0xbefa75d900000000, 0xe67a970e00000000, 0x22d74a5e00000000,\n    0x7a57a88900000000, 0xd3d1fe2a00000000, 0x8b511cfd00000000,\n    0xc0da22b700000000, 0x985ac06000000000, 0x31dc96c300000000,\n    0x695c741400000000, 0xa7caeb5700000000, 0xff4a098000000000,\n    0x56cc5f2300000000, 0x0e4cbdf400000000, 0x45c783be00000000,\n    0x1d47616900000000, 0xb4c137ca00000000, 0xec41d51d00000000,\n    0x3c9a8c6b00000000, 0x641a6ebc00000000, 0xcd9c381f00000000,\n    0x951cdac800000000, 0xde97e48200000000, 0x8617065500000000,\n    0x2f9150f600000000, 0x7711b22100000000, 0xb9872d6200000000,\n    0xe107cfb500000000, 0x4881991600000000, 0x10017bc100000000,\n    0x5b8a458b00000000, 0x030aa75c00000000, 0xaa8cf1ff00000000,\n    0xf20c132800000000, 0x36a1ce7800000000, 0x6e212caf00000000,\n    0xc7a77a0c00000000, 0x9f2798db00000000, 0xd4aca69100000000,\n    0x8c2c444600000000, 0x25aa12e500000000, 0x7d2af03200000000,\n    0xb3bc6f7100000000, 0xeb3c8da600000000, 0x42badb0500000000,\n    0x1a3a39d200000000, 0x51b1079800000000, 0x0931e54f00000000,\n    0xa0b7b3ec00000000, 0xf837513b00000000, 0x50d8119a00000000,\n    0x0858f34d00000000, 0xa1dea5ee00000000, 0xf95e473900000000,\n    0xb2d5797300000000, 0xea559ba400000000, 0x43d3cd0700000000,\n    0x1b532fd000000000, 0xd5c5b09300000000, 0x8d45524400000000,\n    0x24c304e700000000, 0x7c43e63000000000, 0x37c8d87a00000000,\n    0x6f483aad00000000, 0xc6ce6c0e00000000, 0x9e4e8ed900000000,\n    0x5ae3538900000000, 0x0263b15e00000000, 0xabe5e7fd00000000,\n    0xf365052a00000000, 0xb8ee3b6000000000, 0xe06ed9b700000000,\n    0x49e88f1400000000, 0x11686dc300000000, 0xdffef28000000000,\n    0x877e105700000000, 0x2ef846f400000000, 0x7678a42300000000,\n    0x3df39a6900000000, 0x657378be00000000, 0xccf52e1d00000000,\n    0x9475ccca00000000, 0x44ae95bc00000000, 0x1c2e776b00000000,\n    0xb5a821c800000000, 0xed28c31f00000000, 0xa6a3fd5500000000,\n    0xfe231f8200000000, 0x57a5492100000000, 0x0f25abf600000000,\n    0xc1b334b500000000, 0x9933d66200000000, 0x30b580c100000000,\n    0x6835621600000000, 0x23be5c5c00000000, 0x7b3ebe8b00000000,\n    0xd2b8e82800000000, 0x8a380aff00000000, 0x4e95d7af00000000,\n    0x1615357800000000, 0xbf9363db00000000, 0xe713810c00000000,\n    0xac98bf4600000000, 0xf4185d9100000000, 0x5d9e0b3200000000,\n    0x051ee9e500000000, 0xcb8876a600000000, 0x9308947100000000,\n    0x3a8ec2d200000000, 0x620e200500000000, 0x29851e4f00000000,\n    0x7105fc9800000000, 0xd883aa3b00000000, 0x800348ec00000000,\n    0x783419d700000000, 0x20b4fb0000000000, 0x8932ada300000000,\n    0xd1b24f7400000000, 0x9a39713e00000000, 0xc2b993e900000000,\n    0x6b3fc54a00000000, 0x33bf279d00000000, 0xfd29b8de00000000,\n    0xa5a95a0900000000, 0x0c2f0caa00000000, 0x54afee7d00000000,\n    0x1f24d03700000000, 0x47a432e000000000, 0xee22644300000000,\n    0xb6a2869400000000, 0x720f5bc400000000, 0x2a8fb91300000000,\n    0x8309efb000000000, 0xdb890d6700000000, 0x9002332d00000000,\n    0xc882d1fa00000000, 0x6104875900000000, 0x3984658e00000000,\n    0xf712facd00000000, 0xaf92181a00000000, 0x06144eb900000000,\n    0x5e94ac6e00000000, 0x151f922400000000, 0x4d9f70f300000000,\n    0xe419265000000000, 0xbc99c48700000000, 0x6c429df100000000,\n    0x34c27f2600000000, 0x9d44298500000000, 0xc5c4cb5200000000,\n    0x8e4ff51800000000, 0xd6cf17cf00000000, 0x7f49416c00000000,\n    0x27c9a3bb00000000, 0xe95f3cf800000000, 0xb1dfde2f00000000,\n    0x1859888c00000000, 0x40d96a5b00000000, 0x0b52541100000000,\n    0x53d2b6c600000000, 0xfa54e06500000000, 0xa2d402b200000000,\n    0x6679dfe200000000, 0x3ef93d3500000000, 0x977f6b9600000000,\n    0xcfff894100000000, 0x8474b70b00000000, 0xdcf455dc00000000,\n    0x7572037f00000000, 0x2df2e1a800000000, 0xe3647eeb00000000,\n    0xbbe49c3c00000000, 0x1262ca9f00000000, 0x4ae2284800000000,\n    0x0169160200000000, 0x59e9f4d500000000, 0xf06fa27600000000,\n    0xa8ef40a100000000},\n   {0x0000000000000000, 0x463b676500000000, 0x8c76ceca00000000,\n    0xca4da9af00000000, 0x59ebed4e00000000, 0x1fd08a2b00000000,\n    0xd59d238400000000, 0x93a644e100000000, 0xb2d6db9d00000000,\n    0xf4edbcf800000000, 0x3ea0155700000000, 0x789b723200000000,\n    0xeb3d36d300000000, 0xad0651b600000000, 0x674bf81900000000,\n    0x21709f7c00000000, 0x25abc6e000000000, 0x6390a18500000000,\n    0xa9dd082a00000000, 0xefe66f4f00000000, 0x7c402bae00000000,\n    0x3a7b4ccb00000000, 0xf036e56400000000, 0xb60d820100000000,\n    0x977d1d7d00000000, 0xd1467a1800000000, 0x1b0bd3b700000000,\n    0x5d30b4d200000000, 0xce96f03300000000, 0x88ad975600000000,\n    0x42e03ef900000000, 0x04db599c00000000, 0x0b50fc1a00000000,\n    0x4d6b9b7f00000000, 0x872632d000000000, 0xc11d55b500000000,\n    0x52bb115400000000, 0x1480763100000000, 0xdecddf9e00000000,\n    0x98f6b8fb00000000, 0xb986278700000000, 0xffbd40e200000000,\n    0x35f0e94d00000000, 0x73cb8e2800000000, 0xe06dcac900000000,\n    0xa656adac00000000, 0x6c1b040300000000, 0x2a20636600000000,\n    0x2efb3afa00000000, 0x68c05d9f00000000, 0xa28df43000000000,\n    0xe4b6935500000000, 0x7710d7b400000000, 0x312bb0d100000000,\n    0xfb66197e00000000, 0xbd5d7e1b00000000, 0x9c2de16700000000,\n    0xda16860200000000, 0x105b2fad00000000, 0x566048c800000000,\n    0xc5c60c2900000000, 0x83fd6b4c00000000, 0x49b0c2e300000000,\n    0x0f8ba58600000000, 0x16a0f83500000000, 0x509b9f5000000000,\n    0x9ad636ff00000000, 0xdced519a00000000, 0x4f4b157b00000000,\n    0x0970721e00000000, 0xc33ddbb100000000, 0x8506bcd400000000,\n    0xa47623a800000000, 0xe24d44cd00000000, 0x2800ed6200000000,\n    0x6e3b8a0700000000, 0xfd9dcee600000000, 0xbba6a98300000000,\n    0x71eb002c00000000, 0x37d0674900000000, 0x330b3ed500000000,\n    0x753059b000000000, 0xbf7df01f00000000, 0xf946977a00000000,\n    0x6ae0d39b00000000, 0x2cdbb4fe00000000, 0xe6961d5100000000,\n    0xa0ad7a3400000000, 0x81dde54800000000, 0xc7e6822d00000000,\n    0x0dab2b8200000000, 0x4b904ce700000000, 0xd836080600000000,\n    0x9e0d6f6300000000, 0x5440c6cc00000000, 0x127ba1a900000000,\n    0x1df0042f00000000, 0x5bcb634a00000000, 0x9186cae500000000,\n    0xd7bdad8000000000, 0x441be96100000000, 0x02208e0400000000,\n    0xc86d27ab00000000, 0x8e5640ce00000000, 0xaf26dfb200000000,\n    0xe91db8d700000000, 0x2350117800000000, 0x656b761d00000000,\n    0xf6cd32fc00000000, 0xb0f6559900000000, 0x7abbfc3600000000,\n    0x3c809b5300000000, 0x385bc2cf00000000, 0x7e60a5aa00000000,\n    0xb42d0c0500000000, 0xf2166b6000000000, 0x61b02f8100000000,\n    0x278b48e400000000, 0xedc6e14b00000000, 0xabfd862e00000000,\n    0x8a8d195200000000, 0xccb67e3700000000, 0x06fbd79800000000,\n    0x40c0b0fd00000000, 0xd366f41c00000000, 0x955d937900000000,\n    0x5f103ad600000000, 0x192b5db300000000, 0x2c40f16b00000000,\n    0x6a7b960e00000000, 0xa0363fa100000000, 0xe60d58c400000000,\n    0x75ab1c2500000000, 0x33907b4000000000, 0xf9ddd2ef00000000,\n    0xbfe6b58a00000000, 0x9e962af600000000, 0xd8ad4d9300000000,\n    0x12e0e43c00000000, 0x54db835900000000, 0xc77dc7b800000000,\n    0x8146a0dd00000000, 0x4b0b097200000000, 0x0d306e1700000000,\n    0x09eb378b00000000, 0x4fd050ee00000000, 0x859df94100000000,\n    0xc3a69e2400000000, 0x5000dac500000000, 0x163bbda000000000,\n    0xdc76140f00000000, 0x9a4d736a00000000, 0xbb3dec1600000000,\n    0xfd068b7300000000, 0x374b22dc00000000, 0x717045b900000000,\n    0xe2d6015800000000, 0xa4ed663d00000000, 0x6ea0cf9200000000,\n    0x289ba8f700000000, 0x27100d7100000000, 0x612b6a1400000000,\n    0xab66c3bb00000000, 0xed5da4de00000000, 0x7efbe03f00000000,\n    0x38c0875a00000000, 0xf28d2ef500000000, 0xb4b6499000000000,\n    0x95c6d6ec00000000, 0xd3fdb18900000000, 0x19b0182600000000,\n    0x5f8b7f4300000000, 0xcc2d3ba200000000, 0x8a165cc700000000,\n    0x405bf56800000000, 0x0660920d00000000, 0x02bbcb9100000000,\n    0x4480acf400000000, 0x8ecd055b00000000, 0xc8f6623e00000000,\n    0x5b5026df00000000, 0x1d6b41ba00000000, 0xd726e81500000000,\n    0x911d8f7000000000, 0xb06d100c00000000, 0xf656776900000000,\n    0x3c1bdec600000000, 0x7a20b9a300000000, 0xe986fd4200000000,\n    0xafbd9a2700000000, 0x65f0338800000000, 0x23cb54ed00000000,\n    0x3ae0095e00000000, 0x7cdb6e3b00000000, 0xb696c79400000000,\n    0xf0ada0f100000000, 0x630be41000000000, 0x2530837500000000,\n    0xef7d2ada00000000, 0xa9464dbf00000000, 0x8836d2c300000000,\n    0xce0db5a600000000, 0x04401c0900000000, 0x427b7b6c00000000,\n    0xd1dd3f8d00000000, 0x97e658e800000000, 0x5dabf14700000000,\n    0x1b90962200000000, 0x1f4bcfbe00000000, 0x5970a8db00000000,\n    0x933d017400000000, 0xd506661100000000, 0x46a022f000000000,\n    0x009b459500000000, 0xcad6ec3a00000000, 0x8ced8b5f00000000,\n    0xad9d142300000000, 0xeba6734600000000, 0x21ebdae900000000,\n    0x67d0bd8c00000000, 0xf476f96d00000000, 0xb24d9e0800000000,\n    0x780037a700000000, 0x3e3b50c200000000, 0x31b0f54400000000,\n    0x778b922100000000, 0xbdc63b8e00000000, 0xfbfd5ceb00000000,\n    0x685b180a00000000, 0x2e607f6f00000000, 0xe42dd6c000000000,\n    0xa216b1a500000000, 0x83662ed900000000, 0xc55d49bc00000000,\n    0x0f10e01300000000, 0x492b877600000000, 0xda8dc39700000000,\n    0x9cb6a4f200000000, 0x56fb0d5d00000000, 0x10c06a3800000000,\n    0x141b33a400000000, 0x522054c100000000, 0x986dfd6e00000000,\n    0xde569a0b00000000, 0x4df0deea00000000, 0x0bcbb98f00000000,\n    0xc186102000000000, 0x87bd774500000000, 0xa6cde83900000000,\n    0xe0f68f5c00000000, 0x2abb26f300000000, 0x6c80419600000000,\n    0xff26057700000000, 0xb91d621200000000, 0x7350cbbd00000000,\n    0x356bacd800000000},\n   {0x0000000000000000, 0x9e83da9f00000000, 0x7d01c4e400000000,\n    0xe3821e7b00000000, 0xbb04f91200000000, 0x2587238d00000000,\n    0xc6053df600000000, 0x5886e76900000000, 0x7609f22500000000,\n    0xe88a28ba00000000, 0x0b0836c100000000, 0x958bec5e00000000,\n    0xcd0d0b3700000000, 0x538ed1a800000000, 0xb00ccfd300000000,\n    0x2e8f154c00000000, 0xec12e44b00000000, 0x72913ed400000000,\n    0x911320af00000000, 0x0f90fa3000000000, 0x57161d5900000000,\n    0xc995c7c600000000, 0x2a17d9bd00000000, 0xb494032200000000,\n    0x9a1b166e00000000, 0x0498ccf100000000, 0xe71ad28a00000000,\n    0x7999081500000000, 0x211fef7c00000000, 0xbf9c35e300000000,\n    0x5c1e2b9800000000, 0xc29df10700000000, 0xd825c89700000000,\n    0x46a6120800000000, 0xa5240c7300000000, 0x3ba7d6ec00000000,\n    0x6321318500000000, 0xfda2eb1a00000000, 0x1e20f56100000000,\n    0x80a32ffe00000000, 0xae2c3ab200000000, 0x30afe02d00000000,\n    0xd32dfe5600000000, 0x4dae24c900000000, 0x1528c3a000000000,\n    0x8bab193f00000000, 0x6829074400000000, 0xf6aadddb00000000,\n    0x34372cdc00000000, 0xaab4f64300000000, 0x4936e83800000000,\n    0xd7b532a700000000, 0x8f33d5ce00000000, 0x11b00f5100000000,\n    0xf232112a00000000, 0x6cb1cbb500000000, 0x423edef900000000,\n    0xdcbd046600000000, 0x3f3f1a1d00000000, 0xa1bcc08200000000,\n    0xf93a27eb00000000, 0x67b9fd7400000000, 0x843be30f00000000,\n    0x1ab8399000000000, 0xf14de1f400000000, 0x6fce3b6b00000000,\n    0x8c4c251000000000, 0x12cfff8f00000000, 0x4a4918e600000000,\n    0xd4cac27900000000, 0x3748dc0200000000, 0xa9cb069d00000000,\n    0x874413d100000000, 0x19c7c94e00000000, 0xfa45d73500000000,\n    0x64c60daa00000000, 0x3c40eac300000000, 0xa2c3305c00000000,\n    0x41412e2700000000, 0xdfc2f4b800000000, 0x1d5f05bf00000000,\n    0x83dcdf2000000000, 0x605ec15b00000000, 0xfedd1bc400000000,\n    0xa65bfcad00000000, 0x38d8263200000000, 0xdb5a384900000000,\n    0x45d9e2d600000000, 0x6b56f79a00000000, 0xf5d52d0500000000,\n    0x1657337e00000000, 0x88d4e9e100000000, 0xd0520e8800000000,\n    0x4ed1d41700000000, 0xad53ca6c00000000, 0x33d010f300000000,\n    0x2968296300000000, 0xb7ebf3fc00000000, 0x5469ed8700000000,\n    0xcaea371800000000, 0x926cd07100000000, 0x0cef0aee00000000,\n    0xef6d149500000000, 0x71eece0a00000000, 0x5f61db4600000000,\n    0xc1e201d900000000, 0x22601fa200000000, 0xbce3c53d00000000,\n    0xe465225400000000, 0x7ae6f8cb00000000, 0x9964e6b000000000,\n    0x07e73c2f00000000, 0xc57acd2800000000, 0x5bf917b700000000,\n    0xb87b09cc00000000, 0x26f8d35300000000, 0x7e7e343a00000000,\n    0xe0fdeea500000000, 0x037ff0de00000000, 0x9dfc2a4100000000,\n    0xb3733f0d00000000, 0x2df0e59200000000, 0xce72fbe900000000,\n    0x50f1217600000000, 0x0877c61f00000000, 0x96f41c8000000000,\n    0x757602fb00000000, 0xebf5d86400000000, 0xa39db33200000000,\n    0x3d1e69ad00000000, 0xde9c77d600000000, 0x401fad4900000000,\n    0x18994a2000000000, 0x861a90bf00000000, 0x65988ec400000000,\n    0xfb1b545b00000000, 0xd594411700000000, 0x4b179b8800000000,\n    0xa89585f300000000, 0x36165f6c00000000, 0x6e90b80500000000,\n    0xf013629a00000000, 0x13917ce100000000, 0x8d12a67e00000000,\n    0x4f8f577900000000, 0xd10c8de600000000, 0x328e939d00000000,\n    0xac0d490200000000, 0xf48bae6b00000000, 0x6a0874f400000000,\n    0x898a6a8f00000000, 0x1709b01000000000, 0x3986a55c00000000,\n    0xa7057fc300000000, 0x448761b800000000, 0xda04bb2700000000,\n    0x82825c4e00000000, 0x1c0186d100000000, 0xff8398aa00000000,\n    0x6100423500000000, 0x7bb87ba500000000, 0xe53ba13a00000000,\n    0x06b9bf4100000000, 0x983a65de00000000, 0xc0bc82b700000000,\n    0x5e3f582800000000, 0xbdbd465300000000, 0x233e9ccc00000000,\n    0x0db1898000000000, 0x9332531f00000000, 0x70b04d6400000000,\n    0xee3397fb00000000, 0xb6b5709200000000, 0x2836aa0d00000000,\n    0xcbb4b47600000000, 0x55376ee900000000, 0x97aa9fee00000000,\n    0x0929457100000000, 0xeaab5b0a00000000, 0x7428819500000000,\n    0x2cae66fc00000000, 0xb22dbc6300000000, 0x51afa21800000000,\n    0xcf2c788700000000, 0xe1a36dcb00000000, 0x7f20b75400000000,\n    0x9ca2a92f00000000, 0x022173b000000000, 0x5aa794d900000000,\n    0xc4244e4600000000, 0x27a6503d00000000, 0xb9258aa200000000,\n    0x52d052c600000000, 0xcc53885900000000, 0x2fd1962200000000,\n    0xb1524cbd00000000, 0xe9d4abd400000000, 0x7757714b00000000,\n    0x94d56f3000000000, 0x0a56b5af00000000, 0x24d9a0e300000000,\n    0xba5a7a7c00000000, 0x59d8640700000000, 0xc75bbe9800000000,\n    0x9fdd59f100000000, 0x015e836e00000000, 0xe2dc9d1500000000,\n    0x7c5f478a00000000, 0xbec2b68d00000000, 0x20416c1200000000,\n    0xc3c3726900000000, 0x5d40a8f600000000, 0x05c64f9f00000000,\n    0x9b45950000000000, 0x78c78b7b00000000, 0xe64451e400000000,\n    0xc8cb44a800000000, 0x56489e3700000000, 0xb5ca804c00000000,\n    0x2b495ad300000000, 0x73cfbdba00000000, 0xed4c672500000000,\n    0x0ece795e00000000, 0x904da3c100000000, 0x8af59a5100000000,\n    0x147640ce00000000, 0xf7f45eb500000000, 0x6977842a00000000,\n    0x31f1634300000000, 0xaf72b9dc00000000, 0x4cf0a7a700000000,\n    0xd2737d3800000000, 0xfcfc687400000000, 0x627fb2eb00000000,\n    0x81fdac9000000000, 0x1f7e760f00000000, 0x47f8916600000000,\n    0xd97b4bf900000000, 0x3af9558200000000, 0xa47a8f1d00000000,\n    0x66e77e1a00000000, 0xf864a48500000000, 0x1be6bafe00000000,\n    0x8565606100000000, 0xdde3870800000000, 0x43605d9700000000,\n    0xa0e243ec00000000, 0x3e61997300000000, 0x10ee8c3f00000000,\n    0x8e6d56a000000000, 0x6def48db00000000, 0xf36c924400000000,\n    0xabea752d00000000, 0x3569afb200000000, 0xd6ebb1c900000000,\n    0x48686b5600000000},\n   {0x0000000000000000, 0xc064281700000000, 0x80c9502e00000000,\n    0x40ad783900000000, 0x0093a15c00000000, 0xc0f7894b00000000,\n    0x805af17200000000, 0x403ed96500000000, 0x002643b900000000,\n    0xc0426bae00000000, 0x80ef139700000000, 0x408b3b8000000000,\n    0x00b5e2e500000000, 0xc0d1caf200000000, 0x807cb2cb00000000,\n    0x40189adc00000000, 0x414af7a900000000, 0x812edfbe00000000,\n    0xc183a78700000000, 0x01e78f9000000000, 0x41d956f500000000,\n    0x81bd7ee200000000, 0xc11006db00000000, 0x01742ecc00000000,\n    0x416cb41000000000, 0x81089c0700000000, 0xc1a5e43e00000000,\n    0x01c1cc2900000000, 0x41ff154c00000000, 0x819b3d5b00000000,\n    0xc136456200000000, 0x01526d7500000000, 0xc3929f8800000000,\n    0x03f6b79f00000000, 0x435bcfa600000000, 0x833fe7b100000000,\n    0xc3013ed400000000, 0x036516c300000000, 0x43c86efa00000000,\n    0x83ac46ed00000000, 0xc3b4dc3100000000, 0x03d0f42600000000,\n    0x437d8c1f00000000, 0x8319a40800000000, 0xc3277d6d00000000,\n    0x0343557a00000000, 0x43ee2d4300000000, 0x838a055400000000,\n    0x82d8682100000000, 0x42bc403600000000, 0x0211380f00000000,\n    0xc275101800000000, 0x824bc97d00000000, 0x422fe16a00000000,\n    0x0282995300000000, 0xc2e6b14400000000, 0x82fe2b9800000000,\n    0x429a038f00000000, 0x02377bb600000000, 0xc25353a100000000,\n    0x826d8ac400000000, 0x4209a2d300000000, 0x02a4daea00000000,\n    0xc2c0f2fd00000000, 0xc7234eca00000000, 0x074766dd00000000,\n    0x47ea1ee400000000, 0x878e36f300000000, 0xc7b0ef9600000000,\n    0x07d4c78100000000, 0x4779bfb800000000, 0x871d97af00000000,\n    0xc7050d7300000000, 0x0761256400000000, 0x47cc5d5d00000000,\n    0x87a8754a00000000, 0xc796ac2f00000000, 0x07f2843800000000,\n    0x475ffc0100000000, 0x873bd41600000000, 0x8669b96300000000,\n    0x460d917400000000, 0x06a0e94d00000000, 0xc6c4c15a00000000,\n    0x86fa183f00000000, 0x469e302800000000, 0x0633481100000000,\n    0xc657600600000000, 0x864ffada00000000, 0x462bd2cd00000000,\n    0x0686aaf400000000, 0xc6e282e300000000, 0x86dc5b8600000000,\n    0x46b8739100000000, 0x06150ba800000000, 0xc67123bf00000000,\n    0x04b1d14200000000, 0xc4d5f95500000000, 0x8478816c00000000,\n    0x441ca97b00000000, 0x0422701e00000000, 0xc446580900000000,\n    0x84eb203000000000, 0x448f082700000000, 0x049792fb00000000,\n    0xc4f3baec00000000, 0x845ec2d500000000, 0x443aeac200000000,\n    0x040433a700000000, 0xc4601bb000000000, 0x84cd638900000000,\n    0x44a94b9e00000000, 0x45fb26eb00000000, 0x859f0efc00000000,\n    0xc53276c500000000, 0x05565ed200000000, 0x456887b700000000,\n    0x850cafa000000000, 0xc5a1d79900000000, 0x05c5ff8e00000000,\n    0x45dd655200000000, 0x85b94d4500000000, 0xc514357c00000000,\n    0x05701d6b00000000, 0x454ec40e00000000, 0x852aec1900000000,\n    0xc587942000000000, 0x05e3bc3700000000, 0xcf41ed4f00000000,\n    0x0f25c55800000000, 0x4f88bd6100000000, 0x8fec957600000000,\n    0xcfd24c1300000000, 0x0fb6640400000000, 0x4f1b1c3d00000000,\n    0x8f7f342a00000000, 0xcf67aef600000000, 0x0f0386e100000000,\n    0x4faefed800000000, 0x8fcad6cf00000000, 0xcff40faa00000000,\n    0x0f9027bd00000000, 0x4f3d5f8400000000, 0x8f59779300000000,\n    0x8e0b1ae600000000, 0x4e6f32f100000000, 0x0ec24ac800000000,\n    0xcea662df00000000, 0x8e98bbba00000000, 0x4efc93ad00000000,\n    0x0e51eb9400000000, 0xce35c38300000000, 0x8e2d595f00000000,\n    0x4e49714800000000, 0x0ee4097100000000, 0xce80216600000000,\n    0x8ebef80300000000, 0x4edad01400000000, 0x0e77a82d00000000,\n    0xce13803a00000000, 0x0cd372c700000000, 0xccb75ad000000000,\n    0x8c1a22e900000000, 0x4c7e0afe00000000, 0x0c40d39b00000000,\n    0xcc24fb8c00000000, 0x8c8983b500000000, 0x4cedaba200000000,\n    0x0cf5317e00000000, 0xcc91196900000000, 0x8c3c615000000000,\n    0x4c58494700000000, 0x0c66902200000000, 0xcc02b83500000000,\n    0x8cafc00c00000000, 0x4ccbe81b00000000, 0x4d99856e00000000,\n    0x8dfdad7900000000, 0xcd50d54000000000, 0x0d34fd5700000000,\n    0x4d0a243200000000, 0x8d6e0c2500000000, 0xcdc3741c00000000,\n    0x0da75c0b00000000, 0x4dbfc6d700000000, 0x8ddbeec000000000,\n    0xcd7696f900000000, 0x0d12beee00000000, 0x4d2c678b00000000,\n    0x8d484f9c00000000, 0xcde537a500000000, 0x0d811fb200000000,\n    0x0862a38500000000, 0xc8068b9200000000, 0x88abf3ab00000000,\n    0x48cfdbbc00000000, 0x08f102d900000000, 0xc8952ace00000000,\n    0x883852f700000000, 0x485c7ae000000000, 0x0844e03c00000000,\n    0xc820c82b00000000, 0x888db01200000000, 0x48e9980500000000,\n    0x08d7416000000000, 0xc8b3697700000000, 0x881e114e00000000,\n    0x487a395900000000, 0x4928542c00000000, 0x894c7c3b00000000,\n    0xc9e1040200000000, 0x09852c1500000000, 0x49bbf57000000000,\n    0x89dfdd6700000000, 0xc972a55e00000000, 0x09168d4900000000,\n    0x490e179500000000, 0x896a3f8200000000, 0xc9c747bb00000000,\n    0x09a36fac00000000, 0x499db6c900000000, 0x89f99ede00000000,\n    0xc954e6e700000000, 0x0930cef000000000, 0xcbf03c0d00000000,\n    0x0b94141a00000000, 0x4b396c2300000000, 0x8b5d443400000000,\n    0xcb639d5100000000, 0x0b07b54600000000, 0x4baacd7f00000000,\n    0x8bcee56800000000, 0xcbd67fb400000000, 0x0bb257a300000000,\n    0x4b1f2f9a00000000, 0x8b7b078d00000000, 0xcb45dee800000000,\n    0x0b21f6ff00000000, 0x4b8c8ec600000000, 0x8be8a6d100000000,\n    0x8abacba400000000, 0x4adee3b300000000, 0x0a739b8a00000000,\n    0xca17b39d00000000, 0x8a296af800000000, 0x4a4d42ef00000000,\n    0x0ae03ad600000000, 0xca8412c100000000, 0x8a9c881d00000000,\n    0x4af8a00a00000000, 0x0a55d83300000000, 0xca31f02400000000,\n    0x8a0f294100000000, 0x4a6b015600000000, 0x0ac6796f00000000,\n    0xcaa2517800000000},\n   {0x0000000000000000, 0xd4ea739b00000000, 0xe9d396ed00000000,\n    0x3d39e57600000000, 0x93a15c0000000000, 0x474b2f9b00000000,\n    0x7a72caed00000000, 0xae98b97600000000, 0x2643b90000000000,\n    0xf2a9ca9b00000000, 0xcf902fed00000000, 0x1b7a5c7600000000,\n    0xb5e2e50000000000, 0x6108969b00000000, 0x5c3173ed00000000,\n    0x88db007600000000, 0x4c86720100000000, 0x986c019a00000000,\n    0xa555e4ec00000000, 0x71bf977700000000, 0xdf272e0100000000,\n    0x0bcd5d9a00000000, 0x36f4b8ec00000000, 0xe21ecb7700000000,\n    0x6ac5cb0100000000, 0xbe2fb89a00000000, 0x83165dec00000000,\n    0x57fc2e7700000000, 0xf964970100000000, 0x2d8ee49a00000000,\n    0x10b701ec00000000, 0xc45d727700000000, 0x980ce50200000000,\n    0x4ce6969900000000, 0x71df73ef00000000, 0xa535007400000000,\n    0x0badb90200000000, 0xdf47ca9900000000, 0xe27e2fef00000000,\n    0x36945c7400000000, 0xbe4f5c0200000000, 0x6aa52f9900000000,\n    0x579ccaef00000000, 0x8376b97400000000, 0x2dee000200000000,\n    0xf904739900000000, 0xc43d96ef00000000, 0x10d7e57400000000,\n    0xd48a970300000000, 0x0060e49800000000, 0x3d5901ee00000000,\n    0xe9b3727500000000, 0x472bcb0300000000, 0x93c1b89800000000,\n    0xaef85dee00000000, 0x7a122e7500000000, 0xf2c92e0300000000,\n    0x26235d9800000000, 0x1b1ab8ee00000000, 0xcff0cb7500000000,\n    0x6168720300000000, 0xb582019800000000, 0x88bbe4ee00000000,\n    0x5c51977500000000, 0x3019ca0500000000, 0xe4f3b99e00000000,\n    0xd9ca5ce800000000, 0x0d202f7300000000, 0xa3b8960500000000,\n    0x7752e59e00000000, 0x4a6b00e800000000, 0x9e81737300000000,\n    0x165a730500000000, 0xc2b0009e00000000, 0xff89e5e800000000,\n    0x2b63967300000000, 0x85fb2f0500000000, 0x51115c9e00000000,\n    0x6c28b9e800000000, 0xb8c2ca7300000000, 0x7c9fb80400000000,\n    0xa875cb9f00000000, 0x954c2ee900000000, 0x41a65d7200000000,\n    0xef3ee40400000000, 0x3bd4979f00000000, 0x06ed72e900000000,\n    0xd207017200000000, 0x5adc010400000000, 0x8e36729f00000000,\n    0xb30f97e900000000, 0x67e5e47200000000, 0xc97d5d0400000000,\n    0x1d972e9f00000000, 0x20aecbe900000000, 0xf444b87200000000,\n    0xa8152f0700000000, 0x7cff5c9c00000000, 0x41c6b9ea00000000,\n    0x952cca7100000000, 0x3bb4730700000000, 0xef5e009c00000000,\n    0xd267e5ea00000000, 0x068d967100000000, 0x8e56960700000000,\n    0x5abce59c00000000, 0x678500ea00000000, 0xb36f737100000000,\n    0x1df7ca0700000000, 0xc91db99c00000000, 0xf4245cea00000000,\n    0x20ce2f7100000000, 0xe4935d0600000000, 0x30792e9d00000000,\n    0x0d40cbeb00000000, 0xd9aab87000000000, 0x7732010600000000,\n    0xa3d8729d00000000, 0x9ee197eb00000000, 0x4a0be47000000000,\n    0xc2d0e40600000000, 0x163a979d00000000, 0x2b0372eb00000000,\n    0xffe9017000000000, 0x5171b80600000000, 0x859bcb9d00000000,\n    0xb8a22eeb00000000, 0x6c485d7000000000, 0x6032940b00000000,\n    0xb4d8e79000000000, 0x89e102e600000000, 0x5d0b717d00000000,\n    0xf393c80b00000000, 0x2779bb9000000000, 0x1a405ee600000000,\n    0xceaa2d7d00000000, 0x46712d0b00000000, 0x929b5e9000000000,\n    0xafa2bbe600000000, 0x7b48c87d00000000, 0xd5d0710b00000000,\n    0x013a029000000000, 0x3c03e7e600000000, 0xe8e9947d00000000,\n    0x2cb4e60a00000000, 0xf85e959100000000, 0xc56770e700000000,\n    0x118d037c00000000, 0xbf15ba0a00000000, 0x6bffc99100000000,\n    0x56c62ce700000000, 0x822c5f7c00000000, 0x0af75f0a00000000,\n    0xde1d2c9100000000, 0xe324c9e700000000, 0x37ceba7c00000000,\n    0x9956030a00000000, 0x4dbc709100000000, 0x708595e700000000,\n    0xa46fe67c00000000, 0xf83e710900000000, 0x2cd4029200000000,\n    0x11ede7e400000000, 0xc507947f00000000, 0x6b9f2d0900000000,\n    0xbf755e9200000000, 0x824cbbe400000000, 0x56a6c87f00000000,\n    0xde7dc80900000000, 0x0a97bb9200000000, 0x37ae5ee400000000,\n    0xe3442d7f00000000, 0x4ddc940900000000, 0x9936e79200000000,\n    0xa40f02e400000000, 0x70e5717f00000000, 0xb4b8030800000000,\n    0x6052709300000000, 0x5d6b95e500000000, 0x8981e67e00000000,\n    0x27195f0800000000, 0xf3f32c9300000000, 0xcecac9e500000000,\n    0x1a20ba7e00000000, 0x92fbba0800000000, 0x4611c99300000000,\n    0x7b282ce500000000, 0xafc25f7e00000000, 0x015ae60800000000,\n    0xd5b0959300000000, 0xe88970e500000000, 0x3c63037e00000000,\n    0x502b5e0e00000000, 0x84c12d9500000000, 0xb9f8c8e300000000,\n    0x6d12bb7800000000, 0xc38a020e00000000, 0x1760719500000000,\n    0x2a5994e300000000, 0xfeb3e77800000000, 0x7668e70e00000000,\n    0xa282949500000000, 0x9fbb71e300000000, 0x4b51027800000000,\n    0xe5c9bb0e00000000, 0x3123c89500000000, 0x0c1a2de300000000,\n    0xd8f05e7800000000, 0x1cad2c0f00000000, 0xc8475f9400000000,\n    0xf57ebae200000000, 0x2194c97900000000, 0x8f0c700f00000000,\n    0x5be6039400000000, 0x66dfe6e200000000, 0xb235957900000000,\n    0x3aee950f00000000, 0xee04e69400000000, 0xd33d03e200000000,\n    0x07d7707900000000, 0xa94fc90f00000000, 0x7da5ba9400000000,\n    0x409c5fe200000000, 0x94762c7900000000, 0xc827bb0c00000000,\n    0x1ccdc89700000000, 0x21f42de100000000, 0xf51e5e7a00000000,\n    0x5b86e70c00000000, 0x8f6c949700000000, 0xb25571e100000000,\n    0x66bf027a00000000, 0xee64020c00000000, 0x3a8e719700000000,\n    0x07b794e100000000, 0xd35de77a00000000, 0x7dc55e0c00000000,\n    0xa92f2d9700000000, 0x9416c8e100000000, 0x40fcbb7a00000000,\n    0x84a1c90d00000000, 0x504bba9600000000, 0x6d725fe000000000,\n    0xb9982c7b00000000, 0x1700950d00000000, 0xc3eae69600000000,\n    0xfed303e000000000, 0x2a39707b00000000, 0xa2e2700d00000000,\n    0x7608039600000000, 0x4b31e6e000000000, 0x9fdb957b00000000,\n    0x31432c0d00000000, 0xe5a95f9600000000, 0xd890bae000000000,\n    0x0c7ac97b00000000},\n   {0x0000000000000000, 0x2765258100000000, 0x0fcc3bd900000000,\n    0x28a91e5800000000, 0x5f9e066900000000, 0x78fb23e800000000,\n    0x50523db000000000, 0x7737183100000000, 0xbe3c0dd200000000,\n    0x9959285300000000, 0xb1f0360b00000000, 0x9695138a00000000,\n    0xe1a20bbb00000000, 0xc6c72e3a00000000, 0xee6e306200000000,\n    0xc90b15e300000000, 0x3d7f6b7f00000000, 0x1a1a4efe00000000,\n    0x32b350a600000000, 0x15d6752700000000, 0x62e16d1600000000,\n    0x4584489700000000, 0x6d2d56cf00000000, 0x4a48734e00000000,\n    0x834366ad00000000, 0xa426432c00000000, 0x8c8f5d7400000000,\n    0xabea78f500000000, 0xdcdd60c400000000, 0xfbb8454500000000,\n    0xd3115b1d00000000, 0xf4747e9c00000000, 0x7afed6fe00000000,\n    0x5d9bf37f00000000, 0x7532ed2700000000, 0x5257c8a600000000,\n    0x2560d09700000000, 0x0205f51600000000, 0x2aaceb4e00000000,\n    0x0dc9cecf00000000, 0xc4c2db2c00000000, 0xe3a7fead00000000,\n    0xcb0ee0f500000000, 0xec6bc57400000000, 0x9b5cdd4500000000,\n    0xbc39f8c400000000, 0x9490e69c00000000, 0xb3f5c31d00000000,\n    0x4781bd8100000000, 0x60e4980000000000, 0x484d865800000000,\n    0x6f28a3d900000000, 0x181fbbe800000000, 0x3f7a9e6900000000,\n    0x17d3803100000000, 0x30b6a5b000000000, 0xf9bdb05300000000,\n    0xded895d200000000, 0xf6718b8a00000000, 0xd114ae0b00000000,\n    0xa623b63a00000000, 0x814693bb00000000, 0xa9ef8de300000000,\n    0x8e8aa86200000000, 0xb5fadc2600000000, 0x929ff9a700000000,\n    0xba36e7ff00000000, 0x9d53c27e00000000, 0xea64da4f00000000,\n    0xcd01ffce00000000, 0xe5a8e19600000000, 0xc2cdc41700000000,\n    0x0bc6d1f400000000, 0x2ca3f47500000000, 0x040aea2d00000000,\n    0x236fcfac00000000, 0x5458d79d00000000, 0x733df21c00000000,\n    0x5b94ec4400000000, 0x7cf1c9c500000000, 0x8885b75900000000,\n    0xafe092d800000000, 0x87498c8000000000, 0xa02ca90100000000,\n    0xd71bb13000000000, 0xf07e94b100000000, 0xd8d78ae900000000,\n    0xffb2af6800000000, 0x36b9ba8b00000000, 0x11dc9f0a00000000,\n    0x3975815200000000, 0x1e10a4d300000000, 0x6927bce200000000,\n    0x4e42996300000000, 0x66eb873b00000000, 0x418ea2ba00000000,\n    0xcf040ad800000000, 0xe8612f5900000000, 0xc0c8310100000000,\n    0xe7ad148000000000, 0x909a0cb100000000, 0xb7ff293000000000,\n    0x9f56376800000000, 0xb83312e900000000, 0x7138070a00000000,\n    0x565d228b00000000, 0x7ef43cd300000000, 0x5991195200000000,\n    0x2ea6016300000000, 0x09c324e200000000, 0x216a3aba00000000,\n    0x060f1f3b00000000, 0xf27b61a700000000, 0xd51e442600000000,\n    0xfdb75a7e00000000, 0xdad27fff00000000, 0xade567ce00000000,\n    0x8a80424f00000000, 0xa2295c1700000000, 0x854c799600000000,\n    0x4c476c7500000000, 0x6b2249f400000000, 0x438b57ac00000000,\n    0x64ee722d00000000, 0x13d96a1c00000000, 0x34bc4f9d00000000,\n    0x1c1551c500000000, 0x3b70744400000000, 0x6af5b94d00000000,\n    0x4d909ccc00000000, 0x6539829400000000, 0x425ca71500000000,\n    0x356bbf2400000000, 0x120e9aa500000000, 0x3aa784fd00000000,\n    0x1dc2a17c00000000, 0xd4c9b49f00000000, 0xf3ac911e00000000,\n    0xdb058f4600000000, 0xfc60aac700000000, 0x8b57b2f600000000,\n    0xac32977700000000, 0x849b892f00000000, 0xa3feacae00000000,\n    0x578ad23200000000, 0x70eff7b300000000, 0x5846e9eb00000000,\n    0x7f23cc6a00000000, 0x0814d45b00000000, 0x2f71f1da00000000,\n    0x07d8ef8200000000, 0x20bdca0300000000, 0xe9b6dfe000000000,\n    0xced3fa6100000000, 0xe67ae43900000000, 0xc11fc1b800000000,\n    0xb628d98900000000, 0x914dfc0800000000, 0xb9e4e25000000000,\n    0x9e81c7d100000000, 0x100b6fb300000000, 0x376e4a3200000000,\n    0x1fc7546a00000000, 0x38a271eb00000000, 0x4f9569da00000000,\n    0x68f04c5b00000000, 0x4059520300000000, 0x673c778200000000,\n    0xae37626100000000, 0x895247e000000000, 0xa1fb59b800000000,\n    0x869e7c3900000000, 0xf1a9640800000000, 0xd6cc418900000000,\n    0xfe655fd100000000, 0xd9007a5000000000, 0x2d7404cc00000000,\n    0x0a11214d00000000, 0x22b83f1500000000, 0x05dd1a9400000000,\n    0x72ea02a500000000, 0x558f272400000000, 0x7d26397c00000000,\n    0x5a431cfd00000000, 0x9348091e00000000, 0xb42d2c9f00000000,\n    0x9c8432c700000000, 0xbbe1174600000000, 0xccd60f7700000000,\n    0xebb32af600000000, 0xc31a34ae00000000, 0xe47f112f00000000,\n    0xdf0f656b00000000, 0xf86a40ea00000000, 0xd0c35eb200000000,\n    0xf7a67b3300000000, 0x8091630200000000, 0xa7f4468300000000,\n    0x8f5d58db00000000, 0xa8387d5a00000000, 0x613368b900000000,\n    0x46564d3800000000, 0x6eff536000000000, 0x499a76e100000000,\n    0x3ead6ed000000000, 0x19c84b5100000000, 0x3161550900000000,\n    0x1604708800000000, 0xe2700e1400000000, 0xc5152b9500000000,\n    0xedbc35cd00000000, 0xcad9104c00000000, 0xbdee087d00000000,\n    0x9a8b2dfc00000000, 0xb22233a400000000, 0x9547162500000000,\n    0x5c4c03c600000000, 0x7b29264700000000, 0x5380381f00000000,\n    0x74e51d9e00000000, 0x03d205af00000000, 0x24b7202e00000000,\n    0x0c1e3e7600000000, 0x2b7b1bf700000000, 0xa5f1b39500000000,\n    0x8294961400000000, 0xaa3d884c00000000, 0x8d58adcd00000000,\n    0xfa6fb5fc00000000, 0xdd0a907d00000000, 0xf5a38e2500000000,\n    0xd2c6aba400000000, 0x1bcdbe4700000000, 0x3ca89bc600000000,\n    0x1401859e00000000, 0x3364a01f00000000, 0x4453b82e00000000,\n    0x63369daf00000000, 0x4b9f83f700000000, 0x6cfaa67600000000,\n    0x988ed8ea00000000, 0xbfebfd6b00000000, 0x9742e33300000000,\n    0xb027c6b200000000, 0xc710de8300000000, 0xe075fb0200000000,\n    0xc8dce55a00000000, 0xefb9c0db00000000, 0x26b2d53800000000,\n    0x01d7f0b900000000, 0x297eeee100000000, 0x0e1bcb6000000000,\n    0x792cd35100000000, 0x5e49f6d000000000, 0x76e0e88800000000,\n    0x5185cd0900000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0x9ba54c6f, 0xec3b9e9f, 0x779ed2f0, 0x03063b7f,\n    0x98a37710, 0xef3da5e0, 0x7498e98f, 0x060c76fe, 0x9da93a91,\n    0xea37e861, 0x7192a40e, 0x050a4d81, 0x9eaf01ee, 0xe931d31e,\n    0x72949f71, 0x0c18edfc, 0x97bda193, 0xe0237363, 0x7b863f0c,\n    0x0f1ed683, 0x94bb9aec, 0xe325481c, 0x78800473, 0x0a149b02,\n    0x91b1d76d, 0xe62f059d, 0x7d8a49f2, 0x0912a07d, 0x92b7ec12,\n    0xe5293ee2, 0x7e8c728d, 0x1831dbf8, 0x83949797, 0xf40a4567,\n    0x6faf0908, 0x1b37e087, 0x8092ace8, 0xf70c7e18, 0x6ca93277,\n    0x1e3dad06, 0x8598e169, 0xf2063399, 0x69a37ff6, 0x1d3b9679,\n    0x869eda16, 0xf10008e6, 0x6aa54489, 0x14293604, 0x8f8c7a6b,\n    0xf812a89b, 0x63b7e4f4, 0x172f0d7b, 0x8c8a4114, 0xfb1493e4,\n    0x60b1df8b, 0x122540fa, 0x89800c95, 0xfe1ede65, 0x65bb920a,\n    0x11237b85, 0x8a8637ea, 0xfd18e51a, 0x66bda975, 0x3063b7f0,\n    0xabc6fb9f, 0xdc58296f, 0x47fd6500, 0x33658c8f, 0xa8c0c0e0,\n    0xdf5e1210, 0x44fb5e7f, 0x366fc10e, 0xadca8d61, 0xda545f91,\n    0x41f113fe, 0x3569fa71, 0xaeccb61e, 0xd95264ee, 0x42f72881,\n    0x3c7b5a0c, 0xa7de1663, 0xd040c493, 0x4be588fc, 0x3f7d6173,\n    0xa4d82d1c, 0xd346ffec, 0x48e3b383, 0x3a772cf2, 0xa1d2609d,\n    0xd64cb26d, 0x4de9fe02, 0x3971178d, 0xa2d45be2, 0xd54a8912,\n    0x4eefc57d, 0x28526c08, 0xb3f72067, 0xc469f297, 0x5fccbef8,\n    0x2b545777, 0xb0f11b18, 0xc76fc9e8, 0x5cca8587, 0x2e5e1af6,\n    0xb5fb5699, 0xc2658469, 0x59c0c806, 0x2d582189, 0xb6fd6de6,\n    0xc163bf16, 0x5ac6f379, 0x244a81f4, 0xbfefcd9b, 0xc8711f6b,\n    0x53d45304, 0x274cba8b, 0xbce9f6e4, 0xcb772414, 0x50d2687b,\n    0x2246f70a, 0xb9e3bb65, 0xce7d6995, 0x55d825fa, 0x2140cc75,\n    0xbae5801a, 0xcd7b52ea, 0x56de1e85, 0x60c76fe0, 0xfb62238f,\n    0x8cfcf17f, 0x1759bd10, 0x63c1549f, 0xf86418f0, 0x8ffaca00,\n    0x145f866f, 0x66cb191e, 0xfd6e5571, 0x8af08781, 0x1155cbee,\n    0x65cd2261, 0xfe686e0e, 0x89f6bcfe, 0x1253f091, 0x6cdf821c,\n    0xf77ace73, 0x80e41c83, 0x1b4150ec, 0x6fd9b963, 0xf47cf50c,\n    0x83e227fc, 0x18476b93, 0x6ad3f4e2, 0xf176b88d, 0x86e86a7d,\n    0x1d4d2612, 0x69d5cf9d, 0xf27083f2, 0x85ee5102, 0x1e4b1d6d,\n    0x78f6b418, 0xe353f877, 0x94cd2a87, 0x0f6866e8, 0x7bf08f67,\n    0xe055c308, 0x97cb11f8, 0x0c6e5d97, 0x7efac2e6, 0xe55f8e89,\n    0x92c15c79, 0x09641016, 0x7dfcf999, 0xe659b5f6, 0x91c76706,\n    0x0a622b69, 0x74ee59e4, 0xef4b158b, 0x98d5c77b, 0x03708b14,\n    0x77e8629b, 0xec4d2ef4, 0x9bd3fc04, 0x0076b06b, 0x72e22f1a,\n    0xe9476375, 0x9ed9b185, 0x057cfdea, 0x71e41465, 0xea41580a,\n    0x9ddf8afa, 0x067ac695, 0x50a4d810, 0xcb01947f, 0xbc9f468f,\n    0x273a0ae0, 0x53a2e36f, 0xc807af00, 0xbf997df0, 0x243c319f,\n    0x56a8aeee, 0xcd0de281, 0xba933071, 0x21367c1e, 0x55ae9591,\n    0xce0bd9fe, 0xb9950b0e, 0x22304761, 0x5cbc35ec, 0xc7197983,\n    0xb087ab73, 0x2b22e71c, 0x5fba0e93, 0xc41f42fc, 0xb381900c,\n    0x2824dc63, 0x5ab04312, 0xc1150f7d, 0xb68bdd8d, 0x2d2e91e2,\n    0x59b6786d, 0xc2133402, 0xb58de6f2, 0x2e28aa9d, 0x489503e8,\n    0xd3304f87, 0xa4ae9d77, 0x3f0bd118, 0x4b933897, 0xd03674f8,\n    0xa7a8a608, 0x3c0dea67, 0x4e997516, 0xd53c3979, 0xa2a2eb89,\n    0x3907a7e6, 0x4d9f4e69, 0xd63a0206, 0xa1a4d0f6, 0x3a019c99,\n    0x448dee14, 0xdf28a27b, 0xa8b6708b, 0x33133ce4, 0x478bd56b,\n    0xdc2e9904, 0xabb04bf4, 0x3015079b, 0x428198ea, 0xd924d485,\n    0xaeba0675, 0x351f4a1a, 0x4187a395, 0xda22effa, 0xadbc3d0a,\n    0x36197165},\n   {0x00000000, 0xc18edfc0, 0x586cb9c1, 0x99e26601, 0xb0d97382,\n    0x7157ac42, 0xe8b5ca43, 0x293b1583, 0xbac3e145, 0x7b4d3e85,\n    0xe2af5884, 0x23218744, 0x0a1a92c7, 0xcb944d07, 0x52762b06,\n    0x93f8f4c6, 0xaef6c4cb, 0x6f781b0b, 0xf69a7d0a, 0x3714a2ca,\n    0x1e2fb749, 0xdfa16889, 0x46430e88, 0x87cdd148, 0x1435258e,\n    0xd5bbfa4e, 0x4c599c4f, 0x8dd7438f, 0xa4ec560c, 0x656289cc,\n    0xfc80efcd, 0x3d0e300d, 0x869c8fd7, 0x47125017, 0xdef03616,\n    0x1f7ee9d6, 0x3645fc55, 0xf7cb2395, 0x6e294594, 0xafa79a54,\n    0x3c5f6e92, 0xfdd1b152, 0x6433d753, 0xa5bd0893, 0x8c861d10,\n    0x4d08c2d0, 0xd4eaa4d1, 0x15647b11, 0x286a4b1c, 0xe9e494dc,\n    0x7006f2dd, 0xb1882d1d, 0x98b3389e, 0x593de75e, 0xc0df815f,\n    0x01515e9f, 0x92a9aa59, 0x53277599, 0xcac51398, 0x0b4bcc58,\n    0x2270d9db, 0xe3fe061b, 0x7a1c601a, 0xbb92bfda, 0xd64819ef,\n    0x17c6c62f, 0x8e24a02e, 0x4faa7fee, 0x66916a6d, 0xa71fb5ad,\n    0x3efdd3ac, 0xff730c6c, 0x6c8bf8aa, 0xad05276a, 0x34e7416b,\n    0xf5699eab, 0xdc528b28, 0x1ddc54e8, 0x843e32e9, 0x45b0ed29,\n    0x78bedd24, 0xb93002e4, 0x20d264e5, 0xe15cbb25, 0xc867aea6,\n    0x09e97166, 0x900b1767, 0x5185c8a7, 0xc27d3c61, 0x03f3e3a1,\n    0x9a1185a0, 0x5b9f5a60, 0x72a44fe3, 0xb32a9023, 0x2ac8f622,\n    0xeb4629e2, 0x50d49638, 0x915a49f8, 0x08b82ff9, 0xc936f039,\n    0xe00de5ba, 0x21833a7a, 0xb8615c7b, 0x79ef83bb, 0xea17777d,\n    0x2b99a8bd, 0xb27bcebc, 0x73f5117c, 0x5ace04ff, 0x9b40db3f,\n    0x02a2bd3e, 0xc32c62fe, 0xfe2252f3, 0x3fac8d33, 0xa64eeb32,\n    0x67c034f2, 0x4efb2171, 0x8f75feb1, 0x169798b0, 0xd7194770,\n    0x44e1b3b6, 0x856f6c76, 0x1c8d0a77, 0xdd03d5b7, 0xf438c034,\n    0x35b61ff4, 0xac5479f5, 0x6ddaa635, 0x77e1359f, 0xb66fea5f,\n    0x2f8d8c5e, 0xee03539e, 0xc738461d, 0x06b699dd, 0x9f54ffdc,\n    0x5eda201c, 0xcd22d4da, 0x0cac0b1a, 0x954e6d1b, 0x54c0b2db,\n    0x7dfba758, 0xbc757898, 0x25971e99, 0xe419c159, 0xd917f154,\n    0x18992e94, 0x817b4895, 0x40f59755, 0x69ce82d6, 0xa8405d16,\n    0x31a23b17, 0xf02ce4d7, 0x63d41011, 0xa25acfd1, 0x3bb8a9d0,\n    0xfa367610, 0xd30d6393, 0x1283bc53, 0x8b61da52, 0x4aef0592,\n    0xf17dba48, 0x30f36588, 0xa9110389, 0x689fdc49, 0x41a4c9ca,\n    0x802a160a, 0x19c8700b, 0xd846afcb, 0x4bbe5b0d, 0x8a3084cd,\n    0x13d2e2cc, 0xd25c3d0c, 0xfb67288f, 0x3ae9f74f, 0xa30b914e,\n    0x62854e8e, 0x5f8b7e83, 0x9e05a143, 0x07e7c742, 0xc6691882,\n    0xef520d01, 0x2edcd2c1, 0xb73eb4c0, 0x76b06b00, 0xe5489fc6,\n    0x24c64006, 0xbd242607, 0x7caaf9c7, 0x5591ec44, 0x941f3384,\n    0x0dfd5585, 0xcc738a45, 0xa1a92c70, 0x6027f3b0, 0xf9c595b1,\n    0x384b4a71, 0x11705ff2, 0xd0fe8032, 0x491ce633, 0x889239f3,\n    0x1b6acd35, 0xdae412f5, 0x430674f4, 0x8288ab34, 0xabb3beb7,\n    0x6a3d6177, 0xf3df0776, 0x3251d8b6, 0x0f5fe8bb, 0xced1377b,\n    0x5733517a, 0x96bd8eba, 0xbf869b39, 0x7e0844f9, 0xe7ea22f8,\n    0x2664fd38, 0xb59c09fe, 0x7412d63e, 0xedf0b03f, 0x2c7e6fff,\n    0x05457a7c, 0xc4cba5bc, 0x5d29c3bd, 0x9ca71c7d, 0x2735a3a7,\n    0xe6bb7c67, 0x7f591a66, 0xbed7c5a6, 0x97ecd025, 0x56620fe5,\n    0xcf8069e4, 0x0e0eb624, 0x9df642e2, 0x5c789d22, 0xc59afb23,\n    0x041424e3, 0x2d2f3160, 0xeca1eea0, 0x754388a1, 0xb4cd5761,\n    0x89c3676c, 0x484db8ac, 0xd1afdead, 0x1021016d, 0x391a14ee,\n    0xf894cb2e, 0x6176ad2f, 0xa0f872ef, 0x33008629, 0xf28e59e9,\n    0x6b6c3fe8, 0xaae2e028, 0x83d9f5ab, 0x42572a6b, 0xdbb54c6a,\n    0x1a3b93aa},\n   {0x00000000, 0xefc26b3e, 0x04f5d03d, 0xeb37bb03, 0x09eba07a,\n    0xe629cb44, 0x0d1e7047, 0xe2dc1b79, 0x13d740f4, 0xfc152bca,\n    0x172290c9, 0xf8e0fbf7, 0x1a3ce08e, 0xf5fe8bb0, 0x1ec930b3,\n    0xf10b5b8d, 0x27ae81e8, 0xc86cead6, 0x235b51d5, 0xcc993aeb,\n    0x2e452192, 0xc1874aac, 0x2ab0f1af, 0xc5729a91, 0x3479c11c,\n    0xdbbbaa22, 0x308c1121, 0xdf4e7a1f, 0x3d926166, 0xd2500a58,\n    0x3967b15b, 0xd6a5da65, 0x4f5d03d0, 0xa09f68ee, 0x4ba8d3ed,\n    0xa46ab8d3, 0x46b6a3aa, 0xa974c894, 0x42437397, 0xad8118a9,\n    0x5c8a4324, 0xb348281a, 0x587f9319, 0xb7bdf827, 0x5561e35e,\n    0xbaa38860, 0x51943363, 0xbe56585d, 0x68f38238, 0x8731e906,\n    0x6c065205, 0x83c4393b, 0x61182242, 0x8eda497c, 0x65edf27f,\n    0x8a2f9941, 0x7b24c2cc, 0x94e6a9f2, 0x7fd112f1, 0x901379cf,\n    0x72cf62b6, 0x9d0d0988, 0x763ab28b, 0x99f8d9b5, 0x9eba07a0,\n    0x71786c9e, 0x9a4fd79d, 0x758dbca3, 0x9751a7da, 0x7893cce4,\n    0x93a477e7, 0x7c661cd9, 0x8d6d4754, 0x62af2c6a, 0x89989769,\n    0x665afc57, 0x8486e72e, 0x6b448c10, 0x80733713, 0x6fb15c2d,\n    0xb9148648, 0x56d6ed76, 0xbde15675, 0x52233d4b, 0xb0ff2632,\n    0x5f3d4d0c, 0xb40af60f, 0x5bc89d31, 0xaac3c6bc, 0x4501ad82,\n    0xae361681, 0x41f47dbf, 0xa32866c6, 0x4cea0df8, 0xa7ddb6fb,\n    0x481fddc5, 0xd1e70470, 0x3e256f4e, 0xd512d44d, 0x3ad0bf73,\n    0xd80ca40a, 0x37cecf34, 0xdcf97437, 0x333b1f09, 0xc2304484,\n    0x2df22fba, 0xc6c594b9, 0x2907ff87, 0xcbdbe4fe, 0x24198fc0,\n    0xcf2e34c3, 0x20ec5ffd, 0xf6498598, 0x198beea6, 0xf2bc55a5,\n    0x1d7e3e9b, 0xffa225e2, 0x10604edc, 0xfb57f5df, 0x14959ee1,\n    0xe59ec56c, 0x0a5cae52, 0xe16b1551, 0x0ea97e6f, 0xec756516,\n    0x03b70e28, 0xe880b52b, 0x0742de15, 0xe6050901, 0x09c7623f,\n    0xe2f0d93c, 0x0d32b202, 0xefeea97b, 0x002cc245, 0xeb1b7946,\n    0x04d91278, 0xf5d249f5, 0x1a1022cb, 0xf12799c8, 0x1ee5f2f6,\n    0xfc39e98f, 0x13fb82b1, 0xf8cc39b2, 0x170e528c, 0xc1ab88e9,\n    0x2e69e3d7, 0xc55e58d4, 0x2a9c33ea, 0xc8402893, 0x278243ad,\n    0xccb5f8ae, 0x23779390, 0xd27cc81d, 0x3dbea323, 0xd6891820,\n    0x394b731e, 0xdb976867, 0x34550359, 0xdf62b85a, 0x30a0d364,\n    0xa9580ad1, 0x469a61ef, 0xadaddaec, 0x426fb1d2, 0xa0b3aaab,\n    0x4f71c195, 0xa4467a96, 0x4b8411a8, 0xba8f4a25, 0x554d211b,\n    0xbe7a9a18, 0x51b8f126, 0xb364ea5f, 0x5ca68161, 0xb7913a62,\n    0x5853515c, 0x8ef68b39, 0x6134e007, 0x8a035b04, 0x65c1303a,\n    0x871d2b43, 0x68df407d, 0x83e8fb7e, 0x6c2a9040, 0x9d21cbcd,\n    0x72e3a0f3, 0x99d41bf0, 0x761670ce, 0x94ca6bb7, 0x7b080089,\n    0x903fbb8a, 0x7ffdd0b4, 0x78bf0ea1, 0x977d659f, 0x7c4ade9c,\n    0x9388b5a2, 0x7154aedb, 0x9e96c5e5, 0x75a17ee6, 0x9a6315d8,\n    0x6b684e55, 0x84aa256b, 0x6f9d9e68, 0x805ff556, 0x6283ee2f,\n    0x8d418511, 0x66763e12, 0x89b4552c, 0x5f118f49, 0xb0d3e477,\n    0x5be45f74, 0xb426344a, 0x56fa2f33, 0xb938440d, 0x520fff0e,\n    0xbdcd9430, 0x4cc6cfbd, 0xa304a483, 0x48331f80, 0xa7f174be,\n    0x452d6fc7, 0xaaef04f9, 0x41d8bffa, 0xae1ad4c4, 0x37e20d71,\n    0xd820664f, 0x3317dd4c, 0xdcd5b672, 0x3e09ad0b, 0xd1cbc635,\n    0x3afc7d36, 0xd53e1608, 0x24354d85, 0xcbf726bb, 0x20c09db8,\n    0xcf02f686, 0x2ddeedff, 0xc21c86c1, 0x292b3dc2, 0xc6e956fc,\n    0x104c8c99, 0xff8ee7a7, 0x14b95ca4, 0xfb7b379a, 0x19a72ce3,\n    0xf66547dd, 0x1d52fcde, 0xf29097e0, 0x039bcc6d, 0xec59a753,\n    0x076e1c50, 0xe8ac776e, 0x0a706c17, 0xe5b20729, 0x0e85bc2a,\n    0xe147d714},\n   {0x00000000, 0x177b1443, 0x2ef62886, 0x398d3cc5, 0x5dec510c,\n    0x4a97454f, 0x731a798a, 0x64616dc9, 0xbbd8a218, 0xaca3b65b,\n    0x952e8a9e, 0x82559edd, 0xe634f314, 0xf14fe757, 0xc8c2db92,\n    0xdfb9cfd1, 0xacc04271, 0xbbbb5632, 0x82366af7, 0x954d7eb4,\n    0xf12c137d, 0xe657073e, 0xdfda3bfb, 0xc8a12fb8, 0x1718e069,\n    0x0063f42a, 0x39eec8ef, 0x2e95dcac, 0x4af4b165, 0x5d8fa526,\n    0x640299e3, 0x73798da0, 0x82f182a3, 0x958a96e0, 0xac07aa25,\n    0xbb7cbe66, 0xdf1dd3af, 0xc866c7ec, 0xf1ebfb29, 0xe690ef6a,\n    0x392920bb, 0x2e5234f8, 0x17df083d, 0x00a41c7e, 0x64c571b7,\n    0x73be65f4, 0x4a335931, 0x5d484d72, 0x2e31c0d2, 0x394ad491,\n    0x00c7e854, 0x17bcfc17, 0x73dd91de, 0x64a6859d, 0x5d2bb958,\n    0x4a50ad1b, 0x95e962ca, 0x82927689, 0xbb1f4a4c, 0xac645e0f,\n    0xc80533c6, 0xdf7e2785, 0xe6f31b40, 0xf1880f03, 0xde920307,\n    0xc9e91744, 0xf0642b81, 0xe71f3fc2, 0x837e520b, 0x94054648,\n    0xad887a8d, 0xbaf36ece, 0x654aa11f, 0x7231b55c, 0x4bbc8999,\n    0x5cc79dda, 0x38a6f013, 0x2fdde450, 0x1650d895, 0x012bccd6,\n    0x72524176, 0x65295535, 0x5ca469f0, 0x4bdf7db3, 0x2fbe107a,\n    0x38c50439, 0x014838fc, 0x16332cbf, 0xc98ae36e, 0xdef1f72d,\n    0xe77ccbe8, 0xf007dfab, 0x9466b262, 0x831da621, 0xba909ae4,\n    0xadeb8ea7, 0x5c6381a4, 0x4b1895e7, 0x7295a922, 0x65eebd61,\n    0x018fd0a8, 0x16f4c4eb, 0x2f79f82e, 0x3802ec6d, 0xe7bb23bc,\n    0xf0c037ff, 0xc94d0b3a, 0xde361f79, 0xba5772b0, 0xad2c66f3,\n    0x94a15a36, 0x83da4e75, 0xf0a3c3d5, 0xe7d8d796, 0xde55eb53,\n    0xc92eff10, 0xad4f92d9, 0xba34869a, 0x83b9ba5f, 0x94c2ae1c,\n    0x4b7b61cd, 0x5c00758e, 0x658d494b, 0x72f65d08, 0x169730c1,\n    0x01ec2482, 0x38611847, 0x2f1a0c04, 0x6655004f, 0x712e140c,\n    0x48a328c9, 0x5fd83c8a, 0x3bb95143, 0x2cc24500, 0x154f79c5,\n    0x02346d86, 0xdd8da257, 0xcaf6b614, 0xf37b8ad1, 0xe4009e92,\n    0x8061f35b, 0x971ae718, 0xae97dbdd, 0xb9eccf9e, 0xca95423e,\n    0xddee567d, 0xe4636ab8, 0xf3187efb, 0x97791332, 0x80020771,\n    0xb98f3bb4, 0xaef42ff7, 0x714de026, 0x6636f465, 0x5fbbc8a0,\n    0x48c0dce3, 0x2ca1b12a, 0x3bdaa569, 0x025799ac, 0x152c8def,\n    0xe4a482ec, 0xf3df96af, 0xca52aa6a, 0xdd29be29, 0xb948d3e0,\n    0xae33c7a3, 0x97befb66, 0x80c5ef25, 0x5f7c20f4, 0x480734b7,\n    0x718a0872, 0x66f11c31, 0x029071f8, 0x15eb65bb, 0x2c66597e,\n    0x3b1d4d3d, 0x4864c09d, 0x5f1fd4de, 0x6692e81b, 0x71e9fc58,\n    0x15889191, 0x02f385d2, 0x3b7eb917, 0x2c05ad54, 0xf3bc6285,\n    0xe4c776c6, 0xdd4a4a03, 0xca315e40, 0xae503389, 0xb92b27ca,\n    0x80a61b0f, 0x97dd0f4c, 0xb8c70348, 0xafbc170b, 0x96312bce,\n    0x814a3f8d, 0xe52b5244, 0xf2504607, 0xcbdd7ac2, 0xdca66e81,\n    0x031fa150, 0x1464b513, 0x2de989d6, 0x3a929d95, 0x5ef3f05c,\n    0x4988e41f, 0x7005d8da, 0x677ecc99, 0x14074139, 0x037c557a,\n    0x3af169bf, 0x2d8a7dfc, 0x49eb1035, 0x5e900476, 0x671d38b3,\n    0x70662cf0, 0xafdfe321, 0xb8a4f762, 0x8129cba7, 0x9652dfe4,\n    0xf233b22d, 0xe548a66e, 0xdcc59aab, 0xcbbe8ee8, 0x3a3681eb,\n    0x2d4d95a8, 0x14c0a96d, 0x03bbbd2e, 0x67dad0e7, 0x70a1c4a4,\n    0x492cf861, 0x5e57ec22, 0x81ee23f3, 0x969537b0, 0xaf180b75,\n    0xb8631f36, 0xdc0272ff, 0xcb7966bc, 0xf2f45a79, 0xe58f4e3a,\n    0x96f6c39a, 0x818dd7d9, 0xb800eb1c, 0xaf7bff5f, 0xcb1a9296,\n    0xdc6186d5, 0xe5ecba10, 0xf297ae53, 0x2d2e6182, 0x3a5575c1,\n    0x03d84904, 0x14a35d47, 0x70c2308e, 0x67b924cd, 0x5e341808,\n    0x494f0c4b}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0x43147b17, 0x8628f62e, 0xc53c8d39, 0x0c51ec5d,\n    0x4f45974a, 0x8a791a73, 0xc96d6164, 0x18a2d8bb, 0x5bb6a3ac,\n    0x9e8a2e95, 0xdd9e5582, 0x14f334e6, 0x57e74ff1, 0x92dbc2c8,\n    0xd1cfb9df, 0x7142c0ac, 0x3256bbbb, 0xf76a3682, 0xb47e4d95,\n    0x7d132cf1, 0x3e0757e6, 0xfb3bdadf, 0xb82fa1c8, 0x69e01817,\n    0x2af46300, 0xefc8ee39, 0xacdc952e, 0x65b1f44a, 0x26a58f5d,\n    0xe3990264, 0xa08d7973, 0xa382f182, 0xe0968a95, 0x25aa07ac,\n    0x66be7cbb, 0xafd31ddf, 0xecc766c8, 0x29fbebf1, 0x6aef90e6,\n    0xbb202939, 0xf834522e, 0x3d08df17, 0x7e1ca400, 0xb771c564,\n    0xf465be73, 0x3159334a, 0x724d485d, 0xd2c0312e, 0x91d44a39,\n    0x54e8c700, 0x17fcbc17, 0xde91dd73, 0x9d85a664, 0x58b92b5d,\n    0x1bad504a, 0xca62e995, 0x89769282, 0x4c4a1fbb, 0x0f5e64ac,\n    0xc63305c8, 0x85277edf, 0x401bf3e6, 0x030f88f1, 0x070392de,\n    0x4417e9c9, 0x812b64f0, 0xc23f1fe7, 0x0b527e83, 0x48460594,\n    0x8d7a88ad, 0xce6ef3ba, 0x1fa14a65, 0x5cb53172, 0x9989bc4b,\n    0xda9dc75c, 0x13f0a638, 0x50e4dd2f, 0x95d85016, 0xd6cc2b01,\n    0x76415272, 0x35552965, 0xf069a45c, 0xb37ddf4b, 0x7a10be2f,\n    0x3904c538, 0xfc384801, 0xbf2c3316, 0x6ee38ac9, 0x2df7f1de,\n    0xe8cb7ce7, 0xabdf07f0, 0x62b26694, 0x21a61d83, 0xe49a90ba,\n    0xa78eebad, 0xa481635c, 0xe795184b, 0x22a99572, 0x61bdee65,\n    0xa8d08f01, 0xebc4f416, 0x2ef8792f, 0x6dec0238, 0xbc23bbe7,\n    0xff37c0f0, 0x3a0b4dc9, 0x791f36de, 0xb07257ba, 0xf3662cad,\n    0x365aa194, 0x754eda83, 0xd5c3a3f0, 0x96d7d8e7, 0x53eb55de,\n    0x10ff2ec9, 0xd9924fad, 0x9a8634ba, 0x5fbab983, 0x1caec294,\n    0xcd617b4b, 0x8e75005c, 0x4b498d65, 0x085df672, 0xc1309716,\n    0x8224ec01, 0x47186138, 0x040c1a2f, 0x4f005566, 0x0c142e71,\n    0xc928a348, 0x8a3cd85f, 0x4351b93b, 0x0045c22c, 0xc5794f15,\n    0x866d3402, 0x57a28ddd, 0x14b6f6ca, 0xd18a7bf3, 0x929e00e4,\n    0x5bf36180, 0x18e71a97, 0xdddb97ae, 0x9ecfecb9, 0x3e4295ca,\n    0x7d56eedd, 0xb86a63e4, 0xfb7e18f3, 0x32137997, 0x71070280,\n    0xb43b8fb9, 0xf72ff4ae, 0x26e04d71, 0x65f43666, 0xa0c8bb5f,\n    0xe3dcc048, 0x2ab1a12c, 0x69a5da3b, 0xac995702, 0xef8d2c15,\n    0xec82a4e4, 0xaf96dff3, 0x6aaa52ca, 0x29be29dd, 0xe0d348b9,\n    0xa3c733ae, 0x66fbbe97, 0x25efc580, 0xf4207c5f, 0xb7340748,\n    0x72088a71, 0x311cf166, 0xf8719002, 0xbb65eb15, 0x7e59662c,\n    0x3d4d1d3b, 0x9dc06448, 0xded41f5f, 0x1be89266, 0x58fce971,\n    0x91918815, 0xd285f302, 0x17b97e3b, 0x54ad052c, 0x8562bcf3,\n    0xc676c7e4, 0x034a4add, 0x405e31ca, 0x893350ae, 0xca272bb9,\n    0x0f1ba680, 0x4c0fdd97, 0x4803c7b8, 0x0b17bcaf, 0xce2b3196,\n    0x8d3f4a81, 0x44522be5, 0x074650f2, 0xc27addcb, 0x816ea6dc,\n    0x50a11f03, 0x13b56414, 0xd689e92d, 0x959d923a, 0x5cf0f35e,\n    0x1fe48849, 0xdad80570, 0x99cc7e67, 0x39410714, 0x7a557c03,\n    0xbf69f13a, 0xfc7d8a2d, 0x3510eb49, 0x7604905e, 0xb3381d67,\n    0xf02c6670, 0x21e3dfaf, 0x62f7a4b8, 0xa7cb2981, 0xe4df5296,\n    0x2db233f2, 0x6ea648e5, 0xab9ac5dc, 0xe88ebecb, 0xeb81363a,\n    0xa8954d2d, 0x6da9c014, 0x2ebdbb03, 0xe7d0da67, 0xa4c4a170,\n    0x61f82c49, 0x22ec575e, 0xf323ee81, 0xb0379596, 0x750b18af,\n    0x361f63b8, 0xff7202dc, 0xbc6679cb, 0x795af4f2, 0x3a4e8fe5,\n    0x9ac3f696, 0xd9d78d81, 0x1ceb00b8, 0x5fff7baf, 0x96921acb,\n    0xd58661dc, 0x10baece5, 0x53ae97f2, 0x82612e2d, 0xc175553a,\n    0x0449d803, 0x475da314, 0x8e30c270, 0xcd24b967, 0x0818345e,\n    0x4b0c4f49},\n   {0x00000000, 0x3e6bc2ef, 0x3dd0f504, 0x03bb37eb, 0x7aa0eb09,\n    0x44cb29e6, 0x47701e0d, 0x791bdce2, 0xf440d713, 0xca2b15fc,\n    0xc9902217, 0xf7fbe0f8, 0x8ee03c1a, 0xb08bfef5, 0xb330c91e,\n    0x8d5b0bf1, 0xe881ae27, 0xd6ea6cc8, 0xd5515b23, 0xeb3a99cc,\n    0x9221452e, 0xac4a87c1, 0xaff1b02a, 0x919a72c5, 0x1cc17934,\n    0x22aabbdb, 0x21118c30, 0x1f7a4edf, 0x6661923d, 0x580a50d2,\n    0x5bb16739, 0x65daa5d6, 0xd0035d4f, 0xee689fa0, 0xedd3a84b,\n    0xd3b86aa4, 0xaaa3b646, 0x94c874a9, 0x97734342, 0xa91881ad,\n    0x24438a5c, 0x1a2848b3, 0x19937f58, 0x27f8bdb7, 0x5ee36155,\n    0x6088a3ba, 0x63339451, 0x5d5856be, 0x3882f368, 0x06e93187,\n    0x0552066c, 0x3b39c483, 0x42221861, 0x7c49da8e, 0x7ff2ed65,\n    0x41992f8a, 0xccc2247b, 0xf2a9e694, 0xf112d17f, 0xcf791390,\n    0xb662cf72, 0x88090d9d, 0x8bb23a76, 0xb5d9f899, 0xa007ba9e,\n    0x9e6c7871, 0x9dd74f9a, 0xa3bc8d75, 0xdaa75197, 0xe4cc9378,\n    0xe777a493, 0xd91c667c, 0x54476d8d, 0x6a2caf62, 0x69979889,\n    0x57fc5a66, 0x2ee78684, 0x108c446b, 0x13377380, 0x2d5cb16f,\n    0x488614b9, 0x76edd656, 0x7556e1bd, 0x4b3d2352, 0x3226ffb0,\n    0x0c4d3d5f, 0x0ff60ab4, 0x319dc85b, 0xbcc6c3aa, 0x82ad0145,\n    0x811636ae, 0xbf7df441, 0xc66628a3, 0xf80dea4c, 0xfbb6dda7,\n    0xc5dd1f48, 0x7004e7d1, 0x4e6f253e, 0x4dd412d5, 0x73bfd03a,\n    0x0aa40cd8, 0x34cfce37, 0x3774f9dc, 0x091f3b33, 0x844430c2,\n    0xba2ff22d, 0xb994c5c6, 0x87ff0729, 0xfee4dbcb, 0xc08f1924,\n    0xc3342ecf, 0xfd5fec20, 0x988549f6, 0xa6ee8b19, 0xa555bcf2,\n    0x9b3e7e1d, 0xe225a2ff, 0xdc4e6010, 0xdff557fb, 0xe19e9514,\n    0x6cc59ee5, 0x52ae5c0a, 0x51156be1, 0x6f7ea90e, 0x166575ec,\n    0x280eb703, 0x2bb580e8, 0x15de4207, 0x010905e6, 0x3f62c709,\n    0x3cd9f0e2, 0x02b2320d, 0x7ba9eeef, 0x45c22c00, 0x46791beb,\n    0x7812d904, 0xf549d2f5, 0xcb22101a, 0xc89927f1, 0xf6f2e51e,\n    0x8fe939fc, 0xb182fb13, 0xb239ccf8, 0x8c520e17, 0xe988abc1,\n    0xd7e3692e, 0xd4585ec5, 0xea339c2a, 0x932840c8, 0xad438227,\n    0xaef8b5cc, 0x90937723, 0x1dc87cd2, 0x23a3be3d, 0x201889d6,\n    0x1e734b39, 0x676897db, 0x59035534, 0x5ab862df, 0x64d3a030,\n    0xd10a58a9, 0xef619a46, 0xecdaadad, 0xd2b16f42, 0xabaab3a0,\n    0x95c1714f, 0x967a46a4, 0xa811844b, 0x254a8fba, 0x1b214d55,\n    0x189a7abe, 0x26f1b851, 0x5fea64b3, 0x6181a65c, 0x623a91b7,\n    0x5c515358, 0x398bf68e, 0x07e03461, 0x045b038a, 0x3a30c165,\n    0x432b1d87, 0x7d40df68, 0x7efbe883, 0x40902a6c, 0xcdcb219d,\n    0xf3a0e372, 0xf01bd499, 0xce701676, 0xb76bca94, 0x8900087b,\n    0x8abb3f90, 0xb4d0fd7f, 0xa10ebf78, 0x9f657d97, 0x9cde4a7c,\n    0xa2b58893, 0xdbae5471, 0xe5c5969e, 0xe67ea175, 0xd815639a,\n    0x554e686b, 0x6b25aa84, 0x689e9d6f, 0x56f55f80, 0x2fee8362,\n    0x1185418d, 0x123e7666, 0x2c55b489, 0x498f115f, 0x77e4d3b0,\n    0x745fe45b, 0x4a3426b4, 0x332ffa56, 0x0d4438b9, 0x0eff0f52,\n    0x3094cdbd, 0xbdcfc64c, 0x83a404a3, 0x801f3348, 0xbe74f1a7,\n    0xc76f2d45, 0xf904efaa, 0xfabfd841, 0xc4d41aae, 0x710de237,\n    0x4f6620d8, 0x4cdd1733, 0x72b6d5dc, 0x0bad093e, 0x35c6cbd1,\n    0x367dfc3a, 0x08163ed5, 0x854d3524, 0xbb26f7cb, 0xb89dc020,\n    0x86f602cf, 0xffedde2d, 0xc1861cc2, 0xc23d2b29, 0xfc56e9c6,\n    0x998c4c10, 0xa7e78eff, 0xa45cb914, 0x9a377bfb, 0xe32ca719,\n    0xdd4765f6, 0xdefc521d, 0xe09790f2, 0x6dcc9b03, 0x53a759ec,\n    0x501c6e07, 0x6e77ace8, 0x176c700a, 0x2907b2e5, 0x2abc850e,\n    0x14d747e1},\n   {0x00000000, 0xc0df8ec1, 0xc1b96c58, 0x0166e299, 0x8273d9b0,\n    0x42ac5771, 0x43cab5e8, 0x83153b29, 0x45e1c3ba, 0x853e4d7b,\n    0x8458afe2, 0x44872123, 0xc7921a0a, 0x074d94cb, 0x062b7652,\n    0xc6f4f893, 0xcbc4f6ae, 0x0b1b786f, 0x0a7d9af6, 0xcaa21437,\n    0x49b72f1e, 0x8968a1df, 0x880e4346, 0x48d1cd87, 0x8e253514,\n    0x4efabbd5, 0x4f9c594c, 0x8f43d78d, 0x0c56eca4, 0xcc896265,\n    0xcdef80fc, 0x0d300e3d, 0xd78f9c86, 0x17501247, 0x1636f0de,\n    0xd6e97e1f, 0x55fc4536, 0x9523cbf7, 0x9445296e, 0x549aa7af,\n    0x926e5f3c, 0x52b1d1fd, 0x53d73364, 0x9308bda5, 0x101d868c,\n    0xd0c2084d, 0xd1a4ead4, 0x117b6415, 0x1c4b6a28, 0xdc94e4e9,\n    0xddf20670, 0x1d2d88b1, 0x9e38b398, 0x5ee73d59, 0x5f81dfc0,\n    0x9f5e5101, 0x59aaa992, 0x99752753, 0x9813c5ca, 0x58cc4b0b,\n    0xdbd97022, 0x1b06fee3, 0x1a601c7a, 0xdabf92bb, 0xef1948d6,\n    0x2fc6c617, 0x2ea0248e, 0xee7faa4f, 0x6d6a9166, 0xadb51fa7,\n    0xacd3fd3e, 0x6c0c73ff, 0xaaf88b6c, 0x6a2705ad, 0x6b41e734,\n    0xab9e69f5, 0x288b52dc, 0xe854dc1d, 0xe9323e84, 0x29edb045,\n    0x24ddbe78, 0xe40230b9, 0xe564d220, 0x25bb5ce1, 0xa6ae67c8,\n    0x6671e909, 0x67170b90, 0xa7c88551, 0x613c7dc2, 0xa1e3f303,\n    0xa085119a, 0x605a9f5b, 0xe34fa472, 0x23902ab3, 0x22f6c82a,\n    0xe22946eb, 0x3896d450, 0xf8495a91, 0xf92fb808, 0x39f036c9,\n    0xbae50de0, 0x7a3a8321, 0x7b5c61b8, 0xbb83ef79, 0x7d7717ea,\n    0xbda8992b, 0xbcce7bb2, 0x7c11f573, 0xff04ce5a, 0x3fdb409b,\n    0x3ebda202, 0xfe622cc3, 0xf35222fe, 0x338dac3f, 0x32eb4ea6,\n    0xf234c067, 0x7121fb4e, 0xb1fe758f, 0xb0989716, 0x704719d7,\n    0xb6b3e144, 0x766c6f85, 0x770a8d1c, 0xb7d503dd, 0x34c038f4,\n    0xf41fb635, 0xf57954ac, 0x35a6da6d, 0x9f35e177, 0x5fea6fb6,\n    0x5e8c8d2f, 0x9e5303ee, 0x1d4638c7, 0xdd99b606, 0xdcff549f,\n    0x1c20da5e, 0xdad422cd, 0x1a0bac0c, 0x1b6d4e95, 0xdbb2c054,\n    0x58a7fb7d, 0x987875bc, 0x991e9725, 0x59c119e4, 0x54f117d9,\n    0x942e9918, 0x95487b81, 0x5597f540, 0xd682ce69, 0x165d40a8,\n    0x173ba231, 0xd7e42cf0, 0x1110d463, 0xd1cf5aa2, 0xd0a9b83b,\n    0x107636fa, 0x93630dd3, 0x53bc8312, 0x52da618b, 0x9205ef4a,\n    0x48ba7df1, 0x8865f330, 0x890311a9, 0x49dc9f68, 0xcac9a441,\n    0x0a162a80, 0x0b70c819, 0xcbaf46d8, 0x0d5bbe4b, 0xcd84308a,\n    0xcce2d213, 0x0c3d5cd2, 0x8f2867fb, 0x4ff7e93a, 0x4e910ba3,\n    0x8e4e8562, 0x837e8b5f, 0x43a1059e, 0x42c7e707, 0x821869c6,\n    0x010d52ef, 0xc1d2dc2e, 0xc0b43eb7, 0x006bb076, 0xc69f48e5,\n    0x0640c624, 0x072624bd, 0xc7f9aa7c, 0x44ec9155, 0x84331f94,\n    0x8555fd0d, 0x458a73cc, 0x702ca9a1, 0xb0f32760, 0xb195c5f9,\n    0x714a4b38, 0xf25f7011, 0x3280fed0, 0x33e61c49, 0xf3399288,\n    0x35cd6a1b, 0xf512e4da, 0xf4740643, 0x34ab8882, 0xb7beb3ab,\n    0x77613d6a, 0x7607dff3, 0xb6d85132, 0xbbe85f0f, 0x7b37d1ce,\n    0x7a513357, 0xba8ebd96, 0x399b86bf, 0xf944087e, 0xf822eae7,\n    0x38fd6426, 0xfe099cb5, 0x3ed61274, 0x3fb0f0ed, 0xff6f7e2c,\n    0x7c7a4505, 0xbca5cbc4, 0xbdc3295d, 0x7d1ca79c, 0xa7a33527,\n    0x677cbbe6, 0x661a597f, 0xa6c5d7be, 0x25d0ec97, 0xe50f6256,\n    0xe46980cf, 0x24b60e0e, 0xe242f69d, 0x229d785c, 0x23fb9ac5,\n    0xe3241404, 0x60312f2d, 0xa0eea1ec, 0xa1884375, 0x6157cdb4,\n    0x6c67c389, 0xacb84d48, 0xaddeafd1, 0x6d012110, 0xee141a39,\n    0x2ecb94f8, 0x2fad7661, 0xef72f8a0, 0x29860033, 0xe9598ef2,\n    0xe83f6c6b, 0x28e0e2aa, 0xabf5d983, 0x6b2a5742, 0x6a4cb5db,\n    0xaa933b1a},\n   {0x00000000, 0x6f4ca59b, 0x9f9e3bec, 0xf0d29e77, 0x7f3b0603,\n    0x1077a398, 0xe0a53def, 0x8fe99874, 0xfe760c06, 0x913aa99d,\n    0x61e837ea, 0x0ea49271, 0x814d0a05, 0xee01af9e, 0x1ed331e9,\n    0x719f9472, 0xfced180c, 0x93a1bd97, 0x637323e0, 0x0c3f867b,\n    0x83d61e0f, 0xec9abb94, 0x1c4825e3, 0x73048078, 0x029b140a,\n    0x6dd7b191, 0x9d052fe6, 0xf2498a7d, 0x7da01209, 0x12ecb792,\n    0xe23e29e5, 0x8d728c7e, 0xf8db3118, 0x97979483, 0x67450af4,\n    0x0809af6f, 0x87e0371b, 0xe8ac9280, 0x187e0cf7, 0x7732a96c,\n    0x06ad3d1e, 0x69e19885, 0x993306f2, 0xf67fa369, 0x79963b1d,\n    0x16da9e86, 0xe60800f1, 0x8944a56a, 0x04362914, 0x6b7a8c8f,\n    0x9ba812f8, 0xf4e4b763, 0x7b0d2f17, 0x14418a8c, 0xe49314fb,\n    0x8bdfb160, 0xfa402512, 0x950c8089, 0x65de1efe, 0x0a92bb65,\n    0x857b2311, 0xea37868a, 0x1ae518fd, 0x75a9bd66, 0xf0b76330,\n    0x9ffbc6ab, 0x6f2958dc, 0x0065fd47, 0x8f8c6533, 0xe0c0c0a8,\n    0x10125edf, 0x7f5efb44, 0x0ec16f36, 0x618dcaad, 0x915f54da,\n    0xfe13f141, 0x71fa6935, 0x1eb6ccae, 0xee6452d9, 0x8128f742,\n    0x0c5a7b3c, 0x6316dea7, 0x93c440d0, 0xfc88e54b, 0x73617d3f,\n    0x1c2dd8a4, 0xecff46d3, 0x83b3e348, 0xf22c773a, 0x9d60d2a1,\n    0x6db24cd6, 0x02fee94d, 0x8d177139, 0xe25bd4a2, 0x12894ad5,\n    0x7dc5ef4e, 0x086c5228, 0x6720f7b3, 0x97f269c4, 0xf8becc5f,\n    0x7757542b, 0x181bf1b0, 0xe8c96fc7, 0x8785ca5c, 0xf61a5e2e,\n    0x9956fbb5, 0x698465c2, 0x06c8c059, 0x8921582d, 0xe66dfdb6,\n    0x16bf63c1, 0x79f3c65a, 0xf4814a24, 0x9bcdefbf, 0x6b1f71c8,\n    0x0453d453, 0x8bba4c27, 0xe4f6e9bc, 0x142477cb, 0x7b68d250,\n    0x0af74622, 0x65bbe3b9, 0x95697dce, 0xfa25d855, 0x75cc4021,\n    0x1a80e5ba, 0xea527bcd, 0x851ede56, 0xe06fc760, 0x8f2362fb,\n    0x7ff1fc8c, 0x10bd5917, 0x9f54c163, 0xf01864f8, 0x00cafa8f,\n    0x6f865f14, 0x1e19cb66, 0x71556efd, 0x8187f08a, 0xeecb5511,\n    0x6122cd65, 0x0e6e68fe, 0xfebcf689, 0x91f05312, 0x1c82df6c,\n    0x73ce7af7, 0x831ce480, 0xec50411b, 0x63b9d96f, 0x0cf57cf4,\n    0xfc27e283, 0x936b4718, 0xe2f4d36a, 0x8db876f1, 0x7d6ae886,\n    0x12264d1d, 0x9dcfd569, 0xf28370f2, 0x0251ee85, 0x6d1d4b1e,\n    0x18b4f678, 0x77f853e3, 0x872acd94, 0xe866680f, 0x678ff07b,\n    0x08c355e0, 0xf811cb97, 0x975d6e0c, 0xe6c2fa7e, 0x898e5fe5,\n    0x795cc192, 0x16106409, 0x99f9fc7d, 0xf6b559e6, 0x0667c791,\n    0x692b620a, 0xe459ee74, 0x8b154bef, 0x7bc7d598, 0x148b7003,\n    0x9b62e877, 0xf42e4dec, 0x04fcd39b, 0x6bb07600, 0x1a2fe272,\n    0x756347e9, 0x85b1d99e, 0xeafd7c05, 0x6514e471, 0x0a5841ea,\n    0xfa8adf9d, 0x95c67a06, 0x10d8a450, 0x7f9401cb, 0x8f469fbc,\n    0xe00a3a27, 0x6fe3a253, 0x00af07c8, 0xf07d99bf, 0x9f313c24,\n    0xeeaea856, 0x81e20dcd, 0x713093ba, 0x1e7c3621, 0x9195ae55,\n    0xfed90bce, 0x0e0b95b9, 0x61473022, 0xec35bc5c, 0x837919c7,\n    0x73ab87b0, 0x1ce7222b, 0x930eba5f, 0xfc421fc4, 0x0c9081b3,\n    0x63dc2428, 0x1243b05a, 0x7d0f15c1, 0x8ddd8bb6, 0xe2912e2d,\n    0x6d78b659, 0x023413c2, 0xf2e68db5, 0x9daa282e, 0xe8039548,\n    0x874f30d3, 0x779daea4, 0x18d10b3f, 0x9738934b, 0xf87436d0,\n    0x08a6a8a7, 0x67ea0d3c, 0x1675994e, 0x79393cd5, 0x89eba2a2,\n    0xe6a70739, 0x694e9f4d, 0x06023ad6, 0xf6d0a4a1, 0x999c013a,\n    0x14ee8d44, 0x7ba228df, 0x8b70b6a8, 0xe43c1333, 0x6bd58b47,\n    0x04992edc, 0xf44bb0ab, 0x9b071530, 0xea988142, 0x85d424d9,\n    0x7506baae, 0x1a4a1f35, 0x95a38741, 0xfaef22da, 0x0a3dbcad,\n    0x65711936}};\n\n#endif\n\n#endif\n\n#if N == 4\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xf1da05aa, 0x38c50d15, 0xc91f08bf, 0x718a1a2a,\n    0x80501f80, 0x494f173f, 0xb8951295, 0xe3143454, 0x12ce31fe,\n    0xdbd13941, 0x2a0b3ceb, 0x929e2e7e, 0x63442bd4, 0xaa5b236b,\n    0x5b8126c1, 0x1d596ee9, 0xec836b43, 0x259c63fc, 0xd4466656,\n    0x6cd374c3, 0x9d097169, 0x541679d6, 0xa5cc7c7c, 0xfe4d5abd,\n    0x0f975f17, 0xc68857a8, 0x37525202, 0x8fc74097, 0x7e1d453d,\n    0xb7024d82, 0x46d84828, 0x3ab2ddd2, 0xcb68d878, 0x0277d0c7,\n    0xf3add56d, 0x4b38c7f8, 0xbae2c252, 0x73fdcaed, 0x8227cf47,\n    0xd9a6e986, 0x287cec2c, 0xe163e493, 0x10b9e139, 0xa82cf3ac,\n    0x59f6f606, 0x90e9feb9, 0x6133fb13, 0x27ebb33b, 0xd631b691,\n    0x1f2ebe2e, 0xeef4bb84, 0x5661a911, 0xa7bbacbb, 0x6ea4a404,\n    0x9f7ea1ae, 0xc4ff876f, 0x352582c5, 0xfc3a8a7a, 0x0de08fd0,\n    0xb5759d45, 0x44af98ef, 0x8db09050, 0x7c6a95fa, 0x7565bba4,\n    0x84bfbe0e, 0x4da0b6b1, 0xbc7ab31b, 0x04efa18e, 0xf535a424,\n    0x3c2aac9b, 0xcdf0a931, 0x96718ff0, 0x67ab8a5a, 0xaeb482e5,\n    0x5f6e874f, 0xe7fb95da, 0x16219070, 0xdf3e98cf, 0x2ee49d65,\n    0x683cd54d, 0x99e6d0e7, 0x50f9d858, 0xa123ddf2, 0x19b6cf67,\n    0xe86ccacd, 0x2173c272, 0xd0a9c7d8, 0x8b28e119, 0x7af2e4b3,\n    0xb3edec0c, 0x4237e9a6, 0xfaa2fb33, 0x0b78fe99, 0xc267f626,\n    0x33bdf38c, 0x4fd76676, 0xbe0d63dc, 0x77126b63, 0x86c86ec9,\n    0x3e5d7c5c, 0xcf8779f6, 0x06987149, 0xf74274e3, 0xacc35222,\n    0x5d195788, 0x94065f37, 0x65dc5a9d, 0xdd494808, 0x2c934da2,\n    0xe58c451d, 0x145640b7, 0x528e089f, 0xa3540d35, 0x6a4b058a,\n    0x9b910020, 0x230412b5, 0xd2de171f, 0x1bc11fa0, 0xea1b1a0a,\n    0xb19a3ccb, 0x40403961, 0x895f31de, 0x78853474, 0xc01026e1,\n    0x31ca234b, 0xf8d52bf4, 0x090f2e5e, 0xeacb7748, 0x1b1172e2,\n    0xd20e7a5d, 0x23d47ff7, 0x9b416d62, 0x6a9b68c8, 0xa3846077,\n    0x525e65dd, 0x09df431c, 0xf80546b6, 0x311a4e09, 0xc0c04ba3,\n    0x78555936, 0x898f5c9c, 0x40905423, 0xb14a5189, 0xf79219a1,\n    0x06481c0b, 0xcf5714b4, 0x3e8d111e, 0x8618038b, 0x77c20621,\n    0xbedd0e9e, 0x4f070b34, 0x14862df5, 0xe55c285f, 0x2c4320e0,\n    0xdd99254a, 0x650c37df, 0x94d63275, 0x5dc93aca, 0xac133f60,\n    0xd079aa9a, 0x21a3af30, 0xe8bca78f, 0x1966a225, 0xa1f3b0b0,\n    0x5029b51a, 0x9936bda5, 0x68ecb80f, 0x336d9ece, 0xc2b79b64,\n    0x0ba893db, 0xfa729671, 0x42e784e4, 0xb33d814e, 0x7a2289f1,\n    0x8bf88c5b, 0xcd20c473, 0x3cfac1d9, 0xf5e5c966, 0x043fcccc,\n    0xbcaade59, 0x4d70dbf3, 0x846fd34c, 0x75b5d6e6, 0x2e34f027,\n    0xdfeef58d, 0x16f1fd32, 0xe72bf898, 0x5fbeea0d, 0xae64efa7,\n    0x677be718, 0x96a1e2b2, 0x9faeccec, 0x6e74c946, 0xa76bc1f9,\n    0x56b1c453, 0xee24d6c6, 0x1ffed36c, 0xd6e1dbd3, 0x273bde79,\n    0x7cbaf8b8, 0x8d60fd12, 0x447ff5ad, 0xb5a5f007, 0x0d30e292,\n    0xfceae738, 0x35f5ef87, 0xc42fea2d, 0x82f7a205, 0x732da7af,\n    0xba32af10, 0x4be8aaba, 0xf37db82f, 0x02a7bd85, 0xcbb8b53a,\n    0x3a62b090, 0x61e39651, 0x903993fb, 0x59269b44, 0xa8fc9eee,\n    0x10698c7b, 0xe1b389d1, 0x28ac816e, 0xd97684c4, 0xa51c113e,\n    0x54c61494, 0x9dd91c2b, 0x6c031981, 0xd4960b14, 0x254c0ebe,\n    0xec530601, 0x1d8903ab, 0x4608256a, 0xb7d220c0, 0x7ecd287f,\n    0x8f172dd5, 0x37823f40, 0xc6583aea, 0x0f473255, 0xfe9d37ff,\n    0xb8457fd7, 0x499f7a7d, 0x808072c2, 0x715a7768, 0xc9cf65fd,\n    0x38156057, 0xf10a68e8, 0x00d06d42, 0x5b514b83, 0xaa8b4e29,\n    0x63944696, 0x924e433c, 0x2adb51a9, 0xdb015403, 0x121e5cbc,\n    0xe3c45916},\n   {0x00000000, 0x0ee7e8d1, 0x1dcfd1a2, 0x13283973, 0x3b9fa344,\n    0x35784b95, 0x265072e6, 0x28b79a37, 0x773f4688, 0x79d8ae59,\n    0x6af0972a, 0x64177ffb, 0x4ca0e5cc, 0x42470d1d, 0x516f346e,\n    0x5f88dcbf, 0xee7e8d10, 0xe09965c1, 0xf3b15cb2, 0xfd56b463,\n    0xd5e12e54, 0xdb06c685, 0xc82efff6, 0xc6c91727, 0x9941cb98,\n    0x97a62349, 0x848e1a3a, 0x8a69f2eb, 0xa2de68dc, 0xac39800d,\n    0xbf11b97e, 0xb1f651af, 0x078c1c61, 0x096bf4b0, 0x1a43cdc3,\n    0x14a42512, 0x3c13bf25, 0x32f457f4, 0x21dc6e87, 0x2f3b8656,\n    0x70b35ae9, 0x7e54b238, 0x6d7c8b4b, 0x639b639a, 0x4b2cf9ad,\n    0x45cb117c, 0x56e3280f, 0x5804c0de, 0xe9f29171, 0xe71579a0,\n    0xf43d40d3, 0xfadaa802, 0xd26d3235, 0xdc8adae4, 0xcfa2e397,\n    0xc1450b46, 0x9ecdd7f9, 0x902a3f28, 0x8302065b, 0x8de5ee8a,\n    0xa55274bd, 0xabb59c6c, 0xb89da51f, 0xb67a4dce, 0x0f1838c2,\n    0x01ffd013, 0x12d7e960, 0x1c3001b1, 0x34879b86, 0x3a607357,\n    0x29484a24, 0x27afa2f5, 0x78277e4a, 0x76c0969b, 0x65e8afe8,\n    0x6b0f4739, 0x43b8dd0e, 0x4d5f35df, 0x5e770cac, 0x5090e47d,\n    0xe166b5d2, 0xef815d03, 0xfca96470, 0xf24e8ca1, 0xdaf91696,\n    0xd41efe47, 0xc736c734, 0xc9d12fe5, 0x9659f35a, 0x98be1b8b,\n    0x8b9622f8, 0x8571ca29, 0xadc6501e, 0xa321b8cf, 0xb00981bc,\n    0xbeee696d, 0x089424a3, 0x0673cc72, 0x155bf501, 0x1bbc1dd0,\n    0x330b87e7, 0x3dec6f36, 0x2ec45645, 0x2023be94, 0x7fab622b,\n    0x714c8afa, 0x6264b389, 0x6c835b58, 0x4434c16f, 0x4ad329be,\n    0x59fb10cd, 0x571cf81c, 0xe6eaa9b3, 0xe80d4162, 0xfb257811,\n    0xf5c290c0, 0xdd750af7, 0xd392e226, 0xc0badb55, 0xce5d3384,\n    0x91d5ef3b, 0x9f3207ea, 0x8c1a3e99, 0x82fdd648, 0xaa4a4c7f,\n    0xa4ada4ae, 0xb7859ddd, 0xb962750c, 0x1e307184, 0x10d79955,\n    0x03ffa026, 0x0d1848f7, 0x25afd2c0, 0x2b483a11, 0x38600362,\n    0x3687ebb3, 0x690f370c, 0x67e8dfdd, 0x74c0e6ae, 0x7a270e7f,\n    0x52909448, 0x5c777c99, 0x4f5f45ea, 0x41b8ad3b, 0xf04efc94,\n    0xfea91445, 0xed812d36, 0xe366c5e7, 0xcbd15fd0, 0xc536b701,\n    0xd61e8e72, 0xd8f966a3, 0x8771ba1c, 0x899652cd, 0x9abe6bbe,\n    0x9459836f, 0xbcee1958, 0xb209f189, 0xa121c8fa, 0xafc6202b,\n    0x19bc6de5, 0x175b8534, 0x0473bc47, 0x0a945496, 0x2223cea1,\n    0x2cc42670, 0x3fec1f03, 0x310bf7d2, 0x6e832b6d, 0x6064c3bc,\n    0x734cfacf, 0x7dab121e, 0x551c8829, 0x5bfb60f8, 0x48d3598b,\n    0x4634b15a, 0xf7c2e0f5, 0xf9250824, 0xea0d3157, 0xe4ead986,\n    0xcc5d43b1, 0xc2baab60, 0xd1929213, 0xdf757ac2, 0x80fda67d,\n    0x8e1a4eac, 0x9d3277df, 0x93d59f0e, 0xbb620539, 0xb585ede8,\n    0xa6add49b, 0xa84a3c4a, 0x11284946, 0x1fcfa197, 0x0ce798e4,\n    0x02007035, 0x2ab7ea02, 0x245002d3, 0x37783ba0, 0x399fd371,\n    0x66170fce, 0x68f0e71f, 0x7bd8de6c, 0x753f36bd, 0x5d88ac8a,\n    0x536f445b, 0x40477d28, 0x4ea095f9, 0xff56c456, 0xf1b12c87,\n    0xe29915f4, 0xec7efd25, 0xc4c96712, 0xca2e8fc3, 0xd906b6b0,\n    0xd7e15e61, 0x886982de, 0x868e6a0f, 0x95a6537c, 0x9b41bbad,\n    0xb3f6219a, 0xbd11c94b, 0xae39f038, 0xa0de18e9, 0x16a45527,\n    0x1843bdf6, 0x0b6b8485, 0x058c6c54, 0x2d3bf663, 0x23dc1eb2,\n    0x30f427c1, 0x3e13cf10, 0x619b13af, 0x6f7cfb7e, 0x7c54c20d,\n    0x72b32adc, 0x5a04b0eb, 0x54e3583a, 0x47cb6149, 0x492c8998,\n    0xf8dad837, 0xf63d30e6, 0xe5150995, 0xebf2e144, 0xc3457b73,\n    0xcda293a2, 0xde8aaad1, 0xd06d4200, 0x8fe59ebf, 0x8102766e,\n    0x922a4f1d, 0x9ccda7cc, 0xb47a3dfb, 0xba9dd52a, 0xa9b5ec59,\n    0xa7520488},\n   {0x00000000, 0x3c60e308, 0x78c1c610, 0x44a12518, 0xf1838c20,\n    0xcde36f28, 0x89424a30, 0xb522a938, 0x38761e01, 0x0416fd09,\n    0x40b7d811, 0x7cd73b19, 0xc9f59221, 0xf5957129, 0xb1345431,\n    0x8d54b739, 0x70ec3c02, 0x4c8cdf0a, 0x082dfa12, 0x344d191a,\n    0x816fb022, 0xbd0f532a, 0xf9ae7632, 0xc5ce953a, 0x489a2203,\n    0x74fac10b, 0x305be413, 0x0c3b071b, 0xb919ae23, 0x85794d2b,\n    0xc1d86833, 0xfdb88b3b, 0xe1d87804, 0xddb89b0c, 0x9919be14,\n    0xa5795d1c, 0x105bf424, 0x2c3b172c, 0x689a3234, 0x54fad13c,\n    0xd9ae6605, 0xe5ce850d, 0xa16fa015, 0x9d0f431d, 0x282dea25,\n    0x144d092d, 0x50ec2c35, 0x6c8ccf3d, 0x91344406, 0xad54a70e,\n    0xe9f58216, 0xd595611e, 0x60b7c826, 0x5cd72b2e, 0x18760e36,\n    0x2416ed3e, 0xa9425a07, 0x9522b90f, 0xd1839c17, 0xede37f1f,\n    0x58c1d627, 0x64a1352f, 0x20001037, 0x1c60f33f, 0x18c1f649,\n    0x24a11541, 0x60003059, 0x5c60d351, 0xe9427a69, 0xd5229961,\n    0x9183bc79, 0xade35f71, 0x20b7e848, 0x1cd70b40, 0x58762e58,\n    0x6416cd50, 0xd1346468, 0xed548760, 0xa9f5a278, 0x95954170,\n    0x682dca4b, 0x544d2943, 0x10ec0c5b, 0x2c8cef53, 0x99ae466b,\n    0xa5cea563, 0xe16f807b, 0xdd0f6373, 0x505bd44a, 0x6c3b3742,\n    0x289a125a, 0x14faf152, 0xa1d8586a, 0x9db8bb62, 0xd9199e7a,\n    0xe5797d72, 0xf9198e4d, 0xc5796d45, 0x81d8485d, 0xbdb8ab55,\n    0x089a026d, 0x34fae165, 0x705bc47d, 0x4c3b2775, 0xc16f904c,\n    0xfd0f7344, 0xb9ae565c, 0x85ceb554, 0x30ec1c6c, 0x0c8cff64,\n    0x482dda7c, 0x744d3974, 0x89f5b24f, 0xb5955147, 0xf134745f,\n    0xcd549757, 0x78763e6f, 0x4416dd67, 0x00b7f87f, 0x3cd71b77,\n    0xb183ac4e, 0x8de34f46, 0xc9426a5e, 0xf5228956, 0x4000206e,\n    0x7c60c366, 0x38c1e67e, 0x04a10576, 0x3183ec92, 0x0de30f9a,\n    0x49422a82, 0x7522c98a, 0xc00060b2, 0xfc6083ba, 0xb8c1a6a2,\n    0x84a145aa, 0x09f5f293, 0x3595119b, 0x71343483, 0x4d54d78b,\n    0xf8767eb3, 0xc4169dbb, 0x80b7b8a3, 0xbcd75bab, 0x416fd090,\n    0x7d0f3398, 0x39ae1680, 0x05cef588, 0xb0ec5cb0, 0x8c8cbfb8,\n    0xc82d9aa0, 0xf44d79a8, 0x7919ce91, 0x45792d99, 0x01d80881,\n    0x3db8eb89, 0x889a42b1, 0xb4faa1b9, 0xf05b84a1, 0xcc3b67a9,\n    0xd05b9496, 0xec3b779e, 0xa89a5286, 0x94fab18e, 0x21d818b6,\n    0x1db8fbbe, 0x5919dea6, 0x65793dae, 0xe82d8a97, 0xd44d699f,\n    0x90ec4c87, 0xac8caf8f, 0x19ae06b7, 0x25cee5bf, 0x616fc0a7,\n    0x5d0f23af, 0xa0b7a894, 0x9cd74b9c, 0xd8766e84, 0xe4168d8c,\n    0x513424b4, 0x6d54c7bc, 0x29f5e2a4, 0x159501ac, 0x98c1b695,\n    0xa4a1559d, 0xe0007085, 0xdc60938d, 0x69423ab5, 0x5522d9bd,\n    0x1183fca5, 0x2de31fad, 0x29421adb, 0x1522f9d3, 0x5183dccb,\n    0x6de33fc3, 0xd8c196fb, 0xe4a175f3, 0xa00050eb, 0x9c60b3e3,\n    0x113404da, 0x2d54e7d2, 0x69f5c2ca, 0x559521c2, 0xe0b788fa,\n    0xdcd76bf2, 0x98764eea, 0xa416ade2, 0x59ae26d9, 0x65cec5d1,\n    0x216fe0c9, 0x1d0f03c1, 0xa82daaf9, 0x944d49f1, 0xd0ec6ce9,\n    0xec8c8fe1, 0x61d838d8, 0x5db8dbd0, 0x1919fec8, 0x25791dc0,\n    0x905bb4f8, 0xac3b57f0, 0xe89a72e8, 0xd4fa91e0, 0xc89a62df,\n    0xf4fa81d7, 0xb05ba4cf, 0x8c3b47c7, 0x3919eeff, 0x05790df7,\n    0x41d828ef, 0x7db8cbe7, 0xf0ec7cde, 0xcc8c9fd6, 0x882dbace,\n    0xb44d59c6, 0x016ff0fe, 0x3d0f13f6, 0x79ae36ee, 0x45ced5e6,\n    0xb8765edd, 0x8416bdd5, 0xc0b798cd, 0xfcd77bc5, 0x49f5d2fd,\n    0x759531f5, 0x313414ed, 0x0d54f7e5, 0x800040dc, 0xbc60a3d4,\n    0xf8c186cc, 0xc4a165c4, 0x7183ccfc, 0x4de32ff4, 0x09420aec,\n    0x3522e9e4},\n   {0x00000000, 0x6307d924, 0xc60fb248, 0xa5086b6c, 0x576e62d1,\n    0x3469bbf5, 0x9161d099, 0xf26609bd, 0xaedcc5a2, 0xcddb1c86,\n    0x68d377ea, 0x0bd4aece, 0xf9b2a773, 0x9ab57e57, 0x3fbd153b,\n    0x5cbacc1f, 0x86c88d05, 0xe5cf5421, 0x40c73f4d, 0x23c0e669,\n    0xd1a6efd4, 0xb2a136f0, 0x17a95d9c, 0x74ae84b8, 0x281448a7,\n    0x4b139183, 0xee1bfaef, 0x8d1c23cb, 0x7f7a2a76, 0x1c7df352,\n    0xb975983e, 0xda72411a, 0xd6e01c4b, 0xb5e7c56f, 0x10efae03,\n    0x73e87727, 0x818e7e9a, 0xe289a7be, 0x4781ccd2, 0x248615f6,\n    0x783cd9e9, 0x1b3b00cd, 0xbe336ba1, 0xdd34b285, 0x2f52bb38,\n    0x4c55621c, 0xe95d0970, 0x8a5ad054, 0x5028914e, 0x332f486a,\n    0x96272306, 0xf520fa22, 0x0746f39f, 0x64412abb, 0xc14941d7,\n    0xa24e98f3, 0xfef454ec, 0x9df38dc8, 0x38fbe6a4, 0x5bfc3f80,\n    0xa99a363d, 0xca9def19, 0x6f958475, 0x0c925d51, 0x76b13ed7,\n    0x15b6e7f3, 0xb0be8c9f, 0xd3b955bb, 0x21df5c06, 0x42d88522,\n    0xe7d0ee4e, 0x84d7376a, 0xd86dfb75, 0xbb6a2251, 0x1e62493d,\n    0x7d659019, 0x8f0399a4, 0xec044080, 0x490c2bec, 0x2a0bf2c8,\n    0xf079b3d2, 0x937e6af6, 0x3676019a, 0x5571d8be, 0xa717d103,\n    0xc4100827, 0x6118634b, 0x021fba6f, 0x5ea57670, 0x3da2af54,\n    0x98aac438, 0xfbad1d1c, 0x09cb14a1, 0x6acccd85, 0xcfc4a6e9,\n    0xacc37fcd, 0xa051229c, 0xc356fbb8, 0x665e90d4, 0x055949f0,\n    0xf73f404d, 0x94389969, 0x3130f205, 0x52372b21, 0x0e8de73e,\n    0x6d8a3e1a, 0xc8825576, 0xab858c52, 0x59e385ef, 0x3ae45ccb,\n    0x9fec37a7, 0xfcebee83, 0x2699af99, 0x459e76bd, 0xe0961dd1,\n    0x8391c4f5, 0x71f7cd48, 0x12f0146c, 0xb7f87f00, 0xd4ffa624,\n    0x88456a3b, 0xeb42b31f, 0x4e4ad873, 0x2d4d0157, 0xdf2b08ea,\n    0xbc2cd1ce, 0x1924baa2, 0x7a236386, 0xed627dae, 0x8e65a48a,\n    0x2b6dcfe6, 0x486a16c2, 0xba0c1f7f, 0xd90bc65b, 0x7c03ad37,\n    0x1f047413, 0x43beb80c, 0x20b96128, 0x85b10a44, 0xe6b6d360,\n    0x14d0dadd, 0x77d703f9, 0xd2df6895, 0xb1d8b1b1, 0x6baaf0ab,\n    0x08ad298f, 0xada542e3, 0xcea29bc7, 0x3cc4927a, 0x5fc34b5e,\n    0xfacb2032, 0x99ccf916, 0xc5763509, 0xa671ec2d, 0x03798741,\n    0x607e5e65, 0x921857d8, 0xf11f8efc, 0x5417e590, 0x37103cb4,\n    0x3b8261e5, 0x5885b8c1, 0xfd8dd3ad, 0x9e8a0a89, 0x6cec0334,\n    0x0febda10, 0xaae3b17c, 0xc9e46858, 0x955ea447, 0xf6597d63,\n    0x5351160f, 0x3056cf2b, 0xc230c696, 0xa1371fb2, 0x043f74de,\n    0x6738adfa, 0xbd4aece0, 0xde4d35c4, 0x7b455ea8, 0x1842878c,\n    0xea248e31, 0x89235715, 0x2c2b3c79, 0x4f2ce55d, 0x13962942,\n    0x7091f066, 0xd5999b0a, 0xb69e422e, 0x44f84b93, 0x27ff92b7,\n    0x82f7f9db, 0xe1f020ff, 0x9bd34379, 0xf8d49a5d, 0x5ddcf131,\n    0x3edb2815, 0xccbd21a8, 0xafbaf88c, 0x0ab293e0, 0x69b54ac4,\n    0x350f86db, 0x56085fff, 0xf3003493, 0x9007edb7, 0x6261e40a,\n    0x01663d2e, 0xa46e5642, 0xc7698f66, 0x1d1bce7c, 0x7e1c1758,\n    0xdb147c34, 0xb813a510, 0x4a75acad, 0x29727589, 0x8c7a1ee5,\n    0xef7dc7c1, 0xb3c70bde, 0xd0c0d2fa, 0x75c8b996, 0x16cf60b2,\n    0xe4a9690f, 0x87aeb02b, 0x22a6db47, 0x41a10263, 0x4d335f32,\n    0x2e348616, 0x8b3ced7a, 0xe83b345e, 0x1a5d3de3, 0x795ae4c7,\n    0xdc528fab, 0xbf55568f, 0xe3ef9a90, 0x80e843b4, 0x25e028d8,\n    0x46e7f1fc, 0xb481f841, 0xd7862165, 0x728e4a09, 0x1189932d,\n    0xcbfbd237, 0xa8fc0b13, 0x0df4607f, 0x6ef3b95b, 0x9c95b0e6,\n    0xff9269c2, 0x5a9a02ae, 0x399ddb8a, 0x65271795, 0x0620ceb1,\n    0xa328a5dd, 0xc02f7cf9, 0x32497544, 0x514eac60, 0xf446c70c,\n    0x97411e28},\n   {0x00000000, 0x01b5fd1d, 0x036bfa3a, 0x02de0727, 0x06d7f474,\n    0x07620969, 0x05bc0e4e, 0x0409f353, 0x0dafe8e8, 0x0c1a15f5,\n    0x0ec412d2, 0x0f71efcf, 0x0b781c9c, 0x0acde181, 0x0813e6a6,\n    0x09a61bbb, 0x1b5fd1d0, 0x1aea2ccd, 0x18342bea, 0x1981d6f7,\n    0x1d8825a4, 0x1c3dd8b9, 0x1ee3df9e, 0x1f562283, 0x16f03938,\n    0x1745c425, 0x159bc302, 0x142e3e1f, 0x1027cd4c, 0x11923051,\n    0x134c3776, 0x12f9ca6b, 0x36bfa3a0, 0x370a5ebd, 0x35d4599a,\n    0x3461a487, 0x306857d4, 0x31ddaac9, 0x3303adee, 0x32b650f3,\n    0x3b104b48, 0x3aa5b655, 0x387bb172, 0x39ce4c6f, 0x3dc7bf3c,\n    0x3c724221, 0x3eac4506, 0x3f19b81b, 0x2de07270, 0x2c558f6d,\n    0x2e8b884a, 0x2f3e7557, 0x2b378604, 0x2a827b19, 0x285c7c3e,\n    0x29e98123, 0x204f9a98, 0x21fa6785, 0x232460a2, 0x22919dbf,\n    0x26986eec, 0x272d93f1, 0x25f394d6, 0x244669cb, 0x6d7f4740,\n    0x6ccaba5d, 0x6e14bd7a, 0x6fa14067, 0x6ba8b334, 0x6a1d4e29,\n    0x68c3490e, 0x6976b413, 0x60d0afa8, 0x616552b5, 0x63bb5592,\n    0x620ea88f, 0x66075bdc, 0x67b2a6c1, 0x656ca1e6, 0x64d95cfb,\n    0x76209690, 0x77956b8d, 0x754b6caa, 0x74fe91b7, 0x70f762e4,\n    0x71429ff9, 0x739c98de, 0x722965c3, 0x7b8f7e78, 0x7a3a8365,\n    0x78e48442, 0x7951795f, 0x7d588a0c, 0x7ced7711, 0x7e337036,\n    0x7f868d2b, 0x5bc0e4e0, 0x5a7519fd, 0x58ab1eda, 0x591ee3c7,\n    0x5d171094, 0x5ca2ed89, 0x5e7ceaae, 0x5fc917b3, 0x566f0c08,\n    0x57daf115, 0x5504f632, 0x54b10b2f, 0x50b8f87c, 0x510d0561,\n    0x53d30246, 0x5266ff5b, 0x409f3530, 0x412ac82d, 0x43f4cf0a,\n    0x42413217, 0x4648c144, 0x47fd3c59, 0x45233b7e, 0x4496c663,\n    0x4d30ddd8, 0x4c8520c5, 0x4e5b27e2, 0x4feedaff, 0x4be729ac,\n    0x4a52d4b1, 0x488cd396, 0x49392e8b, 0xdafe8e80, 0xdb4b739d,\n    0xd99574ba, 0xd82089a7, 0xdc297af4, 0xdd9c87e9, 0xdf4280ce,\n    0xdef77dd3, 0xd7516668, 0xd6e49b75, 0xd43a9c52, 0xd58f614f,\n    0xd186921c, 0xd0336f01, 0xd2ed6826, 0xd358953b, 0xc1a15f50,\n    0xc014a24d, 0xc2caa56a, 0xc37f5877, 0xc776ab24, 0xc6c35639,\n    0xc41d511e, 0xc5a8ac03, 0xcc0eb7b8, 0xcdbb4aa5, 0xcf654d82,\n    0xced0b09f, 0xcad943cc, 0xcb6cbed1, 0xc9b2b9f6, 0xc80744eb,\n    0xec412d20, 0xedf4d03d, 0xef2ad71a, 0xee9f2a07, 0xea96d954,\n    0xeb232449, 0xe9fd236e, 0xe848de73, 0xe1eec5c8, 0xe05b38d5,\n    0xe2853ff2, 0xe330c2ef, 0xe73931bc, 0xe68ccca1, 0xe452cb86,\n    0xe5e7369b, 0xf71efcf0, 0xf6ab01ed, 0xf47506ca, 0xf5c0fbd7,\n    0xf1c90884, 0xf07cf599, 0xf2a2f2be, 0xf3170fa3, 0xfab11418,\n    0xfb04e905, 0xf9daee22, 0xf86f133f, 0xfc66e06c, 0xfdd31d71,\n    0xff0d1a56, 0xfeb8e74b, 0xb781c9c0, 0xb63434dd, 0xb4ea33fa,\n    0xb55fcee7, 0xb1563db4, 0xb0e3c0a9, 0xb23dc78e, 0xb3883a93,\n    0xba2e2128, 0xbb9bdc35, 0xb945db12, 0xb8f0260f, 0xbcf9d55c,\n    0xbd4c2841, 0xbf922f66, 0xbe27d27b, 0xacde1810, 0xad6be50d,\n    0xafb5e22a, 0xae001f37, 0xaa09ec64, 0xabbc1179, 0xa962165e,\n    0xa8d7eb43, 0xa171f0f8, 0xa0c40de5, 0xa21a0ac2, 0xa3aff7df,\n    0xa7a6048c, 0xa613f991, 0xa4cdfeb6, 0xa57803ab, 0x813e6a60,\n    0x808b977d, 0x8255905a, 0x83e06d47, 0x87e99e14, 0x865c6309,\n    0x8482642e, 0x85379933, 0x8c918288, 0x8d247f95, 0x8ffa78b2,\n    0x8e4f85af, 0x8a4676fc, 0x8bf38be1, 0x892d8cc6, 0x889871db,\n    0x9a61bbb0, 0x9bd446ad, 0x990a418a, 0x98bfbc97, 0x9cb64fc4,\n    0x9d03b2d9, 0x9fddb5fe, 0x9e6848e3, 0x97ce5358, 0x967bae45,\n    0x94a5a962, 0x9510547f, 0x9119a72c, 0x90ac5a31, 0x92725d16,\n    0x93c7a00b},\n   {0x00000000, 0x6e8c1b41, 0xdd183682, 0xb3942dc3, 0x61416b45,\n    0x0fcd7004, 0xbc595dc7, 0xd2d54686, 0xc282d68a, 0xac0ecdcb,\n    0x1f9ae008, 0x7116fb49, 0xa3c3bdcf, 0xcd4fa68e, 0x7edb8b4d,\n    0x1057900c, 0x5e74ab55, 0x30f8b014, 0x836c9dd7, 0xede08696,\n    0x3f35c010, 0x51b9db51, 0xe22df692, 0x8ca1edd3, 0x9cf67ddf,\n    0xf27a669e, 0x41ee4b5d, 0x2f62501c, 0xfdb7169a, 0x933b0ddb,\n    0x20af2018, 0x4e233b59, 0xbce956aa, 0xd2654deb, 0x61f16028,\n    0x0f7d7b69, 0xdda83def, 0xb32426ae, 0x00b00b6d, 0x6e3c102c,\n    0x7e6b8020, 0x10e79b61, 0xa373b6a2, 0xcdffade3, 0x1f2aeb65,\n    0x71a6f024, 0xc232dde7, 0xacbec6a6, 0xe29dfdff, 0x8c11e6be,\n    0x3f85cb7d, 0x5109d03c, 0x83dc96ba, 0xed508dfb, 0x5ec4a038,\n    0x3048bb79, 0x201f2b75, 0x4e933034, 0xfd071df7, 0x938b06b6,\n    0x415e4030, 0x2fd25b71, 0x9c4676b2, 0xf2ca6df3, 0xa2a3ab15,\n    0xcc2fb054, 0x7fbb9d97, 0x113786d6, 0xc3e2c050, 0xad6edb11,\n    0x1efaf6d2, 0x7076ed93, 0x60217d9f, 0x0ead66de, 0xbd394b1d,\n    0xd3b5505c, 0x016016da, 0x6fec0d9b, 0xdc782058, 0xb2f43b19,\n    0xfcd70040, 0x925b1b01, 0x21cf36c2, 0x4f432d83, 0x9d966b05,\n    0xf31a7044, 0x408e5d87, 0x2e0246c6, 0x3e55d6ca, 0x50d9cd8b,\n    0xe34de048, 0x8dc1fb09, 0x5f14bd8f, 0x3198a6ce, 0x820c8b0d,\n    0xec80904c, 0x1e4afdbf, 0x70c6e6fe, 0xc352cb3d, 0xadded07c,\n    0x7f0b96fa, 0x11878dbb, 0xa213a078, 0xcc9fbb39, 0xdcc82b35,\n    0xb2443074, 0x01d01db7, 0x6f5c06f6, 0xbd894070, 0xd3055b31,\n    0x609176f2, 0x0e1d6db3, 0x403e56ea, 0x2eb24dab, 0x9d266068,\n    0xf3aa7b29, 0x217f3daf, 0x4ff326ee, 0xfc670b2d, 0x92eb106c,\n    0x82bc8060, 0xec309b21, 0x5fa4b6e2, 0x3128ada3, 0xe3fdeb25,\n    0x8d71f064, 0x3ee5dda7, 0x5069c6e6, 0x9e36506b, 0xf0ba4b2a,\n    0x432e66e9, 0x2da27da8, 0xff773b2e, 0x91fb206f, 0x226f0dac,\n    0x4ce316ed, 0x5cb486e1, 0x32389da0, 0x81acb063, 0xef20ab22,\n    0x3df5eda4, 0x5379f6e5, 0xe0eddb26, 0x8e61c067, 0xc042fb3e,\n    0xaecee07f, 0x1d5acdbc, 0x73d6d6fd, 0xa103907b, 0xcf8f8b3a,\n    0x7c1ba6f9, 0x1297bdb8, 0x02c02db4, 0x6c4c36f5, 0xdfd81b36,\n    0xb1540077, 0x638146f1, 0x0d0d5db0, 0xbe997073, 0xd0156b32,\n    0x22df06c1, 0x4c531d80, 0xffc73043, 0x914b2b02, 0x439e6d84,\n    0x2d1276c5, 0x9e865b06, 0xf00a4047, 0xe05dd04b, 0x8ed1cb0a,\n    0x3d45e6c9, 0x53c9fd88, 0x811cbb0e, 0xef90a04f, 0x5c048d8c,\n    0x328896cd, 0x7cabad94, 0x1227b6d5, 0xa1b39b16, 0xcf3f8057,\n    0x1deac6d1, 0x7366dd90, 0xc0f2f053, 0xae7eeb12, 0xbe297b1e,\n    0xd0a5605f, 0x63314d9c, 0x0dbd56dd, 0xdf68105b, 0xb1e40b1a,\n    0x027026d9, 0x6cfc3d98, 0x3c95fb7e, 0x5219e03f, 0xe18dcdfc,\n    0x8f01d6bd, 0x5dd4903b, 0x33588b7a, 0x80cca6b9, 0xee40bdf8,\n    0xfe172df4, 0x909b36b5, 0x230f1b76, 0x4d830037, 0x9f5646b1,\n    0xf1da5df0, 0x424e7033, 0x2cc26b72, 0x62e1502b, 0x0c6d4b6a,\n    0xbff966a9, 0xd1757de8, 0x03a03b6e, 0x6d2c202f, 0xdeb80dec,\n    0xb03416ad, 0xa06386a1, 0xceef9de0, 0x7d7bb023, 0x13f7ab62,\n    0xc122ede4, 0xafaef6a5, 0x1c3adb66, 0x72b6c027, 0x807cadd4,\n    0xeef0b695, 0x5d649b56, 0x33e88017, 0xe13dc691, 0x8fb1ddd0,\n    0x3c25f013, 0x52a9eb52, 0x42fe7b5e, 0x2c72601f, 0x9fe64ddc,\n    0xf16a569d, 0x23bf101b, 0x4d330b5a, 0xfea72699, 0x902b3dd8,\n    0xde080681, 0xb0841dc0, 0x03103003, 0x6d9c2b42, 0xbf496dc4,\n    0xd1c57685, 0x62515b46, 0x0cdd4007, 0x1c8ad00b, 0x7206cb4a,\n    0xc192e689, 0xaf1efdc8, 0x7dcbbb4e, 0x1347a00f, 0xa0d38dcc,\n    0xce5f968d},\n   {0x00000000, 0xe71da697, 0x154a4b6f, 0xf257edf8, 0x2a9496de,\n    0xcd893049, 0x3fdeddb1, 0xd8c37b26, 0x55292dbc, 0xb2348b2b,\n    0x406366d3, 0xa77ec044, 0x7fbdbb62, 0x98a01df5, 0x6af7f00d,\n    0x8dea569a, 0xaa525b78, 0x4d4ffdef, 0xbf181017, 0x5805b680,\n    0x80c6cda6, 0x67db6b31, 0x958c86c9, 0x7291205e, 0xff7b76c4,\n    0x1866d053, 0xea313dab, 0x0d2c9b3c, 0xd5efe01a, 0x32f2468d,\n    0xc0a5ab75, 0x27b80de2, 0x8fd5b0b1, 0x68c81626, 0x9a9ffbde,\n    0x7d825d49, 0xa541266f, 0x425c80f8, 0xb00b6d00, 0x5716cb97,\n    0xdafc9d0d, 0x3de13b9a, 0xcfb6d662, 0x28ab70f5, 0xf0680bd3,\n    0x1775ad44, 0xe52240bc, 0x023fe62b, 0x2587ebc9, 0xc29a4d5e,\n    0x30cda0a6, 0xd7d00631, 0x0f137d17, 0xe80edb80, 0x1a593678,\n    0xfd4490ef, 0x70aec675, 0x97b360e2, 0x65e48d1a, 0x82f92b8d,\n    0x5a3a50ab, 0xbd27f63c, 0x4f701bc4, 0xa86dbd53, 0xc4da6723,\n    0x23c7c1b4, 0xd1902c4c, 0x368d8adb, 0xee4ef1fd, 0x0953576a,\n    0xfb04ba92, 0x1c191c05, 0x91f34a9f, 0x76eeec08, 0x84b901f0,\n    0x63a4a767, 0xbb67dc41, 0x5c7a7ad6, 0xae2d972e, 0x493031b9,\n    0x6e883c5b, 0x89959acc, 0x7bc27734, 0x9cdfd1a3, 0x441caa85,\n    0xa3010c12, 0x5156e1ea, 0xb64b477d, 0x3ba111e7, 0xdcbcb770,\n    0x2eeb5a88, 0xc9f6fc1f, 0x11358739, 0xf62821ae, 0x047fcc56,\n    0xe3626ac1, 0x4b0fd792, 0xac127105, 0x5e459cfd, 0xb9583a6a,\n    0x619b414c, 0x8686e7db, 0x74d10a23, 0x93ccacb4, 0x1e26fa2e,\n    0xf93b5cb9, 0x0b6cb141, 0xec7117d6, 0x34b26cf0, 0xd3afca67,\n    0x21f8279f, 0xc6e58108, 0xe15d8cea, 0x06402a7d, 0xf417c785,\n    0x130a6112, 0xcbc91a34, 0x2cd4bca3, 0xde83515b, 0x399ef7cc,\n    0xb474a156, 0x536907c1, 0xa13eea39, 0x46234cae, 0x9ee03788,\n    0x79fd911f, 0x8baa7ce7, 0x6cb7da70, 0x52c5c807, 0xb5d86e90,\n    0x478f8368, 0xa09225ff, 0x78515ed9, 0x9f4cf84e, 0x6d1b15b6,\n    0x8a06b321, 0x07ece5bb, 0xe0f1432c, 0x12a6aed4, 0xf5bb0843,\n    0x2d787365, 0xca65d5f2, 0x3832380a, 0xdf2f9e9d, 0xf897937f,\n    0x1f8a35e8, 0xedddd810, 0x0ac07e87, 0xd20305a1, 0x351ea336,\n    0xc7494ece, 0x2054e859, 0xadbebec3, 0x4aa31854, 0xb8f4f5ac,\n    0x5fe9533b, 0x872a281d, 0x60378e8a, 0x92606372, 0x757dc5e5,\n    0xdd1078b6, 0x3a0dde21, 0xc85a33d9, 0x2f47954e, 0xf784ee68,\n    0x109948ff, 0xe2cea507, 0x05d30390, 0x8839550a, 0x6f24f39d,\n    0x9d731e65, 0x7a6eb8f2, 0xa2adc3d4, 0x45b06543, 0xb7e788bb,\n    0x50fa2e2c, 0x774223ce, 0x905f8559, 0x620868a1, 0x8515ce36,\n    0x5dd6b510, 0xbacb1387, 0x489cfe7f, 0xaf8158e8, 0x226b0e72,\n    0xc576a8e5, 0x3721451d, 0xd03ce38a, 0x08ff98ac, 0xefe23e3b,\n    0x1db5d3c3, 0xfaa87554, 0x961faf24, 0x710209b3, 0x8355e44b,\n    0x644842dc, 0xbc8b39fa, 0x5b969f6d, 0xa9c17295, 0x4edcd402,\n    0xc3368298, 0x242b240f, 0xd67cc9f7, 0x31616f60, 0xe9a21446,\n    0x0ebfb2d1, 0xfce85f29, 0x1bf5f9be, 0x3c4df45c, 0xdb5052cb,\n    0x2907bf33, 0xce1a19a4, 0x16d96282, 0xf1c4c415, 0x039329ed,\n    0xe48e8f7a, 0x6964d9e0, 0x8e797f77, 0x7c2e928f, 0x9b333418,\n    0x43f04f3e, 0xa4ede9a9, 0x56ba0451, 0xb1a7a2c6, 0x19ca1f95,\n    0xfed7b902, 0x0c8054fa, 0xeb9df26d, 0x335e894b, 0xd4432fdc,\n    0x2614c224, 0xc10964b3, 0x4ce33229, 0xabfe94be, 0x59a97946,\n    0xbeb4dfd1, 0x6677a4f7, 0x816a0260, 0x733def98, 0x9420490f,\n    0xb39844ed, 0x5485e27a, 0xa6d20f82, 0x41cfa915, 0x990cd233,\n    0x7e1174a4, 0x8c46995c, 0x6b5b3fcb, 0xe6b16951, 0x01accfc6,\n    0xf3fb223e, 0x14e684a9, 0xcc25ff8f, 0x2b385918, 0xd96fb4e0,\n    0x3e721277},\n   {0x00000000, 0xa58b900e, 0x9066265d, 0x35edb653, 0xfbbd4afb,\n    0x5e36daf5, 0x6bdb6ca6, 0xce50fca8, 0x2c0b93b7, 0x898003b9,\n    0xbc6db5ea, 0x19e625e4, 0xd7b6d94c, 0x723d4942, 0x47d0ff11,\n    0xe25b6f1f, 0x5817276e, 0xfd9cb760, 0xc8710133, 0x6dfa913d,\n    0xa3aa6d95, 0x0621fd9b, 0x33cc4bc8, 0x9647dbc6, 0x741cb4d9,\n    0xd19724d7, 0xe47a9284, 0x41f1028a, 0x8fa1fe22, 0x2a2a6e2c,\n    0x1fc7d87f, 0xba4c4871, 0xb02e4edc, 0x15a5ded2, 0x20486881,\n    0x85c3f88f, 0x4b930427, 0xee189429, 0xdbf5227a, 0x7e7eb274,\n    0x9c25dd6b, 0x39ae4d65, 0x0c43fb36, 0xa9c86b38, 0x67989790,\n    0xc213079e, 0xf7feb1cd, 0x527521c3, 0xe83969b2, 0x4db2f9bc,\n    0x785f4fef, 0xddd4dfe1, 0x13842349, 0xb60fb347, 0x83e20514,\n    0x2669951a, 0xc432fa05, 0x61b96a0b, 0x5454dc58, 0xf1df4c56,\n    0x3f8fb0fe, 0x9a0420f0, 0xafe996a3, 0x0a6206ad, 0xbb2d9bf9,\n    0x1ea60bf7, 0x2b4bbda4, 0x8ec02daa, 0x4090d102, 0xe51b410c,\n    0xd0f6f75f, 0x757d6751, 0x9726084e, 0x32ad9840, 0x07402e13,\n    0xa2cbbe1d, 0x6c9b42b5, 0xc910d2bb, 0xfcfd64e8, 0x5976f4e6,\n    0xe33abc97, 0x46b12c99, 0x735c9aca, 0xd6d70ac4, 0x1887f66c,\n    0xbd0c6662, 0x88e1d031, 0x2d6a403f, 0xcf312f20, 0x6ababf2e,\n    0x5f57097d, 0xfadc9973, 0x348c65db, 0x9107f5d5, 0xa4ea4386,\n    0x0161d388, 0x0b03d525, 0xae88452b, 0x9b65f378, 0x3eee6376,\n    0xf0be9fde, 0x55350fd0, 0x60d8b983, 0xc553298d, 0x27084692,\n    0x8283d69c, 0xb76e60cf, 0x12e5f0c1, 0xdcb50c69, 0x793e9c67,\n    0x4cd32a34, 0xe958ba3a, 0x5314f24b, 0xf69f6245, 0xc372d416,\n    0x66f94418, 0xa8a9b8b0, 0x0d2228be, 0x38cf9eed, 0x9d440ee3,\n    0x7f1f61fc, 0xda94f1f2, 0xef7947a1, 0x4af2d7af, 0x84a22b07,\n    0x2129bb09, 0x14c40d5a, 0xb14f9d54, 0xad2a31b3, 0x08a1a1bd,\n    0x3d4c17ee, 0x98c787e0, 0x56977b48, 0xf31ceb46, 0xc6f15d15,\n    0x637acd1b, 0x8121a204, 0x24aa320a, 0x11478459, 0xb4cc1457,\n    0x7a9ce8ff, 0xdf1778f1, 0xeafacea2, 0x4f715eac, 0xf53d16dd,\n    0x50b686d3, 0x655b3080, 0xc0d0a08e, 0x0e805c26, 0xab0bcc28,\n    0x9ee67a7b, 0x3b6dea75, 0xd936856a, 0x7cbd1564, 0x4950a337,\n    0xecdb3339, 0x228bcf91, 0x87005f9f, 0xb2ede9cc, 0x176679c2,\n    0x1d047f6f, 0xb88fef61, 0x8d625932, 0x28e9c93c, 0xe6b93594,\n    0x4332a59a, 0x76df13c9, 0xd35483c7, 0x310fecd8, 0x94847cd6,\n    0xa169ca85, 0x04e25a8b, 0xcab2a623, 0x6f39362d, 0x5ad4807e,\n    0xff5f1070, 0x45135801, 0xe098c80f, 0xd5757e5c, 0x70feee52,\n    0xbeae12fa, 0x1b2582f4, 0x2ec834a7, 0x8b43a4a9, 0x6918cbb6,\n    0xcc935bb8, 0xf97eedeb, 0x5cf57de5, 0x92a5814d, 0x372e1143,\n    0x02c3a710, 0xa748371e, 0x1607aa4a, 0xb38c3a44, 0x86618c17,\n    0x23ea1c19, 0xedbae0b1, 0x483170bf, 0x7ddcc6ec, 0xd85756e2,\n    0x3a0c39fd, 0x9f87a9f3, 0xaa6a1fa0, 0x0fe18fae, 0xc1b17306,\n    0x643ae308, 0x51d7555b, 0xf45cc555, 0x4e108d24, 0xeb9b1d2a,\n    0xde76ab79, 0x7bfd3b77, 0xb5adc7df, 0x102657d1, 0x25cbe182,\n    0x8040718c, 0x621b1e93, 0xc7908e9d, 0xf27d38ce, 0x57f6a8c0,\n    0x99a65468, 0x3c2dc466, 0x09c07235, 0xac4be23b, 0xa629e496,\n    0x03a27498, 0x364fc2cb, 0x93c452c5, 0x5d94ae6d, 0xf81f3e63,\n    0xcdf28830, 0x6879183e, 0x8a227721, 0x2fa9e72f, 0x1a44517c,\n    0xbfcfc172, 0x719f3dda, 0xd414add4, 0xe1f91b87, 0x44728b89,\n    0xfe3ec3f8, 0x5bb553f6, 0x6e58e5a5, 0xcbd375ab, 0x05838903,\n    0xa008190d, 0x95e5af5e, 0x306e3f50, 0xd235504f, 0x77bec041,\n    0x42537612, 0xe7d8e61c, 0x29881ab4, 0x8c038aba, 0xb9ee3ce9,\n    0x1c65ace7}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0x0e908ba500000000, 0x5d26669000000000,\n    0x53b6ed3500000000, 0xfb4abdfb00000000, 0xf5da365e00000000,\n    0xa66cdb6b00000000, 0xa8fc50ce00000000, 0xb7930b2c00000000,\n    0xb903808900000000, 0xeab56dbc00000000, 0xe425e61900000000,\n    0x4cd9b6d700000000, 0x42493d7200000000, 0x11ffd04700000000,\n    0x1f6f5be200000000, 0x6e27175800000000, 0x60b79cfd00000000,\n    0x330171c800000000, 0x3d91fa6d00000000, 0x956daaa300000000,\n    0x9bfd210600000000, 0xc84bcc3300000000, 0xc6db479600000000,\n    0xd9b41c7400000000, 0xd72497d100000000, 0x84927ae400000000,\n    0x8a02f14100000000, 0x22fea18f00000000, 0x2c6e2a2a00000000,\n    0x7fd8c71f00000000, 0x71484cba00000000, 0xdc4e2eb000000000,\n    0xd2dea51500000000, 0x8168482000000000, 0x8ff8c38500000000,\n    0x2704934b00000000, 0x299418ee00000000, 0x7a22f5db00000000,\n    0x74b27e7e00000000, 0x6bdd259c00000000, 0x654dae3900000000,\n    0x36fb430c00000000, 0x386bc8a900000000, 0x9097986700000000,\n    0x9e0713c200000000, 0xcdb1fef700000000, 0xc321755200000000,\n    0xb26939e800000000, 0xbcf9b24d00000000, 0xef4f5f7800000000,\n    0xe1dfd4dd00000000, 0x4923841300000000, 0x47b30fb600000000,\n    0x1405e28300000000, 0x1a95692600000000, 0x05fa32c400000000,\n    0x0b6ab96100000000, 0x58dc545400000000, 0x564cdff100000000,\n    0xfeb08f3f00000000, 0xf020049a00000000, 0xa396e9af00000000,\n    0xad06620a00000000, 0xf99b2dbb00000000, 0xf70ba61e00000000,\n    0xa4bd4b2b00000000, 0xaa2dc08e00000000, 0x02d1904000000000,\n    0x0c411be500000000, 0x5ff7f6d000000000, 0x51677d7500000000,\n    0x4e08269700000000, 0x4098ad3200000000, 0x132e400700000000,\n    0x1dbecba200000000, 0xb5429b6c00000000, 0xbbd210c900000000,\n    0xe864fdfc00000000, 0xe6f4765900000000, 0x97bc3ae300000000,\n    0x992cb14600000000, 0xca9a5c7300000000, 0xc40ad7d600000000,\n    0x6cf6871800000000, 0x62660cbd00000000, 0x31d0e18800000000,\n    0x3f406a2d00000000, 0x202f31cf00000000, 0x2ebfba6a00000000,\n    0x7d09575f00000000, 0x7399dcfa00000000, 0xdb658c3400000000,\n    0xd5f5079100000000, 0x8643eaa400000000, 0x88d3610100000000,\n    0x25d5030b00000000, 0x2b4588ae00000000, 0x78f3659b00000000,\n    0x7663ee3e00000000, 0xde9fbef000000000, 0xd00f355500000000,\n    0x83b9d86000000000, 0x8d2953c500000000, 0x9246082700000000,\n    0x9cd6838200000000, 0xcf606eb700000000, 0xc1f0e51200000000,\n    0x690cb5dc00000000, 0x679c3e7900000000, 0x342ad34c00000000,\n    0x3aba58e900000000, 0x4bf2145300000000, 0x45629ff600000000,\n    0x16d472c300000000, 0x1844f96600000000, 0xb0b8a9a800000000,\n    0xbe28220d00000000, 0xed9ecf3800000000, 0xe30e449d00000000,\n    0xfc611f7f00000000, 0xf2f194da00000000, 0xa14779ef00000000,\n    0xafd7f24a00000000, 0x072ba28400000000, 0x09bb292100000000,\n    0x5a0dc41400000000, 0x549d4fb100000000, 0xb3312aad00000000,\n    0xbda1a10800000000, 0xee174c3d00000000, 0xe087c79800000000,\n    0x487b975600000000, 0x46eb1cf300000000, 0x155df1c600000000,\n    0x1bcd7a6300000000, 0x04a2218100000000, 0x0a32aa2400000000,\n    0x5984471100000000, 0x5714ccb400000000, 0xffe89c7a00000000,\n    0xf17817df00000000, 0xa2cefaea00000000, 0xac5e714f00000000,\n    0xdd163df500000000, 0xd386b65000000000, 0x80305b6500000000,\n    0x8ea0d0c000000000, 0x265c800e00000000, 0x28cc0bab00000000,\n    0x7b7ae69e00000000, 0x75ea6d3b00000000, 0x6a8536d900000000,\n    0x6415bd7c00000000, 0x37a3504900000000, 0x3933dbec00000000,\n    0x91cf8b2200000000, 0x9f5f008700000000, 0xcce9edb200000000,\n    0xc279661700000000, 0x6f7f041d00000000, 0x61ef8fb800000000,\n    0x3259628d00000000, 0x3cc9e92800000000, 0x9435b9e600000000,\n    0x9aa5324300000000, 0xc913df7600000000, 0xc78354d300000000,\n    0xd8ec0f3100000000, 0xd67c849400000000, 0x85ca69a100000000,\n    0x8b5ae20400000000, 0x23a6b2ca00000000, 0x2d36396f00000000,\n    0x7e80d45a00000000, 0x70105fff00000000, 0x0158134500000000,\n    0x0fc898e000000000, 0x5c7e75d500000000, 0x52eefe7000000000,\n    0xfa12aebe00000000, 0xf482251b00000000, 0xa734c82e00000000,\n    0xa9a4438b00000000, 0xb6cb186900000000, 0xb85b93cc00000000,\n    0xebed7ef900000000, 0xe57df55c00000000, 0x4d81a59200000000,\n    0x43112e3700000000, 0x10a7c30200000000, 0x1e3748a700000000,\n    0x4aaa071600000000, 0x443a8cb300000000, 0x178c618600000000,\n    0x191cea2300000000, 0xb1e0baed00000000, 0xbf70314800000000,\n    0xecc6dc7d00000000, 0xe25657d800000000, 0xfd390c3a00000000,\n    0xf3a9879f00000000, 0xa01f6aaa00000000, 0xae8fe10f00000000,\n    0x0673b1c100000000, 0x08e33a6400000000, 0x5b55d75100000000,\n    0x55c55cf400000000, 0x248d104e00000000, 0x2a1d9beb00000000,\n    0x79ab76de00000000, 0x773bfd7b00000000, 0xdfc7adb500000000,\n    0xd157261000000000, 0x82e1cb2500000000, 0x8c71408000000000,\n    0x931e1b6200000000, 0x9d8e90c700000000, 0xce387df200000000,\n    0xc0a8f65700000000, 0x6854a69900000000, 0x66c42d3c00000000,\n    0x3572c00900000000, 0x3be24bac00000000, 0x96e429a600000000,\n    0x9874a20300000000, 0xcbc24f3600000000, 0xc552c49300000000,\n    0x6dae945d00000000, 0x633e1ff800000000, 0x3088f2cd00000000,\n    0x3e18796800000000, 0x2177228a00000000, 0x2fe7a92f00000000,\n    0x7c51441a00000000, 0x72c1cfbf00000000, 0xda3d9f7100000000,\n    0xd4ad14d400000000, 0x871bf9e100000000, 0x898b724400000000,\n    0xf8c33efe00000000, 0xf653b55b00000000, 0xa5e5586e00000000,\n    0xab75d3cb00000000, 0x0389830500000000, 0x0d1908a000000000,\n    0x5eafe59500000000, 0x503f6e3000000000, 0x4f5035d200000000,\n    0x41c0be7700000000, 0x1276534200000000, 0x1ce6d8e700000000,\n    0xb41a882900000000, 0xba8a038c00000000, 0xe93ceeb900000000,\n    0xe7ac651c00000000},\n   {0x0000000000000000, 0x97a61de700000000, 0x6f4b4a1500000000,\n    0xf8ed57f200000000, 0xde96942a00000000, 0x493089cd00000000,\n    0xb1ddde3f00000000, 0x267bc3d800000000, 0xbc2d295500000000,\n    0x2b8b34b200000000, 0xd366634000000000, 0x44c07ea700000000,\n    0x62bbbd7f00000000, 0xf51da09800000000, 0x0df0f76a00000000,\n    0x9a56ea8d00000000, 0x785b52aa00000000, 0xeffd4f4d00000000,\n    0x171018bf00000000, 0x80b6055800000000, 0xa6cdc68000000000,\n    0x316bdb6700000000, 0xc9868c9500000000, 0x5e20917200000000,\n    0xc4767bff00000000, 0x53d0661800000000, 0xab3d31ea00000000,\n    0x3c9b2c0d00000000, 0x1ae0efd500000000, 0x8d46f23200000000,\n    0x75aba5c000000000, 0xe20db82700000000, 0xb1b0d58f00000000,\n    0x2616c86800000000, 0xdefb9f9a00000000, 0x495d827d00000000,\n    0x6f2641a500000000, 0xf8805c4200000000, 0x006d0bb000000000,\n    0x97cb165700000000, 0x0d9dfcda00000000, 0x9a3be13d00000000,\n    0x62d6b6cf00000000, 0xf570ab2800000000, 0xd30b68f000000000,\n    0x44ad751700000000, 0xbc4022e500000000, 0x2be63f0200000000,\n    0xc9eb872500000000, 0x5e4d9ac200000000, 0xa6a0cd3000000000,\n    0x3106d0d700000000, 0x177d130f00000000, 0x80db0ee800000000,\n    0x7836591a00000000, 0xef9044fd00000000, 0x75c6ae7000000000,\n    0xe260b39700000000, 0x1a8de46500000000, 0x8d2bf98200000000,\n    0xab503a5a00000000, 0x3cf627bd00000000, 0xc41b704f00000000,\n    0x53bd6da800000000, 0x2367dac400000000, 0xb4c1c72300000000,\n    0x4c2c90d100000000, 0xdb8a8d3600000000, 0xfdf14eee00000000,\n    0x6a57530900000000, 0x92ba04fb00000000, 0x051c191c00000000,\n    0x9f4af39100000000, 0x08ecee7600000000, 0xf001b98400000000,\n    0x67a7a46300000000, 0x41dc67bb00000000, 0xd67a7a5c00000000,\n    0x2e972dae00000000, 0xb931304900000000, 0x5b3c886e00000000,\n    0xcc9a958900000000, 0x3477c27b00000000, 0xa3d1df9c00000000,\n    0x85aa1c4400000000, 0x120c01a300000000, 0xeae1565100000000,\n    0x7d474bb600000000, 0xe711a13b00000000, 0x70b7bcdc00000000,\n    0x885aeb2e00000000, 0x1ffcf6c900000000, 0x3987351100000000,\n    0xae2128f600000000, 0x56cc7f0400000000, 0xc16a62e300000000,\n    0x92d70f4b00000000, 0x057112ac00000000, 0xfd9c455e00000000,\n    0x6a3a58b900000000, 0x4c419b6100000000, 0xdbe7868600000000,\n    0x230ad17400000000, 0xb4accc9300000000, 0x2efa261e00000000,\n    0xb95c3bf900000000, 0x41b16c0b00000000, 0xd61771ec00000000,\n    0xf06cb23400000000, 0x67caafd300000000, 0x9f27f82100000000,\n    0x0881e5c600000000, 0xea8c5de100000000, 0x7d2a400600000000,\n    0x85c717f400000000, 0x12610a1300000000, 0x341ac9cb00000000,\n    0xa3bcd42c00000000, 0x5b5183de00000000, 0xccf79e3900000000,\n    0x56a174b400000000, 0xc107695300000000, 0x39ea3ea100000000,\n    0xae4c234600000000, 0x8837e09e00000000, 0x1f91fd7900000000,\n    0xe77caa8b00000000, 0x70dab76c00000000, 0x07c8c55200000000,\n    0x906ed8b500000000, 0x68838f4700000000, 0xff2592a000000000,\n    0xd95e517800000000, 0x4ef84c9f00000000, 0xb6151b6d00000000,\n    0x21b3068a00000000, 0xbbe5ec0700000000, 0x2c43f1e000000000,\n    0xd4aea61200000000, 0x4308bbf500000000, 0x6573782d00000000,\n    0xf2d565ca00000000, 0x0a38323800000000, 0x9d9e2fdf00000000,\n    0x7f9397f800000000, 0xe8358a1f00000000, 0x10d8dded00000000,\n    0x877ec00a00000000, 0xa10503d200000000, 0x36a31e3500000000,\n    0xce4e49c700000000, 0x59e8542000000000, 0xc3bebead00000000,\n    0x5418a34a00000000, 0xacf5f4b800000000, 0x3b53e95f00000000,\n    0x1d282a8700000000, 0x8a8e376000000000, 0x7263609200000000,\n    0xe5c57d7500000000, 0xb67810dd00000000, 0x21de0d3a00000000,\n    0xd9335ac800000000, 0x4e95472f00000000, 0x68ee84f700000000,\n    0xff48991000000000, 0x07a5cee200000000, 0x9003d30500000000,\n    0x0a55398800000000, 0x9df3246f00000000, 0x651e739d00000000,\n    0xf2b86e7a00000000, 0xd4c3ada200000000, 0x4365b04500000000,\n    0xbb88e7b700000000, 0x2c2efa5000000000, 0xce23427700000000,\n    0x59855f9000000000, 0xa168086200000000, 0x36ce158500000000,\n    0x10b5d65d00000000, 0x8713cbba00000000, 0x7ffe9c4800000000,\n    0xe85881af00000000, 0x720e6b2200000000, 0xe5a876c500000000,\n    0x1d45213700000000, 0x8ae33cd000000000, 0xac98ff0800000000,\n    0x3b3ee2ef00000000, 0xc3d3b51d00000000, 0x5475a8fa00000000,\n    0x24af1f9600000000, 0xb309027100000000, 0x4be4558300000000,\n    0xdc42486400000000, 0xfa398bbc00000000, 0x6d9f965b00000000,\n    0x9572c1a900000000, 0x02d4dc4e00000000, 0x988236c300000000,\n    0x0f242b2400000000, 0xf7c97cd600000000, 0x606f613100000000,\n    0x4614a2e900000000, 0xd1b2bf0e00000000, 0x295fe8fc00000000,\n    0xbef9f51b00000000, 0x5cf44d3c00000000, 0xcb5250db00000000,\n    0x33bf072900000000, 0xa4191ace00000000, 0x8262d91600000000,\n    0x15c4c4f100000000, 0xed29930300000000, 0x7a8f8ee400000000,\n    0xe0d9646900000000, 0x777f798e00000000, 0x8f922e7c00000000,\n    0x1834339b00000000, 0x3e4ff04300000000, 0xa9e9eda400000000,\n    0x5104ba5600000000, 0xc6a2a7b100000000, 0x951fca1900000000,\n    0x02b9d7fe00000000, 0xfa54800c00000000, 0x6df29deb00000000,\n    0x4b895e3300000000, 0xdc2f43d400000000, 0x24c2142600000000,\n    0xb36409c100000000, 0x2932e34c00000000, 0xbe94feab00000000,\n    0x4679a95900000000, 0xd1dfb4be00000000, 0xf7a4776600000000,\n    0x60026a8100000000, 0x98ef3d7300000000, 0x0f49209400000000,\n    0xed4498b300000000, 0x7ae2855400000000, 0x820fd2a600000000,\n    0x15a9cf4100000000, 0x33d20c9900000000, 0xa474117e00000000,\n    0x5c99468c00000000, 0xcb3f5b6b00000000, 0x5169b1e600000000,\n    0xc6cfac0100000000, 0x3e22fbf300000000, 0xa984e61400000000,\n    0x8fff25cc00000000, 0x1859382b00000000, 0xe0b46fd900000000,\n    0x7712723e00000000},\n   {0x0000000000000000, 0x411b8c6e00000000, 0x823618dd00000000,\n    0xc32d94b300000000, 0x456b416100000000, 0x0470cd0f00000000,\n    0xc75d59bc00000000, 0x8646d5d200000000, 0x8ad682c200000000,\n    0xcbcd0eac00000000, 0x08e09a1f00000000, 0x49fb167100000000,\n    0xcfbdc3a300000000, 0x8ea64fcd00000000, 0x4d8bdb7e00000000,\n    0x0c90571000000000, 0x55ab745e00000000, 0x14b0f83000000000,\n    0xd79d6c8300000000, 0x9686e0ed00000000, 0x10c0353f00000000,\n    0x51dbb95100000000, 0x92f62de200000000, 0xd3eda18c00000000,\n    0xdf7df69c00000000, 0x9e667af200000000, 0x5d4bee4100000000,\n    0x1c50622f00000000, 0x9a16b7fd00000000, 0xdb0d3b9300000000,\n    0x1820af2000000000, 0x593b234e00000000, 0xaa56e9bc00000000,\n    0xeb4d65d200000000, 0x2860f16100000000, 0x697b7d0f00000000,\n    0xef3da8dd00000000, 0xae2624b300000000, 0x6d0bb00000000000,\n    0x2c103c6e00000000, 0x20806b7e00000000, 0x619be71000000000,\n    0xa2b673a300000000, 0xe3adffcd00000000, 0x65eb2a1f00000000,\n    0x24f0a67100000000, 0xe7dd32c200000000, 0xa6c6beac00000000,\n    0xfffd9de200000000, 0xbee6118c00000000, 0x7dcb853f00000000,\n    0x3cd0095100000000, 0xba96dc8300000000, 0xfb8d50ed00000000,\n    0x38a0c45e00000000, 0x79bb483000000000, 0x752b1f2000000000,\n    0x3430934e00000000, 0xf71d07fd00000000, 0xb6068b9300000000,\n    0x30405e4100000000, 0x715bd22f00000000, 0xb276469c00000000,\n    0xf36dcaf200000000, 0x15aba3a200000000, 0x54b02fcc00000000,\n    0x979dbb7f00000000, 0xd686371100000000, 0x50c0e2c300000000,\n    0x11db6ead00000000, 0xd2f6fa1e00000000, 0x93ed767000000000,\n    0x9f7d216000000000, 0xde66ad0e00000000, 0x1d4b39bd00000000,\n    0x5c50b5d300000000, 0xda16600100000000, 0x9b0dec6f00000000,\n    0x582078dc00000000, 0x193bf4b200000000, 0x4000d7fc00000000,\n    0x011b5b9200000000, 0xc236cf2100000000, 0x832d434f00000000,\n    0x056b969d00000000, 0x44701af300000000, 0x875d8e4000000000,\n    0xc646022e00000000, 0xcad6553e00000000, 0x8bcdd95000000000,\n    0x48e04de300000000, 0x09fbc18d00000000, 0x8fbd145f00000000,\n    0xcea6983100000000, 0x0d8b0c8200000000, 0x4c9080ec00000000,\n    0xbffd4a1e00000000, 0xfee6c67000000000, 0x3dcb52c300000000,\n    0x7cd0dead00000000, 0xfa960b7f00000000, 0xbb8d871100000000,\n    0x78a013a200000000, 0x39bb9fcc00000000, 0x352bc8dc00000000,\n    0x743044b200000000, 0xb71dd00100000000, 0xf6065c6f00000000,\n    0x704089bd00000000, 0x315b05d300000000, 0xf276916000000000,\n    0xb36d1d0e00000000, 0xea563e4000000000, 0xab4db22e00000000,\n    0x6860269d00000000, 0x297baaf300000000, 0xaf3d7f2100000000,\n    0xee26f34f00000000, 0x2d0b67fc00000000, 0x6c10eb9200000000,\n    0x6080bc8200000000, 0x219b30ec00000000, 0xe2b6a45f00000000,\n    0xa3ad283100000000, 0x25ebfde300000000, 0x64f0718d00000000,\n    0xa7dde53e00000000, 0xe6c6695000000000, 0x6b50369e00000000,\n    0x2a4bbaf000000000, 0xe9662e4300000000, 0xa87da22d00000000,\n    0x2e3b77ff00000000, 0x6f20fb9100000000, 0xac0d6f2200000000,\n    0xed16e34c00000000, 0xe186b45c00000000, 0xa09d383200000000,\n    0x63b0ac8100000000, 0x22ab20ef00000000, 0xa4edf53d00000000,\n    0xe5f6795300000000, 0x26dbede000000000, 0x67c0618e00000000,\n    0x3efb42c000000000, 0x7fe0ceae00000000, 0xbccd5a1d00000000,\n    0xfdd6d67300000000, 0x7b9003a100000000, 0x3a8b8fcf00000000,\n    0xf9a61b7c00000000, 0xb8bd971200000000, 0xb42dc00200000000,\n    0xf5364c6c00000000, 0x361bd8df00000000, 0x770054b100000000,\n    0xf146816300000000, 0xb05d0d0d00000000, 0x737099be00000000,\n    0x326b15d000000000, 0xc106df2200000000, 0x801d534c00000000,\n    0x4330c7ff00000000, 0x022b4b9100000000, 0x846d9e4300000000,\n    0xc576122d00000000, 0x065b869e00000000, 0x47400af000000000,\n    0x4bd05de000000000, 0x0acbd18e00000000, 0xc9e6453d00000000,\n    0x88fdc95300000000, 0x0ebb1c8100000000, 0x4fa090ef00000000,\n    0x8c8d045c00000000, 0xcd96883200000000, 0x94adab7c00000000,\n    0xd5b6271200000000, 0x169bb3a100000000, 0x57803fcf00000000,\n    0xd1c6ea1d00000000, 0x90dd667300000000, 0x53f0f2c000000000,\n    0x12eb7eae00000000, 0x1e7b29be00000000, 0x5f60a5d000000000,\n    0x9c4d316300000000, 0xdd56bd0d00000000, 0x5b1068df00000000,\n    0x1a0be4b100000000, 0xd926700200000000, 0x983dfc6c00000000,\n    0x7efb953c00000000, 0x3fe0195200000000, 0xfccd8de100000000,\n    0xbdd6018f00000000, 0x3b90d45d00000000, 0x7a8b583300000000,\n    0xb9a6cc8000000000, 0xf8bd40ee00000000, 0xf42d17fe00000000,\n    0xb5369b9000000000, 0x761b0f2300000000, 0x3700834d00000000,\n    0xb146569f00000000, 0xf05ddaf100000000, 0x33704e4200000000,\n    0x726bc22c00000000, 0x2b50e16200000000, 0x6a4b6d0c00000000,\n    0xa966f9bf00000000, 0xe87d75d100000000, 0x6e3ba00300000000,\n    0x2f202c6d00000000, 0xec0db8de00000000, 0xad1634b000000000,\n    0xa18663a000000000, 0xe09defce00000000, 0x23b07b7d00000000,\n    0x62abf71300000000, 0xe4ed22c100000000, 0xa5f6aeaf00000000,\n    0x66db3a1c00000000, 0x27c0b67200000000, 0xd4ad7c8000000000,\n    0x95b6f0ee00000000, 0x569b645d00000000, 0x1780e83300000000,\n    0x91c63de100000000, 0xd0ddb18f00000000, 0x13f0253c00000000,\n    0x52eba95200000000, 0x5e7bfe4200000000, 0x1f60722c00000000,\n    0xdc4de69f00000000, 0x9d566af100000000, 0x1b10bf2300000000,\n    0x5a0b334d00000000, 0x9926a7fe00000000, 0xd83d2b9000000000,\n    0x810608de00000000, 0xc01d84b000000000, 0x0330100300000000,\n    0x422b9c6d00000000, 0xc46d49bf00000000, 0x8576c5d100000000,\n    0x465b516200000000, 0x0740dd0c00000000, 0x0bd08a1c00000000,\n    0x4acb067200000000, 0x89e692c100000000, 0xc8fd1eaf00000000,\n    0x4ebbcb7d00000000, 0x0fa0471300000000, 0xcc8dd3a000000000,\n    0x8d965fce00000000},\n   {0x0000000000000000, 0x1dfdb50100000000, 0x3afa6b0300000000,\n    0x2707de0200000000, 0x74f4d70600000000, 0x6909620700000000,\n    0x4e0ebc0500000000, 0x53f3090400000000, 0xe8e8af0d00000000,\n    0xf5151a0c00000000, 0xd212c40e00000000, 0xcfef710f00000000,\n    0x9c1c780b00000000, 0x81e1cd0a00000000, 0xa6e6130800000000,\n    0xbb1ba60900000000, 0xd0d15f1b00000000, 0xcd2cea1a00000000,\n    0xea2b341800000000, 0xf7d6811900000000, 0xa425881d00000000,\n    0xb9d83d1c00000000, 0x9edfe31e00000000, 0x8322561f00000000,\n    0x3839f01600000000, 0x25c4451700000000, 0x02c39b1500000000,\n    0x1f3e2e1400000000, 0x4ccd271000000000, 0x5130921100000000,\n    0x76374c1300000000, 0x6bcaf91200000000, 0xa0a3bf3600000000,\n    0xbd5e0a3700000000, 0x9a59d43500000000, 0x87a4613400000000,\n    0xd457683000000000, 0xc9aadd3100000000, 0xeead033300000000,\n    0xf350b63200000000, 0x484b103b00000000, 0x55b6a53a00000000,\n    0x72b17b3800000000, 0x6f4cce3900000000, 0x3cbfc73d00000000,\n    0x2142723c00000000, 0x0645ac3e00000000, 0x1bb8193f00000000,\n    0x7072e02d00000000, 0x6d8f552c00000000, 0x4a888b2e00000000,\n    0x57753e2f00000000, 0x0486372b00000000, 0x197b822a00000000,\n    0x3e7c5c2800000000, 0x2381e92900000000, 0x989a4f2000000000,\n    0x8567fa2100000000, 0xa260242300000000, 0xbf9d912200000000,\n    0xec6e982600000000, 0xf1932d2700000000, 0xd694f32500000000,\n    0xcb69462400000000, 0x40477f6d00000000, 0x5dbaca6c00000000,\n    0x7abd146e00000000, 0x6740a16f00000000, 0x34b3a86b00000000,\n    0x294e1d6a00000000, 0x0e49c36800000000, 0x13b4766900000000,\n    0xa8afd06000000000, 0xb552656100000000, 0x9255bb6300000000,\n    0x8fa80e6200000000, 0xdc5b076600000000, 0xc1a6b26700000000,\n    0xe6a16c6500000000, 0xfb5cd96400000000, 0x9096207600000000,\n    0x8d6b957700000000, 0xaa6c4b7500000000, 0xb791fe7400000000,\n    0xe462f77000000000, 0xf99f427100000000, 0xde989c7300000000,\n    0xc365297200000000, 0x787e8f7b00000000, 0x65833a7a00000000,\n    0x4284e47800000000, 0x5f79517900000000, 0x0c8a587d00000000,\n    0x1177ed7c00000000, 0x3670337e00000000, 0x2b8d867f00000000,\n    0xe0e4c05b00000000, 0xfd19755a00000000, 0xda1eab5800000000,\n    0xc7e31e5900000000, 0x9410175d00000000, 0x89eda25c00000000,\n    0xaeea7c5e00000000, 0xb317c95f00000000, 0x080c6f5600000000,\n    0x15f1da5700000000, 0x32f6045500000000, 0x2f0bb15400000000,\n    0x7cf8b85000000000, 0x61050d5100000000, 0x4602d35300000000,\n    0x5bff665200000000, 0x30359f4000000000, 0x2dc82a4100000000,\n    0x0acff44300000000, 0x1732414200000000, 0x44c1484600000000,\n    0x593cfd4700000000, 0x7e3b234500000000, 0x63c6964400000000,\n    0xd8dd304d00000000, 0xc520854c00000000, 0xe2275b4e00000000,\n    0xffdaee4f00000000, 0xac29e74b00000000, 0xb1d4524a00000000,\n    0x96d38c4800000000, 0x8b2e394900000000, 0x808efeda00000000,\n    0x9d734bdb00000000, 0xba7495d900000000, 0xa78920d800000000,\n    0xf47a29dc00000000, 0xe9879cdd00000000, 0xce8042df00000000,\n    0xd37df7de00000000, 0x686651d700000000, 0x759be4d600000000,\n    0x529c3ad400000000, 0x4f618fd500000000, 0x1c9286d100000000,\n    0x016f33d000000000, 0x2668edd200000000, 0x3b9558d300000000,\n    0x505fa1c100000000, 0x4da214c000000000, 0x6aa5cac200000000,\n    0x77587fc300000000, 0x24ab76c700000000, 0x3956c3c600000000,\n    0x1e511dc400000000, 0x03aca8c500000000, 0xb8b70ecc00000000,\n    0xa54abbcd00000000, 0x824d65cf00000000, 0x9fb0d0ce00000000,\n    0xcc43d9ca00000000, 0xd1be6ccb00000000, 0xf6b9b2c900000000,\n    0xeb4407c800000000, 0x202d41ec00000000, 0x3dd0f4ed00000000,\n    0x1ad72aef00000000, 0x072a9fee00000000, 0x54d996ea00000000,\n    0x492423eb00000000, 0x6e23fde900000000, 0x73de48e800000000,\n    0xc8c5eee100000000, 0xd5385be000000000, 0xf23f85e200000000,\n    0xefc230e300000000, 0xbc3139e700000000, 0xa1cc8ce600000000,\n    0x86cb52e400000000, 0x9b36e7e500000000, 0xf0fc1ef700000000,\n    0xed01abf600000000, 0xca0675f400000000, 0xd7fbc0f500000000,\n    0x8408c9f100000000, 0x99f57cf000000000, 0xbef2a2f200000000,\n    0xa30f17f300000000, 0x1814b1fa00000000, 0x05e904fb00000000,\n    0x22eedaf900000000, 0x3f136ff800000000, 0x6ce066fc00000000,\n    0x711dd3fd00000000, 0x561a0dff00000000, 0x4be7b8fe00000000,\n    0xc0c981b700000000, 0xdd3434b600000000, 0xfa33eab400000000,\n    0xe7ce5fb500000000, 0xb43d56b100000000, 0xa9c0e3b000000000,\n    0x8ec73db200000000, 0x933a88b300000000, 0x28212eba00000000,\n    0x35dc9bbb00000000, 0x12db45b900000000, 0x0f26f0b800000000,\n    0x5cd5f9bc00000000, 0x41284cbd00000000, 0x662f92bf00000000,\n    0x7bd227be00000000, 0x1018deac00000000, 0x0de56bad00000000,\n    0x2ae2b5af00000000, 0x371f00ae00000000, 0x64ec09aa00000000,\n    0x7911bcab00000000, 0x5e1662a900000000, 0x43ebd7a800000000,\n    0xf8f071a100000000, 0xe50dc4a000000000, 0xc20a1aa200000000,\n    0xdff7afa300000000, 0x8c04a6a700000000, 0x91f913a600000000,\n    0xb6fecda400000000, 0xab0378a500000000, 0x606a3e8100000000,\n    0x7d978b8000000000, 0x5a90558200000000, 0x476de08300000000,\n    0x149ee98700000000, 0x09635c8600000000, 0x2e64828400000000,\n    0x3399378500000000, 0x8882918c00000000, 0x957f248d00000000,\n    0xb278fa8f00000000, 0xaf854f8e00000000, 0xfc76468a00000000,\n    0xe18bf38b00000000, 0xc68c2d8900000000, 0xdb71988800000000,\n    0xb0bb619a00000000, 0xad46d49b00000000, 0x8a410a9900000000,\n    0x97bcbf9800000000, 0xc44fb69c00000000, 0xd9b2039d00000000,\n    0xfeb5dd9f00000000, 0xe348689e00000000, 0x5853ce9700000000,\n    0x45ae7b9600000000, 0x62a9a59400000000, 0x7f54109500000000,\n    0x2ca7199100000000, 0x315aac9000000000, 0x165d729200000000,\n    0x0ba0c79300000000},\n   {0x0000000000000000, 0x24d9076300000000, 0x48b20fc600000000,\n    0x6c6b08a500000000, 0xd1626e5700000000, 0xf5bb693400000000,\n    0x99d0619100000000, 0xbd0966f200000000, 0xa2c5dcae00000000,\n    0x861cdbcd00000000, 0xea77d36800000000, 0xceaed40b00000000,\n    0x73a7b2f900000000, 0x577eb59a00000000, 0x3b15bd3f00000000,\n    0x1fccba5c00000000, 0x058dc88600000000, 0x2154cfe500000000,\n    0x4d3fc74000000000, 0x69e6c02300000000, 0xd4efa6d100000000,\n    0xf036a1b200000000, 0x9c5da91700000000, 0xb884ae7400000000,\n    0xa748142800000000, 0x8391134b00000000, 0xeffa1bee00000000,\n    0xcb231c8d00000000, 0x762a7a7f00000000, 0x52f37d1c00000000,\n    0x3e9875b900000000, 0x1a4172da00000000, 0x4b1ce0d600000000,\n    0x6fc5e7b500000000, 0x03aeef1000000000, 0x2777e87300000000,\n    0x9a7e8e8100000000, 0xbea789e200000000, 0xd2cc814700000000,\n    0xf615862400000000, 0xe9d93c7800000000, 0xcd003b1b00000000,\n    0xa16b33be00000000, 0x85b234dd00000000, 0x38bb522f00000000,\n    0x1c62554c00000000, 0x70095de900000000, 0x54d05a8a00000000,\n    0x4e91285000000000, 0x6a482f3300000000, 0x0623279600000000,\n    0x22fa20f500000000, 0x9ff3460700000000, 0xbb2a416400000000,\n    0xd74149c100000000, 0xf3984ea200000000, 0xec54f4fe00000000,\n    0xc88df39d00000000, 0xa4e6fb3800000000, 0x803ffc5b00000000,\n    0x3d369aa900000000, 0x19ef9dca00000000, 0x7584956f00000000,\n    0x515d920c00000000, 0xd73eb17600000000, 0xf3e7b61500000000,\n    0x9f8cbeb000000000, 0xbb55b9d300000000, 0x065cdf2100000000,\n    0x2285d84200000000, 0x4eeed0e700000000, 0x6a37d78400000000,\n    0x75fb6dd800000000, 0x51226abb00000000, 0x3d49621e00000000,\n    0x1990657d00000000, 0xa499038f00000000, 0x804004ec00000000,\n    0xec2b0c4900000000, 0xc8f20b2a00000000, 0xd2b379f000000000,\n    0xf66a7e9300000000, 0x9a01763600000000, 0xbed8715500000000,\n    0x03d117a700000000, 0x270810c400000000, 0x4b63186100000000,\n    0x6fba1f0200000000, 0x7076a55e00000000, 0x54afa23d00000000,\n    0x38c4aa9800000000, 0x1c1dadfb00000000, 0xa114cb0900000000,\n    0x85cdcc6a00000000, 0xe9a6c4cf00000000, 0xcd7fc3ac00000000,\n    0x9c2251a000000000, 0xb8fb56c300000000, 0xd4905e6600000000,\n    0xf049590500000000, 0x4d403ff700000000, 0x6999389400000000,\n    0x05f2303100000000, 0x212b375200000000, 0x3ee78d0e00000000,\n    0x1a3e8a6d00000000, 0x765582c800000000, 0x528c85ab00000000,\n    0xef85e35900000000, 0xcb5ce43a00000000, 0xa737ec9f00000000,\n    0x83eeebfc00000000, 0x99af992600000000, 0xbd769e4500000000,\n    0xd11d96e000000000, 0xf5c4918300000000, 0x48cdf77100000000,\n    0x6c14f01200000000, 0x007ff8b700000000, 0x24a6ffd400000000,\n    0x3b6a458800000000, 0x1fb342eb00000000, 0x73d84a4e00000000,\n    0x57014d2d00000000, 0xea082bdf00000000, 0xced12cbc00000000,\n    0xa2ba241900000000, 0x8663237a00000000, 0xae7d62ed00000000,\n    0x8aa4658e00000000, 0xe6cf6d2b00000000, 0xc2166a4800000000,\n    0x7f1f0cba00000000, 0x5bc60bd900000000, 0x37ad037c00000000,\n    0x1374041f00000000, 0x0cb8be4300000000, 0x2861b92000000000,\n    0x440ab18500000000, 0x60d3b6e600000000, 0xdddad01400000000,\n    0xf903d77700000000, 0x9568dfd200000000, 0xb1b1d8b100000000,\n    0xabf0aa6b00000000, 0x8f29ad0800000000, 0xe342a5ad00000000,\n    0xc79ba2ce00000000, 0x7a92c43c00000000, 0x5e4bc35f00000000,\n    0x3220cbfa00000000, 0x16f9cc9900000000, 0x093576c500000000,\n    0x2dec71a600000000, 0x4187790300000000, 0x655e7e6000000000,\n    0xd857189200000000, 0xfc8e1ff100000000, 0x90e5175400000000,\n    0xb43c103700000000, 0xe561823b00000000, 0xc1b8855800000000,\n    0xadd38dfd00000000, 0x890a8a9e00000000, 0x3403ec6c00000000,\n    0x10daeb0f00000000, 0x7cb1e3aa00000000, 0x5868e4c900000000,\n    0x47a45e9500000000, 0x637d59f600000000, 0x0f16515300000000,\n    0x2bcf563000000000, 0x96c630c200000000, 0xb21f37a100000000,\n    0xde743f0400000000, 0xfaad386700000000, 0xe0ec4abd00000000,\n    0xc4354dde00000000, 0xa85e457b00000000, 0x8c87421800000000,\n    0x318e24ea00000000, 0x1557238900000000, 0x793c2b2c00000000,\n    0x5de52c4f00000000, 0x4229961300000000, 0x66f0917000000000,\n    0x0a9b99d500000000, 0x2e429eb600000000, 0x934bf84400000000,\n    0xb792ff2700000000, 0xdbf9f78200000000, 0xff20f0e100000000,\n    0x7943d39b00000000, 0x5d9ad4f800000000, 0x31f1dc5d00000000,\n    0x1528db3e00000000, 0xa821bdcc00000000, 0x8cf8baaf00000000,\n    0xe093b20a00000000, 0xc44ab56900000000, 0xdb860f3500000000,\n    0xff5f085600000000, 0x933400f300000000, 0xb7ed079000000000,\n    0x0ae4616200000000, 0x2e3d660100000000, 0x42566ea400000000,\n    0x668f69c700000000, 0x7cce1b1d00000000, 0x58171c7e00000000,\n    0x347c14db00000000, 0x10a513b800000000, 0xadac754a00000000,\n    0x8975722900000000, 0xe51e7a8c00000000, 0xc1c77def00000000,\n    0xde0bc7b300000000, 0xfad2c0d000000000, 0x96b9c87500000000,\n    0xb260cf1600000000, 0x0f69a9e400000000, 0x2bb0ae8700000000,\n    0x47dba62200000000, 0x6302a14100000000, 0x325f334d00000000,\n    0x1686342e00000000, 0x7aed3c8b00000000, 0x5e343be800000000,\n    0xe33d5d1a00000000, 0xc7e45a7900000000, 0xab8f52dc00000000,\n    0x8f5655bf00000000, 0x909aefe300000000, 0xb443e88000000000,\n    0xd828e02500000000, 0xfcf1e74600000000, 0x41f881b400000000,\n    0x652186d700000000, 0x094a8e7200000000, 0x2d93891100000000,\n    0x37d2fbcb00000000, 0x130bfca800000000, 0x7f60f40d00000000,\n    0x5bb9f36e00000000, 0xe6b0959c00000000, 0xc26992ff00000000,\n    0xae029a5a00000000, 0x8adb9d3900000000, 0x9517276500000000,\n    0xb1ce200600000000, 0xdda528a300000000, 0xf97c2fc000000000,\n    0x4475493200000000, 0x60ac4e5100000000, 0x0cc746f400000000,\n    0x281e419700000000},\n   {0x0000000000000000, 0x08e3603c00000000, 0x10c6c17800000000,\n    0x1825a14400000000, 0x208c83f100000000, 0x286fe3cd00000000,\n    0x304a428900000000, 0x38a922b500000000, 0x011e763800000000,\n    0x09fd160400000000, 0x11d8b74000000000, 0x193bd77c00000000,\n    0x2192f5c900000000, 0x297195f500000000, 0x315434b100000000,\n    0x39b7548d00000000, 0x023cec7000000000, 0x0adf8c4c00000000,\n    0x12fa2d0800000000, 0x1a194d3400000000, 0x22b06f8100000000,\n    0x2a530fbd00000000, 0x3276aef900000000, 0x3a95cec500000000,\n    0x03229a4800000000, 0x0bc1fa7400000000, 0x13e45b3000000000,\n    0x1b073b0c00000000, 0x23ae19b900000000, 0x2b4d798500000000,\n    0x3368d8c100000000, 0x3b8bb8fd00000000, 0x0478d8e100000000,\n    0x0c9bb8dd00000000, 0x14be199900000000, 0x1c5d79a500000000,\n    0x24f45b1000000000, 0x2c173b2c00000000, 0x34329a6800000000,\n    0x3cd1fa5400000000, 0x0566aed900000000, 0x0d85cee500000000,\n    0x15a06fa100000000, 0x1d430f9d00000000, 0x25ea2d2800000000,\n    0x2d094d1400000000, 0x352cec5000000000, 0x3dcf8c6c00000000,\n    0x0644349100000000, 0x0ea754ad00000000, 0x1682f5e900000000,\n    0x1e6195d500000000, 0x26c8b76000000000, 0x2e2bd75c00000000,\n    0x360e761800000000, 0x3eed162400000000, 0x075a42a900000000,\n    0x0fb9229500000000, 0x179c83d100000000, 0x1f7fe3ed00000000,\n    0x27d6c15800000000, 0x2f35a16400000000, 0x3710002000000000,\n    0x3ff3601c00000000, 0x49f6c11800000000, 0x4115a12400000000,\n    0x5930006000000000, 0x51d3605c00000000, 0x697a42e900000000,\n    0x619922d500000000, 0x79bc839100000000, 0x715fe3ad00000000,\n    0x48e8b72000000000, 0x400bd71c00000000, 0x582e765800000000,\n    0x50cd166400000000, 0x686434d100000000, 0x608754ed00000000,\n    0x78a2f5a900000000, 0x7041959500000000, 0x4bca2d6800000000,\n    0x43294d5400000000, 0x5b0cec1000000000, 0x53ef8c2c00000000,\n    0x6b46ae9900000000, 0x63a5cea500000000, 0x7b806fe100000000,\n    0x73630fdd00000000, 0x4ad45b5000000000, 0x42373b6c00000000,\n    0x5a129a2800000000, 0x52f1fa1400000000, 0x6a58d8a100000000,\n    0x62bbb89d00000000, 0x7a9e19d900000000, 0x727d79e500000000,\n    0x4d8e19f900000000, 0x456d79c500000000, 0x5d48d88100000000,\n    0x55abb8bd00000000, 0x6d029a0800000000, 0x65e1fa3400000000,\n    0x7dc45b7000000000, 0x75273b4c00000000, 0x4c906fc100000000,\n    0x44730ffd00000000, 0x5c56aeb900000000, 0x54b5ce8500000000,\n    0x6c1cec3000000000, 0x64ff8c0c00000000, 0x7cda2d4800000000,\n    0x74394d7400000000, 0x4fb2f58900000000, 0x475195b500000000,\n    0x5f7434f100000000, 0x579754cd00000000, 0x6f3e767800000000,\n    0x67dd164400000000, 0x7ff8b70000000000, 0x771bd73c00000000,\n    0x4eac83b100000000, 0x464fe38d00000000, 0x5e6a42c900000000,\n    0x568922f500000000, 0x6e20004000000000, 0x66c3607c00000000,\n    0x7ee6c13800000000, 0x7605a10400000000, 0x92ec833100000000,\n    0x9a0fe30d00000000, 0x822a424900000000, 0x8ac9227500000000,\n    0xb26000c000000000, 0xba8360fc00000000, 0xa2a6c1b800000000,\n    0xaa45a18400000000, 0x93f2f50900000000, 0x9b11953500000000,\n    0x8334347100000000, 0x8bd7544d00000000, 0xb37e76f800000000,\n    0xbb9d16c400000000, 0xa3b8b78000000000, 0xab5bd7bc00000000,\n    0x90d06f4100000000, 0x98330f7d00000000, 0x8016ae3900000000,\n    0x88f5ce0500000000, 0xb05cecb000000000, 0xb8bf8c8c00000000,\n    0xa09a2dc800000000, 0xa8794df400000000, 0x91ce197900000000,\n    0x992d794500000000, 0x8108d80100000000, 0x89ebb83d00000000,\n    0xb1429a8800000000, 0xb9a1fab400000000, 0xa1845bf000000000,\n    0xa9673bcc00000000, 0x96945bd000000000, 0x9e773bec00000000,\n    0x86529aa800000000, 0x8eb1fa9400000000, 0xb618d82100000000,\n    0xbefbb81d00000000, 0xa6de195900000000, 0xae3d796500000000,\n    0x978a2de800000000, 0x9f694dd400000000, 0x874cec9000000000,\n    0x8faf8cac00000000, 0xb706ae1900000000, 0xbfe5ce2500000000,\n    0xa7c06f6100000000, 0xaf230f5d00000000, 0x94a8b7a000000000,\n    0x9c4bd79c00000000, 0x846e76d800000000, 0x8c8d16e400000000,\n    0xb424345100000000, 0xbcc7546d00000000, 0xa4e2f52900000000,\n    0xac01951500000000, 0x95b6c19800000000, 0x9d55a1a400000000,\n    0x857000e000000000, 0x8d9360dc00000000, 0xb53a426900000000,\n    0xbdd9225500000000, 0xa5fc831100000000, 0xad1fe32d00000000,\n    0xdb1a422900000000, 0xd3f9221500000000, 0xcbdc835100000000,\n    0xc33fe36d00000000, 0xfb96c1d800000000, 0xf375a1e400000000,\n    0xeb5000a000000000, 0xe3b3609c00000000, 0xda04341100000000,\n    0xd2e7542d00000000, 0xcac2f56900000000, 0xc221955500000000,\n    0xfa88b7e000000000, 0xf26bd7dc00000000, 0xea4e769800000000,\n    0xe2ad16a400000000, 0xd926ae5900000000, 0xd1c5ce6500000000,\n    0xc9e06f2100000000, 0xc1030f1d00000000, 0xf9aa2da800000000,\n    0xf1494d9400000000, 0xe96cecd000000000, 0xe18f8cec00000000,\n    0xd838d86100000000, 0xd0dbb85d00000000, 0xc8fe191900000000,\n    0xc01d792500000000, 0xf8b45b9000000000, 0xf0573bac00000000,\n    0xe8729ae800000000, 0xe091fad400000000, 0xdf629ac800000000,\n    0xd781faf400000000, 0xcfa45bb000000000, 0xc7473b8c00000000,\n    0xffee193900000000, 0xf70d790500000000, 0xef28d84100000000,\n    0xe7cbb87d00000000, 0xde7cecf000000000, 0xd69f8ccc00000000,\n    0xceba2d8800000000, 0xc6594db400000000, 0xfef06f0100000000,\n    0xf6130f3d00000000, 0xee36ae7900000000, 0xe6d5ce4500000000,\n    0xdd5e76b800000000, 0xd5bd168400000000, 0xcd98b7c000000000,\n    0xc57bd7fc00000000, 0xfdd2f54900000000, 0xf531957500000000,\n    0xed14343100000000, 0xe5f7540d00000000, 0xdc40008000000000,\n    0xd4a360bc00000000, 0xcc86c1f800000000, 0xc465a1c400000000,\n    0xfccc837100000000, 0xf42fe34d00000000, 0xec0a420900000000,\n    0xe4e9223500000000},\n   {0x0000000000000000, 0xd1e8e70e00000000, 0xa2d1cf1d00000000,\n    0x7339281300000000, 0x44a39f3b00000000, 0x954b783500000000,\n    0xe672502600000000, 0x379ab72800000000, 0x88463f7700000000,\n    0x59aed87900000000, 0x2a97f06a00000000, 0xfb7f176400000000,\n    0xcce5a04c00000000, 0x1d0d474200000000, 0x6e346f5100000000,\n    0xbfdc885f00000000, 0x108d7eee00000000, 0xc16599e000000000,\n    0xb25cb1f300000000, 0x63b456fd00000000, 0x542ee1d500000000,\n    0x85c606db00000000, 0xf6ff2ec800000000, 0x2717c9c600000000,\n    0x98cb419900000000, 0x4923a69700000000, 0x3a1a8e8400000000,\n    0xebf2698a00000000, 0xdc68dea200000000, 0x0d8039ac00000000,\n    0x7eb911bf00000000, 0xaf51f6b100000000, 0x611c8c0700000000,\n    0xb0f46b0900000000, 0xc3cd431a00000000, 0x1225a41400000000,\n    0x25bf133c00000000, 0xf457f43200000000, 0x876edc2100000000,\n    0x56863b2f00000000, 0xe95ab37000000000, 0x38b2547e00000000,\n    0x4b8b7c6d00000000, 0x9a639b6300000000, 0xadf92c4b00000000,\n    0x7c11cb4500000000, 0x0f28e35600000000, 0xdec0045800000000,\n    0x7191f2e900000000, 0xa07915e700000000, 0xd3403df400000000,\n    0x02a8dafa00000000, 0x35326dd200000000, 0xe4da8adc00000000,\n    0x97e3a2cf00000000, 0x460b45c100000000, 0xf9d7cd9e00000000,\n    0x283f2a9000000000, 0x5b06028300000000, 0x8aeee58d00000000,\n    0xbd7452a500000000, 0x6c9cb5ab00000000, 0x1fa59db800000000,\n    0xce4d7ab600000000, 0xc238180f00000000, 0x13d0ff0100000000,\n    0x60e9d71200000000, 0xb101301c00000000, 0x869b873400000000,\n    0x5773603a00000000, 0x244a482900000000, 0xf5a2af2700000000,\n    0x4a7e277800000000, 0x9b96c07600000000, 0xe8afe86500000000,\n    0x39470f6b00000000, 0x0eddb84300000000, 0xdf355f4d00000000,\n    0xac0c775e00000000, 0x7de4905000000000, 0xd2b566e100000000,\n    0x035d81ef00000000, 0x7064a9fc00000000, 0xa18c4ef200000000,\n    0x9616f9da00000000, 0x47fe1ed400000000, 0x34c736c700000000,\n    0xe52fd1c900000000, 0x5af3599600000000, 0x8b1bbe9800000000,\n    0xf822968b00000000, 0x29ca718500000000, 0x1e50c6ad00000000,\n    0xcfb821a300000000, 0xbc8109b000000000, 0x6d69eebe00000000,\n    0xa324940800000000, 0x72cc730600000000, 0x01f55b1500000000,\n    0xd01dbc1b00000000, 0xe7870b3300000000, 0x366fec3d00000000,\n    0x4556c42e00000000, 0x94be232000000000, 0x2b62ab7f00000000,\n    0xfa8a4c7100000000, 0x89b3646200000000, 0x585b836c00000000,\n    0x6fc1344400000000, 0xbe29d34a00000000, 0xcd10fb5900000000,\n    0x1cf81c5700000000, 0xb3a9eae600000000, 0x62410de800000000,\n    0x117825fb00000000, 0xc090c2f500000000, 0xf70a75dd00000000,\n    0x26e292d300000000, 0x55dbbac000000000, 0x84335dce00000000,\n    0x3befd59100000000, 0xea07329f00000000, 0x993e1a8c00000000,\n    0x48d6fd8200000000, 0x7f4c4aaa00000000, 0xaea4ada400000000,\n    0xdd9d85b700000000, 0x0c7562b900000000, 0x8471301e00000000,\n    0x5599d71000000000, 0x26a0ff0300000000, 0xf748180d00000000,\n    0xc0d2af2500000000, 0x113a482b00000000, 0x6203603800000000,\n    0xb3eb873600000000, 0x0c370f6900000000, 0xdddfe86700000000,\n    0xaee6c07400000000, 0x7f0e277a00000000, 0x4894905200000000,\n    0x997c775c00000000, 0xea455f4f00000000, 0x3badb84100000000,\n    0x94fc4ef000000000, 0x4514a9fe00000000, 0x362d81ed00000000,\n    0xe7c566e300000000, 0xd05fd1cb00000000, 0x01b736c500000000,\n    0x728e1ed600000000, 0xa366f9d800000000, 0x1cba718700000000,\n    0xcd52968900000000, 0xbe6bbe9a00000000, 0x6f83599400000000,\n    0x5819eebc00000000, 0x89f109b200000000, 0xfac821a100000000,\n    0x2b20c6af00000000, 0xe56dbc1900000000, 0x34855b1700000000,\n    0x47bc730400000000, 0x9654940a00000000, 0xa1ce232200000000,\n    0x7026c42c00000000, 0x031fec3f00000000, 0xd2f70b3100000000,\n    0x6d2b836e00000000, 0xbcc3646000000000, 0xcffa4c7300000000,\n    0x1e12ab7d00000000, 0x29881c5500000000, 0xf860fb5b00000000,\n    0x8b59d34800000000, 0x5ab1344600000000, 0xf5e0c2f700000000,\n    0x240825f900000000, 0x57310dea00000000, 0x86d9eae400000000,\n    0xb1435dcc00000000, 0x60abbac200000000, 0x139292d100000000,\n    0xc27a75df00000000, 0x7da6fd8000000000, 0xac4e1a8e00000000,\n    0xdf77329d00000000, 0x0e9fd59300000000, 0x390562bb00000000,\n    0xe8ed85b500000000, 0x9bd4ada600000000, 0x4a3c4aa800000000,\n    0x4649281100000000, 0x97a1cf1f00000000, 0xe498e70c00000000,\n    0x3570000200000000, 0x02eab72a00000000, 0xd302502400000000,\n    0xa03b783700000000, 0x71d39f3900000000, 0xce0f176600000000,\n    0x1fe7f06800000000, 0x6cded87b00000000, 0xbd363f7500000000,\n    0x8aac885d00000000, 0x5b446f5300000000, 0x287d474000000000,\n    0xf995a04e00000000, 0x56c456ff00000000, 0x872cb1f100000000,\n    0xf41599e200000000, 0x25fd7eec00000000, 0x1267c9c400000000,\n    0xc38f2eca00000000, 0xb0b606d900000000, 0x615ee1d700000000,\n    0xde82698800000000, 0x0f6a8e8600000000, 0x7c53a69500000000,\n    0xadbb419b00000000, 0x9a21f6b300000000, 0x4bc911bd00000000,\n    0x38f039ae00000000, 0xe918dea000000000, 0x2755a41600000000,\n    0xf6bd431800000000, 0x85846b0b00000000, 0x546c8c0500000000,\n    0x63f63b2d00000000, 0xb21edc2300000000, 0xc127f43000000000,\n    0x10cf133e00000000, 0xaf139b6100000000, 0x7efb7c6f00000000,\n    0x0dc2547c00000000, 0xdc2ab37200000000, 0xebb0045a00000000,\n    0x3a58e35400000000, 0x4961cb4700000000, 0x98892c4900000000,\n    0x37d8daf800000000, 0xe6303df600000000, 0x950915e500000000,\n    0x44e1f2eb00000000, 0x737b45c300000000, 0xa293a2cd00000000,\n    0xd1aa8ade00000000, 0x00426dd000000000, 0xbf9ee58f00000000,\n    0x6e76028100000000, 0x1d4f2a9200000000, 0xcca7cd9c00000000,\n    0xfb3d7ab400000000, 0x2ad59dba00000000, 0x59ecb5a900000000,\n    0x880452a700000000},\n   {0x0000000000000000, 0xaa05daf100000000, 0x150dc53800000000,\n    0xbf081fc900000000, 0x2a1a8a7100000000, 0x801f508000000000,\n    0x3f174f4900000000, 0x951295b800000000, 0x543414e300000000,\n    0xfe31ce1200000000, 0x4139d1db00000000, 0xeb3c0b2a00000000,\n    0x7e2e9e9200000000, 0xd42b446300000000, 0x6b235baa00000000,\n    0xc126815b00000000, 0xe96e591d00000000, 0x436b83ec00000000,\n    0xfc639c2500000000, 0x566646d400000000, 0xc374d36c00000000,\n    0x6971099d00000000, 0xd679165400000000, 0x7c7ccca500000000,\n    0xbd5a4dfe00000000, 0x175f970f00000000, 0xa85788c600000000,\n    0x0252523700000000, 0x9740c78f00000000, 0x3d451d7e00000000,\n    0x824d02b700000000, 0x2848d84600000000, 0xd2ddb23a00000000,\n    0x78d868cb00000000, 0xc7d0770200000000, 0x6dd5adf300000000,\n    0xf8c7384b00000000, 0x52c2e2ba00000000, 0xedcafd7300000000,\n    0x47cf278200000000, 0x86e9a6d900000000, 0x2cec7c2800000000,\n    0x93e463e100000000, 0x39e1b91000000000, 0xacf32ca800000000,\n    0x06f6f65900000000, 0xb9fee99000000000, 0x13fb336100000000,\n    0x3bb3eb2700000000, 0x91b631d600000000, 0x2ebe2e1f00000000,\n    0x84bbf4ee00000000, 0x11a9615600000000, 0xbbacbba700000000,\n    0x04a4a46e00000000, 0xaea17e9f00000000, 0x6f87ffc400000000,\n    0xc582253500000000, 0x7a8a3afc00000000, 0xd08fe00d00000000,\n    0x459d75b500000000, 0xef98af4400000000, 0x5090b08d00000000,\n    0xfa956a7c00000000, 0xa4bb657500000000, 0x0ebebf8400000000,\n    0xb1b6a04d00000000, 0x1bb37abc00000000, 0x8ea1ef0400000000,\n    0x24a435f500000000, 0x9bac2a3c00000000, 0x31a9f0cd00000000,\n    0xf08f719600000000, 0x5a8aab6700000000, 0xe582b4ae00000000,\n    0x4f876e5f00000000, 0xda95fbe700000000, 0x7090211600000000,\n    0xcf983edf00000000, 0x659de42e00000000, 0x4dd53c6800000000,\n    0xe7d0e69900000000, 0x58d8f95000000000, 0xf2dd23a100000000,\n    0x67cfb61900000000, 0xcdca6ce800000000, 0x72c2732100000000,\n    0xd8c7a9d000000000, 0x19e1288b00000000, 0xb3e4f27a00000000,\n    0x0cecedb300000000, 0xa6e9374200000000, 0x33fba2fa00000000,\n    0x99fe780b00000000, 0x26f667c200000000, 0x8cf3bd3300000000,\n    0x7666d74f00000000, 0xdc630dbe00000000, 0x636b127700000000,\n    0xc96ec88600000000, 0x5c7c5d3e00000000, 0xf67987cf00000000,\n    0x4971980600000000, 0xe37442f700000000, 0x2252c3ac00000000,\n    0x8857195d00000000, 0x375f069400000000, 0x9d5adc6500000000,\n    0x084849dd00000000, 0xa24d932c00000000, 0x1d458ce500000000,\n    0xb740561400000000, 0x9f088e5200000000, 0x350d54a300000000,\n    0x8a054b6a00000000, 0x2000919b00000000, 0xb512042300000000,\n    0x1f17ded200000000, 0xa01fc11b00000000, 0x0a1a1bea00000000,\n    0xcb3c9ab100000000, 0x6139404000000000, 0xde315f8900000000,\n    0x7434857800000000, 0xe12610c000000000, 0x4b23ca3100000000,\n    0xf42bd5f800000000, 0x5e2e0f0900000000, 0x4877cbea00000000,\n    0xe272111b00000000, 0x5d7a0ed200000000, 0xf77fd42300000000,\n    0x626d419b00000000, 0xc8689b6a00000000, 0x776084a300000000,\n    0xdd655e5200000000, 0x1c43df0900000000, 0xb64605f800000000,\n    0x094e1a3100000000, 0xa34bc0c000000000, 0x3659557800000000,\n    0x9c5c8f8900000000, 0x2354904000000000, 0x89514ab100000000,\n    0xa11992f700000000, 0x0b1c480600000000, 0xb41457cf00000000,\n    0x1e118d3e00000000, 0x8b03188600000000, 0x2106c27700000000,\n    0x9e0eddbe00000000, 0x340b074f00000000, 0xf52d861400000000,\n    0x5f285ce500000000, 0xe020432c00000000, 0x4a2599dd00000000,\n    0xdf370c6500000000, 0x7532d69400000000, 0xca3ac95d00000000,\n    0x603f13ac00000000, 0x9aaa79d000000000, 0x30afa32100000000,\n    0x8fa7bce800000000, 0x25a2661900000000, 0xb0b0f3a100000000,\n    0x1ab5295000000000, 0xa5bd369900000000, 0x0fb8ec6800000000,\n    0xce9e6d3300000000, 0x649bb7c200000000, 0xdb93a80b00000000,\n    0x719672fa00000000, 0xe484e74200000000, 0x4e813db300000000,\n    0xf189227a00000000, 0x5b8cf88b00000000, 0x73c420cd00000000,\n    0xd9c1fa3c00000000, 0x66c9e5f500000000, 0xcccc3f0400000000,\n    0x59deaabc00000000, 0xf3db704d00000000, 0x4cd36f8400000000,\n    0xe6d6b57500000000, 0x27f0342e00000000, 0x8df5eedf00000000,\n    0x32fdf11600000000, 0x98f82be700000000, 0x0deabe5f00000000,\n    0xa7ef64ae00000000, 0x18e77b6700000000, 0xb2e2a19600000000,\n    0xecccae9f00000000, 0x46c9746e00000000, 0xf9c16ba700000000,\n    0x53c4b15600000000, 0xc6d624ee00000000, 0x6cd3fe1f00000000,\n    0xd3dbe1d600000000, 0x79de3b2700000000, 0xb8f8ba7c00000000,\n    0x12fd608d00000000, 0xadf57f4400000000, 0x07f0a5b500000000,\n    0x92e2300d00000000, 0x38e7eafc00000000, 0x87eff53500000000,\n    0x2dea2fc400000000, 0x05a2f78200000000, 0xafa72d7300000000,\n    0x10af32ba00000000, 0xbaaae84b00000000, 0x2fb87df300000000,\n    0x85bda70200000000, 0x3ab5b8cb00000000, 0x90b0623a00000000,\n    0x5196e36100000000, 0xfb93399000000000, 0x449b265900000000,\n    0xee9efca800000000, 0x7b8c691000000000, 0xd189b3e100000000,\n    0x6e81ac2800000000, 0xc48476d900000000, 0x3e111ca500000000,\n    0x9414c65400000000, 0x2b1cd99d00000000, 0x8119036c00000000,\n    0x140b96d400000000, 0xbe0e4c2500000000, 0x010653ec00000000,\n    0xab03891d00000000, 0x6a25084600000000, 0xc020d2b700000000,\n    0x7f28cd7e00000000, 0xd52d178f00000000, 0x403f823700000000,\n    0xea3a58c600000000, 0x5532470f00000000, 0xff379dfe00000000,\n    0xd77f45b800000000, 0x7d7a9f4900000000, 0xc272808000000000,\n    0x68775a7100000000, 0xfd65cfc900000000, 0x5760153800000000,\n    0xe8680af100000000, 0x426dd00000000000, 0x834b515b00000000,\n    0x294e8baa00000000, 0x9646946300000000, 0x3c434e9200000000,\n    0xa951db2a00000000, 0x035401db00000000, 0xbc5c1e1200000000,\n    0x1659c4e300000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xae689191, 0x87a02563, 0x29c8b4f2, 0xd4314c87,\n    0x7a59dd16, 0x539169e4, 0xfdf9f875, 0x73139f4f, 0xdd7b0ede,\n    0xf4b3ba2c, 0x5adb2bbd, 0xa722d3c8, 0x094a4259, 0x2082f6ab,\n    0x8eea673a, 0xe6273e9e, 0x484faf0f, 0x61871bfd, 0xcfef8a6c,\n    0x32167219, 0x9c7ee388, 0xb5b6577a, 0x1bdec6eb, 0x9534a1d1,\n    0x3b5c3040, 0x129484b2, 0xbcfc1523, 0x4105ed56, 0xef6d7cc7,\n    0xc6a5c835, 0x68cd59a4, 0x173f7b7d, 0xb957eaec, 0x909f5e1e,\n    0x3ef7cf8f, 0xc30e37fa, 0x6d66a66b, 0x44ae1299, 0xeac68308,\n    0x642ce432, 0xca4475a3, 0xe38cc151, 0x4de450c0, 0xb01da8b5,\n    0x1e753924, 0x37bd8dd6, 0x99d51c47, 0xf11845e3, 0x5f70d472,\n    0x76b86080, 0xd8d0f111, 0x25290964, 0x8b4198f5, 0xa2892c07,\n    0x0ce1bd96, 0x820bdaac, 0x2c634b3d, 0x05abffcf, 0xabc36e5e,\n    0x563a962b, 0xf85207ba, 0xd19ab348, 0x7ff222d9, 0x2e7ef6fa,\n    0x8016676b, 0xa9ded399, 0x07b64208, 0xfa4fba7d, 0x54272bec,\n    0x7def9f1e, 0xd3870e8f, 0x5d6d69b5, 0xf305f824, 0xdacd4cd6,\n    0x74a5dd47, 0x895c2532, 0x2734b4a3, 0x0efc0051, 0xa09491c0,\n    0xc859c864, 0x663159f5, 0x4ff9ed07, 0xe1917c96, 0x1c6884e3,\n    0xb2001572, 0x9bc8a180, 0x35a03011, 0xbb4a572b, 0x1522c6ba,\n    0x3cea7248, 0x9282e3d9, 0x6f7b1bac, 0xc1138a3d, 0xe8db3ecf,\n    0x46b3af5e, 0x39418d87, 0x97291c16, 0xbee1a8e4, 0x10893975,\n    0xed70c100, 0x43185091, 0x6ad0e463, 0xc4b875f2, 0x4a5212c8,\n    0xe43a8359, 0xcdf237ab, 0x639aa63a, 0x9e635e4f, 0x300bcfde,\n    0x19c37b2c, 0xb7abeabd, 0xdf66b319, 0x710e2288, 0x58c6967a,\n    0xf6ae07eb, 0x0b57ff9e, 0xa53f6e0f, 0x8cf7dafd, 0x229f4b6c,\n    0xac752c56, 0x021dbdc7, 0x2bd50935, 0x85bd98a4, 0x784460d1,\n    0xd62cf140, 0xffe445b2, 0x518cd423, 0x5cfdedf4, 0xf2957c65,\n    0xdb5dc897, 0x75355906, 0x88cca173, 0x26a430e2, 0x0f6c8410,\n    0xa1041581, 0x2fee72bb, 0x8186e32a, 0xa84e57d8, 0x0626c649,\n    0xfbdf3e3c, 0x55b7afad, 0x7c7f1b5f, 0xd2178ace, 0xbadad36a,\n    0x14b242fb, 0x3d7af609, 0x93126798, 0x6eeb9fed, 0xc0830e7c,\n    0xe94bba8e, 0x47232b1f, 0xc9c94c25, 0x67a1ddb4, 0x4e696946,\n    0xe001f8d7, 0x1df800a2, 0xb3909133, 0x9a5825c1, 0x3430b450,\n    0x4bc29689, 0xe5aa0718, 0xcc62b3ea, 0x620a227b, 0x9ff3da0e,\n    0x319b4b9f, 0x1853ff6d, 0xb63b6efc, 0x38d109c6, 0x96b99857,\n    0xbf712ca5, 0x1119bd34, 0xece04541, 0x4288d4d0, 0x6b406022,\n    0xc528f1b3, 0xade5a817, 0x038d3986, 0x2a458d74, 0x842d1ce5,\n    0x79d4e490, 0xd7bc7501, 0xfe74c1f3, 0x501c5062, 0xdef63758,\n    0x709ea6c9, 0x5956123b, 0xf73e83aa, 0x0ac77bdf, 0xa4afea4e,\n    0x8d675ebc, 0x230fcf2d, 0x72831b0e, 0xdceb8a9f, 0xf5233e6d,\n    0x5b4baffc, 0xa6b25789, 0x08dac618, 0x211272ea, 0x8f7ae37b,\n    0x01908441, 0xaff815d0, 0x8630a122, 0x285830b3, 0xd5a1c8c6,\n    0x7bc95957, 0x5201eda5, 0xfc697c34, 0x94a42590, 0x3accb401,\n    0x130400f3, 0xbd6c9162, 0x40956917, 0xeefdf886, 0xc7354c74,\n    0x695ddde5, 0xe7b7badf, 0x49df2b4e, 0x60179fbc, 0xce7f0e2d,\n    0x3386f658, 0x9dee67c9, 0xb426d33b, 0x1a4e42aa, 0x65bc6073,\n    0xcbd4f1e2, 0xe21c4510, 0x4c74d481, 0xb18d2cf4, 0x1fe5bd65,\n    0x362d0997, 0x98459806, 0x16afff3c, 0xb8c76ead, 0x910fda5f,\n    0x3f674bce, 0xc29eb3bb, 0x6cf6222a, 0x453e96d8, 0xeb560749,\n    0x839b5eed, 0x2df3cf7c, 0x043b7b8e, 0xaa53ea1f, 0x57aa126a,\n    0xf9c283fb, 0xd00a3709, 0x7e62a698, 0xf088c1a2, 0x5ee05033,\n    0x7728e4c1, 0xd9407550, 0x24b98d25, 0x8ad11cb4, 0xa319a846,\n    0x0d7139d7},\n   {0x00000000, 0xb9fbdbe8, 0xa886b191, 0x117d6a79, 0x8a7c6563,\n    0x3387be8b, 0x22fad4f2, 0x9b010f1a, 0xcf89cc87, 0x7672176f,\n    0x670f7d16, 0xdef4a6fe, 0x45f5a9e4, 0xfc0e720c, 0xed731875,\n    0x5488c39d, 0x44629f4f, 0xfd9944a7, 0xece42ede, 0x551ff536,\n    0xce1efa2c, 0x77e521c4, 0x66984bbd, 0xdf639055, 0x8beb53c8,\n    0x32108820, 0x236de259, 0x9a9639b1, 0x019736ab, 0xb86ced43,\n    0xa911873a, 0x10ea5cd2, 0x88c53e9e, 0x313ee576, 0x20438f0f,\n    0x99b854e7, 0x02b95bfd, 0xbb428015, 0xaa3fea6c, 0x13c43184,\n    0x474cf219, 0xfeb729f1, 0xefca4388, 0x56319860, 0xcd30977a,\n    0x74cb4c92, 0x65b626eb, 0xdc4dfd03, 0xcca7a1d1, 0x755c7a39,\n    0x64211040, 0xdddacba8, 0x46dbc4b2, 0xff201f5a, 0xee5d7523,\n    0x57a6aecb, 0x032e6d56, 0xbad5b6be, 0xaba8dcc7, 0x1253072f,\n    0x89520835, 0x30a9d3dd, 0x21d4b9a4, 0x982f624c, 0xcafb7b7d,\n    0x7300a095, 0x627dcaec, 0xdb861104, 0x40871e1e, 0xf97cc5f6,\n    0xe801af8f, 0x51fa7467, 0x0572b7fa, 0xbc896c12, 0xadf4066b,\n    0x140fdd83, 0x8f0ed299, 0x36f50971, 0x27886308, 0x9e73b8e0,\n    0x8e99e432, 0x37623fda, 0x261f55a3, 0x9fe48e4b, 0x04e58151,\n    0xbd1e5ab9, 0xac6330c0, 0x1598eb28, 0x411028b5, 0xf8ebf35d,\n    0xe9969924, 0x506d42cc, 0xcb6c4dd6, 0x7297963e, 0x63eafc47,\n    0xda1127af, 0x423e45e3, 0xfbc59e0b, 0xeab8f472, 0x53432f9a,\n    0xc8422080, 0x71b9fb68, 0x60c49111, 0xd93f4af9, 0x8db78964,\n    0x344c528c, 0x253138f5, 0x9ccae31d, 0x07cbec07, 0xbe3037ef,\n    0xaf4d5d96, 0x16b6867e, 0x065cdaac, 0xbfa70144, 0xaeda6b3d,\n    0x1721b0d5, 0x8c20bfcf, 0x35db6427, 0x24a60e5e, 0x9d5dd5b6,\n    0xc9d5162b, 0x702ecdc3, 0x6153a7ba, 0xd8a87c52, 0x43a97348,\n    0xfa52a8a0, 0xeb2fc2d9, 0x52d41931, 0x4e87f0bb, 0xf77c2b53,\n    0xe601412a, 0x5ffa9ac2, 0xc4fb95d8, 0x7d004e30, 0x6c7d2449,\n    0xd586ffa1, 0x810e3c3c, 0x38f5e7d4, 0x29888dad, 0x90735645,\n    0x0b72595f, 0xb28982b7, 0xa3f4e8ce, 0x1a0f3326, 0x0ae56ff4,\n    0xb31eb41c, 0xa263de65, 0x1b98058d, 0x80990a97, 0x3962d17f,\n    0x281fbb06, 0x91e460ee, 0xc56ca373, 0x7c97789b, 0x6dea12e2,\n    0xd411c90a, 0x4f10c610, 0xf6eb1df8, 0xe7967781, 0x5e6dac69,\n    0xc642ce25, 0x7fb915cd, 0x6ec47fb4, 0xd73fa45c, 0x4c3eab46,\n    0xf5c570ae, 0xe4b81ad7, 0x5d43c13f, 0x09cb02a2, 0xb030d94a,\n    0xa14db333, 0x18b668db, 0x83b767c1, 0x3a4cbc29, 0x2b31d650,\n    0x92ca0db8, 0x8220516a, 0x3bdb8a82, 0x2aa6e0fb, 0x935d3b13,\n    0x085c3409, 0xb1a7efe1, 0xa0da8598, 0x19215e70, 0x4da99ded,\n    0xf4524605, 0xe52f2c7c, 0x5cd4f794, 0xc7d5f88e, 0x7e2e2366,\n    0x6f53491f, 0xd6a892f7, 0x847c8bc6, 0x3d87502e, 0x2cfa3a57,\n    0x9501e1bf, 0x0e00eea5, 0xb7fb354d, 0xa6865f34, 0x1f7d84dc,\n    0x4bf54741, 0xf20e9ca9, 0xe373f6d0, 0x5a882d38, 0xc1892222,\n    0x7872f9ca, 0x690f93b3, 0xd0f4485b, 0xc01e1489, 0x79e5cf61,\n    0x6898a518, 0xd1637ef0, 0x4a6271ea, 0xf399aa02, 0xe2e4c07b,\n    0x5b1f1b93, 0x0f97d80e, 0xb66c03e6, 0xa711699f, 0x1eeab277,\n    0x85ebbd6d, 0x3c106685, 0x2d6d0cfc, 0x9496d714, 0x0cb9b558,\n    0xb5426eb0, 0xa43f04c9, 0x1dc4df21, 0x86c5d03b, 0x3f3e0bd3,\n    0x2e4361aa, 0x97b8ba42, 0xc33079df, 0x7acba237, 0x6bb6c84e,\n    0xd24d13a6, 0x494c1cbc, 0xf0b7c754, 0xe1caad2d, 0x583176c5,\n    0x48db2a17, 0xf120f1ff, 0xe05d9b86, 0x59a6406e, 0xc2a74f74,\n    0x7b5c949c, 0x6a21fee5, 0xd3da250d, 0x8752e690, 0x3ea93d78,\n    0x2fd45701, 0x962f8ce9, 0x0d2e83f3, 0xb4d5581b, 0xa5a83262,\n    0x1c53e98a},\n   {0x00000000, 0x9d0fe176, 0xe16ec4ad, 0x7c6125db, 0x19ac8f1b,\n    0x84a36e6d, 0xf8c24bb6, 0x65cdaac0, 0x33591e36, 0xae56ff40,\n    0xd237da9b, 0x4f383bed, 0x2af5912d, 0xb7fa705b, 0xcb9b5580,\n    0x5694b4f6, 0x66b23c6c, 0xfbbddd1a, 0x87dcf8c1, 0x1ad319b7,\n    0x7f1eb377, 0xe2115201, 0x9e7077da, 0x037f96ac, 0x55eb225a,\n    0xc8e4c32c, 0xb485e6f7, 0x298a0781, 0x4c47ad41, 0xd1484c37,\n    0xad2969ec, 0x3026889a, 0xcd6478d8, 0x506b99ae, 0x2c0abc75,\n    0xb1055d03, 0xd4c8f7c3, 0x49c716b5, 0x35a6336e, 0xa8a9d218,\n    0xfe3d66ee, 0x63328798, 0x1f53a243, 0x825c4335, 0xe791e9f5,\n    0x7a9e0883, 0x06ff2d58, 0x9bf0cc2e, 0xabd644b4, 0x36d9a5c2,\n    0x4ab88019, 0xd7b7616f, 0xb27acbaf, 0x2f752ad9, 0x53140f02,\n    0xce1bee74, 0x988f5a82, 0x0580bbf4, 0x79e19e2f, 0xe4ee7f59,\n    0x8123d599, 0x1c2c34ef, 0x604d1134, 0xfd42f042, 0x41b9f7f1,\n    0xdcb61687, 0xa0d7335c, 0x3dd8d22a, 0x581578ea, 0xc51a999c,\n    0xb97bbc47, 0x24745d31, 0x72e0e9c7, 0xefef08b1, 0x938e2d6a,\n    0x0e81cc1c, 0x6b4c66dc, 0xf64387aa, 0x8a22a271, 0x172d4307,\n    0x270bcb9d, 0xba042aeb, 0xc6650f30, 0x5b6aee46, 0x3ea74486,\n    0xa3a8a5f0, 0xdfc9802b, 0x42c6615d, 0x1452d5ab, 0x895d34dd,\n    0xf53c1106, 0x6833f070, 0x0dfe5ab0, 0x90f1bbc6, 0xec909e1d,\n    0x719f7f6b, 0x8cdd8f29, 0x11d26e5f, 0x6db34b84, 0xf0bcaaf2,\n    0x95710032, 0x087ee144, 0x741fc49f, 0xe91025e9, 0xbf84911f,\n    0x228b7069, 0x5eea55b2, 0xc3e5b4c4, 0xa6281e04, 0x3b27ff72,\n    0x4746daa9, 0xda493bdf, 0xea6fb345, 0x77605233, 0x0b0177e8,\n    0x960e969e, 0xf3c33c5e, 0x6eccdd28, 0x12adf8f3, 0x8fa21985,\n    0xd936ad73, 0x44394c05, 0x385869de, 0xa55788a8, 0xc09a2268,\n    0x5d95c31e, 0x21f4e6c5, 0xbcfb07b3, 0x8373efe2, 0x1e7c0e94,\n    0x621d2b4f, 0xff12ca39, 0x9adf60f9, 0x07d0818f, 0x7bb1a454,\n    0xe6be4522, 0xb02af1d4, 0x2d2510a2, 0x51443579, 0xcc4bd40f,\n    0xa9867ecf, 0x34899fb9, 0x48e8ba62, 0xd5e75b14, 0xe5c1d38e,\n    0x78ce32f8, 0x04af1723, 0x99a0f655, 0xfc6d5c95, 0x6162bde3,\n    0x1d039838, 0x800c794e, 0xd698cdb8, 0x4b972cce, 0x37f60915,\n    0xaaf9e863, 0xcf3442a3, 0x523ba3d5, 0x2e5a860e, 0xb3556778,\n    0x4e17973a, 0xd318764c, 0xaf795397, 0x3276b2e1, 0x57bb1821,\n    0xcab4f957, 0xb6d5dc8c, 0x2bda3dfa, 0x7d4e890c, 0xe041687a,\n    0x9c204da1, 0x012facd7, 0x64e20617, 0xf9ede761, 0x858cc2ba,\n    0x188323cc, 0x28a5ab56, 0xb5aa4a20, 0xc9cb6ffb, 0x54c48e8d,\n    0x3109244d, 0xac06c53b, 0xd067e0e0, 0x4d680196, 0x1bfcb560,\n    0x86f35416, 0xfa9271cd, 0x679d90bb, 0x02503a7b, 0x9f5fdb0d,\n    0xe33efed6, 0x7e311fa0, 0xc2ca1813, 0x5fc5f965, 0x23a4dcbe,\n    0xbeab3dc8, 0xdb669708, 0x4669767e, 0x3a0853a5, 0xa707b2d3,\n    0xf1930625, 0x6c9ce753, 0x10fdc288, 0x8df223fe, 0xe83f893e,\n    0x75306848, 0x09514d93, 0x945eace5, 0xa478247f, 0x3977c509,\n    0x4516e0d2, 0xd81901a4, 0xbdd4ab64, 0x20db4a12, 0x5cba6fc9,\n    0xc1b58ebf, 0x97213a49, 0x0a2edb3f, 0x764ffee4, 0xeb401f92,\n    0x8e8db552, 0x13825424, 0x6fe371ff, 0xf2ec9089, 0x0fae60cb,\n    0x92a181bd, 0xeec0a466, 0x73cf4510, 0x1602efd0, 0x8b0d0ea6,\n    0xf76c2b7d, 0x6a63ca0b, 0x3cf77efd, 0xa1f89f8b, 0xdd99ba50,\n    0x40965b26, 0x255bf1e6, 0xb8541090, 0xc435354b, 0x593ad43d,\n    0x691c5ca7, 0xf413bdd1, 0x8872980a, 0x157d797c, 0x70b0d3bc,\n    0xedbf32ca, 0x91de1711, 0x0cd1f667, 0x5a454291, 0xc74aa3e7,\n    0xbb2b863c, 0x2624674a, 0x43e9cd8a, 0xdee62cfc, 0xa2870927,\n    0x3f88e851},\n   {0x00000000, 0xdd96d985, 0x605cb54b, 0xbdca6cce, 0xc0b96a96,\n    0x1d2fb313, 0xa0e5dfdd, 0x7d730658, 0x5a03d36d, 0x87950ae8,\n    0x3a5f6626, 0xe7c9bfa3, 0x9abab9fb, 0x472c607e, 0xfae60cb0,\n    0x2770d535, 0xb407a6da, 0x69917f5f, 0xd45b1391, 0x09cdca14,\n    0x74becc4c, 0xa92815c9, 0x14e27907, 0xc974a082, 0xee0475b7,\n    0x3392ac32, 0x8e58c0fc, 0x53ce1979, 0x2ebd1f21, 0xf32bc6a4,\n    0x4ee1aa6a, 0x937773ef, 0xb37e4bf5, 0x6ee89270, 0xd322febe,\n    0x0eb4273b, 0x73c72163, 0xae51f8e6, 0x139b9428, 0xce0d4dad,\n    0xe97d9898, 0x34eb411d, 0x89212dd3, 0x54b7f456, 0x29c4f20e,\n    0xf4522b8b, 0x49984745, 0x940e9ec0, 0x0779ed2f, 0xdaef34aa,\n    0x67255864, 0xbab381e1, 0xc7c087b9, 0x1a565e3c, 0xa79c32f2,\n    0x7a0aeb77, 0x5d7a3e42, 0x80ece7c7, 0x3d268b09, 0xe0b0528c,\n    0x9dc354d4, 0x40558d51, 0xfd9fe19f, 0x2009381a, 0xbd8d91ab,\n    0x601b482e, 0xddd124e0, 0x0047fd65, 0x7d34fb3d, 0xa0a222b8,\n    0x1d684e76, 0xc0fe97f3, 0xe78e42c6, 0x3a189b43, 0x87d2f78d,\n    0x5a442e08, 0x27372850, 0xfaa1f1d5, 0x476b9d1b, 0x9afd449e,\n    0x098a3771, 0xd41ceef4, 0x69d6823a, 0xb4405bbf, 0xc9335de7,\n    0x14a58462, 0xa96fe8ac, 0x74f93129, 0x5389e41c, 0x8e1f3d99,\n    0x33d55157, 0xee4388d2, 0x93308e8a, 0x4ea6570f, 0xf36c3bc1,\n    0x2efae244, 0x0ef3da5e, 0xd36503db, 0x6eaf6f15, 0xb339b690,\n    0xce4ab0c8, 0x13dc694d, 0xae160583, 0x7380dc06, 0x54f00933,\n    0x8966d0b6, 0x34acbc78, 0xe93a65fd, 0x944963a5, 0x49dfba20,\n    0xf415d6ee, 0x29830f6b, 0xbaf47c84, 0x6762a501, 0xdaa8c9cf,\n    0x073e104a, 0x7a4d1612, 0xa7dbcf97, 0x1a11a359, 0xc7877adc,\n    0xe0f7afe9, 0x3d61766c, 0x80ab1aa2, 0x5d3dc327, 0x204ec57f,\n    0xfdd81cfa, 0x40127034, 0x9d84a9b1, 0xa06a2517, 0x7dfcfc92,\n    0xc036905c, 0x1da049d9, 0x60d34f81, 0xbd459604, 0x008ffaca,\n    0xdd19234f, 0xfa69f67a, 0x27ff2fff, 0x9a354331, 0x47a39ab4,\n    0x3ad09cec, 0xe7464569, 0x5a8c29a7, 0x871af022, 0x146d83cd,\n    0xc9fb5a48, 0x74313686, 0xa9a7ef03, 0xd4d4e95b, 0x094230de,\n    0xb4885c10, 0x691e8595, 0x4e6e50a0, 0x93f88925, 0x2e32e5eb,\n    0xf3a43c6e, 0x8ed73a36, 0x5341e3b3, 0xee8b8f7d, 0x331d56f8,\n    0x13146ee2, 0xce82b767, 0x7348dba9, 0xaede022c, 0xd3ad0474,\n    0x0e3bddf1, 0xb3f1b13f, 0x6e6768ba, 0x4917bd8f, 0x9481640a,\n    0x294b08c4, 0xf4ddd141, 0x89aed719, 0x54380e9c, 0xe9f26252,\n    0x3464bbd7, 0xa713c838, 0x7a8511bd, 0xc74f7d73, 0x1ad9a4f6,\n    0x67aaa2ae, 0xba3c7b2b, 0x07f617e5, 0xda60ce60, 0xfd101b55,\n    0x2086c2d0, 0x9d4cae1e, 0x40da779b, 0x3da971c3, 0xe03fa846,\n    0x5df5c488, 0x80631d0d, 0x1de7b4bc, 0xc0716d39, 0x7dbb01f7,\n    0xa02dd872, 0xdd5ede2a, 0x00c807af, 0xbd026b61, 0x6094b2e4,\n    0x47e467d1, 0x9a72be54, 0x27b8d29a, 0xfa2e0b1f, 0x875d0d47,\n    0x5acbd4c2, 0xe701b80c, 0x3a976189, 0xa9e01266, 0x7476cbe3,\n    0xc9bca72d, 0x142a7ea8, 0x695978f0, 0xb4cfa175, 0x0905cdbb,\n    0xd493143e, 0xf3e3c10b, 0x2e75188e, 0x93bf7440, 0x4e29adc5,\n    0x335aab9d, 0xeecc7218, 0x53061ed6, 0x8e90c753, 0xae99ff49,\n    0x730f26cc, 0xcec54a02, 0x13539387, 0x6e2095df, 0xb3b64c5a,\n    0x0e7c2094, 0xd3eaf911, 0xf49a2c24, 0x290cf5a1, 0x94c6996f,\n    0x495040ea, 0x342346b2, 0xe9b59f37, 0x547ff3f9, 0x89e92a7c,\n    0x1a9e5993, 0xc7088016, 0x7ac2ecd8, 0xa754355d, 0xda273305,\n    0x07b1ea80, 0xba7b864e, 0x67ed5fcb, 0x409d8afe, 0x9d0b537b,\n    0x20c13fb5, 0xfd57e630, 0x8024e068, 0x5db239ed, 0xe0785523,\n    0x3dee8ca6}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0x85d996dd, 0x4bb55c60, 0xce6ccabd, 0x966ab9c0,\n    0x13b32f1d, 0xdddfe5a0, 0x5806737d, 0x6dd3035a, 0xe80a9587,\n    0x26665f3a, 0xa3bfc9e7, 0xfbb9ba9a, 0x7e602c47, 0xb00ce6fa,\n    0x35d57027, 0xdaa607b4, 0x5f7f9169, 0x91135bd4, 0x14cacd09,\n    0x4cccbe74, 0xc91528a9, 0x0779e214, 0x82a074c9, 0xb77504ee,\n    0x32ac9233, 0xfcc0588e, 0x7919ce53, 0x211fbd2e, 0xa4c62bf3,\n    0x6aaae14e, 0xef737793, 0xf54b7eb3, 0x7092e86e, 0xbefe22d3,\n    0x3b27b40e, 0x6321c773, 0xe6f851ae, 0x28949b13, 0xad4d0dce,\n    0x98987de9, 0x1d41eb34, 0xd32d2189, 0x56f4b754, 0x0ef2c429,\n    0x8b2b52f4, 0x45479849, 0xc09e0e94, 0x2fed7907, 0xaa34efda,\n    0x64582567, 0xe181b3ba, 0xb987c0c7, 0x3c5e561a, 0xf2329ca7,\n    0x77eb0a7a, 0x423e7a5d, 0xc7e7ec80, 0x098b263d, 0x8c52b0e0,\n    0xd454c39d, 0x518d5540, 0x9fe19ffd, 0x1a380920, 0xab918dbd,\n    0x2e481b60, 0xe024d1dd, 0x65fd4700, 0x3dfb347d, 0xb822a2a0,\n    0x764e681d, 0xf397fec0, 0xc6428ee7, 0x439b183a, 0x8df7d287,\n    0x082e445a, 0x50283727, 0xd5f1a1fa, 0x1b9d6b47, 0x9e44fd9a,\n    0x71378a09, 0xf4ee1cd4, 0x3a82d669, 0xbf5b40b4, 0xe75d33c9,\n    0x6284a514, 0xace86fa9, 0x2931f974, 0x1ce48953, 0x993d1f8e,\n    0x5751d533, 0xd28843ee, 0x8a8e3093, 0x0f57a64e, 0xc13b6cf3,\n    0x44e2fa2e, 0x5edaf30e, 0xdb0365d3, 0x156faf6e, 0x90b639b3,\n    0xc8b04ace, 0x4d69dc13, 0x830516ae, 0x06dc8073, 0x3309f054,\n    0xb6d06689, 0x78bcac34, 0xfd653ae9, 0xa5634994, 0x20badf49,\n    0xeed615f4, 0x6b0f8329, 0x847cf4ba, 0x01a56267, 0xcfc9a8da,\n    0x4a103e07, 0x12164d7a, 0x97cfdba7, 0x59a3111a, 0xdc7a87c7,\n    0xe9aff7e0, 0x6c76613d, 0xa21aab80, 0x27c33d5d, 0x7fc54e20,\n    0xfa1cd8fd, 0x34701240, 0xb1a9849d, 0x17256aa0, 0x92fcfc7d,\n    0x5c9036c0, 0xd949a01d, 0x814fd360, 0x049645bd, 0xcafa8f00,\n    0x4f2319dd, 0x7af669fa, 0xff2fff27, 0x3143359a, 0xb49aa347,\n    0xec9cd03a, 0x694546e7, 0xa7298c5a, 0x22f01a87, 0xcd836d14,\n    0x485afbc9, 0x86363174, 0x03efa7a9, 0x5be9d4d4, 0xde304209,\n    0x105c88b4, 0x95851e69, 0xa0506e4e, 0x2589f893, 0xebe5322e,\n    0x6e3ca4f3, 0x363ad78e, 0xb3e34153, 0x7d8f8bee, 0xf8561d33,\n    0xe26e1413, 0x67b782ce, 0xa9db4873, 0x2c02deae, 0x7404add3,\n    0xf1dd3b0e, 0x3fb1f1b3, 0xba68676e, 0x8fbd1749, 0x0a648194,\n    0xc4084b29, 0x41d1ddf4, 0x19d7ae89, 0x9c0e3854, 0x5262f2e9,\n    0xd7bb6434, 0x38c813a7, 0xbd11857a, 0x737d4fc7, 0xf6a4d91a,\n    0xaea2aa67, 0x2b7b3cba, 0xe517f607, 0x60ce60da, 0x551b10fd,\n    0xd0c28620, 0x1eae4c9d, 0x9b77da40, 0xc371a93d, 0x46a83fe0,\n    0x88c4f55d, 0x0d1d6380, 0xbcb4e71d, 0x396d71c0, 0xf701bb7d,\n    0x72d82da0, 0x2ade5edd, 0xaf07c800, 0x616b02bd, 0xe4b29460,\n    0xd167e447, 0x54be729a, 0x9ad2b827, 0x1f0b2efa, 0x470d5d87,\n    0xc2d4cb5a, 0x0cb801e7, 0x8961973a, 0x6612e0a9, 0xe3cb7674,\n    0x2da7bcc9, 0xa87e2a14, 0xf0785969, 0x75a1cfb4, 0xbbcd0509,\n    0x3e1493d4, 0x0bc1e3f3, 0x8e18752e, 0x4074bf93, 0xc5ad294e,\n    0x9dab5a33, 0x1872ccee, 0xd61e0653, 0x53c7908e, 0x49ff99ae,\n    0xcc260f73, 0x024ac5ce, 0x87935313, 0xdf95206e, 0x5a4cb6b3,\n    0x94207c0e, 0x11f9ead3, 0x242c9af4, 0xa1f50c29, 0x6f99c694,\n    0xea405049, 0xb2462334, 0x379fb5e9, 0xf9f37f54, 0x7c2ae989,\n    0x93599e1a, 0x168008c7, 0xd8ecc27a, 0x5d3554a7, 0x053327da,\n    0x80eab107, 0x4e867bba, 0xcb5fed67, 0xfe8a9d40, 0x7b530b9d,\n    0xb53fc120, 0x30e657fd, 0x68e02480, 0xed39b25d, 0x235578e0,\n    0xa68cee3d},\n   {0x00000000, 0x76e10f9d, 0xadc46ee1, 0xdb25617c, 0x1b8fac19,\n    0x6d6ea384, 0xb64bc2f8, 0xc0aacd65, 0x361e5933, 0x40ff56ae,\n    0x9bda37d2, 0xed3b384f, 0x2d91f52a, 0x5b70fab7, 0x80559bcb,\n    0xf6b49456, 0x6c3cb266, 0x1addbdfb, 0xc1f8dc87, 0xb719d31a,\n    0x77b31e7f, 0x015211e2, 0xda77709e, 0xac967f03, 0x5a22eb55,\n    0x2cc3e4c8, 0xf7e685b4, 0x81078a29, 0x41ad474c, 0x374c48d1,\n    0xec6929ad, 0x9a882630, 0xd87864cd, 0xae996b50, 0x75bc0a2c,\n    0x035d05b1, 0xc3f7c8d4, 0xb516c749, 0x6e33a635, 0x18d2a9a8,\n    0xee663dfe, 0x98873263, 0x43a2531f, 0x35435c82, 0xf5e991e7,\n    0x83089e7a, 0x582dff06, 0x2eccf09b, 0xb444d6ab, 0xc2a5d936,\n    0x1980b84a, 0x6f61b7d7, 0xafcb7ab2, 0xd92a752f, 0x020f1453,\n    0x74ee1bce, 0x825a8f98, 0xf4bb8005, 0x2f9ee179, 0x597feee4,\n    0x99d52381, 0xef342c1c, 0x34114d60, 0x42f042fd, 0xf1f7b941,\n    0x8716b6dc, 0x5c33d7a0, 0x2ad2d83d, 0xea781558, 0x9c991ac5,\n    0x47bc7bb9, 0x315d7424, 0xc7e9e072, 0xb108efef, 0x6a2d8e93,\n    0x1ccc810e, 0xdc664c6b, 0xaa8743f6, 0x71a2228a, 0x07432d17,\n    0x9dcb0b27, 0xeb2a04ba, 0x300f65c6, 0x46ee6a5b, 0x8644a73e,\n    0xf0a5a8a3, 0x2b80c9df, 0x5d61c642, 0xabd55214, 0xdd345d89,\n    0x06113cf5, 0x70f03368, 0xb05afe0d, 0xc6bbf190, 0x1d9e90ec,\n    0x6b7f9f71, 0x298fdd8c, 0x5f6ed211, 0x844bb36d, 0xf2aabcf0,\n    0x32007195, 0x44e17e08, 0x9fc41f74, 0xe92510e9, 0x1f9184bf,\n    0x69708b22, 0xb255ea5e, 0xc4b4e5c3, 0x041e28a6, 0x72ff273b,\n    0xa9da4647, 0xdf3b49da, 0x45b36fea, 0x33526077, 0xe877010b,\n    0x9e960e96, 0x5e3cc3f3, 0x28ddcc6e, 0xf3f8ad12, 0x8519a28f,\n    0x73ad36d9, 0x054c3944, 0xde695838, 0xa88857a5, 0x68229ac0,\n    0x1ec3955d, 0xc5e6f421, 0xb307fbbc, 0xe2ef7383, 0x940e7c1e,\n    0x4f2b1d62, 0x39ca12ff, 0xf960df9a, 0x8f81d007, 0x54a4b17b,\n    0x2245bee6, 0xd4f12ab0, 0xa210252d, 0x79354451, 0x0fd44bcc,\n    0xcf7e86a9, 0xb99f8934, 0x62bae848, 0x145be7d5, 0x8ed3c1e5,\n    0xf832ce78, 0x2317af04, 0x55f6a099, 0x955c6dfc, 0xe3bd6261,\n    0x3898031d, 0x4e790c80, 0xb8cd98d6, 0xce2c974b, 0x1509f637,\n    0x63e8f9aa, 0xa34234cf, 0xd5a33b52, 0x0e865a2e, 0x786755b3,\n    0x3a97174e, 0x4c7618d3, 0x975379af, 0xe1b27632, 0x2118bb57,\n    0x57f9b4ca, 0x8cdcd5b6, 0xfa3dda2b, 0x0c894e7d, 0x7a6841e0,\n    0xa14d209c, 0xd7ac2f01, 0x1706e264, 0x61e7edf9, 0xbac28c85,\n    0xcc238318, 0x56aba528, 0x204aaab5, 0xfb6fcbc9, 0x8d8ec454,\n    0x4d240931, 0x3bc506ac, 0xe0e067d0, 0x9601684d, 0x60b5fc1b,\n    0x1654f386, 0xcd7192fa, 0xbb909d67, 0x7b3a5002, 0x0ddb5f9f,\n    0xd6fe3ee3, 0xa01f317e, 0x1318cac2, 0x65f9c55f, 0xbedca423,\n    0xc83dabbe, 0x089766db, 0x7e766946, 0xa553083a, 0xd3b207a7,\n    0x250693f1, 0x53e79c6c, 0x88c2fd10, 0xfe23f28d, 0x3e893fe8,\n    0x48683075, 0x934d5109, 0xe5ac5e94, 0x7f2478a4, 0x09c57739,\n    0xd2e01645, 0xa40119d8, 0x64abd4bd, 0x124adb20, 0xc96fba5c,\n    0xbf8eb5c1, 0x493a2197, 0x3fdb2e0a, 0xe4fe4f76, 0x921f40eb,\n    0x52b58d8e, 0x24548213, 0xff71e36f, 0x8990ecf2, 0xcb60ae0f,\n    0xbd81a192, 0x66a4c0ee, 0x1045cf73, 0xd0ef0216, 0xa60e0d8b,\n    0x7d2b6cf7, 0x0bca636a, 0xfd7ef73c, 0x8b9ff8a1, 0x50ba99dd,\n    0x265b9640, 0xe6f15b25, 0x901054b8, 0x4b3535c4, 0x3dd43a59,\n    0xa75c1c69, 0xd1bd13f4, 0x0a987288, 0x7c797d15, 0xbcd3b070,\n    0xca32bfed, 0x1117de91, 0x67f6d10c, 0x9142455a, 0xe7a34ac7,\n    0x3c862bbb, 0x4a672426, 0x8acde943, 0xfc2ce6de, 0x270987a2,\n    0x51e8883f},\n   {0x00000000, 0xe8dbfbb9, 0x91b186a8, 0x796a7d11, 0x63657c8a,\n    0x8bbe8733, 0xf2d4fa22, 0x1a0f019b, 0x87cc89cf, 0x6f177276,\n    0x167d0f67, 0xfea6f4de, 0xe4a9f545, 0x0c720efc, 0x751873ed,\n    0x9dc38854, 0x4f9f6244, 0xa74499fd, 0xde2ee4ec, 0x36f51f55,\n    0x2cfa1ece, 0xc421e577, 0xbd4b9866, 0x559063df, 0xc853eb8b,\n    0x20881032, 0x59e26d23, 0xb139969a, 0xab369701, 0x43ed6cb8,\n    0x3a8711a9, 0xd25cea10, 0x9e3ec588, 0x76e53e31, 0x0f8f4320,\n    0xe754b899, 0xfd5bb902, 0x158042bb, 0x6cea3faa, 0x8431c413,\n    0x19f24c47, 0xf129b7fe, 0x8843caef, 0x60983156, 0x7a9730cd,\n    0x924ccb74, 0xeb26b665, 0x03fd4ddc, 0xd1a1a7cc, 0x397a5c75,\n    0x40102164, 0xa8cbdadd, 0xb2c4db46, 0x5a1f20ff, 0x23755dee,\n    0xcbaea657, 0x566d2e03, 0xbeb6d5ba, 0xc7dca8ab, 0x2f075312,\n    0x35085289, 0xddd3a930, 0xa4b9d421, 0x4c622f98, 0x7d7bfbca,\n    0x95a00073, 0xecca7d62, 0x041186db, 0x1e1e8740, 0xf6c57cf9,\n    0x8faf01e8, 0x6774fa51, 0xfab77205, 0x126c89bc, 0x6b06f4ad,\n    0x83dd0f14, 0x99d20e8f, 0x7109f536, 0x08638827, 0xe0b8739e,\n    0x32e4998e, 0xda3f6237, 0xa3551f26, 0x4b8ee49f, 0x5181e504,\n    0xb95a1ebd, 0xc03063ac, 0x28eb9815, 0xb5281041, 0x5df3ebf8,\n    0x249996e9, 0xcc426d50, 0xd64d6ccb, 0x3e969772, 0x47fcea63,\n    0xaf2711da, 0xe3453e42, 0x0b9ec5fb, 0x72f4b8ea, 0x9a2f4353,\n    0x802042c8, 0x68fbb971, 0x1191c460, 0xf94a3fd9, 0x6489b78d,\n    0x8c524c34, 0xf5383125, 0x1de3ca9c, 0x07eccb07, 0xef3730be,\n    0x965d4daf, 0x7e86b616, 0xacda5c06, 0x4401a7bf, 0x3d6bdaae,\n    0xd5b02117, 0xcfbf208c, 0x2764db35, 0x5e0ea624, 0xb6d55d9d,\n    0x2b16d5c9, 0xc3cd2e70, 0xbaa75361, 0x527ca8d8, 0x4873a943,\n    0xa0a852fa, 0xd9c22feb, 0x3119d452, 0xbbf0874e, 0x532b7cf7,\n    0x2a4101e6, 0xc29afa5f, 0xd895fbc4, 0x304e007d, 0x49247d6c,\n    0xa1ff86d5, 0x3c3c0e81, 0xd4e7f538, 0xad8d8829, 0x45567390,\n    0x5f59720b, 0xb78289b2, 0xcee8f4a3, 0x26330f1a, 0xf46fe50a,\n    0x1cb41eb3, 0x65de63a2, 0x8d05981b, 0x970a9980, 0x7fd16239,\n    0x06bb1f28, 0xee60e491, 0x73a36cc5, 0x9b78977c, 0xe212ea6d,\n    0x0ac911d4, 0x10c6104f, 0xf81debf6, 0x817796e7, 0x69ac6d5e,\n    0x25ce42c6, 0xcd15b97f, 0xb47fc46e, 0x5ca43fd7, 0x46ab3e4c,\n    0xae70c5f5, 0xd71ab8e4, 0x3fc1435d, 0xa202cb09, 0x4ad930b0,\n    0x33b34da1, 0xdb68b618, 0xc167b783, 0x29bc4c3a, 0x50d6312b,\n    0xb80dca92, 0x6a512082, 0x828adb3b, 0xfbe0a62a, 0x133b5d93,\n    0x09345c08, 0xe1efa7b1, 0x9885daa0, 0x705e2119, 0xed9da94d,\n    0x054652f4, 0x7c2c2fe5, 0x94f7d45c, 0x8ef8d5c7, 0x66232e7e,\n    0x1f49536f, 0xf792a8d6, 0xc68b7c84, 0x2e50873d, 0x573afa2c,\n    0xbfe10195, 0xa5ee000e, 0x4d35fbb7, 0x345f86a6, 0xdc847d1f,\n    0x4147f54b, 0xa99c0ef2, 0xd0f673e3, 0x382d885a, 0x222289c1,\n    0xcaf97278, 0xb3930f69, 0x5b48f4d0, 0x89141ec0, 0x61cfe579,\n    0x18a59868, 0xf07e63d1, 0xea71624a, 0x02aa99f3, 0x7bc0e4e2,\n    0x931b1f5b, 0x0ed8970f, 0xe6036cb6, 0x9f6911a7, 0x77b2ea1e,\n    0x6dbdeb85, 0x8566103c, 0xfc0c6d2d, 0x14d79694, 0x58b5b90c,\n    0xb06e42b5, 0xc9043fa4, 0x21dfc41d, 0x3bd0c586, 0xd30b3e3f,\n    0xaa61432e, 0x42bab897, 0xdf7930c3, 0x37a2cb7a, 0x4ec8b66b,\n    0xa6134dd2, 0xbc1c4c49, 0x54c7b7f0, 0x2dadcae1, 0xc5763158,\n    0x172adb48, 0xfff120f1, 0x869b5de0, 0x6e40a659, 0x744fa7c2,\n    0x9c945c7b, 0xe5fe216a, 0x0d25dad3, 0x90e65287, 0x783da93e,\n    0x0157d42f, 0xe98c2f96, 0xf3832e0d, 0x1b58d5b4, 0x6232a8a5,\n    0x8ae9531c},\n   {0x00000000, 0x919168ae, 0x6325a087, 0xf2b4c829, 0x874c31d4,\n    0x16dd597a, 0xe4699153, 0x75f8f9fd, 0x4f9f1373, 0xde0e7bdd,\n    0x2cbab3f4, 0xbd2bdb5a, 0xc8d322a7, 0x59424a09, 0xabf68220,\n    0x3a67ea8e, 0x9e3e27e6, 0x0faf4f48, 0xfd1b8761, 0x6c8aefcf,\n    0x19721632, 0x88e37e9c, 0x7a57b6b5, 0xebc6de1b, 0xd1a13495,\n    0x40305c3b, 0xb2849412, 0x2315fcbc, 0x56ed0541, 0xc77c6def,\n    0x35c8a5c6, 0xa459cd68, 0x7d7b3f17, 0xecea57b9, 0x1e5e9f90,\n    0x8fcff73e, 0xfa370ec3, 0x6ba6666d, 0x9912ae44, 0x0883c6ea,\n    0x32e42c64, 0xa37544ca, 0x51c18ce3, 0xc050e44d, 0xb5a81db0,\n    0x2439751e, 0xd68dbd37, 0x471cd599, 0xe34518f1, 0x72d4705f,\n    0x8060b876, 0x11f1d0d8, 0x64092925, 0xf598418b, 0x072c89a2,\n    0x96bde10c, 0xacda0b82, 0x3d4b632c, 0xcfffab05, 0x5e6ec3ab,\n    0x2b963a56, 0xba0752f8, 0x48b39ad1, 0xd922f27f, 0xfaf67e2e,\n    0x6b671680, 0x99d3dea9, 0x0842b607, 0x7dba4ffa, 0xec2b2754,\n    0x1e9fef7d, 0x8f0e87d3, 0xb5696d5d, 0x24f805f3, 0xd64ccdda,\n    0x47dda574, 0x32255c89, 0xa3b43427, 0x5100fc0e, 0xc09194a0,\n    0x64c859c8, 0xf5593166, 0x07edf94f, 0x967c91e1, 0xe384681c,\n    0x721500b2, 0x80a1c89b, 0x1130a035, 0x2b574abb, 0xbac62215,\n    0x4872ea3c, 0xd9e38292, 0xac1b7b6f, 0x3d8a13c1, 0xcf3edbe8,\n    0x5eafb346, 0x878d4139, 0x161c2997, 0xe4a8e1be, 0x75398910,\n    0x00c170ed, 0x91501843, 0x63e4d06a, 0xf275b8c4, 0xc812524a,\n    0x59833ae4, 0xab37f2cd, 0x3aa69a63, 0x4f5e639e, 0xdecf0b30,\n    0x2c7bc319, 0xbdeaabb7, 0x19b366df, 0x88220e71, 0x7a96c658,\n    0xeb07aef6, 0x9eff570b, 0x0f6e3fa5, 0xfddaf78c, 0x6c4b9f22,\n    0x562c75ac, 0xc7bd1d02, 0x3509d52b, 0xa498bd85, 0xd1604478,\n    0x40f12cd6, 0xb245e4ff, 0x23d48c51, 0xf4edfd5c, 0x657c95f2,\n    0x97c85ddb, 0x06593575, 0x73a1cc88, 0xe230a426, 0x10846c0f,\n    0x811504a1, 0xbb72ee2f, 0x2ae38681, 0xd8574ea8, 0x49c62606,\n    0x3c3edffb, 0xadafb755, 0x5f1b7f7c, 0xce8a17d2, 0x6ad3daba,\n    0xfb42b214, 0x09f67a3d, 0x98671293, 0xed9feb6e, 0x7c0e83c0,\n    0x8eba4be9, 0x1f2b2347, 0x254cc9c9, 0xb4dda167, 0x4669694e,\n    0xd7f801e0, 0xa200f81d, 0x339190b3, 0xc125589a, 0x50b43034,\n    0x8996c24b, 0x1807aae5, 0xeab362cc, 0x7b220a62, 0x0edaf39f,\n    0x9f4b9b31, 0x6dff5318, 0xfc6e3bb6, 0xc609d138, 0x5798b996,\n    0xa52c71bf, 0x34bd1911, 0x4145e0ec, 0xd0d48842, 0x2260406b,\n    0xb3f128c5, 0x17a8e5ad, 0x86398d03, 0x748d452a, 0xe51c2d84,\n    0x90e4d479, 0x0175bcd7, 0xf3c174fe, 0x62501c50, 0x5837f6de,\n    0xc9a69e70, 0x3b125659, 0xaa833ef7, 0xdf7bc70a, 0x4eeaafa4,\n    0xbc5e678d, 0x2dcf0f23, 0x0e1b8372, 0x9f8aebdc, 0x6d3e23f5,\n    0xfcaf4b5b, 0x8957b2a6, 0x18c6da08, 0xea721221, 0x7be37a8f,\n    0x41849001, 0xd015f8af, 0x22a13086, 0xb3305828, 0xc6c8a1d5,\n    0x5759c97b, 0xa5ed0152, 0x347c69fc, 0x9025a494, 0x01b4cc3a,\n    0xf3000413, 0x62916cbd, 0x17699540, 0x86f8fdee, 0x744c35c7,\n    0xe5dd5d69, 0xdfbab7e7, 0x4e2bdf49, 0xbc9f1760, 0x2d0e7fce,\n    0x58f68633, 0xc967ee9d, 0x3bd326b4, 0xaa424e1a, 0x7360bc65,\n    0xe2f1d4cb, 0x10451ce2, 0x81d4744c, 0xf42c8db1, 0x65bde51f,\n    0x97092d36, 0x06984598, 0x3cffaf16, 0xad6ec7b8, 0x5fda0f91,\n    0xce4b673f, 0xbbb39ec2, 0x2a22f66c, 0xd8963e45, 0x490756eb,\n    0xed5e9b83, 0x7ccff32d, 0x8e7b3b04, 0x1fea53aa, 0x6a12aa57,\n    0xfb83c2f9, 0x09370ad0, 0x98a6627e, 0xa2c188f0, 0x3350e05e,\n    0xc1e42877, 0x507540d9, 0x258db924, 0xb41cd18a, 0x46a819a3,\n    0xd739710d}};\n\n#endif\n\n#endif\n\n#if N == 5\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0xaf449247, 0x85f822cf, 0x2abcb088, 0xd08143df,\n    0x7fc5d198, 0x55796110, 0xfa3df357, 0x7a7381ff, 0xd53713b8,\n    0xff8ba330, 0x50cf3177, 0xaaf2c220, 0x05b65067, 0x2f0ae0ef,\n    0x804e72a8, 0xf4e703fe, 0x5ba391b9, 0x711f2131, 0xde5bb376,\n    0x24664021, 0x8b22d266, 0xa19e62ee, 0x0edaf0a9, 0x8e948201,\n    0x21d01046, 0x0b6ca0ce, 0xa4283289, 0x5e15c1de, 0xf1515399,\n    0xdbede311, 0x74a97156, 0x32bf01bd, 0x9dfb93fa, 0xb7472372,\n    0x1803b135, 0xe23e4262, 0x4d7ad025, 0x67c660ad, 0xc882f2ea,\n    0x48cc8042, 0xe7881205, 0xcd34a28d, 0x627030ca, 0x984dc39d,\n    0x370951da, 0x1db5e152, 0xb2f17315, 0xc6580243, 0x691c9004,\n    0x43a0208c, 0xece4b2cb, 0x16d9419c, 0xb99dd3db, 0x93216353,\n    0x3c65f114, 0xbc2b83bc, 0x136f11fb, 0x39d3a173, 0x96973334,\n    0x6caac063, 0xc3ee5224, 0xe952e2ac, 0x461670eb, 0x657e037a,\n    0xca3a913d, 0xe08621b5, 0x4fc2b3f2, 0xb5ff40a5, 0x1abbd2e2,\n    0x3007626a, 0x9f43f02d, 0x1f0d8285, 0xb04910c2, 0x9af5a04a,\n    0x35b1320d, 0xcf8cc15a, 0x60c8531d, 0x4a74e395, 0xe53071d2,\n    0x91990084, 0x3edd92c3, 0x1461224b, 0xbb25b00c, 0x4118435b,\n    0xee5cd11c, 0xc4e06194, 0x6ba4f3d3, 0xebea817b, 0x44ae133c,\n    0x6e12a3b4, 0xc15631f3, 0x3b6bc2a4, 0x942f50e3, 0xbe93e06b,\n    0x11d7722c, 0x57c102c7, 0xf8859080, 0xd2392008, 0x7d7db24f,\n    0x87404118, 0x2804d35f, 0x02b863d7, 0xadfcf190, 0x2db28338,\n    0x82f6117f, 0xa84aa1f7, 0x070e33b0, 0xfd33c0e7, 0x527752a0,\n    0x78cbe228, 0xd78f706f, 0xa3260139, 0x0c62937e, 0x26de23f6,\n    0x899ab1b1, 0x73a742e6, 0xdce3d0a1, 0xf65f6029, 0x591bf26e,\n    0xd95580c6, 0x76111281, 0x5cada209, 0xf3e9304e, 0x09d4c319,\n    0xa690515e, 0x8c2ce1d6, 0x23687391, 0xcafc06f4, 0x65b894b3,\n    0x4f04243b, 0xe040b67c, 0x1a7d452b, 0xb539d76c, 0x9f8567e4,\n    0x30c1f5a3, 0xb08f870b, 0x1fcb154c, 0x3577a5c4, 0x9a333783,\n    0x600ec4d4, 0xcf4a5693, 0xe5f6e61b, 0x4ab2745c, 0x3e1b050a,\n    0x915f974d, 0xbbe327c5, 0x14a7b582, 0xee9a46d5, 0x41ded492,\n    0x6b62641a, 0xc426f65d, 0x446884f5, 0xeb2c16b2, 0xc190a63a,\n    0x6ed4347d, 0x94e9c72a, 0x3bad556d, 0x1111e5e5, 0xbe5577a2,\n    0xf8430749, 0x5707950e, 0x7dbb2586, 0xd2ffb7c1, 0x28c24496,\n    0x8786d6d1, 0xad3a6659, 0x027ef41e, 0x823086b6, 0x2d7414f1,\n    0x07c8a479, 0xa88c363e, 0x52b1c569, 0xfdf5572e, 0xd749e7a6,\n    0x780d75e1, 0x0ca404b7, 0xa3e096f0, 0x895c2678, 0x2618b43f,\n    0xdc254768, 0x7361d52f, 0x59dd65a7, 0xf699f7e0, 0x76d78548,\n    0xd993170f, 0xf32fa787, 0x5c6b35c0, 0xa656c697, 0x091254d0,\n    0x23aee458, 0x8cea761f, 0xaf82058e, 0x00c697c9, 0x2a7a2741,\n    0x853eb506, 0x7f034651, 0xd047d416, 0xfafb649e, 0x55bff6d9,\n    0xd5f18471, 0x7ab51636, 0x5009a6be, 0xff4d34f9, 0x0570c7ae,\n    0xaa3455e9, 0x8088e561, 0x2fcc7726, 0x5b650670, 0xf4219437,\n    0xde9d24bf, 0x71d9b6f8, 0x8be445af, 0x24a0d7e8, 0x0e1c6760,\n    0xa158f527, 0x2116878f, 0x8e5215c8, 0xa4eea540, 0x0baa3707,\n    0xf197c450, 0x5ed35617, 0x746fe69f, 0xdb2b74d8, 0x9d3d0433,\n    0x32799674, 0x18c526fc, 0xb781b4bb, 0x4dbc47ec, 0xe2f8d5ab,\n    0xc8446523, 0x6700f764, 0xe74e85cc, 0x480a178b, 0x62b6a703,\n    0xcdf23544, 0x37cfc613, 0x988b5454, 0xb237e4dc, 0x1d73769b,\n    0x69da07cd, 0xc69e958a, 0xec222502, 0x4366b745, 0xb95b4412,\n    0x161fd655, 0x3ca366dd, 0x93e7f49a, 0x13a98632, 0xbced1475,\n    0x9651a4fd, 0x391536ba, 0xc328c5ed, 0x6c6c57aa, 0x46d0e722,\n    0xe9947565},\n   {0x00000000, 0x4e890ba9, 0x9d121752, 0xd39b1cfb, 0xe15528e5,\n    0xafdc234c, 0x7c473fb7, 0x32ce341e, 0x19db578b, 0x57525c22,\n    0x84c940d9, 0xca404b70, 0xf88e7f6e, 0xb60774c7, 0x659c683c,\n    0x2b156395, 0x33b6af16, 0x7d3fa4bf, 0xaea4b844, 0xe02db3ed,\n    0xd2e387f3, 0x9c6a8c5a, 0x4ff190a1, 0x01789b08, 0x2a6df89d,\n    0x64e4f334, 0xb77fefcf, 0xf9f6e466, 0xcb38d078, 0x85b1dbd1,\n    0x562ac72a, 0x18a3cc83, 0x676d5e2c, 0x29e45585, 0xfa7f497e,\n    0xb4f642d7, 0x863876c9, 0xc8b17d60, 0x1b2a619b, 0x55a36a32,\n    0x7eb609a7, 0x303f020e, 0xe3a41ef5, 0xad2d155c, 0x9fe32142,\n    0xd16a2aeb, 0x02f13610, 0x4c783db9, 0x54dbf13a, 0x1a52fa93,\n    0xc9c9e668, 0x8740edc1, 0xb58ed9df, 0xfb07d276, 0x289cce8d,\n    0x6615c524, 0x4d00a6b1, 0x0389ad18, 0xd012b1e3, 0x9e9bba4a,\n    0xac558e54, 0xe2dc85fd, 0x31479906, 0x7fce92af, 0xcedabc58,\n    0x8053b7f1, 0x53c8ab0a, 0x1d41a0a3, 0x2f8f94bd, 0x61069f14,\n    0xb29d83ef, 0xfc148846, 0xd701ebd3, 0x9988e07a, 0x4a13fc81,\n    0x049af728, 0x3654c336, 0x78ddc89f, 0xab46d464, 0xe5cfdfcd,\n    0xfd6c134e, 0xb3e518e7, 0x607e041c, 0x2ef70fb5, 0x1c393bab,\n    0x52b03002, 0x812b2cf9, 0xcfa22750, 0xe4b744c5, 0xaa3e4f6c,\n    0x79a55397, 0x372c583e, 0x05e26c20, 0x4b6b6789, 0x98f07b72,\n    0xd67970db, 0xa9b7e274, 0xe73ee9dd, 0x34a5f526, 0x7a2cfe8f,\n    0x48e2ca91, 0x066bc138, 0xd5f0ddc3, 0x9b79d66a, 0xb06cb5ff,\n    0xfee5be56, 0x2d7ea2ad, 0x63f7a904, 0x51399d1a, 0x1fb096b3,\n    0xcc2b8a48, 0x82a281e1, 0x9a014d62, 0xd48846cb, 0x07135a30,\n    0x499a5199, 0x7b546587, 0x35dd6e2e, 0xe64672d5, 0xa8cf797c,\n    0x83da1ae9, 0xcd531140, 0x1ec80dbb, 0x50410612, 0x628f320c,\n    0x2c0639a5, 0xff9d255e, 0xb1142ef7, 0x46c47ef1, 0x084d7558,\n    0xdbd669a3, 0x955f620a, 0xa7915614, 0xe9185dbd, 0x3a834146,\n    0x740a4aef, 0x5f1f297a, 0x119622d3, 0xc20d3e28, 0x8c843581,\n    0xbe4a019f, 0xf0c30a36, 0x235816cd, 0x6dd11d64, 0x7572d1e7,\n    0x3bfbda4e, 0xe860c6b5, 0xa6e9cd1c, 0x9427f902, 0xdaaef2ab,\n    0x0935ee50, 0x47bce5f9, 0x6ca9866c, 0x22208dc5, 0xf1bb913e,\n    0xbf329a97, 0x8dfcae89, 0xc375a520, 0x10eeb9db, 0x5e67b272,\n    0x21a920dd, 0x6f202b74, 0xbcbb378f, 0xf2323c26, 0xc0fc0838,\n    0x8e750391, 0x5dee1f6a, 0x136714c3, 0x38727756, 0x76fb7cff,\n    0xa5606004, 0xebe96bad, 0xd9275fb3, 0x97ae541a, 0x443548e1,\n    0x0abc4348, 0x121f8fcb, 0x5c968462, 0x8f0d9899, 0xc1849330,\n    0xf34aa72e, 0xbdc3ac87, 0x6e58b07c, 0x20d1bbd5, 0x0bc4d840,\n    0x454dd3e9, 0x96d6cf12, 0xd85fc4bb, 0xea91f0a5, 0xa418fb0c,\n    0x7783e7f7, 0x390aec5e, 0x881ec2a9, 0xc697c900, 0x150cd5fb,\n    0x5b85de52, 0x694bea4c, 0x27c2e1e5, 0xf459fd1e, 0xbad0f6b7,\n    0x91c59522, 0xdf4c9e8b, 0x0cd78270, 0x425e89d9, 0x7090bdc7,\n    0x3e19b66e, 0xed82aa95, 0xa30ba13c, 0xbba86dbf, 0xf5216616,\n    0x26ba7aed, 0x68337144, 0x5afd455a, 0x14744ef3, 0xc7ef5208,\n    0x896659a1, 0xa2733a34, 0xecfa319d, 0x3f612d66, 0x71e826cf,\n    0x432612d1, 0x0daf1978, 0xde340583, 0x90bd0e2a, 0xef739c85,\n    0xa1fa972c, 0x72618bd7, 0x3ce8807e, 0x0e26b460, 0x40afbfc9,\n    0x9334a332, 0xddbda89b, 0xf6a8cb0e, 0xb821c0a7, 0x6bbadc5c,\n    0x2533d7f5, 0x17fde3eb, 0x5974e842, 0x8aeff4b9, 0xc466ff10,\n    0xdcc53393, 0x924c383a, 0x41d724c1, 0x0f5e2f68, 0x3d901b76,\n    0x731910df, 0xa0820c24, 0xee0b078d, 0xc51e6418, 0x8b976fb1,\n    0x580c734a, 0x168578e3, 0x244b4cfd, 0x6ac24754, 0xb9595baf,\n    0xf7d05006},\n   {0x00000000, 0x8d88fde2, 0xc060fd85, 0x4de80067, 0x5bb0fd4b,\n    0xd63800a9, 0x9bd000ce, 0x1658fd2c, 0xb761fa96, 0x3ae90774,\n    0x77010713, 0xfa89faf1, 0xecd107dd, 0x6159fa3f, 0x2cb1fa58,\n    0xa13907ba, 0xb5b2f36d, 0x383a0e8f, 0x75d20ee8, 0xf85af30a,\n    0xee020e26, 0x638af3c4, 0x2e62f3a3, 0xa3ea0e41, 0x02d309fb,\n    0x8f5bf419, 0xc2b3f47e, 0x4f3b099c, 0x5963f4b0, 0xd4eb0952,\n    0x99030935, 0x148bf4d7, 0xb014e09b, 0x3d9c1d79, 0x70741d1e,\n    0xfdfce0fc, 0xeba41dd0, 0x662ce032, 0x2bc4e055, 0xa64c1db7,\n    0x07751a0d, 0x8afde7ef, 0xc715e788, 0x4a9d1a6a, 0x5cc5e746,\n    0xd14d1aa4, 0x9ca51ac3, 0x112de721, 0x05a613f6, 0x882eee14,\n    0xc5c6ee73, 0x484e1391, 0x5e16eebd, 0xd39e135f, 0x9e761338,\n    0x13feeeda, 0xb2c7e960, 0x3f4f1482, 0x72a714e5, 0xff2fe907,\n    0xe977142b, 0x64ffe9c9, 0x2917e9ae, 0xa49f144c, 0xbb58c777,\n    0x36d03a95, 0x7b383af2, 0xf6b0c710, 0xe0e83a3c, 0x6d60c7de,\n    0x2088c7b9, 0xad003a5b, 0x0c393de1, 0x81b1c003, 0xcc59c064,\n    0x41d13d86, 0x5789c0aa, 0xda013d48, 0x97e93d2f, 0x1a61c0cd,\n    0x0eea341a, 0x8362c9f8, 0xce8ac99f, 0x4302347d, 0x555ac951,\n    0xd8d234b3, 0x953a34d4, 0x18b2c936, 0xb98bce8c, 0x3403336e,\n    0x79eb3309, 0xf463ceeb, 0xe23b33c7, 0x6fb3ce25, 0x225bce42,\n    0xafd333a0, 0x0b4c27ec, 0x86c4da0e, 0xcb2cda69, 0x46a4278b,\n    0x50fcdaa7, 0xdd742745, 0x909c2722, 0x1d14dac0, 0xbc2ddd7a,\n    0x31a52098, 0x7c4d20ff, 0xf1c5dd1d, 0xe79d2031, 0x6a15ddd3,\n    0x27fdddb4, 0xaa752056, 0xbefed481, 0x33762963, 0x7e9e2904,\n    0xf316d4e6, 0xe54e29ca, 0x68c6d428, 0x252ed44f, 0xa8a629ad,\n    0x099f2e17, 0x8417d3f5, 0xc9ffd392, 0x44772e70, 0x522fd35c,\n    0xdfa72ebe, 0x924f2ed9, 0x1fc7d33b, 0xadc088af, 0x2048754d,\n    0x6da0752a, 0xe02888c8, 0xf67075e4, 0x7bf88806, 0x36108861,\n    0xbb987583, 0x1aa17239, 0x97298fdb, 0xdac18fbc, 0x5749725e,\n    0x41118f72, 0xcc997290, 0x817172f7, 0x0cf98f15, 0x18727bc2,\n    0x95fa8620, 0xd8128647, 0x559a7ba5, 0x43c28689, 0xce4a7b6b,\n    0x83a27b0c, 0x0e2a86ee, 0xaf138154, 0x229b7cb6, 0x6f737cd1,\n    0xe2fb8133, 0xf4a37c1f, 0x792b81fd, 0x34c3819a, 0xb94b7c78,\n    0x1dd46834, 0x905c95d6, 0xddb495b1, 0x503c6853, 0x4664957f,\n    0xcbec689d, 0x860468fa, 0x0b8c9518, 0xaab592a2, 0x273d6f40,\n    0x6ad56f27, 0xe75d92c5, 0xf1056fe9, 0x7c8d920b, 0x3165926c,\n    0xbced6f8e, 0xa8669b59, 0x25ee66bb, 0x680666dc, 0xe58e9b3e,\n    0xf3d66612, 0x7e5e9bf0, 0x33b69b97, 0xbe3e6675, 0x1f0761cf,\n    0x928f9c2d, 0xdf679c4a, 0x52ef61a8, 0x44b79c84, 0xc93f6166,\n    0x84d76101, 0x095f9ce3, 0x16984fd8, 0x9b10b23a, 0xd6f8b25d,\n    0x5b704fbf, 0x4d28b293, 0xc0a04f71, 0x8d484f16, 0x00c0b2f4,\n    0xa1f9b54e, 0x2c7148ac, 0x619948cb, 0xec11b529, 0xfa494805,\n    0x77c1b5e7, 0x3a29b580, 0xb7a14862, 0xa32abcb5, 0x2ea24157,\n    0x634a4130, 0xeec2bcd2, 0xf89a41fe, 0x7512bc1c, 0x38fabc7b,\n    0xb5724199, 0x144b4623, 0x99c3bbc1, 0xd42bbba6, 0x59a34644,\n    0x4ffbbb68, 0xc273468a, 0x8f9b46ed, 0x0213bb0f, 0xa68caf43,\n    0x2b0452a1, 0x66ec52c6, 0xeb64af24, 0xfd3c5208, 0x70b4afea,\n    0x3d5caf8d, 0xb0d4526f, 0x11ed55d5, 0x9c65a837, 0xd18da850,\n    0x5c0555b2, 0x4a5da89e, 0xc7d5557c, 0x8a3d551b, 0x07b5a8f9,\n    0x133e5c2e, 0x9eb6a1cc, 0xd35ea1ab, 0x5ed65c49, 0x488ea165,\n    0xc5065c87, 0x88ee5ce0, 0x0566a102, 0xa45fa6b8, 0x29d75b5a,\n    0x643f5b3d, 0xe9b7a6df, 0xffef5bf3, 0x7267a611, 0x3f8fa676,\n    0xb2075b94},\n   {0x00000000, 0x80f0171f, 0xda91287f, 0x5a613f60, 0x6e5356bf,\n    0xeea341a0, 0xb4c27ec0, 0x343269df, 0xdca6ad7e, 0x5c56ba61,\n    0x06378501, 0x86c7921e, 0xb2f5fbc1, 0x3205ecde, 0x6864d3be,\n    0xe894c4a1, 0x623c5cbd, 0xe2cc4ba2, 0xb8ad74c2, 0x385d63dd,\n    0x0c6f0a02, 0x8c9f1d1d, 0xd6fe227d, 0x560e3562, 0xbe9af1c3,\n    0x3e6ae6dc, 0x640bd9bc, 0xe4fbcea3, 0xd0c9a77c, 0x5039b063,\n    0x0a588f03, 0x8aa8981c, 0xc478b97a, 0x4488ae65, 0x1ee99105,\n    0x9e19861a, 0xaa2befc5, 0x2adbf8da, 0x70bac7ba, 0xf04ad0a5,\n    0x18de1404, 0x982e031b, 0xc24f3c7b, 0x42bf2b64, 0x768d42bb,\n    0xf67d55a4, 0xac1c6ac4, 0x2cec7ddb, 0xa644e5c7, 0x26b4f2d8,\n    0x7cd5cdb8, 0xfc25daa7, 0xc817b378, 0x48e7a467, 0x12869b07,\n    0x92768c18, 0x7ae248b9, 0xfa125fa6, 0xa07360c6, 0x208377d9,\n    0x14b11e06, 0x94410919, 0xce203679, 0x4ed02166, 0x538074b5,\n    0xd37063aa, 0x89115cca, 0x09e14bd5, 0x3dd3220a, 0xbd233515,\n    0xe7420a75, 0x67b21d6a, 0x8f26d9cb, 0x0fd6ced4, 0x55b7f1b4,\n    0xd547e6ab, 0xe1758f74, 0x6185986b, 0x3be4a70b, 0xbb14b014,\n    0x31bc2808, 0xb14c3f17, 0xeb2d0077, 0x6bdd1768, 0x5fef7eb7,\n    0xdf1f69a8, 0x857e56c8, 0x058e41d7, 0xed1a8576, 0x6dea9269,\n    0x378bad09, 0xb77bba16, 0x8349d3c9, 0x03b9c4d6, 0x59d8fbb6,\n    0xd928eca9, 0x97f8cdcf, 0x1708dad0, 0x4d69e5b0, 0xcd99f2af,\n    0xf9ab9b70, 0x795b8c6f, 0x233ab30f, 0xa3caa410, 0x4b5e60b1,\n    0xcbae77ae, 0x91cf48ce, 0x113f5fd1, 0x250d360e, 0xa5fd2111,\n    0xff9c1e71, 0x7f6c096e, 0xf5c49172, 0x7534866d, 0x2f55b90d,\n    0xafa5ae12, 0x9b97c7cd, 0x1b67d0d2, 0x4106efb2, 0xc1f6f8ad,\n    0x29623c0c, 0xa9922b13, 0xf3f31473, 0x7303036c, 0x47316ab3,\n    0xc7c17dac, 0x9da042cc, 0x1d5055d3, 0xa700e96a, 0x27f0fe75,\n    0x7d91c115, 0xfd61d60a, 0xc953bfd5, 0x49a3a8ca, 0x13c297aa,\n    0x933280b5, 0x7ba64414, 0xfb56530b, 0xa1376c6b, 0x21c77b74,\n    0x15f512ab, 0x950505b4, 0xcf643ad4, 0x4f942dcb, 0xc53cb5d7,\n    0x45cca2c8, 0x1fad9da8, 0x9f5d8ab7, 0xab6fe368, 0x2b9ff477,\n    0x71fecb17, 0xf10edc08, 0x199a18a9, 0x996a0fb6, 0xc30b30d6,\n    0x43fb27c9, 0x77c94e16, 0xf7395909, 0xad586669, 0x2da87176,\n    0x63785010, 0xe388470f, 0xb9e9786f, 0x39196f70, 0x0d2b06af,\n    0x8ddb11b0, 0xd7ba2ed0, 0x574a39cf, 0xbfdefd6e, 0x3f2eea71,\n    0x654fd511, 0xe5bfc20e, 0xd18dabd1, 0x517dbcce, 0x0b1c83ae,\n    0x8bec94b1, 0x01440cad, 0x81b41bb2, 0xdbd524d2, 0x5b2533cd,\n    0x6f175a12, 0xefe74d0d, 0xb586726d, 0x35766572, 0xdde2a1d3,\n    0x5d12b6cc, 0x077389ac, 0x87839eb3, 0xb3b1f76c, 0x3341e073,\n    0x6920df13, 0xe9d0c80c, 0xf4809ddf, 0x74708ac0, 0x2e11b5a0,\n    0xaee1a2bf, 0x9ad3cb60, 0x1a23dc7f, 0x4042e31f, 0xc0b2f400,\n    0x282630a1, 0xa8d627be, 0xf2b718de, 0x72470fc1, 0x4675661e,\n    0xc6857101, 0x9ce44e61, 0x1c14597e, 0x96bcc162, 0x164cd67d,\n    0x4c2de91d, 0xccddfe02, 0xf8ef97dd, 0x781f80c2, 0x227ebfa2,\n    0xa28ea8bd, 0x4a1a6c1c, 0xcaea7b03, 0x908b4463, 0x107b537c,\n    0x24493aa3, 0xa4b92dbc, 0xfed812dc, 0x7e2805c3, 0x30f824a5,\n    0xb00833ba, 0xea690cda, 0x6a991bc5, 0x5eab721a, 0xde5b6505,\n    0x843a5a65, 0x04ca4d7a, 0xec5e89db, 0x6cae9ec4, 0x36cfa1a4,\n    0xb63fb6bb, 0x820ddf64, 0x02fdc87b, 0x589cf71b, 0xd86ce004,\n    0x52c47818, 0xd2346f07, 0x88555067, 0x08a54778, 0x3c972ea7,\n    0xbc6739b8, 0xe60606d8, 0x66f611c7, 0x8e62d566, 0x0e92c279,\n    0x54f3fd19, 0xd403ea06, 0xe03183d9, 0x60c194c6, 0x3aa0aba6,\n    0xba50bcb9},\n   {0x00000000, 0x9570d495, 0xf190af6b, 0x64e07bfe, 0x38505897,\n    0xad208c02, 0xc9c0f7fc, 0x5cb02369, 0x70a0b12e, 0xe5d065bb,\n    0x81301e45, 0x1440cad0, 0x48f0e9b9, 0xdd803d2c, 0xb96046d2,\n    0x2c109247, 0xe141625c, 0x7431b6c9, 0x10d1cd37, 0x85a119a2,\n    0xd9113acb, 0x4c61ee5e, 0x288195a0, 0xbdf14135, 0x91e1d372,\n    0x049107e7, 0x60717c19, 0xf501a88c, 0xa9b18be5, 0x3cc15f70,\n    0x5821248e, 0xcd51f01b, 0x19f3c2f9, 0x8c83166c, 0xe8636d92,\n    0x7d13b907, 0x21a39a6e, 0xb4d34efb, 0xd0333505, 0x4543e190,\n    0x695373d7, 0xfc23a742, 0x98c3dcbc, 0x0db30829, 0x51032b40,\n    0xc473ffd5, 0xa093842b, 0x35e350be, 0xf8b2a0a5, 0x6dc27430,\n    0x09220fce, 0x9c52db5b, 0xc0e2f832, 0x55922ca7, 0x31725759,\n    0xa40283cc, 0x8812118b, 0x1d62c51e, 0x7982bee0, 0xecf26a75,\n    0xb042491c, 0x25329d89, 0x41d2e677, 0xd4a232e2, 0x33e785f2,\n    0xa6975167, 0xc2772a99, 0x5707fe0c, 0x0bb7dd65, 0x9ec709f0,\n    0xfa27720e, 0x6f57a69b, 0x434734dc, 0xd637e049, 0xb2d79bb7,\n    0x27a74f22, 0x7b176c4b, 0xee67b8de, 0x8a87c320, 0x1ff717b5,\n    0xd2a6e7ae, 0x47d6333b, 0x233648c5, 0xb6469c50, 0xeaf6bf39,\n    0x7f866bac, 0x1b661052, 0x8e16c4c7, 0xa2065680, 0x37768215,\n    0x5396f9eb, 0xc6e62d7e, 0x9a560e17, 0x0f26da82, 0x6bc6a17c,\n    0xfeb675e9, 0x2a14470b, 0xbf64939e, 0xdb84e860, 0x4ef43cf5,\n    0x12441f9c, 0x8734cb09, 0xe3d4b0f7, 0x76a46462, 0x5ab4f625,\n    0xcfc422b0, 0xab24594e, 0x3e548ddb, 0x62e4aeb2, 0xf7947a27,\n    0x937401d9, 0x0604d54c, 0xcb552557, 0x5e25f1c2, 0x3ac58a3c,\n    0xafb55ea9, 0xf3057dc0, 0x6675a955, 0x0295d2ab, 0x97e5063e,\n    0xbbf59479, 0x2e8540ec, 0x4a653b12, 0xdf15ef87, 0x83a5ccee,\n    0x16d5187b, 0x72356385, 0xe745b710, 0x67cf0be4, 0xf2bfdf71,\n    0x965fa48f, 0x032f701a, 0x5f9f5373, 0xcaef87e6, 0xae0ffc18,\n    0x3b7f288d, 0x176fbaca, 0x821f6e5f, 0xe6ff15a1, 0x738fc134,\n    0x2f3fe25d, 0xba4f36c8, 0xdeaf4d36, 0x4bdf99a3, 0x868e69b8,\n    0x13febd2d, 0x771ec6d3, 0xe26e1246, 0xbede312f, 0x2baee5ba,\n    0x4f4e9e44, 0xda3e4ad1, 0xf62ed896, 0x635e0c03, 0x07be77fd,\n    0x92cea368, 0xce7e8001, 0x5b0e5494, 0x3fee2f6a, 0xaa9efbff,\n    0x7e3cc91d, 0xeb4c1d88, 0x8fac6676, 0x1adcb2e3, 0x466c918a,\n    0xd31c451f, 0xb7fc3ee1, 0x228cea74, 0x0e9c7833, 0x9becaca6,\n    0xff0cd758, 0x6a7c03cd, 0x36cc20a4, 0xa3bcf431, 0xc75c8fcf,\n    0x522c5b5a, 0x9f7dab41, 0x0a0d7fd4, 0x6eed042a, 0xfb9dd0bf,\n    0xa72df3d6, 0x325d2743, 0x56bd5cbd, 0xc3cd8828, 0xefdd1a6f,\n    0x7aadcefa, 0x1e4db504, 0x8b3d6191, 0xd78d42f8, 0x42fd966d,\n    0x261ded93, 0xb36d3906, 0x54288e16, 0xc1585a83, 0xa5b8217d,\n    0x30c8f5e8, 0x6c78d681, 0xf9080214, 0x9de879ea, 0x0898ad7f,\n    0x24883f38, 0xb1f8ebad, 0xd5189053, 0x406844c6, 0x1cd867af,\n    0x89a8b33a, 0xed48c8c4, 0x78381c51, 0xb569ec4a, 0x201938df,\n    0x44f94321, 0xd18997b4, 0x8d39b4dd, 0x18496048, 0x7ca91bb6,\n    0xe9d9cf23, 0xc5c95d64, 0x50b989f1, 0x3459f20f, 0xa129269a,\n    0xfd9905f3, 0x68e9d166, 0x0c09aa98, 0x99797e0d, 0x4ddb4cef,\n    0xd8ab987a, 0xbc4be384, 0x293b3711, 0x758b1478, 0xe0fbc0ed,\n    0x841bbb13, 0x116b6f86, 0x3d7bfdc1, 0xa80b2954, 0xcceb52aa,\n    0x599b863f, 0x052ba556, 0x905b71c3, 0xf4bb0a3d, 0x61cbdea8,\n    0xac9a2eb3, 0x39eafa26, 0x5d0a81d8, 0xc87a554d, 0x94ca7624,\n    0x01baa2b1, 0x655ad94f, 0xf02a0dda, 0xdc3a9f9d, 0x494a4b08,\n    0x2daa30f6, 0xb8dae463, 0xe46ac70a, 0x711a139f, 0x15fa6861,\n    0x808abcf4},\n   {0x00000000, 0xcf9e17c8, 0x444d29d1, 0x8bd33e19, 0x889a53a2,\n    0x4704446a, 0xccd77a73, 0x03496dbb, 0xca45a105, 0x05dbb6cd,\n    0x8e0888d4, 0x41969f1c, 0x42dff2a7, 0x8d41e56f, 0x0692db76,\n    0xc90cccbe, 0x4ffa444b, 0x80645383, 0x0bb76d9a, 0xc4297a52,\n    0xc76017e9, 0x08fe0021, 0x832d3e38, 0x4cb329f0, 0x85bfe54e,\n    0x4a21f286, 0xc1f2cc9f, 0x0e6cdb57, 0x0d25b6ec, 0xc2bba124,\n    0x49689f3d, 0x86f688f5, 0x9ff48896, 0x506a9f5e, 0xdbb9a147,\n    0x1427b68f, 0x176edb34, 0xd8f0ccfc, 0x5323f2e5, 0x9cbde52d,\n    0x55b12993, 0x9a2f3e5b, 0x11fc0042, 0xde62178a, 0xdd2b7a31,\n    0x12b56df9, 0x996653e0, 0x56f84428, 0xd00eccdd, 0x1f90db15,\n    0x9443e50c, 0x5bddf2c4, 0x58949f7f, 0x970a88b7, 0x1cd9b6ae,\n    0xd347a166, 0x1a4b6dd8, 0xd5d57a10, 0x5e064409, 0x919853c1,\n    0x92d13e7a, 0x5d4f29b2, 0xd69c17ab, 0x19020063, 0xe498176d,\n    0x2b0600a5, 0xa0d53ebc, 0x6f4b2974, 0x6c0244cf, 0xa39c5307,\n    0x284f6d1e, 0xe7d17ad6, 0x2eddb668, 0xe143a1a0, 0x6a909fb9,\n    0xa50e8871, 0xa647e5ca, 0x69d9f202, 0xe20acc1b, 0x2d94dbd3,\n    0xab625326, 0x64fc44ee, 0xef2f7af7, 0x20b16d3f, 0x23f80084,\n    0xec66174c, 0x67b52955, 0xa82b3e9d, 0x6127f223, 0xaeb9e5eb,\n    0x256adbf2, 0xeaf4cc3a, 0xe9bda181, 0x2623b649, 0xadf08850,\n    0x626e9f98, 0x7b6c9ffb, 0xb4f28833, 0x3f21b62a, 0xf0bfa1e2,\n    0xf3f6cc59, 0x3c68db91, 0xb7bbe588, 0x7825f240, 0xb1293efe,\n    0x7eb72936, 0xf564172f, 0x3afa00e7, 0x39b36d5c, 0xf62d7a94,\n    0x7dfe448d, 0xb2605345, 0x3496dbb0, 0xfb08cc78, 0x70dbf261,\n    0xbf45e5a9, 0xbc0c8812, 0x73929fda, 0xf841a1c3, 0x37dfb60b,\n    0xfed37ab5, 0x314d6d7d, 0xba9e5364, 0x750044ac, 0x76492917,\n    0xb9d73edf, 0x320400c6, 0xfd9a170e, 0x1241289b, 0xdddf3f53,\n    0x560c014a, 0x99921682, 0x9adb7b39, 0x55456cf1, 0xde9652e8,\n    0x11084520, 0xd804899e, 0x179a9e56, 0x9c49a04f, 0x53d7b787,\n    0x509eda3c, 0x9f00cdf4, 0x14d3f3ed, 0xdb4de425, 0x5dbb6cd0,\n    0x92257b18, 0x19f64501, 0xd66852c9, 0xd5213f72, 0x1abf28ba,\n    0x916c16a3, 0x5ef2016b, 0x97fecdd5, 0x5860da1d, 0xd3b3e404,\n    0x1c2df3cc, 0x1f649e77, 0xd0fa89bf, 0x5b29b7a6, 0x94b7a06e,\n    0x8db5a00d, 0x422bb7c5, 0xc9f889dc, 0x06669e14, 0x052ff3af,\n    0xcab1e467, 0x4162da7e, 0x8efccdb6, 0x47f00108, 0x886e16c0,\n    0x03bd28d9, 0xcc233f11, 0xcf6a52aa, 0x00f44562, 0x8b277b7b,\n    0x44b96cb3, 0xc24fe446, 0x0dd1f38e, 0x8602cd97, 0x499cda5f,\n    0x4ad5b7e4, 0x854ba02c, 0x0e989e35, 0xc10689fd, 0x080a4543,\n    0xc794528b, 0x4c476c92, 0x83d97b5a, 0x809016e1, 0x4f0e0129,\n    0xc4dd3f30, 0x0b4328f8, 0xf6d93ff6, 0x3947283e, 0xb2941627,\n    0x7d0a01ef, 0x7e436c54, 0xb1dd7b9c, 0x3a0e4585, 0xf590524d,\n    0x3c9c9ef3, 0xf302893b, 0x78d1b722, 0xb74fa0ea, 0xb406cd51,\n    0x7b98da99, 0xf04be480, 0x3fd5f348, 0xb9237bbd, 0x76bd6c75,\n    0xfd6e526c, 0x32f045a4, 0x31b9281f, 0xfe273fd7, 0x75f401ce,\n    0xba6a1606, 0x7366dab8, 0xbcf8cd70, 0x372bf369, 0xf8b5e4a1,\n    0xfbfc891a, 0x34629ed2, 0xbfb1a0cb, 0x702fb703, 0x692db760,\n    0xa6b3a0a8, 0x2d609eb1, 0xe2fe8979, 0xe1b7e4c2, 0x2e29f30a,\n    0xa5facd13, 0x6a64dadb, 0xa3681665, 0x6cf601ad, 0xe7253fb4,\n    0x28bb287c, 0x2bf245c7, 0xe46c520f, 0x6fbf6c16, 0xa0217bde,\n    0x26d7f32b, 0xe949e4e3, 0x629adafa, 0xad04cd32, 0xae4da089,\n    0x61d3b741, 0xea008958, 0x259e9e90, 0xec92522e, 0x230c45e6,\n    0xa8df7bff, 0x67416c37, 0x6408018c, 0xab961644, 0x2045285d,\n    0xefdb3f95},\n   {0x00000000, 0x24825136, 0x4904a26c, 0x6d86f35a, 0x920944d8,\n    0xb68b15ee, 0xdb0de6b4, 0xff8fb782, 0xff638ff1, 0xdbe1dec7,\n    0xb6672d9d, 0x92e57cab, 0x6d6acb29, 0x49e89a1f, 0x246e6945,\n    0x00ec3873, 0x25b619a3, 0x01344895, 0x6cb2bbcf, 0x4830eaf9,\n    0xb7bf5d7b, 0x933d0c4d, 0xfebbff17, 0xda39ae21, 0xdad59652,\n    0xfe57c764, 0x93d1343e, 0xb7536508, 0x48dcd28a, 0x6c5e83bc,\n    0x01d870e6, 0x255a21d0, 0x4b6c3346, 0x6fee6270, 0x0268912a,\n    0x26eac01c, 0xd965779e, 0xfde726a8, 0x9061d5f2, 0xb4e384c4,\n    0xb40fbcb7, 0x908ded81, 0xfd0b1edb, 0xd9894fed, 0x2606f86f,\n    0x0284a959, 0x6f025a03, 0x4b800b35, 0x6eda2ae5, 0x4a587bd3,\n    0x27de8889, 0x035cd9bf, 0xfcd36e3d, 0xd8513f0b, 0xb5d7cc51,\n    0x91559d67, 0x91b9a514, 0xb53bf422, 0xd8bd0778, 0xfc3f564e,\n    0x03b0e1cc, 0x2732b0fa, 0x4ab443a0, 0x6e361296, 0x96d8668c,\n    0xb25a37ba, 0xdfdcc4e0, 0xfb5e95d6, 0x04d12254, 0x20537362,\n    0x4dd58038, 0x6957d10e, 0x69bbe97d, 0x4d39b84b, 0x20bf4b11,\n    0x043d1a27, 0xfbb2ada5, 0xdf30fc93, 0xb2b60fc9, 0x96345eff,\n    0xb36e7f2f, 0x97ec2e19, 0xfa6add43, 0xdee88c75, 0x21673bf7,\n    0x05e56ac1, 0x6863999b, 0x4ce1c8ad, 0x4c0df0de, 0x688fa1e8,\n    0x050952b2, 0x218b0384, 0xde04b406, 0xfa86e530, 0x9700166a,\n    0xb382475c, 0xddb455ca, 0xf93604fc, 0x94b0f7a6, 0xb032a690,\n    0x4fbd1112, 0x6b3f4024, 0x06b9b37e, 0x223be248, 0x22d7da3b,\n    0x06558b0d, 0x6bd37857, 0x4f512961, 0xb0de9ee3, 0x945ccfd5,\n    0xf9da3c8f, 0xdd586db9, 0xf8024c69, 0xdc801d5f, 0xb106ee05,\n    0x9584bf33, 0x6a0b08b1, 0x4e895987, 0x230faadd, 0x078dfbeb,\n    0x0761c398, 0x23e392ae, 0x4e6561f4, 0x6ae730c2, 0x95688740,\n    0xb1ead676, 0xdc6c252c, 0xf8ee741a, 0xf6c1cb59, 0xd2439a6f,\n    0xbfc56935, 0x9b473803, 0x64c88f81, 0x404adeb7, 0x2dcc2ded,\n    0x094e7cdb, 0x09a244a8, 0x2d20159e, 0x40a6e6c4, 0x6424b7f2,\n    0x9bab0070, 0xbf295146, 0xd2afa21c, 0xf62df32a, 0xd377d2fa,\n    0xf7f583cc, 0x9a737096, 0xbef121a0, 0x417e9622, 0x65fcc714,\n    0x087a344e, 0x2cf86578, 0x2c145d0b, 0x08960c3d, 0x6510ff67,\n    0x4192ae51, 0xbe1d19d3, 0x9a9f48e5, 0xf719bbbf, 0xd39bea89,\n    0xbdadf81f, 0x992fa929, 0xf4a95a73, 0xd02b0b45, 0x2fa4bcc7,\n    0x0b26edf1, 0x66a01eab, 0x42224f9d, 0x42ce77ee, 0x664c26d8,\n    0x0bcad582, 0x2f4884b4, 0xd0c73336, 0xf4456200, 0x99c3915a,\n    0xbd41c06c, 0x981be1bc, 0xbc99b08a, 0xd11f43d0, 0xf59d12e6,\n    0x0a12a564, 0x2e90f452, 0x43160708, 0x6794563e, 0x67786e4d,\n    0x43fa3f7b, 0x2e7ccc21, 0x0afe9d17, 0xf5712a95, 0xd1f37ba3,\n    0xbc7588f9, 0x98f7d9cf, 0x6019add5, 0x449bfce3, 0x291d0fb9,\n    0x0d9f5e8f, 0xf210e90d, 0xd692b83b, 0xbb144b61, 0x9f961a57,\n    0x9f7a2224, 0xbbf87312, 0xd67e8048, 0xf2fcd17e, 0x0d7366fc,\n    0x29f137ca, 0x4477c490, 0x60f595a6, 0x45afb476, 0x612de540,\n    0x0cab161a, 0x2829472c, 0xd7a6f0ae, 0xf324a198, 0x9ea252c2,\n    0xba2003f4, 0xbacc3b87, 0x9e4e6ab1, 0xf3c899eb, 0xd74ac8dd,\n    0x28c57f5f, 0x0c472e69, 0x61c1dd33, 0x45438c05, 0x2b759e93,\n    0x0ff7cfa5, 0x62713cff, 0x46f36dc9, 0xb97cda4b, 0x9dfe8b7d,\n    0xf0787827, 0xd4fa2911, 0xd4161162, 0xf0944054, 0x9d12b30e,\n    0xb990e238, 0x461f55ba, 0x629d048c, 0x0f1bf7d6, 0x2b99a6e0,\n    0x0ec38730, 0x2a41d606, 0x47c7255c, 0x6345746a, 0x9ccac3e8,\n    0xb84892de, 0xd5ce6184, 0xf14c30b2, 0xf1a008c1, 0xd52259f7,\n    0xb8a4aaad, 0x9c26fb9b, 0x63a94c19, 0x472b1d2f, 0x2aadee75,\n    0x0e2fbf43},\n   {0x00000000, 0x36f290f3, 0x6de521e6, 0x5b17b115, 0xdbca43cc,\n    0xed38d33f, 0xb62f622a, 0x80ddf2d9, 0x6ce581d9, 0x5a17112a,\n    0x0100a03f, 0x37f230cc, 0xb72fc215, 0x81dd52e6, 0xdacae3f3,\n    0xec387300, 0xd9cb03b2, 0xef399341, 0xb42e2254, 0x82dcb2a7,\n    0x0201407e, 0x34f3d08d, 0x6fe46198, 0x5916f16b, 0xb52e826b,\n    0x83dc1298, 0xd8cba38d, 0xee39337e, 0x6ee4c1a7, 0x58165154,\n    0x0301e041, 0x35f370b2, 0x68e70125, 0x5e1591d6, 0x050220c3,\n    0x33f0b030, 0xb32d42e9, 0x85dfd21a, 0xdec8630f, 0xe83af3fc,\n    0x040280fc, 0x32f0100f, 0x69e7a11a, 0x5f1531e9, 0xdfc8c330,\n    0xe93a53c3, 0xb22de2d6, 0x84df7225, 0xb12c0297, 0x87de9264,\n    0xdcc92371, 0xea3bb382, 0x6ae6415b, 0x5c14d1a8, 0x070360bd,\n    0x31f1f04e, 0xddc9834e, 0xeb3b13bd, 0xb02ca2a8, 0x86de325b,\n    0x0603c082, 0x30f15071, 0x6be6e164, 0x5d147197, 0xd1ce024a,\n    0xe73c92b9, 0xbc2b23ac, 0x8ad9b35f, 0x0a044186, 0x3cf6d175,\n    0x67e16060, 0x5113f093, 0xbd2b8393, 0x8bd91360, 0xd0cea275,\n    0xe63c3286, 0x66e1c05f, 0x501350ac, 0x0b04e1b9, 0x3df6714a,\n    0x080501f8, 0x3ef7910b, 0x65e0201e, 0x5312b0ed, 0xd3cf4234,\n    0xe53dd2c7, 0xbe2a63d2, 0x88d8f321, 0x64e08021, 0x521210d2,\n    0x0905a1c7, 0x3ff73134, 0xbf2ac3ed, 0x89d8531e, 0xd2cfe20b,\n    0xe43d72f8, 0xb929036f, 0x8fdb939c, 0xd4cc2289, 0xe23eb27a,\n    0x62e340a3, 0x5411d050, 0x0f066145, 0x39f4f1b6, 0xd5cc82b6,\n    0xe33e1245, 0xb829a350, 0x8edb33a3, 0x0e06c17a, 0x38f45189,\n    0x63e3e09c, 0x5511706f, 0x60e200dd, 0x5610902e, 0x0d07213b,\n    0x3bf5b1c8, 0xbb284311, 0x8ddad3e2, 0xd6cd62f7, 0xe03ff204,\n    0x0c078104, 0x3af511f7, 0x61e2a0e2, 0x57103011, 0xd7cdc2c8,\n    0xe13f523b, 0xba28e32e, 0x8cda73dd, 0x78ed02d5, 0x4e1f9226,\n    0x15082333, 0x23fab3c0, 0xa3274119, 0x95d5d1ea, 0xcec260ff,\n    0xf830f00c, 0x1408830c, 0x22fa13ff, 0x79eda2ea, 0x4f1f3219,\n    0xcfc2c0c0, 0xf9305033, 0xa227e126, 0x94d571d5, 0xa1260167,\n    0x97d49194, 0xccc32081, 0xfa31b072, 0x7aec42ab, 0x4c1ed258,\n    0x1709634d, 0x21fbf3be, 0xcdc380be, 0xfb31104d, 0xa026a158,\n    0x96d431ab, 0x1609c372, 0x20fb5381, 0x7bece294, 0x4d1e7267,\n    0x100a03f0, 0x26f89303, 0x7def2216, 0x4b1db2e5, 0xcbc0403c,\n    0xfd32d0cf, 0xa62561da, 0x90d7f129, 0x7cef8229, 0x4a1d12da,\n    0x110aa3cf, 0x27f8333c, 0xa725c1e5, 0x91d75116, 0xcac0e003,\n    0xfc3270f0, 0xc9c10042, 0xff3390b1, 0xa42421a4, 0x92d6b157,\n    0x120b438e, 0x24f9d37d, 0x7fee6268, 0x491cf29b, 0xa524819b,\n    0x93d61168, 0xc8c1a07d, 0xfe33308e, 0x7eeec257, 0x481c52a4,\n    0x130be3b1, 0x25f97342, 0xa923009f, 0x9fd1906c, 0xc4c62179,\n    0xf234b18a, 0x72e94353, 0x441bd3a0, 0x1f0c62b5, 0x29fef246,\n    0xc5c68146, 0xf33411b5, 0xa823a0a0, 0x9ed13053, 0x1e0cc28a,\n    0x28fe5279, 0x73e9e36c, 0x451b739f, 0x70e8032d, 0x461a93de,\n    0x1d0d22cb, 0x2bffb238, 0xab2240e1, 0x9dd0d012, 0xc6c76107,\n    0xf035f1f4, 0x1c0d82f4, 0x2aff1207, 0x71e8a312, 0x471a33e1,\n    0xc7c7c138, 0xf13551cb, 0xaa22e0de, 0x9cd0702d, 0xc1c401ba,\n    0xf7369149, 0xac21205c, 0x9ad3b0af, 0x1a0e4276, 0x2cfcd285,\n    0x77eb6390, 0x4119f363, 0xad218063, 0x9bd31090, 0xc0c4a185,\n    0xf6363176, 0x76ebc3af, 0x4019535c, 0x1b0ee249, 0x2dfc72ba,\n    0x180f0208, 0x2efd92fb, 0x75ea23ee, 0x4318b31d, 0xc3c541c4,\n    0xf537d137, 0xae206022, 0x98d2f0d1, 0x74ea83d1, 0x42181322,\n    0x190fa237, 0x2ffd32c4, 0xaf20c01d, 0x99d250ee, 0xc2c5e1fb,\n    0xf4377108}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0xf390f23600000000, 0xe621e56d00000000,\n    0x15b1175b00000000, 0xcc43cadb00000000, 0x3fd338ed00000000,\n    0x2a622fb600000000, 0xd9f2dd8000000000, 0xd981e56c00000000,\n    0x2a11175a00000000, 0x3fa0000100000000, 0xcc30f23700000000,\n    0x15c22fb700000000, 0xe652dd8100000000, 0xf3e3cada00000000,\n    0x007338ec00000000, 0xb203cbd900000000, 0x419339ef00000000,\n    0x54222eb400000000, 0xa7b2dc8200000000, 0x7e40010200000000,\n    0x8dd0f33400000000, 0x9861e46f00000000, 0x6bf1165900000000,\n    0x6b822eb500000000, 0x9812dc8300000000, 0x8da3cbd800000000,\n    0x7e3339ee00000000, 0xa7c1e46e00000000, 0x5451165800000000,\n    0x41e0010300000000, 0xb270f33500000000, 0x2501e76800000000,\n    0xd691155e00000000, 0xc320020500000000, 0x30b0f03300000000,\n    0xe9422db300000000, 0x1ad2df8500000000, 0x0f63c8de00000000,\n    0xfcf33ae800000000, 0xfc80020400000000, 0x0f10f03200000000,\n    0x1aa1e76900000000, 0xe931155f00000000, 0x30c3c8df00000000,\n    0xc3533ae900000000, 0xd6e22db200000000, 0x2572df8400000000,\n    0x97022cb100000000, 0x6492de8700000000, 0x7123c9dc00000000,\n    0x82b33bea00000000, 0x5b41e66a00000000, 0xa8d1145c00000000,\n    0xbd60030700000000, 0x4ef0f13100000000, 0x4e83c9dd00000000,\n    0xbd133beb00000000, 0xa8a22cb000000000, 0x5b32de8600000000,\n    0x82c0030600000000, 0x7150f13000000000, 0x64e1e66b00000000,\n    0x9771145d00000000, 0x4a02ced100000000, 0xb9923ce700000000,\n    0xac232bbc00000000, 0x5fb3d98a00000000, 0x8641040a00000000,\n    0x75d1f63c00000000, 0x6060e16700000000, 0x93f0135100000000,\n    0x93832bbd00000000, 0x6013d98b00000000, 0x75a2ced000000000,\n    0x86323ce600000000, 0x5fc0e16600000000, 0xac50135000000000,\n    0xb9e1040b00000000, 0x4a71f63d00000000, 0xf801050800000000,\n    0x0b91f73e00000000, 0x1e20e06500000000, 0xedb0125300000000,\n    0x3442cfd300000000, 0xc7d23de500000000, 0xd2632abe00000000,\n    0x21f3d88800000000, 0x2180e06400000000, 0xd210125200000000,\n    0xc7a1050900000000, 0x3431f73f00000000, 0xedc32abf00000000,\n    0x1e53d88900000000, 0x0be2cfd200000000, 0xf8723de400000000,\n    0x6f0329b900000000, 0x9c93db8f00000000, 0x8922ccd400000000,\n    0x7ab23ee200000000, 0xa340e36200000000, 0x50d0115400000000,\n    0x4561060f00000000, 0xb6f1f43900000000, 0xb682ccd500000000,\n    0x45123ee300000000, 0x50a329b800000000, 0xa333db8e00000000,\n    0x7ac1060e00000000, 0x8951f43800000000, 0x9ce0e36300000000,\n    0x6f70115500000000, 0xdd00e26000000000, 0x2e90105600000000,\n    0x3b21070d00000000, 0xc8b1f53b00000000, 0x114328bb00000000,\n    0xe2d3da8d00000000, 0xf762cdd600000000, 0x04f23fe000000000,\n    0x0481070c00000000, 0xf711f53a00000000, 0xe2a0e26100000000,\n    0x1130105700000000, 0xc8c2cdd700000000, 0x3b523fe100000000,\n    0x2ee328ba00000000, 0xdd73da8c00000000, 0xd502ed7800000000,\n    0x26921f4e00000000, 0x3323081500000000, 0xc0b3fa2300000000,\n    0x194127a300000000, 0xead1d59500000000, 0xff60c2ce00000000,\n    0x0cf030f800000000, 0x0c83081400000000, 0xff13fa2200000000,\n    0xeaa2ed7900000000, 0x19321f4f00000000, 0xc0c0c2cf00000000,\n    0x335030f900000000, 0x26e127a200000000, 0xd571d59400000000,\n    0x670126a100000000, 0x9491d49700000000, 0x8120c3cc00000000,\n    0x72b031fa00000000, 0xab42ec7a00000000, 0x58d21e4c00000000,\n    0x4d63091700000000, 0xbef3fb2100000000, 0xbe80c3cd00000000,\n    0x4d1031fb00000000, 0x58a126a000000000, 0xab31d49600000000,\n    0x72c3091600000000, 0x8153fb2000000000, 0x94e2ec7b00000000,\n    0x67721e4d00000000, 0xf0030a1000000000, 0x0393f82600000000,\n    0x1622ef7d00000000, 0xe5b21d4b00000000, 0x3c40c0cb00000000,\n    0xcfd032fd00000000, 0xda6125a600000000, 0x29f1d79000000000,\n    0x2982ef7c00000000, 0xda121d4a00000000, 0xcfa30a1100000000,\n    0x3c33f82700000000, 0xe5c125a700000000, 0x1651d79100000000,\n    0x03e0c0ca00000000, 0xf07032fc00000000, 0x4200c1c900000000,\n    0xb19033ff00000000, 0xa42124a400000000, 0x57b1d69200000000,\n    0x8e430b1200000000, 0x7dd3f92400000000, 0x6862ee7f00000000,\n    0x9bf21c4900000000, 0x9b8124a500000000, 0x6811d69300000000,\n    0x7da0c1c800000000, 0x8e3033fe00000000, 0x57c2ee7e00000000,\n    0xa4521c4800000000, 0xb1e30b1300000000, 0x4273f92500000000,\n    0x9f0023a900000000, 0x6c90d19f00000000, 0x7921c6c400000000,\n    0x8ab134f200000000, 0x5343e97200000000, 0xa0d31b4400000000,\n    0xb5620c1f00000000, 0x46f2fe2900000000, 0x4681c6c500000000,\n    0xb51134f300000000, 0xa0a023a800000000, 0x5330d19e00000000,\n    0x8ac20c1e00000000, 0x7952fe2800000000, 0x6ce3e97300000000,\n    0x9f731b4500000000, 0x2d03e87000000000, 0xde931a4600000000,\n    0xcb220d1d00000000, 0x38b2ff2b00000000, 0xe14022ab00000000,\n    0x12d0d09d00000000, 0x0761c7c600000000, 0xf4f135f000000000,\n    0xf4820d1c00000000, 0x0712ff2a00000000, 0x12a3e87100000000,\n    0xe1331a4700000000, 0x38c1c7c700000000, 0xcb5135f100000000,\n    0xdee022aa00000000, 0x2d70d09c00000000, 0xba01c4c100000000,\n    0x499136f700000000, 0x5c2021ac00000000, 0xafb0d39a00000000,\n    0x76420e1a00000000, 0x85d2fc2c00000000, 0x9063eb7700000000,\n    0x63f3194100000000, 0x638021ad00000000, 0x9010d39b00000000,\n    0x85a1c4c000000000, 0x763136f600000000, 0xafc3eb7600000000,\n    0x5c53194000000000, 0x49e20e1b00000000, 0xba72fc2d00000000,\n    0x08020f1800000000, 0xfb92fd2e00000000, 0xee23ea7500000000,\n    0x1db3184300000000, 0xc441c5c300000000, 0x37d137f500000000,\n    0x226020ae00000000, 0xd1f0d29800000000, 0xd183ea7400000000,\n    0x2213184200000000, 0x37a20f1900000000, 0xc432fd2f00000000,\n    0x1dc020af00000000, 0xee50d29900000000, 0xfbe1c5c200000000,\n    0x087137f400000000},\n   {0x0000000000000000, 0x3651822400000000, 0x6ca2044900000000,\n    0x5af3866d00000000, 0xd844099200000000, 0xee158bb600000000,\n    0xb4e60ddb00000000, 0x82b78fff00000000, 0xf18f63ff00000000,\n    0xc7dee1db00000000, 0x9d2d67b600000000, 0xab7ce59200000000,\n    0x29cb6a6d00000000, 0x1f9ae84900000000, 0x45696e2400000000,\n    0x7338ec0000000000, 0xa319b62500000000, 0x9548340100000000,\n    0xcfbbb26c00000000, 0xf9ea304800000000, 0x7b5dbfb700000000,\n    0x4d0c3d9300000000, 0x17ffbbfe00000000, 0x21ae39da00000000,\n    0x5296d5da00000000, 0x64c757fe00000000, 0x3e34d19300000000,\n    0x086553b700000000, 0x8ad2dc4800000000, 0xbc835e6c00000000,\n    0xe670d80100000000, 0xd0215a2500000000, 0x46336c4b00000000,\n    0x7062ee6f00000000, 0x2a91680200000000, 0x1cc0ea2600000000,\n    0x9e7765d900000000, 0xa826e7fd00000000, 0xf2d5619000000000,\n    0xc484e3b400000000, 0xb7bc0fb400000000, 0x81ed8d9000000000,\n    0xdb1e0bfd00000000, 0xed4f89d900000000, 0x6ff8062600000000,\n    0x59a9840200000000, 0x035a026f00000000, 0x350b804b00000000,\n    0xe52ada6e00000000, 0xd37b584a00000000, 0x8988de2700000000,\n    0xbfd95c0300000000, 0x3d6ed3fc00000000, 0x0b3f51d800000000,\n    0x51ccd7b500000000, 0x679d559100000000, 0x14a5b99100000000,\n    0x22f43bb500000000, 0x7807bdd800000000, 0x4e563ffc00000000,\n    0xcce1b00300000000, 0xfab0322700000000, 0xa043b44a00000000,\n    0x9612366e00000000, 0x8c66d89600000000, 0xba375ab200000000,\n    0xe0c4dcdf00000000, 0xd6955efb00000000, 0x5422d10400000000,\n    0x6273532000000000, 0x3880d54d00000000, 0x0ed1576900000000,\n    0x7de9bb6900000000, 0x4bb8394d00000000, 0x114bbf2000000000,\n    0x271a3d0400000000, 0xa5adb2fb00000000, 0x93fc30df00000000,\n    0xc90fb6b200000000, 0xff5e349600000000, 0x2f7f6eb300000000,\n    0x192eec9700000000, 0x43dd6afa00000000, 0x758ce8de00000000,\n    0xf73b672100000000, 0xc16ae50500000000, 0x9b99636800000000,\n    0xadc8e14c00000000, 0xdef00d4c00000000, 0xe8a18f6800000000,\n    0xb252090500000000, 0x84038b2100000000, 0x06b404de00000000,\n    0x30e586fa00000000, 0x6a16009700000000, 0x5c4782b300000000,\n    0xca55b4dd00000000, 0xfc0436f900000000, 0xa6f7b09400000000,\n    0x90a632b000000000, 0x1211bd4f00000000, 0x24403f6b00000000,\n    0x7eb3b90600000000, 0x48e23b2200000000, 0x3bdad72200000000,\n    0x0d8b550600000000, 0x5778d36b00000000, 0x6129514f00000000,\n    0xe39edeb000000000, 0xd5cf5c9400000000, 0x8f3cdaf900000000,\n    0xb96d58dd00000000, 0x694c02f800000000, 0x5f1d80dc00000000,\n    0x05ee06b100000000, 0x33bf849500000000, 0xb1080b6a00000000,\n    0x8759894e00000000, 0xddaa0f2300000000, 0xebfb8d0700000000,\n    0x98c3610700000000, 0xae92e32300000000, 0xf461654e00000000,\n    0xc230e76a00000000, 0x4087689500000000, 0x76d6eab100000000,\n    0x2c256cdc00000000, 0x1a74eef800000000, 0x59cbc1f600000000,\n    0x6f9a43d200000000, 0x3569c5bf00000000, 0x0338479b00000000,\n    0x818fc86400000000, 0xb7de4a4000000000, 0xed2dcc2d00000000,\n    0xdb7c4e0900000000, 0xa844a20900000000, 0x9e15202d00000000,\n    0xc4e6a64000000000, 0xf2b7246400000000, 0x7000ab9b00000000,\n    0x465129bf00000000, 0x1ca2afd200000000, 0x2af32df600000000,\n    0xfad277d300000000, 0xcc83f5f700000000, 0x9670739a00000000,\n    0xa021f1be00000000, 0x22967e4100000000, 0x14c7fc6500000000,\n    0x4e347a0800000000, 0x7865f82c00000000, 0x0b5d142c00000000,\n    0x3d0c960800000000, 0x67ff106500000000, 0x51ae924100000000,\n    0xd3191dbe00000000, 0xe5489f9a00000000, 0xbfbb19f700000000,\n    0x89ea9bd300000000, 0x1ff8adbd00000000, 0x29a92f9900000000,\n    0x735aa9f400000000, 0x450b2bd000000000, 0xc7bca42f00000000,\n    0xf1ed260b00000000, 0xab1ea06600000000, 0x9d4f224200000000,\n    0xee77ce4200000000, 0xd8264c6600000000, 0x82d5ca0b00000000,\n    0xb484482f00000000, 0x3633c7d000000000, 0x006245f400000000,\n    0x5a91c39900000000, 0x6cc041bd00000000, 0xbce11b9800000000,\n    0x8ab099bc00000000, 0xd0431fd100000000, 0xe6129df500000000,\n    0x64a5120a00000000, 0x52f4902e00000000, 0x0807164300000000,\n    0x3e56946700000000, 0x4d6e786700000000, 0x7b3ffa4300000000,\n    0x21cc7c2e00000000, 0x179dfe0a00000000, 0x952a71f500000000,\n    0xa37bf3d100000000, 0xf98875bc00000000, 0xcfd9f79800000000,\n    0xd5ad196000000000, 0xe3fc9b4400000000, 0xb90f1d2900000000,\n    0x8f5e9f0d00000000, 0x0de910f200000000, 0x3bb892d600000000,\n    0x614b14bb00000000, 0x571a969f00000000, 0x24227a9f00000000,\n    0x1273f8bb00000000, 0x48807ed600000000, 0x7ed1fcf200000000,\n    0xfc66730d00000000, 0xca37f12900000000, 0x90c4774400000000,\n    0xa695f56000000000, 0x76b4af4500000000, 0x40e52d6100000000,\n    0x1a16ab0c00000000, 0x2c47292800000000, 0xaef0a6d700000000,\n    0x98a124f300000000, 0xc252a29e00000000, 0xf40320ba00000000,\n    0x873bccba00000000, 0xb16a4e9e00000000, 0xeb99c8f300000000,\n    0xddc84ad700000000, 0x5f7fc52800000000, 0x692e470c00000000,\n    0x33ddc16100000000, 0x058c434500000000, 0x939e752b00000000,\n    0xa5cff70f00000000, 0xff3c716200000000, 0xc96df34600000000,\n    0x4bda7cb900000000, 0x7d8bfe9d00000000, 0x277878f000000000,\n    0x1129fad400000000, 0x621116d400000000, 0x544094f000000000,\n    0x0eb3129d00000000, 0x38e290b900000000, 0xba551f4600000000,\n    0x8c049d6200000000, 0xd6f71b0f00000000, 0xe0a6992b00000000,\n    0x3087c30e00000000, 0x06d6412a00000000, 0x5c25c74700000000,\n    0x6a74456300000000, 0xe8c3ca9c00000000, 0xde9248b800000000,\n    0x8461ced500000000, 0xb2304cf100000000, 0xc108a0f100000000,\n    0xf75922d500000000, 0xadaaa4b800000000, 0x9bfb269c00000000,\n    0x194ca96300000000, 0x2f1d2b4700000000, 0x75eead2a00000000,\n    0x43bf2f0e00000000},\n   {0x0000000000000000, 0xc8179ecf00000000, 0xd1294d4400000000,\n    0x193ed38b00000000, 0xa2539a8800000000, 0x6a44044700000000,\n    0x737ad7cc00000000, 0xbb6d490300000000, 0x05a145ca00000000,\n    0xcdb6db0500000000, 0xd488088e00000000, 0x1c9f964100000000,\n    0xa7f2df4200000000, 0x6fe5418d00000000, 0x76db920600000000,\n    0xbecc0cc900000000, 0x4b44fa4f00000000, 0x8353648000000000,\n    0x9a6db70b00000000, 0x527a29c400000000, 0xe91760c700000000,\n    0x2100fe0800000000, 0x383e2d8300000000, 0xf029b34c00000000,\n    0x4ee5bf8500000000, 0x86f2214a00000000, 0x9fccf2c100000000,\n    0x57db6c0e00000000, 0xecb6250d00000000, 0x24a1bbc200000000,\n    0x3d9f684900000000, 0xf588f68600000000, 0x9688f49f00000000,\n    0x5e9f6a5000000000, 0x47a1b9db00000000, 0x8fb6271400000000,\n    0x34db6e1700000000, 0xfcccf0d800000000, 0xe5f2235300000000,\n    0x2de5bd9c00000000, 0x9329b15500000000, 0x5b3e2f9a00000000,\n    0x4200fc1100000000, 0x8a1762de00000000, 0x317a2bdd00000000,\n    0xf96db51200000000, 0xe053669900000000, 0x2844f85600000000,\n    0xddcc0ed000000000, 0x15db901f00000000, 0x0ce5439400000000,\n    0xc4f2dd5b00000000, 0x7f9f945800000000, 0xb7880a9700000000,\n    0xaeb6d91c00000000, 0x66a147d300000000, 0xd86d4b1a00000000,\n    0x107ad5d500000000, 0x0944065e00000000, 0xc153989100000000,\n    0x7a3ed19200000000, 0xb2294f5d00000000, 0xab179cd600000000,\n    0x6300021900000000, 0x6d1798e400000000, 0xa500062b00000000,\n    0xbc3ed5a000000000, 0x74294b6f00000000, 0xcf44026c00000000,\n    0x07539ca300000000, 0x1e6d4f2800000000, 0xd67ad1e700000000,\n    0x68b6dd2e00000000, 0xa0a143e100000000, 0xb99f906a00000000,\n    0x71880ea500000000, 0xcae547a600000000, 0x02f2d96900000000,\n    0x1bcc0ae200000000, 0xd3db942d00000000, 0x265362ab00000000,\n    0xee44fc6400000000, 0xf77a2fef00000000, 0x3f6db12000000000,\n    0x8400f82300000000, 0x4c1766ec00000000, 0x5529b56700000000,\n    0x9d3e2ba800000000, 0x23f2276100000000, 0xebe5b9ae00000000,\n    0xf2db6a2500000000, 0x3accf4ea00000000, 0x81a1bde900000000,\n    0x49b6232600000000, 0x5088f0ad00000000, 0x989f6e6200000000,\n    0xfb9f6c7b00000000, 0x3388f2b400000000, 0x2ab6213f00000000,\n    0xe2a1bff000000000, 0x59ccf6f300000000, 0x91db683c00000000,\n    0x88e5bbb700000000, 0x40f2257800000000, 0xfe3e29b100000000,\n    0x3629b77e00000000, 0x2f1764f500000000, 0xe700fa3a00000000,\n    0x5c6db33900000000, 0x947a2df600000000, 0x8d44fe7d00000000,\n    0x455360b200000000, 0xb0db963400000000, 0x78cc08fb00000000,\n    0x61f2db7000000000, 0xa9e545bf00000000, 0x12880cbc00000000,\n    0xda9f927300000000, 0xc3a141f800000000, 0x0bb6df3700000000,\n    0xb57ad3fe00000000, 0x7d6d4d3100000000, 0x64539eba00000000,\n    0xac44007500000000, 0x1729497600000000, 0xdf3ed7b900000000,\n    0xc600043200000000, 0x0e179afd00000000, 0x9b28411200000000,\n    0x533fdfdd00000000, 0x4a010c5600000000, 0x8216929900000000,\n    0x397bdb9a00000000, 0xf16c455500000000, 0xe85296de00000000,\n    0x2045081100000000, 0x9e8904d800000000, 0x569e9a1700000000,\n    0x4fa0499c00000000, 0x87b7d75300000000, 0x3cda9e5000000000,\n    0xf4cd009f00000000, 0xedf3d31400000000, 0x25e44ddb00000000,\n    0xd06cbb5d00000000, 0x187b259200000000, 0x0145f61900000000,\n    0xc95268d600000000, 0x723f21d500000000, 0xba28bf1a00000000,\n    0xa3166c9100000000, 0x6b01f25e00000000, 0xd5cdfe9700000000,\n    0x1dda605800000000, 0x04e4b3d300000000, 0xccf32d1c00000000,\n    0x779e641f00000000, 0xbf89fad000000000, 0xa6b7295b00000000,\n    0x6ea0b79400000000, 0x0da0b58d00000000, 0xc5b72b4200000000,\n    0xdc89f8c900000000, 0x149e660600000000, 0xaff32f0500000000,\n    0x67e4b1ca00000000, 0x7eda624100000000, 0xb6cdfc8e00000000,\n    0x0801f04700000000, 0xc0166e8800000000, 0xd928bd0300000000,\n    0x113f23cc00000000, 0xaa526acf00000000, 0x6245f40000000000,\n    0x7b7b278b00000000, 0xb36cb94400000000, 0x46e44fc200000000,\n    0x8ef3d10d00000000, 0x97cd028600000000, 0x5fda9c4900000000,\n    0xe4b7d54a00000000, 0x2ca04b8500000000, 0x359e980e00000000,\n    0xfd8906c100000000, 0x43450a0800000000, 0x8b5294c700000000,\n    0x926c474c00000000, 0x5a7bd98300000000, 0xe116908000000000,\n    0x29010e4f00000000, 0x303fddc400000000, 0xf828430b00000000,\n    0xf63fd9f600000000, 0x3e28473900000000, 0x271694b200000000,\n    0xef010a7d00000000, 0x546c437e00000000, 0x9c7bddb100000000,\n    0x85450e3a00000000, 0x4d5290f500000000, 0xf39e9c3c00000000,\n    0x3b8902f300000000, 0x22b7d17800000000, 0xeaa04fb700000000,\n    0x51cd06b400000000, 0x99da987b00000000, 0x80e44bf000000000,\n    0x48f3d53f00000000, 0xbd7b23b900000000, 0x756cbd7600000000,\n    0x6c526efd00000000, 0xa445f03200000000, 0x1f28b93100000000,\n    0xd73f27fe00000000, 0xce01f47500000000, 0x06166aba00000000,\n    0xb8da667300000000, 0x70cdf8bc00000000, 0x69f32b3700000000,\n    0xa1e4b5f800000000, 0x1a89fcfb00000000, 0xd29e623400000000,\n    0xcba0b1bf00000000, 0x03b72f7000000000, 0x60b72d6900000000,\n    0xa8a0b3a600000000, 0xb19e602d00000000, 0x7989fee200000000,\n    0xc2e4b7e100000000, 0x0af3292e00000000, 0x13cdfaa500000000,\n    0xdbda646a00000000, 0x651668a300000000, 0xad01f66c00000000,\n    0xb43f25e700000000, 0x7c28bb2800000000, 0xc745f22b00000000,\n    0x0f526ce400000000, 0x166cbf6f00000000, 0xde7b21a000000000,\n    0x2bf3d72600000000, 0xe3e449e900000000, 0xfada9a6200000000,\n    0x32cd04ad00000000, 0x89a04dae00000000, 0x41b7d36100000000,\n    0x588900ea00000000, 0x909e9e2500000000, 0x2e5292ec00000000,\n    0xe6450c2300000000, 0xff7bdfa800000000, 0x376c416700000000,\n    0x8c01086400000000, 0x441696ab00000000, 0x5d28452000000000,\n    0x953fdbef00000000},\n   {0x0000000000000000, 0x95d4709500000000, 0x6baf90f100000000,\n    0xfe7be06400000000, 0x9758503800000000, 0x028c20ad00000000,\n    0xfcf7c0c900000000, 0x6923b05c00000000, 0x2eb1a07000000000,\n    0xbb65d0e500000000, 0x451e308100000000, 0xd0ca401400000000,\n    0xb9e9f04800000000, 0x2c3d80dd00000000, 0xd24660b900000000,\n    0x4792102c00000000, 0x5c6241e100000000, 0xc9b6317400000000,\n    0x37cdd11000000000, 0xa219a18500000000, 0xcb3a11d900000000,\n    0x5eee614c00000000, 0xa095812800000000, 0x3541f1bd00000000,\n    0x72d3e19100000000, 0xe707910400000000, 0x197c716000000000,\n    0x8ca801f500000000, 0xe58bb1a900000000, 0x705fc13c00000000,\n    0x8e24215800000000, 0x1bf051cd00000000, 0xf9c2f31900000000,\n    0x6c16838c00000000, 0x926d63e800000000, 0x07b9137d00000000,\n    0x6e9aa32100000000, 0xfb4ed3b400000000, 0x053533d000000000,\n    0x90e1434500000000, 0xd773536900000000, 0x42a723fc00000000,\n    0xbcdcc39800000000, 0x2908b30d00000000, 0x402b035100000000,\n    0xd5ff73c400000000, 0x2b8493a000000000, 0xbe50e33500000000,\n    0xa5a0b2f800000000, 0x3074c26d00000000, 0xce0f220900000000,\n    0x5bdb529c00000000, 0x32f8e2c000000000, 0xa72c925500000000,\n    0x5957723100000000, 0xcc8302a400000000, 0x8b11128800000000,\n    0x1ec5621d00000000, 0xe0be827900000000, 0x756af2ec00000000,\n    0x1c4942b000000000, 0x899d322500000000, 0x77e6d24100000000,\n    0xe232a2d400000000, 0xf285e73300000000, 0x675197a600000000,\n    0x992a77c200000000, 0x0cfe075700000000, 0x65ddb70b00000000,\n    0xf009c79e00000000, 0x0e7227fa00000000, 0x9ba6576f00000000,\n    0xdc34474300000000, 0x49e037d600000000, 0xb79bd7b200000000,\n    0x224fa72700000000, 0x4b6c177b00000000, 0xdeb867ee00000000,\n    0x20c3878a00000000, 0xb517f71f00000000, 0xaee7a6d200000000,\n    0x3b33d64700000000, 0xc548362300000000, 0x509c46b600000000,\n    0x39bff6ea00000000, 0xac6b867f00000000, 0x5210661b00000000,\n    0xc7c4168e00000000, 0x805606a200000000, 0x1582763700000000,\n    0xebf9965300000000, 0x7e2de6c600000000, 0x170e569a00000000,\n    0x82da260f00000000, 0x7ca1c66b00000000, 0xe975b6fe00000000,\n    0x0b47142a00000000, 0x9e9364bf00000000, 0x60e884db00000000,\n    0xf53cf44e00000000, 0x9c1f441200000000, 0x09cb348700000000,\n    0xf7b0d4e300000000, 0x6264a47600000000, 0x25f6b45a00000000,\n    0xb022c4cf00000000, 0x4e5924ab00000000, 0xdb8d543e00000000,\n    0xb2aee46200000000, 0x277a94f700000000, 0xd901749300000000,\n    0x4cd5040600000000, 0x572555cb00000000, 0xc2f1255e00000000,\n    0x3c8ac53a00000000, 0xa95eb5af00000000, 0xc07d05f300000000,\n    0x55a9756600000000, 0xabd2950200000000, 0x3e06e59700000000,\n    0x7994f5bb00000000, 0xec40852e00000000, 0x123b654a00000000,\n    0x87ef15df00000000, 0xeecca58300000000, 0x7b18d51600000000,\n    0x8563357200000000, 0x10b745e700000000, 0xe40bcf6700000000,\n    0x71dfbff200000000, 0x8fa45f9600000000, 0x1a702f0300000000,\n    0x73539f5f00000000, 0xe687efca00000000, 0x18fc0fae00000000,\n    0x8d287f3b00000000, 0xcaba6f1700000000, 0x5f6e1f8200000000,\n    0xa115ffe600000000, 0x34c18f7300000000, 0x5de23f2f00000000,\n    0xc8364fba00000000, 0x364dafde00000000, 0xa399df4b00000000,\n    0xb8698e8600000000, 0x2dbdfe1300000000, 0xd3c61e7700000000,\n    0x46126ee200000000, 0x2f31debe00000000, 0xbae5ae2b00000000,\n    0x449e4e4f00000000, 0xd14a3eda00000000, 0x96d82ef600000000,\n    0x030c5e6300000000, 0xfd77be0700000000, 0x68a3ce9200000000,\n    0x01807ece00000000, 0x94540e5b00000000, 0x6a2fee3f00000000,\n    0xfffb9eaa00000000, 0x1dc93c7e00000000, 0x881d4ceb00000000,\n    0x7666ac8f00000000, 0xe3b2dc1a00000000, 0x8a916c4600000000,\n    0x1f451cd300000000, 0xe13efcb700000000, 0x74ea8c2200000000,\n    0x33789c0e00000000, 0xa6acec9b00000000, 0x58d70cff00000000,\n    0xcd037c6a00000000, 0xa420cc3600000000, 0x31f4bca300000000,\n    0xcf8f5cc700000000, 0x5a5b2c5200000000, 0x41ab7d9f00000000,\n    0xd47f0d0a00000000, 0x2a04ed6e00000000, 0xbfd09dfb00000000,\n    0xd6f32da700000000, 0x43275d3200000000, 0xbd5cbd5600000000,\n    0x2888cdc300000000, 0x6f1addef00000000, 0xfacead7a00000000,\n    0x04b54d1e00000000, 0x91613d8b00000000, 0xf8428dd700000000,\n    0x6d96fd4200000000, 0x93ed1d2600000000, 0x06396db300000000,\n    0x168e285400000000, 0x835a58c100000000, 0x7d21b8a500000000,\n    0xe8f5c83000000000, 0x81d6786c00000000, 0x140208f900000000,\n    0xea79e89d00000000, 0x7fad980800000000, 0x383f882400000000,\n    0xadebf8b100000000, 0x539018d500000000, 0xc644684000000000,\n    0xaf67d81c00000000, 0x3ab3a88900000000, 0xc4c848ed00000000,\n    0x511c387800000000, 0x4aec69b500000000, 0xdf38192000000000,\n    0x2143f94400000000, 0xb49789d100000000, 0xddb4398d00000000,\n    0x4860491800000000, 0xb61ba97c00000000, 0x23cfd9e900000000,\n    0x645dc9c500000000, 0xf189b95000000000, 0x0ff2593400000000,\n    0x9a2629a100000000, 0xf30599fd00000000, 0x66d1e96800000000,\n    0x98aa090c00000000, 0x0d7e799900000000, 0xef4cdb4d00000000,\n    0x7a98abd800000000, 0x84e34bbc00000000, 0x11373b2900000000,\n    0x78148b7500000000, 0xedc0fbe000000000, 0x13bb1b8400000000,\n    0x866f6b1100000000, 0xc1fd7b3d00000000, 0x54290ba800000000,\n    0xaa52ebcc00000000, 0x3f869b5900000000, 0x56a52b0500000000,\n    0xc3715b9000000000, 0x3d0abbf400000000, 0xa8decb6100000000,\n    0xb32e9aac00000000, 0x26faea3900000000, 0xd8810a5d00000000,\n    0x4d557ac800000000, 0x2476ca9400000000, 0xb1a2ba0100000000,\n    0x4fd95a6500000000, 0xda0d2af000000000, 0x9d9f3adc00000000,\n    0x084b4a4900000000, 0xf630aa2d00000000, 0x63e4dab800000000,\n    0x0ac76ae400000000, 0x9f131a7100000000, 0x6168fa1500000000,\n    0xf4bc8a8000000000},\n   {0x0000000000000000, 0x1f17f08000000000, 0x7f2891da00000000,\n    0x603f615a00000000, 0xbf56536e00000000, 0xa041a3ee00000000,\n    0xc07ec2b400000000, 0xdf69323400000000, 0x7eada6dc00000000,\n    0x61ba565c00000000, 0x0185370600000000, 0x1e92c78600000000,\n    0xc1fbf5b200000000, 0xdeec053200000000, 0xbed3646800000000,\n    0xa1c494e800000000, 0xbd5c3c6200000000, 0xa24bcce200000000,\n    0xc274adb800000000, 0xdd635d3800000000, 0x020a6f0c00000000,\n    0x1d1d9f8c00000000, 0x7d22fed600000000, 0x62350e5600000000,\n    0xc3f19abe00000000, 0xdce66a3e00000000, 0xbcd90b6400000000,\n    0xa3cefbe400000000, 0x7ca7c9d000000000, 0x63b0395000000000,\n    0x038f580a00000000, 0x1c98a88a00000000, 0x7ab978c400000000,\n    0x65ae884400000000, 0x0591e91e00000000, 0x1a86199e00000000,\n    0xc5ef2baa00000000, 0xdaf8db2a00000000, 0xbac7ba7000000000,\n    0xa5d04af000000000, 0x0414de1800000000, 0x1b032e9800000000,\n    0x7b3c4fc200000000, 0x642bbf4200000000, 0xbb428d7600000000,\n    0xa4557df600000000, 0xc46a1cac00000000, 0xdb7dec2c00000000,\n    0xc7e544a600000000, 0xd8f2b42600000000, 0xb8cdd57c00000000,\n    0xa7da25fc00000000, 0x78b317c800000000, 0x67a4e74800000000,\n    0x079b861200000000, 0x188c769200000000, 0xb948e27a00000000,\n    0xa65f12fa00000000, 0xc66073a000000000, 0xd977832000000000,\n    0x061eb11400000000, 0x1909419400000000, 0x793620ce00000000,\n    0x6621d04e00000000, 0xb574805300000000, 0xaa6370d300000000,\n    0xca5c118900000000, 0xd54be10900000000, 0x0a22d33d00000000,\n    0x153523bd00000000, 0x750a42e700000000, 0x6a1db26700000000,\n    0xcbd9268f00000000, 0xd4ced60f00000000, 0xb4f1b75500000000,\n    0xabe647d500000000, 0x748f75e100000000, 0x6b98856100000000,\n    0x0ba7e43b00000000, 0x14b014bb00000000, 0x0828bc3100000000,\n    0x173f4cb100000000, 0x77002deb00000000, 0x6817dd6b00000000,\n    0xb77eef5f00000000, 0xa8691fdf00000000, 0xc8567e8500000000,\n    0xd7418e0500000000, 0x76851aed00000000, 0x6992ea6d00000000,\n    0x09ad8b3700000000, 0x16ba7bb700000000, 0xc9d3498300000000,\n    0xd6c4b90300000000, 0xb6fbd85900000000, 0xa9ec28d900000000,\n    0xcfcdf89700000000, 0xd0da081700000000, 0xb0e5694d00000000,\n    0xaff299cd00000000, 0x709babf900000000, 0x6f8c5b7900000000,\n    0x0fb33a2300000000, 0x10a4caa300000000, 0xb1605e4b00000000,\n    0xae77aecb00000000, 0xce48cf9100000000, 0xd15f3f1100000000,\n    0x0e360d2500000000, 0x1121fda500000000, 0x711e9cff00000000,\n    0x6e096c7f00000000, 0x7291c4f500000000, 0x6d86347500000000,\n    0x0db9552f00000000, 0x12aea5af00000000, 0xcdc7979b00000000,\n    0xd2d0671b00000000, 0xb2ef064100000000, 0xadf8f6c100000000,\n    0x0c3c622900000000, 0x132b92a900000000, 0x7314f3f300000000,\n    0x6c03037300000000, 0xb36a314700000000, 0xac7dc1c700000000,\n    0xcc42a09d00000000, 0xd355501d00000000, 0x6ae900a700000000,\n    0x75fef02700000000, 0x15c1917d00000000, 0x0ad661fd00000000,\n    0xd5bf53c900000000, 0xcaa8a34900000000, 0xaa97c21300000000,\n    0xb580329300000000, 0x1444a67b00000000, 0x0b5356fb00000000,\n    0x6b6c37a100000000, 0x747bc72100000000, 0xab12f51500000000,\n    0xb405059500000000, 0xd43a64cf00000000, 0xcb2d944f00000000,\n    0xd7b53cc500000000, 0xc8a2cc4500000000, 0xa89dad1f00000000,\n    0xb78a5d9f00000000, 0x68e36fab00000000, 0x77f49f2b00000000,\n    0x17cbfe7100000000, 0x08dc0ef100000000, 0xa9189a1900000000,\n    0xb60f6a9900000000, 0xd6300bc300000000, 0xc927fb4300000000,\n    0x164ec97700000000, 0x095939f700000000, 0x696658ad00000000,\n    0x7671a82d00000000, 0x1050786300000000, 0x0f4788e300000000,\n    0x6f78e9b900000000, 0x706f193900000000, 0xaf062b0d00000000,\n    0xb011db8d00000000, 0xd02ebad700000000, 0xcf394a5700000000,\n    0x6efddebf00000000, 0x71ea2e3f00000000, 0x11d54f6500000000,\n    0x0ec2bfe500000000, 0xd1ab8dd100000000, 0xcebc7d5100000000,\n    0xae831c0b00000000, 0xb194ec8b00000000, 0xad0c440100000000,\n    0xb21bb48100000000, 0xd224d5db00000000, 0xcd33255b00000000,\n    0x125a176f00000000, 0x0d4de7ef00000000, 0x6d7286b500000000,\n    0x7265763500000000, 0xd3a1e2dd00000000, 0xccb6125d00000000,\n    0xac89730700000000, 0xb39e838700000000, 0x6cf7b1b300000000,\n    0x73e0413300000000, 0x13df206900000000, 0x0cc8d0e900000000,\n    0xdf9d80f400000000, 0xc08a707400000000, 0xa0b5112e00000000,\n    0xbfa2e1ae00000000, 0x60cbd39a00000000, 0x7fdc231a00000000,\n    0x1fe3424000000000, 0x00f4b2c000000000, 0xa130262800000000,\n    0xbe27d6a800000000, 0xde18b7f200000000, 0xc10f477200000000,\n    0x1e66754600000000, 0x017185c600000000, 0x614ee49c00000000,\n    0x7e59141c00000000, 0x62c1bc9600000000, 0x7dd64c1600000000,\n    0x1de92d4c00000000, 0x02feddcc00000000, 0xdd97eff800000000,\n    0xc2801f7800000000, 0xa2bf7e2200000000, 0xbda88ea200000000,\n    0x1c6c1a4a00000000, 0x037beaca00000000, 0x63448b9000000000,\n    0x7c537b1000000000, 0xa33a492400000000, 0xbc2db9a400000000,\n    0xdc12d8fe00000000, 0xc305287e00000000, 0xa524f83000000000,\n    0xba3308b000000000, 0xda0c69ea00000000, 0xc51b996a00000000,\n    0x1a72ab5e00000000, 0x05655bde00000000, 0x655a3a8400000000,\n    0x7a4dca0400000000, 0xdb895eec00000000, 0xc49eae6c00000000,\n    0xa4a1cf3600000000, 0xbbb63fb600000000, 0x64df0d8200000000,\n    0x7bc8fd0200000000, 0x1bf79c5800000000, 0x04e06cd800000000,\n    0x1878c45200000000, 0x076f34d200000000, 0x6750558800000000,\n    0x7847a50800000000, 0xa72e973c00000000, 0xb83967bc00000000,\n    0xd80606e600000000, 0xc711f66600000000, 0x66d5628e00000000,\n    0x79c2920e00000000, 0x19fdf35400000000, 0x06ea03d400000000,\n    0xd98331e000000000, 0xc694c16000000000, 0xa6aba03a00000000,\n    0xb9bc50ba00000000},\n   {0x0000000000000000, 0xe2fd888d00000000, 0x85fd60c000000000,\n    0x6700e84d00000000, 0x4bfdb05b00000000, 0xa90038d600000000,\n    0xce00d09b00000000, 0x2cfd581600000000, 0x96fa61b700000000,\n    0x7407e93a00000000, 0x1307017700000000, 0xf1fa89fa00000000,\n    0xdd07d1ec00000000, 0x3ffa596100000000, 0x58fab12c00000000,\n    0xba0739a100000000, 0x6df3b2b500000000, 0x8f0e3a3800000000,\n    0xe80ed27500000000, 0x0af35af800000000, 0x260e02ee00000000,\n    0xc4f38a6300000000, 0xa3f3622e00000000, 0x410eeaa300000000,\n    0xfb09d30200000000, 0x19f45b8f00000000, 0x7ef4b3c200000000,\n    0x9c093b4f00000000, 0xb0f4635900000000, 0x5209ebd400000000,\n    0x3509039900000000, 0xd7f48b1400000000, 0x9be014b000000000,\n    0x791d9c3d00000000, 0x1e1d747000000000, 0xfce0fcfd00000000,\n    0xd01da4eb00000000, 0x32e02c6600000000, 0x55e0c42b00000000,\n    0xb71d4ca600000000, 0x0d1a750700000000, 0xefe7fd8a00000000,\n    0x88e715c700000000, 0x6a1a9d4a00000000, 0x46e7c55c00000000,\n    0xa41a4dd100000000, 0xc31aa59c00000000, 0x21e72d1100000000,\n    0xf613a60500000000, 0x14ee2e8800000000, 0x73eec6c500000000,\n    0x91134e4800000000, 0xbdee165e00000000, 0x5f139ed300000000,\n    0x3813769e00000000, 0xdaeefe1300000000, 0x60e9c7b200000000,\n    0x82144f3f00000000, 0xe514a77200000000, 0x07e92fff00000000,\n    0x2b1477e900000000, 0xc9e9ff6400000000, 0xaee9172900000000,\n    0x4c149fa400000000, 0x77c758bb00000000, 0x953ad03600000000,\n    0xf23a387b00000000, 0x10c7b0f600000000, 0x3c3ae8e000000000,\n    0xdec7606d00000000, 0xb9c7882000000000, 0x5b3a00ad00000000,\n    0xe13d390c00000000, 0x03c0b18100000000, 0x64c059cc00000000,\n    0x863dd14100000000, 0xaac0895700000000, 0x483d01da00000000,\n    0x2f3de99700000000, 0xcdc0611a00000000, 0x1a34ea0e00000000,\n    0xf8c9628300000000, 0x9fc98ace00000000, 0x7d34024300000000,\n    0x51c95a5500000000, 0xb334d2d800000000, 0xd4343a9500000000,\n    0x36c9b21800000000, 0x8cce8bb900000000, 0x6e33033400000000,\n    0x0933eb7900000000, 0xebce63f400000000, 0xc7333be200000000,\n    0x25ceb36f00000000, 0x42ce5b2200000000, 0xa033d3af00000000,\n    0xec274c0b00000000, 0x0edac48600000000, 0x69da2ccb00000000,\n    0x8b27a44600000000, 0xa7dafc5000000000, 0x452774dd00000000,\n    0x22279c9000000000, 0xc0da141d00000000, 0x7add2dbc00000000,\n    0x9820a53100000000, 0xff204d7c00000000, 0x1dddc5f100000000,\n    0x31209de700000000, 0xd3dd156a00000000, 0xb4ddfd2700000000,\n    0x562075aa00000000, 0x81d4febe00000000, 0x6329763300000000,\n    0x04299e7e00000000, 0xe6d416f300000000, 0xca294ee500000000,\n    0x28d4c66800000000, 0x4fd42e2500000000, 0xad29a6a800000000,\n    0x172e9f0900000000, 0xf5d3178400000000, 0x92d3ffc900000000,\n    0x702e774400000000, 0x5cd32f5200000000, 0xbe2ea7df00000000,\n    0xd92e4f9200000000, 0x3bd3c71f00000000, 0xaf88c0ad00000000,\n    0x4d75482000000000, 0x2a75a06d00000000, 0xc88828e000000000,\n    0xe47570f600000000, 0x0688f87b00000000, 0x6188103600000000,\n    0x837598bb00000000, 0x3972a11a00000000, 0xdb8f299700000000,\n    0xbc8fc1da00000000, 0x5e72495700000000, 0x728f114100000000,\n    0x907299cc00000000, 0xf772718100000000, 0x158ff90c00000000,\n    0xc27b721800000000, 0x2086fa9500000000, 0x478612d800000000,\n    0xa57b9a5500000000, 0x8986c24300000000, 0x6b7b4ace00000000,\n    0x0c7ba28300000000, 0xee862a0e00000000, 0x548113af00000000,\n    0xb67c9b2200000000, 0xd17c736f00000000, 0x3381fbe200000000,\n    0x1f7ca3f400000000, 0xfd812b7900000000, 0x9a81c33400000000,\n    0x787c4bb900000000, 0x3468d41d00000000, 0xd6955c9000000000,\n    0xb195b4dd00000000, 0x53683c5000000000, 0x7f95644600000000,\n    0x9d68eccb00000000, 0xfa68048600000000, 0x18958c0b00000000,\n    0xa292b5aa00000000, 0x406f3d2700000000, 0x276fd56a00000000,\n    0xc5925de700000000, 0xe96f05f100000000, 0x0b928d7c00000000,\n    0x6c92653100000000, 0x8e6fedbc00000000, 0x599b66a800000000,\n    0xbb66ee2500000000, 0xdc66066800000000, 0x3e9b8ee500000000,\n    0x1266d6f300000000, 0xf09b5e7e00000000, 0x979bb63300000000,\n    0x75663ebe00000000, 0xcf61071f00000000, 0x2d9c8f9200000000,\n    0x4a9c67df00000000, 0xa861ef5200000000, 0x849cb74400000000,\n    0x66613fc900000000, 0x0161d78400000000, 0xe39c5f0900000000,\n    0xd84f981600000000, 0x3ab2109b00000000, 0x5db2f8d600000000,\n    0xbf4f705b00000000, 0x93b2284d00000000, 0x714fa0c000000000,\n    0x164f488d00000000, 0xf4b2c00000000000, 0x4eb5f9a100000000,\n    0xac48712c00000000, 0xcb48996100000000, 0x29b511ec00000000,\n    0x054849fa00000000, 0xe7b5c17700000000, 0x80b5293a00000000,\n    0x6248a1b700000000, 0xb5bc2aa300000000, 0x5741a22e00000000,\n    0x30414a6300000000, 0xd2bcc2ee00000000, 0xfe419af800000000,\n    0x1cbc127500000000, 0x7bbcfa3800000000, 0x994172b500000000,\n    0x23464b1400000000, 0xc1bbc39900000000, 0xa6bb2bd400000000,\n    0x4446a35900000000, 0x68bbfb4f00000000, 0x8a4673c200000000,\n    0xed469b8f00000000, 0x0fbb130200000000, 0x43af8ca600000000,\n    0xa152042b00000000, 0xc652ec6600000000, 0x24af64eb00000000,\n    0x08523cfd00000000, 0xeaafb47000000000, 0x8daf5c3d00000000,\n    0x6f52d4b000000000, 0xd555ed1100000000, 0x37a8659c00000000,\n    0x50a88dd100000000, 0xb255055c00000000, 0x9ea85d4a00000000,\n    0x7c55d5c700000000, 0x1b553d8a00000000, 0xf9a8b50700000000,\n    0x2e5c3e1300000000, 0xcca1b69e00000000, 0xaba15ed300000000,\n    0x495cd65e00000000, 0x65a18e4800000000, 0x875c06c500000000,\n    0xe05cee8800000000, 0x02a1660500000000, 0xb8a65fa400000000,\n    0x5a5bd72900000000, 0x3d5b3f6400000000, 0xdfa6b7e900000000,\n    0xf35befff00000000, 0x11a6677200000000, 0x76a68f3f00000000,\n    0x945b07b200000000},\n   {0x0000000000000000, 0xa90b894e00000000, 0x5217129d00000000,\n    0xfb1c9bd300000000, 0xe52855e100000000, 0x4c23dcaf00000000,\n    0xb73f477c00000000, 0x1e34ce3200000000, 0x8b57db1900000000,\n    0x225c525700000000, 0xd940c98400000000, 0x704b40ca00000000,\n    0x6e7f8ef800000000, 0xc77407b600000000, 0x3c689c6500000000,\n    0x9563152b00000000, 0x16afb63300000000, 0xbfa43f7d00000000,\n    0x44b8a4ae00000000, 0xedb32de000000000, 0xf387e3d200000000,\n    0x5a8c6a9c00000000, 0xa190f14f00000000, 0x089b780100000000,\n    0x9df86d2a00000000, 0x34f3e46400000000, 0xcfef7fb700000000,\n    0x66e4f6f900000000, 0x78d038cb00000000, 0xd1dbb18500000000,\n    0x2ac72a5600000000, 0x83cca31800000000, 0x2c5e6d6700000000,\n    0x8555e42900000000, 0x7e497ffa00000000, 0xd742f6b400000000,\n    0xc976388600000000, 0x607db1c800000000, 0x9b612a1b00000000,\n    0x326aa35500000000, 0xa709b67e00000000, 0x0e023f3000000000,\n    0xf51ea4e300000000, 0x5c152dad00000000, 0x4221e39f00000000,\n    0xeb2a6ad100000000, 0x1036f10200000000, 0xb93d784c00000000,\n    0x3af1db5400000000, 0x93fa521a00000000, 0x68e6c9c900000000,\n    0xc1ed408700000000, 0xdfd98eb500000000, 0x76d207fb00000000,\n    0x8dce9c2800000000, 0x24c5156600000000, 0xb1a6004d00000000,\n    0x18ad890300000000, 0xe3b112d000000000, 0x4aba9b9e00000000,\n    0x548e55ac00000000, 0xfd85dce200000000, 0x0699473100000000,\n    0xaf92ce7f00000000, 0x58bcdace00000000, 0xf1b7538000000000,\n    0x0aabc85300000000, 0xa3a0411d00000000, 0xbd948f2f00000000,\n    0x149f066100000000, 0xef839db200000000, 0x468814fc00000000,\n    0xd3eb01d700000000, 0x7ae0889900000000, 0x81fc134a00000000,\n    0x28f79a0400000000, 0x36c3543600000000, 0x9fc8dd7800000000,\n    0x64d446ab00000000, 0xcddfcfe500000000, 0x4e136cfd00000000,\n    0xe718e5b300000000, 0x1c047e6000000000, 0xb50ff72e00000000,\n    0xab3b391c00000000, 0x0230b05200000000, 0xf92c2b8100000000,\n    0x5027a2cf00000000, 0xc544b7e400000000, 0x6c4f3eaa00000000,\n    0x9753a57900000000, 0x3e582c3700000000, 0x206ce20500000000,\n    0x89676b4b00000000, 0x727bf09800000000, 0xdb7079d600000000,\n    0x74e2b7a900000000, 0xdde93ee700000000, 0x26f5a53400000000,\n    0x8ffe2c7a00000000, 0x91cae24800000000, 0x38c16b0600000000,\n    0xc3ddf0d500000000, 0x6ad6799b00000000, 0xffb56cb000000000,\n    0x56bee5fe00000000, 0xada27e2d00000000, 0x04a9f76300000000,\n    0x1a9d395100000000, 0xb396b01f00000000, 0x488a2bcc00000000,\n    0xe181a28200000000, 0x624d019a00000000, 0xcb4688d400000000,\n    0x305a130700000000, 0x99519a4900000000, 0x8765547b00000000,\n    0x2e6edd3500000000, 0xd57246e600000000, 0x7c79cfa800000000,\n    0xe91ada8300000000, 0x401153cd00000000, 0xbb0dc81e00000000,\n    0x1206415000000000, 0x0c328f6200000000, 0xa539062c00000000,\n    0x5e259dff00000000, 0xf72e14b100000000, 0xf17ec44600000000,\n    0x58754d0800000000, 0xa369d6db00000000, 0x0a625f9500000000,\n    0x145691a700000000, 0xbd5d18e900000000, 0x4641833a00000000,\n    0xef4a0a7400000000, 0x7a291f5f00000000, 0xd322961100000000,\n    0x283e0dc200000000, 0x8135848c00000000, 0x9f014abe00000000,\n    0x360ac3f000000000, 0xcd16582300000000, 0x641dd16d00000000,\n    0xe7d1727500000000, 0x4edafb3b00000000, 0xb5c660e800000000,\n    0x1ccde9a600000000, 0x02f9279400000000, 0xabf2aeda00000000,\n    0x50ee350900000000, 0xf9e5bc4700000000, 0x6c86a96c00000000,\n    0xc58d202200000000, 0x3e91bbf100000000, 0x979a32bf00000000,\n    0x89aefc8d00000000, 0x20a575c300000000, 0xdbb9ee1000000000,\n    0x72b2675e00000000, 0xdd20a92100000000, 0x742b206f00000000,\n    0x8f37bbbc00000000, 0x263c32f200000000, 0x3808fcc000000000,\n    0x9103758e00000000, 0x6a1fee5d00000000, 0xc314671300000000,\n    0x5677723800000000, 0xff7cfb7600000000, 0x046060a500000000,\n    0xad6be9eb00000000, 0xb35f27d900000000, 0x1a54ae9700000000,\n    0xe148354400000000, 0x4843bc0a00000000, 0xcb8f1f1200000000,\n    0x6284965c00000000, 0x99980d8f00000000, 0x309384c100000000,\n    0x2ea74af300000000, 0x87acc3bd00000000, 0x7cb0586e00000000,\n    0xd5bbd12000000000, 0x40d8c40b00000000, 0xe9d34d4500000000,\n    0x12cfd69600000000, 0xbbc45fd800000000, 0xa5f091ea00000000,\n    0x0cfb18a400000000, 0xf7e7837700000000, 0x5eec0a3900000000,\n    0xa9c21e8800000000, 0x00c997c600000000, 0xfbd50c1500000000,\n    0x52de855b00000000, 0x4cea4b6900000000, 0xe5e1c22700000000,\n    0x1efd59f400000000, 0xb7f6d0ba00000000, 0x2295c59100000000,\n    0x8b9e4cdf00000000, 0x7082d70c00000000, 0xd9895e4200000000,\n    0xc7bd907000000000, 0x6eb6193e00000000, 0x95aa82ed00000000,\n    0x3ca10ba300000000, 0xbf6da8bb00000000, 0x166621f500000000,\n    0xed7aba2600000000, 0x4471336800000000, 0x5a45fd5a00000000,\n    0xf34e741400000000, 0x0852efc700000000, 0xa159668900000000,\n    0x343a73a200000000, 0x9d31faec00000000, 0x662d613f00000000,\n    0xcf26e87100000000, 0xd112264300000000, 0x7819af0d00000000,\n    0x830534de00000000, 0x2a0ebd9000000000, 0x859c73ef00000000,\n    0x2c97faa100000000, 0xd78b617200000000, 0x7e80e83c00000000,\n    0x60b4260e00000000, 0xc9bfaf4000000000, 0x32a3349300000000,\n    0x9ba8bddd00000000, 0x0ecba8f600000000, 0xa7c021b800000000,\n    0x5cdcba6b00000000, 0xf5d7332500000000, 0xebe3fd1700000000,\n    0x42e8745900000000, 0xb9f4ef8a00000000, 0x10ff66c400000000,\n    0x9333c5dc00000000, 0x3a384c9200000000, 0xc124d74100000000,\n    0x682f5e0f00000000, 0x761b903d00000000, 0xdf10197300000000,\n    0x240c82a000000000, 0x8d070bee00000000, 0x18641ec500000000,\n    0xb16f978b00000000, 0x4a730c5800000000, 0xe378851600000000,\n    0xfd4c4b2400000000, 0x5447c26a00000000, 0xaf5b59b900000000,\n    0x0650d0f700000000},\n   {0x0000000000000000, 0x479244af00000000, 0xcf22f88500000000,\n    0x88b0bc2a00000000, 0xdf4381d000000000, 0x98d1c57f00000000,\n    0x1061795500000000, 0x57f33dfa00000000, 0xff81737a00000000,\n    0xb81337d500000000, 0x30a38bff00000000, 0x7731cf5000000000,\n    0x20c2f2aa00000000, 0x6750b60500000000, 0xefe00a2f00000000,\n    0xa8724e8000000000, 0xfe03e7f400000000, 0xb991a35b00000000,\n    0x31211f7100000000, 0x76b35bde00000000, 0x2140662400000000,\n    0x66d2228b00000000, 0xee629ea100000000, 0xa9f0da0e00000000,\n    0x0182948e00000000, 0x4610d02100000000, 0xcea06c0b00000000,\n    0x893228a400000000, 0xdec1155e00000000, 0x995351f100000000,\n    0x11e3eddb00000000, 0x5671a97400000000, 0xbd01bf3200000000,\n    0xfa93fb9d00000000, 0x722347b700000000, 0x35b1031800000000,\n    0x62423ee200000000, 0x25d07a4d00000000, 0xad60c66700000000,\n    0xeaf282c800000000, 0x4280cc4800000000, 0x051288e700000000,\n    0x8da234cd00000000, 0xca30706200000000, 0x9dc34d9800000000,\n    0xda51093700000000, 0x52e1b51d00000000, 0x1573f1b200000000,\n    0x430258c600000000, 0x04901c6900000000, 0x8c20a04300000000,\n    0xcbb2e4ec00000000, 0x9c41d91600000000, 0xdbd39db900000000,\n    0x5363219300000000, 0x14f1653c00000000, 0xbc832bbc00000000,\n    0xfb116f1300000000, 0x73a1d33900000000, 0x3433979600000000,\n    0x63c0aa6c00000000, 0x2452eec300000000, 0xace252e900000000,\n    0xeb70164600000000, 0x7a037e6500000000, 0x3d913aca00000000,\n    0xb52186e000000000, 0xf2b3c24f00000000, 0xa540ffb500000000,\n    0xe2d2bb1a00000000, 0x6a62073000000000, 0x2df0439f00000000,\n    0x85820d1f00000000, 0xc21049b000000000, 0x4aa0f59a00000000,\n    0x0d32b13500000000, 0x5ac18ccf00000000, 0x1d53c86000000000,\n    0x95e3744a00000000, 0xd27130e500000000, 0x8400999100000000,\n    0xc392dd3e00000000, 0x4b22611400000000, 0x0cb025bb00000000,\n    0x5b43184100000000, 0x1cd15cee00000000, 0x9461e0c400000000,\n    0xd3f3a46b00000000, 0x7b81eaeb00000000, 0x3c13ae4400000000,\n    0xb4a3126e00000000, 0xf33156c100000000, 0xa4c26b3b00000000,\n    0xe3502f9400000000, 0x6be093be00000000, 0x2c72d71100000000,\n    0xc702c15700000000, 0x809085f800000000, 0x082039d200000000,\n    0x4fb27d7d00000000, 0x1841408700000000, 0x5fd3042800000000,\n    0xd763b80200000000, 0x90f1fcad00000000, 0x3883b22d00000000,\n    0x7f11f68200000000, 0xf7a14aa800000000, 0xb0330e0700000000,\n    0xe7c033fd00000000, 0xa052775200000000, 0x28e2cb7800000000,\n    0x6f708fd700000000, 0x390126a300000000, 0x7e93620c00000000,\n    0xf623de2600000000, 0xb1b19a8900000000, 0xe642a77300000000,\n    0xa1d0e3dc00000000, 0x29605ff600000000, 0x6ef21b5900000000,\n    0xc68055d900000000, 0x8112117600000000, 0x09a2ad5c00000000,\n    0x4e30e9f300000000, 0x19c3d40900000000, 0x5e5190a600000000,\n    0xd6e12c8c00000000, 0x9173682300000000, 0xf406fcca00000000,\n    0xb394b86500000000, 0x3b24044f00000000, 0x7cb640e000000000,\n    0x2b457d1a00000000, 0x6cd739b500000000, 0xe467859f00000000,\n    0xa3f5c13000000000, 0x0b878fb000000000, 0x4c15cb1f00000000,\n    0xc4a5773500000000, 0x8337339a00000000, 0xd4c40e6000000000,\n    0x93564acf00000000, 0x1be6f6e500000000, 0x5c74b24a00000000,\n    0x0a051b3e00000000, 0x4d975f9100000000, 0xc527e3bb00000000,\n    0x82b5a71400000000, 0xd5469aee00000000, 0x92d4de4100000000,\n    0x1a64626b00000000, 0x5df626c400000000, 0xf584684400000000,\n    0xb2162ceb00000000, 0x3aa690c100000000, 0x7d34d46e00000000,\n    0x2ac7e99400000000, 0x6d55ad3b00000000, 0xe5e5111100000000,\n    0xa27755be00000000, 0x490743f800000000, 0x0e95075700000000,\n    0x8625bb7d00000000, 0xc1b7ffd200000000, 0x9644c22800000000,\n    0xd1d6868700000000, 0x59663aad00000000, 0x1ef47e0200000000,\n    0xb686308200000000, 0xf114742d00000000, 0x79a4c80700000000,\n    0x3e368ca800000000, 0x69c5b15200000000, 0x2e57f5fd00000000,\n    0xa6e749d700000000, 0xe1750d7800000000, 0xb704a40c00000000,\n    0xf096e0a300000000, 0x78265c8900000000, 0x3fb4182600000000,\n    0x684725dc00000000, 0x2fd5617300000000, 0xa765dd5900000000,\n    0xe0f799f600000000, 0x4885d77600000000, 0x0f1793d900000000,\n    0x87a72ff300000000, 0xc0356b5c00000000, 0x97c656a600000000,\n    0xd054120900000000, 0x58e4ae2300000000, 0x1f76ea8c00000000,\n    0x8e0582af00000000, 0xc997c60000000000, 0x41277a2a00000000,\n    0x06b53e8500000000, 0x5146037f00000000, 0x16d447d000000000,\n    0x9e64fbfa00000000, 0xd9f6bf5500000000, 0x7184f1d500000000,\n    0x3616b57a00000000, 0xbea6095000000000, 0xf9344dff00000000,\n    0xaec7700500000000, 0xe95534aa00000000, 0x61e5888000000000,\n    0x2677cc2f00000000, 0x7006655b00000000, 0x379421f400000000,\n    0xbf249dde00000000, 0xf8b6d97100000000, 0xaf45e48b00000000,\n    0xe8d7a02400000000, 0x60671c0e00000000, 0x27f558a100000000,\n    0x8f87162100000000, 0xc815528e00000000, 0x40a5eea400000000,\n    0x0737aa0b00000000, 0x50c497f100000000, 0x1756d35e00000000,\n    0x9fe66f7400000000, 0xd8742bdb00000000, 0x33043d9d00000000,\n    0x7496793200000000, 0xfc26c51800000000, 0xbbb481b700000000,\n    0xec47bc4d00000000, 0xabd5f8e200000000, 0x236544c800000000,\n    0x64f7006700000000, 0xcc854ee700000000, 0x8b170a4800000000,\n    0x03a7b66200000000, 0x4435f2cd00000000, 0x13c6cf3700000000,\n    0x54548b9800000000, 0xdce437b200000000, 0x9b76731d00000000,\n    0xcd07da6900000000, 0x8a959ec600000000, 0x022522ec00000000,\n    0x45b7664300000000, 0x12445bb900000000, 0x55d61f1600000000,\n    0xdd66a33c00000000, 0x9af4e79300000000, 0x3286a91300000000,\n    0x7514edbc00000000, 0xfda4519600000000, 0xba36153900000000,\n    0xedc528c300000000, 0xaa576c6c00000000, 0x22e7d04600000000,\n    0x657594e900000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0x65673b46, 0xcace768c, 0xafa94dca, 0x4eedeb59,\n    0x2b8ad01f, 0x84239dd5, 0xe144a693, 0x9ddbd6b2, 0xf8bcedf4,\n    0x5715a03e, 0x32729b78, 0xd3363deb, 0xb65106ad, 0x19f84b67,\n    0x7c9f7021, 0xe0c6ab25, 0x85a19063, 0x2a08dda9, 0x4f6fe6ef,\n    0xae2b407c, 0xcb4c7b3a, 0x64e536f0, 0x01820db6, 0x7d1d7d97,\n    0x187a46d1, 0xb7d30b1b, 0xd2b4305d, 0x33f096ce, 0x5697ad88,\n    0xf93ee042, 0x9c59db04, 0x1afc500b, 0x7f9b6b4d, 0xd0322687,\n    0xb5551dc1, 0x5411bb52, 0x31768014, 0x9edfcdde, 0xfbb8f698,\n    0x872786b9, 0xe240bdff, 0x4de9f035, 0x288ecb73, 0xc9ca6de0,\n    0xacad56a6, 0x03041b6c, 0x6663202a, 0xfa3afb2e, 0x9f5dc068,\n    0x30f48da2, 0x5593b6e4, 0xb4d71077, 0xd1b02b31, 0x7e1966fb,\n    0x1b7e5dbd, 0x67e12d9c, 0x028616da, 0xad2f5b10, 0xc8486056,\n    0x290cc6c5, 0x4c6bfd83, 0xe3c2b049, 0x86a58b0f, 0x35f8a016,\n    0x509f9b50, 0xff36d69a, 0x9a51eddc, 0x7b154b4f, 0x1e727009,\n    0xb1db3dc3, 0xd4bc0685, 0xa82376a4, 0xcd444de2, 0x62ed0028,\n    0x078a3b6e, 0xe6ce9dfd, 0x83a9a6bb, 0x2c00eb71, 0x4967d037,\n    0xd53e0b33, 0xb0593075, 0x1ff07dbf, 0x7a9746f9, 0x9bd3e06a,\n    0xfeb4db2c, 0x511d96e6, 0x347aada0, 0x48e5dd81, 0x2d82e6c7,\n    0x822bab0d, 0xe74c904b, 0x060836d8, 0x636f0d9e, 0xccc64054,\n    0xa9a17b12, 0x2f04f01d, 0x4a63cb5b, 0xe5ca8691, 0x80adbdd7,\n    0x61e91b44, 0x048e2002, 0xab276dc8, 0xce40568e, 0xb2df26af,\n    0xd7b81de9, 0x78115023, 0x1d766b65, 0xfc32cdf6, 0x9955f6b0,\n    0x36fcbb7a, 0x539b803c, 0xcfc25b38, 0xaaa5607e, 0x050c2db4,\n    0x606b16f2, 0x812fb061, 0xe4488b27, 0x4be1c6ed, 0x2e86fdab,\n    0x52198d8a, 0x377eb6cc, 0x98d7fb06, 0xfdb0c040, 0x1cf466d3,\n    0x79935d95, 0xd63a105f, 0xb35d2b19, 0x6bf1402c, 0x0e967b6a,\n    0xa13f36a0, 0xc4580de6, 0x251cab75, 0x407b9033, 0xefd2ddf9,\n    0x8ab5e6bf, 0xf62a969e, 0x934dadd8, 0x3ce4e012, 0x5983db54,\n    0xb8c77dc7, 0xdda04681, 0x72090b4b, 0x176e300d, 0x8b37eb09,\n    0xee50d04f, 0x41f99d85, 0x249ea6c3, 0xc5da0050, 0xa0bd3b16,\n    0x0f1476dc, 0x6a734d9a, 0x16ec3dbb, 0x738b06fd, 0xdc224b37,\n    0xb9457071, 0x5801d6e2, 0x3d66eda4, 0x92cfa06e, 0xf7a89b28,\n    0x710d1027, 0x146a2b61, 0xbbc366ab, 0xdea45ded, 0x3fe0fb7e,\n    0x5a87c038, 0xf52e8df2, 0x9049b6b4, 0xecd6c695, 0x89b1fdd3,\n    0x2618b019, 0x437f8b5f, 0xa23b2dcc, 0xc75c168a, 0x68f55b40,\n    0x0d926006, 0x91cbbb02, 0xf4ac8044, 0x5b05cd8e, 0x3e62f6c8,\n    0xdf26505b, 0xba416b1d, 0x15e826d7, 0x708f1d91, 0x0c106db0,\n    0x697756f6, 0xc6de1b3c, 0xa3b9207a, 0x42fd86e9, 0x279abdaf,\n    0x8833f065, 0xed54cb23, 0x5e09e03a, 0x3b6edb7c, 0x94c796b6,\n    0xf1a0adf0, 0x10e40b63, 0x75833025, 0xda2a7def, 0xbf4d46a9,\n    0xc3d23688, 0xa6b50dce, 0x091c4004, 0x6c7b7b42, 0x8d3fddd1,\n    0xe858e697, 0x47f1ab5d, 0x2296901b, 0xbecf4b1f, 0xdba87059,\n    0x74013d93, 0x116606d5, 0xf022a046, 0x95459b00, 0x3aecd6ca,\n    0x5f8bed8c, 0x23149dad, 0x4673a6eb, 0xe9daeb21, 0x8cbdd067,\n    0x6df976f4, 0x089e4db2, 0xa7370078, 0xc2503b3e, 0x44f5b031,\n    0x21928b77, 0x8e3bc6bd, 0xeb5cfdfb, 0x0a185b68, 0x6f7f602e,\n    0xc0d62de4, 0xa5b116a2, 0xd92e6683, 0xbc495dc5, 0x13e0100f,\n    0x76872b49, 0x97c38dda, 0xf2a4b69c, 0x5d0dfb56, 0x386ac010,\n    0xa4331b14, 0xc1542052, 0x6efd6d98, 0x0b9a56de, 0xeadef04d,\n    0x8fb9cb0b, 0x201086c1, 0x4577bd87, 0x39e8cda6, 0x5c8ff6e0,\n    0xf326bb2a, 0x9641806c, 0x770526ff, 0x12621db9, 0xbdcb5073,\n    0xd8ac6b35},\n   {0x00000000, 0xd7e28058, 0x74b406f1, 0xa35686a9, 0xe9680de2,\n    0x3e8a8dba, 0x9ddc0b13, 0x4a3e8b4b, 0x09a11d85, 0xde439ddd,\n    0x7d151b74, 0xaaf79b2c, 0xe0c91067, 0x372b903f, 0x947d1696,\n    0x439f96ce, 0x13423b0a, 0xc4a0bb52, 0x67f63dfb, 0xb014bda3,\n    0xfa2a36e8, 0x2dc8b6b0, 0x8e9e3019, 0x597cb041, 0x1ae3268f,\n    0xcd01a6d7, 0x6e57207e, 0xb9b5a026, 0xf38b2b6d, 0x2469ab35,\n    0x873f2d9c, 0x50ddadc4, 0x26847614, 0xf166f64c, 0x523070e5,\n    0x85d2f0bd, 0xcfec7bf6, 0x180efbae, 0xbb587d07, 0x6cbafd5f,\n    0x2f256b91, 0xf8c7ebc9, 0x5b916d60, 0x8c73ed38, 0xc64d6673,\n    0x11afe62b, 0xb2f96082, 0x651be0da, 0x35c64d1e, 0xe224cd46,\n    0x41724bef, 0x9690cbb7, 0xdcae40fc, 0x0b4cc0a4, 0xa81a460d,\n    0x7ff8c655, 0x3c67509b, 0xeb85d0c3, 0x48d3566a, 0x9f31d632,\n    0xd50f5d79, 0x02eddd21, 0xa1bb5b88, 0x7659dbd0, 0x4d08ec28,\n    0x9aea6c70, 0x39bcead9, 0xee5e6a81, 0xa460e1ca, 0x73826192,\n    0xd0d4e73b, 0x07366763, 0x44a9f1ad, 0x934b71f5, 0x301df75c,\n    0xe7ff7704, 0xadc1fc4f, 0x7a237c17, 0xd975fabe, 0x0e977ae6,\n    0x5e4ad722, 0x89a8577a, 0x2afed1d3, 0xfd1c518b, 0xb722dac0,\n    0x60c05a98, 0xc396dc31, 0x14745c69, 0x57ebcaa7, 0x80094aff,\n    0x235fcc56, 0xf4bd4c0e, 0xbe83c745, 0x6961471d, 0xca37c1b4,\n    0x1dd541ec, 0x6b8c9a3c, 0xbc6e1a64, 0x1f389ccd, 0xc8da1c95,\n    0x82e497de, 0x55061786, 0xf650912f, 0x21b21177, 0x622d87b9,\n    0xb5cf07e1, 0x16998148, 0xc17b0110, 0x8b458a5b, 0x5ca70a03,\n    0xfff18caa, 0x28130cf2, 0x78cea136, 0xaf2c216e, 0x0c7aa7c7,\n    0xdb98279f, 0x91a6acd4, 0x46442c8c, 0xe512aa25, 0x32f02a7d,\n    0x716fbcb3, 0xa68d3ceb, 0x05dbba42, 0xd2393a1a, 0x9807b151,\n    0x4fe53109, 0xecb3b7a0, 0x3b5137f8, 0x9a11d850, 0x4df35808,\n    0xeea5dea1, 0x39475ef9, 0x7379d5b2, 0xa49b55ea, 0x07cdd343,\n    0xd02f531b, 0x93b0c5d5, 0x4452458d, 0xe704c324, 0x30e6437c,\n    0x7ad8c837, 0xad3a486f, 0x0e6ccec6, 0xd98e4e9e, 0x8953e35a,\n    0x5eb16302, 0xfde7e5ab, 0x2a0565f3, 0x603beeb8, 0xb7d96ee0,\n    0x148fe849, 0xc36d6811, 0x80f2fedf, 0x57107e87, 0xf446f82e,\n    0x23a47876, 0x699af33d, 0xbe787365, 0x1d2ef5cc, 0xcacc7594,\n    0xbc95ae44, 0x6b772e1c, 0xc821a8b5, 0x1fc328ed, 0x55fda3a6,\n    0x821f23fe, 0x2149a557, 0xf6ab250f, 0xb534b3c1, 0x62d63399,\n    0xc180b530, 0x16623568, 0x5c5cbe23, 0x8bbe3e7b, 0x28e8b8d2,\n    0xff0a388a, 0xafd7954e, 0x78351516, 0xdb6393bf, 0x0c8113e7,\n    0x46bf98ac, 0x915d18f4, 0x320b9e5d, 0xe5e91e05, 0xa67688cb,\n    0x71940893, 0xd2c28e3a, 0x05200e62, 0x4f1e8529, 0x98fc0571,\n    0x3baa83d8, 0xec480380, 0xd7193478, 0x00fbb420, 0xa3ad3289,\n    0x744fb2d1, 0x3e71399a, 0xe993b9c2, 0x4ac53f6b, 0x9d27bf33,\n    0xdeb829fd, 0x095aa9a5, 0xaa0c2f0c, 0x7deeaf54, 0x37d0241f,\n    0xe032a447, 0x436422ee, 0x9486a2b6, 0xc45b0f72, 0x13b98f2a,\n    0xb0ef0983, 0x670d89db, 0x2d330290, 0xfad182c8, 0x59870461,\n    0x8e658439, 0xcdfa12f7, 0x1a1892af, 0xb94e1406, 0x6eac945e,\n    0x24921f15, 0xf3709f4d, 0x502619e4, 0x87c499bc, 0xf19d426c,\n    0x267fc234, 0x8529449d, 0x52cbc4c5, 0x18f54f8e, 0xcf17cfd6,\n    0x6c41497f, 0xbba3c927, 0xf83c5fe9, 0x2fdedfb1, 0x8c885918,\n    0x5b6ad940, 0x1154520b, 0xc6b6d253, 0x65e054fa, 0xb202d4a2,\n    0xe2df7966, 0x353df93e, 0x966b7f97, 0x4189ffcf, 0x0bb77484,\n    0xdc55f4dc, 0x7f037275, 0xa8e1f22d, 0xeb7e64e3, 0x3c9ce4bb,\n    0x9fca6212, 0x4828e24a, 0x02166901, 0xd5f4e959, 0x76a26ff0,\n    0xa140efa8},\n   {0x00000000, 0xef52b6e1, 0x05d46b83, 0xea86dd62, 0x0ba8d706,\n    0xe4fa61e7, 0x0e7cbc85, 0xe12e0a64, 0x1751ae0c, 0xf80318ed,\n    0x1285c58f, 0xfdd7736e, 0x1cf9790a, 0xf3abcfeb, 0x192d1289,\n    0xf67fa468, 0x2ea35c18, 0xc1f1eaf9, 0x2b77379b, 0xc425817a,\n    0x250b8b1e, 0xca593dff, 0x20dfe09d, 0xcf8d567c, 0x39f2f214,\n    0xd6a044f5, 0x3c269997, 0xd3742f76, 0x325a2512, 0xdd0893f3,\n    0x378e4e91, 0xd8dcf870, 0x5d46b830, 0xb2140ed1, 0x5892d3b3,\n    0xb7c06552, 0x56ee6f36, 0xb9bcd9d7, 0x533a04b5, 0xbc68b254,\n    0x4a17163c, 0xa545a0dd, 0x4fc37dbf, 0xa091cb5e, 0x41bfc13a,\n    0xaeed77db, 0x446baab9, 0xab391c58, 0x73e5e428, 0x9cb752c9,\n    0x76318fab, 0x9963394a, 0x784d332e, 0x971f85cf, 0x7d9958ad,\n    0x92cbee4c, 0x64b44a24, 0x8be6fcc5, 0x616021a7, 0x8e329746,\n    0x6f1c9d22, 0x804e2bc3, 0x6ac8f6a1, 0x859a4040, 0xba8d7060,\n    0x55dfc681, 0xbf591be3, 0x500bad02, 0xb125a766, 0x5e771187,\n    0xb4f1cce5, 0x5ba37a04, 0xaddcde6c, 0x428e688d, 0xa808b5ef,\n    0x475a030e, 0xa674096a, 0x4926bf8b, 0xa3a062e9, 0x4cf2d408,\n    0x942e2c78, 0x7b7c9a99, 0x91fa47fb, 0x7ea8f11a, 0x9f86fb7e,\n    0x70d44d9f, 0x9a5290fd, 0x7500261c, 0x837f8274, 0x6c2d3495,\n    0x86abe9f7, 0x69f95f16, 0x88d75572, 0x6785e393, 0x8d033ef1,\n    0x62518810, 0xe7cbc850, 0x08997eb1, 0xe21fa3d3, 0x0d4d1532,\n    0xec631f56, 0x0331a9b7, 0xe9b774d5, 0x06e5c234, 0xf09a665c,\n    0x1fc8d0bd, 0xf54e0ddf, 0x1a1cbb3e, 0xfb32b15a, 0x146007bb,\n    0xfee6dad9, 0x11b46c38, 0xc9689448, 0x263a22a9, 0xccbcffcb,\n    0x23ee492a, 0xc2c0434e, 0x2d92f5af, 0xc71428cd, 0x28469e2c,\n    0xde393a44, 0x316b8ca5, 0xdbed51c7, 0x34bfe726, 0xd591ed42,\n    0x3ac35ba3, 0xd04586c1, 0x3f173020, 0xae6be681, 0x41395060,\n    0xabbf8d02, 0x44ed3be3, 0xa5c33187, 0x4a918766, 0xa0175a04,\n    0x4f45ece5, 0xb93a488d, 0x5668fe6c, 0xbcee230e, 0x53bc95ef,\n    0xb2929f8b, 0x5dc0296a, 0xb746f408, 0x581442e9, 0x80c8ba99,\n    0x6f9a0c78, 0x851cd11a, 0x6a4e67fb, 0x8b606d9f, 0x6432db7e,\n    0x8eb4061c, 0x61e6b0fd, 0x97991495, 0x78cba274, 0x924d7f16,\n    0x7d1fc9f7, 0x9c31c393, 0x73637572, 0x99e5a810, 0x76b71ef1,\n    0xf32d5eb1, 0x1c7fe850, 0xf6f93532, 0x19ab83d3, 0xf88589b7,\n    0x17d73f56, 0xfd51e234, 0x120354d5, 0xe47cf0bd, 0x0b2e465c,\n    0xe1a89b3e, 0x0efa2ddf, 0xefd427bb, 0x0086915a, 0xea004c38,\n    0x0552fad9, 0xdd8e02a9, 0x32dcb448, 0xd85a692a, 0x3708dfcb,\n    0xd626d5af, 0x3974634e, 0xd3f2be2c, 0x3ca008cd, 0xcadfaca5,\n    0x258d1a44, 0xcf0bc726, 0x205971c7, 0xc1777ba3, 0x2e25cd42,\n    0xc4a31020, 0x2bf1a6c1, 0x14e696e1, 0xfbb42000, 0x1132fd62,\n    0xfe604b83, 0x1f4e41e7, 0xf01cf706, 0x1a9a2a64, 0xf5c89c85,\n    0x03b738ed, 0xece58e0c, 0x0663536e, 0xe931e58f, 0x081fefeb,\n    0xe74d590a, 0x0dcb8468, 0xe2993289, 0x3a45caf9, 0xd5177c18,\n    0x3f91a17a, 0xd0c3179b, 0x31ed1dff, 0xdebfab1e, 0x3439767c,\n    0xdb6bc09d, 0x2d1464f5, 0xc246d214, 0x28c00f76, 0xc792b997,\n    0x26bcb3f3, 0xc9ee0512, 0x2368d870, 0xcc3a6e91, 0x49a02ed1,\n    0xa6f29830, 0x4c744552, 0xa326f3b3, 0x4208f9d7, 0xad5a4f36,\n    0x47dc9254, 0xa88e24b5, 0x5ef180dd, 0xb1a3363c, 0x5b25eb5e,\n    0xb4775dbf, 0x555957db, 0xba0be13a, 0x508d3c58, 0xbfdf8ab9,\n    0x670372c9, 0x8851c428, 0x62d7194a, 0x8d85afab, 0x6caba5cf,\n    0x83f9132e, 0x697fce4c, 0x862d78ad, 0x7052dcc5, 0x9f006a24,\n    0x7586b746, 0x9ad401a7, 0x7bfa0bc3, 0x94a8bd22, 0x7e2e6040,\n    0x917cd6a1},\n   {0x00000000, 0x87a6cb43, 0xd43c90c7, 0x539a5b84, 0x730827cf,\n    0xf4aeec8c, 0xa734b708, 0x20927c4b, 0xe6104f9e, 0x61b684dd,\n    0x322cdf59, 0xb58a141a, 0x95186851, 0x12bea312, 0x4124f896,\n    0xc68233d5, 0x1751997d, 0x90f7523e, 0xc36d09ba, 0x44cbc2f9,\n    0x6459beb2, 0xe3ff75f1, 0xb0652e75, 0x37c3e536, 0xf141d6e3,\n    0x76e71da0, 0x257d4624, 0xa2db8d67, 0x8249f12c, 0x05ef3a6f,\n    0x567561eb, 0xd1d3aaa8, 0x2ea332fa, 0xa905f9b9, 0xfa9fa23d,\n    0x7d39697e, 0x5dab1535, 0xda0dde76, 0x899785f2, 0x0e314eb1,\n    0xc8b37d64, 0x4f15b627, 0x1c8feda3, 0x9b2926e0, 0xbbbb5aab,\n    0x3c1d91e8, 0x6f87ca6c, 0xe821012f, 0x39f2ab87, 0xbe5460c4,\n    0xedce3b40, 0x6a68f003, 0x4afa8c48, 0xcd5c470b, 0x9ec61c8f,\n    0x1960d7cc, 0xdfe2e419, 0x58442f5a, 0x0bde74de, 0x8c78bf9d,\n    0xaceac3d6, 0x2b4c0895, 0x78d65311, 0xff709852, 0x5d4665f4,\n    0xdae0aeb7, 0x897af533, 0x0edc3e70, 0x2e4e423b, 0xa9e88978,\n    0xfa72d2fc, 0x7dd419bf, 0xbb562a6a, 0x3cf0e129, 0x6f6abaad,\n    0xe8cc71ee, 0xc85e0da5, 0x4ff8c6e6, 0x1c629d62, 0x9bc45621,\n    0x4a17fc89, 0xcdb137ca, 0x9e2b6c4e, 0x198da70d, 0x391fdb46,\n    0xbeb91005, 0xed234b81, 0x6a8580c2, 0xac07b317, 0x2ba17854,\n    0x783b23d0, 0xff9de893, 0xdf0f94d8, 0x58a95f9b, 0x0b33041f,\n    0x8c95cf5c, 0x73e5570e, 0xf4439c4d, 0xa7d9c7c9, 0x207f0c8a,\n    0x00ed70c1, 0x874bbb82, 0xd4d1e006, 0x53772b45, 0x95f51890,\n    0x1253d3d3, 0x41c98857, 0xc66f4314, 0xe6fd3f5f, 0x615bf41c,\n    0x32c1af98, 0xb56764db, 0x64b4ce73, 0xe3120530, 0xb0885eb4,\n    0x372e95f7, 0x17bce9bc, 0x901a22ff, 0xc380797b, 0x4426b238,\n    0x82a481ed, 0x05024aae, 0x5698112a, 0xd13eda69, 0xf1aca622,\n    0x760a6d61, 0x259036e5, 0xa236fda6, 0xba8ccbe8, 0x3d2a00ab,\n    0x6eb05b2f, 0xe916906c, 0xc984ec27, 0x4e222764, 0x1db87ce0,\n    0x9a1eb7a3, 0x5c9c8476, 0xdb3a4f35, 0x88a014b1, 0x0f06dff2,\n    0x2f94a3b9, 0xa83268fa, 0xfba8337e, 0x7c0ef83d, 0xaddd5295,\n    0x2a7b99d6, 0x79e1c252, 0xfe470911, 0xded5755a, 0x5973be19,\n    0x0ae9e59d, 0x8d4f2ede, 0x4bcd1d0b, 0xcc6bd648, 0x9ff18dcc,\n    0x1857468f, 0x38c53ac4, 0xbf63f187, 0xecf9aa03, 0x6b5f6140,\n    0x942ff912, 0x13893251, 0x401369d5, 0xc7b5a296, 0xe727dedd,\n    0x6081159e, 0x331b4e1a, 0xb4bd8559, 0x723fb68c, 0xf5997dcf,\n    0xa603264b, 0x21a5ed08, 0x01379143, 0x86915a00, 0xd50b0184,\n    0x52adcac7, 0x837e606f, 0x04d8ab2c, 0x5742f0a8, 0xd0e43beb,\n    0xf07647a0, 0x77d08ce3, 0x244ad767, 0xa3ec1c24, 0x656e2ff1,\n    0xe2c8e4b2, 0xb152bf36, 0x36f47475, 0x1666083e, 0x91c0c37d,\n    0xc25a98f9, 0x45fc53ba, 0xe7caae1c, 0x606c655f, 0x33f63edb,\n    0xb450f598, 0x94c289d3, 0x13644290, 0x40fe1914, 0xc758d257,\n    0x01dae182, 0x867c2ac1, 0xd5e67145, 0x5240ba06, 0x72d2c64d,\n    0xf5740d0e, 0xa6ee568a, 0x21489dc9, 0xf09b3761, 0x773dfc22,\n    0x24a7a7a6, 0xa3016ce5, 0x839310ae, 0x0435dbed, 0x57af8069,\n    0xd0094b2a, 0x168b78ff, 0x912db3bc, 0xc2b7e838, 0x4511237b,\n    0x65835f30, 0xe2259473, 0xb1bfcff7, 0x361904b4, 0xc9699ce6,\n    0x4ecf57a5, 0x1d550c21, 0x9af3c762, 0xba61bb29, 0x3dc7706a,\n    0x6e5d2bee, 0xe9fbe0ad, 0x2f79d378, 0xa8df183b, 0xfb4543bf,\n    0x7ce388fc, 0x5c71f4b7, 0xdbd73ff4, 0x884d6470, 0x0febaf33,\n    0xde38059b, 0x599eced8, 0x0a04955c, 0x8da25e1f, 0xad302254,\n    0x2a96e917, 0x790cb293, 0xfeaa79d0, 0x38284a05, 0xbf8e8146,\n    0xec14dac2, 0x6bb21181, 0x4b206dca, 0xcc86a689, 0x9f1cfd0d,\n    0x18ba364e}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0x43cba687, 0xc7903cd4, 0x845b9a53, 0xcf270873,\n    0x8cecaef4, 0x08b734a7, 0x4b7c9220, 0x9e4f10e6, 0xdd84b661,\n    0x59df2c32, 0x1a148ab5, 0x51681895, 0x12a3be12, 0x96f82441,\n    0xd53382c6, 0x7d995117, 0x3e52f790, 0xba096dc3, 0xf9c2cb44,\n    0xb2be5964, 0xf175ffe3, 0x752e65b0, 0x36e5c337, 0xe3d641f1,\n    0xa01de776, 0x24467d25, 0x678ddba2, 0x2cf14982, 0x6f3aef05,\n    0xeb617556, 0xa8aad3d1, 0xfa32a32e, 0xb9f905a9, 0x3da29ffa,\n    0x7e69397d, 0x3515ab5d, 0x76de0dda, 0xf2859789, 0xb14e310e,\n    0x647db3c8, 0x27b6154f, 0xa3ed8f1c, 0xe026299b, 0xab5abbbb,\n    0xe8911d3c, 0x6cca876f, 0x2f0121e8, 0x87abf239, 0xc46054be,\n    0x403bceed, 0x03f0686a, 0x488cfa4a, 0x0b475ccd, 0x8f1cc69e,\n    0xccd76019, 0x19e4e2df, 0x5a2f4458, 0xde74de0b, 0x9dbf788c,\n    0xd6c3eaac, 0x95084c2b, 0x1153d678, 0x529870ff, 0xf465465d,\n    0xb7aee0da, 0x33f57a89, 0x703edc0e, 0x3b424e2e, 0x7889e8a9,\n    0xfcd272fa, 0xbf19d47d, 0x6a2a56bb, 0x29e1f03c, 0xadba6a6f,\n    0xee71cce8, 0xa50d5ec8, 0xe6c6f84f, 0x629d621c, 0x2156c49b,\n    0x89fc174a, 0xca37b1cd, 0x4e6c2b9e, 0x0da78d19, 0x46db1f39,\n    0x0510b9be, 0x814b23ed, 0xc280856a, 0x17b307ac, 0x5478a12b,\n    0xd0233b78, 0x93e89dff, 0xd8940fdf, 0x9b5fa958, 0x1f04330b,\n    0x5ccf958c, 0x0e57e573, 0x4d9c43f4, 0xc9c7d9a7, 0x8a0c7f20,\n    0xc170ed00, 0x82bb4b87, 0x06e0d1d4, 0x452b7753, 0x9018f595,\n    0xd3d35312, 0x5788c941, 0x14436fc6, 0x5f3ffde6, 0x1cf45b61,\n    0x98afc132, 0xdb6467b5, 0x73ceb464, 0x300512e3, 0xb45e88b0,\n    0xf7952e37, 0xbce9bc17, 0xff221a90, 0x7b7980c3, 0x38b22644,\n    0xed81a482, 0xae4a0205, 0x2a119856, 0x69da3ed1, 0x22a6acf1,\n    0x616d0a76, 0xe5369025, 0xa6fd36a2, 0xe8cb8cba, 0xab002a3d,\n    0x2f5bb06e, 0x6c9016e9, 0x27ec84c9, 0x6427224e, 0xe07cb81d,\n    0xa3b71e9a, 0x76849c5c, 0x354f3adb, 0xb114a088, 0xf2df060f,\n    0xb9a3942f, 0xfa6832a8, 0x7e33a8fb, 0x3df80e7c, 0x9552ddad,\n    0xd6997b2a, 0x52c2e179, 0x110947fe, 0x5a75d5de, 0x19be7359,\n    0x9de5e90a, 0xde2e4f8d, 0x0b1dcd4b, 0x48d66bcc, 0xcc8df19f,\n    0x8f465718, 0xc43ac538, 0x87f163bf, 0x03aaf9ec, 0x40615f6b,\n    0x12f92f94, 0x51328913, 0xd5691340, 0x96a2b5c7, 0xddde27e7,\n    0x9e158160, 0x1a4e1b33, 0x5985bdb4, 0x8cb63f72, 0xcf7d99f5,\n    0x4b2603a6, 0x08eda521, 0x43913701, 0x005a9186, 0x84010bd5,\n    0xc7caad52, 0x6f607e83, 0x2cabd804, 0xa8f04257, 0xeb3be4d0,\n    0xa04776f0, 0xe38cd077, 0x67d74a24, 0x241ceca3, 0xf12f6e65,\n    0xb2e4c8e2, 0x36bf52b1, 0x7574f436, 0x3e086616, 0x7dc3c091,\n    0xf9985ac2, 0xba53fc45, 0x1caecae7, 0x5f656c60, 0xdb3ef633,\n    0x98f550b4, 0xd389c294, 0x90426413, 0x1419fe40, 0x57d258c7,\n    0x82e1da01, 0xc12a7c86, 0x4571e6d5, 0x06ba4052, 0x4dc6d272,\n    0x0e0d74f5, 0x8a56eea6, 0xc99d4821, 0x61379bf0, 0x22fc3d77,\n    0xa6a7a724, 0xe56c01a3, 0xae109383, 0xeddb3504, 0x6980af57,\n    0x2a4b09d0, 0xff788b16, 0xbcb32d91, 0x38e8b7c2, 0x7b231145,\n    0x305f8365, 0x739425e2, 0xf7cfbfb1, 0xb4041936, 0xe69c69c9,\n    0xa557cf4e, 0x210c551d, 0x62c7f39a, 0x29bb61ba, 0x6a70c73d,\n    0xee2b5d6e, 0xade0fbe9, 0x78d3792f, 0x3b18dfa8, 0xbf4345fb,\n    0xfc88e37c, 0xb7f4715c, 0xf43fd7db, 0x70644d88, 0x33afeb0f,\n    0x9b0538de, 0xd8ce9e59, 0x5c95040a, 0x1f5ea28d, 0x542230ad,\n    0x17e9962a, 0x93b20c79, 0xd079aafe, 0x054a2838, 0x46818ebf,\n    0xc2da14ec, 0x8111b26b, 0xca6d204b, 0x89a686cc, 0x0dfd1c9f,\n    0x4e36ba18},\n   {0x00000000, 0xe1b652ef, 0x836bd405, 0x62dd86ea, 0x06d7a80b,\n    0xe761fae4, 0x85bc7c0e, 0x640a2ee1, 0x0cae5117, 0xed1803f8,\n    0x8fc58512, 0x6e73d7fd, 0x0a79f91c, 0xebcfabf3, 0x89122d19,\n    0x68a47ff6, 0x185ca32e, 0xf9eaf1c1, 0x9b37772b, 0x7a8125c4,\n    0x1e8b0b25, 0xff3d59ca, 0x9de0df20, 0x7c568dcf, 0x14f2f239,\n    0xf544a0d6, 0x9799263c, 0x762f74d3, 0x12255a32, 0xf39308dd,\n    0x914e8e37, 0x70f8dcd8, 0x30b8465d, 0xd10e14b2, 0xb3d39258,\n    0x5265c0b7, 0x366fee56, 0xd7d9bcb9, 0xb5043a53, 0x54b268bc,\n    0x3c16174a, 0xdda045a5, 0xbf7dc34f, 0x5ecb91a0, 0x3ac1bf41,\n    0xdb77edae, 0xb9aa6b44, 0x581c39ab, 0x28e4e573, 0xc952b79c,\n    0xab8f3176, 0x4a396399, 0x2e334d78, 0xcf851f97, 0xad58997d,\n    0x4ceecb92, 0x244ab464, 0xc5fce68b, 0xa7216061, 0x4697328e,\n    0x229d1c6f, 0xc32b4e80, 0xa1f6c86a, 0x40409a85, 0x60708dba,\n    0x81c6df55, 0xe31b59bf, 0x02ad0b50, 0x66a725b1, 0x8711775e,\n    0xe5ccf1b4, 0x047aa35b, 0x6cdedcad, 0x8d688e42, 0xefb508a8,\n    0x0e035a47, 0x6a0974a6, 0x8bbf2649, 0xe962a0a3, 0x08d4f24c,\n    0x782c2e94, 0x999a7c7b, 0xfb47fa91, 0x1af1a87e, 0x7efb869f,\n    0x9f4dd470, 0xfd90529a, 0x1c260075, 0x74827f83, 0x95342d6c,\n    0xf7e9ab86, 0x165ff969, 0x7255d788, 0x93e38567, 0xf13e038d,\n    0x10885162, 0x50c8cbe7, 0xb17e9908, 0xd3a31fe2, 0x32154d0d,\n    0x561f63ec, 0xb7a93103, 0xd574b7e9, 0x34c2e506, 0x5c669af0,\n    0xbdd0c81f, 0xdf0d4ef5, 0x3ebb1c1a, 0x5ab132fb, 0xbb076014,\n    0xd9dae6fe, 0x386cb411, 0x489468c9, 0xa9223a26, 0xcbffbccc,\n    0x2a49ee23, 0x4e43c0c2, 0xaff5922d, 0xcd2814c7, 0x2c9e4628,\n    0x443a39de, 0xa58c6b31, 0xc751eddb, 0x26e7bf34, 0x42ed91d5,\n    0xa35bc33a, 0xc18645d0, 0x2030173f, 0x81e66bae, 0x60503941,\n    0x028dbfab, 0xe33bed44, 0x8731c3a5, 0x6687914a, 0x045a17a0,\n    0xe5ec454f, 0x8d483ab9, 0x6cfe6856, 0x0e23eebc, 0xef95bc53,\n    0x8b9f92b2, 0x6a29c05d, 0x08f446b7, 0xe9421458, 0x99bac880,\n    0x780c9a6f, 0x1ad11c85, 0xfb674e6a, 0x9f6d608b, 0x7edb3264,\n    0x1c06b48e, 0xfdb0e661, 0x95149997, 0x74a2cb78, 0x167f4d92,\n    0xf7c91f7d, 0x93c3319c, 0x72756373, 0x10a8e599, 0xf11eb776,\n    0xb15e2df3, 0x50e87f1c, 0x3235f9f6, 0xd383ab19, 0xb78985f8,\n    0x563fd717, 0x34e251fd, 0xd5540312, 0xbdf07ce4, 0x5c462e0b,\n    0x3e9ba8e1, 0xdf2dfa0e, 0xbb27d4ef, 0x5a918600, 0x384c00ea,\n    0xd9fa5205, 0xa9028edd, 0x48b4dc32, 0x2a695ad8, 0xcbdf0837,\n    0xafd526d6, 0x4e637439, 0x2cbef2d3, 0xcd08a03c, 0xa5acdfca,\n    0x441a8d25, 0x26c70bcf, 0xc7715920, 0xa37b77c1, 0x42cd252e,\n    0x2010a3c4, 0xc1a6f12b, 0xe196e614, 0x0020b4fb, 0x62fd3211,\n    0x834b60fe, 0xe7414e1f, 0x06f71cf0, 0x642a9a1a, 0x859cc8f5,\n    0xed38b703, 0x0c8ee5ec, 0x6e536306, 0x8fe531e9, 0xebef1f08,\n    0x0a594de7, 0x6884cb0d, 0x893299e2, 0xf9ca453a, 0x187c17d5,\n    0x7aa1913f, 0x9b17c3d0, 0xff1ded31, 0x1eabbfde, 0x7c763934,\n    0x9dc06bdb, 0xf564142d, 0x14d246c2, 0x760fc028, 0x97b992c7,\n    0xf3b3bc26, 0x1205eec9, 0x70d86823, 0x916e3acc, 0xd12ea049,\n    0x3098f2a6, 0x5245744c, 0xb3f326a3, 0xd7f90842, 0x364f5aad,\n    0x5492dc47, 0xb5248ea8, 0xdd80f15e, 0x3c36a3b1, 0x5eeb255b,\n    0xbf5d77b4, 0xdb575955, 0x3ae10bba, 0x583c8d50, 0xb98adfbf,\n    0xc9720367, 0x28c45188, 0x4a19d762, 0xabaf858d, 0xcfa5ab6c,\n    0x2e13f983, 0x4cce7f69, 0xad782d86, 0xc5dc5270, 0x246a009f,\n    0x46b78675, 0xa701d49a, 0xc30bfa7b, 0x22bda894, 0x40602e7e,\n    0xa1d67c91},\n   {0x00000000, 0x5880e2d7, 0xf106b474, 0xa98656a3, 0xe20d68e9,\n    0xba8d8a3e, 0x130bdc9d, 0x4b8b3e4a, 0x851da109, 0xdd9d43de,\n    0x741b157d, 0x2c9bf7aa, 0x6710c9e0, 0x3f902b37, 0x96167d94,\n    0xce969f43, 0x0a3b4213, 0x52bba0c4, 0xfb3df667, 0xa3bd14b0,\n    0xe8362afa, 0xb0b6c82d, 0x19309e8e, 0x41b07c59, 0x8f26e31a,\n    0xd7a601cd, 0x7e20576e, 0x26a0b5b9, 0x6d2b8bf3, 0x35ab6924,\n    0x9c2d3f87, 0xc4addd50, 0x14768426, 0x4cf666f1, 0xe5703052,\n    0xbdf0d285, 0xf67beccf, 0xaefb0e18, 0x077d58bb, 0x5ffdba6c,\n    0x916b252f, 0xc9ebc7f8, 0x606d915b, 0x38ed738c, 0x73664dc6,\n    0x2be6af11, 0x8260f9b2, 0xdae01b65, 0x1e4dc635, 0x46cd24e2,\n    0xef4b7241, 0xb7cb9096, 0xfc40aedc, 0xa4c04c0b, 0x0d461aa8,\n    0x55c6f87f, 0x9b50673c, 0xc3d085eb, 0x6a56d348, 0x32d6319f,\n    0x795d0fd5, 0x21dded02, 0x885bbba1, 0xd0db5976, 0x28ec084d,\n    0x706cea9a, 0xd9eabc39, 0x816a5eee, 0xcae160a4, 0x92618273,\n    0x3be7d4d0, 0x63673607, 0xadf1a944, 0xf5714b93, 0x5cf71d30,\n    0x0477ffe7, 0x4ffcc1ad, 0x177c237a, 0xbefa75d9, 0xe67a970e,\n    0x22d74a5e, 0x7a57a889, 0xd3d1fe2a, 0x8b511cfd, 0xc0da22b7,\n    0x985ac060, 0x31dc96c3, 0x695c7414, 0xa7caeb57, 0xff4a0980,\n    0x56cc5f23, 0x0e4cbdf4, 0x45c783be, 0x1d476169, 0xb4c137ca,\n    0xec41d51d, 0x3c9a8c6b, 0x641a6ebc, 0xcd9c381f, 0x951cdac8,\n    0xde97e482, 0x86170655, 0x2f9150f6, 0x7711b221, 0xb9872d62,\n    0xe107cfb5, 0x48819916, 0x10017bc1, 0x5b8a458b, 0x030aa75c,\n    0xaa8cf1ff, 0xf20c1328, 0x36a1ce78, 0x6e212caf, 0xc7a77a0c,\n    0x9f2798db, 0xd4aca691, 0x8c2c4446, 0x25aa12e5, 0x7d2af032,\n    0xb3bc6f71, 0xeb3c8da6, 0x42badb05, 0x1a3a39d2, 0x51b10798,\n    0x0931e54f, 0xa0b7b3ec, 0xf837513b, 0x50d8119a, 0x0858f34d,\n    0xa1dea5ee, 0xf95e4739, 0xb2d57973, 0xea559ba4, 0x43d3cd07,\n    0x1b532fd0, 0xd5c5b093, 0x8d455244, 0x24c304e7, 0x7c43e630,\n    0x37c8d87a, 0x6f483aad, 0xc6ce6c0e, 0x9e4e8ed9, 0x5ae35389,\n    0x0263b15e, 0xabe5e7fd, 0xf365052a, 0xb8ee3b60, 0xe06ed9b7,\n    0x49e88f14, 0x11686dc3, 0xdffef280, 0x877e1057, 0x2ef846f4,\n    0x7678a423, 0x3df39a69, 0x657378be, 0xccf52e1d, 0x9475ccca,\n    0x44ae95bc, 0x1c2e776b, 0xb5a821c8, 0xed28c31f, 0xa6a3fd55,\n    0xfe231f82, 0x57a54921, 0x0f25abf6, 0xc1b334b5, 0x9933d662,\n    0x30b580c1, 0x68356216, 0x23be5c5c, 0x7b3ebe8b, 0xd2b8e828,\n    0x8a380aff, 0x4e95d7af, 0x16153578, 0xbf9363db, 0xe713810c,\n    0xac98bf46, 0xf4185d91, 0x5d9e0b32, 0x051ee9e5, 0xcb8876a6,\n    0x93089471, 0x3a8ec2d2, 0x620e2005, 0x29851e4f, 0x7105fc98,\n    0xd883aa3b, 0x800348ec, 0x783419d7, 0x20b4fb00, 0x8932ada3,\n    0xd1b24f74, 0x9a39713e, 0xc2b993e9, 0x6b3fc54a, 0x33bf279d,\n    0xfd29b8de, 0xa5a95a09, 0x0c2f0caa, 0x54afee7d, 0x1f24d037,\n    0x47a432e0, 0xee226443, 0xb6a28694, 0x720f5bc4, 0x2a8fb913,\n    0x8309efb0, 0xdb890d67, 0x9002332d, 0xc882d1fa, 0x61048759,\n    0x3984658e, 0xf712facd, 0xaf92181a, 0x06144eb9, 0x5e94ac6e,\n    0x151f9224, 0x4d9f70f3, 0xe4192650, 0xbc99c487, 0x6c429df1,\n    0x34c27f26, 0x9d442985, 0xc5c4cb52, 0x8e4ff518, 0xd6cf17cf,\n    0x7f49416c, 0x27c9a3bb, 0xe95f3cf8, 0xb1dfde2f, 0x1859888c,\n    0x40d96a5b, 0x0b525411, 0x53d2b6c6, 0xfa54e065, 0xa2d402b2,\n    0x6679dfe2, 0x3ef93d35, 0x977f6b96, 0xcfff8941, 0x8474b70b,\n    0xdcf455dc, 0x7572037f, 0x2df2e1a8, 0xe3647eeb, 0xbbe49c3c,\n    0x1262ca9f, 0x4ae22848, 0x01691602, 0x59e9f4d5, 0xf06fa276,\n    0xa8ef40a1},\n   {0x00000000, 0x463b6765, 0x8c76ceca, 0xca4da9af, 0x59ebed4e,\n    0x1fd08a2b, 0xd59d2384, 0x93a644e1, 0xb2d6db9d, 0xf4edbcf8,\n    0x3ea01557, 0x789b7232, 0xeb3d36d3, 0xad0651b6, 0x674bf819,\n    0x21709f7c, 0x25abc6e0, 0x6390a185, 0xa9dd082a, 0xefe66f4f,\n    0x7c402bae, 0x3a7b4ccb, 0xf036e564, 0xb60d8201, 0x977d1d7d,\n    0xd1467a18, 0x1b0bd3b7, 0x5d30b4d2, 0xce96f033, 0x88ad9756,\n    0x42e03ef9, 0x04db599c, 0x0b50fc1a, 0x4d6b9b7f, 0x872632d0,\n    0xc11d55b5, 0x52bb1154, 0x14807631, 0xdecddf9e, 0x98f6b8fb,\n    0xb9862787, 0xffbd40e2, 0x35f0e94d, 0x73cb8e28, 0xe06dcac9,\n    0xa656adac, 0x6c1b0403, 0x2a206366, 0x2efb3afa, 0x68c05d9f,\n    0xa28df430, 0xe4b69355, 0x7710d7b4, 0x312bb0d1, 0xfb66197e,\n    0xbd5d7e1b, 0x9c2de167, 0xda168602, 0x105b2fad, 0x566048c8,\n    0xc5c60c29, 0x83fd6b4c, 0x49b0c2e3, 0x0f8ba586, 0x16a0f835,\n    0x509b9f50, 0x9ad636ff, 0xdced519a, 0x4f4b157b, 0x0970721e,\n    0xc33ddbb1, 0x8506bcd4, 0xa47623a8, 0xe24d44cd, 0x2800ed62,\n    0x6e3b8a07, 0xfd9dcee6, 0xbba6a983, 0x71eb002c, 0x37d06749,\n    0x330b3ed5, 0x753059b0, 0xbf7df01f, 0xf946977a, 0x6ae0d39b,\n    0x2cdbb4fe, 0xe6961d51, 0xa0ad7a34, 0x81dde548, 0xc7e6822d,\n    0x0dab2b82, 0x4b904ce7, 0xd8360806, 0x9e0d6f63, 0x5440c6cc,\n    0x127ba1a9, 0x1df0042f, 0x5bcb634a, 0x9186cae5, 0xd7bdad80,\n    0x441be961, 0x02208e04, 0xc86d27ab, 0x8e5640ce, 0xaf26dfb2,\n    0xe91db8d7, 0x23501178, 0x656b761d, 0xf6cd32fc, 0xb0f65599,\n    0x7abbfc36, 0x3c809b53, 0x385bc2cf, 0x7e60a5aa, 0xb42d0c05,\n    0xf2166b60, 0x61b02f81, 0x278b48e4, 0xedc6e14b, 0xabfd862e,\n    0x8a8d1952, 0xccb67e37, 0x06fbd798, 0x40c0b0fd, 0xd366f41c,\n    0x955d9379, 0x5f103ad6, 0x192b5db3, 0x2c40f16b, 0x6a7b960e,\n    0xa0363fa1, 0xe60d58c4, 0x75ab1c25, 0x33907b40, 0xf9ddd2ef,\n    0xbfe6b58a, 0x9e962af6, 0xd8ad4d93, 0x12e0e43c, 0x54db8359,\n    0xc77dc7b8, 0x8146a0dd, 0x4b0b0972, 0x0d306e17, 0x09eb378b,\n    0x4fd050ee, 0x859df941, 0xc3a69e24, 0x5000dac5, 0x163bbda0,\n    0xdc76140f, 0x9a4d736a, 0xbb3dec16, 0xfd068b73, 0x374b22dc,\n    0x717045b9, 0xe2d60158, 0xa4ed663d, 0x6ea0cf92, 0x289ba8f7,\n    0x27100d71, 0x612b6a14, 0xab66c3bb, 0xed5da4de, 0x7efbe03f,\n    0x38c0875a, 0xf28d2ef5, 0xb4b64990, 0x95c6d6ec, 0xd3fdb189,\n    0x19b01826, 0x5f8b7f43, 0xcc2d3ba2, 0x8a165cc7, 0x405bf568,\n    0x0660920d, 0x02bbcb91, 0x4480acf4, 0x8ecd055b, 0xc8f6623e,\n    0x5b5026df, 0x1d6b41ba, 0xd726e815, 0x911d8f70, 0xb06d100c,\n    0xf6567769, 0x3c1bdec6, 0x7a20b9a3, 0xe986fd42, 0xafbd9a27,\n    0x65f03388, 0x23cb54ed, 0x3ae0095e, 0x7cdb6e3b, 0xb696c794,\n    0xf0ada0f1, 0x630be410, 0x25308375, 0xef7d2ada, 0xa9464dbf,\n    0x8836d2c3, 0xce0db5a6, 0x04401c09, 0x427b7b6c, 0xd1dd3f8d,\n    0x97e658e8, 0x5dabf147, 0x1b909622, 0x1f4bcfbe, 0x5970a8db,\n    0x933d0174, 0xd5066611, 0x46a022f0, 0x009b4595, 0xcad6ec3a,\n    0x8ced8b5f, 0xad9d1423, 0xeba67346, 0x21ebdae9, 0x67d0bd8c,\n    0xf476f96d, 0xb24d9e08, 0x780037a7, 0x3e3b50c2, 0x31b0f544,\n    0x778b9221, 0xbdc63b8e, 0xfbfd5ceb, 0x685b180a, 0x2e607f6f,\n    0xe42dd6c0, 0xa216b1a5, 0x83662ed9, 0xc55d49bc, 0x0f10e013,\n    0x492b8776, 0xda8dc397, 0x9cb6a4f2, 0x56fb0d5d, 0x10c06a38,\n    0x141b33a4, 0x522054c1, 0x986dfd6e, 0xde569a0b, 0x4df0deea,\n    0x0bcbb98f, 0xc1861020, 0x87bd7745, 0xa6cde839, 0xe0f68f5c,\n    0x2abb26f3, 0x6c804196, 0xff260577, 0xb91d6212, 0x7350cbbd,\n    0x356bacd8}};\n\n#endif\n\n#endif\n\n#if N == 6\n\n#if W == 8\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0x3db1ecdc, 0x7b63d9b8, 0x46d23564, 0xf6c7b370,\n    0xcb765fac, 0x8da46ac8, 0xb0158614, 0x36fe60a1, 0x0b4f8c7d,\n    0x4d9db919, 0x702c55c5, 0xc039d3d1, 0xfd883f0d, 0xbb5a0a69,\n    0x86ebe6b5, 0x6dfcc142, 0x504d2d9e, 0x169f18fa, 0x2b2ef426,\n    0x9b3b7232, 0xa68a9eee, 0xe058ab8a, 0xdde94756, 0x5b02a1e3,\n    0x66b34d3f, 0x2061785b, 0x1dd09487, 0xadc51293, 0x9074fe4f,\n    0xd6a6cb2b, 0xeb1727f7, 0xdbf98284, 0xe6486e58, 0xa09a5b3c,\n    0x9d2bb7e0, 0x2d3e31f4, 0x108fdd28, 0x565de84c, 0x6bec0490,\n    0xed07e225, 0xd0b60ef9, 0x96643b9d, 0xabd5d741, 0x1bc05155,\n    0x2671bd89, 0x60a388ed, 0x5d126431, 0xb60543c6, 0x8bb4af1a,\n    0xcd669a7e, 0xf0d776a2, 0x40c2f0b6, 0x7d731c6a, 0x3ba1290e,\n    0x0610c5d2, 0x80fb2367, 0xbd4acfbb, 0xfb98fadf, 0xc6291603,\n    0x763c9017, 0x4b8d7ccb, 0x0d5f49af, 0x30eea573, 0x6c820349,\n    0x5133ef95, 0x17e1daf1, 0x2a50362d, 0x9a45b039, 0xa7f45ce5,\n    0xe1266981, 0xdc97855d, 0x5a7c63e8, 0x67cd8f34, 0x211fba50,\n    0x1cae568c, 0xacbbd098, 0x910a3c44, 0xd7d80920, 0xea69e5fc,\n    0x017ec20b, 0x3ccf2ed7, 0x7a1d1bb3, 0x47acf76f, 0xf7b9717b,\n    0xca089da7, 0x8cdaa8c3, 0xb16b441f, 0x3780a2aa, 0x0a314e76,\n    0x4ce37b12, 0x715297ce, 0xc14711da, 0xfcf6fd06, 0xba24c862,\n    0x879524be, 0xb77b81cd, 0x8aca6d11, 0xcc185875, 0xf1a9b4a9,\n    0x41bc32bd, 0x7c0dde61, 0x3adfeb05, 0x076e07d9, 0x8185e16c,\n    0xbc340db0, 0xfae638d4, 0xc757d408, 0x7742521c, 0x4af3bec0,\n    0x0c218ba4, 0x31906778, 0xda87408f, 0xe736ac53, 0xa1e49937,\n    0x9c5575eb, 0x2c40f3ff, 0x11f11f23, 0x57232a47, 0x6a92c69b,\n    0xec79202e, 0xd1c8ccf2, 0x971af996, 0xaaab154a, 0x1abe935e,\n    0x270f7f82, 0x61dd4ae6, 0x5c6ca63a, 0xd9040692, 0xe4b5ea4e,\n    0xa267df2a, 0x9fd633f6, 0x2fc3b5e2, 0x1272593e, 0x54a06c5a,\n    0x69118086, 0xeffa6633, 0xd24b8aef, 0x9499bf8b, 0xa9285357,\n    0x193dd543, 0x248c399f, 0x625e0cfb, 0x5fefe027, 0xb4f8c7d0,\n    0x89492b0c, 0xcf9b1e68, 0xf22af2b4, 0x423f74a0, 0x7f8e987c,\n    0x395cad18, 0x04ed41c4, 0x8206a771, 0xbfb74bad, 0xf9657ec9,\n    0xc4d49215, 0x74c11401, 0x4970f8dd, 0x0fa2cdb9, 0x32132165,\n    0x02fd8416, 0x3f4c68ca, 0x799e5dae, 0x442fb172, 0xf43a3766,\n    0xc98bdbba, 0x8f59eede, 0xb2e80202, 0x3403e4b7, 0x09b2086b,\n    0x4f603d0f, 0x72d1d1d3, 0xc2c457c7, 0xff75bb1b, 0xb9a78e7f,\n    0x841662a3, 0x6f014554, 0x52b0a988, 0x14629cec, 0x29d37030,\n    0x99c6f624, 0xa4771af8, 0xe2a52f9c, 0xdf14c340, 0x59ff25f5,\n    0x644ec929, 0x229cfc4d, 0x1f2d1091, 0xaf389685, 0x92897a59,\n    0xd45b4f3d, 0xe9eaa3e1, 0xb58605db, 0x8837e907, 0xcee5dc63,\n    0xf35430bf, 0x4341b6ab, 0x7ef05a77, 0x38226f13, 0x059383cf,\n    0x8378657a, 0xbec989a6, 0xf81bbcc2, 0xc5aa501e, 0x75bfd60a,\n    0x480e3ad6, 0x0edc0fb2, 0x336de36e, 0xd87ac499, 0xe5cb2845,\n    0xa3191d21, 0x9ea8f1fd, 0x2ebd77e9, 0x130c9b35, 0x55deae51,\n    0x686f428d, 0xee84a438, 0xd33548e4, 0x95e77d80, 0xa856915c,\n    0x18431748, 0x25f2fb94, 0x6320cef0, 0x5e91222c, 0x6e7f875f,\n    0x53ce6b83, 0x151c5ee7, 0x28adb23b, 0x98b8342f, 0xa509d8f3,\n    0xe3dbed97, 0xde6a014b, 0x5881e7fe, 0x65300b22, 0x23e23e46,\n    0x1e53d29a, 0xae46548e, 0x93f7b852, 0xd5258d36, 0xe89461ea,\n    0x0383461d, 0x3e32aac1, 0x78e09fa5, 0x45517379, 0xf544f56d,\n    0xc8f519b1, 0x8e272cd5, 0xb396c009, 0x357d26bc, 0x08ccca60,\n    0x4e1eff04, 0x73af13d8, 0xc3ba95cc, 0xfe0b7910, 0xb8d94c74,\n    0x8568a0a8},\n   {0x00000000, 0x69790b65, 0xd2f216ca, 0xbb8b1daf, 0x7e952bd5,\n    0x17ec20b0, 0xac673d1f, 0xc51e367a, 0xfd2a57aa, 0x94535ccf,\n    0x2fd84160, 0x46a14a05, 0x83bf7c7f, 0xeac6771a, 0x514d6ab5,\n    0x383461d0, 0x2125a915, 0x485ca270, 0xf3d7bfdf, 0x9aaeb4ba,\n    0x5fb082c0, 0x36c989a5, 0x8d42940a, 0xe43b9f6f, 0xdc0ffebf,\n    0xb576f5da, 0x0efde875, 0x6784e310, 0xa29ad56a, 0xcbe3de0f,\n    0x7068c3a0, 0x1911c8c5, 0x424b522a, 0x2b32594f, 0x90b944e0,\n    0xf9c04f85, 0x3cde79ff, 0x55a7729a, 0xee2c6f35, 0x87556450,\n    0xbf610580, 0xd6180ee5, 0x6d93134a, 0x04ea182f, 0xc1f42e55,\n    0xa88d2530, 0x1306389f, 0x7a7f33fa, 0x636efb3f, 0x0a17f05a,\n    0xb19cedf5, 0xd8e5e690, 0x1dfbd0ea, 0x7482db8f, 0xcf09c620,\n    0xa670cd45, 0x9e44ac95, 0xf73da7f0, 0x4cb6ba5f, 0x25cfb13a,\n    0xe0d18740, 0x89a88c25, 0x3223918a, 0x5b5a9aef, 0x8496a454,\n    0xedefaf31, 0x5664b29e, 0x3f1db9fb, 0xfa038f81, 0x937a84e4,\n    0x28f1994b, 0x4188922e, 0x79bcf3fe, 0x10c5f89b, 0xab4ee534,\n    0xc237ee51, 0x0729d82b, 0x6e50d34e, 0xd5dbcee1, 0xbca2c584,\n    0xa5b30d41, 0xccca0624, 0x77411b8b, 0x1e3810ee, 0xdb262694,\n    0xb25f2df1, 0x09d4305e, 0x60ad3b3b, 0x58995aeb, 0x31e0518e,\n    0x8a6b4c21, 0xe3124744, 0x260c713e, 0x4f757a5b, 0xf4fe67f4,\n    0x9d876c91, 0xc6ddf67e, 0xafa4fd1b, 0x142fe0b4, 0x7d56ebd1,\n    0xb848ddab, 0xd131d6ce, 0x6abacb61, 0x03c3c004, 0x3bf7a1d4,\n    0x528eaab1, 0xe905b71e, 0x807cbc7b, 0x45628a01, 0x2c1b8164,\n    0x97909ccb, 0xfee997ae, 0xe7f85f6b, 0x8e81540e, 0x350a49a1,\n    0x5c7342c4, 0x996d74be, 0xf0147fdb, 0x4b9f6274, 0x22e66911,\n    0x1ad208c1, 0x73ab03a4, 0xc8201e0b, 0xa159156e, 0x64472314,\n    0x0d3e2871, 0xb6b535de, 0xdfcc3ebb, 0xd25c4ee9, 0xbb25458c,\n    0x00ae5823, 0x69d75346, 0xacc9653c, 0xc5b06e59, 0x7e3b73f6,\n    0x17427893, 0x2f761943, 0x460f1226, 0xfd840f89, 0x94fd04ec,\n    0x51e33296, 0x389a39f3, 0x8311245c, 0xea682f39, 0xf379e7fc,\n    0x9a00ec99, 0x218bf136, 0x48f2fa53, 0x8deccc29, 0xe495c74c,\n    0x5f1edae3, 0x3667d186, 0x0e53b056, 0x672abb33, 0xdca1a69c,\n    0xb5d8adf9, 0x70c69b83, 0x19bf90e6, 0xa2348d49, 0xcb4d862c,\n    0x90171cc3, 0xf96e17a6, 0x42e50a09, 0x2b9c016c, 0xee823716,\n    0x87fb3c73, 0x3c7021dc, 0x55092ab9, 0x6d3d4b69, 0x0444400c,\n    0xbfcf5da3, 0xd6b656c6, 0x13a860bc, 0x7ad16bd9, 0xc15a7676,\n    0xa8237d13, 0xb132b5d6, 0xd84bbeb3, 0x63c0a31c, 0x0ab9a879,\n    0xcfa79e03, 0xa6de9566, 0x1d5588c9, 0x742c83ac, 0x4c18e27c,\n    0x2561e919, 0x9eeaf4b6, 0xf793ffd3, 0x328dc9a9, 0x5bf4c2cc,\n    0xe07fdf63, 0x8906d406, 0x56caeabd, 0x3fb3e1d8, 0x8438fc77,\n    0xed41f712, 0x285fc168, 0x4126ca0d, 0xfaadd7a2, 0x93d4dcc7,\n    0xabe0bd17, 0xc299b672, 0x7912abdd, 0x106ba0b8, 0xd57596c2,\n    0xbc0c9da7, 0x07878008, 0x6efe8b6d, 0x77ef43a8, 0x1e9648cd,\n    0xa51d5562, 0xcc645e07, 0x097a687d, 0x60036318, 0xdb887eb7,\n    0xb2f175d2, 0x8ac51402, 0xe3bc1f67, 0x583702c8, 0x314e09ad,\n    0xf4503fd7, 0x9d2934b2, 0x26a2291d, 0x4fdb2278, 0x1481b897,\n    0x7df8b3f2, 0xc673ae5d, 0xaf0aa538, 0x6a149342, 0x036d9827,\n    0xb8e68588, 0xd19f8eed, 0xe9abef3d, 0x80d2e458, 0x3b59f9f7,\n    0x5220f292, 0x973ec4e8, 0xfe47cf8d, 0x45ccd222, 0x2cb5d947,\n    0x35a41182, 0x5cdd1ae7, 0xe7560748, 0x8e2f0c2d, 0x4b313a57,\n    0x22483132, 0x99c32c9d, 0xf0ba27f8, 0xc88e4628, 0xa1f74d4d,\n    0x1a7c50e2, 0x73055b87, 0xb61b6dfd, 0xdf626698, 0x64e97b37,\n    0x0d907052},\n   {0x00000000, 0x7fc99b93, 0xff933726, 0x805aacb5, 0x2457680d,\n    0x5b9ef39e, 0xdbc45f2b, 0xa40dc4b8, 0x48aed01a, 0x37674b89,\n    0xb73de73c, 0xc8f47caf, 0x6cf9b817, 0x13302384, 0x936a8f31,\n    0xeca314a2, 0x915da034, 0xee943ba7, 0x6ece9712, 0x11070c81,\n    0xb50ac839, 0xcac353aa, 0x4a99ff1f, 0x3550648c, 0xd9f3702e,\n    0xa63aebbd, 0x26604708, 0x59a9dc9b, 0xfda41823, 0x826d83b0,\n    0x02372f05, 0x7dfeb496, 0xf9ca4629, 0x8603ddba, 0x0659710f,\n    0x7990ea9c, 0xdd9d2e24, 0xa254b5b7, 0x220e1902, 0x5dc78291,\n    0xb1649633, 0xcead0da0, 0x4ef7a115, 0x313e3a86, 0x9533fe3e,\n    0xeafa65ad, 0x6aa0c918, 0x1569528b, 0x6897e61d, 0x175e7d8e,\n    0x9704d13b, 0xe8cd4aa8, 0x4cc08e10, 0x33091583, 0xb353b936,\n    0xcc9a22a5, 0x20393607, 0x5ff0ad94, 0xdfaa0121, 0xa0639ab2,\n    0x046e5e0a, 0x7ba7c599, 0xfbfd692c, 0x8434f2bf, 0x28e58a13,\n    0x572c1180, 0xd776bd35, 0xa8bf26a6, 0x0cb2e21e, 0x737b798d,\n    0xf321d538, 0x8ce84eab, 0x604b5a09, 0x1f82c19a, 0x9fd86d2f,\n    0xe011f6bc, 0x441c3204, 0x3bd5a997, 0xbb8f0522, 0xc4469eb1,\n    0xb9b82a27, 0xc671b1b4, 0x462b1d01, 0x39e28692, 0x9def422a,\n    0xe226d9b9, 0x627c750c, 0x1db5ee9f, 0xf116fa3d, 0x8edf61ae,\n    0x0e85cd1b, 0x714c5688, 0xd5419230, 0xaa8809a3, 0x2ad2a516,\n    0x551b3e85, 0xd12fcc3a, 0xaee657a9, 0x2ebcfb1c, 0x5175608f,\n    0xf578a437, 0x8ab13fa4, 0x0aeb9311, 0x75220882, 0x99811c20,\n    0xe64887b3, 0x66122b06, 0x19dbb095, 0xbdd6742d, 0xc21fefbe,\n    0x4245430b, 0x3d8cd898, 0x40726c0e, 0x3fbbf79d, 0xbfe15b28,\n    0xc028c0bb, 0x64250403, 0x1bec9f90, 0x9bb63325, 0xe47fa8b6,\n    0x08dcbc14, 0x77152787, 0xf74f8b32, 0x888610a1, 0x2c8bd419,\n    0x53424f8a, 0xd318e33f, 0xacd178ac, 0x51cb1426, 0x2e028fb5,\n    0xae582300, 0xd191b893, 0x759c7c2b, 0x0a55e7b8, 0x8a0f4b0d,\n    0xf5c6d09e, 0x1965c43c, 0x66ac5faf, 0xe6f6f31a, 0x993f6889,\n    0x3d32ac31, 0x42fb37a2, 0xc2a19b17, 0xbd680084, 0xc096b412,\n    0xbf5f2f81, 0x3f058334, 0x40cc18a7, 0xe4c1dc1f, 0x9b08478c,\n    0x1b52eb39, 0x649b70aa, 0x88386408, 0xf7f1ff9b, 0x77ab532e,\n    0x0862c8bd, 0xac6f0c05, 0xd3a69796, 0x53fc3b23, 0x2c35a0b0,\n    0xa801520f, 0xd7c8c99c, 0x57926529, 0x285bfeba, 0x8c563a02,\n    0xf39fa191, 0x73c50d24, 0x0c0c96b7, 0xe0af8215, 0x9f661986,\n    0x1f3cb533, 0x60f52ea0, 0xc4f8ea18, 0xbb31718b, 0x3b6bdd3e,\n    0x44a246ad, 0x395cf23b, 0x469569a8, 0xc6cfc51d, 0xb9065e8e,\n    0x1d0b9a36, 0x62c201a5, 0xe298ad10, 0x9d513683, 0x71f22221,\n    0x0e3bb9b2, 0x8e611507, 0xf1a88e94, 0x55a54a2c, 0x2a6cd1bf,\n    0xaa367d0a, 0xd5ffe699, 0x792e9e35, 0x06e705a6, 0x86bda913,\n    0xf9743280, 0x5d79f638, 0x22b06dab, 0xa2eac11e, 0xdd235a8d,\n    0x31804e2f, 0x4e49d5bc, 0xce137909, 0xb1dae29a, 0x15d72622,\n    0x6a1ebdb1, 0xea441104, 0x958d8a97, 0xe8733e01, 0x97baa592,\n    0x17e00927, 0x682992b4, 0xcc24560c, 0xb3edcd9f, 0x33b7612a,\n    0x4c7efab9, 0xa0ddee1b, 0xdf147588, 0x5f4ed93d, 0x208742ae,\n    0x848a8616, 0xfb431d85, 0x7b19b130, 0x04d02aa3, 0x80e4d81c,\n    0xff2d438f, 0x7f77ef3a, 0x00be74a9, 0xa4b3b011, 0xdb7a2b82,\n    0x5b208737, 0x24e91ca4, 0xc84a0806, 0xb7839395, 0x37d93f20,\n    0x4810a4b3, 0xec1d600b, 0x93d4fb98, 0x138e572d, 0x6c47ccbe,\n    0x11b97828, 0x6e70e3bb, 0xee2a4f0e, 0x91e3d49d, 0x35ee1025,\n    0x4a278bb6, 0xca7d2703, 0xb5b4bc90, 0x5917a832, 0x26de33a1,\n    0xa6849f14, 0xd94d0487, 0x7d40c03f, 0x02895bac, 0x82d3f719,\n    0xfd1a6c8a},\n   {0x00000000, 0xa396284c, 0x9c5d56d9, 0x3fcb7e95, 0xe3cbabf3,\n    0x405d83bf, 0x7f96fd2a, 0xdc00d566, 0x1ce651a7, 0xbf7079eb,\n    0x80bb077e, 0x232d2f32, 0xff2dfa54, 0x5cbbd218, 0x6370ac8d,\n    0xc0e684c1, 0x39cca34e, 0x9a5a8b02, 0xa591f597, 0x0607dddb,\n    0xda0708bd, 0x799120f1, 0x465a5e64, 0xe5cc7628, 0x252af2e9,\n    0x86bcdaa5, 0xb977a430, 0x1ae18c7c, 0xc6e1591a, 0x65777156,\n    0x5abc0fc3, 0xf92a278f, 0x7399469c, 0xd00f6ed0, 0xefc41045,\n    0x4c523809, 0x9052ed6f, 0x33c4c523, 0x0c0fbbb6, 0xaf9993fa,\n    0x6f7f173b, 0xcce93f77, 0xf32241e2, 0x50b469ae, 0x8cb4bcc8,\n    0x2f229484, 0x10e9ea11, 0xb37fc25d, 0x4a55e5d2, 0xe9c3cd9e,\n    0xd608b30b, 0x759e9b47, 0xa99e4e21, 0x0a08666d, 0x35c318f8,\n    0x965530b4, 0x56b3b475, 0xf5259c39, 0xcaeee2ac, 0x6978cae0,\n    0xb5781f86, 0x16ee37ca, 0x2925495f, 0x8ab36113, 0xe7328d38,\n    0x44a4a574, 0x7b6fdbe1, 0xd8f9f3ad, 0x04f926cb, 0xa76f0e87,\n    0x98a47012, 0x3b32585e, 0xfbd4dc9f, 0x5842f4d3, 0x67898a46,\n    0xc41fa20a, 0x181f776c, 0xbb895f20, 0x844221b5, 0x27d409f9,\n    0xdefe2e76, 0x7d68063a, 0x42a378af, 0xe13550e3, 0x3d358585,\n    0x9ea3adc9, 0xa168d35c, 0x02fefb10, 0xc2187fd1, 0x618e579d,\n    0x5e452908, 0xfdd30144, 0x21d3d422, 0x8245fc6e, 0xbd8e82fb,\n    0x1e18aab7, 0x94abcba4, 0x373de3e8, 0x08f69d7d, 0xab60b531,\n    0x77606057, 0xd4f6481b, 0xeb3d368e, 0x48ab1ec2, 0x884d9a03,\n    0x2bdbb24f, 0x1410ccda, 0xb786e496, 0x6b8631f0, 0xc81019bc,\n    0xf7db6729, 0x544d4f65, 0xad6768ea, 0x0ef140a6, 0x313a3e33,\n    0x92ac167f, 0x4eacc319, 0xed3aeb55, 0xd2f195c0, 0x7167bd8c,\n    0xb181394d, 0x12171101, 0x2ddc6f94, 0x8e4a47d8, 0x524a92be,\n    0xf1dcbaf2, 0xce17c467, 0x6d81ec2b, 0x15141c31, 0xb682347d,\n    0x89494ae8, 0x2adf62a4, 0xf6dfb7c2, 0x55499f8e, 0x6a82e11b,\n    0xc914c957, 0x09f24d96, 0xaa6465da, 0x95af1b4f, 0x36393303,\n    0xea39e665, 0x49afce29, 0x7664b0bc, 0xd5f298f0, 0x2cd8bf7f,\n    0x8f4e9733, 0xb085e9a6, 0x1313c1ea, 0xcf13148c, 0x6c853cc0,\n    0x534e4255, 0xf0d86a19, 0x303eeed8, 0x93a8c694, 0xac63b801,\n    0x0ff5904d, 0xd3f5452b, 0x70636d67, 0x4fa813f2, 0xec3e3bbe,\n    0x668d5aad, 0xc51b72e1, 0xfad00c74, 0x59462438, 0x8546f15e,\n    0x26d0d912, 0x191ba787, 0xba8d8fcb, 0x7a6b0b0a, 0xd9fd2346,\n    0xe6365dd3, 0x45a0759f, 0x99a0a0f9, 0x3a3688b5, 0x05fdf620,\n    0xa66bde6c, 0x5f41f9e3, 0xfcd7d1af, 0xc31caf3a, 0x608a8776,\n    0xbc8a5210, 0x1f1c7a5c, 0x20d704c9, 0x83412c85, 0x43a7a844,\n    0xe0318008, 0xdffafe9d, 0x7c6cd6d1, 0xa06c03b7, 0x03fa2bfb,\n    0x3c31556e, 0x9fa77d22, 0xf2269109, 0x51b0b945, 0x6e7bc7d0,\n    0xcdedef9c, 0x11ed3afa, 0xb27b12b6, 0x8db06c23, 0x2e26446f,\n    0xeec0c0ae, 0x4d56e8e2, 0x729d9677, 0xd10bbe3b, 0x0d0b6b5d,\n    0xae9d4311, 0x91563d84, 0x32c015c8, 0xcbea3247, 0x687c1a0b,\n    0x57b7649e, 0xf4214cd2, 0x282199b4, 0x8bb7b1f8, 0xb47ccf6d,\n    0x17eae721, 0xd70c63e0, 0x749a4bac, 0x4b513539, 0xe8c71d75,\n    0x34c7c813, 0x9751e05f, 0xa89a9eca, 0x0b0cb686, 0x81bfd795,\n    0x2229ffd9, 0x1de2814c, 0xbe74a900, 0x62747c66, 0xc1e2542a,\n    0xfe292abf, 0x5dbf02f3, 0x9d598632, 0x3ecfae7e, 0x0104d0eb,\n    0xa292f8a7, 0x7e922dc1, 0xdd04058d, 0xe2cf7b18, 0x41595354,\n    0xb87374db, 0x1be55c97, 0x242e2202, 0x87b80a4e, 0x5bb8df28,\n    0xf82ef764, 0xc7e589f1, 0x6473a1bd, 0xa495257c, 0x07030d30,\n    0x38c873a5, 0x9b5e5be9, 0x475e8e8f, 0xe4c8a6c3, 0xdb03d856,\n    0x7895f01a},\n   {0x00000000, 0x2a283862, 0x545070c4, 0x7e7848a6, 0xa8a0e188,\n    0x8288d9ea, 0xfcf0914c, 0xd6d8a92e, 0x8a30c551, 0xa018fd33,\n    0xde60b595, 0xf4488df7, 0x229024d9, 0x08b81cbb, 0x76c0541d,\n    0x5ce86c7f, 0xcf108ce3, 0xe538b481, 0x9b40fc27, 0xb168c445,\n    0x67b06d6b, 0x4d985509, 0x33e01daf, 0x19c825cd, 0x452049b2,\n    0x6f0871d0, 0x11703976, 0x3b580114, 0xed80a83a, 0xc7a89058,\n    0xb9d0d8fe, 0x93f8e09c, 0x45501f87, 0x6f7827e5, 0x11006f43,\n    0x3b285721, 0xedf0fe0f, 0xc7d8c66d, 0xb9a08ecb, 0x9388b6a9,\n    0xcf60dad6, 0xe548e2b4, 0x9b30aa12, 0xb1189270, 0x67c03b5e,\n    0x4de8033c, 0x33904b9a, 0x19b873f8, 0x8a409364, 0xa068ab06,\n    0xde10e3a0, 0xf438dbc2, 0x22e072ec, 0x08c84a8e, 0x76b00228,\n    0x5c983a4a, 0x00705635, 0x2a586e57, 0x542026f1, 0x7e081e93,\n    0xa8d0b7bd, 0x82f88fdf, 0xfc80c779, 0xd6a8ff1b, 0x8aa03f0e,\n    0xa088076c, 0xdef04fca, 0xf4d877a8, 0x2200de86, 0x0828e6e4,\n    0x7650ae42, 0x5c789620, 0x0090fa5f, 0x2ab8c23d, 0x54c08a9b,\n    0x7ee8b2f9, 0xa8301bd7, 0x821823b5, 0xfc606b13, 0xd6485371,\n    0x45b0b3ed, 0x6f988b8f, 0x11e0c329, 0x3bc8fb4b, 0xed105265,\n    0xc7386a07, 0xb94022a1, 0x93681ac3, 0xcf8076bc, 0xe5a84ede,\n    0x9bd00678, 0xb1f83e1a, 0x67209734, 0x4d08af56, 0x3370e7f0,\n    0x1958df92, 0xcff02089, 0xe5d818eb, 0x9ba0504d, 0xb188682f,\n    0x6750c101, 0x4d78f963, 0x3300b1c5, 0x192889a7, 0x45c0e5d8,\n    0x6fe8ddba, 0x1190951c, 0x3bb8ad7e, 0xed600450, 0xc7483c32,\n    0xb9307494, 0x93184cf6, 0x00e0ac6a, 0x2ac89408, 0x54b0dcae,\n    0x7e98e4cc, 0xa8404de2, 0x82687580, 0xfc103d26, 0xd6380544,\n    0x8ad0693b, 0xa0f85159, 0xde8019ff, 0xf4a8219d, 0x227088b3,\n    0x0858b0d1, 0x7620f877, 0x5c08c015, 0xce31785d, 0xe419403f,\n    0x9a610899, 0xb04930fb, 0x669199d5, 0x4cb9a1b7, 0x32c1e911,\n    0x18e9d173, 0x4401bd0c, 0x6e29856e, 0x1051cdc8, 0x3a79f5aa,\n    0xeca15c84, 0xc68964e6, 0xb8f12c40, 0x92d91422, 0x0121f4be,\n    0x2b09ccdc, 0x5571847a, 0x7f59bc18, 0xa9811536, 0x83a92d54,\n    0xfdd165f2, 0xd7f95d90, 0x8b1131ef, 0xa139098d, 0xdf41412b,\n    0xf5697949, 0x23b1d067, 0x0999e805, 0x77e1a0a3, 0x5dc998c1,\n    0x8b6167da, 0xa1495fb8, 0xdf31171e, 0xf5192f7c, 0x23c18652,\n    0x09e9be30, 0x7791f696, 0x5db9cef4, 0x0151a28b, 0x2b799ae9,\n    0x5501d24f, 0x7f29ea2d, 0xa9f14303, 0x83d97b61, 0xfda133c7,\n    0xd7890ba5, 0x4471eb39, 0x6e59d35b, 0x10219bfd, 0x3a09a39f,\n    0xecd10ab1, 0xc6f932d3, 0xb8817a75, 0x92a94217, 0xce412e68,\n    0xe469160a, 0x9a115eac, 0xb03966ce, 0x66e1cfe0, 0x4cc9f782,\n    0x32b1bf24, 0x18998746, 0x44914753, 0x6eb97f31, 0x10c13797,\n    0x3ae90ff5, 0xec31a6db, 0xc6199eb9, 0xb861d61f, 0x9249ee7d,\n    0xcea18202, 0xe489ba60, 0x9af1f2c6, 0xb0d9caa4, 0x6601638a,\n    0x4c295be8, 0x3251134e, 0x18792b2c, 0x8b81cbb0, 0xa1a9f3d2,\n    0xdfd1bb74, 0xf5f98316, 0x23212a38, 0x0909125a, 0x77715afc,\n    0x5d59629e, 0x01b10ee1, 0x2b993683, 0x55e17e25, 0x7fc94647,\n    0xa911ef69, 0x8339d70b, 0xfd419fad, 0xd769a7cf, 0x01c158d4,\n    0x2be960b6, 0x55912810, 0x7fb91072, 0xa961b95c, 0x8349813e,\n    0xfd31c998, 0xd719f1fa, 0x8bf19d85, 0xa1d9a5e7, 0xdfa1ed41,\n    0xf589d523, 0x23517c0d, 0x0979446f, 0x77010cc9, 0x5d2934ab,\n    0xced1d437, 0xe4f9ec55, 0x9a81a4f3, 0xb0a99c91, 0x667135bf,\n    0x4c590ddd, 0x3221457b, 0x18097d19, 0x44e11166, 0x6ec92904,\n    0x10b161a2, 0x3a9959c0, 0xec41f0ee, 0xc669c88c, 0xb811802a,\n    0x9239b848},\n   {0x00000000, 0x4713f6fb, 0x8e27edf6, 0xc9341b0d, 0xc73eddad,\n    0x802d2b56, 0x4919305b, 0x0e0ac6a0, 0x550cbd1b, 0x121f4be0,\n    0xdb2b50ed, 0x9c38a616, 0x923260b6, 0xd521964d, 0x1c158d40,\n    0x5b067bbb, 0xaa197a36, 0xed0a8ccd, 0x243e97c0, 0x632d613b,\n    0x6d27a79b, 0x2a345160, 0xe3004a6d, 0xa413bc96, 0xff15c72d,\n    0xb80631d6, 0x71322adb, 0x3621dc20, 0x382b1a80, 0x7f38ec7b,\n    0xb60cf776, 0xf11f018d, 0x8f43f22d, 0xc85004d6, 0x01641fdb,\n    0x4677e920, 0x487d2f80, 0x0f6ed97b, 0xc65ac276, 0x8149348d,\n    0xda4f4f36, 0x9d5cb9cd, 0x5468a2c0, 0x137b543b, 0x1d71929b,\n    0x5a626460, 0x93567f6d, 0xd4458996, 0x255a881b, 0x62497ee0,\n    0xab7d65ed, 0xec6e9316, 0xe26455b6, 0xa577a34d, 0x6c43b840,\n    0x2b504ebb, 0x70563500, 0x3745c3fb, 0xfe71d8f6, 0xb9622e0d,\n    0xb768e8ad, 0xf07b1e56, 0x394f055b, 0x7e5cf3a0, 0xc5f6e21b,\n    0x82e514e0, 0x4bd10fed, 0x0cc2f916, 0x02c83fb6, 0x45dbc94d,\n    0x8cefd240, 0xcbfc24bb, 0x90fa5f00, 0xd7e9a9fb, 0x1eddb2f6,\n    0x59ce440d, 0x57c482ad, 0x10d77456, 0xd9e36f5b, 0x9ef099a0,\n    0x6fef982d, 0x28fc6ed6, 0xe1c875db, 0xa6db8320, 0xa8d14580,\n    0xefc2b37b, 0x26f6a876, 0x61e55e8d, 0x3ae32536, 0x7df0d3cd,\n    0xb4c4c8c0, 0xf3d73e3b, 0xfdddf89b, 0xbace0e60, 0x73fa156d,\n    0x34e9e396, 0x4ab51036, 0x0da6e6cd, 0xc492fdc0, 0x83810b3b,\n    0x8d8bcd9b, 0xca983b60, 0x03ac206d, 0x44bfd696, 0x1fb9ad2d,\n    0x58aa5bd6, 0x919e40db, 0xd68db620, 0xd8877080, 0x9f94867b,\n    0x56a09d76, 0x11b36b8d, 0xe0ac6a00, 0xa7bf9cfb, 0x6e8b87f6,\n    0x2998710d, 0x2792b7ad, 0x60814156, 0xa9b55a5b, 0xeea6aca0,\n    0xb5a0d71b, 0xf2b321e0, 0x3b873aed, 0x7c94cc16, 0x729e0ab6,\n    0x358dfc4d, 0xfcb9e740, 0xbbaa11bb, 0x509cc277, 0x178f348c,\n    0xdebb2f81, 0x99a8d97a, 0x97a21fda, 0xd0b1e921, 0x1985f22c,\n    0x5e9604d7, 0x05907f6c, 0x42838997, 0x8bb7929a, 0xcca46461,\n    0xc2aea2c1, 0x85bd543a, 0x4c894f37, 0x0b9ab9cc, 0xfa85b841,\n    0xbd964eba, 0x74a255b7, 0x33b1a34c, 0x3dbb65ec, 0x7aa89317,\n    0xb39c881a, 0xf48f7ee1, 0xaf89055a, 0xe89af3a1, 0x21aee8ac,\n    0x66bd1e57, 0x68b7d8f7, 0x2fa42e0c, 0xe6903501, 0xa183c3fa,\n    0xdfdf305a, 0x98ccc6a1, 0x51f8ddac, 0x16eb2b57, 0x18e1edf7,\n    0x5ff21b0c, 0x96c60001, 0xd1d5f6fa, 0x8ad38d41, 0xcdc07bba,\n    0x04f460b7, 0x43e7964c, 0x4ded50ec, 0x0afea617, 0xc3cabd1a,\n    0x84d94be1, 0x75c64a6c, 0x32d5bc97, 0xfbe1a79a, 0xbcf25161,\n    0xb2f897c1, 0xf5eb613a, 0x3cdf7a37, 0x7bcc8ccc, 0x20caf777,\n    0x67d9018c, 0xaeed1a81, 0xe9feec7a, 0xe7f42ada, 0xa0e7dc21,\n    0x69d3c72c, 0x2ec031d7, 0x956a206c, 0xd279d697, 0x1b4dcd9a,\n    0x5c5e3b61, 0x5254fdc1, 0x15470b3a, 0xdc731037, 0x9b60e6cc,\n    0xc0669d77, 0x87756b8c, 0x4e417081, 0x0952867a, 0x075840da,\n    0x404bb621, 0x897fad2c, 0xce6c5bd7, 0x3f735a5a, 0x7860aca1,\n    0xb154b7ac, 0xf6474157, 0xf84d87f7, 0xbf5e710c, 0x766a6a01,\n    0x31799cfa, 0x6a7fe741, 0x2d6c11ba, 0xe4580ab7, 0xa34bfc4c,\n    0xad413aec, 0xea52cc17, 0x2366d71a, 0x647521e1, 0x1a29d241,\n    0x5d3a24ba, 0x940e3fb7, 0xd31dc94c, 0xdd170fec, 0x9a04f917,\n    0x5330e21a, 0x142314e1, 0x4f256f5a, 0x083699a1, 0xc10282ac,\n    0x86117457, 0x881bb2f7, 0xcf08440c, 0x063c5f01, 0x412fa9fa,\n    0xb030a877, 0xf7235e8c, 0x3e174581, 0x7904b37a, 0x770e75da,\n    0x301d8321, 0xf929982c, 0xbe3a6ed7, 0xe53c156c, 0xa22fe397,\n    0x6b1bf89a, 0x2c080e61, 0x2202c8c1, 0x65113e3a, 0xac252537,\n    0xeb36d3cc},\n   {0x00000000, 0xa13984ee, 0x99020f9d, 0x383b8b73, 0xe975197b,\n    0x484c9d95, 0x707716e6, 0xd14e9208, 0x099b34b7, 0xa8a2b059,\n    0x90993b2a, 0x31a0bfc4, 0xe0ee2dcc, 0x41d7a922, 0x79ec2251,\n    0xd8d5a6bf, 0x1336696e, 0xb20fed80, 0x8a3466f3, 0x2b0de21d,\n    0xfa437015, 0x5b7af4fb, 0x63417f88, 0xc278fb66, 0x1aad5dd9,\n    0xbb94d937, 0x83af5244, 0x2296d6aa, 0xf3d844a2, 0x52e1c04c,\n    0x6ada4b3f, 0xcbe3cfd1, 0x266cd2dc, 0x87555632, 0xbf6edd41,\n    0x1e5759af, 0xcf19cba7, 0x6e204f49, 0x561bc43a, 0xf72240d4,\n    0x2ff7e66b, 0x8ece6285, 0xb6f5e9f6, 0x17cc6d18, 0xc682ff10,\n    0x67bb7bfe, 0x5f80f08d, 0xfeb97463, 0x355abbb2, 0x94633f5c,\n    0xac58b42f, 0x0d6130c1, 0xdc2fa2c9, 0x7d162627, 0x452dad54,\n    0xe41429ba, 0x3cc18f05, 0x9df80beb, 0xa5c38098, 0x04fa0476,\n    0xd5b4967e, 0x748d1290, 0x4cb699e3, 0xed8f1d0d, 0x4cd9a5b8,\n    0xede02156, 0xd5dbaa25, 0x74e22ecb, 0xa5acbcc3, 0x0495382d,\n    0x3caeb35e, 0x9d9737b0, 0x4542910f, 0xe47b15e1, 0xdc409e92,\n    0x7d791a7c, 0xac378874, 0x0d0e0c9a, 0x353587e9, 0x940c0307,\n    0x5fefccd6, 0xfed64838, 0xc6edc34b, 0x67d447a5, 0xb69ad5ad,\n    0x17a35143, 0x2f98da30, 0x8ea15ede, 0x5674f861, 0xf74d7c8f,\n    0xcf76f7fc, 0x6e4f7312, 0xbf01e11a, 0x1e3865f4, 0x2603ee87,\n    0x873a6a69, 0x6ab57764, 0xcb8cf38a, 0xf3b778f9, 0x528efc17,\n    0x83c06e1f, 0x22f9eaf1, 0x1ac26182, 0xbbfbe56c, 0x632e43d3,\n    0xc217c73d, 0xfa2c4c4e, 0x5b15c8a0, 0x8a5b5aa8, 0x2b62de46,\n    0x13595535, 0xb260d1db, 0x79831e0a, 0xd8ba9ae4, 0xe0811197,\n    0x41b89579, 0x90f60771, 0x31cf839f, 0x09f408ec, 0xa8cd8c02,\n    0x70182abd, 0xd121ae53, 0xe91a2520, 0x4823a1ce, 0x996d33c6,\n    0x3854b728, 0x006f3c5b, 0xa156b8b5, 0x99b34b70, 0x388acf9e,\n    0x00b144ed, 0xa188c003, 0x70c6520b, 0xd1ffd6e5, 0xe9c45d96,\n    0x48fdd978, 0x90287fc7, 0x3111fb29, 0x092a705a, 0xa813f4b4,\n    0x795d66bc, 0xd864e252, 0xe05f6921, 0x4166edcf, 0x8a85221e,\n    0x2bbca6f0, 0x13872d83, 0xb2bea96d, 0x63f03b65, 0xc2c9bf8b,\n    0xfaf234f8, 0x5bcbb016, 0x831e16a9, 0x22279247, 0x1a1c1934,\n    0xbb259dda, 0x6a6b0fd2, 0xcb528b3c, 0xf369004f, 0x525084a1,\n    0xbfdf99ac, 0x1ee61d42, 0x26dd9631, 0x87e412df, 0x56aa80d7,\n    0xf7930439, 0xcfa88f4a, 0x6e910ba4, 0xb644ad1b, 0x177d29f5,\n    0x2f46a286, 0x8e7f2668, 0x5f31b460, 0xfe08308e, 0xc633bbfd,\n    0x670a3f13, 0xace9f0c2, 0x0dd0742c, 0x35ebff5f, 0x94d27bb1,\n    0x459ce9b9, 0xe4a56d57, 0xdc9ee624, 0x7da762ca, 0xa572c475,\n    0x044b409b, 0x3c70cbe8, 0x9d494f06, 0x4c07dd0e, 0xed3e59e0,\n    0xd505d293, 0x743c567d, 0xd56aeec8, 0x74536a26, 0x4c68e155,\n    0xed5165bb, 0x3c1ff7b3, 0x9d26735d, 0xa51df82e, 0x04247cc0,\n    0xdcf1da7f, 0x7dc85e91, 0x45f3d5e2, 0xe4ca510c, 0x3584c304,\n    0x94bd47ea, 0xac86cc99, 0x0dbf4877, 0xc65c87a6, 0x67650348,\n    0x5f5e883b, 0xfe670cd5, 0x2f299edd, 0x8e101a33, 0xb62b9140,\n    0x171215ae, 0xcfc7b311, 0x6efe37ff, 0x56c5bc8c, 0xf7fc3862,\n    0x26b2aa6a, 0x878b2e84, 0xbfb0a5f7, 0x1e892119, 0xf3063c14,\n    0x523fb8fa, 0x6a043389, 0xcb3db767, 0x1a73256f, 0xbb4aa181,\n    0x83712af2, 0x2248ae1c, 0xfa9d08a3, 0x5ba48c4d, 0x639f073e,\n    0xc2a683d0, 0x13e811d8, 0xb2d19536, 0x8aea1e45, 0x2bd39aab,\n    0xe030557a, 0x4109d194, 0x79325ae7, 0xd80bde09, 0x09454c01,\n    0xa87cc8ef, 0x9047439c, 0x317ec772, 0xe9ab61cd, 0x4892e523,\n    0x70a96e50, 0xd190eabe, 0x00de78b6, 0xa1e7fc58, 0x99dc772b,\n    0x38e5f3c5},\n   {0x00000000, 0xe81790a1, 0x0b5e2703, 0xe349b7a2, 0x16bc4e06,\n    0xfeabdea7, 0x1de26905, 0xf5f5f9a4, 0x2d789c0c, 0xc56f0cad,\n    0x2626bb0f, 0xce312bae, 0x3bc4d20a, 0xd3d342ab, 0x309af509,\n    0xd88d65a8, 0x5af13818, 0xb2e6a8b9, 0x51af1f1b, 0xb9b88fba,\n    0x4c4d761e, 0xa45ae6bf, 0x4713511d, 0xaf04c1bc, 0x7789a414,\n    0x9f9e34b5, 0x7cd78317, 0x94c013b6, 0x6135ea12, 0x89227ab3,\n    0x6a6bcd11, 0x827c5db0, 0xb5e27030, 0x5df5e091, 0xbebc5733,\n    0x56abc792, 0xa35e3e36, 0x4b49ae97, 0xa8001935, 0x40178994,\n    0x989aec3c, 0x708d7c9d, 0x93c4cb3f, 0x7bd35b9e, 0x8e26a23a,\n    0x6631329b, 0x85788539, 0x6d6f1598, 0xef134828, 0x0704d889,\n    0xe44d6f2b, 0x0c5aff8a, 0xf9af062e, 0x11b8968f, 0xf2f1212d,\n    0x1ae6b18c, 0xc26bd424, 0x2a7c4485, 0xc935f327, 0x21226386,\n    0xd4d79a22, 0x3cc00a83, 0xdf89bd21, 0x379e2d80, 0xb0b5e621,\n    0x58a27680, 0xbbebc122, 0x53fc5183, 0xa609a827, 0x4e1e3886,\n    0xad578f24, 0x45401f85, 0x9dcd7a2d, 0x75daea8c, 0x96935d2e,\n    0x7e84cd8f, 0x8b71342b, 0x6366a48a, 0x802f1328, 0x68388389,\n    0xea44de39, 0x02534e98, 0xe11af93a, 0x090d699b, 0xfcf8903f,\n    0x14ef009e, 0xf7a6b73c, 0x1fb1279d, 0xc73c4235, 0x2f2bd294,\n    0xcc626536, 0x2475f597, 0xd1800c33, 0x39979c92, 0xdade2b30,\n    0x32c9bb91, 0x05579611, 0xed4006b0, 0x0e09b112, 0xe61e21b3,\n    0x13ebd817, 0xfbfc48b6, 0x18b5ff14, 0xf0a26fb5, 0x282f0a1d,\n    0xc0389abc, 0x23712d1e, 0xcb66bdbf, 0x3e93441b, 0xd684d4ba,\n    0x35cd6318, 0xdddaf3b9, 0x5fa6ae09, 0xb7b13ea8, 0x54f8890a,\n    0xbcef19ab, 0x491ae00f, 0xa10d70ae, 0x4244c70c, 0xaa5357ad,\n    0x72de3205, 0x9ac9a2a4, 0x79801506, 0x919785a7, 0x64627c03,\n    0x8c75eca2, 0x6f3c5b00, 0x872bcba1, 0xba1aca03, 0x520d5aa2,\n    0xb144ed00, 0x59537da1, 0xaca68405, 0x44b114a4, 0xa7f8a306,\n    0x4fef33a7, 0x9762560f, 0x7f75c6ae, 0x9c3c710c, 0x742be1ad,\n    0x81de1809, 0x69c988a8, 0x8a803f0a, 0x6297afab, 0xe0ebf21b,\n    0x08fc62ba, 0xebb5d518, 0x03a245b9, 0xf657bc1d, 0x1e402cbc,\n    0xfd099b1e, 0x151e0bbf, 0xcd936e17, 0x2584feb6, 0xc6cd4914,\n    0x2edad9b5, 0xdb2f2011, 0x3338b0b0, 0xd0710712, 0x386697b3,\n    0x0ff8ba33, 0xe7ef2a92, 0x04a69d30, 0xecb10d91, 0x1944f435,\n    0xf1536494, 0x121ad336, 0xfa0d4397, 0x2280263f, 0xca97b69e,\n    0x29de013c, 0xc1c9919d, 0x343c6839, 0xdc2bf898, 0x3f624f3a,\n    0xd775df9b, 0x5509822b, 0xbd1e128a, 0x5e57a528, 0xb6403589,\n    0x43b5cc2d, 0xaba25c8c, 0x48ebeb2e, 0xa0fc7b8f, 0x78711e27,\n    0x90668e86, 0x732f3924, 0x9b38a985, 0x6ecd5021, 0x86dac080,\n    0x65937722, 0x8d84e783, 0x0aaf2c22, 0xe2b8bc83, 0x01f10b21,\n    0xe9e69b80, 0x1c136224, 0xf404f285, 0x174d4527, 0xff5ad586,\n    0x27d7b02e, 0xcfc0208f, 0x2c89972d, 0xc49e078c, 0x316bfe28,\n    0xd97c6e89, 0x3a35d92b, 0xd222498a, 0x505e143a, 0xb849849b,\n    0x5b003339, 0xb317a398, 0x46e25a3c, 0xaef5ca9d, 0x4dbc7d3f,\n    0xa5abed9e, 0x7d268836, 0x95311897, 0x7678af35, 0x9e6f3f94,\n    0x6b9ac630, 0x838d5691, 0x60c4e133, 0x88d37192, 0xbf4d5c12,\n    0x575accb3, 0xb4137b11, 0x5c04ebb0, 0xa9f11214, 0x41e682b5,\n    0xa2af3517, 0x4ab8a5b6, 0x9235c01e, 0x7a2250bf, 0x996be71d,\n    0x717c77bc, 0x84898e18, 0x6c9e1eb9, 0x8fd7a91b, 0x67c039ba,\n    0xe5bc640a, 0x0dabf4ab, 0xeee24309, 0x06f5d3a8, 0xf3002a0c,\n    0x1b17baad, 0xf85e0d0f, 0x10499dae, 0xc8c4f806, 0x20d368a7,\n    0xc39adf05, 0x2b8d4fa4, 0xde78b600, 0x366f26a1, 0xd5269103,\n    0x3d3101a2}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x0000000000000000, 0xa19017e800000000, 0x03275e0b00000000,\n    0xa2b749e300000000, 0x064ebc1600000000, 0xa7deabfe00000000,\n    0x0569e21d00000000, 0xa4f9f5f500000000, 0x0c9c782d00000000,\n    0xad0c6fc500000000, 0x0fbb262600000000, 0xae2b31ce00000000,\n    0x0ad2c43b00000000, 0xab42d3d300000000, 0x09f59a3000000000,\n    0xa8658dd800000000, 0x1838f15a00000000, 0xb9a8e6b200000000,\n    0x1b1faf5100000000, 0xba8fb8b900000000, 0x1e764d4c00000000,\n    0xbfe65aa400000000, 0x1d51134700000000, 0xbcc104af00000000,\n    0x14a4897700000000, 0xb5349e9f00000000, 0x1783d77c00000000,\n    0xb613c09400000000, 0x12ea356100000000, 0xb37a228900000000,\n    0x11cd6b6a00000000, 0xb05d7c8200000000, 0x3070e2b500000000,\n    0x91e0f55d00000000, 0x3357bcbe00000000, 0x92c7ab5600000000,\n    0x363e5ea300000000, 0x97ae494b00000000, 0x351900a800000000,\n    0x9489174000000000, 0x3cec9a9800000000, 0x9d7c8d7000000000,\n    0x3fcbc49300000000, 0x9e5bd37b00000000, 0x3aa2268e00000000,\n    0x9b32316600000000, 0x3985788500000000, 0x98156f6d00000000,\n    0x284813ef00000000, 0x89d8040700000000, 0x2b6f4de400000000,\n    0x8aff5a0c00000000, 0x2e06aff900000000, 0x8f96b81100000000,\n    0x2d21f1f200000000, 0x8cb1e61a00000000, 0x24d46bc200000000,\n    0x85447c2a00000000, 0x27f335c900000000, 0x8663222100000000,\n    0x229ad7d400000000, 0x830ac03c00000000, 0x21bd89df00000000,\n    0x802d9e3700000000, 0x21e6b5b000000000, 0x8076a25800000000,\n    0x22c1ebbb00000000, 0x8351fc5300000000, 0x27a809a600000000,\n    0x86381e4e00000000, 0x248f57ad00000000, 0x851f404500000000,\n    0x2d7acd9d00000000, 0x8ceada7500000000, 0x2e5d939600000000,\n    0x8fcd847e00000000, 0x2b34718b00000000, 0x8aa4666300000000,\n    0x28132f8000000000, 0x8983386800000000, 0x39de44ea00000000,\n    0x984e530200000000, 0x3af91ae100000000, 0x9b690d0900000000,\n    0x3f90f8fc00000000, 0x9e00ef1400000000, 0x3cb7a6f700000000,\n    0x9d27b11f00000000, 0x35423cc700000000, 0x94d22b2f00000000,\n    0x366562cc00000000, 0x97f5752400000000, 0x330c80d100000000,\n    0x929c973900000000, 0x302bdeda00000000, 0x91bbc93200000000,\n    0x1196570500000000, 0xb00640ed00000000, 0x12b1090e00000000,\n    0xb3211ee600000000, 0x17d8eb1300000000, 0xb648fcfb00000000,\n    0x14ffb51800000000, 0xb56fa2f000000000, 0x1d0a2f2800000000,\n    0xbc9a38c000000000, 0x1e2d712300000000, 0xbfbd66cb00000000,\n    0x1b44933e00000000, 0xbad484d600000000, 0x1863cd3500000000,\n    0xb9f3dadd00000000, 0x09aea65f00000000, 0xa83eb1b700000000,\n    0x0a89f85400000000, 0xab19efbc00000000, 0x0fe01a4900000000,\n    0xae700da100000000, 0x0cc7444200000000, 0xad5753aa00000000,\n    0x0532de7200000000, 0xa4a2c99a00000000, 0x0615807900000000,\n    0xa785979100000000, 0x037c626400000000, 0xa2ec758c00000000,\n    0x005b3c6f00000000, 0xa1cb2b8700000000, 0x03ca1aba00000000,\n    0xa25a0d5200000000, 0x00ed44b100000000, 0xa17d535900000000,\n    0x0584a6ac00000000, 0xa414b14400000000, 0x06a3f8a700000000,\n    0xa733ef4f00000000, 0x0f56629700000000, 0xaec6757f00000000,\n    0x0c713c9c00000000, 0xade12b7400000000, 0x0918de8100000000,\n    0xa888c96900000000, 0x0a3f808a00000000, 0xabaf976200000000,\n    0x1bf2ebe000000000, 0xba62fc0800000000, 0x18d5b5eb00000000,\n    0xb945a20300000000, 0x1dbc57f600000000, 0xbc2c401e00000000,\n    0x1e9b09fd00000000, 0xbf0b1e1500000000, 0x176e93cd00000000,\n    0xb6fe842500000000, 0x1449cdc600000000, 0xb5d9da2e00000000,\n    0x11202fdb00000000, 0xb0b0383300000000, 0x120771d000000000,\n    0xb397663800000000, 0x33baf80f00000000, 0x922aefe700000000,\n    0x309da60400000000, 0x910db1ec00000000, 0x35f4441900000000,\n    0x946453f100000000, 0x36d31a1200000000, 0x97430dfa00000000,\n    0x3f26802200000000, 0x9eb697ca00000000, 0x3c01de2900000000,\n    0x9d91c9c100000000, 0x39683c3400000000, 0x98f82bdc00000000,\n    0x3a4f623f00000000, 0x9bdf75d700000000, 0x2b82095500000000,\n    0x8a121ebd00000000, 0x28a5575e00000000, 0x893540b600000000,\n    0x2dccb54300000000, 0x8c5ca2ab00000000, 0x2eebeb4800000000,\n    0x8f7bfca000000000, 0x271e717800000000, 0x868e669000000000,\n    0x24392f7300000000, 0x85a9389b00000000, 0x2150cd6e00000000,\n    0x80c0da8600000000, 0x2277936500000000, 0x83e7848d00000000,\n    0x222caf0a00000000, 0x83bcb8e200000000, 0x210bf10100000000,\n    0x809be6e900000000, 0x2462131c00000000, 0x85f204f400000000,\n    0x27454d1700000000, 0x86d55aff00000000, 0x2eb0d72700000000,\n    0x8f20c0cf00000000, 0x2d97892c00000000, 0x8c079ec400000000,\n    0x28fe6b3100000000, 0x896e7cd900000000, 0x2bd9353a00000000,\n    0x8a4922d200000000, 0x3a145e5000000000, 0x9b8449b800000000,\n    0x3933005b00000000, 0x98a317b300000000, 0x3c5ae24600000000,\n    0x9dcaf5ae00000000, 0x3f7dbc4d00000000, 0x9eedaba500000000,\n    0x3688267d00000000, 0x9718319500000000, 0x35af787600000000,\n    0x943f6f9e00000000, 0x30c69a6b00000000, 0x91568d8300000000,\n    0x33e1c46000000000, 0x9271d38800000000, 0x125c4dbf00000000,\n    0xb3cc5a5700000000, 0x117b13b400000000, 0xb0eb045c00000000,\n    0x1412f1a900000000, 0xb582e64100000000, 0x1735afa200000000,\n    0xb6a5b84a00000000, 0x1ec0359200000000, 0xbf50227a00000000,\n    0x1de76b9900000000, 0xbc777c7100000000, 0x188e898400000000,\n    0xb91e9e6c00000000, 0x1ba9d78f00000000, 0xba39c06700000000,\n    0x0a64bce500000000, 0xabf4ab0d00000000, 0x0943e2ee00000000,\n    0xa8d3f50600000000, 0x0c2a00f300000000, 0xadba171b00000000,\n    0x0f0d5ef800000000, 0xae9d491000000000, 0x06f8c4c800000000,\n    0xa768d32000000000, 0x05df9ac300000000, 0xa44f8d2b00000000,\n    0x00b678de00000000, 0xa1266f3600000000, 0x039126d500000000,\n    0xa201313d00000000},\n   {0x0000000000000000, 0xee8439a100000000, 0x9d0f029900000000,\n    0x738b3b3800000000, 0x7b1975e900000000, 0x959d4c4800000000,\n    0xe616777000000000, 0x08924ed100000000, 0xb7349b0900000000,\n    0x59b0a2a800000000, 0x2a3b999000000000, 0xc4bfa03100000000,\n    0xcc2deee000000000, 0x22a9d74100000000, 0x5122ec7900000000,\n    0xbfa6d5d800000000, 0x6e69361300000000, 0x80ed0fb200000000,\n    0xf366348a00000000, 0x1de20d2b00000000, 0x157043fa00000000,\n    0xfbf47a5b00000000, 0x887f416300000000, 0x66fb78c200000000,\n    0xd95dad1a00000000, 0x37d994bb00000000, 0x4452af8300000000,\n    0xaad6962200000000, 0xa244d8f300000000, 0x4cc0e15200000000,\n    0x3f4bda6a00000000, 0xd1cfe3cb00000000, 0xdcd26c2600000000,\n    0x3256558700000000, 0x41dd6ebf00000000, 0xaf59571e00000000,\n    0xa7cb19cf00000000, 0x494f206e00000000, 0x3ac41b5600000000,\n    0xd44022f700000000, 0x6be6f72f00000000, 0x8562ce8e00000000,\n    0xf6e9f5b600000000, 0x186dcc1700000000, 0x10ff82c600000000,\n    0xfe7bbb6700000000, 0x8df0805f00000000, 0x6374b9fe00000000,\n    0xb2bb5a3500000000, 0x5c3f639400000000, 0x2fb458ac00000000,\n    0xc130610d00000000, 0xc9a22fdc00000000, 0x2726167d00000000,\n    0x54ad2d4500000000, 0xba2914e400000000, 0x058fc13c00000000,\n    0xeb0bf89d00000000, 0x9880c3a500000000, 0x7604fa0400000000,\n    0x7e96b4d500000000, 0x90128d7400000000, 0xe399b64c00000000,\n    0x0d1d8fed00000000, 0xb8a5d94c00000000, 0x5621e0ed00000000,\n    0x25aadbd500000000, 0xcb2ee27400000000, 0xc3bcaca500000000,\n    0x2d38950400000000, 0x5eb3ae3c00000000, 0xb037979d00000000,\n    0x0f91424500000000, 0xe1157be400000000, 0x929e40dc00000000,\n    0x7c1a797d00000000, 0x748837ac00000000, 0x9a0c0e0d00000000,\n    0xe987353500000000, 0x07030c9400000000, 0xd6ccef5f00000000,\n    0x3848d6fe00000000, 0x4bc3edc600000000, 0xa547d46700000000,\n    0xadd59ab600000000, 0x4351a31700000000, 0x30da982f00000000,\n    0xde5ea18e00000000, 0x61f8745600000000, 0x8f7c4df700000000,\n    0xfcf776cf00000000, 0x12734f6e00000000, 0x1ae101bf00000000,\n    0xf465381e00000000, 0x87ee032600000000, 0x696a3a8700000000,\n    0x6477b56a00000000, 0x8af38ccb00000000, 0xf978b7f300000000,\n    0x17fc8e5200000000, 0x1f6ec08300000000, 0xf1eaf92200000000,\n    0x8261c21a00000000, 0x6ce5fbbb00000000, 0xd3432e6300000000,\n    0x3dc717c200000000, 0x4e4c2cfa00000000, 0xa0c8155b00000000,\n    0xa85a5b8a00000000, 0x46de622b00000000, 0x3555591300000000,\n    0xdbd160b200000000, 0x0a1e837900000000, 0xe49abad800000000,\n    0x971181e000000000, 0x7995b84100000000, 0x7107f69000000000,\n    0x9f83cf3100000000, 0xec08f40900000000, 0x028ccda800000000,\n    0xbd2a187000000000, 0x53ae21d100000000, 0x20251ae900000000,\n    0xcea1234800000000, 0xc6336d9900000000, 0x28b7543800000000,\n    0x5b3c6f0000000000, 0xb5b856a100000000, 0x704bb39900000000,\n    0x9ecf8a3800000000, 0xed44b10000000000, 0x03c088a100000000,\n    0x0b52c67000000000, 0xe5d6ffd100000000, 0x965dc4e900000000,\n    0x78d9fd4800000000, 0xc77f289000000000, 0x29fb113100000000,\n    0x5a702a0900000000, 0xb4f413a800000000, 0xbc665d7900000000,\n    0x52e264d800000000, 0x21695fe000000000, 0xcfed664100000000,\n    0x1e22858a00000000, 0xf0a6bc2b00000000, 0x832d871300000000,\n    0x6da9beb200000000, 0x653bf06300000000, 0x8bbfc9c200000000,\n    0xf834f2fa00000000, 0x16b0cb5b00000000, 0xa9161e8300000000,\n    0x4792272200000000, 0x34191c1a00000000, 0xda9d25bb00000000,\n    0xd20f6b6a00000000, 0x3c8b52cb00000000, 0x4f0069f300000000,\n    0xa184505200000000, 0xac99dfbf00000000, 0x421de61e00000000,\n    0x3196dd2600000000, 0xdf12e48700000000, 0xd780aa5600000000,\n    0x390493f700000000, 0x4a8fa8cf00000000, 0xa40b916e00000000,\n    0x1bad44b600000000, 0xf5297d1700000000, 0x86a2462f00000000,\n    0x68267f8e00000000, 0x60b4315f00000000, 0x8e3008fe00000000,\n    0xfdbb33c600000000, 0x133f0a6700000000, 0xc2f0e9ac00000000,\n    0x2c74d00d00000000, 0x5fffeb3500000000, 0xb17bd29400000000,\n    0xb9e99c4500000000, 0x576da5e400000000, 0x24e69edc00000000,\n    0xca62a77d00000000, 0x75c472a500000000, 0x9b404b0400000000,\n    0xe8cb703c00000000, 0x064f499d00000000, 0x0edd074c00000000,\n    0xe0593eed00000000, 0x93d205d500000000, 0x7d563c7400000000,\n    0xc8ee6ad500000000, 0x266a537400000000, 0x55e1684c00000000,\n    0xbb6551ed00000000, 0xb3f71f3c00000000, 0x5d73269d00000000,\n    0x2ef81da500000000, 0xc07c240400000000, 0x7fdaf1dc00000000,\n    0x915ec87d00000000, 0xe2d5f34500000000, 0x0c51cae400000000,\n    0x04c3843500000000, 0xea47bd9400000000, 0x99cc86ac00000000,\n    0x7748bf0d00000000, 0xa6875cc600000000, 0x4803656700000000,\n    0x3b885e5f00000000, 0xd50c67fe00000000, 0xdd9e292f00000000,\n    0x331a108e00000000, 0x40912bb600000000, 0xae15121700000000,\n    0x11b3c7cf00000000, 0xff37fe6e00000000, 0x8cbcc55600000000,\n    0x6238fcf700000000, 0x6aaab22600000000, 0x842e8b8700000000,\n    0xf7a5b0bf00000000, 0x1921891e00000000, 0x143c06f300000000,\n    0xfab83f5200000000, 0x8933046a00000000, 0x67b73dcb00000000,\n    0x6f25731a00000000, 0x81a14abb00000000, 0xf22a718300000000,\n    0x1cae482200000000, 0xa3089dfa00000000, 0x4d8ca45b00000000,\n    0x3e079f6300000000, 0xd083a6c200000000, 0xd811e81300000000,\n    0x3695d1b200000000, 0x451eea8a00000000, 0xab9ad32b00000000,\n    0x7a5530e000000000, 0x94d1094100000000, 0xe75a327900000000,\n    0x09de0bd800000000, 0x014c450900000000, 0xefc87ca800000000,\n    0x9c43479000000000, 0x72c77e3100000000, 0xcd61abe900000000,\n    0x23e5924800000000, 0x506ea97000000000, 0xbeea90d100000000,\n    0xb678de0000000000, 0x58fce7a100000000, 0x2b77dc9900000000,\n    0xc5f3e53800000000},\n   {0x0000000000000000, 0xfbf6134700000000, 0xf6ed278e00000000,\n    0x0d1b34c900000000, 0xaddd3ec700000000, 0x562b2d8000000000,\n    0x5b30194900000000, 0xa0c60a0e00000000, 0x1bbd0c5500000000,\n    0xe04b1f1200000000, 0xed502bdb00000000, 0x16a6389c00000000,\n    0xb660329200000000, 0x4d9621d500000000, 0x408d151c00000000,\n    0xbb7b065b00000000, 0x367a19aa00000000, 0xcd8c0aed00000000,\n    0xc0973e2400000000, 0x3b612d6300000000, 0x9ba7276d00000000,\n    0x6051342a00000000, 0x6d4a00e300000000, 0x96bc13a400000000,\n    0x2dc715ff00000000, 0xd63106b800000000, 0xdb2a327100000000,\n    0x20dc213600000000, 0x801a2b3800000000, 0x7bec387f00000000,\n    0x76f70cb600000000, 0x8d011ff100000000, 0x2df2438f00000000,\n    0xd60450c800000000, 0xdb1f640100000000, 0x20e9774600000000,\n    0x802f7d4800000000, 0x7bd96e0f00000000, 0x76c25ac600000000,\n    0x8d34498100000000, 0x364f4fda00000000, 0xcdb95c9d00000000,\n    0xc0a2685400000000, 0x3b547b1300000000, 0x9b92711d00000000,\n    0x6064625a00000000, 0x6d7f569300000000, 0x968945d400000000,\n    0x1b885a2500000000, 0xe07e496200000000, 0xed657dab00000000,\n    0x16936eec00000000, 0xb65564e200000000, 0x4da377a500000000,\n    0x40b8436c00000000, 0xbb4e502b00000000, 0x0035567000000000,\n    0xfbc3453700000000, 0xf6d871fe00000000, 0x0d2e62b900000000,\n    0xade868b700000000, 0x561e7bf000000000, 0x5b054f3900000000,\n    0xa0f35c7e00000000, 0x1be2f6c500000000, 0xe014e58200000000,\n    0xed0fd14b00000000, 0x16f9c20c00000000, 0xb63fc80200000000,\n    0x4dc9db4500000000, 0x40d2ef8c00000000, 0xbb24fccb00000000,\n    0x005ffa9000000000, 0xfba9e9d700000000, 0xf6b2dd1e00000000,\n    0x0d44ce5900000000, 0xad82c45700000000, 0x5674d71000000000,\n    0x5b6fe3d900000000, 0xa099f09e00000000, 0x2d98ef6f00000000,\n    0xd66efc2800000000, 0xdb75c8e100000000, 0x2083dba600000000,\n    0x8045d1a800000000, 0x7bb3c2ef00000000, 0x76a8f62600000000,\n    0x8d5ee56100000000, 0x3625e33a00000000, 0xcdd3f07d00000000,\n    0xc0c8c4b400000000, 0x3b3ed7f300000000, 0x9bf8ddfd00000000,\n    0x600eceba00000000, 0x6d15fa7300000000, 0x96e3e93400000000,\n    0x3610b54a00000000, 0xcde6a60d00000000, 0xc0fd92c400000000,\n    0x3b0b818300000000, 0x9bcd8b8d00000000, 0x603b98ca00000000,\n    0x6d20ac0300000000, 0x96d6bf4400000000, 0x2dadb91f00000000,\n    0xd65baa5800000000, 0xdb409e9100000000, 0x20b68dd600000000,\n    0x807087d800000000, 0x7b86949f00000000, 0x769da05600000000,\n    0x8d6bb31100000000, 0x006aace000000000, 0xfb9cbfa700000000,\n    0xf6878b6e00000000, 0x0d71982900000000, 0xadb7922700000000,\n    0x5641816000000000, 0x5b5ab5a900000000, 0xa0aca6ee00000000,\n    0x1bd7a0b500000000, 0xe021b3f200000000, 0xed3a873b00000000,\n    0x16cc947c00000000, 0xb60a9e7200000000, 0x4dfc8d3500000000,\n    0x40e7b9fc00000000, 0xbb11aabb00000000, 0x77c29c5000000000,\n    0x8c348f1700000000, 0x812fbbde00000000, 0x7ad9a89900000000,\n    0xda1fa29700000000, 0x21e9b1d000000000, 0x2cf2851900000000,\n    0xd704965e00000000, 0x6c7f900500000000, 0x9789834200000000,\n    0x9a92b78b00000000, 0x6164a4cc00000000, 0xc1a2aec200000000,\n    0x3a54bd8500000000, 0x374f894c00000000, 0xccb99a0b00000000,\n    0x41b885fa00000000, 0xba4e96bd00000000, 0xb755a27400000000,\n    0x4ca3b13300000000, 0xec65bb3d00000000, 0x1793a87a00000000,\n    0x1a889cb300000000, 0xe17e8ff400000000, 0x5a0589af00000000,\n    0xa1f39ae800000000, 0xace8ae2100000000, 0x571ebd6600000000,\n    0xf7d8b76800000000, 0x0c2ea42f00000000, 0x013590e600000000,\n    0xfac383a100000000, 0x5a30dfdf00000000, 0xa1c6cc9800000000,\n    0xacddf85100000000, 0x572beb1600000000, 0xf7ede11800000000,\n    0x0c1bf25f00000000, 0x0100c69600000000, 0xfaf6d5d100000000,\n    0x418dd38a00000000, 0xba7bc0cd00000000, 0xb760f40400000000,\n    0x4c96e74300000000, 0xec50ed4d00000000, 0x17a6fe0a00000000,\n    0x1abdcac300000000, 0xe14bd98400000000, 0x6c4ac67500000000,\n    0x97bcd53200000000, 0x9aa7e1fb00000000, 0x6151f2bc00000000,\n    0xc197f8b200000000, 0x3a61ebf500000000, 0x377adf3c00000000,\n    0xcc8ccc7b00000000, 0x77f7ca2000000000, 0x8c01d96700000000,\n    0x811aedae00000000, 0x7aecfee900000000, 0xda2af4e700000000,\n    0x21dce7a000000000, 0x2cc7d36900000000, 0xd731c02e00000000,\n    0x6c206a9500000000, 0x97d679d200000000, 0x9acd4d1b00000000,\n    0x613b5e5c00000000, 0xc1fd545200000000, 0x3a0b471500000000,\n    0x371073dc00000000, 0xcce6609b00000000, 0x779d66c000000000,\n    0x8c6b758700000000, 0x8170414e00000000, 0x7a86520900000000,\n    0xda40580700000000, 0x21b64b4000000000, 0x2cad7f8900000000,\n    0xd75b6cce00000000, 0x5a5a733f00000000, 0xa1ac607800000000,\n    0xacb754b100000000, 0x574147f600000000, 0xf7874df800000000,\n    0x0c715ebf00000000, 0x016a6a7600000000, 0xfa9c793100000000,\n    0x41e77f6a00000000, 0xba116c2d00000000, 0xb70a58e400000000,\n    0x4cfc4ba300000000, 0xec3a41ad00000000, 0x17cc52ea00000000,\n    0x1ad7662300000000, 0xe121756400000000, 0x41d2291a00000000,\n    0xba243a5d00000000, 0xb73f0e9400000000, 0x4cc91dd300000000,\n    0xec0f17dd00000000, 0x17f9049a00000000, 0x1ae2305300000000,\n    0xe114231400000000, 0x5a6f254f00000000, 0xa199360800000000,\n    0xac8202c100000000, 0x5774118600000000, 0xf7b21b8800000000,\n    0x0c4408cf00000000, 0x015f3c0600000000, 0xfaa92f4100000000,\n    0x77a830b000000000, 0x8c5e23f700000000, 0x8145173e00000000,\n    0x7ab3047900000000, 0xda750e7700000000, 0x21831d3000000000,\n    0x2c9829f900000000, 0xd76e3abe00000000, 0x6c153ce500000000,\n    0x97e32fa200000000, 0x9af81b6b00000000, 0x610e082c00000000,\n    0xc1c8022200000000, 0x3a3e116500000000, 0x372525ac00000000,\n    0xccd336eb00000000},\n   {0x0000000000000000, 0x6238282a00000000, 0xc470505400000000,\n    0xa648787e00000000, 0x88e1a0a800000000, 0xead9888200000000,\n    0x4c91f0fc00000000, 0x2ea9d8d600000000, 0x51c5308a00000000,\n    0x33fd18a000000000, 0x95b560de00000000, 0xf78d48f400000000,\n    0xd924902200000000, 0xbb1cb80800000000, 0x1d54c07600000000,\n    0x7f6ce85c00000000, 0xe38c10cf00000000, 0x81b438e500000000,\n    0x27fc409b00000000, 0x45c468b100000000, 0x6b6db06700000000,\n    0x0955984d00000000, 0xaf1de03300000000, 0xcd25c81900000000,\n    0xb249204500000000, 0xd071086f00000000, 0x7639701100000000,\n    0x1401583b00000000, 0x3aa880ed00000000, 0x5890a8c700000000,\n    0xfed8d0b900000000, 0x9ce0f89300000000, 0x871f504500000000,\n    0xe527786f00000000, 0x436f001100000000, 0x2157283b00000000,\n    0x0ffef0ed00000000, 0x6dc6d8c700000000, 0xcb8ea0b900000000,\n    0xa9b6889300000000, 0xd6da60cf00000000, 0xb4e248e500000000,\n    0x12aa309b00000000, 0x709218b100000000, 0x5e3bc06700000000,\n    0x3c03e84d00000000, 0x9a4b903300000000, 0xf873b81900000000,\n    0x6493408a00000000, 0x06ab68a000000000, 0xa0e310de00000000,\n    0xc2db38f400000000, 0xec72e02200000000, 0x8e4ac80800000000,\n    0x2802b07600000000, 0x4a3a985c00000000, 0x3556700000000000,\n    0x576e582a00000000, 0xf126205400000000, 0x931e087e00000000,\n    0xbdb7d0a800000000, 0xdf8ff88200000000, 0x79c780fc00000000,\n    0x1bffa8d600000000, 0x0e3fa08a00000000, 0x6c0788a000000000,\n    0xca4ff0de00000000, 0xa877d8f400000000, 0x86de002200000000,\n    0xe4e6280800000000, 0x42ae507600000000, 0x2096785c00000000,\n    0x5ffa900000000000, 0x3dc2b82a00000000, 0x9b8ac05400000000,\n    0xf9b2e87e00000000, 0xd71b30a800000000, 0xb523188200000000,\n    0x136b60fc00000000, 0x715348d600000000, 0xedb3b04500000000,\n    0x8f8b986f00000000, 0x29c3e01100000000, 0x4bfbc83b00000000,\n    0x655210ed00000000, 0x076a38c700000000, 0xa12240b900000000,\n    0xc31a689300000000, 0xbc7680cf00000000, 0xde4ea8e500000000,\n    0x7806d09b00000000, 0x1a3ef8b100000000, 0x3497206700000000,\n    0x56af084d00000000, 0xf0e7703300000000, 0x92df581900000000,\n    0x8920f0cf00000000, 0xeb18d8e500000000, 0x4d50a09b00000000,\n    0x2f6888b100000000, 0x01c1506700000000, 0x63f9784d00000000,\n    0xc5b1003300000000, 0xa789281900000000, 0xd8e5c04500000000,\n    0xbadde86f00000000, 0x1c95901100000000, 0x7eadb83b00000000,\n    0x500460ed00000000, 0x323c48c700000000, 0x947430b900000000,\n    0xf64c189300000000, 0x6aace00000000000, 0x0894c82a00000000,\n    0xaedcb05400000000, 0xcce4987e00000000, 0xe24d40a800000000,\n    0x8075688200000000, 0x263d10fc00000000, 0x440538d600000000,\n    0x3b69d08a00000000, 0x5951f8a000000000, 0xff1980de00000000,\n    0x9d21a8f400000000, 0xb388702200000000, 0xd1b0580800000000,\n    0x77f8207600000000, 0x15c0085c00000000, 0x5d7831ce00000000,\n    0x3f4019e400000000, 0x9908619a00000000, 0xfb3049b000000000,\n    0xd599916600000000, 0xb7a1b94c00000000, 0x11e9c13200000000,\n    0x73d1e91800000000, 0x0cbd014400000000, 0x6e85296e00000000,\n    0xc8cd511000000000, 0xaaf5793a00000000, 0x845ca1ec00000000,\n    0xe66489c600000000, 0x402cf1b800000000, 0x2214d99200000000,\n    0xbef4210100000000, 0xdccc092b00000000, 0x7a84715500000000,\n    0x18bc597f00000000, 0x361581a900000000, 0x542da98300000000,\n    0xf265d1fd00000000, 0x905df9d700000000, 0xef31118b00000000,\n    0x8d0939a100000000, 0x2b4141df00000000, 0x497969f500000000,\n    0x67d0b12300000000, 0x05e8990900000000, 0xa3a0e17700000000,\n    0xc198c95d00000000, 0xda67618b00000000, 0xb85f49a100000000,\n    0x1e1731df00000000, 0x7c2f19f500000000, 0x5286c12300000000,\n    0x30bee90900000000, 0x96f6917700000000, 0xf4ceb95d00000000,\n    0x8ba2510100000000, 0xe99a792b00000000, 0x4fd2015500000000,\n    0x2dea297f00000000, 0x0343f1a900000000, 0x617bd98300000000,\n    0xc733a1fd00000000, 0xa50b89d700000000, 0x39eb714400000000,\n    0x5bd3596e00000000, 0xfd9b211000000000, 0x9fa3093a00000000,\n    0xb10ad1ec00000000, 0xd332f9c600000000, 0x757a81b800000000,\n    0x1742a99200000000, 0x682e41ce00000000, 0x0a1669e400000000,\n    0xac5e119a00000000, 0xce6639b000000000, 0xe0cfe16600000000,\n    0x82f7c94c00000000, 0x24bfb13200000000, 0x4687991800000000,\n    0x5347914400000000, 0x317fb96e00000000, 0x9737c11000000000,\n    0xf50fe93a00000000, 0xdba631ec00000000, 0xb99e19c600000000,\n    0x1fd661b800000000, 0x7dee499200000000, 0x0282a1ce00000000,\n    0x60ba89e400000000, 0xc6f2f19a00000000, 0xa4cad9b000000000,\n    0x8a63016600000000, 0xe85b294c00000000, 0x4e13513200000000,\n    0x2c2b791800000000, 0xb0cb818b00000000, 0xd2f3a9a100000000,\n    0x74bbd1df00000000, 0x1683f9f500000000, 0x382a212300000000,\n    0x5a12090900000000, 0xfc5a717700000000, 0x9e62595d00000000,\n    0xe10eb10100000000, 0x8336992b00000000, 0x257ee15500000000,\n    0x4746c97f00000000, 0x69ef11a900000000, 0x0bd7398300000000,\n    0xad9f41fd00000000, 0xcfa769d700000000, 0xd458c10100000000,\n    0xb660e92b00000000, 0x1028915500000000, 0x7210b97f00000000,\n    0x5cb961a900000000, 0x3e81498300000000, 0x98c931fd00000000,\n    0xfaf119d700000000, 0x859df18b00000000, 0xe7a5d9a100000000,\n    0x41eda1df00000000, 0x23d589f500000000, 0x0d7c512300000000,\n    0x6f44790900000000, 0xc90c017700000000, 0xab34295d00000000,\n    0x37d4d1ce00000000, 0x55ecf9e400000000, 0xf3a4819a00000000,\n    0x919ca9b000000000, 0xbf35716600000000, 0xdd0d594c00000000,\n    0x7b45213200000000, 0x197d091800000000, 0x6611e14400000000,\n    0x0429c96e00000000, 0xa261b11000000000, 0xc059993a00000000,\n    0xeef041ec00000000, 0x8cc869c600000000, 0x2a8011b800000000,\n    0x48b8399200000000},\n   {0x0000000000000000, 0x4c2896a300000000, 0xd9565d9c00000000,\n    0x957ecb3f00000000, 0xf3abcbe300000000, 0xbf835d4000000000,\n    0x2afd967f00000000, 0x66d500dc00000000, 0xa751e61c00000000,\n    0xeb7970bf00000000, 0x7e07bb8000000000, 0x322f2d2300000000,\n    0x54fa2dff00000000, 0x18d2bb5c00000000, 0x8dac706300000000,\n    0xc184e6c000000000, 0x4ea3cc3900000000, 0x028b5a9a00000000,\n    0x97f591a500000000, 0xdbdd070600000000, 0xbd0807da00000000,\n    0xf120917900000000, 0x645e5a4600000000, 0x2876cce500000000,\n    0xe9f22a2500000000, 0xa5dabc8600000000, 0x30a477b900000000,\n    0x7c8ce11a00000000, 0x1a59e1c600000000, 0x5671776500000000,\n    0xc30fbc5a00000000, 0x8f272af900000000, 0x9c46997300000000,\n    0xd06e0fd000000000, 0x4510c4ef00000000, 0x0938524c00000000,\n    0x6fed529000000000, 0x23c5c43300000000, 0xb6bb0f0c00000000,\n    0xfa9399af00000000, 0x3b177f6f00000000, 0x773fe9cc00000000,\n    0xe24122f300000000, 0xae69b45000000000, 0xc8bcb48c00000000,\n    0x8494222f00000000, 0x11eae91000000000, 0x5dc27fb300000000,\n    0xd2e5554a00000000, 0x9ecdc3e900000000, 0x0bb308d600000000,\n    0x479b9e7500000000, 0x214e9ea900000000, 0x6d66080a00000000,\n    0xf818c33500000000, 0xb430559600000000, 0x75b4b35600000000,\n    0x399c25f500000000, 0xace2eeca00000000, 0xe0ca786900000000,\n    0x861f78b500000000, 0xca37ee1600000000, 0x5f49252900000000,\n    0x1361b38a00000000, 0x388d32e700000000, 0x74a5a44400000000,\n    0xe1db6f7b00000000, 0xadf3f9d800000000, 0xcb26f90400000000,\n    0x870e6fa700000000, 0x1270a49800000000, 0x5e58323b00000000,\n    0x9fdcd4fb00000000, 0xd3f4425800000000, 0x468a896700000000,\n    0x0aa21fc400000000, 0x6c771f1800000000, 0x205f89bb00000000,\n    0xb521428400000000, 0xf909d42700000000, 0x762efede00000000,\n    0x3a06687d00000000, 0xaf78a34200000000, 0xe35035e100000000,\n    0x8585353d00000000, 0xc9ada39e00000000, 0x5cd368a100000000,\n    0x10fbfe0200000000, 0xd17f18c200000000, 0x9d578e6100000000,\n    0x0829455e00000000, 0x4401d3fd00000000, 0x22d4d32100000000,\n    0x6efc458200000000, 0xfb828ebd00000000, 0xb7aa181e00000000,\n    0xa4cbab9400000000, 0xe8e33d3700000000, 0x7d9df60800000000,\n    0x31b560ab00000000, 0x5760607700000000, 0x1b48f6d400000000,\n    0x8e363deb00000000, 0xc21eab4800000000, 0x039a4d8800000000,\n    0x4fb2db2b00000000, 0xdacc101400000000, 0x96e486b700000000,\n    0xf031866b00000000, 0xbc1910c800000000, 0x2967dbf700000000,\n    0x654f4d5400000000, 0xea6867ad00000000, 0xa640f10e00000000,\n    0x333e3a3100000000, 0x7f16ac9200000000, 0x19c3ac4e00000000,\n    0x55eb3aed00000000, 0xc095f1d200000000, 0x8cbd677100000000,\n    0x4d3981b100000000, 0x0111171200000000, 0x946fdc2d00000000,\n    0xd8474a8e00000000, 0xbe924a5200000000, 0xf2badcf100000000,\n    0x67c417ce00000000, 0x2bec816d00000000, 0x311c141500000000,\n    0x7d3482b600000000, 0xe84a498900000000, 0xa462df2a00000000,\n    0xc2b7dff600000000, 0x8e9f495500000000, 0x1be1826a00000000,\n    0x57c914c900000000, 0x964df20900000000, 0xda6564aa00000000,\n    0x4f1baf9500000000, 0x0333393600000000, 0x65e639ea00000000,\n    0x29ceaf4900000000, 0xbcb0647600000000, 0xf098f2d500000000,\n    0x7fbfd82c00000000, 0x33974e8f00000000, 0xa6e985b000000000,\n    0xeac1131300000000, 0x8c1413cf00000000, 0xc03c856c00000000,\n    0x55424e5300000000, 0x196ad8f000000000, 0xd8ee3e3000000000,\n    0x94c6a89300000000, 0x01b863ac00000000, 0x4d90f50f00000000,\n    0x2b45f5d300000000, 0x676d637000000000, 0xf213a84f00000000,\n    0xbe3b3eec00000000, 0xad5a8d6600000000, 0xe1721bc500000000,\n    0x740cd0fa00000000, 0x3824465900000000, 0x5ef1468500000000,\n    0x12d9d02600000000, 0x87a71b1900000000, 0xcb8f8dba00000000,\n    0x0a0b6b7a00000000, 0x4623fdd900000000, 0xd35d36e600000000,\n    0x9f75a04500000000, 0xf9a0a09900000000, 0xb588363a00000000,\n    0x20f6fd0500000000, 0x6cde6ba600000000, 0xe3f9415f00000000,\n    0xafd1d7fc00000000, 0x3aaf1cc300000000, 0x76878a6000000000,\n    0x10528abc00000000, 0x5c7a1c1f00000000, 0xc904d72000000000,\n    0x852c418300000000, 0x44a8a74300000000, 0x088031e000000000,\n    0x9dfefadf00000000, 0xd1d66c7c00000000, 0xb7036ca000000000,\n    0xfb2bfa0300000000, 0x6e55313c00000000, 0x227da79f00000000,\n    0x099126f200000000, 0x45b9b05100000000, 0xd0c77b6e00000000,\n    0x9cefedcd00000000, 0xfa3aed1100000000, 0xb6127bb200000000,\n    0x236cb08d00000000, 0x6f44262e00000000, 0xaec0c0ee00000000,\n    0xe2e8564d00000000, 0x77969d7200000000, 0x3bbe0bd100000000,\n    0x5d6b0b0d00000000, 0x11439dae00000000, 0x843d569100000000,\n    0xc815c03200000000, 0x4732eacb00000000, 0x0b1a7c6800000000,\n    0x9e64b75700000000, 0xd24c21f400000000, 0xb499212800000000,\n    0xf8b1b78b00000000, 0x6dcf7cb400000000, 0x21e7ea1700000000,\n    0xe0630cd700000000, 0xac4b9a7400000000, 0x3935514b00000000,\n    0x751dc7e800000000, 0x13c8c73400000000, 0x5fe0519700000000,\n    0xca9e9aa800000000, 0x86b60c0b00000000, 0x95d7bf8100000000,\n    0xd9ff292200000000, 0x4c81e21d00000000, 0x00a974be00000000,\n    0x667c746200000000, 0x2a54e2c100000000, 0xbf2a29fe00000000,\n    0xf302bf5d00000000, 0x3286599d00000000, 0x7eaecf3e00000000,\n    0xebd0040100000000, 0xa7f892a200000000, 0xc12d927e00000000,\n    0x8d0504dd00000000, 0x187bcfe200000000, 0x5453594100000000,\n    0xdb7473b800000000, 0x975ce51b00000000, 0x02222e2400000000,\n    0x4e0ab88700000000, 0x28dfb85b00000000, 0x64f72ef800000000,\n    0xf189e5c700000000, 0xbda1736400000000, 0x7c2595a400000000,\n    0x300d030700000000, 0xa573c83800000000, 0xe95b5e9b00000000,\n    0x8f8e5e4700000000, 0xc3a6c8e400000000, 0x56d803db00000000,\n    0x1af0957800000000},\n   {0x0000000000000000, 0x939bc97f00000000, 0x263793ff00000000,\n    0xb5ac5a8000000000, 0x0d68572400000000, 0x9ef39e5b00000000,\n    0x2b5fc4db00000000, 0xb8c40da400000000, 0x1ad0ae4800000000,\n    0x894b673700000000, 0x3ce73db700000000, 0xaf7cf4c800000000,\n    0x17b8f96c00000000, 0x8423301300000000, 0x318f6a9300000000,\n    0xa214a3ec00000000, 0x34a05d9100000000, 0xa73b94ee00000000,\n    0x1297ce6e00000000, 0x810c071100000000, 0x39c80ab500000000,\n    0xaa53c3ca00000000, 0x1fff994a00000000, 0x8c64503500000000,\n    0x2e70f3d900000000, 0xbdeb3aa600000000, 0x0847602600000000,\n    0x9bdca95900000000, 0x2318a4fd00000000, 0xb0836d8200000000,\n    0x052f370200000000, 0x96b4fe7d00000000, 0x2946caf900000000,\n    0xbadd038600000000, 0x0f71590600000000, 0x9cea907900000000,\n    0x242e9ddd00000000, 0xb7b554a200000000, 0x02190e2200000000,\n    0x9182c75d00000000, 0x339664b100000000, 0xa00dadce00000000,\n    0x15a1f74e00000000, 0x863a3e3100000000, 0x3efe339500000000,\n    0xad65faea00000000, 0x18c9a06a00000000, 0x8b52691500000000,\n    0x1de6976800000000, 0x8e7d5e1700000000, 0x3bd1049700000000,\n    0xa84acde800000000, 0x108ec04c00000000, 0x8315093300000000,\n    0x36b953b300000000, 0xa5229acc00000000, 0x0736392000000000,\n    0x94adf05f00000000, 0x2101aadf00000000, 0xb29a63a000000000,\n    0x0a5e6e0400000000, 0x99c5a77b00000000, 0x2c69fdfb00000000,\n    0xbff2348400000000, 0x138ae52800000000, 0x80112c5700000000,\n    0x35bd76d700000000, 0xa626bfa800000000, 0x1ee2b20c00000000,\n    0x8d797b7300000000, 0x38d521f300000000, 0xab4ee88c00000000,\n    0x095a4b6000000000, 0x9ac1821f00000000, 0x2f6dd89f00000000,\n    0xbcf611e000000000, 0x04321c4400000000, 0x97a9d53b00000000,\n    0x22058fbb00000000, 0xb19e46c400000000, 0x272ab8b900000000,\n    0xb4b171c600000000, 0x011d2b4600000000, 0x9286e23900000000,\n    0x2a42ef9d00000000, 0xb9d926e200000000, 0x0c757c6200000000,\n    0x9feeb51d00000000, 0x3dfa16f100000000, 0xae61df8e00000000,\n    0x1bcd850e00000000, 0x88564c7100000000, 0x309241d500000000,\n    0xa30988aa00000000, 0x16a5d22a00000000, 0x853e1b5500000000,\n    0x3acc2fd100000000, 0xa957e6ae00000000, 0x1cfbbc2e00000000,\n    0x8f60755100000000, 0x37a478f500000000, 0xa43fb18a00000000,\n    0x1193eb0a00000000, 0x8208227500000000, 0x201c819900000000,\n    0xb38748e600000000, 0x062b126600000000, 0x95b0db1900000000,\n    0x2d74d6bd00000000, 0xbeef1fc200000000, 0x0b43454200000000,\n    0x98d88c3d00000000, 0x0e6c724000000000, 0x9df7bb3f00000000,\n    0x285be1bf00000000, 0xbbc028c000000000, 0x0304256400000000,\n    0x909fec1b00000000, 0x2533b69b00000000, 0xb6a87fe400000000,\n    0x14bcdc0800000000, 0x8727157700000000, 0x328b4ff700000000,\n    0xa110868800000000, 0x19d48b2c00000000, 0x8a4f425300000000,\n    0x3fe318d300000000, 0xac78d1ac00000000, 0x2614cb5100000000,\n    0xb58f022e00000000, 0x002358ae00000000, 0x93b891d100000000,\n    0x2b7c9c7500000000, 0xb8e7550a00000000, 0x0d4b0f8a00000000,\n    0x9ed0c6f500000000, 0x3cc4651900000000, 0xaf5fac6600000000,\n    0x1af3f6e600000000, 0x89683f9900000000, 0x31ac323d00000000,\n    0xa237fb4200000000, 0x179ba1c200000000, 0x840068bd00000000,\n    0x12b496c000000000, 0x812f5fbf00000000, 0x3483053f00000000,\n    0xa718cc4000000000, 0x1fdcc1e400000000, 0x8c47089b00000000,\n    0x39eb521b00000000, 0xaa709b6400000000, 0x0864388800000000,\n    0x9bfff1f700000000, 0x2e53ab7700000000, 0xbdc8620800000000,\n    0x050c6fac00000000, 0x9697a6d300000000, 0x233bfc5300000000,\n    0xb0a0352c00000000, 0x0f5201a800000000, 0x9cc9c8d700000000,\n    0x2965925700000000, 0xbafe5b2800000000, 0x023a568c00000000,\n    0x91a19ff300000000, 0x240dc57300000000, 0xb7960c0c00000000,\n    0x1582afe000000000, 0x8619669f00000000, 0x33b53c1f00000000,\n    0xa02ef56000000000, 0x18eaf8c400000000, 0x8b7131bb00000000,\n    0x3edd6b3b00000000, 0xad46a24400000000, 0x3bf25c3900000000,\n    0xa869954600000000, 0x1dc5cfc600000000, 0x8e5e06b900000000,\n    0x369a0b1d00000000, 0xa501c26200000000, 0x10ad98e200000000,\n    0x8336519d00000000, 0x2122f27100000000, 0xb2b93b0e00000000,\n    0x0715618e00000000, 0x948ea8f100000000, 0x2c4aa55500000000,\n    0xbfd16c2a00000000, 0x0a7d36aa00000000, 0x99e6ffd500000000,\n    0x359e2e7900000000, 0xa605e70600000000, 0x13a9bd8600000000,\n    0x803274f900000000, 0x38f6795d00000000, 0xab6db02200000000,\n    0x1ec1eaa200000000, 0x8d5a23dd00000000, 0x2f4e803100000000,\n    0xbcd5494e00000000, 0x097913ce00000000, 0x9ae2dab100000000,\n    0x2226d71500000000, 0xb1bd1e6a00000000, 0x041144ea00000000,\n    0x978a8d9500000000, 0x013e73e800000000, 0x92a5ba9700000000,\n    0x2709e01700000000, 0xb492296800000000, 0x0c5624cc00000000,\n    0x9fcdedb300000000, 0x2a61b73300000000, 0xb9fa7e4c00000000,\n    0x1beedda000000000, 0x887514df00000000, 0x3dd94e5f00000000,\n    0xae42872000000000, 0x16868a8400000000, 0x851d43fb00000000,\n    0x30b1197b00000000, 0xa32ad00400000000, 0x1cd8e48000000000,\n    0x8f432dff00000000, 0x3aef777f00000000, 0xa974be0000000000,\n    0x11b0b3a400000000, 0x822b7adb00000000, 0x3787205b00000000,\n    0xa41ce92400000000, 0x06084ac800000000, 0x959383b700000000,\n    0x203fd93700000000, 0xb3a4104800000000, 0x0b601dec00000000,\n    0x98fbd49300000000, 0x2d578e1300000000, 0xbecc476c00000000,\n    0x2878b91100000000, 0xbbe3706e00000000, 0x0e4f2aee00000000,\n    0x9dd4e39100000000, 0x2510ee3500000000, 0xb68b274a00000000,\n    0x03277dca00000000, 0x90bcb4b500000000, 0x32a8175900000000,\n    0xa133de2600000000, 0x149f84a600000000, 0x87044dd900000000,\n    0x3fc0407d00000000, 0xac5b890200000000, 0x19f7d38200000000,\n    0x8a6c1afd00000000},\n   {0x0000000000000000, 0x650b796900000000, 0xca16f2d200000000,\n    0xaf1d8bbb00000000, 0xd52b957e00000000, 0xb020ec1700000000,\n    0x1f3d67ac00000000, 0x7a361ec500000000, 0xaa572afd00000000,\n    0xcf5c539400000000, 0x6041d82f00000000, 0x054aa14600000000,\n    0x7f7cbf8300000000, 0x1a77c6ea00000000, 0xb56a4d5100000000,\n    0xd061343800000000, 0x15a9252100000000, 0x70a25c4800000000,\n    0xdfbfd7f300000000, 0xbab4ae9a00000000, 0xc082b05f00000000,\n    0xa589c93600000000, 0x0a94428d00000000, 0x6f9f3be400000000,\n    0xbffe0fdc00000000, 0xdaf576b500000000, 0x75e8fd0e00000000,\n    0x10e3846700000000, 0x6ad59aa200000000, 0x0fdee3cb00000000,\n    0xa0c3687000000000, 0xc5c8111900000000, 0x2a524b4200000000,\n    0x4f59322b00000000, 0xe044b99000000000, 0x854fc0f900000000,\n    0xff79de3c00000000, 0x9a72a75500000000, 0x356f2cee00000000,\n    0x5064558700000000, 0x800561bf00000000, 0xe50e18d600000000,\n    0x4a13936d00000000, 0x2f18ea0400000000, 0x552ef4c100000000,\n    0x30258da800000000, 0x9f38061300000000, 0xfa337f7a00000000,\n    0x3ffb6e6300000000, 0x5af0170a00000000, 0xf5ed9cb100000000,\n    0x90e6e5d800000000, 0xead0fb1d00000000, 0x8fdb827400000000,\n    0x20c609cf00000000, 0x45cd70a600000000, 0x95ac449e00000000,\n    0xf0a73df700000000, 0x5fbab64c00000000, 0x3ab1cf2500000000,\n    0x4087d1e000000000, 0x258ca88900000000, 0x8a91233200000000,\n    0xef9a5a5b00000000, 0x54a4968400000000, 0x31afefed00000000,\n    0x9eb2645600000000, 0xfbb91d3f00000000, 0x818f03fa00000000,\n    0xe4847a9300000000, 0x4b99f12800000000, 0x2e92884100000000,\n    0xfef3bc7900000000, 0x9bf8c51000000000, 0x34e54eab00000000,\n    0x51ee37c200000000, 0x2bd8290700000000, 0x4ed3506e00000000,\n    0xe1cedbd500000000, 0x84c5a2bc00000000, 0x410db3a500000000,\n    0x2406cacc00000000, 0x8b1b417700000000, 0xee10381e00000000,\n    0x942626db00000000, 0xf12d5fb200000000, 0x5e30d40900000000,\n    0x3b3bad6000000000, 0xeb5a995800000000, 0x8e51e03100000000,\n    0x214c6b8a00000000, 0x444712e300000000, 0x3e710c2600000000,\n    0x5b7a754f00000000, 0xf467fef400000000, 0x916c879d00000000,\n    0x7ef6ddc600000000, 0x1bfda4af00000000, 0xb4e02f1400000000,\n    0xd1eb567d00000000, 0xabdd48b800000000, 0xced631d100000000,\n    0x61cbba6a00000000, 0x04c0c30300000000, 0xd4a1f73b00000000,\n    0xb1aa8e5200000000, 0x1eb705e900000000, 0x7bbc7c8000000000,\n    0x018a624500000000, 0x64811b2c00000000, 0xcb9c909700000000,\n    0xae97e9fe00000000, 0x6b5ff8e700000000, 0x0e54818e00000000,\n    0xa1490a3500000000, 0xc442735c00000000, 0xbe746d9900000000,\n    0xdb7f14f000000000, 0x74629f4b00000000, 0x1169e62200000000,\n    0xc108d21a00000000, 0xa403ab7300000000, 0x0b1e20c800000000,\n    0x6e1559a100000000, 0x1423476400000000, 0x71283e0d00000000,\n    0xde35b5b600000000, 0xbb3eccdf00000000, 0xe94e5cd200000000,\n    0x8c4525bb00000000, 0x2358ae0000000000, 0x4653d76900000000,\n    0x3c65c9ac00000000, 0x596eb0c500000000, 0xf6733b7e00000000,\n    0x9378421700000000, 0x4319762f00000000, 0x26120f4600000000,\n    0x890f84fd00000000, 0xec04fd9400000000, 0x9632e35100000000,\n    0xf3399a3800000000, 0x5c24118300000000, 0x392f68ea00000000,\n    0xfce779f300000000, 0x99ec009a00000000, 0x36f18b2100000000,\n    0x53faf24800000000, 0x29ccec8d00000000, 0x4cc795e400000000,\n    0xe3da1e5f00000000, 0x86d1673600000000, 0x56b0530e00000000,\n    0x33bb2a6700000000, 0x9ca6a1dc00000000, 0xf9add8b500000000,\n    0x839bc67000000000, 0xe690bf1900000000, 0x498d34a200000000,\n    0x2c864dcb00000000, 0xc31c179000000000, 0xa6176ef900000000,\n    0x090ae54200000000, 0x6c019c2b00000000, 0x163782ee00000000,\n    0x733cfb8700000000, 0xdc21703c00000000, 0xb92a095500000000,\n    0x694b3d6d00000000, 0x0c40440400000000, 0xa35dcfbf00000000,\n    0xc656b6d600000000, 0xbc60a81300000000, 0xd96bd17a00000000,\n    0x76765ac100000000, 0x137d23a800000000, 0xd6b532b100000000,\n    0xb3be4bd800000000, 0x1ca3c06300000000, 0x79a8b90a00000000,\n    0x039ea7cf00000000, 0x6695dea600000000, 0xc988551d00000000,\n    0xac832c7400000000, 0x7ce2184c00000000, 0x19e9612500000000,\n    0xb6f4ea9e00000000, 0xd3ff93f700000000, 0xa9c98d3200000000,\n    0xccc2f45b00000000, 0x63df7fe000000000, 0x06d4068900000000,\n    0xbdeaca5600000000, 0xd8e1b33f00000000, 0x77fc388400000000,\n    0x12f741ed00000000, 0x68c15f2800000000, 0x0dca264100000000,\n    0xa2d7adfa00000000, 0xc7dcd49300000000, 0x17bde0ab00000000,\n    0x72b699c200000000, 0xddab127900000000, 0xb8a06b1000000000,\n    0xc29675d500000000, 0xa79d0cbc00000000, 0x0880870700000000,\n    0x6d8bfe6e00000000, 0xa843ef7700000000, 0xcd48961e00000000,\n    0x62551da500000000, 0x075e64cc00000000, 0x7d687a0900000000,\n    0x1863036000000000, 0xb77e88db00000000, 0xd275f1b200000000,\n    0x0214c58a00000000, 0x671fbce300000000, 0xc802375800000000,\n    0xad094e3100000000, 0xd73f50f400000000, 0xb234299d00000000,\n    0x1d29a22600000000, 0x7822db4f00000000, 0x97b8811400000000,\n    0xf2b3f87d00000000, 0x5dae73c600000000, 0x38a50aaf00000000,\n    0x4293146a00000000, 0x27986d0300000000, 0x8885e6b800000000,\n    0xed8e9fd100000000, 0x3defabe900000000, 0x58e4d28000000000,\n    0xf7f9593b00000000, 0x92f2205200000000, 0xe8c43e9700000000,\n    0x8dcf47fe00000000, 0x22d2cc4500000000, 0x47d9b52c00000000,\n    0x8211a43500000000, 0xe71add5c00000000, 0x480756e700000000,\n    0x2d0c2f8e00000000, 0x573a314b00000000, 0x3231482200000000,\n    0x9d2cc39900000000, 0xf827baf000000000, 0x28468ec800000000,\n    0x4d4df7a100000000, 0xe2507c1a00000000, 0x875b057300000000,\n    0xfd6d1bb600000000, 0x986662df00000000, 0x377be96400000000,\n    0x5270900d00000000},\n   {0x0000000000000000, 0xdcecb13d00000000, 0xb8d9637b00000000,\n    0x6435d24600000000, 0x70b3c7f600000000, 0xac5f76cb00000000,\n    0xc86aa48d00000000, 0x148615b000000000, 0xa160fe3600000000,\n    0x7d8c4f0b00000000, 0x19b99d4d00000000, 0xc5552c7000000000,\n    0xd1d339c000000000, 0x0d3f88fd00000000, 0x690a5abb00000000,\n    0xb5e6eb8600000000, 0x42c1fc6d00000000, 0x9e2d4d5000000000,\n    0xfa189f1600000000, 0x26f42e2b00000000, 0x32723b9b00000000,\n    0xee9e8aa600000000, 0x8aab58e000000000, 0x5647e9dd00000000,\n    0xe3a1025b00000000, 0x3f4db36600000000, 0x5b78612000000000,\n    0x8794d01d00000000, 0x9312c5ad00000000, 0x4ffe749000000000,\n    0x2bcba6d600000000, 0xf72717eb00000000, 0x8482f9db00000000,\n    0x586e48e600000000, 0x3c5b9aa000000000, 0xe0b72b9d00000000,\n    0xf4313e2d00000000, 0x28dd8f1000000000, 0x4ce85d5600000000,\n    0x9004ec6b00000000, 0x25e207ed00000000, 0xf90eb6d000000000,\n    0x9d3b649600000000, 0x41d7d5ab00000000, 0x5551c01b00000000,\n    0x89bd712600000000, 0xed88a36000000000, 0x3164125d00000000,\n    0xc64305b600000000, 0x1aafb48b00000000, 0x7e9a66cd00000000,\n    0xa276d7f000000000, 0xb6f0c24000000000, 0x6a1c737d00000000,\n    0x0e29a13b00000000, 0xd2c5100600000000, 0x6723fb8000000000,\n    0xbbcf4abd00000000, 0xdffa98fb00000000, 0x031629c600000000,\n    0x17903c7600000000, 0xcb7c8d4b00000000, 0xaf495f0d00000000,\n    0x73a5ee3000000000, 0x4903826c00000000, 0x95ef335100000000,\n    0xf1dae11700000000, 0x2d36502a00000000, 0x39b0459a00000000,\n    0xe55cf4a700000000, 0x816926e100000000, 0x5d8597dc00000000,\n    0xe8637c5a00000000, 0x348fcd6700000000, 0x50ba1f2100000000,\n    0x8c56ae1c00000000, 0x98d0bbac00000000, 0x443c0a9100000000,\n    0x2009d8d700000000, 0xfce569ea00000000, 0x0bc27e0100000000,\n    0xd72ecf3c00000000, 0xb31b1d7a00000000, 0x6ff7ac4700000000,\n    0x7b71b9f700000000, 0xa79d08ca00000000, 0xc3a8da8c00000000,\n    0x1f446bb100000000, 0xaaa2803700000000, 0x764e310a00000000,\n    0x127be34c00000000, 0xce97527100000000, 0xda1147c100000000,\n    0x06fdf6fc00000000, 0x62c824ba00000000, 0xbe24958700000000,\n    0xcd817bb700000000, 0x116dca8a00000000, 0x755818cc00000000,\n    0xa9b4a9f100000000, 0xbd32bc4100000000, 0x61de0d7c00000000,\n    0x05ebdf3a00000000, 0xd9076e0700000000, 0x6ce1858100000000,\n    0xb00d34bc00000000, 0xd438e6fa00000000, 0x08d457c700000000,\n    0x1c52427700000000, 0xc0bef34a00000000, 0xa48b210c00000000,\n    0x7867903100000000, 0x8f4087da00000000, 0x53ac36e700000000,\n    0x3799e4a100000000, 0xeb75559c00000000, 0xfff3402c00000000,\n    0x231ff11100000000, 0x472a235700000000, 0x9bc6926a00000000,\n    0x2e2079ec00000000, 0xf2ccc8d100000000, 0x96f91a9700000000,\n    0x4a15abaa00000000, 0x5e93be1a00000000, 0x827f0f2700000000,\n    0xe64add6100000000, 0x3aa66c5c00000000, 0x920604d900000000,\n    0x4eeab5e400000000, 0x2adf67a200000000, 0xf633d69f00000000,\n    0xe2b5c32f00000000, 0x3e59721200000000, 0x5a6ca05400000000,\n    0x8680116900000000, 0x3366faef00000000, 0xef8a4bd200000000,\n    0x8bbf999400000000, 0x575328a900000000, 0x43d53d1900000000,\n    0x9f398c2400000000, 0xfb0c5e6200000000, 0x27e0ef5f00000000,\n    0xd0c7f8b400000000, 0x0c2b498900000000, 0x681e9bcf00000000,\n    0xb4f22af200000000, 0xa0743f4200000000, 0x7c988e7f00000000,\n    0x18ad5c3900000000, 0xc441ed0400000000, 0x71a7068200000000,\n    0xad4bb7bf00000000, 0xc97e65f900000000, 0x1592d4c400000000,\n    0x0114c17400000000, 0xddf8704900000000, 0xb9cda20f00000000,\n    0x6521133200000000, 0x1684fd0200000000, 0xca684c3f00000000,\n    0xae5d9e7900000000, 0x72b12f4400000000, 0x66373af400000000,\n    0xbadb8bc900000000, 0xdeee598f00000000, 0x0202e8b200000000,\n    0xb7e4033400000000, 0x6b08b20900000000, 0x0f3d604f00000000,\n    0xd3d1d17200000000, 0xc757c4c200000000, 0x1bbb75ff00000000,\n    0x7f8ea7b900000000, 0xa362168400000000, 0x5445016f00000000,\n    0x88a9b05200000000, 0xec9c621400000000, 0x3070d32900000000,\n    0x24f6c69900000000, 0xf81a77a400000000, 0x9c2fa5e200000000,\n    0x40c314df00000000, 0xf525ff5900000000, 0x29c94e6400000000,\n    0x4dfc9c2200000000, 0x91102d1f00000000, 0x859638af00000000,\n    0x597a899200000000, 0x3d4f5bd400000000, 0xe1a3eae900000000,\n    0xdb0586b500000000, 0x07e9378800000000, 0x63dce5ce00000000,\n    0xbf3054f300000000, 0xabb6414300000000, 0x775af07e00000000,\n    0x136f223800000000, 0xcf83930500000000, 0x7a65788300000000,\n    0xa689c9be00000000, 0xc2bc1bf800000000, 0x1e50aac500000000,\n    0x0ad6bf7500000000, 0xd63a0e4800000000, 0xb20fdc0e00000000,\n    0x6ee36d3300000000, 0x99c47ad800000000, 0x4528cbe500000000,\n    0x211d19a300000000, 0xfdf1a89e00000000, 0xe977bd2e00000000,\n    0x359b0c1300000000, 0x51aede5500000000, 0x8d426f6800000000,\n    0x38a484ee00000000, 0xe44835d300000000, 0x807de79500000000,\n    0x5c9156a800000000, 0x4817431800000000, 0x94fbf22500000000,\n    0xf0ce206300000000, 0x2c22915e00000000, 0x5f877f6e00000000,\n    0x836bce5300000000, 0xe75e1c1500000000, 0x3bb2ad2800000000,\n    0x2f34b89800000000, 0xf3d809a500000000, 0x97eddbe300000000,\n    0x4b016ade00000000, 0xfee7815800000000, 0x220b306500000000,\n    0x463ee22300000000, 0x9ad2531e00000000, 0x8e5446ae00000000,\n    0x52b8f79300000000, 0x368d25d500000000, 0xea6194e800000000,\n    0x1d46830300000000, 0xc1aa323e00000000, 0xa59fe07800000000,\n    0x7973514500000000, 0x6df544f500000000, 0xb119f5c800000000,\n    0xd52c278e00000000, 0x09c096b300000000, 0xbc267d3500000000,\n    0x60cacc0800000000, 0x04ff1e4e00000000, 0xd813af7300000000,\n    0xcc95bac300000000, 0x10790bfe00000000, 0x744cd9b800000000,\n    0xa8a0688500000000}};\n\n#else /* W == 4 */\n\nlocal const z_crc_t FAR crc_braid_table[][256] = {\n   {0x00000000, 0x81256527, 0xd93bcc0f, 0x581ea928, 0x69069e5f,\n    0xe823fb78, 0xb03d5250, 0x31183777, 0xd20d3cbe, 0x53285999,\n    0x0b36f0b1, 0x8a139596, 0xbb0ba2e1, 0x3a2ec7c6, 0x62306eee,\n    0xe3150bc9, 0x7f6b7f3d, 0xfe4e1a1a, 0xa650b332, 0x2775d615,\n    0x166de162, 0x97488445, 0xcf562d6d, 0x4e73484a, 0xad664383,\n    0x2c4326a4, 0x745d8f8c, 0xf578eaab, 0xc460dddc, 0x4545b8fb,\n    0x1d5b11d3, 0x9c7e74f4, 0xfed6fe7a, 0x7ff39b5d, 0x27ed3275,\n    0xa6c85752, 0x97d06025, 0x16f50502, 0x4eebac2a, 0xcfcec90d,\n    0x2cdbc2c4, 0xadfea7e3, 0xf5e00ecb, 0x74c56bec, 0x45dd5c9b,\n    0xc4f839bc, 0x9ce69094, 0x1dc3f5b3, 0x81bd8147, 0x0098e460,\n    0x58864d48, 0xd9a3286f, 0xe8bb1f18, 0x699e7a3f, 0x3180d317,\n    0xb0a5b630, 0x53b0bdf9, 0xd295d8de, 0x8a8b71f6, 0x0bae14d1,\n    0x3ab623a6, 0xbb934681, 0xe38defa9, 0x62a88a8e, 0x26dcfab5,\n    0xa7f99f92, 0xffe736ba, 0x7ec2539d, 0x4fda64ea, 0xceff01cd,\n    0x96e1a8e5, 0x17c4cdc2, 0xf4d1c60b, 0x75f4a32c, 0x2dea0a04,\n    0xaccf6f23, 0x9dd75854, 0x1cf23d73, 0x44ec945b, 0xc5c9f17c,\n    0x59b78588, 0xd892e0af, 0x808c4987, 0x01a92ca0, 0x30b11bd7,\n    0xb1947ef0, 0xe98ad7d8, 0x68afb2ff, 0x8bbab936, 0x0a9fdc11,\n    0x52817539, 0xd3a4101e, 0xe2bc2769, 0x6399424e, 0x3b87eb66,\n    0xbaa28e41, 0xd80a04cf, 0x592f61e8, 0x0131c8c0, 0x8014ade7,\n    0xb10c9a90, 0x3029ffb7, 0x6837569f, 0xe91233b8, 0x0a073871,\n    0x8b225d56, 0xd33cf47e, 0x52199159, 0x6301a62e, 0xe224c309,\n    0xba3a6a21, 0x3b1f0f06, 0xa7617bf2, 0x26441ed5, 0x7e5ab7fd,\n    0xff7fd2da, 0xce67e5ad, 0x4f42808a, 0x175c29a2, 0x96794c85,\n    0x756c474c, 0xf449226b, 0xac578b43, 0x2d72ee64, 0x1c6ad913,\n    0x9d4fbc34, 0xc551151c, 0x4474703b, 0x4db9f56a, 0xcc9c904d,\n    0x94823965, 0x15a75c42, 0x24bf6b35, 0xa59a0e12, 0xfd84a73a,\n    0x7ca1c21d, 0x9fb4c9d4, 0x1e91acf3, 0x468f05db, 0xc7aa60fc,\n    0xf6b2578b, 0x779732ac, 0x2f899b84, 0xaeacfea3, 0x32d28a57,\n    0xb3f7ef70, 0xebe94658, 0x6acc237f, 0x5bd41408, 0xdaf1712f,\n    0x82efd807, 0x03cabd20, 0xe0dfb6e9, 0x61fad3ce, 0x39e47ae6,\n    0xb8c11fc1, 0x89d928b6, 0x08fc4d91, 0x50e2e4b9, 0xd1c7819e,\n    0xb36f0b10, 0x324a6e37, 0x6a54c71f, 0xeb71a238, 0xda69954f,\n    0x5b4cf068, 0x03525940, 0x82773c67, 0x616237ae, 0xe0475289,\n    0xb859fba1, 0x397c9e86, 0x0864a9f1, 0x8941ccd6, 0xd15f65fe,\n    0x507a00d9, 0xcc04742d, 0x4d21110a, 0x153fb822, 0x941add05,\n    0xa502ea72, 0x24278f55, 0x7c39267d, 0xfd1c435a, 0x1e094893,\n    0x9f2c2db4, 0xc732849c, 0x4617e1bb, 0x770fd6cc, 0xf62ab3eb,\n    0xae341ac3, 0x2f117fe4, 0x6b650fdf, 0xea406af8, 0xb25ec3d0,\n    0x337ba6f7, 0x02639180, 0x8346f4a7, 0xdb585d8f, 0x5a7d38a8,\n    0xb9683361, 0x384d5646, 0x6053ff6e, 0xe1769a49, 0xd06ead3e,\n    0x514bc819, 0x09556131, 0x88700416, 0x140e70e2, 0x952b15c5,\n    0xcd35bced, 0x4c10d9ca, 0x7d08eebd, 0xfc2d8b9a, 0xa43322b2,\n    0x25164795, 0xc6034c5c, 0x4726297b, 0x1f388053, 0x9e1de574,\n    0xaf05d203, 0x2e20b724, 0x763e1e0c, 0xf71b7b2b, 0x95b3f1a5,\n    0x14969482, 0x4c883daa, 0xcdad588d, 0xfcb56ffa, 0x7d900add,\n    0x258ea3f5, 0xa4abc6d2, 0x47becd1b, 0xc69ba83c, 0x9e850114,\n    0x1fa06433, 0x2eb85344, 0xaf9d3663, 0xf7839f4b, 0x76a6fa6c,\n    0xead88e98, 0x6bfdebbf, 0x33e34297, 0xb2c627b0, 0x83de10c7,\n    0x02fb75e0, 0x5ae5dcc8, 0xdbc0b9ef, 0x38d5b226, 0xb9f0d701,\n    0xe1ee7e29, 0x60cb1b0e, 0x51d32c79, 0xd0f6495e, 0x88e8e076,\n    0x09cd8551},\n   {0x00000000, 0x9b73ead4, 0xed96d3e9, 0x76e5393d, 0x005ca193,\n    0x9b2f4b47, 0xedca727a, 0x76b998ae, 0x00b94326, 0x9bcaa9f2,\n    0xed2f90cf, 0x765c7a1b, 0x00e5e2b5, 0x9b960861, 0xed73315c,\n    0x7600db88, 0x0172864c, 0x9a016c98, 0xece455a5, 0x7797bf71,\n    0x012e27df, 0x9a5dcd0b, 0xecb8f436, 0x77cb1ee2, 0x01cbc56a,\n    0x9ab82fbe, 0xec5d1683, 0x772efc57, 0x019764f9, 0x9ae48e2d,\n    0xec01b710, 0x77725dc4, 0x02e50c98, 0x9996e64c, 0xef73df71,\n    0x740035a5, 0x02b9ad0b, 0x99ca47df, 0xef2f7ee2, 0x745c9436,\n    0x025c4fbe, 0x992fa56a, 0xefca9c57, 0x74b97683, 0x0200ee2d,\n    0x997304f9, 0xef963dc4, 0x74e5d710, 0x03978ad4, 0x98e46000,\n    0xee01593d, 0x7572b3e9, 0x03cb2b47, 0x98b8c193, 0xee5df8ae,\n    0x752e127a, 0x032ec9f2, 0x985d2326, 0xeeb81a1b, 0x75cbf0cf,\n    0x03726861, 0x980182b5, 0xeee4bb88, 0x7597515c, 0x05ca1930,\n    0x9eb9f3e4, 0xe85ccad9, 0x732f200d, 0x0596b8a3, 0x9ee55277,\n    0xe8006b4a, 0x7373819e, 0x05735a16, 0x9e00b0c2, 0xe8e589ff,\n    0x7396632b, 0x052ffb85, 0x9e5c1151, 0xe8b9286c, 0x73cac2b8,\n    0x04b89f7c, 0x9fcb75a8, 0xe92e4c95, 0x725da641, 0x04e43eef,\n    0x9f97d43b, 0xe972ed06, 0x720107d2, 0x0401dc5a, 0x9f72368e,\n    0xe9970fb3, 0x72e4e567, 0x045d7dc9, 0x9f2e971d, 0xe9cbae20,\n    0x72b844f4, 0x072f15a8, 0x9c5cff7c, 0xeab9c641, 0x71ca2c95,\n    0x0773b43b, 0x9c005eef, 0xeae567d2, 0x71968d06, 0x0796568e,\n    0x9ce5bc5a, 0xea008567, 0x71736fb3, 0x07caf71d, 0x9cb91dc9,\n    0xea5c24f4, 0x712fce20, 0x065d93e4, 0x9d2e7930, 0xebcb400d,\n    0x70b8aad9, 0x06013277, 0x9d72d8a3, 0xeb97e19e, 0x70e40b4a,\n    0x06e4d0c2, 0x9d973a16, 0xeb72032b, 0x7001e9ff, 0x06b87151,\n    0x9dcb9b85, 0xeb2ea2b8, 0x705d486c, 0x0b943260, 0x90e7d8b4,\n    0xe602e189, 0x7d710b5d, 0x0bc893f3, 0x90bb7927, 0xe65e401a,\n    0x7d2daace, 0x0b2d7146, 0x905e9b92, 0xe6bba2af, 0x7dc8487b,\n    0x0b71d0d5, 0x90023a01, 0xe6e7033c, 0x7d94e9e8, 0x0ae6b42c,\n    0x91955ef8, 0xe77067c5, 0x7c038d11, 0x0aba15bf, 0x91c9ff6b,\n    0xe72cc656, 0x7c5f2c82, 0x0a5ff70a, 0x912c1dde, 0xe7c924e3,\n    0x7cbace37, 0x0a035699, 0x9170bc4d, 0xe7958570, 0x7ce66fa4,\n    0x09713ef8, 0x9202d42c, 0xe4e7ed11, 0x7f9407c5, 0x092d9f6b,\n    0x925e75bf, 0xe4bb4c82, 0x7fc8a656, 0x09c87dde, 0x92bb970a,\n    0xe45eae37, 0x7f2d44e3, 0x0994dc4d, 0x92e73699, 0xe4020fa4,\n    0x7f71e570, 0x0803b8b4, 0x93705260, 0xe5956b5d, 0x7ee68189,\n    0x085f1927, 0x932cf3f3, 0xe5c9cace, 0x7eba201a, 0x08bafb92,\n    0x93c91146, 0xe52c287b, 0x7e5fc2af, 0x08e65a01, 0x9395b0d5,\n    0xe57089e8, 0x7e03633c, 0x0e5e2b50, 0x952dc184, 0xe3c8f8b9,\n    0x78bb126d, 0x0e028ac3, 0x95716017, 0xe394592a, 0x78e7b3fe,\n    0x0ee76876, 0x959482a2, 0xe371bb9f, 0x7802514b, 0x0ebbc9e5,\n    0x95c82331, 0xe32d1a0c, 0x785ef0d8, 0x0f2cad1c, 0x945f47c8,\n    0xe2ba7ef5, 0x79c99421, 0x0f700c8f, 0x9403e65b, 0xe2e6df66,\n    0x799535b2, 0x0f95ee3a, 0x94e604ee, 0xe2033dd3, 0x7970d707,\n    0x0fc94fa9, 0x94baa57d, 0xe25f9c40, 0x792c7694, 0x0cbb27c8,\n    0x97c8cd1c, 0xe12df421, 0x7a5e1ef5, 0x0ce7865b, 0x97946c8f,\n    0xe17155b2, 0x7a02bf66, 0x0c0264ee, 0x97718e3a, 0xe194b707,\n    0x7ae75dd3, 0x0c5ec57d, 0x972d2fa9, 0xe1c81694, 0x7abbfc40,\n    0x0dc9a184, 0x96ba4b50, 0xe05f726d, 0x7b2c98b9, 0x0d950017,\n    0x96e6eac3, 0xe003d3fe, 0x7b70392a, 0x0d70e2a2, 0x96030876,\n    0xe0e6314b, 0x7b95db9f, 0x0d2c4331, 0x965fa9e5, 0xe0ba90d8,\n    0x7bc97a0c},\n   {0x00000000, 0x172864c0, 0x2e50c980, 0x3978ad40, 0x5ca19300,\n    0x4b89f7c0, 0x72f15a80, 0x65d93e40, 0xb9432600, 0xae6b42c0,\n    0x9713ef80, 0x803b8b40, 0xe5e2b500, 0xf2cad1c0, 0xcbb27c80,\n    0xdc9a1840, 0xa9f74a41, 0xbedf2e81, 0x87a783c1, 0x908fe701,\n    0xf556d941, 0xe27ebd81, 0xdb0610c1, 0xcc2e7401, 0x10b46c41,\n    0x079c0881, 0x3ee4a5c1, 0x29ccc101, 0x4c15ff41, 0x5b3d9b81,\n    0x624536c1, 0x756d5201, 0x889f92c3, 0x9fb7f603, 0xa6cf5b43,\n    0xb1e73f83, 0xd43e01c3, 0xc3166503, 0xfa6ec843, 0xed46ac83,\n    0x31dcb4c3, 0x26f4d003, 0x1f8c7d43, 0x08a41983, 0x6d7d27c3,\n    0x7a554303, 0x432dee43, 0x54058a83, 0x2168d882, 0x3640bc42,\n    0x0f381102, 0x181075c2, 0x7dc94b82, 0x6ae12f42, 0x53998202,\n    0x44b1e6c2, 0x982bfe82, 0x8f039a42, 0xb67b3702, 0xa15353c2,\n    0xc48a6d82, 0xd3a20942, 0xeadaa402, 0xfdf2c0c2, 0xca4e23c7,\n    0xdd664707, 0xe41eea47, 0xf3368e87, 0x96efb0c7, 0x81c7d407,\n    0xb8bf7947, 0xaf971d87, 0x730d05c7, 0x64256107, 0x5d5dcc47,\n    0x4a75a887, 0x2fac96c7, 0x3884f207, 0x01fc5f47, 0x16d43b87,\n    0x63b96986, 0x74910d46, 0x4de9a006, 0x5ac1c4c6, 0x3f18fa86,\n    0x28309e46, 0x11483306, 0x066057c6, 0xdafa4f86, 0xcdd22b46,\n    0xf4aa8606, 0xe382e2c6, 0x865bdc86, 0x9173b846, 0xa80b1506,\n    0xbf2371c6, 0x42d1b104, 0x55f9d5c4, 0x6c817884, 0x7ba91c44,\n    0x1e702204, 0x095846c4, 0x3020eb84, 0x27088f44, 0xfb929704,\n    0xecbaf3c4, 0xd5c25e84, 0xc2ea3a44, 0xa7330404, 0xb01b60c4,\n    0x8963cd84, 0x9e4ba944, 0xeb26fb45, 0xfc0e9f85, 0xc57632c5,\n    0xd25e5605, 0xb7876845, 0xa0af0c85, 0x99d7a1c5, 0x8effc505,\n    0x5265dd45, 0x454db985, 0x7c3514c5, 0x6b1d7005, 0x0ec44e45,\n    0x19ec2a85, 0x209487c5, 0x37bce305, 0x4fed41cf, 0x58c5250f,\n    0x61bd884f, 0x7695ec8f, 0x134cd2cf, 0x0464b60f, 0x3d1c1b4f,\n    0x2a347f8f, 0xf6ae67cf, 0xe186030f, 0xd8feae4f, 0xcfd6ca8f,\n    0xaa0ff4cf, 0xbd27900f, 0x845f3d4f, 0x9377598f, 0xe61a0b8e,\n    0xf1326f4e, 0xc84ac20e, 0xdf62a6ce, 0xbabb988e, 0xad93fc4e,\n    0x94eb510e, 0x83c335ce, 0x5f592d8e, 0x4871494e, 0x7109e40e,\n    0x662180ce, 0x03f8be8e, 0x14d0da4e, 0x2da8770e, 0x3a8013ce,\n    0xc772d30c, 0xd05ab7cc, 0xe9221a8c, 0xfe0a7e4c, 0x9bd3400c,\n    0x8cfb24cc, 0xb583898c, 0xa2abed4c, 0x7e31f50c, 0x691991cc,\n    0x50613c8c, 0x4749584c, 0x2290660c, 0x35b802cc, 0x0cc0af8c,\n    0x1be8cb4c, 0x6e85994d, 0x79adfd8d, 0x40d550cd, 0x57fd340d,\n    0x32240a4d, 0x250c6e8d, 0x1c74c3cd, 0x0b5ca70d, 0xd7c6bf4d,\n    0xc0eedb8d, 0xf99676cd, 0xeebe120d, 0x8b672c4d, 0x9c4f488d,\n    0xa537e5cd, 0xb21f810d, 0x85a36208, 0x928b06c8, 0xabf3ab88,\n    0xbcdbcf48, 0xd902f108, 0xce2a95c8, 0xf7523888, 0xe07a5c48,\n    0x3ce04408, 0x2bc820c8, 0x12b08d88, 0x0598e948, 0x6041d708,\n    0x7769b3c8, 0x4e111e88, 0x59397a48, 0x2c542849, 0x3b7c4c89,\n    0x0204e1c9, 0x152c8509, 0x70f5bb49, 0x67dddf89, 0x5ea572c9,\n    0x498d1609, 0x95170e49, 0x823f6a89, 0xbb47c7c9, 0xac6fa309,\n    0xc9b69d49, 0xde9ef989, 0xe7e654c9, 0xf0ce3009, 0x0d3cf0cb,\n    0x1a14940b, 0x236c394b, 0x34445d8b, 0x519d63cb, 0x46b5070b,\n    0x7fcdaa4b, 0x68e5ce8b, 0xb47fd6cb, 0xa357b20b, 0x9a2f1f4b,\n    0x8d077b8b, 0xe8de45cb, 0xfff6210b, 0xc68e8c4b, 0xd1a6e88b,\n    0xa4cbba8a, 0xb3e3de4a, 0x8a9b730a, 0x9db317ca, 0xf86a298a,\n    0xef424d4a, 0xd63ae00a, 0xc11284ca, 0x1d889c8a, 0x0aa0f84a,\n    0x33d8550a, 0x24f031ca, 0x41290f8a, 0x56016b4a, 0x6f79c60a,\n    0x7851a2ca},\n   {0x00000000, 0x9fda839e, 0xe4c4017d, 0x7b1e82e3, 0x12f904bb,\n    0x8d238725, 0xf63d05c6, 0x69e78658, 0x25f20976, 0xba288ae8,\n    0xc136080b, 0x5eec8b95, 0x370b0dcd, 0xa8d18e53, 0xd3cf0cb0,\n    0x4c158f2e, 0x4be412ec, 0xd43e9172, 0xaf201391, 0x30fa900f,\n    0x591d1657, 0xc6c795c9, 0xbdd9172a, 0x220394b4, 0x6e161b9a,\n    0xf1cc9804, 0x8ad21ae7, 0x15089979, 0x7cef1f21, 0xe3359cbf,\n    0x982b1e5c, 0x07f19dc2, 0x97c825d8, 0x0812a646, 0x730c24a5,\n    0xecd6a73b, 0x85312163, 0x1aeba2fd, 0x61f5201e, 0xfe2fa380,\n    0xb23a2cae, 0x2de0af30, 0x56fe2dd3, 0xc924ae4d, 0xa0c32815,\n    0x3f19ab8b, 0x44072968, 0xdbddaaf6, 0xdc2c3734, 0x43f6b4aa,\n    0x38e83649, 0xa732b5d7, 0xced5338f, 0x510fb011, 0x2a1132f2,\n    0xb5cbb16c, 0xf9de3e42, 0x6604bddc, 0x1d1a3f3f, 0x82c0bca1,\n    0xeb273af9, 0x74fdb967, 0x0fe33b84, 0x9039b81a, 0xf4e14df1,\n    0x6b3bce6f, 0x10254c8c, 0x8fffcf12, 0xe618494a, 0x79c2cad4,\n    0x02dc4837, 0x9d06cba9, 0xd1134487, 0x4ec9c719, 0x35d745fa,\n    0xaa0dc664, 0xc3ea403c, 0x5c30c3a2, 0x272e4141, 0xb8f4c2df,\n    0xbf055f1d, 0x20dfdc83, 0x5bc15e60, 0xc41bddfe, 0xadfc5ba6,\n    0x3226d838, 0x49385adb, 0xd6e2d945, 0x9af7566b, 0x052dd5f5,\n    0x7e335716, 0xe1e9d488, 0x880e52d0, 0x17d4d14e, 0x6cca53ad,\n    0xf310d033, 0x63296829, 0xfcf3ebb7, 0x87ed6954, 0x1837eaca,\n    0x71d06c92, 0xee0aef0c, 0x95146def, 0x0aceee71, 0x46db615f,\n    0xd901e2c1, 0xa21f6022, 0x3dc5e3bc, 0x542265e4, 0xcbf8e67a,\n    0xb0e66499, 0x2f3ce707, 0x28cd7ac5, 0xb717f95b, 0xcc097bb8,\n    0x53d3f826, 0x3a347e7e, 0xa5eefde0, 0xdef07f03, 0x412afc9d,\n    0x0d3f73b3, 0x92e5f02d, 0xe9fb72ce, 0x7621f150, 0x1fc67708,\n    0x801cf496, 0xfb027675, 0x64d8f5eb, 0x32b39da3, 0xad691e3d,\n    0xd6779cde, 0x49ad1f40, 0x204a9918, 0xbf901a86, 0xc48e9865,\n    0x5b541bfb, 0x174194d5, 0x889b174b, 0xf38595a8, 0x6c5f1636,\n    0x05b8906e, 0x9a6213f0, 0xe17c9113, 0x7ea6128d, 0x79578f4f,\n    0xe68d0cd1, 0x9d938e32, 0x02490dac, 0x6bae8bf4, 0xf474086a,\n    0x8f6a8a89, 0x10b00917, 0x5ca58639, 0xc37f05a7, 0xb8618744,\n    0x27bb04da, 0x4e5c8282, 0xd186011c, 0xaa9883ff, 0x35420061,\n    0xa57bb87b, 0x3aa13be5, 0x41bfb906, 0xde653a98, 0xb782bcc0,\n    0x28583f5e, 0x5346bdbd, 0xcc9c3e23, 0x8089b10d, 0x1f533293,\n    0x644db070, 0xfb9733ee, 0x9270b5b6, 0x0daa3628, 0x76b4b4cb,\n    0xe96e3755, 0xee9faa97, 0x71452909, 0x0a5babea, 0x95812874,\n    0xfc66ae2c, 0x63bc2db2, 0x18a2af51, 0x87782ccf, 0xcb6da3e1,\n    0x54b7207f, 0x2fa9a29c, 0xb0732102, 0xd994a75a, 0x464e24c4,\n    0x3d50a627, 0xa28a25b9, 0xc652d052, 0x598853cc, 0x2296d12f,\n    0xbd4c52b1, 0xd4abd4e9, 0x4b715777, 0x306fd594, 0xafb5560a,\n    0xe3a0d924, 0x7c7a5aba, 0x0764d859, 0x98be5bc7, 0xf159dd9f,\n    0x6e835e01, 0x159ddce2, 0x8a475f7c, 0x8db6c2be, 0x126c4120,\n    0x6972c3c3, 0xf6a8405d, 0x9f4fc605, 0x0095459b, 0x7b8bc778,\n    0xe45144e6, 0xa844cbc8, 0x379e4856, 0x4c80cab5, 0xd35a492b,\n    0xbabdcf73, 0x25674ced, 0x5e79ce0e, 0xc1a34d90, 0x519af58a,\n    0xce407614, 0xb55ef4f7, 0x2a847769, 0x4363f131, 0xdcb972af,\n    0xa7a7f04c, 0x387d73d2, 0x7468fcfc, 0xebb27f62, 0x90acfd81,\n    0x0f767e1f, 0x6691f847, 0xf94b7bd9, 0x8255f93a, 0x1d8f7aa4,\n    0x1a7ee766, 0x85a464f8, 0xfebae61b, 0x61606585, 0x0887e3dd,\n    0x975d6043, 0xec43e2a0, 0x7399613e, 0x3f8cee10, 0xa0566d8e,\n    0xdb48ef6d, 0x44926cf3, 0x2d75eaab, 0xb2af6935, 0xc9b1ebd6,\n    0x566b6848}};\n\nlocal const z_word_t FAR crc_braid_big_table[][256] = {\n   {0x00000000, 0x9e83da9f, 0x7d01c4e4, 0xe3821e7b, 0xbb04f912,\n    0x2587238d, 0xc6053df6, 0x5886e769, 0x7609f225, 0xe88a28ba,\n    0x0b0836c1, 0x958bec5e, 0xcd0d0b37, 0x538ed1a8, 0xb00ccfd3,\n    0x2e8f154c, 0xec12e44b, 0x72913ed4, 0x911320af, 0x0f90fa30,\n    0x57161d59, 0xc995c7c6, 0x2a17d9bd, 0xb4940322, 0x9a1b166e,\n    0x0498ccf1, 0xe71ad28a, 0x79990815, 0x211fef7c, 0xbf9c35e3,\n    0x5c1e2b98, 0xc29df107, 0xd825c897, 0x46a61208, 0xa5240c73,\n    0x3ba7d6ec, 0x63213185, 0xfda2eb1a, 0x1e20f561, 0x80a32ffe,\n    0xae2c3ab2, 0x30afe02d, 0xd32dfe56, 0x4dae24c9, 0x1528c3a0,\n    0x8bab193f, 0x68290744, 0xf6aadddb, 0x34372cdc, 0xaab4f643,\n    0x4936e838, 0xd7b532a7, 0x8f33d5ce, 0x11b00f51, 0xf232112a,\n    0x6cb1cbb5, 0x423edef9, 0xdcbd0466, 0x3f3f1a1d, 0xa1bcc082,\n    0xf93a27eb, 0x67b9fd74, 0x843be30f, 0x1ab83990, 0xf14de1f4,\n    0x6fce3b6b, 0x8c4c2510, 0x12cfff8f, 0x4a4918e6, 0xd4cac279,\n    0x3748dc02, 0xa9cb069d, 0x874413d1, 0x19c7c94e, 0xfa45d735,\n    0x64c60daa, 0x3c40eac3, 0xa2c3305c, 0x41412e27, 0xdfc2f4b8,\n    0x1d5f05bf, 0x83dcdf20, 0x605ec15b, 0xfedd1bc4, 0xa65bfcad,\n    0x38d82632, 0xdb5a3849, 0x45d9e2d6, 0x6b56f79a, 0xf5d52d05,\n    0x1657337e, 0x88d4e9e1, 0xd0520e88, 0x4ed1d417, 0xad53ca6c,\n    0x33d010f3, 0x29682963, 0xb7ebf3fc, 0x5469ed87, 0xcaea3718,\n    0x926cd071, 0x0cef0aee, 0xef6d1495, 0x71eece0a, 0x5f61db46,\n    0xc1e201d9, 0x22601fa2, 0xbce3c53d, 0xe4652254, 0x7ae6f8cb,\n    0x9964e6b0, 0x07e73c2f, 0xc57acd28, 0x5bf917b7, 0xb87b09cc,\n    0x26f8d353, 0x7e7e343a, 0xe0fdeea5, 0x037ff0de, 0x9dfc2a41,\n    0xb3733f0d, 0x2df0e592, 0xce72fbe9, 0x50f12176, 0x0877c61f,\n    0x96f41c80, 0x757602fb, 0xebf5d864, 0xa39db332, 0x3d1e69ad,\n    0xde9c77d6, 0x401fad49, 0x18994a20, 0x861a90bf, 0x65988ec4,\n    0xfb1b545b, 0xd5944117, 0x4b179b88, 0xa89585f3, 0x36165f6c,\n    0x6e90b805, 0xf013629a, 0x13917ce1, 0x8d12a67e, 0x4f8f5779,\n    0xd10c8de6, 0x328e939d, 0xac0d4902, 0xf48bae6b, 0x6a0874f4,\n    0x898a6a8f, 0x1709b010, 0x3986a55c, 0xa7057fc3, 0x448761b8,\n    0xda04bb27, 0x82825c4e, 0x1c0186d1, 0xff8398aa, 0x61004235,\n    0x7bb87ba5, 0xe53ba13a, 0x06b9bf41, 0x983a65de, 0xc0bc82b7,\n    0x5e3f5828, 0xbdbd4653, 0x233e9ccc, 0x0db18980, 0x9332531f,\n    0x70b04d64, 0xee3397fb, 0xb6b57092, 0x2836aa0d, 0xcbb4b476,\n    0x55376ee9, 0x97aa9fee, 0x09294571, 0xeaab5b0a, 0x74288195,\n    0x2cae66fc, 0xb22dbc63, 0x51afa218, 0xcf2c7887, 0xe1a36dcb,\n    0x7f20b754, 0x9ca2a92f, 0x022173b0, 0x5aa794d9, 0xc4244e46,\n    0x27a6503d, 0xb9258aa2, 0x52d052c6, 0xcc538859, 0x2fd19622,\n    0xb1524cbd, 0xe9d4abd4, 0x7757714b, 0x94d56f30, 0x0a56b5af,\n    0x24d9a0e3, 0xba5a7a7c, 0x59d86407, 0xc75bbe98, 0x9fdd59f1,\n    0x015e836e, 0xe2dc9d15, 0x7c5f478a, 0xbec2b68d, 0x20416c12,\n    0xc3c37269, 0x5d40a8f6, 0x05c64f9f, 0x9b459500, 0x78c78b7b,\n    0xe64451e4, 0xc8cb44a8, 0x56489e37, 0xb5ca804c, 0x2b495ad3,\n    0x73cfbdba, 0xed4c6725, 0x0ece795e, 0x904da3c1, 0x8af59a51,\n    0x147640ce, 0xf7f45eb5, 0x6977842a, 0x31f16343, 0xaf72b9dc,\n    0x4cf0a7a7, 0xd2737d38, 0xfcfc6874, 0x627fb2eb, 0x81fdac90,\n    0x1f7e760f, 0x47f89166, 0xd97b4bf9, 0x3af95582, 0xa47a8f1d,\n    0x66e77e1a, 0xf864a485, 0x1be6bafe, 0x85656061, 0xdde38708,\n    0x43605d97, 0xa0e243ec, 0x3e619973, 0x10ee8c3f, 0x8e6d56a0,\n    0x6def48db, 0xf36c9244, 0xabea752d, 0x3569afb2, 0xd6ebb1c9,\n    0x48686b56},\n   {0x00000000, 0xc0642817, 0x80c9502e, 0x40ad7839, 0x0093a15c,\n    0xc0f7894b, 0x805af172, 0x403ed965, 0x002643b9, 0xc0426bae,\n    0x80ef1397, 0x408b3b80, 0x00b5e2e5, 0xc0d1caf2, 0x807cb2cb,\n    0x40189adc, 0x414af7a9, 0x812edfbe, 0xc183a787, 0x01e78f90,\n    0x41d956f5, 0x81bd7ee2, 0xc11006db, 0x01742ecc, 0x416cb410,\n    0x81089c07, 0xc1a5e43e, 0x01c1cc29, 0x41ff154c, 0x819b3d5b,\n    0xc1364562, 0x01526d75, 0xc3929f88, 0x03f6b79f, 0x435bcfa6,\n    0x833fe7b1, 0xc3013ed4, 0x036516c3, 0x43c86efa, 0x83ac46ed,\n    0xc3b4dc31, 0x03d0f426, 0x437d8c1f, 0x8319a408, 0xc3277d6d,\n    0x0343557a, 0x43ee2d43, 0x838a0554, 0x82d86821, 0x42bc4036,\n    0x0211380f, 0xc2751018, 0x824bc97d, 0x422fe16a, 0x02829953,\n    0xc2e6b144, 0x82fe2b98, 0x429a038f, 0x02377bb6, 0xc25353a1,\n    0x826d8ac4, 0x4209a2d3, 0x02a4daea, 0xc2c0f2fd, 0xc7234eca,\n    0x074766dd, 0x47ea1ee4, 0x878e36f3, 0xc7b0ef96, 0x07d4c781,\n    0x4779bfb8, 0x871d97af, 0xc7050d73, 0x07612564, 0x47cc5d5d,\n    0x87a8754a, 0xc796ac2f, 0x07f28438, 0x475ffc01, 0x873bd416,\n    0x8669b963, 0x460d9174, 0x06a0e94d, 0xc6c4c15a, 0x86fa183f,\n    0x469e3028, 0x06334811, 0xc6576006, 0x864ffada, 0x462bd2cd,\n    0x0686aaf4, 0xc6e282e3, 0x86dc5b86, 0x46b87391, 0x06150ba8,\n    0xc67123bf, 0x04b1d142, 0xc4d5f955, 0x8478816c, 0x441ca97b,\n    0x0422701e, 0xc4465809, 0x84eb2030, 0x448f0827, 0x049792fb,\n    0xc4f3baec, 0x845ec2d5, 0x443aeac2, 0x040433a7, 0xc4601bb0,\n    0x84cd6389, 0x44a94b9e, 0x45fb26eb, 0x859f0efc, 0xc53276c5,\n    0x05565ed2, 0x456887b7, 0x850cafa0, 0xc5a1d799, 0x05c5ff8e,\n    0x45dd6552, 0x85b94d45, 0xc514357c, 0x05701d6b, 0x454ec40e,\n    0x852aec19, 0xc5879420, 0x05e3bc37, 0xcf41ed4f, 0x0f25c558,\n    0x4f88bd61, 0x8fec9576, 0xcfd24c13, 0x0fb66404, 0x4f1b1c3d,\n    0x8f7f342a, 0xcf67aef6, 0x0f0386e1, 0x4faefed8, 0x8fcad6cf,\n    0xcff40faa, 0x0f9027bd, 0x4f3d5f84, 0x8f597793, 0x8e0b1ae6,\n    0x4e6f32f1, 0x0ec24ac8, 0xcea662df, 0x8e98bbba, 0x4efc93ad,\n    0x0e51eb94, 0xce35c383, 0x8e2d595f, 0x4e497148, 0x0ee40971,\n    0xce802166, 0x8ebef803, 0x4edad014, 0x0e77a82d, 0xce13803a,\n    0x0cd372c7, 0xccb75ad0, 0x8c1a22e9, 0x4c7e0afe, 0x0c40d39b,\n    0xcc24fb8c, 0x8c8983b5, 0x4cedaba2, 0x0cf5317e, 0xcc911969,\n    0x8c3c6150, 0x4c584947, 0x0c669022, 0xcc02b835, 0x8cafc00c,\n    0x4ccbe81b, 0x4d99856e, 0x8dfdad79, 0xcd50d540, 0x0d34fd57,\n    0x4d0a2432, 0x8d6e0c25, 0xcdc3741c, 0x0da75c0b, 0x4dbfc6d7,\n    0x8ddbeec0, 0xcd7696f9, 0x0d12beee, 0x4d2c678b, 0x8d484f9c,\n    0xcde537a5, 0x0d811fb2, 0x0862a385, 0xc8068b92, 0x88abf3ab,\n    0x48cfdbbc, 0x08f102d9, 0xc8952ace, 0x883852f7, 0x485c7ae0,\n    0x0844e03c, 0xc820c82b, 0x888db012, 0x48e99805, 0x08d74160,\n    0xc8b36977, 0x881e114e, 0x487a3959, 0x4928542c, 0x894c7c3b,\n    0xc9e10402, 0x09852c15, 0x49bbf570, 0x89dfdd67, 0xc972a55e,\n    0x09168d49, 0x490e1795, 0x896a3f82, 0xc9c747bb, 0x09a36fac,\n    0x499db6c9, 0x89f99ede, 0xc954e6e7, 0x0930cef0, 0xcbf03c0d,\n    0x0b94141a, 0x4b396c23, 0x8b5d4434, 0xcb639d51, 0x0b07b546,\n    0x4baacd7f, 0x8bcee568, 0xcbd67fb4, 0x0bb257a3, 0x4b1f2f9a,\n    0x8b7b078d, 0xcb45dee8, 0x0b21f6ff, 0x4b8c8ec6, 0x8be8a6d1,\n    0x8abacba4, 0x4adee3b3, 0x0a739b8a, 0xca17b39d, 0x8a296af8,\n    0x4a4d42ef, 0x0ae03ad6, 0xca8412c1, 0x8a9c881d, 0x4af8a00a,\n    0x0a55d833, 0xca31f024, 0x8a0f2941, 0x4a6b0156, 0x0ac6796f,\n    0xcaa25178},\n   {0x00000000, 0xd4ea739b, 0xe9d396ed, 0x3d39e576, 0x93a15c00,\n    0x474b2f9b, 0x7a72caed, 0xae98b976, 0x2643b900, 0xf2a9ca9b,\n    0xcf902fed, 0x1b7a5c76, 0xb5e2e500, 0x6108969b, 0x5c3173ed,\n    0x88db0076, 0x4c867201, 0x986c019a, 0xa555e4ec, 0x71bf9777,\n    0xdf272e01, 0x0bcd5d9a, 0x36f4b8ec, 0xe21ecb77, 0x6ac5cb01,\n    0xbe2fb89a, 0x83165dec, 0x57fc2e77, 0xf9649701, 0x2d8ee49a,\n    0x10b701ec, 0xc45d7277, 0x980ce502, 0x4ce69699, 0x71df73ef,\n    0xa5350074, 0x0badb902, 0xdf47ca99, 0xe27e2fef, 0x36945c74,\n    0xbe4f5c02, 0x6aa52f99, 0x579ccaef, 0x8376b974, 0x2dee0002,\n    0xf9047399, 0xc43d96ef, 0x10d7e574, 0xd48a9703, 0x0060e498,\n    0x3d5901ee, 0xe9b37275, 0x472bcb03, 0x93c1b898, 0xaef85dee,\n    0x7a122e75, 0xf2c92e03, 0x26235d98, 0x1b1ab8ee, 0xcff0cb75,\n    0x61687203, 0xb5820198, 0x88bbe4ee, 0x5c519775, 0x3019ca05,\n    0xe4f3b99e, 0xd9ca5ce8, 0x0d202f73, 0xa3b89605, 0x7752e59e,\n    0x4a6b00e8, 0x9e817373, 0x165a7305, 0xc2b0009e, 0xff89e5e8,\n    0x2b639673, 0x85fb2f05, 0x51115c9e, 0x6c28b9e8, 0xb8c2ca73,\n    0x7c9fb804, 0xa875cb9f, 0x954c2ee9, 0x41a65d72, 0xef3ee404,\n    0x3bd4979f, 0x06ed72e9, 0xd2070172, 0x5adc0104, 0x8e36729f,\n    0xb30f97e9, 0x67e5e472, 0xc97d5d04, 0x1d972e9f, 0x20aecbe9,\n    0xf444b872, 0xa8152f07, 0x7cff5c9c, 0x41c6b9ea, 0x952cca71,\n    0x3bb47307, 0xef5e009c, 0xd267e5ea, 0x068d9671, 0x8e569607,\n    0x5abce59c, 0x678500ea, 0xb36f7371, 0x1df7ca07, 0xc91db99c,\n    0xf4245cea, 0x20ce2f71, 0xe4935d06, 0x30792e9d, 0x0d40cbeb,\n    0xd9aab870, 0x77320106, 0xa3d8729d, 0x9ee197eb, 0x4a0be470,\n    0xc2d0e406, 0x163a979d, 0x2b0372eb, 0xffe90170, 0x5171b806,\n    0x859bcb9d, 0xb8a22eeb, 0x6c485d70, 0x6032940b, 0xb4d8e790,\n    0x89e102e6, 0x5d0b717d, 0xf393c80b, 0x2779bb90, 0x1a405ee6,\n    0xceaa2d7d, 0x46712d0b, 0x929b5e90, 0xafa2bbe6, 0x7b48c87d,\n    0xd5d0710b, 0x013a0290, 0x3c03e7e6, 0xe8e9947d, 0x2cb4e60a,\n    0xf85e9591, 0xc56770e7, 0x118d037c, 0xbf15ba0a, 0x6bffc991,\n    0x56c62ce7, 0x822c5f7c, 0x0af75f0a, 0xde1d2c91, 0xe324c9e7,\n    0x37ceba7c, 0x9956030a, 0x4dbc7091, 0x708595e7, 0xa46fe67c,\n    0xf83e7109, 0x2cd40292, 0x11ede7e4, 0xc507947f, 0x6b9f2d09,\n    0xbf755e92, 0x824cbbe4, 0x56a6c87f, 0xde7dc809, 0x0a97bb92,\n    0x37ae5ee4, 0xe3442d7f, 0x4ddc9409, 0x9936e792, 0xa40f02e4,\n    0x70e5717f, 0xb4b80308, 0x60527093, 0x5d6b95e5, 0x8981e67e,\n    0x27195f08, 0xf3f32c93, 0xcecac9e5, 0x1a20ba7e, 0x92fbba08,\n    0x4611c993, 0x7b282ce5, 0xafc25f7e, 0x015ae608, 0xd5b09593,\n    0xe88970e5, 0x3c63037e, 0x502b5e0e, 0x84c12d95, 0xb9f8c8e3,\n    0x6d12bb78, 0xc38a020e, 0x17607195, 0x2a5994e3, 0xfeb3e778,\n    0x7668e70e, 0xa2829495, 0x9fbb71e3, 0x4b510278, 0xe5c9bb0e,\n    0x3123c895, 0x0c1a2de3, 0xd8f05e78, 0x1cad2c0f, 0xc8475f94,\n    0xf57ebae2, 0x2194c979, 0x8f0c700f, 0x5be60394, 0x66dfe6e2,\n    0xb2359579, 0x3aee950f, 0xee04e694, 0xd33d03e2, 0x07d77079,\n    0xa94fc90f, 0x7da5ba94, 0x409c5fe2, 0x94762c79, 0xc827bb0c,\n    0x1ccdc897, 0x21f42de1, 0xf51e5e7a, 0x5b86e70c, 0x8f6c9497,\n    0xb25571e1, 0x66bf027a, 0xee64020c, 0x3a8e7197, 0x07b794e1,\n    0xd35de77a, 0x7dc55e0c, 0xa92f2d97, 0x9416c8e1, 0x40fcbb7a,\n    0x84a1c90d, 0x504bba96, 0x6d725fe0, 0xb9982c7b, 0x1700950d,\n    0xc3eae696, 0xfed303e0, 0x2a39707b, 0xa2e2700d, 0x76080396,\n    0x4b31e6e0, 0x9fdb957b, 0x31432c0d, 0xe5a95f96, 0xd890bae0,\n    0x0c7ac97b},\n   {0x00000000, 0x27652581, 0x0fcc3bd9, 0x28a91e58, 0x5f9e0669,\n    0x78fb23e8, 0x50523db0, 0x77371831, 0xbe3c0dd2, 0x99592853,\n    0xb1f0360b, 0x9695138a, 0xe1a20bbb, 0xc6c72e3a, 0xee6e3062,\n    0xc90b15e3, 0x3d7f6b7f, 0x1a1a4efe, 0x32b350a6, 0x15d67527,\n    0x62e16d16, 0x45844897, 0x6d2d56cf, 0x4a48734e, 0x834366ad,\n    0xa426432c, 0x8c8f5d74, 0xabea78f5, 0xdcdd60c4, 0xfbb84545,\n    0xd3115b1d, 0xf4747e9c, 0x7afed6fe, 0x5d9bf37f, 0x7532ed27,\n    0x5257c8a6, 0x2560d097, 0x0205f516, 0x2aaceb4e, 0x0dc9cecf,\n    0xc4c2db2c, 0xe3a7fead, 0xcb0ee0f5, 0xec6bc574, 0x9b5cdd45,\n    0xbc39f8c4, 0x9490e69c, 0xb3f5c31d, 0x4781bd81, 0x60e49800,\n    0x484d8658, 0x6f28a3d9, 0x181fbbe8, 0x3f7a9e69, 0x17d38031,\n    0x30b6a5b0, 0xf9bdb053, 0xded895d2, 0xf6718b8a, 0xd114ae0b,\n    0xa623b63a, 0x814693bb, 0xa9ef8de3, 0x8e8aa862, 0xb5fadc26,\n    0x929ff9a7, 0xba36e7ff, 0x9d53c27e, 0xea64da4f, 0xcd01ffce,\n    0xe5a8e196, 0xc2cdc417, 0x0bc6d1f4, 0x2ca3f475, 0x040aea2d,\n    0x236fcfac, 0x5458d79d, 0x733df21c, 0x5b94ec44, 0x7cf1c9c5,\n    0x8885b759, 0xafe092d8, 0x87498c80, 0xa02ca901, 0xd71bb130,\n    0xf07e94b1, 0xd8d78ae9, 0xffb2af68, 0x36b9ba8b, 0x11dc9f0a,\n    0x39758152, 0x1e10a4d3, 0x6927bce2, 0x4e429963, 0x66eb873b,\n    0x418ea2ba, 0xcf040ad8, 0xe8612f59, 0xc0c83101, 0xe7ad1480,\n    0x909a0cb1, 0xb7ff2930, 0x9f563768, 0xb83312e9, 0x7138070a,\n    0x565d228b, 0x7ef43cd3, 0x59911952, 0x2ea60163, 0x09c324e2,\n    0x216a3aba, 0x060f1f3b, 0xf27b61a7, 0xd51e4426, 0xfdb75a7e,\n    0xdad27fff, 0xade567ce, 0x8a80424f, 0xa2295c17, 0x854c7996,\n    0x4c476c75, 0x6b2249f4, 0x438b57ac, 0x64ee722d, 0x13d96a1c,\n    0x34bc4f9d, 0x1c1551c5, 0x3b707444, 0x6af5b94d, 0x4d909ccc,\n    0x65398294, 0x425ca715, 0x356bbf24, 0x120e9aa5, 0x3aa784fd,\n    0x1dc2a17c, 0xd4c9b49f, 0xf3ac911e, 0xdb058f46, 0xfc60aac7,\n    0x8b57b2f6, 0xac329777, 0x849b892f, 0xa3feacae, 0x578ad232,\n    0x70eff7b3, 0x5846e9eb, 0x7f23cc6a, 0x0814d45b, 0x2f71f1da,\n    0x07d8ef82, 0x20bdca03, 0xe9b6dfe0, 0xced3fa61, 0xe67ae439,\n    0xc11fc1b8, 0xb628d989, 0x914dfc08, 0xb9e4e250, 0x9e81c7d1,\n    0x100b6fb3, 0x376e4a32, 0x1fc7546a, 0x38a271eb, 0x4f9569da,\n    0x68f04c5b, 0x40595203, 0x673c7782, 0xae376261, 0x895247e0,\n    0xa1fb59b8, 0x869e7c39, 0xf1a96408, 0xd6cc4189, 0xfe655fd1,\n    0xd9007a50, 0x2d7404cc, 0x0a11214d, 0x22b83f15, 0x05dd1a94,\n    0x72ea02a5, 0x558f2724, 0x7d26397c, 0x5a431cfd, 0x9348091e,\n    0xb42d2c9f, 0x9c8432c7, 0xbbe11746, 0xccd60f77, 0xebb32af6,\n    0xc31a34ae, 0xe47f112f, 0xdf0f656b, 0xf86a40ea, 0xd0c35eb2,\n    0xf7a67b33, 0x80916302, 0xa7f44683, 0x8f5d58db, 0xa8387d5a,\n    0x613368b9, 0x46564d38, 0x6eff5360, 0x499a76e1, 0x3ead6ed0,\n    0x19c84b51, 0x31615509, 0x16047088, 0xe2700e14, 0xc5152b95,\n    0xedbc35cd, 0xcad9104c, 0xbdee087d, 0x9a8b2dfc, 0xb22233a4,\n    0x95471625, 0x5c4c03c6, 0x7b292647, 0x5380381f, 0x74e51d9e,\n    0x03d205af, 0x24b7202e, 0x0c1e3e76, 0x2b7b1bf7, 0xa5f1b395,\n    0x82949614, 0xaa3d884c, 0x8d58adcd, 0xfa6fb5fc, 0xdd0a907d,\n    0xf5a38e25, 0xd2c6aba4, 0x1bcdbe47, 0x3ca89bc6, 0x1401859e,\n    0x3364a01f, 0x4453b82e, 0x63369daf, 0x4b9f83f7, 0x6cfaa676,\n    0x988ed8ea, 0xbfebfd6b, 0x9742e333, 0xb027c6b2, 0xc710de83,\n    0xe075fb02, 0xc8dce55a, 0xefb9c0db, 0x26b2d538, 0x01d7f0b9,\n    0x297eeee1, 0x0e1bcb60, 0x792cd351, 0x5e49f6d0, 0x76e0e888,\n    0x5185cd09}};\n\n#endif\n\n#endif\n\n#endif\n\nlocal const z_crc_t FAR x2n_table[] = {\n    0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000,\n    0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467,\n    0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0,\n    0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169,\n    0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37,\n    0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a,\n    0xc40ba6d0, 0xc4e22c3c};\n"
  },
  {
    "path": "eidos_zlib/deflate.c",
    "content": "/* deflate.c -- compress data using the deflation algorithm\n * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n// BCH 16 April 2020: adding pragmas to disable spurious warnings\n#pragma GCC diagnostic ignored \"-Wshorten-64-to-32\"\n#pragma clang diagnostic ignored \"-Wshorten-64-to-32\"\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic ignored \"-Wconversion\"\n#pragma GCC diagnostic ignored \"-Wcomma\"\n#pragma clang diagnostic ignored \"-Wcomma\"\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process depends on being able to identify portions\n *      of the input text which are identical to earlier input (within a\n *      sliding window trailing behind the input currently being processed).\n *\n *      The most straightforward technique turns out to be the fastest for\n *      most input files: try all possible matches and select the longest.\n *      The key feature of this algorithm is that insertions into the string\n *      dictionary are very simple and thus fast, and deletions are avoided\n *      completely. Insertions are performed at each input character, whereas\n *      string matches are performed only when the previous match ends. So it\n *      is preferable to spend more time in matches to allow very fast string\n *      insertions and avoid deletions. The matching algorithm for small\n *      strings is inspired from that of Rabin & Karp. A brute force approach\n *      is used to find longer strings when a small match has been found.\n *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze\n *      (by Leonid Broukhis).\n *         A previous version of this file used a more sophisticated algorithm\n *      (by Fiala and Greene) which is guaranteed to run in linear amortized\n *      time, but has a larger average cost, uses more memory and is patented.\n *      However the F&G algorithm may be faster for some highly redundant\n *      files if the parameter max_chain_length (described below) is too large.\n *\n *  ACKNOWLEDGEMENTS\n *\n *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and\n *      I found it in 'freeze' written by Leonid Broukhis.\n *      Thanks to many people for bug reports and testing.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"DEFLATE Compressed Data Format Specification\".\n *      Available in http://tools.ietf.org/html/rfc1951\n *\n *      A description of the Rabin and Karp algorithm is given in the book\n *         \"Algorithms\" by R. Sedgewick, Addison-Wesley, p252.\n *\n *      Fiala,E.R., and Greene,D.H.\n *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595\n *\n */\n\n/* @(#) $Id$ */\n\n#include \"deflate.h\"\n\nconst char deflate_copyright[] =\n   \" deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\ntypedef enum {\n    need_more,      /* block not completed, need more input or more output */\n    block_done,     /* block flush performed */\n    finish_started, /* finish started, need only more output at next deflate */\n    finish_done     /* finish done, accept no more input or output */\n} block_state;\n\ntypedef block_state (*compress_func)(deflate_state *s, int flush);\n/* Compression function. Returns the block state after the call. */\n\nlocal block_state deflate_stored(deflate_state *s, int flush);\nlocal block_state deflate_fast(deflate_state *s, int flush);\n#ifndef FASTEST\nlocal block_state deflate_slow(deflate_state *s, int flush);\n#endif\nlocal block_state deflate_rle(deflate_state *s, int flush);\nlocal block_state deflate_huff(deflate_state *s, int flush);\n\n/* ===========================================================================\n * Local data\n */\n\n#define NIL 0\n/* Tail of hash chains */\n\n#ifndef TOO_FAR\n#  define TOO_FAR 4096\n#endif\n/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\ntypedef struct config_s {\n   ush good_length; /* reduce lazy search above this match length */\n   ush max_lazy;    /* do not perform lazy search above this match length */\n   ush nice_length; /* quit search above this match length */\n   ush max_chain;\n   compress_func func;\n} config;\n\n#ifdef FASTEST\nlocal const config configuration_table[2] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */\n#else\nlocal const config configuration_table[10] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */\n/* 2 */ {4,    5, 16,    8, deflate_fast},\n/* 3 */ {4,    6, 32,   32, deflate_fast},\n\n/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */\n/* 5 */ {8,   16, 32,   32, deflate_slow},\n/* 6 */ {8,   16, 128, 128, deflate_slow},\n/* 7 */ {8,   32, 128, 256, deflate_slow},\n/* 8 */ {32, 128, 258, 1024, deflate_slow},\n/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */\n#endif\n\n/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4\n * For deflate_fast() (levels <= 3) good is ignored and lazy has a different\n * meaning.\n */\n\n/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */\n#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))\n\n/* ===========================================================================\n * Update a hash value with the given input byte\n * IN  assertion: all calls to UPDATE_HASH are made with consecutive input\n *    characters, so that a running hash key can be computed from the previous\n *    key instead of complete recalculation each time.\n */\n#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask)\n\n\n/* ===========================================================================\n * Insert string str in the dictionary and set match_head to the previous head\n * of the hash chain (the most recent string with same hash key). Return\n * the previous length of the hash chain.\n * If this file is compiled with -DFASTEST, the compression level is forced\n * to 1, and no hash chains are maintained.\n * IN  assertion: all calls to INSERT_STRING are made with consecutive input\n *    characters and the first MIN_MATCH bytes of str are valid (except for\n *    the last MIN_MATCH-1 bytes of the input file).\n */\n#ifdef FASTEST\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#else\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#endif\n\n/* ===========================================================================\n * Initialize the hash table (avoiding 64K overflow for 16 bit systems).\n * prev[] will be initialized on the fly.\n */\n#define CLEAR_HASH(s) \\\n    do { \\\n        s->head[s->hash_size - 1] = NIL; \\\n        zmemzero((Bytef *)s->head, \\\n                 (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \\\n    } while (0)\n\n/* ===========================================================================\n * Slide the hash table when sliding the window down (could be avoided with 32\n * bit values at the expense of memory usage). We slide even when level == 0 to\n * keep the hash table consistent if we switch back to level > 0 later.\n */\n#if defined(__has_feature)\n#  if __has_feature(memory_sanitizer)\n     __attribute__((no_sanitize(\"memory\")))\n#  endif\n#endif\nlocal void slide_hash(deflate_state *s) {\n    unsigned n, m;\n    Posf *p;\n    uInt wsize = s->w_size;\n\n    n = s->hash_size;\n    p = &s->head[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n    } while (--n);\n    n = wsize;\n#ifndef FASTEST\n    p = &s->prev[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n    } while (--n);\n#endif\n}\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->next_in buffer and copying from it.\n * (See also flush_pending()).\n */\nlocal unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) {\n    unsigned len = strm->avail_in;\n\n    if (len > size) len = size;\n    if (len == 0) return 0;\n\n    strm->avail_in  -= len;\n\n    zmemcpy(buf, strm->next_in, len);\n    if (strm->state->wrap == 1) {\n        strm->adler = adler32(strm->adler, buf, len);\n    }\n#ifdef GZIP\n    else if (strm->state->wrap == 2) {\n        strm->adler = crc32(strm->adler, buf, len);\n    }\n#endif\n    strm->next_in  += len;\n    strm->total_in += len;\n\n    return len;\n}\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nlocal void fill_window(deflate_state *s) {\n    unsigned n;\n    unsigned more;    /* Amount of free space at the end of the window. */\n    uInt wsize = s->w_size;\n\n    Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n    do {\n        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);\n\n        /* Deal with !@#$% 64K limit: */\n        if (sizeof(int) <= 2) {\n            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n                more = wsize;\n\n            } else if (more == (unsigned)(-1)) {\n                /* Very unlikely, but possible on 16 bit machine if\n                 * strstart == 0 && lookahead == 1 (input done a byte at time)\n                 */\n                more--;\n            }\n        }\n\n        /* If the window is almost full and there is insufficient lookahead,\n         * move the upper half to the lower one to make room in the upper half.\n         */\n        if (s->strstart >= wsize + MAX_DIST(s)) {\n\n            zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);\n            s->match_start -= wsize;\n            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */\n            s->block_start -= (long) wsize;\n            if (s->insert > s->strstart)\n                s->insert = s->strstart;\n            slide_hash(s);\n            more += wsize;\n        }\n        if (s->strm->avail_in == 0) break;\n\n        /* If there was no sliding:\n         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n         *    more == window_size - lookahead - strstart\n         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n         * => more >= window_size - 2*WSIZE + 2\n         * In the BIG_MEM or MMAP case (not yet supported),\n         *   window_size == input_size + MIN_LOOKAHEAD  &&\n         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n         * Otherwise, window_size == 2*WSIZE so more >= 2.\n         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n         */\n        Assert(more >= 2, \"more < 2\");\n\n        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);\n        s->lookahead += n;\n\n        /* Initialize the hash value now that we have some input: */\n        if (s->lookahead + s->insert >= MIN_MATCH) {\n            uInt str = s->strstart - s->insert;\n            s->ins_h = s->window[str];\n            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);\n#if MIN_MATCH != 3\n            Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n            while (s->insert) {\n                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n                s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n                s->head[s->ins_h] = (Pos)str;\n                str++;\n                s->insert--;\n                if (s->lookahead + s->insert < MIN_MATCH)\n                    break;\n            }\n        }\n        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n         * but this is not important since only literal bytes will be emitted.\n         */\n\n    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);\n\n    /* If the WIN_INIT bytes after the end of the current data have never been\n     * written, then zero those bytes in order to avoid memory check reports of\n     * the use of uninitialized (or uninitialised as Julian writes) bytes by\n     * the longest match routines.  Update the high water mark for the next\n     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n     */\n    if (s->high_water < s->window_size) {\n        ulg curr = s->strstart + (ulg)(s->lookahead);\n        ulg init;\n\n        if (s->high_water < curr) {\n            /* Previous high water mark below current data -- zero WIN_INIT\n             * bytes or up to end of window, whichever is less.\n             */\n            init = s->window_size - curr;\n            if (init > WIN_INIT)\n                init = WIN_INIT;\n            zmemzero(s->window + curr, (unsigned)init);\n            s->high_water = curr + init;\n        }\n        else if (s->high_water < (ulg)curr + WIN_INIT) {\n            /* High water mark at or above current data, but below current data\n             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n             * to end of window, whichever is less.\n             */\n            init = (ulg)curr + WIN_INIT - s->high_water;\n            if (init > s->window_size - s->high_water)\n                init = s->window_size - s->high_water;\n            zmemzero(s->window + s->high_water, (unsigned)init);\n            s->high_water += init;\n        }\n    }\n\n    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n           \"not enough room for search\");\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit_(z_streamp strm, int level, const char *version,\n                         int stream_size) {\n    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,\n                         Z_DEFAULT_STRATEGY, version, stream_size);\n    /* To do: ignore strm->next_in if we use it as window */\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit2_(z_streamp strm, int level, int method,\n                          int windowBits, int memLevel, int strategy,\n                          const char *version, int stream_size) {\n    deflate_state *s;\n    int wrap = 1;\n    static const char my_version[] = ZLIB_VERSION;\n\n    if (version == Z_NULL || version[0] != my_version[0] ||\n        stream_size != sizeof(z_stream)) {\n        return Z_VERSION_ERROR;\n    }\n    if (strm == Z_NULL) return Z_STREAM_ERROR;\n\n    strm->msg = Z_NULL;\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zfree = zcfree;\n#endif\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n\n    if (windowBits < 0) { /* suppress zlib wrapper */\n        wrap = 0;\n        if (windowBits < -15)\n            return Z_STREAM_ERROR;\n        windowBits = -windowBits;\n    }\n#ifdef GZIP\n    else if (windowBits > 15) {\n        wrap = 2;       /* write gzip wrapper instead */\n        windowBits -= 16;\n    }\n#endif\n    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||\n        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n        strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {\n        return Z_STREAM_ERROR;\n    }\n    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */\n    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));\n    if (s == Z_NULL) return Z_MEM_ERROR;\n    strm->state = (struct internal_state FAR *)s;\n    s->strm = strm;\n    s->status = INIT_STATE;     /* to pass state test in deflateReset() */\n\n    s->wrap = wrap;\n    s->gzhead = Z_NULL;\n    s->w_bits = (uInt)windowBits;\n    s->w_size = 1 << s->w_bits;\n    s->w_mask = s->w_size - 1;\n\n    s->hash_bits = (uInt)memLevel + 7;\n    s->hash_size = 1 << s->hash_bits;\n    s->hash_mask = s->hash_size - 1;\n    s->hash_shift =  ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH);\n\n    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));\n    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));\n    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));\n\n    s->high_water = 0;      /* nothing written to s->window yet */\n\n    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n    /* We overlay pending_buf and sym_buf. This works since the average size\n     * for length/distance pairs over any compressed block is assured to be 31\n     * bits or less.\n     *\n     * Analysis: The longest fixed codes are a length code of 8 bits plus 5\n     * extra bits, for lengths 131 to 257. The longest fixed distance codes are\n     * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest\n     * possible fixed-codes length/distance pair is then 31 bits total.\n     *\n     * sym_buf starts one-fourth of the way into pending_buf. So there are\n     * three bytes in sym_buf for every four bytes in pending_buf. Each symbol\n     * in sym_buf is three bytes -- two for the distance and one for the\n     * literal/length. As each symbol is consumed, the pointer to the next\n     * sym_buf value to read moves forward three bytes. From that symbol, up to\n     * 31 bits are written to pending_buf. The closest the written pending_buf\n     * bits gets to the next sym_buf symbol to read is just before the last\n     * code is written. At that time, 31*(n - 2) bits have been written, just\n     * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at\n     * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1\n     * symbols are written.) The closest the writing gets to what is unread is\n     * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and\n     * can range from 128 to 32768.\n     *\n     * Therefore, at a minimum, there are 142 bits of space between what is\n     * written and what is read in the overlain buffers, so the symbols cannot\n     * be overwritten by the compressed data. That space is actually 139 bits,\n     * due to the three-bit fixed-code block header.\n     *\n     * That covers the case where either Z_FIXED is specified, forcing fixed\n     * codes, or when the use of fixed codes is chosen, because that choice\n     * results in a smaller compressed block than dynamic codes. That latter\n     * condition then assures that the above analysis also covers all dynamic\n     * blocks. A dynamic-code block will only be chosen to be emitted if it has\n     * fewer bits than a fixed-code block would for the same set of symbols.\n     * Therefore its average symbol length is assured to be less than 31. So\n     * the compressed data for a dynamic block also cannot overwrite the\n     * symbols from which it is being constructed.\n     */\n\n    s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS);\n    s->pending_buf_size = (ulg)s->lit_bufsize * 4;\n\n    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||\n        s->pending_buf == Z_NULL) {\n        s->status = FINISH_STATE;\n        strm->msg = ERR_MSG(Z_MEM_ERROR);\n        deflateEnd (strm);\n        return Z_MEM_ERROR;\n    }\n#ifdef LIT_MEM\n    s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1));\n    s->l_buf = s->pending_buf + (s->lit_bufsize << 2);\n    s->sym_end = s->lit_bufsize - 1;\n#else\n    s->sym_buf = s->pending_buf + s->lit_bufsize;\n    s->sym_end = (s->lit_bufsize - 1) * 3;\n#endif\n    /* We avoid equality with lit_bufsize*3 because of wraparound at 64K\n     * on 16 bit machines and because stored blocks are restricted to\n     * 64K-1 bytes.\n     */\n\n    s->level = level;\n    s->strategy = strategy;\n    s->method = (Byte)method;\n\n    return deflateReset(strm);\n}\n\n/* =========================================================================\n * Check for a valid deflate stream state. Return 0 if ok, 1 if not.\n */\nlocal int deflateStateCheck(z_streamp strm) {\n    deflate_state *s;\n    if (strm == Z_NULL ||\n        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)\n        return 1;\n    s = strm->state;\n    if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&\n#ifdef GZIP\n                                           s->status != GZIP_STATE &&\n#endif\n                                           s->status != EXTRA_STATE &&\n                                           s->status != NAME_STATE &&\n                                           s->status != COMMENT_STATE &&\n                                           s->status != HCRC_STATE &&\n                                           s->status != BUSY_STATE &&\n                                           s->status != FINISH_STATE))\n        return 1;\n    return 0;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary,\n                                 uInt  dictLength) {\n    deflate_state *s;\n    uInt str, n;\n    int wrap;\n    unsigned avail;\n    z_const unsigned char *next;\n\n    if (deflateStateCheck(strm) || dictionary == Z_NULL)\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    wrap = s->wrap;\n    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)\n        return Z_STREAM_ERROR;\n\n    /* when using zlib wrappers, compute Adler-32 for provided dictionary */\n    if (wrap == 1)\n        strm->adler = adler32(strm->adler, dictionary, dictLength);\n    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */\n\n    /* if dictionary would fill window, just replace the history */\n    if (dictLength >= s->w_size) {\n        if (wrap == 0) {            /* already empty otherwise */\n            CLEAR_HASH(s);\n            s->strstart = 0;\n            s->block_start = 0L;\n            s->insert = 0;\n        }\n        dictionary += dictLength - s->w_size;  /* use the tail */\n        dictLength = s->w_size;\n    }\n\n    /* insert dictionary into window and hash */\n    avail = strm->avail_in;\n    next = strm->next_in;\n    strm->avail_in = dictLength;\n    strm->next_in = (z_const Bytef *)dictionary;\n    fill_window(s);\n    while (s->lookahead >= MIN_MATCH) {\n        str = s->strstart;\n        n = s->lookahead - (MIN_MATCH-1);\n        do {\n            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n            s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n            s->head[s->ins_h] = (Pos)str;\n            str++;\n        } while (--n);\n        s->strstart = str;\n        s->lookahead = MIN_MATCH-1;\n        fill_window(s);\n    }\n    s->strstart += s->lookahead;\n    s->block_start = (long)s->strstart;\n    s->insert = s->lookahead;\n    s->lookahead = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    strm->next_in = next;\n    strm->avail_in = avail;\n    s->wrap = wrap;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary,\n                                 uInt *dictLength) {\n    deflate_state *s;\n    uInt len;\n\n    if (deflateStateCheck(strm))\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    len = s->strstart + s->lookahead;\n    if (len > s->w_size)\n        len = s->w_size;\n    if (dictionary != Z_NULL && len)\n        zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);\n    if (dictLength != Z_NULL)\n        *dictLength = len;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateResetKeep(z_streamp strm) {\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) {\n        return Z_STREAM_ERROR;\n    }\n\n    strm->total_in = strm->total_out = 0;\n    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */\n    strm->data_type = Z_UNKNOWN;\n\n    s = (deflate_state *)strm->state;\n    s->pending = 0;\n    s->pending_out = s->pending_buf;\n\n    if (s->wrap < 0) {\n        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */\n    }\n    s->status =\n#ifdef GZIP\n        s->wrap == 2 ? GZIP_STATE :\n#endif\n        INIT_STATE;\n    strm->adler =\n#ifdef GZIP\n        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :\n#endif\n        adler32(0L, Z_NULL, 0);\n    s->last_flush = -2;\n\n    _tr_init(s);\n\n    return Z_OK;\n}\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nlocal void lm_init(deflate_state *s) {\n    s->window_size = (ulg)2L*s->w_size;\n\n    CLEAR_HASH(s);\n\n    /* Set the default configuration parameters:\n     */\n    s->max_lazy_match   = configuration_table[s->level].max_lazy;\n    s->good_match       = configuration_table[s->level].good_length;\n    s->nice_match       = configuration_table[s->level].nice_length;\n    s->max_chain_length = configuration_table[s->level].max_chain;\n\n    s->strstart = 0;\n    s->block_start = 0L;\n    s->lookahead = 0;\n    s->insert = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    s->ins_h = 0;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateReset(z_streamp strm) {\n    int ret;\n\n    ret = deflateResetKeep(strm);\n    if (ret == Z_OK)\n        lm_init(strm->state);\n    return ret;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) {\n    if (deflateStateCheck(strm) || strm->state->wrap != 2)\n        return Z_STREAM_ERROR;\n    strm->state->gzhead = head;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) {\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    if (pending != Z_NULL)\n        *pending = strm->state->pending;\n    if (bits != Z_NULL)\n        *bits = strm->state->bi_valid;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {\n    deflate_state *s;\n    int put;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n#ifdef LIT_MEM\n    if (bits < 0 || bits > 16 ||\n        (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3))\n        return Z_BUF_ERROR;\n#else\n    if (bits < 0 || bits > 16 ||\n        s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))\n        return Z_BUF_ERROR;\n#endif\n    do {\n        put = Buf_size - s->bi_valid;\n        if (put > bits)\n            put = bits;\n        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);\n        s->bi_valid += put;\n        _tr_flush_bits(s);\n        value >>= put;\n        bits -= put;\n    } while (bits);\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateParams(z_streamp strm, int level, int strategy) {\n    deflate_state *s;\n    compress_func func;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {\n        return Z_STREAM_ERROR;\n    }\n    func = configuration_table[s->level].func;\n\n    if ((strategy != s->strategy || func != configuration_table[level].func) &&\n        s->last_flush != -2) {\n        /* Flush the last buffer: */\n        int err = deflate(strm, Z_BLOCK);\n        if (err == Z_STREAM_ERROR)\n            return err;\n        if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead)\n            return Z_BUF_ERROR;\n    }\n    if (s->level != level) {\n        if (s->level == 0 && s->matches != 0) {\n            if (s->matches == 1)\n                slide_hash(s);\n            else\n                CLEAR_HASH(s);\n            s->matches = 0;\n        }\n        s->level = level;\n        s->max_lazy_match   = configuration_table[level].max_lazy;\n        s->good_match       = configuration_table[level].good_length;\n        s->nice_match       = configuration_table[level].nice_length;\n        s->max_chain_length = configuration_table[level].max_chain;\n    }\n    s->strategy = strategy;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy,\n                        int nice_length, int max_chain) {\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n    s->good_match = (uInt)good_length;\n    s->max_lazy_match = (uInt)max_lazy;\n    s->nice_match = nice_length;\n    s->max_chain_length = (uInt)max_chain;\n    return Z_OK;\n}\n\n/* =========================================================================\n * For the default windowBits of 15 and memLevel of 8, this function returns a\n * close to exact, as well as small, upper bound on the compressed size. This\n * is an expansion of ~0.03%, plus a small constant.\n *\n * For any setting other than those defaults for windowBits and memLevel, one\n * of two worst case bounds is returned. This is at most an expansion of ~4% or\n * ~13%, plus a small constant.\n *\n * Both the 0.03% and 4% derive from the overhead of stored blocks. The first\n * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second\n * is for stored blocks of 127 bytes (the worst case memLevel == 1). The\n * expansion results from five bytes of header for each stored block.\n *\n * The larger expansion of 13% results from a window size less than or equal to\n * the symbols buffer size (windowBits <= memLevel + 7). In that case some of\n * the data being compressed may have slid out of the sliding window, impeding\n * a stored block from being emitted. Then the only choice is a fixed or\n * dynamic block, where a fixed block limits the maximum expansion to 9 bits\n * per 8-bit byte, plus 10 bits for every block. The smallest block size for\n * which this can occur is 255 (memLevel == 2).\n *\n * Shifts are used to approximate divisions, for speed.\n */\nuLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {\n    deflate_state *s;\n    uLong fixedlen, storelen, wraplen;\n\n    /* upper bound for fixed blocks with 9-bit literals and length 255\n       (memLevel == 2, which is the lowest that may not use stored blocks) --\n       ~13% overhead plus a small constant */\n    fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +\n               (sourceLen >> 9) + 4;\n\n    /* upper bound for stored blocks with length 127 (memLevel == 1) --\n       ~4% overhead plus a small constant */\n    storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +\n               (sourceLen >> 11) + 7;\n\n    /* if can't get parameters, return larger bound plus a zlib wrapper */\n    if (deflateStateCheck(strm))\n        return (fixedlen > storelen ? fixedlen : storelen) + 6;\n\n    /* compute wrapper length */\n    s = strm->state;\n    switch (s->wrap) {\n    case 0:                                 /* raw deflate */\n        wraplen = 0;\n        break;\n    case 1:                                 /* zlib wrapper */\n        wraplen = 6 + (s->strstart ? 4 : 0);\n        break;\n#ifdef GZIP\n    case 2:                                 /* gzip wrapper */\n        wraplen = 18;\n        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */\n            Bytef *str;\n            if (s->gzhead->extra != Z_NULL)\n                wraplen += 2 + s->gzhead->extra_len;\n            str = s->gzhead->name;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            str = s->gzhead->comment;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            if (s->gzhead->hcrc)\n                wraplen += 2;\n        }\n        break;\n#endif\n    default:                                /* for compiler happiness */\n        wraplen = 6;\n    }\n\n    /* if not default parameters, return one of the conservative bounds */\n    if (s->w_bits != 15 || s->hash_bits != 8 + 7)\n        return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +\n               wraplen;\n\n    /* default settings: return tight bound for that case -- ~0.03% overhead\n       plus a small constant */\n    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +\n           (sourceLen >> 25) + 13 - 6 + wraplen;\n}\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nlocal void putShortMSB(deflate_state *s, uInt b) {\n    put_byte(s, (Byte)(b >> 8));\n    put_byte(s, (Byte)(b & 0xff));\n}\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output, except for\n * some deflate_stored() output, goes through this function so some\n * applications may wish to modify it to avoid allocating a large\n * strm->next_out buffer and copying into it. (See also read_buf()).\n */\nlocal void flush_pending(z_streamp strm) {\n    unsigned len;\n    deflate_state *s = strm->state;\n\n    _tr_flush_bits(s);\n    len = s->pending;\n    if (len > strm->avail_out) len = strm->avail_out;\n    if (len == 0) return;\n\n    zmemcpy(strm->next_out, s->pending_out, len);\n    strm->next_out  += len;\n    s->pending_out  += len;\n    strm->total_out += len;\n    strm->avail_out -= len;\n    s->pending      -= len;\n    if (s->pending == 0) {\n        s->pending_out = s->pending_buf;\n    }\n}\n\n/* ===========================================================================\n * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].\n */\n#define HCRC_UPDATE(beg) \\\n    do { \\\n        if (s->gzhead->hcrc && s->pending > (beg)) \\\n            strm->adler = crc32(strm->adler, s->pending_buf + (beg), \\\n                                s->pending - (beg)); \\\n    } while (0)\n\n/* ========================================================================= */\nint ZEXPORT deflate(z_streamp strm, int flush) {\n    int old_flush; /* value of flush param for previous deflate call */\n    deflate_state *s;\n\n    if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {\n        return Z_STREAM_ERROR;\n    }\n    s = strm->state;\n\n    if (strm->next_out == Z_NULL ||\n        (strm->avail_in != 0 && strm->next_in == Z_NULL) ||\n        (s->status == FINISH_STATE && flush != Z_FINISH)) {\n        ERR_RETURN(strm, Z_STREAM_ERROR);\n    }\n    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);\n\n    old_flush = s->last_flush;\n    s->last_flush = flush;\n\n    /* Flush as much pending output as possible */\n    if (s->pending != 0) {\n        flush_pending(strm);\n        if (strm->avail_out == 0) {\n            /* Since avail_out is 0, deflate will be called again with\n             * more output space, but possibly with both pending and\n             * avail_in equal to zero. There won't be anything to do,\n             * but this is not an error situation so make sure we\n             * return OK instead of BUF_ERROR at next call of deflate:\n             */\n            s->last_flush = -1;\n            return Z_OK;\n        }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&\n               flush != Z_FINISH) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* User must not provide more input after the first FINISH: */\n    if (s->status == FINISH_STATE && strm->avail_in != 0) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* Write the header */\n    if (s->status == INIT_STATE && s->wrap == 0)\n        s->status = BUSY_STATE;\n    if (s->status == INIT_STATE) {\n        /* zlib header */\n        uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8;\n        uInt level_flags;\n\n        if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)\n            level_flags = 0;\n        else if (s->level < 6)\n            level_flags = 1;\n        else if (s->level == 6)\n            level_flags = 2;\n        else\n            level_flags = 3;\n        header |= (level_flags << 6);\n        if (s->strstart != 0) header |= PRESET_DICT;\n        header += 31 - (header % 31);\n\n        putShortMSB(s, header);\n\n        /* Save the adler32 of the preset dictionary: */\n        if (s->strstart != 0) {\n            putShortMSB(s, (uInt)(strm->adler >> 16));\n            putShortMSB(s, (uInt)(strm->adler & 0xffff));\n        }\n        strm->adler = adler32(0L, Z_NULL, 0);\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#ifdef GZIP\n    if (s->status == GZIP_STATE) {\n        /* gzip header */\n        strm->adler = crc32(0L, Z_NULL, 0);\n        put_byte(s, 31);\n        put_byte(s, 139);\n        put_byte(s, 8);\n        if (s->gzhead == Z_NULL) {\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, OS_CODE);\n            s->status = BUSY_STATE;\n\n            /* Compression must start with an empty pending buffer */\n            flush_pending(strm);\n            if (s->pending != 0) {\n                s->last_flush = -1;\n                return Z_OK;\n            }\n        }\n        else {\n            put_byte(s, (s->gzhead->text ? 1 : 0) +\n                     (s->gzhead->hcrc ? 2 : 0) +\n                     (s->gzhead->extra == Z_NULL ? 0 : 4) +\n                     (s->gzhead->name == Z_NULL ? 0 : 8) +\n                     (s->gzhead->comment == Z_NULL ? 0 : 16)\n                     );\n            put_byte(s, (Byte)(s->gzhead->time & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, s->gzhead->os & 0xff);\n            if (s->gzhead->extra != Z_NULL) {\n                put_byte(s, s->gzhead->extra_len & 0xff);\n                put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);\n            }\n            if (s->gzhead->hcrc)\n                strm->adler = crc32(strm->adler, s->pending_buf,\n                                    s->pending);\n            s->gzindex = 0;\n            s->status = EXTRA_STATE;\n        }\n    }\n    if (s->status == EXTRA_STATE) {\n        if (s->gzhead->extra != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;\n            while (s->pending + left > s->pending_buf_size) {\n                uInt copy = s->pending_buf_size - s->pending;\n                zmemcpy(s->pending_buf + s->pending,\n                        s->gzhead->extra + s->gzindex, copy);\n                s->pending = s->pending_buf_size;\n                HCRC_UPDATE(beg);\n                s->gzindex += copy;\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n                beg = 0;\n                left -= copy;\n            }\n            zmemcpy(s->pending_buf + s->pending,\n                    s->gzhead->extra + s->gzindex, left);\n            s->pending += left;\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = NAME_STATE;\n    }\n    if (s->status == NAME_STATE) {\n        if (s->gzhead->name != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->name[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = COMMENT_STATE;\n    }\n    if (s->status == COMMENT_STATE) {\n        if (s->gzhead->comment != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->comment[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n        }\n        s->status = HCRC_STATE;\n    }\n    if (s->status == HCRC_STATE) {\n        if (s->gzhead->hcrc) {\n            if (s->pending + 2 > s->pending_buf_size) {\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n            }\n            put_byte(s, (Byte)(strm->adler & 0xff));\n            put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n            strm->adler = crc32(0L, Z_NULL, 0);\n        }\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#endif\n\n    /* Start a new block or continue the current one.\n     */\n    if (strm->avail_in != 0 || s->lookahead != 0 ||\n        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {\n        block_state bstate;\n\n        bstate = s->level == 0 ? deflate_stored(s, flush) :\n                 s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :\n                 s->strategy == Z_RLE ? deflate_rle(s, flush) :\n                 (*(configuration_table[s->level].func))(s, flush);\n\n        if (bstate == finish_started || bstate == finish_done) {\n            s->status = FINISH_STATE;\n        }\n        if (bstate == need_more || bstate == finish_started) {\n            if (strm->avail_out == 0) {\n                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */\n            }\n            return Z_OK;\n            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n             * of deflate should use the same flush parameter to make sure\n             * that the flush is complete. So we don't have to output an\n             * empty block here, this will be done at next call. This also\n             * ensures that for a very small output buffer, we emit at most\n             * one empty block.\n             */\n        }\n        if (bstate == block_done) {\n            if (flush == Z_PARTIAL_FLUSH) {\n                _tr_align(s);\n            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n                _tr_stored_block(s, (char*)0, 0L, 0);\n                /* For a full flush, this empty block will be recognized\n                 * as a special marker by inflate_sync().\n                 */\n                if (flush == Z_FULL_FLUSH) {\n                    CLEAR_HASH(s);             /* forget history */\n                    if (s->lookahead == 0) {\n                        s->strstart = 0;\n                        s->block_start = 0L;\n                        s->insert = 0;\n                    }\n                }\n            }\n            flush_pending(strm);\n            if (strm->avail_out == 0) {\n              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n              return Z_OK;\n            }\n        }\n    }\n\n    if (flush != Z_FINISH) return Z_OK;\n    if (s->wrap <= 0) return Z_STREAM_END;\n\n    /* Write the trailer */\n#ifdef GZIP\n    if (s->wrap == 2) {\n        put_byte(s, (Byte)(strm->adler & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));\n        put_byte(s, (Byte)(strm->total_in & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));\n    }\n    else\n#endif\n    {\n        putShortMSB(s, (uInt)(strm->adler >> 16));\n        putShortMSB(s, (uInt)(strm->adler & 0xffff));\n    }\n    flush_pending(strm);\n    /* If avail_out is zero, the application will call deflate again\n     * to flush the rest.\n     */\n    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */\n    return s->pending != 0 ? Z_OK : Z_STREAM_END;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateEnd(z_streamp strm) {\n    int status;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n\n    status = strm->state->status;\n\n    /* Deallocate in reverse order of allocations: */\n    TRY_FREE(strm, strm->state->pending_buf);\n    TRY_FREE(strm, strm->state->head);\n    TRY_FREE(strm, strm->state->prev);\n    TRY_FREE(strm, strm->state->window);\n\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n\n    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;\n}\n\n/* =========================================================================\n * Copy the source state to the destination state.\n * To simplify the source, this is not supported for 16-bit MSDOS (which\n * doesn't have enough memory anyway to duplicate compression states).\n */\nint ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {\n#ifdef MAXSEG_64K\n    (void)dest;\n    (void)source;\n    return Z_STREAM_ERROR;\n#else\n    deflate_state *ds;\n    deflate_state *ss;\n\n\n    if (deflateStateCheck(source) || dest == Z_NULL) {\n        return Z_STREAM_ERROR;\n    }\n\n    ss = source->state;\n\n    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));\n\n    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));\n    if (ds == Z_NULL) return Z_MEM_ERROR;\n    dest->state = (struct internal_state FAR *) ds;\n    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));\n    ds->strm = dest;\n\n    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));\n    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));\n    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));\n    ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS);\n\n    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||\n        ds->pending_buf == Z_NULL) {\n        deflateEnd (dest);\n        return Z_MEM_ERROR;\n    }\n    /* following zmemcpy do not work for 16-bit MSDOS */\n    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));\n    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));\n    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));\n    zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS);\n\n    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);\n#ifdef LIT_MEM\n    ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1));\n    ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2);\n#else\n    ds->sym_buf = ds->pending_buf + ds->lit_bufsize;\n#endif\n\n    ds->l_desc.dyn_tree = ds->dyn_ltree;\n    ds->d_desc.dyn_tree = ds->dyn_dtree;\n    ds->bl_desc.dyn_tree = ds->bl_tree;\n\n    return Z_OK;\n#endif /* MAXSEG_64K */\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\nlocal uInt longest_match(deflate_state *s, IPos cur_match) {\n    unsigned chain_length = s->max_chain_length;/* max hash chain length */\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                      /* matched string */\n    register int len;                           /* length of current match */\n    int best_len = (int)s->prev_length;         /* best match length so far */\n    int nice_match = s->nice_match;             /* stop if match long enough */\n    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?\n        s->strstart - (IPos)MAX_DIST(s) : NIL;\n    /* Stop when cur_match becomes <= limit. To simplify the code,\n     * we prevent matches with the string of window index 0.\n     */\n    Posf *prev = s->prev;\n    uInt wmask = s->w_mask;\n\n#ifdef UNALIGNED_OK\n    /* Compare two bytes at a time. Note: this is not always beneficial.\n     * Try with and without -DUNALIGNED_OK to check.\n     */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;\n    register ush scan_start = *(ushf*)scan;\n    register ush scan_end   = *(ushf*)(scan + best_len - 1);\n#else\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n    register Byte scan_end1  = scan[best_len - 1];\n    register Byte scan_end   = scan[best_len];\n#endif\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    /* Do not waste too much time if we already have a good match: */\n    if (s->prev_length >= s->good_match) {\n        chain_length >>= 2;\n    }\n    /* Do not look for matches beyond the end of the input. This is necessary\n     * to make deflate deterministic.\n     */\n    if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;\n\n    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n           \"need lookahead\");\n\n    do {\n        Assert(cur_match < s->strstart, \"no future\");\n        match = s->window + cur_match;\n\n        /* Skip to next match if the match length cannot increase\n         * or if the match length is less than 2.  Note that the checks below\n         * for insufficient lookahead only occur occasionally for performance\n         * reasons.  Therefore uninitialized memory will be accessed, and\n         * conditional jumps will be made that depend on those values.\n         * However the length of the match is limited to the lookahead, so\n         * the output of deflate is not affected by the uninitialized values.\n         */\n#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)\n        /* This code assumes sizeof(unsigned short) == 2. Do not use\n         * UNALIGNED_OK if your compiler uses a different size.\n         */\n        if (*(ushf*)(match + best_len - 1) != scan_end ||\n            *(ushf*)match != scan_start) continue;\n\n        /* It is not necessary to compare scan[2] and match[2] since they are\n         * always equal when the other bytes match, given that the hash keys\n         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at\n         * strstart + 3, + 5, up to strstart + 257. We check for insufficient\n         * lookahead only every 4th comparison; the 128th check will be made\n         * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is\n         * necessary to put more guard bytes at the end of the window, or\n         * to check more often for insufficient lookahead.\n         */\n        Assert(scan[2] == match[2], \"scan[2]?\");\n        scan++, match++;\n        do {\n        } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&\n                 *(ushf*)(scan += 2) == *(ushf*)(match += 2) &&\n                 *(ushf*)(scan += 2) == *(ushf*)(match += 2) &&\n                 *(ushf*)(scan += 2) == *(ushf*)(match += 2) &&\n                 scan < strend);\n        /* The funny \"do {}\" generates better code on most compilers */\n\n        /* Here, scan <= window + strstart + 257 */\n        Assert(scan <= s->window + (unsigned)(s->window_size - 1),\n               \"wild scan\");\n        if (*scan == *match) scan++;\n\n        len = (MAX_MATCH - 1) - (int)(strend - scan);\n        scan = strend - (MAX_MATCH-1);\n\n#else /* UNALIGNED_OK */\n\n        if (match[best_len]     != scan_end  ||\n            match[best_len - 1] != scan_end1 ||\n            *match              != *scan     ||\n            *++match            != scan[1])      continue;\n\n        /* The check at best_len - 1 can be removed because it will be made\n         * again later. (This heuristic is not always a win.)\n         * It is not necessary to compare scan[2] and match[2] since they\n         * are always equal when the other bytes match, given that\n         * the hash keys are equal and that HASH_BITS >= 8.\n         */\n        scan += 2, match++;\n        Assert(*scan == *match, \"match[2]?\");\n\n        /* We check for insufficient lookahead only every 8th comparison;\n         * the 256th check will be made at strstart + 258.\n         */\n        do {\n        } while (*++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 scan < strend);\n\n        Assert(scan <= s->window + (unsigned)(s->window_size - 1),\n               \"wild scan\");\n\n        len = MAX_MATCH - (int)(strend - scan);\n        scan = strend - MAX_MATCH;\n\n#endif /* UNALIGNED_OK */\n\n        if (len > best_len) {\n            s->match_start = cur_match;\n            best_len = len;\n            if (len >= nice_match) break;\n#ifdef UNALIGNED_OK\n            scan_end = *(ushf*)(scan + best_len - 1);\n#else\n            scan_end1  = scan[best_len - 1];\n            scan_end   = scan[best_len];\n#endif\n        }\n    } while ((cur_match = prev[cur_match & wmask]) > limit\n             && --chain_length != 0);\n\n    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;\n    return s->lookahead;\n}\n\n#else /* FASTEST */\n\n/* ---------------------------------------------------------------------------\n * Optimized version for FASTEST only\n */\nlocal uInt longest_match(deflate_state *s, IPos cur_match) {\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                       /* matched string */\n    register int len;                           /* length of current match */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n           \"need lookahead\");\n\n    Assert(cur_match < s->strstart, \"no future\");\n\n    match = s->window + cur_match;\n\n    /* Return failure if the match length is less than 2:\n     */\n    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;\n\n    /* The check at best_len - 1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2, match += 2;\n    Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart + 258.\n     */\n    do {\n    } while (*++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             scan < strend);\n\n    Assert(scan <= s->window + (unsigned)(s->window_size - 1), \"wild scan\");\n\n    len = MAX_MATCH - (int)(strend - scan);\n\n    if (len < MIN_MATCH) return MIN_MATCH - 1;\n\n    s->match_start = cur_match;\n    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;\n}\n\n#endif /* FASTEST */\n\n#ifdef ZLIB_DEBUG\n\n#define EQUAL 0\n/* result of memcmp for equal strings */\n\n/* ===========================================================================\n * Check that the match at match_start is indeed a match.\n */\nlocal void check_match(deflate_state *s, IPos start, IPos match, int length) {\n    /* check that the match is indeed a match */\n    Bytef *back = s->window + (int)match, *here = s->window + start;\n    IPos len = length;\n    if (match == (IPos)-1) {\n        /* match starts one byte before the current window -- just compare the\n           subsequent length-1 bytes */\n        back++;\n        here++;\n        len--;\n    }\n    if (zmemcmp(back, here, len) != EQUAL) {\n        fprintf(stderr, \" start %u, match %d, length %d\\n\",\n                start, (int)match, length);\n        do {\n            fprintf(stderr, \"(%02x %02x)\", *back++, *here++);\n        } while (--len != 0);\n        z_error(\"invalid match\");\n    }\n    if (z_verbose > 1) {\n        fprintf(stderr,\"\\\\[%d,%d]\", start - match, length);\n        do { putc(s->window[start++], stderr); } while (--length != 0);\n    }\n}\n#else\n#  define check_match(s, start, match, length)\n#endif /* ZLIB_DEBUG */\n\n/* ===========================================================================\n * Flush the current block, with given end-of-file flag.\n * IN assertion: strstart is set to the end of the current match.\n */\n#define FLUSH_BLOCK_ONLY(s, last) { \\\n   _tr_flush_block(s, (s->block_start >= 0L ? \\\n                   (charf *)&s->window[(unsigned)s->block_start] : \\\n                   (charf *)Z_NULL), \\\n                (ulg)((long)s->strstart - s->block_start), \\\n                (last)); \\\n   s->block_start = s->strstart; \\\n   flush_pending(s->strm); \\\n   Tracev((stderr,\"[FLUSH]\")); \\\n}\n\n/* Same but force premature exit if necessary. */\n#define FLUSH_BLOCK(s, last) { \\\n   FLUSH_BLOCK_ONLY(s, last); \\\n   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \\\n}\n\n/* Maximum stored block length in deflate format (not including header). */\n#define MAX_STORED 65535\n\n/* Minimum of a and b. */\n#define MIN(a, b) ((a) > (b) ? (b) : (a))\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n *\n * In case deflateParams() is used to later switch to a non-zero compression\n * level, s->matches (otherwise unused when storing) keeps track of the number\n * of hash table slides to perform. If s->matches is 1, then one hash table\n * slide will be done when switching. If s->matches is 2, the maximum value\n * allowed here, then the hash table will be cleared, since two or more slides\n * is the same as a clear.\n *\n * deflate_stored() is written to minimize the number of times an input byte is\n * copied. It is most efficient with large input and output buffers, which\n * maximizes the opportunities to have a single copy from next_in to next_out.\n */\nlocal block_state deflate_stored(deflate_state *s, int flush) {\n    /* Smallest worthy block size when not flushing or finishing. By default\n     * this is 32K. This can be as small as 507 bytes for memLevel == 1. For\n     * large input and output buffers, the stored block size will be larger.\n     */\n    unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);\n\n    /* Copy as many min_block or larger stored blocks directly to next_out as\n     * possible. If flushing, copy the remaining available input to next_out as\n     * stored blocks, if there is enough space.\n     */\n    unsigned len, left, have, last = 0;\n    unsigned used = s->strm->avail_in;\n    do {\n        /* Set len to the maximum size block that we can copy directly with the\n         * available input data and output space. Set left to how much of that\n         * would be copied from what's left in the window.\n         */\n        len = MAX_STORED;       /* maximum deflate stored block length */\n        have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        if (s->strm->avail_out < have)          /* need room for header */\n            break;\n            /* maximum stored block length that will fit in avail_out: */\n        have = s->strm->avail_out - have;\n        left = s->strstart - s->block_start;    /* bytes left in window */\n        if (len > (ulg)left + s->strm->avail_in)\n            len = left + s->strm->avail_in;     /* limit len to the input */\n        if (len > have)\n            len = have;                         /* limit len to the output */\n\n        /* If the stored block would be less than min_block in length, or if\n         * unable to copy all of the available input when flushing, then try\n         * copying to the window and the pending buffer instead. Also don't\n         * write an empty block when flushing -- deflate() does that.\n         */\n        if (len < min_block && ((len == 0 && flush != Z_FINISH) ||\n                                flush == Z_NO_FLUSH ||\n                                len != left + s->strm->avail_in))\n            break;\n\n        /* Make a dummy stored block in pending to get the header bytes,\n         * including any pending bits. This also updates the debugging counts.\n         */\n        last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;\n        _tr_stored_block(s, (char *)0, 0L, last);\n\n        /* Replace the lengths in the dummy stored block with len. */\n        s->pending_buf[s->pending - 4] = len;\n        s->pending_buf[s->pending - 3] = len >> 8;\n        s->pending_buf[s->pending - 2] = ~len;\n        s->pending_buf[s->pending - 1] = ~len >> 8;\n\n        /* Write the stored block header bytes. */\n        flush_pending(s->strm);\n\n#ifdef ZLIB_DEBUG\n        /* Update debugging counts for the data about to be copied. */\n        s->compressed_len += len << 3;\n        s->bits_sent += len << 3;\n#endif\n\n        /* Copy uncompressed bytes from the window to next_out. */\n        if (left) {\n            if (left > len)\n                left = len;\n            zmemcpy(s->strm->next_out, s->window + s->block_start, left);\n            s->strm->next_out += left;\n            s->strm->avail_out -= left;\n            s->strm->total_out += left;\n            s->block_start += left;\n            len -= left;\n        }\n\n        /* Copy uncompressed bytes directly from next_in to next_out, updating\n         * the check value.\n         */\n        if (len) {\n            read_buf(s->strm, s->strm->next_out, len);\n            s->strm->next_out += len;\n            s->strm->avail_out -= len;\n            s->strm->total_out += len;\n        }\n    } while (last == 0);\n\n    /* Update the sliding window with the last s->w_size bytes of the copied\n     * data, or append all of the copied data to the existing window if less\n     * than s->w_size bytes were copied. Also update the number of bytes to\n     * insert in the hash tables, in the event that deflateParams() switches to\n     * a non-zero compression level.\n     */\n    used -= s->strm->avail_in;      /* number of input bytes directly copied */\n    if (used) {\n        /* If any input was used, then no unused input remains in the window,\n         * therefore s->block_start == s->strstart.\n         */\n        if (used >= s->w_size) {    /* supplant the previous history */\n            s->matches = 2;         /* clear hash */\n            zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);\n            s->strstart = s->w_size;\n            s->insert = s->strstart;\n        }\n        else {\n            if (s->window_size - s->strstart <= used) {\n                /* Slide the window down. */\n                s->strstart -= s->w_size;\n                zmemcpy(s->window, s->window + s->w_size, s->strstart);\n                if (s->matches < 2)\n                    s->matches++;   /* add a pending slide_hash() */\n                if (s->insert > s->strstart)\n                    s->insert = s->strstart;\n            }\n            zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);\n            s->strstart += used;\n            s->insert += MIN(used, s->w_size - s->insert);\n        }\n        s->block_start = s->strstart;\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* If the last block was written to next_out, then done. */\n    if (last)\n        return finish_done;\n\n    /* If flushing and all input has been consumed, then done. */\n    if (flush != Z_NO_FLUSH && flush != Z_FINISH &&\n        s->strm->avail_in == 0 && (long)s->strstart == s->block_start)\n        return block_done;\n\n    /* Fill the window with any remaining input. */\n    have = s->window_size - s->strstart;\n    if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {\n        /* Slide the window down. */\n        s->block_start -= s->w_size;\n        s->strstart -= s->w_size;\n        zmemcpy(s->window, s->window + s->w_size, s->strstart);\n        if (s->matches < 2)\n            s->matches++;           /* add a pending slide_hash() */\n        have += s->w_size;          /* more space now */\n        if (s->insert > s->strstart)\n            s->insert = s->strstart;\n    }\n    if (have > s->strm->avail_in)\n        have = s->strm->avail_in;\n    if (have) {\n        read_buf(s->strm, s->window + s->strstart, have);\n        s->strstart += have;\n        s->insert += MIN(have, s->w_size - s->insert);\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* There was not enough avail_out to write a complete worthy or flushed\n     * stored block to next_out. Write a stored block to pending instead, if we\n     * have enough input for a worthy block, or if flushing and there is enough\n     * room for the remaining input as a stored block in the pending buffer.\n     */\n    have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        /* maximum stored block length that will fit in pending: */\n    have = MIN(s->pending_buf_size - have, MAX_STORED);\n    min_block = MIN(have, s->w_size);\n    left = s->strstart - s->block_start;\n    if (left >= min_block ||\n        ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&\n         s->strm->avail_in == 0 && left <= have)) {\n        len = MIN(left, have);\n        last = flush == Z_FINISH && s->strm->avail_in == 0 &&\n               len == left ? 1 : 0;\n        _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);\n        s->block_start += len;\n        flush_pending(s->strm);\n    }\n\n    /* We've done all we can with the available input and output. */\n    return last ? finish_started : need_more;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nlocal block_state deflate_fast(deflate_state *s, int flush) {\n    IPos hash_head;       /* head of the hash chain */\n    int bflush;           /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart + 2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         * At this point we have always match_length < MIN_MATCH\n         */\n        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n        }\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->match_start, s->match_length);\n\n            _tr_tally_dist(s, s->strstart - s->match_start,\n                           s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n\n            /* Insert new strings in the hash table only if the match length\n             * is not too large. This saves time but degrades compression.\n             */\n#ifndef FASTEST\n            if (s->match_length <= s->max_insert_length &&\n                s->lookahead >= MIN_MATCH) {\n                s->match_length--; /* string at strstart already in table */\n                do {\n                    s->strstart++;\n                    INSERT_STRING(s, s->strstart, hash_head);\n                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n                     * always MIN_MATCH bytes ahead.\n                     */\n                } while (--s->match_length != 0);\n                s->strstart++;\n            } else\n#endif\n            {\n                s->strstart += s->match_length;\n                s->match_length = 0;\n                s->ins_h = s->window[s->strstart];\n                UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);\n#if MIN_MATCH != 3\n                Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n                 * matter since it will be recomputed at next deflate call.\n                 */\n            }\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit(s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->sym_next)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nlocal block_state deflate_slow(deflate_state *s, int flush) {\n    IPos hash_head;          /* head of hash chain */\n    int bflush;              /* set if current block must be flushed */\n\n    /* Process the input block. */\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart + 2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         */\n        s->prev_length = s->match_length, s->prev_match = s->match_start;\n        s->match_length = MIN_MATCH-1;\n\n        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&\n            s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n\n            if (s->match_length <= 5 && (s->strategy == Z_FILTERED\n#if TOO_FAR <= 32767\n                || (s->match_length == MIN_MATCH &&\n                    s->strstart - s->match_start > TOO_FAR)\n#endif\n                )) {\n\n                /* If prev_match is also MIN_MATCH, match_start is garbage\n                 * but we will ignore the current match anyway.\n                 */\n                s->match_length = MIN_MATCH-1;\n            }\n        }\n        /* If there was a match at the previous step and the current\n         * match is not better, output the previous match:\n         */\n        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {\n            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;\n            /* Do not insert strings in hash table beyond this. */\n\n            check_match(s, s->strstart - 1, s->prev_match, s->prev_length);\n\n            _tr_tally_dist(s, s->strstart - 1 - s->prev_match,\n                           s->prev_length - MIN_MATCH, bflush);\n\n            /* Insert in hash table all strings up to the end of the match.\n             * strstart - 1 and strstart are already inserted. If there is not\n             * enough lookahead, the last two strings are not inserted in\n             * the hash table.\n             */\n            s->lookahead -= s->prev_length - 1;\n            s->prev_length -= 2;\n            do {\n                if (++s->strstart <= max_insert) {\n                    INSERT_STRING(s, s->strstart, hash_head);\n                }\n            } while (--s->prev_length != 0);\n            s->match_available = 0;\n            s->match_length = MIN_MATCH-1;\n            s->strstart++;\n\n            if (bflush) FLUSH_BLOCK(s, 0);\n\n        } else if (s->match_available) {\n            /* If there was no match at the previous position, output a\n             * single literal. If there was a match but the current match\n             * is longer, truncate the previous match to a single literal.\n             */\n            Tracevv((stderr,\"%c\", s->window[s->strstart - 1]));\n            _tr_tally_lit(s, s->window[s->strstart - 1], bflush);\n            if (bflush) {\n                FLUSH_BLOCK_ONLY(s, 0);\n            }\n            s->strstart++;\n            s->lookahead--;\n            if (s->strm->avail_out == 0) return need_more;\n        } else {\n            /* There is no previous match to compare with, wait for\n             * the next step to decide.\n             */\n            s->match_available = 1;\n            s->strstart++;\n            s->lookahead--;\n        }\n    }\n    Assert (flush != Z_NO_FLUSH, \"no flush?\");\n    if (s->match_available) {\n        Tracevv((stderr,\"%c\", s->window[s->strstart - 1]));\n        _tr_tally_lit(s, s->window[s->strstart - 1], bflush);\n        s->match_available = 0;\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->sym_next)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n#endif /* FASTEST */\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nlocal block_state deflate_rle(deflate_state *s, int flush) {\n    int bflush;             /* set if current block must be flushed */\n    uInt prev;              /* byte at distance one to match */\n    Bytef *scan, *strend;   /* scan goes up to strend for length of run */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the longest run, plus one for the unrolled loop.\n         */\n        if (s->lookahead <= MAX_MATCH) {\n            fill_window(s);\n            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* See how many times the previous byte repeats */\n        s->match_length = 0;\n        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {\n            scan = s->window + s->strstart - 1;\n            prev = *scan;\n            if (prev == *++scan && prev == *++scan && prev == *++scan) {\n                strend = s->window + s->strstart + MAX_MATCH;\n                do {\n                } while (prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         scan < strend);\n                s->match_length = MAX_MATCH - (uInt)(strend - scan);\n                if (s->match_length > s->lookahead)\n                    s->match_length = s->lookahead;\n            }\n            Assert(scan <= s->window + (uInt)(s->window_size - 1),\n                   \"wild scan\");\n        }\n\n        /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->strstart - 1, s->match_length);\n\n            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n            s->strstart += s->match_length;\n            s->match_length = 0;\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit(s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->sym_next)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nlocal block_state deflate_huff(deflate_state *s, int flush) {\n    int bflush;             /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we have a literal to write. */\n        if (s->lookahead == 0) {\n            fill_window(s);\n            if (s->lookahead == 0) {\n                if (flush == Z_NO_FLUSH)\n                    return need_more;\n                break;      /* flush the current block */\n            }\n        }\n\n        /* Output a literal byte */\n        s->match_length = 0;\n        Tracevv((stderr,\"%c\", s->window[s->strstart]));\n        _tr_tally_lit(s, s->window[s->strstart], bflush);\n        s->lookahead--;\n        s->strstart++;\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->sym_next)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n"
  },
  {
    "path": "eidos_zlib/deflate.h",
    "content": "/* deflate.h -- internal compression state\n * Copyright (C) 1995-2024 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef DEFLATE_H\n#define DEFLATE_H\n\n#include \"zutil.h\"\n\n/* define NO_GZIP when compiling if you want to disable gzip header and\n   trailer creation by deflate().  NO_GZIP would be used to avoid linking in\n   the crc code when it is not needed.  For shared libraries, gzip encoding\n   should be left enabled. */\n#ifndef NO_GZIP\n#  define GZIP\n#endif\n\n/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at\n   the cost of a larger memory footprint */\n/* #define LIT_MEM */\n\n/* ===========================================================================\n * Internal compression state.\n */\n\n#define LENGTH_CODES 29\n/* number of length codes, not counting the special END_BLOCK code */\n\n#define LITERALS  256\n/* number of literal bytes 0..255 */\n\n#define L_CODES (LITERALS+1+LENGTH_CODES)\n/* number of Literal or Length codes, including the END_BLOCK code */\n\n#define D_CODES   30\n/* number of distance codes */\n\n#define BL_CODES  19\n/* number of codes used to transfer the bit lengths */\n\n#define HEAP_SIZE (2*L_CODES+1)\n/* maximum heap size */\n\n#define MAX_BITS 15\n/* All codes must not exceed MAX_BITS bits */\n\n#define Buf_size 16\n/* size of bit buffer in bi_buf */\n\n#define INIT_STATE    42    /* zlib header -> BUSY_STATE */\n#ifdef GZIP\n#  define GZIP_STATE  57    /* gzip header -> BUSY_STATE | EXTRA_STATE */\n#endif\n#define EXTRA_STATE   69    /* gzip extra block -> NAME_STATE */\n#define NAME_STATE    73    /* gzip file name -> COMMENT_STATE */\n#define COMMENT_STATE 91    /* gzip comment -> HCRC_STATE */\n#define HCRC_STATE   103    /* gzip header CRC -> BUSY_STATE */\n#define BUSY_STATE   113    /* deflate -> FINISH_STATE */\n#define FINISH_STATE 666    /* stream complete */\n/* Stream status */\n\n\n/* Data structure describing a single value and its code string. */\ntypedef struct ct_data_s {\n    union {\n        ush  freq;       /* frequency count */\n        ush  code;       /* bit string */\n    } fc;\n    union {\n        ush  dad;        /* father node in Huffman tree */\n        ush  len;        /* length of bit string */\n    } dl;\n} FAR ct_data;\n\n#define Freq fc.freq\n#define Code fc.code\n#define Dad  dl.dad\n#define Len  dl.len\n\ntypedef struct static_tree_desc_s  static_tree_desc;\n\ntypedef struct tree_desc_s {\n    ct_data *dyn_tree;           /* the dynamic tree */\n    int     max_code;            /* largest code with non zero frequency */\n    const static_tree_desc *stat_desc;  /* the corresponding static tree */\n} FAR tree_desc;\n\ntypedef ush Pos;\ntypedef Pos FAR Posf;\ntypedef unsigned IPos;\n\n/* A Pos is an index in the character window. We use short instead of int to\n * save space in the various tables. IPos is used only for parameter passing.\n */\n\ntypedef struct internal_state {\n    z_streamp strm;      /* pointer back to this zlib stream */\n    int   status;        /* as the name implies */\n    Bytef *pending_buf;  /* output still pending */\n    ulg   pending_buf_size; /* size of pending_buf */\n    Bytef *pending_out;  /* next pending byte to output to the stream */\n    ulg   pending;       /* nb of bytes in the pending buffer */\n    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */\n    gz_headerp  gzhead;  /* gzip header information to write */\n    ulg   gzindex;       /* where in extra, name, or comment */\n    Byte  method;        /* can only be DEFLATED */\n    int   last_flush;    /* value of flush param for previous deflate call */\n\n                /* used by deflate.c: */\n\n    uInt  w_size;        /* LZ77 window size (32K by default) */\n    uInt  w_bits;        /* log2(w_size)  (8..16) */\n    uInt  w_mask;        /* w_size - 1 */\n\n    Bytef *window;\n    /* Sliding window. Input bytes are read into the second half of the window,\n     * and move to the first half later to keep a dictionary of at least wSize\n     * bytes. With this organization, matches are limited to a distance of\n     * wSize-MAX_MATCH bytes, but this ensures that IO is always\n     * performed with a length multiple of the block size. Also, it limits\n     * the window size to 64K, which is quite useful on MSDOS.\n     * To do: use the user input buffer as sliding window.\n     */\n\n    ulg window_size;\n    /* Actual size of window: 2*wSize, except when the user input buffer\n     * is directly used as sliding window.\n     */\n\n    Posf *prev;\n    /* Link to older string with same hash index. To limit the size of this\n     * array to 64K, this link is maintained only for the last 32K strings.\n     * An index in this array is thus a window index modulo 32K.\n     */\n\n    Posf *head; /* Heads of the hash chains or NIL. */\n\n    uInt  ins_h;          /* hash index of string to be inserted */\n    uInt  hash_size;      /* number of elements in hash table */\n    uInt  hash_bits;      /* log2(hash_size) */\n    uInt  hash_mask;      /* hash_size-1 */\n\n    uInt  hash_shift;\n    /* Number of bits by which ins_h must be shifted at each input\n     * step. It must be such that after MIN_MATCH steps, the oldest\n     * byte no longer takes part in the hash key, that is:\n     *   hash_shift * MIN_MATCH >= hash_bits\n     */\n\n    long block_start;\n    /* Window position at the beginning of the current output block. Gets\n     * negative when the window is moved backwards.\n     */\n\n    uInt match_length;           /* length of best match */\n    IPos prev_match;             /* previous match */\n    int match_available;         /* set if previous match exists */\n    uInt strstart;               /* start of string to insert */\n    uInt match_start;            /* start of matching string */\n    uInt lookahead;              /* number of valid bytes ahead in window */\n\n    uInt prev_length;\n    /* Length of the best match at previous step. Matches not greater than this\n     * are discarded. This is used in the lazy match evaluation.\n     */\n\n    uInt max_chain_length;\n    /* To speed up deflation, hash chains are never searched beyond this\n     * length.  A higher limit improves compression ratio but degrades the\n     * speed.\n     */\n\n    uInt max_lazy_match;\n    /* Attempt to find a better match only when the current match is strictly\n     * smaller than this value. This mechanism is used only for compression\n     * levels >= 4.\n     */\n#   define max_insert_length  max_lazy_match\n    /* Insert new strings in the hash table only if the match length is not\n     * greater than this length. This saves time but degrades compression.\n     * max_insert_length is used only for compression levels <= 3.\n     */\n\n    int level;    /* compression level (1..9) */\n    int strategy; /* favor or force Huffman coding*/\n\n    uInt good_match;\n    /* Use a faster search when the previous match is longer than this */\n\n    int nice_match; /* Stop searching when current match exceeds this */\n\n                /* used by trees.c: */\n    /* Didn't use ct_data typedef below to suppress compiler warning */\n    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n    struct tree_desc_s l_desc;               /* desc. for literal tree */\n    struct tree_desc_s d_desc;               /* desc. for distance tree */\n    struct tree_desc_s bl_desc;              /* desc. for bit length tree */\n\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n    int heap_len;               /* number of elements in the heap */\n    int heap_max;               /* element of largest frequency */\n    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n     * The same heap array is used to build all trees.\n     */\n\n    uch depth[2*L_CODES+1];\n    /* Depth of each subtree used as tie breaker for trees of equal frequency\n     */\n\n#ifdef LIT_MEM\n#   define LIT_BUFS 5\n    ushf *d_buf;          /* buffer for distances */\n    uchf *l_buf;          /* buffer for literals/lengths */\n#else\n#   define LIT_BUFS 4\n    uchf *sym_buf;        /* buffer for distances and literals/lengths */\n#endif\n\n    uInt  lit_bufsize;\n    /* Size of match buffer for literals/lengths.  There are 4 reasons for\n     * limiting lit_bufsize to 64K:\n     *   - frequencies can be kept in 16 bit counters\n     *   - if compression is not successful for the first block, all input\n     *     data is still in the window so we can still emit a stored block even\n     *     when input comes from standard input.  (This can also be done for\n     *     all blocks if lit_bufsize is not greater than 32K.)\n     *   - if compression is not successful for a file smaller than 64K, we can\n     *     even emit a stored file instead of a stored block (saving 5 bytes).\n     *     This is applicable only for zip (not gzip or zlib).\n     *   - creating new Huffman trees less frequently may not provide fast\n     *     adaptation to changes in the input data statistics. (Take for\n     *     example a binary file with poorly compressible code followed by\n     *     a highly compressible string table.) Smaller buffer sizes give\n     *     fast adaptation but have of course the overhead of transmitting\n     *     trees more frequently.\n     *   - I can't count above 4\n     */\n\n    uInt sym_next;      /* running index in symbol buffer */\n    uInt sym_end;       /* symbol table full when sym_next reaches this */\n\n    ulg opt_len;        /* bit length of current block with optimal trees */\n    ulg static_len;     /* bit length of current block with static trees */\n    uInt matches;       /* number of string matches in current block */\n    uInt insert;        /* bytes at end of window left to insert */\n\n#ifdef ZLIB_DEBUG\n    ulg compressed_len; /* total bit length of compressed file mod 2^32 */\n    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */\n#endif\n\n    ush bi_buf;\n    /* Output buffer. bits are inserted starting at the bottom (least\n     * significant bits).\n     */\n    int bi_valid;\n    /* Number of valid bits in bi_buf.  All bits above the last valid bit\n     * are always zero.\n     */\n\n    ulg high_water;\n    /* High water mark offset in window for initialized bytes -- bytes above\n     * this are set to zero in order to avoid memory check warnings when\n     * longest match routines access bytes past the input.  This is then\n     * updated to the new high water mark.\n     */\n\n} FAR deflate_state;\n\n/* Output a byte on the stream.\n * IN assertion: there is enough room in pending_buf.\n */\n#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}\n\n\n#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)\n/* Minimum amount of lookahead, except at the end of the input file.\n * See deflate.c for comments about the MIN_MATCH+1.\n */\n\n#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)\n/* In order to simplify the code, particularly on 16 bit machines, match\n * distances are limited to MAX_DIST instead of WSIZE.\n */\n\n#define WIN_INIT MAX_MATCH\n/* Number of bytes after end of data in window to initialize in order to avoid\n   memory checker errors from longest match routines */\n\n        /* in trees.c */\nvoid ZLIB_INTERNAL _tr_init(deflate_state *s);\nint ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);\nvoid ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,\n                                   ulg stored_len, int last);\nvoid ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);\nvoid ZLIB_INTERNAL _tr_align(deflate_state *s);\nvoid ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,\n                                    ulg stored_len, int last);\n\n#define d_code(dist) \\\n   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])\n/* Mapping from a distance to a distance code. dist is the distance - 1 and\n * must not have side effects. _dist_code[256] and _dist_code[257] are never\n * used.\n */\n\n#ifndef ZLIB_DEBUG\n/* Inline versions of _tr_tally for speed: */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n  extern uch ZLIB_INTERNAL _length_code[];\n  extern uch ZLIB_INTERNAL _dist_code[];\n#else\n  extern const uch ZLIB_INTERNAL _length_code[];\n  extern const uch ZLIB_INTERNAL _dist_code[];\n#endif\n\n#ifdef LIT_MEM\n# define _tr_tally_lit(s, c, flush) \\\n  { uch cc = (c); \\\n    s->d_buf[s->sym_next] = 0; \\\n    s->l_buf[s->sym_next++] = cc; \\\n    s->dyn_ltree[cc].Freq++; \\\n    flush = (s->sym_next == s->sym_end); \\\n   }\n# define _tr_tally_dist(s, distance, length, flush) \\\n  { uch len = (uch)(length); \\\n    ush dist = (ush)(distance); \\\n    s->d_buf[s->sym_next] = dist; \\\n    s->l_buf[s->sym_next++] = len; \\\n    dist--; \\\n    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \\\n    s->dyn_dtree[d_code(dist)].Freq++; \\\n    flush = (s->sym_next == s->sym_end); \\\n  }\n#else\n# define _tr_tally_lit(s, c, flush) \\\n  { uch cc = (c); \\\n    s->sym_buf[s->sym_next++] = 0; \\\n    s->sym_buf[s->sym_next++] = 0; \\\n    s->sym_buf[s->sym_next++] = cc; \\\n    s->dyn_ltree[cc].Freq++; \\\n    flush = (s->sym_next == s->sym_end); \\\n   }\n# define _tr_tally_dist(s, distance, length, flush) \\\n  { uch len = (uch)(length); \\\n    ush dist = (ush)(distance); \\\n    s->sym_buf[s->sym_next++] = (uch)dist; \\\n    s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \\\n    s->sym_buf[s->sym_next++] = len; \\\n    dist--; \\\n    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \\\n    s->dyn_dtree[d_code(dist)].Freq++; \\\n    flush = (s->sym_next == s->sym_end); \\\n  }\n#endif\n#else\n# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)\n# define _tr_tally_dist(s, distance, length, flush) \\\n              flush = _tr_tally(s, distance, length)\n#endif\n\n#endif /* DEFLATE_H */\n"
  },
  {
    "path": "eidos_zlib/eidos_zlib.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2020-04-17T14:17:13\n#\n#-------------------------------------------------\n\nQT       -= core gui\n\nTEMPLATE = lib\nCONFIG += staticlib\n\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\nCONFIG -= qt\nCONFIG += c11\nQMAKE_CFLAGS += -std=c11\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1\nQMAKE_CFLAGS_RELEASE += -O3\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CFLAGS += -Wno-unknown-pragmas -Wno-pragmas\n}\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n\nSOURCES += \\\n    zutil.c \\\n    adler32.c \\\n    compress.c \\\n    crc32.c \\\n    deflate.c \\\n    gzlib.c \\\n    gzwrite.c \\\n    trees.c\n\nHEADERS += \\\n    zutil.h \\\n    crc32.h \\\n    deflate.h \\\n    gzguts.h \\\n    trees.h \\\n    zconf.h \\\n    zlib.h\n\n"
  },
  {
    "path": "eidos_zlib/gzguts.h",
    "content": "/* gzguts.h -- zlib internal header definitions for gz* operations\n * Copyright (C) 2004-2024 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#ifdef _LARGEFILE64_SOURCE\n#  ifndef _LARGEFILE_SOURCE\n#    define _LARGEFILE_SOURCE 1\n#  endif\n#  undef _FILE_OFFSET_BITS\n#  undef _TIME_BITS\n#endif\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include <stdio.h>\n#include \"zlib.h\"\n#ifdef STDC\n#  include <string.h>\n#  include <stdlib.h>\n#  include <limits.h>\n#endif\n\n#ifndef _POSIX_SOURCE\n#  define _POSIX_SOURCE\n#endif\n#include <fcntl.h>\n\n#ifdef _WIN32\n#  include <stddef.h>\n#endif\n\n#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)\n#  include <io.h>\n#endif\n\n#if defined(_WIN32)\n#  define WIDECHAR\n#endif\n\n#ifdef WINAPI_FAMILY\n#  define open _open\n#  define read _read\n#  define write _write\n#  define close _close\n#endif\n\n#ifdef NO_DEFLATE       /* for compatibility with old definition */\n#  define NO_GZCOMPRESS\n#endif\n\n#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(__CYGWIN__)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#ifndef HAVE_VSNPRINTF\n#  ifdef MSDOS\n/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),\n   but for now we just assume it doesn't. */\n#    define NO_vsnprintf\n#  endif\n#  ifdef __TURBOC__\n#    define NO_vsnprintf\n#  endif\n#  ifdef WIN32\n/* In Win32, vsnprintf is available as the \"non-ANSI\" _vsnprintf. */\n#    if !defined(vsnprintf) && !defined(NO_vsnprintf)\n#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )\n#         define vsnprintf _vsnprintf\n#      endif\n#    endif\n#  endif\n#  ifdef __SASC\n#    define NO_vsnprintf\n#  endif\n#  ifdef VMS\n#    define NO_vsnprintf\n#  endif\n#  ifdef __OS400__\n#    define NO_vsnprintf\n#  endif\n#  ifdef __MVS__\n#    define NO_vsnprintf\n#  endif\n#endif\n\n/* unlike snprintf (which is required in C99), _snprintf does not guarantee\n   null termination of the result -- however this is only used in gzlib.c where\n   the result is assured to fit in the space provided */\n#if defined(_MSC_VER) && _MSC_VER < 1900\n#  define snprintf _snprintf\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\n/* gz* functions always use library allocation functions */\n#ifndef STDC\n  extern voidp  malloc(uInt size);\n  extern void   free(voidpf ptr);\n#endif\n\n/* get errno and strerror definition */\n#if defined UNDER_CE\n#  include <windows.h>\n#  define zstrerror() gz_strwinerror((DWORD)GetLastError())\n#else\n#  ifndef NO_STRERROR\n#    include <errno.h>\n#    define zstrerror() strerror(errno)\n#  else\n#    define zstrerror() \"stdio error (consult errno)\"\n#  endif\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0\n    ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);\n    ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);\n    ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);\n    ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);\n#endif\n\n/* default memLevel */\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n\n/* default i/o buffer size -- double this for output when reading (this and\n   twice this must be able to fit in an unsigned type) */\n#define GZBUFSIZE 8192\n\n/* gzip modes, also provide a little integrity check on the passed structure */\n#define GZ_NONE 0\n#define GZ_READ 7247\n#define GZ_WRITE 31153\n#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */\n\n/* values for gz_state how */\n#define LOOK 0      /* look for a gzip header */\n#define COPY 1      /* copy input directly */\n#define GZIP 2      /* decompress a gzip stream */\n\n/* internal gzip file state data structure */\ntypedef struct {\n        /* exposed contents for gzgetc() macro */\n    struct gzFile_s x;      /* \"x\" for exposed */\n                            /* x.have: number of bytes available at x.next */\n                            /* x.next: next output data to deliver or write */\n                            /* x.pos: current position in uncompressed data */\n        /* used for both reading and writing */\n    int mode;               /* see gzip modes above */\n    int fd;                 /* file descriptor */\n    char *path;             /* path or fd for error messages */\n    unsigned size;          /* buffer size, zero if not allocated yet */\n    unsigned want;          /* requested buffer size, default is GZBUFSIZE */\n    unsigned char *in;      /* input buffer (double-sized when writing) */\n    unsigned char *out;     /* output buffer (double-sized when reading) */\n    int direct;             /* 0 if processing gzip, 1 if transparent */\n        /* just for reading */\n    int how;                /* 0: get header, 1: copy, 2: decompress */\n    z_off64_t start;        /* where the gzip data started, for rewinding */\n    int eof;                /* true if end of input file reached */\n    int past;               /* true if read requested past end */\n        /* just for writing */\n    int level;              /* compression level */\n    int strategy;           /* compression strategy */\n    int reset;              /* true if a reset is pending after a Z_FINISH */\n        /* seek request */\n    z_off64_t skip;         /* amount to skip (already rewound if backwards) */\n    int seek;               /* true if seek request pending */\n        /* error information */\n    int err;                /* error code */\n    char *msg;              /* error message */\n        /* zlib inflate or deflate stream */\n    z_stream strm;          /* stream structure in-place (not a pointer) */\n} gz_state;\ntypedef gz_state FAR *gz_statep;\n\n/* shared functions */\nvoid ZLIB_INTERNAL gz_error(gz_statep, int, const char *);\n#if defined UNDER_CE\nchar ZLIB_INTERNAL *gz_strwinerror(DWORD error);\n#endif\n\n/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t\n   value -- needed when comparing unsigned to z_off64_t, which is signed\n   (possible z_off64_t types off_t, off64_t, and long are all signed) */\nunsigned ZLIB_INTERNAL gz_intmax(void);\n#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())\n"
  },
  {
    "path": "eidos_zlib/gzlib.c",
    "content": "/* gzlib.c -- zlib functions common to reading and writing gzip files\n * Copyright (C) 2004-2024 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n#if defined(_WIN32) && !defined(__BORLANDC__)\n#  define LSEEK _lseeki64\n#else\n#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0\n#  define LSEEK lseek64\n#else\n#  define LSEEK lseek\n#endif\n#endif\n\n#if defined UNDER_CE\n\n/* Map the Windows error number in ERROR to a locale-dependent error message\n   string and return a pointer to it.  Typically, the values for ERROR come\n   from GetLastError.\n\n   The string pointed to shall not be modified by the application, but may be\n   overwritten by a subsequent call to gz_strwinerror\n\n   The gz_strwinerror function does not change the current setting of\n   GetLastError. */\nchar ZLIB_INTERNAL *gz_strwinerror(DWORD error) {\n    static char buf[1024];\n\n    wchar_t *msgbuf;\n    DWORD lasterr = GetLastError();\n    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM\n        | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n        NULL,\n        error,\n        0, /* Default language */\n        (LPVOID)&msgbuf,\n        0,\n        NULL);\n    if (chars != 0) {\n        /* If there is an \\r\\n appended, zap it.  */\n        if (chars >= 2\n            && msgbuf[chars - 2] == '\\r' && msgbuf[chars - 1] == '\\n') {\n            chars -= 2;\n            msgbuf[chars] = 0;\n        }\n\n        if (chars > sizeof (buf) - 1) {\n            chars = sizeof (buf) - 1;\n            msgbuf[chars] = 0;\n        }\n\n        wcstombs(buf, msgbuf, chars + 1);\n        LocalFree(msgbuf);\n    }\n    else {\n        sprintf(buf, \"unknown win32 error (%ld)\", error);\n    }\n\n    SetLastError(lasterr);\n    return buf;\n}\n\n#endif /* UNDER_CE */\n\n/* Reset gzip file state */\nlocal void gz_reset(gz_statep state) {\n    state->x.have = 0;              /* no output data available */\n    if (state->mode == GZ_READ) {   /* for reading ... */\n        state->eof = 0;             /* not at end of file */\n        state->past = 0;            /* have not read past end yet */\n        state->how = LOOK;          /* look for gzip header */\n    }\n    else                            /* for writing ... */\n        state->reset = 0;           /* no deflateReset pending */\n    state->seek = 0;                /* no seek request pending */\n    gz_error(state, Z_OK, NULL);    /* clear error */\n    state->x.pos = 0;               /* no uncompressed data yet */\n    state->strm.avail_in = 0;       /* no input data yet */\n}\n\n/* Open a gzip file either by name or file descriptor. */\nlocal gzFile gz_open(const void *path, int fd, const char *mode) {\n    gz_statep state;\n    z_size_t len;\n    int oflag;\n#ifdef O_CLOEXEC\n    int cloexec = 0;\n#endif\n#ifdef O_EXCL\n    int exclusive = 0;\n#endif\n\n    /* check input */\n    if (path == NULL)\n        return NULL;\n\n    /* allocate gzFile structure to return */\n    state = (gz_statep)malloc(sizeof(gz_state));\n    if (state == NULL)\n        return NULL;\n    state->size = 0;            /* no buffers allocated yet */\n    state->want = GZBUFSIZE;    /* requested buffer size */\n    state->msg = NULL;          /* no error message yet */\n\n    /* interpret mode */\n    state->mode = GZ_NONE;\n    state->level = Z_DEFAULT_COMPRESSION;\n    state->strategy = Z_DEFAULT_STRATEGY;\n    state->direct = 0;\n    while (*mode) {\n        if (*mode >= '0' && *mode <= '9')\n            state->level = *mode - '0';\n        else\n            switch (*mode) {\n            case 'r':\n                state->mode = GZ_READ;\n                break;\n#ifndef NO_GZCOMPRESS\n            case 'w':\n                state->mode = GZ_WRITE;\n                break;\n            case 'a':\n                state->mode = GZ_APPEND;\n                break;\n#endif\n            case '+':       /* can't read and write at the same time */\n                free(state);\n                return NULL;\n            case 'b':       /* ignore -- will request binary anyway */\n                break;\n#ifdef O_CLOEXEC\n            case 'e':\n                cloexec = 1;\n                break;\n#endif\n#ifdef O_EXCL\n            case 'x':\n                exclusive = 1;\n                break;\n#endif\n            case 'f':\n                state->strategy = Z_FILTERED;\n                break;\n            case 'h':\n                state->strategy = Z_HUFFMAN_ONLY;\n                break;\n            case 'R':\n                state->strategy = Z_RLE;\n                break;\n            case 'F':\n                state->strategy = Z_FIXED;\n                break;\n            case 'T':\n                state->direct = 1;\n                break;\n            default:        /* could consider as an error, but just ignore */\n                ;\n            }\n        mode++;\n    }\n\n    /* must provide an \"r\", \"w\", or \"a\" */\n    if (state->mode == GZ_NONE) {\n        free(state);\n        return NULL;\n    }\n\n    /* can't force transparent read */\n    if (state->mode == GZ_READ) {\n        if (state->direct) {\n            free(state);\n            return NULL;\n        }\n        state->direct = 1;      /* for empty file */\n    }\n\n    /* save the path name for error messages */\n#ifdef WIDECHAR\n    if (fd == -2) {\n        len = wcstombs(NULL, path, 0);\n        if (len == (z_size_t)-1)\n            len = 0;\n    }\n    else\n#endif\n        len = strlen((const char *)path);\n    state->path = (char *)malloc(len + 1);\n    if (state->path == NULL) {\n        free(state);\n        return NULL;\n    }\n#ifdef WIDECHAR\n    if (fd == -2)\n        if (len)\n            wcstombs(state->path, path, len + 1);\n        else\n            *(state->path) = 0;\n    else\n#endif\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n        (void)snprintf(state->path, len + 1, \"%s\", (const char *)path);\n#else\n        strcpy(state->path, path);\n#endif\n\n    /* compute the flags for open() */\n    oflag =\n#ifdef O_LARGEFILE\n        O_LARGEFILE |\n#endif\n#ifdef O_BINARY\n        O_BINARY |\n#endif\n#ifdef O_CLOEXEC\n        (cloexec ? O_CLOEXEC : 0) |\n#endif\n        (state->mode == GZ_READ ?\n         O_RDONLY :\n         (O_WRONLY | O_CREAT |\n#ifdef O_EXCL\n          (exclusive ? O_EXCL : 0) |\n#endif\n          (state->mode == GZ_WRITE ?\n           O_TRUNC :\n           O_APPEND)));\n\n    /* open the file with the appropriate flags (or just use fd) */\n    state->fd = fd > -1 ? fd : (\n#ifdef WIDECHAR\n        fd == -2 ? _wopen(path, oflag, 0666) :\n#endif\n        open((const char *)path, oflag, 0666));\n    if (state->fd == -1) {\n        free(state->path);\n        free(state);\n        return NULL;\n    }\n    if (state->mode == GZ_APPEND) {\n        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */\n        state->mode = GZ_WRITE;         /* simplify later checks */\n    }\n\n    /* save the current position for rewinding (only if reading) */\n    if (state->mode == GZ_READ) {\n        state->start = LSEEK(state->fd, 0, SEEK_CUR);\n        if (state->start == -1) state->start = 0;\n    }\n\n    /* initialize stream */\n    gz_reset(state);\n\n    /* return stream */\n    return (gzFile)state;\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzopen(const char *path, const char *mode) {\n    return gz_open(path, -1, mode);\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzopen64(const char *path, const char *mode) {\n    return gz_open(path, -1, mode);\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzdopen(int fd, const char *mode) {\n    char *path;         /* identifier for error messages */\n    gzFile gz;\n\n    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)\n        return NULL;\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n    (void)snprintf(path, 7 + 3 * sizeof(int), \"<fd:%d>\", fd);\n#else\n    sprintf(path, \"<fd:%d>\", fd);   /* for debugging */\n#endif\n    gz = gz_open(path, fd, mode);\n    free(path);\n    return gz;\n}\n\n/* -- see zlib.h -- */\n#ifdef WIDECHAR\ngzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {\n    return gz_open(path, -2, mode);\n}\n#endif\n\n/* -- see zlib.h -- */\nint ZEXPORT gzbuffer(gzFile file, unsigned size) {\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* make sure we haven't already allocated memory */\n    if (state->size != 0)\n        return -1;\n\n    /* check and set requested size */\n    if ((size << 1) < size)\n        return -1;              /* need to be able to double it */\n    if (size < 8)\n        size = 8;               /* needed to behave well with flushing */\n    state->want = size;\n    return 0;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzrewind(gzFile file) {\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no error */\n    if (state->mode != GZ_READ ||\n            (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return -1;\n\n    /* back up and start over */\n    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)\n        return -1;\n    gz_reset(state);\n    return 0;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {\n    unsigned n;\n    z_off64_t ret;\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* check that there's no error */\n    if (state->err != Z_OK && state->err != Z_BUF_ERROR)\n        return -1;\n\n    /* can only seek from start or relative to current position */\n    if (whence != SEEK_SET && whence != SEEK_CUR)\n        return -1;\n\n    /* normalize offset to a SEEK_CUR specification */\n    if (whence == SEEK_SET)\n        offset -= state->x.pos;\n    else if (state->seek)\n        offset += state->skip;\n    state->seek = 0;\n\n    /* if within raw area while reading, just go there */\n    if (state->mode == GZ_READ && state->how == COPY &&\n            state->x.pos + offset >= 0) {\n        ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);\n        if (ret == -1)\n            return -1;\n        state->x.have = 0;\n        state->eof = 0;\n        state->past = 0;\n        state->seek = 0;\n        gz_error(state, Z_OK, NULL);\n        state->strm.avail_in = 0;\n        state->x.pos += offset;\n        return state->x.pos;\n    }\n\n    /* calculate skip amount, rewinding if needed for back seek when reading */\n    if (offset < 0) {\n        if (state->mode != GZ_READ)         /* writing -- can't go backwards */\n            return -1;\n        offset += state->x.pos;\n        if (offset < 0)                     /* before start of file! */\n            return -1;\n        if (gzrewind(file) == -1)           /* rewind, then skip to offset */\n            return -1;\n    }\n\n    /* if reading, skip what's in output buffer (one less gzgetc() check) */\n    if (state->mode == GZ_READ) {\n        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?\n            (unsigned)offset : state->x.have;\n        state->x.have -= n;\n        state->x.next += n;\n        state->x.pos += n;\n        offset -= n;\n    }\n\n    /* request skip (if not zero) */\n    if (offset) {\n        state->seek = 1;\n        state->skip = offset;\n    }\n    return state->x.pos + offset;\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {\n    z_off64_t ret;\n\n    ret = gzseek64(file, (z_off64_t)offset, whence);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gztell64(gzFile file) {\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* return position */\n    return state->x.pos + (state->seek ? state->skip : 0);\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gztell(gzFile file) {\n    z_off64_t ret;\n\n    ret = gztell64(file);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gzoffset64(gzFile file) {\n    z_off64_t offset;\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* compute and return effective offset in file */\n    offset = LSEEK(state->fd, 0, SEEK_CUR);\n    if (offset == -1)\n        return -1;\n    if (state->mode == GZ_READ)             /* reading */\n        offset -= state->strm.avail_in;     /* don't count buffered input */\n    return offset;\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gzoffset(gzFile file) {\n    z_off64_t ret;\n\n    ret = gzoffset64(file);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzeof(gzFile file) {\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return 0;\n\n    /* return end-of-file state */\n    return state->mode == GZ_READ ? state->past : 0;\n}\n\n/* -- see zlib.h -- */\nconst char * ZEXPORT gzerror(gzFile file, int *errnum) {\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return NULL;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return NULL;\n\n    /* return error information */\n    if (errnum != NULL)\n        *errnum = state->err;\n    return state->err == Z_MEM_ERROR ? \"out of memory\" :\n                                       (state->msg == NULL ? \"\" : state->msg);\n}\n\n/* -- see zlib.h -- */\nvoid ZEXPORT gzclearerr(gzFile file) {\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return;\n\n    /* clear error and end-of-file */\n    if (state->mode == GZ_READ) {\n        state->eof = 0;\n        state->past = 0;\n    }\n    gz_error(state, Z_OK, NULL);\n}\n\n/* Create an error message in allocated memory and set state->err and\n   state->msg accordingly.  Free any previous error message already there.  Do\n   not try to free or allocate space if the error is Z_MEM_ERROR (out of\n   memory).  Simply save the error message as a static string.  If there is an\n   allocation failure constructing the error message, then convert the error to\n   out of memory. */\nvoid ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {\n    /* free previously allocated message and clear */\n    if (state->msg != NULL) {\n        if (state->err != Z_MEM_ERROR)\n            free(state->msg);\n        state->msg = NULL;\n    }\n\n    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */\n    if (err != Z_OK && err != Z_BUF_ERROR)\n        state->x.have = 0;\n\n    /* set error code, and if no message, then done */\n    state->err = err;\n    if (msg == NULL)\n        return;\n\n    /* for an out of memory error, return literal string when requested */\n    if (err == Z_MEM_ERROR)\n        return;\n\n    /* construct error message with path */\n    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==\n            NULL) {\n        state->err = Z_MEM_ERROR;\n        return;\n    }\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,\n                   \"%s%s%s\", state->path, \": \", msg);\n#else\n    strcpy(state->msg, state->path);\n    strcat(state->msg, \": \");\n    strcat(state->msg, msg);\n#endif\n}\n\n/* portably return maximum value for an int (when limits.h presumed not\n   available) -- we need to do this to cover cases where 2's complement not\n   used, since C standard permits 1's complement and sign-bit representations,\n   otherwise we could just use ((unsigned)-1) >> 1 */\nunsigned ZLIB_INTERNAL gz_intmax(void) {\n#ifdef INT_MAX\n    return INT_MAX;\n#else\n    unsigned p = 1, q;\n    do {\n        q = p;\n        p <<= 1;\n        p++;\n    } while (p > q);\n    return q >> 1;\n#endif\n}\n"
  },
  {
    "path": "eidos_zlib/gzwrite.c",
    "content": "/* gzwrite.c -- zlib functions for writing gzip files\n * Copyright (C) 2004-2019 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n// BCH 16 April 2020: adding pragmas to disable spurious warnings\n#pragma GCC diagnostic ignored \"-Wshorten-64-to-32\"\n#pragma clang diagnostic ignored \"-Wshorten-64-to-32\"\n\n/* Initialize state for writing a gzip file.  Mark initialization by setting\n   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on\n   success. */\nlocal int gz_init(gz_statep state) {\n    int ret;\n    z_streamp strm = &(state->strm);\n\n    /* allocate input buffer (double size for gzprintf) */\n    state->in = (unsigned char *)malloc(state->want << 1);\n    if (state->in == NULL) {\n        gz_error(state, Z_MEM_ERROR, \"out of memory\");\n        return -1;\n    }\n\n    /* only need output buffer and deflate state if compressing */\n    if (!state->direct) {\n        /* allocate output buffer */\n        state->out = (unsigned char *)malloc(state->want);\n        if (state->out == NULL) {\n            free(state->in);\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n\n        /* allocate deflate memory, set up for gzip compression */\n        strm->zalloc = Z_NULL;\n        strm->zfree = Z_NULL;\n        strm->opaque = Z_NULL;\n        ret = deflateInit2(strm, state->level, Z_DEFLATED,\n                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);\n        if (ret != Z_OK) {\n            free(state->out);\n            free(state->in);\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n        strm->next_in = NULL;\n    }\n\n    /* mark state as initialized */\n    state->size = state->want;\n\n    /* initialize write buffer if compressing */\n    if (!state->direct) {\n        strm->avail_out = state->size;\n        strm->next_out = state->out;\n        state->x.next = strm->next_out;\n    }\n    return 0;\n}\n\n/* Compress whatever is at avail_in and next_in and write to the output file.\n   Return -1 if there is an error writing to the output file or if gz_init()\n   fails to allocate memory, otherwise 0.  flush is assumed to be a valid\n   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is\n   reset to start a new gzip stream.  If gz->direct is true, then simply write\n   to the output file without compressing, and ignore flush. */\nlocal int gz_comp(gz_statep state, int flush) {\n    int ret, writ;\n    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;\n    z_streamp strm = &(state->strm);\n\n    /* allocate memory if this is the first time through */\n    if (state->size == 0 && gz_init(state) == -1)\n        return -1;\n\n    /* write directly if requested */\n    if (state->direct) {\n        while (strm->avail_in) {\n            put = strm->avail_in > max ? max : strm->avail_in;\n            writ = write(state->fd, strm->next_in, put);\n            if (writ < 0) {\n                gz_error(state, Z_ERRNO, zstrerror());\n                return -1;\n            }\n            strm->avail_in -= (unsigned)writ;\n            strm->next_in += writ;\n        }\n        return 0;\n    }\n\n    /* check for a pending reset */\n    if (state->reset) {\n        /* don't start a new gzip member unless there is data to write */\n        if (strm->avail_in == 0)\n            return 0;\n        deflateReset(strm);\n        state->reset = 0;\n    }\n\n    /* run deflate() on provided input until it produces no more output */\n    ret = Z_OK;\n    do {\n        /* write out current buffer contents if full, or if flushing, but if\n           doing Z_FINISH then don't write until we get to Z_STREAM_END */\n        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&\n            (flush != Z_FINISH || ret == Z_STREAM_END))) {\n            while (strm->next_out > state->x.next) {\n                put = strm->next_out - state->x.next > (int)max ? max :\n                      (unsigned)(strm->next_out - state->x.next);\n                writ = write(state->fd, state->x.next, put);\n                if (writ < 0) {\n                    gz_error(state, Z_ERRNO, zstrerror());\n                    return -1;\n                }\n                state->x.next += writ;\n            }\n            if (strm->avail_out == 0) {\n                strm->avail_out = state->size;\n                strm->next_out = state->out;\n                state->x.next = state->out;\n            }\n        }\n\n        /* compress */\n        have = strm->avail_out;\n        ret = deflate(strm, flush);\n        if (ret == Z_STREAM_ERROR) {\n            gz_error(state, Z_STREAM_ERROR,\n                      \"internal error: deflate stream corrupt\");\n            return -1;\n        }\n        have -= strm->avail_out;\n    } while (have);\n\n    /* if that completed a deflate stream, allow another to start */\n    if (flush == Z_FINISH)\n        state->reset = 1;\n\n    /* all done, no errors */\n    return 0;\n}\n\n/* Compress len zeros to output.  Return -1 on a write error or memory\n   allocation failure by gz_comp(), or 0 on success. */\nlocal int gz_zero(gz_statep state, z_off64_t len) {\n    int first;\n    unsigned n;\n    z_streamp strm = &(state->strm);\n\n    /* consume whatever's left in the input buffer */\n    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)\n        return -1;\n\n    /* compress len zeros (len guaranteed > 0) */\n    first = 1;\n    while (len) {\n        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?\n            (unsigned)len : state->size;\n        if (first) {\n            memset(state->in, 0, n);\n            first = 0;\n        }\n        strm->avail_in = n;\n        strm->next_in = state->in;\n        state->x.pos += n;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return -1;\n        len -= n;\n    }\n    return 0;\n}\n\n/* Write len bytes from buf to file.  Return the number of bytes written.  If\n   the returned value is less than len, then there was an error. */\nlocal z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {\n    z_size_t put = len;\n\n    /* if len is zero, avoid unnecessary operations */\n    if (len == 0)\n        return 0;\n\n    /* allocate memory if this is the first time through */\n    if (state->size == 0 && gz_init(state) == -1)\n        return 0;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return 0;\n    }\n\n    /* for small len, copy to input buffer, otherwise compress directly */\n    if (len < state->size) {\n        /* copy to input buffer, compress when full */\n        do {\n            unsigned have, copy;\n\n            if (state->strm.avail_in == 0)\n                state->strm.next_in = state->in;\n            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -\n                              state->in);\n            copy = state->size - have;\n            if (copy > len)\n                copy = (unsigned)len;\n            memcpy(state->in + have, buf, copy);\n            state->strm.avail_in += copy;\n            state->x.pos += copy;\n            buf = (const char *)buf + copy;\n            len -= copy;\n            if (len && gz_comp(state, Z_NO_FLUSH) == -1)\n                return 0;\n        } while (len);\n    }\n    else {\n        /* consume whatever's left in the input buffer */\n        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)\n            return 0;\n\n        /* directly compress user buffer to file */\n        state->strm.next_in = (z_const Bytef *)buf;\n        do {\n            unsigned n = (unsigned)-1;\n            if (n > len)\n                n = (unsigned)len;\n            state->strm.avail_in = n;\n            state->x.pos += n;\n            if (gz_comp(state, Z_NO_FLUSH) == -1)\n                return 0;\n            len -= n;\n        } while (len);\n    }\n\n    /* input was all buffered or compressed */\n    return put;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return 0;\n\n    /* since an int is returned, make sure len fits in one, otherwise return\n       with an error (this avoids a flaw in the interface) */\n    if ((int)len < 0) {\n        gz_error(state, Z_DATA_ERROR, \"requested length does not fit in int\");\n        return 0;\n    }\n\n    /* write len bytes from buf (the return value will fit in an int) */\n    return (int)gz_write(state, buf, len);\n}\n\n/* -- see zlib.h -- */\nz_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,\n                          gzFile file) {\n    z_size_t len;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return 0;\n\n    /* compute bytes to read -- error on overflow */\n    len = nitems * size;\n    if (size && len / size != nitems) {\n        gz_error(state, Z_STREAM_ERROR, \"request does not fit in a size_t\");\n        return 0;\n    }\n\n    /* write len bytes to buf, return the number of full items written */\n    return len ? gz_write(state, buf, len) / size : 0;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzputc(gzFile file, int c) {\n    unsigned have;\n    unsigned char buf[1];\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return -1;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return -1;\n    }\n\n    /* try writing to input buffer for speed (state->size == 0 if buffer not\n       initialized) */\n    if (state->size) {\n        if (strm->avail_in == 0)\n            strm->next_in = state->in;\n        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);\n        if (have < state->size) {\n            state->in[have] = (unsigned char)c;\n            strm->avail_in++;\n            state->x.pos++;\n            return c & 0xff;\n        }\n    }\n\n    /* no room in buffer or not initialized, use gz_write() */\n    buf[0] = (unsigned char)c;\n    if (gz_write(state, buf, 1) != 1)\n        return -1;\n    return c & 0xff;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzputs(gzFile file, const char *s) {\n    z_size_t len, put;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return -1;\n\n    /* write string */\n    len = strlen(s);\n    if ((int)len < 0 || (unsigned)len != len) {\n        gz_error(state, Z_STREAM_ERROR, \"string length does not fit in int\");\n        return -1;\n    }\n    put = gz_write(state, s, len);\n    return put < len ? -1 : (int)len;\n}\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#include <stdarg.h>\n\n/* -- see zlib.h -- */\nint ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {\n    int len;\n    unsigned left;\n    char *next;\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* make sure we have some buffer space */\n    if (state->size == 0 && gz_init(state) == -1)\n        return state->err;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* do the printf() into the input buffer, put length in len -- the input\n       buffer is double-sized just for this function, so there is guaranteed to\n       be state->size bytes available after the current contents */\n    if (strm->avail_in == 0)\n        strm->next_in = state->in;\n    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);\n    next[state->size - 1] = 0;\n#ifdef NO_vsnprintf\n#  ifdef HAS_vsprintf_void\n    (void)vsprintf(next, format, va);\n    for (len = 0; len < state->size; len++)\n        if (next[len] == 0) break;\n#  else\n    len = vsprintf(next, format, va);\n#  endif\n#else\n#  ifdef HAS_vsnprintf_void\n    (void)vsnprintf(next, state->size, format, va);\n    len = strlen(next);\n#  else\n    len = vsnprintf(next, state->size, format, va);\n#  endif\n#endif\n\n    /* check that printf() results fit in buffer */\n    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)\n        return 0;\n\n    /* update buffer and position, compress first half if past that */\n    strm->avail_in += (unsigned)len;\n    state->x.pos += len;\n    if (strm->avail_in >= state->size) {\n        left = strm->avail_in - state->size;\n        strm->avail_in = state->size;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return state->err;\n        memmove(state->in, state->in + state->size, left);\n        strm->next_in = state->in;\n        strm->avail_in = left;\n    }\n    return len;\n}\n\nint ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {\n    va_list va;\n    int ret;\n\n    va_start(va, format);\n    ret = gzvprintf(file, format, va);\n    va_end(va);\n    return ret;\n}\n\n#else /* !STDC && !Z_HAVE_STDARG_H */\n\n/* -- see zlib.h -- */\nint ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,\n                       int a4, int a5, int a6, int a7, int a8, int a9, int a10,\n                       int a11, int a12, int a13, int a14, int a15, int a16,\n                       int a17, int a18, int a19, int a20) {\n    unsigned len, left;\n    char *next;\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that can really pass pointer in ints */\n    if (sizeof(int) != sizeof(void *))\n        return Z_STREAM_ERROR;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* make sure we have some buffer space */\n    if (state->size == 0 && gz_init(state) == -1)\n        return state->error;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->error;\n    }\n\n    /* do the printf() into the input buffer, put length in len -- the input\n       buffer is double-sized just for this function, so there is guaranteed to\n       be state->size bytes available after the current contents */\n    if (strm->avail_in == 0)\n        strm->next_in = state->in;\n    next = (char *)(strm->next_in + strm->avail_in);\n    next[state->size - 1] = 0;\n#ifdef NO_snprintf\n#  ifdef HAS_sprintf_void\n    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,\n            a13, a14, a15, a16, a17, a18, a19, a20);\n    for (len = 0; len < size; len++)\n        if (next[len] == 0)\n            break;\n#  else\n    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,\n                  a12, a13, a14, a15, a16, a17, a18, a19, a20);\n#  endif\n#else\n#  ifdef HAS_snprintf_void\n    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,\n             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);\n    len = strlen(next);\n#  else\n    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,\n                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);\n#  endif\n#endif\n\n    /* check that printf() results fit in buffer */\n    if (len == 0 || len >= state->size || next[state->size - 1] != 0)\n        return 0;\n\n    /* update buffer and position, compress first half if past that */\n    strm->avail_in += len;\n    state->x.pos += len;\n    if (strm->avail_in >= state->size) {\n        left = strm->avail_in - state->size;\n        strm->avail_in = state->size;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return state->err;\n        memmove(state->in, state->in + state->size, left);\n        strm->next_in = state->in;\n        strm->avail_in = left;\n    }\n    return (int)len;\n}\n\n#endif\n\n/* -- see zlib.h -- */\nint ZEXPORT gzflush(gzFile file, int flush) {\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* check flush parameter */\n    if (flush < 0 || flush > Z_FINISH)\n        return Z_STREAM_ERROR;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* compress remaining data with requested flush */\n    (void)gz_comp(state, flush);\n    return state->err;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzsetparams(gzFile file, int level, int strategy) {\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)\n        return Z_STREAM_ERROR;\n\n    /* if no change is requested, then do nothing */\n    if (level == state->level && strategy == state->strategy)\n        return Z_OK;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* change compression parameters for subsequent input */\n    if (state->size) {\n        /* flush previous input with previous parameters before changing */\n        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)\n            return state->err;\n        deflateParams(strm, level, strategy);\n    }\n    state->level = level;\n    state->strategy = strategy;\n    return Z_OK;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzclose_w(gzFile file) {\n    int ret = Z_OK;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    /* check that we're writing */\n    if (state->mode != GZ_WRITE)\n        return Z_STREAM_ERROR;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            ret = state->err;\n    }\n\n    /* flush, free memory, and close file */\n    if (gz_comp(state, Z_FINISH) == -1)\n        ret = state->err;\n    if (state->size) {\n        if (!state->direct) {\n            (void)deflateEnd(&(state->strm));\n            free(state->out);\n        }\n        free(state->in);\n    }\n    gz_error(state, Z_OK, NULL);\n    free(state->path);\n    if (close(state->fd) == -1)\n        ret = Z_ERRNO;\n    free(state);\n    return ret;\n}\n"
  },
  {
    "path": "eidos_zlib/trees.c",
    "content": "/* trees.c -- output deflated data using Huffman coding\n * Copyright (C) 1995-2024 Jean-loup Gailly\n * detect_data_type() function provided freely by Cosmin Truta, 2006\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#pragma GCC diagnostic ignored \"-Wcomma\"\n#pragma clang diagnostic ignored \"-Wcomma\"\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process uses several Huffman trees. The more\n *      common source values are represented by shorter bit sequences.\n *\n *      Each code tree is stored in a compressed form which is itself\n * a Huffman encoding of the lengths of all the code strings (in\n * ascending order by source values).  The actual code strings are\n * reconstructed from the lengths in the inflate process, as described\n * in the deflate specification.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"'Deflate' Compressed Data Format Specification\".\n *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc\n *\n *      Storer, James A.\n *          Data Compression:  Methods and Theory, pp. 49-50.\n *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.\n *\n *      Sedgewick, R.\n *          Algorithms, p290.\n *          Addison-Wesley, 1983. ISBN 0-201-06672-6.\n */\n\n/* @(#) $Id$ */\n\n/* #define GEN_TREES_H */\n\n#include \"deflate.h\"\n\n#ifdef ZLIB_DEBUG\n#  include <ctype.h>\n#endif\n\n/* ===========================================================================\n * Constants\n */\n\n#define MAX_BL_BITS 7\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\n#define END_BLOCK 256\n/* end of block literal code */\n\n#define REP_3_6      16\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\n#define REPZ_3_10    17\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\n#define REPZ_11_138  18\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\nlocal const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */\n   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};\n\nlocal const int extra_dbits[D_CODES] /* extra bits for each distance code */\n   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nlocal const int extra_blbits[BL_CODES]/* extra bits for each bit length code */\n   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};\n\nlocal const uch bl_order[BL_CODES]\n   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n#define DIST_CODE_LEN  512 /* see definition of array dist_code below */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n/* non ANSI compilers may not accept trees.h */\n\nlocal ct_data static_ltree[L_CODES+2];\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nlocal ct_data static_dtree[D_CODES];\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nuch _dist_code[DIST_CODE_LEN];\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nuch _length_code[MAX_MATCH-MIN_MATCH+1];\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nlocal int base_length[LENGTH_CODES];\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nlocal int base_dist[D_CODES];\n/* First normalized distance for each code (0 = distance of 1) */\n\n#else\n#  include \"trees.h\"\n#endif /* GEN_TREES_H */\n\nstruct static_tree_desc_s {\n    const ct_data *static_tree;  /* static tree or NULL */\n    const intf *extra_bits;      /* extra bits for each code or NULL */\n    int     extra_base;          /* base index for extra_bits */\n    int     elems;               /* max number of elements in the tree */\n    int     max_length;          /* max bit length for the codes */\n};\n\n#ifdef NO_INIT_GLOBAL_POINTERS\n#  define TCONST\n#else\n#  define TCONST const\n#endif\n\nlocal TCONST static_tree_desc static_l_desc =\n{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};\n\nlocal TCONST static_tree_desc static_d_desc =\n{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};\n\nlocal TCONST static_tree_desc static_bl_desc =\n{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\n#define put_short(s, w) { \\\n    put_byte(s, (uch)((w) & 0xff)); \\\n    put_byte(s, (uch)((ush)(w) >> 8)); \\\n}\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nlocal unsigned bi_reverse(unsigned code, int len) {\n    register unsigned res = 0;\n    do {\n        res |= code & 1;\n        code >>= 1, res <<= 1;\n    } while (--len > 0);\n    return res >> 1;\n}\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nlocal void bi_flush(deflate_state *s) {\n    if (s->bi_valid == 16) {\n        put_short(s, s->bi_buf);\n        s->bi_buf = 0;\n        s->bi_valid = 0;\n    } else if (s->bi_valid >= 8) {\n        put_byte(s, (Byte)s->bi_buf);\n        s->bi_buf >>= 8;\n        s->bi_valid -= 8;\n    }\n}\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nlocal void bi_windup(deflate_state *s) {\n    if (s->bi_valid > 8) {\n        put_short(s, s->bi_buf);\n    } else if (s->bi_valid > 0) {\n        put_byte(s, (Byte)s->bi_buf);\n    }\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->bits_sent = (s->bits_sent + 7) & ~7;\n#endif\n}\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nlocal void gen_codes(ct_data *tree, int max_code, ushf *bl_count) {\n    ush next_code[MAX_BITS+1]; /* next code value for each bit length */\n    unsigned code = 0;         /* running code value */\n    int bits;                  /* bit index */\n    int n;                     /* code index */\n\n    /* The distribution counts are first used to generate the code values\n     * without bit reversal.\n     */\n    for (bits = 1; bits <= MAX_BITS; bits++) {\n        code = (code + bl_count[bits - 1]) << 1;\n        next_code[bits] = (ush)code;\n    }\n    /* Check that the bit counts in bl_count are consistent. The last code\n     * must be all ones.\n     */\n    Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,\n            \"inconsistent bit counts\");\n    Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n    for (n = 0;  n <= max_code; n++) {\n        int len = tree[n].Len;\n        if (len == 0) continue;\n        /* Now reverse the bits */\n        tree[n].Code = (ush)bi_reverse(next_code[len]++, len);\n\n        Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n            n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1));\n    }\n}\n\n#ifdef GEN_TREES_H\nlocal void gen_trees_header(void);\n#endif\n\n#ifndef ZLIB_DEBUG\n#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)\n   /* Send a code of the given tree. c and tree must not have side effects */\n\n#else /* !ZLIB_DEBUG */\n#  define send_code(s, c, tree) \\\n     { if (z_verbose>2) fprintf(stderr,\"\\ncd %3d \",(c)); \\\n       send_bits(s, tree[c].Code, tree[c].Len); }\n#endif\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\n#ifdef ZLIB_DEBUG\nlocal void send_bits(deflate_state *s, int value, int length) {\n    Tracevv((stderr,\" l %2d v %4x \", length, value));\n    Assert(length > 0 && length <= 15, \"invalid length\");\n    s->bits_sent += (ulg)length;\n\n    /* If not enough room in bi_buf, use (valid) bits from bi_buf and\n     * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid))\n     * unused bits in value.\n     */\n    if (s->bi_valid > (int)Buf_size - length) {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        put_short(s, s->bi_buf);\n        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);\n        s->bi_valid += length - Buf_size;\n    } else {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        s->bi_valid += length;\n    }\n}\n#else /* !ZLIB_DEBUG */\n\n#define send_bits(s, value, length) \\\n{ int len = length;\\\n  if (s->bi_valid > (int)Buf_size - len) {\\\n    int val = (int)value;\\\n    s->bi_buf |= (ush)val << s->bi_valid;\\\n    put_short(s, s->bi_buf);\\\n    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\\\n    s->bi_valid += len - Buf_size;\\\n  } else {\\\n    s->bi_buf |= (ush)(value) << s->bi_valid;\\\n    s->bi_valid += len;\\\n  }\\\n}\n#endif /* ZLIB_DEBUG */\n\n\n/* the arguments must not have side effects */\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nlocal void tr_static_init(void) {\n#if defined(GEN_TREES_H) || !defined(STDC)\n    static int static_init_done = 0;\n    int n;        /* iterates over tree elements */\n    int bits;     /* bit counter */\n    int length;   /* length value */\n    int code;     /* code value */\n    int dist;     /* distance index */\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    if (static_init_done) return;\n\n    /* For some embedded targets, global variables are not initialized: */\n#ifdef NO_INIT_GLOBAL_POINTERS\n    static_l_desc.static_tree = static_ltree;\n    static_l_desc.extra_bits = extra_lbits;\n    static_d_desc.static_tree = static_dtree;\n    static_d_desc.extra_bits = extra_dbits;\n    static_bl_desc.extra_bits = extra_blbits;\n#endif\n\n    /* Initialize the mapping length (0..255) -> length code (0..28) */\n    length = 0;\n    for (code = 0; code < LENGTH_CODES-1; code++) {\n        base_length[code] = length;\n        for (n = 0; n < (1 << extra_lbits[code]); n++) {\n            _length_code[length++] = (uch)code;\n        }\n    }\n    Assert (length == 256, \"tr_static_init: length != 256\");\n    /* Note that the length 255 (match length 258) can be represented\n     * in two different ways: code 284 + 5 bits or code 285, so we\n     * overwrite length_code[255] to use the best encoding:\n     */\n    _length_code[length - 1] = (uch)code;\n\n    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n    dist = 0;\n    for (code = 0 ; code < 16; code++) {\n        base_dist[code] = dist;\n        for (n = 0; n < (1 << extra_dbits[code]); n++) {\n            _dist_code[dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: dist != 256\");\n    dist >>= 7; /* from now on, all distances are divided by 128 */\n    for ( ; code < D_CODES; code++) {\n        base_dist[code] = dist << 7;\n        for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {\n            _dist_code[256 + dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: 256 + dist != 512\");\n\n    /* Construct the codes of the static literal tree */\n    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;\n    n = 0;\n    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;\n    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;\n    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;\n    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;\n    /* Codes 286 and 287 do not exist, but we must include them in the\n     * tree construction to get a canonical Huffman tree (longest code\n     * all ones)\n     */\n    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);\n\n    /* The static distance tree is trivial: */\n    for (n = 0; n < D_CODES; n++) {\n        static_dtree[n].Len = 5;\n        static_dtree[n].Code = bi_reverse((unsigned)n, 5);\n    }\n    static_init_done = 1;\n\n#  ifdef GEN_TREES_H\n    gen_trees_header();\n#  endif\n#endif /* defined(GEN_TREES_H) || !defined(STDC) */\n}\n\n/* ===========================================================================\n * Generate the file trees.h describing the static trees.\n */\n#ifdef GEN_TREES_H\n#  ifndef ZLIB_DEBUG\n#    include <stdio.h>\n#  endif\n\n#  define SEPARATOR(i, last, width) \\\n      ((i) == (last)? \"\\n};\\n\\n\" :    \\\n       ((i) % (width) == (width) - 1 ? \",\\n\" : \", \"))\n\nvoid gen_trees_header(void) {\n    FILE *header = fopen(\"trees.h\", \"w\");\n    int i;\n\n    Assert (header != NULL, \"Can't open trees.h\");\n    fprintf(header,\n            \"/* header created automatically with -DGEN_TREES_H */\\n\\n\");\n\n    fprintf(header, \"local const ct_data static_ltree[L_CODES+2] = {\\n\");\n    for (i = 0; i < L_CODES+2; i++) {\n        fprintf(header, \"{{%3u},{%3u}}%s\", static_ltree[i].Code,\n                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));\n    }\n\n    fprintf(header, \"local const ct_data static_dtree[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"{{%2u},{%2u}}%s\", static_dtree[i].Code,\n                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));\n    }\n\n    fprintf(header, \"const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\\n\");\n    for (i = 0; i < DIST_CODE_LEN; i++) {\n        fprintf(header, \"%2u%s\", _dist_code[i],\n                SEPARATOR(i, DIST_CODE_LEN-1, 20));\n    }\n\n    fprintf(header,\n        \"const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\\n\");\n    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {\n        fprintf(header, \"%2u%s\", _length_code[i],\n                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));\n    }\n\n    fprintf(header, \"local const int base_length[LENGTH_CODES] = {\\n\");\n    for (i = 0; i < LENGTH_CODES; i++) {\n        fprintf(header, \"%1u%s\", base_length[i],\n                SEPARATOR(i, LENGTH_CODES-1, 20));\n    }\n\n    fprintf(header, \"local const int base_dist[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"%5u%s\", base_dist[i],\n                SEPARATOR(i, D_CODES-1, 10));\n    }\n\n    fclose(header);\n}\n#endif /* GEN_TREES_H */\n\n/* ===========================================================================\n * Initialize a new block.\n */\nlocal void init_block(deflate_state *s) {\n    int n; /* iterates over tree elements */\n\n    /* Initialize the trees. */\n    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;\n    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;\n    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;\n\n    s->dyn_ltree[END_BLOCK].Freq = 1;\n    s->opt_len = s->static_len = 0L;\n    s->sym_next = s->matches = 0;\n}\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nvoid ZLIB_INTERNAL _tr_init(deflate_state *s) {\n    tr_static_init();\n\n    s->l_desc.dyn_tree = s->dyn_ltree;\n    s->l_desc.stat_desc = &static_l_desc;\n\n    s->d_desc.dyn_tree = s->dyn_dtree;\n    s->d_desc.stat_desc = &static_d_desc;\n\n    s->bl_desc.dyn_tree = s->bl_tree;\n    s->bl_desc.stat_desc = &static_bl_desc;\n\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = 0L;\n    s->bits_sent = 0L;\n#endif\n\n    /* Initialize the first block of the first file: */\n    init_block(s);\n}\n\n#define SMALLEST 1\n/* Index within the heap array of least frequent node in the Huffman tree */\n\n\n/* ===========================================================================\n * Remove the smallest element from the heap and recreate the heap with\n * one less element. Updates heap and heap_len.\n */\n#define pqremove(s, tree, top) \\\n{\\\n    top = s->heap[SMALLEST]; \\\n    s->heap[SMALLEST] = s->heap[s->heap_len--]; \\\n    pqdownheap(s, tree, SMALLEST); \\\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\n#define smaller(tree, n, m, depth) \\\n   (tree[n].Freq < tree[m].Freq || \\\n   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nlocal void pqdownheap(deflate_state *s, ct_data *tree, int k) {\n    int v = s->heap[k];\n    int j = k << 1;  /* left son of k */\n    while (j <= s->heap_len) {\n        /* Set j to the smallest of the two sons: */\n        if (j < s->heap_len &&\n            smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) {\n            j++;\n        }\n        /* Exit if v is smaller than both sons */\n        if (smaller(tree, v, s->heap[j], s->depth)) break;\n\n        /* Exchange v with the smallest son */\n        s->heap[k] = s->heap[j];  k = j;\n\n        /* And continue down the tree, setting j to the left son of k */\n        j <<= 1;\n    }\n    s->heap[k] = v;\n}\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nlocal void gen_bitlen(deflate_state *s, tree_desc *desc) {\n    ct_data *tree        = desc->dyn_tree;\n    int max_code         = desc->max_code;\n    const ct_data *stree = desc->stat_desc->static_tree;\n    const intf *extra    = desc->stat_desc->extra_bits;\n    int base             = desc->stat_desc->extra_base;\n    int max_length       = desc->stat_desc->max_length;\n    int h;              /* heap index */\n    int n, m;           /* iterate over the tree elements */\n    int bits;           /* bit length */\n    int xbits;          /* extra bits */\n    ush f;              /* frequency */\n    int overflow = 0;   /* number of elements with bit length too large */\n\n    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;\n\n    /* In a first pass, compute the optimal bit lengths (which may\n     * overflow in the case of the bit length tree).\n     */\n    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */\n\n    for (h = s->heap_max + 1; h < HEAP_SIZE; h++) {\n        n = s->heap[h];\n        bits = tree[tree[n].Dad].Len + 1;\n        if (bits > max_length) bits = max_length, overflow++;\n        tree[n].Len = (ush)bits;\n        /* We overwrite tree[n].Dad which is no longer needed */\n\n        if (n > max_code) continue; /* not a leaf node */\n\n        s->bl_count[bits]++;\n        xbits = 0;\n        if (n >= base) xbits = extra[n - base];\n        f = tree[n].Freq;\n        s->opt_len += (ulg)f * (unsigned)(bits + xbits);\n        if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);\n    }\n    if (overflow == 0) return;\n\n    Tracev((stderr,\"\\nbit length overflow\\n\"));\n    /* This happens for example on obj2 and pic of the Calgary corpus */\n\n    /* Find the first bit length which could increase: */\n    do {\n        bits = max_length - 1;\n        while (s->bl_count[bits] == 0) bits--;\n        s->bl_count[bits]--;        /* move one leaf down the tree */\n        s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */\n        s->bl_count[max_length]--;\n        /* The brother of the overflow item also moves one step up,\n         * but this does not affect bl_count[max_length]\n         */\n        overflow -= 2;\n    } while (overflow > 0);\n\n    /* Now recompute all bit lengths, scanning in increasing frequency.\n     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n     * lengths instead of fixing only the wrong ones. This idea is taken\n     * from 'ar' written by Haruhiko Okumura.)\n     */\n    for (bits = max_length; bits != 0; bits--) {\n        n = s->bl_count[bits];\n        while (n != 0) {\n            m = s->heap[--h];\n            if (m > max_code) continue;\n            if ((unsigned) tree[m].Len != (unsigned) bits) {\n                Tracev((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n                s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;\n                tree[m].Len = (ush)bits;\n            }\n            n--;\n        }\n    }\n}\n\n#ifdef DUMP_BL_TREE\n#  include <stdio.h>\n#endif\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nlocal void build_tree(deflate_state *s, tree_desc *desc) {\n    ct_data *tree         = desc->dyn_tree;\n    const ct_data *stree  = desc->stat_desc->static_tree;\n    int elems             = desc->stat_desc->elems;\n    int n, m;          /* iterate over heap elements */\n    int max_code = -1; /* largest code with non zero frequency */\n    int node;          /* new node being created */\n\n    /* Construct the initial heap, with least frequent element in\n     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1].\n     * heap[0] is not used.\n     */\n    s->heap_len = 0, s->heap_max = HEAP_SIZE;\n\n    for (n = 0; n < elems; n++) {\n        if (tree[n].Freq != 0) {\n            s->heap[++(s->heap_len)] = max_code = n;\n            s->depth[n] = 0;\n        } else {\n            tree[n].Len = 0;\n        }\n    }\n\n    /* The pkzip format requires that at least one distance code exists,\n     * and that at least one bit should be sent even if there is only one\n     * possible code. So to avoid special checks later on we force at least\n     * two codes of non zero frequency.\n     */\n    while (s->heap_len < 2) {\n        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);\n        tree[node].Freq = 1;\n        s->depth[node] = 0;\n        s->opt_len--; if (stree) s->static_len -= stree[node].Len;\n        /* node is 0 or 1 so it does not have extra bits */\n    }\n    desc->max_code = max_code;\n\n    /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree,\n     * establish sub-heaps of increasing lengths:\n     */\n    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);\n\n    /* Construct the Huffman tree by repeatedly combining the least two\n     * frequent nodes.\n     */\n    node = elems;              /* next internal node of the tree */\n    do {\n        pqremove(s, tree, n);  /* n = node of least frequency */\n        m = s->heap[SMALLEST]; /* m = node of next least frequency */\n\n        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */\n        s->heap[--(s->heap_max)] = m;\n\n        /* Create a new node father of n and m */\n        tree[node].Freq = tree[n].Freq + tree[m].Freq;\n        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?\n                                s->depth[n] : s->depth[m]) + 1);\n        tree[n].Dad = tree[m].Dad = (ush)node;\n#ifdef DUMP_BL_TREE\n        if (tree == s->bl_tree) {\n            fprintf(stderr,\"\\nnode %d(%d), sons %d(%d) %d(%d)\",\n                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);\n        }\n#endif\n        /* and insert the new node in the heap */\n        s->heap[SMALLEST] = node++;\n        pqdownheap(s, tree, SMALLEST);\n\n    } while (s->heap_len >= 2);\n\n    s->heap[--(s->heap_max)] = s->heap[SMALLEST];\n\n    /* At this point, the fields freq and dad are set. We can now\n     * generate the bit lengths.\n     */\n    gen_bitlen(s, (tree_desc *)desc);\n\n    /* The field len is now set, we can generate the bit codes */\n    gen_codes ((ct_data *)tree, max_code, s->bl_count);\n}\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nlocal void scan_tree(deflate_state *s, ct_data *tree, int max_code) {\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    if (nextlen == 0) max_count = 138, min_count = 3;\n    tree[max_code + 1].Len = (ush)0xffff; /* guard */\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n + 1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            s->bl_tree[curlen].Freq += count;\n        } else if (curlen != 0) {\n            if (curlen != prevlen) s->bl_tree[curlen].Freq++;\n            s->bl_tree[REP_3_6].Freq++;\n        } else if (count <= 10) {\n            s->bl_tree[REPZ_3_10].Freq++;\n        } else {\n            s->bl_tree[REPZ_11_138].Freq++;\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nlocal void send_tree(deflate_state *s, ct_data *tree, int max_code) {\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    /* tree[max_code + 1].Len = -1; */  /* guard already set */\n    if (nextlen == 0) max_count = 138, min_count = 3;\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n + 1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);\n\n        } else if (curlen != 0) {\n            if (curlen != prevlen) {\n                send_code(s, curlen, s->bl_tree); count--;\n            }\n            Assert(count >= 3 && count <= 6, \" 3_6?\");\n            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2);\n\n        } else if (count <= 10) {\n            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3);\n\n        } else {\n            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7);\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nlocal int build_bl_tree(deflate_state *s) {\n    int max_blindex;  /* index of last bit length code of non zero freq */\n\n    /* Determine the bit length frequencies for literal and distance trees */\n    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);\n    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);\n\n    /* Build the bit length tree: */\n    build_tree(s, (tree_desc *)(&(s->bl_desc)));\n    /* opt_len now includes the length of the tree representations, except the\n     * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts.\n     */\n\n    /* Determine the number of bit length codes to send. The pkzip format\n     * requires that at least 4 bit length codes be sent. (appnote.txt says\n     * 3 but the actual value used is 4.)\n     */\n    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {\n        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;\n    }\n    /* Update opt_len to include the bit length tree and counts */\n    s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4;\n    Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n            s->opt_len, s->static_len));\n\n    return max_blindex;\n}\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nlocal void send_all_trees(deflate_state *s, int lcodes, int dcodes,\n                          int blcodes) {\n    int rank;                    /* index in bl_order */\n\n    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n            \"too many codes\");\n    Tracev((stderr, \"\\nbl counts: \"));\n    send_bits(s, lcodes - 257, 5);  /* not +255 as stated in appnote.txt */\n    send_bits(s, dcodes - 1,   5);\n    send_bits(s, blcodes - 4,  4);  /* not -3 as stated in appnote.txt */\n    for (rank = 0; rank < blcodes; rank++) {\n        Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);\n    }\n    Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1);  /* literal tree */\n    Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1);  /* distance tree */\n    Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n/* ===========================================================================\n * Send a stored block\n */\nvoid ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,\n                                    ulg stored_len, int last) {\n    send_bits(s, (STORED_BLOCK<<1) + last, 3);  /* send block type */\n    bi_windup(s);        /* align on byte boundary */\n    put_short(s, (ush)stored_len);\n    put_short(s, (ush)~stored_len);\n    if (stored_len)\n        zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);\n    s->pending += stored_len;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;\n    s->compressed_len += (stored_len + 4) << 3;\n    s->bits_sent += 2*16;\n    s->bits_sent += stored_len << 3;\n#endif\n}\n\n/* ===========================================================================\n * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)\n */\nvoid ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) {\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nvoid ZLIB_INTERNAL _tr_align(deflate_state *s) {\n    send_bits(s, STATIC_TREES<<1, 3);\n    send_code(s, END_BLOCK, static_ltree);\n#ifdef ZLIB_DEBUG\n    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */\n#endif\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nlocal void compress_block(deflate_state *s, const ct_data *ltree,\n                          const ct_data *dtree) {\n    unsigned dist;      /* distance of matched string */\n    int lc;             /* match length or unmatched char (if dist == 0) */\n    unsigned sx = 0;    /* running index in symbol buffers */\n    unsigned code;      /* the code to send */\n    int extra;          /* number of extra bits to send */\n\n    if (s->sym_next != 0) do {\n#ifdef LIT_MEM\n        dist = s->d_buf[sx];\n        lc = s->l_buf[sx++];\n#else\n        dist = s->sym_buf[sx++] & 0xff;\n        dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;\n        lc = s->sym_buf[sx++];\n#endif\n        if (dist == 0) {\n            send_code(s, lc, ltree); /* send a literal byte */\n            Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n        } else {\n            /* Here, lc is the match length - MIN_MATCH */\n            code = _length_code[lc];\n            send_code(s, code + LITERALS + 1, ltree);   /* send length code */\n            extra = extra_lbits[code];\n            if (extra != 0) {\n                lc -= base_length[code];\n                send_bits(s, lc, extra);       /* send the extra length bits */\n            }\n            dist--; /* dist is now the match distance - 1 */\n            code = d_code(dist);\n            Assert (code < D_CODES, \"bad d_code\");\n\n            send_code(s, code, dtree);       /* send the distance code */\n            extra = extra_dbits[code];\n            if (extra != 0) {\n                dist -= (unsigned)base_dist[code];\n                send_bits(s, dist, extra);   /* send the extra distance bits */\n            }\n        } /* literal or match pair ? */\n\n        /* Check for no overlay of pending_buf on needed symbols */\n#ifdef LIT_MEM\n        Assert(s->pending < 2 * (s->lit_bufsize + sx), \"pendingBuf overflow\");\n#else\n        Assert(s->pending < s->lit_bufsize + sx, \"pendingBuf overflow\");\n#endif\n\n    } while (sx < s->sym_next);\n\n    send_code(s, END_BLOCK, ltree);\n}\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"block list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"allow list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nlocal int detect_data_type(deflate_state *s) {\n    /* block_mask is the bit mask of block-listed bytes\n     * set bits 0..6, 14..25, and 28..31\n     * 0xf3ffc07f = binary 11110011111111111100000001111111\n     */\n    unsigned long block_mask = 0xf3ffc07fUL;\n    int n;\n\n    /* Check for non-textual (\"block-listed\") bytes. */\n    for (n = 0; n <= 31; n++, block_mask >>= 1)\n        if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0))\n            return Z_BINARY;\n\n    /* Check for textual (\"allow-listed\") bytes. */\n    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0\n            || s->dyn_ltree[13].Freq != 0)\n        return Z_TEXT;\n    for (n = 32; n < LITERALS; n++)\n        if (s->dyn_ltree[n].Freq != 0)\n            return Z_TEXT;\n\n    /* There are no \"block-listed\" or \"allow-listed\" bytes:\n     * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n     */\n    return Z_BINARY;\n}\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and write out the encoded block.\n */\nvoid ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,\n                                   ulg stored_len, int last) {\n    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */\n    int max_blindex = 0;  /* index of last bit length code of non zero freq */\n\n    /* Build the Huffman trees unless a stored block is forced */\n    if (s->level > 0) {\n\n        /* Check if the file is binary or text */\n        if (s->strm->data_type == Z_UNKNOWN)\n            s->strm->data_type = detect_data_type(s);\n\n        /* Construct the literal and distance trees */\n        build_tree(s, (tree_desc *)(&(s->l_desc)));\n        Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n\n        build_tree(s, (tree_desc *)(&(s->d_desc)));\n        Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n        /* At this point, opt_len and static_len are the total bit lengths of\n         * the compressed block data, excluding the tree representations.\n         */\n\n        /* Build the bit length tree for the above two trees, and get the index\n         * in bl_order of the last bit length code to send.\n         */\n        max_blindex = build_bl_tree(s);\n\n        /* Determine the best encoding. Compute the block lengths in bytes. */\n        opt_lenb = (s->opt_len + 3 + 7) >> 3;\n        static_lenb = (s->static_len + 3 + 7) >> 3;\n\n        Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n                s->sym_next / 3));\n\n#ifndef FORCE_STATIC\n        if (static_lenb <= opt_lenb || s->strategy == Z_FIXED)\n#endif\n            opt_lenb = static_lenb;\n\n    } else {\n        Assert(buf != (char*)0, \"lost buf\");\n        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n    }\n\n#ifdef FORCE_STORED\n    if (buf != (char*)0) { /* force stored block */\n#else\n    if (stored_len + 4 <= opt_lenb && buf != (char*)0) {\n                       /* 4: two words for the lengths */\n#endif\n        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n         * Otherwise we can't have processed more than WSIZE input bytes since\n         * the last block flush, because compression would have been\n         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n         * transform a block into a stored block.\n         */\n        _tr_stored_block(s, buf, stored_len, last);\n\n    } else if (static_lenb == opt_lenb) {\n        send_bits(s, (STATIC_TREES<<1) + last, 3);\n        compress_block(s, (const ct_data *)static_ltree,\n                       (const ct_data *)static_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->static_len;\n#endif\n    } else {\n        send_bits(s, (DYN_TREES<<1) + last, 3);\n        send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1,\n                       max_blindex + 1);\n        compress_block(s, (const ct_data *)s->dyn_ltree,\n                       (const ct_data *)s->dyn_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->opt_len;\n#endif\n    }\n    Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n    /* The above check is made mod 2^32, for files larger than 512 MB\n     * and uLong implemented on 32 bits.\n     */\n    init_block(s);\n\n    if (last) {\n        bi_windup(s);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 7;  /* align on byte boundary */\n#endif\n    }\n    Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len >> 3,\n           s->compressed_len - 7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nint ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) {\n#ifdef LIT_MEM\n    s->d_buf[s->sym_next] = (ush)dist;\n    s->l_buf[s->sym_next++] = (uch)lc;\n#else\n    s->sym_buf[s->sym_next++] = (uch)dist;\n    s->sym_buf[s->sym_next++] = (uch)(dist >> 8);\n    s->sym_buf[s->sym_next++] = (uch)lc;\n#endif\n    if (dist == 0) {\n        /* lc is the unmatched char */\n        s->dyn_ltree[lc].Freq++;\n    } else {\n        s->matches++;\n        /* Here, lc is the match length - MIN_MATCH */\n        dist--;             /* dist = match distance - 1 */\n        Assert((ush)dist < (ush)MAX_DIST(s) &&\n               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n               (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n        s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++;\n        s->dyn_dtree[d_code(dist)].Freq++;\n    }\n    return (s->sym_next == s->sym_end);\n}\n"
  },
  {
    "path": "eidos_zlib/trees.h",
    "content": "/* header created automatically with -DGEN_TREES_H */\n\nlocal const ct_data static_ltree[L_CODES+2] = {\n{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},\n{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},\n{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},\n{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},\n{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},\n{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},\n{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},\n{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},\n{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},\n{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},\n{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},\n{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},\n{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},\n{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},\n{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},\n{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},\n{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},\n{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},\n{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},\n{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},\n{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},\n{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},\n{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},\n{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},\n{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},\n{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},\n{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},\n{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},\n{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},\n{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},\n{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},\n{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},\n{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},\n{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},\n{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},\n{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},\n{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},\n{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},\n{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},\n{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},\n{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},\n{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},\n{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},\n{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},\n{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},\n{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},\n{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},\n{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},\n{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},\n{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},\n{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},\n{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},\n{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},\n{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},\n{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},\n{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},\n{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},\n{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}\n};\n\nlocal const ct_data static_dtree[D_CODES] = {\n{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},\n{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},\n{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},\n{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},\n{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},\n{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}\n};\n\nconst uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,\n 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,\n10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,\n11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,\n18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29\n};\n\nconst uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,\n13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,\n17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,\n19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,\n21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,\n22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28\n};\n\nlocal const int base_length[LENGTH_CODES] = {\n0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,\n64, 80, 96, 112, 128, 160, 192, 224, 0\n};\n\nlocal const int base_dist[D_CODES] = {\n    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,\n   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,\n 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576\n};\n\n"
  },
  {
    "path": "eidos_zlib/zconf.h",
    "content": "/* zconf.h -- configuration of the zlib compression library\n * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZCONF_H\n#define ZCONF_H\n\n// BCH 12 April 2023: Add defines we need that would come from configure\n#define HAVE_UNISTD_H 1\n\n/*\n * If you *really* need a unique prefix for all types and library functions,\n * compile with -DZ_PREFIX. The \"standard\" zlib should be compiled without it.\n * Even better than compiling with -DZ_PREFIX would be to use configure to set\n * this permanently in zconf.h using \"./configure --zprefix\".\n */\n#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */\n#  define Z_PREFIX_SET\n\n/* all linked symbols and init macros */\n#  define _dist_code            z__dist_code\n#  define _length_code          z__length_code\n#  define _tr_align             z__tr_align\n#  define _tr_flush_bits        z__tr_flush_bits\n#  define _tr_flush_block       z__tr_flush_block\n#  define _tr_init              z__tr_init\n#  define _tr_stored_block      z__tr_stored_block\n#  define _tr_tally             z__tr_tally\n#  define adler32               z_adler32\n#  define adler32_combine       z_adler32_combine\n#  define adler32_combine64     z_adler32_combine64\n#  define adler32_z             z_adler32_z\n#  ifndef Z_SOLO\n#    define compress              z_compress\n#    define compress2             z_compress2\n#    define compressBound         z_compressBound\n#  endif\n#  define crc32                 z_crc32\n#  define crc32_combine         z_crc32_combine\n#  define crc32_combine64       z_crc32_combine64\n#  define crc32_combine_gen     z_crc32_combine_gen\n#  define crc32_combine_gen64   z_crc32_combine_gen64\n#  define crc32_combine_op      z_crc32_combine_op\n#  define crc32_z               z_crc32_z\n#  define deflate               z_deflate\n#  define deflateBound          z_deflateBound\n#  define deflateCopy           z_deflateCopy\n#  define deflateEnd            z_deflateEnd\n#  define deflateGetDictionary  z_deflateGetDictionary\n#  define deflateInit           z_deflateInit\n#  define deflateInit2          z_deflateInit2\n#  define deflateInit2_         z_deflateInit2_\n#  define deflateInit_          z_deflateInit_\n#  define deflateParams         z_deflateParams\n#  define deflatePending        z_deflatePending\n#  define deflatePrime          z_deflatePrime\n#  define deflateReset          z_deflateReset\n#  define deflateResetKeep      z_deflateResetKeep\n#  define deflateSetDictionary  z_deflateSetDictionary\n#  define deflateSetHeader      z_deflateSetHeader\n#  define deflateTune           z_deflateTune\n#  define deflate_copyright     z_deflate_copyright\n#  define get_crc_table         z_get_crc_table\n#  ifndef Z_SOLO\n#    define gz_error              z_gz_error\n#    define gz_intmax             z_gz_intmax\n#    define gz_strwinerror        z_gz_strwinerror\n#    define gzbuffer              z_gzbuffer\n#    define gzclearerr            z_gzclearerr\n#    define gzclose               z_gzclose\n#    define gzclose_r             z_gzclose_r\n#    define gzclose_w             z_gzclose_w\n#    define gzdirect              z_gzdirect\n#    define gzdopen               z_gzdopen\n#    define gzeof                 z_gzeof\n#    define gzerror               z_gzerror\n#    define gzflush               z_gzflush\n#    define gzfread               z_gzfread\n#    define gzfwrite              z_gzfwrite\n#    define gzgetc                z_gzgetc\n#    define gzgetc_               z_gzgetc_\n#    define gzgets                z_gzgets\n#    define gzoffset              z_gzoffset\n#    define gzoffset64            z_gzoffset64\n#    define gzopen                z_gzopen\n#    define gzopen64              z_gzopen64\n#    ifdef _WIN32\n#      define gzopen_w              z_gzopen_w\n#    endif\n#    define gzprintf              z_gzprintf\n#    define gzputc                z_gzputc\n#    define gzputs                z_gzputs\n#    define gzread                z_gzread\n#    define gzrewind              z_gzrewind\n#    define gzseek                z_gzseek\n#    define gzseek64              z_gzseek64\n#    define gzsetparams           z_gzsetparams\n#    define gztell                z_gztell\n#    define gztell64              z_gztell64\n#    define gzungetc              z_gzungetc\n#    define gzvprintf             z_gzvprintf\n#    define gzwrite               z_gzwrite\n#  endif\n#  define inflate               z_inflate\n#  define inflateBack           z_inflateBack\n#  define inflateBackEnd        z_inflateBackEnd\n#  define inflateBackInit       z_inflateBackInit\n#  define inflateBackInit_      z_inflateBackInit_\n#  define inflateCodesUsed      z_inflateCodesUsed\n#  define inflateCopy           z_inflateCopy\n#  define inflateEnd            z_inflateEnd\n#  define inflateGetDictionary  z_inflateGetDictionary\n#  define inflateGetHeader      z_inflateGetHeader\n#  define inflateInit           z_inflateInit\n#  define inflateInit2          z_inflateInit2\n#  define inflateInit2_         z_inflateInit2_\n#  define inflateInit_          z_inflateInit_\n#  define inflateMark           z_inflateMark\n#  define inflatePrime          z_inflatePrime\n#  define inflateReset          z_inflateReset\n#  define inflateReset2         z_inflateReset2\n#  define inflateResetKeep      z_inflateResetKeep\n#  define inflateSetDictionary  z_inflateSetDictionary\n#  define inflateSync           z_inflateSync\n#  define inflateSyncPoint      z_inflateSyncPoint\n#  define inflateUndermine      z_inflateUndermine\n#  define inflateValidate       z_inflateValidate\n#  define inflate_copyright     z_inflate_copyright\n#  define inflate_fast          z_inflate_fast\n#  define inflate_table         z_inflate_table\n#  ifndef Z_SOLO\n#    define uncompress            z_uncompress\n#    define uncompress2           z_uncompress2\n#  endif\n#  define zError                z_zError\n#  ifndef Z_SOLO\n#    define zcalloc               z_zcalloc\n#    define zcfree                z_zcfree\n#  endif\n#  define zlibCompileFlags      z_zlibCompileFlags\n#  define zlibVersion           z_zlibVersion\n\n/* all zlib typedefs in zlib.h and zconf.h */\n#  define Byte                  z_Byte\n#  define Bytef                 z_Bytef\n#  define alloc_func            z_alloc_func\n#  define charf                 z_charf\n#  define free_func             z_free_func\n#  ifndef Z_SOLO\n#    define gzFile                z_gzFile\n#  endif\n#  define gz_header             z_gz_header\n#  define gz_headerp            z_gz_headerp\n#  define in_func               z_in_func\n#  define intf                  z_intf\n#  define out_func              z_out_func\n#  define uInt                  z_uInt\n#  define uIntf                 z_uIntf\n#  define uLong                 z_uLong\n#  define uLongf                z_uLongf\n#  define voidp                 z_voidp\n#  define voidpc                z_voidpc\n#  define voidpf                z_voidpf\n\n/* all zlib structs in zlib.h and zconf.h */\n#  define gz_header_s           z_gz_header_s\n#  define internal_state        z_internal_state\n\n#endif\n\n#if defined(__MSDOS__) && !defined(MSDOS)\n#  define MSDOS\n#endif\n#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)\n#  define OS2\n#endif\n#if defined(_WINDOWS) && !defined(WINDOWS)\n#  define WINDOWS\n#endif\n#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)\n#  ifndef WIN32\n#    define WIN32\n#  endif\n#endif\n#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)\n#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)\n#    ifndef SYS16BIT\n#      define SYS16BIT\n#    endif\n#  endif\n#endif\n\n/*\n * Compile with -DMAXSEG_64K if the alloc function cannot allocate more\n * than 64k bytes at a time (needed on systems with 16-bit int).\n */\n#ifdef SYS16BIT\n#  define MAXSEG_64K\n#endif\n#ifdef MSDOS\n#  define UNALIGNED_OK\n#endif\n\n#ifdef __STDC_VERSION__\n#  ifndef STDC\n#    define STDC\n#  endif\n#  if __STDC_VERSION__ >= 199901L\n#    ifndef STDC99\n#      define STDC99\n#    endif\n#  endif\n#endif\n#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))\n#  define STDC\n#endif\n\n#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */\n#  define STDC\n#endif\n\n#ifndef STDC\n#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */\n#    define const       /* note: need a more gentle solution here */\n#  endif\n#endif\n\n#if defined(ZLIB_CONST) && !defined(z_const)\n#  define z_const const\n#else\n#  define z_const\n#endif\n\n#ifdef Z_SOLO\n#  ifdef _WIN64\n     typedef unsigned long long z_size_t;\n#  else\n     typedef unsigned long z_size_t;\n#  endif\n#else\n#  define z_longlong long long\n#  if defined(NO_SIZE_T)\n     typedef unsigned NO_SIZE_T z_size_t;\n#  elif defined(STDC)\n#    include <stddef.h>\n     typedef size_t z_size_t;\n#  else\n     typedef unsigned long z_size_t;\n#  endif\n#  undef z_longlong\n#endif\n\n/* Maximum value for memLevel in deflateInit2 */\n#ifndef MAX_MEM_LEVEL\n#  ifdef MAXSEG_64K\n#    define MAX_MEM_LEVEL 8\n#  else\n#    define MAX_MEM_LEVEL 9\n#  endif\n#endif\n\n/* Maximum value for windowBits in deflateInit2 and inflateInit2.\n * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files\n * created by gzip. (Files created by minigzip can still be extracted by\n * gzip.)\n */\n#ifndef MAX_WBITS\n#  define MAX_WBITS   15 /* 32K LZ77 window */\n#endif\n\n/* The memory requirements for deflate are (in bytes):\n            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n plus a few kilobytes for small objects. For example, if you want to reduce\n the default memory requirements from 256K to 128K, compile with\n     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n Of course this will generally degrade compression (there's no free lunch).\n\n   The memory requirements for inflate are (in bytes) 1 << windowBits\n that is, 32K for windowBits=15 (default value) plus about 7 kilobytes\n for small objects.\n*/\n\n                        /* Type declarations */\n\n#ifndef OF /* function prototypes */\n#  ifdef STDC\n#    define OF(args)  args\n#  else\n#    define OF(args)  ()\n#  endif\n#endif\n\n/* The following definitions for FAR are needed only for MSDOS mixed\n * model programming (small or medium model with some far allocations).\n * This was tested only with MSC; for other MSDOS compilers you may have\n * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,\n * just define FAR to be empty.\n */\n#ifdef SYS16BIT\n#  if defined(M_I86SM) || defined(M_I86MM)\n     /* MSC small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef _MSC_VER\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#  if (defined(__SMALL__) || defined(__MEDIUM__))\n     /* Turbo C small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef __BORLANDC__\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#endif\n\n#if defined(WINDOWS) || defined(WIN32)\n   /* If building or using zlib as a DLL, define ZLIB_DLL.\n    * This is not mandatory, but it offers a little performance increase.\n    */\n#  ifdef ZLIB_DLL\n#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))\n#      ifdef ZLIB_INTERNAL\n#        define ZEXTERN extern __declspec(dllexport)\n#      else\n#        define ZEXTERN extern __declspec(dllimport)\n#      endif\n#    endif\n#  endif  /* ZLIB_DLL */\n   /* If building or using zlib with the WINAPI/WINAPIV calling convention,\n    * define ZLIB_WINAPI.\n    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.\n    */\n#  ifdef ZLIB_WINAPI\n#    ifdef FAR\n#      undef FAR\n#    endif\n#    ifndef WIN32_LEAN_AND_MEAN\n#      define WIN32_LEAN_AND_MEAN\n#    endif\n#    include <windows.h>\n     /* No need for _export, use ZLIB.DEF instead. */\n     /* For complete Windows compatibility, use WINAPI, not __stdcall. */\n#    define ZEXPORT WINAPI\n#    ifdef WIN32\n#      define ZEXPORTVA WINAPIV\n#    else\n#      define ZEXPORTVA FAR CDECL\n#    endif\n#  endif\n#endif\n\n#if defined (__BEOS__)\n#  ifdef ZLIB_DLL\n#    ifdef ZLIB_INTERNAL\n#      define ZEXPORT   __declspec(dllexport)\n#      define ZEXPORTVA __declspec(dllexport)\n#    else\n#      define ZEXPORT   __declspec(dllimport)\n#      define ZEXPORTVA __declspec(dllimport)\n#    endif\n#  endif\n#endif\n\n#ifndef ZEXTERN\n#  define ZEXTERN extern\n#endif\n#ifndef ZEXPORT\n#  define ZEXPORT\n#endif\n#ifndef ZEXPORTVA\n#  define ZEXPORTVA\n#endif\n\n#ifndef FAR\n#  define FAR\n#endif\n\n#if !defined(__MACTYPES__)\ntypedef unsigned char  Byte;  /* 8 bits */\n#endif\ntypedef unsigned int   uInt;  /* 16 bits or more */\ntypedef unsigned long  uLong; /* 32 bits or more */\n\n#ifdef SMALL_MEDIUM\n   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */\n#  define Bytef Byte FAR\n#else\n   typedef Byte  FAR Bytef;\n#endif\ntypedef char  FAR charf;\ntypedef int   FAR intf;\ntypedef uInt  FAR uIntf;\ntypedef uLong FAR uLongf;\n\n#ifdef STDC\n   typedef void const *voidpc;\n   typedef void FAR   *voidpf;\n   typedef void       *voidp;\n#else\n   typedef Byte const *voidpc;\n   typedef Byte FAR   *voidpf;\n   typedef Byte       *voidp;\n#endif\n\n#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)\n#  include <limits.h>\n#  if (UINT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned\n#  elif (ULONG_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned long\n#  elif (USHRT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned short\n#  endif\n#endif\n\n#ifdef Z_U4\n   typedef Z_U4 z_crc_t;\n#else\n   typedef unsigned long z_crc_t;\n#endif\n\n#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_UNISTD_H\n#endif\n\n#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_STDARG_H\n#endif\n\n#ifdef STDC\n#  ifndef Z_SOLO\n#    include <sys/types.h>      /* for off_t */\n#  endif\n#endif\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\n#    include <stdarg.h>         /* for va_list */\n#  endif\n#endif\n\n#ifdef _WIN32\n#  ifndef Z_SOLO\n#    include <stddef.h>         /* for wchar_t */\n#  endif\n#endif\n\n/* a little trick to accommodate both \"#define _LARGEFILE64_SOURCE\" and\n * \"#define _LARGEFILE64_SOURCE 1\" as requesting 64-bit operations, (even\n * though the former does not conform to the LFS document), but considering\n * both \"#undef _LARGEFILE64_SOURCE\" and \"#define _LARGEFILE64_SOURCE 0\" as\n * equivalently requesting no 64-bit operations\n */\n#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1\n#  undef _LARGEFILE64_SOURCE\n#endif\n\n#ifndef Z_HAVE_UNISTD_H\n#  ifdef __WATCOMC__\n#    define Z_HAVE_UNISTD_H\n#  endif\n#endif\n#ifndef Z_HAVE_UNISTD_H\n#  if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)\n#    define Z_HAVE_UNISTD_H\n#  endif\n#endif\n#ifndef Z_SOLO\n#  if defined(Z_HAVE_UNISTD_H)\n#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */\n#    ifdef VMS\n#      include <unixio.h>       /* for off_t */\n#    endif\n#    ifndef z_off_t\n#      define z_off_t off_t\n#    endif\n#  endif\n#endif\n\n#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0\n#  define Z_LFS64\n#endif\n\n#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)\n#  define Z_LARGE64\n#endif\n\n#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)\n#  define Z_WANT64\n#endif\n\n#if !defined(SEEK_SET) && !defined(Z_SOLO)\n#  define SEEK_SET        0       /* Seek from beginning of file.  */\n#  define SEEK_CUR        1       /* Seek from current position.  */\n#  define SEEK_END        2       /* Set file pointer to EOF plus \"offset\" */\n#endif\n\n#ifndef z_off_t\n#  define z_off_t long\n#endif\n\n#if !defined(_WIN32) && defined(Z_LARGE64)\n#  define z_off64_t off64_t\n#else\n#  if defined(_WIN32) && !defined(__GNUC__)\n#    define z_off64_t __int64\n#  else\n#    define z_off64_t z_off_t\n#  endif\n#endif\n\n/* MVS linker does not support external names larger than 8 bytes */\n#if defined(__MVS__)\n  #pragma map(deflateInit_,\"DEIN\")\n  #pragma map(deflateInit2_,\"DEIN2\")\n  #pragma map(deflateEnd,\"DEEND\")\n  #pragma map(deflateBound,\"DEBND\")\n  #pragma map(inflateInit_,\"ININ\")\n  #pragma map(inflateInit2_,\"ININ2\")\n  #pragma map(inflateEnd,\"INEND\")\n  #pragma map(inflateSync,\"INSY\")\n  #pragma map(inflateSetDictionary,\"INSEDI\")\n  #pragma map(compressBound,\"CMBND\")\n  #pragma map(inflate_table,\"INTABL\")\n  #pragma map(inflate_fast,\"INFA\")\n  #pragma map(inflate_copyright,\"INCOPY\")\n#endif\n\n#endif /* ZCONF_H */\n"
  },
  {
    "path": "eidos_zlib/zlib.h",
    "content": "/*\n\n\tREVISIONS FOR SLiM\n\n\tThe zlib sources in this directory are a pruned-down version of\n\tthe original zlib 1.3.1 sources.  Please go to http://zlib.net/\n\tfor the original sources.  Here I have removed code needed only\n\tfor inflation, or for anything other than the simple base case\n\tused by SLiM, and have configured for macOS 10.15.3 with the\n\toption \"./configure --zprefix\".\n\n\tBenjamin C. Haller\n\tbhaller@mac.com\n\t16 April 2020 (revisited 18 July 2024)\n\n*/\n\n/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.3.1, January 22nd, 2024\n\n  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n\n#ifndef ZLIB_H\n#define ZLIB_H\n\n#include \"zconf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZLIB_VERSION \"1.3.1.f-slim\"\n#define ZLIB_VERNUM 0x131f\n#define ZLIB_VER_MAJOR 1\n#define ZLIB_VER_MINOR 3\n#define ZLIB_VER_REVISION 1\n#define ZLIB_VER_SUBREVISION 0\n\n/*\n    The 'zlib' compression library provides in-memory compression and\n  decompression functions, including integrity checks of the uncompressed data.\n  This version of the library supports only one compression method (deflation)\n  but other algorithms will be added later and will have the same stream\n  interface.\n\n    Compression can be done in a single step if the buffers are large enough,\n  or can be done by repeated calls of the compression function.  In the latter\n  case, the application must provide more input and/or consume the output\n  (providing more output space) before each call.\n\n    The compressed data format used by default by the in-memory functions is\n  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped\n  around a deflate stream, which is itself documented in RFC 1951.\n\n    The library also supports reading and writing files in gzip (.gz) format\n  with an interface similar to that of stdio using the functions that start\n  with \"gz\".  The gzip format is different from the zlib format.  gzip is a\n  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.\n\n    This library can optionally read and write gzip and raw deflate streams in\n  memory as well.\n\n    The zlib format was designed to be compact and fast for use in memory\n  and on communications channels.  The gzip format was designed for single-\n  file compression on file systems, has a larger header than zlib to maintain\n  directory information, and uses a different, slower check method than zlib.\n\n    The library does not install any signal handler.  The decoder checks\n  the consistency of the compressed data, so the library should never crash\n  even in the case of corrupted input.\n*/\n\ntypedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size);\ntypedef void   (*free_func)(voidpf opaque, voidpf address);\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n    z_const Bytef *next_in;     /* next input byte */\n    uInt     avail_in;  /* number of bytes available at next_in */\n    uLong    total_in;  /* total number of input bytes read so far */\n\n    Bytef    *next_out; /* next output byte will go here */\n    uInt     avail_out; /* remaining free space at next_out */\n    uLong    total_out; /* total number of bytes output so far */\n\n    z_const char *msg;  /* last error message, NULL if no error */\n    struct internal_state FAR *state; /* not visible by applications */\n\n    alloc_func zalloc;  /* used to allocate the internal state */\n    free_func  zfree;   /* used to free the internal state */\n    voidpf     opaque;  /* private data object passed to zalloc and zfree */\n\n    int     data_type;  /* best guess about the data type: binary or text\n                           for deflate, or the decoding state for inflate */\n    uLong   adler;      /* Adler-32 or CRC-32 value of the uncompressed data */\n    uLong   reserved;   /* reserved for future use */\n} z_stream;\n\ntypedef z_stream FAR *z_streamp;\n\n/*\n     gzip header information passed to and from zlib routines.  See RFC 1952\n  for more details on the meanings of these fields.\n*/\ntypedef struct gz_header_s {\n    int     text;       /* true if compressed data believed to be text */\n    uLong   time;       /* modification time */\n    int     xflags;     /* extra flags (not used when writing a gzip file) */\n    int     os;         /* operating system */\n    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */\n    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */\n    uInt    extra_max;  /* space at extra (only when reading header) */\n    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */\n    uInt    name_max;   /* space at name (only when reading header) */\n    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */\n    uInt    comm_max;   /* space at comment (only when reading header) */\n    int     hcrc;       /* true if there was or will be a header crc */\n    int     done;       /* true when done reading gzip header (not used\n                           when writing a gzip file) */\n} gz_header;\n\ntypedef gz_header FAR *gz_headerp;\n\n/*\n     The application must update next_in and avail_in when avail_in has dropped\n   to zero.  It must update next_out and avail_out when avail_out has dropped\n   to zero.  The application must initialize zalloc, zfree and opaque before\n   calling the init function.  All other fields are set by the compression\n   library and must not be updated by the application.\n\n     The opaque value provided by the application will be passed as the first\n   parameter for calls of zalloc and zfree.  This can be useful for custom\n   memory management.  The compression library attaches no meaning to the\n   opaque value.\n\n     zalloc must return Z_NULL if there is not enough memory for the object.\n   If zlib is used in a multi-threaded application, zalloc and zfree must be\n   thread safe.  In that case, zlib is thread-safe.  When zalloc and zfree are\n   Z_NULL on entry to the initialization function, they are set to internal\n   routines that use the standard library functions malloc() and free().\n\n     On 16-bit systems, the functions zalloc and zfree must be able to allocate\n   exactly 65536 bytes, but will not be required to allocate more than this if\n   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers\n   returned by zalloc for objects of exactly 65536 bytes *must* have their\n   offset normalized to zero.  The default allocation function provided by this\n   library ensures this (see zutil.c).  To reduce memory requirements and avoid\n   any allocation of 64K objects, at the expense of compression ratio, compile\n   the library with -DMAX_WBITS=14 (see zconf.h).\n\n     The fields total_in and total_out can be used for statistics or progress\n   reports.  After compression, total_in holds the total size of the\n   uncompressed data and may be saved for use by the decompressor (particularly\n   if the decompressor wants to decompress everything in a single step).\n*/\n\n                        /* constants */\n\n#define Z_NO_FLUSH      0\n#define Z_PARTIAL_FLUSH 1\n#define Z_SYNC_FLUSH    2\n#define Z_FULL_FLUSH    3\n#define Z_FINISH        4\n#define Z_BLOCK         5\n#define Z_TREES         6\n/* Allowed flush values; see deflate() and inflate() below for details */\n\n#define Z_OK            0\n#define Z_STREAM_END    1\n#define Z_NEED_DICT     2\n#define Z_ERRNO        (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR   (-3)\n#define Z_MEM_ERROR    (-4)\n#define Z_BUF_ERROR    (-5)\n#define Z_VERSION_ERROR (-6)\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\n\n#define Z_NO_COMPRESSION         0\n#define Z_BEST_SPEED             1\n#define Z_BEST_COMPRESSION       9\n#define Z_DEFAULT_COMPRESSION  (-1)\n/* compression levels */\n\n#define Z_FILTERED            1\n#define Z_HUFFMAN_ONLY        2\n#define Z_RLE                 3\n#define Z_FIXED               4\n#define Z_DEFAULT_STRATEGY    0\n/* compression strategy; see deflateInit2() below for details */\n\n#define Z_BINARY   0\n#define Z_TEXT     1\n#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */\n#define Z_UNKNOWN  2\n/* Possible values of the data_type field for deflate() */\n\n#define Z_DEFLATED   8\n/* The deflate compression method (the only one supported in this version) */\n\n#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */\n\n#define zlib_version zlibVersion()\n/* for compatibility with versions < 1.0.2 */\n\n\n                        /* basic functions */\n\nZEXTERN const char * ZEXPORT zlibVersion(void);\n/* The application can compare zlibVersion and ZLIB_VERSION for consistency.\n   If the first character differs, the library code actually used is not\n   compatible with the zlib.h header file used by the application.  This check\n   is automatically made by deflateInit and inflateInit.\n */\n\n/*\nZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level);\n\n     Initializes the internal stream state for compression.  The fields\n   zalloc, zfree and opaque must be initialized before by the caller.  If\n   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default\n   allocation functions.  total_in, total_out, adler, and msg are initialized.\n\n     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:\n   1 gives best speed, 9 gives best compression, 0 gives no compression at all\n   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION\n   requests a default compromise between speed and compression (currently\n   equivalent to level 6).\n\n     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if level is not a valid compression level, or\n   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible\n   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null\n   if there is no error message.  deflateInit does not perform any compression:\n   this will be done by deflate().\n*/\n\n\nZEXTERN int ZEXPORT deflate(z_streamp strm, int flush);\n/*\n    deflate compresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n    The detailed semantics are as follows.  deflate performs one or both of the\n  following actions:\n\n  - Compress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), next_in and avail_in are updated and\n    processing will resume at this point for the next call of deflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  This action is forced if the parameter flush is non zero.\n    Forcing flush frequently degrades the compression ratio, so this parameter\n    should be set only when necessary.  Some output may be provided even if\n    flush is zero.\n\n    Before the call of deflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating avail_in or avail_out accordingly; avail_out should\n  never be zero before the call.  The application can consume the compressed\n  output when it wants, for example when the output buffer is full (avail_out\n  == 0), or after each call of deflate().  If deflate returns Z_OK and with\n  zero avail_out, it must be called again after making room in the output\n  buffer because there might be more output pending. See deflatePending(),\n  which can be used if desired to determine whether or not there is more output\n  in that case.\n\n    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to\n  decide how much data to accumulate before producing output, in order to\n  maximize compression.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is\n  flushed to the output buffer and the output is aligned on a byte boundary, so\n  that the decompressor can get all input data available so far.  (In\n  particular avail_in is zero after the call if enough output space has been\n  provided before the call.) Flushing may degrade compression for some\n  compression algorithms and so it should be used only when necessary.  This\n  completes the current deflate block and follows it with an empty stored block\n  that is three bits plus filler bits to the next byte, followed by four bytes\n  (00 00 ff ff).\n\n    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the\n  output buffer, but the output is not aligned to a byte boundary.  All of the\n  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.\n  This completes the current deflate block and follows it with an empty fixed\n  codes block that is 10 bits long.  This assures that enough bytes are output\n  in order for the decompressor to finish the block before the empty fixed\n  codes block.\n\n    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as\n  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to\n  seven bits of the current block are held to be written as the next byte after\n  the next deflate block is completed.  In this case, the decompressor may not\n  be provided enough bits at this point in order to complete decompression of\n  the data provided so far to the compressor.  It may need to wait for the next\n  block to be emitted.  This is for advanced applications that need to control\n  the emission of deflate blocks.\n\n    If flush is set to Z_FULL_FLUSH, all output is flushed as with\n  Z_SYNC_FLUSH, and the compression state is reset so that decompression can\n  restart from this point if previous compressed data has been damaged or if\n  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade\n  compression.\n\n    If deflate returns with avail_out == 0, this function must be called again\n  with the same value of the flush parameter and more output space (updated\n  avail_out), until the flush is complete (deflate returns with non-zero\n  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that\n  avail_out is greater than six when the flush marker begins, in order to avoid\n  repeated flush markers upon calling deflate() again when avail_out == 0.\n\n    If the parameter flush is set to Z_FINISH, pending input is processed,\n  pending output is flushed and deflate returns with Z_STREAM_END if there was\n  enough output space.  If deflate returns with Z_OK or Z_BUF_ERROR, this\n  function must be called again with Z_FINISH and more output space (updated\n  avail_out) but no more input data, until it returns with Z_STREAM_END or an\n  error.  After deflate has returned Z_STREAM_END, the only possible operations\n  on the stream are deflateReset or deflateEnd.\n\n    Z_FINISH can be used in the first deflate call after deflateInit if all the\n  compression is to be done in a single step.  In order to complete in one\n  call, avail_out must be at least the value returned by deflateBound (see\n  below).  Then deflate is guaranteed to return Z_STREAM_END.  If not enough\n  output space is provided, deflate will not return Z_STREAM_END, and it must\n  be called again as described above.\n\n    deflate() sets strm->adler to the Adler-32 checksum of all input read\n  so far (that is, total_in bytes).  If a gzip stream is being generated, then\n  strm->adler will be the CRC-32 checksum of the input read so far.  (See\n  deflateInit2 below.)\n\n    deflate() may update strm->data_type if it can make a good guess about\n  the input data type (Z_BINARY or Z_TEXT).  If in doubt, the data is\n  considered binary.  This field is only for information purposes and does not\n  affect the compression algorithm in any manner.\n\n    deflate() returns Z_OK if some progress has been made (more input\n  processed or more output produced), Z_STREAM_END if all input has been\n  consumed and all output has been produced (only when flush is set to\n  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example\n  if next_in or next_out was Z_NULL or the state was inadvertently written over\n  by the application), or Z_BUF_ERROR if no progress is possible (for example\n  avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not fatal, and\n  deflate() can be called again with more input and more output space to\n  continue compressing.\n*/\n\n\nZEXTERN int ZEXPORT deflateEnd(z_streamp strm);\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the\n   stream state was inconsistent, Z_DATA_ERROR if the stream was freed\n   prematurely (some input or output was discarded).  In the error case, msg\n   may be set but then points to a static string (which must not be\n   deallocated).\n*/\n\n\n/*\nZEXTERN int ZEXPORT inflateInit(z_streamp strm);\n\n     Initializes the internal stream state for decompression.  The fields\n   next_in, avail_in, zalloc, zfree and opaque must be initialized before by\n   the caller.  In the current version of inflate, the provided input is not\n   read or consumed.  The allocation of a sliding window will be deferred to\n   the first call of inflate (if the decompression does not complete on the\n   first call).  If zalloc and zfree are set to Z_NULL, inflateInit updates\n   them to use default allocation functions.  total_in, total_out, adler, and\n   msg are initialized.\n\n     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit does not perform any decompression.\n   Actual decompression will be done by inflate().  So next_in, and avail_in,\n   next_out, and avail_out are unused and unchanged.  The current\n   implementation of inflateInit() does not process any header information --\n   that is deferred until inflate() is called.\n*/\n\n\nZEXTERN int ZEXPORT inflate(z_streamp strm, int flush);\n/*\n    inflate decompresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n  The detailed semantics are as follows.  inflate performs one or both of the\n  following actions:\n\n  - Decompress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), then next_in and avail_in are updated\n    accordingly, and processing will resume at this point for the next call of\n    inflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  inflate() provides as much output as possible, until there is\n    no more input data or no more space in the output buffer (see below about\n    the flush parameter).\n\n    Before the call of inflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating the next_* and avail_* values accordingly.  If the\n  caller of inflate() does not provide both available input and available\n  output space, it is possible that there will be no progress made.  The\n  application can consume the uncompressed output when it wants, for example\n  when the output buffer is full (avail_out == 0), or after each call of\n  inflate().  If inflate returns Z_OK and with zero avail_out, it must be\n  called again after making room in the output buffer because there might be\n  more output pending.\n\n    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,\n  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much\n  output as possible to the output buffer.  Z_BLOCK requests that inflate()\n  stop if and when it gets to the next deflate block boundary.  When decoding\n  the zlib or gzip format, this will cause inflate() to return immediately\n  after the header and before the first block.  When doing a raw inflate,\n  inflate() will go ahead and process the first block, and will return when it\n  gets to the end of that block, or when it runs out of data.\n\n    The Z_BLOCK option assists in appending to or combining deflate streams.\n  To assist in this, on return inflate() always sets strm->data_type to the\n  number of unused bits in the last byte taken from strm->next_in, plus 64 if\n  inflate() is currently decoding the last block in the deflate stream, plus\n  128 if inflate() returned immediately after decoding an end-of-block code or\n  decoding the complete header up to just before the first byte of the deflate\n  stream.  The end-of-block will not be indicated until all of the uncompressed\n  data from that block has been written to strm->next_out.  The number of\n  unused bits may in general be greater than seven, except when bit 7 of\n  data_type is set, in which case the number of unused bits will be less than\n  eight.  data_type is set as noted here every time inflate() returns for all\n  flush options, and so can be used to determine the amount of currently\n  consumed input in bits.\n\n    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the\n  end of each deflate block header is reached, before any actual data in that\n  block is decoded.  This allows the caller to determine the length of the\n  deflate block header for later use in random access within a deflate block.\n  256 is added to the value of strm->data_type when inflate() returns\n  immediately after reaching the end of the deflate block header.\n\n    inflate() should normally be called until it returns Z_STREAM_END or an\n  error.  However if all decompression is to be performed in a single step (a\n  single call of inflate), the parameter flush should be set to Z_FINISH.  In\n  this case all pending input is processed and all pending output is flushed;\n  avail_out must be large enough to hold all of the uncompressed data for the\n  operation to complete.  (The size of the uncompressed data may have been\n  saved by the compressor for this purpose.)  The use of Z_FINISH is not\n  required to perform an inflation in one step.  However it may be used to\n  inform inflate that a faster approach can be used for the single inflate()\n  call.  Z_FINISH also informs inflate to not maintain a sliding window if the\n  stream completes, which reduces inflate's memory footprint.  If the stream\n  does not complete, either because not all of the stream is provided or not\n  enough output space is provided, then a sliding window will be allocated and\n  inflate() can be called again to continue the operation as if Z_NO_FLUSH had\n  been used.\n\n     In this implementation, inflate() always flushes as much output as\n  possible to the output buffer, and always uses the faster approach on the\n  first call.  So the effects of the flush parameter in this implementation are\n  on the return value of inflate() as noted below, when inflate() returns early\n  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of\n  memory for a sliding window when Z_FINISH is used.\n\n     If a preset dictionary is needed after this call (see inflateSetDictionary\n  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary\n  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets\n  strm->adler to the Adler-32 checksum of all output produced so far (that is,\n  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described\n  below.  At the end of the stream, inflate() checks that its computed Adler-32\n  checksum is equal to that saved by the compressor and returns Z_STREAM_END\n  only if the checksum is correct.\n\n    inflate() can decompress and check either zlib-wrapped or gzip-wrapped\n  deflate data.  The header type is detected automatically, if requested when\n  initializing with inflateInit2().  Any information contained in the gzip\n  header is not retained unless inflateGetHeader() is used.  When processing\n  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output\n  produced so far.  The CRC-32 is checked against the gzip trailer, as is the\n  uncompressed length, modulo 2^32.\n\n    inflate() returns Z_OK if some progress has been made (more input processed\n  or more output produced), Z_STREAM_END if the end of the compressed data has\n  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was\n  corrupted (input stream not conforming to the zlib format or incorrect check\n  value, in which case strm->msg points to a string with a more specific\n  error), Z_STREAM_ERROR if the stream structure was inconsistent (for example\n  next_in or next_out was Z_NULL, or the state was inadvertently written over\n  by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR\n  if no progress was possible or if there was not enough room in the output\n  buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and\n  inflate() can be called again with more input and more output space to\n  continue decompressing.  If Z_DATA_ERROR is returned, the application may\n  then call inflateSync() to look for a good compression block if a partial\n  recovery of the data is to be attempted.\n*/\n\n\nZEXTERN int ZEXPORT inflateEnd(z_streamp strm);\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state\n   was inconsistent.\n*/\n\n\n                        /* Advanced functions */\n\n/*\n    The following functions are needed only in some special applications.\n*/\n\n/*\nZEXTERN int ZEXPORT deflateInit2(z_streamp strm,\n                                 int level,\n                                 int method,\n                                 int windowBits,\n                                 int memLevel,\n                                 int strategy);\n\n     This is another version of deflateInit with more compression options.  The\n   fields zalloc, zfree and opaque must be initialized before by the caller.\n\n     The method parameter is the compression method.  It must be Z_DEFLATED in\n   this version of the library.\n\n     The windowBits parameter is the base two logarithm of the window size\n   (the size of the history buffer).  It should be in the range 8..15 for this\n   version of the library.  Larger values of this parameter result in better\n   compression at the expense of memory usage.  The default value is 15 if\n   deflateInit is used instead.\n\n     For the current implementation of deflate(), a windowBits value of 8 (a\n   window size of 256 bytes) is not supported.  As a result, a request for 8\n   will result in 9 (a 512-byte window).  In that case, providing 8 to\n   inflateInit2() will result in an error when the zlib header with 9 is\n   checked against the initialization of inflate().  The remedy is to not use 8\n   with deflateInit2() with this initialization, or at least in that case use 9\n   with inflateInit2().\n\n     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits\n   determines the window size.  deflate() will then generate raw deflate data\n   with no zlib header or trailer, and will not compute a check value.\n\n     windowBits can also be greater than 15 for optional gzip encoding.  Add\n   16 to windowBits to write a simple gzip header and trailer around the\n   compressed data instead of a zlib wrapper.  The gzip header will have no\n   file name, no extra data, no comment, no modification time (set to zero), no\n   header crc, and the operating system will be set to the appropriate value,\n   if the operating system was determined at compile time.  If a gzip stream is\n   being written, strm->adler is a CRC-32 instead of an Adler-32.\n\n     For raw deflate or gzip encoding, a request for a 256-byte window is\n   rejected as invalid, since only the zlib header provides a means of\n   transmitting the window size to the decompressor.\n\n     The memLevel parameter specifies how much memory should be allocated\n   for the internal compression state.  memLevel=1 uses minimum memory but is\n   slow and reduces compression ratio; memLevel=9 uses maximum memory for\n   optimal speed.  The default value is 8.  See zconf.h for total memory usage\n   as a function of windowBits and memLevel.\n\n     The strategy parameter is used to tune the compression algorithm.  Use the\n   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a\n   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no\n   string match), or Z_RLE to limit match distances to one (run-length\n   encoding).  Filtered data consists mostly of small values with a somewhat\n   random distribution.  In this case, the compression algorithm is tuned to\n   compress them better.  The effect of Z_FILTERED is to force more Huffman\n   coding and less string matching; it is somewhat intermediate between\n   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as\n   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The\n   strategy parameter only affects the compression ratio but not the\n   correctness of the compressed output even if it is not set appropriately.\n   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler\n   decoder for special applications.\n\n     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid\n   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is\n   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is\n   set to null if there is no error message.  deflateInit2 does not perform any\n   compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm,\n                                         const Bytef *dictionary,\n                                         uInt  dictLength);\n/*\n     Initializes the compression dictionary from the given byte sequence\n   without producing any compressed output.  When using the zlib format, this\n   function must be called immediately after deflateInit, deflateInit2 or\n   deflateReset, and before any call of deflate.  When doing raw deflate, this\n   function must be called either before any call of deflate, or immediately\n   after the completion of a deflate block, i.e. after all input has been\n   consumed and all output has been delivered when using any of the flush\n   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The\n   compressor and decompressor must use exactly the same dictionary (see\n   inflateSetDictionary).\n\n     The dictionary should consist of strings (byte sequences) that are likely\n   to be encountered later in the data to be compressed, with the most commonly\n   used strings preferably put towards the end of the dictionary.  Using a\n   dictionary is most useful when the data to be compressed is short and can be\n   predicted with good accuracy; the data can then be compressed better than\n   with the default empty dictionary.\n\n     Depending on the size of the compression data structures selected by\n   deflateInit or deflateInit2, a part of the dictionary may in effect be\n   discarded, for example if the dictionary is larger than the window size\n   provided in deflateInit or deflateInit2.  Thus the strings most likely to be\n   useful should be put at the end of the dictionary, not at the front.  In\n   addition, the current implementation of deflate will use at most the window\n   size minus 262 bytes of the provided dictionary.\n\n     Upon return of this function, strm->adler is set to the Adler-32 value\n   of the dictionary; the decompressor may later use this value to determine\n   which dictionary has been used by the compressor.  (The Adler-32 value\n   applies to the whole dictionary even if only a subset of the dictionary is\n   actually used by the compressor.) If a raw deflate was requested, then the\n   Adler-32 value is not computed and strm->adler is not set.\n\n     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent (for example if deflate has already been called for this stream\n   or if not at a block boundary for raw deflate).  deflateSetDictionary does\n   not perform any compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm,\n                                         Bytef *dictionary,\n                                         uInt  *dictLength);\n/*\n     Returns the sliding dictionary being maintained by deflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If deflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similarly, if dictLength is Z_NULL, then it is not set.\n\n     deflateGetDictionary() may return a length less than the window size, even\n   when more than the window size in input has been provided. It may return up\n   to 258 bytes less in that case, due to how zlib's implementation of deflate\n   manages the sliding window and lookahead for matches, where matches can be\n   up to 258 bytes long. If the application needs the last window-size bytes of\n   input, then that would need to be saved by the application outside of zlib.\n\n     deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateCopy(z_streamp dest,\n                                z_streamp source);\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when several compression strategies will be\n   tried, for example when there are several ways of pre-processing the input\n   data with a filter.  The streams that will be discarded should then be freed\n   by calling deflateEnd.  Note that deflateCopy duplicates the internal\n   compression state which can be quite large, so this strategy is slow and can\n   consume lots of memory.\n\n     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT deflateReset(z_streamp strm);\n/*\n     This function is equivalent to deflateEnd followed by deflateInit, but\n   does not free and reallocate the internal compression state.  The stream\n   will leave the compression level and any other attributes that may have been\n   set unchanged.  total_in, total_out, adler, and msg are initialized.\n\n     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT deflateParams(z_streamp strm,\n                                  int level,\n                                  int strategy);\n/*\n     Dynamically update the compression level and compression strategy.  The\n   interpretation of level and strategy is as in deflateInit2().  This can be\n   used to switch between compression and straight copy of the input data, or\n   to switch to a different kind of input data requiring a different strategy.\n   If the compression approach (which is a function of the level) or the\n   strategy is changed, and if there have been any deflate() calls since the\n   state was initialized or reset, then the input available so far is\n   compressed with the old level and strategy using deflate(strm, Z_BLOCK).\n   There are three approaches for the compression levels 0, 1..3, and 4..9\n   respectively.  The new level and strategy will take effect at the next call\n   of deflate().\n\n     If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does\n   not have enough output space to complete, then the parameter change will not\n   take effect.  In this case, deflateParams() can be called again with the\n   same parameters and more output space to try again.\n\n     In order to assure a change in the parameters on the first try, the\n   deflate stream should be flushed using deflate() with Z_BLOCK or other flush\n   request until strm.avail_out is not zero, before calling deflateParams().\n   Then no more input data should be provided before the deflateParams() call.\n   If this is done, the old level and strategy will be applied to the data\n   compressed before deflateParams(), and the new level and strategy will be\n   applied to the data compressed after deflateParams().\n\n     deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream\n   state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if\n   there was not enough output space to complete the compression of the\n   available input data before a change in the strategy or approach.  Note that\n   in the case of a Z_BUF_ERROR, the parameters are not changed.  A return\n   value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be\n   retried with more output space.\n*/\n\nZEXTERN int ZEXPORT deflateTune(z_streamp strm,\n                                int good_length,\n                                int max_lazy,\n                                int nice_length,\n                                int max_chain);\n/*\n     Fine tune deflate's internal compression parameters.  This should only be\n   used by someone who understands the algorithm used by zlib's deflate for\n   searching for the best matching string, and even then only by the most\n   fanatic optimizer trying to squeeze out the last compressed bit for their\n   specific input data.  Read the deflate.c source code for the meaning of the\n   max_lazy, good_length, nice_length, and max_chain parameters.\n\n     deflateTune() can be called after deflateInit() or deflateInit2(), and\n   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.\n */\n\nZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,\n                                   uLong sourceLen);\n/*\n     deflateBound() returns an upper bound on the compressed size after\n   deflation of sourceLen bytes.  It must be called after deflateInit() or\n   deflateInit2(), and after deflateSetHeader(), if used.  This would be used\n   to allocate an output buffer for deflation in a single pass, and so would be\n   called before deflate().  If that first deflate() call is provided the\n   sourceLen input bytes, an output buffer allocated to the size returned by\n   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed\n   to return Z_STREAM_END.  Note that it is possible for the compressed size to\n   be larger than the value returned by deflateBound() if flush options other\n   than Z_FINISH or Z_NO_FLUSH are used.\n*/\n\nZEXTERN int ZEXPORT deflatePending(z_streamp strm,\n                                   unsigned *pending,\n                                   int *bits);\n/*\n     deflatePending() returns the number of bytes and bits of output that have\n   been generated, but not yet provided in the available output.  The bytes not\n   provided would be due to the available output space having being consumed.\n   The number of bits of output not provided are between 0 and 7, where they\n   await more bits to join them in order to fill out a full byte.  If pending\n   or bits are Z_NULL, then those values are not set.\n\n     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n */\n\nZEXTERN int ZEXPORT deflatePrime(z_streamp strm,\n                                 int bits,\n                                 int value);\n/*\n     deflatePrime() inserts bits in the deflate output stream.  The intent\n   is that this function is used to start off the deflate output with the bits\n   leftover from a previous deflate stream when appending to it.  As such, this\n   function can only be used for raw deflate, and must be used before the first\n   deflate() call after a deflateInit2() or deflateReset().  bits must be less\n   than or equal to 16, and that many of the least significant bits of value\n   will be inserted in the output.\n\n     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough\n   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm,\n                                     gz_headerp head);\n/*\n     deflateSetHeader() provides gzip header information for when a gzip\n   stream is requested by deflateInit2().  deflateSetHeader() may be called\n   after deflateInit2() or deflateReset() and before the first call of\n   deflate().  The text, time, os, extra field, name, and comment information\n   in the provided gz_header structure are written to the gzip header (xflag is\n   ignored -- the extra flags are set according to the compression level).  The\n   caller must assure that, if not Z_NULL, name and comment are terminated with\n   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are\n   available there.  If hcrc is true, a gzip header crc is included.  Note that\n   the current versions of the command-line version of gzip (up through version\n   1.3.x) do not support header crc's, and will report that it is a \"multi-part\n   gzip file\" and give up.\n\n     If deflateSetHeader is not used, the default gzip header has text false,\n   the time set to zero, and os set to the current operating system, with no\n   extra, name, or comment fields.  The gzip header is returned to the default\n   state by deflateReset().\n\n     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateInit2(z_streamp strm,\n                                 int windowBits);\n\n     This is another version of inflateInit with an extra parameter.  The\n   fields next_in, avail_in, zalloc, zfree and opaque must be initialized\n   before by the caller.\n\n     The windowBits parameter is the base two logarithm of the maximum window\n   size (the size of the history buffer).  It should be in the range 8..15 for\n   this version of the library.  The default value is 15 if inflateInit is used\n   instead.  windowBits must be greater than or equal to the windowBits value\n   provided to deflateInit2() while compressing, or it must be equal to 15 if\n   deflateInit2() was not used.  If a compressed stream with a larger window\n   size is given as input, inflate() will return with the error code\n   Z_DATA_ERROR instead of trying to allocate a larger window.\n\n     windowBits can also be zero to request that inflate use the window size in\n   the zlib header of the compressed stream.\n\n     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits\n   determines the window size.  inflate() will then process raw deflate data,\n   not looking for a zlib or gzip header, not generating a check value, and not\n   looking for any check values for comparison at the end of the stream.  This\n   is for use with other formats that use the deflate compressed data format\n   such as zip.  Those formats provide their own check values.  If a custom\n   format is developed using the raw deflate format for compressed data, it is\n   recommended that a check value such as an Adler-32 or a CRC-32 be applied to\n   the uncompressed data as is done in the zlib, gzip, and zip formats.  For\n   most applications, the zlib format should be used as is.  Note that comments\n   above on the use in deflateInit2() applies to the magnitude of windowBits.\n\n     windowBits can also be greater than 15 for optional gzip decoding.  Add\n   32 to windowBits to enable zlib and gzip decoding with automatic header\n   detection, or add 16 to decode only the gzip format (the zlib format will\n   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a\n   CRC-32 instead of an Adler-32.  Unlike the gunzip utility and gzread() (see\n   below), inflate() will *not* automatically decode concatenated gzip members.\n   inflate() will return Z_STREAM_END at the end of the gzip member.  The state\n   would need to be reset to continue decoding a subsequent gzip member.  This\n   *must* be done if there is more data after a gzip member, in order for the\n   decompression to be compliant with the gzip standard (RFC 1952).\n\n     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit2 does not perform any decompression\n   apart from possibly reading the zlib header if present: actual decompression\n   will be done by inflate().  (So next_in and avail_in may be modified, but\n   next_out and avail_out are unused and unchanged.) The current implementation\n   of inflateInit2() does not process any header information -- that is\n   deferred until inflate() is called.\n*/\n\nZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm,\n                                         const Bytef *dictionary,\n                                         uInt  dictLength);\n/*\n     Initializes the decompression dictionary from the given uncompressed byte\n   sequence.  This function must be called immediately after a call of inflate,\n   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor\n   can be determined from the Adler-32 value returned by that call of inflate.\n   The compressor and decompressor must use exactly the same dictionary (see\n   deflateSetDictionary).  For raw inflate, this function can be called at any\n   time to set the dictionary.  If the provided dictionary is smaller than the\n   window and there is already data in the window, then the provided dictionary\n   will amend what's there.  The application must insure that the dictionary\n   that was used for compression is provided.\n\n     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n   expected one (incorrect Adler-32 value).  inflateSetDictionary does not\n   perform any decompression: this will be done by subsequent calls of\n   inflate().\n*/\n\nZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm,\n                                         Bytef *dictionary,\n                                         uInt  *dictLength);\n/*\n     Returns the sliding dictionary being maintained by inflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If inflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similarly, if dictLength is Z_NULL, then it is not set.\n\n     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateSync(z_streamp strm);\n/*\n     Skips invalid compressed data until a possible full flush point (see above\n   for the description of deflate with Z_FULL_FLUSH) can be found, or until all\n   available input is skipped.  No output is provided.\n\n     inflateSync searches for a 00 00 FF FF pattern in the compressed data.\n   All full flush points have this pattern, but not all occurrences of this\n   pattern are full flush points.\n\n     inflateSync returns Z_OK if a possible full flush point has been found,\n   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point\n   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.\n   In the success case, the application may save the current value of total_in\n   which indicates where valid compressed data was found.  In the error case,\n   the application may repeatedly call inflateSync, providing more input each\n   time, until success or end of the input data.\n*/\n\nZEXTERN int ZEXPORT inflateCopy(z_streamp dest,\n                                z_streamp source);\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when randomly accessing a large stream.  The\n   first pass through the stream can periodically record the inflate state,\n   allowing restarting inflate at those points when randomly accessing the\n   stream.\n\n     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT inflateReset(z_streamp strm);\n/*\n     This function is equivalent to inflateEnd followed by inflateInit,\n   but does not free and reallocate the internal decompression state.  The\n   stream will keep attributes that may have been set by inflateInit2.\n   total_in, total_out, adler, and msg are initialized.\n\n     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT inflateReset2(z_streamp strm,\n                                  int windowBits);\n/*\n     This function is the same as inflateReset, but it also permits changing\n   the wrap and window size requests.  The windowBits parameter is interpreted\n   the same as it is for inflateInit2.  If the window size is changed, then the\n   memory allocated for the window is freed, and the window will be reallocated\n   by inflate() if needed.\n\n     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL), or if\n   the windowBits parameter is invalid.\n*/\n\nZEXTERN int ZEXPORT inflatePrime(z_streamp strm,\n                                 int bits,\n                                 int value);\n/*\n     This function inserts bits in the inflate input stream.  The intent is\n   that this function is used to start inflating at a bit position in the\n   middle of a byte.  The provided bits will be used before any bytes are used\n   from next_in.  This function should only be used with raw inflate, and\n   should be used before the first inflate() call after inflateInit2() or\n   inflateReset().  bits must be less than or equal to 16, and that many of the\n   least significant bits of value will be inserted in the input.\n\n     If bits is negative, then the input stream bit buffer is emptied.  Then\n   inflatePrime() can be called again to put bits in the buffer.  This is used\n   to clear out bits leftover after feeding inflate a block description prior\n   to feeding inflate codes.\n\n     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\nZEXTERN long ZEXPORT inflateMark(z_streamp strm);\n/*\n     This function returns two values, one in the lower 16 bits of the return\n   value, and the other in the remaining upper bits, obtained by shifting the\n   return value down 16 bits.  If the upper value is -1 and the lower value is\n   zero, then inflate() is currently decoding information outside of a block.\n   If the upper value is -1 and the lower value is non-zero, then inflate is in\n   the middle of a stored block, with the lower value equaling the number of\n   bytes from the input remaining to copy.  If the upper value is not -1, then\n   it is the number of bits back from the current bit position in the input of\n   the code (literal or length/distance pair) currently being processed.  In\n   that case the lower value is the number of bytes already emitted for that\n   code.\n\n     A code is being processed if inflate is waiting for more input to complete\n   decoding of the code, or if it has completed decoding but is waiting for\n   more output space to write the literal or match data.\n\n     inflateMark() is used to mark locations in the input data for random\n   access, which may be at bit positions, and to note those cases where the\n   output of a code may span boundaries of random access blocks.  The current\n   location in the input stream can be determined from avail_in and data_type\n   as noted in the description for the Z_BLOCK flush parameter for inflate.\n\n     inflateMark returns the value noted above, or -65536 if the provided\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm,\n                                     gz_headerp head);\n/*\n     inflateGetHeader() requests that gzip header information be stored in the\n   provided gz_header structure.  inflateGetHeader() may be called after\n   inflateInit2() or inflateReset(), and before the first call of inflate().\n   As inflate() processes the gzip stream, head->done is zero until the header\n   is completed, at which time head->done is set to one.  If a zlib stream is\n   being decoded, then head->done is set to -1 to indicate that there will be\n   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be\n   used to force inflate() to return immediately after header processing is\n   complete and before any actual data is decompressed.\n\n     The text, time, xflags, and os fields are filled in with the gzip header\n   contents.  hcrc is set to true if there is a header CRC.  (The header CRC\n   was valid if done is set to one.) If extra is not Z_NULL, then extra_max\n   contains the maximum number of bytes to write to extra.  Once done is true,\n   extra_len contains the actual extra field length, and extra contains the\n   extra field, or that field truncated if extra_max is less than extra_len.\n   If name is not Z_NULL, then up to name_max characters are written there,\n   terminated with a zero unless the length is greater than name_max.  If\n   comment is not Z_NULL, then up to comm_max characters are written there,\n   terminated with a zero unless the length is greater than comm_max.  When any\n   of extra, name, or comment are not Z_NULL and the respective field is not\n   present in the header, then that field is set to Z_NULL to signal its\n   absence.  This allows the use of deflateSetHeader() with the returned\n   structure to duplicate the header.  However if those fields are set to\n   allocated memory, then the application will need to save those pointers\n   elsewhere so that they can be eventually freed.\n\n     If inflateGetHeader is not used, then the header information is simply\n   discarded.  The header is always checked for validity, including the header\n   CRC if present.  inflateReset() will reset the process to discard the header\n   information.  The application would need to call inflateGetHeader() again to\n   retrieve the header from the next gzip stream.\n\n     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits,\n                                    unsigned char FAR *window);\n\n     Initialize the internal stream state for decompression using inflateBack()\n   calls.  The fields zalloc, zfree and opaque in strm must be initialized\n   before the call.  If zalloc and zfree are Z_NULL, then the default library-\n   derived memory allocation routines are used.  windowBits is the base two\n   logarithm of the window size, in the range 8..15.  window is a caller\n   supplied buffer of that size.  Except for special applications where it is\n   assured that deflate was used with small window sizes, windowBits must be 15\n   and a 32K byte window must be supplied to be able to decompress general\n   deflate streams.\n\n     See inflateBack() for the usage of these routines.\n\n     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of\n   the parameters are invalid, Z_MEM_ERROR if the internal state could not be\n   allocated, or Z_VERSION_ERROR if the version of the library does not match\n   the version of the header file.\n*/\n\ntypedef unsigned (*in_func)(void FAR *,\n                            z_const unsigned char FAR * FAR *);\ntypedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned);\n\nZEXTERN int ZEXPORT inflateBack(z_streamp strm,\n                                in_func in, void FAR *in_desc,\n                                out_func out, void FAR *out_desc);\n/*\n     inflateBack() does a raw inflate with a single call using a call-back\n   interface for input and output.  This is potentially more efficient than\n   inflate() for file i/o applications, in that it avoids copying between the\n   output and the sliding window by simply making the window itself the output\n   buffer.  inflate() can be faster on modern CPUs when used with large\n   buffers.  inflateBack() trusts the application to not change the output\n   buffer passed by the output function, at least until inflateBack() returns.\n\n     inflateBackInit() must be called first to allocate the internal state\n   and to initialize the state with the user-provided window buffer.\n   inflateBack() may then be used multiple times to inflate a complete, raw\n   deflate stream with each call.  inflateBackEnd() is then called to free the\n   allocated state.\n\n     A raw deflate stream is one with no zlib or gzip header or trailer.\n   This routine would normally be used in a utility that reads zip or gzip\n   files and writes out uncompressed files.  The utility would decode the\n   header and process the trailer on its own, hence this routine expects only\n   the raw deflate stream to decompress.  This is different from the default\n   behavior of inflate(), which expects a zlib header and trailer around the\n   deflate stream.\n\n     inflateBack() uses two subroutines supplied by the caller that are then\n   called by inflateBack() for input and output.  inflateBack() calls those\n   routines until it reads a complete deflate stream and writes out all of the\n   uncompressed data, or until it encounters an error.  The function's\n   parameters and return types are defined above in the in_func and out_func\n   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the\n   number of bytes of provided input, and a pointer to that input in buf.  If\n   there is no input available, in() must return zero -- buf is ignored in that\n   case -- and inflateBack() will return a buffer error.  inflateBack() will\n   call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].\n   out() should return zero on success, or non-zero on failure.  If out()\n   returns non-zero, inflateBack() will return with an error.  Neither in() nor\n   out() are permitted to change the contents of the window provided to\n   inflateBackInit(), which is also the buffer that out() uses to write from.\n   The length written by out() will be at most the window size.  Any non-zero\n   amount of input may be provided by in().\n\n     For convenience, inflateBack() can be provided input on the first call by\n   setting strm->next_in and strm->avail_in.  If that input is exhausted, then\n   in() will be called.  Therefore strm->next_in must be initialized before\n   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called\n   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in\n   must also be initialized, and then if strm->avail_in is not zero, input will\n   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].\n\n     The in_desc and out_desc parameters of inflateBack() is passed as the\n   first parameter of in() and out() respectively when they are called.  These\n   descriptors can be optionally used to pass any information that the caller-\n   supplied in() and out() functions need to do their job.\n\n     On return, inflateBack() will set strm->next_in and strm->avail_in to\n   pass back any unused input that was provided by the last in() call.  The\n   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR\n   if in() or out() returned an error, Z_DATA_ERROR if there was a format error\n   in the deflate stream (in which case strm->msg is set to indicate the nature\n   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.\n   In the case of Z_BUF_ERROR, an input or output error can be distinguished\n   using strm->next_in which will be Z_NULL only if in() returned an error.  If\n   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning\n   non-zero.  (in() will always be called before out(), so strm->next_in is\n   assured to be defined if out() returns non-zero.)  Note that inflateBack()\n   cannot return Z_OK.\n*/\n\nZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm);\n/*\n     All memory allocated by inflateBackInit() is freed.\n\n     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream\n   state was inconsistent.\n*/\n\nZEXTERN uLong ZEXPORT zlibCompileFlags(void);\n/* Return flags indicating compile-time options.\n\n    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:\n     1.0: size of uInt\n     3.2: size of uLong\n     5.4: size of voidpf (pointer)\n     7.6: size of z_off_t\n\n    Compiler, assembler, and debug options:\n     8: ZLIB_DEBUG\n     9: ASMV or ASMINF -- use ASM code\n     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention\n     11: 0 (reserved)\n\n    One-time table building (smaller code, but not thread-safe if true):\n     12: BUILDFIXED -- build static block decoding tables when needed\n     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed\n     14,15: 0 (reserved)\n\n    Library content (indicates missing functionality):\n     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking\n                          deflate code when not needed)\n     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect\n                    and decode gzip streams (to avoid linking crc code)\n     18-19: 0 (reserved)\n\n    Operation variations (changes in library functionality):\n     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate\n     21: FASTEST -- deflate algorithm with only one, lowest compression level\n     22,23: 0 (reserved)\n\n    The sprintf variant used by gzprintf (zero is best):\n     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format\n     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!\n     26: 0 = returns value, 1 = void -- 1 means inferred string length returned\n\n    Remainder:\n     27-31: 0 (reserved)\n */\n\n#ifndef Z_SOLO\n\n                        /* utility functions */\n\n/*\n     The following utility functions are implemented on top of the basic\n   stream-oriented functions.  To simplify the interface, some default options\n   are assumed (compression level and memory usage, standard memory allocation\n   functions).  The source code of these utility functions can be modified if\n   you need special options.\n*/\n\nZEXTERN int ZEXPORT compress(Bytef *dest,   uLongf *destLen,\n                             const Bytef *source, uLong sourceLen);\n/*\n     Compresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.  compress() is equivalent to compress2() with a level\n   parameter of Z_DEFAULT_COMPRESSION.\n\n     compress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer.\n*/\n\nZEXTERN int ZEXPORT compress2(Bytef *dest,   uLongf *destLen,\n                              const Bytef *source, uLong sourceLen,\n                              int level);\n/*\n     Compresses the source buffer into the destination buffer.  The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer.  Upon entry, destLen is the total size of the\n   destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\n\nZEXTERN uLong ZEXPORT compressBound(uLong sourceLen);\n/*\n     compressBound() returns an upper bound on the compressed size after\n   compress() or compress2() on sourceLen bytes.  It would be used before a\n   compress() or compress2() call to allocate the destination buffer.\n*/\n\nZEXTERN int ZEXPORT uncompress(Bytef *dest,   uLongf *destLen,\n                               const Bytef *source, uLong sourceLen);\n/*\n     Decompresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be large enough to hold the entire\n   uncompressed data.  (The size of the uncompressed data must have been saved\n   previously by the compressor and transmitted to the decompressor by some\n   mechanism outside the scope of this compression library.) Upon exit, destLen\n   is the actual size of the uncompressed data.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In\n   the case where there is not enough room, uncompress() will fill the output\n   buffer with the uncompressed data up to that point.\n*/\n\nZEXTERN int ZEXPORT uncompress2(Bytef *dest,   uLongf *destLen,\n                                const Bytef *source, uLong *sourceLen);\n/*\n     Same as uncompress, except that sourceLen is a pointer, where the\n   length of the source is *sourceLen.  On return, *sourceLen is the number of\n   source bytes consumed.\n*/\n\n                        /* gzip file access functions */\n\n/*\n     This library supports reading and writing files in gzip (.gz) format with\n   an interface similar to that of stdio, using the functions that start with\n   \"gz\".  The gzip format is different from the zlib format.  gzip is a gzip\n   wrapper, documented in RFC 1952, wrapped around a deflate stream.\n*/\n\ntypedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */\n\n/*\nZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);\n\n     Open the gzip (.gz) file at path for reading and decompressing, or\n   compressing and writing.  The mode parameter is as in fopen (\"rb\" or \"wb\")\n   but can also include a compression level (\"wb9\") or a strategy: 'f' for\n   filtered data as in \"wb6f\", 'h' for Huffman-only compression as in \"wb1h\",\n   'R' for run-length encoding as in \"wb1R\", or 'F' for fixed code compression\n   as in \"wb9F\".  (See the description of deflateInit2 for more information\n   about the strategy parameter.)  'T' will request transparent writing or\n   appending with no compression and not using the gzip format.\n\n     \"a\" can be used instead of \"w\" to request that the gzip stream that will\n   be written be appended to the file.  \"+\" will result in an error, since\n   reading and writing to the same gzip file is not supported.  The addition of\n   \"x\" when writing will create the file exclusively, which fails if the file\n   already exists.  On systems that support it, the addition of \"e\" when\n   reading or writing will set the flag to close the file on an execve() call.\n\n     These functions, as well as gzip, will read and decode a sequence of gzip\n   streams in a file.  The append function of gzopen() can be used to create\n   such a file.  (Also see gzflush() for another way to do this.)  When\n   appending, gzopen does not test whether the file begins with a gzip stream,\n   nor does it look for the end of the gzip streams to begin appending.  gzopen\n   will simply append a gzip stream to the existing file.\n\n     gzopen can be used to read a file which is not in gzip format; in this\n   case gzread will directly read from the file without decompression.  When\n   reading, this will be detected automatically by looking for the magic two-\n   byte gzip header.\n\n     gzopen returns NULL if the file could not be opened, if there was\n   insufficient memory to allocate the gzFile state, or if an invalid mode was\n   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).\n   errno can be checked to determine if the reason gzopen failed was that the\n   file could not be opened.\n*/\n\nZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);\n/*\n     Associate a gzFile with the file descriptor fd.  File descriptors are\n   obtained from calls like open, dup, creat, pipe or fileno (if the file has\n   been previously opened with fopen).  The mode parameter is as in gzopen.\n\n     The next call of gzclose on the returned gzFile will also close the file\n   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor\n   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,\n   mode);.  The duplicated descriptor should be saved to avoid a leak, since\n   gzdopen does not close fd if it fails.  If you are using fileno() to get the\n   file descriptor from a FILE *, then you will have to use dup() to avoid\n   double-close()ing the file descriptor.  Both gzclose() and fclose() will\n   close the associated file descriptor, so they need to have different file\n   descriptors.\n\n     gzdopen returns NULL if there was insufficient memory to allocate the\n   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not\n   provided, or '+' was provided), or if fd is -1.  The file descriptor is not\n   used until the next gz* read, write, seek, or close operation, so gzdopen\n   will not detect if fd is invalid (unless fd is -1).\n*/\n\nZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size);\n/*\n     Set the internal buffer size used by this library's functions for file to\n   size.  The default buffer size is 8192 bytes.  This function must be called\n   after gzopen() or gzdopen(), and before any other calls that read or write\n   the file.  The buffer memory allocation is always deferred to the first read\n   or write.  Three times that size in buffer space is allocated.  A larger\n   buffer size of, for example, 64K or 128K bytes will noticeably increase the\n   speed of decompression (reading).\n\n     The new buffer size also affects the maximum length for gzprintf().\n\n     gzbuffer() returns 0 on success, or -1 on failure, such as being called\n   too late.\n*/\n\nZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy);\n/*\n     Dynamically update the compression level and strategy for file.  See the\n   description of deflateInit2 for the meaning of these parameters. Previously\n   provided data is flushed before applying the parameter changes.\n\n     gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not\n   opened for writing, Z_ERRNO if there is an error writing the flushed data,\n   or Z_MEM_ERROR if there is a memory allocation error.\n*/\n\nZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);\n/*\n     Read and decompress up to len uncompressed bytes from file into buf.  If\n   the input file is not in gzip format, gzread copies the given number of\n   bytes into the buffer directly from the file.\n\n     After reaching the end of a gzip stream in the input, gzread will continue\n   to read, looking for another gzip stream.  Any number of gzip streams may be\n   concatenated in the input file, and will all be decompressed by gzread().\n   If something other than a gzip stream is encountered after a gzip stream,\n   that remaining trailing garbage is ignored (and no error is returned).\n\n     gzread can be used to read a gzip file that is being concurrently written.\n   Upon reaching the end of the input, gzread will return with the available\n   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then\n   gzclearerr can be used to clear the end of file indicator in order to permit\n   gzread to be tried again.  Z_OK indicates that a gzip stream was completed\n   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the\n   middle of a gzip stream.  Note that gzread does not return -1 in the event\n   of an incomplete gzip stream.  This error is deferred until gzclose(), which\n   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip\n   stream.  Alternatively, gzerror can be used before gzclose to detect this\n   case.\n\n     gzread returns the number of uncompressed bytes actually read, less than\n   len for end of file, or -1 for error.  If len is too large to fit in an int,\n   then nothing is read, -1 is returned, and the error state is set to\n   Z_STREAM_ERROR.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,\n                                 gzFile file);\n/*\n     Read and decompress up to nitems items of size size from file into buf,\n   otherwise operating as gzread() does.  This duplicates the interface of\n   stdio's fread(), with size_t request and return types.  If the library\n   defines size_t, then z_size_t is identical to size_t.  If not, then z_size_t\n   is an unsigned integer type that can contain a pointer.\n\n     gzfread() returns the number of full items read of size size, or zero if\n   the end of the file was reached and a full item could not be read, or if\n   there was an error.  gzerror() must be consulted if zero is returned in\n   order to determine if there was an error.  If the multiplication of size and\n   nitems overflows, i.e. the product does not fit in a z_size_t, then nothing\n   is read, zero is returned, and the error state is set to Z_STREAM_ERROR.\n\n     In the event that the end of file is reached and only a partial item is\n   available at the end, i.e. the remaining uncompressed data length is not a\n   multiple of size, then the final partial item is nevertheless read into buf\n   and the end-of-file flag is set.  The length of the partial item read is not\n   provided, but could be inferred from the result of gztell().  This behavior\n   is the same as the behavior of fread() implementations in common libraries,\n   but it prevents the direct use of gzfread() to read a concurrently written\n   file, resetting and retrying on end-of-file, when size is not 1.\n*/\n\nZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);\n/*\n     Compress and write the len uncompressed bytes at buf to file. gzwrite\n   returns the number of uncompressed bytes written or 0 in case of error.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,\n                                  z_size_t nitems, gzFile file);\n/*\n     Compress and write nitems items of size size from buf to file, duplicating\n   the interface of stdio's fwrite(), with size_t request and return types.  If\n   the library defines size_t, then z_size_t is identical to size_t.  If not,\n   then z_size_t is an unsigned integer type that can contain a pointer.\n\n     gzfwrite() returns the number of full items written of size size, or zero\n   if there was an error.  If the multiplication of size and nitems overflows,\n   i.e. the product does not fit in a z_size_t, then nothing is written, zero\n   is returned, and the error state is set to Z_STREAM_ERROR.\n*/\n\nZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);\n/*\n     Convert, format, compress, and write the arguments (...) to file under\n   control of the string format, as in fprintf.  gzprintf returns the number of\n   uncompressed bytes actually written, or a negative zlib error code in case\n   of error.  The number of uncompressed bytes written is limited to 8191, or\n   one less than the buffer size given to gzbuffer().  The caller should assure\n   that this limit is not exceeded.  If it is exceeded, then gzprintf() will\n   return an error (0) with nothing written.  In this case, there may also be a\n   buffer overflow with unpredictable consequences, which is possible only if\n   zlib was compiled with the insecure functions sprintf() or vsprintf(),\n   because the secure snprintf() or vsnprintf() functions were not available.\n   This can be determined using zlibCompileFlags().\n*/\n\nZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);\n/*\n     Compress and write the given null-terminated string s to file, excluding\n   the terminating null character.\n\n     gzputs returns the number of characters written, or -1 in case of error.\n*/\n\nZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);\n/*\n     Read and decompress bytes from file into buf, until len-1 characters are\n   read, or until a newline character is read and transferred to buf, or an\n   end-of-file condition is encountered.  If any characters are read or if len\n   is one, the string is terminated with a null character.  If no characters\n   are read due to an end-of-file or len is less than one, then the buffer is\n   left untouched.\n\n     gzgets returns buf which is a null-terminated string, or it returns NULL\n   for end-of-file or in case of error.  If there was an error, the contents at\n   buf are indeterminate.\n*/\n\nZEXTERN int ZEXPORT gzputc(gzFile file, int c);\n/*\n     Compress and write c, converted to an unsigned char, into file.  gzputc\n   returns the value that was written, or -1 in case of error.\n*/\n\nZEXTERN int ZEXPORT gzgetc(gzFile file);\n/*\n     Read and decompress one byte from file.  gzgetc returns this byte or -1\n   in case of end of file or error.  This is implemented as a macro for speed.\n   As such, it does not do all of the checking the other functions do.  I.e.\n   it does not check to see if file is NULL, nor whether the structure file\n   points to has been clobbered or not.\n*/\n\nZEXTERN int ZEXPORT gzungetc(int c, gzFile file);\n/*\n     Push c back onto the stream for file to be read as the first character on\n   the next read.  At least one character of push-back is always allowed.\n   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will\n   fail if c is -1, and may fail if a character has been pushed but not read\n   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the\n   output buffer size of pushed characters is allowed.  (See gzbuffer above.)\n   The pushed character will be discarded if the stream is repositioned with\n   gzseek() or gzrewind().\n*/\n\nZEXTERN int ZEXPORT gzflush(gzFile file, int flush);\n/*\n     Flush all pending output to file.  The parameter flush is as in the\n   deflate() function.  The return value is the zlib error number (see function\n   gzerror below).  gzflush is only permitted when writing.\n\n     If the flush parameter is Z_FINISH, the remaining data is written and the\n   gzip stream is completed in the output.  If gzwrite() is called again, a new\n   gzip stream will be started in the output.  gzread() is able to read such\n   concatenated gzip streams.\n\n     gzflush should be called only when strictly necessary because it will\n   degrade compression if called too often.\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzseek(gzFile file,\n                               z_off_t offset, int whence);\n\n     Set the starting position to offset relative to whence for the next gzread\n   or gzwrite on file.  The offset represents a number of bytes in the\n   uncompressed data stream.  The whence parameter is defined as in lseek(2);\n   the value SEEK_END is not supported.\n\n     If the file is opened for reading, this function is emulated but can be\n   extremely slow.  If the file is opened for writing, only forward seeks are\n   supported; gzseek then compresses a sequence of zeroes up to the new\n   starting position.\n\n     gzseek returns the resulting offset location as measured in bytes from\n   the beginning of the uncompressed stream, or -1 in case of error, in\n   particular if the file is opened for writing and the new starting position\n   would be before the current position.\n*/\n\nZEXTERN int ZEXPORT    gzrewind(gzFile file);\n/*\n     Rewind file. This function is supported only for reading.\n\n     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET).\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT    gztell(gzFile file);\n\n     Return the starting position for the next gzread or gzwrite on file.\n   This position represents a number of bytes in the uncompressed data stream,\n   and is zero when starting, even if appending or reading a gzip stream from\n   the middle of a file using gzdopen().\n\n     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzoffset(gzFile file);\n\n     Return the current compressed (actual) read or write offset of file.  This\n   offset includes the count of bytes that precede the gzip stream, for example\n   when appending or when using gzdopen() for reading.  When reading, the\n   offset does not include as yet unused buffered input.  This information can\n   be used for a progress indicator.  On error, gzoffset() returns -1.\n*/\n\nZEXTERN int ZEXPORT gzeof(gzFile file);\n/*\n     Return true (1) if the end-of-file indicator for file has been set while\n   reading, false (0) otherwise.  Note that the end-of-file indicator is set\n   only if the read tried to go past the end of the input, but came up short.\n   Therefore, just like feof(), gzeof() may return false even if there is no\n   more data to read, in the event that the last read request was for the exact\n   number of bytes remaining in the input file.  This will happen if the input\n   file size is an exact multiple of the buffer size.\n\n     If gzeof() returns true, then the read functions will return no more data,\n   unless the end-of-file indicator is reset by gzclearerr() and the input file\n   has grown since the previous end of file was detected.\n*/\n\nZEXTERN int ZEXPORT gzdirect(gzFile file);\n/*\n     Return true (1) if file is being copied directly while reading, or false\n   (0) if file is a gzip stream being decompressed.\n\n     If the input file is empty, gzdirect() will return true, since the input\n   does not contain a gzip stream.\n\n     If gzdirect() is used immediately after gzopen() or gzdopen() it will\n   cause buffers to be allocated to allow reading the file to determine if it\n   is a gzip file.  Therefore if gzbuffer() is used, it should be called before\n   gzdirect().\n\n     When writing, gzdirect() returns true (1) if transparent writing was\n   requested (\"wT\" for the gzopen() mode), or false (0) otherwise.  (Note:\n   gzdirect() is not needed when writing.  Transparent writing must be\n   explicitly requested, so the application already knows the answer.  When\n   linking statically, using gzdirect() will include all of the zlib code for\n   gzip file reading and decompression, which may not be desired.)\n*/\n\nZEXTERN int ZEXPORT    gzclose(gzFile file);\n/*\n     Flush all pending output for file, if necessary, close file and\n   deallocate the (de)compression state.  Note that once file is closed, you\n   cannot call gzerror with file, since its structures have been deallocated.\n   gzclose must not be called more than once on the same file, just as free\n   must not be called more than once on the same allocation.\n\n     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a\n   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the\n   last read ended in the middle of a gzip stream, or Z_OK on success.\n*/\n\nZEXTERN int ZEXPORT gzclose_r(gzFile file);\nZEXTERN int ZEXPORT gzclose_w(gzFile file);\n/*\n     Same as gzclose(), but gzclose_r() is only for use when reading, and\n   gzclose_w() is only for use when writing or appending.  The advantage to\n   using these instead of gzclose() is that they avoid linking in zlib\n   compression or decompression code that is not used when only reading or only\n   writing respectively.  If gzclose() is used, then both compression and\n   decompression code will be included the application when linking to a static\n   zlib library.\n*/\n\nZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);\n/*\n     Return the error message for the last error which occurred on file.\n   errnum is set to zlib error number.  If an error occurred in the file system\n   and not in the compression library, errnum is set to Z_ERRNO and the\n   application may consult errno to get the exact error code.\n\n     The application must not modify the returned string.  Future calls to\n   this function may invalidate the previously returned string.  If file is\n   closed, then the string previously returned by gzerror will no longer be\n   available.\n\n     gzerror() should be used to distinguish errors from end-of-file for those\n   functions above that do not distinguish those cases in their return values.\n*/\n\nZEXTERN void ZEXPORT gzclearerr(gzFile file);\n/*\n     Clear the error and end-of-file flags for file.  This is analogous to the\n   clearerr() function in stdio.  This is useful for continuing to read a gzip\n   file that is being written concurrently.\n*/\n\n#endif /* !Z_SOLO */\n\n                        /* checksum functions */\n\n/*\n     These functions are not related to compression but are exported\n   anyway because they might be useful in applications using the compression\n   library.\n*/\n\nZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len);\n/*\n     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n   return the updated checksum. An Adler-32 value is in the range of a 32-bit\n   unsigned integer. If buf is Z_NULL, this function returns the required\n   initial value for the checksum.\n\n     An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed\n   much faster.\n\n   Usage example:\n\n     uLong adler = adler32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       adler = adler32(adler, buffer, length);\n     }\n     if (adler != original_adler) error();\n*/\n\nZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf,\n                                z_size_t len);\n/*\n     Same as adler32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2,\n                                      z_off_t len2);\n\n     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1\n   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for\n   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of\n   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note\n   that the z_off_t type (like off_t) is a signed integer.  If len2 is\n   negative, the result has no meaning or utility.\n*/\n\nZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len);\n/*\n     Update a running CRC-32 with the bytes buf[0..len-1] and return the\n   updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer.\n   If buf is Z_NULL, this function returns the required initial value for the\n   crc. Pre- and post-conditioning (one's complement) is performed within this\n   function so it shouldn't be done by the application.\n\n   Usage example:\n\n     uLong crc = crc32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       crc = crc32(crc, buffer, length);\n     }\n     if (crc != original_crc) error();\n*/\n\nZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf,\n                              z_size_t len);\n/*\n     Same as crc32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);\n\n     Combine two CRC-32 check values into one.  For two sequences of bytes,\n   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were\n   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32\n   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and\n   len2. len2 must be non-negative.\n*/\n\n/*\nZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);\n\n     Return the operator corresponding to length len2, to be used with\n   crc32_combine_op(). len2 must be non-negative.\n*/\n\nZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);\n/*\n     Give the same result as crc32_combine(), using op in place of len2. op is\n   is generated from len2 by crc32_combine_gen(). This will be faster than\n   crc32_combine() if the generated op is used more than once.\n*/\n\n\n                        /* various hacks, don't look :) */\n\n/* deflateInit and inflateInit are macros to allow checking the zlib version\n * and the compiler's view of z_stream:\n */\nZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level,\n                                 const char *version, int stream_size);\nZEXTERN int ZEXPORT inflateInit_(z_streamp strm,\n                                 const char *version, int stream_size);\nZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int  level, int  method,\n                                  int windowBits, int memLevel,\n                                  int strategy, const char *version,\n                                  int stream_size);\nZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int  windowBits,\n                                  const char *version, int stream_size);\nZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,\n                                     unsigned char FAR *window,\n                                     const char *version,\n                                     int stream_size);\n#ifdef Z_PREFIX_SET\n#  define z_deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define z_inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#else\n#  define deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#endif\n\n#ifndef Z_SOLO\n\n/* gzgetc() macro and its supporting function and exposed data structure.  Note\n * that the real internal state is much larger than the exposed structure.\n * This abbreviated structure exposes just enough for the gzgetc() macro.  The\n * user should not mess with these exposed elements, since their names or\n * behavior could change in the future, perhaps even capriciously.  They can\n * only be used by the gzgetc() macro.  You have been warned.\n */\nstruct gzFile_s {\n    unsigned have;\n    unsigned char *next;\n    z_off64_t pos;\n};\nZEXTERN int ZEXPORT gzgetc_(gzFile file);       /* backward compatibility */\n#ifdef Z_PREFIX_SET\n#  undef z_gzgetc\n#  define z_gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#else\n#  define gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#endif\n\n/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or\n * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if\n * both are true, the application gets the *64 functions, and the regular\n * functions are changed to 64 bits) -- in case these are set on systems\n * without large file support, _LFS64_LARGEFILE must also be true\n */\n#ifdef Z_LARGE64\n   ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);\n   ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);\n   ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);\n   ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);\n   ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);\n   ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);\n   ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);\n#endif\n\n#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)\n#  ifdef Z_PREFIX_SET\n#    define z_gzopen z_gzopen64\n#    define z_gzseek z_gzseek64\n#    define z_gztell z_gztell64\n#    define z_gzoffset z_gzoffset64\n#    define z_adler32_combine z_adler32_combine64\n#    define z_crc32_combine z_crc32_combine64\n#    define z_crc32_combine_gen z_crc32_combine_gen64\n#  else\n#    define gzopen gzopen64\n#    define gzseek gzseek64\n#    define gztell gztell64\n#    define gzoffset gzoffset64\n#    define adler32_combine adler32_combine64\n#    define crc32_combine crc32_combine64\n#    define crc32_combine_gen crc32_combine_gen64\n#  endif\n#  ifndef Z_LARGE64\n     ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);\n     ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);\n     ZEXTERN z_off_t ZEXPORT gztell64(gzFile);\n     ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);\n     ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);\n     ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);\n     ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);\n#  endif\n#else\n   ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);\n   ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int);\n   ZEXTERN z_off_t ZEXPORT gztell(gzFile);\n   ZEXTERN z_off_t ZEXPORT gzoffset(gzFile);\n   ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);\n   ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);\n   ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);\n#endif\n\n#else /* Z_SOLO */\n\n   ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);\n   ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);\n   ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);\n\n#endif /* !Z_SOLO */\n\n/* undocumented functions */\nZEXTERN const char   * ZEXPORT zError(int);\nZEXTERN int            ZEXPORT inflateSyncPoint(z_streamp);\nZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void);\nZEXTERN int            ZEXPORT inflateUndermine(z_streamp, int);\nZEXTERN int            ZEXPORT inflateValidate(z_streamp, int);\nZEXTERN unsigned long  ZEXPORT inflateCodesUsed(z_streamp);\nZEXTERN int            ZEXPORT inflateResetKeep(z_streamp);\nZEXTERN int            ZEXPORT deflateResetKeep(z_streamp);\n#if defined(_WIN32) && !defined(Z_SOLO)\nZEXTERN gzFile         ZEXPORT gzopen_w(const wchar_t *path,\n                                        const char *mode);\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\nZEXTERN int            ZEXPORTVA gzvprintf(gzFile file,\n                                           const char *format,\n                                           va_list va);\n#  endif\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZLIB_H */\n"
  },
  {
    "path": "eidos_zlib/zutil.c",
    "content": "/* zutil.c -- target dependent utility functions for the compression library\n * Copyright (C) 1995-2017 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n#ifndef Z_SOLO\n#  include \"gzguts.h\"\n#endif\n\nz_const char * const z_errmsg[10] = {\n    (z_const char *)\"need dictionary\",     /* Z_NEED_DICT       2  */\n    (z_const char *)\"stream end\",          /* Z_STREAM_END      1  */\n    (z_const char *)\"\",                    /* Z_OK              0  */\n    (z_const char *)\"file error\",          /* Z_ERRNO         (-1) */\n    (z_const char *)\"stream error\",        /* Z_STREAM_ERROR  (-2) */\n    (z_const char *)\"data error\",          /* Z_DATA_ERROR    (-3) */\n    (z_const char *)\"insufficient memory\", /* Z_MEM_ERROR     (-4) */\n    (z_const char *)\"buffer error\",        /* Z_BUF_ERROR     (-5) */\n    (z_const char *)\"incompatible version\",/* Z_VERSION_ERROR (-6) */\n    (z_const char *)\"\"\n};\n\n\nconst char * ZEXPORT zlibVersion(void) {\n    return ZLIB_VERSION;\n}\n\nuLong ZEXPORT zlibCompileFlags(void) {\n    uLong flags;\n\n    flags = 0;\n    switch ((int)(sizeof(uInt))) {\n    case 2:     break;\n    case 4:     flags += 1;     break;\n    case 8:     flags += 2;     break;\n    default:    flags += 3;\n    }\n    switch ((int)(sizeof(uLong))) {\n    case 2:     break;\n    case 4:     flags += 1 << 2;        break;\n    case 8:     flags += 2 << 2;        break;\n    default:    flags += 3 << 2;\n    }\n    switch ((int)(sizeof(voidpf))) {\n    case 2:     break;\n    case 4:     flags += 1 << 4;        break;\n    case 8:     flags += 2 << 4;        break;\n    default:    flags += 3 << 4;\n    }\n    switch ((int)(sizeof(z_off_t))) {\n    case 2:     break;\n    case 4:     flags += 1 << 6;        break;\n    case 8:     flags += 2 << 6;        break;\n    default:    flags += 3 << 6;\n    }\n#ifdef ZLIB_DEBUG\n    flags += 1 << 8;\n#endif\n    /*\n#if defined(ASMV) || defined(ASMINF)\n    flags += 1 << 9;\n#endif\n     */\n#ifdef ZLIB_WINAPI\n    flags += 1 << 10;\n#endif\n#ifdef BUILDFIXED\n    flags += 1 << 12;\n#endif\n#ifdef DYNAMIC_CRC_TABLE\n    flags += 1 << 13;\n#endif\n#ifdef NO_GZCOMPRESS\n    flags += 1L << 16;\n#endif\n#ifdef NO_GZIP\n    flags += 1L << 17;\n#endif\n#ifdef PKZIP_BUG_WORKAROUND\n    flags += 1L << 20;\n#endif\n#ifdef FASTEST\n    flags += 1L << 21;\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifdef NO_vsnprintf\n    flags += 1L << 25;\n#    ifdef HAS_vsprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_vsnprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#else\n    flags += 1L << 24;\n#  ifdef NO_snprintf\n    flags += 1L << 25;\n#    ifdef HAS_sprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_snprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#endif\n    return flags;\n}\n\n#ifdef ZLIB_DEBUG\n#include <stdlib.h>\n#  ifndef verbose\n#    define verbose 0\n#  endif\nint ZLIB_INTERNAL z_verbose = verbose;\n\nvoid ZLIB_INTERNAL z_error(char *m) {\n    fprintf(stderr, \"%s\\n\", m);\n    exit(1);\n}\n#endif\n\n/* exported to allow conversion of error code to string for compress() and\n * uncompress()\n */\nconst char * ZEXPORT zError(int err) {\n    return ERR_MSG(err);\n}\n\n#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800\n    /* The older Microsoft C Run-Time Library for Windows CE doesn't have\n     * errno.  We define it as a global variable to simplify porting.\n     * Its value is always 0 and should not be used.\n     */\n    int errno = 0;\n#endif\n\n#ifndef HAVE_MEMCPY\n\nvoid ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {\n    if (len == 0) return;\n    do {\n        *dest++ = *source++; /* ??? to be unrolled */\n    } while (--len != 0);\n}\n\nint ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {\n    uInt j;\n\n    for (j = 0; j < len; j++) {\n        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;\n    }\n    return 0;\n}\n\nvoid ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {\n    if (len == 0) return;\n    do {\n        *dest++ = 0;  /* ??? to be unrolled */\n    } while (--len != 0);\n}\n#endif\n\n#ifndef Z_SOLO\n\n#ifdef SYS16BIT\n\n#ifdef __TURBOC__\n/* Turbo C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n/* Turbo C malloc() does not allow dynamic allocation of 64K bytes\n * and farmalloc(64K) returns a pointer with an offset of 8, so we\n * must fix the pointer. Warning: the pointer must be put back to its\n * original form in order to free it, use zcfree().\n */\n\n#define MAX_PTR 10\n/* 10*64K = 640K */\n\nlocal int next_ptr = 0;\n\ntypedef struct ptr_table_s {\n    voidpf org_ptr;\n    voidpf new_ptr;\n} ptr_table;\n\nlocal ptr_table table[MAX_PTR];\n/* This table is used to remember the original form of pointers\n * to large buffers (64K). Such pointers are normalized with a zero offset.\n * Since MSDOS is not a preemptive multitasking OS, this table is not\n * protected from concurrent access. This hack doesn't work anyway on\n * a protected system like OS/2. Use Microsoft C instead.\n */\n\nvoidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {\n    voidpf buf;\n    ulg bsize = (ulg)items*size;\n\n    (void)opaque;\n\n    /* If we allocate less than 65520 bytes, we assume that farmalloc\n     * will return a usable pointer which doesn't have to be normalized.\n     */\n    if (bsize < 65520L) {\n        buf = farmalloc(bsize);\n        if (*(ush*)&buf != 0) return buf;\n    } else {\n        buf = farmalloc(bsize + 16L);\n    }\n    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;\n    table[next_ptr].org_ptr = buf;\n\n    /* Normalize the pointer to seg:0 */\n    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;\n    *(ush*)&buf = 0;\n    table[next_ptr++].new_ptr = buf;\n    return buf;\n}\n\nvoid ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {\n    int n;\n\n    (void)opaque;\n\n    if (*(ush*)&ptr != 0) { /* object < 64K */\n        farfree(ptr);\n        return;\n    }\n    /* Find the original pointer */\n    for (n = 0; n < next_ptr; n++) {\n        if (ptr != table[n].new_ptr) continue;\n\n        farfree(table[n].org_ptr);\n        while (++n < next_ptr) {\n            table[n-1] = table[n];\n        }\n        next_ptr--;\n        return;\n    }\n    Assert(0, \"zcfree: ptr not found\");\n}\n\n#endif /* __TURBOC__ */\n\n\n#ifdef M_I86\n/* Microsoft C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n#if (!defined(_MSC_VER) || (_MSC_VER <= 600))\n#  define _halloc  halloc\n#  define _hfree   hfree\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {\n    (void)opaque;\n    return _halloc((long)items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {\n    (void)opaque;\n    _hfree(ptr);\n}\n\n#endif /* M_I86 */\n\n#endif /* SYS16BIT */\n\n\n#ifndef MY_ZCALLOC /* Any system without a special alloc function */\n\n#ifndef STDC\nextern voidp malloc(uInt size);\nextern voidp calloc(uInt items, uInt size);\nextern void free(voidpf ptr);\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {\n    (void)opaque;\n    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :\n                              (voidpf)calloc(items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {\n    (void)opaque;\n    free(ptr);\n}\n\n#endif /* MY_ZCALLOC */\n\n#endif /* !Z_SOLO */\n"
  },
  {
    "path": "eidos_zlib/zutil.h",
    "content": "/* zutil.h -- internal interface and configuration of the compression library\n * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZUTIL_H\n#define ZUTIL_H\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include \"zlib.h\"\n\n#if defined(STDC) && !defined(Z_SOLO)\n#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))\n#    include <stddef.h>\n#  endif\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\ntypedef unsigned char  uch;\ntypedef uch FAR uchf;\ntypedef unsigned short ush;\ntypedef ush FAR ushf;\ntypedef unsigned long  ulg;\n\n#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC)\n#  include <limits.h>\n#  if (ULONG_MAX == 0xffffffffffffffff)\n#    define Z_U8 unsigned long\n#  elif (ULLONG_MAX == 0xffffffffffffffff)\n#    define Z_U8 unsigned long long\n#  elif (UINT_MAX == 0xffffffffffffffff)\n#    define Z_U8 unsigned\n#  endif\n#endif\n\nextern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */\n/* (size given to avoid silly warnings with Visual C++) */\n\n#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)]\n\n#define ERR_RETURN(strm,err) \\\n  return (strm->msg = ERR_MSG(err), (err))\n/* To be used only when the state is known to be valid */\n\n        /* common constants */\n\n#ifndef DEF_WBITS\n#  define DEF_WBITS MAX_WBITS\n#endif\n/* default windowBits for decompression. MAX_WBITS is for compression only */\n\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n/* default memLevel */\n\n#define STORED_BLOCK 0\n#define STATIC_TREES 1\n#define DYN_TREES    2\n/* The three kinds of block type */\n\n#define MIN_MATCH  3\n#define MAX_MATCH  258\n/* The minimum and maximum match lengths */\n\n#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */\n\n        /* target dependencies */\n\n#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))\n#  define OS_CODE  0x00\n#  ifndef Z_SOLO\n#    if defined(__TURBOC__) || defined(__BORLANDC__)\n#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))\n         /* Allow compilation with ANSI keywords only enabled */\n         void _Cdecl farfree( void *block );\n         void *_Cdecl farmalloc( unsigned long nbytes );\n#      else\n#        include <alloc.h>\n#      endif\n#    else /* MSC or DJGPP */\n#      include <malloc.h>\n#    endif\n#  endif\n#endif\n\n#ifdef AMIGA\n#  define OS_CODE  1\n#endif\n\n#if defined(VAXC) || defined(VMS)\n#  define OS_CODE  2\n#  define F_OPEN(name, mode) \\\n     fopen((name), (mode), \"mbc=60\", \"ctx=stm\", \"rfm=fix\", \"mrs=512\")\n#endif\n\n#ifdef __370__\n#  if __TARGET_LIB__ < 0x20000000\n#    define OS_CODE 4\n#  elif __TARGET_LIB__ < 0x40000000\n#    define OS_CODE 11\n#  else\n#    define OS_CODE 8\n#  endif\n#endif\n\n#if defined(ATARI) || defined(atarist)\n#  define OS_CODE  5\n#endif\n\n#ifdef OS2\n#  define OS_CODE  6\n#  if defined(M_I86) && !defined(Z_SOLO)\n#    include <malloc.h>\n#  endif\n#endif\n\n#if defined(MACOS)\n#  define OS_CODE  7\n#endif\n\n#ifdef __acorn\n#  define OS_CODE 13\n#endif\n\n#if defined(WIN32) && !defined(__CYGWIN__)\n#  define OS_CODE  10\n#endif\n\n#ifdef _BEOS_\n#  define OS_CODE  16\n#endif\n\n#ifdef __TOS_OS400__\n#  define OS_CODE 18\n#endif\n\n#ifdef __APPLE__\n#  define OS_CODE 19\n#endif\n\n#if defined(__BORLANDC__) && !defined(MSDOS)\n  #pragma warn -8004\n  #pragma warn -8008\n  #pragma warn -8066\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_WIN32) && \\\n    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)\n    ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);\n    ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);\n    ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);\n#endif\n\n        /* common defaults */\n\n#ifndef OS_CODE\n#  define OS_CODE  3     /* assume Unix */\n#endif\n\n#ifndef F_OPEN\n#  define F_OPEN(name, mode) fopen((name), (mode))\n#endif\n\n         /* functions */\n\n#if defined(pyr) || defined(Z_SOLO)\n#  define NO_MEMCPY\n#endif\n#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)\n /* Use our own functions for small and medium model with MSC <= 5.0.\n  * You may have to use the same strategy for Borland C (untested).\n  * The __SC__ check is for Symantec.\n  */\n#  define NO_MEMCPY\n#endif\n#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)\n#  define HAVE_MEMCPY\n#endif\n#ifdef HAVE_MEMCPY\n#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */\n#    define zmemcpy _fmemcpy\n#    define zmemcmp _fmemcmp\n#    define zmemzero(dest, len) _fmemset(dest, 0, len)\n#  else\n#    define zmemcpy memcpy\n#    define zmemcmp memcmp\n#    define zmemzero(dest, len) memset(dest, 0, len)\n#  endif\n#else\n   void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);\n   int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);\n   void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);\n#endif\n\n/* Diagnostic functions */\n#ifdef ZLIB_DEBUG\n#  include <stdio.h>\n   extern int ZLIB_INTERNAL z_verbose;\n   extern void ZLIB_INTERNAL z_error(char *m);\n#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}\n#  define Trace(x) {if (z_verbose>=0) fprintf x ;}\n#  define Tracev(x) {if (z_verbose>0) fprintf x ;}\n#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}\n#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}\n#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}\n#else\n#  define Assert(cond,msg)\n#  define Trace(x)\n#  define Tracev(x)\n#  define Tracevv(x)\n#  define Tracec(c,x)\n#  define Tracecv(c,x)\n#endif\n\n#ifndef Z_SOLO\n   voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,\n                                unsigned size);\n   void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);\n#endif\n\n#define ZALLOC(strm, items, size) \\\n           (*((strm)->zalloc))((strm)->opaque, (items), (size))\n#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))\n#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}\n\n/* Reverse the bytes in a 32-bit value */\n#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \\\n                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))\n\n#endif /* ZUTIL_H */\n"
  },
  {
    "path": "eidostool/main.cpp",
    "content": "//\n//  main.cpp\n//  eidos\n//\n//  Created by Ben Haller on 9/15/15.\n//  Copyright (c) 2015-2022 Benjamin C. Haller.  All rights reserved.\n//\tA product of the Messer Lab, http://messerlab.org/slim/\n//\n\n#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <string>\n#include <ctime>\n#include <chrono>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/stat.h>\n\n#include \"eidos_globals.h\"\n#include \"eidos_interpreter.h\"\n#include \"eidos_test.h\"\n\n#include \"eidos_openmp.h\"\n\n\nvoid PrintUsageAndDie();\n\nvoid PrintUsageAndDie()\n{\n\tstd::cout << \"usage: eidos -version | -usage | -testEidos | [-time] [-mem]\" << std::endl;\n\tstd::cout << \"   \";\n#ifdef _OPENMP\n\t// Some flags are visible only for a parallel build\n\tstd::cout << \"[-maxThreads <n>] [-perTaskThreads \\\"x\\\"] \";\n#endif\n\tstd::cout << \"<script file>\" << std::endl;\n\texit(EXIT_SUCCESS);\n}\n\nint main(int argc, const char * argv[])\n{\n\t// command-line Eidos generally terminates rather than throwing\n\tgEidosTerminateThrows = false;\n\t\n\t// parse command-line arguments\n\tconst char *input_file = nullptr;\n\tbool keep_time = false, keep_mem = false;\n\t\n#ifdef _OPENMP\n\tlong max_thread_count = omp_get_max_threads();\n\tbool changed_max_thread_count = false;\n\tstd::string per_task_thread_count_set_name = \"\";\t\t// default per-task thread counts\n#endif\n\t\n\t// \"slim\" with no arguments prints usage, *unless* stdin is not a tty, in which case we're running the stdin script\n\tif ((argc == 1) && isatty(fileno(stdin)))\n\t\tPrintUsageAndDie();\n\t\n\tfor (int arg_index = 1; arg_index < argc; ++arg_index)\n\t{\n\t\tconst char *arg = argv[arg_index];\n\t\t\n\t\t// -time or -t: take a time measurement and output it at the end of execution\n\t\tif (strcmp(arg, \"-time\") == 0 || strcmp(arg, \"-t\") == 0)\n\t\t{\n\t\t\tkeep_time = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -mem or -m: take a peak memory usage measurement and output it at the end of execution\n\t\tif (strcmp(arg, \"-mem\") == 0 || strcmp(arg, \"-m\") == 0)\n\t\t{\n\t\t\tkeep_mem = true;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\t// -version or -v: print version information\n\t\tif (strcmp(arg, \"-version\") == 0 || strcmp(arg, \"-v\") == 0)\n\t\t{\n\t\t\tstd::cout << \"Eidos version \" << EIDOS_VERSION_STRING << \", built \" << __DATE__ << \" \" __TIME__ << std::endl;\n\t\t\texit(EXIT_SUCCESS);\n\t\t}\n\t\t\n\t\t// -testEidos or -te: run Eidos tests and quit\n\t\tif (strcmp(arg, \"-testEidos\") == 0 || strcmp(arg, \"-te\") == 0)\n\t\t{\n#ifdef _OPENMP\n\t\t\tEidos_WarmUpOpenMP(&std::cerr, changed_max_thread_count, (int)max_thread_count, true, /* max per-task thread counts */ \"maxThreads\");\n#endif\n\t\t\tEidos_WarmUp();\n\t\t\t\n\t\t\tgEidosTerminateThrows = true;\n\t\t\t\n\t\t\tint test_result = RunEidosTests();\n\t\t\t\n\t\t\tEidos_FlushFiles();\n\t\t\texit(test_result);\n\t\t}\n\t\t\n\t\t// -usage or -u: print usage information\n\t\tif (strcmp(arg, \"-usage\") == 0 || strcmp(arg, \"-u\") == 0 || strcmp(arg, \"-?\") == 0)\n\t\t{\n\t\t\tPrintUsageAndDie();\n\t\t}\n\t\t\n\t\t// -maxThreads <x>: set the maximum number of OpenMP threads that will be used\n\t\tif (strcmp(arg, \"-maxThreads\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie();\n\t\t\t\n\t\t\tlong count = strtol(argv[arg_index], NULL, 10);\n\t\t\t\n#ifdef _OPENMP\n\t\t\tmax_thread_count = count;\n\t\t\tchanged_max_thread_count = true;\n\t\t\t\n\t\t\tif ((max_thread_count < 1) || (max_thread_count > EIDOS_OMP_MAX_THREADS))\n\t\t\t{\n\t\t\t\tstd::cout << \"The -maxThreads command-line option enforces a range of [1, \" << EIDOS_OMP_MAX_THREADS << \"].\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n\t\t\t\n\t\t\tcontinue;\n#else\n\t\t\tif (count != 1)\n\t\t\t{\n\t\t\t\tstd::cout << \"The -maxThreads command-line option only allows a value of 1 when not running a PARALLEL build.\" << std::endl;\n\t\t\t\texit(EXIT_FAILURE);\n\t\t\t}\n#endif\n\t\t}\n\t\t\n\t\t// -perTaskThreads \"x\": set the per-task thread counts to be used in OpenMP to a named set \"x\"\n\t\tif (strcmp(arg, \"-perTaskThreads\") == 0)\n\t\t{\n\t\t\tif (++arg_index == argc)\n\t\t\t\tPrintUsageAndDie();\n\t\t\t\n#ifdef _OPENMP\n\t\t\t// We just take the name as given; testing against known values will be done later\n\t\t\t// This command-line argument is ignored completely when not parallel\n\t\t\tper_task_thread_count_set_name = std::string(argv[arg_index]);\n#endif\n\t\t}\n\t\t\n\t\t// this is the fall-through, which should be the input file, and should be the last argument given\n\t\tif (arg_index + 1 != argc)\n\t\t\tPrintUsageAndDie();\n\t\t\n\t\tinput_file = argv[arg_index];\n\t}\n\t\n\t// check that we got what we need\n\tif (!input_file && isatty(fileno(stdin)))\n\t\tPrintUsageAndDie();\n\t\n\t// announce if we are running a debug build, etc.\n#ifdef DEBUG\n\tstd::cerr << \"// ********** DEBUG defined – you are not using a release build of Eidos\" << std::endl << std::endl;\n#endif\n\t\n#ifdef _OPENMP\n\tEidos_WarmUpOpenMP(&std::cerr, changed_max_thread_count, (int)max_thread_count, true, per_task_thread_count_set_name);\n#endif\n\t\n\t// keep time (we do this whether or not the -time flag was passed)\n\tstd::clock_t begin_cpu = std::clock();\n\t\n\t// keep memory usage information, if asked to\n\tsize_t initial_mem_usage = 0;\n\tsize_t peak_mem_usage = 0;\n\t\n\tif (keep_mem)\n\t{\n\t\t// note we subtract the size of our memory-tracking buffer, here and below\n\t\tinitial_mem_usage = Eidos_GetCurrentRSS();\n\t}\n\t\n\t// warm up and load the script\n\tEidos_WarmUp();\n\tClearErrorPosition();\n\t\n\tEidosScript *script = nullptr;\n\t\n\tif (!input_file)\n\t{\n\t\t// no input file supplied; either the user forgot (if stdin is a tty) or they're piping a script into stdin\n\t\t// we checked for the tty case above, so here we assume stdin will supply the script\n\t\tstd::stringstream buffer;\n\t\t\n\t\tbuffer << std::cin.rdbuf();\n\t\t\n\t\tscript = new EidosScript(buffer.str(), nullptr, 0, 0, 0);\n\t}\n\telse\n\t{\n\t\t// BCH 1/18/2020: check that input_file is a valid path to a file that we can access before opening it\n\t\t{\n\t\t\tFILE *fp = fopen(input_file, \"r\");\n\t\t\t\n\t\t\tif (!fp)\n\t\t\t\tEIDOS_TERMINATION << std::endl << \"ERROR (main): could not open input file: \" << input_file << \".\" << EidosTerminate();\n\t\t\t\n\t\t\tstruct stat fileInfo;\n\t\t\tint retval = fstat(fileno(fp), &fileInfo);\n\t\t\t\n\t\t\tif (retval != 0)\n\t\t\t\tEIDOS_TERMINATION << std::endl << \"ERROR (main): could not access input file: \" << input_file << \".\" << EidosTerminate();\n\t\t\t\n\t\t\t// BCH 30 March 2020: adding S_ISFIFO() as a permitted file type here, to re-enable redirection of input\n\t\t\tif (!S_ISREG(fileInfo.st_mode) && !S_ISFIFO(fileInfo.st_mode))\n\t\t\t{\n\t\t\t\tfclose(fp);\n\t\t\t\tEIDOS_TERMINATION << std::endl << \"ERROR (main): input file \" << input_file << \" is not a regular file or a fifo (it might be a directory or other special file).\" << EidosTerminate();\n\t\t\t}\n\t\t\tfclose(fp);\n\t\t}\n\t\t\n\t\tstd::ifstream infile(input_file);\n\t\t\n\t\tif (!infile.is_open())\n\t\t\tEIDOS_TERMINATION << \"ERROR (eidos): could not open input file: \" << input_file << \".\" << EidosTerminate();\n\t\t\n\t\tinfile.seekg(0, std::fstream::beg);\n\t\tstd::stringstream buffer;\n\t\t\n\t\tbuffer << infile.rdbuf();\n\t\t\n\t\tscript = new EidosScript(buffer.str(), nullptr, 0, 0, 0);\n\t}\n\t\n\t// set up top-level error-reporting info\n\tgEidosErrorContext.currentScript = script;\n\t\n\tscript->Tokenize();\n\tscript->ParseInterpreterBlockToAST(true);\n\t\n\t// reset error position indicators used by SLiMgui\n\tClearErrorPosition();\n\n\tEidosSymbolTable *variable_symbols = new EidosSymbolTable(EidosSymbolTableType::kGlobalVariablesTable, gEidosConstantsSymbolTable);\n\tEidosFunctionMap function_map(*EidosInterpreter::BuiltInFunctionMap());\n\tEidosInterpreter interpreter(*script, *variable_symbols, function_map, nullptr, std::cout, std::cerr);\n\t\n\tEidosValue_SP result = interpreter.EvaluateInterpreterBlock(true, true);\t// print output, return the last statement value (result not used)\n\t\n\tEidos_FlushFiles();\n\t\n\t// end timing and print elapsed time\n\tif (keep_time)\n\t{\n\t\tstd::clock_t end_cpu = std::clock();\n\t\tdouble cpu_time_secs = static_cast<double>(end_cpu - begin_cpu) / CLOCKS_PER_SEC;\n\t\tdouble user_time, sys_time;\n\t\t\n\t\tEidos_GetUserSysTime(&user_time, &sys_time);\n\t\t\n\t\tstd::cout << \"// ********** CPU time used: \" << cpu_time_secs << std::endl;\n\t\tif (user_time > 0.0)\n\t\t\tstd::cout << \"// ********** User CPU time: \" << user_time << std::endl;\n\t\tif (sys_time > 0.0)\n\t\t\tstd::cout << \"// ********** System CPU time: \" << sys_time << std::endl;\n\t\tstd::cout << \"// ********** Wall time used: \" << Eidos_WallTimeSeconds() << std::endl;\n\t}\n\t\n\t// print memory usage stats\n\tif (keep_mem)\n\t{\n\t\tpeak_mem_usage = Eidos_GetPeakRSS();\n\t\t\n\t\tstd::cout << \"// ********** Initial memory usage: \" << initial_mem_usage << \" bytes (\" << initial_mem_usage / 1024.0 << \"K, \" << initial_mem_usage / (1024.0 * 1024) << \"MB)\" << std::endl;\n\t\tstd::cout << \"// ********** Peak memory usage: \" << peak_mem_usage << \" bytes (\" << peak_mem_usage / 1024.0 << \"K, \" << peak_mem_usage / (1024.0 * 1024) << \"MB)\" << std::endl;\n\t}\n\t\n\treturn EXIT_SUCCESS;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "gsl/AUTHORS",
    "content": "Mark Galassi (rosalia@lanl.gov) - overall design, simulated annealing\nJim Davies (jimmyd@nis.lanl.gov) - statistics library\nJames Theiler (jt@lanl.gov) - random number generators\nBrian Gough (bjg@network-theory.co.uk) -\n  FFTs, numerical integration, random number generators and distributions,\n  root finding, minimization and fitting, polynomial solvers, complex\n  numbers, physical constants, permutations, vector and matrix functions,\n  histograms, statistics, ieee-utils, revised CBLAS Level 2 & 3, matrix\n  decompositions and eigensystems.\nReid Priedhorsky (rp@lanl.gov) - root finding\nGerard Jungman (jungman@lanl.gov) special functions, interpolation, \n  series acceleration, ODEs, BLAS, Linear Algebra, Eigensystems,\n  Hankel Transforms.\nMichael Booth (booth@debian.org (email address not working)) - Monte \n  Carlo integration\nFabrice Rossi (rossi@ufrmd.dauphine.fr) - Multidimensional minimization\nSimone Piccardi (piccardi@fi.infn.it) - Ntuples\nCarlo Perassi (carlo@linux.it) - Additional random number generators\nDan, Ho-Jin (hjdan@sys713.kaist.ac.kr) - divided differences interpolation\nSzymon Jaroszewicz (sj@cs.umb.edu) - combinations\nNicolas Darnis (ndarnis@cvf.fr) - cyclic functions and the initial functions for\n canonical permutations.\nTuomo Keskitalo (tuomo.keskitalo@iki.fi) - multidimensional minimization and \n ode-initval2 routines for ordinary differential equations\nIvo Alxneit (ivo.alxneit@psi.ch) - multidimensional minimization, wavelet \n  transforms\nJason H. Stover (jason@sakla.net) - cumulative distribution functions\nPatrick Alken <patrick.alken@colorado.edu> - nonsymmetric and generalized\n  eigensystems, B-splines, sparse matrices, linear and nonlinear least squares\nRhys Ulerich (rhys.ulerich@gmail.com) - multisets\nPavel Holoborodko <pavel@holoborodko.com> - fixed order Gauss-Legendre quadrature\nPedro Gonnet <gonnet@maths.ox.ac.uk> - CQUAD integration routines.\n"
  },
  {
    "path": "gsl/COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "gsl/README",
    "content": "GSL - GNU Scientific Library\n============================\n\nThis is GSL, the GNU Scientific Library, a collection of numerical\nroutines for scientific computing.\n\nGSL is free software, you can redistribute it and/or modify it under\nthe terms of the GNU General Public License.\n\nThe GNU General Public License does not permit this software to be\nredistributed in proprietary programs.\n\nThis library is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nAvailability\n============\n\nThe current stable version of GSL is always available from ftp.gnu.org\nin the directory /pub/gnu/gsl.\n\nA list of mirror sites can be found at http://www.gnu.org/order/ftp.html\n\nInstallation\n============\n\nGSL follows the standard GNU installation procedure.  Please consult\nthe INSTALL file in this distribution for more detailed instructions.\n\nFor information about specific platforms and compilers see the\n\"Compilation Notes\" section in the INSTALL file.\n\nMore information about GSL\n==========================\n\nThe project homepage is http://www.gnu.org/software/gsl/\n\nSee the NEWS file for recent changes to the library.\n\nThe GSL Manual has been published and can be ordered from most\nbookstores. The publication details are,\n\n  GNU Scientific Library Reference Manual - Revised Second Edition, \n  M. Galassi et al, ISBN 0954161734 (620 pages, paperback).\n\nThe money raised from sales of the manual helps support the\ndevelopment of GSL.\n\nA Japanese translation of the reference manual is available from the\nGSL website above (thanks to Daisuke TOMINAGA).\n\nReporting Bugs\n==============\n\nA list of known bugs can be found in the BUGS file.  Details of\ncompilation problems can be found in the INSTALL file.\n\nIf you find a bug which is not listed in these files please report it\nto bug-gsl@gnu.org.\n\nAll bug reports should include:\n\n       The version number of GSL, and where you obtained it.\n       The hardware and operating system\n       The compiler used, including version number and compilation options\n       A description of the bug behaviour\n       A short program which reproducibly exercises the bug\n\nIt is useful if you can check whether the same problem occurs when the\nlibrary is compiled without optimization.  Thank you.\n\nAny errors or omissions in the manual can also be reported to the\nsame address.\n\nContributing to GSL\n===================\n\nIf you are interested in participating in GSL development, please see\nthe webpage at http://www.gnu.org/software/gsl/\n\n"
  },
  {
    "path": "gsl/THANKS",
    "content": "* Jim McElwaine for very useful comments and discussions\n  about the dilogarithm and related functions.\n\n* Simone Piccardi <piccardi@fi.infn.it> for extensions to the\nhistogram routines, and providing the ntuple code\n\n* Nelson H. F. Beebe <beebe@math.utah.edu> for references and testing\nthe software on many different platforms.\n\n* Tim Mooney <mooney@dogbert.cc.ndsu.nodak.edu> for IEEE support for\nTru64, AIX, IRIX, fixes for odes, and testing\n\n* Thomas Walter <walter@pctc.chemie.uni-erlangen.de> for heapsort\nroutines, cholesky decomposition, bug reports and useful suggestions\n\n* Jorma Olavi Tähtinen <jotahtin@cc.hut.fi> for complex arithmetic\nfunctions\n\n* Barak Pearlmutter <bap@cs.unm.edu>\n\n* Frederick W. Wheeler <wheeler@cipr.rpi.edu>\n\n* Bernd Petrovitsch <bernd@ict.tuwien.ac.at>\n\n* Jacek Pliszka <Jacek.Pliszka@fuw.edu.pl> for bug report\n\n* Michele Clark <clark@cs.unc.edu> for bug report\n\n* Jeffrey Russell Horner <jhorner@cs.utk.edu> for information on CBLAS\n\n* Rahul V. Herwadkar <RHERWADK@us.oracle.com> for testing\n\n* Trond Bo <datb@dnmi.no> for bug report\n\n* Jan Kasprzak <kas@informatics.muni.cz> for bug report\n\n* David Kaelbling <drk@sgi.com> for testing\n\n* Mark Levedahl <mlevedahl@fallschurch.esys.com> for bug report\n\n* David Billinghurst <David.Billinghurst@riotinto.com.au> for testing\n\n* Jean-Bernard ADDOR <jbaddor@sca.uqam.ca> for bug report\n\n* Fabrice Rossi <rossi@ufrmd.dauphine.fr> bug reports and suggestions\n\n* Paul Walmsley <pwalmsley@iee.org> for bug report and patch for\n  fixing matmult.\n\n* Dave Morrison <dave@bnl.gov> for advice on build procedure and\n  various patches, the diff/ numerical differentiation routines,\n  multmin documentation, and Landau distribution\n\n* Brett Viren <bviren@superk.physics.sunysb.edu> for debugging qpsrt.c.\n\n* Christopher Gabriel <cgabriel@firenze.linux.it> contributed the\n  gsl-config and gsl.m4 we use.\n\n* C M Murphy <C.M.Murphy@bath.ac.uk> patch to fix up consts in header files\n\n* Bracy H. Elton for correcting a reference in the FFT Algorithms document\n\n* Tadhg O'Meara <tadhg@net-cs.ucd.ie> for finding a bug in gsl-randist\n\n* Steve Robbins <stever@bic.mni.mcgill.ca> patch to work around FP_RND\n  problems on Tru64, testing and other patches., bug fix for nm_simplex\n  algorithm.\n\n* John Fisher <johnfish@uclink4.berkeley.edu> testing on powerpc linux \n  and support for fp-ppclinux.c\n\n* OKUJI Yoshinori <okuji@gnu.org> for a patch for fp-x86linux.c for libc5\n\n* Pablo Bianucci <pbian@pccp.com.ar> for patches to complex matrix/vectors\n\n* Toby White <tow@theor.ch.cam.ac.uk> for several patches and\nimprovements to the design, OpenBSD support\n\n* Bill Brower <wbrower@ll.mit.edu> for bug report on gsl.m4\n\n* Vladimir Kushnir <vkushnir@Alfacom.net> for ieee support for FreeBSD\n\n* F J Franklin <MEP95JFF@sheffield.ac.uk> for test reports and debugging\n\n* Keith Briggs <briggsk@info.bt.co.uk> for bug reports and code for\nthe skewed Levy alpha-stable variates gsl_ran_levy_skew\n\n* Vince <vattervi@msu.edu> for permutation iterator functions\n\n* Henry Sobotka <sobotka@axess.com> for ieee support for OS/2 and bug fixes\n\n* Remy Bruno <remy.bruno@libertysurf.fr> for bug fix\n\n* M. Lavasani <lavasani@connect.org.uk> for bug reports and testing on HPUX11\n\n* Jason Beegan <jasontd@indigo.ie> for NetBSD support\n\n* Zeger Knops <zeger@cs.uu.nl> for bug fix\n\n* Rodney Sparapani <rsparapa@mcw.edu> for Darwin support\n\n* Ramin Nakisa <raminnakisa@yahoo.com> for bug reports\n\n* Achim Gaedke <achim@zpr.uni-koeln.de> for bug reports and\nsuggestions, additional histogram code, PyGSL python interface, 2d\nhistogram statistics, bug fixes for simulated annealing\n\n* Eric Rose <erose@memot.unibe.ch> for bug report and useful tip on casting\n\n* M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> for bug reports\n\n* Albert Chin <china@thewrittenword.com> for bug reports, patches, and\nproviding HP-UX platforms for testing\n\n* Asterio Gonzalez <agonzalez@udiberica.com> for a bug report for multmin\n\n* Carlo Perassi <carlo@linux.it> for implementing the random number\ngenerators in Knuth's Seminumerical Algorithms, 3rd Ed.\n\n* Dan, Ho-Jin <hjdan@sys713.kaist.ac.kr> for divided differences interpolation\nroutines\n\n* Stefan Koch <s.koch@seh-zuelpich.de> for useful bug reports and\nfixes for the special functions\n\n* Szymon Jaroszewicz <sj@cs.umb.edu> for the combinations modules and\n  bug reports\n\n* Theis Peter Hansen <tph@com.dtu.dk> fixed unchecked status values in\nmultiroots\n\n* Jungemann Markus <Markus.Jungemann@de.bosch.com> documentation fixes\n\n* Hans E. Plesser (hans dot plesser at itf dot nlh dot no) more\nreliable implementation of gamma_inc, multifit bug fixes\n\n* Arin Chaudhuri <achaudh@unity.ncsu.edu> documentation bug reports\n\n* Karsten Howes <karsten@videotron.ca> siman bug fix\n\n* Vladimir Savichev <vlad@ariel.phys.wesleyan.edu> bug reports\n\n* Jochen Küpper <jochen@jochen-kuepper.de> doc bug fixes, additional\nconstants\n\n* John Ketchum <johnk@qualcomm.com> for bug reports for the blas library\n\n* Nicolas Darnis <ndarnis@cvf.fr> additional permutation functions\n\n* Jeff Spirko <spirko@lehigh.edu> patch for 1d minimization\n\n* David Necas (Yeti) <yeti@physics.muni.cz> bug reports and patches\nfor linear algebra, interpolation, additional tridiagonal solvers\n\n* <zunda@24i.net> for bug report\n\n* Christian T. Steigies <cts@debian.org> for documentation bug report\n\n* Atakan Gurkan <ato@northwestern.edu> for bug reports and patches for the \nrandom number generators.\n\n* David Ronis <ronis@ronispc.chem.mcgill.ca> for bug reports and\npatches\n\n* Christian T. Steigies <cts@debian.org> for a documentation fix\n\n* Teun Burgers <a.rburgers@freeler.nl> improvements to configure script\n\n* Olivier Andrieu <andrieu@ijm.jussieu.fr> bug report for Chebyschev\nmemory leak\n\n* Hiroshi Imamura <hima@cmt.is.tohoku.ac.jp> extension to psi(1+iy)\n\n* Taliver Heath <taliver@paul.rutgers.edu> keep track of best solution\nin siman_solve.\n\n* Trevor Blackwell <tlb@trevorblackwell.com> bug report test case for\nSVD d_n = 0, bug fix to mt19937 generator\n\n* Nicolas Bock <nbock@buffalo.edu> documentation bug report\n\n* Alan Aspuru-Guzik <aspuru@okra.cchem.Berkeley.edu> documentation bug report\n\n* Peter S. Christopher <peterc@midway.uchicago.edu> bug fix for\nsimulated annealing\n\n* Gene Carter <ecarter@mindspring.com> build shared libraries on MacOS X\n\n* Fabian Jakobs <fabian.jakobs@web.de> fixed a bug in\ngsl_linalg_bidiag_unpack_B, and documentation bug-fix for blas\n\n* Gavin Crooks <gec@threeplusone.com> documentation bug fix,\ndirichlet distribution, multinomial distribution\n\n* Gert Van den Eynde <gvdeynde@sckcen.be> gsl_ldexp, gsl_frexp, gsl_fcmp\n\n* Reinhold Bader <Reinhold.Bader@lrz-muenchen.de>, fixes for Hitachi SR8000\n\n* Slaven Peles <peles@cns.physics.gatech.edu>, build options for\nCompaq cc, doc bug fix\n\n* David Favis-Mortlock <d.favis-mortlock@dial.pipex.com> bug report for\ngsl_rng_taus2 seeding\n\n* Alexander Babansky <babansky@mail.ru> documentation bug report for Ei(x)\n\n* Tiago de Paula Peixoto <count0@fissionauthority.com> bug report for multifit\nmemory allocation\n\n* Adam Johansen <amj26@hermes.cam.ac.uk> bug report for eigenvalue routines\n\n* Wolfgang Hoermann <hormannw@boun.edu.tr> bug report for niederreiter qrng\n\n* Jerome Houdayer <houdayer@spht.saclay.cea.fr> bug report for taus seeding\n\n* Conrad Curry <cwcurry@orca.st.usm.edu> bug and documentation reports\n\n* Erik Schnetter <schnetter@uni-tuebingen.de> documentation bug reports\n\n* Maarten De Munck <indigo@kotnet.org> bug fix for vector/matrix get\n\n* Axel Hutt <hutt@wias-berlin.de> bug fix for QAWC integration,\ndocumentation bug fix\n\n* Martin Jansche <jansche@ling.ohio-state.edu> various bug reports\n\n* Gregory Soyez <g.soyez@ulg.ac.be> documentation bug report\n\n* Attilio Rivoldini <rivoldini@oma.be> bug report for CBLAS tests\n\n* W.M. Vissers <vissers@theochem.kun.nl> bug report for\ngsl_complex_arccsc_real\n\n* Paolo Redaelli <paolo.redaelli@libero.it> bug report for chebyshev\nfunctions\n\n* Andrew Howard <ahoward@pollux.usc.edu> bug report for gsl_ran_discrete\n\n* Heiko Bauke <Heiko.Bauke@Physik.Uni-Magdeburg.DE> bug reports and patches\nfor random number generators\n\n* Vincent Sacksteder <vincent@sacksteder.com> bug reports for MSVC7\n\n* Peter Verveer <verveer@embl-heidelberg.de> improvement to memory\nusage of MINPACK routines\n\n* Mario Pernici <Mario.Pernici@mi.infn.it> bug fix for\ngsl_combination_valid and new function gsl_permutation_memcpy,\ndoc fix for bessel functions, bug fix for gsl_sf_psi_1_int,\nbug report for gsl_permutation_canonical_to_linear, linalg\nQRPT bug reports and fixes, and many other corrections.\n\n* Fabio Brugnara <brugnara@itc.it> provided a much-needed bug\nfix for the conjugate gradient algorithm multidimensional\nminimisers.\n\n* Krzysztof Pachucki <krp@fuw.edu.pl> bug report for gsl_sf_hypergU_int\n\n* Carsten Svaneborg <svanebor@mpip-mainz.mpg.de> documentation bug report\n\n* Liguo Song <liguo.song@vanderbilt.edu> documentation bug report\n\n* Carlo Ferrigno <ferrigno@pa.iasf.cnr.it> bug report for CGS units\n\n* Giulio Bottazzi <bottazzi@sssup.it> many useful bug reports\n\n* Olaf Lenz <olenz@Physik.Uni-Bielefeld.DE> rng frwite/fread, bug reports\n\n* Jamie Lokier <jamie@shareable.org> for testing\n\n* Grant Lythe <grant@maths.leeds.ac.uk> documentation bug report\n\n* Jussi Piitulainen <jpiitula@ling.helsinki.fi> documentation bug report\n\n* Aaron Schweiger <aschweig@bu.edu> bug report for SVD/column balancing\n\n* Carlo Ferrigno <ferrigno@pa.iasf.cnr.it> bug report about const problems\n\n* Jussi Piitulainen <jpiitula@ling.helsinki.fi> documenation bug report for\ngsl_ran_hypergeometric_pdf\n\n* Bas Zoetekouw <bas@debian.org> documentation bug report\n\n* Paul Sydney <sydney@maui.net> bug report and patch for min/brent.c\n\n* Alexei Podtelezhnikov <apodtele@mccammon.ucsd.edu> patch for sphere.c\n\n* Neil Bushong <bushong@mh-4426b.ucsd.edu> documentation typo bug report\n\n* Brad Bell <brad@apl.washington.edu> documentation bug report\n\n* Andreas Schneider <1@c07.de> bug report for R250\n\n* Luigi Ballabio <luigi.ballabio@fastwebnet.it> fix m4 quoting in gsl.m4\n\n* Zbigniew Koza <zkoza@ift.uni.wroc.pl> documentation bug fix for odes\n\n* James Scott <j.scott@runbox.com> fix for linalg tests on MSVC\n\n* Rémi Butel <r.butel@epoc.u-bordeaux1.fr> fixes for multimin overflow\nconditions\n\n* Andris Pavenis <pavenis@latnet.lv> Makefile fix for EXEEXT\n\n* Daniel Webb <lists@danielwebb.us> bug report for potential cspline\ndivision by zero\n\n* Ewald Stamp <stamp@math.hu-berlin.de> bugfix for vector/swap_source.c\n\n* Joerg Wensch <wensch@informatik.uni-halle.de>  LQ decompositions\n\n* Jason Stover <jstover@sdf.lonestar.org> patch for cdf/beta.c,\ninverse cumulative distributions, discrete cumulative distributions\n\n* Ralph Menikoff <rtm@lanl.gov> bug report for gsl_sf_expint_scaled\n\n* Yoshiki <ytsunesada@yahoo.co.jp> documentation bug report\n\n* Nigel Lowry <nigel-lowry@ultra.eclipse.co.uk> documentation proofreading\n\n* Giulio Bottazzi <bottazzi@sssup.it> cdf for exponential power\ndistribution, bug reports\n\n* Tuomo Keskitalo <Tuomo.Keskitalo@HUT.Fi> many improvements to ode-initval\n\n* Britton Kerin <bkerin@asf.alaska.edu> documentation bug reports\n\n* Patricio Rojo <pato@astro.cornell.edu> patch for numerical\ninstability in interpolation integrate function\n\n* Damir Herman <herman@ncbi.nlm.nih.gov> improved accuracy of\nhistogram range calculations\n\n* John Salmon <jsalmon@thesalmons.org> bug report for gsl_cheb_eval_n_err\n\n* Dirk Eddelbuettel <edd@debian.org> for bug reports and testing, and\nmaintaining the Debian package for GSL.\n\n* Jari Häkkinen <jari@chiralcomp.com> for svd bug reports, rng bug reports\n\n* Marco Canini <marco.canini@fastwebnet.it> patch for IXP2400 Xscale\n\n* Ben Klemens <klemens@hss.caltech.edu> bug report for sorting vectors\nwith NANs\n\n* Peter Brommer <pbro@itap.physik.uni-stuttgart.de> bug report and patch\nfor Brent minimisation algorithm.\n\n* Gabriel Withington <gabriel.withington@umassmed.edu> typo in docs\n\n* Stewart V. Wright <swright+gsl@physics.adelaide.edu.au> patch for missing \nspline functions\n\n* Richard Mathar <mathar@strw.leidenuniv.nl> additional Debye\nfunctions n=5,6, handle case x==1 in 2F1.\n\n* Stefan Jahn <stefan@gruft.de>  bug fix for periodic cubic splines with n=3\n\n* Yoram Burak <yorambu@kitp.ucsb.edu> bug report for scaled bessel function In_scaled\n\n* Mario Santos <mgrsantos@ist.utl.pt> bug report for spherical bessel function \n\n* Vincent Plagnol <vincent.plagnol@normalesup.org> bug report for gsl_randist_binomial_pdf\n\n* John Houck <houck@space.mit.edu> bug report for gsl_sf_synchrotron_1\n\n* Jochen Voss <voss@seehuhn.de> ziggurat gaussian generator\n\n* John D Lamb <J.D.Lamb@btinternet.com> Marsaglia-Tsang gamma generator, bug reports\n\n* Giulio Bottazzi <giulio.bottazzi@libero.it> improved exponential\npower distribution and gsl_multifit_linear_est\n\n* Charles Karney <ckarney@sarnoff.com> added Leva bounds to gaussian ratio method generator\n\n* Torquil Sorenson <torquil@gmail.com> documentation bug fixes for FFTs\n\n* Yajun Wang <yalding@cs.ust.hk> - bug report for multifit n<p\n\n* Erik Schnetter <schnetter@cct.lsu.edu> - patch for Macos X on Intel\n\n* Lowell Johnson <ldj00@sio.midco.net> - implementation of mathieu functions\n\n* Brian Gladman <brg@gladman.plus.com> - useful bug reports\n\n* B. Lazarov <bsl@mek.dtu.dk> - compilation bug report for randist\n\n* Harald Moseby <harald.moseby@fnh.no> - special functions bug reports\n\n* Neil Harvey <neilharvey@gmail.com> - bug report for beta pdf\n\n* Felipe G. Nievinski <f.nievinski@unb.ca> - documentation bug report\n\n* Daisuke TOMINAGA <tominaga@cbrc.jp> - Japanese translation of manual and numerous corrections\n\n* Andoline Bucciolini <andoline_bucciolini@women-at-work.org> - documentation bug for BLAS\n\n* Daniel Falster <dfalster@bio.mq.edu.au> bug report for fdist_Pinv\n\n* Giancarlo Marra <giancarlo.marra@bancaditalia.it> bug report for M_PI_4\n\n* Alan Irwin <irwin@beluga.phys.uvic.ca> for sample implementation of\nimproved BFGS algorithm.\n\n* Lionel Barnett <lionelb.nospam@googlemail.com> for pointing out an\nerror in the elliptic integrals\n\n* Ed Smith-Rowland <3dw4rd@verizon.net> patch for laguerre polynomials\n\n* Katrin Wolff <katrin_wolff@gmx.de> bug report for Lambert W function\n\n* \"Heikki Orsila <heikki.orsila@iki.fi>\" cleaning up siman code\n\n* Eugene Loh <Eugene.Loh@Sun.COM> bug report for gsl_log1p\n\n* Richard Smith <Richard.Smith@Sun.COM> bug report and suggestions for\ncorrect use of isfinite\n\n* Marco Lombardi <marco.lombardi@gmail.com> bug report for svd\n\n* I J Wilson <i.j.wilson@newcastle.ac.uk> bug report for dirichlet\nfunction\n\n* Justin Lenzo <j-lenzo@northwestern.edu> bug reports for\nvector/matrix tests.\n\n* Sebastian Queißer <sebastian@queisser-net.de> bug report for\ngsl_cdf_beta_Pinv\n\n* Andries Brouwer <Andries.Brouwer@cwi.nl> bug report for\nunderflow in symmetric eigenvalues\n\n* Mingxi Wu <mwu@cise.ufl.edu> bug report for multinomial pdf\n\n* Chris Mihelich <umbricola@gmail.com> bug reports and suggestions for\ngsl_ldexp and gsl_frexp\n\n* Frank Reininghaus <frank78ac@googlemail.com> complex polynomial\nevaluation and ode improvements\n\n* Jason Coy <funkdart@gmail.com> optimisation for dwt.c\n\n* Richard Guenther <rguenther@suse.de> bug reports\n\n* Stijn van Dongen <svd@sanger.ac.uk> bug fix for overflow in\n  gsl_cdf_hypergeometric_{P,Q}\n\n*  Claude Dion <claude.dion@tp.umu.se> documentation bug reports\n\n* Michael Kuklik <mkuklik@gmail.com> bug report for simplex\n\n* Paul Accisano, bug report and fix for cyclic solver\n\n* Thomas Weber <thomas.weber.mail@gmail.com> bug and patch for interp\n  accelerator\n\n* Lori A. Pritchett-Sheats bug report for vegas chisq.\n\n* Frank Wang <frank.wang@validusre.bm> bug report for gsl_ran_gamma_knuth.\n\n* Peter Johansson <trojkan@gmail.com> fix for make install prefix=PREFIX\n\n* Taneli Kalvas <taneli.kalvas@jyu.fi> bug report for odes\n\n* Marco Maggi <mrc.mgg@gmail.com> bug fix for gsl_blas_drotm\n\n* Mateus Araújo Santos - bug fix for LM set\n\n* James Howse - quad_golden minimisation algorithm\n\n* Marc JOURDAIN - polynomial derivatives function\n\n* Andrew Steiner - for bug reports\n\n* Ettl Martin - bug report, rk4 memory\n\n* Yevgeniy Naumovich - bspline allocators fix\n\n* Huan Wu - gsl_linalg_complex_cholesky_invert\n\n* Ralf Wildenhues - numerous proofreading corrections\n\n* Thomas Tanner <tanner@gmx.de> - bug report for gsl_sf_beta_inc\n\n* Sam Mason <sam@samason.me.uk> - bug fix for gsl_pow_int\n\n* José Luis García Pallero <jgpallero@gmail.com> - error checking for GSL cblas\n\n* Teemu Ikonen <tpikonen@gmail.com> patch for gsl_ran_chisq_pdf\n\n* Evgeny Kurbatov <EvgenyKurbatov@yandex.ru> - patch for error\n  handling in interpolation routines\n\n* Michel Kern <Michel.Kern@inria.fr> - fix for singular Jacobian in\n  Newton solver\n\n* Nikolay Simakov <nsimakov@andrew.cmu.edu> - bug report for gsl_eigen_jacobi\n\n* Jim Ward - numerous bug reports and useful suggestions\n\n* Josh Neil & Curt Hash - patch for negative binomial\n\n* Maximilian Treiber <maximilian.treiber@physik.lmu.de> - bug report for gsl_sf_lncosh\n\n* Martin Landriau <landriau@mpe.mpg.de> bug report for 3j coupling\n\n* Grigory I. Rubtsov <grisha@ms2.inr.ac.ru> - extend range of 3j\n\n* Matthias Sitte <matthias.sitte@gmail.com> - bug report and patch for\n  failing complex matrix IO routines\n\n* Raymond Rogers <raymond.rogers72@gmail.com> - bug fixes for confluent\n  hypergeometric functions\n"
  },
  {
    "path": "gsl/_README",
    "content": "This directory, and subdirectories, contains a gutted version of the\nGNU Scientific Library (GSL) for use within SLiM and Eidos.  The goal\nis to allow this project to build without an external dependency on\nthe GSL, so people don't have to worry about how to install the GSL.\n\nThis distribution is based upon version 2.5 of the GSL.  The code is\nmostly unmodified.  Header references have been changed from <> to \"\",\nsome #pragmas have been added to mask warnings generated by the GSL\ncode that look innocent, and a few other small differences exist.\nMostly, though, the code is untouched except for the fact that most\nof the source files of the GSL are missing in this distribution, and\nin the source files that are present, large swathes of code are often\ndeleted; we took only what we needed for SLiM and Eidos.\n\nThis directory includes a config.h file that was built on OS X 10.11.3\nwith Xcode 7.2; in different environments you might need to change the\nconfig.h file to whatever your local config.h file would be.  To do\nthat, get the GSL code from GNU, and run ./configure in its directory.\nThat should generate a config.h file that you can copy over the version\nin this directory.\n\nThe standard GNU warranty and license are included in this directory,\nand apply to this distribution of the GSL.\n"
  },
  {
    "path": "gsl/blas/blas.c",
    "content": "/* blas/blas.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2009 Gerard Jungman & Brian \n * Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* GSL implementation of BLAS operations for vectors and dense\n * matrices.  Note that GSL native storage is row-major.  */\n\n#include \"config.h\"\n//#include <gsl/gsl_math.h>\n//#include <gsl/gsl_errno.h>\n//#include <gsl/gsl_cblas.h>\n//#include <gsl/gsl_cblas.h>\n//#include <gsl/gsl_blas_types.h>\n#include \"gsl_blas.h\"\n\n/* ========================================================================\n * Level 1\n * ========================================================================\n */\n\n/* CBLAS defines vector sizes in terms of int. GSL defines sizes in\n terms of size_t, so we need to convert these into integers.  There\n is the possibility of overflow here. FIXME: Maybe this could be\n caught */\n\n#define INT(X) ((int)(X))\n\n\nint\ngsl_blas_ddot (const gsl_vector * X, const gsl_vector * Y, double *result)\n{\n\tif (X->size == Y->size)\n\t{\n\t\t*result =\n\t\tcblas_ddot (INT (X->size), X->data, INT (X->stride), Y->data,\n\t\t\t\t\tINT (Y->stride));\n\t\treturn GSL_SUCCESS;\n\t}\n\telse\n\t{\n\t\tGSL_ERROR (\"invalid length\", GSL_EBADLEN);\n\t}\n}\n\nint\ngsl_blas_daxpy (double alpha, const gsl_vector * X, gsl_vector * Y)\n{\n  if (X->size == Y->size)\n\t{\n\t  cblas_daxpy (INT (X->size), alpha, X->data, INT (X->stride), Y->data,\n\t\t\t\t   INT (Y->stride));\n\t  return GSL_SUCCESS;\n\t}\n  else\n\t{\n\t  GSL_ERROR (\"invalid length\", GSL_EBADLEN);\n\t}\n}\n\nint\ngsl_blas_dgemv (CBLAS_TRANSPOSE_t TransA, double alpha, const gsl_matrix * A,\n\t\t\t\tconst gsl_vector * X, double beta, gsl_vector * Y)\n{\n\tconst size_t M = A->size1;\n\tconst size_t N = A->size2;\n\t\n\tif ((TransA == CblasNoTrans && N == X->size && M == Y->size)\n\t\t|| (TransA == CblasTrans && M == X->size && N == Y->size))\n\t{\n\t\tcblas_dgemv (CblasRowMajor, TransA, INT (M), INT (N), alpha, A->data,\n\t\t\t\t\t INT (A->tda), X->data, INT (X->stride), beta, Y->data,\n\t\t\t\t\t INT (Y->stride));\n\t\treturn GSL_SUCCESS;\n\t}\n\telse\n\t{\n\t\tGSL_ERROR (\"invalid length\", GSL_EBADLEN);\n\t}\n}\n\nint\ngsl_blas_dtrmv (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                CBLAS_DIAG_t Diag, const gsl_matrix * A, gsl_vector * X)\n{\n  const size_t M = A->size1;\n  const size_t N = A->size2;\n\n  if (M != N)\n    {\n      GSL_ERROR (\"matrix must be square\", GSL_ENOTSQR);\n    }\n  else if (N != X->size)\n    {\n      GSL_ERROR (\"invalid length\", GSL_EBADLEN);\n    }\n\n  cblas_dtrmv (CblasRowMajor, Uplo, TransA, Diag, INT (N), A->data,\n               INT (A->tda), X->data, INT (X->stride));\n  return GSL_SUCCESS;\n}\n\nint\ngsl_blas_dtrsv (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n\t\t\t\tCBLAS_DIAG_t Diag, const gsl_matrix * A, gsl_vector * X)\n{\n\tconst size_t M = A->size1;\n\tconst size_t N = A->size2;\n\t\n\tif (M != N)\n\t{\n\t\tGSL_ERROR (\"matrix must be square\", GSL_ENOTSQR);\n\t}\n\telse if (N != X->size)\n\t{\n\t\tGSL_ERROR (\"invalid length\", GSL_EBADLEN);\n\t}\n\t\n\tcblas_dtrsv (CblasRowMajor, Uplo, TransA, Diag, INT (N), A->data,\n\t\t\t\t INT (A->tda), X->data, INT (X->stride));\n\treturn GSL_SUCCESS;\n}\n\n\n\n"
  },
  {
    "path": "gsl/blas/gsl_blas.h",
    "content": "/* blas/gsl_blas.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * Author:  G. Jungman\n */\n#ifndef __GSL_BLAS_H__\n#define __GSL_BLAS_H__\n\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n\n#include \"gsl_blas_types.h\"\n\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* ========================================================================\n * Level 1\n * ========================================================================\n */\n\n/*int gsl_blas_sdsdot (float alpha,\n                     const gsl_vector_float * X,\n                     const gsl_vector_float * Y,\n                     float * result\n                     );\n\nint gsl_blas_dsdot (const gsl_vector_float * X,\n                    const gsl_vector_float * Y,\n                    double * result\n                    );\n\nint gsl_blas_sdot (const gsl_vector_float * X,\n                   const gsl_vector_float * Y,\n                   float * result\n                   );*/\n\nint gsl_blas_ddot (const gsl_vector * X,\n                   const gsl_vector * Y,\n                   double * result\n                   );\n\n/*\nint  gsl_blas_cdotu (const gsl_vector_complex_float * X,\n                     const gsl_vector_complex_float * Y,\n                     gsl_complex_float * dotu);\n\nint  gsl_blas_cdotc (const gsl_vector_complex_float * X,\n                     const gsl_vector_complex_float * Y,\n                     gsl_complex_float * dotc);\n\nint  gsl_blas_zdotu (const gsl_vector_complex * X,\n                     const gsl_vector_complex * Y,\n                     gsl_complex * dotu);\n\nint  gsl_blas_zdotc (const gsl_vector_complex * X,\n                     const gsl_vector_complex * Y,\n                     gsl_complex * dotc);\n\n\nfloat  gsl_blas_snrm2  (const gsl_vector_float * X);\nfloat  gsl_blas_sasum  (const gsl_vector_float * X);\ndouble gsl_blas_dnrm2  (const gsl_vector * X);\ndouble gsl_blas_dasum  (const gsl_vector * X);\nfloat  gsl_blas_scnrm2 (const gsl_vector_complex_float * X);\nfloat  gsl_blas_scasum (const gsl_vector_complex_float * X);\ndouble gsl_blas_dznrm2 (const gsl_vector_complex * X);\ndouble gsl_blas_dzasum (const gsl_vector_complex * X);\n\n\nCBLAS_INDEX_t gsl_blas_isamax (const gsl_vector_float * X);\nCBLAS_INDEX_t gsl_blas_idamax (const gsl_vector * X);\nCBLAS_INDEX_t gsl_blas_icamax (const gsl_vector_complex_float * X);\nCBLAS_INDEX_t gsl_blas_izamax (const gsl_vector_complex * X);\n\n\nint  gsl_blas_sswap (gsl_vector_float * X,\n                     gsl_vector_float * Y);\n\nint  gsl_blas_scopy (const gsl_vector_float * X,\n                     gsl_vector_float * Y);\n\nint  gsl_blas_saxpy (float alpha,\n                     const gsl_vector_float * X,\n                     gsl_vector_float * Y);\n\nint  gsl_blas_dswap (gsl_vector * X,\n                     gsl_vector * Y);\n\nint  gsl_blas_dcopy (const gsl_vector * X,\n                     gsl_vector * Y);*/\n\nint  gsl_blas_daxpy (double alpha,\n                     const gsl_vector * X,\n                     gsl_vector * Y);\n\n/*int  gsl_blas_cswap (gsl_vector_complex_float * X,\n                     gsl_vector_complex_float * Y);\n\nint  gsl_blas_ccopy (const gsl_vector_complex_float * X,\n                     gsl_vector_complex_float * Y);\n\nint  gsl_blas_caxpy (const gsl_complex_float alpha,\n                     const gsl_vector_complex_float * X,\n                     gsl_vector_complex_float * Y);\n\nint  gsl_blas_zswap (gsl_vector_complex * X,\n                     gsl_vector_complex * Y);\n\nint  gsl_blas_zcopy (const gsl_vector_complex * X,\n                     gsl_vector_complex * Y);\n\nint  gsl_blas_zaxpy (const gsl_complex alpha,\n                     const gsl_vector_complex * X,\n                     gsl_vector_complex * Y);\n\n\nint  gsl_blas_srotg (float a[], float b[], float c[], float s[]);\n\nint  gsl_blas_srotmg (float d1[], float d2[], float b1[], float b2, float P[]);\n\nint  gsl_blas_srot (gsl_vector_float * X,\n                    gsl_vector_float * Y,\n                    float c, float s);\n\nint  gsl_blas_srotm (gsl_vector_float * X,\n                     gsl_vector_float * Y,\n                     const float P[]);\n\nint  gsl_blas_drotg (double a[], double b[], double c[], double s[]);\n\nint  gsl_blas_drotmg (double d1[], double d2[], double b1[],\n                      double b2, double P[]);\n\nint  gsl_blas_drot (gsl_vector * X,\n                    gsl_vector * Y,\n                    const double c, const double s);\n\nint  gsl_blas_drotm (gsl_vector * X,\n                     gsl_vector * Y,\n                     const double P[]);\n\n\nvoid gsl_blas_sscal  (float  alpha, gsl_vector_float * X);\nvoid gsl_blas_dscal  (double alpha, gsl_vector * X);\nvoid gsl_blas_cscal  (const gsl_complex_float alpha, gsl_vector_complex_float * X);\nvoid gsl_blas_zscal  (const gsl_complex alpha, gsl_vector_complex * X);\nvoid gsl_blas_csscal (float  alpha, gsl_vector_complex_float * X);\nvoid gsl_blas_zdscal (double alpha, gsl_vector_complex * X);*/\n\n\n/* ===========================================================================\n * Level 2\n * ===========================================================================\n */\n\n/*\n * Routines with standard 4 prefixes (S, D, C, Z)\n */\n/*int  gsl_blas_sgemv (CBLAS_TRANSPOSE_t TransA,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     const gsl_vector_float * X,\n                     float beta,\n                     gsl_vector_float * Y);\n\nint  gsl_blas_strmv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_float * A,\n                     gsl_vector_float * X);\n\nint  gsl_blas_strsv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_float * A,\n                     gsl_vector_float * X);*/\n\nint  gsl_blas_dgemv (CBLAS_TRANSPOSE_t TransA,\n                     double alpha,\n                     const gsl_matrix * A,\n                     const gsl_vector * X,\n                     double beta,\n                     gsl_vector * Y);\n\nint  gsl_blas_dtrmv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix * A,\n                     gsl_vector * X);\n\nint  gsl_blas_dtrsv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix * A,\n                     gsl_vector * X);\n\n/*int  gsl_blas_cgemv (CBLAS_TRANSPOSE_t TransA,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_vector_complex_float * X,\n                     const gsl_complex_float beta,\n                     gsl_vector_complex_float * Y);\n\nint  gsl_blas_ctrmv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_complex_float * A,\n                     gsl_vector_complex_float * X);\n\nint  gsl_blas_ctrsv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_complex_float * A,\n                     gsl_vector_complex_float * X);\n\nint  gsl_blas_zgemv (CBLAS_TRANSPOSE_t TransA,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_vector_complex * X,\n                     const gsl_complex beta,\n                     gsl_vector_complex * Y);\n\nint  gsl_blas_ztrmv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_complex * A,\n                     gsl_vector_complex * X);\n\nint  gsl_blas_ztrsv (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,\n                     const gsl_matrix_complex * A,\n                     gsl_vector_complex *X);*/\n\n/*\n * Routines with S and D prefixes only\n */\n/*int  gsl_blas_ssymv (CBLAS_UPLO_t Uplo,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     const gsl_vector_float * X,\n                     float beta,\n                     gsl_vector_float * Y);\n\nint  gsl_blas_sger (float alpha,\n                    const gsl_vector_float * X,\n                    const gsl_vector_float * Y,\n                    gsl_matrix_float * A);\n\nint  gsl_blas_ssyr (CBLAS_UPLO_t Uplo,\n                    float alpha,\n                    const gsl_vector_float * X,\n                    gsl_matrix_float * A);\n\nint  gsl_blas_ssyr2 (CBLAS_UPLO_t Uplo,\n                     float alpha,\n                     const gsl_vector_float * X,\n                     const gsl_vector_float * Y,\n                     gsl_matrix_float * A);\n\nint  gsl_blas_dsymv (CBLAS_UPLO_t Uplo,\n                     double alpha,\n                     const gsl_matrix * A,\n                     const gsl_vector * X,\n                     double beta,\n                     gsl_vector * Y);\nint  gsl_blas_dger (double alpha,\n                    const gsl_vector * X,\n                    const gsl_vector * Y,\n                    gsl_matrix * A);\n\nint  gsl_blas_dsyr (CBLAS_UPLO_t Uplo,\n                    double alpha,\n                    const gsl_vector * X,\n                    gsl_matrix * A);\n\nint  gsl_blas_dsyr2 (CBLAS_UPLO_t Uplo,\n                     double alpha,\n                     const gsl_vector * X,\n                     const gsl_vector * Y,\n                     gsl_matrix * A);*/\n\n/*\n * Routines with C and Z prefixes only\n */\n\n/*int  gsl_blas_chemv (CBLAS_UPLO_t Uplo,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_vector_complex_float * X,\n                     const gsl_complex_float beta,\n                     gsl_vector_complex_float * Y);\n\nint  gsl_blas_cgeru (const gsl_complex_float alpha,\n                     const gsl_vector_complex_float * X,\n                     const gsl_vector_complex_float * Y,\n                     gsl_matrix_complex_float * A);\n\nint  gsl_blas_cgerc (const gsl_complex_float alpha,\n                     const gsl_vector_complex_float * X,\n                     const gsl_vector_complex_float * Y,\n                     gsl_matrix_complex_float * A);\n\nint  gsl_blas_cher (CBLAS_UPLO_t Uplo,\n                    float alpha,\n                    const gsl_vector_complex_float * X,\n                    gsl_matrix_complex_float * A);\n\nint  gsl_blas_cher2 (CBLAS_UPLO_t Uplo,\n                     const gsl_complex_float alpha,\n                     const gsl_vector_complex_float * X,\n                     const gsl_vector_complex_float * Y,\n                     gsl_matrix_complex_float * A);\n\nint  gsl_blas_zhemv (CBLAS_UPLO_t Uplo,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_vector_complex * X,\n                     const gsl_complex beta,\n                     gsl_vector_complex * Y);\n\nint  gsl_blas_zgeru (const gsl_complex alpha,\n                     const gsl_vector_complex * X,\n                     const gsl_vector_complex * Y,\n                     gsl_matrix_complex * A);\n\nint  gsl_blas_zgerc (const gsl_complex alpha,\n                     const gsl_vector_complex * X,\n                     const gsl_vector_complex * Y,\n                     gsl_matrix_complex * A);\n\nint  gsl_blas_zher (CBLAS_UPLO_t Uplo,\n                    double alpha,\n                    const gsl_vector_complex * X,\n                    gsl_matrix_complex * A);\n\nint  gsl_blas_zher2 (CBLAS_UPLO_t Uplo,\n                     const gsl_complex alpha,\n                     const gsl_vector_complex * X,\n                     const gsl_vector_complex * Y,\n                     gsl_matrix_complex * A);*/\n\n/*\n * ===========================================================================\n * Prototypes for level 3 BLAS\n * ===========================================================================\n */\n\n/*\n * Routines with standard 4 prefixes (S, D, C, Z)\n */\n/*int  gsl_blas_sgemm (CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_TRANSPOSE_t TransB,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     const gsl_matrix_float * B,\n                     float beta,\n                     gsl_matrix_float * C);\n\nint  gsl_blas_ssymm (CBLAS_SIDE_t Side, CBLAS_UPLO_t Uplo,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     const gsl_matrix_float * B,\n                     float beta,\n                     gsl_matrix_float * C);\n\nint  gsl_blas_ssyrk (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t Trans,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     float beta,\n                     gsl_matrix_float * C);\n\nint  gsl_blas_ssyr2k (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t Trans,\n                      float alpha,\n                      const gsl_matrix_float * A,\n                      const gsl_matrix_float * B,\n                      float beta,\n                      gsl_matrix_float * C);\n\nint  gsl_blas_strmm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     gsl_matrix_float * B);\n\nint  gsl_blas_strsm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     float alpha,\n                     const gsl_matrix_float * A,\n                     gsl_matrix_float * B);\n\nint  gsl_blas_dgemm (CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_TRANSPOSE_t TransB,\n                     double alpha,\n                     const gsl_matrix * A,\n                     const gsl_matrix * B,\n                     double beta,\n                     gsl_matrix * C);\n\nint  gsl_blas_dsymm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo,\n                     double alpha,\n                     const gsl_matrix * A,\n                     const gsl_matrix * B,\n                     double beta,\n                     gsl_matrix * C);\n\nint  gsl_blas_dsyrk (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t Trans,\n                     double alpha,\n                     const gsl_matrix * A,\n                     double beta,\n                     gsl_matrix * C);\n\nint  gsl_blas_dsyr2k (CBLAS_UPLO_t Uplo,\n                      CBLAS_TRANSPOSE_t Trans,\n                      double alpha,\n                      const  gsl_matrix * A,\n                      const  gsl_matrix * B,\n                      double beta,\n                      gsl_matrix * C);\n\nint  gsl_blas_dtrmm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     double alpha,\n                     const gsl_matrix * A,\n                     gsl_matrix * B);\n\nint  gsl_blas_dtrsm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     double alpha,\n                     const gsl_matrix * A,\n                     gsl_matrix * B);\n\nint  gsl_blas_cgemm (CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_TRANSPOSE_t TransB,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_matrix_complex_float * B,\n                     const gsl_complex_float beta,\n                     gsl_matrix_complex_float * C);\n\nint  gsl_blas_csymm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_matrix_complex_float * B,\n                     const gsl_complex_float beta,\n                     gsl_matrix_complex_float * C);\n\nint  gsl_blas_csyrk (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t Trans,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_complex_float beta,\n                     gsl_matrix_complex_float * C);\n\nint  gsl_blas_csyr2k (CBLAS_UPLO_t Uplo,\n                      CBLAS_TRANSPOSE_t Trans,\n                      const gsl_complex_float alpha,\n                      const gsl_matrix_complex_float * A,\n                      const gsl_matrix_complex_float * B,\n                      const gsl_complex_float beta,\n                      gsl_matrix_complex_float * C);\n\nint  gsl_blas_ctrmm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     gsl_matrix_complex_float * B);\n\nint  gsl_blas_ctrsm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     gsl_matrix_complex_float * B);\n\nint  gsl_blas_zgemm (CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_TRANSPOSE_t TransB,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_matrix_complex * B,\n                     const gsl_complex beta,\n                     gsl_matrix_complex * C);\n\nint  gsl_blas_zsymm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_matrix_complex * B,\n                     const gsl_complex beta,\n                     gsl_matrix_complex * C);\n\nint  gsl_blas_zsyrk (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t Trans,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_complex beta,\n                     gsl_matrix_complex * C);\n\nint  gsl_blas_zsyr2k (CBLAS_UPLO_t Uplo,\n                      CBLAS_TRANSPOSE_t Trans,\n                      const gsl_complex alpha,\n                      const gsl_matrix_complex * A,\n                      const gsl_matrix_complex * B,\n                      const gsl_complex beta,\n                      gsl_matrix_complex *C);\n\nint  gsl_blas_ztrmm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     gsl_matrix_complex * B);\n\nint  gsl_blas_ztrsm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,\n                     CBLAS_DIAG_t Diag,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     gsl_matrix_complex * B);*/\n\n/*\n * Routines with prefixes C and Z only\n */\n/*int  gsl_blas_chemm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo,\n                     const gsl_complex_float alpha,\n                     const gsl_matrix_complex_float * A,\n                     const gsl_matrix_complex_float * B,\n                     const gsl_complex_float beta,\n                     gsl_matrix_complex_float * C);\n\nint  gsl_blas_cherk (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t Trans,\n                     float alpha,\n                     const gsl_matrix_complex_float * A,\n                     float beta,\n                     gsl_matrix_complex_float * C);\n\nint  gsl_blas_cher2k (CBLAS_UPLO_t Uplo,\n                      CBLAS_TRANSPOSE_t Trans,\n                      const gsl_complex_float alpha,\n                      const gsl_matrix_complex_float * A,\n                      const gsl_matrix_complex_float * B,\n                      float beta,\n                      gsl_matrix_complex_float * C);\n\nint  gsl_blas_zhemm (CBLAS_SIDE_t Side,\n                     CBLAS_UPLO_t Uplo,\n                     const gsl_complex alpha,\n                     const gsl_matrix_complex * A,\n                     const gsl_matrix_complex * B,\n                     const gsl_complex beta,\n                     gsl_matrix_complex * C);\n\nint  gsl_blas_zherk (CBLAS_UPLO_t Uplo,\n                     CBLAS_TRANSPOSE_t Trans,\n                     double alpha,\n                     const gsl_matrix_complex * A,\n                     double beta,\n                     gsl_matrix_complex * C);\n\nint  gsl_blas_zher2k (CBLAS_UPLO_t Uplo,\n                      CBLAS_TRANSPOSE_t Trans,\n                      const gsl_complex alpha,\n                      const gsl_matrix_complex * A,\n                      const gsl_matrix_complex * B,\n                      double beta,\n                      gsl_matrix_complex * C);*/\n\n\n__END_DECLS\n\n#endif /* __GSL_BLAS_H__ */\n"
  },
  {
    "path": "gsl/blas/gsl_blas_types.h",
    "content": "/* blas/gsl_blas_types.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * Author:  G. Jungman\n */\n/* Based on draft BLAST C interface specification  [Jul 7 1998]\n */\n#ifndef __GSL_BLAS_TYPES_H__\n#define __GSL_BLAS_TYPES_H__\n\n#include \"gsl_cblas.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ntypedef  CBLAS_INDEX  CBLAS_INDEX_t;\ntypedef  enum CBLAS_ORDER       CBLAS_ORDER_t;\ntypedef  enum CBLAS_TRANSPOSE   CBLAS_TRANSPOSE_t;\ntypedef  enum CBLAS_UPLO        CBLAS_UPLO_t;\ntypedef  enum CBLAS_DIAG        CBLAS_DIAG_t;\ntypedef  enum CBLAS_SIDE        CBLAS_SIDE_t;\n\n/* typedef  gsl_complex  COMPLEX; */\n\n__END_DECLS\n\n\n#endif /* __GSL_BLAS_TYPES_H__ */\n"
  },
  {
    "path": "gsl/block/gsl_block.h",
    "content": "#ifndef __GSL_BLOCK_H__\n#define __GSL_BLOCK_H__\n\n//#include <gsl/gsl_block_complex_long_double.h>\n//#include <gsl/gsl_block_complex_double.h>\n//#include <gsl/gsl_block_complex_float.h>\n\n//#include <gsl/gsl_block_long_double.h>\n#include \"gsl_block_double.h\"\n//#include <gsl/gsl_block_float.h>\n\n//#include <gsl/gsl_block_ulong.h>\n//#include <gsl/gsl_block_long.h>\n\n//#include <gsl/gsl_block_uint.h>\n//#include <gsl/gsl_block_int.h>\n\n//#include <gsl/gsl_block_ushort.h>\n//#include <gsl/gsl_block_short.h>\n\n//#include <gsl/gsl_block_uchar.h>\n//#include <gsl/gsl_block_char.h>\n\n#endif /* __GSL_BLOCK_H__ */\n"
  },
  {
    "path": "gsl/block/gsl_block_double.h",
    "content": "/* block/gsl_block_double.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_BLOCK_DOUBLE_H__\n#define __GSL_BLOCK_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nstruct gsl_block_struct\n{\n  size_t size;\n  double *data;\n};\n\ntypedef struct gsl_block_struct gsl_block;\n\ngsl_block *gsl_block_alloc (const size_t n);\ngsl_block *gsl_block_calloc (const size_t n);\nvoid gsl_block_free (gsl_block * b);\n\nint gsl_block_fread (FILE * stream, gsl_block * b);\nint gsl_block_fwrite (FILE * stream, const gsl_block * b);\nint gsl_block_fscanf (FILE * stream, gsl_block * b);\nint gsl_block_fprintf (FILE * stream, const gsl_block * b, const char *format);\n\nint gsl_block_raw_fread (FILE * stream, double * b, const size_t n, const size_t stride);\nint gsl_block_raw_fwrite (FILE * stream, const double * b, const size_t n, const size_t stride);\nint gsl_block_raw_fscanf (FILE * stream, double * b, const size_t n, const size_t stride);\nint gsl_block_raw_fprintf (FILE * stream, const double * b, const size_t n, const size_t stride, const char *format);\n\nsize_t gsl_block_size (const gsl_block * b);\ndouble * gsl_block_data (const gsl_block * b);\n\n__END_DECLS\n\n#endif /* __GSL_BLOCK_DOUBLE_H__ */\n"
  },
  {
    "path": "gsl/block/gsl_check_range.h",
    "content": "/* vector/gsl_check_range.h\n * \n * Copyright (C) 2003, 2004, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_CHECK_RANGE_H__\n#define __GSL_CHECK_RANGE_H__\n\n#include <stdlib.h>\n#include \"gsl_types.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nGSL_VAR int gsl_check_range;\n\n/* Turn range checking on by default, unless the user defines\n   GSL_RANGE_CHECK_OFF, or defines GSL_RANGE_CHECK to 0 explicitly */\n\n#ifdef GSL_RANGE_CHECK_OFF\n# ifndef GSL_RANGE_CHECK\n#  define GSL_RANGE_CHECK 0\n# else\n#  error \"cannot set both GSL_RANGE_CHECK and GSL_RANGE_CHECK_OFF\"\n# endif\n#else\n# ifndef GSL_RANGE_CHECK\n#  define GSL_RANGE_CHECK 1\n# endif\n#endif\n\n__END_DECLS\n\n#endif /* __GSL_CHECK_RANGE_H__ */\n"
  },
  {
    "path": "gsl/block/init.c",
    "content": "#include \"config.h\"\n#include <stdlib.h>\n#include <string.h>\n#include \"gsl_block.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/block/init_source.inc",
    "content": "/* block/init_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nTYPE (gsl_block) *\nFUNCTION (gsl_block, alloc) (const size_t n)\n{\n  TYPE (gsl_block) * b;\n\n  b = (TYPE (gsl_block) *) malloc (sizeof (TYPE (gsl_block)));\n\n  if (b == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for block struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  b->data = (ATOMIC *) malloc (MULTIPLICITY * n * sizeof (ATOMIC));\n\n  if (b->data == 0 && n > 0) /* malloc may return NULL when n == 0 */\n    {\n      free (b);         /* exception in constructor, avoid memory leak */\n\n      GSL_ERROR_VAL (\"failed to allocate space for block data\",\n                        GSL_ENOMEM, 0);\n    }\n\n  b->size = n;\n\n  return b;\n}\n\nTYPE (gsl_block) *\nFUNCTION (gsl_block, calloc) (const size_t n)\n{\n  size_t i;\n\n  TYPE (gsl_block) * b = FUNCTION (gsl_block, alloc) (n);\n\n  if (b == 0)\n    return 0;\n\n  /* initialize block to zero; the memset call takes care of padding bytes */\n  memset(b->data, 0, MULTIPLICITY * n * sizeof(ATOMIC));\n\n  for (i = 0; i < MULTIPLICITY * n; i++)\n    {\n      b->data[i] = 0;\n    }\n\n  return b;\n}\n\nvoid\nFUNCTION (gsl_block, free) (TYPE (gsl_block) * b)\n{\n  RETURN_IF_NULL (b);\n  free (b->data);\n  free (b);\n}\n"
  },
  {
    "path": "gsl/build.h",
    "content": "/* Compile subsequent inline functions as static functions */\n\n#ifdef __GSL_BUILD_H__\n#error build.h must not be included multiple times\n#endif\n\n#define __GSL_BUILD_H__\n\n#ifdef COMPILE_INLINE_STATIC\n#ifndef HIDE_INLINE_STATIC  /* skip if inline functions are hidden */\n\n#undef __GSL_INLINE_H__\n#define __GSL_INLINE_H__  /* first, ignore the gsl_inline.h header file */\n\n#undef INLINE_DECL\n#define INLINE_DECL       /* disable inline in declarations */\n\n#undef INLINE_FUN\n#define INLINE_FUN        /* disable inline in definitions */\n\n#ifndef HAVE_INLINE       /* enable compilation of definitions in .h files */\n#define HAVE_INLINE\n#endif     \n\n/* Compile range checking code for inline functions used in the library */\n#undef GSL_RANGE_CHECK\n#define GSL_RANGE_CHECK 1\n\n/* Use the global variable gsl_check_range to enable/disable range checking at\n   runtime */\n#undef GSL_RANGE_COND\n#define GSL_RANGE_COND(x) (gsl_check_range && (x))\n\n#endif\n#else \n#error must be called with COMPILE_INLINE_STATIC\n#endif\n"
  },
  {
    "path": "gsl/cblas/cblas.h",
    "content": "#define INDEX int\n#define OFFSET(N, incX) ((incX) > 0 ?  0 : ((N) - 1) * (-(incX)))\n#define BLAS_ERROR(x)  cblas_xerbla(0, __FILE__, x); \n\n#define CONJUGATE(x) ((x) == CblasConjTrans)\n#define TRANSPOSE(x) ((x) == CblasTrans || (x) == CblasConjTrans)\n#define UPPER(x) ((x) == CblasUpper)\n#define LOWER(x) ((x) == CblasLower)\n\n/* Handling of packed complex types... */\n\n#define REAL(a,i) (((BASE *) a)[2*(i)])\n#define IMAG(a,i) (((BASE *) a)[2*(i)+1])\n\n#define REAL0(a) (((BASE *)a)[0])\n#define IMAG0(a) (((BASE *)a)[1])\n\n#define CONST_REAL(a,i) (((const BASE *) a)[2*(i)])\n#define CONST_IMAG(a,i) (((const BASE *) a)[2*(i)+1])\n\n#define CONST_REAL0(a) (((const BASE *)a)[0])\n#define CONST_IMAG0(a) (((const BASE *)a)[1])\n\n\n#define GB(KU,KL,lda,i,j) ((KU+1+(i-j))*lda + j)\n\n#define TRCOUNT(N,i) ((((i)+1)*(2*(N)-(i)))/2)\n\n/* #define TBUP(N,i,j) */\n/* #define TBLO(N,i,j) */\n\n#define TPUP(N,i,j) (TRCOUNT(N,(i)-1)+(j)-(i))\n#define TPLO(N,i,j) (((i)*((i)+1))/2 + (j))\n\n"
  },
  {
    "path": "gsl/cblas/daxpy.c",
    "content": "#include \"gsl_math.h\"\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n\nvoid\ncblas_daxpy (const int N, const double alpha, const double *X, const int incX,\n             double *Y, const int incY)\n{\n#define BASE double\n#include \"source_axpy_r.h\"\n#undef BASE\n}\n"
  },
  {
    "path": "gsl/cblas/ddot.c",
    "content": "#include \"gsl_math.h\"\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n\ndouble\ncblas_ddot (const int N, const double *X, const int incX, const double *Y,\n            const int incY)\n{\n#define INIT_VAL  0.0\n#define ACC_TYPE  double\n#define BASE double\n#include \"source_dot_r.h\"\n#undef ACC_TYPE\n#undef BASE\n#undef INIT_VAL\n}\n"
  },
  {
    "path": "gsl/cblas/dgemv.c",
    "content": "#include \"gsl_math.h\"\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n#include \"error_cblas_l2.h\"\n\nvoid\ncblas_dgemv (const enum CBLAS_ORDER order, const enum CBLAS_TRANSPOSE TransA,\n             const int M, const int N, const double alpha, const double *A,\n             const int lda, const double *X, const int incX,\n             const double beta, double *Y, const int incY)\n{\n#define BASE double\n#include \"source_gemv_r.h\"\n#undef BASE\n}\n"
  },
  {
    "path": "gsl/cblas/dtrmv.c",
    "content": "#include \"gsl_math.h\"\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n#include \"error_cblas_l2.h\"\n\nvoid\ncblas_dtrmv (const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n             const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n             const int N, const double *A, const int lda, double *X,\n             const int incX)\n{\n#define BASE double\n#include \"source_trmv_r.h\"\n#undef BASE\n}\n"
  },
  {
    "path": "gsl/cblas/dtrsv.c",
    "content": "#include \"gsl_math.h\"\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n#include \"error_cblas_l2.h\"\n\nvoid\ncblas_dtrsv (const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n             const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n             const int N, const double *A, const int lda, double *X,\n             const int incX)\n{\n#define BASE double\n#include \"source_trsv_r.h\"\n#undef BASE\n}\n"
  },
  {
    "path": "gsl/cblas/error_cblas.h",
    "content": "/* cblas/error_cblas.h\n *\n * Copyright (C) 2010 José Luis García Pallero\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __ERROR_CBLAS_H__\n#define __ERROR_CBLAS_H__\n\n\n#define CHECK_ARGS_X(FUNCTION,VAR,ARGS) do { int VAR = 0 ;      \\\n    CBLAS_ERROR_##FUNCTION ARGS ; \\\n    if (VAR) cblas_xerbla(pos,__FILE__,\"\"); } while (0)\n\n#define CHECK_ARGS7(FUNCTION,A1,A2,A3,A4,A5,A6,A7) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7))\n\n#define CHECK_ARGS8(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8))\n\n#define CHECK_ARGS9(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9))\n\n#define CHECK_ARGS10(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10))\n\n#define CHECK_ARGS11(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11))\n\n#define CHECK_ARGS12(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12))\n\n#define CHECK_ARGS13(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13))\n\n#define CHECK_ARGS14(FUNCTION,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14) \\\n  CHECK_ARGS_X(FUNCTION,pos,(pos,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14))\n\n/* check if CBLAS_ORDER is correct */\n#define CHECK_ORDER(pos,posIfError,order) \\\nif(((order)!=CblasRowMajor)&&((order)!=CblasColMajor)) \\\n     pos = posIfError;\n\n/* check if CBLAS_TRANSPOSE is correct */\n#define CHECK_TRANSPOSE(pos,posIfError,Trans) \\\nif(((Trans)!=CblasNoTrans)&&((Trans)!=CblasTrans)&&((Trans)!=CblasConjTrans)) \\\n    pos = posIfError;\n\n/* check if CBLAS_UPLO is correct */\n#define CHECK_UPLO(pos,posIfError,Uplo) \\\nif(((Uplo)!=CblasUpper)&&((Uplo)!=CblasLower)) \\\n    pos = posIfError;\n\n/* check if CBLAS_DIAG is correct */\n#define CHECK_DIAG(pos,posIfError,Diag) \\\nif(((Diag)!=CblasNonUnit)&&((Diag)!=CblasUnit)) \\\n    pos = posIfError;\n\n/* check if CBLAS_SIDE is correct */\n#define CHECK_SIDE(pos,posIfError,Side) \\\nif(((Side)!=CblasLeft)&&((Side)!=CblasRight)) \\\n    pos = posIfError;\n\n/* check if a dimension argument is correct */\n#define CHECK_DIM(pos,posIfError,dim) \\\nif((dim)<0) \\\n    pos = posIfError;\n\n/* check if a stride argument is correct */\n#define CHECK_STRIDE(pos,posIfError,stride) \\\nif((stride)==0) \\\n    pos = posIfError;\n\n#endif /* __ERROR_CBLAS_H__ */\n"
  },
  {
    "path": "gsl/cblas/error_cblas_l2.h",
    "content": "/* cblas/error_cblas_l2.h\n *\n * Copyright (C) 2010 José Luis García Pallero\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __ERROR_CBLAS_L2_H__\n#define __ERROR_CBLAS_L2_H__\n#include \"gsl_math.h\"\n#include \"error_cblas.h\"\n/*\n * =============================================================================\n * Prototypes for level 2 BLAS\n * =============================================================================\n */\n\n/*\n * Routines with standard 4 prefixes (S, D, C, Z)\n */\n\n/* cblas_xgemv() */\n#define CBLAS_ERROR_GEMV(pos,order,TransA,M,N,alpha,A,lda,X,incX,beta,Y,incY) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_TRANSPOSE(pos,2,TransA); \\\nCHECK_DIM(pos,3,M); \\\nCHECK_DIM(pos,4,N); \\\nif((order)==CblasRowMajor) { \\\n    if((lda)<GSL_MAX(1,N)) { \\\n        pos = 7; \\\n    } \\\n} else if((order)==CblasColMajor) { \\\n    if((lda)<GSL_MAX(1,M)) { \\\n        pos = 7; \\\n    } \\\n};                       \\\nCHECK_STRIDE(pos,9,incX); \\\nCHECK_STRIDE(pos,12,incY);\n\n/* cblas_xgbmv() */\n#define CBLAS_ERROR_GBMV(pos,order,TransA,M,N,KL,KU,alpha,A,lda,X,incX,beta,Y,incY) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_TRANSPOSE(pos,2,TransA); \\\nCHECK_DIM(pos,3,M); \\\nCHECK_DIM(pos,4,N); \\\nCHECK_DIM(pos,5,KL); \\\nCHECK_DIM(pos,6,KU); \\\nif((lda)<GSL_MAX(1,(KL+KU+1))) { \\\n    pos = 9; \\\n};                        \\\nCHECK_STRIDE(pos,11,incX); \\\nCHECK_STRIDE(pos,14,incY);\n\n/* cblas_xtrmv() */\n#define CBLAS_ERROR_TRMV(pos,order,Uplo,TransA,Diag,N,A,lda,X,incX) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_TRANSPOSE(pos,3,TransA); \\\nCHECK_DIAG(pos,4,Diag); \\\nCHECK_DIM(pos,5,N); \\\nif((lda)<GSL_MAX(1,N)) \\\n    pos = 7; \\\nCHECK_STRIDE(pos,9,incX);\n\n/* cblas_xtbmv() */\n#define CBLAS_ERROR_TBMV(pos,order,Uplo,TransA,Diag,N,K,A,lda,X,incX) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_TRANSPOSE(pos,3,TransA); \\\nCHECK_DIAG(pos,4,Diag); \\\nCHECK_DIM(pos,5,N); \\\nCHECK_DIM(pos,6,K); \\\nif((lda)<GSL_MAX(1,(K+1))) { \\\n    pos = 8; \\\n}; \\\nCHECK_STRIDE(pos,10,incX);\n\n/* cblas_xtpmv() */\n#define CBLAS_ERROR_TPMV(pos,order,Uplo,TransA,Diag,N,Ap,X,incX) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_TRANSPOSE(pos,3,TransA); \\\nCHECK_DIAG(pos,4,Diag); \\\nCHECK_DIM(pos,5,N); \\\nCHECK_STRIDE(pos,8,incX);\n\n/* cblas_xtrsv() */\n#define CBLAS_ERROR_TRSV(pos,order,Uplo,TransA,Diag,N,A,lda,X,incX) \\\nCBLAS_ERROR_TRMV(pos,order,Uplo,TransA,Diag,N,A,lda,X,incX)\n\n/* cblas_xtbsv() */\n#define CBLAS_ERROR_TBSV(pos,order,Uplo,TransA,Diag,N,K,A,lda,X,incX) \\\nCBLAS_ERROR_TBMV(pos,order,Uplo,TransA,Diag,N,K,A,lda,X,incX)\n\n/* cblas_xtpsv() */\n#define CBLAS_ERROR_TPSV(pos,order,Uplo,TransA,Diag,N,Ap,X,incX) \\\nCBLAS_ERROR_TPMV(pos,order,Uplo,TransA,Diag,N,Ap,X,incX)\n\n/*\n * Routines with S and D prefixes only\n */\n\n/* cblas_xsymv() */\n#define CBLAS_ERROR_SD_SYMV(pos,order,Uplo,N,alpha,A,lda,X,incX,beta,Y,incY) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nif((lda)<GSL_MAX(1,N)) { \\\n    pos = 6; \\\n};                       \\\nCHECK_STRIDE(pos,8,incX); \\\nCHECK_STRIDE(pos,11,incY);\n\n/* cblas_xsbmv() */\n#define CBLAS_ERROR_SD_SBMV(pos,order,Uplo,N,K,alpha,A,lda,X,incX,beta,Y,incY) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_DIM(pos,4,K); \\\nif((lda)<GSL_MAX(1,K+1)) { \\\n    pos = 7; \\\n};                       \\\nCHECK_STRIDE(pos,9,incX); \\\nCHECK_STRIDE(pos,12,incY);\n\n/* cblas_xspmv() */\n#define CBLAS_ERROR_SD_SPMV(pos,order,Uplo,N,alpha,Ap,X,incX,beta,Y,incY) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,7,incX); \\\nCHECK_STRIDE(pos,10,incY);\n\n/* cblas_xger() */\n#define CBLAS_ERROR_SD_GER(pos,order,M,N,alpha,X,incX,Y,incY,A,lda) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_DIM(pos,2,M); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,6,incX); \\\nCHECK_STRIDE(pos,8,incY); \\\nif((order)==CblasRowMajor) { \\\n    if((lda)<GSL_MAX(1,N)) { \\\n        pos = 10; \\\n    } \\\n} else if((order)==CblasColMajor) { \\\n    if((lda)<GSL_MAX(1,M)) { \\\n        pos = 10; \\\n    } \\\n};\n\n/* cblas_xsyr() */\n#define CBLAS_ERROR_SD_SYR(pos,order,Uplo,N,alpha,X,incX,A,lda) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,6,incX); \\\nif((lda)<GSL_MAX(1,N)) { \\\n    pos = 8; \\\n};\n\n/* cblas_xspr() */\n#define CBLAS_ERROR_SD_SPR(pos,order,Uplo,N,alpha,X,incX,Ap) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,6,incX);\n\n/* cblas_xsyr2() */\n#define CBLAS_ERROR_SD_SYR2(pos,order,Uplo,N,alpha,X,incX,Y,incY,A,lda) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,6,incX); \\\nCHECK_STRIDE(pos,8,incY); \\\nif((lda)<GSL_MAX(1,N)) { \\\n    pos = 10; \\\n};\n\n/* cblas_xspr2() */\n#define CBLAS_ERROR_SD_SPR2(pos,order,Uplo,N,alpha,X,incX,Y,incY,A) \\\nCHECK_ORDER(pos,1,order); \\\nCHECK_UPLO(pos,2,Uplo); \\\nCHECK_DIM(pos,3,N); \\\nCHECK_STRIDE(pos,6,incX); \\\nCHECK_STRIDE(pos,8,incY);\n\n/*\n * Routines with C and Z prefixes only\n */\n\n/* cblas_xhemv() */\n#define CBLAS_ERROR_CZ_HEMV(pos,order,Uplo,N,alpha,A,lda,X,incX,beta,Y,incY) \\\nCBLAS_ERROR_SD_SYMV(pos,order,Uplo,N,alpha,A,lda,X,incX,beta,Y,incY)\n\n/* cblas_xhbmv() */\n#define CBLAS_ERROR_CZ_HBMV(pos,order,Uplo,N,K,alpha,A,lda,X,incX,beta,Y,incY) \\\nCBLAS_ERROR_SD_SBMV(pos,order,Uplo,N,K,alpha,A,lda,X,incX,beta,Y,incY)\n\n/* cblas_xhpmv() */\n#define CBLAS_ERROR_CZ_HPMV(pos,order,Uplo,N,alpha,Ap,X,incX,beta,Y,incY) \\\nCBLAS_ERROR_SD_SPMV(pos,order,Uplo,N,alpha,Ap,X,incX,beta,Y,incY)\n\n/* cblas_xgeru() */\n#define CBLAS_ERROR_CZ_GERU(pos,order,M,N,alpha,X,incX,Y,incY,A,lda) \\\nCBLAS_ERROR_SD_GER(pos,order,M,N,alpha,X,incX,Y,incY,A,lda)\n\n/* cblas_xgerc() */\n#define CBLAS_ERROR_CZ_GERC(pos,order,M,N,alpha,X,incX,Y,incY,A,lda) \\\nCBLAS_ERROR_SD_GER(pos,order,M,N,alpha,X,incX,Y,incY,A,lda)\n\n/* cblas_xher() */\n#define CBLAS_ERROR_CZ_HER(pos,order,Uplo,N,alpha,X,incX,A,lda) \\\nCBLAS_ERROR_SD_SYR(pos,order,Uplo,N,alpha,X,incX,A,lda)\n\n/* cblas_xhpr() */\n#define CBLAS_ERROR_CZ_HPR(pos,order,Uplo,N,alpha,X,incX,A) \\\nCBLAS_ERROR_SD_SPR(pos,order,Uplo,N,alpha,X,incX,A)\n\n/* cblas_xher2() */\n#define CBLAS_ERROR_CZ_HER2(pos,order,Uplo,N,alpha,X,incX,Y,incY,A,lda) \\\nCBLAS_ERROR_SD_SYR2(pos,order,Uplo,N,alpha,X,incX,Y,incY,A,lda)\n\n/* cblas_xhpr2() */\n#define CBLAS_ERROR_CZ_HPR2(pos,order,Uplo,N,alpha,X,incX,Y,incY,Ap) \\\nCBLAS_ERROR_SD_SPR2(pos,order,Uplo,N,alpha,X,incX,Y,incY,Ap)\n\n#endif /* __ERROR_CBLAS_L2_H__ */\n"
  },
  {
    "path": "gsl/cblas/gsl_cblas.h",
    "content": "/* blas/gsl_cblas.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* This is a copy of the CBLAS standard header.\n * We carry this around so we do not have to\n * break our model for flexible BLAS functionality.\n */\n\n#ifndef __GSL_CBLAS_H__\n#define __GSL_CBLAS_H__\n#include <stddef.h>\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n#define __BEGIN_DECLS extern \"C\" {\n#define __END_DECLS }\n#else\n#define __BEGIN_DECLS           /* empty */\n#define __END_DECLS             /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/*\n * Enumerated and derived types\n */\n#define CBLAS_INDEX size_t  /* this may vary between platforms */\n\nenum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};\nenum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};\nenum CBLAS_UPLO {CblasUpper=121, CblasLower=122};\nenum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};\nenum CBLAS_SIDE {CblasLeft=141, CblasRight=142};\n\n/*\n * ===========================================================================\n * Prototypes for level 1 BLAS functions (complex are recast as routines)\n * ===========================================================================\n */\n/*float  cblas_sdsdot(const int N, const float alpha, const float *X,\n                    const int incX, const float *Y, const int incY);\ndouble cblas_dsdot(const int N, const float *X, const int incX, const float *Y,\n                   const int incY);\nfloat  cblas_sdot(const int N, const float  *X, const int incX,\n                  const float  *Y, const int incY);*/\ndouble cblas_ddot(const int N, const double *X, const int incX,\n                  const double *Y, const int incY);\n\n/*\n * Functions having prefixes Z and C only\n */\n/*void   cblas_cdotu_sub(const int N, const void *X, const int incX,\n                       const void *Y, const int incY, void *dotu);\nvoid   cblas_cdotc_sub(const int N, const void *X, const int incX,\n                       const void *Y, const int incY, void *dotc);\n\nvoid   cblas_zdotu_sub(const int N, const void *X, const int incX,\n                       const void *Y, const int incY, void *dotu);\nvoid   cblas_zdotc_sub(const int N, const void *X, const int incX,\n                       const void *Y, const int incY, void *dotc);*/\n\n\n/*\n * Functions having prefixes S D SC DZ\n */\n/*float  cblas_snrm2(const int N, const float *X, const int incX);\nfloat  cblas_sasum(const int N, const float *X, const int incX);\n\ndouble cblas_dnrm2(const int N, const double *X, const int incX);\ndouble cblas_dasum(const int N, const double *X, const int incX);\n\nfloat  cblas_scnrm2(const int N, const void *X, const int incX);\nfloat  cblas_scasum(const int N, const void *X, const int incX);\n\ndouble cblas_dznrm2(const int N, const void *X, const int incX);\ndouble cblas_dzasum(const int N, const void *X, const int incX);*/\n\n\n/*\n * Functions having standard 4 prefixes (S D C Z)\n */\n/*CBLAS_INDEX cblas_isamax(const int N, const float  *X, const int incX);\nCBLAS_INDEX cblas_idamax(const int N, const double *X, const int incX);\nCBLAS_INDEX cblas_icamax(const int N, const void   *X, const int incX);\nCBLAS_INDEX cblas_izamax(const int N, const void   *X, const int incX);*/\n\n/*\n * ===========================================================================\n * Prototypes for level 1 BLAS routines\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (s, d, c, z)\n */\n/*void cblas_sswap(const int N, float *X, const int incX, \n                 float *Y, const int incY);\nvoid cblas_scopy(const int N, const float *X, const int incX, \n                 float *Y, const int incY);\nvoid cblas_saxpy(const int N, const float alpha, const float *X,\n                 const int incX, float *Y, const int incY);\n\nvoid cblas_dswap(const int N, double *X, const int incX, \n                 double *Y, const int incY);\nvoid cblas_dcopy(const int N, const double *X, const int incX, \n                 double *Y, const int incY);*/\nvoid cblas_daxpy(const int N, const double alpha, const double *X,\n                 const int incX, double *Y, const int incY);\n\n/*void cblas_cswap(const int N, void *X, const int incX, \n                 void *Y, const int incY);\nvoid cblas_ccopy(const int N, const void *X, const int incX, \n                 void *Y, const int incY);\nvoid cblas_caxpy(const int N, const void *alpha, const void *X,\n                 const int incX, void *Y, const int incY);\n\nvoid cblas_zswap(const int N, void *X, const int incX, \n                 void *Y, const int incY);\nvoid cblas_zcopy(const int N, const void *X, const int incX, \n                 void *Y, const int incY);\nvoid cblas_zaxpy(const int N, const void *alpha, const void *X,\n                 const int incX, void *Y, const int incY);*/\n\n\n/* \n * Routines with S and D prefix only\n */\n/*void cblas_srotg(float *a, float *b, float *c, float *s);\nvoid cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P);\nvoid cblas_srot(const int N, float *X, const int incX,\n                float *Y, const int incY, const float c, const float s);\nvoid cblas_srotm(const int N, float *X, const int incX,\n                float *Y, const int incY, const float *P);\n\nvoid cblas_drotg(double *a, double *b, double *c, double *s);\nvoid cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P);\nvoid cblas_drot(const int N, double *X, const int incX,\n                double *Y, const int incY, const double c, const double  s);\nvoid cblas_drotm(const int N, double *X, const int incX,\n                double *Y, const int incY, const double *P);*/\n\n\n/* \n * Routines with S D C Z CS and ZD prefixes\n */\n/*void cblas_sscal(const int N, const float alpha, float *X, const int incX);\nvoid cblas_dscal(const int N, const double alpha, double *X, const int incX);\nvoid cblas_cscal(const int N, const void *alpha, void *X, const int incX);\nvoid cblas_zscal(const int N, const void *alpha, void *X, const int incX);\nvoid cblas_csscal(const int N, const float alpha, void *X, const int incX);\nvoid cblas_zdscal(const int N, const double alpha, void *X, const int incX);*/\n\n/*\n * ===========================================================================\n * Prototypes for level 2 BLAS\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (S, D, C, Z)\n */\n/*void cblas_sgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const float alpha, const float *A, const int lda,\n                 const float *X, const int incX, const float beta,\n                 float *Y, const int incY);\nvoid cblas_sgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const int KL, const int KU, const float alpha,\n                 const float *A, const int lda, const float *X,\n                 const int incX, const float beta, float *Y, const int incY);\nvoid cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const float *A, const int lda, \n                 float *X, const int incX);\nvoid cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const float *A, const int lda, \n                 float *X, const int incX);\nvoid cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const float *Ap, float *X, const int incX);\nvoid cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const float *A, const int lda, float *X,\n                 const int incX);\nvoid cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const float *A, const int lda,\n                 float *X, const int incX);\nvoid cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const float *Ap, float *X, const int incX);*/\n\nvoid cblas_dgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const double alpha, const double *A, const int lda,\n                 const double *X, const int incX, const double beta,\n                 double *Y, const int incY);\n/*void cblas_dgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const int KL, const int KU, const double alpha,\n                 const double *A, const int lda, const double *X,\n                 const int incX, const double beta, double *Y, const int incY);*/\nvoid cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const double *A, const int lda, \n                 double *X, const int incX);\n/*void cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const double *A, const int lda, \n                 double *X, const int incX);\nvoid cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const double *Ap, double *X, const int incX);*/\nvoid cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const double *A, const int lda, double *X,\n                 const int incX);\n/*void cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const double *A, const int lda,\n                 double *X, const int incX);\nvoid cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const double *Ap, double *X, const int incX);\n\nvoid cblas_cgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *X, const int incX, const void *beta,\n                 void *Y, const int incY);\nvoid cblas_cgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const int KL, const int KU, const void *alpha,\n                 const void *A, const int lda, const void *X,\n                 const int incX, const void *beta, void *Y, const int incY);\nvoid cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *A, const int lda, \n                 void *X, const int incX);\nvoid cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const void *A, const int lda, \n                 void *X, const int incX);\nvoid cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *Ap, void *X, const int incX);\nvoid cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *A, const int lda, void *X,\n                 const int incX);\nvoid cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const void *A, const int lda,\n                 void *X, const int incX);\nvoid cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *Ap, void *X, const int incX);\n\nvoid cblas_zgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *X, const int incX, const void *beta,\n                 void *Y, const int incY);\nvoid cblas_zgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const int M, const int N,\n                 const int KL, const int KU, const void *alpha,\n                 const void *A, const int lda, const void *X,\n                 const int incX, const void *beta, void *Y, const int incY);\nvoid cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *A, const int lda, \n                 void *X, const int incX);\nvoid cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const void *A, const int lda, \n                 void *X, const int incX);\nvoid cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *Ap, void *X, const int incX);\nvoid cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *A, const int lda, void *X,\n                 const int incX);\nvoid cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const int K, const void *A, const int lda,\n                 void *X, const int incX);\nvoid cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const int N, const void *Ap, void *X, const int incX);*/\n\n\n/* \n * Routines with S and D prefixes only\n */\n/*void cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const float alpha, const float *A,\n                 const int lda, const float *X, const int incX,\n                 const float beta, float *Y, const int incY);\nvoid cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const int K, const float alpha, const float *A,\n                 const int lda, const float *X, const int incX,\n                 const float beta, float *Y, const int incY);\nvoid cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const float alpha, const float *Ap,\n                 const float *X, const int incX,\n                 const float beta, float *Y, const int incY);\nvoid cblas_sger(const enum CBLAS_ORDER order, const int M, const int N,\n                const float alpha, const float *X, const int incX,\n                const float *Y, const int incY, float *A, const int lda);\nvoid cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const float *X,\n                const int incX, float *A, const int lda);\nvoid cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const float *X,\n                const int incX, float *Ap);\nvoid cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const float *X,\n                const int incX, const float *Y, const int incY, float *A,\n                const int lda);\nvoid cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const float *X,\n                const int incX, const float *Y, const int incY, float *A);\n\nvoid cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const double alpha, const double *A,\n                 const int lda, const double *X, const int incX,\n                 const double beta, double *Y, const int incY);\nvoid cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const int K, const double alpha, const double *A,\n                 const int lda, const double *X, const int incX,\n                 const double beta, double *Y, const int incY);\nvoid cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const double alpha, const double *Ap,\n                 const double *X, const int incX,\n                 const double beta, double *Y, const int incY);\nvoid cblas_dger(const enum CBLAS_ORDER order, const int M, const int N,\n                const double alpha, const double *X, const int incX,\n                const double *Y, const int incY, double *A, const int lda);\nvoid cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const double *X,\n                const int incX, double *A, const int lda);\nvoid cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const double *X,\n                const int incX, double *Ap);\nvoid cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const double *X,\n                const int incX, const double *Y, const int incY, double *A,\n                const int lda);\nvoid cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const double *X,\n                const int incX, const double *Y, const int incY, double *A);*/\n\n\n/* \n * Routines with C and Z prefixes only\n */\n/*void cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const void *alpha, const void *A,\n                 const int lda, const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const int K, const void *alpha, const void *A,\n                 const int lda, const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const void *alpha, const void *Ap,\n                 const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N,\n                 const void *alpha, const void *X, const int incX,\n                 const void *Y, const int incY, void *A, const int lda);\nvoid cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N,\n                 const void *alpha, const void *X, const int incX,\n                 const void *Y, const int incY, void *A, const int lda);\nvoid cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const void *X, const int incX,\n                void *A, const int lda);\nvoid cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const float alpha, const void *X,\n                const int incX, void *A);\nvoid cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,\n                const void *alpha, const void *X, const int incX,\n                const void *Y, const int incY, void *A, const int lda);\nvoid cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,\n                const void *alpha, const void *X, const int incX,\n                const void *Y, const int incY, void *Ap);\n\nvoid cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const void *alpha, const void *A,\n                 const int lda, const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const int K, const void *alpha, const void *A,\n                 const int lda, const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const int N, const void *alpha, const void *Ap,\n                 const void *X, const int incX,\n                 const void *beta, void *Y, const int incY);\nvoid cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N,\n                 const void *alpha, const void *X, const int incX,\n                 const void *Y, const int incY, void *A, const int lda);\nvoid cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N,\n                 const void *alpha, const void *X, const int incX,\n                 const void *Y, const int incY, void *A, const int lda);\nvoid cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const void *X, const int incX,\n                void *A, const int lda);\nvoid cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const int N, const double alpha, const void *X,\n                const int incX, void *A);\nvoid cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,\n                const void *alpha, const void *X, const int incX,\n                const void *Y, const int incY, void *A, const int lda);\nvoid cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,\n                const void *alpha, const void *X, const int incX,\n                const void *Y, const int incY, void *Ap);*/\n\n/*\n * ===========================================================================\n * Prototypes for level 3 BLAS\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (S, D, C, Z)\n */\n/*void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const int M, const int N,\n                 const int K, const float alpha, const float *A,\n                 const int lda, const float *B, const int ldb,\n                 const float beta, float *C, const int ldc);\nvoid cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const float alpha, const float *A, const int lda,\n                 const float *B, const int ldb, const float beta,\n                 float *C, const int ldc);\nvoid cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const float alpha, const float *A, const int lda,\n                 const float beta, float *C, const int ldc);\nvoid cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const float alpha, const float *A, const int lda,\n                  const float *B, const int ldb, const float beta,\n                  float *C, const int ldc);\nvoid cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const float alpha, const float *A, const int lda,\n                 float *B, const int ldb);\nvoid cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const float alpha, const float *A, const int lda,\n                 float *B, const int ldb);\n\nvoid cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const int M, const int N,\n                 const int K, const double alpha, const double *A,\n                 const int lda, const double *B, const int ldb,\n                 const double beta, double *C, const int ldc);\nvoid cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const double alpha, const double *A, const int lda,\n                 const double *B, const int ldb, const double beta,\n                 double *C, const int ldc);\nvoid cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const double alpha, const double *A, const int lda,\n                 const double beta, double *C, const int ldc);\nvoid cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const double alpha, const double *A, const int lda,\n                  const double *B, const int ldb, const double beta,\n                  double *C, const int ldc);\nvoid cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const double alpha, const double *A, const int lda,\n                 double *B, const int ldb);\nvoid cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const double alpha, const double *A, const int lda,\n                 double *B, const int ldb);\n\nvoid cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const int M, const int N,\n                 const int K, const void *alpha, const void *A,\n                 const int lda, const void *B, const int ldb,\n                 const void *beta, void *C, const int ldc);\nvoid cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *B, const int ldb, const void *beta,\n                 void *C, const int ldc);\nvoid cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const void *alpha, const void *A, const int lda,\n                 const void *beta, void *C, const int ldc);\nvoid cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const void *alpha, const void *A, const int lda,\n                  const void *B, const int ldb, const void *beta,\n                  void *C, const int ldc);\nvoid cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 void *B, const int ldb);\nvoid cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 void *B, const int ldb);\n\nvoid cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const int M, const int N,\n                 const int K, const void *alpha, const void *A,\n                 const int lda, const void *B, const int ldb,\n                 const void *beta, void *C, const int ldc);\nvoid cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *B, const int ldb, const void *beta,\n                 void *C, const int ldc);\nvoid cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const void *alpha, const void *A, const int lda,\n                 const void *beta, void *C, const int ldc);\nvoid cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const void *alpha, const void *A, const int lda,\n                  const void *B, const int ldb, const void *beta,\n                  void *C, const int ldc);\nvoid cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 void *B, const int ldb);\nvoid cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 void *B, const int ldb);*/\n\n\n/* \n * Routines with prefixes C and Z only\n */\n/*void cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *B, const int ldb, const void *beta,\n                 void *C, const int ldc);\nvoid cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const float alpha, const void *A, const int lda,\n                 const float beta, void *C, const int ldc);\nvoid cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const void *alpha, const void *A, const int lda,\n                  const void *B, const int ldb, const float beta,\n                  void *C, const int ldc);\n\nvoid cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const int M, const int N,\n                 const void *alpha, const void *A, const int lda,\n                 const void *B, const int ldb, const void *beta,\n                 void *C, const int ldc);\nvoid cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                 const double alpha, const void *A, const int lda,\n                 const double beta, void *C, const int ldc);\nvoid cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const int N, const int K,\n                  const void *alpha, const void *A, const int lda,\n                  const void *B, const int ldb, const double beta,\n                  void *C, const int ldc);*/\n\nvoid cblas_xerbla(int p, const char *rout, const char *form, ...);\n\n__END_DECLS\n\n#endif /* __GSL_CBLAS_H__ */\n"
  },
  {
    "path": "gsl/cblas/source_axpy_r.h",
    "content": "/* blas/source_axpy_r.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n{\n  INDEX i;\n\n  if (alpha == 0.0) {\n    return;\n  }\n\n  if (incX == 1 && incY == 1) {\n    const INDEX m = N % 4;\n\n    for (i = 0; i < m; i++) {\n      Y[i] += alpha * X[i];\n    }\n\n    for (i = m; i + 3 < N; i += 4) {\n      Y[i] += alpha * X[i];\n      Y[i + 1] += alpha * X[i + 1];\n      Y[i + 2] += alpha * X[i + 2];\n      Y[i + 3] += alpha * X[i + 3];\n    }\n  } else {\n    INDEX ix = OFFSET(N, incX);\n    INDEX iy = OFFSET(N, incY);\n\n    for (i = 0; i < N; i++) {\n      Y[iy] += alpha * X[ix];\n      ix += incX;\n      iy += incY;\n    }\n  }\n}\n"
  },
  {
    "path": "gsl/cblas/source_dot_r.h",
    "content": "/* blas/source_dot_r.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n{\n  ACC_TYPE r = INIT_VAL;\n  INDEX i;\n  INDEX ix = OFFSET(N, incX);\n  INDEX iy = OFFSET(N, incY);\n\n  for (i = 0; i < N; i++) {\n    r += X[ix] * Y[iy];\n    ix += incX;\n    iy += incY;\n  }\n\n  return r;\n}\n"
  },
  {
    "path": "gsl/cblas/source_gemv_r.h",
    "content": "/* blas/source_gemv_r.h\n *\n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n{\n  INDEX i, j;\n  INDEX lenX, lenY;\n\n  const int Trans = (TransA != CblasConjTrans) ? TransA : CblasTrans;\n\n  CHECK_ARGS12(GEMV,order,TransA,M,N,alpha,A,lda,X,incX,beta,Y,incY);\n\n  if (M == 0 || N == 0)\n    return;\n\n  if (alpha == 0.0 && beta == 1.0)\n    return;\n\n  if (Trans == CblasNoTrans) {\n    lenX = N;\n    lenY = M;\n  } else {\n    lenX = M;\n    lenY = N;\n  }\n\n  /* form  y := beta*y */\n  if (beta == 0.0) {\n    INDEX iy = OFFSET(lenY, incY);\n    for (i = 0; i < lenY; i++) {\n      Y[iy] = 0.0;\n      iy += incY;\n    }\n  } else if (beta != 1.0) {\n    INDEX iy = OFFSET(lenY, incY);\n    for (i = 0; i < lenY; i++) {\n      Y[iy] *= beta;\n      iy += incY;\n    }\n  }\n\n  if (alpha == 0.0)\n    return;\n\n  if ((order == CblasRowMajor && Trans == CblasNoTrans)\n      || (order == CblasColMajor && Trans == CblasTrans)) {\n    /* form  y := alpha*A*x + y */\n    INDEX iy = OFFSET(lenY, incY);\n    for (i = 0; i < lenY; i++) {\n      BASE temp = 0.0;\n      INDEX ix = OFFSET(lenX, incX);\n      for (j = 0; j < lenX; j++) {\n        temp += X[ix] * A[lda * i + j];\n        ix += incX;\n      }\n      Y[iy] += alpha * temp;\n      iy += incY;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasTrans)\n             || (order == CblasColMajor && Trans == CblasNoTrans)) {\n    /* form  y := alpha*A'*x + y */\n    INDEX ix = OFFSET(lenX, incX);\n    for (j = 0; j < lenX; j++) {\n      const BASE temp = alpha * X[ix];\n      if (temp != 0.0) {\n        INDEX iy = OFFSET(lenY, incY);\n        for (i = 0; i < lenY; i++) {\n          Y[iy] += temp * A[lda * j + i];\n          iy += incY;\n        }\n      }\n      ix += incX;\n    }\n  } else {\n    BLAS_ERROR(\"unrecognized operation\");\n  }\n}\n"
  },
  {
    "path": "gsl/cblas/source_trmv_r.h",
    "content": "/* blas/source_trmv_r.h\n *\n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n{\n  INDEX i, j;\n\n  const int nonunit = (Diag == CblasNonUnit);\n  const int Trans = (TransA != CblasConjTrans) ? TransA : CblasTrans;\n\n  CHECK_ARGS9(TRMV,order,Uplo,TransA,Diag,N,A,lda,X,incX);\n\n  if ((order == CblasRowMajor && Trans == CblasNoTrans && Uplo == CblasUpper)\n      || (order == CblasColMajor && Trans == CblasTrans && Uplo == CblasLower)) {\n    /* form  x := A*x */\n\n    INDEX ix = OFFSET(N, incX);\n    for (i = 0; i < N; i++) {\n      BASE temp = 0.0;\n      const INDEX j_min = i + 1;\n      const INDEX j_max = N;\n      INDEX jx = OFFSET(N, incX) + j_min * incX;\n      for (j = j_min; j < j_max; j++) {\n        temp += X[jx] * A[lda * i + j];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = temp + X[ix] * A[lda * i + i];\n      } else {\n        X[ix] += temp;\n      }\n      ix += incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasNoTrans && Uplo == CblasLower)\n             || (order == CblasColMajor && Trans == CblasTrans && Uplo == CblasUpper)) {\n    INDEX ix = OFFSET(N, incX) + (N - 1) * incX;\n    for (i = N; i > 0 && i--;) {\n      BASE temp = 0.0;\n      const INDEX j_min = 0;\n      const INDEX j_max = i;\n      INDEX jx = OFFSET(N, incX) + j_min * incX;\n      for (j = j_min; j < j_max; j++) {\n        temp += X[jx] * A[lda * i + j];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = temp + X[ix] * A[lda * i + i];\n      } else {\n        X[ix] += temp;\n      }\n      ix -= incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasTrans && Uplo == CblasUpper)\n             || (order == CblasColMajor && Trans == CblasNoTrans && Uplo == CblasLower)) {\n    /* form  x := A'*x */\n    INDEX ix = OFFSET(N, incX) + (N - 1) * incX;\n    for (i = N; i > 0 && i--;) {\n      BASE temp = 0.0;\n      const INDEX j_min = 0;\n      const INDEX j_max = i;\n      INDEX jx = OFFSET(N, incX) + j_min * incX;\n      for (j = j_min; j < j_max; j++) {\n        temp += X[jx] * A[lda * j + i];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = temp + X[ix] * A[lda * i + i];\n      } else {\n        X[ix] += temp;\n      }\n      ix -= incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasTrans && Uplo == CblasLower)\n             || (order == CblasColMajor && Trans == CblasNoTrans && Uplo == CblasUpper)) {\n    INDEX ix = OFFSET(N, incX);\n    for (i = 0; i < N; i++) {\n      BASE temp = 0.0;\n      const INDEX j_min = i + 1;\n      const INDEX j_max = N;\n      INDEX jx = OFFSET(N, incX) + (i + 1) * incX;\n      for (j = j_min; j < j_max; j++) {\n        temp += X[jx] * A[lda * j + i];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = temp + X[ix] * A[lda * i + i];\n      } else {\n        X[ix] += temp;\n      }\n      ix += incX;\n    }\n  } else {\n    BLAS_ERROR(\"unrecognized operation\");\n  }\n}\n"
  },
  {
    "path": "gsl/cblas/source_trsv_r.h",
    "content": "/* blas/source_trsv_r.h\n *\n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n{\n  const int nonunit = (Diag == CblasNonUnit);\n  INDEX ix, jx;\n  INDEX i, j;\n  const int Trans = (TransA != CblasConjTrans) ? TransA : CblasTrans;\n\n  CHECK_ARGS9(TRSV,order,Uplo,TransA,Diag,N,A,lda,X,incX);\n\n  if (N == 0)\n    return;\n\n  /* form  x := inv( A )*x */\n\n  if ((order == CblasRowMajor && Trans == CblasNoTrans && Uplo == CblasUpper)\n      || (order == CblasColMajor && Trans == CblasTrans && Uplo == CblasLower)) {\n    /* backsubstitution */\n    ix = OFFSET(N, incX) + incX * (N - 1);\n    if (nonunit) {\n      X[ix] = X[ix] / A[lda * (N - 1) + (N - 1)];\n    }\n    ix -= incX;\n    for (i = N - 1; i > 0 && i--;) {\n      BASE tmp = X[ix];\n      jx = ix + incX;\n      for (j = i + 1; j < N; j++) {\n        const BASE Aij = A[lda * i + j];\n        tmp -= Aij * X[jx];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = tmp / A[lda * i + i];\n      } else {\n        X[ix] = tmp;\n      }\n      ix -= incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasNoTrans && Uplo == CblasLower)\n             || (order == CblasColMajor && Trans == CblasTrans && Uplo == CblasUpper)) {\n\n    /* forward substitution */\n    ix = OFFSET(N, incX);\n    if (nonunit) {\n      X[ix] = X[ix] / A[lda * 0 + 0];\n    }\n    ix += incX;\n    for (i = 1; i < N; i++) {\n      BASE tmp = X[ix];\n      jx = OFFSET(N, incX);\n      for (j = 0; j < i; j++) {\n        const BASE Aij = A[lda * i + j];\n        tmp -= Aij * X[jx];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = tmp / A[lda * i + i];\n      } else {\n        X[ix] = tmp;\n      }\n      ix += incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasTrans && Uplo == CblasUpper)\n             || (order == CblasColMajor && Trans == CblasNoTrans && Uplo == CblasLower)) {\n\n    /* form  x := inv( A' )*x */\n\n    /* forward substitution */\n    ix = OFFSET(N, incX);\n    if (nonunit) {\n      X[ix] = X[ix] / A[lda * 0 + 0];\n    }\n    ix += incX;\n    for (i = 1; i < N; i++) {\n      BASE tmp = X[ix];\n      jx = OFFSET(N, incX);\n      for (j = 0; j < i; j++) {\n        const BASE Aji = A[lda * j + i];\n        tmp -= Aji * X[jx];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = tmp / A[lda * i + i];\n      } else {\n        X[ix] = tmp;\n      }\n      ix += incX;\n    }\n  } else if ((order == CblasRowMajor && Trans == CblasTrans && Uplo == CblasLower)\n             || (order == CblasColMajor && Trans == CblasNoTrans && Uplo == CblasUpper)) {\n\n    /* backsubstitution */\n    ix = OFFSET(N, incX) + (N - 1) * incX;\n    if (nonunit) {\n      X[ix] = X[ix] / A[lda * (N - 1) + (N - 1)];\n    }\n    ix -= incX;\n    for (i = N - 1; i > 0 && i--;) {\n      BASE tmp = X[ix];\n      jx = ix + incX;\n      for (j = i + 1; j < N; j++) {\n        const BASE Aji = A[lda * j + i];\n        tmp -= Aji * X[jx];\n        jx += incX;\n      }\n      if (nonunit) {\n        X[ix] = tmp / A[lda * i + i];\n      } else {\n        X[ix] = tmp;\n      }\n      ix -= incX;\n    }\n  } else {\n    BLAS_ERROR(\"unrecognized operation\");\n  }\n\n}\n"
  },
  {
    "path": "gsl/cblas/xerbla.c",
    "content": "/* xerbla.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\n#include \"gsl_cblas.h\"\n#include \"cblas.h\"\n\nvoid\ncblas_xerbla (int p, const char *rout, const char *form, ...)\n{\n  va_list ap;\n\n  va_start (ap, form);\n\n  if (p)\n    {\n      fprintf (stderr, \"Parameter %d to routine %s was incorrect\\n\", p, rout);\n    }\n\n  vfprintf (stderr, form, ap);\n  va_end (ap);\n\n  abort ();\n}\n"
  },
  {
    "path": "gsl/cdf/beta_inc.inc",
    "content": "/* specfunc/beta_inc.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n/* Modified for cdfs by Brian Gough, June 2003 */\n\n#include \"gsl_sf_gamma.h\"\n\nstatic double\nbeta_cont_frac (const double a, const double b, const double x,\n                const double epsabs)\n{\n  const unsigned int max_iter = 512;    /* control iterations      */\n  const double cutoff = 2.0 * GSL_DBL_MIN;      /* control the zero cutoff */\n  unsigned int iter_count = 0;\n  double cf;\n\n  /* standard initialization for continued fraction */\n  double num_term = 1.0;\n  double den_term = 1.0 - (a + b) * x / (a + 1.0);\n\n  if (fabs (den_term) < cutoff)\n    den_term = GSL_NAN;\n\n  den_term = 1.0 / den_term;\n  cf = den_term;\n\n  while (iter_count < max_iter)\n    {\n      const int k = iter_count + 1;\n      double coeff = k * (b - k) * x / (((a - 1.0) + 2 * k) * (a + 2 * k));\n      double delta_frac;\n\n      /* first step */\n      den_term = 1.0 + coeff * den_term;\n      num_term = 1.0 + coeff / num_term;\n\n      if (fabs (den_term) < cutoff)\n        den_term = GSL_NAN;\n\n      if (fabs (num_term) < cutoff)\n        num_term = GSL_NAN;\n\n      den_term = 1.0 / den_term;\n\n      delta_frac = den_term * num_term;\n      cf *= delta_frac;\n\n      coeff = -(a + k) * (a + b + k) * x / ((a + 2 * k) * (a + 2 * k + 1.0));\n\n      /* second step */\n      den_term = 1.0 + coeff * den_term;\n      num_term = 1.0 + coeff / num_term;\n\n      if (fabs (den_term) < cutoff)\n        den_term = GSL_NAN;\n\n      if (fabs (num_term) < cutoff)\n        num_term = GSL_NAN;\n\n      den_term = 1.0 / den_term;\n\n      delta_frac = den_term * num_term;\n      cf *= delta_frac;\n\n      if (fabs (delta_frac - 1.0) < 2.0 * GSL_DBL_EPSILON)\n        break;\n\n      if (cf * fabs (delta_frac - 1.0) < epsabs)\n        break;\n\n      ++iter_count;\n    }\n\n  if (iter_count >= max_iter)\n    return GSL_NAN;\n\n  return cf;\n}\n\n/* The function beta_inc_AXPY(A,Y,a,b,x) computes A * beta_inc(a,b,x)\n   + Y taking account of possible cancellations when using the\n   hypergeometric transformation beta_inc(a,b,x)=1-beta_inc(b,a,1-x).\n\n   It also adjusts the accuracy of beta_inc() to fit the overall\n   absolute error when A*beta_inc is added to Y. (e.g. if Y >>\n   A*beta_inc then the accuracy of beta_inc can be reduced) */\n\n\n\nstatic double\nbeta_inc_AXPY (const double A, const double Y,\n               const double a, const double b, const double x)\n{\n  if (x == 0.0)\n    {\n      return A * 0 + Y;\n    }\n  else if (x == 1.0)\n    {\n      return A * 1 + Y;\n    }\n  else if (a > 1e5 && b < 10 && x > a / (a + b))\n    {\n      /* Handle asymptotic regime, large a, small b, x > peak [AS 26.5.17] */\n      double N = a + (b - 1.0) / 2.0;\n      return A * gsl_sf_gamma_inc_Q (b, -N * log (x)) + Y;\n    }\n  else if (b > 1e5 && a < 10 && x < b / (a + b))\n    {\n      /* Handle asymptotic regime, small a, large b, x < peak [AS 26.5.17] */\n      double N = b + (a - 1.0) / 2.0;\n      return A * gsl_sf_gamma_inc_P (a, -N * log1p (-x)) + Y;\n    }\n  else\n    {\n      double ln_beta = gsl_sf_lnbeta (a, b);\n      double ln_pre = -ln_beta + a * log (x) + b * log1p (-x);\n\n      double prefactor = exp (ln_pre);\n\n      if (x < (a + 1.0) / (a + b + 2.0))\n        {\n          /* Apply continued fraction directly. */\n          double epsabs = fabs (Y / (A * prefactor / a)) * GSL_DBL_EPSILON;\n\n          double cf = beta_cont_frac (a, b, x, epsabs);\n\n          return A * (prefactor * cf / a) + Y;\n        }\n      else\n        {\n          /* Apply continued fraction after hypergeometric transformation. */\n          double epsabs =\n            fabs ((A + Y) / (A * prefactor / b)) * GSL_DBL_EPSILON;\n          double cf = beta_cont_frac (b, a, 1.0 - x, epsabs);\n          double term = prefactor * cf / b;\n\n          if (A == -Y)\n            {\n              return -A * term;\n            }\n          else\n            {\n              return A * (1 - term) + Y;\n            }\n        }\n    }\n}\n\n/* Direct series evaluation for testing purposes only */\n\n#if 0\nstatic double\nbeta_series (const double a, const double b, const double x,\n             const double epsabs)\n{\n  double f = x / (1 - x);\n  double c = (b - 1) / (a + 1) * f;\n  double s = 1;\n  double n = 0;\n\n  s += c;\n\n  do\n    {\n      n++;\n      c *= -f * (2 + n - b) / (2 + n + a);\n      s += c;\n    }\n  while (n < 512 && fabs (c) > GSL_DBL_EPSILON * fabs (s) + epsabs);\n\n  s /= (1 - x);\n\n  return s;\n}\n#endif\n"
  },
  {
    "path": "gsl/cdf/gauss.c",
    "content": "/* cdf/gauss.c\n *\n * Copyright (C) 2002, 2004 Jason H. Stover.\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * Computes the cumulative distribution function for the Gaussian\n * distribution using a rational function approximation.  The\n * computation is for the standard Normal distribution, i.e., mean 0\n * and standard deviation 1. If you want to compute Pr(X < t) for a\n * Gaussian random variable X with non-zero mean m and standard\n * deviation sd not equal to 1, find gsl_cdf_ugaussian ((t-m)/sd).\n * This approximation is accurate to at least double precision. The\n * accuracy was verified with a pari-gp script.  The largest error\n * found was about 1.4E-20. The coefficients were derived by Cody.\n *\n * References:\n *\n * W.J. Cody. \"Rational Chebyshev Approximations for the Error\n * Function,\" Mathematics of Computation, v23 n107 1969, 631-637.\n *\n * W. Fraser, J.F Hart. \"On the Computation of Rational Approximations\n * to Continuous Functions,\" Communications of the ACM, v5 1962.\n *\n * W.J. Kennedy Jr., J.E. Gentle. \"Statistical Computing.\" Marcel Dekker. 1980.\n * \n *  \n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_cdf.h\"\n\n#ifndef M_1_SQRT2PI\n#define M_1_SQRT2PI (M_2_SQRTPI * M_SQRT1_2 / 2.0)\n#endif\n\n#define SQRT32 (4.0 * M_SQRT2)\n\n/*\n * IEEE double precision dependent constants.\n *\n * GAUSS_EPSILON: Smallest positive value such that \n *                gsl_cdf_gaussian(x) > 0.5.\n * GAUSS_XUPPER: Largest value x such that gsl_cdf_gaussian(x) < 1.0.\n * GAUSS_XLOWER: Smallest value x such that gsl_cdf_gaussian(x) > 0.0.\n */\n\n#define GAUSS_EPSILON  (GSL_DBL_EPSILON / 2)\n#define GAUSS_XUPPER (8.572)\n#define GAUSS_XLOWER (-37.519)\n\n#define GAUSS_SCALE (16.0)\n\nstatic double\nget_del (double x, double rational)\n{\n  double xsq = 0.0;\n  double del = 0.0;\n  double result = 0.0;\n\n  xsq = floor (x * GAUSS_SCALE) / GAUSS_SCALE;\n  del = (x - xsq) * (x + xsq);\n  del *= 0.5;\n\n  result = exp (-0.5 * xsq * xsq) * exp (-1.0 * del) * rational;\n\n  return result;\n}\n\n/*\n * Normal cdf for fabs(x) < 0.66291\n */\nstatic double\ngauss_small (const double x)\n{\n  unsigned int i;\n  double result = 0.0;\n  double xsq;\n  double xnum;\n  double xden;\n\n  const double a[5] = {\n    2.2352520354606839287,\n    161.02823106855587881,\n    1067.6894854603709582,\n    18154.981253343561249,\n    0.065682337918207449113\n  };\n  const double b[4] = {\n    47.20258190468824187,\n    976.09855173777669322,\n    10260.932208618978205,\n    45507.789335026729956\n  };\n\n  xsq = x * x;\n  xnum = a[4] * xsq;\n  xden = xsq;\n\n  for (i = 0; i < 3; i++)\n    {\n      xnum = (xnum + a[i]) * xsq;\n      xden = (xden + b[i]) * xsq;\n    }\n\n  result = x * (xnum + a[3]) / (xden + b[3]);\n\n  return result;\n}\n\n/*\n * Normal cdf for 0.66291 < fabs(x) < sqrt(32).\n */\nstatic double\ngauss_medium (const double x)\n{\n  unsigned int i;\n  double temp = 0.0;\n  double result = 0.0;\n  double xnum;\n  double xden;\n  double absx;\n\n  const double c[9] = {\n    0.39894151208813466764,\n    8.8831497943883759412,\n    93.506656132177855979,\n    597.27027639480026226,\n    2494.5375852903726711,\n    6848.1904505362823326,\n    11602.651437647350124,\n    9842.7148383839780218,\n    1.0765576773720192317e-8\n  };\n  const double d[8] = {\n    22.266688044328115691,\n    235.38790178262499861,\n    1519.377599407554805,\n    6485.558298266760755,\n    18615.571640885098091,\n    34900.952721145977266,\n    38912.003286093271411,\n    19685.429676859990727\n  };\n\n  absx = fabs (x);\n\n  xnum = c[8] * absx;\n  xden = absx;\n\n  for (i = 0; i < 7; i++)\n    {\n      xnum = (xnum + c[i]) * absx;\n      xden = (xden + d[i]) * absx;\n    }\n\n  temp = (xnum + c[7]) / (xden + d[7]);\n\n  result = get_del (x, temp);\n\n  return result;\n}\n\n/*\n * Normal cdf for \n * {sqrt(32) < x < GAUSS_XUPPER} union { GAUSS_XLOWER < x < -sqrt(32) }.\n */\nstatic double\ngauss_large (const double x)\n{\n  int i;\n  double result;\n  double xsq;\n  double temp;\n  double xnum;\n  double xden;\n  double absx;\n\n  const double p[6] = {\n    0.21589853405795699,\n    0.1274011611602473639,\n    0.022235277870649807,\n    0.001421619193227893466,\n    2.9112874951168792e-5,\n    0.02307344176494017303\n  };\n  const double q[5] = {\n    1.28426009614491121,\n    0.468238212480865118,\n    0.0659881378689285515,\n    0.00378239633202758244,\n    7.29751555083966205e-5\n  };\n\n  absx = fabs (x);\n  xsq = 1.0 / (x * x);\n  xnum = p[5] * xsq;\n  xden = xsq;\n\n  for (i = 0; i < 4; i++)\n    {\n      xnum = (xnum + p[i]) * xsq;\n      xden = (xden + q[i]) * xsq;\n    }\n\n  temp = xsq * (xnum + p[4]) / (xden + q[4]);\n  temp = (M_1_SQRT2PI - temp) / absx;\n\n  result = get_del (x, temp);\n\n  return result;\n}\n\ndouble\ngsl_cdf_ugaussian_P (const double x)\n{\n  double result;\n  double absx = fabs (x);\n\n  if (absx < GAUSS_EPSILON)\n    {\n      result = 0.5;\n      return result;\n    }\n  else if (absx < 0.66291)\n    {\n      result = 0.5 + gauss_small (x);\n      return result;\n    }\n  else if (absx < SQRT32)\n    {\n      result = gauss_medium (x);\n\n      if (x > 0.0)\n        {\n          result = 1.0 - result;\n        }\n\n      return result;\n    }\n  else if (x > GAUSS_XUPPER)\n    {\n      result = 1.0;\n      return result;\n    }\n  else if (x < GAUSS_XLOWER)\n    {\n      result = 0.0;\n      return result;\n    }\n  else\n    {\n      result = gauss_large (x);\n\n      if (x > 0.0)\n        {\n          result = 1.0 - result;\n        }\n    }\n\n  return result;\n}\n\ndouble\ngsl_cdf_ugaussian_Q (const double x)\n{\n  double result;\n  double absx = fabs (x);\n\n  if (absx < GAUSS_EPSILON)\n    {\n      result = 0.5;\n      return result;\n    }\n  else if (absx < 0.66291)\n    {\n      result = gauss_small (x);\n\n      if (x < 0.0)\n        {\n          result = fabs (result) + 0.5;\n        }\n      else\n        {\n          result = 0.5 - result;\n        }\n\n      return result;\n    }\n  else if (absx < SQRT32)\n    {\n      result = gauss_medium (x);\n\n      if (x < 0.0)\n        {\n          result = 1.0 - result;\n        }\n\n      return result;\n    }\n  else if (x > -(GAUSS_XLOWER))\n    {\n      result = 0.0;\n      return result;\n    }\n  else if (x < -(GAUSS_XUPPER))\n    {\n      result = 1.0;\n      return result;\n    }\n  else\n    {\n      result = gauss_large (x);\n\n      if (x < 0.0)\n        {\n          result = 1.0 - result;\n        }\n\n    }\n\n  return result;\n}\n\ndouble\ngsl_cdf_gaussian_P (const double x, const double sigma)\n{\n  return gsl_cdf_ugaussian_P (x / sigma);\n}\n\ndouble\ngsl_cdf_gaussian_Q (const double x, const double sigma)\n{\n  return gsl_cdf_ugaussian_Q (x / sigma);\n}\n"
  },
  {
    "path": "gsl/cdf/gaussinv.c",
    "content": "/* cdf/inverse_normal.c\n *\n * Copyright (C) 2002 Przemyslaw Sliwa and Jason H. Stover.\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * Computes the inverse normal cumulative distribution function \n * according to the algorithm shown in \n *\n *      Wichura, M.J. (1988).\n *      Algorithm AS 241: The Percentage Points of the Normal Distribution.\n *      Applied Statistics, 37, 477-484.\n */\n\n#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_math.h\"\n#include \"gsl_cdf.h\"\n\n#include \"rat_eval.h\"\n\nstatic double\nsmall (double q)\n{\n  const double a[8] = { 3.387132872796366608, 133.14166789178437745,\n    1971.5909503065514427, 13731.693765509461125,\n    45921.953931549871457, 67265.770927008700853,\n    33430.575583588128105, 2509.0809287301226727\n  };\n\n  const double b[8] = { 1.0, 42.313330701600911252,\n    687.1870074920579083, 5394.1960214247511077,\n    21213.794301586595867, 39307.89580009271061,\n    28729.085735721942674, 5226.495278852854561\n  };\n\n  double r = 0.180625 - q * q;\n\n  double x = q * rat_eval (a, 8, b, 8, r);\n\n  return x;\n}\n\nstatic double\nintermediate (double r)\n{\n  const double a[] = { 1.42343711074968357734, 4.6303378461565452959,\n    5.7694972214606914055, 3.64784832476320460504,\n    1.27045825245236838258, 0.24178072517745061177,\n    0.0227238449892691845833, 7.7454501427834140764e-4\n  };\n\n  const double b[] = { 1.0, 2.05319162663775882187,\n    1.6763848301838038494, 0.68976733498510000455,\n    0.14810397642748007459, 0.0151986665636164571966,\n    5.475938084995344946e-4, 1.05075007164441684324e-9\n  };\n\n  double x = rat_eval (a, 8, b, 8, (r - 1.6));\n\n  return x;\n}\n\nstatic double\ntail (double r)\n{\n  const double a[] = { 6.6579046435011037772, 5.4637849111641143699,\n    1.7848265399172913358, 0.29656057182850489123,\n    0.026532189526576123093, 0.0012426609473880784386,\n    2.71155556874348757815e-5, 2.01033439929228813265e-7\n  };\n\n  const double b[] = { 1.0, 0.59983220655588793769,\n    0.13692988092273580531, 0.0148753612908506148525,\n    7.868691311456132591e-4, 1.8463183175100546818e-5,\n    1.4215117583164458887e-7, 2.04426310338993978564e-15\n  };\n\n  double x = rat_eval (a, 8, b, 8, (r - 5.0));\n\n  return x;\n}\n\ndouble\ngsl_cdf_ugaussian_Pinv (const double P)\n{\n  double r, x, pp;\n\n  double dP = P - 0.5;\n\n  if (P == 1.0)\n    {\n      return GSL_POSINF;\n    }\n  else if (P == 0.0)\n    {\n      return GSL_NEGINF;\n    }\n\n  if (fabs (dP) <= 0.425)\n    {\n      x = small (dP);\n\n      return x;\n    }\n\n  pp = (P < 0.5) ? P : 1.0 - P;\n\n  r = sqrt (-log (pp));\n\n  if (r <= 5.0)\n    {\n      x = intermediate (r);\n    }\n  else\n    {\n      x = tail (r);\n    }\n\n  if (P < 0.5)\n    {\n      return -x;\n    }\n  else\n    {\n      return x;\n    }\n\n}\n\ndouble\ngsl_cdf_ugaussian_Qinv (const double Q)\n{\n  double r, x, pp;\n\n  double dQ = Q - 0.5;\n\n  if (Q == 1.0)\n    {\n      return GSL_NEGINF;\n    }\n  else if (Q == 0.0)\n    {\n      return GSL_POSINF;\n    }\n\n  if (fabs (dQ) <= 0.425)\n    {\n      x = small (dQ);\n\n      return -x;\n    }\n\n  pp = (Q < 0.5) ? Q : 1.0 - Q;\n\n  r = sqrt (-log (pp));\n\n  if (r <= 5.0)\n    {\n      x = intermediate (r);\n    }\n  else\n    {\n      x = tail (r);\n    }\n\n  if (Q < 0.5)\n    {\n      return x;\n    }\n  else\n    {\n      return -x;\n    }\n}\n\n\ndouble\ngsl_cdf_gaussian_Pinv (const double P, const double sigma)\n{\n  return sigma * gsl_cdf_ugaussian_Pinv (P);\n}\n\ndouble\ngsl_cdf_gaussian_Qinv (const double Q, const double sigma)\n{\n  return sigma * gsl_cdf_ugaussian_Qinv (Q);\n}\n"
  },
  {
    "path": "gsl/cdf/gsl_cdf.h",
    "content": "/* cdf/gsl_cdf.h\n * \n * Copyright (C) 2002 Jason H. Stover.\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  J. Stover */\n\n#ifndef __GSL_CDF_H__\n#define __GSL_CDF_H__\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS          /* empty */\n# define __END_DECLS            /* empty */\n#endif\n\n__BEGIN_DECLS \n\ndouble gsl_cdf_ugaussian_P (const double x);\ndouble gsl_cdf_ugaussian_Q (const double x);\n\ndouble gsl_cdf_ugaussian_Pinv (const double P);\ndouble gsl_cdf_ugaussian_Qinv (const double Q);\n\ndouble gsl_cdf_gaussian_P (const double x, const double sigma);\ndouble gsl_cdf_gaussian_Q (const double x, const double sigma);\n\ndouble gsl_cdf_gaussian_Pinv (const double P, const double sigma);\ndouble gsl_cdf_gaussian_Qinv (const double Q, const double sigma);\n\ndouble gsl_cdf_gamma_P (const double x, const double a, const double b);\ndouble gsl_cdf_gamma_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_gamma_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_gamma_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_cauchy_P (const double x, const double a);\ndouble gsl_cdf_cauchy_Q (const double x, const double a);\n\ndouble gsl_cdf_cauchy_Pinv (const double P, const double a);\ndouble gsl_cdf_cauchy_Qinv (const double Q, const double a);\n\ndouble gsl_cdf_laplace_P (const double x, const double a);\ndouble gsl_cdf_laplace_Q (const double x, const double a);\n\ndouble gsl_cdf_laplace_Pinv (const double P, const double a);\ndouble gsl_cdf_laplace_Qinv (const double Q, const double a);\n\ndouble gsl_cdf_rayleigh_P (const double x, const double sigma);\ndouble gsl_cdf_rayleigh_Q (const double x, const double sigma);\n\ndouble gsl_cdf_rayleigh_Pinv (const double P, const double sigma);\ndouble gsl_cdf_rayleigh_Qinv (const double Q, const double sigma);\n\ndouble gsl_cdf_chisq_P (const double x, const double nu);\ndouble gsl_cdf_chisq_Q (const double x, const double nu);\n\ndouble gsl_cdf_chisq_Pinv (const double P, const double nu);\ndouble gsl_cdf_chisq_Qinv (const double Q, const double nu);\n\ndouble gsl_cdf_exponential_P (const double x, const double mu);\ndouble gsl_cdf_exponential_Q (const double x, const double mu);\n\ndouble gsl_cdf_exponential_Pinv (const double P, const double mu);\ndouble gsl_cdf_exponential_Qinv (const double Q, const double mu);\n\ndouble gsl_cdf_exppow_P (const double x, const double a, const double b);\ndouble gsl_cdf_exppow_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_tdist_P (const double x, const double nu);\ndouble gsl_cdf_tdist_Q (const double x, const double nu);\n\ndouble gsl_cdf_tdist_Pinv (const double P, const double nu);\ndouble gsl_cdf_tdist_Qinv (const double Q, const double nu);\n\ndouble gsl_cdf_fdist_P (const double x, const double nu1, const double nu2);\ndouble gsl_cdf_fdist_Q (const double x, const double nu1, const double nu2);\n\ndouble gsl_cdf_fdist_Pinv (const double P, const double nu1, const double nu2);\ndouble gsl_cdf_fdist_Qinv (const double Q, const double nu1, const double nu2);\n\ndouble gsl_cdf_beta_P (const double x, const double a, const double b);\ndouble gsl_cdf_beta_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_beta_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_beta_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_flat_P (const double x, const double a, const double b);\ndouble gsl_cdf_flat_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_flat_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_flat_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_lognormal_P (const double x, const double zeta, const double sigma);\ndouble gsl_cdf_lognormal_Q (const double x, const double zeta, const double sigma);\n\ndouble gsl_cdf_lognormal_Pinv (const double P, const double zeta, const double sigma);\ndouble gsl_cdf_lognormal_Qinv (const double Q, const double zeta, const double sigma);\n\ndouble gsl_cdf_gumbel1_P (const double x, const double a, const double b);\ndouble gsl_cdf_gumbel1_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_gumbel1_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_gumbel1_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_gumbel2_P (const double x, const double a, const double b);\ndouble gsl_cdf_gumbel2_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_gumbel2_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_gumbel2_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_weibull_P (const double x, const double a, const double b);\ndouble gsl_cdf_weibull_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_weibull_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_weibull_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_pareto_P (const double x, const double a, const double b);\ndouble gsl_cdf_pareto_Q (const double x, const double a, const double b);\n\ndouble gsl_cdf_pareto_Pinv (const double P, const double a, const double b);\ndouble gsl_cdf_pareto_Qinv (const double Q, const double a, const double b);\n\ndouble gsl_cdf_logistic_P (const double x, const double a);\ndouble gsl_cdf_logistic_Q (const double x, const double a);\n\ndouble gsl_cdf_logistic_Pinv (const double P, const double a);\ndouble gsl_cdf_logistic_Qinv (const double Q, const double a);\n\ndouble gsl_cdf_binomial_P (const unsigned int k, const double p, const unsigned int n);\ndouble gsl_cdf_binomial_Q (const unsigned int k, const double p, const unsigned int n);\n\ndouble gsl_cdf_poisson_P (const unsigned int k, const double mu);\ndouble gsl_cdf_poisson_Q (const unsigned int k, const double mu);\n\ndouble gsl_cdf_geometric_P (const unsigned int k, const double p);\ndouble gsl_cdf_geometric_Q (const unsigned int k, const double p);\n\ndouble gsl_cdf_negative_binomial_P (const unsigned int k, const double p, const double n);\ndouble gsl_cdf_negative_binomial_Q (const unsigned int k, const double p, const double n);\n\ndouble gsl_cdf_pascal_P (const unsigned int k, const double p, const unsigned int n);\ndouble gsl_cdf_pascal_Q (const unsigned int k, const double p, const unsigned int n);\n\ndouble gsl_cdf_hypergeometric_P (const unsigned int k, const unsigned int n1,\n                                 const unsigned int n2, const unsigned int t);\ndouble gsl_cdf_hypergeometric_Q (const unsigned int k, const unsigned int n1,\n                                 const unsigned int n2, const unsigned int t);\n\n__END_DECLS\n\n#endif /* __GSL_CDF_H__ */\n"
  },
  {
    "path": "gsl/cdf/rat_eval.h",
    "content": "static double\nrat_eval (const double a[], const size_t na,\n          const double b[], const size_t nb, const double x)\n{\n  size_t i, j;\n  double u, v, r;\n\n  u = a[na - 1];\n\n  for (i = na - 1; i > 0; i--)\n    {\n      u = x * u + a[i - 1];\n    }\n\n  v = b[nb - 1];\n\n  for (j = nb - 1; j > 0; j--)\n    {\n      v = x * v + b[j - 1];\n    }\n\n  r = u / v;\n\n  return r;\n}\n"
  },
  {
    "path": "gsl/cdf/tdist.c",
    "content": "/* cdf/tdist.c\n *\n * Copyright (C) 2002 Jason H. Stover.\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software Foundation,\n * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * Computes the Student's t cumulative distribution function using\n * the method detailed in \n * \n * W.J. Kennedy and J.E. Gentle, \"Statistical Computing.\" 1980. \n * Marcel Dekker. ISBN 0-8247-6898-1.\n *\n * G.W. Hill and A.W. Davis. \"Generalized asymptotic expansions\n * of Cornish-Fisher type.\" Annals of Mathematical Statistics, \n * vol. 39, 1264-1273. 1968.\n *\n * G.W. Hill. \"Algorithm 395: Student's t-distribution,\" Communications\n * of the ACM, volume 13, number 10, page 617. October 1970.\n *\n * G.W. Hill, \"Remark on algorithm 395: Student's t-distribution,\"\n * Transactions on Mathematical Software, volume 7, number 2, page\n * 247. June 1982.\n */\n\n#include \"config.h\"\n#include \"gsl_cdf.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n\n#include \"beta_inc.inc\"\n\nstatic double\npoly_eval (const double c[], unsigned int n, double x)\n{\n  unsigned int i;\n  double y = c[0] * x;\n\n  for (i = 1; i < n; i++)\n    {\n      y = x * (y + c[i]);\n    }\n\n  y += c[n];\n\n  return y;\n}\n\n/* \n * Use the Cornish-Fisher asymptotic expansion to find a point u such\n * that gsl_cdf_gauss(y) = tcdf(t).\n * \n */\n\nstatic double\ncornish_fisher (double t, double n)\n{\n  const double coeffs6[10] = {\n    0.265974025974025974026,\n    5.449696969696969696970,\n    122.20294372294372294372,\n    2354.7298701298701298701,\n    37625.00902597402597403,\n    486996.1392857142857143,\n    4960870.65,\n    37978595.55,\n    201505390.875,\n    622437908.625\n  };\n  const double coeffs5[8] = {\n    0.2742857142857142857142,\n    4.499047619047619047619,\n    78.45142857142857142857,\n    1118.710714285714285714,\n    12387.6,\n    101024.55,\n    559494.0,\n    1764959.625\n  };\n  const double coeffs4[6] = {\n    0.3047619047619047619048,\n    3.752380952380952380952,\n    46.67142857142857142857,\n    427.5,\n    2587.5,\n    8518.5\n  };\n  const double coeffs3[4] = {\n    0.4,\n    3.3,\n    24.0,\n    85.5\n  };\n\n  double a = n - 0.5;\n  double b = 48.0 * a * a;\n\n  double z2 = a * log1p (t * t / n);\n  double z = sqrt (z2);\n\n  double p5 = z * poly_eval (coeffs6, 9, z2);\n  double p4 = -z * poly_eval (coeffs5, 7, z2);\n  double p3 = z * poly_eval (coeffs4, 5, z2);\n  double p2 = -z * poly_eval (coeffs3, 3, z2);\n  double p1 = z * (z2 + 3.0);\n  double p0 = z;\n\n  double y = p5;\n  y = (y / b) + p4;\n  y = (y / b) + p3;\n  y = (y / b) + p2;\n  y = (y / b) + p1;\n  y = (y / b) + p0;\n\n  if (t < 0)\n    y *= -1;\n\n  return y;\n}\n\n#if 0\n/*\n * Series approximation for t > 4.0. This needs to be fixed;\n * it shouldn't subtract the result from 1.0. A better way is\n * to use two different series expansions. Figuring this out\n * means rummaging through Fisher's paper in Metron, v5, 1926, \n * \"Expansion of Student's integral in powers of n^{-1}.\"\n */\n\n#define MAXI 40\n\nstatic double\nnormal_approx (const double x, const double nu)\n{\n  double y;\n  double num;\n  double diff;\n  double q;\n  int i;\n  double lg1, lg2;\n\n  y = 1 / sqrt (1 + x * x / nu);\n  num = 1.0;\n  q = 0.0;\n  diff = 2 * GSL_DBL_EPSILON;\n  for (i = 2; (i < MAXI) && (diff > GSL_DBL_EPSILON); i += 2)\n    {\n      diff = q;\n      num *= y * y * (i - 1) / i;\n      q += num / (nu + i);\n      diff = q - diff;\n    }\n  q += 1 / nu;\n  lg1 = gsl_sf_lngamma (nu / 2.0);\n  lg2 = gsl_sf_lngamma ((nu + 1.0) / 2.0);\n\n  diff = lg2 - lg1;\n  q *= pow (y, nu) * exp (diff) / sqrt (M_PI);\n\n  return q;\n}\n#endif\n\ndouble\ngsl_cdf_tdist_P (const double x, const double nu)\n{\n  double P;\n\n  double x2 = x * x;\n\n  if (nu > 30 && x2 < 10 * nu)\n    {\n      double u = cornish_fisher (x, nu);\n      P = gsl_cdf_ugaussian_P (u);\n\n      return P;\n    }\n\n  if (x2 < nu)\n    {\n      double u = x2 / nu;\n      double eps = u / (1 + u);\n\n      if (x >= 0)\n        {\n          P = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);\n        }\n      else\n        {\n          P = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);\n        }\n    }\n  else\n    {\n      double v = nu / (x * x);\n      double eps = v / (1 + v);\n\n      if (x >= 0)\n        {\n          P = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);\n        }\n      else\n        {\n          P = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);\n        }\n    }\n\n  return P;\n}\n\n\ndouble\ngsl_cdf_tdist_Q (const double x, const double nu)\n{\n  double Q;\n\n  double x2 = x * x;\n\n  if (nu > 30 && x2 < 10 * nu)\n    {\n      double u = cornish_fisher (x, nu);\n      Q = gsl_cdf_ugaussian_Q (u);\n\n      return Q;\n    }\n\n  if (x2 < nu)\n    {\n      double u = x2 / nu;\n      double eps = u / (1 + u);\n\n      if (x >= 0)\n        {\n          Q = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);\n        }\n      else\n        {\n          Q = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);\n        }\n    }\n  else\n    {\n      double v = nu / (x * x);\n      double eps = v / (1 + v);\n\n      if (x >= 0)\n        {\n          Q = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);\n        }\n      else\n        {\n          Q = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);\n        }\n    }\n\n  return Q;\n}\n"
  },
  {
    "path": "gsl/complex/gsl_complex.h",
    "content": "/* complex/gsl_complex.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_COMPLEX_H__\n#define __GSL_COMPLEX_H__\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* two consecutive built-in types as a complex number */\ntypedef double *       gsl_complex_packed ;\ntypedef float *        gsl_complex_packed_float  ;\ntypedef long double *  gsl_complex_packed_long_double ;\n\ntypedef const double *       gsl_const_complex_packed ;\ntypedef const float *        gsl_const_complex_packed_float  ;\ntypedef const long double *  gsl_const_complex_packed_long_double ;\n\n\n/* 2N consecutive built-in types as N complex numbers */\ntypedef double *       gsl_complex_packed_array ;\ntypedef float *        gsl_complex_packed_array_float  ;\ntypedef long double *  gsl_complex_packed_array_long_double ;\n\ntypedef const double *       gsl_const_complex_packed_array ;\ntypedef const float *        gsl_const_complex_packed_array_float  ;\ntypedef const long double *  gsl_const_complex_packed_array_long_double ;\n\n\n/* Yes... this seems weird. Trust us. The point is just that\n   sometimes you want to make it obvious that something is\n   an output value. The fact that it lacks a 'const' may not\n   be enough of a clue for people in some contexts.\n */\ntypedef double *       gsl_complex_packed_ptr ;\ntypedef float *        gsl_complex_packed_float_ptr  ;\ntypedef long double *  gsl_complex_packed_long_double_ptr ;\n\ntypedef const double *       gsl_const_complex_packed_ptr ;\ntypedef const float *        gsl_const_complex_packed_float_ptr  ;\ntypedef const long double *  gsl_const_complex_packed_long_double_ptr ;\n\n\ntypedef struct\n  {\n    long double dat[2];\n  }\ngsl_complex_long_double;\n\ntypedef struct\n  {\n    double dat[2];\n  }\ngsl_complex;\n\ntypedef struct\n  {\n    float dat[2];\n  }\ngsl_complex_float;\n\n#define GSL_REAL(z)     ((z).dat[0])\n#define GSL_IMAG(z)     ((z).dat[1])\n#define GSL_COMPLEX_P(zp) ((zp)->dat)\n#define GSL_COMPLEX_P_REAL(zp)  ((zp)->dat[0])\n#define GSL_COMPLEX_P_IMAG(zp)  ((zp)->dat[1])\n#define GSL_COMPLEX_EQ(z1,z2) (((z1).dat[0] == (z2).dat[0]) && ((z1).dat[1] == (z2).dat[1]))\n\n#define GSL_SET_COMPLEX(zp,x,y) do {(zp)->dat[0]=(x); (zp)->dat[1]=(y);} while(0)\n#define GSL_SET_REAL(zp,x) do {(zp)->dat[0]=(x);} while(0)\n#define GSL_SET_IMAG(zp,y) do {(zp)->dat[1]=(y);} while(0)\n\n#define GSL_SET_COMPLEX_PACKED(zp,n,x,y) do {*((zp)+2*(n))=(x); *((zp)+(2*(n)+1))=(y);} while(0)\n\n__END_DECLS\n\n#endif /* __GSL_COMPLEX_H__ */\n"
  },
  {
    "path": "gsl/complex/gsl_complex_math.h",
    "content": "/* complex/gsl_complex_math.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Jorma Olavi Thtinen, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_COMPLEX_MATH_H__\n#define __GSL_COMPLEX_MATH_H__\n#include \"gsl_inline.h\"\n#include \"gsl_complex.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n#define __BEGIN_DECLS extern \"C\" {\n#define __END_DECLS }\n#else\n#define __BEGIN_DECLS           /* empty */\n#define __END_DECLS             /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* Complex numbers */\n\ngsl_complex gsl_complex_polar (double r, double theta); /* r= r e^(i theta) */\n\nINLINE_DECL gsl_complex gsl_complex_rect (double x, double y);  /* r= real+i*imag */\n\n#ifdef HAVE_INLINE\nINLINE_FUN gsl_complex\ngsl_complex_rect (double x, double y)\n{                               /* return z = x + i y */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, x, y);\n  return z;\n}\n#endif\n\n#define GSL_COMPLEX_ONE (gsl_complex_rect(1.0,0.0))\n#define GSL_COMPLEX_ZERO (gsl_complex_rect(0.0,0.0))\n#define GSL_COMPLEX_NEGONE (gsl_complex_rect(-1.0,0.0))\n\n/* Properties of complex numbers */\n\ndouble gsl_complex_arg (gsl_complex z); /* return arg(z), -pi< arg(z) <=+pi */\ndouble gsl_complex_abs (gsl_complex z);   /* return |z|   */\ndouble gsl_complex_abs2 (gsl_complex z);  /* return |z|^2 */\ndouble gsl_complex_logabs (gsl_complex z); /* return log|z| */\n\n/* Complex arithmetic operators */\n\ngsl_complex gsl_complex_add (gsl_complex a, gsl_complex b);  /* r=a+b */\ngsl_complex gsl_complex_sub (gsl_complex a, gsl_complex b);  /* r=a-b */\ngsl_complex gsl_complex_mul (gsl_complex a, gsl_complex b);  /* r=a*b */\ngsl_complex gsl_complex_div (gsl_complex a, gsl_complex b);  /* r=a/b */\n                                                           \ngsl_complex gsl_complex_add_real (gsl_complex a, double x);  /* r=a+x */\ngsl_complex gsl_complex_sub_real (gsl_complex a, double x);  /* r=a-x */\ngsl_complex gsl_complex_mul_real (gsl_complex a, double x);  /* r=a*x */\ngsl_complex gsl_complex_div_real (gsl_complex a, double x);  /* r=a/x */\n\ngsl_complex gsl_complex_add_imag (gsl_complex a, double y);  /* r=a+iy */\ngsl_complex gsl_complex_sub_imag (gsl_complex a, double y);  /* r=a-iy */\ngsl_complex gsl_complex_mul_imag (gsl_complex a, double y);  /* r=a*iy */\ngsl_complex gsl_complex_div_imag (gsl_complex a, double y);  /* r=a/iy */\n\ngsl_complex gsl_complex_conjugate (gsl_complex z);  /* r=conj(z) */\ngsl_complex gsl_complex_inverse (gsl_complex a);    /* r=1/a */\ngsl_complex gsl_complex_negative (gsl_complex a);    /* r=-a */\n\n/* Elementary Complex Functions */\n\ngsl_complex gsl_complex_sqrt (gsl_complex z);  /* r=sqrt(z) */\ngsl_complex gsl_complex_sqrt_real (double x);  /* r=sqrt(x) (x<0 ok) */\n\ngsl_complex gsl_complex_pow (gsl_complex a, gsl_complex b);  /* r=a^b */\ngsl_complex gsl_complex_pow_real (gsl_complex a, double b);  /* r=a^b */\n\ngsl_complex gsl_complex_exp (gsl_complex a);    /* r=exp(a) */\ngsl_complex gsl_complex_log (gsl_complex a);    /* r=log(a) (base e) */\ngsl_complex gsl_complex_log10 (gsl_complex a);  /* r=log10(a) (base 10) */\ngsl_complex gsl_complex_log_b (gsl_complex a, gsl_complex b);   /* r=log_b(a) (base=b) */\n\n/* Complex Trigonometric Functions */\n\ngsl_complex gsl_complex_sin (gsl_complex a);  /* r=sin(a) */\ngsl_complex gsl_complex_cos (gsl_complex a);  /* r=cos(a) */\ngsl_complex gsl_complex_sec (gsl_complex a);  /* r=sec(a) */\ngsl_complex gsl_complex_csc (gsl_complex a);  /* r=csc(a) */\ngsl_complex gsl_complex_tan (gsl_complex a);  /* r=tan(a) */\ngsl_complex gsl_complex_cot (gsl_complex a);  /* r=cot(a) */\n\n/* Inverse Complex Trigonometric Functions */\n\ngsl_complex gsl_complex_arcsin (gsl_complex a);  /* r=arcsin(a) */\ngsl_complex gsl_complex_arcsin_real (double a);  /* r=arcsin(a) */\ngsl_complex gsl_complex_arccos (gsl_complex a);  /* r=arccos(a) */\ngsl_complex gsl_complex_arccos_real (double a);  /* r=arccos(a) */\ngsl_complex gsl_complex_arcsec (gsl_complex a);  /* r=arcsec(a) */\ngsl_complex gsl_complex_arcsec_real (double a);  /* r=arcsec(a) */\ngsl_complex gsl_complex_arccsc (gsl_complex a);  /* r=arccsc(a) */\ngsl_complex gsl_complex_arccsc_real (double a);  /* r=arccsc(a) */\ngsl_complex gsl_complex_arctan (gsl_complex a);  /* r=arctan(a) */\ngsl_complex gsl_complex_arccot (gsl_complex a);  /* r=arccot(a) */\n\n/* Complex Hyperbolic Functions */\n\ngsl_complex gsl_complex_sinh (gsl_complex a);  /* r=sinh(a) */\ngsl_complex gsl_complex_cosh (gsl_complex a);  /* r=coshh(a) */\ngsl_complex gsl_complex_sech (gsl_complex a);  /* r=sech(a) */\ngsl_complex gsl_complex_csch (gsl_complex a);  /* r=csch(a) */\ngsl_complex gsl_complex_tanh (gsl_complex a);  /* r=tanh(a) */\ngsl_complex gsl_complex_coth (gsl_complex a);  /* r=coth(a) */\n\n/* Inverse Complex Hyperbolic Functions */\n\ngsl_complex gsl_complex_arcsinh (gsl_complex a);  /* r=arcsinh(a) */\ngsl_complex gsl_complex_arccosh (gsl_complex a);  /* r=arccosh(a) */\ngsl_complex gsl_complex_arccosh_real (double a);  /* r=arccosh(a) */\ngsl_complex gsl_complex_arcsech (gsl_complex a);  /* r=arcsech(a) */\ngsl_complex gsl_complex_arccsch (gsl_complex a);  /* r=arccsch(a) */\ngsl_complex gsl_complex_arctanh (gsl_complex a);  /* r=arctanh(a) */\ngsl_complex gsl_complex_arctanh_real (double a);  /* r=arctanh(a) */\ngsl_complex gsl_complex_arccoth (gsl_complex a);  /* r=arccoth(a) */\n\n__END_DECLS\n\n#endif /* __GSL_COMPLEX_MATH_H__ */\n"
  },
  {
    "path": "gsl/complex/inline.c",
    "content": "/* complex/inline.c\n * \n * Copyright (C) 2008 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_complex_math.h\"\n"
  },
  {
    "path": "gsl/complex/math.c",
    "content": "/* complex/math.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Jorma Olavi Thtinen, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Basic complex arithmetic functions\n\n * Original version by Jorma Olavi Thtinen <jotahtin@cc.hut.fi>\n *\n * Modified for GSL by Brian Gough, 3/2000\n */\n\n/* The following references describe the methods used in these\n * functions,\n *\n *   T. E. Hull and Thomas F. Fairgrieve and Ping Tak Peter Tang,\n *   \"Implementing Complex Elementary Functions Using Exception\n *   Handling\", ACM Transactions on Mathematical Software, Volume 20\n *   (1994), pp 215-244, Corrigenda, p553\n *\n *   Hull et al, \"Implementing the complex arcsin and arccosine\n *   functions using exception handling\", ACM Transactions on\n *   Mathematical Software, Volume 23 (1997) pp 299-335\n *\n *   Abramowitz and Stegun, Handbook of Mathematical Functions, \"Inverse\n *   Circular Functions in Terms of Real and Imaginary Parts\", Formulas\n *   4.4.37, 4.4.38, 4.4.39\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_complex.h\"\n#include \"gsl_complex_math.h\"\n\n/**********************************************************************\n * Complex numbers\n **********************************************************************/\n\ngsl_complex\ngsl_complex_polar (double r, double theta)\n{                               /* return z = r exp(i theta) */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, r * cos (theta), r * sin (theta));\n  return z;\n}\n\n/**********************************************************************\n * Properties of complex numbers\n **********************************************************************/\n\ndouble\ngsl_complex_arg (gsl_complex z)\n{                               /* return arg(z),  -pi < arg(z) <= +pi */\n  double x = GSL_REAL (z);\n  double y = GSL_IMAG (z);\n\n  if (x == 0.0 && y == 0.0)\n    {\n      return 0;\n    }\n\n  return atan2 (y, x);\n}\n\ndouble\ngsl_complex_abs (gsl_complex z)\n{                               /* return |z| */\n  return hypot (GSL_REAL (z), GSL_IMAG (z));\n}\n\ndouble\ngsl_complex_abs2 (gsl_complex z)\n{                               /* return |z|^2 */\n  double x = GSL_REAL (z);\n  double y = GSL_IMAG (z);\n\n  return (x * x + y * y);\n}\n\ndouble\ngsl_complex_logabs (gsl_complex z)\n{                               /* return log|z| */\n  double xabs = fabs (GSL_REAL (z));\n  double yabs = fabs (GSL_IMAG (z));\n  double max, u;\n\n  if (xabs >= yabs)\n    {\n      max = xabs;\n      u = yabs / xabs;\n    }\n  else\n    {\n      max = yabs;\n      u = xabs / yabs;\n    }\n\n  /* Handle underflow when u is close to 0 */\n\n  return log (max) + 0.5 * log1p (u * u);\n}\n\n\n/***********************************************************************\n * Complex arithmetic operators\n ***********************************************************************/\n\ngsl_complex\ngsl_complex_add (gsl_complex a, gsl_complex b)\n{                               /* z=a+b */\n  double ar = GSL_REAL (a), ai = GSL_IMAG (a);\n  double br = GSL_REAL (b), bi = GSL_IMAG (b);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, ar + br, ai + bi);\n  return z;\n}\n\ngsl_complex\ngsl_complex_add_real (gsl_complex a, double x)\n{                               /* z=a+x */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a) + x, GSL_IMAG (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_add_imag (gsl_complex a, double y)\n{                               /* z=a+iy */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a), GSL_IMAG (a) + y);\n  return z;\n}\n\n\ngsl_complex\ngsl_complex_sub (gsl_complex a, gsl_complex b)\n{                               /* z=a-b */\n  double ar = GSL_REAL (a), ai = GSL_IMAG (a);\n  double br = GSL_REAL (b), bi = GSL_IMAG (b);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, ar - br, ai - bi);\n  return z;\n}\n\ngsl_complex\ngsl_complex_sub_real (gsl_complex a, double x)\n{                               /* z=a-x */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a) - x, GSL_IMAG (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_sub_imag (gsl_complex a, double y)\n{                               /* z=a-iy */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a), GSL_IMAG (a) - y);\n  return z;\n}\n\ngsl_complex\ngsl_complex_mul (gsl_complex a, gsl_complex b)\n{                               /* z=a*b */\n  double ar = GSL_REAL (a), ai = GSL_IMAG (a);\n  double br = GSL_REAL (b), bi = GSL_IMAG (b);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, ar * br - ai * bi, ar * bi + ai * br);\n  return z;\n}\n\ngsl_complex\ngsl_complex_mul_real (gsl_complex a, double x)\n{                               /* z=a*x */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, x * GSL_REAL (a), x * GSL_IMAG (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_mul_imag (gsl_complex a, double y)\n{                               /* z=a*iy */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, -y * GSL_IMAG (a), y * GSL_REAL (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_div (gsl_complex a, gsl_complex b)\n{                               /* z=a/b */\n  double ar = GSL_REAL (a), ai = GSL_IMAG (a);\n  double br = GSL_REAL (b), bi = GSL_IMAG (b);\n\n  double s = 1.0 / gsl_complex_abs (b);\n\n  double sbr = s * br;\n  double sbi = s * bi;\n\n  double zr = (ar * sbr + ai * sbi) * s;\n  double zi = (ai * sbr - ar * sbi) * s;\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, zr, zi);\n  return z;\n}\n\ngsl_complex\ngsl_complex_div_real (gsl_complex a, double x)\n{                               /* z=a/x */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a) / x, GSL_IMAG (a) / x);\n  return z;\n}\n\ngsl_complex\ngsl_complex_div_imag (gsl_complex a, double y)\n{                               /* z=a/(iy) */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_IMAG (a) / y,  - GSL_REAL (a) / y);\n  return z;\n}\n\ngsl_complex\ngsl_complex_conjugate (gsl_complex a)\n{                               /* z=conj(a) */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, GSL_REAL (a), -GSL_IMAG (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_negative (gsl_complex a)\n{                               /* z=-a */\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, -GSL_REAL (a), -GSL_IMAG (a));\n  return z;\n}\n\ngsl_complex\ngsl_complex_inverse (gsl_complex a)\n{                               /* z=1/a */\n  double s = 1.0 / gsl_complex_abs (a);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, (GSL_REAL (a) * s) * s, -(GSL_IMAG (a) * s) * s);\n  return z;\n}\n\n/**********************************************************************\n * Elementary complex functions\n **********************************************************************/\n\ngsl_complex\ngsl_complex_sqrt (gsl_complex a)\n{                               /* z=sqrt(a) */\n  gsl_complex z;\n\n  if (GSL_REAL (a) == 0.0 && GSL_IMAG (a) == 0.0)\n    {\n      GSL_SET_COMPLEX (&z, 0, 0);\n    }\n  else\n    {\n      double x = fabs (GSL_REAL (a));\n      double y = fabs (GSL_IMAG (a));\n      double w;\n\n      if (x >= y)\n        {\n          double t = y / x;\n          w = sqrt (x) * sqrt (0.5 * (1.0 + sqrt (1.0 + t * t)));\n        }\n      else\n        {\n          double t = x / y;\n          w = sqrt (y) * sqrt (0.5 * (t + sqrt (1.0 + t * t)));\n        }\n\n      if (GSL_REAL (a) >= 0.0)\n        {\n          double ai = GSL_IMAG (a);\n          GSL_SET_COMPLEX (&z, w, ai / (2.0 * w));\n        }\n      else\n        {\n          double ai = GSL_IMAG (a);\n          double vi = (ai >= 0) ? w : -w;\n          GSL_SET_COMPLEX (&z, ai / (2.0 * vi), vi);\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_sqrt_real (double x)\n{                               /* z=sqrt(x) */\n  gsl_complex z;\n\n  if (x >= 0)\n    {\n      GSL_SET_COMPLEX (&z, sqrt (x), 0.0);\n    }\n  else\n    {\n      GSL_SET_COMPLEX (&z, 0.0, sqrt (-x));\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_exp (gsl_complex a)\n{                               /* z=exp(a) */\n  double rho = exp (GSL_REAL (a));\n  double theta = GSL_IMAG (a);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, rho * cos (theta), rho * sin (theta));\n  return z;\n}\n\ngsl_complex\ngsl_complex_pow (gsl_complex a, gsl_complex b)\n{                               /* z=a^b */\n  gsl_complex z;\n\n  if (GSL_REAL (a) == 0 && GSL_IMAG (a) == 0.0)\n    {\n      if (GSL_REAL (b) == 0 && GSL_IMAG (b) == 0.0)\n        {\n          GSL_SET_COMPLEX (&z, 1.0, 0.0);\n        }\n      else \n        {\n          GSL_SET_COMPLEX (&z, 0.0, 0.0);\n        }\n    }\n  else if (GSL_REAL (b) == 1.0 && GSL_IMAG (b) == 0.0) \n    {\n      return a;\n    }\n  else if (GSL_REAL (b) == -1.0 && GSL_IMAG (b) == 0.0) \n    {\n      return gsl_complex_inverse (a);\n    }\n  else\n    {\n      double logr = gsl_complex_logabs (a);\n      double theta = gsl_complex_arg (a);\n\n      double br = GSL_REAL (b), bi = GSL_IMAG (b);\n\n      double rho = exp (logr * br - bi * theta);\n      double beta = theta * br + bi * logr;\n\n      GSL_SET_COMPLEX (&z, rho * cos (beta), rho * sin (beta));\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_pow_real (gsl_complex a, double b)\n{                               /* z=a^b */\n  gsl_complex z;\n\n  if (GSL_REAL (a) == 0 && GSL_IMAG (a) == 0)\n    {\n      if (b == 0)\n        {\n          GSL_SET_COMPLEX (&z, 1, 0);\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, 0, 0);\n        }\n    }\n  else\n    {\n      double logr = gsl_complex_logabs (a);\n      double theta = gsl_complex_arg (a);\n      double rho = exp (logr * b);\n      double beta = theta * b;\n      GSL_SET_COMPLEX (&z, rho * cos (beta), rho * sin (beta));\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_log (gsl_complex a)\n{                               /* z=log(a) */\n  double logr = gsl_complex_logabs (a);\n  double theta = gsl_complex_arg (a);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, logr, theta);\n  return z;\n}\n\ngsl_complex\ngsl_complex_log10 (gsl_complex a)\n{                               /* z = log10(a) */\n  return gsl_complex_mul_real (gsl_complex_log (a), 1 / log (10.));\n}\n\ngsl_complex\ngsl_complex_log_b (gsl_complex a, gsl_complex b)\n{\n  return gsl_complex_div (gsl_complex_log (a), gsl_complex_log (b));\n}\n\n/***********************************************************************\n * Complex trigonometric functions\n ***********************************************************************/\n\ngsl_complex\ngsl_complex_sin (gsl_complex a)\n{                               /* z = sin(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n\n  gsl_complex z;\n\n  if (I == 0.0) \n    {\n      /* avoid returing negative zero (-0.0) for the imaginary part  */\n\n      GSL_SET_COMPLEX (&z, sin (R), 0.0);  \n    } \n  else \n    {\n      GSL_SET_COMPLEX (&z, sin (R) * cosh (I), cos (R) * sinh (I));\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_cos (gsl_complex a)\n{                               /* z = cos(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n\n  gsl_complex z;\n\n  if (I == 0.0) \n    {\n      /* avoid returing negative zero (-0.0) for the imaginary part  */\n\n      GSL_SET_COMPLEX (&z, cos (R), 0.0);  \n    } \n  else \n    {\n      GSL_SET_COMPLEX (&z, cos (R) * cosh (I), sin (R) * sinh (-I));\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_tan (gsl_complex a)\n{                               /* z = tan(a) */\n\tdouble R = GSL_REAL (a), I = GSL_IMAG (a);\n\t\n\tgsl_complex z;\n\t\n\tif (fabs (I) < 1)\n\t{\n\t\tdouble D = pow (cos (R), 2.0) + pow (sinh (I), 2.0);\n\t\t\n\t\tGSL_SET_COMPLEX (&z, 0.5 * sin (2 * R) / D, 0.5 * sinh (2 * I) / D);\n\t}\n\telse\n\t{\n\t\tdouble D = pow (cos (R), 2.0) + pow (sinh (I), 2.0);\n\t\tdouble F = 1 + pow(cos (R)/sinh (I), 2.0);\n\t\t\n\t\tGSL_SET_COMPLEX (&z, 0.5 * sin (2 * R) / D, 1 / (tanh (I) * F));\n\t}\n\t\n\treturn z;\n}\n\ngsl_complex\ngsl_complex_sec (gsl_complex a)\n{                               /* z = sec(a) */\n  gsl_complex z = gsl_complex_cos (a);\n  return gsl_complex_inverse (z);\n}\n\ngsl_complex\ngsl_complex_csc (gsl_complex a)\n{                               /* z = csc(a) */\n  gsl_complex z = gsl_complex_sin (a);\n  return gsl_complex_inverse(z);\n}\n\n\ngsl_complex\ngsl_complex_cot (gsl_complex a)\n{                               /* z = cot(a) */\n  gsl_complex z = gsl_complex_tan (a);\n  return gsl_complex_inverse (z);\n}\n\n/**********************************************************************\n * Inverse Complex Trigonometric Functions\n **********************************************************************/\n\ngsl_complex\ngsl_complex_arcsin (gsl_complex a)\n{                               /* z = arcsin(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n  gsl_complex z;\n\n  if (I == 0)\n    {\n      z = gsl_complex_arcsin_real (R);\n    }\n  else\n    {\n      double x = fabs (R), y = fabs (I);\n      double r = hypot (x + 1, y), s = hypot (x - 1, y);\n      double A = 0.5 * (r + s);\n      double B = x / A;\n      double y2 = y * y;\n\n      double real, imag;\n\n      const double A_crossover = 1.5, B_crossover = 0.6417;\n\n      if (B <= B_crossover)\n        {\n          real = asin (B);\n        }\n      else\n        {\n          if (x <= 1)\n            {\n              double D = 0.5 * (A + x) * (y2 / (r + x + 1) + (s + (1 - x)));\n              real = atan (x / sqrt (D));\n            }\n          else\n            {\n              double Apx = A + x;\n              double D = 0.5 * (Apx / (r + x + 1) + Apx / (s + (x - 1)));\n              real = atan (x / (y * sqrt (D)));\n            }\n        }\n\n      if (A <= A_crossover)\n        {\n          double Am1;\n\n          if (x < 1)\n            {\n              Am1 = 0.5 * (y2 / (r + (x + 1)) + y2 / (s + (1 - x)));\n            }\n          else\n            {\n              Am1 = 0.5 * (y2 / (r + (x + 1)) + (s + (x - 1)));\n            }\n\n          imag = log1p (Am1 + sqrt (Am1 * (A + 1)));\n        }\n      else\n        {\n          imag = log (A + sqrt (A * A - 1));\n        }\n\n      GSL_SET_COMPLEX (&z, (R >= 0) ? real : -real, (I >= 0) ? imag : -imag);\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arcsin_real (double a)\n{                               /* z = arcsin(a) */\n  gsl_complex z;\n\n  if (fabs (a) <= 1.0)\n    {\n      GSL_SET_COMPLEX (&z, asin (a), 0.0);\n    }\n  else\n    {\n      if (a < 0.0)\n        {\n          GSL_SET_COMPLEX (&z, -M_PI_2, acosh (-a));\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, M_PI_2, -acosh (a));\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccos (gsl_complex a)\n{                               /* z = arccos(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n  gsl_complex z;\n\n  if (I == 0)\n    {\n      z = gsl_complex_arccos_real (R);\n    }\n  else\n    {\n      double x = fabs (R), y = fabs (I);\n      double r = hypot (x + 1, y), s = hypot (x - 1, y);\n      double A = 0.5 * (r + s);\n      double B = x / A;\n      double y2 = y * y;\n\n      double real, imag;\n\n      const double A_crossover = 1.5, B_crossover = 0.6417;\n\n      if (B <= B_crossover)\n        {\n          real = acos (B);\n        }\n      else\n        {\n          if (x <= 1)\n            {\n              double D = 0.5 * (A + x) * (y2 / (r + x + 1) + (s + (1 - x)));\n              real = atan (sqrt (D) / x);\n            }\n          else\n            {\n              double Apx = A + x;\n              double D = 0.5 * (Apx / (r + x + 1) + Apx / (s + (x - 1)));\n              real = atan ((y * sqrt (D)) / x);\n            }\n        }\n\n      if (A <= A_crossover)\n        {\n          double Am1;\n\n          if (x < 1)\n            {\n              Am1 = 0.5 * (y2 / (r + (x + 1)) + y2 / (s + (1 - x)));\n            }\n          else\n            {\n              Am1 = 0.5 * (y2 / (r + (x + 1)) + (s + (x - 1)));\n            }\n\n          imag = log1p (Am1 + sqrt (Am1 * (A + 1)));\n        }\n      else\n        {\n          imag = log (A + sqrt (A * A - 1));\n        }\n\n      GSL_SET_COMPLEX (&z, (R >= 0) ? real : M_PI - real, (I >= 0) ? -imag : imag);\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccos_real (double a)\n{                               /* z = arccos(a) */\n  gsl_complex z;\n\n  if (fabs (a) <= 1.0)\n    {\n      GSL_SET_COMPLEX (&z, acos (a), 0);\n    }\n  else\n    {\n      if (a < 0.0)\n        {\n          GSL_SET_COMPLEX (&z, M_PI, -acosh (-a));\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, 0, acosh (a));\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arctan (gsl_complex a)\n{                               /* z = arctan(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n  gsl_complex z;\n\n  if (I == 0)\n    {\n      GSL_SET_COMPLEX (&z, atan (R), 0);\n    }\n  else\n    {\n      /* FIXME: This is a naive implementation which does not fully\n         take into account cancellation errors, overflow, underflow\n         etc.  It would benefit from the Hull et al treatment. */\n\n      double r = hypot (R, I);\n\n      double imag;\n\n      double u = 2 * I / (1 + r * r);\n\n      /* FIXME: the following cross-over should be optimized but 0.1\n         seems to work ok */\n\n      if (fabs (u) < 0.1)\n        {\n          imag = 0.25 * (log1p (u) - log1p (-u));\n        }\n      else\n        {\n          double A = hypot (R, I + 1);\n          double B = hypot (R, I - 1);\n          imag = 0.5 * log (A / B);\n        }\n\n      if (R == 0)\n        {\n          if (I > 1)\n            {\n              GSL_SET_COMPLEX (&z, M_PI_2, imag);\n            }\n          else if (I < -1)\n            {\n              GSL_SET_COMPLEX (&z, -M_PI_2, imag);\n            }\n          else\n            {\n              GSL_SET_COMPLEX (&z, 0, imag);\n            };\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, 0.5 * atan2 (2 * R, ((1 + r) * (1 - r))), imag);\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arcsec (gsl_complex a)\n{                               /* z = arcsec(a) */\n  gsl_complex z = gsl_complex_inverse (a);\n  return gsl_complex_arccos (z);\n}\n\ngsl_complex\ngsl_complex_arcsec_real (double a)\n{                               /* z = arcsec(a) */\n  gsl_complex z;\n\n  if (a <= -1.0 || a >= 1.0)\n    {\n      GSL_SET_COMPLEX (&z, acos (1 / a), 0.0);\n    }\n  else\n    {\n      if (a >= 0.0)\n        {\n          GSL_SET_COMPLEX (&z, 0, acosh (1 / a));\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, M_PI, -acosh (-1 / a));\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccsc (gsl_complex a)\n{                               /* z = arccsc(a) */\n  gsl_complex z = gsl_complex_inverse (a);\n  return gsl_complex_arcsin (z);\n}\n\ngsl_complex\ngsl_complex_arccsc_real (double a)\n{                               /* z = arccsc(a) */\n  gsl_complex z;\n\n  if (a <= -1.0 || a >= 1.0)\n    {\n      GSL_SET_COMPLEX (&z, asin (1 / a), 0.0);\n    }\n  else\n    {\n      if (a >= 0.0)\n        {\n          GSL_SET_COMPLEX (&z, M_PI_2, -acosh (1 / a));\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, -M_PI_2, acosh (-1 / a));\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccot (gsl_complex a)\n{                               /* z = arccot(a) */\n  gsl_complex z;\n\n  if (GSL_REAL (a) == 0.0 && GSL_IMAG (a) == 0.0)\n    {\n      GSL_SET_COMPLEX (&z, M_PI_2, 0);\n    }\n  else\n    {\n      z = gsl_complex_inverse (a);\n      z = gsl_complex_arctan (z);\n    }\n\n  return z;\n}\n\n/**********************************************************************\n * Complex Hyperbolic Functions\n **********************************************************************/\n\ngsl_complex\ngsl_complex_sinh (gsl_complex a)\n{                               /* z = sinh(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, sinh (R) * cos (I), cosh (R) * sin (I));\n  return z;\n}\n\ngsl_complex\ngsl_complex_cosh (gsl_complex a)\n{                               /* z = cosh(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n\n  gsl_complex z;\n  GSL_SET_COMPLEX (&z, cosh (R) * cos (I), sinh (R) * sin (I));\n  return z;\n}\n\ngsl_complex\ngsl_complex_tanh (gsl_complex a)\n{                               /* z = tanh(a) */\n  double R = GSL_REAL (a), I = GSL_IMAG (a);\n\n  gsl_complex z;\n\n  if (fabs(R) < 1.0) \n    {\n      double D = pow (cos (I), 2.0) + pow (sinh (R), 2.0);\n      \n      GSL_SET_COMPLEX (&z, sinh (R) * cosh (R) / D, 0.5 * sin (2 * I) / D);\n    }\n  else\n    {\n      double D = pow (cos (I), 2.0) + pow (sinh (R), 2.0);\n      double F = 1 + pow (cos (I) / sinh (R), 2.0);\n\n      GSL_SET_COMPLEX (&z, 1.0 / (tanh (R) * F), 0.5 * sin (2 * I) / D);\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_sech (gsl_complex a)\n{                               /* z = sech(a) */\n  gsl_complex z = gsl_complex_cosh (a);\n  return gsl_complex_inverse (z);\n}\n\ngsl_complex\ngsl_complex_csch (gsl_complex a)\n{                               /* z = csch(a) */\n  gsl_complex z = gsl_complex_sinh (a);\n  return gsl_complex_inverse (z);\n}\n\ngsl_complex\ngsl_complex_coth (gsl_complex a)\n{                               /* z = coth(a) */\n  gsl_complex z = gsl_complex_tanh (a);\n  return gsl_complex_inverse (z);\n}\n\n/**********************************************************************\n * Inverse Complex Hyperbolic Functions\n **********************************************************************/\n\ngsl_complex\ngsl_complex_arcsinh (gsl_complex a)\n{                               /* z = arcsinh(a) */\n  gsl_complex z = gsl_complex_mul_imag(a, 1.0);\n  z = gsl_complex_arcsin (z);\n  z = gsl_complex_mul_imag (z, -1.0);\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccosh (gsl_complex a)\n{                               /* z = arccosh(a) */\n  gsl_complex z = gsl_complex_arccos (a);\n  z = gsl_complex_mul_imag (z, GSL_IMAG(z) > 0 ? -1.0 : 1.0);\n  return z;\n}\n\ngsl_complex\ngsl_complex_arccosh_real (double a)\n{                               /* z = arccosh(a) */\n  gsl_complex z;\n\n  if (a >= 1)\n    {\n      GSL_SET_COMPLEX (&z, acosh (a), 0);\n    }\n  else\n    {\n      if (a >= -1.0)\n        {\n          GSL_SET_COMPLEX (&z, 0, acos (a));\n        }\n      else\n        {\n          GSL_SET_COMPLEX (&z, acosh (-a), M_PI);\n        }\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arctanh (gsl_complex a)\n{                               /* z = arctanh(a) */\n  if (GSL_IMAG (a) == 0.0)\n    {\n      return gsl_complex_arctanh_real (GSL_REAL (a));\n    }\n  else\n    {\n      gsl_complex z = gsl_complex_mul_imag(a, 1.0);\n      z = gsl_complex_arctan (z);\n      z = gsl_complex_mul_imag (z, -1.0);\n      return z;\n    }\n}\n\ngsl_complex\ngsl_complex_arctanh_real (double a)\n{                               /* z = arctanh(a) */\n  gsl_complex z;\n\n  if (a > -1.0 && a < 1.0)\n    {\n      GSL_SET_COMPLEX (&z, atanh (a), 0);\n    }\n  else\n    {\n      GSL_SET_COMPLEX (&z, atanh (1 / a), (a < 0) ? M_PI_2 : -M_PI_2);\n    }\n\n  return z;\n}\n\ngsl_complex\ngsl_complex_arcsech (gsl_complex a)\n{                               /* z = arcsech(a); */\n  gsl_complex t = gsl_complex_inverse (a);\n  return gsl_complex_arccosh (t);\n}\n\ngsl_complex\ngsl_complex_arccsch (gsl_complex a)\n{                               /* z = arccsch(a) */\n  gsl_complex t = gsl_complex_inverse (a);\n  return gsl_complex_arcsinh (t);\n}\n\ngsl_complex\ngsl_complex_arccoth (gsl_complex a)\n{                               /* z = arccoth(a) */\n  gsl_complex t = gsl_complex_inverse (a);\n  return gsl_complex_arctanh (t);\n}\n"
  },
  {
    "path": "gsl/config.h",
    "content": "/* config.h.  Generated from config.h.in by configure.  */\n/* config.h.in.  Generated from configure.ac by autoheader.  */\n\n/* Disable deprecated functions and enums while building */\n#define GSL_DISABLE_DEPRECATED 1\n\n/* Define if you have inline with C99 behavior */\n#define HAVE_C99_INLINE 1\n\n/* Define to 1 if you have the declaration of `acosh', and to 0 if you don't.\n */\n#define HAVE_DECL_ACOSH 1\n\n/* Define to 1 if you have the declaration of `asinh', and to 0 if you don't.\n */\n#define HAVE_DECL_ASINH 1\n\n/* Define to 1 if you have the declaration of `atanh', and to 0 if you don't.\n */\n#define HAVE_DECL_ATANH 1\n\n/* Define to 1 if you have the declaration of `expm1', and to 0 if you don't.\n */\n#define HAVE_DECL_EXPM1 1\n\n/* Define to 1 if you have the declaration of `feenableexcept', and to 0 if\n you don't. */\n#define HAVE_DECL_FEENABLEEXCEPT 0\n\n/* Define to 1 if you have the declaration of `fesettrapenable', and to 0 if\n you don't. */\n#define HAVE_DECL_FESETTRAPENABLE 0\n\n/* Define to 1 if you have the declaration of `finite', and to 0 if you don't.\n */\n#define HAVE_DECL_FINITE 1\n\n/* Define to 1 if you have the declaration of `fprnd_t', and to 0 if you\n don't. */\n#define HAVE_DECL_FPRND_T 0\n\n/* Define to 1 if you have the declaration of `frexp', and to 0 if you don't.\n */\n#define HAVE_DECL_FREXP 1\n\n/* Define to 1 if you have the declaration of `hypot', and to 0 if you don't.\n */\n#define HAVE_DECL_HYPOT 1\n\n/* Define to 1 if you have the declaration of `isfinite', and to 0 if you\n don't. */\n#define HAVE_DECL_ISFINITE 1\n\n/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.\n */\n#define HAVE_DECL_ISINF 1\n\n/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.\n */\n#define HAVE_DECL_ISNAN 1\n\n/* Define to 1 if you have the declaration of `ldexp', and to 0 if you don't.\n */\n#define HAVE_DECL_LDEXP 1\n\n/* Define to 1 if you have the declaration of `log1p', and to 0 if you don't.\n */\n#define HAVE_DECL_LOG1P 1\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#define HAVE_DLFCN_H 1\n\n/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */\n/* #undef HAVE_DOPRNT */\n\n/* Defined if you have ansi EXIT_SUCCESS and EXIT_FAILURE in stdlib.h */\n#define HAVE_EXIT_SUCCESS_AND_FAILURE 1\n\n/* Defined on architectures with excess floating-point precision */\n#define HAVE_EXTENDED_PRECISION_REGISTERS 1\n\n/* Define if x86 processor has sse extensions. */\n/* #undef HAVE_FPU_X86_SSE */\n\n/* Define to 1 if you have the <ieeefp.h> header file. */\n/* #undef HAVE_IEEEFP_H */\n\n/* Define this if IEEE comparisons work correctly (e.g. NaN != NaN) */\n#define HAVE_IEEE_COMPARISONS 1\n\n/* Define this if IEEE denormalized numbers are available */\n#define HAVE_IEEE_DENORMALS 1\n\n/* Define if you have inline */\n#define HAVE_INLINE 1\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#define HAVE_INTTYPES_H 1\n\n/* Define to 1 if you have the `m' library (-lm). */\n#define HAVE_LIBM 1\n\n/* Define to 1 if you have the `memcpy' function. */\n#define HAVE_MEMCPY 1\n\n/* Define to 1 if you have the `memmove' function. */\n#define HAVE_MEMMOVE 1\n\n/* Define to 1 if you have the <memory.h> header file. */\n#define HAVE_MEMORY_H 1\n\n/* Define this if printf can handle %Lf for long double */\n#define HAVE_PRINTF_LONGDOUBLE 1\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#define HAVE_STDINT_H 1\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#define HAVE_STDLIB_H 1\n\n/* Define to 1 if you have the `strdup' function. */\n#define HAVE_STRDUP 1\n\n/* Define to 1 if you have the <strings.h> header file. */\n#define HAVE_STRINGS_H 1\n\n/* Define to 1 if you have the <string.h> header file. */\n#define HAVE_STRING_H 1\n\n/* Define to 1 if you have the `strtol' function. */\n#define HAVE_STRTOL 1\n\n/* Define to 1 if you have the `strtoul' function. */\n#define HAVE_STRTOUL 1\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#define HAVE_SYS_STAT_H 1\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#define HAVE_SYS_TYPES_H 1\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#define HAVE_UNISTD_H 1\n\n/* Define to 1 if you have the `vprintf' function. */\n#define HAVE_VPRINTF 1\n\n/* Define if you need to hide the static definitions of inline functions */\n/* #undef HIDE_INLINE_STATIC */\n\n/* Define to the sub-directory in which libtool stores uninstalled libraries.\n */\n#define LT_OBJDIR \".libs/\"\n\n/* Name of package */\n#define PACKAGE \"gsl\"\n\n/* Define to the address where bug reports for this package should be sent. */\n#define PACKAGE_BUGREPORT \"\"\n\n/* Define to the full name of this package. */\n#define PACKAGE_NAME \"gsl\"\n\n/* Define to the full name and version of this package. */\n#define PACKAGE_STRING \"gsl 2.1\"\n\n/* Define to the one symbol short name of this package. */\n#define PACKAGE_TARNAME \"gsl\"\n\n/* Define to the home page for this package. */\n#define PACKAGE_URL \"\"\n\n/* Define to the version of this package. */\n#define PACKAGE_VERSION \"2.1\"\n\n/* Defined if this is an official release */\n#define RELEASED /**/\n\n/* Define to 1 if you have the ANSI C header files. */\n#define STDC_HEADERS 1\n\n/* Version number of package */\n#define VERSION \"2.1\"\n\n/* Define to 1 if type `char' is unsigned and you are not using gcc.  */\n#ifndef __CHAR_UNSIGNED__\n/* # undef __CHAR_UNSIGNED__ */\n#endif\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n/* #undef inline */\n#endif\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n/* #undef size_t */\n\n/* Define to empty if the keyword `volatile' does not work. Warning: valid\n code using `volatile' can become incorrect without. Disable with care. */\n/* #undef volatile */\n\n/* Use 0 and 1 for EXIT_SUCCESS and EXIT_FAILURE if we don't have them */\n#if !HAVE_EXIT_SUCCESS_AND_FAILURE\n#define EXIT_SUCCESS 0\n#define EXIT_FAILURE 1\n#endif\n\n/* Define one of these if you have a known IEEE arithmetic interface */\n/* #undef HAVE_GNUSPARC_IEEE_INTERFACE */\n/* #undef HAVE_GNUM68K_IEEE_INTERFACE */\n/* #undef HAVE_GNUPPC_IEEE_INTERFACE */\n/* #undef HAVE_GNUX86_IEEE_INTERFACE */\n/* #undef HAVE_SUNOS4_IEEE_INTERFACE */\n/* #undef HAVE_SOLARIS_IEEE_INTERFACE */\n/* #undef HAVE_HPUX11_IEEE_INTERFACE */\n/* #undef HAVE_HPUX_IEEE_INTERFACE */\n/* #undef HAVE_TRU64_IEEE_INTERFACE */\n/* #undef HAVE_IRIX_IEEE_INTERFACE */\n/* #undef HAVE_AIX_IEEE_INTERFACE */\n/* #undef HAVE_FREEBSD_IEEE_INTERFACE */\n/* #undef HAVE_OS2EMX_IEEE_INTERFACE */\n/* #undef HAVE_NETBSD_IEEE_INTERFACE */\n/* #undef HAVE_OPENBSD_IEEE_INTERFACE */\n/* #undef HAVE_DARWIN_IEEE_INTERFACE */\n/* #undef HAVE_DARWIN86_IEEE_INTERFACE */\n\n/* Define a rounding function which moves extended precision values\n out of registers and rounds them to double-precision. This should\n be used *sparingly*, in places where it is necessary to keep\n double-precision rounding for critical expressions while running in\n extended precision. For example, the following code should ensure\n exact equality, even when extended precision registers are in use,\n \n double q = GSL_COERCE_DBL(3.0/7.0) ;\n if (q == GSL_COERCE_DBL(3.0/7.0)) { ... } ;\n \n It carries a penalty even when the program is running in double\n precision mode unless you compile a separate version of the\n library with HAVE_EXTENDED_PRECISION_REGISTERS turned off. */\n\n#if HAVE_EXTENDED_PRECISION_REGISTERS\n#define GSL_COERCE_DBL(x) (gsl_coerce_double(x))\n#else\n#define GSL_COERCE_DBL(x) (x)\n#endif\n\n/* Substitute gsl functions for missing system functions */\n\n#if !HAVE_DECL_HYPOT\n#define hypot gsl_hypot\n#endif\n\n#if !HAVE_DECL_LOG1P\n#define log1p gsl_log1p\n#endif\n\n#if !HAVE_DECL_EXPM1\n#define expm1 gsl_expm1\n#endif\n\n#if !HAVE_DECL_ACOSH\n#define acosh gsl_acosh\n#endif\n\n#if !HAVE_DECL_ASINH\n#define asinh gsl_asinh\n#endif\n\n#if !HAVE_DECL_ATANH\n#define atanh gsl_atanh\n#endif\n\n#if !HAVE_DECL_LDEXP\n#define ldexp gsl_ldexp\n#endif\n\n#if !HAVE_DECL_FREXP\n#define frexp gsl_frexp\n#endif\n\n#if !HAVE_DECL_ISINF\n#define isinf gsl_isinf\n#endif\n\n#if !HAVE_DECL_ISFINITE\n#define isfinite gsl_finite\n#endif\n\n#if !HAVE_DECL_FINITE\n#define finite gsl_finite\n#endif\n\n#if !HAVE_DECL_ISNAN\n#define isnan gsl_isnan\n#endif\n\n#ifdef __GNUC__\n#define DISCARD_POINTER(p) do { ; } while(p ? 0 : 0);\n#else\n#define DISCARD_POINTER(p) /* ignoring discarded pointer */\n#endif\n\n#if defined(GSL_RANGE_CHECK_OFF) || !defined(GSL_RANGE_CHECK)\n#define GSL_RANGE_CHECK 0  /* turn off range checking by default internally */\n#endif\n\n#define RETURN_IF_NULL(x) if (!x) { return ; }\n\n"
  },
  {
    "path": "gsl/err/error.c",
    "content": "/* err/error.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stddef.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"gsl_errno.h\"\n//#include \"gsl_message.h\"\n\ngsl_error_handler_t * gsl_error_handler = NULL;\n\nstatic void no_error_handler (const char *reason, const char *file, int line, int gsl_errno);\n\nvoid\ngsl_error (const char * reason, const char * file, int line, int gsl_errno)\n{\n  if (gsl_error_handler) \n    {\n      (*gsl_error_handler) (reason, file, line, gsl_errno);\n      return ;\n    }\n\n  gsl_stream_printf (\"ERROR\", file, line, reason);\n\n  fflush (stdout);\n  fprintf (stderr, \"Default GSL error handler invoked.\\n\");\n  fflush (stderr);\n\n  abort ();\n}\n\ngsl_error_handler_t *\ngsl_set_error_handler (gsl_error_handler_t * new_handler)\n{\n  gsl_error_handler_t * previous_handler = gsl_error_handler;\n  gsl_error_handler = new_handler;\n  return previous_handler;\n}\n\n\ngsl_error_handler_t *\ngsl_set_error_handler_off (void)\n{\n  gsl_error_handler_t * previous_handler = gsl_error_handler;\n  gsl_error_handler = no_error_handler;\n  return previous_handler;\n}\n\nstatic void\nno_error_handler (const char *reason, const char *file, int line, int gsl_errno)\n{\n  /* do nothing */\n  reason = 0;\n  file = 0;\n  line = 0;\n  gsl_errno = 0;\n  \n  // suppress \"variable set but not used\" warnings; I have no idea why the GSL does this...\n  (void)line;\n  (void)gsl_errno;\n  (void)file;\n  (void)reason;\n  \n  return;\n}\n\n\n"
  },
  {
    "path": "gsl/err/gsl_message.h",
    "content": "/* err/gsl_message.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_MESSAGE_H__\n#define __GSL_MESSAGE_H__\n#include \"gsl_types.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* Provide a general messaging service for client use.  Messages can\n * be selectively turned off at compile time by defining an\n * appropriate message mask. Client code which uses the GSL_MESSAGE()\n * macro must provide a mask which is or'ed with the GSL_MESSAGE_MASK.\n *\n * The messaging service can be completely turned off\n * by defining GSL_MESSAGING_OFF.  */\n\nvoid gsl_message(const char * message, const char * file, int line,\n                 unsigned int mask);\n\n#ifndef GSL_MESSAGE_MASK\n#define GSL_MESSAGE_MASK 0xffffffffu /* default all messages allowed */\n#endif\n\nGSL_VAR unsigned int gsl_message_mask ;\n\n/* Provide some symolic masks for client ease of use. */\n\nenum {\n  GSL_MESSAGE_MASK_A = 1,\n  GSL_MESSAGE_MASK_B = 2,\n  GSL_MESSAGE_MASK_C = 4,\n  GSL_MESSAGE_MASK_D = 8,\n  GSL_MESSAGE_MASK_E = 16,\n  GSL_MESSAGE_MASK_F = 32,\n  GSL_MESSAGE_MASK_G = 64,\n  GSL_MESSAGE_MASK_H = 128\n} ;\n\n#ifdef GSL_MESSAGING_OFF        /* throw away messages */ \n#define GSL_MESSAGE(message, mask) do { } while(0)\n#else                           /* output all messages */\n#define GSL_MESSAGE(message, mask) \\\n       do { \\\n       if (mask & GSL_MESSAGE_MASK) \\\n         gsl_message (message, __FILE__, __LINE__, mask) ; \\\n       } while (0)\n#endif\n\n__END_DECLS\n\n#endif /* __GSL_MESSAGE_H__ */\n\n\n"
  },
  {
    "path": "gsl/err/message.c",
    "content": "/* err/message.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stddef.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"gsl_errno.h\"\n#include \"gsl_message.h\"\n\nunsigned int gsl_message_mask = GSL_MESSAGE_MASK;\n\nvoid\ngsl_message (const char * reason, const char * file, int line, \n             unsigned int mask)\n{\n  if (mask & gsl_message_mask)\n    {\n      gsl_stream_printf (\"MESSAGE\", file, line, reason);\n    }\n}\n"
  },
  {
    "path": "gsl/err/stream.c",
    "content": "/* err/stream.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stddef.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include \"gsl_errno.h\"\n#include \"gsl_message.h\"\n\nFILE * gsl_stream = NULL ;\ngsl_stream_handler_t * gsl_stream_handler = NULL;\n\nvoid\ngsl_stream_printf (const char *label, const char *file, int line, \n                   const char *reason)\n{\n  if (gsl_stream == NULL)\n    {\n      gsl_stream = stderr;\n    }\n  if (gsl_stream_handler)\n    {\n      (*gsl_stream_handler) (label, file, line, reason);\n      return;\n    }\n  fprintf (gsl_stream, \"gsl: %s:%d: %s: %s\\n\", file, line, label, reason);\n\n}\n\ngsl_stream_handler_t *\ngsl_set_stream_handler (gsl_stream_handler_t * new_handler)\n{\n  gsl_stream_handler_t * previous_handler = gsl_stream_handler;\n  gsl_stream_handler = new_handler;\n  return previous_handler;\n}\n\nFILE *\ngsl_set_stream (FILE * new_stream)\n{\n  FILE * previous_stream;\n  if (gsl_stream == NULL) {\n    gsl_stream = stderr;\n  }\n  previous_stream = gsl_stream;\n  gsl_stream = new_stream;\n  return previous_stream;\n}\n"
  },
  {
    "path": "gsl/gsl.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2019-07-10T22:38:01\n#\n#-------------------------------------------------\n\nQT       -= core gui\n\nTEMPLATE = lib\nCONFIG += staticlib\n\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\nCONFIG -= qt\nCONFIG += object_parallel_to_source\nCONFIG += c11\nQMAKE_CFLAGS += -std=c11\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1\nQMAKE_CFLAGS_RELEASE += -O3\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CFLAGS += -Wno-unknown-pragmas -Wno-attributes -Wno-unused-parameter -Wno-unused-but-set-parameter\n}\n\nINCLUDEPATH = . ./blas ./block ./cblas ./cdf ./complex ./err ./interpolation ./linalg ./matrix ./permutation ./randist ./rng ./specfunc ./sys ./vector\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n\nSOURCES += \\\n    blas/blas.c \\\n    block/init.c \\\n    cblas/daxpy.c \\\n    cblas/ddot.c \\\n    cblas/dgemv.c \\\n    cblas/dtrmv.c \\\n    cblas/dtrsv.c \\\n    cblas/xerbla.c \\\n    cdf/gauss.c \\\n    cdf/gaussinv.c \\\n    cdf/tdist.c \\\n    complex/inline.c \\\n    complex/math.c \\\n    err/error.c \\\n    err/message.c \\\n    err/stream.c \\\n    interpolation/accel.c \\\n    interpolation/akima.c \\\n    interpolation/bicubic.c \\\n    interpolation/bilinear.c \\\n    interpolation/cspline.c \\\n    interpolation/inline.c \\\n    interpolation/interp.c \\\n    interpolation/interp2d.c \\\n    interpolation/linear.c \\\n    interpolation/spline.c \\\n    interpolation/spline2d.c \\\n    linalg/cholesky.c \\\n    linalg/lu.c \\\n    linalg/tridiag.c \\\n    matrix/copy.c \\\n    matrix/init.c \\\n    matrix/matrix.c \\\n    matrix/rowcol.c \\\n    matrix/submatrix.c \\\n    matrix/swap.c \\\n    permutation/init.c \\\n    permutation/permutation.c \\\n    permutation/permute.c \\\n    randist/beta.c \\\n    randist/binomial_tpe.c \\\n    randist/cauchy.c \\\n    randist/chisq.c \\\n    randist/dirichlet.c \\\n    randist/discrete.c \\\n    randist/exponential.c \\\n    randist/fdist.c \\\n    randist/gamma.c \\\n    randist/gauss.c \\\n    randist/gausszig.c \\\n    randist/geometric.c \\\n    randist/laplace.c \\\n    randist/lognormal.c \\\n    randist/multinomial.c \\\n    randist/mvgauss.c \\\n    randist/nbinomial.c \\\n    randist/poisson.c \\\n    randist/shuffle.c \\\n    randist/tdist.c \\\n    randist/weibull.c \\\n    rng/inline.c \\\n    rng/mt.c \\\n    rng/rng.c \\\n    rng/taus.c \\\n    specfunc/beta.c \\\n    specfunc/elementary.c \\\n    specfunc/erfc.c \\\n    specfunc/exp.c \\\n    specfunc/expint.c \\\n    specfunc/gamma_inc.c \\\n    specfunc/gamma.c \\\n    specfunc/log.c \\\n    specfunc/pow_int.c \\\n    specfunc/psi.c \\\n    specfunc/trig.c \\\n    specfunc/zeta.c \\\n    sys/coerce.c \\\n    sys/fdiv.c \\\n    sys/infnan.c \\\n    sys/minmax.c \\\n    sys/pow_int.c \\\n    vector/copy.c \\\n    vector/init.c \\\n    vector/oper.c \\\n    vector/vector.c \\\n    vector/view.c\n\nHEADERS += \\\n    build.h \\\n    config.h \\\n    gsl_errno.h \\\n    gsl_inline.h \\\n    gsl_machine.h \\\n    gsl_math.h \\\n    gsl_minmax.h \\\n    gsl_nan.h \\\n    gsl_pow_int.h \\\n    gsl_precision.h \\\n    gsl_types.h \\\n    gsl_version.h \\\n    blas/gsl_blas_types.h \\\n    blas/gsl_blas.h \\\n    block/gsl_block_double.h \\\n    block/gsl_block.h \\\n    block/gsl_check_range.h \\\n    cblas/cblas.h \\\n    cblas/error_cblas_l2.h \\\n    cblas/error_cblas.h \\\n    cblas/gsl_cblas.h \\\n    cblas/source_axpy_r.h \\\n    cblas/source_dot_r.h \\\n    cblas/source_gemv_r.h \\\n    cblas/source_trmv_r.h \\\n    cblas/source_trsv_r.h \\\n    cdf/gsl_cdf.h \\\n    cdf/rat_eval.h \\\n    complex/gsl_complex_math.h \\\n    complex/gsl_complex.h \\\n    err/gsl_message.h \\\n    interpolation/gsl_interp.h \\\n    interpolation/gsl_interp2d.h \\\n    interpolation/gsl_spline.h \\\n    interpolation/gsl_spline2d.h \\\n    interpolation/integ_eval.h \\\n    linalg/gsl_linalg.h \\\n    linalg/tridiag.h \\\n    matrix/gsl_matrix_double.h \\\n    matrix/gsl_matrix.h \\\n    matrix/view.h \\\n    permutation/gsl_permutation.h \\\n    permutation/gsl_permute.h \\\n    permutation/gsl_permute_double.h \\\n    permutation/gsl_permute_matrix.h \\\n    permutation/gsl_permute_matrix_double.h \\\n    permutation/gsl_permute_vector.h \\\n    permutation/gsl_permute_source.h \\\n    randist/gsl_randist.h \\\n    rng/gsl_rng.h \\\n    specfunc/chebyshev.h \\\n    specfunc/check.h \\\n    specfunc/error.h \\\n    specfunc/eval.h \\\n    specfunc/gsl_sf_elementary.h \\\n    specfunc/gsl_sf_erf.h \\\n    specfunc/gsl_sf_exp.h \\\n    specfunc/gsl_sf_expint.h \\\n    specfunc/gsl_sf_gamma.h \\\n    specfunc/gsl_sf_log.h \\\n    specfunc/gsl_sf_pow_int.h \\\n    specfunc/gsl_sf_psi.h \\\n    specfunc/gsl_sf_result.h \\\n    specfunc/gsl_sf_trig.h \\\n    specfunc/gsl_sf_zeta.h \\\n    sys/gsl_sys.h \\\n    vector/gsl_vector_double.h \\\n    vector/gsl_vector.h \\\n    vector/view.h\n\n\n"
  },
  {
    "path": "gsl/gsl_errno.h",
    "content": "/* err/gsl_errno.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_ERRNO_H__\n#define __GSL_ERRNO_H__\n\n#include <stdio.h>\n#include <errno.h>\n#include \"gsl_types.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nenum { \n  GSL_SUCCESS  = 0, \n  GSL_FAILURE  = -1,\n  GSL_CONTINUE = -2,  /* iteration has not converged */\n  GSL_EDOM     = 1,   /* input domain error, e.g sqrt(-1) */\n  GSL_ERANGE   = 2,   /* output range error, e.g. exp(1e100) */\n  GSL_EFAULT   = 3,   /* invalid pointer */\n  GSL_EINVAL   = 4,   /* invalid argument supplied by user */\n  GSL_EFAILED  = 5,   /* generic failure */\n  GSL_EFACTOR  = 6,   /* factorization failed */\n  GSL_ESANITY  = 7,   /* sanity check failed - shouldn't happen */\n  GSL_ENOMEM   = 8,   /* malloc failed */\n  GSL_EBADFUNC = 9,   /* problem with user-supplied function */\n  GSL_ERUNAWAY = 10,  /* iterative process is out of control */\n  GSL_EMAXITER = 11,  /* exceeded max number of iterations */\n  GSL_EZERODIV = 12,  /* tried to divide by zero */\n  GSL_EBADTOL  = 13,  /* user specified an invalid tolerance */\n  GSL_ETOL     = 14,  /* failed to reach the specified tolerance */\n  GSL_EUNDRFLW = 15,  /* underflow */\n  GSL_EOVRFLW  = 16,  /* overflow  */\n  GSL_ELOSS    = 17,  /* loss of accuracy */\n  GSL_EROUND   = 18,  /* failed because of roundoff error */\n  GSL_EBADLEN  = 19,  /* matrix, vector lengths are not conformant */\n  GSL_ENOTSQR  = 20,  /* matrix not square */\n  GSL_ESING    = 21,  /* apparent singularity detected */\n  GSL_EDIVERGE = 22,  /* integral or series is divergent */\n  GSL_EUNSUP   = 23,  /* requested feature is not supported by the hardware */\n  GSL_EUNIMPL  = 24,  /* requested feature not (yet) implemented */\n  GSL_ECACHE   = 25,  /* cache limit exceeded */\n  GSL_ETABLE   = 26,  /* table limit exceeded */\n  GSL_ENOPROG  = 27,  /* iteration is not making progress towards solution */\n  GSL_ENOPROGJ = 28,  /* jacobian evaluations are not improving the solution */\n  GSL_ETOLF    = 29,  /* cannot reach the specified tolerance in F */\n  GSL_ETOLX    = 30,  /* cannot reach the specified tolerance in X */\n  GSL_ETOLG    = 31,  /* cannot reach the specified tolerance in gradient */\n  GSL_EOF      = 32   /* end of file */\n} ;\n\n#ifdef __clang_analyzer__\nvoid gsl_error (const char * reason, const char * file, int line,\n                int gsl_errno) __attribute__((analyzer_noreturn));\n#else\nvoid gsl_error (const char * reason, const char * file, int line,\n\t\t\t\tint gsl_errno);\n#endif\n\nvoid gsl_stream_printf (const char *label, const char *file,\n                        int line, const char *reason);\n\nconst char * gsl_strerror (const int gsl_errno);\n\ntypedef void gsl_error_handler_t (const char * reason, const char * file,\n                                  int line, int gsl_errno);\n\ntypedef void gsl_stream_handler_t (const char * label, const char * file,\n                                   int line, const char * reason);\n\ngsl_error_handler_t * \ngsl_set_error_handler (gsl_error_handler_t * new_handler);\n\ngsl_error_handler_t *\ngsl_set_error_handler_off (void);\n\ngsl_stream_handler_t * \ngsl_set_stream_handler (gsl_stream_handler_t * new_handler);\n\nFILE * gsl_set_stream (FILE * new_stream);\n\n/* GSL_ERROR: call the error handler, and return the error code */\n\n#define GSL_ERROR(reason, gsl_errno) \\\n       do { \\\n       gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \\\n       return gsl_errno ; \\\n       } while (0)\n\n/* GSL_ERROR_VAL: call the error handler, and return the given value */\n\n#define GSL_ERROR_VAL(reason, gsl_errno, value) \\\n       do { \\\n       gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \\\n       return value ; \\\n       } while (0)\n\n/* GSL_ERROR_VOID: call the error handler, and then return\n   (for void functions which still need to generate an error) */\n\n#define GSL_ERROR_VOID(reason, gsl_errno) \\\n       do { \\\n       gsl_error (reason, __FILE__, __LINE__, gsl_errno) ; \\\n       return ; \\\n       } while (0)\n\n/* GSL_ERROR_NULL suitable for out-of-memory conditions */\n\n#define GSL_ERROR_NULL(reason, gsl_errno) GSL_ERROR_VAL(reason, gsl_errno, 0)\n\n/* Sometimes you have several status results returned from\n * function calls and you want to combine them in some sensible\n * way. You cannot produce a \"total\" status condition, but you can\n * pick one from a set of conditions based on an implied hierarchy.\n *\n * In other words:\n *    you have: status_a, status_b, ...\n *    you want: status = (status_a if it is bad, or status_b if it is bad,...)\n *\n * In this example you consider status_a to be more important and\n * it is checked first, followed by the others in the order specified.\n *\n * Here are some dumb macros to do this.\n */\n#define GSL_ERROR_SELECT_2(a,b)       ((a) != GSL_SUCCESS ? (a) : ((b) != GSL_SUCCESS ? (b) : GSL_SUCCESS))\n#define GSL_ERROR_SELECT_3(a,b,c)     ((a) != GSL_SUCCESS ? (a) : GSL_ERROR_SELECT_2(b,c))\n#define GSL_ERROR_SELECT_4(a,b,c,d)   ((a) != GSL_SUCCESS ? (a) : GSL_ERROR_SELECT_3(b,c,d))\n#define GSL_ERROR_SELECT_5(a,b,c,d,e) ((a) != GSL_SUCCESS ? (a) : GSL_ERROR_SELECT_4(b,c,d,e))\n\n#define GSL_STATUS_UPDATE(sp, s) do { if ((s) != GSL_SUCCESS) *(sp) = (s);} while(0)\n\n__END_DECLS\n\n#endif /* __GSL_ERRNO_H__ */\n"
  },
  {
    "path": "gsl/gsl_inline.h",
    "content": "/* gsl_inline.h\n * \n * Copyright (C) 2008, 2009 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_INLINE_H__\n#define __GSL_INLINE_H__\n\n/* In recent versiions of GCC, the inline keyword has two different\n   forms: GNU and C99.\n\n   In GNU mode we can use 'extern inline' to make inline functions\n   work like macros.  The function is only inlined--it is never output\n   as a definition in an object file.\n\n   In the new C99 mode 'extern inline' has a different meaning--it\n   causes the definition of the function to be output in each object\n   file where it is used.  This will result in multiple-definition\n   errors on linking.  The 'inline' keyword on its own (without\n   extern) has the same behavior as the original GNU 'extern inline'.\n\n   The C99 style is the default with -std=c99 in GCC 4.3.  \n\n   This header file allows either form of inline to be used by\n   redefining the macros INLINE_DECL and INLINE_FUN.  These are used\n   in the public header files as\n\n        INLINE_DECL double gsl_foo (double x);\n\t#ifdef HAVE_INLINE\n\tINLINE_FUN double gsl_foo (double x) { return x+1.0; } ;\n        #endif\n   \n*/\n\n#ifdef HAVE_INLINE\n#  if defined(__GNUC_STDC_INLINE__) || defined(GSL_C99_INLINE) || defined(HAVE_C99_INLINE)\n#    define INLINE_DECL inline  /* use C99 inline */\n#    define INLINE_FUN inline\n#  else\n#    define INLINE_DECL         /* use GNU extern inline */\n#    define INLINE_FUN extern inline\n#  endif\n#else\n#  define INLINE_DECL /* */\n#endif\n\n/* Range checking conditions in headers do not require any run-time\n   tests of the global variable gsl_check_range.  They are enabled or\n   disabled in user code at compile time with GSL_RANGE_CHECK macro.\n   See also build.h. */\n#define GSL_RANGE_COND(x) (x)\n\n#endif /* __GSL_INLINE_H__ */\n"
  },
  {
    "path": "gsl/gsl_machine.h",
    "content": "/* Author:  B. Gough and G. Jungman */\n#ifndef __GSL_MACHINE_H__\n#define __GSL_MACHINE_H__\n\n#include <limits.h>\n#include <float.h>\n\n/* magic constants; mostly for the benefit of the implementation */\n\n/* -*-MACHINE CONSTANTS-*-\n *\n * PLATFORM: Whiz-O-Matic 9000\n * FP_PLATFORM: IEEE-Virtual\n * HOSTNAME: nnn.lanl.gov\n * DATE: Fri Nov 20 17:53:26 MST 1998\n */\n#define GSL_DBL_EPSILON        2.2204460492503131e-16\n#define GSL_SQRT_DBL_EPSILON   1.4901161193847656e-08\n#define GSL_ROOT3_DBL_EPSILON  6.0554544523933429e-06\n#define GSL_ROOT4_DBL_EPSILON  1.2207031250000000e-04\n#define GSL_ROOT5_DBL_EPSILON  7.4009597974140505e-04\n#define GSL_ROOT6_DBL_EPSILON  2.4607833005759251e-03\n#define GSL_LOG_DBL_EPSILON   (-3.6043653389117154e+01)\n\n#define GSL_DBL_MIN        2.2250738585072014e-308\n#define GSL_SQRT_DBL_MIN   1.4916681462400413e-154\n#define GSL_ROOT3_DBL_MIN  2.8126442852362996e-103\n#define GSL_ROOT4_DBL_MIN  1.2213386697554620e-77\n#define GSL_ROOT5_DBL_MIN  2.9476022969691763e-62\n#define GSL_ROOT6_DBL_MIN  5.3034368905798218e-52\n#define GSL_LOG_DBL_MIN   (-7.0839641853226408e+02)\n\n#define GSL_DBL_MAX        1.7976931348623157e+308\n#define GSL_SQRT_DBL_MAX   1.3407807929942596e+154\n#define GSL_ROOT3_DBL_MAX  5.6438030941222897e+102\n#define GSL_ROOT4_DBL_MAX  1.1579208923731620e+77\n#define GSL_ROOT5_DBL_MAX  4.4765466227572707e+61\n#define GSL_ROOT6_DBL_MAX  2.3756689782295612e+51\n#define GSL_LOG_DBL_MAX    7.0978271289338397e+02\n\n#define GSL_FLT_EPSILON        1.1920928955078125e-07\n#define GSL_SQRT_FLT_EPSILON   3.4526698300124393e-04\n#define GSL_ROOT3_FLT_EPSILON  4.9215666011518501e-03\n#define GSL_ROOT4_FLT_EPSILON  1.8581361171917516e-02\n#define GSL_ROOT5_FLT_EPSILON  4.1234622211652937e-02\n#define GSL_ROOT6_FLT_EPSILON  7.0153878019335827e-02\n#define GSL_LOG_FLT_EPSILON   (-1.5942385152878742e+01)\n\n#define GSL_FLT_MIN        1.1754943508222875e-38\n#define GSL_SQRT_FLT_MIN   1.0842021724855044e-19\n#define GSL_ROOT3_FLT_MIN  2.2737367544323241e-13\n#define GSL_ROOT4_FLT_MIN  3.2927225399135965e-10\n#define GSL_ROOT5_FLT_MIN  2.5944428542140822e-08\n#define GSL_ROOT6_FLT_MIN  4.7683715820312542e-07\n#define GSL_LOG_FLT_MIN   (-8.7336544750553102e+01)\n\n#define GSL_FLT_MAX        3.4028234663852886e+38\n#define GSL_SQRT_FLT_MAX   1.8446743523953730e+19\n#define GSL_ROOT3_FLT_MAX  6.9814635196223242e+12\n#define GSL_ROOT4_FLT_MAX  4.2949672319999986e+09\n#define GSL_ROOT5_FLT_MAX  5.0859007855960041e+07\n#define GSL_ROOT6_FLT_MAX  2.6422459233807749e+06\n#define GSL_LOG_FLT_MAX    8.8722839052068352e+01\n\n#define GSL_SFLT_EPSILON        4.8828125000000000e-04\n#define GSL_SQRT_SFLT_EPSILON   2.2097086912079612e-02\n#define GSL_ROOT3_SFLT_EPSILON  7.8745065618429588e-02\n#define GSL_ROOT4_SFLT_EPSILON  1.4865088937534013e-01\n#define GSL_ROOT5_SFLT_EPSILON  2.1763764082403100e-01\n#define GSL_ROOT6_SFLT_EPSILON  2.8061551207734325e-01\n#define GSL_LOG_SFLT_EPSILON   (-7.6246189861593985e+00)\n\n/* !MACHINE CONSTANTS! */\n\n\n/* a little internal backwards compatibility */\n#define GSL_MACH_EPS  GSL_DBL_EPSILON\n\n\n\n/* Here are the constants related to or derived from\n * machine constants. These are not to be confused with\n * the constants that define various precision levels\n * for the precision/error system.\n *\n * This information is determined at configure time\n * and is platform dependent. Edit at your own risk.\n *\n * PLATFORM: WHIZ-O-MATIC\n * CONFIG-DATE: Thu Nov 19 19:27:18 MST 1998\n * CONFIG-HOST: nnn.lanl.gov\n */\n\n/* machine precision constants */\n/* #define GSL_MACH_EPS         1.0e-15 */\n#define GSL_SQRT_MACH_EPS       3.2e-08\n#define GSL_ROOT3_MACH_EPS      1.0e-05\n#define GSL_ROOT4_MACH_EPS      0.000178\n#define GSL_ROOT5_MACH_EPS      0.00100\n#define GSL_ROOT6_MACH_EPS      0.00316\n#define GSL_LOG_MACH_EPS       (-34.54)\n\n\n#endif /* __GSL_MACHINE_H__ */\n"
  },
  {
    "path": "gsl/gsl_math.h",
    "content": "/* gsl_math.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_MATH_H__\n#define __GSL_MATH_H__\n#include <math.h>\n#include \"gsl_sys.h\"\n#include \"gsl_inline.h\"\n#include \"gsl_machine.h\"\n#include \"gsl_precision.h\"\n#include \"gsl_nan.h\"\n#include \"gsl_pow_int.h\"\n#include \"gsl_minmax.h\"\n\n#ifndef M_E\n#define M_E        2.71828182845904523536028747135      /* e */\n#endif\n\n#ifndef M_LOG2E\n#define M_LOG2E    1.44269504088896340735992468100      /* log_2 (e) */\n#endif\n\n#ifndef M_LOG10E\n#define M_LOG10E   0.43429448190325182765112891892      /* log_10 (e) */\n#endif\n\n#ifndef M_SQRT2\n#define M_SQRT2    1.41421356237309504880168872421      /* sqrt(2) */\n#endif\n\n#ifndef M_SQRT1_2\n#define M_SQRT1_2  0.70710678118654752440084436210      /* sqrt(1/2) */\n#endif\n\n\n#ifndef M_SQRT3\n#define M_SQRT3    1.73205080756887729352744634151      /* sqrt(3) */\n#endif\n\n#ifndef M_PI\n#define M_PI       3.14159265358979323846264338328      /* pi */\n#endif\n\n#ifndef M_PI_2\n#define M_PI_2     1.57079632679489661923132169164      /* pi/2 */\n#endif\n\n#ifndef M_PI_4\n#define M_PI_4     0.78539816339744830961566084582     /* pi/4 */\n#endif\n\n#ifndef M_SQRTPI\n#define M_SQRTPI   1.77245385090551602729816748334      /* sqrt(pi) */\n#endif\n\n#ifndef M_2_SQRTPI\n#define M_2_SQRTPI 1.12837916709551257389615890312      /* 2/sqrt(pi) */\n#endif\n\n#ifndef M_1_PI\n#define M_1_PI     0.31830988618379067153776752675      /* 1/pi */\n#endif\n\n#ifndef M_2_PI\n#define M_2_PI     0.63661977236758134307553505349      /* 2/pi */\n#endif\n\n#ifndef M_LN10\n#define M_LN10     2.30258509299404568401799145468      /* ln(10) */\n#endif\n\n#ifndef M_LN2\n#define M_LN2      0.69314718055994530941723212146      /* ln(2) */\n#endif\n\n#ifndef M_LNPI\n#define M_LNPI     1.14472988584940017414342735135      /* ln(pi) */\n#endif\n\n#ifndef M_EULER\n#define M_EULER    0.57721566490153286060651209008      /* Euler constant */\n#endif\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* other needlessly compulsive abstractions */\n\n#define GSL_IS_ODD(n)  ((n) & 1)\n#define GSL_IS_EVEN(n) (!(GSL_IS_ODD(n)))\n#define GSL_SIGN(x)    ((x) >= 0.0 ? 1 : -1)\n\n/* Return nonzero if x is a real number, i.e. non NaN or infinite. */\n#define GSL_IS_REAL(x) (gsl_finite(x))\n\n/* Definition of an arbitrary function with parameters */\n\nstruct gsl_function_struct \n{\n  double (* function) (double x, void * params);\n  void * params;\n};\n\ntypedef struct gsl_function_struct gsl_function ;\n\n#define GSL_FN_EVAL(F,x) (*((F)->function))(x,(F)->params)\n\n/* Definition of an arbitrary function returning two values, r1, r2 */\n\nstruct gsl_function_fdf_struct \n{\n  double (* f) (double x, void * params);\n  double (* df) (double x, void * params);\n  void (* fdf) (double x, void * params, double * f, double * df);\n  void * params;\n};\n\ntypedef struct gsl_function_fdf_struct gsl_function_fdf ;\n\n#define GSL_FN_FDF_EVAL_F(FDF,x) (*((FDF)->f))(x,(FDF)->params)\n#define GSL_FN_FDF_EVAL_DF(FDF,x) (*((FDF)->df))(x,(FDF)->params)\n#define GSL_FN_FDF_EVAL_F_DF(FDF,x,y,dy) (*((FDF)->fdf))(x,(FDF)->params,(y),(dy))\n\n\n/* Definition of an arbitrary vector-valued function with parameters */\n\nstruct gsl_function_vec_struct \n{\n  int (* function) (double x, double y[], void * params);\n  void * params;\n};\n\ntypedef struct gsl_function_vec_struct gsl_function_vec ;\n\n#define GSL_FN_VEC_EVAL(F,x,y) (*((F)->function))(x,y,(F)->params)\n\n__END_DECLS\n\n#endif /* __GSL_MATH_H__ */\n"
  },
  {
    "path": "gsl/gsl_minmax.h",
    "content": "/* gsl_minmax.h\n * \n * Copyright (C) 2008 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_MINMAX_H__\n#define __GSL_MINMAX_H__\n#include \"gsl_inline.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* Define MAX and MIN macros/functions if they don't exist. */\n\n/* plain old macros for general use */\n#define GSL_MAX(a,b) ((a) > (b) ? (a) : (b))\n#define GSL_MIN(a,b) ((a) < (b) ? (a) : (b))\n\n/* function versions of the above, in case they are needed */\ndouble gsl_max (double a, double b);\ndouble gsl_min (double a, double b);\n\n/* inline-friendly strongly typed versions */\n#ifdef HAVE_INLINE\n\nINLINE_FUN int GSL_MAX_INT (int a, int b);\nINLINE_FUN int GSL_MIN_INT (int a, int b);\nINLINE_FUN double GSL_MAX_DBL (double a, double b);\nINLINE_FUN double GSL_MIN_DBL (double a, double b);\nINLINE_FUN long double GSL_MAX_LDBL (long double a, long double b);\nINLINE_FUN long double GSL_MIN_LDBL (long double a, long double b);\n\nINLINE_FUN int\nGSL_MAX_INT (int a, int b)\n{\n  return GSL_MAX (a, b);\n}\n\nINLINE_FUN int\nGSL_MIN_INT (int a, int b)\n{\n  return GSL_MIN (a, b);\n}\n\nINLINE_FUN double\nGSL_MAX_DBL (double a, double b)\n{\n  return GSL_MAX (a, b);\n}\n\nINLINE_FUN double\nGSL_MIN_DBL (double a, double b)\n{\n  return GSL_MIN (a, b);\n}\n\nINLINE_FUN long double\nGSL_MAX_LDBL (long double a, long double b)\n{\n  return GSL_MAX (a, b);\n}\n\nINLINE_FUN long double\nGSL_MIN_LDBL (long double a, long double b)\n{\n  return GSL_MIN (a, b);\n}\n#else\n#define GSL_MAX_INT(a,b)   GSL_MAX(a,b)\n#define GSL_MIN_INT(a,b)   GSL_MIN(a,b)\n#define GSL_MAX_DBL(a,b)   GSL_MAX(a,b)\n#define GSL_MIN_DBL(a,b)   GSL_MIN(a,b)\n#define GSL_MAX_LDBL(a,b)  GSL_MAX(a,b)\n#define GSL_MIN_LDBL(a,b)  GSL_MIN(a,b)\n#endif /* HAVE_INLINE */\n\n__END_DECLS\n\n#endif /* __GSL_POW_INT_H__ */\n"
  },
  {
    "path": "gsl/gsl_nan.h",
    "content": "/* gsl_nan.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_NAN_H__\n#define __GSL_NAN_H__\n\n#ifdef INFINITY\n# define GSL_POSINF INFINITY\n# define GSL_NEGINF (-INFINITY)\n#elif defined(HUGE_VAL)\n# define GSL_POSINF HUGE_VAL\n# define GSL_NEGINF (-HUGE_VAL)\n#else\n# define GSL_POSINF (gsl_posinf())\n# define GSL_NEGINF (gsl_neginf())\n#endif\n\n#ifdef NAN\n# define GSL_NAN NAN\n#elif defined(INFINITY)\n# define GSL_NAN (INFINITY/INFINITY)\n#else\n# define GSL_NAN (gsl_nan())\n#endif\n\n#define GSL_POSZERO (+0.0)\n#define GSL_NEGZERO (-0.0)\n\n#endif /* __GSL_NAN_H__ */\n"
  },
  {
    "path": "gsl/gsl_pow_int.h",
    "content": "/* gsl_pow_int.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_POW_INT_H__\n#define __GSL_POW_INT_H__\n#include \"gsl_inline.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nINLINE_DECL double gsl_pow_2(const double x);\nINLINE_DECL double gsl_pow_3(const double x);\nINLINE_DECL double gsl_pow_4(const double x);\nINLINE_DECL double gsl_pow_5(const double x);\nINLINE_DECL double gsl_pow_6(const double x);\nINLINE_DECL double gsl_pow_7(const double x);\nINLINE_DECL double gsl_pow_8(const double x);\nINLINE_DECL double gsl_pow_9(const double x);\n\n#ifdef HAVE_INLINE\nINLINE_FUN double gsl_pow_2(const double x) { return x*x;   }\nINLINE_FUN double gsl_pow_3(const double x) { return x*x*x; }\nINLINE_FUN double gsl_pow_4(const double x) { double x2 = x*x;   return x2*x2;    }\nINLINE_FUN double gsl_pow_5(const double x) { double x2 = x*x;   return x2*x2*x;  }\nINLINE_FUN double gsl_pow_6(const double x) { double x2 = x*x;   return x2*x2*x2; }\nINLINE_FUN double gsl_pow_7(const double x) { double x3 = x*x*x; return x3*x3*x;  }\nINLINE_FUN double gsl_pow_8(const double x) { double x2 = x*x;   double x4 = x2*x2; return x4*x4; }\nINLINE_FUN double gsl_pow_9(const double x) { double x3 = x*x*x; return x3*x3*x3; }\n#endif\n\ndouble gsl_pow_int(double x, int n);\ndouble gsl_pow_uint(double x, unsigned int n);\n\n__END_DECLS\n\n#endif /* __GSL_POW_INT_H__ */\n"
  },
  {
    "path": "gsl/gsl_precision.h",
    "content": "/* gsl_precision.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  B. Gough and G. Jungman */\n\n#ifndef __GSL_PRECISION_H__\n#define __GSL_PRECISION_H__\n#include \"gsl_types.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* A type for the precision indicator.\n * This is mainly for pedagogy.\n */\ntypedef  unsigned int  gsl_prec_t;\n\n\n/* The number of precision types.\n * Remember that precision-mode\n * can index an array.\n */\n#define _GSL_PREC_T_NUM 3\n\n\n/* Arrays containing derived\n * precision constants for the\n * different precision levels.\n */\nGSL_VAR const double gsl_prec_eps[];\nGSL_VAR const double gsl_prec_sqrt_eps[];\nGSL_VAR const double gsl_prec_root3_eps[];\nGSL_VAR const double gsl_prec_root4_eps[];\nGSL_VAR const double gsl_prec_root5_eps[];\nGSL_VAR const double gsl_prec_root6_eps[];\n\n\n__END_DECLS\n\n#endif /* __GSL_PRECISION_H__ */\n"
  },
  {
    "path": "gsl/gsl_types.h",
    "content": "/* gsl_types.h\n * \n * Copyright (C) 2001, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_TYPES_H__\n#define __GSL_TYPES_H__\n\n#ifndef GSL_VAR\n\n#ifdef WIN32\n#  ifdef GSL_DLL\n#    ifdef DLL_EXPORT\n#      define GSL_VAR extern __declspec(dllexport)\n#    else\n#      define GSL_VAR extern __declspec(dllimport)\n#    endif\n#  else\n#    define GSL_VAR extern\n#  endif\n#else\n#  define GSL_VAR extern\n#endif\n\n#endif\n\n#endif /* __GSL_TYPES_H__ */\n"
  },
  {
    "path": "gsl/gsl_version.h",
    "content": "#ifndef __GSL_VERSION_H__\n#define __GSL_VERSION_H__\n\n#include <gsl/gsl_types.h>\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n__BEGIN_DECLS\n\n\n#define GSL_VERSION \"2.5\"\n#define GSL_MAJOR_VERSION 2\n#define GSL_MINOR_VERSION 5\n\nGSL_VAR const char * gsl_version;\n\n__END_DECLS\n\n#endif /* __GSL_VERSION_H__ */\n"
  },
  {
    "path": "gsl/interpolation/accel.c",
    "content": "/* interpolation/accel.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_interp.h\"\n\ngsl_interp_accel *\ngsl_interp_accel_alloc (void)\n{\n  gsl_interp_accel *a = (gsl_interp_accel *) malloc (sizeof (gsl_interp_accel));\n  if (a == 0)\n    {\n      GSL_ERROR_NULL(\"could not allocate space for gsl_interp_accel\", GSL_ENOMEM);\n    }\n\n  a->cache = 0;\n  a->hit_count = 0;\n  a->miss_count = 0;\n\n  return a;\n}\n\nint\ngsl_interp_accel_reset (gsl_interp_accel * a)\n{\n  a->cache = 0;\n  a->hit_count = 0;\n  a->miss_count = 0;\n\n  return GSL_SUCCESS;\n}\n\nvoid\ngsl_interp_accel_free (gsl_interp_accel * a)\n{\n  RETURN_IF_NULL (a);\n  free (a);\n}\n"
  },
  {
    "path": "gsl/interpolation/akima.c",
    "content": "/* interpolation/akima.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include <stdlib.h>\n#include <math.h>\n#include \"gsl_errno.h\"\n#include \"integ_eval.h\"\n#include \"gsl_interp.h\"\n\ntypedef struct\n{\n  double * b;\n  double * c;\n  double * d;\n  double * _m;\n} akima_state_t;\n\n\n/* common creation */\nstatic void *\nakima_alloc (size_t size)\n{\n  akima_state_t *state = (akima_state_t *) malloc (sizeof (akima_state_t));\n  \n  if (state == NULL)\n    {\n      GSL_ERROR_NULL(\"failed to allocate space for state\", GSL_ENOMEM);\n    }\n  \n  state->b = (double *) malloc (size * sizeof (double));\n  \n  if (state->b == NULL)\n    {\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for b\", GSL_ENOMEM);\n    }\n  \n  state->c = (double *) malloc (size * sizeof (double));\n  \n  if (state->c == NULL)\n    {\n      free (state->b);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for c\", GSL_ENOMEM);\n    }\n  \n  state->d = (double *) malloc (size * sizeof (double));\n  \n  if (state->d == NULL)\n    {\n      free (state->c);\n      free (state->b);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for d\", GSL_ENOMEM);\n    }\n\n  state->_m = (double *) malloc ((size + 4) * sizeof (double));\n\n  if (state->_m == NULL)\n    {\n      free (state->d);\n      free (state->c);\n      free (state->b);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for _m\", GSL_ENOMEM);\n    }\n  \n  return state;\n}\n\n\n/* common calculation */\nstatic void\nakima_calc (const double x_array[], double b[],  double c[],  double d[], size_t size, double m[])\n{\n  size_t i;\n\n  for (i = 0; i < (size - 1); i++)\n    {\n      const double NE = fabs (m[i + 1] - m[i]) + fabs (m[i - 1] - m[i - 2]);\n      if (NE == 0.0)\n        {\n          b[i] = m[i];\n          c[i] = 0.0;\n          d[i] = 0.0;\n        }\n      else\n        {\n          const double h_i = x_array[i + 1] - x_array[i];\n          const double NE_next = fabs (m[i + 2] - m[i + 1]) + fabs (m[i] - m[i - 1]);\n          const double alpha_i = fabs (m[i - 1] - m[i - 2]) / NE;\n          double alpha_ip1;\n          double tL_ip1;\n          if (NE_next == 0.0)\n            {\n              tL_ip1 = m[i];\n            }\n          else\n            {\n              alpha_ip1 = fabs (m[i] - m[i - 1]) / NE_next;\n              tL_ip1 = (1.0 - alpha_ip1) * m[i] + alpha_ip1 * m[i + 1];\n            }\n          b[i] = (1.0 - alpha_i) * m[i - 1] + alpha_i * m[i];\n          c[i] = (3.0 * m[i] - 2.0 * b[i] - tL_ip1) / h_i;\n          d[i] = (b[i] + tL_ip1 - 2.0 * m[i]) / (h_i * h_i);\n        }\n    }\n}\n\n\nstatic int\nakima_init (void * vstate, const double x_array[], const double y_array[],\n            size_t size)\n{\n  akima_state_t *state = (akima_state_t *) vstate;\n\n  double * m = state->_m + 2; /* offset so we can address the -1,-2\n                                 components */\n\n  size_t i;\n  for (i = 0; i <= size - 2; i++)\n    {\n      m[i] = (y_array[i + 1] - y_array[i]) / (x_array[i + 1] - x_array[i]);\n    }\n  \n  /* non-periodic boundary conditions */\n  m[-2] = 3.0 * m[0] - 2.0 * m[1];\n  m[-1] = 2.0 * m[0] - m[1];\n  m[size - 1] = 2.0 * m[size - 2] - m[size - 3];\n  m[size] = 3.0 * m[size - 2] - 2.0 * m[size - 3];\n  \n  akima_calc (x_array, state->b, state->c, state->d, size, m);\n  \n  return GSL_SUCCESS;\n}\n\n\nstatic int\nakima_init_periodic (void * vstate,\n                     const double x_array[],\n                     const double y_array[],\n                     size_t size)\n{\n  akima_state_t *state = (akima_state_t *) vstate;\n  \n  double * m = state->_m + 2; /* offset so we can address the -1,-2\n                                 components */\n\n  size_t i;\n  for (i = 0; i <= size - 2; i++)\n    {\n      m[i] = (y_array[i + 1] - y_array[i]) / (x_array[i + 1] - x_array[i]);\n    }\n  \n  /* periodic boundary conditions */\n  m[-2] = m[size - 1 - 2];\n  m[-1] = m[size - 1 - 1];\n  m[size - 1] = m[0];\n  m[size] = m[1];\n  \n  akima_calc (x_array, state->b, state->c, state->d, size, m);\n\n  return GSL_SUCCESS;\n}\n\nstatic void\nakima_free (void * vstate)\n{\n  akima_state_t *state = (akima_state_t *) vstate;\n\n  free (state->b);\n  free (state->c);\n  free (state->d);\n  free (state->_m);\n  free (state);\n}\n\n\nstatic\nint\nakima_eval (const void * vstate,\n            const double x_array[], const double y_array[], size_t size,\n            double x,\n            gsl_interp_accel * a,\n            double *y)\n{\n  const akima_state_t *state = (const akima_state_t *) vstate;\n\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  {\n    const double x_lo = x_array[index];\n    const double delx = x - x_lo;\n    const double b = state->b[index];\n    const double c = state->c[index];\n    const double d = state->d[index];\n    *y = y_array[index] + delx * (b + delx * (c + d * delx));\n    return GSL_SUCCESS;\n  }\n}\n\n\nstatic int\nakima_eval_deriv (const void * vstate,\n                  const double x_array[], const double y_array[], size_t size,\n                  double x,\n                  gsl_interp_accel * a,\n                  double *dydx)\n{\n  const akima_state_t *state = (const akima_state_t *) vstate;\n\n  size_t index;\n\n  DISCARD_POINTER(y_array); /* prevent warning about unused parameter */\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  {\n    double x_lo = x_array[index];\n    double delx = x - x_lo;\n    double b = state->b[index];\n    double c = state->c[index];\n    double d = state->d[index];\n    *dydx = b + delx * (2.0 * c + 3.0 * d * delx);\n    return GSL_SUCCESS;\n  }\n}\n\n\nstatic\nint\nakima_eval_deriv2 (const void * vstate,\n                   const double x_array[], const double y_array[], size_t size,\n                   double x,\n                   gsl_interp_accel * a,\n                   double *y_pp)\n{\n  const akima_state_t *state = (const akima_state_t *) vstate;\n\n  size_t index;\n\n  DISCARD_POINTER(y_array); /* prevent warning about unused parameter */\n\n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  {\n    const double x_lo = x_array[index];\n    const double delx = x - x_lo;\n    const double c = state->c[index];\n    const double d = state->d[index];\n    *y_pp = 2.0 * c + 6.0 * d * delx;\n    return GSL_SUCCESS;\n  }\n}\n\n\nstatic\nint\nakima_eval_integ (const void * vstate,\n                  const double x_array[], const double y_array[], size_t size,\n                  gsl_interp_accel * acc,\n                  double a, double b,\n                  double * result)\n{\n  const akima_state_t *state = (const akima_state_t *) vstate;\n\n  size_t i, index_a, index_b;\n\n  if (acc != 0)\n    {\n      index_a = gsl_interp_accel_find (acc, x_array, size, a);\n      index_b = gsl_interp_accel_find (acc, x_array, size, b);\n    }\n  else\n    {\n      index_a = gsl_interp_bsearch (x_array, a, 0, size - 1);\n      index_b = gsl_interp_bsearch (x_array, b, 0, size - 1);\n    }\n  \n  *result = 0.0;\n\n  /* interior intervals */\n  \n  for(i=index_a; i<=index_b; i++) {\n    const double x_hi = x_array[i + 1];\n    const double x_lo = x_array[i];\n    const double y_lo = y_array[i];\n    const double dx = x_hi - x_lo;\n    if(dx != 0.0) {\n\n      if (i == index_a || i == index_b)\n        {\n          double x1 = (i == index_a) ? a : x_lo;\n          double x2 = (i == index_b) ? b : x_hi;\n          *result += integ_eval (y_lo, state->b[i], state->c[i], state->d[i],\n                                 x_lo, x1, x2);\n        }\n      else\n        {\n          *result += dx * (y_lo \n                           + dx*(0.5*state->b[i] \n                                 + dx*(state->c[i]/3.0 \n                                       + 0.25*state->d[i]*dx)));\n        }\n    }\n    else {\n      *result = 0.0;\n      return GSL_EINVAL;\n    }\n  }\n  \n  return GSL_SUCCESS;\n}\n\n\nstatic const gsl_interp_type akima_type = \n{\n  \"akima\", \n  5,\n  &akima_alloc,\n  &akima_init,\n  &akima_eval,\n  &akima_eval_deriv,\n  &akima_eval_deriv2,\n  &akima_eval_integ,\n  &akima_free\n};\n\nconst gsl_interp_type * gsl_interp_akima = &akima_type;\n\nstatic const gsl_interp_type akima_periodic_type = \n{\n  \"akima-periodic\", \n  5,\n  &akima_alloc,\n  &akima_init_periodic,\n  &akima_eval,\n  &akima_eval_deriv,\n  &akima_eval_deriv2,\n  &akima_eval_integ,\n  &akima_free\n};\n\nconst gsl_interp_type * gsl_interp_akima_periodic = &akima_periodic_type;\n"
  },
  {
    "path": "gsl/interpolation/bicubic.c",
    "content": "/* interpolation/bicubic.c\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_spline.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_interp.h\"\n#include \"gsl_interp2d.h\"\n\n#define IDX2D(i, j, w) ((j) * ((w)->xsize) + (i))\n\ntypedef struct\n{\n  double * zx;\n  double * zy;\n  double * zxy;\n  size_t xsize;\n  size_t ysize;\n} bicubic_state_t;\n\nstatic void bicubic_free (void * vstate);\n\nstatic void *\nbicubic_alloc(size_t xsize, size_t ysize)\n{\n  bicubic_state_t *state;\n  \n  state = calloc(1, sizeof (bicubic_state_t));\n\n  if (state == NULL)\n    {\n      GSL_ERROR_NULL(\"failed to allocate space for state\", GSL_ENOMEM);\n    }\n\n  state->zx = (double *) malloc (xsize * ysize * sizeof (double));\n  if (state->zx == NULL)\n    {\n      bicubic_free(state);\n      GSL_ERROR_NULL(\"failed to allocate space for zx\", GSL_ENOMEM);\n    }\n\n  state->zy = (double *) malloc (xsize * ysize * sizeof (double));\n  if (state->zy == NULL)\n    {\n      bicubic_free(state);\n      GSL_ERROR_NULL(\"failed to allocate space for zy\", GSL_ENOMEM);\n    }\n\n  state->zxy = (double *) malloc (xsize * ysize * sizeof (double));\n  if (state->zxy == NULL)\n    {\n      bicubic_free(state);\n      GSL_ERROR_NULL(\"failed to allocate space for zxy\", GSL_ENOMEM);\n    }\n\n  state->xsize = xsize;\n  state->ysize = ysize;\n\n  return state;\n} /* bicubic_alloc() */\n\nstatic void\nbicubic_free (void * vstate)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  RETURN_IF_NULL(state);\n\n  if (state->zx)\n    free (state->zx);\n\n  if (state->zy)\n    free (state->zy);\n\n  if (state->zxy)\n    free (state->zxy);\n\n  free (state);\n} /* bicubic_free() */\n\nstatic int\nbicubic_init(void * vstate, const double xa[], const double ya[],\n             const double za[], size_t xsize, size_t ysize)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  gsl_interp_accel *acc = gsl_interp_accel_alloc();\n  gsl_spline *spline;\n  gsl_vector *x;\n  gsl_vector *y;\n  size_t i, j;\n\n  x = gsl_vector_alloc(xsize);\n  y = gsl_vector_alloc(xsize);\n  spline = gsl_spline_alloc(gsl_interp_cspline, xsize);\n  for (j = 0; j <= ysize - 1; j++)\n    {\n      for (i = 0; i <= xsize - 1; i++)\n        {\n          gsl_vector_set(x, i, xa[i]);\n          gsl_vector_set(y, i, za[IDX2D(i, j, state)]);\n        }\n      gsl_spline_init(spline, x->data, y->data, xsize);\n      for (i = 0; i <= xsize - 1; i++)\n        {\n          state->zx[IDX2D(i, j, state)] = gsl_spline_eval_deriv(spline, xa[i], acc);\n        }\n    }\n  gsl_vector_free(x);\n  gsl_vector_free(y);\n  gsl_spline_free(spline);\n  gsl_interp_accel_reset(acc);\n\n  x = gsl_vector_alloc(ysize);\n  y = gsl_vector_alloc(ysize);\n  spline = gsl_spline_alloc(gsl_interp_cspline, ysize);\n  for (i = 0; i <= xsize - 1; i++)\n    {\n      for (j = 0; j <= ysize - 1; j++)\n        {\n          gsl_vector_set(x, j, ya[j]);\n          gsl_vector_set(y, j, za[IDX2D(i, j, state)]);\n        }\n      gsl_spline_init(spline, x->data, y->data, ysize);\n      for (j = 0; j <= ysize - 1; j++)\n        {\n          state->zy[IDX2D(i, j, state)] = gsl_spline_eval_deriv(spline, ya[j], acc);\n        }\n    }\n  gsl_vector_free(x);\n  gsl_vector_free(y);\n  gsl_spline_free(spline);\n  gsl_interp_accel_reset(acc);\n\n  x = gsl_vector_alloc(xsize);\n  y = gsl_vector_alloc(xsize);\n  spline = gsl_spline_alloc(gsl_interp_cspline, xsize);\n  for (j = 0; j <= ysize - 1; j++)\n    {\n      for (i = 0; i <= xsize - 1; i++)\n        {\n          gsl_vector_set(x, i, xa[i]);\n          gsl_vector_set(y, i, state->zy[IDX2D(i, j, state)]);\n        }\n      gsl_spline_init(spline, x->data, y->data, xsize);\n      for (i = 0; i <= xsize - 1; i++)\n        {\n          state->zxy[IDX2D(i, j, state)] = gsl_spline_eval_deriv(spline, xa[i], acc);\n        }\n    }\n  gsl_vector_free(x);\n  gsl_vector_free(y);\n  gsl_spline_free(spline);\n  gsl_interp_accel_free(acc);\n\n  return GSL_SUCCESS;\n} /* bicubic_init() */\n\n\nstatic int\nbicubic_eval(const void * vstate, const double xarr[], const double yarr[],\n             const double zarr[], size_t xsize, size_t ysize,\n             double x, double y, gsl_interp_accel * xa,\n             gsl_interp_accel * ya, double * z)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n\n  double dx, dy;   /* size of the grid cell */\n  double dt, du;\n\n  /*\n   * t and u are the positions within the grid cell at which we are computing\n   * the interpolation, in units of grid cell size\n   */\n  double t, u;\n  double t0, t1, t2, t3, u0, u1, u2, u3;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n  /* Get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n  t0 = 1;\n  t1 = t;\n  t2 = t*t;\n  t3 = t*t2;\n  u0 = 1;\n  u1 = u;\n  u2 = u*u;\n  u3 = u*u2;\n\n  *z = 0;\n  v = zminmin;\n  *z += v*t0*u0;\n  v = zyminmin;\n  *z += v*t0*u1;\n  v = -3*zminmin + 3*zminmax - 2*zyminmin - zyminmax;\n  *z += v*t0*u2;\n  v = 2*zminmin - 2*zminmax + zyminmin + zyminmax;\n  *z += v*t0*u3;\n  v = zxminmin;\n  *z += v*t1*u0;\n  v = zxyminmin;\n  *z += v*t1*u1;\n  v = -3*zxminmin + 3*zxminmax - 2*zxyminmin - zxyminmax;\n  *z += v*t1*u2;\n  v = 2*zxminmin - 2*zxminmax + zxyminmin + zxyminmax;\n  *z += v*t1*u3;\n  v = -3*zminmin + 3*zmaxmin - 2*zxminmin - zxmaxmin;\n  *z += v*t2*u0;\n  v = -3*zyminmin + 3*zymaxmin - 2*zxyminmin - zxymaxmin;\n  *z += v*t2*u1;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z += v*t2*u2;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z += v*t2*u3;\n  v = 2*zminmin - 2*zmaxmin + zxminmin + zxmaxmin;\n  *z += v*t3*u0;\n  v = 2*zyminmin - 2*zymaxmin + zxyminmin + zxymaxmin;\n  *z += v*t3*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z += v*t3*u2;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z += v*t3*u3;\n\n  return GSL_SUCCESS;\n} /* bicubic_eval() */\n\nstatic int\nbicubic_deriv_x(const void * vstate, const double xarr[], const double yarr[],\n                const double zarr[], size_t xsize, size_t ysize,\n                double x, double y,\n                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_p)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n  double dx, dy; /* size of the grid cell */\n  double dt, du;\n\n  /*\n   * t and u are the positions within the grid cell at which we are computing\n   * the interpolation, in units of grid cell size\n   */\n  double t, u;\n  double t0, t1, t2, u0, u1, u2, u3;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n\n  /* get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n\n  t0 = 1;\n  t1 = t;\n  t2 = t*t;\n  u0 = 1;\n  u1 = u;\n  u2 = u*u;\n  u3 = u*u2;\n\n  *z_p = 0;\n  v = zxminmin;\n  *z_p += v*t0*u0;\n  v = zxyminmin;\n  *z_p += v*t0*u1;\n  v = -3*zxminmin + 3*zxminmax - 2*zxyminmin - zxyminmax;\n  *z_p += v*t0*u2;\n  v = 2*zxminmin - 2*zxminmax + zxyminmin + zxyminmax;\n  *z_p += v*t0*u3;\n  v = -3*zminmin + 3*zmaxmin - 2*zxminmin - zxmaxmin;\n  *z_p += 2*v*t1*u0;\n  v = -3*zyminmin + 3*zymaxmin - 2*zxyminmin - zxymaxmin;\n  *z_p += 2*v*t1*u1;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z_p += 2*v*t1*u2;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z_p += 2*v*t1*u3;\n  v = 2*zminmin - 2*zmaxmin + zxminmin + zxmaxmin;\n  *z_p += 3*v*t2*u0;\n  v = 2*zyminmin - 2*zymaxmin + zxyminmin + zxymaxmin;\n  *z_p += 3*v*t2*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z_p += 3*v*t2*u2;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z_p += 3*v*t2*u3;\n  *z_p *= dt;\n\n  return GSL_SUCCESS;\n} /* bicubic_deriv_x() */\n\nstatic int\nbicubic_deriv_y(const void * vstate, const double xarr[], const double yarr[],\n                const double zarr[], size_t xsize, size_t ysize,\n                double x, double y,\n                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_p)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n  /* dx and dy are the size of the grid cell */\n  double dx, dy;\n  double dt, du;\n  /* t and u are the positions within the grid cell at which we are\n   * computing the interpolation, in units of grid cell size */\n  double t, u;\n  double t0, t1, t2, t3, u0, u1, u2;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n\n  /* get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n\n  t0 = 1;\n  t1 = t;\n  t2 = t*t;\n  t3 = t*t2;\n  u0 = 1;\n  u1 = u;\n  u2 = u*u;\n\n  *z_p = 0;\n  v = zyminmin;\n  *z_p += v*t0*u0;\n  v = -3*zminmin + 3*zminmax - 2*zyminmin - zyminmax;\n  *z_p += 2*v*t0*u1;\n  v = 2*zminmin-2*zminmax + zyminmin + zyminmax;\n  *z_p += 3*v*t0*u2;\n  v = zxyminmin;\n  *z_p += v*t1*u0;\n  v = -3*zxminmin + 3*zxminmax - 2*zxyminmin - zxyminmax;\n  *z_p += 2*v*t1*u1;\n  v = 2*zxminmin - 2*zxminmax + zxyminmin + zxyminmax;\n  *z_p += 3*v*t1*u2;\n  v = -3*zyminmin + 3*zymaxmin - 2*zxyminmin - zxymaxmin;\n  *z_p += v*t2*u0;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z_p += 2*v*t2*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z_p += 3*v*t2*u2;\n  v = 2*zyminmin - 2*zymaxmin + zxyminmin + zxymaxmin;\n  *z_p += v*t3*u0;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z_p += 2*v*t3*u1;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z_p += 3*v*t3*u2;\n  *z_p *= du;\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbicubic_deriv_xx(const void * vstate, const double xarr[], const double yarr[],\n                 const double zarr[], size_t xsize, size_t ysize,\n                 double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_pp)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n\n  double dx, dy; /* size of the grid cell */\n  double dt, du;\n\n  /*\n   * t and u are the positions within the grid cell at which we are computing\n   * the interpolation, in units of grid cell size\n   */\n  double t, u;\n  double t0, t1, u0, u1, u2, u3;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n\n  /* get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n\n  t0 = 1;\n  t1 = t;\n  u0 = 1;\n  u1 = u;\n  u2 = u*u;\n  u3 = u*u2;\n\n  *z_pp = 0;\n  v = -3*zminmin + 3*zmaxmin - 2*zxminmin - zxmaxmin;\n  *z_pp += 2*v*t0*u0;\n  v = -3*zyminmin + 3*zymaxmin - 2*zxyminmin - zxymaxmin;\n  *z_pp += 2*v*t0*u1;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z_pp += 2*v*t0*u2;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z_pp += 2*v*t0*u3;\n  v = 2*zminmin - 2*zmaxmin + zxminmin + zxmaxmin;\n  *z_pp += 6*v*t1*u0;\n  v = 2*zyminmin - 2*zymaxmin + zxyminmin + zxymaxmin;\n  *z_pp += 6*v*t1*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z_pp += 6*v*t1*u2;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z_pp += 6*v*t1*u3;\n  *z_pp *= dt*dt;\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbicubic_deriv_xy(const void * vstate, const double xarr[], const double yarr[],\n                 const double zarr[], size_t xsize, size_t ysize,\n                 double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_pp)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n\n  double dx, dy; /* size of the grid cell */\n  double dt, du;\n\n  /*\n   * t and u are the positions within the grid cell at which we are computing\n   * the interpolation, in units of grid cell size\n   */\n  double t, u;\n  double t0, t1, t2, u0, u1, u2;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n\n  /* get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n\n  t0 = 1;\n  t1 = t;\n  t2 = t*t;\n  u0 = 1;\n  u1 = u;\n  u2 = u*u;\n\n  *z_pp = 0;\n  v = zxyminmin;\n  *z_pp += v*t0*u0;\n  v = -3*zxminmin + 3*zxminmax - 2*zxyminmin - zxyminmax;\n  *z_pp += 2*v*t0*u1;\n  v = 2*zxminmin - 2*zxminmax + zxyminmin + zxyminmax;\n  *z_pp += 3*v*t0*u2;\n  v = -3*zyminmin + 3*zymaxmin - 2*zxyminmin - zxymaxmin;\n  *z_pp += 2*v*t1*u0;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z_pp += 4*v*t1*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z_pp += 6*v*t1*u2;\n  v = 2*zyminmin - 2*zymaxmin + zxyminmin + zxymaxmin;\n  *z_pp += 3*v*t2*u0;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z_pp += 6*v*t2*u1;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z_pp += 9*v*t2*u2;\n  *z_pp *= dt*du;\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbicubic_deriv_yy(const void * vstate, const double xarr[], const double yarr[],\n                 const double zarr[], size_t xsize, size_t ysize,\n                 double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_pp)\n{\n  bicubic_state_t *state = (bicubic_state_t *) vstate;\n\n  double xmin, xmax, ymin, ymax;\n  double zminmin, zminmax, zmaxmin, zmaxmax;\n  double zxminmin, zxminmax, zxmaxmin, zxmaxmax;\n  double zyminmin, zyminmax, zymaxmin, zymaxmax;\n  double zxyminmin, zxyminmax, zxymaxmin, zxymaxmax;\n\n  double dx, dy; /* size of the grid cell */\n  double dt, du;\n\n  /*\n   * t and u are the positions within the grid cell at which we are computing\n   * the interpolation, in units of grid cell size\n   */\n  double t, u;\n  double t0, t1, t2, t3, u0, u1;\n  double v;\n  size_t xi, yi;\n\n  /* first compute the indices into the data arrays where we are interpolating */\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  /* find the minimum and maximum values on the grid cell in each dimension */\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, state)];\n  zminmax = zarr[IDX2D(xi, yi + 1, state)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, state)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, state)];\n\n  /* get the width and height of the grid cell */\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n\n  zxminmin = state->zx[IDX2D(xi, yi, state)]/dt;\n  zxminmax = state->zx[IDX2D(xi, yi + 1, state)]/dt;\n  zxmaxmin = state->zx[IDX2D(xi + 1, yi, state)]/dt;\n  zxmaxmax = state->zx[IDX2D(xi + 1, yi + 1, state)]/dt;\n  zyminmin = state->zy[IDX2D(xi, yi, state)]/du;\n  zyminmax = state->zy[IDX2D(xi, yi + 1, state)]/du;\n  zymaxmin = state->zy[IDX2D(xi + 1, yi, state)]/du;\n  zymaxmax = state->zy[IDX2D(xi + 1, yi + 1, state)]/du;\n  zxyminmin = state->zxy[IDX2D(xi, yi, state)]/(dt*du);\n  zxyminmax = state->zxy[IDX2D(xi, yi + 1, state)]/(dt*du);\n  zxymaxmin = state->zxy[IDX2D(xi + 1, yi, state)]/(dt*du);\n  zxymaxmax = state->zxy[IDX2D(xi + 1, yi + 1, state)]/(dt*du);\n\n  t0 = 1;\n  t1 = t;\n  t2 = t*t;\n  t3 = t*t2;\n  u0 = 1;\n  u1 = u;\n\n  *z_pp = 0;\n  v = -3*zminmin + 3*zminmax - 2*zyminmin - zyminmax;\n  *z_pp += 2*v*t0*u0;\n  v = 2*zminmin-2*zminmax + zyminmin + zyminmax;\n  *z_pp += 6*v*t0*u1;\n  v = -3*zxminmin + 3*zxminmax - 2*zxyminmin - zxyminmax;\n  *z_pp += 2*v*t1*u0;\n  v = 2*zxminmin - 2*zxminmax + zxyminmin + zxyminmax;\n  *z_pp += 6*v*t1*u1;\n  v = 9*zminmin - 9*zmaxmin + 9*zmaxmax - 9*zminmax + 6*zxminmin + 3*zxmaxmin - 3*zxmaxmax - 6*zxminmax + 6*zyminmin - 6*zymaxmin - 3*zymaxmax + 3*zyminmax + 4*zxyminmin + 2*zxymaxmin + zxymaxmax + 2*zxyminmax;\n  *z_pp += 2*v*t2*u0;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 4*zxminmin - 2*zxmaxmin + 2*zxmaxmax + 4*zxminmax - 3*zyminmin + 3*zymaxmin + 3*zymaxmax - 3*zyminmax - 2*zxyminmin - zxymaxmin - zxymaxmax - 2*zxyminmax;\n  *z_pp += 6*v*t2*u1;\n  v = -6*zminmin + 6*zmaxmin - 6*zmaxmax + 6*zminmax - 3*zxminmin - 3*zxmaxmin + 3*zxmaxmax + 3*zxminmax - 4*zyminmin + 4*zymaxmin + 2*zymaxmax - 2*zyminmax - 2*zxyminmin - 2*zxymaxmin - zxymaxmax - zxyminmax;\n  *z_pp += 2*v*t3*u0;\n  v = 4*zminmin - 4*zmaxmin + 4*zmaxmax - 4*zminmax + 2*zxminmin + 2*zxmaxmin - 2*zxmaxmax - 2*zxminmax + 2*zyminmin - 2*zymaxmin - 2*zymaxmax + 2*zyminmax + zxyminmin + zxymaxmin + zxymaxmax + zxyminmax;\n  *z_pp += 6*v*t3*u1;\n  *z_pp *= du*du;\n\n  return GSL_SUCCESS;\n}\n\nstatic const gsl_interp2d_type bicubic_type = {\n  \"bicubic\",\n  4,\n  &bicubic_alloc,\n  &bicubic_init,\n  &bicubic_eval,\n  &bicubic_deriv_x,\n  &bicubic_deriv_y,\n  &bicubic_deriv_xx,\n  &bicubic_deriv_xy,\n  &bicubic_deriv_yy,\n  &bicubic_free\n};\n\nconst gsl_interp2d_type * gsl_interp2d_bicubic = &bicubic_type;\n\n#undef IDX2D\n"
  },
  {
    "path": "gsl/interpolation/bilinear.c",
    "content": "/* interpolation/bilinear.c\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_interp.h\"\n#include \"gsl_interp2d.h\"\n\n#define IDX2D(i, j, xsize, ysize) ((j) * (xsize) + (i))\n\nstatic int\nbilinear_init(__attribute__ ((unused)) void * state, __attribute__ ((unused)) const double xa[], __attribute__ ((unused)) const double ya[],\n\t\t\t  __attribute__ ((unused)) const double za[], __attribute__ ((unused)) size_t xsize, __attribute__ ((unused)) size_t ysize)\n{\n  return GSL_SUCCESS;\n}\n\nstatic int\nbilinear_eval(__attribute__ ((unused)) const void * state, const double xarr[], const double yarr[],\n              const double zarr[], size_t xsize, size_t ysize,\n              double x, double y, gsl_interp_accel * xa,\n              gsl_interp_accel * ya, double * z)\n{\n  double xmin, xmax, ymin, ymax, zminmin, zminmax, zmaxmin, zmaxmax;\n  double dx, dy;\n  double t, u;\n  size_t xi, yi;\n\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, xsize, ysize)];\n  zminmax = zarr[IDX2D(xi, yi + 1, xsize, ysize)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, xsize, ysize)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, xsize, ysize)];\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  u = (y - ymin)/dy;\n  *z = (1.-t)*(1.-u)*zminmin + t*(1.-u)*zmaxmin + (1.-t)*u*zminmax + t*u*zmaxmax;\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbilinear_deriv_x(__attribute__ ((unused)) const void * state, const double xarr[],\n                 const double yarr[], const double zarr[],\n                 size_t xsize, size_t ysize, double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_p)\n{\n  double xmin, xmax, ymin, ymax, zminmin, zminmax, zmaxmin, zmaxmax;\n  double dx, dy;\n  double dt, u;\n  size_t xi, yi;\n\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, xsize, ysize)];\n  zminmax = zarr[IDX2D(xi, yi + 1, xsize, ysize)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, xsize, ysize)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, xsize, ysize)];\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  dt = 1./dx; /* partial t / partial x */\n  u = (y - ymin)/dy;\n  *z_p = dt*(-(1.-u)*zminmin + (1.-u)*zmaxmin - u*zminmax + u*zmaxmax);\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbilinear_deriv_y(__attribute__ ((unused)) const void * state, const double xarr[],\n                 const double yarr[], const double zarr[],\n                 size_t xsize, size_t ysize, double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_p)\n{\n  double xmin, xmax, ymin, ymax, zminmin, zminmax, zmaxmin, zmaxmax;\n  double dx, dy;\n  double t, du;\n  size_t xi, yi;\n\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, xsize, ysize)];\n  zminmax = zarr[IDX2D(xi, yi + 1, xsize, ysize)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, xsize, ysize)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, xsize, ysize)];\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  t = (x - xmin)/dx;\n  du = 1./dy; /* partial u / partial y */\n  *z_p = du*(-(1.-t)*zminmin - t*zmaxmin + (1.-t)*zminmax + t*zmaxmax);\n\n  return GSL_SUCCESS;\n}\n\nstatic int\nbilinear_deriv2(__attribute__ ((unused)) const void * state, __attribute__ ((unused)) const double xarr[],\n\t\t\t\t__attribute__ ((unused)) const double yarr[], __attribute__ ((unused)) const double zarr[],\n\t\t\t\t__attribute__ ((unused)) size_t xsize, __attribute__ ((unused)) size_t ysize, __attribute__ ((unused)) double x, __attribute__ ((unused)) double y,\n\t\t\t\t__attribute__ ((unused)) gsl_interp_accel * xa, __attribute__ ((unused)) gsl_interp_accel * ya, double * z_pp)\n{\n  *z_pp = 0.0;\n  return GSL_SUCCESS;\n}\n\nstatic int\nbilinear_derivxy(__attribute__ ((unused)) const void * state, const double xarr[],\n                 const double yarr[], const double zarr[],\n                 size_t xsize, size_t ysize, double x, double y,\n                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z_pp)\n{\n  double xmin, xmax, ymin, ymax, zminmin, zminmax, zmaxmin, zmaxmax;\n  double dx, dy;\n  double dt, du;\n  size_t xi, yi;\n\n  if (xa != NULL)\n    xi = gsl_interp_accel_find(xa, xarr, xsize, x);\n  else\n    xi = gsl_interp_bsearch(xarr, x, 0, xsize - 1);\n\n  if (ya != NULL)\n    yi = gsl_interp_accel_find(ya, yarr, ysize, y);\n  else\n    yi = gsl_interp_bsearch(yarr, y, 0, ysize - 1);\n\n  xmin = xarr[xi];\n  xmax = xarr[xi + 1];\n  ymin = yarr[yi];\n  ymax = yarr[yi + 1];\n  zminmin = zarr[IDX2D(xi, yi, xsize, ysize)];\n  zminmax = zarr[IDX2D(xi, yi + 1, xsize, ysize)];\n  zmaxmin = zarr[IDX2D(xi + 1, yi, xsize, ysize)];\n  zmaxmax = zarr[IDX2D(xi + 1, yi + 1, xsize, ysize)];\n  dx = xmax - xmin;\n  dy = ymax - ymin;\n  dt = 1./dx; /* partial t / partial x */\n  du = 1./dy; /* partial u / partial y */\n  *z_pp = dt*du*(zminmin-zmaxmin-zminmax+zmaxmax);\n\n  return GSL_SUCCESS;\n}\n\nstatic const gsl_interp2d_type bilinear_type = {\n  \"bilinear\",\n  2,\n  NULL,\n  &bilinear_init,\n  &bilinear_eval,\n  &bilinear_deriv_x,\n  &bilinear_deriv_y,\n  &bilinear_deriv2,\n  &bilinear_derivxy,\n  &bilinear_deriv2,\n  NULL\n};\n\nconst gsl_interp2d_type * gsl_interp2d_bilinear = &bilinear_type;\n\n#undef IDX2D\n"
  },
  {
    "path": "gsl/interpolation/cspline.c",
    "content": "/* interpolation/cspline.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_linalg.h\"\n#include \"gsl_vector.h\"\n#include \"integ_eval.h\"\n#include \"gsl_interp.h\"\n\ntypedef struct\n{\n  double * c;\n  double * g;\n  double * diag;\n  double * offdiag;\n} cspline_state_t;\n\n\n/* common initialization */\nstatic void *\ncspline_alloc (size_t size)\n{\n  cspline_state_t * state = (cspline_state_t *) malloc (sizeof (cspline_state_t));\n\n  if (state == NULL)\n    {\n      GSL_ERROR_NULL(\"failed to allocate space for state\", GSL_ENOMEM);\n    }\n  \n  state->c = (double *) malloc (size * sizeof (double));\n  \n  if (state->c == NULL)\n    {\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for c\", GSL_ENOMEM);\n    }\n\n  state->g = (double *) malloc (size * sizeof (double));\n  \n  if (state->g == NULL)\n    {\n      free (state->c);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for g\", GSL_ENOMEM);\n    }\n\n  state->diag = (double *) malloc (size * sizeof (double));\n  \n  if (state->diag == NULL)\n    {\n      free (state->g);\n      free (state->c);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for diag\", GSL_ENOMEM);\n    }\n\n  state->offdiag = (double *) malloc (size * sizeof (double));\n  \n  if (state->offdiag == NULL)\n    {\n      free (state->diag);\n      free (state->g);\n      free (state->c);\n      free (state);\n      GSL_ERROR_NULL(\"failed to allocate space for offdiag\", GSL_ENOMEM);\n    }\n\n  return state;\n}\n\n\n/* natural spline calculation\n * see [Engeln-Mullges + Uhlig, p. 254]\n */\nstatic int\ncspline_init (void * vstate, const double xa[], const double ya[],\n              size_t size)\n{\n  cspline_state_t *state = (cspline_state_t *) vstate;\n\n  size_t i;\n  size_t num_points = size;\n  size_t max_index = num_points - 1;  /* Engeln-Mullges + Uhlig \"n\" */\n  size_t sys_size = max_index - 1;    /* linear system is sys_size x sys_size */\n\n  state->c[0] = 0.0;\n  state->c[max_index] = 0.0;\n\n  for (i = 0; i < sys_size; i++)\n    {\n      const double h_i   = xa[i + 1] - xa[i];\n      const double h_ip1 = xa[i + 2] - xa[i + 1];\n      const double ydiff_i   = ya[i + 1] - ya[i];\n      const double ydiff_ip1 = ya[i + 2] - ya[i + 1];\n      const double g_i = (h_i != 0.0) ? 1.0 / h_i : 0.0;\n      const double g_ip1 = (h_ip1 != 0.0) ? 1.0 / h_ip1 : 0.0;\n      state->offdiag[i] = h_ip1;\n      state->diag[i] = 2.0 * (h_ip1 + h_i);\n      state->g[i] = 3.0 * (ydiff_ip1 * g_ip1 -  ydiff_i * g_i);\n    }\n\n  if (sys_size == 1)\n    {\n      state->c[1] = state->g[0] / state->diag[0];\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      gsl_vector_view g_vec = gsl_vector_view_array(state->g, sys_size);\n      gsl_vector_view diag_vec = gsl_vector_view_array(state->diag, sys_size);\n      gsl_vector_view offdiag_vec = gsl_vector_view_array(state->offdiag, sys_size - 1);\n      gsl_vector_view solution_vec = gsl_vector_view_array ((state->c) + 1, sys_size);\n      \n      int status = gsl_linalg_solve_symm_tridiag(&diag_vec.vector, \n                                                 &offdiag_vec.vector, \n                                                 &g_vec.vector, \n                                                 &solution_vec.vector);\n      return status;\n    }\n}\n\n\n/* periodic spline calculation\n * see [Engeln-Mullges + Uhlig, p. 256]\n */\nstatic int\ncspline_init_periodic (void * vstate, const double xa[], const double ya[],\n                       size_t size)\n{\n  cspline_state_t *state = (cspline_state_t *) vstate;\n\n  size_t i;\n  size_t num_points = size;\n  size_t max_index = num_points - 1;  /* Engeln-Mullges + Uhlig \"n\" */\n  size_t sys_size = max_index;    /* linear system is sys_size x sys_size */\n\n  if (sys_size == 2) {\n    /* solve 2x2 system */\n    \n    const double h0 = xa[1] - xa[0];\n    const double h1 = xa[2] - xa[1];\n\n    const double A = 2.0*(h0 + h1);\n    const double B = h0 + h1;\n    double g[2];\n    double det;\n    \n    g[0] = 3.0 * ((ya[2] - ya[1]) / h1 - (ya[1] - ya[0]) / h0);\n    g[1] = 3.0 * ((ya[1] - ya[2]) / h0 - (ya[2] - ya[1]) / h1);\n    \n    det = 3.0 * (h0 + h1) * (h0 + h1);\n    state->c[1] = ( A * g[0] - B * g[1])/det;\n    state->c[2] = (-B * g[0] + A * g[1])/det;\n    state->c[0] = state->c[2];\n    \n    return GSL_SUCCESS;\n  } else {\n    \n    for (i = 0; i < sys_size-1; i++) {\n      const double h_i       = xa[i + 1] - xa[i];\n      const double h_ip1     = xa[i + 2] - xa[i + 1];\n      const double ydiff_i   = ya[i + 1] - ya[i];\n      const double ydiff_ip1 = ya[i + 2] - ya[i + 1];\n      const double g_i = (h_i != 0.0) ? 1.0 / h_i : 0.0;\n      const double g_ip1 = (h_ip1 != 0.0) ? 1.0 / h_ip1 : 0.0;\n      state->offdiag[i] = h_ip1;\n      state->diag[i] = 2.0 * (h_ip1 + h_i);\n      state->g[i] = 3.0 * (ydiff_ip1 * g_ip1 - ydiff_i * g_i);\n    }\n\n    i = sys_size - 1;\n\n    {\n      const double h_i       = xa[i + 1] - xa[i];\n      const double h_ip1     = xa[1] - xa[0];\n      const double ydiff_i   = ya[i + 1] - ya[i];\n      const double ydiff_ip1 = ya[1] - ya[0];\n      const double g_i = (h_i != 0.0) ? 1.0 / h_i : 0.0;\n      const double g_ip1 = (h_ip1 != 0.0) ? 1.0 / h_ip1 : 0.0;\n      state->offdiag[i] = h_ip1;\n      state->diag[i] = 2.0 * (h_ip1 + h_i);\n      state->g[i] = 3.0 * (ydiff_ip1 * g_ip1 - ydiff_i * g_i);\n    }\n    \n    {\n      gsl_vector_view g_vec = gsl_vector_view_array(state->g, sys_size);\n      gsl_vector_view diag_vec = gsl_vector_view_array(state->diag, sys_size);\n      gsl_vector_view offdiag_vec = gsl_vector_view_array(state->offdiag, sys_size);\n      gsl_vector_view solution_vec = gsl_vector_view_array ((state->c) + 1, sys_size);\n      \n      int status = gsl_linalg_solve_symm_cyc_tridiag(&diag_vec.vector, \n                                                     &offdiag_vec.vector, \n                                                     &g_vec.vector, \n                                                     &solution_vec.vector);\n      state->c[0] = state->c[max_index];\n      \n      return status;\n    }\n  }\n}\n\n\nstatic\nvoid\ncspline_free (void * vstate)\n{\n  cspline_state_t *state = (cspline_state_t *) vstate;\n  \n  free (state->c);\n  free (state->g);\n  free (state->diag);\n  free (state->offdiag);\n  free (state);\n}\n\n/* function for common coefficient determination\n */\nstatic inline void\ncoeff_calc (const double c_array[], double dy, double dx, size_t index,  \n            double * b, double * c, double * d)\n{\n  const double c_i = c_array[index];\n  const double c_ip1 = c_array[index + 1];\n  *b = (dy / dx) - dx * (c_ip1 + 2.0 * c_i) / 3.0;\n  *c = c_i;\n  *d = (c_ip1 - c_i) / (3.0 * dx);\n}\n\n\nstatic\nint\ncspline_eval (const void * vstate,\n              const double x_array[], const double y_array[], size_t size,\n              double x,\n              gsl_interp_accel * a,\n              double *y)\n{\n  const cspline_state_t *state = (const cspline_state_t *) vstate;\n\n  double x_lo, x_hi;\n  double dx;\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  x_hi = x_array[index + 1];\n  x_lo = x_array[index];\n  dx = x_hi - x_lo;\n  if (dx > 0.0)\n    {\n      const double y_lo = y_array[index];\n      const double y_hi = y_array[index + 1];\n      const double dy = y_hi - y_lo;\n      double delx = x - x_lo;\n      double b_i, c_i, d_i; \n      coeff_calc(state->c, dy, dx, index,  &b_i, &c_i, &d_i);\n      *y = y_lo + delx * (b_i + delx * (c_i + delx * d_i));\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      *y = 0.0;\n      return GSL_EINVAL;\n    }\n}\n\n\nstatic\nint\ncspline_eval_deriv (const void * vstate,\n                    const double x_array[], const double y_array[], size_t size,\n                    double x,\n                    gsl_interp_accel * a,\n                    double *dydx)\n{\n  const cspline_state_t *state = (const cspline_state_t *) vstate;\n\n  double x_lo, x_hi;\n  double dx;\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  x_hi = x_array[index + 1];\n  x_lo = x_array[index];\n  dx = x_hi - x_lo;\n  if (dx > 0.0)\n    {\n      const double y_lo = y_array[index];\n      const double y_hi = y_array[index + 1];\n      const double dy = y_hi - y_lo;\n      double delx = x - x_lo;\n      double b_i, c_i, d_i; \n      coeff_calc(state->c, dy, dx, index,  &b_i, &c_i, &d_i);\n      *dydx = b_i + delx * (2.0 * c_i + 3.0 * d_i * delx);\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      *dydx = 0.0;\n      return GSL_EINVAL;\n    }\n}\n\n\nstatic\nint\ncspline_eval_deriv2 (const void * vstate,\n                     const double x_array[], const double y_array[], size_t size,\n                     double x,\n                     gsl_interp_accel * a,\n                     double * y_pp)\n{\n  const cspline_state_t *state = (const cspline_state_t *) vstate;\n\n  double x_lo, x_hi;\n  double dx;\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  x_hi = x_array[index + 1];\n  x_lo = x_array[index];\n  dx = x_hi - x_lo;\n  if (dx > 0.0)\n    {\n      const double y_lo = y_array[index];\n      const double y_hi = y_array[index + 1];\n      const double dy = y_hi - y_lo;\n      double delx = x - x_lo;\n      double b_i, c_i, d_i;\n      coeff_calc(state->c, dy, dx, index,  &b_i, &c_i, &d_i);\n      *y_pp = 2.0 * c_i + 6.0 * d_i * delx;\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      *y_pp = 0.0;\n      return GSL_EINVAL;\n    }\n}\n\n\nstatic\nint\ncspline_eval_integ (const void * vstate,\n                    const double x_array[], const double y_array[], size_t size,\n                    gsl_interp_accel * acc,\n                    double a, double b,\n                    double * result)\n{\n  const cspline_state_t *state = (const cspline_state_t *) vstate;\n\n  size_t i, index_a, index_b;\n  \n  if (acc != 0)\n    {\n      index_a = gsl_interp_accel_find (acc, x_array, size, a);\n      index_b = gsl_interp_accel_find (acc, x_array, size, b);\n    }\n  else\n    {\n      index_a = gsl_interp_bsearch (x_array, a, 0, size - 1);\n      index_b = gsl_interp_bsearch (x_array, b, 0, size - 1);\n    }\n\n  *result = 0.0;\n  \n  /* interior intervals */\n  for(i=index_a; i<=index_b; i++) {\n    const double x_hi = x_array[i + 1];\n    const double x_lo = x_array[i];\n    const double y_lo = y_array[i];\n    const double y_hi = y_array[i + 1];\n    const double dx = x_hi - x_lo;\n    const double dy = y_hi - y_lo;\n    if(dx != 0.0) {\n      double b_i, c_i, d_i; \n      coeff_calc(state->c, dy, dx, i,  &b_i, &c_i, &d_i);\n      \n      if (i == index_a || i == index_b)\n        {\n          double x1 = (i == index_a) ? a : x_lo;\n          double x2 = (i == index_b) ? b : x_hi;\n          *result += integ_eval(y_lo, b_i, c_i, d_i, x_lo, x1, x2);\n        }\n      else\n        {\n          *result += dx * (y_lo + dx*(0.5*b_i + dx*(c_i/3.0 + 0.25*d_i*dx)));\n        }\n    }\n    else {\n      *result = 0.0;\n      return GSL_EINVAL;\n    }\n  }\n  \n  return GSL_SUCCESS;\n}\n\nstatic const gsl_interp_type cspline_type = \n{\n  \"cspline\", \n  3,\n  &cspline_alloc,\n  &cspline_init,\n  &cspline_eval,\n  &cspline_eval_deriv,\n  &cspline_eval_deriv2,\n  &cspline_eval_integ,\n  &cspline_free\n};\n\nconst gsl_interp_type * gsl_interp_cspline = &cspline_type;\n\nstatic const gsl_interp_type cspline_periodic_type = \n{\n  \"cspline-periodic\", \n  2,\n  &cspline_alloc,\n  &cspline_init_periodic,\n  &cspline_eval,\n  &cspline_eval_deriv,\n  &cspline_eval_deriv2,\n  &cspline_eval_integ,\n  &cspline_free\n};\n\nconst gsl_interp_type * gsl_interp_cspline_periodic = &cspline_periodic_type;\n\n\n"
  },
  {
    "path": "gsl/interpolation/gsl_interp.h",
    "content": "/* interpolation/gsl_interp.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#ifndef __GSL_INTERP_H__\n#define __GSL_INTERP_H__\n#include <stdlib.h>\n#include \"gsl_inline.h\"\n#include \"gsl_types.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* evaluation accelerator */\ntypedef struct {\n  size_t  cache;        /* cache of index   */\n  size_t  miss_count;   /* keep statistics  */\n  size_t  hit_count;\n}\ngsl_interp_accel;\n\n\n/* interpolation object type */\ntypedef struct {\n  const char * name;\n  unsigned int min_size;\n  void *  (*alloc) (size_t size);\n  int     (*init)    (void *, const double xa[], const double ya[], size_t size);\n  int     (*eval)    (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y);\n  int     (*eval_deriv)  (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y_p);\n  int     (*eval_deriv2) (const void *, const double xa[], const double ya[], size_t size, double x, gsl_interp_accel *, double * y_pp);\n  int     (*eval_integ)  (const void *, const double xa[], const double ya[], size_t size, gsl_interp_accel *, double a, double b, double * result);\n  void    (*free)         (void *);\n\n} gsl_interp_type;\n\n\n/* general interpolation object */\ntypedef struct {\n  const gsl_interp_type * type;\n  double  xmin;\n  double  xmax;\n  size_t  size;\n  void * state;\n} gsl_interp;\n\n\n/* available types */\nGSL_VAR const gsl_interp_type * gsl_interp_linear;\nGSL_VAR const gsl_interp_type * gsl_interp_polynomial;\nGSL_VAR const gsl_interp_type * gsl_interp_cspline;\nGSL_VAR const gsl_interp_type * gsl_interp_cspline_periodic;\nGSL_VAR const gsl_interp_type * gsl_interp_akima;\nGSL_VAR const gsl_interp_type * gsl_interp_akima_periodic;\nGSL_VAR const gsl_interp_type * gsl_interp_steffen;\n\ngsl_interp_accel *\ngsl_interp_accel_alloc(void);\n\nint\ngsl_interp_accel_reset (gsl_interp_accel * a);\n\nvoid\ngsl_interp_accel_free(gsl_interp_accel * a);\n\ngsl_interp *\ngsl_interp_alloc(const gsl_interp_type * T, size_t n);\n     \nint\ngsl_interp_init(gsl_interp * obj, const double xa[], const double ya[], size_t size);\n\nconst char * gsl_interp_name(const gsl_interp * interp);\nunsigned int gsl_interp_min_size(const gsl_interp * interp);\nunsigned int gsl_interp_type_min_size(const gsl_interp_type * T);\n\n\nint\ngsl_interp_eval_e(const gsl_interp * obj,\n                  const double xa[], const double ya[], double x,\n                  gsl_interp_accel * a, double * y);\n\ndouble\ngsl_interp_eval(const gsl_interp * obj,\n                const double xa[], const double ya[], double x,\n                gsl_interp_accel * a);\n\nint\ngsl_interp_eval_deriv_e(const gsl_interp * obj,\n                        const double xa[], const double ya[], double x,\n                        gsl_interp_accel * a,\n                        double * d);\n\ndouble\ngsl_interp_eval_deriv(const gsl_interp * obj,\n                      const double xa[], const double ya[], double x,\n                      gsl_interp_accel * a);\n\nint\ngsl_interp_eval_deriv2_e(const gsl_interp * obj,\n                         const double xa[], const double ya[], double x,\n                         gsl_interp_accel * a,\n                         double * d2);\n\ndouble\ngsl_interp_eval_deriv2(const gsl_interp * obj,\n                       const double xa[], const double ya[], double x,\n                       gsl_interp_accel * a);\n\nint\ngsl_interp_eval_integ_e(const gsl_interp * obj,\n                        const double xa[], const double ya[],\n                        double a, double b,\n                        gsl_interp_accel * acc,\n                        double * result);\n\ndouble\ngsl_interp_eval_integ(const gsl_interp * obj,\n                      const double xa[], const double ya[],\n                      double a, double b,\n                      gsl_interp_accel * acc);\n\nvoid\ngsl_interp_free(gsl_interp * interp);\n\nINLINE_DECL size_t\ngsl_interp_bsearch(const double x_array[], double x,\n                   size_t index_lo, size_t index_hi);\n\n#ifdef HAVE_INLINE\n\n/* Perform a binary search of an array of values.\n * \n * The parameters index_lo and index_hi provide an initial bracket,\n * and it is assumed that index_lo < index_hi. The resulting index\n * is guaranteed to be strictly less than index_hi and greater than\n * or equal to index_lo, so that the implicit bracket [index, index+1]\n * always corresponds to a region within the implicit value range of\n * the value array.\n *\n * Note that this means the relationship of 'x' to x_array[index]\n * and x_array[index+1] depends on the result region, i.e. the\n * behaviour at the boundaries may not correspond to what you\n * expect. We have the following complete specification of the\n * behaviour.\n * Suppose the input is x_array[] = { x0, x1, ..., xN }\n *    if ( x == x0 )           then  index == 0\n *    if ( x > x0 && x <= x1 ) then  index == 0, and sim. for other interior pts\n *    if ( x == xN )           then  index == N-1\n *    if ( x > xN )            then  index == N-1\n *    if ( x < x0 )            then  index == 0 \n */\n\nINLINE_FUN size_t\ngsl_interp_bsearch(const double x_array[], double x,\n                   size_t index_lo, size_t index_hi)\n{\n  size_t ilo = index_lo;\n  size_t ihi = index_hi;\n  while(ihi > ilo + 1) {\n    size_t i = (ihi + ilo)/2;\n    if(x_array[i] > x)\n      ihi = i;\n    else\n      ilo = i;\n  }\n  \n  return ilo;\n}\n#endif\n\nINLINE_DECL size_t \ngsl_interp_accel_find(gsl_interp_accel * a, const double x_array[], size_t size, double x);\n\n#ifdef HAVE_INLINE\nINLINE_FUN size_t\ngsl_interp_accel_find(gsl_interp_accel * a, const double xa[], size_t len, double x)\n{\n  size_t x_index = a->cache;\n \n  if(x < xa[x_index]) {\n    a->miss_count++;\n    a->cache = gsl_interp_bsearch(xa, x, 0, x_index);\n  }\n  else if(x >= xa[x_index + 1]) {\n    a->miss_count++;\n    a->cache = gsl_interp_bsearch(xa, x, x_index, len-1);\n  }\n  else {\n    a->hit_count++;\n  }\n  \n  return a->cache;\n}\n#endif /* HAVE_INLINE */\n\n\n__END_DECLS\n\n#endif /* __GSL_INTERP_H__ */\n"
  },
  {
    "path": "gsl/interpolation/gsl_interp2d.h",
    "content": "/* interpolation/gsl_interp2d.h\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_INTERP2D_H__\n#define __GSL_INTERP2D_H__\n\n#include \"gsl_interp.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ntypedef struct {\n    const char* name;\n    unsigned int min_size;\n    void * (*alloc)(size_t xsize, size_t ysize);\n    int    (*init)(void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize);\n    int    (*eval)(const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z);\n    int    (*eval_deriv_x) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_p);\n    int    (*eval_deriv_y) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_p);\n    int    (*eval_deriv_xx) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);\n    int    (*eval_deriv_xy) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);\n    int    (*eval_deriv_yy) (const void *, const double xa[], const double ya[], const double za[], size_t xsize, size_t ysize, double x, double y, gsl_interp_accel*, gsl_interp_accel*, double* z_pp);\n    void   (*free)(void *);\n} gsl_interp2d_type;\n\ntypedef struct {\n    const gsl_interp2d_type * type; /* interpolation type */\n    double xmin;                    /* minimum value of x for which data have been provided */\n    double xmax;                    /* maximum value of x for which data have been provided */\n    double ymin;                    /* minimum value of y for which data have been provided */\n    double ymax;                    /* maximum value of y for which data have been provided */\n    size_t xsize;                   /* number of x values provided */\n    size_t ysize;                   /* number of y values provided */\n    void * state;                   /* internal state object specific to the interpolation type */\n} gsl_interp2d;\n\n/* available types */\nGSL_VAR const gsl_interp2d_type * gsl_interp2d_bilinear;\nGSL_VAR const gsl_interp2d_type * gsl_interp2d_bicubic;\n\ngsl_interp2d * gsl_interp2d_alloc(const gsl_interp2d_type * T, const size_t xsize,\n                                  const size_t ysize);\n\nconst char * gsl_interp2d_name(const gsl_interp2d * interp);\nsize_t gsl_interp2d_min_size(const gsl_interp2d * interp);\nsize_t gsl_interp2d_type_min_size(const gsl_interp2d_type * T);\nint gsl_interp2d_set(const gsl_interp2d * interp, double zarr[],\n                     const size_t i, const size_t j, const double z);\ndouble gsl_interp2d_get(const gsl_interp2d * interp, const double zarr[],\n                        const size_t i, const size_t j);\nsize_t gsl_interp2d_idx(const gsl_interp2d * interp,\n                        const size_t i, const size_t j);\nint gsl_interp2d_init(gsl_interp2d * interp, const double xa[], const double ya[],\n                      const double za[], const size_t xsize, const size_t ysize);\nvoid gsl_interp2d_free(gsl_interp2d * interp);\n\ndouble gsl_interp2d_eval(const gsl_interp2d * interp, const double xarr[],\n                         const double yarr[], const double zarr[], const double x,\n                         const double y, gsl_interp_accel * xa, gsl_interp_accel * ya);\n\ndouble gsl_interp2d_eval_extrap(const gsl_interp2d * interp,\n                                const double xarr[], const double yarr[],\n                                const double zarr[], const double x,\n                                const double y, gsl_interp_accel * xa,\n                                gsl_interp_accel * ya);\n\nint gsl_interp2d_eval_e(const gsl_interp2d * interp, const double xarr[],\n                        const double yarr[], const double zarr[],\n                        const double x, const double y, gsl_interp_accel* xa,\n                        gsl_interp_accel* ya, double * z);\n\nint gsl_interp2d_eval_e_extrap(const gsl_interp2d * interp,\n                               const double xarr[],\n                               const double yarr[],\n                               const double zarr[],\n                               const double x,\n                               const double y,\n                               gsl_interp_accel * xa,\n                               gsl_interp_accel * ya,\n                               double * z);\n\ndouble gsl_interp2d_eval_deriv_x(const gsl_interp2d * interp, const double xarr[],\n                                 const double yarr[], const double zarr[],\n                                 const double x, const double y, gsl_interp_accel * xa,\n                                 gsl_interp_accel * ya);\n\nint gsl_interp2d_eval_deriv_x_e(const gsl_interp2d * interp, const double xarr[],\n                                const double yarr[], const double zarr[],\n                                const double x, const double y,\n                                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);\n\ndouble gsl_interp2d_eval_deriv_y(const gsl_interp2d * interp, const double xarr[],\n                                 const double yarr[], const double zarr[],\n                                 const double x, const double y,\n                                 gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_interp2d_eval_deriv_y_e(const gsl_interp2d * interp, const double xarr[],\n                                const double yarr[], const double zarr[],\n                                const double x, const double y,\n                                gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);\n\ndouble gsl_interp2d_eval_deriv_xx(const gsl_interp2d * interp, const double xarr[],\n                                  const double yarr[], const double zarr[],\n                                  const double x, const double y,\n                                  gsl_interp_accel * xa, gsl_interp_accel * ya);\n\nint gsl_interp2d_eval_deriv_xx_e(const gsl_interp2d * interp, const double xarr[],\n                                 const double yarr[], const double zarr[],\n                                 const double x, const double y,\n                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);\n\ndouble gsl_interp2d_eval_deriv_yy(const gsl_interp2d * interp, const double xarr[],\n                                  const double yarr[], const double zarr[],\n                                  const double x, const double y,\n                                  gsl_interp_accel * xa, gsl_interp_accel * ya);\n\nint gsl_interp2d_eval_deriv_yy_e(const gsl_interp2d * interp, const double xarr[],\n                                 const double yarr[], const double zarr[],\n                                 const double x, const double y,\n                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);\n\ndouble gsl_interp2d_eval_deriv_xy(const gsl_interp2d * interp, const double xarr[],\n                                  const double yarr[], const double zarr[],\n                                  const double x, const double y,\n                                  gsl_interp_accel * xa, gsl_interp_accel * ya);\n\nint gsl_interp2d_eval_deriv_xy_e(const gsl_interp2d * interp, const double xarr[],\n                                 const double yarr[], const double zarr[],\n                                 const double x, const double y,\n                                 gsl_interp_accel * xa, gsl_interp_accel * ya, double * z);\n\n\n__END_DECLS\n\n#endif /* __GSL_INTERP2D_H__ */\n"
  },
  {
    "path": "gsl/interpolation/gsl_spline.h",
    "content": "/* interpolation/gsl_spline.h\n * \n * Copyright (C) 2001, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_SPLINE_H__\n#define __GSL_SPLINE_H__\n#include <stdlib.h>\n#include \"gsl_interp.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* general interpolation object */\ntypedef struct {\n  gsl_interp * interp;\n  double  * x;\n  double  * y;\n  size_t  size;\n} gsl_spline;\n\ngsl_spline *\ngsl_spline_alloc(const gsl_interp_type * T, size_t size);\n     \nint\ngsl_spline_init(gsl_spline * spline, const double xa[], const double ya[], size_t size);\n\nconst char * gsl_spline_name(const gsl_spline * spline);\nunsigned int gsl_spline_min_size(const gsl_spline * spline);\n\n\nint\ngsl_spline_eval_e(const gsl_spline * spline, double x,\n                  gsl_interp_accel * a, double * y);\n\ndouble\ngsl_spline_eval(const gsl_spline * spline, double x, gsl_interp_accel * a);\n\nint\ngsl_spline_eval_deriv_e(const gsl_spline * spline,\n                        double x,\n                        gsl_interp_accel * a,\n                        double * y);\n\ndouble\ngsl_spline_eval_deriv(const gsl_spline * spline,\n                      double x,\n                      gsl_interp_accel * a);\n\nint\ngsl_spline_eval_deriv2_e(const gsl_spline * spline,\n                         double x,\n                         gsl_interp_accel * a,\n                         double * y);\n\ndouble\ngsl_spline_eval_deriv2(const gsl_spline * spline,\n                       double x,\n                       gsl_interp_accel * a);\n\nint\ngsl_spline_eval_integ_e(const gsl_spline * spline,\n                        double a, double b,\n                        gsl_interp_accel * acc,\n                        double * y);\n\ndouble\ngsl_spline_eval_integ(const gsl_spline * spline,\n                      double a, double b,\n                      gsl_interp_accel * acc);\n\nvoid\ngsl_spline_free(gsl_spline * spline);\n\n__END_DECLS\n\n#endif /* __GSL_INTERP_H__ */\n"
  },
  {
    "path": "gsl/interpolation/gsl_spline2d.h",
    "content": "/* interpolation/gsl_spline2d.h\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_SPLINE2D_H__\n#define __GSL_SPLINE2D_H__\n\n#include \"gsl_interp.h\"\n#include \"gsl_interp2d.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/*\n * A 2D interpolation object which stores the arrays defining the function.\n * In all other respects, this is just like a gsl_interp2d object.\n */\ntypedef struct\n{\n  gsl_interp2d interp_object; /* low-level interpolation object */\n  double * xarr;              /* x data array */\n  double * yarr;              /* y data array */\n  double * zarr;              /* z data array */\n} gsl_spline2d;\n\ngsl_spline2d * gsl_spline2d_alloc(const gsl_interp2d_type * T, size_t xsize, size_t ysize);\n\nint gsl_spline2d_init(gsl_spline2d * interp, const double xa[],\n                      const double ya[], const double za[],\n                      size_t xsize, size_t ysize);\n\nvoid gsl_spline2d_free(gsl_spline2d * interp);\n\ndouble gsl_spline2d_eval(const gsl_spline2d * interp, const double x,\n                         const double y, gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_e(const gsl_spline2d * interp, const double x,\n                        const double y, gsl_interp_accel* xa, gsl_interp_accel* ya,\n                        double * z);\n\ndouble gsl_spline2d_eval_deriv_x(const gsl_spline2d * interp, const double x,\n                                 const double y, gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_deriv_x_e(const gsl_spline2d * interp, const double x,\n                                const double y, gsl_interp_accel* xa,\n                                gsl_interp_accel* ya, double * z);\n\ndouble gsl_spline2d_eval_deriv_y(const gsl_spline2d * interp, const double x,\n                                 const double y, gsl_interp_accel* xa,\n                                 gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_deriv_y_e(const gsl_spline2d * interp, const double x,\n                                const double y, gsl_interp_accel* xa,\n                                gsl_interp_accel* ya, double * z);\n\ndouble gsl_spline2d_eval_deriv_xx(const gsl_spline2d * interp, const double x,\n                                  const double y, gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_deriv_xx_e(const gsl_spline2d * interp, const double x,\n                                 const double y, gsl_interp_accel* xa,\n                                 gsl_interp_accel* ya, double * z);\n\ndouble gsl_spline2d_eval_deriv_yy(const gsl_spline2d * interp, const double x,\n                                  const double y, gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_deriv_yy_e(const gsl_spline2d * interp, const double x,\n                                 const double y, gsl_interp_accel* xa,\n                                 gsl_interp_accel* ya, double * z);\n\ndouble gsl_spline2d_eval_deriv_xy(const gsl_spline2d * interp, const double x,\n                                  const double y, gsl_interp_accel* xa, gsl_interp_accel* ya);\n\nint gsl_spline2d_eval_deriv_xy_e(const gsl_spline2d * interp, const double x,\n                                 const double y, gsl_interp_accel* xa,\n                                 gsl_interp_accel* ya, double * z);\n\nsize_t gsl_spline2d_min_size(const gsl_spline2d * interp);\n\nconst char * gsl_spline2d_name(const gsl_spline2d * interp);\n\nint gsl_spline2d_set(const gsl_spline2d * interp, double zarr[],\n                     const size_t i, const size_t j, const double z);\ndouble gsl_spline2d_get(const gsl_spline2d * interp, const double zarr[],\n                        const size_t i, const size_t j);\n\n__END_DECLS\n\n#endif /* __GSL_SPLINE2D_H__ */\n"
  },
  {
    "path": "gsl/interpolation/inline.c",
    "content": "/* interpolation/bsearch.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include <stdlib.h>\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_interp.h\"\n\n"
  },
  {
    "path": "gsl/interpolation/integ_eval.h",
    "content": "/* interpolation/integ_eval_macro.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* function for doing the spline integral evaluation\n   which is common to both the cspline and akima methods\n */\n\nstatic inline double\ninteg_eval (double ai, double bi, double ci, double di, double xi, double a,\n            double b)\n{\n  const double r1 = a - xi;\n  const double r2 = b - xi;\n  const double r12 = r1 + r2;\n  const double bterm = 0.5 * bi * r12;\n  const double cterm = (1.0 / 3.0) * ci * (r1 * r1 + r2 * r2 + r1 * r2);\n  const double dterm = 0.25 * di * r12 * (r1 * r1 + r2 * r2);\n\n  return (b - a) * (ai + bterm + cterm + dterm);\n}\n"
  },
  {
    "path": "gsl/interpolation/interp.c",
    "content": "/* interpolation/interp.c\n * \n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_math.h\"\n#include \"gsl_interp.h\"\n\n#define DISCARD_STATUS(s) if ((s) != GSL_SUCCESS) { GSL_ERROR_VAL(\"interpolation error\", (s),  GSL_NAN); }\n\ngsl_interp *\ngsl_interp_alloc (const gsl_interp_type * T, size_t size)\n{\n  gsl_interp * interp;\n\n  if (size < T->min_size)\n    {\n      GSL_ERROR_NULL (\"insufficient number of points for interpolation type\",\n                      GSL_EINVAL);\n    }\n\n  interp = (gsl_interp *) malloc (sizeof(gsl_interp));\n  \n  if (interp == NULL)\n    {\n      GSL_ERROR_NULL (\"failed to allocate space for interp struct\", \n                      GSL_ENOMEM);\n    }\n  \n  interp->type = T;\n  interp->size = size;\n\n  if (interp->type->alloc == NULL)\n    {\n      interp->state = NULL;\n      return interp;\n    }\n\n  interp->state = interp->type->alloc(size);\n  \n  if (interp->state == NULL)\n    {\n      free (interp);          \n      GSL_ERROR_NULL (\"failed to allocate space for interp state\", GSL_ENOMEM);\n    };\n    \n  return interp;\n}\n\nint\ngsl_interp_init (gsl_interp * interp, const double x_array[], const double y_array[], size_t size)\n{\n  size_t i;\n\n  if (size != interp->size)\n    {\n      GSL_ERROR (\"data must match size of interpolation object\", GSL_EINVAL);\n    }\n\n  for (i = 1; i < size; i++) \n    {\n      if (!(x_array[i-1] < x_array[i])) \n        {\n          GSL_ERROR (\"x values must be strictly increasing\", GSL_EINVAL);\n        }\n    }\n\n  interp->xmin = x_array[0];\n  interp->xmax = x_array[size - 1];\n\n  {\n    int status = interp->type->init(interp->state, x_array, y_array, size);\n    return status;\n  }\n}\n\nconst char *\ngsl_interp_name(const gsl_interp * interp)\n{\n  return interp->type->name;\n}\n\nunsigned int\ngsl_interp_min_size(const gsl_interp * interp)\n{\n  return interp->type->min_size;\n}\n\nunsigned int\ngsl_interp_type_min_size(const gsl_interp_type * T)\n{\n  return T->min_size;\n}\n\nvoid\ngsl_interp_free (gsl_interp * interp)\n{\n  RETURN_IF_NULL (interp);\n\n  if (interp->type->free)\n    interp->type->free (interp->state);\n  free (interp);\n}\n\n\n\nint\ngsl_interp_eval_e (const gsl_interp * interp,\n                   const double xa[], const double ya[], double x,\n                   gsl_interp_accel * a, double *y)\n{\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      *y = GSL_NAN;\n      return GSL_EDOM;\n    }\n\n  return interp->type->eval (interp->state, xa, ya, interp->size, x, a, y);\n}\n\ndouble\ngsl_interp_eval (const gsl_interp * interp,\n                 const double xa[], const double ya[], double x,\n                 gsl_interp_accel * a)\n{\n  double y;\n  int status;\n\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      GSL_ERROR_VAL(\"interpolation error\", GSL_EDOM, GSL_NAN);\n    }\n\n  status = interp->type->eval (interp->state, xa, ya, interp->size, x, a, &y);\n\n  DISCARD_STATUS(status);\n\n  return y;\n}\n\n\nint\ngsl_interp_eval_deriv_e (const gsl_interp * interp,\n                         const double xa[], const double ya[], double x,\n                         gsl_interp_accel * a,\n                         double *dydx)\n{\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      *dydx = GSL_NAN;\n      return GSL_EDOM;\n    }\n\n  return interp->type->eval_deriv (interp->state, xa, ya, interp->size, x, a, dydx);\n}\n\ndouble\ngsl_interp_eval_deriv (const gsl_interp * interp,\n                       const double xa[], const double ya[], double x,\n                       gsl_interp_accel * a)\n{\n  double dydx;\n  int status;\n\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      GSL_ERROR_VAL(\"interpolation error\", GSL_EDOM, GSL_NAN);\n    }\n\n  status = interp->type->eval_deriv (interp->state, xa, ya, interp->size, x, a, &dydx);\n\n  DISCARD_STATUS(status);\n\n  return dydx;\n}\n\n\nint\ngsl_interp_eval_deriv2_e (const gsl_interp * interp,\n                          const double xa[], const double ya[], double x,\n                          gsl_interp_accel * a,\n                          double * d2)\n{\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      *d2 = GSL_NAN;\n      return GSL_EDOM;\n    }\n\n  return interp->type->eval_deriv2 (interp->state, xa, ya, interp->size, x, a, d2);\n}\n\ndouble\ngsl_interp_eval_deriv2 (const gsl_interp * interp,\n                        const double xa[], const double ya[], double x,\n                        gsl_interp_accel * a)\n{\n  double d2;\n  int status;\n\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      GSL_ERROR_VAL(\"interpolation error\", GSL_EDOM, GSL_NAN);\n    }\n\n  status = interp->type->eval_deriv2 (interp->state, xa, ya, interp->size, x, a, &d2);\n\n  DISCARD_STATUS(status);\n\n  return d2;\n}\n\n\nint\ngsl_interp_eval_integ_e (const gsl_interp * interp,\n                         const double xa[], const double ya[],\n                         double a, double b,\n                         gsl_interp_accel * acc,\n                         double * result)\n{\n  if (a > b || a < interp->xmin || b > interp->xmax)\n    {\n      *result = GSL_NAN;\n      return GSL_EDOM;\n    }\n  else if(a == b)\n    {\n      *result = 0.0;\n      return GSL_SUCCESS;\n    }\n\n  return interp->type->eval_integ (interp->state, xa, ya, interp->size, acc, a, b, result);\n}\n\n\ndouble\ngsl_interp_eval_integ (const gsl_interp * interp,\n                       const double xa[], const double ya[],\n                       double a, double b,\n                       gsl_interp_accel * acc)\n{\n  double result;\n  int status;\n\n  if (a > b || a < interp->xmin || b > interp->xmax)\n    {\n      GSL_ERROR_VAL(\"interpolation error\", GSL_EDOM, GSL_NAN);\n    }\n  else if(a == b)\n    {\n      return 0.0;\n    }\n\n  status = interp->type->eval_integ (interp->state, xa, ya, interp->size, acc, a, b, &result);\n\n  DISCARD_STATUS(status);\n\n  return result;\n}\n\n\n"
  },
  {
    "path": "gsl/interpolation/interp2d.c",
    "content": "/* interpolation/interp2d.c\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_math.h\"\n#include \"gsl_interp.h\"\n#include \"gsl_interp2d.h\"\n\n/**\n * Triggers a GSL error if the argument is not equal to GSL_SUCCESS.\n * If the argument is GSL_SUCCESS, this does nothing.\n */\n#define DISCARD_STATUS(s) if ((s) != GSL_SUCCESS) { GSL_ERROR_VAL(\"interpolation error\", (s),  GSL_NAN); }\n\n#define IDX2D(i, j, w) ((j) * ((w)->xsize) + (i))\n\ngsl_interp2d *\ngsl_interp2d_alloc(const gsl_interp2d_type * T, const size_t xsize,\n                   const size_t ysize)\n{\n  gsl_interp2d * interp;\n\n  if (xsize < T->min_size || ysize < T->min_size)\n    {\n      GSL_ERROR_NULL (\"insufficient number of points for interpolation type\",\n                      GSL_EINVAL);\n    }\n\n  interp = (gsl_interp2d *) calloc(1, sizeof(gsl_interp2d));\n  if (interp == NULL)\n    {\n      GSL_ERROR_NULL (\"failed to allocate space for gsl_interp2d struct\",\n                      GSL_ENOMEM);\n    }\n\n  interp->type = T;\n  interp->xsize = xsize;\n  interp->ysize = ysize;\n\n  if (interp->type->alloc == NULL)\n    {\n      interp->state = NULL;\n      return interp;\n    }\n\n  interp->state = interp->type->alloc(xsize, ysize);\n  if (interp->state == NULL)\n    {\n      free(interp);\n      GSL_ERROR_NULL (\"failed to allocate space for gsl_interp2d state\",\n                      GSL_ENOMEM);\n    }\n\n  return interp;\n} /* gsl_interp2d_alloc() */\n\nvoid\ngsl_interp2d_free (gsl_interp2d * interp)\n{\n  RETURN_IF_NULL(interp);\n\n  if (interp->type->free)\n    interp->type->free(interp->state);\n\n  free(interp);\n} /* gsl_interp2d_free() */\n\nint\ngsl_interp2d_init (gsl_interp2d * interp, const double xarr[], const double yarr[],\n                   const double zarr[], const size_t xsize, const size_t ysize)\n{\n  size_t i;\n\n  if (xsize != interp->xsize || ysize != interp->ysize)\n    {\n      GSL_ERROR(\"data must match size of interpolation object\", GSL_EINVAL);\n    }\n\n  for (i = 1; i < xsize; i++)\n    {\n      if (xarr[i-1] >= xarr[i])\n        {\n          GSL_ERROR(\"x values must be strictly increasing\", GSL_EINVAL);\n        }\n    }\n\n  for (i = 1; i < ysize; i++)\n    {\n      if (yarr[i-1] >= yarr[i])\n        {\n          GSL_ERROR(\"y values must be strictly increasing\", GSL_EINVAL);\n        }\n    }\n\n  interp->xmin = xarr[0];\n  interp->xmax = xarr[xsize - 1];\n  interp->ymin = yarr[0];\n  interp->ymax = yarr[ysize - 1];\n\n  {\n    int status = interp->type->init(interp->state, xarr, yarr, zarr,\n                                    xsize, ysize);\n    return status;\n  }\n} /* gsl_interp2d_init() */\n\n/*\n * A wrapper function that checks boundary conditions, calls an evaluator\n * which implements the actual calculation of the function value or \n * derivative etc., and checks the return status.\n */\nstatic int\ninterp2d_eval(int (*evaluator)(const void *, const double xa[], const double ya[],\n                               const double za[], size_t xsize, size_t ysize,\n                               double x, double y, gsl_interp_accel *,\n                               gsl_interp_accel *, double * z),\n              const gsl_interp2d * interp, const double xarr[],\n              const double yarr[], const double zarr[],\n              const double x, const double y,\n              gsl_interp_accel * xa, gsl_interp_accel * ya,\n              double * result)\n{\n  if (x < interp->xmin || x > interp->xmax)\n    {\n      GSL_ERROR (\"interpolation x value out of range\", GSL_EDOM);\n    }\n  else if (y < interp->ymin || y > interp->ymax)\n    {\n      GSL_ERROR (\"interpolation y value out of range\", GSL_EDOM);\n    }\n\n  return evaluator(interp->state, xarr, yarr, zarr,\n                   interp->xsize, interp->ysize,\n                   x, y, xa, ya, result);\n}\n\n/*\n * Another wrapper function that serves as a drop-in replacement for\n * interp2d_eval but does not check the bounds. This can be used\n * for extrapolation.\n */\nstatic int\ninterp2d_eval_extrap(int (*evaluator)(const void *, const double xa[],\n                                      const double ya[], const double za[],\n                                      size_t xsize, size_t ysize,\n                                      double x, double y,\n                                      gsl_interp_accel *,\n                                      gsl_interp_accel *, double * z),\n                     const gsl_interp2d * interp, const double xarr[],\n                     const double yarr[], const double zarr[],\n                     const double x, const double y,\n                     gsl_interp_accel * xa, gsl_interp_accel * ya,\n                     double * result)\n{\n  return evaluator(interp->state, xarr, yarr, zarr,\n                   interp->xsize, interp->ysize, x, y, xa, ya, result);\n}\n\ndouble\ngsl_interp2d_eval (const gsl_interp2d * interp, const double xarr[],\n                   const double yarr[], const double zarr[],\n                   const double x, const double y,\n                   gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n} /* gsl_interp2d_eval() */\n\ndouble\ngsl_interp2d_eval_extrap (const gsl_interp2d * interp,\n                          const double xarr[],\n                          const double yarr[],\n                          const double zarr[],\n                          const double x,\n                          const double y,\n                          gsl_interp_accel * xa,\n                          gsl_interp_accel * ya)\n{\n  double z;\n  int status =\n    interp2d_eval_extrap(interp->type->eval, interp,\n                         xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_e (const gsl_interp2d * interp, const double xarr[],\n                     const double yarr[], const double zarr[],\n                     const double x, const double y,\n                     gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n} /* gsl_interp2d_eval_e() */\n\nint\ngsl_interp2d_eval_e_extrap (const gsl_interp2d * interp,\n                            const double xarr[], const double yarr[],\n                            const double zarr[], const double x,\n                            const double y, gsl_interp_accel * xa,\n                            gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval_extrap(interp->type->eval, interp,\n                              xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_interp2d_eval_deriv_x (const gsl_interp2d * interp, const double xarr[],\n                           const double yarr[], const double zarr[],\n                           const double x, const double y,\n                           gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_deriv_x_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_deriv_x_e (const gsl_interp2d * interp, const double xarr[],\n                             const double yarr[], const double zarr[],\n                             const double x, const double y,\n                             gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval_deriv_x, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_interp2d_eval_deriv_y (const gsl_interp2d * interp, const double xarr[],\n                           const double yarr[], const double zarr[],\n                           const double x, const double y,\n                           gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_deriv_y_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_deriv_y_e (const gsl_interp2d * interp, const double xarr[],\n                             const double yarr[], const double zarr[],\n                             const double x, const double y,\n                             gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval_deriv_y, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_interp2d_eval_deriv_xx (const gsl_interp2d * interp, const double xarr[],\n                            const double yarr[], const double zarr[],\n                            const double x, const double y,\n                            gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_deriv_xx_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_deriv_xx_e (const gsl_interp2d * interp, const double xarr[],\n                              const double yarr[], const double zarr[],\n                              const double x, const double y,\n                              gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval_deriv_xx, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_interp2d_eval_deriv_yy (const gsl_interp2d * interp, const double xarr[],\n                            const double yarr[], const double zarr[],\n                            const double x, const double y,\n                            gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_deriv_yy_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_deriv_yy_e (const gsl_interp2d * interp, const double xarr[],\n                              const double yarr[], const double zarr[],\n                              const double x, const double y,\n                              gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval_deriv_yy, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_interp2d_eval_deriv_xy (const gsl_interp2d * interp, const double xarr[],\n                            const double yarr[], const double zarr[],\n                            const double x, const double y,\n                            gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  double z;\n  int status = gsl_interp2d_eval_deriv_xy_e(interp, xarr, yarr, zarr, x, y, xa, ya, &z);\n  DISCARD_STATUS(status)\n  return z;\n}\n\nint\ngsl_interp2d_eval_deriv_xy_e (const gsl_interp2d * interp, const double xarr[],\n                              const double yarr[], const double zarr[],\n                              const double x, const double y,\n                              gsl_interp_accel * xa, gsl_interp_accel * ya, double * z)\n{\n  return interp2d_eval(interp->type->eval_deriv_xy, interp,\n                       xarr, yarr, zarr, x, y, xa, ya, z);\n}\n\nsize_t\ngsl_interp2d_type_min_size(const gsl_interp2d_type * T)\n{\n  return T->min_size;\n}\n\nsize_t\ngsl_interp2d_min_size(const gsl_interp2d * interp)\n{\n  return interp->type->min_size;\n}\n\nconst char *\ngsl_interp2d_name(const gsl_interp2d * interp)\n{\n  return interp->type->name;\n}\n\nsize_t\ngsl_interp2d_idx(const gsl_interp2d * interp,\n                 const size_t i, const size_t j)\n{\n  if (i >= interp->xsize)\n    {\n      GSL_ERROR_VAL (\"x index out of range\", GSL_ERANGE, 0);\n    }\n  else if (j >= interp->ysize)\n    {\n      GSL_ERROR_VAL (\"y index out of range\", GSL_ERANGE, 0);\n    }\n  else\n    {\n      return IDX2D(i, j, interp);\n    }\n} /* gsl_interp2d_idx() */\n\nint\ngsl_interp2d_set(const gsl_interp2d * interp, double zarr[],\n                 const size_t i, const size_t j, const double z)\n{\n  if (i >= interp->xsize)\n    {\n      GSL_ERROR (\"x index out of range\", GSL_ERANGE);\n    }\n  else if (j >= interp->ysize)\n    {\n      GSL_ERROR (\"y index out of range\", GSL_ERANGE);\n    }\n  else\n    {\n      zarr[IDX2D(i, j, interp)] = z;\n      return GSL_SUCCESS;\n    }\n} /* gsl_interp2d_set() */\n\ndouble\ngsl_interp2d_get(const gsl_interp2d * interp, const double zarr[],\n                 const size_t i, const size_t j)\n{\n  if (i >= interp->xsize)\n    {\n      GSL_ERROR_VAL (\"x index out of range\", GSL_ERANGE, 0);\n    }\n  else if (j >= interp->ysize)\n    {\n      GSL_ERROR_VAL (\"y index out of range\", GSL_ERANGE, 0);\n    }\n  else\n    {\n      return zarr[IDX2D(i, j, interp)];\n    }\n} /* gsl_interp2d_get() */\n\n#undef IDX2D\n"
  },
  {
    "path": "gsl/interpolation/linear.c",
    "content": "/* interpolation/linear.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_interp.h\"\n\nstatic int\nlinear_init (__attribute__ ((unused)) void * vstate,\n\t\t\t __attribute__ ((unused)) const double x_array[],\n\t\t\t __attribute__ ((unused)) const double y_array[],\n\t\t\t __attribute__ ((unused)) size_t size)\n{\n  return GSL_SUCCESS;\n}\n\nstatic\nint\nlinear_eval (__attribute__ ((unused)) const void * vstate,\n             const double x_array[], const double y_array[], size_t size,\n             double x,\n             gsl_interp_accel * a,\n             double *y)\n{\n  double x_lo, x_hi;\n  double y_lo, y_hi;\n  double dx;\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  x_lo = x_array[index];\n  x_hi = x_array[index + 1];\n  y_lo = y_array[index];\n  y_hi = y_array[index + 1];\n  dx = x_hi - x_lo;\n  if (dx > 0.0)\n    {\n      *y = y_lo + (x - x_lo) / dx * (y_hi - y_lo);\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      *y = 0.0;\n      return GSL_EINVAL;\n    }\n}\n\n\nstatic\nint\nlinear_eval_deriv (__attribute__ ((unused)) const void * vstate,\n                   const double x_array[], const double y_array[], size_t size,\n                   double x,\n                   gsl_interp_accel * a,\n                   double *dydx)\n{\n  double x_lo, x_hi;\n  double y_lo, y_hi;\n  double dx;\n  double dy;\n  size_t index;\n  \n  if (a != 0)\n    {\n      index = gsl_interp_accel_find (a, x_array, size, x);\n    }\n  else\n    {\n      index = gsl_interp_bsearch (x_array, x, 0, size - 1);\n    }\n  \n  /* evaluate */\n  x_lo = x_array[index];\n  x_hi = x_array[index + 1];\n  y_lo = y_array[index];\n  y_hi = y_array[index + 1];\n  dx = x_hi - x_lo;\n  dy = y_hi - y_lo;\n  if (dx > 0.0)\n    {\n      *dydx = dy / dx;;\n      return GSL_SUCCESS;\n    }\n  else\n    {\n      *dydx = 0.0;\n      return GSL_EINVAL;\n    }\n}\n\n\nstatic\nint\nlinear_eval_deriv2 (__attribute__ ((unused)) const void * vstate,\n\t\t\t\t\t__attribute__ ((unused)) const double x_array[], __attribute__ ((unused)) const double y_array[], __attribute__ ((unused)) size_t size,\n\t\t\t\t\t__attribute__ ((unused)) double x,\n\t\t\t\t\t__attribute__ ((unused)) gsl_interp_accel * a,\n                    double *y_pp)\n{\n  *y_pp = 0.0;\n\n  return GSL_SUCCESS;\n}\n\n\nstatic\nint\nlinear_eval_integ (__attribute__ ((unused)) const void * vstate,\n                   const double x_array[], const double y_array[], size_t size,\n                   gsl_interp_accel * acc,\n                   double a, double b,\n                   double * result)\n{\n  size_t i, index_a, index_b;\n  \n  if (acc != 0)\n    {\n      index_a = gsl_interp_accel_find (acc, x_array, size, a);\n      index_b = gsl_interp_accel_find (acc, x_array, size, b);\n    }\n  else\n    {\n      index_a = gsl_interp_bsearch (x_array, a, 0, size - 1);\n      index_b = gsl_interp_bsearch (x_array, b, 0, size - 1);\n    }\n  \n    /* endpoints span more than one interval */\n\n  *result = 0.0;\n  \n  /* interior intervals */\n  for(i=index_a; i<=index_b; i++) {\n    const double x_hi = x_array[i + 1];\n    const double x_lo = x_array[i];\n    const double y_lo = y_array[i];\n    const double y_hi = y_array[i + 1];\n    const double dx = x_hi - x_lo;\n\n    if(dx != 0.0) {\n      if (i == index_a || i == index_b)\n        {\n          double x1 = (i == index_a) ? a : x_lo;\n          double x2 = (i == index_b) ? b : x_hi;\n          const double D = (y_hi-y_lo)/dx;\n          *result += (x2-x1) * (y_lo + 0.5*D*((x2-x_lo)+(x1-x_lo)));\n        }\n      else\n        {\n          *result += 0.5 * dx * (y_lo + y_hi);\n        }\n    }\n  }\n    \n  return GSL_SUCCESS;\n}\n\nstatic const gsl_interp_type linear_type = \n{\n  \"linear\", \n  2,\n  NULL, /* alloc, not applicable */\n  &linear_init,\n  &linear_eval,\n  &linear_eval_deriv,\n  &linear_eval_deriv2,\n  &linear_eval_integ,\n  NULL, /* free, not applicable */\n};\n\nconst gsl_interp_type * gsl_interp_linear = &linear_type;\n"
  },
  {
    "path": "gsl/interpolation/spline.c",
    "content": "/* interpolation/spline.c\n * \n * Copyright (C) 2001, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <string.h>\n#include \"gsl_errno.h\"\n#include \"gsl_interp.h\"\n#include \"gsl_spline.h\"\n\ngsl_spline *\ngsl_spline_alloc (const gsl_interp_type * T, size_t size)\n{\n  gsl_spline * spline = (gsl_spline *) malloc (sizeof(gsl_spline));\n  \n  if (spline == NULL)\n    {\n      GSL_ERROR_NULL (\"failed to allocate space for spline struct\", \n                      GSL_ENOMEM);\n    }\n  \n  spline->interp = gsl_interp_alloc (T, size);\n  \n  if (spline->interp == NULL)\n    {\n      free (spline);          \n      GSL_ERROR_NULL (\"failed to allocate space for interp\", GSL_ENOMEM);\n    };\n    \n  spline->x = (double *) malloc (size * sizeof(double));\n\n  if (spline->x == NULL)\n    {\n      gsl_interp_free(spline->interp);\n      free(spline);\n      GSL_ERROR_NULL (\"failed to allocate space for x\", GSL_ENOMEM);\n    }\n\n  spline->y = (double *) malloc (size * sizeof(double));\n\n  if (spline->y == NULL)\n    {\n      free(spline->x);\n      gsl_interp_free(spline->interp);\n      free(spline);\n      GSL_ERROR_NULL (\"failed to allocate space for y\", GSL_ENOMEM);\n    }\n  \n  spline->size = size;\n\n  return spline;\n}\n\nint\ngsl_spline_init (gsl_spline * spline, const double x_array[], const double y_array[], size_t size)\n{\n  if (size != spline->size)\n    {\n      GSL_ERROR (\"data must match size of spline object\", GSL_EINVAL);\n    }\n  \n  memcpy (spline->x, x_array, size * sizeof(double));\n  memcpy (spline->y, y_array, size * sizeof(double));\n\n  {\n    int status = gsl_interp_init (spline->interp, x_array, y_array, size);\n    return status;\n  }\n}\n\nconst char *\ngsl_spline_name(const gsl_spline * spline)\n{\n  return gsl_interp_name(spline->interp);\n}\n\nunsigned int\ngsl_spline_min_size(const gsl_spline * spline)\n{\n  return gsl_interp_min_size(spline->interp);\n}\n\nvoid\ngsl_spline_free (gsl_spline * spline)\n{\n  RETURN_IF_NULL (spline);\n  gsl_interp_free (spline->interp);\n  free (spline->x);\n  free (spline->y);\n  free (spline);\n}\n\nint\ngsl_spline_eval_e (const gsl_spline * spline, \n                   double x,\n                   gsl_interp_accel * a, double *y)\n{\n  return gsl_interp_eval_e (spline->interp, \n                            spline->x, spline->y,\n                            x, a, y);\n}\n\ndouble\ngsl_spline_eval (const gsl_spline * spline,\n                 double x,\n                 gsl_interp_accel * a)\n{\n  return gsl_interp_eval (spline->interp, \n                          spline->x, spline->y,\n                          x, a);\n}\n\n\nint\ngsl_spline_eval_deriv_e (const gsl_spline * spline,\n                         double x,\n                         gsl_interp_accel * a,\n                         double *dydx)\n{\n  return gsl_interp_eval_deriv_e (spline->interp, \n                                  spline->x, spline->y,\n                                  x, a, dydx);\n}\n\ndouble\ngsl_spline_eval_deriv (const gsl_spline * spline,\n                       double x,\n                       gsl_interp_accel * a)\n{\n  return gsl_interp_eval_deriv (spline->interp, \n                                spline->x, spline->y,\n                                x, a);\n}\n\n\nint\ngsl_spline_eval_deriv2_e (const gsl_spline * spline,\n                          double x,\n                          gsl_interp_accel * a,\n                          double * d2)\n{\n  return gsl_interp_eval_deriv2_e (spline->interp, \n                                   spline->x, spline->y,\n                                   x, a, d2);\n}\n\ndouble\ngsl_spline_eval_deriv2 (const gsl_spline * spline,\n                        double x,\n                        gsl_interp_accel * a)\n{\n  return gsl_interp_eval_deriv2 (spline->interp, \n                                 spline->x, spline->y,\n                                 x, a);\n}\n\n\nint\ngsl_spline_eval_integ_e (const gsl_spline * spline,\n                         double a, double b,\n                         gsl_interp_accel * acc,\n                         double * result)\n{\n  return gsl_interp_eval_integ_e (spline->interp, \n                                  spline->x, spline->y,\n                                  a, b, acc, result);\n}\n\n\ndouble\ngsl_spline_eval_integ (const gsl_spline * spline,\n                       double a, double b,\n                       gsl_interp_accel * acc)\n{\n  return gsl_interp_eval_integ (spline->interp, \n                                spline->x, spline->y,\n                                a, b, acc);\n}\n\n"
  },
  {
    "path": "gsl/interpolation/spline2d.c",
    "content": "/* interpolation/spline2d.c\n * \n * Copyright 2012 David Zaslavsky\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <string.h>\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_math.h\"\n#include \"gsl_interp.h\"\n#include \"gsl_interp2d.h\"\n#include \"gsl_spline2d.h\"\n\ngsl_spline2d *\ngsl_spline2d_alloc(const gsl_interp2d_type * T, size_t xsize, size_t ysize)\n{\n  double * array_mem;\n  gsl_spline2d * interp;\n\n  if (xsize < T->min_size || ysize < T->min_size)\n    {\n      GSL_ERROR_NULL(\"insufficient number of points for interpolation type\", GSL_EINVAL);\n    }\n\n  interp = calloc(1, sizeof(gsl_spline2d));\n  if (interp == NULL)\n    {\n      GSL_ERROR_NULL(\"failed to allocate space for gsl_spline2d struct\", GSL_ENOMEM);\n    }\n\n  interp->interp_object.type = T;\n  interp->interp_object.xsize = xsize;\n  interp->interp_object.ysize = ysize;\n  if (interp->interp_object.type->alloc == NULL)\n    {\n      interp->interp_object.state = NULL;\n    }\n  else\n    {\n      interp->interp_object.state = interp->interp_object.type->alloc(xsize, ysize);\n      if (interp->interp_object.state == NULL)\n        {\n          gsl_spline2d_free(interp);\n          GSL_ERROR_NULL(\"failed to allocate space for gsl_spline2d state\", GSL_ENOMEM);\n        }\n    }\n\n  /*\n   * Use one contiguous block of memory for all three data arrays.\n   * That way the code fails immediately if there isn't sufficient space for everything,\n   * rather than allocating one or two and then having to free them.\n   */\n  array_mem = (double *)calloc(xsize + ysize + xsize * ysize, sizeof(double));\n  if (array_mem == NULL)\n    {\n      gsl_spline2d_free(interp);\n      GSL_ERROR_NULL(\"failed to allocate space for data arrays\", GSL_ENOMEM);\n    }\n\n  interp->xarr = array_mem;\n  interp->yarr = array_mem + xsize;\n  interp->zarr = array_mem + xsize + ysize;\n\n  return interp;\n} /* gsl_spline2d_alloc() */\n\nint\ngsl_spline2d_init(gsl_spline2d * interp, const double xarr[],\n                  const double yarr[], const double zarr[],\n                  size_t xsize, size_t ysize)\n{\n  int status = gsl_interp2d_init(&(interp->interp_object), xarr, yarr, zarr, xsize, ysize);\n\n  memcpy(interp->xarr, xarr, xsize * sizeof(double));\n  memcpy(interp->yarr, yarr, ysize * sizeof(double));\n  memcpy(interp->zarr, zarr, xsize * ysize * sizeof(double));\n\n  return status;\n} /* gsl_spline2d_init() */\n\nvoid\ngsl_spline2d_free(gsl_spline2d * interp)\n{\n  RETURN_IF_NULL(interp);\n\n  if (interp->interp_object.type->free)\n    interp->interp_object.type->free(interp->interp_object.state);\n\n  /*\n   * interp->xarr points to the beginning of one contiguous block of memory\n   * that holds interp->xarr, interp->yarr, and interp->zarr. So it all gets\n   * freed with one call. cf. gsl_spline2d_alloc() implementation\n   */\n  if (interp->xarr)\n    free(interp->xarr);\n\n  free(interp);\n} /* gsl_spline2d_free() */\n\ndouble\ngsl_spline2d_eval(const gsl_spline2d * interp, const double x,\n                  const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval(&(interp->interp_object), interp->xarr, interp->yarr,\n                           interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_e(const gsl_spline2d * interp, const double x,\n                    const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                    double * z)\n{\n  return gsl_interp2d_eval_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                             interp->zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_spline2d_eval_deriv_x(const gsl_spline2d * interp, const double x,\n                          const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval_deriv_x(&(interp->interp_object), interp->xarr, interp->yarr,\n                                   interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_deriv_x_e(const gsl_spline2d * interp, const double x,\n                            const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                            double * z)\n{\n  return gsl_interp2d_eval_deriv_x_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                                     interp->zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_spline2d_eval_deriv_y(const gsl_spline2d * interp, const double x,\n                          const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval_deriv_y(&(interp->interp_object), interp->xarr, interp->yarr,\n                                   interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_deriv_y_e(const gsl_spline2d * interp, const double x,\n                            const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                            double * z)\n{\n  return gsl_interp2d_eval_deriv_y_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                                     interp->zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_spline2d_eval_deriv_xx(const gsl_spline2d * interp, const double x,\n                           const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval_deriv_xx(&(interp->interp_object), interp->xarr, interp->yarr,\n                                    interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_deriv_xx_e(const gsl_spline2d * interp, const double x,\n                             const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                             double * z)\n{\n  return gsl_interp2d_eval_deriv_xx_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                                      interp->zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_spline2d_eval_deriv_yy(const gsl_spline2d * interp, const double x,\n                           const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval_deriv_yy(&(interp->interp_object), interp->xarr, interp->yarr,\n                                    interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_deriv_yy_e(const gsl_spline2d * interp, const double x,\n                             const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                             double * z)\n{\n  return gsl_interp2d_eval_deriv_yy_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                                      interp->zarr, x, y, xa, ya, z);\n}\n\ndouble\ngsl_spline2d_eval_deriv_xy(const gsl_spline2d * interp, const double x,\n                           const double y, gsl_interp_accel * xa, gsl_interp_accel * ya)\n{\n  return gsl_interp2d_eval_deriv_xy(&(interp->interp_object), interp->xarr, interp->yarr,\n                                    interp->zarr, x, y, xa, ya);\n}\n\nint\ngsl_spline2d_eval_deriv_xy_e(const gsl_spline2d * interp, const double x,\n                             const double y, gsl_interp_accel * xa, gsl_interp_accel * ya,\n                             double * z)\n{\n  return gsl_interp2d_eval_deriv_xy_e(&(interp->interp_object), interp->xarr, interp->yarr,\n                                      interp->zarr, x, y, xa, ya, z);\n}\n\nsize_t\ngsl_spline2d_min_size(const gsl_spline2d * interp)\n{\n  return gsl_interp2d_min_size(&(interp->interp_object));\n}\n\nconst char *\ngsl_spline2d_name(const gsl_spline2d * interp)\n{\n  return gsl_interp2d_name(&(interp->interp_object));\n}\n\nint\ngsl_spline2d_set(const gsl_spline2d * interp, double zarr[],\n                 const size_t i, const size_t j, const double z)\n{\n  return gsl_interp2d_set(&(interp->interp_object), zarr, i, j, z);\n} /* gsl_spline2d_set() */\n\ndouble\ngsl_spline2d_get(const gsl_spline2d * interp, const double zarr[],\n                 const size_t i, const size_t j)\n{\n  return gsl_interp2d_get(&(interp->interp_object), zarr, i, j);\n} /* gsl_spline2d_get() */\n"
  },
  {
    "path": "gsl/linalg/cholesky.c",
    "content": "/* Cholesky Decomposition\n *\n * Copyright (C) 2000 Thomas Walter\n * Copyright (C) 2000, 2001, 2002, 2003, 2005, 2007 Brian Gough, Gerard Jungman\n * Copyright (C) 2016 Patrick Alken\n *\n * This is free software; you can redistribute it and/or modify it\n * under the terms of the GNU General Public License as published by the\n * Free Software Foundation; either version 3, or (at your option) any\n * later version.\n *\n * This source is distributed in the hope that it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n * for more details.\n *\n * 03 May 2000: Modified for GSL by Brian Gough\n * 29 Jul 2005: Additions by Gerard Jungman\n * 04 Mar 2016: Change Cholesky algorithm to gaxpy version by Patrick Alken\n */\n\n/*\n * Cholesky decomposition of a symmetrix positive definite matrix.\n * This is useful to solve the matrix arising in\n *    periodic cubic splines\n *    approximating splines\n *\n * This algorithm does:\n *   A = L * L'\n * with\n *   L  := lower left triangle matrix\n *   L' := the transposed form of L.\n *\n */\n\n#include \"config.h\"\n\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_blas.h\"\n#include \"gsl_linalg.h\"\n\n/*\nIn GSL 2.2, we decided to modify the behavior of the Cholesky decomposition\nto store the Cholesky factor in the lower triangle, and store the original\nmatrix in the upper triangle. Previous versions stored the Cholesky factor in\nboth places. The routine gsl_linalg_cholesky_decomp1 was added for the new\nbehavior, and gsl_linalg_cholesky_decomp is maintained for backward compatibility.\nIt will be removed in a future release.\n*/\n\nint\ngsl_linalg_cholesky_decomp (gsl_matrix * A)\n{\n  int status;\n\n  status = gsl_linalg_cholesky_decomp1(A);\n  if (status == GSL_SUCCESS)\n    {\n      gsl_matrix_transpose_tricpy('L', 0, A, A);\n    }\n\n  return status;\n}\n\n/*\ngsl_linalg_cholesky_decomp1()\n  Perform Cholesky decomposition of a symmetric positive\ndefinite matrix using lower triangle\n\nInputs: A - (input) symmetric, positive definite matrix\n            (output) lower triangle contains Cholesky factor\n\nReturn: success/error\n\nNotes:\n1) Based on algorithm 4.2.1 (Gaxpy Cholesky) of Golub and\nVan Loan, Matrix Computations (4th ed).\n\n2) original matrix is saved in upper triangle on output\n*/\n\nint\ngsl_linalg_cholesky_decomp1 (gsl_matrix * A)\n{\n  const size_t M = A->size1;\n  const size_t N = A->size2;\n\n  if (M != N)\n    {\n      GSL_ERROR(\"cholesky decomposition requires square matrix\", GSL_ENOTSQR);\n    }\n  else\n    {\n      size_t j;\n\n      /* save original matrix in upper triangle for later rcond calculation */\n      gsl_matrix_transpose_tricpy('L', 0, A, A);\n\n      for (j = 0; j < N; ++j)\n        {\n          double ajj;\n          gsl_vector_view v = gsl_matrix_subcolumn(A, j, j, N - j); /* A(j:n,j) */\n\n          if (j > 0)\n            {\n              gsl_vector_view w = gsl_matrix_subrow(A, j, 0, j);           /* A(j,1:j-1)^T */\n              gsl_matrix_view m = gsl_matrix_submatrix(A, j, 0, N - j, j); /* A(j:n,1:j-1) */\n\n              gsl_blas_dgemv(CblasNoTrans, -1.0, &m.matrix, &w.vector, 1.0, &v.vector);\n            }\n\n          ajj = gsl_matrix_get(A, j, j);\n\n          if (ajj <= 0.0)\n            {\n              GSL_ERROR(\"matrix is not positive definite\", GSL_EDOM);\n            }\n\n          ajj = sqrt(ajj);\n          gsl_vector_scale(&v.vector, 1.0 / ajj);\n        }\n\n      return GSL_SUCCESS;\n    }\n}\n\n"
  },
  {
    "path": "gsl/linalg/gsl_linalg.h",
    "content": "/* linalg/gsl_linalg.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2006, 2007 Gerard Jungman, Brian Gough, Patrick Alken\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_LINALG_H__\n#define __GSL_LINALG_H__\n\n#include <stdlib.h>\n//#include \"gsl_mode.h\"\n#include \"gsl_permutation.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_math.h\"\n#include \"gsl_inline.h\"\n#include \"gsl_blas.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n#define __BEGIN_DECLS extern \"C\" {\n#define __END_DECLS }\n#else\n#define __BEGIN_DECLS           /* empty */\n#define __END_DECLS             /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* LU Decomposition, Gaussian elimination with partial pivoting\n */\n\nint gsl_linalg_LU_decomp (gsl_matrix * A, gsl_permutation * p, int *signum);\n\nint gsl_linalg_LU_solve (const gsl_matrix * LU,\n\t\t\t\t\t\t const gsl_permutation * p,\n\t\t\t\t\t\t const gsl_vector * b,\n\t\t\t\t\t\t gsl_vector * x);\n\nint gsl_linalg_LU_svx (const gsl_matrix * LU,\n\t\t\t\t\t   const gsl_permutation * p,\n\t\t\t\t\t   gsl_vector * x);\n\nint gsl_linalg_LU_refine (const gsl_matrix * A,\n\t\t\t\t\t\t  const gsl_matrix * LU,\n\t\t\t\t\t\t  const gsl_permutation * p,\n\t\t\t\t\t\t  const gsl_vector * b,\n\t\t\t\t\t\t  gsl_vector * x,\n\t\t\t\t\t\t  gsl_vector * work);\n\nint gsl_linalg_LU_invert (const gsl_matrix * LU,\n\t\t\t\t\t\t  const gsl_permutation * p,\n\t\t\t\t\t\t  gsl_matrix * inverse);\n\ndouble gsl_linalg_LU_det (gsl_matrix * LU, int signum);\ndouble gsl_linalg_LU_lndet (gsl_matrix * LU);\nint gsl_linalg_LU_sgndet (gsl_matrix * lu, int signum);\n\n/* Cholesky Decomposition */\n\nint gsl_linalg_cholesky_decomp (gsl_matrix * A);\nint gsl_linalg_cholesky_decomp1 (gsl_matrix * A);\n\n/* Linear solve for a symmetric tridiagonal system.\n\n * The input vectors represent the NxN matrix as follows:\n *\n *     diag[0]  offdiag[0]             0    ...\n *  offdiag[0]     diag[1]    offdiag[1]    ...\n *           0  offdiag[1]       diag[2]    ...\n *           0           0    offdiag[2]    ...\n *         ...         ...           ...    ...\n */\nint gsl_linalg_solve_symm_tridiag (const gsl_vector * diag,\n\t\t\t\t\t\t\t\t   const gsl_vector * offdiag,\n\t\t\t\t\t\t\t\t   const gsl_vector * b,\n\t\t\t\t\t\t\t\t   gsl_vector * x);\n\n/* Linear solve for a nonsymmetric tridiagonal system.\n\n * The input vectors represent the NxN matrix as follows:\n *\n *       diag[0]  abovediag[0]              0    ...\n *  belowdiag[0]       diag[1]   abovediag[1]    ...\n *             0  belowdiag[1]        diag[2]    ...\n *             0             0   belowdiag[2]    ...\n *           ...           ...            ...    ...\n */\nint gsl_linalg_solve_tridiag (const gsl_vector * diag,\n\t\t\t\t\t\t\t\t   const gsl_vector * abovediag,\n\t\t\t\t\t\t\t\t   const gsl_vector * belowdiag,\n\t\t\t\t\t\t\t\t   const gsl_vector * b,\n\t\t\t\t\t\t\t\t   gsl_vector * x);\n\n\n/* Linear solve for a symmetric cyclic tridiagonal system.\n\n * The input vectors represent the NxN matrix as follows:\n *\n *      diag[0]  offdiag[0]             0   .....  offdiag[N-1]\n *   offdiag[0]     diag[1]    offdiag[1]   .....\n *            0  offdiag[1]       diag[2]   .....\n *            0           0    offdiag[2]   .....\n *          ...         ...\n * offdiag[N-1]         ...\n */\nint gsl_linalg_solve_symm_cyc_tridiag (const gsl_vector * diag,\n\t\t\t\t\t\t\t\t\t   const gsl_vector * offdiag,\n\t\t\t\t\t\t\t\t\t   const gsl_vector * b,\n\t\t\t\t\t\t\t\t\t   gsl_vector * x);\n\n/* Linear solve for a nonsymmetric cyclic tridiagonal system.\n\n * The input vectors represent the NxN matrix as follows:\n *\n *        diag[0]  abovediag[0]             0   .....  belowdiag[N-1]\n *   belowdiag[0]       diag[1]  abovediag[1]   .....\n *              0  belowdiag[1]       diag[2]\n *              0             0  belowdiag[2]   .....\n *            ...           ...\n * abovediag[N-1]           ...\n */\nint gsl_linalg_solve_cyc_tridiag (const gsl_vector * diag,\n\t\t\t\t\t\t\t\t  const gsl_vector * abovediag,\n\t\t\t\t\t\t\t\t  const gsl_vector * belowdiag,\n\t\t\t\t\t\t\t\t  const gsl_vector * b,\n\t\t\t\t\t\t\t\t  gsl_vector * x);\n\n__END_DECLS\n\n#endif /* __GSL_LINALG_H__ */\n"
  },
  {
    "path": "gsl/linalg/lu.c",
    "content": "/* linalg/lu.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"stdlib.h\"\n#include \"string.h\"\n#include \"gsl_math.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_permute_vector.h\"\n#include \"gsl_blas.h\"\n\n#include \"gsl_linalg.h\"\n\n#define REAL double\nstatic int singular (const gsl_matrix * LU);\n\n/* Factorise a general N x N matrix A into,\n *\n *   P A = L U\n *\n * where P is a permutation matrix, L is unit lower triangular and U\n * is upper triangular.\n *\n * L is stored in the strict lower triangular part of the input\n * matrix. The diagonal elements of L are unity and are not stored.\n *\n * U is stored in the diagonal and upper triangular part of the\n * input matrix.  \n * \n * P is stored in the permutation p. Column j of P is column k of the\n * identity matrix, where k = permutation->data[j]\n *\n * signum gives the sign of the permutation, (-1)^n, where n is the\n * number of interchanges in the permutation. \n *\n * See Golub & Van Loan, Matrix Computations, Algorithm 3.4.1 (Gauss\n * Elimination with Partial Pivoting).\n */\n\nint\ngsl_linalg_LU_decomp (gsl_matrix * A, gsl_permutation * p, int *signum)\n{\n  if (A->size1 != A->size2)\n    {\n      GSL_ERROR (\"LU decomposition requires square matrix\", GSL_ENOTSQR);\n    }\n  else if (p->size != A->size1)\n    {\n      GSL_ERROR (\"permutation length must match matrix size\", GSL_EBADLEN);\n    }\n  else\n    {\n      const size_t N = A->size1;\n      size_t i, j, k;\n\n      *signum = 1;\n      gsl_permutation_init (p);\n\n      for (j = 0; j < N - 1; j++)\n        {\n          /* Find maximum in the j-th column */\n\n          REAL ajj, max = fabs (gsl_matrix_get (A, j, j));\n          size_t i_pivot = j;\n\n          for (i = j + 1; i < N; i++)\n            {\n              REAL aij = fabs (gsl_matrix_get (A, i, j));\n\n              if (aij > max)\n                {\n                  max = aij;\n                  i_pivot = i;\n                }\n            }\n\n          if (i_pivot != j)\n            {\n              gsl_matrix_swap_rows (A, j, i_pivot);\n              gsl_permutation_swap (p, j, i_pivot);\n              *signum = -(*signum);\n            }\n\n          ajj = gsl_matrix_get (A, j, j);\n\n          if (ajj != 0.0)\n            {\n              for (i = j + 1; i < N; i++)\n                {\n                  REAL aij = gsl_matrix_get (A, i, j) / ajj;\n                  gsl_matrix_set (A, i, j, aij);\n\n                  for (k = j + 1; k < N; k++)\n                    {\n                      REAL aik = gsl_matrix_get (A, i, k);\n                      REAL ajk = gsl_matrix_get (A, j, k);\n                      gsl_matrix_set (A, i, k, aik - aij * ajk);\n                    }\n                }\n            }\n        }\n      \n      return GSL_SUCCESS;\n    }\n}\n\nint\ngsl_linalg_LU_solve (const gsl_matrix * LU, const gsl_permutation * p, const gsl_vector * b, gsl_vector * x)\n{\n  if (LU->size1 != LU->size2)\n    {\n      GSL_ERROR (\"LU matrix must be square\", GSL_ENOTSQR);\n    }\n  else if (LU->size1 != p->size)\n    {\n      GSL_ERROR (\"permutation length must match matrix size\", GSL_EBADLEN);\n    }\n  else if (LU->size1 != b->size)\n    {\n      GSL_ERROR (\"matrix size must match b size\", GSL_EBADLEN);\n    }\n  else if (LU->size2 != x->size)\n    {\n      GSL_ERROR (\"matrix size must match solution size\", GSL_EBADLEN);\n    }\n  else if (singular (LU)) \n    {\n      GSL_ERROR (\"matrix is singular\", GSL_EDOM);\n    }\n  else\n    {\n      int status;\n\n      /* Copy x <- b */\n\n      gsl_vector_memcpy (x, b);\n\n      /* Solve for x */\n\n      status = gsl_linalg_LU_svx (LU, p, x);\n\n      return status;\n    }\n}\n\n\nint\ngsl_linalg_LU_svx (const gsl_matrix * LU, const gsl_permutation * p, gsl_vector * x)\n{\n  if (LU->size1 != LU->size2)\n    {\n      GSL_ERROR (\"LU matrix must be square\", GSL_ENOTSQR);\n    }\n  else if (LU->size1 != p->size)\n    {\n      GSL_ERROR (\"permutation length must match matrix size\", GSL_EBADLEN);\n    }\n  else if (LU->size1 != x->size)\n    {\n      GSL_ERROR (\"matrix size must match solution/rhs size\", GSL_EBADLEN);\n    }\n  else if (singular (LU)) \n    {\n      GSL_ERROR (\"matrix is singular\", GSL_EDOM);\n    }\n  else\n    {\n      /* Apply permutation to RHS */\n\n      gsl_permute_vector (p, x);\n\n      /* Solve for c using forward-substitution, L c = P b */\n\n      gsl_blas_dtrsv (CblasLower, CblasNoTrans, CblasUnit, LU, x);\n\n      /* Perform back-substitution, U x = c */\n\n      gsl_blas_dtrsv (CblasUpper, CblasNoTrans, CblasNonUnit, LU, x);\n\n      return GSL_SUCCESS;\n    }\n}\n\n\nint\ngsl_linalg_LU_refine (const gsl_matrix * A, const gsl_matrix * LU, const gsl_permutation * p, const gsl_vector * b, gsl_vector * x, gsl_vector * work)\n{\n  if (A->size1 != A->size2)\n    {\n      GSL_ERROR (\"matrix a must be square\", GSL_ENOTSQR);\n    }\n  if (LU->size1 != LU->size2)\n    {\n      GSL_ERROR (\"LU matrix must be square\", GSL_ENOTSQR);\n    }\n  else if (A->size1 != LU->size2)\n    {\n      GSL_ERROR (\"LU matrix must be decomposition of a\", GSL_ENOTSQR);\n    }\n  else if (LU->size1 != p->size)\n    {\n      GSL_ERROR (\"permutation length must match matrix size\", GSL_EBADLEN);\n    }\n  else if (LU->size1 != b->size)\n    {\n      GSL_ERROR (\"matrix size must match b size\", GSL_EBADLEN);\n    }\n  else if (LU->size1 != x->size)\n    {\n      GSL_ERROR (\"matrix size must match solution size\", GSL_EBADLEN);\n    }\n  else if (LU->size1 != work->size)\n    {\n      GSL_ERROR (\"matrix size must match workspace size\", GSL_EBADLEN);\n    }\n  else if (singular (LU)) \n    {\n      GSL_ERROR (\"matrix is singular\", GSL_EDOM);\n    }\n  else\n    {\n      int status;\n\n      /* Compute residual = (A * x  - b) */\n\n      gsl_vector_memcpy (work, b);\n      gsl_blas_dgemv (CblasNoTrans, 1.0, A, x, -1.0, work);\n\n      /* Find correction, delta = - (A^-1) * residual, and apply it */\n\n      status = gsl_linalg_LU_svx (LU, p, work);\n      gsl_blas_daxpy (-1.0, work, x);\n\n      return status;\n    }\n}\n\nint\ngsl_linalg_LU_invert (const gsl_matrix * LU, const gsl_permutation * p, gsl_matrix * inverse)\n{\n  size_t i, n = LU->size1;\n\n  int status = GSL_SUCCESS;\n\n  if (singular (LU)) \n    {\n      GSL_ERROR (\"matrix is singular\", GSL_EDOM);\n    }\n\n  gsl_matrix_set_identity (inverse);\n\n  for (i = 0; i < n; i++)\n    {\n      gsl_vector_view c = gsl_matrix_column (inverse, i);\n      int status_i = gsl_linalg_LU_svx (LU, p, &(c.vector));\n\n      if (status_i)\n        status = status_i;\n    }\n\n  return status;\n}\n\ndouble\ngsl_linalg_LU_det (gsl_matrix * LU, int signum)\n{\n  size_t i, n = LU->size1;\n\n  double det = (double) signum;\n\n  for (i = 0; i < n; i++)\n    {\n      det *= gsl_matrix_get (LU, i, i);\n    }\n\n  return det;\n}\n\n\ndouble\ngsl_linalg_LU_lndet (gsl_matrix * LU)\n{\n  size_t i, n = LU->size1;\n\n  double lndet = 0.0;\n\n  for (i = 0; i < n; i++)\n    {\n      lndet += log (fabs (gsl_matrix_get (LU, i, i)));\n    }\n\n  return lndet;\n}\n\nint\ngsl_linalg_LU_sgndet (gsl_matrix * LU, int signum)\n{\n  size_t i, n = LU->size1;\n\n  int s = signum;\n\n  for (i = 0; i < n; i++)\n    {\n      double u = gsl_matrix_get (LU, i, i);\n\n      if (u < 0)\n        {\n          s *= -1;\n        }\n      else if (u == 0)\n        {\n          s = 0;\n          break;\n        }\n    }\n\n  return s;\n}\n\nstatic int\nsingular (const gsl_matrix * LU)\n{\n  size_t i, n = LU->size1;\n\n  for (i = 0; i < n; i++)\n    {\n      double u = gsl_matrix_get (LU, i, i);\n      if (u == 0) return 1;\n    }\n \n return 0;\n}\n\n"
  },
  {
    "path": "gsl/linalg/tridiag.c",
    "content": "/* linalg/tridiag.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2004, 2007 Gerard Jungman, Brian Gough, David Necas\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author: G. Jungman */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include <math.h>\n#include \"gsl_errno.h\"\n#include \"tridiag.h\"\n#include \"gsl_linalg.h\"\n\n/* for description of method see [Engeln-Mullges + Uhlig, p. 92]\n *\n *     diag[0]  offdiag[0]             0   .....\n *  offdiag[0]     diag[1]    offdiag[1]   .....\n *           0  offdiag[1]       diag[2]\n *           0           0    offdiag[2]   .....\n */\nstatic\nint \nsolve_tridiag(\n  const double diag[], size_t d_stride,\n  const double offdiag[], size_t o_stride,\n  const double b[], size_t b_stride,\n  double x[], size_t x_stride,\n  size_t N)\n{\n  int status = GSL_SUCCESS;\n  double *gamma = (double *) malloc (N * sizeof (double));\n  double *alpha = (double *) malloc (N * sizeof (double));\n  double *c = (double *) malloc (N * sizeof (double));\n  double *z = (double *) malloc (N * sizeof (double));\n\n  if (gamma == 0 || alpha == 0 || c == 0 || z == 0)\n    {\n      GSL_ERROR(\"failed to allocate working space\", GSL_ENOMEM);\n    }\n  else\n    {\n      size_t i, j;\n\n      /* Cholesky decomposition\n         A = L.D.L^t\n         lower_diag(L) = gamma\n         diag(D) = alpha\n       */\n      alpha[0] = diag[0];\n      gamma[0] = offdiag[0] / alpha[0];\n\n      if (alpha[0] == 0) {\n        status = GSL_EZERODIV;\n      }\n\n      for (i = 1; i < N - 1; i++)\n        {\n          alpha[i] = diag[d_stride * i] - offdiag[o_stride*(i - 1)] * gamma[i - 1];\n          gamma[i] = offdiag[o_stride * i] / alpha[i];\n          if (alpha[i] == 0) {\n            status = GSL_EZERODIV;\n          }\n        }\n\n      if (N > 1) \n        {\n          alpha[N - 1] = diag[d_stride * (N - 1)] - offdiag[o_stride*(N - 2)] * gamma[N - 2];\n        }\n\n      /* update RHS */\n      z[0] = b[0];\n      for (i = 1; i < N; i++)\n        {\n          z[i] = b[b_stride * i] - gamma[i - 1] * z[i - 1];\n        }\n      for (i = 0; i < N; i++)\n        {\n          c[i] = z[i] / alpha[i];\n        }\n\n      /* backsubstitution */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wuninitialized\"\n#if defined(__has_warning)\n#if __has_warning(\"-Wmaybe-uninitialized\")\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n#endif\n#endif\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wuninitialized\"\n#if defined(__has_warning)\n#if __has_warning(\"-Wmaybe-uninitialized\")\n#pragma clang diagnostic ignored \"-Wmaybe-uninitialized\"\n#endif\n#endif\n      x[x_stride * (N - 1)] = c[N - 1];\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n      if (N >= 2)\n        {\n          for (i = N - 2, j = 0; j <= N - 2; j++, i--)\n            {\n              x[x_stride * i] = c[i] - gamma[i] * x[x_stride * (i + 1)];\n            }\n        }\n    }\n\n  if (z != 0)\n    free (z);\n  if (c != 0)\n    free (c);\n  if (alpha != 0)\n    free (alpha);\n  if (gamma != 0)\n    free (gamma);\n\n  if (status == GSL_EZERODIV) {\n    GSL_ERROR (\"matrix must be positive definite\", status);\n  }\n\n  return status;\n}\n\n/* plain gauss elimination, only not bothering with the zeroes\n *\n *       diag[0]  abovediag[0]             0   .....\n *  belowdiag[0]       diag[1]  abovediag[1]   .....\n *             0  belowdiag[1]       diag[2]\n *             0             0  belowdiag[2]   .....\n */\nstatic\nint \nsolve_tridiag_nonsym(\n  const double diag[], size_t d_stride,\n  const double abovediag[], size_t a_stride,\n  const double belowdiag[], size_t b_stride,\n  const double rhs[], size_t r_stride,\n  double x[], size_t x_stride,\n  size_t N)\n{\n  int status = GSL_SUCCESS;\n  double *alpha = (double *) malloc (N * sizeof (double));\n  double *z = (double *) malloc (N * sizeof (double));\n\n  if (alpha == 0 || z == 0)\n    {\n      GSL_ERROR(\"failed to allocate working space\", GSL_ENOMEM);\n    }\n  else\n    {\n      size_t i, j;\n\n      /* Bidiagonalization (eliminating belowdiag)\n         & rhs update\n         diag' = alpha\n         rhs' = z\n       */\n      alpha[0] = diag[0];\n      z[0] = rhs[0];\n      \n      if (alpha[0] == 0) {\n        status = GSL_EZERODIV;\n      }\n\n      for (i = 1; i < N; i++)\n        {\n          const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];\n          alpha[i] = diag[d_stride*i] - t*abovediag[a_stride*(i - 1)];\n          z[i] = rhs[r_stride*i] - t*z[i-1];\n          if (alpha[i] == 0) {\n            status = GSL_EZERODIV;\n          }\n        }\n\n      /* backsubstitution */\n      x[x_stride * (N - 1)] = z[N - 1]/alpha[N - 1];\n      if (N >= 2)\n        {\n          for (i = N - 2, j = 0; j <= N - 2; j++, i--)\n            {\n              x[x_stride * i] = (z[i] - abovediag[a_stride*i] * x[x_stride * (i + 1)])/alpha[i];\n            }\n        }\n    }\n\n  if (z != 0)\n    free (z);\n  if (alpha != 0)\n    free (alpha);\n\n  if (status == GSL_EZERODIV) {\n    GSL_ERROR (\"matrix must be positive definite\", status);\n  }\n\n  return status;\n}\n\n/* for description of method see [Engeln-Mullges + Uhlig, p. 96]\n *\n *      diag[0]  offdiag[0]             0   .....  offdiag[N-1]\n *   offdiag[0]     diag[1]    offdiag[1]   .....\n *            0  offdiag[1]       diag[2]\n *            0           0    offdiag[2]   .....\n *          ...         ...\n * offdiag[N-1]         ...\n *\n */\nstatic\nint \nsolve_cyc_tridiag(\n  const double diag[], size_t d_stride,\n  const double offdiag[], size_t o_stride,\n  const double b[], size_t b_stride,\n  double x[], size_t x_stride,\n  size_t N)\n{\n  int status = GSL_SUCCESS;\n  double * delta = (double *) malloc (N * sizeof (double));\n  double * gamma = (double *) malloc (N * sizeof (double));\n  double * alpha = (double *) malloc (N * sizeof (double));\n  double * c = (double *) malloc (N * sizeof (double));\n  double * z = (double *) malloc (N * sizeof (double));\n\n  if (delta == 0 || gamma == 0 || alpha == 0 || c == 0 || z == 0)\n    {\n      GSL_ERROR(\"failed to allocate working space\", GSL_ENOMEM);\n    }\n  else\n    {\n      size_t i, j;\n      double sum = 0.0;\n\n      /* factor */\n\n      if (N == 1) \n        {\n          x[0] = b[0] / diag[0];\n          free(delta);\n          free(gamma);\n          free(alpha);\n          free(c);\n          free(z);\n          return GSL_SUCCESS;\n        }\n\n      alpha[0] = diag[0];\n      gamma[0] = offdiag[0] / alpha[0];\n      delta[0] = offdiag[o_stride * (N-1)] / alpha[0];\n\n      if (alpha[0] == 0) {\n        status = GSL_EZERODIV;\n      }\n\n      for (i = 1; i < N - 2; i++)\n        {\n          alpha[i] = diag[d_stride * i] - offdiag[o_stride * (i-1)] * gamma[i - 1];\n          gamma[i] = offdiag[o_stride * i] / alpha[i];\n          delta[i] = -delta[i - 1] * offdiag[o_stride * (i-1)] / alpha[i];\n          if (alpha[i] == 0) {\n            status = GSL_EZERODIV;\n          }\n        }\n\n      for (i = 0; i < N - 2; i++)\n        {\n          sum += alpha[i] * delta[i] * delta[i];\n        }\n\n      alpha[N - 2] = diag[d_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * gamma[N - 3];\n\n      gamma[N - 2] = (offdiag[o_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * delta[N - 3]) / alpha[N - 2];\n\n      alpha[N - 1] = diag[d_stride * (N - 1)] - sum - alpha[(N - 2)] * gamma[N - 2] * gamma[N - 2];\n\n      /* update */\n      z[0] = b[0];\n      for (i = 1; i < N - 1; i++)\n        {\n          z[i] = b[b_stride * i] - z[i - 1] * gamma[i - 1];\n        }\n      sum = 0.0;\n      for (i = 0; i < N - 2; i++)\n        {\n          sum += delta[i] * z[i];\n        }\n      z[N - 1] = b[b_stride * (N - 1)] - sum - gamma[N - 2] * z[N - 2];\n      for (i = 0; i < N; i++)\n        {\n          c[i] = z[i] / alpha[i];\n        }\n\n      /* backsubstitution */\n      x[x_stride * (N - 1)] = c[N - 1];\n      x[x_stride * (N - 2)] = c[N - 2] - gamma[N - 2] * x[x_stride * (N - 1)];\n      if (N >= 3)\n        {\n          for (i = N - 3, j = 0; j <= N - 3; j++, i--)\n            {\n              x[x_stride * i] = c[i] - gamma[i] * x[x_stride * (i + 1)] - delta[i] * x[x_stride * (N - 1)];\n            }\n        }\n    }\n\n  if (z != 0)\n    free (z);\n  if (c != 0)\n    free (c);\n  if (alpha != 0)\n    free (alpha);\n  if (gamma != 0)\n    free (gamma);\n  if (delta != 0)\n    free (delta);\n\n  if (status == GSL_EZERODIV) {\n    GSL_ERROR (\"matrix must be positive definite\", status);\n  }\n\n  return status;\n}\n\n/* solve following system w/o the corner elements and then use\n * Sherman-Morrison formula to compensate for them\n *\n *        diag[0]  abovediag[0]             0   .....  belowdiag[N-1]\n *   belowdiag[0]       diag[1]  abovediag[1]   .....\n *              0  belowdiag[1]       diag[2]\n *              0             0  belowdiag[2]   .....\n *            ...           ...\n * abovediag[N-1]           ...\n */\nstatic\nint solve_cyc_tridiag_nonsym(\n  const double diag[], size_t d_stride,\n  const double abovediag[], size_t a_stride,\n  const double belowdiag[], size_t b_stride,\n  const double rhs[], size_t r_stride,\n  double x[], size_t x_stride,\n  size_t N)\n{\n  int status = GSL_SUCCESS;\n  double *alpha = (double *) malloc (N * sizeof (double));\n  double *zb = (double *) malloc (N * sizeof (double));\n  double *zu = (double *) malloc (N * sizeof (double));\n  double *w = (double *) malloc (N * sizeof (double));\n\n  if (alpha == 0 || zb == 0 || zu == 0 || w == 0)\n    {\n      GSL_ERROR(\"failed to allocate working space\", GSL_ENOMEM);\n    }\n  else\n    {\n      double beta;\n\n      /* Bidiagonalization (eliminating belowdiag)\n         & rhs update\n         diag' = alpha\n         rhs' = zb\n         rhs' for Aq=u is zu\n       */\n      zb[0] = rhs[0];\n      if (diag[0] != 0) beta = -diag[0]; else beta = 1;\n      {\n        const double q = 1 - abovediag[0]*belowdiag[0]/(diag[0]*diag[d_stride]);\n        if (fabs(q/beta) > 0.5 && fabs(q/beta) < 2) {\n          beta *= (fabs(q/beta) < 1) ? 0.5 : 2;\n        }\n      }\n      zu[0] = beta;\n      alpha[0] = diag[0] - beta;\n\n      if (alpha[0] == 0) {\n        status = GSL_EZERODIV;\n      }\n\n      { \n        size_t i;\n        for (i = 1; i+1 < N; i++)\n        {\n          const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];\n          alpha[i] = diag[d_stride*i] - t*abovediag[a_stride*(i - 1)];\n          zb[i] = rhs[r_stride*i] - t*zb[i-1];\n          zu[i] = -t*zu[i-1];\n          /* FIXME!!! */\n          if (alpha[i] == 0) {\n            status = GSL_EZERODIV;\n          }\n        }\n      }\n\n      {\n        const size_t i = N-1;\n        const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];\n        alpha[i] = diag[d_stride*i]\n                   - abovediag[a_stride*i]*belowdiag[b_stride*i]/beta\n                   - t*abovediag[a_stride*(i - 1)];\n        zb[i] = rhs[r_stride*i] - t*zb[i-1];\n        zu[i] = abovediag[a_stride*i] - t*zu[i-1];\n        /* FIXME!!! */\n        if (alpha[i] == 0) {\n          status = GSL_EZERODIV;\n        }\n      }\n\n      /* backsubstitution */\n      {\n        size_t i, j;\n        w[N-1] = zu[N-1]/alpha[N-1];\n        x[x_stride*(N-1)] = zb[N-1]/alpha[N-1];\n        for (i = N - 2, j = 0; j <= N - 2; j++, i--)\n          {\n            w[i] = (zu[i] - abovediag[a_stride*i] * w[i+1])/alpha[i];\n            x[i*x_stride] = (zb[i] - abovediag[a_stride*i] * x[x_stride*(i + 1)])/alpha[i];\n          }\n      }\n      \n      /* Sherman-Morrison */\n      {\n        const double vw = w[0] + belowdiag[b_stride*(N - 1)]/beta * w[N-1];\n        const double vx = x[0] + belowdiag[b_stride*(N - 1)]/beta * x[x_stride*(N - 1)];\n        /* FIXME!!! */\n        if (vw + 1 == 0) {\n          status = GSL_EZERODIV;\n        }\n\n        {\n          size_t i;\n          for (i = 0; i < N; i++)\n            x[i*x_stride] -= vx/(1 + vw)*w[i];\n        }\n      }\n    }\n\n  if (zb != 0)\n    free (zb);\n  if (zu != 0)\n    free (zu);\n  if (w != 0)\n    free (w);\n  if (alpha != 0)\n    free (alpha);\n\n  if (status == GSL_EZERODIV) {\n    GSL_ERROR (\"matrix must be positive definite\", status);\n  }\n\n  return status;\n}\n\nint\ngsl_linalg_solve_symm_tridiag(\n  const gsl_vector * diag,\n  const gsl_vector * offdiag,\n  const gsl_vector * rhs,\n  gsl_vector * solution)\n{\n  if(diag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of diag must match rhs\", GSL_EBADLEN);\n    }\n  else if (offdiag->size != rhs->size-1)\n    {\n      GSL_ERROR (\"size of offdiag must match rhs-1\", GSL_EBADLEN);\n    }\n  else if (solution->size != rhs->size)\n    {\n      GSL_ERROR (\"size of solution must match rhs\", GSL_EBADLEN);\n    }\n  else \n    {\n      return solve_tridiag(diag->data, diag->stride,\n                           offdiag->data, offdiag->stride,\n                           rhs->data, rhs->stride,\n                           solution->data, solution->stride,\n                           diag->size);\n\n    }\n}\n\nint\ngsl_linalg_solve_tridiag(\n  const gsl_vector * diag,\n  const gsl_vector * abovediag,\n  const gsl_vector * belowdiag,\n  const gsl_vector * rhs,\n  gsl_vector * solution)\n{\n  if(diag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of diag must match rhs\", GSL_EBADLEN);\n    }\n  else if (abovediag->size != rhs->size-1)\n    {\n      GSL_ERROR (\"size of abovediag must match rhs-1\", GSL_EBADLEN);\n    }\n  else if (belowdiag->size != rhs->size-1)\n    {\n      GSL_ERROR (\"size of belowdiag must match rhs-1\", GSL_EBADLEN);\n    }\n  else if (solution->size != rhs->size)\n    {\n      GSL_ERROR (\"size of solution must match rhs\", GSL_EBADLEN);\n    }\n  else \n    {\n      return solve_tridiag_nonsym(diag->data, diag->stride,\n                                  abovediag->data, abovediag->stride,\n                                  belowdiag->data, belowdiag->stride,\n                                  rhs->data, rhs->stride,\n                                  solution->data, solution->stride,\n                                  diag->size);\n    }\n}\n\n\nint\ngsl_linalg_solve_symm_cyc_tridiag(\n  const gsl_vector * diag,\n  const gsl_vector * offdiag,\n  const gsl_vector * rhs,\n  gsl_vector * solution)\n{\n  if(diag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of diag must match rhs\", GSL_EBADLEN);\n    }\n  else if (offdiag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of offdiag must match rhs\", GSL_EBADLEN);\n    }\n  else if (solution->size != rhs->size)\n    {\n      GSL_ERROR (\"size of solution must match rhs\", GSL_EBADLEN);\n    }\n  else if (diag->size < 3)\n    {\n      GSL_ERROR (\"size of cyclic system must be 3 or more\", GSL_EBADLEN);\n    }\n  else \n    {\n      return solve_cyc_tridiag(diag->data, diag->stride,\n                               offdiag->data, offdiag->stride,\n                               rhs->data, rhs->stride,\n                               solution->data, solution->stride,\n                               diag->size);\n    }\n}\n\nint\ngsl_linalg_solve_cyc_tridiag(\n  const gsl_vector * diag,\n  const gsl_vector * abovediag,\n  const gsl_vector * belowdiag,\n  const gsl_vector * rhs,\n  gsl_vector * solution)\n{\n  if(diag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of diag must match rhs\", GSL_EBADLEN);\n    }\n  else if (abovediag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of abovediag must match rhs\", GSL_EBADLEN);\n    }\n  else if (belowdiag->size != rhs->size)\n    {\n      GSL_ERROR (\"size of belowdiag must match rhs\", GSL_EBADLEN);\n    }\n  else if (solution->size != rhs->size)\n    {\n      GSL_ERROR (\"size of solution must match rhs\", GSL_EBADLEN);\n    }\n  else if (diag->size < 3)\n    {\n      GSL_ERROR (\"size of cyclic system must be 3 or more\", GSL_EBADLEN);\n    }\n  else \n    {\n      return solve_cyc_tridiag_nonsym(diag->data, diag->stride,\n                                      abovediag->data, abovediag->stride,\n                                      belowdiag->data, belowdiag->stride,\n                                      rhs->data, rhs->stride,\n                                      solution->data, solution->stride,\n                                      diag->size);\n    }\n}\n"
  },
  {
    "path": "gsl/linalg/tridiag.h",
    "content": "/* linalg/tridiag.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002 Gerard Jungman,\n * Brian Gough, David Necas\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman\n */\n/* Low level tridiagonal solvers.\n * Used internally in other areas of GSL.\n */\n#ifndef __GSL_TRIDIAG_H__\n#define __GSL_TRIDIAG_H__\n\n#include <stdlib.h>\n\nstatic\nint solve_tridiag_nonsym(\n  const double diag[], size_t d_stride,\n  const double abovediag[], size_t a_stride,\n  const double belowdiag[], size_t b_stride,\n  const double rhs[], size_t r_stride,\n  double x[], size_t x_stride,\n  size_t N\n  );\n\nstatic\nint solve_tridiag(\n  const double diag[], size_t d_stride,\n  const double offdiag[], size_t o_stride,\n  const double b[], size_t b_stride,\n  double x[], size_t x_stride,\n  size_t N);\n\nstatic\nint solve_cyc_tridiag(\n  const double diag[], size_t d_stride,\n  const double offdiag[], size_t o_stride,\n  const double b[], size_t b_stride,\n  double x[], size_t x_stride,\n  size_t N\n  );\n\nstatic\nint solve_cyc_tridiag_nonsym(\n  const double diag[], size_t d_stride,\n  const double abovediag[], size_t a_stride,\n  const double belowdiag[], size_t b_stride,\n  const double rhs[], size_t r_stride,\n  double x[], size_t x_stride,\n  size_t N);\n\n#endif /* __GSL_TRIDIAG_H__ */\n"
  },
  {
    "path": "gsl/matrix/copy.c",
    "content": "#include \"config.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_errno.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"copy_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/matrix/copy_source.inc",
    "content": "/* matrix/copy_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nint\nFUNCTION (gsl_matrix, memcpy) (TYPE (gsl_matrix) * dest,\n                               const TYPE (gsl_matrix) * src)\n{\n  const size_t src_size1 = src->size1;\n  const size_t src_size2 = src->size2;\n  const size_t dest_size1 = dest->size1;\n  const size_t dest_size2 = dest->size2;\n\n  if (src_size1 != dest_size1 || src_size2 != dest_size2)\n    {\n      GSL_ERROR (\"matrix sizes are different\", GSL_EBADLEN);\n    }\n\n  {\n    const size_t src_tda = src->tda ;\n    const size_t dest_tda = dest->tda ;\n    size_t i, j;\n\n    for (i = 0; i < src_size1 ; i++)\n      {\n        for (j = 0; j < MULTIPLICITY * src_size2; j++)\n          {\n            dest->data[MULTIPLICITY * dest_tda * i + j] \n              = src->data[MULTIPLICITY * src_tda * i + j];\n          }\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n\n\nint\nFUNCTION (gsl_matrix, swap) (TYPE (gsl_matrix) * dest, TYPE (gsl_matrix) * src)\n{\n  const size_t src_size1 = src->size1;\n  const size_t src_size2 = src->size2;\n  const size_t dest_size1 = dest->size1;\n  const size_t dest_size2 = dest->size2;\n\n  if (src_size1 != dest_size1 || src_size2 != dest_size2)\n    {\n      GSL_ERROR (\"matrix sizes are different\", GSL_EBADLEN);\n    }\n\n  {\n    const size_t src_tda = src->tda ;\n    const size_t dest_tda = dest->tda ;\n    size_t i, j;\n\n    for (i = 0; i < src_size1 ; i++)\n      {\n        for (j = 0; j < MULTIPLICITY * src_size2; j++)\n          {\n            ATOMIC tmp = src->data[MULTIPLICITY * src_tda * i + j];\n            src->data[MULTIPLICITY * src_tda * i + j] \n              = dest->data[MULTIPLICITY * dest_tda * i + j];\n            dest->data[MULTIPLICITY * dest_tda * i + j] = tmp ;\n          }\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n\n\nint\nFUNCTION (gsl_matrix, tricpy) (const char uplo_src,\n                               const int copy_diag, TYPE (gsl_matrix) * dest,\n                               const TYPE (gsl_matrix) * src)\n{\n  const size_t src_size1 = src->size1;\n  const size_t src_size2 = src->size2;\n  const size_t dest_size1 = dest->size1;\n  const size_t dest_size2 = dest->size2;\n\n  if (src_size1 != dest_size1 || src_size2 != dest_size2)\n    {\n      GSL_ERROR (\"matrix sizes are different\", GSL_EBADLEN);\n    }\n\n  {\n    const size_t src_tda = src->tda ;\n    const size_t dest_tda = dest->tda ;\n    size_t i, j, k;\n\n    if (uplo_src == 'L')\n      {\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (j = 0; j < i; j++)\n              {\n                for (k = 0; k < MULTIPLICITY; k++)\n                  {\n                    size_t e1 = (i *  dest_tda + j) * MULTIPLICITY + k ;\n                    size_t e2 = (i *  src_tda + j) * MULTIPLICITY + k ;\n                    dest->data[e1] = src->data[e2];\n                  }\n              }\n          }\n      }\n    else if (uplo_src == 'U')\n      {\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (j = i + 1; j < src_size2; j++)\n              {\n                for (k = 0; k < MULTIPLICITY; k++)\n                  {\n                    size_t e1 = (i *  dest_tda + j) * MULTIPLICITY + k ;\n                    size_t e2 = (i *  src_tda + j) * MULTIPLICITY + k ;\n                    dest->data[e1] = src->data[e2];\n                  }\n              }\n          }\n      }\n    else\n      {\n        GSL_ERROR (\"invalid uplo parameters\", GSL_EINVAL);\n      }\n\n    if (copy_diag)\n      {\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (k = 0; k < MULTIPLICITY; k++)\n              {\n                size_t e1 = (i *  dest_tda + i) * MULTIPLICITY + k ;\n                size_t e2 = (i *  src_tda + i) * MULTIPLICITY + k ;\n                dest->data[e1] = src->data[e2];\n              }\n          }\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n\n\n"
  },
  {
    "path": "gsl/matrix/gsl_matrix.h",
    "content": "#ifndef __GSL_MATRIX_H__\n#define __GSL_MATRIX_H__\n\n//#include <gsl/gsl_matrix_complex_long_double.h>\n//#include <gsl/gsl_matrix_complex_double.h>\n//#include <gsl/gsl_matrix_complex_float.h>\n\n//#include <gsl/gsl_matrix_long_double.h>\n#include \"gsl_matrix_double.h\"\n//#include <gsl/gsl_matrix_float.h>\n\n//#include <gsl/gsl_matrix_ulong.h>\n//#include <gsl/gsl_matrix_long.h>\n\n//#include <gsl/gsl_matrix_uint.h>\n//#include <gsl/gsl_matrix_int.h>\n\n//#include <gsl/gsl_matrix_ushort.h>\n//#include <gsl/gsl_matrix_short.h>\n\n//#include <gsl/gsl_matrix_uchar.h>\n//#include <gsl/gsl_matrix_char.h>\n\n\n#endif /* __GSL_MATRIX_H__ */\n"
  },
  {
    "path": "gsl/matrix/gsl_matrix_double.h",
    "content": "/* matrix/gsl_matrix_double.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_MATRIX_DOUBLE_H__\n#define __GSL_MATRIX_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_types.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_inline.h\"\n#include \"gsl_check_range.h\"\n#include \"gsl_vector_double.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ntypedef struct \n{\n  size_t size1;\n  size_t size2;\n  size_t tda;\n  double * data;\n  gsl_block * block;\n  int owner;\n} gsl_matrix;\n\ntypedef struct\n{\n  gsl_matrix matrix;\n} _gsl_matrix_view;\n\ntypedef _gsl_matrix_view gsl_matrix_view;\n\ntypedef struct\n{\n  gsl_matrix matrix;\n} _gsl_matrix_const_view;\n\ntypedef const _gsl_matrix_const_view gsl_matrix_const_view;\n\n/* Allocation */\n\ngsl_matrix * \ngsl_matrix_alloc (const size_t n1, const size_t n2);\n\ngsl_matrix * \ngsl_matrix_calloc (const size_t n1, const size_t n2);\n\ngsl_matrix * \ngsl_matrix_alloc_from_block (gsl_block * b, \n                                   const size_t offset, \n                                   const size_t n1, \n                                   const size_t n2, \n                                   const size_t d2);\n\ngsl_matrix * \ngsl_matrix_alloc_from_matrix (gsl_matrix * m,\n                                    const size_t k1, \n                                    const size_t k2,\n                                    const size_t n1, \n                                    const size_t n2);\n\ngsl_vector * \ngsl_vector_alloc_row_from_matrix (gsl_matrix * m,\n                                        const size_t i);\n\ngsl_vector * \ngsl_vector_alloc_col_from_matrix (gsl_matrix * m,\n                                        const size_t j);\n\nvoid gsl_matrix_free (gsl_matrix * m);\n\n/* Views */\n\n_gsl_matrix_view \ngsl_matrix_submatrix (gsl_matrix * m, \n                            const size_t i, const size_t j, \n                            const size_t n1, const size_t n2);\n\n_gsl_vector_view \ngsl_matrix_row (gsl_matrix * m, const size_t i);\n\n_gsl_vector_view \ngsl_matrix_column (gsl_matrix * m, const size_t j);\n\n_gsl_vector_view \ngsl_matrix_diagonal (gsl_matrix * m);\n\n_gsl_vector_view \ngsl_matrix_subdiagonal (gsl_matrix * m, const size_t k);\n\n_gsl_vector_view \ngsl_matrix_superdiagonal (gsl_matrix * m, const size_t k);\n\n_gsl_vector_view\ngsl_matrix_subrow (gsl_matrix * m, const size_t i,\n                         const size_t offset, const size_t n);\n\n_gsl_vector_view\ngsl_matrix_subcolumn (gsl_matrix * m, const size_t j,\n                            const size_t offset, const size_t n);\n\n_gsl_matrix_view\ngsl_matrix_view_array (double * base,\n                             const size_t n1, \n                             const size_t n2);\n\n_gsl_matrix_view\ngsl_matrix_view_array_with_tda (double * base, \n                                      const size_t n1, \n                                      const size_t n2,\n                                      const size_t tda);\n\n\n_gsl_matrix_view\ngsl_matrix_view_vector (gsl_vector * v,\n                              const size_t n1, \n                              const size_t n2);\n\n_gsl_matrix_view\ngsl_matrix_view_vector_with_tda (gsl_vector * v,\n                                       const size_t n1, \n                                       const size_t n2,\n                                       const size_t tda);\n\n\n_gsl_matrix_const_view \ngsl_matrix_const_submatrix (const gsl_matrix * m, \n                                  const size_t i, const size_t j, \n                                  const size_t n1, const size_t n2);\n\n_gsl_vector_const_view \ngsl_matrix_const_row (const gsl_matrix * m, \n                            const size_t i);\n\n_gsl_vector_const_view \ngsl_matrix_const_column (const gsl_matrix * m, \n                               const size_t j);\n\n_gsl_vector_const_view\ngsl_matrix_const_diagonal (const gsl_matrix * m);\n\n_gsl_vector_const_view \ngsl_matrix_const_subdiagonal (const gsl_matrix * m, \n                                    const size_t k);\n\n_gsl_vector_const_view \ngsl_matrix_const_superdiagonal (const gsl_matrix * m, \n                                      const size_t k);\n\n_gsl_vector_const_view\ngsl_matrix_const_subrow (const gsl_matrix * m, const size_t i,\n                               const size_t offset, const size_t n);\n\n_gsl_vector_const_view\ngsl_matrix_const_subcolumn (const gsl_matrix * m, const size_t j,\n                                  const size_t offset, const size_t n);\n\n_gsl_matrix_const_view\ngsl_matrix_const_view_array (const double * base,\n                                   const size_t n1, \n                                   const size_t n2);\n\n_gsl_matrix_const_view\ngsl_matrix_const_view_array_with_tda (const double * base, \n                                            const size_t n1, \n                                            const size_t n2,\n                                            const size_t tda);\n\n_gsl_matrix_const_view\ngsl_matrix_const_view_vector (const gsl_vector * v,\n                                    const size_t n1, \n                                    const size_t n2);\n\n_gsl_matrix_const_view\ngsl_matrix_const_view_vector_with_tda (const gsl_vector * v,\n                                             const size_t n1, \n                                             const size_t n2,\n                                             const size_t tda);\n\n/* Operations */\n\nvoid gsl_matrix_set_zero (gsl_matrix * m);\nvoid gsl_matrix_set_identity (gsl_matrix * m);\nvoid gsl_matrix_set_all (gsl_matrix * m, double x);\n\nint gsl_matrix_fread (FILE * stream, gsl_matrix * m) ;\nint gsl_matrix_fwrite (FILE * stream, const gsl_matrix * m) ;\nint gsl_matrix_fscanf (FILE * stream, gsl_matrix * m);\nint gsl_matrix_fprintf (FILE * stream, const gsl_matrix * m, const char * format);\n \nint gsl_matrix_memcpy(gsl_matrix * dest, const gsl_matrix * src);\nint gsl_matrix_swap(gsl_matrix * m1, gsl_matrix * m2);\nint gsl_matrix_tricpy(const char uplo_src, const int copy_diag, gsl_matrix * dest, const gsl_matrix * src);\n\nint gsl_matrix_swap_rows(gsl_matrix * m, const size_t i, const size_t j);\nint gsl_matrix_swap_columns(gsl_matrix * m, const size_t i, const size_t j);\nint gsl_matrix_swap_rowcol(gsl_matrix * m, const size_t i, const size_t j);\nint gsl_matrix_transpose (gsl_matrix * m);\nint gsl_matrix_transpose_memcpy (gsl_matrix * dest, const gsl_matrix * src);\nint gsl_matrix_transpose_tricpy (const char uplo_src, const int copy_diag, gsl_matrix * dest, const gsl_matrix * src);\n\ndouble gsl_matrix_max (const gsl_matrix * m);\ndouble gsl_matrix_min (const gsl_matrix * m);\nvoid gsl_matrix_minmax (const gsl_matrix * m, double * min_out, double * max_out);\n\nvoid gsl_matrix_max_index (const gsl_matrix * m, size_t * imax, size_t *jmax);\nvoid gsl_matrix_min_index (const gsl_matrix * m, size_t * imin, size_t *jmin);\nvoid gsl_matrix_minmax_index (const gsl_matrix * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);\n\nint gsl_matrix_equal (const gsl_matrix * a, const gsl_matrix * b);\n\nint gsl_matrix_isnull (const gsl_matrix * m);\nint gsl_matrix_ispos (const gsl_matrix * m);\nint gsl_matrix_isneg (const gsl_matrix * m);\nint gsl_matrix_isnonneg (const gsl_matrix * m);\n\nint gsl_matrix_add (gsl_matrix * a, const gsl_matrix * b);\nint gsl_matrix_sub (gsl_matrix * a, const gsl_matrix * b);\nint gsl_matrix_mul_elements (gsl_matrix * a, const gsl_matrix * b);\nint gsl_matrix_div_elements (gsl_matrix * a, const gsl_matrix * b);\nint gsl_matrix_scale (gsl_matrix * a, const double x);\nint gsl_matrix_add_constant (gsl_matrix * a, const double x);\nint gsl_matrix_add_diagonal (gsl_matrix * a, const double x);\n\n/***********************************************************************/\n/* The functions below are obsolete                                    */\n/***********************************************************************/\nint gsl_matrix_get_row(gsl_vector * v, const gsl_matrix * m, const size_t i);\nint gsl_matrix_get_col(gsl_vector * v, const gsl_matrix * m, const size_t j);\nint gsl_matrix_set_row(gsl_matrix * m, const size_t i, const gsl_vector * v);\nint gsl_matrix_set_col(gsl_matrix * m, const size_t j, const gsl_vector * v);\n/***********************************************************************/\n\n/* inline functions if you are using GCC */\n\nINLINE_DECL double   gsl_matrix_get(const gsl_matrix * m, const size_t i, const size_t j);\nINLINE_DECL void    gsl_matrix_set(gsl_matrix * m, const size_t i, const size_t j, const double x);\nINLINE_DECL double * gsl_matrix_ptr(gsl_matrix * m, const size_t i, const size_t j);\nINLINE_DECL const double * gsl_matrix_const_ptr(const gsl_matrix * m, const size_t i, const size_t j);\n\n#ifdef HAVE_INLINE\nINLINE_FUN \ndouble\ngsl_matrix_get(const gsl_matrix * m, const size_t i, const size_t j)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(1)) \n    {\n      if (i >= m->size1)\n        {\n          GSL_ERROR_VAL(\"first index out of range\", GSL_EINVAL, 0) ;\n        }\n      else if (j >= m->size2)\n        {\n          GSL_ERROR_VAL(\"second index out of range\", GSL_EINVAL, 0) ;\n        }\n    }\n#endif\n  return m->data[i * m->tda + j] ;\n} \n\nINLINE_FUN \nvoid\ngsl_matrix_set(gsl_matrix * m, const size_t i, const size_t j, const double x)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(1)) \n    {\n      if (i >= m->size1)\n        {\n          GSL_ERROR_VOID(\"first index out of range\", GSL_EINVAL) ;\n        }\n      else if (j >= m->size2)\n        {\n          GSL_ERROR_VOID(\"second index out of range\", GSL_EINVAL) ;\n        }\n    }\n#endif\n  m->data[i * m->tda + j] = x ;\n}\n\nINLINE_FUN \ndouble *\ngsl_matrix_ptr(gsl_matrix * m, const size_t i, const size_t j)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(1)) \n    {\n      if (i >= m->size1)\n        {\n          GSL_ERROR_NULL(\"first index out of range\", GSL_EINVAL) ;\n        }\n      else if (j >= m->size2)\n        {\n          GSL_ERROR_NULL(\"second index out of range\", GSL_EINVAL) ;\n        }\n    }\n#endif\n  return (double *) (m->data + (i * m->tda + j)) ;\n} \n\nINLINE_FUN \nconst double *\ngsl_matrix_const_ptr(const gsl_matrix * m, const size_t i, const size_t j)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(1)) \n    {\n      if (i >= m->size1)\n        {\n          GSL_ERROR_NULL(\"first index out of range\", GSL_EINVAL) ;\n        }\n      else if (j >= m->size2)\n        {\n          GSL_ERROR_NULL(\"second index out of range\", GSL_EINVAL) ;\n        }\n    }\n#endif\n  return (const double *) (m->data + (i * m->tda + j)) ;\n} \n\n#endif\n\n__END_DECLS\n\n#endif /* __GSL_MATRIX_DOUBLE_H__ */\n"
  },
  {
    "path": "gsl/matrix/init.c",
    "content": "#include \"config.h\"\n#include <string.h>\n#include \"gsl_errno.h\"\n#include \"gsl_matrix.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/matrix/init_source.inc",
    "content": "/* matrix/init_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nTYPE (gsl_matrix) *\nFUNCTION (gsl_matrix, alloc) (const size_t n1, const size_t n2)\n{\n  TYPE (gsl_block) * block;\n  TYPE (gsl_matrix) * m;\n\n  m = (TYPE (gsl_matrix) *) malloc (sizeof (TYPE (gsl_matrix)));\n\n  if (m == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for matrix struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  /* FIXME: n1*n2 could overflow for large dimensions */\n\n  block = FUNCTION(gsl_block, alloc) (n1 * n2) ;\n\n  if (block == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for block\",\n                        GSL_ENOMEM, 0);\n    }\n\n  m->data = block->data;\n  m->size1 = n1;\n  m->size2 = n2;\n  m->tda = n2; \n  m->block = block;\n  m->owner = 1;\n\n  return m;\n}\n\nTYPE (gsl_matrix) *\nFUNCTION (gsl_matrix, calloc) (const size_t n1, const size_t n2)\n{\n  size_t i;\n\n  TYPE (gsl_matrix) * m = FUNCTION (gsl_matrix, alloc) (n1, n2);\n\n  if (m == 0)\n    return 0;\n\n  /* initialize matrix to zero */\n  memset(m->data, 0, MULTIPLICITY * n1 * n2 * sizeof(ATOMIC));\n\n  for (i = 0; i < MULTIPLICITY * n1 * n2; i++)\n    {\n      m->data[i] = 0;\n    }\n\n  return m;\n}\n\nTYPE (gsl_matrix) *\nFUNCTION (gsl_matrix, alloc_from_block) (TYPE(gsl_block) * block, \n                                         const size_t offset,\n                                         const size_t n1, \n                                         const size_t n2,\n                                         const size_t d2)\n{\n  TYPE (gsl_matrix) * m;\n\n  if (d2 < n2)\n    {\n      GSL_ERROR_VAL (\"matrix dimension d2 must be greater than n2\",\n                        GSL_EINVAL, 0);\n    }\n  else if (block->size < offset + n1 * d2)\n    {\n      GSL_ERROR_VAL (\"matrix size exceeds available block size\",\n                        GSL_EINVAL, 0);\n    }\n\n  m = (TYPE (gsl_matrix) *) malloc (sizeof (TYPE (gsl_matrix)));\n\n  if (m == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for matrix struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  m->data = block->data + MULTIPLICITY * offset;\n  m->size1 = n1;\n  m->size2 = n2;\n  m->tda = d2;\n  m->block = block;\n  m->owner = 0;\n\n  return m;\n}\n\n\nTYPE (gsl_matrix) *\nFUNCTION (gsl_matrix, alloc_from_matrix) (TYPE(gsl_matrix) * mm, \n                                          const size_t k1,\n                                          const size_t k2,\n                                          const size_t n1, \n                                          const size_t n2)\n{\n  TYPE (gsl_matrix) * m;\n\n  if (k1 + n1 > mm->size1)\n    {\n      GSL_ERROR_VAL (\"submatrix dimension 1 exceeds size of original\",\n                        GSL_EINVAL, 0);\n    }\n  else if (k2 + n2 > mm->size2)\n    {\n      GSL_ERROR_VAL (\"submatrix dimension 2 exceeds size of original\",\n                        GSL_EINVAL, 0);\n    }\n\n  m = (TYPE (gsl_matrix) *) malloc (sizeof (TYPE (gsl_matrix)));\n\n  if (m == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for matrix struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  m->data = mm->data + k1 * mm->tda + k2 ;\n  m->size1 = n1;\n  m->size2 = n2;\n  m->tda = mm->tda;\n  m->block = mm->block;\n  m->owner = 0;\n\n  return m;\n}\n\nvoid\nFUNCTION (gsl_matrix, free) (TYPE (gsl_matrix) * m)\n{\n  RETURN_IF_NULL (m);\n\n  if (m->owner)\n    {\n      FUNCTION(gsl_block, free) (m->block);\n    }\n\n  free (m);\n}\nvoid\nFUNCTION (gsl_matrix, set_identity) (TYPE (gsl_matrix) * m)\n{\n  size_t i, j;\n  ATOMIC * const data = m->data;\n  const size_t p = m->size1 ;\n  const size_t q = m->size2 ;\n  const size_t tda = m->tda ;\n\n  const BASE zero = ZERO;\n  const BASE one = ONE;\n\n  for (i = 0; i < p; i++)\n    {\n      for (j = 0; j < q; j++)\n        {\n          *(BASE *) (data + MULTIPLICITY * (i * tda + j)) = ((i == j) ? one : zero);\n        }\n    }\n}\n\nvoid\nFUNCTION (gsl_matrix, set_zero) (TYPE (gsl_matrix) * m)\n{\n  size_t i, j;\n  ATOMIC * const data = m->data;\n  const size_t p = m->size1 ;\n  const size_t q = m->size2 ;\n  const size_t tda = m->tda ;\n\n  const BASE zero = ZERO;\n\n  for (i = 0; i < p; i++)\n    {\n      for (j = 0; j < q; j++)\n        {\n          *(BASE *) (data + MULTIPLICITY * (i * tda + j)) = zero;\n        }\n    }\n}\n\nvoid\nFUNCTION (gsl_matrix, set_all) (TYPE (gsl_matrix) * m, BASE x)\n{\n  size_t i, j;\n  ATOMIC * const data = m->data;\n  const size_t p = m->size1 ;\n  const size_t q = m->size2 ;\n  const size_t tda = m->tda ;\n\n  for (i = 0; i < p; i++)\n    {\n      for (j = 0; j < q; j++)\n        {\n          *(BASE *) (data + MULTIPLICITY * (i * tda + j)) = x;\n        }\n    }\n}\n\n"
  },
  {
    "path": "gsl/matrix/matrix.c",
    "content": "#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_vector.h\"\n\n/* Compile all the inline matrix functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_matrix.h\"\n\n"
  },
  {
    "path": "gsl/matrix/rowcol.c",
    "content": "#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_errno.h\"\n\n#include \"view.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"rowcol_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n\n#define USE_QUALIFIER\n#define QUALIFIER const\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"rowcol_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"rowcol_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/matrix/rowcol_source.inc",
    "content": "/* matrix/rowcol_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, row) (QUALIFIED_TYPE(gsl_matrix) * m, const size_t i)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n  \n  if (i >= m->size1)\n    {\n      GSL_ERROR_VAL (\"row index is out of range\", GSL_EINVAL, view);\n    }\n  \n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + i * MULTIPLICITY * m->tda;\n    v.size = m->size2;\n    v.stride = 1;\n    v.block = m->block;\n    v.owner = 0;\n    \n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, column) (QUALIFIED_TYPE(gsl_matrix) * m, const size_t j)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n  \n  if (j >= m->size2)\n    {\n      GSL_ERROR_VAL (\"column index is out of range\", GSL_EINVAL, view);\n    }\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + j * MULTIPLICITY;\n    v.size = m->size1;\n    v.stride = m->tda;\n    v.block = m->block;\n    v.owner = 0;\n\n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, diagonal) (QUALIFIED_TYPE(gsl_matrix) * m)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n\n  TYPE(gsl_vector) v = NULL_VECTOR;\n  v.data = m->data;\n  v.size = GSL_MIN(m->size1,m->size2);\n  v.stride = m->tda + 1;\n  v.block = m->block;\n  v.owner = 0;\n\n  view.vector = v;\n  return view;\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, subdiagonal) (QUALIFIED_TYPE(gsl_matrix) * m,\n                                    const size_t k)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n  \n  if (k >= m->size1)\n    {\n      GSL_ERROR_VAL (\"subdiagonal index is out of range\", GSL_EINVAL, view);\n    }\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + k * MULTIPLICITY * m->tda;\n    v.size = GSL_MIN(m->size1 - k, m->size2);\n    v.stride = m->tda + 1;\n    v.block = m->block;\n    v.owner = 0;\n    \n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, superdiagonal) (QUALIFIED_TYPE(gsl_matrix) * m,\n                                      const size_t k)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n\n\n  if (k >= m->size2)\n    {\n      GSL_ERROR_VAL (\"column index is out of range\", GSL_EINVAL, view);\n    }\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + k * MULTIPLICITY;\n    v.size = GSL_MIN(m->size1, m->size2 - k);\n    v.stride = m->tda + 1;\n    v.block = m->block;\n    v.owner = 0;\n\n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, subrow) (QUALIFIED_TYPE(gsl_matrix) * m, const size_t i, const size_t offset, const size_t n)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n  \n  if (i >= m->size1)\n    {\n      GSL_ERROR_VAL (\"row index is out of range\", GSL_EINVAL, view);\n    }\n  else if (n == 0)\n    {\n      GSL_ERROR_VAL (\"vector length n must be positive integer\",\n                     GSL_EINVAL, view);\n    }\n  else if (offset + n > m->size2)\n    {\n      GSL_ERROR_VAL (\"dimension n overflows matrix\", GSL_EINVAL, view);\n    }\n  \n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + MULTIPLICITY * (i * m->tda + offset);\n    v.size = n;\n    v.stride = 1;\n    v.block = m->block;\n    v.owner = 0;\n    \n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION (gsl_matrix, subcolumn) (QUALIFIED_TYPE(gsl_matrix) * m, const size_t j, const size_t offset, const size_t n)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n  \n  if (j >= m->size2)\n    {\n      GSL_ERROR_VAL (\"column index is out of range\", GSL_EINVAL, view);\n    }\n  else if (n == 0)\n    {\n      GSL_ERROR_VAL (\"vector length n must be positive integer\",\n                     GSL_EINVAL, view);\n    }\n  else if (offset + n > m->size1)\n    {\n      GSL_ERROR_VAL (\"dimension n overflows matrix\", GSL_EINVAL, view);\n    }\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = m->data + MULTIPLICITY * (offset * m->tda + j);\n    v.size = n;\n    v.stride = m->tda;\n    v.block = m->block;\n    v.owner = 0;\n\n    view.vector = v;\n    return view;\n  }\n}\n"
  },
  {
    "path": "gsl/matrix/submatrix.c",
    "content": "#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_errno.h\"\n\n#include \"view.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"submatrix_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n\n#define USE_QUALIFIER\n#define QUALIFIER const\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"submatrix_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"submatrix_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/matrix/submatrix_source.inc",
    "content": "/* matrix/submatrix_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nQUALIFIED_VIEW(_gsl_matrix,view)\nFUNCTION (gsl_matrix, submatrix) (QUALIFIED_TYPE(gsl_matrix) * m, \n                                  const size_t i, const size_t j,\n                                  const size_t n1, const size_t n2)\n{\n  QUALIFIED_VIEW(_gsl_matrix,view) view = NULL_MATRIX_VIEW; \n\n  if (i >= m->size1)\n    {\n      GSL_ERROR_VAL (\"row index is out of range\", GSL_EINVAL, view);\n    }\n  else if (j >= m->size2)\n    {\n      GSL_ERROR_VAL (\"column index is out of range\", GSL_EINVAL, view);\n    }\n  else if (i + n1 > m->size1)\n    {\n      GSL_ERROR_VAL (\"first dimension overflows matrix\", GSL_EINVAL, view);\n    }\n  else if (j + n2 > m->size2)\n    {\n      GSL_ERROR_VAL (\"second dimension overflows matrix\", GSL_EINVAL, view);\n    }\n\n  {\n     TYPE(gsl_matrix) s = NULL_MATRIX;\n\n     s.data = m->data + MULTIPLICITY * (i * m->tda + j);\n     s.size1 = n1;\n     s.size2 = n2;\n     s.tda = m->tda;\n     s.block = m->block;\n     s.owner = 0;\n     \n     view.matrix = s;     \n     return view;\n  }\n}\n\n"
  },
  {
    "path": "gsl/matrix/swap.c",
    "content": "#include \"config.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_errno.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"swap_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"swap_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/matrix/swap_source.inc",
    "content": "/* matrix/swap_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nint\nFUNCTION (gsl_matrix, swap_rows) (TYPE (gsl_matrix) * m,\n                                 const size_t i, const size_t j)\n{\n  const size_t size1 = m->size1;\n  const size_t size2 = m->size2;\n\n  if (i >= size1)\n    {\n      GSL_ERROR (\"first row index is out of range\", GSL_EINVAL);\n    }\n\n  if (j >= size1)\n    {\n      GSL_ERROR (\"second row index is out of range\", GSL_EINVAL);\n    }\n\n  if (i != j)\n    {\n      ATOMIC *row1 = m->data + MULTIPLICITY * i * m->tda;\n      ATOMIC *row2 = m->data + MULTIPLICITY * j * m->tda;\n      \n      size_t k;\n      \n      for (k = 0; k < MULTIPLICITY * size2; k++)\n        {\n          ATOMIC tmp = row1[k] ;\n          row1[k] = row2[k] ;\n          row2[k] = tmp ;\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\nFUNCTION (gsl_matrix, swap_columns) (TYPE (gsl_matrix) * m,\n                                     const size_t i, const size_t j)\n{\n  const size_t size1 = m->size1;\n  const size_t size2 = m->size2;\n\n  if (i >= size2)\n    {\n      GSL_ERROR (\"first column index is out of range\", GSL_EINVAL);\n    }\n\n  if (j >= size2)\n    {\n      GSL_ERROR (\"second column index is out of range\", GSL_EINVAL);\n    }\n\n  if (i != j)\n    {\n      ATOMIC *col1 = m->data + MULTIPLICITY * i;\n      ATOMIC *col2 = m->data + MULTIPLICITY * j;\n      \n      size_t p;\n      \n      for (p = 0; p < size1; p++)\n        {\n          size_t k;\n          size_t n = p * MULTIPLICITY * m->tda;\n \n          for (k = 0; k < MULTIPLICITY; k++)\n            {\n              ATOMIC tmp = col1[n+k] ;\n              col1[n+k] = col2[n+k] ;\n              col2[n+k] = tmp ;\n            }\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\n\nint\nFUNCTION (gsl_matrix, swap_rowcol) (TYPE (gsl_matrix) * m,\n                                    const size_t i, const size_t j)\n{\n  const size_t size1 = m->size1;\n  const size_t size2 = m->size2;\n\n  if (size1 != size2)\n    {\n      GSL_ERROR (\"matrix must be square to swap row and column\", GSL_ENOTSQR);\n    }\n\n  if (i >= size1)\n    {\n      GSL_ERROR (\"row index is out of range\", GSL_EINVAL);\n    }\n\n  if (j >= size2)\n    {\n      GSL_ERROR (\"column index is out of range\", GSL_EINVAL);\n    }\n\n  {\n    ATOMIC *row = m->data + MULTIPLICITY * i * m->tda;\n    ATOMIC *col = m->data + MULTIPLICITY * j;\n      \n    size_t p;\n    \n    for (p = 0; p < size1; p++)\n      {\n        size_t k;\n\n        size_t r = p * MULTIPLICITY;\n        size_t c = p * MULTIPLICITY * m->tda;\n        \n          for (k = 0; k < MULTIPLICITY; k++)\n            {\n              ATOMIC tmp = col[c+k] ;\n              col[c+k] = row[r+k] ;\n              row[r+k] = tmp ;\n            }\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\n\nint\nFUNCTION (gsl_matrix, transpose) (TYPE (gsl_matrix) * m)\n{\n  const size_t size1 = m->size1;\n  const size_t size2 = m->size2;\n  size_t i, j, k;\n\n  if (size1 != size2)\n    {\n      GSL_ERROR (\"matrix must be square to take transpose\", GSL_ENOTSQR);\n    }\n\n  for (i = 0; i < size1; i++)\n    {\n      for (j = i + 1 ; j < size2 ; j++) \n        {\n          for (k = 0; k < MULTIPLICITY; k++)\n            {\n              size_t e1 = (i *  m->tda + j) * MULTIPLICITY + k ;\n              size_t e2 = (j *  m->tda + i) * MULTIPLICITY + k ;\n              {\n                ATOMIC tmp = m->data[e1] ;\n                m->data[e1] = m->data[e2] ;\n                m->data[e2] = tmp ;\n              }\n            }\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\nFUNCTION (gsl_matrix, transpose_memcpy) (TYPE (gsl_matrix) * dest, \n                                         const TYPE (gsl_matrix) * src)\n{\n  const size_t src_size1 = src->size1;\n  const size_t src_size2 = src->size2;\n\n  const size_t dest_size1 = dest->size1;\n  const size_t dest_size2 = dest->size2;\n\n  size_t i, j, k;\n\n  if (dest_size2 != src_size1 || dest_size1 != src_size2)\n    {\n      GSL_ERROR (\"dimensions of dest matrix must be transpose of src matrix\", \n                 GSL_EBADLEN);\n    }\n\n  for (i = 0; i < dest_size1; i++)\n    {\n      for (j = 0 ; j < dest_size2; j++) \n        {\n          for (k = 0; k < MULTIPLICITY; k++)\n            {\n              size_t e1 = (i *  dest->tda + j) * MULTIPLICITY + k ;\n              size_t e2 = (j *  src->tda + i) * MULTIPLICITY + k ;\n\n              dest->data[e1] = src->data[e2] ;\n            }\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\nFUNCTION (gsl_matrix, transpose_tricpy) (const char uplo_src,\n                                         const int copy_diag, TYPE (gsl_matrix) * dest,\n                                         const TYPE (gsl_matrix) * src)\n{\n  const size_t src_size1 = src->size1;\n  const size_t src_size2 = src->size2;\n  const size_t dest_size1 = dest->size1;\n  const size_t dest_size2 = dest->size2;\n\n  if (src_size1 != dest_size1 || src_size2 != dest_size2)\n    {\n      GSL_ERROR (\"matrix sizes are different\", GSL_EBADLEN);\n    }\n\n  {\n    const size_t src_tda = src->tda ;\n    const size_t dest_tda = dest->tda ;\n    size_t i, j, k;\n\n    if (uplo_src == 'L')\n      {\n        /* copy lower triangle of src to upper triangle of dest */\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (j = 0; j < i; j++)\n              {\n                for (k = 0; k < MULTIPLICITY; k++)\n                  {\n                    size_t e1 = (j *  dest_tda + i) * MULTIPLICITY + k ;\n                    size_t e2 = (i *  src_tda + j) * MULTIPLICITY + k ;\n                    dest->data[e1] = src->data[e2];\n                  }\n              }\n          }\n      }\n    else if (uplo_src == 'U')\n      {\n        /* copy upper triangle of src to lower triangle of dest */\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (j = i + 1; j < src_size2; j++)\n              {\n                for (k = 0; k < MULTIPLICITY; k++)\n                  {\n                    size_t e1 = (j *  dest_tda + i) * MULTIPLICITY + k ;\n                    size_t e2 = (i *  src_tda + j) * MULTIPLICITY + k ;\n                    dest->data[e1] = src->data[e2];\n                  }\n              }\n          }\n      }\n    else\n      {\n        GSL_ERROR (\"invalid uplo_src parameter\", GSL_EINVAL);\n      }\n\n    if (copy_diag)\n      {\n        for (i = 0; i < src_size1 ; i++)\n          {\n            for (k = 0; k < MULTIPLICITY; k++)\n              {\n                size_t e1 = (i * dest_tda + i) * MULTIPLICITY + k ;\n                size_t e2 = (i * src_tda + i) * MULTIPLICITY + k ;\n                dest->data[e1] = src->data[e2];\n              }\n          }\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n"
  },
  {
    "path": "gsl/matrix/view.h",
    "content": "#define NULL_VECTOR {0, 0, 0, 0, 0}\n#define NULL_VECTOR_VIEW {{0, 0, 0, 0, 0}}\n\n#define NULL_MATRIX {0, 0, 0, 0, 0, 0}\n#define NULL_MATRIX_VIEW {{0, 0, 0, 0, 0, 0}}\n"
  },
  {
    "path": "gsl/permutation/gsl_permutation.h",
    "content": "/* permutation/gsl_permutation.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_PERMUTATION_H__\n#define __GSL_PERMUTATION_H__\n\n#include <stdlib.h>\n#include \"gsl_types.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_inline.h\"\n#include \"gsl_check_range.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nstruct gsl_permutation_struct\n{\n  size_t size;\n  size_t *data;\n};\n\ntypedef struct gsl_permutation_struct gsl_permutation;\n\ngsl_permutation *gsl_permutation_alloc (const size_t n);\ngsl_permutation *gsl_permutation_calloc (const size_t n);\nvoid gsl_permutation_init (gsl_permutation * p);\nvoid gsl_permutation_free (gsl_permutation * p);\nint gsl_permutation_memcpy (gsl_permutation * dest, const gsl_permutation * src);\n\nint gsl_permutation_fread (FILE * stream, gsl_permutation * p);\nint gsl_permutation_fwrite (FILE * stream, const gsl_permutation * p);\nint gsl_permutation_fscanf (FILE * stream, gsl_permutation * p);\nint gsl_permutation_fprintf (FILE * stream, const gsl_permutation * p, const char *format);\n\nsize_t gsl_permutation_size (const gsl_permutation * p);\nsize_t * gsl_permutation_data (const gsl_permutation * p);\n\nint gsl_permutation_swap (gsl_permutation * p, const size_t i, const size_t j);\n\nint gsl_permutation_valid (const gsl_permutation * p);\nvoid gsl_permutation_reverse (gsl_permutation * p);\nint gsl_permutation_inverse (gsl_permutation * inv, const gsl_permutation * p);\nint gsl_permutation_next (gsl_permutation * p);\nint gsl_permutation_prev (gsl_permutation * p);\nint gsl_permutation_mul (gsl_permutation * p, const gsl_permutation * pa, const gsl_permutation * pb);\n\nint gsl_permutation_linear_to_canonical (gsl_permutation * q, const gsl_permutation * p);\nint gsl_permutation_canonical_to_linear (gsl_permutation * p, const gsl_permutation * q);\n\nsize_t gsl_permutation_inversions (const gsl_permutation * p);\nsize_t gsl_permutation_linear_cycles (const gsl_permutation * p);\nsize_t gsl_permutation_canonical_cycles (const gsl_permutation * q);\n\nINLINE_DECL size_t gsl_permutation_get (const gsl_permutation * p, const size_t i);\n\n#ifdef HAVE_INLINE\n\nINLINE_FUN\nsize_t\ngsl_permutation_get (const gsl_permutation * p, const size_t i)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(i >= p->size))\n    {\n      GSL_ERROR_VAL (\"index out of range\", GSL_EINVAL, 0);\n    }\n#endif\n  return p->data[i];\n}\n\n#endif /* HAVE_INLINE */\n\n__END_DECLS\n\n#endif /* __GSL_PERMUTATION_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute.h",
    "content": "#ifndef __GSL_PERMUTE_H__\n#define __GSL_PERMUTE_H__\n\n/*#include <gsl/gsl_permute_complex_long_double.h>\n#include <gsl/gsl_permute_complex_double.h>\n#include <gsl/gsl_permute_complex_float.h>\n\n#include <gsl/gsl_permute_long_double.h>*/\n#include \"gsl_permute_double.h\"\n/*#include <gsl/gsl_permute_float.h>\n\n#include <gsl/gsl_permute_ulong.h>\n#include <gsl/gsl_permute_long.h>\n\n#include <gsl/gsl_permute_uint.h>\n#include <gsl/gsl_permute_int.h>\n\n#include <gsl/gsl_permute_ushort.h>\n#include <gsl/gsl_permute_short.h>\n\n#include <gsl/gsl_permute_uchar.h>\n#include <gsl/gsl_permute_char.h>*/\n\n#endif /* __GSL_PERMUTE_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute_double.h",
    "content": "/* permutation/gsl_permute_double.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_PERMUTE_DOUBLE_H__\n#define __GSL_PERMUTE_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_permutation.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nint gsl_permute (const size_t * p, double * data, const size_t stride, const size_t n);\nint gsl_permute_inverse (const size_t * p, double * data, const size_t stride, const size_t n);\n\n__END_DECLS\n\n#endif /* __GSL_PERMUTE_DOUBLE_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute_matrix.h",
    "content": "#ifndef __GSL_PERMUTE_MATRIX_H__\n#define __GSL_PERMUTE_MATRIX_H__\n\n/*#include <gsl/gsl_permute_matrix_complex_long_double.h>\n#include <gsl/gsl_permute_matrix_complex_double.h>\n#include <gsl/gsl_permute_matrix_complex_float.h>\n\n#include <gsl/gsl_permute_matrix_long_double.h>*/\n#include \"gsl_permute_matrix_double.h\"\n/*#include <gsl/gsl_permute_matrix_float.h>\n\n#include <gsl/gsl_permute_matrix_ulong.h>\n#include <gsl/gsl_permute_matrix_long.h>\n\n#include <gsl/gsl_permute_matrix_uint.h>\n#include <gsl/gsl_permute_matrix_int.h>\n\n#include <gsl/gsl_permute_matrix_ushort.h>\n#include <gsl/gsl_permute_matrix_short.h>\n\n#include <gsl/gsl_permute_matrix_uchar.h>\n#include <gsl/gsl_permute_matrix_char.h>*/\n\n#endif /* __GSL_PERMUTE_MATRIX_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute_matrix_double.h",
    "content": "/* permutation/gsl_permute_matrix_double.h\n * \n * Copyright (C) 2016 Patrick Alken\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_PERMUTE_MATRIX_DOUBLE_H__\n#define __GSL_PERMUTE_MATRIX_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_permutation.h\"\n#include \"gsl_matrix_double.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nint gsl_permute_matrix (const gsl_permutation * p, gsl_matrix * A);\n\n__END_DECLS\n\n#endif /* __GSL_PERMUTE_MATRIX_DOUBLE_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute_vector.h",
    "content": "#ifndef __GSL_PERMUTE_VECTOR_H__\n#define __GSL_PERMUTE_VECTOR_H__\n\n//#include \"gsl_permute_vector_complex_long_double.h\"\n//#include \"gsl_permute_vector_complex_double.h\"\n//#include \"gsl_permute_vector_complex_float.h\"\n//\n//#include \"gsl_permute_vector_long_double.h\"\n#include \"gsl_permute_vector_double.h\"\n//#include \"gsl_permute_vector_float.h\"\n//\n//#include \"gsl_permute_vector_ulong.h\"\n//#include \"gsl_permute_vector_long.h\"\n//\n//#include \"gsl_permute_vector_uint.h\"\n//#include \"gsl_permute_vector_int.h\"\n//\n//#include \"gsl_permute_vector_ushort.h\"\n//#include \"gsl_permute_vector_short.h\"\n//\n//#include \"gsl_permute_vector_uchar.h\"\n//#include \"gsl_permute_vector_char.h\"\n\n#endif /* __GSL_PERMUTE_VECTOR_H__ */\n"
  },
  {
    "path": "gsl/permutation/gsl_permute_vector_double.h",
    "content": "/* permutation/gsl_permute_vector_double.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_PERMUTE_VECTOR_DOUBLE_H__\n#define __GSL_PERMUTE_VECTOR_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_permutation.h\"\n#include \"gsl_vector_double.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nint gsl_permute_vector (const gsl_permutation * p, gsl_vector * v);\nint gsl_permute_vector_inverse (const gsl_permutation * p, gsl_vector * v);\n\n__END_DECLS\n\n#endif /* __GSL_PERMUTE_VECTOR_DOUBLE_H__ */\n"
  },
  {
    "path": "gsl/permutation/init.c",
    "content": "/* permutation/init.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_errno.h\"\n#include \"gsl_permutation.h\"\n\ngsl_permutation *\ngsl_permutation_alloc (const size_t n)\n{\n  gsl_permutation * p;\n\n  if (n == 0)\n    {\n      GSL_ERROR_VAL (\"permutation length n must be positive integer\",\n                        GSL_EDOM, 0);\n    }\n\n  p = (gsl_permutation *) malloc (sizeof (gsl_permutation));\n\n  if (p == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for permutation struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  p->data = (size_t *) malloc (n * sizeof (size_t));\n\n  if (p->data == 0)\n    {\n      free (p);         /* exception in constructor, avoid memory leak */\n\n      GSL_ERROR_VAL (\"failed to allocate space for permutation data\",\n                        GSL_ENOMEM, 0);\n    }\n\n  p->size = n;\n\n  return p;\n}\n\ngsl_permutation *\ngsl_permutation_calloc (const size_t n)\n{\n  size_t i;\n\n  gsl_permutation * p =  gsl_permutation_alloc (n);\n\n  if (p == 0)\n    return 0;\n\n  /* initialize permutation to identity */\n\n  for (i = 0; i < n; i++)\n    {\n      p->data[i] = i;\n    }\n\n  return p;\n}\n\nvoid\ngsl_permutation_init (gsl_permutation * p)\n{\n  const size_t n = p->size ;\n  size_t i;\n\n  /* initialize permutation to identity */\n\n  for (i = 0; i < n; i++)\n    {\n      p->data[i] = i;\n    }\n}\n\nvoid\ngsl_permutation_free (gsl_permutation * p)\n{\n  RETURN_IF_NULL (p);\n  free (p->data);\n  free (p);\n}\n"
  },
  {
    "path": "gsl/permutation/permutation.c",
    "content": "/* permutation/permutation.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_permutation.h\"\n\nsize_t\ngsl_permutation_size (const gsl_permutation * p)\n{\n  return p->size ;\n}\n\nsize_t *\ngsl_permutation_data (const gsl_permutation * p)\n{\n  return p->data ;\n}\n\nint\ngsl_permutation_swap (gsl_permutation * p, const size_t i, const size_t j)\n{\n  const size_t size = p->size ;\n  \n  if (i >= size)\n    {\n      GSL_ERROR(\"first index is out of range\", GSL_EINVAL);\n    }\n\n  if (j >= size)\n    {\n      GSL_ERROR(\"second index is out of range\", GSL_EINVAL);\n    }\n\n  if (i != j)\n    {\n      size_t tmp = p->data[i];\n      p->data[i] = p->data[j];\n      p->data[j] = tmp;\n    }\n  \n  return GSL_SUCCESS;\n}\n\n\nint\ngsl_permutation_valid (const gsl_permutation * p)\n{\n  const size_t size = p->size ;\n\n  size_t i, j ;\n\n  for (i = 0; i < size; i++) \n    {\n      if (p->data[i] >= size)\n        {\n          GSL_ERROR(\"permutation index outside range\", GSL_FAILURE) ;\n        }\n\n      for (j = 0; j < i; j++)\n        {\n          if (p->data[i] == p->data[j])\n            {\n              GSL_ERROR(\"duplicate permutation index\", GSL_FAILURE) ;\n            }\n        }\n    }\n  \n  return GSL_SUCCESS;\n}\n\nvoid\ngsl_permutation_reverse (gsl_permutation * p)\n{\n  const size_t size = p->size ;\n\n  size_t i ;\n  \n  for (i = 0; i < (size / 2); i++) \n    {\n      size_t j = size - i - 1;\n\n      size_t tmp = p->data[i] ;\n      p->data[i] = p->data[j] ;\n      p->data[j] = tmp ;\n    }\n}\n\nint \ngsl_permutation_inverse (gsl_permutation * inv, const gsl_permutation * p)\n{\n  const size_t size = p->size ;\n\n  size_t i ;\n\n  if (inv->size != size)\n    {\n      GSL_ERROR(\"permutation lengths are not equal\", GSL_EBADLEN);\n    }\n  \n  for (i = 0; i < size; i++) \n    {\n      inv->data[p->data[i]] = i ;\n    }\n  \n  return GSL_SUCCESS ;\n}\n\nint\ngsl_permutation_next (gsl_permutation * p)\n{\n  /* Replaces p with the next permutation (in the standard lexicographical\n   * ordering).  Returns GSL_FAILURE if there is no next permutation.\n   */\n  const size_t size = p->size;\n  size_t i, j, k;\n\n  if (size < 2)\n    {\n      return GSL_FAILURE;\n    }\n\n  i = size - 2;\n\n  while ((p->data[i] > p->data[i+1]) && (i != 0))\n    {\n      i--;\n    }\n\n  if ((i == 0) && (p->data[0] > p->data[1]))\n    {\n     return GSL_FAILURE;\n    }\n\n  k = i + 1;\n\n  for (j = i + 2; j < size; j++ )\n    {\n      if ((p->data[j] > p->data[i]) && (p->data[j] < p->data[k]))\n        {\n          k = j;\n        }\n    }\n\n  /* swap i and k */\n\n  {\n    size_t tmp = p->data[i];\n    p->data[i] = p->data[k];\n    p->data[k] = tmp;\n  }\n\n  for (j = i + 1; j <= ((size + i) / 2); j++)\n    {\n      size_t tmp = p->data[j];\n      p->data[j] = p->data[size + i - j];\n      p->data[size + i - j] = tmp;\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\ngsl_permutation_prev (gsl_permutation * p)\n{\n  const size_t size = p->size;\n  size_t i, j, k;\n\n  if (size < 2)\n    {\n      return GSL_FAILURE;\n    }\n\n  i = size - 2;\n\n  while ((p->data[i] < p->data[i+1]) && (i != 0))\n    {\n      i--;\n    }\n\n  if ((i == 0) && (p->data[0] < p->data[1]))\n    {\n      return GSL_FAILURE;\n    }\n\n  k = i + 1;\n\n  for (j = i + 2; j < size; j++ )\n    {\n      if ((p->data[j] < p->data[i]) && (p->data[j] > p->data[k]))\n        {\n          k = j;\n        }\n    }\n\n  /* swap i and k */\n\n  {\n    size_t tmp = p->data[i];\n    p->data[i] = p->data[k];\n    p->data[k] = tmp;\n  }\n\n  for (j = i + 1; j <= ((size + i) / 2); j++)\n    {\n      size_t tmp = p->data[j];\n      p->data[j] = p->data[size + i - j];\n      p->data[size + i - j] = tmp;\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\ngsl_permutation_mul (gsl_permutation * p, const gsl_permutation * pa, const gsl_permutation * pb)\n{\n  size_t i;\n  const size_t size = p->size;\n\n  if (pa->size != size)\n    {\n      GSL_ERROR(\"size of result does not match size of pa\", GSL_EINVAL);\n    }\n\n  if (pb->size != size)\n    {\n      GSL_ERROR(\"size of result does not match size of pb\", GSL_EINVAL);\n    }\n\n  for (i = 0; i < size; i++)\n    {\n      p->data[i] = pb->data[pa->data[i]];\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\ngsl_permutation_memcpy (gsl_permutation * dest,\n                        const gsl_permutation * src)\n{\n  const size_t src_size = src->size;\n  const size_t dest_size = dest->size;\n\n  if (src_size != dest_size)\n    {\n      GSL_ERROR (\"permutation lengths are not equal\", GSL_EBADLEN);\n    }\n\n  {\n    size_t j;\n\n    for (j = 0; j < src_size; j++)\n      {\n        dest->data[j] = src->data[j];\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n"
  },
  {
    "path": "gsl/permutation/permute.c",
    "content": "#include \"config.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_permute.h\"\n#include \"gsl_permute_vector.h\"\n#include \"gsl_permute_matrix.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"permute_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"permute_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/permutation/permute_source.inc",
    "content": "/* permutation/permute_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* In-place Permutations \n\n   permute:    OUT[i]       = IN[perm[i]]     i = 0 .. N-1\n   invpermute: OUT[perm[i]] = IN[i]           i = 0 .. N-1\n\n   PERM is an index map, i.e. a vector which contains a permutation of\n   the integers 0 .. N-1.\n\n   From Knuth \"Sorting and Searching\", Volume 3 (3rd ed), Section 5.2\n   Exercise 10 (answers), p 617\n\n   FIXME: these have not been fully tested.\n*/\n\nint\nTYPE (gsl_permute) (const size_t * p, ATOMIC * data, const size_t stride, const size_t n)\n{\n  size_t i, k, pk;\n\n  for (i = 0; i < n; i++)\n    {\n      k = p[i];\n      \n      while (k > i) \n        k = p[k];\n      \n      if (k < i)\n        continue ;\n      \n      /* Now have k == i, i.e the least in its cycle */\n      \n      pk = p[k];\n      \n      if (pk == i)\n        continue ;\n      \n      /* shuffle the elements of the cycle */\n      \n      {\n        unsigned int a;\n\n        ATOMIC t[MULTIPLICITY];\n        \n        for (a = 0; a < MULTIPLICITY; a++)\n          t[a] = data[i*stride*MULTIPLICITY + a];\n      \n        while (pk != i)\n          {\n            for (a = 0; a < MULTIPLICITY; a++)\n              {\n                ATOMIC r1 = data[pk*stride*MULTIPLICITY + a];\n                data[k*stride*MULTIPLICITY + a] = r1;\n              }\n            k = pk;\n            pk = p[k];\n          };\n        \n        for (a = 0; a < MULTIPLICITY; a++)\n          data[k*stride*MULTIPLICITY + a] = t[a];\n      }\n    }\n\n  return GSL_SUCCESS;\n}\n\nint\nFUNCTION (gsl_permute,inverse) (const size_t * p, ATOMIC * data, const size_t stride, const size_t n)\n{\n  size_t i, k, pk;\n\n  for (i = 0; i < n; i++)\n    {\n      k = p[i];\n          \n      while (k > i) \n        k = p[k];\n\n      if (k < i)\n        continue ;\n      \n      /* Now have k == i, i.e the least in its cycle */\n\n      pk = p[k];\n\n      if (pk == i)\n        continue ;\n      \n      /* shuffle the elements of the cycle in the inverse direction */\n      \n      {\n        unsigned int a;\n\n        ATOMIC t[MULTIPLICITY];\n\n        for (a = 0; a < MULTIPLICITY; a++)\n          t[a] = data[k*stride*MULTIPLICITY+a];\n\n        while (pk != i)\n          {\n            for (a = 0; a < MULTIPLICITY; a++)\n              {\n                ATOMIC r1 = data[pk*stride*MULTIPLICITY + a];\n                data[pk*stride*MULTIPLICITY + a] = t[a];\n                t[a] = r1;\n              }\n\n            k = pk;\n            pk = p[k];\n          };\n\n        for (a = 0; a < MULTIPLICITY; a++)\n          data[pk*stride*MULTIPLICITY+a] = t[a];\n      }\n    }\n\n  return GSL_SUCCESS;\n}\n\n\nint\nTYPE (gsl_permute_vector) (const gsl_permutation * p, TYPE (gsl_vector) * v)\n{\n  if (v->size != p->size)\n    {\n      GSL_ERROR (\"vector and permutation must be the same length\", GSL_EBADLEN);\n    }\n\n  TYPE (gsl_permute) (p->data, v->data, v->stride, v->size) ;\n\n  return GSL_SUCCESS;\n}\n\nint\nFUNCTION (gsl_permute_vector,inverse) (const gsl_permutation * p, TYPE (gsl_vector) * v)\n{\n  if (v->size != p->size)\n    {\n      GSL_ERROR (\"vector and permutation must be the same length\", GSL_EBADLEN);\n    }\n\n  FUNCTION (gsl_permute,inverse) (p->data, v->data, v->stride, v->size) ;\n\n  return GSL_SUCCESS;\n}\n\nint\nTYPE (gsl_permute_matrix) (const gsl_permutation * p, TYPE (gsl_matrix) * A)\n{\n  if (A->size2 != p->size)\n    {\n      GSL_ERROR (\"matrix columns and permutation must be the same length\", GSL_EBADLEN);\n    }\n  else\n    {\n      size_t i;\n\n      for (i = 0; i < A->size1; ++i)\n        {\n          QUALIFIED_VIEW (gsl_vector, view) r = FUNCTION (gsl_matrix, row) (A, i);\n\n          TYPE (gsl_permute_vector) (p, &r.vector);\n        }\n\n      return GSL_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/beta.c",
    "content": "/* randist/beta.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_sf_gamma.h\"\n\n/* The beta distribution has the form\n\n   p(x) dx = (Gamma(a + b)/(Gamma(a) Gamma(b))) x^(a-1) (1-x)^(b-1) dx\n\n   The method used here is the one described in Knuth */\n\ndouble\ngsl_ran_beta (const gsl_rng * r, const double a, const double b)\n{\n\tif ( (a <= 1.0) && (b <= 1.0) )\n\t{\n\t\tdouble U, V, X, Y;\n\t\twhile (1)\n\t\t{\n\t\t\tU = gsl_rng_uniform_pos(r);\n\t\t\tV = gsl_rng_uniform_pos(r);\n\t\t\tX = pow(U, 1.0/a);\n\t\t\tY = pow(V, 1.0/b);\n\t\t\tif ((X + Y ) <= 1.0)\n\t\t\t{\n\t\t\t\tif (X + Y > 0)\n\t\t\t\t{\n\t\t\t\t\treturn X/ (X + Y);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdouble logX = log(U)/a;\n\t\t\t\t\tdouble logY = log(V)/b;\n\t\t\t\t\tdouble logM = logX > logY ? logX: logY;\n\t\t\t\t\tlogX -= logM;\n\t\t\t\t\tlogY -= logM;\n\t\t\t\t\treturn exp(logX - log(exp(logX) + exp(logY)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble x1 = gsl_ran_gamma (r, a, 1.0);\n\t\tdouble x2 = gsl_ran_gamma (r, b, 1.0);\n\t\treturn x1 / (x1 + x2);\n\t}\n}\n\ndouble\ngsl_ran_beta_pdf (const double x, const double a, const double b)\n{\n  if (x < 0 || x > 1)\n    {\n      return 0 ;\n    }\n  else \n    {\n      double p;\n\n      double gab = gsl_sf_lngamma (a + b);\n      double ga = gsl_sf_lngamma (a);\n      double gb = gsl_sf_lngamma (b);\n      \n      if (x == 0.0 || x == 1.0) \n        {\n\t  if (a > 1.0 && b > 1.0)\n\t    {\n\t      p = 0.0;\n\t    }\n\t  else\n\t    {\n\t      p = exp (gab - ga - gb) * pow (x, a - 1) * pow (1 - x, b - 1);\n\t    }\n        }\n      else\n        {\n          p = exp (gab - ga - gb + log(x) * (a - 1)  + log1p(-x) * (b - 1));\n        }\n\n      return p;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/binomial_tpe.c",
    "content": "/* randist/binomial_tpe.c\n * \n * Copyright (C) 1996, 2003, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_pow_int.h\"\n#include \"gsl_sf_gamma.h\"\n\n/* The binomial distribution has the form,\n\n   f(x) =  n!/(x!(n-x)!) * p^x (1-p)^(n-x) for integer 0 <= x <= n\n        =  0                               otherwise\n\n   This implementation follows the public domain ranlib function\n   \"ignbin\", the bulk of which is the BTPE (Binomial Triangle\n   Parallelogram Exponential) algorithm introduced in\n   Kachitvichyanukul and Schmeiser[1].  It has been translated to use\n   modern C coding standards.\n\n   If n is small and/or p is near 0 or near 1 (specifically, if\n   n*min(p,1-p) < SMALL_MEAN), then a different algorithm, called\n   BINV, is used which has an average runtime that scales linearly\n   with n*min(p,1-p).\n\n   But for larger problems, the BTPE algorithm takes the form of two\n   functions b(x) and t(x) -- \"bottom\" and \"top\" -- for which b(x) <\n   f(x)/f(M) < t(x), with M = floor(n*p+p).  b(x) defines a triangular\n   region, and t(x) includes a parallelogram and two tails.  Details\n   (including a nice drawing) are in the paper.\n\n   [1] Kachitvichyanukul, V. and Schmeiser, B. W.  Binomial Random\n   Variate Generation.  Communications of the ACM, 31, 2 (February,\n   1988) 216.\n\n   Note, Bruce Schmeiser (personal communication) points out that if\n   you want very fast binomial deviates, and you are happy with\n   approximate results, and/or n and n*p are both large, then you can\n   just use gaussian estimates: mean=n*p, variance=n*p*(1-p).\n\n   This implementation by James Theiler, April 2003, after obtaining\n   permission -- and some good advice -- from Drs. Kachitvichyanukul\n   and Schmeiser to use their code as a starting point, and then doing\n   a little bit of tweaking.\n\n   Additional polishing for GSL coding standards by Brian Gough.  */\n\n#define SMALL_MEAN 14           /* If n*p < SMALL_MEAN then use BINV\n                                   algorithm. The ranlib\n                                   implementation used cutoff=30; but\n                                   on my computer 14 works better */\n\n#define BINV_CUTOFF 110         /* In BINV, do not permit ix too large */\n\n#define FAR_FROM_MEAN 20        /* If ix-n*p is larger than this, then\n                                   use the \"squeeze\" algorithm.\n                                   Ranlib used 20, and this seems to\n                                   be the best choice on my machine as\n                                   well */\n\n#define LNFACT(x) gsl_sf_lnfact(x)\n\ninline static double\nStirling (double y1)\n{\n  double y2 = y1 * y1;\n  double s =\n    (13860.0 -\n     (462.0 - (132.0 - (99.0 - 140.0 / y2) / y2) / y2) / y2) / y1 / 166320.0;\n  return s;\n}\n\nunsigned int\ngsl_ran_binomial_tpe (const gsl_rng * rng, double p, unsigned int n)\n{\n  return gsl_ran_binomial (rng, p, n);\n}\n\nunsigned int\ngsl_ran_binomial (const gsl_rng * rng, double p, unsigned int n)\n{\n  int ix;                       /* return value */\n  int flipped = 0;\n  double q, s, np;\n\n  if (n == 0)\n    return 0;\n\n  if (p > 0.5)\n    {\n      p = 1.0 - p;              /* work with small p */\n      flipped = 1;\n    }\n\n  q = 1 - p;\n  s = p / q;\n  np = n * p;\n\n  /* Inverse cdf logic for small mean (BINV in K+S) */\n\n  if (np < SMALL_MEAN)\n    {\n      double f0 = gsl_pow_uint (q, n);   /* f(x), starting with x=0 */\n\n      while (1)\n        {\n          /* This while(1) loop will almost certainly only loop once; but\n           * if u=1 to within a few epsilons of machine precision, then it\n           * is possible for roundoff to prevent the main loop over ix to\n           * achieve its proper value.  following the ranlib implementation,\n           * we introduce a check for that situation, and when it occurs,\n           * we just try again.\n           */\n\n          double f = f0;\n          double u = gsl_rng_uniform (rng);\n\n          for (ix = 0; ix <= BINV_CUTOFF; ++ix)\n            {\n              if (u < f)\n                goto Finish;\n              u -= f;\n              /* Use recursion f(x+1) = f(x)*[(n-x)/(x+1)]*[p/(1-p)] */\n              f *= s * (n - ix) / (ix + 1);\n            }\n\n          /* It should be the case that the 'goto Finish' was encountered\n           * before this point was ever reached.  But if we have reached\n           * this point, then roundoff has prevented u from decreasing\n           * all the way to zero.  This can happen only if the initial u\n           * was very nearly equal to 1, which is a rare situation.  In\n           * that rare situation, we just try again.\n           *\n           * Note, following the ranlib implementation, we loop ix only to\n           * a hardcoded value of SMALL_MEAN_LARGE_N=110; we could have\n           * looped to n, and 99.99...% of the time it won't matter.  This\n           * choice, I think is a little more robust against the rare\n           * roundoff error.  If n>LARGE_N, then it is technically\n           * possible for ix>LARGE_N, but it is astronomically rare, and\n           * if ix is that large, it is more likely due to roundoff than\n           * probability, so better to nip it at LARGE_N than to take a\n           * chance that roundoff will somehow conspire to produce an even\n           * larger (and more improbable) ix.  If n<LARGE_N, then once\n           * ix=n, f=0, and the loop will continue until ix=LARGE_N.\n           */\n        }\n    }\n  else\n    {\n      /* For n >= SMALL_MEAN, we invoke the BTPE algorithm */\n\n      int k;\n\n      double ffm = np + p;      /* ffm = n*p+p             */\n      int m = (int) ffm;        /* m = int floor[n*p+p]    */\n      double fm = m;            /* fm = double m;          */\n      double xm = fm + 0.5;     /* xm = half integer mean (tip of triangle)  */\n      double npq = np * q;      /* npq = n*p*q            */\n\n      /* Compute cumulative area of tri, para, exp tails */\n\n      /* p1: radius of triangle region; since height=1, also: area of region */\n      /* p2: p1 + area of parallelogram region */\n      /* p3: p2 + area of left tail */\n      /* p4: p3 + area of right tail */\n      /* pi/p4: probability of i'th area (i=1,2,3,4) */\n\n      /* Note: magic numbers 2.195, 4.6, 0.134, 20.5, 15.3 */\n      /* These magic numbers are not adjustable...at least not easily! */\n\n      double p1 = floor (2.195 * sqrt (npq) - 4.6 * q) + 0.5;\n\n      /* xl, xr: left and right edges of triangle */\n      double xl = xm - p1;\n      double xr = xm + p1;\n\n      /* Parameter of exponential tails */\n      /* Left tail:  t(x) = c*exp(-lambda_l*[xl - (x+0.5)]) */\n      /* Right tail: t(x) = c*exp(-lambda_r*[(x+0.5) - xr]) */\n\n      double c = 0.134 + 20.5 / (15.3 + fm);\n      double p2 = p1 * (1.0 + c + c);\n\n      double al = (ffm - xl) / (ffm - xl * p);\n      double lambda_l = al * (1.0 + 0.5 * al);\n      double ar = (xr - ffm) / (xr * q);\n      double lambda_r = ar * (1.0 + 0.5 * ar);\n      double p3 = p2 + c / lambda_l;\n      double p4 = p3 + c / lambda_r;\n\n      double var, accept;\n      double u, v;              /* random variates */\n\n    TryAgain:\n\n      /* generate random variates, u specifies which region: Tri, Par, Tail */\n      u = gsl_rng_uniform (rng) * p4;\n      v = gsl_rng_uniform (rng);\n\n      if (u <= p1)\n        {\n          /* Triangular region */\n          ix = (int) (xm - p1 * v + u);\n          goto Finish;\n        }\n      else if (u <= p2)\n        {\n          /* Parallelogram region */\n          double x = xl + (u - p1) / c;\n          v = v * c + 1.0 - fabs (x - xm) / p1;\n          if (v > 1.0 || v <= 0.0)\n            goto TryAgain;\n          ix = (int) x;\n        }\n      else if (u <= p3)\n        {\n          /* Left tail */\n          ix = (int) (xl + log (v) / lambda_l);\n          if (ix < 0)\n            goto TryAgain;\n          v *= ((u - p2) * lambda_l);\n        }\n      else\n        {\n          /* Right tail */\n          ix = (int) (xr - log (v) / lambda_r);\n          if (ix > (double) n)\n            goto TryAgain;\n          v *= ((u - p3) * lambda_r);\n        }\n\n      /* At this point, the goal is to test whether v <= f(x)/f(m) \n       *\n       *  v <= f(x)/f(m) = (m!(n-m)! / (x!(n-x)!)) * (p/q)^{x-m}\n       *\n       */\n\n      /* Here is a direct test using logarithms.  It is a little\n       * slower than the various \"squeezing\" computations below, but\n       * if things are working, it should give exactly the same answer\n       * (given the same random number seed).  */\n\n#ifdef DIRECT\n      var = log (v);\n\n      accept =\n        LNFACT (m) + LNFACT (n - m) - LNFACT (ix) - LNFACT (n - ix)\n        + (ix - m) * log (p / q);\n\n#else /* SQUEEZE METHOD */\n\n      /* More efficient determination of whether v < f(x)/f(M) */\n\n      k = abs (ix - m);\n\n      if (k <= FAR_FROM_MEAN)\n        {\n          /* \n           * If ix near m (ie, |ix-m|<FAR_FROM_MEAN), then do\n           * explicit evaluation using recursion relation for f(x)\n           */\n          double g = (n + 1) * s;\n          double f = 1.0;\n\n          var = v;\n\n          if (m < ix)\n            {\n              int i;\n              for (i = m + 1; i <= ix; i++)\n                {\n                  f *= (g / i - s);\n                }\n            }\n          else if (m > ix)\n            {\n              int i;\n              for (i = ix + 1; i <= m; i++)\n                {\n                  f /= (g / i - s);\n                }\n            }\n\n          accept = f;\n        }\n      else\n        {\n          /* If ix is far from the mean m: k=ABS(ix-m) large */\n\n          var = log (v);\n\n          if (k < npq / 2 - 1)\n            {\n              /* \"Squeeze\" using upper and lower bounds on\n               * log(f(x)) The squeeze condition was derived\n               * under the condition k < npq/2-1 */\n              double amaxp =\n                k / npq * ((k * (k / 3.0 + 0.625) + (1.0 / 6.0)) / npq + 0.5);\n              double ynorm = -(k * k / (2.0 * npq));\n              if (var < ynorm - amaxp)\n                goto Finish;\n              if (var > ynorm + amaxp)\n                goto TryAgain;\n            }\n\n          /* Now, again: do the test log(v) vs. log f(x)/f(M) */\n\n#if USE_EXACT\n          /* This is equivalent to the above, but is a little (~20%) slower */\n          /* There are five log's vs three above, maybe that's it? */\n\n          accept = LNFACT (m) + LNFACT (n - m)\n            - LNFACT (ix) - LNFACT (n - ix) + (ix - m) * log (p / q);\n\n#else /* USE STIRLING */\n          /* The \"#define Stirling\" above corresponds to the first five\n           * terms in asymptoic formula for\n           * log Gamma (y) - (y-0.5)log(y) + y - 0.5 log(2*pi);\n           * See Abramowitz and Stegun, eq 6.1.40\n           */\n\n          /* Note below: two Stirling's are added, and two are\n           * subtracted.  In both K+S, and in the ranlib\n           * implementation, all four are added.  I (jt) believe that\n           * is a mistake -- this has been confirmed by personal\n           * correspondence w/ Dr. Kachitvichyanukul.  Note, however,\n           * the corrections are so small, that I couldn't find an\n           * example where it made a difference that could be\n           * observed, let alone tested.  In fact, define'ing Stirling\n           * to be zero gave identical results!!  In practice, alv is\n           * O(1), ranging 0 to -10 or so, while the Stirling\n           * correction is typically O(10^{-5}) ...setting the\n           * correction to zero gives about a 2% performance boost;\n           * might as well keep it just to be pendantic.  */\n\n          {\n            double x1 = ix + 1.0;\n            double w1 = n - ix + 1.0;\n            double f1 = fm + 1.0;\n            double z1 = n + 1.0 - fm;\n\n            accept = xm * log (f1 / x1) + (n - m + 0.5) * log (z1 / w1)\n              + (ix - m) * log (w1 * p / (x1 * q))\n              + Stirling (f1) + Stirling (z1) - Stirling (x1) - Stirling (w1);\n          }\n#endif\n#endif\n        }\n\n\n      if (var <= accept)\n        {\n          goto Finish;\n        }\n      else\n        {\n          goto TryAgain;\n        }\n    }\n\nFinish:\n\n  return (flipped) ? (n - ix) : (unsigned int)ix;\n}\n"
  },
  {
    "path": "gsl/randist/cauchy.c",
    "content": "/* randist/cauchy.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The Cauchy probability distribution is \n\n   p(x) dx = (1/(pi a)) (1 + (x/a)^2)^(-1) dx\n\n   It is also known as the Lorentzian probability distribution */\n\ndouble\ngsl_ran_cauchy (const gsl_rng * r, const double a)\n{\n  double u;\n  do\n    {\n      u = gsl_rng_uniform (r);\n    }\n  while (u == 0.5);\n\n  return a * tan (M_PI * u);\n}\n\ndouble\ngsl_ran_cauchy_pdf (const double x, const double a)\n{\n  double u = x / a;\n  double p = (1 / (M_PI * a)) / (1 + u * u);\n  return p;\n}\n"
  },
  {
    "path": "gsl/randist/chisq.c",
    "content": "/* randist/chisq.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The chisq distribution has the form\n\n   p(x) dx = (1/(2*Gamma(nu/2))) (x/2)^(nu/2 - 1) exp(-x/2) dx\n\n   for x = 0 ... +infty */\n\ndouble\ngsl_ran_chisq (const gsl_rng * r, const double nu)\n{\n  double chisq = 2 * gsl_ran_gamma (r, nu / 2, 1.0);\n  return chisq;\n}\n\ndouble\ngsl_ran_chisq_pdf (const double x, const double nu)\n{\n  if (x < 0)\n    {\n      return 0 ;\n    }\n  else\n    {\n      if(nu == 2.0)\n        {\n          return exp(-x/2.0) / 2.0;\n        }\n      else\n        {\n          double p;\n          double lngamma = gsl_sf_lngamma (nu / 2);\n\n          p = exp ((nu / 2 - 1) * log (x/2) - x/2 - lngamma) / 2;\n          return p;\n        }\n    }\n}\n"
  },
  {
    "path": "gsl/randist/dirichlet.c",
    "content": "/* randist/dirichlet.c\n * \n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 2002 Gavin E. Crooks <gec@compbio.berkeley.edu>\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_sf_gamma.h\"\n\n\n/* The Dirichlet probability distribution of order K-1 is \n\n     p(\\theta_1,...,\\theta_K) d\\theta_1 ... d\\theta_K = \n        (1/Z) \\prod_i=1,K \\theta_i^{alpha_i - 1} \\delta(1 -\\sum_i=1,K \\theta_i)\n\n   The normalization factor Z can be expressed in terms of gamma functions:\n\n      Z = {\\prod_i=1,K \\Gamma(\\alpha_i)} / {\\Gamma( \\sum_i=1,K \\alpha_i)}  \n\n   The K constants, \\alpha_1,...,\\alpha_K, must be positive. The K parameters, \n   \\theta_1,...,\\theta_K are nonnegative and sum to 1.\n\n   The random variates are generated by sampling K values from gamma\n   distributions with parameters a=\\alpha_i, b=1, and renormalizing. \n   See A.M. Law, W.D. Kelton, Simulation Modeling and Analysis (1991).\n\n   Gavin E. Crooks <gec@compbio.berkeley.edu> (2002)\n*/\n\nstatic void ran_dirichlet_small (const gsl_rng * r, const size_t K, const double alpha[], double theta[]);\n\nvoid\ngsl_ran_dirichlet (const gsl_rng * r, const size_t K,\n                   const double alpha[], double theta[])\n{\n  size_t i;\n  double norm = 0.0;\n\n  for (i = 0; i < K; i++)\n    {\n      theta[i] = gsl_ran_gamma (r, alpha[i], 1.0);\n    }\n  \n  for (i = 0; i < K; i++)\n    {\n      norm += theta[i];\n    }\n\n  if (norm < GSL_SQRT_DBL_MIN)  /* Handle underflow */\n    {\n      ran_dirichlet_small (r, K, alpha, theta);\n      return;\n    }\n\n  for (i = 0; i < K; i++)\n    {\n      theta[i] /= norm;\n    }\n}\n\n\n/* When the values of alpha[] are small, scale the variates to avoid\n   underflow so that the result is not 0/0.  Note that the Dirichlet\n   distribution is defined by a ratio of gamma functions so we can\n   take out an arbitrary factor to keep the values in the range of\n   double precision. */\n\nstatic void \nran_dirichlet_small (const gsl_rng * r, const size_t K,\n                     const double alpha[], double theta[])\n{\n  size_t i;\n  double norm = 0.0, umax = 0;\n\n  for (i = 0; i < K; i++)\n    {\n      double u = log(gsl_rng_uniform_pos (r)) / alpha[i];\n      \n      theta[i] = u;\n\n      if (u > umax || i == 0) {\n        umax = u;\n      }\n    }\n  \n  for (i = 0; i < K; i++)\n    {\n      theta[i] = exp(theta[i] - umax);\n    }\n  \n  for (i = 0; i < K; i++)\n    {\n      theta[i] = theta[i] * gsl_ran_gamma (r, alpha[i] + 1.0, 1.0);\n    }\n\n  for (i = 0; i < K; i++)\n    {\n      norm += theta[i];\n    }\n\n  for (i = 0; i < K; i++)\n    {\n      theta[i] /= norm;\n    }\n}\n\n\n\n\n\ndouble\ngsl_ran_dirichlet_pdf (const size_t K,\n                       const double alpha[], const double theta[])\n{\n  return exp (gsl_ran_dirichlet_lnpdf (K, alpha, theta));\n}\n\ndouble\ngsl_ran_dirichlet_lnpdf (const size_t K,\n                         const double alpha[], const double theta[])\n{\n  /*We calculate the log of the pdf to minimize the possibility of overflow */\n  size_t i;\n  double log_p = 0.0;\n  double sum_alpha = 0.0;\n\n  for (i = 0; i < K; i++)\n    {\n      log_p += (alpha[i] - 1.0) * log (theta[i]);\n    }\n\n  for (i = 0; i < K; i++)\n    {\n      sum_alpha += alpha[i];\n    }\n\n  log_p += gsl_sf_lngamma (sum_alpha);\n\n  for (i = 0; i < K; i++)\n    {\n      log_p -= gsl_sf_lngamma (alpha[i]);\n    }\n\n  return log_p;\n}\n"
  },
  {
    "path": "gsl/randist/discrete.c",
    "content": "/* randist/discrete.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License along\n * with this library; if not, write to the Free Software Foundation, Inc.,\n * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n   Random Discrete Events\n   \n   Given K discrete events with different probabilities P[k]\n   produce a value k consistent with its probability.\n\n   This program is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 3 of the\n   License, or (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   General Public License for more details.  You should have received\n   a copy of the GNU General Public License along with this library; if\n   not, write to the Free Software Foundation, Inc., 51 Franklin Street,\n   Fifth Floor, Boston, MA 02110-1301, USA.\n*/\n\n/*\n * Based on: Alastair J Walker, An efficient method for generating\n * discrete random variables with general distributions, ACM Trans\n * Math Soft 3, 253-256 (1977).  See also: D. E. Knuth, The Art of\n * Computer Programming, Volume 2 (Seminumerical algorithms), 3rd\n * edition, Addison-Wesley (1997), p120.\n\n * Walker's algorithm does some preprocessing, and provides two\n * arrays: floating point F[k] and integer A[k].  A value k is chosen\n * from 0..K-1 with equal likelihood, and then a uniform random number\n * u is compared to F[k].  If it is less than F[k], then k is\n * returned.  Otherwise, A[k] is returned.\n   \n * Walker's original paper describes an O(K^2) algorithm for setting\n * up the F and A arrays.  I found this disturbing since I wanted to\n * use very large values of K.  I'm sure I'm not the first to realize\n * this, but in fact the preprocessing can be done in O(K) steps.\n\n * A figure of merit for the preprocessing is the average value for\n * the F[k]'s (that is, SUM_k F[k]/K); this corresponds to the\n * probability that k is returned, instead of A[k], thereby saving a\n * redirection.  Walker's O(K^2) preprocessing will generally improve\n * that figure of merit, compared to my cheaper O(K) method; from some\n * experiments with a perl script, I get values of around 0.6 for my\n * method and just under 0.75 for Walker's.  Knuth has pointed out\n * that finding _the_ optimum lookup tables, which maximize the\n * average F[k], is a combinatorially difficult problem.  But any\n * valid preprocessing will still provide O(1) time for the call to\n * gsl_ran_discrete().  I find that if I artificially set F[k]=1 --\n * ie, better than optimum! -- I get a speedup of maybe 20%, so that's\n * the maximum I could expect from the most expensive preprocessing.\n * Folding in the difference of 0.6 vs 0.75, I'd estimate that the\n * speedup would be less than 10%.\n\n * I've not implemented it here, but one compromise is to sort the\n * probabilities once, and then work from the two ends inward.  This\n * requires O(K log K), still lots cheaper than O(K^2), and from my\n * experiments with the perl script, the figure of merit is within\n * about 0.01 for K up to 1000, and no sign of diverging (in fact,\n * they seemed to be converging, but it's hard to say with just a\n * handful of runs).\n\n * The O(K) algorithm goes through all the p_k's and decides if they\n * are \"smalls\" or \"bigs\" according to whether they are less than or\n * greater than the mean value 1/K.  The indices to the smalls and the\n * bigs are put in separate stacks, and then we work through the\n * stacks together.  For each small, we pair it up with the next big\n * in the stack (Walker always wanted to pair up the smallest small\n * with the biggest big).  The small \"borrows\" from the big just\n * enough to bring the small up to mean.  This reduces the size of the\n * big, so the (smaller) big is compared again to the mean, and if it\n * is smaller, it gets \"popped\" from the big stack and \"pushed\" to the\n * small stack.  Otherwise, it stays put.  Since every time we pop a\n * small, we are able to deal with it right then and there, and we\n * never have to pop more than K smalls, then the algorithm is O(K).\n\n * This implementation sets up two separate stacks, and allocates K\n * elements between them.  Since neither stack ever grows, we do an\n * extra O(K) pass through the data to determine how many smalls and\n * bigs there are to begin with and allocate appropriately.  In all\n * there are 2*K*sizeof(double) transient bytes of memory that are\n * used than returned, and K*(sizeof(int)+sizeof(double)) bytes used\n * in the lookup table.\n   \n * Walker spoke of using two random numbers (an integer 0..K-1, and a\n * floating point u in [0,1]), but Knuth points out that one can just\n * use the integer and fractional parts of K*u where u is in [0,1].\n * In fact, Knuth further notes that taking F'[k]=(k+F[k])/K, one can\n * directly compare u to F'[k] without having to explicitly set\n * u=K*u-int(K*u).\n\n * Usage:\n\n * Starting with an array of probabilities P, initialize and do\n * preprocessing with a call to:\n\n *    gsl_rng *r;\n *    gsl_ran_discrete_t *f;\n *    f = gsl_ran_discrete_preproc(K,P);\n   \n * Then, whenever a random index 0..K-1 is desired, use\n\n *    k = gsl_ran_discrete(r,f);\n\n * Note that several different randevent struct's can be\n * simultaneously active.\n\n * Aside: A very clever alternative approach is described in\n * Abramowitz and Stegun, p 950, citing: Marsaglia, Random variables\n * and computers, Proc Third Prague Conference in Probability Theory,\n * 1962.  A more accesible reference is: G. Marsaglia, Generating\n * discrete random numbers in a computer, Comm ACM 6, 37-38 (1963).\n * If anybody is interested, I (jt) have also coded up this version as\n * part of another software package.  However, I've done some\n * comparisons, and the Walker method is both faster and more stingy\n * with memory.  So, in the end I decided not to include it with the\n * GSL package.\n   \n * Written 26 Jan 1999, James Theiler, jt@lanl.gov\n * Adapted to GSL, 30 Jan 1999, jt\n\n */\n\n#include \"config.h\"\n#include <stdio.h>              /* used for NULL, also fprintf(stderr,...) */\n#include <stdlib.h>             /* used for malloc's */\n#include <math.h>\n#include \"gsl_errno.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#define KNUTH_CONVENTION 1      /* Saves a few steps of arithmetic\n                                 * in the call to gsl_ran_discrete()\n                                 */\n\n/*** Begin Stack (this code is used just in this file) ***/\n\n/* Stack code converted to use unsigned indices (i.e. s->i == 0 now\n   means an empty stack, instead of -1), for consistency and to give a\n   bigger allowable range. BJG */\n\ntypedef struct {\n    size_t N;                      /* max number of elts on stack */\n    size_t *v;                     /* array of values on the stack */\n    size_t i;                      /* index of top of stack */\n} gsl_stack_t;\n\nstatic gsl_stack_t *\nnew_stack(size_t N) {\n    gsl_stack_t *s;\n    s = (gsl_stack_t *)malloc(sizeof(gsl_stack_t));\n    s->N = N;\n    s->i = 0;                  /* indicates stack is empty */\n    s->v = (size_t *)malloc(sizeof(size_t)*N);\n    return s;\n}\n\nstatic int\npush_stack(gsl_stack_t *s, size_t v)\n{\n    if ((s->i) >= (s->N)) {\n      return -1; /* stack overflow (shouldn't happen) */\n    }\n    (s->v)[s->i] = v;\n    s->i += 1;\n    return 0;\n}\n\nstatic size_t pop_stack(gsl_stack_t *s)\n{\n    if ((s->i) == 0) {\n      GSL_ERROR (\"internal error - stack exhausted\", GSL_ESANITY);\n    }\n    s->i -= 1;\n    return ((s->v)[s->i]);\n}\n\nstatic inline size_t size_stack(const gsl_stack_t *s)\n{\n    return s->i;\n}\n\nstatic void free_stack(gsl_stack_t *s)\n{\n    free((char *)(s->v));\n    free((char *)s);\n}\n\n/*** End Stack ***/\n\n\n/*** Begin Walker's Algorithm ***/\n\ngsl_ran_discrete_t *\ngsl_ran_discrete_preproc(size_t Kevents, const double *ProbArray)\n{\n    size_t k,b,s;\n    gsl_ran_discrete_t *g;\n    size_t nBigs, nSmalls;\n    gsl_stack_t *Bigs;\n    gsl_stack_t *Smalls;\n    double *E;\n    double pTotal = 0.0, mean, d;\n    \n    if (Kevents < 1) {\n      /* Could probably treat Kevents=1 as a special case */\n\n      GSL_ERROR_VAL (\"number of events must be a positive integer\", \n                        GSL_EINVAL, 0);\n    }\n\n    /* Make sure elements of ProbArray[] are positive.\n     * Won't enforce that sum is unity; instead will just normalize\n     */\n\n    for (k=0; k<Kevents; ++k) {\n        if (ProbArray[k] < 0) {\n          GSL_ERROR_VAL (\"probabilities must be non-negative\",\n                            GSL_EINVAL, 0) ;\n        }\n        pTotal += ProbArray[k];\n    }\n\n    /* Begin setting up the main \"object\" (just a struct, no steroids) */\n    g = (gsl_ran_discrete_t *)malloc(sizeof(gsl_ran_discrete_t));\n    g->K = Kevents;\n    g->F = (double *)malloc(sizeof(double)*Kevents);\n    g->A = (size_t *)malloc(sizeof(size_t)*Kevents);\n\n    E = (double *)malloc(sizeof(double)*Kevents);\n\n    if (E==NULL) {\n      GSL_ERROR_VAL (\"Cannot allocate memory for randevent\", GSL_ENOMEM, 0);\n    }\n\n    for (k=0; k<Kevents; ++k) {\n        E[k] = ProbArray[k]/pTotal;\n    }\n\n    /* Now create the Bigs and the Smalls */\n    mean = 1.0/Kevents;\n    nSmalls=nBigs=0;\n    {\n      /* Temporarily use which[k] = g->A[k] to indicate small or large */\n      size_t * const which = g->A;\n\n      for (k=0; k<Kevents; ++k) {\n        if (E[k] < mean) { \n          ++nSmalls; which[k] = 0;\n        } else { \n          ++nBigs; which[k] = 1; \n        }\n      }\n\n      Bigs   = new_stack(nBigs);\n      Smalls = new_stack(nSmalls);\n      for (k=0; k<Kevents; ++k) {\n        gsl_stack_t * Dest = which[k] ? Bigs : Smalls;\n        int status = push_stack(Dest,k);\n        if (status)\n          GSL_ERROR_VAL (\"failed to build stacks\", GSL_EFAILED, 0);\n      }\n    }\n\n    /* Now work through the smalls */\n    while (size_stack(Smalls) > 0) {\n        s = pop_stack(Smalls);\n        if (size_stack(Bigs) == 0) {\n            (g->A)[s]=s;\n            (g->F)[s]=1.0;\n            continue;\n        }\n        b = pop_stack(Bigs);\n        (g->A)[s]=b;\n        (g->F)[s]=Kevents*E[s];\n        d = mean - E[s];\n        E[s] += d;              /* now E[s] == mean */\n        E[b] -= d;\n        if (E[b] < mean) {\n            push_stack(Smalls,b); /* no longer big, join ranks of the small */\n        }\n        else if (E[b] > mean) {\n            push_stack(Bigs,b); /* still big, put it back where you found it */\n        }\n        else {\n            /* E[b]==mean implies it is finished too */\n            (g->A)[b]=b;\n            (g->F)[b]=1.0;\n        }\n    }\n    while (size_stack(Bigs) > 0) {\n        b = pop_stack(Bigs);\n        (g->A)[b]=b;\n        (g->F)[b]=1.0;\n    }\n    /* Stacks have been emptied, and A and F have been filled */\n\n    if ( size_stack(Smalls) != 0) {\n      GSL_ERROR_VAL (\"Smalls stack has not been emptied\",\n                     GSL_ESANITY, 0 );\n    }\n    \n#if 0\n    /* if 1, then artificially set all F[k]'s to unity.  This will\n     * give wrong answers, but you'll get them faster.  But, not\n     * that much faster (I get maybe 20%); that's an upper bound\n     * on what the optimal preprocessing would give.\n     */\n    for (k=0; k<Kevents; ++k) {\n        (g->F)[k] = 1.0;\n    }\n#endif\n\n#if KNUTH_CONVENTION\n    /* For convenience, set F'[k]=(k+F[k])/K */\n    /* This saves some arithmetic in gsl_ran_discrete(); I find that\n     * it doesn't actually make much difference.\n     */\n    for (k=0; k<Kevents; ++k) {\n        (g->F)[k] += k;\n        (g->F)[k] /= Kevents;\n    }\n#endif    \n\n    free_stack(Bigs);\n    free_stack(Smalls);\n    free((char *)E);\n\n    return g;\n}\n\nsize_t\ngsl_ran_discrete(const gsl_rng *r, const gsl_ran_discrete_t *g)\n{\n    size_t c=0;\n    double u,f;\n    u = gsl_rng_uniform(r);\n#if KNUTH_CONVENTION\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\tc = (u*(g->K));\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n#else\n    u *= g->K;\n    c = u;\n    u -= c;\n#endif\n    f = (g->F)[c];\n    /* fprintf(stderr,\"c,f,u: %d %.4f %f\\n\",c,f,u); */\n    if (f == 1.0) return c;\n\n    if (u < f) {\n        return c;\n    }\n    else {\n        return (g->A)[c];\n    }\n}\n\nvoid gsl_ran_discrete_free(gsl_ran_discrete_t *g)\n{\n    RETURN_IF_NULL (g);\n    free((char *)(g->A));\n    free((char *)(g->F));\n    free((char *)g);\n}\n\ndouble\ngsl_ran_discrete_pdf(size_t k, const gsl_ran_discrete_t *g)\n{\n    size_t i,K;\n    double f,p=0;\n    K= g->K;\n    if (k>K) return 0;\n    for (i=0; i<K; ++i) {\n        f = (g->F)[i];\n#if KNUTH_CONVENTION\n        f = K*f-i;\n#endif        \n        if (i==k) {\n            p += f;\n        } else if (k == (g->A)[i]) {\n            p += 1.0 - f;\n        }\n    }\n    return p/K;\n}\n"
  },
  {
    "path": "gsl/randist/exponential.c",
    "content": "/* randist/exponential.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2009 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The exponential distribution has the form\n\n   p(x) dx = exp(-x/mu) dx/mu\n\n   for x = 0 ... +infty */\n\ndouble\ngsl_ran_exponential (const gsl_rng * r, const double mu)\n{\n  double u = gsl_rng_uniform (r);\n\n  return -mu * log1p (-u);\n}\n\ndouble\ngsl_ran_exponential_pdf (const double x, const double mu)\n{\n  if (x < 0)\n    {\n      return 0 ;\n    }\n  else\n    {\n      double p = exp (-x/mu)/mu;\n      \n      return p;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/fdist.c",
    "content": "/* randist/fdist.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2010 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The F distribution has the form\n\n   p(x) dx = (nu1^(nu1/2) nu2^(nu2/2) Gamma((nu1 + nu2)/2) /\n   Gamma(nu1/2) Gamma(nu2/2)) *\n   x^(nu1/2 - 1) (nu2 + nu1 * x)^(-nu1/2 -nu2/2) dx\n\n   The method used here is the one described in Knuth */\n\ndouble\ngsl_ran_fdist (const gsl_rng * r, const double nu1, const double nu2)\n{\n\n  double Y1 =  gsl_ran_gamma (r, nu1 / 2, 2.0);\n  double Y2 =  gsl_ran_gamma (r, nu2 / 2, 2.0);\n\n  double f = (Y1 * nu2) / (Y2 * nu1);\n\n  return f;\n}\n\n"
  },
  {
    "path": "gsl/randist/gamma.c",
    "content": "/* randist/gamma.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\nstatic double gamma_large (const gsl_rng * r, const double a);\nstatic double gamma_frac (const gsl_rng * r, const double a);\n\n/* The Gamma distribution of order a>0 is defined by:\n\n   p(x) dx = {1 / \\Gamma(a) b^a } x^{a-1} e^{-x/b} dx\n\n   for x>0.  If X and Y are independent gamma-distributed random\n   variables of order a1 and a2 with the same scale parameter b, then\n   X+Y has gamma distribution of order a1+a2.\n\n   The algorithms below are from Knuth, vol 2, 2nd ed, p. 129. */\n\ndouble\ngsl_ran_gamma_knuth (const gsl_rng * r, const double a, const double b)\n{\n  /* assume a > 0 */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\tunsigned int na = floor (a);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\n  if(a >= UINT_MAX) \n    {\n      return b * (gamma_large (r, floor (a)) + gamma_frac (r, a - floor (a)));\n    }\n  else if (a == na)\n    {\n      return b * gsl_ran_gamma_int (r, na);\n    }\n  else if (na == 0)\n    {\n      return b * gamma_frac (r, a);\n    }\n  else\n    {\n      return b * (gsl_ran_gamma_int (r, na) + gamma_frac (r, a - na)) ;\n    }\n}\n\ndouble\ngsl_ran_gamma_int (const gsl_rng * r, const unsigned int a)\n{\n  if (a < 12)\n    {\n      unsigned int i;\n      double prod = 1;\n\n      for (i = 0; i < a; i++)\n        {\n          prod *= gsl_rng_uniform_pos (r);\n        }\n\n      /* Note: for 12 iterations we are safe against underflow, since\n         the smallest positive random number is O(2^-32). This means\n         the smallest possible product is 2^(-12*32) = 10^-116 which\n         is within the range of double precision. */\n\n      return -log (prod);\n    }\n  else\n    {\n      return gamma_large (r, (double) a);\n    }\n}\n\nstatic double\ngamma_large (const gsl_rng * r, const double a)\n{\n  /* Works only if a > 1, and is most efficient if a is large\n\n     This algorithm, reported in Knuth, is attributed to Ahrens.  A\n     faster one, we are told, can be found in: J. H. Ahrens and\n     U. Dieter, Computing 12 (1974) 223-246.  */\n\n  double sqa, x, y, v;\n  sqa = sqrt (2 * a - 1);\n  do\n    {\n      do\n        {\n          y = tan (M_PI * gsl_rng_uniform (r));\n          x = sqa * y + a - 1;\n        }\n      while (x <= 0);\n      v = gsl_rng_uniform (r);\n    }\n  while (v > (1 + y * y) * exp ((a - 1) * log (x / (a - 1)) - sqa * y));\n\n  return x;\n}\n\nstatic double\ngamma_frac (const gsl_rng * r, const double a)\n{\n  /* This is exercise 16 from Knuth; see page 135, and the solution is\n     on page 551.  */\n\n  double p, q, x, u, v;\n\n  if (a == 0) {\n    return 0;\n  }\n\n  p = M_E / (a + M_E);\n  do\n    {\n      u = gsl_rng_uniform (r);\n      v = gsl_rng_uniform_pos (r);\n\n      if (u < p)\n        {\n          x = exp ((1 / a) * log (v));\n          q = exp (-x);\n        }\n      else\n        {\n          x = 1 - log (v);\n          q = exp ((a - 1) * log (x));\n        }\n    }\n  while (gsl_rng_uniform (r) >= q);\n\n  return x;\n}\n\ndouble\ngsl_ran_gamma_pdf (const double x, const double a, const double b)\n{\n  if (x < 0)\n    {\n      return 0 ;\n    }\n  else if (x == 0)\n    {\n      if (a == 1)\n        return 1/b ;\n      else\n        return 0 ;\n    }\n  else if (a == 1)\n    {\n      return exp(-x/b)/b ;\n    }\n  else \n    {\n      double p;\n      double lngamma = gsl_sf_lngamma (a);\n      p = exp ((a - 1) * log (x/b) - x/b - lngamma)/b;\n      return p;\n    }\n}\n\n\n/* New version based on Marsaglia and Tsang, \"A Simple Method for\n * generating gamma variables\", ACM Transactions on Mathematical\n * Software, Vol 26, No 3 (2000), p363-372.\n *\n * Implemented by J.D.Lamb@btinternet.com, minor modifications for GSL\n * by Brian Gough\n */\n\ndouble\ngsl_ran_gamma_mt (const gsl_rng * r, const double a, const double b)\n{\n  return gsl_ran_gamma (r, a, b);\n}\n\ndouble\ngsl_ran_gamma (const gsl_rng * r, const double a, const double b)\n{\n  /* assume a > 0 */\n\n  if (a < 1)\n    {\n      double u = gsl_rng_uniform_pos (r);\n      return gsl_ran_gamma (r, 1.0 + a, b) * pow (u, 1.0 / a);\n    }\n\n  {\n    double x, v, u;\n    double d = a - 1.0 / 3.0;\n    double c = (1.0 / 3.0) / sqrt (d);\n\n    while (1)\n      {\n        do\n          {\n            x = gsl_ran_gaussian_ziggurat (r, 1.0);\n            v = 1.0 + c * x;\n          }\n        while (v <= 0);\n\n        v = v * v * v;\n        u = gsl_rng_uniform_pos (r);\n\n        if (u < 1 - 0.0331 * x * x * x * x) \n          break;\n\n        if (log (u) < 0.5 * x * x + d * (1 - v + log (v)))\n          break;\n      }\n    \n    return b * d * v;\n  }\n}\n"
  },
  {
    "path": "gsl/randist/gauss.c",
    "content": "/* randist/gauss.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2006, 2007 James Theiler, Brian Gough\n * Copyright (C) 2006 Charles Karney\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* Of the two methods provided below, I think the Polar method is more\n * efficient, but only when you are actually producing two random\n * deviates.  We don't produce two, because then we'd have to save one\n * in a static variable for the next call, and that would screws up\n * re-entrant or threaded code, so we only produce one.  This makes\n * the Ratio method suddenly more appealing.\n *\n * [Added by Charles Karney] We use Leva's implementation of the Ratio\n * method which avoids calling log() nearly all the time and makes the\n * Ratio method faster than the Polar method (when it produces just one\n * result per call).  Timing per call (gcc -O2 on 866MHz Pentium,\n * average over 10^8 calls)\n *\n *   Polar method: 660 ns\n *   Ratio method: 368 ns\n *\n */\n\n/* Polar (Box-Mueller) method; See Knuth v2, 3rd ed, p122 */\n\ndouble\ngsl_ran_gaussian (const gsl_rng * r, const double sigma)\n{\n  double x, y, r2;\n\n  do\n    {\n      /* choose x,y in uniform square (-1,-1) to (+1,+1) */\n      x = -1 + 2 * gsl_rng_uniform_pos (r);\n      y = -1 + 2 * gsl_rng_uniform_pos (r);\n\n      /* see if it is in the unit circle */\n      r2 = x * x + y * y;\n    }\n  while (r2 > 1.0 || r2 == 0);\n\n  /* Box-Muller transform */\n  return sigma * y * sqrt (-2.0 * log (r2) / r2);\n}\n\n/* Ratio method (Kinderman-Monahan); see Knuth v2, 3rd ed, p130.\n * K+M, ACM Trans Math Software 3 (1977) 257-260.\n *\n * [Added by Charles Karney] This is an implementation of Leva's\n * modifications to the original K+M method; see:\n * J. L. Leva, ACM Trans Math Software 18 (1992) 449-453 and 454-455. */\n\ndouble\ngsl_ran_gaussian_ratio_method (const gsl_rng * r, const double sigma)\n{\n  double u, v, x, y, Q;\n  const double s = 0.449871;    /* Constants from Leva */\n  const double t = -0.386595;\n  const double a = 0.19600;\n  const double b = 0.25472;\n  const double r1 = 0.27597;\n  const double r2 = 0.27846;\n\n  do                            /* This loop is executed 1.369 times on average  */\n    {\n      /* Generate a point P = (u, v) uniform in a rectangle enclosing\n         the K+M region v^2 <= - 4 u^2 log(u). */\n\n      /* u in (0, 1] to avoid singularity at u = 0 */\n      u = 1 - gsl_rng_uniform (r);\n\n      /* v is in the asymmetric interval [-0.5, 0.5).  However v = -0.5\n         is rejected in the last part of the while clause.  The\n         resulting normal deviate is strictly symmetric about 0\n         (provided that v is symmetric once v = -0.5 is excluded). */\n      v = gsl_rng_uniform (r) - 0.5;\n\n      /* Constant 1.7156 > sqrt(8/e) (for accuracy); but not by too\n         much (for efficiency). */\n      v *= 1.7156;\n\n      /* Compute Leva's quadratic form Q */\n      x = u - s;\n      y = fabs (v) - t;\n      Q = x * x + y * (a * y - b * x);\n\n      /* Accept P if Q < r1 (Leva) */\n      /* Reject P if Q > r2 (Leva) */\n      /* Accept if v^2 <= -4 u^2 log(u) (K+M) */\n      /* This final test is executed 0.012 times on average. */\n    }\n  while (Q >= r1 && (Q > r2 || v * v > -4 * u * u * log (u)));\n\n  return sigma * (v / u);       /* Return slope */\n}\n\ndouble\ngsl_ran_gaussian_pdf (const double x, const double sigma)\n{\n  double u = x / fabs (sigma);\n  double p = (1 / (sqrt (2 * M_PI) * fabs (sigma))) * exp (-u * u / 2);\n  return p;\n}\n\ndouble\ngsl_ran_ugaussian (const gsl_rng * r)\n{\n  return gsl_ran_gaussian (r, 1.0);\n}\n\ndouble\ngsl_ran_ugaussian_ratio_method (const gsl_rng * r)\n{\n  return gsl_ran_gaussian_ratio_method (r, 1.0);\n}\n\ndouble\ngsl_ran_ugaussian_pdf (const double x)\n{\n  return gsl_ran_gaussian_pdf (x, 1.0);\n}\n\n"
  },
  {
    "path": "gsl/randist/gausszig.c",
    "content": "/* gauss.c - gaussian random numbers, using the Ziggurat method\n *\n * Copyright (C) 2005  Jochen Voss.\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License along\n * with this library; if not, write to the Free Software Foundation, Inc.,\n * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/*\n * This routine is based on the following article, with a couple of\n * modifications which simplify the implementation.\n *\n *     George Marsaglia, Wai Wan Tsang\n *     The Ziggurat Method for Generating Random Variables\n *     Journal of Statistical Software, vol. 5 (2000), no. 8\n *     http://www.jstatsoft.org/v05/i08/\n *\n * The modifications are:\n *\n * 1) use 128 steps instead of 256 to decrease the amount of static\n * data necessary.  \n *\n * 2) use an acceptance sampling from an exponential wedge\n * exp(-R*(x-R/2)) for the tail of the base strip to simplify the\n * implementation.  The area of exponential wedge is used in\n * calculating 'v' and the coefficients in ziggurat table, so the\n * coefficients differ slightly from those in the Marsaglia and Tsang\n * paper.\n *\n * See also Leong et al, \"A Comment on the Implementation of the\n * Ziggurat Method\", Journal of Statistical Software, vol 5 (2005), no 7.\n *\n */\n\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* position of right-most step */\n#define PARAM_R 3.44428647676\n\n/* tabulated values for the heigt of the Ziggurat levels */\nstatic const double ytab[128] = {\n  1, 0.963598623011, 0.936280813353, 0.913041104253,\n  0.892278506696, 0.873239356919, 0.855496407634, 0.838778928349,\n  0.822902083699, 0.807732738234, 0.793171045519, 0.779139726505,\n  0.765577436082, 0.752434456248, 0.739669787677, 0.727249120285,\n  0.715143377413, 0.703327646455, 0.691780377035, 0.68048276891,\n  0.669418297233, 0.65857233912, 0.647931876189, 0.637485254896,\n  0.62722199145, 0.617132611532, 0.607208517467, 0.597441877296,\n  0.587825531465, 0.578352913803, 0.569017984198, 0.559815170911,\n  0.550739320877, 0.541785656682, 0.532949739145, 0.524227434628,\n  0.515614886373, 0.507108489253, 0.498704867478, 0.490400854812,\n  0.482193476986, 0.47407993601, 0.466057596125, 0.458123971214,\n  0.450276713467, 0.442513603171, 0.434832539473, 0.427231532022,\n  0.419708693379, 0.41226223212, 0.404890446548, 0.397591718955,\n  0.390364510382, 0.383207355816, 0.376118859788, 0.369097692334,\n  0.362142585282, 0.355252328834, 0.348425768415, 0.341661801776,\n  0.334959376311, 0.328317486588, 0.321735172063, 0.31521151497,\n  0.308745638367, 0.302336704338, 0.29598391232, 0.289686497571,\n  0.283443729739, 0.27725491156, 0.271119377649, 0.265036493387,\n  0.259005653912, 0.253026283183, 0.247097833139, 0.241219782932,\n  0.235391638239, 0.229612930649, 0.223883217122, 0.218202079518,\n  0.212569124201, 0.206983981709, 0.201446306496, 0.195955776745,\n  0.190512094256, 0.185114984406, 0.179764196185, 0.174459502324,\n  0.169200699492, 0.1639876086, 0.158820075195, 0.153697969964,\n  0.148621189348, 0.143589656295, 0.138603321143, 0.133662162669,\n  0.128766189309, 0.123915440582, 0.119109988745, 0.114349940703,\n  0.10963544023, 0.104966670533, 0.100343857232, 0.0957672718266,\n  0.0912372357329, 0.0867541250127, 0.082318375932, 0.0779304915295,\n  0.0735910494266, 0.0693007111742, 0.065060233529, 0.0608704821745,\n  0.056732448584, 0.05264727098, 0.0486162607163, 0.0446409359769,\n  0.0407230655415, 0.0368647267386, 0.0330683839378, 0.0293369977411,\n  0.0256741818288, 0.0220844372634, 0.0185735200577, 0.0151490552854,\n  0.0118216532614, 0.00860719483079, 0.00553245272614, 0.00265435214565\n};\n\n/* tabulated values for 2^24 times x[i]/x[i+1],\n * used to accept for U*x[i+1]<=x[i] without any floating point operations */\nstatic const unsigned long ktab[128] = {\n  0, 12590644, 14272653, 14988939,\n  15384584, 15635009, 15807561, 15933577,\n  16029594, 16105155, 16166147, 16216399,\n  16258508, 16294295, 16325078, 16351831,\n  16375291, 16396026, 16414479, 16431002,\n  16445880, 16459343, 16471578, 16482744,\n  16492970, 16502368, 16511031, 16519039,\n  16526459, 16533352, 16539769, 16545755,\n  16551348, 16556584, 16561493, 16566101,\n  16570433, 16574511, 16578353, 16581977,\n  16585398, 16588629, 16591685, 16594575,\n  16597311, 16599901, 16602354, 16604679,\n  16606881, 16608968, 16610945, 16612818,\n  16614592, 16616272, 16617861, 16619363,\n  16620782, 16622121, 16623383, 16624570,\n  16625685, 16626730, 16627708, 16628619,\n  16629465, 16630248, 16630969, 16631628,\n  16632228, 16632768, 16633248, 16633671,\n  16634034, 16634340, 16634586, 16634774,\n  16634903, 16634972, 16634980, 16634926,\n  16634810, 16634628, 16634381, 16634066,\n  16633680, 16633222, 16632688, 16632075,\n  16631380, 16630598, 16629726, 16628757,\n  16627686, 16626507, 16625212, 16623794,\n  16622243, 16620548, 16618698, 16616679,\n  16614476, 16612071, 16609444, 16606571,\n  16603425, 16599973, 16596178, 16591995,\n  16587369, 16582237, 16576520, 16570120,\n  16562917, 16554758, 16545450, 16534739,\n  16522287, 16507638, 16490152, 16468907,\n  16442518, 16408804, 16364095, 16301683,\n  16207738, 16047994, 15704248, 15472926\n};\n\n/* tabulated values of 2^{-24}*x[i] */\nstatic const double wtab[128] = {\n  1.62318314817e-08, 2.16291505214e-08, 2.54246305087e-08, 2.84579525938e-08,\n  3.10340022482e-08, 3.33011726243e-08, 3.53439060345e-08, 3.72152672658e-08,\n  3.8950989572e-08, 4.05763964764e-08, 4.21101548915e-08, 4.35664624904e-08,\n  4.49563968336e-08, 4.62887864029e-08, 4.75707945735e-08, 4.88083237257e-08,\n  5.00063025384e-08, 5.11688950428e-08, 5.22996558616e-08, 5.34016475624e-08,\n  5.44775307871e-08, 5.55296344581e-08, 5.65600111659e-08, 5.75704813695e-08,\n  5.85626690412e-08, 5.95380306862e-08, 6.04978791776e-08, 6.14434034901e-08,\n  6.23756851626e-08, 6.32957121259e-08, 6.42043903937e-08, 6.51025540077e-08,\n  6.59909735447e-08, 6.68703634341e-08, 6.77413882848e-08, 6.8604668381e-08,\n  6.94607844804e-08, 7.03102820203e-08, 7.11536748229e-08, 7.1991448372e-08,\n  7.2824062723e-08, 7.36519550992e-08, 7.44755422158e-08, 7.52952223703e-08,\n  7.61113773308e-08, 7.69243740467e-08, 7.77345662086e-08, 7.85422956743e-08,\n  7.93478937793e-08, 8.01516825471e-08, 8.09539758128e-08, 8.17550802699e-08,\n  8.25552964535e-08, 8.33549196661e-08, 8.41542408569e-08, 8.49535474601e-08,\n  8.57531242006e-08, 8.65532538723e-08, 8.73542180955e-08, 8.8156298059e-08,\n  8.89597752521e-08, 8.97649321908e-08, 9.05720531451e-08, 9.138142487e-08,\n  9.21933373471e-08, 9.30080845407e-08, 9.38259651738e-08, 9.46472835298e-08,\n  9.54723502847e-08, 9.63014833769e-08, 9.71350089201e-08, 9.79732621669e-08,\n  9.88165885297e-08, 9.96653446693e-08, 1.00519899658e-07, 1.0138063623e-07,\n  1.02247952126e-07, 1.03122261554e-07, 1.04003996769e-07, 1.04893609795e-07,\n  1.05791574313e-07, 1.06698387725e-07, 1.07614573423e-07, 1.08540683296e-07,\n  1.09477300508e-07, 1.1042504257e-07, 1.11384564771e-07, 1.12356564007e-07,\n  1.13341783071e-07, 1.14341015475e-07, 1.15355110887e-07, 1.16384981291e-07,\n  1.17431607977e-07, 1.18496049514e-07, 1.19579450872e-07, 1.20683053909e-07,\n  1.21808209468e-07, 1.2295639141e-07, 1.24129212952e-07, 1.25328445797e-07,\n  1.26556042658e-07, 1.27814163916e-07, 1.29105209375e-07, 1.30431856341e-07,\n  1.31797105598e-07, 1.3320433736e-07, 1.34657379914e-07, 1.36160594606e-07,\n  1.37718982103e-07, 1.39338316679e-07, 1.41025317971e-07, 1.42787873535e-07,\n  1.44635331499e-07, 1.4657889173e-07, 1.48632138436e-07, 1.50811780719e-07,\n  1.53138707402e-07, 1.55639532047e-07, 1.58348931426e-07, 1.61313325908e-07,\n  1.64596952856e-07, 1.68292495203e-07, 1.72541128694e-07, 1.77574279496e-07,\n  1.83813550477e-07, 1.92166040885e-07, 2.05295471952e-07, 2.22600839893e-07\n};\n\n\ndouble\ngsl_ran_gaussian_ziggurat (const gsl_rng * r, const double sigma)\n{\n  unsigned long int i, j;\n  int sign;\n  double x, y;\n\n  const unsigned long int range = r->type->max - r->type->min;\n  const unsigned long int offset = r->type->min;\n\n  while (1)\n    {\n      if (range >= 0xFFFFFFFF)\n        {\n          unsigned long int k = gsl_rng_get(r) - offset;\n          i = (k & 0xFF);\n          j = (k >> 8) & 0xFFFFFF;\n        }\n      else if (range >= 0x00FFFFFF)\n        {\n          unsigned long int k1 = gsl_rng_get(r) - offset;\n          unsigned long int k2 = gsl_rng_get(r) - offset;\n          i = (k1 & 0xFF);\n          j = (k2 & 0x00FFFFFF);\n        }\n      else\n        {\n          i = gsl_rng_uniform_int (r, 256); /*  choose the step */\n          j = gsl_rng_uniform_int (r, 16777216);  /* sample from 2^24 */\n        }\n\n      sign = (i & 0x80) ? +1 : -1;\n      i &= 0x7f;\n\n      x = j * wtab[i];\n\n      if (j < ktab[i])\n        break;\n\n      if (i < 127)\n        {\n          double y0, y1, U1;\n          y0 = ytab[i];\n          y1 = ytab[i + 1];\n          U1 = gsl_rng_uniform (r);\n          y = y1 + (y0 - y1) * U1;\n        }\n      else\n        {\n          double U1, U2;\n          U1 = 1.0 - gsl_rng_uniform (r);\n          U2 = gsl_rng_uniform (r);\n          x = PARAM_R - log (U1) / PARAM_R;\n          y = exp (-PARAM_R * (x - 0.5 * PARAM_R)) * U2;\n        }\n\n      if (y < exp (-0.5 * x * x))\n        break;\n    }\n\n  return sign * sigma * x;\n}\n"
  },
  {
    "path": "gsl/randist/geometric.c",
    "content": "/* randist/geometric.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* Geometric distribution (bernoulli trial with probability p) \n\n   prob(k) =  p (1 - p)^(k-1) for n = 1, 2, 3, ...\n\n   It gives the distribution of \"waiting times\" for an event that\n   occurs with probability p. */\n\nunsigned int\ngsl_ran_geometric (const gsl_rng * r, const double p)\n{\n  double u = gsl_rng_uniform_pos (r);\n\n  unsigned int k;\n\n  if (p == 1)\n    {\n      k = 1;\n    }\n  else\n    {\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t\tk = log (u) / log (1 - p) + 1;\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n    }\n\n  return k;\n}\n\ndouble\ngsl_ran_geometric_pdf (const unsigned int k, const double p)\n{\n  if (k == 0)\n    {\n      return 0 ;\n    }\n  else if (k == 1)\n    {\n      return p ;\n    }\n  else\n    {\n      double P = p * pow (1 - p, k - 1.0);\n      return P;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/gsl_randist.h",
    "content": "/* randist/gsl_randist.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_RANDIST_H__\n#define __GSL_RANDIST_H__\n#include \"gsl_rng.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nunsigned int gsl_ran_bernoulli (const gsl_rng * r, double p);\ndouble gsl_ran_bernoulli_pdf (const unsigned int k, double p);\n\ndouble gsl_ran_beta (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_beta_pdf (const double x, const double a, const double b);\n\nunsigned int gsl_ran_binomial (const gsl_rng * r, double p, unsigned int n);\nunsigned int gsl_ran_binomial_knuth (const gsl_rng * r, double p, unsigned int n);\nunsigned int gsl_ran_binomial_tpe (const gsl_rng * r, double p, unsigned int n);\ndouble gsl_ran_binomial_pdf (const unsigned int k, const double p, const unsigned int n);\n\ndouble gsl_ran_exponential (const gsl_rng * r, const double mu);\ndouble gsl_ran_exponential_pdf (const double x, const double mu);\n\ndouble gsl_ran_exppow (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_exppow_pdf (const double x, const double a, const double b);\n\ndouble gsl_ran_cauchy (const gsl_rng * r, const double a);\ndouble gsl_ran_cauchy_pdf (const double x, const double a);\n\ndouble gsl_ran_chisq (const gsl_rng * r, const double nu);\ndouble gsl_ran_chisq_pdf (const double x, const double nu);\n\nvoid gsl_ran_dirichlet (const gsl_rng * r, const size_t K, const double alpha[], double theta[]);\ndouble gsl_ran_dirichlet_pdf (const size_t K, const double alpha[], const double theta[]);\ndouble gsl_ran_dirichlet_lnpdf (const size_t K, const double alpha[], const double theta[]);\n\ndouble gsl_ran_erlang (const gsl_rng * r, const double a, const double n);\ndouble gsl_ran_erlang_pdf (const double x, const double a, const double n);\n\ndouble gsl_ran_fdist (const gsl_rng * r, const double nu1, const double nu2);\ndouble gsl_ran_fdist_pdf (const double x, const double nu1, const double nu2);\n\n// BCH 9 Sept. 2022: commenting this out to remind myself that it has a bug in the GSL code!\n// see https://github.com/tskit-dev/msprime/issues/1997\n//double gsl_ran_flat (const gsl_rng * r, const double a, const double b);\n//double gsl_ran_flat_pdf (double x, const double a, const double b);\n\ndouble gsl_ran_gamma (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_gamma_int (const gsl_rng * r, const unsigned int a);\ndouble gsl_ran_gamma_pdf (const double x, const double a, const double b);\ndouble gsl_ran_gamma_mt (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_gamma_knuth (const gsl_rng * r, const double a, const double b);\n\ndouble gsl_ran_gaussian (const gsl_rng * r, const double sigma);\ndouble gsl_ran_gaussian_ratio_method (const gsl_rng * r, const double sigma);\ndouble gsl_ran_gaussian_ziggurat (const gsl_rng * r, const double sigma);\ndouble gsl_ran_gaussian_pdf (const double x, const double sigma);\n\ndouble gsl_ran_ugaussian (const gsl_rng * r);\ndouble gsl_ran_ugaussian_ratio_method (const gsl_rng * r);\ndouble gsl_ran_ugaussian_pdf (const double x);\n\ndouble gsl_ran_gaussian_tail (const gsl_rng * r, const double a, const double sigma);\ndouble gsl_ran_gaussian_tail_pdf (const double x, const double a, const double sigma);\n\ndouble gsl_ran_ugaussian_tail (const gsl_rng * r, const double a);\ndouble gsl_ran_ugaussian_tail_pdf (const double x, const double a);\n\nvoid gsl_ran_bivariate_gaussian (const gsl_rng * r, double sigma_x, double sigma_y, double rho, double *x, double *y);\ndouble gsl_ran_bivariate_gaussian_pdf (const double x, const double y, const double sigma_x, const double sigma_y, const double rho);\n\nint gsl_ran_multivariate_gaussian (const gsl_rng * r, const gsl_vector * mu, const gsl_matrix * L, gsl_vector * result);\nint gsl_ran_multivariate_gaussian_log_pdf (const gsl_vector * x,\n                                           const gsl_vector * mu,\n                                           const gsl_matrix * L,\n                                           double * result,\n                                           gsl_vector * work);\nint gsl_ran_multivariate_gaussian_pdf (const gsl_vector * x,\n                                       const gsl_vector * mu,\n                                       const gsl_matrix * L,\n                                       double * result,\n                                       gsl_vector * work);\nint gsl_ran_multivariate_gaussian_mean (const gsl_matrix * X, gsl_vector * mu_hat);\nint gsl_ran_multivariate_gaussian_vcov (const gsl_matrix * X, gsl_matrix * sigma_hat);\n\nint gsl_ran_wishart (const gsl_rng * r,\n                     const double df,\n                     const gsl_matrix * L,\n                     gsl_matrix * result,\n                     gsl_matrix * work);\nint gsl_ran_wishart_log_pdf (const gsl_matrix * X,\n                             const gsl_matrix * L_X,\n                             const double df,\n                             const gsl_matrix * L,\n                             double * result,\n                             gsl_matrix * work);\nint gsl_ran_wishart_pdf (const gsl_matrix * X,\n                         const gsl_matrix * L_X,\n                         const double df,\n                         const gsl_matrix * L,\n                         double * result,\n                         gsl_matrix * work);\n\ndouble gsl_ran_landau (const gsl_rng * r);\ndouble gsl_ran_landau_pdf (const double x);\n\nunsigned int gsl_ran_geometric (const gsl_rng * r, const double p);\ndouble gsl_ran_geometric_pdf (const unsigned int k, const double p);\n\nunsigned int gsl_ran_hypergeometric (const gsl_rng * r, unsigned int n1, unsigned int n2, unsigned int t);\ndouble gsl_ran_hypergeometric_pdf (const unsigned int k, const unsigned int n1, const unsigned int n2, unsigned int t);\n\ndouble gsl_ran_gumbel1 (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_gumbel1_pdf (const double x, const double a, const double b);\n\ndouble gsl_ran_gumbel2 (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_gumbel2_pdf (const double x, const double a, const double b);\n\ndouble gsl_ran_logistic (const gsl_rng * r, const double a);\ndouble gsl_ran_logistic_pdf (const double x, const double a);\n\ndouble gsl_ran_lognormal (const gsl_rng * r, const double zeta, const double sigma);\ndouble gsl_ran_lognormal_pdf (const double x, const double zeta, const double sigma);\n\nunsigned int gsl_ran_logarithmic (const gsl_rng * r, const double p);\ndouble gsl_ran_logarithmic_pdf (const unsigned int k, const double p);\n\nvoid gsl_ran_multinomial (const gsl_rng * r, const size_t K,\n                          const unsigned int N, const double p[],\n                          unsigned int n[] );\ndouble gsl_ran_multinomial_pdf (const size_t K,\n                                const double p[], const unsigned int n[] );\ndouble gsl_ran_multinomial_lnpdf (const size_t K,\n                           const double p[], const unsigned int n[] );\n\n\nunsigned int gsl_ran_negative_binomial (const gsl_rng * r, double p, double n);\ndouble gsl_ran_negative_binomial_pdf (const unsigned int k, const double p, double n);\n\nunsigned int gsl_ran_pascal (const gsl_rng * r, double p, unsigned int n);\ndouble gsl_ran_pascal_pdf (const unsigned int k, const double p, unsigned int n);\n\ndouble gsl_ran_pareto (const gsl_rng * r, double a, const double b);\ndouble gsl_ran_pareto_pdf (const double x, const double a, const double b);\n\nunsigned int gsl_ran_poisson (const gsl_rng * r, double mu);\nvoid gsl_ran_poisson_array (const gsl_rng * r, size_t n, unsigned int array[],\n                            double mu);\ndouble gsl_ran_poisson_pdf (const unsigned int k, const double mu);\n\ndouble gsl_ran_rayleigh (const gsl_rng * r, const double sigma);\ndouble gsl_ran_rayleigh_pdf (const double x, const double sigma);\n\ndouble gsl_ran_rayleigh_tail (const gsl_rng * r, const double a, const double sigma);\ndouble gsl_ran_rayleigh_tail_pdf (const double x, const double a, const double sigma);\n\ndouble gsl_ran_tdist (const gsl_rng * r, const double nu);\ndouble gsl_ran_tdist_pdf (const double x, const double nu);\n\ndouble gsl_ran_laplace (const gsl_rng * r, const double a);\ndouble gsl_ran_laplace_pdf (const double x, const double a);\n\ndouble gsl_ran_levy (const gsl_rng * r, const double c, const double alpha);\ndouble gsl_ran_levy_skew (const gsl_rng * r, const double c, const double alpha, const double beta);\n\ndouble gsl_ran_weibull (const gsl_rng * r, const double a, const double b);\ndouble gsl_ran_weibull_pdf (const double x, const double a, const double b);\n\nvoid gsl_ran_dir_2d (const gsl_rng * r, double * x, double * y);\nvoid gsl_ran_dir_2d_trig_method (const gsl_rng * r, double * x, double * y);\nvoid gsl_ran_dir_3d (const gsl_rng * r, double * x, double * y, double * z);\nvoid gsl_ran_dir_nd (const gsl_rng * r, size_t n, double * x);\n\nvoid gsl_ran_shuffle (const gsl_rng * r, void * base, size_t nmembm, size_t size);\nint gsl_ran_choose (const gsl_rng * r, void * dest, size_t k, void * src, size_t n, size_t size) ;\nvoid gsl_ran_sample (const gsl_rng * r, void * dest, size_t k, void * src, size_t n, size_t size) ;\n\n\ntypedef struct {                /* struct for Walker algorithm */\n    size_t K;\n    size_t *A;\n    double *F;\n} gsl_ran_discrete_t;\n\ngsl_ran_discrete_t * gsl_ran_discrete_preproc (size_t K, const double *P);\nvoid gsl_ran_discrete_free(gsl_ran_discrete_t *g);\nsize_t gsl_ran_discrete (const gsl_rng *r, const gsl_ran_discrete_t *g);\ndouble gsl_ran_discrete_pdf (size_t k, const gsl_ran_discrete_t *g);\n\n\n__END_DECLS\n\n#endif /* __GSL_RANDIST_H__ */\n"
  },
  {
    "path": "gsl/randist/laplace.c",
    "content": "/* randist/laplace.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The two-sided exponential probability distribution is  \n   p(x) dx = (1/(2 a)) * exp(-|x/a|) dx\n   for -infty < x < infty. It is also known as the Laplace distribution.  */\n\ndouble\ngsl_ran_laplace (const gsl_rng * r, const double a)\n{\n  double u;\n  do\n    {\n      u = 2 * gsl_rng_uniform (r) - 1.0;\n    }\n  while (u == 0.0);\n\n  if (u < 0)\n    {\n      return a * log (-u);\n    }\n  else\n    {\n      return -a * log (u);\n    }\n}\n\ndouble\ngsl_ran_laplace_pdf (const double x, const double a)\n{\n  double p = (1/(2*a)) * exp (-fabs (x)/a);\n  return p;\n}\n"
  },
  {
    "path": "gsl/randist/lognormal.c",
    "content": "/* randist/lognormal.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The lognormal distribution has the form \n\n   p(x) dx = 1/(x * sqrt(2 pi sigma^2)) exp(-(ln(x) - zeta)^2/2 sigma^2) dx\n\n   for x > 0. Lognormal random numbers are the exponentials of\n   gaussian random numbers */\n\ndouble\ngsl_ran_lognormal (const gsl_rng * r, const double zeta, const double sigma)\n{\n  double u, v, r2, normal, z;\n\n  do\n    {\n      /* choose x,y in uniform square (-1,-1) to (+1,+1) */\n\n      u = -1 + 2 * gsl_rng_uniform (r);\n      v = -1 + 2 * gsl_rng_uniform (r);\n\n      /* see if it is in the unit circle */\n      r2 = u * u + v * v;\n    }\n  while (r2 > 1.0 || r2 == 0);\n\n  normal = u * sqrt (-2.0 * log (r2) / r2);\n\n  z =  exp (sigma * normal + zeta);\n\n  return z;\n}\n\ndouble\ngsl_ran_lognormal_pdf (const double x, const double zeta, const double sigma)\n{\n  if (x <= 0)\n    {\n      return 0 ;\n    }\n  else\n    {\n      double u = (log (x) - zeta)/sigma;\n      double p = 1 / (x * fabs(sigma) * sqrt (2 * M_PI)) * exp (-(u * u) /2);\n      return p;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/multinomial.c",
    "content": "/* randist/multinomial.c\n * \n * Copyright (C) 2002 Gavin E. Crooks <gec@compbio.berkeley.edu>\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_sf_gamma.h\"\n\n/* The multinomial distribution has the form\n\n                                      N!           n_1  n_2      n_K\n   prob(n_1, n_2, ... n_K) = -------------------- p_1  p_2  ... p_K\n                             (n_1! n_2! ... n_K!) \n\n   where n_1, n_2, ... n_K are nonnegative integers, sum_{k=1,K} n_k = N,\n   and p = (p_1, p_2, ..., p_K) is a probability distribution. \n\n   Random variates are generated using the conditional binomial method.\n   This scales well with N and does not require a setup step.\n\n   Ref: \n   C.S. David, The computer generation of multinomial random variates,\n   Comp. Stat. Data Anal. 16 (1993) 205-217\n*/\n\nvoid\ngsl_ran_multinomial (const gsl_rng * r, const size_t K,\n                     const unsigned int N, const double p[], unsigned int n[])\n{\n  size_t k;\n  double norm = 0.0;\n  double sum_p = 0.0;\n\n  unsigned int sum_n = 0;\n\n  /* p[k] may contain non-negative weights that do not sum to 1.0.\n   * Even a probability distribution will not exactly sum to 1.0\n   * due to rounding errors. \n   */\n\n  for (k = 0; k < K; k++)\n    {\n      norm += p[k];\n    }\n\n  for (k = 0; k < K; k++)\n    {\n      if (p[k] > 0.0)\n        {\n          n[k] = gsl_ran_binomial (r, p[k] / (norm - sum_p), N - sum_n);\n        }\n      else\n        {\n          n[k] = 0;\n        }\n\n      sum_p += p[k];\n      sum_n += n[k];\n    }\n\n}\n\n\ndouble\ngsl_ran_multinomial_pdf (const size_t K,\n                         const double p[], const unsigned int n[])\n{\n  return exp (gsl_ran_multinomial_lnpdf (K, p, n));\n}\n\n\ndouble\ngsl_ran_multinomial_lnpdf (const size_t K,\n                           const double p[], const unsigned int n[])\n{\n  size_t k;\n  unsigned int N = 0;\n  double log_pdf = 0.0;\n  double norm = 0.0;\n\n  for (k = 0; k < K; k++)\n    {\n      N += n[k];\n    }\n\n  for (k = 0; k < K; k++)\n    {\n      norm += p[k];\n    }\n\n  log_pdf = gsl_sf_lnfact (N);\n\n  for (k = 0; k < K; k++)\n    {\n      /* Handle case where n[k]==0 and p[k]==0 */\n\n      if (n[k] > 0) \n        {\n          log_pdf += log (p[k] / norm) * n[k] - gsl_sf_lnfact (n[k]);\n        }\n    }\n\n  return log_pdf;\n}\n"
  },
  {
    "path": "gsl/randist/mvgauss.c",
    "content": "/* randist/mvgauss.c\n * \n * Copyright (C) 2016 Timothée Flutre, Patrick Alken\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_matrix.h\"\n#include \"gsl_blas.h\"\n//#include \"gsl_linalg.h\"\n//#include \"gsl_statistics.h\"\n\n/* Generate a random vector from a multivariate Gaussian distribution using\n * the Cholesky decomposition of the variance-covariance matrix, following\n * \"Computational Statistics\" from Gentle (2009), section 7.4.\n *\n * mu      mean vector (dimension d)\n * L       matrix resulting from the Cholesky decomposition of\n *         variance-covariance matrix Sigma = L L^T (dimension d x d)\n * result  output vector (dimension d)\n */\nint\ngsl_ran_multivariate_gaussian (const gsl_rng * r,\n                               const gsl_vector * mu,\n                               const gsl_matrix * L,\n                               gsl_vector * result)\n{\n  const size_t M = L->size1;\n  const size_t N = L->size2;\n\n  if (M != N)\n    {\n      GSL_ERROR(\"requires square matrix\", GSL_ENOTSQR);\n    }\n  else if (mu->size != M)\n    {\n      GSL_ERROR(\"incompatible dimension of mean vector with variance-covariance matrix\", GSL_EBADLEN);\n    }\n  else if (result->size != M)\n    {\n      GSL_ERROR(\"incompatible dimension of result vector\", GSL_EBADLEN);\n    }\n  else\n    {\n      size_t i;\n\n      for (i = 0; i < M; ++i)\n        gsl_vector_set(result, i, gsl_ran_ugaussian(r));\n\n      gsl_blas_dtrmv(CblasLower, CblasNoTrans, CblasNonUnit, L, result);\n      gsl_vector_add(result, mu);\n\n      return GSL_SUCCESS;\n    }\n}\n\n/* Compute the log of the probability density function at a given quantile\n * vector for a multivariate Gaussian distribution using the Cholesky\n * decomposition of the variance-covariance matrix.\n *\n * x       vector of quantiles (dimension d)\n * mu      mean vector (dimension d)\n * L       matrix resulting from the Cholesky decomposition of\n *         variance-covariance matrix Sigma = L L^T (dimension d x d)\n * result  output of the density (dimension 1)\n * work    vector used for intermediate computations (dimension d)\n */\nint\ngsl_ran_multivariate_gaussian_log_pdf (const gsl_vector * x,\n\t\t\t\t\t\t\t\t\t   const gsl_vector * mu,\n\t\t\t\t\t\t\t\t\t   const gsl_matrix * L,\n\t\t\t\t\t\t\t\t\t   double * result,\n\t\t\t\t\t\t\t\t\t   gsl_vector * work)\n{\n\tconst size_t M = L->size1;\n\tconst size_t N = L->size2;\n\t\n\tif (M != N)\n\t{\n\t\tGSL_ERROR(\"requires square matrix\", GSL_ENOTSQR);\n\t}\n\telse if (mu->size != M)\n\t{\n\t\tGSL_ERROR(\"incompatible dimension of mean vector with variance-covariance matrix\", GSL_EBADLEN);\n\t}\n\telse if (x->size != M)\n\t{\n\t\tGSL_ERROR(\"incompatible dimension of quantile vector\", GSL_EBADLEN);\n\t}\n\telse if (work->size != M)\n\t{\n\t\tGSL_ERROR(\"incompatible dimension of work vector\", GSL_EBADLEN);\n\t}\n\telse\n\t{\n\t\tsize_t i;\n\t\tdouble quadForm;        /* (x - mu)' Sigma^{-1} (x - mu) */\n\t\tdouble logSqrtDetSigma; /* log [ sqrt(|Sigma|) ] */\n\t\t\n\t\t/* compute: work = x - mu */\n\t\tfor (i = 0; i < M; ++i)\n\t\t{\n\t\t\tdouble xi = gsl_vector_get(x, i);\n\t\t\tdouble mui = gsl_vector_get(mu, i);\n\t\t\tgsl_vector_set(work, i, xi - mui);\n\t\t}\n\t\t\n\t\t/* compute: work = L^{-1} * (x - mu) */\n\t\tgsl_blas_dtrsv(CblasLower, CblasNoTrans, CblasNonUnit, L, work);\n\t\t\n\t\t/* compute: quadForm = (x - mu)' Sigma^{-1} (x - mu) */\n\t\tgsl_blas_ddot(work, work, &quadForm);\n\t\t\n\t\t/* compute: log [ sqrt(|Sigma|) ] = sum_i log L_{ii} */\n\t\tlogSqrtDetSigma = 0.0;\n\t\tfor (i = 0; i < M; ++i)\n\t\t{\n\t\t\tdouble Lii = gsl_matrix_get(L, i, i);\n\t\t\tlogSqrtDetSigma += log(Lii);\n\t\t}\n\t\t\n\t\t*result = -0.5*quadForm - logSqrtDetSigma - 0.5*M*log(2.0*M_PI);\n\t\t\n\t\treturn GSL_SUCCESS;\n\t}\n}\n\nint\ngsl_ran_multivariate_gaussian_pdf (const gsl_vector * x,\n\t\t\t\t\t\t\t\t   const gsl_vector * mu,\n\t\t\t\t\t\t\t\t   const gsl_matrix * L,\n\t\t\t\t\t\t\t\t   double * result,\n\t\t\t\t\t\t\t\t   gsl_vector * work)\n{\n\tdouble logpdf;\n\tint status = gsl_ran_multivariate_gaussian_log_pdf(x, mu, L, &logpdf, work);\n\t\n\tif (status == GSL_SUCCESS)\n\t\t*result = exp(logpdf);\n\t\n\treturn status;\n}\n"
  },
  {
    "path": "gsl/randist/nbinomial.c",
    "content": "/* randist/nbinomial.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_sys.h\"\n\n/* The negative binomial distribution has the form,\n\n   prob(k) =  Gamma(n + k)/(Gamma(n) Gamma(k + 1))  p^n (1-p)^k \n\n   for k = 0, 1, ... . Note that n does not have to be an integer.\n\n   This is the Leger's algorithm (given in the answers in Knuth) */\n\nunsigned int\ngsl_ran_negative_binomial (const gsl_rng * r, double p, double n)\n{\n  double X = gsl_ran_gamma (r, n, 1.0) ;\n  unsigned int k = gsl_ran_poisson (r, X*(1-p)/p) ;\n  return k ;\n}\n\ndouble\ngsl_ran_negative_binomial_pdf (const unsigned int k, const double p, double n)\n{\n  double P;\n\n  double f = gsl_sf_lngamma (k + n) ;\n  double a = gsl_sf_lngamma (n) ;\n  double b = gsl_sf_lngamma (k + 1.0) ;\n\n  P = exp(f - a - b + n * log(p) + k * log1p(-p));\n\n  return P;\n}\n"
  },
  {
    "path": "gsl/randist/poisson.c",
    "content": "/* randist/poisson.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The poisson distribution has the form\n\n   p(n) = (mu^n / n!) exp(-mu) \n\n   for n = 0, 1, 2, ... . The method used here is the one from Knuth. */\n\nunsigned int\ngsl_ran_poisson (const gsl_rng * r, double mu)\n{\n  double emu;\n  double prod = 1.0;\n  unsigned int k = 0;\n\n  while (mu > 10)\n    {\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t\tunsigned int m = mu * (7.0 / 8.0);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\n      double X = gsl_ran_gamma_int (r, m);\n\n      if (X >= mu)\n        {\n          return k + gsl_ran_binomial (r, mu / X, m - 1);\n        }\n      else\n        {\n          k += m;\n          mu -= X; \n        }\n    }\n\n  /* This following method works well when mu is small */\n\n  emu = exp (-mu);\n\n  do\n    {\n      prod *= gsl_rng_uniform (r);\n      k++;\n    }\n  while (prod > emu);\n\n  return k - 1;\n\n}\n\nvoid\ngsl_ran_poisson_array (const gsl_rng * r, size_t n, unsigned int array[],\n                       double mu)\n{\n  size_t i;\n\n  for (i = 0; i < n; i++)\n    {\n      array[i] = gsl_ran_poisson (r, mu);\n    }\n\n  return;\n}\n\ndouble\ngsl_ran_poisson_pdf (const unsigned int k, const double mu)\n{\n  double p;\n  double lf = gsl_sf_lnfact (k); \n\n  p = exp (log (mu) * k - lf - mu);\n  return p;\n}\n"
  },
  {
    "path": "gsl/randist/shuffle.c",
    "content": "/* randist/shuffle.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* Inline swap and copy functions for moving objects around */\n\nstatic inline \nvoid swap (void * base, size_t size, size_t i, size_t j)\n{\n  register char * a = size * i + (char *) base ;\n  register char * b = size * j + (char *) base ;\n  register size_t s = size ;\n\n  if (i == j)\n    return ;\n  \n  do                                            \n    {                                           \n      char tmp = *a;                            \n      *a++ = *b;                                \n      *b++ = tmp;                               \n    } \n  while (--s > 0);                              \n}\n\nstatic inline void \ncopy (void * dest, size_t i, void * src, size_t j, size_t size)\n{\n  register char * a = size * i + (char *) dest ;\n  register char * b = size * j + (char *) src ;\n  register size_t s = size ;\n  \n  do                                            \n    {                                           \n      *a++ = *b++;                              \n    } \n  while (--s > 0);                              \n}\n\n/* Randomly permute (shuffle) N indices\n\n   Supply an array x[N] with nmemb members, each of size size and on\n   return it will be shuffled into a random order.  The algorithm is\n   from Knuth, SemiNumerical Algorithms, v2, p139, who cites Moses and\n   Oakford, and Durstenfeld */\n\nvoid\ngsl_ran_shuffle (const gsl_rng * r, void * base, size_t n, size_t size)\n{\n  size_t i ;\n\n  for (i = n - 1; i > 0; i--)\n    {\n      size_t j = gsl_rng_uniform_int(r, i+1); /* originally (i + 1) * gsl_rng_uniform (r) */\n\n      swap (base, size, i, j) ;\n    }\n}\n\nint\ngsl_ran_choose (const gsl_rng * r, void * dest, size_t k, void * src, \n                 size_t n, size_t size)\n{\n  size_t i, j = 0;\n\n  /* Choose k out of n items, return an array x[] of the k items.\n     These items will prevserve the relative order of the original\n     input -- you can use shuffle() to randomize the output if you\n     wish */\n\n  if (k > n)\n    {\n      GSL_ERROR (\"k is greater than n, cannot sample more than n items\",\n                 GSL_EINVAL) ;\n    }\n\n  for (i = 0; i < n && j < k; i++)\n    {\n      if ((n - i) * gsl_rng_uniform (r) < k - j)\n        {\n          copy (dest, j, src, i, size) ;\n          j++ ;\n        }\n    }\n\n  return GSL_SUCCESS;\n}\n\nvoid\ngsl_ran_sample (const gsl_rng * r, void * dest, size_t k, void * src, \n                size_t n, size_t size)\n{\n  size_t i, j = 0;\n\n  /* Choose k out of n items, with replacement */\n\n  for (i = 0; i < k; i++)\n    {\n      j = gsl_rng_uniform_int (r, n);  /* originally n * gsl_rng_uniform (r) */\n\n      copy (dest, i, src, j, size) ;\n    }\n}\n"
  },
  {
    "path": "gsl/randist/tdist.c",
    "content": "/* randist/tdist.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The t-distribution has the form\n\n   p(x) dx = (Gamma((nu + 1)/2)/(sqrt(pi nu) Gamma(nu/2))\n   * (1 + (x^2)/nu)^-((nu + 1)/2) dx\n\n   The method used here is the one described in Knuth */\n\ndouble\ngsl_ran_tdist (const gsl_rng * r, const double nu)\n{\n  if (nu <= 2)\n    {\n      double Y1 = gsl_ran_ugaussian (r);\n      double Y2 = gsl_ran_chisq (r, nu);\n\n      double t = Y1 / sqrt (Y2 / nu);\n\n      return t;\n    }\n  else\n    {\n      double Y1, Y2, Z, t;\n      do\n        {\n          Y1 = gsl_ran_ugaussian (r);\n          Y2 = gsl_ran_exponential (r, 1 / (nu/2 - 1));\n\n          Z = Y1 * Y1 / (nu - 2);\n        }\n      while (1 - Z < 0 || exp (-Y2 - Z) > (1 - Z));\n\n      /* Note that there is a typo in Knuth's formula, the line below\n         is taken from the original paper of Marsaglia, Mathematics of\n         Computation, 34 (1980), p 234-256 */\n\n      t = Y1 / sqrt ((1 - 2 / nu) * (1 - Z));\n      return t;\n    }\n}\n\ndouble\ngsl_ran_tdist_pdf (const double x, const double nu)\n{\n  double p;\n\n  double lg1 = gsl_sf_lngamma (nu / 2);\n  double lg2 = gsl_sf_lngamma ((nu + 1) / 2);\n\n  p = ((exp (lg2 - lg1) / sqrt (M_PI * nu)) \n       * pow ((1 + x * x / nu), -(nu + 1) / 2));\n  return p;\n}\n\n\n"
  },
  {
    "path": "gsl/randist/weibull.c",
    "content": "/* randist/weibull.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_rng.h\"\n#include \"gsl_randist.h\"\n\n/* The Weibull distribution has the form,\n\n   p(x) dx = (b/a) (x/a)^(b-1) exp(-(x/a)^b) dx\n\n */\n\ndouble\ngsl_ran_weibull (const gsl_rng * r, const double a, const double b)\n{\n  double x = gsl_rng_uniform_pos (r);\n\n  double z = pow (-log (x), 1 / b);\n\n  return a * z;\n}\n\ndouble\ngsl_ran_weibull_pdf (const double x, const double a, const double b)\n{\n  if (x < 0)\n    {\n      return 0 ;\n    }\n  else if (x == 0)\n    {\n      if (b == 1)\n        return 1/a ;\n      else\n        return 0 ;\n    }\n  else if (b == 1)\n    {\n      return exp(-x/a)/a ;\n    }\n  else\n    {\n      double p = (b/a) * exp (-pow (x/a, b) + (b - 1) * log (x/a));\n      return p;\n    }\n}\n"
  },
  {
    "path": "gsl/rng/gsl_rng.h",
    "content": "/* rng/gsl_rng.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_RNG_H__\n#define __GSL_RNG_H__\n#include <stdlib.h>\n#include \"gsl_types.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_inline.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ntypedef struct\n  {\n    const char *name;\n    unsigned long int max;\n    unsigned long int min;\n    size_t size;\n    void (*set) (void *state, unsigned long int seed);\n    unsigned long int (*get) (void *state);\n    double (*get_double) (void *state);\n  }\ngsl_rng_type;\n\ntypedef struct\n  {\n    const gsl_rng_type * type;\n    void *state;\n  }\ngsl_rng;\n\n\n/* These structs also need to appear in default.c so you can select\n   them via the environment variable GSL_RNG_TYPE */\n\nGSL_VAR const gsl_rng_type *gsl_rng_borosh13;\nGSL_VAR const gsl_rng_type *gsl_rng_coveyou;\nGSL_VAR const gsl_rng_type *gsl_rng_cmrg;\nGSL_VAR const gsl_rng_type *gsl_rng_fishman18;\nGSL_VAR const gsl_rng_type *gsl_rng_fishman20;\nGSL_VAR const gsl_rng_type *gsl_rng_fishman2x;\nGSL_VAR const gsl_rng_type *gsl_rng_gfsr4;\nGSL_VAR const gsl_rng_type *gsl_rng_knuthran;\nGSL_VAR const gsl_rng_type *gsl_rng_knuthran2;\nGSL_VAR const gsl_rng_type *gsl_rng_knuthran2002;\nGSL_VAR const gsl_rng_type *gsl_rng_lecuyer21;\nGSL_VAR const gsl_rng_type *gsl_rng_minstd;\nGSL_VAR const gsl_rng_type *gsl_rng_mrg;\nGSL_VAR const gsl_rng_type *gsl_rng_mt19937;\nGSL_VAR const gsl_rng_type *gsl_rng_mt19937_1999;\nGSL_VAR const gsl_rng_type *gsl_rng_mt19937_1998;\nGSL_VAR const gsl_rng_type *gsl_rng_r250;\nGSL_VAR const gsl_rng_type *gsl_rng_ran0;\nGSL_VAR const gsl_rng_type *gsl_rng_ran1;\nGSL_VAR const gsl_rng_type *gsl_rng_ran2;\nGSL_VAR const gsl_rng_type *gsl_rng_ran3;\nGSL_VAR const gsl_rng_type *gsl_rng_rand;\nGSL_VAR const gsl_rng_type *gsl_rng_rand48;\nGSL_VAR const gsl_rng_type *gsl_rng_random128_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random128_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random128_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_random256_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random256_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random256_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_random32_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random32_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random32_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_random64_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random64_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random64_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_random8_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random8_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random8_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_random_bsd;\nGSL_VAR const gsl_rng_type *gsl_rng_random_glibc2;\nGSL_VAR const gsl_rng_type *gsl_rng_random_libc5;\nGSL_VAR const gsl_rng_type *gsl_rng_randu;\nGSL_VAR const gsl_rng_type *gsl_rng_ranf;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlux;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlux389;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlxd1;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlxd2;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlxs0;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlxs1;\nGSL_VAR const gsl_rng_type *gsl_rng_ranlxs2;\nGSL_VAR const gsl_rng_type *gsl_rng_ranmar;\nGSL_VAR const gsl_rng_type *gsl_rng_slatec;\nGSL_VAR const gsl_rng_type *gsl_rng_taus;\nGSL_VAR const gsl_rng_type *gsl_rng_taus2;\nGSL_VAR const gsl_rng_type *gsl_rng_taus113;\nGSL_VAR const gsl_rng_type *gsl_rng_transputer;\nGSL_VAR const gsl_rng_type *gsl_rng_tt800;\nGSL_VAR const gsl_rng_type *gsl_rng_uni;\nGSL_VAR const gsl_rng_type *gsl_rng_uni32;\nGSL_VAR const gsl_rng_type *gsl_rng_vax;\nGSL_VAR const gsl_rng_type *gsl_rng_waterman14;\nGSL_VAR const gsl_rng_type *gsl_rng_zuf;\n\nconst gsl_rng_type ** gsl_rng_types_setup(void);\n\nGSL_VAR const gsl_rng_type *gsl_rng_default;\nGSL_VAR unsigned long int gsl_rng_default_seed;\n\ngsl_rng *gsl_rng_alloc (const gsl_rng_type * T);\nint gsl_rng_memcpy (gsl_rng * dest, const gsl_rng * src);\ngsl_rng *gsl_rng_clone (const gsl_rng * r);\n\nvoid gsl_rng_free (gsl_rng * r);\n\nvoid gsl_rng_set (const gsl_rng * r, unsigned long int seed);\nunsigned long int gsl_rng_max (const gsl_rng * r);\nunsigned long int gsl_rng_min (const gsl_rng * r);\nconst char *gsl_rng_name (const gsl_rng * r);\n\nint gsl_rng_fread (FILE * stream, gsl_rng * r);\nint gsl_rng_fwrite (FILE * stream, const gsl_rng * r);\n\nsize_t gsl_rng_size (const gsl_rng * r);\nvoid * gsl_rng_state (const gsl_rng * r);\n\nvoid gsl_rng_print_state (const gsl_rng * r);\n\nconst gsl_rng_type * gsl_rng_env_setup (void);\n\nINLINE_DECL unsigned long int gsl_rng_get (const gsl_rng * r);\nINLINE_DECL double gsl_rng_uniform (const gsl_rng * r);\nINLINE_DECL double gsl_rng_uniform_pos (const gsl_rng * r);\nINLINE_DECL unsigned long int gsl_rng_uniform_int (const gsl_rng * r, unsigned long int n);\n\n#ifdef HAVE_INLINE\n\nINLINE_FUN unsigned long int\ngsl_rng_get (const gsl_rng * r)\n{\n  return (r->type->get) (r->state);\n}\n\nINLINE_FUN double\ngsl_rng_uniform (const gsl_rng * r)\n{\n  return (r->type->get_double) (r->state);\n}\n\nINLINE_FUN double\ngsl_rng_uniform_pos (const gsl_rng * r)\n{\n  double x ;\n  do\n    {\n      x = (r->type->get_double) (r->state) ;\n    }\n  while (x == 0) ;\n\n  return x ;\n}\n\n/* Note: to avoid integer overflow in (range+1) we work with scale =\n   range/n = (max-min)/n rather than scale=(max-min+1)/n, this reduces\n   efficiency slightly but avoids having to check for the out of range\n   value.  Note that range is typically O(2^32) so the addition of 1\n   is negligible in most usage. */\n\nINLINE_FUN unsigned long int\ngsl_rng_uniform_int (const gsl_rng * r, unsigned long int n)\n{\n  unsigned long int offset = r->type->min;\n  unsigned long int range = r->type->max - offset;\n  unsigned long int scale;\n  unsigned long int k;\n\n  if (n > range || n == 0) \n    {\n      GSL_ERROR_VAL (\"invalid n, either 0 or exceeds maximum value of generator\",\n                     GSL_EINVAL, 0) ;\n    }\n\n  scale = range / n;\n\n  do\n    {\n      k = (((r->type->get) (r->state)) - offset) / scale;\n    }\n  while (k >= n);\n\n  return k;\n}\n#endif /* HAVE_INLINE */\n\n__END_DECLS\n\n#endif /* __GSL_RNG_H__ */\n"
  },
  {
    "path": "gsl/rng/inline.c",
    "content": "/* rng/inline.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include \"gsl_errno.h\"\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_rng.h\"\n"
  },
  {
    "path": "gsl/rng/mt.c",
    "content": "/* This program is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 3 of the\n   License, or (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   General Public License for more details.  You should have received\n   a copy of the GNU General Public License along with this library; if\n   not, write to the Free Software Foundation, Inc., 51 Franklin Street,\n   Fifth Floor, Boston, MA 02110-1301, USA.\n\n   Original implementation was copyright (C) 1997 Makoto Matsumoto and\n   Takuji Nishimura. Coded by Takuji Nishimura, considering the\n   suggestions by Topher Cooper and Marc Rieffel in July-Aug. 1997, \"A\n   C-program for MT19937: Integer version (1998/4/6)\"\n\n   This implementation copyright (C) 1998 Brian Gough. I reorganized\n   the code to use the module framework of GSL.  The license on this\n   implementation was changed from LGPL to GPL, following paragraph 3\n   of the LGPL, version 2.\n\n   Update:\n\n   The seeding procedure has been updated to match the 10/99 release\n   of MT19937.\n\n   Update:\n\n   The seeding procedure has been updated again to match the 2002\n   release of MT19937\n\n   The original code included the comment: \"When you use this, send an\n   email to: matumoto@math.keio.ac.jp with an appropriate reference to\n   your work\".\n\n   Makoto Matsumoto has a web page with more information about the\n   generator, http://www.math.keio.ac.jp/~matumoto/emt.html. \n\n   The paper below has details of the algorithm.\n\n   From: Makoto Matsumoto and Takuji Nishimura, \"Mersenne Twister: A\n   623-dimensionally equidistributerd uniform pseudorandom number\n   generator\". ACM Transactions on Modeling and Computer Simulation,\n   Vol. 8, No. 1 (Jan. 1998), Pages 3-30\n\n   You can obtain the paper directly from Makoto Matsumoto's web page.\n\n   The period of this generator is 2^{19937} - 1.\n\n*/\n\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_rng.h\"\n\nstatic inline unsigned long int mt_get (void *vstate);\nstatic double mt_get_double (void *vstate);\nstatic void mt_set (void *state, unsigned long int s);\n\n#define N 624   /* Period parameters */\n#define M 397\n\n/* most significant w-r bits */\nstatic const unsigned long UPPER_MASK = 0x80000000UL;   \n\n/* least significant r bits */\nstatic const unsigned long LOWER_MASK = 0x7fffffffUL;   \n\ntypedef struct\n  {\n    unsigned long mt[N];\n    int mti;\n  }\nmt_state_t;\n\nstatic inline unsigned long\nmt_get (void *vstate)\n{\n  mt_state_t *state = (mt_state_t *) vstate;\n\n  unsigned long k ;\n  unsigned long int *const mt = state->mt;\n\n#define MAGIC(y) (((y)&0x1) ? 0x9908b0dfUL : 0)\n\n  if (state->mti >= N)\n    {   /* generate N words at one time */\n      int kk;\n\n      for (kk = 0; kk < N - M; kk++)\n        {\n          unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);\n          mt[kk] = mt[kk + M] ^ (y >> 1) ^ MAGIC(y);\n        }\n      for (; kk < N - 1; kk++)\n        {\n          unsigned long y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);\n          mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ MAGIC(y);\n        }\n\n      {\n        unsigned long y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);\n        mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ MAGIC(y);\n      }\n\n      state->mti = 0;\n    }\n\n  /* Tempering */\n  \n  k = mt[state->mti];\n  k ^= (k >> 11);\n  k ^= (k << 7) & 0x9d2c5680UL;\n  k ^= (k << 15) & 0xefc60000UL;\n  k ^= (k >> 18);\n\n  state->mti++;\n\n  return k;\n}\n\nstatic double\nmt_get_double (void * vstate)\n{\n  return mt_get (vstate) / 4294967296.0 ;\n}\n\nstatic void\nmt_set (void *vstate, unsigned long int s)\n{\n  mt_state_t *state = (mt_state_t *) vstate;\n  int i;\n\n  if (s == 0)\n    s = 4357;   /* the default seed is 4357 */\n\n  state->mt[0]= s & 0xffffffffUL;\n\n  for (i = 1; i < N; i++)\n    {\n      /* See Knuth's \"Art of Computer Programming\" Vol. 2, 3rd\n         Ed. p.106 for multiplier. */\n\n      state->mt[i] =\n        (1812433253UL * (state->mt[i-1] ^ (state->mt[i-1] >> 30)) + i);\n      \n      state->mt[i] &= 0xffffffffUL;\n    }\n\n  state->mti = i;\n}\n\nstatic void\nmt_1999_set (void *vstate, unsigned long int s)\n{\n  mt_state_t *state = (mt_state_t *) vstate;\n  int i;\n\n  if (s == 0)\n    s = 4357;   /* the default seed is 4357 */\n\n  /* This is the October 1999 version of the seeding procedure. It\n     was updated by the original developers to avoid the periodicity\n     in the simple congruence originally used.\n\n     Note that an ANSI-C unsigned long integer arithmetic is\n     automatically modulo 2^32 (or a higher power of two), so we can\n     safely ignore overflow. */\n\n#define LCG(x) ((69069 * x) + 1) &0xffffffffUL\n\n  for (i = 0; i < N; i++)\n    {\n      state->mt[i] = s & 0xffff0000UL;\n      s = LCG(s);\n      state->mt[i] |= (s &0xffff0000UL) >> 16;\n      s = LCG(s);\n    }\n\n  state->mti = i;\n}\n\n/* This is the original version of the seeding procedure, no longer\n   used but available for compatibility with the original MT19937. */\n\nstatic void\nmt_1998_set (void *vstate, unsigned long int s)\n{\n  mt_state_t *state = (mt_state_t *) vstate;\n  int i;\n\n  if (s == 0)\n    s = 4357;   /* the default seed is 4357 */\n\n  state->mt[0] = s & 0xffffffffUL;\n\n#define LCG1998(n) ((69069 * n) & 0xffffffffUL)\n\n  for (i = 1; i < N; i++)\n    state->mt[i] = LCG1998 (state->mt[i - 1]);\n\n  state->mti = i;\n}\n\nstatic const gsl_rng_type mt_type =\n{\"mt19937\",                     /* name */\n 0xffffffffUL,                  /* RAND_MAX  */\n 0,                             /* RAND_MIN  */\n sizeof (mt_state_t),\n &mt_set,\n &mt_get,\n &mt_get_double};\n\nstatic const gsl_rng_type mt_1999_type =\n{\"mt19937_1999\",                /* name */\n 0xffffffffUL,                  /* RAND_MAX  */\n 0,                             /* RAND_MIN  */\n sizeof (mt_state_t),\n &mt_1999_set,\n &mt_get,\n &mt_get_double};\n\nstatic const gsl_rng_type mt_1998_type =\n{\"mt19937_1998\",                /* name */\n 0xffffffffUL,                  /* RAND_MAX  */\n 0,                             /* RAND_MIN  */\n sizeof (mt_state_t),\n &mt_1998_set,\n &mt_get,\n &mt_get_double};\n\nconst gsl_rng_type *gsl_rng_mt19937 = &mt_type;\nconst gsl_rng_type *gsl_rng_mt19937_1999 = &mt_1999_type;\nconst gsl_rng_type *gsl_rng_mt19937_1998 = &mt_1998_type;\n\n/* MT19937 is the default generator, so define that here too */\n\nconst gsl_rng_type *gsl_rng_default = &mt_type;\nunsigned long int gsl_rng_default_seed = 0;\n"
  },
  {
    "path": "gsl/rng/rng.c",
    "content": "/* rng/rng.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include \"gsl_errno.h\"\n#include \"gsl_rng.h\"\n\ngsl_rng *\ngsl_rng_alloc (const gsl_rng_type * T)\n{\n\n  gsl_rng *r = (gsl_rng *) malloc (sizeof (gsl_rng));\n\n  if (r == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for rng struct\",\n                        GSL_ENOMEM, 0);\n    };\n\n  r->state = calloc (1, T->size);\n\n  if (r->state == 0)\n    {\n      free (r);         /* exception in constructor, avoid memory leak */\n\n      GSL_ERROR_VAL (\"failed to allocate space for rng state\",\n                        GSL_ENOMEM, 0);\n    };\n\n  r->type = T;\n\n  gsl_rng_set (r, gsl_rng_default_seed);        /* seed the generator */\n\n  return r;\n}\n\nint\ngsl_rng_memcpy (gsl_rng * dest, const gsl_rng * src)\n{\n  if (dest->type != src->type)\n    {\n      GSL_ERROR (\"generators must be of the same type\", GSL_EINVAL);\n    }\n\n  memcpy (dest->state, src->state, src->type->size);\n\n  return GSL_SUCCESS;\n}\n\ngsl_rng *\ngsl_rng_clone (const gsl_rng * q)\n{\n  gsl_rng *r = (gsl_rng *) malloc (sizeof (gsl_rng));\n\n  if (r == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for rng struct\",\n                        GSL_ENOMEM, 0);\n    };\n\n  r->state = malloc (q->type->size);\n\n  if (r->state == 0)\n    {\n      free (r);         /* exception in constructor, avoid memory leak */\n\n      GSL_ERROR_VAL (\"failed to allocate space for rng state\",\n                        GSL_ENOMEM, 0);\n    };\n\n  r->type = q->type;\n\n  memcpy (r->state, q->state, q->type->size);\n\n  return r;\n}\n\nvoid\ngsl_rng_set (const gsl_rng * r, unsigned long int seed)\n{\n  (r->type->set) (r->state, seed);\n}\n\nunsigned long int\ngsl_rng_max (const gsl_rng * r)\n{\n  return r->type->max;\n}\n\nunsigned long int\ngsl_rng_min (const gsl_rng * r)\n{\n  return r->type->min;\n}\n\nconst char *\ngsl_rng_name (const gsl_rng * r)\n{\n  return r->type->name;\n}\n\nsize_t\ngsl_rng_size (const gsl_rng * r)\n{\n  return r->type->size;\n}\n\nvoid *\ngsl_rng_state (const gsl_rng * r)\n{\n  return r->state;\n}\n\nvoid\ngsl_rng_print_state (const gsl_rng * r)\n{\n  size_t i;\n  unsigned char *p = (unsigned char *) (r->state);\n  const size_t n = r->type->size;\n\n  for (i = 0; i < n; i++)\n    {\n      /* FIXME: we're assuming that a char is 8 bits */\n      printf (\"%.2x\", *(p + i));\n    }\n\n}\n\nvoid\ngsl_rng_free (gsl_rng * r)\n{\n  RETURN_IF_NULL (r);\n  free (r->state);\n  free (r);\n}\n"
  },
  {
    "path": "gsl/rng/taus.c",
    "content": "/* rng/taus.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_rng.h\"\n\n/* This is a maximally equidistributed combined Tausworthe\n   generator. The sequence is,\n\n   x_n = (s1_n ^ s2_n ^ s3_n) \n\n   s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))\n   s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))\n   s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))\n\n   computed modulo 2^32. In the three formulas above '^' means\n   exclusive-or (C-notation), not exponentiation. Note that the\n   algorithm relies on the properties of 32-bit unsigned integers (it\n   is formally defined on bit-vectors of length 32). I have added a\n   bitmask to make it work on 64 bit machines.\n\n   We initialize the generator with s1_1 .. s3_1 = s_n MOD m, where\n   s_n = (69069 * s_{n-1}) mod 2^32, and s_0 = s is the user-supplied\n   seed.\n\n   The theoretical value of x_{10007} is 2733957125. The subscript\n   10007 means (1) seed the generator with s=1 (2) do six warm-up\n   iterations, (3) then do 10000 actual iterations.\n\n   The period of this generator is about 2^88.\n\n   From: P. L'Ecuyer, \"Maximally Equidistributed Combined Tausworthe\n   Generators\", Mathematics of Computation, 65, 213 (1996), 203--213.\n\n   This is available on the net from L'Ecuyer's home page,\n\n   http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps\n   ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps \n\n   Update: April 2002\n\n   There is an erratum in the paper \"Tables of Maximally\n   Equidistributed Combined LFSR Generators\", Mathematics of\n   Computation, 68, 225 (1999), 261--269:\n   http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps\n\n        ... the k_j most significant bits of z_j must be non-\n        zero, for each j. (Note: this restriction also applies to the \n        computer code given in [4], but was mistakenly not mentioned in\n        that paper.)\n   \n   This affects the seeding procedure by imposing the requirement\n   s1 > 1, s2 > 7, s3 > 15.\n\n   The generator taus2 has been added to satisfy this requirement.\n   The original taus generator is unchanged.\n\n   Update: November 2002\n\n   There was a bug in the correction to the seeding procedure for s2.\n   It affected the following seeds 254679140 1264751179 1519430319\n   2274823218 2529502358 3284895257 3539574397 (s2 < 8).\n\n*/\n\nstatic unsigned long int taus_get (void *vstate);\nstatic double taus_get_double (void *vstate);\nstatic void taus_set (void *state, unsigned long int s);\n\ntypedef struct\n  {\n    unsigned long int s1, s2, s3;\n  }\ntaus_state_t;\n\nstatic inline unsigned long\ntaus_get (void *vstate)\n{\n  taus_state_t *state = (taus_state_t *) vstate;\n\n#define MASK 0xffffffffUL\n#define TAUSWORTHE(s,a,b,c,d) (((s &c) <<d) &MASK) ^ ((((s <<a) &MASK)^s) >>b)\n\n  state->s1 = TAUSWORTHE (state->s1, 13, 19, 4294967294UL, 12);\n  state->s2 = TAUSWORTHE (state->s2, 2, 25, 4294967288UL, 4);\n  state->s3 = TAUSWORTHE (state->s3, 3, 11, 4294967280UL, 17);\n\n  return (state->s1 ^ state->s2 ^ state->s3);\n}\n\nstatic double\ntaus_get_double (void *vstate)\n{\n  return taus_get (vstate) / 4294967296.0 ;\n}\n\nstatic void\ntaus_set (void *vstate, unsigned long int s)\n{\n  taus_state_t *state = (taus_state_t *) vstate;\n\n  if (s == 0)\n    s = 1;      /* default seed is 1 */\n\n#define LCG(n) ((69069 * n) & 0xffffffffUL)\n  state->s1 = LCG (s);\n  state->s2 = LCG (state->s1);\n  state->s3 = LCG (state->s2);\n\n  /* \"warm it up\" */\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  return;\n}\n\nstatic void\ntaus2_set (void *vstate, unsigned long int s)\n{\n  taus_state_t *state = (taus_state_t *) vstate;\n\n  if (s == 0)\n    s = 1;      /* default seed is 1 */\n\n#define LCG(n) ((69069 * n) & 0xffffffffUL)\n  state->s1 = LCG (s);\n  if (state->s1 < 2) state->s1 += 2UL;\n  state->s2 = LCG (state->s1);\n  if (state->s2 < 8) state->s2 += 8UL;\n  state->s3 = LCG (state->s2);\n  if (state->s3 < 16) state->s3 += 16UL;\n\n  /* \"warm it up\" */\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  taus_get (state);\n  return;\n}\n\n\nstatic const gsl_rng_type taus_type =\n{\"taus\",                        /* name */\n 0xffffffffUL,                  /* RAND_MAX */\n 0,                             /* RAND_MIN */\n sizeof (taus_state_t),\n &taus_set,\n &taus_get,\n &taus_get_double};\n\nconst gsl_rng_type *gsl_rng_taus = &taus_type;\n\nstatic const gsl_rng_type taus2_type =\n{\"taus2\",                       /* name */\n 0xffffffffUL,                  /* RAND_MAX */\n 0,                             /* RAND_MIN */\n sizeof (taus_state_t),\n &taus2_set,\n &taus_get,\n &taus_get_double};\n\nconst gsl_rng_type *gsl_rng_taus2 = &taus2_type;\n"
  },
  {
    "path": "gsl/specfunc/beta.c",
    "content": "/* specfunc/beta.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_log.h\"\n#include \"gsl_sf_psi.h\"\n#include \"gsl_sf_gamma.h\"\n\n#include \"error.h\"\n\nstatic double\nisnegint (const double x) \n{\n  return (x < 0) && (x == floor(x));\n}\n\nint\ngsl_sf_lnbeta_e(const double x, const double y, gsl_sf_result * result)\n{\n  double sgn;\n  int status = gsl_sf_lnbeta_sgn_e(x,y,result,&sgn);\n  if (sgn == -1) {\n    DOMAIN_ERROR(result);\n  }\n  return status;\n}\n\nint\ngsl_sf_lnbeta_sgn_e(const double x, const double y, gsl_sf_result * result, double * sgn)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x == 0.0 || y == 0.0) {\n    *sgn = 0.0;\n    DOMAIN_ERROR(result);\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n  } else if (isnegint(x) || isnegint(y)) {\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n    *sgn = 0.0;\n    DOMAIN_ERROR(result); /* not defined for negative integers */\n  }\n\n  /* See if we can handle the postive case with min/max < 0.2 */\n\n  if (x > 0 && y > 0) {\n    const double max = GSL_MAX(x,y);\n    const double min = GSL_MIN(x,y);\n    const double rat = min/max;\n    \n    if(rat < 0.2) {\n      /* min << max, so be careful\n       * with the subtraction\n       */\n      double lnpre_val;\n      double lnpre_err;\n      double lnpow_val;\n      double lnpow_err;\n      double t1, t2, t3;\n      gsl_sf_result lnopr;\n      gsl_sf_result gsx, gsy, gsxy;\n      gsl_sf_gammastar_e(x, &gsx);\n      gsl_sf_gammastar_e(y, &gsy);\n      gsl_sf_gammastar_e(x+y, &gsxy);\n      gsl_sf_log_1plusx_e(rat, &lnopr);\n      lnpre_val = log(gsx.val*gsy.val/gsxy.val * M_SQRT2*M_SQRTPI);\n      lnpre_err = gsx.err/gsx.val + gsy.err/gsy.val + gsxy.err/gsxy.val;\n      t1 = min*log(rat);\n      t2 = 0.5*log(min);\n      t3 = (x+y-0.5)*lnopr.val;\n      lnpow_val  = t1 - t2 - t3;\n      lnpow_err  = GSL_DBL_EPSILON * (fabs(t1) + fabs(t2) + fabs(t3));\n      lnpow_err += fabs(x+y-0.5) * lnopr.err;\n      result->val  = lnpre_val + lnpow_val;\n      result->err  = lnpre_err + lnpow_err;\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      *sgn = 1.0;\n      return GSL_SUCCESS;\n    }\n  }\n\n  /* General case - Fallback */\n  {\n    gsl_sf_result lgx, lgy, lgxy;\n    double sgx, sgy, sgxy, xy = x+y;\n    int stat_gx  = gsl_sf_lngamma_sgn_e(x, &lgx, &sgx);\n    int stat_gy  = gsl_sf_lngamma_sgn_e(y, &lgy, &sgy);\n    int stat_gxy = gsl_sf_lngamma_sgn_e(xy, &lgxy, &sgxy);\n    *sgn = sgx * sgy * sgxy;\n    result->val  = lgx.val + lgy.val - lgxy.val;\n    result->err  = lgx.err + lgy.err + lgxy.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * (fabs(lgx.val) + fabs(lgy.val) + fabs(lgxy.val));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_ERROR_SELECT_3(stat_gx, stat_gy, stat_gxy);\n  }\n}\n\n\nint\ngsl_sf_beta_e(const double x, const double y, gsl_sf_result * result)\n{\n  if((x > 0 && y > 0) && x < 50.0 && y < 50.0) {\n    /* Handle the easy case */\n    gsl_sf_result gx, gy, gxy;\n    gsl_sf_gamma_e(x, &gx);\n    gsl_sf_gamma_e(y, &gy);\n    gsl_sf_gamma_e(x+y, &gxy);\n    result->val  = (gx.val*gy.val)/gxy.val;\n    result->err  = gx.err * fabs(gy.val/gxy.val);\n    result->err += gy.err * fabs(gx.val/gxy.val);\n    result->err += fabs((gx.val*gy.val)/(gxy.val*gxy.val)) * gxy.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n  } else if (isnegint(x) || isnegint(y)) {\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n    DOMAIN_ERROR(result);\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n  } else if (isnegint(x+y)) {  /* infinity in the denominator */\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  } else {\n    gsl_sf_result lb;\n    double sgn;\n    int stat_lb = gsl_sf_lnbeta_sgn_e(x, y, &lb, &sgn);\n    if(stat_lb == GSL_SUCCESS) {\n      int status = gsl_sf_exp_err_e(lb.val, lb.err, result);\n      result->val *= sgn;\n      return status;\n    }\n    else {\n      result->val = 0.0;\n      result->err = 0.0;\n      return stat_lb;\n    }\n  }\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_lnbeta(const double x, const double y)\n{\n  EVAL_RESULT(gsl_sf_lnbeta_e(x, y, &result));\n}\n\ndouble gsl_sf_beta(const double x, const double y)\n{\n  EVAL_RESULT(gsl_sf_beta_e(x, y, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/cheb_eval.inc",
    "content": "\nstatic inline int\ncheb_eval_e(const cheb_series * cs,\n            const double x,\n            gsl_sf_result * result)\n{\n  int j;\n  double d  = 0.0;\n  double dd = 0.0;\n\n  double y  = (2.0*x - cs->a - cs->b) / (cs->b - cs->a);\n  double y2 = 2.0 * y;\n\n  double e = 0.0;\n\n  for(j = cs->order; j>=1; j--) {\n    double temp = d;\n    d = y2*d - dd + cs->c[j];\n    e += fabs(y2*temp) + fabs(dd) + fabs(cs->c[j]);\n    dd = temp;\n  }\n\n  { \n    double temp = d;\n    d = y*d - dd + 0.5 * cs->c[0];\n    e += fabs(y*temp) + fabs(dd) + 0.5 * fabs(cs->c[0]);\n  }\n\n  result->val = d;\n  result->err = GSL_DBL_EPSILON * e + fabs(cs->c[cs->order]);\n\n  return GSL_SUCCESS;\n}\n\n"
  },
  {
    "path": "gsl/specfunc/chebyshev.h",
    "content": "/* specfunc/chebyshev.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* data for a Chebyshev series over a given interval */\n\nstruct cheb_series_struct {\n  double * c;   /* coefficients                */\n  int order;    /* order of expansion          */\n  double a;     /* lower interval point        */\n  double b;     /* upper interval point        */\n  int order_sp; /* effective single precision order */\n};\ntypedef struct cheb_series_struct cheb_series;\n\n\n"
  },
  {
    "path": "gsl/specfunc/check.h",
    "content": "/* check for underflow */\n\n#define CHECK_UNDERFLOW(r) if (fabs((r)->val) < GSL_DBL_MIN) GSL_ERROR(\"underflow\", GSL_EUNDRFLW);\n"
  },
  {
    "path": "gsl/specfunc/elementary.c",
    "content": "/* specfunc/elementary.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_elementary.h\"\n\n#include \"error.h\"\n#include \"check.h\"\n\nint\ngsl_sf_multiply_e(const double x, const double y, gsl_sf_result * result)\n{\n  const double ax = fabs(x);\n  const double ay = fabs(y);\n\n  if(x == 0.0 || y == 0.0) {\n    /* It is necessary to eliminate this immediately.\n     */\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if((ax <= 1.0 && ay >= 1.0) || (ay <= 1.0 && ax >= 1.0)) {\n    /* Straddling 1.0 is always safe.\n     */\n    result->val = x*y;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    const double f = 1.0 - 2.0 * GSL_DBL_EPSILON;\n    const double min = GSL_MIN_DBL(fabs(x), fabs(y));\n    const double max = GSL_MAX_DBL(fabs(x), fabs(y));\n    if(max < 0.9 * GSL_SQRT_DBL_MAX || min < (f * DBL_MAX)/max) {\n      result->val = GSL_COERCE_DBL(x*y);\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      CHECK_UNDERFLOW(result);\n      return GSL_SUCCESS;\n    }\n    else {\n      OVERFLOW_ERROR(result);\n    }\n  }\n}\n\n\nint\ngsl_sf_multiply_err_e(const double x, const double dx,\n                         const double y, const double dy,\n                         gsl_sf_result * result)\n{\n  int status = gsl_sf_multiply_e(x, y, result);\n  result->err += fabs(dx*y) + fabs(dy*x);\n  return status;\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_multiply(const double x, const double y)\n{\n  EVAL_RESULT(gsl_sf_multiply_e(x, y, &result));\n}\n\n"
  },
  {
    "path": "gsl/specfunc/erfc.c",
    "content": "/* specfunc/erfc.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  J. Theiler (modifications by G. Jungman) */\n\n/*\n * See Hart et al, Computer Approximations, John Wiley and Sons, New York (1968)\n * (This applies only to the erfc8 stuff, which is the part\n *  of the original code that survives. I have replaced much of\n *  the other stuff with Chebyshev fits. These are simpler and\n *  more precise than the original approximations. [GJ])\n */\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_erf.h\"\n\n#include \"check.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n#define LogRootPi_  0.57236494292470008706\n\n\nstatic double erfc8_sum(double x)\n{\n  /* estimates erfc(x) valid for 8 < x < 100 */\n  /* This is based on index 5725 in Hart et al */\n\n  static double P[] = {\n      2.97886562639399288862,\n      7.409740605964741794425,\n      6.1602098531096305440906,\n      5.019049726784267463450058,\n      1.275366644729965952479585264,\n      0.5641895835477550741253201704\n  };\n  static double Q[] = {\n      3.3690752069827527677,\n      9.608965327192787870698,\n      17.08144074746600431571095,\n      12.0489519278551290360340491,\n      9.396034016235054150430579648,\n      2.260528520767326969591866945,\n      1.0\n  };\n  double num=0.0, den=0.0;\n  int i;\n\n  num = P[5];\n  for (i=4; i>=0; --i) {\n      num = x*num + P[i];\n  }\n  den = Q[6];\n  for (i=5; i>=0; --i) {\n      den = x*den + Q[i];\n  }\n\n  return num/den;\n}\n\ninline\nstatic double erfc8(double x)\n{\n  double e;\n  e = erfc8_sum(x);\n  e *= exp(-x*x);\n  return e;\n}\n\ninline\nstatic double log_erfc8(double x)\n{\n  double e;\n  e = erfc8_sum(x);\n  e = log(e) - x*x;\n  return e;\n}\n\n#if 0\n/* Abramowitz+Stegun, 7.2.14 */\nstatic double erfcasympsum(double x)\n{\n  int i;\n  double e = 1.;\n  double coef = 1.;\n  for (i=1; i<5; ++i) {\n    /* coef *= -(2*i-1)/(2*x*x); ??? [GJ] */\n    coef *= -(2*i+1)/(i*(4*x*x*x*x));\n    e += coef;\n    /*\n    if (fabs(coef) < 1.0e-15) break;\n    if (fabs(coef) > 1.0e10) break;\n    \n    [GJ]: These tests are not useful. This function is only\n    used below. Took them out; they gum up the pipeline.\n    */\n  }\n  return e;\n}\n#endif /* 0 */\n\n\n/* Abramowitz+Stegun, 7.1.5 */\nstatic int erfseries(double x, gsl_sf_result * result)\n{\n  double coef = x;\n  double e    = coef;\n  double del;\n  int k;\n  for (k=1; k<30; ++k) {\n    coef *= -x*x/k;\n    del   = coef/(2.0*k+1.0);\n    e += del;\n  }\n  result->val = 2.0 / M_SQRTPI * e;\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wuninitialized\"\n#if (GNU_C >= 5)\n#pragma GCC diagnostic ignored \"-Wconditional-uninitialized\"\n#endif\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wuninitialized\"\n#pragma clang diagnostic ignored \"-Wconditional-uninitialized\"\n  result->err = 2.0 / M_SQRTPI * (fabs(del) + GSL_DBL_EPSILON);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n  return GSL_SUCCESS;\n}\n\n\n/* Chebyshev fit for erfc((t+1)/2), -1 < t < 1\n */\nstatic double erfc_xlt1_data[20] = {\n  1.06073416421769980345174155056,\n -0.42582445804381043569204735291,\n  0.04955262679620434040357683080,\n  0.00449293488768382749558001242,\n -0.00129194104658496953494224761,\n -0.00001836389292149396270416979,\n  0.00002211114704099526291538556,\n -5.23337485234257134673693179020e-7,\n -2.78184788833537885382530989578e-7,\n  1.41158092748813114560316684249e-8,\n  2.72571296330561699984539141865e-9,\n -2.06343904872070629406401492476e-10,\n -2.14273991996785367924201401812e-11,\n  2.22990255539358204580285098119e-12,\n  1.36250074650698280575807934155e-13,\n -1.95144010922293091898995913038e-14,\n -6.85627169231704599442806370690e-16,\n  1.44506492869699938239521607493e-16,\n  2.45935306460536488037576200030e-18,\n -9.29599561220523396007359328540e-19\n};\nstatic cheb_series erfc_xlt1_cs = {\n  erfc_xlt1_data,\n  19,\n  -1, 1,\n  12\n};\n\n/* Chebyshev fit for erfc(x) exp(x^2), 1 < x < 5, x = 2t + 3, -1 < t < 1\n */\nstatic double erfc_x15_data[25] = {\n  0.44045832024338111077637466616,\n -0.143958836762168335790826895326,\n  0.044786499817939267247056666937,\n -0.013343124200271211203618353102,\n  0.003824682739750469767692372556,\n -0.001058699227195126547306482530,\n  0.000283859419210073742736310108,\n -0.000073906170662206760483959432,\n  0.000018725312521489179015872934,\n -4.62530981164919445131297264430e-6,\n  1.11558657244432857487884006422e-6,\n -2.63098662650834130067808832725e-7,\n  6.07462122724551777372119408710e-8,\n -1.37460865539865444777251011793e-8,\n  3.05157051905475145520096717210e-9,\n -6.65174789720310713757307724790e-10,\n  1.42483346273207784489792999706e-10,\n -3.00141127395323902092018744545e-11,\n  6.22171792645348091472914001250e-12,\n -1.26994639225668496876152836555e-12,\n  2.55385883033257575402681845385e-13,\n -5.06258237507038698392265499770e-14,\n  9.89705409478327321641264227110e-15,\n -1.90685978789192181051961024995e-15,\n  3.50826648032737849245113757340e-16\n};\nstatic cheb_series erfc_x15_cs = {\n  erfc_x15_data,\n  24,\n  -1, 1,\n  16\n};\n\n/* Chebyshev fit for erfc(x) x exp(x^2), 5 < x < 10, x = (5t + 15)/2, -1 < t < 1\n */\nstatic double erfc_x510_data[20] = {\n  1.11684990123545698684297865808,\n  0.003736240359381998520654927536,\n -0.000916623948045470238763619870,\n  0.000199094325044940833965078819,\n -0.000040276384918650072591781859,\n  7.76515264697061049477127605790e-6,\n -1.44464794206689070402099225301e-6,\n  2.61311930343463958393485241947e-7,\n -4.61833026634844152345304095560e-8,\n  8.00253111512943601598732144340e-9,\n -1.36291114862793031395712122089e-9,\n  2.28570483090160869607683087722e-10,\n -3.78022521563251805044056974560e-11,\n  6.17253683874528285729910462130e-12,\n -9.96019290955316888445830597430e-13,\n  1.58953143706980770269506726000e-13,\n -2.51045971047162509999527428316e-14,\n  3.92607828989125810013581287560e-15,\n -6.07970619384160374392535453420e-16,\n  9.12600607264794717315507477670e-17\n};\nstatic cheb_series erfc_x510_cs = {\n  erfc_x510_data,\n  19,\n  -1, 1,\n  12\n};\n\n#if 0\ninline\nstatic double\nerfc_asymptotic(double x)\n{\n  return exp(-x*x)/x * erfcasympsum(x) / M_SQRTPI;\n}\ninline\nstatic double\nlog_erfc_asymptotic(double x)\n{\n  return log(erfcasympsum(x)/x) - x*x - LogRootPi_;\n}\n#endif /* 0 */\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\nint gsl_sf_erfc_e(double x, gsl_sf_result * result)\n{\n  const double ax = fabs(x);\n  double e_val, e_err;\n\n  /* CHECK_POINTER(result) */\n\n  if(ax <= 1.0) {\n    double t = 2.0*ax - 1.0;\n    gsl_sf_result c;\n    cheb_eval_e(&erfc_xlt1_cs, t, &c);\n    e_val = c.val;\n    e_err = c.err;\n  }\n  else if(ax <= 5.0) {\n    double ex2 = exp(-x*x);\n    double t = 0.5*(ax-3.0);\n    gsl_sf_result c;\n    cheb_eval_e(&erfc_x15_cs, t, &c);\n    e_val = ex2 * c.val;\n    e_err = ex2 * (c.err + 2.0*fabs(x)*GSL_DBL_EPSILON);\n  }\n  else if(ax < 10.0) {\n    double exterm = exp(-x*x) / ax;\n    double t = (2.0*ax - 15.0)/5.0;\n    gsl_sf_result c;\n    cheb_eval_e(&erfc_x510_cs, t, &c);\n    e_val = exterm * c.val;\n    e_err = exterm * (c.err + 2.0*fabs(x)*GSL_DBL_EPSILON + GSL_DBL_EPSILON);\n  }\n  else {\n    e_val = erfc8(ax);\n    e_err = (x*x + 1.0) * GSL_DBL_EPSILON * fabs(e_val);\n  }\n\n  if(x < 0.0) {\n    result->val  = 2.0 - e_val;\n    result->err  = e_err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n  }\n  else {\n    result->val  = e_val;\n    result->err  = e_err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n  }\n\n  return GSL_SUCCESS;\n}\n\n\nint gsl_sf_log_erfc_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x*x < 10.0*GSL_ROOT6_DBL_EPSILON) {\n    const double y = x / M_SQRTPI;\n    /* series for -1/2 Log[Erfc[Sqrt[Pi] y]] */\n    const double c3 = (4.0 - M_PI)/3.0;\n    const double c4 = 2.0*(1.0 - M_PI/3.0);\n    const double c5 = -0.001829764677455021;  /* (96.0 - 40.0*M_PI + 3.0*M_PI*M_PI)/30.0  */\n    const double c6 =  0.02629651521057465;   /* 2.0*(120.0 - 60.0*M_PI + 7.0*M_PI*M_PI)/45.0 */\n    const double c7 = -0.01621575378835404;\n    const double c8 =  0.00125993961762116;\n    const double c9 =  0.00556964649138;\n    const double c10 = -0.0045563339802;\n    const double c11 =  0.0009461589032;\n    const double c12 =  0.0013200243174;\n    const double c13 = -0.00142906;\n    const double c14 =  0.00048204;\n    double series = c8 + y*(c9 + y*(c10 + y*(c11 + y*(c12 + y*(c13 + c14*y)))));\n    series = y*(1.0 + y*(1.0 + y*(c3 + y*(c4 + y*(c5 + y*(c6 + y*(c7 + y*series)))))));\n    result->val = -2.0 * series;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  /*\n  don't like use of log1p(); added above series stuff for small x instead, should be ok [GJ]\n  else if (fabs(x) < 1.0) {\n    gsl_sf_result result_erf;\n    gsl_sf_erf_e(x, &result_erf);\n    result->val  = log1p(-result_erf.val);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  */\n  else if(x > 8.0) {\n    result->val = log_erfc8(x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_result result_erfc;\n    gsl_sf_erfc_e(x, &result_erfc);\n    result->val  = log(result_erfc.val);\n    result->err  = fabs(result_erfc.err / result_erfc.val);\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_erf_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(fabs(x) < 1.0) {\n    return erfseries(x, result);\n  }\n  else {\n    gsl_sf_result result_erfc;\n    gsl_sf_erfc_e(x, &result_erfc);\n    result->val  = 1.0 - result_erfc.val;\n    result->err  = result_erfc.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_erf_Z_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    const double ex2 = exp(-x*x/2.0);\n    result->val  = ex2 / (M_SQRT2 * M_SQRTPI);\n    result->err  = fabs(x * result->val) * GSL_DBL_EPSILON;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    CHECK_UNDERFLOW(result);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_erf_Q_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    gsl_sf_result result_erfc;\n    int stat = gsl_sf_erfc_e(x/M_SQRT2, &result_erfc);\n    result->val  = 0.5 * result_erfc.val;\n    result->err  = 0.5 * result_erfc.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return stat;\n  }\n}\n\n\nint gsl_sf_hazard_e(double x, gsl_sf_result * result)\n{\n  if(x < 25.0)\n  {\n    gsl_sf_result result_ln_erfc;\n    const int stat_l = gsl_sf_log_erfc_e(x/M_SQRT2, &result_ln_erfc);\n    const double lnc = -0.22579135264472743236; /* ln(sqrt(2/pi)) */\n    const double arg = lnc - 0.5*x*x - result_ln_erfc.val;\n    const int stat_e = gsl_sf_exp_e(arg, result);\n    result->err += 3.0 * (1.0 + fabs(x)) * GSL_DBL_EPSILON * fabs(result->val);\n    result->err += fabs(result_ln_erfc.err * result->val);\n    return GSL_ERROR_SELECT_2(stat_l, stat_e);\n  }\n  else\n  {\n    const double ix2 = 1.0/(x*x);\n    const double corrB = 1.0 - 9.0*ix2 * (1.0 - 11.0*ix2);\n    const double corrM = 1.0 - 5.0*ix2 * (1.0 - 7.0*ix2 * corrB);\n    const double corrT = 1.0 - ix2 * (1.0 - 3.0*ix2*corrM);\n    result->val = x / corrT;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_erfc(double x)\n{\n  EVAL_RESULT(gsl_sf_erfc_e(x, &result));\n}\n\ndouble gsl_sf_log_erfc(double x)\n{\n  EVAL_RESULT(gsl_sf_log_erfc_e(x, &result));\n}\n\ndouble gsl_sf_erf(double x)\n{\n  EVAL_RESULT(gsl_sf_erf_e(x, &result));\n}\n\ndouble gsl_sf_erf_Z(double x)\n{\n  EVAL_RESULT(gsl_sf_erf_Z_e(x, &result));\n}\n\ndouble gsl_sf_erf_Q(double x)\n{\n  EVAL_RESULT(gsl_sf_erf_Q_e(x, &result));\n}\n\ndouble gsl_sf_hazard(double x)\n{\n  EVAL_RESULT(gsl_sf_hazard_e(x, &result));\n}\n\n"
  },
  {
    "path": "gsl/specfunc/error.h",
    "content": "#define OVERFLOW_ERROR(result) do { (result)->val = GSL_POSINF; (result)->err = GSL_POSINF; GSL_ERROR (\"overflow\", GSL_EOVRFLW); } while(0)\n\n#define UNDERFLOW_ERROR(result) do { (result)->val = 0.0; (result)->err = GSL_DBL_MIN; GSL_ERROR (\"underflow\", GSL_EUNDRFLW); } while(0)\n\n#define INTERNAL_OVERFLOW_ERROR(result) do { (result)->val = GSL_POSINF; (result)->err = GSL_POSINF; return GSL_EOVRFLW; } while(0)\n\n#define INTERNAL_UNDERFLOW_ERROR(result) do { (result)->val = 0.0; (result)->err = GSL_DBL_MIN; return GSL_EUNDRFLW; } while(0)\n\n#define DOMAIN_ERROR(result) do { (result)->val = GSL_NAN; (result)->err = GSL_NAN; GSL_ERROR (\"domain error\", GSL_EDOM); } while(0)\n\n#define DOMAIN_ERROR_MSG(msg, result) do { (result)->val = GSL_NAN; (result)->err = GSL_NAN; GSL_ERROR ((msg), GSL_EDOM); } while(0)\n\n#define DOMAIN_ERROR_E10(result) do { (result)->val = GSL_NAN; (result)->err = GSL_NAN; (result)->e10 = 0 ; GSL_ERROR (\"domain error\", GSL_EDOM); } while(0)\n\n#define OVERFLOW_ERROR_E10(result) do { (result)->val = GSL_POSINF; (result)->err = GSL_POSINF; (result)->e10 = 0; GSL_ERROR (\"overflow\", GSL_EOVRFLW); } while(0)\n#define UNDERFLOW_ERROR_E10(result) do { (result)->val = 0.0; (result)->err = GSL_DBL_MIN; (result)->e10 = 0; GSL_ERROR (\"underflow\", GSL_EUNDRFLW); } while(0)\n\n\n#define OVERFLOW_ERROR_2(r1,r2) do { (r1)->val = GSL_POSINF; (r1)->err = GSL_POSINF; (r2)->val = GSL_POSINF ; (r2)->err=GSL_POSINF; GSL_ERROR (\"overflow\", GSL_EOVRFLW); } while(0)\n\n#define UNDERFLOW_ERROR_2(r1,r2) do { (r1)->val = 0.0; (r1)->err = GSL_DBL_MIN; (r2)->val = 0.0 ; (r2)->err = GSL_DBL_MIN; GSL_ERROR (\"underflow\", GSL_EUNDRFLW); } while(0)\n\n#define DOMAIN_ERROR_2(r1,r2) do { (r1)->val = GSL_NAN; (r1)->err = GSL_NAN;  (r2)->val = GSL_NAN; (r2)->err = GSL_NAN;  GSL_ERROR (\"domain error\", GSL_EDOM); } while(0)\n\n#define MAXITER_ERROR(result) do { (result)->val = GSL_NAN; (result)->err = GSL_NAN; GSL_ERROR (\"too many iterations error\", GSL_EMAXITER); } while(0)\n"
  },
  {
    "path": "gsl/specfunc/eval.h",
    "content": "/* evaluate a function discarding the status value in a modifiable way */\n\n#define EVAL_RESULT(fn) \\\n   gsl_sf_result result; \\\n   int status = fn; \\\n   if (status != GSL_SUCCESS) { \\\n     GSL_ERROR_VAL(#fn, status, result.val); \\\n   } ; \\\n   return result.val;\n\n#define EVAL_DOUBLE(fn) \\\n   int status = fn; \\\n   if (status != GSL_SUCCESS) { \\\n     GSL_ERROR_VAL(#fn, status, result); \\\n   } ; \\\n   return result;\n\n"
  },
  {
    "path": "gsl/specfunc/exp.c",
    "content": "/* specfunc/exp.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_sf_exp.h\"\n\n#include \"error.h\"\n\n/* Evaluate the continued fraction for exprel.\n * [Abramowitz+Stegun, 4.2.41]\n */\nstatic\nint\nexprel_n_CF(const double N, const double x, gsl_sf_result * result)\n{\n  const double RECUR_BIG = GSL_SQRT_DBL_MAX;\n  const int maxiter = 5000;\n  int n = 1;\n  double Anm2 = 1.0;\n  double Bnm2 = 0.0;\n  double Anm1 = 0.0;\n  double Bnm1 = 1.0;\n  double a1 = 1.0;\n  double b1 = 1.0;\n  double a2 = -x;\n  double b2 = N+1;\n  double an, bn;\n\n  double fn;\n\n  double An = b1*Anm1 + a1*Anm2;   /* A1 */\n  double Bn = b1*Bnm1 + a1*Bnm2;   /* B1 */\n  \n  /* One explicit step, before we get to the main pattern. */\n  n++;\n  Anm2 = Anm1;\n  Bnm2 = Bnm1;\n  Anm1 = An;\n  Bnm1 = Bn;\n  An = b2*Anm1 + a2*Anm2;   /* A2 */\n  Bn = b2*Bnm1 + a2*Bnm2;   /* B2 */\n\n  fn = An/Bn;\n\n  while(n < maxiter) {\n    double old_fn;\n    double del;\n    n++;\n    Anm2 = Anm1;\n    Bnm2 = Bnm1;\n    Anm1 = An;\n    Bnm1 = Bn;\n    an = ( GSL_IS_ODD(n) ? ((n-1)/2)*x : -(N+(n/2)-1)*x );\n    bn = N + n - 1;\n    An = bn*Anm1 + an*Anm2;\n    Bn = bn*Bnm1 + an*Bnm2;\n\n    if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {\n      An /= RECUR_BIG;\n      Bn /= RECUR_BIG;\n      Anm1 /= RECUR_BIG;\n      Bnm1 /= RECUR_BIG;\n      Anm2 /= RECUR_BIG;\n      Bnm2 /= RECUR_BIG;\n\t\t\n#ifdef __clang_analyzer__\n\t\t// acknowledge dead stores; I have no idea why the GSL does this...\n\t\tAnm2;\n\t\tBnm2;\n#endif\n    }\n\n    old_fn = fn;\n    fn = An/Bn;\n    del = old_fn/fn;\n    \n    if(fabs(del - 1.0) < 2.0*GSL_DBL_EPSILON) break;\n  }\n\n  result->val = fn;\n  result->err = 4.0*(n+1.0)*GSL_DBL_EPSILON*fabs(fn);\n\n  if(n == maxiter)\n    GSL_ERROR (\"error\", GSL_EMAXITER);\n  else\n    return GSL_SUCCESS;\n}\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\nint gsl_sf_exp_e(const double x, gsl_sf_result * result)\n{\n  if(x > GSL_LOG_DBL_MAX) {\n    OVERFLOW_ERROR(result);\n  }\n  else if(x < GSL_LOG_DBL_MIN) {\n    UNDERFLOW_ERROR(result);\n  }\n  else {\n    result->val = exp(x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\nint gsl_sf_exp_e10_e(const double x, gsl_sf_result_e10 * result)\n{\n  if(x > INT_MAX-1) {\n    OVERFLOW_ERROR_E10(result);\n  }\n  else if(x < INT_MIN+1) {\n    UNDERFLOW_ERROR_E10(result);\n  }\n  else {\n    const int N = (x > GSL_LOG_DBL_MAX || x < GSL_LOG_DBL_MIN) ? (int) floor(x/M_LN10) : 0;\n    result->val = exp(x-N*M_LN10);\n    result->err = 2.0 * (fabs(x)+1.0) * GSL_DBL_EPSILON * fabs(result->val);\n    result->e10 = N;\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_exp_mult_e(const double x, const double y, gsl_sf_result * result)\n{\n  const double ay  = fabs(y);\n\n  if(y == 0.0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(   ( x < 0.5*GSL_LOG_DBL_MAX   &&   x > 0.5*GSL_LOG_DBL_MIN)\n          && (ay < 0.8*GSL_SQRT_DBL_MAX  &&  ay > 1.2*GSL_SQRT_DBL_MIN)\n    ) {\n    const double ex = exp(x);\n    result->val = y * ex;\n    result->err = (2.0 + fabs(x)) * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    const double ly  = log(ay);\n    const double lnr = x + ly;\n\n    if(lnr > GSL_LOG_DBL_MAX - 0.01) {\n      OVERFLOW_ERROR(result);\n    }\n    else if(lnr < GSL_LOG_DBL_MIN + 0.01) {\n      UNDERFLOW_ERROR(result);\n    }\n    else {\n      const double sy   = GSL_SIGN(y);\n      const double M    = floor(x);\n      const double N    = floor(ly);\n      const double a    = x  - M;\n      const double b    = ly - N;\n      const double berr = 2.0 * GSL_DBL_EPSILON * (fabs(ly) + fabs(N));\n      result->val  = sy * exp(M+N) * exp(a+b);\n      result->err  = berr * fabs(result->val);\n      result->err += 2.0 * GSL_DBL_EPSILON * (M + N + 1.0) * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint gsl_sf_exp_mult_e10_e(const double x, const double y, gsl_sf_result_e10 * result)\n{\n  const double ay  = fabs(y);\n\n  if(y == 0.0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    result->e10 = 0;\n    return GSL_SUCCESS;\n  }\n  else if(   ( x < 0.5*GSL_LOG_DBL_MAX   &&   x > 0.5*GSL_LOG_DBL_MIN)\n          && (ay < 0.8*GSL_SQRT_DBL_MAX  &&  ay > 1.2*GSL_SQRT_DBL_MIN)\n    ) {\n    const double ex = exp(x);\n    result->val = y * ex;\n    result->err = (2.0 + fabs(x)) * GSL_DBL_EPSILON * fabs(result->val);\n    result->e10 = 0;\n    return GSL_SUCCESS;\n  }\n  else {\n    const double ly  = log(ay);\n    const double l10_val = (x + ly)/M_LN10;\n\n    if(l10_val > INT_MAX-1) {\n      OVERFLOW_ERROR_E10(result);\n    }\n    else if(l10_val < INT_MIN+1) {\n      UNDERFLOW_ERROR_E10(result);\n    }\n    else {\n      const double sy  = GSL_SIGN(y);\n      const int    N   = (int) floor(l10_val);\n      const double arg_val = (l10_val - N) * M_LN10;\n#pragma GCC diagnostic push\n#if (GNU_C >= 5)\n#pragma GCC diagnostic ignored \"-Wabsolute-value\"\n#endif\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wabsolute-value\"\n\t\tconst double arg_err = 2.0 * GSL_DBL_EPSILON * (fabs(x) + fabs(ly) + M_LN10*fabs(N));   // may produce a warning; ignore\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\n      result->val  = sy * exp(arg_val);\n      result->err  = arg_err * fabs(result->val);\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      result->e10 = N;\n\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint gsl_sf_exp_mult_err_e(const double x, const double dx,\n                             const double y, const double dy,\n                             gsl_sf_result * result)\n{\n  const double ay  = fabs(y);\n\n  if(y == 0.0) {\n    result->val = 0.0;\n    result->err = fabs(dy * exp(x));\n    return GSL_SUCCESS;\n  }\n  else if(   ( x < 0.5*GSL_LOG_DBL_MAX   &&   x > 0.5*GSL_LOG_DBL_MIN)\n          && (ay < 0.8*GSL_SQRT_DBL_MAX  &&  ay > 1.2*GSL_SQRT_DBL_MIN)\n    ) {\n    double ex = exp(x);\n    result->val  = y * ex;\n    result->err  = ex * (fabs(dy) + fabs(y*dx));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    const double ly  = log(ay);\n    const double lnr = x + ly;\n\n    if(lnr > GSL_LOG_DBL_MAX - 0.01) {\n      OVERFLOW_ERROR(result);\n    }\n    else if(lnr < GSL_LOG_DBL_MIN + 0.01) {\n      UNDERFLOW_ERROR(result);\n    }\n    else {\n      const double sy  = GSL_SIGN(y);\n      const double M   = floor(x);\n      const double N   = floor(ly);\n      const double a   = x  - M;\n      const double b   = ly - N;\n      const double eMN = exp(M+N);\n      const double eab = exp(a+b);\n      result->val  = sy * eMN * eab;\n      result->err  = eMN * eab * 2.0*GSL_DBL_EPSILON;\n      result->err += eMN * eab * fabs(dy/y);\n      result->err += eMN * eab * fabs(dx);\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint gsl_sf_exp_mult_err_e10_e(const double x, const double dx,\n                             const double y, const double dy,\n                             gsl_sf_result_e10 * result)\n{\n  const double ay  = fabs(y);\n\n  if(y == 0.0) {\n    result->val = 0.0;\n    result->err = fabs(dy * exp(x));\n    result->e10 = 0;\n    return GSL_SUCCESS;\n  }\n  else if(   ( x < 0.5*GSL_LOG_DBL_MAX   &&   x > 0.5*GSL_LOG_DBL_MIN)\n          && (ay < 0.8*GSL_SQRT_DBL_MAX  &&  ay > 1.2*GSL_SQRT_DBL_MIN)\n    ) {\n    const double ex = exp(x);\n    result->val  = y * ex;\n    result->err  = ex * (fabs(dy) + fabs(y*dx));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    result->e10 = 0;\n    return GSL_SUCCESS;\n  }\n  else {\n    const double ly  = log(ay);\n    const double l10_val = (x + ly)/M_LN10;\n\n    if(l10_val > INT_MAX-1) {\n      OVERFLOW_ERROR_E10(result);\n    }\n    else if(l10_val < INT_MIN+1) {\n      UNDERFLOW_ERROR_E10(result);\n    }\n    else {\n      const double sy  = GSL_SIGN(y);\n      const int    N   = (int) floor(l10_val);\n      const double arg_val = (l10_val - N) * M_LN10;\n      const double arg_err = dy/fabs(y) + dx + 2.0*GSL_DBL_EPSILON*fabs(arg_val);\n\n      result->val  = sy * exp(arg_val);\n      result->err  = arg_err * fabs(result->val);\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      result->e10 = N;\n\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint gsl_sf_expm1_e(const double x, gsl_sf_result * result)\n{\n  const double cut = 0.002;\n\n  if(x < GSL_LOG_DBL_MIN) {\n    result->val = -1.0;\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(x < -cut) {\n    result->val = exp(x) - 1.0;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < cut) {\n    result->val = x * (1.0 + 0.5*x*(1.0 + x/3.0*(1.0 + 0.25*x*(1.0 + 0.2*x))));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  } \n  else if(x < GSL_LOG_DBL_MAX) {\n    result->val = exp(x) - 1.0;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\nint gsl_sf_exprel_e(const double x, gsl_sf_result * result)\n{\n  const double cut = 0.002;\n\n  if(x < GSL_LOG_DBL_MIN) {\n    result->val = -1.0/x;\n    result->err = GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < -cut) {\n    result->val = (exp(x) - 1.0)/x;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < cut) {\n    result->val = (1.0 + 0.5*x*(1.0 + x/3.0*(1.0 + 0.25*x*(1.0 + 0.2*x))));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  } \n  else if(x < GSL_LOG_DBL_MAX) {\n    result->val = (exp(x) - 1.0)/x;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\nint gsl_sf_exprel_2_e(double x, gsl_sf_result * result)\n{\n  const double cut = 0.002;\n\n  if(x < GSL_LOG_DBL_MIN) {\n    result->val = -2.0/x*(1.0 + 1.0/x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < -cut) {\n    result->val = 2.0*(exp(x) - 1.0 - x)/(x*x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < cut) {\n    result->val = (1.0 + 1.0/3.0*x*(1.0 + 0.25*x*(1.0 + 0.2*x*(1.0 + 1.0/6.0*x))));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  } \n  else if(x < GSL_LOG_DBL_MAX) {\n    result->val = 2.0*(exp(x) - 1.0 - x)/(x*x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\nint\ngsl_sf_exprel_n_CF_e(const double N, const double x, gsl_sf_result * result)\n{\n  return exprel_n_CF(N, x, result);\n}\n\nint\ngsl_sf_exprel_n_e(const int N, const double x, gsl_sf_result * result)\n{\n  if(N < 0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x == 0.0) {\n    result->val = 1.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(fabs(x) < GSL_ROOT3_DBL_EPSILON * N) {\n    result->val = 1.0 + x/(N+1) * (1.0 + x/(N+2));\n    result->err = 2.0 * GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(N == 0) {\n    return gsl_sf_exp_e(x, result);\n  }\n  else if(N == 1) {\n    return gsl_sf_exprel_e(x, result);\n  }\n  else if(N == 2) {\n    return gsl_sf_exprel_2_e(x, result);\n  }\n  else {\n    if(x > N && (-x + N*(1.0 + log(x/N)) < GSL_LOG_DBL_EPSILON)) {\n      /* x is much larger than n.\n       * Ignore polynomial part, so\n       * exprel_N(x) ~= e^x N!/x^N\n       */\n      gsl_sf_result lnf_N;\n      double lnr_val;\n      double lnr_err;\n      double lnterm;\n      gsl_sf_lnfact_e(N, &lnf_N);\n      lnterm = N*log(x);\n      lnr_val  = x + lnf_N.val - lnterm;\n      lnr_err  = GSL_DBL_EPSILON * (fabs(x) + fabs(lnf_N.val) + fabs(lnterm));\n      lnr_err += lnf_N.err;\n      return gsl_sf_exp_err_e(lnr_val, lnr_err, result);\n    }\n    else if(x > N) {\n      /* Write the identity\n       *   exprel_n(x) = e^x n! / x^n (1 - Gamma[n,x]/Gamma[n])\n       * then use the asymptotic expansion\n       * Gamma[n,x] ~ x^(n-1) e^(-x) (1 + (n-1)/x + (n-1)(n-2)/x^2 + ...)\n       */\n      double ln_x = log(x);\n      gsl_sf_result lnf_N;\n      double lg_N;\n      double lnpre_val;\n      double lnpre_err;\n      gsl_sf_lnfact_e(N, &lnf_N);    /* log(N!)       */\n      lg_N  = lnf_N.val - log(N);       /* log(Gamma(N)) */\n      lnpre_val  = x + lnf_N.val - N*ln_x;\n      lnpre_err  = GSL_DBL_EPSILON * (fabs(x) + fabs(lnf_N.val) + fabs(N*ln_x));\n      lnpre_err += lnf_N.err;\n      if(lnpre_val < GSL_LOG_DBL_MAX - 5.0) {\n        int stat_eG;\n        gsl_sf_result bigG_ratio;\n        gsl_sf_result pre;\n        int stat_ex = gsl_sf_exp_err_e(lnpre_val, lnpre_err, &pre);\n        double ln_bigG_ratio_pre = -x + (N-1)*ln_x - lg_N;\n        double bigGsum = 1.0;\n        double term = 1.0;\n        int k;\n        for(k=1; k<N; k++) {\n          term *= (N-k)/x;\n          bigGsum += term;\n        }\n        stat_eG = gsl_sf_exp_mult_e(ln_bigG_ratio_pre, bigGsum, &bigG_ratio);\n        if(stat_eG == GSL_SUCCESS) {\n          result->val  = pre.val * (1.0 - bigG_ratio.val);\n          result->err  = pre.val * (2.0*GSL_DBL_EPSILON + bigG_ratio.err);\n          result->err += pre.err * fabs(1.0 - bigG_ratio.val);\n          result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n          return stat_ex;\n        }\n        else {\n          result->val = 0.0;\n          result->err = 0.0;\n          return stat_eG;\n        }\n      }\n      else {\n        OVERFLOW_ERROR(result);\n      }\n    }\n    else if(x > -10.0*N) {\n      return exprel_n_CF(N, x, result);\n    }\n    else {\n      /* x -> -Inf asymptotic:\n       * exprel_n(x) ~ e^x n!/x^n - n/x (1 + (n-1)/x + (n-1)(n-2)/x + ...)\n       *             ~ - n/x (1 + (n-1)/x + (n-1)(n-2)/x + ...)\n       */\n      double sum  = 1.0;\n      double term = 1.0;\n      int k;\n      for(k=1; k<N; k++) {\n        term *= (N-k)/x;\n        sum  += term;\n      }\n      result->val = -N/x * sum;\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint\ngsl_sf_exp_err_e(const double x, const double dx, gsl_sf_result * result)\n{\n  const double adx = fabs(dx);\n\n  /* CHECK_POINTER(result) */\n\n  if(x + adx > GSL_LOG_DBL_MAX) {\n    OVERFLOW_ERROR(result);\n  }\n  else if(x - adx < GSL_LOG_DBL_MIN) {\n    UNDERFLOW_ERROR(result);\n  }\n  else {\n    const double ex  = exp(x);\n    const double edx = exp(adx);\n    result->val  = ex;\n    result->err  = ex * GSL_MAX_DBL(GSL_DBL_EPSILON, edx - 1.0/edx);\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint\ngsl_sf_exp_err_e10_e(const double x, const double dx, gsl_sf_result_e10 * result)\n{\n  const double adx = fabs(dx);\n\n  /* CHECK_POINTER(result) */\n\n  if(x + adx > INT_MAX - 1) {\n    OVERFLOW_ERROR_E10(result);\n  }\n  else if(x - adx < INT_MIN + 1) {\n    UNDERFLOW_ERROR_E10(result);\n  }\n  else {\n    const int    N  = (int)floor(x/M_LN10);\n    const double ex = exp(x-N*M_LN10);\n    result->val = ex;\n    result->err = ex * (2.0 * GSL_DBL_EPSILON * (fabs(x) + 1.0) + adx);\n    result->e10 = N;\n    return GSL_SUCCESS;\n  }\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_exp(const double x)\n{\n  EVAL_RESULT(gsl_sf_exp_e(x, &result));\n}\n\ndouble gsl_sf_exp_mult(const double x, const double y)\n{\n  EVAL_RESULT(gsl_sf_exp_mult_e(x, y, &result));\n}\n\ndouble gsl_sf_expm1(const double x)\n{\n  EVAL_RESULT(gsl_sf_expm1_e(x, &result));\n}\n\ndouble gsl_sf_exprel(const double x)\n{\n  EVAL_RESULT(gsl_sf_exprel_e(x, &result));\n}\n\ndouble gsl_sf_exprel_2(const double x)\n{\n  EVAL_RESULT(gsl_sf_exprel_2_e(x, &result));\n}\n\ndouble gsl_sf_exprel_n(const int n, const double x)\n{\n  EVAL_RESULT(gsl_sf_exprel_n_e(n, x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/expint.c",
    "content": "/* specfunc/expint.c\n * \n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author: G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_expint.h\"\n#include \"gsl_sf_gamma.h\"\n\n#include \"error.h\"\n#include \"check.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/\n\n/*\n Chebyshev expansions: based on SLATEC e1.f, W. Fullerton\n \n Series for AE11       on the interval -1.00000D-01 to  0.\n                                        with weighted error   1.76E-17\n                                         log weighted error  16.75\n                               significant figures required  15.70\n                                    decimal places required  17.55\n\n\n Series for AE12       on the interval -2.50000D-01 to -1.00000D-01\n                                        with weighted error   5.83E-17\n                                         log weighted error  16.23\n                               significant figures required  15.76\n                                    decimal places required  16.93\n\n\n Series for E11        on the interval -4.00000D+00 to -1.00000D+00\n                                        with weighted error   1.08E-18\n                                         log weighted error  17.97\n                               significant figures required  19.02\n                                    decimal places required  18.61\n\n\n Series for E12        on the interval -1.00000D+00 to  1.00000D+00\n                                        with weighted error   3.15E-18\n                                         log weighted error  17.50\n                        approx significant figures required  15.8\n                                    decimal places required  18.10\n\n\n Series for AE13       on the interval  2.50000D-01 to  1.00000D+00\n                                        with weighted error   2.34E-17\n                                         log weighted error  16.63\n                               significant figures required  16.14\n                                    decimal places required  17.33\n\n\n Series for AE14       on the interval  0.          to  2.50000D-01\n                                        with weighted error   5.41E-17\n                                         log weighted error  16.27\n                               significant figures required  15.38\n                                    decimal places required  16.97\n*/\n\nstatic double AE11_data[39] = {\n   0.121503239716065790,\n  -0.065088778513550150,\n   0.004897651357459670,\n  -0.000649237843027216,\n   0.000093840434587471,\n   0.000000420236380882,\n  -0.000008113374735904,\n   0.000002804247688663,\n   0.000000056487164441,\n  -0.000000344809174450,\n   0.000000058209273578,\n   0.000000038711426349,\n  -0.000000012453235014,\n  -0.000000005118504888,\n   0.000000002148771527,\n   0.000000000868459898,\n  -0.000000000343650105,\n  -0.000000000179796603,\n   0.000000000047442060,\n   0.000000000040423282,\n  -0.000000000003543928,\n  -0.000000000008853444,\n  -0.000000000000960151,\n   0.000000000001692921,\n   0.000000000000607990,\n  -0.000000000000224338,\n  -0.000000000000200327,\n  -0.000000000000006246,\n   0.000000000000045571,\n   0.000000000000016383,\n  -0.000000000000005561,\n  -0.000000000000006074,\n  -0.000000000000000862,\n   0.000000000000001223,\n   0.000000000000000716,\n  -0.000000000000000024,\n  -0.000000000000000201,\n  -0.000000000000000082,\n   0.000000000000000017\n};\nstatic cheb_series AE11_cs = {\n  AE11_data,\n  38,\n  -1, 1,\n  20\n};\n\nstatic double AE12_data[25] = {\n   0.582417495134726740,\n  -0.158348850905782750,\n  -0.006764275590323141,\n   0.005125843950185725,\n   0.000435232492169391,\n  -0.000143613366305483,\n  -0.000041801320556301,\n  -0.000002713395758640,\n   0.000001151381913647,\n   0.000000420650022012,\n   0.000000066581901391,\n   0.000000000662143777,\n  -0.000000002844104870,\n  -0.000000000940724197,\n  -0.000000000177476602,\n  -0.000000000015830222,\n   0.000000000002905732,\n   0.000000000001769356,\n   0.000000000000492735,\n   0.000000000000093709,\n   0.000000000000010707,\n  -0.000000000000000537,\n  -0.000000000000000716,\n  -0.000000000000000244,\n  -0.000000000000000058\n};\nstatic cheb_series AE12_cs = {\n  AE12_data,\n  24,\n  -1, 1,\n  15\n};\n\nstatic double E11_data[19] = {\n  -16.11346165557149402600,\n    7.79407277874268027690,\n   -1.95540581886314195070,\n    0.37337293866277945612,\n   -0.05692503191092901938,\n    0.00721107776966009185,\n   -0.00078104901449841593,\n    0.00007388093356262168,\n   -0.00000620286187580820,\n    0.00000046816002303176,\n   -0.00000003209288853329,\n    0.00000000201519974874,\n   -0.00000000011673686816,\n    0.00000000000627627066,\n   -0.00000000000031481541,\n    0.00000000000001479904,\n   -0.00000000000000065457,\n    0.00000000000000002733,\n   -0.00000000000000000108\n};\nstatic cheb_series E11_cs = {\n  E11_data,\n  18,\n  -1, 1,\n  13\n};\n\nstatic double E12_data[16] = {\n  -0.03739021479220279500,\n   0.04272398606220957700,\n  -0.13031820798497005440,\n   0.01441912402469889073,\n  -0.00134617078051068022,\n   0.00010731029253063780,\n  -0.00000742999951611943,\n   0.00000045377325690753,\n  -0.00000002476417211390,\n   0.00000000122076581374,\n  -0.00000000005485141480,\n   0.00000000000226362142,\n  -0.00000000000008635897,\n   0.00000000000000306291,\n  -0.00000000000000010148,\n   0.00000000000000000315\n};\nstatic cheb_series E12_cs = {\n  E12_data,\n  15,\n  -1, 1,\n  10\n};\n\nstatic double AE13_data[25] = {\n  -0.605773246640603460,\n  -0.112535243483660900,\n   0.013432266247902779,\n  -0.001926845187381145,\n   0.000309118337720603,\n  -0.000053564132129618,\n   0.000009827812880247,\n  -0.000001885368984916,\n   0.000000374943193568,\n  -0.000000076823455870,\n   0.000000016143270567,\n  -0.000000003466802211,\n   0.000000000758754209,\n  -0.000000000168864333,\n   0.000000000038145706,\n  -0.000000000008733026,\n   0.000000000002023672,\n  -0.000000000000474132,\n   0.000000000000112211,\n  -0.000000000000026804,\n   0.000000000000006457,\n  -0.000000000000001568,\n   0.000000000000000383,\n  -0.000000000000000094,\n   0.000000000000000023\n};\nstatic cheb_series AE13_cs = {\n  AE13_data,\n  24,\n  -1, 1,\n  15\n};\n\nstatic double AE14_data[26] = {\n  -0.18929180007530170,\n  -0.08648117855259871,\n   0.00722410154374659,\n  -0.00080975594575573,\n   0.00010999134432661,\n  -0.00001717332998937,\n   0.00000298562751447,\n  -0.00000056596491457,\n   0.00000011526808397,\n  -0.00000002495030440,\n   0.00000000569232420,\n  -0.00000000135995766,\n   0.00000000033846628,\n  -0.00000000008737853,\n   0.00000000002331588,\n  -0.00000000000641148,\n   0.00000000000181224,\n  -0.00000000000052538,\n   0.00000000000015592,\n  -0.00000000000004729,\n   0.00000000000001463,\n  -0.00000000000000461,\n   0.00000000000000148,\n  -0.00000000000000048,\n   0.00000000000000016,\n  -0.00000000000000005\n};\nstatic cheb_series AE14_cs = {\n  AE14_data,\n  25,\n  -1, 1,\n  13\n};\n\n\n\n/* implementation for E1, allowing for scaling by exp(x) */\nstatic\nint expint_E1_impl(const double x, gsl_sf_result * result, const int scale)\n{\n  const double xmaxt = -GSL_LOG_DBL_MIN;      /* XMAXT = -LOG (R1MACH(1)) */\n  const double xmax  = xmaxt - log(xmaxt);    /* XMAX = XMAXT - LOG(XMAXT) */\n\n  /* CHECK_POINTER(result) */\n\n  if(x < -xmax && !scale) {\n      OVERFLOW_ERROR(result);\n  }\n  else if(x <= -10.0) {\n    const double s = 1.0/x * ( scale ? 1.0 : exp(-x) );\n    gsl_sf_result result_c;\n    cheb_eval_e(&AE11_cs, 20.0/x+1.0, &result_c);\n    result->val  = s * (1.0 + result_c.val);\n    result->err  = s * result_c.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * (fabs(x) + 1.0) * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x <= -4.0) {\n    const double s = 1.0/x * ( scale ? 1.0 : exp(-x) );\n    gsl_sf_result result_c;\n    cheb_eval_e(&AE12_cs, (40.0/x+7.0)/3.0, &result_c);\n    result->val  = s * (1.0 + result_c.val);\n    result->err  = s * result_c.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x <= -1.0) {\n    const double ln_term = -log(fabs(x));\n    const double scale_factor = ( scale ? exp(x) : 1.0 );\n    gsl_sf_result result_c;\n    cheb_eval_e(&E11_cs, (2.0*x+5.0)/3.0, &result_c);\n    result->val  = scale_factor * (ln_term + result_c.val);\n    result->err  = scale_factor * (result_c.err + GSL_DBL_EPSILON * fabs(ln_term));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x == 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x <= 1.0) {\n    const double ln_term = -log(fabs(x));\n    const double scale_factor = ( scale ? exp(x) : 1.0 );\n    gsl_sf_result result_c;\n    cheb_eval_e(&E12_cs, x, &result_c);\n    result->val  = scale_factor * (ln_term - 0.6875 + x + result_c.val);\n    result->err  = scale_factor * (result_c.err + GSL_DBL_EPSILON * fabs(ln_term));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x <= 4.0) {\n    const double s = 1.0/x * ( scale ? 1.0 : exp(-x) );\n    gsl_sf_result result_c;\n    cheb_eval_e(&AE13_cs, (8.0/x-5.0)/3.0, &result_c);\n    result->val  = s * (1.0 + result_c.val);\n    result->err  = s * result_c.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x <= xmax || scale) {\n    const double s = 1.0/x * ( scale ? 1.0 : exp(-x) );\n    gsl_sf_result result_c;\n    cheb_eval_e(&AE14_cs, 8.0/x-1.0, &result_c);\n    result->val  = s * (1.0 +  result_c.val);\n    result->err  = s * (GSL_DBL_EPSILON + result_c.err);\n    result->err += 2.0 * (x + 1.0) * GSL_DBL_EPSILON * fabs(result->val);\n    if(result->val == 0.0)\n      UNDERFLOW_ERROR(result);\n    else\n      return GSL_SUCCESS;\n  }\n  else {\n    UNDERFLOW_ERROR(result);\n  }\n}\n\n\nstatic\nint expint_E2_impl(const double x, gsl_sf_result * result, const int scale)\n{\n  const double xmaxt = -GSL_LOG_DBL_MIN;\n  const double xmax  = xmaxt - log(xmaxt);\n\n  /* CHECK_POINTER(result) */\n\n  if(x < -xmax && !scale) {\n    OVERFLOW_ERROR(result);\n  }\n  else if (x == 0.0) {\n    result->val = 1.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  } else if(x < 100.0) {\n    const double ex = ( scale ? 1.0 : exp(-x) );\n    gsl_sf_result result_E1;\n    int stat_E1 = expint_E1_impl(x, &result_E1, scale);\n    result->val  = ex - x*result_E1.val;\n    result->err  = GSL_DBL_EPSILON*ex + fabs(x) * result_E1.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return stat_E1;\n  }\n  else if(x < xmax || scale) {\n    const double s = ( scale ? 1.0 : exp(-x) );\n    const double c1  = -2.0;\n    const double c2  =  6.0;\n    const double c3  = -24.0;\n    const double c4  =  120.0;\n    const double c5  = -720.0;\n    const double c6  =  5040.0;\n    const double c7  = -40320.0;\n    const double c8  =  362880.0;\n    const double c9  = -3628800.0;\n    const double c10 =  39916800.0;\n    const double c11 = -479001600.0;\n    const double c12 =  6227020800.0;\n    const double c13 = -87178291200.0;\n    const double y = 1.0/x;\n    const double sum6 = c6+y*(c7+y*(c8+y*(c9+y*(c10+y*(c11+y*(c12+y*c13))))));\n    const double sum  = y*(c1+y*(c2+y*(c3+y*(c4+y*(c5+y*sum6)))));\n    result->val = s * (1.0 + sum)/x;\n    result->err = 2.0 * (x + 1.0) * GSL_DBL_EPSILON * result->val;\n    if(result->val == 0.0)\n      UNDERFLOW_ERROR(result);\n    else\n      return GSL_SUCCESS;\n  }\n  else {\n    UNDERFLOW_ERROR(result);\n  }\n}\n\nstatic\nint expint_En_impl(const int n, const double x, gsl_sf_result * result, const int scale)\n{\n  if (n < 0) {\n    DOMAIN_ERROR(result);\n  } else if (n == 0) {\n    if (x == 0) {\n      DOMAIN_ERROR(result);\n    } else {\n      result->val = (scale ? 1.0 : exp(-x)) / x;\n      result->err = 2 * GSL_DBL_EPSILON * fabs(result->val);\n      CHECK_UNDERFLOW(result);\n      return GSL_SUCCESS;\n    }\n  } else if (n == 1) {\n    return expint_E1_impl(x, result, scale);\n  } else if (n == 2) {\n    return expint_E2_impl(x, result, scale);\n  } else { \n    if(x < 0) {\n      DOMAIN_ERROR(result);\n    }\n    if (x == 0) {\n      result->val = (scale ? exp(x) : 1 ) * (1/(n-1.0));\n      result->err = 2 * GSL_DBL_EPSILON * fabs(result->val);\n      CHECK_UNDERFLOW(result);\n      return GSL_SUCCESS;\n    } else {\n      gsl_sf_result result_g;\n      double prefactor = pow(x, n-1);\n      int status = gsl_sf_gamma_inc_e (1-n, x, &result_g);\n      double scale_factor = ( scale ? exp(x) : 1.0 );\n      result->val = scale_factor * prefactor * result_g.val;\n      result->err = 2 * GSL_DBL_EPSILON * fabs(result->val);\n      result->err += 2 * fabs(scale_factor * prefactor * result_g.err);\n      if (status == GSL_SUCCESS) CHECK_UNDERFLOW(result);\n      return status;\n    }\n  }\n}\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\n\nint gsl_sf_expint_E1_e(const double x, gsl_sf_result * result)\n{\n  return expint_E1_impl(x, result, 0);\n}\n\n\nint gsl_sf_expint_E1_scaled_e(const double x, gsl_sf_result * result)\n{\n  return expint_E1_impl(x, result, 1);\n}\n\n\nint gsl_sf_expint_E2_e(const double x, gsl_sf_result * result)\n{\n  return expint_E2_impl(x, result, 0);\n}\n\n\nint gsl_sf_expint_E2_scaled_e(const double x, gsl_sf_result * result)\n{\n  return expint_E2_impl(x, result, 1);\n}\n\nint gsl_sf_expint_En_e(const int n, const double x, gsl_sf_result * result)\n{\n  return expint_En_impl(n, x, result, 0);\n}\n\n\nint gsl_sf_expint_En_scaled_e(const int n, const double x, gsl_sf_result * result)\n{\n  return expint_En_impl(n, x, result, 1);\n}\n\n\nint gsl_sf_expint_Ei_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    int status = gsl_sf_expint_E1_e(-x, result);\n    result->val = -result->val;\n    return status;\n  }\n}\n\n\nint gsl_sf_expint_Ei_scaled_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    int status = gsl_sf_expint_E1_scaled_e(-x, result);\n    result->val = -result->val;\n    return status;\n  }\n}\n\n\n#if 0\nstatic double recurse_En(int n, double x, double E1)\n{\n  int i;\n  double En = E1;\n  double ex = exp(-x);\n  for(i=2; i<=n; i++) {\n    En = 1./(i-1) * (ex - x * En);\n  }\n  return En;\n}\n#endif\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_expint_E1(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_E1_e(x, &result));\n}\n\ndouble gsl_sf_expint_E1_scaled(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_E1_scaled_e(x, &result));\n}\n\ndouble gsl_sf_expint_E2(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_E2_e(x, &result));\n}\n\ndouble gsl_sf_expint_E2_scaled(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_E2_scaled_e(x, &result));\n}\n\ndouble gsl_sf_expint_En(const int n, const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_En_e(n, x, &result));\n}\n\ndouble gsl_sf_expint_En_scaled(const int n, const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_En_scaled_e(n, x, &result));\n}\n\ndouble gsl_sf_expint_Ei(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_Ei_e(x, &result));\n}\n\ndouble gsl_sf_expint_Ei_scaled(const double x)\n{\n  EVAL_RESULT(gsl_sf_expint_Ei_scaled_e(x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/gamma.c",
    "content": "/* specfunc/gamma.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_log.h\"\n#include \"gsl_sf_psi.h\"\n#include \"gsl_sf_trig.h\"\n#include \"gsl_sf_gamma.h\"\n\n#include \"error.h\"\n#include \"check.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n#define LogRootTwoPi_  0.9189385332046727418\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/\n\nstatic struct {int n; double f; long i; } fact_table[GSL_SF_FACT_NMAX + 1] = {\n    { 0,  1.0,     1L     },\n    { 1,  1.0,     1L     },\n    { 2,  2.0,     2L     },\n    { 3,  6.0,     6L     },\n    { 4,  24.0,    24L    },\n    { 5,  120.0,   120L   },\n    { 6,  720.0,   720L   },\n    { 7,  5040.0,  5040L  },\n    { 8,  40320.0, 40320L },\n\n    { 9,  362880.0,     362880L    },\n    { 10, 3628800.0,    3628800L   },\n    { 11, 39916800.0,   39916800L  },\n    { 12, 479001600.0,  479001600L },\n\n    { 13, 6227020800.0,                               0 },\n    { 14, 87178291200.0,                              0 },\n    { 15, 1307674368000.0,                            0 },\n    { 16, 20922789888000.0,                           0 },\n    { 17, 355687428096000.0,                          0 },\n    { 18, 6402373705728000.0,                         0 },\n    { 19, 121645100408832000.0,                       0 },\n    { 20, 2432902008176640000.0,                      0 },\n    { 21, 51090942171709440000.0,                     0 },\n    { 22, 1124000727777607680000.0,                   0 },\n    { 23, 25852016738884976640000.0,                  0 },\n    { 24, 620448401733239439360000.0,                 0 },\n    { 25, 15511210043330985984000000.0,               0 },\n    { 26, 403291461126605635584000000.0,              0 },\n    { 27, 10888869450418352160768000000.0,            0 },\n    { 28, 304888344611713860501504000000.0,           0 },\n    { 29, 8841761993739701954543616000000.0,          0 },\n    { 30, 265252859812191058636308480000000.0,        0 },\n    { 31, 8222838654177922817725562880000000.0,       0 },\n    { 32, 263130836933693530167218012160000000.0,     0 },\n    { 33, 8683317618811886495518194401280000000.0,    0 },\n    { 34, 2.95232799039604140847618609644e38,  0 },\n    { 35, 1.03331479663861449296666513375e40,  0 },\n    { 36, 3.71993326789901217467999448151e41,  0 },\n    { 37, 1.37637530912263450463159795816e43,  0 },\n    { 38, 5.23022617466601111760007224100e44,  0 },\n    { 39, 2.03978820811974433586402817399e46,  0 },\n    { 40, 8.15915283247897734345611269600e47,  0 },\n    { 41, 3.34525266131638071081700620534e49,  0 },\n    { 42, 1.40500611775287989854314260624e51,  0 },\n    { 43, 6.04152630633738356373551320685e52,  0 },\n    { 44, 2.65827157478844876804362581101e54,  0 },\n    { 45, 1.19622220865480194561963161496e56,  0 },\n    { 46, 5.50262215981208894985030542880e57,  0 },\n    { 47, 2.58623241511168180642964355154e59,  0 },\n    { 48, 1.24139155925360726708622890474e61,  0 },\n    { 49, 6.08281864034267560872252163321e62,  0 },\n    { 50, 3.04140932017133780436126081661e64,  0 },\n    { 51, 1.55111875328738228022424301647e66,  0 },\n    { 52, 8.06581751709438785716606368564e67,  0 },\n    { 53, 4.27488328406002556429801375339e69,  0 },\n    { 54, 2.30843697339241380472092742683e71,  0 },\n    { 55, 1.26964033536582759259651008476e73,  0 },\n    { 56, 7.10998587804863451854045647464e74,  0 },\n    { 57, 4.05269195048772167556806019054e76,  0 },\n    { 58, 2.35056133128287857182947491052e78,  0 },\n    { 59, 1.38683118545689835737939019720e80,  0 },\n    { 60, 8.32098711274139014427634118320e81,  0 },\n    { 61, 5.07580213877224798800856812177e83,  0 },\n    { 62, 3.14699732603879375256531223550e85,  0 },\n    { 63, 1.982608315404440064116146708360e87,  0 },\n    { 64, 1.268869321858841641034333893350e89,  0 },\n    { 65, 8.247650592082470666723170306800e90,  0 },\n    { 66, 5.443449390774430640037292402480e92,  0 },\n    { 67, 3.647111091818868528824985909660e94,  0 },\n    { 68, 2.480035542436830599600990418570e96,  0 },\n    { 69, 1.711224524281413113724683388810e98,  0 },\n    { 70, 1.197857166996989179607278372170e100,  0 },\n    { 71, 8.504785885678623175211676442400e101,  0 },\n    { 72, 6.123445837688608686152407038530e103,  0 },\n    { 73, 4.470115461512684340891257138130e105,  0 },\n    { 74, 3.307885441519386412259530282210e107,  0 },\n    { 75, 2.480914081139539809194647711660e109,  0 },\n    { 76, 1.885494701666050254987932260860e111,  0 },\n    { 77, 1.451830920282858696340707840860e113,  0 },\n    { 78, 1.132428117820629783145752115870e115,  0 },\n    { 79, 8.946182130782975286851441715400e116,  0 },\n    { 80, 7.156945704626380229481153372320e118,  0 },\n    { 81, 5.797126020747367985879734231580e120,  0 },\n    { 82, 4.753643337012841748421382069890e122,  0 },\n    { 83, 3.945523969720658651189747118010e124,  0 },\n    { 84, 3.314240134565353266999387579130e126,  0 },\n    { 85, 2.817104114380550276949479442260e128,  0 },\n    { 86, 2.422709538367273238176552320340e130,  0 },\n    { 87, 2.107757298379527717213600518700e132,  0 },\n    { 88, 1.854826422573984391147968456460e134,  0 },\n    { 89, 1.650795516090846108121691926250e136,  0 },\n    { 90, 1.485715964481761497309522733620e138,  0 },\n    { 91, 1.352001527678402962551665687590e140,  0 },\n    { 92, 1.243841405464130725547532432590e142,  0 },\n    { 93, 1.156772507081641574759205162310e144,  0 },\n    { 94, 1.087366156656743080273652852570e146,  0 },\n    { 95, 1.032997848823905926259970209940e148,  0 },\n    { 96, 9.916779348709496892095714015400e149,  0 },\n    { 97, 9.619275968248211985332842594960e151,  0 },\n    { 98, 9.426890448883247745626185743100e153,  0 },\n    { 99, 9.332621544394415268169923885600e155,  0 },\n    { 100, 9.33262154439441526816992388563e157,  0 },\n    { 101, 9.42594775983835942085162312450e159,  0 },\n    { 102, 9.61446671503512660926865558700e161,  0 },\n    { 103, 9.90290071648618040754671525458e163,  0 },\n    { 104, 1.02990167451456276238485838648e166,  0 },\n    { 105, 1.08139675824029090050410130580e168,  0 },\n    { 106, 1.146280563734708354534347384148e170,  0 },\n    { 107, 1.226520203196137939351751701040e172,  0 },\n    { 108, 1.324641819451828974499891837120e174,  0 },\n    { 109, 1.443859583202493582204882102460e176,  0 },\n    { 110, 1.588245541522742940425370312710e178,  0 },\n    { 111, 1.762952551090244663872161047110e180,  0 },\n    { 112, 1.974506857221074023536820372760e182,  0 },\n    { 113, 2.231192748659813646596607021220e184,  0 },\n    { 114, 2.543559733472187557120132004190e186,  0 },\n    { 115, 2.925093693493015690688151804820e188,  0 },\n    { 116, 3.393108684451898201198256093590e190,  0 },\n    { 117, 3.96993716080872089540195962950e192,  0 },\n    { 118, 4.68452584975429065657431236281e194,  0 },\n    { 119, 5.57458576120760588132343171174e196,  0 },\n    { 120, 6.68950291344912705758811805409e198,  0 },\n    { 121, 8.09429852527344373968162284545e200,  0 },\n    { 122, 9.87504420083360136241157987140e202,  0 },\n    { 123, 1.21463043670253296757662432419e205,  0 },\n    { 124, 1.50614174151114087979501416199e207,  0 },\n    { 125, 1.88267717688892609974376770249e209,  0 },\n    { 126, 2.37217324288004688567714730514e211,  0 },\n    { 127, 3.01266001845765954480997707753e213,  0 },\n    { 128, 3.85620482362580421735677065923e215,  0 },\n    { 129, 4.97450422247728744039023415041e217,  0 },\n    { 130, 6.46685548922047367250730439554e219,  0 },\n    { 131, 8.47158069087882051098456875820e221,  0 },\n    { 132, 1.11824865119600430744996307608e224,  0 },\n    { 133, 1.48727070609068572890845089118e226,  0 },\n    { 134, 1.99294274616151887673732419418e228,  0 },\n    { 135, 2.69047270731805048359538766215e230,  0 },\n    { 136, 3.65904288195254865768972722052e232,  0 },\n    { 137, 5.01288874827499166103492629211e234,  0 },\n    { 138, 6.91778647261948849222819828311e236,  0 },\n    { 139, 9.61572319694108900419719561353e238,  0 },\n    { 140, 1.34620124757175246058760738589e241,  0 },\n    { 141, 1.89814375907617096942852641411e243,  0 },\n    { 142, 2.69536413788816277658850750804e245,  0 },\n    { 143, 3.85437071718007277052156573649e247,  0 },\n    { 144, 5.55029383273930478955105466055e249,  0 },\n    { 145, 8.04792605747199194484902925780e251,  0 },\n    { 146, 1.17499720439091082394795827164e254,  0 },\n    { 147, 1.72724589045463891120349865931e256,  0 },\n    { 148, 2.55632391787286558858117801578e258,  0 },\n    { 149, 3.80892263763056972698595524351e260,  0 },\n    { 150, 5.71338395644585459047893286526e262,  0 },\n    { 151, 8.62720977423324043162318862650e264,  0 },\n    { 152, 1.31133588568345254560672467123e267,  0 },\n    { 153, 2.00634390509568239477828874699e269,  0 },\n    { 154, 3.08976961384735088795856467036e271,  0 },\n    { 155, 4.78914290146339387633577523906e273,  0 },\n    { 156, 7.47106292628289444708380937294e275,  0 },\n    { 157, 1.17295687942641442819215807155e278,  0 },\n    { 158, 1.85327186949373479654360975305e280,  0 },\n    { 159, 2.94670227249503832650433950735e282,  0 },\n    { 160, 4.71472363599206132240694321176e284,  0 },\n    { 161, 7.59070505394721872907517857094e286,  0 },\n    { 162, 1.22969421873944943411017892849e289,  0 },\n    { 163, 2.00440157654530257759959165344e291,  0 },\n    { 164, 3.28721858553429622726333031164e293,  0 },\n    { 165, 5.42391066613158877498449501421e295,  0 },\n    { 166, 9.00369170577843736647426172359e297,  0 },\n    { 167, 1.50361651486499904020120170784e300,  0 },\n    { 168, 2.52607574497319838753801886917e302,  0 },\n    { 169, 4.26906800900470527493925188890e304,  0 },\n    { 170, 7.25741561530799896739672821113e306,  0 },\n\n    /*\n    { 171, 1.24101807021766782342484052410e309,  0 },\n    { 172, 2.13455108077438865629072570146e311,  0 },\n    { 173, 3.69277336973969237538295546352e313,  0 },\n    { 174, 6.42542566334706473316634250653e315,  0 },\n    { 175, 1.12444949108573632830410993864e318,  0 },\n    { 176, 1.97903110431089593781523349201e320,  0 },\n    { 177, 3.50288505463028580993296328086e322,  0 },\n    { 178, 6.23513539724190874168067463993e324,  0 },\n    { 179, 1.11608923610630166476084076055e327,  0 },\n    { 180, 2.00896062499134299656951336898e329,  0 },\n    { 181, 3.63621873123433082379081919786e331,  0 },\n    { 182, 6.61791809084648209929929094011e333,  0 },\n    { 183, 1.21107901062490622417177024204e336,  0 },\n    { 184, 2.22838537954982745247605724535e338,  0 },\n    { 185, 4.12251295216718078708070590390e340,  0 },\n    { 186, 7.66787409103095626397011298130e342,  0 },\n    { 187, 1.43389245502278882136241112750e345,  0 },\n    { 188, 2.69571781544284298416133291969e347,  0 },\n    { 189, 5.09490667118697324006491921822e349,  0 },\n    { 190, 9.68032267525524915612334651460e351,  0 },\n    { 191, 1.84894163097375258881955918429e354,  0 },\n    { 192, 3.54996793146960497053355363384e356,  0 },\n    { 193, 6.85143810773633759312975851330e358,  0 },\n    { 194, 1.32917899290084949306717315158e361,  0 },\n    { 195, 2.59189903615665651148098764559e363,  0 },\n    { 196, 5.08012211086704676250273578535e365,  0 },\n    { 197, 1.00078405584080821221303894971e368,  0 },\n    { 198, 1.98155243056480026018181712043e370,  0 },\n    { 199, 3.94328933682395251776181606966e372,  0 },\n    { 200, 7.88657867364790503552363213932e374,  0 }\n    */\n};\n\nstatic struct {int n; double f; long i; } doub_fact_table[GSL_SF_DOUBLEFACT_NMAX + 1] = {\n  { 0,  1.000000000000000000000000000,    1L    },\n  { 1,  1.000000000000000000000000000,    1L    },\n  { 2,  2.000000000000000000000000000,    2L    },\n  { 3,  3.000000000000000000000000000,    3L    },\n  { 4,  8.000000000000000000000000000,    8L    },\n  { 5,  15.00000000000000000000000000,    15L   },\n  { 6,  48.00000000000000000000000000,    48L   },\n  { 7,  105.0000000000000000000000000,    105L  },\n  { 8,  384.0000000000000000000000000,    384L  },\n  { 9,  945.0000000000000000000000000,    945L  },\n  { 10, 3840.000000000000000000000000,    3840L   },\n  { 11, 10395.00000000000000000000000,    10395L  },\n  { 12, 46080.00000000000000000000000,       46080L       },\n  { 13, 135135.0000000000000000000000,       135135L      },\n  { 14, 645120.00000000000000000000000,      645120L      },\n  { 15, 2.02702500000000000000000000000e6,   2027025L     },\n  { 16, 1.03219200000000000000000000000e7,   10321920L    },\n  { 17, 3.4459425000000000000000000000e7,    34459425L    },\n  { 18, 1.85794560000000000000000000000e8,   185794560L   },\n  { 19, 6.5472907500000000000000000000e8,            0 },\n  { 20, 3.7158912000000000000000000000e9,            0 },\n  { 21, 1.37493105750000000000000000000e10,          0 },\n  { 22, 8.1749606400000000000000000000e10,           0 },\n  { 23, 3.1623414322500000000000000000e11,           0 },\n  { 24, 1.96199055360000000000000000000e12,          0 },\n  { 25, 7.9058535806250000000000000000e12,           0 },\n  { 26, 5.1011754393600000000000000000e13,           0 },\n  { 27, 2.13458046676875000000000000000e14,          0 },\n  { 28, 1.42832912302080000000000000000e15,          0 },\n  { 29, 6.1902833536293750000000000000e15,           0 },\n  { 30, 4.2849873690624000000000000000e16,           0 },\n  { 31, 1.91898783962510625000000000000e17,          0 },\n  { 32, 1.37119595809996800000000000000e18,          0 },\n  { 33, 6.3326598707628506250000000000e18,           0 },\n  { 34, 4.6620662575398912000000000000e19,           0 },\n  { 35, 2.21643095476699771875000000000e20,          0 },\n  { 36, 1.67834385271436083200000000000e21,          0 },\n  { 37, 8.2007945326378915593750000000e21,           0 },\n  { 38, 6.3777066403145711616000000000e22,           0 },\n  { 39, 3.1983098677287777081562500000e23,           0 },\n  { 40, 2.55108265612582846464000000000e24,          0 },\n  { 41, 1.31130704576879886034406250000e25,          0 },\n  { 42, 1.07145471557284795514880000000e26,          0 },\n  { 43, 5.6386202968058350994794687500e26,           0 },\n  { 44, 4.7144007485205310026547200000e27,           0 },\n  { 45, 2.53737913356262579476576093750e28,          0 },\n  { 46, 2.16862434431944426122117120000e29,          0 },\n  { 47, 1.19256819277443412353990764062e30,          0 },\n  { 48, 1.04093968527333324538616217600e31,          0 },\n  { 49, 5.8435841445947272053455474391e31,           0 },\n  { 50, 5.2046984263666662269308108800e32,           0 },\n  { 51, 2.98022791374331087472622919392e33,          0 },\n  { 52, 2.70644318171066643800402165760e34,          0 },\n  { 53, 1.57952079428395476360490147278e35,          0 },\n  { 54, 1.46147931812375987652217169510e36,          0 },\n  { 55, 8.6873643685617511998269581003e36,           0 },\n  { 56, 8.1842841814930553085241614926e37,           0 },\n  { 57, 4.9517976900801981839013661172e38,           0 },\n  { 58, 4.7468848252659720789440136657e39,           0 },\n  { 59, 2.92156063714731692850180600912e40,       0 },\n  { 60, 2.84813089515958324736640819942e41,       0 },\n  { 61, 1.78215198865986332638610166557e42,       0 },\n  { 62, 1.76584115499894161336717308364e43,       0 },\n  { 63, 1.12275575285571389562324404931e44,       0 },\n  { 64, 1.13013833919932263255499077353e45,       0 },\n  { 65, 7.2979123935621403215510863205e45,        0 },\n  { 66, 7.4589130387155293748629391053e46,        0 },\n  { 67, 4.8896013036866340154392278347e47,        0 },\n  { 68, 5.0720608663265599749067985916e48,        0 },\n  { 69, 3.3738248995437774706530672060e49,        0 },\n  { 70, 3.5504426064285919824347590141e50,        0 },\n  { 71, 2.39541567867608200416367771623e51,       0 },\n  { 72, 2.55631867662858622735302649017e52,       0 },\n  { 73, 1.74865344543353986303948473285e53,       0 },\n  { 74, 1.89167582070515380824123960272e54,       0 },\n  { 75, 1.31149008407515489727961354964e55,       0 },\n  { 76, 1.43767362373591689426334209807e56,       0 },\n  { 77, 1.00984736473786927090530243322e57,       0 },\n  { 78, 1.12138542651401517752540683649e58,       0 },\n  { 79, 7.9777941814291672401518892225e58,        0 },\n  { 80, 8.9710834121121214202032546920e59,        0 },\n  { 81, 6.4620132869576254645230302702e60,        0 },\n  { 82, 7.3562883979319395645666688474e61,        0 },\n  { 83, 5.3634710281748291355541151243e62,        0 },\n  { 84, 6.1792822542628292342360018318e63,        0 },\n  { 85, 4.5589503739486047652209978556e64,        0 },\n  { 86, 5.3141827386660331414429615754e65,        0 },\n  { 87, 3.9662868253352861457422681344e66,        0 },\n  { 88, 4.6764808100261091644698061863e67,        0 },\n  { 89, 3.5299952745484046697106186396e68,        0 },\n  { 90, 4.2088327290234982480228255677e69,        0 },\n  { 91, 3.2122956998390482494366629620e70,        0 },\n  { 92, 3.8721261107016183881809995223e71,        0 },\n  { 93, 2.98743500085031487197609655470e72,       0 },\n  { 94, 3.6397985440595212848901395509e73,        0 },\n  { 95, 2.83806325080779912837729172696e74,       0 },\n  { 96, 3.4942066022971404334945339689e75,        0 },\n  { 97, 2.75292135328356515452597297515e76,       0 },\n  { 98, 3.4243224702511976248246432895e77,        0 },\n  { 99, 2.72539213975072950298071324540e78,       0 },\n  { 100, 3.4243224702511976248246432895e79,       0 },\n  { 101, 2.75264606114823679801052037785e80,      0 },\n  { 102, 3.4928089196562215773211361553e81,       0 },\n  { 103, 2.83522544298268390195083598919e82,      0 },\n  { 104, 3.6325212764424704404139816015e83,       0 },\n  { 105, 2.97698671513181809704837778865e84,      0 },\n  { 106, 3.8504725530290186668388204976e85,       0 },\n  { 107, 3.1853757851910453638417642339e86,       0 },\n  { 108, 4.1585103572713401601859261374e87,       0 },\n  { 109, 3.4720596058582394465875230149e88,       0 },\n  { 110, 4.5743613929984741762045187512e89,       0 },\n  { 111, 3.8539861625026457857121505465e90,       0 },\n  { 112, 5.1232847601582910773490610013e91,       0 },\n  { 113, 4.3550043636279897378547301176e92,       0 },\n  { 114, 5.8405446265804518281779295415e93,       0 },\n  { 115, 5.0082550181721881985329396352e94,       0 },\n  { 116, 6.7750317668333241206863982681e95,       0 },\n  { 117, 5.8596583712614601922835393732e96,       0 },\n  { 118, 7.9945374848633224624099499564e97,       0 },\n  { 119, 6.9729934618011376288174118541e98,       0 },\n  { 120, 9.5934449818359869548919399477e99,       0 },\n  { 121, 8.4373220887793765308690683435e100,      0 },\n  { 122, 1.17040028778399040849681667362e102,       0 },\n  { 123, 1.03779061691986331329689540625e103,       0 },\n  { 124, 1.45129635685214810653605267528e104,       0 },\n  { 125, 1.29723827114982914162111925781e105,       0 },\n  { 126, 1.82863340963370661423542637086e106,       0 },\n  { 127, 1.64749260436028300985882145742e107,       0 },\n  { 128, 2.34065076433114446622134575470e108,       0 },\n  { 129, 2.12526545962476508271787968008e109,       0 },\n  { 130, 3.04284599363048780608774948111e110,       0 },\n  { 131, 2.78409775210844225836042238090e111,       0 },\n  { 132, 4.0165567115922439040358293151e112,        0 },\n  { 133, 3.7028500103042282036193617666e113,        0 },\n  { 134, 5.3821859935336068314080112822e114,        0 },\n  { 135, 4.9988475139107080748861383849e115,        0 },\n  { 136, 7.3197729512057052907148953438e116,        0 },\n  { 137, 6.8484210940576700625940095873e117,        0 },\n  { 138, 1.01012866726638733011865555744e119,       0 },\n  { 139, 9.5193053207401613870056733264e119,        0 },\n  { 140, 1.41418013417294226216611778042e121,       0 },\n  { 141, 1.34222205022436275556779993902e122,       0 },\n  { 142, 2.00813579052557801227588724819e123,       0 },\n  { 143, 1.91937753182083874046195391280e124,       0 },\n  { 144, 2.89171553835683233767727763739e125,       0 },\n  { 145, 2.78309742114021617366983317355e126,       0 },\n  { 146, 4.2219046860009752130088253506e127,        0 },\n  { 147, 4.0911532090761177752946547651e128,        0 },\n  { 148, 6.2484189352814433152530615189e129,        0 },\n  { 149, 6.0958182815234154851890356000e130,        0 },\n  { 150, 9.3726284029221649728795922783e131,        0 },\n  { 151, 9.2046856051003573826354437561e132,        0 },\n  { 152, 1.42463951724416907587769802630e134,       0 },\n  { 153, 1.40831689758035467954322289468e135,       0 },\n  { 154, 2.19394485655602037685165496051e136,       0 },\n  { 155, 2.18289119124954975329199548675e137,       0 },\n  { 156, 3.4225539762273917878885817384e138,        0 },\n  { 157, 3.4271391702617931126684329142e139,        0 },\n  { 158, 5.4076352824392790248639591467e140,        0 },\n  { 159, 5.4491512807162510491428083336e141,        0 },\n  { 160, 8.6522164519028464397823346347e142,        0 },\n  { 161, 8.7731335619531641891199214170e143,        0 },\n  { 162, 1.40165906520826112324473821082e145,       0 },\n  { 163, 1.43002077059836576282654719098e146,       0 },\n  { 164, 2.29872086694154824212137066574e147,       0 },\n  { 165, 2.35953427148730350866380286512e148,       0 },\n  { 166, 3.8158766391229700819214753051e149,        0 },\n  { 167, 3.9404222333837968594685507847e150,        0 },\n  { 168, 6.4106727537265897376280785126e151,        0 },\n  { 169, 6.6593135744186166925018508262e152,        0 },\n  { 170, 1.08981436813352025539677334714e154,       0 },\n  { 171, 1.13874262122558345441781649128e155,       0 },\n  { 172, 1.87448071318965483928245015709e156,       0 },\n  { 173, 1.97002473472025937614282252992e157,       0 },\n  { 174, 3.2615964409499994203514632733e158,        0 },\n  { 175, 3.4475432857604539082499394274e159,        0 },\n  { 176, 5.7404097360719989798185753611e160,        0 },\n  { 177, 6.1021516157960034176023927864e161,        0 },\n  { 178, 1.02179293302081581840770641427e163,       0 },\n  { 179, 1.09228513922748461175082830877e164,       0 },\n  { 180, 1.83922727943746847313387154568e165,       0 },\n  { 181, 1.97703610200174714726899923887e166,       0 },\n  { 182, 3.3473936485761926211036462131e167,        0 },\n  { 183, 3.6179760666631972795022686071e168,        0 },\n  { 184, 6.1592043133801944228307090322e169,        0 },\n  { 185, 6.6932557233269149670791969232e170,        0 },\n  { 186, 1.14561200228871616264651187999e172,       0 },\n  { 187, 1.25163882026213309884380982464e173,       0 },\n  { 188, 2.15375056430278638577544233437e174,       0 },\n  { 189, 2.36559737029543155681480056857e175,       0 },\n  { 190, 4.0921260721752941329733404353e176,        0 },\n  { 191, 4.5182909772642742735162690860e177,        0 },\n  { 192, 7.8568820585765647353088136358e178,        0 },\n  { 193, 8.7203015861200493478863993359e179,        0 },\n  { 194, 1.52423511936385355864990984535e181,       0 },\n  { 195, 1.70045880929340962283784787050e182,       0 },\n  { 196, 2.98750083395315297495382329688e183,       0 },\n  { 197, 3.3499038543080169569905603049e184,        0 },\n  { 198, 5.9152516512272428904085701278e185,        0 },\n  { 199, 6.6663086700729537444112150067e186,        0 },\n  { 200, 1.18305033024544857808171402556e188,       0 },\n  { 201, 1.33992804268466370262665421635e189,       0 },\n  { 202, 2.38976166709580612772506233164e190,       0 },\n  { 203, 2.72005392664986731633210805920e191,       0 },\n  { 204, 4.8751138008754445005591271565e192,        0 },\n  { 205, 5.5761105496322279984808215214e193,        0 },\n  { 206, 1.00427344298034156711518019425e195,       0 },\n  { 207, 1.15425488377387119568553005492e196,       0 },\n  { 208, 2.08888876139911045959957480403e197,       0 },\n  { 209, 2.41239270708739079898275781478e198,       0 },\n  { 210, 4.3866663989381319651591070885e199,        0 },\n  { 211, 5.0901486119543945858536189892e200,        0 },\n  { 212, 9.2997327657488397661373070276e201,        0 },\n  { 213, 1.08420165434628604678682084470e203,       0 },\n  { 214, 1.99014281187025170995338370390e204,       0 },\n  { 215, 2.33103355684451500059166481610e205,       0 },\n  { 216, 4.2987084736397436934993088004e206,        0 },\n  { 217, 5.0583428183525975512839126509e207,        0 },\n  { 218, 9.3711844725346412518284931849e208,        0 },\n  { 219, 1.10777707721921886373117687056e210,       0 },\n  { 220, 2.06166058395762107540226850068e211,       0 },\n  { 221, 2.44818734065447368884590088393e212,       0 },\n  { 222, 4.5768864963859187873930360715e213,        0 },\n  { 223, 5.4594577696594763261263589712e214,        0 },\n  { 224, 1.02522257519044580837604008002e216,       0 },\n  { 225, 1.22837799817338217337843076851e217,       0 },\n  { 226, 2.31700301993040752692985058084e218,       0 },\n  { 227, 2.78841805585357753356903784452e219,       0 },\n  { 228, 5.2827668854413291614000593243e220,        0 },\n  { 229, 6.3854773479046925518730966640e221,        0 },\n  { 230, 1.21503638365150570712201364459e223,       0 },\n  { 231, 1.47504526736598397948268532937e224,       0 },\n  { 232, 2.81888441007149324052307165546e225,       0 },\n  { 233, 3.4368554729627426721946568174e226,        0 },\n  { 234, 6.5961895195672941828239876738e227,        0 },\n  { 235, 8.0766103614624452796574435210e228,        0 },\n  { 236, 1.55670072661788142714646109101e230,       0 },\n  { 237, 1.91415665566659953127881411447e231,       0 },\n  { 238, 3.7049477293505577966085773966e232,        0 },\n  { 239, 4.5748344070431728797563657336e233,        0 },\n  { 240, 8.8918745504413387118605857518e234,        0 },\n  { 241, 1.10253509209740466402128414180e236,       0 },\n  { 242, 2.15183364120680396827026175195e237,       0 },\n  { 243, 2.67916027379669333357172046456e238,       0 },\n  { 244, 5.2504740845446016825794386748e239,        0 },\n  { 245, 6.5639426708018986672507151382e240,        0 },\n  { 246, 1.29161662479797201391454191399e242,       0 },\n  { 247, 1.62129383968806897081092663913e243,       0 },\n  { 248, 3.2032092294989705945080639467e244,        0 },\n  { 249, 4.0370216608232917373192073314e245,        0 },\n  { 250, 8.0080230737474264862701598667e246,        0 },\n  { 251, 1.01329243686664622606712104019e248,       0 },\n  { 252, 2.01802181458435147454008028642e249,       0 },\n  { 253, 2.56362986527261495194981623168e250,       0 },\n  { 254, 5.1257754090442527453318039275e251,        0 },\n  { 255, 6.5372561564451681274720313908e252,        0 },\n  { 256, 1.31219850471532870280494180544e254,       0 },\n  { 257, 1.68007483220640820876031206743e255,       0 },\n  { 258, 3.3854721421655480532367498580e256,        0 },\n  { 259, 4.3513938154145972606892082546e257,        0 },\n  { 260, 8.8022275696304249384155496309e258,        0 },\n  { 261, 1.13571378582320988503988335446e260,       0 },\n  { 262, 2.30618362324317133386487400329e261,       0 },\n  { 263, 2.98692725671504199765489322224e262,       0 },\n  { 264, 6.0883247653619723214032673687e263,        0 },\n  { 265, 7.9153572302948612937854670389e264,        0 },\n  { 266, 1.61949438758628463749326912007e266,       0 },\n  { 267, 2.11340038048872796544071969939e267,       0 },\n  { 268, 4.3402449587312428284819612418e268,        0 },\n  { 269, 5.6850470235146782270355359914e269,        0 },\n  { 270, 1.17186613885743556369012953528e271,       0 },\n  { 271, 1.54064774337247779952663025366e272,       0 },\n  { 272, 3.1874758976922247332371523360e273,        0 },\n  { 273, 4.2059683394068643927077005925e274,        0 },\n  { 274, 8.7336839596766957690697974006e275,        0 },\n  { 275, 1.15664129333688770799461766294e277,       0 },\n  { 276, 2.41049677287076803226326408256e278,       0 },\n  { 277, 3.2038963825431789511450909263e279,        0 },\n  { 278, 6.7011810285807351296918741495e280,        0 },\n  { 279, 8.9388709072954692736948036845e281,        0 },\n  { 280, 1.87633068800260583631372476186e283,       0 },\n  { 281, 2.51182272495002686590823983534e284,       0 },\n  { 282, 5.2912525401673484584047038284e285,        0 },\n  { 283, 7.1084583116085760305203187340e286,        0 },\n  { 284, 1.50271572140752696218693588728e288,       0 },\n  { 285, 2.02591061880844416869829083919e289,       0 },\n  { 286, 4.2977669632255271118546366376e290,        0 },\n  { 287, 5.8143634759802347641640947085e291,        0 },\n  { 288, 1.23775688540895180821413535163e293,       0 },\n  { 289, 1.68035104455828784684342337075e294,       0 },\n  { 290, 3.5894949676859602438209925197e295,        0 },\n  { 291, 4.8898215396646176343143620089e296,        0 },\n  { 292, 1.04813253056430039119572981576e298,       0 },\n  { 293, 1.43271771112173296685410806860e299,       0 },\n  { 294, 3.08150963985904315011544565835e300,       0 },\n  { 295, 4.2265172478091122522196188024e301,        0 },\n  { 296, 9.1212685339827677243417191487e302,        0 },\n  { 297, 1.25527562259930633890922678431e304,       0 },\n  /*\n  { 298, 2.71813802312686478185383230631e305,       0 },\n  { 299, 3.7532741115719259533385880851e306,        0 },\n  { 300, 8.1544140693805943455614969189e307,  }\n  */\n};\n\n\n/* Chebyshev coefficients for Gamma*(3/4(t+1)+1/2), -1<t<1\n */\nstatic double gstar_a_data[30] = {\n  2.16786447866463034423060819465,\n -0.05533249018745584258035832802,\n  0.01800392431460719960888319748,\n -0.00580919269468937714480019814,\n  0.00186523689488400339978881560,\n -0.00059746524113955531852595159,\n  0.00019125169907783353925426722,\n -0.00006124996546944685735909697,\n  0.00001963889633130842586440945,\n -6.3067741254637180272515795142e-06,\n  2.0288698405861392526872789863e-06,\n -6.5384896660838465981983750582e-07,\n  2.1108698058908865476480734911e-07,\n -6.8260714912274941677892994580e-08,\n  2.2108560875880560555583978510e-08,\n -7.1710331930255456643627187187e-09,\n  2.3290892983985406754602564745e-09,\n -7.5740371598505586754890405359e-10,\n  2.4658267222594334398525312084e-10,\n -8.0362243171659883803428749516e-11,\n  2.6215616826341594653521346229e-11,\n -8.5596155025948750540420068109e-12,\n  2.7970831499487963614315315444e-12,\n -9.1471771211886202805502562414e-13,\n  2.9934720198063397094916415927e-13,\n -9.8026575909753445931073620469e-14,\n  3.2116773667767153777571410671e-14,\n -1.0518035333878147029650507254e-14,\n  3.4144405720185253938994854173e-15,\n -1.0115153943081187052322643819e-15\n};\nstatic cheb_series gstar_a_cs = {\n  gstar_a_data,\n  29,\n  -1, 1,\n  17\n};\n\n\n/* Chebyshev coefficients for\n * x^2(Gamma*(x) - 1 - 1/(12x)), x = 4(t+1)+2, -1 < t < 1\n */\nstatic double gstar_b_data[] = {\n  0.0057502277273114339831606096782,\n  0.0004496689534965685038254147807,\n -0.0001672763153188717308905047405,\n  0.0000615137014913154794776670946,\n -0.0000223726551711525016380862195,\n  8.0507405356647954540694800545e-06,\n -2.8671077107583395569766746448e-06,\n  1.0106727053742747568362254106e-06,\n -3.5265558477595061262310873482e-07,\n  1.2179216046419401193247254591e-07,\n -4.1619640180795366971160162267e-08,\n  1.4066283500795206892487241294e-08,\n -4.6982570380537099016106141654e-09,\n  1.5491248664620612686423108936e-09,\n -5.0340936319394885789686867772e-10,\n  1.6084448673736032249959475006e-10,\n -5.0349733196835456497619787559e-11,\n  1.5357154939762136997591808461e-11,\n -4.5233809655775649997667176224e-12,\n  1.2664429179254447281068538964e-12,\n -3.2648287937449326771785041692e-13,\n  7.1528272726086133795579071407e-14,\n -9.4831735252566034505739531258e-15,\n -2.3124001991413207293120906691e-15,\n  2.8406613277170391482590129474e-15,\n -1.7245370321618816421281770927e-15,\n  8.6507923128671112154695006592e-16,\n -3.9506563665427555895391869919e-16,\n  1.6779342132074761078792361165e-16,\n -6.0483153034414765129837716260e-17\n};\nstatic cheb_series gstar_b_cs = {\n  gstar_b_data,\n  29,\n  -1, 1,\n  18\n};\n\n\n/* coefficients for gamma=7, kmax=8  Lanczos method */\nstatic double lanczos_7_c[9] = {\n  0.99999999999980993227684700473478,\n  676.520368121885098567009190444019,\n -1259.13921672240287047156078755283,\n  771.3234287776530788486528258894,\n -176.61502916214059906584551354,\n  12.507343278686904814458936853,\n -0.13857109526572011689554707,\n  9.984369578019570859563e-6,\n  1.50563273514931155834e-7\n};\n\n/* complex version of Lanczos method; this is not safe for export\n * since it becomes bad in the left half-plane\n */\nstatic\nint\nlngamma_lanczos_complex(double zr, double zi, gsl_sf_result * yr, gsl_sf_result * yi)\n{\n  int k;\n  gsl_sf_result log1_r,    log1_i;\n  gsl_sf_result logAg_r,   logAg_i;\n  double Ag_r, Ag_i;\n  double yi_tmp_val, yi_tmp_err;\n\n  zr -= 1.0; /* Lanczos writes z! instead of Gamma(z) */\n\n  Ag_r = lanczos_7_c[0];\n  Ag_i = 0.0;\n  for(k=1; k<=8; k++) {\n    double R = zr + k;\n    double I = zi;\n    double a = lanczos_7_c[k] / (R*R + I*I);\n    Ag_r +=  a * R;\n    Ag_i -=  a * I;\n  }\n\n  gsl_sf_complex_log_e(zr + 7.5, zi, &log1_r,  &log1_i);\n  gsl_sf_complex_log_e(Ag_r, Ag_i,   &logAg_r, &logAg_i);\n\n  /* (z+0.5)*log(z+7.5) - (z+7.5) + LogRootTwoPi_ + log(Ag(z)) */\n  yr->val = (zr+0.5)*log1_r.val - zi*log1_i.val - (zr+7.5) + LogRootTwoPi_ + logAg_r.val;\n  yi->val = zi*log1_r.val + (zr+0.5)*log1_i.val - zi + logAg_i.val;\n  yr->err = 4.0 * GSL_DBL_EPSILON * fabs(yr->val);\n  yi->err = 4.0 * GSL_DBL_EPSILON * fabs(yi->val);\n  yi_tmp_val = yi->val;\n  yi_tmp_err = yi->err;\n  gsl_sf_angle_restrict_symm_err_e(yi_tmp_val, yi);\n  yi->err += yi_tmp_err;\n  return GSL_SUCCESS;\n}\n\n\n/* Lanczos method for real x > 0;\n * gamma=7, truncated at 1/(z+8) \n * [J. SIAM Numer. Anal, Ser. B, 1 (1964) 86]\n */\nstatic\nint\nlngamma_lanczos(double x, gsl_sf_result * result)\n{\n  int k;\n  double Ag;\n  double term1, term2;\n\n  x -= 1.0; /* Lanczos writes z! instead of Gamma(z) */\n\n  Ag = lanczos_7_c[0];\n  for(k=1; k<=8; k++) { Ag += lanczos_7_c[k]/(x+k); }\n\n  /* (x+0.5)*log(x+7.5) - (x+7.5) + LogRootTwoPi_ + log(Ag(x)) */\n  term1 = (x+0.5)*log((x+7.5)/M_E);\n  term2 = LogRootTwoPi_ + log(Ag);\n  result->val  = term1 + (term2 - 7.0);\n  result->err  = 2.0 * GSL_DBL_EPSILON * (fabs(term1) + fabs(term2) + 7.0);\n  result->err += GSL_DBL_EPSILON * fabs(result->val);\n\n  return GSL_SUCCESS;\n}\n\n/* x = eps near zero\n * gives double-precision for |eps| < 0.02\n */\nstatic\nint\nlngamma_sgn_0(double eps, gsl_sf_result * lng, double * sgn)\n{\n  /* calculate series for g(eps) = Gamma(eps) eps - 1/(1+eps) - eps/2 */\n  const double c1  = -0.07721566490153286061;\n  const double c2  = -0.01094400467202744461;\n  const double c3  =  0.09252092391911371098;\n  const double c4  = -0.01827191316559981266;\n  const double c5  =  0.01800493109685479790;\n  const double c6  = -0.00685088537872380685;\n  const double c7  =  0.00399823955756846603;\n  const double c8  = -0.00189430621687107802;\n  const double c9  =  0.00097473237804513221;\n  const double c10 = -0.00048434392722255893;\n  const double g6  = c6+eps*(c7+eps*(c8 + eps*(c9 + eps*c10)));\n  const double g   = eps*(c1+eps*(c2+eps*(c3+eps*(c4+eps*(c5+eps*g6)))));\n\n  /* calculate Gamma(eps) eps, a positive quantity */\n  const double gee = g + 1.0/(1.0+eps) + 0.5*eps;\n\n  lng->val = log(gee/fabs(eps));\n  lng->err = 4.0 * GSL_DBL_EPSILON * fabs(lng->val);\n  *sgn = GSL_SIGN(eps);\n\n  return GSL_SUCCESS;\n}\n\n\n/* x near a negative integer\n * Calculates sign as well as log(|gamma(x)|).\n * x = -N + eps\n * assumes N >= 1\n */\nstatic\nint\nlngamma_sgn_sing(int N, double eps, gsl_sf_result * lng, double * sgn)\n{\n  if(eps == 0.0) {\n    lng->val = 0.0;\n    lng->err = 0.0;\n    *sgn = 0.0;\n    GSL_ERROR (\"error\", GSL_EDOM);\n  }\n  else if(N == 1) {\n    /* calculate series for\n     * g = eps gamma(-1+eps) + 1 + eps/2 (1+3eps)/(1-eps^2)\n     * double-precision for |eps| < 0.02\n     */\n    const double c0 =  0.07721566490153286061;\n    const double c1 =  0.08815966957356030521;\n    const double c2 = -0.00436125434555340577;\n    const double c3 =  0.01391065882004640689;\n    const double c4 = -0.00409427227680839100;\n    const double c5 =  0.00275661310191541584;\n    const double c6 = -0.00124162645565305019;\n    const double c7 =  0.00065267976121802783;\n    const double c8 = -0.00032205261682710437;\n    const double c9 =  0.00016229131039545456;\n    const double g5 = c5 + eps*(c6 + eps*(c7 + eps*(c8 + eps*c9)));\n    const double g  = eps*(c0 + eps*(c1 + eps*(c2 + eps*(c3 + eps*(c4 + eps*g5)))));\n\n    /* calculate eps gamma(-1+eps), a negative quantity */\n    const double gam_e = g - 1.0 - 0.5*eps*(1.0+3.0*eps)/(1.0 - eps*eps);\n\n    lng->val = log(fabs(gam_e)/fabs(eps));\n    lng->err = 2.0 * GSL_DBL_EPSILON * fabs(lng->val);\n    *sgn = ( eps > 0.0 ? -1.0 : 1.0 );\n    return GSL_SUCCESS;\n  }\n  else {\n    double g;\n\n    /* series for sin(Pi(N+1-eps))/(Pi eps) modulo the sign\n     * double-precision for |eps| < 0.02\n     */\n    const double cs1 = -1.6449340668482264365;\n    const double cs2 =  0.8117424252833536436;\n    const double cs3 = -0.1907518241220842137;\n    const double cs4 =  0.0261478478176548005;\n    const double cs5 = -0.0023460810354558236;\n    const double e2  = eps*eps;\n    const double sin_ser = 1.0 + e2*(cs1+e2*(cs2+e2*(cs3+e2*(cs4+e2*cs5))));\n\n    /* calculate series for ln(gamma(1+N-eps))\n     * double-precision for |eps| < 0.02\n     */\n    double aeps = fabs(eps);\n    double c1, c2, c3, c4, c5, c6, c7;\n    double lng_ser;\n    gsl_sf_result c0;\n    gsl_sf_result psi_0;\n    gsl_sf_result psi_1;\n    gsl_sf_result psi_2;\n    gsl_sf_result psi_3;\n    gsl_sf_result psi_4;\n    gsl_sf_result psi_5;\n    gsl_sf_result psi_6;\n    psi_2.val = 0.0;\n    psi_3.val = 0.0;\n    psi_4.val = 0.0;\n    psi_5.val = 0.0;\n    psi_6.val = 0.0;\n    gsl_sf_lnfact_e(N, &c0);\n    gsl_sf_psi_int_e(N+1, &psi_0);\n    gsl_sf_psi_1_int_e(N+1, &psi_1);\n    if(aeps > 0.00001) gsl_sf_psi_n_e(2, N+1.0, &psi_2);\n    if(aeps > 0.0002)  gsl_sf_psi_n_e(3, N+1.0, &psi_3);\n    if(aeps > 0.001)   gsl_sf_psi_n_e(4, N+1.0, &psi_4);\n    if(aeps > 0.005)   gsl_sf_psi_n_e(5, N+1.0, &psi_5);\n    if(aeps > 0.01)    gsl_sf_psi_n_e(6, N+1.0, &psi_6);\n    c1 = psi_0.val;\n    c2 = psi_1.val/2.0;\n    c3 = psi_2.val/6.0;\n    c4 = psi_3.val/24.0;\n    c5 = psi_4.val/120.0;\n    c6 = psi_5.val/720.0;\n    c7 = psi_6.val/5040.0;\n    lng_ser = c0.val-eps*(c1-eps*(c2-eps*(c3-eps*(c4-eps*(c5-eps*(c6-eps*c7))))));\n\n    /* calculate\n     * g = ln(|eps gamma(-N+eps)|)\n     *   = -ln(gamma(1+N-eps)) + ln(|eps Pi/sin(Pi(N+1+eps))|)\n     */\n    g = -lng_ser - log(sin_ser);\n\n    lng->val = g - log(fabs(eps));\n    lng->err = c0.err + 2.0 * GSL_DBL_EPSILON * (fabs(g) + fabs(lng->val));\n\n    *sgn = ( GSL_IS_ODD(N) ? -1.0 : 1.0 ) * ( eps > 0.0 ? 1.0 : -1.0 );\n\n    return GSL_SUCCESS;\n  }\n}\n\n\n/* This gets bad near the negative half axis. However, this\n * region can be avoided by use of the reflection formula, as usual.\n * Only the first two terms of the series are kept.\n */\n#if 0\nstatic\nint\nlngamma_complex_stirling(const double zr, const double zi, double * lg_r, double * arg)\n{\n  double re_zinv,  im_zinv;\n  double re_zinv2, im_zinv2;\n  double re_zinv3, im_zinv3;\n  double re_zhlnz, im_zhlnz;\n  double r, lnr, theta;\n  gsl_sf_complex_log_e(zr, zi, &lnr, &theta);  /* z = r e^{i theta} */\n  r = exp(lnr);\n  re_zinv =  (zr/r)/r;\n  im_zinv = -(zi/r)/r;\n  re_zinv2 = re_zinv*re_zinv - im_zinv*im_zinv;\n  re_zinv2 = 2.0*re_zinv*im_zinv;\n  re_zinv3 = re_zinv2*re_zinv - im_zinv2*im_zinv;\n  re_zinv3 = re_zinv2*im_zinv + im_zinv2*re_zinv;\n  re_zhlnz = (zr - 0.5)*lnr - zi*theta;\n  im_zhlnz = zi*lnr + zr*theta;\n  *lg_r = re_zhlnz - zr + 0.5*(M_LN2+M_LNPI) + re_zinv/12.0 - re_zinv3/360.0;\n  *arg  = im_zhlnz - zi + 1.0/12.0*im_zinv - im_zinv3/360.0;\n  return GSL_SUCCESS;\n}\n#endif /* 0 */\n\n\ninline\nstatic\nint\nlngamma_1_pade(const double eps, gsl_sf_result * result)\n{\n  /* Use (2,2) Pade for Log[Gamma[1+eps]]/eps\n   * plus a correction series.\n   */\n  const double n1 = -1.0017419282349508699871138440;\n  const double n2 =  1.7364839209922879823280541733;\n  const double d1 =  1.2433006018858751556055436011;\n  const double d2 =  5.0456274100274010152489597514;\n  const double num = (eps + n1) * (eps + n2);\n  const double den = (eps + d1) * (eps + d2);\n  const double pade = 2.0816265188662692474880210318 * num / den;\n  const double c0 =  0.004785324257581753;\n  const double c1 = -0.01192457083645441;\n  const double c2 =  0.01931961413960498;\n  const double c3 = -0.02594027398725020;\n  const double c4 =  0.03141928755021455;\n  const double eps5 = eps*eps*eps*eps*eps;\n  const double corr = eps5 * (c0 + eps*(c1 + eps*(c2 + eps*(c3 + c4*eps))));\n  result->val = eps * (pade + corr);\n  result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n  return GSL_SUCCESS;\n}\n\ninline\nstatic\nint\nlngamma_2_pade(const double eps, gsl_sf_result * result)\n{\n  /* Use (2,2) Pade for Log[Gamma[2+eps]]/eps\n   * plus a correction series.\n   */\n  const double n1 = 1.000895834786669227164446568;\n  const double n2 = 4.209376735287755081642901277;\n  const double d1 = 2.618851904903217274682578255;\n  const double d2 = 10.85766559900983515322922936;\n  const double num = (eps + n1) * (eps + n2);\n  const double den = (eps + d1) * (eps + d2);\n  const double pade = 2.85337998765781918463568869 * num/den;\n  const double c0 =  0.0001139406357036744;\n  const double c1 = -0.0001365435269792533;\n  const double c2 =  0.0001067287169183665;\n  const double c3 = -0.0000693271800931282;\n  const double c4 =  0.0000407220927867950;\n  const double eps5 = eps*eps*eps*eps*eps;\n  const double corr = eps5 * (c0 + eps*(c1 + eps*(c2 + eps*(c3 + c4*eps))));\n  result->val = eps * (pade + corr);\n  result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n  return GSL_SUCCESS;\n}\n\n\n/* series for gammastar(x)\n * double-precision for x > 10.0\n */\nstatic\nint\ngammastar_ser(const double x, gsl_sf_result * result)\n{\n  /* Use the Stirling series for the correction to Log(Gamma(x)),\n   * which is better behaved and easier to compute than the\n   * regular Stirling series for Gamma(x). \n   */\n  const double y = 1.0/(x*x);\n  const double c0 =  1.0/12.0;\n  const double c1 = -1.0/360.0;\n  const double c2 =  1.0/1260.0;\n  const double c3 = -1.0/1680.0;\n  const double c4 =  1.0/1188.0;\n  const double c5 = -691.0/360360.0;\n  const double c6 =  1.0/156.0;\n  const double c7 = -3617.0/122400.0;\n  const double ser = c0 + y*(c1 + y*(c2 + y*(c3 + y*(c4 + y*(c5 + y*(c6 + y*c7))))));\n  result->val = exp(ser/x);\n  result->err = 2.0 * GSL_DBL_EPSILON * result->val * GSL_MAX_DBL(1.0, ser/x);\n  return GSL_SUCCESS;\n}\n\n\n/* Chebyshev expansion for log(gamma(x)/gamma(8))\n * 5 < x < 10\n * -1 < t < 1\n */\nstatic double gamma_5_10_data[24] = {\n -1.5285594096661578881275075214,\n  4.8259152300595906319768555035,\n  0.2277712320977614992970601978,\n -0.0138867665685617873604917300,\n  0.0012704876495201082588139723,\n -0.0001393841240254993658962470,\n  0.0000169709242992322702260663,\n -2.2108528820210580075775889168e-06,\n  3.0196602854202309805163918716e-07,\n -4.2705675000079118380587357358e-08,\n  6.2026423818051402794663551945e-09,\n -9.1993973208880910416311405656e-10,\n  1.3875551258028145778301211638e-10,\n -2.1218861491906788718519522978e-11,\n  3.2821736040381439555133562600e-12,\n -5.1260001009953791220611135264e-13,\n  8.0713532554874636696982146610e-14,\n -1.2798522376569209083811628061e-14,\n  2.0417711600852502310258808643e-15,\n -3.2745239502992355776882614137e-16,\n  5.2759418422036579482120897453e-17,\n -8.5354147151695233960425725513e-18,\n  1.3858639703888078291599886143e-18,\n -2.2574398807738626571560124396e-19\n};\nstatic const cheb_series gamma_5_10_cs = {\n  gamma_5_10_data,\n  23,\n  -1, 1,\n  11\n};\n\n\n/* gamma(x) for x >= 1/2\n * assumes x >= 1/2\n */\nstatic\nint\ngamma_xgthalf(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x == 0.5) {\n    result->val = 1.77245385090551602729817;\n    result->err = GSL_DBL_EPSILON * result->val;\n    return GSL_SUCCESS;\n  } else if (x <= (GSL_SF_FACT_NMAX + 1.0) && x == floor(x)) {\n    int n = (int) floor (x);\n    result->val = fact_table[n - 1].f;\n    result->err = GSL_DBL_EPSILON * result->val;\n    return GSL_SUCCESS;\n  }    \n  else if(fabs(x - 1.0) < 0.01) {\n    /* Use series for Gamma[1+eps] - 1/(1+eps).\n     */\n    const double eps = x - 1.0;\n    const double c1 =  0.4227843350984671394;\n    const double c2 = -0.01094400467202744461;\n    const double c3 =  0.09252092391911371098;\n    const double c4 = -0.018271913165599812664;\n    const double c5 =  0.018004931096854797895;\n    const double c6 = -0.006850885378723806846;\n    const double c7 =  0.003998239557568466030;\n    result->val = 1.0/x + eps*(c1+eps*(c2+eps*(c3+eps*(c4+eps*(c5+eps*(c6+eps*c7))))));\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(fabs(x - 2.0) < 0.01) {\n    /* Use series for Gamma[1 + eps].\n     */\n    const double eps = x - 2.0;\n    const double c1 =  0.4227843350984671394;\n    const double c2 =  0.4118403304264396948;\n    const double c3 =  0.08157691924708626638;\n    const double c4 =  0.07424901075351389832;\n    const double c5 = -0.00026698206874501476832;\n    const double c6 =  0.011154045718130991049;\n    const double c7 = -0.002852645821155340816;\n    const double c8 =  0.0021039333406973880085;\n    result->val = 1.0 + eps*(c1+eps*(c2+eps*(c3+eps*(c4+eps*(c5+eps*(c6+eps*(c7+eps*c8)))))));\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(x < 5.0) {\n    /* Exponentiating the logarithm is fine, as\n     * long as the exponential is not so large\n     * that it greatly amplifies the error.\n     */\n    gsl_sf_result lg;\n    lngamma_lanczos(x, &lg);\n    result->val = exp(lg.val);\n    result->err = result->val * (lg.err + 2.0 * GSL_DBL_EPSILON);\n    return GSL_SUCCESS;\n  }\n  else if(x < 10.0) {\n    /* This is a sticky area. The logarithm\n     * is too large and the gammastar series\n     * is not good.\n     */\n    const double gamma_8 = 5040.0;\n    const double t = (2.0*x - 15.0)/5.0;\n    gsl_sf_result c;\n    cheb_eval_e(&gamma_5_10_cs, t, &c);\n    result->val  = exp(c.val) * gamma_8;\n    result->err  = result->val * c.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * result->val;\n    return GSL_SUCCESS;\n  }\n  else if(x < GSL_SF_GAMMA_XMAX) {\n    /* We do not want to exponentiate the logarithm\n     * if x is large because of the inevitable\n     * inflation of the error. So we carefully\n     * use pow() and exp() with exact quantities.\n     */\n    double p = pow(x, 0.5*x);\n    double e = exp(-x);\n    double q = (p * e) * p;\n    double pre = M_SQRT2 * M_SQRTPI * q/sqrt(x);\n    gsl_sf_result gstar;\n    int stat_gs = gammastar_ser(x, &gstar);\n    result->val = pre * gstar.val;\n    result->err = (x + 2.5) * GSL_DBL_EPSILON * result->val;\n    return stat_gs;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\n\nint gsl_sf_lngamma_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(fabs(x - 1.0) < 0.01) {\n    /* Note that we must amplify the errors\n     * from the Pade evaluations because of\n     * the way we must pass the argument, i.e.\n     * writing (1-x) is a loss of precision\n     * when x is near 1.\n     */\n    int stat = lngamma_1_pade(x - 1.0, result);\n    result->err *= 1.0/(GSL_DBL_EPSILON + fabs(x - 1.0));\n    return stat;\n  }\n  else if(fabs(x - 2.0) < 0.01) {\n    int stat = lngamma_2_pade(x - 2.0, result);\n    result->err *= 1.0/(GSL_DBL_EPSILON + fabs(x - 2.0));\n    return stat;\n  }\n  else if(x >= 0.5) {\n    return lngamma_lanczos(x, result);\n  }\n  else if(x == 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(fabs(x) < 0.02) {\n    double sgn;\n    return lngamma_sgn_0(x, result, &sgn);\n  }\n  else if(x > -0.5/(GSL_DBL_EPSILON*M_PI)) {\n    /* Try to extract a fractional\n     * part from x.\n     */\n    double z  = 1.0 - x;\n    double s  = sin(M_PI*z);\n    double as = fabs(s);\n    if(s == 0.0) {\n      DOMAIN_ERROR(result);\n    }\n    else if(as < M_PI*0.015) {\n      /* x is near a negative integer, -N */\n      if(x < INT_MIN + 2.0) {\n        result->val = 0.0;\n        result->err = 0.0;\n        GSL_ERROR (\"error\", GSL_EROUND);\n      }\n      else {\n        int N = -(int)(x - 0.5);\n        double eps = x + N;\n        double sgn;\n        return lngamma_sgn_sing(N, eps, result, &sgn);\n      }\n    }\n    else {\n      gsl_sf_result lg_z;\n      lngamma_lanczos(z, &lg_z);\n      result->val = M_LNPI - (log(as) + lg_z.val);\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + lg_z.err;\n      return GSL_SUCCESS;\n    }\n  }\n  else {\n    /* |x| was too large to extract any fractional part */\n    result->val = 0.0;\n    result->err = 0.0;\n    GSL_ERROR (\"error\", GSL_EROUND);\n  }\n}\n\n\nint gsl_sf_lngamma_sgn_e(double x, gsl_sf_result * result_lg, double * sgn)\n{\n  if(fabs(x - 1.0) < 0.01) {\n    int stat = lngamma_1_pade(x - 1.0, result_lg);\n    result_lg->err *= 1.0/(GSL_DBL_EPSILON + fabs(x - 1.0));\n    *sgn = 1.0;\n    return stat;\n  }\n  else if(fabs(x - 2.0) < 0.01) {\n   int stat = lngamma_2_pade(x - 2.0, result_lg);\n    result_lg->err *= 1.0/(GSL_DBL_EPSILON + fabs(x - 2.0));\n    *sgn = 1.0;\n    return stat;\n  }\n  else if(x >= 0.5) {\n    *sgn = 1.0;\n    return lngamma_lanczos(x, result_lg);\n  }\n  else if(x == 0.0) {\n    *sgn = 0.0;\n    DOMAIN_ERROR(result_lg);\n  }\n  else if(fabs(x) < 0.02) {\n    return lngamma_sgn_0(x, result_lg, sgn);\n  }\n  else if(x > -0.5/(GSL_DBL_EPSILON*M_PI)) {\n   /* Try to extract a fractional\n     * part from x.\n     */\n    double z = 1.0 - x;\n    double s = sin(M_PI*x);\n    double as = fabs(s);\n    if(s == 0.0) {\n      *sgn = 0.0;\n      DOMAIN_ERROR(result_lg);\n    }\n    else if(as < M_PI*0.015) {\n      /* x is near a negative integer, -N */\n      if(x < INT_MIN + 2.0) {\n        result_lg->val = 0.0;\n        result_lg->err = 0.0;\n        *sgn = 0.0;\n        GSL_ERROR (\"error\", GSL_EROUND);\n      }\n      else {\n        int N = -(int)(x - 0.5);\n        double eps = x + N;\n        return lngamma_sgn_sing(N, eps, result_lg, sgn);\n      }\n    }\n    else {\n      gsl_sf_result lg_z;\n      lngamma_lanczos(z, &lg_z);\n      *sgn = (s > 0.0 ? 1.0 : -1.0);\n      result_lg->val = M_LNPI - (log(as) + lg_z.val);\n      result_lg->err = 2.0 * GSL_DBL_EPSILON * fabs(result_lg->val) + lg_z.err;\n      return GSL_SUCCESS;\n    }\n  }\n  else {\n    /* |x| was too large to extract any fractional part */\n    result_lg->val = 0.0;\n    result_lg->err = 0.0;\n    *sgn = 0.0;\n    GSL_ERROR (\"x too large to extract fraction part\", GSL_EROUND);\n  }\n}\n\n\nint\ngsl_sf_gamma_e(const double x, gsl_sf_result * result)\n{\n  if(x < 0.5) {\n    int rint_x = (int)floor(x+0.5);\n    double f_x = x - rint_x;\n    double sgn_gamma = ( GSL_IS_EVEN(rint_x) ? 1.0 : -1.0 );\n    double sin_term = sgn_gamma * sin(M_PI * f_x) / M_PI;\n\n    if(sin_term == 0.0) {\n      DOMAIN_ERROR(result);\n    }\n    else if(x > -169.0) {\n      gsl_sf_result g;\n      gamma_xgthalf(1.0-x, &g);\n      if(fabs(sin_term) * g.val * GSL_DBL_MIN < 1.0) {\n        result->val  = 1.0/(sin_term * g.val);\n        result->err  = fabs(g.err/g.val) * fabs(result->val);\n        result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n        return GSL_SUCCESS;\n      }\n      else {\n        UNDERFLOW_ERROR(result);\n      }\n    }\n    else {\n      /* It is hard to control it here.\n       * We can only exponentiate the\n       * logarithm and eat the loss of\n       * precision.\n       */\n      gsl_sf_result lng;\n      double sgn;\n      int stat_lng = gsl_sf_lngamma_sgn_e(x, &lng, &sgn);\n      int stat_e   = gsl_sf_exp_mult_err_e(lng.val, lng.err, sgn, 0.0, result);\n      return GSL_ERROR_SELECT_2(stat_e, stat_lng);\n    }\n  }\n  else {\n    return gamma_xgthalf(x, result);\n  }\n}\n\n\nint\ngsl_sf_gammastar_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x <= 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x < 0.5) {\n    gsl_sf_result lg;\n    const int stat_lg = gsl_sf_lngamma_e(x, &lg);\n    const double lx = log(x);\n    const double c  = 0.5*(M_LN2+M_LNPI);\n    const double lnr_val = lg.val - (x-0.5)*lx + x - c;\n    const double lnr_err = lg.err + 2.0 * GSL_DBL_EPSILON *((x+0.5)*fabs(lx) + c);\n    const int stat_e  = gsl_sf_exp_err_e(lnr_val, lnr_err, result);\n    return GSL_ERROR_SELECT_2(stat_lg, stat_e);\n  }\n  else if(x < 2.0) {\n    const double t = 4.0/3.0*(x-0.5) - 1.0;\n    return cheb_eval_e(&gstar_a_cs, t, result);\n  }\n  else if(x < 10.0) {\n    const double t = 0.25*(x-2.0) - 1.0;\n    gsl_sf_result c;\n    cheb_eval_e(&gstar_b_cs, t, &c);\n    result->val  = c.val/(x*x) + 1.0 + 1.0/(12.0*x);\n    result->err  = c.err/(x*x);\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < 1.0/GSL_ROOT4_DBL_EPSILON) {\n    return gammastar_ser(x, result);\n  }\n  else if(x < 1.0/GSL_DBL_EPSILON) {\n    /* Use Stirling formula for Gamma(x).\n     */\n    const double xi = 1.0/x;\n    result->val = 1.0 + xi/12.0*(1.0 + xi/24.0*(1.0 - xi*(139.0/180.0 + 571.0/8640.0*xi)));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    result->val = 1.0;\n    result->err = 1.0/x;\n    return GSL_SUCCESS;\n  }\n}\n\n\nint\ngsl_sf_gammainv_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if (x <= 0.0 && x == floor(x)) { /* negative integer */\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  } else if(x < 0.5) {\n    gsl_sf_result lng;\n    double sgn;\n    int stat_lng = gsl_sf_lngamma_sgn_e(x, &lng, &sgn);\n    if(stat_lng == GSL_EDOM) {\n      result->val = 0.0;\n      result->err = 0.0;\n      return GSL_SUCCESS;\n    }\n    else if(stat_lng != GSL_SUCCESS) {\n      result->val = 0.0;\n      result->err = 0.0;\n      return stat_lng;\n    }\n    else {\n      return gsl_sf_exp_mult_err_e(-lng.val, lng.err, sgn, 0.0, result);\n    }\n  }\n  else {\n    gsl_sf_result g;\n    int stat_g = gamma_xgthalf(x, &g);\n    if(stat_g == GSL_EOVRFLW) {\n      UNDERFLOW_ERROR(result);\n    }\n    else {\n      result->val  = 1.0/g.val;\n      result->err  = fabs(g.err/g.val) * fabs(result->val);\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      CHECK_UNDERFLOW(result);\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint\ngsl_sf_lngamma_complex_e(double zr, double zi, gsl_sf_result * lnr, gsl_sf_result * arg)\n{\n  if(zr <= 0.5) {\n    /* Transform to right half plane using reflection;\n     * in fact we do a little better by stopping at 1/2.\n     */\n    double x = 1.0-zr;\n    double y = -zi;\n    gsl_sf_result a, b;\n    gsl_sf_result lnsin_r, lnsin_i;\n\n    int stat_l = lngamma_lanczos_complex(x, y, &a, &b);\n    int stat_s = gsl_sf_complex_logsin_e(M_PI*zr, M_PI*zi, &lnsin_r, &lnsin_i);\n\n    if(stat_s == GSL_SUCCESS) {\n      int stat_r;\n      lnr->val = M_LNPI - lnsin_r.val - a.val;\n      lnr->err = lnsin_r.err + a.err + 2.0 * GSL_DBL_EPSILON * fabs(lnr->val);\n      arg->val = -lnsin_i.val - b.val;\n      arg->err = lnsin_i.err + b.err + 2.0 * GSL_DBL_EPSILON * fabs(arg->val);\n      stat_r = gsl_sf_angle_restrict_symm_e(&(arg->val));\n      return GSL_ERROR_SELECT_2(stat_r, stat_l);\n    }\n    else {\n      DOMAIN_ERROR_2(lnr,arg);\n    }\n  }\n  else {\n    /* otherwise plain vanilla Lanczos */\n    return lngamma_lanczos_complex(zr, zi, lnr, arg);\n  }\n}\n\n\nint gsl_sf_taylorcoeff_e(const int n, const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x < 0.0 || n < 0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(n == 0) {\n    result->val = 1.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(n == 1) {\n    result->val = x;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(x == 0.0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else {\n    const double log2pi = M_LNPI + M_LN2;\n    const double ln_test = n*(log(x)+1.0) + 1.0 - (n+0.5)*log(n+1.0) + 0.5*log2pi;\n\n    if(ln_test < GSL_LOG_DBL_MIN+1.0) {\n      UNDERFLOW_ERROR(result);\n    }\n    else if(ln_test > GSL_LOG_DBL_MAX-1.0) {\n      OVERFLOW_ERROR(result);\n    }\n    else {\n      double product = 1.0;\n      int k;\n      for(k=1; k<=n; k++) {\n        product *= (x/k);\n      }\n      result->val = product;\n      result->err = n * GSL_DBL_EPSILON * product;\n      CHECK_UNDERFLOW(result);\n      return GSL_SUCCESS;\n    }    \n  }\n}\n\n\nint gsl_sf_fact_e(const unsigned int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n < 18) {\n    result->val = fact_table[n].f;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(n <= GSL_SF_FACT_NMAX){\n    result->val = fact_table[n].f;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\nint gsl_sf_doublefact_e(const unsigned int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n < 26) {\n    result->val = doub_fact_table[n].f;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(n <= GSL_SF_DOUBLEFACT_NMAX){\n    result->val = doub_fact_table[n].f;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR(result);\n  }\n}\n\n\nint gsl_sf_lnfact_e(const unsigned int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n <= GSL_SF_FACT_NMAX){\n    result->val = log(fact_table[n].f);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_lngamma_e(n+1.0, result);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_lndoublefact_e(const unsigned int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n <= GSL_SF_DOUBLEFACT_NMAX){\n    result->val = log(doub_fact_table[n].f);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(GSL_IS_ODD(n)) {\n    gsl_sf_result lg;\n    gsl_sf_lngamma_e(0.5*(n+2.0), &lg);\n    result->val = 0.5*(n+1.0) * M_LN2 - 0.5*M_LNPI + lg.val;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + lg.err;\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_result lg;\n    gsl_sf_lngamma_e(0.5*n+1.0, &lg);\n    result->val = 0.5*n*M_LN2 + lg.val;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + lg.err;\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_lnchoose_e(unsigned int n, unsigned int m, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(m > n) {\n    DOMAIN_ERROR(result);\n  }\n  else if(m == n || m == 0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_result nf;\n    gsl_sf_result mf;\n    gsl_sf_result nmmf;\n    if(m*2 > n) m = n-m;\n    gsl_sf_lnfact_e(n, &nf);\n    gsl_sf_lnfact_e(m, &mf);\n    gsl_sf_lnfact_e(n-m, &nmmf);\n    result->val  = nf.val - mf.val - nmmf.val;\n    result->err  = nf.err + mf.err + nmmf.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_choose_e(unsigned int n, unsigned int m, gsl_sf_result * result)\n{\n  if(m > n) {\n    DOMAIN_ERROR(result);\n  }\n  else if(m == n || m == 0) {\n    result->val = 1.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if (n <= GSL_SF_FACT_NMAX) {\n    result->val = (fact_table[n].f / fact_table[m].f) / fact_table[n-m].f;\n    result->err = 6.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  } else {\n    if(m*2 < n) m = n-m;\n\n    if (n - m < 64)  /* compute product for a manageable number of terms */\n      {\n        double prod = 1.0;\n        unsigned int k;\n        \n        for(k=n; k>=m+1; k--) {\n          double tk = (double)k / (double)(k-m);\n          if(tk > GSL_DBL_MAX/prod) {\n            OVERFLOW_ERROR(result);\n          }\n          prod *= tk;\n        }\n        result->val = prod;\n#pragma GCC diagnostic push\n#if (GNU_C >= 5)\n#pragma GCC diagnostic ignored \"-Wabsolute-value\"\n#endif\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wabsolute-value\"\n\t\t  result->err = 2.0 * GSL_DBL_EPSILON * prod * fabs(n-m);   // may produce a warning; ignore\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n        return GSL_SUCCESS;\n      }\n    else\n      {\n        gsl_sf_result lc;\n        const int stat_lc = gsl_sf_lnchoose_e (n, m, &lc);\n        const int stat_e  = gsl_sf_exp_err_e(lc.val, lc.err, result);\n        return GSL_ERROR_SELECT_2(stat_lc, stat_e);\n      }\n  }\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_fact(const unsigned int n)\n{\n  EVAL_RESULT(gsl_sf_fact_e(n, &result));\n}\n\ndouble gsl_sf_lnfact(const unsigned int n)\n{\n  EVAL_RESULT(gsl_sf_lnfact_e(n, &result));\n}\n\ndouble gsl_sf_doublefact(const unsigned int n)\n{\n  EVAL_RESULT(gsl_sf_doublefact_e(n, &result));\n}\n\ndouble gsl_sf_lndoublefact(const unsigned int n)\n{\n  EVAL_RESULT(gsl_sf_lndoublefact_e(n, &result));\n}\n\ndouble gsl_sf_lngamma(const double x)\n{\n  EVAL_RESULT(gsl_sf_lngamma_e(x, &result));\n}\n\ndouble gsl_sf_gamma(const double x)\n{\n  EVAL_RESULT(gsl_sf_gamma_e(x, &result));\n}\n\ndouble gsl_sf_gammastar(const double x)\n{\n  EVAL_RESULT(gsl_sf_gammastar_e(x, &result));\n}\n\ndouble gsl_sf_gammainv(const double x)\n{\n  EVAL_RESULT(gsl_sf_gammainv_e(x, &result));\n}\n\ndouble gsl_sf_taylorcoeff(const int n, const double x)\n{\n  EVAL_RESULT(gsl_sf_taylorcoeff_e(n, x, &result));\n}\n\ndouble gsl_sf_choose(unsigned int n, unsigned int m)\n{\n  EVAL_RESULT(gsl_sf_choose_e(n, m, &result));\n}\n\ndouble gsl_sf_lnchoose(unsigned int n, unsigned int m)\n{\n  EVAL_RESULT(gsl_sf_lnchoose_e(n, m, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/gamma_inc.c",
    "content": "/* specfunc/gamma_inc.c\n *\n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_erf.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_log.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_sf_expint.h\"\n\n#include \"error.h\"\n\n/* The dominant part,\n * D(a,x) := x^a e^(-x) / Gamma(a+1)\n */\nstatic\nint\ngamma_inc_D(const double a, const double x, gsl_sf_result * result)\n{\n  if(a < 10.0) {\n    double lnr;\n    gsl_sf_result lg;\n    gsl_sf_lngamma_e(a+1.0, &lg);\n    lnr = a * log(x) - x - lg.val;\n    result->val = exp(lnr);\n    result->err = 2.0 * GSL_DBL_EPSILON * (fabs(lnr) + 1.0) * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_result gstar;\n    gsl_sf_result ln_term;\n    double term1;\n    if (x < 0.5*a) {\n      double u = x/a;   \n      double ln_u = log(u);\n      ln_term.val = ln_u - u + 1.0;\n      ln_term.err = (fabs(ln_u) + fabs(u) + 1.0) * GSL_DBL_EPSILON;\n    } else {\n      double mu = (x-a)/a;\n      gsl_sf_log_1plusx_mx_e(mu, &ln_term);  /* log(1+mu) - mu */\n      /* Propagate cancellation error from x-a, since the absolute\n         error of mu=x-a is DBL_EPSILON */\n      ln_term.err += GSL_DBL_EPSILON * fabs(mu);\n    };\n    gsl_sf_gammastar_e(a, &gstar);\n    term1 = exp(a*ln_term.val)/sqrt(2.0*M_PI*a);\n    result->val  = term1/gstar.val;\n    result->err  = 2.0 * GSL_DBL_EPSILON * (fabs(a*ln_term.val) + 1.0) * fabs(result->val);\n    /* Include propagated error from log term */\n    result->err += fabs(a) * ln_term.err * fabs(result->val);\n    result->err += gstar.err/fabs(gstar.val) * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n\n}\n\n\n/* P series representation.\n */\nstatic\nint\ngamma_inc_P_series(const double a, const double x, gsl_sf_result * result)\n{\n  const int nmax = 10000;\n\n  gsl_sf_result D;\n  int stat_D = gamma_inc_D(a, x, &D);\n\n  /* Approximating the terms of the series using Stirling's\n     approximation gives t_n = (x/a)^n * exp(-n(n+1)/(2a)), so the\n     convergence condition is n^2 / (2a) + (1-(x/a) + (1/2a)) n >>\n     -log(GSL_DBL_EPS) if we want t_n < O(1e-16) t_0. The condition\n     below detects cases where the minimum value of n is > 5000 */\n\n  if (x > 0.995 * a && a > 1e5) { /* Difficult case: try continued fraction */\n    gsl_sf_result cf_res;\n    int status =  gsl_sf_exprel_n_CF_e(a, x, &cf_res);\n    result->val = D.val * cf_res.val;\n    result->err = fabs(D.val * cf_res.err) + fabs(D.err * cf_res.val);\n    return status;\n  }\n\n  /* Series would require excessive number of terms */\n\n  if (x > (a + nmax)) {\n    GSL_ERROR (\"gamma_inc_P_series x>>a exceeds range\", GSL_EMAXITER);\n  }\n\n  /* Normal case: sum the series */\n\n  {\n    double sum  = 1.0;\n    double term = 1.0;\n    double remainder;\n    int n;\n\n    /* Handle lower part of the series where t_n is increasing, |x| > a+n */\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n    int nlow = (x > a) ? (x - a): 0;\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n\n    for(n=1; n < nlow; n++) {\n      term *= x/(a+n);\n      sum  += term;\n    }\n\n    /* Handle upper part of the series where t_n is decreasing, |x| < a+n */\n\n    for (/* n = previous n */ ; n<nmax; n++)  {\n      term *= x/(a+n);\n      sum  += term;\n      if(fabs(term/sum) < GSL_DBL_EPSILON) break;\n    }\n\n    /*  Estimate remainder of series ~ t_(n+1)/(1-x/(a+n+1)) */\n    {\n      double tnp1 = (x/(a+n)) * term;\n      remainder =  tnp1 / (1.0 - x/(a + n + 1.0));\n    }\n\n    result->val  = D.val * sum;\n    result->err  = D.err * fabs(sum) + fabs(D.val * remainder);\n    result->err += (1.0 + n) * GSL_DBL_EPSILON * fabs(result->val);\n\n    if(n == nmax && fabs(remainder/sum) > GSL_SQRT_DBL_EPSILON)\n      GSL_ERROR (\"gamma_inc_P_series failed to converge\", GSL_EMAXITER);\n    else\n      return stat_D;\n  }\n}\n\n\n/* Q large x asymptotic\n */\nstatic\nint\ngamma_inc_Q_large_x(const double a, const double x, gsl_sf_result * result)\n{\n  const int nmax = 5000;\n\n  gsl_sf_result D;\n  const int stat_D = gamma_inc_D(a, x, &D);\n\n  double sum  = 1.0;\n  double term = 1.0;\n  double last = 1.0;\n  int n;\n  for(n=1; n<nmax; n++) {\n    term *= (a-n)/x;\n    if(fabs(term/last) > 1.0) break;\n    if(fabs(term/sum)  < GSL_DBL_EPSILON) break;\n    sum  += term;\n    last  = term;\n  }\n\n  result->val  = D.val * (a/x) * sum;\n  result->err  = D.err * fabs((a/x) * sum);\n  result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n\n  if(n == nmax)\n    GSL_ERROR (\"error in large x asymptotic\", GSL_EMAXITER);\n  else\n    return stat_D;\n}\n\n\n/* Uniform asymptotic for x near a, a and x large.\n * See [Temme, p. 285]\n */\nstatic\nint\ngamma_inc_Q_asymp_unif(const double a, const double x, gsl_sf_result * result)\n{\n  const double rta = sqrt(a);\n  const double eps = (x-a)/a;\n\n  gsl_sf_result ln_term;\n  const int stat_ln = gsl_sf_log_1plusx_mx_e(eps, &ln_term);  /* log(1+eps) - eps */\n  const double eta  = GSL_SIGN(eps) * sqrt(-2.0*ln_term.val);\n\n  gsl_sf_result erfc;\n\n  double R;\n  double c0, c1;\n\n  /* This used to say erfc(eta*M_SQRT2*rta), which is wrong.\n   * The sqrt(2) is in the denominator. Oops.\n   * Fixed: [GJ] Mon Nov 15 13:25:32 MST 2004\n   */\n  gsl_sf_erfc_e(eta*rta/M_SQRT2, &erfc);\n\n  if(fabs(eps) < GSL_ROOT5_DBL_EPSILON) {\n    c0 = -1.0/3.0 + eps*(1.0/12.0 - eps*(23.0/540.0 - eps*(353.0/12960.0 - eps*589.0/30240.0)));\n    c1 = -1.0/540.0 - eps/288.0;\n  }\n  else {\n    const double rt_term = sqrt(-2.0 * ln_term.val/(eps*eps));\n    const double lam = x/a;\n    c0 = (1.0 - 1.0/rt_term)/eps;\n    c1 = -(eta*eta*eta * (lam*lam + 10.0*lam + 1.0) - 12.0 * eps*eps*eps) / (12.0 * eta*eta*eta*eps*eps*eps);\n  }\n\n  R = exp(-0.5*a*eta*eta)/(M_SQRT2*M_SQRTPI*rta) * (c0 + c1/a);\n\n  result->val  = 0.5 * erfc.val + R;\n  result->err  = GSL_DBL_EPSILON * fabs(R * 0.5 * a*eta*eta) + 0.5 * erfc.err;\n  result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n\n  return stat_ln;\n}\n\n\n/* Continued fraction which occurs in evaluation\n * of Q(a,x) or Gamma(a,x).\n *\n *              1   (1-a)/x  1/x  (2-a)/x   2/x  (3-a)/x\n *   F(a,x) =  ---- ------- ----- -------- ----- -------- ...\n *             1 +   1 +     1 +   1 +      1 +   1 +\n *\n * Hans E. Plesser, 2002-01-22 (hans dot plesser at itf dot nlh dot no).\n *\n * Split out from gamma_inc_Q_CF() by GJ [Tue Apr  1 13:16:41 MST 2003].\n * See gamma_inc_Q_CF() below.\n *\n */\nstatic int\ngamma_inc_F_CF(const double a, const double x, gsl_sf_result * result)\n{\n  const int    nmax  =  5000;\n  const double small =  gsl_pow_3 (GSL_DBL_EPSILON);\n\n  double hn = 1.0;           /* convergent */\n  double Cn = 1.0 / small;\n  double Dn = 1.0;\n  int n;\n\n  /* n == 1 has a_1, b_1, b_0 independent of a,x,\n     so that has been done by hand                */\n  for ( n = 2 ; n < nmax ; n++ )\n  {\n    double an;\n    double delta;\n\n    if(GSL_IS_ODD(n))\n      an = 0.5*(n-1)/x;\n    else\n      an = (0.5*n-a)/x;\n\n    Dn = 1.0 + an * Dn;\n    if ( fabs(Dn) < small )\n      Dn = small;\n    Cn = 1.0 + an/Cn;\n    if ( fabs(Cn) < small )\n      Cn = small;\n    Dn = 1.0 / Dn;\n    delta = Cn * Dn;\n    hn *= delta;\n    if(fabs(delta-1.0) < GSL_DBL_EPSILON) break;\n  }\n\n  result->val = hn;\n  result->err = 2.0*GSL_DBL_EPSILON * fabs(hn);\n  result->err += GSL_DBL_EPSILON * (2.0 + 0.5*n) * fabs(result->val);\n\n  if(n == nmax)\n    GSL_ERROR (\"error in CF for F(a,x)\", GSL_EMAXITER);\n  else\n    return GSL_SUCCESS;\n}\n\n\n/* Continued fraction for Q.\n *\n * Q(a,x) = D(a,x) a/x F(a,x)\n *\n * Hans E. Plesser, 2002-01-22 (hans dot plesser at itf dot nlh dot no):\n *\n * Since the Gautschi equivalent series method for CF evaluation may lead\n * to singularities, I have replaced it with the modified Lentz algorithm\n * given in\n *\n * I J Thompson and A R Barnett\n * Coulomb and Bessel Functions of Complex Arguments and Order\n * J Computational Physics 64:490-509 (1986)\n *\n * In consequence, gamma_inc_Q_CF_protected() is now obsolete and has been\n * removed.\n *\n * Identification of terms between the above equation for F(a, x) and\n * the first equation in the appendix of Thompson&Barnett is as follows:\n *\n *    b_0 = 0, b_n = 1 for all n > 0\n *\n *    a_1 = 1\n *    a_n = (n/2-a)/x    for n even\n *    a_n = (n-1)/(2x)   for n odd\n *\n */\nstatic\nint\ngamma_inc_Q_CF(const double a, const double x, gsl_sf_result * result)\n{\n  gsl_sf_result D;\n  gsl_sf_result F;\n  const int stat_D = gamma_inc_D(a, x, &D);\n  const int stat_F = gamma_inc_F_CF(a, x, &F);\n\n  result->val  = D.val * (a/x) * F.val;\n  result->err  = D.err * fabs((a/x) * F.val) + fabs(D.val * a/x * F.err);\n\n  return GSL_ERROR_SELECT_2(stat_F, stat_D);\n}\n\n\n/* Useful for small a and x. Handles the subtraction analytically.\n */\nstatic\nint\ngamma_inc_Q_series(const double a, const double x, gsl_sf_result * result)\n{\n  double term1;  /* 1 - x^a/Gamma(a+1) */\n  double sum;    /* 1 + (a+1)/(a+2)(-x)/2! + (a+1)/(a+3)(-x)^2/3! + ... */\n  int stat_sum;\n  double term2;  /* a temporary variable used at the end */\n\n  {\n    /* Evaluate series for 1 - x^a/Gamma(a+1), small a\n     */\n    const double pg21 = -2.404113806319188570799476;  /* PolyGamma[2,1] */\n    const double lnx  = log(x);\n    const double el   = M_EULER+lnx;\n    const double c1 = -el;\n    const double c2 = M_PI*M_PI/12.0 - 0.5*el*el;\n    const double c3 = el*(M_PI*M_PI/12.0 - el*el/6.0) + pg21/6.0;\n    const double c4 = -0.04166666666666666667\n                       * (-1.758243446661483480 + lnx)\n                       * (-0.764428657272716373 + lnx)\n                       * ( 0.723980571623507657 + lnx)\n                       * ( 4.107554191916823640 + lnx);\n    const double c5 = -0.0083333333333333333\n                       * (-2.06563396085715900 + lnx)\n                       * (-1.28459889470864700 + lnx)\n                       * (-0.27583535756454143 + lnx)\n                       * ( 1.33677371336239618 + lnx)\n                       * ( 5.17537282427561550 + lnx);\n    const double c6 = -0.0013888888888888889\n                       * (-2.30814336454783200 + lnx)\n                       * (-1.65846557706987300 + lnx)\n                       * (-0.88768082560020400 + lnx)\n                       * ( 0.17043847751371778 + lnx)\n                       * ( 1.92135970115863890 + lnx)\n                       * ( 6.22578557795474900 + lnx);\n    const double c7 = -0.00019841269841269841\n                       * (-2.5078657901291800 + lnx)\n                       * (-1.9478900888958200 + lnx)\n                       * (-1.3194837322612730 + lnx)\n                       * (-0.5281322700249279 + lnx)\n                       * ( 0.5913834939078759 + lnx)\n                       * ( 2.4876819633378140 + lnx)\n                       * ( 7.2648160783762400 + lnx);\n    const double c8 = -0.00002480158730158730\n                       * (-2.677341544966400 + lnx)\n                       * (-2.182810448271700 + lnx)\n                       * (-1.649350342277400 + lnx)\n                       * (-1.014099048290790 + lnx)\n                       * (-0.191366955370652 + lnx)\n                       * ( 0.995403817918724 + lnx)\n                       * ( 3.041323283529310 + lnx)\n                       * ( 8.295966556941250 + lnx);\n    const double c9 = -2.75573192239859e-6\n                       * (-2.8243487670469080 + lnx)\n                       * (-2.3798494322701120 + lnx)\n                       * (-1.9143674728689960 + lnx)\n                       * (-1.3814529102920370 + lnx)\n                       * (-0.7294312810261694 + lnx)\n                       * ( 0.1299079285269565 + lnx)\n                       * ( 1.3873333251885240 + lnx)\n                       * ( 3.5857258865210760 + lnx)\n                       * ( 9.3214237073814600 + lnx);\n    const double c10 = -2.75573192239859e-7\n                       * (-2.9540329644556910 + lnx)\n                       * (-2.5491366926991850 + lnx)\n                       * (-2.1348279229279880 + lnx)\n                       * (-1.6741881076349450 + lnx)\n                       * (-1.1325949616098420 + lnx)\n                       * (-0.4590034650618494 + lnx)\n                       * ( 0.4399352987435699 + lnx)\n                       * ( 1.7702236517651670 + lnx)\n                       * ( 4.1231539047474080 + lnx)\n                       * ( 10.342627908148680 + lnx);\n\n    term1 = a*(c1+a*(c2+a*(c3+a*(c4+a*(c5+a*(c6+a*(c7+a*(c8+a*(c9+a*c10)))))))));\n  }\n\n  {\n    /* Evaluate the sum.\n     */\n    const int nmax = 5000;\n    double t = 1.0;\n    int n;\n    sum = 1.0;\n\n    for(n=1; n<nmax; n++) {\n      t *= -x/(n+1.0);\n      sum += (a+1.0)/(a+n+1.0)*t;\n      if(fabs(t/sum) < GSL_DBL_EPSILON) break;\n    }\n\n    if(n == nmax)\n      stat_sum = GSL_EMAXITER;\n    else\n      stat_sum = GSL_SUCCESS;\n  }\n\n  term2 = (1.0 - term1) * a/(a+1.0) * x * sum;\n  result->val  = term1 + term2;\n  result->err  = GSL_DBL_EPSILON * (fabs(term1) + 2.0*fabs(term2));\n  result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n  return stat_sum;\n}\n\n\n/* series for small a and x, but not defined for a == 0 */\nstatic int\ngamma_inc_series(double a, double x, gsl_sf_result * result)\n{\n  gsl_sf_result Q;\n  gsl_sf_result G;\n  const int stat_Q = gamma_inc_Q_series(a, x, &Q);\n  const int stat_G = gsl_sf_gamma_e(a, &G);\n  result->val = Q.val * G.val;\n  result->err = fabs(Q.val * G.err) + fabs(Q.err * G.val);\n  result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n\n  return GSL_ERROR_SELECT_2(stat_Q, stat_G);\n}\n\n\nstatic int\ngamma_inc_a_gt_0(double a, double x, gsl_sf_result * result)\n{\n  /* x > 0 and a > 0; use result for Q */\n  gsl_sf_result Q;\n  gsl_sf_result G;\n  const int stat_Q = gsl_sf_gamma_inc_Q_e(a, x, &Q);\n  const int stat_G = gsl_sf_gamma_e(a, &G);\n\n  result->val = G.val * Q.val;\n  result->err = fabs(G.val * Q.err) + fabs(G.err * Q.val);\n  result->err += 2.0*GSL_DBL_EPSILON * fabs(result->val);\n\n  return GSL_ERROR_SELECT_2(stat_G, stat_Q);\n}\n\n\nstatic int\ngamma_inc_CF(double a, double x, gsl_sf_result * result)\n{\n  gsl_sf_result F;\n  gsl_sf_result pre;\n  const double am1lgx = (a-1.0)*log(x);\n  const int stat_F = gamma_inc_F_CF(a, x, &F);\n  const int stat_E = gsl_sf_exp_err_e(am1lgx - x, GSL_DBL_EPSILON*fabs(am1lgx), &pre);\n\n  result->val = F.val * pre.val;\n  result->err = fabs(F.err * pre.val) + fabs(F.val * pre.err);\n  result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n\n  return GSL_ERROR_SELECT_2(stat_F, stat_E);\n}\n\n\n/* evaluate Gamma(0,x), x > 0 */\n#define GAMMA_INC_A_0(x, result) gsl_sf_expint_E1_e(x, result)\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\nint\ngsl_sf_gamma_inc_Q_e(const double a, const double x, gsl_sf_result * result)\n{\n  if(a < 0.0 || x < 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x == 0.0) {\n    result->val = 1.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(a == 0.0)\n  {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(x <= 0.5*a) {\n    /* If the series is quick, do that. It is\n     * robust and simple.\n     */\n    gsl_sf_result P;\n    int stat_P = gamma_inc_P_series(a, x, &P);\n    result->val  = 1.0 - P.val;\n    result->err  = P.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return stat_P;\n  }\n  else if(a >= 1.0e+06 && (x-a)*(x-a) < a) {\n    /* Then try the difficult asymptotic regime.\n     * This is the only way to do this region.\n     */\n    return gamma_inc_Q_asymp_unif(a, x, result);\n  }\n  else if(a < 0.2 && x < 5.0) {\n    /* Cancellations at small a must be handled\n     * analytically; x should not be too big\n     * either since the series terms grow\n     * with x and log(x).\n     */\n    return gamma_inc_Q_series(a, x, result);\n  }\n  else if(a <= x) {\n    if(x <= 1.0e+06) {\n      /* Continued fraction is excellent for x >~ a.\n       * We do not let x be too large when x > a since\n       * it is somewhat pointless to try this there;\n       * the function is rapidly decreasing for\n       * x large and x > a, and it will just\n       * underflow in that region anyway. We\n       * catch that case in the standard\n       * large-x method.\n       */\n      return gamma_inc_Q_CF(a, x, result);\n    }\n    else {\n      return gamma_inc_Q_large_x(a, x, result);\n    }\n  }\n  else {\n    if(x > a - sqrt(a)) {\n      /* Continued fraction again. The convergence\n       * is a little slower here, but that is fine.\n       * We have to trade that off against the slow\n       * convergence of the series, which is the\n       * only other option.\n       */\n      return gamma_inc_Q_CF(a, x, result);\n    }\n    else {\n      gsl_sf_result P;\n      int stat_P = gamma_inc_P_series(a, x, &P);\n      result->val  = 1.0 - P.val;\n      result->err  = P.err;\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return stat_P;\n    }\n  }\n}\n\n\nint\ngsl_sf_gamma_inc_P_e(const double a, const double x, gsl_sf_result * result)\n{\n  if(a <= 0.0 || x < 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x == 0.0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else if(x < 20.0 || x < 0.5*a) {\n    /* Do the easy series cases. Robust and quick.\n     */\n    return gamma_inc_P_series(a, x, result);\n  }\n  else if(a > 1.0e+06 && (x-a)*(x-a) < a) {\n    /* Crossover region. Note that Q and P are\n     * roughly the same order of magnitude here,\n     * so the subtraction is stable.\n     */\n    gsl_sf_result Q;\n    int stat_Q = gamma_inc_Q_asymp_unif(a, x, &Q);\n    result->val  = 1.0 - Q.val;\n    result->err  = Q.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return stat_Q;\n  }\n  else if(a <= x) {\n    /* Q <~ P in this area, so the\n     * subtractions are stable.\n     */\n    gsl_sf_result Q;\n    int stat_Q;\n    if(a > 0.2*x) {\n      stat_Q = gamma_inc_Q_CF(a, x, &Q);\n    }\n    else {\n      stat_Q = gamma_inc_Q_large_x(a, x, &Q);\n    }\n    result->val  = 1.0 - Q.val;\n    result->err  = Q.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return stat_Q;\n  }\n  else {\n    if((x-a)*(x-a) < a) {\n      /* This condition is meant to insure\n       * that Q is not very close to 1,\n       * so the subtraction is stable.\n       */\n      gsl_sf_result Q;\n      int stat_Q = gamma_inc_Q_CF(a, x, &Q);\n      result->val  = 1.0 - Q.val;\n      result->err  = Q.err;\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return stat_Q;\n    }\n    else {\n      return gamma_inc_P_series(a, x, result);\n    }\n  }\n}\n\n\nint\ngsl_sf_gamma_inc_e(const double a, const double x, gsl_sf_result * result)\n{\n  if(x < 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x == 0.0) {\n    return gsl_sf_gamma_e(a, result);\n  }\n  else if(a == 0.0)\n  {\n    return GAMMA_INC_A_0(x, result);\n  }\n  else if(a > 0.0)\n  {\n    return gamma_inc_a_gt_0(a, x, result);\n  }\n  else if(x > 0.25)\n  {\n    /* continued fraction seems to fail for x too small; otherwise\n       it is ok, independent of the value of |x/a|, because of the\n       non-oscillation in the expansion, i.e. the CF is\n       un-conditionally convergent for a < 0 and x > 0\n     */\n    return gamma_inc_CF(a, x, result);\n  }\n  else if(fabs(a) < 0.5)\n  {\n    return gamma_inc_series(a, x, result);\n  }\n  else\n  {\n    /* a = fa + da; da >= 0 */\n    const double fa = floor(a);\n    const double da = a - fa;\n\n    gsl_sf_result g_da;\n    const int stat_g_da = ( da > 0.0 ? gamma_inc_a_gt_0(da, x, &g_da)\n                                     : GAMMA_INC_A_0(x, &g_da));\n\n    double alpha = da;\n    double gax = g_da.val;\n\n    /* Gamma(alpha-1,x) = 1/(alpha-1) (Gamma(a,x) - x^(alpha-1) e^-x) */\n    do\n    {\n      const double shift = exp(-x + (alpha-1.0)*log(x));\n      gax = (gax - shift) / (alpha - 1.0);\n      alpha -= 1.0;\n    } while(alpha > a);\n\n    result->val = gax;\n    result->err = 2.0*(1.0 + fabs(a))*GSL_DBL_EPSILON*fabs(gax);\n    return stat_g_da;\n  }\n\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_gamma_inc_P(const double a, const double x)\n{\n  EVAL_RESULT(gsl_sf_gamma_inc_P_e(a, x, &result));\n}\n\ndouble gsl_sf_gamma_inc_Q(const double a, const double x)\n{\n  EVAL_RESULT(gsl_sf_gamma_inc_Q_e(a, x, &result));\n}\n\ndouble gsl_sf_gamma_inc(const double a, const double x)\n{\n   EVAL_RESULT(gsl_sf_gamma_inc_e(a, x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_elementary.h",
    "content": "/* specfunc/gsl_sf_elementary.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n/* Miscellaneous elementary functions and operations.\n */\n#ifndef __GSL_SF_ELEMENTARY_H__\n#define __GSL_SF_ELEMENTARY_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Multiplication.\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_multiply_e(const double x, const double y, gsl_sf_result * result);\ndouble gsl_sf_multiply(const double x, const double y);\n\n\n/* Multiplication of quantities with associated errors.\n */\nint gsl_sf_multiply_err_e(const double x, const double dx, const double y, const double dy, gsl_sf_result * result);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_ELEMENTARY_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_erf.h",
    "content": "/* specfunc/gsl_sf_erf.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_ERF_H__\n#define __GSL_SF_ERF_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Complementary Error Function\n * erfc(x) := 2/Sqrt[Pi] Integrate[Exp[-t^2], {t,x,Infinity}]\n *\n * exceptions: none\n */\nint gsl_sf_erfc_e(double x, gsl_sf_result * result);\ndouble gsl_sf_erfc(double x);\n\n\n/* Log Complementary Error Function\n *\n * exceptions: none\n */\nint gsl_sf_log_erfc_e(double x, gsl_sf_result * result);\ndouble gsl_sf_log_erfc(double x);\n\n\n/* Error Function\n * erf(x) := 2/Sqrt[Pi] Integrate[Exp[-t^2], {t,0,x}]\n *\n * exceptions: none\n */\nint gsl_sf_erf_e(double x, gsl_sf_result * result);\ndouble gsl_sf_erf(double x);\n\n\n/* Probability functions:\n * Z(x) :  Abramowitz+Stegun 26.2.1\n * Q(x) :  Abramowitz+Stegun 26.2.3\n *\n * exceptions: none\n */\nint gsl_sf_erf_Z_e(double x, gsl_sf_result * result);\nint gsl_sf_erf_Q_e(double x, gsl_sf_result * result);\ndouble gsl_sf_erf_Z(double x);\ndouble gsl_sf_erf_Q(double x);\n\n\n/* Hazard function, also known as the inverse Mill's ratio.\n *\n *   H(x) := Z(x)/Q(x)\n *         = Sqrt[2/Pi] Exp[-x^2 / 2] / Erfc[x/Sqrt[2]]\n *\n * exceptions: GSL_EUNDRFLW\n */\nint gsl_sf_hazard_e(double x, gsl_sf_result * result);\ndouble gsl_sf_hazard(double x);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_ERF_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_exp.h",
    "content": "/* specfunc/gsl_sf_exp.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_EXP_H__\n#define __GSL_SF_EXP_H__\n\n#include \"gsl_sf_result.h\"\n#include \"gsl_precision.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n/* Provide an exp() function with GSL semantics,\n * i.e. with proper error checking, etc.\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_exp(const double x);\n\n\n/* Exp(x)\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_e10_e(const double x, gsl_sf_result_e10 * result);\n\n\n/* Exponentiate and multiply by a given factor:  y * Exp(x)\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_mult_e(const double x, const double y, gsl_sf_result * result);\ndouble gsl_sf_exp_mult(const double x, const double y);\n\n\n/* Exponentiate and multiply by a given factor:  y * Exp(x)\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_mult_e10_e(const double x, const double y, gsl_sf_result_e10 * result);\n\n\n/* exp(x)-1\n *\n * exceptions: GSL_EOVRFLW\n */\nint gsl_sf_expm1_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_expm1(const double x);\n\n\n/* (exp(x)-1)/x = 1 + x/2 + x^2/(2*3) + x^3/(2*3*4) + ...\n *\n * exceptions: GSL_EOVRFLW\n */\nint gsl_sf_exprel_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_exprel(const double x);\n\n\n/* 2(exp(x)-1-x)/x^2 = 1 + x/3 + x^2/(3*4) + x^3/(3*4*5) + ...\n *\n * exceptions: GSL_EOVRFLW\n */\nint gsl_sf_exprel_2_e(double x, gsl_sf_result * result);\ndouble gsl_sf_exprel_2(const double x);\n\n\n/* Similarly for the N-th generalization of\n * the above. The so-called N-relative exponential\n *\n * exprel_N(x) = N!/x^N (exp(x) - Sum[x^k/k!, {k,0,N-1}])\n *             = 1 + x/(N+1) + x^2/((N+1)(N+2)) + ...\n *             = 1F1(1,1+N,x)\n */\nint gsl_sf_exprel_n_e(const int n, const double x, gsl_sf_result * result);\ndouble gsl_sf_exprel_n(const int n, const double x);\n\nint gsl_sf_exprel_n_CF_e(const double n, const double x, gsl_sf_result * result);\n\n\n/* Exponentiate a quantity with an associated error.\n */\nint gsl_sf_exp_err_e(const double x, const double dx, gsl_sf_result * result);\n\n/* Exponentiate a quantity with an associated error.\n */\nint gsl_sf_exp_err_e10_e(const double x, const double dx, gsl_sf_result_e10 * result);\n\n\n/* Exponentiate and multiply by a given factor:  y * Exp(x),\n * for quantities with associated errors.\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_mult_err_e(const double x, const double dx, const double y, const double dy, gsl_sf_result * result);\n\n\n/* Exponentiate and multiply by a given factor:  y * Exp(x),\n * for quantities with associated errors.\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_exp_mult_err_e10_e(const double x, const double dx, const double y, const double dy, gsl_sf_result_e10 * result);\n\n__END_DECLS\n\n#endif /* __GSL_SF_EXP_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_expint.h",
    "content": "/* specfunc/gsl_sf_expint.h\n * \n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author: G. Jungman */\n\n#ifndef __GSL_SF_EXPINT_H__\n#define __GSL_SF_EXPINT_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* E_1(x) := Re[ Integrate[ Exp[-xt]/t, {t,1,Infinity}] ]\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_E1_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_E1(const double x);\n\n\n/* E_2(x) := Re[ Integrate[ Exp[-xt]/t^2, {t,1,Infinity}] ]\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_E2_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_E2(const double x);\n\n\n/* E_n(x) := Re[ Integrate[ Exp[-xt]/t^n, {t,1,Infinity}] ]\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_En_e(const int n, const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_En(const int n, const double x);\n\n\n/* E_1_scaled(x) := exp(x) E_1(x)\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_E1_scaled_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_E1_scaled(const double x);\n\n\n/* E_2_scaled(x) := exp(x) E_2(x)\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_E2_scaled_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_E2_scaled(const double x);\n\n/* E_n_scaled(x) := exp(x) E_n(x)\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_En_scaled_e(const int n, const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_En_scaled(const int n, const double x);\n\n\n/* Ei(x) := - PV Integrate[ Exp[-t]/t, {t,-x,Infinity}]\n *       :=   PV Integrate[ Exp[t]/t, {t,-Infinity,x}]\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_Ei_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_Ei(const double x);\n\n\n/* Ei_scaled(x) := exp(-x) Ei(x)\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_expint_Ei_scaled_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_Ei_scaled(const double x);\n\n\n/* Shi(x) := Integrate[ Sinh[t]/t, {t,0,x}]\n *\n * exceptions: GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_Shi_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_Shi(const double x);\n\n\n/* Chi(x) := Re[ M_EULER + log(x) + Integrate[(Cosh[t]-1)/t, {t,0,x}] ]\n *\n * x != 0.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint     gsl_sf_Chi_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_Chi(const double x);\n\n\n/* Ei_3(x) := Integral[ Exp[-t^3], {t,0,x}]\n *\n * x >= 0.0\n * exceptions: GSL_EDOM\n */\nint     gsl_sf_expint_3_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_expint_3(double x);\n\n\n/* Si(x) := Integrate[ Sin[t]/t, {t,0,x}]\n *\n * exceptions: none\n */\nint     gsl_sf_Si_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_Si(const double x);\n\n\n/* Ci(x) := -Integrate[ Cos[t]/t, {t,x,Infinity}]\n *\n * x > 0.0\n * exceptions: GSL_EDOM \n */\nint     gsl_sf_Ci_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_Ci(const double x);\n\n\n/* AtanInt(x) := Integral[ Arctan[t]/t, {t,0,x}]\n *\n *\n * exceptions:\n */\nint     gsl_sf_atanint_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_atanint(const double x);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_EXPINT_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_gamma.h",
    "content": "/* specfunc/gsl_sf_gamma.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_GAMMA_H__\n#define __GSL_SF_GAMMA_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Log[Gamma(x)], x not a negative integer\n * Uses real Lanczos method.\n * Returns the real part of Log[Gamma[x]] when x < 0,\n * i.e. Log[|Gamma[x]|].\n *\n * exceptions: GSL_EDOM, GSL_EROUND\n */\nint gsl_sf_lngamma_e(double x, gsl_sf_result * result);\ndouble gsl_sf_lngamma(const double x);\n\n\n/* Log[Gamma(x)], x not a negative integer\n * Uses real Lanczos method. Determines\n * the sign of Gamma[x] as well as Log[|Gamma[x]|] for x < 0.\n * So Gamma[x] = sgn * Exp[result_lg].\n *\n * exceptions: GSL_EDOM, GSL_EROUND\n */\nint gsl_sf_lngamma_sgn_e(double x, gsl_sf_result * result_lg, double *sgn);\n\n\n/* Gamma(x), x not a negative integer\n * Uses real Lanczos method.\n *\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EROUND\n */\nint gsl_sf_gamma_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_gamma(const double x);\n\n\n/* Regulated Gamma Function, x > 0\n * Gamma^*(x) = Gamma(x)/(Sqrt[2Pi] x^(x-1/2) exp(-x))\n *            = (1 + 1/(12x) + ...),  x->Inf\n * A useful suggestion of Temme.\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_gammastar_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_gammastar(const double x);\n\n\n/* 1/Gamma(x)\n * Uses real Lanczos method.\n *\n * exceptions: GSL_EUNDRFLW, GSL_EROUND\n */\nint gsl_sf_gammainv_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_gammainv(const double x);\n\n\n/* Log[Gamma(z)] for z complex, z not a negative integer\n * Uses complex Lanczos method. Note that the phase part (arg)\n * is not well-determined when |z| is very large, due\n * to inevitable roundoff in restricting to (-Pi,Pi].\n * This will raise the GSL_ELOSS exception when it occurs.\n * The absolute value part (lnr), however, never suffers.\n *\n * Calculates:\n *   lnr = log|Gamma(z)|\n *   arg = arg(Gamma(z))  in (-Pi, Pi]\n *\n * exceptions: GSL_EDOM, GSL_ELOSS\n */\nint gsl_sf_lngamma_complex_e(double zr, double zi, gsl_sf_result * lnr, gsl_sf_result * arg);\n\n\n/* x^n / n!\n *\n * x >= 0.0, n >= 0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_taylorcoeff_e(const int n, const double x, gsl_sf_result * result);\ndouble gsl_sf_taylorcoeff(const int n, const double x);\n\n\n/* n!\n *\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_fact_e(const unsigned int n, gsl_sf_result * result);\ndouble gsl_sf_fact(const unsigned int n);\n\n\n/* n!! = n(n-2)(n-4) ... \n *\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_doublefact_e(const unsigned int n, gsl_sf_result * result);\ndouble gsl_sf_doublefact(const unsigned int n);\n\n\n/* log(n!) \n * Faster than ln(Gamma(n+1)) for n < 170; defers for larger n.\n *\n * exceptions: none\n */\nint gsl_sf_lnfact_e(const unsigned int n, gsl_sf_result * result);\ndouble gsl_sf_lnfact(const unsigned int n);\n\n\n/* log(n!!) \n *\n * exceptions: none\n */\nint gsl_sf_lndoublefact_e(const unsigned int n, gsl_sf_result * result);\ndouble gsl_sf_lndoublefact(const unsigned int n);\n\n\n/* log(n choose m)\n *\n * exceptions: GSL_EDOM \n */\nint gsl_sf_lnchoose_e(unsigned int n, unsigned int m, gsl_sf_result * result);\ndouble gsl_sf_lnchoose(unsigned int n, unsigned int m);\n\n\n/* n choose m\n *\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_choose_e(unsigned int n, unsigned int m, gsl_sf_result * result);\ndouble gsl_sf_choose(unsigned int n, unsigned int m);\n\n\n/* Logarithm of Pochhammer (Apell) symbol\n *   log( (a)_x )\n *   where (a)_x := Gamma[a + x]/Gamma[a]\n *\n * a > 0, a+x > 0\n *\n * exceptions:  GSL_EDOM\n */\nint gsl_sf_lnpoch_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_lnpoch(const double a, const double x);\n\n\n/* Logarithm of Pochhammer (Apell) symbol, with sign information.\n *   result = log( |(a)_x| )\n *   sgn    = sgn( (a)_x )\n *   where (a)_x := Gamma[a + x]/Gamma[a]\n *\n * a != neg integer, a+x != neg integer\n *\n * exceptions:  GSL_EDOM\n */\nint gsl_sf_lnpoch_sgn_e(const double a, const double x, gsl_sf_result * result, double * sgn);\n\n\n/* Pochhammer (Apell) symbol\n *   (a)_x := Gamma[a + x]/Gamma[x]\n *\n * a != neg integer, a+x != neg integer\n *\n * exceptions:  GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_poch_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_poch(const double a, const double x);\n\n\n/* Relative Pochhammer (Apell) symbol\n *   ((a,x) - 1)/x\n *   where (a,x) = (a)_x := Gamma[a + x]/Gamma[a]\n *\n * exceptions:  GSL_EDOM\n */\nint gsl_sf_pochrel_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_pochrel(const double a, const double x);\n\n\n/* Normalized Incomplete Gamma Function\n *\n * Q(a,x) = 1/Gamma(a) Integral[ t^(a-1) e^(-t), {t,x,Infinity} ]\n *\n * a >= 0, x >= 0\n *   Q(a,0) := 1\n *   Q(0,x) := 0, x != 0\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_gamma_inc_Q_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_gamma_inc_Q(const double a, const double x);\n\n\n/* Complementary Normalized Incomplete Gamma Function\n *\n * P(a,x) = 1/Gamma(a) Integral[ t^(a-1) e^(-t), {t,0,x} ]\n *\n * a > 0, x >= 0\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_gamma_inc_P_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_gamma_inc_P(const double a, const double x);\n\n\n/* Non-normalized Incomplete Gamma Function\n *\n * Gamma(a,x) := Integral[ t^(a-1) e^(-t), {t,x,Infinity} ]\n *\n * x >= 0.0\n *   Gamma(a, 0) := Gamma(a)\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_gamma_inc_e(const double a, const double x, gsl_sf_result * result);\ndouble gsl_sf_gamma_inc(const double a, const double x);\n\n\n/* Logarithm of Beta Function\n * Log[B(a,b)]\n *\n * a > 0, b > 0\n * exceptions: GSL_EDOM\n */\nint gsl_sf_lnbeta_e(const double a, const double b, gsl_sf_result * result);\ndouble gsl_sf_lnbeta(const double a, const double b);\n\nint gsl_sf_lnbeta_sgn_e(const double x, const double y, gsl_sf_result * result, double * sgn);\n\n\n/* Beta Function\n * B(a,b)\n *\n * a > 0, b > 0\n * exceptions: GSL_EDOM, GSL_EOVRFLW, GSL_EUNDRFLW\n */\nint gsl_sf_beta_e(const double a, const double b, gsl_sf_result * result);\ndouble gsl_sf_beta(const double a, const double b);\n\n\n/* Normalized Incomplete Beta Function\n * B_x(a,b)/B(a,b)\n *\n * a > 0, b > 0, 0 <= x <= 1\n * exceptions: GSL_EDOM, GSL_EUNDRFLW\n */\nint gsl_sf_beta_inc_e(const double a, const double b, const double x, gsl_sf_result * result);\ndouble gsl_sf_beta_inc(const double a, const double b, const double x);\n\n\n/* The maximum x such that gamma(x) is not\n * considered an overflow.\n */\n#define GSL_SF_GAMMA_XMAX  171.0\n\n/* The maximum n such that gsl_sf_fact(n) does not give an overflow. */\n#define GSL_SF_FACT_NMAX 170\n\n/* The maximum n such that gsl_sf_doublefact(n) does not give an overflow. */\n#define GSL_SF_DOUBLEFACT_NMAX 297\n\n__END_DECLS\n\n#endif /* __GSL_SF_GAMMA_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_log.h",
    "content": "/* specfunc/gsl_sf_log.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_LOG_H__\n#define __GSL_SF_LOG_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Provide a logarithm function with GSL semantics.\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_log_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_log(const double x);\n\n\n/* Log(|x|)\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_log_abs_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_log_abs(const double x);\n\n\n/* Complex Logarithm\n *   exp(lnr + I theta) = zr + I zi\n * Returns argument in [-pi,pi].\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_complex_log_e(const double zr, const double zi, gsl_sf_result * lnr, gsl_sf_result * theta);\n\n\n/* Log(1 + x)\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_log_1plusx_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_log_1plusx(const double x);\n\n\n/* Log(1 + x) - x\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_log_1plusx_mx_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_log_1plusx_mx(const double x);\n\n__END_DECLS\n\n#endif /* __GSL_SF_LOG_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_pow_int.h",
    "content": "/* specfunc/gsl_sf_pow_int.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_POW_INT_H__\n#define __GSL_SF_POW_INT_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Calculate x^n.\n * Does not check for overflow/underflow.\n */\nint     gsl_sf_pow_int_e(double x, int n, gsl_sf_result * result);\ndouble  gsl_sf_pow_int(const double x, const int n);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_POW_INT_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_psi.h",
    "content": "/* specfunc/gsl_sf_psi.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_PSI_H__\n#define __GSL_SF_PSI_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Poly-Gamma Functions\n *\n * psi(m,x) := (d/dx)^m psi(0,x) = (d/dx)^{m+1} log(gamma(x))\n */\n\n\n/* Di-Gamma Function  psi(n) = psi(0,n)\n *\n * n > 0\n * exceptions: GSL_EDOM\n */\nint     gsl_sf_psi_int_e(const int n, gsl_sf_result * result);\ndouble  gsl_sf_psi_int(const int n);\n\n\n/* Di-Gamma Function psi(x) = psi(0, x)\n *\n * x != 0.0, -1.0, -2.0, ...\n * exceptions: GSL_EDOM, GSL_ELOSS\n */\nint     gsl_sf_psi_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_psi(const double x);\n\n\n/* Di-Gamma Function Re[psi(1 + I y)]\n *\n * exceptions: none\n */\nint     gsl_sf_psi_1piy_e(const double y, gsl_sf_result * result);\ndouble  gsl_sf_psi_1piy(const double y);\n\n\n/* Di-Gamma Function psi(z) for general complex argument z = x + iy\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_complex_psi_e(\n  const double x,\n  const double y,\n  gsl_sf_result * result_re,\n  gsl_sf_result * result_im\n  );\n\n\n/* Tri-Gamma Function psi^(1)(n)\n *\n * n > 0\n * exceptions: GSL_EDOM\n */\nint     gsl_sf_psi_1_int_e(const int n, gsl_sf_result * result);\ndouble  gsl_sf_psi_1_int(const int n);\n\n\n/* Tri-Gamma Function psi^(1)(x)\n *\n * x != 0.0, -1.0, -2.0, ...\n * exceptions: GSL_EDOM, GSL_ELOSS\n */\nint     gsl_sf_psi_1_e(const double x, gsl_sf_result * result);\ndouble  gsl_sf_psi_1(const double x);\n\n\n/* Poly-Gamma Function psi^(n)(x)\n *\n * n >= 0, x > 0.0\n * exceptions: GSL_EDOM\n */\nint     gsl_sf_psi_n_e(const int n, const double x, gsl_sf_result * result);\ndouble  gsl_sf_psi_n(const int n, const double x);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_PSI_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_result.h",
    "content": "/* specfunc/gsl_sf_result.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_RESULT_H__\n#define __GSL_SF_RESULT_H__\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\nstruct gsl_sf_result_struct {\n  double val;\n  double err;\n};\ntypedef struct gsl_sf_result_struct gsl_sf_result;\n\n#define GSL_SF_RESULT_SET(r,v,e) do { (r)->val=(v); (r)->err=(e); } while(0)\n\n\nstruct gsl_sf_result_e10_struct {\n  double val;\n  double err;\n  int    e10;\n};\ntypedef struct gsl_sf_result_e10_struct gsl_sf_result_e10;\n\n\nint gsl_sf_result_smash_e(const gsl_sf_result_e10 * re, gsl_sf_result * r);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_RESULT_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_trig.h",
    "content": "/* specfunc/gsl_sf_trig.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_TRIG_H__\n#define __GSL_SF_TRIG_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Sin(x) with GSL semantics. This is actually important\n * because we want to control the error estimate, and trying\n * to guess the error for the standard library implementation\n * every time it is used would be a little goofy.\n */\nint gsl_sf_sin_e(double x, gsl_sf_result * result);\ndouble gsl_sf_sin(const double x);\n\n\n/* Cos(x) with GSL semantics.\n */\nint gsl_sf_cos_e(double x, gsl_sf_result * result);\ndouble gsl_sf_cos(const double x);\n\n\n/* Hypot(x,y) with GSL semantics.\n */\nint gsl_sf_hypot_e(const double x, const double y, gsl_sf_result * result);\ndouble gsl_sf_hypot(const double x, const double y);\n\n\n/* Sin(z) for complex z\n *\n * exceptions: GSL_EOVRFLW\n */\nint gsl_sf_complex_sin_e(const double zr, const double zi, gsl_sf_result * szr, gsl_sf_result * szi);\n\n\n/* Cos(z) for complex z\n *\n * exceptions: GSL_EOVRFLW\n */\nint gsl_sf_complex_cos_e(const double zr, const double zi, gsl_sf_result * czr, gsl_sf_result * czi);\n\n\n/* Log(Sin(z)) for complex z\n *\n * exceptions: GSL_EDOM, GSL_ELOSS\n */\nint gsl_sf_complex_logsin_e(const double zr, const double zi, gsl_sf_result * lszr, gsl_sf_result * lszi);\n\n\n/* Sinc(x) = sin(pi x) / (pi x)\n *\n * exceptions: none\n */\nint gsl_sf_sinc_e(double x, gsl_sf_result * result);\ndouble gsl_sf_sinc(const double x);\n\n\n/* Log(Sinh(x)), x > 0\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_lnsinh_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_lnsinh(const double x);\n\n\n/* Log(Cosh(x))\n *\n * exceptions: none\n */\nint gsl_sf_lncosh_e(const double x, gsl_sf_result * result);\ndouble gsl_sf_lncosh(const double x);\n\n\n/* Convert polar to rectlinear coordinates.\n *\n * exceptions: GSL_ELOSS\n */\nint gsl_sf_polar_to_rect(const double r, const double theta, gsl_sf_result * x, gsl_sf_result * y);\n\n/* Convert rectilinear to polar coordinates.\n * return argument in range [-pi, pi]\n *\n * exceptions: GSL_EDOM\n */\nint gsl_sf_rect_to_polar(const double x, const double y, gsl_sf_result * r, gsl_sf_result * theta);\n\n/* Sin(x) for quantity with an associated error.\n */\nint gsl_sf_sin_err_e(const double x, const double dx, gsl_sf_result * result);\n\n\n/* Cos(x) for quantity with an associated error.\n */\nint gsl_sf_cos_err_e(const double x, const double dx, gsl_sf_result * result);\n\n\n/* Force an angle to lie in the range (-pi,pi].\n *\n * exceptions: GSL_ELOSS\n */\nint gsl_sf_angle_restrict_symm_e(double * theta);\ndouble gsl_sf_angle_restrict_symm(const double theta);\n\n\n/* Force an angle to lie in the range [0, 2pi)\n *\n * exceptions: GSL_ELOSS\n */\nint gsl_sf_angle_restrict_pos_e(double * theta);\ndouble gsl_sf_angle_restrict_pos(const double theta);\n\n\nint gsl_sf_angle_restrict_symm_err_e(const double theta, gsl_sf_result * result);\n\nint gsl_sf_angle_restrict_pos_err_e(const double theta, gsl_sf_result * result);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_TRIG_H__ */\n"
  },
  {
    "path": "gsl/specfunc/gsl_sf_zeta.h",
    "content": "/* specfunc/gsl_sf_zeta.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#ifndef __GSL_SF_ZETA_H__\n#define __GSL_SF_ZETA_H__\n\n#include \"gsl_sf_result.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\n\n/* Riemann Zeta Function\n * zeta(n) = Sum[ k^(-n), {k,1,Infinity} ]\n *\n * n=integer, n != 1\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_zeta_int_e(const int n, gsl_sf_result * result);\ndouble gsl_sf_zeta_int(const int n);\n\n\n/* Riemann Zeta Function\n * zeta(x) = Sum[ k^(-s), {k,1,Infinity} ], s != 1.0\n *\n * s != 1.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_zeta_e(const double s, gsl_sf_result * result);\ndouble gsl_sf_zeta(const double s);\n\n\n/* Riemann Zeta Function minus 1\n *   useful for evaluating the fractional part\n *   of Riemann zeta for large argument\n *\n * s != 1.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_zetam1_e(const double s, gsl_sf_result * result);\ndouble gsl_sf_zetam1(const double s);\n\n\n/* Riemann Zeta Function minus 1 for integer arg\n *   useful for evaluating the fractional part\n *   of Riemann zeta for large argument\n *\n * s != 1.0\n * exceptions: GSL_EDOM, GSL_EOVRFLW\n */\nint gsl_sf_zetam1_int_e(const int s, gsl_sf_result * result);\ndouble gsl_sf_zetam1_int(const int s);\n\n\n/* Hurwitz Zeta Function\n * zeta(s,q) = Sum[ (k+q)^(-s), {k,0,Infinity} ]\n *\n * s > 1.0, q > 0.0\n * exceptions: GSL_EDOM, GSL_EUNDRFLW, GSL_EOVRFLW\n */\nint gsl_sf_hzeta_e(const double s, const double q, gsl_sf_result * result);\ndouble gsl_sf_hzeta(const double s, const double q);\n\n\n/* Eta Function\n * eta(n) = (1-2^(1-n)) zeta(n)\n *\n * exceptions: GSL_EUNDRFLW, GSL_EOVRFLW\n */\nint gsl_sf_eta_int_e(int n, gsl_sf_result * result);\ndouble gsl_sf_eta_int(const int n);\n\n\n/* Eta Function\n * eta(s) = (1-2^(1-s)) zeta(s)\n *\n * exceptions: GSL_EUNDRFLW, GSL_EOVRFLW\n */\nint gsl_sf_eta_e(const double s, gsl_sf_result * result);\ndouble gsl_sf_eta(const double s);\n\n\n__END_DECLS\n\n#endif /* __GSL_SF_ZETA_H__ */\n"
  },
  {
    "path": "gsl/specfunc/log.c",
    "content": "/* specfunc/log.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_log.h\"\n\n#include \"error.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/\n\n/* Chebyshev expansion for log(1 + x(t))/x(t)\n *\n * x(t) = (4t-1)/(2(4-t))\n * t(x) = (8x+1)/(2(x+2))\n * -1/2 < x < 1/2\n * -1 < t < 1\n */\nstatic double lopx_data[21] = {\n  2.16647910664395270521272590407,\n -0.28565398551049742084877469679,\n  0.01517767255690553732382488171,\n -0.00200215904941415466274422081,\n  0.00019211375164056698287947962,\n -0.00002553258886105542567601400,\n  2.9004512660400621301999384544e-06,\n -3.8873813517057343800270917900e-07,\n  4.7743678729400456026672697926e-08,\n -6.4501969776090319441714445454e-09,\n  8.2751976628812389601561347296e-10,\n -1.1260499376492049411710290413e-10,\n  1.4844576692270934446023686322e-11,\n -2.0328515972462118942821556033e-12,\n  2.7291231220549214896095654769e-13,\n -3.7581977830387938294437434651e-14,\n  5.1107345870861673561462339876e-15,\n -7.0722150011433276578323272272e-16,\n  9.7089758328248469219003866867e-17,\n -1.3492637457521938883731579510e-17,\n  1.8657327910677296608121390705e-18\n};\nstatic cheb_series lopx_cs = {\n  lopx_data,\n  20,\n  -1, 1,\n  10\n};\n\n/* Chebyshev expansion for (log(1 + x(t)) - x(t))/x(t)^2\n *\n * x(t) = (4t-1)/(2(4-t))\n * t(x) = (8x+1)/(2(x+2))\n * -1/2 < x < 1/2\n * -1 < t < 1\n */\nstatic double lopxmx_data[20] = {\n -1.12100231323744103373737274541,\n  0.19553462773379386241549597019,\n -0.01467470453808083971825344956,\n  0.00166678250474365477643629067,\n -0.00018543356147700369785746902,\n  0.00002280154021771635036301071,\n -2.8031253116633521699214134172e-06,\n  3.5936568872522162983669541401e-07,\n -4.6241857041062060284381167925e-08,\n  6.0822637459403991012451054971e-09,\n -8.0339824424815790302621320732e-10,\n  1.0751718277499375044851551587e-10,\n -1.4445310914224613448759230882e-11,\n  1.9573912180610336168921438426e-12,\n -2.6614436796793061741564104510e-13,\n  3.6402634315269586532158344584e-14,\n -4.9937495922755006545809120531e-15,\n  6.8802890218846809524646902703e-16,\n -9.5034129794804273611403251480e-17,\n  1.3170135013050997157326965813e-17\n};\nstatic cheb_series lopxmx_cs = {\n  lopxmx_data,\n  19,\n  -1, 1,\n  9\n};\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\nint\ngsl_sf_log_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x <= 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else {\n    result->val = log(x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint\ngsl_sf_log_abs_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x == 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else {\n    result->val = log(fabs(x));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\nint\ngsl_sf_complex_log_e(const double zr, const double zi, gsl_sf_result * lnr, gsl_sf_result * theta)\n{\n  /* CHECK_POINTER(lnr) */\n  /* CHECK_POINTER(theta) */\n\n  if(zr != 0.0 || zi != 0.0) {\n    const double ax = fabs(zr);\n    const double ay = fabs(zi);\n    const double min = GSL_MIN(ax, ay);\n    const double max = GSL_MAX(ax, ay);\n    lnr->val = log(max) + 0.5 * log(1.0 + (min/max)*(min/max));\n    lnr->err = 2.0 * GSL_DBL_EPSILON * fabs(lnr->val);\n    theta->val = atan2(zi, zr);\n    theta->err = GSL_DBL_EPSILON * fabs(lnr->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    DOMAIN_ERROR_2(lnr, theta);\n  }\n}\n\n\nint\ngsl_sf_log_1plusx_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x <= -1.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(fabs(x) < GSL_ROOT6_DBL_EPSILON) {\n    const double c1 = -0.5;\n    const double c2 =  1.0/3.0;\n    const double c3 = -1.0/4.0;\n    const double c4 =  1.0/5.0;\n    const double c5 = -1.0/6.0;\n    const double c6 =  1.0/7.0;\n    const double c7 = -1.0/8.0;\n    const double c8 =  1.0/9.0;\n    const double c9 = -1.0/10.0;\n    const double t  =  c5 + x*(c6 + x*(c7 + x*(c8 + x*c9)));\n    result->val = x * (1.0 + x*(c1 + x*(c2 + x*(c3 + x*(c4 + x*t)))));\n    result->err = GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(fabs(x) < 0.5) {\n    double t = 0.5*(8.0*x + 1.0)/(x+2.0);\n    gsl_sf_result c;\n    cheb_eval_e(&lopx_cs, t, &c);\n    result->val = x * c.val;\n    result->err = fabs(x * c.err);\n    return GSL_SUCCESS;\n  }\n  else {\n    result->val = log(1.0 + x);\n    result->err = GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint\ngsl_sf_log_1plusx_mx_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x <= -1.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(fabs(x) < GSL_ROOT5_DBL_EPSILON) {\n    const double c1 = -0.5;\n    const double c2 =  1.0/3.0;\n    const double c3 = -1.0/4.0;\n    const double c4 =  1.0/5.0;\n    const double c5 = -1.0/6.0;\n    const double c6 =  1.0/7.0;\n    const double c7 = -1.0/8.0;\n    const double c8 =  1.0/9.0;\n    const double c9 = -1.0/10.0;\n    const double t  =  c5 + x*(c6 + x*(c7 + x*(c8 + x*c9)));\n    result->val = x*x * (c1 + x*(c2 + x*(c3 + x*(c4 + x*t))));\n    result->err = GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(fabs(x) < 0.5) {\n    double t = 0.5*(8.0*x + 1.0)/(x+2.0);\n    gsl_sf_result c;\n    cheb_eval_e(&lopxmx_cs, t, &c);\n    result->val = x*x * c.val;\n    result->err = x*x * c.err;\n    return GSL_SUCCESS;\n  }\n  else {\n    const double lterm = log(1.0 + x);\n    result->val = lterm - x;\n    result->err = GSL_DBL_EPSILON * (fabs(lterm) + fabs(x));\n    return GSL_SUCCESS;\n  }\n}\n\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_log(const double x)\n{\n  EVAL_RESULT(gsl_sf_log_e(x, &result));\n}\n\ndouble gsl_sf_log_abs(const double x)\n{\n  EVAL_RESULT(gsl_sf_log_abs_e(x, &result));\n}\n\ndouble gsl_sf_log_1plusx(const double x)\n{\n  EVAL_RESULT(gsl_sf_log_1plusx_e(x, &result));\n}\n\ndouble gsl_sf_log_1plusx_mx(const double x)\n{\n  EVAL_RESULT(gsl_sf_log_1plusx_mx_e(x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/pow_int.c",
    "content": "/* specfunc/pow_int.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_pow_int.h\"\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions w/ Error handling *-*-*-*-*-*-*-*-*-*-*-*/\n\nint gsl_sf_pow_int_e(double x, int n, gsl_sf_result * result)\n{\n  double value = 1.0;\n  int count = 0;\n\n  /* CHECK_POINTER(result) */\n\n\n  if(n < 0) {\n    n = -n;\n\n    if(x == 0.0) {\n      double u = 1.0 / x;\n      result->val = (n % 2) ? u : (u * u) ;  /* correct sign of infinity */\n      result->err = GSL_POSINF;\n      GSL_ERROR (\"overflow\", GSL_EOVRFLW);\n    }\n\n    x = 1.0/x;\n  }\n\n  /* repeated squaring method \n   * returns 0.0^0 = 1.0, so continuous in x\n   */\n  do {\n     if(GSL_IS_ODD(n)) value *= x;\n     n >>= 1;\n     x *= x;\n     ++count;\n  } while (n);\n\n  result->val = value;\n  result->err = 2.0 * GSL_DBL_EPSILON * (count + 1.0) * fabs(value); \n\n  return GSL_SUCCESS;\n}\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_pow_int(const double x, const int n)\n{\n  EVAL_RESULT(gsl_sf_pow_int_e(x, n, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/psi.c",
    "content": "/* specfunc/psi.c\n * \n * Copyright (C) 2007 Brian Gough\n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004, 2005, 2006 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author: G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_sf_zeta.h\"\n#include \"gsl_sf_psi.h\"\n#include \"gsl_complex_math.h\"\n\n#include <stdio.h>\n\n#include \"error.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/\n\n\n/* Chebyshev fit for f(y) = Re(Psi(1+Iy)) + M_EULER - y^2/(1+y^2) - y^2/(2(4+y^2))\n * 1 < y < 10\n *   ==>\n * y(x) = (9x + 11)/2,  -1 < x < 1\n * x(y) = (2y - 11)/9\n *\n * g(x) := f(y(x))\n */\nstatic double r1py_data[] = {\n   1.59888328244976954803168395603,\n   0.67905625353213463845115658455,\n  -0.068485802980122530009506482524,\n  -0.005788184183095866792008831182,\n   0.008511258167108615980419855648,\n  -0.004042656134699693434334556409,\n   0.001352328406159402601778462956,\n  -0.000311646563930660566674525382,\n   0.000018507563785249135437219139,\n   0.000028348705427529850296492146,\n  -0.000019487536014574535567541960,\n   8.0709788710834469408621587335e-06,\n  -2.2983564321340518037060346561e-06,\n   3.0506629599604749843855962658e-07,\n   1.3042238632418364610774284846e-07,\n  -1.2308657181048950589464690208e-07,\n   5.7710855710682427240667414345e-08,\n  -1.8275559342450963966092636354e-08,\n   3.1020471300626589420759518930e-09,\n   6.8989327480593812470039430640e-10,\n  -8.7182290258923059852334818997e-10,\n   4.4069147710243611798213548777e-10,\n  -1.4727311099198535963467200277e-10,\n   2.7589682523262644748825844248e-11,\n   4.1871826756975856411554363568e-12,\n  -6.5673460487260087541400767340e-12,\n   3.4487900886723214020103638000e-12,\n  -1.1807251417448690607973794078e-12,\n   2.3798314343969589258709315574e-13,\n   2.1663630410818831824259465821e-15\n};\nstatic cheb_series r1py_cs = {\n  r1py_data,\n  29,\n  -1,1,\n  18\n};\n\n\n/* Chebyshev fits from SLATEC code for psi(x)\n\n Series for PSI        on the interval  0.         to  1.00000D+00\n                                       with weighted error   2.03E-17\n                                        log weighted error  16.69\n                              significant figures required  16.39\n                                   decimal places required  17.37\n\n Series for APSI       on the interval  0.         to  2.50000D-01\n                                       with weighted error   5.54E-17\n                                        log weighted error  16.26\n                              significant figures required  14.42\n                                   decimal places required  16.86\n\n*/\n\nstatic double psics_data[23] = {\n  -.038057080835217922,\n   .491415393029387130, \n  -.056815747821244730,\n   .008357821225914313,\n  -.001333232857994342,\n   .000220313287069308,\n  -.000037040238178456,\n   .000006283793654854,\n  -.000001071263908506,\n   .000000183128394654,\n  -.000000031353509361,\n   .000000005372808776,\n  -.000000000921168141,\n   .000000000157981265,\n  -.000000000027098646,\n   .000000000004648722,\n  -.000000000000797527,\n   .000000000000136827,\n  -.000000000000023475,\n   .000000000000004027,\n  -.000000000000000691,\n   .000000000000000118,\n  -.000000000000000020\n};\nstatic cheb_series psi_cs = {\n  psics_data,\n  22,\n  -1, 1,\n  17\n};\n\nstatic double apsics_data[16] = {    \n  -.0204749044678185,\n  -.0101801271534859,\n   .0000559718725387,\n  -.0000012917176570,\n   .0000000572858606,\n  -.0000000038213539,\n   .0000000003397434,\n  -.0000000000374838,\n   .0000000000048990,\n  -.0000000000007344,\n   .0000000000001233,\n  -.0000000000000228,\n   .0000000000000045,\n  -.0000000000000009,\n   .0000000000000002,\n  -.0000000000000000 \n};    \nstatic cheb_series apsi_cs = {\n  apsics_data,\n  15,\n  -1, 1,\n  9\n};\n\n#define PSI_TABLE_NMAX 100\nstatic double psi_table[PSI_TABLE_NMAX+1] = {\n  0.0,  /* Infinity */              /* psi(0) */\n -M_EULER,                          /* psi(1) */\n  0.42278433509846713939348790992,  /* ...    */\n  0.92278433509846713939348790992,\n  1.25611766843180047272682124325,\n  1.50611766843180047272682124325,\n  1.70611766843180047272682124325,\n  1.87278433509846713939348790992,\n  2.01564147795560999653634505277,\n  2.14064147795560999653634505277,\n  2.25175258906672110764745616389,\n  2.35175258906672110764745616389,\n  2.44266167997581201673836525479,\n  2.52599501330914535007169858813,\n  2.60291809023222227314862166505,\n  2.67434666166079370172005023648,\n  2.74101332832746036838671690315,\n  2.80351332832746036838671690315,\n  2.86233685773922507426906984432,\n  2.91789241329478062982462539988,\n  2.97052399224214905087725697883,\n  3.02052399224214905087725697883,\n  3.06814303986119666992487602645,\n  3.11359758531574212447033057190,\n  3.15707584618530734186163491973,\n  3.1987425128519740085283015864,\n  3.2387425128519740085283015864,\n  3.2772040513135124700667631249,\n  3.3142410883505495071038001619,\n  3.3499553740648352213895144476,\n  3.3844381326855248765619282407,\n  3.4177714660188582098952615740,\n  3.4500295305349872421533260902,\n  3.4812795305349872421533260902,\n  3.5115825608380175451836291205,\n  3.5409943255438998981248055911,\n  3.5695657541153284695533770196,\n  3.5973435318931062473311547974,\n  3.6243705589201332743581818244,\n  3.6506863483938174848844976139,\n  3.6763273740348431259101386396,\n  3.7013273740348431259101386396,\n  3.7257176179372821503003825420,\n  3.7495271417468059598241920658,\n  3.7727829557002943319172153216,\n  3.7955102284275670591899425943,\n  3.8177324506497892814121648166,\n  3.8394715810845718901078169905,\n  3.8607481768292527411716467777,\n  3.8815815101625860745049801110,\n  3.9019896734278921969539597029,\n  3.9219896734278921969539597029,\n  3.9415975165651470989147440166,\n  3.9608282857959163296839747858,\n  3.9796962103242182164764276160,\n  3.9982147288427367349949461345,\n  4.0163965470245549168131279527,\n  4.0342536898816977739559850956,\n  4.0517975495308205809735289552,\n  4.0690389288411654085597358518,\n  4.0859880813835382899156680552,\n  4.1026547480502049565823347218,\n  4.1190481906731557762544658694,\n  4.1351772229312202923834981274,\n  4.1510502388042361653993711433,\n  4.1666752388042361653993711433,\n  4.1820598541888515500147557587,\n  4.1972113693403667015299072739,\n  4.2121367424746950597388624977,\n  4.2268426248276362362094507330,\n  4.2413353784508246420065521823,\n  4.2556210927365389277208378966,\n  4.2697055997787924488475984600,\n  4.2835944886676813377364873489,\n  4.2972931188046676391063503626,\n  4.3108066323181811526198638761,\n  4.3241399656515144859531972094,\n  4.3372978603883565912163551041,\n  4.3502848733753695782293421171,\n  4.3631053861958823987421626300,\n  4.3757636140439836645649474401,\n  4.3882636140439836645649474401,\n  4.4006092930563293435772931191,\n  4.4128044150075488557724150703,\n  4.4248526077786331931218126607,\n  4.4367573696833950978837174226,\n  4.4485220755657480390601880108,\n  4.4601499825424922251066996387,\n  4.4716442354160554434975042364,\n  4.4830078717796918071338678728,\n  4.4942438268358715824147667492,\n  4.5053549379469826935258778603,\n  4.5163439489359936825368668713,\n  4.5272135141533849868846929582,\n  4.5379662023254279976373811303,\n  4.5486045001977684231692960239,\n  4.5591308159872421073798223397,\n  4.5695474826539087740464890064,\n  4.5798567610044242379640147796,\n  4.5900608426370772991885045755,\n  4.6001618527380874001986055856\n};\n\n\n#define PSI_1_TABLE_NMAX 100\nstatic double psi_1_table[PSI_1_TABLE_NMAX+1] = {\n  0.0,  /* Infinity */              /* psi(1,0) */\n  M_PI*M_PI/6.0,                    /* psi(1,1) */\n  0.644934066848226436472415,       /* ...      */\n  0.394934066848226436472415,\n  0.2838229557371153253613041,\n  0.2213229557371153253613041,\n  0.1813229557371153253613041,\n  0.1535451779593375475835263,\n  0.1331370146940314251345467,\n  0.1175120146940314251345467,\n  0.1051663356816857461222010,\n  0.0951663356816857461222010,\n  0.0869018728717683907503002,\n  0.0799574284273239463058557,\n  0.0740402686640103368384001,\n  0.0689382278476838062261552,\n  0.0644937834032393617817108,\n  0.0605875334032393617817108,\n  0.0571273257907826143768665,\n  0.0540409060376961946237801,\n  0.0512708229352031198315363,\n  0.0487708229352031198315363,\n  0.0465032492390579951149830,\n  0.0444371335365786562720078,\n  0.0425467743683366902984728,\n  0.0408106632572255791873617,\n  0.0392106632572255791873617,\n  0.0377313733163971768204978,\n  0.0363596312039143235969038,\n  0.0350841209998326909438426,\n  0.0338950603577399442137594,\n  0.0327839492466288331026483,\n  0.0317433665203020901265817,\n  0.03076680402030209012658168,\n  0.02984853037475571730748159,\n  0.02898347847164153045627052,\n  0.02816715194102928555831133,\n  0.02739554700275768062003973,\n  0.02666508681283803124093089,\n  0.02597256603721476254286995,\n  0.02531510384129102815759710,\n  0.02469010384129102815759710,\n  0.02409521984367056414807896,\n  0.02352832641963428296894063,\n  0.02298749353699501850166102,\n  0.02247096461137518379091722,\n  0.02197713745088135663042339,\n  0.02150454765882086513703965,\n  0.02105185413233829383780923,\n  0.02061782635456051606003145,\n  0.02020133322669712580597065,\n  0.01980133322669712580597065,\n  0.01941686571420193164987683,\n  0.01904704322899483105816086,\n  0.01869104465298913508094477,\n  0.01834810912486842177504628,\n  0.01801753061247172756017024,\n  0.01769865306145131939690494,\n  0.01739086605006319997554452,\n  0.01709360088954001329302371,\n  0.01680632711763538818529605,\n  0.01652854933985761040751827,\n  0.01625980437882562975715546,\n  0.01599965869724394401313881,\n  0.01574770606433893015574400,\n  0.01550356543933893015574400,\n  0.01526687904880638577704578,\n  0.01503731063741979257227076,\n  0.01481454387422086185273411,\n  0.01459828089844231513993134,\n  0.01438824099085987447620523,\n  0.01418415935820681325171544,\n  0.01398578601958352422176106,\n  0.01379288478501562298719316,\n  0.01360523231738567365335942,\n  0.01342261726990576130858221,\n  0.01324483949212798353080444,\n  0.01307170929822216635628920,\n  0.01290304679189732236910755,\n  0.01273868124291638877278934,\n  0.01257845051066194236996928,\n  0.01242220051066194236996928,\n  0.01226978472038606978956995,\n  0.01212106372098095378719041,\n  0.01197590477193174490346273,\n  0.01183418141592267460867815,\n  0.01169577311142440471248438,\n  0.01156056489076458859566448,\n  0.01142844704164317229232189,\n  0.01129931481023821361463594,\n  0.01117306812421372175754719,\n  0.01104961133409026496742374,\n  0.01092885297157366069257770,\n  0.01081070552355853781923177,\n  0.01069508522063334415522437,\n  0.01058191183901270133041676,\n  0.01047110851491297833872701,\n  0.01036260157046853389428257,\n  0.01025632035036012704977199,  /* ...        */\n  0.01015219706839427948625679,  /* psi(1,99)  */\n  0.01005016666333357139524567   /* psi(1,100) */\n};\n\n\n/* digamma for x both positive and negative; we do both\n * cases here because of the way we use even/odd parts\n * of the function\n */\nstatic int\npsi_x(const double x, gsl_sf_result * result)\n{\n  const double y = fabs(x);\n\n  if(x == 0.0 || x == -1.0 || x == -2.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(y >= 2.0) {\n    const double t = 8.0/(y*y)-1.0;\n    gsl_sf_result result_c;\n    cheb_eval_e(&apsi_cs, t, &result_c);\n    if(x < 0.0) {\n      const double s = sin(M_PI*x);\n      const double c = cos(M_PI*x);\n      if(fabs(s) < 2.0*GSL_SQRT_DBL_MIN) {\n        DOMAIN_ERROR(result);\n      }\n      else {\n        result->val  = log(y) - 0.5/x + result_c.val - M_PI * c/s;\n        result->err  = M_PI*fabs(x)*GSL_DBL_EPSILON/(s*s);\n        result->err += result_c.err;\n        result->err += GSL_DBL_EPSILON * fabs(result->val);\n        return GSL_SUCCESS;\n      }\n    }\n    else {\n      result->val  = log(y) - 0.5/x + result_c.val;\n      result->err  = result_c.err;\n      result->err += GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n  }\n  else { /* -2 < x < 2 */\n    gsl_sf_result result_c;\n\n    if(x < -1.0) { /* x = -2 + v */\n      const double v  = x + 2.0;\n      const double t1 = 1.0/x;\n      const double t2 = 1.0/(x+1.0);\n      const double t3 = 1.0/v;\n      cheb_eval_e(&psi_cs, 2.0*v-1.0, &result_c);\n      \n      result->val  = -(t1 + t2 + t3) + result_c.val;\n      result->err  = GSL_DBL_EPSILON * (fabs(t1) + fabs(x/(t2*t2)) + fabs(x/(t3*t3)));\n      result->err += result_c.err;\n      result->err += GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else if(x < 0.0) { /* x = -1 + v */\n      const double v  = x + 1.0;\n      const double t1 = 1.0/x;\n      const double t2 = 1.0/v;\n      cheb_eval_e(&psi_cs, 2.0*v-1.0, &result_c);\n      \n      result->val  = -(t1 + t2) + result_c.val;\n      result->err  = GSL_DBL_EPSILON * (fabs(t1) + fabs(x/(t2*t2)));\n      result->err += result_c.err;\n      result->err += GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else if(x < 1.0) { /* x = v */\n      const double t1 = 1.0/x;\n      cheb_eval_e(&psi_cs, 2.0*x-1.0, &result_c);\n      \n      result->val  = -t1 + result_c.val;\n      result->err  = GSL_DBL_EPSILON * t1;\n      result->err += result_c.err;\n      result->err += GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else { /* x = 1 + v */\n      const double v = x - 1.0;\n      return cheb_eval_e(&psi_cs, 2.0*v-1.0, result);\n    }\n  }\n}\n\n\n/* psi(z) for large |z| in the right half-plane; [Abramowitz + Stegun, 6.3.18] */\nstatic\ngsl_complex\npsi_complex_asymp(gsl_complex z)\n{\n  /* coefficients in the asymptotic expansion for large z;\n   * let w = z^(-2) and write the expression in the form\n   *\n   *   ln(z) - 1/(2z) - 1/12 w (1 + c1 w + c2 w + c3 w + ... )\n   */\n  static const double c1 = -0.1;\n  static const double c2 =  1.0/21.0;\n  static const double c3 = -0.05;\n\n  gsl_complex zi = gsl_complex_inverse(z);\n  gsl_complex w  = gsl_complex_mul(zi, zi);\n  gsl_complex cs;\n\n  /* Horner method evaluation of term in parentheses */\n  gsl_complex sum;\n  sum = gsl_complex_mul_real(w, c3/c2);\n  sum = gsl_complex_add_real(sum, 1.0);\n  sum = gsl_complex_mul_real(sum, c2/c1);\n  sum = gsl_complex_mul(sum, w);\n  sum = gsl_complex_add_real(sum, 1.0);\n  sum = gsl_complex_mul_real(sum, c1);\n  sum = gsl_complex_mul(sum, w);\n  sum = gsl_complex_add_real(sum, 1.0);\n\n  /* correction added to log(z) */\n  cs = gsl_complex_mul(sum, w);\n  cs = gsl_complex_mul_real(cs, -1.0/12.0);\n  cs = gsl_complex_add(cs, gsl_complex_mul_real(zi, -0.5));\n\n  return gsl_complex_add(gsl_complex_log(z), cs);\n}\n\n\n\n/* psi(z) for complex z in the right half-plane */\nstatic int\npsi_complex_rhp(\n  gsl_complex z,\n  gsl_sf_result * result_re,\n  gsl_sf_result * result_im\n  )\n{\n  int n_recurse = 0;\n  int i;\n  gsl_complex a;\n\n  if(GSL_REAL(z) == 0.0 && GSL_IMAG(z) == 0.0)\n  {\n    result_re->val = 0.0;\n    result_im->val = 0.0;\n    result_re->err = 0.0;\n    result_im->err = 0.0;\n    return GSL_EDOM;\n  }\n\n  /* compute the number of recurrences to apply */\n  if(GSL_REAL(z) < 20.0 && fabs(GSL_IMAG(z)) < 20.0)\n  {\n    const double sp = sqrt(20.0 + GSL_IMAG(z));\n    const double sn = sqrt(20.0 - GSL_IMAG(z));\n    const double rhs = sp*sn - GSL_REAL(z);\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t  if(rhs > 0.0) n_recurse = ceil(rhs);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n  }\n\n  /* compute asymptotic at the large value z + n_recurse */\n  a = psi_complex_asymp(gsl_complex_add_real(z, n_recurse));\n\n  result_re->err = 2.0 * GSL_DBL_EPSILON * fabs(GSL_REAL(a));\n  result_im->err = 2.0 * GSL_DBL_EPSILON * fabs(GSL_IMAG(a));\n\n  /* descend recursively, if necessary */\n  for(i = n_recurse; i >= 1; --i)\n  {\n    gsl_complex zn = gsl_complex_add_real(z, i - 1.0);\n    gsl_complex zn_inverse = gsl_complex_inverse(zn);\n    a = gsl_complex_sub(a, zn_inverse);\n\n    /* accumulate the error, to catch cancellations */\n    result_re->err += 2.0 * GSL_DBL_EPSILON * fabs(GSL_REAL(zn_inverse));\n    result_im->err += 2.0 * GSL_DBL_EPSILON * fabs(GSL_IMAG(zn_inverse));\n  }\n\n  result_re->val = GSL_REAL(a);\n  result_im->val = GSL_IMAG(a);\n\n  result_re->err += 2.0 * GSL_DBL_EPSILON * fabs(result_re->val);\n  result_im->err += 2.0 * GSL_DBL_EPSILON * fabs(result_im->val);\n\n  return GSL_SUCCESS;\n}\n\n\n\n/* generic polygamma; assumes n >= 0 and x > 0\n */\nstatic int\npsi_n_xg0(const int n, const double x, gsl_sf_result * result)\n{\n  if(n == 0) {\n    return gsl_sf_psi_e(x, result);\n  }\n  else {\n    /* Abramowitz + Stegun 6.4.10 */\n    gsl_sf_result ln_nf;\n    gsl_sf_result hzeta;\n    int stat_hz = gsl_sf_hzeta_e(n+1.0, x, &hzeta);\n    int stat_nf = gsl_sf_lnfact_e((unsigned int) n, &ln_nf);\n    int stat_e  = gsl_sf_exp_mult_err_e(ln_nf.val, ln_nf.err,\n                                           hzeta.val, hzeta.err,\n                                           result);\n    if(GSL_IS_EVEN(n)) result->val = -result->val;\n    return GSL_ERROR_SELECT_3(stat_e, stat_nf, stat_hz);\n  }\n}\n\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\nint gsl_sf_psi_int_e(const int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n <= 0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(n <= PSI_TABLE_NMAX) {\n    result->val = psi_table[n];\n    result->err = GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    /* Abramowitz+Stegun 6.3.18 */\n    const double c2 = -1.0/12.0;\n    const double c3 =  1.0/120.0;\n    const double c4 = -1.0/252.0;\n    const double c5 =  1.0/240.0;\n    const double ni2 = (1.0/n)*(1.0/n);\n    const double ser = ni2 * (c2 + ni2 * (c3 + ni2 * (c4 + ni2*c5)));\n    result->val  = log(n) - 0.5/n + ser;\n    result->err  = GSL_DBL_EPSILON * (fabs(log(n)) + fabs(0.5/n) + fabs(ser));\n    result->err += GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_psi_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n  return psi_x(x, result);\n}\n\n\nint\ngsl_sf_psi_1piy_e(const double y, gsl_sf_result * result)\n{\n  const double ay = fabs(y);\n\n  /* CHECK_POINTER(result) */\n\n  if(ay > 1000.0) {\n    /* [Abramowitz+Stegun, 6.3.19] */\n    const double yi2 = 1.0/(ay*ay);\n    const double lny = log(ay);\n    const double sum = yi2 * (1.0/12.0 + 1.0/120.0 * yi2 + 1.0/252.0 * yi2*yi2);\n    result->val = lny + sum;\n    result->err = 2.0 * GSL_DBL_EPSILON * (fabs(lny) + fabs(sum));\n    return GSL_SUCCESS;\n  }\n  else if(ay > 10.0) {\n    /* [Abramowitz+Stegun, 6.3.19] */\n    const double yi2 = 1.0/(ay*ay);\n    const double lny = log(ay);\n    const double sum = yi2 * (1.0/12.0 +\n                         yi2 * (1.0/120.0 +\n                           yi2 * (1.0/252.0 +\n                             yi2 * (1.0/240.0 +\n                               yi2 * (1.0/132.0 + 691.0/32760.0 * yi2)))));\n    result->val = lny + sum;\n    result->err = 2.0 * GSL_DBL_EPSILON * (fabs(lny) + fabs(sum));\n    return GSL_SUCCESS;\n  }\n  else if(ay > 1.0){\n    const double y2 = ay*ay;\n    const double x  = (2.0*ay - 11.0)/9.0;\n    const double v  = y2*(1.0/(1.0+y2) + 0.5/(4.0+y2));\n    gsl_sf_result result_c;\n    cheb_eval_e(&r1py_cs, x, &result_c);\n    result->val  = result_c.val - M_EULER + v;\n    result->err  = result_c.err;\n    result->err += 2.0 * GSL_DBL_EPSILON * (fabs(v) + M_EULER + fabs(result_c.val));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    result->err *= 5.0; /* FIXME: losing a digit somewhere... maybe at x=... ? */\n    return GSL_SUCCESS;\n  }\n  else {\n    /* [Abramowitz+Stegun, 6.3.17]\n     *\n     * -M_EULER + y^2 Sum[1/n 1/(n^2 + y^2), {n,1,M}]\n     *   +     Sum[1/n^3, {n,M+1,Infinity}]\n     *   - y^2 Sum[1/n^5, {n,M+1,Infinity}]\n     *   + y^4 Sum[1/n^7, {n,M+1,Infinity}]\n     *   - y^6 Sum[1/n^9, {n,M+1,Infinity}]\n     *   + O(y^8)\n     *\n     * We take M=50 for at least 15 digit precision.\n     */\n    const int M = 50;\n    const double y2 = y*y;\n    const double c0 = 0.00019603999466879846570;\n    const double c2 = 3.8426659205114376860e-08;\n    const double c4 = 1.0041592839497643554e-11;\n    const double c6 = 2.9516743763500191289e-15;\n    const double p  = c0 + y2 *(-c2 + y2*(c4 - y2*c6));\n    double sum = 0.0;\n    double v;\n    \n    int n;\n    for(n=1; n<=M; n++) {\n      sum += 1.0/(n * (n*n + y*y));\n    }\n\n    v = y2 * (sum + p);\n    result->val  = -M_EULER + v;\n    result->err  = GSL_DBL_EPSILON * (M_EULER + fabs(v));\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_psi_1_int_e(const int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n  if(n <= 0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(n <= PSI_1_TABLE_NMAX) {\n    result->val = psi_1_table[n];\n    result->err = GSL_DBL_EPSILON * result->val;\n    return GSL_SUCCESS;\n  }\n  else {\n    /* Abramowitz+Stegun 6.4.12\n     * double-precision for n > 100\n     */\n    const double c0 = -1.0/30.0;\n    const double c1 =  1.0/42.0;\n    const double c2 = -1.0/30.0;\n    const double ni2 = (1.0/n)*(1.0/n);\n    const double ser =  ni2*ni2 * (c0 + ni2*(c1 + c2*ni2));\n    result->val = (1.0 + 0.5/n + 1.0/(6.0*n*n) + ser) / n;\n    result->err = GSL_DBL_EPSILON * result->val;\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_psi_1_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x == 0.0 || x == -1.0 || x == -2.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(x > 0.0)\n  {\n    return psi_n_xg0(1, x, result);\n  }\n  else if(x > -5.0)\n  {\n    /* Abramowitz + Stegun 6.4.6 */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t  int M = -floor(x);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n    double fx = x + M;\n    double sum = 0.0;\n    int m;\n\n    if(fx == 0.0)\n      DOMAIN_ERROR(result);\n\n    for(m = 0; m < M; ++m)\n      sum += 1.0/((x+m)*(x+m));\n\n    {\n      int stat_psi = psi_n_xg0(1, fx, result);\n      result->val += sum;\n      result->err += M * GSL_DBL_EPSILON * sum;\n      return stat_psi;\n    }\n  }\n  else\n  {\n    /* Abramowitz + Stegun 6.4.7 */\n    const double sin_px = sin(M_PI * x);\n    const double d = M_PI*M_PI/(sin_px*sin_px);\n    gsl_sf_result r;\n    int stat_psi = psi_n_xg0(1, 1.0-x, &r);\n    result->val = d - r.val;\n    result->err = r.err + 2.0*GSL_DBL_EPSILON*d;\n    return stat_psi;\n  }\n}\n\n\nint gsl_sf_psi_n_e(const int n, const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n == 0)\n  {\n    return gsl_sf_psi_e(x, result);\n  }\n  else if(n == 1)\n  {\n    return gsl_sf_psi_1_e(x, result);\n  }\n  else if(n < 0 || x <= 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else {\n    gsl_sf_result ln_nf;\n    gsl_sf_result hzeta;\n    int stat_hz = gsl_sf_hzeta_e(n+1.0, x, &hzeta);\n    int stat_nf = gsl_sf_lnfact_e((unsigned int) n, &ln_nf);\n    int stat_e  = gsl_sf_exp_mult_err_e(ln_nf.val, ln_nf.err,\n                                           hzeta.val, hzeta.err,\n                                           result);\n    if(GSL_IS_EVEN(n)) result->val = -result->val;\n    return GSL_ERROR_SELECT_3(stat_e, stat_nf, stat_hz);\n  }\n}\n\n\nint\ngsl_sf_complex_psi_e(\n  const double x,\n  const double y,\n  gsl_sf_result * result_re,\n  gsl_sf_result * result_im\n  )\n{\n  if(x >= 0.0)\n  {\n    gsl_complex z = gsl_complex_rect(x, y);\n    return psi_complex_rhp(z, result_re, result_im);\n  }\n  else\n  {\n    /* reflection formula [Abramowitz+Stegun, 6.3.7] */\n    gsl_complex z = gsl_complex_rect(x, y);\n    gsl_complex omz = gsl_complex_rect(1.0 - x, -y);\n    gsl_complex zpi = gsl_complex_mul_real(z, M_PI);\n    gsl_complex cotzpi = gsl_complex_cot(zpi);\n    int ret_val = psi_complex_rhp(omz, result_re, result_im);\n\n    if(GSL_IS_REAL(GSL_REAL(cotzpi)) && GSL_IS_REAL(GSL_IMAG(cotzpi)))\n    {\n      result_re->val -= M_PI * GSL_REAL(cotzpi);\n      result_im->val -= M_PI * GSL_IMAG(cotzpi);\n      return ret_val;\n    }\n    else\n    {\n      GSL_ERROR(\"singularity\", GSL_EDOM);\n    }\n  }\n}\n\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_psi_int(const int n)\n{\n  EVAL_RESULT(gsl_sf_psi_int_e(n, &result));\n}\n\ndouble gsl_sf_psi(const double x)\n{\n  EVAL_RESULT(gsl_sf_psi_e(x, &result));\n}\n\ndouble gsl_sf_psi_1piy(const double x)\n{\n  EVAL_RESULT(gsl_sf_psi_1piy_e(x, &result));\n}\n\ndouble gsl_sf_psi_1_int(const int n)\n{\n  EVAL_RESULT(gsl_sf_psi_1_int_e(n, &result));\n}\n\ndouble gsl_sf_psi_1(const double x)\n{\n  EVAL_RESULT(gsl_sf_psi_1_e(x, &result));\n}\n\ndouble gsl_sf_psi_n(const int n, const double x)\n{\n  EVAL_RESULT(gsl_sf_psi_n_e(n, x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/trig.c",
    "content": "/* specfunc/trig.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_log.h\"\n#include \"gsl_sf_trig.h\"\n\n#include \"error.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n/* sinh(x) series\n * double-precision for |x| < 1.0\n */\ninline\nstatic\nint\nsinh_series(const double x, double * result)\n{\n  const double y = x*x;\n  const double c0 = 1.0/6.0;\n  const double c1 = 1.0/120.0;\n  const double c2 = 1.0/5040.0;\n  const double c3 = 1.0/362880.0;\n  const double c4 = 1.0/39916800.0;\n  const double c5 = 1.0/6227020800.0;\n  const double c6 = 1.0/1307674368000.0;\n  const double c7 = 1.0/355687428096000.0;\n  *result = x*(1.0 + y*(c0+y*(c1+y*(c2+y*(c3+y*(c4+y*(c5+y*(c6+y*c7))))))));\n  return GSL_SUCCESS;\n}\n\n\n/* cosh(x)-1 series\n * double-precision for |x| < 1.0\n */\ninline\nstatic\nint\ncosh_m1_series(const double x, double * result)\n{\n  const double y = x*x;\n  const double c0 = 0.5;\n  const double c1 = 1.0/24.0;\n  const double c2 = 1.0/720.0;\n  const double c3 = 1.0/40320.0;\n  const double c4 = 1.0/3628800.0;\n  const double c5 = 1.0/479001600.0;\n  const double c6 = 1.0/87178291200.0;\n  const double c7 = 1.0/20922789888000.0;\n  const double c8 = 1.0/6402373705728000.0;\n  *result = y*(c0+y*(c1+y*(c2+y*(c3+y*(c4+y*(c5+y*(c6+y*(c7+y*c8))))))));\n  return GSL_SUCCESS;\n}\n\n\n/* Chebyshev expansion for f(t) = sinc((t+1)/2), -1 < t < 1\n */\nstatic double sinc_data[17] = {\n  1.133648177811747875422,\n -0.532677564732557348781,\n -0.068293048346633177859,\n  0.033403684226353715020,\n  0.001485679893925747818,\n -0.000734421305768455295,\n -0.000016837282388837229,\n  0.000008359950146618018,\n  0.000000117382095601192,\n -0.000000058413665922724,\n -0.000000000554763755743,\n  0.000000000276434190426,\n  0.000000000001895374892,\n -0.000000000000945237101,\n -0.000000000000004900690,\n  0.000000000000002445383,\n  0.000000000000000009925\n};\nstatic cheb_series sinc_cs = {\n  sinc_data,\n  16,\n  -1, 1,\n  10\n};\n\n\n/* Chebyshev expansion for f(t) = g((t+1)Pi/8), -1<t<1\n * g(x) = (sin(x)/x - 1)/(x*x)\n */\nstatic double sin_data[12] = {\n  -0.3295190160663511504173,\n   0.0025374284671667991990,\n   0.0006261928782647355874,\n  -4.6495547521854042157541e-06,\n  -5.6917531549379706526677e-07,\n   3.7283335140973803627866e-09,\n   3.0267376484747473727186e-10,\n  -1.7400875016436622322022e-12,\n  -1.0554678305790849834462e-13,\n   5.3701981409132410797062e-16,\n   2.5984137983099020336115e-17,\n  -1.1821555255364833468288e-19\n};\nstatic cheb_series sin_cs = {\n  sin_data,\n  11,\n  -1, 1,\n  11\n};\n\n/* Chebyshev expansion for f(t) = g((t+1)Pi/8), -1<t<1\n * g(x) = (2(cos(x) - 1)/(x^2) + 1) / x^2\n */\nstatic double cos_data[11] = {\n  0.165391825637921473505668118136,\n -0.00084852883845000173671196530195,\n -0.000210086507222940730213625768083,\n  1.16582269619760204299639757584e-6,\n  1.43319375856259870334412701165e-7,\n -7.4770883429007141617951330184e-10,\n -6.0969994944584252706997438007e-11,\n  2.90748249201909353949854872638e-13,\n  1.77126739876261435667156490461e-14,\n -7.6896421502815579078577263149e-17,\n -3.7363121133079412079201377318e-18\n};\nstatic cheb_series cos_cs = {\n  cos_data,\n  10,\n  -1, 1,\n  10\n};\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\n/* I would have prefered just using the library sin() function.\n * But after some experimentation I decided that there was\n * no good way to understand the error; library sin() is just a black box.\n * So we have to roll our own.\n */\nint\ngsl_sf_sin_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    const double P1 = 7.85398125648498535156e-1;\n    const double P2 = 3.77489470793079817668e-8;\n    const double P3 = 2.69515142907905952645e-15;\n\n    const double sgn_x = GSL_SIGN(x);\n    const double abs_x = fabs(x);\n\n    if(abs_x < GSL_ROOT4_DBL_EPSILON) {\n      const double x2 = x*x;\n      result->val = x * (1.0 - x2/6.0);\n      result->err = fabs(x*x2*x2 / 100.0);\n      return GSL_SUCCESS;\n    }\n    else {\n      double sgn_result = sgn_x;\n      double y = floor(abs_x/(0.25*M_PI));\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t\tint octant = y - ldexp(floor(ldexp(y,-3)),3);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n      int stat_cs;\n      double z;\n\n      if(GSL_IS_ODD(octant)) {\n        octant += 1;\n        octant &= 07;\n        y += 1.0;\n      }\n\n      if(octant > 3) {\n        octant -= 4;\n        sgn_result = -sgn_result;\n      }\n      \n      z = ((abs_x - y * P1) - y * P2) - y * P3;\n\n      if(octant == 0) {\n        gsl_sf_result sin_cs_result;\n        const double t = 8.0*fabs(z)/M_PI - 1.0;\n        stat_cs = cheb_eval_e(&sin_cs, t, &sin_cs_result);\n        result->val = z * (1.0 + z*z * sin_cs_result.val);\n      }\n      else { /* octant == 2 */\n        gsl_sf_result cos_cs_result;\n        const double t = 8.0*fabs(z)/M_PI - 1.0;\n        stat_cs = cheb_eval_e(&cos_cs, t, &cos_cs_result);\n        result->val = 1.0 - 0.5*z*z * (1.0 - z*z * cos_cs_result.val);\n      }\n\n      result->val *= sgn_result;\n\n      if(abs_x > 1.0/GSL_DBL_EPSILON) {\n        result->err = fabs(result->val);\n      }\n      else if(abs_x > 100.0/GSL_SQRT_DBL_EPSILON) {\n        result->err = 2.0 * abs_x * GSL_DBL_EPSILON * fabs(result->val);\n      }\n      else if(abs_x > 0.1/GSL_SQRT_DBL_EPSILON) {\n        result->err = 2.0 * GSL_SQRT_DBL_EPSILON * fabs(result->val);\n      }\n      else {\n        result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      }\n\n      return stat_cs;\n    }\n  }\n}\n\n\nint\ngsl_sf_cos_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    const double P1 = 7.85398125648498535156e-1;\n    const double P2 = 3.77489470793079817668e-8;\n    const double P3 = 2.69515142907905952645e-15;\n\n    const double abs_x = fabs(x);\n\n    if(abs_x < GSL_ROOT4_DBL_EPSILON) {\n      const double x2 = x*x;\n      result->val = 1.0 - 0.5*x2;\n      result->err = fabs(x2*x2/12.0);\n      return GSL_SUCCESS;\n    }\n    else {\n      double sgn_result = 1.0;\n      double y = floor(abs_x/(0.25*M_PI));\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t\tint octant = y - ldexp(floor(ldexp(y,-3)),3);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n      int stat_cs;\n      double z;\n\n      if(GSL_IS_ODD(octant)) {\n        octant += 1;\n        octant &= 07;\n        y += 1.0;\n      }\n\n      if(octant > 3) {\n        octant -= 4;\n        sgn_result = -sgn_result;\n      }\n\n      if(octant > 1) {\n        sgn_result = -sgn_result;\n      }\n\n      z = ((abs_x - y * P1) - y * P2) - y * P3;\n\n      if(octant == 0) {\n        gsl_sf_result cos_cs_result;\n        const double t = 8.0*fabs(z)/M_PI - 1.0;\n        stat_cs = cheb_eval_e(&cos_cs, t, &cos_cs_result);\n        result->val = 1.0 - 0.5*z*z * (1.0 - z*z * cos_cs_result.val);\n      }\n      else { /* octant == 2 */\n        gsl_sf_result sin_cs_result;\n        const double t = 8.0*fabs(z)/M_PI - 1.0;\n        stat_cs = cheb_eval_e(&sin_cs, t, &sin_cs_result);\n        result->val = z * (1.0 + z*z * sin_cs_result.val);\n      }\n\n      result->val *= sgn_result;\n\n      if(abs_x > 1.0/GSL_DBL_EPSILON) {\n        result->err = fabs(result->val);\n      }\n      else if(abs_x > 100.0/GSL_SQRT_DBL_EPSILON) {\n        result->err = 2.0 * abs_x * GSL_DBL_EPSILON * fabs(result->val);\n      }\n      else if(abs_x > 0.1/GSL_SQRT_DBL_EPSILON) {\n        result->err = 2.0 * GSL_SQRT_DBL_EPSILON * fabs(result->val);\n      }\n      else {\n        result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      }\n\n      return stat_cs;\n    }\n  }\n}\n\n\nint\ngsl_sf_hypot_e(const double x, const double y, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x == 0.0 && y == 0.0) {\n    result->val = 0.0;\n    result->err = 0.0;\n    return GSL_SUCCESS;\n  }\n  else {\n    const double a = fabs(x);\n    const double b = fabs(y);\n    const double min = GSL_MIN_DBL(a,b);\n    const double max = GSL_MAX_DBL(a,b);\n    const double rat = min/max;\n    const double root_term = sqrt(1.0 + rat*rat);\n\n    if(max < GSL_DBL_MAX/root_term) {\n      result->val = max * root_term;\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      OVERFLOW_ERROR(result);\n    }\n  }\n}\n\n\nint\ngsl_sf_complex_sin_e(const double zr, const double zi,\n                        gsl_sf_result * szr, gsl_sf_result * szi)\n{\n  /* CHECK_POINTER(szr) */\n  /* CHECK_POINTER(szi) */\n\n  if(fabs(zi) < 1.0) {\n    double ch_m1, sh;\n    sinh_series(zi, &sh);\n    cosh_m1_series(zi, &ch_m1);\n    szr->val = sin(zr)*(ch_m1 + 1.0);\n    szi->val = cos(zr)*sh;\n    szr->err = 2.0 * GSL_DBL_EPSILON * fabs(szr->val);\n    szi->err = 2.0 * GSL_DBL_EPSILON * fabs(szi->val);\n    return GSL_SUCCESS;\n  }\n  else if(fabs(zi) < GSL_LOG_DBL_MAX) {\n    double ex = exp(zi);\n    double ch = 0.5*(ex+1.0/ex);\n    double sh = 0.5*(ex-1.0/ex);\n    szr->val = sin(zr)*ch;\n    szi->val = cos(zr)*sh;\n    szr->err = 2.0 * GSL_DBL_EPSILON * fabs(szr->val);\n    szi->err = 2.0 * GSL_DBL_EPSILON * fabs(szi->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR_2(szr, szi);\n  }\n}\n\n\nint\ngsl_sf_complex_cos_e(const double zr, const double zi,\n                        gsl_sf_result * czr, gsl_sf_result * czi)\n{\n  /* CHECK_POINTER(czr) */\n  /* CHECK_POINTER(czi) */\n\n  if(fabs(zi) < 1.0) {\n    double ch_m1, sh;\n    sinh_series(zi, &sh);\n    cosh_m1_series(zi, &ch_m1);\n    czr->val =  cos(zr)*(ch_m1 + 1.0);\n    czi->val = -sin(zr)*sh;\n    czr->err = 2.0 * GSL_DBL_EPSILON * fabs(czr->val);\n    czi->err = 2.0 * GSL_DBL_EPSILON * fabs(czi->val);\n    return GSL_SUCCESS;\n  }\n  else if(fabs(zi) < GSL_LOG_DBL_MAX) {\n    double ex = exp(zi);\n    double ch = 0.5*(ex+1.0/ex);\n    double sh = 0.5*(ex-1.0/ex);\n    czr->val =  cos(zr)*ch;\n    czi->val = -sin(zr)*sh;\n    czr->err = 2.0 * GSL_DBL_EPSILON * fabs(czr->val);\n    czi->err = 2.0 * GSL_DBL_EPSILON * fabs(czi->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    OVERFLOW_ERROR_2(czr,czi);\n  }\n}\n\n\nint\ngsl_sf_complex_logsin_e(const double zr, const double zi,\n                           gsl_sf_result * lszr, gsl_sf_result * lszi)\n{\n  /* CHECK_POINTER(lszr) */\n  /* CHECK_POINTER(lszi) */\n\n  if(zi > 60.0) {\n    lszr->val = -M_LN2 + zi;\n    lszi->val =  0.5*M_PI - zr;\n    lszr->err = 2.0 * GSL_DBL_EPSILON * fabs(lszr->val);\n    lszi->err = 2.0 * GSL_DBL_EPSILON * fabs(lszi->val);\n  }\n  else if(zi < -60.0) {\n    lszr->val = -M_LN2 - zi;\n    lszi->val = -0.5*M_PI + zr;\n    lszr->err = 2.0 * GSL_DBL_EPSILON * fabs(lszr->val);\n    lszi->err = 2.0 * GSL_DBL_EPSILON * fabs(lszi->val);\n  }\n  else {\n    gsl_sf_result sin_r, sin_i;\n    int status;\n    gsl_sf_complex_sin_e(zr, zi, &sin_r, &sin_i); /* ok by construction */\n    status = gsl_sf_complex_log_e(sin_r.val, sin_i.val, lszr, lszi);\n    if(status == GSL_EDOM) {\n      DOMAIN_ERROR_2(lszr, lszi);\n    }\n  }\n  return gsl_sf_angle_restrict_symm_e(&(lszi->val));\n}\n\n\nint\ngsl_sf_lnsinh_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(x <= 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(fabs(x) < 1.0) {\n    double eps;\n    sinh_series(x, &eps);\n    result->val = log(eps);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(x < -0.5*GSL_LOG_DBL_EPSILON) {\n    result->val = x + log(0.5*(1.0 - exp(-2.0*x)));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    result->val = -M_LN2 + x;\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_lncosh_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(fabs(x) < 1.0) {\n    double eps;\n    cosh_m1_series(x, &eps);\n    return gsl_sf_log_1plusx_e(eps, result);\n  }\n  else if(fabs(x) < -0.5*GSL_LOG_DBL_EPSILON) {\n    result->val = fabs(x) + log(0.5*(1.0 + exp(-2.0*fabs(x))));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    result->val = -M_LN2 + fabs(x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\n/*\ninline int gsl_sf_sincos_e(const double theta, double * s, double * c)\n{\n  double tan_half = tan(0.5 * theta);\n  double den = 1. + tan_half*tan_half;\n  double cos_theta = (1.0 - tan_half*tan_half) / den;\n  double sin_theta = 2.0 * tan_half / den;\n}\n*/\n\nint\ngsl_sf_polar_to_rect(const double r, const double theta,\n                          gsl_sf_result * x, gsl_sf_result * y)\n{\n  double t   = theta;\n  int status = gsl_sf_angle_restrict_symm_e(&t);\n  double c = cos(t);\n  double s = sin(t);\n  x->val = r * cos(t);\n  y->val = r * sin(t);\n  x->err  = r * fabs(s * GSL_DBL_EPSILON * t);\n  x->err += 2.0 * GSL_DBL_EPSILON * fabs(x->val);\n  y->err  = r * fabs(c * GSL_DBL_EPSILON * t);\n  y->err += 2.0 * GSL_DBL_EPSILON * fabs(y->val);\n  return status;\n}\n\n\nint\ngsl_sf_rect_to_polar(const double x, const double y,\n                          gsl_sf_result * r, gsl_sf_result * theta)\n{\n  int stat_h = gsl_sf_hypot_e(x, y, r);\n  if(r->val > 0.0) {\n    theta->val = atan2(y, x);\n    theta->err = 2.0 * GSL_DBL_EPSILON * fabs(theta->val);\n    return stat_h;\n  }\n  else {\n    DOMAIN_ERROR(theta);\n  }\n}\n\n\nint gsl_sf_angle_restrict_symm_err_e(const double theta, gsl_sf_result * result)\n{\n  /* synthetic extended precision constants */\n  const double P1 = 4 * 7.8539812564849853515625e-01;\n  const double P2 = 4 * 3.7748947079307981766760e-08;\n  const double P3 = 4 * 2.6951514290790594840552e-15;\n  const double TwoPi = 2*(P1 + P2 + P3);\n\n  const double y = GSL_SIGN(theta) * 2 * floor(fabs(theta)/TwoPi);\n  double r = ((theta - y*P1) - y*P2) - y*P3;\n\n  if(r >  M_PI) { r = (((r-2*P1)-2*P2)-2*P3); }  /* r-TwoPi */\n  else if (r < -M_PI) r = (((r+2*P1)+2*P2)+2*P3); /* r+TwoPi */\n\n  result->val = r;\n\n  if(fabs(theta) > 0.0625/GSL_DBL_EPSILON) {\n    result->val = GSL_NAN;\n    result->err = GSL_NAN;\n    GSL_ERROR (\"error\", GSL_ELOSS);\n  }\n  else if(fabs(theta) > 0.0625/GSL_SQRT_DBL_EPSILON) {\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val - theta);\n    return GSL_SUCCESS;\n  }\n  else {\n    double delta = fabs(result->val - theta);\n    result->err = 2.0 * GSL_DBL_EPSILON * ((delta < M_PI) ? delta : M_PI);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_angle_restrict_pos_err_e(const double theta, gsl_sf_result * result)\n{\n  /* synthetic extended precision constants */\n  const double P1 = 4 * 7.85398125648498535156e-01;\n  const double P2 = 4 * 3.77489470793079817668e-08;\n  const double P3 = 4 * 2.69515142907905952645e-15;\n  const double TwoPi = 2*(P1 + P2 + P3);\n\n  const double y = 2*floor(theta/TwoPi);\n\n  double r = ((theta - y*P1) - y*P2) - y*P3;\n\n  if(r > TwoPi) {r = (((r-2*P1)-2*P2)-2*P3); }  /* r-TwoPi */\n  else if (r < 0) { /* may happen due to FP rounding */\n    r = (((r+2*P1)+2*P2)+2*P3); /* r+TwoPi */\n  }\n\n  result->val = r;\n\n  if(fabs(theta) > 0.0625/GSL_DBL_EPSILON) {\n    result->val = GSL_NAN;\n    result->err = fabs(result->val);\n    GSL_ERROR (\"error\", GSL_ELOSS);\n  }\n  else if(fabs(theta) > 0.0625/GSL_SQRT_DBL_EPSILON) {\n    result->err = GSL_DBL_EPSILON * fabs(result->val - theta);\n    return GSL_SUCCESS;\n  }\n  else {\n    double delta = fabs(result->val - theta);\n    result->err = 2.0 * GSL_DBL_EPSILON * ((delta < M_PI) ? delta : M_PI);\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_angle_restrict_symm_e(double * theta)\n{\n  gsl_sf_result r;\n  int stat = gsl_sf_angle_restrict_symm_err_e(*theta, &r);\n  *theta = r.val;\n  return stat;\n}\n\n\nint gsl_sf_angle_restrict_pos_e(double * theta)\n{\n  gsl_sf_result r;\n  int stat = gsl_sf_angle_restrict_pos_err_e(*theta, &r);\n  *theta = r.val;\n  return stat;\n}\n\n\nint gsl_sf_sin_err_e(const double x, const double dx, gsl_sf_result * result)\n{\n  int stat_s = gsl_sf_sin_e(x, result);\n  result->err += fabs(cos(x) * dx);\n  result->err += GSL_DBL_EPSILON * fabs(result->val);\n  return stat_s;\n}\n\n\nint gsl_sf_cos_err_e(const double x, const double dx, gsl_sf_result * result)\n{\n  int stat_c = gsl_sf_cos_e(x, result);\n  result->err += fabs(sin(x) * dx);\n  result->err += GSL_DBL_EPSILON * fabs(result->val);\n  return stat_c;\n}\n\n\n#if 0\nint\ngsl_sf_sin_pi_x_e(const double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(-100.0 < x && x < 100.0) {\n    result->val = sin(M_PI * x) / (M_PI * x);\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    const double N = floor(x + 0.5);\n    const double f = x - N;\n\n    if(N < INT_MAX && N > INT_MIN) {\n      /* Make it an integer if we can. Saves another\n       * call to floor().\n       */\n      const int intN    = (int)N;\n      const double sign = ( GSL_IS_ODD(intN) ? -1.0 : 1.0 );\n      result->val = sign * sin(M_PI * f);\n      result->err = GSL_DBL_EPSILON * fabs(result->val);\n    }\n    else if(N > 2.0/GSL_DBL_EPSILON || N < -2.0/GSL_DBL_EPSILON) {\n      /* All integer-valued floating point numbers\n       * bigger than 2/eps=2^53 are actually even.\n       */\n      result->val = 0.0;\n      result->err = 0.0;\n    }\n    else {\n      const double resN = N - 2.0*floor(0.5*N); /* 0 for even N, 1 for odd N */\n      const double sign = ( fabs(resN) > 0.5 ? -1.0 : 1.0 );\n      result->val = sign * sin(M_PI*f);\n      result->err = GSL_DBL_EPSILON * fabs(result->val);\n    }\n\n    return GSL_SUCCESS;\n  }\n}\n#endif\n\n\nint gsl_sf_sinc_e(double x, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  {\n    const double ax = fabs(x);\n\n    if(ax < 0.8) {\n      /* Do not go to the limit of the fit since\n       * there is a zero there and the Chebyshev\n       * accuracy will go to zero.\n       */\n      return cheb_eval_e(&sinc_cs, 2.0*ax-1.0, result);\n    }\n    else if(ax < 100.0) {\n      /* Small arguments are no problem.\n       * We trust the library sin() to\n       * roughly machine precision.\n       */\n      result->val = sin(M_PI * ax)/(M_PI * ax);\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      /* Large arguments must be handled separately.\n       */\n      const double r = M_PI*ax;\n      gsl_sf_result s;\n      int stat_s = gsl_sf_sin_e(r, &s);\n      result->val = s.val/r;\n      result->err = s.err/r + 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return stat_s;\n    }\n  }\n}\n\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_sin(const double x)\n{\n  EVAL_RESULT(gsl_sf_sin_e(x, &result));\n}\n\ndouble gsl_sf_cos(const double x)\n{\n  EVAL_RESULT(gsl_sf_cos_e(x, &result));\n}\n\ndouble gsl_sf_hypot(const double x, const double y)\n{\n  EVAL_RESULT(gsl_sf_hypot_e(x, y, &result));\n}\n\ndouble gsl_sf_lnsinh(const double x)\n{\n  EVAL_RESULT(gsl_sf_lnsinh_e(x, &result));\n}\n\ndouble gsl_sf_lncosh(const double x)\n{\n  EVAL_RESULT(gsl_sf_lncosh_e(x, &result));\n}\n\ndouble gsl_sf_angle_restrict_symm(const double theta)\n{\n  double result = theta;\n  EVAL_DOUBLE(gsl_sf_angle_restrict_symm_e(&result));\n}\n\ndouble gsl_sf_angle_restrict_pos(const double theta)\n{\n  double result = theta;\n  EVAL_DOUBLE(gsl_sf_angle_restrict_pos_e(&result));\n}\n\n#if 0\ndouble gsl_sf_sin_pi_x(const double x)\n{\n  EVAL_RESULT(gsl_sf_sin_pi_x_e(x, &result));\n}\n#endif\n\ndouble gsl_sf_sinc(const double x)\n{\n  EVAL_RESULT(gsl_sf_sinc_e(x, &result));\n}\n"
  },
  {
    "path": "gsl/specfunc/zeta.c",
    "content": "/* specfunc/zeta.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2004 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n/* Author:  G. Jungman */\n\n#include \"config.h\"\n#include \"gsl_math.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_sf_elementary.h\"\n#include \"gsl_sf_exp.h\"\n#include \"gsl_sf_gamma.h\"\n#include \"gsl_sf_pow_int.h\"\n#include \"gsl_sf_zeta.h\"\n\n#include \"error.h\"\n\n#include \"chebyshev.h\"\n#include \"cheb_eval.inc\"\n\n#define LogTwoPi_  1.8378770664093454835606594728111235279723\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/\n\n/* chebyshev fit for (s(t)-1)Zeta[s(t)]\n * s(t)= (t+1)/2\n * -1 <= t <= 1\n */\nstatic double zeta_xlt1_data[14] = {\n  1.48018677156931561235192914649,\n  0.25012062539889426471999938167,\n  0.00991137502135360774243761467,\n -0.00012084759656676410329833091,\n -4.7585866367662556504652535281e-06,\n  2.2229946694466391855561441361e-07,\n -2.2237496498030257121309056582e-09,\n -1.0173226513229028319420799028e-10,\n  4.3756643450424558284466248449e-12,\n -6.2229632593100551465504090814e-14,\n -6.6116201003272207115277520305e-16,\n  4.9477279533373912324518463830e-17,\n -1.0429819093456189719660003522e-18,\n  6.9925216166580021051464412040e-21,\n};\nstatic cheb_series zeta_xlt1_cs = {\n  zeta_xlt1_data,\n  13,\n  -1, 1,\n  8\n};\n\n/* chebyshev fit for (s(t)-1)Zeta[s(t)]\n * s(t)= (19t+21)/2\n * -1 <= t <= 1\n */\nstatic double zeta_xgt1_data[30] = {\n  19.3918515726724119415911269006,\n   9.1525329692510756181581271500,\n   0.2427897658867379985365270155,\n  -0.1339000688262027338316641329,\n   0.0577827064065028595578410202,\n  -0.0187625983754002298566409700,\n   0.0039403014258320354840823803,\n  -0.0000581508273158127963598882,\n  -0.0003756148907214820704594549,\n   0.0001892530548109214349092999,\n  -0.0000549032199695513496115090,\n   8.7086484008939038610413331863e-6,\n   6.4609477924811889068410083425e-7,\n  -9.6749773915059089205835337136e-7,\n   3.6585400766767257736982342461e-7,\n  -8.4592516427275164351876072573e-8,\n   9.9956786144497936572288988883e-9,\n   1.4260036420951118112457144842e-9,\n  -1.1761968823382879195380320948e-9,\n   3.7114575899785204664648987295e-10,\n  -7.4756855194210961661210215325e-11,\n   7.8536934209183700456512982968e-12,\n   9.9827182259685539619810406271e-13,\n  -7.5276687030192221587850302453e-13,\n   2.1955026393964279988917878654e-13,\n  -4.1934859852834647427576319246e-14,\n   4.6341149635933550715779074274e-15,\n   2.3742488509048340106830309402e-16,\n  -2.7276516388124786119323824391e-16,\n   7.8473570134636044722154797225e-17\n};\nstatic cheb_series zeta_xgt1_cs = {\n  zeta_xgt1_data,\n  29,\n  -1, 1,\n  17\n};\n\n\n/* chebyshev fit for Ln[Zeta[s(t)] - 1 - 2^(-s(t))]\n * s(t)= 10 + 5t\n * -1 <= t <= 1; 5 <= s <= 15\n */\nstatic double zetam1_inter_data[24] = {\n  -21.7509435653088483422022339374,\n  -5.63036877698121782876372020472,\n   0.0528041358684229425504861579635,\n  -0.0156381809179670789342700883562,\n   0.00408218474372355881195080781927,\n  -0.0010264867349474874045036628282,\n   0.000260469880409886900143834962387,\n  -0.0000676175847209968878098566819447,\n   0.0000179284472587833525426660171124,\n  -4.83238651318556188834107605116e-6,\n   1.31913788964999288471371329447e-6,\n  -3.63760500656329972578222188542e-7,\n   1.01146847513194744989748396574e-7,\n  -2.83215225141806501619105289509e-8,\n   7.97733710252021423361012829496e-9,\n  -2.25850168553956886676250696891e-9,\n   6.42269392950164306086395744145e-10,\n  -1.83363861846127284505060843614e-10,\n   5.25309763895283179960368072104e-11,\n  -1.50958687042589821074710575446e-11,\n   4.34997545516049244697776942981e-12,\n  -1.25597782748190416118082322061e-12,\n   3.61280740072222650030134104162e-13,\n  -9.66437239205745207188920348801e-14\n}; \nstatic cheb_series zetam1_inter_cs = {\n  zetam1_inter_data,\n  22,\n  -1, 1,\n  12\n};\n\n\n\n/* assumes s >= 0 and s != 1.0 */\ninline\nstatic int\nriemann_zeta_sgt0(double s, gsl_sf_result * result)\n{\n  if(s < 1.0) {\n    gsl_sf_result c;\n    cheb_eval_e(&zeta_xlt1_cs, 2.0*s - 1.0, &c);\n    result->val = c.val / (s - 1.0);\n    result->err = c.err / fabs(s-1.0) + GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else if(s <= 20.0) {\n    double x = (2.0*s - 21.0)/19.0;\n    gsl_sf_result c;\n    cheb_eval_e(&zeta_xgt1_cs, x, &c);\n    result->val = c.val / (s - 1.0);\n    result->err = c.err / (s - 1.0) + GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    double f2 = 1.0 - pow(2.0,-s);\n    double f3 = 1.0 - pow(3.0,-s);\n    double f5 = 1.0 - pow(5.0,-s);\n    double f7 = 1.0 - pow(7.0,-s);\n    result->val = 1.0/(f2*f3*f5*f7);\n    result->err = 3.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\ninline\nstatic int\nriemann_zeta1ms_slt0(double s, gsl_sf_result * result)\n{\n  if(s > -19.0) {\n    double x = (-19 - 2.0*s)/19.0;\n    gsl_sf_result c;\n    cheb_eval_e(&zeta_xgt1_cs, x, &c);\n    result->val = c.val / (-s);\n    result->err = c.err / (-s) + GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    double f2 = 1.0 - pow(2.0,-(1.0-s));\n    double f3 = 1.0 - pow(3.0,-(1.0-s));\n    double f5 = 1.0 - pow(5.0,-(1.0-s));\n    double f7 = 1.0 - pow(7.0,-(1.0-s));\n    result->val = 1.0/(f2*f3*f5*f7);\n    result->err = 3.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n}\n\n\n/* works for 5 < s < 15*/\nstatic int\nriemann_zeta_minus_1_intermediate_s(double s, gsl_sf_result * result)\n{\n  double t = (s - 10.0)/5.0;\n  gsl_sf_result c;\n  cheb_eval_e(&zetam1_inter_cs, t, &c);\n  result->val = exp(c.val) + pow(2.0, -s);\n  result->err = (c.err + 2.0*GSL_DBL_EPSILON)*result->val;\n  return GSL_SUCCESS;\n}\n\n\n/* assumes s is large and positive\n * write: zeta(s) - 1 = zeta(s) * (1 - 1/zeta(s))\n * and expand a few terms of the product formula to evaluate 1 - 1/zeta(s)\n *\n * works well for s > 15\n */\nstatic int\nriemann_zeta_minus1_large_s(double s, gsl_sf_result * result)\n{\n  double a = pow( 2.0,-s);\n  double b = pow( 3.0,-s);\n  double c = pow( 5.0,-s);\n  double d = pow( 7.0,-s);\n  double e = pow(11.0,-s);\n  double f = pow(13.0,-s);\n  double t1 = a + b + c + d + e + f;\n  double t2 = a*(b+c+d+e+f) + b*(c+d+e+f) + c*(d+e+f) + d*(e+f) + e*f;\n  /*\n  double t3 = a*(b*(c+d+e+f) + c*(d+e+f) + d*(e+f) + e*f) +\n              b*(c*(d+e+f) + d*(e+f) + e*f) +\n              c*(d*(e+f) + e*f) +\n              d*e*f;\n  double t4 = a*(b*(c*(d + e + f) + d*(e + f) + e*f) + c*(d*(e+f) + e*f) + d*e*f) +\n              b*(c*(d*(e+f) + e*f) + d*e*f) +\n              c*d*e*f;\n  double t5 = b*c*d*e*f + a*c*d*e*f+ a*b*d*e*f+ a*b*c*e*f+ a*b*c*d*f+ a*b*c*d*e;\n  double t6 = a*b*c*d*e*f;\n  */\n  double numt = t1 - t2 /* + t3 - t4 + t5 - t6 */;\n  double zeta = 1.0/((1.0-a)*(1.0-b)*(1.0-c)*(1.0-d)*(1.0-e)*(1.0-f));\n  result->val = numt*zeta;\n  result->err = (15.0/s + 1.0) * 6.0*GSL_DBL_EPSILON*result->val;\n  return GSL_SUCCESS;\n}\n\n\n#if 0\n/* zeta(n) */\n#define ZETA_POS_TABLE_NMAX   100\nstatic double zeta_pos_int_table_OLD[ZETA_POS_TABLE_NMAX+1] = {\n -0.50000000000000000000000000000,       /* zeta(0) */\n  0.0 /* FIXME: DirectedInfinity() */,   /* zeta(1) */\n  1.64493406684822643647241516665,       /* ...     */\n  1.20205690315959428539973816151,\n  1.08232323371113819151600369654,\n  1.03692775514336992633136548646,\n  1.01734306198444913971451792979,\n  1.00834927738192282683979754985,\n  1.00407735619794433937868523851,\n  1.00200839282608221441785276923,\n  1.00099457512781808533714595890,\n  1.00049418860411946455870228253,\n  1.00024608655330804829863799805,\n  1.00012271334757848914675183653,\n  1.00006124813505870482925854511,\n  1.00003058823630702049355172851,\n  1.00001528225940865187173257149,\n  1.00000763719763789976227360029,\n  1.00000381729326499983985646164,\n  1.00000190821271655393892565696,\n  1.00000095396203387279611315204,\n  1.00000047693298678780646311672,\n  1.00000023845050272773299000365,\n  1.00000011921992596531107306779,\n  1.00000005960818905125947961244,\n  1.00000002980350351465228018606,\n  1.00000001490155482836504123466,\n  1.00000000745071178983542949198,\n  1.00000000372533402478845705482,\n  1.00000000186265972351304900640,\n  1.00000000093132743241966818287,\n  1.00000000046566290650337840730,\n  1.00000000023283118336765054920,\n  1.00000000011641550172700519776,\n  1.00000000005820772087902700889,\n  1.00000000002910385044497099687,\n  1.00000000001455192189104198424,\n  1.00000000000727595983505748101,\n  1.00000000000363797954737865119,\n  1.00000000000181898965030706595,\n  1.00000000000090949478402638893,\n  1.00000000000045474737830421540,\n  1.00000000000022737368458246525,\n  1.00000000000011368684076802278,\n  1.00000000000005684341987627586,\n  1.00000000000002842170976889302,\n  1.00000000000001421085482803161,\n  1.00000000000000710542739521085,\n  1.00000000000000355271369133711,\n  1.00000000000000177635684357912,\n  1.00000000000000088817842109308,\n  1.00000000000000044408921031438,\n  1.00000000000000022204460507980,\n  1.00000000000000011102230251411,\n  1.00000000000000005551115124845,\n  1.00000000000000002775557562136,\n  1.00000000000000001387778780973,\n  1.00000000000000000693889390454,\n  1.00000000000000000346944695217,\n  1.00000000000000000173472347605,\n  1.00000000000000000086736173801,\n  1.00000000000000000043368086900,\n  1.00000000000000000021684043450,\n  1.00000000000000000010842021725,\n  1.00000000000000000005421010862,\n  1.00000000000000000002710505431,\n  1.00000000000000000001355252716,\n  1.00000000000000000000677626358,\n  1.00000000000000000000338813179,\n  1.00000000000000000000169406589,\n  1.00000000000000000000084703295,\n  1.00000000000000000000042351647,\n  1.00000000000000000000021175824,\n  1.00000000000000000000010587912,\n  1.00000000000000000000005293956,\n  1.00000000000000000000002646978,\n  1.00000000000000000000001323489,\n  1.00000000000000000000000661744,\n  1.00000000000000000000000330872,\n  1.00000000000000000000000165436,\n  1.00000000000000000000000082718,\n  1.00000000000000000000000041359,\n  1.00000000000000000000000020680,\n  1.00000000000000000000000010340,\n  1.00000000000000000000000005170,\n  1.00000000000000000000000002585,\n  1.00000000000000000000000001292,\n  1.00000000000000000000000000646,\n  1.00000000000000000000000000323,\n  1.00000000000000000000000000162,\n  1.00000000000000000000000000081,\n  1.00000000000000000000000000040,\n  1.00000000000000000000000000020,\n  1.00000000000000000000000000010,\n  1.00000000000000000000000000005,\n  1.00000000000000000000000000003,\n  1.00000000000000000000000000001,\n  1.00000000000000000000000000001,\n  1.00000000000000000000000000000,\n  1.00000000000000000000000000000,\n  1.00000000000000000000000000000\n};\n#endif /* 0 */\n\n\n/* zeta(n) - 1 */\n#define ZETA_POS_TABLE_NMAX   100\nstatic double zetam1_pos_int_table[ZETA_POS_TABLE_NMAX+1] = {\n -1.5,                               /* zeta(0) */\n  0.0,       /* FIXME: Infinity */   /* zeta(1) - 1 */\n  0.644934066848226436472415166646,  /* zeta(2) - 1 */\n  0.202056903159594285399738161511,\n  0.082323233711138191516003696541,\n  0.036927755143369926331365486457,\n  0.017343061984449139714517929790,\n  0.008349277381922826839797549849,\n  0.004077356197944339378685238508,\n  0.002008392826082214417852769232,\n  0.000994575127818085337145958900,\n  0.000494188604119464558702282526,\n  0.000246086553308048298637998047,\n  0.000122713347578489146751836526,\n  0.000061248135058704829258545105,\n  0.000030588236307020493551728510,\n  0.000015282259408651871732571487,\n  7.6371976378997622736002935630e-6,\n  3.8172932649998398564616446219e-6,\n  1.9082127165539389256569577951e-6,\n  9.5396203387279611315203868344e-7,\n  4.7693298678780646311671960437e-7,\n  2.3845050272773299000364818675e-7,\n  1.1921992596531107306778871888e-7,\n  5.9608189051259479612440207935e-8,\n  2.9803503514652280186063705069e-8,\n  1.4901554828365041234658506630e-8,\n  7.4507117898354294919810041706e-9,\n  3.7253340247884570548192040184e-9,\n  1.8626597235130490064039099454e-9,\n  9.3132743241966818287176473502e-10,\n  4.6566290650337840729892332512e-10,\n  2.3283118336765054920014559759e-10,\n  1.1641550172700519775929738354e-10,\n  5.8207720879027008892436859891e-11,\n  2.9103850444970996869294252278e-11,\n  1.4551921891041984235929632245e-11,\n  7.2759598350574810145208690123e-12,\n  3.6379795473786511902372363558e-12,\n  1.8189896503070659475848321007e-12,\n  9.0949478402638892825331183869e-13,\n  4.5474737830421540267991120294e-13,\n  2.2737368458246525152268215779e-13,\n  1.1368684076802278493491048380e-13,\n  5.6843419876275856092771829675e-14,\n  2.8421709768893018554550737049e-14,\n  1.4210854828031606769834307141e-14,\n  7.1054273952108527128773544799e-15,\n  3.5527136913371136732984695340e-15,\n  1.7763568435791203274733490144e-15,\n  8.8817842109308159030960913863e-16,\n  4.4408921031438133641977709402e-16,\n  2.2204460507980419839993200942e-16,\n  1.1102230251410661337205445699e-16,\n  5.5511151248454812437237365905e-17,\n  2.7755575621361241725816324538e-17,\n  1.3877787809725232762839094906e-17,\n  6.9388939045441536974460853262e-18,\n  3.4694469521659226247442714961e-18,\n  1.7347234760475765720489729699e-18,\n  8.6736173801199337283420550673e-19,\n  4.3368086900206504874970235659e-19,\n  2.1684043449972197850139101683e-19,\n  1.0842021724942414063012711165e-19,\n  5.4210108624566454109187004043e-20,\n  2.7105054312234688319546213119e-20,\n  1.3552527156101164581485233996e-20,\n  6.7762635780451890979952987415e-21,\n  3.3881317890207968180857031004e-21,\n  1.6940658945097991654064927471e-21,\n  8.4703294725469983482469926091e-22,\n  4.2351647362728333478622704833e-22,\n  2.1175823681361947318442094398e-22,\n  1.0587911840680233852265001539e-22,\n  5.2939559203398703238139123029e-23,\n  2.6469779601698529611341166842e-23,\n  1.3234889800848990803094510250e-23,\n  6.6174449004244040673552453323e-24,\n  3.3087224502121715889469563843e-24,\n  1.6543612251060756462299236771e-24,\n  8.2718061255303444036711056167e-25,\n  4.1359030627651609260093824555e-25,\n  2.0679515313825767043959679193e-25,\n  1.0339757656912870993284095591e-25,\n  5.1698788284564313204101332166e-26,\n  2.5849394142282142681277617708e-26,\n  1.2924697071141066700381126118e-26,\n  6.4623485355705318034380021611e-27,\n  3.2311742677852653861348141180e-27,\n  1.6155871338926325212060114057e-27,\n  8.0779356694631620331587381863e-28,\n  4.0389678347315808256222628129e-28,\n  2.0194839173657903491587626465e-28,\n  1.0097419586828951533619250700e-28,\n  5.0487097934144756960847711725e-29,\n  2.5243548967072378244674341938e-29,\n  1.2621774483536189043753999660e-29,\n  6.3108872417680944956826093943e-30,\n  3.1554436208840472391098412184e-30,\n  1.5777218104420236166444327830e-30,\n  7.8886090522101180735205378276e-31\n};\n\n\n#define ZETA_NEG_TABLE_NMAX  99\n#define ZETA_NEG_TABLE_SIZE  50\nstatic double zeta_neg_int_table[ZETA_NEG_TABLE_SIZE] = {\n -0.083333333333333333333333333333,     /* zeta(-1) */\n  0.008333333333333333333333333333,     /* zeta(-3) */\n -0.003968253968253968253968253968,     /* ...      */\n  0.004166666666666666666666666667,\n -0.007575757575757575757575757576,\n  0.021092796092796092796092796093,\n -0.083333333333333333333333333333,\n  0.44325980392156862745098039216,\n -3.05395433027011974380395433027,\n  26.4562121212121212121212121212,\n -281.460144927536231884057971014,\n  3607.5105463980463980463980464,\n -54827.583333333333333333333333,\n  974936.82385057471264367816092,\n -2.0052695796688078946143462272e+07,\n  4.7238486772162990196078431373e+08,\n -1.2635724795916666666666666667e+10,\n  3.8087931125245368811553022079e+11,\n -1.2850850499305083333333333333e+13,\n  4.8241448354850170371581670362e+14,\n -2.0040310656516252738108421663e+16,\n  9.1677436031953307756992753623e+17,\n -4.5979888343656503490437943262e+19,\n  2.5180471921451095697089023320e+21,\n -1.5001733492153928733711440151e+23,\n  9.6899578874635940656497942895e+24,\n -6.7645882379292820990945242302e+26,\n  5.0890659468662289689766332916e+28,\n -4.1147288792557978697665486068e+30,\n  3.5666582095375556109684574609e+32,\n -3.3066089876577576725680214670e+34,\n  3.2715634236478716264211227016e+36,\n -3.4473782558278053878256455080e+38,\n  3.8614279832705258893092720200e+40,\n -4.5892974432454332168863989006e+42,\n  5.7775386342770431824884825688e+44,\n -7.6919858759507135167410075972e+46,\n  1.0813635449971654696354033351e+49,\n -1.6029364522008965406067102346e+51,\n  2.5019479041560462843656661499e+53,\n -4.1067052335810212479752045004e+55,\n  7.0798774408494580617452972433e+57,\n -1.2804546887939508790190849756e+60,\n  2.4267340392333524078020892067e+62,\n -4.8143218874045769355129570066e+64,\n  9.9875574175727530680652777408e+66,\n -2.1645634868435185631335136160e+69,\n  4.8962327039620553206849224516e+71,    /* ...        */\n -1.1549023923963519663954271692e+74,    /* zeta(-97)  */\n  2.8382249570693706959264156336e+76     /* zeta(-99)  */\n};\n\n\n/* coefficients for Maclaurin summation in hzeta()\n * B_{2j}/(2j)!\n */\nstatic double hzeta_c[15] = {\n  1.00000000000000000000000000000,\n  0.083333333333333333333333333333,\n -0.00138888888888888888888888888889,\n  0.000033068783068783068783068783069,\n -8.2671957671957671957671957672e-07,\n  2.0876756987868098979210090321e-08,\n -5.2841901386874931848476822022e-10,\n  1.3382536530684678832826980975e-11,\n -3.3896802963225828668301953912e-13,\n  8.5860620562778445641359054504e-15,\n -2.1748686985580618730415164239e-16,\n  5.5090028283602295152026526089e-18,\n -1.3954464685812523340707686264e-19,\n  3.5347070396294674716932299778e-21,\n -8.9535174270375468504026113181e-23\n};\n\n#define ETA_POS_TABLE_NMAX  100\nstatic double eta_pos_int_table[ETA_POS_TABLE_NMAX+1] = {\n0.50000000000000000000000000000,  /* eta(0) */\nM_LN2,                            /* eta(1) */\n0.82246703342411321823620758332,  /* ...    */\n0.90154267736969571404980362113,\n0.94703282949724591757650323447,\n0.97211977044690930593565514355,\n0.98555109129743510409843924448,\n0.99259381992283028267042571313,\n0.99623300185264789922728926008,\n0.99809429754160533076778303185,\n0.99903950759827156563922184570,\n0.99951714349806075414409417483,\n0.99975768514385819085317967871,\n0.99987854276326511549217499282,\n0.99993917034597971817095419226,\n0.99996955121309923808263293263,\n0.99998476421490610644168277496,\n0.99999237829204101197693787224,\n0.99999618786961011347968922641,\n0.99999809350817167510685649297,\n0.99999904661158152211505084256,\n0.99999952325821554281631666433,\n0.99999976161323082254789720494,\n0.99999988080131843950322382485,\n0.99999994039889239462836140314,\n0.99999997019885696283441513311,\n0.99999998509923199656878766181,\n0.99999999254955048496351585274,\n0.99999999627475340010872752767,\n0.99999999813736941811218674656,\n0.99999999906868228145397862728,\n0.99999999953434033145421751469,\n0.99999999976716989595149082282,\n0.99999999988358485804603047265,\n0.99999999994179239904531592388,\n0.99999999997089618952980952258,\n0.99999999998544809143388476396,\n0.99999999999272404460658475006,\n0.99999999999636202193316875550,\n0.99999999999818101084320873555,\n0.99999999999909050538047887809,\n0.99999999999954525267653087357,\n0.99999999999977262633369589773,\n0.99999999999988631316532476488,\n0.99999999999994315658215465336,\n0.99999999999997157829090808339,\n0.99999999999998578914539762720,\n0.99999999999999289457268000875,\n0.99999999999999644728633373609,\n0.99999999999999822364316477861,\n0.99999999999999911182158169283,\n0.99999999999999955591079061426,\n0.99999999999999977795539522974,\n0.99999999999999988897769758908,\n0.99999999999999994448884878594,\n0.99999999999999997224442439010,\n0.99999999999999998612221219410,\n0.99999999999999999306110609673,\n0.99999999999999999653055304826,\n0.99999999999999999826527652409,\n0.99999999999999999913263826204,\n0.99999999999999999956631913101,\n0.99999999999999999978315956551,\n0.99999999999999999989157978275,\n0.99999999999999999994578989138,\n0.99999999999999999997289494569,\n0.99999999999999999998644747284,\n0.99999999999999999999322373642,\n0.99999999999999999999661186821,\n0.99999999999999999999830593411,\n0.99999999999999999999915296705,\n0.99999999999999999999957648353,\n0.99999999999999999999978824176,\n0.99999999999999999999989412088,\n0.99999999999999999999994706044,\n0.99999999999999999999997353022,\n0.99999999999999999999998676511,\n0.99999999999999999999999338256,\n0.99999999999999999999999669128,\n0.99999999999999999999999834564,\n0.99999999999999999999999917282,\n0.99999999999999999999999958641,\n0.99999999999999999999999979320,\n0.99999999999999999999999989660,\n0.99999999999999999999999994830,\n0.99999999999999999999999997415,\n0.99999999999999999999999998708,\n0.99999999999999999999999999354,\n0.99999999999999999999999999677,\n0.99999999999999999999999999838,\n0.99999999999999999999999999919,\n0.99999999999999999999999999960,\n0.99999999999999999999999999980,\n0.99999999999999999999999999990,\n0.99999999999999999999999999995,\n0.99999999999999999999999999997,\n0.99999999999999999999999999999,\n0.99999999999999999999999999999,\n1.00000000000000000000000000000,\n1.00000000000000000000000000000,\n1.00000000000000000000000000000,\n};\n\n\n#define ETA_NEG_TABLE_NMAX  99\n#define ETA_NEG_TABLE_SIZE  50\nstatic double eta_neg_int_table[ETA_NEG_TABLE_SIZE] = {\n 0.25000000000000000000000000000,   /* eta(-1) */\n-0.12500000000000000000000000000,   /* eta(-3) */\n 0.25000000000000000000000000000,   /* ...      */\n-1.06250000000000000000000000000,\n 7.75000000000000000000000000000,\n-86.3750000000000000000000000000,\n 1365.25000000000000000000000000,\n-29049.0312500000000000000000000,\n 800572.750000000000000000000000,\n-2.7741322625000000000000000000e+7,\n 1.1805291302500000000000000000e+9,\n-6.0523980051687500000000000000e+10,\n 3.6794167785377500000000000000e+12,\n-2.6170760990658387500000000000e+14,\n 2.1531418140800295250000000000e+16,\n-2.0288775575173015930156250000e+18,\n 2.1708009902623770590275000000e+20,\n-2.6173826968455814932120125000e+22,\n 3.5324148876863877826668602500e+24,\n-5.3042033406864906641493838981e+26,\n 8.8138218364311576767253114668e+28,\n-1.6128065107490778547354654864e+31,\n 3.2355470001722734208527794569e+33,\n-7.0876727476537493198506645215e+35,\n 1.6890450341293965779175629389e+38,\n-4.3639690731216831157655651358e+40,\n 1.2185998827061261322605065672e+43,\n-3.6670584803153006180101262324e+45,\n 1.1859898526302099104271449748e+48,\n-4.1120769493584015047981746438e+50,\n 1.5249042436787620309090168687e+53,\n-6.0349693196941307074572991901e+55,\n 2.5437161764210695823197691519e+58,\n-1.1396923802632287851130360170e+61,\n 5.4180861064753979196802726455e+63,\n-2.7283654799994373847287197104e+66,\n 1.4529750514918543238511171663e+69,\n-8.1705519371067450079777183386e+71,\n 4.8445781606678367790247757259e+74,\n-3.0246694206649519336179448018e+77,\n 1.9858807961690493054169047970e+80,\n-1.3694474620720086994386818232e+83,\n 9.9070382984295807826303785989e+85,\n-7.5103780796592645925968460677e+88,\n 5.9598418264260880840077992227e+91,\n-4.9455988887500020399263196307e+94,\n 4.2873596927020241277675775935e+97,\n-3.8791952037716162900707994047e+100,\n 3.6600317773156342245401829308e+103,\n-3.5978775704117283875784869570e+106    /* eta(-99)  */\n};\n\n\n/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/\n\n\nint gsl_sf_hzeta_e(const double s, const double q, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(s <= 1.0 || q <= 0.0) {\n    DOMAIN_ERROR(result);\n  }\n  else {\n    const double max_bits = 54.0;\n    const double ln_term0 = -s * log(q);  \n\n    if(ln_term0 < GSL_LOG_DBL_MIN + 1.0) {\n      UNDERFLOW_ERROR(result);\n    }\n    else if(ln_term0 > GSL_LOG_DBL_MAX - 1.0) {\n      OVERFLOW_ERROR (result);\n    }\n    else if((s > max_bits && q < 1.0) || (s > 0.5*max_bits && q < 0.25)) {\n      result->val = pow(q, -s);\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else if(s > 0.5*max_bits && q < 1.0) {\n      const double p1 = pow(q, -s);\n      const double p2 = pow(q/(1.0+q), s);\n      const double p3 = pow(q/(2.0+q), s);\n      result->val = p1 * (1.0 + p2 + p3);\n      result->err = GSL_DBL_EPSILON * (0.5*s + 2.0) * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      /* Euler-Maclaurin summation formula \n       * [Moshier, p. 400, with several typo corrections]\n       */\n      const int jmax = 12;\n      const int kmax = 10;\n      int j, k;\n      const double pmax  = pow(kmax + q, -s);\n      double scp = s;\n      double pcp = pmax / (kmax + q);\n      double ans = pmax*((kmax+q)/(s-1.0) + 0.5);\n\n      for(k=0; k<kmax; k++) {\n        ans += pow(k + q, -s);\n      }\n\n      for(j=0; j<=jmax; j++) {\n        double delta = hzeta_c[j+1] * scp * pcp;\n        ans += delta;\n        if(fabs(delta/ans) < 0.5*GSL_DBL_EPSILON) break;\n        scp *= (s+2*j+1)*(s+2*j+2);\n        pcp /= (kmax + q)*(kmax + q);\n      }\n\n      result->val = ans;\n      result->err = 2.0 * (jmax + 1.0) * GSL_DBL_EPSILON * fabs(ans);\n      return GSL_SUCCESS;\n    }\n  }\n}\n\n\nint gsl_sf_zeta_e(const double s, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(s == 1.0) {\n    DOMAIN_ERROR(result);\n  }\n  else if(s >= 0.0) {\n    return riemann_zeta_sgt0(s, result);\n  }\n  else {\n    /* reflection formula, [Abramowitz+Stegun, 23.2.5] */\n\n    gsl_sf_result zeta_one_minus_s;\n    const int stat_zoms = riemann_zeta1ms_slt0(s, &zeta_one_minus_s);\n    const double sin_term = (fmod(s,2.0) == 0.0) ? 0.0 : sin(0.5*M_PI*fmod(s,4.0))/M_PI;\n\n    if(sin_term == 0.0) {\n      result->val = 0.0;\n      result->err = 0.0;\n      return GSL_SUCCESS;\n    }\n    else if(s > -170) {\n      /* We have to be careful about losing digits\n       * in calculating pow(2 Pi, s). The gamma\n       * function is fine because we were careful\n       * with that implementation.\n       * We keep an array of (2 Pi)^(10 n).\n       */\n      const double twopi_pow[18] = { 1.0,\n                                     9.589560061550901348e+007,\n                                     9.195966217409212684e+015,\n                                     8.818527036583869903e+023,\n                                     8.456579467173150313e+031,\n                                     8.109487671573504384e+039,\n                                     7.776641909496069036e+047,\n                                     7.457457466828644277e+055,\n                                     7.151373628461452286e+063,\n                                     6.857852693272229709e+071,\n                                     6.576379029540265771e+079,\n                                     6.306458169130020789e+087,\n                                     6.047615938853066678e+095,\n                                     5.799397627482402614e+103,\n                                     5.561367186955830005e+111,\n                                     5.333106466365131227e+119,\n                                     5.114214477385391780e+127,\n                                     4.904306689854036836e+135\n                                    };\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wconversion\"\n\t\tconst int n = floor((-s)/10.0);\n#pragma clang diagnostic pop\n#pragma GCC diagnostic pop\n      const double fs = s + 10.0*n;\n      const double p = pow(2.0*M_PI, fs) / twopi_pow[n];\n\n      gsl_sf_result g;\n      const int stat_g = gsl_sf_gamma_e(1.0-s, &g);\n      result->val  = p * g.val * sin_term * zeta_one_minus_s.val;\n      result->err  = fabs(p * g.val * sin_term) * zeta_one_minus_s.err;\n      result->err += fabs(p * sin_term * zeta_one_minus_s.val) * g.err;\n      result->err += GSL_DBL_EPSILON * (fabs(s)+2.0) * fabs(result->val);\n      return GSL_ERROR_SELECT_2(stat_g, stat_zoms);\n    }\n    else {\n      /* The actual zeta function may or may not\n       * overflow here. But we have no easy way\n       * to calculate it when the prefactor(s)\n       * overflow. Trying to use log's and exp\n       * is no good because we loose a couple\n       * digits to the exp error amplification.\n       * When we gather a little more patience,\n       * we can implement something here. Until\n       * then just give up.\n       */\n      OVERFLOW_ERROR(result);\n    }\n  }\n}\n\n\nint gsl_sf_zeta_int_e(const int n, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(n < 0) {\n    if(!GSL_IS_ODD(n)) {\n      result->val = 0.0; /* exactly zero at even negative integers */\n      result->err = 0.0;\n      return GSL_SUCCESS;\n    }\n    else if(n > -ZETA_NEG_TABLE_NMAX) {\n      result->val = zeta_neg_int_table[-(n+1)/2];\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      return gsl_sf_zeta_e((double)n, result);\n    }\n  }\n  else if(n == 1){\n    DOMAIN_ERROR(result);\n  }\n  else if(n <= ZETA_POS_TABLE_NMAX){\n    result->val = 1.0 + zetam1_pos_int_table[n];\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    result->val = 1.0;\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n}\n\n\nint gsl_sf_zetam1_e(const double s, gsl_sf_result * result)\n{\n  if(s <= 5.0)\n  {\n    int stat = gsl_sf_zeta_e(s, result);\n    result->val = result->val - 1.0;\n    return stat;\n  }\n  else if(s < 15.0)\n  {\n    return riemann_zeta_minus_1_intermediate_s(s, result);\n  }\n  else\n  {\n    return riemann_zeta_minus1_large_s(s, result);\n  }\n}\n\n\nint gsl_sf_zetam1_int_e(const int n, gsl_sf_result * result)\n{\n  if(n < 0) {\n    if(!GSL_IS_ODD(n)) {\n      result->val = -1.0; /* at even negative integers zetam1 == -1 since zeta is exactly zero */\n      result->err = 0.0;\n      return GSL_SUCCESS;\n    }\n    else if(n > -ZETA_NEG_TABLE_NMAX) {\n      result->val = zeta_neg_int_table[-(n+1)/2] - 1.0;\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      /* could use gsl_sf_zetam1_e here but subtracting 1 makes no difference\n         for such large values, so go straight to the result */\n      return gsl_sf_zeta_e((double)n, result);  \n    }\n  }\n  else if(n == 1){\n    DOMAIN_ERROR(result);\n  }\n  else if(n <= ZETA_POS_TABLE_NMAX){\n    result->val = zetam1_pos_int_table[n];\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    return gsl_sf_zetam1_e(n, result);\n  }\n}\n\n\nint gsl_sf_eta_int_e(int n, gsl_sf_result * result)\n{\n  if(n > ETA_POS_TABLE_NMAX) {\n    result->val = 1.0;\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(n >= 0) {\n    result->val = eta_pos_int_table[n];\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    /* n < 0 */\n\n    if(!GSL_IS_ODD(n)) {\n      /* exactly zero at even negative integers */\n      result->val = 0.0;\n      result->err = 0.0;\n      return GSL_SUCCESS;\n    }\n    else if(n > -ETA_NEG_TABLE_NMAX) {\n      result->val = eta_neg_int_table[-(n+1)/2];\n      result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_SUCCESS;\n    }\n    else {\n      gsl_sf_result z;\n      gsl_sf_result p;\n      int stat_z = gsl_sf_zeta_int_e(n, &z);\n      int stat_p = gsl_sf_exp_e((1.0-n)*M_LN2, &p);\n      int stat_m = gsl_sf_multiply_e(-p.val, z.val, result);\n      result->err  = fabs(p.err * (M_LN2*(1.0-n)) * z.val) + z.err * fabs(p.val);\n      result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n      return GSL_ERROR_SELECT_3(stat_m, stat_p, stat_z);\n    }\n  }\n}\n\n\nint gsl_sf_eta_e(const double s, gsl_sf_result * result)\n{\n  /* CHECK_POINTER(result) */\n\n  if(s > 100.0) {\n    result->val = 1.0;\n    result->err = GSL_DBL_EPSILON;\n    return GSL_SUCCESS;\n  }\n  else if(fabs(s-1.0) < 10.0*GSL_ROOT5_DBL_EPSILON) {\n    double del = s-1.0;\n    double c0  = M_LN2;\n    double c1  = M_LN2 * (M_EULER - 0.5*M_LN2);\n    double c2  = -0.0326862962794492996;\n    double c3  =  0.0015689917054155150;\n    double c4  =  0.00074987242112047532;\n    result->val = c0 + del * (c1 + del * (c2 + del * (c3 + del * c4)));\n    result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_SUCCESS;\n  }\n  else {\n    gsl_sf_result z;\n    gsl_sf_result p;\n    int stat_z = gsl_sf_zeta_e(s, &z);\n    int stat_p = gsl_sf_exp_e((1.0-s)*M_LN2, &p);\n    int stat_m = gsl_sf_multiply_e(1.0-p.val, z.val, result);\n    result->err  = fabs(p.err * (M_LN2*(1.0-s)) * z.val) + z.err * fabs(p.val);\n    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);\n    return GSL_ERROR_SELECT_3(stat_m, stat_p, stat_z);\n  }\n}\n\n\n/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/\n\n#include \"eval.h\"\n\ndouble gsl_sf_zeta(const double s)\n{\n  EVAL_RESULT(gsl_sf_zeta_e(s, &result));\n}\n\ndouble gsl_sf_hzeta(const double s, const double a)\n{\n  EVAL_RESULT(gsl_sf_hzeta_e(s, a, &result));\n}\n\ndouble gsl_sf_zeta_int(const int s)\n{\n  EVAL_RESULT(gsl_sf_zeta_int_e(s, &result));\n}\n\ndouble gsl_sf_zetam1(const double s)\n{\n  EVAL_RESULT(gsl_sf_zetam1_e(s, &result));\n}\n\ndouble gsl_sf_zetam1_int(const int s)\n{\n  EVAL_RESULT(gsl_sf_zetam1_int_e(s, &result));\n}\n\ndouble gsl_sf_eta_int(const int s)\n{\n  EVAL_RESULT(gsl_sf_eta_int_e(s, &result));\n}\n\ndouble gsl_sf_eta(const double s)\n{\n  EVAL_RESULT(gsl_sf_eta_e(s, &result));\n}\n"
  },
  {
    "path": "gsl/sys/coerce.c",
    "content": "/* sys/coerce.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_sys.h\"\n\ndouble \ngsl_coerce_double (const double x)\n{\n  volatile double y;\n  y = x;\n  return y;\n}\n\nfloat \ngsl_coerce_float (const float x)\n{\n  volatile float y;\n  y = x;\n  return y;\n}\n\n/* The following function is not needed, but is included for completeness */\n\nlong double \ngsl_coerce_long_double (const long double x)\n{\n  volatile long double y;\n  y = x;\n  return y;\n}\n\n"
  },
  {
    "path": "gsl/sys/fdiv.c",
    "content": "/* sys/fdiv.c\n * \n * Copyright (C) 2001, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n#include \"gsl_sys.h\"\n\ndouble \ngsl_fdiv (const double x, const double y)\n{\n  return x / y;\n}\n"
  },
  {
    "path": "gsl/sys/gsl_sys.h",
    "content": "/* sys/gsl_sys.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_SYS_H__\n#define __GSL_SYS_H__\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ndouble gsl_log1p (const double x);\ndouble gsl_expm1 (const double x);\ndouble gsl_hypot (const double x, const double y);\ndouble gsl_hypot3 (const double x, const double y, const double z);\ndouble gsl_acosh (const double x);\ndouble gsl_asinh (const double x);\ndouble gsl_atanh (const double x);\n\nint gsl_isnan (const double x);\nint gsl_isinf (const double x);\nint gsl_finite (const double x);\n\ndouble gsl_nan (void);\ndouble gsl_posinf (void);\ndouble gsl_neginf (void);\ndouble gsl_fdiv (const double x, const double y);\n\ndouble gsl_coerce_double (const double x);\nfloat gsl_coerce_float (const float x);\nlong double gsl_coerce_long_double (const long double x);\n\ndouble gsl_ldexp(const double x, const int e);\ndouble gsl_frexp(const double x, int * e);\n\nint gsl_fcmp (const double x1, const double x2, const double epsilon);\n\n__END_DECLS\n\n#endif /* __GSL_SYS_H__ */\n"
  },
  {
    "path": "gsl/sys/infnan.c",
    "content": "/* sys/infnan.c\n * \n * Copyright (C) 2001, 2004, 2007, 2010 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include <math.h>\n\n#if HAVE_IEEEFP_H\n#include <ieeefp.h>\n#endif\n\n#include \"gsl_sys.h\"\n\ndouble gsl_nan (void)\n{\n  return gsl_fdiv (0.0, 0.0);\n}\n\ndouble gsl_posinf (void)\n{\n  return gsl_fdiv (+1.0, 0.0);\n}\n\ndouble gsl_neginf (void)\n{\n  return gsl_fdiv (-1.0, 0.0);\n}\n\n\nint gsl_isnan (const double x);\nint gsl_isinf (const double x);\nint gsl_finite (const double x);\n\n#if defined(_MSC_VER) /* Microsoft Visual C++ */\n#include <float.h>\nint\ngsl_isnan (const double x)\n{\n  return _isnan(x);\n}\n\nint\ngsl_isinf (const double x)\n{\n  int fpc = _fpclass(x);\n\n  if (fpc == _FPCLASS_PINF)\n    return +1;\n  else if (fpc == _FPCLASS_NINF)\n    return -1;\n  else \n    return 0;\n}\n\nint\ngsl_finite (const double x)\n{\n  return _finite(x);\n}\n#else\n\n# if HAVE_DECL_ISFINITE\nint\ngsl_finite (const double x)\n{\n  return isfinite(x);\n}\n# elif HAVE_DECL_FINITE\nint\ngsl_finite (const double x)\n{\n  return finite(x);\n}\n# elif HAVE_IEEE_COMPARISONS\nint\ngsl_finite (const double x)\n{\n  const double y = x - x;\n  int status = (y == y);\n  return status;\n}\n# else\n# error \"cannot define gsl_finite without HAVE_DECL_FINITE or HAVE_IEEE_COMPARISONS\"\n# endif\n\n# if HAVE_DECL_ISNAN\nint\ngsl_isnan (const double x)\n{\n  return isnan(x);\n}\n#elif HAVE_IEEE_COMPARISONS\nint\ngsl_isnan (const double x)\n{\n  int status = (x != x);\n  return status;\n}\n# else\n# error \"cannot define gsl_isnan without HAVE_DECL_ISNAN or HAVE_IEEE_COMPARISONS\"\n# endif\n\n# if HAVE_DECL_ISINF\nint\ngsl_isinf (const double x)\n{\n  /* isinf(3): In glibc 2.01 and earlier, isinf() returns a\n     non-zero value (actually: 1) if x is an infinity (positive or\n     negative).  (This is all that C99 requires.) */\n\n  if (isinf(x)) \n    {\n      return (x > 0) ? 1 : -1;\n    } \n  else \n    {\n      return 0;\n    }\n}\n# else\n\nint\ngsl_isinf (const double x)\n{\n  if (! gsl_finite(x) && ! gsl_isnan(x)) \n    {\n      return (x > 0 ? +1 : -1); \n    } \n  else \n    {\n      return 0;\n    }\n}\n\n# endif\n#endif\n\n"
  },
  {
    "path": "gsl/sys/minmax.c",
    "content": "/* sys/minmax.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_minmax.h\"\n\n/* Define some static functions which are always available */\n\ndouble gsl_max (double a, double b)\n{\n  return GSL_MAX (a, b);\n}\n\ndouble gsl_min (double a, double b)\n{\n  return GSL_MIN (a, b);\n}\n\n"
  },
  {
    "path": "gsl/sys/pow_int.c",
    "content": "/* sys/pow_int.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n#include \"config.h\"\n#include <math.h>\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_pow_int.h\"\n\ndouble gsl_pow_int(double x, int n)\n{\n  unsigned int un;\n\n  if(n < 0) {\n    x = 1.0/x;\n    un = -n;\n  } else {\n    un = n;\n  }\n\n  return gsl_pow_uint(x, un);\n}\n\ndouble gsl_pow_uint(double x, unsigned int n)\n{\n  double value = 1.0;\n\n  /* repeated squaring method \n   * returns 0.0^0 = 1.0, so continuous in x\n   */\n  do {\n     if(n & 1) value *= x;  /* for n odd */\n     n >>= 1;\n     x *= x;\n  } while (n);\n\n  return value;\n}\n"
  },
  {
    "path": "gsl/templates_off.h",
    "content": "#ifdef FUNCTION\n#undef FUNCTION\n#endif\n\n#ifdef CONCAT4\n#undef CONCAT4\n#endif\n\n#ifdef CONCAT4x\n#undef CONCAT4x\n#endif\n\n#ifdef CONCAT3\n#undef CONCAT3\n#endif\n\n#ifdef CONCAT3x\n#undef CONCAT3x\n#endif\n\n#ifdef CONCAT2\n#undef CONCAT2\n#endif\n\n#ifdef CONCAT2x\n#undef CONCAT2x\n#endif\n\n#ifdef TYPE\n#undef TYPE\n#endif\n\n#ifdef REAL_TYPE\n#undef REAL_TYPE\n#endif\n\n#ifdef QUALIFIED_TYPE\n#undef QUALIFIED_TYPE\n#endif\n\n#ifdef VIEW\n#undef VIEW\n#endif\n\n#ifdef REAL_VIEW\n#undef REAL_VIEW\n#endif\n\n#ifdef QUALIFIED_VIEW\n#undef QUALIFIED_VIEW\n#endif\n\n#ifdef QUALIFIED_REAL_TYPE\n#undef QUALIFIED_REAL_TYPE\n#endif\n\n#ifdef QUALIFIED_REAL_VIEW\n#undef QUALIFIED_REAL_VIEW\n#endif\n\n#ifdef USES_LONGDOUBLE\n#undef USES_LONGDOUBLE\n#endif\n\n#ifdef SHORT_REAL\n#undef SHORT_REAL\n#endif\n\n#ifndef USE_QUALIFIER\n#ifdef QUALIFIER\n#undef QUALIFIER\n#endif\n#endif\n\n#undef BASE\n#undef BASE_EPSILON\n#undef SHORT\n#undef ATOMIC\n#undef MULTIPLICITY\n#undef IN_FORMAT\n#undef OUT_FORMAT\n#undef ATOMIC_IO\n#undef ZERO\n#undef ONE\n#undef NAME\n#undef STRING\n#undef EXPAND\n#undef UNSIGNED\n\n#ifdef FP\n#undef FP\n#endif\n"
  },
  {
    "path": "gsl/templates_on.h",
    "content": "/* If BASE is undefined we use function names like gsl_name()\n   and assume that we are using doubles.\n\n   If BASE is defined we used function names like gsl_BASE_name()\n   and use BASE as the base datatype      */\n\n#if   defined(BASE_GSL_COMPLEX_LONG)\n#define BASE gsl_complex_long_double\n#define SHORT complex_long_double\n#define SHORT_REAL long_double\n#define ATOMIC long double\n#define USES_LONGDOUBLE 1\n#define MULTIPLICITY 2\n#define FP 1\n#define IN_FORMAT \"%Lg\"\n#define OUT_FORMAT \"%Lg\"\n#define ATOMIC_IO ATOMIC\n#define ZERO {{0.0L,0.0L}}\n#define ONE {{1.0L,0.0L}}\n#define BASE_EPSILON GSL_DBL_EPSILON\n\n#elif defined(BASE_GSL_COMPLEX)\n#if defined(_MSC_VER) && defined(complex)\n#undef complex\n#endif\n#define BASE gsl_complex\n#define SHORT complex\n#define SHORT_REAL\n#define ATOMIC double\n#define MULTIPLICITY 2\n#define FP 1\n#define IN_FORMAT \"%lg\"\n#define OUT_FORMAT \"%g\"\n#define ATOMIC_IO ATOMIC\n#define ZERO {{0.0,0.0}}\n#define ONE {{1.0,0.0}}\n#define BASE_EPSILON GSL_DBL_EPSILON\n\n#elif defined(BASE_GSL_COMPLEX_FLOAT)\n#define BASE gsl_complex_float\n#define SHORT complex_float\n#define SHORT_REAL float\n#define ATOMIC float\n#define MULTIPLICITY 2\n#define FP 1\n#define IN_FORMAT \"%g\"\n#define OUT_FORMAT \"%g\"\n#define ATOMIC_IO ATOMIC\n#define ZERO {{0.0F,0.0F}}\n#define ONE {{1.0F,0.0F}}\n#define BASE_EPSILON GSL_FLT_EPSILON\n\n#elif defined(BASE_LONG_DOUBLE)\n#define BASE long double\n#define SHORT long_double\n#define ATOMIC long double\n#define USES_LONGDOUBLE 1\n#define MULTIPLICITY 1\n#define FP 1\n#define IN_FORMAT \"%Lg\"\n#define OUT_FORMAT \"%Lg\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0.0L\n#define ONE 1.0L\n#define BASE_EPSILON GSL_DBL_EPSILON\n\n#elif defined(BASE_DOUBLE)\n#define BASE double\n#define SHORT\n#define ATOMIC double\n#define MULTIPLICITY 1\n#define FP 1\n#define IN_FORMAT \"%lg\"\n#define OUT_FORMAT \"%g\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0.0\n#define ONE 1.0\n#define BASE_EPSILON GSL_DBL_EPSILON\n\n#elif defined(BASE_FLOAT)\n#define BASE float\n#define SHORT float\n#define ATOMIC float\n#define MULTIPLICITY 1\n#define FP 1\n#define IN_FORMAT \"%g\"\n#define OUT_FORMAT \"%g\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0.0F\n#define ONE 1.0F\n#define BASE_EPSILON GSL_FLT_EPSILON\n\n#elif defined(BASE_ULONG)\n#define BASE unsigned long\n#define SHORT ulong\n#define ATOMIC unsigned long\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%lu\"\n#define OUT_FORMAT \"%lu\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0UL\n#define ONE 1UL\n#define UNSIGNED 1\n\n#elif defined(BASE_LONG)\n#define BASE long\n#define SHORT long\n#define ATOMIC long\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%ld\"\n#define OUT_FORMAT \"%ld\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0L\n#define ONE 1L\n\n#elif defined(BASE_UINT)\n#define BASE unsigned int\n#define SHORT uint\n#define ATOMIC unsigned int\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%u\"\n#define OUT_FORMAT \"%u\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0U\n#define ONE 1U\n#define UNSIGNED 1\n\n#elif defined(BASE_INT)\n#define BASE int\n#define SHORT int\n#define ATOMIC int\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%d\"\n#define OUT_FORMAT \"%d\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0\n#define ONE 1\n\n#elif defined(BASE_USHORT)\n#define BASE unsigned short\n#define SHORT ushort\n#define ATOMIC unsigned short\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%hu\"\n#define OUT_FORMAT \"%hu\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0U\n#define ONE 1U\n#define UNSIGNED 1\n\n#elif defined(BASE_SHORT)\n#define BASE short\n#define SHORT short\n#define ATOMIC short\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%hd\"\n#define OUT_FORMAT \"%hd\"\n#define ATOMIC_IO ATOMIC\n#define ZERO 0\n#define ONE 1\n\n#elif defined(BASE_UCHAR)\n#define BASE unsigned char\n#define SHORT uchar\n#define ATOMIC unsigned char\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%u\"\n#define OUT_FORMAT \"%u\"\n#define ATOMIC_IO unsigned int\n#define ZERO 0U\n#define ONE 1U\n#define UNSIGNED 1\n\n#elif defined(BASE_CHAR)\n#define BASE char\n#define SHORT char\n#define ATOMIC char\n#define MULTIPLICITY 1\n#define IN_FORMAT \"%d\"\n#define OUT_FORMAT \"%d\"\n#define ATOMIC_IO int\n#define ZERO 0\n#define ONE 1\n#ifdef __CHAR_UNSIGNED__\n#define UNSIGNED 1\n#endif\n\n#else\n#error unknown BASE_ directive in source.h\n#endif\n\n#define CONCAT2x(a,b) a ## _ ## b \n#define CONCAT2(a,b) CONCAT2x(a,b)\n#define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c\n#define CONCAT3(a,b,c) CONCAT3x(a,b,c)\n#define CONCAT4x(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d\n#define CONCAT4(a,b,c,d) CONCAT4x(a,b,c,d)\n\n#ifndef USE_QUALIFIER\n#define QUALIFIER\n#endif\n\n#ifdef USE_QUALIFIER\n#if defined(BASE_DOUBLE)\n#define FUNCTION(dir,name) CONCAT3(dir,QUALIFIER,name)\n#define TYPE(dir) dir\n#define VIEW(dir,name) CONCAT2(dir,name)\n#define QUALIFIED_TYPE(dir) QUALIFIER dir\n#define QUALIFIED_VIEW(dir,name) CONCAT3(dir,QUALIFIER,name)\n#else\n#define FUNCTION(a,c) CONCAT4(a,SHORT,QUALIFIER,c)\n#define TYPE(dir) CONCAT2(dir,SHORT)\n#define VIEW(dir,name) CONCAT3(dir,SHORT,name)\n#define QUALIFIED_TYPE(dir) QUALIFIER CONCAT2(dir,SHORT)\n#define QUALIFIED_VIEW(dir,name) CONCAT4(dir,SHORT,QUALIFIER,name)\n#endif\n#if defined(BASE_GSL_COMPLEX)\n#define REAL_TYPE(dir) dir\n#define REAL_VIEW(dir,name) CONCAT2(dir,name)\n#define QUALIFIED_REAL_TYPE(dir) QUALIFIER dir\n#define QUALIFIED_REAL_VIEW(dir,name) CONCAT3(dir,QUALIFIER,name)\n#else\n#define REAL_TYPE(dir) CONCAT2(dir,SHORT_REAL)\n#define REAL_VIEW(dir,name) CONCAT3(dir,SHORT_REAL,name)\n#define QUALIFIED_REAL_TYPE(dir) QUALIFIER CONCAT2(dir,SHORT_REAL)\n#define QUALIFIED_REAL_VIEW(dir,name) CONCAT4(dir,SHORT_REAL,QUALIFIER,name)\n#endif\n#else\n#if defined(BASE_DOUBLE)\n#define FUNCTION(dir,name) CONCAT2(dir,name)\n#define TYPE(dir) dir\n#define VIEW(dir,name) CONCAT2(dir,name)\n#define QUALIFIED_TYPE(dir) TYPE(dir)\n#define QUALIFIED_VIEW(dir,name) CONCAT2(dir,name)\n#else\n#define FUNCTION(a,c) CONCAT3(a,SHORT,c)\n#define TYPE(dir) CONCAT2(dir,SHORT)\n#define VIEW(dir,name) CONCAT3(dir,SHORT,name)\n#define QUALIFIED_TYPE(dir) TYPE(dir)\n#define QUALIFIED_VIEW(dir,name) CONCAT3(dir,SHORT,name)\n#endif\n#if defined(BASE_GSL_COMPLEX)\n#define REAL_TYPE(dir) dir\n#define REAL_VIEW(dir,name) CONCAT2(dir,name)\n#define QUALIFIED_REAL_TYPE(dir) dir\n#define QUALIFIED_REAL_VIEW(dir,name) CONCAT2(dir,name)\n#else\n#define REAL_TYPE(dir) CONCAT2(dir,SHORT_REAL)\n#define REAL_VIEW(dir,name) CONCAT3(dir,SHORT_REAL,name)\n#define QUALIFIED_REAL_TYPE(dir) CONCAT2(dir,SHORT_REAL)\n#define QUALIFIED_REAL_VIEW(dir,name) CONCAT3(dir,SHORT_REAL,name)\n#endif\n#endif\n\n#define STRING(x) #x\n#define EXPAND(x) STRING(x)\n#define NAME(x) EXPAND(TYPE(x))\n"
  },
  {
    "path": "gsl/vector/copy.c",
    "content": "#include \"config.h\"\n#include \"gsl_vector.h\"\n#include \"gsl_errno.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"copy_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"copy_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/vector/copy_source.inc",
    "content": "/* vector/copy_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nint\nFUNCTION (gsl_vector, memcpy) (TYPE (gsl_vector) * dest,\n                               const TYPE (gsl_vector) * src)\n{\n  const size_t src_size = src->size;\n  const size_t dest_size = dest->size;\n\n  if (src_size != dest_size)\n    {\n      GSL_ERROR (\"vector lengths are not equal\", GSL_EBADLEN);\n    }\n\n  {\n    const size_t src_stride = src->stride ;\n    const size_t dest_stride = dest->stride ;\n    size_t j;\n\n    for (j = 0; j < src_size; j++)\n      {\n        size_t k;\n\n        for (k = 0; k < MULTIPLICITY; k++) \n          {\n            dest->data[MULTIPLICITY * dest_stride * j + k] \n              = src->data[MULTIPLICITY * src_stride * j + k];\n          }\n      }\n  }\n\n  return GSL_SUCCESS;\n}\n\n"
  },
  {
    "path": "gsl/vector/gsl_vector.h",
    "content": "#ifndef __GSL_VECTOR_H__\n#define __GSL_VECTOR_H__\n\n//#include <gsl/gsl_vector_complex_long_double.h>\n//#include <gsl/gsl_vector_complex_double.h>\n//#include <gsl/gsl_vector_complex_float.h>\n\n//#include <gsl/gsl_vector_long_double.h>\n#include \"gsl_vector_double.h\"\n//#include <gsl/gsl_vector_float.h>\n\n//#include <gsl/gsl_vector_ulong.h>\n//#include <gsl/gsl_vector_long.h>\n\n//#include <gsl/gsl_vector_uint.h>\n//#include <gsl/gsl_vector_int.h>\n\n//#include <gsl/gsl_vector_ushort.h>\n//#include <gsl/gsl_vector_short.h>\n\n//#include <gsl/gsl_vector_uchar.h>\n//#include <gsl/gsl_vector_char.h>\n\n\n#endif /* __GSL_VECTOR_H__ */\n"
  },
  {
    "path": "gsl/vector/gsl_vector_double.h",
    "content": "/* vector/gsl_vector_double.h\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#ifndef __GSL_VECTOR_DOUBLE_H__\n#define __GSL_VECTOR_DOUBLE_H__\n\n#include <stdlib.h>\n#include \"gsl_types.h\"\n#include \"gsl_errno.h\"\n#include \"gsl_inline.h\"\n#include \"gsl_check_range.h\"\n#include \"gsl_block_double.h\"\n\n#undef __BEGIN_DECLS\n#undef __END_DECLS\n#ifdef __cplusplus\n# define __BEGIN_DECLS extern \"C\" {\n# define __END_DECLS }\n#else\n# define __BEGIN_DECLS /* empty */\n# define __END_DECLS /* empty */\n#endif\n\n__BEGIN_DECLS\n\ntypedef struct \n{\n  size_t size;\n  size_t stride;\n  double *data;\n  gsl_block *block;\n  int owner;\n} \ngsl_vector;\n\ntypedef struct\n{\n  gsl_vector vector;\n} _gsl_vector_view;\n\ntypedef _gsl_vector_view gsl_vector_view;\n\ntypedef struct\n{\n  gsl_vector vector;\n} _gsl_vector_const_view;\n\ntypedef const _gsl_vector_const_view gsl_vector_const_view;\n\n\n/* Allocation */\n\ngsl_vector *gsl_vector_alloc (const size_t n);\ngsl_vector *gsl_vector_calloc (const size_t n);\n\ngsl_vector *gsl_vector_alloc_from_block (gsl_block * b,\n                                                     const size_t offset, \n                                                     const size_t n, \n                                                     const size_t stride);\n\ngsl_vector *gsl_vector_alloc_from_vector (gsl_vector * v,\n                                                      const size_t offset, \n                                                      const size_t n, \n                                                      const size_t stride);\n\nvoid gsl_vector_free (gsl_vector * v);\n\n/* Views */\n\n_gsl_vector_view \ngsl_vector_view_array (double *v, size_t n);\n\n_gsl_vector_view \ngsl_vector_view_array_with_stride (double *base,\n                                         size_t stride,\n                                         size_t n);\n\n_gsl_vector_const_view \ngsl_vector_const_view_array (const double *v, size_t n);\n\n_gsl_vector_const_view \ngsl_vector_const_view_array_with_stride (const double *base,\n                                               size_t stride,\n                                               size_t n);\n\n_gsl_vector_view \ngsl_vector_subvector (gsl_vector *v, \n                            size_t i, \n                            size_t n);\n\n_gsl_vector_view \ngsl_vector_subvector_with_stride (gsl_vector *v, \n                                        size_t i,\n                                        size_t stride,\n                                        size_t n);\n\n_gsl_vector_const_view \ngsl_vector_const_subvector (const gsl_vector *v, \n                                  size_t i, \n                                  size_t n);\n\n_gsl_vector_const_view \ngsl_vector_const_subvector_with_stride (const gsl_vector *v, \n                                              size_t i, \n                                              size_t stride,\n                                              size_t n);\n\n/* Operations */\n\nvoid gsl_vector_set_zero (gsl_vector * v);\nvoid gsl_vector_set_all (gsl_vector * v, double x);\nint gsl_vector_set_basis (gsl_vector * v, size_t i);\n\nint gsl_vector_fread (FILE * stream, gsl_vector * v);\nint gsl_vector_fwrite (FILE * stream, const gsl_vector * v);\nint gsl_vector_fscanf (FILE * stream, gsl_vector * v);\nint gsl_vector_fprintf (FILE * stream, const gsl_vector * v,\n                              const char *format);\n\nint gsl_vector_memcpy (gsl_vector * dest, const gsl_vector * src);\n\nint gsl_vector_reverse (gsl_vector * v);\n\nint gsl_vector_swap (gsl_vector * v, gsl_vector * w);\nint gsl_vector_swap_elements (gsl_vector * v, const size_t i, const size_t j);\n\ndouble gsl_vector_max (const gsl_vector * v);\ndouble gsl_vector_min (const gsl_vector * v);\nvoid gsl_vector_minmax (const gsl_vector * v, double * min_out, double * max_out);\n\nsize_t gsl_vector_max_index (const gsl_vector * v);\nsize_t gsl_vector_min_index (const gsl_vector * v);\nvoid gsl_vector_minmax_index (const gsl_vector * v, size_t * imin, size_t * imax);\n\nint gsl_vector_add (gsl_vector * a, const gsl_vector * b);\nint gsl_vector_sub (gsl_vector * a, const gsl_vector * b);\nint gsl_vector_mul (gsl_vector * a, const gsl_vector * b);\nint gsl_vector_div (gsl_vector * a, const gsl_vector * b);\nint gsl_vector_scale (gsl_vector * a, const double x);\nint gsl_vector_add_constant (gsl_vector * a, const double x);\n\nint gsl_vector_equal (const gsl_vector * u, \n                            const gsl_vector * v);\n\nint gsl_vector_isnull (const gsl_vector * v);\nint gsl_vector_ispos (const gsl_vector * v);\nint gsl_vector_isneg (const gsl_vector * v);\nint gsl_vector_isnonneg (const gsl_vector * v);\n\nINLINE_DECL double gsl_vector_get (const gsl_vector * v, const size_t i);\nINLINE_DECL void gsl_vector_set (gsl_vector * v, const size_t i, double x);\nINLINE_DECL double * gsl_vector_ptr (gsl_vector * v, const size_t i);\nINLINE_DECL const double * gsl_vector_const_ptr (const gsl_vector * v, const size_t i);\n\n#ifdef HAVE_INLINE\n\nINLINE_FUN\ndouble\ngsl_vector_get (const gsl_vector * v, const size_t i)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(i >= v->size))\n    {\n      GSL_ERROR_VAL (\"index out of range\", GSL_EINVAL, 0);\n    }\n#endif\n  return v->data[i * v->stride];\n}\n\nINLINE_FUN\nvoid\ngsl_vector_set (gsl_vector * v, const size_t i, double x)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(i >= v->size))\n    {\n      GSL_ERROR_VOID (\"index out of range\", GSL_EINVAL);\n    }\n#endif\n  v->data[i * v->stride] = x;\n}\n\nINLINE_FUN\ndouble *\ngsl_vector_ptr (gsl_vector * v, const size_t i)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(i >= v->size))\n    {\n      GSL_ERROR_NULL (\"index out of range\", GSL_EINVAL);\n    }\n#endif\n  return (double *) (v->data + i * v->stride);\n}\n\nINLINE_FUN\nconst double *\ngsl_vector_const_ptr (const gsl_vector * v, const size_t i)\n{\n#if GSL_RANGE_CHECK\n  if (GSL_RANGE_COND(i >= v->size))\n    {\n      GSL_ERROR_NULL (\"index out of range\", GSL_EINVAL);\n    }\n#endif\n  return (const double *) (v->data + i * v->stride);\n}\n#endif /* HAVE_INLINE */\n\n__END_DECLS\n\n#endif /* __GSL_VECTOR_DOUBLE_H__ */\n\n\n"
  },
  {
    "path": "gsl/vector/init.c",
    "content": "#include \"config.h\"\n#include <stdlib.h>\n#include <string.h>\n#include \"gsl_vector.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"init_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"init_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/vector/init_source.inc",
    "content": "/* vector/init_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nTYPE (gsl_vector) *\nFUNCTION (gsl_vector, alloc) (const size_t n)\n{\n  TYPE (gsl_block) * block;\n  TYPE (gsl_vector) * v;\n\n  v = (TYPE (gsl_vector) *) malloc (sizeof (TYPE (gsl_vector)));\n\n  if (v == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for vector struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  block = FUNCTION (gsl_block,alloc) (n);\n\n  if (block == 0)\n    {\n      free (v) ;\n\n      GSL_ERROR_VAL (\"failed to allocate space for block\",\n                        GSL_ENOMEM, 0);\n    }\n\n  v->data = block->data ;\n  v->size = n;\n  v->stride = 1;\n  v->block = block;\n  v->owner = 1;\n\n  return v;\n}\n\nTYPE (gsl_vector) *\nFUNCTION (gsl_vector, calloc) (const size_t n)\n{\n  size_t i;\n\n  TYPE (gsl_vector) * v = FUNCTION (gsl_vector, alloc) (n);\n\n  if (v == 0)\n    return 0;\n\n  /* initialize vector to zero; memset takes care of the padding bytes */\n  memset(v->data, 0, MULTIPLICITY * n * sizeof(ATOMIC));\n\n  for (i = 0; i < MULTIPLICITY * n; i++)\n    {\n      v->data[i] = 0;\n    }\n\n  return v;\n}\n\nTYPE (gsl_vector) *\nFUNCTION (gsl_vector, alloc_from_block) (TYPE(gsl_block) * block, \n                                         const size_t offset, \n                                         const size_t n, \n                                         const size_t stride)\n{\n  TYPE (gsl_vector) * v;\n\n  if (stride == 0)\n    {\n      GSL_ERROR_VAL (\"stride must be positive integer\", GSL_EINVAL, 0);\n    }\n\n  if (block->size <= offset + (n > 0 ? n - 1 : 0) * stride)\n    {\n      GSL_ERROR_VAL (\"vector would extend past end of block\", GSL_EINVAL, 0);\n    }\n\n  v = (TYPE (gsl_vector) *) malloc (sizeof (TYPE (gsl_vector)));\n\n  if (v == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for vector struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  v->data = block->data + MULTIPLICITY * offset ;\n  v->size = n;\n  v->stride = stride;\n  v->block = block;\n  v->owner = 0;\n\n  return v;\n}\n\nTYPE (gsl_vector) *\nFUNCTION (gsl_vector, alloc_from_vector) (TYPE(gsl_vector) * w, \n                                         const size_t offset, \n                                         const size_t n, \n                                         const size_t stride)\n{\n  TYPE (gsl_vector) * v;\n\n  if (stride == 0)\n    {\n      GSL_ERROR_VAL (\"stride must be positive integer\", GSL_EINVAL, 0);\n    }\n\n  if (offset + (n > 0 ? n - 1 : 0) * stride >= w->size)\n    {\n      GSL_ERROR_VAL (\"vector would extend past end of block\", GSL_EINVAL, 0);\n    }\n\n  v = (TYPE (gsl_vector) *) malloc (sizeof (TYPE (gsl_vector)));\n\n  if (v == 0)\n    {\n      GSL_ERROR_VAL (\"failed to allocate space for vector struct\",\n                        GSL_ENOMEM, 0);\n    }\n\n  v->data = w->data + MULTIPLICITY * w->stride * offset ;\n  v->size = n;\n  v->stride = stride * w->stride;\n  v->block = w->block;\n  v->owner = 0;\n\n  return v;\n}\n\n\nvoid\nFUNCTION (gsl_vector, free) (TYPE (gsl_vector) * v)\n{\n  RETURN_IF_NULL (v);\n\n  if (v->owner)\n    {\n      FUNCTION(gsl_block, free) (v->block) ;\n    }\n  free (v);\n}\n\n\nvoid\nFUNCTION (gsl_vector, set_all) (TYPE (gsl_vector) * v, BASE x)\n{\n  ATOMIC * const data = v->data;\n  const size_t n = v->size;\n  const size_t stride = v->stride;\n\n  size_t i;\n\n  for (i = 0; i < n; i++)\n    {\n      *(BASE *) (data + MULTIPLICITY * i * stride) = x;\n    }\n}\n\nvoid\nFUNCTION (gsl_vector, set_zero) (TYPE (gsl_vector) * v)\n{\n  ATOMIC * const data = v->data;\n  const size_t n = v->size;\n  const size_t stride = v->stride;\n  const BASE zero = ZERO ;\n\n  size_t i;\n\n  for (i = 0; i < n; i++)\n    {\n      *(BASE *) (data + MULTIPLICITY * i * stride) = zero;\n    }\n}\n\nint\nFUNCTION (gsl_vector, set_basis) (TYPE (gsl_vector) * v, size_t i)\n{\n  ATOMIC * const data = v->data;\n  const size_t n = v->size;\n  const size_t stride = v->stride;\n  const BASE zero = ZERO ;\n  const BASE one = ONE;\n\n  size_t k;\n\n  if (i >= n)\n    {\n      GSL_ERROR (\"index out of range\", GSL_EINVAL);\n    }\n\n  for (k = 0; k < n; k++)\n    {\n      *(BASE *) (data + MULTIPLICITY * k * stride) = zero;\n    }\n\n  *(BASE *) (data + MULTIPLICITY * i * stride) = one;\n\n  return GSL_SUCCESS;\n}\n"
  },
  {
    "path": "gsl/vector/oper.c",
    "content": "#include \"config.h\"\n#include <stdlib.h>\n#include <math.h>\n#include \"gsl_math.h\"\n#include \"gsl_vector.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"oper_complex_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"oper_complex_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"oper_complex_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"oper_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"oper_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n\n\n"
  },
  {
    "path": "gsl/vector/oper_source.inc",
    "content": "/* vector/oper_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nint \nFUNCTION(gsl_vector, add) (TYPE(gsl_vector) * a, const TYPE(gsl_vector) * b)\n{\n  const size_t N = a->size;\n\n  if (b->size != N)\n    {\n      GSL_ERROR (\"vectors must have same length\", GSL_EBADLEN);\n    }\n  else \n    {\n      const size_t stride_a = a->stride;\n      const size_t stride_b = b->stride;\n\n      size_t i;\n\n      for (i = 0; i < N; i++)\n        {\n          a->data[i * stride_a] += b->data[i * stride_b];\n        }\n      \n      return GSL_SUCCESS;\n    }\n}\n\nint \nFUNCTION(gsl_vector, sub) (TYPE(gsl_vector) * a, const TYPE(gsl_vector) * b)\n{\n  const size_t N = a->size;\n\n  if (b->size != N)\n    {\n      GSL_ERROR (\"vectors must have same length\", GSL_EBADLEN);\n    }\n  else \n    {\n      const size_t stride_a = a->stride;\n      const size_t stride_b = b->stride;\n\n      size_t i;\n\n      for (i = 0; i < N; i++)\n        {\n          a->data[i * stride_a] -= b->data[i * stride_b];\n        }\n      \n      return GSL_SUCCESS;\n    }\n}\n\nint \nFUNCTION(gsl_vector, mul) (TYPE(gsl_vector) * a, const TYPE(gsl_vector) * b)\n{\n  const size_t N = a->size;\n\n  if (b->size != N)\n    {\n      GSL_ERROR (\"vectors must have same length\", GSL_EBADLEN);\n    }\n  else \n    {\n      const size_t stride_a = a->stride;\n      const size_t stride_b = b->stride;\n\n      size_t i;\n\n      for (i = 0; i < N; i++)\n        {\n          a->data[i * stride_a] *= b->data[i * stride_b];\n        }\n      \n      return GSL_SUCCESS;\n    }\n}\n\nint \nFUNCTION(gsl_vector, div) (TYPE(gsl_vector) * a, const TYPE(gsl_vector) * b)\n{\n  const size_t N = a->size;\n\n  if (b->size != N)\n    {\n      GSL_ERROR (\"vectors must have same length\", GSL_EBADLEN);\n    }\n  else \n    {\n      const size_t stride_a = a->stride;\n      const size_t stride_b = b->stride;\n\n      size_t i;\n\n      for (i = 0; i < N; i++)\n        {\n          a->data[i * stride_a] /= b->data[i * stride_b];\n        }\n      \n      return GSL_SUCCESS;\n    }\n}\n\nint \nFUNCTION(gsl_vector, scale) (TYPE(gsl_vector) * a, const double x)\n{\n  const size_t N = a->size;\n  const size_t stride = a->stride;\n  \n  size_t i;\n  \n  for (i = 0; i < N; i++)\n    {\n      a->data[i * stride] *= x;\n    }\n  \n  return GSL_SUCCESS;\n}\n\nint \nFUNCTION(gsl_vector, add_constant) (TYPE(gsl_vector) * a, const double x)\n{\n  const size_t N = a->size;\n  const size_t stride = a->stride;\n  \n  size_t i;\n  \n  for (i = 0; i < N; i++)\n    {\n      a->data[i * stride] += x;\n    }\n  \n  return GSL_SUCCESS;\n}\n\n"
  },
  {
    "path": "gsl/vector/vector.c",
    "content": "/* vector/vector.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\n#include \"config.h\"\n#include \"gsl_errno.h\"\n\n/* Compile all the inline functions */\n\n#define COMPILE_INLINE_STATIC\n#include \"build.h\"\n#include \"gsl_vector.h\"\n\n/* turn on range checking at runtime (disabled if zero) */\nint gsl_check_range = 1;\n\n"
  },
  {
    "path": "gsl/vector/view.c",
    "content": "#include \"config.h\"\n#include <stdlib.h>\n#include \"gsl_vector.h\"\n\n#include \"view.h\"\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"view_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n\n#define USE_QUALIFIER\n#define QUALIFIER const\n\n/*#define BASE_GSL_COMPLEX_LONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_LONG\n\n#define BASE_GSL_COMPLEX\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX\n\n#define BASE_GSL_COMPLEX_FLOAT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_GSL_COMPLEX_FLOAT\n\n#define BASE_LONG_DOUBLE\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG_DOUBLE*/\n\n#define BASE_DOUBLE\n#include \"templates_on.h\"\n#include \"view_source.inc\"\n#include \"templates_off.h\"\n#undef  BASE_DOUBLE\n\n/*#define BASE_FLOAT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_FLOAT\n\n#define BASE_ULONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_ULONG\n\n#define BASE_LONG\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_LONG\n\n#define BASE_UINT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UINT\n\n#define BASE_INT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_INT\n\n#define BASE_USHORT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_USHORT\n\n#define BASE_SHORT\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_SHORT\n\n#define BASE_UCHAR\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_UCHAR\n\n#define BASE_CHAR\n#include \"templates_on.h\"\n#include \"view_source.c\"\n#include \"templates_off.h\"\n#undef  BASE_CHAR*/\n"
  },
  {
    "path": "gsl/vector/view.h",
    "content": "#define NULL_VECTOR {0, 0, 0, 0, 0}\n#define NULL_VECTOR_VIEW {{0, 0, 0, 0, 0}}\n"
  },
  {
    "path": "gsl/vector/view_source.inc",
    "content": "/* vector/view_source.c\n * \n * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2007 Gerard Jungman, Brian Gough\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or (at\n * your option) any later version.\n * \n * This program is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n */\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION(gsl_vector, view_array) (QUALIFIER ATOMIC * base, size_t n)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n\n    v.data = (ATOMIC *)base  ;\n    v.size = n;\n    v.stride = 1;\n    v.block = 0;\n    v.owner = 0;\n\n    view.vector = v;\n    return view;\n  }\n}\n\nQUALIFIED_VIEW(_gsl_vector,view)\nFUNCTION(gsl_vector, view_array_with_stride) (QUALIFIER ATOMIC * base, \n                                              size_t stride,\n                                              size_t n)\n{\n  QUALIFIED_VIEW(_gsl_vector,view) view = NULL_VECTOR_VIEW;\n\n  if (stride == 0)\n    {\n      GSL_ERROR_VAL (\"stride must be positive integer\", \n                     GSL_EINVAL, view);\n    }\n\n  {\n    TYPE(gsl_vector) v = NULL_VECTOR;\n    \n    v.data = (ATOMIC *)base ;\n    v.size = n;\n    v.stride = stride;\n    v.block = 0;\n    v.owner = 0;\n\n    view.vector = v;\n    return view;\n  }\n}\n"
  },
  {
    "path": "simd_benchmarks/README.md",
    "content": "# SIMD Benchmarks\n\nThis directory contains benchmark scripts used during the development of SIMD optimizations for SLiM. These files are provided for internal development use and are **not used in the build of SLiM**.\n\n## Contents\n\n- **`run_benchmarks.sh`** - Shell script that builds SLiM with and without SIMD, runs both benchmark scripts, and reports speedup comparisons.\n\n- **`simd_benchmark.eidos`** - Eidos script that benchmarks SIMD-optimized math functions (`sqrt`, `abs`, `floor`, `ceil`, `round`, `trunc`, `sum`, `product`) on large arrays.\n\n- **`slim_benchmark.slim`** - SLiM simulation benchmark (N=5000, 1Mb chromosome, 5000 generations with selection) for measuring overall simulation performance.\n\n- **`dnorm_benchmark.eidos`** - Eidos script that benchmarks the SIMD-optimized `dnorm()` function with singleton and vector mu/sigma parameters.\n\n- **`benchmark_all_kernels.slim`** - SLiM script that benchmarks all 6 SIMD-optimized spatial interaction kernel types (Fixed, Linear, Exponential, Normal, Cauchy, Student's T).\n\n- **`SIMD_BUILD_FLAGS.md`** - Documentation on how SIMD and SLEEF build flags are set and interact.\n\nFor SLEEF header generation scripts and documentation, see `eidos/sleef/`.\n\n## Author\n\nThese benchmarks were developed by Andrew Kern as part of SIMD optimization work for SLiM.\n\n## Usage\n\nThese files are not part of the SLiM build system. To run the benchmarks:\n\n```bash\ncd simd_benchmarks\n./run_benchmarks.sh [num_runs]\n```\n\nThis will build both SIMD-enabled and scalar versions of SLiM, run the benchmarks, and report the speedup.\n\n## Results\n\nBenchmark results look like the following (example output):\n\n```\n$ simd_benchmarks/run_benchmarks.sh \n============================================\nSIMD Benchmark Runner\n============================================\nSLiM root: /home/adkern/SLiM\nRuns per benchmark: 3\n\nBuilding with SIMD enabled...\n  Done.\nBuilding with SIMD disabled...\n  Done.\n\n============================================\nEidos Math Function Benchmarks\n============================================\n\nSIMD Build:\n  Running Eidos benchmark (SIMD)...\n    sqrt():    0.105 sec\n    abs():     0.171 sec\n    floor():   0.164 sec\n    ceil():    0.166 sec\n    round():   0.164 sec\n    trunc():   0.165 sec\n    sum():     0.032 sec\n    product(): 0.003 sec (1000 elements, 10000 iters)\n\nScalar Build:\n  Running Eidos benchmark (Scalar)...\n    sqrt():    0.108 sec\n    abs():     0.166 sec\n    floor():   0.231 sec\n    ceil():    0.246 sec\n    round():   0.473 sec\n    trunc():   0.246 sec\n    sum():     0.166 sec\n    product(): 0.017 sec (1000 elements, 10000 iters)\n\n============================================\nSLiM Simulation Benchmark\n(N=5000, 5000 generations, selection)\n============================================\n\nRunning 3 iterations each...\n\nSIMD Build:   12.756s (avg)\nScalar Build: 12.316s (avg)\n\nSpeedup: .96x\n\n============================================\nBenchmark complete\n============================================\n```\nso the takeaway is that SIMD provided significant speedups for eidos math functions, while the overall SLiM simulation speedup was minimal in this specific benchmark scenario.\n\n## dnorm() Benchmark Results\n\nThe `dnorm()` function was optimized to batch `exp()` calls using SLEEF SIMD vectorization. Results on x86_64 with AVX2 (N=1,000,000 elements, 10 iterations):\n\n| Case | SIMD (M elem/s) | Scalar (M elem/s) | Speedup |\n|------|-----------------|-------------------|---------|\n| `dnorm(x, scalar, scalar)` | 119.9 | 43.7 | **2.74x** |\n| `dnorm(x, scalar, vector)` | 52.5 | 33.5 | **1.57x** |\n| `dnorm(x, vector, scalar)` | 56.8 | 34.3 | **1.66x** |\n| `dnorm(x, vector, vector)` | 41.7 | 28.2 | **1.48x** |\n\nThe single mu/sigma case shows the best speedup at 2.74x. Variable parameter cases have additional overhead from per-element lookups but still benefit from batched SIMD exp().\n\nTo run this benchmark:\n```bash\n# Build with SIMD\nmkdir build && cd build && cmake .. && make eidos\n./eidos ../simd_benchmarks/dnorm_benchmark.eidos\n\n# Build without SIMD for comparison\nmkdir build_nosimd && cd build_nosimd && cmake .. -DUSE_SIMD=OFF && make eidos\n./eidos ../simd_benchmarks/dnorm_benchmark.eidos\n```\n\n## Spatial Interaction Kernel Benchmark Results\n\nThe `benchmark_all_kernels.slim` script tests SIMD-optimized spatial interaction kernels. All kernel types except Fixed use a two-pass approach (build distances, then batch transform) enabling SIMD vectorization via SLEEF.\n\nResults on x86_64 with AVX2 (50,000 individuals, ~2,262 neighbors per individual, 30 generations):\n\n| Kernel | Original | SIMD | Speedup |\n|--------|----------|------|---------|\n| Fixed | 31.97s | 31.36s | 1.02x |\n| Linear | 37.26s | 32.95s | **1.13x** |\n| Exponential | 59.58s | 34.88s | **1.71x** |\n| Normal | 56.37s | 35.15s | **1.60x** |\n| Cauchy | 40.04s | 33.00s | **1.21x** |\n| Student's T | 130.10s | 49.76s | **2.61x** |\n| **Total** | **356.04s** | **217.80s** | **1.64x** |\n\nThe biggest gains come from kernels using transcendental functions:\n- **Student's T** (2.61x): Uses `pow()` via SLEEF\n- **Exponential/Normal** (1.6-1.7x): Use `exp()` via SLEEF\n- **Linear/Cauchy** (~1.1-1.2x): Simple arithmetic, modest gains from explicit SIMD\n- **Fixed** (1.02x): Uses special-case single-pass path (no benefit from two-pass)\n\nTo run this benchmark:\n```bash\n# Build with SIMD\nmkdir build && cd build && cmake .. && make slim\n./slim -s 42 ../simd_benchmarks/benchmark_all_kernels.slim\n\n# Build without SIMD for comparison\nmkdir build_nosimd && cd build_nosimd && cmake .. -DUSE_SIMD=OFF && make slim\n./slim -s 42 ../simd_benchmarks/benchmark_all_kernels.slim\n```\n\nAdjust `W` in the script to change neighbor density (W=25 for ~2200 neighbors, W=266 for ~20 neighbors).\n\n## SpatialMap smooth() vs smooth_fast() Benchmark Results\n\nI first wrote a benchmark to compare the original `smooth()` method with the new SIMD-optimized `smooth_fast()` method for SpatialMap convolution operations. Results on x86_64 with AVX2:\n\n\n### SIMD Build (AVX2+FMA)\n\n| Test | smooth() | smooth_fast() | Speedup |\n|------|----------|---------------|---------|\n| 1D 100 pts | 0.006ms | 0.002ms | **2.96x** |\n| 1D 1000 pts | 0.131ms | 0.031ms | **4.22x** |\n| 2D 50x50 | 0.349ms | 0.144ms | **2.43x** |\n| 2D 100x100 | 5.615ms | 1.202ms | **4.67x** |\n| 2D 200x200 | 88.485ms | 15.035ms | **5.89x** |\n| 3D 20x20x20 | 3.571ms | 1.589ms | **2.25x** |\n| 3D 30x30x30 | 12.394ms | 5.800ms | **2.14x** |\n\n### NO_SIMD Build (Scalar)\n\n| Test | smooth() | smooth_fast() | Speedup |\n|------|----------|---------------|---------|\n| 1D 100 pts | 0.006ms | 0.003ms | **2.24x** |\n| 1D 1000 pts | 0.097ms | 0.084ms | **1.16x** |\n| 2D 50x50 | 0.243ms | 0.167ms | **1.46x** |\n| 2D 100x100 | 3.595ms | 2.336ms | **1.54x** |\n| 2D 200x200 | 53.854ms | 39.838ms | **1.35x** |\n| 3D 20x20x20 | 4.130ms | 1.458ms | **2.83x** |\n| 3D 30x30x30 | 14.161ms | 5.283ms | **2.68x** |\n\n\nAs this speedup was significant, after conversations with Ben Haller, we decided to replace the original `smooth()` method with `smooth_fast()`. The benchmark script is now retired as the original method is no longer present in SLiM."
  },
  {
    "path": "simd_benchmarks/SIMD_BUILD_FLAGS.md",
    "content": "# SIMD and SLEEF Build Flags\n\nThis document explains how the SIMD and SLEEF build flags work and interact in the SLiM/Eidos codebase.\n\n## Author\nThese flags and configurations were developed by Andrew Kern as part of SIMD optimization work for SLiM.\n\n## Overview\n\nThere are three layers:\n1. **CMake options** - set at configure time\n2. **Compiler definitions** - passed via `-D` flags\n3. **Header conditionals** - control which code paths are compiled\n\n## Layer 1: CMake Configuration\n\nIn `CMakeLists.txt`:\n\n```cmake\noption(USE_SIMD \"Enable SIMD optimizations\" ON)  # User-controllable\n```\n\nWhen `USE_SIMD=ON` (default), CMake detects the platform and compiler capabilities:\n\n| Platform | Detection | Defines Set |\n|----------|-----------|-------------|\n| Linux/macOS x86_64 | Tests `-mavx2`, `-mfma` flags | `EIDOS_HAS_AVX2=1`, `EIDOS_HAS_FMA=1` |\n| Linux/macOS ARM64 | Always available | `EIDOS_HAS_NEON=1` |\n| Windows/MinGW | Tests `-mavx2`, `-mfma` flags | `EIDOS_HAS_AVX2=1`, `EIDOS_HAS_FMA=1` |\n| SSE4.2 only | Tests `-msse4.2` | `EIDOS_HAS_SSE42=1` |\n\n## Layer 2: Header Selection\n\nIn `eidos/eidos_simd.h` (around line 57):\n\n```cpp\n// Include SLEEF config if we have AVX2 or NEON\n#if defined(EIDOS_HAS_AVX2) || defined(EIDOS_HAS_NEON)\n#include \"sleef/sleef_config.h\"\n#endif\n```\n\nIn `eidos/sleef/sleef_config.h`:\n\n```cpp\n#ifndef EIDOS_SLEEF_AVAILABLE  // Allow command-line override\n\n#if defined(EIDOS_HAS_AVX2) && defined(EIDOS_HAS_FMA)\n    // AVX2+FMA path (Intel Haswell+, AMD Zen+)\n    #include \"sleefinline_avx2.h\"\n    #define EIDOS_SLEEF_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE 4        // 4 doubles per vector\n    #define EIDOS_SLEEF_EXP_D(v) Sleef_expd4_u10avx2(v)\n    // ... other function macros\n\n#elif defined(EIDOS_HAS_NEON)\n    // ARM NEON path (Apple Silicon, ARM64 Linux)\n    #include \"sleefinline_advsimd.h\"\n    #define EIDOS_SLEEF_AVAILABLE 1\n    #define EIDOS_SLEEF_VEC_SIZE 2        // 2 doubles per vector\n    #define EIDOS_SLEEF_EXP_D(v) Sleef_expd2_u10advsimd(v)\n    // ... other function macros\n\n#else\n    // Scalar fallback (SSE4.2-only or no SIMD)\n    #define EIDOS_SLEEF_AVAILABLE 0\n    #define EIDOS_SLEEF_VEC_SIZE 1\n#endif\n\n#endif // EIDOS_SLEEF_AVAILABLE\n```\n\n## Layer 3: Function Implementation\n\nIn `eidos/eidos_simd.h`, the actual functions use the macros:\n\n```cpp\ninline void exp_float64(const double *input, double *output, int64_t count)\n{\n    int64_t i = 0;\n\n#if EIDOS_SLEEF_AVAILABLE\n    // SIMD loop - process 4 (AVX2) or 2 (NEON) doubles at a time\n    for (; i + EIDOS_SLEEF_VEC_SIZE <= count; i += EIDOS_SLEEF_VEC_SIZE)\n    {\n        EIDOS_SLEEF_TYPE_D v = EIDOS_SLEEF_LOAD_D(&input[i]);\n        EIDOS_SLEEF_TYPE_D r = EIDOS_SLEEF_EXP_D(v);\n        EIDOS_SLEEF_STORE_D(&output[i], r);\n    }\n#endif\n\n    // Scalar remainder (always runs for leftover elements)\n    for (; i < count; i++)\n        output[i] = std::exp(input[i]);\n}\n```\n\n## Flag Interaction Summary\n\n```\nUSE_SIMD=ON (cmake)\n    │\n    ├─► x86_64 + AVX2 + FMA detected\n    │       │\n    │       ├─► -DEIDOS_HAS_AVX2=1 -DEIDOS_HAS_FMA=1 -mavx2 -mfma\n    │       │\n    │       └─► sleef_config.h sets EIDOS_SLEEF_AVAILABLE=1, VEC_SIZE=4\n    │               │\n    │               └─► exp_float64() uses Sleef_expd4_u10avx2() (4-wide)\n    │\n    ├─► ARM64 detected\n    │       │\n    │       ├─► -DEIDOS_HAS_NEON=1\n    │       │\n    │       └─► sleef_config.h sets EIDOS_SLEEF_AVAILABLE=1, VEC_SIZE=2\n    │               │\n    │               └─► exp_float64() uses Sleef_expd2_u10advsimd() (2-wide)\n    │\n    └─► SSE4.2-only or unknown\n            │\n            ├─► -DEIDOS_HAS_SSE42=1 (or nothing)\n            │\n            └─► sleef_config.h sets EIDOS_SLEEF_AVAILABLE=0\n                    │\n                    └─► exp_float64() uses std::exp() (scalar)\n\nUSE_SIMD=OFF (cmake)\n    │\n    └─► No EIDOS_HAS_* defined\n            │\n            └─► All SIMD disabled, scalar fallback everywhere\n```\n\n## Testing/Override\n\nYou can force SLEEF off for benchmarking:\n\n```bash\ncmake .. -DCMAKE_CXX_FLAGS=\"-DEIDOS_SLEEF_AVAILABLE=0\"\n```\n\nThis works because `sleef_config.h` checks `#ifndef EIDOS_SLEEF_AVAILABLE` before defining it.\n\n## What Uses SLEEF vs Hand-Written SIMD\n\n| Function | Implementation | Why |\n|----------|---------------|-----|\n| `exp`, `log`, `log10`, `log2` | **SLEEF** | Transcendentals need complex algorithms |\n| `sqrt`, `abs` | Hand-written SIMD | Hardware has direct instructions (`vsqrtpd`, bit ops) |\n| `floor`, `ceil`, `round`, `trunc` | Hand-written SIMD | Hardware rounding instructions |\n| `sum`, `product` | Hand-written SIMD | Simple accumulation + horizontal reduction |\n\n## Performance Results\n\nBenchmarks on 1M elements, 10 repetitions (x86_64 AVX2):\n\n| Function | Without SLEEF | With SLEEF | Speedup |\n|----------|---------------|------------|---------|\n| exp()    | 8.30 ms       | 4.05 ms    | **2.1x** |\n| log()    | 6.17 ms       | 3.37 ms    | **1.8x** |\n| log10()  | 10.79 ms      | 3.66 ms    | **2.9x** |\n| log2()   | 5.81 ms       | 3.99 ms    | **1.5x** |\n\n## Key Files\n\n- `CMakeLists.txt` - SIMD detection and flag setting (lines ~306-360)\n- `eidos/eidos_simd.h` - SIMD function implementations\n- `eidos/sleef/sleef_config.h` - SLEEF architecture selection\n- `eidos/sleef/sleefinline_avx2.h` - SLEEF AVX2 inline functions\n- `eidos/sleef/sleefinline_advsimd.h` - SLEEF ARM NEON inline functions\n- `cmake/toolchain-mingw64.cmake` - Windows cross-compilation toolchain\n"
  },
  {
    "path": "simd_benchmarks/benchmark_all_kernels.slim",
    "content": "// Comprehensive benchmark for ALL spatial interaction kernel types\n// Tests: Fixed, Linear, Exponential, Normal, Cauchy, Student's T\n\ninitialize() {\n    initializeSLiMModelType(\"WF\");\n    initializeSLiMOptions(dimensionality=\"xy\");\n\n    defineConstant(\"POP_SIZE\", 50000);\n    defineConstant(\"W\", 25.0);   // Medium density (~2262 neighbors with 50k)\n    defineConstant(\"SI\", 1.0);\n    defineConstant(\"GENS\", 30);\n\n    initializeMutationRate(0);\n    initializeRecombinationRate(0);\n    initializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n    initializeGenomicElementType(\"g1\", m1, 1.0);\n    initializeGenomicElement(g1, 0, 99);\n\n    // 1. Fixed kernel: strength = fmax (constant)\n    initializeInteractionType(1, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i1.setInteractionFunction(\"f\", 1.0);\n\n    // 2. Linear kernel: strength = fmax * (1 - d/maxDist)\n    initializeInteractionType(2, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i2.setInteractionFunction(\"l\", 1.0);\n\n    // 3. Exponential kernel: strength = fmax * exp(-lambda * d)\n    initializeInteractionType(3, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i3.setInteractionFunction(\"e\", 1.0, 1.0/SI);\n\n    // 4. Normal/Gaussian kernel: strength = fmax * exp(-d^2 / 2*sigma^2)\n    initializeInteractionType(4, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i4.setInteractionFunction(\"n\", 1.0, SI);\n\n    // 5. Cauchy kernel: strength = fmax / (1 + (d/scale)^2)\n    initializeInteractionType(5, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i5.setInteractionFunction(\"c\", 1.0, SI);\n\n    // 6. Student's T kernel\n    initializeInteractionType(6, \"xy\", reciprocal=T, maxDistance=SI * 3);\n    i6.setInteractionFunction(\"t\", 1.0, 5.0, SI);  // fmax, nu, scale\n}\n\n1 early() {\n    sim.addSubpop(\"p1\", POP_SIZE);\n    p1.setSpatialBounds(c(0, 0, W, W));\n\n    for (ind in p1.individuals) {\n        ind.setSpatialPosition(p1.pointUniform());\n    }\n\n    catn(\"================================================\");\n    catn(\"ALL KERNELS BENCHMARK (2D)\");\n    catn(\"================================================\");\n    catn(\"Population: \" + POP_SIZE + \" | World: \" + W + \"x\" + W);\n    density = POP_SIZE / (W^2);\n    avg_neighbors = density * PI * (SI*3)^2;\n    catn(\"Est. neighbors/ind: ~\" + format(\"%.0f\", avg_neighbors));\n    catn(\"Generations: \" + GENS);\n    catn(\"------------------------------------------------\");\n\n    defineGlobal(\"start_time\", clock());\n    defineGlobal(\"fixed_time\", 0.0);\n    defineGlobal(\"linear_time\", 0.0);\n    defineGlobal(\"exp_time\", 0.0);\n    defineGlobal(\"normal_time\", 0.0);\n    defineGlobal(\"cauchy_time\", 0.0);\n    defineGlobal(\"studentst_time\", 0.0);\n}\n\nearly() {\n    // Fixed\n    t0 = clock();\n    i1.evaluate(p1);\n    i1.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"fixed_time\", fixed_time + (clock() - t0));\n\n    // Linear\n    t0 = clock();\n    i2.evaluate(p1);\n    i2.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"linear_time\", linear_time + (clock() - t0));\n\n    // Exponential\n    t0 = clock();\n    i3.evaluate(p1);\n    i3.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"exp_time\", exp_time + (clock() - t0));\n\n    // Normal\n    t0 = clock();\n    i4.evaluate(p1);\n    i4.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"normal_time\", normal_time + (clock() - t0));\n\n    // Cauchy\n    t0 = clock();\n    i5.evaluate(p1);\n    i5.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"cauchy_time\", cauchy_time + (clock() - t0));\n\n    // Student's T\n    t0 = clock();\n    i6.evaluate(p1);\n    i6.totalOfNeighborStrengths(p1.individuals);\n    defineGlobal(\"studentst_time\", studentst_time + (clock() - t0));\n}\n\nlate() {\n    for (ind in p1.individuals) {\n        ind.setSpatialPosition(p1.pointUniform());\n    }\n}\n\n30 late() {\n    elapsed = clock() - start_time;\n\n    catn(\"\\n================================================\");\n    catn(\"RESULTS\");\n    catn(\"================================================\");\n    catn(\"Fixed:      \" + format(\"%6.3f\", fixed_time) + \" s\");\n    catn(\"Linear:     \" + format(\"%6.3f\", linear_time) + \" s\");\n    catn(\"Exponential:\" + format(\"%6.3f\", exp_time) + \" s\");\n    catn(\"Normal:     \" + format(\"%6.3f\", normal_time) + \" s\");\n    catn(\"Cauchy:     \" + format(\"%6.3f\", cauchy_time) + \" s\");\n    catn(\"Student's T:\" + format(\"%6.3f\", studentst_time) + \" s\");\n    catn(\"------------------------------------------------\");\n    catn(\"TOTAL:      \" + format(\"%6.3f\", elapsed) + \" s\");\n    catn(\"================================================\");\n    sim.simulationFinished();\n}\n"
  },
  {
    "path": "simd_benchmarks/dnorm_benchmark.eidos",
    "content": "// Benchmark dnorm() SIMD optimization\n// Tests both singleton and variable mu/sigma cases\n\ndefineGlobal(\"N\", 1000000);\ndefineGlobal(\"ITERS\", 10);\n\n// Generate test data\nx = rnorm(N, 0, 1);\n\ncatn(\"dnorm() SIMD Benchmark\");\ncatn(\"  N = \" + N + \", iterations = \" + ITERS);\ncatn(\"\");\n\n// Path 1: singleton mu and sigma (most common case)\nstart = clock();\nfor (i in 1:ITERS)\n\tresult = dnorm(x, 0.0, 1.0);\nelapsed = clock() - start;\ncatn(\"Path 1 - dnorm(x, scalar, scalar):\");\ncatn(\"  Time: \" + format(\"%.3f\", elapsed) + \"s for \" + ITERS + \" iterations\");\ncatn(\"  Throughput: \" + format(\"%.1f\", N * ITERS / elapsed / 1e6) + \" M elements/sec\");\ncatn(\"\");\n\n// Path 2a: variable sigma only\nsigmas = rep(1.0, N) + runif(N, -0.1, 0.1);\nstart = clock();\nfor (i in 1:ITERS)\n\tresult = dnorm(x, 0.0, sigmas);\nelapsed = clock() - start;\ncatn(\"Path 2a - dnorm(x, scalar, vector):\");\ncatn(\"  Time: \" + format(\"%.3f\", elapsed) + \"s for \" + ITERS + \" iterations\");\ncatn(\"  Throughput: \" + format(\"%.1f\", N * ITERS / elapsed / 1e6) + \" M elements/sec\");\ncatn(\"\");\n\n// Path 2b: variable mu only\nmus = runif(N, -0.1, 0.1);\nstart = clock();\nfor (i in 1:ITERS)\n\tresult = dnorm(x, mus, 1.0);\nelapsed = clock() - start;\ncatn(\"Path 2b - dnorm(x, vector, scalar):\");\ncatn(\"  Time: \" + format(\"%.3f\", elapsed) + \"s for \" + ITERS + \" iterations\");\ncatn(\"  Throughput: \" + format(\"%.1f\", N * ITERS / elapsed / 1e6) + \" M elements/sec\");\ncatn(\"\");\n\n// Path 2c: variable mu and sigma\nstart = clock();\nfor (i in 1:ITERS)\n\tresult = dnorm(x, mus, sigmas);\nelapsed = clock() - start;\ncatn(\"Path 2c - dnorm(x, vector, vector):\");\ncatn(\"  Time: \" + format(\"%.3f\", elapsed) + \"s for \" + ITERS + \" iterations\");\ncatn(\"  Throughput: \" + format(\"%.1f\", N * ITERS / elapsed / 1e6) + \" M elements/sec\");\n"
  },
  {
    "path": "simd_benchmarks/run_benchmarks.sh",
    "content": "#!/bin/bash\n# SIMD Benchmark Runner\n# Builds SLiM with and without SIMD, runs benchmarks, compares results\n\nset -e\n\nSLIM_ROOT=\"$(cd \"$(dirname \"$0\")/..\" && pwd)\"\nBENCHMARK_DIR=\"$SLIM_ROOT/simd_benchmarks\"\nBUILD_SIMD=\"$SLIM_ROOT/build_simd\"\nBUILD_SCALAR=\"$SLIM_ROOT/build_scalar\"\n\nNUM_RUNS=${1:-3}  # Default to 3 runs, or use first argument\n\necho \"============================================\"\necho \"SIMD Benchmark Runner\"\necho \"============================================\"\necho \"SLiM root: $SLIM_ROOT\"\necho \"Runs per benchmark: $NUM_RUNS\"\necho \"\"\n\n# Build with SIMD\necho \"Building with SIMD enabled...\"\nrm -rf \"$BUILD_SIMD\"\nmkdir -p \"$BUILD_SIMD\"\ncd \"$BUILD_SIMD\"\ncmake -DUSE_SIMD=ON -DCMAKE_BUILD_TYPE=Release .. > /dev/null\nmake -j10 > /dev/null 2>&1\necho \"  Done.\"\n\n# Build without SIMD\necho \"Building with SIMD disabled...\"\nrm -rf \"$BUILD_SCALAR\"\nmkdir -p \"$BUILD_SCALAR\"\ncd \"$BUILD_SCALAR\"\ncmake -DUSE_SIMD=OFF -DCMAKE_BUILD_TYPE=Release .. > /dev/null\nmake -j10 > /dev/null 2>&1\necho \"  Done.\"\necho \"\"\n\n# Function to run eidos benchmark and extract times\nrun_eidos_benchmark() {\n    local binary=\"$1\"\n    local label=\"$2\"\n\n    echo \"  Running Eidos benchmark ($label)...\"\n    \"$binary\" \"$BENCHMARK_DIR/simd_benchmark.eidos\" 2>/dev/null | grep -E \"^\\w+\\(\\):\" | while read line; do\n        echo \"    $line\"\n    done\n}\n\n# Function to run slim benchmark and get average time\nrun_slim_benchmark() {\n    local binary=\"$1\"\n    local runs=\"$2\"\n    local total=0\n\n    for ((i=1; i<=runs; i++)); do\n        time=$(\"$binary\" \"$BENCHMARK_DIR/slim_benchmark.slim\" 2>/dev/null | grep \"Elapsed time\" | grep -oE '[0-9]+\\.[0-9]+')\n        total=$(echo \"$total + $time\" | bc)\n    done\n\n    avg=$(echo \"scale=3; $total / $runs\" | bc)\n    echo \"$avg\"\n}\n\necho \"============================================\"\necho \"Eidos Math Function Benchmarks\"\necho \"============================================\"\necho \"\"\n\necho \"SIMD Build:\"\nrun_eidos_benchmark \"$BUILD_SIMD/eidos\" \"SIMD\"\necho \"\"\n\necho \"Scalar Build:\"\nrun_eidos_benchmark \"$BUILD_SCALAR/eidos\" \"Scalar\"\necho \"\"\n\necho \"============================================\"\necho \"SLiM Simulation Benchmark\"\necho \"(N=5000, 5000 generations, selection)\"\necho \"============================================\"\necho \"\"\n\necho \"Running $NUM_RUNS iterations each...\"\necho \"\"\n\nsimd_time=$(run_slim_benchmark \"$BUILD_SIMD/slim\" \"$NUM_RUNS\")\necho \"SIMD Build:   ${simd_time}s (avg)\"\n\nscalar_time=$(run_slim_benchmark \"$BUILD_SCALAR/slim\" \"$NUM_RUNS\")\necho \"Scalar Build: ${scalar_time}s (avg)\"\n\nif [ \"$(echo \"$scalar_time > 0\" | bc)\" -eq 1 ]; then\n    speedup=$(echo \"scale=2; $scalar_time / $simd_time\" | bc)\n    echo \"\"\n    echo \"Speedup: ${speedup}x\"\nfi\n\necho \"\"\necho \"============================================\"\necho \"Benchmark complete\"\necho \"============================================\"\n"
  },
  {
    "path": "simd_benchmarks/simd_benchmark.eidos",
    "content": "// SIMD Benchmark for Eidos math functions\n// Tests performance with large float arrays\n\ndefineGlobal(\"ARRAY_SIZE\", 1000000);\ndefineGlobal(\"ITERATIONS\", 100);\n\ncatn(\"SIMD Benchmark\");\ncatn(\"Array size: \" + ARRAY_SIZE);\ncatn(\"Iterations: \" + ITERATIONS);\ncatn(\"----------------------------------------\");\n\n// Generate test data\nx = runif(ARRAY_SIZE);\n\n// Benchmark sqrt\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = sqrt(x); }\nt1 = clock();\ncatn(\"sqrt():    \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark abs\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = abs(x - 0.5); }\nt1 = clock();\ncatn(\"abs():     \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark floor\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = floor(x * 100); }\nt1 = clock();\ncatn(\"floor():   \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark ceil\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = ceil(x * 100); }\nt1 = clock();\ncatn(\"ceil():    \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark round\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = round(x * 100); }\nt1 = clock();\ncatn(\"round():   \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark trunc\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = trunc(x * 100); }\nt1 = clock();\ncatn(\"trunc():   \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark sum\nt0 = clock();\nfor (i in 1:ITERATIONS) { y = sum(x); }\nt1 = clock();\ncatn(\"sum():     \" + format(\"%.3f\", (t1-t0)) + \" sec\");\n\n// Benchmark product (smaller array to avoid underflow)\nx_small = runif(1000, 0.99, 1.01);\nt0 = clock();\nfor (i in 1:(ITERATIONS*100)) { y = product(x_small); }\nt1 = clock();\ncatn(\"product(): \" + format(\"%.3f\", (t1-t0)) + \" sec (1000 elements, 10000 iters)\");\n\ncatn(\"----------------------------------------\");\ncatn(\"Done.\");\n"
  },
  {
    "path": "simd_benchmarks/sleef_benchmark.slim",
    "content": "// SLEEF Transcendental Functions Benchmark\n// Tests exp(), log(), log10(), log2(), trig functions, and pow() performance\n\ninitialize() {\n    initializeSLiMModelType(\"nonWF\");\n    defineConstant(\"N\", 1000000);  // 1M elements\n    defineConstant(\"REPS\", 10);    // repetitions for timing\n}\n\n1 early() {\n    // Create test data\n    x = runif(N, 0.1, 10.0);\n\n    // Data for trig functions (angles in radians)\n    angles = runif(N, -PI, PI);\n\n    // Data for inverse trig (must be in [-1, 1])\n    trig_input = runif(N, -0.99, 0.99);\n\n    // Second array for atan2 and pow\n    x2 = runif(N, 0.1, 5.0);\n\n    catn(\"Benchmarking SLEEF functions on \" + N + \" elements, \" + REPS + \" reps each\\n\");\n\n    catn(\"=== Exponential/Logarithmic ===\");\n\n    // Benchmark exp()\n    start = clock();\n    for (i in 1:REPS)\n        y = exp(x);\n    elapsed = clock() - start;\n    catn(\"exp():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark log()\n    start = clock();\n    for (i in 1:REPS)\n        y = log(x);\n    elapsed = clock() - start;\n    catn(\"log():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark log10()\n    start = clock();\n    for (i in 1:REPS)\n        y = log10(x);\n    elapsed = clock() - start;\n    catn(\"log10():  \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark log2()\n    start = clock();\n    for (i in 1:REPS)\n        y = log2(x);\n    elapsed = clock() - start;\n    catn(\"log2():   \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    catn(\"\\n=== Trigonometric ===\");\n\n    // Benchmark sin()\n    start = clock();\n    for (i in 1:REPS)\n        y = sin(angles);\n    elapsed = clock() - start;\n    catn(\"sin():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark cos()\n    start = clock();\n    for (i in 1:REPS)\n        y = cos(angles);\n    elapsed = clock() - start;\n    catn(\"cos():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark tan()\n    start = clock();\n    for (i in 1:REPS)\n        y = tan(angles);\n    elapsed = clock() - start;\n    catn(\"tan():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    catn(\"\\n=== Inverse Trigonometric ===\");\n\n    // Benchmark asin()\n    start = clock();\n    for (i in 1:REPS)\n        y = asin(trig_input);\n    elapsed = clock() - start;\n    catn(\"asin():   \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark acos()\n    start = clock();\n    for (i in 1:REPS)\n        y = acos(trig_input);\n    elapsed = clock() - start;\n    catn(\"acos():   \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark atan()\n    start = clock();\n    for (i in 1:REPS)\n        y = atan(x);\n    elapsed = clock() - start;\n    catn(\"atan():   \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark atan2()\n    start = clock();\n    for (i in 1:REPS)\n        y = atan2(angles, x2);\n    elapsed = clock() - start;\n    catn(\"atan2():  \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    catn(\"\\n=== Power ===\");\n\n    // Benchmark pow (x ^ y with two arrays)\n    start = clock();\n    for (i in 1:REPS)\n        y = x ^ x2;\n    elapsed = clock() - start;\n    catn(\"x^y:      \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark pow with scalar exponent (x ^ 2.5)\n    start = clock();\n    for (i in 1:REPS)\n        y = x ^ 2.5;\n    elapsed = clock() - start;\n    catn(\"x^2.5:    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark pow with scalar base (2.0 ^ x)\n    start = clock();\n    for (i in 1:REPS)\n        y = 2.0 ^ x;\n    elapsed = clock() - start;\n    catn(\"2.0^x:    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    catn(\"\\n=== Native SIMD (comparison) ===\");\n\n    // Benchmark sqrt()\n    start = clock();\n    for (i in 1:REPS)\n        y = sqrt(x);\n    elapsed = clock() - start;\n    catn(\"sqrt():   \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark abs()\n    x2 = x - 5.0;  // make some negative\n    start = clock();\n    for (i in 1:REPS)\n        y = abs(x2);\n    elapsed = clock() - start;\n    catn(\"abs():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    // Benchmark sum()\n    start = clock();\n    for (i in 1:REPS)\n        s = sum(x);\n    elapsed = clock() - start;\n    catn(\"sum():    \" + format(\"%.3f\", elapsed/REPS*1000) + \" ms per call\");\n\n    sim.simulationFinished();\n}\n"
  },
  {
    "path": "simd_benchmarks/slim_benchmark.slim",
    "content": "// SLiM Benchmark: Simple simulation with recombination and selection\n// Tests whether SIMD optimizations provide any incidental speedup\n\ninitialize() {\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\n\t// Neutral and selected mutations\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);         // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.03, 0.2);  // deleterious (gamma)\n\tinitializeMutationType(\"m3\", 0.5, \"e\", 0.1);         // beneficial (exponential)\n\n\tinitializeGenomicElementType(\"g1\", c(m1, m2, m3), c(0.7, 0.25, 0.05));\n\tinitializeGenomicElement(g1, 0, 999999);  // 1 Mb chromosome\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 5000);\n\tcatn(\"Starting simulation: N=5000, 1Mb chromosome, 500 generations\");\n\tcatn(\"Mutation rate: 1e-7, Recombination rate: 1e-8\");\n\tdefineGlobal(\"start_time\", clock());\n}\n\n5000 late() {\n\tend_time = clock();\n\telapsed = end_time - start_time;\n\n\tcatn(\"\\n----------------------------------------\");\n\tcatn(\"Simulation complete\");\n\tcatn(\"Elapsed time: \" + format(\"%.2f\", elapsed) + \" seconds\");\n\tcatn(\"Final mutation count: \" + size(sim.mutations));\n\tcatn(\"Population size: \" + p1.individualCount);\n\tcatn(\"----------------------------------------\");\n}\n"
  },
  {
    "path": "slim_multi.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "sonar-project.properties",
    "content": "# must be unique in a given SonarQube instance\nsonar.projectKey=SLiM\n\n# this is the name and version displayed in the SonarQube UI\nsonar.projectName=SLiM\nsonar.projectVersion=2.5\n\n# path is relative to the sonar-project.properties file.\n# This property is optional if sonar.modules is set. \nsonar.sources=.\n\n# encoding of the source code\nsonar.sourceEncoding=UTF-8\n\n# C family build wrapper info\nsonar.cfamily.build-wrapper-output=bw-output\n\n# my organization\nsonar.organization=bhaller-github\n"
  },
  {
    "path": "treerec/_README",
    "content": "This directory, and subdirectories, contains code related to the tree\nsequence recording facility of SLiM.\n\n\nThe code in `tskit/` is from [tskit/tree/main/c/tskit](https://github.com/tskit-dev/tskit/tree/main/c/tskit)\n\nThe code in `tskit/kastore` is from [kastore/c](https://github.com/tskit-dev/kastore/tree/master/c)\n\n**Changelog:**\n\n- *30 November 2025*: updated to tskit 1.0.0\n- *24 September 2025*: updated to tskit C_1.2.0 (=1.0.0b2) (still kastore C_2.1.1)\n- *15 April 2025*: updated to tskit C_1.1.4 (=0.6.2) (still kastore C_2.1.1)\n- *7 November 2023*: updated to tskit C_1.1.2 (=0.5.5) (still kastore C_2.1.1)\n- *2 June 2022*: updated to tskit C_1.0.0 and kastore C_2.1.1\n- *5 September 2020*: updated to tskit C_0.99.5\n- *27 August 2020*: updated to tskit C_0.99.5\n- *12 August 2020*: updated to tskit C_0.99.4 and kastore 0.3.0.\n- *10 June 2021*: updated to tskit 0.3.6 and kastore 0.3.1.\n- *7 Sept 2021*: updated to tskit C_0.99.14\n- *27 Nov 2021*: updated to tskit 763e8db4471cdaf45f99b6d8f8400acbf174db97 and kastore C_2.0.1\n- *7 December 2021*: updated to tskit C_0.99.15 and kastore C_2.0.2\n"
  },
  {
    "path": "treerec/implementation.md",
    "content": "# Notes on implementation\n\n## Overall design\n\nTo get into how tree-sequence recording in SLiM works, start out looking at SLiM 4.3 (https://github.com/MesserLab/SLiM/releases/tag/v4.3), since that is the last release before SLiM extended to multiple chromosomes (with one tree sequence per chromosome).  The architecture was considerably simpler back then.  You can move up to the SLiM 5.1 sources when you want to see how we handle multiple chromosomes; that topic is also discussed in its own section below.\n\nThere are two goals of tree sequence recording in SLiM:\n\n1. Record the genotypes and genealogical history of the final generation and any Remembered individuals.\n2. Be able to reload the exact state of the simulation from the tree sequence.\n\nHere \"the state of the simulation\" means all the individuals, populations, etcetera, but does not include global variables or random seed.\nSome of the complexity of the tree sequence recording design is to accommodate the second point: for instance, the ordering of individuals to match SLiM's internal ordering mentioned below.\n\nThe relevant variables are mostly in `species.h` (because there is one tree sequence per species, in SLiM 4.3), under the comment `// TREE SEQUENCE RECORDING`.  The most important variable is the table collection,  `tsk_table_collection_t tables_`.  If you search on `tsk_table_collection_` (ignoring hits inside SLiM’s private copy of tskit), you’ll find various interesting spots, such as `Species::AllocateTreeSequenceTables()` where we call `tsk_table_collection_init()` to allocate the table collection, `Species::SimplifyTreeSequence()` where we do a sequence of steps culminating in a call to `tsk_table_collection_simplify()` to simplify the tree sequence, and `Species::FreeTreeSequence()` where we free the table collection with `tsk_table_collection_free()`.  `Species::CheckTreeSeqIntegrity()` calls `tsk_table_collection_check_integrity()` to check that the tree-sequence tables pass all of tskit’s requirements, and is called in various places. `Species::CrosscheckTreeSeqIntegrity()` checks the information in the table collection against the information in SLiM’s own data structures and tries to make sure that they correspond to each other exactly; that’s quite slow and so is mostly done when compiled for debugging, but there is a user-level switch with `initializeTreeSeq(runCrosschecks=T)` that turns it on even in release builds.\n\nA search using the regex `tsk_.*add_row` will turn up places where we record things into various tables.  We build the individual table only at save time, so `tsk_individual_table_add_row()` is called only at that time, notably in `Species::AddIndividualsToTable()` but also in `Species::ReorderIndividualTable()`.  We call `tsk_node_table_add_row()` to record nodes in the node table whenever a new individual is created, in `Species::RecordNewGenome()` (called `RecordNewHaplosome()` in SLiM 5 as a result of the \"genome\" -> \"haplosome\" terminology shift that occurred with SLiM 5's multi-chromosome support).  That method also records the edge table entries that describe how that node inherits from ancestral nodes, with `tsk_edge_table_add_row()`.  Notice, by the way, that we check for errors using tskit’s return values after every call we make, and typically call `Species::handle_error()` if there was an error, which uses `tsk_strerror()` to print a user-readable error message; that’s important for catching errors at the point the arise.  `Species::RecordNewDerivedState()` is called whenever a new mutation arises, recording an entry in the site table with `tsk_site_table_add_row()` and an entry in the mutation table with `tsk_mutation_table_add_row()`.  There is considerable strangeness (necessary strangeness) to how SLiM records mutations; you can read about it in chapter 29 of the SLiM manual (again I’d recommend that you start with the 4.3 manual, which you can get from the GitHub release, and only graduate to 5.1 when you’re well-rested :->).  What else?  The population table and an entry for the provenance table are also generated only at save; you can find those place by searching for the appropriate `add_row()` function calls.  There is additional complexity for “remembering” individuals (guaranteeing that they don’t get simplified away); the variable `remembered_genomes_` is the crux of that.  And for “retracting” offspring that get vetoed by a `modifyChild()` callback in the user’s script, the variable `table_position_` records a bookmark that we can roll back to if a proposed child is rejected, in `RetractNewIndividual()`; so it’s the crux of that.\n\nReading in a `.trees` tree sequence file and creating the corresponding SLiM objects is a complex process that is managed by `Species::_InitializePopulationFromTskitBinaryFile()`, which calls down to a sequence of methods implementing a sequence of sub-steps.  One weirdness to be aware of is that the \"derived states\" column of the mutation table is required by tskit to be ASCII, but SLiM keeps binary data in it at runtime.  To keep tskit happy, the `Species::DerivedStatesToAscii()` method converts SLiM's binary derived states to ASCII at save time, and the `Species::DerivedStatesFromAscii()` method converts them back to binary at load time.  Speaking of saving, that is done by `Species::WriteTreeSequence()`.\n\nSLiM keeps lots of metadata on the side, in various tables.  That is detailed in chapter 29 of the SLiM manual, \"SLiM additions to the .trees file format\".  Encoding of metadata is done by the methods `Species::MetadataForMutation()`, `Species::MetadataForSubstitution()`, `Species::MetadataForGenome()`, and `Species::MetadataForIndividual()`.  In SLiM 5 the metadata for genomes (now called haplosomes) got much more complex; you can search on `HaplosomeMetadataRec` in SLiM 5 to find the new code, which has to track which haplosomes are \"vacant\" and which are not in a multi-chromosome simulation, and this is discussed below in more detail.  SLiM's top-level metadata, including an optional user-supplied metadata dictionary that can be passed to `treeSeqOutput()`, is written by `Species::WriteTreeSequenceMetadata()` and read back in with `ReadTreeSequenceMetadata()`.  SLiM provides schemas for its metadata; they are given in `slim_globals.cpp` beginning with `gSLiM_tsk_metadata_schema`.  In SLiM 4.3 this was complicated by backward compatibility for reading old metadata in SLiM.  In SLiM 5 we abandoned that backward compatibility; the user now needs to use `pyslim` to bring old `.trees` files forward to the current format for reading, which considerably simplified SLiM's code.\n\nThat’s most of it.  The remainder of this document will cover more specific implementation details and decisions.\n\n\n## Individual tracking\n\nBoth individuals and nodes (= haplosomes) have flags. We use individual flags for\ninternal bookkeeping in SLiM; while msprime uses the SAMPLE flag of nodes.\n\n1. When an individual is created in the simulation, its haplosomes (nodes) are automatically\n    added to the node table with the `NODE_IS_SAMPLE` flag, because the SAMPLE flag means\n    that we have whole-haplosome information about the node, which at this point we do.\n    Node times are recorded as the number of generations before the start of the\n    simulation (i.e., -1 * sim.generation). However, the individuals themselves are *not*\n    automatically added to the individuals table, in part because much of the information\n    in that table (e.g., location, age) may change, so the user should have control over\n    when it is recorded. Individuals are only added to the table during output (when all\n    the currently alive individuals are added) or if we explicitly choose to call the\n    RememberIndividuals() function.\n\n2. RememberIndividuals is called with a list of Individual instances. We add each of\n    those to to the individual table (but must first check if they are already present).\n    If `permanent=T` (default) we remember them permanently, whereas if `permanent=F` we\n    simply flag them to be *retained* while their nodes exist in the simulation. When we\n    ask an individual to be permanently remembered it has the `INDIVIDUAL_REMEMBERED`\n    flag set in the individuals table, and its haplosomes' node IDs are added to the\n    `remembered_nodes_` vector. In contrast, an individual which is retained has the\n    `INDIVIDUAL_RETAINED` flag set (which allows round-tripping on input/output).\n    However, unless it has also been permanently remembered, a retained individual is\n    subject to removal via simplification.\n\n3. Simplify, if it occurs, first constructs the list of nodes to maintain as samples\n    by starting with `remembered_nodes_`, and then adding the nodes of the current\n    generation.  All permanently remembered individuals in the individual table should be\n    maintained, because they are all pointed to by nodes in this list; other individuals\n    which have been retained, but not permanently remembered, may get removed by the\n    normal simplification algorithm.  We also update the `msp_node_id_` property of the\n    currently alive SLiM haplosomes. After simplify, we reset the `NODE_IS_SAMPLE` flag in\n    the node table, leaving it set only on those nodes listed in `remembered_nodes_`.\n    Note that we call `simplify` with the `keep_input_roots` option to retain\n    lineages back to the first generation, and the `filter_individuals` option to remove\n    individuals that no longer need to be retained.\n\n4. On output, we (optionally) simplify, copy the tables, and with these tables:\n    add the current generation to the individual table, marked with the `INDIVIDUAL_ALIVE` flag;\n    and reorder the individual tables so that the currently alive ones come first,\n    and in the order they currently exist in the population.\n    Also, node times have the current generation added to them, so they are in units\n    of number of generations before the end of the simulation.\n    Note that if simplify is *not* performed before output, all the nodes since the last\n    simplify will be marked with the `NODE_IS_SAMPLE` flag, even those not alive. Many of\n    these may not have an associated individual. This is deliberate, as we have full\n    genomic information for them, even if they are not ALIVE.\n\n5. On input from tables, we use the `INDIVIDUAL_ALIVE` flag to decide who is currently\n    alive and therefore must be instantiated into a SLiM individual, and use the\n    `INDIVIDUAL_REMEMBERED` flag to decide which haplosomes to add to `remembered_nodes_`.\n    From the individual table, we remove all individuals apart from those that are marked\n    as either `INDIVIDUAL_REMEMBERED` or `INDIVIDUAL_RETAINED` (thus we remove from the\n    table individuals that were only exported in the first place because they were ALIVE\n    at the time of export). `msp_node_id_` is set based on the nodes that point to that\n    individual in the tables. Also, node times have the current generation subtracted\n    from them, so they are in units of number of generations before the start of the simulation.\n\nInternal state:\n\n- `tables.individuals`:\n\n    * who's in the table: REMEMBERED and (if they have an existing node) RETAINED\n    * flags: everyone either REMEMBERED or RETAINED or both (never ALIVE)\n\n- `tables.nodes`:\n\n    * NODE_IS_SAMPLE flag: **unused** by SLiM; but set if they are in\n      REMEMBERED individuals, or if they're from a generation since the\n      last simplify (or the current generation, if that just happened)\n\n    * individual column: if their individual is REMEMBERED or RETAINED\n\n        - created by AddIndividualsToTable, called by RememberIndividuals\n\n    * time: (-1) * birth generation.\n\n- `remembered_nodes_`: the node IDs of nodes whose individuals are REMEMBERED\n\n    * initialized at the start of each new, not-from-anywhere-else subpopulation\n    * added to by RememberIndividuals\n    * updated by Simplify\n\n- `msp_node_id_` properties of currently alive SLiM individual `haplosome1_` and `haplosome2_`:\n    always contains an ID of the node table.\n\n    * created when a new individual is created, by `node_table_add_row()`\n    * updated by Simplify\n\nState at output:\n\n- `tables.individuals`:\n\n    * who's in the table: ALIVE and/or REMEMBERED and/or (if node exists) RETAINED\n    * flags: everyone is ALIVE and/or REMEMBERED and/or RETAINED\n    * reordered by ReorderIndividualTable so that order matches currently alive ones\n\n- `tables.nodes`:\n\n    * NODE_IS_SAMPLE flag: if they are REMEMBERED and/or ALIVE, or all nodes since the\n       last simplification if output has been done with simplify=F\n    * individual column: if they are REMEMBERED and/or ALIVE\n    * time: (current generation - birth generation)\n\n\n## Mutation recording\n\n### Alleles\n\nWe record as the `derived_state` for each mutation the\n*concatenation* of all mutations at that site that the individual has.\nThis is necessary because stacking rules can change dynamically,\nand makes sense, because this is what the individual actually passes on to offspring.\n\n### Sites and mutation parents\n\nWhenever a new mutation is encountered, we do the following:\n\n1. Add a new `site` to the site table at this position.\n2. Add a new `mutation` to the mutation table at the newly created site.\n\nThis is lazy and wrong, because:\n\na. There might have already been sites in the site table with the same position,\nb. and/or a mutation (at the same position) that this mutation should record as it's `parent`.\n\nBut, it's all OK because here's what we do:\n\n1. Add rows to the mutation and site tables as described above.\n2. Periodically, `sort_tables`, `deduplicate_sites`,  and `simplify_tables`, then return to (1.), except that\n3. Sometimes, to output the tables, we `sort_tables`, `compute_parents`,\n    (optionally `simplify_tables`), and dump these out to a file.\n\n*Note:* as things are going along we do *not* have to `compute_parents`;\nthis only has to happen before the final (output) step.\nIt might also be possible to skip the `deduplicate_sites` as we go along,\nif `simplify_tables` is OK with more than one site at the same position.\n\nAnd, these operations have the following properties:\n\n1. Mutations appear in the mutation table ordered by time of appearance,\n    so that a mutation will always appear after the one that it replaced (i.e., it's parent).\n2. Furthermore, if mutation B appears after mutation A, but at the same site,\n    then mutation B's site will appear after mutation A's site in the site table.\n3. `sort_tables` sorts sites by position, and then by ID, so that the relative ordering of sites\n    at the same position is maintained, thus preserving property (2).\n4. `sort_tables` sorts mutations by site, and then by ID, thus preserving property (1);\n    if the mutations are at separate sites (but the same position),\n    this fact is thanks to property (2).\n5. `simplify_tables` also preserves ordering of any rows in the site and mutation tables\n    that do not get discarded.\n5. `deduplicate_sites` goes through and collapses all sites at the same position to only one site,\n    maintaining order otherwise.\n6.  `compute_parents` fills in the `mutation.parent` information by using property (1).\n\n\n## Population table state\n\nSLiM needs to be able to have an entry in the population table without individuals\nactually mean that there's an empty population (for nonWF models),\nand so we (now as of SLiM v4.0) have the requirement that all the populations\nin the population table that have valid SLiM metadata (which currently just means\nhaving a \"slim_id\" key) must represent actual extant subpopulation in SLiM.\nIn other words, the state of the population table represents the state of things\n*at the time the tree sequence is written*, although it might have other,\nnon-SLiM entries in it which got carried over by SLiM from a tree sequence\nthat was read in.\n\nWe also require the \"slim_id\" key in metadata to match the row of the population table\nin which it is found. The reason for this is because we may refer to (sub)population IDs\nin several places: (a) the population column of the node table; (b) the subpopulation\nentry of the individual metadata; (c) the subpopulation entry of the mutation metadata.\nOf these, (a) is exposed to tskit (and so will remain consistent under tskit operations)\nbut (b) and (c) are not. However, SLiM will ensure that (a), (b), and (c) remain consistent.\nIt would be possible to decouple row of the population table with \"slim_id\" entry in metadata,\nby simply declaring that things referred to in metadata refer to the slim_id of a population's\nmetadata, while the population column in tables refers to the population id as usual.\nHowever, this would then require substantial downstream consistency checking:\nfor instance, individual->node->population.metadata[\"slim_id\"] should always\nequal individual.metadata[\"subpopulation\"] . We would also need to ensure that the slim_id's\nwere always unique.\n\n## Metadata schemas\n\ntskit provides methods for structured metadata decoding using [JSON schemas](https://json-schema.org/understanding-json-schema/index.html),\nto document what the metadata means.\nWe don't make use of these, but write them to the tree sequence for tskit use.\nThere's both top-level metadata (ie for the whole tree sequence)\nand metadata for every row in every table.\n(But, we only use some of these.)\n\nFor practical purposes, the metadata schema can be any equivalent JSON.\nHowever, when checking for table equality,\nthe code checks whether the underlying string representations are equal.\nSo, we want the metadata schema as written by SLiM to match that written by pyslim (using tskit).\nThe way that tskit writes out a metadata schema to a tree sequence\nis by (a) defining the schema using a dict\nand (b) creating a string using `json.dumps(schema_dict, sort_keys=True, indent=4)`.\nHappily, the resulting text matches the output of nlohmann::json dump(4),\nso - it seems - we can merrily write out JSON ourselves.\nNonetheless, we only actually do JSON parsing and writing in SLiM's code for top-level metadata:\nfor all the schemas (including the top-level metadata schema)\nwe just write out the string representation, as output by tskit, saved in `slim_globals.h`.\n\nIn the future we may want to *keep* whatever top-level metadata there is\nin the tree sequence already (and the associated keys in the schema).\nWe've not done that yet because making things exactly match seems like a pain,\nand no-one else is using the top-level metadata yet.\n\n## Reading in tree sequences\n\nIn addition to the various things mentioned above,\nTo read in a tree sequence, SLiM requires that:\n\n1. the two nodes corresponding to haplosomes of a given individual are adjacent in the node table,\n    and sorted by haplosome ID.\n\nThis is because of how `__TabulateSubpopulationsFromTreeSequence` works;\nprobably it could be made more general, but it isn't.\n\n## Multiple chromosomes and multiple tree sequences\n\nIn SLiM 5.0 we added support for simulating multiple chromosomes in SLiM, and that added\nsome wrinkles to how tree-sequence recording is implemented in SLiM.  In particular, we\nnow keep one tree sequence per chromosome being simulated.  In `species.h` we now define\na struct named `TreeSeqInfo` that keeps the `tsk_table_collection_t`, in particular, as\nwell as a couple of other bits of information.  Each Species then keeps its own `std::vector`\nof `TreeSeqInfo` structs, named `treeseq_`.  Where operations used to involve the table\ncollection, they now typically involve a loop over the elements of `treeseq_` to perform\nthe operation on each table collection in turn.\n\nThe main complication here is that all of these table collections share three tskit tables:\nthe node, individual, and population tables.  This means that the table collections all\nhave a shared structure, and that needs to be preserved across operations like simplify.\nThe shared tables are kept by the first chromosome's table collection, in `treeseq_[0]`.\nThe other table collections zero-fill their node, individual, and population tables most\nof the time.  That means that, in that state, they are not compliant with tskit\nrequirements, and trying to use them will often produce a segfault due to a dereference\nof a NULL pointer.  That is deliberate and useful; it makes it easy to debug situations\nwhere the table collections are being used when they should not be.  Sometimes we want the\ntable collections to actually be usable.  For that, `Species::CopySharedTablesIn()` will\ndo a bitwise, shallow copy of the shared tables into a given table collection; it should\nbe matched by `DisconnectCopiedSharedTables()` as soon as the operation is done, restoring\nthe zero-filled table state.  See https://github.com/tskit-dev/tskit/pull/2665 for\nJerome's original multi-chromosome parallel simplification example, from which this design\nwas derived.\n\nThe end goal is that this will allow parallel simplification to happen in SLiM.  The code\nin `Species::SimplifyAllTreeSequences()` now implements the extra bookkeeping needed to\nmaintain the shared table structure, so the design is ready to be parallelized when I\nreturn to the parallelization project.\n\nSingle-chromosome simulations still get saved out as a .trees tree sequence file.  With\nmultiple chromosomes, we now save out a \"trees archive\" with one .trees file per chromosome.\nThis is not directly supported on the tskit side at the moment; you can just iterate over\nthe files in the trees archive and process them as you wish in Python.  An example of this\nis provided in the SimHumanity paper, https://doi.org/10.47248/hpgg2505040006.\n\nThere is some new top-level metadata associated with trees archives and multiple chromosomes.\nThis is detailed in section 29.1 of the SLiM manual.  In particular, there are new top-level\nkeys `this_chromosome` and `chromosomes` that should be provided in every .trees file.  The\n`chromosomes` key provides a table of all of the chromosomes involved in the trees archive.\nThe `this_chromosome` key provides information about the particular chromosome represented\nby one particular .trees file in the trees archive.\n\nThe haplosome metadata also needs to track which nodes are \"vacant\" in which chromosomes.  Each individual has two nodes associated with it, and those two nodes are used, in the shared node table, to represent all of the haplosomes for all of the chromosomes for a given individual.  A male individual with a diploid autosome would have two haplosomes for that autosome, and would thus use both node table entries, so the two nodes would not be \"vacant\" for that autosome.  But an X chromosome in the same male individual would have only one X haplosome, and so it would use only the first of the two nodes for that individual; the second node would be \"vacant\" for that chromosome in that individual.  The state for the vacant vs. non-vacant state for each node, per chromosome, is kept in the node metadata in SLiM 5.  Section 29.3 of the SLiM manual provides further details and discussion; see also the `remove_vacant()` and `restore_vacant()` methods of `pyslim`.\n"
  },
  {
    "path": "treerec/tests/.gitignore",
    "content": "NodeTable.txt\nEdgeTable.txt\nTESToutput.txt\ntest_output\n__pycache__\n"
  },
  {
    "path": "treerec/tests/README.md",
    "content": "# Test suite for tree sequence output from SLiM\n\n## Running the tests\nJust do `python3 -m pytest` from within this directory to run the tests on the results of SLiM scripts listed in the `testRecipes/` directory. Alternatively, to run just one of the recipes do e.g.\n`python3 -m pytest -k test_000_sexual_nonwf`\n\n## Recaching in GitHub Actions to get a new tskit/msprime version\nGitHub Actions caches its install of `tskit`, `msprime`, and other software.  When a new version of such software is released, a recache needs to be forced or these tests will likely fail in CI.  This cannot presently be gone in GitHub's UI; see [this GitHub issue](https://github.com/actions/cache/issues/2).  So to trigger a recache, you need to increment the cache version number.  It is found in `.github/workflows/tests.yml` in the line:\n\n`key: ${{ runner.os }}-${{ matrix.python}}-conda-v10-${{ hashFiles('treerec/tests/conda-requirements.txt') }}-${{ hashFiles('treerec/tests/pip-requirements.txt') }}`\n\nFor example, change `v10` here to `v11`.  You can also consider putting an explicit version number in `treerec/tests/conda-requirements.txt`; for example, we now have `tskit >= 0.4.0` there, although presumably it would get the most recent shipping version anyway; I guess this expresses the version requirement semantically, for human readers, at least.  Changing either the version number or the `conda-requirements.txt` should apparently trigger a recache.  See [this issue](https://github.com/MesserLab/SLiM/issues/232) for the context that led to this comment.\n\n## Adding new tests\n\n\nTo add a new test:\n\n1. Put the recipe in the `test_recipes/` directory, with a filename like `test_XXX.slim`.\n2. Add a config line in `recipe_specs.py` which determines which tests to run.\n3. Add the additional necessary stuff to the SLiM recipe:\n\n    * To check that haplotypes agree between SLiM and the tree sequence, just put\n\n      ```\n      source(\"init.slim\");\n      ```\n\n      in `initialize()` (this defines functions); and then call\n\n      ```\n      outputMutationResult();\n      ```\n\n      at the end (well, whenever you want, really;).\n\n    * To mark individuals in the initial generation with particular mutation types so we\n      can check *something* even with mutation recording turned off, instead of sourcing\n      \"init.slim\", source \"init_marked_mutations.slim\", i.e. place\n\n      ```\n      source(\"init_marked_mutations.slim\");\n\t  ```\n\n      in `initialize()` and then call\n\n      ```\n      initializeMarks(n_marks);\n      ```\n\n      in `1` (after adding the subpop), and then, as before,\n\n      ```\n      outputMutationResult();\n      ```\n      at the end. Note that this will only work properly if there is no new mutation.\n\n    * Make sure you call `initializeTreeSeq();` after the `source(...)` line\n\n    * Add `chooseAncestralSamples(5)` to some generations along the way\n      to add some individuals as \"ancestral samples\". This is done by \"remembering\" them.\n\n    * If you want to check that individuals in the simulation\n      are present in generated tree sequence, call\n\n      ```\n      outputIndividuals()\n      ```\n\n      By default this simply saves a list of the individuals from the simulation at the point\n      when it is called, and compares it to the list in the tree sequence. However, you can\n      add individuals to the saved list by calling `addIndividuals(individuals)` at any point\n      in the simulation.\n\n\nTo temporarily turn off a test just comment out the appropriate line in `recipe_specs.py`\n"
  },
  {
    "path": "treerec/tests/conda-requirements.txt",
    "content": "tskit >= 0.4.1\nmsprime >= 1.2.0\n"
  },
  {
    "path": "treerec/tests/conftest.py",
    "content": "# Configuration for pytest\nimport collections\nimport os\nimport subprocess\nimport pathlib\n\nfrom filelock import FileLock\nimport pytest\nimport tskit\n\nfrom recipe_specs import recipe_specs\n\nSLiMindividual = collections.namedtuple('SLiMindividual', 'type sex population pos nodes')\n\n\ndef load_file_or_dir(p):\n    if os.path.isdir(p):\n        tsl = [tskit.load(f) for f in pathlib.Path(p).glob(\"*.trees\")]\n    else:\n        tsl = [tskit.load(p),]\n    tsi = [ts.metadata['SLiM']['this_chromosome']['id'] for ts in tsl]\n    out = {i : ts for i, ts in zip(tsi, tsl)}\n    assert len(out) == len(tsl) # ensures keys are unique\n    return out\n\n\nclass OutputResult:\n    \"\"\"\n    A wrapper to process the results files returned from a ts\n    \"\"\"\n    def __init__(self, out_dir):\n        assert os.path.isdir(out_dir)\n        self.dir = out_dir\n\n    def get_normal_ts(self):\n        ts = tskit.load(os.path.join(self.dir, \"test_output.trees\"))\n        return ts\n\n    def get_ts(self):\n        # binary\n        print(\"******** Binary input.\")\n        bin_ts = load_file_or_dir(os.path.join(self.dir, \"test_output.trees\"))\n        yield bin_ts\n        # and nonsimplified binary\n        print(\"******** Unsimplified binary.\")\n        bin_nonsimp_ts = load_file_or_dir(\n            os.path.join(self.dir, \"test_output.unsimplified.trees\"))\n        yield bin_nonsimp_ts\n\n    @staticmethod\n    def get_slim_ids(ts):\n        # get SLiM ID -> msprime ID map from metadata\n        ids = {}\n        for n in ts.nodes():\n            ids[n.metadata[\"slim_id\"]] = n.id\n        return ids\n\n    def mutation_output(self):\n        \"\"\"\n        Read in the genotypes output by the SLiM function outputMutationResult(),\n        producing a dictionary indexed by position, whose values are dictionaries\n        indexed by SLiM genome ID, giving the mutations carried at that position\n        in that genome; also return a list of SLiM IDs found.\n        \"\"\"\n        basename = \"slim_mutation_output.txt\"  # matches the name in init.slim\n        filename = os.path.join(self.dir, basename)\n        if not os.path.isfile(filename):\n            raise RuntimeError(f\"No mutation file {basename} in {self.dir}\")\n        slim_file = open(filename, \"r\")\n        slim = {}\n        slim_ids = []\n        for header in slim_file:\n            headstring = header.split()\n            assert headstring[0] == \"#Genome:\"\n            genome = int(headstring[1])\n            chrom = int(headstring[2])\n            # sex = int(headstring[3])\n            # ped_id = int(headstring[4])\n            slim_ids.append(genome)\n            mutations = slim_file.readline().split()\n            assert mutations[0] == \"Mutations:\"\n            mutations = [int(u) for u in mutations[1:]]\n            positions = slim_file.readline().split()\n            assert positions[0] == \"Positions:\"\n            positions = [int(u) for u in positions[1:]]\n            for pos, mut in zip(positions, mutations):\n                key = (chrom, pos)\n                if key not in slim:\n                    slim[key] = {}\n                if genome not in slim[key]:\n                    slim[key][genome] = []\n                slim[key][genome].append(mut)\n        return slim, slim_ids\n\n    def marked_mutation_output(self, ts):\n        \"\"\"\n        This provides a dictionary indexed by chromosome ID,\n        whose values are lists indexed by position,\n        which contain dicts indexed by mutation type giving the indivs\n        inheriting that mut at that position\n        \"\"\"\n        basename = \"slim_no_mutation_output.txt\"  # matches the name in init.slim\n        filename = os.path.join(self.dir, basename)\n        if not os.path.isfile(filename):\n            raise RuntimeError(f\"No marked mutation file {basename} in {self.dir}\")\n        slim_file = open(filename, \"r\")\n        ids = self.get_slim_ids(ts)\n        slim = {}\n        for header in slim_file:\n            assert header[0:12] == \"MutationType\"\n            mut, pos, chrom = header[12:].split()\n            chrom = int(chrom)\n            if chrom not in slim:\n                slim[chrom] = []\n            pos = int(pos)\n            while pos >= len(slim[chrom]):\n                slim[chrom].append({})\n            slim_ids = [int(u) for u in slim_file.readline().split()]\n            for u in slim_ids:\n                assert u in ids\n            slim[chrom][pos][mut] = [ids[u] for u in slim_ids]\n        return slim\n\n    def individual_output(self):\n        # Read in the individuals output by the SLiM function addIndividuals(),\n        # producing a dictionary indexed by individual pedigree ID\n        basename = \"slim_individual_output.txt\"  # matches the name in init.slim\n        filename = os.path.join(self.dir, basename)\n        if not os.path.isfile(filename):\n            raise RuntimeError(f\"No individual details file {basename} in {self.dir}\")\n        slim_file = open(filename, \"r\")\n        slim = {}\n        for line in slim_file:\n            fields = line.split()\n            assert fields[0].startswith(\"#Individual:\")\n            store = fields[0][len(\"#Individual:\"):]\n            assert store in (\"remember\", \"retain\", \"retain_even_if_unary\", \"output\")\n            pedigree_id = int(fields[1])\n            if pedigree_id in slim:\n                # We have a duplicate; 'remember' takes priority\n                if slim[pedigree_id].type == \"remember\":\n                    store = slim[pedigree_id].type\n            slim[pedigree_id] = SLiMindividual(\n                type=store,\n                sex=fields[2],\n                population=int(fields[3]),\n                pos=[float(p) for p in fields[4].split(\",\")],\n                nodes=[int(p) for p in fields[5].split(\",\")],\n            )\n        return slim\n\ndef make_result(run_dir):\n    \"\"\"\n    SLiM recipes are expected to output their results into a set of directories\n    within the run_dir: return a list of results, one for each subdirectory\n    \"\"\"\n    return [\n        OutputResult(os.path.join(run_dir, f.name))\n        for f in os.scandir(run_dir)\n        if f.is_dir()\n    ]\n\ndef run_slim(recipe, run_dir, recipe_dir=\"test_recipes\"):\n    \"\"\"\n    Run the script specified by recipe (which should switch to the run_dir directory).\n    Recipes should dump files into subdirectories of run_dir, and we return a list of\n    these directories, which contain the files on which tests should be run\n    \"\"\"\n    script_dir = os.path.dirname(os.path.realpath(__file__))  # Path to this file\n    full_recipe = os.path.abspath(os.path.join(script_dir, recipe_dir, recipe))\n    assert os.path.isdir(run_dir)  # should have been created by caller\n    if os.name == \"nt\":\n        run_dir = str(run_dir).replace(\"\\\\\", \"/\")\n    cmd = [\"slim\", \"-s\", \"22\", \"-d\", f\"RUN_DIR=\\\"{run_dir}\\\"\", full_recipe]\n    print(f\"Running {cmd} in dir '{run_dir}', errors etc to 'SLiM_run_output.log'\")\n    with open(os.path.join(run_dir, \"SLiM_run_output.log\"), \"w\") as out:\n        retval = subprocess.call(cmd, cwd=script_dir, stderr=subprocess.STDOUT, stdout=out)\n        if retval != 0:\n            raise RuntimeError(f\"Could not run `{cmd}`\")\n    return make_result(run_dir)\n\n\n@pytest.fixture(scope=\"session\", params=recipe_specs.keys())\ndef recipe(request, tmp_path_factory, worker_id):\n    \"\"\"\n    Return a dict containing information about the recipe results. Most logic in this\n    fixture is to check whether we are running as a single proc, or as a worker.\n    \"\"\"\n    recipe_name = request.param\n    return_val = {\"name\": recipe_name}\n    return_val.update(recipe_specs[recipe_name])\n\n    if worker_id == \"master\":\n        # not executing in with multiple workers\n        run_dir = tmp_path_factory.getbasetemp() / recipe_name\n    else:\n        # get the temp directory shared by all workers, so that simulation files\n        # are shared between workers\n        run_dir = tmp_path_factory.getbasetemp().parent / recipe_name\n    with FileLock(str(run_dir) + \".lock\"):\n        # lock until all simulations are done\n        if run_dir.is_dir():\n            return_val[\"results\"] = make_result(run_dir)\n        else:\n            os.makedirs(run_dir, exist_ok=True)\n            return_val[\"results\"] = run_slim(recipe_name, run_dir)\n    return return_val\n\n"
  },
  {
    "path": "treerec/tests/environment.yml",
    "content": "channels:\n  - conda-forge\n  - nodefaults\ndependencies:\n  - tskit >= 0.4.1\n  - msprime >= 1.2.0\n  - pyslim >= 1.0.4\n  - setuptools\n  - filelock\n  - numpy\n  - pytest\n  - pytest-xdist"
  },
  {
    "path": "treerec/tests/init.slim",
    "content": "// Define functions used in the tests, then switch to RUN_DIR\n\ndefineGlobal(\"mutationsFile\", \"slim_mutation_output.txt\");\ndefineGlobal(\"individualsFile\", \"slim_individual_output.txt\");\n\nfunction (void)initializeMarkedMutations(i$ num_marks)\n{\n   defineGlobal(\"mutationsFile\", \"slim_no_mutation_output.txt\");\n   for(i in 1:num_marks){\n      initializeMutationType(\"m\" + asString(i), 0.5, \"f\", 0.0);\n   }\n   // used for ongoing marking\n   initializeMutationType(\"m0\", 0.5, \"f\", 0.0);\n   m0.mutationStackPolicy = \"l\";\n   return;\n}\n\nfunction (void)initializeMarks(i$ num_marks)\n{\n   // add a separate type of mutation to each of some genomes\n   markedGenomes = sample(sim.subpopulations.haplosomes,\n        min(num_marks,2*sum(sim.subpopulations.individualCount)));\n   for (k in seqAlong(markedGenomes)){\n      chrom = markedGenomes[k].chromosome;\n      for (pos in 0:chrom.lastPosition){\n          mut = sim.mutationTypes[k];\n          markedGenomes[k].addNewDrawnMutation(mut,pos);\n        }\n   }\n   return;\n}\n\nfunction (void)saveTreeSeq(void) {\n   // create tree seq representation in various formats: this could overwrite any\n   // existing ones output in the same cycle, but they should be identical\n   // if done in the same cycle at the same point of the lifecycle\n   // Note that this should happen after other output functions, and only once;\n   // if not, then there will be errors in Windows CI where we get an error due\n   // to having to delete the directory when writing out the tree sequence file again.\n   setwdForGen();\n   sim.treeSeqOutput(\"test_output.trees\", simplify=T);\n   sim.treeSeqOutput(\"test_output.unsimplified.trees\", simplify=F);\n}\n\nfunction (void)saveIndividualMutations(o<Individual>$ ind) {\n   /* * *\n    * To the mutationsFile, save:\n    * a list of mutations, and\n    * a list of positions of those mutations.\n    * * */\n   pedID = ind.pedigreeID;\n   for (k in c(0, 1)) {\n      if (k == 0) {\n         haploidGenome = ind.haploidGenome1;\n      } else {\n         haploidGenome = ind.haploidGenome2;\n      }\n      for (haplosome in haploidGenome) {\n         haplosomeID = haplosome.haplosomePedigreeID;\n         chromID = haplosome.chromosome.id;\n         if (haplosome.isNullHaplosome) {\n            ids = c();\n            positions = c();\n         } else {\n            subs = sim.substitutions[sim.substitutions.chromosome.id == chromID];\n            ids = c(haplosome.mutations.id, subs.id);\n            positions = c(haplosome.mutations.position, subs.position);\n         }\n         writeFile(mutationsFile, \"#Genome: \" + paste(haplosomeID) + \" \" + paste(chromID)\n                   + \" \" + paste(ind.sex) + \" \" + paste(pedID), append=T);\n         writeFile(mutationsFile, \"Mutations: \" + paste(ids), append=T);\n         writeFile(mutationsFile, \"Positions: \" + paste(positions), append=T);\n      }\n   }\n}\n\nfunction (void)addAncestralSamples(i$ num_samples) {\n   /* * *\n    * Mark some individuals to retain as ancestral samples\n    * in the tree sequence, and write out their genome to the current mutationsFile\n    * * */\n   inds = sample(sim.subpopulations.individuals, \n              min(num_samples, sum(sim.subpopulations.individualCount)));\n   sim.treeSeqRememberIndividuals(inds);\n   addIndividuals(inds, \"remember\");\n   if(!exists(\"n_marks\")) {\n      for (ind in inds) {\n         catn(\"Recording genomes from individual \" + ind.pedigreeID);\n         saveIndividualMutations(ind);\n      }\n   } else {\n      // FIXME: why don't we save ancestral samples here?\n   }\n}\n\nfunction (void)addIndividuals([No<Individual> individuals=NULL], [s$ store=\"remember\"]) {\n   /* * *\n    * For each individual in `individuals`, write out a line to the current individualsFile,\n    * containing:\n    * \"remember\", \"retain\", or \"output\" (the `store` param) to indicate whether this \n    *  individual should have been permanently remembered, simply retained, or\n    *  is an individual written during output of the whole population\n    * the pedigree ID\n    * other stuff\n    * * */\n   for (ind in individuals) {\n      outstr = \"#Individual:\" + store +\n         \" \" + paste(ind.pedigreeID) +\n         \" \" + paste(ind.sex) +\n         \" \" + paste(ind.subpopulation.id) +\n         \" \" + paste(ind.x, ind.y, ind.z, sep=\",\") +\n         \" \" + paste(unique(ind.haplosomes.haplosomePedigreeID), sep=\",\");\n      writeFile(\n         individualsFile,\n         outstr,\n         append=T);\n   }\n}\n\nfunction (string$)setwdForGen(void) {\n   // change the working dir to a new subdir named by cycle, and return the old subdir\n   saveDir = paste(sim.cycle); // should probably append late or early\n   if(!fileExists(saveDir)) {\n      createDirectory(saveDir);\n   }\n   return(setwd(saveDir));\n}\n\nfunction (string$)copyIntoNewWdForGen(s$ file) {\n   /* * *\n    * Copy the file into a new working subdir named by cycle, returning the old subdir\n    * This allows us to take a stored output file in the parent dir (if it exists) and append \n    * stuff to a new version in a newly created subdir that's only relevant to that cycle\n    * * */\n   if(fileExists(file)) {\n      fileContents = readFile(file);  // copy\n      baseDir = setwdForGen();      // switch to new subdir\n      writeFile(file, fileContents);  // paste into new file\n   } else {\n      baseDir = setwdForGen();      // switch to new subdir\n   };\n   return(baseDir);\n}\n\nfunction (void)outputMutationResult(void) {\n   /* * *\n    * Take the existing data (in the current mutationsFile)\n    * and make a copy, appending data from in the current cycle\n    * * */\n   baseDir = copyIntoNewWdForGen(mutationsFile); // copy the current mutationsFile\n   if(!exists(\"n_marks\")) {\n      // Normal output: append details of mutations\n      for (pop in sim.subpopulations) {\n         for (ind in pop.individuals) {\n            saveIndividualMutations(ind);\n         }\n      }\n   } else {\n      // Marked output: For each mutation type, output at each position the list\n      // of genomes that have inherited a mutation of that type at that position\n      for (Mut in sim.mutationTypes){\n         for (chrom in sim.chromosomes) {\n            for (Pos in 0:chrom.lastPosition){\n               GenomesWithMutAtPos = NULL;\n               for (pop in sim.subpopulations) {\n                  for (Ind in pop.individuals){\n                     pedID = Ind.pedigreeID;\n                     for (k in seqAlong(Ind.haplosomesForChromosomes(chrom))){\n                        haplosomeID = (2 * pedID) + k;\n                        if (Ind.haplosomes[k].containsMarkerMutation(Mut,Pos)){\n                           GenomesWithMutAtPos = c(GenomesWithMutAtPos, haplosomeID);\n                        }\n                     }\n                  }\n                  writeFile(mutationsFile, paste(Mut) + \" \" + paste(Pos) + \" \" + paste(chrom.id), append=T);\n                  writeFile(mutationsFile, paste(GenomesWithMutAtPos), append=T);\n               }\n            }\n         }\n      }\n   }\n   setwd(baseDir); // reset, so we can output in another cycle\n}\n\nfunction (void)outputIndividuals(void) {\n   // copy the existing individualsFile into a new subdir and append the current individuals\n   baseDir = copyIntoNewWdForGen(individualsFile); // copy the current individualsFile\n   for (pop in sim.subpopulations) {\n      addIndividuals(pop.individuals, \"output\");\n   }\n   setwd(baseDir); // reset, so we can output in another cycle\n}\n\nif (!exists(\"RUN_DIR\")) defineGlobal(\"RUN_DIR\", \".\"); \nsetwd(RUN_DIR);\n"
  },
  {
    "path": "treerec/tests/init_marked_mutations.slim",
    "content": "defineConstant(\"n_marks\", 20);   // number of marked genomes - also tags a marked_mutation sim\n\nsource(\"init.slim\");\n\ninitializeMarkedMutations(n_marks);\n\n"
  },
  {
    "path": "treerec/tests/pip-requirements.txt",
    "content": "setuptools\nfilelock\nnumpy\npytest\npytest-xdist\n"
  },
  {
    "path": "treerec/tests/recipe_specs.py",
    "content": "\"\"\"specify which tests to run on each of the recipes in ./test_recipes\"\"\"\n\nimport os\n\n# Possible attributes to simulation scripts are\n#  mutations/marked_mutations: does the recipe source init.slim or init_marked_mutations.slim? \n#  individuals: records individuals \n#\n# All files are of the form `tests/test_recipes/{key}`. By convention a name like\n# test_002_xxx is based on the corresponding SLiM test recipe\nrecipe_specs = {\n    \"test_____ancestral_marks.slim\":\t            {\"marked_mutations\": True},\n    \"test_____sexual_WF.slim\":\t\t                {\"marked_mutations\": True},\n    \"test_____sexual_nonwf.slim\":\t\t            {\"mutations\": True, \"individuals\": True},\n    \"test_____simple_nonwf.slim\":\t\t            {\"mutations\": True, \"individuals\": True},\n    \"test_____withdraw_indivs.slim\":\t            {\"mutations\": True, \"individuals\": True},\n    \"test_____multipops.slim\":\t                    {\"marked_mutations\": True, \"individuals\": True},\n    \"test_002_quick_neutral.slim\":\t                {\"marked_mutations\": True},\n    \"test_004 simple sexual A.slim\":\t            {\"mutations\": True, \"individuals\": True},\n    \"test_005 simple sexual X.slim\":\t            {\"mutations\": True, \"individuals\": True},\n    \"test_006 simple sexual Y.slim\":\t            {\"mutations\": True, \"individuals\": True},\n    \"test_007 cloning and selfing.slim\":            {\"mutations\": True, \"individuals\": True},\n    \"test_008 cyclical subpop.slim\":                {\"mutations\": True, \"individuals\": True},\n    \"test_009 linear island.slim\":                  {\"mutations\": True, \"individuals\": True},\n    \"test_013 gene conversion.slim\":                {\"mutations\": True, \"individuals\": True},\n    \"test_024 gene drive.slim\":                     {\"mutations\": True, \"individuals\": True},\n    \"test_038 pure cloning.slim\":                   {\"mutations\": True, \"individuals\": True},\n    \"test_039 pure selfing.slim\":                   {\"mutations\": True, \"individuals\": True},\n    \"test_040 pure cloning sexual.slim\":            {\"mutations\": True, \"individuals\": True},\n    \"test_042 haploid clonals.slim\":                {\"mutations\": True, \"individuals\": True},\n    \"test_____remember_individuals.slim\":           {\"marked_mutations\": True, \"individuals\": True},\n    \"test_____retain_individuals_nonWF.slim\":       {\"marked_mutations\": True, \"individuals\": True},\n    \"test_____retain_individuals_unary.slim\":       {\"marked_mutations\": True, \"individuals\": True},\n    \"test_____retain_and_remember_individuals.slim\": {\"marked_mutations\": True, \"individuals\": True},\n    \"test_____retain_individuals_nonWF_unary.slim\": {\"marked_mutations\": True, \"individuals\": True},\n    \"test_097 modeling nucleotides.slim\":           {\"mutations\": True, \"individuals\": True},\n    \"test_____pop_names_pX.slim\":\t\t            {},\n    \"test_____pop_names_nondefault.slim\":           {},\n    \"test_____simple_not_perm.slim\":                {},\n    \"test_____simple_perm.slim\":                    {},\n    \"test_____simple_none.slim\":                    {},\n    \"test_____no_generations.slim\":                 {\"individuals\": True},\n    \"test_____all_the_chromosome_types.slim\":       {\"mutations\": True, \"individuals\": True},\n    \"test_____all_the_chromosomes.slim\":            {\"individuals\": True, \"everyone\": True},\n    \"test_____H-_chromosome.slim\":                  {\"mutations\": True, \"individuals\": True},\n    \"test_831_multiple diploid autosomes.slim\":     {\"mutations\": True, \"individuals\": True},\n    \"test_832_clonal haploids and chromosome types.slim\": {\"mutations\": True, \"individuals\": True},\n    \"test_833_haploids with recombination.slim\":    {\"mutations\": True, \"individuals\": True},\n    \"test_834_sex-chromosome evolution and null haplosomes.slim\": {\"mutations\": True, \"individuals\": True},\n    \"test_836_output from multiple-chromosome models.slim\": {\"mutations\": True, \"individuals\": True},\n    \"test_169_complex multi-chromosome inheritance.slim\": {\"mutations\": True, \"individuals\": True},\n    \"test_1610_modeling pseudo-autosomal regions.slim\": {\"mutations\": True, \"individuals\": True},\n}\n\n\ndef recipe_eq(*keys, exclude=None):\n    \"\"\"\n    Return an iterator over those recipes whose spec contains the specified keys.\n    If key is empty, return all of them.\n    If exclude_key is given exclude recipes with the specified key\n    \"\"\"\n    if exclude is None:\n        return (k for k, v in recipe_specs.items() if all(kk in v for kk in keys))\n    else:\n        return (\n            k for k, v in recipe_specs.items()\n            if exclude not in v and all(kk in v for kk in keys)\n        )\n"
  },
  {
    "path": "treerec/tests/test_consistency.py",
    "content": "import tskit, msprime, pyslim\nimport numpy as np\nimport pytest\n\nfrom recipe_specs import recipe_eq\n\ndef node_has_data(ts, n):\n    # some chromosome types are represented by a single haplosome\n    # in SLiM but still two nodes in the output, and not (currently)\n    # distinguishable in any way except they have only missing data\n    return (\n        np.sum(ts.edges_parent == n) + np.sum(ts.edges_child == n)\n        > 0\n    )\n\n@pytest.mark.parametrize('recipe', recipe_eq(\"mutations\"), indirect=True)\nclass TestWithMutations:\n\n    def test_mutation_consistency(self, recipe):\n        for result in recipe[\"results\"]:\n            slim, slim_ids = result.mutation_output()\n            for tsl in result.get_ts():\n                for chrom_id in tsl:\n                    ts = tsl[chrom_id]\n                    assert ts.num_mutations > 0, ts.metadata['SLiM']['this_chromosome']\n                    # this is a dictionary of SLiM -> tskit ID (from metadata in nodes)\n                    ids = result.get_slim_ids(ts)\n                    for sid in ids:\n                        has_data = node_has_data(ts, ids[sid])\n                        if ts.node(ids[sid]).is_sample() and has_data:\n                            assert sid in slim_ids\n                    # this is a dict of tskit ID -> index in samples\n                    msp_samples = {}\n                    for k, u in enumerate(ts.samples()):\n                        msp_samples[u] = k\n                    pos = -1\n                    for var in ts.variants(isolated_as_missing=False):\n                        pos += 1\n                        while pos < int(var.position):\n                            # invariant sites: no genotypes\n                            assert pos < ts.sequence_length\n                            assert (chrom_id, pos) not in slim\n                            pos += 1\n                        key = (chrom_id, pos)\n                        # print(\"-----------------\")\n                        # print(\"chrom_id, pos:\", key)\n                        # print(\"slim:\", None if key not in slim else slim[key])\n                        # print(var)\n                        for j in ids:\n                            if ids[j] in msp_samples:\n                                sample_num = msp_samples[ids[j]]\n                                geno = var.genotypes[sample_num]\n                                msp_genotypes = var.alleles[geno].split(\",\")\n                                if (key not in slim) or (j not in slim[key]):\n                                    # no mutations at this site\n                                    assert msp_genotypes == [''], f\"sid={j}, msp={ids[j]}, {key in slim} / {j in slim[key]}\\n   {slim[key]}\"\n                                else:\n                                    assert set(msp_genotypes) == set([str(x) for x in slim[key][j]]), f\"slim: {slim[key][j]}\"\n\n\n@pytest.mark.parametrize('recipe', recipe_eq(\"marked_mutations\"), indirect=True)\nclass TestMarkedMutations:\n\n    def check_consistency(self, x, y):\n        # here y is an iterable of disjoint lists of ids (determined by indivs\n        # who share mutations in SLiM) and x is a dict whose keys are ids and\n        # whose values are labels (the roots in msprime); check that any two\n        # ids in the same element of y have the same label in x\n        all_ids = []\n        for a in y:\n            if len(y[a]) > 0:\n                a_labels = []\n                for u in y[a]:\n                    assert u in x\n                    assert u not in all_ids\n                    all_ids.append(u)\n                    a_labels.append(x[u])\n                print('IDs sharing mutation', a, \":\", y[a])\n                print('labels of roots in from tree:', a_labels)\n                assert len(set(a_labels)) == 1\n\n    def test_marked_consistency(self, recipe):\n        for result in recipe[\"results\"]:\n            # load tree sequence representations\n            for tsl in result.get_ts():\n                for chrom_id in tsl:\n                    ts = tsl[chrom_id]\n                    assert ts.num_mutations > 0\n                    # this is a dictionary of SLiM -> msprime ID (from metadata in nodes)\n                    slim = result.marked_mutation_output(ts)[chrom_id]\n                    pos = 0\n                    for t in ts.trees():\n                        # get partition of leaves from this tree, using SLiM IDs\n                        fams = {}\n                        for x in t.nodes():\n                            u = x\n                            while t.parent(u) != tskit.NULL:\n                                u = t.parent(u)\n                            fams[x] = u\n                        while pos < t.interval[1]:\n                            print(\"pos:\", pos, \"------------\")\n                            self.check_consistency(fams, slim[pos])\n                            pos += 1\n\n\n@pytest.mark.parametrize('recipe', recipe_eq(\"individuals\"), indirect=True)\nclass TestIndividuals:\n\n    def test_individual_consistency(self, recipe):\n        # load tree sequence\n        for result in recipe[\"results\"]:\n            slim_individuals = result.individual_output()\n            for tsl in result.get_ts():\n                for chrom_id in tsl:\n                    ts = tsl[chrom_id].simplify(filter_individuals=True)\n                    # this is a dictionary of SLiM -> tskit ID (from metadata in nodes)\n                    ids = result.get_slim_ids(ts)\n                    # this is a dict of tskit ID -> index in samples\n                    # check that all the individual data lines up\n                    ts_individuals = {i.metadata['pedigree_id']: i for i in ts.individuals()}\n                    alive = {\n                            ts.individual(i).metadata['pedigree_id']\n                            for i in pyslim.individuals_alive_at(ts, 0)\n                    }\n                    num_expected = 0\n                    for ped_id, slim_ind in slim_individuals.items():\n                        if slim_ind.type.startswith(\"retain\"):\n                            # retained individuals should only be present in the TS if they\n                            # have genomic material. We should check which have nodes that exist\n                            ts_nodes = [ids[n] for n in slim_ind.nodes if n in ids]\n                            if len(ts_nodes) > 0:\n                                num_expected += 1\n                                assert ped_id in ts_individuals\n                                metadata = ts_individuals[ped_id].metadata\n                                # in metadata, sex is 0 for female, 1 for male, -1 for hermaphrodite\n                                if slim_ind.sex == \"F\":\n                                    assert metadata['sex'] == 0\n                                elif slim_ind.sex == \"M\":\n                                    assert metadata['sex'] == 1\n                                elif slim_ind.sex == \"H\":\n                                    assert metadata['sex'] == -1\n                                else:\n                                    assert False, \"Bad sex field in metadata\"\n                                assert slim_ind.population == metadata['subpopulation']\n                                assert np.allclose(slim_ind.pos, ts_individuals[ped_id].location)\n                                for n in ts_nodes:\n                                    assert not ts.node(n).is_sample()\n                            else:\n                                assert ped_id not in ts_individuals\n                        elif slim_ind.type==\"remember\":\n                            # permanently \"remember\"ed individuals and ones that exist during ts\n                            # output are always present, and their nodes should be marked as\n                            # as samples\n                            num_expected += 1\n                            assert ped_id in ts_individuals\n                            metadata = ts_individuals[ped_id].metadata\n                            assert slim_ind.population == metadata['subpopulation']\n                            assert np.allclose(slim_ind.pos, ts_individuals[ped_id].location)\n                            ts_nodes = set([ids[n] for n in slim_ind.nodes])\n                            ind_nodes = ts_individuals[ped_id].nodes\n                            # haplosomes can legit have all missing data in the tree sequence\n                            # in certain circumstances; for instance, if they have no coalescent\n                            # ancestors (since we simplify above), or if they were in the\n                            # original generation and Remembered.\n                            has_data = [node_has_data(ts, n) for n in ind_nodes]\n                            for n, h in zip(ind_nodes, has_data):\n                                assert n in ts_nodes or not h\n                            for n in ts_nodes:\n                                assert n in ind_nodes\n                                assert ts.node(n).is_sample()\n                            if ped_id not in alive:\n                                assert slim_ind.type == \"remember\"\n                        elif slim_ind.type==\"output\":\n                            num_expected += 1\n                            \n                    assert num_expected == ts.num_individuals\n\n\nclass TestChromosomes:\n\n    def chrom_details(self, chrom):\n        # in metadata:\n        # sex is 0 for female, 1 for male, -1 for hermaphrodite\n        # chrom is:\n        # \"A\" (autosome), the default\n        # \"H\" (haploid), specifying a haploid autosomal chromosome\n        #    that recombines in biparental crosses.\n        # Some sex-chromosome types are supported only in sexual models:\n        # \"X\" (X), an X chromosome that is diploid (XX) in females, haploid (X-) in males.\n        # \"Y\" (Y), a Y chromosome that is haploid (Y) in males, absent (-) in females.\n        # \"Z\" (Z), a Z chromosome that is diploid (ZZ) in males, haploid (-Z) in females.\n        # \"W\" (W), a W chromosome that is haploid (W) in females, absent (-) in males.\n        # And there are haploid chromosome types that are also supported only in sexual models:\n        # \"HF\" (haploid female-inherited), a haploid autosomal chromosome \n        #   inherited by both sexes from the first (female) parent in biparental crosses.\n        # \"FL\" (female line), specifying a haploid autosomal chromosome \n        #   inherited only by females, from the female parent, \n        #   represented by a null haplosome in males.\n        # \"HM\" (haploid male-inherited), a haploid autosomal chromosome \n        #   inherited by both sexes from the second (male) parent in biparental crosses.\n        # \"ML\" (male line), specifying a haploid autosomal chromosome \n        #   inherited only by males, from the male parent, \n        #   represented by a null haplosome in females.\n        # Finally, \"H-\" and \"-Y\", are supported for backward compatibility.\n        #\n        # This returns a dictionary with keys:\n        # ploidy: ploidy of chromsome; all inds should have this many\n        # (F/M/H): number of null chromosomes expected for this sex\n        sexes = [\"F\", \"M\", \"H\"]\n        if chrom == \"A\":\n            out = { \"ploidy\" : 2 }\n            out.update({ x: 0 for x in sexes })\n        elif chrom == \"H\":\n            out = { \"ploidy\" : 1 }\n            out.update({ x: 0 for x in sexes })\n        elif chrom == \"X\":\n            out = { \"ploidy\" : 2, \"F\": 0, \"M\": 1 }\n        elif chrom == \"Y\":\n            out = { \"ploidy\" : 1, \"F\": 1, \"M\": 0 }\n        elif chrom == \"Z\":\n            out = { \"ploidy\" : 2, \"F\": 1, \"M\": 0 }\n        elif chrom == \"W\":\n            out = { \"ploidy\" : 1, \"F\": 0, \"M\": 1 }\n        elif chrom == \"HF\":\n            out = { \"ploidy\" : 1, \"F\": 0, \"M\": 0 }\n        elif chrom == \"FL\":\n            out = { \"ploidy\" : 1, \"F\": 0, \"M\": 1 }\n        elif chrom == \"HM\":\n            out = { \"ploidy\" : 1, \"F\": 0, \"M\": 0 }\n        elif chrom == \"ML\":\n            out = { \"ploidy\" : 1, \"F\": 1, \"M\": 0 }\n        elif chrom == \"H-\":\n            out = { \"ploidy\" : 2, \"H\": 1 }\n        elif chrom == \"-Y\":\n            out = { \"ploidy\" : 2, \"F\": 2, \"M\": 1 }\n        else:\n            assert False, f\"Unknown chromosome type {chrom}\"\n        return out\n\n    def chrom_inheritance(self, chrom):\n        # This returns a dictionary with keys:\n        # F/M : dictionary with how many haplosomes should be inherited from said parent\n        sexes = [\"F\", \"M\", \"H\"]\n        if chrom == \"A\":\n            out = { \"F\" : { \"F\" : 1, \"M\" : 1 }, \"M\" : { \"F\" : 1, \"M\" : 1 } }\n        elif chrom == \"X\":\n            out = { \"F\" : { \"F\" : 1, \"M\" : 1 }, \"M\" : { \"F\" : 1, \"M\" : 0 } }\n        elif chrom == \"Y\":\n            out = { \"F\" : { \"F\" : 0, \"M\" : 0 }, \"M\" : { \"F\" : 0, \"M\" : 1 } }\n        elif chrom == \"Z\":\n            out = { \"F\" : { \"F\" : 0, \"M\" : 1 }, \"M\" : { \"F\" : 1, \"M\" : 1 } }\n        elif chrom == \"W\":\n            out = { \"F\" : { \"F\" : 1, \"M\" : 0 }, \"M\" : { \"F\" : 0, \"M\" : 0 } }\n        elif chrom == \"HF\":\n            out = { \"F\" : { \"F\" : 1, \"M\" : 0 }, \"M\" : { \"F\" : 1, \"M\" : 0 } }\n        elif chrom == \"FL\":\n            out = { \"F\" : { \"F\" : 1, \"M\" : 0 }, \"M\" : { \"F\" : 0, \"M\" : 0 } }\n        elif chrom == \"HM\":\n            out = { \"F\" : { \"F\" : 0, \"M\" : 1 }, \"M\" : { \"F\" : 0, \"M\" : 1 } }\n        elif chrom == \"ML\":\n            out = { \"F\" : { \"F\" : 0, \"M\" : 0 }, \"M\" : { \"F\" : 0, \"M\" : 1 } }\n        elif chrom == \"-Y\":\n            out = { \"F\" : { \"F\" : 0, \"M\" : 0 }, \"M\" : { \"F\" : 0, \"M\" : 1 } }\n        else:\n            assert False, f\"Unknown chromosome type {chrom}\"\n        return out\n\n\n    def is_chrom_vacant(self, k, b):\n        # From the SLiM manual on is_vacant:\n        # M bytes (uint8_t): a series of bytes comprising a bitfield of is_vacant\n        # values, true (1) if this node represents a null haplosome for a given\n        # chromosome, false (0) otherwise. For chromosomes with indices 0...N−1, the\n        # chromosome with index k has its is_vacant bit in bit k%8 of byte k/8, where\n        # byte 0 is the first byte in the series of bytes provided, and bit 0 is the\n        # least-significant bit, the one with value 0x01 (hexadecimal 1). The number\n        # of bytes present, M, is equal to (N+7)/8, the minimum number of bytes\n        # necessary. The operators / and % here are integer divide (rounding down)\n        # and integer modulo, respectively.\n        assert len(b) >= (1 + k) / 8\n        b = b[int(k / 8)]\n        i = k % 8\n        return (b >> i & 1) > 0\n\n    @pytest.mark.parametrize('recipe', recipe_eq(), indirect=True)\n    def test_chromosome_consistency(self, recipe):\n        # check whether chromsomes are null when they're supposed to be\n        # and individuals have the right number of chromosomes\n        for result in recipe[\"results\"]:\n            for tsl in result.get_ts():\n                for chrom_id in tsl:\n                    ts = tsl[chrom_id]\n                    chrom_type = ts.metadata['SLiM']['this_chromosome']['type']\n                    chrom_index = ts.metadata['SLiM']['this_chromosome']['index']\n                    details = self.chrom_details(chrom_type)\n                    if chrom_type in ['X', 'Y', 'Z', 'W', 'HF', 'FL', 'HM', 'ML']:\n                        assert ts.metadata['SLiM']['separate_sexes']\n                    for ind in ts.individuals():\n                        if ind.flags & (pyslim.INDIVIDUAL_ALIVE | pyslim.INDIVIDUAL_REMEMBERED) > 0:\n                            sex = {0 : \"F\", 1 : \"M\", -1 : \"H\"}[ind.metadata['sex']]\n                            assert sex in details, f\"Invalid sex {sex} for {chrom_type} chrom\"\n                            assert len(ind.nodes) == 2\n                            num_vacant = 0\n                            for ni in ind.nodes:\n                                n = ts.node(ni)\n                                has_data = (np.sum(ts.edges_parent == ni)\n                                            + np.sum(ts.edges_child == ni) > 0)\n                                is_vacant = self.is_chrom_vacant(chrom_index, n.metadata['is_vacant'])\n                                num_vacant += is_vacant\n                                if is_vacant:\n                                    assert not has_data\n                            assert num_vacant == 2 - details['ploidy'] + details[sex]\n                            if details['ploidy'] == 1:\n                                n = ts.node(ind.nodes[1])\n                                is_vacant = self.is_chrom_vacant(chrom_index, n.metadata['is_vacant'])\n                                assert is_vacant, \"Second node for haploid chromosomes should be vacant.\"\n\n    @pytest.mark.parametrize('recipe', recipe_eq('everyone'), indirect=True)\n    def test_chromosome_inheritance(self, recipe):\n        # check whether chromsomes are inherited from the right parent\n        for result in recipe[\"results\"]:\n            for tsl in result.get_ts():\n                for chrom_id in tsl:\n                    ts = tsl[chrom_id]\n                    chrom_type = ts.metadata['SLiM']['this_chromosome']['type']\n                    if chrom_type == \"H\":\n                        continue\n                    chrom_index = ts.metadata['SLiM']['this_chromosome']['index']\n                    inheritance = self.chrom_inheritance(chrom_type)\n                    for ind in ts.individuals():\n                        if len(ind.parents) > 0:\n                            sex = {0 : \"F\", 1 : \"M\", -1 : \"H\"}[ind.metadata['sex']]\n                            assert len(ind.nodes) == 2\n                            this_inh = { \"F\" : 0, \"M\" : 0 }\n                            for ni in ind.nodes:\n                                n = ts.node(ni)\n                                is_vacant = self.is_chrom_vacant(chrom_index, n.metadata['is_vacant'])\n                                ne = ts.edges_child == ni\n                                if is_vacant:\n                                    assert np.sum(ne) == 0\n                                else:\n                                    assert np.sum(ne) > 0\n                                    pnodes = ts.edges_parent[ne]\n                                    parents = [ts.node(u).individual for u in pnodes]\n                                    assert len(set(parents)) == 1\n                                    assert parents[0] in ind.parents\n                                    psex = {0 : \"F\", 1 : \"M\", -1 : \"H\"}[ts.individual(parents[0]).metadata['sex']]\n                                    this_inh[psex] += 1\n                                    if chrom_type in [\"Y\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"-Y\"]:\n                                        # no recombination\n                                        assert len(pnodes) == 1\n                            assert this_inh == inheritance[sex]\n\n\n\n"
  },
  {
    "path": "treerec/tests/test_metadata_schemas.py",
    "content": "\"\"\"\nTests for metadata schema stuff.\nIndividual recipes can be specified by decorating with\n@pytest.mark.parametrize('recipe', ['test_____my_specific_recipe.slim'], indirect=True)\n\"\"\"\nimport json\nimport tskit\nimport msprime\nimport pyslim\nimport pytest\n\nfrom recipe_specs import recipe_eq\n\ntable_names = [\n    'edges', 'individuals', 'migrations', 'mutations',\n    'nodes', 'populations', 'sites'\n]\n\n# this is for indexing pyslim.slim_metadata_schemas\ntable_namex = [\n    'edge', 'individual', 'mutation',\n    'node', 'population', 'site'\n]\n\nclass TestMetadataSchemas:\n\n    def round_trip_schema(self, table):\n        a = table.metadata_schema\n        new_table = table.copy()\n        new_table.assert_equals(table)\n        b = new_table.metadata_schema\n        assert a == b\n        assert a.schema == b.schema\n        new_table.clear()\n        new_table.set_columns(**table.asdict())\n        new_table.assert_equals(table)\n        b = new_table.metadata_schema\n        assert a == b\n        assert a.schema == b.schema\n\n    def copy_schema(self, table):\n        new_table = table.__class__()\n        new_table.schema = table.schema\n        assert new_table.schema == table.schema\n        assert new_table.schema.schema == table.schema.schema\n\n    @pytest.mark.parametrize('recipe, table_name', indirect=['recipe'], argvalues=[\n        ('test_____pop_names_pX.slim', x) for x in table_names\n    ])\n    def test_slim_canonical_json(self, recipe, table_name):\n        # Here we want to test that whatever tskit does to the schema\n        # when copying tables doesn't change the underlying .schema;\n        # I can't figure out a good way to actually do that besides\n        # making a copy of the tables.\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        t = ts.tables.table_name_map[table_name]\n        tc = t.copy()\n        # this should be true since it's been canonicalized\n        # to produce the repr() which gets compared:\n        assert t.metadata_schema == tc.metadata_schema\n        if t.metadata_schema.schema != tc.metadata_schema.schema:\n            # print out JSON that should give us a correct schema\n            # so we can put it in the SLiM code\n            j = tskit.canonical_json(tc.metadata_schema.schema)\n            # this should succeed because json.loads returns an unordered\n            # dictionary, and the two differ only on ordering\n            assert json.loads(j) == t.metadata_schema.schema\n            # put back in the placeholder\n            if table_name == \"nodes\":\n                u = '\"length\":1'\n                ix = j.find(u)\n                j = j[:ix] + '\"length\":\"%d\"' + j[(ix+len(u)):]\n            print(f\"Schema for {table_name} does not match. \"\n                  \"Use this (equivalent) JSON.\")\n            print(\".................... begin\")\n            print(j)\n            print(\"...................... end\")\n        assert t.metadata_schema.schema == tc.metadata_schema.schema\n\n    @pytest.mark.parametrize('recipe, table_name', indirect=['recipe'], argvalues=[\n        ('test_____pop_names_pX.slim', x) for x in table_names\n    ])\n    def test_slim_round_trip(self, recipe, table_name):\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        self.round_trip_schema(ts.tables.table_name_map[table_name])\n\n    @pytest.mark.parametrize('table_name', argvalues=table_names)\n    def test_annotate_round_trip(self, table_name):\n        ts = msprime.sim_ancestry(1, sequence_length=10, random_seed=123)\n        ts = msprime.sim_mutations(ts, rate=1, random_seed=123)\n        assert ts.num_mutations > 0\n        t = ts.dump_tables()\n        pyslim.annotate_tables(t, model_type='WF', tick=1)\n        self.round_trip_schema(t.table_name_map[table_name])\n\n    @pytest.mark.parametrize('table_name', argvalues=table_namex)\n    def test_json_round_trip(self, table_name):\n        # pyslim schema -> json -> schema\n        orig = pyslim.slim_metadata_schemas[table_name]\n        j = tskit.canonical_json(orig.schema)\n        new = tskit.MetadataSchema(json.loads(j))\n        assert new == orig\n        assert new.schema == orig.schema\n\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/dont_test_recapitation.py",
    "content": "import msprime\nimport pyslim\nimport numpy as np\n\ndecap = pyslim.load(\"temp/decapitated.trees\", slim_format=True)\n\nrecap = []\nrecap_simplified = []\nfor _ in range(10):\n    recap = decap.recapitate(recombination_rate=1e-6, Ne=1000)\n    recap_mut = pyslim.mutate(recap,\n                rate=1e-6, keep=True)\n    ru = recap.simplify(ru.samples())\n    recap_simplified.append(ru)\n\ndef get_stats(ts):\n    bs = msprime.BranchLengthStatCalculator(ts)\n    stats = {'num_trees' : ts.num_trees,\n             'sequence_length' : ts.sequence_length,\n             'num_samples' : ts.num_samples,\n             'num_mutations' : ts.num_mutations,\n             'divergence' : -1 # bs.divergence(sample_sets=[list(ts.samples())], windows=[0.0, ts.sequence_length])\n             }\n    print(stats)\n    return stats\n\ndef summarize_stats(tslist):\n    statlist = list(map(get_stats, tslist))\n    out = {}\n    for a in statlist[0]:\n        x = [u[a] for u in statlist]\n        out[a] = {'mean':np.mean(x), 'sd':np.std(x)*np.sqrt(len(x)/(len(x)-1))}\n    return out\n\nprint(\"recapitated:\")\nrecap_stats = summarize_stats(recap)\nprint(\"-----------------------\")\nprint(\"recapitated | simplified:\")\nrecap_simplified_stats = summarize_stats(recap_simplified)\nprint(\"-----------------------\")\n\nprint(\"-----------------------\")\nprint(\"  Summaries: \")\n\nprint(\"decapitated:\")\nget_stats(decap)\nprint(\"\\n\")\n\nprint(\"recapitated:\")\nprint(recap_stats)\nprint(\"\\n\")\n\nprint(\"recapitated | simplified:\")\nprint(recap_simplified_stats)\nprint(\"\\n\")\n"
  },
  {
    "path": "treerec/tests/test_recipes/dont_test_recapitation.slim",
    "content": "initialize()\n{\n    initializeTreeSeq(); \n    initializeMutationRate(1e-6);\n    initializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n    initializeGenomicElementType(\"g1\", m1, 1.0);\n    initializeGenomicElement(g1, 0, 99999);\n    initializeRecombinationRate(1e-6);\n}\n1\nearly() {\n    sim.addSubpop(\"p1\", 1000);\n}\n500\nearly() {\n    sim.treeSeqOutput(\"temp/decapitated.trees\");\n    sim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_ancestral_marks.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeGenomicElementType(\"g1\",m1,1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n}   \n\n1 early() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n10 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_ongoing_muts.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",8);  \n\n\tinitializeGenomicElementType(\"g1\",m1,1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",100);\n}   \n\n1 early() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_sexual_WF.slim",
    "content": "initialize() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\",10);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\n2 early() {\n\taddAncestralSamples(5);\n}\n\n10 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_sexual_nonwf.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tinitializeSex('A');\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction(NULL,\"F\") {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}   \n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_simple_nonwf.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}\n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_000_withdraw_indivs.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tinitializeSex('A');\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction(NULL,\"F\") {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}   \n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\nmodifyChild() {\n\t// discard half of offspring arbitrarily\n\treturn (rbinom(1, 1, 0.5) > 0);\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_002_quick_neutral.slim",
    "content": "// quick neutral.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script with a quick, vanilla neutral simulation; this is the SLiMgui default model\n//\ninitialize() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n200 late() {\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_004 simple sexual A.slim",
    "content": "// simple sexual A.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for the simple autosomal case\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeSex('A');\n\tinitializeMutationRate(1e-2);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeRecombinationRate(1e-2);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\taddAncestralSamples(5);\n}\n50 early() {\n\taddAncestralSamples(5);\n}\n\n100 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\t// cat(\"\\nTotal mutation frequencies: \" + sum(sim.mutationFrequencies(NULL)) + \"\\n\"); \n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_005 simple sexual X.slim",
    "content": "// simple sexual X.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for the simple X chromosome case\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeSex('X');\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\taddAncestralSamples(5);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_006 simple sexual Y.slim",
    "content": "// simple sexual Y.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for the simple Y chromosome case\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeSex('Y');\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\taddAncestralSamples(5);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\tcat(\"\\nTotal mutation frequencies: \" + sum(sim.mutationFrequencies(NULL)) + \"\\n\"); \n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_007 cloning and selfing.slim",
    "content": "// cloning and selfing.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for clonign and selfing\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\t\n\tp1.setSelfingRate(0.4);\n\tp1.setCloningRate(0.4);\n\n\taddAncestralSamples(5);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\tcat(\"\\nTotal mutation frequencies: \" + sum(sim.mutationFrequencies(NULL)) + \"\\n\"); \n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_008 cyclical subpop.slim",
    "content": "// cyclical subpop.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script using a cyclically varying subpop size\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n}\nearly() {\n\tnewSize = cos((community.tick - 1) / 100) * 100 + 150;\n\tp1.setSubpopulationSize(asInteger(newSize));\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\t// cat(\"\\nTotal mutation frequencies: \" + sum(sim.mutationFrequencies(NULL)) + \"\\n\"); \n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_009 linear island.slim",
    "content": "// linear island.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script using a linear island neutral model\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsubpopCount = 10;\n\tfor (i in 1:subpopCount)\n\t\tsim.addSubpop(i, 20);\n\tfor (i in 2:subpopCount)\n\t\tsim.subpopulations[i-1].setMigrationRates(i-1, 0.2);\n\tfor (i in 1:(subpopCount-1))\n\t\tsim.subpopulations[i-1].setMigrationRates(i+1, 0.05);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\tcat(\"\\nTotal mutation frequencies: \" + sum(sim.mutationFrequencies(NULL)) + \"\\n\"); \n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_013 gene conversion.slim",
    "content": "// gene conversion.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script with a longer vanilla neutral simulation\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-6);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-7);\n\tinitializeGeneConversion(0.2, 25, 0.75);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 200);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_024 gene drive.slim",
    "content": "// gametophytic self-incompatibility.slim : ^Outcome: (.*)$\n//\n// A test script for modeling gametophytic self-incompatibility with a modifyChild() callback\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);   // neutral\n\tinitializeMutationType(\"m2\", 0.5, \"f\", -0.1);  // MCR complex\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tfor (i in 0:5)\n\t\tsim.addSubpop(i, 100);\n\tfor (i in 1:5)\n\t\tsim.subpopulations[i].setMigrationRates(i-1, 0.001);\n\tfor (i in 0:4)\n\t\tsim.subpopulations[i].setMigrationRates(i+1, 0.1);\n}\n100 late() {\n\ttarget = sample(p0.haplosomes, 50);\n\n\t// use old mutation addition formula for backward compatibility\n\tmut = target[0].addNewDrawnMutation(m2, 10000);\n\ttarget[1:49].addMutations(mut);\n}\n100:500 late() {\n\tif (sim.countOfMutationsOfType(m2) == 0)\n\t{\n\t\tfixed = any(sim.substitutions.mutationType == m2);\n\t\tcat(ifelse(fixed, \"Outcome: FIXED \", \"Outcome: LOST \") + community.tick + \"\\n\");\n\t\toutputMutationResult();\n      outputIndividuals();\n      saveTreeSeq();\n\t\tsim.simulationFinished();\n\t}\n}\nmutationEffect(m2) {\n\treturn 1.5 - subpop.id * 0.15;\n}\n100:500 modifyChild() {\n\tmut = sim.mutationsOfType(m2);\n\tif (size(mut) == 1)\n\t{\n\t\thasMutOnChromosome1 = child.haploidGenome1.containsMutations(mut);\n\t\thasMutOnChromosome2 = child.haploidGenome2.containsMutations(mut);\n\t\tif (hasMutOnChromosome1 & !hasMutOnChromosome2)\n\t\t\tchild.haploidGenome2.addMutations(mut);\n\t\telse if (hasMutOnChromosome2 & !hasMutOnChromosome1)\n\t\t\tchild.haploidGenome1.addMutations(mut);\n\t}\n\treturn T;\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_038 pure cloning.slim",
    "content": "// pure cloning.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for cloning\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tp1.setCloningRate(1.0);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_039 pure selfing.slim",
    "content": "// pure selfing.slim : ^Total mutation frequencies: (.*)$\n//\n// A test script for selfing\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tp1.setSelfingRate(1.0);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_040 pure cloning sexual.slim",
    "content": "// pure cloning sexual.slim : ^Mean mutation frequency: (.*)$\n//\n// A test script for cloning\n//\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tinitializeSex(\"A\");\n\tinitializeMutationRate(1e-7);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t\n\tp1.setCloningRate(1.0);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_042 haploid clonals.slim",
    "content": "// haploid clonals.slim : ^Fixed mutation count: (.*)$\n//\n// A test script for haploid clonal organisms, measured by heterozygosity\n//\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tdefineConstant(\"L\", 1e6);\n\tdefineConstant(\"mu\", 1e-7);\n\tdefineConstant(\"N\", 500);\n\t\n\tinitializeMutationRate(mu);\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, L-1);\n\tinitializeRecombinationRate(0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", N);\n\tp1.setCloningRate(1.0);\n}\nmodifyChild() {\n\tchild.haploidGenome2.removeMutations(child.haploidGenome2.mutations);\n\treturn T;\n}\nlate() {\n\tmuts = sim.mutationsOfType(m1);\n\tfreqs = sim.mutationFrequencies(NULL, muts);\n\tsim.subpopulations.haplosomes.removeMutations(muts[freqs == 0.5], T);\n}\n5 early() {\n\taddAncestralSamples(5);\n}\n9 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_097 modeling nucleotides.slim",
    "content": "// modeling nucleotides.slim : ^Weighted selection coefficient total: (.*)$\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\tdefineConstant(\"C\", 100);\t  // number of loci\n\t\n\t// Create our loci\n\tfor (locus in 0:(C-1))\n\t{\n\t\t// Effects for the nucleotides ATGC are drawn from a normal DFE\n\t\teffects = rnorm(4, mean=0, sd=0.05);\n\t\t\n\t\t// Each locus is set up with its own mutType and geType\n\t\tmtA = initializeMutationType(locus*4 + 0, 0.5, \"f\", effects[0]);\n\t\tmtT = initializeMutationType(locus*4 + 1, 0.5, \"f\", effects[1]);\n\t\tmtG = initializeMutationType(locus*4 + 2, 0.5, \"f\", effects[2]);\n\t\tmtC = initializeMutationType(locus*4 + 3, 0.5, \"f\", effects[3]);\n\t\tmt = c(mtA, mtT, mtG, mtC);\n\t\tgeType = initializeGenomicElementType(locus, mt, c(1,1,1,1));\n\t\tinitializeGenomicElement(geType, locus, locus);\n\t\t\n\t\t// We do not want mutations to stack or fix\n\t\tmt.mutationStackPolicy = \"l\";\n\t\tmt.mutationStackGroup = -1;\n\t\tmt.convertToSubstitution = F;\n\t\t\n\t\t// Each mutation type knows the nucleotide it represents\n\t\tmtA.setValue(\"nucleotide\", \"A\");\n\t\tmtT.setValue(\"nucleotide\", \"T\");\n\t\tmtG.setValue(\"nucleotide\", \"G\");\n\t\tmtC.setValue(\"nucleotide\", \"C\");\n\t}\n\t\n\tinitializeMutationRate(1e-6);   // includes 25% identity mutations\n\tinitializeRecombinationRate(1e-8);\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\", 200);\n\t\n\t// The initial population is fixed for a single wild-type\n\t// nucleotide fixed at each locus in the chromosome\n\tgeTypes = sim.chromosome.genomicElements.genomicElementType;\n\n\tif (isNULL(version()))\t// backward compatibility\t\t\n\t   mutTypes = apply(geTypes, \"sample(applyValue.mutationTypes, 1, weights=applyValue.mutationFractions);\");\n\telse\n\t\tmutTypes = sapply(geTypes, \"sample(applyValue.mutationTypes, 1, weights=applyValue.mutationFractions);\");\n\t\n\t// don't rely on vectorized addNewDrawnMutation()...\n\tg = p1.haplosomes;\n\t\n\tfor (pos in 0:(C-1))\n\t\tg.addNewDrawnMutation(mutTypes[pos], pos);\n\t\n\tcat(\"Initial nucleotide sequence:\");\n\tcat(\" \" + paste(mutTypes.getValue(\"nucleotide\")) + \"\\n\\n\");\n}\n\n2: late() {\n\t// optionally, we can unique new mutations onto existing mutations\n\t// this runs only in 2: - it is assumed the gen. 1 setup is uniqued\n\tallMuts = sim.mutations;\n\tnewMuts = allMuts[allMuts.originTick == community.tick];\n\t\n\tif (size(newMuts))\n\t{\n\t\thaplosomes = sim.subpopulations.haplosomes;\n\t\t\n\t\toldMuts = allMuts[allMuts.originTick != community.tick];\n\t\toldMutsPositions = oldMuts.position;\n\t\t\n\t\tnewMutsPositions = newMuts.position;\n\t\tuniquePositions = unique(newMutsPositions, preserveOrder=F);\n\t\toverlappingMuts = (size(newMutsPositions) != size(uniquePositions));\n\t\t\n\t\tfor (newMut in newMuts)\n\t\t{\n\t\t\tnewMutLocus = newMut.position;\n\t\t\tnewMutType = newMut.mutationType;\n\t\t\toldLocus = oldMuts[oldMutsPositions == newMutLocus];\n\t\t\toldMatched = oldLocus[oldLocus.mutationType == newMutType];\n\t\t\t\n\t\t\tif (size(oldMatched) == 1)\n\t\t\t{\n\t\t\t\t// We found a match; this nucleotide already exists, substitute\n\t\t\t\tcontaining = haplosomes[haplosomes.containsMutations(newMut)];\n\t\t\t\tcontaining.removeMutations(newMut);\n\t\t\t\tcontaining.addMutations(oldMatched);\n\t\t\t}\n\t\t\telse if (overlappingMuts)\n\t\t\t{\n\t\t\t\t// First instance; it is now the standard reference mutation\n\t\t\t\t// This only needs to be done if overlappingMuts==T because\n\t\t\t\t// only then will we see another new mut at this position.\n\t\t\t\toldMuts = c(oldMuts, newMut);\n\t\t\t\toldMutsPositions = c(oldMutsPositions, newMutLocus);\n\t\t\t}\n\t\t}\n\t}\n}\n\n100 early() {\n\taddAncestralSamples(5);\n}\n\n500 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\t// muts = sim.mutations;   // all mutations, no uniquing\n\t// freqs = sim.mutationFrequencies(NULL, muts);\n\t// selCoeffs = muts.selectionCoeff;\n\t// totalSel = sum(freqs * selCoeffs);\n\t// \n\t// catn(\"Weighted selection coefficient total: \" + totalSel);\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_1610_modeling pseudo-autosomal regions.slim",
    "content": "// Keywords: multiple chromosomes, pseudo-autosomal region (PAR)\n\ninitialize() {\n\tdefineConstant(\"A1_LEN\", 2e5);\n\tdefineConstant(\"PAR1_LEN\", 27714);\n\tdefineConstant(\"PAR2_LEN\", 3295);\n\tdefineConstant(\"X_LEN\", 1560408 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"Y_LEN\", 572274 - (PAR1_LEN + PAR2_LEN));\n\tdefineConstant(\"MU\", 1e-6);\n\tdefineConstant(\"R\", 1e-5);\n\tdefineConstant(\"N\", 20);\n\t\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tinitializeSex();\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0).convertToSubstitution = T;\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:5, length in c(A1_LEN, PAR1_LEN, X_LEN, Y_LEN, PAR2_LEN),\n\t\ttype in c(\"A\",\"A\",\"X\",\"Y\",\"A\"), symbol in c(\"A1\",\"P1\",\"X\",\"Y\",\"P2\"))\n\t{\n\t\tchr = initializeChromosome(id, length, type=type, symbol=symbol);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t\tinitializeMutationRate(MU);\n\t\tinitializeRecombinationRate(R);\n\t\tdefineConstant(paste0(\"CHR_\", symbol), chr);\n\t}\n}\n1 late() {\n\tsim.addSubpop(\"p1\", N);\n}\nreproduction()\n{\n\tfor (i in seqLen(N))\n\t{\n\t\tparentF = p1.sampleIndividuals(1, sex=\"F\");\n\t\tparentM = p1.sampleIndividuals(1, sex=\"M\");\n\t\n\t\t// generate breakpoints for the female parent (X recombines)\n\t\tbreaks_F_P1 = CHR_P1.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_X = CHR_X.drawBreakpoints(parent=parentF);\n\t\tbreaks_F_P2 = CHR_P2.drawBreakpoints(parent=parentF);\n\t\t\n\t\t// generate breakpoints for the male parent (only PARs recombine)\n\t\tbreaks_M_P1 = CHR_P1.drawBreakpoints(parent=parentM);\n\t\tbreaks_M_P2 = CHR_P2.drawBreakpoints(parent=parentM);\n\t\t\n\t\t// get the haplosomes for each chromosome in each parent\n\t\tstrands_F_P1 = parentF.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_F_X = parentF.haplosomesForChromosomes(CHR_X);    // 2\n\t\tstrands_F_P2 = parentF.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\tstrands_M_P1 = parentM.haplosomesForChromosomes(CHR_P1);  // 2\n\t\tstrands_M_X = parentM.haplosomesForChromosomes(CHR_X)[0]; // 1\n\t\tstrands_M_Y = parentM.haplosomesForChromosomes(CHR_Y);    // 1\n\t\tstrands_M_P2 = parentM.haplosomesForChromosomes(CHR_P2);  // 2\n\t\t\n\t\t// choose initial copy strand indices for PAR1 in both (coin flip)\n\t\tinitial_F_P1 = rbinom(1, 1, 0.5);\n\t\tinitial_M_P1 = rbinom(1, 1, 0.5);\n\t\t\n\t\t// generate the inheritance dictionary for PAR1\n\t\ts1_F_P1 = strands_F_P1[initial_F_P1];\n\t\ts2_F_P1 = strands_F_P1[1 - initial_F_P1];\n\t\t\n\t\ts1_M_P1 = strands_M_P1[initial_M_P1];\n\t\ts2_M_P1 = strands_M_P1[1 - initial_M_P1];\n\t\t\n\t\tpattern = sim.addPatternForRecombinant(CHR_P1, NULL,\n\t\t\ts1_F_P1, s2_F_P1, breaks_F_P1, s1_M_P1, s2_M_P1, breaks_M_P1,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// the initial strand for the X in the female follows from the\n\t\t// above, because PAR1 is physically linked to the start of the\n\t\t// X; if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_X = initial_F_P1;\n\t\tif (size(breaks_F_P1) % 2 == 1) initial_F_X = 1 - initial_F_X;\n\t\tif (runif(1) < R) initial_F_X = 1 - initial_F_X;\n\t\t\n\t\t// do the same for the male, but the \"initial strand\" is the\n\t\t// X if 0, the Y if 1, and it determines the offspring sex\n\t\tinitial_M_XY = initial_M_P1;\n\t\tif (size(breaks_M_P1) % 2 == 1) initial_M_XY = 1 - initial_M_XY;\n\t\tif (runif(1) < R) initial_M_XY = 1 - initial_M_XY;\n\t\t\n\t\tsex = ((initial_M_XY == 0) ? \"F\" else \"M\");\n\t\t\n\t\t// generate the inheritance dictionaries for the X and Y\n\t\ts1_F_X = strands_F_X[initial_F_X];\n\t\ts2_F_X = strands_F_X[1 - initial_F_X];\n\t\t\n\t\tif (sex == \"F\")\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, strands_M_X, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForNull(CHR_Y, pattern, sex=sex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsim.addPatternForRecombinant(CHR_X, pattern,\n\t\t\t\ts1_F_X, s2_F_X, breaks_F_X, NULL, NULL, NULL,\n\t\t\t\tsex=sex, randomizeStrands=F);\n\t\t\tsim.addPatternForClone(CHR_Y, pattern, parent=parentM, sex=sex);\n\t\t}\n\t\t\n\t\t// and the initial copy strand for PAR2 follows from the above,\n\t\t// because PAR2 is physically linked to the end of the X/Y;\n\t\t// if an odd number of crossovers occurred, switch strands\n\t\tinitial_F_P2 = initial_F_X;\n\t\tif (size(breaks_F_X) % 2 == 1) initial_F_P2 = 1 - initial_F_P2;\n\t\tif (runif(1) < R) initial_F_P2 = 1 - initial_F_P2;\n\t\t\n\t\tinitial_M_P2 = initial_M_XY;\n\t\tif (runif(1) < R) initial_M_P2 = 1 - initial_M_P2;\n\t\t\n\t\t// generate the inheritance dictionary for PAR2\n\t\ts1_F_P2 = strands_F_P2[initial_F_P2];\n\t\ts2_F_P2 = strands_F_P2[1 - initial_F_P2];\n\t\t\n\t\ts1_M_P2 = strands_M_P2[initial_M_P2];\n\t\ts2_M_P2 = strands_M_P2[1 - initial_M_P2];\n\t\t\n\t\tsim.addPatternForRecombinant(CHR_P2, pattern,\n\t\t\ts1_F_P2, s2_F_P2, breaks_F_P2, s1_M_P2, s2_M_P2, breaks_M_P2,\n\t\t\trandomizeStrands=F);\n\t\t\n\t\t// finally, generate the offspring following the pattern dictionary\n\t\tsubpop.addMultiRecombinant(pattern, sex=sex,\n\t\t\tparent1=parentF, parent2=parentM, randomizeStrands=F);\n\t}\n\t\n\tself.active = 0;\n}\n2: early() {\n\t// non-overlapping generations\n\tadults = p1.subsetIndividuals(minAge=1);\n\tsim.killIndividuals(adults);\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_169_complex multi-chromosome inheritance.slim",
    "content": "// Keywords: multiple chromosomes, inheritance patterns, mating systems\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"K\", 20);\t// carrying capacity\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\tids = 1:7;\n\tsymbols = c(\"A\", \"X\", \"Y\", \"P\", \"Q\", \"R\", \"S\");\n\tlengths = c(3e4, 2e4, 1e4, 1e4, 1e4, 1e4, 1e4);\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"H\", \"H\", \"H\");\n\t\n\tfor (id in ids, symbol in symbols, length in lengths, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-5);\n\t\tinitializeRecombinationRate(1e-5);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t}\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\t\n\tpattern = Dictionary();\n\tsim.addPatternForClone(\"P\", pattern, individual);\n\tsim.addPatternForClone(\"Q\", pattern, runif(1) < 0.5 ? individual else mate);\n\tsim.addPatternForCross(\"R\", pattern, individual, mate);\n\tind_hapS = individual.haplosomesForChromosomes(\"S\");\n\tmate_hapS = mate.haplosomesForChromosomes(\"S\");\n\tsim.addPatternForRecombinant(\"S\", pattern, ind_hapS, mate_hapS, NULL,\n\t\tNULL, NULL, NULL);\n\tsubpop.addMultiRecombinant(pattern, parent1=individual, parent2=mate,\n\t\trandomizeStrands=F);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_831_multiple diploid autosomes.slim",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeMutationType(\"m2\", 0.5, \"g\", -0.03, 0.2);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElementType(\"g2\", c(m1, m2), c(1,2));\n\t\n\tinitializeChromosome(1, 1e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n\t\n\tinitializeChromosome(2, 2e5);\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeGenomicElement(g2, 1e5, 1e5+5e4-1);\n\tinitializeGenomicElement(g1, 1e5+5e4, 2e5-1);\n\tinitializeMutationRate(2e-7);\n\tinitializeRecombinationRate(1e-7);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n100 early() {\n\taddAncestralSamples(5);\n}\n150 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_832_clonal haploids and chromosome types.slim",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, 1e5, type=\"H\");\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(0.0);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n\tp1.setCloningRate(1.0);\n}\n100 early() {\n\taddAncestralSamples(5);\n}\n150 late() { \n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_833_haploids with recombination.slim",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tinitializeMutationType(\"m1\", 1.0, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, 1e5, type=\"H\");\n\tinitializeGenomicElement(g1, 0, 1e5-1);\n\tinitializeMutationRate(1e-7);\n\tinitializeRecombinationRate(1e-8);\n}\n1 early() { sim.addSubpop(\"p1\", 100); }\n10 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_834_sex-chromosome evolution and null haplosomes.slim",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"X_LEN\", 15604);\n\tdefineConstant(\"Y_LEN\", 5722);\n\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tinitializeChromosome(1, X_LEN, type=\"X\", symbol=\"X\");\n\tinitializeGenomicElement(g1, 0, X_LEN-1);\n\tinitializeMutationRate(1e-4);\n\tinitializeRecombinationRate(1e-4);\n\t\n\tinitializeChromosome(2, Y_LEN, type=\"Y\", symbol=\"Y\");\n\tinitializeGenomicElement(g1, 0, Y_LEN-1);\n\tinitializeMutationRate(1e-4);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 50);\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n25 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_836_output from multiple-chromosome models.slim",
    "content": "// Keywords: multiple chromosomes\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\t\n\tfor (id in 1:3, type in c(\"A\", \"X\", \"Y\"))\n\t{\n\t\tinitializeChromosome(id, 1e6, type=type, symbol=type);\n\t\tinitializeGenomicElement(g1, 0, 1e5-1);\n\t\tinitializeMutationRate(1e-6);\n\t\tinitializeRecombinationRate(1e-6);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 20);\n}\n20 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____H-_chromosome.slim",
    "content": "initialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"K\", 20);\t// carrying capacity\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\ttypes = c(\"H-\", \"A\", \"H-\", \"H\");\n\tsymbols = c(\"H1\", \"A\", \"H2\", \"H\");\n\tids = 1 + seqAlong(types);\n   length = 1e4;\n\t\n\tfor (id in ids, symbol in symbols, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-5);\n\t\tinitializeRecombinationRate(1e-5);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t}\n}\nreproduction(NULL) {\n\tsubpop.addCloned(individual, count=rpois(1, lambda=1.5));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____all_the_chromosome_types.slim",
    "content": "// Keywords: multiple chromosomes, inheritance patterns, mating systems\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"K\", 20);\t// carrying capacity\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"-Y\");\n\tsymbols = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"nY\");\n\tids = 1 + seqAlong(types);\n   length = 1e4;\n\t\n\tfor (id in ids, symbol in symbols, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-5);\n\t\tinitializeRecombinationRate(1e-5);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t}\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\tsubpop.addCrossed(individual, mate, count=rpois(1, lambda=1.5));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n10 early() {\n\taddAncestralSamples(5);\n}\n30 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____all_the_chromosomes.slim",
    "content": "// Keywords: multiple chromosomes, inheritance patterns, mating systems\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"K\", 20);\t// carrying capacity\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"-Y\");\n\tsymbols = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"nY\");\n\tids = 1 + seqAlong(types);\n   length = 1e4;\n\t\n\tfor (id in ids, symbol in symbols, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-5);\n\t\tinitializeRecombinationRate(1e-5);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t}\n}\nreproduction(NULL, \"F\") {\n\tmate = subpop.sampleIndividuals(1, sex=\"M\");\n\tsubpop.addCrossed(individual, mate, count=rpois(1, lambda=1.5));\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n}\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\nlate() {\n   addAncestralSamples(p1.individualCount);\n}\n10 late() {\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____ancestral_marks.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeGenomicElementType(\"g1\",m1,1.0);\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n}   \n\n1 early() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n10 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____multipops.slim",
    "content": "// A test script to check that adding and removing populations at various times\n// doesn't run into issues.\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq(simplificationInterval=20);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\n50 late() {\n    sim.addSubpop(\"p0\", 100);\n\t// permanently remember the first 5 individuals\n    for (p in sim.subpopulations) {\n      sim.treeSeqRememberIndividuals(p.individuals[1:5], permanent=T);\n      addIndividuals(p.individuals[1:5]);\n    }\n}\n\n100 late() {\n    sim.addSubpop(\"p3\", 20);\n    p1.setSubpopulationSize(0);\n}\n\n150 late() {\n    sim.addSubpopSplit(\"p2\", 20, p0);\n    for (p in sim.subpopulations) {\n      sim.treeSeqRememberIndividuals(p.individuals[1:5], permanent=T);\n      addIndividuals(p.individuals[1:5]);\n    }\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____no_generations.slim",
    "content": "initialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\tdefineConstant(\"K\", 20);\t// carrying capacity\n\tinitializeSex();\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tm1.convertToSubstitution = T;\n\t\n\ttypes = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"-Y\");\n\tsymbols = c(\"A\", \"X\", \"Y\", \"H\", \"Z\", \"W\", \"HF\", \"FL\", \"HM\", \"ML\", \"nY\");\n\tids = 1 + seqAlong(types);\n   length = 1e4;\n\t\n\tfor (id in ids, symbol in symbols, type in types)\n\t{\n\t\tinitializeChromosome(id, length, type, symbol);\n\t\tinitializeMutationRate(1e-5);\n\t\tinitializeRecombinationRate(1e-5);\n\t\tinitializeGenomicElement(g1, 0, length-1);\n\t}\n}\n1 early() {\n\tsim.addSubpop(\"p1\", K);\n\toutputIndividuals();\n   saveTreeSeq();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____pop_names_nondefault.slim",
    "content": "initialize() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n\tinitializeTreeSeq(); \n\t\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0); // Neutral mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1000);\n\tinitializeRecombinationRate(1e-8);\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n    p1.name = \"the_p1\";\n}\n\n10 early() {\n\tsim.addSubpopSplit(\"p3\", 101, p1);\n    p3.name = \"the_p3\";\n}\n\n11 early() {\n\tp1.setSubpopulationSize(0);\n}\n\n20 late() {\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____pop_names_pX.slim",
    "content": "initialize() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init.slim\");\n\tinitializeTreeSeq(); \n\t\n\tinitializeMutationRate(0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0); // Neutral mutations\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 1000);\n\tinitializeRecombinationRate(1e-8);\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 100);\n}\n\n10 early() {\n\tsim.addSubpopSplit(\"p3\", 101, p1);\n}\n\n11 early() {\n\tp1.setSubpopulationSize(0);\n}\n\n20 late() {\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____remember_individuals.slim",
    "content": "// A test script to check that remembered individuals are output in the TS\n// uses a modified version of the standard continuous space recipe, so that\n// we can check on the x,y position of individuals.\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\n1 late() {\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n\n50 late() {\n\t// permanently remember the first 5 individuals\n\tsim.treeSeqRememberIndividuals(p1.individuals[1:5], permanent=T);\n\taddIndividuals(p1.individuals[1:5]);\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____retain_and_remember_individuals.slim",
    "content": "// A test script to check that some retained individuals are output in the TS\n// uses a modified version of the standard continuous space recipe, so that\n// we can check on the x,y position of individuals.\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\n1 late() {\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n\n50 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain\");\n}\n\n100 late() {\n\t// also retain all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain\");\n\t// but also remember a few of them\n\tsim.treeSeqRememberIndividuals(p1.individuals[1:5]);\n\taddIndividuals(p1.individuals[1:5], \"remember\");\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____retain_individuals_nonWF.slim",
    "content": "// A test script to check that some retained individuals are output in the TS\n// uses a modified version of the standard continuous space recipe, so that\n// we can check on the x,y position of individuals.\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n\tdefineConstant(\"K\", 500); //carrying capacity for global density dependence\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1)); //random mating\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount; //scale fitness (so that some individuals die when number of individuals is greater than K)\n}\n\n1 late() {\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n\n50 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain\");\n}\n\n100 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain\");\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____retain_individuals_nonWF_unary.slim",
    "content": "// A test script to check that some retained individuals are output in the TS\n// uses a modified version of the standard continuous space recipe, so that\n// we can check on the x,y position of individuals.\n\ninitialize() {\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq(retainCoalescentOnly=F);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n\tdefineConstant(\"K\", 500); //carrying capacity for global density dependence\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual, subpop.sampleIndividuals(1)); //random mating\n}\n\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount; //scale fitness (so that some individuals die when number of individuals is greater than K)\n}\n\n1 late() {\n\t// initial positions are random in ([0,1], [0,1])\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n\n10 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain_even_if_unary\");\n}\n\n20 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain_even_if_unary\");\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____retain_individuals_unary.slim",
    "content": "// A test script to check that some retained individuals are output in the TS\n// uses a modified version of the standard continuous space recipe, so that\n// we can check on the x,y position of individuals.\n\ninitialize() {\n\tinitializeSLiMOptions(keepPedigrees=T, dimensionality=\"xy\");\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq(retainCoalescentOnly=F);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n}\n1 early() {\n\tsim.addSubpop(\"p1\", 500);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);  \n}\n\n1 late() {\n\t// initial positions are random in ([0,1], [0,1])\n\t//sim.treeSeqRememberIndividuals(p1.individuals[1:2], permanent=T);\n\tp1.individuals.x = runif(p1.individualCount);\n\tp1.individuals.y = runif(p1.individualCount);\n}\nmodifyChild() {\n\t// draw a child position near the first parent, within bounds\n\tdo child.x = parent1.x + rnorm(1, 0, 0.02);\n\twhile ((child.x < 0.0) | (child.x > 1.0));\n\t\n\tdo child.y = parent1.y + rnorm(1, 0, 0.02);\n\twhile ((child.y < 0.0) | (child.y > 1.0));\n\t\n\treturn T;\n}\n\n50 late() {\n\t// retain but do not permanently remember all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain_even_if_unary\");\n}\n\n100 late() {\n\t// also retain all the individuals in this generation\n\tsim.treeSeqRememberIndividuals(p1.individuals, permanent=F);\n\taddIndividuals(p1.individuals, \"retain_even_if_unary\");\n\t// but also remember a few of them\n\tsim.treeSeqRememberIndividuals(p1.individuals[1:5]);\n\taddIndividuals(p1.individuals[1:5], \"remember\");\n}\n\n200 late() {\n\toutputIndividuals();\n\toutputMutationResult();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____sexual_WF.slim",
    "content": "initialize() {\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tsource(\"init_marked_mutations.slim\");\n    initializeTreeSeq();\n\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 9);\n\tinitializeMutationRate(0.0);\n\tinitializeRecombinationRate(0.2);\t\n}\n\n1 late() {\n\tsim.addSubpop(\"p1\",10);\n\t// TREE SEQUENCE TEST OUTPUT\n\tinitializeMarks(n_marks);\n}\n\n2 early() {\n\taddAncestralSamples(5);\n}\n\n10 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n   saveTreeSeq();\n\n\tsim.simulationFinished();\n}\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____sexual_nonwf.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tinitializeSex('A');\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction(NULL,\"F\") {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}   \n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\tsim.simulationFinished();\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____simple_none.slim",
    "content": "initialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0.0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(0.0);\n   setSeed(123);\n   setwd(RUN_DIR);\n}\n1 early() {\tsim.addSubpop(\"p1\", 4); }\n4 late() {\n   createDirectory(\"end\");\n   sim.treeSeqOutput(\"end/test_output.trees\");\n   sim.treeSeqOutput(\"end/test_output.unsimplified.trees\", simplify=F);\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____simple_nonwf.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n\tinitializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction() {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}\n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\n\tsim.simulationFinished();\n}\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____simple_not_perm.slim",
    "content": "initialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0.0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(0.0);\n   setSeed(123);\n   setwd(RUN_DIR);\n}\n1 early() {\tsim.addSubpop(\"p1\", 4); }\n2 late() { sim.treeSeqRememberIndividuals(p1.individuals, permanent=F); }\n4 late() {\n   createDirectory(\"end\");\n   sim.treeSeqOutput(\"end/test_output.trees\");\n   sim.treeSeqOutput(\"end/test_output.unsimplified.trees\", simplify=F);\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____simple_perm.slim",
    "content": "initialize() {\n\tinitializeTreeSeq();\n\tinitializeMutationRate(0.0);\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tinitializeGenomicElementType(\"g1\", m1, 1.0);\n\tinitializeGenomicElement(g1, 0, 99999);\n\tinitializeRecombinationRate(0.0);\n   setSeed(123);\n   setwd(RUN_DIR);\n}\n1 early() {\tsim.addSubpop(\"p1\", 4); }\n2 late() { sim.treeSeqRememberIndividuals(p1.individuals, permanent=T); }\n4 late() {\n   createDirectory(\"end\");\n   sim.treeSeqOutput(\"end/test_output.trees\");\n   sim.treeSeqOutput(\"end/test_output.unsimplified.trees\", simplify=F);\n}\n\n"
  },
  {
    "path": "treerec/tests/test_recipes/test_____withdraw_indivs.slim",
    "content": "initialize() {\n\n\tinitializeSLiMModelType(\"nonWF\");\n\tinitializeSLiMOptions(keepPedigrees=T); // necessary for pedigreeID\n\tinitializeSex('A');\n\n\t// TREE SEQUENCE TEST OUTPUT\n\tsource(\"init.slim\");\n    initializeTreeSeq();\n\n\tdefineConstant(\"K\",30);  \n\n\tinitializeMutationType(\"m1\", 0.5, \"f\", 0.0);\n\tm1.mutationStackPolicy = \"l\";\n\tinitializeMutationType(\"m2\", 0.5, \"f\", 0.0);\n\tm2.mutationStackPolicy = \"s\";\n\tinitializeMutationType(\"m3\", 0.5, \"f\", 0.0);\n\tm3.mutationStackPolicy = \"f\";\n\n\tinitializeGenomicElementType(\"g1\",c(m1,m2,m3),c(1.0,1.0,1.0));\n\tinitializeGenomicElement(g1, 0, 99);\n\tinitializeMutationRate(0.1);\n\tinitializeRecombinationRate(0.1);\n}\n\nreproduction(NULL,\"F\") {\n\tsubpop.addCrossed(individual,subpop.sampleIndividuals(1, sex=\"M\"));\n}\n1 early() {\n\tsim.addSubpop(\"p1\",10);\n\taddAncestralSamples(5);\n}   \n\n100 early() {\n\taddAncestralSamples(5);\n}\n\nearly() {\n\tp1.fitnessScaling = K / p1.individualCount;\n}\n\nmodifyChild() {\n\t// discard half of offspring arbitrarily\n\treturn (rbinom(1, 1, 0.5) > 0);\n}\n\n200 late() {\n\n\t// TREE SEQUENCE TEST OUTPUT\n\toutputMutationResult();\n\toutputIndividuals();\n   saveTreeSeq();\n\n\tsim.simulationFinished();\n}\n\n\n"
  },
  {
    "path": "treerec/tests/test_specific_recipes.py",
    "content": "\"\"\"\nTests that look at the result of specific recipes in test_recipes\nThese may depend on the exact random seed used to run the SLiM simulation.\nIndividual recipes can be specified by decorating with\n@pytest.mark.parametrize('recipe', ['test_____my_specific_recipe.slim'], indirect=True)\n\"\"\"\nimport msprime\nimport numpy as np\nimport pyslim\nimport pytest\n\nfrom recipe_specs import recipe_eq\n\n\nclass TestUnaryNodes:\n\n    def max_children_node(self, ts, exclude_roots=True, exclude_samples=True):\n        \"\"\"\n        Return a dict mapping nodes to their maximumn # children in the ts\n        \"\"\"\n\n        max_children = np.zeros(ts.num_nodes, dtype=int)\n        filter = np.zeros(ts.num_nodes, dtype=bool)\n        if exclude_samples:\n            filter[ts.samples()] = True\n        if exclude_roots:\n            filter[np.isin(np.arange(ts.num_nodes), ts.tables.edges.child) == False] = True\n        for tree in ts.trees():\n            for n in tree.nodes():\n                if not ts.node(n).is_sample():\n                    max_children[n] = max(max_children[n], tree.num_children(n))\n        arr = {n:mc for n, (mc, rm) in enumerate(zip(max_children, filter)) if not rm}\n        return arr\n        \n\n    @pytest.mark.parametrize('recipe', indirect=True, argvalues=[\n        \"test_____retain_individuals_nonWF_unary.slim\",\n        \"test_____retain_individuals_unary.slim\",\n    ])\n    def test_contains_unary_nonsample_nodes(self, recipe):\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        assert np.any(np.array(list(self.max_children_node(ts).values())) == 1)\n\n    @pytest.mark.parametrize('recipe', indirect=True, argvalues=[\n        'test_____remember_individuals.slim',\n    ])\n    def test_contains_unary_sample_nodes(self, recipe):\n        \"\"\"\n        Historical remembered individuals can have a node with a single descendant\n        \"\"\"\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        num_unary_nodes = 0\n        for tree in ts.trees():\n            for n in tree.nodes():\n                if tree.num_children(n) == 1 and tree.parent(n) >= 0:\n                    assert ts.node(n).individual >= 0  # has an individual\n                    ind = ts.individual(ts.node(n).individual)\n                    assert ts.node(n).is_sample()\n                    assert (ind.flags & pyslim.INDIVIDUAL_REMEMBERED) != 0\n                    num_unary_nodes += 1\n        assert num_unary_nodes > 0\n\n    @pytest.mark.parametrize('recipe', indirect=True, argvalues=[\n        \"test_____retain_and_remember_individuals.slim\",\n        \"test_____retain_individuals_nonWF.slim\",\n        \"test_____remember_individuals.slim\",\n    ])\n    def test_no_purely_unary_internal_nonsample_nodes(self, recipe):\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        max_children_per_node = self.max_children_node(ts)\n        assert np.all(np.array(list(max_children_per_node.values())) != 1)\n\n\nclass TestIndividualsInGeneration:\n    \"\"\"\n    Test that all the nodes on the ancestry at a fixed set of generations are present\n    \"\"\"\n    def num_lineages_at_time(self, ts, focal_time, pos):\n        edges = ts.tables.edges\n        times = ts.tables.nodes.time\n        return np.sum(np.logical_and.reduce((\n            times[edges.parent] > focal_time,\n            times[edges.child] <= focal_time,\n            edges.left <= pos,\n            edges.right > pos,\n        )))\n        \n\n    @pytest.mark.parametrize('recipe, gens, final_gen', indirect=[\"recipe\"], argvalues=[\n        ('test_____retain_individuals_unary.slim', (50, 100), 200),\n    ])\n    def test_all_lineages_covered(self, recipe, gens, final_gen):\n        \"\"\"\n        If all individuals in `gen` are retained with retainCoalescentOnly=F, we should\n        have unary nodes in individuals for all tree sequence lineages\n        \"\"\"\n        gens = final_gen - np.array(gens)  # convert to ts times\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        # Check all initial generation nodes are roots\n        nodes_at_start = np.where(ts.tables.nodes.time == final_gen)[0]\n        nodes_at_gen = {g: np.where(ts.tables.nodes.time == g)[0] for g in gens}\n        for nodes in nodes_at_gen.values():\n            # All nodes in the target generations should have an individual\n            assert np.all(ts.tables.nodes.individual[nodes] >= 0)\n        for tree in ts.trees():\n            assert np.all(np.isin(tree.roots, nodes_at_start))\n            for gen, nodes in nodes_at_gen.items():\n                treenodes_at_gen = set(tree.nodes()) & set(nodes)\n                assert len(treenodes_at_gen) == self.num_lineages_at_time(\n                    ts, gen, tree.interval.left)\n\n    @pytest.mark.parametrize('recipe, gens, final_gen', indirect=[\"recipe\"], argvalues=[\n        ('test_____retain_and_remember_individuals.slim', (50, 100), 200),\n    ])\n    def test_not_all_lineages_covered(self, recipe, gens, final_gen):\n        \"\"\"\n        If all individuals in `gen` are retained with retainCoalescentOnly=T, we should\n        simplify out those with only unary nodes, and not all lineages will have a node\n        \"\"\"\n        gens = final_gen - np.array(gens)  # convert to ts times\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        # Check all initial generation nodes are roots\n        nodes_at_start = np.where(ts.tables.nodes.time == final_gen)[0]\n        nodes_at_gen = {g: np.where(ts.tables.nodes.time == g)[0] for g in gens}\n        for nodes in nodes_at_gen.values():\n            # All nodes in the target generations should have an individual\n            assert np.all(ts.tables.nodes.individual[nodes] >= 0)\n        for tree in ts.trees():\n            assert np.all(np.isin(tree.roots, nodes_at_start))\n            for gen, nodes in nodes_at_gen.items():\n                treenodes_at_gen = set(tree.nodes()) & set(nodes)\n                assert len(treenodes_at_gen) < self.num_lineages_at_time(\n                    ts, gen, tree.interval.left)\n\n\nclass TestPopNames:\n    \"\"\"\n    Test that population names are correctly retained\n    \"\"\"\n\n    @pytest.mark.parametrize('recipe', indirect=True, argvalues=[\n        'test_____pop_names_pX.slim',\n    ])\n    def test_still_has_name_default(self, recipe):\n        \"\"\"\n        Even if p1 is gone by the time we write out the tree sequence,\n        it should still have a name in the population table.\n        \"\"\"\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        pop_names = [p.metadata['name'] if p.metadata is not None else None for p in ts.populations()]\n        assert pop_names[1] == \"p1\"\n        assert pop_names[3] == \"p3\"\n\n    @pytest.mark.parametrize('recipe', indirect=True, argvalues=[\n        'test_____pop_names_nondefault.slim',\n    ])\n    def test_still_has_name_assigned(self, recipe):\n        \"\"\"\n        Even if p1 is gone by the time we write out the tree sequence,\n        it should still have a name in the population table.\n        \"\"\"\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        pop_names = [p.metadata['name'] if p.metadata is not None else None for p in ts.populations()]\n        assert pop_names[1] == \"the_p1\"\n        assert pop_names[3] == \"the_p3\"\n\n\nclass TestSimple:\n    # Some very very simple tests that are designed to be easier to track down\n    # than the exhaustive make-sure-everything-matches tests.\n\n    @pytest.mark.parametrize('recipe', [\"test_____simple_none.slim\"], indirect=True)\n    def test_simple_not_remembered(self, recipe):\n        # this is a recipe that has 4 individuals, runs for 4 ticks.\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        assert np.max(ts.nodes_time) == 4.0\n        assert len(ts.samples(time=0.0)) == 8\n        for t in np.arange(1, 6):\n            assert len(ts.samples(time=t)) == 0\n\n    @pytest.mark.parametrize('recipe', [\"test_____simple_not_perm.slim\"], indirect=True)\n    def test_simple_remembered_not_perm(self, recipe):\n        # this is a recipe that has 4 individuals, runs for 4 ticks,\n        # and remembers individuals not-permanently at tick 2\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        assert np.max(ts.nodes_time) == 4.0\n        assert len(ts.samples(time=0.0)) == 8\n        for t in np.arange(1, 6):\n            assert len(ts.samples(time=t)) == 0\n\n    @pytest.mark.parametrize('recipe', [\"test_____simple_perm.slim\"], indirect=True)\n    def test_simple_remembered_perm(self, recipe):\n        # this is a recipe that has 4 individuals, runs for 4 ticks,\n        # and remembers individuals permanently at tick 2\n        assert len(recipe[\"results\"]) == 1\n        ts = recipe[\"results\"][0].get_normal_ts()\n        assert np.max(ts.nodes_time) == 4.0\n        assert len(ts.samples(time=0.0)) == 8\n        for t in np.arange(1, 6):\n            assert len(ts.samples(time=t)) == (0 if t != 2.0 else 8)\n\n"
  },
  {
    "path": "treerec/tskit/convert.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2018-2025 Tskit Developers\n * Copyright (c) 2015-2017 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <tskit/convert.h>\n\n/* ======================================================== *\n * Newick output.\n * ======================================================== */\n\n/* This infrastructure is left-over from an earlier more complex version\n * of this algorithm that worked over a tree sequence and cached the newick\n * subtrees, updating according to diffs. It's unclear whether this complexity\n * was of any real-world use, since newick output for large trees is pretty\n * pointless. */\n\ntypedef struct {\n    unsigned int precision;\n    tsk_flags_t options;\n    char *newick;\n    tsk_id_t *traversal_stack;\n    const tsk_tree_t *tree;\n} tsk_newick_converter_t;\n\nstatic int\ntsk_newick_converter_run(\n    tsk_newick_converter_t *self, tsk_id_t root, size_t buffer_size, char *buffer)\n{\n    int ret = TSK_ERR_GENERIC;\n    const tsk_tree_t *tree = self->tree;\n    tsk_id_t *stack = self->traversal_stack;\n    const double *time = self->tree->tree_sequence->tables->nodes.time;\n    const tsk_flags_t *flags = self->tree->tree_sequence->tables->nodes.flags;\n    int stack_top = 0;\n    int label;\n    size_t s = 0;\n    int r;\n    tsk_id_t u, v, w, root_parent;\n    double branch_length;\n    bool ms_labels = self->options & TSK_NEWICK_LEGACY_MS_LABELS;\n    const char *label_format = ms_labels ? \"%d\" : \"n%d\";\n\n    if (root < 0 || root >= (tsk_id_t) self->tree->num_nodes) {\n        ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    if (buffer == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    root_parent = tree->parent[root];\n    stack[0] = root;\n    u = root_parent;\n    while (stack_top >= 0) {\n        v = stack[stack_top];\n        if (tree->left_child[v] != TSK_NULL && v != u) {\n            if (s >= buffer_size) {\n                ret = tsk_trace_error(TSK_ERR_BUFFER_OVERFLOW);\n                goto out;\n            }\n            buffer[s] = '(';\n            s++;\n            for (w = tree->right_child[v]; w != TSK_NULL; w = tree->left_sib[w]) {\n                stack_top++;\n                stack[stack_top] = w;\n            }\n        } else {\n            u = tree->parent[v];\n            stack_top--;\n            label = -1;\n            if (ms_labels) {\n                if (tree->left_child[v] == TSK_NULL) {\n                    label = (int) v + 1;\n                }\n            } else if (flags[v] & TSK_NODE_IS_SAMPLE) {\n                label = (int) v;\n            }\n            if (label != -1) {\n                if (s >= buffer_size) {\n                    ret = tsk_trace_error(TSK_ERR_BUFFER_OVERFLOW);\n                    goto out;\n                }\n                r = snprintf(buffer + s, buffer_size - s, label_format, label);\n                if (r < 0) {\n                    ret = tsk_trace_error(TSK_ERR_IO);\n                    goto out;\n                }\n                s += (size_t) r;\n                if (s >= buffer_size) {\n                    ret = tsk_trace_error(TSK_ERR_BUFFER_OVERFLOW);\n                    goto out;\n                }\n            }\n            if (u != root_parent) {\n                branch_length = (time[u] - time[v]);\n                r = snprintf(buffer + s, buffer_size - s, \":%.*f\", (int) self->precision,\n                    branch_length);\n                if (r < 0) {\n                    ret = tsk_trace_error(TSK_ERR_IO);\n                    goto out;\n                }\n                s += (size_t) r;\n                if (s >= buffer_size) {\n                    ret = tsk_trace_error(TSK_ERR_BUFFER_OVERFLOW);\n                    goto out;\n                }\n                if (v == tree->right_child[u]) {\n                    buffer[s] = ')';\n                } else {\n                    buffer[s] = ',';\n                }\n                s++;\n            }\n        }\n    }\n    if ((s + 1) >= buffer_size) {\n        ret = tsk_trace_error(TSK_ERR_BUFFER_OVERFLOW);\n        goto out;\n    }\n    buffer[s] = ';';\n    buffer[s + 1] = '\\0';\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ntsk_newick_converter_init(tsk_newick_converter_t *self, const tsk_tree_t *tree,\n    unsigned int precision, tsk_flags_t options)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_newick_converter_t));\n    self->precision = precision;\n    self->options = options;\n    self->tree = tree;\n    self->traversal_stack\n        = tsk_malloc(tsk_tree_get_size_bound(tree) * sizeof(*self->traversal_stack));\n    if (self->traversal_stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_newick_converter_free(tsk_newick_converter_t *self)\n{\n    tsk_safe_free(self->traversal_stack);\n    return 0;\n}\n\nint\ntsk_convert_newick(const tsk_tree_t *tree, tsk_id_t root, unsigned int precision,\n    tsk_flags_t options, size_t buffer_size, char *buffer)\n{\n    int ret = 0;\n    tsk_newick_converter_t nc;\n\n    ret = tsk_newick_converter_init(&nc, tree, precision, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_newick_converter_run(&nc, root, buffer_size, buffer);\nout:\n    tsk_newick_converter_free(&nc);\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/convert.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2018-2021 Tskit Developers\n * Copyright (c) 2015-2017 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef TSK_CONVERT_H\n#define TSK_CONVERT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <tskit/trees.h>\n\n#define TSK_NEWICK_LEGACY_MS_LABELS (1 << 0)\n\nint tsk_convert_newick(const tsk_tree_t *tree, tsk_id_t root, unsigned int precision,\n    tsk_flags_t options, size_t buffer_size, char *buffer);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/core.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n * Copyright (c) 2015-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n#include <math.h>\n\n#include <kastore.h>\n#include <tskit/core.h>\n\n#define UUID_NUM_BYTES 16\n\n#if defined(_WIN32)\n\n#include <windows.h>\n#include <wincrypt.h>\n\nstatic int TSK_WARN_UNUSED\nget_random_bytes(uint8_t *buf)\n{\n    /* Based on CPython's code in bootstrap_hash.c */\n    int ret = 0;\n    HCRYPTPROV hCryptProv = (HCRYPTPROV) NULL;\n\n    if (!CryptAcquireContext(\n            &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\n    if (!CryptGenRandom(hCryptProv, (DWORD) UUID_NUM_BYTES, buf)) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\n    if (!CryptReleaseContext(hCryptProv, 0)) {\n        hCryptProv = (HCRYPTPROV) NULL;\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\n    hCryptProv = (HCRYPTPROV) NULL;\nout:\n    if (hCryptProv != (HCRYPTPROV) NULL) {\n        CryptReleaseContext(hCryptProv, 0);\n    }\n    return ret;\n}\n\n#else\n\n/* Assuming the existance of /dev/urandom on Unix platforms */\nstatic int TSK_WARN_UNUSED\nget_random_bytes(uint8_t *buf)\n{\n    int ret = 0;\n    FILE *f = fopen(\"/dev/urandom\", \"r\");\n\n    if (f == NULL) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\n    if (fread(buf, UUID_NUM_BYTES, 1, f) != 1) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\n    if (fclose(f) != 0) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\nout:\n    return ret;\n}\n\n#endif\n\n/* Generate a new UUID4 using a system-generated source of randomness.\n * Note that this function writes a NULL terminator to the end of this\n * string, so that the total length of the buffer must be 37 bytes.\n */\nint\ntsk_generate_uuid(char *dest, int TSK_UNUSED(flags))\n{\n    int ret = 0;\n    uint8_t buf[UUID_NUM_BYTES];\n    const char *pattern\n        = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n\n    ret = get_random_bytes(buf);\n    if (ret != 0) {\n        goto out;\n    }\n    if (snprintf(dest, TSK_UUID_SIZE + 1, pattern, buf[0], buf[1], buf[2], buf[3],\n            buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],\n            buf[13], buf[14], buf[15])\n        < 0) {\n        ret = tsk_trace_error(TSK_ERR_GENERATE_UUID);\n        goto out;\n    }\nout:\n    return ret;\n}\nstatic const char *\ntsk_strerror_internal(int err)\n{\n    const char *ret = \"Unknown error\";\n\n    switch (err) {\n        case 0:\n            ret = \"Normal exit condition. This is not an error!\";\n            break;\n\n        /* General errors */\n        case TSK_ERR_GENERIC:\n            ret = \"Generic error; please file a bug report. (TSK_ERR_GENERIC)\";\n            break;\n        case TSK_ERR_NO_MEMORY:\n            ret = \"Out of memory. (TSK_ERR_NO_MEMORY)\";\n            break;\n        case TSK_ERR_IO:\n            if (errno != 0) {\n                ret = strerror(errno);\n            } else {\n                ret = \"Unspecified IO error\";\n            }\n            break;\n        case TSK_ERR_BAD_PARAM_VALUE:\n            ret = \"Bad parameter value provided. (TSK_ERR_BAD_PARAM_VALUE)\";\n            break;\n        case TSK_ERR_BUFFER_OVERFLOW:\n            ret = \"Supplied buffer is too small. (TSK_ERR_BUFFER_OVERFLOW)\";\n            break;\n        case TSK_ERR_UNSUPPORTED_OPERATION:\n            ret = \"Operation cannot be performed in current configuration. \"\n                  \"(TSK_ERR_UNSUPPORTED_OPERATION)\";\n            break;\n        case TSK_ERR_GENERATE_UUID:\n            ret = \"Error generating UUID. (TSK_ERR_GENERATE_UUID)\";\n            break;\n        case TSK_ERR_EOF:\n            ret = \"End of file. (TSK_ERR_EOF)\";\n            break;\n\n        /* File format errors */\n        case TSK_ERR_FILE_FORMAT:\n            ret = \"File format error. (TSK_ERR_FILE_FORMAT)\";\n            break;\n        case TSK_ERR_FILE_VERSION_TOO_OLD:\n            ret = \"tskit file version too old. Please upgrade using the \"\n                  \"'tskit upgrade' command from tskit version<0.6.2. \"\n                  \"(TSK_ERR_FILE_VERSION_TOO_OLD)\";\n            break;\n        case TSK_ERR_FILE_VERSION_TOO_NEW:\n            ret = \"tskit file version is too new for this instance. \"\n                  \"Please upgrade tskit to the latest version. \"\n                  \"(TSK_ERR_FILE_VERSION_TOO_NEW)\";\n            break;\n        case TSK_ERR_REQUIRED_COL_NOT_FOUND:\n            ret = \"A required column was not found in the file. \"\n                  \"(TSK_ERR_REQUIRED_COL_NOT_FOUND)\";\n            break;\n        case TSK_ERR_BOTH_COLUMNS_REQUIRED:\n            ret = \"Both columns in a related pair must be provided. \"\n                  \"(TSK_ERR_BOTH_COLUMNS_REQUIRED)\";\n            break;\n        case TSK_ERR_BAD_COLUMN_TYPE:\n            ret = \"An incompatible type for a column was found in the file. \"\n                  \"(TSK_ERR_BAD_COLUMN_TYPE)\";\n            break;\n\n        /* Out of bounds errors */\n        case TSK_ERR_BAD_OFFSET:\n            ret = \"Bad offset provided in input array. (TSK_ERR_BAD_OFFSET)\";\n            break;\n        case TSK_ERR_NODE_OUT_OF_BOUNDS:\n            ret = \"Node out of bounds. (TSK_ERR_NODE_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_EDGE_OUT_OF_BOUNDS:\n            ret = \"Edge out of bounds. (TSK_ERR_EDGE_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_POPULATION_OUT_OF_BOUNDS:\n            ret = \"Population out of bounds. (TSK_ERR_POPULATION_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_SITE_OUT_OF_BOUNDS:\n            ret = \"Site out of bounds. (TSK_ERR_SITE_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_MUTATION_OUT_OF_BOUNDS:\n            ret = \"Mutation out of bounds. (TSK_ERR_MUTATION_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_MIGRATION_OUT_OF_BOUNDS:\n            ret = \"Migration out of bounds. (TSK_ERR_MIGRATION_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS:\n            ret = \"Individual out of bounds. (TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_PROVENANCE_OUT_OF_BOUNDS:\n            ret = \"Provenance out of bounds. (TSK_ERR_PROVENANCE_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_TIME_NONFINITE:\n            ret = \"Times must be finite. (TSK_ERR_TIME_NONFINITE)\";\n            break;\n        case TSK_ERR_GENOME_COORDS_NONFINITE:\n            ret = \"Genome coordinates must be finite numbers. \"\n                  \"(TSK_ERR_GENOME_COORDS_NONFINITE)\";\n            break;\n        case TSK_ERR_SEEK_OUT_OF_BOUNDS:\n            ret = \"Tree seek position out of bounds. (TSK_ERR_SEEK_OUT_OF_BOUNDS)\";\n            break;\n        case TSK_ERR_KEEP_ROWS_MAP_TO_DELETED:\n            ret = \"One of the kept rows in the table refers to a deleted row. \"\n                  \"(TSK_ERR_KEEP_ROWS_MAP_TO_DELETED)\";\n            break;\n        case TSK_ERR_POSITION_OUT_OF_BOUNDS:\n            ret = \"Position out of bounds. (TSK_ERR_POSITION_OUT_OF_BOUNDS)\";\n            break;\n\n        /* Edge errors */\n        case TSK_ERR_NULL_PARENT:\n            ret = \"Edge parent is null. (TSK_ERR_NULL_PARENT)\";\n            break;\n        case TSK_ERR_NULL_CHILD:\n            ret = \"Edge child is null. (TSK_ERR_NULL_CHILD)\";\n            break;\n        case TSK_ERR_EDGES_NOT_SORTED_PARENT_TIME:\n            ret = \"Edges must be listed in (time[parent], child, left) order;\"\n                  \" time[parent] order violated. (TSK_ERR_EDGES_NOT_SORTED_PARENT_TIME)\";\n            break;\n        case TSK_ERR_EDGES_NONCONTIGUOUS_PARENTS:\n            ret = \"All edges for a given parent must be contiguous. \"\n                  \"(TSK_ERR_EDGES_NONCONTIGUOUS_PARENTS)\";\n            break;\n        case TSK_ERR_EDGES_NOT_SORTED_CHILD:\n            ret = \"Edges must be listed in (time[parent], child, left) order;\"\n                  \" child order violated. (TSK_ERR_EDGES_NOT_SORTED_CHILD)\";\n            break;\n        case TSK_ERR_EDGES_NOT_SORTED_LEFT:\n            ret = \"Edges must be listed in (time[parent], child, left) order;\"\n                  \" left order violated. (TSK_ERR_EDGES_NOT_SORTED_LEFT)\";\n            break;\n        case TSK_ERR_BAD_NODE_TIME_ORDERING:\n            ret = \"time[parent] must be greater than time[child]. \"\n                  \"(TSK_ERR_BAD_NODE_TIME_ORDERING)\";\n            break;\n        case TSK_ERR_BAD_EDGE_INTERVAL:\n            ret = \"Bad edge interval where right <= left. (TSK_ERR_BAD_EDGE_INTERVAL)\";\n            break;\n        case TSK_ERR_DUPLICATE_EDGES:\n            ret = \"Duplicate edges provided. (TSK_ERR_DUPLICATE_EDGES)\";\n            break;\n        case TSK_ERR_RIGHT_GREATER_SEQ_LENGTH:\n            ret = \"Right coordinate > sequence length. \"\n                  \"(TSK_ERR_RIGHT_GREATER_SEQ_LENGTH)\";\n            break;\n        case TSK_ERR_LEFT_LESS_ZERO:\n            ret = \"Left coordinate must be >= 0. (TSK_ERR_LEFT_LESS_ZERO)\";\n            break;\n        case TSK_ERR_BAD_EDGES_CONTRADICTORY_CHILDREN:\n            ret = \"Bad edges: contradictory children for a given parent over \"\n                  \"an interval, or indexes need to be rebuilt. \"\n                  \"(TSK_ERR_BAD_EDGES_CONTRADICTORY_CHILDREN)\";\n            break;\n        case TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA:\n            ret = \"Can't squash, flush, simplify or link ancestors with edges that have \"\n                  \"non-empty metadata. Removing the metadata from the edges will allow \"\n                  \"these operations to proceed. For example using \"\n                  \"tables.edges.drop_metadata() in the tskit Python API. \"\n                  \"(TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA)\";\n            break;\n\n        /* Site errors */\n        case TSK_ERR_UNSORTED_SITES:\n            ret = \"Sites must be provided in strictly increasing position order. \"\n                  \"(TSK_ERR_UNSORTED_SITES)\";\n            break;\n        case TSK_ERR_DUPLICATE_SITE_POSITION:\n            ret = \"Duplicate site positions. (TSK_ERR_DUPLICATE_SITE_POSITION)\";\n            break;\n        case TSK_ERR_BAD_SITE_POSITION:\n            ret = \"Site positions must be between 0 and sequence_length. \"\n                  \"(TSK_ERR_BAD_SITE_POSITION)\";\n            break;\n\n        /* Mutation errors */\n        case TSK_ERR_MUTATION_PARENT_DIFFERENT_SITE:\n            ret = \"Specified parent mutation is at a different site. \"\n                  \"(TSK_ERR_MUTATION_PARENT_DIFFERENT_SITE)\";\n            break;\n        case TSK_ERR_MUTATION_PARENT_EQUAL:\n            ret = \"Parent mutation refers to itself. (TSK_ERR_MUTATION_PARENT_EQUAL)\";\n            break;\n        case TSK_ERR_MUTATION_PARENT_AFTER_CHILD:\n            ret = \"Parent mutation ID must be < current ID. \"\n                  \"(TSK_ERR_MUTATION_PARENT_AFTER_CHILD)\";\n            break;\n        case TSK_ERR_MUTATION_PARENT_INCONSISTENT:\n            ret = \"Mutation parent references form a loop. \"\n                  \"(TSK_ERR_MUTATION_PARENT_INCONSISTENT)\";\n            break;\n        case TSK_ERR_UNSORTED_MUTATIONS:\n            ret = \"Mutations must be provided in non-decreasing site order and \"\n                  \"non-increasing time order within each site. \"\n                  \"(TSK_ERR_UNSORTED_MUTATIONS)\";\n            break;\n        case TSK_ERR_MUTATION_TIME_YOUNGER_THAN_NODE:\n            ret = \"A mutation's time must be >= the node time, or be marked as \"\n                  \"'unknown'. (TSK_ERR_MUTATION_TIME_YOUNGER_THAN_NODE)\";\n            break;\n        case TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_MUTATION:\n            ret = \"A mutation's time must be <= the parent mutation time (if known), or \"\n                  \"be marked as 'unknown'. \"\n                  \"(TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_MUTATION)\";\n            break;\n        case TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_NODE:\n            ret = \"A mutation's time must be < the parent node of the edge on which it \"\n                  \"occurs, or be marked as 'unknown'. \"\n                  \"(TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_NODE)\";\n            break;\n        case TSK_ERR_MUTATION_TIME_HAS_BOTH_KNOWN_AND_UNKNOWN:\n            ret = \"Mutation times must either be all marked 'unknown', or all be known \"\n                  \"values for any single site. \"\n                  \"(TSK_ERR_MUTATION_TIME_HAS_BOTH_KNOWN_AND_UNKNOWN)\";\n            break;\n        case TSK_ERR_DISALLOWED_UNKNOWN_MUTATION_TIME:\n            ret = \"Some mutation times are marked 'unknown' for a method that requires \"\n                  \"no unknown times. (Use compute_mutation_times to add times?) \"\n                  \"(TSK_ERR_DISALLOWED_UNKNOWN_MUTATION_TIME)\";\n            break;\n\n        case TSK_ERR_BAD_MUTATION_PARENT:\n            ret = \"A mutation's parent is not consistent with the topology of the tree. \"\n                  \"Use compute_mutation_parents to set the parents correctly.\"\n                  \"(TSK_ERR_BAD_MUTATION_PARENT)\";\n            break;\n\n        /* Migration errors */\n        case TSK_ERR_UNSORTED_MIGRATIONS:\n            ret = \"Migrations must be sorted by time. (TSK_ERR_UNSORTED_MIGRATIONS)\";\n            break;\n\n        /* Sample errors */\n        case TSK_ERR_DUPLICATE_SAMPLE:\n            ret = \"Duplicate sample value. (TSK_ERR_DUPLICATE_SAMPLE)\";\n            break;\n        case TSK_ERR_BAD_SAMPLES:\n            ret = \"The nodes provided are not samples. (TSK_ERR_BAD_SAMPLES)\";\n            break;\n\n        /* Table errors */\n        case TSK_ERR_BAD_TABLE_POSITION:\n            ret = \"Bad table position provided to truncate/reset. \"\n                  \"(TSK_ERR_BAD_TABLE_POSITION)\";\n            break;\n        case TSK_ERR_BAD_SEQUENCE_LENGTH:\n            ret = \"Sequence length must be > 0. (TSK_ERR_BAD_SEQUENCE_LENGTH)\";\n            break;\n        case TSK_ERR_TABLES_NOT_INDEXED:\n            ret = \"Table collection must be indexed. (TSK_ERR_TABLES_NOT_INDEXED)\";\n            break;\n        case TSK_ERR_TABLES_BAD_INDEXES:\n            ret = \"Table collection indexes inconsistent: do they need to be rebuilt? \"\n                  \"(TSK_ERR_TABLES_BAD_INDEXES)\";\n            break;\n        case TSK_ERR_TABLE_OVERFLOW:\n            ret = \"Table too large; cannot allocate more than 2**31 rows. This error \"\n                  \"is often caused by a lack of simplification when simulating. \"\n                  \"(TSK_ERR_TABLE_OVERFLOW)\";\n            break;\n        case TSK_ERR_COLUMN_OVERFLOW:\n            ret = \"Table column too large; cannot be more than 2**64 bytes. \"\n                  \"(TSK_ERR_COLUMN_OVERFLOW)\";\n            break;\n        case TSK_ERR_TREE_OVERFLOW:\n            ret = \"Too many trees; cannot be more than 2**31. (TSK_ERR_TREE_OVERFLOW)\";\n            break;\n        case TSK_ERR_METADATA_DISABLED:\n            ret = \"Metadata is disabled for this table, so cannot be set. \"\n                  \"(TSK_ERR_METADATA_DISABLED)\";\n            break;\n\n        /* Limitations */\n        case TSK_ERR_ONLY_INFINITE_SITES:\n            ret = \"Only infinite sites mutations are supported for this operation, \"\n                  \"i.e. at most a single mutation per site. \"\n                  \"(TSK_ERR_ONLY_INFINITE_SITES)\";\n            break;\n        case TSK_ERR_SIMPLIFY_MIGRATIONS_NOT_SUPPORTED:\n            ret = \"Migrations not currently supported by simplify. \"\n                  \"(TSK_ERR_SIMPLIFY_MIGRATIONS_NOT_SUPPORTED)\";\n            break;\n        case TSK_ERR_SORT_MIGRATIONS_NOT_SUPPORTED:\n            ret = \"Migrations not currently supported by sort. \"\n                  \"(TSK_ERR_SORT_MIGRATIONS_NOT_SUPPORTED)\";\n            break;\n        case TSK_ERR_SORT_OFFSET_NOT_SUPPORTED:\n            ret = \"Sort offsets for sites and mutations must be either 0 \"\n                  \"or the length of the respective tables. Intermediate values \"\n                  \"are not supported. (TSK_ERR_SORT_OFFSET_NOT_SUPPORTED)\";\n            break;\n        case TSK_ERR_NONBINARY_MUTATIONS_UNSUPPORTED:\n            ret = \"Only binary mutations are supported for this operation. \"\n                  \"(TSK_ERR_NONBINARY_MUTATIONS_UNSUPPORTED)\";\n            break;\n        case TSK_ERR_MIGRATIONS_NOT_SUPPORTED:\n            ret = \"Migrations not currently supported by this operation. \"\n                  \"(TSK_ERR_MIGRATIONS_NOT_SUPPORTED)\";\n            break;\n        case TSK_ERR_CANNOT_EXTEND_FROM_SELF:\n            ret = \"Tables can only be extended using rows from a different table. \"\n                  \"(TSK_ERR_CANNOT_EXTEND_FROM_SELF)\";\n            break;\n        case TSK_ERR_SILENT_MUTATIONS_NOT_SUPPORTED:\n            ret = \"Silent mutations not supported by this operation. \"\n                  \"(TSK_ERR_SILENT_MUTATIONS_NOT_SUPPORTED)\";\n            break;\n        case TSK_ERR_VARIANT_CANT_DECODE_COPY:\n            ret = \"Can't decode a copy of a variant. (TSK_ERR_VARIANT_CANT_DECODE_COPY)\";\n            break;\n        case TSK_ERR_CANT_TAKE_OWNERSHIP_NO_EDGE_METADATA:\n            ret = \"A tree sequence can't take ownership of tables with \"\n                  \"TSK_NO_EDGE_METADATA. (TSK_ERR_CANT_TAKE_OWNERSHIP_NO_EDGE_METADATA)\";\n            break;\n        case TSK_ERR_UNDEFINED_NONBINARY:\n            ret = \"Operation undefined for nonbinary trees. \"\n                  \"(TSK_ERR_UNDEFINED_NONBINARY)\";\n            break;\n        case TSK_ERR_UNDEFINED_MULTIROOT:\n            ret = \"Operation undefined for trees that are not singly-rooted. \"\n                  \"(TSK_ERR_UNDEFINED_MULTIROOT)\";\n            break;\n\n        /* Stats errors */\n        case TSK_ERR_BAD_NUM_WINDOWS:\n            ret = \"Must have at least one window, [0, L]. (TSK_ERR_BAD_NUM_WINDOWS)\";\n            break;\n        case TSK_ERR_BAD_WINDOWS:\n            ret = \"Windows must be increasing list [0, ..., L]. (TSK_ERR_BAD_WINDOWS)\";\n            break;\n        case TSK_ERR_MULTIPLE_STAT_MODES:\n            ret = \"Cannot specify more than one stats mode. \"\n                  \"(TSK_ERR_MULTIPLE_STAT_MODES)\";\n            break;\n        case TSK_ERR_BAD_STATE_DIMS:\n            ret = \"Must have state dimension >= 1. (TSK_ERR_BAD_STATE_DIMS)\";\n            break;\n        case TSK_ERR_BAD_RESULT_DIMS:\n            ret = \"Must have result dimension >= 1. (TSK_ERR_BAD_RESULT_DIMS)\";\n            break;\n        case TSK_ERR_INSUFFICIENT_SAMPLE_SETS:\n            ret = \"Insufficient sample sets provided. \"\n                  \"(TSK_ERR_INSUFFICIENT_SAMPLE_SETS)\";\n            break;\n        case TSK_ERR_INSUFFICIENT_INDEX_TUPLES:\n            ret = \"Insufficient sample set index tuples provided. \"\n                  \"(TSK_ERR_INSUFFICIENT_INDEX_TUPLES)\";\n            break;\n        case TSK_ERR_BAD_SAMPLE_SET_INDEX:\n            ret = \"Sample set index out of bounds. (TSK_ERR_BAD_SAMPLE_SET_INDEX)\";\n            break;\n        case TSK_ERR_EMPTY_SAMPLE_SET:\n            ret = \"Samples cannot be empty. (TSK_ERR_EMPTY_SAMPLE_SET)\";\n            break;\n        case TSK_ERR_UNSUPPORTED_STAT_MODE:\n            ret = \"Requested statistics mode not supported for this method. \"\n                  \"(TSK_ERR_UNSUPPORTED_STAT_MODE)\";\n            break;\n        case TSK_ERR_TIME_UNCALIBRATED:\n            ret = \"Statistics using branch lengths cannot be calculated when time_units \"\n                  \"is 'uncalibrated'. (TSK_ERR_TIME_UNCALIBRATED)\";\n            break;\n        case TSK_ERR_STAT_POLARISED_UNSUPPORTED:\n            ret = \"The TSK_STAT_POLARISED option is not supported by this statistic. \"\n                  \"(TSK_ERR_STAT_POLARISED_UNSUPPORTED)\";\n            break;\n        case TSK_ERR_STAT_SPAN_NORMALISE_UNSUPPORTED:\n            ret = \"The TSK_STAT_SPAN_NORMALISE option is not supported by this \"\n                  \"statistic. \"\n                  \"(TSK_ERR_STAT_SPAN_NORMALISE_UNSUPPORTED)\";\n            break;\n        case TSK_ERR_INSUFFICIENT_WEIGHTS:\n            ret = \"Insufficient weights provided (at least 1 required). \"\n                  \"(TSK_ERR_INSUFFICIENT_WEIGHTS)\";\n            break;\n\n        /* Pair coalescence errors */\n        case TSK_ERR_BAD_NODE_BIN_MAP:\n            ret = \"Node-to-bin map contains values less than TSK_NULL. \"\n                  \"(TSK_ERR_BAD_NODE_BIN_MAP)\";\n            break;\n        case TSK_ERR_BAD_NODE_BIN_MAP_DIM:\n            ret = \"Maximum index in node-to-bin map is greater than the \"\n                  \"output dimension. (TSK_ERR_BAD_NODE_BIN_MAP_DIM)\";\n            break;\n        case TSK_ERR_BAD_QUANTILES:\n            ret = \"Quantiles must be between 0 and 1 (inclusive) \"\n                  \"and strictly increasing. (TSK_ERR_BAD_QUANTILES)\";\n            break;\n        case TSK_ERR_UNSORTED_TIMES:\n            ret = \"Times must be strictly increasing. (TSK_ERR_UNSORTED_TIMES)\";\n            break;\n        case TSK_ERR_BAD_TIME_WINDOWS_DIM:\n            ret = \"Must have at least one time window. (TSK_ERR_BAD_TIME_WINDOWS_DIM)\";\n            break;\n        case TSK_ERR_BAD_SAMPLE_PAIR_TIMES:\n            ret = \"All sample times must be equal to the start of first time window. \"\n                  \"(TSK_ERR_BAD_SAMPLE_PAIR_TIMES)\";\n            break;\n        case TSK_ERR_BAD_TIME_WINDOWS:\n            ret = \"Time windows must start at zero and be strictly increasing. \"\n                  \"(TSK_ERR_BAD_TIME_WINDOWS)\";\n            break;\n        case TSK_ERR_BAD_TIME_WINDOWS_END:\n            ret = \"Time windows must end at infinity for this method. \"\n                  \"(TSK_ERR_BAD_TIME_WINDOWS_END)\";\n            break;\n        case TSK_ERR_BAD_NODE_TIME_WINDOW:\n            ret = \"Node time does not fall within assigned time window. \"\n                  \"(TSK_ERR_BAD_NODE_TIME_WINDOW)\";\n            break;\n\n        /* Two locus errors */\n        case TSK_ERR_STAT_UNSORTED_POSITIONS:\n            ret = \"The provided positions are not sorted in strictly increasing \"\n                  \"order. (TSK_ERR_STAT_UNSORTED_POSITIONS)\";\n            break;\n        case TSK_ERR_STAT_DUPLICATE_POSITIONS:\n            ret = \"The provided positions contain duplicates. \"\n                  \"(TSK_ERR_STAT_DUPLICATE_POSITIONS)\";\n            break;\n        case TSK_ERR_STAT_UNSORTED_SITES:\n            ret = \"The provided sites are not sorted in strictly increasing position \"\n                  \"order. (TSK_ERR_STAT_UNSORTED_SITES)\";\n            break;\n        case TSK_ERR_STAT_DUPLICATE_SITES:\n            ret = \"The provided sites contain duplicated entries. \"\n                  \"(TSK_ERR_STAT_DUPLICATE_SITES)\";\n            break;\n\n        /* Mutation mapping errors */\n        case TSK_ERR_GENOTYPES_ALL_MISSING:\n            ret = \"Must provide at least one non-missing genotype. \"\n                  \"(TSK_ERR_GENOTYPES_ALL_MISSING)\";\n            break;\n        case TSK_ERR_BAD_GENOTYPE:\n            ret = \"Bad genotype value provided. (TSK_ERR_BAD_GENOTYPE)\";\n            break;\n        case TSK_ERR_BAD_ANCESTRAL_STATE:\n            ret = \"Bad ancestral state specified. (TSK_ERR_BAD_ANCESTRAL_STATE)\";\n            break;\n\n        /* Genotype decoding errors */\n        case TSK_ERR_MUST_IMPUTE_NON_SAMPLES:\n            ret = \"Cannot generate genotypes for non-samples when isolated nodes are \"\n                  \"considered as missing. (TSK_ERR_MUST_IMPUTE_NON_SAMPLES)\";\n            break;\n        case TSK_ERR_ALLELE_NOT_FOUND:\n            ret = \"An allele was not found in the user-specified allele map. \"\n                  \"(TSK_ERR_ALLELE_NOT_FOUND)\";\n            break;\n        case TSK_ERR_TOO_MANY_ALLELES:\n            ret = \"Cannot have more than 2147483647 alleles (TSK_ERR_TOO_MANY_ALLELES)\";\n            break;\n        case TSK_ERR_ZERO_ALLELES:\n            ret = \"Must have at least one allele when specifying an allele map. \"\n                  \"(TSK_ERR_ZERO_ALLELES)\";\n            break;\n        case TSK_ERR_BAD_ALLELE_LENGTH:\n            ret = \"Alleles used when decoding alignments must have length one. \"\n                  \"(TSK_ERR_BAD_ALLELE_LENGTH)\";\n            break;\n        case TSK_ERR_MISSING_CHAR_COLLISION:\n            ret = \"Alleles used when decoding alignments must not match the missing \"\n                  \"data character. (TSK_ERR_MISSING_CHAR_COLLISION)\";\n            break;\n\n        /* Distance metric errors */\n        case TSK_ERR_SAMPLE_SIZE_MISMATCH:\n            ret = \"Cannot compare trees with different numbers of samples. \"\n                  \"(TSK_ERR_SAMPLE_SIZE_MISMATCH)\";\n            break;\n        case TSK_ERR_SAMPLES_NOT_EQUAL:\n            ret = \"Samples must be identical in trees to compare. \"\n                  \"(TSK_ERR_SAMPLES_NOT_EQUAL)\";\n            break;\n        case TSK_ERR_MULTIPLE_ROOTS:\n            ret = \"Trees with multiple roots not supported. (TSK_ERR_MULTIPLE_ROOTS)\";\n            break;\n        case TSK_ERR_UNARY_NODES:\n            ret = \"Unsimplified trees with unary nodes are not supported. \"\n                  \"(TSK_ERR_UNARY_NODES)\";\n            break;\n        case TSK_ERR_SEQUENCE_LENGTH_MISMATCH:\n            ret = \"Sequence lengths must be identical to compare. \"\n                  \"(TSK_ERR_SEQUENCE_LENGTH_MISMATCH)\";\n            break;\n        case TSK_ERR_NO_SAMPLE_LISTS:\n            ret = \"The sample_lists option must be enabled on the tree to perform this \"\n                  \"operation. Pass the option to the constructor or method that created \"\n                  \"the tree. (TSK_ERR_NO_SAMPLE_LISTS)\";\n            break;\n\n        /* Haplotype matching errors */\n        case TSK_ERR_NULL_VITERBI_MATRIX:\n            ret = \"Viterbi matrix has not filled. (TSK_ERR_NULL_VITERBI_MATRIX)\";\n            break;\n        case TSK_ERR_MATCH_IMPOSSIBLE:\n            ret = \"No matching haplotype exists with current parameters. \"\n                  \"(TSK_ERR_MATCH_IMPOSSIBLE)\";\n            break;\n        case TSK_ERR_BAD_COMPRESSED_MATRIX_NODE:\n            ret = \"The compressed matrix contains a node that subtends no samples. \"\n                  \"(TSK_ERR_BAD_COMPRESSED_MATRIX_NODE)\";\n            break;\n        case TSK_ERR_TOO_MANY_VALUES:\n            ret = \"Too many values to compress. (TSK_ERR_TOO_MANY_VALUES)\";\n            break;\n\n        /* Union errors */\n        case TSK_ERR_UNION_BAD_MAP:\n            ret = \"Node map contains an entry of a node not present in this table \"\n                  \"collection. (TSK_ERR_UNION_BAD_MAP)\";\n            break;\n        case TSK_ERR_UNION_DIFF_HISTORIES:\n            // histories could be equivalent, because subset does not reorder\n            // edges (if not sorted) or mutations.\n            ret = \"Shared portions of the tree sequences are not equal. \"\n                  \"(TSK_ERR_UNION_DIFF_HISTORIES)\";\n            break;\n\n        /* IBD errors */\n        case TSK_ERR_SAME_NODES_IN_PAIR:\n            ret = \"Both nodes in the sample pair are the same. \"\n                  \"(TSK_ERR_SAME_NODES_IN_PAIR)\";\n            break;\n\n        case TSK_ERR_IBD_PAIRS_NOT_STORED:\n            ret = \"The sample pairs are not stored by default in ibd_segments. Please \"\n                  \"add the TSK_IBD_STORE_PAIRS option flag if per-pair statistics are \"\n                  \"required. (TSK_ERR_IBD_PAIRS_NOT_STORED)\";\n            break;\n\n        case TSK_ERR_IBD_SEGMENTS_NOT_STORED:\n            ret = \"All segments are not stored by default in ibd_segments. Please \"\n                  \"add the TSK_IBD_STORE_SEGMENTS option flag if they are required. \"\n                  \"(TSK_ERR_IBD_SEGMENTS_NOT_STORED)\";\n            break;\n\n        /* Simplify errors */\n        case TSK_ERR_KEEP_UNARY_MUTUALLY_EXCLUSIVE:\n            ret = \"You cannot specify both TSK_SIMPLIFY_KEEP_UNARY and \"\n                  \"TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVDUALS. \"\n                  \"(TSK_ERR_KEEP_UNARY_MUTUALLY_EXCLUSIVE)\";\n            break;\n\n        /* Individual errors */\n        case TSK_ERR_UNSORTED_INDIVIDUALS:\n            ret = \"Individuals must be provided in an order where children are after \"\n                  \"their parent individuals (TSK_ERR_UNSORTED_INDIVIDUALS)\";\n            break;\n\n        case TSK_ERR_INDIVIDUAL_SELF_PARENT:\n            ret = \"Individuals cannot be their own parents. \"\n                  \"(TSK_ERR_INDIVIDUAL_SELF_PARENT)\";\n            break;\n\n        case TSK_ERR_INDIVIDUAL_PARENT_CYCLE:\n            ret = \"Individuals cannot be their own ancestor. \"\n                  \"(TSK_ERR_INDIVIDUAL_PARENT_CYCLE)\";\n            break;\n\n        case TSK_ERR_INDIVIDUAL_POPULATION_MISMATCH:\n            ret = \"Individual populations cannot be returned \"\n                  \"if an individual has nodes from more than one population. \"\n                  \"(TSK_ERR_INDIVIDUAL_POPULATION_MISMATCH)\";\n            break;\n\n        case TSK_ERR_INDIVIDUAL_TIME_MISMATCH:\n            ret = \"Individual times cannot be returned \"\n                  \"if an individual has nodes from more than one time. \"\n                  \"(TSK_ERR_INDIVIDUAL_TIME_MISMATCH)\";\n            break;\n\n        case TSK_ERR_EXTEND_EDGES_BAD_MAXITER:\n            ret = \"Maximum number of iterations must be positive. \"\n                  \"(TSK_ERR_EXTEND_EDGES_BAD_MAXITER)\";\n            break;\n    }\n    return ret;\n}\n\nint\ntsk_set_kas_error(int err)\n{\n    if (err == KAS_ERR_IO) {\n        /* If we've detected an IO error, report it as TSK_ERR_IO so that we have\n         * a consistent error code covering these situtations */\n        return TSK_ERR_IO;\n    } else {\n        /* Flip this bit. As the error is negative, this sets the bit to 0 */\n        return err ^ (1 << TSK_KAS_ERR_BIT);\n    }\n}\n\nbool\ntsk_is_kas_error(int err)\n{\n    return !(err & (1 << TSK_KAS_ERR_BIT));\n}\n\nint\ntsk_get_kas_error(int err)\n{\n    return err ^ (1 << TSK_KAS_ERR_BIT);\n}\n\nconst char *\ntsk_strerror(int err)\n{\n    if (err != 0 && tsk_is_kas_error(err)) {\n        return kas_strerror(tsk_get_kas_error(err));\n    } else {\n        return tsk_strerror_internal(err);\n    }\n}\n\nvoid\n__tsk_safe_free(void **ptr)\n{\n    if (ptr != NULL) {\n        if (*ptr != NULL) {\n            free(*ptr);\n            *ptr = NULL;\n        }\n    }\n}\n\n/* Block allocator. Simple allocator when we lots of chunks of memory\n * and don't need to free them individually.\n */\n\nvoid\ntsk_blkalloc_print_state(tsk_blkalloc_t *self, FILE *out)\n{\n    fprintf(out, \"Block allocator%p::\\n\", (void *) self);\n    fprintf(out, \"\\ttop = %lld\\n\", (long long) self->top);\n    fprintf(out, \"\\tchunk_size = %lld\\n\", (long long) self->chunk_size);\n    fprintf(out, \"\\tnum_chunks = %lld\\n\", (long long) self->num_chunks);\n    fprintf(out, \"\\ttotal_allocated = %lld\\n\", (long long) self->total_allocated);\n    fprintf(out, \"\\ttotal_size = %lld\\n\", (long long) self->total_size);\n}\n\nint TSK_WARN_UNUSED\ntsk_blkalloc_reset(tsk_blkalloc_t *self)\n{\n    int ret = 0;\n\n    self->top = 0;\n    self->current_chunk = 0;\n    self->total_allocated = 0;\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_blkalloc_init(tsk_blkalloc_t *self, size_t chunk_size)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_blkalloc_t));\n    if (chunk_size < 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    self->chunk_size = chunk_size;\n    self->top = 0;\n    self->current_chunk = 0;\n    self->total_allocated = 0;\n    self->total_size = 0;\n    self->num_chunks = 0;\n    self->mem_chunks = malloc(sizeof(char *));\n    if (self->mem_chunks == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    self->mem_chunks[0] = malloc(chunk_size);\n    if (self->mem_chunks[0] == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    self->num_chunks = 1;\n    self->total_size = chunk_size + sizeof(void *);\nout:\n    return ret;\n}\n\nvoid *TSK_WARN_UNUSED\ntsk_blkalloc_get(tsk_blkalloc_t *self, size_t size)\n{\n    void *ret = NULL;\n    void *p;\n\n    if (size > self->chunk_size) {\n        goto out;\n    }\n    if ((self->top + size) > self->chunk_size) {\n        if (self->current_chunk == (self->num_chunks - 1)) {\n            p = realloc(self->mem_chunks, (self->num_chunks + 1) * sizeof(void *));\n            if (p == NULL) {\n                goto out;\n            }\n            self->mem_chunks = p;\n            p = malloc(self->chunk_size);\n            if (p == NULL) {\n                goto out;\n            }\n            self->mem_chunks[self->num_chunks] = p;\n            self->num_chunks++;\n            self->total_size += self->chunk_size + sizeof(void *);\n        }\n        self->current_chunk++;\n        self->top = 0;\n    }\n    ret = self->mem_chunks[self->current_chunk] + self->top;\n    self->top += size;\n    self->total_allocated += size;\nout:\n    return ret;\n}\n\nvoid\ntsk_blkalloc_free(tsk_blkalloc_t *self)\n{\n    size_t j;\n\n    for (j = 0; j < self->num_chunks; j++) {\n        if (self->mem_chunks[j] != NULL) {\n            free(self->mem_chunks[j]);\n        }\n    }\n    if (self->mem_chunks != NULL) {\n        free(self->mem_chunks);\n    }\n}\n\n/* Mirrors the semantics of numpy's searchsorted function. Uses binary\n * search to find the index of the closest value in the array. */\ntsk_size_t\ntsk_search_sorted(const double *restrict array, tsk_size_t size, double value)\n{\n    int64_t upper = (int64_t) size;\n    int64_t lower = 0;\n    int64_t offset = 0;\n    int64_t mid;\n\n    if (upper == 0) {\n        return 0;\n    }\n\n    while (upper - lower > 1) {\n        mid = (upper + lower) / 2;\n        if (value >= array[mid]) {\n            lower = mid;\n        } else {\n            upper = mid;\n        }\n    }\n    offset = (int64_t)(array[lower] < value);\n    return (tsk_size_t)(lower + offset);\n}\n\n/* Rounds the specified double to the closest multiple of 10**-num_digits. If\n * num_digits > 22, return value without changes. This is intended for use with\n * small positive numbers; behaviour with large inputs has not been considered.\n *\n * Based on double_round from the Python standard library\n * https://github.com/python/cpython/blob/master/Objects/floatobject.c#L985\n */\ndouble\ntsk_round(double x, unsigned int ndigits)\n{\n    double pow1, y, z;\n\n    z = x;\n    if (ndigits < 22) {\n        pow1 = pow(10.0, (double) ndigits);\n        y = x * pow1;\n        z = round(y);\n        if (fabs(y - z) == 0.5) {\n            /* halfway between two integers; use round-half-even */\n            z = 2.0 * round(y / 2.0);\n        }\n        z = z / pow1;\n    }\n    return z;\n}\n\n/* As NANs are not equal, use this function to check for equality to TSK_UNKNOWN_TIME */\nbool\ntsk_is_unknown_time(double val)\n{\n    union {\n        uint64_t i;\n        double f;\n    } nan_union;\n    nan_union.f = val;\n    return nan_union.i == TSK_UNKNOWN_TIME_HEX;\n}\n\n/* Work around a bug which seems to show up on various mixtures of\n * compiler and libc versions, where isfinite and isnan result in\n * spurious warnings about casting down to float. The original issue\n * is here:\n * https://github.com/tskit-dev/tskit/issues/721\n *\n * The simplest approach seems to be to use the builtins where they\n * are available (clang and gcc), and to use the library macro\n * otherwise. There would be no disadvantage to using the builtin\n * version, so there's no real harm in this approach.\n */\n\nbool\ntsk_isnan(double val)\n{\n#if defined(__GNUC__)\n    return __builtin_isnan(val);\n#else\n    return isnan(val);\n#endif\n}\n\nbool\ntsk_isfinite(double val)\n{\n#if defined(__GNUC__)\n    return __builtin_isfinite(val);\n#else\n    return isfinite(val);\n#endif\n}\n\nvoid *\ntsk_malloc(tsk_size_t size)\n{\n    /* Avoid malloc(0) as it's not portable */\n    if (size == 0) {\n        size = 1;\n    }\n#if TSK_MAX_SIZE > SIZE_MAX\n    if (size > SIZE_MAX) {\n        return NULL;\n    }\n#endif\n    return malloc((size_t) size);\n}\n\nvoid *\ntsk_realloc(void *ptr, tsk_size_t size)\n{\n    /* We shouldn't ever realloc to a zero size in tskit */\n    tsk_bug_assert(size > 0);\n    return realloc(ptr, (size_t) size);\n}\n\n/* We keep the size argument here as a size_t because we'd have to\n * cast the outputs of sizeof() otherwise, which would lead to\n * less readable code. We need to be careful to use calloc within\n * the library accordingly, so that size can't overflow on 32 bit.\n */\nvoid *\ntsk_calloc(tsk_size_t n, size_t size)\n{\n    /* Avoid calloc(0) as it's not portable */\n    if (n == 0) {\n        n = 1;\n    }\n#if TSK_MAX_SIZE > SIZE_MAX\n    if (n > SIZE_MAX) {\n        return NULL;\n    }\n#endif\n    return calloc((size_t) n, size);\n}\n\nvoid *\ntsk_memset(void *ptr, int fill, tsk_size_t size)\n{\n    return memset(ptr, fill, (size_t) size);\n}\n\nvoid *\ntsk_memcpy(void *dest, const void *src, tsk_size_t size)\n{\n    return memcpy(dest, src, (size_t) size);\n}\n\nvoid *\ntsk_memmove(void *dest, const void *src, tsk_size_t size)\n{\n    return memmove(dest, src, (size_t) size);\n}\n\nint\ntsk_memcmp(const void *s1, const void *s2, tsk_size_t size)\n{\n    return memcmp(s1, s2, (size_t) size);\n}\n\n/* We can't initialise the stream to its real default value because\n * of limitations on static initialisers. To work around this, we initialise\n * it to NULL and then set the value to the required standard stream\n * when called. */\n\nFILE *_tsk_debug_stream = NULL;\n\nvoid\ntsk_set_debug_stream(FILE *f)\n{\n    _tsk_debug_stream = f;\n}\n\nFILE *\ntsk_get_debug_stream(void)\n{\n    if (_tsk_debug_stream == NULL) {\n        _tsk_debug_stream = stdout;\n    }\n    return _tsk_debug_stream;\n}\n\n/* AVL Tree implementation. This is based directly on Knuth's implementation\n * in TAOCP. See the python/tests/test_avl_tree.py for more information,\n * and equivalent code annotated with the original algorithm listing.\n */\n\nstatic void\ntsk_avl_tree_int_print_node(tsk_avl_node_int_t *node, int depth, FILE *out)\n{\n    int d;\n\n    if (node == NULL) {\n        return;\n    }\n    for (d = 0; d < depth; d++) {\n        fprintf(out, \"  \");\n    }\n    fprintf(out, \"key=%d balance=%d\\n\", (int) node->key, node->balance);\n    tsk_avl_tree_int_print_node(node->llink, depth + 1, out);\n    tsk_avl_tree_int_print_node(node->rlink, depth + 1, out);\n}\nvoid\ntsk_avl_tree_int_print_state(tsk_avl_tree_int_t *self, FILE *out)\n{\n    fprintf(out, \"AVL tree: size=%d height=%d\\n\", (int) self->size, (int) self->height);\n    tsk_avl_tree_int_print_node(self->head.rlink, 0, out);\n}\n\nint\ntsk_avl_tree_int_init(tsk_avl_tree_int_t *self)\n{\n    memset(self, 0, sizeof(*self));\n    return 0;\n}\n\nint\ntsk_avl_tree_int_free(tsk_avl_tree_int_t *TSK_UNUSED(self))\n{\n    return 0;\n}\n\ntsk_avl_node_int_t *\ntsk_avl_tree_int_get_root(const tsk_avl_tree_int_t *self)\n{\n    return self->head.rlink;\n}\n\ntsk_avl_node_int_t *\ntsk_avl_tree_int_search(const tsk_avl_tree_int_t *self, int64_t key)\n{\n    tsk_avl_node_int_t *P = self->head.rlink;\n\n    while (P != NULL) {\n        if (key == P->key) {\n            break;\n        } else if (key < P->key) {\n            P = P->llink;\n        } else {\n            P = P->rlink;\n        }\n    }\n    return P;\n}\n\nstatic int\ntsk_avl_tree_int_insert_empty(tsk_avl_tree_int_t *self, tsk_avl_node_int_t *node)\n{\n    self->head.rlink = node;\n    self->size = 1;\n    self->height = 1;\n    node->llink = NULL;\n    node->rlink = NULL;\n    node->balance = 0;\n    return 0;\n}\n\n#define get_link(a, P) ((a) == -1 ? (P)->llink : (P)->rlink)\n#define set_link(a, P, val)                                                             \\\n    do {                                                                                \\\n        if ((a) == -1) {                                                                \\\n            (P)->llink = val;                                                           \\\n        } else {                                                                        \\\n            (P)->rlink = val;                                                           \\\n        }                                                                               \\\n    } while (0);\n\nstatic int\ntsk_avl_tree_int_insert_non_empty(tsk_avl_tree_int_t *self, tsk_avl_node_int_t *node)\n{\n    const int64_t K = node->key;\n    tsk_avl_node_int_t *T = &self->head;\n    tsk_avl_node_int_t *S = T->rlink;\n    tsk_avl_node_int_t *P = T->rlink;\n    tsk_avl_node_int_t *Q, *R;\n    int a;\n\n    while (true) {\n        if (K == P->key) {\n            /* TODO figure out what the most useful semantics are here. Just\n             * returning 1 as a non-zero value for now. */\n            return 1;\n        } else if (K < P->key) {\n            Q = P->llink;\n            if (Q == NULL) {\n                Q = node;\n                P->llink = Q;\n                break;\n            }\n        } else {\n            Q = P->rlink;\n            if (Q == NULL) {\n                Q = node;\n                P->rlink = Q;\n                break;\n            }\n        }\n        if (Q->balance != 0) {\n            T = P;\n            S = Q;\n        }\n        P = Q;\n    }\n\n    self->size++;\n    Q->llink = NULL;\n    Q->rlink = NULL;\n    Q->balance = 0;\n\n    if (K < S->key) {\n        a = -1;\n    } else {\n        a = 1;\n    }\n    P = get_link(a, S);\n    R = P;\n    while (P != Q) {\n        if (K < P->key) {\n            P->balance = -1;\n            P = P->llink;\n        } else if (K > P->key) {\n            P->balance = 1;\n            P = P->rlink;\n        }\n    }\n\n    if (S->balance == 0) {\n        S->balance = a;\n        self->height++;\n    } else if (S->balance == -a) {\n        S->balance = 0;\n    } else {\n        if (R->balance == a) {\n            P = R;\n            set_link(a, S, get_link(-a, R));\n            set_link(-a, R, S);\n            S->balance = 0;\n            R->balance = 0;\n        } else if (R->balance == -a) {\n            P = get_link(-a, R);\n            set_link(-a, R, get_link(a, P));\n            set_link(a, P, R);\n            set_link(a, S, get_link(-a, P));\n            set_link(-a, P, S);\n            if (P->balance == a) {\n                S->balance = -a;\n                R->balance = 0;\n            } else if (P->balance == 0) {\n                S->balance = 0;\n                R->balance = 0;\n            } else {\n                S->balance = 0;\n                R->balance = a;\n            }\n            P->balance = 0;\n        }\n        if (S == T->rlink) {\n            T->rlink = P;\n        } else {\n            T->llink = P;\n        }\n    }\n    return 0;\n}\n\nint\ntsk_avl_tree_int_insert(tsk_avl_tree_int_t *self, tsk_avl_node_int_t *node)\n{\n    int ret = 0;\n\n    if (self->size == 0) {\n        ret = tsk_avl_tree_int_insert_empty(self, node);\n    } else {\n        ret = tsk_avl_tree_int_insert_non_empty(self, node);\n    }\n    return ret;\n}\n\n/* An inorder traversal of the nodes in an AVL tree (or any binary search tree)\n * yields the keys in sorted order. The recursive implementation is safe here\n * because this is an AVL tree and it is strictly balanced, the depth is very\n * limited. Using GCC's __builtin_frame_address it looks like the size of a stack\n * frame for this function is 48 bytes. Assuming a stack size of 1MiB, this\n * would give us a maximum tree depth of 21845 - so, we're pretty safe.\n */\nstatic int\nordered_nodes_traverse(tsk_avl_node_int_t *node, int index, tsk_avl_node_int_t **out)\n{\n    if (node == NULL) {\n        return index;\n    }\n    index = ordered_nodes_traverse(node->llink, index, out);\n    out[index] = node;\n    return ordered_nodes_traverse(node->rlink, index + 1, out);\n}\n\nint\ntsk_avl_tree_int_ordered_nodes(const tsk_avl_tree_int_t *self, tsk_avl_node_int_t **out)\n{\n    ordered_nodes_traverse(self->head.rlink, 0, out);\n    return 0;\n}\n\n// Bit Array implementation. Allows us to store unsigned integers in a compact manner.\n// Currently implemented as an array of 32-bit unsigned integers.\n\nint\ntsk_bitset_init(tsk_bitset_t *self, tsk_size_t num_bits, tsk_size_t length)\n{\n    int ret = 0;\n\n    self->row_len = (num_bits / TSK_BITSET_BITS) + (num_bits % TSK_BITSET_BITS ? 1 : 0);\n    self->len = length;\n    self->data = tsk_calloc(self->row_len * length, sizeof(*self->data));\n    if (self->data == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\n#define BITSET_DATA_ROW(bs, row) ((bs)->data + (row) * (bs)->row_len)\n\nvoid\ntsk_bitset_intersect(const tsk_bitset_t *self, tsk_size_t self_row,\n    const tsk_bitset_t *other, tsk_size_t other_row, tsk_bitset_t *out)\n{\n    const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);\n    const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);\n    tsk_bitset_val_t *restrict out_d = out->data;\n    for (tsk_size_t i = 0; i < self->row_len; i++) {\n        out_d[i] = self_d[i] & other_d[i];\n    }\n}\n\nvoid\ntsk_bitset_subtract(tsk_bitset_t *self, tsk_size_t self_row, const tsk_bitset_t *other,\n    tsk_size_t other_row)\n{\n    tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);\n    const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);\n    for (tsk_size_t i = 0; i < self->row_len; i++) {\n        self_d[i] &= ~(other_d[i]);\n    }\n}\n\nvoid\ntsk_bitset_union(tsk_bitset_t *self, tsk_size_t self_row, const tsk_bitset_t *other,\n    tsk_size_t other_row)\n{\n    tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, self_row);\n    const tsk_bitset_val_t *restrict other_d = BITSET_DATA_ROW(other, other_row);\n    for (tsk_size_t i = 0; i < self->row_len; i++) {\n        self_d[i] |= other_d[i];\n    }\n}\n\nvoid\ntsk_bitset_set_bit(tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit)\n{\n    tsk_bitset_val_t i = (bit / TSK_BITSET_BITS);\n    *(BITSET_DATA_ROW(self, row) + i) |= (tsk_bitset_val_t) 1\n                                         << (bit - (TSK_BITSET_BITS * i));\n}\n\nbool\ntsk_bitset_contains(const tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit)\n{\n    tsk_bitset_val_t i = (bit / TSK_BITSET_BITS);\n    return *(BITSET_DATA_ROW(self, row) + i)\n           & ((tsk_bitset_val_t) 1 << (bit - (TSK_BITSET_BITS * i)));\n}\n\nstatic inline uint32_t\npopcount(tsk_bitset_val_t v)\n{\n    // Utilizes 12 operations per chunk. NB this only works on 32 bit integers.\n    // Taken from:\n    //   https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel\n    // There's a nice breakdown of this algorithm here:\n    //   https://stackoverflow.com/a/109025\n    //\n    // The gcc/clang compiler flag will -mpopcnt will convert this code to a\n    // popcnt instruction (most if not all modern CPUs will support this). The\n    // popcnt instruction will yield some speed improvements, which depend on\n    // the tree sequence.\n    //\n    // NB: 32bit counting is typically faster than 64bit counting for this task.\n    //     (at least on x86-64)\n\n    v = v - ((v >> 1) & 0x55555555);\n    v = (v & 0x33333333) + ((v >> 2) & 0x33333333);\n    return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;\n}\n\ntsk_size_t\ntsk_bitset_count(const tsk_bitset_t *self, tsk_size_t row)\n{\n    tsk_size_t i = 0;\n    tsk_size_t count = 0;\n    const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, row);\n\n    for (i = 0; i < self->row_len; i++) {\n        count += popcount(self_d[i]);\n    }\n    return count;\n}\n\nvoid\ntsk_bitset_get_items(\n    const tsk_bitset_t *self, tsk_size_t row, tsk_id_t *items, tsk_size_t *n_items)\n{\n    // Get the items stored in the row of a bitset.\n    // Uses a de Bruijn sequence lookup table to determine the lowest bit set.\n    // See the wikipedia article for more info: https://w.wiki/BYiF\n\n    tsk_size_t i, n, off;\n    tsk_bitset_val_t v, lsb; // least significant bit\n    static const tsk_id_t lookup[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25,\n        17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };\n    const tsk_bitset_val_t *restrict self_d = BITSET_DATA_ROW(self, row);\n\n    n = 0;\n    for (i = 0; i < self->row_len; i++) {\n        v = self_d[i];\n        off = i * TSK_BITSET_BITS;\n        if (v == 0) {\n            continue;\n        }\n        while ((lsb = v & -v)) {\n            items[n] = lookup[(lsb * 0x077cb531U) >> 27] + (tsk_id_t) off;\n            n++;\n            v ^= lsb;\n        }\n    }\n    *n_items = n;\n}\n\nvoid\ntsk_bitset_free(tsk_bitset_t *self)\n{\n    tsk_safe_free(self->data);\n}\n"
  },
  {
    "path": "treerec/tskit/core.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n * Copyright (c) 2015-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @file core.h\n * @brief Core utilities used in all of tskit.\n */\n#ifndef __TSK_CORE_H__\n#define __TSK_CORE_H__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <math.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <limits.h>\n\n#ifdef __GNUC__\n#define TSK_WARN_UNUSED __attribute__((warn_unused_result))\n#define TSK_UNUSED(x) TSK_UNUSED_##x __attribute__((__unused__))\n#else\n#define TSK_WARN_UNUSED\n#define TSK_UNUSED(x) TSK_UNUSED_##x\n/* Don't bother with restrict for MSVC */\n#define restrict\n#endif\n\n/* We assume CHAR_BIT == 8 when loading strings from 8-bit byte arrays */\n#if CHAR_BIT != 8\n#error CHAR_BIT MUST EQUAL 8\n#endif\n\n/* This sets up TSK_DBL_DECIMAL_DIG, which can then be used as a\n * precision specifier when writing out doubles, if you want sufficient\n * decimal digits to be written to guarantee a lossless round-trip\n * after being read back in.  Usage:\n *\n *     printf(\"%.*g\", TSK_DBL_DECIMAL_DIG, foo);\n *\n * See https://stackoverflow.com/a/19897395/2752221\n */\n#ifdef DBL_DECIMAL_DIG\n#define TSK_DBL_DECIMAL_DIG (DBL_DECIMAL_DIG)\n#else\n#define TSK_DBL_DECIMAL_DIG (DBL_DIG + 3)\n#endif\n\n/**\n@brief Tskit Object IDs.\n\n@rst\nAll objects in tskit are referred to by integer IDs corresponding to the\nrow they occupy in the relevant table. The ``tsk_id_t`` type should be used\nwhen manipulating these ID values. The reserved value :c:macro:`TSK_NULL` (-1) defines\nmissing data.\n@endrst\n*/\n#ifdef _TSK_BIG_TABLES\n/* Allow tables to have more than 2^31 rows. This is an EXPERIMENTAL feature\n * and is not supported in any way. This typedef is only included for\n * future-proofing purposes, so that we can be sure that we don't make any\n * design decisions that are incompatible with big tables by building the\n * library in 64 bit mode in CI. See the discussion here for more background:\n\n * https://github.com/tskit-dev/tskit/issues/343\n *\n * If you need big tables, please open an issue on GitHub to discuss, or comment\n * on the thread above.\n */\ntypedef int64_t tsk_id_t;\n#define TSK_MAX_ID INT64_MAX - 1\n#define TSK_ID_STORAGE_TYPE KAS_INT64\n#else\ntypedef int32_t tsk_id_t;\n#define TSK_MAX_ID INT32_MAX - 1\n#define TSK_ID_STORAGE_TYPE KAS_INT32\n#endif\n\n/**\n@brief Tskit sizes.\n\n@rst\nThe ``tsk_size_t`` type is an unsigned integer used for any size or count value.\n@endrst\n*/\ntypedef uint64_t tsk_size_t;\n#define TSK_MAX_SIZE UINT64_MAX\n#define TSK_SIZE_STORAGE_TYPE KAS_UINT64\n\n/**\n@brief Container for bitwise flags.\n\n@rst\nBitwise flags are used in tskit as a column type and also as a way to\nspecify options to API functions.\n@endrst\n*/\ntypedef uint32_t tsk_flags_t;\n#define TSK_FLAGS_STORAGE_TYPE KAS_UINT32\n\n/**\n@brief Boolean type.\n\n@rst\nFixed-size (1 byte) boolean values.\n@endrst\n*/\ntypedef uint8_t tsk_bool_t;\n\n// clang-format off\n/**\n@defgroup API_VERSION_GROUP API version macros.\n@{\n*/\n/**\nThe library major version. Incremented when breaking changes to the API or ABI are\nintroduced. This includes any changes to the signatures of functions and the\nsizes and types of externally visible structs.\n*/\n#define TSK_VERSION_MAJOR   1\n/**\nThe library minor version. Incremented when non-breaking backward-compatible changes\nto the API or ABI are introduced, i.e., the addition of a new function.\n*/\n#define TSK_VERSION_MINOR   3\n/**\nThe library patch version. Incremented when any changes not relevant to the\nto the API or ABI are introduced, i.e., internal refactors of bugfixes.\n*/\n#define TSK_VERSION_PATCH   0\n/** @} */\n\n/*\nWe define a specific NAN value for default mutation time which indicates\nthe time is unknown. We use a specific value so that if mutation time is set to\na NAN from a computation we can reject it. This specific value is a non-signalling\nNAN with the last six fraction bytes set to the ascii of \"tskit!\"\n*/\n#define TSK_UNKNOWN_TIME_HEX 0x7FF874736B697421ULL\nstatic inline double\n__tsk_nan_f(void)\n{\n    const union {\n        uint64_t i;\n        double f;\n    } nan_union = { .i = TSK_UNKNOWN_TIME_HEX };\n    return nan_union.f;\n}\n\n/**\n@defgroup GENERIC_CONSTANTS General options flags used in some functions.\n@{\n*/\n/**\nUsed in node flags to indicate that a node is a sample node.\n*/\n#define TSK_NODE_IS_SAMPLE 1u\n\n/**\nNull value used for cases such as absent id references.\n*/\n#define TSK_NULL ((tsk_id_t) -1)\n\n/**\nValue used for missing data in genotype arrays.\n*/\n#define TSK_MISSING_DATA    (-1)\n\n/**\nValue to indicate that a time is unknown. Note that this value is a non-signalling NAN\nwhose representation differs from the NAN generated by computations such as divide by zeros.\n*/\n#define TSK_UNKNOWN_TIME __tsk_nan_f()\n\n/** @} */\n\n#define TSK_TIME_UNITS_UNKNOWN \"unknown\"\n#define TSK_TIME_UNITS_UNCALIBRATED \"uncalibrated\"\n\n\n#define TSK_FILE_FORMAT_NAME          \"tskit.trees\"\n#define TSK_FILE_FORMAT_NAME_LENGTH   11\n#define TSK_FILE_FORMAT_VERSION_MAJOR 12\n#define TSK_FILE_FORMAT_VERSION_MINOR 7\n\n/**\n@defgroup GENERIC_FUNCTION_OPTIONS General options flags used in some functions.\n@{\n*/\n\n/* Place the common options at the top of the space; this way we can start\noptions for individual functions at the bottom without worrying about\nclashing with the common options\n*/\n\n/** Turn on debugging output. Not supported by all functions. */\n#define TSK_DEBUG (1u << 31)\n\n/** Do not initialise the parameter object. */\n#define TSK_NO_INIT (1u << 30)\n\n/**\nDo not run integrity checks before performing an operation.\nThis performance optimisation should not be used unless the calling code can\nguarantee reference integrity within the table collection. References\nto rows not in the table or bad offsets will result in undefined\nbehaviour.\n*/\n#define TSK_NO_CHECK_INTEGRITY (1u << 29)\n\n/**\nInstead of taking a copy of input objects, the function should take ownership\nof them and manage their lifecycle. The caller specifying this flag should no\nlonger modify or free the object or objects passed. See individual functions\nusing this flag for what object it applies to.\n*/\n#define TSK_TAKE_OWNERSHIP (1u << 28)\n\n/** @} */\n\n\n/**\n@defgroup GENERAL_ERROR_GROUP General errors.\n@{\n*/\n\n/**\nGeneric error thrown when no other message can be generated.\n*/\n#define TSK_ERR_GENERIC                                             -1\n/**\nMemory could not be allocated.\n*/\n#define TSK_ERR_NO_MEMORY                                           -2\n/**\nAn IO error occurred.\n*/\n#define TSK_ERR_IO                                                  -3\n#define TSK_ERR_BAD_PARAM_VALUE                                     -4\n#define TSK_ERR_BUFFER_OVERFLOW                                     -5\n#define TSK_ERR_UNSUPPORTED_OPERATION                               -6\n#define TSK_ERR_GENERATE_UUID                                       -7\n/**\nThe file stream ended after reading zero bytes.\n*/\n#define TSK_ERR_EOF                                                 -8\n/** @} */\n\n/**\n@defgroup FILE_FORMAT_ERROR_GROUP File format errors.\n@{\n*/\n\n/**\nA file could not be read because it is in the wrong format\n*/\n#define TSK_ERR_FILE_FORMAT                                         -100\n/**\nThe file is in tskit format, but the version is too old for the\nlibrary to read. The file should be upgraded to the latest version\nusing the ``tskit upgrade`` command line utility from tskit version<0.6.2.\n*/\n#define TSK_ERR_FILE_VERSION_TOO_OLD                                -101\n/**\nThe file is in tskit format, but the version is too new for the\nlibrary to read. To read the file you must upgrade the version\nof tskit.\n*/\n#define TSK_ERR_FILE_VERSION_TOO_NEW                                -102\n\n/**\nA column that is a required member of a table was not found in\nthe file.\n*/\n#define TSK_ERR_REQUIRED_COL_NOT_FOUND                              -103\n\n/**\nOne of a pair of columns that must be specified together was\nnot found in the file.\n*/\n#define TSK_ERR_BOTH_COLUMNS_REQUIRED                               -104\n\n/**\nAn unsupported type was provided for a column in the file.\n*/\n#define TSK_ERR_BAD_COLUMN_TYPE                                     -105\n/** @} */\n\n/**\n@defgroup OOB_ERROR_GROUP Out of bounds errors.\n@{\n*/\n/**\nA bad value was provided for a ragged column offset, values should\nstart at zero and be monotonically increasing.\n*/\n#define TSK_ERR_BAD_OFFSET                                          -200\n/**\nA position to seek to was less than zero or greater than the length\nof the genome\n*/\n#define TSK_ERR_SEEK_OUT_OF_BOUNDS                                  -201\n/**\nA node id was less than zero or greater than the final index\n*/\n#define TSK_ERR_NODE_OUT_OF_BOUNDS                                  -202\n/**\nA edge id was less than zero or greater than the final index\n*/\n#define TSK_ERR_EDGE_OUT_OF_BOUNDS                                  -203\n/**\nA population id was less than zero or greater than the final index\n*/\n#define TSK_ERR_POPULATION_OUT_OF_BOUNDS                            -204\n/**\nA site id was less than zero or greater than the final index\n*/\n#define TSK_ERR_SITE_OUT_OF_BOUNDS                                  -205\n/**\nA mutation id was less than zero or greater than the final index\n*/\n#define TSK_ERR_MUTATION_OUT_OF_BOUNDS                              -206\n/**\nAn individual id was less than zero or greater than the final index\n*/\n#define TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS                            -207\n/**\nA migration id was less than zero or greater than the final index\n*/\n#define TSK_ERR_MIGRATION_OUT_OF_BOUNDS                             -208\n/**\nA provenance id was less than zero or greater than the final index\n*/\n#define TSK_ERR_PROVENANCE_OUT_OF_BOUNDS                            -209\n/**\nA time value was non-finite (NaN counts as finite)\n*/\n#define TSK_ERR_TIME_NONFINITE                                      -210\n/**\nA genomic position was non-finite\n*/\n#define TSK_ERR_GENOME_COORDS_NONFINITE                             -211\n/**\nOne of the rows in the retained table refers to a row that has been\ndeleted.\n*/\n#define TSK_ERR_KEEP_ROWS_MAP_TO_DELETED                            -212\n/**\nA genomic position was less than zero or greater equal to the sequence\nlength\n*/\n#define TSK_ERR_POSITION_OUT_OF_BOUNDS                              -213\n\n/** @} */\n\n/**\n@defgroup EDGE_ERROR_GROUP Edge errors.\n@{\n*/\n/**\nA parent node of an edge was TSK_NULL.\n*/\n#define TSK_ERR_NULL_PARENT                                         -300\n/**\nA child node of an edge was TSK_NULL.\n*/\n#define TSK_ERR_NULL_CHILD                                          -301\n/**\nThe edge table was not sorted by the time of each edge's parent\nnodes. Sort order is (time[parent], child, left).\n*/\n#define TSK_ERR_EDGES_NOT_SORTED_PARENT_TIME                        -302\n/**\nA parent node had edges that were non-contigious.\n*/\n#define TSK_ERR_EDGES_NONCONTIGUOUS_PARENTS                         -303\n/**\nThe edge table was not sorted by the id of the child node of each edge.\nSort order is (time[parent], child, left).\n*/\n#define TSK_ERR_EDGES_NOT_SORTED_CHILD                              -304\n/**\nThe edge table was not sorted by the left coordinate each edge.\nSort order is (time[parent], child, left).\n*/\n#define TSK_ERR_EDGES_NOT_SORTED_LEFT                               -305\n/**\nAn edge had child node that was older than the parent. Parent times must\nbe greater than the child time.\n*/\n#define TSK_ERR_BAD_NODE_TIME_ORDERING                              -306\n/**\nAn edge had a genomic interval where right was greater or equal to left.\n*/\n#define TSK_ERR_BAD_EDGE_INTERVAL                                   -307\n/**\nAn edge was duplicated.\n*/\n#define TSK_ERR_DUPLICATE_EDGES                                     -308\n/**\nAn edge had a right coord greater than the genomic length.\n*/\n#define TSK_ERR_RIGHT_GREATER_SEQ_LENGTH                            -309\n/**\nAn edge had a left coord less than zero.\n*/\n#define TSK_ERR_LEFT_LESS_ZERO                                      -310\n/**\nA parent node had edges that were contradictory over an interval.\n*/\n#define TSK_ERR_BAD_EDGES_CONTRADICTORY_CHILDREN                    -311\n/**\nA method that doesn't support edge metadata was attempted on an edge\ntable containing metadata.\n*/\n#define TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA                    -312\n/** @} */\n\n/**\n@defgroup SITE_ERROR_GROUP Site errors.\n@{\n*/\n/**\nThe site table was not in order of increasing genomic position.\n*/\n#define TSK_ERR_UNSORTED_SITES                                      -400\n/**\nThe site table had more than one site at a single genomic position.\n*/\n#define TSK_ERR_DUPLICATE_SITE_POSITION                             -401\n/**\nA site had a position that was less than zero or greater than the sequence\nlength.\n*/\n#define TSK_ERR_BAD_SITE_POSITION                                   -402\n/** @} */\n\n/**\n@defgroup MUTATION_ERROR_GROUP Mutation errors.\n@{\n*/\n/**\nA mutation had a parent mutation that was at a different site.\n*/\n#define TSK_ERR_MUTATION_PARENT_DIFFERENT_SITE                      -500\n/**\nA mutation had a parent mutation that was itself.\n*/\n#define TSK_ERR_MUTATION_PARENT_EQUAL                               -501\n/**\nA mutation had a parent mutation that had a greater id.\n*/\n#define TSK_ERR_MUTATION_PARENT_AFTER_CHILD                         -502\n/**\nTwo or more mutation parent references formed a loop\n*/\n#define TSK_ERR_MUTATION_PARENT_INCONSISTENT                        -503\n/**\nThe mutation table was not in the order of non-decreasing site id and\nnon-increasing time within each site.\n*/\n#define TSK_ERR_UNSORTED_MUTATIONS                                  -504\n/* 505 was the now unused TSK_ERR_NON_SINGLE_CHAR_MUTATION */\n/**\nA mutation's time was younger (not >=) the time of its node\nand wasn't TSK_UNKNOWN_TIME.\n*/\n#define TSK_ERR_MUTATION_TIME_YOUNGER_THAN_NODE                     -506\n/**\nA mutation's time was older (not <=) than the time of its parent\nmutation, and wasn't TSK_UNKNOWN_TIME.\n*/\n#define TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_MUTATION            -507\n/**\nA mutation's time was older (not <) than the time of the parent node of\nthe edge on which it occurs, and wasn't TSK_UNKNOWN_TIME.\n*/\n#define TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_NODE                -508\n/**\nA single site had a mixture of known mutation times and TSK_UNKNOWN_TIME\n*/\n#define TSK_ERR_MUTATION_TIME_HAS_BOTH_KNOWN_AND_UNKNOWN            -509\n/**\nSome mutations have TSK_UNKNOWN_TIME in an algorithm where that's\ndisallowed (use compute_mutation_times?).\n*/\n#define TSK_ERR_DISALLOWED_UNKNOWN_MUTATION_TIME                    -510\n\n/** \nA mutation's parent was not consistent with the topology of the tree.\n */\n#define TSK_ERR_BAD_MUTATION_PARENT                                 -511\n\n/** @} */\n\n/**\n@defgroup MIGRATION_ERROR_GROUP Migration errors.\n@{\n*/\n/**\nThe migration table was not sorted by time.\n*/\n#define TSK_ERR_UNSORTED_MIGRATIONS                                 -550\n/** @} */\n\n/**\n@defgroup SAMPLE_ERROR_GROUP Sample errors.\n@{\n*/\n/**\nA duplicate sample was specified.\n*/\n#define TSK_ERR_DUPLICATE_SAMPLE                                    -600\n/**\nA sample id that was not valid was specified.\n*/\n#define TSK_ERR_BAD_SAMPLES                                         -601\n/** @} */\n\n/**\n@defgroup TABLE_ERROR_GROUP Table errors.\n@{\n*/\n/**\nAn invalid table position was specifed.\n*/\n#define TSK_ERR_BAD_TABLE_POSITION                                  -700\n/**\nA sequence length equal to or less than zero was specified.\n*/\n#define TSK_ERR_BAD_SEQUENCE_LENGTH                                 -701\n/**\nThe table collection was not indexed.\n*/\n#define TSK_ERR_TABLES_NOT_INDEXED                                  -702\n/**\nTables cannot be larger than 2**31 rows.\n*/\n#define TSK_ERR_TABLE_OVERFLOW                                      -703\n/**\nRagged array columns cannot be larger than 2**64 bytes.\n*/\n#define TSK_ERR_COLUMN_OVERFLOW                                     -704\n/**\nThe table collection contains more than 2**31 trees.\n*/\n#define TSK_ERR_TREE_OVERFLOW                                       -705\n/**\nMetadata was attempted to be set on a table where it is disabled.\n*/\n#define TSK_ERR_METADATA_DISABLED                                   -706\n/**\nThere was an error with the table's indexes.\n*/\n#define TSK_ERR_TABLES_BAD_INDEXES                                  -707\n/** @} */\n\n/**\n@defgroup LIMITATION_ERROR_GROUP Limitation errors.\n@{\n*/\n/**\nAn operation was attempted that only supports infinite sites, i.e.\nat most a single mutation per site.\n*/\n#define TSK_ERR_ONLY_INFINITE_SITES                                 -800\n/**\nSimplification was attempted with migrations present, which are not\nsupported.\n*/\n#define TSK_ERR_SIMPLIFY_MIGRATIONS_NOT_SUPPORTED                   -801\n/**\nSorting was attempted on migrations, which is not supported.\n*/\n#define TSK_ERR_SORT_MIGRATIONS_NOT_SUPPORTED                       -802\n/**\nAn invalid sort offset was specified, for sites and mutations this must\nbe either 0 or the table length.\n*/\n#define TSK_ERR_SORT_OFFSET_NOT_SUPPORTED                           -803\n/**\nAn operation was attempted that only supports binary mutations.\n*/\n#define TSK_ERR_NONBINARY_MUTATIONS_UNSUPPORTED                     -804\n/**\nAn operation was attempted that doesn't support migrations, with a\nnon-empty migration table.\n*/\n#define TSK_ERR_MIGRATIONS_NOT_SUPPORTED                            -805\n/**\nA table attempted to extend from itself.\n*/\n#define TSK_ERR_CANNOT_EXTEND_FROM_SELF                             -806\n/**\nAn operation was attempted that doesn't support silent mutations, i.e.\na mutation that doesn't change the allelic state.\n*/\n#define TSK_ERR_SILENT_MUTATIONS_NOT_SUPPORTED                      -807\n/**\nA copy of a variant cannot be decoded.\n*/\n#define TSK_ERR_VARIANT_CANT_DECODE_COPY                            -808\n/**\nA tree sequence cannot take ownership of a table collection where\nTSK_NO_EDGE_METADATA.\n*/\n#define TSK_ERR_CANT_TAKE_OWNERSHIP_NO_EDGE_METADATA                -809\n/**\nOperation is undefined for nonbinary trees\n*/\n#define TSK_ERR_UNDEFINED_NONBINARY                                 -810\n/**\nOperation is undefined for trees with multiple roots.\n*/\n#define TSK_ERR_UNDEFINED_MULTIROOT                                 -811\n\n/** @} */\n\n/**\n@defgroup STATS_ERROR_GROUP Stats errors.\n@{\n*/\n/**\nZero windows were specified, at least one window must be specified.\n*/\n#define TSK_ERR_BAD_NUM_WINDOWS                                     -900\n/**\nThe window specification was not an increasing list of positions between\n0 and the sequence length.\n*/\n#define TSK_ERR_BAD_WINDOWS                                         -901\n/**\nMore than one stat mode was specified.\n*/\n#define TSK_ERR_MULTIPLE_STAT_MODES                                 -902\n/**\nThe state dimension was not >=1.\n*/\n#define TSK_ERR_BAD_STATE_DIMS                                      -903\n/**\nThe result dimension was not >=1.\n*/\n#define TSK_ERR_BAD_RESULT_DIMS                                     -904\n/**\nInsufficient sample sets were provided.\n*/\n#define TSK_ERR_INSUFFICIENT_SAMPLE_SETS                            -905\n/**\nInsufficient sample set index tuples were provided.\n*/\n#define TSK_ERR_INSUFFICIENT_INDEX_TUPLES                           -906\n/**\nThe sample set index was out of bounds.\n*/\n#define TSK_ERR_BAD_SAMPLE_SET_INDEX                                -907\n/**\nThe sample set index was empty.\n*/\n#define TSK_ERR_EMPTY_SAMPLE_SET                                    -908\n/**\nA stat mode was attempted that is not supported by the operation.\n*/\n#define TSK_ERR_UNSUPPORTED_STAT_MODE                               -909\n/**\nStatistics based on branch lengths were attempted when the ``time_units``\nwere ``uncalibrated``.\n*/\n#define TSK_ERR_TIME_UNCALIBRATED                                   -910\n/**\nThe TSK_STAT_POLARISED option was passed to a statistic that does\nnot support it.\n*/\n#define TSK_ERR_STAT_POLARISED_UNSUPPORTED                          -911\n/**\nThe TSK_STAT_SPAN_NORMALISE option was passed to a statistic that does\nnot support it.\n*/\n#define TSK_ERR_STAT_SPAN_NORMALISE_UNSUPPORTED                     -912\n/**\nInsufficient weights were provided.\n*/\n#define TSK_ERR_INSUFFICIENT_WEIGHTS                                -913\n/**\nThe node bin map contains a value less than TSK_NULL.\n*/\n#define TSK_ERR_BAD_NODE_BIN_MAP                                    -914\n/**\nMaximum index in node bin map is greater than output dimension.\n*/\n#define TSK_ERR_BAD_NODE_BIN_MAP_DIM                                -915\n/**\nThe vector of quantiles is out of bounds or in nonascending order.\n*/\n#define TSK_ERR_BAD_QUANTILES                                       -916\n/**\nTimes are not in ascending order\n*/\n#define TSK_ERR_UNSORTED_TIMES                                      -917\n/*\nThe provided positions are not provided in strictly increasing order\n*/\n#define TSK_ERR_STAT_UNSORTED_POSITIONS                             -918\n/**\nThe provided positions are not unique\n*/\n#define TSK_ERR_STAT_DUPLICATE_POSITIONS                            -919\n/**\nThe provided sites are not provided in strictly increasing position order\n*/\n#define TSK_ERR_STAT_UNSORTED_SITES                                 -920\n/**\nThe provided sites are not unique\n*/\n#define TSK_ERR_STAT_DUPLICATE_SITES                                -921\n/**\nThe number of time windows is zero\n*/\n#define TSK_ERR_BAD_TIME_WINDOWS_DIM                                -922\n/**\nSample times do not all equal the start of first time window\n*/\n#define TSK_ERR_BAD_SAMPLE_PAIR_TIMES                               -923\n/**\nTime windows are not strictly increasing\n*/\n#define TSK_ERR_BAD_TIME_WINDOWS                                    -924\n/**\nTime windows do not end at infinity\n*/\n#define TSK_ERR_BAD_TIME_WINDOWS_END                                -925\n/**\nNode time does not fall within assigned time window\n*/\n#define TSK_ERR_BAD_NODE_TIME_WINDOW                                -926\n/** @} */\n\n/**\n@defgroup MAPPING_ERROR_GROUP Mutation mapping errors.\n@{\n*/\n/**\nOnly missing genotypes were specified, at least one non-missing is\nrequired.\n*/\n#define TSK_ERR_GENOTYPES_ALL_MISSING                              -1000\n/**\nA genotype value was greater than the maximum allowed (64) or less\nthan TSK_MISSING_DATA (-1).\n*/\n#define TSK_ERR_BAD_GENOTYPE                                       -1001\n/**\nA ancestral genotype value was greater than the maximum allowed (64) or less\nthan 0.\n*/\n#define TSK_ERR_BAD_ANCESTRAL_STATE                                -1002\n/** @} */\n\n/**\n@defgroup GENOTYPE_ERROR_GROUP Genotype decoding errors.\n@{\n*/\n/**\nGenotypes were requested for non-samples at the same time\nas asking that isolated nodes be marked as missing. This is not\nsupported.\n*/\n#define TSK_ERR_MUST_IMPUTE_NON_SAMPLES                            -1100\n/**\nA user-specified allele map was used, but didn't contain an allele\nfound in the tree sequence.\n*/\n#define TSK_ERR_ALLELE_NOT_FOUND                                   -1101\n/**\nMore than 2147483647 alleles were specified.\n*/\n#define TSK_ERR_TOO_MANY_ALLELES                                   -1102\n/**\nA user-specified allele map was used, but it contained zero alleles.\n*/\n#define TSK_ERR_ZERO_ALLELES                                       -1103\n/**\nAn allele used when decoding alignments had length other than one.\n*/\n#define TSK_ERR_BAD_ALLELE_LENGTH                                  -1104\n/**\nAn allele used when decoding alignments matched the missing data character.\n*/\n#define TSK_ERR_MISSING_CHAR_COLLISION                             -1105\n/** @} */\n\n/**\n@defgroup DISTANCE_ERROR_GROUP Distance metric errors.\n@{\n*/\n/**\nTrees with different numbers of samples were specified.\n*/\n#define TSK_ERR_SAMPLE_SIZE_MISMATCH                               -1200\n/**\nTrees with nonidentical samples were specified.\n*/\n#define TSK_ERR_SAMPLES_NOT_EQUAL                                  -1201\n/**\nA tree with multiple roots was specified.\n*/\n#define TSK_ERR_MULTIPLE_ROOTS                                     -1202\n/**\nA tree with unary nodes was specified.\n*/\n#define TSK_ERR_UNARY_NODES                                        -1203\n/**\nTrees were specifed that had unequal sequence lengths.\n*/\n#define TSK_ERR_SEQUENCE_LENGTH_MISMATCH                           -1204\n/**\nA tree was specifed that did not have the sample lists option\nenabled (TSK_SAMPLE_LISTS).\n*/\n#define TSK_ERR_NO_SAMPLE_LISTS                                    -1205\n/** @} */\n\n/**\n@defgroup HAPLOTYPE_ERROR_GROUP Haplotype matching errors.\n@{\n*/\n/**\nThe Viterbi matrix has not filled (it has zero transitions).\n*/\n#define TSK_ERR_NULL_VITERBI_MATRIX                                -1300\n/**\nThere was no matching haplotype.\n*/\n#define TSK_ERR_MATCH_IMPOSSIBLE                                   -1301\n/**\nThe compressed matrix has a node that has no samples in it's descendants.\n*/\n#define TSK_ERR_BAD_COMPRESSED_MATRIX_NODE                         -1302\n/**\nThere are too many values to compress.\n*/\n#define TSK_ERR_TOO_MANY_VALUES                                    -1303\n/** @} */\n\n/**\n@defgroup UNION_ERROR_GROUP Union errors.\n@{\n*/\n/**\nA node map was specified that contained a node not present in the\nspecified table collection.\n*/\n#define TSK_ERR_UNION_BAD_MAP                                      -1400\n/**\nThe shared portions of the specified tree sequences are not equal.\nNote that this may be the case if the table collections were not\nfully sorted before union was called.\n*/\n#define TSK_ERR_UNION_DIFF_HISTORIES                               -1401\n/** @} */\n\n/**\n@defgroup IBD_ERROR_GROUP IBD errors.\n@{\n*/\n/**\nBoth nodes in a sample pair are the same node.\n*/\n#define TSK_ERR_SAME_NODES_IN_PAIR                                 -1500\n/**\nPer-pair statistics were requested without TSK_IBD_STORE_PAIRS being\nspecified.\n*/\n#define TSK_ERR_IBD_PAIRS_NOT_STORED                               -1501\n/**\nSegments were requested without TSK_IBD_STORE_SEGMENTS being specified.\n*/\n#define TSK_ERR_IBD_SEGMENTS_NOT_STORED                            -1502\n/** @} */\n\n/**\n@defgroup SIMPLIFY_ERROR_GROUP Simplify errors.\n@{\n*/\n/**\nBoth TSK_SIMPLIFY_KEEP_UNARY and TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS\nwere specified. Only one can be used.\n*/\n#define TSK_ERR_KEEP_UNARY_MUTUALLY_EXCLUSIVE                      -1600\n/** @} */\n\n/**\n@defgroup INDIVIDUAL_ERROR_GROUP Individual errors.\n@{\n*/\n/**\nIndividuals were provided in an order where parents were after their\nchildren.\n*/\n#define TSK_ERR_UNSORTED_INDIVIDUALS                               -1700\n/**\nAn individual was its own parent.\n*/\n#define TSK_ERR_INDIVIDUAL_SELF_PARENT                             -1701\n/**\nAn individual was its own ancestor in a cycle of references.\n*/\n#define TSK_ERR_INDIVIDUAL_PARENT_CYCLE                            -1702\n/**\nAn individual had nodes from more than one population\n(and only one was requested).\n*/\n#define TSK_ERR_INDIVIDUAL_POPULATION_MISMATCH                     -1703\n/**\nAn individual had nodes from more than one time\n(and only one was requested).\n*/\n#define TSK_ERR_INDIVIDUAL_TIME_MISMATCH                           -1704\n/** @} */\n\n/**\n@defgroup EXTEND_EDGES_ERROR_GROUP Extend edges errors.\n@{\n*/\n/**\nMaximum iteration number (max_iter) must be positive.\n*/\n#define TSK_ERR_EXTEND_EDGES_BAD_MAXITER                          -1800\n/** @} */\n// clang-format on\n\n/* This bit is 0 for any errors originating from kastore */\n#define TSK_KAS_ERR_BIT 14\n\nint tsk_set_kas_error(int err);\nbool tsk_is_kas_error(int err);\nint tsk_get_kas_error(int err);\n\n/**\n@brief Return a description of the specified error.\n\nThe memory for the returned string is handled by the library and should\nnot be freed by client code.\n\n@param err A tskit error code.\n@return A description of the error.\n*/\nconst char *tsk_strerror(int err);\n\n#ifdef TSK_TRACE_ERRORS\n\nstatic inline int\n_tsk_trace_error(int err, int line, const char *file)\n{\n    fprintf(stderr, \"tskit-trace-error: %d='%s' at line %d in %s\\n\", err,\n        tsk_strerror(err), line, file);\n    return err;\n}\n\n#define tsk_trace_error(err) (_tsk_trace_error(err, __LINE__, __FILE__))\n#else\n#define tsk_trace_error(err) (err)\n#endif\n\n#ifndef TSK_BUG_ASSERT_MESSAGE\n#define TSK_BUG_ASSERT_MESSAGE                                                          \\\n    \"If you are using tskit directly please open an issue on\"                           \\\n    \" GitHub, ideally with a reproducible example.\"                                     \\\n    \" (https://github.com/tskit-dev/tskit/issues) If you are\"                           \\\n    \" using software that uses tskit, please report an issue\"                           \\\n    \" to that software's issue tracker, at least initially.\"\n#endif\n\n/**\nWe often wish to assert a condition that is unexpected, but using the normal `assert`\nmeans compiling without NDEBUG. This macro still asserts when NDEBUG is defined.\nIf you are using this macro in your own software then please set TSK_BUG_ASSERT_MESSAGE\nto point users to your issue tracker.\n*/\n#define tsk_bug_assert(condition)                                                       \\\n    do {                                                                                \\\n        if (!(condition)) {                                                             \\\n            fprintf(stderr, \"Bug detected in %s at line %d. %s\\n\", __FILE__, __LINE__,  \\\n                TSK_BUG_ASSERT_MESSAGE);                                                \\\n            abort();                                                                    \\\n        }                                                                               \\\n    } while (0)\n\nvoid __tsk_safe_free(void **ptr);\n#define tsk_safe_free(pointer) __tsk_safe_free((void **) &(pointer))\n\n#define TSK_MAX(a, b) ((a) > (b) ? (a) : (b))\n#define TSK_MIN(a, b) ((a) < (b) ? (a) : (b))\n\n/* This is a simple allocator that is optimised to efficiently allocate a\n * large number of small objects without large numbers of calls to malloc.\n * The allocator mallocs memory in chunks of a configurable size. When\n * responding to calls to get(), it will return a chunk of this memory.\n * This memory cannot be subsequently handed back to the allocator. However,\n * all memory allocated by the allocator can be returned at once by calling\n * reset.\n */\n\ntypedef struct {\n    size_t chunk_size; /* number of bytes per chunk */\n    size_t top;        /* the offset of the next available byte in the current chunk */\n    size_t current_chunk;   /* the index of the chunk currently being used */\n    size_t total_size;      /* the total number of bytes allocated + overhead. */\n    size_t total_allocated; /* the total number of bytes allocated. */\n    size_t num_chunks;      /* the number of memory chunks. */\n    char **mem_chunks;      /* the memory chunks */\n} tsk_blkalloc_t;\n\nextern void tsk_blkalloc_print_state(tsk_blkalloc_t *self, FILE *out);\nextern int tsk_blkalloc_reset(tsk_blkalloc_t *self);\nextern int tsk_blkalloc_init(tsk_blkalloc_t *self, size_t chunk_size);\nextern void *tsk_blkalloc_get(tsk_blkalloc_t *self, size_t size);\nextern void tsk_blkalloc_free(tsk_blkalloc_t *self);\n\ntypedef struct _tsk_avl_node_int_t {\n    int64_t key;\n    void *value;\n    struct _tsk_avl_node_int_t *llink;\n    struct _tsk_avl_node_int_t *rlink;\n    /* This can only contain -1, 0, 1. We could set it to a smaller type,\n     * but there's no point because of struct padding and alignment so\n     * it's simplest to keep it as a plain int. */\n    int balance;\n} tsk_avl_node_int_t;\n\ntypedef struct {\n    tsk_avl_node_int_t head;\n    tsk_size_t size;\n    tsk_size_t height;\n} tsk_avl_tree_int_t;\n\nint tsk_avl_tree_int_init(tsk_avl_tree_int_t *self);\nint tsk_avl_tree_int_free(tsk_avl_tree_int_t *self);\nvoid tsk_avl_tree_int_print_state(tsk_avl_tree_int_t *self, FILE *out);\nint tsk_avl_tree_int_insert(tsk_avl_tree_int_t *self, tsk_avl_node_int_t *node);\ntsk_avl_node_int_t *tsk_avl_tree_int_search(const tsk_avl_tree_int_t *self, int64_t key);\nint tsk_avl_tree_int_ordered_nodes(\n    const tsk_avl_tree_int_t *self, tsk_avl_node_int_t **out);\ntsk_avl_node_int_t *tsk_avl_tree_int_get_root(const tsk_avl_tree_int_t *self);\n\ntsk_size_t tsk_search_sorted(const double *array, tsk_size_t size, double value);\n\ndouble tsk_round(double x, unsigned int ndigits);\n\n/**\n@brief Check if a number is ``TSK_UNKNOWN_TIME``\n\n@rst\nUnknown time values in tskit are represented by a particular NaN value. Since NaN values\nare not equal to each other by definition, a simple comparison like\n``mutation.time == TSK_UNKNOWN_TIME`` will fail even if the mutation's time is\nTSK_UNKNOWN_TIME. This function compares the underlying bit representation of a double\nvalue and returns true iff it is equal to the specific NaN value\n:c:macro:`TSK_UNKNOWN_TIME`.\n@endrst\n\n@param val The number to check\n@return true if the number is ``TSK_UNKNOWN_TIME`` else false\n*/\nbool tsk_is_unknown_time(double val);\n\n/* We define local versions of isnan and isfinite to workaround some portability\n * issues. */\nbool tsk_isnan(double val);\nbool tsk_isfinite(double val);\n\n#define TSK_UUID_SIZE 36\nint tsk_generate_uuid(char *dest, int flags);\n\n/* TODO most of these can probably be macros so they compile out as no-ops.\n * Lets do the 64 bit tsk_size_t switch first though. */\nvoid *tsk_malloc(tsk_size_t size);\nvoid *tsk_realloc(void *ptr, tsk_size_t size);\nvoid *tsk_calloc(tsk_size_t n, size_t size);\nvoid *tsk_memset(void *ptr, int fill, tsk_size_t size);\nvoid *tsk_memcpy(void *dest, const void *src, tsk_size_t size);\nvoid *tsk_memmove(void *dest, const void *src, tsk_size_t size);\nint tsk_memcmp(const void *s1, const void *s2, tsk_size_t size);\n\n/* Developer debug utilities. These are **not** threadsafe */\nvoid tsk_set_debug_stream(FILE *f);\nFILE *tsk_get_debug_stream(void);\n\n/* Bit Array functionality */\n\n// define a 32-bit chunk size for our bitsets.\n// this means we'll be able to hold 32 distinct items in each 32 bit uint\n#define TSK_BITSET_BITS ((tsk_size_t) 32)\ntypedef uint32_t tsk_bitset_val_t;\n\ntypedef struct {\n    tsk_size_t row_len; // Number of size TSK_BITSET_BITS chunks per row\n    tsk_size_t len;     // Number of rows\n    tsk_bitset_val_t *data;\n} tsk_bitset_t;\n\nint tsk_bitset_init(tsk_bitset_t *self, tsk_size_t num_bits, tsk_size_t length);\nvoid tsk_bitset_free(tsk_bitset_t *self);\nvoid tsk_bitset_intersect(const tsk_bitset_t *self, tsk_size_t self_row,\n    const tsk_bitset_t *other, tsk_size_t other_row, tsk_bitset_t *out);\nvoid tsk_bitset_subtract(tsk_bitset_t *self, tsk_size_t self_row,\n    const tsk_bitset_t *other, tsk_size_t other_row);\nvoid tsk_bitset_union(tsk_bitset_t *self, tsk_size_t self_row, const tsk_bitset_t *other,\n    tsk_size_t other_row);\nvoid tsk_bitset_set_bit(tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit);\nbool tsk_bitset_contains(\n    const tsk_bitset_t *self, tsk_size_t row, const tsk_bitset_val_t bit);\ntsk_size_t tsk_bitset_count(const tsk_bitset_t *self, tsk_size_t row);\nvoid tsk_bitset_get_items(\n    const tsk_bitset_t *self, tsk_size_t row, tsk_id_t *items, tsk_size_t *n_items);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "treerec/tskit/genotypes.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n * Copyright (c) 2016-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <tskit/genotypes.h>\n\n/* ======================================================== *\n * Variant generator\n * ======================================================== */\n\nvoid\ntsk_variant_print_state(const tsk_variant_t *self, FILE *out)\n{\n    tsk_size_t j;\n\n    fprintf(out, \"tsk_variant state\\n\");\n    fprintf(out, \"user_alleles = %lld\\n\", (long long) self->user_alleles);\n    fprintf(out, \"num_alleles = %lld\\n\", (long long) self->num_alleles);\n    for (j = 0; j < self->num_alleles; j++) {\n        fprintf(out, \"\\tlen = %lld, '%.*s'\\n\", (long long) self->allele_lengths[j],\n            (int) self->allele_lengths[j], self->alleles[j]);\n    }\n    fprintf(out, \"num_samples = %lld\\n\", (long long) self->num_samples);\n}\n\nvoid\ntsk_vargen_print_state(const tsk_vargen_t *self, FILE *out)\n{\n    tsk_variant_print_state(&self->variant, out);\n}\n\n/* Copy the fixed allele mapping specified by the user into local\n * memory. */\nstatic int\ntsk_variant_copy_alleles(tsk_variant_t *self, const char **alleles)\n{\n    int ret = 0;\n    tsk_size_t j;\n    size_t total_len, allele_len, offset;\n\n    self->num_alleles = self->max_alleles;\n\n    total_len = 0;\n    for (j = 0; j < self->num_alleles; j++) {\n        allele_len = strlen(alleles[j]);\n        self->allele_lengths[j] = (tsk_size_t) allele_len;\n        total_len += allele_len;\n    }\n    self->user_alleles_mem = tsk_malloc(total_len * sizeof(char *));\n    if (self->user_alleles_mem == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    offset = 0;\n    for (j = 0; j < self->num_alleles; j++) {\n        strcpy(self->user_alleles_mem + offset, alleles[j]);\n        self->alleles[j] = self->user_alleles_mem + offset;\n        offset += (size_t) self->allele_lengths[j];\n    }\nout:\n    return ret;\n}\n\nstatic int\nvariant_init_samples_and_index_map(tsk_variant_t *self,\n    const tsk_treeseq_t *tree_sequence, const tsk_id_t *samples, tsk_size_t num_samples,\n    size_t num_samples_alloc, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_size_t j, num_nodes;\n    tsk_id_t u;\n\n    num_nodes = tsk_treeseq_get_num_nodes(tree_sequence);\n    self->alt_samples = tsk_malloc(num_samples_alloc * sizeof(*samples));\n    self->alt_sample_index_map\n        = tsk_malloc(num_nodes * sizeof(*self->alt_sample_index_map));\n    if (self->alt_samples == NULL || self->alt_sample_index_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memcpy(self->alt_samples, samples, num_samples * sizeof(*samples));\n    tsk_memset(self->alt_sample_index_map, 0xff,\n        num_nodes * sizeof(*self->alt_sample_index_map));\n    /* Create the reverse mapping */\n    for (j = 0; j < num_samples; j++) {\n        u = samples[j];\n        if (u < 0 || u >= (tsk_id_t) num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (self->alt_sample_index_map[u] != TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        self->alt_sample_index_map[samples[j]] = (tsk_id_t) j;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_variant_init(tsk_variant_t *self, const tsk_treeseq_t *tree_sequence,\n    const tsk_id_t *samples, tsk_size_t num_samples, const char **alleles,\n    tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t max_alleles_limit, max_alleles;\n    tsk_size_t num_samples_alloc;\n\n    tsk_memset(self, 0, sizeof(tsk_variant_t));\n\n    /* Set site id to NULL to indicate the variant is not decoded */\n    self->site.id = TSK_NULL;\n\n    self->tree_sequence = tree_sequence;\n    ret = tsk_tree_init(\n        &self->tree, tree_sequence, samples == NULL ? TSK_SAMPLE_LISTS : 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (samples != NULL) {\n        /* Take a copy of the samples so we don't have to manage the lifecycle*/\n        self->samples = tsk_malloc(num_samples * sizeof(*samples));\n        if (self->samples == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        tsk_memcpy(self->samples, samples, num_samples * sizeof(*samples));\n        self->num_samples = num_samples;\n    }\n\n    self->options = options;\n\n    max_alleles_limit = INT32_MAX;\n\n    if (alleles == NULL) {\n        self->user_alleles = false;\n        max_alleles = 4; /* Arbitrary --- we'll rarely have more than this */\n    } else {\n        self->user_alleles = true;\n        /* Count the input alleles. The end is designated by the NULL sentinel. */\n        for (max_alleles = 0; alleles[max_alleles] != NULL; max_alleles++)\n            ;\n        if (max_alleles > max_alleles_limit) {\n            ret = tsk_trace_error(TSK_ERR_TOO_MANY_ALLELES);\n            goto out;\n        }\n        if (max_alleles == 0) {\n            ret = tsk_trace_error(TSK_ERR_ZERO_ALLELES);\n            goto out;\n        }\n    }\n    self->max_alleles = max_alleles;\n    self->alleles = tsk_calloc(max_alleles, sizeof(*self->alleles));\n    self->allele_lengths = tsk_malloc(max_alleles * sizeof(*self->allele_lengths));\n    if (self->alleles == NULL || self->allele_lengths == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (self->user_alleles) {\n        ret = tsk_variant_copy_alleles(self, alleles);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (self->samples == NULL) {\n        self->num_samples = tsk_treeseq_get_num_samples(tree_sequence);\n        self->samples = tsk_malloc(self->num_samples * sizeof(*self->samples));\n        if (self->samples == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        tsk_memcpy(self->samples, tsk_treeseq_get_samples(tree_sequence),\n            self->num_samples * sizeof(*self->samples));\n\n        self->sample_index_map = tsk_treeseq_get_sample_index_map(tree_sequence);\n        num_samples_alloc = self->num_samples;\n    } else {\n        num_samples_alloc = self->num_samples;\n        ret = variant_init_samples_and_index_map(self, tree_sequence, self->samples,\n            self->num_samples, (size_t) num_samples_alloc, self->options);\n        if (ret != 0) {\n            goto out;\n        }\n        self->sample_index_map = self->alt_sample_index_map;\n    }\n    /* When a list of samples is given, we use the traversal based algorithm\n     * which doesn't use sample list tracking in the tree */\n    if (self->alt_samples != NULL) {\n        self->traversal_stack = tsk_malloc(\n            tsk_treeseq_get_num_nodes(tree_sequence) * sizeof(*self->traversal_stack));\n        if (self->traversal_stack == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    self->genotypes = tsk_malloc(num_samples_alloc * sizeof(*self->genotypes));\n    if (self->genotypes == NULL || self->alleles == NULL\n        || self->allele_lengths == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\nout:\n    return ret;\n}\n\nint\ntsk_vargen_init(tsk_vargen_t *self, const tsk_treeseq_t *tree_sequence,\n    const tsk_id_t *samples, tsk_size_t num_samples, const char **alleles,\n    tsk_flags_t options)\n{\n    int ret = 0;\n\n    tsk_bug_assert(tree_sequence != NULL);\n    tsk_memset(self, 0, sizeof(tsk_vargen_t));\n\n    self->tree_sequence = tree_sequence;\n    ret = tsk_variant_init(\n        &self->variant, tree_sequence, samples, num_samples, alleles, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nint\ntsk_variant_free(tsk_variant_t *self)\n{\n    if (self->tree_sequence != NULL) {\n        tsk_tree_free(&self->tree);\n    }\n    tsk_safe_free(self->genotypes);\n    tsk_safe_free(self->alleles);\n    tsk_safe_free(self->allele_lengths);\n    tsk_safe_free(self->user_alleles_mem);\n    tsk_safe_free(self->samples);\n    tsk_safe_free(self->alt_samples);\n    tsk_safe_free(self->alt_sample_index_map);\n    tsk_safe_free(self->traversal_stack);\n    return 0;\n}\n\nint\ntsk_vargen_free(tsk_vargen_t *self)\n{\n    tsk_variant_free(&self->variant);\n    return 0;\n}\n\nstatic int\ntsk_variant_expand_alleles(tsk_variant_t *self)\n{\n    int ret = 0;\n    void *p;\n    tsk_size_t hard_limit = INT32_MAX;\n\n    if (self->max_alleles == hard_limit) {\n        ret = tsk_trace_error(TSK_ERR_TOO_MANY_ALLELES);\n        goto out;\n    }\n    self->max_alleles = TSK_MIN(hard_limit, self->max_alleles * 2);\n    p = tsk_realloc(self->alleles, self->max_alleles * sizeof(*self->alleles));\n    if (p == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    self->alleles = p;\n    p = tsk_realloc(\n        self->allele_lengths, self->max_alleles * sizeof(*self->allele_lengths));\n    if (p == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    self->allele_lengths = p;\nout:\n    return ret;\n}\n\n/* The following pair of functions are identical except one handles 8 bit\n * genotypes and the other handles 16 bit genotypes. This is done for performance\n * reasons as this is a key function and for common alleles can entail\n * iterating over millions of samples. The compiler hints are included for the\n * same reason.\n */\nstatic int TSK_WARN_UNUSED\ntsk_variant_update_genotypes_sample_list(\n    tsk_variant_t *self, tsk_id_t node, tsk_id_t derived)\n{\n    int32_t *restrict genotypes = self->genotypes;\n    const tsk_id_t *restrict list_left = self->tree.left_sample;\n    const tsk_id_t *restrict list_right = self->tree.right_sample;\n    const tsk_id_t *restrict list_next = self->tree.next_sample;\n    tsk_id_t index, stop;\n    int ret = 0;\n\n    tsk_bug_assert(derived < INT32_MAX);\n\n    index = list_left[node];\n    if (index != TSK_NULL) {\n        stop = list_right[node];\n        while (true) {\n\n            ret += genotypes[index] == TSK_MISSING_DATA;\n            genotypes[index] = (int32_t) derived;\n            if (index == stop) {\n                break;\n            }\n            index = list_next[index];\n        }\n    }\n\n    return ret;\n}\n\n/* The following functions implement the genotype setting by traversing\n * down the tree to the samples. We're not so worried about performance here\n * because this should only be used when we have a very small number of samples,\n * and so we use a visit function to avoid duplicating code.\n */\n\ntypedef int (*visit_func_t)(tsk_variant_t *, tsk_id_t, tsk_id_t);\n\nstatic int TSK_WARN_UNUSED\ntsk_variant_traverse(\n    tsk_variant_t *self, tsk_id_t node, tsk_id_t derived, visit_func_t visit)\n{\n    int ret = 0;\n    tsk_id_t *restrict stack = self->traversal_stack;\n    const tsk_id_t *restrict left_child = self->tree.left_child;\n    const tsk_id_t *restrict right_sib = self->tree.right_sib;\n    const tsk_id_t *restrict sample_index_map = self->sample_index_map;\n    tsk_id_t u, v, sample_index;\n    int stack_top;\n    int no_longer_missing = 0;\n\n    stack_top = 0;\n    stack[0] = node;\n    while (stack_top >= 0) {\n        u = stack[stack_top];\n        sample_index = sample_index_map[u];\n        if (sample_index != TSK_NULL) {\n            ret = visit(self, sample_index, derived);\n            if (ret < 0) {\n                goto out;\n            }\n            no_longer_missing += ret;\n        }\n        stack_top--;\n        for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n            stack_top++;\n            stack[stack_top] = v;\n        }\n    }\n    ret = no_longer_missing;\nout:\n    return ret;\n}\n\nstatic int\ntsk_variant_visit(tsk_variant_t *self, tsk_id_t sample_index, tsk_id_t derived)\n{\n    int ret = 0;\n    int32_t *restrict genotypes = self->genotypes;\n\n    tsk_bug_assert(derived < INT32_MAX);\n    tsk_bug_assert(sample_index != -1);\n\n    ret = genotypes[sample_index] == TSK_MISSING_DATA;\n    genotypes[sample_index] = (int32_t) derived;\n\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_variant_update_genotypes_traversal(\n    tsk_variant_t *self, tsk_id_t node, tsk_id_t derived)\n{\n    return tsk_variant_traverse(self, node, derived, tsk_variant_visit);\n}\n\nstatic tsk_size_t\ntsk_variant_mark_missing(tsk_variant_t *self)\n{\n    tsk_size_t num_missing = 0;\n    const tsk_id_t *restrict left_child = self->tree.left_child;\n    const tsk_id_t *restrict right_sib = self->tree.right_sib;\n    const tsk_id_t *restrict sample_index_map = self->sample_index_map;\n    const tsk_id_t N = self->tree.virtual_root;\n    int32_t *restrict genotypes = self->genotypes;\n    tsk_id_t root, sample_index;\n\n    for (root = left_child[N]; root != TSK_NULL; root = right_sib[root]) {\n        if (left_child[root] == TSK_NULL) {\n            sample_index = sample_index_map[root];\n            if (sample_index != TSK_NULL) {\n                genotypes[sample_index] = TSK_MISSING_DATA;\n                num_missing++;\n            }\n        }\n    }\n    return num_missing;\n}\n\n/* Mark missing for any requested node (sample or non-sample) that is isolated\n * in the current tree, i.e., has no parent and no children at this position. */\nstatic tsk_size_t\ntsk_variant_mark_missing_any(tsk_variant_t *self)\n{\n    tsk_size_t num_missing = 0;\n    int32_t *restrict genotypes = self->genotypes;\n    const tsk_id_t *restrict parent = self->tree.parent;\n    const tsk_id_t *restrict left_child = self->tree.left_child;\n    tsk_size_t j;\n\n    for (j = 0; j < self->num_samples; j++) {\n        tsk_id_t u = self->samples[j];\n        if (parent[u] == TSK_NULL && left_child[u] == TSK_NULL) {\n            genotypes[j] = TSK_MISSING_DATA;\n            num_missing++;\n        }\n    }\n    return num_missing;\n}\n\nstatic tsk_id_t\ntsk_variant_get_allele_index(tsk_variant_t *self, const char *allele, tsk_size_t length)\n{\n    tsk_id_t ret = -1;\n    tsk_size_t j;\n\n    for (j = 0; j < self->num_alleles; j++) {\n        if (length == self->allele_lengths[j]\n            && tsk_memcmp(allele, self->alleles[j], length) == 0) {\n            ret = (tsk_id_t) j;\n            break;\n        }\n    }\n    return ret;\n}\n\nint\ntsk_variant_decode(\n    tsk_variant_t *self, tsk_id_t site_id, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t allele_index;\n    tsk_size_t j, num_missing;\n    int no_longer_missing;\n    tsk_mutation_t mutation;\n    bool impute_missing = !!(self->options & TSK_ISOLATED_NOT_MISSING);\n    bool by_traversal = self->alt_samples != NULL;\n    int (*update_genotypes)(tsk_variant_t *, tsk_id_t, tsk_id_t);\n    tsk_size_t (*mark_missing)(tsk_variant_t *);\n\n    if (self->tree_sequence == NULL) {\n        ret = tsk_trace_error(TSK_ERR_VARIANT_CANT_DECODE_COPY);\n        goto out;\n    }\n\n    ret = tsk_treeseq_get_site(self->tree_sequence, site_id, &self->site);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_tree_seek(&self->tree, self->site.position, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* When we have no specified samples we need sample lists to be active\n     * on the tree, as indicated by the presence of left_sample */\n    if (!by_traversal && self->tree.left_sample == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_SAMPLE_LISTS);\n        goto out;\n    }\n\n    /* For now we use a traversal method to find genotypes when we have a\n     * specified set of samples, but we should provide the option to do it\n     * via tracked_samples in the tree also. There will be a tradeoff: if\n     * we only have a small number of samples, it's probably better to\n     * do it by traversal. For large sets of samples though, it may be\n     * better to use the sample list infrastructure. */\n\n    mark_missing = tsk_variant_mark_missing;\n    update_genotypes = tsk_variant_update_genotypes_sample_list;\n    if (by_traversal) {\n        update_genotypes = tsk_variant_update_genotypes_traversal;\n        /* When decoding a user-provided list of nodes (which may include\n         * non-samples), mark isolated nodes as missing directly by checking\n         * isolation status for each requested node. */\n        mark_missing = tsk_variant_mark_missing_any;\n    }\n\n    if (self->user_alleles) {\n        allele_index = tsk_variant_get_allele_index(\n            self, self->site.ancestral_state, self->site.ancestral_state_length);\n        if (allele_index == -1) {\n            ret = tsk_trace_error(TSK_ERR_ALLELE_NOT_FOUND);\n            goto out;\n        }\n    } else {\n        /* Ancestral state is always allele 0 */\n        self->alleles[0] = self->site.ancestral_state;\n        self->allele_lengths[0] = self->site.ancestral_state_length;\n        self->num_alleles = 1;\n        allele_index = 0;\n    }\n\n    /* The algorithm for generating the allelic state of every sample works by\n     * examining each mutation in order, and setting the state for all the\n     * samples under the mutation's node. For complex sites where there is\n     * more than one mutation, we depend on the ordering of mutations being\n     * correct. Specifically, any mutation that is above another mutation in\n     * the tree must be visited first. This is enforced using the mutation.parent\n     * field, where we require that a mutation's parent must appear before it\n     * in the list of mutations. This guarantees the correctness of this algorithm.\n     */\n    for (j = 0; j < self->num_samples; j++) {\n        self->genotypes[j] = (int32_t) allele_index;\n    }\n\n    /* We mark missing data *before* updating the genotypes because\n     * mutations directly over samples should not be missing */\n    num_missing = 0;\n    if (!impute_missing) {\n        num_missing = mark_missing(self);\n    }\n    for (j = 0; j < self->site.mutations_length; j++) {\n        mutation = self->site.mutations[j];\n        /* Compute the allele index for this derived state value. */\n        allele_index = tsk_variant_get_allele_index(\n            self, mutation.derived_state, mutation.derived_state_length);\n        if (allele_index == -1) {\n            if (self->user_alleles) {\n                ret = tsk_trace_error(TSK_ERR_ALLELE_NOT_FOUND);\n                goto out;\n            }\n            if (self->num_alleles == self->max_alleles) {\n                ret = tsk_variant_expand_alleles(self);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n            allele_index = (tsk_id_t) self->num_alleles;\n            self->alleles[allele_index] = mutation.derived_state;\n            self->allele_lengths[allele_index] = mutation.derived_state_length;\n            self->num_alleles++;\n        }\n\n        no_longer_missing = update_genotypes(self, mutation.node, allele_index);\n        if (no_longer_missing < 0) {\n            ret = no_longer_missing;\n            goto out;\n        }\n        /* Update genotypes returns the number of missing values marked\n         * not-missing */\n        num_missing -= (tsk_size_t) no_longer_missing;\n    }\n    self->has_missing_data = num_missing > 0;\nout:\n    return ret;\n}\n\nint\ntsk_variant_restricted_copy(const tsk_variant_t *self, tsk_variant_t *other)\n{\n    int ret = 0;\n    tsk_size_t total_len, offset, j;\n\n    /* Copy everything */\n    tsk_memcpy(other, self, sizeof(*other));\n    /* Tree sequence left as NULL and zero'd tree is a way of indicating this variant is\n     * fixed and cannot be further decoded. */\n    other->tree_sequence = NULL;\n    tsk_memset(&other->tree, sizeof(other->tree), 0);\n    other->traversal_stack = NULL;\n    other->samples = NULL;\n    other->sample_index_map = NULL;\n    other->alt_samples = NULL;\n    other->alt_sample_index_map = NULL;\n    other->user_alleles_mem = NULL;\n\n    total_len = 0;\n    for (j = 0; j < self->num_alleles; j++) {\n        total_len += self->allele_lengths[j];\n    }\n    other->samples = tsk_malloc(other->num_samples * sizeof(*other->samples));\n    other->genotypes = tsk_malloc(other->num_samples * sizeof(*other->genotypes));\n    other->user_alleles_mem = tsk_malloc(total_len * sizeof(*other->user_alleles_mem));\n    other->allele_lengths\n        = tsk_malloc(other->num_alleles * sizeof(*other->allele_lengths));\n    other->alleles = tsk_malloc(other->num_alleles * sizeof(*other->alleles));\n    if (other->samples == NULL || other->genotypes == NULL\n        || other->user_alleles_mem == NULL || other->allele_lengths == NULL\n        || other->alleles == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memcpy(\n        other->samples, self->samples, other->num_samples * sizeof(*other->samples));\n    tsk_memcpy(other->genotypes, self->genotypes,\n        other->num_samples * sizeof(*other->genotypes));\n    tsk_memcpy(other->allele_lengths, self->allele_lengths,\n        other->num_alleles * sizeof(*other->allele_lengths));\n    offset = 0;\n    for (j = 0; j < other->num_alleles; j++) {\n        tsk_memcpy(other->user_alleles_mem + offset, self->alleles[j],\n            other->allele_lengths[j] * sizeof(*other->user_alleles_mem));\n        other->alleles[j] = other->user_alleles_mem + offset;\n        offset += other->allele_lengths[j];\n    }\n\nout:\n    return ret;\n}\n\nint\ntsk_vargen_next(tsk_vargen_t *self, tsk_variant_t **variant)\n{\n    int ret = 0;\n\n    if ((tsk_size_t) self->site_index < tsk_treeseq_get_num_sites(self->tree_sequence)) {\n        ret = tsk_variant_decode(&self->variant, self->site_index, 0);\n        if (ret != 0) {\n            goto out;\n        }\n        self->site_index++;\n        *variant = &self->variant;\n        ret = 1;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_treeseq_decode_alignments_overlay_missing(const tsk_treeseq_t *self,\n    const tsk_id_t *nodes, tsk_size_t num_nodes, double left, double right,\n    char missing_data_character, tsk_size_t L, char *alignments_out)\n{\n    int ret = 0;\n    tsk_tree_t tree;\n    tsk_size_t i, seg_left, seg_right;\n    char *row = NULL;\n    tsk_id_t u;\n\n    tsk_memset(&tree, 0, sizeof(tree));\n\n    ret = tsk_tree_init(&tree, self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_seek(&tree, left, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    while (tree.index != -1 && tree.interval.left < right) {\n        seg_left = TSK_MAX((tsk_size_t) tree.interval.left, (tsk_size_t) left);\n        seg_right = TSK_MIN((tsk_size_t) tree.interval.right, (tsk_size_t) right);\n        if (seg_right > seg_left) {\n            for (i = 0; i < num_nodes; i++) {\n                u = nodes[i];\n                if (tree.parent[u] == TSK_NULL && tree.left_child[u] == TSK_NULL) {\n                    row = alignments_out + i * L;\n                    /* memset takes an `int`, `missing_data_character` is a `char` which\n                     * can be signed or unsigned depending on the platform, so we need to\n                     * cast. Some tools/compilers will warn if we just cast\n                     * to `unsigned char` and leave the cast to `int` as implicit, hence\n                     * the double cast. */\n                    tsk_memset(row + (seg_left - (tsk_size_t) left),\n                        (int) (unsigned char) missing_data_character,\n                        seg_right - seg_left);\n                }\n            }\n        }\n        ret = tsk_tree_next(&tree);\n        if (ret < 0) {\n            goto out;\n        }\n    }\n\n    /* On success we should return 0, not TSK_TREE_OK from the last tsk_tree_next */\n    ret = 0;\nout:\n    tsk_tree_free(&tree);\n    return ret;\n}\n\nstatic int\ntsk_treeseq_decode_alignments_overlay_sites(const tsk_treeseq_t *self,\n    const tsk_id_t *nodes, tsk_size_t num_nodes, double left, double right,\n    char missing_data_character, tsk_size_t L, char *alignments_out, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_variant_t var;\n    tsk_id_t site_id;\n    tsk_site_t site;\n    char *allele_byte = NULL;\n    tsk_size_t allele_cap = 0;\n    tsk_size_t i, j;\n    char *row = NULL;\n    int32_t g;\n    char c;\n    char *tmp = NULL;\n\n    tsk_memset(&var, 0, sizeof(var));\n\n    ret = tsk_variant_init(&var, self, nodes, num_nodes, NULL, options);\n    if (ret != 0) {\n        goto out;\n    }\n    for (site_id = 0; site_id < (tsk_id_t) tsk_treeseq_get_num_sites(self); site_id++) {\n        ret = tsk_treeseq_get_site(self, site_id, &site);\n        if (ret != 0) {\n            goto out;\n        }\n        if (site.position < left) {\n            continue;\n        }\n        if (site.position >= right) {\n            break;\n        }\n        ret = tsk_variant_decode(&var, site_id, 0);\n        if (ret != 0) {\n            goto out;\n        }\n        if (var.num_alleles > 0) {\n            if (var.num_alleles > allele_cap) {\n                tmp = tsk_realloc(allele_byte, var.num_alleles * sizeof(*allele_byte));\n                if (tmp == NULL) {\n                    ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                    goto out;\n                }\n                allele_byte = tmp;\n                allele_cap = var.num_alleles;\n            }\n            for (j = 0; j < var.num_alleles; j++) {\n                if (var.allele_lengths[j] != 1) {\n                    ret = tsk_trace_error(TSK_ERR_BAD_ALLELE_LENGTH);\n                    goto out;\n                }\n                allele_byte[j] = var.alleles[j][0];\n                if (allele_byte[j] == missing_data_character) {\n                    ret = tsk_trace_error(TSK_ERR_MISSING_CHAR_COLLISION);\n                    goto out;\n                }\n            }\n            for (i = 0; i < num_nodes; i++) {\n                row = alignments_out + i * L;\n                g = var.genotypes[i];\n                c = missing_data_character;\n                if (g != TSK_MISSING_DATA) {\n                    tsk_bug_assert(g >= 0);\n                    tsk_bug_assert((tsk_size_t) g < var.num_alleles);\n                    c = allele_byte[g];\n                }\n                row[((tsk_size_t) site.position) - (tsk_size_t) left] = (char) c;\n            }\n        }\n    }\n\nout:\n    tsk_safe_free(allele_byte);\n    tsk_variant_free(&var);\n    return ret;\n}\n\n/* NOTE: We usually keep functions with a tsk_treeseq_t signature in trees.c.\n * tsk_treeseq_decode_alignments is implemented here instead because it\n * depends directly on tsk_variant_t and the genotype/allele machinery in\n * this file (and thus on genotypes.h). This slightly breaks that layering\n * convention but keeps the implementation close to the variant code. */\nint\ntsk_treeseq_decode_alignments(const tsk_treeseq_t *self, const char *ref_seq,\n    tsk_size_t ref_seq_length, const tsk_id_t *nodes, tsk_size_t num_nodes, double left,\n    double right, char missing_data_character, char *alignments_out, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t i, L;\n    char *row = NULL;\n\n    if (!tsk_treeseq_get_discrete_genome(self)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (ref_seq == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (ref_seq_length != (tsk_size_t) tsk_treeseq_get_sequence_length(self)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (trunc(left) != left || trunc(right) != right) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (left < 0 || right > tsk_treeseq_get_sequence_length(self)\n        || (tsk_size_t) left >= (tsk_size_t) right) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    L = (tsk_size_t) right - (tsk_size_t) left;\n    if (num_nodes == 0) {\n        return 0;\n    }\n    if (nodes == NULL || alignments_out == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    for (i = 0; i < num_nodes; i++) {\n        if (nodes[i] < 0 || nodes[i] >= (tsk_id_t) tsk_treeseq_get_num_nodes(self)) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n    }\n\n    /* Fill rows with the reference slice */\n    for (i = 0; i < num_nodes; i++) {\n        row = alignments_out + i * L;\n        tsk_memcpy(row, ref_seq + (tsk_size_t) left, L);\n    }\n    if (!(options & TSK_ISOLATED_NOT_MISSING)) {\n        ret = tsk_treeseq_decode_alignments_overlay_missing(self, nodes, num_nodes, left,\n            right, missing_data_character, L, alignments_out);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_treeseq_decode_alignments_overlay_sites(self, nodes, num_nodes, left,\n        right, missing_data_character, L, alignments_out, options);\n    if (ret != 0) {\n        goto out;\n    }\n\nout:\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/genotypes.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2022 Tskit Developers\n * Copyright (c) 2016-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef TSK_GENOTYPES_H\n#define TSK_GENOTYPES_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <tskit/trees.h>\n\n#define TSK_ISOLATED_NOT_MISSING (1 << 1)\n\n/**\n@brief A variant at a specific site.\n\n@rst\nUsed to generate the genotypes for a given set of samples at a given\nsite.\n@endrst\n*/\ntypedef struct {\n    /** @brief Unowned reference to the tree sequence of the variant */\n    const tsk_treeseq_t *tree_sequence;\n    /** @brief The site this variant is currently decoded at*/\n    tsk_site_t site;\n    tsk_tree_t tree;\n    /** @brief Array of allele strings that the genotypes of the variant refer to\n     *  These are not NULL terminated - use `allele_lengths` for example:.\n     *  `printf(\"%.*s\", (int) var->allele_lengths[j], var->alleles[j]);`\n     */\n    const char **alleles;\n    /** @brief Lengths of the allele strings */\n    tsk_size_t *allele_lengths;\n    /** @brief Length of the allele array */\n    tsk_size_t num_alleles;\n    tsk_size_t max_alleles;\n    /** @brief If True the genotypes of isolated nodes have been decoded to the \"missing\"\n     * genotype. If False they are set to the ancestral state (in the absence of\n     * mutations above them)*/\n    bool has_missing_data;\n    /** @brief Array of genotypes for the current site */\n    int32_t *genotypes;\n    /** @brief Number of samples */\n    tsk_size_t num_samples;\n    /** @brief Array of sample ids used*/\n    tsk_id_t *samples;\n\n    const tsk_id_t *sample_index_map;\n    bool user_alleles;\n    char *user_alleles_mem;\n    tsk_id_t *traversal_stack;\n    tsk_flags_t options;\n    tsk_id_t *alt_samples;\n    tsk_id_t *alt_sample_index_map;\n\n} tsk_variant_t;\n\n/* All vargen related structs and methods were deprecated in C API v1.0 */\ntypedef struct {\n    const tsk_treeseq_t *tree_sequence;\n    tsk_id_t site_index;\n    tsk_variant_t variant;\n} tsk_vargen_t;\n\n/**\n@defgroup VARIANT_API_GROUP Variant API for obtaining genotypes.\n@{\n*/\n\n/**\n@brief Initialises the variant by allocating the internal memory\n\n@rst\nThis must be called before any operations are performed on the variant.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_variant_t object.\n@param tree_sequence A pointer to the tree sequence from which this variant\nwill decode genotypes. No copy is taken, so this tree sequence must persist\nfor the lifetime of the variant.\n@param samples Optional. Either `NULL` or an array of node ids of the samples that are to\nhave their genotypes decoded. A copy of this array will be taken by the variant. If\n`NULL` then the samples from the tree sequence will be used.\n@param num_samples The number of ids in the samples array, ignored if `samples` is `NULL`\n@param alleles Optional. Either ``NULL`` or an array of string alleles with a terminal\n``NULL`` sentinel value.\nIf specified, the genotypes will be decoded to match the index in this allele array.\nIf ``NULL`` then alleles will be automatically determined from the mutations encountered.\n@param options Variant options. Either ``0`` or ``TSK_ISOLATED_NOT_MISSING`` which\nif specified indicates that isolated sample nodes should not be decoded as the \"missing\"\nstate but as the ancestral state (or the state of any mutation above them).\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_variant_init(tsk_variant_t *self, const tsk_treeseq_t *tree_sequence,\n    const tsk_id_t *samples, tsk_size_t num_samples, const char **alleles,\n    tsk_flags_t options);\n\n/**\n@brief Copies the state of this variant to another variant\n\n@rst\nCopies the site, genotypes and alleles from this variant to another. Note that\nthe other variant should be uninitialised as this method does not free any\nmemory that the other variant owns. After copying `other` is frozen and\nthis restricts it from being further decoded at any site. `self` remains unchanged.\n@endrst\n\n@param self A pointer to an initialised and decoded tsk_variant_t object.\n@param other A pointer to an uninitialised tsk_variant_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_variant_restricted_copy(const tsk_variant_t *self, tsk_variant_t *other);\n\n/**\n@brief Decode the genotypes at the given site, storing them in this variant.\n\n@rst\nDecodes the genotypes for this variant's samples, indexed to this variant's alleles,\nat the specified site.\nThis method is most efficient at decoding sites in-order, either forwards or backwards\nalong the tree sequence. Resulting genotypes are stored in the ``genotypes`` member of\nthis variant.\n@endrst\n\n@param self A pointer to an initialised tsk_variant_t object.\n@param site_id A valid site id for the tree sequence of this variant.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of `tskit`.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_variant_decode(tsk_variant_t *self, tsk_id_t site_id, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified variant.\n\n@param self A pointer to an initialised tsk_variant_t object.\n@return Always returns 0.\n*/\nint tsk_variant_free(tsk_variant_t *self);\n\n/**\n@brief Print out the state of this variant to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_variant_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_variant_print_state(const tsk_variant_t *self, FILE *out);\n\n/** @} */\n\n/* Deprecated vargen methods (since C API v1.0) */\nint tsk_vargen_init(tsk_vargen_t *self, const tsk_treeseq_t *tree_sequence,\n    const tsk_id_t *samples, tsk_size_t num_samples, const char **alleles,\n    tsk_flags_t options);\nint tsk_vargen_next(tsk_vargen_t *self, tsk_variant_t **variant);\nint tsk_vargen_free(tsk_vargen_t *self);\nvoid tsk_vargen_print_state(const tsk_vargen_t *self, FILE *out);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/haplotype_matching.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <math.h>\n#include <float.h>\n#include <assert.h>\n\n#include <tskit/haplotype_matching.h>\n\n#define MAX_PARSIMONY_WORDS 256\n\nconst char *_zero_one_alleles[] = { \"0\", \"1\", NULL };\nconst char *_acgt_alleles[] = { \"A\", \"C\", \"G\", \"T\", NULL };\n\nstatic int\ncmp_double(const void *a, const void *b)\n{\n    const double *ia = (const double *) a;\n    const double *ib = (const double *) b;\n    return (*ia > *ib) - (*ia < *ib);\n}\n\nstatic int\ncmp_argsort(const void *a, const void *b)\n{\n    const tsk_argsort_t *ia = (const tsk_argsort_t *) a;\n    const tsk_argsort_t *ib = (const tsk_argsort_t *) b;\n    int ret = (ia->value > ib->value) - (ia->value < ib->value);\n    /* Break any ties using the index to ensure consistency */\n    if (ret == 0) {\n        ret = (ia->index > ib->index) - (ia->index < ib->index);\n    }\n    return ret;\n}\n\nstatic void\ntsk_ls_hmm_check_state(tsk_ls_hmm_t *self)\n{\n    tsk_id_t *T_index = self->transition_index;\n    tsk_value_transition_t *T = self->transitions;\n    tsk_id_t j;\n\n    for (j = 0; j < (tsk_id_t) self->num_transitions; j++) {\n        if (T[j].tree_node != TSK_NULL) {\n            tsk_bug_assert(T_index[T[j].tree_node] == j);\n        }\n    }\n    /* tsk_bug_assert(self->num_transitions <= self->num_samples); */\n\n    if (self->num_transitions > 0) {\n        for (j = 0; j < (tsk_id_t) self->num_nodes; j++) {\n            if (T_index[j] != TSK_NULL) {\n                tsk_bug_assert(T[T_index[j]].tree_node == j);\n            }\n            tsk_bug_assert(self->tree.parent[j] == self->parent[j]);\n        }\n    }\n}\n\nvoid\ntsk_ls_hmm_print_state(tsk_ls_hmm_t *self, FILE *out)\n{\n    tsk_size_t j, l;\n\n    fprintf(out, \"tree_sequence   = %p\\n\", (void *) self->tree_sequence);\n    fprintf(out, \"num_sites       = %lld\\n\", (long long) self->num_sites);\n    fprintf(out, \"num_samples     = %lld\\n\", (long long) self->num_samples);\n    fprintf(out, \"num_values      = %lld\\n\", (long long) self->num_values);\n    fprintf(out, \"max_values      = %lld\\n\", (long long) self->max_values);\n    fprintf(out, \"num_optimal_value_set_words = %lld\\n\",\n        (long long) self->num_optimal_value_set_words);\n\n    fprintf(out, \"sites::\\n\");\n    for (l = 0; l < self->num_sites; l++) {\n        fprintf(out, \"%lld\\t%lld\\t[\", (long long) l, (long long) self->num_alleles[l]);\n        for (j = 0; j < self->num_alleles[l]; j++) {\n            fprintf(out, \"%s,\", self->alleles[l][j]);\n        }\n        fprintf(out, \"]\\n\");\n    }\n    fprintf(out, \"transitions::%lld\\n\", (long long) self->num_transitions);\n    for (j = 0; j < self->num_transitions; j++) {\n        fprintf(out, \"tree_node=%lld\\tvalue=%.14f\\tvalue_index=%lld\\n\",\n            (long long) self->transitions[j].tree_node, self->transitions[j].value,\n            (long long) self->transitions[j].value_index);\n    }\n    if (self->num_transitions > 0) {\n        fprintf(out, \"tree::%lld\\n\", (long long) self->num_nodes);\n        for (j = 0; j < self->num_nodes; j++) {\n            fprintf(out, \"%lld\\tparent=%lld\\ttransition=%lld\\n\", (long long) j,\n                (long long) self->parent[j], (long long) self->transition_index[j]);\n        }\n    }\n    tsk_ls_hmm_check_state(self);\n}\n\nint TSK_WARN_UNUSED\ntsk_ls_hmm_init(tsk_ls_hmm_t *self, tsk_treeseq_t *tree_sequence,\n    double *recombination_rate, double *mutation_rate, tsk_flags_t options)\n{\n    int ret = TSK_ERR_GENERIC;\n    tsk_size_t l;\n\n    tsk_memset(self, 0, sizeof(tsk_ls_hmm_t));\n    self->tree_sequence = tree_sequence;\n    self->precision = 6; /* Seems like a safe value, but probably not ideal for perf */\n    self->num_sites = tsk_treeseq_get_num_sites(tree_sequence);\n    self->num_samples = tsk_treeseq_get_num_samples(tree_sequence);\n    self->num_alleles = tsk_malloc(self->num_sites * sizeof(*self->num_alleles));\n    self->num_nodes = tsk_treeseq_get_num_nodes(tree_sequence);\n    self->parent = tsk_malloc(self->num_nodes * sizeof(*self->parent));\n    self->allelic_state = tsk_malloc(self->num_nodes * sizeof(*self->allelic_state));\n    self->transition_index\n        = tsk_malloc(self->num_nodes * sizeof(*self->transition_index));\n    self->transition_stack\n        = tsk_malloc(self->num_nodes * sizeof(*self->transition_stack));\n    /* We can't have more than 2 * num_samples transitions, so we use this as the\n     * upper bound. Because of the implementation, we'll also have to worry about\n     * the extra mutations at the first site, which in worst case involves all\n     * mutations. We can definitely save some memory here if we want to.*/\n    self->max_transitions\n        = 2 * self->num_samples + tsk_treeseq_get_num_mutations(tree_sequence);\n    /* FIXME Arbitrarily doubling this after hitting problems */\n    self->max_transitions *= 2;\n    self->transitions = tsk_malloc(self->max_transitions * sizeof(*self->transitions));\n    self->transitions_copy\n        = tsk_malloc(self->max_transitions * sizeof(*self->transitions));\n    self->num_transition_samples\n        = tsk_malloc(self->max_transitions * sizeof(*self->num_transition_samples));\n    self->transition_parent\n        = tsk_malloc(self->max_transitions * sizeof(*self->transition_parent));\n    self->transition_time_order\n        = tsk_malloc(self->max_transitions * sizeof(*self->transition_time_order));\n    self->values = tsk_malloc(self->max_transitions * sizeof(*self->values));\n    self->recombination_rate\n        = tsk_malloc(self->num_sites * sizeof(*self->recombination_rate));\n    self->mutation_rate = tsk_malloc(self->num_sites * sizeof(*self->mutation_rate));\n    self->alleles = tsk_calloc(self->num_sites, sizeof(*self->alleles));\n    if (self->num_alleles == NULL || self->parent == NULL || self->allelic_state == NULL\n        || self->transition_index == NULL || self->transition_stack == NULL\n        || self->transitions == NULL || self->transitions_copy == NULL\n        || self->num_transition_samples == NULL || self->transition_parent == NULL\n        || self->transition_time_order == NULL || self->values == NULL\n        || self->recombination_rate == NULL || self->mutation_rate == NULL\n        || self->alleles == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (l = 0; l < self->num_sites; l++) {\n        /* TODO check these inputs */\n        self->recombination_rate[l] = recombination_rate[l];\n        self->mutation_rate[l] = mutation_rate[l];\n        if (options & TSK_ALLELES_ACGT) {\n            self->num_alleles[l] = 4;\n            self->alleles[l] = _acgt_alleles;\n        } else {\n            /* Default to the 0/1 alleles */\n            self->num_alleles[l] = 2;\n            self->alleles[l] = _zero_one_alleles;\n        }\n    }\n    ret = tsk_tree_init(&self->tree, self->tree_sequence, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    self->num_values = 0;\n    self->max_values = 0;\n    /* Keep this as a struct variable so that we can test overflow, but this\n     * should never be set to more than MAX_PARSIMONY_WORDS as we're doing\n     * a bunch of stack allocations based on this. */\n    self->max_parsimony_words = MAX_PARSIMONY_WORDS;\n    ret = 0;\nout:\n    return ret;\n}\n\nint\ntsk_ls_hmm_set_precision(tsk_ls_hmm_t *self, unsigned int precision)\n{\n    self->precision = precision;\n    return 0;\n}\n\nint\ntsk_ls_hmm_free(tsk_ls_hmm_t *self)\n{\n    tsk_tree_free(&self->tree);\n    tsk_safe_free(self->recombination_rate);\n    tsk_safe_free(self->mutation_rate);\n    tsk_safe_free(self->recombination_rate);\n    tsk_safe_free(self->alleles);\n    tsk_safe_free(self->num_alleles);\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->allelic_state);\n    tsk_safe_free(self->transition_index);\n    tsk_safe_free(self->transition_stack);\n    tsk_safe_free(self->transitions);\n    tsk_safe_free(self->transitions_copy);\n    tsk_safe_free(self->transition_time_order);\n    tsk_safe_free(self->values);\n    tsk_safe_free(self->num_transition_samples);\n    tsk_safe_free(self->transition_parent);\n    tsk_safe_free(self->optimal_value_sets);\n    return 0;\n}\n\nstatic int\ntsk_ls_hmm_reset(tsk_ls_hmm_t *self, double value)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t u;\n    const tsk_id_t *samples;\n    tsk_size_t N = self->num_nodes;\n\n    tsk_memset(self->parent, 0xff, N * sizeof(*self->parent));\n    tsk_memset(self->transition_index, 0xff, N * sizeof(*self->transition_index));\n    tsk_memset(self->allelic_state, 0xff, N * sizeof(*self->allelic_state));\n    tsk_memset(self->transitions, 0, self->max_transitions * sizeof(*self->transitions));\n    tsk_memset(self->num_transition_samples, 0,\n        self->max_transitions * sizeof(*self->num_transition_samples));\n    tsk_memset(self->transition_parent, 0xff,\n        self->max_transitions * sizeof(*self->transition_parent));\n\n    samples = tsk_treeseq_get_samples(self->tree_sequence);\n    for (j = 0; j < self->num_samples; j++) {\n        u = samples[j];\n        self->transitions[j].tree_node = u;\n        self->transitions[j].value = value;\n        self->transition_index[u] = (tsk_id_t) j;\n    }\n    self->num_transitions = self->num_samples;\n    return ret;\n}\n\n/* After we have moved on to a new tree we can have transitions still associated\n * with the old roots, which are now disconnected. Remove. */\nstatic int\ntsk_ls_hmm_remove_dead_roots(tsk_ls_hmm_t *self)\n{\n    tsk_id_t *restrict T_index = self->transition_index;\n    tsk_value_transition_t *restrict T = self->transitions;\n    const tsk_id_t *restrict right_sib = self->tree.right_sib;\n    const tsk_id_t left_root = tsk_tree_get_left_root(&self->tree);\n    const tsk_id_t *restrict parent = self->parent;\n    tsk_id_t root, u;\n    tsk_size_t j;\n    const tsk_id_t root_marker = -2;\n\n    for (root = left_root; root != TSK_NULL; root = right_sib[root]) {\n        if (T_index[root] != TSK_NULL) {\n            /* Use the value_index slot as a marker. We don't use this between\n             * iterations, so it's safe to appropriate here */\n            T[T_index[root]].value_index = root_marker;\n        }\n    }\n    for (j = 0; j < self->num_transitions; j++) {\n        u = T[j].tree_node;\n        if (u != TSK_NULL) {\n            if (parent[u] == TSK_NULL && T[j].value_index != root_marker) {\n                T_index[u] = TSK_NULL;\n                T[j].tree_node = TSK_NULL;\n            }\n            T[j].value_index = -1;\n        }\n    }\n    return 0;\n}\n\nstatic int\ntsk_ls_hmm_update_tree(tsk_ls_hmm_t *self, int direction)\n{\n    int ret = 0;\n    tsk_id_t *restrict parent = self->parent;\n    tsk_id_t *restrict T_index = self->transition_index;\n    const tsk_id_t *restrict edges_child = self->tree_sequence->tables->edges.child;\n    const tsk_id_t *restrict edges_parent = self->tree_sequence->tables->edges.parent;\n    tsk_value_transition_t *restrict T = self->transitions;\n    tsk_id_t u, c, p, j, e;\n    tsk_value_transition_t *vt;\n    tsk_tree_position_t tree_pos;\n\n    tree_pos = self->tree.tree_pos;\n    for (j = tree_pos.out.start; j != tree_pos.out.stop; j += direction) {\n        e = tree_pos.out.order[j];\n        c = edges_child[e];\n        u = c;\n        if (T_index[u] == TSK_NULL) {\n            /* Ensure the subtree we're detaching has a transition at the root */\n            while (T_index[u] == TSK_NULL) {\n                u = parent[u];\n                tsk_bug_assert(u != TSK_NULL);\n            }\n            tsk_bug_assert(self->num_transitions < self->max_transitions);\n            T_index[c] = (tsk_id_t) self->num_transitions;\n            T[self->num_transitions].tree_node = c;\n            T[self->num_transitions].value = T[T_index[u]].value;\n            self->num_transitions++;\n        }\n        parent[c] = TSK_NULL;\n    }\n\n    for (j = tree_pos.in.start; j != tree_pos.in.stop; j += direction) {\n        e = tree_pos.in.order[j];\n        c = edges_child[e];\n        p = edges_parent[e];\n        parent[c] = p;\n        u = p;\n        if (parent[p] == TSK_NULL) {\n            /* Grafting onto a new root. */\n            if (T_index[p] == TSK_NULL) {\n                T_index[p] = (tsk_id_t) self->num_transitions;\n                tsk_bug_assert(self->num_transitions < self->max_transitions);\n                T[self->num_transitions].tree_node = p;\n                T[self->num_transitions].value = T[T_index[c]].value;\n                self->num_transitions++;\n            }\n        } else {\n            /* Grafting into an existing subtree. */\n            while (T_index[u] == TSK_NULL) {\n                u = parent[u];\n            }\n            tsk_bug_assert(u != TSK_NULL);\n        }\n        tsk_bug_assert(T_index[u] != -1 && T_index[c] != -1);\n        if (T[T_index[u]].value == T[T_index[c]].value) {\n            vt = &T[T_index[c]];\n            /* Mark the value transition as unusued */\n            vt->value = -1;\n            vt->tree_node = TSK_NULL;\n            T_index[c] = TSK_NULL;\n        }\n    }\n\n    ret = tsk_ls_hmm_remove_dead_roots(self);\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_get_allele_index(tsk_ls_hmm_t *self, tsk_id_t site, const char *allele_state,\n    const tsk_size_t allele_length)\n{\n    /* Note we're not doing tsk_trace_error here because it would require changing\n     * the logic of the function. Could be done easily enough, though */\n    int ret = TSK_ERR_ALLELE_NOT_FOUND;\n    const char **alleles = self->alleles[site];\n    const tsk_id_t num_alleles = (tsk_id_t) self->num_alleles[site];\n\n    tsk_id_t j;\n\n    for (j = 0; j < num_alleles; j++) {\n        if (strlen(alleles[j]) != allele_length) {\n            break;\n        }\n        if (strncmp(alleles[j], allele_state, (size_t) allele_length) == 0) {\n            ret = (int) j;\n            break;\n        }\n    }\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_update_probabilities(\n    tsk_ls_hmm_t *self, const tsk_site_t *site, int32_t haplotype_state)\n{\n    int ret = 0;\n    tsk_id_t root;\n    tsk_tree_t *tree = &self->tree;\n    tsk_id_t *restrict parent = self->parent;\n    tsk_id_t *restrict T_index = self->transition_index;\n    tsk_value_transition_t *restrict T = self->transitions;\n    int32_t *restrict allelic_state = self->allelic_state;\n    const tsk_id_t left_root = tsk_tree_get_left_root(tree);\n    tsk_mutation_t mut;\n    tsk_id_t j, u, v;\n    double x;\n    bool match;\n\n    /* Set the allelic states */\n    ret = tsk_ls_hmm_get_allele_index(\n        self, site->id, site->ancestral_state, site->ancestral_state_length);\n    if (ret < 0) {\n        goto out;\n    }\n    for (root = left_root; root != TSK_NULL; root = tree->right_sib[root]) {\n        allelic_state[root] = (int32_t) ret;\n    }\n\n    for (j = 0; j < (tsk_id_t) site->mutations_length; j++) {\n        mut = site->mutations[j];\n        ret = tsk_ls_hmm_get_allele_index(\n            self, site->id, mut.derived_state, mut.derived_state_length);\n        if (ret < 0) {\n            goto out;\n        }\n        u = mut.node;\n        allelic_state[u] = (int32_t) ret;\n        if (T_index[u] == TSK_NULL) {\n            while (T_index[u] == TSK_NULL) {\n                u = parent[u];\n            }\n            tsk_bug_assert(self->num_transitions < self->max_transitions);\n            T_index[mut.node] = (tsk_id_t) self->num_transitions;\n            T[self->num_transitions].tree_node = mut.node;\n            T[self->num_transitions].value = T[T_index[u]].value;\n            self->num_transitions++;\n        }\n    }\n\n    for (j = 0; j < (tsk_id_t) self->num_transitions; j++) {\n        u = T[j].tree_node;\n        if (u != TSK_NULL) {\n            /* Get the allelic_state at u. */\n            v = u;\n            while (allelic_state[v] == TSK_MISSING_DATA) {\n                v = parent[v];\n                tsk_bug_assert(v != -1);\n            }\n            match = haplotype_state == TSK_MISSING_DATA\n                    || haplotype_state == allelic_state[v];\n            ret = self->next_probability(self, site->id, T[j].value, match, u, &x);\n            if (ret != 0) {\n                goto out;\n            }\n            T[j].value = x;\n        }\n    }\n\n    /* Unset the allelic states */\n    for (root = left_root; root != TSK_NULL; root = tree->right_sib[root]) {\n        allelic_state[root] = TSK_MISSING_DATA;\n    }\n    for (j = 0; j < (tsk_id_t) site->mutations_length; j++) {\n        mut = site->mutations[j];\n        allelic_state[mut.node] = TSK_MISSING_DATA;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_discretise_values(tsk_ls_hmm_t *self)\n{\n    int ret = 0;\n    tsk_value_transition_t *T = self->transitions;\n    double *values = self->values;\n    tsk_size_t j, k, num_values;\n\n    num_values = 0;\n    for (j = 0; j < self->num_transitions; j++) {\n        if (T[j].tree_node != TSK_NULL) {\n            values[num_values] = T[j].value;\n            num_values++;\n        }\n    }\n    tsk_bug_assert(num_values > 0);\n\n    qsort(values, (size_t) num_values, sizeof(double), cmp_double);\n\n    k = 0;\n    for (j = 1; j < num_values; j++) {\n        if (values[j] != values[k]) {\n            k++;\n            values[k] = values[j];\n        }\n    }\n    num_values = k + 1;\n    self->num_values = num_values;\n    for (j = 0; j < self->num_transitions; j++) {\n        if (T[j].tree_node != TSK_NULL) {\n            T[j].value_index\n                = (tsk_id_t) tsk_search_sorted(values, num_values, T[j].value);\n            tsk_bug_assert(T[j].value == self->values[T[j].value_index]);\n        }\n    }\n    return ret;\n}\n\n/*\n * TODO We also have these function in tree.c where they're used in the\n * parsimony calculations (which are slightly different). It would be good to bring\n * these together, or at least avoid having the same function in two\n * files. Keeping it as it is for now so that it can be inlined, since\n * it's perf-sensitive. */\n\nstatic inline tsk_id_t\nget_smallest_set_bit(uint64_t v)\n{\n    /* This is an inefficient implementation, there are several better\n     * approaches. On GCC we can use\n     * return (uint8_t) (__builtin_ffsll((long long) v) - 1);\n     */\n    uint64_t t = 1;\n    tsk_id_t r = 0;\n    assert(v != 0);\n\n    while ((v & t) == 0) {\n        t <<= 1;\n        r++;\n    }\n    return r;\n}\n\nstatic inline uint64_t\nset_bit(uint64_t value, uint8_t bit)\n{\n    return value | (1ULL << bit);\n}\n\nstatic inline bool\nbit_is_set(uint64_t value, uint8_t bit)\n{\n    return (value & (1ULL << bit)) != 0;\n}\n\nstatic inline tsk_id_t\nget_smallest_element(const uint64_t *restrict A, tsk_size_t u, tsk_size_t num_words)\n{\n    tsk_size_t base = u * num_words;\n    const uint64_t *restrict a = A + base;\n    tsk_id_t j = 0;\n\n    while (a[j] == 0) {\n        j++;\n        tsk_bug_assert(j < (tsk_id_t) num_words);\n    }\n    return j * 64 + get_smallest_set_bit(a[j]);\n}\n\n/* static variables are zero-initialised by default. */\nstatic const uint64_t zero_block[MAX_PARSIMONY_WORDS];\n\nstatic inline bool\nall_zero(const uint64_t *restrict A, tsk_id_t u, tsk_size_t num_words)\n{\n    if (num_words == 1) {\n        return A[u] == 0;\n    } else {\n        return tsk_memcmp(\n                   zero_block, A + (tsk_size_t) u * num_words, num_words * sizeof(*A))\n               == 0;\n    }\n}\n\nstatic inline bool\nelement_in(\n    const uint64_t *restrict A, tsk_id_t u, const tsk_id_t state, tsk_size_t num_words)\n{\n    tsk_size_t index = ((tsk_size_t) u) * num_words + (tsk_size_t)(state / 64);\n    return (A[index] & (1ULL << (state % 64))) != 0;\n}\n\nstatic inline void\nset_optimal_value(\n    uint64_t *restrict A, tsk_id_t u, const tsk_size_t num_words, tsk_id_t state)\n{\n    tsk_size_t index = ((tsk_size_t) u) * num_words + (tsk_size_t)(state / 64);\n    tsk_bug_assert(((tsk_size_t) state) / 64 < num_words);\n    A[index] |= 1ULL << (state % 64);\n}\n\n/* TODO the implementation here isn't particularly optimal and the way things\n * were organised was really driven by the old Fitch parsimony algorithm\n * (which only worked on binary trees. In particular, we should be working\n * word-by-word where possible rather than iterating by values like we do here.\n * Needs to be reworked when we're documenting/writing up this algorithm.\n */\n\nstatic void\ncompute_optimal_value_1(uint64_t *restrict A, const tsk_id_t *restrict left_child,\n    const tsk_id_t *restrict right_sib, const tsk_id_t u, const tsk_id_t parent_state,\n    const tsk_size_t num_values)\n{\n    tsk_id_t v;\n    uint64_t child;\n    tsk_size_t value_count[64], max_value_count;\n    uint8_t j;\n\n    assert(num_values < 64);\n\n    tsk_memset(value_count, 0, num_values * sizeof(*value_count));\n    for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n        child = A[v];\n        /* If the set for a given child is empty, then we know it inherits\n         * directly from the parent state and must be a singleton set. */\n        if (child == 0) {\n            child = 1ULL << parent_state;\n        }\n        for (j = 0; j < num_values; j++) {\n            value_count[j] += bit_is_set(child, j);\n        }\n    }\n    max_value_count = 0;\n    for (j = 0; j < num_values; j++) {\n        max_value_count = TSK_MAX(max_value_count, value_count[j]);\n    }\n    A[u] = 0;\n    for (j = 0; j < num_values; j++) {\n        if (value_count[j] == max_value_count) {\n            A[u] = set_bit(A[u], j);\n        }\n    }\n}\n\nstatic void\ncompute_optimal_value_general(uint64_t *restrict A, const tsk_id_t *restrict left_child,\n    const tsk_id_t *restrict right_sib, const tsk_id_t u, const tsk_id_t parent_state,\n    const tsk_size_t num_values, const tsk_size_t num_words)\n{\n    tsk_id_t v;\n    uint64_t child[MAX_PARSIMONY_WORDS];\n    uint64_t *Au;\n    tsk_size_t base, word, bit;\n    bool child_all_zero;\n    const tsk_id_t state_index = parent_state / 64;\n    const uint64_t state_word = 1ULL << (parent_state % 64);\n    tsk_size_t value_count[64 * MAX_PARSIMONY_WORDS], max_value_count;\n    tsk_size_t j;\n\n    tsk_bug_assert(num_values < 64 * MAX_PARSIMONY_WORDS);\n    tsk_bug_assert(num_words <= MAX_PARSIMONY_WORDS);\n    for (j = 0; j < num_values; j++) {\n        value_count[j] = 0;\n    }\n\n    for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n        child_all_zero = true;\n        base = ((tsk_size_t) v) * num_words;\n        for (word = 0; word < num_words; word++) {\n            child[word] = A[base + word];\n            child_all_zero = child_all_zero && (child[word] == 0);\n        }\n        /* If the set for a given child is empty, then we know it inherits\n         * directly from the parent state and must be a singleton set. */\n        if (child_all_zero) {\n            child[state_index] = state_word;\n        }\n        for (j = 0; j < num_values; j++) {\n            word = j / 64;\n            bit = j % 64;\n            assert(word < num_words);\n            value_count[j] += bit_is_set(child[word], (uint8_t) bit);\n        }\n    }\n    max_value_count = 0;\n    for (j = 0; j < num_values; j++) {\n        max_value_count = TSK_MAX(max_value_count, value_count[j]);\n    }\n\n    Au = A + ((size_t) u * num_words);\n    for (word = 0; word < num_words; word++) {\n        Au[word] = 0;\n    }\n    for (j = 0; j < num_values; j++) {\n        if (value_count[j] == max_value_count) {\n            word = j / 64;\n            bit = j % 64;\n            Au[word] = set_bit(Au[word], (uint8_t) bit);\n        }\n    }\n}\n\nstatic void\ncompute_optimal_value(uint64_t *restrict A, const tsk_id_t *restrict left_child,\n    const tsk_id_t *restrict right_sib, const tsk_id_t u, const tsk_id_t parent_state,\n    const tsk_size_t num_values, const tsk_size_t num_words)\n{\n    if (num_words == 1) {\n        compute_optimal_value_1(A, left_child, right_sib, u, parent_state, num_values);\n    } else {\n        compute_optimal_value_general(\n            A, left_child, right_sib, u, parent_state, num_values, num_words);\n    }\n}\n\nstatic int\ntsk_ls_hmm_setup_optimal_value_sets(tsk_ls_hmm_t *self)\n{\n    int ret = 0;\n\n    /* We expect that most of the time there will be one word per optimal_value set,\n     * but there will be times when we need more than one word. This approach\n     * lets us expand the memory if we need to, but when the number of\n     * values goes back below 64 we revert to using one word per set. We\n     * could in principle release back the memory as well, but it doesn't seem\n     * worth the bother. */\n    self->num_optimal_value_set_words = (self->num_values / 64) + 1;\n    if (self->num_optimal_value_set_words > self->max_parsimony_words) {\n        ret = tsk_trace_error(TSK_ERR_TOO_MANY_VALUES);\n        goto out;\n    }\n    if (self->num_values >= self->max_values) {\n        self->max_values = self->num_optimal_value_set_words * 64;\n        tsk_safe_free(self->optimal_value_sets);\n        self->optimal_value_sets\n            = tsk_calloc(self->num_nodes * self->num_optimal_value_set_words,\n                sizeof(*self->optimal_value_sets));\n        if (self->optimal_value_sets == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_build_optimal_value_sets(tsk_ls_hmm_t *self)\n{\n    int ret = 0;\n    const double *restrict node_time = self->tree_sequence->tables->nodes.time;\n    const tsk_id_t *restrict left_child = self->tree.left_child;\n    const tsk_id_t *restrict right_sib = self->tree.right_sib;\n    const tsk_id_t *restrict parent = self->parent;\n    const tsk_value_transition_t *restrict T = self->transitions;\n    const tsk_id_t *restrict T_index = self->transition_index;\n    tsk_argsort_t *restrict order = self->transition_time_order;\n    const tsk_size_t num_optimal_value_set_words = self->num_optimal_value_set_words;\n    uint64_t *restrict A = self->optimal_value_sets;\n    tsk_size_t j;\n    tsk_id_t u, v, state, parent_state;\n\n    /* argsort the transitions by node time so we can visit them in the\n     * correct order */\n    for (j = 0; j < self->num_transitions; j++) {\n        order[j].index = j;\n        order[j].value = DBL_MAX;\n        if (T[j].tree_node != TSK_NULL) {\n            order[j].value = node_time[T[j].tree_node];\n        }\n    }\n    qsort(order, (size_t) self->num_transitions, sizeof(*order), cmp_argsort);\n\n    for (j = 0; j < self->num_transitions; j++) {\n        u = T[order[j].index].tree_node;\n        if (u != TSK_NULL) {\n            state = T[order[j].index].value_index;\n            if (left_child[u] == TSK_NULL) {\n                /* leaf node */\n                set_optimal_value(A, u, num_optimal_value_set_words, state);\n            } else {\n                compute_optimal_value(A, left_child, right_sib, u, state,\n                    self->num_values, num_optimal_value_set_words);\n            }\n            v = parent[u];\n            if (v != TSK_NULL) {\n                while (T_index[v] == TSK_NULL) {\n                    v = parent[v];\n                    tsk_bug_assert(v != TSK_NULL);\n                }\n                parent_state = T[T_index[v]].value_index;\n                v = parent[u];\n                while (T_index[v] == TSK_NULL) {\n                    compute_optimal_value(A, left_child, right_sib, v, parent_state,\n                        self->num_values, num_optimal_value_set_words);\n                    v = parent[v];\n                    tsk_bug_assert(v != TSK_NULL);\n                }\n            }\n        }\n    }\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_redistribute_transitions(tsk_ls_hmm_t *self)\n{\n    int ret = 0;\n    const tsk_id_t *restrict left_child = self->tree.left_child;\n    const tsk_id_t *restrict right_sib = self->tree.right_sib;\n    const tsk_id_t *restrict parent = self->parent;\n    tsk_id_t *restrict T_index = self->transition_index;\n    tsk_id_t *restrict T_parent = self->transition_parent;\n    tsk_value_transition_t *restrict T = self->transitions;\n    tsk_value_transition_t *restrict T_old = self->transitions_copy;\n    tsk_transition_stack_t *stack = self->transition_stack;\n    uint64_t *restrict A = self->optimal_value_sets;\n    const tsk_size_t num_optimal_value_set_words = self->num_optimal_value_set_words;\n    tsk_transition_stack_t s, child_s;\n    tsk_id_t root, u, v;\n    int stack_top = 0;\n    tsk_size_t j, old_num_transitions;\n\n    tsk_memcpy(T_old, T, self->num_transitions * sizeof(*T));\n    old_num_transitions = self->num_transitions;\n    self->num_transitions = 0;\n\n    /* TODO refactor this to push the virtual root onto the stack rather then\n     * iterating over the roots. See the existing parsimony implementations\n     * for an example. */\n    for (root = tsk_tree_get_left_root(&self->tree); root != TSK_NULL;\n         root = right_sib[root]) {\n        stack[0].tree_node = root;\n        stack[0].old_state = T_old[T_index[root]].value_index;\n        stack[0].new_state\n            = get_smallest_element(A, (tsk_size_t) root, num_optimal_value_set_words);\n        stack[0].transition_parent = 0;\n        stack_top = 0;\n\n        tsk_bug_assert(self->num_transitions < self->max_transitions);\n        T_parent[self->num_transitions] = TSK_NULL;\n        T[self->num_transitions].tree_node = stack[0].tree_node;\n        T[self->num_transitions].value_index = stack[0].new_state;\n        self->num_transitions++;\n\n        while (stack_top >= 0) {\n            s = stack[stack_top];\n            stack_top--;\n            for (v = left_child[s.tree_node]; v != TSK_NULL; v = right_sib[v]) {\n                child_s = s;\n                child_s.tree_node = v;\n                if (T_index[v] != TSK_NULL) {\n                    child_s.old_state = T_old[T_index[v]].value_index;\n                }\n                if (!all_zero(A, v, num_optimal_value_set_words)) {\n                    if (!element_in(A, v, s.new_state, num_optimal_value_set_words)) {\n                        child_s.new_state = get_smallest_element(\n                            A, (tsk_size_t) v, num_optimal_value_set_words);\n                        child_s.transition_parent = (tsk_id_t) self->num_transitions;\n                        /* Add a new transition */\n                        tsk_bug_assert(self->num_transitions < self->max_transitions);\n                        T_parent[self->num_transitions] = s.transition_parent;\n                        T[self->num_transitions].tree_node = v;\n                        T[self->num_transitions].value_index = child_s.new_state;\n                        self->num_transitions++;\n                    }\n                    stack_top++;\n                    stack[stack_top] = child_s;\n                } else {\n                    /* Node that we didn't visit when moving up the tree */\n                    if (s.old_state != s.new_state) {\n                        tsk_bug_assert(self->num_transitions < self->max_transitions);\n                        T_parent[self->num_transitions] = s.transition_parent;\n                        T[self->num_transitions].tree_node = v;\n                        T[self->num_transitions].value_index = s.old_state;\n                        self->num_transitions++;\n                    }\n                }\n            }\n        }\n    }\n\n    /* Unset the old T_index pointers and optimal_value sets. */\n    for (j = 0; j < old_num_transitions; j++) {\n        u = T_old[j].tree_node;\n        if (u != TSK_NULL) {\n            T_index[u] = TSK_NULL;\n            while (u != TSK_NULL && !all_zero(A, u, num_optimal_value_set_words)) {\n                tsk_memset(A + ((tsk_size_t) u) * num_optimal_value_set_words, 0,\n                    num_optimal_value_set_words * sizeof(uint64_t));\n                u = parent[u];\n            }\n        }\n    }\n    /* Set the new pointers for transition nodes and the values.*/\n    for (j = 0; j < self->num_transitions; j++) {\n        T_index[T[j].tree_node] = (tsk_id_t) j;\n        T[j].value = self->values[T[j].value_index];\n    }\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_compress(tsk_ls_hmm_t *self)\n{\n    int ret = 0;\n\n    ret = tsk_ls_hmm_discretise_values(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ls_hmm_setup_optimal_value_sets(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ls_hmm_build_optimal_value_sets(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ls_hmm_redistribute_transitions(self);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_process_site_forward(\n    tsk_ls_hmm_t *self, const tsk_site_t *site, int32_t haplotype_state)\n{\n    int ret = 0;\n    double x, normalisation_factor;\n    tsk_compressed_matrix_t *output = (tsk_compressed_matrix_t *) self->output;\n    tsk_value_transition_t *restrict T = self->transitions;\n    const unsigned int precision = (unsigned int) self->precision;\n    tsk_size_t j;\n\n    ret = tsk_ls_hmm_update_probabilities(self, site, haplotype_state);\n    if (ret != 0) {\n        goto out;\n    }\n    /* See notes in the Python implementation on why we don't want to compress\n     * here, but rather should be doing it after rounding. */\n    ret = tsk_ls_hmm_compress(self);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_bug_assert(self->num_transitions <= self->num_samples);\n    normalisation_factor = self->compute_normalisation_factor(self);\n\n    if (normalisation_factor == 0) {\n        ret = tsk_trace_error(TSK_ERR_MATCH_IMPOSSIBLE);\n        goto out;\n    }\n    for (j = 0; j < self->num_transitions; j++) {\n        tsk_bug_assert(T[j].tree_node != TSK_NULL);\n        x = T[j].value / normalisation_factor;\n        T[j].value = tsk_round(x, precision);\n    }\n\n    ret = tsk_compressed_matrix_store_site(\n        output, site->id, normalisation_factor, (tsk_size_t) self->num_transitions, T);\nout:\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_run_forward(tsk_ls_hmm_t *self, int32_t *haplotype)\n{\n    int ret = 0;\n    int t_ret;\n    const tsk_site_t *sites;\n    tsk_size_t j, num_sites;\n    const double n = (double) self->num_samples;\n\n    ret = tsk_ls_hmm_reset(self, 1 / n);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (t_ret = tsk_tree_first(&self->tree); t_ret == TSK_TREE_OK;\n         t_ret = tsk_tree_next(&self->tree)) {\n        ret = tsk_ls_hmm_update_tree(self, TSK_DIR_FORWARD);\n        if (ret != 0) {\n            goto out;\n        }\n        /* tsk_ls_hmm_check_state(self); */\n        ret = tsk_tree_get_sites(&self->tree, &sites, &num_sites);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_sites; j++) {\n            ret = tsk_ls_hmm_process_site_forward(\n                self, &sites[j], haplotype[sites[j].id]);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\n    /* Set to zero so we can print and check the state OK. */\n    self->num_transitions = 0;\n    if (t_ret != 0) {\n        ret = t_ret;\n        goto out;\n    }\nout:\n    return ret;\n}\n\n/****************************************************************\n * Forward Algorithm\n ****************************************************************/\n\nstatic double\ntsk_ls_hmm_compute_normalisation_factor_forward(tsk_ls_hmm_t *self)\n{\n    tsk_size_t *restrict N = self->num_transition_samples;\n    tsk_value_transition_t *restrict T = self->transitions;\n    const tsk_id_t *restrict T_parent = self->transition_parent;\n    const tsk_size_t *restrict num_samples = self->tree.num_samples;\n    const tsk_id_t num_transitions = (tsk_id_t) self->num_transitions;\n    double normalisation_factor;\n    tsk_id_t j;\n\n    /* Compute the number of samples directly inheriting from each transition */\n    for (j = 0; j < num_transitions; j++) {\n        tsk_bug_assert(T[j].tree_node != TSK_NULL);\n        N[j] = num_samples[T[j].tree_node];\n    }\n    for (j = 0; j < num_transitions; j++) {\n        if (T_parent[j] != TSK_NULL) {\n            N[T_parent[j]] -= N[j];\n        }\n    }\n\n    /* Compute the normalising constant used to avoid underflow */\n    normalisation_factor = 0;\n    for (j = 0; j < num_transitions; j++) {\n        normalisation_factor += (double) N[j] * T[j].value;\n    }\n    return normalisation_factor;\n}\n\nstatic int\ntsk_ls_hmm_next_probability_forward(tsk_ls_hmm_t *self, tsk_id_t site_id, double p_last,\n    bool is_match, tsk_id_t TSK_UNUSED(node), double *result)\n{\n    const double rho = self->recombination_rate[site_id];\n    const double mu = self->mutation_rate[site_id];\n    const double n = (double) self->num_samples;\n    const double num_alleles = self->num_alleles[site_id];\n    double p_t, p_e;\n\n    p_t = p_last * (1 - rho) + rho / n;\n    p_e = mu;\n    if (is_match) {\n        p_e = 1 - (num_alleles - 1) * mu;\n    }\n    *result = p_t * p_e;\n    return 0;\n}\n\nint\ntsk_ls_hmm_forward(tsk_ls_hmm_t *self, int32_t *haplotype,\n    tsk_compressed_matrix_t *output, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_compressed_matrix_init(output, self->tree_sequence, 0, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        if (output->tree_sequence != self->tree_sequence) {\n            ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n            goto out;\n        }\n        ret = tsk_compressed_matrix_clear(output);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    self->next_probability = tsk_ls_hmm_next_probability_forward;\n    self->compute_normalisation_factor = tsk_ls_hmm_compute_normalisation_factor_forward;\n    self->output = output;\n\n    ret = tsk_ls_hmm_run_forward(self, haplotype);\nout:\n    return ret;\n}\n\n/****************************************************************\n * Backward Algorithm\n ****************************************************************/\n\nstatic int\ntsk_ls_hmm_next_probability_backward(tsk_ls_hmm_t *self, tsk_id_t site_id, double p_last,\n    bool is_match, tsk_id_t TSK_UNUSED(node), double *result)\n{\n    const double mu = self->mutation_rate[site_id];\n    const double num_alleles = self->num_alleles[site_id];\n    double p_e;\n\n    p_e = mu;\n    if (is_match) {\n        p_e = 1 - (num_alleles - 1) * mu;\n    }\n    *result = p_last * p_e;\n    return 0;\n}\n\nstatic int\ntsk_ls_hmm_process_site_backward(tsk_ls_hmm_t *self, const tsk_site_t *site,\n    const int32_t haplotype_state, const double normalisation_factor)\n{\n    int ret = 0;\n    double x, b_last_sum;\n    tsk_compressed_matrix_t *output = (tsk_compressed_matrix_t *) self->output;\n    tsk_value_transition_t *restrict T = self->transitions;\n    const unsigned int precision = (unsigned int) self->precision;\n    const double rho = self->recombination_rate[site->id];\n    const double n = (double) self->num_samples;\n    tsk_size_t j;\n\n    /* FIXME!!! We are calling compress twice here because we need to compress\n     * immediately before calling store_site in order to filter out -1 nodes,\n     * and also (crucially) to ensure that the value transitions are listed\n     * in preorder, which we rely on later for decoding.\n     *\n     * https://github.com/tskit-dev/tskit/issues/2803\n     */\n    ret = tsk_ls_hmm_compress(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_compressed_matrix_store_site(\n        output, site->id, normalisation_factor, (tsk_size_t) self->num_transitions, T);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_ls_hmm_update_probabilities(self, site, haplotype_state);\n    if (ret != 0) {\n        goto out;\n    }\n    /* DO WE NEED THIS compress?? See above */\n    ret = tsk_ls_hmm_compress(self);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_bug_assert(self->num_transitions <= self->num_samples);\n    b_last_sum = self->compute_normalisation_factor(self);\n    for (j = 0; j < self->num_transitions; j++) {\n        tsk_bug_assert(T[j].tree_node != TSK_NULL);\n        x = rho * b_last_sum / n + (1 - rho) * T[j].value;\n        x /= normalisation_factor;\n        T[j].value = tsk_round(x, precision);\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ls_hmm_run_backward(\n    tsk_ls_hmm_t *self, int32_t *haplotype, const double *forward_norm)\n{\n    int ret = 0;\n    int t_ret;\n    const tsk_site_t *sites;\n    double s;\n    tsk_size_t num_sites;\n    tsk_id_t j;\n\n    ret = tsk_ls_hmm_reset(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (t_ret = tsk_tree_last(&self->tree); t_ret == TSK_TREE_OK;\n         t_ret = tsk_tree_prev(&self->tree)) {\n        ret = tsk_ls_hmm_update_tree(self, TSK_DIR_REVERSE);\n        if (ret != 0) {\n            goto out;\n        }\n        /* tsk_ls_hmm_check_state(self); */\n        ret = tsk_tree_get_sites(&self->tree, &sites, &num_sites);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = (tsk_id_t) num_sites - 1; j >= 0; j--) {\n            s = forward_norm[sites[j].id];\n            if (s <= 0) {\n                /* NOTE: I'm not sure if this is the correct interpretation,\n                 * but norm values of 0 do lead to problems, and this seems\n                 * like a simple way of guarding against it. We do seem to\n                 * get norm values of 0 with impossible matches from the fwd\n                 * matrix.\n                 */\n                ret = tsk_trace_error(TSK_ERR_MATCH_IMPOSSIBLE);\n                goto out;\n            }\n            ret = tsk_ls_hmm_process_site_backward(\n                self, &sites[j], haplotype[sites[j].id], s);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\n    /* Set to zero so we can print and check the state OK. */\n    self->num_transitions = 0;\n    if (t_ret != 0) {\n        ret = t_ret;\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_ls_hmm_backward(tsk_ls_hmm_t *self, int32_t *haplotype, const double *forward_norm,\n    tsk_compressed_matrix_t *output, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_compressed_matrix_init(output, self->tree_sequence, 0, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        if (output->tree_sequence != self->tree_sequence) {\n            ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n            goto out;\n        }\n        ret = tsk_compressed_matrix_clear(output);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    self->next_probability = tsk_ls_hmm_next_probability_backward;\n    self->compute_normalisation_factor = tsk_ls_hmm_compute_normalisation_factor_forward;\n    self->output = output;\n\n    ret = tsk_ls_hmm_run_backward(self, haplotype, forward_norm);\nout:\n    return ret;\n}\n\n/****************************************************************\n * Viterbi Algorithm\n ****************************************************************/\n\nstatic double\ntsk_ls_hmm_compute_normalisation_factor_viterbi(tsk_ls_hmm_t *self)\n{\n    tsk_value_transition_t *restrict T = self->transitions;\n    const tsk_id_t num_transitions = (tsk_id_t) self->num_transitions;\n    tsk_value_transition_t max_vt;\n    tsk_id_t j;\n\n    max_vt.value = -1;\n    max_vt.tree_node = 0; /* keep compiler happy */\n    tsk_bug_assert(num_transitions > 0);\n    for (j = 0; j < num_transitions; j++) {\n        tsk_bug_assert(T[j].tree_node != TSK_NULL);\n        if (T[j].value > max_vt.value) {\n            max_vt = T[j];\n        }\n    }\n    return max_vt.value;\n}\n\nstatic int\ntsk_ls_hmm_next_probability_viterbi(tsk_ls_hmm_t *self, tsk_id_t site, double p_last,\n    bool is_match, tsk_id_t node, double *result)\n{\n    const double rho = self->recombination_rate[site];\n    const double mu = self->mutation_rate[site];\n    const double num_alleles = self->num_alleles[site];\n    const double n = (double) self->num_samples;\n    double p_recomb, p_no_recomb, p_t, p_e;\n    bool recombination_required = false;\n\n    p_no_recomb = p_last * (1 - rho + rho / n);\n    p_recomb = rho / n;\n    if (p_no_recomb > p_recomb) {\n        p_t = p_no_recomb;\n    } else {\n        p_t = p_recomb;\n        recombination_required = true;\n    }\n    p_e = mu;\n    if (is_match) {\n        p_e = 1 - (num_alleles - 1) * mu;\n    }\n    *result = p_t * p_e;\n    return tsk_viterbi_matrix_add_recombination_required(\n        self->output, site, node, recombination_required);\n}\n\nint\ntsk_ls_hmm_viterbi(tsk_ls_hmm_t *self, int32_t *haplotype, tsk_viterbi_matrix_t *output,\n    tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_viterbi_matrix_init(output, self->tree_sequence, 0, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        if (output->matrix.tree_sequence != self->tree_sequence) {\n            ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n            goto out;\n        }\n        ret = tsk_viterbi_matrix_clear(output);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    self->next_probability = tsk_ls_hmm_next_probability_viterbi;\n    self->compute_normalisation_factor = tsk_ls_hmm_compute_normalisation_factor_viterbi;\n    self->output = output;\n\n    ret = tsk_ls_hmm_run_forward(self, haplotype);\nout:\n    return ret;\n}\n\n/****************************************************************\n * Compressed matrix\n ****************************************************************/\n\nint\ntsk_compressed_matrix_init(tsk_compressed_matrix_t *self, tsk_treeseq_t *tree_sequence,\n    tsk_size_t block_size, tsk_flags_t options)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(*self));\n    self->tree_sequence = tree_sequence;\n    self->options = options;\n    self->num_sites = tsk_treeseq_get_num_sites(tree_sequence);\n    self->num_samples = tsk_treeseq_get_num_samples(tree_sequence);\n    self->num_transitions = tsk_malloc(self->num_sites * sizeof(*self->num_transitions));\n    self->normalisation_factor\n        = tsk_malloc(self->num_sites * sizeof(*self->normalisation_factor));\n    self->values = tsk_malloc(self->num_sites * sizeof(*self->values));\n    self->nodes = tsk_malloc(self->num_sites * sizeof(*self->nodes));\n    if (self->num_transitions == NULL || self->values == NULL || self->nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (block_size == 0) {\n        block_size = 1 << 20;\n    }\n    ret = tsk_blkalloc_init(&self->memory, (size_t) block_size);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_compressed_matrix_clear(self);\nout:\n    return ret;\n}\n\nint\ntsk_compressed_matrix_free(tsk_compressed_matrix_t *self)\n{\n    tsk_blkalloc_free(&self->memory);\n    tsk_safe_free(self->num_transitions);\n    tsk_safe_free(self->normalisation_factor);\n    tsk_safe_free(self->values);\n    tsk_safe_free(self->nodes);\n    return 0;\n}\n\nint\ntsk_compressed_matrix_clear(tsk_compressed_matrix_t *self)\n{\n    tsk_blkalloc_reset(&self->memory);\n    tsk_memset(\n        self->num_transitions, 0, self->num_sites * sizeof(*self->num_transitions));\n    tsk_memset(self->normalisation_factor, 0,\n        self->num_sites * sizeof(*self->normalisation_factor));\n    return 0;\n}\n\nvoid\ntsk_compressed_matrix_print_state(tsk_compressed_matrix_t *self, FILE *out)\n{\n    tsk_size_t l, j;\n\n    fprintf(out, \"Compressed matrix for %p\\n\", (void *) self->tree_sequence);\n    fprintf(out, \"num_sites = %lld\\n\", (long long) self->num_sites);\n    fprintf(out, \"num_samples = %lld\\n\", (long long) self->num_samples);\n    for (l = 0; l < self->num_sites; l++) {\n        fprintf(out, \"%lld\\ts=%f\\tv=%lld [\", (long long) l,\n            self->normalisation_factor[l], (long long) self->num_transitions[l]);\n        for (j = 0; j < self->num_transitions[l]; j++) {\n            fprintf(\n                out, \"(%lld, %f)\", (long long) self->nodes[l][j], self->values[l][j]);\n            if (j < self->num_transitions[l] - 1) {\n                fprintf(out, \",\");\n            } else {\n                fprintf(out, \"]\\n\");\n            }\n        }\n    }\n    fprintf(out, \"Memory:\\n\");\n    tsk_blkalloc_print_state(&self->memory, out);\n}\n\nint\ntsk_compressed_matrix_store_site(tsk_compressed_matrix_t *self, tsk_id_t site,\n    double normalisation_factor, tsk_size_t num_transitions,\n    const tsk_value_transition_t *transitions)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    if (site < 0 || site >= (tsk_id_t) self->num_sites) {\n        ret = tsk_trace_error(TSK_ERR_SITE_OUT_OF_BOUNDS);\n        goto out;\n    }\n\n    self->num_transitions[site] = num_transitions;\n    self->normalisation_factor[site] = normalisation_factor;\n    self->nodes[site]\n        = tsk_blkalloc_get(&self->memory, (size_t) num_transitions * sizeof(tsk_id_t));\n    self->values[site]\n        = tsk_blkalloc_get(&self->memory, (size_t) num_transitions * sizeof(double));\n    if (self->nodes[site] == NULL || self->values[site] == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (j = 0; j < num_transitions; j++) {\n        tsk_bug_assert(transitions[j].tree_node >= 0);\n        self->values[site][j] = transitions[j].value;\n        self->nodes[site][j] = transitions[j].tree_node;\n    }\n\nout:\n    return ret;\n}\n\nstatic int\ntsk_compressed_matrix_decode_site(tsk_compressed_matrix_t *self, const tsk_tree_t *tree,\n    const tsk_id_t site, double *values)\n{\n    int ret = 0;\n    const tsk_id_t *restrict list_left = tree->left_sample;\n    const tsk_id_t *restrict list_right = tree->right_sample;\n    const tsk_id_t *restrict list_next = tree->next_sample;\n    const tsk_id_t num_nodes = (tsk_id_t) tsk_treeseq_get_num_nodes(self->tree_sequence);\n    tsk_size_t j;\n    tsk_id_t node, index, stop;\n    double value;\n\n    for (j = 0; j < self->num_transitions[site]; j++) {\n        node = self->nodes[site][j];\n        if (node < 0 || node >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        value = self->values[site][j];\n        index = list_left[node];\n        if (index == TSK_NULL) {\n            /* It's an error if there are nodes that don't subtend any samples */\n            ret = tsk_trace_error(TSK_ERR_BAD_COMPRESSED_MATRIX_NODE);\n            goto out;\n        }\n        stop = list_right[node];\n        while (true) {\n            values[index] = value;\n            if (index == stop) {\n                break;\n            }\n            index = list_next[index];\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_compressed_matrix_decode(tsk_compressed_matrix_t *self, double *values)\n{\n    int ret = 0;\n    int t_ret;\n    tsk_tree_t tree;\n    tsk_size_t j, num_tree_sites;\n    const tsk_site_t *sites = NULL;\n    tsk_id_t site_id;\n    double *site_array;\n\n    ret = tsk_tree_init(&tree, self->tree_sequence, TSK_SAMPLE_LISTS);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (t_ret = tsk_tree_first(&tree); t_ret == TSK_TREE_OK;\n         t_ret = tsk_tree_next(&tree)) {\n        ret = tsk_tree_get_sites(&tree, &sites, &num_tree_sites);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_tree_sites; j++) {\n            site_id = sites[j].id;\n            site_array = values + ((tsk_size_t) site_id) * self->num_samples;\n            if (self->num_transitions[site_id] == 0) {\n                tsk_memset(site_array, 0, self->num_samples * sizeof(*site_array));\n            } else {\n                ret = tsk_compressed_matrix_decode_site(\n                    self, &tree, site_id, site_array);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        }\n    }\n    if (t_ret < 0) {\n        ret = t_ret;\n        goto out;\n    }\nout:\n    tsk_tree_free(&tree);\n    return ret;\n}\n\n/****************************************************************\n * Viterbi matrix\n ****************************************************************/\n\nstatic int\ntsk_viterbi_matrix_expand_recomb_records(tsk_viterbi_matrix_t *self)\n{\n    int ret = 0;\n    tsk_recomb_required_record *tmp = tsk_realloc(\n        self->recombination_required, self->max_recomb_records * sizeof(*tmp));\n\n    if (tmp == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    self->recombination_required = tmp;\nout:\n    return ret;\n}\n\nint\ntsk_viterbi_matrix_init(tsk_viterbi_matrix_t *self, tsk_treeseq_t *tree_sequence,\n    tsk_size_t block_size, tsk_flags_t options)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(*self));\n    if (block_size == 0) {\n        block_size = 1 << 20; /* 1MiB */\n    }\n    ret = tsk_compressed_matrix_init(&self->matrix, tree_sequence, block_size, options);\n    if (ret != 0) {\n        goto out;\n    }\n\n    self->max_recomb_records\n        = TSK_MAX(1, block_size / sizeof(tsk_recomb_required_record));\n    ret = tsk_viterbi_matrix_expand_recomb_records(self);\n    if (ret != 0) {\n        goto out;\n    }\n    /* Add the sentinel at the start to simplify traceback */\n    self->recombination_required[0].site = -1;\n\n    ret = tsk_viterbi_matrix_clear(self);\nout:\n    return ret;\n}\n\nint\ntsk_viterbi_matrix_free(tsk_viterbi_matrix_t *self)\n{\n    tsk_compressed_matrix_free(&self->matrix);\n    tsk_safe_free(self->recombination_required);\n    return 0;\n}\n\nint\ntsk_viterbi_matrix_clear(tsk_viterbi_matrix_t *self)\n{\n    self->num_recomb_records = 1;\n    tsk_compressed_matrix_clear(&self->matrix);\n    return 0;\n}\n\nvoid\ntsk_viterbi_matrix_print_state(tsk_viterbi_matrix_t *self, FILE *out)\n{\n    tsk_id_t l, j;\n\n    fprintf(out, \"viterbi_matrix\\n\");\n    fprintf(out, \"num_recomb_records = %lld\\n\", (long long) self->num_recomb_records);\n    fprintf(out, \"max_recomb_records = %lld\\n\", (long long) self->max_recomb_records);\n\n    j = 1;\n    for (l = 0; l < (tsk_id_t) self->matrix.num_sites; l++) {\n        fprintf(out, \"%lld\\t[\", (long long) l);\n        while (j < (tsk_id_t) self->num_recomb_records\n               && self->recombination_required[j].site == l) {\n            fprintf(out, \"(%lld, %d) \", (long long) self->recombination_required[j].node,\n                self->recombination_required[j].required);\n            j++;\n        }\n        fprintf(out, \"]\\n\");\n    }\n    tsk_compressed_matrix_print_state(&self->matrix, out);\n}\n\nTSK_WARN_UNUSED int\ntsk_viterbi_matrix_add_recombination_required(\n    tsk_viterbi_matrix_t *self, tsk_id_t site, tsk_id_t node, bool required)\n{\n    int ret = 0;\n    tsk_recomb_required_record *record;\n\n    if (self->num_recomb_records == self->max_recomb_records) {\n        self->max_recomb_records *= 2;\n        ret = tsk_viterbi_matrix_expand_recomb_records(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    record = self->recombination_required + self->num_recomb_records;\n    record->site = site;\n    record->node = node;\n    record->required = required;\n    self->num_recomb_records++;\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_viterbi_matrix_choose_sample(\n    tsk_viterbi_matrix_t *self, tsk_id_t site, tsk_tree_t *tree)\n{\n    tsk_id_t ret;\n    tsk_id_t u = TSK_NULL;\n    const tsk_flags_t *node_flags = self->matrix.tree_sequence->tables->nodes.flags;\n    const tsk_size_t num_transitions = self->matrix.num_transitions[site];\n    const tsk_id_t *transition_nodes = self->matrix.nodes[site];\n    const double *transition_values = self->matrix.values[site];\n    double max_value = -1;\n    tsk_size_t j;\n    tsk_id_t v;\n    bool found;\n\n    if (num_transitions == 0) {\n        ret = tsk_trace_error(TSK_ERR_NULL_VITERBI_MATRIX);\n        goto out;\n    }\n    for (j = 0; j < num_transitions; j++) {\n        if (max_value < transition_values[j]) {\n            u = transition_nodes[j];\n            max_value = transition_values[j];\n        }\n    }\n    tsk_bug_assert(u != TSK_NULL);\n\n    while (!(node_flags[u] & TSK_NODE_IS_SAMPLE)) {\n        found = false;\n        for (v = tree->left_child[u]; v != TSK_NULL; v = tree->right_sib[v]) {\n            /* Choose the first child that is not in the list of transition nodes */\n            for (j = 0; j < num_transitions; j++) {\n                if (transition_nodes[j] == v) {\n                    break;\n                }\n            }\n            if (j == num_transitions) {\n                u = v;\n                found = true;\n                break;\n            }\n        }\n        /* TODO: should remove this once we're sure this is robust */\n        tsk_bug_assert(found);\n    }\n    ret = u;\nout:\n    return ret;\n}\n\nint\ntsk_viterbi_matrix_traceback(\n    tsk_viterbi_matrix_t *self, tsk_id_t *path, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_site_t site;\n    tsk_id_t u, site_id, current_node;\n    tsk_recomb_required_record *rr_record, *rr_record_tmp;\n    const tsk_id_t num_sites = (tsk_id_t) self->matrix.num_sites;\n    const tsk_id_t num_nodes\n        = (tsk_id_t) tsk_treeseq_get_num_nodes(self->matrix.tree_sequence);\n    tsk_tree_t tree;\n    tsk_id_t *recombination_tree\n        = tsk_malloc((size_t) num_nodes * sizeof(*recombination_tree));\n\n    ret = tsk_tree_init(&tree, self->matrix.tree_sequence, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (recombination_tree == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    /* Initialise the path an recombination_tree to contain TSK_NULL */\n    tsk_memset(path, 0xff, ((size_t) num_sites) * sizeof(*path));\n    tsk_memset(recombination_tree, 0xff, ((size_t) num_nodes) * sizeof(*path));\n\n    current_node = TSK_NULL;\n    rr_record = &self->recombination_required[self->num_recomb_records - 1];\n    ret = tsk_tree_last(&tree);\n    if (ret < 0) {\n        goto out;\n    }\n\n    for (site_id = num_sites - 1; site_id >= 0; site_id--) {\n        ret = tsk_treeseq_get_site(self->matrix.tree_sequence, site_id, &site);\n        if (ret != 0) {\n            goto out;\n        }\n        while (tree.interval.left > site.position) {\n            ret = tsk_tree_prev(&tree);\n            if (ret < 0) {\n                goto out;\n            }\n        }\n        tsk_bug_assert(tree.interval.left <= site.position);\n        tsk_bug_assert(site.position < tree.interval.right);\n\n        /* Fill in the recombination tree */\n        rr_record_tmp = rr_record;\n        while (rr_record->site == site.id) {\n            recombination_tree[rr_record->node] = rr_record->required;\n            rr_record--;\n        }\n        if (current_node == TSK_NULL) {\n            current_node = tsk_viterbi_matrix_choose_sample(self, site.id, &tree);\n            if (current_node < 0) {\n                ret = (int) current_node;\n                goto out;\n            }\n        }\n        path[site.id] = current_node;\n        /* Now traverse up the tree from the current node. The\n         * first marked node tells us whether we need to recombine */\n        u = current_node;\n        while (u != TSK_NULL && recombination_tree[u] == TSK_NULL) {\n            u = tree.parent[u];\n        }\n        tsk_bug_assert(u != TSK_NULL);\n        if (recombination_tree[u] == 1) {\n            /* Switch at the next site */\n            current_node = TSK_NULL;\n        }\n\n        /* Reset in the recombination tree */\n        rr_record = rr_record_tmp;\n        while (rr_record->site == site.id) {\n            recombination_tree[rr_record->node] = TSK_NULL;\n            rr_record--;\n        }\n    }\n    ret = 0;\nout:\n    tsk_tree_free(&tree);\n    tsk_safe_free(recombination_tree);\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/haplotype_matching.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2024 Tskit Developers\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef TSK_HAPLOTYPE_MATCHING_H\n#define TSK_HAPLOTYPE_MATCHING_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <tskit/trees.h>\n\n/* Seems like we might use this somewhere else as well, so putting it into the middle\n * of the flags space */\n#define TSK_ALLELES_ACGT (1 << 16)\n\ntypedef struct {\n    tsk_id_t tree_node;\n    tsk_id_t value_index;\n    double value;\n} tsk_value_transition_t;\n\ntypedef struct {\n    tsk_size_t index;\n    double value;\n} tsk_argsort_t;\n\ntypedef struct {\n    tsk_id_t tree_node;\n    tsk_id_t old_state;\n    tsk_id_t new_state;\n    tsk_id_t transition_parent;\n} tsk_transition_stack_t;\n\ntypedef struct {\n    double normalisation_factor;\n    double *value;\n    tsk_id_t *node;\n    tsk_size_t num_values;\n} tsk_site_probability_t;\n\ntypedef struct {\n    tsk_treeseq_t *tree_sequence;\n    tsk_flags_t options;\n    tsk_size_t num_sites;\n    tsk_size_t num_samples;\n    double *normalisation_factor;\n    tsk_size_t *num_transitions;\n    double **values;\n    tsk_id_t **nodes;\n    tsk_blkalloc_t memory;\n} tsk_compressed_matrix_t;\n\ntypedef struct {\n    tsk_id_t site;\n    tsk_id_t node;\n    bool required;\n} tsk_recomb_required_record;\n\ntypedef struct {\n    tsk_compressed_matrix_t matrix;\n    tsk_recomb_required_record *recombination_required;\n    tsk_size_t num_recomb_records;\n    tsk_size_t max_recomb_records;\n} tsk_viterbi_matrix_t;\n\ntypedef struct _tsk_ls_hmm_t {\n    /* input */\n    tsk_treeseq_t *tree_sequence;\n    double *recombination_rate;\n    double *mutation_rate;\n    const char ***alleles;\n    unsigned int precision;\n    uint32_t *num_alleles;\n    tsk_size_t num_samples;\n    tsk_size_t num_sites;\n    tsk_size_t num_nodes;\n    /* state */\n    tsk_tree_t tree;\n    tsk_id_t *parent;\n    /* The probability value transitions on the tree */\n    tsk_value_transition_t *transitions;\n    tsk_value_transition_t *transitions_copy;\n    /* Stack used when distributing transitions on the tree */\n    tsk_transition_stack_t *transition_stack;\n    /* Map of node_id to index in the transitions list */\n    tsk_id_t *transition_index;\n    /* Buffer used to argsort the transitions by node time */\n    tsk_argsort_t *transition_time_order;\n    tsk_size_t num_transitions;\n    tsk_size_t max_transitions;\n    /* The distinct values in the transitions */\n    double *values;\n    tsk_size_t num_values;\n    tsk_size_t max_values;\n    tsk_size_t max_parsimony_words;\n    /* Number of machine words per node optimal value set. */\n    tsk_size_t num_optimal_value_set_words;\n    uint64_t *optimal_value_sets;\n    /* The parent transition; used during compression */\n    tsk_id_t *transition_parent;\n    /* The number of samples directly subtended by a transition */\n    tsk_size_t *num_transition_samples;\n    int32_t *allelic_state;\n    /* Algorithms set these values before they are run */\n    int (*next_probability)(\n        struct _tsk_ls_hmm_t *, tsk_id_t, double, bool, tsk_id_t, double *);\n    double (*compute_normalisation_factor)(struct _tsk_ls_hmm_t *);\n    void *output;\n} tsk_ls_hmm_t;\n\n/* TODO constify these APIs */\nint tsk_ls_hmm_init(tsk_ls_hmm_t *self, tsk_treeseq_t *tree_sequence,\n    double *recombination_rate, double *mutation_rate, tsk_flags_t options);\nint tsk_ls_hmm_set_precision(tsk_ls_hmm_t *self, unsigned int precision);\nint tsk_ls_hmm_free(tsk_ls_hmm_t *self);\nvoid tsk_ls_hmm_print_state(tsk_ls_hmm_t *self, FILE *out);\nint tsk_ls_hmm_forward(tsk_ls_hmm_t *self, int32_t *haplotype,\n    tsk_compressed_matrix_t *output, tsk_flags_t options);\nint tsk_ls_hmm_backward(tsk_ls_hmm_t *self, int32_t *haplotype,\n    const double *forward_norm, tsk_compressed_matrix_t *output, tsk_flags_t options);\nint tsk_ls_hmm_viterbi(tsk_ls_hmm_t *self, int32_t *haplotype,\n    tsk_viterbi_matrix_t *output, tsk_flags_t options);\n\nint tsk_compressed_matrix_init(tsk_compressed_matrix_t *self,\n    tsk_treeseq_t *tree_sequence, tsk_size_t block_size, tsk_flags_t options);\nint tsk_compressed_matrix_free(tsk_compressed_matrix_t *self);\nint tsk_compressed_matrix_clear(tsk_compressed_matrix_t *self);\nvoid tsk_compressed_matrix_print_state(tsk_compressed_matrix_t *self, FILE *out);\nint tsk_compressed_matrix_store_site(tsk_compressed_matrix_t *self, tsk_id_t site,\n    double normalisation_factor, tsk_size_t num_transitions,\n    const tsk_value_transition_t *transitions);\nint tsk_compressed_matrix_decode(tsk_compressed_matrix_t *self, double *values);\n\nint tsk_viterbi_matrix_init(tsk_viterbi_matrix_t *self, tsk_treeseq_t *tree_sequence,\n    tsk_size_t block_size, tsk_flags_t options);\nint tsk_viterbi_matrix_free(tsk_viterbi_matrix_t *self);\nint tsk_viterbi_matrix_clear(tsk_viterbi_matrix_t *self);\nvoid tsk_viterbi_matrix_print_state(tsk_viterbi_matrix_t *self, FILE *out);\nint tsk_viterbi_matrix_add_recombination_required(\n    tsk_viterbi_matrix_t *self, tsk_id_t site, tsk_id_t node, bool required);\nint tsk_viterbi_matrix_traceback(\n    tsk_viterbi_matrix_t *self, tsk_id_t *path, tsk_flags_t options);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/kastore/kastore.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <errno.h>\n#include <stdbool.h>\n\n#include \"kastore.h\"\n\n/* Private flag used to indicate when we have opened the file ourselves\n * and need to free it. */\n/* Note: we use 1<<14 to keep this flag at the end of the flag space,\n * and this is the highest bit that can be guaranteed to fit into\n * an int. */\n#define OWN_FILE (1 << 14)\n\nconst char *\nkas_strerror(int err)\n{\n    const char *ret = \"Unknown error\";\n\n    switch (err) {\n        case KAS_ERR_GENERIC:\n            ret = \"Generic error; please file a bug report\";\n            break;\n        case KAS_ERR_IO:\n            if (errno != 0) {\n                ret = strerror(errno);\n            } else {\n                ret = \"I/O error with errno unset. Please file a bug report\";\n            }\n            break;\n        case KAS_ERR_BAD_MODE:\n            ret = \"Bad open mode; must be \\\"r\\\", \\\"w\\\", or \\\"a\\\"\";\n            break;\n        case KAS_ERR_BAD_FLAGS:\n            ret = \"Unknown flags specified. Only (KAS_GET_TAKES_OWNERSHIP and/or\"\n                  \"KAS_READ_ALL) or 0 can be specified \"\n                  \"for open, and KAS_BORROWS_ARRAY or 0 for put\";\n            break;\n        case KAS_ERR_NO_MEMORY:\n            ret = \"Out of memory\";\n            break;\n        case KAS_ERR_BAD_FILE_FORMAT:\n            ret = \"File not in KAS format\";\n            break;\n        case KAS_ERR_VERSION_TOO_OLD:\n            ret = \"File format version is too old. Please upgrade using \"\n                  \"'kas upgrade <filename>'\";\n            break;\n        case KAS_ERR_VERSION_TOO_NEW:\n            ret = \"File format version is too new. Please upgrade your \"\n                  \"kastore library version\";\n            break;\n        case KAS_ERR_BAD_TYPE:\n            ret = \"Unknown data type\";\n            break;\n        case KAS_ERR_DUPLICATE_KEY:\n            ret = \"Duplicate key provided\";\n            break;\n        case KAS_ERR_KEY_NOT_FOUND:\n            ret = \"Key not found\";\n            break;\n        case KAS_ERR_EMPTY_KEY:\n            ret = \"Keys cannot be empty\";\n            break;\n        case KAS_ERR_ILLEGAL_OPERATION:\n            ret = \"Cannot perform the requested operation in the current mode\";\n            break;\n        case KAS_ERR_TYPE_MISMATCH:\n            ret = \"Mismatch between requested and stored types for array\";\n            break;\n        case KAS_ERR_EOF:\n            ret = \"End of file\";\n            break;\n    }\n    return ret;\n}\n\nkas_version_t\nkas_version(void)\n{\n    kas_version_t version;\n\n    version.major = KAS_VERSION_MAJOR;\n    version.minor = KAS_VERSION_MINOR;\n    version.patch = KAS_VERSION_PATCH;\n    return version;\n}\n\nstatic size_t\ntype_size(int type)\n{\n    const size_t type_size_map[] = { 1, 1, 2, 2, 4, 4, 8, 8, 4, 8 };\n    assert(type < KAS_NUM_TYPES);\n    return type_size_map[type];\n}\n\n/* Compare item keys lexicographically. */\nstatic int\ncompare_items(const void *a, const void *b)\n{\n    const kaitem_t *ia = (const kaitem_t *) a;\n    const kaitem_t *ib = (const kaitem_t *) b;\n    size_t len = ia->key_len < ib->key_len ? ia->key_len : ib->key_len;\n    int ret = memcmp(ia->key, ib->key, len);\n    if (ret == 0) {\n        ret = (ia->key_len > ib->key_len) - (ia->key_len < ib->key_len);\n    }\n    return ret;\n}\n\n/* When a read error occurs we don't know whether this is because the file\n * ended unexpectedly or an IO error occured. If the file ends unexpectedly\n * this is a file format error.\n */\nstatic int KAS_WARN_UNUSED\nkastore_get_read_io_error(kastore_t *self)\n{\n    int ret = KAS_ERR_IO;\n\n    if (feof(self->file) || errno == 0) {\n        ret = KAS_ERR_BAD_FILE_FORMAT;\n    }\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_write_header(kastore_t *self)\n{\n    int ret = 0;\n    char header[KAS_HEADER_SIZE];\n    uint16_t version_major = KAS_FILE_VERSION_MAJOR;\n    uint16_t version_minor = KAS_FILE_VERSION_MINOR;\n    uint32_t num_items = (uint32_t) self->num_items;\n    uint64_t file_size = (uint64_t) self->file_size;\n\n    memset(header, 0, sizeof(header));\n    memcpy(header, KAS_MAGIC, 8);\n    memcpy(header + 8, &version_major, 2);\n    memcpy(header + 10, &version_minor, 2);\n    memcpy(header + 12, &num_items, 4);\n    memcpy(header + 16, &file_size, 8);\n    /* Rest of header is reserved */\n    if (fwrite(header, KAS_HEADER_SIZE, 1, self->file) != 1) {\n        ret = KAS_ERR_IO;\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_read_header(kastore_t *self)\n{\n    int ret = 0;\n    char header[KAS_HEADER_SIZE];\n    uint16_t version_major, version_minor;\n    uint32_t num_items;\n    uint64_t file_size;\n    size_t count;\n\n    count = fread(header, 1, KAS_HEADER_SIZE, self->file);\n    if (count == 0 && feof(self->file)) {\n        ret = KAS_ERR_EOF;\n        goto out;\n    } else if (count != KAS_HEADER_SIZE) {\n        ret = kastore_get_read_io_error(self);\n        goto out;\n    }\n    if (strncmp(header, KAS_MAGIC, 8) != 0) {\n        ret = KAS_ERR_BAD_FILE_FORMAT;\n        goto out;\n    }\n    memcpy(&version_major, header + 8, 2);\n    memcpy(&version_minor, header + 10, 2);\n    memcpy(&num_items, header + 12, 4);\n    memcpy(&file_size, header + 16, 8);\n    self->file_version[0] = (int) version_major;\n    self->file_version[1] = (int) version_minor;\n    if (self->file_version[0] < KAS_FILE_VERSION_MAJOR) {\n        ret = KAS_ERR_VERSION_TOO_OLD;\n        goto out;\n    } else if (self->file_version[0] > KAS_FILE_VERSION_MAJOR) {\n        ret = KAS_ERR_VERSION_TOO_NEW;\n        goto out;\n    }\n    self->num_items = num_items;\n    self->file_size = (size_t) file_size;\n    if (self->file_size < KAS_HEADER_SIZE) {\n        ret = KAS_ERR_BAD_FILE_FORMAT;\n        goto out;\n    }\nout:\n    return ret;\n}\n\n/* Compute the locations of the keys and arrays in the file. */\nstatic void\nkastore_pack_items(kastore_t *self)\n{\n    size_t j, offset, remainder;\n\n    /* Pack the keys */\n    offset = KAS_HEADER_SIZE + self->num_items * KAS_ITEM_DESCRIPTOR_SIZE;\n    for (j = 0; j < self->num_items; j++) {\n        self->items[j].key_start = offset;\n        offset += self->items[j].key_len;\n    }\n    /* Pack the arrays */\n    for (j = 0; j < self->num_items; j++) {\n        remainder = offset % KAS_ARRAY_ALIGN;\n        if (remainder != 0) {\n            offset += KAS_ARRAY_ALIGN - remainder;\n        }\n        self->items[j].array_start = offset;\n        offset += self->items[j].array_len * type_size(self->items[j].type);\n    }\n    self->file_size = offset;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_write_descriptors(kastore_t *self)\n{\n    int ret = 0;\n    size_t j;\n    uint8_t type;\n    uint64_t key_start, key_len, array_start, array_len;\n    char descriptor[KAS_ITEM_DESCRIPTOR_SIZE];\n\n    for (j = 0; j < self->num_items; j++) {\n        memset(descriptor, 0, KAS_ITEM_DESCRIPTOR_SIZE);\n        type = (uint8_t) self->items[j].type;\n        key_start = (uint64_t) self->items[j].key_start;\n        key_len = (uint64_t) self->items[j].key_len;\n        array_start = (uint64_t) self->items[j].array_start;\n        array_len = (uint64_t) self->items[j].array_len;\n        memcpy(descriptor, &type, 1);\n        /* Bytes 1-8 are reserved */\n        memcpy(descriptor + 8, &key_start, 8);\n        memcpy(descriptor + 16, &key_len, 8);\n        memcpy(descriptor + 24, &array_start, 8);\n        memcpy(descriptor + 32, &array_len, 8);\n        /* Rest of descriptor is reserved */\n        if (fwrite(descriptor, sizeof(descriptor), 1, self->file) != 1) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_read_descriptors(kastore_t *self)\n{\n    int ret = KAS_ERR_BAD_FILE_FORMAT;\n    size_t j;\n    uint8_t type;\n    uint64_t key_start, key_len, array_start, array_len;\n    char *descriptor;\n    size_t descriptor_offset, offset, remainder, size, count;\n    char *read_buffer = NULL;\n\n    size = self->num_items * KAS_ITEM_DESCRIPTOR_SIZE;\n    if (size + KAS_HEADER_SIZE > self->file_size) {\n        goto out;\n    }\n    read_buffer = (char *) malloc(size);\n    if (read_buffer == NULL) {\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    count = fread(read_buffer, size, 1, self->file);\n    if (count == 0) {\n        ret = kastore_get_read_io_error(self);\n        goto out;\n    }\n\n    descriptor_offset = 0;\n    for (j = 0; j < self->num_items; j++) {\n        descriptor = read_buffer + descriptor_offset;\n        descriptor_offset += KAS_ITEM_DESCRIPTOR_SIZE;\n        memcpy(&type, descriptor, 1);\n        memcpy(&key_start, descriptor + 8, 8);\n        memcpy(&key_len, descriptor + 16, 8);\n        memcpy(&array_start, descriptor + 24, 8);\n        memcpy(&array_len, descriptor + 32, 8);\n\n        if (type >= KAS_NUM_TYPES) {\n            ret = KAS_ERR_BAD_TYPE;\n            goto out;\n        }\n        self->items[j].type = (int) type;\n        if (key_start + key_len > self->file_size) {\n            goto out;\n        }\n        self->items[j].key_start = (size_t) key_start;\n        self->items[j].key_len = (size_t) key_len;\n        if (array_start + array_len * type_size(type) > self->file_size) {\n            goto out;\n        }\n        self->items[j].array_start = (size_t) array_start;\n        self->items[j].array_len = (size_t) array_len;\n    }\n\n    /* Check the integrity of the key and array packing. Keys must\n     * be packed sequentially starting immediately after the descriptors. */\n    offset = KAS_HEADER_SIZE + self->num_items * KAS_ITEM_DESCRIPTOR_SIZE;\n    for (j = 0; j < self->num_items; j++) {\n        if (self->items[j].key_start != offset) {\n            ret = KAS_ERR_BAD_FILE_FORMAT;\n            goto out;\n        }\n        offset += self->items[j].key_len;\n    }\n    for (j = 0; j < self->num_items; j++) {\n        /* Arrays are 8 byte aligned and adjacent */\n        remainder = offset % KAS_ARRAY_ALIGN;\n        if (remainder != 0) {\n            offset += KAS_ARRAY_ALIGN - remainder;\n        }\n        if (self->items[j].array_start != offset) {\n            ret = KAS_ERR_BAD_FILE_FORMAT;\n            goto out;\n        }\n        offset += self->items[j].array_len * type_size(self->items[j].type);\n    }\n    if (offset != self->file_size) {\n        ret = KAS_ERR_BAD_FILE_FORMAT;\n        goto out;\n    }\n    ret = 0;\nout:\n    kas_safe_free(read_buffer);\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_write_data(kastore_t *self)\n{\n    int ret = 0;\n    size_t j, size, offset, padding;\n    char pad[KAS_ARRAY_ALIGN] = { 0, 0, 0, 0, 0, 0, 0 };\n    const void *write_array;\n\n    offset = KAS_HEADER_SIZE + self->num_items * KAS_ITEM_DESCRIPTOR_SIZE;\n\n    /* Write the keys. */\n    for (j = 0; j < self->num_items; j++) {\n        assert(offset == self->items[j].key_start);\n        if (fwrite(self->items[j].key, self->items[j].key_len, 1, self->file) != 1) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n        offset += self->items[j].key_len;\n    }\n    /* Write the arrays. */\n    for (j = 0; j < self->num_items; j++) {\n        padding = self->items[j].array_start - offset;\n        assert(padding < KAS_ARRAY_ALIGN);\n        if (padding > 0 && fwrite(pad, padding, 1, self->file) != 1) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n        size = self->items[j].array_len * type_size(self->items[j].type);\n        write_array = self->items[j].borrowed_array != NULL\n                          ? self->items[j].borrowed_array\n                          : self->items[j].array;\n        assert(write_array != NULL);\n        if (size > 0 && fwrite(write_array, size, 1, self->file) != 1) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n        offset = self->items[j].array_start + size;\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_read_file(kastore_t *self)\n{\n    int ret = 0;\n    size_t count, size, offset, j;\n    bool read_all = !!(self->flags & KAS_READ_ALL);\n\n    offset = KAS_HEADER_SIZE + self->num_items * KAS_ITEM_DESCRIPTOR_SIZE;\n\n    /* Read in up to the start of first array. This will contain all the keys. */\n    size = self->items[0].array_start;\n\n    assert(size > offset);\n    size -= offset;\n\n    self->key_read_buffer = (char *) malloc(size);\n    if (self->key_read_buffer == NULL) {\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    count = fread(self->key_read_buffer, size, 1, self->file);\n    if (count == 0) {\n        ret = kastore_get_read_io_error(self);\n        goto out;\n    }\n    /* Assign the pointers for the keys and arrays */\n    for (j = 0; j < self->num_items; j++) {\n        /* keys are already loaded in the read buffer */\n        self->items[j].key = self->key_read_buffer + self->items[j].key_start - offset;\n        if (read_all) {\n            if (j == self->num_items - 1) {\n                size = self->file_size - self->items[j].array_start;\n            } else {\n                size = self->items[j + 1].array_start - self->items[j].array_start;\n            }\n            self->items[j].array = (char *) malloc(size == 0 ? 1 : size);\n            if (self->items[j].array == NULL) {\n                ret = KAS_ERR_NO_MEMORY;\n                goto out;\n            }\n            if (size > 0) {\n                count = fread(self->items[j].array, size, 1, self->file);\n                if (count == 0) {\n                    ret = kastore_get_read_io_error(self);\n                    goto out;\n                }\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_read_item(kastore_t *self, kaitem_t *item)\n{\n    int ret = 0;\n    int err;\n    size_t size = item->array_len * type_size(item->type);\n    size_t count;\n\n    item->array = malloc(size == 0 ? 1 : size);\n    if (item->array == NULL) {\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    if (size > 0) {\n        err = fseek(self->file, self->file_offset + (long) item->array_start, SEEK_SET);\n        if (err != 0) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n        count = fread(item->array, size, 1, self->file);\n        if (count == 0) {\n            ret = kastore_get_read_io_error(self);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_write_file(kastore_t *self)\n{\n    int ret = 0;\n\n    qsort(self->items, self->num_items, sizeof(kaitem_t), compare_items);\n    kastore_pack_items(self);\n    ret = kastore_write_header(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = kastore_write_descriptors(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = kastore_write_data(self);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_read(kastore_t *self)\n{\n    int ret = 0;\n\n    if (!(self->flags & KAS_READ_ALL)) {\n        /* Record the current file offset, in case this is a multi-store file,\n         * so that we can seek to the correct location in kastore_read_item().\n         */\n        self->file_offset = ftell(self->file);\n        if (self->file_offset == -1) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n    }\n    ret = kastore_read_header(self);\n    if (ret != 0) {\n        goto out;\n    }\n    if (self->num_items > 0) {\n        self->items = (kaitem_t *) calloc(self->num_items, sizeof(*self->items));\n        if (self->items == NULL) {\n            ret = KAS_ERR_NO_MEMORY;\n            goto out;\n        }\n        ret = kastore_read_descriptors(self);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = kastore_read_file(self);\n        if (ret != 0) {\n            goto out;\n        }\n    } else if (self->file_size != KAS_HEADER_SIZE) {\n        ret = KAS_ERR_BAD_FILE_FORMAT;\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_insert_all(kastore_t *self, kastore_t *other)\n{\n    size_t j;\n    int ret = 0;\n    kaitem_t item;\n\n    for (j = 0; j < other->num_items; j++) {\n        item = other->items[j];\n        ret = kastore_put(\n            self, item.key, item.key_len, item.array, item.array_len, item.type, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_open(kastore_t *self, const char *filename, const char *mode, int flags)\n{\n    int ret = 0;\n    const char *file_mode;\n    bool appending = false;\n    kastore_t tmp;\n    FILE *file;\n    int err;\n\n    memset(self, 0, sizeof(*self));\n    memset(&tmp, 0, sizeof(tmp));\n    if (strlen(mode) != 1) {\n        ret = KAS_ERR_BAD_MODE;\n        goto out;\n    }\n    if (strncmp(mode, \"r\", 1) == 0) {\n        file_mode = \"rb\";\n    } else if (strncmp(mode, \"w\", 1) == 0) {\n        file_mode = \"wb\";\n    } else if (strncmp(mode, \"a\", 1) == 0) {\n        mode = \"w\";\n        file_mode = \"wb\";\n        appending = true;\n    } else {\n        ret = KAS_ERR_BAD_MODE;\n        goto out;\n    }\n    if (appending) {\n        ret = kastore_open(&tmp, filename, \"r\", KAS_READ_ALL);\n        if (ret != 0) {\n            goto out;\n        }\n        /* tmp will now have read all of the data into memory. We can now\n         * close its file. We have to do this for Windows. */\n        err = fclose(tmp.file);\n        tmp.file = NULL;\n        if (err != 0) {\n            ret = KAS_ERR_IO;\n            goto out;\n        }\n    }\n    file = fopen(filename, file_mode);\n    if (file == NULL) {\n        ret = KAS_ERR_IO;\n        goto out;\n    }\n    ret = kastore_openf(self, file, mode, flags);\n    if (ret != 0) {\n        (void) fclose(file);\n    } else {\n        self->flags |= OWN_FILE;\n        if (appending) {\n            ret = kastore_insert_all(self, &tmp);\n        }\n    }\nout:\n    if (appending) {\n        kastore_close(&tmp);\n    }\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_openf(kastore_t *self, FILE *file, const char *mode, int flags)\n{\n    int ret = 0;\n\n    memset(self, 0, sizeof(*self));\n    if (strlen(mode) != 1) {\n        ret = KAS_ERR_BAD_MODE;\n        goto out;\n    }\n    if (strncmp(mode, \"r\", 1) == 0) {\n        self->mode = KAS_READ;\n    } else if (strncmp(mode, \"w\", 1) == 0) {\n        self->mode = KAS_WRITE;\n    } else {\n        ret = KAS_ERR_BAD_MODE;\n        goto out;\n    }\n\n    if (flags > (KAS_READ_ALL | KAS_GET_TAKES_OWNERSHIP) || flags < 0) {\n        ret = KAS_ERR_BAD_FLAGS;\n        goto out;\n    }\n\n    self->flags = flags;\n    self->file = file;\n    if (self->mode == KAS_READ) {\n        ret = kastore_read(self);\n    }\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_close(kastore_t *self)\n{\n    int ret = 0;\n    int err;\n    size_t j;\n\n    if (self->mode == KAS_WRITE) {\n        if (self->file != NULL) {\n            ret = kastore_write_file(self);\n            if (ret != 0) {\n                /* Ignore errors on close now */\n                if (self->flags & OWN_FILE) {\n                    fclose(self->file);\n                }\n                self->file = NULL;\n            }\n        }\n        if (self->items != NULL) {\n            /* We only alloc memory for the keys and arrays in write mode */\n            for (j = 0; j < self->num_items; j++) {\n                kas_safe_free(self->items[j].key);\n                kas_safe_free(self->items[j].array);\n            }\n        }\n    } else {\n        kas_safe_free(self->key_read_buffer);\n        if (self->items != NULL) {\n            for (j = 0; j < self->num_items; j++) {\n                kas_safe_free(self->items[j].array);\n            }\n        }\n    }\n    kas_safe_free(self->items);\n    if (self->file != NULL && (self->flags & OWN_FILE)) {\n        err = fclose(self->file);\n        if (err != 0) {\n            ret = KAS_ERR_IO;\n        }\n    }\n    memset(self, 0, sizeof(*self));\n    return ret;\n}\n\nstatic int\nkastore_find_item(kastore_t *self, const char *key, size_t key_len, kaitem_t **item)\n{\n    int ret = KAS_ERR_KEY_NOT_FOUND;\n    kaitem_t search;\n    search.key = (char *) malloc(key_len);\n    search.key_len = key_len;\n\n    if (self->mode != KAS_READ) {\n        ret = KAS_ERR_ILLEGAL_OPERATION;\n        goto out;\n    }\n    if (search.key == NULL) {\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    memcpy(search.key, key, key_len);\n    *item = bsearch(\n        &search, self->items, self->num_items, sizeof(kaitem_t), compare_items);\n    if (*item == NULL) {\n        goto out;\n    }\n    ret = 0;\nout:\n    kas_safe_free(search.key);\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_contains(kastore_t *self, const char *key, size_t key_len)\n{\n    kaitem_t *item;\n    int ret = kastore_find_item(self, key, key_len, &item);\n    if (ret == 0) {\n        ret = 1;\n    } else if (ret == KAS_ERR_KEY_NOT_FOUND) {\n        ret = 0;\n    }\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_containss(kastore_t *self, const char *key)\n{\n    return kastore_contains(self, key, strlen(key));\n}\n\nint KAS_WARN_UNUSED\nkastore_get(kastore_t *self, const char *key, size_t key_len, void **array,\n    size_t *array_len, int *type)\n{\n    kaitem_t *item;\n    int ret = kastore_find_item(self, key, key_len, &item);\n    if (ret != 0) {\n        goto out;\n    }\n    if (item->array == NULL) {\n        ret = kastore_read_item(self, item);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    *array = item->array;\n    *array_len = item->array_len;\n    *type = item->type;\n    if (self->flags & KAS_GET_TAKES_OWNERSHIP) {\n        item->array = NULL;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_gets(\n    kastore_t *self, const char *key, void **array, size_t *array_len, int *type)\n{\n    return kastore_get(self, key, strlen(key), array, array_len, type);\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_gets_type(\n    kastore_t *self, const char *key, void **array, size_t *array_len, int type)\n{\n    int loaded_type = -1;\n    int ret;\n\n    ret = kastore_get(self, key, strlen(key), array, array_len, &loaded_type);\n    if (ret != 0) {\n        goto out;\n    }\n    if (type != loaded_type) {\n        ret = KAS_ERR_TYPE_MISMATCH;\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_int8(kastore_t *self, const char *key, int8_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_INT8);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_uint8(kastore_t *self, const char *key, uint8_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_UINT8);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_int16(kastore_t *self, const char *key, int16_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_INT16);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_uint16(\n    kastore_t *self, const char *key, uint16_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_UINT16);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_int32(kastore_t *self, const char *key, int32_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_INT32);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_uint32(\n    kastore_t *self, const char *key, uint32_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_UINT32);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_int64(kastore_t *self, const char *key, int64_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_INT64);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_uint64(\n    kastore_t *self, const char *key, uint64_t **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_UINT64);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_float32(kastore_t *self, const char *key, float **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_FLOAT32);\n}\n\nint KAS_WARN_UNUSED\nkastore_gets_float64(kastore_t *self, const char *key, double **array, size_t *array_len)\n{\n    return kastore_gets_type(self, key, (void **) array, array_len, KAS_FLOAT64);\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_put_item(kastore_t *self, kaitem_t **ret_item, const char *key, size_t key_len,\n    int type, int KAS_UNUSED(flags))\n{\n    int ret = 0;\n    kaitem_t *new_item;\n    kaitem_t *p;\n    size_t j;\n\n    if (self->mode != KAS_WRITE) {\n        ret = KAS_ERR_ILLEGAL_OPERATION;\n        goto out;\n    }\n    if (type < 0 || type >= KAS_NUM_TYPES) {\n        ret = KAS_ERR_BAD_TYPE;\n        goto out;\n    }\n    if (key_len == 0) {\n        ret = KAS_ERR_EMPTY_KEY;\n        goto out;\n    }\n    /* This isn't terribly efficient, but we're not expecting large\n     * numbers of items. */\n    p = (kaitem_t *) realloc(self->items, (self->num_items + 1) * sizeof(*self->items));\n    if (p == NULL) {\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    self->items = p;\n    new_item = self->items + self->num_items;\n\n    memset(new_item, 0, sizeof(*new_item));\n    new_item->type = type;\n    new_item->key_len = key_len;\n    new_item->key = (char *) malloc(key_len);\n    if (new_item->key == NULL) {\n        kas_safe_free(new_item->key);\n        ret = KAS_ERR_NO_MEMORY;\n        goto out;\n    }\n    self->num_items++;\n    memcpy(new_item->key, key, key_len);\n\n    /* Check if this key is already in here. OK, this is a quadratic time\n     * algorithm, but we're not expecting to have lots of items (< 100). In\n     * this case, the simple algorithm is probably better. If/when we ever\n     * deal with more items than this, then we will need a better algorithm.\n     */\n    for (j = 0; j < self->num_items - 1; j++) {\n        if (compare_items(new_item, self->items + j) == 0) {\n            /* Free the key memory and remove this item */\n            self->num_items--;\n            kas_safe_free(new_item->key);\n            ret = KAS_ERR_DUPLICATE_KEY;\n            goto out;\n        }\n    }\n    *ret_item = new_item;\nout:\n    return ret;\n}\n\nstatic int KAS_WARN_UNUSED\nkastore_bput(kastore_t *self, const char *key, size_t key_len, const void *array,\n    size_t array_len, int type, int flags)\n{\n    int ret = 0;\n    kaitem_t *item;\n    ret = kastore_put_item(self, &item, key, key_len, type, flags);\n    if (ret != 0) {\n        goto out;\n    }\n    if (array == NULL) {\n        /* Both can't be null, so assign a dummy array */\n        item->array = malloc(1);\n    } else {\n        item->borrowed_array = array;\n    }\n    item->borrowed_array = array;\n    item->array_len = array_len;\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_put(kastore_t *self, const char *key, size_t key_len, const void *array,\n    size_t array_len, int type, int flags)\n{\n    int ret;\n    size_t array_size;\n    void *array_copy = NULL;\n\n    if (flags != KAS_BORROWS_ARRAY && flags != 0) {\n        ret = KAS_ERR_BAD_FLAGS;\n        goto out;\n    }\n\n    if (type < 0 || type >= KAS_NUM_TYPES) {\n        ret = KAS_ERR_BAD_TYPE;\n        goto out;\n    }\n    if (flags & KAS_BORROWS_ARRAY) {\n        ret = kastore_bput(self, key, key_len, array, array_len, type, flags);\n    } else {\n        array_size = type_size(type) * array_len;\n        array_copy = malloc(array_size == 0 ? 1 : array_size);\n        if (array_copy == NULL) {\n            ret = KAS_ERR_NO_MEMORY;\n            goto out;\n        }\n        memcpy(array_copy, array, array_size);\n        ret = kastore_oput(self, key, key_len, array_copy, array_len, type, flags);\n        if (ret == 0) {\n            /* Kastore has taken ownership of the array, so we don't need to free it */\n            array_copy = NULL;\n        }\n    }\nout:\n    kas_safe_free(array_copy);\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_oput(kastore_t *self, const char *key, size_t key_len, void *array,\n    size_t array_len, int type, int flags)\n{\n    int ret = 0;\n    kaitem_t *item;\n\n    if (flags != 0) {\n        ret = KAS_ERR_BAD_FLAGS;\n        goto out;\n    }\n\n    ret = kastore_put_item(self, &item, key, key_len, type, flags);\n    if (ret != 0) {\n        goto out;\n    }\n    item->array = array;\n    item->array_len = array_len;\nout:\n    return ret;\n}\n\nint KAS_WARN_UNUSED\nkastore_puts(kastore_t *self, const char *key, const void *array, size_t array_len,\n    int type, int flags)\n{\n    return kastore_put(self, key, strlen(key), array, array_len, type, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_int8(\n    kastore_t *self, const char *key, const int8_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_INT8, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_uint8(\n    kastore_t *self, const char *key, const uint8_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_UINT8, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_int16(\n    kastore_t *self, const char *key, const int16_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_INT16, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_uint16(\n    kastore_t *self, const char *key, const uint16_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_UINT16, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_int32(\n    kastore_t *self, const char *key, const int32_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_INT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_uint32(\n    kastore_t *self, const char *key, const uint32_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_UINT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_int64(\n    kastore_t *self, const char *key, const int64_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_INT64, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_uint64(\n    kastore_t *self, const char *key, const uint64_t *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_UINT64, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_float32(\n    kastore_t *self, const char *key, const float *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_FLOAT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_puts_float64(\n    kastore_t *self, const char *key, const double *array, size_t array_len, int flags)\n{\n    return kastore_puts(self, key, (const void *) array, array_len, KAS_FLOAT64, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs(\n    kastore_t *self, const char *key, void *array, size_t array_len, int type, int flags)\n{\n    return kastore_oput(self, key, strlen(key), array, array_len, type, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_int8(\n    kastore_t *self, const char *key, int8_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_INT8, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_uint8(\n    kastore_t *self, const char *key, uint8_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT8, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_int16(\n    kastore_t *self, const char *key, int16_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_INT16, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_uint16(\n    kastore_t *self, const char *key, uint16_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT16, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_int32(\n    kastore_t *self, const char *key, int32_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_INT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_uint32(\n    kastore_t *self, const char *key, uint32_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_int64(\n    kastore_t *self, const char *key, int64_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_INT64, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_uint64(\n    kastore_t *self, const char *key, uint64_t *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_UINT64, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_float32(\n    kastore_t *self, const char *key, float *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_FLOAT32, flags);\n}\n\nint KAS_WARN_UNUSED\nkastore_oputs_float64(\n    kastore_t *self, const char *key, double *array, size_t array_len, int flags)\n{\n    return kastore_oputs(self, key, (void *) array, array_len, KAS_FLOAT64, flags);\n}\n\nvoid\nkastore_print_state(kastore_t *self, FILE *out)\n{\n    kaitem_t *item;\n    size_t j;\n\n    fprintf(out, \"============================\\n\");\n    fprintf(out, \"kastore state\\n\");\n    fprintf(out, \"file_version = %d.%d\\n\", self->file_version[0], self->file_version[1]);\n    fprintf(out, \"mode  = %d\\n\", self->mode);\n    fprintf(out, \"flags = %d\\n\", self->flags);\n    fprintf(out, \"num_items = %zu\\n\", self->num_items);\n    fprintf(out, \"file_size = %zu\\n\", self->file_size);\n    fprintf(out, \"own_file  = %d\\n\", !!(self->flags & OWN_FILE));\n    fprintf(out, \"file = '%p'\\n\", (void *) self->file);\n    fprintf(out, \"============================\\n\");\n    for (j = 0; j < self->num_items; j++) {\n        item = self->items + j;\n        fprintf(out,\n            \"%.*s: type=%d, key_start=%zu, key_len=%zu, key=%p, \"\n            \"array_start=%zu, array_len=%zu, array=%p\\n\",\n            (int) item->key_len, item->key, item->type, item->key_start, item->key_len,\n            (void *) item->key, item->array_start, item->array_len,\n            (void *) item->array);\n    }\n    fprintf(out, \"============================\\n\");\n}\n"
  },
  {
    "path": "treerec/tskit/kastore/kastore.h",
    "content": "/**\n * @file kastore.h\n * @brief Public API for kastore.\n *\n * This is the API documentation for kastore.\n */\n#ifndef KASTORE_H\n#define KASTORE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef __GNUC__\n#define KAS_WARN_UNUSED __attribute__((warn_unused_result))\n#define KAS_UNUSED(x) KAS_UNUSED_##x __attribute__((__unused__))\n#else\n#define KAS_WARN_UNUSED\n#define KAS_UNUSED(x) KAS_UNUSED_##x\n#endif\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <stdio.h>\n\n/**\n@defgroup ERROR_GROUP Error return values.\n@{\n*/\n// clang-format off\n/**\nGeneric error thrown when no other message can be generated.\n*/\n#define KAS_ERR_GENERIC                               -1\n/**\nAn error occured during IO.\n*/\n#define KAS_ERR_IO                                    -2\n/**\nAn unrecognised mode string was passed to open().\n*/\n#define KAS_ERR_BAD_MODE                              -3\n/**\nOut-of-memory condition.\n*/\n#define KAS_ERR_NO_MEMORY                             -4\n/**\nAttempt to read an unknown file format.\n*/\n#define KAS_ERR_BAD_FILE_FORMAT                       -5\n/**\nThe file is in kastore format, but the version is too old for this\nversion of the library to read.\n*/\n#define KAS_ERR_VERSION_TOO_OLD                       -6\n/**\nThe file is in kastore format, but the version is too new for this\nversion of the library to read.\n*/\n#define KAS_ERR_VERSION_TOO_NEW                       -7\n/**\nAn unknown type key was specified.\n*/\n#define KAS_ERR_BAD_TYPE                              -8\n/**\nA zero-length key was specified.\n*/\n#define KAS_ERR_EMPTY_KEY                             -9\n/**\nA duplicate key was specified.\n*/\n#define KAS_ERR_DUPLICATE_KEY                         -10\n/**\nThe requested key does not exist in the store.\n*/\n#define KAS_ERR_KEY_NOT_FOUND                         -11\n/**\nThe requestion function cannot be called in the current mode.\n*/\n#define KAS_ERR_ILLEGAL_OPERATION                     -12\n/**\nThe requested type does not match the type of the stored values.\n*/\n#define KAS_ERR_TYPE_MISMATCH                         -13\n/**\nEnd of file was reached while reading data.\n*/\n#define KAS_ERR_EOF                                   -14\n/**\nUnknown flags were provided to open.\n*/\n#define KAS_ERR_BAD_FLAGS                             -15\n/** @} */\n\n/* Flags for open */\n#define KAS_READ_ALL                       (1 << 0)\n#define KAS_GET_TAKES_OWNERSHIP            (1 << 1)\n\n/* Flags for put */\n#define KAS_BORROWS_ARRAY          (1 << 8)\n\n\n/**\n@defgroup TYPE_GROUP Data types.\n@{\n*/\n#define KAS_INT8                0\n#define KAS_UINT8               1\n#define KAS_INT16               2\n#define KAS_UINT16              3\n#define KAS_INT32               4\n#define KAS_UINT32              5\n#define KAS_INT64               6\n#define KAS_UINT64              7\n#define KAS_FLOAT32             8\n#define KAS_FLOAT64             9\n/** @} */\n\n#define KAS_NUM_TYPES           10\n\n#define KAS_READ                1\n#define KAS_WRITE               2\n\n/**\n@defgroup FILE_VERSION_GROUP File version macros.\n@{\n*/\n/**\nThe file version major number. Incremented when any breaking changes are made\nto the file format.\n*/\n#define KAS_FILE_VERSION_MAJOR  1\n/**\nThe file version minor number. Incremented when non-breaking backward-compatible\nchanges are made to the file format.\n*/\n#define KAS_FILE_VERSION_MINOR  0\n/** @} */\n\n/**\n@defgroup API_VERSION_GROUP API version macros.\n@{\n*/\n/**\nThe library major version. Incremented when breaking changes to the API or ABI are\nintroduced. This includes any changes to the signatures of functions and the\nsizes and types of externally visible structs.\n*/\n#define KAS_VERSION_MAJOR   2\n/**\nThe library minor version. Incremented when non-breaking backward-compatible changes\nto the API or ABI are introduced, i.e., the addition of a new function.\n*/\n#define KAS_VERSION_MINOR   1\n/**\nThe library patch version. Incremented when any changes not relevant to the\nto the API or ABI are introduced, i.e., internal refactors of bugfixes.\n*/\n#define KAS_VERSION_PATCH   1\n/** @} */\n\n#define KAS_HEADER_SIZE             64\n#define KAS_ITEM_DESCRIPTOR_SIZE    64\n#define KAS_MAGIC                   \"\\211KAS\\r\\n\\032\\n\"\n#define KAS_ARRAY_ALIGN             8\n// clang-format on\n\n#ifndef KAS_BUG_ASSERT_MESSAGE\n#define KAS_BUG_ASSERT_MESSAGE                                                          \\\n    \"If you are using kastore directly please open an issue on\"                         \\\n    \" GitHub, ideally with a reproducible example.\"                                     \\\n    \" (https://github.com/tskit-dev/kastore/issues) If you are\"                         \\\n    \" using software that uses kastore, please report an issue\"                         \\\n    \" to that software's issue tracker, at least initially.\"\n#endif\n\n/**\nWe often wish to assert a condition that is unexpected, but using the normal `assert`\nmeans compiling without NDEBUG. This macro still asserts when NDEBUG is defined.\n*/\n#define kas_bug_assert(condition)                                                       \\\n    do {                                                                                \\\n        if (!(condition)) {                                                             \\\n            fprintf(stderr, \"Bug detected in %s at line %d. %s\\n\", __FILE__, __LINE__,  \\\n                KAS_BUG_ASSERT_MESSAGE);                                                \\\n            abort();                                                                    \\\n        }                                                                               \\\n    } while (0)\n\ntypedef struct {\n    int type;\n    size_t key_len;\n    size_t array_len;\n    char *key;\n    /* Used when KAS_BORROWS_ARRAY is set */\n    const void *borrowed_array;\n    void *array;\n    size_t key_start;\n    size_t array_start;\n} kaitem_t;\n\n/**\n@brief A file-backed store of key-array values.\n*/\ntypedef struct {\n    int flags;\n    int mode;\n    int file_version[2];\n    size_t num_items;\n    kaitem_t *items;\n    FILE *file;\n    size_t file_size;\n    long file_offset;\n    char *key_read_buffer;\n} kastore_t;\n\n/**\n@brief Library version information.\n*/\ntypedef struct {\n    /** @brief The major version number. */\n    int major;\n    /** @brief The minor version number. */\n    int minor;\n    /** @brief The patch version number. */\n    int patch;\n} kas_version_t;\n\n/**\n@brief Open a store from a given file in read (\"r\"), write (\"w\") or\nappend (\"a\") mode.\n\n@rst\nIn read mode, a store can be queried using the :ref:`get functions\n<sec_c_api_get>` and any attempts to write to the store will return an error.\nIn write and append mode, the store can written to using the :ref:`put\nfunctions <sec_c_api_put>` and any attempt to read will return an error.\n\nAfter :c:func:`kastore_open` has been called on a particular store,\n:c:func:`kastore_close` must be called to avoid leaking memory. This must also\nbe done when :c:func:`kastore_open` returns an error.\n\nWhen opened in read-mode, the default is to read key/array values from file\non demand. This is useful when a subset of the data is required and we don't\nwish to read the entire file. If the entire file is to be read, the\n``KAS_READ_ALL`` flag may be specified to improve performance.\n\n**Flags**\n\nKAS_READ_ALL\n    If this option is specified, read the entire file at\n    open time. This will give slightly better performance as the file can\n    be read sequentially in a single pass.\n\nKAS_GET_TAKES_OWNERSHIP\n    If this option is specified, all ``get`` operations will transfer\n    ownership of the array to the caller. ``kastore`` will not ``free``\n    the array memory and this is the responsibility of the caller.\n    If ``get`` is called on the same key multiple times, a new buffer will be\n    returned each time. Note that second and subsequent ``get`` calls\n    on a given key will result in ``seek`` operations even when the\n    KAS_READ_ALL flag is set, and will therefore fail on unseekable\n    streams.\n\n@endrst\n\n@param self A pointer to a kastore object.\n@param filename The file path to open.\n@param mode The open mode: can be read (\"r\"), write (\"w\") or append (\"a\").\n@param flags The open flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_open(kastore_t *self, const char *filename, const char *mode, int flags);\n\n/**\n@brief Open a store from a given FILE pointer.\n\n@rst\nBehaviour, mode and flags follow that of :c:func:`kastore_open`,\nexcept append mode is not supported.\nThe ``file`` argument must be opened in an appropriate mode (e.g. \"r\"\nfor a kastore in \"r\" mode).  Files open with other modes will result\nin KAS_ERR_IO being returned when read/write operations are attempted.\n\nThe FILE will not be closed when :c:func:`kastore_close` is called.\nIf the KAS_READ_ALL flag is supplied, no ``seek`` operations will be\nperformed on the FILE and so streams such as stdin, FIFOs etc are\nsupported. The FILE pointer will be positioned exactly at the end\nof the kastore encoded bytes once reading is completed, and reading\nmultiple stores from the same FILE sequentially is fully supported.\n@endrst\n\n@param self A pointer to a kastore object.\n@param file The FILE* to read/write the store from/to.\n@param mode The open mode: can be read (\"r\") or write (\"w\").\n@param flags The open flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_openf(kastore_t *self, FILE *file, const char *mode, int flags);\n\n/**\n@brief Close an opened store, freeing all resources.\n\nAny store that has been opened must be closed to avoid memory leaks\n(including cases in which errors have occured). It is not an error to\ncall ``kastore_close`` multiple times on the same object, but\n``kastore_open`` must be called before ``kastore_close``.\n\n@param self A pointer to a kastore object.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_close(kastore_t *self);\n\n/**\n@brief Return 1 if the store contains the specified key and 0 if it does not.\n\n@rst\nQueries the store for the specified key and returns 1 if it exists. If the\nkey does not exist, 0 is returned. If an error occurs (for example, if querying\nthe store while it is in write-mode), a negative value is returned.\n\nFor keys that are standard NULL terminated strings, the :c:func:`kastore_containss`\nfunction may be more convenient.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param key_len The length of the key.\n@return Return 1 if the key is present and 0 if it does not. If an error occurs,\n    return a negative value.\n*/\nint kastore_contains(kastore_t *self, const char *key, size_t key_len);\n\n/**\n@brief Return 1 if the store contains the specified NULL terminated key\nand 0 if it does not.\n\n@rst\nQueries the store for the specified key, which must be a NULL terminated string,\nand returns 1 if it exists. If the\nkey does not exist, 0 is returned. If an error occurs (for example, if querying\nthe store while it is in write-mode), a negative value is returned.\nthe array in the specified destination pointers.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@return Return 1 if the key is present and 0 if it does not. If an error occurs,\n    return a negative value.\n*/\nint kastore_containss(kastore_t *self, const char *key);\n\n/**\n@brief Get the array for the specified key.\n\n@rst\nQueries the store for the specified key and stores pointers to the memory for\nthe corresponding array, the number of elements in this array and the type of\nthe array in the specified destination pointers. This is the most general form\nof ``get`` query in kastore, as non NULL-terminated strings can be used as\nkeys and the resulting array is returned in a generic pointer. When standard C\nstrings are used as keys and the type of the array is known, it is more\nconvenient to use the :ref:`typed variants <sec_c_api_typed_get>` of this function.\n\nThe returned array points to memory that is internally managed by the store\nand must not be freed or modified. The pointer is guaranteed to be valid\nuntil :c:func:`kastore_close` is called.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param key_len The length of the key.\n@param array The destination pointer for the array.\n@param array_len The destination pointer for the number of elements\nin the array.\n@param type The destination pointer for the type code of the array.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_get(kastore_t *self, const char *key, size_t key_len, void **array,\n    size_t *array_len, int *type);\n\n/**\n@brief Get the array for the specified NULL-terminated key.\n\n@rst\nAs for :c:func:`kastore_get()` except the key is a NULL-terminated string.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param array The destination pointer for the array.\n@param array_len The destination pointer for the number of elements\nin the array.\n@param type The destination pointer for the type code of the array.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_gets(\n    kastore_t *self, const char *key, void **array, size_t *array_len, int *type);\n\n/**\n@defgroup TYPED_GETS_GROUP Typed get functions.\n@{\n*/\n\nint kastore_gets_int8(\n    kastore_t *self, const char *key, int8_t **array, size_t *array_len);\nint kastore_gets_uint8(\n    kastore_t *self, const char *key, uint8_t **array, size_t *array_len);\nint kastore_gets_int16(\n    kastore_t *self, const char *key, int16_t **array, size_t *array_len);\nint kastore_gets_uint16(\n    kastore_t *self, const char *key, uint16_t **array, size_t *array_len);\nint kastore_gets_int32(\n    kastore_t *self, const char *key, int32_t **array, size_t *array_len);\nint kastore_gets_uint32(\n    kastore_t *self, const char *key, uint32_t **array, size_t *array_len);\nint kastore_gets_int64(\n    kastore_t *self, const char *key, int64_t **array, size_t *array_len);\nint kastore_gets_uint64(\n    kastore_t *self, const char *key, uint64_t **array, size_t *array_len);\nint kastore_gets_float32(\n    kastore_t *self, const char *key, float **array, size_t *array_len);\nint kastore_gets_float64(\n    kastore_t *self, const char *key, double **array, size_t *array_len);\n\n/** @} */\n\n/**\n@brief Insert the specified key-array pair into the store.\n\n@rst\nA key with the specified length is inserted into the store and associated with\nan array of the specified type and number of elements. The contents of the\nspecified key and array are copied unless the KAS_BORROWS_ARRAY flag is specified.\nIf KAS_BORROWS_ARRAY is specified the array buffer must persist until the\nkastore is closed.\nKeys can be any sequence of bytes but must be at least one byte long and be\nunique. There is no restriction on the contents of arrays. This is the most\ngeneral form of ``put`` operation in kastore; when the type of the array\nis known and the keys are standard C strings, it is usually more convenient\nto use the :ref:`typed variants <sec_c_api_typed_put>` of this function.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param key_len The length of the key.\n@param array The array.\n@param array_len The number of elements in the array.\n@param type The type of the array.\n@param flags The insertion flags, only KAS_BORROWS_ARRAY or 0 is a valid.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_put(kastore_t *self, const char *key, size_t key_len, const void *array,\n    size_t array_len, int type, int flags);\n/**\n@brief Insert the specified NULL terminated key and array pair into the store.\n\n@rst\nAs for :c:func:`kastore_put` except the key must be NULL-terminated C string.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param array The array.\n@param array_len The number of elements in the array.\n@param type The type of the array.\n@param flags The insertion flags, only KAS_BORROWS_ARRAY or 0 is a valid.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_puts(kastore_t *self, const char *key, const void *array, size_t array_len,\n    int type, int flags);\n\n/**\n @defgroup TYPED_PUTS_GROUP Typed put functions.\n @{\n */\n\nint kastore_puts_int8(\n    kastore_t *self, const char *key, const int8_t *array, size_t array_len, int flags);\nint kastore_puts_uint8(\n    kastore_t *self, const char *key, const uint8_t *array, size_t array_len, int flags);\nint kastore_puts_int16(\n    kastore_t *self, const char *key, const int16_t *array, size_t array_len, int flags);\nint kastore_puts_uint16(kastore_t *self, const char *key, const uint16_t *array,\n    size_t array_len, int flags);\nint kastore_puts_int32(\n    kastore_t *self, const char *key, const int32_t *array, size_t array_len, int flags);\nint kastore_puts_uint32(kastore_t *self, const char *key, const uint32_t *array,\n    size_t array_len, int flags);\nint kastore_puts_int64(\n    kastore_t *self, const char *key, const int64_t *array, size_t array_len, int flags);\nint kastore_puts_uint64(kastore_t *self, const char *key, const uint64_t *array,\n    size_t array_len, int flags);\nint kastore_puts_float32(\n    kastore_t *self, const char *key, const float *array, size_t array_len, int flags);\nint kastore_puts_float64(\n    kastore_t *self, const char *key, const double *array, size_t array_len, int flags);\n\n/** @} */\n\n/**\n@brief Insert the specified key-array pair into the store, transferring ownership\nof the malloced array buffer to the store (own-put).\n\n@rst\nA key with the specified length is inserted into the store and associated with\nan array of the specified type and number of elements. The contents of the\nspecified key is copied, but the array buffer is taken directly and freed when\nthe store is closed. The array buffer must be a pointer returned by ``malloc``\nor ``calloc``. Ownership of the buffer is not taken unless the function returns\nsuccessfully.\n\nApart from taking ownership of the array buffer, the semantics of this\nfunction are identical to :c:func:`kastore_put`.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param key_len The length of the key.\n@param array The array. Must be a pointer returned by malloc/calloc.\n@param array_len The number of elements in the array.\n@param type The type of the array.\n@param flags The insertion flags. Currently unused.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_oput(kastore_t *self, const char *key, size_t key_len, void *array,\n    size_t array_len, int type, int flags);\n/**\n@brief Insert the specified NULL terminated key and array pair into the store,\ntransferring ownership of the malloced array buffer to the store (own-put).\n\n@rst\nAs for :c:func:`kastore_oput` except the key must be NULL-terminated C string.\n@endrst\n\n@param self A pointer to a kastore object.\n@param key The key.\n@param array The array. Must be a pointer returned by malloc/calloc.\n@param array_len The number of elements in the array.\n@param type The type of the array.\n@param flags The insertion flags. Currently unused.\n@return Return 0 on success or a negative value on failure.\n*/\nint kastore_oputs(kastore_t *self, const char *key, void *array, size_t array_len,\n    int type, int flags);\n\n/**\n @defgroup TYPED_OPUTS_GROUP Typed own-and-put functions.\n @{\n */\n\nint kastore_oputs_int8(\n    kastore_t *self, const char *key, int8_t *array, size_t array_len, int flags);\nint kastore_oputs_uint8(\n    kastore_t *self, const char *key, uint8_t *array, size_t array_len, int flags);\nint kastore_oputs_int16(\n    kastore_t *self, const char *key, int16_t *array, size_t array_len, int flags);\nint kastore_oputs_uint16(\n    kastore_t *self, const char *key, uint16_t *array, size_t array_len, int flags);\nint kastore_oputs_int32(\n    kastore_t *self, const char *key, int32_t *array, size_t array_len, int flags);\nint kastore_oputs_uint32(\n    kastore_t *self, const char *key, uint32_t *array, size_t array_len, int flags);\nint kastore_oputs_int64(\n    kastore_t *self, const char *key, int64_t *array, size_t array_len, int flags);\nint kastore_oputs_uint64(\n    kastore_t *self, const char *key, uint64_t *array, size_t array_len, int flags);\nint kastore_oputs_float32(\n    kastore_t *self, const char *key, float *array, size_t array_len, int flags);\nint kastore_oputs_float64(\n    kastore_t *self, const char *key, double *array, size_t array_len, int flags);\n\n/** @} */\n\nvoid kastore_print_state(kastore_t *self, FILE *out);\n\n/**\n@brief Returns a description of the specified error code.\n\n@param err The error code.\n@return String describing the error code.\n*/\nconst char *kas_strerror(int err);\n\n/**\n@brief Returns the API version.\n\n@rst\nThe API follows the `semver convention <https://semver.org/>`_, where the\nmajor, minor and patch numbers have specific meanings. The versioning\nscheme here also takes into account ABI compatability.\n@endrst\n*/\nkas_version_t kas_version(void);\n\n#define kas_safe_free(pointer)                                                          \\\n    do {                                                                                \\\n        if (pointer != NULL) {                                                          \\\n            free(pointer);                                                              \\\n            pointer = NULL;                                                             \\\n        }                                                                               \\\n    } while (0)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "treerec/tskit/stats.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2018-2025 Tskit Developers\n * Copyright (c) 2016-2017 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <tskit/stats.h>\n\nvoid\ntsk_ld_calc_print_state(const tsk_ld_calc_t *self, FILE *out)\n{\n    fprintf(out, \"tree = %p\\n\", (const void *) &self->tree);\n    fprintf(out, \"max_sites = %d\\n\", (int) self->max_sites);\n    fprintf(out, \"max_distance = %f\\n\", self->max_distance);\n}\n\nint TSK_WARN_UNUSED\ntsk_ld_calc_init(tsk_ld_calc_t *self, const tsk_treeseq_t *tree_sequence)\n{\n    int ret = 0;\n    tsk_memset(self, 0, sizeof(*self));\n\n    ret = tsk_tree_init(&self->tree, tree_sequence, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    self->tree_sequence = tree_sequence;\n    self->total_samples = tsk_treeseq_get_num_samples(self->tree_sequence);\n\n    self->sample_buffer = tsk_malloc(self->total_samples * sizeof(*self->sample_buffer));\n    if (self->sample_buffer == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_ld_calc_free(tsk_ld_calc_t *self)\n{\n    tsk_tree_free(&self->tree);\n    tsk_safe_free(self->sample_buffer);\n    return 0;\n}\n\nstatic int\ntsk_ld_calc_check_site(tsk_ld_calc_t *TSK_UNUSED(self), const tsk_site_t *site)\n{\n    int ret = 0;\n\n    /* These are both limitations in the current implementation, there's no\n     * fundamental reason why we can't support them */\n    if (site->mutations_length != 1) {\n        ret = tsk_trace_error(TSK_ERR_ONLY_INFINITE_SITES);\n        goto out;\n    }\n    if (site->ancestral_state_length == site->mutations[0].derived_state_length\n        && tsk_memcmp(site->ancestral_state, site->mutations[0].derived_state,\n               site->ancestral_state_length)\n               == 0) {\n        ret = tsk_trace_error(TSK_ERR_SILENT_MUTATIONS_NOT_SUPPORTED);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_set_focal_samples(tsk_ld_calc_t *self)\n{\n    int ret = 0;\n    tsk_id_t focal_node = self->focal_site.mutations[0].node;\n\n    ret = tsk_tree_track_descendant_samples(&self->tree, focal_node);\n    if (ret != 0) {\n        goto out;\n    }\n    self->focal_samples = self->tree.num_tracked_samples[focal_node];\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_initialise(tsk_ld_calc_t *self, tsk_id_t a)\n{\n    int ret = 0;\n\n    ret = tsk_treeseq_get_site(self->tree_sequence, a, &self->focal_site);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ld_calc_check_site(self, &self->focal_site);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_seek(&self->tree, self->focal_site.position, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ld_calc_set_focal_samples(self);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_compute_r2(tsk_ld_calc_t *self, const tsk_site_t *target_site, double *r2)\n{\n    const double n = (double) self->total_samples;\n    double f_a, f_b, f_ab, D, denom;\n    tsk_id_t node;\n    int ret = tsk_ld_calc_check_site(self, target_site);\n\n    if (ret != 0) {\n        goto out;\n    }\n    node = target_site->mutations[0].node;\n    f_a = ((double) self->focal_samples) / n;\n    f_b = ((double) self->tree.num_samples[node]) / n;\n    f_ab = ((double) self->tree.num_tracked_samples[node]) / n;\n    D = f_ab - f_a * f_b;\n    denom = f_a * f_b * (1 - f_a) * (1 - f_b);\n    *r2 = (D * D) / denom;\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_compute_and_append(\n    tsk_ld_calc_t *self, const tsk_site_t *target_site, bool *ret_done)\n{\n    int ret = 0;\n    double r2;\n    double distance = fabs(self->focal_site.position - target_site->position);\n    bool done = true;\n\n    if (distance <= self->max_distance && self->result_length < self->max_sites) {\n        ret = tsk_ld_calc_compute_r2(self, target_site, &r2);\n        if (ret != 0) {\n            goto out;\n        }\n        self->result[self->result_length] = r2;\n        self->result_length++;\n        done = false;\n    }\n    *ret_done = done;\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_run_forward(tsk_ld_calc_t *self)\n{\n    int ret = 0;\n    tsk_size_t j;\n    bool done = false;\n\n    for (j = 0; j < self->tree.sites_length; j++) {\n        if (self->tree.sites[j].id > self->focal_site.id) {\n            ret = tsk_ld_calc_compute_and_append(self, &self->tree.sites[j], &done);\n            if (ret != 0) {\n                goto out;\n            }\n            if (done) {\n                break;\n            }\n        }\n    }\n    while (((ret = tsk_tree_next(&self->tree)) == TSK_TREE_OK) && !done) {\n        for (j = 0; j < self->tree.sites_length; j++) {\n            ret = tsk_ld_calc_compute_and_append(self, &self->tree.sites[j], &done);\n            if (ret != 0) {\n                goto out;\n            }\n            if (done) {\n                break;\n            }\n        }\n    }\n    if (ret < 0) {\n        goto out;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ntsk_ld_calc_run_reverse(tsk_ld_calc_t *self)\n{\n    int ret = 0;\n    tsk_id_t j;\n    bool done = false;\n\n    for (j = (tsk_id_t) self->tree.sites_length - 1; j >= 0; j--) {\n        if (self->tree.sites[j].id < self->focal_site.id) {\n            ret = tsk_ld_calc_compute_and_append(self, &self->tree.sites[j], &done);\n            if (ret != 0) {\n                goto out;\n            }\n            if (done) {\n                break;\n            }\n        }\n    }\n    while (((ret = tsk_tree_prev(&self->tree)) == TSK_TREE_OK) && !done) {\n        for (j = (tsk_id_t) self->tree.sites_length - 1; j >= 0; j--) {\n            ret = tsk_ld_calc_compute_and_append(self, &self->tree.sites[j], &done);\n            if (ret != 0) {\n                goto out;\n            }\n            if (done) {\n                break;\n            }\n        }\n    }\n    if (ret < 0) {\n        goto out;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nint\ntsk_ld_calc_get_r2(tsk_ld_calc_t *self, tsk_id_t a, tsk_id_t b, double *r2)\n{\n    int ret = 0;\n    tsk_site_t target_site;\n\n    ret = tsk_ld_calc_initialise(self, a);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_get_site(self->tree_sequence, b, &target_site);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_seek(&self->tree, target_site.position, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ld_calc_compute_r2(self, &target_site, r2);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_ld_calc_get_r2_array(tsk_ld_calc_t *self, tsk_id_t a, int direction,\n    tsk_size_t max_sites, double max_distance, double *r2, tsk_size_t *num_r2_values)\n{\n    int ret = tsk_ld_calc_initialise(self, a);\n\n    if (ret != 0) {\n        goto out;\n    }\n\n    self->max_sites = max_sites;\n    self->max_distance = max_distance;\n    self->result_length = 0;\n    self->result = r2;\n\n    if (direction == TSK_DIR_FORWARD) {\n        ret = tsk_ld_calc_run_forward(self);\n    } else if (direction == TSK_DIR_REVERSE) {\n        ret = tsk_ld_calc_run_reverse(self);\n    } else {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n    }\n    if (ret != 0) {\n        goto out;\n    }\n    *num_r2_values = self->result_length;\nout:\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/stats.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2021 Tskit Developers\n * Copyright (c) 2016-2017 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef TSK_STATS_H\n#define TSK_STATS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <tskit/trees.h>\n\ntypedef struct {\n    const tsk_treeseq_t *tree_sequence;\n    tsk_site_t focal_site;\n    tsk_size_t total_samples;\n    tsk_size_t focal_samples;\n    double max_distance;\n    tsk_size_t max_sites;\n    tsk_tree_t tree;\n    tsk_id_t *sample_buffer;\n    double *result;\n    tsk_size_t result_length;\n} tsk_ld_calc_t;\n\nint tsk_ld_calc_init(tsk_ld_calc_t *self, const tsk_treeseq_t *tree_sequence);\nint tsk_ld_calc_free(tsk_ld_calc_t *self);\nvoid tsk_ld_calc_print_state(const tsk_ld_calc_t *self, FILE *out);\nint tsk_ld_calc_get_r2(tsk_ld_calc_t *self, tsk_id_t a, tsk_id_t b, double *r2);\nint tsk_ld_calc_get_r2_array(tsk_ld_calc_t *self, tsk_id_t a, int direction,\n    tsk_size_t max_sites, double max_distance, double *r2, tsk_size_t *num_r2_values);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/tables.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n * Copyright (c) 2017-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <assert.h>\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <float.h>\n#include <math.h>\n\n#include <tskit/tables.h>\n\n#define TABLE_SEP \"-----------------------------------------\\n\"\n\n#define TSK_COL_OPTIONAL (1 << 0)\n\ntypedef struct {\n    const char *name;\n    void **array_dest;\n    int type;\n    tsk_flags_t options;\n} read_table_col_t;\n\ntypedef struct {\n    const char *name;\n    void **data_array_dest;\n    tsk_size_t *data_len_dest;\n    int data_type;\n    tsk_size_t **offset_array_dest;\n    tsk_flags_t options;\n} read_table_ragged_col_t;\n\ntypedef struct {\n    const char *name;\n    void **array_dest;\n    tsk_size_t *len_dest;\n    int type;\n    tsk_flags_t options;\n} read_table_property_t;\n\ntypedef struct {\n    const char *name;\n    const void *array;\n    tsk_size_t len;\n    int type;\n} write_table_col_t;\n\ntypedef struct {\n    const char *name;\n    const void *data_array;\n    tsk_size_t data_len;\n    int data_type;\n    const tsk_size_t *offset_array;\n    tsk_size_t num_rows;\n} write_table_ragged_col_t;\n\n/* Returns true if adding the specified number of rows would result in overflow.\n * Tables can support indexes from 0 to TSK_MAX_ID, and therefore could have at most\n * TSK_MAX_ID + 1 rows. However we limit to TSK_MAX_ID rows so that counts of rows\n * can fit in a tsk_id_t. */\nstatic bool\ncheck_table_overflow(tsk_size_t current_size, tsk_size_t additional_rows)\n{\n    tsk_size_t max_val = TSK_MAX_ID;\n    return additional_rows > max_val || current_size > (max_val - additional_rows);\n}\n\n/* Returns true if adding the specified number of elements would result in overflow\n * of an offset column.\n */\nstatic bool\ncheck_offset_overflow(tsk_size_t current_size, tsk_size_t additional_elements)\n{\n    tsk_size_t max_val = TSK_MAX_SIZE;\n    return additional_elements > max_val\n           || current_size > (max_val - additional_elements);\n}\n\n#define TSK_NUM_ROWS_UNSET ((tsk_size_t) -1)\n#define TSK_MAX_COL_NAME_LEN 64\n\nstatic int\nread_table_cols(kastore_t *store, tsk_size_t *num_rows, read_table_col_t *cols,\n    tsk_flags_t TSK_UNUSED(flags))\n{\n    int ret = 0;\n    size_t len;\n    int type;\n    read_table_col_t *col;\n\n    for (col = cols; col->name != NULL; col++) {\n        ret = kastore_containss(store, col->name);\n        if (ret < 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        if (ret == 1) {\n            ret = kastore_gets(store, col->name, col->array_dest, &len, &type);\n            if (ret != 0) {\n                ret = tsk_set_kas_error(ret);\n                goto out;\n            }\n            if (*num_rows == TSK_NUM_ROWS_UNSET) {\n                *num_rows = (tsk_size_t) len;\n            } else {\n                if (*num_rows != (tsk_size_t) len) {\n                    ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n                    goto out;\n                }\n            }\n            if (type != col->type) {\n                ret = tsk_trace_error(TSK_ERR_BAD_COLUMN_TYPE);\n                goto out;\n            }\n        } else if (!(col->options & TSK_COL_OPTIONAL)) {\n            ret = tsk_trace_error(TSK_ERR_REQUIRED_COL_NOT_FOUND);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ncast_offset_array(read_table_ragged_col_t *col, uint32_t *source, tsk_size_t num_rows)\n{\n    int ret = 0;\n    tsk_size_t len = num_rows + 1;\n    tsk_size_t j;\n    uint64_t *dest = tsk_malloc(len * sizeof(*dest));\n\n    if (dest == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    *col->offset_array_dest = dest;\n    for (j = 0; j < len; j++) {\n        dest[j] = source[j];\n    }\nout:\n    return ret;\n}\n\nstatic int\nread_table_ragged_cols(kastore_t *store, tsk_size_t *num_rows,\n    read_table_ragged_col_t *cols, tsk_flags_t TSK_UNUSED(flags))\n{\n    int ret = 0;\n    size_t data_len = 0; // initial value unused, just to keep the compiler happy.\n    size_t offset_len;\n    int type;\n    read_table_ragged_col_t *col;\n    char offset_col_name[TSK_MAX_COL_NAME_LEN];\n    bool data_col_present, offset_col_present;\n    void *store_offset_array = NULL;\n    tsk_size_t *offset_array;\n\n    for (col = cols; col->name != NULL; col++) {\n        ret = kastore_containss(store, col->name);\n        if (ret < 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        data_col_present = false;\n        if (ret == 1) {\n            ret = kastore_gets(store, col->name, col->data_array_dest, &data_len, &type);\n            if (ret != 0) {\n                ret = tsk_set_kas_error(ret);\n                goto out;\n            }\n            if (type != col->data_type) {\n                ret = tsk_trace_error(TSK_ERR_BAD_COLUMN_TYPE);\n                goto out;\n            }\n            *col->data_len_dest = (tsk_size_t) data_len;\n            data_col_present = true;\n        } else if (!(col->options & TSK_COL_OPTIONAL)) {\n            ret = tsk_trace_error(TSK_ERR_REQUIRED_COL_NOT_FOUND);\n            goto out;\n        }\n\n        assert(strlen(col->name) + strlen(\"_offset\") + 2 < sizeof(offset_col_name));\n        strcpy(offset_col_name, col->name);\n        strcat(offset_col_name, \"_offset\");\n\n        ret = kastore_containss(store, offset_col_name);\n        if (ret < 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        offset_col_present = ret == 1;\n        if (offset_col_present != data_col_present) {\n            ret = tsk_trace_error(TSK_ERR_BOTH_COLUMNS_REQUIRED);\n            goto out;\n        }\n        if (offset_col_present) {\n            ret = kastore_gets(\n                store, offset_col_name, &store_offset_array, &offset_len, &type);\n            if (ret != 0) {\n                ret = tsk_set_kas_error(ret);\n                goto out;\n            }\n            /* A table with zero rows will still have an offset length of 1;\n             * catching this here prevents underflows in the logic below */\n            if (offset_len == 0) {\n                ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n                goto out;\n            }\n            /* Some tables have only ragged columns */\n            if (*num_rows == TSK_NUM_ROWS_UNSET) {\n                *num_rows = (tsk_size_t) offset_len - 1;\n            } else {\n                if (*num_rows != (tsk_size_t) offset_len - 1) {\n                    ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n                    goto out;\n                }\n            }\n            if (type == KAS_UINT64) {\n                *col->offset_array_dest = (uint64_t *) store_offset_array;\n                store_offset_array = NULL;\n            } else if (type == KAS_UINT32) {\n                ret = cast_offset_array(col, (uint32_t *) store_offset_array, *num_rows);\n                if (ret != 0) {\n                    goto out;\n                }\n                tsk_safe_free(store_offset_array);\n                store_offset_array = NULL;\n            } else {\n                ret = tsk_trace_error(TSK_ERR_BAD_COLUMN_TYPE);\n                goto out;\n            }\n            offset_array = *col->offset_array_dest;\n            if (offset_array[*num_rows] != (tsk_size_t) data_len) {\n                ret = tsk_trace_error(TSK_ERR_BAD_OFFSET);\n                goto out;\n            }\n        }\n    }\nout:\n    tsk_safe_free(store_offset_array);\n    return ret;\n}\n\nstatic int\nread_table_properties(\n    kastore_t *store, read_table_property_t *properties, tsk_flags_t TSK_UNUSED(flags))\n{\n    int ret = 0;\n    size_t len;\n    int type;\n    read_table_property_t *property;\n\n    for (property = properties; property->name != NULL; property++) {\n        ret = kastore_containss(store, property->name);\n        if (ret < 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        if (ret == 1) {\n            ret = kastore_gets(store, property->name, property->array_dest, &len, &type);\n            if (ret != 0) {\n                ret = tsk_set_kas_error(ret);\n                assert(ret != 0); /* Tell static analysers that we're handling errors */\n                goto out;\n            }\n            if (type != property->type) {\n                ret = tsk_trace_error(TSK_ERR_BAD_COLUMN_TYPE);\n                goto out;\n            }\n            *property->len_dest = (tsk_size_t) len;\n        }\n        assert(property->options & TSK_COL_OPTIONAL);\n    }\nout:\n    return ret;\n}\n\nstatic int\nread_table(kastore_t *store, tsk_size_t *num_rows, read_table_col_t *cols,\n    read_table_ragged_col_t *ragged_cols, read_table_property_t *properties,\n    tsk_flags_t options)\n{\n    int ret = 0;\n\n    *num_rows = TSK_NUM_ROWS_UNSET;\n    if (cols != NULL) {\n        ret = read_table_cols(store, num_rows, cols, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (ragged_cols != NULL) {\n        ret = read_table_ragged_cols(store, num_rows, ragged_cols, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (*num_rows == TSK_NUM_ROWS_UNSET) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n    if (properties != NULL) {\n        ret = read_table_properties(store, properties, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic void\nfree_read_table_mem(read_table_col_t *cols, read_table_ragged_col_t *ragged_cols,\n    read_table_property_t *properties)\n{\n    read_table_col_t *col;\n    read_table_ragged_col_t *ragged_col;\n    read_table_property_t *property;\n\n    if (cols != NULL) {\n        for (col = cols; col->name != NULL; col++) {\n            tsk_safe_free(*(col->array_dest));\n        }\n    }\n    if (ragged_cols != NULL) {\n        for (ragged_col = ragged_cols; ragged_col->name != NULL; ragged_col++) {\n            tsk_safe_free(*(ragged_col->data_array_dest));\n            tsk_safe_free(*(ragged_col->offset_array_dest));\n        }\n    }\n    if (properties != NULL) {\n        for (property = properties; property->name != NULL; property++) {\n            tsk_safe_free(*(property->array_dest));\n        }\n    }\n}\n\nstatic int\nwrite_offset_col(\n    kastore_t *store, const write_table_ragged_col_t *col, tsk_flags_t options)\n{\n    int ret = 0;\n    char offset_col_name[TSK_MAX_COL_NAME_LEN];\n    uint32_t *offset32 = NULL;\n    tsk_size_t len = col->num_rows + 1;\n    tsk_size_t j;\n    int32_t put_flags = 0;\n    int type;\n    const void *data;\n    bool needs_64 = col->offset_array[col->num_rows] > UINT32_MAX;\n\n    assert(strlen(col->name) + strlen(\"_offset\") + 2 < sizeof(offset_col_name));\n    strcpy(offset_col_name, col->name);\n    strcat(offset_col_name, \"_offset\");\n\n    if (options & TSK_DUMP_FORCE_OFFSET_64 || needs_64) {\n        type = KAS_UINT64;\n        data = col->offset_array;\n        put_flags = KAS_BORROWS_ARRAY;\n    } else {\n        offset32 = tsk_malloc(len * sizeof(*offset32));\n        if (offset32 == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        for (j = 0; j < len; j++) {\n            offset32[j] = (uint32_t) col->offset_array[j];\n        }\n        type = KAS_UINT32;\n        data = offset32;\n        /* We've just allocated a temp buffer, so kas can't borrow so leave put_flags=0*/\n    }\n    ret = kastore_puts(store, offset_col_name, data, (size_t) len, type, put_flags);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\nout:\n    tsk_safe_free(offset32);\n    return ret;\n}\n\nstatic int\nwrite_table_ragged_cols(\n    kastore_t *store, const write_table_ragged_col_t *write_cols, tsk_flags_t options)\n{\n    int ret = 0;\n    const write_table_ragged_col_t *col;\n\n    for (col = write_cols; col->name != NULL; col++) {\n        ret = kastore_puts(store, col->name, col->data_array, (size_t) col->data_len,\n            col->data_type, KAS_BORROWS_ARRAY);\n        if (ret != 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        ret = write_offset_col(store, col, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\nwrite_table_cols(kastore_t *store, const write_table_col_t *write_cols,\n    tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    const write_table_col_t *col;\n\n    for (col = write_cols; col->name != NULL; col++) {\n        ret = kastore_puts(store, col->name, col->array, (size_t) col->len, col->type,\n            KAS_BORROWS_ARRAY);\n        if (ret != 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\nwrite_table(kastore_t *store, const write_table_col_t *cols,\n    const write_table_ragged_col_t *ragged_cols, tsk_flags_t options)\n{\n    int ret = write_table_cols(store, cols, options);\n\n    if (ret != 0) {\n        goto out;\n    }\n    ret = write_table_ragged_cols(store, ragged_cols, options);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\n/* Checks that the specified list of offsets is well-formed. */\nstatic int\ncheck_offsets(\n    tsk_size_t num_rows, const tsk_size_t *offsets, tsk_size_t length, bool check_length)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    if (offsets[0] != 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_OFFSET);\n        goto out;\n    }\n    if (check_length && offsets[num_rows] != length) {\n        ret = tsk_trace_error(TSK_ERR_BAD_OFFSET);\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        if (offsets[j] > offsets[j + 1]) {\n            ret = tsk_trace_error(TSK_ERR_BAD_OFFSET);\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ncalculate_max_rows(tsk_size_t num_rows, tsk_size_t max_rows,\n    tsk_size_t max_rows_increment, tsk_size_t additional_rows,\n    tsk_size_t *ret_new_max_rows)\n{\n    tsk_size_t new_max_rows;\n    int ret = 0;\n\n    if (check_table_overflow(num_rows, additional_rows)) {\n        ret = tsk_trace_error(TSK_ERR_TABLE_OVERFLOW);\n        goto out;\n    }\n\n    if (num_rows + additional_rows <= max_rows) {\n        new_max_rows = max_rows;\n    } else {\n        if (max_rows_increment == 0) {\n            /* Doubling by default */\n            new_max_rows = TSK_MIN(max_rows * 2, TSK_MAX_ID + (tsk_size_t) 1);\n            /* Add some constraints to prevent very small allocations */\n            if (new_max_rows < 1024) {\n                new_max_rows = 1024;\n            }\n            /* Prevent allocating more than ~2 million additional rows unless needed*/\n            if (new_max_rows - max_rows > 2097152) {\n                new_max_rows = max_rows + 2097152;\n            }\n        } else {\n            /* Use user increment value */\n            if (check_table_overflow(max_rows, max_rows_increment)) {\n                ret = tsk_trace_error(TSK_ERR_TABLE_OVERFLOW);\n                goto out;\n            }\n            new_max_rows = max_rows + max_rows_increment;\n        }\n        new_max_rows = TSK_MAX(new_max_rows, num_rows + additional_rows);\n    }\n    *ret_new_max_rows = new_max_rows;\nout:\n    return ret;\n}\n\nstatic int\ncalculate_max_length(tsk_size_t current_length, tsk_size_t max_length,\n    tsk_size_t max_length_increment, tsk_size_t additional_length,\n    tsk_size_t *ret_new_max_length)\n{\n    tsk_size_t new_max_length;\n    int ret = 0;\n\n    if (check_offset_overflow(current_length, additional_length)) {\n        ret = tsk_trace_error(TSK_ERR_COLUMN_OVERFLOW);\n        goto out;\n    }\n\n    if (current_length + additional_length <= max_length) {\n        new_max_length = max_length;\n    } else {\n        if (max_length_increment == 0) {\n            /* Doubling by default */\n            new_max_length = TSK_MIN(max_length * 2, TSK_MAX_SIZE);\n            /* Add some constraints to prevent very small allocations */\n            if (new_max_length < 65536) {\n                new_max_length = 65536;\n            }\n            /* Prevent allocating more than 100MB additional unless needed*/\n            if (new_max_length - max_length > 104857600) {\n                new_max_length = max_length + 104857600;\n            }\n            new_max_length = TSK_MAX(new_max_length, current_length + additional_length);\n        } else {\n            /* Use user increment value */\n            if (check_offset_overflow(max_length, max_length_increment)) {\n                /* Here we could allocate to the maximum size.\n                 * Instead we are erroring out as this is much easier to test.\n                 * The cost is that (at most) the last \"max_length_increment\"-1\n                 * bytes of the possible array space can't be used. */\n                ret = tsk_trace_error(TSK_ERR_COLUMN_OVERFLOW);\n                goto out;\n            }\n            new_max_length = max_length + max_length_increment;\n        }\n        new_max_length = TSK_MAX(new_max_length, current_length + additional_length);\n    }\n    *ret_new_max_length = new_max_length;\nout:\n    return ret;\n}\n\nstatic int\nexpand_column(void **column, tsk_size_t new_max_rows, size_t element_size)\n{\n    int ret = 0;\n    void *tmp;\n\n    tmp = tsk_realloc((void **) *column, new_max_rows * element_size);\n    if (tmp == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    *column = tmp;\nout:\n    return ret;\n}\n\nstatic int\nexpand_ragged_column(tsk_size_t current_length, tsk_size_t additional_length,\n    tsk_size_t max_length_increment, tsk_size_t *max_length, void **column,\n    size_t element_size)\n{\n    int ret = 0;\n    tsk_size_t new_max_length;\n\n    ret = calculate_max_length(current_length, *max_length, max_length_increment,\n        additional_length, &new_max_length);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (new_max_length > *max_length) {\n        ret = expand_column(column, new_max_length, element_size);\n        if (ret != 0) {\n            goto out;\n        }\n        *max_length = new_max_length;\n    }\nout:\n    return ret;\n}\n\n/* TODO rename to copy_string or replace_and_copy_string */\nstatic int\nreplace_string(\n    char **str, tsk_size_t *len, const char *new_str, const tsk_size_t new_len)\n{\n    int ret = 0;\n    tsk_safe_free(*str);\n    *str = NULL;\n    *len = new_len;\n    if (new_len > 0) {\n        *str = tsk_malloc(new_len * sizeof(char));\n        if (*str == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        tsk_memcpy(*str, new_str, new_len * sizeof(char));\n    }\nout:\n    return ret;\n}\n\nstatic int\ntakeset_string(char **str, tsk_size_t *len, char *new_str, const tsk_size_t new_len)\n{\n    tsk_safe_free(*str);\n    *str = new_str;\n    *len = new_len;\n    return 0;\n}\n\nstatic int\nalloc_empty_ragged_column(tsk_size_t num_rows, void **data_col, tsk_size_t **offset_col)\n{\n    int ret = 0;\n\n    *data_col = tsk_malloc(1);\n    *offset_col = tsk_calloc(num_rows + 1, sizeof(tsk_size_t));\n    if (*data_col == NULL || *offset_col == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ncheck_ragged_column(tsk_size_t num_rows, void *data, tsk_size_t *offset)\n{\n    int ret = 0;\n    if ((data == NULL) != (offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (data != NULL) {\n        ret = check_offsets(num_rows, offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntakeset_ragged_column(tsk_size_t num_rows, void *data, tsk_size_t *offset,\n    void **data_dest, tsk_size_t **offset_dest, tsk_size_t *length_dest)\n{\n    int ret = 0;\n    if (data == NULL) {\n        ret = alloc_empty_ragged_column(num_rows, (void *) data_dest, offset_dest);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        *data_dest = data;\n        *offset_dest = offset;\n    }\n    *length_dest = (*offset_dest)[num_rows];\nout:\n    return ret;\n}\n\nstatic int\ntakeset_optional_id_column(tsk_size_t num_rows, tsk_id_t *input, tsk_id_t **dest)\n{\n    int ret = 0;\n    tsk_size_t buffsize;\n    tsk_id_t *buff;\n\n    if (input == NULL) {\n        buffsize = num_rows * sizeof(*buff);\n        buff = tsk_malloc(buffsize);\n        if (buff == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        *dest = buff;\n        tsk_memset(buff, 0xff, buffsize);\n    } else {\n        *dest = input;\n    }\nout:\n    return ret;\n}\n\nstatic int\nwrite_metadata_schema_header(\n    FILE *out, const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    const char *fmt = \"#metadata_schema#\\n\"\n                      \"%.*s\\n\"\n                      \"#end#metadata_schema\\n\" TABLE_SEP;\n    return fprintf(out, fmt, (int) metadata_schema_length, metadata_schema);\n}\n\n/* Utilities for in-place subsetting columns */\n\nstatic tsk_size_t\ncount_true(tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j;\n    tsk_size_t count = 0;\n\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            count++;\n        }\n    }\n    return count;\n}\n\nstatic void\nkeep_mask_to_id_map(\n    tsk_size_t num_rows, const tsk_bool_t *restrict keep, tsk_id_t *restrict id_map)\n{\n    tsk_size_t j;\n    tsk_id_t next_id = 0;\n\n    for (j = 0; j < num_rows; j++) {\n        id_map[j] = TSK_NULL;\n        if (keep[j]) {\n            id_map[j] = next_id;\n            next_id++;\n        }\n    }\n}\n\nstatic tsk_size_t\nsubset_remap_id_column(tsk_id_t *restrict column, tsk_size_t num_rows,\n    const tsk_bool_t *restrict keep, const tsk_id_t *restrict id_map)\n{\n    tsk_size_t j, k;\n    tsk_id_t value;\n\n    k = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            value = column[j];\n            if (value != TSK_NULL) {\n                value = id_map[value];\n            }\n            column[k] = value;\n            k++;\n        }\n    }\n    return k;\n}\n\n/* Trigger warning: C++ programmers should look away... This may be one of the\n * few cases where some macro funkiness is warranted, as these are exact\n * duplicates of the same function with just the type of the column\n * parameter changed. */\n\nstatic tsk_size_t\nsubset_id_column(\n    tsk_id_t *restrict column, tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j, k;\n\n    k = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            column[k] = column[j];\n            k++;\n        }\n    }\n    return k;\n}\n\nstatic tsk_size_t\nsubset_flags_column(\n    tsk_flags_t *restrict column, tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j, k;\n\n    k = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            column[k] = column[j];\n            k++;\n        }\n    }\n    return k;\n}\n\nstatic tsk_size_t\nsubset_double_column(\n    double *restrict column, tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j, k;\n\n    k = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            column[k] = column[j];\n            k++;\n        }\n    }\n    return k;\n}\n\nstatic tsk_size_t\nsubset_ragged_char_column(char *restrict data, tsk_size_t *restrict offset_col,\n    tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j, k, i, offset;\n\n    k = 0;\n    offset = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            offset_col[k] = offset;\n            /* Note: Unclear whether it's worth calling memcpy instead here?\n             * Need to be careful since the regions are overlapping */\n            for (i = offset_col[j]; i < offset_col[j + 1]; i++) {\n                data[offset] = data[i];\n                offset++;\n            }\n            k++;\n        }\n    }\n    offset_col[k] = offset;\n    return offset;\n}\n\nstatic tsk_size_t\nsubset_ragged_double_column(double *restrict data, tsk_size_t *restrict offset_col,\n    tsk_size_t num_rows, const tsk_bool_t *restrict keep)\n{\n    tsk_size_t j, k, i, offset;\n\n    k = 0;\n    offset = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            offset_col[k] = offset;\n            /* Note: Unclear whether it's worth calling memcpy instead here?\n             * Need to be careful since the regions are overlapping */\n            for (i = offset_col[j]; i < offset_col[j + 1]; i++) {\n                data[offset] = data[i];\n                offset++;\n            }\n            k++;\n        }\n    }\n    offset_col[k] = offset;\n    return offset;\n}\n\nstatic tsk_size_t\nsubset_remap_ragged_id_column(tsk_id_t *restrict data, tsk_size_t *restrict offset_col,\n    tsk_size_t num_rows, const tsk_bool_t *restrict keep,\n    const tsk_id_t *restrict id_map)\n{\n    tsk_size_t j, k, i, offset;\n    tsk_id_t di;\n\n    k = 0;\n    offset = 0;\n    for (j = 0; j < num_rows; j++) {\n        if (keep[j]) {\n            offset_col[k] = offset;\n            for (i = offset_col[j]; i < offset_col[j + 1]; i++) {\n                di = data[i];\n                if (di != TSK_NULL) {\n                    di = id_map[di];\n                }\n                data[offset] = di;\n                offset++;\n            }\n            k++;\n        }\n    }\n    offset_col[k] = offset;\n    return offset;\n}\n\n/*************************\n * reference sequence\n *************************/\n\nint\ntsk_reference_sequence_init(\n    tsk_reference_sequence_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    tsk_memset(self, 0, sizeof(*self));\n    return 0;\n}\n\nint\ntsk_reference_sequence_free(tsk_reference_sequence_t *self)\n{\n    tsk_safe_free(self->data);\n    tsk_safe_free(self->url);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nbool\ntsk_reference_sequence_is_null(const tsk_reference_sequence_t *self)\n{\n    return self->data_length == 0 && self->url_length == 0 && self->metadata_length == 0\n           && self->metadata_schema_length == 0;\n}\n\nbool\ntsk_reference_sequence_equals(const tsk_reference_sequence_t *self,\n    const tsk_reference_sequence_t *other, tsk_flags_t options)\n{\n    int ret\n        = self->data_length == other->data_length\n          && self->url_length == other->url_length\n          && tsk_memcmp(self->data, other->data, self->data_length * sizeof(char)) == 0\n          && tsk_memcmp(self->url, other->url, self->url_length * sizeof(char)) == 0;\n\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_reference_sequence_copy(const tsk_reference_sequence_t *self,\n    tsk_reference_sequence_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_reference_sequence_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    if (tsk_reference_sequence_is_null(self)) {\n        /* This is a simple way to get any input into the NULL state */\n        tsk_reference_sequence_free(dest);\n    } else {\n        ret = tsk_reference_sequence_set_data(dest, self->data, self->data_length);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_reference_sequence_set_url(dest, self->url, self->url_length);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_reference_sequence_set_metadata(\n            dest, self->metadata, self->metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_reference_sequence_set_metadata_schema(\n            dest, self->metadata_schema, self->metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_reference_sequence_set_data(\n    tsk_reference_sequence_t *self, const char *data, tsk_size_t data_length)\n{\n    return replace_string(&self->data, &self->data_length, data, data_length);\n}\n\nint\ntsk_reference_sequence_set_url(\n    tsk_reference_sequence_t *self, const char *url, tsk_size_t url_length)\n{\n    return replace_string(&self->url, &self->url_length, url, url_length);\n}\n\nint\ntsk_reference_sequence_set_metadata(\n    tsk_reference_sequence_t *self, const char *metadata, tsk_size_t metadata_length)\n{\n    return replace_string(\n        &self->metadata, &self->metadata_length, metadata, metadata_length);\n}\n\nint\ntsk_reference_sequence_set_metadata_schema(tsk_reference_sequence_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_reference_sequence_takeset_data(\n    tsk_reference_sequence_t *self, char *data, tsk_size_t data_length)\n{\n    return takeset_string(&self->data, &self->data_length, data, data_length);\n}\n\nint\ntsk_reference_sequence_takeset_metadata(\n    tsk_reference_sequence_t *self, char *metadata, tsk_size_t metadata_length)\n{\n    return takeset_string(\n        &self->metadata, &self->metadata_length, metadata, metadata_length);\n}\n\n/*************************\n * individual table\n *************************/\n\nstatic void\ntsk_individual_table_free_columns(tsk_individual_table_t *self)\n{\n    tsk_safe_free(self->flags);\n    tsk_safe_free(self->location);\n    tsk_safe_free(self->location_offset);\n    tsk_safe_free(self->parents);\n    tsk_safe_free(self->parents_offset);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_individual_table_free(tsk_individual_table_t *self)\n{\n    tsk_individual_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_individual_table_expand_main_columns(\n    tsk_individual_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column((void **) &self->flags, new_max_rows, sizeof(tsk_flags_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->location_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->parents_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_individual_table_expand_location(\n    tsk_individual_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->location_length, additional_length,\n        self->max_location_length_increment, &self->max_location_length,\n        (void **) &self->location, sizeof(*self->location));\n}\n\nstatic int\ntsk_individual_table_expand_parents(\n    tsk_individual_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->parents_length, additional_length,\n        self->max_parents_length_increment, &self->max_parents_length,\n        (void **) &self->parents, sizeof(*self->parents));\n}\n\nstatic int\ntsk_individual_table_expand_metadata(\n    tsk_individual_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_individual_table_set_max_rows_increment(\n    tsk_individual_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_individual_table_set_max_metadata_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = (tsk_size_t) max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_individual_table_set_max_location_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_location_length_increment)\n{\n    self->max_location_length_increment = (tsk_size_t) max_location_length_increment;\n    return 0;\n}\n\nint\ntsk_individual_table_set_max_parents_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_parents_length_increment)\n{\n    self->max_parents_length_increment = (tsk_size_t) max_parents_length_increment;\n    return 0;\n}\n\nint\ntsk_individual_table_init(tsk_individual_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_individual_table_t));\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_location_length_increment = 1;\n    self->max_parents_length_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_individual_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_expand_location(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->location_offset[0] = 0;\n    ret = tsk_individual_table_expand_parents(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->parents_offset[0] = 0;\n    ret = tsk_individual_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_location_length_increment = 0;\n    self->max_parents_length_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_individual_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_individual_table_copy(const tsk_individual_table_t *self,\n    tsk_individual_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_individual_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_individual_table_set_columns(dest, self->num_rows, self->flags,\n        self->location, self->location_offset, self->parents, self->parents_offset,\n        self->metadata, self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_individual_table_set_columns(tsk_individual_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *location, const tsk_size_t *location_offset,\n    const tsk_id_t *parents, const tsk_size_t *parents_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret;\n\n    ret = tsk_individual_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_append_columns(self, num_rows, flags, location,\n        location_offset, parents, parents_offset, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_individual_table_takeset_columns(tsk_individual_table_t *self, tsk_size_t num_rows,\n    tsk_flags_t *flags, double *location, tsk_size_t *location_offset, tsk_id_t *parents,\n    tsk_size_t *parents_offset, char *metadata, tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    ret = check_ragged_column(num_rows, location, location_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, parents, parents_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_individual_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n\n    if (flags == NULL) {\n        /* Flags defaults to all zeros if not specified. The column is often\n         * unused so this is a worthwhile optimisation. */\n        self->flags = tsk_calloc(num_rows, sizeof(*self->flags));\n        if (self->flags == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    } else {\n        self->flags = flags;\n    }\n\n    ret = takeset_ragged_column(num_rows, location, location_offset,\n        (void *) &self->location, &self->location_offset, &self->location_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_ragged_column(num_rows, parents, parents_offset,\n        (void *) &self->parents, &self->parents_offset, &self->parents_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_individual_table_append_columns(tsk_individual_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *location, const tsk_size_t *location_offset,\n    const tsk_id_t *parents, const tsk_size_t *parents_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret;\n    tsk_size_t j, metadata_length, location_length, parents_length;\n\n    if (flags == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((location == NULL) != (location_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((parents == NULL) != (parents_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = tsk_individual_table_expand_main_columns(self, (tsk_size_t) num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->flags + self->num_rows, flags, num_rows * sizeof(tsk_flags_t));\n    if (location == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->location_offset[self->num_rows + j + 1]\n                = (tsk_size_t) self->location_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, location_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->location_offset[self->num_rows + j]\n                = (tsk_size_t) self->location_length + location_offset[j];\n        }\n        location_length = location_offset[num_rows];\n        ret = tsk_individual_table_expand_location(self, location_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->location + self->location_length, location,\n            location_length * sizeof(double));\n        self->location_length += location_length;\n    }\n    if (parents == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->parents_offset[self->num_rows + j + 1]\n                = (tsk_size_t) self->parents_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, parents_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->parents_offset[self->num_rows + j]\n                = (tsk_size_t) self->parents_length + parents_offset[j];\n        }\n        parents_length = parents_offset[num_rows];\n        ret = tsk_individual_table_expand_parents(self, parents_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->parents + self->parents_length, parents,\n            parents_length * sizeof(tsk_id_t));\n        self->parents_length += parents_length;\n    }\n    if (metadata == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j + 1]\n                = (tsk_size_t) self->metadata_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, metadata_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j]\n                = (tsk_size_t) self->metadata_length + metadata_offset[j];\n        }\n        metadata_length = metadata_offset[num_rows];\n        ret = tsk_individual_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->metadata + self->metadata_length, metadata,\n            metadata_length * sizeof(char));\n        self->metadata_length += metadata_length;\n    }\n    self->num_rows += (tsk_size_t) num_rows;\n    self->location_offset[self->num_rows] = self->location_length;\n    self->parents_offset[self->num_rows] = self->parents_length;\n    self->metadata_offset[self->num_rows] = self->metadata_length;\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_individual_table_add_row_internal(tsk_individual_table_t *self, tsk_flags_t flags,\n    const double *location, tsk_size_t location_length, const tsk_id_t *parents,\n    const tsk_size_t parents_length, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    tsk_bug_assert(self->parents_length + parents_length <= self->max_parents_length);\n    tsk_bug_assert(self->metadata_length + metadata_length <= self->max_metadata_length);\n    tsk_bug_assert(self->location_length + location_length <= self->max_location_length);\n    self->flags[self->num_rows] = flags;\n    tsk_memmove(self->location + self->location_length, location,\n        location_length * sizeof(*self->location));\n    self->location_offset[self->num_rows + 1] = self->location_length + location_length;\n    self->location_length += location_length;\n    tsk_memmove(self->parents + self->parents_length, parents,\n        parents_length * sizeof(*self->parents));\n    self->parents_offset[self->num_rows + 1] = self->parents_length + parents_length;\n    self->parents_length += parents_length;\n    tsk_memmove(self->metadata + self->metadata_length, metadata,\n        metadata_length * sizeof(*self->metadata));\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length + metadata_length;\n    self->metadata_length += metadata_length;\n    self->num_rows++;\n    return (tsk_id_t) self->num_rows - 1;\n}\n\ntsk_id_t\ntsk_individual_table_add_row(tsk_individual_table_t *self, tsk_flags_t flags,\n    const double *location, tsk_size_t location_length, const tsk_id_t *parents,\n    tsk_size_t parents_length, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    ret = tsk_individual_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_expand_location(self, location_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_expand_parents(self, parents_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_add_row_internal(self, flags, location, location_length,\n        parents, parents_length, metadata, metadata_length);\nout:\n    return ret;\n}\n\nstatic int\ntsk_individual_table_update_row_rewrite(tsk_individual_table_t *self, tsk_id_t index,\n    tsk_flags_t flags, const double *location, tsk_size_t location_length,\n    const tsk_id_t *parents, tsk_size_t parents_length, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_individual_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_individual_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_individual_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_individual_table_add_row(self, flags, location, location_length,\n        parents, parents_length, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_individual_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_individual_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_individual_table_update_row(tsk_individual_table_t *self, tsk_id_t index,\n    tsk_flags_t flags, const double *location, tsk_size_t location_length,\n    const tsk_id_t *parents, tsk_size_t parents_length, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_individual_t current_row;\n\n    ret = tsk_individual_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.location_length == location_length\n        && current_row.parents_length == parents_length\n        && current_row.metadata_length == metadata_length) {\n        self->flags[index] = flags;\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->location[self->location_offset[index]], location,\n            location_length * sizeof(*location));\n        tsk_memmove(&self->parents[self->parents_offset[index]], parents,\n            parents_length * sizeof(*parents));\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_individual_table_update_row_rewrite(self, index, flags, location,\n            location_length, parents, parents_length, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_individual_table_clear(tsk_individual_table_t *self)\n{\n    return tsk_individual_table_truncate(self, 0);\n}\n\nint\ntsk_individual_table_truncate(tsk_individual_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->location_length = self->location_offset[num_rows];\n    self->parents_length = self->parents_offset[num_rows];\n    self->metadata_length = self->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_individual_table_extend(tsk_individual_table_t *self,\n    const tsk_individual_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_individual_t individual;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_individual_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_individual_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &individual);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_individual_table_add_row(self, individual.flags,\n            individual.location, individual.location_length, individual.parents,\n            individual.parents_length, individual.metadata, individual.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_individual_table_print_state(const tsk_individual_table_t *self, FILE *out)\n{\n    tsk_size_t j, k;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"tsk_individual_tbl: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows          = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"metadata_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    /* We duplicate the dump_text code here because we want to output\n     * the offset columns. */\n    write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    fprintf(out, \"id\\tflags\\tlocation_offset\\tlocation\\t\");\n    fprintf(out, \"parents_offset\\tparents\\t\");\n    fprintf(out, \"metadata_offset\\tmetadata\\n\");\n    for (j = 0; j < self->num_rows; j++) {\n        fprintf(out, \"%lld\\t%lld\\t\", (long long) j, (long long) self->flags[j]);\n        fprintf(out, \"%lld\\t\", (long long) self->location_offset[j]);\n        for (k = self->location_offset[j]; k < self->location_offset[j + 1]; k++) {\n            fprintf(out, \"%f\", self->location[k]);\n            if (k + 1 < self->location_offset[j + 1]) {\n                fprintf(out, \",\");\n            }\n        }\n        fprintf(out, \"\\t\");\n        fprintf(out, \"%lld\\t\", (long long) self->parents_offset[j]);\n        for (k = self->parents_offset[j]; k < self->parents_offset[j + 1]; k++) {\n            fprintf(out, \"%lld\", (long long) self->parents[k]);\n            if (k + 1 < self->parents_offset[j + 1]) {\n                fprintf(out, \",\");\n            }\n        }\n        fprintf(out, \"\\t\");\n        fprintf(out, \"%lld\\t\", (long long) self->metadata_offset[j]);\n        for (k = self->metadata_offset[j]; k < self->metadata_offset[j + 1]; k++) {\n            fprintf(out, \"%c\", self->metadata[k]);\n        }\n        fprintf(out, \"\\n\");\n    }\n}\n\nstatic inline void\ntsk_individual_table_get_row_unsafe(\n    const tsk_individual_table_t *self, tsk_id_t index, tsk_individual_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->flags = self->flags[index];\n    row->location_length\n        = self->location_offset[index + 1] - self->location_offset[index];\n    row->location = self->location + self->location_offset[index];\n    row->parents_length = self->parents_offset[index + 1] - self->parents_offset[index];\n    row->parents = self->parents + self->parents_offset[index];\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n    /* Also have referencing individuals here. Should this be a different struct?\n     * See also site. */\n    row->nodes_length = 0;\n    row->nodes = NULL;\n}\n\nint\ntsk_individual_table_get_row(\n    const tsk_individual_table_t *self, tsk_id_t index, tsk_individual_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_individual_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_individual_table_set_metadata_schema(tsk_individual_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_individual_table_dump_text(const tsk_individual_table_t *self, FILE *out)\n{\n    int ret = TSK_ERR_IO;\n    tsk_size_t j, k;\n    tsk_size_t metadata_len;\n    int err;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"id\\tflags\\tlocation\\tparents\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%lld\\t%lld\\t\", (long long) j, (long long) self->flags[j]);\n        if (err < 0) {\n            goto out;\n        }\n        for (k = self->location_offset[j]; k < self->location_offset[j + 1]; k++) {\n            err = fprintf(out, \"%.*g\", TSK_DBL_DECIMAL_DIG, self->location[k]);\n            if (err < 0) {\n                goto out;\n            }\n            if (k + 1 < self->location_offset[j + 1]) {\n                err = fprintf(out, \",\");\n                if (err < 0) {\n                    goto out;\n                }\n            }\n        }\n        err = fprintf(out, \"\\t\");\n        if (err < 0) {\n            goto out;\n        }\n        for (k = self->parents_offset[j]; k < self->parents_offset[j + 1]; k++) {\n            err = fprintf(out, \"%lld\", (long long) self->parents[k]);\n            if (err < 0) {\n                goto out;\n            }\n            if (k + 1 < self->parents_offset[j + 1]) {\n                err = fprintf(out, \",\");\n                if (err < 0) {\n                    goto out;\n                }\n            }\n        }\n        err = fprintf(out, \"\\t%.*s\\n\", (int) metadata_len,\n            self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_individual_table_equals(const tsk_individual_table_t *self,\n    const tsk_individual_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && tsk_memcmp(self->flags, other->flags, self->num_rows * sizeof(tsk_flags_t))\n                 == 0\n          && tsk_memcmp(self->location_offset, other->location_offset,\n                 (self->num_rows + 1) * sizeof(tsk_size_t))\n                 == 0\n          && tsk_memcmp(\n                 self->location, other->location, self->location_length * sizeof(double))\n                 == 0\n          && tsk_memcmp(self->parents_offset, other->parents_offset,\n                 (self->num_rows + 1) * sizeof(tsk_size_t))\n                 == 0\n          && tsk_memcmp(\n                 self->parents, other->parents, self->parents_length * sizeof(tsk_id_t))\n                 == 0;\n\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_individual_table_keep_rows(tsk_individual_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *ret_id_map)\n{\n    int ret = 0;\n    const tsk_size_t current_num_rows = self->num_rows;\n    tsk_size_t j, k, remaining_rows;\n    tsk_id_t pk;\n    tsk_id_t *id_map = ret_id_map;\n    tsk_id_t *restrict parents = self->parents;\n    tsk_size_t *restrict parents_offset = self->parents_offset;\n\n    if (ret_id_map == NULL) {\n        id_map = tsk_malloc(current_num_rows * sizeof(*id_map));\n        if (id_map == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    keep_mask_to_id_map(current_num_rows, keep, id_map);\n\n    /* See notes in tsk_mutation_table_keep_rows for possibilities\n     * on making this more flexible */\n    for (j = 0; j < current_num_rows; j++) {\n        if (keep[j]) {\n            for (k = parents_offset[j]; k < parents_offset[j + 1]; k++) {\n                pk = parents[k];\n                if (pk != TSK_NULL) {\n                    if (pk < 0 || pk >= (tsk_id_t) current_num_rows) {\n                        ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS);\n                        ;\n                        goto out;\n                    }\n                    if (id_map[pk] == TSK_NULL) {\n                        ret = tsk_trace_error(TSK_ERR_KEEP_ROWS_MAP_TO_DELETED);\n                        goto out;\n                    }\n                }\n            }\n        }\n    }\n\n    remaining_rows = subset_flags_column(self->flags, current_num_rows, keep);\n    self->parents_length = subset_remap_ragged_id_column(\n        self->parents, self->parents_offset, current_num_rows, keep, id_map);\n    self->location_length = subset_ragged_double_column(\n        self->location, self->location_offset, current_num_rows, keep);\n    if (self->metadata_length > 0) {\n        /* Implementation note: we special case metadata here because\n         * it'll make the common-case of no metadata a bit faster, and\n         * to also potentially support more general use of the\n         * TSK_TABLE_NO_METADATA option. This is done for all the tables\n         * but only commented on here. */\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, current_num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\nout:\n    if (ret_id_map == NULL) {\n        tsk_safe_free(id_map);\n    }\n    return ret;\n}\n\nstatic int\ntsk_individual_table_dump(\n    const tsk_individual_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t write_cols[] = {\n        { \"individuals/flags\", (void *) self->flags, self->num_rows,\n            TSK_FLAGS_STORAGE_TYPE },\n        { \"individuals/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"individuals/location\", (void *) self->location, self->location_length,\n            KAS_FLOAT64, self->location_offset, self->num_rows },\n        { \"individuals/parents\", (void *) self->parents, self->parents_length,\n            TSK_ID_STORAGE_TYPE, self->parents_offset, self->num_rows },\n        { \"individuals/metadata\", (void *) self->metadata, self->metadata_length,\n            KAS_UINT8, self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, write_cols, ragged_cols, options);\n}\n\nstatic int\ntsk_individual_table_load(tsk_individual_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    tsk_flags_t *flags = NULL;\n    double *location = NULL;\n    tsk_size_t *location_offset = NULL;\n    tsk_id_t *parents = NULL;\n    tsk_size_t *parents_offset = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    char *metadata_schema = NULL;\n    tsk_size_t num_rows, location_length, parents_length, metadata_length,\n        metadata_schema_length;\n\n    read_table_col_t cols[] = {\n        { \"individuals/flags\", (void **) &flags, TSK_FLAGS_STORAGE_TYPE, 0 },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"individuals/location\", (void **) &location, &location_length, KAS_FLOAT64,\n            &location_offset, 0 },\n        { \"individuals/parents\", (void **) &parents, &parents_length,\n            TSK_ID_STORAGE_TYPE, &parents_offset, TSK_COL_OPTIONAL },\n        { \"individuals/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, 0 },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"individuals/metadata_schema\", (void **) &metadata_schema,\n            &metadata_schema_length, KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_individual_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_individual_table_takeset_columns(self, num_rows, flags, location,\n        location_offset, parents, parents_offset, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    flags = NULL;\n    location = NULL;\n    location_offset = NULL;\n    parents = NULL;\n    parents_offset = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\n\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * node table\n *************************/\n\nstatic void\ntsk_node_table_free_columns(tsk_node_table_t *self)\n{\n    tsk_safe_free(self->flags);\n    tsk_safe_free(self->time);\n    tsk_safe_free(self->population);\n    tsk_safe_free(self->individual);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_node_table_free(tsk_node_table_t *self)\n{\n    tsk_node_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_node_table_expand_main_columns(tsk_node_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (new_max_rows > self->max_rows) {\n        ret = expand_column((void **) &self->flags, new_max_rows, sizeof(tsk_flags_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->time, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->population, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->individual, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_node_table_expand_metadata(tsk_node_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_node_table_set_max_rows_increment(\n    tsk_node_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_node_table_set_max_metadata_length_increment(\n    tsk_node_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_node_table_init(tsk_node_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_node_table_t));\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_node_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_node_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_node_table_copy(\n    const tsk_node_table_t *self, tsk_node_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_node_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_node_table_set_columns(dest, self->num_rows, self->flags, self->time,\n        self->population, self->individual, self->metadata, self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_node_table_set_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *time, const tsk_id_t *population,\n    const tsk_id_t *individual, const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n\n    ret = tsk_node_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_append_columns(\n        self, num_rows, flags, time, population, individual, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_node_table_takeset_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    tsk_flags_t *flags, double *time, tsk_id_t *population, tsk_id_t *individual,\n    char *metadata, tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    if (flags == NULL || time == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_node_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n    self->flags = flags;\n    self->time = time;\n\n    ret = takeset_optional_id_column(num_rows, population, &self->population);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_optional_id_column(num_rows, individual, &self->individual);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_node_table_append_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *time, const tsk_id_t *population,\n    const tsk_id_t *individual, const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n    tsk_size_t j, metadata_length;\n\n    if (flags == NULL || time == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = tsk_node_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->time + self->num_rows, time, num_rows * sizeof(double));\n    tsk_memcpy(self->flags + self->num_rows, flags, num_rows * sizeof(tsk_flags_t));\n    if (metadata == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j + 1] = self->metadata_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, metadata_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j]\n                = (tsk_size_t) self->metadata_length + metadata_offset[j];\n        }\n        metadata_length = metadata_offset[num_rows];\n        ret = tsk_node_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->metadata + self->metadata_length, metadata,\n            metadata_length * sizeof(char));\n        self->metadata_length += metadata_length;\n    }\n    if (population == NULL) {\n        /* Set population to NULL_POPULATION (-1) if not specified */\n        tsk_memset(self->population + self->num_rows, 0xff, num_rows * sizeof(tsk_id_t));\n    } else {\n        tsk_memcpy(\n            self->population + self->num_rows, population, num_rows * sizeof(tsk_id_t));\n    }\n    if (individual == NULL) {\n        /* Set individual to NULL_INDIVIDUAL (-1) if not specified */\n        tsk_memset(self->individual + self->num_rows, 0xff, num_rows * sizeof(tsk_id_t));\n    } else {\n        tsk_memcpy(\n            self->individual + self->num_rows, individual, num_rows * sizeof(tsk_id_t));\n    }\n    self->num_rows += (tsk_size_t) num_rows;\n    self->metadata_offset[self->num_rows] = self->metadata_length;\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_node_table_add_row_internal(tsk_node_table_t *self, tsk_flags_t flags, double time,\n    tsk_id_t population, tsk_id_t individual, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    tsk_bug_assert(self->metadata_length + metadata_length <= self->max_metadata_length);\n    tsk_memmove(self->metadata + self->metadata_length, metadata, metadata_length);\n    self->flags[self->num_rows] = flags;\n    self->time[self->num_rows] = time;\n    self->population[self->num_rows] = population;\n    self->individual[self->num_rows] = individual;\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length + metadata_length;\n    self->metadata_length += metadata_length;\n    self->num_rows++;\n    return (tsk_id_t) self->num_rows - 1;\n}\n\ntsk_id_t\ntsk_node_table_add_row(tsk_node_table_t *self, tsk_flags_t flags, double time,\n    tsk_id_t population, tsk_id_t individual, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    ret = tsk_node_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_add_row_internal(\n        self, flags, time, population, individual, metadata, metadata_length);\nout:\n    return ret;\n}\n\nstatic int\ntsk_node_table_update_row_rewrite(tsk_node_table_t *self, tsk_id_t index,\n    tsk_flags_t flags, double time, tsk_id_t population, tsk_id_t individual,\n    const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_node_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_node_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_node_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_node_table_add_row(\n        self, flags, time, population, individual, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_node_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_node_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_node_table_update_row(tsk_node_table_t *self, tsk_id_t index, tsk_flags_t flags,\n    double time, tsk_id_t population, tsk_id_t individual, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_node_t current_row;\n\n    ret = tsk_node_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length) {\n        self->flags[index] = flags;\n        self->time[index] = time;\n        self->population[index] = population;\n        self->individual[index] = individual;\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_node_table_update_row_rewrite(\n            self, index, flags, time, population, individual, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_node_table_clear(tsk_node_table_t *self)\n{\n    return tsk_node_table_truncate(self, 0);\n}\n\nint\ntsk_node_table_truncate(tsk_node_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->metadata_length = self->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_node_table_extend(tsk_node_table_t *self, const tsk_node_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_node_t node;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_node_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_node_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &node);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_node_table_add_row(self, node.flags, node.time, node.population,\n            node.individual, node.metadata, node.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_node_table_print_state(const tsk_node_table_t *self, FILE *out)\n{\n    tsk_size_t j, k;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"tsk_node_tbl: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows          = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"metadata_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    /* We duplicate the dump_text code here for simplicity because we want to output\n     * the flags column directly. */\n    write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    fprintf(out, \"id\\tflags\\ttime\\tpopulation\\tindividual\\tmetadata_offset\\tmetadata\\n\");\n    for (j = 0; j < self->num_rows; j++) {\n        fprintf(out, \"%lld\\t%lld\\t%f\\t%lld\\t%lld\\t%lld\\t\", (long long) j,\n            (long long) self->flags[j], self->time[j], (long long) self->population[j],\n            (long long) self->individual[j], (long long) self->metadata_offset[j]);\n        for (k = self->metadata_offset[j]; k < self->metadata_offset[j + 1]; k++) {\n            fprintf(out, \"%c\", self->metadata[k]);\n        }\n        fprintf(out, \"\\n\");\n    }\n    tsk_bug_assert(self->metadata_offset[0] == 0);\n    tsk_bug_assert(self->metadata_offset[self->num_rows] == self->metadata_length);\n}\n\nint\ntsk_node_table_set_metadata_schema(tsk_node_table_t *self, const char *metadata_schema,\n    tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_node_table_dump_text(const tsk_node_table_t *self, FILE *out)\n{\n    int ret = TSK_ERR_IO;\n    tsk_size_t j;\n    tsk_size_t metadata_len;\n    int err;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"id\\tis_sample\\ttime\\tpopulation\\tindividual\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%lld\\t%lld\\t%f\\t%lld\\t%lld\\t%.*s\\n\", (long long) j,\n            (long long) (self->flags[j] & TSK_NODE_IS_SAMPLE), self->time[j],\n            (long long) self->population[j], (long long) self->individual[j],\n            (int) metadata_len, self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_node_table_equals(\n    const tsk_node_table_t *self, const tsk_node_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && tsk_memcmp(self->time, other->time, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->flags, other->flags, self->num_rows * sizeof(tsk_flags_t))\n                 == 0\n          && tsk_memcmp(\n                 self->population, other->population, self->num_rows * sizeof(tsk_id_t))\n                 == 0\n          && tsk_memcmp(\n                 self->individual, other->individual, self->num_rows * sizeof(tsk_id_t))\n                 == 0;\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nstatic inline void\ntsk_node_table_get_row_unsafe(\n    const tsk_node_table_t *self, tsk_id_t index, tsk_node_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->flags = self->flags[index];\n    row->time = self->time[index];\n    row->population = self->population[index];\n    row->individual = self->individual[index];\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n}\n\nint\ntsk_node_table_get_row(const tsk_node_table_t *self, tsk_id_t index, tsk_node_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_node_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_node_table_keep_rows(tsk_node_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n    tsk_size_t remaining_rows;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n\n    remaining_rows = subset_flags_column(self->flags, self->num_rows, keep);\n    subset_double_column(self->time, self->num_rows, keep);\n    subset_id_column(self->population, self->num_rows, keep);\n    subset_id_column(self->individual, self->num_rows, keep);\n    if (self->metadata_length > 0) {\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, self->num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\n    return ret;\n}\n\nstatic int\ntsk_node_table_dump(const tsk_node_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t cols[] = {\n        { \"nodes/time\", (void *) self->time, self->num_rows, KAS_FLOAT64 },\n        { \"nodes/flags\", (void *) self->flags, self->num_rows, TSK_FLAGS_STORAGE_TYPE },\n        { \"nodes/population\", (void *) self->population, self->num_rows,\n            TSK_ID_STORAGE_TYPE },\n        { \"nodes/individual\", (void *) self->individual, self->num_rows,\n            TSK_ID_STORAGE_TYPE },\n        { \"nodes/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"nodes/metadata\", (void *) self->metadata, self->metadata_length, KAS_UINT8,\n            self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, cols, ragged_cols, options);\n}\n\nstatic int\ntsk_node_table_load(tsk_node_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    char *metadata_schema = NULL;\n    double *time = NULL;\n    tsk_flags_t *flags = NULL;\n    tsk_id_t *population = NULL;\n    tsk_id_t *individual = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    tsk_size_t num_rows, metadata_length, metadata_schema_length;\n    read_table_col_t cols[] = {\n        { \"nodes/time\", (void **) &time, KAS_FLOAT64, 0 },\n        { \"nodes/flags\", (void **) &flags, TSK_FLAGS_STORAGE_TYPE, 0 },\n        { \"nodes/population\", (void **) &population, TSK_ID_STORAGE_TYPE, 0 },\n        { \"nodes/individual\", (void **) &individual, TSK_ID_STORAGE_TYPE, 0 },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"nodes/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, 0 },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"nodes/metadata_schema\", (void **) &metadata_schema, &metadata_schema_length,\n            KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_node_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_node_table_takeset_columns(\n        self, num_rows, flags, time, population, individual, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    flags = NULL;\n    time = NULL;\n    population = NULL;\n    individual = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * edge table\n *************************/\n\nstatic void\ntsk_edge_table_free_columns(tsk_edge_table_t *self)\n{\n    tsk_safe_free(self->left);\n    tsk_safe_free(self->right);\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->child);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_edge_table_free(tsk_edge_table_t *self)\n{\n    tsk_edge_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_edge_table_has_metadata(const tsk_edge_table_t *self)\n{\n    return !(self->options & TSK_TABLE_NO_METADATA);\n}\n\nstatic int\ntsk_edge_table_expand_main_columns(tsk_edge_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column((void **) &self->left, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->right, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->parent, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->child, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        if (tsk_edge_table_has_metadata(self)) {\n            ret = expand_column(\n                (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n            if (ret != 0) {\n                goto out;\n            }\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_edge_table_expand_metadata(tsk_edge_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_edge_table_set_max_rows_increment(\n    tsk_edge_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_edge_table_set_max_metadata_length_increment(\n    tsk_edge_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_edge_table_init(tsk_edge_table_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(*self));\n    self->options = options;\n\n    /* Allocate space for one row initially, ensuring we always have valid\n     * pointers even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_edge_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    if (tsk_edge_table_has_metadata(self)) {\n        ret = tsk_edge_table_expand_metadata(self, 1);\n        if (ret != 0) {\n            goto out;\n        }\n        self->metadata_offset[0] = 0;\n    }\n    self->max_rows_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_edge_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\ntsk_id_t\ntsk_edge_table_add_row(tsk_edge_table_t *self, double left, double right,\n    tsk_id_t parent, tsk_id_t child, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    if (metadata_length > 0 && !tsk_edge_table_has_metadata(self)) {\n        ret = tsk_trace_error(TSK_ERR_METADATA_DISABLED);\n        goto out;\n    }\n\n    ret = tsk_edge_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    self->left[self->num_rows] = left;\n    self->right[self->num_rows] = right;\n    self->parent[self->num_rows] = parent;\n    self->child[self->num_rows] = child;\n\n    if (tsk_edge_table_has_metadata(self)) {\n        ret = tsk_edge_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_bug_assert(\n            self->metadata_length + metadata_length <= self->max_metadata_length);\n        tsk_memmove(self->metadata + self->metadata_length, metadata, metadata_length);\n        self->metadata_offset[self->num_rows + 1]\n            = self->metadata_length + metadata_length;\n        self->metadata_length += metadata_length;\n    }\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\nout:\n    return ret;\n}\n\nstatic int\ntsk_edge_table_update_row_rewrite(tsk_edge_table_t *self, tsk_id_t index, double left,\n    double right, tsk_id_t parent, tsk_id_t child, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_edge_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_edge_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_edge_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_edge_table_add_row(\n        self, left, right, parent, child, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_edge_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_edge_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_edge_table_update_row(tsk_edge_table_t *self, tsk_id_t index, double left,\n    double right, tsk_id_t parent, tsk_id_t child, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_edge_t current_row;\n\n    ret = tsk_edge_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length) {\n        self->left[index] = left;\n        self->right[index] = right;\n        self->parent[index] = parent;\n        self->child[index] = child;\n        if (tsk_edge_table_has_metadata(self)) {\n            /* Note: important to use tsk_memmove here as we may be provided pointers\n             * to the column memory as input via get_row */\n            tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n                metadata_length * sizeof(*metadata));\n        }\n    } else {\n        ret = tsk_edge_table_update_row_rewrite(\n            self, index, left, right, parent, child, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_edge_table_copy(\n    const tsk_edge_table_t *self, tsk_edge_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_edge_table_init(dest, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    /* We can't use TSK_TABLE_NO_METADATA in dest if metadata_length is non-zero.\n     * This also captures the case where TSK_TABLE_NO_METADATA is set on this table.\n     */\n    if (self->metadata_length > 0 && !tsk_edge_table_has_metadata(dest)) {\n        ret = tsk_trace_error(TSK_ERR_METADATA_DISABLED);\n        goto out;\n    }\n    if (tsk_edge_table_has_metadata(dest)) {\n        metadata = self->metadata;\n        metadata_offset = self->metadata_offset;\n    }\n    ret = tsk_edge_table_set_columns(dest, self->num_rows, self->left, self->right,\n        self->parent, self->child, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint\ntsk_edge_table_set_columns(tsk_edge_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *parent,\n    const tsk_id_t *child, const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    ret = tsk_edge_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_append_columns(\n        self, num_rows, left, right, parent, child, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_edge_table_takeset_columns(tsk_edge_table_t *self, tsk_size_t num_rows, double *left,\n    double *right, tsk_id_t *parent, tsk_id_t *child, char *metadata,\n    tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    if (left == NULL || right == NULL || parent == NULL || child == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (metadata != NULL && !tsk_edge_table_has_metadata(self)) {\n        ret = tsk_trace_error(TSK_ERR_METADATA_DISABLED);\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_edge_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n    self->left = left;\n    self->right = right;\n    self->parent = parent;\n    self->child = child;\n\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_edge_table_append_columns(tsk_edge_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *parent,\n    const tsk_id_t *child, const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n    tsk_size_t j, metadata_length;\n\n    if (left == NULL || right == NULL || parent == NULL || child == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (metadata != NULL && !tsk_edge_table_has_metadata(self)) {\n        ret = tsk_trace_error(TSK_ERR_METADATA_DISABLED);\n        goto out;\n    }\n\n    ret = tsk_edge_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->left + self->num_rows, left, num_rows * sizeof(double));\n    tsk_memcpy(self->right + self->num_rows, right, num_rows * sizeof(double));\n    tsk_memcpy(self->parent + self->num_rows, parent, num_rows * sizeof(tsk_id_t));\n    tsk_memcpy(self->child + self->num_rows, child, num_rows * sizeof(tsk_id_t));\n    if (tsk_edge_table_has_metadata(self)) {\n        if (metadata == NULL) {\n            for (j = 0; j < num_rows; j++) {\n                self->metadata_offset[self->num_rows + j + 1] = self->metadata_length;\n            }\n        } else {\n            ret = check_offsets(num_rows, metadata_offset, 0, false);\n            if (ret != 0) {\n                goto out;\n            }\n            for (j = 0; j < num_rows; j++) {\n                self->metadata_offset[self->num_rows + j]\n                    = (tsk_size_t) self->metadata_length + metadata_offset[j];\n            }\n            metadata_length = metadata_offset[num_rows];\n            ret = tsk_edge_table_expand_metadata(self, metadata_length);\n            if (ret != 0) {\n                goto out;\n            }\n            tsk_memcpy(self->metadata + self->metadata_length, metadata,\n                metadata_length * sizeof(char));\n            self->metadata_length += metadata_length;\n        }\n        self->num_rows += num_rows;\n        self->metadata_offset[self->num_rows] = self->metadata_length;\n    } else {\n        self->num_rows += num_rows;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_edge_table_clear(tsk_edge_table_t *self)\n{\n    return tsk_edge_table_truncate(self, 0);\n}\n\nint\ntsk_edge_table_truncate(tsk_edge_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    if (tsk_edge_table_has_metadata(self)) {\n        self->metadata_length = self->metadata_offset[num_rows];\n    }\nout:\n    return ret;\n}\n\nint\ntsk_edge_table_extend(tsk_edge_table_t *self, const tsk_edge_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_edge_t edge;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_edge_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_edge_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &edge);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_edge_table_add_row(self, edge.left, edge.right, edge.parent,\n            edge.child, edge.metadata, edge.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic inline void\ntsk_edge_table_get_row_unsafe(\n    const tsk_edge_table_t *self, tsk_id_t index, tsk_edge_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->left = self->left[index];\n    row->right = self->right[index];\n    row->parent = self->parent[index];\n    row->child = self->child[index];\n    if (tsk_edge_table_has_metadata(self)) {\n        row->metadata_length\n            = self->metadata_offset[index + 1] - self->metadata_offset[index];\n        row->metadata = self->metadata + self->metadata_offset[index];\n    } else {\n        row->metadata_length = 0;\n        row->metadata = NULL;\n    }\n}\n\nint\ntsk_edge_table_get_row(const tsk_edge_table_t *self, tsk_id_t index, tsk_edge_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_EDGE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_edge_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nvoid\ntsk_edge_table_print_state(const tsk_edge_table_t *self, FILE *out)\n{\n    int ret;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"edge_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"options         = 0x%X\\n\", self->options);\n    fprintf(out, \"num_rows        = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"metadata_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    ret = tsk_edge_table_dump_text(self, out);\n    tsk_bug_assert(ret == 0);\n}\n\nint\ntsk_edge_table_set_metadata_schema(tsk_edge_table_t *self, const char *metadata_schema,\n    tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_edge_table_dump_text(const tsk_edge_table_t *self, FILE *out)\n{\n    tsk_id_t j;\n    int ret = TSK_ERR_IO;\n    tsk_edge_t row;\n    int err;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"id\\tleft\\tright\\tparent\\tchild\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < (tsk_id_t) self->num_rows; j++) {\n        tsk_edge_table_get_row_unsafe(self, j, &row);\n        err = fprintf(out, \"%lld\\t%.3f\\t%.3f\\t%lld\\t%lld\\t%.*s\\n\", (long long) j,\n            row.left, row.right, (long long) row.parent, (long long) row.child,\n            (int) row.metadata_length, row.metadata);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_edge_table_equals(\n    const tsk_edge_table_t *self, const tsk_edge_table_t *other, tsk_flags_t options)\n{\n    bool metadata_equal;\n    bool ret\n        = self->num_rows == other->num_rows\n          && tsk_memcmp(self->left, other->left, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->right, other->right, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->parent, other->parent, self->num_rows * sizeof(tsk_id_t))\n                 == 0\n          && tsk_memcmp(self->child, other->child, self->num_rows * sizeof(tsk_id_t))\n                 == 0;\n\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n        metadata_equal = false;\n        if (self->metadata_length == other->metadata_length) {\n            if (tsk_edge_table_has_metadata(self)\n                && tsk_edge_table_has_metadata(other)) {\n                metadata_equal\n                    = tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                          (self->num_rows + 1) * sizeof(tsk_size_t))\n                          == 0\n                      && tsk_memcmp(self->metadata, other->metadata,\n                             self->metadata_length * sizeof(char))\n                             == 0;\n            } else {\n                /* The only way that the metadata lengths can be equal (which\n                 * we've already tested) and either one or the other of the tables\n                 * hasn't got metadata is if they are both zero length. */\n                tsk_bug_assert(self->metadata_length == 0);\n                metadata_equal = true;\n            }\n        }\n        ret = ret && metadata_equal;\n    }\n    return ret;\n}\n\nint\ntsk_edge_table_keep_rows(tsk_edge_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n    tsk_size_t remaining_rows;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n    remaining_rows = subset_double_column(self->left, self->num_rows, keep);\n    subset_double_column(self->right, self->num_rows, keep);\n    subset_id_column(self->parent, self->num_rows, keep);\n    subset_id_column(self->child, self->num_rows, keep);\n    if (self->metadata_length > 0) {\n        tsk_bug_assert(!(self->options & TSK_TABLE_NO_METADATA));\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, self->num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\n    return ret;\n}\n\nstatic int\ntsk_edge_table_dump(const tsk_edge_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    int ret = 0;\n    const write_table_col_t write_cols[] = {\n        { \"edges/left\", (void *) self->left, self->num_rows, KAS_FLOAT64 },\n        { \"edges/right\", (void *) self->right, self->num_rows, KAS_FLOAT64 },\n        { \"edges/parent\", (void *) self->parent, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"edges/child\", (void *) self->child, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"edges/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"edges/metadata\", (void *) self->metadata, self->metadata_length, KAS_UINT8,\n            self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    /* TODO when the general code has been updated to only write out the\n     * column when the lenght of ragged columns is > 0 we can get rid of\n     * this special case here and use write_table. */\n    ret = write_table_cols(store, write_cols, options);\n    if (ret != 0) {\n        goto out;\n    }\n    if (tsk_edge_table_has_metadata(self)) {\n        ret = write_table_ragged_cols(store, ragged_cols, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_edge_table_load(tsk_edge_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    char *metadata_schema = NULL;\n    double *left = NULL;\n    double *right = NULL;\n    tsk_id_t *parent = NULL;\n    tsk_id_t *child = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    tsk_size_t num_rows, metadata_length, metadata_schema_length;\n\n    read_table_col_t cols[] = {\n        { \"edges/left\", (void **) &left, KAS_FLOAT64, 0 },\n        { \"edges/right\", (void **) &right, KAS_FLOAT64, 0 },\n        { \"edges/parent\", (void **) &parent, TSK_ID_STORAGE_TYPE, 0 },\n        { \"edges/child\", (void **) &child, TSK_ID_STORAGE_TYPE, 0 },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"edges/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"edges/metadata_schema\", (void **) &metadata_schema, &metadata_schema_length,\n            KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_edge_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_edge_table_takeset_columns(\n        self, num_rows, left, right, parent, child, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    left = NULL;\n    right = NULL;\n    parent = NULL;\n    child = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\nint\ntsk_edge_table_squash(tsk_edge_table_t *self)\n{\n    int k;\n    int ret = 0;\n    tsk_edge_t *edges = NULL;\n    tsk_size_t num_output_edges;\n\n    if (self->metadata_length > 0) {\n        ret = tsk_trace_error(TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA);\n        goto out;\n    }\n\n    edges = tsk_malloc(self->num_rows * sizeof(tsk_edge_t));\n    if (edges == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (k = 0; k < (int) self->num_rows; k++) {\n        edges[k].left = self->left[k];\n        edges[k].right = self->right[k];\n        edges[k].parent = self->parent[k];\n        edges[k].child = self->child[k];\n        edges[k].metadata_length = 0;\n    }\n\n    ret = tsk_squash_edges(edges, self->num_rows, &num_output_edges);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_edge_table_clear(self);\n    tsk_bug_assert(num_output_edges <= self->max_rows);\n    self->num_rows = num_output_edges;\n    for (k = 0; k < (int) num_output_edges; k++) {\n        self->left[k] = edges[k].left;\n        self->right[k] = edges[k].right;\n        self->parent[k] = edges[k].parent;\n        self->child[k] = edges[k].child;\n    }\nout:\n    tsk_safe_free(edges);\n    return ret;\n}\n\n/*************************\n * site table\n *************************/\n\nstatic void\ntsk_site_table_free_columns(tsk_site_table_t *self)\n{\n    tsk_safe_free(self->position);\n    tsk_safe_free(self->ancestral_state);\n    tsk_safe_free(self->ancestral_state_offset);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_site_table_free(tsk_site_table_t *self)\n{\n    tsk_site_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_site_table_expand_main_columns(tsk_site_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column((void **) &self->position, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->ancestral_state_offset, new_max_rows + 1,\n            sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_site_table_expand_ancestral_state(\n    tsk_site_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->ancestral_state_length, additional_length,\n        self->max_ancestral_state_length_increment, &self->max_ancestral_state_length,\n        (void **) &self->ancestral_state, sizeof(*self->ancestral_state));\n}\n\nstatic int\ntsk_site_table_expand_metadata(tsk_site_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_site_table_set_max_rows_increment(\n    tsk_site_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_site_table_set_max_metadata_length_increment(\n    tsk_site_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_site_table_set_max_ancestral_state_length_increment(\n    tsk_site_table_t *self, tsk_size_t max_ancestral_state_length_increment)\n{\n    self->max_ancestral_state_length_increment = max_ancestral_state_length_increment;\n    return 0;\n}\n\nint\ntsk_site_table_init(tsk_site_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_site_table_t));\n\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_ancestral_state_length_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_site_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_expand_ancestral_state(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->ancestral_state_offset[0] = 0;\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_ancestral_state_length_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_site_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\ntsk_id_t\ntsk_site_table_add_row(tsk_site_table_t *self, double position,\n    const char *ancestral_state, tsk_size_t ancestral_state_length, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n    tsk_size_t ancestral_state_offset, metadata_offset;\n\n    ret = tsk_site_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->position[self->num_rows] = position;\n\n    ancestral_state_offset = (tsk_size_t) self->ancestral_state_length;\n    tsk_bug_assert(\n        self->ancestral_state_offset[self->num_rows] == ancestral_state_offset);\n    ret = tsk_site_table_expand_ancestral_state(self, ancestral_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    self->ancestral_state_length += ancestral_state_length;\n    tsk_memmove(self->ancestral_state + ancestral_state_offset, ancestral_state,\n        ancestral_state_length);\n    self->ancestral_state_offset[self->num_rows + 1] = self->ancestral_state_length;\n\n    metadata_offset = (tsk_size_t) self->metadata_length;\n    tsk_bug_assert(self->metadata_offset[self->num_rows] == metadata_offset);\n    ret = tsk_site_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_length += metadata_length;\n    tsk_memmove(self->metadata + metadata_offset, metadata, metadata_length);\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length;\n\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\nout:\n    return ret;\n}\n\nstatic int\ntsk_site_table_update_row_rewrite(tsk_site_table_t *self, tsk_id_t index,\n    double position, const char *ancestral_state, tsk_size_t ancestral_state_length,\n    const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_site_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_site_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_site_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_site_table_add_row(self, position, ancestral_state,\n        ancestral_state_length, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_site_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_site_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_site_table_update_row(tsk_site_table_t *self, tsk_id_t index, double position,\n    const char *ancestral_state, tsk_size_t ancestral_state_length, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_site_t current_row;\n\n    ret = tsk_site_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length\n        && current_row.ancestral_state_length == ancestral_state_length) {\n        self->position[index] = position;\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->ancestral_state[self->ancestral_state_offset[index]],\n            ancestral_state, ancestral_state_length * sizeof(*ancestral_state));\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_site_table_update_row_rewrite(self, index, position, ancestral_state,\n            ancestral_state_length, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_site_table_append_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    const double *position, const char *ancestral_state,\n    const tsk_size_t *ancestral_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n    tsk_size_t j, ancestral_state_length, metadata_length;\n\n    if (position == NULL || ancestral_state == NULL || ancestral_state_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    ret = tsk_site_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->position + self->num_rows, position, num_rows * sizeof(double));\n\n    /* Metadata column */\n    if (metadata == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j + 1] = self->metadata_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, metadata_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        metadata_length = metadata_offset[num_rows];\n        ret = tsk_site_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->metadata + self->metadata_length, metadata,\n            metadata_length * sizeof(char));\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j]\n                = self->metadata_length + metadata_offset[j];\n        }\n        self->metadata_length += metadata_length;\n    }\n    self->metadata_offset[self->num_rows + num_rows] = self->metadata_length;\n\n    /* Ancestral state column */\n    ret = check_offsets(num_rows, ancestral_state_offset, 0, false);\n    if (ret != 0) {\n        goto out;\n    }\n    ancestral_state_length = ancestral_state_offset[num_rows];\n    ret = tsk_site_table_expand_ancestral_state(self, ancestral_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->ancestral_state + self->ancestral_state_length, ancestral_state,\n        ancestral_state_length * sizeof(char));\n    for (j = 0; j < num_rows; j++) {\n        self->ancestral_state_offset[self->num_rows + j]\n            = self->ancestral_state_length + ancestral_state_offset[j];\n    }\n    self->ancestral_state_length += ancestral_state_length;\n    self->ancestral_state_offset[self->num_rows + num_rows]\n        = self->ancestral_state_length;\n\n    self->num_rows += num_rows;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_site_table_copy(\n    const tsk_site_table_t *self, tsk_site_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_site_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_site_table_set_columns(dest, self->num_rows, self->position,\n        self->ancestral_state, self->ancestral_state_offset, self->metadata,\n        self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint\ntsk_site_table_set_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    const double *position, const char *ancestral_state,\n    const tsk_size_t *ancestral_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    ret = tsk_site_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_append_columns(self, num_rows, position, ancestral_state,\n        ancestral_state_offset, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nint\ntsk_site_table_takeset_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    double *position, char *ancestral_state, tsk_size_t *ancestral_state_offset,\n    char *metadata, tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    if (position == NULL || ancestral_state == NULL || ancestral_state_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, ancestral_state, ancestral_state_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_site_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n    self->position = position;\n\n    ret = takeset_ragged_column(num_rows, ancestral_state, ancestral_state_offset,\n        (void *) &self->ancestral_state, &self->ancestral_state_offset,\n        &self->ancestral_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nbool\ntsk_site_table_equals(\n    const tsk_site_table_t *self, const tsk_site_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && self->ancestral_state_length == other->ancestral_state_length\n          && tsk_memcmp(self->position, other->position, self->num_rows * sizeof(double))\n                 == 0\n          && tsk_memcmp(self->ancestral_state_offset, other->ancestral_state_offset,\n                 (self->num_rows + 1) * sizeof(tsk_size_t))\n                 == 0\n          && tsk_memcmp(self->ancestral_state, other->ancestral_state,\n                 self->ancestral_state_length * sizeof(char))\n                 == 0;\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_site_table_clear(tsk_site_table_t *self)\n{\n    return tsk_site_table_truncate(self, 0);\n}\n\nint\ntsk_site_table_truncate(tsk_site_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->ancestral_state_length = self->ancestral_state_offset[num_rows];\n    self->metadata_length = self->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_site_table_extend(tsk_site_table_t *self, const tsk_site_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_site_t site;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_site_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_site_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &site);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_site_table_add_row(self, site.position, site.ancestral_state,\n            site.ancestral_state_length, site.metadata, site.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_site_table_print_state(const tsk_site_table_t *self, FILE *out)\n{\n    int ret;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"site_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows = %lld\\t(max= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"ancestral_state_length = %lld\\t(max= %lld\\tincrement = %lld)\\n\",\n        (long long) self->ancestral_state_length,\n        (long long) self->max_ancestral_state_length,\n        (long long) self->max_ancestral_state_length_increment);\n    fprintf(out, \"metadata_length = %lld(\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    ret = tsk_site_table_dump_text(self, out);\n    tsk_bug_assert(ret == 0);\n\n    tsk_bug_assert(self->ancestral_state_offset[0] == 0);\n    tsk_bug_assert(\n        self->ancestral_state_length == self->ancestral_state_offset[self->num_rows]);\n    tsk_bug_assert(self->metadata_offset[0] == 0);\n    tsk_bug_assert(self->metadata_length == self->metadata_offset[self->num_rows]);\n}\n\nstatic inline void\ntsk_site_table_get_row_unsafe(\n    const tsk_site_table_t *self, tsk_id_t index, tsk_site_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->position = self->position[index];\n    row->ancestral_state_length\n        = self->ancestral_state_offset[index + 1] - self->ancestral_state_offset[index];\n    row->ancestral_state = self->ancestral_state + self->ancestral_state_offset[index];\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n    /* This struct has a placeholder for mutations. Probably should be separate\n     * structs for this (tsk_site_table_row_t?) */\n    row->mutations_length = 0;\n    row->mutations = NULL;\n}\n\nint\ntsk_site_table_get_row(const tsk_site_table_t *self, tsk_id_t index, tsk_site_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_SITE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_site_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_site_table_set_metadata_schema(tsk_site_table_t *self, const char *metadata_schema,\n    tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_site_table_dump_text(const tsk_site_table_t *self, FILE *out)\n{\n    tsk_size_t j;\n    int ret = TSK_ERR_IO;\n    int err;\n    tsk_size_t ancestral_state_len, metadata_len;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"id\\tposition\\tancestral_state\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        ancestral_state_len\n            = self->ancestral_state_offset[j + 1] - self->ancestral_state_offset[j];\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%lld\\t%f\\t%.*s\\t%.*s\\n\", (long long) j, self->position[j],\n            (int) ancestral_state_len,\n            self->ancestral_state + self->ancestral_state_offset[j], (int) metadata_len,\n            self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nint\ntsk_site_table_keep_rows(tsk_site_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n    tsk_size_t remaining_rows;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n\n    remaining_rows = subset_double_column(self->position, self->num_rows, keep);\n    self->ancestral_state_length = subset_ragged_char_column(\n        self->ancestral_state, self->ancestral_state_offset, self->num_rows, keep);\n    if (self->metadata_length > 0) {\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, self->num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\n    return ret;\n}\n\nstatic int\ntsk_site_table_dump(const tsk_site_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t cols[] = {\n        { \"sites/position\", (void *) self->position, self->num_rows, KAS_FLOAT64 },\n        { \"sites/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"sites/ancestral_state\", (void *) self->ancestral_state,\n            self->ancestral_state_length, KAS_UINT8, self->ancestral_state_offset,\n            self->num_rows },\n        { \"sites/metadata\", (void *) self->metadata, self->metadata_length, KAS_UINT8,\n            self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, cols, ragged_cols, options);\n}\n\nstatic int\ntsk_site_table_load(tsk_site_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    char *metadata_schema = NULL;\n    double *position = NULL;\n    char *ancestral_state = NULL;\n    tsk_size_t *ancestral_state_offset = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    tsk_size_t num_rows, ancestral_state_length, metadata_length, metadata_schema_length;\n\n    read_table_col_t cols[] = {\n        { \"sites/position\", (void **) &position, KAS_FLOAT64, 0 },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"sites/ancestral_state\", (void **) &ancestral_state, &ancestral_state_length,\n            KAS_UINT8, &ancestral_state_offset, 0 },\n        { \"sites/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, 0 },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"sites/metadata_schema\", (void **) &metadata_schema, &metadata_schema_length,\n            KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_site_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_site_table_takeset_columns(self, num_rows, position, ancestral_state,\n        ancestral_state_offset, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    position = NULL;\n    ancestral_state = NULL;\n    ancestral_state_offset = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\n\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * mutation table\n *************************/\n\nstatic void\ntsk_mutation_table_free_columns(tsk_mutation_table_t *self)\n{\n    tsk_safe_free(self->node);\n    tsk_safe_free(self->site);\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->time);\n    tsk_safe_free(self->derived_state);\n    tsk_safe_free(self->derived_state_offset);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_mutation_table_free(tsk_mutation_table_t *self)\n{\n    tsk_mutation_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_mutation_table_expand_main_columns(\n    tsk_mutation_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column((void **) &self->site, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->node, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->parent, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->time, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->derived_state_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_mutation_table_expand_derived_state(\n    tsk_mutation_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->derived_state_length, additional_length,\n        self->max_derived_state_length_increment, &self->max_derived_state_length,\n        (void **) &self->derived_state, sizeof(*self->derived_state));\n}\n\nstatic int\ntsk_mutation_table_expand_metadata(\n    tsk_mutation_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_mutation_table_set_max_rows_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_mutation_table_set_max_metadata_length_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_mutation_table_set_max_derived_state_length_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_derived_state_length_increment)\n{\n    self->max_derived_state_length_increment = max_derived_state_length_increment;\n    return 0;\n}\n\nint\ntsk_mutation_table_init(tsk_mutation_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_mutation_table_t));\n\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_derived_state_length_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_mutation_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_expand_derived_state(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->derived_state_offset[0] = 0;\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_derived_state_length_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_mutation_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\ntsk_id_t\ntsk_mutation_table_add_row(tsk_mutation_table_t *self, tsk_id_t site, tsk_id_t node,\n    tsk_id_t parent, double time, const char *derived_state,\n    tsk_size_t derived_state_length, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_id_t ret;\n    tsk_size_t derived_state_offset, metadata_offset;\n\n    ret = tsk_mutation_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->site[self->num_rows] = site;\n    self->node[self->num_rows] = node;\n    self->parent[self->num_rows] = parent;\n    self->time[self->num_rows] = time;\n\n    derived_state_offset = self->derived_state_length;\n    tsk_bug_assert(self->derived_state_offset[self->num_rows] == derived_state_offset);\n    ret = tsk_mutation_table_expand_derived_state(self, derived_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    self->derived_state_length += derived_state_length;\n    tsk_memmove(\n        self->derived_state + derived_state_offset, derived_state, derived_state_length);\n    self->derived_state_offset[self->num_rows + 1] = self->derived_state_length;\n\n    metadata_offset = self->metadata_length;\n    tsk_bug_assert(self->metadata_offset[self->num_rows] == metadata_offset);\n    ret = tsk_mutation_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_length += metadata_length;\n    tsk_memmove(self->metadata + metadata_offset, metadata, metadata_length);\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length;\n\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\nout:\n    return ret;\n}\n\nstatic int\ntsk_mutation_table_update_row_rewrite(tsk_mutation_table_t *self, tsk_id_t index,\n    tsk_id_t site, tsk_id_t node, tsk_id_t parent, double time,\n    const char *derived_state, tsk_size_t derived_state_length, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_mutation_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_mutation_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_mutation_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_mutation_table_add_row(self, site, node, parent, time, derived_state,\n        derived_state_length, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_mutation_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_mutation_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_mutation_table_update_row(tsk_mutation_table_t *self, tsk_id_t index, tsk_id_t site,\n    tsk_id_t node, tsk_id_t parent, double time, const char *derived_state,\n    tsk_size_t derived_state_length, const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_mutation_t current_row;\n\n    ret = tsk_mutation_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length\n        && current_row.derived_state_length == derived_state_length) {\n        self->site[index] = site;\n        self->node[index] = node;\n        self->parent[index] = parent;\n        self->time[index] = time;\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->derived_state[self->derived_state_offset[index]],\n            derived_state, derived_state_length * sizeof(*derived_state));\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_mutation_table_update_row_rewrite(self, index, site, node, parent,\n            time, derived_state, derived_state_length, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_mutation_table_append_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    const tsk_id_t *site, const tsk_id_t *node, const tsk_id_t *parent,\n    const double *time, const char *derived_state,\n    const tsk_size_t *derived_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n    tsk_size_t j, derived_state_length, metadata_length;\n\n    if (site == NULL || node == NULL || derived_state == NULL\n        || derived_state_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    ret = tsk_mutation_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->site + self->num_rows, site, num_rows * sizeof(tsk_id_t));\n    tsk_memcpy(self->node + self->num_rows, node, num_rows * sizeof(tsk_id_t));\n    if (parent == NULL) {\n        /* If parent is NULL, set all parents to the null mutation */\n        tsk_memset(self->parent + self->num_rows, 0xff, num_rows * sizeof(tsk_id_t));\n    } else {\n        tsk_memcpy(self->parent + self->num_rows, parent, num_rows * sizeof(tsk_id_t));\n    }\n    if (time == NULL) {\n        /* If time is NULL, set all times to TSK_UNKNOWN_TIME which is the\n         * default */\n        for (j = 0; j < num_rows; j++) {\n            self->time[self->num_rows + j] = TSK_UNKNOWN_TIME;\n        }\n    } else {\n        tsk_memcpy(self->time + self->num_rows, time, num_rows * sizeof(double));\n    }\n\n    /* Metadata column */\n    if (metadata == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j + 1] = self->metadata_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, metadata_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        metadata_length = metadata_offset[num_rows];\n        ret = tsk_mutation_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->metadata + self->metadata_length, metadata,\n            metadata_length * sizeof(char));\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j]\n                = self->metadata_length + metadata_offset[j];\n        }\n        self->metadata_length += metadata_length;\n    }\n    self->metadata_offset[self->num_rows + num_rows] = self->metadata_length;\n\n    /* Derived state column */\n    ret = check_offsets(num_rows, derived_state_offset, 0, false);\n    if (ret != 0) {\n        goto out;\n    }\n    derived_state_length = derived_state_offset[num_rows];\n    ret = tsk_mutation_table_expand_derived_state(self, derived_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->derived_state + self->derived_state_length, derived_state,\n        derived_state_length * sizeof(char));\n    for (j = 0; j < num_rows; j++) {\n        self->derived_state_offset[self->num_rows + j]\n            = self->derived_state_length + derived_state_offset[j];\n    }\n    self->derived_state_length += derived_state_length;\n    self->derived_state_offset[self->num_rows + num_rows] = self->derived_state_length;\n\n    self->num_rows += num_rows;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_mutation_table_takeset_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    tsk_id_t *site, tsk_id_t *node, tsk_id_t *parent, double *time, char *derived_state,\n    tsk_size_t *derived_state_offset, char *metadata, tsk_size_t *metadata_offset)\n{\n    tsk_size_t j;\n    int ret = 0;\n\n    if (site == NULL || node == NULL || derived_state == NULL\n        || derived_state_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    /* We need to check all the inputs before we start freeing or taking memory */\n    ret = check_ragged_column(num_rows, derived_state, derived_state_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_mutation_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n    self->site = site;\n    self->node = node;\n\n    ret = takeset_optional_id_column(num_rows, parent, &self->parent);\n    if (ret != 0) {\n        goto out;\n    }\n    if (time == NULL) {\n        /* Time defaults to unknown time if not specified. */\n        self->time = tsk_malloc(num_rows * sizeof(*self->time));\n        if (self->time == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->time[j] = TSK_UNKNOWN_TIME;\n        }\n\n    } else {\n        self->time = time;\n    }\n\n    ret = takeset_ragged_column(num_rows, derived_state, derived_state_offset,\n        (void *) &self->derived_state, &self->derived_state_offset,\n        &self->derived_state_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_mutation_table_copy(\n    const tsk_mutation_table_t *self, tsk_mutation_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_mutation_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_mutation_table_set_columns(dest, self->num_rows, self->site, self->node,\n        self->parent, self->time, self->derived_state, self->derived_state_offset,\n        self->metadata, self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint\ntsk_mutation_table_set_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    const tsk_id_t *site, const tsk_id_t *node, const tsk_id_t *parent,\n    const double *time, const char *derived_state,\n    const tsk_size_t *derived_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    ret = tsk_mutation_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_append_columns(self, num_rows, site, node, parent, time,\n        derived_state, derived_state_offset, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nbool\ntsk_mutation_table_equals(const tsk_mutation_table_t *self,\n    const tsk_mutation_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && self->derived_state_length == other->derived_state_length\n          && tsk_memcmp(self->site, other->site, self->num_rows * sizeof(tsk_id_t)) == 0\n          && tsk_memcmp(self->node, other->node, self->num_rows * sizeof(tsk_id_t)) == 0\n          && tsk_memcmp(self->parent, other->parent, self->num_rows * sizeof(tsk_id_t))\n                 == 0\n          && tsk_memcmp(self->time, other->time, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->derived_state_offset, other->derived_state_offset,\n                 (self->num_rows + 1) * sizeof(tsk_size_t))\n                 == 0\n          && tsk_memcmp(self->derived_state, other->derived_state,\n                 self->derived_state_length * sizeof(char))\n                 == 0;\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_mutation_table_clear(tsk_mutation_table_t *self)\n{\n    return tsk_mutation_table_truncate(self, 0);\n}\n\nint\ntsk_mutation_table_truncate(tsk_mutation_table_t *mutations, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > mutations->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    mutations->num_rows = num_rows;\n    mutations->derived_state_length = mutations->derived_state_offset[num_rows];\n    mutations->metadata_length = mutations->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_mutation_table_extend(tsk_mutation_table_t *self, const tsk_mutation_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_mutation_t mutation;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_mutation_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_mutation_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &mutation);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_mutation_table_add_row(self, mutation.site, mutation.node,\n            mutation.parent, mutation.time, mutation.derived_state,\n            mutation.derived_state_length, mutation.metadata, mutation.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_mutation_table_print_state(const tsk_mutation_table_t *self, FILE *out)\n{\n    int ret;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"mutation_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"derived_state_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->derived_state_length,\n        (long long) self->max_derived_state_length,\n        (long long) self->max_derived_state_length_increment);\n    fprintf(out, \"metadata_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    ret = tsk_mutation_table_dump_text(self, out);\n    tsk_bug_assert(ret == 0);\n    tsk_bug_assert(self->derived_state_offset[0] == 0);\n    tsk_bug_assert(\n        self->derived_state_length == self->derived_state_offset[self->num_rows]);\n    tsk_bug_assert(self->metadata_offset[0] == 0);\n    tsk_bug_assert(self->metadata_length == self->metadata_offset[self->num_rows]);\n}\n\nstatic inline void\ntsk_mutation_table_get_row_unsafe(\n    const tsk_mutation_table_t *self, tsk_id_t index, tsk_mutation_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->site = self->site[index];\n    row->node = self->node[index];\n    row->parent = self->parent[index];\n    row->time = self->time[index];\n    row->derived_state_length\n        = self->derived_state_offset[index + 1] - self->derived_state_offset[index];\n    row->derived_state = self->derived_state + self->derived_state_offset[index];\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n    row->edge = TSK_NULL;\n}\n\nint\ntsk_mutation_table_get_row(\n    const tsk_mutation_table_t *self, tsk_id_t index, tsk_mutation_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_MUTATION_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_mutation_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_mutation_table_set_metadata_schema(tsk_mutation_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_mutation_table_dump_text(const tsk_mutation_table_t *self, FILE *out)\n{\n    int ret = TSK_ERR_IO;\n    int err;\n    tsk_size_t j, derived_state_len, metadata_len;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"id\\tsite\\tnode\\tparent\\ttime\\tderived_state\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        derived_state_len\n            = self->derived_state_offset[j + 1] - self->derived_state_offset[j];\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%lld\\t%lld\\t%lld\\t%lld\\t%f\\t%.*s\\t%.*s\\n\", (long long) j,\n            (long long) self->site[j], (long long) self->node[j],\n            (long long) self->parent[j], self->time[j], (int) derived_state_len,\n            self->derived_state + self->derived_state_offset[j], (int) metadata_len,\n            self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nint\ntsk_mutation_table_keep_rows(tsk_mutation_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *ret_id_map)\n{\n    int ret = 0;\n    const tsk_size_t current_num_rows = self->num_rows;\n    tsk_size_t j, remaining_rows;\n    tsk_id_t pj;\n    tsk_id_t *id_map = ret_id_map;\n    tsk_id_t *restrict parent = self->parent;\n\n    if (ret_id_map == NULL) {\n        id_map = tsk_malloc(current_num_rows * sizeof(*id_map));\n        if (id_map == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    keep_mask_to_id_map(current_num_rows, keep, id_map);\n\n    /* Note: we could add some options to avoid these checks if we wanted.\n     * MAP_DELETED_TO_NULL is an obvious one, and I guess it might be\n     * helpful to also provide NO_REMAP to prevent reference remapping\n     * entirely. */\n    for (j = 0; j < current_num_rows; j++) {\n        if (keep[j]) {\n            pj = parent[j];\n            if (pj != TSK_NULL) {\n                if (pj < 0 || pj >= (tsk_id_t) current_num_rows) {\n                    ret = tsk_trace_error(TSK_ERR_MUTATION_OUT_OF_BOUNDS);\n                    goto out;\n                }\n                if (id_map[pj] == TSK_NULL) {\n                    ret = tsk_trace_error(TSK_ERR_KEEP_ROWS_MAP_TO_DELETED);\n                    goto out;\n                }\n            }\n        }\n    }\n\n    remaining_rows = subset_id_column(self->site, current_num_rows, keep);\n    subset_id_column(self->node, current_num_rows, keep);\n    subset_remap_id_column(parent, current_num_rows, keep, id_map);\n    subset_double_column(self->time, current_num_rows, keep);\n    self->derived_state_length = subset_ragged_char_column(\n        self->derived_state, self->derived_state_offset, current_num_rows, keep);\n    if (self->metadata_length > 0) {\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, current_num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\nout:\n    if (ret_id_map == NULL) {\n        tsk_safe_free(id_map);\n    }\n    return ret;\n}\n\nstatic int\ntsk_mutation_table_dump(\n    const tsk_mutation_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t cols[] = {\n        { \"mutations/site\", (void *) self->site, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"mutations/node\", (void *) self->node, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"mutations/parent\", (void *) self->parent, self->num_rows,\n            TSK_ID_STORAGE_TYPE },\n        { \"mutations/time\", (void *) self->time, self->num_rows, KAS_FLOAT64 },\n        { \"mutations/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"mutations/derived_state\", (void *) self->derived_state,\n            self->derived_state_length, KAS_UINT8, self->derived_state_offset,\n            self->num_rows },\n        { \"mutations/metadata\", (void *) self->metadata, self->metadata_length,\n            KAS_UINT8, self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, cols, ragged_cols, options);\n}\n\nstatic int\ntsk_mutation_table_load(tsk_mutation_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    tsk_id_t *node = NULL;\n    tsk_id_t *site = NULL;\n    tsk_id_t *parent = NULL;\n    double *time = NULL;\n    char *derived_state = NULL;\n    tsk_size_t *derived_state_offset = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    char *metadata_schema = NULL;\n    tsk_size_t num_rows, derived_state_length, metadata_length, metadata_schema_length;\n\n    read_table_col_t cols[] = {\n        { \"mutations/site\", (void **) &site, TSK_ID_STORAGE_TYPE, 0 },\n        { \"mutations/node\", (void **) &node, TSK_ID_STORAGE_TYPE, 0 },\n        { \"mutations/parent\", (void **) &parent, TSK_ID_STORAGE_TYPE, 0 },\n        { \"mutations/time\", (void **) &time, KAS_FLOAT64, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"mutations/derived_state\", (void **) &derived_state, &derived_state_length,\n            KAS_UINT8, &derived_state_offset, 0 },\n        { \"mutations/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, 0 },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"mutations/metadata_schema\", (void **) &metadata_schema,\n            &metadata_schema_length, KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_mutation_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_mutation_table_takeset_columns(self, num_rows, site, node, parent, time,\n        derived_state, derived_state_offset, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    site = NULL;\n    node = NULL;\n    parent = NULL;\n    time = NULL;\n    derived_state = NULL;\n    derived_state_offset = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\n\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * migration table\n *************************/\n\nstatic void\ntsk_migration_table_free_columns(tsk_migration_table_t *self)\n{\n    tsk_safe_free(self->left);\n    tsk_safe_free(self->right);\n    tsk_safe_free(self->node);\n    tsk_safe_free(self->source);\n    tsk_safe_free(self->dest);\n    tsk_safe_free(self->time);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_migration_table_free(tsk_migration_table_t *self)\n{\n    tsk_migration_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_migration_table_expand_main_columns(\n    tsk_migration_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column((void **) &self->left, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->right, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->node, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->source, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->dest, new_max_rows, sizeof(tsk_id_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column((void **) &self->time, new_max_rows, sizeof(double));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_migration_table_expand_metadata(\n    tsk_migration_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_migration_table_set_max_rows_increment(\n    tsk_migration_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_migration_table_set_max_metadata_length_increment(\n    tsk_migration_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_migration_table_init(tsk_migration_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_migration_table_t));\n\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_migration_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_migration_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\nint\ntsk_migration_table_append_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *node,\n    const tsk_id_t *source, const tsk_id_t *dest, const double *time,\n    const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n    tsk_size_t j, metadata_length;\n\n    if (left == NULL || right == NULL || node == NULL || source == NULL || dest == NULL\n        || time == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if ((metadata == NULL) != (metadata_offset == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    ret = tsk_migration_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->left + self->num_rows, left, num_rows * sizeof(double));\n    tsk_memcpy(self->right + self->num_rows, right, num_rows * sizeof(double));\n    tsk_memcpy(self->node + self->num_rows, node, num_rows * sizeof(tsk_id_t));\n    tsk_memcpy(self->source + self->num_rows, source, num_rows * sizeof(tsk_id_t));\n    tsk_memcpy(self->dest + self->num_rows, dest, num_rows * sizeof(tsk_id_t));\n    tsk_memcpy(self->time + self->num_rows, time, num_rows * sizeof(double));\n    if (metadata == NULL) {\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j + 1] = self->metadata_length;\n        }\n    } else {\n        ret = check_offsets(num_rows, metadata_offset, 0, false);\n        if (ret != 0) {\n            goto out;\n        }\n        for (j = 0; j < num_rows; j++) {\n            self->metadata_offset[self->num_rows + j]\n                = (tsk_size_t) self->metadata_length + metadata_offset[j];\n        }\n        metadata_length = metadata_offset[num_rows];\n        ret = tsk_migration_table_expand_metadata(self, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        tsk_memcpy(self->metadata + self->metadata_length, metadata,\n            metadata_length * sizeof(char));\n        self->metadata_length += metadata_length;\n    }\n\n    self->num_rows += num_rows;\n    self->metadata_offset[self->num_rows] = self->metadata_length;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_migration_table_takeset_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    double *left, double *right, tsk_id_t *node, tsk_id_t *source, tsk_id_t *dest,\n    double *time, char *metadata, tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    if (left == NULL || right == NULL || node == NULL || source == NULL || dest == NULL\n        || time == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_migration_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n    self->left = left;\n    self->right = right;\n    self->node = node;\n    self->source = source;\n    self->dest = dest;\n    self->time = time;\n\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_migration_table_copy(\n    const tsk_migration_table_t *self, tsk_migration_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_migration_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_migration_table_set_columns(dest, self->num_rows, self->left, self->right,\n        self->node, self->source, self->dest, self->time, self->metadata,\n        self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint\ntsk_migration_table_set_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *node,\n    const tsk_id_t *source, const tsk_id_t *dest, const double *time,\n    const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n\n    ret = tsk_migration_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_append_columns(self, num_rows, left, right, node, source,\n        dest, time, metadata, metadata_offset);\nout:\n    return ret;\n}\n\ntsk_id_t\ntsk_migration_table_add_row(tsk_migration_table_t *self, double left, double right,\n    tsk_id_t node, tsk_id_t source, tsk_id_t dest, double time, const char *metadata,\n    tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    ret = tsk_migration_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    tsk_bug_assert(self->metadata_length + metadata_length <= self->max_metadata_length);\n    tsk_memmove(self->metadata + self->metadata_length, metadata, metadata_length);\n    self->left[self->num_rows] = left;\n    self->right[self->num_rows] = right;\n    self->node[self->num_rows] = node;\n    self->source[self->num_rows] = source;\n    self->dest[self->num_rows] = dest;\n    self->time[self->num_rows] = time;\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length + metadata_length;\n    self->metadata_length += metadata_length;\n\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\nout:\n    return ret;\n}\n\nstatic int\ntsk_migration_table_update_row_rewrite(tsk_migration_table_t *self, tsk_id_t index,\n    double left, double right, tsk_id_t node, tsk_id_t source, tsk_id_t dest,\n    double time, const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_migration_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_migration_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_migration_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_migration_table_add_row(\n        self, left, right, node, source, dest, time, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_migration_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_migration_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_migration_table_update_row(tsk_migration_table_t *self, tsk_id_t index, double left,\n    double right, tsk_id_t node, tsk_id_t source, tsk_id_t dest, double time,\n    const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_migration_t current_row;\n\n    ret = tsk_migration_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length) {\n        self->left[index] = left;\n        self->right[index] = right;\n        self->node[index] = node;\n        self->source[index] = source;\n        self->dest[index] = dest;\n        self->time[index] = time;\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_migration_table_update_row_rewrite(self, index, left, right, node,\n            source, dest, time, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_migration_table_clear(tsk_migration_table_t *self)\n{\n    return tsk_migration_table_truncate(self, 0);\n}\n\nint\ntsk_migration_table_truncate(tsk_migration_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->metadata_length = self->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_migration_table_extend(tsk_migration_table_t *self,\n    const tsk_migration_table_t *other, tsk_size_t num_rows, const tsk_id_t *row_indexes,\n    tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_migration_t migration;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_migration_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_migration_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &migration);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_migration_table_add_row(self, migration.left, migration.right,\n            migration.node, migration.source, migration.dest, migration.time,\n            migration.metadata, migration.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_migration_table_print_state(const tsk_migration_table_t *self, FILE *out)\n{\n    int ret;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"migration_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"metadata_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    ret = tsk_migration_table_dump_text(self, out);\n    tsk_bug_assert(ret == 0);\n}\n\nstatic inline void\ntsk_migration_table_get_row_unsafe(\n    const tsk_migration_table_t *self, tsk_id_t index, tsk_migration_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->left = self->left[index];\n    row->right = self->right[index];\n    row->node = self->node[index];\n    row->source = self->source[index];\n    row->dest = self->dest[index];\n    row->time = self->time[index];\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n}\n\nint\ntsk_migration_table_get_row(\n    const tsk_migration_table_t *self, tsk_id_t index, tsk_migration_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_MIGRATION_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_migration_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_migration_table_set_metadata_schema(tsk_migration_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_migration_table_dump_text(const tsk_migration_table_t *self, FILE *out)\n{\n    tsk_size_t j;\n    int ret = TSK_ERR_IO;\n    tsk_size_t metadata_len;\n    int err;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"left\\tright\\tnode\\tsource\\tdest\\ttime\\tmetadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%.3f\\t%.3f\\t%lld\\t%lld\\t%lld\\t%f\\t%.*s\\n\", self->left[j],\n            self->right[j], (long long) self->node[j], (long long) self->source[j],\n            (long long) self->dest[j], self->time[j], (int) metadata_len,\n            self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_migration_table_equals(const tsk_migration_table_t *self,\n    const tsk_migration_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && tsk_memcmp(self->left, other->left, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->right, other->right, self->num_rows * sizeof(double)) == 0\n          && tsk_memcmp(self->node, other->node, self->num_rows * sizeof(tsk_id_t)) == 0\n          && tsk_memcmp(self->source, other->source, self->num_rows * sizeof(tsk_id_t))\n                 == 0\n          && tsk_memcmp(self->dest, other->dest, self->num_rows * sizeof(tsk_id_t)) == 0\n          && tsk_memcmp(self->time, other->time, self->num_rows * sizeof(double)) == 0;\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_migration_table_keep_rows(tsk_migration_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n    tsk_size_t remaining_rows;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n\n    remaining_rows = subset_double_column(self->left, self->num_rows, keep);\n    subset_double_column(self->right, self->num_rows, keep);\n    subset_id_column(self->node, self->num_rows, keep);\n    subset_id_column(self->source, self->num_rows, keep);\n    subset_id_column(self->dest, self->num_rows, keep);\n    subset_double_column(self->time, self->num_rows, keep);\n    if (self->metadata_length > 0) {\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, self->num_rows, keep);\n    }\n    self->num_rows = remaining_rows;\n    return ret;\n}\n\nstatic int\ntsk_migration_table_dump(\n    const tsk_migration_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t cols[] = {\n        { \"migrations/left\", (void *) self->left, self->num_rows, KAS_FLOAT64 },\n        { \"migrations/right\", (void *) self->right, self->num_rows, KAS_FLOAT64 },\n        { \"migrations/node\", (void *) self->node, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"migrations/source\", (void *) self->source, self->num_rows,\n            TSK_ID_STORAGE_TYPE },\n        { \"migrations/dest\", (void *) self->dest, self->num_rows, TSK_ID_STORAGE_TYPE },\n        { \"migrations/time\", (void *) self->time, self->num_rows, KAS_FLOAT64 },\n        { \"migrations/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"migrations/metadata\", (void *) self->metadata, self->metadata_length,\n            KAS_UINT8, self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, cols, ragged_cols, options);\n}\n\nstatic int\ntsk_migration_table_load(tsk_migration_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    tsk_id_t *source = NULL;\n    tsk_id_t *dest = NULL;\n    tsk_id_t *node = NULL;\n    double *left = NULL;\n    double *right = NULL;\n    double *time = NULL;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    char *metadata_schema = NULL;\n    tsk_size_t num_rows, metadata_length, metadata_schema_length;\n\n    read_table_col_t cols[] = {\n        { \"migrations/left\", (void **) &left, KAS_FLOAT64, 0 },\n        { \"migrations/right\", (void **) &right, KAS_FLOAT64, 0 },\n        { \"migrations/node\", (void **) &node, TSK_ID_STORAGE_TYPE, 0 },\n        { \"migrations/source\", (void **) &source, TSK_ID_STORAGE_TYPE, 0 },\n        { \"migrations/dest\", (void **) &dest, TSK_ID_STORAGE_TYPE, 0 },\n        { \"migrations/time\", (void **) &time, KAS_FLOAT64, 0 },\n        { .name = NULL },\n    };\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"migrations/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"migrations/metadata_schema\", (void **) &metadata_schema,\n            &metadata_schema_length, KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, cols, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_migration_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_migration_table_takeset_columns(self, num_rows, left, right, node, source,\n        dest, time, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    left = NULL;\n    right = NULL;\n    node = NULL;\n    source = NULL;\n    dest = NULL;\n    time = NULL;\n    metadata = NULL;\n    metadata_offset = NULL;\n\nout:\n    free_read_table_mem(cols, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * population table\n *************************/\n\nstatic void\ntsk_population_table_free_columns(tsk_population_table_t *self)\n{\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_offset);\n}\n\nint\ntsk_population_table_free(tsk_population_table_t *self)\n{\n    tsk_population_table_free_columns(self);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nstatic int\ntsk_population_table_expand_main_columns(\n    tsk_population_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column(\n            (void **) &self->metadata_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_population_table_expand_metadata(\n    tsk_population_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->metadata_length, additional_length,\n        self->max_metadata_length_increment, &self->max_metadata_length,\n        (void **) &self->metadata, sizeof(*self->metadata));\n}\n\nint\ntsk_population_table_set_max_rows_increment(\n    tsk_population_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_population_table_set_max_metadata_length_increment(\n    tsk_population_table_t *self, tsk_size_t max_metadata_length_increment)\n{\n    self->max_metadata_length_increment = max_metadata_length_increment;\n    return 0;\n}\n\nint\ntsk_population_table_init(tsk_population_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_population_table_t));\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_metadata_length_increment = 1;\n    ret = tsk_population_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_expand_metadata(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->metadata_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_metadata_length_increment = 0;\n    tsk_population_table_set_metadata_schema(self, NULL, 0);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_population_table_copy(const tsk_population_table_t *self,\n    tsk_population_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_population_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_population_table_set_columns(\n        dest, self->num_rows, self->metadata, self->metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\nout:\n    return ret;\n}\n\nint\ntsk_population_table_set_columns(tsk_population_table_t *self, tsk_size_t num_rows,\n    const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n\n    ret = tsk_population_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_append_columns(self, num_rows, metadata, metadata_offset);\nout:\n    return ret;\n}\n\nint\ntsk_population_table_append_columns(tsk_population_table_t *self, tsk_size_t num_rows,\n    const char *metadata, const tsk_size_t *metadata_offset)\n{\n    int ret;\n    tsk_size_t j, metadata_length;\n\n    if (metadata == NULL || metadata_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = tsk_population_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = check_offsets(num_rows, metadata_offset, 0, false);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        self->metadata_offset[self->num_rows + j]\n            = self->metadata_length + metadata_offset[j];\n    }\n    metadata_length = metadata_offset[num_rows];\n    ret = tsk_population_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->metadata + self->metadata_length, metadata,\n        metadata_length * sizeof(char));\n    self->metadata_length += metadata_length;\n\n    self->num_rows += num_rows;\n    self->metadata_offset[self->num_rows] = self->metadata_length;\nout:\n    return ret;\n}\n\nint\ntsk_population_table_takeset_columns(tsk_population_table_t *self, tsk_size_t num_rows,\n    char *metadata, tsk_size_t *metadata_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    if (metadata == NULL || metadata_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_population_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n\n    ret = takeset_ragged_column(num_rows, metadata, metadata_offset,\n        (void *) &self->metadata, &self->metadata_offset, &self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_population_table_add_row_internal(\n    tsk_population_table_t *self, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    tsk_bug_assert(self->metadata_length + metadata_length <= self->max_metadata_length);\n    tsk_memmove(self->metadata + self->metadata_length, metadata, metadata_length);\n    self->metadata_offset[self->num_rows + 1] = self->metadata_length + metadata_length;\n    self->metadata_length += metadata_length;\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\n    return ret;\n}\n\ntsk_id_t\ntsk_population_table_add_row(\n    tsk_population_table_t *self, const char *metadata, tsk_size_t metadata_length)\n{\n    tsk_id_t ret = 0;\n\n    ret = tsk_population_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_expand_metadata(self, metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_add_row_internal(self, metadata, metadata_length);\nout:\n    return ret;\n}\n\nstatic int\ntsk_population_table_update_row_rewrite(tsk_population_table_t *self, tsk_id_t index,\n    const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_population_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_population_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_population_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_population_table_add_row(self, metadata, metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_population_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_population_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_population_table_update_row(tsk_population_table_t *self, tsk_id_t index,\n    const char *metadata, tsk_size_t metadata_length)\n{\n    int ret = 0;\n    tsk_population_t current_row;\n\n    ret = tsk_population_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.metadata_length == metadata_length) {\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->metadata[self->metadata_offset[index]], metadata,\n            metadata_length * sizeof(*metadata));\n    } else {\n        ret = tsk_population_table_update_row_rewrite(\n            self, index, metadata, metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_population_table_clear(tsk_population_table_t *self)\n{\n    return tsk_population_table_truncate(self, 0);\n}\n\nint\ntsk_population_table_truncate(tsk_population_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->metadata_length = self->metadata_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_population_table_extend(tsk_population_table_t *self,\n    const tsk_population_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_population_t population;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_population_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_population_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &population);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_population_table_add_row(\n            self, population.metadata, population.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_population_table_print_state(const tsk_population_table_t *self, FILE *out)\n{\n    tsk_size_t j, k;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"population_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows          = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"metadata_length  = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->metadata_length, (long long) self->max_metadata_length,\n        (long long) self->max_metadata_length_increment);\n    fprintf(out, TABLE_SEP);\n    write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    fprintf(out, \"index\\tmetadata_offset\\tmetadata\\n\");\n    for (j = 0; j < self->num_rows; j++) {\n        fprintf(\n            out, \"%lld\\t%lld\\t\", (long long) j, (long long) self->metadata_offset[j]);\n        for (k = self->metadata_offset[j]; k < self->metadata_offset[j + 1]; k++) {\n            fprintf(out, \"%c\", self->metadata[k]);\n        }\n        fprintf(out, \"\\n\");\n    }\n    tsk_bug_assert(self->metadata_offset[0] == 0);\n    tsk_bug_assert(self->metadata_offset[self->num_rows] == self->metadata_length);\n}\n\nstatic inline void\ntsk_population_table_get_row_unsafe(\n    const tsk_population_table_t *self, tsk_id_t index, tsk_population_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->metadata_length\n        = self->metadata_offset[index + 1] - self->metadata_offset[index];\n    row->metadata = self->metadata + self->metadata_offset[index];\n}\n\nint\ntsk_population_table_get_row(\n    const tsk_population_table_t *self, tsk_id_t index, tsk_population_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_POPULATION_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_population_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_population_table_set_metadata_schema(tsk_population_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_population_table_dump_text(const tsk_population_table_t *self, FILE *out)\n{\n    int ret = TSK_ERR_IO;\n    int err;\n    tsk_size_t j;\n    tsk_size_t metadata_len;\n\n    err = write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    if (err < 0) {\n        goto out;\n    }\n    err = fprintf(out, \"metadata\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        metadata_len = self->metadata_offset[j + 1] - self->metadata_offset[j];\n        err = fprintf(out, \"%.*s\\n\", (int) metadata_len,\n            self->metadata + self->metadata_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_population_table_equals(const tsk_population_table_t *self,\n    const tsk_population_table_t *other, tsk_flags_t options)\n{\n    /* Since we only have the metadata column in the table currently, equality\n     * reduces to comparing the number of rows if we disable metadata comparison.\n     */\n    bool ret = self->num_rows == other->num_rows;\n    if (!(options & TSK_CMP_IGNORE_METADATA)) {\n        ret = ret && self->metadata_length == other->metadata_length\n              && self->metadata_schema_length == other->metadata_schema_length\n              && tsk_memcmp(self->metadata_offset, other->metadata_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->metadata, other->metadata,\n                     self->metadata_length * sizeof(char))\n                     == 0\n              && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                     self->metadata_schema_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_population_table_keep_rows(tsk_population_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n\n    if (self->metadata_length > 0) {\n        self->metadata_length = subset_ragged_char_column(\n            self->metadata, self->metadata_offset, self->num_rows, keep);\n    }\n    self->num_rows = count_true(self->num_rows, keep);\n    return ret;\n}\n\nstatic int\ntsk_population_table_dump(\n    const tsk_population_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    const write_table_col_t cols[] = {\n        { \"populations/metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    const write_table_ragged_col_t ragged_cols[] = {\n        { \"populations/metadata\", (void *) self->metadata, self->metadata_length,\n            KAS_UINT8, self->metadata_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table(store, cols, ragged_cols, options);\n}\n\nstatic int\ntsk_population_table_load(tsk_population_table_t *self, kastore_t *store)\n{\n    int ret = 0;\n    char *metadata = NULL;\n    tsk_size_t *metadata_offset = NULL;\n    char *metadata_schema = NULL;\n    tsk_size_t num_rows, metadata_length, metadata_schema_length;\n\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"populations/metadata\", (void **) &metadata, &metadata_length, KAS_UINT8,\n            &metadata_offset, 0 },\n        { .name = NULL },\n    };\n    read_table_property_t properties[] = {\n        { \"populations/metadata_schema\", (void **) &metadata_schema,\n            &metadata_schema_length, KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, NULL, ragged_cols, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_population_table_set_metadata_schema(\n            self, metadata_schema, metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_population_table_takeset_columns(\n        self, num_rows, metadata, metadata_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    metadata = NULL;\n    metadata_offset = NULL;\n\nout:\n    free_read_table_mem(NULL, ragged_cols, properties);\n    return ret;\n}\n\n/*************************\n * provenance table\n *************************/\n\nstatic void\ntsk_provenance_table_free_columns(tsk_provenance_table_t *self)\n{\n    tsk_safe_free(self->timestamp);\n    tsk_safe_free(self->timestamp_offset);\n    tsk_safe_free(self->record);\n    tsk_safe_free(self->record_offset);\n}\n\nint\ntsk_provenance_table_free(tsk_provenance_table_t *self)\n{\n    tsk_provenance_table_free_columns(self);\n    return 0;\n}\n\nstatic int\ntsk_provenance_table_expand_main_columns(\n    tsk_provenance_table_t *self, tsk_size_t additional_rows)\n{\n    int ret = 0;\n    tsk_size_t new_max_rows;\n\n    ret = calculate_max_rows(self->num_rows, self->max_rows, self->max_rows_increment,\n        additional_rows, &new_max_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    if ((self->num_rows + additional_rows) > self->max_rows) {\n        ret = expand_column(\n            (void **) &self->timestamp_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = expand_column(\n            (void **) &self->record_offset, new_max_rows + 1, sizeof(tsk_size_t));\n        if (ret != 0) {\n            goto out;\n        }\n        self->max_rows = new_max_rows;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_provenance_table_expand_timestamp(\n    tsk_provenance_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->timestamp_length, additional_length,\n        self->max_timestamp_length_increment, &self->max_timestamp_length,\n        (void **) &self->timestamp, sizeof(*self->timestamp));\n}\n\nstatic int\ntsk_provenance_table_expand_record(\n    tsk_provenance_table_t *self, tsk_size_t additional_length)\n{\n    return expand_ragged_column(self->record_length, additional_length,\n        self->max_record_length_increment, &self->max_record_length,\n        (void **) &self->record, sizeof(*self->record));\n}\n\nint\ntsk_provenance_table_set_max_rows_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_rows_increment)\n{\n    self->max_rows_increment = max_rows_increment;\n    return 0;\n}\n\nint\ntsk_provenance_table_set_max_timestamp_length_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_timestamp_length_increment)\n{\n    self->max_timestamp_length_increment = max_timestamp_length_increment;\n    return 0;\n}\n\nint\ntsk_provenance_table_set_max_record_length_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_record_length_increment)\n{\n    self->max_record_length_increment = max_record_length_increment;\n    return 0;\n}\n\nint\ntsk_provenance_table_init(tsk_provenance_table_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(tsk_provenance_table_t));\n    /* Allocate space for one row initially, ensuring we always have valid pointers\n     * even if the table is empty */\n    self->max_rows_increment = 1;\n    self->max_timestamp_length_increment = 1;\n    self->max_record_length_increment = 1;\n    ret = tsk_provenance_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_expand_timestamp(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->timestamp_offset[0] = 0;\n    ret = tsk_provenance_table_expand_record(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    self->record_offset[0] = 0;\n    self->max_rows_increment = 0;\n    self->max_timestamp_length_increment = 0;\n    self->max_record_length_increment = 0;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_provenance_table_copy(const tsk_provenance_table_t *self,\n    tsk_provenance_table_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_provenance_table_init(dest, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_provenance_table_set_columns(dest, self->num_rows, self->timestamp,\n        self->timestamp_offset, self->record, self->record_offset);\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_set_columns(tsk_provenance_table_t *self, tsk_size_t num_rows,\n    const char *timestamp, const tsk_size_t *timestamp_offset, const char *record,\n    const tsk_size_t *record_offset)\n{\n    int ret;\n\n    ret = tsk_provenance_table_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_append_columns(\n        self, num_rows, timestamp, timestamp_offset, record, record_offset);\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_append_columns(tsk_provenance_table_t *self, tsk_size_t num_rows,\n    const char *timestamp, const tsk_size_t *timestamp_offset, const char *record,\n    const tsk_size_t *record_offset)\n{\n    int ret;\n    tsk_size_t j, timestamp_length, record_length;\n\n    if (timestamp == NULL || timestamp_offset == NULL || record == NULL\n        || record_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = tsk_provenance_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = check_offsets(num_rows, timestamp_offset, 0, false);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        self->timestamp_offset[self->num_rows + j]\n            = self->timestamp_length + timestamp_offset[j];\n    }\n    timestamp_length = timestamp_offset[num_rows];\n    ret = tsk_provenance_table_expand_timestamp(self, timestamp_length);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->timestamp + self->timestamp_length, timestamp,\n        timestamp_length * sizeof(char));\n    self->timestamp_length += timestamp_length;\n\n    ret = check_offsets(num_rows, record_offset, 0, false);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        self->record_offset[self->num_rows + j] = self->record_length + record_offset[j];\n    }\n    record_length = record_offset[num_rows];\n    ret = tsk_provenance_table_expand_record(self, record_length);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_memcpy(self->record + self->record_length, record, record_length * sizeof(char));\n    self->record_length += record_length;\n\n    self->num_rows += num_rows;\n    self->timestamp_offset[self->num_rows] = self->timestamp_length;\n    self->record_offset[self->num_rows] = self->record_length;\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_takeset_columns(tsk_provenance_table_t *self, tsk_size_t num_rows,\n    char *timestamp, tsk_size_t *timestamp_offset, char *record,\n    tsk_size_t *record_offset)\n{\n    int ret = 0;\n\n    /* We need to check all the inputs before we start freeing or taking memory */\n    if (timestamp == NULL || timestamp_offset == NULL || record == NULL\n        || record_offset == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, timestamp, timestamp_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_ragged_column(num_rows, record, record_offset);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_provenance_table_free_columns(self);\n    self->num_rows = num_rows;\n    self->max_rows = num_rows;\n\n    ret = takeset_ragged_column(num_rows, timestamp, timestamp_offset,\n        (void *) &self->timestamp, &self->timestamp_offset, &self->timestamp_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = takeset_ragged_column(num_rows, record, record_offset, (void *) &self->record,\n        &self->record_offset, &self->record_length);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_provenance_table_add_row_internal(tsk_provenance_table_t *self,\n    const char *timestamp, tsk_size_t timestamp_length, const char *record,\n    tsk_size_t record_length)\n{\n    tsk_id_t ret = 0;\n\n    tsk_bug_assert(self->num_rows < self->max_rows);\n    tsk_bug_assert(\n        self->timestamp_length + timestamp_length <= self->max_timestamp_length);\n    tsk_memmove(self->timestamp + self->timestamp_length, timestamp, timestamp_length);\n    self->timestamp_offset[self->num_rows + 1]\n        = self->timestamp_length + timestamp_length;\n    self->timestamp_length += timestamp_length;\n    tsk_bug_assert(self->record_length + record_length <= self->max_record_length);\n    tsk_memmove(self->record + self->record_length, record, record_length);\n    self->record_offset[self->num_rows + 1] = self->record_length + record_length;\n    self->record_length += record_length;\n    ret = (tsk_id_t) self->num_rows;\n    self->num_rows++;\n    return ret;\n}\n\ntsk_id_t\ntsk_provenance_table_add_row(tsk_provenance_table_t *self, const char *timestamp,\n    tsk_size_t timestamp_length, const char *record, tsk_size_t record_length)\n{\n    tsk_id_t ret = 0;\n\n    ret = tsk_provenance_table_expand_main_columns(self, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_expand_timestamp(self, timestamp_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_expand_record(self, record_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_add_row_internal(\n        self, timestamp, timestamp_length, record, record_length);\nout:\n    return ret;\n}\n\nstatic int\ntsk_provenance_table_update_row_rewrite(tsk_provenance_table_t *self, tsk_id_t index,\n    const char *timestamp, tsk_size_t timestamp_length, const char *record,\n    tsk_size_t record_length)\n{\n    int ret = 0;\n    tsk_id_t j, ret_id;\n    tsk_provenance_table_t copy;\n    tsk_size_t num_rows;\n    tsk_id_t *rows = NULL;\n\n    ret = tsk_provenance_table_copy(self, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    rows = tsk_malloc(self->num_rows * sizeof(*rows));\n    if (rows == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_provenance_table_truncate(self, (tsk_size_t) index);\n    tsk_bug_assert(ret == 0);\n    ret_id = tsk_provenance_table_add_row(\n        self, timestamp, timestamp_length, record, record_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    num_rows = 0;\n    for (j = index + 1; j < (tsk_id_t) copy.num_rows; j++) {\n        rows[num_rows] = j;\n        num_rows++;\n    }\n    ret = tsk_provenance_table_extend(self, &copy, num_rows, rows, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_provenance_table_free(&copy);\n    tsk_safe_free(rows);\n    return ret;\n}\n\nint\ntsk_provenance_table_update_row(tsk_provenance_table_t *self, tsk_id_t index,\n    const char *timestamp, tsk_size_t timestamp_length, const char *record,\n    tsk_size_t record_length)\n{\n    int ret = 0;\n    tsk_provenance_t current_row;\n\n    ret = tsk_provenance_table_get_row(self, index, &current_row);\n    if (ret != 0) {\n        goto out;\n    }\n    if (current_row.timestamp_length == timestamp_length\n        && current_row.record_length == record_length) {\n        /* Note: important to use tsk_memmove here as we may be provided pointers\n         * to the column memory as input via get_row */\n        tsk_memmove(&self->timestamp[self->timestamp_offset[index]], timestamp,\n            timestamp_length * sizeof(*timestamp));\n        tsk_memmove(&self->record[self->record_offset[index]], record,\n            record_length * sizeof(*record));\n    } else {\n        ret = tsk_provenance_table_update_row_rewrite(\n            self, index, timestamp, timestamp_length, record, record_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_clear(tsk_provenance_table_t *self)\n{\n    return tsk_provenance_table_truncate(self, 0);\n}\n\nint\ntsk_provenance_table_truncate(tsk_provenance_table_t *self, tsk_size_t num_rows)\n{\n    int ret = 0;\n\n    if (num_rows > self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TABLE_POSITION);\n        goto out;\n    }\n    self->num_rows = num_rows;\n    self->timestamp_length = self->timestamp_offset[num_rows];\n    self->record_length = self->record_offset[num_rows];\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_extend(tsk_provenance_table_t *self,\n    const tsk_provenance_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_provenance_t provenance;\n\n    if (self == other) {\n        ret = tsk_trace_error(TSK_ERR_CANNOT_EXTEND_FROM_SELF);\n        goto out;\n    }\n\n    /* We know how much to expand the non-ragged columns, so do it ahead of time */\n    ret = tsk_provenance_table_expand_main_columns(self, num_rows);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_rows; j++) {\n        ret = tsk_provenance_table_get_row(\n            other, row_indexes == NULL ? (tsk_id_t) j : row_indexes[j], &provenance);\n        if (ret != 0) {\n            goto out;\n        }\n        ret_id = tsk_provenance_table_add_row(self, provenance.timestamp,\n            provenance.timestamp_length, provenance.record, provenance.record_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nvoid\ntsk_provenance_table_print_state(const tsk_provenance_table_t *self, FILE *out)\n{\n    tsk_size_t j, k;\n\n    fprintf(out, \"\\n\" TABLE_SEP);\n    fprintf(out, \"provenance_table: %p:\\n\", (const void *) self);\n    fprintf(out, \"num_rows          = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->num_rows, (long long) self->max_rows,\n        (long long) self->max_rows_increment);\n    fprintf(out, \"timestamp_length  = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->timestamp_length, (long long) self->max_timestamp_length,\n        (long long) self->max_timestamp_length_increment);\n    fprintf(out, \"record_length = %lld\\tmax= %lld\\tincrement = %lld)\\n\",\n        (long long) self->record_length, (long long) self->max_record_length,\n        (long long) self->max_record_length_increment);\n    fprintf(out, TABLE_SEP);\n    fprintf(out, \"index\\ttimestamp_offset\\ttimestamp\\trecord_offset\\tprovenance\\n\");\n    for (j = 0; j < self->num_rows; j++) {\n        fprintf(\n            out, \"%lld\\t%lld\\t\", (long long) j, (long long) self->timestamp_offset[j]);\n        for (k = self->timestamp_offset[j]; k < self->timestamp_offset[j + 1]; k++) {\n            fprintf(out, \"%c\", self->timestamp[k]);\n        }\n        fprintf(out, \"\\t%lld\\t\", (long long) self->record_offset[j]);\n        for (k = self->record_offset[j]; k < self->record_offset[j + 1]; k++) {\n            fprintf(out, \"%c\", self->record[k]);\n        }\n        fprintf(out, \"\\n\");\n    }\n    tsk_bug_assert(self->timestamp_offset[0] == 0);\n    tsk_bug_assert(self->timestamp_offset[self->num_rows] == self->timestamp_length);\n    tsk_bug_assert(self->record_offset[0] == 0);\n    tsk_bug_assert(self->record_offset[self->num_rows] == self->record_length);\n}\n\nstatic inline void\ntsk_provenance_table_get_row_unsafe(\n    const tsk_provenance_table_t *self, tsk_id_t index, tsk_provenance_t *row)\n{\n    row->id = (tsk_id_t) index;\n    row->timestamp_length\n        = self->timestamp_offset[index + 1] - self->timestamp_offset[index];\n    row->timestamp = self->timestamp + self->timestamp_offset[index];\n    row->record_length = self->record_offset[index + 1] - self->record_offset[index];\n    row->record = self->record + self->record_offset[index];\n}\n\nint\ntsk_provenance_table_get_row(\n    const tsk_provenance_table_t *self, tsk_id_t index, tsk_provenance_t *row)\n{\n    int ret = 0;\n\n    if (index < 0 || index >= (tsk_id_t) self->num_rows) {\n        ret = tsk_trace_error(TSK_ERR_PROVENANCE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    tsk_provenance_table_get_row_unsafe(self, index, row);\nout:\n    return ret;\n}\n\nint\ntsk_provenance_table_dump_text(const tsk_provenance_table_t *self, FILE *out)\n{\n    int ret = TSK_ERR_IO;\n    int err;\n    tsk_size_t j, timestamp_len, record_len;\n\n    err = fprintf(out, \"record\\ttimestamp\\n\");\n    if (err < 0) {\n        goto out;\n    }\n    for (j = 0; j < self->num_rows; j++) {\n        record_len = self->record_offset[j + 1] - self->record_offset[j];\n        timestamp_len = self->timestamp_offset[j + 1] - self->timestamp_offset[j];\n        err = fprintf(out, \"%.*s\\t%.*s\\n\", (int) record_len,\n            self->record + self->record_offset[j], (int) timestamp_len,\n            self->timestamp + self->timestamp_offset[j]);\n        if (err < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool\ntsk_provenance_table_equals(const tsk_provenance_table_t *self,\n    const tsk_provenance_table_t *other, tsk_flags_t options)\n{\n    bool ret\n        = self->num_rows == other->num_rows\n          && self->record_length == other->record_length\n          && tsk_memcmp(self->record_offset, other->record_offset,\n                 (self->num_rows + 1) * sizeof(tsk_size_t))\n                 == 0\n          && tsk_memcmp(self->record, other->record, self->record_length * sizeof(char))\n                 == 0;\n    if (!(options & TSK_CMP_IGNORE_TIMESTAMPS)) {\n        ret = ret && self->timestamp_length == other->timestamp_length\n              && tsk_memcmp(self->timestamp_offset, other->timestamp_offset,\n                     (self->num_rows + 1) * sizeof(tsk_size_t))\n                     == 0\n              && tsk_memcmp(self->timestamp, other->timestamp,\n                     self->timestamp_length * sizeof(char))\n                     == 0;\n    }\n    return ret;\n}\n\nint\ntsk_provenance_table_keep_rows(tsk_provenance_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t TSK_UNUSED(options), tsk_id_t *id_map)\n{\n    int ret = 0;\n\n    if (id_map != NULL) {\n        keep_mask_to_id_map(self->num_rows, keep, id_map);\n    }\n    self->timestamp_length = subset_ragged_char_column(\n        self->timestamp, self->timestamp_offset, self->num_rows, keep);\n    self->record_length = subset_ragged_char_column(\n        self->record, self->record_offset, self->num_rows, keep);\n    self->num_rows = count_true(self->num_rows, keep);\n\n    return ret;\n}\n\nstatic int\ntsk_provenance_table_dump(\n    const tsk_provenance_table_t *self, kastore_t *store, tsk_flags_t options)\n{\n    write_table_ragged_col_t ragged_cols[] = {\n        { \"provenances/timestamp\", (void *) self->timestamp, self->timestamp_length,\n            KAS_UINT8, self->timestamp_offset, self->num_rows },\n        { \"provenances/record\", (void *) self->record, self->record_length, KAS_UINT8,\n            self->record_offset, self->num_rows },\n        { .name = NULL },\n    };\n\n    return write_table_ragged_cols(store, ragged_cols, options);\n}\n\nstatic int\ntsk_provenance_table_load(tsk_provenance_table_t *self, kastore_t *store)\n{\n    int ret;\n    char *timestamp = NULL;\n    tsk_size_t *timestamp_offset = NULL;\n    char *record = NULL;\n    tsk_size_t *record_offset = NULL;\n    tsk_size_t num_rows, timestamp_length, record_length;\n\n    read_table_ragged_col_t ragged_cols[] = {\n        { \"provenances/timestamp\", (void **) &timestamp, &timestamp_length, KAS_UINT8,\n            &timestamp_offset, 0 },\n        { \"provenances/record\", (void **) &record, &record_length, KAS_UINT8,\n            &record_offset, 0 },\n        { .name = NULL },\n    };\n\n    ret = read_table(store, &num_rows, NULL, ragged_cols, NULL, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_takeset_columns(\n        self, num_rows, timestamp, timestamp_offset, record, record_offset);\n    if (ret != 0) {\n        goto out;\n    }\n    timestamp = NULL;\n    timestamp_offset = NULL;\n    record = NULL;\n    record_offset = NULL;\n\nout:\n    free_read_table_mem(NULL, ragged_cols, NULL);\n    return ret;\n}\n\n/*************************\n * sort_tables\n *************************/\n\ntypedef struct {\n    double left;\n    double right;\n    tsk_id_t parent;\n    tsk_id_t child;\n    double time;\n    /* It would be a little bit more convenient to store a pointer to the\n     * metadata here in the struct rather than an offset back into the\n     * original array. However, this would increase the size of the struct\n     * from 40 bytes to 48 and we will allocate very large numbers of these.\n     */\n    tsk_size_t metadata_offset;\n    tsk_size_t metadata_length;\n} edge_sort_t;\n\ntypedef struct {\n    tsk_mutation_t mut;\n    int num_descendants;\n    double node_time;\n} mutation_sort_t;\n\ntypedef struct {\n    tsk_individual_t ind;\n    tsk_id_t first_node;\n    tsk_size_t num_descendants;\n} individual_canonical_sort_t;\n\ntypedef struct {\n    double left;\n    double right;\n    tsk_id_t node;\n    tsk_id_t source;\n    tsk_id_t dest;\n    double time;\n    tsk_size_t metadata_offset;\n    tsk_size_t metadata_length;\n} migration_sort_t;\n\nstatic int\ncmp_site(const void *a, const void *b)\n{\n    const tsk_site_t *ia = (const tsk_site_t *) a;\n    const tsk_site_t *ib = (const tsk_site_t *) b;\n    /* Compare sites by position */\n    int ret = (ia->position > ib->position) - (ia->position < ib->position);\n    if (ret == 0) {\n        /* Within a particular position sort by ID.  This ensures that relative\n         * ordering of multiple sites at the same position is maintained; the\n         * redundant sites will get compacted down by clean_tables(), but in the\n         * meantime if the order of the redundant sites changes it will cause the\n         * sort order of mutations to be corrupted, as the mutations will follow\n         * their sites. */\n        ret = (ia->id > ib->id) - (ia->id < ib->id);\n    }\n    return ret;\n}\n\nstatic int\ncmp_mutation(const void *a, const void *b)\n{\n    const mutation_sort_t *ia = (const mutation_sort_t *) a;\n    const mutation_sort_t *ib = (const mutation_sort_t *) b;\n    /* Compare mutations by site */\n    int ret = (ia->mut.site > ib->mut.site) - (ia->mut.site < ib->mut.site);\n\n    /* Within a particular site sort by time if known */\n    if (ret == 0 && !tsk_is_unknown_time(ia->mut.time)\n        && !tsk_is_unknown_time(ib->mut.time)) {\n        ret = (ia->mut.time < ib->mut.time) - (ia->mut.time > ib->mut.time);\n    }\n    /* Or node times when mutation times are unknown or equal */\n    if (ret == 0) {\n        ret = (ia->node_time < ib->node_time) - (ia->node_time > ib->node_time);\n    }\n    /* If node times are equal, sort by number of descendants */\n    if (ret == 0) {\n        ret = (ia->num_descendants < ib->num_descendants)\n              - (ia->num_descendants > ib->num_descendants);\n    }\n    /* If number of descendants are equal, sort by node */\n    if (ret == 0) {\n        ret = (ia->mut.node > ib->mut.node) - (ia->mut.node < ib->mut.node);\n    }\n    /* Final tiebreaker: ID */\n    if (ret == 0) {\n        ret = (ia->mut.id > ib->mut.id) - (ia->mut.id < ib->mut.id);\n    }\n    return ret;\n}\n\nstatic int\ncmp_individual_canonical(const void *a, const void *b)\n{\n    const individual_canonical_sort_t *ia = (const individual_canonical_sort_t *) a;\n    const individual_canonical_sort_t *ib = (const individual_canonical_sort_t *) b;\n    int ret = (ia->num_descendants < ib->num_descendants)\n              - (ia->num_descendants > ib->num_descendants);\n    if (ret == 0) {\n        ret = (ia->first_node > ib->first_node) - (ia->first_node < ib->first_node);\n    }\n    if (ret == 0) {\n        ret = (ia->ind.id > ib->ind.id) - (ia->ind.id < ib->ind.id);\n    }\n    return ret;\n}\n\nstatic int\ncmp_edge(const void *a, const void *b)\n{\n    const edge_sort_t *ca = (const edge_sort_t *) a;\n    const edge_sort_t *cb = (const edge_sort_t *) b;\n\n    int ret = (ca->time > cb->time) - (ca->time < cb->time);\n    /* If time values are equal, sort by the parent node */\n    if (ret == 0) {\n        ret = (ca->parent > cb->parent) - (ca->parent < cb->parent);\n        /* If the parent nodes are equal, sort by the child ID. */\n        if (ret == 0) {\n            ret = (ca->child > cb->child) - (ca->child < cb->child);\n            /* If the child nodes are equal, sort by the left coordinate. */\n            if (ret == 0) {\n                ret = (ca->left > cb->left) - (ca->left < cb->left);\n            }\n        }\n    }\n    return ret;\n}\n\nstatic int\ncmp_migration(const void *a, const void *b)\n{\n    const migration_sort_t *ca = (const migration_sort_t *) a;\n    const migration_sort_t *cb = (const migration_sort_t *) b;\n\n    int ret = (ca->time > cb->time) - (ca->time < cb->time);\n    /* If time values are equal, sort by the source population */\n    if (ret == 0) {\n        ret = (ca->source > cb->source) - (ca->source < cb->source);\n        /* If the source populations are equal, sort by the dest */\n        if (ret == 0) {\n            ret = (ca->dest > cb->dest) - (ca->dest < cb->dest);\n            /* If the dest populations are equal, sort by the left coordinate. */\n            if (ret == 0) {\n                ret = (ca->left > cb->left) - (ca->left < cb->left);\n                /* If everything else is equal, compare by node */\n                if (ret == 0) {\n                    ret = (ca->node > cb->node) - (ca->node < cb->node);\n                }\n            }\n        }\n    }\n    return ret;\n}\n\nstatic int\ntsk_table_sorter_sort_edges(tsk_table_sorter_t *self, tsk_size_t start)\n{\n    int ret = 0;\n    const tsk_edge_table_t *edges = &self->tables->edges;\n    const double *restrict node_time = self->tables->nodes.time;\n    edge_sort_t *e;\n    tsk_size_t j, k, metadata_offset;\n    tsk_size_t n = edges->num_rows - start;\n    edge_sort_t *sorted_edges = tsk_malloc(n * sizeof(*sorted_edges));\n    char *old_metadata = tsk_malloc(edges->metadata_length);\n    bool has_metadata = tsk_edge_table_has_metadata(edges);\n\n    if (sorted_edges == NULL || old_metadata == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memcpy(old_metadata, edges->metadata, edges->metadata_length);\n    for (j = 0; j < n; j++) {\n        e = sorted_edges + j;\n        k = start + j;\n        e->left = edges->left[k];\n        e->right = edges->right[k];\n        e->parent = edges->parent[k];\n        e->child = edges->child[k];\n        e->time = node_time[e->parent];\n        if (has_metadata) {\n            e->metadata_offset = edges->metadata_offset[k];\n            e->metadata_length\n                = edges->metadata_offset[k + 1] - edges->metadata_offset[k];\n        }\n    }\n    qsort(sorted_edges, (size_t) n, sizeof(edge_sort_t), cmp_edge);\n    /* Copy the edges back into the table. */\n    metadata_offset = 0;\n    for (j = 0; j < n; j++) {\n        e = sorted_edges + j;\n        k = start + j;\n        edges->left[k] = e->left;\n        edges->right[k] = e->right;\n        edges->parent[k] = e->parent;\n        edges->child[k] = e->child;\n        if (has_metadata) {\n            tsk_memcpy(edges->metadata + metadata_offset,\n                old_metadata + e->metadata_offset, e->metadata_length);\n            edges->metadata_offset[k] = metadata_offset;\n            metadata_offset += e->metadata_length;\n        }\n    }\nout:\n    tsk_safe_free(sorted_edges);\n    tsk_safe_free(old_metadata);\n    return ret;\n}\n\nstatic int\ntsk_table_sorter_sort_migrations(tsk_table_sorter_t *self, tsk_size_t start)\n{\n    int ret = 0;\n    const tsk_migration_table_t *migrations = &self->tables->migrations;\n    migration_sort_t *m;\n    tsk_size_t j, k, metadata_offset;\n    tsk_size_t n = migrations->num_rows - start;\n    migration_sort_t *sorted_migrations = tsk_malloc(n * sizeof(*sorted_migrations));\n    char *old_metadata = tsk_malloc(migrations->metadata_length);\n\n    if (sorted_migrations == NULL || old_metadata == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memcpy(old_metadata, migrations->metadata, migrations->metadata_length);\n    for (j = 0; j < n; j++) {\n        m = sorted_migrations + j;\n        k = start + j;\n        m->left = migrations->left[k];\n        m->right = migrations->right[k];\n        m->node = migrations->node[k];\n        m->source = migrations->source[k];\n        m->dest = migrations->dest[k];\n        m->time = migrations->time[k];\n        m->metadata_offset = migrations->metadata_offset[k];\n        m->metadata_length\n            = migrations->metadata_offset[k + 1] - migrations->metadata_offset[k];\n    }\n    qsort(sorted_migrations, (size_t) n, sizeof(migration_sort_t), cmp_migration);\n    /* Copy the migrations back into the table. */\n    metadata_offset = 0;\n    for (j = 0; j < n; j++) {\n        m = sorted_migrations + j;\n        k = start + j;\n        migrations->left[k] = m->left;\n        migrations->right[k] = m->right;\n        migrations->node[k] = m->node;\n        migrations->source[k] = m->source;\n        migrations->dest[k] = m->dest;\n        migrations->time[k] = m->time;\n        tsk_memcpy(migrations->metadata + metadata_offset,\n            old_metadata + m->metadata_offset, m->metadata_length);\n        migrations->metadata_offset[k] = metadata_offset;\n        metadata_offset += m->metadata_length;\n    }\nout:\n    tsk_safe_free(sorted_migrations);\n    tsk_safe_free(old_metadata);\n    return ret;\n}\n\nstatic int\ntsk_table_sorter_sort_sites(tsk_table_sorter_t *self)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_site_table_t *sites = &self->tables->sites;\n    tsk_site_table_t copy;\n    tsk_size_t j;\n    tsk_size_t num_sites = sites->num_rows;\n    tsk_site_t *sorted_sites = tsk_malloc(num_sites * sizeof(*sorted_sites));\n\n    ret = tsk_site_table_copy(sites, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (sorted_sites == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (j = 0; j < num_sites; j++) {\n        tsk_site_table_get_row_unsafe(&copy, (tsk_id_t) j, sorted_sites + j);\n    }\n\n    /* Sort the sites by position */\n    qsort(sorted_sites, (size_t) num_sites, sizeof(*sorted_sites), cmp_site);\n\n    /* Build the mapping from old site IDs to new site IDs and copy back into the\n     * table\n     */\n    tsk_site_table_clear(sites);\n    for (j = 0; j < num_sites; j++) {\n        self->site_id_map[sorted_sites[j].id] = (tsk_id_t) j;\n        ret_id = tsk_site_table_add_row(sites, sorted_sites[j].position,\n            sorted_sites[j].ancestral_state, sorted_sites[j].ancestral_state_length,\n            sorted_sites[j].metadata, sorted_sites[j].metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    tsk_safe_free(sorted_sites);\n    tsk_site_table_free(&copy);\n    return ret;\n}\n\nstatic int\ntsk_table_sorter_sort_mutations(tsk_table_sorter_t *self)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t ret_id, parent, mapped_parent, p;\n    tsk_mutation_table_t *mutations = &self->tables->mutations;\n    tsk_node_table_t *nodes = &self->tables->nodes;\n    tsk_size_t num_mutations = mutations->num_rows;\n    tsk_mutation_table_t copy;\n    mutation_sort_t *sorted_mutations\n        = tsk_malloc(num_mutations * sizeof(*sorted_mutations));\n    tsk_id_t *mutation_id_map = tsk_malloc(num_mutations * sizeof(*mutation_id_map));\n\n    ret = tsk_mutation_table_copy(mutations, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (mutation_id_map == NULL || sorted_mutations == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* compute numbers of descendants for each mutation */\n    for (j = 0; j < num_mutations; j++) {\n        sorted_mutations[j].num_descendants = 0;\n    }\n    for (j = 0; j < num_mutations; j++) {\n        p = mutations->parent[j];\n        while (p != TSK_NULL) {\n            sorted_mutations[p].num_descendants += 1;\n            if (sorted_mutations[p].num_descendants > (int) num_mutations) {\n                ret = tsk_trace_error(TSK_ERR_MUTATION_PARENT_INCONSISTENT);\n                goto out;\n            }\n            p = mutations->parent[p];\n        }\n    }\n\n    for (j = 0; j < num_mutations; j++) {\n        tsk_mutation_table_get_row_unsafe(&copy, (tsk_id_t) j, &sorted_mutations[j].mut);\n        sorted_mutations[j].mut.site = self->site_id_map[sorted_mutations[j].mut.site];\n        sorted_mutations[j].node_time = nodes->time[sorted_mutations[j].mut.node];\n    }\n    ret = tsk_mutation_table_clear(mutations);\n    if (ret != 0) {\n        goto out;\n    }\n\n    qsort(sorted_mutations, (size_t) num_mutations, sizeof(*sorted_mutations),\n        cmp_mutation);\n\n    /* Make a first pass through the sorted mutations to build the ID map. */\n    for (j = 0; j < num_mutations; j++) {\n        mutation_id_map[sorted_mutations[j].mut.id] = (tsk_id_t) j;\n    }\n\n    for (j = 0; j < num_mutations; j++) {\n        mapped_parent = TSK_NULL;\n        parent = sorted_mutations[j].mut.parent;\n        if (parent != TSK_NULL) {\n            mapped_parent = mutation_id_map[parent];\n        }\n        ret_id = tsk_mutation_table_add_row(mutations, sorted_mutations[j].mut.site,\n            sorted_mutations[j].mut.node, mapped_parent, sorted_mutations[j].mut.time,\n            sorted_mutations[j].mut.derived_state,\n            sorted_mutations[j].mut.derived_state_length,\n            sorted_mutations[j].mut.metadata, sorted_mutations[j].mut.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\n\nout:\n    tsk_safe_free(mutation_id_map);\n    tsk_safe_free(sorted_mutations);\n    tsk_mutation_table_free(&copy);\n    return ret;\n}\n\nstatic int\ntsk_individual_table_topological_sort(\n    tsk_individual_table_t *self, tsk_id_t *traversal_order, tsk_size_t *num_descendants)\n{\n    int ret = 0;\n    tsk_id_t i, j, p;\n    tsk_individual_t individual;\n    tsk_size_t num_individuals = self->num_rows;\n    tsk_size_t current_todo = 0;\n    tsk_size_t todo_insertion_point = 0;\n    tsk_size_t *incoming_edge_count\n        = tsk_malloc(num_individuals * sizeof(*incoming_edge_count));\n    bool count_descendants = (num_descendants != NULL);\n\n    if (incoming_edge_count == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (i = 0; i < (tsk_id_t) num_individuals; i++) {\n        incoming_edge_count[i] = 0;\n        traversal_order[i] = TSK_NULL;\n        if (count_descendants) {\n            num_descendants[i] = 0;\n        }\n    }\n\n    /* First find the set of individuals that have no children by creating\n     * an array of incoming edge counts */\n    for (i = 0; i < (tsk_id_t) self->parents_length; i++) {\n        if (self->parents[i] != TSK_NULL) {\n            incoming_edge_count[self->parents[i]]++;\n        }\n    }\n    /* Use these as the starting points for checking all individuals,\n     * doing this in reverse makes the sort stable */\n    for (i = (tsk_id_t) num_individuals - 1; i >= 0; i--) {\n        if (incoming_edge_count[i] == 0) {\n            traversal_order[todo_insertion_point] = i;\n            todo_insertion_point++;\n        }\n    }\n\n    /* Now process individuals from the set that have no children, updating their\n     * parents' information as we go, and adding their parents to the list if\n     * this was their last child */\n    while (current_todo < todo_insertion_point) {\n        j = traversal_order[current_todo];\n        tsk_individual_table_get_row_unsafe(self, j, &individual);\n        for (i = 0; i < (tsk_id_t) individual.parents_length; i++) {\n            p = individual.parents[i];\n            if (p != TSK_NULL) {\n                incoming_edge_count[p]--;\n                if (count_descendants) {\n                    num_descendants[p] += 1 + num_descendants[j];\n                }\n                if (incoming_edge_count[p] == 0) {\n                    traversal_order[todo_insertion_point] = p;\n                    todo_insertion_point++;\n                }\n            }\n        }\n        current_todo++;\n    }\n\n    /* Any edges left are parts of cycles */\n    for (i = 0; i < (tsk_id_t) num_individuals; i++) {\n        if (incoming_edge_count[i] > 0) {\n            ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_PARENT_CYCLE);\n            goto out;\n        }\n    }\n\nout:\n    tsk_safe_free(incoming_edge_count);\n    return ret;\n}\n\nint\ntsk_table_collection_individual_topological_sort(\n    tsk_table_collection_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t i, ret_id;\n    tsk_individual_table_t copy;\n    tsk_individual_t individual;\n    tsk_individual_table_t *individuals = &self->individuals;\n    tsk_node_table_t *nodes = &self->nodes;\n    tsk_size_t num_individuals = individuals->num_rows;\n    tsk_id_t *traversal_order = tsk_malloc(num_individuals * sizeof(*traversal_order));\n    tsk_id_t *new_id_map = tsk_malloc(num_individuals * sizeof(*new_id_map));\n\n    if (new_id_map == NULL || traversal_order == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(new_id_map, 0xff, num_individuals * sizeof(*new_id_map));\n\n    ret = tsk_individual_table_copy(individuals, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret_id = tsk_table_collection_check_integrity(self, 0);\n    if (ret_id != 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n\n    ret = tsk_individual_table_clear(individuals);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_individual_table_topological_sort(&copy, traversal_order, NULL);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* The sorted individuals are in reverse order */\n    for (i = (tsk_id_t) num_individuals - 1; i >= 0; i--) {\n        tsk_individual_table_get_row_unsafe(&copy, traversal_order[i], &individual);\n        ret_id = tsk_individual_table_add_row(individuals, individual.flags,\n            individual.location, individual.location_length, individual.parents,\n            individual.parents_length, individual.metadata, individual.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n        new_id_map[traversal_order[i]] = ret_id;\n    }\n\n    /* Rewrite the parent ids */\n    for (i = 0; i < (tsk_id_t) individuals->parents_length; i++) {\n        if (individuals->parents[i] != TSK_NULL) {\n            individuals->parents[i] = new_id_map[individuals->parents[i]];\n        }\n    }\n    /* Rewrite the node individual ids */\n    for (i = 0; i < (tsk_id_t) nodes->num_rows; i++) {\n        if (nodes->individual[i] != TSK_NULL) {\n            nodes->individual[i] = new_id_map[nodes->individual[i]];\n        }\n    }\n\n    ret = 0;\nout:\n    tsk_safe_free(traversal_order);\n    tsk_safe_free(new_id_map);\n    tsk_individual_table_free(&copy);\n    return ret;\n}\n\nstatic int\ntsk_table_sorter_sort_individuals_canonical(tsk_table_sorter_t *self)\n{\n    int ret = 0;\n    tsk_id_t ret_id, i, j, parent, mapped_parent;\n    tsk_individual_table_t *individuals = &self->tables->individuals;\n    tsk_node_table_t *nodes = &self->tables->nodes;\n    tsk_individual_table_t copy;\n    tsk_size_t num_individuals = individuals->num_rows;\n    individual_canonical_sort_t *sorted_individuals\n        = tsk_malloc(num_individuals * sizeof(*sorted_individuals));\n    tsk_id_t *individual_id_map\n        = tsk_malloc(num_individuals * sizeof(*individual_id_map));\n    tsk_size_t *num_descendants = tsk_malloc(num_individuals * sizeof(*num_descendants));\n    tsk_id_t *traversal_order = tsk_malloc(num_individuals * sizeof(*traversal_order));\n\n    if (individual_id_map == NULL || sorted_individuals == NULL\n        || traversal_order == NULL || num_descendants == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_individual_table_copy(individuals, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_clear(individuals);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_individual_table_topological_sort(&copy, traversal_order, num_descendants);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (i = 0; i < (tsk_id_t) num_individuals; i++) {\n        sorted_individuals[i].num_descendants = num_descendants[i];\n        sorted_individuals[i].first_node = (tsk_id_t) nodes->num_rows;\n    }\n\n    /* find first referring node */\n    for (j = 0; j < (tsk_id_t) nodes->num_rows; j++) {\n        if (nodes->individual[j] != TSK_NULL) {\n            sorted_individuals[nodes->individual[j]].first_node\n                = TSK_MIN(j, sorted_individuals[nodes->individual[j]].first_node);\n        }\n    }\n\n    for (j = 0; j < (tsk_id_t) num_individuals; j++) {\n        tsk_individual_table_get_row_unsafe(\n            &copy, (tsk_id_t) j, &sorted_individuals[j].ind);\n    }\n\n    qsort(sorted_individuals, (size_t) num_individuals, sizeof(*sorted_individuals),\n        cmp_individual_canonical);\n\n    /* Make a first pass through the sorted individuals to build the ID map. */\n    for (j = 0; j < (tsk_id_t) num_individuals; j++) {\n        individual_id_map[sorted_individuals[j].ind.id] = (tsk_id_t) j;\n    }\n\n    for (i = 0; i < (tsk_id_t) num_individuals; i++) {\n        for (j = 0; j < (tsk_id_t) sorted_individuals[i].ind.parents_length; j++) {\n            parent = sorted_individuals[i].ind.parents[j];\n            if (parent != TSK_NULL) {\n                mapped_parent = individual_id_map[parent];\n                sorted_individuals[i].ind.parents[j] = mapped_parent;\n            }\n        }\n        ret_id = tsk_individual_table_add_row(individuals,\n            sorted_individuals[i].ind.flags, sorted_individuals[i].ind.location,\n            sorted_individuals[i].ind.location_length, sorted_individuals[i].ind.parents,\n            sorted_individuals[i].ind.parents_length, sorted_individuals[i].ind.metadata,\n            sorted_individuals[i].ind.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    ret = 0;\n\n    /* remap individuals in the node table */\n    for (i = 0; i < (tsk_id_t) nodes->num_rows; i++) {\n        j = nodes->individual[i];\n        if (j != TSK_NULL) {\n            nodes->individual[i] = individual_id_map[j];\n        }\n    }\n\nout:\n    tsk_safe_free(sorted_individuals);\n    tsk_safe_free(individual_id_map);\n    tsk_safe_free(traversal_order);\n    tsk_safe_free(num_descendants);\n    tsk_individual_table_free(&copy);\n    return ret;\n}\n\nint\ntsk_table_sorter_run(tsk_table_sorter_t *self, const tsk_bookmark_t *start)\n{\n    int ret = 0;\n    tsk_size_t edge_start = 0;\n    tsk_size_t migration_start = 0;\n    bool skip_sites = false;\n    bool skip_individuals = false;\n\n    if (start != NULL) {\n        if (start->edges > self->tables->edges.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_EDGE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        edge_start = start->edges;\n        if (start->migrations > self->tables->migrations.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_MIGRATION_OUT_OF_BOUNDS);\n            goto out;\n        }\n        migration_start = start->migrations;\n\n        /* We only allow sites and mutations to be specified as a way to\n         * skip sorting them entirely. Both sites and mutations must be\n         * equal to the number of rows */\n        if (start->sites == self->tables->sites.num_rows\n            && start->mutations == self->tables->mutations.num_rows) {\n            skip_sites = true;\n        } else if (start->sites != 0 || start->mutations != 0) {\n            ret = tsk_trace_error(TSK_ERR_SORT_OFFSET_NOT_SUPPORTED);\n            goto out;\n        }\n    }\n    /* The indexes will be invalidated, so drop them */\n    ret = tsk_table_collection_drop_index(self->tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (self->sort_edges != NULL) {\n        ret = self->sort_edges(self, edge_start);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    /* Avoid calling sort_migrations in the common case when it's a no-op */\n    if (self->tables->migrations.num_rows > 0) {\n        ret = tsk_table_sorter_sort_migrations(self, migration_start);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (!skip_sites) {\n        ret = tsk_table_sorter_sort_sites(self);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = self->sort_mutations(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (!skip_individuals && self->sort_individuals != NULL) {\n        ret = self->sort_individuals(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_table_sorter_init(\n    tsk_table_sorter_t *self, tsk_table_collection_t *tables, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n\n    tsk_memset(self, 0, sizeof(tsk_table_sorter_t));\n    if (!(options & TSK_NO_CHECK_INTEGRITY)) {\n        ret_id = tsk_table_collection_check_integrity(tables, 0);\n        if (ret_id != 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n    self->tables = tables;\n\n    self->site_id_map = tsk_malloc(self->tables->sites.num_rows * sizeof(tsk_id_t));\n    if (self->site_id_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* Set the sort_edges and sort_mutations methods to the default. */\n    self->sort_edges = tsk_table_sorter_sort_edges;\n    self->sort_mutations = tsk_table_sorter_sort_mutations;\n    /* Default sort doesn't touch individuals */\n    self->sort_individuals = NULL;\nout:\n    return ret;\n}\n\nint\ntsk_table_sorter_free(tsk_table_sorter_t *self)\n{\n    tsk_safe_free(self->site_id_map);\n    return 0;\n}\n\n/*************************\n * segment overlapper\n *************************/\n\ntypedef struct _interval_list_t {\n    double left;\n    double right;\n    struct _interval_list_t *next;\n} interval_list_t;\n\ntypedef struct _mutation_id_list_t {\n    tsk_id_t mutation;\n    struct _mutation_id_list_t *next;\n} mutation_id_list_t;\n\ntypedef struct _tsk_segment_t {\n    double left;\n    double right;\n    struct _tsk_segment_t *next;\n    tsk_id_t node;\n} tsk_segment_t;\n\n/* segment overlap finding algorithm */\ntypedef struct {\n    /* The input segments. This buffer is sorted by the algorithm and we also\n     * assume that there is space for an extra element at the end */\n    tsk_segment_t *segments;\n    tsk_size_t num_segments;\n    tsk_size_t index;\n    tsk_size_t num_overlapping;\n    double left;\n    double right;\n    /* Output buffer */\n    tsk_size_t max_overlapping;\n    tsk_segment_t **overlapping;\n} segment_overlapper_t;\n\ntypedef struct {\n    tsk_size_t num_samples;\n    tsk_flags_t options;\n    tsk_table_collection_t *tables;\n    /* Keep a copy of the input tables */\n    tsk_table_collection_t input_tables;\n    /* State for topology */\n    tsk_segment_t **ancestor_map_head;\n    tsk_segment_t **ancestor_map_tail;\n    /* Mapping of input node IDs to output node IDs. */\n    tsk_id_t *node_id_map;\n    bool *is_sample;\n    /* Segments for a particular parent that are processed together */\n    tsk_segment_t *segment_queue;\n    tsk_size_t segment_queue_size;\n    tsk_size_t max_segment_queue_size;\n    segment_overlapper_t segment_overlapper;\n    tsk_blkalloc_t segment_heap;\n    /* Buffer for output edges. For each child we keep a linked list of\n     * intervals, and also store the actual children that have been buffered. */\n    tsk_blkalloc_t interval_list_heap;\n    interval_list_t **child_edge_map_head;\n    interval_list_t **child_edge_map_tail;\n    tsk_id_t *buffered_children;\n    tsk_size_t num_buffered_children;\n    /* For each mutation, map its output node. */\n    tsk_id_t *mutation_node_map;\n    /* Map of input nodes to the list of input mutation IDs */\n    mutation_id_list_t **node_mutation_list_map_head;\n    mutation_id_list_t **node_mutation_list_map_tail;\n    mutation_id_list_t *node_mutation_list_mem;\n    /* When reducing topology, we need a map positions to their corresponding\n     * sites.*/\n    double *position_lookup;\n    int64_t edge_sort_offset;\n} simplifier_t;\n\nstatic int\ncmp_segment(const void *a, const void *b)\n{\n    const tsk_segment_t *ia = (const tsk_segment_t *) a;\n    const tsk_segment_t *ib = (const tsk_segment_t *) b;\n    int ret = (ia->left > ib->left) - (ia->left < ib->left);\n    /* Break ties using the node */\n    if (ret == 0) {\n        ret = (ia->node > ib->node) - (ia->node < ib->node);\n    }\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsegment_overlapper_alloc(segment_overlapper_t *self)\n{\n    int ret = 0;\n\n    tsk_memset(self, 0, sizeof(*self));\n    self->max_overlapping = 8; /* Making sure we call tsk_realloc in tests */\n    self->overlapping = tsk_malloc(self->max_overlapping * sizeof(*self->overlapping));\n    if (self->overlapping == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nsegment_overlapper_free(segment_overlapper_t *self)\n{\n    tsk_safe_free(self->overlapping);\n    return 0;\n}\n\n/* Initialise the segment overlapper for use. Note that the segments\n * array must have space for num_segments + 1 elements!\n */\nstatic int TSK_WARN_UNUSED\nsegment_overlapper_start(\n    segment_overlapper_t *self, tsk_segment_t *segments, tsk_size_t num_segments)\n{\n    int ret = 0;\n    tsk_segment_t *sentinel;\n    void *p;\n\n    if (self->max_overlapping < num_segments) {\n        self->max_overlapping = num_segments;\n        p = tsk_realloc(\n            self->overlapping, self->max_overlapping * sizeof(*self->overlapping));\n        if (p == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->overlapping = p;\n    }\n    self->segments = segments;\n    self->num_segments = num_segments;\n    self->index = 0;\n    self->num_overlapping = 0;\n    self->left = 0;\n    self->right = DBL_MAX;\n\n    /* Sort the segments in the buffer by left coordinate */\n    qsort(\n        self->segments, (size_t) self->num_segments, sizeof(tsk_segment_t), cmp_segment);\n    /* NOTE! We are assuming that there's space for another element on the end\n     * here. This is to insert a sentinel which simplifies the logic. */\n    sentinel = self->segments + self->num_segments;\n    sentinel->left = DBL_MAX;\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsegment_overlapper_next(segment_overlapper_t *self, double *left, double *right,\n    tsk_segment_t ***overlapping, tsk_size_t *num_overlapping)\n{\n    int ret = 0;\n    tsk_size_t j, k;\n    tsk_size_t n = self->num_segments;\n    tsk_segment_t *S = self->segments;\n\n    if (self->index < n) {\n        self->left = self->right;\n        /* Remove any elements of X with right <= left */\n        k = 0;\n        for (j = 0; j < self->num_overlapping; j++) {\n            if (self->overlapping[j]->right > self->left) {\n                self->overlapping[k] = self->overlapping[j];\n                k++;\n            }\n        }\n        self->num_overlapping = k;\n        if (k == 0) {\n            self->left = S[self->index].left;\n        }\n        while (self->index < n && S[self->index].left == self->left) {\n            tsk_bug_assert(self->num_overlapping < self->max_overlapping);\n            self->overlapping[self->num_overlapping] = &S[self->index];\n            self->num_overlapping++;\n            self->index++;\n        }\n        self->index--;\n        self->right = S[self->index + 1].left;\n        for (j = 0; j < self->num_overlapping; j++) {\n            self->right = TSK_MIN(self->right, self->overlapping[j]->right);\n        }\n        tsk_bug_assert(self->left < self->right);\n        self->index++;\n        ret = 1;\n    } else {\n        self->left = self->right;\n        self->right = DBL_MAX;\n        k = 0;\n        for (j = 0; j < self->num_overlapping; j++) {\n            if (self->overlapping[j]->right > self->left) {\n                self->right = TSK_MIN(self->right, self->overlapping[j]->right);\n                self->overlapping[k] = self->overlapping[j];\n                k++;\n            }\n        }\n        self->num_overlapping = k;\n        if (k > 0) {\n            ret = 1;\n        }\n    }\n\n    *left = self->left;\n    *right = self->right;\n    *overlapping = self->overlapping;\n    *num_overlapping = self->num_overlapping;\n    return ret;\n}\n\nstatic int\ncmp_node_id(const void *a, const void *b)\n{\n    const tsk_id_t *ia = (const tsk_id_t *) a;\n    const tsk_id_t *ib = (const tsk_id_t *) b;\n    return (*ia > *ib) - (*ia < *ib);\n}\n\n/*************************\n * Ancestor mapper\n *************************/\n\n/* NOTE: this struct shares a lot with the simplifier_t, mostly in\n * terms of infrastructure for managing the list of intervals, saving\n * edges etc. We should try to abstract the common functionality out\n * into a separate class, which handles this.\n */\ntypedef struct {\n    tsk_id_t *samples;\n    tsk_size_t num_samples;\n    tsk_id_t *ancestors;\n    tsk_size_t num_ancestors;\n    tsk_table_collection_t *tables;\n    tsk_edge_table_t *result;\n    tsk_segment_t **ancestor_map_head;\n    tsk_segment_t **ancestor_map_tail;\n    bool *is_sample;\n    bool *is_ancestor;\n    tsk_segment_t *segment_queue;\n    tsk_size_t segment_queue_size;\n    tsk_size_t max_segment_queue_size;\n    segment_overlapper_t segment_overlapper;\n    tsk_blkalloc_t segment_heap;\n    tsk_blkalloc_t interval_list_heap;\n    interval_list_t **child_edge_map_head;\n    interval_list_t **child_edge_map_tail;\n    tsk_id_t *buffered_children;\n    tsk_size_t num_buffered_children;\n    double sequence_length;\n    double oldest_node_time;\n} ancestor_mapper_t;\n\nstatic tsk_segment_t *TSK_WARN_UNUSED\nancestor_mapper_alloc_segment(\n    ancestor_mapper_t *self, double left, double right, tsk_id_t node)\n{\n    tsk_segment_t *seg = NULL;\n\n    seg = tsk_blkalloc_get(&self->segment_heap, sizeof(*seg));\n    if (seg == NULL) {\n        goto out;\n    }\n    seg->next = NULL;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\nout:\n    return seg;\n}\n\nstatic interval_list_t *TSK_WARN_UNUSED\nancestor_mapper_alloc_interval_list(ancestor_mapper_t *self, double left, double right)\n{\n    interval_list_t *x = NULL;\n\n    x = tsk_blkalloc_get(&self->interval_list_heap, sizeof(*x));\n    if (x == NULL) {\n        goto out;\n    }\n    x->next = NULL;\n    x->left = left;\n    x->right = right;\nout:\n    return x;\n}\n\nstatic int\nancestor_mapper_flush_edges(\n    ancestor_mapper_t *self, tsk_id_t parent, tsk_size_t *ret_num_edges)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_id_t child;\n    interval_list_t *x;\n    tsk_size_t num_edges = 0;\n\n    qsort(self->buffered_children, (size_t) self->num_buffered_children,\n        sizeof(tsk_id_t), cmp_node_id);\n    for (j = 0; j < self->num_buffered_children; j++) {\n        child = self->buffered_children[j];\n        for (x = self->child_edge_map_head[child]; x != NULL; x = x->next) {\n            ret_id = tsk_edge_table_add_row(\n                self->result, x->left, x->right, parent, child, NULL, 0);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            num_edges++;\n        }\n        self->child_edge_map_head[child] = NULL;\n        self->child_edge_map_tail[child] = NULL;\n    }\n    self->num_buffered_children = 0;\n    *ret_num_edges = num_edges;\n    ret = tsk_blkalloc_reset(&self->interval_list_heap);\nout:\n    return ret;\n}\n\nstatic int\nancestor_mapper_record_edge(\n    ancestor_mapper_t *self, double left, double right, tsk_id_t child)\n{\n    int ret = 0;\n    interval_list_t *tail, *x;\n\n    tail = self->child_edge_map_tail[child];\n    if (tail == NULL) {\n        tsk_bug_assert(self->num_buffered_children < self->tables->nodes.num_rows);\n        self->buffered_children[self->num_buffered_children] = child;\n        self->num_buffered_children++;\n        x = ancestor_mapper_alloc_interval_list(self, left, right);\n        if (x == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->child_edge_map_head[child] = x;\n        self->child_edge_map_tail[child] = x;\n    } else {\n        if (tail->right == left) {\n            tail->right = right;\n        } else {\n            x = ancestor_mapper_alloc_interval_list(self, left, right);\n            if (x == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            tail->next = x;\n            self->child_edge_map_tail[child] = x;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nancestor_mapper_add_ancestry(ancestor_mapper_t *self, tsk_id_t input_id, double left,\n    double right, tsk_id_t output_id)\n{\n    int ret = 0;\n    tsk_segment_t *tail = self->ancestor_map_tail[input_id];\n    tsk_segment_t *x;\n\n    tsk_bug_assert(left < right);\n    if (tail == NULL) {\n        x = ancestor_mapper_alloc_segment(self, left, right, output_id);\n        if (x == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->ancestor_map_head[input_id] = x;\n        self->ancestor_map_tail[input_id] = x;\n    } else {\n        if (tail->right == left && tail->node == output_id) {\n            tail->right = right;\n        } else {\n            x = ancestor_mapper_alloc_segment(self, left, right, output_id);\n            if (x == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            tail->next = x;\n            self->ancestor_map_tail[input_id] = x;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic void\nancestor_mapper_find_oldest_node(ancestor_mapper_t *self)\n{\n    const double *node_time = self->tables->nodes.time;\n    tsk_size_t j;\n    double max_time = -1;\n\n    for (j = 0; j < self->num_ancestors; j++) {\n        max_time = TSK_MAX(max_time, node_time[self->ancestors[j]]);\n    }\n    for (j = 0; j < self->num_samples; j++) {\n        max_time = TSK_MAX(max_time, node_time[self->samples[j]]);\n    }\n\n    self->oldest_node_time = max_time;\n}\n\nstatic int\nancestor_mapper_init_samples(ancestor_mapper_t *self, tsk_id_t *samples)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    /* Go through the samples to check for errors. */\n    for (j = 0; j < self->num_samples; j++) {\n        if (samples[j] < 0 || samples[j] > (tsk_id_t) self->tables->nodes.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (self->is_sample[samples[j]]) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        self->is_sample[samples[j]] = true;\n        ret = ancestor_mapper_add_ancestry(\n            self, samples[j], 0, self->tables->sequence_length, samples[j]);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\nancestor_mapper_init_ancestors(ancestor_mapper_t *self, tsk_id_t *ancestors)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    /* Go through the samples to check for errors. */\n    for (j = 0; j < self->num_ancestors; j++) {\n        if (ancestors[j] < 0 || ancestors[j] > (tsk_id_t) self->tables->nodes.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (self->is_ancestor[ancestors[j]]) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        self->is_ancestor[ancestors[j]] = true;\n    }\nout:\n    return ret;\n}\n\nstatic int\nancestor_mapper_init(ancestor_mapper_t *self, tsk_id_t *samples, tsk_size_t num_samples,\n    tsk_id_t *ancestors, tsk_size_t num_ancestors, tsk_table_collection_t *tables,\n    tsk_edge_table_t *result)\n{\n    int ret = 0;\n    tsk_size_t num_nodes;\n\n    tsk_memset(self, 0, sizeof(ancestor_mapper_t));\n    self->num_samples = num_samples;\n    self->num_ancestors = num_ancestors;\n    self->samples = samples;\n    self->ancestors = ancestors;\n    self->tables = tables;\n    self->result = result;\n    self->sequence_length = self->tables->sequence_length;\n\n    if (samples == NULL || num_samples == 0 || ancestors == NULL || num_ancestors == 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    /* Allocate the heaps used for small objects-> Assuming 8K is a good chunk size\n     */\n    ret = tsk_blkalloc_init(&self->segment_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_blkalloc_init(&self->interval_list_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = segment_overlapper_alloc(&self->segment_overlapper);\n    if (ret != 0) {\n        goto out;\n    }\n\n    num_nodes = tables->nodes.num_rows;\n    /* Make the maps and set the intial state */\n    self->ancestor_map_head = tsk_calloc(num_nodes, sizeof(tsk_segment_t *));\n    self->ancestor_map_tail = tsk_calloc(num_nodes, sizeof(tsk_segment_t *));\n    self->child_edge_map_head = tsk_calloc(num_nodes, sizeof(interval_list_t *));\n    self->child_edge_map_tail = tsk_calloc(num_nodes, sizeof(interval_list_t *));\n    self->buffered_children = tsk_malloc(num_nodes * sizeof(tsk_id_t));\n    self->is_sample = tsk_calloc(num_nodes, sizeof(bool));\n    self->is_ancestor = tsk_calloc(num_nodes, sizeof(bool));\n    self->max_segment_queue_size = 64;\n    self->segment_queue\n        = tsk_malloc(self->max_segment_queue_size * sizeof(tsk_segment_t));\n    if (self->ancestor_map_head == NULL || self->ancestor_map_tail == NULL\n        || self->child_edge_map_head == NULL || self->child_edge_map_tail == NULL\n        || self->is_sample == NULL || self->is_ancestor == NULL\n        || self->segment_queue == NULL || self->buffered_children == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    // Clear memory.\n    ret = ancestor_mapper_init_samples(self, samples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = ancestor_mapper_init_ancestors(self, ancestors);\n    if (ret != 0) {\n        goto out;\n    }\n    ancestor_mapper_find_oldest_node(self);\n    ret = tsk_edge_table_clear(self->result);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nancestor_mapper_free(ancestor_mapper_t *self)\n{\n    tsk_blkalloc_free(&self->segment_heap);\n    tsk_blkalloc_free(&self->interval_list_heap);\n    segment_overlapper_free(&self->segment_overlapper);\n    tsk_safe_free(self->ancestor_map_head);\n    tsk_safe_free(self->ancestor_map_tail);\n    tsk_safe_free(self->child_edge_map_head);\n    tsk_safe_free(self->child_edge_map_tail);\n    tsk_safe_free(self->segment_queue);\n    tsk_safe_free(self->is_sample);\n    tsk_safe_free(self->is_ancestor);\n    tsk_safe_free(self->buffered_children);\n    return 0;\n}\n\nstatic int TSK_WARN_UNUSED\nancestor_mapper_enqueue_segment(\n    ancestor_mapper_t *self, double left, double right, tsk_id_t node)\n{\n    int ret = 0;\n    tsk_segment_t *seg;\n    void *p;\n\n    tsk_bug_assert(left < right);\n    /* Make sure we always have room for one more segment in the queue so we\n     * can put a tail sentinel on it */\n    if (self->segment_queue_size == self->max_segment_queue_size - 1) {\n        self->max_segment_queue_size *= 2;\n        p = tsk_realloc(self->segment_queue,\n            self->max_segment_queue_size * sizeof(*self->segment_queue));\n        if (p == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->segment_queue = p;\n    }\n    seg = self->segment_queue + self->segment_queue_size;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\n    self->segment_queue_size++;\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nancestor_mapper_merge_ancestors(ancestor_mapper_t *self, tsk_id_t input_id)\n{\n    int ret = 0;\n    tsk_segment_t **X, *x;\n    tsk_size_t j, num_overlapping, num_flushed_edges;\n    double left, right, prev_right;\n    bool is_sample = self->is_sample[input_id];\n    bool is_ancestor = self->is_ancestor[input_id];\n\n    if (is_sample) {\n        /* Free up the existing ancestry mapping. */\n        x = self->ancestor_map_tail[input_id];\n        tsk_bug_assert(x->left == 0 && x->right == self->sequence_length);\n        self->ancestor_map_head[input_id] = NULL;\n        self->ancestor_map_tail[input_id] = NULL;\n    }\n    ret = segment_overlapper_start(\n        &self->segment_overlapper, self->segment_queue, self->segment_queue_size);\n    if (ret != 0) {\n        goto out;\n    }\n\n    prev_right = 0;\n    while ((ret = segment_overlapper_next(\n                &self->segment_overlapper, &left, &right, &X, &num_overlapping))\n           == 1) {\n        tsk_bug_assert(left < right);\n        tsk_bug_assert(num_overlapping > 0);\n        if (is_ancestor || is_sample) {\n            for (j = 0; j < num_overlapping; j++) {\n                ret = ancestor_mapper_record_edge(self, left, right, X[j]->node);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n            ret = ancestor_mapper_add_ancestry(self, input_id, left, right, input_id);\n            if (ret != 0) {\n                goto out;\n            }\n            if (is_sample && left != prev_right) {\n                /* Fill in any gaps in ancestry for the sample */\n                ret = ancestor_mapper_add_ancestry(\n                    self, input_id, prev_right, left, input_id);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        } else {\n            for (j = 0; j < num_overlapping; j++) {\n                ret = ancestor_mapper_add_ancestry(\n                    self, input_id, left, right, X[j]->node);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        }\n        prev_right = right;\n    }\n    if (is_sample && prev_right != self->tables->sequence_length) {\n        /* If a trailing gap exists in the sample ancestry, fill it in. */\n        ret = ancestor_mapper_add_ancestry(\n            self, input_id, prev_right, self->sequence_length, input_id);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (input_id != TSK_NULL) {\n        ret = ancestor_mapper_flush_edges(self, input_id, &num_flushed_edges);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nancestor_mapper_process_parent_edges(\n    ancestor_mapper_t *self, tsk_id_t parent, tsk_size_t start, tsk_size_t end)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_segment_t *x;\n    const tsk_edge_table_t *input_edges = &self->tables->edges;\n    tsk_id_t child;\n    double left, right;\n\n    /* Go through the edges and queue up ancestry segments for processing. */\n    self->segment_queue_size = 0;\n    for (j = start; j < end; j++) {\n        tsk_bug_assert(parent == input_edges->parent[j]);\n        child = input_edges->child[j];\n        left = input_edges->left[j];\n        right = input_edges->right[j];\n        // printf(\"C: %i, L: %f, R: %f\\n\", child, left, right);\n        for (x = self->ancestor_map_head[child]; x != NULL; x = x->next) {\n            if (x->right > left && right > x->left) {\n                ret = ancestor_mapper_enqueue_segment(\n                    self, TSK_MAX(x->left, left), TSK_MIN(x->right, right), x->node);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        }\n    }\n    // We can now merge the ancestral segments for the parent\n    ret = ancestor_mapper_merge_ancestors(self, parent);\n    if (ret != 0) {\n        goto out;\n    }\n\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nancestor_mapper_run(ancestor_mapper_t *self)\n{\n    int ret = 0;\n    tsk_size_t j, start;\n    tsk_id_t parent, current_parent;\n    const tsk_edge_table_t *input_edges = &self->tables->edges;\n    tsk_size_t num_edges = input_edges->num_rows;\n    const double *node_time = self->tables->nodes.time;\n    bool early_exit = false;\n\n    if (num_edges > 0) {\n        start = 0;\n        current_parent = input_edges->parent[0];\n        for (j = 0; j < num_edges; j++) {\n            parent = input_edges->parent[j];\n            if (parent != current_parent) {\n                ret = ancestor_mapper_process_parent_edges(\n                    self, current_parent, start, j);\n                if (ret != 0) {\n                    goto out;\n                }\n                start = j;\n                current_parent = parent;\n                if (node_time[current_parent] > self->oldest_node_time) {\n                    early_exit = true;\n                    break;\n                }\n            }\n        }\n        if (!early_exit) {\n            /* If we didn't break out of the loop early, we need to still process\n             * the final parent */\n            ret = ancestor_mapper_process_parent_edges(self, current_parent, start, j);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\n/*************************\n * IBD Segments\n *************************/\n\n/* This maps two positive integers 0 <= a < b < N into the set\n * {0, ..., N^2}. For us to overflow an int64, N would need to\n * be > sqrt(2^63), ~3 * 10^9. The maximum value for a 32bit int\n * is ~2 * 10^9, so this can't happen here, however it is\n * theoretically possible with 64 bit IDs. It would require\n * a *very* large node table --- assuming 24 bytes per row\n * it would be at least 67GiB. To make sure this eventuality\n * doesn't happen, we have a tsk_bug_assert in the\n * tsk_identity_segments_init.\n */\nstatic inline int64_t\npair_to_integer(tsk_id_t a, tsk_id_t b, tsk_size_t N)\n{\n    tsk_id_t tmp;\n    if (a > b) {\n        tmp = a;\n        a = b;\n        b = tmp;\n    }\n    return ((int64_t) a) * (int64_t) N + (int64_t) b;\n}\n\nstatic inline void\ninteger_to_pair(int64_t index, tsk_size_t N, tsk_id_t *a, tsk_id_t *b)\n{\n    *a = (tsk_id_t)(index / (int64_t) N);\n    *b = (tsk_id_t)(index % (int64_t) N);\n}\n\nstatic int64_t\ntsk_identity_segments_get_key(\n    const tsk_identity_segments_t *self, tsk_id_t a, tsk_id_t b)\n{\n    int64_t ret;\n    tsk_id_t N = (tsk_id_t) self->num_nodes;\n\n    if (a < 0 || b < 0 || a >= N || b >= N) {\n        ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n        goto out;\n    }\n    if (a == b) {\n        ret = tsk_trace_error(TSK_ERR_SAME_NODES_IN_PAIR);\n        goto out;\n    }\n    ret = pair_to_integer(a, b, self->num_nodes);\nout:\n    return ret;\n}\n\nstatic tsk_identity_segment_t *TSK_WARN_UNUSED\ntsk_identity_segments_alloc_segment(\n    tsk_identity_segments_t *self, double left, double right, tsk_id_t node)\n{\n    tsk_identity_segment_t *seg = tsk_blkalloc_get(&self->heap, sizeof(*seg));\n    if (seg == NULL) {\n        goto out;\n    }\n    tsk_bug_assert(left < right);\n    tsk_bug_assert(node >= 0 && node < (tsk_id_t) self->num_nodes);\n\n    seg->next = NULL;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\nout:\n    return seg;\n}\n\nstatic tsk_avl_node_int_t *\ntsk_identity_segments_alloc_new_pair(tsk_identity_segments_t *self, int64_t key)\n{\n    tsk_avl_node_int_t *avl_node = tsk_blkalloc_get(&self->heap, sizeof(*avl_node));\n    tsk_identity_segment_list_t *list = tsk_blkalloc_get(&self->heap, sizeof(*list));\n\n    if (avl_node == NULL || list == NULL) {\n        return NULL;\n    }\n    avl_node->key = key;\n    avl_node->value = list;\n    memset(list, 0, sizeof(*list));\n    return avl_node;\n}\n\n/* Deliberately not making this a part of the public interface for now,\n * so we don't have to worry about the signature */\nstatic int\ntsk_identity_segments_init(\n    tsk_identity_segments_t *self, tsk_size_t num_nodes, tsk_flags_t options)\n{\n    int ret = 0;\n    /* Make sure we don't overflow in the ID mapping. See the comments in pair_to_integer\n     * for details. */\n    double max_num_nodes = sqrt(1ULL << 63);\n    tsk_bug_assert((double) num_nodes < max_num_nodes);\n\n    memset(self, 0, sizeof(*self));\n    self->num_nodes = num_nodes;\n    /* Storing segments implies storing pairs */\n    if (options & TSK_IBD_STORE_SEGMENTS) {\n        self->store_pairs = true;\n        self->store_segments = true;\n    } else if (options & TSK_IBD_STORE_PAIRS) {\n        self->store_pairs = true;\n    }\n    ret = tsk_avl_tree_int_init(&self->pair_map);\n    if (ret != 0) {\n        goto out;\n    }\n    /* Allocate heap memory in 1MiB blocks */\n    ret = tsk_blkalloc_init(&self->heap, 1024 * 1024);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nvoid\ntsk_identity_segments_print_state(tsk_identity_segments_t *self, FILE *out)\n{\n    tsk_avl_node_int_t **nodes = tsk_malloc(self->pair_map.size * sizeof(*nodes));\n    int64_t key;\n    tsk_identity_segment_list_t *value;\n    tsk_identity_segment_t *seg;\n    tsk_size_t j;\n    tsk_id_t a, b;\n\n    tsk_bug_assert(nodes != NULL);\n\n    fprintf(out, \"===\\nIBD Result\\n===\\n\");\n    fprintf(out, \"total_span     = %f\\n\", self->total_span);\n    fprintf(out, \"num_segments   = %lld\\n\", (unsigned long long) self->num_segments);\n    fprintf(out, \"store_pairs    = %d\\n\", self->store_pairs);\n    fprintf(out, \"store_segments = %d\\n\", self->store_segments);\n    if (self->store_pairs) {\n        fprintf(out, \"num_keys       = %d\\n\", (int) self->pair_map.size);\n        tsk_avl_tree_int_ordered_nodes(&self->pair_map, nodes);\n        for (j = 0; j < self->pair_map.size; j++) {\n            key = nodes[j]->key;\n            value = (tsk_identity_segment_list_t *) nodes[j]->value;\n            integer_to_pair(key, self->num_nodes, &a, &b);\n            fprintf(out, \"%lld\\t(%d,%d) n=%d total_span=%f\\t\", (long long) key, (int) a,\n                (int) b, (int) value->num_segments, value->total_span);\n            if (self->store_segments) {\n                for (seg = value->head; seg != NULL; seg = seg->next) {\n                    fprintf(\n                        out, \"(%f, %f)->%d, \", seg->left, seg->right, (int) seg->node);\n                }\n            }\n            fprintf(out, \"\\n\");\n        }\n    }\n    fprintf(out, \"Segment memory\\n\");\n    tsk_blkalloc_print_state(&self->heap, out);\n    tsk_safe_free(nodes);\n}\n\ntsk_size_t\ntsk_identity_segments_get_num_segments(const tsk_identity_segments_t *self)\n{\n    return self->num_segments;\n}\n\ndouble\ntsk_identity_segments_get_total_span(const tsk_identity_segments_t *self)\n{\n    return self->total_span;\n}\n\ntsk_size_t\ntsk_identity_segments_get_num_pairs(const tsk_identity_segments_t *self)\n{\n    return self->pair_map.size;\n}\n\n/* Use an inorder traversal on the AVL tree to get the pairs in order.\n * Recursion is safe here because it's a balanced tree (see the AVL tree\n * code for notes on this).\n */\nstatic int\nget_keys_traverse(tsk_avl_node_int_t *node, int index, tsk_size_t N, tsk_id_t *pairs)\n{\n    tsk_id_t a, b;\n\n    if (node == NULL) {\n        return index;\n    }\n    index = get_keys_traverse(node->llink, index, N, pairs);\n    integer_to_pair(node->key, N, &a, &b);\n    pairs[2 * index] = a;\n    pairs[2 * index + 1] = b;\n    return get_keys_traverse(node->rlink, index + 1, N, pairs);\n}\n\nint\ntsk_identity_segments_get_keys(const tsk_identity_segments_t *self, tsk_id_t *pairs)\n{\n    if (!self->store_pairs) {\n        return TSK_ERR_IBD_PAIRS_NOT_STORED;\n    }\n    get_keys_traverse(\n        tsk_avl_tree_int_get_root(&self->pair_map), 0, self->num_nodes, pairs);\n    return 0;\n}\n\nstatic int\nget_items_traverse(tsk_avl_node_int_t *node, int index, tsk_size_t N, tsk_id_t *pairs,\n    tsk_identity_segment_list_t **lists)\n{\n    tsk_id_t a, b;\n\n    if (node == NULL) {\n        return index;\n    }\n    index = get_items_traverse(node->llink, index, N, pairs, lists);\n    integer_to_pair(node->key, N, &a, &b);\n    pairs[2 * index] = a;\n    pairs[2 * index + 1] = b;\n    lists[index] = node->value;\n    return get_items_traverse(node->rlink, index + 1, N, pairs, lists);\n}\n\nint\ntsk_identity_segments_get_items(const tsk_identity_segments_t *self, tsk_id_t *pairs,\n    tsk_identity_segment_list_t **lists)\n{\n    if (!self->store_pairs) {\n        return TSK_ERR_IBD_PAIRS_NOT_STORED;\n    }\n    get_items_traverse(\n        tsk_avl_tree_int_get_root(&self->pair_map), 0, self->num_nodes, pairs, lists);\n    return 0;\n}\n\nint\ntsk_identity_segments_free(tsk_identity_segments_t *self)\n{\n    tsk_blkalloc_free(&self->heap);\n    tsk_avl_tree_int_free(&self->pair_map);\n    return 0;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_identity_segments_update_pair(tsk_identity_segments_t *self, tsk_id_t a, tsk_id_t b,\n    double left, double right, tsk_id_t node)\n{\n    int ret = 0;\n    tsk_identity_segment_t *x;\n    tsk_identity_segment_list_t *list;\n    /* skip the error checking here since this an internal API */\n    int64_t key = pair_to_integer(a, b, self->num_nodes);\n    tsk_avl_node_int_t *avl_node = tsk_avl_tree_int_search(&self->pair_map, key);\n\n    if (avl_node == NULL) {\n        /* We haven't seen this pair before */\n        avl_node = tsk_identity_segments_alloc_new_pair(self, key);\n        if (avl_node == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        ret = tsk_avl_tree_int_insert(&self->pair_map, avl_node);\n        tsk_bug_assert(ret == 0);\n    }\n    list = (tsk_identity_segment_list_t *) avl_node->value;\n    list->num_segments++;\n    list->total_span += right - left;\n    if (self->store_segments) {\n        x = tsk_identity_segments_alloc_segment(self, left, right, node);\n        if (x == NULL) {\n            goto out;\n        }\n        if (list->tail == NULL) {\n            list->head = x;\n            list->tail = x;\n        } else {\n            list->tail->next = x;\n            list->tail = x;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_identity_segments_add_segment(tsk_identity_segments_t *self, tsk_id_t a, tsk_id_t b,\n    double left, double right, tsk_id_t node)\n{\n    int ret = 0;\n\n    if (self->store_pairs) {\n        ret = tsk_identity_segments_update_pair(self, a, b, left, right, node);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    self->total_span += right - left;\n    self->num_segments++;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_identity_segments_get(const tsk_identity_segments_t *self, tsk_id_t sample_a,\n    tsk_id_t sample_b, tsk_identity_segment_list_t **ret_list)\n{\n    int ret = 0;\n    int64_t key = tsk_identity_segments_get_key(self, sample_a, sample_b);\n    tsk_avl_node_int_t *avl_node;\n\n    if (key < 0) {\n        ret = (int) key;\n        goto out;\n    }\n    if (!self->store_pairs) {\n        ret = tsk_trace_error(TSK_ERR_IBD_PAIRS_NOT_STORED);\n        goto out;\n    }\n    avl_node = tsk_avl_tree_int_search(&self->pair_map, key);\n    *ret_list = NULL;\n    if (avl_node != NULL) {\n        *ret_list = (tsk_identity_segment_list_t *) avl_node->value;\n    }\nout:\n    return ret;\n}\n\n/*************************\n * IBD finder\n *************************/\n\ntypedef struct {\n    tsk_identity_segments_t *result;\n    double min_span;\n    double max_time;\n    const tsk_table_collection_t *tables;\n    /* Maps nodes to their sample set IDs. Input samples map to set 0\n     * in the \"within\" case. */\n    tsk_id_t *sample_set_id;\n    /* True if we're finding IBD between sample sets, false otherwise. */\n    bool finding_between;\n    tsk_segment_t **ancestor_map_head;\n    tsk_segment_t **ancestor_map_tail;\n    tsk_segment_t *segment_queue;\n    tsk_size_t segment_queue_size;\n    tsk_size_t max_segment_queue_size;\n    tsk_blkalloc_t segment_heap;\n} tsk_ibd_finder_t;\n\nstatic tsk_segment_t *TSK_WARN_UNUSED\ntsk_ibd_finder_alloc_segment(\n    tsk_ibd_finder_t *self, double left, double right, tsk_id_t node)\n{\n    tsk_segment_t *seg = NULL;\n\n    seg = tsk_blkalloc_get(&self->segment_heap, sizeof(*seg));\n    if (seg == NULL) {\n        goto out;\n    }\n    seg->next = NULL;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\n\nout:\n    return seg;\n}\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_add_ancestry(tsk_ibd_finder_t *self, tsk_id_t input_id, double left,\n    double right, tsk_id_t output_id)\n{\n    int ret = 0;\n    tsk_segment_t *tail = self->ancestor_map_tail[input_id];\n    tsk_segment_t *x = NULL;\n\n    tsk_bug_assert(left < right);\n    x = tsk_ibd_finder_alloc_segment(self, left, right, output_id);\n    if (x == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (tail == NULL) {\n        self->ancestor_map_head[input_id] = x;\n        self->ancestor_map_tail[input_id] = x;\n    } else {\n        tail->next = x;\n        self->ancestor_map_tail[input_id] = x;\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ibd_finder_init_samples_from_set(\n    tsk_ibd_finder_t *self, const tsk_id_t *samples, tsk_size_t num_samples)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t u;\n\n    for (j = 0; j < num_samples; j++) {\n        u = samples[j];\n\n        if (u < 0 || u > (tsk_id_t) self->tables->nodes.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (self->sample_set_id[u] != TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        self->sample_set_id[u] = 0;\n    }\nout:\n    return ret;\n}\n\nstatic void\ntsk_ibd_finder_init_samples_from_nodes(tsk_ibd_finder_t *self)\n{\n    tsk_id_t u;\n    const tsk_id_t num_nodes = (tsk_id_t) self->tables->nodes.num_rows;\n    const tsk_flags_t *restrict flags = self->tables->nodes.flags;\n\n    for (u = 0; u < num_nodes; u++) {\n        if (flags[u] & TSK_NODE_IS_SAMPLE) {\n            self->sample_set_id[u] = 0;\n        }\n    }\n}\n\nstatic int\ntsk_ibd_finder_add_sample_ancestry(tsk_ibd_finder_t *self)\n{\n\n    int ret = 0;\n    tsk_id_t u;\n    const tsk_id_t num_nodes = (tsk_id_t) self->tables->nodes.num_rows;\n    const double L = self->tables->sequence_length;\n\n    for (u = 0; u < num_nodes; u++) {\n        if (self->sample_set_id[u] != TSK_NULL) {\n            ret = tsk_ibd_finder_add_ancestry(self, u, 0, L, u);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_init(tsk_ibd_finder_t *self, const tsk_table_collection_t *tables,\n    tsk_identity_segments_t *result, double min_span, double max_time)\n{\n    int ret = 0;\n    tsk_size_t num_nodes;\n\n    tsk_memset(self, 0, sizeof(tsk_ibd_finder_t));\n\n    if (min_span < 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (max_time < 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    self->tables = tables;\n    self->result = result;\n    self->max_time = max_time;\n    self->min_span = min_span;\n\n    ret = tsk_blkalloc_init(&self->segment_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n\n    num_nodes = tables->nodes.num_rows;\n    self->ancestor_map_head = tsk_calloc(num_nodes, sizeof(*self->ancestor_map_head));\n    self->ancestor_map_tail = tsk_calloc(num_nodes, sizeof(*self->ancestor_map_tail));\n    self->sample_set_id = tsk_malloc(num_nodes * sizeof(*self->sample_set_id));\n    self->segment_queue_size = 0;\n    self->max_segment_queue_size = 64;\n    self->segment_queue\n        = tsk_malloc(self->max_segment_queue_size * sizeof(*self->segment_queue));\n    if (self->ancestor_map_head == NULL || self->ancestor_map_tail == NULL\n        || self->sample_set_id == NULL || self->segment_queue == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(self->sample_set_id, TSK_NULL, num_nodes * sizeof(*self->sample_set_id));\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_enqueue_segment(\n    tsk_ibd_finder_t *self, double left, double right, tsk_id_t node)\n{\n    int ret = 0;\n    tsk_segment_t *seg;\n    void *p;\n\n    if ((right - left) > self->min_span) {\n        /* Make sure we always have room for one more segment in the queue so we\n         * can put a tail sentinel on it */\n        if (self->segment_queue_size == self->max_segment_queue_size - 1) {\n            self->max_segment_queue_size *= 2;\n            p = tsk_realloc(self->segment_queue,\n                self->max_segment_queue_size * sizeof(*self->segment_queue));\n            if (p == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            self->segment_queue = p;\n        }\n        seg = self->segment_queue + self->segment_queue_size;\n        seg->left = left;\n        seg->right = right;\n        seg->node = node;\n        self->segment_queue_size++;\n    }\nout:\n    return ret;\n}\n\nstatic bool\ntsk_ibd_finder_passes_filters(\n    const tsk_ibd_finder_t *self, tsk_id_t a, tsk_id_t b, double left, double right)\n{\n    if (a == b) {\n        return false;\n    }\n    if ((right - left) <= self->min_span) {\n        return false;\n    }\n    if (self->finding_between) {\n        return self->sample_set_id[a] != self->sample_set_id[b];\n    } else {\n        return true;\n    }\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_record_ibd(tsk_ibd_finder_t *self, tsk_id_t parent)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_segment_t *seg0, *seg1;\n    double left, right;\n\n    for (seg0 = self->ancestor_map_head[parent]; seg0 != NULL; seg0 = seg0->next) {\n        for (j = 0; j < self->segment_queue_size; j++) {\n            seg1 = &self->segment_queue[j];\n            left = TSK_MAX(seg0->left, seg1->left);\n            right = TSK_MIN(seg0->right, seg1->right);\n            if (tsk_ibd_finder_passes_filters(\n                    self, seg0->node, seg1->node, left, right)) {\n                ret = tsk_identity_segments_add_segment(\n                    self->result, seg0->node, seg1->node, left, right, parent);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_add_queued_ancestry(tsk_ibd_finder_t *self, tsk_id_t parent)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_segment_t seg;\n\n    for (j = 0; j < self->segment_queue_size; j++) {\n        seg = self->segment_queue[j];\n        ret = tsk_ibd_finder_add_ancestry(self, parent, seg.left, seg.right, seg.node);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    self->segment_queue_size = 0;\nout:\n    return ret;\n}\n\nstatic void\ntsk_ibd_finder_print_state(tsk_ibd_finder_t *self, FILE *out)\n{\n    tsk_size_t j;\n    tsk_segment_t *u = NULL;\n\n    fprintf(out, \"--ibd-finder stats--\\n\");\n    fprintf(out, \"max_time = %f\\n\", self->max_time);\n    fprintf(out, \"min_span = %f\\n\", self->min_span);\n    fprintf(out, \"finding_between = %d\\n\", self->finding_between);\n    fprintf(out, \"===\\nEdges\\n===\\n\");\n    for (j = 0; j < self->tables->edges.num_rows; j++) {\n        fprintf(out, \"L:%f, R:%f, P:%lld, C:%lld\\n\", self->tables->edges.left[j],\n            self->tables->edges.right[j], (long long) self->tables->edges.parent[j],\n            (long long) self->tables->edges.child[j]);\n    }\n    fprintf(out, \"===\\nNodes\\n===\\n\");\n    for (j = 0; j < self->tables->nodes.num_rows; j++) {\n        fprintf(out, \"ID:%d, Time:%f, Flag:%lld Sample set:%d\\n\", (int) j,\n            self->tables->nodes.time[j], (long long) self->tables->nodes.flags[j],\n            (int) self->sample_set_id[j]);\n    }\n    fprintf(out, \"===\\nAncestral map\\n===\\n\");\n    for (j = 0; j < self->tables->nodes.num_rows; j++) {\n        fprintf(out, \"Node %lld: \", (long long) j);\n        for (u = self->ancestor_map_head[j]; u != NULL; u = u->next) {\n            fprintf(out, \"(%f,%f->%lld)\", u->left, u->right, (long long) u->node);\n        }\n        fprintf(out, \"\\n\");\n    }\n    tsk_identity_segments_print_state(self->result, out);\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_init_within(\n    tsk_ibd_finder_t *self, const tsk_id_t *samples, tsk_size_t num_samples)\n{\n    int ret;\n\n    if (samples == NULL) {\n        tsk_ibd_finder_init_samples_from_nodes(self);\n    } else {\n        ret = tsk_ibd_finder_init_samples_from_set(self, samples, num_samples);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    self->finding_between = false;\n    ret = tsk_ibd_finder_add_sample_ancestry(self);\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_init_between(tsk_ibd_finder_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets)\n{\n    int ret = 0;\n    tsk_size_t j, k, index;\n    tsk_id_t u;\n\n    index = 0;\n    for (j = 0; j < num_sample_sets; j++) {\n        for (k = 0; k < sample_set_sizes[j]; k++) {\n            u = sample_sets[index];\n            if (u < 0 || u > (tsk_id_t) self->tables->nodes.num_rows) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            if (self->sample_set_id[u] != TSK_NULL) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            self->sample_set_id[u] = (tsk_id_t) j;\n            index++;\n        }\n    }\n    self->finding_between = true;\n    ret = tsk_ibd_finder_add_sample_ancestry(self);\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_ibd_finder_run(tsk_ibd_finder_t *self)\n{\n    const tsk_edge_table_t *input_edges = &self->tables->edges;\n    const tsk_size_t num_edges = input_edges->num_rows;\n    int ret = 0;\n    tsk_size_t j;\n    tsk_segment_t *s;\n    tsk_id_t parent, child;\n    double left, right, intvl_l, intvl_r, time;\n\n    for (j = 0; j < num_edges; j++) {\n        parent = input_edges->parent[j];\n        left = input_edges->left[j];\n        right = input_edges->right[j];\n        child = input_edges->child[j];\n        time = self->tables->nodes.time[parent];\n        if (time > self->max_time) {\n            break;\n        }\n\n        for (s = self->ancestor_map_head[child]; s != NULL; s = s->next) {\n            intvl_l = TSK_MAX(left, s->left);\n            intvl_r = TSK_MIN(right, s->right);\n            ret = tsk_ibd_finder_enqueue_segment(self, intvl_l, intvl_r, s->node);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n        ret = tsk_ibd_finder_record_ibd(self, parent);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_ibd_finder_add_queued_ancestry(self, parent);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_ibd_finder_free(tsk_ibd_finder_t *self)\n{\n    tsk_blkalloc_free(&self->segment_heap);\n    tsk_safe_free(self->sample_set_id);\n    tsk_safe_free(self->ancestor_map_head);\n    tsk_safe_free(self->ancestor_map_tail);\n    tsk_safe_free(self->segment_queue);\n    return 0;\n}\n\n/*************************\n * simplifier\n *************************/\n\nstatic void\nsimplifier_check_state(simplifier_t *self)\n{\n    tsk_size_t j, k;\n    tsk_segment_t *u;\n    mutation_id_list_t *list_node;\n    tsk_id_t site;\n    interval_list_t *int_list;\n    tsk_id_t child;\n    double position, last_position;\n    bool found;\n    tsk_size_t num_intervals;\n\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        tsk_bug_assert((self->ancestor_map_head[j] == NULL)\n                       == (self->ancestor_map_tail[j] == NULL));\n        for (u = self->ancestor_map_head[j]; u != NULL; u = u->next) {\n            tsk_bug_assert(u->left < u->right);\n            if (u->next != NULL) {\n                tsk_bug_assert(u->right <= u->next->left);\n                if (u->right == u->next->left) {\n                    tsk_bug_assert(u->node != u->next->node);\n                }\n            } else {\n                tsk_bug_assert(u == self->ancestor_map_tail[j]);\n            }\n        }\n    }\n\n    for (j = 0; j < self->segment_queue_size; j++) {\n        tsk_bug_assert(self->segment_queue[j].left < self->segment_queue[j].right);\n    }\n\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        last_position = -1;\n        for (list_node = self->node_mutation_list_map_head[j]; list_node != NULL;\n             list_node = list_node->next) {\n            tsk_bug_assert(\n                self->input_tables.mutations.node[list_node->mutation] == (tsk_id_t) j);\n            site = self->input_tables.mutations.site[list_node->mutation];\n            position = self->input_tables.sites.position[site];\n            tsk_bug_assert(last_position <= position);\n            last_position = position;\n        }\n    }\n\n    /* check the buffered edges */\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        tsk_bug_assert((self->child_edge_map_head[j] == NULL)\n                       == (self->child_edge_map_tail[j] == NULL));\n        if (self->child_edge_map_head[j] != NULL) {\n            /* Make sure that the child is in our list */\n            found = false;\n            for (k = 0; k < self->num_buffered_children; k++) {\n                if (self->buffered_children[k] == (tsk_id_t) j) {\n                    found = true;\n                    break;\n                }\n            }\n            tsk_bug_assert(found);\n        }\n    }\n    num_intervals = 0;\n    for (j = 0; j < self->num_buffered_children; j++) {\n        child = self->buffered_children[j];\n        tsk_bug_assert(self->child_edge_map_head[child] != NULL);\n        for (int_list = self->child_edge_map_head[child]; int_list != NULL;\n             int_list = int_list->next) {\n            tsk_bug_assert(int_list->left < int_list->right);\n            if (int_list->next != NULL) {\n                tsk_bug_assert(int_list->right < int_list->next->left);\n            }\n            num_intervals++;\n        }\n    }\n    tsk_bug_assert(\n        num_intervals\n        == self->interval_list_heap.total_allocated / (sizeof(interval_list_t)));\n}\n\nstatic void\nprint_segment_chain(tsk_segment_t *head, FILE *out)\n{\n    tsk_segment_t *u;\n\n    for (u = head; u != NULL; u = u->next) {\n        fprintf(out, \"(%f,%f->%lld)\", u->left, u->right, (long long) u->node);\n    }\n}\n\nstatic void\nsimplifier_print_state(simplifier_t *self, FILE *out)\n{\n    tsk_size_t j;\n    tsk_segment_t *u;\n    mutation_id_list_t *list_node;\n    interval_list_t *int_list;\n    tsk_id_t child;\n\n    fprintf(out, \"--simplifier state--\\n\");\n    fprintf(out, \"options:\\n\");\n    fprintf(out, \"\\tfilter_unreferenced_sites   : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_FILTER_SITES));\n    fprintf(out, \"\\tno_filter_nodes   : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_NO_FILTER_NODES));\n    fprintf(out, \"\\treduce_to_site_topology : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY));\n    fprintf(out, \"\\tkeep_unary              : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_KEEP_UNARY));\n    fprintf(out, \"\\tkeep_input_roots        : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_KEEP_INPUT_ROOTS));\n    fprintf(out, \"\\tkeep_unary_in_individuals : %d\\n\",\n        !!(self->options & TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS));\n\n    fprintf(out, \"===\\nInput tables\\n==\\n\");\n    tsk_table_collection_print_state(&self->input_tables, out);\n    fprintf(out, \"===\\nOutput tables\\n==\\n\");\n    tsk_table_collection_print_state(self->tables, out);\n    fprintf(out, \"===\\nmemory heaps\\n==\\n\");\n    fprintf(out, \"segment_heap:\\n\");\n    tsk_blkalloc_print_state(&self->segment_heap, out);\n    fprintf(out, \"interval_list_heap:\\n\");\n    tsk_blkalloc_print_state(&self->interval_list_heap, out);\n    fprintf(out, \"===\\nancestors\\n==\\n\");\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        fprintf(out, \"%lld:\\t\", (long long) j);\n        print_segment_chain(self->ancestor_map_head[j], out);\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"===\\nnode_id map (input->output)\\n==\\n\");\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        if (self->node_id_map[j] != TSK_NULL) {\n            fprintf(\n                out, \"%lld->%lld\\n\", (long long) j, (long long) self->node_id_map[j]);\n        }\n    }\n    fprintf(out, \"===\\nsegment queue\\n==\\n\");\n    for (j = 0; j < self->segment_queue_size; j++) {\n        u = &self->segment_queue[j];\n        fprintf(out, \"(%f,%f->%lld)\", u->left, u->right, (long long) u->node);\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"===\\nbuffered children\\n==\\n\");\n    for (j = 0; j < self->num_buffered_children; j++) {\n        child = self->buffered_children[j];\n        fprintf(out, \"%lld -> \", (long long) j);\n        for (int_list = self->child_edge_map_head[child]; int_list != NULL;\n             int_list = int_list->next) {\n            fprintf(out, \"(%f, %f), \", int_list->left, int_list->right);\n        }\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"===\\nmutation node map\\n==\\n\");\n    for (j = 0; j < self->input_tables.mutations.num_rows; j++) {\n        fprintf(out, \"%lld\\t-> %lld\\n\", (long long) j,\n            (long long) self->mutation_node_map[j]);\n    }\n    fprintf(out, \"===\\nnode mutation id list map\\n==\\n\");\n    for (j = 0; j < self->input_tables.nodes.num_rows; j++) {\n        if (self->node_mutation_list_map_head[j] != NULL) {\n            fprintf(out, \"%lld\\t-> [\", (long long) j);\n            for (list_node = self->node_mutation_list_map_head[j]; list_node != NULL;\n                 list_node = list_node->next) {\n                fprintf(out, \"%lld,\", (long long) list_node->mutation);\n            }\n            fprintf(out, \"]\\n\");\n        }\n    }\n    if (!!(self->options & TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY)) {\n        fprintf(out, \"===\\nposition_lookup\\n==\\n\");\n        for (j = 0; j < self->input_tables.sites.num_rows + 2; j++) {\n            fprintf(out, \"%lld\\t-> %f\\n\", (long long) j, self->position_lookup[j]);\n        }\n    }\n    simplifier_check_state(self);\n}\n\nstatic tsk_segment_t *TSK_WARN_UNUSED\nsimplifier_alloc_segment(simplifier_t *self, double left, double right, tsk_id_t node)\n{\n    tsk_segment_t *seg = NULL;\n\n    seg = tsk_blkalloc_get(&self->segment_heap, sizeof(*seg));\n    if (seg == NULL) {\n        goto out;\n    }\n    seg->next = NULL;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\nout:\n    return seg;\n}\n\nstatic interval_list_t *TSK_WARN_UNUSED\nsimplifier_alloc_interval_list(simplifier_t *self, double left, double right)\n{\n    interval_list_t *x = NULL;\n\n    x = tsk_blkalloc_get(&self->interval_list_heap, sizeof(*x));\n    if (x == NULL) {\n        goto out;\n    }\n    x->next = NULL;\n    x->left = left;\n    x->right = right;\nout:\n    return x;\n}\n\n/* Add a new node to the output node table corresponding to the specified input id.\n * Returns the new ID. */\nstatic tsk_id_t TSK_WARN_UNUSED\nsimplifier_record_node(simplifier_t *self, tsk_id_t input_id)\n{\n    tsk_node_t node;\n    bool update_flags = !(self->options & TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS);\n\n    tsk_node_table_get_row_unsafe(&self->input_tables.nodes, (tsk_id_t) input_id, &node);\n    if (update_flags) {\n        /* Zero out the sample bit */\n        node.flags &= (tsk_flags_t) ~TSK_NODE_IS_SAMPLE;\n        if (self->is_sample[input_id]) {\n            node.flags |= TSK_NODE_IS_SAMPLE;\n        }\n    }\n    self->node_id_map[input_id] = (tsk_id_t) self->tables->nodes.num_rows;\n    return tsk_node_table_add_row(&self->tables->nodes, node.flags, node.time,\n        node.population, node.individual, node.metadata, node.metadata_length);\n}\n\n/* Remove the mapping for the last recorded node. */\nstatic int\nsimplifier_rewind_node(simplifier_t *self, tsk_id_t input_id, tsk_id_t output_id)\n{\n    self->node_id_map[input_id] = TSK_NULL;\n    return tsk_node_table_truncate(&self->tables->nodes, (tsk_size_t) output_id);\n}\n\nstatic int\nsimplifier_flush_edges(simplifier_t *self, tsk_id_t parent, tsk_size_t *ret_num_edges)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_id_t child;\n    interval_list_t *x;\n    tsk_size_t num_edges = 0;\n\n    qsort(self->buffered_children, (size_t) self->num_buffered_children,\n        sizeof(tsk_id_t), cmp_node_id);\n    for (j = 0; j < self->num_buffered_children; j++) {\n        child = self->buffered_children[j];\n        for (x = self->child_edge_map_head[child]; x != NULL; x = x->next) {\n            ret_id = tsk_edge_table_add_row(\n                &self->tables->edges, x->left, x->right, parent, child, NULL, 0);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            num_edges++;\n        }\n        self->child_edge_map_head[child] = NULL;\n        self->child_edge_map_tail[child] = NULL;\n    }\n    self->num_buffered_children = 0;\n    *ret_num_edges = num_edges;\n    ret = tsk_blkalloc_reset(&self->interval_list_heap);\nout:\n    return ret;\n}\n\n/* When we are reducing topology down to what is visible at the sites we need a\n * lookup table to find the closest site position for each edge. We do this with\n * a sorted array and binary search */\nstatic int\nsimplifier_init_position_lookup(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_size_t num_sites = self->input_tables.sites.num_rows;\n\n    self->position_lookup = tsk_malloc((num_sites + 2) * sizeof(*self->position_lookup));\n    if (self->position_lookup == NULL) {\n        goto out;\n    }\n    self->position_lookup[0] = 0;\n    self->position_lookup[num_sites + 1] = self->input_tables.sequence_length;\n    tsk_memcpy(self->position_lookup + 1, self->input_tables.sites.position,\n        num_sites * sizeof(double));\nout:\n    return ret;\n}\n/*\n * Find the smallest site position index greater than or equal to left\n * and right, i.e., slide each endpoint of an interval to the right\n * until they hit a site position. If both left and right map to the\n * the same position then we discard this edge. We also discard an\n * edge if left = 0 and right is less than the first site position.\n */\nstatic bool\nsimplifier_map_reduced_coordinates(simplifier_t *self, double *left, double *right)\n{\n    double *X = self->position_lookup;\n    tsk_size_t N = self->input_tables.sites.num_rows + 2;\n    tsk_size_t left_index, right_index;\n    bool skip = false;\n\n    left_index = tsk_search_sorted(X, N, *left);\n    right_index = tsk_search_sorted(X, N, *right);\n    if (left_index == right_index || (left_index == 0 && right_index == 1)) {\n        skip = true;\n    } else {\n        /* Remap back to zero if the left end maps to the first site. */\n        if (left_index == 1) {\n            left_index = 0;\n        }\n        *left = X[left_index];\n        *right = X[right_index];\n    }\n    return skip;\n}\n\n/* Records the specified edge for the current parent by buffering it */\nstatic int\nsimplifier_record_edge(simplifier_t *self, double left, double right, tsk_id_t child)\n{\n    int ret = 0;\n    interval_list_t *tail, *x;\n    bool skip;\n\n    if (self->options & TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY) {\n        skip = simplifier_map_reduced_coordinates(self, &left, &right);\n        /* NOTE: we exit early here when reduce_coordindates has told us to\n         * skip this edge, as it is not visible in the reduced tree sequence */\n        if (skip) {\n            goto out;\n        }\n    }\n\n    tail = self->child_edge_map_tail[child];\n    if (tail == NULL) {\n        tsk_bug_assert(self->num_buffered_children < self->input_tables.nodes.num_rows);\n        self->buffered_children[self->num_buffered_children] = child;\n        self->num_buffered_children++;\n        x = simplifier_alloc_interval_list(self, left, right);\n        if (x == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->child_edge_map_head[child] = x;\n        self->child_edge_map_tail[child] = x;\n    } else {\n        if (tail->right == left) {\n            tail->right = right;\n        } else {\n            x = simplifier_alloc_interval_list(self, left, right);\n            if (x == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            tail->next = x;\n            self->child_edge_map_tail[child] = x;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\nsimplifier_init_sites(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_id_t node;\n    mutation_id_list_t *list_node;\n    tsk_size_t j;\n\n    self->mutation_node_map\n        = tsk_calloc(self->input_tables.mutations.num_rows, sizeof(tsk_id_t));\n    self->node_mutation_list_mem\n        = tsk_malloc(self->input_tables.mutations.num_rows * sizeof(mutation_id_list_t));\n    self->node_mutation_list_map_head\n        = tsk_calloc(self->input_tables.nodes.num_rows, sizeof(mutation_id_list_t *));\n    self->node_mutation_list_map_tail\n        = tsk_calloc(self->input_tables.nodes.num_rows, sizeof(mutation_id_list_t *));\n    if (self->mutation_node_map == NULL || self->node_mutation_list_mem == NULL\n        || self->node_mutation_list_map_head == NULL\n        || self->node_mutation_list_map_tail == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(self->mutation_node_map, 0xff,\n        self->input_tables.mutations.num_rows * sizeof(tsk_id_t));\n\n    for (j = 0; j < self->input_tables.mutations.num_rows; j++) {\n        node = self->input_tables.mutations.node[j];\n        list_node = self->node_mutation_list_mem + j;\n        list_node->mutation = (tsk_id_t) j;\n        list_node->next = NULL;\n        if (self->node_mutation_list_map_head[node] == NULL) {\n            self->node_mutation_list_map_head[node] = list_node;\n        } else {\n            self->node_mutation_list_map_tail[node]->next = list_node;\n        }\n        self->node_mutation_list_map_tail[node] = list_node;\n    }\nout:\n    return ret;\n}\n\nstatic void\nsimplifier_map_mutations(\n    simplifier_t *self, tsk_id_t input_id, double left, double right, tsk_id_t output_id)\n{\n    mutation_id_list_t *m_node;\n    double position;\n    tsk_id_t site;\n\n    m_node = self->node_mutation_list_map_head[input_id];\n    while (m_node != NULL) {\n        site = self->input_tables.mutations.site[m_node->mutation];\n        position = self->input_tables.sites.position[site];\n        if (left <= position && position < right) {\n            self->mutation_node_map[m_node->mutation] = output_id;\n        }\n        m_node = m_node->next;\n    }\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_add_ancestry(\n    simplifier_t *self, tsk_id_t input_id, double left, double right, tsk_id_t output_id)\n{\n    int ret = 0;\n    tsk_segment_t *tail = self->ancestor_map_tail[input_id];\n    tsk_segment_t *x;\n\n    tsk_bug_assert(left < right);\n    if (tail == NULL) {\n        x = simplifier_alloc_segment(self, left, right, output_id);\n        if (x == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->ancestor_map_head[input_id] = x;\n        self->ancestor_map_tail[input_id] = x;\n    } else {\n        if (tail->right == left && tail->node == output_id) {\n            tail->right = right;\n        } else {\n            x = simplifier_alloc_segment(self, left, right, output_id);\n            if (x == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            tail->next = x;\n            self->ancestor_map_tail[input_id] = x;\n        }\n    }\n    simplifier_map_mutations(self, input_id, left, right, output_id);\nout:\n    return ret;\n}\n\n/* Sets up the internal working copies of the various tables, as needed\n * depending on the specified options. */\nstatic int\nsimplifier_init_tables(simplifier_t *self)\n{\n    int ret;\n    bool filter_nodes = !(self->options & TSK_SIMPLIFY_NO_FILTER_NODES);\n    bool filter_populations = self->options & TSK_SIMPLIFY_FILTER_POPULATIONS;\n    bool filter_individuals = self->options & TSK_SIMPLIFY_FILTER_INDIVIDUALS;\n    bool filter_sites = self->options & TSK_SIMPLIFY_FILTER_SITES;\n    tsk_bookmark_t rows_to_retain;\n\n    /* NOTE: this is a bit inefficient here as we're taking copies of\n     * the tables even in the no-filter case where the original tables\n     * won't be touched (beyond references to external tables that may\n     * need updating). Future versions may do something a bit more\n     * complicated like temporarily stealing the pointers to the\n     * underlying column memory in these tables, and then being careful\n     * not to free the table at the end.\n     */\n    ret = tsk_table_collection_copy(self->tables, &self->input_tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    memset(&rows_to_retain, 0, sizeof(rows_to_retain));\n    rows_to_retain.provenances = self->tables->provenances.num_rows;\n    if (!filter_nodes) {\n        rows_to_retain.nodes = self->tables->nodes.num_rows;\n    }\n    if (!filter_populations) {\n        rows_to_retain.populations = self->tables->populations.num_rows;\n    }\n    if (!filter_individuals) {\n        rows_to_retain.individuals = self->tables->individuals.num_rows;\n    }\n    if (!filter_sites) {\n        rows_to_retain.sites = self->tables->sites.num_rows;\n    }\n\n    ret = tsk_table_collection_truncate(self->tables, &rows_to_retain);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nsimplifier_init_nodes(simplifier_t *self, const tsk_id_t *samples)\n{\n    int ret = 0;\n    tsk_id_t node_id;\n    tsk_size_t j;\n    const tsk_size_t num_nodes = self->input_tables.nodes.num_rows;\n    bool filter_nodes = !(self->options & TSK_SIMPLIFY_NO_FILTER_NODES);\n    bool update_flags = !(self->options & TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS);\n    tsk_flags_t *node_flags = self->tables->nodes.flags;\n    tsk_id_t *node_id_map = self->node_id_map;\n\n    if (filter_nodes) {\n        tsk_bug_assert(self->tables->nodes.num_rows == 0);\n        /* The node table has been cleared. Add nodes for the samples. */\n        for (j = 0; j < self->num_samples; j++) {\n            node_id = simplifier_record_node(self, samples[j]);\n            if (node_id < 0) {\n                ret = (int) node_id;\n                goto out;\n            }\n        }\n    } else {\n        tsk_bug_assert(self->tables->nodes.num_rows == num_nodes);\n        if (update_flags) {\n            for (j = 0; j < num_nodes; j++) {\n                /* Reset the sample flags */\n                node_flags[j] &= (tsk_flags_t) ~TSK_NODE_IS_SAMPLE;\n                if (self->is_sample[j]) {\n                    node_flags[j] |= TSK_NODE_IS_SAMPLE;\n                }\n            }\n        }\n\n        for (j = 0; j < num_nodes; j++) {\n            node_id_map[j] = (tsk_id_t) j;\n        }\n    }\n    /* Add the initial ancestry */\n    for (j = 0; j < self->num_samples; j++) {\n        node_id = samples[j];\n        ret = simplifier_add_ancestry(self, node_id, 0,\n            self->input_tables.sequence_length, self->node_id_map[node_id]);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\nsimplifier_init(simplifier_t *self, const tsk_id_t *samples, tsk_size_t num_samples,\n    tsk_table_collection_t *tables, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t ret_id;\n    tsk_size_t num_nodes;\n\n    tsk_memset(self, 0, sizeof(simplifier_t));\n    self->num_samples = num_samples;\n    self->options = options;\n    self->tables = tables;\n\n    /* TODO we can add a flag to skip these checks for when we know they are\n     * unnecessary */\n    /* TODO Current unit tests require TSK_CHECK_SITE_DUPLICATES but it's\n     * debateable whether we need it. If we remove, we definitely need explicit\n     * tests to ensure we're doing sensible things with duplicate sites.\n     * (Particularly, re TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY.) */\n    ret_id = tsk_table_collection_check_integrity(tables,\n        TSK_CHECK_EDGE_ORDERING | TSK_CHECK_SITE_ORDERING | TSK_CHECK_SITE_DUPLICATES);\n    if (ret_id != 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n\n    /* Allocate the heaps used for small objects-> Assuming 8K is a good chunk size\n     */\n    ret = tsk_blkalloc_init(&self->segment_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_blkalloc_init(&self->interval_list_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = segment_overlapper_alloc(&self->segment_overlapper);\n    if (ret != 0) {\n        goto out;\n    }\n    num_nodes = tables->nodes.num_rows;\n    /* Make the maps and set the intial state */\n    self->ancestor_map_head = tsk_calloc(num_nodes, sizeof(tsk_segment_t *));\n    self->ancestor_map_tail = tsk_calloc(num_nodes, sizeof(tsk_segment_t *));\n    self->child_edge_map_head = tsk_calloc(num_nodes, sizeof(interval_list_t *));\n    self->child_edge_map_tail = tsk_calloc(num_nodes, sizeof(interval_list_t *));\n    self->node_id_map = tsk_malloc(num_nodes * sizeof(tsk_id_t));\n    self->buffered_children = tsk_malloc(num_nodes * sizeof(tsk_id_t));\n    self->is_sample = tsk_calloc(num_nodes, sizeof(bool));\n    self->max_segment_queue_size = 64;\n    self->segment_queue\n        = tsk_malloc(self->max_segment_queue_size * sizeof(tsk_segment_t));\n    if (self->ancestor_map_head == NULL || self->ancestor_map_tail == NULL\n        || self->child_edge_map_head == NULL || self->child_edge_map_tail == NULL\n        || self->node_id_map == NULL || self->is_sample == NULL\n        || self->segment_queue == NULL || self->buffered_children == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* Go through the samples to check for errors before we clear the tables. */\n    for (j = 0; j < self->num_samples; j++) {\n        if (samples[j] < 0 || samples[j] >= (tsk_id_t) num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (self->is_sample[samples[j]]) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        self->is_sample[samples[j]] = true;\n    }\n    tsk_memset(self->node_id_map, 0xff, num_nodes * sizeof(tsk_id_t));\n\n    ret = simplifier_init_tables(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = simplifier_init_sites(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = simplifier_init_nodes(self, samples);\n    if (ret != 0) {\n        goto out;\n    }\n    if (self->options & TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY) {\n        ret = simplifier_init_position_lookup(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    self->edge_sort_offset = TSK_NULL;\nout:\n    return ret;\n}\n\nstatic int\nsimplifier_free(simplifier_t *self)\n{\n    tsk_table_collection_free(&self->input_tables);\n    tsk_blkalloc_free(&self->segment_heap);\n    tsk_blkalloc_free(&self->interval_list_heap);\n    segment_overlapper_free(&self->segment_overlapper);\n    tsk_safe_free(self->ancestor_map_head);\n    tsk_safe_free(self->ancestor_map_tail);\n    tsk_safe_free(self->child_edge_map_head);\n    tsk_safe_free(self->child_edge_map_tail);\n    tsk_safe_free(self->node_id_map);\n    tsk_safe_free(self->segment_queue);\n    tsk_safe_free(self->is_sample);\n    tsk_safe_free(self->mutation_node_map);\n    tsk_safe_free(self->node_mutation_list_mem);\n    tsk_safe_free(self->node_mutation_list_map_head);\n    tsk_safe_free(self->node_mutation_list_map_tail);\n    tsk_safe_free(self->buffered_children);\n    tsk_safe_free(self->position_lookup);\n    return 0;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_enqueue_segment(simplifier_t *self, double left, double right, tsk_id_t node)\n{\n    int ret = 0;\n    tsk_segment_t *seg;\n    void *p;\n\n    tsk_bug_assert(left < right);\n    /* Make sure we always have room for one more segment in the queue so we\n     * can put a tail sentinel on it */\n    if (self->segment_queue_size == self->max_segment_queue_size - 1) {\n        self->max_segment_queue_size *= 2;\n        p = tsk_realloc(self->segment_queue,\n            self->max_segment_queue_size * sizeof(*self->segment_queue));\n        if (p == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        self->segment_queue = p;\n    }\n    seg = self->segment_queue + self->segment_queue_size;\n    seg->left = left;\n    seg->right = right;\n    seg->node = node;\n    self->segment_queue_size++;\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_merge_ancestors(simplifier_t *self, tsk_id_t input_id)\n{\n    int ret = 0;\n    tsk_segment_t **X, *x;\n    tsk_size_t j, num_overlapping, num_flushed_edges;\n    double left, right, prev_right;\n    tsk_id_t ancestry_node;\n    tsk_id_t output_id = self->node_id_map[input_id];\n    bool is_sample = self->is_sample[input_id];\n    bool filter_nodes = !(self->options & TSK_SIMPLIFY_NO_FILTER_NODES);\n    bool keep_unary = self->options & TSK_SIMPLIFY_KEEP_UNARY;\n\n    if ((self->options & TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS)\n        && (self->input_tables.nodes.individual[input_id] != TSK_NULL)) {\n        keep_unary = true;\n    }\n\n    if (is_sample) {\n        /* Free up the existing ancestry mapping. */\n        x = self->ancestor_map_tail[input_id];\n        tsk_bug_assert(x->left == 0 && x->right == self->tables->sequence_length);\n        self->ancestor_map_head[input_id] = NULL;\n        self->ancestor_map_tail[input_id] = NULL;\n    }\n\n    ret = segment_overlapper_start(\n        &self->segment_overlapper, self->segment_queue, self->segment_queue_size);\n    if (ret != 0) {\n        goto out;\n    }\n    prev_right = 0;\n    while ((ret = segment_overlapper_next(\n                &self->segment_overlapper, &left, &right, &X, &num_overlapping))\n           == 1) {\n        tsk_bug_assert(left < right);\n        tsk_bug_assert(num_overlapping > 0);\n        if (num_overlapping == 1) {\n            ancestry_node = X[0]->node;\n            if (is_sample) {\n                ret = simplifier_record_edge(self, left, right, ancestry_node);\n                if (ret != 0) {\n                    goto out;\n                }\n                ancestry_node = output_id;\n            } else if (keep_unary) {\n                if (output_id == TSK_NULL) {\n                    output_id = simplifier_record_node(self, input_id);\n                }\n                ret = simplifier_record_edge(self, left, right, ancestry_node);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        } else {\n            if (output_id == TSK_NULL) {\n                output_id = simplifier_record_node(self, input_id);\n                if (output_id < 0) {\n                    ret = (int) output_id;\n                    goto out;\n                }\n            }\n            ancestry_node = output_id;\n            for (j = 0; j < num_overlapping; j++) {\n                ret = simplifier_record_edge(self, left, right, X[j]->node);\n                if (ret != 0) {\n                    goto out;\n                }\n            }\n        }\n        if (is_sample && left != prev_right) {\n            /* Fill in any gaps in ancestry for the sample */\n            ret = simplifier_add_ancestry(self, input_id, prev_right, left, output_id);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n        if (keep_unary) {\n            ancestry_node = output_id;\n        }\n        ret = simplifier_add_ancestry(self, input_id, left, right, ancestry_node);\n        if (ret != 0) {\n            goto out;\n        }\n        prev_right = right;\n    }\n    /* Check for errors occuring in the loop condition */\n    if (ret != 0) {\n        goto out;\n    }\n    if (is_sample && prev_right != self->tables->sequence_length) {\n        /* If a trailing gap exists in the sample ancestry, fill it in. */\n        ret = simplifier_add_ancestry(\n            self, input_id, prev_right, self->tables->sequence_length, output_id);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (output_id != TSK_NULL) {\n        ret = simplifier_flush_edges(self, output_id, &num_flushed_edges);\n        if (ret != 0) {\n            goto out;\n        }\n        if (filter_nodes && (num_flushed_edges == 0) && !is_sample) {\n            ret = simplifier_rewind_node(self, input_id, output_id);\n        }\n    }\nout:\n    return ret;\n}\n\n/* Extract the ancestry for the specified input node over the specified\n * interval and queue it up for merging.\n */\nstatic int TSK_WARN_UNUSED\nsimplifier_extract_ancestry(\n    simplifier_t *self, double left, double right, tsk_id_t input_id)\n{\n    int ret = 0;\n    tsk_segment_t *x = self->ancestor_map_head[input_id];\n    tsk_segment_t y; /* y is the segment that has been removed */\n    tsk_segment_t *x_head, *x_prev, *seg_left, *seg_right;\n\n    x_head = NULL;\n    x_prev = NULL;\n    while (x != NULL) {\n        if (x->right > left && right > x->left) {\n            y.left = TSK_MAX(x->left, left);\n            y.right = TSK_MIN(x->right, right);\n            y.node = x->node;\n            ret = simplifier_enqueue_segment(self, y.left, y.right, y.node);\n            if (ret != 0) {\n                goto out;\n            }\n            seg_left = NULL;\n            seg_right = NULL;\n            if (x->left != y.left) {\n                seg_left = simplifier_alloc_segment(self, x->left, y.left, x->node);\n                if (seg_left == NULL) {\n                    ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                    goto out;\n                }\n                if (x_prev == NULL) {\n                    x_head = seg_left;\n                } else {\n                    x_prev->next = seg_left;\n                }\n                x_prev = seg_left;\n            }\n            if (x->right != y.right) {\n                x->left = y.right;\n                seg_right = x;\n            } else {\n                seg_right = x->next;\n                // TODO free x\n            }\n            if (x_prev == NULL) {\n                x_head = seg_right;\n            } else {\n                x_prev->next = seg_right;\n            }\n            x = seg_right;\n        } else {\n            if (x_prev == NULL) {\n                x_head = x;\n            }\n            x_prev = x;\n            x = x->next;\n        }\n    }\n\n    self->ancestor_map_head[input_id] = x_head;\n    self->ancestor_map_tail[input_id] = x_prev;\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_process_parent_edges(\n    simplifier_t *self, tsk_id_t parent, tsk_size_t start, tsk_size_t end)\n{\n    int ret = 0;\n    tsk_size_t j;\n    const tsk_edge_table_t *input_edges = &self->input_tables.edges;\n    tsk_id_t child;\n    double left, right;\n\n    /* Go through the edges and queue up ancestry segments for processing. */\n    self->segment_queue_size = 0;\n    for (j = start; j < end; j++) {\n        tsk_bug_assert(parent == input_edges->parent[j]);\n        child = input_edges->child[j];\n        left = input_edges->left[j];\n        right = input_edges->right[j];\n        ret = simplifier_extract_ancestry(self, left, right, child);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    /* We can now merge the ancestral segments for the parent */\n    ret = simplifier_merge_ancestors(self, parent);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_finalise_site_references(\n    simplifier_t *self, const bool *site_referenced, tsk_id_t *site_id_map)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_site_t site;\n    const tsk_size_t num_sites = self->input_tables.sites.num_rows;\n\n    if (self->options & TSK_SIMPLIFY_FILTER_SITES) {\n        for (j = 0; j < num_sites; j++) {\n            tsk_site_table_get_row_unsafe(\n                &self->input_tables.sites, (tsk_id_t) j, &site);\n            site_id_map[j] = TSK_NULL;\n            if (site_referenced[j]) {\n                ret_id = tsk_site_table_add_row(&self->tables->sites, site.position,\n                    site.ancestral_state, site.ancestral_state_length, site.metadata,\n                    site.metadata_length);\n                if (ret_id < 0) {\n                    ret = (int) ret_id;\n                    goto out;\n                }\n                site_id_map[j] = ret_id;\n            }\n        }\n    } else {\n        tsk_bug_assert(self->tables->sites.num_rows == num_sites);\n        for (j = 0; j < num_sites; j++) {\n            site_id_map[j] = (tsk_id_t) j;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_finalise_population_references(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t pop_id, ret_id;\n    tsk_population_t pop;\n    tsk_id_t *node_population = self->tables->nodes.population;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_size_t num_populations = self->input_tables.populations.num_rows;\n    bool *population_referenced\n        = tsk_calloc(num_populations, sizeof(*population_referenced));\n    tsk_id_t *population_id_map\n        = tsk_malloc(num_populations * sizeof(*population_id_map));\n\n    tsk_bug_assert(self->options & TSK_SIMPLIFY_FILTER_POPULATIONS);\n\n    if (population_referenced == NULL || population_id_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (j = 0; j < num_nodes; j++) {\n        pop_id = node_population[j];\n        if (pop_id != TSK_NULL) {\n            population_referenced[pop_id] = true;\n        }\n    }\n\n    for (j = 0; j < num_populations; j++) {\n        tsk_population_table_get_row_unsafe(\n            &self->input_tables.populations, (tsk_id_t) j, &pop);\n        population_id_map[j] = TSK_NULL;\n        if (population_referenced[j]) {\n            ret_id = tsk_population_table_add_row(\n                &self->tables->populations, pop.metadata, pop.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            population_id_map[j] = ret_id;\n        }\n    }\n\n    /* Remap the IDs in the node table */\n    for (j = 0; j < num_nodes; j++) {\n        pop_id = node_population[j];\n        if (pop_id != TSK_NULL) {\n            node_population[j] = population_id_map[pop_id];\n        }\n    }\nout:\n    tsk_safe_free(population_id_map);\n    tsk_safe_free(population_referenced);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_finalise_individual_references(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t pop_id, ret_id;\n    tsk_individual_t ind;\n    tsk_id_t *node_individual = self->tables->nodes.individual;\n    tsk_id_t *parents;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_size_t num_individuals = self->input_tables.individuals.num_rows;\n    bool *individual_referenced\n        = tsk_calloc(num_individuals, sizeof(*individual_referenced));\n    tsk_id_t *individual_id_map\n        = tsk_malloc(num_individuals * sizeof(*individual_id_map));\n\n    tsk_bug_assert(self->options & TSK_SIMPLIFY_FILTER_INDIVIDUALS);\n\n    if (individual_referenced == NULL || individual_id_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (j = 0; j < num_nodes; j++) {\n        pop_id = node_individual[j];\n        if (pop_id != TSK_NULL) {\n            individual_referenced[pop_id] = true;\n        }\n    }\n\n    for (j = 0; j < num_individuals; j++) {\n        tsk_individual_table_get_row_unsafe(\n            &self->input_tables.individuals, (tsk_id_t) j, &ind);\n        individual_id_map[j] = TSK_NULL;\n        if (individual_referenced[j]) {\n            /* Can't remap the parents inline here because we have no\n             * guarantees about sortedness */\n            ret_id = tsk_individual_table_add_row(&self->tables->individuals, ind.flags,\n                ind.location, ind.location_length, ind.parents, ind.parents_length,\n                ind.metadata, ind.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            individual_id_map[j] = ret_id;\n        }\n    }\n\n    /* Remap the IDs in the node table */\n    for (j = 0; j < num_nodes; j++) {\n        pop_id = node_individual[j];\n        if (pop_id != TSK_NULL) {\n            node_individual[j] = individual_id_map[pop_id];\n        }\n    }\n\n    /* Remap parent IDs. *\n     * NOTE! must take the pointer reference here as it can change from\n     * the start of the function */\n    parents = self->tables->individuals.parents;\n    for (j = 0; j < self->tables->individuals.parents_length; j++) {\n        if (parents[j] != TSK_NULL) {\n            parents[j] = individual_id_map[parents[j]];\n        }\n    }\n\nout:\n    tsk_safe_free(individual_id_map);\n    tsk_safe_free(individual_referenced);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_output_sites(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    tsk_mutation_t mutation;\n    const tsk_size_t num_sites = self->input_tables.sites.num_rows;\n    const tsk_size_t num_mutations = self->input_tables.mutations.num_rows;\n    bool *site_referenced = tsk_calloc(num_sites, sizeof(*site_referenced));\n    tsk_id_t *site_id_map = tsk_malloc(num_sites * sizeof(*site_id_map));\n    tsk_id_t *mutation_id_map = tsk_malloc(num_mutations * sizeof(*mutation_id_map));\n    const tsk_id_t *mutation_node_map = self->mutation_node_map;\n    const tsk_id_t *mutation_site = self->input_tables.mutations.site;\n\n    if (site_referenced == NULL || site_id_map == NULL || mutation_id_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (j = 0; j < num_mutations; j++) {\n        if (mutation_node_map[j] != TSK_NULL) {\n            site_referenced[mutation_site[j]] = true;\n        }\n    }\n    ret = simplifier_finalise_site_references(self, site_referenced, site_id_map);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (j = 0; j < num_mutations; j++) {\n        mutation_id_map[j] = TSK_NULL;\n        if (mutation_node_map[j] != TSK_NULL) {\n            tsk_mutation_table_get_row_unsafe(\n                &self->input_tables.mutations, (tsk_id_t) j, &mutation);\n            mutation.node = mutation_node_map[j];\n            mutation.site = site_id_map[mutation.site];\n            if (mutation.parent != TSK_NULL) {\n                mutation.parent = mutation_id_map[mutation.parent];\n            }\n            ret_id = tsk_mutation_table_add_row(&self->tables->mutations, mutation.site,\n                mutation.node, mutation.parent, mutation.time, mutation.derived_state,\n                mutation.derived_state_length, mutation.metadata,\n                mutation.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            mutation_id_map[j] = ret_id;\n        }\n    }\nout:\n    tsk_safe_free(site_referenced);\n    tsk_safe_free(site_id_map);\n    tsk_safe_free(mutation_id_map);\n    return ret;\n}\n\n/* Flush the remaining non-edge and node data in the model to the\n * output tables. */\nstatic int TSK_WARN_UNUSED\nsimplifier_flush_output(simplifier_t *self)\n{\n    int ret = 0;\n\n    /* TODO Migrations fit reasonably neatly into the pattern that we have here. We\n     * can consider references to populations from migration objects in the same way\n     * as from nodes, so that we only remove a population if its referenced by\n     * neither. Mapping the population IDs in migrations is then easy. In principle\n     * nodes are similar, but the semantics are slightly different because we've\n     * already allocated all the nodes by their references from edges. We then\n     * need to decide whether we remove migrations that reference unmapped nodes\n     * or whether to add these nodes back in (probably the former is the correct\n     * approach).*/\n    if (self->input_tables.migrations.num_rows != 0) {\n        ret = tsk_trace_error(TSK_ERR_SIMPLIFY_MIGRATIONS_NOT_SUPPORTED);\n        goto out;\n    }\n\n    ret = simplifier_output_sites(self);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (self->options & TSK_SIMPLIFY_FILTER_POPULATIONS) {\n        ret = simplifier_finalise_population_references(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (self->options & TSK_SIMPLIFY_FILTER_INDIVIDUALS) {\n        ret = simplifier_finalise_individual_references(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\nout:\n    return ret;\n}\n\nstatic void\nsimplifier_set_edge_sort_offset(simplifier_t *self, double youngest_root_time)\n{\n    const tsk_edge_table_t edges = self->tables->edges;\n    const double *node_time = self->tables->nodes.time;\n    int64_t offset;\n\n    for (offset = 0; offset < (int64_t) edges.num_rows; offset++) {\n        if (node_time[edges.parent[offset]] >= youngest_root_time) {\n            break;\n        }\n    }\n    self->edge_sort_offset = offset;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_sort_edges(simplifier_t *self)\n{\n    /* designated initialisers are guaranteed to set any missing fields to\n     * zero, so we don't need to set the rest of them. */\n    tsk_bookmark_t bookmark = {\n        .edges = (tsk_size_t) self->edge_sort_offset,\n        .sites = self->tables->sites.num_rows,\n        .mutations = self->tables->mutations.num_rows,\n    };\n    tsk_bug_assert(self->edge_sort_offset >= 0);\n    return tsk_table_collection_sort(self->tables, &bookmark, 0);\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_insert_input_roots(simplifier_t *self)\n{\n    int ret = 0;\n    tsk_id_t input_id, output_id;\n    tsk_segment_t *x;\n    tsk_size_t num_flushed_edges;\n    double youngest_root_time = DBL_MAX;\n    const double *node_time = self->tables->nodes.time;\n\n    for (input_id = 0; input_id < (tsk_id_t) self->input_tables.nodes.num_rows;\n         input_id++) {\n        x = self->ancestor_map_head[input_id];\n        if (x != NULL) {\n            output_id = self->node_id_map[input_id];\n            if (output_id == TSK_NULL) {\n                output_id = simplifier_record_node(self, input_id);\n                if (output_id < 0) {\n                    ret = (int) output_id;\n                    goto out;\n                }\n            }\n            youngest_root_time = TSK_MIN(youngest_root_time, node_time[output_id]);\n            while (x != NULL) {\n                if (x->node != output_id) {\n                    ret = simplifier_record_edge(self, x->left, x->right, x->node);\n                    if (ret != 0) {\n                        goto out;\n                    }\n                    simplifier_map_mutations(\n                        self, input_id, x->left, x->right, output_id);\n                }\n                x = x->next;\n            }\n            ret = simplifier_flush_edges(self, output_id, &num_flushed_edges);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\n    if (youngest_root_time != DBL_MAX) {\n        simplifier_set_edge_sort_offset(self, youngest_root_time);\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\nsimplifier_run(simplifier_t *self, tsk_id_t *node_map)\n{\n    int ret = 0;\n    tsk_size_t j, start;\n    tsk_id_t parent, current_parent;\n    const tsk_edge_table_t *input_edges = &self->input_tables.edges;\n    tsk_size_t num_edges = input_edges->num_rows;\n\n    if (num_edges > 0) {\n        start = 0;\n        current_parent = input_edges->parent[0];\n        for (j = 0; j < num_edges; j++) {\n            parent = input_edges->parent[j];\n            if (parent != current_parent) {\n                ret = simplifier_process_parent_edges(self, current_parent, start, j);\n                if (ret != 0) {\n                    goto out;\n                }\n                current_parent = parent;\n                start = j;\n            }\n        }\n        ret = simplifier_process_parent_edges(self, current_parent, start, num_edges);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (self->options & TSK_SIMPLIFY_KEEP_INPUT_ROOTS) {\n        ret = simplifier_insert_input_roots(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = simplifier_flush_output(self);\n    if (ret != 0) {\n        goto out;\n    }\n    if (node_map != NULL) {\n        /* Finally, output the new IDs for the nodes, if required. */\n        tsk_memcpy(node_map, self->node_id_map,\n            self->input_tables.nodes.num_rows * sizeof(tsk_id_t));\n    }\n    if (self->edge_sort_offset != TSK_NULL) {\n        tsk_bug_assert(self->options & TSK_SIMPLIFY_KEEP_INPUT_ROOTS);\n        ret = simplifier_sort_edges(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\n/*************************\n * table_collection\n *************************/\n\ntypedef struct {\n    tsk_id_t index;\n    /* These are the sort keys in order */\n    double first;\n    double second;\n    tsk_id_t third;\n    tsk_id_t fourth;\n} index_sort_t;\n\nstatic int\ncmp_index_sort(const void *a, const void *b)\n{\n    const index_sort_t *ca = (const index_sort_t *) a;\n    const index_sort_t *cb = (const index_sort_t *) b;\n    int ret = (ca->first > cb->first) - (ca->first < cb->first);\n    if (ret == 0) {\n        ret = (ca->second > cb->second) - (ca->second < cb->second);\n        if (ret == 0) {\n            ret = (ca->third > cb->third) - (ca->third < cb->third);\n            if (ret == 0) {\n                ret = (ca->fourth > cb->fourth) - (ca->fourth < cb->fourth);\n            }\n        }\n    }\n    return ret;\n}\n\nstatic int\ntsk_table_collection_check_offsets(const tsk_table_collection_t *self)\n{\n    int ret = 0;\n\n    ret = check_offsets(self->nodes.num_rows, self->nodes.metadata_offset,\n        self->nodes.metadata_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->sites.num_rows, self->sites.ancestral_state_offset,\n        self->sites.ancestral_state_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->sites.num_rows, self->sites.metadata_offset,\n        self->sites.metadata_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->mutations.num_rows, self->mutations.derived_state_offset,\n        self->mutations.derived_state_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->mutations.num_rows, self->mutations.metadata_offset,\n        self->mutations.metadata_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->individuals.num_rows, self->individuals.metadata_offset,\n        self->individuals.metadata_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->provenances.num_rows, self->provenances.timestamp_offset,\n        self->provenances.timestamp_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_offsets(self->provenances.num_rows, self->provenances.record_offset,\n        self->provenances.record_length, true);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ntsk_table_collection_check_node_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    double node_time;\n    tsk_id_t population, individual;\n    tsk_id_t num_populations = (tsk_id_t) self->populations.num_rows;\n    tsk_id_t num_individuals = (tsk_id_t) self->individuals.num_rows;\n    const bool check_population_refs = !(options & TSK_NO_CHECK_POPULATION_REFS);\n\n    for (j = 0; j < self->nodes.num_rows; j++) {\n        node_time = self->nodes.time[j];\n        if (!tsk_isfinite(node_time)) {\n            ret = tsk_trace_error(TSK_ERR_TIME_NONFINITE);\n            goto out;\n        }\n        if (check_population_refs) {\n            population = self->nodes.population[j];\n            if (population < TSK_NULL || population >= num_populations) {\n                ret = tsk_trace_error(TSK_ERR_POPULATION_OUT_OF_BOUNDS);\n                goto out;\n            }\n        }\n        individual = self->nodes.individual[j];\n        if (individual < TSK_NULL || individual >= num_individuals) {\n            ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_table_collection_check_edge_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t parent, last_parent, child, last_child;\n    double left, last_left, right;\n    const double *time = self->nodes.time;\n    const double L = self->sequence_length;\n    const tsk_edge_table_t edges = self->edges;\n    const tsk_id_t num_nodes = (tsk_id_t) self->nodes.num_rows;\n    const bool check_ordering = !!(options & TSK_CHECK_EDGE_ORDERING);\n    bool *parent_seen = NULL;\n\n    if (check_ordering) {\n        parent_seen = tsk_calloc((tsk_size_t) num_nodes, sizeof(*parent_seen));\n        if (parent_seen == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    /* Just keeping compiler happy; these values don't matter. */\n    last_left = 0;\n    last_parent = 0;\n    last_child = 0;\n    for (j = 0; j < edges.num_rows; j++) {\n        parent = edges.parent[j];\n        child = edges.child[j];\n        left = edges.left[j];\n        right = edges.right[j];\n        /* Node ID integrity */\n        if (parent == TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_NULL_PARENT);\n            goto out;\n        }\n        if (parent < 0 || parent >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (child == TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_NULL_CHILD);\n            goto out;\n        }\n        if (child < 0 || child >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        /* Spatial requirements for edges */\n        if (!(tsk_isfinite(left) && tsk_isfinite(right))) {\n            ret = tsk_trace_error(TSK_ERR_GENOME_COORDS_NONFINITE);\n            goto out;\n        }\n        if (left < 0) {\n            ret = tsk_trace_error(TSK_ERR_LEFT_LESS_ZERO);\n            goto out;\n        }\n        if (right > L) {\n            ret = tsk_trace_error(TSK_ERR_RIGHT_GREATER_SEQ_LENGTH);\n            goto out;\n        }\n        if (left >= right) {\n            ret = tsk_trace_error(TSK_ERR_BAD_EDGE_INTERVAL);\n            goto out;\n        }\n        /* time[child] must be < time[parent] */\n        if (time[child] >= time[parent]) {\n            ret = tsk_trace_error(TSK_ERR_BAD_NODE_TIME_ORDERING);\n            goto out;\n        }\n\n        if (check_ordering) {\n            if (parent_seen[parent]) {\n                ret = tsk_trace_error(TSK_ERR_EDGES_NONCONTIGUOUS_PARENTS);\n                goto out;\n            }\n            if (j > 0) {\n                /* Input data must sorted by (time[parent], parent, child, left). */\n                if (time[parent] < time[last_parent]) {\n                    ret = tsk_trace_error(TSK_ERR_EDGES_NOT_SORTED_PARENT_TIME);\n                    goto out;\n                }\n                if (time[parent] == time[last_parent]) {\n                    if (parent == last_parent) {\n                        if (child < last_child) {\n                            ret = tsk_trace_error(TSK_ERR_EDGES_NOT_SORTED_CHILD);\n                            goto out;\n                        }\n                        if (child == last_child) {\n                            if (left == last_left) {\n                                ret = tsk_trace_error(TSK_ERR_DUPLICATE_EDGES);\n                                goto out;\n                            } else if (left < last_left) {\n                                ret = tsk_trace_error(TSK_ERR_EDGES_NOT_SORTED_LEFT);\n                                goto out;\n                            }\n                        }\n                    } else {\n                        parent_seen[last_parent] = true;\n                    }\n                }\n            }\n            last_parent = parent;\n            last_child = child;\n            last_left = left;\n        }\n    }\nout:\n    tsk_safe_free(parent_seen);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_site_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    double position;\n    const double L = self->sequence_length;\n    const tsk_site_table_t sites = self->sites;\n    const bool check_site_ordering = !!(options & TSK_CHECK_SITE_ORDERING);\n    const bool check_site_duplicates = !!(options & TSK_CHECK_SITE_DUPLICATES);\n\n    for (j = 0; j < sites.num_rows; j++) {\n        position = sites.position[j];\n        /* Spatial requirements */\n        if (!tsk_isfinite(position)) {\n            ret = tsk_trace_error(TSK_ERR_BAD_SITE_POSITION);\n            goto out;\n        }\n        if (position < 0 || position >= L) {\n            ret = tsk_trace_error(TSK_ERR_BAD_SITE_POSITION);\n            goto out;\n        }\n        if (j > 0) {\n            if (check_site_duplicates && sites.position[j - 1] == position) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SITE_POSITION);\n                goto out;\n            }\n            if (check_site_ordering && sites.position[j - 1] > position) {\n                ret = tsk_trace_error(TSK_ERR_UNSORTED_SITES);\n                goto out;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_mutation_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t parent_mut;\n    double mutation_time;\n    double last_known_time = INFINITY;\n    const tsk_mutation_table_t mutations = self->mutations;\n    const tsk_id_t num_nodes = (tsk_id_t) self->nodes.num_rows;\n    const tsk_id_t num_sites = (tsk_id_t) self->sites.num_rows;\n    const tsk_id_t num_mutations = (tsk_id_t) self->mutations.num_rows;\n    const double *node_time = self->nodes.time;\n    const bool check_mutation_ordering = !!(options & TSK_CHECK_MUTATION_ORDERING);\n    bool unknown_time;\n    int num_known_times = 0;\n    int num_unknown_times = 0;\n\n    for (j = 0; j < mutations.num_rows; j++) {\n        /* Basic reference integrity */\n        if (mutations.site[j] < 0 || mutations.site[j] >= num_sites) {\n            ret = tsk_trace_error(TSK_ERR_SITE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (mutations.node[j] < 0 || mutations.node[j] >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        /* Integrity check for mutation parent */\n        parent_mut = mutations.parent[j];\n        if (parent_mut < TSK_NULL || parent_mut >= num_mutations) {\n            ret = tsk_trace_error(TSK_ERR_MUTATION_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (parent_mut == (tsk_id_t) j) {\n            ret = tsk_trace_error(TSK_ERR_MUTATION_PARENT_EQUAL);\n            goto out;\n        }\n        /* Check that time is finite and not more recent than node time */\n        mutation_time = mutations.time[j];\n        unknown_time = tsk_is_unknown_time(mutation_time);\n        if (!unknown_time) {\n            if (!tsk_isfinite(mutation_time)) {\n                ret = tsk_trace_error(TSK_ERR_TIME_NONFINITE);\n                goto out;\n            }\n            if (mutation_time < node_time[mutations.node[j]]) {\n                ret = tsk_trace_error(TSK_ERR_MUTATION_TIME_YOUNGER_THAN_NODE);\n                goto out;\n            }\n        }\n\n        /* reset checks when reaching a new site */\n        if (j > 0 && mutations.site[j - 1] != mutations.site[j]) {\n            last_known_time = INFINITY;\n            num_known_times = 0;\n            num_unknown_times = 0;\n        }\n\n        /* Check known/unknown times are not both present on a site */\n        if (unknown_time) {\n            num_unknown_times++;\n        } else {\n            num_known_times++;\n        }\n        if ((num_unknown_times > 0) && (num_known_times > 0)) {\n            ret = tsk_trace_error(TSK_ERR_MUTATION_TIME_HAS_BOTH_KNOWN_AND_UNKNOWN);\n            goto out;\n        }\n\n        /* check parent site agrees */\n        if (parent_mut != TSK_NULL) {\n            if (mutations.site[parent_mut] != mutations.site[j]) {\n                ret = tsk_trace_error(TSK_ERR_MUTATION_PARENT_DIFFERENT_SITE);\n                goto out;\n            }\n            /* If this mutation time is known, then the parent time\n             * must also be, or else the\n             * TSK_ERR_MUTATION_TIME_HAS_BOTH_KNOWN_AND_UNKNOWN check\n             * above will fail. */\n            if (!unknown_time && mutation_time > mutations.time[parent_mut]) {\n                ret = tsk_trace_error(TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_MUTATION);\n                goto out;\n            }\n        }\n\n        if (check_mutation_ordering) {\n            /* Check site ordering */\n            if (j > 0 && mutations.site[j - 1] > mutations.site[j]) {\n                ret = tsk_trace_error(TSK_ERR_UNSORTED_MUTATIONS);\n                goto out;\n            }\n\n            /* Check if parents are listed before their children */\n            if (parent_mut != TSK_NULL && parent_mut > (tsk_id_t) j) {\n                ret = tsk_trace_error(TSK_ERR_MUTATION_PARENT_AFTER_CHILD);\n                goto out;\n            }\n\n            /* Check time ordering. We do this after the other checks above,\n             * so that more specific errors trigger first */\n            if (!unknown_time) {\n                if (mutation_time > last_known_time) {\n                    ret = tsk_trace_error(TSK_ERR_UNSORTED_MUTATIONS);\n                    goto out;\n                }\n                last_known_time = mutation_time;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_migration_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n    double left, right, time;\n    const double L = self->sequence_length;\n    const tsk_migration_table_t migrations = self->migrations;\n    const tsk_id_t num_nodes = (tsk_id_t) self->nodes.num_rows;\n    const tsk_id_t num_populations = (tsk_id_t) self->populations.num_rows;\n    const bool check_population_refs = !(options & TSK_NO_CHECK_POPULATION_REFS);\n    const bool check_migration_ordering = !!(options & TSK_CHECK_MIGRATION_ORDERING);\n\n    for (j = 0; j < migrations.num_rows; j++) {\n        if (migrations.node[j] < 0 || migrations.node[j] >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (check_population_refs) {\n            if (migrations.source[j] < 0 || migrations.source[j] >= num_populations) {\n                ret = tsk_trace_error(TSK_ERR_POPULATION_OUT_OF_BOUNDS);\n                goto out;\n            }\n            if (migrations.dest[j] < 0 || migrations.dest[j] >= num_populations) {\n                ret = tsk_trace_error(TSK_ERR_POPULATION_OUT_OF_BOUNDS);\n                goto out;\n            }\n        }\n        time = migrations.time[j];\n        if (!tsk_isfinite(time)) {\n            ret = tsk_trace_error(TSK_ERR_TIME_NONFINITE);\n            goto out;\n        }\n        if (j > 0) {\n            if (check_migration_ordering && migrations.time[j - 1] > time) {\n                ret = tsk_trace_error(TSK_ERR_UNSORTED_MIGRATIONS);\n                goto out;\n            }\n        }\n        left = migrations.left[j];\n        right = migrations.right[j];\n        /* Spatial requirements */\n        /* TODO it's a bit misleading to use the edge-specific errors here. */\n        if (!(tsk_isfinite(left) && tsk_isfinite(right))) {\n            ret = tsk_trace_error(TSK_ERR_GENOME_COORDS_NONFINITE);\n            goto out;\n        }\n        if (left < 0) {\n            ret = tsk_trace_error(TSK_ERR_LEFT_LESS_ZERO);\n            goto out;\n        }\n        if (right > L) {\n            ret = tsk_trace_error(TSK_ERR_RIGHT_GREATER_SEQ_LENGTH);\n            goto out;\n        }\n        if (left >= right) {\n            ret = tsk_trace_error(TSK_ERR_BAD_EDGE_INTERVAL);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_individual_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j, k;\n    const tsk_individual_table_t individuals = self->individuals;\n    const tsk_id_t num_individuals = (tsk_id_t) individuals.num_rows;\n    const bool check_individual_ordering = options & TSK_CHECK_INDIVIDUAL_ORDERING;\n\n    for (j = 0; j < (tsk_size_t) num_individuals; j++) {\n        for (k = individuals.parents_offset[j]; k < individuals.parents_offset[j + 1];\n             k++) {\n            /* Check parent references are valid */\n            if (individuals.parents[k] != TSK_NULL\n                && (individuals.parents[k] < 0\n                       || individuals.parents[k] >= num_individuals)) {\n                ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_OUT_OF_BOUNDS);\n                goto out;\n            }\n            /* Check no-one is their own parent */\n            if (individuals.parents[k] == (tsk_id_t) j) {\n                ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_SELF_PARENT);\n                goto out;\n            }\n            /* Check parents are ordered */\n            if (check_individual_ordering && individuals.parents[k] != TSK_NULL\n                && individuals.parents[k] >= (tsk_id_t) j) {\n                ret = tsk_trace_error(TSK_ERR_UNSORTED_INDIVIDUALS);\n                goto out;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic tsk_id_t TSK_WARN_UNUSED\ntsk_table_collection_check_tree_integrity(const tsk_table_collection_t *self)\n{\n    tsk_id_t ret = 0;\n    tsk_size_t j, k;\n    tsk_id_t e, u, site, mutation;\n    double tree_left, tree_right;\n    const double sequence_length = self->sequence_length;\n    const tsk_id_t num_sites = (tsk_id_t) self->sites.num_rows;\n    const tsk_id_t num_mutations = (tsk_id_t) self->mutations.num_rows;\n    const tsk_size_t num_edges = self->edges.num_rows;\n    const double *restrict site_position = self->sites.position;\n    const tsk_id_t *restrict mutation_site = self->mutations.site;\n    const tsk_id_t *restrict mutation_node = self->mutations.node;\n    const double *restrict mutation_time = self->mutations.time;\n    const double *restrict node_time = self->nodes.time;\n    const tsk_id_t *restrict I = self->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->indexes.edge_removal_order;\n    const double *restrict edge_right = self->edges.right;\n    const double *restrict edge_left = self->edges.left;\n    const tsk_id_t *restrict edge_child = self->edges.child;\n    const tsk_id_t *restrict edge_parent = self->edges.parent;\n    tsk_id_t *restrict parent = NULL;\n    int8_t *restrict used_edges = NULL;\n    tsk_id_t num_trees = 0;\n\n    parent = tsk_malloc(self->nodes.num_rows * sizeof(*parent));\n    used_edges = tsk_malloc(num_edges * sizeof(*used_edges));\n    if (parent == NULL || used_edges == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, self->nodes.num_rows * sizeof(*parent));\n    tsk_memset(used_edges, 0, num_edges * sizeof(*used_edges));\n\n    tree_left = 0;\n    num_trees = 0;\n    j = 0;\n    k = 0;\n    site = 0;\n    mutation = 0;\n    tsk_bug_assert(I != NULL && O != NULL);\n    tsk_bug_assert(self->indexes.num_edges == num_edges);\n\n    while (j < num_edges || tree_left < sequence_length) {\n        while (k < num_edges && edge_right[O[k]] == tree_left) {\n            e = O[k];\n            if (used_edges[e] != 1) {\n                ret = tsk_trace_error(TSK_ERR_TABLES_BAD_INDEXES);\n                goto out;\n            }\n            parent[edge_child[e]] = TSK_NULL;\n            used_edges[e]++;\n            k++;\n        }\n        while (j < num_edges && edge_left[I[j]] == tree_left) {\n            e = I[j];\n            if (used_edges[e] != 0) {\n                ret = tsk_trace_error(TSK_ERR_TABLES_BAD_INDEXES);\n                goto out;\n            }\n            used_edges[e]++;\n            u = edge_child[e];\n            if (parent[u] != TSK_NULL) {\n                ret = tsk_trace_error(TSK_ERR_BAD_EDGES_CONTRADICTORY_CHILDREN);\n                goto out;\n            }\n            parent[u] = edge_parent[e];\n            j++;\n        }\n        tree_right = sequence_length;\n        if (j < num_edges) {\n            tree_right = TSK_MIN(tree_right, edge_left[I[j]]);\n        }\n        if (k < num_edges) {\n            tree_right = TSK_MIN(tree_right, edge_right[O[k]]);\n        }\n        while (site < num_sites && site_position[site] < tree_right) {\n            while (mutation < num_mutations && mutation_site[mutation] == site) {\n                if (!tsk_is_unknown_time(mutation_time[mutation])\n                    && parent[mutation_node[mutation]] != TSK_NULL\n                    && node_time[parent[mutation_node[mutation]]]\n                           <= mutation_time[mutation]) {\n                    ret = tsk_trace_error(TSK_ERR_MUTATION_TIME_OLDER_THAN_PARENT_NODE);\n                    goto out;\n                }\n                mutation++;\n            }\n            site++;\n        }\n        if (tree_right <= tree_left) {\n            ret = tsk_trace_error(TSK_ERR_TABLES_BAD_INDEXES);\n            goto out;\n        }\n        tree_left = tree_right;\n        /* This is technically possible; if we have 2**31 edges each defining\n         * a single tree, and there's a gap between each of these edges we\n         * would overflow this counter. */\n        if (num_trees == TSK_MAX_ID) {\n            ret = tsk_trace_error(TSK_ERR_TREE_OVERFLOW);\n            goto out;\n        }\n        num_trees++;\n    }\n    tsk_bug_assert(j == num_edges);\n    while (k < num_edges) {\n        /* At this point it must be that used_edges[O[k]] == 1,\n         * since otherwise we would have added a different edge twice,\n         * and so hit the error above. */\n        e = O[k];\n        if (edge_right[e] != sequence_length) {\n            ret = tsk_trace_error(TSK_ERR_TABLES_BAD_INDEXES);\n            goto out;\n        }\n        used_edges[e]++;\n        k++;\n    }\n    ret = num_trees;\nout:\n    /* Can't use tsk_safe_free because of restrict*/\n    if (parent != NULL) {\n        free(parent);\n    }\n    if (used_edges != NULL) {\n        free(used_edges);\n    }\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_index_integrity(const tsk_table_collection_t *self)\n{\n    int ret = 0;\n    tsk_id_t j;\n    const tsk_id_t num_edges = (tsk_id_t) self->edges.num_rows;\n    const tsk_id_t *edge_insertion_order = self->indexes.edge_insertion_order;\n    const tsk_id_t *edge_removal_order = self->indexes.edge_removal_order;\n\n    if (!tsk_table_collection_has_index(self, 0)) {\n        ret = tsk_trace_error(TSK_ERR_TABLES_NOT_INDEXED);\n        goto out;\n    }\n    for (j = 0; j < num_edges; j++) {\n        if (edge_insertion_order[j] < 0 || edge_insertion_order[j] >= num_edges) {\n            ret = tsk_trace_error(TSK_ERR_EDGE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (edge_removal_order[j] < 0 || edge_removal_order[j] >= num_edges) {\n            ret = tsk_trace_error(TSK_ERR_EDGE_OUT_OF_BOUNDS);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_compute_mutation_parents_to_array(\n    const tsk_table_collection_t *self, tsk_id_t *mutation_parent)\n{\n    int ret = 0;\n    const tsk_id_t *I, *O;\n    const tsk_edge_table_t edges = self->edges;\n    const tsk_node_table_t nodes = self->nodes;\n    const tsk_site_table_t sites = self->sites;\n    const tsk_mutation_table_t mutations = self->mutations;\n    const tsk_id_t M = (tsk_id_t) edges.num_rows;\n    tsk_id_t tj, tk;\n    tsk_id_t *parent = NULL;\n    tsk_id_t *bottom_mutation = NULL;\n    tsk_id_t u;\n    double left, right;\n    tsk_id_t site;\n    /* Using unsigned values here avoids potentially undefined behaviour */\n    tsk_size_t j, mutation, first_mutation;\n\n    parent = tsk_malloc(nodes.num_rows * sizeof(*parent));\n    bottom_mutation = tsk_malloc(nodes.num_rows * sizeof(*bottom_mutation));\n    if (parent == NULL || bottom_mutation == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, nodes.num_rows * sizeof(*parent));\n    tsk_memset(bottom_mutation, 0xff, nodes.num_rows * sizeof(*bottom_mutation));\n    tsk_memset(mutation_parent, 0xff, self->mutations.num_rows * sizeof(tsk_id_t));\n\n    I = self->indexes.edge_insertion_order;\n    O = self->indexes.edge_removal_order;\n    tj = 0;\n    tk = 0;\n    site = 0;\n    mutation = 0;\n    left = 0;\n    while (tj < M || left < self->sequence_length) {\n        while (tk < M && edges.right[O[tk]] == left) {\n            parent[edges.child[O[tk]]] = TSK_NULL;\n            tk++;\n        }\n        while (tj < M && edges.left[I[tj]] == left) {\n            parent[edges.child[I[tj]]] = edges.parent[I[tj]];\n            tj++;\n        }\n        right = self->sequence_length;\n        if (tj < M) {\n            right = TSK_MIN(right, edges.left[I[tj]]);\n        }\n        if (tk < M) {\n            right = TSK_MIN(right, edges.right[O[tk]]);\n        }\n\n        /* Tree is now ready. We look at each site on this tree in turn */\n        while (site < (tsk_id_t) sites.num_rows && sites.position[site] < right) {\n            /* Create a mapping from mutations to nodes. If we see more than one\n             * mutation at a node, the previously seen one must be the parent\n             * of the current since we assume they are in order. */\n            first_mutation = mutation;\n            while (mutation < mutations.num_rows && mutations.site[mutation] == site) {\n                u = mutations.node[mutation];\n                if (bottom_mutation[u] != TSK_NULL) {\n                    mutation_parent[mutation] = bottom_mutation[u];\n                }\n                bottom_mutation[u] = (tsk_id_t) mutation;\n                mutation++;\n            }\n            /* Make the common case of 1 mutation fast */\n            if (mutation > first_mutation + 1) {\n                /* If we have more than one mutation, compute the parent for each\n                 * one by traversing up the tree until we find a node that has a\n                 * mutation. */\n                for (j = first_mutation; j < mutation; j++) {\n                    if (mutation_parent[j] == TSK_NULL) {\n                        u = parent[mutations.node[j]];\n                        while (u != TSK_NULL && bottom_mutation[u] == TSK_NULL) {\n                            u = parent[u];\n                        }\n                        if (u != TSK_NULL) {\n                            mutation_parent[j] = bottom_mutation[u];\n                        }\n                    }\n                }\n            }\n            /* Reset the mapping for the next site */\n            for (j = first_mutation; j < mutation; j++) {\n                u = mutations.node[j];\n                bottom_mutation[u] = TSK_NULL;\n                /* Check that we haven't violated the sortedness property */\n                if (mutation_parent[j] > (tsk_id_t) j) {\n                    ret = tsk_trace_error(TSK_ERR_MUTATION_PARENT_AFTER_CHILD);\n                    goto out;\n                }\n            }\n            site++;\n        }\n        /* Move on to the next tree */\n        left = right;\n    }\n\nout:\n    tsk_safe_free(parent);\n    tsk_safe_free(bottom_mutation);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_check_mutation_parents(const tsk_table_collection_t *self)\n{\n    int ret = 0;\n    tsk_mutation_table_t mutations = self->mutations;\n    tsk_id_t *new_parents = NULL;\n    tsk_size_t j;\n\n    if (mutations.num_rows == 0) {\n        return ret;\n    }\n\n    new_parents = tsk_malloc(mutations.num_rows * sizeof(*new_parents));\n    if (new_parents == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_table_collection_compute_mutation_parents_to_array(self, new_parents);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (j = 0; j < mutations.num_rows; j++) {\n        if (mutations.parent[j] != new_parents[j]) {\n            ret = tsk_trace_error(TSK_ERR_BAD_MUTATION_PARENT);\n            goto out;\n        }\n    }\n\nout:\n    tsk_safe_free(new_parents);\n    return ret;\n}\n\ntsk_id_t TSK_WARN_UNUSED\ntsk_table_collection_check_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options)\n{\n    tsk_id_t ret = 0;\n    int mut_ret = 0;\n\n    if (options & TSK_CHECK_MUTATION_PARENTS) {\n        /* If we're checking mutation parents, we need to check the trees first */\n        options |= TSK_CHECK_TREES;\n    }\n\n    if (options & TSK_CHECK_TREES) {\n        /* Checking the trees implies these checks */\n        options |= TSK_CHECK_EDGE_ORDERING | TSK_CHECK_SITE_ORDERING\n                   | TSK_CHECK_SITE_DUPLICATES | TSK_CHECK_MUTATION_ORDERING\n                   | TSK_CHECK_MIGRATION_ORDERING | TSK_CHECK_INDEXES;\n    }\n\n    if (!tsk_isfinite(self->sequence_length) || self->sequence_length <= 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_SEQUENCE_LENGTH);\n        goto out;\n    }\n    ret = tsk_table_collection_check_offsets(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_node_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_edge_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_site_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_mutation_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_migration_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_check_individual_integrity(self, options);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (options & TSK_CHECK_INDEXES) {\n        ret = tsk_table_collection_check_index_integrity(self);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (options & TSK_CHECK_TREES) {\n        ret = tsk_table_collection_check_tree_integrity(self);\n        if (ret < 0) {\n            goto out;\n        }\n        /* This check requires tree integrity so do it last */\n        if (options & TSK_CHECK_MUTATION_PARENTS) {\n            mut_ret = tsk_table_collection_check_mutation_parents(self);\n            if (mut_ret != 0) {\n                ret = mut_ret;\n                goto out;\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nvoid\ntsk_table_collection_print_state(const tsk_table_collection_t *self, FILE *out)\n{\n    fprintf(out, \"Table collection state\\n\");\n    fprintf(out, \"sequence_length = %f\\n\", self->sequence_length);\n\n    write_metadata_schema_header(\n        out, self->metadata_schema, self->metadata_schema_length);\n    fprintf(out, \"#metadata#\\n\");\n    fprintf(out, \"%.*s\\n\", (int) self->metadata_length, self->metadata);\n    fprintf(out, \"#end#metadata\\n\");\n    fprintf(out, \"#time_units#\\n\");\n    fprintf(out, \"%.*s\\n\", (int) self->time_units_length, self->time_units);\n    fprintf(out, \"#end#time_units\\n\");\n    tsk_individual_table_print_state(&self->individuals, out);\n    tsk_node_table_print_state(&self->nodes, out);\n    tsk_edge_table_print_state(&self->edges, out);\n    tsk_migration_table_print_state(&self->migrations, out);\n    tsk_site_table_print_state(&self->sites, out);\n    tsk_mutation_table_print_state(&self->mutations, out);\n    tsk_population_table_print_state(&self->populations, out);\n    tsk_provenance_table_print_state(&self->provenances, out);\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_init(tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_flags_t edge_options = 0;\n\n    tsk_memset(self, 0, sizeof(*self));\n    if (options & TSK_TC_NO_EDGE_METADATA) {\n        edge_options |= TSK_TABLE_NO_METADATA;\n    }\n\n    /* Set default time_units value */\n    ret = tsk_table_collection_set_time_units(\n        self, TSK_TIME_UNITS_UNKNOWN, strlen(TSK_TIME_UNITS_UNKNOWN));\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_node_table_init(&self->nodes, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_init(&self->edges, edge_options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_init(&self->migrations, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_init(&self->sites, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_init(&self->mutations, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_init(&self->individuals, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_init(&self->populations, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_init(&self->provenances, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_reference_sequence_init(&self->reference_sequence, 0);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint\ntsk_table_collection_free(tsk_table_collection_t *self)\n{\n    tsk_individual_table_free(&self->individuals);\n    tsk_node_table_free(&self->nodes);\n    tsk_edge_table_free(&self->edges);\n    tsk_migration_table_free(&self->migrations);\n    tsk_site_table_free(&self->sites);\n    tsk_mutation_table_free(&self->mutations);\n    tsk_population_table_free(&self->populations);\n    tsk_provenance_table_free(&self->provenances);\n    tsk_reference_sequence_free(&self->reference_sequence);\n    tsk_safe_free(self->indexes.edge_insertion_order);\n    tsk_safe_free(self->indexes.edge_removal_order);\n    tsk_safe_free(self->file_uuid);\n    tsk_safe_free(self->time_units);\n    tsk_safe_free(self->metadata);\n    tsk_safe_free(self->metadata_schema);\n    return 0;\n}\n\nbool\ntsk_table_collection_equals(const tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, tsk_flags_t options)\n{\n    bool ret = self->sequence_length == other->sequence_length\n               && self->time_units_length == other->time_units_length\n               && tsk_memcmp(self->time_units, other->time_units,\n                      self->time_units_length * sizeof(char))\n                      == 0;\n    if (!(options & TSK_CMP_IGNORE_TABLES)) {\n        ret = ret\n              && tsk_individual_table_equals(\n                     &self->individuals, &other->individuals, options)\n              && tsk_node_table_equals(&self->nodes, &other->nodes, options)\n              && tsk_edge_table_equals(&self->edges, &other->edges, options)\n              && tsk_migration_table_equals(\n                     &self->migrations, &other->migrations, options)\n              && tsk_site_table_equals(&self->sites, &other->sites, options)\n              && tsk_mutation_table_equals(&self->mutations, &other->mutations, options)\n              && tsk_population_table_equals(\n                     &self->populations, &other->populations, options);\n        /* TSK_CMP_IGNORE_TABLES implies TSK_CMP_IGNORE_PROVENANCE */\n        if (!(options & TSK_CMP_IGNORE_PROVENANCE)) {\n            ret = ret\n                  && tsk_provenance_table_equals(\n                         &self->provenances, &other->provenances, options);\n        }\n    }\n    /* TSK_CMP_IGNORE_TS_METADATA is implied by TSK_CMP_IGNORE_METADATA */\n    if (options & TSK_CMP_IGNORE_METADATA) {\n        options |= TSK_CMP_IGNORE_TS_METADATA;\n    }\n    if (!(options & TSK_CMP_IGNORE_TS_METADATA)) {\n        ret = ret\n              && (self->metadata_length == other->metadata_length\n                     && self->metadata_schema_length == other->metadata_schema_length\n                     && tsk_memcmp(self->metadata, other->metadata,\n                            self->metadata_length * sizeof(char))\n                            == 0\n                     && tsk_memcmp(self->metadata_schema, other->metadata_schema,\n                            self->metadata_schema_length * sizeof(char))\n                            == 0);\n    }\n\n    if (!(options & TSK_CMP_IGNORE_REFERENCE_SEQUENCE)) {\n        ret = ret\n              && tsk_reference_sequence_equals(\n                     &self->reference_sequence, &other->reference_sequence, options);\n    }\n    return ret;\n}\n\nint\ntsk_table_collection_set_time_units(\n    tsk_table_collection_t *self, const char *time_units, tsk_size_t time_units_length)\n{\n    return replace_string(\n        &self->time_units, &self->time_units_length, time_units, time_units_length);\n}\n\nint\ntsk_table_collection_set_metadata(\n    tsk_table_collection_t *self, const char *metadata, tsk_size_t metadata_length)\n{\n    return replace_string(\n        &self->metadata, &self->metadata_length, metadata, metadata_length);\n}\n\nint\ntsk_table_collection_takeset_metadata(\n    tsk_table_collection_t *self, char *metadata, tsk_size_t metadata_length)\n{\n    return takeset_string(\n        &self->metadata, &self->metadata_length, metadata, metadata_length);\n}\n\nint\ntsk_table_collection_set_metadata_schema(tsk_table_collection_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length)\n{\n    return replace_string(&self->metadata_schema, &self->metadata_schema_length,\n        metadata_schema, metadata_schema_length);\n}\n\nint\ntsk_table_collection_set_indexes(tsk_table_collection_t *self,\n    tsk_id_t *edge_insertion_order, tsk_id_t *edge_removal_order)\n{\n    int ret = 0;\n    tsk_size_t index_size = self->edges.num_rows * sizeof(tsk_id_t);\n\n    tsk_table_collection_drop_index(self, 0);\n    self->indexes.edge_insertion_order = tsk_malloc(index_size);\n    self->indexes.edge_removal_order = tsk_malloc(index_size);\n    if (self->indexes.edge_insertion_order == NULL\n        || self->indexes.edge_removal_order == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memcpy(self->indexes.edge_insertion_order, edge_insertion_order, index_size);\n    tsk_memcpy(self->indexes.edge_removal_order, edge_removal_order, index_size);\n    self->indexes.num_edges = self->edges.num_rows;\nout:\n    return ret;\n}\n\nint\ntsk_table_collection_takeset_indexes(tsk_table_collection_t *self,\n    tsk_id_t *edge_insertion_order, tsk_id_t *edge_removal_order)\n{\n    int ret = 0;\n\n    if (edge_insertion_order == NULL || edge_removal_order == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    tsk_table_collection_drop_index(self, 0);\n    self->indexes.edge_insertion_order = edge_insertion_order;\n    self->indexes.edge_removal_order = edge_removal_order;\n    self->indexes.num_edges = self->edges.num_rows;\nout:\n    return ret;\n}\n\nbool\ntsk_table_collection_has_index(\n    const tsk_table_collection_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    return self->indexes.edge_insertion_order != NULL\n           && self->indexes.edge_removal_order != NULL\n           && self->indexes.num_edges == self->edges.num_rows;\n}\n\nbool\ntsk_table_collection_has_reference_sequence(const tsk_table_collection_t *self)\n{\n    return !tsk_reference_sequence_is_null(&self->reference_sequence);\n}\n\nint\ntsk_table_collection_drop_index(\n    tsk_table_collection_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    tsk_safe_free(self->indexes.edge_insertion_order);\n    tsk_safe_free(self->indexes.edge_removal_order);\n    self->indexes.edge_insertion_order = NULL;\n    self->indexes.edge_removal_order = NULL;\n    self->indexes.num_edges = 0;\n    return 0;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_build_index(\n    tsk_table_collection_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = TSK_ERR_GENERIC;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    double *time = self->nodes.time;\n    index_sort_t *sort_buff = NULL;\n    tsk_id_t parent;\n\n    /* For build indexes to make sense we must have referential integrity and\n     * sorted edges */\n    ret_id = tsk_table_collection_check_integrity(self, TSK_CHECK_EDGE_ORDERING);\n    if (ret_id != 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n\n    tsk_table_collection_drop_index(self, 0);\n    self->indexes.edge_insertion_order\n        = tsk_malloc(self->edges.num_rows * sizeof(tsk_id_t));\n    self->indexes.edge_removal_order\n        = tsk_malloc(self->edges.num_rows * sizeof(tsk_id_t));\n    sort_buff = tsk_malloc(self->edges.num_rows * sizeof(index_sort_t));\n    if (self->indexes.edge_insertion_order == NULL\n        || self->indexes.edge_removal_order == NULL || sort_buff == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* sort by left and increasing time to give us the order in which\n     * records should be inserted */\n    for (j = 0; j < self->edges.num_rows; j++) {\n        sort_buff[j].index = (tsk_id_t) j;\n        sort_buff[j].first = self->edges.left[j];\n        parent = self->edges.parent[j];\n        sort_buff[j].second = time[parent];\n        sort_buff[j].third = parent;\n        sort_buff[j].fourth = self->edges.child[j];\n    }\n    qsort(\n        sort_buff, (size_t) self->edges.num_rows, sizeof(index_sort_t), cmp_index_sort);\n    for (j = 0; j < self->edges.num_rows; j++) {\n        self->indexes.edge_insertion_order[j] = sort_buff[j].index;\n    }\n    /* sort by right and decreasing parent time to give us the order in which\n     * records should be removed. */\n    for (j = 0; j < self->edges.num_rows; j++) {\n        sort_buff[j].index = (tsk_id_t) j;\n        sort_buff[j].first = self->edges.right[j];\n        parent = self->edges.parent[j];\n        sort_buff[j].second = -time[parent];\n        sort_buff[j].third = -parent;\n        sort_buff[j].fourth = -self->edges.child[j];\n    }\n    qsort(\n        sort_buff, (size_t) self->edges.num_rows, sizeof(index_sort_t), cmp_index_sort);\n    for (j = 0; j < self->edges.num_rows; j++) {\n        self->indexes.edge_removal_order[j] = sort_buff[j].index;\n    }\n    self->indexes.num_edges = self->edges.num_rows;\n    ret = 0;\nout:\n    tsk_safe_free(sort_buff);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_set_file_uuid(tsk_table_collection_t *self, const char *uuid)\n{\n    int ret = 0;\n\n    tsk_safe_free(self->file_uuid);\n    self->file_uuid = NULL;\n\n    if (uuid != NULL) {\n        /* Allow space for \\0 so we can print it as a string */\n        self->file_uuid = tsk_malloc(TSK_UUID_SIZE + 1);\n        if (self->file_uuid == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        tsk_memcpy(self->file_uuid, uuid, TSK_UUID_SIZE);\n        self->file_uuid[TSK_UUID_SIZE] = '\\0';\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_copy(const tsk_table_collection_t *self,\n    tsk_table_collection_t *dest, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_table_collection_init(dest, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_node_table_copy(&self->nodes, &dest->nodes, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_copy(&self->edges, &dest->edges, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_copy(&self->migrations, &dest->migrations, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_copy(&self->sites, &dest->sites, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_copy(&self->mutations, &dest->mutations, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_copy(&self->individuals, &dest->individuals, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_copy(&self->populations, &dest->populations, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_copy(&self->provenances, &dest->provenances, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    dest->sequence_length = self->sequence_length;\n    if (tsk_table_collection_has_index(self, 0)) {\n        ret = tsk_table_collection_set_indexes(\n            dest, self->indexes.edge_insertion_order, self->indexes.edge_removal_order);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_table_collection_set_time_units(\n        dest, self->time_units, self->time_units_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_set_metadata(dest, self->metadata, self->metadata_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_set_metadata_schema(\n        dest, self->metadata_schema, self->metadata_schema_length);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_reference_sequence_copy(\n        &self->reference_sequence, &dest->reference_sequence, options);\n    if (ret != 0) {\n        goto out;\n    }\n    if (options & TSK_COPY_FILE_UUID) {\n        /* The UUID should only be generated on writing to a file (see the call\n         * to generate_uuid in tsk_table_collection_write_format_data) and\n         * no other writing access is supported. We only read the value from\n         * the file, and raise an error if it's the wrong length there. Thus,\n         * finding a UUID value of any other length here is undefined behaviour.\n         */\n        tsk_bug_assert(\n            self->file_uuid == NULL || strlen(self->file_uuid) == TSK_UUID_SIZE);\n        ret = tsk_table_collection_set_file_uuid(dest, self->file_uuid);\n        if (ret != 0) {\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_read_format_data(tsk_table_collection_t *self, kastore_t *store)\n{\n    int ret = 0;\n    size_t len;\n    uint32_t *version = NULL;\n    int8_t *format_name = NULL;\n    int8_t *uuid = NULL;\n    double *L = NULL;\n    char *time_units = NULL;\n    char *metadata = NULL;\n    char *metadata_schema = NULL;\n    size_t time_units_length, metadata_length, metadata_schema_length;\n    /* TODO we could simplify this function quite a bit if we use the\n     * read_table_properties infrastructure. We would need to add the\n     * ability to have non-optional columns to that though. */\n\n    ret = kastore_gets_int8(store, \"format/name\", &format_name, &len);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (len != TSK_FILE_FORMAT_NAME_LENGTH) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n    if (tsk_memcmp(TSK_FILE_FORMAT_NAME, format_name, TSK_FILE_FORMAT_NAME_LENGTH)\n        != 0) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n\n    ret = kastore_gets_uint32(store, \"format/version\", &version, &len);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (len != 2) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n    if (version[0] < TSK_FILE_FORMAT_VERSION_MAJOR) {\n        ret = tsk_trace_error(TSK_ERR_FILE_VERSION_TOO_OLD);\n        goto out;\n    }\n    if (version[0] > TSK_FILE_FORMAT_VERSION_MAJOR) {\n        ret = tsk_trace_error(TSK_ERR_FILE_VERSION_TOO_NEW);\n        goto out;\n    }\n\n    ret = kastore_gets_float64(store, \"sequence_length\", &L, &len);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (len != 1) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n    if (L[0] <= 0.0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_SEQUENCE_LENGTH);\n        goto out;\n    }\n    self->sequence_length = L[0];\n\n    ret = kastore_gets_int8(store, \"uuid\", &uuid, &len);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (len != TSK_UUID_SIZE) {\n        ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n        goto out;\n    }\n    ret = tsk_table_collection_set_file_uuid(self, (const char *) uuid);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = kastore_containss(store, \"time_units\");\n    if (ret < 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (ret == 1) {\n        ret = kastore_gets_int8(\n            store, \"time_units\", (int8_t **) &time_units, &time_units_length);\n        if (ret != 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        ret = tsk_table_collection_set_time_units(\n            self, time_units, (tsk_size_t) time_units_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = kastore_containss(store, \"metadata\");\n    if (ret < 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (ret == 1) {\n        ret = kastore_gets_int8(\n            store, \"metadata\", (int8_t **) &metadata, &metadata_length);\n        if (ret != 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        ret = tsk_table_collection_takeset_metadata(\n            self, metadata, (tsk_size_t) metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        metadata = NULL;\n    }\n\n    ret = kastore_containss(store, \"metadata_schema\");\n    if (ret < 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n    if (ret == 1) {\n        ret = kastore_gets_int8(store, \"metadata_schema\", (int8_t **) &metadata_schema,\n            (size_t *) &metadata_schema_length);\n        if (ret != 0) {\n            ret = tsk_set_kas_error(ret);\n            goto out;\n        }\n        ret = tsk_table_collection_set_metadata_schema(\n            self, metadata_schema, (tsk_size_t) metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\nout:\n    if ((ret ^ (1 << TSK_KAS_ERR_BIT)) == KAS_ERR_KEY_NOT_FOUND) {\n        ret = tsk_trace_error(TSK_ERR_REQUIRED_COL_NOT_FOUND);\n    }\n    tsk_safe_free(version);\n    tsk_safe_free(format_name);\n    tsk_safe_free(uuid);\n    tsk_safe_free(L);\n    tsk_safe_free(time_units);\n    tsk_safe_free(metadata_schema);\n    tsk_safe_free(metadata);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_dump_indexes(const tsk_table_collection_t *self, kastore_t *store,\n    tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    write_table_col_t cols[] = {\n        { \"indexes/edge_insertion_order\", NULL, self->indexes.num_edges,\n            TSK_ID_STORAGE_TYPE },\n        { \"indexes/edge_removal_order\", NULL, self->indexes.num_edges,\n            TSK_ID_STORAGE_TYPE },\n        { .name = NULL },\n    };\n\n    if (tsk_table_collection_has_index(self, 0)) {\n        cols[0].array = self->indexes.edge_insertion_order;\n        cols[1].array = self->indexes.edge_removal_order;\n        ret = write_table_cols(store, cols, 0);\n    }\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_load_indexes(tsk_table_collection_t *self, kastore_t *store)\n{\n    int ret = 0;\n    tsk_id_t *edge_insertion_order = NULL;\n    tsk_id_t *edge_removal_order = NULL;\n    tsk_size_t num_rows;\n\n    read_table_col_t cols[] = {\n        { \"indexes/edge_insertion_order\", (void **) &edge_insertion_order,\n            TSK_ID_STORAGE_TYPE, TSK_COL_OPTIONAL },\n        { \"indexes/edge_removal_order\", (void **) &edge_removal_order,\n            TSK_ID_STORAGE_TYPE, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    num_rows = TSK_NUM_ROWS_UNSET;\n    ret = read_table_cols(store, &num_rows, cols, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if ((edge_insertion_order == NULL) != (edge_removal_order == NULL)) {\n        ret = tsk_trace_error(TSK_ERR_BOTH_COLUMNS_REQUIRED);\n        goto out;\n    }\n    if (edge_insertion_order != NULL) {\n        if (num_rows != self->edges.num_rows) {\n            ret = tsk_trace_error(TSK_ERR_FILE_FORMAT);\n            goto out;\n        }\n        ret = tsk_table_collection_takeset_indexes(\n            self, edge_insertion_order, edge_removal_order);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    edge_insertion_order = NULL;\n    edge_removal_order = NULL;\nout:\n    tsk_safe_free(edge_insertion_order);\n    tsk_safe_free(edge_removal_order);\n    return ret;\n}\n\nstatic int\ntsk_table_collection_load_reference_sequence(\n    tsk_table_collection_t *self, kastore_t *store)\n{\n    int ret = 0;\n    char *data = NULL;\n    char *url = NULL;\n    char *metadata = NULL;\n    char *metadata_schema = NULL;\n    tsk_size_t data_length = 0, url_length, metadata_length, metadata_schema_length;\n\n    read_table_property_t properties[] = {\n        { \"reference_sequence/data\", (void **) &data, &data_length, KAS_UINT8,\n            TSK_COL_OPTIONAL },\n        { \"reference_sequence/url\", (void **) &url, &url_length, KAS_UINT8,\n            TSK_COL_OPTIONAL },\n        { \"reference_sequence/metadata\", (void **) &metadata, &metadata_length,\n            KAS_UINT8, TSK_COL_OPTIONAL },\n        { \"reference_sequence/metadata_schema\", (void **) &metadata_schema,\n            &metadata_schema_length, KAS_UINT8, TSK_COL_OPTIONAL },\n        { .name = NULL },\n    };\n\n    ret = read_table_properties(store, properties, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (data != NULL) {\n        ret = tsk_reference_sequence_takeset_data(\n            &self->reference_sequence, data, (tsk_size_t) data_length);\n        if (ret != 0) {\n            goto out;\n        }\n        data = NULL;\n    }\n    if (metadata != NULL) {\n        ret = tsk_reference_sequence_takeset_metadata(\n            &self->reference_sequence, metadata, (tsk_size_t) metadata_length);\n        if (ret != 0) {\n            goto out;\n        }\n        metadata = NULL;\n    }\n    if (metadata_schema != NULL) {\n        ret = tsk_reference_sequence_set_metadata_schema(&self->reference_sequence,\n            metadata_schema, (tsk_size_t) metadata_schema_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (url != NULL) {\n        ret = tsk_reference_sequence_set_url(\n            &self->reference_sequence, url, (tsk_size_t) url_length);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\nout:\n    free_read_table_mem(NULL, NULL, properties);\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_loadf_inited(\n    tsk_table_collection_t *self, FILE *file, tsk_flags_t options)\n{\n    int ret = 0;\n    kastore_t store;\n\n    int kas_flags = KAS_READ_ALL;\n    if ((options & TSK_LOAD_SKIP_TABLES)\n        || (options & TSK_LOAD_SKIP_REFERENCE_SEQUENCE)) {\n        kas_flags = 0;\n    }\n    kas_flags = kas_flags | KAS_GET_TAKES_OWNERSHIP;\n    ret = kastore_openf(&store, file, \"r\", kas_flags);\n\n    if (ret != 0) {\n        if (ret == KAS_ERR_EOF) {\n            /* KAS_ERR_EOF means that we tried to read a store from the stream\n             * and we hit EOF immediately without reading any bytes. We signal\n             * this back to the client, which allows it to read an indefinite\n             * number of stores from a stream */\n            ret = tsk_trace_error(TSK_ERR_EOF);\n        } else {\n            ret = tsk_set_kas_error(ret);\n        }\n        goto out;\n    }\n    ret = tsk_table_collection_read_format_data(self, &store);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!(options & TSK_LOAD_SKIP_TABLES)) {\n        ret = tsk_node_table_load(&self->nodes, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_edge_table_load(&self->edges, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_site_table_load(&self->sites, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_mutation_table_load(&self->mutations, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_migration_table_load(&self->migrations, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_individual_table_load(&self->individuals, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_population_table_load(&self->populations, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_provenance_table_load(&self->provenances, &store);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_table_collection_load_indexes(self, &store);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        ret = tsk_table_collection_build_index(self, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (!(options & TSK_LOAD_SKIP_REFERENCE_SEQUENCE)) {\n        ret = tsk_table_collection_load_reference_sequence(self, &store);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = kastore_close(&store);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    /* If we're exiting on an error, we ignore any further errors that might come\n     * from kastore. In the nominal case, closing an already-closed store is a\n     * safe noop */\n    kastore_close(&store);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_loadf(tsk_table_collection_t *self, FILE *file, tsk_flags_t options)\n{\n    int ret = 0;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_table_collection_init(self, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    ret = tsk_table_collection_loadf_inited(self, file, options);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_load(\n    tsk_table_collection_t *self, const char *filename, tsk_flags_t options)\n{\n    int ret = 0;\n    FILE *file = NULL;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_table_collection_init(self, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    file = fopen(filename, \"rb\");\n    if (file == NULL) {\n        ret = tsk_trace_error(TSK_ERR_IO);\n        goto out;\n    }\n    ret = tsk_table_collection_loadf_inited(self, file, options);\n    if (ret != 0) {\n        goto out;\n    }\n    if (fclose(file) != 0) {\n        ret = tsk_trace_error(TSK_ERR_IO);\n        goto out;\n    }\n    file = NULL;\nout:\n    if (file != NULL) {\n        /* Ignore any additional errors we might get when closing the file\n         * in error conditions */\n        fclose(file);\n    }\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_table_collection_dump_reference_sequence(const tsk_table_collection_t *self,\n    kastore_t *store, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    const tsk_reference_sequence_t *ref = &self->reference_sequence;\n    write_table_col_t write_cols[] = {\n        { \"reference_sequence/data\", (void *) ref->data, ref->data_length, KAS_UINT8 },\n        { \"reference_sequence/url\", (void *) ref->url, ref->url_length, KAS_UINT8 },\n        { \"reference_sequence/metadata\", (void *) ref->metadata, ref->metadata_length,\n            KAS_UINT8 },\n        { \"reference_sequence/metadata_schema\", (void *) ref->metadata_schema,\n            ref->metadata_schema_length, KAS_UINT8 },\n        { .name = NULL },\n    };\n    if (tsk_table_collection_has_reference_sequence(self)) {\n        ret = write_table_cols(store, write_cols, 0);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_dump(\n    const tsk_table_collection_t *self, const char *filename, tsk_flags_t options)\n{\n    int ret = 0;\n    FILE *file = fopen(filename, \"wb\");\n\n    if (file == NULL) {\n        ret = tsk_trace_error(TSK_ERR_IO);\n        goto out;\n    }\n    ret = tsk_table_collection_dumpf(self, file, options);\n    if (ret != 0) {\n        goto out;\n    }\n    if (fclose(file) != 0) {\n        ret = tsk_trace_error(TSK_ERR_IO);\n        goto out;\n    }\n    file = NULL;\nout:\n    if (file != NULL) {\n        /* Ignore any additional errors we might get when closing the file\n         * in error conditions */\n        fclose(file);\n        /* If an error occurred make sure that the filename is removed */\n        remove(filename);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_dumpf(\n    const tsk_table_collection_t *self, FILE *file, tsk_flags_t options)\n{\n    int ret = 0;\n    kastore_t store;\n    char uuid[TSK_UUID_SIZE + 1]; // Must include space for trailing null.\n    write_table_col_t format_columns[] = {\n        { \"format/name\", (const void *) &TSK_FILE_FORMAT_NAME,\n            TSK_FILE_FORMAT_NAME_LENGTH, KAS_INT8 },\n        { \"format/version\",\n            (const void *) &(uint32_t[]){\n                TSK_FILE_FORMAT_VERSION_MAJOR, TSK_FILE_FORMAT_VERSION_MINOR },\n            2, KAS_UINT32 },\n        { \"sequence_length\", (const void *) &self->sequence_length, 1, KAS_FLOAT64 },\n        { \"uuid\", (void *) uuid, TSK_UUID_SIZE, KAS_INT8 },\n        { \"time_units\", (void *) self->time_units, self->time_units_length, KAS_INT8 },\n        { \"metadata\", (void *) self->metadata, self->metadata_length, KAS_INT8 },\n        { \"metadata_schema\", (void *) self->metadata_schema,\n            self->metadata_schema_length, KAS_INT8 },\n        { .name = NULL },\n    };\n\n    tsk_memset(&store, 0, sizeof(store));\n\n    ret = kastore_openf(&store, file, \"w\", 0);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\n\n    /* Write format data */\n    ret = tsk_generate_uuid(uuid, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = write_table_cols(&store, format_columns, options);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* All of these functions will set the kas_error internally, so we don't have\n     * to modify the return value. */\n    ret = tsk_node_table_dump(&self->nodes, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_dump(&self->edges, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_dump(&self->sites, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_dump(&self->migrations, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_dump(&self->mutations, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_dump(&self->individuals, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_dump(&self->populations, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_dump(&self->provenances, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_dump_indexes(self, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_dump_reference_sequence(self, &store, options);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = kastore_close(&store);\n    if (ret != 0) {\n        ret = tsk_set_kas_error(ret);\n        goto out;\n    }\nout:\n    /* It's safe to close a kastore twice. */\n    if (ret != 0) {\n        kastore_close(&store);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_simplify(tsk_table_collection_t *self, const tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_flags_t options, tsk_id_t *node_map)\n{\n    int ret = 0;\n    simplifier_t simplifier;\n    tsk_id_t *local_samples = NULL;\n    tsk_id_t u;\n\n    /* Avoid calling to simplifier_free with uninit'd memory on error branches */\n    tsk_memset(&simplifier, 0, sizeof(simplifier_t));\n\n    if ((options & TSK_SIMPLIFY_KEEP_UNARY)\n        && (options & TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS)) {\n        ret = tsk_trace_error(TSK_ERR_KEEP_UNARY_MUTUALLY_EXCLUSIVE);\n        goto out;\n    }\n\n    /* For now we don't bother with edge metadata, but it can easily be\n     * implemented. */\n    if (self->edges.metadata_length > 0) {\n        ret = tsk_trace_error(TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA);\n        goto out;\n    }\n\n    if (samples == NULL) {\n        local_samples = tsk_malloc(self->nodes.num_rows * sizeof(*local_samples));\n        if (local_samples == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        num_samples = 0;\n        for (u = 0; u < (tsk_id_t) self->nodes.num_rows; u++) {\n            if (!!(self->nodes.flags[u] & TSK_NODE_IS_SAMPLE)) {\n                local_samples[num_samples] = u;\n                num_samples++;\n            }\n        }\n        samples = local_samples;\n    }\n\n    ret = simplifier_init(&simplifier, samples, num_samples, self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = simplifier_run(&simplifier, node_map);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!!(options & TSK_DEBUG)) {\n        simplifier_print_state(&simplifier, tsk_get_debug_stream());\n    }\n    /* The indexes are invalidated now so drop them */\n    ret = tsk_table_collection_drop_index(self, 0);\nout:\n    simplifier_free(&simplifier);\n    tsk_safe_free(local_samples);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_link_ancestors(tsk_table_collection_t *self, tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_id_t *ancestors, tsk_size_t num_ancestors,\n    tsk_flags_t TSK_UNUSED(options), tsk_edge_table_t *result)\n{\n    int ret = 0;\n    ancestor_mapper_t ancestor_mapper;\n\n    tsk_memset(&ancestor_mapper, 0, sizeof(ancestor_mapper_t));\n\n    if (self->edges.metadata_length > 0) {\n        ret = tsk_trace_error(TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA);\n        goto out;\n    }\n\n    ret = ancestor_mapper_init(\n        &ancestor_mapper, samples, num_samples, ancestors, num_ancestors, self, result);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = ancestor_mapper_run(&ancestor_mapper);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    ancestor_mapper_free(&ancestor_mapper);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_ibd_within(const tsk_table_collection_t *self,\n    tsk_identity_segments_t *result, const tsk_id_t *samples, tsk_size_t num_samples,\n    double min_span, double max_time, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_ibd_finder_t ibd_finder;\n\n    ret = tsk_identity_segments_init(result, self->nodes.num_rows, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_init(&ibd_finder, self, result, min_span, max_time);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_init_within(&ibd_finder, samples, num_samples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_run(&ibd_finder);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!!(options & TSK_DEBUG)) {\n        tsk_ibd_finder_print_state(&ibd_finder, tsk_get_debug_stream());\n    }\nout:\n    tsk_ibd_finder_free(&ibd_finder);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_ibd_between(const tsk_table_collection_t *self,\n    tsk_identity_segments_t *result, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, double min_span,\n    double max_time, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_ibd_finder_t ibd_finder;\n\n    ret = tsk_identity_segments_init(result, self->nodes.num_rows, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_init(&ibd_finder, self, result, min_span, max_time);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_init_between(\n        &ibd_finder, num_sample_sets, sample_set_sizes, sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_ibd_finder_run(&ibd_finder);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!!(options & TSK_DEBUG)) {\n        tsk_ibd_finder_print_state(&ibd_finder, tsk_get_debug_stream());\n    }\nout:\n    tsk_ibd_finder_free(&ibd_finder);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_sort(\n    tsk_table_collection_t *self, const tsk_bookmark_t *start, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_table_sorter_t sorter;\n\n    ret = tsk_table_sorter_init(&sorter, self, options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_sorter_run(&sorter, start);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_table_sorter_free(&sorter);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_canonicalise(tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_id_t k;\n    tsk_id_t *nodes = NULL;\n    tsk_table_sorter_t sorter;\n    tsk_flags_t subset_options = options & TSK_SUBSET_KEEP_UNREFERENCED;\n\n    ret = tsk_table_sorter_init(&sorter, self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    sorter.sort_mutations = tsk_table_sorter_sort_mutations;\n    sorter.sort_individuals = tsk_table_sorter_sort_individuals_canonical;\n\n    nodes = tsk_malloc(self->nodes.num_rows * sizeof(*nodes));\n    if (nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (k = 0; k < (tsk_id_t) self->nodes.num_rows; k++) {\n        nodes[k] = k;\n    }\n    ret = tsk_table_collection_subset(self, nodes, self->nodes.num_rows, subset_options);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_sorter_run(&sorter, NULL);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    tsk_safe_free(nodes);\n    tsk_table_sorter_free(&sorter);\n    return ret;\n}\n\n/*\n * Remove any sites with duplicate positions, retaining only the *first*\n * one. Assumes the tables have been sorted, throwing an error if not.\n */\nint TSK_WARN_UNUSED\ntsk_table_collection_deduplicate_sites(\n    tsk_table_collection_t *self, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t ret_id;\n    tsk_size_t j;\n    /* Map of old site IDs to new site IDs. */\n    tsk_id_t *site_id_map = NULL;\n    tsk_site_table_t copy;\n    tsk_site_t row, last_row;\n\n    /* Early exit if there's 0 rows. We don't exit early for one row because\n     * we would then skip error checking, making the semantics inconsistent. */\n    if (self->sites.num_rows == 0) {\n        return 0;\n    }\n\n    /* Must allocate the site table first for tsk_site_table_free to be safe */\n    ret = tsk_site_table_copy(&self->sites, &copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret_id = tsk_table_collection_check_integrity(self, TSK_CHECK_SITE_ORDERING);\n    if (ret_id != 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n\n    site_id_map = tsk_malloc(copy.num_rows * sizeof(*site_id_map));\n    if (site_id_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_site_table_clear(&self->sites);\n    if (ret != 0) {\n        goto out;\n    }\n\n    last_row.position = -1;\n    site_id_map[0] = 0;\n    for (j = 0; j < copy.num_rows; j++) {\n        tsk_site_table_get_row_unsafe(&copy, (tsk_id_t) j, &row);\n        if (row.position != last_row.position) {\n            ret_id\n                = tsk_site_table_add_row(&self->sites, row.position, row.ancestral_state,\n                    row.ancestral_state_length, row.metadata, row.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n        }\n        site_id_map[j] = (tsk_id_t) self->sites.num_rows - 1;\n        last_row = row;\n    }\n\n    if (self->sites.num_rows < copy.num_rows) {\n        // Remap sites in the mutation table\n        // (but only if there's been any changed sites)\n        for (j = 0; j < self->mutations.num_rows; j++) {\n            self->mutations.site[j] = site_id_map[self->mutations.site[j]];\n        }\n    }\n    ret = 0;\nout:\n    tsk_site_table_free(&copy);\n    tsk_safe_free(site_id_map);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_compute_mutation_parents(\n    tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_mutation_table_t *mutations = &self->mutations;\n    tsk_id_t *parent_backup = NULL;\n    bool restore_parents = false;\n\n    if (!(options & TSK_NO_CHECK_INTEGRITY)) {\n        if (mutations->num_rows > 0) {\n            /* We need to wipe the parent column before computing, as otherwise invalid\n             * parents can cause integrity checks to fail. We take a copy to restore on\n             * error */\n            parent_backup = tsk_malloc(mutations->num_rows * sizeof(*parent_backup));\n            if (parent_backup == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            tsk_memcpy(parent_backup, mutations->parent,\n                mutations->num_rows * sizeof(*parent_backup));\n            /* Set the parent pointers to TSK_NULL */\n            tsk_memset(mutations->parent, 0xff,\n                mutations->num_rows * sizeof(*mutations->parent));\n            restore_parents = true;\n        }\n        /* Safe to cast here as we're not counting trees */\n        ret = (int) tsk_table_collection_check_integrity(self, TSK_CHECK_TREES);\n        if (ret < 0) {\n            goto out;\n        }\n    }\n\n    ret = tsk_table_collection_compute_mutation_parents_to_array(\n        self, self->mutations.parent);\n    if (ret != 0) {\n        goto out;\n    }\n\nout:\n    if (ret != 0 && restore_parents) {\n        tsk_memcpy(mutations->parent, parent_backup,\n            mutations->num_rows * sizeof(*parent_backup));\n    }\n    tsk_safe_free(parent_backup);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_compute_mutation_times(\n    tsk_table_collection_t *self, double *random, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_id_t num_trees;\n    const tsk_id_t *restrict I = self->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->indexes.edge_removal_order;\n    const tsk_edge_table_t edges = self->edges;\n    const tsk_node_table_t nodes = self->nodes;\n    const tsk_site_table_t sites = self->sites;\n    const tsk_mutation_table_t mutations = self->mutations;\n    const tsk_id_t M = (tsk_id_t) edges.num_rows;\n    tsk_id_t tj, tk;\n    tsk_id_t *parent = NULL;\n    double *numerator = NULL;\n    double *denominator = NULL;\n    tsk_id_t u;\n    double left, right, parent_time;\n    tsk_id_t site;\n    /* Using unsigned values here avoids potentially undefined behaviour */\n    tsk_size_t j, mutation, first_mutation;\n    tsk_bookmark_t skip_edges = { 0, 0, self->edges.num_rows, 0, 0, 0, 0, 0 };\n\n    /* The random param is for future usage */\n    if (random != NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n\n    /* First set the times to TSK_UNKNOWN_TIME so that check will succeed */\n    for (j = 0; j < mutations.num_rows; j++) {\n        mutations.time[j] = TSK_UNKNOWN_TIME;\n    }\n    /* TSK_CHECK_MUTATION_PARENTS isn't needed here as we're not using the parents */\n    num_trees = tsk_table_collection_check_integrity(self, TSK_CHECK_TREES);\n    if (num_trees < 0) {\n        ret = (int) num_trees;\n        goto out;\n    }\n    parent = tsk_malloc(nodes.num_rows * sizeof(*parent));\n    numerator = tsk_malloc(nodes.num_rows * sizeof(*numerator));\n    denominator = tsk_malloc(nodes.num_rows * sizeof(*denominator));\n    if (parent == NULL || numerator == NULL || denominator == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, nodes.num_rows * sizeof(*parent));\n    tsk_memset(numerator, 0, nodes.num_rows * sizeof(*numerator));\n    tsk_memset(denominator, 0, nodes.num_rows * sizeof(*denominator));\n\n    tj = 0;\n    tk = 0;\n    site = 0;\n    mutation = 0;\n    left = 0;\n    while (tj < M || left < self->sequence_length) {\n        while (tk < M && edges.right[O[tk]] == left) {\n            parent[edges.child[O[tk]]] = TSK_NULL;\n            tk++;\n        }\n        while (tj < M && edges.left[I[tj]] == left) {\n            parent[edges.child[I[tj]]] = edges.parent[I[tj]];\n            tj++;\n        }\n        right = self->sequence_length;\n        if (tj < M) {\n            right = TSK_MIN(right, edges.left[I[tj]]);\n        }\n        if (tk < M) {\n            right = TSK_MIN(right, edges.right[O[tk]]);\n        }\n\n        /* Tree is now ready. We look at each site on this tree in turn */\n        while (site < (tsk_id_t) sites.num_rows && sites.position[site] < right) {\n            first_mutation = mutation;\n            /* Count how many mutations each edge has to get our\n               denominator */\n            while (mutation < mutations.num_rows && mutations.site[mutation] == site) {\n                denominator[mutations.node[mutation]]++;\n                mutation++;\n            }\n            /* Go over the mutations again assigning times. As the sorting\n               requirements guarantee that parents are before children, we assign\n               oldest first */\n            for (j = first_mutation; j < mutation; j++) {\n                u = mutations.node[j];\n                numerator[u]++;\n                if (parent[u] == TSK_NULL) {\n                    /* This mutation is above a root */\n                    mutations.time[j] = nodes.time[u];\n                } else {\n                    parent_time = nodes.time[parent[u]];\n                    mutations.time[j] = parent_time\n                                        - (parent_time - nodes.time[u]) * numerator[u]\n                                              / (denominator[u] + 1);\n                }\n            }\n            /* Reset the book-keeping for the next site */\n            for (j = first_mutation; j < mutation; j++) {\n                u = mutations.node[j];\n                numerator[u] = 0;\n                denominator[u] = 0;\n            }\n            site++;\n        }\n        /* Move on to the next tree */\n        left = right;\n    }\n\n    /* Now that mutations have times their sort order may have been invalidated, so\n     * re-sort. Safe to cast the result to an int here because we're not counting\n     * trees. */\n    ret = (int) tsk_table_collection_check_integrity(self, TSK_CHECK_MUTATION_ORDERING);\n    if (ret == TSK_ERR_UNSORTED_MUTATIONS) {\n        ret = tsk_table_collection_sort(self, &skip_edges, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    } else if (ret < 0) {\n        goto out;\n    }\n\nout:\n    tsk_safe_free(parent);\n    tsk_safe_free(numerator);\n    tsk_safe_free(denominator);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_delete_older(\n    tsk_table_collection_t *self, double time, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_edge_t edge;\n    tsk_mutation_t mutation;\n    tsk_migration_t migration;\n    tsk_edge_table_t edges;\n    tsk_mutation_table_t mutations;\n    tsk_migration_table_t migrations;\n    const double *restrict node_time = self->nodes.time;\n    tsk_id_t j, ret_id, parent;\n    double mutation_time;\n    tsk_id_t *mutation_map = NULL;\n\n    memset(&edges, 0, sizeof(edges));\n    memset(&mutations, 0, sizeof(mutations));\n    memset(&migrations, 0, sizeof(migrations));\n\n    ret = tsk_edge_table_copy(&self->edges, &edges, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_clear(&self->edges);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < (tsk_id_t) edges.num_rows; j++) {\n        tsk_edge_table_get_row_unsafe(&edges, j, &edge);\n        if (node_time[edge.parent] <= time) {\n            ret_id = tsk_edge_table_add_row(&self->edges, edge.left, edge.right,\n                edge.parent, edge.child, edge.metadata, edge.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n        }\n    }\n    /* Calling x_table_free multiple times is safe, so get rid of the\n     * extra edge table memory as soon as we can. */\n    tsk_edge_table_free(&edges);\n\n    mutation_map = tsk_malloc(self->mutations.num_rows * sizeof(*mutation_map));\n    if (mutation_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_mutation_table_copy(&self->mutations, &mutations, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_clear(&self->mutations);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < (tsk_id_t) mutations.num_rows; j++) {\n        tsk_mutation_table_get_row_unsafe(&mutations, j, &mutation);\n        mutation_time = tsk_is_unknown_time(mutation.time) ? node_time[mutation.node]\n                                                           : mutation.time;\n        mutation_map[j] = TSK_NULL;\n        if (mutation_time < time) {\n            ret_id = tsk_mutation_table_add_row(&self->mutations, mutation.site,\n                mutation.node, mutation.parent, mutation.time, mutation.derived_state,\n                mutation.derived_state_length, mutation.metadata,\n                mutation.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            mutation_map[j] = ret_id;\n        }\n    }\n    tsk_mutation_table_free(&mutations);\n    for (j = 0; j < (tsk_id_t) self->mutations.num_rows; j++) {\n        parent = self->mutations.parent[j];\n        if (parent != TSK_NULL) {\n            self->mutations.parent[j] = mutation_map[parent];\n        }\n    }\n\n    ret = tsk_migration_table_copy(&self->migrations, &migrations, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_clear(&self->migrations);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < (tsk_id_t) migrations.num_rows; j++) {\n        tsk_migration_table_get_row_unsafe(&migrations, j, &migration);\n        if (migration.time < time) {\n            ret_id = tsk_migration_table_add_row(&self->migrations, migration.left,\n                migration.right, migration.node, migration.source, migration.dest,\n                migration.time, migration.metadata, migration.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n        }\n    }\n    tsk_migration_table_free(&migrations);\nout:\n    tsk_edge_table_free(&edges);\n    tsk_mutation_table_free(&mutations);\n    tsk_migration_table_free(&migrations);\n    tsk_safe_free(mutation_map);\n    return ret;\n}\n\nint\ntsk_table_collection_record_num_rows(\n    const tsk_table_collection_t *self, tsk_bookmark_t *position)\n{\n    position->individuals = self->individuals.num_rows;\n    position->nodes = self->nodes.num_rows;\n    position->edges = self->edges.num_rows;\n    position->migrations = self->migrations.num_rows;\n    position->sites = self->sites.num_rows;\n    position->mutations = self->mutations.num_rows;\n    position->populations = self->populations.num_rows;\n    position->provenances = self->provenances.num_rows;\n    return 0;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_truncate(tsk_table_collection_t *tables, tsk_bookmark_t *position)\n{\n    int ret = 0;\n\n    ret = tsk_table_collection_drop_index(tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_individual_table_truncate(&tables->individuals, position->individuals);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_node_table_truncate(&tables->nodes, position->nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_edge_table_truncate(&tables->edges, position->edges);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_migration_table_truncate(&tables->migrations, position->migrations);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_site_table_truncate(&tables->sites, position->sites);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_truncate(&tables->mutations, position->mutations);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_population_table_truncate(&tables->populations, position->populations);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_provenance_table_truncate(&tables->provenances, position->provenances);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_clear(tsk_table_collection_t *self, tsk_flags_t options)\n{\n    int ret = 0;\n    bool clear_provenance = !!(options & TSK_CLEAR_PROVENANCE);\n    bool clear_metadata_schemas = !!(options & TSK_CLEAR_METADATA_SCHEMAS);\n    bool clear_ts_metadata = !!(options & TSK_CLEAR_TS_METADATA_AND_SCHEMA);\n    tsk_bookmark_t rows_to_retain\n        = { .provenances = clear_provenance ? 0 : self->provenances.num_rows };\n\n    ret = tsk_table_collection_truncate(self, &rows_to_retain);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (clear_metadata_schemas) {\n        ret = tsk_individual_table_set_metadata_schema(&self->individuals, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_node_table_set_metadata_schema(&self->nodes, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_edge_table_set_metadata_schema(&self->edges, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_migration_table_set_metadata_schema(&self->migrations, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_site_table_set_metadata_schema(&self->sites, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_mutation_table_set_metadata_schema(&self->mutations, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_population_table_set_metadata_schema(&self->populations, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    if (clear_ts_metadata) {\n        ret = tsk_table_collection_set_metadata(self, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_table_collection_set_metadata_schema(self, \"\", 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\nout:\n    return ret;\n}\n\nstatic int\ntsk_table_collection_add_and_remap_node(tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, tsk_id_t node_id, tsk_id_t *individual_map,\n    tsk_id_t *population_map, tsk_id_t *node_map, bool add_populations)\n{\n    int ret = 0;\n    tsk_id_t ret_id, new_ind, new_pop;\n    tsk_node_t node;\n    tsk_individual_t ind;\n    tsk_population_t pop;\n\n    ret = tsk_node_table_get_row(&other->nodes, node_id, &node);\n    if (ret < 0) {\n        goto out;\n    }\n    new_ind = TSK_NULL;\n    if (node.individual != TSK_NULL) {\n        if (individual_map[node.individual] == TSK_NULL) {\n            ret = tsk_individual_table_get_row(\n                &other->individuals, node.individual, &ind);\n            if (ret < 0) {\n                goto out;\n            }\n            ret_id = tsk_individual_table_add_row(&self->individuals, ind.flags,\n                ind.location, ind.location_length, ind.parents, ind.parents_length,\n                ind.metadata, ind.metadata_length);\n            if (ret < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            individual_map[node.individual] = ret_id;\n        }\n        new_ind = individual_map[node.individual];\n    }\n    new_pop = TSK_NULL;\n    if (node.population != TSK_NULL) {\n        // keep same pops if add_populations is False\n        if (!add_populations) {\n            population_map[node.population] = node.population;\n        }\n        if (population_map[node.population] == TSK_NULL) {\n            ret = tsk_population_table_get_row(\n                &other->populations, node.population, &pop);\n            if (ret < 0) {\n                goto out;\n            }\n            ret_id = tsk_population_table_add_row(\n                &self->populations, pop.metadata, pop.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            population_map[node.population] = ret_id;\n        }\n        new_pop = population_map[node.population];\n    }\n    ret_id = tsk_node_table_add_row(&self->nodes, node.flags, node.time, new_pop,\n        new_ind, node.metadata, node.metadata_length);\n    if (ret_id < 0) {\n        ret = (int) ret_id;\n        goto out;\n    }\n    node_map[node.id] = ret_id;\n\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_subset(tsk_table_collection_t *self, const tsk_id_t *nodes,\n    tsk_size_t num_nodes, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_id_t ret_id, j, k, parent_ind, new_parent, new_child, new_node, site_id;\n    tsk_size_t num_parents;\n    tsk_individual_t ind;\n    tsk_edge_t edge;\n    tsk_id_t *node_map = NULL;\n    tsk_id_t *individual_map = NULL;\n    tsk_id_t *population_map = NULL;\n    tsk_id_t *site_map = NULL;\n    tsk_id_t *mutation_map = NULL;\n    tsk_table_collection_t tables;\n    tsk_population_t pop;\n    tsk_site_t site;\n    tsk_mutation_t mut;\n    bool keep_unreferenced = !!(options & TSK_SUBSET_KEEP_UNREFERENCED);\n    bool no_change_populations = !!(options & TSK_SUBSET_NO_CHANGE_POPULATIONS);\n\n    ret = tsk_table_collection_copy(self, &tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    /* Not calling TSK_CHECK_TREES so casting to int is safe */\n    ret = (int) tsk_table_collection_check_integrity(self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_clear(self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    node_map = tsk_malloc(tables.nodes.num_rows * sizeof(*node_map));\n    individual_map = tsk_malloc(tables.individuals.num_rows * sizeof(*individual_map));\n    population_map = tsk_malloc(tables.populations.num_rows * sizeof(*population_map));\n    site_map = tsk_malloc(tables.sites.num_rows * sizeof(*site_map));\n    mutation_map = tsk_malloc(tables.mutations.num_rows * sizeof(*mutation_map));\n    if (node_map == NULL || individual_map == NULL || population_map == NULL\n        || site_map == NULL || mutation_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(node_map, 0xff, tables.nodes.num_rows * sizeof(*node_map));\n    tsk_memset(\n        individual_map, 0xff, tables.individuals.num_rows * sizeof(*individual_map));\n    tsk_memset(\n        population_map, 0xff, tables.populations.num_rows * sizeof(*population_map));\n    tsk_memset(site_map, 0xff, tables.sites.num_rows * sizeof(*site_map));\n    tsk_memset(mutation_map, 0xff, tables.mutations.num_rows * sizeof(*mutation_map));\n\n    if (no_change_populations) {\n        ret = tsk_population_table_copy(\n            &tables.populations, &self->populations, TSK_NO_INIT);\n        if (ret < 0) {\n            goto out;\n        }\n        for (k = 0; k < (tsk_id_t) tables.populations.num_rows; k++) {\n            population_map[k] = k;\n        }\n    }\n\n    // First do individuals so they stay in the same order.\n    // So we can remap individual parents and not rely on sortedness,\n    // we first check who to keep; then build the individual map, and\n    // finally populate the tables.\n    if (keep_unreferenced) {\n        for (k = 0; k < (tsk_id_t) tables.individuals.num_rows; k++) {\n            // put a non-NULL value here; fill in the actual order next\n            individual_map[k] = 0;\n        }\n    } else {\n        for (k = 0; k < (tsk_id_t) num_nodes; k++) {\n            if (nodes[k] < 0 || nodes[k] >= (tsk_id_t) tables.nodes.num_rows) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            j = tables.nodes.individual[nodes[k]];\n            if (j != TSK_NULL) {\n                individual_map[j] = 0;\n            }\n        }\n    }\n    j = 0;\n    for (k = 0; k < (tsk_id_t) tables.individuals.num_rows; k++) {\n        if (individual_map[k] != TSK_NULL) {\n            individual_map[k] = j;\n            j++;\n        }\n    }\n    for (k = 0; k < (tsk_id_t) tables.individuals.num_rows; k++) {\n        if (individual_map[k] != TSK_NULL) {\n            tsk_individual_table_get_row_unsafe(&tables.individuals, k, &ind);\n            num_parents = 0;\n            for (j = 0; j < (tsk_id_t) ind.parents_length; j++) {\n                parent_ind = ind.parents[j];\n                new_parent = parent_ind;\n                if (parent_ind != TSK_NULL) {\n                    new_parent = individual_map[parent_ind];\n                }\n                if ((parent_ind == TSK_NULL) || (new_parent != TSK_NULL)) {\n                    /* Beware: this modifies the parents column of tables.individuals\n                     * in-place! But it's OK as we don't use it again. */\n                    ind.parents[num_parents] = new_parent;\n                    num_parents++;\n                }\n            }\n            ret_id = tsk_individual_table_add_row(&self->individuals, ind.flags,\n                ind.location, ind.location_length, ind.parents, num_parents,\n                ind.metadata, ind.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            tsk_bug_assert(individual_map[k] == ret_id);\n        }\n    }\n\n    // Nodes and populations\n    for (k = 0; k < (tsk_id_t) num_nodes; k++) {\n        ret = tsk_table_collection_add_and_remap_node(\n            self, &tables, nodes[k], individual_map, population_map, node_map, true);\n        if (ret < 0) {\n            goto out;\n        }\n    }\n\n    /* TODO: Subset the migrations table. We would need to make sure\n     * that we don't remove populations that are referenced, so it would\n     * need to be done before the next code block. */\n    if (tables.migrations.num_rows != 0) {\n        ret = tsk_trace_error(TSK_ERR_MIGRATIONS_NOT_SUPPORTED);\n        goto out;\n    }\n\n    if (keep_unreferenced) {\n        // Keep unused populations\n        for (k = 0; k < (tsk_id_t) tables.populations.num_rows; k++) {\n            if (population_map[k] == TSK_NULL) {\n                tsk_population_table_get_row_unsafe(&tables.populations, k, &pop);\n                ret_id = tsk_population_table_add_row(\n                    &self->populations, pop.metadata, pop.metadata_length);\n                if (ret_id < 0) {\n                    ret = (int) ret_id;\n                    goto out;\n                }\n            }\n        }\n    }\n\n    // Edges\n    for (k = 0; k < (tsk_id_t) tables.edges.num_rows; k++) {\n        tsk_edge_table_get_row_unsafe(&tables.edges, k, &edge);\n        new_parent = node_map[edge.parent];\n        new_child = node_map[edge.child];\n        if ((new_parent != TSK_NULL) && (new_child != TSK_NULL)) {\n            ret_id = tsk_edge_table_add_row(&self->edges, edge.left, edge.right,\n                new_parent, new_child, edge.metadata, edge.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n        }\n    }\n\n    // Mutations and sites\n    // Make a first pass through to build the mutation_map so that\n    // mutation parent can be remapped even if the table is not in order.\n    j = 0;\n    for (k = 0; k < (tsk_id_t) tables.mutations.num_rows; k++) {\n        if (node_map[tables.mutations.node[k]] != TSK_NULL) {\n            mutation_map[k] = j;\n            j++;\n            site_id = tables.mutations.site[k];\n            if (site_map[site_id] == TSK_NULL) {\n                // Insert a temporary non-NULL value\n                site_map[site_id] = 1;\n            }\n        }\n    }\n    // Keep retained sites in their original order\n    j = 0;\n    for (k = 0; k < (tsk_id_t) tables.sites.num_rows; k++) {\n        if (keep_unreferenced || site_map[k] != TSK_NULL) {\n            tsk_site_table_get_row_unsafe(&tables.sites, k, &site);\n            ret_id = tsk_site_table_add_row(&self->sites, site.position,\n                site.ancestral_state, site.ancestral_state_length, site.metadata,\n                site.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            site_map[k] = j;\n            j++;\n        }\n    }\n    for (k = 0; k < (tsk_id_t) tables.mutations.num_rows; k++) {\n        tsk_mutation_table_get_row_unsafe(&tables.mutations, k, &mut);\n        new_node = node_map[mut.node];\n        if (new_node != TSK_NULL) {\n            new_parent = TSK_NULL;\n            if (mut.parent != TSK_NULL) {\n                new_parent = mutation_map[mut.parent];\n            }\n            ret_id = tsk_mutation_table_add_row(&self->mutations, site_map[mut.site],\n                new_node, new_parent, mut.time, mut.derived_state,\n                mut.derived_state_length, mut.metadata, mut.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            tsk_bug_assert(mutation_map[mut.id] == ret_id);\n        }\n        if (ret < 0) {\n            goto out;\n        }\n    }\n\n    ret = 0;\nout:\n    tsk_safe_free(node_map);\n    tsk_safe_free(individual_map);\n    tsk_safe_free(population_map);\n    tsk_safe_free(site_map);\n    tsk_safe_free(mutation_map);\n    tsk_table_collection_free(&tables);\n    return ret;\n}\n\nstatic int\ntsk_check_subset_equality(tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, const tsk_id_t *other_node_mapping,\n    tsk_size_t num_shared_nodes)\n{\n    int ret = 0;\n    tsk_id_t k, i;\n    tsk_id_t *self_nodes = NULL;\n    tsk_id_t *other_nodes = NULL;\n    tsk_table_collection_t self_copy;\n    tsk_table_collection_t other_copy;\n\n    tsk_memset(&self_copy, 0, sizeof(self_copy));\n    tsk_memset(&other_copy, 0, sizeof(other_copy));\n    self_nodes = tsk_malloc(num_shared_nodes * sizeof(*self_nodes));\n    other_nodes = tsk_malloc(num_shared_nodes * sizeof(*other_nodes));\n    if (self_nodes == NULL || other_nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    i = 0;\n    for (k = 0; k < (tsk_id_t) other->nodes.num_rows; k++) {\n        if (other_node_mapping[k] != TSK_NULL) {\n            self_nodes[i] = other_node_mapping[k];\n            other_nodes[i] = k;\n            i++;\n        }\n    }\n\n    ret = tsk_table_collection_copy(self, &self_copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_copy(other, &other_copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_subset(&self_copy, self_nodes, num_shared_nodes, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_subset(&other_copy, other_nodes, num_shared_nodes, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_canonicalise(&self_copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_canonicalise(&other_copy, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!tsk_table_collection_equals(&self_copy, &other_copy,\n            TSK_CMP_IGNORE_TS_METADATA | TSK_CMP_IGNORE_PROVENANCE\n                | TSK_CMP_IGNORE_REFERENCE_SEQUENCE)) {\n        ret = tsk_trace_error(TSK_ERR_UNION_DIFF_HISTORIES);\n        goto out;\n    }\n\nout:\n    tsk_table_collection_free(&self_copy);\n    tsk_table_collection_free(&other_copy);\n    tsk_safe_free(other_nodes);\n    tsk_safe_free(self_nodes);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_table_collection_union(tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, const tsk_id_t *other_node_mapping,\n    tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_id_t ret_id, k, i, new_parent, new_child;\n    tsk_size_t num_shared_nodes = 0;\n    tsk_size_t num_individuals_self = self->individuals.num_rows;\n    tsk_edge_t edge;\n    tsk_mutation_t mut;\n    tsk_site_t site;\n    tsk_id_t *node_map = NULL;\n    tsk_id_t *individual_map = NULL;\n    tsk_id_t *population_map = NULL;\n    tsk_id_t *site_map = NULL;\n    bool add_populations = !(options & TSK_UNION_NO_ADD_POP);\n    bool check_shared_portion = !(options & TSK_UNION_NO_CHECK_SHARED);\n    bool all_edges = !!(options & TSK_UNION_ALL_EDGES);\n    bool all_mutations = !!(options & TSK_UNION_ALL_MUTATIONS);\n\n    /* Not calling TSK_CHECK_TREES so casting to int is safe */\n    ret = (int) tsk_table_collection_check_integrity(self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = (int) tsk_table_collection_check_integrity(other, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    for (k = 0; k < (tsk_id_t) other->nodes.num_rows; k++) {\n        if (other_node_mapping[k] >= (tsk_id_t) self->nodes.num_rows\n            || other_node_mapping[k] < TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_UNION_BAD_MAP);\n            goto out;\n        }\n        if (other_node_mapping[k] != TSK_NULL) {\n            num_shared_nodes++;\n        }\n    }\n\n    if (check_shared_portion) {\n        ret = tsk_check_subset_equality(\n            self, other, other_node_mapping, num_shared_nodes);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    // Maps relating the IDs in other to the new IDs in self.\n    node_map = tsk_malloc(other->nodes.num_rows * sizeof(*node_map));\n    individual_map = tsk_malloc(other->individuals.num_rows * sizeof(*individual_map));\n    population_map = tsk_malloc(other->populations.num_rows * sizeof(*population_map));\n    site_map = tsk_malloc(other->sites.num_rows * sizeof(*site_map));\n    if (node_map == NULL || individual_map == NULL || population_map == NULL\n        || site_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(node_map, 0xff, other->nodes.num_rows * sizeof(*node_map));\n    tsk_memset(\n        individual_map, 0xff, other->individuals.num_rows * sizeof(*individual_map));\n    tsk_memset(\n        population_map, 0xff, other->populations.num_rows * sizeof(*population_map));\n    tsk_memset(site_map, 0xff, other->sites.num_rows * sizeof(*site_map));\n\n    /* We have to map the individuals who are linked to nodes in the intersection first\n       as otherwise an individual linked to one node in the intersection and one in\n       `other` would be duplicated. We assume that the individual in `self` takes\n       priority.\n     */\n    for (k = 0; k < (tsk_id_t) other->nodes.num_rows; k++) {\n        if (other_node_mapping[k] != TSK_NULL\n            && other->nodes.individual[k] != TSK_NULL) {\n            individual_map[other->nodes.individual[k]]\n                = self->nodes.individual[other_node_mapping[k]];\n        }\n    }\n    // nodes, individuals, populations\n    for (k = 0; k < (tsk_id_t) other->nodes.num_rows; k++) {\n        if (other_node_mapping[k] != TSK_NULL) {\n            node_map[k] = other_node_mapping[k];\n        } else {\n            ret = tsk_table_collection_add_and_remap_node(self, other, k, individual_map,\n                population_map, node_map, add_populations);\n            if (ret < 0) {\n                goto out;\n            }\n        }\n    }\n\n    /* Now we know the full individual map we can remap the parents of the new\n     * individuals*/\n    for (k = (tsk_id_t) self->individuals.parents_offset[num_individuals_self];\n         k < (tsk_id_t) self->individuals.parents_length; k++) {\n        if (self->individuals.parents[k] != TSK_NULL) {\n            self->individuals.parents[k] = individual_map[self->individuals.parents[k]];\n        }\n    }\n\n    // edges\n    for (k = 0; k < (tsk_id_t) other->edges.num_rows; k++) {\n        tsk_edge_table_get_row_unsafe(&other->edges, k, &edge);\n        if (all_edges || (other_node_mapping[edge.parent] == TSK_NULL)\n            || (other_node_mapping[edge.child] == TSK_NULL)) {\n            new_parent = node_map[edge.parent];\n            new_child = node_map[edge.child];\n            ret_id = tsk_edge_table_add_row(&self->edges, edge.left, edge.right,\n                new_parent, new_child, edge.metadata, edge.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n        }\n    }\n\n    // sites\n    // first do the \"disjoint\" (all_mutations) case, where we just add all sites;\n    // otherwise we want to just add sites for new mutations\n    if (all_mutations) {\n        for (k = 0; k < (tsk_id_t) other->sites.num_rows; k++) {\n            tsk_site_table_get_row_unsafe(&other->sites, k, &site);\n            ret_id = tsk_site_table_add_row(&self->sites, site.position,\n                site.ancestral_state, site.ancestral_state_length, site.metadata,\n                site.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            site_map[site.id] = ret_id;\n        }\n    }\n\n    // mutations (and maybe sites)\n    i = 0;\n    for (k = 0; k < (tsk_id_t) other->sites.num_rows; k++) {\n        tsk_site_table_get_row_unsafe(&other->sites, k, &site);\n        while ((i < (tsk_id_t) other->mutations.num_rows)\n               && (other->mutations.site[i] == site.id)) {\n            tsk_mutation_table_get_row_unsafe(&other->mutations, i, &mut);\n            if (all_mutations || (other_node_mapping[mut.node] == TSK_NULL)) {\n                if (site_map[site.id] == TSK_NULL) {\n                    ret_id = tsk_site_table_add_row(&self->sites, site.position,\n                        site.ancestral_state, site.ancestral_state_length, site.metadata,\n                        site.metadata_length);\n                    if (ret_id < 0) {\n                        ret = (int) ret_id;\n                        goto out;\n                    }\n                    site_map[site.id] = ret_id;\n                }\n                // the parents will be recomputed later\n                new_parent = TSK_NULL;\n                ret_id = tsk_mutation_table_add_row(&self->mutations, site_map[site.id],\n                    node_map[mut.node], new_parent, mut.time, mut.derived_state,\n                    mut.derived_state_length, mut.metadata, mut.metadata_length);\n                if (ret_id < 0) {\n                    ret = (int) ret_id;\n                    goto out;\n                }\n            }\n            i++;\n        }\n    }\n\n    /* TODO: Union of the Migrations Table. The only hindrance to performing the\n     * union operation on Migrations Tables is that tsk_table_collection_sort\n     * does not sort migrations by time, and instead throws an error. */\n    if (self->migrations.num_rows != 0 || other->migrations.num_rows != 0) {\n        ret = tsk_trace_error(TSK_ERR_MIGRATIONS_NOT_SUPPORTED);\n        goto out;\n    }\n\n    // sorting, deduplicating, and computing parents\n    ret = tsk_table_collection_sort(self, 0, 0);\n    if (ret < 0) {\n        goto out;\n    }\n\n    ret = tsk_table_collection_deduplicate_sites(self, 0);\n    if (ret < 0) {\n        goto out;\n    }\n\n    // need to sort again since after deduplicating sites, mutations\n    // may not be sorted by time within sites\n    ret = tsk_table_collection_sort(self, 0, 0);\n    if (ret < 0) {\n        goto out;\n    }\n\n    ret = tsk_table_collection_build_index(self, 0);\n    if (ret < 0) {\n        goto out;\n    }\n\n    ret = tsk_table_collection_compute_mutation_parents(self, 0);\n    if (ret < 0) {\n        goto out;\n    }\n\nout:\n    tsk_safe_free(node_map);\n    tsk_safe_free(individual_map);\n    tsk_safe_free(population_map);\n    tsk_safe_free(site_map);\n    return ret;\n}\n\nstatic int\ncmp_edge_cl(const void *a, const void *b)\n{\n    const tsk_edge_t *ia = (const tsk_edge_t *) a;\n    const tsk_edge_t *ib = (const tsk_edge_t *) b;\n    int ret = (ia->parent > ib->parent) - (ia->parent < ib->parent);\n    if (ret == 0) {\n        ret = (ia->child > ib->child) - (ia->child < ib->child);\n        if (ret == 0) {\n            ret = (ia->left > ib->left) - (ia->left < ib->left);\n        }\n    }\n    return ret;\n}\n\n/* Squash the edges in the specified array in place. The output edges will\n * be sorted by (child_id, left).\n */\n\nint TSK_WARN_UNUSED\ntsk_squash_edges(tsk_edge_t *edges, tsk_size_t num_edges, tsk_size_t *num_output_edges)\n{\n    int ret = 0;\n    tsk_size_t j, k, l;\n\n    if (num_edges < 2) {\n        *num_output_edges = num_edges;\n        return ret;\n    }\n\n    qsort(edges, (size_t) num_edges, sizeof(tsk_edge_t), cmp_edge_cl);\n    j = 0;\n    l = 0;\n    for (k = 1; k < num_edges; k++) {\n        if (edges[k - 1].metadata_length > 0) {\n            ret = tsk_trace_error(TSK_ERR_CANT_PROCESS_EDGES_WITH_METADATA);\n            goto out;\n        }\n\n        /* Check for overlapping edges. */\n        if (edges[k - 1].parent == edges[k].parent\n            && edges[k - 1].child == edges[k].child\n            && edges[k - 1].right > edges[k].left) {\n            ret = tsk_trace_error(TSK_ERR_BAD_EDGES_CONTRADICTORY_CHILDREN);\n            goto out;\n        }\n\n        /* Add squashed edge. */\n        if (edges[k - 1].parent != edges[k].parent || edges[k - 1].right != edges[k].left\n            || edges[j].child != edges[k].child) {\n\n            edges[l].left = edges[j].left;\n            edges[l].right = edges[k - 1].right;\n            edges[l].parent = edges[j].parent;\n            edges[l].child = edges[j].child;\n\n            j = k;\n            l++;\n        }\n    }\n    edges[l].left = edges[j].left;\n    edges[l].right = edges[k - 1].right;\n    edges[l].parent = edges[j].parent;\n    edges[l].child = edges[j].child;\n\n    *num_output_edges = (tsk_size_t) l + 1;\n\nout:\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/tables.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2024 Tskit Developers\n * Copyright (c) 2017-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @file tables.h\n * @brief Tskit Tables API.\n */\n#ifndef TSK_TABLES_H\n#define TSK_TABLES_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdio.h>\n#include <stdbool.h>\n#include <stdint.h>\n\n#include <kastore.h>\n\n#include <tskit/core.h>\n\n/****************************************************************************/\n/* Definitions for the basic objects */\n/****************************************************************************/\n\n/**\n@brief A single individual defined by a row in the individual table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\nan individual and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Bitwise flags. */\n    tsk_flags_t flags;\n    /** @brief Spatial location. The number of dimensions is defined by\n     * ``location_length``. */\n    const double *location;\n    /** @brief Number of spatial dimensions. */\n    tsk_size_t location_length;\n    /** @brief IDs of the parents. The number of parents given by ``parents_length``*/\n    tsk_id_t *parents;\n    /** @brief Number of parents. */\n    tsk_size_t parents_length;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Size of the metadata in bytes. */\n    tsk_size_t metadata_length;\n    /** @brief An array of the nodes associated with this individual */\n    const tsk_id_t *nodes;\n    /** @brief The number of nodes associated with this individual*/\n    tsk_size_t nodes_length;\n} tsk_individual_t;\n\n/**\n@brief A single node defined by a row in the node table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na node and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Bitwise flags. */\n    tsk_flags_t flags;\n    /** @brief Time. */\n    double time;\n    /** @brief Population ID. */\n    tsk_id_t population;\n    /** @brief Individual ID. */\n    tsk_id_t individual;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Size of the metadata in bytes. */\n    tsk_size_t metadata_length;\n} tsk_node_t;\n\n/**\n@brief A single edge defined by a row in the edge table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\nan edge and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Parent node ID. */\n    tsk_id_t parent;\n    /** @brief Child node ID. */\n    tsk_id_t child;\n    /** @brief Left coordinate. */\n    double left;\n    /** @brief Right coordinate. */\n    double right;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Size of the metadata in bytes. */\n    tsk_size_t metadata_length;\n} tsk_edge_t;\n\n/**\n@brief A single mutation defined by a row in the mutation table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na mutation and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Site ID. */\n    tsk_id_t site;\n    /** @brief Node ID. */\n    tsk_id_t node;\n    /** @brief Parent mutation ID. */\n    tsk_id_t parent;\n    /** @brief Mutation time. */\n    double time;\n    /** @brief Derived state. */\n    const char *derived_state;\n    /** @brief Size of the derived state in bytes. */\n    tsk_size_t derived_state_length;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Size of the metadata in bytes. */\n    tsk_size_t metadata_length;\n    /** @brief The ID of the edge that this mutation lies on, or TSK_NULL\n      if there is no corresponding edge.*/\n    tsk_id_t edge;\n    /** @brief Inherited state. */\n    const char *inherited_state;\n    /** @brief Size of the inherited state in bytes. */\n    tsk_size_t inherited_state_length;\n} tsk_mutation_t;\n\n/**\n@brief A single site defined by a row in the site table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na site and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Position coordinate. */\n    double position;\n    /** @brief Ancestral state. */\n    const char *ancestral_state;\n    /** @brief Ancestral state length in bytes. */\n    tsk_size_t ancestral_state_length;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Metadata length in bytes. */\n    tsk_size_t metadata_length;\n    /** @brief An array of this site's mutations */\n    const tsk_mutation_t *mutations;\n    /** @brief The number of mutations at this site */\n    tsk_size_t mutations_length;\n} tsk_site_t;\n\n/**\n@brief A single migration defined by a row in the migration table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na migration and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Source population ID. */\n    tsk_id_t source;\n    /** @brief Destination population ID. */\n    tsk_id_t dest;\n    /** @brief Node ID. */\n    tsk_id_t node;\n    /** @brief Left coordinate. */\n    double left;\n    /** @brief Right coordinate. */\n    double right;\n    /** @brief Time. */\n    double time;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Size of the metadata in bytes. */\n    tsk_size_t metadata_length;\n\n} tsk_migration_t;\n\n/**\n@brief A single population defined by a row in the population table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na population and its properties.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief Metadata. */\n    const char *metadata;\n    /** @brief Metadata length in bytes. */\n    tsk_size_t metadata_length;\n} tsk_population_t;\n\n/**\n@brief A single provenance defined by a row in the provenance table.\n\n@rst\nSee the :ref:`data model <sec_data_model_definitions>` section for the definition of\na provenance object and its properties. See the :ref:`sec_provenance` section\nfor more information on how provenance records should be structured.\n@endrst\n*/\ntypedef struct {\n    /** @brief Non-negative ID value corresponding to table row. */\n    tsk_id_t id;\n    /** @brief The timestamp. */\n    const char *timestamp;\n    /** @brief The timestamp length in bytes. */\n    tsk_size_t timestamp_length;\n    /** @brief The record. */\n    const char *record;\n    /** @brief The record length in bytes. */\n    tsk_size_t record_length;\n} tsk_provenance_t;\n\n/****************************************************************************/\n/* Table definitions */\n/****************************************************************************/\n\n/**\n@brief The individual table.\n\n@rst\nSee the individual :ref:`table definition <sec_individual_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the location column. */\n    tsk_size_t location_length;\n    tsk_size_t max_location_length;\n    tsk_size_t max_location_length_increment;\n    /** @brief The total length of the parent column. */\n    tsk_size_t parents_length;\n    tsk_size_t max_parents_length;\n    tsk_size_t max_parents_length_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The flags column. */\n    tsk_flags_t *flags;\n    /** @brief The location column. */\n    double *location;\n    /** @brief The location_offset column. */\n    tsk_size_t *location_offset;\n    /** @brief The parents column. */\n    tsk_id_t *parents;\n    /** @brief The parents_offset column. */\n    tsk_size_t *parents_offset;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_individual_table_t;\n\n/**\n@brief The node table.\n\n@rst\nSee the node :ref:`table definition <sec_node_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The flags column. */\n    tsk_flags_t *flags;\n    /** @brief The time column. */\n    double *time;\n    /** @brief The population column. */\n    tsk_id_t *population;\n    /** @brief The individual column. */\n    tsk_id_t *individual;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_node_table_t;\n\n/**\n@brief The edge table.\n\n@rst\nSee the edge :ref:`table definition <sec_edge_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The left column. */\n    double *left;\n    /** @brief The right column. */\n    double *right;\n    /** @brief The parent column. */\n    tsk_id_t *parent;\n    /** @brief The child column. */\n    tsk_id_t *child;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n    /** @brief Flags for this table */\n    tsk_flags_t options;\n} tsk_edge_table_t;\n\n/**\n@brief The migration table.\n\n@rst\nSee the migration :ref:`table definition <sec_migration_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The source column. */\n    tsk_id_t *source;\n    /** @brief The dest column. */\n    tsk_id_t *dest;\n    /** @brief The node column. */\n    tsk_id_t *node;\n    /** @brief The left column. */\n    double *left;\n    /** @brief The right column. */\n    double *right;\n    /** @brief The time column. */\n    double *time;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_migration_table_t;\n\n/**\n@brief The site table.\n\n@rst\nSee the site :ref:`table definition <sec_site_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    tsk_size_t ancestral_state_length;\n    tsk_size_t max_ancestral_state_length;\n    tsk_size_t max_ancestral_state_length_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The position column. */\n    double *position;\n    /** @brief The ancestral_state column. */\n    char *ancestral_state;\n    /** @brief The ancestral_state_offset column. */\n    tsk_size_t *ancestral_state_offset;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_site_table_t;\n\n/**\n@brief The mutation table.\n\n@rst\nSee the mutation :ref:`table definition <sec_mutation_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    tsk_size_t derived_state_length;\n    tsk_size_t max_derived_state_length;\n    tsk_size_t max_derived_state_length_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The node column. */\n    tsk_id_t *node;\n    /** @brief The site column. */\n    tsk_id_t *site;\n    /** @brief The parent column. */\n    tsk_id_t *parent;\n    /** @brief The time column. */\n    double *time;\n    /** @brief The derived_state column. */\n    char *derived_state;\n    /** @brief The derived_state_offset column. */\n    tsk_size_t *derived_state_offset;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_mutation_table_t;\n\n/**\n@brief The population table.\n\n@rst\nSee the population :ref:`table definition <sec_population_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the metadata column. */\n    tsk_size_t metadata_length;\n    tsk_size_t max_metadata_length;\n    tsk_size_t max_metadata_length_increment;\n    tsk_size_t metadata_schema_length;\n    /** @brief The metadata column. */\n    char *metadata;\n    /** @brief The metadata_offset column. */\n    tsk_size_t *metadata_offset;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n} tsk_population_table_t;\n\n/**\n@brief The provenance table.\n\n@rst\nSee the provenance :ref:`table definition <sec_provenance_table_definition>` for\ndetails of the columns in this table.\n@endrst\n*/\ntypedef struct {\n    /** @brief The number of rows in this table. */\n    tsk_size_t num_rows;\n    tsk_size_t max_rows;\n    tsk_size_t max_rows_increment;\n    /** @brief The total length of the timestamp column. */\n    tsk_size_t timestamp_length;\n    tsk_size_t max_timestamp_length;\n    tsk_size_t max_timestamp_length_increment;\n    /** @brief The total length of the record column. */\n    tsk_size_t record_length;\n    tsk_size_t max_record_length;\n    tsk_size_t max_record_length_increment;\n    /** @brief The timestamp column. */\n    char *timestamp;\n    /** @brief The timestamp_offset column. */\n    tsk_size_t *timestamp_offset;\n    /** @brief The record column. */\n    char *record;\n    /** @brief The record_offset column. */\n    tsk_size_t *record_offset;\n} tsk_provenance_table_t;\n\ntypedef struct {\n    char *data;\n    tsk_size_t data_length;\n    char *url;\n    tsk_size_t url_length;\n    char *metadata;\n    tsk_size_t metadata_length;\n    char *metadata_schema;\n    tsk_size_t metadata_schema_length;\n} tsk_reference_sequence_t;\n\n/**\n@brief A collection of tables defining the data for a tree sequence.\n*/\ntypedef struct {\n    /** @brief The sequence length defining the tree sequence's coordinate space */\n    double sequence_length;\n    char *file_uuid;\n    /** @brief The units of the time dimension */\n    char *time_units;\n    tsk_size_t time_units_length;\n    /** @brief The tree-sequence metadata */\n    char *metadata;\n    tsk_size_t metadata_length;\n    /** @brief The metadata schema */\n    char *metadata_schema;\n    tsk_size_t metadata_schema_length;\n    tsk_reference_sequence_t reference_sequence;\n    /** @brief The individual table */\n    tsk_individual_table_t individuals;\n    /** @brief The node table */\n    tsk_node_table_t nodes;\n    /** @brief The edge table */\n    tsk_edge_table_t edges;\n    /** @brief The migration table */\n    tsk_migration_table_t migrations;\n    /** @brief The site table */\n    tsk_site_table_t sites;\n    /** @brief The mutation table */\n    tsk_mutation_table_t mutations;\n    /** @brief The population table */\n    tsk_population_table_t populations;\n    /** @brief The provenance table */\n    tsk_provenance_table_t provenances;\n    struct {\n        tsk_id_t *edge_insertion_order;\n        tsk_id_t *edge_removal_order;\n        tsk_size_t num_edges;\n    } indexes;\n} tsk_table_collection_t;\n\n/**\n@brief A bookmark recording the position of all the tables in a table collection.\n*/\ntypedef struct {\n    /** @brief The position in the individual table. */\n    tsk_size_t individuals;\n    /** @brief The position in the node table. */\n    tsk_size_t nodes;\n    /** @brief The position in the edge table. */\n    tsk_size_t edges;\n    /** @brief The position in the migration table. */\n    tsk_size_t migrations;\n    /** @brief The position in the site table. */\n    tsk_size_t sites;\n    /** @brief The position in the mutation table. */\n    tsk_size_t mutations;\n    /** @brief The position in the population table. */\n    tsk_size_t populations;\n    /** @brief The position in the provenance table. */\n    tsk_size_t provenances;\n} tsk_bookmark_t;\n\n/**\n@brief Low-level table sorting method.\n*/\ntypedef struct _tsk_table_sorter_t {\n    /** @brief The input tables that are being sorted. */\n    tsk_table_collection_t *tables;\n    /** @brief The edge sorting function. If set to NULL, edges are not sorted. */\n    int (*sort_edges)(struct _tsk_table_sorter_t *self, tsk_size_t start);\n    /** @brief The mutation sorting function. */\n    int (*sort_mutations)(struct _tsk_table_sorter_t *self);\n    /** @brief The individual sorting function. */\n    int (*sort_individuals)(struct _tsk_table_sorter_t *self);\n    /** @brief An opaque pointer for use by client code */\n    void *user_data;\n    /** @brief Mapping from input site IDs to output site IDs */\n    tsk_id_t *site_id_map;\n} tsk_table_sorter_t;\n\n/* Structs for IBD finding.\n * TODO: document properly\n * */\n\n/* Note for tskit developers: it's perhaps a bit confusing/pointless to\n * have the tsk_identity_segment_t struct as well as the internal tsk_segment_t\n * struct (which is identical). However, we may want to implement either\n * segment type differently in future, and since the tsk_identity_segment_t\n * is part of the public API we want to allow the freedom for the different\n * structures to evolve over time */\ntypedef struct _tsk_identity_segment_t {\n    double left;\n    double right;\n    struct _tsk_identity_segment_t *next;\n    tsk_id_t node;\n} tsk_identity_segment_t;\n\ntypedef struct {\n    tsk_size_t num_segments;\n    double total_span;\n    tsk_identity_segment_t *head;\n    tsk_identity_segment_t *tail;\n} tsk_identity_segment_list_t;\n\ntypedef struct {\n    tsk_size_t num_nodes;\n    tsk_avl_tree_int_t pair_map;\n    tsk_size_t num_segments;\n    double total_span;\n    tsk_blkalloc_t heap;\n    bool store_segments;\n    bool store_pairs;\n} tsk_identity_segments_t;\n\n/* Diff iterator. */\ntypedef struct _tsk_edge_list_node_t {\n    tsk_edge_t edge;\n    struct _tsk_edge_list_node_t *next;\n    struct _tsk_edge_list_node_t *prev;\n} tsk_edge_list_node_t;\n\ntypedef struct {\n    tsk_edge_list_node_t *head;\n    tsk_edge_list_node_t *tail;\n} tsk_edge_list_t;\n\n/****************************************************************************/\n/* Common function options */\n/****************************************************************************/\n\n/**\n@defgroup API_FLAGS_SIMPLIFY_GROUP :c:func:`tsk_table_collection_simplify` and\n:c:func:`tsk_treeseq_simplify` specific flags.\n@{\n*/\n/** Remove sites from the output if there are no mutations that reference them.*/\n#define TSK_SIMPLIFY_FILTER_SITES (1 << 0)\n/** Remove populations from the output if there are no nodes or migrations that\nreference them. */\n#define TSK_SIMPLIFY_FILTER_POPULATIONS (1 << 1)\n/** Remove individuals from the output if there are no nodes that reference them.*/\n#define TSK_SIMPLIFY_FILTER_INDIVIDUALS (1 << 2)\n/** Do not remove nodes from the output if there are no edges that reference\nthem and do not reorder nodes so that the samples are nodes 0 to num_samples - 1.\nNote that this flag is negated compared to other filtering options because\nthe default behaviour is to filter unreferenced nodes and reorder to put samples\nfirst.\n*/\n#define TSK_SIMPLIFY_NO_FILTER_NODES (1 << 7)\n/**\nDo not update the sample status of nodes as a result of simplification.\n*/\n#define TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS (1 << 8)\n/**\nReduce the topological information in the tables to the minimum necessary to\nrepresent the trees that contain sites. If there are zero sites this will\nresult in an zero output edges. When the number of sites is greater than zero,\nevery tree in the output tree sequence will contain at least one site.\nFor a given site, the topology of the tree containing that site will be\nidentical (up to node ID remapping) to the topology of the corresponding tree\nin the input.\n*/\n#define TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY (1 << 3)\n/**\nBy default simplify removes unary nodes (i.e., nodes with exactly one child)\nalong the path from samples to root. If this option is specified such unary\nnodes will be preserved in the output.\n*/\n#define TSK_SIMPLIFY_KEEP_UNARY (1 << 4)\n/**\nBy default simplify removes all topology ancestral the MRCAs of the samples.\nThis option inserts edges from these MRCAs back to the roots of the input\ntrees.\n*/\n#define TSK_SIMPLIFY_KEEP_INPUT_ROOTS (1 << 5)\n/**\n@rst\nThis acts like :c:macro:`TSK_SIMPLIFY_KEEP_UNARY` (and is mutually exclusive with that\nflag). It keeps unary nodes, but only if the unary node is referenced from an individual.\n@endrst\n*/\n#define TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS (1 << 6)\n/** @} */\n\n/**\n@defgroup API_FLAGS_SUBSET_GROUP :c:func:`tsk_table_collection_subset` specific flags.\n@{\n*/\n/**If this flag is provided, the population table will not be changed in any way.*/\n#define TSK_SUBSET_NO_CHANGE_POPULATIONS (1 << 0)\n/**\n@rst\nIf this flag is provided, then unreferenced sites, individuals, and populations\nwill not be removed. If so, the site and individual tables will not be changed,\nand (unless :c:macro:`TSK_SUBSET_NO_CHANGE_POPULATIONS` is also provided) unreferenced\npopulations will be placed last, in their original order.\n@endrst\n*/\n#define TSK_SUBSET_KEEP_UNREFERENCED (1 << 1)\n/** @} */\n\n/**\n@defgroup API_FLAGS_CHECK_INTEGRITY_GROUP :c:func:`tsk_table_collection_check_integrity`\nspecific flags.\n@{\n*/\n/** Check edge ordering constraints for a tree sequence. */\n#define TSK_CHECK_EDGE_ORDERING (1 << 0)\n/** Check that sites are in non-decreasing position order. */\n#define TSK_CHECK_SITE_ORDERING (1 << 1)\n/**Check for any duplicate site positions. */\n#define TSK_CHECK_SITE_DUPLICATES (1 << 2)\n/**\nCheck constraints on the ordering of mutations. Any non-null\nmutation parents and known times are checked for ordering\nconstraints.\n*/\n#define TSK_CHECK_MUTATION_ORDERING (1 << 3)\n/**Check individual parents are before children, where specified. */\n#define TSK_CHECK_INDIVIDUAL_ORDERING (1 << 4)\n/**Check migrations are ordered by time. */\n#define TSK_CHECK_MIGRATION_ORDERING (1 << 5)\n/**Check that the table indexes exist, and contain valid edge references. */\n#define TSK_CHECK_INDEXES (1 << 6)\n/**\nAll checks needed to define a valid tree sequence. Note that\nthis implies all of the above checks.\n*/\n#define TSK_CHECK_TREES (1 << 7)\n/**\nCheck mutation parents are consistent with topology.\nImplies TSK_CHECK_TREES.\n*/\n#define TSK_CHECK_MUTATION_PARENTS (1 << 8)\n\n/* Leave room for more positive check flags */\n/**\nDo not check integrity of references to populations. This\ncan be safely combined with the other checks.\n*/\n#define TSK_NO_CHECK_POPULATION_REFS (1 << 12)\n/** @} */\n\n/**\n@defgroup API_FLAGS_LOAD_INIT_GROUP Flags used by load and init methods.\n@{\n*/\n/* These flags are for table collection load or init, or used as\n   flags on table collection or individual tables.\n * As flags are passed though from load to init they share a namespace */\n/** Skip reading tables, and only load top-level information. */\n#define TSK_LOAD_SKIP_TABLES (1 << 0)\n/** Do not load reference sequence. */\n#define TSK_LOAD_SKIP_REFERENCE_SEQUENCE (1 << 1)\n/**\n@rst\nDo not allocate space to store metadata in this table. Operations\nattempting to add non-empty metadata to the table will fail\nwith error TSK_ERR_METADATA_DISABLED.\n@endrst\n*/\n#define TSK_TABLE_NO_METADATA (1 << 2)\n/**\n@rst\nDo not allocate space to store metadata in the edge table. Operations\nattempting to add non-empty metadata to the edge table will fail\nwith error TSK_ERR_METADATA_DISABLED.\n@endrst\n*/\n#define TSK_TC_NO_EDGE_METADATA (1 << 3)\n/** @} */\n\n/* Flags for dump tables */\n/* We may not want to document this flag, but it's useful for testing\n * so we put it high up in the bit space, below the common options */\n#define TSK_DUMP_FORCE_OFFSET_64 (1 << 27)\n\n/**\n@defgroup API_FLAGS_COPY_GROUP Flags used by :c:func:`tsk_table_collection_copy`.\n@{\n*/\n/** Copy the file uuid, by default this is not copied. */\n#define TSK_COPY_FILE_UUID (1 << 0)\n/** @} */\n\n/**\n@defgroup API_FLAGS_UNION_GROUP Flags used by :c:func:`tsk_table_collection_union`.\n@{\n*/\n/**\nBy default, union checks that the portion of shared history between\n``self`` and ``other``, as implied by ``other_node_mapping``, are indeed\nequivalent. It does so by subsetting both ``self`` and ``other`` on the\nequivalent nodes specified in ``other_node_mapping``, and then checking for\nequality of the subsets.\n*/\n#define TSK_UNION_NO_CHECK_SHARED (1 << 0)\n/**\nBy default, all nodes new to ``self`` are assigned new populations. If this\noption is specified, nodes that are added to ``self`` will retain the\npopulation IDs they have in ``other``.\n */\n#define TSK_UNION_NO_ADD_POP (1 << 1)\n/**\nBy default, union only adds edges adjacent to a newly added node;\nthis option adds all edges.\n */\n#define TSK_UNION_ALL_EDGES (1 << 2)\n/**\nBy default, union only adds only mutations on newly added edges, and\nsites for those mutations; this option adds all mutations and all sites.\n */\n#define TSK_UNION_ALL_MUTATIONS (1 << 3)\n/** @} */\n\n/**\n@defgroup API_FLAGS_CMP_GROUP Flags used by :c:func:`tsk_table_collection_equals`.\n@{\n*/\n/**\nDo not include the top-level tree sequence metadata and metadata schemas\nin the comparison.\n*/\n#define TSK_CMP_IGNORE_TS_METADATA (1 << 0)\n/** Do not include the provenance table in comparison. */\n#define TSK_CMP_IGNORE_PROVENANCE (1 << 1)\n/**\n@rst\nDo not include metadata when comparing the table collections.\nThis includes both the top-level tree sequence metadata as well as the\nmetadata for each of the tables (i.e, :c:macro:`TSK_CMP_IGNORE_TS_METADATA` is implied).\nAll metadata schemas are also ignored.\n@endrst\n*/\n#define TSK_CMP_IGNORE_METADATA (1 << 2)\n/**\n@rst\nDo not include the timestamp information when comparing the provenance\ntables. This has no effect if :c:macro:`TSK_CMP_IGNORE_PROVENANCE` is specified.\n@endrst\n*/\n#define TSK_CMP_IGNORE_TIMESTAMPS (1 << 3)\n/**\nDo not include any tables in the comparison, thus comparing only the\ntop-level information of the table collections being compared.\n*/\n#define TSK_CMP_IGNORE_TABLES (1 << 4)\n/** Do not include the reference sequence in the comparison. */\n#define TSK_CMP_IGNORE_REFERENCE_SEQUENCE (1 << 5)\n/** @} */\n\n/**\n@defgroup API_FLAGS_CLEAR_GROUP Flags used by :c:func:`tsk_table_collection_clear`.\n@{\n*/\n/** Additionally clear the table metadata schemas*/\n#define TSK_CLEAR_METADATA_SCHEMAS (1 << 0)\n/** Additionally clear the tree-sequence metadata and schema*/\n#define TSK_CLEAR_TS_METADATA_AND_SCHEMA (1 << 1)\n/** Additionally clear the provenance table*/\n#define TSK_CLEAR_PROVENANCE (1 << 2)\n/** @} */\n\n/* For the edge diff iterator */\n#define TSK_INCLUDE_TERMINAL (1 << 0)\n\n/** @brief Value returned by seeking methods when they have successfully\n    seeked to a non-null tree.\n\n    @ingroup TREE_API_SEEKING_GROUP\n*/\n#define TSK_TREE_OK 1\n\n/****************************************************************************/\n/* Function signatures */\n/****************************************************************************/\n\n/**\n@defgroup INDIVIDUAL_TABLE_API_GROUP Individual table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_individual_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_init(tsk_individual_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_individual_table_t object.\n@return Always returns 0.\n*/\nint tsk_individual_table_free(tsk_individual_table_t *self);\n\n/**\n@brief Adds a row to this individual table.\n\n@rst\nAdd a new individual with the specified ``flags``, ``location``, ``parents`` and\n``metadata`` to the table. Copies of the ``location``, ``parents`` and ``metadata``\nparameters are taken immediately. See the :ref:`table definition\n<sec_individual_table_definition>` for details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param flags The bitwise flags for the new individual.\n@param location A pointer to a double array representing the spatial location\n    of the new individual. Can be ``NULL`` if ``location_length`` is 0.\n@param location_length The number of dimensions in the locations position.\n    Note this the number of elements in the corresponding double array\n    not the number of bytes.\n@param parents A pointer to a ``tsk_id`` array representing the parents\n    of the new individual. Can be ``NULL`` if ``parents_length`` is 0.\n@param parents_length The number of parents.\n    Note this the number of elements in the corresponding ``tsk_id`` array\n    not the number of bytes.\n@param metadata The metadata to be associated with the new individual. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return the ID of the newly added individual on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_individual_table_add_row(tsk_individual_table_t *self, tsk_flags_t flags,\n    const double *location, tsk_size_t location_length, const tsk_id_t *parents,\n    tsk_size_t parents_length, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. Copies of the ``location``, ``parents`` and ``metadata``\nparameters are taken immediately. See the :ref:`table definition\n<sec_individual_table_definition>` for details of the columns in this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param index The row to update.\n@param flags The bitwise flags for the individual.\n@param location A pointer to a double array representing the spatial location\n    of the new individual. Can be ``NULL`` if ``location_length`` is 0.\n@param location_length The number of dimensions in the locations position.\n    Note this the number of elements in the corresponding double array\n    not the number of bytes.\n@param parents A pointer to a ``tsk_id`` array representing the parents\n    of the new individual. Can be ``NULL`` if ``parents_length`` is 0.\n@param parents_length The number of parents.\n    Note this the number of elements in the corresponding ``tsk_id`` array\n    not the number of bytes.\n@param metadata The metadata to be associated with the new individual. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_update_row(tsk_individual_table_t *self, tsk_id_t index,\n    tsk_flags_t flags, const double *location, tsk_size_t location_length,\n    const tsk_id_t *parents, tsk_size_t parents_length, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_individual_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_clear(tsk_individual_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_individual_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_truncate(tsk_individual_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object where rows are to be added.\n@param other A pointer to a tsk_individual_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_extend(tsk_individual_table_t *self,\n    const tsk_individual_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\nThe values in the ``parents`` column are updated according to this map, so that\nreference integrity within the table is maintained. As a consequence of this,\nthe values in the ``parents`` column for kept rows are bounds-checked and an\nerror raised if they are not valid. Rows that are deleted are not checked for\nparent ID integrity.\n\nIf an attempt is made to delete rows that are referred to by the ``parents``\ncolumn of rows that are retained, an error is raised.\n\nThese error conditions are checked before any alterations to the table are\nmade.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_keep_rows(tsk_individual_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param other A pointer to a tsk_individual_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_individual_table_equals(const tsk_individual_table_t *self,\n    const tsk_individual_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n\nIndexes that are present are also copied to the destination table.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param dest A pointer to a tsk_individual_table_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised individual table. If not, it must be an\nuninitialised individual table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_copy(const tsk_individual_table_t *self,\n    tsk_individual_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified individual struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_individual_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_get_row(\n    const tsk_individual_table_t *self, tsk_id_t index, tsk_individual_t *row);\n\n/**\n@brief Set the metadata schema\n\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_metadata_schema(tsk_individual_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_individual_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_individual_table_print_state(const tsk_individual_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param flags The array of tsk_flag_t flag values to be copied.\n@param location The array of double location values to be copied.\n@param location_offset The array of tsk_size_t location offset values to be copied.\n@param parents The array of tsk_id_t parent values to be copied.\n@param parents_offset The array of tsk_size_t parent offset values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_columns(tsk_individual_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *location, const tsk_size_t *location_offset,\n    const tsk_id_t *parents, const tsk_size_t *parents_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays\n@param flags The array of tsk_flag_t flag values to be copied.\n@param location The array of double location values to be copied.\n@param location_offset The array of tsk_size_t location offset values to be copied.\n@param parents The array of tsk_id_t parent values to be copied.\n@param parents_offset The array of tsk_size_t parent offset values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_append_columns(tsk_individual_table_t *self,\n    tsk_size_t num_rows, const tsk_flags_t *flags, const double *location,\n    const tsk_size_t *location_offset, const tsk_id_t *parents,\n    const tsk_size_t *parents_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_max_rows_increment(\n    tsk_individual_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_max_metadata_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the location column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param max_location_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_max_location_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_location_length_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the parents column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param max_parents_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_individual_table_set_max_parents_length_increment(\n    tsk_individual_table_t *self, tsk_size_t max_parents_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_individual_table_dump_text(const tsk_individual_table_t *self, FILE *out);\n/**\n@defgroup NODE_TABLE_API_GROUP Node table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_node_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_init(tsk_node_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_node_table_t object.\n@return Always returns 0.\n*/\nint tsk_node_table_free(tsk_node_table_t *self);\n\n/**\n@brief Adds a row to this node table.\n\n@rst\nAdd a new node with the specified ``flags``, ``time``, ``population``,\n``individual`` and ``metadata`` to the table. A copy of the ``metadata`` parameter\nis taken immediately. See the :ref:`table definition <sec_node_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param flags The bitwise flags for the new node.\n@param time The time for the new node.\n@param population The population for the new node. Set to TSK_NULL if not\nknown.\n@param individual The individual for the new node. Set to TSK_NULL if not\nknown.\n@param metadata The metadata to be associated with the new node. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return the ID of the newly added node on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_node_table_add_row(tsk_node_table_t *self, tsk_flags_t flags, double time,\n    tsk_id_t population, tsk_id_t individual, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. A copy of the ``metadata`` parameter is taken immediately. See the\n:ref:`table definition <sec_node_table_definition>` for details of the columns\nin this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param index The row to update.\n@param flags The bitwise flags for the node.\n@param time The time for the node.\n@param population The population for the node. Set to TSK_NULL if not known.\n@param individual The individual for the node. Set to TSK_NULL if not known.\n@param metadata The metadata to be associated with the node. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_update_row(tsk_node_table_t *self, tsk_id_t index, tsk_flags_t flags,\n    double time, tsk_id_t population, tsk_id_t individual, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_node_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_clear(tsk_node_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_node_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_truncate(tsk_node_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object where rows are to be added.\n@param other A pointer to a tsk_node_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_extend(tsk_node_table_t *self, const tsk_node_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_keep_rows(tsk_node_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param other A pointer to a tsk_node_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_node_table_equals(\n    const tsk_node_table_t *self, const tsk_node_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the TSK_NO_INIT option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param dest A pointer to a tsk_node_table_t object. If the TSK_NO_INIT option\n    is specified, this must be an initialised node table. If not, it must\n    be an uninitialised node table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_copy(\n    const tsk_node_table_t *self, tsk_node_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified node struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_node_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_get_row(\n    const tsk_node_table_t *self, tsk_id_t index, tsk_node_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_node_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_set_metadata_schema(tsk_node_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_node_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_node_table_print_state(const tsk_node_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param flags The array of tsk_flag_t values to be copied.\n@param time The array of double time values to be copied.\n@param population The array of tsk_id_t population values to be copied.\n@param individual The array of tsk_id_t individual values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_set_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *time, const tsk_id_t *population,\n    const tsk_id_t *individual, const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays\n@param flags The array of tsk_flag_t values to be copied.\n@param time The array of double time values to be copied.\n@param population The array of tsk_id_t population values to be copied.\n@param individual The array of tsk_id_t individual values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_append_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    const tsk_flags_t *flags, const double *time, const tsk_id_t *population,\n    const tsk_id_t *individual, const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\n\nint tsk_node_table_set_max_rows_increment(\n    tsk_node_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_node_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_node_table_set_max_metadata_length_increment(\n    tsk_node_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_node_table_dump_text(const tsk_node_table_t *self, FILE *out);\n\n/**\n@defgroup EDGE_TABLE_API_GROUP Edge table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n\n**Options**\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_TABLE_NO_METADATA`\n@endrst\n\n@param self A pointer to an uninitialised tsk_edge_table_t object.\n@param options Allocation time options.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_init(tsk_edge_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_edge_table_t object.\n@return Always returns 0.\n*/\nint tsk_edge_table_free(tsk_edge_table_t *self);\n\n/**\n@brief Adds a row to this edge table.\n\n@rst\nAdd a new edge with the specified ``left``, ``right``, ``parent``, ``child`` and\n``metadata`` to the table. See the :ref:`table definition <sec_edge_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param left The left coordinate for the new edge.\n@param right The right coordinate for the new edge.\n@param parent The parent node for the new edge.\n@param child The child node for the new edge.\n@param metadata The metadata to be associated with the new edge. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n\n@return Return the ID of the newly added edge on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_edge_table_add_row(tsk_edge_table_t *self, double left, double right,\n    tsk_id_t parent, tsk_id_t child, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. A copy of the ``metadata`` parameter is taken immediately. See the\n:ref:`table definition <sec_edge_table_definition>` for details of the columns\nin this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param index The row to update.\n@param left The left coordinate for the edge.\n@param right The right coordinate for the edge.\n@param parent The parent node for the edge.\n@param child The child node for the edge.\n@param metadata The metadata to be associated with the edge. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_update_row(tsk_edge_table_t *self, tsk_id_t index, double left,\n    double right, tsk_id_t parent, tsk_id_t child, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_edge_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_clear(tsk_edge_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_edge_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_truncate(tsk_edge_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is ``NULL``,\nappend the first ``num_rows`` from ``other`` to this table. Note that metadata is copied\nas-is and is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object where rows are to be added.\n@param other A pointer to a tsk_edge_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_extend(tsk_edge_table_t *self, const tsk_edge_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_keep_rows(tsk_edge_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param other A pointer to a tsk_edge_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_edge_table_equals(\n    const tsk_edge_table_t *self, const tsk_edge_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param dest A pointer to a tsk_edge_table_t object. If the TSK_NO_INIT option\n    is specified, this must be an initialised edge table. If not, it must\n    be an uninitialised edge table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_copy(\n    const tsk_edge_table_t *self, tsk_edge_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified edge struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_edge_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_get_row(\n    const tsk_edge_table_t *self, tsk_id_t index, tsk_edge_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_edge_table_t object.\n@param metadata_schema A pointer to a char array\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_set_metadata_schema(tsk_edge_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_edge_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_edge_table_print_state(const tsk_edge_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param left The array of double left values to be copied.\n@param right The array of double right values to be copied.\n@param parent The array of tsk_id_t parent values to be copied.\n@param child The array of tsk_id_t child values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_set_columns(tsk_edge_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *parent,\n    const tsk_id_t *child, const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param left The array of double left values to be copied.\n@param right The array of double right values to be copied.\n@param parent The array of tsk_id_t parent values to be copied.\n@param child The array of tsk_id_t child values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n*/\nint tsk_edge_table_append_columns(tsk_edge_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *parent,\n    const tsk_id_t *child, const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_set_max_rows_increment(\n    tsk_edge_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_set_max_metadata_length_increment(\n    tsk_edge_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/**\n@brief Squash adjacent edges in-place\n\n@rst\nSorts, then condenses the table into the smallest possible number of rows by\ncombining any adjacent edges. A pair of edges is said to be `adjacent` if\nthey have the same parent and child nodes, and if the left coordinate of\none of the edges is equal to the right coordinate of the other edge.\nThis process is performed in-place so that any set of adjacent edges is\nreplaced by a single edge. The new edge will have the same parent and child\nnode, a left coordinate equal to the smallest left coordinate in the set,\nand a right coordinate equal to the largest right coordinate in the set.\nThe new edge table will be sorted in the canonical order (P, C, L, R).\n\n.. note::\n    Note that this method will fail if any edges have non-empty metadata.\n\n@endrst\n\n@param self A pointer to a tsk_edge_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_edge_table_squash(tsk_edge_table_t *self);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_edge_table_dump_text(const tsk_edge_table_t *self, FILE *out);\n\n/**\n@defgroup MIGRATION_TABLE_API_GROUP Migration table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_migration_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_init(tsk_migration_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_migration_table_t object.\n@return Always returns 0.\n*/\nint tsk_migration_table_free(tsk_migration_table_t *self);\n\n/**\n@brief Adds a row to this migration table.\n\n@rst\nAdd a new migration with the specified ``left``, ``right``, ``node``,\n``source``, ``dest``, ``time`` and ``metadata`` to the table.\nSee the :ref:`table definition <sec_migration_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param left The left coordinate for the new migration.\n@param right The right coordinate for the new migration.\n@param node The node ID for the new migration.\n@param source The source population ID for the new migration.\n@param dest The destination population ID for the new migration.\n@param time The time for the new migration.\n@param metadata The metadata to be associated with the new migration. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n\n@return Return the ID of the newly added migration on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_migration_table_add_row(tsk_migration_table_t *self, double left,\n    double right, tsk_id_t node, tsk_id_t source, tsk_id_t dest, double time,\n    const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. A copy of the ``metadata`` parameter is taken immediately. See the\n:ref:`table definition <sec_migration_table_definition>` for details of the columns\nin this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param index The row to update.\n@param left The left coordinate for the migration.\n@param right The right coordinate for the migration.\n@param node The node ID for the migration.\n@param source The source population ID for the migration.\n@param dest The destination population ID for the migration.\n@param time The time for the migration.\n@param metadata The metadata to be associated with the migration. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_update_row(tsk_migration_table_t *self, tsk_id_t index,\n    double left, double right, tsk_id_t node, tsk_id_t source, tsk_id_t dest,\n    double time, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_migration_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_clear(tsk_migration_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_migration_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_truncate(tsk_migration_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object where rows are to be added.\n@param other A pointer to a tsk_migration_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\n\nint tsk_migration_table_extend(tsk_migration_table_t *self,\n    const tsk_migration_table_t *other, tsk_size_t num_rows, const tsk_id_t *row_indexes,\n    tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_keep_rows(tsk_migration_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param other A pointer to a tsk_migration_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_migration_table_equals(const tsk_migration_table_t *self,\n    const tsk_migration_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param dest A pointer to a tsk_migration_table_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised migration table. If not, it must be an\nuninitialised migration table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_copy(\n    const tsk_migration_table_t *self, tsk_migration_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified migration struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_migration_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_get_row(\n    const tsk_migration_table_t *self, tsk_id_t index, tsk_migration_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_migration_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_set_metadata_schema(tsk_migration_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_migration_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_migration_table_print_state(const tsk_migration_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param left The array of double left values to be copied.\n@param right The array of double right values to be copied.\n@param node The array of tsk_id_t node values to be copied.\n@param source The array of tsk_id_t source values to be copied.\n@param dest The array of tsk_id_t dest values to be copied.\n@param time The array of double time values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_set_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *node,\n    const tsk_id_t *source, const tsk_id_t *dest, const double *time,\n    const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays\n@param left The array of double left values to be copied.\n@param right The array of double right values to be copied.\n@param node The array of tsk_id_t node values to be copied.\n@param source The array of tsk_id_t source values to be copied.\n@param dest The array of tsk_id_t dest values to be copied.\n@param time The array of double time values to be copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_append_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    const double *left, const double *right, const tsk_id_t *node,\n    const tsk_id_t *source, const tsk_id_t *dest, const double *time,\n    const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_set_max_rows_increment(\n    tsk_migration_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_migration_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_migration_table_set_max_metadata_length_increment(\n    tsk_migration_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_migration_table_dump_text(const tsk_migration_table_t *self, FILE *out);\n\n/**\n@defgroup SITE_TABLE_API_GROUP Site table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_site_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_init(tsk_site_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_site_table_t object.\n@return Always returns 0.\n*/\nint tsk_site_table_free(tsk_site_table_t *self);\n\n/**\n@brief Adds a row to this site table.\n\n@rst\nAdd a new site with the specified ``position``, ``ancestral_state``\nand ``metadata`` to the table. Copies of ``ancestral_state`` and ``metadata``\nare immediately taken. See the :ref:`table definition <sec_site_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param position The position coordinate for the new site.\n@param ancestral_state The ancestral_state for the new site.\n@param ancestral_state_length The length of the ancestral_state in bytes.\n@param metadata The metadata to be associated with the new site. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return the ID of the newly added site on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_site_table_add_row(tsk_site_table_t *self, double position,\n    const char *ancestral_state, tsk_size_t ancestral_state_length, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. Copies of the ``ancestral_state`` and ``metadata`` parameters are taken\nimmediately. See the :ref:`table definition <sec_site_table_definition>` for\ndetails of the columns in this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param index The row to update.\n@param position The position coordinate for the site.\n@param ancestral_state The ancestral_state for the site.\n@param ancestral_state_length The length of the ancestral_state in bytes.\n@param metadata The metadata to be associated with the site. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_update_row(tsk_site_table_t *self, tsk_id_t index, double position,\n    const char *ancestral_state, tsk_size_t ancestral_state_length, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_site_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_clear(tsk_site_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_site_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_truncate(tsk_site_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object where rows are to be added.\n@param other A pointer to a tsk_site_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_extend(tsk_site_table_t *self, const tsk_site_table_t *other,\n    tsk_size_t num_rows, const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_keep_rows(tsk_site_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param other A pointer to a tsk_site_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_site_table_equals(\n    const tsk_site_table_t *self, const tsk_site_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param dest A pointer to a tsk_site_table_t object. If the TSK_NO_INIT option\n    is specified, this must be an initialised site table. If not, it must\n    be an uninitialised site table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_copy(\n    const tsk_site_table_t *self, tsk_site_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified site struct to reflect the values in the specified row.\n\nThis function always sets the ``mutations`` and ``mutations_length``\nfields in the parameter :c:struct:`tsk_site_t` to ``NULL`` and ``0`` respectively.\nTo get access to the mutations for a particular site, please use the\ntree sequence method, :c:func:`tsk_treeseq_get_site`.\n\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_site_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_get_row(\n    const tsk_site_table_t *self, tsk_id_t index, tsk_site_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_site_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_set_metadata_schema(tsk_site_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_site_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_site_table_print_state(const tsk_site_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param position The array of double position values to be copied.\n@param ancestral_state The array of char ancestral state values to be copied.\n@param ancestral_state_offset The array of tsk_size_t ancestral state offset values to be\n        copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_set_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    const double *position, const char *ancestral_state,\n    const tsk_size_t *ancestral_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param position The array of double position values to be copied.\n@param ancestral_state The array of char ancestral state values to be copied.\n@param ancestral_state_offset The array of tsk_size_t ancestral state offset values to be\n    copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_append_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    const double *position, const char *ancestral_state,\n    const tsk_size_t *ancestral_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_set_max_rows_increment(\n    tsk_site_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\n\nint tsk_site_table_set_max_metadata_length_increment(\n    tsk_site_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the ancestral_state column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_site_table_t object.\n@param max_ancestral_state_length_increment The number of bytes to pre-allocate, or zero\nfor the default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_site_table_set_max_ancestral_state_length_increment(\n    tsk_site_table_t *self, tsk_size_t max_ancestral_state_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_site_table_dump_text(const tsk_site_table_t *self, FILE *out);\n\n/**\n@defgroup MUTATION_TABLE_API_GROUP Mutation table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_mutation_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_init(tsk_mutation_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_mutation_table_t object.\n@return Always returns 0.\n*/\nint tsk_mutation_table_free(tsk_mutation_table_t *self);\n\n/**\n@brief Adds a row to this mutation table.\n\n@rst\nAdd a new mutation with the specified ``site``, ``parent``, ``derived_state``\nand ``metadata`` to the table. Copies of ``derived_state`` and ``metadata``\nare immediately taken. See the :ref:`table definition <sec_mutation_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param site The site ID for the new mutation.\n@param node The ID of the node this mutation occurs over.\n@param parent The ID of the parent mutation.\n@param time The time of the mutation.\n@param derived_state The derived_state for the new mutation.\n@param derived_state_length The length of the derived_state in bytes.\n@param metadata The metadata to be associated with the new mutation. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return the ID of the newly added mutation on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_mutation_table_add_row(tsk_mutation_table_t *self, tsk_id_t site,\n    tsk_id_t node, tsk_id_t parent, double time, const char *derived_state,\n    tsk_size_t derived_state_length, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. Copies of the ``derived_state`` and ``metadata`` parameters are taken\nimmediately. See the :ref:`table definition <sec_mutation_table_definition>` for\ndetails of the columns in this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param index The row to update.\n@param site The site ID for the mutation.\n@param node The ID of the node this mutation occurs over.\n@param parent The ID of the parent mutation.\n@param time The time of the mutation.\n@param derived_state The derived_state for the mutation.\n@param derived_state_length The length of the derived_state in bytes.\n@param metadata The metadata to be associated with the mutation. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_update_row(tsk_mutation_table_t *self, tsk_id_t index,\n    tsk_id_t site, tsk_id_t node, tsk_id_t parent, double time,\n    const char *derived_state, tsk_size_t derived_state_length, const char *metadata,\n    tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_mutation_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_clear(tsk_mutation_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_truncate(tsk_mutation_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object where rows are to be added.\n@param other A pointer to a tsk_mutation_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_extend(tsk_mutation_table_t *self,\n    const tsk_mutation_table_t *other, tsk_size_t num_rows, const tsk_id_t *row_indexes,\n    tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\nThe values in the ``parent`` column are updated according to this map, so that\nreference integrity within the table is maintained. As a consequence of this,\nthe values in the ``parent`` column for kept rows are bounds-checked and an\nerror raised if they are not valid. Rows that are deleted are not checked for\nparent ID integrity.\n\nIf an attempt is made to delete rows that are referred to by the ``parent``\ncolumn of rows that are retained, an error is raised.\n\nThese error conditions are checked before any alterations to the table are\nmade.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_keep_rows(tsk_mutation_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param other A pointer to a tsk_mutation_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_mutation_table_equals(const tsk_mutation_table_t *self,\n    const tsk_mutation_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param dest A pointer to a tsk_mutation_table_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised mutation table. If not, it must be an\nuninitialised mutation table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_copy(\n    const tsk_mutation_table_t *self, tsk_mutation_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified mutation struct to reflect the values in the specified row.\n\nThis function always sets the ``edge`` field in parameter\n:c:struct:`tsk_mutation_t` to ``TSK_NULL``. To determine the ID of\nthe edge associated with a particular mutation, please use the\ntree sequence method, :c:func:`tsk_treeseq_get_mutation`.\n\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_mutation_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_get_row(\n    const tsk_mutation_table_t *self, tsk_id_t index, tsk_mutation_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_mutation_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_set_metadata_schema(tsk_mutation_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_mutation_table_print_state(const tsk_mutation_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param site The array of tsk_id_t site values to be copied.\n@param node The array of tsk_id_t node values to be copied.\n@param parent The array of tsk_id_t parent values to be copied.\n@param time The array of double time values to be copied.\n@param derived_state The array of char derived_state values to be copied.\n@param derived_state_offset The array of tsk_size_t derived state offset values to be\ncopied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_set_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    const tsk_id_t *site, const tsk_id_t *node, const tsk_id_t *parent,\n    const double *time, const char *derived_state,\n    const tsk_size_t *derived_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param site The array of tsk_id_t site values to be copied.\n@param node The array of tsk_id_t node values to be copied.\n@param parent The array of tsk_id_t parent values to be copied.\n@param time The array of double time values to be copied.\n@param derived_state The array of char derived_state values to be copied.\n@param derived_state_offset The array of tsk_size_t derived state offset values to be\n    copied.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_append_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    const tsk_id_t *site, const tsk_id_t *node, const tsk_id_t *parent,\n    const double *time, const char *derived_state,\n    const tsk_size_t *derived_state_offset, const char *metadata,\n    const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_set_max_rows_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_set_max_metadata_length_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the derived_state column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_mutation_table_t object.\n@param max_derived_state_length_increment The number of bytes to pre-allocate, or zero\nfor the default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_mutation_table_set_max_derived_state_length_increment(\n    tsk_mutation_table_t *self, tsk_size_t max_derived_state_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_mutation_table_dump_text(const tsk_mutation_table_t *self, FILE *out);\n\n/**\n@defgroup POPULATION_TABLE_API_GROUP Population table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_population_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_init(tsk_population_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_population_table_t object.\n@return Always returns 0.\n*/\nint tsk_population_table_free(tsk_population_table_t *self);\n\n/**\n@brief Adds a row to this population table.\n\n@rst\nAdd a new population with the specified ``metadata`` to the table. A copy of the\n``metadata`` is immediately taken. See the :ref:`table definition\n<sec_population_table_definition>` for details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param metadata The metadata to be associated with the new population. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return the ID of the newly added population on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_population_table_add_row(\n    tsk_population_table_t *self, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. A copy of the ``metadata`` parameter is taken immediately. See the\n:ref:`table definition <sec_population_table_definition>` for details of the\ncolumns in this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param index The row to update.\n@param metadata The metadata to be associated with the population. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``metadata_length`` is 0.\n@param metadata_length The size of the metadata array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_update_row(tsk_population_table_t *self, tsk_id_t index,\n    const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_population_table_free` to free the table's internal resources. Note that the\nmetadata schema is not cleared.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_clear(tsk_population_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_population_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_truncate(tsk_population_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table. Note that metadata is copied as-is\nand is not checked for compatibility with any existing schema on this table.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object where rows are to be added.\n@param other A pointer to a tsk_population_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_extend(tsk_population_table_t *self,\n    const tsk_population_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_keep_rows(tsk_population_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns,\nand their metadata schemas are byte-wise identical.\n\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n    Do not include metadata in the comparison. Note that as metadata is the\n    only column in the population table, two population tables are considered\n    equal if they have the same number of rows if this flag is specified.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param other A pointer to a tsk_population_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_population_table_equals(const tsk_population_table_t *self,\n    const tsk_population_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param dest A pointer to a tsk_population_table_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised population table. If not, it must be an\nuninitialised population table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_copy(const tsk_population_table_t *self,\n    tsk_population_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified population struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_population_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_get_row(\n    const tsk_population_table_t *self, tsk_id_t index, tsk_population_t *row);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table, replacing any existing.\n@endrst\n@param self A pointer to a tsk_population_table_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_set_metadata_schema(tsk_population_table_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_population_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_population_table_print_state(const tsk_population_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_set_columns(tsk_population_table_t *self, tsk_size_t num_rows,\n    const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param metadata The array of char metadata values to be copied.\n@param metadata_offset The array of tsk_size_t metadata offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_append_columns(tsk_population_table_t *self,\n    tsk_size_t num_rows, const char *metadata, const tsk_size_t *metadata_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_set_max_rows_increment(\n    tsk_population_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the metadata column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_population_table_t object.\n@param max_metadata_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_population_table_set_max_metadata_length_increment(\n    tsk_population_table_t *self, tsk_size_t max_metadata_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\n\nint tsk_population_table_dump_text(const tsk_population_table_t *self, FILE *out);\n\n/**\n@defgroup PROVENANCE_TABLE_API_GROUP Provenance table API.\n@{\n*/\n\n/**\n@brief Initialises the table by allocating the internal memory.\n\n@rst\nThis must be called before any operations are performed on the table.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n@endrst\n\n@param self A pointer to an uninitialised tsk_provenance_table_t object.\n@param options Allocation time options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_init(tsk_provenance_table_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table.\n\n@param self A pointer to an initialised tsk_provenance_table_t object.\n@return Always returns 0.\n*/\nint tsk_provenance_table_free(tsk_provenance_table_t *self);\n\n/**\n@brief Adds a row to this provenance table.\n\n@rst\nAdd a new provenance with the specified ``timestamp`` and ``record`` to the table.\nCopies of the ``timestamp`` and ``record`` are immediately taken.\nSee the :ref:`table definition <sec_provenance_table_definition>`\nfor details of the columns in this table.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param timestamp The timestamp to be associated with the new provenance. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``timestamp_length`` is 0.\n@param timestamp_length The size of the timestamp array in bytes.\n@param record The record to be associated with the new provenance. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``record_length`` is 0.\n@param record_length The size of the record array in bytes.\n@return Return the ID of the newly added provenance on success,\n    or a negative value on failure.\n*/\ntsk_id_t tsk_provenance_table_add_row(tsk_provenance_table_t *self,\n    const char *timestamp, tsk_size_t timestamp_length, const char *record,\n    tsk_size_t record_length);\n\n/**\n@brief Updates the row at the specified index.\n\n@rst\nRewrite the row at the specified index in this table to use the specified\nvalues. Copies of the ``timestamp`` and ``record`` parameters are taken\nimmediately. See the :ref:`table definition <sec_provenance_table_definition>`\nfor details of the columns in this table.\n\n.. warning::\n    Because of the way that ragged columns are encoded, this method requires a\n    full rewrite of the internal column memory in worst case, and would\n    therefore be inefficient for bulk updates for such columns. However, if the\n    sizes of all ragged column values are unchanged in the updated row, this\n    method is guaranteed to only update the memory for the row in question.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param index The row to update.\n@param timestamp The timestamp to be associated with new provenance. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``timestamp_length`` is 0.\n@param timestamp_length The size of the timestamp array in bytes.\n@param record The record to be associated with the provenance. This\n    is a pointer to arbitrary memory. Can be ``NULL`` if ``record_length`` is 0.\n@param record_length The size of the record array in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_update_row(tsk_provenance_table_t *self, tsk_id_t index,\n    const char *timestamp, tsk_size_t timestamp_length, const char *record,\n    tsk_size_t record_length);\n\n/**\n@brief Clears this table, setting the number of rows to zero.\n\n@rst\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_provenance_table_free` to free the table's internal resources.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_clear(tsk_provenance_table_t *self);\n\n/**\n@brief Truncates this table so that only the first num_rows are retained.\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param num_rows The number of rows to retain in the table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_truncate(tsk_provenance_table_t *self, tsk_size_t num_rows);\n\n/**\n@brief Extends this table by appending rows copied from another table.\n\n@rst\nAppends the rows at the specified indexes from the table ``other`` to the end of this\ntable. Row indexes can be repeated and in any order. If ``row_indexes`` is NULL, append\nthe first ``num_rows`` from ``other`` to this table.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object where rows are to be added.\n@param other A pointer to a tsk_provenance_table_t object where rows are copied from.\n@param num_rows The number of rows from ``other`` to append to this table.\n@param row_indexes Array of row indexes in ``other``. If ``NULL`` is passed then the\n    first ``num_rows`` of ``other`` are used.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_extend(tsk_provenance_table_t *self,\n    const tsk_provenance_table_t *other, tsk_size_t num_rows,\n    const tsk_id_t *row_indexes, tsk_flags_t options);\n\n/**\n@brief Subset this table by keeping rows according to a boolean mask.\n\n@rst\nDeletes rows from this table and optionally return the mapping from IDs in\nthe current table to the updated table. Rows are kept or deleted according to\nthe specified boolean array ``keep`` such that for each row ``j`` if\n``keep[j]`` is false (zero) the row is deleted, and otherwise the row is\nretained. Thus, ``keep`` must be an array of at least ``num_rows``\n:c:type:`bool` values.\n\nIf the ``id_map`` argument is non-null, this array will be updated to represent\nthe mapping between IDs before and after row deletion. For row ``j``,\n``id_map[j]`` will contain the new ID for row ``j`` if it is retained, or\n:c:macro:`TSK_NULL` if the row has been removed. Thus, ``id_map`` must be an\narray of at least ``num_rows`` :c:type:`tsk_id_t` values.\n\n.. warning::\n    C++ users need to be careful to specify the correct type when\n    passing in values for the ``keep`` array,\n    using ``std::vector<tsk_bool_t>`` and not ``std::vector<bool>``,\n    as the latter may not be correct size.\n\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param keep Array of boolean flags describing whether a particular\n    row should be kept or not. Must be at least ``num_rows`` long.\n@param options Bitwise option flags. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@param id_map An array in which to store the mapping between new\n    and old IDs. If NULL, this will be ignored.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_keep_rows(tsk_provenance_table_t *self, const tsk_bool_t *keep,\n    tsk_flags_t options, tsk_id_t *id_map);\n\n/**\n@brief Returns true if the data in the specified table is identical to the data\n       in this table.\n\n@rst\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) tables are\nconsidered equal if they are byte-wise identical in all columns.\n\n- :c:macro:`TSK_CMP_IGNORE_TIMESTAMPS`\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param other A pointer to a tsk_provenance_table_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table is equal to this table.\n*/\nbool tsk_provenance_table_equals(const tsk_provenance_table_t *self,\n    const tsk_provenance_table_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param dest A pointer to a tsk_provenance_table_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised provenance table. If not, it must be an\nuninitialised provenance table.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_copy(const tsk_provenance_table_t *self,\n    tsk_provenance_table_t *dest, tsk_flags_t options);\n\n/**\n@brief Get the row at the specified index.\n\n@rst\nUpdates the specified provenance struct to reflect the values in the specified row.\nPointers to memory within this struct are handled by the table and should **not**\nbe freed by client code. These pointers are guaranteed to be valid until the\nnext operation that modifies the table (e.g., by adding a new row), but not afterwards.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param index The requested table row.\n@param row A pointer to a tsk_provenance_t struct that is updated to reflect the\n    values in the specified row.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_get_row(\n    const tsk_provenance_table_t *self, tsk_id_t index, tsk_provenance_t *row);\n\n/**\n@brief Print out the state of this table to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_provenance_table_print_state(const tsk_provenance_table_t *self, FILE *out);\n\n/**\n@brief Replace this table's data by copying from a set of column arrays\n\n@rst\nClears the data columns of this table and then copies column data from the specified\nset of arrays. The supplied arrays should all contain data on the same number of rows.\nThe metadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param timestamp The array of char timestamp values to be copied.\n@param timestamp_offset The array of tsk_size_t timestamp offset values to be copied.\n@param record The array of char record values to be copied.\n@param record_offset The array of tsk_size_t record offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_set_columns(tsk_provenance_table_t *self, tsk_size_t num_rows,\n    const char *timestamp, const tsk_size_t *timestamp_offset, const char *record,\n    const tsk_size_t *record_offset);\n\n/**\n@brief Extends this table by copying from a set of column arrays\n\n@rst\nCopies column data from the specified set of arrays to create new rows at the end of the\ntable. The supplied arrays should all contain data on the same number of rows. The\nmetadata schema is not affected.\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param num_rows The number of rows to copy from the specifed arrays.\n@param timestamp The array of char timestamp values to be copied.\n@param timestamp_offset The array of tsk_size_t timestamp offset values to be copied.\n@param record The array of char record values to be copied.\n@param record_offset The array of tsk_size_t record offset values to be copied.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_append_columns(tsk_provenance_table_t *self,\n    tsk_size_t num_rows, const char *timestamp, const tsk_size_t *timestamp_offset,\n    const char *record, const tsk_size_t *record_offset);\n\n/**\n@brief Controls the pre-allocation strategy for this table\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param max_rows_increment The number of rows to pre-allocate, or zero for the default\n    doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_set_max_rows_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_rows_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the timestamp column\n\n@rst\nSet a fixed pre-allocation size, or use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param max_timestamp_length_increment The number of bytes to pre-allocate, or zero for\nthe default doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_set_max_timestamp_length_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_timestamp_length_increment);\n\n/**\n@brief Controls the pre-allocation strategy for the record column\n\n@rst\nSet a fixed pre-allocation size, use the default doubling strategy.\nSee :ref:`sec_c_api_memory_allocation_strategy` for details on the default\npre-allocation strategy,\n@endrst\n\n@param self A pointer to a tsk_provenance_table_t object.\n@param max_record_length_increment The number of bytes to pre-allocate, or zero for the\ndefault doubling strategy.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_provenance_table_set_max_record_length_increment(\n    tsk_provenance_table_t *self, tsk_size_t max_record_length_increment);\n\n/** @} */\n\n/* Undocumented methods */\nint tsk_provenance_table_dump_text(const tsk_provenance_table_t *self, FILE *out);\n\n/****************************************************************************/\n/* Table collection .*/\n/****************************************************************************/\n\n/**\n@defgroup TABLE_COLLECTION_API_GROUP Table collection API.\n@{\n*/\n\n/**\n@brief Initialises the table collection by allocating the internal memory\n       and initialising all the constituent tables.\n\n@rst\nThis must be called before any operations are performed on the table\ncollection. See the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n\n**Options**\n\nOptions can be specified by providing bitwise flags:\n\n- :c:macro:`TSK_TC_NO_EDGE_METADATA`\n@endrst\n\n@param self A pointer to an uninitialised tsk_table_collection_t object.\n@param options Allocation time options as above.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_init(tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified table collection.\n\n@param self A pointer to an initialised tsk_table_collection_t object.\n@return Always returns 0.\n*/\nint tsk_table_collection_free(tsk_table_collection_t *self);\n\n/**\n@brief Clears data tables (and optionally provenances and metadata) in\nthis table collection.\n\n@rst\nBy default this operation clears all tables except the provenance table, retaining\ntable metadata schemas and the tree-sequence level metadata and schema.\n\nNo memory is freed as a result of this operation; please use\n:c:func:`tsk_table_collection_free` to free internal resources.\n\n**Options**\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_CLEAR_PROVENANCE`\n- :c:macro:`TSK_CLEAR_METADATA_SCHEMAS`\n- :c:macro:`TSK_CLEAR_TS_METADATA_AND_SCHEMA`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Bitwise clearing options.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_clear(tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Returns true if the data in the specified table collection is equal\n    to the data in this table collection.\n\n@rst\n\nReturns true if the two table collections are equal. The indexes are\nnot considered as these are derived from the tables. We also do not\nconsider the ``file_uuid``, since it is a property of the file that set\nof tables is stored in.\n\n**Options**\n\nOptions to control the comparison can be specified by providing one or\nmore of the following bitwise flags. By default (options=0) two table\ncollections are considered equal if all of the tables are byte-wise\nidentical, and the sequence lengths, metadata and metadata schemas\nof the two table collections are identical.\n\n- :c:macro:`TSK_CMP_IGNORE_PROVENANCE`\n- :c:macro:`TSK_CMP_IGNORE_METADATA`\n- :c:macro:`TSK_CMP_IGNORE_TS_METADATA`\n- :c:macro:`TSK_CMP_IGNORE_TIMESTAMPS`\n- :c:macro:`TSK_CMP_IGNORE_TABLES`\n- :c:macro:`TSK_CMP_IGNORE_REFERENCE_SEQUENCE`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param other A pointer to a tsk_table_collection_t object.\n@param options Bitwise comparison options.\n@return Return true if the specified table collection is equal to this table.\n*/\nbool tsk_table_collection_equals(const tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, tsk_flags_t options);\n\n/**\n@brief Copies the state of this table collection into the specified destination.\n\n@rst\nBy default the method initialises the specified destination table collection. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n\n**Options**\n\nOptions can be specified by providing bitwise flags:\n\n:c:macro:`TSK_COPY_FILE_UUID`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param dest A pointer to a tsk_table_collection_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised table collection. If not, it must be an\nuninitialised table collection.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_copy(const tsk_table_collection_t *self,\n    tsk_table_collection_t *dest, tsk_flags_t options);\n\n/**\n@brief Print out the state of this table collection to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_table_collection_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_table_collection_print_state(const tsk_table_collection_t *self, FILE *out);\n\n/**\n@brief Load a table collection from a file path.\n\n@rst\nLoads the data from the specified file into this table collection.\nBy default, the table collection is also initialised.\nThe resources allocated must be freed using\n:c:func:`tsk_table_collection_free` even in error conditions.\n\nIf the :c:macro:`TSK_NO_INIT` option is set, the table collection is\nnot initialised, allowing an already initialised table collection to\nbe overwritten with the data from a file.\n\nIf the file contains multiple table collections, this function will load\nthe first. Please see the :c:func:`tsk_table_collection_loadf` for details\non how to sequentially load table collections from a stream.\n\nIf the :c:macro:`TSK_LOAD_SKIP_TABLES` option is set, only the non-table information from\nthe table collection will be read, leaving all tables with zero rows and no\nmetadata or schema.\nIf the :c:macro:`TSK_LOAD_SKIP_REFERENCE_SEQUENCE` option is set, the table collection is\nread without loading the reference sequence.\n\n**Options**\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_NO_INIT`\n- :c:macro:`TSK_LOAD_SKIP_TABLES`\n- :c:macro:`TSK_LOAD_SKIP_REFERENCE_SEQUENCE`\n\n**Examples**\n\n.. code-block:: c\n\n    int ret;\n    tsk_table_collection_t tables;\n    ret = tsk_table_collection_load(&tables, \"data.trees\", 0);\n    if (ret != 0) {\n        fprintf(stderr, \"Load error:%s\\n\", tsk_strerror(ret));\n        exit(EXIT_FAILURE);\n    }\n\n@endrst\n\n@param self A pointer to an uninitialised tsk_table_collection_t object\n    if the TSK_NO_INIT option is not set (default), or an initialised\n    tsk_table_collection_t otherwise.\n@param filename A NULL terminated string containing the filename.\n@param options Bitwise options. See above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_load(\n    tsk_table_collection_t *self, const char *filename, tsk_flags_t options);\n\n/**\n@brief Load a table collection from a stream.\n\n@rst\nLoads a tables definition from the specified file stream to this table\ncollection. By default, the table collection is also initialised.\nThe resources allocated must be freed using\n:c:func:`tsk_table_collection_free` even in error conditions.\n\nIf the :c:macro:`TSK_NO_INIT` option is set, the table collection is\nnot initialised, allowing an already initialised table collection to\nbe overwritten with the data from a file.\n\nThe stream can be an arbitrary file descriptor, for example a network socket.\nNo seek operations are performed.\n\nIf the stream contains multiple table collection definitions, this function\nwill load the next table collection from the stream. If the stream contains no\nmore table collection definitions the error value :c:macro:`TSK_ERR_EOF` will\nbe returned. Note that EOF is only returned in the case where zero bytes are\nread from the stream --- malformed files or other errors will result in\ndifferent error conditions. Please see the\n:ref:`sec_c_api_examples_file_streaming` section for an example of how to\nsequentially load tree sequences from a stream.\n\nPlease note that this streaming behaviour is not supported if the\n:c:macro:`TSK_LOAD_SKIP_TABLES` or :c:macro:`TSK_LOAD_SKIP_REFERENCE_SEQUENCE` option is\nset. If the :c:macro:`TSK_LOAD_SKIP_TABLES` option is set, only the non-table information\nfrom the table collection will be read, leaving all tables with zero rows and no metadata\nor schema. If the :c:macro:`TSK_LOAD_SKIP_REFERENCE_SEQUENCE` option is set, the table\ncollection is read without loading the reference sequence. When attempting to read from a\nstream with multiple table collection definitions and either of these two options set,\nthe requested information from the first table collection will be read on the first call\nto :c:func:`tsk_table_collection_loadf`, with subsequent calls leading to errors.\n\n**Options**\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_NO_INIT`\n- :c:macro:`TSK_LOAD_SKIP_TABLES`\n- :c:macro:`TSK_LOAD_SKIP_REFERENCE_SEQUENCE`\n@endrst\n\n@param self A pointer to an uninitialised tsk_table_collection_t object\n    if the TSK_NO_INIT option is not set (default), or an initialised\n    tsk_table_collection_t otherwise.\n@param file A FILE stream opened in an appropriate mode for reading (e.g.\n    \"r\", \"r+\" or \"w+\") positioned at the beginning of a table collection\n    definition.\n@param options Bitwise options. See above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_loadf(\n    tsk_table_collection_t *self, FILE *file, tsk_flags_t options);\n\n/**\n@brief Write a table collection to file.\n\n@rst\nWrites the data from this table collection to the specified file.\n\nIf an error occurs the file path is deleted, ensuring that only complete\nand well formed files will be written.\n\n**Examples**\n\n.. code-block:: c\n\n    int ret;\n    tsk_table_collection_t tables;\n\n    ret = tsk_table_collection_init(&tables, 0);\n    error_check(ret);\n    tables.sequence_length = 1.0;\n    // Write out the empty tree sequence\n    ret = tsk_table_collection_dump(&tables, \"empty.trees\", 0);\n    error_check(ret);\n\n@endrst\n\n@param self A pointer to an initialised tsk_table_collection_t object.\n@param filename A NULL terminated string containing the filename.\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_dump(\n    const tsk_table_collection_t *self, const char *filename, tsk_flags_t options);\n\n/**\n@brief Write a table collection to a stream.\n\n@rst\nWrites the data from this table collection to the specified FILE stream.\nSemantics are identical to :c:func:`tsk_table_collection_dump`.\n\nPlease see the :ref:`sec_c_api_examples_file_streaming` section for an example\nof how to sequentially dump and load tree sequences from a stream.\n\n@endrst\n\n@param self A pointer to an initialised tsk_table_collection_t object.\n@param file A FILE stream opened in an appropriate mode for writing (e.g.\n    \"w\", \"a\", \"r+\" or \"w+\").\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_dumpf(\n    const tsk_table_collection_t *self, FILE *file, tsk_flags_t options);\n\n/**\n@brief Record the number of rows in each table in the specified tsk_bookmark_t object.\n\n@param self A pointer to an initialised tsk_table_collection_t object.\n@param bookmark A pointer to a tsk_bookmark_t which is updated to contain the number of\n    rows in all tables.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_record_num_rows(\n    const tsk_table_collection_t *self, tsk_bookmark_t *bookmark);\n\n/**\n@brief Truncates the tables in this table collection according to the specified bookmark.\n\n@rst\nTruncate the tables in this collection so that each one has the number\nof rows specified in the parameter :c:type:`tsk_bookmark_t`. Use the\n:c:func:`tsk_table_collection_record_num_rows` function to record the\nnumber rows for each table in a table collection at a particular time.\n@endrst\n\n@param self A pointer to a tsk_individual_table_t object.\n@param bookmark The number of rows to retain in each table.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_truncate(\n    tsk_table_collection_t *self, tsk_bookmark_t *bookmark);\n\n/**\n@brief Sorts the tables in this collection.\n\n@rst\nSome of the tables in a table collection must satisfy specific sortedness requirements\nin order to define a :ref:`valid tree sequence <sec_valid_tree_sequence_requirements>`.\nThis method sorts the ``edge``, ``site``, ``mutation`` and ``individual`` tables such\nthat these requirements are guaranteed to be fulfilled. The ``node``, ``population``\nand ``provenance`` tables do not have any sortedness requirements, and are therefore\nignored by this method.\n\n.. note:: The current implementation **may** sort in such a way that exceeds\n    these requirements, but this behaviour should not be relied upon and later\n    versions may weaken the level of sortedness. However, the method does **guarantee**\n    that the resulting tables describes a valid tree sequence.\n\n.. warning:: Sorting migrations is currently not supported and an error will be raised\n    if a table collection containing a non-empty migration table is specified.\n\nThe specified :c:type:`tsk_bookmark_t` allows us to specify a start position\nfor sorting in each of the tables; rows before this value are assumed to already be\nin sorted order and this information is used to make sorting more efficient.\nPositions in tables that are not sorted (``node``, ``population``\nand ``provenance``) are ignored and can be set to arbitrary values.\n\n.. warning:: The current implementation only supports specifying a start\n    position for the ``edge`` table and in a limited form for the\n    ``site``, ``mutation`` and ``individual`` tables. Specifying a non-zero\n    ``migration``, start position results in an error. The start positions for the\n    ``site``, ``mutation`` and ``individual`` tables can either be 0 or the length of the\n    respective tables, allowing these tables to either be fully sorted, or not sorted at\n    all.\n\nThe table collection will always be unindexed after sort successfully completes.\n\nFor more control over the sorting process, see the :ref:`sec_c_api_low_level_sorting`\nsection.\n\n**Options**\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n:c:macro:`TSK_NO_CHECK_INTEGRITY`\n    Do not run integrity checks using\n    :c:func:`tsk_table_collection_check_integrity` before sorting,\n    potentially leading to a small reduction in execution time. This\n    performance optimisation should not be used unless the calling code can\n    guarantee reference integrity within the table collection. References\n    to rows not in the table or bad offsets will result in undefined\n    behaviour.\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param start The position to begin sorting in each table; all rows less than this\n    position must fulfill the tree sequence sortedness requirements. If this is\n    NULL, sort all rows.\n@param options Sort options.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_sort(\n    tsk_table_collection_t *self, const tsk_bookmark_t *start, tsk_flags_t options);\n\n/**\n@brief Sorts the individual table in this collection.\n\n@rst\nSorts the individual table in place, so that parents come before children,\nand the parent column is remapped as required. Node references to individuals\nare also updated.\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Sort options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_individual_topological_sort(\n    tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Puts the tables into canonical form.\n\n@rst\nPut tables into canonical form such that randomly reshuffled tables\nare guaranteed to always be sorted in the same order, and redundant\ninformation is removed. The canonical sorting exceeds the usual\ntree sequence sortedness requirements.\n\n**Options**:\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_SUBSET_KEEP_UNREFERENCED`\n\n@endrst\n\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_canonicalise(tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Simplify the tables to remove redundant information.\n\n@rst\nSimplification transforms the tables to remove redundancy and canonicalise\ntree sequence data. See the :ref:`simplification <sec_simplification>` tutorial for\nmore details.\n\nA mapping from the node IDs in the table before simplification to their equivalent\nvalues after simplification can be obtained via the ``node_map`` argument. If this\nis non NULL, ``node_map[u]`` will contain the new ID for node ``u`` after simplification,\nor :c:macro:`TSK_NULL` if the node has been removed. Thus, ``node_map`` must be an array\nof at least ``self->nodes.num_rows`` :c:type:`tsk_id_t` values.\n\nIf the `TSK_SIMPLIFY_NO_FILTER_NODES` option is specified, the node table will be\nunaltered except for changing the sample status of nodes (but see the\n`TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS` option below) and to update references\nto other tables that may have changed as a result of filtering (see below).\nThe ``node_map`` (if specified) will always be the identity mapping, such that\n``node_map[u] == u`` for all nodes. Note also that the order of the list of\nsamples is not important in this case.\n\nWhen a table is not filtered (i.e., if the `TSK_SIMPLIFY_NO_FILTER_NODES`\noption is provided or the `TSK_SIMPLIFY_FILTER_SITES`,\n`TSK_SIMPLIFY_FILTER_POPULATIONS` or `TSK_SIMPLIFY_FILTER_INDIVIDUALS`\noptions are *not* provided) the corresponding table is modified as\nlittle as possible, and all pointers are guaranteed to remain valid\nafter simplification. The only changes made to an unfiltered table are\nto update any references to tables that may have changed (for example,\nremapping population IDs in the node table if\n`TSK_SIMPLIFY_FILTER_POPULATIONS` was specified) or altering the\nsample status flag of nodes.\n\n.. note:: It is possible for populations and individuals to be filtered\n   even if `TSK_SIMPLIFY_NO_FILTER_NODES` is specified because there\n   may be entirely unreferenced entities in the input tables, which\n   are not affected by whether we filter nodes or not.\n\nBy default, the node sample flags are updated by unsetting the\n:c:macro:`TSK_NODE_IS_SAMPLE` flag for all nodes and subsequently setting it\nfor the nodes provided as input to this function. The\n`TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS` option will prevent this from occuring,\nmaking it the responsibility of calling code to keep track of the ultimate\nsample status of nodes. Using this option in conjunction with\n`TSK_SIMPLIFY_NO_FILTER_NODES` (and without the\n`TSK_SIMPLIFY_FILTER_POPULATIONS` and `TSK_SIMPLIFY_FILTER_INDIVIDUALS`\noptions) guarantees that the node table will not be written to during the\nlifetime of this function.\n\nThe table collection will always be unindexed after simplify successfully completes.\n\n.. note:: Migrations are currently not supported by simplify, and an error will\n    be raised if we attempt call simplify on a table collection with greater\n    than zero migrations. See `<https://github.com/tskit-dev/tskit/issues/20>`_\n\n**Options**:\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_SIMPLIFY_FILTER_SITES`\n- :c:macro:`TSK_SIMPLIFY_FILTER_POPULATIONS`\n- :c:macro:`TSK_SIMPLIFY_FILTER_INDIVIDUALS`\n- :c:macro:`TSK_SIMPLIFY_NO_FILTER_NODES`\n- :c:macro:`TSK_SIMPLIFY_NO_UPDATE_SAMPLE_FLAGS`\n- :c:macro:`TSK_SIMPLIFY_REDUCE_TO_SITE_TOPOLOGY`\n- :c:macro:`TSK_SIMPLIFY_KEEP_UNARY`\n- :c:macro:`TSK_SIMPLIFY_KEEP_INPUT_ROOTS`\n- :c:macro:`TSK_SIMPLIFY_KEEP_UNARY_IN_INDIVIDUALS`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param samples Either NULL or an array of num_samples distinct and valid node IDs.\n    If non-null the nodes in this array will be marked as samples in the output.\n    If NULL, the num_samples parameter is ignored and the samples in the output\n    will be the same as the samples in the input. This is equivalent to populating\n    the samples array with all of the sample nodes in the input in increasing\n    order of ID.\n@param num_samples The number of node IDs in the input samples array. Ignored\n    if the samples array is NULL.\n@param options Simplify options; see above for the available bitwise flags.\n    For the default behaviour, a value of 0 should be provided.\n@param node_map If not NULL, this array will be filled to define the mapping\n    between nodes IDs in the table collection before and after simplification.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_simplify(tsk_table_collection_t *self, const tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_flags_t options, tsk_id_t *node_map);\n\n/**\n@brief Subsets and reorders a table collection according to an array of nodes.\n\n@rst\nReduces the table collection to contain only the entries referring to\nthe provided list of nodes, with nodes reordered according to the order\nthey appear in the ``nodes`` argument. Specifically, this subsets and reorders\neach of the tables as follows (but see options, below):\n\n1. Nodes: if in the list of nodes, and in the order provided.\n2. Individuals: if referred to by a retained node.\n3. Populations: if referred to by a retained node, and in the order first seen\n   when traversing the list of retained nodes.\n4. Edges: if both parent and child are retained nodes.\n5. Mutations: if the mutation's node is a retained node.\n6. Sites: if any mutations remain at the site after removing mutations.\n\nRetained individuals, edges, mutations, and sites appear in the same\norder as in the original tables. Note that only the information *directly*\nassociated with the provided nodes is retained - for instance,\nsubsetting to nodes=[A, B] does not retain nodes ancestral to A and B,\nand only retains the individuals A and B are in, and not their parents.\n\nThis function does *not* require the tables to be sorted.\n\n.. note:: Migrations are currently not supported by subset, and an error will\n    be raised if we attempt call subset on a table collection with greater\n    than zero migrations.\n\n**Options**:\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_SUBSET_NO_CHANGE_POPULATIONS`\n- :c:macro:`TSK_SUBSET_KEEP_UNREFERENCED`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param nodes An array of num_nodes valid node IDs.\n@param num_nodes The number of node IDs in the input nodes array.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_subset(tsk_table_collection_t *self, const tsk_id_t *nodes,\n    tsk_size_t num_nodes, tsk_flags_t options);\n\n/**\n@brief Forms the node-wise union of two table collections.\n\n@rst\nExpands this table collection by adding the non-shared portions of another table\ncollection to itself. The ``other_node_mapping`` encodes which nodes in ``other`` are\nequivalent to a node in ``self``. The positions in the ``other_node_mapping`` array\ncorrespond to node ids in ``other``, and the elements encode the equivalent\nnode id in ``self`` or :c:macro:`TSK_NULL` if the node is exclusive to ``other``. Nodes\nthat are exclusive ``other`` are added to ``self``, along with:\n\n1. Individuals which are new to ``self``.\n2. Edges whose parent or child are new to ``self``.\n3. Sites which were not present in ``self``.\n4. Mutations whose nodes are new to ``self``.\n\nBy default, populations of newly added nodes are assumed to be new populations,\nand added to the population table as well.\n\nThe behavior can be changed by the flags ``TSK_UNION_ALL_EDGES`` and\n``TSK_UNION_ALL_MUTATIONS``, which will (respectively) add *all* edges\nor *all* sites and mutations instead.\n\nThis operation will also sort the resulting tables, so the tables may change\neven if nothing new is added, if the original tables were not sorted.\n\n.. note:: Migrations are currently not supported by union, and an error will\n    be raised if we attempt call union on a table collection with migrations.\n\n**Options**:\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_UNION_NO_CHECK_SHARED`\n- :c:macro:`TSK_UNION_NO_ADD_POP`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param other A pointer to a tsk_table_collection_t object.\n@param other_node_mapping An array of node IDs that relate nodes in other to nodes in\nself: the k-th element of other_node_mapping should be the index of the equivalent\nnode in self, or TSK_NULL if the node is not present in self (in which case it\nwill be added to self).\n@param options Union options; see above for the available bitwise flags.\n    For the default behaviour, a value of 0 should be provided.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_union(tsk_table_collection_t *self,\n    const tsk_table_collection_t *other, const tsk_id_t *other_node_mapping,\n    tsk_flags_t options);\n\n/**\n@brief Set the time_units\n@rst\nCopies the time_units string to this table collection, replacing any existing.\n@endrst\n@param self A pointer to a tsk_table_collection_t object.\n@param time_units A pointer to a char array.\n@param time_units_length The size of the time units string in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_set_time_units(\n    tsk_table_collection_t *self, const char *time_units, tsk_size_t time_units_length);\n\n/**\n@brief Set the metadata\n@rst\nCopies the metadata string to this table collection, replacing any existing.\n@endrst\n@param self A pointer to a tsk_table_collection_t object.\n@param metadata A pointer to a char array.\n@param metadata_length The size of the metadata in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_set_metadata(\n    tsk_table_collection_t *self, const char *metadata, tsk_size_t metadata_length);\n\n/**\n@brief Set the metadata schema\n@rst\nCopies the metadata schema string to this table collection, replacing any existing.\n@endrst\n@param self A pointer to a tsk_table_collection_t object.\n@param metadata_schema A pointer to a char array.\n@param metadata_schema_length The size of the metadata schema in bytes.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_set_metadata_schema(tsk_table_collection_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\n\n/**\n@brief Returns true if this table collection is indexed.\n\n@rst\nThis method returns true if the table collection has an index\nfor the edge table. It guarantees that the index exists, and that\nit is for the same number of edges that are in the edge table. It\ndoes *not* guarantee that the index is valid (i.e., if the rows\nin the edge have been permuted in some way since the index was built).\n\nSee the :ref:`sec_c_api_table_indexes` section for details on the index\nlife-cycle.\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return true if there is an index present for this table collection.\n*/\nbool tsk_table_collection_has_index(\n    const tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Deletes the indexes for this table collection.\n\n@rst\nUnconditionally drop the indexes that may be present for this table collection. It\nis not an error to call this method on an unindexed table collection.\nSee the :ref:`sec_c_api_table_indexes` section for details on the index\nlife-cycle.\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Always returns 0.\n*/\nint tsk_table_collection_drop_index(tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Builds indexes for this table collection.\n\n@rst\nBuilds the tree traversal :ref:`indexes <sec_table_indexes>` for this table\ncollection. Any existing index is first dropped using\n:c:func:`tsk_table_collection_drop_index`. See the\n:ref:`sec_c_api_table_indexes` section for details on the index life-cycle.\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_collection_build_index(tsk_table_collection_t *self, tsk_flags_t options);\n\n/**\n@brief Runs integrity checks on this table collection.\n\n@rst\n\nChecks the integrity of this table collection. The default checks (i.e., with\noptions = 0) guarantee the integrity of memory and entity references within the\ntable collection. All positions along the genome are checked\nto see if they are finite values and within the required bounds. Time values\nare checked to see if they are finite or marked as unknown.\nConsistency of the direction of inheritance is also checked: whether\nparents are more recent than children, mutations are not more recent\nthan their nodes or their mutation parents, etcetera.\n\nTo check if a set of tables fulfills the :ref:`requirements\n<sec_valid_tree_sequence_requirements>` needed for a valid tree sequence, use\nthe :c:macro:`TSK_CHECK_TREES` option. When this method is called with\n:c:macro:`TSK_CHECK_TREES`, the number of trees in the tree sequence is returned. Thus,\nto check for errors client code should verify that the return value is less than zero.\nAll other options will return zero on success and a negative value on failure.\n\nMore fine-grained checks can be achieved using bitwise combinations of the\nother options.\n\n**Options**:\n\nOptions can be specified by providing one or more of the following bitwise\nflags:\n\n- :c:macro:`TSK_CHECK_EDGE_ORDERING`\n- :c:macro:`TSK_CHECK_SITE_ORDERING`\n- :c:macro:`TSK_CHECK_SITE_DUPLICATES`\n- :c:macro:`TSK_CHECK_MUTATION_ORDERING`\n- :c:macro:`TSK_CHECK_INDIVIDUAL_ORDERING`\n- :c:macro:`TSK_CHECK_MIGRATION_ORDERING`\n- :c:macro:`TSK_CHECK_INDEXES`\n- :c:macro:`TSK_CHECK_TREES`\n- :c:macro:`TSK_NO_CHECK_POPULATION_REFS`\n@endrst\n\n@param self A pointer to a tsk_table_collection_t object.\n@param options Bitwise options.\n@return Return a negative error value on if any problems are detected\n   in the tree sequence. If the TSK_CHECK_TREES option is provided,\n   the number of trees in the tree sequence will be returned, on\n   success.\n*/\ntsk_id_t tsk_table_collection_check_integrity(\n    const tsk_table_collection_t *self, tsk_flags_t options);\n\n/** @} */\n\n/* Undocumented methods */\n\n/* Flags for ibd_segments */\n#define TSK_IBD_STORE_PAIRS (1 << 0)\n#define TSK_IBD_STORE_SEGMENTS (1 << 1)\n\n/* TODO be systematic about where \"result\" should be in the params\n * list, different here and in link_ancestors. */\n/* FIXME the order of num_samples and samples needs to be reversed in within.\n * This should be done as part of documenting, I guess. */\nint tsk_table_collection_ibd_within(const tsk_table_collection_t *self,\n    tsk_identity_segments_t *result, const tsk_id_t *samples, tsk_size_t num_samples,\n    double min_span, double max_time, tsk_flags_t options);\n\nint tsk_table_collection_ibd_between(const tsk_table_collection_t *self,\n    tsk_identity_segments_t *result, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, double min_span,\n    double max_time, tsk_flags_t options);\n\nint tsk_table_collection_link_ancestors(tsk_table_collection_t *self, tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_id_t *ancestors, tsk_size_t num_ancestors,\n    tsk_flags_t options, tsk_edge_table_t *result);\nint tsk_table_collection_deduplicate_sites(\n    tsk_table_collection_t *tables, tsk_flags_t options);\nint tsk_table_collection_compute_mutation_parents(\n    tsk_table_collection_t *self, tsk_flags_t options);\nint tsk_table_collection_compute_mutation_times(\n    tsk_table_collection_t *self, double *random, tsk_flags_t options);\nint tsk_table_collection_delete_older(\n    tsk_table_collection_t *self, double time, tsk_flags_t options);\n\nint tsk_table_collection_set_indexes(tsk_table_collection_t *self,\n    tsk_id_t *edge_insertion_order, tsk_id_t *edge_removal_order);\n\nint tsk_table_collection_takeset_metadata(\n    tsk_table_collection_t *self, char *metadata, tsk_size_t metadata_length);\nint tsk_table_collection_takeset_indexes(tsk_table_collection_t *self,\n    tsk_id_t *edge_insertion_order, tsk_id_t *edge_removal_order);\nint tsk_individual_table_takeset_columns(tsk_individual_table_t *self,\n    tsk_size_t num_rows, tsk_flags_t *flags, double *location,\n    tsk_size_t *location_offset, tsk_id_t *parents, tsk_size_t *parents_offset,\n    char *metadata, tsk_size_t *metadata_offset);\nint tsk_node_table_takeset_columns(tsk_node_table_t *self, tsk_size_t num_rows,\n    tsk_flags_t *flags, double *time, tsk_id_t *population, tsk_id_t *individual,\n    char *metadata, tsk_size_t *metadata_offset);\nint tsk_edge_table_takeset_columns(tsk_edge_table_t *self, tsk_size_t num_rows,\n    double *left, double *right, tsk_id_t *parent, tsk_id_t *child, char *metadata,\n    tsk_size_t *metadata_offset);\nint tsk_migration_table_takeset_columns(tsk_migration_table_t *self, tsk_size_t num_rows,\n    double *left, double *right, tsk_id_t *node, tsk_id_t *source, tsk_id_t *dest,\n    double *time, char *metadata, tsk_size_t *metadata_offset);\nint tsk_site_table_takeset_columns(tsk_site_table_t *self, tsk_size_t num_rows,\n    double *position, char *ancestral_state, tsk_size_t *ancestral_state_offset,\n    char *metadata, tsk_size_t *metadata_offset);\nint tsk_mutation_table_takeset_columns(tsk_mutation_table_t *self, tsk_size_t num_rows,\n    tsk_id_t *site, tsk_id_t *node, tsk_id_t *parent, double *time, char *derived_state,\n    tsk_size_t *derived_state_offset, char *metadata, tsk_size_t *metadata_offset);\nint tsk_population_table_takeset_columns(tsk_population_table_t *self,\n    tsk_size_t num_rows, char *metadata, tsk_size_t *metadata_offset);\nint tsk_provenance_table_takeset_columns(tsk_provenance_table_t *self,\n    tsk_size_t num_rows, char *timestamp, tsk_size_t *timestamp_offset, char *record,\n    tsk_size_t *record_offset);\n\nbool tsk_table_collection_has_reference_sequence(const tsk_table_collection_t *self);\n\nint tsk_reference_sequence_init(tsk_reference_sequence_t *self, tsk_flags_t options);\nint tsk_reference_sequence_free(tsk_reference_sequence_t *self);\nbool tsk_reference_sequence_is_null(const tsk_reference_sequence_t *self);\nbool tsk_reference_sequence_equals(const tsk_reference_sequence_t *self,\n    const tsk_reference_sequence_t *other, tsk_flags_t options);\nint tsk_reference_sequence_copy(const tsk_reference_sequence_t *self,\n    tsk_reference_sequence_t *dest, tsk_flags_t options);\nint tsk_reference_sequence_set_data(\n    tsk_reference_sequence_t *self, const char *data, tsk_size_t data_length);\nint tsk_reference_sequence_set_url(\n    tsk_reference_sequence_t *self, const char *url, tsk_size_t url_length);\nint tsk_reference_sequence_set_metadata(\n    tsk_reference_sequence_t *self, const char *metadata, tsk_size_t metadata_length);\nint tsk_reference_sequence_set_metadata_schema(tsk_reference_sequence_t *self,\n    const char *metadata_schema, tsk_size_t metadata_schema_length);\nint tsk_reference_sequence_takeset_data(\n    tsk_reference_sequence_t *self, char *data, tsk_size_t data_length);\nint tsk_reference_sequence_takeset_metadata(\n    tsk_reference_sequence_t *self, char *metadata, tsk_size_t metadata_length);\n\n/**\n@defgroup TABLE_SORTER_API_GROUP Low-level table sorter API.\n@{\n*/\n\n/* NOTE: We use the \"struct _tsk_table_sorter_t\" form here\n * rather then the usual tsk_table_sorter_t alias because\n * of problems with Doxygen. This was the only way I could\n * get it to work - ideally, we'd use the usual typedefs\n * to avoid confusing people.\n */\n\n/**\n@brief Initialises the memory for the sorter object.\n\n@rst\nThis must be called before any operations are performed on the\ntable sorter and initialises all fields. The ``edge_sort`` function\nis set to the default method using qsort. The ``user_data``\nfield is set to NULL.\nThis method supports the same options as\n:c:func:`tsk_table_collection_sort`.\n\n@endrst\n\n@param self A pointer to an uninitialised tsk_table_sorter_t object.\n@param tables The table collection to sort.\n@param options Sorting options.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_sorter_init(struct _tsk_table_sorter_t *self,\n    tsk_table_collection_t *tables, tsk_flags_t options);\n\n/**\n@brief Runs the sort using the configured functions.\n\n@rst\nRuns the sorting process:\n\n1. Drop the table indexes.\n2. If the ``sort_edges`` function pointer is not NULL, run it. The\n   first parameter to the called function will be a pointer to this\n   table_sorter_t object. The second parameter will be the value\n   ``start.edges``. This specifies the offset at which sorting should\n   start in the edge table. This offset is guaranteed to be within the\n   bounds of the edge table.\n3. Sort the site table, building the mapping between site IDs in the\n   current and sorted tables.\n4. Sort the mutation table, using the ``sort_mutations`` pointer.\n\nIf an error occurs during the execution of a user-supplied\nsorting function a non-zero value must be returned. This value\nwill then be returned by ``tsk_table_sorter_run``. The error\nreturn value should be chosen to avoid conflicts with tskit error\ncodes.\n\nSee :c:func:`tsk_table_collection_sort` for details on the ``start`` parameter.\n\n@endrst\n\n@param self A pointer to a tsk_table_sorter_t object.\n@param start The position in the tables at which sorting starts.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_table_sorter_run(struct _tsk_table_sorter_t *self, const tsk_bookmark_t *start);\n\n/**\n@brief Free the internal memory for the specified table sorter.\n\n@param self A pointer to an initialised tsk_table_sorter_t object.\n@return Always returns 0.\n*/\nint tsk_table_sorter_free(struct _tsk_table_sorter_t *self);\n\n/** @} */\n\nint tsk_squash_edges(\n    tsk_edge_t *edges, tsk_size_t num_edges, tsk_size_t *num_output_edges);\n\n/* IBD segments API. This is experimental and the interface may change. */\n\ntsk_size_t tsk_identity_segments_get_num_segments(const tsk_identity_segments_t *self);\ndouble tsk_identity_segments_get_total_span(const tsk_identity_segments_t *self);\ntsk_size_t tsk_identity_segments_get_num_pairs(const tsk_identity_segments_t *self);\nint tsk_identity_segments_get_keys(\n    const tsk_identity_segments_t *result, tsk_id_t *pairs);\nint tsk_identity_segments_get_items(const tsk_identity_segments_t *self, tsk_id_t *pairs,\n    tsk_identity_segment_list_t **lists);\nint tsk_identity_segments_get(const tsk_identity_segments_t *self, tsk_id_t a,\n    tsk_id_t b, tsk_identity_segment_list_t **ret_list);\nvoid tsk_identity_segments_print_state(tsk_identity_segments_t *self, FILE *out);\nint tsk_identity_segments_free(tsk_identity_segments_t *self);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/text_input.c",
    "content": "#define _GNU_SOURCE\n\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n#include <assert.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <float.h>\n\n#include \"tables.h\"\n#include \"text_input.h\"\n\n\n/*************************\n * load_text\n *************************/\n\n\n/****\n * Simple utilities to parse text, mostly for debugging purposes.\n * General assumptions:\n *  files are strictly tab-separated (columns separated by exactly one tab)\n *  columns are in the expected order\n ****/\n\n\n/* ****\n * Tab-separated parsing:\n * These will be used on null-terminated strings, which are included,\n * so `end`, if not NULL, will always be at least one before the end\n * of the string.\n *\n * These return: \n *   1 if `sep` is found and delimits a nonzero-length token; \n *   0 if `sep` is found as the first character;\n *   and -1 otherwise.\n * ***/\n\nstatic int\nget_sep_atoi(char **start, int *out, int sep)\n{\n    int ret;\n    char *next;\n    next = strchr(*start, sep);\n    if (next == NULL) {\n        ret = -1;\n    } else {\n        ret = (int) (next != *start);\n        *next = '\\0';\n    }\n    *out = atoi(*start);\n    *start = (next == NULL) ? NULL : next + 1;\n    return ret;\n}\n\nstatic int\nget_sep_atof(char **start, double *out, int sep)\n{\n    int ret;\n    char *next;\n    next = strchr(*start, sep);\n    if (next == NULL) {\n        ret = -1;\n    } else {\n        ret = (int) (next != *start);\n        *next = '\\0';\n    }\n    *out = atof(*start);\n    *start = (next == NULL) ? NULL : next + 1;\n    return ret;\n}\n\nstatic int\nget_sep_atoa(char **start, char **out, int sep)\n{\n    int ret;\n    char *next;\n    next = strchr(*start, sep);\n    if (next == NULL) {\n        ret = -1;\n    } else {\n        ret = (int) (next != *start);\n        *next = '\\0';\n    }\n    *out = *start;\n    *start = (next == NULL) ? NULL : next + 1;\n    return ret;\n}\n\n\n// This reads the header line of a file into *linep, just like a call to\n// getline(linep, linecapp, stream), but also eats any metadata header\n// present, returning the first line of it (which should be all of it,\n// if the metadata is compactified as expected) to the caller if requested\n\n// copied from tables.c:\n#define TABLE_SEP \"-----------------------------------------\\n\"\n\nstatic ssize_t\nread_text_headers(char **linep, size_t *linecapp, FILE *file, char **metadata_schema)\n{\n\tssize_t err = getline(linep, linecapp, file);\n\tif (err < 0)\n\t\treturn err;\n\t\n\tchar *local_schema = NULL;\n\t\n\tif (strcmp(*linep, \"#metadata_schema#\\n\") == 0)\n\t{\n\t\tdo {\n\t\t\terr = getline(linep, linecapp, file);\n\t\t\tif (err < 0)\n\t\t\t{\n\t\t\t\tfree(local_schema);\n\t\t\t\treturn err;\n\t\t\t}\n            if (strcmp(*linep, \"#end#metadata_schema\\n\") == 0)\n                break;\n            \n\t\t\t// take the first non-empty line in this section as the full schema; multiline schemas are not understood\n\t\t\t// we keep this in a local variable until we're done, since we don't want to return it if an error occurs\n\t\t\tsize_t schema_len = strlen(*linep);\n\t\t\t\n\t\t\tif (schema_len && !local_schema)\n\t\t\t{\n\t\t\t\tlocal_schema = malloc(schema_len + 1);  // +1 for the NUL\n\t\t\t\tstrcpy(local_schema, *linep);\n\t\t\t\tlocal_schema[schema_len] = '\\0';    // replace the trailing newline with a new NUL\n\t\t\t}\n\t\t} while (true);\n\t\t\n\t\terr = getline(linep, linecapp, file);\n\t\tif (err < 0)\n\t\t{\n\t\t\tfree(local_schema);\n\t\t\treturn err;\n\t\t}\n\t\t\n\t\tif (strcmp(*linep, TABLE_SEP) == 0)\n\t\t\terr = getline(linep, linecapp, file);\n\t\tif (err < 0)\n\t\t{\n\t\t\tfree(local_schema);\n\t\t\treturn err;\n\t\t}\n\t}\n\n\tif (local_schema)\n\t{\n\t\tif ((err >= 0) && metadata_schema && (*metadata_schema == NULL))\n\t\t\t*metadata_schema = local_schema;\n\t\telse\n\t\t\tfree(local_schema);\n\t}\n\t\n\treturn err;\n}\n\n\nint\nnode_table_load_text(tsk_node_table_t *node_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line = NULL;\n    double time;\n    int flags, population, individual, id, is_sample;\n    char *name;\n    const char *header = \"id\\tis_sample\\ttime\\tpopulation\\tindividual\\tmetadata\\n\";\n    char *start;\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_node_table_clear(node_table);\n    if (ret < 0) {\n        goto out;\n    }\n\t\n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoi(&start, &id, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &is_sample, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        flags = is_sample ? TSK_NODE_IS_SAMPLE : 0;\n        err = get_sep_atof(&start, &time, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &population, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &individual, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &name, '\\n');\n        if (err < 0 || *start != '\\0') {\n            goto out;\n        }\n        ret = tsk_node_table_add_row(node_table, flags, time, population, individual,\n                name, (tsk_size_t)strlen(name));\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\nedge_table_load_text(tsk_edge_table_t *edge_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line = NULL;\n    double left, right;\n    tsk_id_t parent, child;\n    int id;\n\tchar *metadata;\n    const char *header = \"id\\tleft\\tright\\tparent\\tchild\\tmetadata\\n\";\n    char *start, *childs;\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_edge_table_clear(edge_table);\n    if (ret < 0) {\n        goto out;\n    }\n    \n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoi(&start, &id, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &left, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &right, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &parent, '\\t');\n        if (err <= 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &childs, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &metadata, '\\n');\n        if (err < 0 || *start != '\\0') {\n\t\t\t// require empty metadata for now\n            goto out;\n        }\n        do {\n            err = get_sep_atoi(&childs, &child, ',');\n            ret = tsk_edge_table_add_row(edge_table, left, right, parent, child, metadata, (tsk_size_t) strlen(metadata));\n            if (ret < 0) {\n                goto out;\n            }\n        } while (err > 0);\n        assert(err == -1);\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\nsite_table_load_text(tsk_site_table_t *site_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line = NULL;\n    int id;\n    double position;\n    char *ancestral_state, *metadata;\n    const char *header = \"id\\tposition\\tancestral_state\\tmetadata\\n\";\n    char *start;\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_site_table_clear(site_table);\n    if (ret < 0) {\n        goto out;\n    }\n    \n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoi(&start, &id, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &position, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &ancestral_state, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &metadata, '\\n');\n        if (err < 0 || *start != '\\0') {\n            goto out;\n        }\n        ret = tsk_site_table_add_row(site_table, position, ancestral_state,\n                (tsk_size_t) strlen(ancestral_state), metadata, (tsk_size_t) strlen(metadata));\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\nmutation_table_load_text(tsk_mutation_table_t *mutation_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line;\n    int id;\n    tsk_id_t node;\n    tsk_id_t site;\n    tsk_id_t parent;\n    double time;\n    char *derived_state, *metadata;\n    const char *header = \"id\\tsite\\tnode\\tparent\\ttime\\tderived_state\\tmetadata\\n\";\n    char *start;\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_mutation_table_clear(mutation_table);\n    if (ret < 0) {\n        goto out;\n    }\n    \n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoi(&start, &id, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &site, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &node, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &parent, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &time, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &derived_state, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &metadata, '\\n');\n        if (err < 0 || *start != '\\0') {\n\t\t\t// require empty metadata for now\n            goto out;\n        }\n        ret = tsk_mutation_table_add_row(mutation_table, site, node, parent, time,\n                derived_state, (tsk_size_t) strlen(derived_state), metadata, (tsk_size_t) strlen(metadata));\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\nmigration_table_load_text(tsk_migration_table_t *migration_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line = NULL;\n    double left, right, time;\n    int node, source, dest;\n    const char *header = \"left\\tright\\tnode\\tsource\\tdest\\ttime\\n\";\n    char *start;\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_migration_table_clear(migration_table);\n    if (ret < 0) {\n        goto out;\n    }\n\n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atof(&start, &left, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &right, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &node, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &source, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &dest, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atof(&start, &time, '\\n');\n        if (err < 0) {\n            goto out;\n        }\n        ret = tsk_migration_table_add_row(migration_table, left, right, node,\n                source, dest, time, NULL, 0);\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\nindividual_table_load_text(tsk_individual_table_t *individual_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k, loc_count, par_count;\n    size_t MAX_LINE = 1024;\n    char *line, *start, *loc, *par;\n    double location[MAX_LINE];\n\tint parents[MAX_LINE];\n    int flags, id;\n    char *metadata;\n    const char *header = \"id\\tflags\\tlocation\\tparents\\tmetadata\\n\";\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_individual_table_clear(individual_table);\n    if (ret < 0) {\n        goto out;\n    }\n    \n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoi(&start, &id, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoi(&start, &flags, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n\t\tloc_count = 0;\n        err = get_sep_atoa(&start, &loc, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        if (err > 0) {\n            while ((err = get_sep_atof(&loc, location + loc_count, ',')) != 0) {\n\t\t\t\tloc_count++;\n\t\t\t\tif (err == -1)\n\t\t\t\t\tbreak;\n            }\n            if (err == 0) {\n                goto out;\n            }\n        }\n\t\tpar_count = 0;\n\t\terr = get_sep_atoa(&start, &par, '\\t');\n\t\tif (err < 0) {\n\t\t\tgoto out;\n\t\t}\n\t\tif (err > 0) {\n\t\t\twhile ((err = get_sep_atoi(&par, parents + par_count, ',')) != 0) {\n\t\t\t\tpar_count++;\n\t\t\t\tif (err == -1)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (err == 0) {\n\t\t\t\tgoto out;\n\t\t\t}\n\t\t}\n        err = get_sep_atoa(&start, &metadata, '\\n');\n        if (err < 0 || *start != '\\0') {\n            goto out;\n        }\n        ret = tsk_individual_table_add_row(individual_table, flags,\n\t\t\t\tlocation, (tsk_size_t)loc_count,\n                parents, (tsk_size_t)par_count, // for individual parents\n                metadata, (tsk_size_t)strlen(metadata));\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\npopulation_table_load_text(tsk_population_table_t *population_table, FILE *file)\n{\n\tint ret;\n\tint err;\n\tsize_t k;\n\tsize_t MAX_LINE = 1024;\n\tchar *line = NULL;\n    char *metadata_schema = NULL;\n\tchar *metadata;\n\tconst char *header = \"metadata\\n\";\n\tchar *start;\n\t\n\tline = malloc(MAX_LINE);\n\tif (line == NULL) {\n\t\tret = TSK_ERR_NO_MEMORY;\n\t\tgoto out;\n\t}\n\tk = MAX_LINE;\n\t\n\tret = tsk_population_table_clear(population_table);\n\tif (ret < 0) {\n\t\tgoto out;\n\t}\n\t\n\t// check the header\n\tret = TSK_ERR_FILE_FORMAT;\n\terr = (int) read_text_headers(&line, &k, file, &metadata_schema);\n\tif (err < 0) {\n\t\tgoto out;\n\t}\n\terr = strcmp(line, header);\n\tif (err != 0) {\n\t\tgoto out;\n\t}\n\t\n\twhile (getline(&line, &k, file) != -1) {\n\t\tstart = line;\n\t\terr = get_sep_atoa(&start, &metadata, '\\n');\n\t\tif (err < 0 || *start != '\\0') {\n\t\t\t// require empty metadata for now\n\t\t\tgoto out;\n\t\t}\n\t\tret = tsk_population_table_add_row(population_table,\n\t\t\t\t\t\t\t\t metadata, (tsk_size_t) strlen(metadata));\n\t\tif (ret < 0) {\n\t\t\tgoto out;\n\t\t}\n\t}\n    if (metadata_schema && strlen(metadata_schema))\n    {\n        population_table->metadata_schema = metadata_schema;\n        population_table->metadata_schema_length = strlen(metadata_schema);\n    }\n\tret = 0;\nout:\n\tfree(line);\n\treturn ret;\n}\n\n\nint\nprovenance_table_load_text(tsk_provenance_table_t *provenance_table, FILE *file)\n{\n    int ret;\n    int err;\n    size_t k;\n    size_t MAX_LINE = 1024;\n    char *line = NULL;\n    char *record, *timestamp;\n    char *start;\n    const char *header = \"record\\ttimestamp\\n\";\n\n    line = malloc(MAX_LINE);\n    if (line == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    k = MAX_LINE;\n\n    ret = tsk_provenance_table_clear(provenance_table);\n    if (ret < 0) {\n        goto out;\n    }\n    \n    // check the header\n    ret = TSK_ERR_FILE_FORMAT;\n    err = (int) read_text_headers(&line, &k, file, NULL);\n    if (err < 0) {\n        goto out;\n    }\n    err = strcmp(line, header);\n    if (err != 0) {\n        goto out;\n    }\n\n    while (getline(&line, &k, file) != -1) {\n        start = line;\n        err = get_sep_atoa(&start, &record, '\\t');\n        if (err < 0) {\n            goto out;\n        }\n        err = get_sep_atoa(&start, &timestamp, '\\n');\n        if (err < 0 || *start != '\\0') {\n            goto out;\n        }\n        ret = tsk_provenance_table_add_row(provenance_table, timestamp, (tsk_size_t)strlen(timestamp), \n                record, (tsk_size_t)strlen(record));\n        if (ret < 0) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    free(line);\n    return ret;\n}\n\n\nint\ntable_collection_load_text(tsk_table_collection_t *tables, FILE *nodes, FILE *edges,\n        FILE *sites, FILE *mutations, FILE *migrations, FILE *individuals, \n        FILE *populations, FILE *provenances)\n{\n    int ret;\n    tsk_size_t j;\n    double sequence_length;\n\n    ret = node_table_load_text(&tables->nodes, nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = edge_table_load_text(&tables->edges, edges);\n    if (ret != 0) {\n        goto out;\n    }\n    if (sites != NULL) {\n        ret = site_table_load_text(&tables->sites, sites);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (mutations != NULL) {\n        ret = mutation_table_load_text(&tables->mutations, mutations);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (migrations != NULL) {\n        ret = migration_table_load_text(&tables->migrations, migrations);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (individuals != NULL) {\n        ret = individual_table_load_text(&tables->individuals, individuals);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (populations != NULL) {\n        ret = population_table_load_text(&tables->populations, populations);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (provenances != NULL) {\n        ret = provenance_table_load_text(&tables->provenances, provenances);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    /* infer sequence length from the edges and/or sites */\n    sequence_length = 0.0;\n    for (j = 0; j < tables->edges.num_rows; j++) {\n        sequence_length = TSK_MAX(sequence_length, tables->edges.right[j]);\n    }\n    for (j = 0; j < tables->sites.num_rows; j++) {\n        sequence_length = TSK_MAX(sequence_length, tables->sites.position[j]);\n    }\n    if (sequence_length <= 0.0) {\n        ret = TSK_ERR_BAD_SEQUENCE_LENGTH;\n        goto out;\n    }\n    tables->sequence_length = sequence_length;\nout :\n    return ret;\n}\n\n"
  },
  {
    "path": "treerec/tskit/text_input.h",
    "content": "#ifndef TSK_TEXT_INPUT_H\n#define TSK_TEXT_INPUT_H\n\n#include <stdio.h>\n\n#include \"tables.h\"\n\nint node_table_load_text(tsk_node_table_t *node_table, FILE *file);\nint edge_table_load_text(tsk_edge_table_t *edge_table, FILE *file);\nint site_table_load_text(tsk_site_table_t *site_table, FILE *file);\nint mutation_table_load_text(tsk_mutation_table_t *mutation_table, FILE *file);\nint migration_table_load_text(tsk_migration_table_t *migration_table, FILE *file);\nint individual_table_load_text(tsk_individual_table_t *individual_table, FILE *file);\nint population_table_load_text(tsk_population_table_t *population_table, FILE *file);\nint provenance_table_load_text(tsk_provenance_table_t *provenance_table, FILE *file);\nint table_collection_load_text(tsk_table_collection_t *tables, FILE *nodes, FILE *edges,\n        FILE *sites, FILE *mutations, FILE *migrations, FILE *individuals, \n        FILE *populations, FILE *provenances);\n\n#endif /* TSK_TEXT_INPUT_H */\n\n"
  },
  {
    "path": "treerec/tskit/trees.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2025 Tskit Developers\n * Copyright (c) 2015-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <math.h>\n#include <assert.h>\n\n#include <tskit/trees.h>\n#include <tskit/genotypes.h>\n\nstatic inline bool\nis_discrete(double x)\n{\n    return trunc(x) == x;\n}\n\n/* ======================================================== *\n * tree sequence\n * ======================================================== */\n\nstatic void\ntsk_treeseq_check_state(const tsk_treeseq_t *self)\n{\n    tsk_size_t j;\n    tsk_size_t k, l;\n    tsk_site_t site;\n    tsk_id_t site_id = 0;\n\n    for (j = 0; j < self->num_trees; j++) {\n        for (k = 0; k < self->tree_sites_length[j]; k++) {\n            site = self->tree_sites[j][k];\n            tsk_bug_assert(site.id == site_id);\n            site_id++;\n            for (l = 0; l < site.mutations_length; l++) {\n                tsk_bug_assert(site.mutations[l].site == site.id);\n            }\n        }\n    }\n}\n\nvoid\ntsk_treeseq_print_state(const tsk_treeseq_t *self, FILE *out)\n{\n    tsk_size_t j;\n    tsk_size_t k, l, m;\n    tsk_site_t site;\n\n    fprintf(out, \"tree_sequence state\\n\");\n    fprintf(out, \"num_trees = %lld\\n\", (long long) self->num_trees);\n    fprintf(out, \"samples = (%lld)\\n\", (long long) self->num_samples);\n    for (j = 0; j < self->num_samples; j++) {\n        fprintf(out, \"\\t%lld\\n\", (long long) self->samples[j]);\n    }\n    tsk_table_collection_print_state(self->tables, out);\n    fprintf(out, \"tree_sites = \\n\");\n    for (j = 0; j < self->num_trees; j++) {\n        fprintf(out, \"tree %lld\\t%lld sites\\n\", (long long) j,\n            (long long) self->tree_sites_length[j]);\n        for (k = 0; k < self->tree_sites_length[j]; k++) {\n            site = self->tree_sites[j][k];\n            fprintf(out, \"\\tsite %lld pos = %f ancestral state = \", (long long) site.id,\n                site.position);\n            for (l = 0; l < site.ancestral_state_length; l++) {\n                fprintf(out, \"%c\", site.ancestral_state[l]);\n            }\n            fprintf(out, \" %lld mutations\\n\", (long long) site.mutations_length);\n            for (l = 0; l < site.mutations_length; l++) {\n                fprintf(out, \"\\t\\tmutation %lld node = %lld derived_state = \",\n                    (long long) site.mutations[l].id,\n                    (long long) site.mutations[l].node);\n                for (m = 0; m < site.mutations[l].derived_state_length; m++) {\n                    fprintf(out, \"%c\", site.mutations[l].derived_state[m]);\n                }\n                fprintf(out, \"\\n\");\n            }\n        }\n    }\n    tsk_treeseq_check_state(self);\n}\n\nint\ntsk_treeseq_free(tsk_treeseq_t *self)\n{\n    if (self->tables != NULL) {\n        tsk_table_collection_free(self->tables);\n    }\n    tsk_safe_free(self->tables);\n    tsk_safe_free(self->samples);\n    tsk_safe_free(self->sample_index_map);\n    tsk_safe_free(self->breakpoints);\n    tsk_safe_free(self->tree_sites);\n    tsk_safe_free(self->tree_sites_length);\n    tsk_safe_free(self->tree_sites_mem);\n    tsk_safe_free(self->site_mutations_mem);\n    tsk_safe_free(self->site_mutations_length);\n    tsk_safe_free(self->site_mutations);\n    tsk_safe_free(self->individual_nodes_mem);\n    tsk_safe_free(self->individual_nodes_length);\n    tsk_safe_free(self->individual_nodes);\n    return 0;\n}\n\nstatic int\ntsk_treeseq_init_sites(tsk_treeseq_t *self)\n{\n    tsk_id_t j, k;\n    int ret = 0;\n    tsk_size_t offset = 0;\n    const tsk_size_t num_mutations = self->tables->mutations.num_rows;\n    const tsk_size_t num_sites = self->tables->sites.num_rows;\n    const tsk_id_t *restrict mutation_site = self->tables->mutations.site;\n    const double *restrict site_position = self->tables->sites.position;\n    bool discrete_sites = true;\n    tsk_mutation_t *mutation;\n\n    self->site_mutations_mem\n        = tsk_malloc(num_mutations * sizeof(*self->site_mutations_mem));\n    self->site_mutations_length\n        = tsk_malloc(num_sites * sizeof(*self->site_mutations_length));\n    self->site_mutations = tsk_malloc(num_sites * sizeof(*self->site_mutations));\n    self->tree_sites_mem = tsk_malloc(num_sites * sizeof(*self->tree_sites_mem));\n    if (self->site_mutations_mem == NULL || self->site_mutations_length == NULL\n        || self->site_mutations == NULL || self->tree_sites_mem == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (k = 0; k < (tsk_id_t) num_mutations; k++) {\n        mutation = self->site_mutations_mem + k;\n        ret = tsk_treeseq_get_mutation(self, k, mutation);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    k = 0;\n    for (j = 0; j < (tsk_id_t) num_sites; j++) {\n        discrete_sites = discrete_sites && is_discrete(site_position[j]);\n        self->site_mutations[j] = self->site_mutations_mem + offset;\n        self->site_mutations_length[j] = 0;\n        /* Go through all mutations for this site */\n        while (k < (tsk_id_t) num_mutations && mutation_site[k] == j) {\n            self->site_mutations_length[j]++;\n            offset++;\n            k++;\n        }\n        ret = tsk_treeseq_get_site(self, j, self->tree_sites_mem + j);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    self->discrete_genome = self->discrete_genome && discrete_sites;\nout:\n    return ret;\n}\n\nstatic int\ntsk_treeseq_init_individuals(tsk_treeseq_t *self)\n{\n    int ret = 0;\n    tsk_id_t node;\n    tsk_id_t ind;\n    tsk_size_t offset = 0;\n    tsk_size_t total_node_refs = 0;\n    tsk_size_t *node_count = NULL;\n    tsk_id_t *node_array;\n    const tsk_size_t num_inds = self->tables->individuals.num_rows;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t *restrict node_individual = self->tables->nodes.individual;\n\n    // First find number of nodes per individual\n    self->individual_nodes_length\n        = tsk_calloc(TSK_MAX(1, num_inds), sizeof(*self->individual_nodes_length));\n    node_count = tsk_calloc(TSK_MAX(1, num_inds), sizeof(*node_count));\n\n    if (self->individual_nodes_length == NULL || node_count == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (node = 0; node < (tsk_id_t) num_nodes; node++) {\n        ind = node_individual[node];\n        if (ind != TSK_NULL) {\n            self->individual_nodes_length[ind]++;\n            total_node_refs++;\n        }\n    }\n\n    self->individual_nodes_mem\n        = tsk_malloc(TSK_MAX(1, total_node_refs) * sizeof(tsk_node_t));\n    self->individual_nodes = tsk_malloc(TSK_MAX(1, num_inds) * sizeof(tsk_node_t *));\n    if (self->individual_nodes_mem == NULL || self->individual_nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* Now fill in the node IDs */\n    for (ind = 0; ind < (tsk_id_t) num_inds; ind++) {\n        self->individual_nodes[ind] = self->individual_nodes_mem + offset;\n        offset += self->individual_nodes_length[ind];\n    }\n    for (node = 0; node < (tsk_id_t) num_nodes; node++) {\n        ind = node_individual[node];\n        if (ind != TSK_NULL) {\n            node_array = self->individual_nodes[ind];\n            tsk_bug_assert(node_array - self->individual_nodes_mem\n                           < (tsk_id_t)(total_node_refs - node_count[ind]));\n            node_array[node_count[ind]] = node;\n            node_count[ind] += 1;\n        }\n    }\nout:\n    tsk_safe_free(node_count);\n    return ret;\n}\n\n/* Initialises memory associated with the trees.\n */\nstatic int\ntsk_treeseq_init_trees(tsk_treeseq_t *self)\n{\n    int ret = TSK_ERR_GENERIC;\n    tsk_size_t j, k, tree_index;\n    tsk_id_t site_id, edge_id, mutation_id;\n    double tree_left, tree_right;\n    const double sequence_length = self->tables->sequence_length;\n    const tsk_id_t num_sites = (tsk_id_t) self->tables->sites.num_rows;\n    const tsk_id_t num_mutations = (tsk_id_t) self->tables->mutations.num_rows;\n    const tsk_size_t num_edges = self->tables->edges.num_rows;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const double *restrict site_position = self->tables->sites.position;\n    const tsk_id_t *restrict mutation_site = self->tables->mutations.site;\n    const tsk_id_t *restrict mutation_parent = self->tables->mutations.parent;\n    const char *restrict sites_ancestral_state = self->tables->sites.ancestral_state;\n    const tsk_size_t *restrict sites_ancestral_state_offset\n        = self->tables->sites.ancestral_state_offset;\n    const char *restrict mutations_derived_state = self->tables->mutations.derived_state;\n    const tsk_size_t *restrict mutations_derived_state_offset\n        = self->tables->mutations.derived_state_offset;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_right = self->tables->edges.right;\n    const double *restrict edge_left = self->tables->edges.left;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    tsk_size_t num_trees_alloc = self->num_trees + 1;\n    bool discrete_breakpoints = true;\n    tsk_id_t *node_edge_map = tsk_malloc(num_nodes * sizeof(*node_edge_map));\n    tsk_mutation_t *mutation;\n    tsk_id_t parent_id;\n\n    self->tree_sites_length\n        = tsk_malloc(num_trees_alloc * sizeof(*self->tree_sites_length));\n    self->tree_sites = tsk_malloc(num_trees_alloc * sizeof(*self->tree_sites));\n    self->breakpoints = tsk_malloc(num_trees_alloc * sizeof(*self->breakpoints));\n    if (node_edge_map == NULL || self->tree_sites == NULL\n        || self->tree_sites_length == NULL || self->breakpoints == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(\n        self->tree_sites_length, 0, self->num_trees * sizeof(*self->tree_sites_length));\n    tsk_memset(self->tree_sites, 0, self->num_trees * sizeof(*self->tree_sites));\n    tsk_memset(node_edge_map, TSK_NULL, num_nodes * sizeof(*node_edge_map));\n\n    tree_left = 0;\n    tree_right = sequence_length;\n    tree_index = 0;\n    site_id = 0;\n    mutation_id = 0;\n    j = 0;\n    k = 0;\n    while (j < num_edges || tree_left < sequence_length) {\n        discrete_breakpoints = discrete_breakpoints && is_discrete(tree_left);\n        self->breakpoints[tree_index] = tree_left;\n        while (k < num_edges && edge_right[O[k]] == tree_left) {\n            edge_id = O[k];\n            node_edge_map[edge_child[edge_id]] = TSK_NULL;\n            k++;\n        }\n        while (j < num_edges && edge_left[I[j]] == tree_left) {\n            edge_id = I[j];\n            node_edge_map[edge_child[edge_id]] = edge_id;\n            j++;\n        }\n        tree_right = sequence_length;\n        if (j < num_edges) {\n            tree_right = TSK_MIN(tree_right, edge_left[I[j]]);\n        }\n        if (k < num_edges) {\n            tree_right = TSK_MIN(tree_right, edge_right[O[k]]);\n        }\n        self->tree_sites[tree_index] = self->tree_sites_mem + site_id;\n        while (site_id < num_sites && site_position[site_id] < tree_right) {\n            self->tree_sites_length[tree_index]++;\n            while (\n                mutation_id < num_mutations && mutation_site[mutation_id] == site_id) {\n                mutation = self->site_mutations_mem + mutation_id;\n                mutation->edge = node_edge_map[mutation->node];\n\n                /* Compute inherited state */\n                if (mutation_parent[mutation_id] == TSK_NULL) {\n                    /* No parent: inherited state is the site's ancestral state */\n                    mutation->inherited_state\n                        = sites_ancestral_state + sites_ancestral_state_offset[site_id];\n                    mutation->inherited_state_length\n                        = sites_ancestral_state_offset[site_id + 1]\n                          - sites_ancestral_state_offset[site_id];\n                } else {\n                    /* Has parent: inherited state is parent's derived state */\n                    parent_id = mutation_parent[mutation_id];\n                    mutation->inherited_state\n                        = mutations_derived_state\n                          + mutations_derived_state_offset[parent_id];\n                    mutation->inherited_state_length\n                        = mutations_derived_state_offset[parent_id + 1]\n                          - mutations_derived_state_offset[parent_id];\n                }\n\n                mutation_id++;\n            }\n            site_id++;\n        }\n        tree_left = tree_right;\n        tree_index++;\n    }\n    tsk_bug_assert(site_id == num_sites);\n    tsk_bug_assert(tree_index == self->num_trees);\n    self->breakpoints[tree_index] = tree_right;\n    discrete_breakpoints = discrete_breakpoints && is_discrete(tree_right);\n    self->discrete_genome = self->discrete_genome && discrete_breakpoints;\n    ret = 0;\nout:\n    tsk_safe_free(node_edge_map);\n    return ret;\n}\n\nstatic void\ntsk_treeseq_init_migrations(tsk_treeseq_t *self)\n{\n    tsk_size_t j;\n    tsk_size_t num_migrations = self->tables->migrations.num_rows;\n    const double *restrict left = self->tables->migrations.left;\n    const double *restrict right = self->tables->migrations.right;\n    const double *restrict time = self->tables->migrations.time;\n    bool discrete_breakpoints = true;\n    bool discrete_times = true;\n\n    for (j = 0; j < num_migrations; j++) {\n        discrete_breakpoints\n            = discrete_breakpoints && is_discrete(left[j]) && is_discrete(right[j]);\n        discrete_times\n            = discrete_times && (is_discrete(time[j]) || tsk_is_unknown_time(time[j]));\n    }\n    self->discrete_genome = self->discrete_genome && discrete_breakpoints;\n    self->discrete_time = self->discrete_time && discrete_times;\n}\n\nstatic void\ntsk_treeseq_init_mutations(tsk_treeseq_t *self)\n{\n    tsk_size_t j;\n    tsk_size_t num_mutations = self->tables->mutations.num_rows;\n    const double *restrict time = self->tables->mutations.time;\n    bool discrete_times = true;\n\n    for (j = 0; j < num_mutations; j++) {\n        discrete_times\n            = discrete_times && (is_discrete(time[j]) || tsk_is_unknown_time(time[j]));\n    }\n    self->discrete_time = self->discrete_time && discrete_times;\n\n    for (j = 0; j < num_mutations; j++) {\n        if (!tsk_is_unknown_time(time[j])) {\n            self->min_time = TSK_MIN(self->min_time, time[j]);\n            self->max_time = TSK_MAX(self->max_time, time[j]);\n        }\n    }\n}\n\nstatic int\ntsk_treeseq_init_nodes(tsk_treeseq_t *self)\n{\n    tsk_size_t j, k;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_flags_t *restrict node_flags = self->tables->nodes.flags;\n    const double *restrict time = self->tables->nodes.time;\n    int ret = 0;\n    bool discrete_times = true;\n\n    /* Determine the sample size */\n    self->num_samples = 0;\n    for (j = 0; j < num_nodes; j++) {\n        if (!!(node_flags[j] & TSK_NODE_IS_SAMPLE)) {\n            self->num_samples++;\n        }\n    }\n    /* TODO raise an error if < 2 samples?? */\n    self->samples = tsk_malloc(self->num_samples * sizeof(tsk_id_t));\n    self->sample_index_map = tsk_malloc(num_nodes * sizeof(tsk_id_t));\n    if (self->samples == NULL || self->sample_index_map == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    k = 0;\n    for (j = 0; j < num_nodes; j++) {\n        self->sample_index_map[j] = -1;\n        if (!!(node_flags[j] & TSK_NODE_IS_SAMPLE)) {\n            self->samples[k] = (tsk_id_t) j;\n            self->sample_index_map[j] = (tsk_id_t) k;\n            k++;\n        }\n    }\n    tsk_bug_assert(k == self->num_samples);\n\n    for (j = 0; j < num_nodes; j++) {\n        discrete_times\n            = discrete_times && (is_discrete(time[j]) || tsk_is_unknown_time(time[j]));\n    }\n    self->discrete_time = self->discrete_time && discrete_times;\n\n    for (j = 0; j < num_nodes; j++) {\n        if (!tsk_is_unknown_time(time[j])) {\n            self->min_time = TSK_MIN(self->min_time, time[j]);\n            self->max_time = TSK_MAX(self->max_time, time[j]);\n        }\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_init(\n    tsk_treeseq_t *self, tsk_table_collection_t *tables, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_id_t num_trees;\n\n    tsk_memset(self, 0, sizeof(*self));\n    if (options & TSK_TAKE_OWNERSHIP) {\n        self->tables = tables;\n        if (tables->edges.options & TSK_TABLE_NO_METADATA) {\n            ret = tsk_trace_error(TSK_ERR_CANT_TAKE_OWNERSHIP_NO_EDGE_METADATA);\n            goto out;\n        }\n    } else {\n        self->tables = tsk_malloc(sizeof(*self->tables));\n        if (self->tables == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n\n        /* Note that this copy reinstates metadata for a table collection with\n         * TSK_TC_NO_EDGE_METADATA. Otherwise a table without metadata would\n         * crash tsk_diff_iter_next. */\n        ret = tsk_table_collection_copy(tables, self->tables, TSK_COPY_FILE_UUID);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (options & TSK_TS_INIT_BUILD_INDEXES) {\n        ret = tsk_table_collection_build_index(self->tables, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    if (options & TSK_TS_INIT_COMPUTE_MUTATION_PARENTS) {\n        /* As tsk_table_collection_compute_mutation_parents performs an\n           integrity check, and we don't wish to do that twice we perform\n           our own check here */\n        num_trees = tsk_table_collection_check_integrity(self->tables, TSK_CHECK_TREES);\n        if (num_trees < 0) {\n            ret = (int) num_trees;\n            goto out;\n        }\n\n        ret = tsk_table_collection_compute_mutation_parents(\n            self->tables, TSK_NO_CHECK_INTEGRITY);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        num_trees = tsk_table_collection_check_integrity(\n            self->tables, TSK_CHECK_TREES | TSK_CHECK_MUTATION_PARENTS);\n        if (num_trees < 0) {\n            ret = (int) num_trees;\n            goto out;\n        }\n    }\n    self->num_trees = (tsk_size_t) num_trees;\n    self->discrete_genome = true;\n    self->discrete_time = true;\n    self->min_time = INFINITY;\n    self->max_time = -INFINITY;\n    ret = tsk_treeseq_init_nodes(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_init_sites(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_init_individuals(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_init_trees(self);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_treeseq_init_migrations(self);\n    tsk_treeseq_init_mutations(self);\n\n    if (tsk_treeseq_get_time_units_length(self) == strlen(TSK_TIME_UNITS_UNCALIBRATED)\n        && !strncmp(tsk_treeseq_get_time_units(self), TSK_TIME_UNITS_UNCALIBRATED,\n               strlen(TSK_TIME_UNITS_UNCALIBRATED))) {\n        self->time_uncalibrated = true;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_copy_tables(\n    const tsk_treeseq_t *self, tsk_table_collection_t *tables, tsk_flags_t options)\n{\n    return tsk_table_collection_copy(self->tables, tables, options);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_load(tsk_treeseq_t *self, const char *filename, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = malloc(sizeof(*tables));\n\n    /* Need to make sure that we're zero'd out in case of error */\n    tsk_memset(self, 0, sizeof(*self));\n\n    if (tables == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_table_collection_load(tables, filename, options);\n    if (ret != 0) {\n        tsk_table_collection_free(tables);\n        tsk_safe_free(tables);\n        goto out;\n    }\n    /* TSK_TAKE_OWNERSHIP takes immediate ownership of the tables, regardless\n     * of error conditions. */\n    ret = tsk_treeseq_init(self, tables, TSK_TAKE_OWNERSHIP);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_loadf(tsk_treeseq_t *self, FILE *file, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = malloc(sizeof(*tables));\n\n    /* Need to make sure that we're zero'd out in case of error */\n    tsk_memset(self, 0, sizeof(*self));\n\n    if (tables == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    ret = tsk_table_collection_loadf(tables, file, options);\n    if (ret != 0) {\n        tsk_table_collection_free(tables);\n        tsk_safe_free(tables);\n        goto out;\n    }\n    /* TSK_TAKE_OWNERSHIP takes immediate ownership of the tables, regardless\n     * of error conditions. */\n    ret = tsk_treeseq_init(self, tables, TSK_TAKE_OWNERSHIP);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_dump(const tsk_treeseq_t *self, const char *filename, tsk_flags_t options)\n{\n    return tsk_table_collection_dump(self->tables, filename, options);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_dumpf(const tsk_treeseq_t *self, FILE *file, tsk_flags_t options)\n{\n    return tsk_table_collection_dumpf(self->tables, file, options);\n}\n\n/* Simple attribute getters */\n\nconst char *\ntsk_treeseq_get_metadata(const tsk_treeseq_t *self)\n{\n    return self->tables->metadata;\n}\n\ntsk_size_t\ntsk_treeseq_get_metadata_length(const tsk_treeseq_t *self)\n{\n    return self->tables->metadata_length;\n}\n\nconst char *\ntsk_treeseq_get_metadata_schema(const tsk_treeseq_t *self)\n{\n    return self->tables->metadata_schema;\n}\n\ntsk_size_t\ntsk_treeseq_get_metadata_schema_length(const tsk_treeseq_t *self)\n{\n    return self->tables->metadata_schema_length;\n}\n\nconst char *\ntsk_treeseq_get_time_units(const tsk_treeseq_t *self)\n{\n    return self->tables->time_units;\n}\n\ntsk_size_t\ntsk_treeseq_get_time_units_length(const tsk_treeseq_t *self)\n{\n    return self->tables->time_units_length;\n}\n\ndouble\ntsk_treeseq_get_sequence_length(const tsk_treeseq_t *self)\n{\n    return self->tables->sequence_length;\n}\n\nconst char *\ntsk_treeseq_get_file_uuid(const tsk_treeseq_t *self)\n{\n    return self->tables->file_uuid;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_samples(const tsk_treeseq_t *self)\n{\n    return self->num_samples;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_nodes(const tsk_treeseq_t *self)\n{\n    return self->tables->nodes.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_edges(const tsk_treeseq_t *self)\n{\n    return self->tables->edges.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_migrations(const tsk_treeseq_t *self)\n{\n    return self->tables->migrations.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_sites(const tsk_treeseq_t *self)\n{\n    return self->tables->sites.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_mutations(const tsk_treeseq_t *self)\n{\n    return self->tables->mutations.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_populations(const tsk_treeseq_t *self)\n{\n    return self->tables->populations.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_individuals(const tsk_treeseq_t *self)\n{\n    return self->tables->individuals.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_provenances(const tsk_treeseq_t *self)\n{\n    return self->tables->provenances.num_rows;\n}\n\ntsk_size_t\ntsk_treeseq_get_num_trees(const tsk_treeseq_t *self)\n{\n    return self->num_trees;\n}\n\nconst double *\ntsk_treeseq_get_breakpoints(const tsk_treeseq_t *self)\n{\n    return self->breakpoints;\n}\n\nconst tsk_id_t *\ntsk_treeseq_get_samples(const tsk_treeseq_t *self)\n{\n    return self->samples;\n}\n\nconst tsk_id_t *\ntsk_treeseq_get_sample_index_map(const tsk_treeseq_t *self)\n{\n    return self->sample_index_map;\n}\n\nbool\ntsk_treeseq_is_sample(const tsk_treeseq_t *self, tsk_id_t u)\n{\n    bool ret = false;\n\n    if (u >= 0 && u < (tsk_id_t) self->tables->nodes.num_rows) {\n        ret = !!(self->tables->nodes.flags[u] & TSK_NODE_IS_SAMPLE);\n    }\n    return ret;\n}\n\nbool\ntsk_treeseq_get_discrete_genome(const tsk_treeseq_t *self)\n{\n    return self->discrete_genome;\n}\n\nbool\ntsk_treeseq_get_discrete_time(const tsk_treeseq_t *self)\n{\n    return self->discrete_time;\n}\n\ndouble\ntsk_treeseq_get_min_time(const tsk_treeseq_t *self)\n{\n    return self->min_time;\n}\n\ndouble\ntsk_treeseq_get_max_time(const tsk_treeseq_t *self)\n{\n    return self->max_time;\n}\n\nbool\ntsk_treeseq_has_reference_sequence(const tsk_treeseq_t *self)\n{\n    return tsk_table_collection_has_reference_sequence(self->tables);\n}\n\nint\ntsk_treeseq_get_individuals_population(const tsk_treeseq_t *self, tsk_id_t *output)\n{\n    int ret = 0;\n    tsk_size_t i, j;\n    tsk_individual_t ind;\n    tsk_id_t ind_pop;\n    const tsk_id_t *node_population = self->tables->nodes.population;\n    const tsk_size_t num_individuals = self->tables->individuals.num_rows;\n\n    tsk_memset(output, TSK_NULL, num_individuals * sizeof(*output));\n\n    for (i = 0; i < num_individuals; i++) {\n        ret = tsk_treeseq_get_individual(self, (tsk_id_t) i, &ind);\n        tsk_bug_assert(ret == 0);\n        if (ind.nodes_length > 0) {\n            ind_pop = -2;\n            for (j = 0; j < ind.nodes_length; j++) {\n                if (ind_pop == -2) {\n                    ind_pop = node_population[ind.nodes[j]];\n                } else if (ind_pop != node_population[ind.nodes[j]]) {\n                    ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_POPULATION_MISMATCH);\n                    goto out;\n                }\n            }\n            output[ind.id] = ind_pop;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_treeseq_get_individuals_time(const tsk_treeseq_t *self, double *output)\n{\n    int ret = 0;\n    tsk_size_t i, j;\n    tsk_individual_t ind;\n    double ind_time;\n    const double *node_time = self->tables->nodes.time;\n    const tsk_size_t num_individuals = self->tables->individuals.num_rows;\n\n    for (i = 0; i < num_individuals; i++) {\n        ret = tsk_treeseq_get_individual(self, (tsk_id_t) i, &ind);\n        tsk_bug_assert(ret == 0);\n        /* the default is UNKNOWN_TIME, but nodes cannot have\n         * UNKNOWN _TIME so this is safe. */\n        ind_time = TSK_UNKNOWN_TIME;\n        for (j = 0; j < ind.nodes_length; j++) {\n            if (j == 0) {\n                ind_time = node_time[ind.nodes[j]];\n            } else if (ind_time != node_time[ind.nodes[j]]) {\n                ret = tsk_trace_error(TSK_ERR_INDIVIDUAL_TIME_MISMATCH);\n                goto out;\n            }\n        }\n        output[ind.id] = ind_time;\n    }\nout:\n    return ret;\n}\n\n/* Stats functions */\n\n#define GET_2D_ROW(array, row_len, row) (array + (((size_t)(row_len)) * (size_t)(row)))\n\nstatic inline double *\nGET_3D_ROW(double *base, tsk_size_t num_nodes, tsk_size_t output_dim,\n    tsk_size_t window_index, tsk_id_t u)\n{\n    tsk_size_t offset\n        = window_index * num_nodes * output_dim + ((tsk_size_t) u) * output_dim;\n    return base + offset;\n}\n\n/* Increments the n-dimensional array with the specified shape by the specified value at\n * the specified coordinate. */\nstatic inline void\nincrement_nd_array_value(double *array, tsk_size_t n, const tsk_size_t *shape,\n    const tsk_size_t *coordinate, double value)\n{\n    tsk_size_t offset = 0;\n    tsk_size_t product = 1;\n    int k;\n\n    for (k = (int) n - 1; k >= 0; k--) {\n        tsk_bug_assert(coordinate[k] < shape[k]);\n        offset += coordinate[k] * product;\n        product *= shape[k];\n    }\n    array[offset] += value;\n}\n\n/* TODO flatten the reference sets input here and follow the same pattern used\n * in diversity, divergence, etc. */\nint TSK_WARN_UNUSED\ntsk_treeseq_genealogical_nearest_neighbours(const tsk_treeseq_t *self,\n    const tsk_id_t *focal, tsk_size_t num_focal, const tsk_id_t *const *reference_sets,\n    const tsk_size_t *reference_set_size, tsk_size_t num_reference_sets,\n    tsk_flags_t TSK_UNUSED(options), double *ret_array)\n{\n    int ret = 0;\n    tsk_id_t u, v, p;\n    tsk_size_t j;\n    /* TODO It's probably not worth bothering with the int16_t here. */\n    int16_t k, focal_reference_set;\n    /* We use the K'th element of the array for the total. */\n    const int16_t K = (int16_t)(num_reference_sets + 1);\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t tj, tk, h;\n    double left, right, *A_row, scale, tree_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    double *restrict length = tsk_calloc(num_focal, sizeof(*length));\n    uint32_t *restrict ref_count\n        = tsk_calloc(((tsk_size_t) K) * num_nodes, sizeof(*ref_count));\n    int16_t *restrict reference_set_map\n        = tsk_malloc(num_nodes * sizeof(*reference_set_map));\n    uint32_t *restrict row = NULL;\n    uint32_t *restrict child_row = NULL;\n    uint32_t total, delta;\n\n    /* We support a max of 8K focal sets */\n    if (num_reference_sets == 0 || num_reference_sets > (INT16_MAX - 1)) {\n        /* TODO: more specific error */\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (parent == NULL || ref_count == NULL || reference_set_map == NULL\n        || length == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n    tsk_memset(reference_set_map, 0xff, num_nodes * sizeof(*reference_set_map));\n    tsk_memset(ret_array, 0, num_focal * num_reference_sets * sizeof(*ret_array));\n\n    total = 0; /* keep the compiler happy */\n\n    /* Set the initial conditions and check the input. */\n    for (k = 0; k < (int16_t) num_reference_sets; k++) {\n        for (j = 0; j < reference_set_size[k]; j++) {\n            u = reference_sets[k][j];\n            if (u < 0 || u >= (tsk_id_t) num_nodes) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            if (reference_set_map[u] != TSK_NULL) {\n                /* FIXME Technically inaccurate here: duplicate focal not sample */\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            reference_set_map[u] = k;\n            row = GET_2D_ROW(ref_count, K, u);\n            row[k] = 1;\n            /* Also set the count for the total among all sets */\n            row[K - 1] = 1;\n        }\n    }\n    for (j = 0; j < num_focal; j++) {\n        u = focal[j];\n        if (u < 0 || u >= (tsk_id_t) num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n    }\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    left = 0;\n    while (tj < num_edges || left < sequence_length) {\n        while (tk < num_edges && edge_right[O[tk]] == left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = TSK_NULL;\n            child_row = GET_2D_ROW(ref_count, K, u);\n            while (v != TSK_NULL) {\n                row = GET_2D_ROW(ref_count, K, v);\n                for (k = 0; k < K; k++) {\n                    row[k] -= child_row[k];\n                }\n                v = parent[v];\n            }\n        }\n        while (tj < num_edges && edge_left[I[tj]] == left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            child_row = GET_2D_ROW(ref_count, K, u);\n            while (v != TSK_NULL) {\n                row = GET_2D_ROW(ref_count, K, v);\n                for (k = 0; k < K; k++) {\n                    row[k] += child_row[k];\n                }\n                v = parent[v];\n            }\n        }\n        right = sequence_length;\n        if (tj < num_edges) {\n            right = TSK_MIN(right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            right = TSK_MIN(right, edge_right[O[tk]]);\n        }\n\n        tree_length = right - left;\n        /* Process this tree */\n        for (j = 0; j < num_focal; j++) {\n            u = focal[j];\n            focal_reference_set = reference_set_map[u];\n            delta = focal_reference_set != -1;\n            p = u;\n            while (p != TSK_NULL) {\n                row = GET_2D_ROW(ref_count, K, p);\n                total = row[K - 1];\n                if (total > delta) {\n                    break;\n                }\n                p = parent[p];\n            }\n            if (p != TSK_NULL) {\n                length[j] += tree_length;\n                scale = tree_length / (total - delta);\n                A_row = GET_2D_ROW(ret_array, num_reference_sets, j);\n                for (k = 0; k < K - 1; k++) {\n                    A_row[k] += row[k] * scale;\n                }\n                if (focal_reference_set != -1) {\n                    /* Remove the contribution for the reference set u belongs to and\n                     * insert the correct value. The long-hand version is\n                     * A_row[k] = A_row[k] - row[k] * scale + (row[k] - 1) * scale;\n                     * which cancels to give: */\n                    A_row[focal_reference_set] -= scale;\n                }\n            }\n        }\n\n        /* Move on to the next tree */\n        left = right;\n    }\n\n    /* Divide by the accumulated length for each node to normalise */\n    for (j = 0; j < num_focal; j++) {\n        A_row = GET_2D_ROW(ret_array, num_reference_sets, j);\n        if (length[j] > 0) {\n            for (k = 0; k < K - 1; k++) {\n                A_row[k] /= length[j];\n            }\n        }\n    }\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    if (ref_count != NULL) {\n        free(ref_count);\n    }\n    if (reference_set_map != NULL) {\n        free(reference_set_map);\n    }\n    if (length != NULL) {\n        free(length);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_mean_descendants(const tsk_treeseq_t *self,\n    const tsk_id_t *const *reference_sets, const tsk_size_t *reference_set_size,\n    tsk_size_t num_reference_sets, tsk_flags_t TSK_UNUSED(options), double *ret_array)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t j;\n    int32_t k;\n    /* We use the K'th element of the array for the total. */\n    const int32_t K = (int32_t)(num_reference_sets + 1);\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t tj, tk, h;\n    double left, right, length, *restrict C_row;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    uint32_t *restrict ref_count\n        = tsk_calloc(num_nodes * ((size_t) K), sizeof(*ref_count));\n    double *restrict last_update = tsk_calloc(num_nodes, sizeof(*last_update));\n    double *restrict total_length = tsk_calloc(num_nodes, sizeof(*total_length));\n    uint32_t *restrict row, *restrict child_row;\n\n    if (num_reference_sets == 0 || num_reference_sets > (INT32_MAX - 1)) {\n        /* TODO: more specific error */\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    if (parent == NULL || ref_count == NULL || last_update == NULL\n        || total_length == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    /* TODO add check for duplicate values in the reference sets */\n\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n    tsk_memset(ret_array, 0, num_nodes * num_reference_sets * sizeof(*ret_array));\n\n    /* Set the initial conditions and check the input. */\n    for (k = 0; k < (int32_t) num_reference_sets; k++) {\n        for (j = 0; j < reference_set_size[k]; j++) {\n            u = reference_sets[k][j];\n            if (u < 0 || u >= (tsk_id_t) num_nodes) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            row = GET_2D_ROW(ref_count, K, u);\n            row[k] = 1;\n            /* Also set the count for the total among all sets */\n            row[K - 1] = 1;\n        }\n    }\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    left = 0;\n    while (tj < num_edges || left < sequence_length) {\n        while (tk < num_edges && edge_right[O[tk]] == left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = TSK_NULL;\n            child_row = GET_2D_ROW(ref_count, K, u);\n            while (v != TSK_NULL) {\n                row = GET_2D_ROW(ref_count, K, v);\n                if (last_update[v] != left) {\n                    if (row[K - 1] > 0) {\n                        length = left - last_update[v];\n                        C_row = GET_2D_ROW(ret_array, num_reference_sets, v);\n                        for (k = 0; k < (int32_t) num_reference_sets; k++) {\n                            C_row[k] += length * row[k];\n                        }\n                        total_length[v] += length;\n                    }\n                    last_update[v] = left;\n                }\n                for (k = 0; k < K; k++) {\n                    row[k] -= child_row[k];\n                }\n                v = parent[v];\n            }\n        }\n        while (tj < num_edges && edge_left[I[tj]] == left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            child_row = GET_2D_ROW(ref_count, K, u);\n            while (v != TSK_NULL) {\n                row = GET_2D_ROW(ref_count, K, v);\n                if (last_update[v] != left) {\n                    if (row[K - 1] > 0) {\n                        length = left - last_update[v];\n                        C_row = GET_2D_ROW(ret_array, num_reference_sets, v);\n                        for (k = 0; k < (int32_t) num_reference_sets; k++) {\n                            C_row[k] += length * row[k];\n                        }\n                        total_length[v] += length;\n                    }\n                    last_update[v] = left;\n                }\n                for (k = 0; k < K; k++) {\n                    row[k] += child_row[k];\n                }\n                v = parent[v];\n            }\n        }\n        right = sequence_length;\n        if (tj < num_edges) {\n            right = TSK_MIN(right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            right = TSK_MIN(right, edge_right[O[tk]]);\n        }\n        left = right;\n    }\n\n    /* Add the stats for the last tree and divide by the total length that\n     * each node was an ancestor to > 0 of the reference nodes. */\n    for (v = 0; v < (tsk_id_t) num_nodes; v++) {\n        row = GET_2D_ROW(ref_count, K, v);\n        C_row = GET_2D_ROW(ret_array, num_reference_sets, v);\n        if (row[K - 1] > 0) {\n            length = sequence_length - last_update[v];\n            total_length[v] += length;\n            for (k = 0; k < (int32_t) num_reference_sets; k++) {\n                C_row[k] += length * row[k];\n            }\n        }\n        if (total_length[v] > 0) {\n            length = total_length[v];\n            for (k = 0; k < (int32_t) num_reference_sets; k++) {\n                C_row[k] /= length;\n            }\n        }\n    }\n\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    if (ref_count != NULL) {\n        free(ref_count);\n    }\n    if (last_update != NULL) {\n        free(last_update);\n    }\n    if (total_length != NULL) {\n        free(total_length);\n    }\n    return ret;\n}\n\n/***********************************\n * General stats framework\n ***********************************/\n\n#define TSK_REQUIRE_FULL_SPAN 1\n\nstatic int\ntsk_treeseq_check_windows(const tsk_treeseq_t *self, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    if (num_windows < 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_NUM_WINDOWS);\n        goto out;\n    }\n    if (options & TSK_REQUIRE_FULL_SPAN) {\n        /* TODO the general stat code currently requires that we include the\n         * entire tree sequence span. This should be relaxed, so hopefully\n         * this branch (and the option) can be removed at some point */\n        if (windows[0] != 0) {\n            ret = tsk_trace_error(TSK_ERR_BAD_WINDOWS);\n            goto out;\n        }\n        if (windows[num_windows] != self->tables->sequence_length) {\n            ret = tsk_trace_error(TSK_ERR_BAD_WINDOWS);\n            goto out;\n        }\n    } else {\n        if (windows[0] < 0) {\n            ret = tsk_trace_error(TSK_ERR_BAD_WINDOWS);\n            goto out;\n        }\n        if (windows[num_windows] > self->tables->sequence_length) {\n            ret = tsk_trace_error(TSK_ERR_BAD_WINDOWS);\n            goto out;\n        }\n    }\n    for (j = 0; j < num_windows; j++) {\n        if (windows[j] >= windows[j + 1]) {\n            ret = tsk_trace_error(TSK_ERR_BAD_WINDOWS);\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ntsk_treeseq_check_time_windows(tsk_size_t num_windows, const double *windows)\n{\n    // This does not check the last window ends at infinity,\n    // which is required for some time window functions.\n    int ret = TSK_ERR_BAD_TIME_WINDOWS;\n    tsk_size_t j;\n\n    if (num_windows < 1) {\n        ret = TSK_ERR_BAD_TIME_WINDOWS_DIM;\n        goto out;\n    }\n\n    if (windows[0] != 0.0) {\n        goto out;\n    }\n\n    for (j = 0; j < num_windows; j++) {\n        if (windows[j] >= windows[j + 1]) {\n            goto out;\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\n/* TODO make these functions more consistent in how the arguments are ordered */\n\nstatic inline void\nupdate_state(double *X, tsk_size_t state_dim, tsk_id_t dest, tsk_id_t source, int sign)\n{\n    tsk_size_t k;\n    double *X_dest = GET_2D_ROW(X, state_dim, dest);\n    double *X_source = GET_2D_ROW(X, state_dim, source);\n\n    for (k = 0; k < state_dim; k++) {\n        X_dest[k] += sign * X_source[k];\n    }\n}\n\nstatic inline int\nupdate_node_summary(tsk_id_t u, tsk_size_t result_dim, double *node_summary, double *X,\n    tsk_size_t state_dim, general_stat_func_t *f, void *f_params)\n{\n    double *X_u = GET_2D_ROW(X, state_dim, u);\n    double *summary_u = GET_2D_ROW(node_summary, result_dim, u);\n\n    return f(state_dim, X_u, result_dim, summary_u, f_params);\n}\n\nstatic inline void\nupdate_running_sum(tsk_id_t u, double sign, const double *restrict branch_length,\n    const double *summary, tsk_size_t result_dim, double *running_sum)\n{\n    const double *summary_u = GET_2D_ROW(summary, result_dim, u);\n    const double x = sign * branch_length[u];\n    tsk_size_t m;\n\n    for (m = 0; m < result_dim; m++) {\n        running_sum[m] += x * summary_u[m];\n    }\n}\n\nstatic int\ntsk_treeseq_branch_general_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    const double *sample_weights, tsk_size_t result_dim, general_stat_func_t *f,\n    void *f_params, tsk_size_t num_windows, const double *windows, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t j, k, window_index;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double *restrict time = self->tables->nodes.time;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    double *restrict branch_length = tsk_calloc(num_nodes, sizeof(*branch_length));\n    tsk_id_t tj, tk, h;\n    double t_left, t_right, w_left, w_right, left, right, scale;\n    const double *weight_u;\n    double *state_u, *result_row, *summary_u;\n    double *state = tsk_calloc(num_nodes * state_dim, sizeof(*state));\n    double *summary = tsk_calloc(num_nodes * result_dim, sizeof(*summary));\n    double *running_sum = tsk_calloc(result_dim, sizeof(*running_sum));\n    double *zero_state = tsk_calloc(state_dim, sizeof(*zero_state));\n    double *zero_summary = tsk_calloc(result_dim, sizeof(*zero_state));\n\n    if (self->time_uncalibrated && !(options & TSK_STAT_ALLOW_TIME_UNCALIBRATED)) {\n        ret = tsk_trace_error(TSK_ERR_TIME_UNCALIBRATED);\n        goto out;\n    }\n\n    if (parent == NULL || branch_length == NULL || state == NULL || running_sum == NULL\n        || summary == NULL || zero_state == NULL || zero_summary == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n\n    /* If f is not strict, we may need to set conditions for non-sample nodes as well. */\n    ret = f(state_dim, zero_state, result_dim, zero_summary, f_params);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_nodes; j++) { // we could skip this if zero_summary is zero\n        summary_u = GET_2D_ROW(summary, result_dim, j);\n        tsk_memcpy(summary_u, zero_summary, result_dim * sizeof(*zero_summary));\n    }\n    /* Set the initial conditions */\n    for (j = 0; j < self->num_samples; j++) {\n        u = self->samples[j];\n        state_u = GET_2D_ROW(state, state_dim, u);\n        weight_u = GET_2D_ROW(sample_weights, state_dim, j);\n        tsk_memcpy(state_u, weight_u, state_dim * sizeof(*state_u));\n        summary_u = GET_2D_ROW(summary, result_dim, u);\n        ret = f(state_dim, state_u, result_dim, summary_u, f_params);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    tsk_memset(result, 0, num_windows * result_dim * sizeof(*result));\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    t_left = 0;\n    window_index = 0;\n    while (tj < num_edges || t_left < sequence_length) {\n        while (tk < num_edges && edge_right[O[tk]] == t_left) {\n            h = O[tk];\n            tk++;\n\n            u = edge_child[h];\n            update_running_sum(u, -1, branch_length, summary, result_dim, running_sum);\n            parent[u] = TSK_NULL;\n            branch_length[u] = 0;\n\n            u = edge_parent[h];\n            while (u != TSK_NULL) {\n                update_running_sum(\n                    u, -1, branch_length, summary, result_dim, running_sum);\n                update_state(state, state_dim, u, edge_child[h], -1);\n                ret = update_node_summary(\n                    u, result_dim, summary, state, state_dim, f, f_params);\n                if (ret != 0) {\n                    goto out;\n                }\n                update_running_sum(\n                    u, +1, branch_length, summary, result_dim, running_sum);\n                u = parent[u];\n            }\n        }\n\n        while (tj < num_edges && edge_left[I[tj]] == t_left) {\n            h = I[tj];\n            tj++;\n\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            branch_length[u] = time[v] - time[u];\n            update_running_sum(u, +1, branch_length, summary, result_dim, running_sum);\n\n            u = v;\n            while (u != TSK_NULL) {\n                update_running_sum(\n                    u, -1, branch_length, summary, result_dim, running_sum);\n                update_state(state, state_dim, u, edge_child[h], +1);\n                ret = update_node_summary(\n                    u, result_dim, summary, state, state_dim, f, f_params);\n                if (ret != 0) {\n                    goto out;\n                }\n                update_running_sum(\n                    u, +1, branch_length, summary, result_dim, running_sum);\n                u = parent[u];\n            }\n        }\n\n        t_right = sequence_length;\n        if (tj < num_edges) {\n            t_right = TSK_MIN(t_right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            t_right = TSK_MIN(t_right, edge_right[O[tk]]);\n        }\n\n        while (windows[window_index] < t_right) {\n            tsk_bug_assert(window_index < num_windows);\n            w_left = windows[window_index];\n            w_right = windows[window_index + 1];\n            left = TSK_MAX(t_left, w_left);\n            right = TSK_MIN(t_right, w_right);\n            scale = (right - left);\n            tsk_bug_assert(scale > 0);\n            result_row = GET_2D_ROW(result, result_dim, window_index);\n            for (k = 0; k < result_dim; k++) {\n                result_row[k] += running_sum[k] * scale;\n            }\n\n            if (w_right <= t_right) {\n                window_index++;\n            } else {\n                /* This interval crosses a tree boundary, so we update it again in the */\n                /* for the next tree */\n                break;\n            }\n        }\n        /* Move to the next tree */\n        t_left = t_right;\n    }\n    tsk_bug_assert(window_index == num_windows);\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    if (branch_length != NULL) {\n        free(branch_length);\n    }\n    tsk_safe_free(state);\n    tsk_safe_free(summary);\n    tsk_safe_free(running_sum);\n    tsk_safe_free(zero_state);\n    tsk_safe_free(zero_summary);\n    return ret;\n}\n\nstatic int\nget_allele_weights(const tsk_site_t *site, const double *state, tsk_size_t state_dim,\n    const double *total_weight, tsk_size_t *ret_num_alleles, double **ret_allele_states)\n{\n    int ret = 0;\n    tsk_size_t k;\n    tsk_mutation_t mutation, parent_mut;\n    tsk_size_t mutation_index, allele, num_alleles, alt_allele_length;\n    /* The allele table */\n    tsk_size_t max_alleles = site->mutations_length + 1;\n    const char **alleles = tsk_malloc(max_alleles * sizeof(*alleles));\n    tsk_size_t *allele_lengths = tsk_calloc(max_alleles, sizeof(*allele_lengths));\n    double *allele_states = tsk_calloc(max_alleles * state_dim, sizeof(*allele_states));\n    double *allele_row;\n    const double *state_row;\n    const char *alt_allele;\n\n    if (alleles == NULL || allele_lengths == NULL || allele_states == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    tsk_bug_assert(state != NULL);\n    alleles[0] = site->ancestral_state;\n    allele_lengths[0] = site->ancestral_state_length;\n    tsk_memcpy(allele_states, total_weight, state_dim * sizeof(*allele_states));\n    num_alleles = 1;\n\n    for (mutation_index = 0; mutation_index < site->mutations_length; mutation_index++) {\n        mutation = site->mutations[mutation_index];\n        /* Compute the allele index for this derived state value. */\n        allele = 0;\n        while (allele < num_alleles) {\n            if (mutation.derived_state_length == allele_lengths[allele]\n                && tsk_memcmp(\n                       mutation.derived_state, alleles[allele], allele_lengths[allele])\n                       == 0) {\n                break;\n            }\n            allele++;\n        }\n        if (allele == num_alleles) {\n            tsk_bug_assert(allele < max_alleles);\n            alleles[allele] = mutation.derived_state;\n            allele_lengths[allele] = mutation.derived_state_length;\n            num_alleles++;\n        }\n\n        /* Add the state for the the mutation's node to this allele */\n        state_row = GET_2D_ROW(state, state_dim, mutation.node);\n        allele_row = GET_2D_ROW(allele_states, state_dim, allele);\n        for (k = 0; k < state_dim; k++) {\n            allele_row[k] += state_row[k];\n        }\n\n        /* Get the index for the alternate allele that we must subtract from */\n        alt_allele = site->ancestral_state;\n        alt_allele_length = site->ancestral_state_length;\n        if (mutation.parent != TSK_NULL) {\n            parent_mut = site->mutations[mutation.parent - site->mutations[0].id];\n            alt_allele = parent_mut.derived_state;\n            alt_allele_length = parent_mut.derived_state_length;\n        }\n        allele = 0;\n        while (allele < num_alleles) {\n            if (alt_allele_length == allele_lengths[allele]\n                && tsk_memcmp(alt_allele, alleles[allele], allele_lengths[allele])\n                       == 0) {\n                break;\n            }\n            allele++;\n        }\n        tsk_bug_assert(allele < num_alleles);\n\n        allele_row = GET_2D_ROW(allele_states, state_dim, allele);\n        for (k = 0; k < state_dim; k++) {\n            allele_row[k] -= state_row[k];\n        }\n    }\n    *ret_num_alleles = num_alleles;\n    *ret_allele_states = allele_states;\n    allele_states = NULL;\nout:\n    tsk_safe_free(alleles);\n    tsk_safe_free(allele_lengths);\n    tsk_safe_free(allele_states);\n    return ret;\n}\n\nstatic int\ncompute_general_stat_site_result(tsk_site_t *site, double *state, tsk_size_t state_dim,\n    tsk_size_t result_dim, general_stat_func_t *f, void *f_params, double *total_weight,\n    bool polarised, double *result)\n{\n    int ret = 0;\n    tsk_size_t k;\n    tsk_size_t allele, num_alleles;\n    double *allele_states;\n    double *result_tmp = tsk_calloc(result_dim, sizeof(*result_tmp));\n\n    if (result_tmp == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(result, 0, result_dim * sizeof(*result));\n\n    ret = get_allele_weights(\n        site, state, state_dim, total_weight, &num_alleles, &allele_states);\n    if (ret != 0) {\n        goto out;\n    }\n    /* Sum over the allele weights. Skip the ancestral state if this is a polarised stat\n     */\n    for (allele = polarised ? 1 : 0; allele < num_alleles; allele++) {\n        ret = f(state_dim, GET_2D_ROW(allele_states, state_dim, allele), result_dim,\n            result_tmp, f_params);\n        if (ret != 0) {\n            goto out;\n        }\n        for (k = 0; k < result_dim; k++) {\n            result[k] += result_tmp[k];\n        }\n    }\nout:\n    tsk_safe_free(result_tmp);\n    tsk_safe_free(allele_states);\n    return ret;\n}\n\nstatic int\ntsk_treeseq_site_general_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    const double *sample_weights, tsk_size_t result_dim, general_stat_func_t *f,\n    void *f_params, tsk_size_t num_windows, const double *windows, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t j, k, tree_site, tree_index, window_index;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    tsk_site_t *site;\n    tsk_id_t tj, tk, h;\n    double t_left, t_right;\n    const double *weight_u;\n    double *state_u, *result_row;\n    double *state = tsk_calloc(num_nodes * state_dim, sizeof(*state));\n    double *total_weight = tsk_calloc(state_dim, sizeof(*total_weight));\n    double *site_result = tsk_calloc(result_dim, sizeof(*site_result));\n    bool polarised = false;\n\n    if (parent == NULL || state == NULL || total_weight == NULL || site_result == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n\n    if (options & TSK_STAT_POLARISED) {\n        polarised = true;\n    }\n\n    /* Set the initial conditions */\n    for (j = 0; j < self->num_samples; j++) {\n        u = self->samples[j];\n        state_u = GET_2D_ROW(state, state_dim, u);\n        weight_u = GET_2D_ROW(sample_weights, state_dim, j);\n        tsk_memcpy(state_u, weight_u, state_dim * sizeof(*state_u));\n        for (k = 0; k < state_dim; k++) {\n            total_weight[k] += weight_u[k];\n        }\n    }\n    tsk_memset(result, 0, num_windows * result_dim * sizeof(*result));\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    t_left = 0;\n    tree_index = 0;\n    window_index = 0;\n    while (tj < num_edges || t_left < sequence_length) {\n        while (tk < num_edges && edge_right[O[tk]] == t_left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            while (v != TSK_NULL) {\n                update_state(state, state_dim, v, u, -1);\n                v = parent[v];\n            }\n            parent[u] = TSK_NULL;\n        }\n\n        while (tj < num_edges && edge_left[I[tj]] == t_left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            while (v != TSK_NULL) {\n                update_state(state, state_dim, v, u, +1);\n                v = parent[v];\n            }\n        }\n        t_right = sequence_length;\n        if (tj < num_edges) {\n            t_right = TSK_MIN(t_right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            t_right = TSK_MIN(t_right, edge_right[O[tk]]);\n        }\n\n        /* Update the sites */\n        for (tree_site = 0; tree_site < self->tree_sites_length[tree_index];\n             tree_site++) {\n            site = self->tree_sites[tree_index] + tree_site;\n            ret = compute_general_stat_site_result(site, state, state_dim, result_dim, f,\n                f_params, total_weight, polarised, site_result);\n            if (ret != 0) {\n                goto out;\n            }\n\n            while (windows[window_index + 1] <= site->position) {\n                window_index++;\n                tsk_bug_assert(window_index < num_windows);\n            }\n            tsk_bug_assert(windows[window_index] <= site->position);\n            tsk_bug_assert(site->position < windows[window_index + 1]);\n            result_row = GET_2D_ROW(result, result_dim, window_index);\n            for (k = 0; k < result_dim; k++) {\n                result_row[k] += site_result[k];\n            }\n        }\n        tree_index++;\n        t_left = t_right;\n    }\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    tsk_safe_free(state);\n    tsk_safe_free(total_weight);\n    tsk_safe_free(site_result);\n    return ret;\n}\n\nstatic inline void\nincrement_row(tsk_size_t length, double multiplier, double *source, double *dest)\n{\n    tsk_size_t j;\n\n    for (j = 0; j < length; j++) {\n        dest[j] += multiplier * source[j];\n    }\n}\n\nstatic int\ntsk_treeseq_node_general_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    const double *sample_weights, tsk_size_t result_dim, general_stat_func_t *f,\n    void *f_params, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t TSK_UNUSED(options), double *result)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t j, window_index;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    tsk_id_t tj, tk, h;\n    const double *weight_u;\n    double *state_u;\n    double *state = tsk_calloc(num_nodes * state_dim, sizeof(*state));\n    double *node_summary = tsk_calloc(num_nodes * result_dim, sizeof(*node_summary));\n    double *last_update = tsk_calloc(num_nodes, sizeof(*last_update));\n    double t_left, t_right, w_right;\n\n    if (parent == NULL || state == NULL || node_summary == NULL || last_update == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n    tsk_memset(result, 0, num_windows * num_nodes * result_dim * sizeof(*result));\n\n    /* Set the initial conditions */\n    for (j = 0; j < self->num_samples; j++) {\n        u = self->samples[j];\n        state_u = GET_2D_ROW(state, state_dim, u);\n        weight_u = GET_2D_ROW(sample_weights, state_dim, j);\n        tsk_memcpy(state_u, weight_u, state_dim * sizeof(*state_u));\n    }\n    for (u = 0; u < (tsk_id_t) num_nodes; u++) {\n        ret = update_node_summary(\n            u, result_dim, node_summary, state, state_dim, f, f_params);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    t_left = 0;\n    window_index = 0;\n    while (tj < num_edges || t_left < sequence_length) {\n        tsk_bug_assert(window_index < num_windows);\n        while (tk < num_edges && edge_right[O[tk]] == t_left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            while (v != TSK_NULL) {\n                increment_row(result_dim, t_left - last_update[v],\n                    GET_2D_ROW(node_summary, result_dim, v),\n                    GET_3D_ROW(result, num_nodes, result_dim, window_index, v));\n                last_update[v] = t_left;\n                update_state(state, state_dim, v, u, -1);\n                ret = update_node_summary(\n                    v, result_dim, node_summary, state, state_dim, f, f_params);\n                if (ret != 0) {\n                    goto out;\n                }\n                v = parent[v];\n            }\n            parent[u] = TSK_NULL;\n        }\n\n        while (tj < num_edges && edge_left[I[tj]] == t_left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            while (v != TSK_NULL) {\n                increment_row(result_dim, t_left - last_update[v],\n                    GET_2D_ROW(node_summary, result_dim, v),\n                    GET_3D_ROW(result, num_nodes, result_dim, window_index, v));\n                last_update[v] = t_left;\n                update_state(state, state_dim, v, u, +1);\n                ret = update_node_summary(\n                    v, result_dim, node_summary, state, state_dim, f, f_params);\n                if (ret != 0) {\n                    goto out;\n                }\n                v = parent[v];\n            }\n        }\n\n        t_right = sequence_length;\n        if (tj < num_edges) {\n            t_right = TSK_MIN(t_right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            t_right = TSK_MIN(t_right, edge_right[O[tk]]);\n        }\n\n        while (window_index < num_windows && windows[window_index + 1] <= t_right) {\n            w_right = windows[window_index + 1];\n            /* Flush the contributions of all nodes to the current window */\n            for (u = 0; u < (tsk_id_t) num_nodes; u++) {\n                tsk_bug_assert(last_update[u] < w_right);\n                increment_row(result_dim, w_right - last_update[u],\n                    GET_2D_ROW(node_summary, result_dim, u),\n                    GET_3D_ROW(result, num_nodes, result_dim, window_index, u));\n                last_update[u] = w_right;\n            }\n            window_index++;\n        }\n\n        t_left = t_right;\n    }\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    tsk_safe_free(state);\n    tsk_safe_free(node_summary);\n    tsk_safe_free(last_update);\n    return ret;\n}\n\nstatic void\nspan_normalise(\n    tsk_size_t num_windows, const double *windows, tsk_size_t row_size, double *array)\n{\n    tsk_size_t window_index, k;\n    double span, *row;\n\n    for (window_index = 0; window_index < num_windows; window_index++) {\n        span = windows[window_index + 1] - windows[window_index];\n        row = GET_2D_ROW(array, row_size, window_index);\n        for (k = 0; k < row_size; k++) {\n            row[k] /= span;\n        }\n    }\n}\n\ntypedef struct {\n    general_stat_func_t *f;\n    void *f_params;\n    double *total_weight;\n    double *total_minus_state;\n    double *result_tmp;\n} unpolarised_summary_func_args;\n\nstatic int\nunpolarised_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    int ret = 0;\n    unpolarised_summary_func_args *upargs = (unpolarised_summary_func_args *) params;\n    const double *total_weight = upargs->total_weight;\n    double *total_minus_state = upargs->total_minus_state;\n    double *result_tmp = upargs->result_tmp;\n    tsk_size_t k, m;\n\n    ret = upargs->f(state_dim, state, result_dim, result, upargs->f_params);\n    if (ret != 0) {\n        goto out;\n    }\n    for (k = 0; k < state_dim; k++) {\n        total_minus_state[k] = total_weight[k] - state[k];\n    }\n    ret = upargs->f(\n        state_dim, total_minus_state, result_dim, result_tmp, upargs->f_params);\n    if (ret != 0) {\n        goto out;\n    }\n    for (m = 0; m < result_dim; m++) {\n        result[m] += result_tmp[m];\n    }\nout:\n    return ret;\n}\n\n/* Abstracts the running of node and branch stats where the summary function\n * is run twice when non-polarised. We replace the call to the input summary\n * function with a call of the required form when non-polarised, simplifying\n * the implementation and memory management for the node and branch stats.\n */\nstatic int\ntsk_polarisable_func_general_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    const double *sample_weights, tsk_size_t result_dim, general_stat_func_t *f,\n    void *f_params, tsk_size_t num_windows, const double *windows, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    bool stat_branch = !!(options & TSK_STAT_BRANCH);\n    bool polarised = options & TSK_STAT_POLARISED;\n    general_stat_func_t *wrapped_f = f;\n    void *wrapped_f_params = f_params;\n    const double *weight_u;\n    unpolarised_summary_func_args upargs;\n    tsk_size_t j, k;\n\n    tsk_memset(&upargs, 0, sizeof(upargs));\n    if (!polarised) {\n        upargs.f = f;\n        upargs.f_params = f_params;\n        upargs.total_weight = tsk_calloc(state_dim, sizeof(double));\n        upargs.total_minus_state = tsk_calloc(state_dim, sizeof(double));\n        upargs.result_tmp = tsk_calloc(result_dim, sizeof(double));\n\n        if (upargs.total_weight == NULL || upargs.total_minus_state == NULL\n            || upargs.result_tmp == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n\n        /* Compute the total weight */\n        for (j = 0; j < self->num_samples; j++) {\n            weight_u = GET_2D_ROW(sample_weights, state_dim, j);\n            for (k = 0; k < state_dim; k++) {\n                upargs.total_weight[k] += weight_u[k];\n            }\n        }\n\n        wrapped_f = unpolarised_summary_func;\n        wrapped_f_params = &upargs;\n    }\n\n    if (stat_branch) {\n        ret = tsk_treeseq_branch_general_stat(self, state_dim, sample_weights,\n            result_dim, wrapped_f, wrapped_f_params, num_windows, windows, options,\n            result);\n    } else {\n        ret = tsk_treeseq_node_general_stat(self, state_dim, sample_weights, result_dim,\n            wrapped_f, wrapped_f_params, num_windows, windows, options, result);\n    }\nout:\n    tsk_safe_free(upargs.total_weight);\n    tsk_safe_free(upargs.total_minus_state);\n    tsk_safe_free(upargs.result_tmp);\n    return ret;\n}\n\nint\ntsk_treeseq_general_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    const double *sample_weights, tsk_size_t result_dim, general_stat_func_t *f,\n    void *f_params, tsk_size_t num_windows, const double *windows, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    bool stat_site = !!(options & TSK_STAT_SITE);\n    bool stat_branch = !!(options & TSK_STAT_BRANCH);\n    bool stat_node = !!(options & TSK_STAT_NODE);\n    double default_windows[] = { 0, self->tables->sequence_length };\n    tsk_size_t row_size;\n\n    /* If no mode is specified, we default to site mode */\n    if (!(stat_site || stat_branch || stat_node)) {\n        stat_site = true;\n    }\n    /* It's an error to specify more than one mode */\n    if (stat_site + stat_branch + stat_node > 1) {\n        ret = tsk_trace_error(TSK_ERR_MULTIPLE_STAT_MODES);\n        goto out;\n    }\n\n    if (state_dim < 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_STATE_DIMS);\n        goto out;\n    }\n    if (result_dim < 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_RESULT_DIMS);\n        goto out;\n    }\n    if (windows == NULL) {\n        num_windows = 1;\n        windows = default_windows;\n    } else {\n        ret = tsk_treeseq_check_windows(\n            self, num_windows, windows, TSK_REQUIRE_FULL_SPAN);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    if (stat_site) {\n        ret = tsk_treeseq_site_general_stat(self, state_dim, sample_weights, result_dim,\n            f, f_params, num_windows, windows, options, result);\n    } else {\n        ret = tsk_polarisable_func_general_stat(self, state_dim, sample_weights,\n            result_dim, f, f_params, num_windows, windows, options, result);\n    }\n\n    if (options & TSK_STAT_SPAN_NORMALISE) {\n        row_size = result_dim;\n        if (stat_node) {\n            row_size = result_dim * tsk_treeseq_get_num_nodes(self);\n        }\n        span_normalise(num_windows, windows, row_size, result);\n    }\n\nout:\n    return ret;\n}\n\nstatic int\ncheck_set_indexes(\n    tsk_size_t num_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes)\n{\n    int ret = 0;\n    tsk_size_t j;\n\n    for (j = 0; j < num_set_indexes; j++) {\n        if (set_indexes[j] < 0 || set_indexes[j] >= (tsk_id_t) num_sets) {\n            ret = tsk_trace_error(TSK_ERR_BAD_SAMPLE_SET_INDEX);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ntsk_treeseq_check_sample_sets(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets)\n{\n    int ret = 0;\n    tsk_size_t j, k, l;\n    const tsk_id_t num_nodes = (tsk_id_t) self->tables->nodes.num_rows;\n    tsk_id_t u, sample_index;\n\n    if (num_sample_sets == 0) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_SAMPLE_SETS);\n        goto out;\n    }\n    j = 0;\n    for (k = 0; k < num_sample_sets; k++) {\n        if (sample_set_sizes[k] == 0) {\n            ret = tsk_trace_error(TSK_ERR_EMPTY_SAMPLE_SET);\n            goto out;\n        }\n        for (l = 0; l < sample_set_sizes[k]; l++) {\n            u = sample_sets[j];\n            if (u < 0 || u >= num_nodes) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            sample_index = self->sample_index_map[u];\n            if (sample_index == TSK_NULL) {\n                ret = tsk_trace_error(TSK_ERR_BAD_SAMPLES);\n                goto out;\n            }\n            j++;\n        }\n    }\nout:\n    return ret;\n}\n\ntypedef struct {\n    tsk_size_t num_samples;\n} weight_stat_params_t;\n\ntypedef struct {\n    tsk_size_t num_samples;\n    tsk_size_t num_covariates;\n    double *V;\n} covariates_stat_params_t;\n\ntypedef struct {\n    const tsk_id_t *sample_sets;\n    tsk_size_t num_sample_sets;\n    const tsk_size_t *sample_set_sizes;\n    const tsk_id_t *set_indexes;\n} sample_count_stat_params_t;\n\ntypedef struct {\n    tsk_size_t num_samples;\n    double *total_weights;\n    const tsk_id_t *index_tuples;\n} indexed_weight_stat_params_t;\n\nstatic int\ntsk_treeseq_sample_count_stat(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t result_dim, const tsk_id_t *set_indexes, general_stat_func_t *f,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    const tsk_size_t num_samples = self->num_samples;\n    tsk_size_t j, k, l;\n    tsk_id_t u, sample_index;\n    double *weights = NULL;\n    double *weight_row;\n    sample_count_stat_params_t args = { .sample_sets = sample_sets,\n        .num_sample_sets = num_sample_sets,\n        .sample_set_sizes = sample_set_sizes,\n        .set_indexes = set_indexes };\n\n    ret = tsk_treeseq_check_sample_sets(\n        self, num_sample_sets, sample_set_sizes, sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n    weights = tsk_calloc(num_samples * num_sample_sets, sizeof(*weights));\n    if (weights == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    j = 0;\n    for (k = 0; k < num_sample_sets; k++) {\n        for (l = 0; l < sample_set_sizes[k]; l++) {\n            u = sample_sets[j];\n            sample_index = self->sample_index_map[u];\n            weight_row = GET_2D_ROW(weights, num_sample_sets, sample_index);\n            if (weight_row[k] != 0) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            weight_row[k] = 1;\n            j++;\n        }\n    }\n    ret = tsk_treeseq_general_stat(self, num_sample_sets, weights, result_dim, f, &args,\n        num_windows, windows, options, result);\nout:\n    tsk_safe_free(weights);\n    return ret;\n}\n\n/***********************************\n * Two Locus Statistics\n ***********************************/\n\nstatic int\nget_allele_samples(const tsk_site_t *site, tsk_size_t site_offset,\n    const tsk_bitset_t *state, tsk_bitset_t *out_allele_samples,\n    tsk_size_t *out_num_alleles)\n{\n    int ret = 0;\n    tsk_mutation_t mutation, parent_mut;\n    tsk_size_t mutation_index, allele, alt_allele, alt_allele_length;\n    /* The allele table */\n    tsk_size_t max_alleles = site->mutations_length + 1;\n    const char **alleles = tsk_malloc(max_alleles * sizeof(*alleles));\n    tsk_size_t *allele_lengths = tsk_calloc(max_alleles, sizeof(*allele_lengths));\n    const char *alt_allele_state;\n    tsk_size_t num_alleles = 1;\n\n    if (alleles == NULL || allele_lengths == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    tsk_bug_assert(state != NULL);\n    alleles[0] = site->ancestral_state;\n    allele_lengths[0] = site->ancestral_state_length;\n\n    for (mutation_index = 0; mutation_index < site->mutations_length; mutation_index++) {\n        mutation = site->mutations[mutation_index];\n        /* Compute the allele index for this derived state value. */\n        for (allele = 0; allele < num_alleles; allele++) {\n            if (mutation.derived_state_length == allele_lengths[allele]\n                && tsk_memcmp(\n                       mutation.derived_state, alleles[allele], allele_lengths[allele])\n                       == 0) {\n                break;\n            }\n        }\n        if (allele == num_alleles) {\n            tsk_bug_assert(allele < max_alleles);\n            alleles[allele] = mutation.derived_state;\n            allele_lengths[allele] = mutation.derived_state_length;\n            num_alleles++;\n        }\n\n        /* Add the mutation's samples to this allele */\n        tsk_bitset_union(\n            out_allele_samples, allele + site_offset, state, mutation_index);\n\n        /* Get the index for the alternate allele that we must subtract from */\n        alt_allele_state = site->ancestral_state;\n        alt_allele_length = site->ancestral_state_length;\n        if (mutation.parent != TSK_NULL) {\n            parent_mut = site->mutations[mutation.parent - site->mutations[0].id];\n            alt_allele_state = parent_mut.derived_state;\n            alt_allele_length = parent_mut.derived_state_length;\n        }\n        for (alt_allele = 0; alt_allele < num_alleles; alt_allele++) {\n            if (alt_allele_length == allele_lengths[alt_allele]\n                && tsk_memcmp(\n                       alt_allele_state, alleles[alt_allele], allele_lengths[alt_allele])\n                       == 0) {\n                break;\n            }\n        }\n        tsk_bug_assert(allele < num_alleles);\n\n        tsk_bitset_subtract(out_allele_samples, alt_allele + site_offset,\n            out_allele_samples, allele + site_offset);\n    }\n    *out_num_alleles = num_alleles;\nout:\n    tsk_safe_free(alleles);\n    tsk_safe_free(allele_lengths);\n    return ret;\n}\n\nstatic int\nnorm_hap_weighted(tsk_size_t result_dim, const double *hap_weights,\n    tsk_size_t TSK_UNUSED(n_a), tsk_size_t TSK_UNUSED(n_b), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *weight_row;\n    double n;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        weight_row = GET_2D_ROW(hap_weights, 3, k);\n        n = (double) args.sample_set_sizes[k];\n        result[k] = weight_row[0] / n;\n    }\n    return 0;\n}\n\nstatic int\nnorm_hap_weighted_ij(tsk_size_t result_dim, const double *hap_weights,\n    tsk_size_t TSK_UNUSED(n_a), tsk_size_t TSK_UNUSED(n_b), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *weight_row;\n    double ni, nj, wAB_i, wAB_j;\n    tsk_id_t i, j;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        weight_row = GET_2D_ROW(hap_weights, 3, i);\n        wAB_i = weight_row[0];\n        weight_row = GET_2D_ROW(hap_weights, 3, j);\n        wAB_j = weight_row[0];\n\n        result[k] = (wAB_i + wAB_j) / (ni + nj);\n    }\n\n    return 0;\n}\n\nstatic int\nnorm_total_weighted(tsk_size_t result_dim, const double *TSK_UNUSED(hap_weights),\n    tsk_size_t n_a, tsk_size_t n_b, double *result, void *TSK_UNUSED(params))\n{\n    tsk_size_t k;\n    double norm = 1 / (double) (n_a * n_b);\n\n    for (k = 0; k < result_dim; k++) {\n        result[k] = norm;\n    }\n    return 0;\n}\n\nstatic void\nget_all_samples_bits(tsk_bitset_t *all_samples, tsk_size_t n)\n{\n    tsk_size_t i;\n    const tsk_bitset_val_t all = ~((tsk_bitset_val_t) 0);\n    const tsk_bitset_val_t remainder_samples = n % TSK_BITSET_BITS;\n\n    all_samples->data[all_samples->row_len - 1]\n        = remainder_samples ? ~(all << remainder_samples) : all;\n    for (i = 0; i < all_samples->row_len - 1; i++) {\n        all_samples->data[i] = all;\n    }\n}\n\n// Stores the intermediate values for computing two-locus statistics.\ntypedef struct {\n    double *weights;\n    double *norm;\n    double *result_tmp;\n    tsk_bitset_t AB_samples;\n} two_locus_work_t;\n\nstatic int\ntwo_locus_work_init(tsk_size_t max_alleles, tsk_size_t num_samples,\n    tsk_size_t result_dim, tsk_size_t state_dim, two_locus_work_t *out)\n{\n    int ret = 0;\n\n    out->weights = tsk_malloc(3 * state_dim * sizeof(*out->weights));\n    out->norm = tsk_malloc(result_dim * sizeof(*out->norm));\n    out->result_tmp\n        = tsk_malloc(result_dim * max_alleles * max_alleles * sizeof(*out->result_tmp));\n    tsk_memset(&out->AB_samples, 0, sizeof(out->AB_samples));\n    if (out->weights == NULL || out->norm == NULL || out->result_tmp == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_bitset_init(&out->AB_samples, num_samples, 1);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic void\ntwo_locus_work_free(two_locus_work_t *work)\n{\n    tsk_safe_free(work->weights);\n    tsk_safe_free(work->norm);\n    tsk_safe_free(work->result_tmp);\n    tsk_bitset_free(&work->AB_samples);\n}\n\nstatic int\ncompute_general_normed_two_site_stat_result(const tsk_bitset_t *state,\n    const tsk_size_t *allele_counts, tsk_size_t a_off, tsk_size_t b_off,\n    tsk_size_t num_a_alleles, tsk_size_t num_b_alleles, tsk_size_t state_dim,\n    tsk_size_t result_dim, general_stat_func_t *f, sample_count_stat_params_t *f_params,\n    norm_func_t *norm_f, bool polarised, two_locus_work_t *restrict work, double *result)\n{\n    int ret = 0;\n    // Sample sets and b sites are rows, a sites are columns\n    //       b1           b2           b3\n    // a1   [s1, s2, s3] [s1, s2, s3] [s1, s2, s3]\n    // a2   [s1, s2, s3] [s1, s2, s3] [s1, s2, s3]\n    // a3   [s1, s2, s3] [s1, s2, s3] [s1, s2, s3]\n    tsk_size_t k, mut_a, mut_b, result_row_len = num_b_alleles * result_dim;\n    uint8_t is_polarised = polarised ? 1 : 0;\n    double *restrict hap_row, *restrict result_tmp_row;\n    double *restrict norm = work->norm;\n    double *restrict weights = work->weights;\n    double *restrict result_tmp = work->result_tmp;\n    tsk_bitset_t AB_samples = work->AB_samples;\n\n    for (mut_a = is_polarised; mut_a < num_a_alleles; mut_a++) {\n        result_tmp_row = GET_2D_ROW(result_tmp, result_row_len, mut_a);\n        for (mut_b = is_polarised; mut_b < num_b_alleles; mut_b++) {\n            for (k = 0; k < state_dim; k++) {\n                tsk_bitset_intersect(state, a_off + (mut_a * state_dim) + k, state,\n                    b_off + (mut_b * state_dim) + k, &AB_samples);\n                hap_row = GET_2D_ROW(weights, 3, k);\n                hap_row[0] = (double) tsk_bitset_count(&AB_samples, 0);\n                hap_row[1] = (double) allele_counts[a_off + (mut_a * state_dim) + k]\n                             - hap_row[0];\n                hap_row[2] = (double) allele_counts[b_off + (mut_b * state_dim) + k]\n                             - hap_row[0];\n            }\n            ret = f(state_dim, weights, result_dim, result_tmp_row, f_params);\n            if (ret != 0) {\n                goto out;\n            }\n            ret = norm_f(result_dim, weights, num_a_alleles - is_polarised,\n                num_b_alleles - is_polarised, norm, f_params);\n            if (ret != 0) {\n                goto out;\n            }\n            for (k = 0; k < result_dim; k++) {\n                result[k] += result_tmp_row[k] * norm[k];\n            }\n            result_tmp_row += result_dim; // Advance to the next column\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ncompute_general_two_site_stat_result(const tsk_bitset_t *state,\n    const tsk_size_t *allele_counts, tsk_size_t a_off, tsk_size_t b_off,\n    tsk_size_t state_dim, tsk_size_t result_dim, general_stat_func_t *f,\n    sample_count_stat_params_t *f_params, two_locus_work_t *restrict work,\n    double *result)\n{\n    int ret = 0;\n    tsk_size_t k;\n    tsk_bitset_t AB_samples = work->AB_samples;\n    tsk_size_t mut_a = 1, mut_b = 1;\n    double *restrict hap_row, *restrict weights = work->weights;\n\n    for (k = 0; k < state_dim; k++) {\n        tsk_bitset_intersect(state, a_off + (mut_a * state_dim) + k, state,\n            b_off + (mut_b * state_dim) + k, &AB_samples);\n        hap_row = GET_2D_ROW(weights, 3, k);\n        hap_row[0] = (double) tsk_bitset_count(&AB_samples, 0);\n        hap_row[1]\n            = (double) allele_counts[a_off + (mut_a * state_dim) + k] - hap_row[0];\n        hap_row[2]\n            = (double) allele_counts[b_off + (mut_b * state_dim) + k] - hap_row[0];\n    }\n    ret = f(state_dim, weights, result_dim, result, f_params);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic void\nget_site_row_col_indices(tsk_size_t n_rows, const tsk_id_t *row_sites, tsk_size_t n_cols,\n    const tsk_id_t *col_sites, tsk_id_t *sites, tsk_size_t *n_sites, tsk_size_t *row_idx,\n    tsk_size_t *col_idx)\n{\n    tsk_size_t r = 0, c = 0, s = 0;\n\n    // Iterate rows and columns until we've exhaused one of the lists\n    while ((r < n_rows) && (c < n_cols)) {\n        if (row_sites[r] < col_sites[c]) {\n            sites[s] = row_sites[r];\n            row_idx[r] = s;\n            s++;\n            r++;\n        } else if (col_sites[c] < row_sites[r]) {\n            sites[s] = col_sites[c];\n            col_idx[c] = s;\n            s++;\n            c++;\n        } else { // row == col\n            sites[s] = row_sites[r];\n            col_idx[c] = s;\n            row_idx[r] = s;\n            s++;\n            r++;\n            c++;\n        }\n    }\n\n    // If there are any items remaining in the other list, drain it\n    while (r < n_rows) {\n        sites[s] = row_sites[r];\n        row_idx[r] = s;\n        s++;\n        r++;\n    }\n    while (c < n_cols) {\n        sites[s] = col_sites[c];\n        col_idx[c] = s;\n        s++;\n        c++;\n    }\n    *n_sites = s;\n}\n\nstatic int\nget_mutation_samples(const tsk_treeseq_t *ts, const tsk_id_t *sites, tsk_size_t n_sites,\n    tsk_size_t *num_alleles, tsk_bitset_t *allele_samples)\n{\n    int ret = 0;\n    const tsk_flags_t *restrict flags = ts->tables->nodes.flags;\n    const tsk_size_t num_samples = tsk_treeseq_get_num_samples(ts);\n    const tsk_size_t *restrict site_muts_len = ts->site_mutations_length;\n    tsk_site_t site;\n    tsk_tree_t tree;\n    tsk_bitset_t all_samples_bits, mut_samples;\n    tsk_size_t max_muts_len, site_offset, num_nodes, site_idx, s, m, n;\n    tsk_id_t node, *nodes = NULL;\n    void *tmp_nodes;\n\n    tsk_memset(&mut_samples, 0, sizeof(mut_samples));\n    tsk_memset(&all_samples_bits, 0, sizeof(all_samples_bits));\n\n    max_muts_len = 0;\n    for (s = 0; s < n_sites; s++) {\n        max_muts_len = TSK_MAX(site_muts_len[sites[s]], max_muts_len);\n    }\n    // Allocate a bit array of size max alleles for all sites\n    ret = tsk_bitset_init(&mut_samples, num_samples, max_muts_len);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_bitset_init(&all_samples_bits, num_samples, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    get_all_samples_bits(&all_samples_bits, num_samples);\n    ret = tsk_tree_init(&tree, ts, TSK_NO_SAMPLE_COUNTS);\n    if (ret != 0) {\n        goto out;\n    }\n\n    // For each mutation within each site, perform one preorder traversal to gather\n    // the samples under each mutation's node.\n    site_offset = 0;\n    for (site_idx = 0; site_idx < n_sites; site_idx++) {\n        tsk_treeseq_get_site(ts, sites[site_idx], &site);\n        ret = tsk_tree_seek(&tree, site.position, 0);\n        if (ret != 0) {\n            goto out;\n        }\n        tmp_nodes = tsk_realloc(nodes, tsk_tree_get_size_bound(&tree) * sizeof(*nodes));\n        if (tmp_nodes == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        nodes = tmp_nodes;\n        tsk_bitset_union(allele_samples, site_offset, &all_samples_bits, 0);\n        // Zero out results before the start of each iteration\n        tsk_memset(mut_samples.data, 0,\n            mut_samples.row_len * max_muts_len * sizeof(tsk_bitset_val_t));\n        for (m = 0; m < site.mutations_length; m++) {\n            node = site.mutations[m].node;\n            ret = tsk_tree_preorder_from(&tree, node, nodes, &num_nodes);\n            if (ret != 0) {\n                goto out;\n            }\n            for (n = 0; n < num_nodes; n++) {\n                node = nodes[n];\n                if (flags[node] & TSK_NODE_IS_SAMPLE) {\n                    tsk_bitset_set_bit(\n                        &mut_samples, m, (tsk_bitset_val_t) ts->sample_index_map[node]);\n                }\n            }\n        }\n        get_allele_samples(\n            &site, site_offset, &mut_samples, allele_samples, &(num_alleles[site_idx]));\n        site_offset += site.mutations_length + 1;\n    }\n// if adding code below, check ret before continuing\nout:\n    tsk_safe_free(nodes);\n    tsk_tree_free(&tree);\n    tsk_bitset_free(&mut_samples);\n    tsk_bitset_free(&all_samples_bits);\n    return ret == TSK_TREE_OK ? 0 : ret;\n}\n\n// Given the samples under each allele's node and the sample sets, get the samples under\n// each allele's node for each sample set. We pack this data into a bitset\n// (`allele_sample_sets`) that is size m x n, where m is (n_alleles * num_sample_sets)\n// and n is the size of the largest sample set. In addition, we compute the number of\n// samples contained in the intersection of each allele's samples and each sample set in\n// an array (`allele_sample_sets`) of length (n_alleles * num_sample_sets).\nstatic void\nget_mutation_sample_sets(const tsk_bitset_t *allele_samples, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    const tsk_id_t *sample_index_map, tsk_bitset_t *allele_sample_sets,\n    tsk_size_t *allele_sample_set_counts)\n{\n    tsk_bitset_val_t k, sample;\n    tsk_size_t i, j, ss_off;\n\n    for (i = 0; i < allele_samples->len; i++) {\n        ss_off = 0;\n        for (j = 0; j < num_sample_sets; j++) {\n            for (k = 0; k < sample_set_sizes[j]; k++) {\n                sample = (tsk_bitset_val_t) sample_index_map[sample_sets[k + ss_off]];\n                if (tsk_bitset_contains(allele_samples, i, sample)) {\n                    tsk_bitset_set_bit(allele_sample_sets, j + i * num_sample_sets, k);\n                    allele_sample_set_counts[j + i * num_sample_sets]++;\n                }\n            }\n            ss_off += sample_set_sizes[j];\n        }\n    }\n}\n\nstatic int\ntsk_treeseq_two_site_count_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t result_dim, general_stat_func_t *f,\n    sample_count_stat_params_t *f_params, norm_func_t *norm_f, tsk_size_t n_rows,\n    const tsk_id_t *row_sites, tsk_size_t n_cols, const tsk_id_t *col_sites,\n    tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    tsk_bitset_t allele_samples, allele_sample_sets;\n    bool polarised = options & TSK_STAT_POLARISED;\n    tsk_id_t *sites;\n    tsk_size_t i, j, n_sites, *row_idx, *col_idx;\n    double *result_row;\n    const tsk_size_t num_samples = self->num_samples;\n    tsk_size_t *num_alleles = NULL, *site_offsets = NULL, *allele_counts = NULL;\n    tsk_size_t result_row_len = n_cols * result_dim;\n    tsk_size_t max_ss_size = 0, max_alleles = 0, n_alleles = 0;\n    two_locus_work_t work;\n\n    tsk_memset(&work, 0, sizeof(work));\n    tsk_memset(&allele_samples, 0, sizeof(allele_samples));\n    tsk_memset(&allele_sample_sets, 0, sizeof(allele_sample_sets));\n    sites = tsk_malloc(self->tables->sites.num_rows * sizeof(*sites));\n    row_idx = tsk_malloc(self->tables->sites.num_rows * sizeof(*row_idx));\n    col_idx = tsk_malloc(self->tables->sites.num_rows * sizeof(*col_idx));\n    if (sites == NULL || row_idx == NULL || col_idx == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    get_site_row_col_indices(\n        n_rows, row_sites, n_cols, col_sites, sites, &n_sites, row_idx, col_idx);\n    // depends on n_sites\n    num_alleles = tsk_malloc(n_sites * sizeof(*num_alleles));\n    site_offsets = tsk_malloc(n_sites * sizeof(*site_offsets));\n    if (num_alleles == NULL || site_offsets == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (i = 0; i < n_sites; i++) {\n        site_offsets[i] = n_alleles * num_sample_sets;\n        n_alleles += self->site_mutations_length[sites[i]] + 1;\n        max_alleles = TSK_MAX(self->site_mutations_length[sites[i]], max_alleles);\n    }\n    max_alleles++; // add 1 for the ancestral allele\n    // depends on n_alleles\n    ret = tsk_bitset_init(&allele_samples, num_samples, n_alleles);\n    if (ret != 0) {\n        goto out;\n    }\n    for (i = 0; i < num_sample_sets; i++) {\n        max_ss_size = TSK_MAX(sample_set_sizes[i], max_ss_size);\n    }\n    // depend on n_alleles and max_ss_size\n    ret = tsk_bitset_init(&allele_sample_sets, max_ss_size, n_alleles * num_sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n    allele_counts = tsk_calloc(n_alleles * num_sample_sets, sizeof(*allele_counts));\n    if (allele_counts == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    // depends on max_ss_size and max_alleles\n    ret = two_locus_work_init(max_alleles, max_ss_size, result_dim, state_dim, &work);\n    if (ret != 0) {\n        goto out;\n    }\n    // we track the number of alleles to account for backmutations\n    ret = get_mutation_samples(self, sites, n_sites, num_alleles, &allele_samples);\n    if (ret != 0) {\n        goto out;\n    }\n    get_mutation_sample_sets(&allele_samples, num_sample_sets, sample_set_sizes,\n        sample_sets, self->sample_index_map, &allele_sample_sets, allele_counts);\n    // For each row/column pair, fill in the sample set in the result matrix.\n    for (i = 0; i < n_rows; i++) {\n        result_row = GET_2D_ROW(result, result_row_len, i);\n        for (j = 0; j < n_cols; j++) {\n            if (num_alleles[row_idx[i]] == 2 && num_alleles[col_idx[j]] == 2) {\n                // both sites are biallelic\n                ret = compute_general_two_site_stat_result(&allele_sample_sets,\n                    allele_counts, site_offsets[row_idx[i]], site_offsets[col_idx[j]],\n                    state_dim, result_dim, f, f_params, &work,\n                    &(result_row[j * result_dim]));\n            } else {\n                // at least one site is multiallelic\n                ret = compute_general_normed_two_site_stat_result(&allele_sample_sets,\n                    allele_counts, site_offsets[row_idx[i]], site_offsets[col_idx[j]],\n                    num_alleles[row_idx[i]], num_alleles[col_idx[j]], state_dim,\n                    result_dim, f, f_params, norm_f, polarised, &work,\n                    &(result_row[j * result_dim]));\n            }\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\n\nout:\n    tsk_safe_free(sites);\n    tsk_safe_free(row_idx);\n    tsk_safe_free(col_idx);\n    tsk_safe_free(num_alleles);\n    tsk_safe_free(site_offsets);\n    tsk_safe_free(allele_counts);\n    two_locus_work_free(&work);\n    tsk_bitset_free(&allele_samples);\n    tsk_bitset_free(&allele_sample_sets);\n    return ret;\n}\n\nstatic int\nsample_sets_to_bitset(const tsk_treeseq_t *self, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_sample_sets,\n    tsk_bitset_t *sample_sets_bits)\n{\n    int ret;\n    tsk_size_t j, k, l;\n    tsk_id_t u, sample_index;\n\n    ret = tsk_bitset_init(sample_sets_bits, self->num_samples, num_sample_sets);\n    if (ret != 0) {\n        return ret;\n    }\n    j = 0;\n    for (k = 0; k < num_sample_sets; k++) {\n        for (l = 0; l < sample_set_sizes[k]; l++) {\n            u = sample_sets[j];\n            sample_index = self->sample_index_map[u];\n            if (tsk_bitset_contains(\n                    sample_sets_bits, k, (tsk_bitset_val_t) sample_index)) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            tsk_bitset_set_bit(sample_sets_bits, k, (tsk_bitset_val_t) sample_index);\n            j++;\n        }\n    }\n\nout:\n    return ret;\n}\n\nstatic int\ncheck_sites(const tsk_id_t *sites, tsk_size_t num_sites, tsk_size_t num_site_rows)\n{\n    int ret = 0;\n    tsk_size_t i;\n\n    if (num_sites == 0) {\n        return ret; // No need to verify sites if there aren't any\n    }\n\n    for (i = 0; i < num_sites - 1; i++) {\n        if (sites[i] < 0 || sites[i] >= (tsk_id_t) num_site_rows) {\n            ret = tsk_trace_error(TSK_ERR_SITE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (sites[i] > sites[i + 1]) {\n            ret = tsk_trace_error(TSK_ERR_STAT_UNSORTED_SITES);\n            goto out;\n        }\n        if (sites[i] == sites[i + 1]) {\n            ret = tsk_trace_error(TSK_ERR_STAT_DUPLICATE_SITES);\n            goto out;\n        }\n    }\n    // check the last value\n    if (sites[i] < 0 || sites[i] >= (tsk_id_t) num_site_rows) {\n        ret = tsk_trace_error(TSK_ERR_SITE_OUT_OF_BOUNDS);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ncheck_positions(\n    const double *positions, tsk_size_t num_positions, double sequence_length)\n{\n    int ret = 0;\n    tsk_size_t i;\n\n    if (num_positions == 0) {\n        return ret; // No need to verify positions if there aren't any\n    }\n\n    for (i = 0; i < num_positions - 1; i++) {\n        if (positions[i] < 0 || positions[i] >= sequence_length) {\n            ret = tsk_trace_error(TSK_ERR_POSITION_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (positions[i] > positions[i + 1]) {\n            ret = tsk_trace_error(TSK_ERR_STAT_UNSORTED_POSITIONS);\n            goto out;\n        }\n        if (positions[i] == positions[i + 1]) {\n            ret = tsk_trace_error(TSK_ERR_STAT_DUPLICATE_POSITIONS);\n            goto out;\n        }\n    }\n    // check bounds of last value\n    if (positions[i] < 0 || positions[i] >= sequence_length) {\n        ret = tsk_trace_error(TSK_ERR_POSITION_OUT_OF_BOUNDS);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\npositions_to_tree_indexes(const tsk_treeseq_t *ts, const double *positions,\n    tsk_size_t num_positions, tsk_id_t **tree_indexes)\n{\n    int ret = 0;\n    tsk_id_t tree_index = 0;\n    tsk_size_t i, num_trees = ts->num_trees;\n\n    // This is tricky. If there are 0 positions, we calloc a size of 1\n    // we must calloc, because memset will have no effect when called with size 0\n    *tree_indexes = tsk_calloc(num_positions, sizeof(*tree_indexes));\n    if (tree_indexes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(*tree_indexes, TSK_NULL, num_positions * sizeof(**tree_indexes));\n    for (i = 0; i < num_positions; i++) {\n        while (ts->breakpoints[tree_index + 1] <= positions[i]) {\n            tree_index++;\n        }\n        (*tree_indexes)[i] = tree_index;\n    }\n    tsk_bug_assert(tree_index <= (tsk_id_t)(num_trees - 1));\n\nout:\n    return ret;\n}\n\nstatic int\nget_index_counts(\n    const tsk_id_t *indexes, tsk_size_t num_indexes, tsk_size_t **out_counts)\n{\n    int ret = 0;\n    tsk_id_t index = indexes[0];\n    tsk_size_t count, i;\n    tsk_size_t *counts = tsk_calloc(\n        (tsk_size_t)(indexes[num_indexes ? num_indexes - 1 : 0] - indexes[0] + 1),\n        sizeof(*counts));\n    if (counts == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    count = 1;\n    for (i = 1; i < num_indexes; i++) {\n        if (indexes[i] == indexes[i - 1]) {\n            count++;\n        } else {\n            counts[index - indexes[0]] = count;\n            count = 1;\n            index = indexes[i];\n        }\n    }\n    counts[index - indexes[0]] = count;\n    *out_counts = counts;\nout:\n    return ret;\n}\n\ntypedef struct {\n    tsk_tree_t tree;\n    tsk_bitset_t *node_samples;\n    tsk_id_t *parent;\n    tsk_id_t *edges_out;\n    tsk_id_t *edges_in;\n    double *branch_len;\n    tsk_size_t n_edges_out;\n    tsk_size_t n_edges_in;\n} iter_state;\n\nstatic int\niter_state_init(iter_state *self, const tsk_treeseq_t *ts, tsk_size_t state_dim)\n{\n    int ret = 0;\n    const tsk_size_t num_nodes = ts->tables->nodes.num_rows;\n\n    ret = tsk_tree_init(&self->tree, ts, TSK_NO_SAMPLE_COUNTS);\n    if (ret != 0) {\n        goto out;\n    }\n    self->node_samples = tsk_calloc(1, sizeof(*self->node_samples));\n    if (self->node_samples == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_bitset_init(self->node_samples, ts->num_samples, state_dim * num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    self->parent = tsk_malloc(num_nodes * sizeof(*self->parent));\n    self->edges_out = tsk_malloc(num_nodes * sizeof(*self->edges_out));\n    self->edges_in = tsk_malloc(num_nodes * sizeof(*self->edges_in));\n    self->branch_len = tsk_calloc(num_nodes, sizeof(*self->branch_len));\n    if (self->parent == NULL || self->edges_out == NULL || self->edges_in == NULL\n        || self->branch_len == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nget_node_samples(const tsk_treeseq_t *ts, tsk_size_t state_dim,\n    const tsk_bitset_t *sample_sets, tsk_bitset_t *node_samples)\n{\n    int ret = 0;\n    tsk_size_t n, k;\n    tsk_size_t num_nodes = ts->tables->nodes.num_rows;\n    tsk_bitset_val_t sample;\n    const tsk_id_t *restrict sample_index_map = ts->sample_index_map;\n    const tsk_flags_t *restrict flags = ts->tables->nodes.flags;\n\n    ret = tsk_bitset_init(node_samples, ts->num_samples, num_nodes * state_dim);\n    if (ret != 0) {\n        goto out;\n    }\n    for (k = 0; k < state_dim; k++) {\n        for (n = 0; n < num_nodes; n++) {\n            if (flags[n] & TSK_NODE_IS_SAMPLE) {\n                sample = (tsk_bitset_val_t) sample_index_map[n];\n                if (tsk_bitset_contains(sample_sets, k, sample)) {\n                    tsk_bitset_set_bit(node_samples, (state_dim * n) + k, sample);\n                }\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic void\niter_state_clear(iter_state *self, tsk_size_t state_dim, tsk_size_t num_nodes,\n    const tsk_bitset_t *node_samples)\n{\n    self->n_edges_out = 0;\n    self->n_edges_in = 0;\n    tsk_tree_clear(&self->tree);\n    tsk_memset(self->parent, TSK_NULL, num_nodes * sizeof(*self->parent));\n    tsk_memset(self->edges_out, TSK_NULL, num_nodes * sizeof(*self->edges_out));\n    tsk_memset(self->edges_in, TSK_NULL, num_nodes * sizeof(*self->edges_in));\n    tsk_memset(self->branch_len, 0, num_nodes * sizeof(*self->branch_len));\n    tsk_memcpy(self->node_samples->data, node_samples->data,\n        node_samples->row_len * state_dim * num_nodes * sizeof(*node_samples->data));\n}\n\nstatic void\niter_state_free(iter_state *self)\n{\n    tsk_tree_free(&self->tree);\n    tsk_bitset_free(self->node_samples);\n    tsk_safe_free(self->node_samples);\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->edges_out);\n    tsk_safe_free(self->edges_in);\n    tsk_safe_free(self->branch_len);\n}\n\nstatic int\nadvance_collect_edges(iter_state *s, tsk_id_t index)\n{\n    int ret = 0;\n    tsk_id_t j, e;\n    tsk_size_t i;\n    double left, right;\n    tsk_tree_position_t pos;\n    tsk_tree_t *tree = &s->tree;\n    const double *restrict edge_left = tree->tree_sequence->tables->edges.left;\n    const double *restrict edge_right = tree->tree_sequence->tables->edges.right;\n\n    // Either we're seeking forward one step from some nonzero position in the tree, or\n    // from the beginning of the tree sequence.\n    if (tree->index != TSK_NULL || index == 0) {\n        ret = tsk_tree_next(tree);\n        if (ret < 0) {\n            goto out;\n        }\n        pos = tree->tree_pos;\n        i = 0;\n        for (j = pos.out.start; j != pos.out.stop; j++) {\n            s->edges_out[i] = pos.out.order[j];\n            i++;\n        }\n        s->n_edges_out = i;\n        i = 0;\n        for (j = pos.in.start; j != pos.in.stop; j++) {\n            s->edges_in[i] = pos.in.order[j];\n            i++;\n        }\n        s->n_edges_in = i;\n    } else {\n        // Seek from an arbitrary nonzero position from an uninitialized tree.\n        tsk_bug_assert(tree->index == -1);\n        ret = tsk_tree_seek_index(tree, index, 0);\n        if (ret < 0) {\n            goto out;\n        }\n        pos = tree->tree_pos;\n        i = 0;\n        if (pos.direction == TSK_DIR_FORWARD) {\n            left = pos.interval.left;\n            for (j = pos.in.start; j != pos.in.stop; j++) {\n                e = pos.in.order[j];\n                if (edge_left[e] <= left && left < edge_right[e]) {\n                    s->edges_in[i] = pos.in.order[j];\n                    i++;\n                }\n            }\n        } else {\n            right = pos.interval.right;\n            for (j = pos.in.start; j != pos.in.stop; j--) {\n                e = pos.in.order[j];\n                if (edge_right[e] >= right && right > edge_left[e]) {\n                    s->edges_in[i] = pos.in.order[j];\n                    i++;\n                }\n            }\n        }\n        s->n_edges_out = 0;\n        s->n_edges_in = i;\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int\ncompute_two_tree_branch_state_update(const tsk_treeseq_t *ts, tsk_id_t c,\n    const iter_state *A_state, const iter_state *B_state, tsk_size_t state_dim,\n    tsk_size_t result_dim, int sign, general_stat_func_t *f,\n    sample_count_stat_params_t *f_params, two_locus_work_t *restrict work,\n    double *result)\n{\n    int ret = 0;\n    double a_len, b_len;\n    double *restrict B_branch_len = B_state->branch_len;\n    double *weights_row;\n    tsk_size_t n, k, a_row, b_row;\n    const double *restrict A_branch_len = A_state->branch_len;\n    const tsk_bitset_t *restrict A_state_samples = A_state->node_samples;\n    const tsk_bitset_t *restrict B_state_samples = B_state->node_samples;\n    tsk_size_t num_nodes = ts->tables->nodes.num_rows;\n    double *weights = work->weights;\n    double *result_tmp = work->result_tmp;\n    tsk_bitset_t AB_samples = work->AB_samples;\n\n    b_len = B_branch_len[c] * sign;\n    if (b_len == 0) {\n        return ret;\n    }\n    for (n = 0; n < num_nodes; n++) {\n        a_len = A_branch_len[n];\n        if (a_len == 0) {\n            continue;\n        }\n        for (k = 0; k < state_dim; k++) {\n            a_row = (state_dim * n) + k;\n            b_row = (state_dim * (tsk_size_t) c) + k;\n            weights_row = GET_2D_ROW(weights, 3, k);\n            tsk_bitset_intersect(\n                A_state_samples, a_row, B_state_samples, b_row, &AB_samples);\n            weights_row[0] = (double) tsk_bitset_count(&AB_samples, 0);\n            weights_row[1]\n                = (double) tsk_bitset_count(A_state_samples, a_row) - weights_row[0];\n            weights_row[2]\n                = (double) tsk_bitset_count(B_state_samples, b_row) - weights_row[0];\n        }\n        ret = f(state_dim, weights, result_dim, result_tmp, f_params);\n        if (ret != 0) {\n            goto out;\n        }\n        for (k = 0; k < result_dim; k++) {\n            result[k] += result_tmp[k] * a_len * b_len;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ncompute_two_tree_branch_stat(const tsk_treeseq_t *ts, const iter_state *l_state,\n    iter_state *r_state, general_stat_func_t *f, sample_count_stat_params_t *f_params,\n    tsk_size_t result_dim, tsk_size_t state_dim, double *result)\n{\n    int ret = 0;\n    tsk_id_t e, c, ec, p, *updated_nodes = NULL;\n    tsk_size_t j, k, n_updates;\n    const double *restrict time = ts->tables->nodes.time;\n    const tsk_id_t *restrict edges_child = ts->tables->edges.child;\n    const tsk_id_t *restrict edges_parent = ts->tables->edges.parent;\n    const tsk_size_t num_nodes = ts->tables->nodes.num_rows;\n    tsk_bitset_t updates, *r_samples = r_state->node_samples;\n    two_locus_work_t work;\n\n    tsk_memset(&work, 0, sizeof(work));\n    tsk_memset(&updates, 0, sizeof(updates));\n    // only two alleles are possible for branch stats\n    ret = two_locus_work_init(2, ts->num_samples, result_dim, state_dim, &work);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_bitset_init(&updates, num_nodes, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    updated_nodes = tsk_calloc(num_nodes, sizeof(*updated_nodes));\n    if (updated_nodes == NULL) {\n        ret = TSK_ERR_NO_MEMORY;\n        goto out;\n    }\n    // Identify modified nodes both added and removed\n    for (j = 0; j < r_state->n_edges_out + r_state->n_edges_in; j++) {\n        e = j < r_state->n_edges_out ? r_state->edges_out[j]\n                                     : r_state->edges_in[j - r_state->n_edges_out];\n        p = edges_parent[e];\n        c = edges_child[e];\n        // Identify affected nodes above child\n        while (p != TSK_NULL) {\n            tsk_bitset_set_bit(&updates, 0, (tsk_bitset_val_t) c);\n            c = p;\n            p = r_state->parent[p];\n        }\n    }\n    // Subtract the whole contribution from the child node\n    tsk_bitset_get_items(&updates, 0, updated_nodes, &n_updates);\n    while (n_updates != 0) {\n        n_updates--;\n        c = updated_nodes[n_updates];\n        compute_two_tree_branch_state_update(ts, c, l_state, r_state, state_dim,\n            result_dim, -1, f, f_params, &work, result);\n    }\n    // Remove samples under nodes from removed edges to parent nodes\n    for (j = 0; j < r_state->n_edges_out; j++) {\n        e = r_state->edges_out[j];\n        p = edges_parent[e];\n        ec = edges_child[e]; // edge child\n        while (p != TSK_NULL) {\n            for (k = 0; k < state_dim; k++) {\n                tsk_bitset_subtract(r_samples, (state_dim * (tsk_size_t) p) + k,\n                    r_samples, (state_dim * (tsk_size_t) ec) + k);\n            }\n            p = r_state->parent[p];\n        }\n        r_state->branch_len[ec] = 0;\n        r_state->parent[ec] = TSK_NULL;\n    }\n    // Add samples under nodes from added edges\n    for (j = 0; j < r_state->n_edges_in; j++) {\n        e = r_state->edges_in[j];\n        p = edges_parent[e];\n        ec = c = edges_child[e];\n        r_state->branch_len[c] = time[p] - time[c];\n        r_state->parent[c] = p;\n        while (p != TSK_NULL) {\n            tsk_bitset_set_bit(&updates, 0, (tsk_bitset_val_t) c);\n            for (k = 0; k < state_dim; k++) {\n                tsk_bitset_union(r_samples, (state_dim * (tsk_size_t) p) + k, r_samples,\n                    (state_dim * (tsk_size_t) ec) + k);\n            }\n            c = p;\n            p = r_state->parent[p];\n        }\n    }\n    // Update all affected child nodes (fully subtracted, deferred from addition)\n    n_updates = 0;\n    tsk_bitset_get_items(&updates, 0, updated_nodes, &n_updates);\n    while (n_updates != 0) {\n        n_updates--;\n        c = updated_nodes[n_updates];\n        compute_two_tree_branch_state_update(ts, c, l_state, r_state, state_dim,\n            result_dim, +1, f, f_params, &work, result);\n    }\nout:\n    tsk_safe_free(updated_nodes);\n    two_locus_work_free(&work);\n    tsk_bitset_free(&updates);\n    return ret;\n}\n\nstatic int\ntsk_treeseq_two_branch_count_stat(const tsk_treeseq_t *self, tsk_size_t state_dim,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t result_dim, general_stat_func_t *f,\n    sample_count_stat_params_t *f_params, norm_func_t *TSK_UNUSED(norm_f),\n    tsk_size_t n_rows, const double *row_positions, tsk_size_t n_cols,\n    const double *col_positions, tsk_flags_t TSK_UNUSED(options), double *result)\n{\n    int ret = 0;\n    int r, c;\n    tsk_id_t *row_indexes = NULL, *col_indexes = NULL;\n    tsk_size_t i, j, k, row, col, *row_repeats = NULL, *col_repeats = NULL;\n    tsk_bitset_t node_samples, sample_sets_bits;\n    iter_state l_state, r_state;\n    double *result_tmp = NULL, *result_row;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n\n    tsk_memset(&sample_sets_bits, 0, sizeof(sample_sets_bits));\n    tsk_memset(&node_samples, 0, sizeof(node_samples));\n    tsk_memset(&l_state, 0, sizeof(l_state));\n    tsk_memset(&r_state, 0, sizeof(r_state));\n    result_tmp = tsk_malloc(result_dim * sizeof(*result_tmp));\n    if (result_tmp == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = iter_state_init(&l_state, self, state_dim);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = iter_state_init(&r_state, self, state_dim);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = sample_sets_to_bitset(\n        self, sample_set_sizes, sample_sets, num_sample_sets, &sample_sets_bits);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = positions_to_tree_indexes(self, row_positions, n_rows, &row_indexes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = positions_to_tree_indexes(self, col_positions, n_cols, &col_indexes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = get_index_counts(row_indexes, n_rows, &row_repeats);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = get_index_counts(col_indexes, n_cols, &col_repeats);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = get_node_samples(self, state_dim, &sample_sets_bits, &node_samples);\n    if (ret != 0) {\n        goto out;\n    }\n    iter_state_clear(&l_state, state_dim, num_nodes, &node_samples);\n    row = 0;\n    for (r = 0; r < (row_indexes[n_rows ? n_rows - 1U : 0] - row_indexes[0] + 1); r++) {\n        tsk_memset(result_tmp, 0, result_dim * sizeof(*result_tmp));\n        iter_state_clear(&r_state, state_dim, num_nodes, &node_samples);\n        ret = advance_collect_edges(&l_state, (tsk_id_t) r + row_indexes[0]);\n        if (ret != 0) {\n            goto out;\n        }\n        result_row = GET_2D_ROW(result, result_dim * n_cols, row);\n        ret = compute_two_tree_branch_stat(\n            self, &r_state, &l_state, f, f_params, result_dim, state_dim, result_tmp);\n        if (ret != 0) {\n            goto out;\n        }\n        col = 0;\n        for (c = 0; c < (col_indexes[n_cols ? n_cols - 1 : 0] - col_indexes[0] + 1);\n             c++) {\n            ret = advance_collect_edges(&r_state, (tsk_id_t) c + col_indexes[0]);\n            if (ret != 0) {\n                goto out;\n            }\n            ret = compute_two_tree_branch_stat(self, &l_state, &r_state, f, f_params,\n                result_dim, state_dim, result_tmp);\n            if (ret != 0) {\n                goto out;\n            }\n            for (i = 0; i < row_repeats[r]; i++) {\n                for (j = 0; j < col_repeats[c]; j++) {\n                    result_row = GET_2D_ROW(result, result_dim * n_cols, row + i);\n                    for (k = 0; k < result_dim; k++) {\n                        result_row[col + (j * result_dim) + k] = result_tmp[k];\n                    }\n                }\n            }\n            col += (col_repeats[c] * result_dim);\n        }\n        row += row_repeats[r];\n    }\nout:\n    tsk_safe_free(result_tmp);\n    tsk_safe_free(row_indexes);\n    tsk_safe_free(col_indexes);\n    tsk_safe_free(row_repeats);\n    tsk_safe_free(col_repeats);\n    iter_state_free(&l_state);\n    iter_state_free(&r_state);\n    tsk_bitset_free(&node_samples);\n    tsk_bitset_free(&sample_sets_bits);\n    return ret;\n}\n\nstatic int\ncheck_sample_set_dups(tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, const tsk_id_t *restrict sample_index_map,\n    tsk_size_t num_samples)\n{\n    int ret;\n    tsk_size_t j, k, l;\n    tsk_id_t u, sample_index;\n    tsk_bitset_t tmp;\n\n    tsk_memset(&tmp, 0, sizeof(tmp));\n    ret = tsk_bitset_init(&tmp, num_samples, 1);\n    if (ret != 0) {\n        goto out;\n    }\n    j = 0;\n    for (k = 0; k < num_sample_sets; k++) {\n        tsk_memset(tmp.data, 0, sizeof(*tmp.data) * tmp.row_len);\n        for (l = 0; l < sample_set_sizes[k]; l++) {\n            u = sample_sets[j];\n            sample_index = sample_index_map[u];\n            if (tsk_bitset_contains(&tmp, 0, (tsk_bitset_val_t) sample_index)) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            tsk_bitset_set_bit(&tmp, 0, (tsk_bitset_val_t) sample_index);\n            j++;\n        }\n    }\nout:\n    tsk_bitset_free(&tmp);\n    return ret;\n}\n\nint\ntsk_treeseq_two_locus_count_stat(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t result_dim, const tsk_id_t *set_indexes, general_stat_func_t *f,\n    norm_func_t *norm_f, tsk_size_t out_rows, const tsk_id_t *row_sites,\n    const double *row_positions, tsk_size_t out_cols, const tsk_id_t *col_sites,\n    const double *col_positions, tsk_flags_t options, double *result)\n{\n    // TODO: generalize this function if we ever decide to do weighted two_locus stats.\n    //       We only implement count stats and therefore we don't handle weights.\n    int ret = 0;\n    bool stat_site = !!(options & TSK_STAT_SITE);\n    bool stat_branch = !!(options & TSK_STAT_BRANCH);\n    tsk_size_t state_dim = num_sample_sets;\n    sample_count_stat_params_t f_params = { .sample_sets = sample_sets,\n        .num_sample_sets = num_sample_sets,\n        .sample_set_sizes = sample_set_sizes,\n        .set_indexes = set_indexes };\n\n    // We do not support two-locus node stats\n    if (!!(options & TSK_STAT_NODE)) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_STAT_MODE);\n        goto out;\n    }\n    // If no mode is specified, we default to site mode\n    if (!(stat_site || stat_branch)) {\n        stat_site = true;\n    }\n    // It's an error to specify more than one mode\n    if (stat_site + stat_branch > 1) {\n        ret = tsk_trace_error(TSK_ERR_MULTIPLE_STAT_MODES);\n        goto out;\n    }\n    ret = tsk_treeseq_check_sample_sets(\n        self, num_sample_sets, sample_set_sizes, sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n    if (result_dim < 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_RESULT_DIMS);\n        goto out;\n    }\n    if (stat_site) {\n        ret = check_sites(row_sites, out_rows, self->tables->sites.num_rows);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = check_sites(col_sites, out_cols, self->tables->sites.num_rows);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = check_sample_set_dups(num_sample_sets, sample_set_sizes, sample_sets,\n            self->sample_index_map, self->num_samples);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_treeseq_two_site_count_stat(self, state_dim, num_sample_sets,\n            sample_set_sizes, sample_sets, result_dim, f, &f_params, norm_f, out_rows,\n            row_sites, out_cols, col_sites, options, result);\n    } else if (stat_branch) {\n        ret = check_positions(\n            row_positions, out_rows, tsk_treeseq_get_sequence_length(self));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = check_positions(\n            col_positions, out_cols, tsk_treeseq_get_sequence_length(self));\n        if (ret != 0) {\n            goto out;\n        }\n        ret = tsk_treeseq_two_branch_count_stat(self, state_dim, num_sample_sets,\n            sample_set_sizes, sample_sets, result_dim, f, &f_params, norm_f, out_rows,\n            row_positions, out_cols, col_positions, options, result);\n    }\nout:\n    return ret;\n}\n\n/***********************************\n * Allele frequency spectrum\n ***********************************/\n\nstatic inline void\nfold(tsk_size_t *restrict coordinate, const tsk_size_t *restrict dims,\n    tsk_size_t num_dims)\n{\n    tsk_size_t k;\n    double n = 0;\n    int s = 0;\n\n    for (k = 0; k < num_dims; k++) {\n        tsk_bug_assert(coordinate[k] < dims[k]);\n        n += (double) dims[k] - 1;\n        s += (int) coordinate[k];\n    }\n    n /= 2;\n    k = num_dims;\n    while (s == n && k > 0) {\n        k--;\n        n -= ((double) (dims[k] - 1)) / 2;\n        s -= (int) coordinate[k];\n    }\n    if (s > n) {\n        for (k = 0; k < num_dims; k++) {\n            s = (int) (dims[k] - 1 - coordinate[k]);\n            tsk_bug_assert(s >= 0);\n            coordinate[k] = (tsk_size_t) s;\n        }\n    }\n}\n\nstatic int\ntsk_treeseq_update_site_afs(const tsk_treeseq_t *self, const tsk_site_t *site,\n    const double *total_counts, const double *counts, tsk_size_t num_sample_sets,\n    tsk_size_t window_index, tsk_size_t *result_dims, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    tsk_size_t afs_size;\n    tsk_size_t k, allele, num_alleles, all_samples;\n    double increment, *afs, *allele_counts, *allele_count;\n    tsk_size_t *coordinate = tsk_malloc(num_sample_sets * sizeof(*coordinate));\n    bool polarised = !!(options & TSK_STAT_POLARISED);\n    const tsk_size_t K = num_sample_sets + 1;\n\n    if (coordinate == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = get_allele_weights(\n        site, counts, K, total_counts, &num_alleles, &allele_counts);\n    if (ret != 0) {\n        goto out;\n    }\n\n    afs_size = result_dims[num_sample_sets];\n    afs = result + afs_size * window_index;\n\n    increment = polarised ? 1 : 0.5;\n    /* Sum over the allele weights. Skip the ancestral state if polarised. */\n    for (allele = polarised ? 1 : 0; allele < num_alleles; allele++) {\n        allele_count = GET_2D_ROW(allele_counts, K, allele);\n        all_samples = (tsk_size_t) allele_count[num_sample_sets];\n        if (all_samples > 0 && all_samples < self->num_samples) {\n            for (k = 0; k < num_sample_sets; k++) {\n                coordinate[k] = (tsk_size_t) allele_count[k];\n            }\n            if (!polarised) {\n                fold(coordinate, result_dims, num_sample_sets);\n            }\n            increment_nd_array_value(\n                afs, num_sample_sets, result_dims, coordinate, increment);\n        }\n    }\nout:\n    tsk_safe_free(coordinate);\n    tsk_safe_free(allele_counts);\n    return ret;\n}\n\nstatic int\ntsk_treeseq_site_allele_frequency_spectrum(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes, double *counts,\n    tsk_size_t num_windows, const double *windows, tsk_size_t *result_dims,\n    tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t tree_site, tree_index, window_index;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    tsk_site_t *site;\n    tsk_id_t tj, tk, h;\n    tsk_size_t j;\n    const tsk_size_t K = num_sample_sets + 1;\n    double t_left, t_right;\n    double *total_counts = tsk_malloc((1 + num_sample_sets) * sizeof(*total_counts));\n\n    if (parent == NULL || total_counts == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n\n    for (j = 0; j < num_sample_sets; j++) {\n        total_counts[j] = (double) sample_set_sizes[j];\n    }\n    total_counts[num_sample_sets] = (double) self->num_samples;\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    t_left = 0;\n    tree_index = 0;\n    window_index = 0;\n    while (tj < num_edges || t_left < sequence_length) {\n        while (tk < num_edges && edge_right[O[tk]] == t_left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            while (v != TSK_NULL) {\n                update_state(counts, K, v, u, -1);\n                v = parent[v];\n            }\n            parent[u] = TSK_NULL;\n        }\n\n        while (tj < num_edges && edge_left[I[tj]] == t_left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            while (v != TSK_NULL) {\n                update_state(counts, K, v, u, +1);\n                v = parent[v];\n            }\n        }\n        t_right = sequence_length;\n        if (tj < num_edges) {\n            t_right = TSK_MIN(t_right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            t_right = TSK_MIN(t_right, edge_right[O[tk]]);\n        }\n\n        /* Update the sites */\n        for (tree_site = 0; tree_site < self->tree_sites_length[tree_index];\n             tree_site++) {\n            site = self->tree_sites[tree_index] + tree_site;\n            while (windows[window_index + 1] <= site->position) {\n                window_index++;\n                tsk_bug_assert(window_index < num_windows);\n            }\n            ret = tsk_treeseq_update_site_afs(self, site, total_counts, counts,\n                num_sample_sets, window_index, result_dims, options, result);\n            if (ret != 0) {\n                goto out;\n            }\n            tsk_bug_assert(windows[window_index] <= site->position);\n            tsk_bug_assert(site->position < windows[window_index + 1]);\n        }\n        tree_index++;\n        t_left = t_right;\n    }\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    tsk_safe_free(total_counts);\n    return ret;\n}\n\nstatic void\ntsk_treeseq_update_branch_afs(const tsk_treeseq_t *self, tsk_id_t u, double right,\n    double *restrict last_update, const double *restrict time, tsk_id_t *restrict parent,\n    tsk_size_t *restrict coordinate, const double *counts, tsk_size_t num_sample_sets,\n    tsk_size_t num_time_windows, const double *time_windows, tsk_size_t window_index,\n    const tsk_size_t *result_dims, tsk_flags_t options, double *result)\n{\n    tsk_size_t afs_size;\n    tsk_size_t k;\n    tsk_size_t time_window_index;\n    double *afs;\n    bool polarised = !!(options & TSK_STAT_POLARISED);\n    const double *count_row = GET_2D_ROW(counts, num_sample_sets + 1, u);\n    double x = 0;\n    double t_u, t_v;\n    double tw_branch_length = 0;\n    const tsk_size_t all_samples = (tsk_size_t) count_row[num_sample_sets];\n    if (parent[u] != TSK_NULL) {\n        t_u = time[u];\n        t_v = time[parent[u]];\n        if (0 < all_samples && all_samples < self->num_samples) {\n            time_window_index = 0;\n            afs_size = result_dims[num_sample_sets];\n            while (time_window_index < num_time_windows\n                   && time_windows[time_window_index] < t_v) {\n                afs = result\n                      + afs_size * (window_index * num_time_windows + time_window_index);\n                for (k = 0; k < num_sample_sets; k++) {\n                    coordinate[k] = (tsk_size_t) count_row[k];\n                }\n                if (!polarised) {\n                    fold(coordinate, result_dims, num_sample_sets);\n                }\n                tw_branch_length\n                    = TSK_MAX(0.0, TSK_MIN(time_windows[time_window_index + 1], t_v)\n                                       - TSK_MAX(time_windows[time_window_index], t_u));\n                x = (right - last_update[u]) * tw_branch_length;\n                increment_nd_array_value(\n                    afs, num_sample_sets, result_dims, coordinate, x);\n                time_window_index++;\n            }\n        }\n    }\n    last_update[u] = right;\n}\n\nstatic int\ntsk_treeseq_branch_allele_frequency_spectrum(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, double *counts, tsk_size_t num_windows,\n    const double *windows, tsk_size_t num_time_windows, const double *time_windows,\n    const tsk_size_t *result_dims, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    tsk_id_t u, v;\n    tsk_size_t window_index;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_id_t num_edges = (tsk_id_t) self->tables->edges.num_rows;\n    const tsk_id_t *restrict I = self->tables->indexes.edge_insertion_order;\n    const tsk_id_t *restrict O = self->tables->indexes.edge_removal_order;\n    const double *restrict edge_left = self->tables->edges.left;\n    const double *restrict edge_right = self->tables->edges.right;\n    const tsk_id_t *restrict edge_parent = self->tables->edges.parent;\n    const tsk_id_t *restrict edge_child = self->tables->edges.child;\n    const double *restrict node_time = self->tables->nodes.time;\n    const double sequence_length = self->tables->sequence_length;\n    tsk_id_t *restrict parent = tsk_malloc(num_nodes * sizeof(*parent));\n    double *restrict last_update = tsk_calloc(num_nodes, sizeof(*last_update));\n    double *restrict branch_length = tsk_calloc(num_nodes, sizeof(*branch_length));\n    tsk_size_t *restrict coordinate = tsk_malloc(num_sample_sets * sizeof(*coordinate));\n    tsk_id_t tj, tk, h;\n    double t_left, t_right, w_right;\n    const tsk_size_t K = num_sample_sets + 1;\n\n    if (self->time_uncalibrated && !(options & TSK_STAT_ALLOW_TIME_UNCALIBRATED)) {\n        ret = tsk_trace_error(TSK_ERR_TIME_UNCALIBRATED);\n        goto out;\n    }\n\n    if (parent == NULL || last_update == NULL || coordinate == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(parent, 0xff, num_nodes * sizeof(*parent));\n\n    /* Iterate over the trees */\n    tj = 0;\n    tk = 0;\n    t_left = 0;\n    window_index = 0;\n    while (tj < num_edges || t_left < sequence_length) {\n        tsk_bug_assert(window_index < num_windows);\n        while (tk < num_edges && edge_right[O[tk]] == t_left) {\n            h = O[tk];\n            tk++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            tsk_treeseq_update_branch_afs(self, u, t_left, last_update, node_time,\n                parent, coordinate, counts, num_sample_sets, num_time_windows,\n                time_windows, window_index, result_dims, options, result);\n            while (v != TSK_NULL) {\n                tsk_treeseq_update_branch_afs(self, v, t_left, last_update, node_time,\n                    parent, coordinate, counts, num_sample_sets, num_time_windows,\n                    time_windows, window_index, result_dims, options, result);\n                update_state(counts, K, v, u, -1);\n                v = parent[v];\n            }\n            parent[u] = TSK_NULL;\n            branch_length[u] = 0;\n        }\n\n        while (tj < num_edges && edge_left[I[tj]] == t_left) {\n            h = I[tj];\n            tj++;\n            u = edge_child[h];\n            v = edge_parent[h];\n            parent[u] = v;\n            branch_length[u] = node_time[v] - node_time[u];\n            while (v != TSK_NULL) {\n                tsk_treeseq_update_branch_afs(self, v, t_left, last_update, node_time,\n                    parent, coordinate, counts, num_sample_sets, num_time_windows,\n                    time_windows, window_index, result_dims, options, result);\n                update_state(counts, K, v, u, +1);\n                v = parent[v];\n            }\n        }\n\n        t_right = sequence_length;\n        if (tj < num_edges) {\n            t_right = TSK_MIN(t_right, edge_left[I[tj]]);\n        }\n        if (tk < num_edges) {\n            t_right = TSK_MIN(t_right, edge_right[O[tk]]);\n        }\n\n        while (window_index < num_windows && windows[window_index + 1] <= t_right) {\n            w_right = windows[window_index + 1];\n            /* Flush the contributions of all nodes to the current window */\n            for (u = 0; u < (tsk_id_t) num_nodes; u++) {\n                tsk_bug_assert(last_update[u] < w_right);\n                tsk_treeseq_update_branch_afs(self, u, w_right, last_update, node_time,\n                    parent, coordinate, counts, num_sample_sets, num_time_windows,\n                    time_windows, window_index, result_dims, options, result);\n            }\n            window_index++;\n        }\n\n        t_left = t_right;\n    }\nout:\n    /* Can't use msp_safe_free here because of restrict */\n    if (parent != NULL) {\n        free(parent);\n    }\n    if (last_update != NULL) {\n        free(last_update);\n    }\n    if (branch_length != NULL) {\n        free(branch_length);\n    }\n    if (coordinate != NULL) {\n        free(coordinate);\n    }\n    return ret;\n}\n\nint\ntsk_treeseq_allele_frequency_spectrum(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_windows, const double *windows,\n    tsk_size_t num_time_windows, const double *time_windows, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    bool stat_site = !!(options & TSK_STAT_SITE);\n    bool stat_branch = !!(options & TSK_STAT_BRANCH);\n    bool stat_node = !!(options & TSK_STAT_NODE);\n    const double default_windows[] = { 0, self->tables->sequence_length };\n    const double default_time_windows[] = { 0, INFINITY };\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_size_t K = num_sample_sets + 1;\n    tsk_size_t j, k, l, afs_size;\n    tsk_id_t u;\n    tsk_size_t *result_dims = NULL;\n    /* These counts should really be ints, but we use doubles so that we can\n     * reuse code from the general_stats code paths. */\n    double *counts = NULL;\n    double *count_row;\n    if (stat_node) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_STAT_MODE);\n        goto out;\n    }\n    /* If no mode is specified, we default to site mode */\n    if (!(stat_site || stat_branch)) {\n        stat_site = true;\n    }\n    /* It's an error to specify more than one mode */\n    if (stat_site + stat_branch > 1) {\n        ret = tsk_trace_error(TSK_ERR_MULTIPLE_STAT_MODES);\n        goto out;\n    }\n    if (windows == NULL) {\n        num_windows = 1;\n        windows = default_windows;\n    } else {\n        ret = tsk_treeseq_check_windows(\n            self, num_windows, windows, TSK_REQUIRE_FULL_SPAN);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (time_windows == NULL) {\n        num_time_windows = 1;\n        time_windows = default_time_windows;\n    } else {\n        ret = tsk_treeseq_check_time_windows(num_time_windows, time_windows);\n        if (ret != 0) {\n            goto out;\n        }\n        // Site mode does not support time windows\n        if (stat_site && !(time_windows[0] == 0.0 && isinf((float) time_windows[1]))) {\n            ret = TSK_ERR_UNSUPPORTED_STAT_MODE;\n            goto out;\n        }\n    }\n    ret = tsk_treeseq_check_sample_sets(\n        self, num_sample_sets, sample_set_sizes, sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* the last element of result_dims stores the total size of the dimensions */\n    result_dims = tsk_malloc((num_sample_sets + 1) * sizeof(*result_dims));\n    counts = tsk_calloc(num_nodes * K, sizeof(*counts));\n    if (counts == NULL || result_dims == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    afs_size = 1;\n    j = 0;\n    for (k = 0; k < num_sample_sets; k++) {\n        result_dims[k] = 1 + sample_set_sizes[k];\n        afs_size *= result_dims[k];\n        for (l = 0; l < sample_set_sizes[k]; l++) {\n            u = sample_sets[j];\n            count_row = GET_2D_ROW(counts, K, u);\n            if (count_row[k] != 0) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            count_row[k] = 1;\n            j++;\n        }\n    }\n    for (j = 0; j < self->num_samples; j++) {\n        u = self->samples[j];\n        count_row = GET_2D_ROW(counts, K, u);\n        count_row[num_sample_sets] = 1;\n    }\n    result_dims[num_sample_sets] = (tsk_size_t) afs_size;\n    tsk_memset(result, 0, num_windows * num_time_windows * afs_size * sizeof(*result));\n\n    if (stat_site) {\n        ret = tsk_treeseq_site_allele_frequency_spectrum(self, num_sample_sets,\n            sample_set_sizes, counts, num_windows, windows, result_dims, options,\n            result);\n    } else {\n        ret = tsk_treeseq_branch_allele_frequency_spectrum(self, num_sample_sets, counts,\n            num_windows, windows, num_time_windows, time_windows, result_dims, options,\n            result);\n    }\n\n    if (options & TSK_STAT_SPAN_NORMALISE) {\n        span_normalise(num_windows, windows, afs_size * num_time_windows, result);\n    }\nout:\n    tsk_safe_free(counts);\n    tsk_safe_free(result_dims);\n    return ret;\n}\n\n/***********************************\n * One way stats\n ***********************************/\n\nstatic int\ndiversity_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double n;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        result[j] = x[j] * (n - x[j]) / (n * (n - 1));\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_diversity(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    return tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, diversity_summary_func, num_windows, windows,\n        options, result);\n}\n\nstatic int\ntrait_covariance_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    weight_stat_params_t args = *(weight_stat_params_t *) params;\n    const double n = (double) args.num_samples;\n    const double *x = state;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        result[j] = (x[j] * x[j]) / (2 * (n - 1) * (n - 1));\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_trait_covariance(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result)\n{\n    tsk_size_t num_samples = self->num_samples;\n    tsk_size_t j, k;\n    int ret;\n    const double *row;\n    double *new_row;\n    double *means = tsk_calloc(num_weights, sizeof(double));\n    double *new_weights = tsk_malloc((num_weights + 1) * num_samples * sizeof(double));\n    weight_stat_params_t args = { num_samples = self->num_samples };\n\n    if (new_weights == NULL || means == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (num_weights == 0) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_WEIGHTS);\n        goto out;\n    }\n\n    // center weights\n    for (j = 0; j < num_samples; j++) {\n        row = GET_2D_ROW(weights, num_weights, j);\n        for (k = 0; k < num_weights; k++) {\n            means[k] += row[k];\n        }\n    }\n    for (k = 0; k < num_weights; k++) {\n        means[k] /= (double) num_samples;\n    }\n    for (j = 0; j < num_samples; j++) {\n        row = GET_2D_ROW(weights, num_weights, j);\n        new_row = GET_2D_ROW(new_weights, num_weights, j);\n        for (k = 0; k < num_weights; k++) {\n            new_row[k] = row[k] - means[k];\n        }\n    }\n\n    ret = tsk_treeseq_general_stat(self, num_weights, new_weights, num_weights,\n        trait_covariance_summary_func, &args, num_windows, windows, options, result);\n\nout:\n    tsk_safe_free(means);\n    tsk_safe_free(new_weights);\n    return ret;\n}\n\nstatic int\ntrait_correlation_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    weight_stat_params_t args = *(weight_stat_params_t *) params;\n    const double n = (double) args.num_samples;\n    const double *x = state;\n    double p;\n    tsk_size_t j;\n\n    p = x[state_dim - 1];\n    for (j = 0; j < state_dim - 1; j++) {\n        if ((p > 0.0) && (p < 1.0)) {\n            result[j] = (x[j] * x[j]) / (2 * (p * (1 - p)) * n * (n - 1));\n        } else {\n            result[j] = 0.0;\n        }\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_trait_correlation(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result)\n{\n    tsk_size_t num_samples = self->num_samples;\n    tsk_size_t j, k;\n    int ret;\n    double *means = tsk_calloc(num_weights, sizeof(double));\n    double *meansqs = tsk_calloc(num_weights, sizeof(double));\n    double *sds = tsk_calloc(num_weights, sizeof(double));\n    const double *row;\n    double *new_row;\n    double *new_weights = tsk_malloc((num_weights + 1) * num_samples * sizeof(double));\n    weight_stat_params_t args = { num_samples = self->num_samples };\n\n    if (new_weights == NULL || means == NULL || meansqs == NULL || sds == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    if (num_weights < 1) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_WEIGHTS);\n        goto out;\n    }\n\n    // center and scale weights\n    for (j = 0; j < num_samples; j++) {\n        row = GET_2D_ROW(weights, num_weights, j);\n        for (k = 0; k < num_weights; k++) {\n            means[k] += row[k];\n            meansqs[k] += row[k] * row[k];\n        }\n    }\n    for (k = 0; k < num_weights; k++) {\n        means[k] /= (double) num_samples;\n        meansqs[k] -= means[k] * means[k] * (double) num_samples;\n        meansqs[k] /= (double) (num_samples - 1);\n        sds[k] = sqrt(meansqs[k]);\n    }\n    for (j = 0; j < num_samples; j++) {\n        row = GET_2D_ROW(weights, num_weights, j);\n        new_row = GET_2D_ROW(new_weights, num_weights + 1, j);\n        for (k = 0; k < num_weights; k++) {\n            new_row[k] = (row[k] - means[k]) / sds[k];\n        }\n        // set final row to 1/n to compute frequency\n        new_row[num_weights] = 1.0 / (double) num_samples;\n    }\n\n    ret = tsk_treeseq_general_stat(self, num_weights + 1, new_weights, num_weights,\n        trait_correlation_summary_func, &args, num_windows, windows, options, result);\n\nout:\n    tsk_safe_free(means);\n    tsk_safe_free(meansqs);\n    tsk_safe_free(sds);\n    tsk_safe_free(new_weights);\n    return ret;\n}\n\nstatic int\ntrait_linear_model_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    covariates_stat_params_t args = *(covariates_stat_params_t *) params;\n    const double num_samples = (double) args.num_samples;\n    const tsk_size_t k = args.num_covariates;\n    const double *V = args.V;\n    ;\n    const double *x = state;\n    const double *v;\n    double m, a, denom, z;\n    tsk_size_t i, j;\n    // x[0], ..., x[result_dim - 1] contains the traits, W\n    // x[result_dim], ..., x[state_dim - 2] contains the covariates, Z\n    // x[state_dim - 1] has the number of samples below the node\n\n    m = x[state_dim - 1];\n    for (i = 0; i < result_dim; i++) {\n        if ((m > 0.0) && (m < num_samples)) {\n            v = GET_2D_ROW(V, k, i);\n            a = x[i];\n            denom = m;\n            for (j = 0; j < k; j++) {\n                z = x[result_dim + j];\n                a -= z * v[j];\n                denom -= z * z;\n            }\n            // denom is the length of projection of the trait onto the subspace\n            // spanned by the covariates, so if it is zero then the system is\n            // singular and the solution is nonunique. This numerical tolerance\n            // could be smaller without hitting floating-point error, but being\n            // a tiny bit conservative about when the trait is almost in the\n            // span of the covariates is probably good.\n            if (denom < 1e-8) {\n                result[i] = 0.0;\n            } else {\n                result[i] = (a * a) / (2 * denom * denom);\n            }\n        } else {\n            result[i] = 0.0;\n        }\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_trait_linear_model(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_covariates, const double *covariates,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    tsk_size_t num_samples = self->num_samples;\n    tsk_size_t i, j, k;\n    int ret;\n    const double *w, *z;\n    double *v, *new_row;\n    double *V = tsk_calloc(num_covariates * num_weights, sizeof(double));\n    double *new_weights\n        = tsk_malloc((num_weights + num_covariates + 1) * num_samples * sizeof(double));\n\n    covariates_stat_params_t args\n        = { .num_samples = self->num_samples, .num_covariates = num_covariates, .V = V };\n\n    // We assume that the covariates have been *already standardised*,\n    // so that (a) 1 is in the span of the columns, and\n    // (b) their crossproduct is the identity.\n    // We could do this instead here with gsl linalg.\n\n    if (new_weights == NULL || V == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    if (num_weights < 1) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_WEIGHTS);\n        goto out;\n    }\n\n    // V = weights^T (matrix mult) covariates\n    for (k = 0; k < num_samples; k++) {\n        w = GET_2D_ROW(weights, num_weights, k);\n        z = GET_2D_ROW(covariates, num_covariates, k);\n        for (i = 0; i < num_weights; i++) {\n            v = GET_2D_ROW(V, num_covariates, i);\n            for (j = 0; j < num_covariates; j++) {\n                v[j] += w[i] * z[j];\n            }\n        }\n    }\n\n    for (k = 0; k < num_samples; k++) {\n        w = GET_2D_ROW(weights, num_weights, k);\n        z = GET_2D_ROW(covariates, num_covariates, k);\n        new_row = GET_2D_ROW(new_weights, num_covariates + num_weights + 1, k);\n        for (i = 0; i < num_weights; i++) {\n            new_row[i] = w[i];\n        }\n        for (i = 0; i < num_covariates; i++) {\n            new_row[i + num_weights] = z[i];\n        }\n        // set final row to 1 to count alleles\n        new_row[num_weights + num_covariates] = 1.0;\n    }\n\n    ret = tsk_treeseq_general_stat(self, num_weights + num_covariates + 1, new_weights,\n        num_weights, trait_linear_model_summary_func, &args, num_windows, windows,\n        options, result);\n\nout:\n    tsk_safe_free(V);\n    tsk_safe_free(new_weights);\n    return ret;\n}\n\nstatic int\nsegregating_sites_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double n;\n    tsk_size_t j;\n\n    // this works because sum_{i=1}^k (1-p_i) = k-1\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        result[j] = (x[j] > 0) * (1 - x[j] / n);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_segregating_sites(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    return tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, segregating_sites_summary_func, num_windows,\n        windows, options, result);\n}\n\nstatic int\nY1_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, denom, numer;\n    tsk_size_t i;\n\n    for (i = 0; i < result_dim; i++) {\n        ni = (double) args.sample_set_sizes[i];\n        denom = ni * (ni - 1) * (ni - 2);\n        numer = x[i] * (ni - x[i]) * (ni - x[i] - 1);\n        result[i] = numer / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_Y1(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    return tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, Y1_summary_func, num_windows, windows,\n        options, result);\n}\n\nstatic int\nD_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n        result[j] = p_AB - (p_A * p_B);\n    }\n\n    return 0;\n}\n\nint\ntsk_treeseq_D(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    options |= TSK_STAT_POLARISED; // TODO: allow user to pick?\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, D_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\nD2_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n        result[j] = p_AB - (p_A * p_B);\n        result[j] *= result[j];\n    }\n\n    return 0;\n}\n\nint\ntsk_treeseq_D2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, D2_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\nr2_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n\n        double D = p_AB - (p_A * p_B);\n        double denom = p_A * p_B * (1 - p_A) * (1 - p_B);\n\n        result[j] = (D * D) / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_r2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, r2_summary_func, norm_hap_weighted, num_rows,\n        row_sites, row_positions, num_cols, col_sites, col_positions, options, result);\n}\n\nstatic int\nD_prime_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n\n        double D = p_AB - (p_A * p_B);\n\n        if (D >= 0) {\n            result[j] = D / TSK_MIN(p_A * (1 - p_B), (1 - p_A) * p_B);\n        } else if (D < 0) {\n            result[j] = D / TSK_MIN(p_A * p_B, (1 - p_A) * (1 - p_B));\n        }\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_D_prime(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    options |= TSK_STAT_POLARISED; // TODO: allow user to pick?\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, D_prime_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\nr_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n\n        double D = p_AB - (p_A * p_B);\n        double denom = p_A * p_B * (1 - p_A) * (1 - p_B);\n\n        result[j] = D / sqrt(denom);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_r(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    options |= TSK_STAT_POLARISED; // TODO: allow user to pick?\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, r_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\nDz_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n\n        double D = p_AB - (p_A * p_B);\n\n        result[j] = D * (1 - 2 * p_A) * (1 - 2 * p_B);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_Dz(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, Dz_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\npi2_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double p_AB = state_row[0] / n;\n        double p_Ab = state_row[1] / n;\n        double p_aB = state_row[2] / n;\n\n        double p_A = p_AB + p_Ab;\n        double p_B = p_AB + p_aB;\n        result[j] = p_A * (1 - p_A) * p_B * (1 - p_B);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_pi2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, pi2_summary_func, norm_total_weighted,\n        num_rows, row_sites, row_positions, num_cols, col_sites, col_positions, options,\n        result);\n}\n\nstatic int\nD2_unbiased_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double w_AB = state_row[0];\n        double w_Ab = state_row[1];\n        double w_aB = state_row[2];\n        double w_ab = n - (w_AB + w_Ab + w_aB);\n        result[j] = (1 / (n * (n - 1) * (n - 2) * (n - 3)))\n                    * ((w_aB * w_aB * (w_Ab - 1) * w_Ab)\n                          + ((w_ab - 1) * w_ab * (w_AB - 1) * w_AB)\n                          - (w_aB * w_Ab * (w_Ab + (2 * w_ab * w_AB) - 1)));\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_D2_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, D2_unbiased_summary_func,\n        norm_total_weighted, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\n}\n\nstatic int\nDz_unbiased_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double w_AB = state_row[0];\n        double w_Ab = state_row[1];\n        double w_aB = state_row[2];\n        double w_ab = n - (w_AB + w_Ab + w_aB);\n        result[j] = (1 / (n * (n - 1) * (n - 2) * (n - 3)))\n                    * ((((w_AB * w_ab) - (w_Ab * w_aB)) * (w_aB + w_ab - w_AB - w_Ab)\n                           * (w_Ab + w_ab - w_AB - w_aB))\n                          - ((w_AB * w_ab) * (w_AB + w_ab - w_Ab - w_aB - 2))\n                          - ((w_Ab * w_aB) * (w_Ab + w_aB - w_AB - w_ab - 2)));\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_Dz_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, Dz_unbiased_summary_func,\n        norm_total_weighted, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\n}\n\nstatic int\npi2_unbiased_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t TSK_UNUSED(result_dim), double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    double n;\n    const double *state_row;\n    tsk_size_t j;\n\n    for (j = 0; j < state_dim; j++) {\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        double w_AB = state_row[0];\n        double w_Ab = state_row[1];\n        double w_aB = state_row[2];\n        double w_ab = n - (w_AB + w_Ab + w_aB);\n        result[j]\n            = (1 / (n * (n - 1) * (n - 2) * (n - 3)))\n              * (((w_AB + w_Ab) * (w_aB + w_ab) * (w_AB + w_aB) * (w_Ab + w_ab))\n                    - ((w_AB * w_ab) * (w_AB + w_ab + (3 * w_Ab) + (3 * w_aB) - 1))\n                    - ((w_Ab * w_aB) * (w_Ab + w_aB + (3 * w_AB) + (3 * w_ab) - 1)));\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_pi2_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    return tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_sample_sets, NULL, pi2_unbiased_summary_func,\n        norm_total_weighted, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\n}\n\n/***********************************\n * Two way stats\n ***********************************/\n\nstatic int\ncheck_sample_stat_inputs(tsk_size_t num_sample_sets, tsk_size_t tuple_size,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples)\n{\n    int ret = 0;\n\n    if (num_sample_sets < 1) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_SAMPLE_SETS);\n        goto out;\n    }\n    if (num_index_tuples < 1) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_INDEX_TUPLES);\n        goto out;\n    }\n    ret = check_set_indexes(\n        num_sample_sets, tuple_size * num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\ndivergence_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, denom;\n    tsk_id_t i, j;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        denom = ni * (nj - (i == j));\n        result[k] = x[i] * (nj - x[j]) / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_divergence(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, divergence_summary_func,\n        num_windows, windows, options, result);\nout:\n    return ret;\n}\n\nstatic int\ngenetic_relatedness_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    tsk_id_t i, j;\n    tsk_size_t k;\n    double sumx = 0;\n    double meanx, ni, nj;\n\n    for (k = 0; k < state_dim; k++) {\n        sumx += x[k] / (double) args.sample_set_sizes[k];\n    }\n\n    meanx = sumx / (double) state_dim;\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        result[k] = (x[i] / ni - meanx) * (x[j] / nj - meanx);\n    }\n    return 0;\n}\n\nstatic int\ngenetic_relatedness_noncentred_summary_func(tsk_size_t TSK_UNUSED(state_dim),\n    const double *state, tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    tsk_id_t i, j;\n    tsk_size_t k;\n    double ni, nj;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        result[k] = x[i] * x[j] / (ni * nj);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_genetic_relatedness(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    if (!(options & TSK_STAT_NONCENTRED)) {\n        ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n            sample_sets, num_index_tuples, index_tuples,\n            genetic_relatedness_summary_func, num_windows, windows, options, result);\n    } else {\n        ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n            sample_sets, num_index_tuples, index_tuples,\n            genetic_relatedness_noncentred_summary_func, num_windows, windows, options,\n            result);\n    }\nout:\n    return ret;\n}\n\nstatic int\ngenetic_relatedness_weighted_summary_func(tsk_size_t state_dim, const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    indexed_weight_stat_params_t args = *(indexed_weight_stat_params_t *) params;\n    const double *x = state;\n    tsk_id_t i, j;\n    tsk_size_t k;\n    double pn, ni, nj;\n\n    pn = state[state_dim - 1];\n    for (k = 0; k < result_dim; k++) {\n        i = args.index_tuples[2 * k];\n        j = args.index_tuples[2 * k + 1];\n        ni = args.total_weights[i];\n        nj = args.total_weights[j];\n        result[k] = (x[i] - ni * pn) * (x[j] - nj * pn);\n    }\n    return 0;\n}\n\nstatic int\ngenetic_relatedness_weighted_noncentred_summary_func(tsk_size_t TSK_UNUSED(state_dim),\n    const double *state, tsk_size_t result_dim, double *result, void *params)\n{\n    indexed_weight_stat_params_t args = *(indexed_weight_stat_params_t *) params;\n    const double *x = state;\n    tsk_id_t i, j;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.index_tuples[2 * k];\n        j = args.index_tuples[2 * k + 1];\n        result[k] = x[i] * x[j];\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_genetic_relatedness_weighted(const tsk_treeseq_t *self,\n    tsk_size_t num_weights, const double *weights, tsk_size_t num_index_tuples,\n    const tsk_id_t *index_tuples, tsk_size_t num_windows, const double *windows,\n    double *result, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t num_samples = self->num_samples;\n    size_t j, k;\n    indexed_weight_stat_params_t args;\n    const double *row;\n    double *new_row;\n    double *total_weights = tsk_calloc((num_weights + 1), sizeof(*total_weights));\n    double *new_weights\n        = tsk_malloc((num_weights + 1) * num_samples * sizeof(*new_weights));\n\n    if (total_weights == NULL || new_weights == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (num_weights == 0) {\n        ret = tsk_trace_error(TSK_ERR_INSUFFICIENT_WEIGHTS);\n        goto out;\n    }\n\n    // Add a column of ones to W\n    for (j = 0; j < num_samples; j++) {\n        row = GET_2D_ROW(weights, num_weights, j);\n        new_row = GET_2D_ROW(new_weights, num_weights + 1, j);\n        for (k = 0; k < num_weights; k++) {\n            new_row[k] = row[k];\n            total_weights[k] += row[k];\n        }\n        new_row[num_weights] = 1.0 / (double) num_samples;\n    }\n    total_weights[num_weights] = 1.0;\n\n    args.total_weights = total_weights;\n    args.index_tuples = index_tuples;\n    if (!(options & TSK_STAT_NONCENTRED)) {\n        ret = tsk_treeseq_general_stat(self, num_weights + 1, new_weights,\n            num_index_tuples, genetic_relatedness_weighted_summary_func, &args,\n            num_windows, windows, options, result);\n        if (ret != 0) {\n            goto out;\n        }\n    } else {\n        ret = tsk_treeseq_general_stat(self, num_weights + 1, new_weights,\n            num_index_tuples, genetic_relatedness_weighted_noncentred_summary_func,\n            &args, num_windows, windows, options, result);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\nout:\n    tsk_safe_free(total_weights);\n    tsk_safe_free(new_weights);\n    return ret;\n}\n\nstatic int\nY2_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, denom;\n    tsk_id_t i, j;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        denom = ni * nj * (nj - 1);\n        result[k] = x[i] * (nj - x[j]) * (nj - x[j] - 1) / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_Y2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, Y2_summary_func, num_windows,\n        windows, options, result);\nout:\n    return ret;\n}\n\nstatic int\nf2_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, denom, numer;\n    tsk_id_t i, j;\n    tsk_size_t k;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        denom = ni * (ni - 1) * nj * (nj - 1);\n        numer = x[i] * (x[i] - 1) * (nj - x[j]) * (nj - x[j] - 1)\n                - x[i] * (ni - x[i]) * (nj - x[j]) * x[j];\n        result[k] = numer / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_f2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, f2_summary_func, num_windows,\n        windows, options, result);\nout:\n    return ret;\n}\n\nstatic int\nD2_ij_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *state_row;\n    double n;\n    tsk_size_t k;\n    tsk_id_t i, j;\n    double p_A, p_B, p_AB, p_Ab, p_aB, D_i, D_j;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n\n        n = (double) args.sample_set_sizes[i];\n        state_row = GET_2D_ROW(state, 3, i);\n        p_AB = state_row[0] / n;\n        p_Ab = state_row[1] / n;\n        p_aB = state_row[2] / n;\n        p_A = p_AB + p_Ab;\n        p_B = p_AB + p_aB;\n        D_i = p_AB - (p_A * p_B);\n\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        p_AB = state_row[0] / n;\n        p_Ab = state_row[1] / n;\n        p_aB = state_row[2] / n;\n        p_A = p_AB + p_Ab;\n        p_B = p_AB + p_aB;\n        D_j = p_AB - (p_A * p_B);\n\n        result[k] = D_i * D_j;\n    }\n\n    return 0;\n}\n\nint\ntsk_treeseq_D2_ij(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, D2_ij_summary_func,\n        norm_total_weighted, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\nout:\n    return ret;\n}\n\nstatic int\nD2_ij_unbiased_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *state_row;\n    tsk_size_t k;\n    tsk_id_t i, j;\n    double n_i, n_j;\n    double w_AB_i, w_Ab_i, w_aB_i, w_ab_i;\n    double w_AB_j, w_Ab_j, w_aB_j, w_ab_j;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n        if (i == j) {\n            // We require disjoint sample sets because we test equality here\n            n_i = (double) args.sample_set_sizes[i];\n            state_row = GET_2D_ROW(state, 3, i);\n            w_AB_i = state_row[0];\n            w_Ab_i = state_row[1];\n            w_aB_i = state_row[2];\n            w_ab_i = n_i - (w_AB_i + w_Ab_i + w_aB_i);\n            result[k] = (w_AB_i * (w_AB_i - 1) * w_ab_i * (w_ab_i - 1)\n                            + w_Ab_i * (w_Ab_i - 1) * w_aB_i * (w_aB_i - 1)\n                            - 2 * w_AB_i * w_Ab_i * w_aB_i * w_ab_i)\n                        / n_i / (n_i - 1) / (n_i - 2) / (n_i - 3);\n        }\n\n        else {\n            n_i = (double) args.sample_set_sizes[i];\n            state_row = GET_2D_ROW(state, 3, i);\n            w_AB_i = state_row[0];\n            w_Ab_i = state_row[1];\n            w_aB_i = state_row[2];\n            w_ab_i = n_i - (w_AB_i + w_Ab_i + w_aB_i);\n\n            n_j = (double) args.sample_set_sizes[j];\n            state_row = GET_2D_ROW(state, 3, j);\n            w_AB_j = state_row[0];\n            w_Ab_j = state_row[1];\n            w_aB_j = state_row[2];\n            w_ab_j = n_j - (w_AB_j + w_Ab_j + w_aB_j);\n\n            result[k] = (w_Ab_i * w_aB_i - w_AB_i * w_ab_i)\n                        * (w_Ab_j * w_aB_j - w_AB_j * w_ab_j) / n_i / (n_i - 1) / n_j\n                        / (n_j - 1);\n        }\n    }\n\n    return 0;\n}\n\nint\ntsk_treeseq_D2_ij_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, D2_ij_unbiased_summary_func,\n        norm_total_weighted, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\nout:\n    return ret;\n}\n\nstatic int\nr2_ij_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *state_row;\n    tsk_size_t k;\n    tsk_id_t i, j;\n    double n, pAB, pAb, paB, pA, pB, D_i, D_j, denom_i, denom_j;\n\n    for (k = 0; k < result_dim; k++) {\n        i = args.set_indexes[2 * k];\n        j = args.set_indexes[2 * k + 1];\n\n        n = (double) args.sample_set_sizes[i];\n        state_row = GET_2D_ROW(state, 3, i);\n        pAB = state_row[0] / n;\n        pAb = state_row[1] / n;\n        paB = state_row[2] / n;\n        pA = pAB + pAb;\n        pB = pAB + paB;\n        D_i = pAB - (pA * pB);\n        denom_i = sqrt(pA * (1 - pA) * pB * (1 - pB));\n\n        n = (double) args.sample_set_sizes[j];\n        state_row = GET_2D_ROW(state, 3, j);\n        pAB = state_row[0] / n;\n        pAb = state_row[1] / n;\n        paB = state_row[2] / n;\n        pA = pAB + pAb;\n        pB = pAB + paB;\n        D_j = pAB - (pA * pB);\n        denom_j = sqrt(pA * (1 - pA) * pB * (1 - pB));\n\n        result[k] = (D_i * D_j) / (denom_i * denom_j);\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_r2_ij(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 2, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_two_locus_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, r2_ij_summary_func,\n        norm_hap_weighted_ij, num_rows, row_sites, row_positions, num_cols, col_sites,\n        col_positions, options, result);\nout:\n    return ret;\n}\n\n/***********************************\n * Three way stats\n ***********************************/\n\nstatic int\nY3_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, nk, denom, numer;\n    tsk_id_t i, j, k;\n    tsk_size_t tuple_index;\n\n    for (tuple_index = 0; tuple_index < result_dim; tuple_index++) {\n        i = args.set_indexes[3 * tuple_index];\n        j = args.set_indexes[3 * tuple_index + 1];\n        k = args.set_indexes[3 * tuple_index + 2];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        nk = (double) args.sample_set_sizes[k];\n        denom = ni * nj * nk;\n        numer = x[i] * (nj - x[j]) * (nk - x[k]);\n        result[tuple_index] = numer / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_Y3(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 3, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, Y3_summary_func, num_windows,\n        windows, options, result);\nout:\n    return ret;\n}\n\nstatic int\nf3_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, nk, denom, numer;\n    tsk_id_t i, j, k;\n    tsk_size_t tuple_index;\n\n    for (tuple_index = 0; tuple_index < result_dim; tuple_index++) {\n        i = args.set_indexes[3 * tuple_index];\n        j = args.set_indexes[3 * tuple_index + 1];\n        k = args.set_indexes[3 * tuple_index + 2];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        nk = (double) args.sample_set_sizes[k];\n        denom = ni * (ni - 1) * nj * nk;\n        numer = x[i] * (x[i] - 1) * (nj - x[j]) * (nk - x[k])\n                - x[i] * (ni - x[i]) * (nj - x[j]) * x[k];\n        result[tuple_index] = numer / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_f3(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 3, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, f3_summary_func, num_windows,\n        windows, options, result);\nout:\n    return ret;\n}\n\n/***********************************\n * Four way stats\n ***********************************/\n\nstatic int\nf4_summary_func(tsk_size_t TSK_UNUSED(state_dim), const double *state,\n    tsk_size_t result_dim, double *result, void *params)\n{\n    sample_count_stat_params_t args = *(sample_count_stat_params_t *) params;\n    const double *x = state;\n    double ni, nj, nk, nl, denom, numer;\n    tsk_id_t i, j, k, l;\n    tsk_size_t tuple_index;\n\n    for (tuple_index = 0; tuple_index < result_dim; tuple_index++) {\n        i = args.set_indexes[4 * tuple_index];\n        j = args.set_indexes[4 * tuple_index + 1];\n        k = args.set_indexes[4 * tuple_index + 2];\n        l = args.set_indexes[4 * tuple_index + 3];\n        ni = (double) args.sample_set_sizes[i];\n        nj = (double) args.sample_set_sizes[j];\n        nk = (double) args.sample_set_sizes[k];\n        nl = (double) args.sample_set_sizes[l];\n        denom = ni * nj * nk * nl;\n        numer = x[i] * x[k] * (nj - x[j]) * (nl - x[l])\n                - x[i] * x[l] * (nj - x[j]) * (nk - x[k]);\n        result[tuple_index] = numer / denom;\n    }\n    return 0;\n}\n\nint\ntsk_treeseq_f4(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    ret = check_sample_stat_inputs(num_sample_sets, 4, num_index_tuples, index_tuples);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_sample_count_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_index_tuples, index_tuples, f4_summary_func, num_windows,\n        windows, options, result);\nout:\n    return ret;\n}\n\n/* Error-raising getter functions */\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_node(const tsk_treeseq_t *self, tsk_id_t index, tsk_node_t *node)\n{\n    return tsk_node_table_get_row(&self->tables->nodes, index, node);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_edge(const tsk_treeseq_t *self, tsk_id_t index, tsk_edge_t *edge)\n{\n    return tsk_edge_table_get_row(&self->tables->edges, index, edge);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_migration(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_migration_t *migration)\n{\n    return tsk_migration_table_get_row(&self->tables->migrations, index, migration);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_mutation(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_mutation_t *mutation)\n{\n    int ret = 0;\n\n    ret = tsk_mutation_table_get_row(&self->tables->mutations, index, mutation);\n    if (ret != 0) {\n        goto out;\n    }\n    mutation->edge = self->site_mutations_mem[index].edge;\n    mutation->inherited_state = self->site_mutations_mem[index].inherited_state;\n    mutation->inherited_state_length\n        = self->site_mutations_mem[index].inherited_state_length;\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_site(const tsk_treeseq_t *self, tsk_id_t index, tsk_site_t *site)\n{\n    int ret = 0;\n\n    ret = tsk_site_table_get_row(&self->tables->sites, index, site);\n    if (ret != 0) {\n        goto out;\n    }\n    site->mutations = self->site_mutations[index];\n    site->mutations_length = self->site_mutations_length[index];\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_individual(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_individual_t *individual)\n{\n    int ret = 0;\n\n    ret = tsk_individual_table_get_row(&self->tables->individuals, index, individual);\n    if (ret != 0) {\n        goto out;\n    }\n    individual->nodes = self->individual_nodes[index];\n    individual->nodes_length = self->individual_nodes_length[index];\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_population(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_population_t *population)\n{\n    return tsk_population_table_get_row(&self->tables->populations, index, population);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_get_provenance(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_provenance_t *provenance)\n{\n    return tsk_provenance_table_get_row(&self->tables->provenances, index, provenance);\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_simplify(const tsk_treeseq_t *self, const tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_flags_t options, tsk_treeseq_t *output,\n    tsk_id_t *node_map)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = tsk_malloc(sizeof(*tables));\n\n    if (tables == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_treeseq_copy_tables(self, tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_table_collection_simplify(tables, samples, num_samples, options, node_map);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_init(\n        output, tables, TSK_TS_INIT_BUILD_INDEXES | TSK_TAKE_OWNERSHIP);\n    /* Once tsk_treeseq_init has returned ownership of tables is transferred */\n    tables = NULL;\nout:\n    if (tables != NULL) {\n        tsk_table_collection_free(tables);\n        tsk_safe_free(tables);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_split_edges(const tsk_treeseq_t *self, double time, tsk_flags_t flags,\n    tsk_id_t population, const char *metadata, tsk_size_t metadata_length,\n    tsk_flags_t TSK_UNUSED(options), tsk_treeseq_t *output)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = tsk_malloc(sizeof(*tables));\n    const double *restrict node_time = self->tables->nodes.time;\n    const tsk_size_t num_edges = self->tables->edges.num_rows;\n    const tsk_size_t num_mutations = self->tables->mutations.num_rows;\n    tsk_id_t *split_edge = tsk_malloc(num_edges * sizeof(*split_edge));\n    tsk_id_t j, u, mapped_node, ret_id;\n    double mutation_time;\n    tsk_edge_t edge;\n    tsk_mutation_t mutation;\n    tsk_bookmark_t sort_start;\n\n    memset(output, 0, sizeof(*output));\n    if (split_edge == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_treeseq_copy_tables(self, tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    if (tables->migrations.num_rows > 0) {\n        ret = tsk_trace_error(TSK_ERR_MIGRATIONS_NOT_SUPPORTED);\n        goto out;\n    }\n    /* We could catch this below in add_row, but it's simpler to guarantee\n     * that we always catch the error in corner cases where the values\n     * aren't used. */\n    if (population < -1 || population >= (tsk_id_t) self->tables->populations.num_rows) {\n        ret = tsk_trace_error(TSK_ERR_POPULATION_OUT_OF_BOUNDS);\n        goto out;\n    }\n    if (!tsk_isfinite(time)) {\n        ret = tsk_trace_error(TSK_ERR_TIME_NONFINITE);\n        goto out;\n    }\n\n    tsk_edge_table_clear(&tables->edges);\n    tsk_memset(split_edge, TSK_NULL, num_edges * sizeof(*split_edge));\n\n    for (j = 0; j < (tsk_id_t) num_edges; j++) {\n        /* Would prefer to use tsk_edge_table_get_row_unsafe, but it's\n         * currently static to tables.c */\n        ret = tsk_edge_table_get_row(&self->tables->edges, j, &edge);\n        tsk_bug_assert(ret == 0);\n        if (node_time[edge.child] < time && time < node_time[edge.parent]) {\n            u = tsk_node_table_add_row(&tables->nodes, flags, time, population, TSK_NULL,\n                metadata, metadata_length);\n            if (u < 0) {\n                ret = (int) u;\n                goto out;\n            }\n            ret_id = tsk_edge_table_add_row(&tables->edges, edge.left, edge.right, u,\n                edge.child, edge.metadata, edge.metadata_length);\n            if (ret_id < 0) {\n                ret = (int) ret_id;\n                goto out;\n            }\n            edge.child = u;\n            split_edge[j] = u;\n        }\n        ret_id = tsk_edge_table_add_row(&tables->edges, edge.left, edge.right,\n            edge.parent, edge.child, edge.metadata, edge.metadata_length);\n        if (ret_id < 0) {\n            ret = (int) ret_id;\n            goto out;\n        }\n    }\n\n    for (j = 0; j < (tsk_id_t) num_mutations; j++) {\n        /* Note: we could speed this up a bit by accessing the local\n         * memory for mutations directly. */\n        ret = tsk_treeseq_get_mutation(self, j, &mutation);\n        tsk_bug_assert(ret == 0);\n        mapped_node = TSK_NULL;\n        if (mutation.edge != TSK_NULL) {\n            mapped_node = split_edge[mutation.edge];\n        }\n        mutation_time = tsk_is_unknown_time(mutation.time) ? node_time[mutation.node]\n                                                           : mutation.time;\n        if (mapped_node != TSK_NULL && mutation_time >= time) {\n            /* Update the column in-place to save a bit of time. */\n            tables->mutations.node[j] = mapped_node;\n        }\n    }\n\n    /* Skip mutations and sites as they haven't been altered */\n    /* Note we can probably optimise the edge sort a bit here also by\n     * reasoning about when the first edge gets altered in the table.\n     */\n    memset(&sort_start, 0, sizeof(sort_start));\n    sort_start.sites = tables->sites.num_rows;\n    sort_start.mutations = tables->mutations.num_rows;\n    ret = tsk_table_collection_sort(tables, &sort_start, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_treeseq_init(\n        output, tables, TSK_TS_INIT_BUILD_INDEXES | TSK_TAKE_OWNERSHIP);\n    tables = NULL;\nout:\n    if (tables != NULL) {\n        tsk_table_collection_free(tables);\n        tsk_safe_free(tables);\n    }\n    tsk_safe_free(split_edge);\n    return ret;\n}\n\n/* ======================================================== *\n * tree_position\n * ======================================================== */\n\nstatic void\ntsk_tree_position_set_null(tsk_tree_position_t *self)\n{\n    self->index = -1;\n    self->interval.left = 0;\n    self->interval.right = 0;\n}\n\nint\ntsk_tree_position_init(tsk_tree_position_t *self, const tsk_treeseq_t *tree_sequence,\n    tsk_flags_t TSK_UNUSED(options))\n{\n    memset(self, 0, sizeof(*self));\n    self->tree_sequence = tree_sequence;\n    tsk_tree_position_set_null(self);\n    return 0;\n}\n\nint\ntsk_tree_position_free(tsk_tree_position_t *TSK_UNUSED(self))\n{\n    return 0;\n}\n\nint\ntsk_tree_position_print_state(const tsk_tree_position_t *self, FILE *out)\n{\n    fprintf(out, \"Tree position state\\n\");\n    fprintf(out, \"index = %d\\n\", (int) self->index);\n    fprintf(out, \"interval = [%f,\\t%f)\\n\", self->interval.left, self->interval.right);\n    fprintf(\n        out, \"out   = start=%d\\tstop=%d\\n\", (int) self->out.start, (int) self->out.stop);\n    fprintf(\n        out, \"in    = start=%d\\tstop=%d\\n\", (int) self->in.start, (int) self->in.stop);\n    return 0;\n}\n\nbool\ntsk_tree_position_next(tsk_tree_position_t *self)\n{\n    const tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t M = (tsk_id_t) tables->edges.num_rows;\n    const tsk_id_t num_trees = (tsk_id_t) self->tree_sequence->num_trees;\n    const double *restrict left_coords = tables->edges.left;\n    const tsk_id_t *restrict left_order = tables->indexes.edge_insertion_order;\n    const double *restrict right_coords = tables->edges.right;\n    const tsk_id_t *restrict right_order = tables->indexes.edge_removal_order;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n    tsk_id_t j, left_current_index, right_current_index;\n    double left;\n\n    if (self->index == -1) {\n        self->interval.right = 0;\n        self->in.stop = 0;\n        self->out.stop = 0;\n        self->direction = TSK_DIR_FORWARD;\n    }\n\n    if (self->direction == TSK_DIR_FORWARD) {\n        left_current_index = self->in.stop;\n        right_current_index = self->out.stop;\n    } else {\n        left_current_index = self->out.stop + 1;\n        right_current_index = self->in.stop + 1;\n    }\n\n    left = self->interval.right;\n\n    j = right_current_index;\n    self->out.start = j;\n    while (j < M && right_coords[right_order[j]] == left) {\n        j++;\n    }\n    self->out.stop = j;\n    self->out.order = right_order;\n\n    j = left_current_index;\n    self->in.start = j;\n    while (j < M && left_coords[left_order[j]] == left) {\n        j++;\n    }\n    self->in.stop = j;\n    self->in.order = left_order;\n\n    self->direction = TSK_DIR_FORWARD;\n    self->index++;\n    if (self->index == num_trees) {\n        tsk_tree_position_set_null(self);\n    } else {\n        self->interval.left = left;\n        self->interval.right = breakpoints[self->index + 1];\n    }\n    return self->index != -1;\n}\n\nbool\ntsk_tree_position_prev(tsk_tree_position_t *self)\n{\n    const tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t M = (tsk_id_t) tables->edges.num_rows;\n    const double sequence_length = tables->sequence_length;\n    const tsk_id_t num_trees = (tsk_id_t) self->tree_sequence->num_trees;\n    const double *restrict left_coords = tables->edges.left;\n    const tsk_id_t *restrict left_order = tables->indexes.edge_insertion_order;\n    const double *restrict right_coords = tables->edges.right;\n    const tsk_id_t *restrict right_order = tables->indexes.edge_removal_order;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n    tsk_id_t j, left_current_index, right_current_index;\n    double right;\n\n    if (self->index == -1) {\n        self->index = num_trees;\n        self->interval.left = sequence_length;\n        self->in.stop = M - 1;\n        self->out.stop = M - 1;\n        self->direction = TSK_DIR_REVERSE;\n    }\n\n    if (self->direction == TSK_DIR_REVERSE) {\n        left_current_index = self->out.stop;\n        right_current_index = self->in.stop;\n    } else {\n        left_current_index = self->in.stop - 1;\n        right_current_index = self->out.stop - 1;\n    }\n\n    right = self->interval.left;\n\n    j = left_current_index;\n    self->out.start = j;\n    while (j >= 0 && left_coords[left_order[j]] == right) {\n        j--;\n    }\n    self->out.stop = j;\n    self->out.order = left_order;\n\n    j = right_current_index;\n    self->in.start = j;\n    while (j >= 0 && right_coords[right_order[j]] == right) {\n        j--;\n    }\n    self->in.stop = j;\n    self->in.order = right_order;\n\n    self->index--;\n    self->direction = TSK_DIR_REVERSE;\n    if (self->index == -1) {\n        tsk_tree_position_set_null(self);\n    } else {\n        self->interval.left = breakpoints[self->index];\n        self->interval.right = right;\n    }\n    return self->index != -1;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_position_seek_forward(tsk_tree_position_t *self, tsk_id_t index)\n{\n    int ret = 0;\n    const tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t M = (tsk_id_t) tables->edges.num_rows;\n    const tsk_id_t num_trees = (tsk_id_t) self->tree_sequence->num_trees;\n    const double *restrict left_coords = tables->edges.left;\n    const tsk_id_t *restrict left_order = tables->indexes.edge_insertion_order;\n    const double *restrict right_coords = tables->edges.right;\n    const tsk_id_t *restrict right_order = tables->indexes.edge_removal_order;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n    tsk_id_t j, left_current_index, right_current_index;\n    double left;\n\n    tsk_bug_assert(index >= self->index && index < num_trees);\n\n    if (self->index == -1) {\n        self->interval.right = 0;\n        self->in.stop = 0;\n        self->out.stop = 0;\n        self->direction = TSK_DIR_FORWARD;\n    }\n\n    if (self->direction == TSK_DIR_FORWARD) {\n        left_current_index = self->in.stop;\n        right_current_index = self->out.stop;\n    } else {\n        left_current_index = self->out.stop + 1;\n        right_current_index = self->in.stop + 1;\n    }\n\n    self->direction = TSK_DIR_FORWARD;\n    left = breakpoints[index];\n\n    j = right_current_index;\n    self->out.start = j;\n    while (j < M && right_coords[right_order[j]] <= left) {\n        j++;\n    }\n    self->out.stop = j;\n\n    if (self->index == -1) {\n        self->out.start = self->out.stop;\n    }\n\n    j = left_current_index;\n    while (j < M && right_coords[left_order[j]] <= left) {\n        j++;\n    }\n    self->in.start = j;\n    while (j < M && left_coords[left_order[j]] <= left) {\n        j++;\n    }\n    self->in.stop = j;\n\n    self->interval.left = left;\n    self->interval.right = breakpoints[index + 1];\n    self->out.order = right_order;\n    self->in.order = left_order;\n    self->index = index;\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_position_seek_backward(tsk_tree_position_t *self, tsk_id_t index)\n{\n    int ret = 0;\n    const tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t M = (tsk_id_t) tables->edges.num_rows;\n    const double sequence_length = tables->sequence_length;\n    const tsk_id_t num_trees = (tsk_id_t) self->tree_sequence->num_trees;\n    const double *restrict left_coords = tables->edges.left;\n    const tsk_id_t *restrict left_order = tables->indexes.edge_insertion_order;\n    const double *restrict right_coords = tables->edges.right;\n    const tsk_id_t *restrict right_order = tables->indexes.edge_removal_order;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n    tsk_id_t j, left_current_index, right_current_index;\n    double right;\n\n    if (self->index == -1) {\n        self->index = num_trees;\n        self->interval.left = sequence_length;\n        self->in.stop = M - 1;\n        self->out.stop = M - 1;\n        self->direction = TSK_DIR_REVERSE;\n    }\n    tsk_bug_assert(index <= self->index);\n\n    if (self->direction == TSK_DIR_REVERSE) {\n        left_current_index = self->out.stop;\n        right_current_index = self->in.stop;\n    } else {\n        left_current_index = self->in.stop - 1;\n        right_current_index = self->out.stop - 1;\n    }\n\n    self->direction = TSK_DIR_REVERSE;\n    right = breakpoints[index + 1];\n\n    j = left_current_index;\n    self->out.start = j;\n    while (j >= 0 && left_coords[left_order[j]] >= right) {\n        j--;\n    }\n    self->out.stop = j;\n\n    if (self->index == num_trees) {\n        self->out.start = self->out.stop;\n    }\n\n    j = right_current_index;\n    while (j >= 0 && left_coords[right_order[j]] >= right) {\n        j--;\n    }\n    self->in.start = j;\n    while (j >= 0 && right_coords[right_order[j]] >= right) {\n        j--;\n    }\n    self->in.stop = j;\n\n    self->interval.right = right;\n    self->interval.left = breakpoints[index];\n    self->out.order = left_order;\n    self->in.order = right_order;\n    self->index = index;\n\n    return ret;\n}\n\n/* ======================================================== *\n * Tree\n * ======================================================== */\n\n/* Return the root for the specified node.\n * NOTE: no bounds checking is done here.\n */\nstatic tsk_id_t\ntsk_tree_get_node_root(const tsk_tree_t *self, tsk_id_t u)\n{\n    const tsk_id_t *restrict parent = self->parent;\n\n    while (parent[u] != TSK_NULL) {\n        u = parent[u];\n    }\n    return u;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_init(tsk_tree_t *self, const tsk_treeseq_t *tree_sequence, tsk_flags_t options)\n{\n    int ret = 0;\n    tsk_size_t num_samples, num_nodes, N;\n\n    tsk_memset(self, 0, sizeof(tsk_tree_t));\n    if (tree_sequence == NULL) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    num_nodes = tree_sequence->tables->nodes.num_rows;\n    num_samples = tree_sequence->num_samples;\n    self->num_nodes = num_nodes;\n    self->virtual_root = (tsk_id_t) num_nodes;\n    self->tree_sequence = tree_sequence;\n    self->samples = tree_sequence->samples;\n    self->options = options;\n    self->root_threshold = 1;\n\n    /* Allocate space in the quintuply linked tree for the virtual root */\n    N = num_nodes + 1;\n    self->parent = tsk_malloc(N * sizeof(*self->parent));\n    self->left_child = tsk_malloc(N * sizeof(*self->left_child));\n    self->right_child = tsk_malloc(N * sizeof(*self->right_child));\n    self->left_sib = tsk_malloc(N * sizeof(*self->left_sib));\n    self->right_sib = tsk_malloc(N * sizeof(*self->right_sib));\n    self->num_children = tsk_calloc(N, sizeof(*self->num_children));\n    self->edge = tsk_malloc(N * sizeof(*self->edge));\n    if (self->parent == NULL || self->left_child == NULL || self->right_child == NULL\n        || self->left_sib == NULL || self->right_sib == NULL\n        || self->num_children == NULL || self->edge == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n        self->num_samples = tsk_calloc(N, sizeof(*self->num_samples));\n        self->num_tracked_samples = tsk_calloc(N, sizeof(*self->num_tracked_samples));\n        if (self->num_samples == NULL || self->num_tracked_samples == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n    if (self->options & TSK_SAMPLE_LISTS) {\n        self->left_sample = tsk_malloc(N * sizeof(*self->left_sample));\n        self->right_sample = tsk_malloc(N * sizeof(*self->right_sample));\n        self->next_sample = tsk_malloc(num_samples * sizeof(*self->next_sample));\n        if (self->left_sample == NULL || self->right_sample == NULL\n            || self->next_sample == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    ret = tsk_tree_position_init(&self->tree_pos, tree_sequence, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_clear(self);\nout:\n    return ret;\n}\n\nint\ntsk_tree_set_root_threshold(tsk_tree_t *self, tsk_size_t root_threshold)\n{\n    int ret = 0;\n\n    if (root_threshold == 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    /* Don't allow the value to be set when the tree is out of the null\n     * state */\n    if (self->index != -1) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n        goto out;\n    }\n    self->root_threshold = root_threshold;\n    /* Reset the roots */\n    ret = tsk_tree_clear(self);\nout:\n    return ret;\n}\n\ntsk_size_t\ntsk_tree_get_root_threshold(const tsk_tree_t *self)\n{\n    return self->root_threshold;\n}\n\nint\ntsk_tree_free(tsk_tree_t *self)\n{\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->left_child);\n    tsk_safe_free(self->right_child);\n    tsk_safe_free(self->left_sib);\n    tsk_safe_free(self->right_sib);\n    tsk_safe_free(self->num_samples);\n    tsk_safe_free(self->num_tracked_samples);\n    tsk_safe_free(self->left_sample);\n    tsk_safe_free(self->right_sample);\n    tsk_safe_free(self->next_sample);\n    tsk_safe_free(self->num_children);\n    tsk_safe_free(self->edge);\n    tsk_tree_position_free(&self->tree_pos);\n    return 0;\n}\n\nbool\ntsk_tree_has_sample_lists(const tsk_tree_t *self)\n{\n    return !!(self->options & TSK_SAMPLE_LISTS);\n}\n\nbool\ntsk_tree_has_sample_counts(const tsk_tree_t *self)\n{\n    return !(self->options & TSK_NO_SAMPLE_COUNTS);\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_tree_reset_tracked_samples(tsk_tree_t *self)\n{\n    int ret = 0;\n\n    if (!tsk_tree_has_sample_counts(self)) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n        goto out;\n    }\n    tsk_memset(self->num_tracked_samples, 0,\n        (self->num_nodes + 1) * sizeof(*self->num_tracked_samples));\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_set_tracked_samples(\n    tsk_tree_t *self, tsk_size_t num_tracked_samples, const tsk_id_t *tracked_samples)\n{\n    int ret = TSK_ERR_GENERIC;\n    tsk_size_t *tree_num_tracked_samples = self->num_tracked_samples;\n    const tsk_id_t *parent = self->parent;\n    tsk_size_t j;\n    tsk_id_t u;\n\n    /* TODO This is not needed when the tree is new. We should use the\n     * state machine to check and only reset the tracked samples when needed.\n     */\n    ret = tsk_tree_reset_tracked_samples(self);\n    if (ret != 0) {\n        goto out;\n    }\n    self->num_tracked_samples[self->virtual_root] = num_tracked_samples;\n    for (j = 0; j < num_tracked_samples; j++) {\n        u = tracked_samples[j];\n        if (u < 0 || u >= (tsk_id_t) self->num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n        if (!tsk_treeseq_is_sample(self->tree_sequence, u)) {\n            ret = tsk_trace_error(TSK_ERR_BAD_SAMPLES);\n            goto out;\n        }\n        if (self->num_tracked_samples[u] != 0) {\n            ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n            goto out;\n        }\n        /* Propagate this upwards */\n        while (u != TSK_NULL) {\n            tree_num_tracked_samples[u]++;\n            u = parent[u];\n        }\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_track_descendant_samples(tsk_tree_t *self, tsk_id_t node)\n{\n    int ret = 0;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    const tsk_id_t *restrict parent = self->parent;\n    const tsk_id_t *restrict left_child = self->left_child;\n    const tsk_id_t *restrict right_sib = self->right_sib;\n    const tsk_flags_t *restrict flags = self->tree_sequence->tables->nodes.flags;\n    tsk_size_t *num_tracked_samples = self->num_tracked_samples;\n    tsk_size_t n, j, num_nodes;\n    tsk_id_t u, v;\n\n    if (nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_tree_postorder_from(self, node, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_reset_tracked_samples(self);\n    if (ret != 0) {\n        goto out;\n    }\n    u = 0; /* keep the compiler happy */\n    for (j = 0; j < num_nodes; j++) {\n        u = nodes[j];\n        for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n            num_tracked_samples[u] += num_tracked_samples[v];\n        }\n        num_tracked_samples[u] += flags[u] & TSK_NODE_IS_SAMPLE ? 1 : 0;\n    }\n    n = num_tracked_samples[u];\n    u = parent[u];\n    while (u != TSK_NULL) {\n        num_tracked_samples[u] = n;\n        u = parent[u];\n    }\n    num_tracked_samples[self->virtual_root] = n;\nout:\n    tsk_safe_free(nodes);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_copy(const tsk_tree_t *self, tsk_tree_t *dest, tsk_flags_t options)\n{\n    int ret = TSK_ERR_GENERIC;\n    tsk_size_t N = self->num_nodes + 1;\n\n    if (!(options & TSK_NO_INIT)) {\n        ret = tsk_tree_init(dest, self->tree_sequence, options);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n    if (self->tree_sequence != dest->tree_sequence) {\n        ret = tsk_trace_error(TSK_ERR_BAD_PARAM_VALUE);\n        goto out;\n    }\n    dest->interval = self->interval;\n    dest->left_index = self->left_index;\n    dest->right_index = self->right_index;\n    dest->direction = self->direction;\n    dest->index = self->index;\n    dest->sites = self->sites;\n    dest->sites_length = self->sites_length;\n    dest->root_threshold = self->root_threshold;\n    dest->num_edges = self->num_edges;\n    dest->tree_pos = self->tree_pos;\n\n    tsk_memcpy(dest->parent, self->parent, N * sizeof(*self->parent));\n    tsk_memcpy(dest->left_child, self->left_child, N * sizeof(*self->left_child));\n    tsk_memcpy(dest->right_child, self->right_child, N * sizeof(*self->right_child));\n    tsk_memcpy(dest->left_sib, self->left_sib, N * sizeof(*self->left_sib));\n    tsk_memcpy(dest->right_sib, self->right_sib, N * sizeof(*self->right_sib));\n    tsk_memcpy(dest->num_children, self->num_children, N * sizeof(*self->num_children));\n    tsk_memcpy(dest->edge, self->edge, N * sizeof(*self->edge));\n    if (!(dest->options & TSK_NO_SAMPLE_COUNTS)) {\n        if (self->options & TSK_NO_SAMPLE_COUNTS) {\n            ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n            goto out;\n        }\n        tsk_memcpy(dest->num_samples, self->num_samples, N * sizeof(*self->num_samples));\n        tsk_memcpy(dest->num_tracked_samples, self->num_tracked_samples,\n            N * sizeof(*self->num_tracked_samples));\n    }\n    if (dest->options & TSK_SAMPLE_LISTS) {\n        if (!(self->options & TSK_SAMPLE_LISTS)) {\n            ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n            goto out;\n        }\n        tsk_memcpy(dest->left_sample, self->left_sample, N * sizeof(*self->left_sample));\n        tsk_memcpy(\n            dest->right_sample, self->right_sample, N * sizeof(*self->right_sample));\n        tsk_memcpy(dest->next_sample, self->next_sample,\n            self->tree_sequence->num_samples * sizeof(*self->next_sample));\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nbool TSK_WARN_UNUSED\ntsk_tree_equals(const tsk_tree_t *self, const tsk_tree_t *other)\n{\n    bool ret = false;\n\n    if (self->tree_sequence == other->tree_sequence) {\n        ret = self->index == other->index;\n    }\n    return ret;\n}\n\nstatic int\ntsk_tree_check_node(const tsk_tree_t *self, tsk_id_t u)\n{\n    int ret = 0;\n    if (u < 0 || u > (tsk_id_t) self->num_nodes) {\n        ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n    }\n    return ret;\n}\n\nbool\ntsk_tree_is_descendant(const tsk_tree_t *self, tsk_id_t u, tsk_id_t v)\n{\n    bool ret = false;\n    tsk_id_t w = u;\n    tsk_id_t *restrict parent = self->parent;\n\n    if (tsk_tree_check_node(self, u) == 0 && tsk_tree_check_node(self, v) == 0) {\n        while (w != v && w != TSK_NULL) {\n            w = parent[w];\n        }\n        ret = w == v;\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_mrca(const tsk_tree_t *self, tsk_id_t u, tsk_id_t v, tsk_id_t *mrca)\n{\n    int ret = 0;\n    double tu, tv;\n    const tsk_id_t *restrict parent = self->parent;\n    const double *restrict time = self->tree_sequence->tables->nodes.time;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_check_node(self, v);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* Simplest to make the virtual_root a special case here to avoid\n     * doing the time lookup. */\n    if (u == self->virtual_root || v == self->virtual_root) {\n        *mrca = self->virtual_root;\n        return 0;\n    }\n\n    tu = time[u];\n    tv = time[v];\n    while (u != v) {\n        if (tu < tv) {\n            u = parent[u];\n            if (u == TSK_NULL) {\n                break;\n            }\n            tu = time[u];\n        } else {\n            v = parent[v];\n            if (v == TSK_NULL) {\n                break;\n            }\n            tv = time[v];\n        }\n    }\n    *mrca = u == v ? u : TSK_NULL;\nout:\n    return ret;\n}\n\nstatic int\ntsk_tree_get_num_samples_by_traversal(\n    const tsk_tree_t *self, tsk_id_t u, tsk_size_t *num_samples)\n{\n    int ret = 0;\n    tsk_size_t num_nodes, j;\n    tsk_size_t count = 0;\n    const tsk_flags_t *restrict flags = self->tree_sequence->tables->nodes.flags;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    tsk_id_t v;\n\n    if (nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_tree_preorder_from(self, u, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_nodes; j++) {\n        v = nodes[j];\n        if (flags[v] & TSK_NODE_IS_SAMPLE) {\n            count++;\n        }\n    }\n    *num_samples = count;\nout:\n    tsk_safe_free(nodes);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_num_samples(const tsk_tree_t *self, tsk_id_t u, tsk_size_t *num_samples)\n{\n    int ret = 0;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n        *num_samples = (tsk_size_t) self->num_samples[u];\n    } else {\n        ret = tsk_tree_get_num_samples_by_traversal(self, u, num_samples);\n    }\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_num_tracked_samples(\n    const tsk_tree_t *self, tsk_id_t u, tsk_size_t *num_tracked_samples)\n{\n    int ret = 0;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n    if (self->options & TSK_NO_SAMPLE_COUNTS) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n        goto out;\n    }\n    *num_tracked_samples = self->num_tracked_samples[u];\nout:\n    return ret;\n}\n\nbool\ntsk_tree_is_sample(const tsk_tree_t *self, tsk_id_t u)\n{\n    return tsk_treeseq_is_sample(self->tree_sequence, u);\n}\n\ntsk_id_t\ntsk_tree_get_left_root(const tsk_tree_t *self)\n{\n    return self->left_child[self->virtual_root];\n}\n\ntsk_id_t\ntsk_tree_get_right_root(const tsk_tree_t *self)\n{\n    return self->right_child[self->virtual_root];\n}\n\ntsk_size_t\ntsk_tree_get_num_roots(const tsk_tree_t *self)\n{\n    return (tsk_size_t) self->num_children[self->virtual_root];\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_parent(const tsk_tree_t *self, tsk_id_t u, tsk_id_t *parent)\n{\n    int ret = 0;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n    *parent = self->parent[u];\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_time(const tsk_tree_t *self, tsk_id_t u, double *t)\n{\n    int ret = 0;\n    tsk_node_t node;\n\n    if (u == self->virtual_root) {\n        *t = INFINITY;\n    } else {\n        ret = tsk_treeseq_get_node(self->tree_sequence, u, &node);\n        if (ret != 0) {\n            goto out;\n        }\n        *t = node.time;\n    }\nout:\n    return ret;\n}\n\nstatic inline double\ntsk_tree_get_branch_length_unsafe(const tsk_tree_t *self, tsk_id_t u)\n{\n    const double *times = self->tree_sequence->tables->nodes.time;\n    const tsk_id_t parent = self->parent[u];\n\n    return parent == TSK_NULL ? 0 : times[parent] - times[u];\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_branch_length(const tsk_tree_t *self, tsk_id_t u, double *ret_branch_length)\n{\n    int ret = 0;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n    *ret_branch_length = tsk_tree_get_branch_length_unsafe(self, u);\nout:\n    return ret;\n}\n\nint\ntsk_tree_get_total_branch_length(const tsk_tree_t *self, tsk_id_t node, double *ret_tbl)\n{\n    int ret = 0;\n    tsk_size_t j, num_nodes;\n    tsk_id_t u, v;\n    const tsk_id_t *restrict parent = self->parent;\n    const double *restrict time = self->tree_sequence->tables->nodes.time;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    double sum = 0;\n\n    if (nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_tree_preorder_from(self, node, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    /* We always skip the first node because we don't return the branch length\n     * over the input node. */\n    for (j = 1; j < num_nodes; j++) {\n        u = nodes[j];\n        v = parent[u];\n        if (v != TSK_NULL) {\n            sum += time[v] - time[u];\n        }\n    }\n    *ret_tbl = sum;\nout:\n    tsk_safe_free(nodes);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_sites(\n    const tsk_tree_t *self, const tsk_site_t **sites, tsk_size_t *sites_length)\n{\n    *sites = self->sites;\n    *sites_length = self->sites_length;\n    return 0;\n}\n\n/* u must be a valid node in the tree. For internal use */\nstatic int\ntsk_tree_get_depth_unsafe(const tsk_tree_t *self, tsk_id_t u)\n{\n    tsk_id_t v;\n    const tsk_id_t *restrict parent = self->parent;\n    int depth = 0;\n\n    if (u == self->virtual_root) {\n        return -1;\n    }\n    for (v = parent[u]; v != TSK_NULL; v = parent[v]) {\n        depth++;\n    }\n    return depth;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_get_depth(const tsk_tree_t *self, tsk_id_t u, int *depth_ret)\n{\n    int ret = 0;\n\n    ret = tsk_tree_check_node(self, u);\n    if (ret != 0) {\n        goto out;\n    }\n\n    *depth_ret = tsk_tree_get_depth_unsafe(self, u);\nout:\n    return ret;\n}\n\nstatic tsk_id_t\ntsk_tree_node_root(tsk_tree_t *self, tsk_id_t u)\n{\n    tsk_id_t v = u;\n    while (self->parent[v] != TSK_NULL) {\n        v = self->parent[v];\n    }\n\n    return v;\n}\n\nstatic void\ntsk_tree_check_state(const tsk_tree_t *self)\n{\n    tsk_id_t u, v;\n    tsk_size_t j, num_samples;\n    int err, c;\n    tsk_site_t site;\n    tsk_id_t *children = tsk_malloc(self->num_nodes * sizeof(tsk_id_t));\n    bool *is_root = tsk_calloc(self->num_nodes, sizeof(bool));\n\n    tsk_bug_assert(children != NULL);\n\n    /* Check the virtual root properties */\n    tsk_bug_assert(self->parent[self->virtual_root] == TSK_NULL);\n    tsk_bug_assert(self->left_sib[self->virtual_root] == TSK_NULL);\n    tsk_bug_assert(self->right_sib[self->virtual_root] == TSK_NULL);\n\n    for (j = 0; j < self->tree_sequence->num_samples; j++) {\n        u = self->samples[j];\n        while (self->parent[u] != TSK_NULL) {\n            u = self->parent[u];\n        }\n        is_root[u] = true;\n    }\n    if (self->tree_sequence->num_samples == 0) {\n        tsk_bug_assert(self->left_child[self->virtual_root] == TSK_NULL);\n    }\n\n    /* Iterate over the roots and make sure they are set */\n    for (u = tsk_tree_get_left_root(self); u != TSK_NULL; u = self->right_sib[u]) {\n        tsk_bug_assert(is_root[u]);\n        is_root[u] = false;\n    }\n    for (u = 0; u < (tsk_id_t) self->num_nodes; u++) {\n        tsk_bug_assert(!is_root[u]);\n        c = 0;\n        for (v = self->left_child[u]; v != TSK_NULL; v = self->right_sib[v]) {\n            tsk_bug_assert(self->parent[v] == u);\n            children[c] = v;\n            c++;\n        }\n        for (v = self->right_child[u]; v != TSK_NULL; v = self->left_sib[v]) {\n            tsk_bug_assert(c > 0);\n            c--;\n            tsk_bug_assert(v == children[c]);\n        }\n    }\n    for (j = 0; j < self->sites_length; j++) {\n        site = self->sites[j];\n        tsk_bug_assert(self->interval.left <= site.position);\n        tsk_bug_assert(site.position < self->interval.right);\n    }\n\n    if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n        tsk_bug_assert(self->num_samples != NULL);\n        tsk_bug_assert(self->num_tracked_samples != NULL);\n        for (u = 0; u < (tsk_id_t) self->num_nodes; u++) {\n            err = tsk_tree_get_num_samples_by_traversal(self, u, &num_samples);\n            tsk_bug_assert(err == 0);\n            tsk_bug_assert(num_samples == (tsk_size_t) self->num_samples[u]);\n        }\n    } else {\n        tsk_bug_assert(self->num_samples == NULL);\n        tsk_bug_assert(self->num_tracked_samples == NULL);\n    }\n    if (self->options & TSK_SAMPLE_LISTS) {\n        tsk_bug_assert(self->right_sample != NULL);\n        tsk_bug_assert(self->left_sample != NULL);\n        tsk_bug_assert(self->next_sample != NULL);\n    } else {\n        tsk_bug_assert(self->right_sample == NULL);\n        tsk_bug_assert(self->left_sample == NULL);\n        tsk_bug_assert(self->next_sample == NULL);\n    }\n\n    free(children);\n    free(is_root);\n}\n\nvoid\ntsk_tree_print_state(const tsk_tree_t *self, FILE *out)\n{\n    tsk_size_t j;\n    tsk_site_t site;\n\n    fprintf(out, \"Tree state:\\n\");\n    fprintf(out, \"options = %d\\n\", self->options);\n    fprintf(out, \"root_threshold = %lld\\n\", (long long) self->root_threshold);\n    fprintf(out, \"left = %f\\n\", self->interval.left);\n    fprintf(out, \"right = %f\\n\", self->interval.right);\n    fprintf(out, \"index = %lld\\n\", (long long) self->index);\n    fprintf(out, \"num_edges = %d\\n\", (int) self->num_edges);\n    fprintf(out, \"node\\tedge\\tparent\\tlchild\\trchild\\tlsib\\trsib\");\n    if (self->options & TSK_SAMPLE_LISTS) {\n        fprintf(out, \"\\thead\\ttail\");\n    }\n    fprintf(out, \"\\n\");\n\n    for (j = 0; j < self->num_nodes + 1; j++) {\n        fprintf(out, \"%lld\\t%lld\\t%lld\\t%lld\\t%lld\\t%lld\\t%lld\", (long long) j,\n            (long long) self->edge[j], (long long) self->parent[j],\n            (long long) self->left_child[j], (long long) self->right_child[j],\n            (long long) self->left_sib[j], (long long) self->right_sib[j]);\n        if (self->options & TSK_SAMPLE_LISTS) {\n            fprintf(out, \"\\t%lld\\t%lld\\t\", (long long) self->left_sample[j],\n                (long long) self->right_sample[j]);\n        }\n        if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n            fprintf(out, \"\\t%lld\\t%lld\", (long long) self->num_samples[j],\n                (long long) self->num_tracked_samples[j]);\n        }\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"sites = \\n\");\n    for (j = 0; j < self->sites_length; j++) {\n        site = self->sites[j];\n        fprintf(out, \"\\t%lld\\t%f\\n\", (long long) site.id, site.position);\n    }\n    tsk_tree_check_state(self);\n}\n\n/* Methods for positioning the tree along the sequence */\n\n/* The following methods are performance sensitive and so we use a\n * lot of restrict pointers. Because we are saying that we don't have\n * any aliases to these pointers, we pass around the reference to parent\n * since it's used in all the functions. */\nstatic inline void\ntsk_tree_update_sample_lists(\n    tsk_tree_t *self, tsk_id_t node, const tsk_id_t *restrict parent)\n{\n    tsk_id_t u, v, sample_index;\n    tsk_id_t *restrict left_child = self->left_child;\n    tsk_id_t *restrict right_sib = self->right_sib;\n    tsk_id_t *restrict left = self->left_sample;\n    tsk_id_t *restrict right = self->right_sample;\n    tsk_id_t *restrict next = self->next_sample;\n    const tsk_id_t *restrict sample_index_map = self->tree_sequence->sample_index_map;\n\n    for (u = node; u != TSK_NULL; u = parent[u]) {\n        sample_index = sample_index_map[u];\n        if (sample_index != TSK_NULL) {\n            right[u] = left[u];\n        } else {\n            left[u] = TSK_NULL;\n            right[u] = TSK_NULL;\n        }\n        for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n            if (left[v] != TSK_NULL) {\n                tsk_bug_assert(right[v] != TSK_NULL);\n                if (left[u] == TSK_NULL) {\n                    left[u] = left[v];\n                    right[u] = right[v];\n                } else {\n                    next[right[u]] = left[v];\n                    right[u] = right[v];\n                }\n            }\n        }\n    }\n}\n\nstatic inline void\ntsk_tree_remove_branch(\n    tsk_tree_t *self, tsk_id_t p, tsk_id_t c, tsk_id_t *restrict parent)\n{\n    tsk_id_t *restrict left_child = self->left_child;\n    tsk_id_t *restrict right_child = self->right_child;\n    tsk_id_t *restrict left_sib = self->left_sib;\n    tsk_id_t *restrict right_sib = self->right_sib;\n    tsk_id_t *restrict num_children = self->num_children;\n    tsk_id_t lsib = left_sib[c];\n    tsk_id_t rsib = right_sib[c];\n\n    if (lsib == TSK_NULL) {\n        left_child[p] = rsib;\n    } else {\n        right_sib[lsib] = rsib;\n    }\n    if (rsib == TSK_NULL) {\n        right_child[p] = lsib;\n    } else {\n        left_sib[rsib] = lsib;\n    }\n    parent[c] = TSK_NULL;\n    left_sib[c] = TSK_NULL;\n    right_sib[c] = TSK_NULL;\n    num_children[p]--;\n}\n\nstatic inline void\ntsk_tree_insert_branch(\n    tsk_tree_t *self, tsk_id_t p, tsk_id_t c, tsk_id_t *restrict parent)\n{\n    tsk_id_t *restrict left_child = self->left_child;\n    tsk_id_t *restrict right_child = self->right_child;\n    tsk_id_t *restrict left_sib = self->left_sib;\n    tsk_id_t *restrict right_sib = self->right_sib;\n    tsk_id_t *restrict num_children = self->num_children;\n    tsk_id_t u;\n\n    parent[c] = p;\n    u = right_child[p];\n    if (u == TSK_NULL) {\n        left_child[p] = c;\n        left_sib[c] = TSK_NULL;\n        right_sib[c] = TSK_NULL;\n    } else {\n        right_sib[u] = c;\n        left_sib[c] = u;\n        right_sib[c] = TSK_NULL;\n    }\n    right_child[p] = c;\n    num_children[p]++;\n}\n\nstatic inline void\ntsk_tree_insert_root(tsk_tree_t *self, tsk_id_t root, tsk_id_t *restrict parent)\n{\n    tsk_tree_insert_branch(self, self->virtual_root, root, parent);\n    parent[root] = TSK_NULL;\n}\n\nstatic inline void\ntsk_tree_remove_root(tsk_tree_t *self, tsk_id_t root, tsk_id_t *restrict parent)\n{\n    tsk_tree_remove_branch(self, self->virtual_root, root, parent);\n}\n\nstatic void\ntsk_tree_remove_edge(\n    tsk_tree_t *self, tsk_id_t p, tsk_id_t c, tsk_id_t TSK_UNUSED(edge_id))\n{\n    tsk_id_t *restrict parent = self->parent;\n    tsk_size_t *restrict num_samples = self->num_samples;\n    tsk_size_t *restrict num_tracked_samples = self->num_tracked_samples;\n    tsk_id_t *restrict edge = self->edge;\n    const tsk_size_t root_threshold = self->root_threshold;\n    tsk_id_t u;\n    tsk_id_t path_end = TSK_NULL;\n    bool path_end_was_root = false;\n\n#define POTENTIAL_ROOT(U) (num_samples[U] >= root_threshold)\n\n    tsk_tree_remove_branch(self, p, c, parent);\n    self->num_edges--;\n    edge[c] = TSK_NULL;\n\n    if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n        u = p;\n        while (u != TSK_NULL) {\n            path_end = u;\n            path_end_was_root = POTENTIAL_ROOT(u);\n            num_samples[u] -= num_samples[c];\n            num_tracked_samples[u] -= num_tracked_samples[c];\n            u = parent[u];\n        }\n\n        if (path_end_was_root && !POTENTIAL_ROOT(path_end)) {\n            tsk_tree_remove_root(self, path_end, parent);\n        }\n        if (POTENTIAL_ROOT(c)) {\n            tsk_tree_insert_root(self, c, parent);\n        }\n    }\n\n    if (self->options & TSK_SAMPLE_LISTS) {\n        tsk_tree_update_sample_lists(self, p, parent);\n    }\n}\n\nstatic void\ntsk_tree_insert_edge(tsk_tree_t *self, tsk_id_t p, tsk_id_t c, tsk_id_t edge_id)\n{\n    tsk_id_t *restrict parent = self->parent;\n    tsk_size_t *restrict num_samples = self->num_samples;\n    tsk_size_t *restrict num_tracked_samples = self->num_tracked_samples;\n    tsk_id_t *restrict edge = self->edge;\n    const tsk_size_t root_threshold = self->root_threshold;\n    tsk_id_t u;\n    tsk_id_t path_end = TSK_NULL;\n    bool path_end_was_root = false;\n\n#define POTENTIAL_ROOT(U) (num_samples[U] >= root_threshold)\n\n    if (!(self->options & TSK_NO_SAMPLE_COUNTS)) {\n        u = p;\n        while (u != TSK_NULL) {\n            path_end = u;\n            path_end_was_root = POTENTIAL_ROOT(u);\n            num_samples[u] += num_samples[c];\n            num_tracked_samples[u] += num_tracked_samples[c];\n            u = parent[u];\n        }\n\n        if (POTENTIAL_ROOT(c)) {\n            tsk_tree_remove_root(self, c, parent);\n        }\n        if (POTENTIAL_ROOT(path_end) && !path_end_was_root) {\n            tsk_tree_insert_root(self, path_end, parent);\n        }\n    }\n\n    tsk_tree_insert_branch(self, p, c, parent);\n    self->num_edges++;\n    edge[c] = edge_id;\n\n    if (self->options & TSK_SAMPLE_LISTS) {\n        tsk_tree_update_sample_lists(self, p, parent);\n    }\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_first(tsk_tree_t *self)\n{\n    int ret = TSK_TREE_OK;\n\n    ret = tsk_tree_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_next(self);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_last(tsk_tree_t *self)\n{\n    int ret = TSK_TREE_OK;\n\n    ret = tsk_tree_clear(self);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_tree_prev(self);\nout:\n    return ret;\n}\n\nstatic void\ntsk_tree_update_index_and_interval(tsk_tree_t *self)\n{\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n\n    self->index = self->tree_pos.index;\n    self->interval.left = self->tree_pos.interval.left;\n    self->interval.right = self->tree_pos.interval.right;\n\n    if (tables->sites.num_rows > 0) {\n        self->sites = self->tree_sequence->tree_sites[self->index];\n        self->sites_length = self->tree_sequence->tree_sites_length[self->index];\n    }\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_next(tsk_tree_t *self)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t *restrict edge_parent = tables->edges.parent;\n    const tsk_id_t *restrict edge_child = tables->edges.child;\n    tsk_id_t j, e;\n    tsk_tree_position_t tree_pos;\n    bool valid;\n\n    valid = tsk_tree_position_next(&self->tree_pos);\n    tree_pos = self->tree_pos;\n\n    if (valid) {\n        for (j = tree_pos.out.start; j != tree_pos.out.stop; j++) {\n            e = tree_pos.out.order[j];\n            tsk_tree_remove_edge(self, edge_parent[e], edge_child[e], e);\n        }\n\n        for (j = tree_pos.in.start; j != tree_pos.in.stop; j++) {\n            e = tree_pos.in.order[j];\n            tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n        }\n        ret = TSK_TREE_OK;\n        tsk_tree_update_index_and_interval(self);\n    } else {\n        ret = tsk_tree_clear(self);\n    }\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_prev(tsk_tree_t *self)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t *restrict edge_parent = tables->edges.parent;\n    const tsk_id_t *restrict edge_child = tables->edges.child;\n    tsk_id_t j, e;\n    tsk_tree_position_t tree_pos;\n    bool valid;\n\n    valid = tsk_tree_position_prev(&self->tree_pos);\n    tree_pos = self->tree_pos;\n\n    if (valid) {\n        for (j = tree_pos.out.start; j != tree_pos.out.stop; j--) {\n            e = tree_pos.out.order[j];\n            tsk_tree_remove_edge(self, edge_parent[e], edge_child[e], e);\n        }\n\n        for (j = tree_pos.in.start; j != tree_pos.in.stop; j--) {\n            e = tree_pos.in.order[j];\n            tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n        }\n        ret = TSK_TREE_OK;\n        tsk_tree_update_index_and_interval(self);\n    } else {\n        ret = tsk_tree_clear(self);\n    }\n    return ret;\n}\n\nstatic inline bool\ntsk_tree_position_in_interval(const tsk_tree_t *self, double x)\n{\n    return self->interval.left <= x && x < self->interval.right;\n}\n\nstatic int\ntsk_tree_seek_from_null(tsk_tree_t *self, double x, tsk_flags_t TSK_UNUSED(options))\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t *restrict edge_parent = tables->edges.parent;\n    const tsk_id_t *restrict edge_child = tables->edges.child;\n    const double *restrict edge_left = tables->edges.left;\n    const double *restrict edge_right = tables->edges.right;\n    double interval_left, interval_right;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n    const tsk_size_t num_trees = self->tree_sequence->num_trees;\n    const double L = tsk_treeseq_get_sequence_length(self->tree_sequence);\n    tsk_id_t j, e, index;\n    tsk_tree_position_t tree_pos;\n\n    index = (tsk_id_t) tsk_search_sorted(breakpoints, num_trees + 1, x);\n    if (breakpoints[index] > x) {\n        index--;\n    }\n\n    if (x <= L / 2.0) {\n        ret = tsk_tree_position_seek_forward(&self->tree_pos, index);\n        if (ret != 0) {\n            goto out;\n        }\n        // Since we are seeking from null, there are no edges to remove\n        tree_pos = self->tree_pos;\n        interval_left = tree_pos.interval.left;\n        for (j = tree_pos.in.start; j != tree_pos.in.stop; j++) {\n            e = tree_pos.in.order[j];\n            if (edge_left[e] <= interval_left && interval_left < edge_right[e]) {\n                tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n            }\n        }\n    } else {\n        ret = tsk_tree_position_seek_backward(&self->tree_pos, index);\n        if (ret != 0) {\n            goto out;\n        }\n        tree_pos = self->tree_pos;\n        interval_right = tree_pos.interval.right;\n        for (j = tree_pos.in.start; j != tree_pos.in.stop; j--) {\n            e = tree_pos.in.order[j];\n            if (edge_right[e] >= interval_right && interval_right > edge_left[e]) {\n                tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n            }\n        }\n    }\n    tsk_tree_update_index_and_interval(self);\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_tree_seek_forward(tsk_tree_t *self, tsk_id_t index)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t *restrict edge_parent = tables->edges.parent;\n    const tsk_id_t *restrict edge_child = tables->edges.child;\n    const double *restrict edge_left = tables->edges.left;\n    const double *restrict edge_right = tables->edges.right;\n    double interval_left, e_left;\n    const double old_right = self->interval.right;\n    tsk_id_t j, e;\n    tsk_tree_position_t tree_pos;\n\n    ret = tsk_tree_position_seek_forward(&self->tree_pos, index);\n    if (ret != 0) {\n        goto out;\n    }\n    tree_pos = self->tree_pos;\n    interval_left = tree_pos.interval.left;\n\n    for (j = tree_pos.out.start; j != tree_pos.out.stop; j++) {\n        e = tree_pos.out.order[j];\n        e_left = edge_left[e];\n        if (e_left < old_right) {\n            tsk_bug_assert(edge_parent[e] != TSK_NULL);\n            tsk_tree_remove_edge(self, edge_parent[e], edge_child[e], e);\n        }\n        tsk_bug_assert(e_left < interval_left);\n    }\n\n    for (j = tree_pos.in.start; j != tree_pos.in.stop; j++) {\n        e = tree_pos.in.order[j];\n        if (edge_left[e] <= interval_left && interval_left < edge_right[e]) {\n            tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n        }\n    }\n    tsk_tree_update_index_and_interval(self);\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_tree_seek_backward(tsk_tree_t *self, tsk_id_t index)\n{\n    int ret = 0;\n    tsk_table_collection_t *tables = self->tree_sequence->tables;\n    const tsk_id_t *restrict edge_parent = tables->edges.parent;\n    const tsk_id_t *restrict edge_child = tables->edges.child;\n    const double *restrict edge_left = tables->edges.left;\n    const double *restrict edge_right = tables->edges.right;\n    double interval_right, e_right;\n    const double old_right = self->interval.right;\n    tsk_id_t j, e;\n    tsk_tree_position_t tree_pos;\n\n    ret = tsk_tree_position_seek_backward(&self->tree_pos, index);\n    if (ret != 0) {\n        goto out;\n    }\n    tree_pos = self->tree_pos;\n    interval_right = tree_pos.interval.right;\n\n    for (j = tree_pos.out.start; j != tree_pos.out.stop; j--) {\n        e = tree_pos.out.order[j];\n        e_right = edge_right[e];\n        if (e_right >= old_right) {\n            tsk_bug_assert(edge_parent[e] != TSK_NULL);\n            tsk_tree_remove_edge(self, edge_parent[e], edge_child[e], e);\n        }\n        tsk_bug_assert(e_right > interval_right);\n    }\n\n    for (j = tree_pos.in.start; j != tree_pos.in.stop; j--) {\n        e = tree_pos.in.order[j];\n        if (edge_right[e] >= interval_right && interval_right > edge_left[e]) {\n            tsk_tree_insert_edge(self, edge_parent[e], edge_child[e], e);\n        }\n    }\n    tsk_tree_update_index_and_interval(self);\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_seek_index(tsk_tree_t *self, tsk_id_t tree, tsk_flags_t options)\n{\n    int ret = 0;\n    double x;\n\n    if (tree < 0 || tree >= (tsk_id_t) self->tree_sequence->num_trees) {\n        ret = tsk_trace_error(TSK_ERR_SEEK_OUT_OF_BOUNDS);\n        goto out;\n    }\n    x = self->tree_sequence->breakpoints[tree];\n    ret = tsk_tree_seek(self, x, options);\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_tree_seek_linear(tsk_tree_t *self, double x)\n{\n    const double L = tsk_treeseq_get_sequence_length(self->tree_sequence);\n    const double t_l = self->interval.left;\n    const double t_r = self->interval.right;\n    int ret = 0;\n    double distance_left, distance_right;\n\n    if (x < t_l) {\n        /* |-----|-----|========|---------| */\n        /* 0     x    t_l      t_r        L */\n        distance_left = t_l - x;\n        distance_right = L - t_r + x;\n    } else {\n        /* |------|========|------|-------| */\n        /* 0     t_l      t_r     x       L */\n        distance_right = x - t_r;\n        distance_left = t_l + L - x;\n    }\n    if (distance_right <= distance_left) {\n        while (!tsk_tree_position_in_interval(self, x)) {\n            ret = tsk_tree_next(self);\n            if (ret < 0) {\n                goto out;\n            }\n        }\n    } else {\n        while (!tsk_tree_position_in_interval(self, x)) {\n            ret = tsk_tree_prev(self);\n            if (ret < 0) {\n                goto out;\n            }\n        }\n    }\n    ret = 0;\nout:\n    return ret;\n}\n\nstatic int TSK_WARN_UNUSED\ntsk_tree_seek_skip(tsk_tree_t *self, double x)\n{\n    const double t_l = self->interval.left;\n    int ret = 0;\n    tsk_id_t index;\n    const tsk_size_t num_trees = self->tree_sequence->num_trees;\n    const double *restrict breakpoints = self->tree_sequence->breakpoints;\n\n    index = (tsk_id_t) tsk_search_sorted(breakpoints, num_trees + 1, x);\n    if (breakpoints[index] > x) {\n        index--;\n    }\n\n    if (x < t_l) {\n        ret = tsk_tree_seek_backward(self, index);\n    } else {\n        ret = tsk_tree_seek_forward(self, index);\n    }\n    tsk_bug_assert(tsk_tree_position_in_interval(self, x));\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_seek(tsk_tree_t *self, double x, tsk_flags_t options)\n{\n    int ret = 0;\n    const double L = tsk_treeseq_get_sequence_length(self->tree_sequence);\n\n    if (x < 0 || x >= L) {\n        ret = tsk_trace_error(TSK_ERR_SEEK_OUT_OF_BOUNDS);\n        goto out;\n    }\n\n    if (self->index == -1) {\n        ret = tsk_tree_seek_from_null(self, x, options);\n    } else {\n        if (options & TSK_SEEK_SKIP) {\n            ret = tsk_tree_seek_skip(self, x);\n        } else {\n            ret = tsk_tree_seek_linear(self, x);\n        }\n    }\n\nout:\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_tree_clear(tsk_tree_t *self)\n{\n    int ret = 0;\n    tsk_size_t j;\n    tsk_id_t u;\n    const tsk_size_t N = self->num_nodes + 1;\n    const tsk_size_t num_samples = self->tree_sequence->num_samples;\n    const bool sample_counts = !(self->options & TSK_NO_SAMPLE_COUNTS);\n    const bool sample_lists = !!(self->options & TSK_SAMPLE_LISTS);\n    const tsk_flags_t *flags = self->tree_sequence->tables->nodes.flags;\n\n    self->interval.left = 0;\n    self->interval.right = 0;\n    self->num_edges = 0;\n    self->index = -1;\n    tsk_tree_position_set_null(&self->tree_pos);\n    /* TODO we should profile this method to see if just doing a single loop over\n     * the nodes would be more efficient than multiple memsets.\n     */\n    tsk_memset(self->parent, 0xff, N * sizeof(*self->parent));\n    tsk_memset(self->left_child, 0xff, N * sizeof(*self->left_child));\n    tsk_memset(self->right_child, 0xff, N * sizeof(*self->right_child));\n    tsk_memset(self->left_sib, 0xff, N * sizeof(*self->left_sib));\n    tsk_memset(self->right_sib, 0xff, N * sizeof(*self->right_sib));\n    tsk_memset(self->num_children, 0, N * sizeof(*self->num_children));\n    tsk_memset(self->edge, 0xff, N * sizeof(*self->edge));\n\n    if (sample_counts) {\n        tsk_memset(self->num_samples, 0, N * sizeof(*self->num_samples));\n        /* We can't reset the tracked samples via memset because we don't\n         * know where the tracked samples are.\n         */\n        for (j = 0; j < self->num_nodes; j++) {\n            if (!(flags[j] & TSK_NODE_IS_SAMPLE)) {\n                self->num_tracked_samples[j] = 0;\n            }\n        }\n        /* The total tracked_samples gets set in set_tracked_samples */\n        self->num_samples[self->virtual_root] = num_samples;\n    }\n    if (sample_lists) {\n        tsk_memset(self->left_sample, 0xff, N * sizeof(tsk_id_t));\n        tsk_memset(self->right_sample, 0xff, N * sizeof(tsk_id_t));\n        tsk_memset(self->next_sample, 0xff, num_samples * sizeof(tsk_id_t));\n    }\n    /* Set the sample attributes */\n    for (j = 0; j < num_samples; j++) {\n        u = self->samples[j];\n        if (sample_counts) {\n            self->num_samples[u] = 1;\n        }\n        if (sample_lists) {\n            /* We are mapping to *indexes* into the list of samples here */\n            self->left_sample[u] = (tsk_id_t) j;\n            self->right_sample[u] = (tsk_id_t) j;\n        }\n    }\n    if (sample_counts && self->root_threshold == 1 && num_samples > 0) {\n        for (j = 0; j < num_samples; j++) {\n            /* Set initial roots */\n            if (self->root_threshold == 1) {\n                tsk_tree_insert_root(self, self->samples[j], self->parent);\n            }\n        }\n    }\n    return ret;\n}\n\ntsk_size_t\ntsk_tree_get_size_bound(const tsk_tree_t *self)\n{\n    tsk_size_t bound = 0;\n\n    if (self->tree_sequence != NULL) {\n        /* This is a safe upper bound which can be computed cheaply.\n         * We have at most n roots and each edge adds at most one new\n         * node to the tree. We also allow space for the virtual root,\n         * to simplify client code.\n         *\n         * In the common case of a binary tree with a single root, we have\n         * 2n - 1 nodes in total, and 2n - 2 edges. Therefore, we return\n         * 3n - 1, which is an over-estimate of 1/2 and we allocate\n         * 1.5 times as much memory as we need.\n         *\n         * Since tracking the exact number of nodes in the tree would require\n         * storing the number of nodes beneath every node and complicate\n         * the tree transition method, this seems like a good compromise\n         * and will result in less memory usage overall in nearly all cases.\n         */\n        bound = 1 + self->tree_sequence->num_samples + self->num_edges;\n    }\n    return bound;\n}\n\n/* Traversal orders */\nstatic tsk_id_t *\ntsk_tree_alloc_node_stack(const tsk_tree_t *self)\n{\n    return tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(tsk_id_t));\n}\n\nint\ntsk_tree_preorder(const tsk_tree_t *self, tsk_id_t *nodes, tsk_size_t *num_nodes_ret)\n{\n    return tsk_tree_preorder_from(self, -1, nodes, num_nodes_ret);\n}\n\nint\ntsk_tree_preorder_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes_ret)\n{\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    tsk_id_t *stack = tsk_tree_alloc_node_stack(self);\n    tsk_size_t num_nodes = 0;\n    tsk_id_t u, v;\n    int stack_top;\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    if ((root == -1 || root == self->virtual_root)\n        && !tsk_tree_has_sample_counts(self)) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n        goto out;\n    }\n    if (root == -1) {\n        stack_top = -1;\n        for (u = right_child[self->virtual_root]; u != TSK_NULL; u = left_sib[u]) {\n            stack_top++;\n            stack[stack_top] = u;\n        }\n    } else {\n        ret = tsk_tree_check_node(self, root);\n        if (ret != 0) {\n            goto out;\n        }\n        stack_top = 0;\n        stack[stack_top] = root;\n    }\n\n    while (stack_top >= 0) {\n        u = stack[stack_top];\n        stack_top--;\n        nodes[num_nodes] = u;\n        num_nodes++;\n        for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n            stack_top++;\n            stack[stack_top] = v;\n        }\n    }\n    *num_nodes_ret = num_nodes;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\n/* We could implement this using the preorder function, but since it's\n * going to be performance critical we want to avoid the overhead\n * of mallocing the intermediate node list (which will be bigger than\n * the number of samples). */\nint\ntsk_tree_preorder_samples_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes_ret)\n{\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    const tsk_flags_t *restrict flags = self->tree_sequence->tables->nodes.flags;\n    tsk_id_t *stack = tsk_tree_alloc_node_stack(self);\n    tsk_size_t num_nodes = 0;\n    tsk_id_t u, v;\n    int stack_top;\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    /* We could push the virtual_root onto the stack directly to simplify\n     * the code a little, but then we'd have to check put an extra check\n     * when looking up the flags array (which isn't defined for virtual_root).\n     */\n    if (root == -1 || root == self->virtual_root) {\n        if (!tsk_tree_has_sample_counts(self)) {\n            ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n            goto out;\n        }\n        stack_top = -1;\n        for (u = right_child[self->virtual_root]; u != TSK_NULL; u = left_sib[u]) {\n            stack_top++;\n            stack[stack_top] = u;\n        }\n    } else {\n        ret = tsk_tree_check_node(self, root);\n        if (ret != 0) {\n            goto out;\n        }\n        stack_top = 0;\n        stack[stack_top] = root;\n    }\n\n    while (stack_top >= 0) {\n        u = stack[stack_top];\n        stack_top--;\n        if (flags[u] & TSK_NODE_IS_SAMPLE) {\n            nodes[num_nodes] = u;\n            num_nodes++;\n        }\n        for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n            stack_top++;\n            stack[stack_top] = v;\n        }\n    }\n    *num_nodes_ret = num_nodes;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\nint\ntsk_tree_postorder(const tsk_tree_t *self, tsk_id_t *nodes, tsk_size_t *num_nodes_ret)\n{\n    return tsk_tree_postorder_from(self, -1, nodes, num_nodes_ret);\n}\nint\ntsk_tree_postorder_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes_ret)\n{\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    const tsk_id_t *restrict parent = self->parent;\n    tsk_id_t *stack = tsk_tree_alloc_node_stack(self);\n    tsk_size_t num_nodes = 0;\n    tsk_id_t u, v, postorder_parent;\n    int stack_top;\n    bool is_virtual_root = root == self->virtual_root;\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    if (root == -1 || is_virtual_root) {\n        if (!tsk_tree_has_sample_counts(self)) {\n            ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_OPERATION);\n            goto out;\n        }\n        stack_top = -1;\n        for (u = right_child[self->virtual_root]; u != TSK_NULL; u = left_sib[u]) {\n            stack_top++;\n            stack[stack_top] = u;\n        }\n    } else {\n        ret = tsk_tree_check_node(self, root);\n        if (ret != 0) {\n            goto out;\n        }\n        stack_top = 0;\n        stack[stack_top] = root;\n    }\n\n    postorder_parent = TSK_NULL;\n    while (stack_top >= 0) {\n        u = stack[stack_top];\n        if (right_child[u] != TSK_NULL && u != postorder_parent) {\n            for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n                stack_top++;\n                stack[stack_top] = v;\n            }\n        } else {\n            stack_top--;\n            postorder_parent = parent[u];\n            nodes[num_nodes] = u;\n            num_nodes++;\n        }\n    }\n    if (is_virtual_root) {\n        nodes[num_nodes] = root;\n        num_nodes++;\n    }\n    *num_nodes_ret = num_nodes;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\n/* Balance/imbalance metrics */\n\n/* Result is a tsk_size_t value here because we could imagine the total\n * depth overflowing a 32bit integer for a large tree. */\nint\ntsk_tree_sackin_index(const tsk_tree_t *self, tsk_size_t *result)\n{\n    /* Keep the size of the stack elements to 8 bytes in total in the\n     * standard case. A tsk_id_t depth value is always safe, since\n     * depth counts the number of nodes encountered on a path.\n     */\n    struct stack_elem {\n        tsk_id_t node;\n        tsk_id_t depth;\n    };\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    struct stack_elem *stack\n        = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*stack));\n    int stack_top;\n    tsk_size_t total_depth;\n    tsk_id_t u;\n    struct stack_elem s = { .node = TSK_NULL, .depth = 0 };\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    stack_top = -1;\n    for (u = right_child[self->virtual_root]; u != TSK_NULL; u = left_sib[u]) {\n        stack_top++;\n        s.node = u;\n        stack[stack_top] = s;\n    }\n    total_depth = 0;\n    while (stack_top >= 0) {\n        s = stack[stack_top];\n        stack_top--;\n        u = right_child[s.node];\n        if (u == TSK_NULL) {\n            total_depth += (tsk_size_t) s.depth;\n        } else {\n            s.depth++;\n            while (u != TSK_NULL) {\n                stack_top++;\n                s.node = u;\n                stack[stack_top] = s;\n                u = left_sib[u];\n            }\n        }\n    }\n    *result = total_depth;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\nint\ntsk_tree_colless_index(const tsk_tree_t *self, tsk_size_t *result)\n{\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    tsk_id_t *num_leaves = tsk_calloc(self->num_nodes, sizeof(*num_leaves));\n    tsk_size_t j, num_nodes, total;\n    tsk_id_t num_children, u, v;\n\n    if (nodes == NULL || num_leaves == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (tsk_tree_get_num_roots(self) != 1) {\n        ret = tsk_trace_error(TSK_ERR_UNDEFINED_MULTIROOT);\n        goto out;\n    }\n    ret = tsk_tree_postorder(self, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n\n    total = 0;\n    for (j = 0; j < num_nodes; j++) {\n        u = nodes[j];\n        /* Cheaper to compute this on the fly than to access the num_children array.\n         * since we're already iterating over the children. */\n        num_children = 0;\n        for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n            num_children++;\n            num_leaves[u] += num_leaves[v];\n        }\n        if (num_children == 0) {\n            num_leaves[u] = 1;\n        } else if (num_children == 2) {\n            v = right_child[u];\n            total += (tsk_size_t) llabs(num_leaves[v] - num_leaves[left_sib[v]]);\n        } else {\n            ret = tsk_trace_error(TSK_ERR_UNDEFINED_NONBINARY);\n            goto out;\n        }\n    }\n    *result = total;\nout:\n    tsk_safe_free(nodes);\n    tsk_safe_free(num_leaves);\n    return ret;\n}\n\nint\ntsk_tree_b1_index(const tsk_tree_t *self, double *result)\n{\n    int ret = 0;\n    const tsk_id_t *restrict parent = self->parent;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    tsk_size_t *max_path_length = tsk_calloc(self->num_nodes, sizeof(*max_path_length));\n    tsk_size_t j, num_nodes, mpl;\n    double total = 0.0;\n    tsk_id_t u, v;\n\n    if (nodes == NULL || max_path_length == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = tsk_tree_postorder(self, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (j = 0; j < num_nodes; j++) {\n        u = nodes[j];\n        if (parent[u] != TSK_NULL && right_child[u] != TSK_NULL) {\n            mpl = 0;\n            for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n                mpl = TSK_MAX(mpl, max_path_length[v]);\n            }\n            max_path_length[u] = mpl + 1;\n            total += 1 / (double) max_path_length[u];\n        }\n    }\n    *result = total;\nout:\n    tsk_safe_free(nodes);\n    tsk_safe_free(max_path_length);\n    return ret;\n}\n\nstatic double\ngeneral_log(double x, double base)\n{\n    return log(x) / log(base);\n}\n\nint\ntsk_tree_b2_index(const tsk_tree_t *self, double base, double *result)\n{\n    struct stack_elem {\n        tsk_id_t node;\n        double path_product;\n    };\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    struct stack_elem *stack\n        = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*stack));\n    int stack_top;\n    double total_proba = 0;\n    double num_children;\n    tsk_id_t u;\n    struct stack_elem s = { .node = TSK_NULL, .path_product = 1 };\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (tsk_tree_get_num_roots(self) != 1) {\n        ret = tsk_trace_error(TSK_ERR_UNDEFINED_MULTIROOT);\n        goto out;\n    }\n\n    stack_top = 0;\n    s.node = tsk_tree_get_left_root(self);\n    stack[stack_top] = s;\n\n    while (stack_top >= 0) {\n        s = stack[stack_top];\n        stack_top--;\n        u = right_child[s.node];\n        if (u == TSK_NULL) {\n            total_proba -= s.path_product * general_log(s.path_product, base);\n        } else {\n            num_children = 0;\n            for (; u != TSK_NULL; u = left_sib[u]) {\n                num_children++;\n            }\n            s.path_product *= 1 / num_children;\n            for (u = right_child[s.node]; u != TSK_NULL; u = left_sib[u]) {\n                stack_top++;\n                s.node = u;\n                stack[stack_top] = s;\n            }\n        }\n    }\n    *result = total_proba;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\nint\ntsk_tree_num_lineages(const tsk_tree_t *self, double t, tsk_size_t *result)\n{\n    int ret = 0;\n    const tsk_id_t *restrict right_child = self->right_child;\n    const tsk_id_t *restrict left_sib = self->left_sib;\n    const double *restrict time = self->tree_sequence->tables->nodes.time;\n    tsk_id_t *stack = tsk_tree_alloc_node_stack(self);\n    tsk_size_t num_lineages = 0;\n    int stack_top;\n    tsk_id_t u, v;\n    double child_time, parent_time;\n\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (!tsk_isfinite(t)) {\n        ret = tsk_trace_error(TSK_ERR_TIME_NONFINITE);\n        goto out;\n    }\n    /* Push the roots onto the stack */\n    stack_top = -1;\n    for (u = right_child[self->virtual_root]; u != TSK_NULL; u = left_sib[u]) {\n        stack_top++;\n        stack[stack_top] = u;\n    }\n\n    while (stack_top >= 0) {\n        u = stack[stack_top];\n        parent_time = time[u];\n        stack_top--;\n        for (v = right_child[u]; v != TSK_NULL; v = left_sib[v]) {\n            child_time = time[v];\n            /* Only traverse down the tree as far as we need to */\n            if (child_time > t) {\n                stack_top++;\n                stack[stack_top] = v;\n            } else if (t < parent_time) {\n                num_lineages++;\n            }\n        }\n    }\n    *result = num_lineages;\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\n/* Parsimony methods */\n\nstatic inline uint64_t\nset_bit(uint64_t value, int32_t bit)\n{\n    return value | (1ULL << bit);\n}\n\nstatic inline bool\nbit_is_set(uint64_t value, int32_t bit)\n{\n    return (value & (1ULL << bit)) != 0;\n}\n\nstatic inline int8_t\nget_smallest_set_bit(uint64_t v)\n{\n    /* This is an inefficient implementation, there are several better\n     * approaches. On GCC we can use\n     * return (uint8_t) (__builtin_ffsll((long long) v) - 1);\n     */\n    uint64_t t = 1;\n    int8_t r = 0;\n\n    assert(v != 0);\n    while ((v & t) == 0) {\n        t <<= 1;\n        r++;\n    }\n    return r;\n}\n\n#define HARTIGAN_MAX_ALLELES 64\n\n/* This interface is experimental. In the future, we should provide the option to\n * use a general cost matrix, in which case we'll use the Sankoff algorithm. For\n * now this is unused.\n *\n * We should also vectorise the function so that several sites can be processed\n * at once.\n *\n * The algorithm used here is Hartigan parsimony, \"Minimum Mutation Fits to a\n * Given Tree\", Biometrics 1973.\n */\nint TSK_WARN_UNUSED\ntsk_tree_map_mutations(tsk_tree_t *self, int32_t *genotypes,\n    double *TSK_UNUSED(cost_matrix), tsk_flags_t options, int32_t *r_ancestral_state,\n    tsk_size_t *r_num_transitions, tsk_state_transition_t **r_transitions)\n{\n    int ret = 0;\n    struct stack_elem {\n        tsk_id_t node;\n        tsk_id_t transition_parent;\n        int32_t state;\n    };\n    const tsk_size_t num_samples = self->tree_sequence->num_samples;\n    const tsk_id_t *restrict left_child = self->left_child;\n    const tsk_id_t *restrict right_sib = self->right_sib;\n    const tsk_size_t N = tsk_treeseq_get_num_nodes(self->tree_sequence);\n    const tsk_flags_t *restrict node_flags = self->tree_sequence->tables->nodes.flags;\n    tsk_id_t *nodes = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*nodes));\n    /* Note: to use less memory here and to improve cache performance we should\n     * probably change to allocating exactly the number of nodes returned by\n     * a preorder traversal, and then lay the memory out in this order. So, we'd\n     * need a map from node ID to its index in the preorder traversal, but this\n     * is trivial to compute. Probably doesn't matter so much at the moment\n     * when we're doing a single site, but it would make a big difference if\n     * we were vectorising over lots of sites. */\n    uint64_t *restrict optimal_set = tsk_calloc(N + 1, sizeof(*optimal_set));\n    struct stack_elem *restrict preorder_stack\n        = tsk_malloc(tsk_tree_get_size_bound(self) * sizeof(*preorder_stack));\n    tsk_id_t u, v;\n    /* The largest possible number of transitions is one over every sample */\n    tsk_state_transition_t *transitions = tsk_malloc(num_samples * sizeof(*transitions));\n    int32_t allele, ancestral_state;\n    int stack_top;\n    struct stack_elem s;\n    tsk_size_t j, num_transitions, max_allele_count, num_nodes;\n    tsk_size_t allele_count[HARTIGAN_MAX_ALLELES];\n    tsk_size_t non_missing = 0;\n    int32_t num_alleles = 0;\n\n    if (optimal_set == NULL || preorder_stack == NULL || transitions == NULL\n        || nodes == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (j = 0; j < num_samples; j++) {\n        if (genotypes[j] >= HARTIGAN_MAX_ALLELES || genotypes[j] < TSK_MISSING_DATA) {\n            ret = tsk_trace_error(TSK_ERR_BAD_GENOTYPE);\n            goto out;\n        }\n        u = self->tree_sequence->samples[j];\n        if (genotypes[j] == TSK_MISSING_DATA) {\n            /* All bits set */\n            optimal_set[u] = UINT64_MAX;\n        } else {\n            optimal_set[u] = set_bit(optimal_set[u], genotypes[j]);\n            num_alleles = TSK_MAX(genotypes[j], num_alleles);\n            non_missing++;\n        }\n    }\n\n    if (non_missing == 0) {\n        ret = tsk_trace_error(TSK_ERR_GENOTYPES_ALL_MISSING);\n        goto out;\n    }\n    num_alleles++;\n\n    ancestral_state = 0; /* keep compiler happy */\n    if (options & TSK_MM_FIXED_ANCESTRAL_STATE) {\n        ancestral_state = *r_ancestral_state;\n        if ((ancestral_state < 0) || (ancestral_state >= HARTIGAN_MAX_ALLELES)) {\n            ret = tsk_trace_error(TSK_ERR_BAD_ANCESTRAL_STATE);\n            goto out;\n        } else if (ancestral_state >= num_alleles) {\n            num_alleles = (int32_t)(ancestral_state + 1);\n        }\n    }\n\n    ret = tsk_tree_postorder_from(self, self->virtual_root, nodes, &num_nodes);\n    if (ret != 0) {\n        goto out;\n    }\n    for (j = 0; j < num_nodes; j++) {\n        u = nodes[j];\n        tsk_memset(allele_count, 0, ((size_t) num_alleles) * sizeof(*allele_count));\n        for (v = left_child[u]; v != TSK_NULL; v = right_sib[v]) {\n            for (allele = 0; allele < num_alleles; allele++) {\n                allele_count[allele] += bit_is_set(optimal_set[v], allele);\n            }\n        }\n        /* the virtual root has no flags defined */\n        if (u == (tsk_id_t) N || !(node_flags[u] & TSK_NODE_IS_SAMPLE)) {\n            max_allele_count = 0;\n            for (allele = 0; allele < num_alleles; allele++) {\n                max_allele_count = TSK_MAX(max_allele_count, allele_count[allele]);\n            }\n            for (allele = 0; allele < num_alleles; allele++) {\n                if (allele_count[allele] == max_allele_count) {\n                    optimal_set[u] = set_bit(optimal_set[u], allele);\n                }\n            }\n        }\n    }\n    if (!(options & TSK_MM_FIXED_ANCESTRAL_STATE)) {\n        ancestral_state = get_smallest_set_bit(optimal_set[self->virtual_root]);\n    } else {\n        optimal_set[self->virtual_root] = UINT64_MAX;\n    }\n\n    num_transitions = 0;\n\n    /* Do a preorder traversal */\n    preorder_stack[0].node = self->virtual_root;\n    preorder_stack[0].state = ancestral_state;\n    preorder_stack[0].transition_parent = TSK_NULL;\n    stack_top = 0;\n    while (stack_top >= 0) {\n        s = preorder_stack[stack_top];\n        stack_top--;\n\n        if (!bit_is_set(optimal_set[s.node], s.state)) {\n            s.state = get_smallest_set_bit(optimal_set[s.node]);\n            transitions[num_transitions].node = s.node;\n            transitions[num_transitions].parent = s.transition_parent;\n            transitions[num_transitions].state = s.state;\n            s.transition_parent = (tsk_id_t) num_transitions;\n            num_transitions++;\n        }\n        for (v = left_child[s.node]; v != TSK_NULL; v = right_sib[v]) {\n            stack_top++;\n            s.node = v;\n            preorder_stack[stack_top] = s;\n        }\n    }\n\n    *r_transitions = transitions;\n    *r_num_transitions = num_transitions;\n    *r_ancestral_state = ancestral_state;\n    transitions = NULL;\nout:\n    tsk_safe_free(transitions);\n    /* Cannot safe_free because of 'restrict' */\n    if (optimal_set != NULL) {\n        free(optimal_set);\n    }\n    if (preorder_stack != NULL) {\n        free(preorder_stack);\n    }\n    if (nodes != NULL) {\n        free(nodes);\n    }\n    return ret;\n}\n\n/* ======================================================== *\n * KC Distance\n * ======================================================== */\n\ntypedef struct {\n    tsk_size_t *m;\n    double *M;\n    tsk_id_t n;\n    tsk_id_t N;\n} kc_vectors;\n\nstatic int\nkc_vectors_alloc(kc_vectors *self, tsk_id_t n)\n{\n    int ret = 0;\n\n    self->n = n;\n    self->N = (n * (n - 1)) / 2;\n    self->m = tsk_calloc((size_t)(self->N + self->n), sizeof(*self->m));\n    self->M = tsk_calloc((size_t)(self->N + self->n), sizeof(*self->M));\n    if (self->m == NULL || self->M == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\nout:\n    return ret;\n}\n\nstatic void\nkc_vectors_free(kc_vectors *self)\n{\n    tsk_safe_free(self->m);\n    tsk_safe_free(self->M);\n}\n\nstatic inline void\nupdate_kc_vectors_single_sample(\n    const tsk_treeseq_t *ts, kc_vectors *kc_vecs, tsk_id_t u, double time)\n{\n    const tsk_id_t *sample_index_map = ts->sample_index_map;\n    tsk_id_t u_index = sample_index_map[u];\n\n    kc_vecs->m[kc_vecs->N + u_index] = 1;\n    kc_vecs->M[kc_vecs->N + u_index] = time;\n}\n\nstatic inline void\nupdate_kc_vectors_all_pairs(const tsk_tree_t *tree, kc_vectors *kc_vecs, tsk_id_t u,\n    tsk_id_t v, tsk_size_t depth, double time)\n{\n    tsk_id_t sample1_index, sample2_index, n1, n2, tmp, pair_index;\n    const tsk_id_t *restrict left_sample = tree->left_sample;\n    const tsk_id_t *restrict right_sample = tree->right_sample;\n    const tsk_id_t *restrict next_sample = tree->next_sample;\n    tsk_size_t *restrict kc_m = kc_vecs->m;\n    double *restrict kc_M = kc_vecs->M;\n\n    sample1_index = left_sample[u];\n    while (sample1_index != TSK_NULL) {\n        sample2_index = left_sample[v];\n        while (sample2_index != TSK_NULL) {\n            n1 = sample1_index;\n            n2 = sample2_index;\n            if (n1 > n2) {\n                tmp = n1;\n                n1 = n2;\n                n2 = tmp;\n            }\n\n            /* We spend ~40% of our time here because these accesses\n             * are not in order and gets very poor cache behavior */\n            pair_index = n2 - n1 - 1 + (-1 * n1 * (n1 - 2 * kc_vecs->n + 1)) / 2;\n            kc_m[pair_index] = depth;\n            kc_M[pair_index] = time;\n\n            if (sample2_index == right_sample[v]) {\n                break;\n            }\n            sample2_index = next_sample[sample2_index];\n        }\n        if (sample1_index == right_sample[u]) {\n            break;\n        }\n        sample1_index = next_sample[sample1_index];\n    }\n}\n\nstruct kc_stack_elmt {\n    tsk_id_t node;\n    tsk_size_t depth;\n};\n\nstatic int\nfill_kc_vectors(const tsk_tree_t *t, kc_vectors *kc_vecs)\n{\n    int stack_top;\n    tsk_size_t depth;\n    double time;\n    const double *times;\n    struct kc_stack_elmt *stack;\n    tsk_id_t root, u, c1, c2;\n    int ret = 0;\n    const tsk_treeseq_t *ts = t->tree_sequence;\n\n    stack = tsk_malloc(tsk_tree_get_size_bound(t) * sizeof(*stack));\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    times = t->tree_sequence->tables->nodes.time;\n\n    for (root = tsk_tree_get_left_root(t); root != TSK_NULL; root = t->right_sib[root]) {\n        stack_top = 0;\n        stack[stack_top].node = root;\n        stack[stack_top].depth = 0;\n        while (stack_top >= 0) {\n            u = stack[stack_top].node;\n            depth = stack[stack_top].depth;\n            stack_top--;\n\n            if (tsk_tree_is_sample(t, u)) {\n                time = tsk_tree_get_branch_length_unsafe(t, u);\n                update_kc_vectors_single_sample(ts, kc_vecs, u, time);\n            }\n\n            /* Don't bother going deeper if there are no samples under this node */\n            if (t->left_sample[u] != TSK_NULL) {\n                for (c1 = t->left_child[u]; c1 != TSK_NULL; c1 = t->right_sib[c1]) {\n                    stack_top++;\n                    stack[stack_top].node = c1;\n                    stack[stack_top].depth = depth + 1;\n\n                    for (c2 = t->right_sib[c1]; c2 != TSK_NULL; c2 = t->right_sib[c2]) {\n                        time = times[root] - times[u];\n                        update_kc_vectors_all_pairs(t, kc_vecs, c1, c2, depth, time);\n                    }\n                }\n            }\n        }\n    }\n\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\nstatic double\nnorm_kc_vectors(kc_vectors *self, kc_vectors *other, double lambda)\n{\n    double vT1, vT2, distance_sum;\n    tsk_id_t i;\n\n    distance_sum = 0;\n    for (i = 0; i < self->n + self->N; i++) {\n        vT1 = ((double) self->m[i] * (1 - lambda)) + (lambda * self->M[i]);\n        vT2 = ((double) other->m[i] * (1 - lambda)) + (lambda * other->M[i]);\n        distance_sum += (vT1 - vT2) * (vT1 - vT2);\n    }\n\n    return sqrt(distance_sum);\n}\n\nstatic int\ncheck_kc_distance_tree_inputs(const tsk_tree_t *self)\n{\n    tsk_id_t u, num_nodes, left_child;\n    int ret = 0;\n\n    if (tsk_tree_get_num_roots(self) != 1) {\n        ret = tsk_trace_error(TSK_ERR_MULTIPLE_ROOTS);\n        goto out;\n    }\n    if (!tsk_tree_has_sample_lists(self)) {\n        ret = tsk_trace_error(TSK_ERR_NO_SAMPLE_LISTS);\n        goto out;\n    }\n\n    num_nodes = (tsk_id_t) tsk_treeseq_get_num_nodes(self->tree_sequence);\n    for (u = 0; u < num_nodes; u++) {\n        left_child = self->left_child[u];\n        if (left_child != TSK_NULL && left_child == self->right_child[u]) {\n            ret = tsk_trace_error(TSK_ERR_UNARY_NODES);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nstatic int\ncheck_kc_distance_samples_inputs(const tsk_treeseq_t *self, const tsk_treeseq_t *other)\n{\n    const tsk_id_t *samples, *other_samples;\n    tsk_id_t i, n;\n    int ret = 0;\n\n    if (self->num_samples != other->num_samples) {\n        ret = tsk_trace_error(TSK_ERR_SAMPLE_SIZE_MISMATCH);\n        goto out;\n    }\n\n    samples = self->samples;\n    other_samples = other->samples;\n    n = (tsk_id_t) self->num_samples;\n    for (i = 0; i < n; i++) {\n        if (samples[i] != other_samples[i]) {\n            ret = tsk_trace_error(TSK_ERR_SAMPLES_NOT_EQUAL);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_tree_kc_distance(\n    const tsk_tree_t *self, const tsk_tree_t *other, double lambda, double *result)\n{\n    tsk_id_t n, i;\n    kc_vectors vecs[2];\n    const tsk_tree_t *trees[2] = { self, other };\n    int ret = 0;\n\n    for (i = 0; i < 2; i++) {\n        tsk_memset(&vecs[i], 0, sizeof(kc_vectors));\n    }\n\n    ret = check_kc_distance_samples_inputs(self->tree_sequence, other->tree_sequence);\n    if (ret != 0) {\n        goto out;\n    }\n    for (i = 0; i < 2; i++) {\n        ret = check_kc_distance_tree_inputs(trees[i]);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    n = (tsk_id_t) self->tree_sequence->num_samples;\n    for (i = 0; i < 2; i++) {\n        ret = kc_vectors_alloc(&vecs[i], n);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = fill_kc_vectors(trees[i], &vecs[i]);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    *result = norm_kc_vectors(&vecs[0], &vecs[1], lambda);\nout:\n    for (i = 0; i < 2; i++) {\n        kc_vectors_free(&vecs[i]);\n    }\n    return ret;\n}\n\nstatic int\ncheck_kc_distance_tree_sequence_inputs(\n    const tsk_treeseq_t *self, const tsk_treeseq_t *other)\n{\n    int ret = 0;\n\n    if (self->tables->sequence_length != other->tables->sequence_length) {\n        ret = tsk_trace_error(TSK_ERR_SEQUENCE_LENGTH_MISMATCH);\n        goto out;\n    }\n\n    ret = check_kc_distance_samples_inputs(self, other);\n    if (ret != 0) {\n        goto out;\n    }\n\nout:\n    return ret;\n}\n\nstatic void\nupdate_kc_pair_with_sample(const tsk_tree_t *self, kc_vectors *kc, tsk_id_t sample,\n    tsk_size_t *depths, double root_time)\n{\n    tsk_id_t c, p, sib;\n    double time;\n    tsk_size_t depth;\n    double *times = self->tree_sequence->tables->nodes.time;\n\n    c = sample;\n    for (p = self->parent[sample]; p != TSK_NULL; p = self->parent[p]) {\n        time = root_time - times[p];\n        depth = depths[p];\n        for (sib = self->left_child[p]; sib != TSK_NULL; sib = self->right_sib[sib]) {\n            if (sib != c) {\n                update_kc_vectors_all_pairs(self, kc, sample, sib, depth, time);\n            }\n        }\n        c = p;\n    }\n}\n\nstatic int\nupdate_kc_subtree_state(\n    tsk_tree_t *t, kc_vectors *kc, tsk_id_t u, tsk_size_t *depths, double root_time)\n{\n    int stack_top;\n    tsk_id_t v, c;\n    tsk_id_t *stack = NULL;\n    int ret = 0;\n\n    stack = tsk_malloc(tsk_tree_get_size_bound(t) * sizeof(*stack));\n    if (stack == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    stack_top = 0;\n    stack[stack_top] = u;\n    while (stack_top >= 0) {\n        v = stack[stack_top];\n        stack_top--;\n\n        if (tsk_tree_is_sample(t, v)) {\n            update_kc_pair_with_sample(t, kc, v, depths, root_time);\n        }\n        for (c = t->left_child[v]; c != TSK_NULL; c = t->right_sib[c]) {\n            if (depths[c] != 0) {\n                depths[c] = depths[v] + 1;\n                stack_top++;\n                stack[stack_top] = c;\n            }\n        }\n    }\n\nout:\n    tsk_safe_free(stack);\n    return ret;\n}\n\nstatic int\nupdate_kc_incremental(tsk_tree_t *tree, kc_vectors *kc, tsk_size_t *depths)\n{\n    int ret = 0;\n    tsk_id_t u, v, e, j;\n    double root_time, time;\n    const double *restrict times = tree->tree_sequence->tables->nodes.time;\n    const tsk_id_t *restrict edges_child = tree->tree_sequence->tables->edges.child;\n    const tsk_id_t *restrict edges_parent = tree->tree_sequence->tables->edges.parent;\n    tsk_tree_position_t tree_pos = tree->tree_pos;\n\n    /* Update state of detached subtrees */\n    for (j = tree_pos.out.stop - 1; j >= tree_pos.out.start; j--) {\n        e = tree_pos.out.order[j];\n        u = edges_child[e];\n        depths[u] = 0;\n\n        if (tree->parent[u] == TSK_NULL) {\n            root_time = times[tsk_tree_node_root(tree, u)];\n            ret = update_kc_subtree_state(tree, kc, u, depths, root_time);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n    }\n\n    /* Propagate state change down into reattached subtrees. */\n    for (j = tree_pos.in.stop - 1; j >= tree_pos.in.start; j--) {\n        e = tree_pos.in.order[j];\n        u = edges_child[e];\n        v = edges_parent[e];\n\n        tsk_bug_assert(depths[u] == 0);\n        depths[u] = depths[v] + 1;\n\n        root_time = times[tsk_tree_node_root(tree, u)];\n        ret = update_kc_subtree_state(tree, kc, u, depths, root_time);\n        if (ret != 0) {\n            goto out;\n        }\n\n        if (tsk_tree_is_sample(tree, u)) {\n            time = tsk_tree_get_branch_length_unsafe(tree, u);\n            update_kc_vectors_single_sample(tree->tree_sequence, kc, u, time);\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_treeseq_kc_distance(const tsk_treeseq_t *self, const tsk_treeseq_t *other,\n    double lambda_, double *result)\n{\n    int i;\n    tsk_id_t n;\n    tsk_size_t num_nodes;\n    double left, span, total;\n    const tsk_treeseq_t *treeseqs[2] = { self, other };\n    tsk_tree_t trees[2];\n    kc_vectors kcs[2];\n    tsk_size_t *depths[2];\n    int ret = 0;\n\n    for (i = 0; i < 2; i++) {\n        tsk_memset(&trees[i], 0, sizeof(trees[i]));\n        tsk_memset(&kcs[i], 0, sizeof(kcs[i]));\n        depths[i] = NULL;\n    }\n\n    ret = check_kc_distance_tree_sequence_inputs(self, other);\n    if (ret != 0) {\n        goto out;\n    }\n\n    n = (tsk_id_t) self->num_samples;\n    for (i = 0; i < 2; i++) {\n        ret = tsk_tree_init(&trees[i], treeseqs[i], TSK_SAMPLE_LISTS);\n        if (ret != 0) {\n            goto out;\n        }\n        ret = kc_vectors_alloc(&kcs[i], n);\n        if (ret != 0) {\n            goto out;\n        }\n        num_nodes = tsk_treeseq_get_num_nodes(treeseqs[i]);\n        depths[i] = tsk_calloc(num_nodes, sizeof(*depths[i]));\n        if (depths[i] == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n    }\n\n    total = 0;\n    left = 0;\n\n    ret = tsk_tree_first(&trees[0]);\n    if (ret != TSK_TREE_OK) {\n        goto out;\n    }\n    ret = check_kc_distance_tree_inputs(&trees[0]);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = update_kc_incremental(&trees[0], &kcs[0], depths[0]);\n    if (ret != 0) {\n        goto out;\n    }\n    while ((ret = tsk_tree_next(&trees[1])) == TSK_TREE_OK) {\n        ret = check_kc_distance_tree_inputs(&trees[1]);\n        if (ret != 0) {\n            goto out;\n        }\n\n        ret = update_kc_incremental(&trees[1], &kcs[1], depths[1]);\n        if (ret != 0) {\n            goto out;\n        }\n        while (trees[0].interval.right < trees[1].interval.right) {\n            span = trees[0].interval.right - left;\n            total += norm_kc_vectors(&kcs[0], &kcs[1], lambda_) * span;\n\n            left = trees[0].interval.right;\n            ret = tsk_tree_next(&trees[0]);\n            tsk_bug_assert(ret == TSK_TREE_OK);\n            ret = check_kc_distance_tree_inputs(&trees[0]);\n            if (ret != 0) {\n                goto out;\n            }\n            ret = update_kc_incremental(&trees[0], &kcs[0], depths[0]);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n        span = trees[1].interval.right - left;\n        left = trees[1].interval.right;\n        total += norm_kc_vectors(&kcs[0], &kcs[1], lambda_) * span;\n    }\n    if (ret != 0) {\n        goto out;\n    }\n\n    *result = total / self->tables->sequence_length;\nout:\n    for (i = 0; i < 2; i++) {\n        tsk_tree_free(&trees[i]);\n        kc_vectors_free(&kcs[i]);\n        tsk_safe_free(depths[i]);\n    }\n    return ret;\n}\n\n/*\n * Divergence matrix\n */\n\ntypedef struct {\n    /* Note it's a waste storing the triply linked tree here, but the code\n     * is written on the assumption of 1-based trees and the algorithm is\n     * frighteningly subtle, so it doesn't seem worth messing with it\n     * unless we really need to save some memory */\n    tsk_id_t *parent;\n    tsk_id_t *child;\n    tsk_id_t *sib;\n    tsk_id_t *lambda;\n    tsk_id_t *pi;\n    tsk_id_t *tau;\n    tsk_id_t *beta;\n    tsk_id_t *alpha;\n} sv_tables_t;\n\nstatic int\nsv_tables_init(sv_tables_t *self, tsk_size_t n)\n{\n    int ret = 0;\n\n    self->parent = tsk_malloc(n * sizeof(*self->parent));\n    self->child = tsk_malloc(n * sizeof(*self->child));\n    self->sib = tsk_malloc(n * sizeof(*self->sib));\n    self->pi = tsk_malloc(n * sizeof(*self->pi));\n    self->lambda = tsk_malloc(n * sizeof(*self->lambda));\n    self->tau = tsk_malloc(n * sizeof(*self->tau));\n    self->beta = tsk_malloc(n * sizeof(*self->beta));\n    self->alpha = tsk_malloc(n * sizeof(*self->alpha));\n    if (self->parent == NULL || self->child == NULL || self->sib == NULL\n        || self->lambda == NULL || self->tau == NULL || self->beta == NULL\n        || self->alpha == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nsv_tables_free(sv_tables_t *self)\n{\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->child);\n    tsk_safe_free(self->sib);\n    tsk_safe_free(self->lambda);\n    tsk_safe_free(self->pi);\n    tsk_safe_free(self->tau);\n    tsk_safe_free(self->beta);\n    tsk_safe_free(self->alpha);\n    return 0;\n}\nstatic void\nsv_tables_reset(sv_tables_t *self, tsk_tree_t *tree)\n{\n    const tsk_size_t n = 1 + tree->num_nodes;\n    tsk_memset(self->parent, 0, n * sizeof(*self->parent));\n    tsk_memset(self->child, 0, n * sizeof(*self->child));\n    tsk_memset(self->sib, 0, n * sizeof(*self->sib));\n    tsk_memset(self->pi, 0, n * sizeof(*self->pi));\n    tsk_memset(self->lambda, 0, n * sizeof(*self->lambda));\n    tsk_memset(self->tau, 0, n * sizeof(*self->tau));\n    tsk_memset(self->beta, 0, n * sizeof(*self->beta));\n    tsk_memset(self->alpha, 0, n * sizeof(*self->alpha));\n}\n\nstatic void\nsv_tables_convert_tree(sv_tables_t *self, tsk_tree_t *tree)\n{\n    const tsk_size_t n = 1 + tree->num_nodes;\n    const tsk_id_t *restrict tsk_parent = tree->parent;\n    tsk_id_t *restrict child = self->child;\n    tsk_id_t *restrict parent = self->parent;\n    tsk_id_t *restrict sib = self->sib;\n    tsk_size_t j;\n    tsk_id_t u, v;\n\n    for (j = 0; j < n - 1; j++) {\n        u = (tsk_id_t) j + 1;\n        v = tsk_parent[j] + 1;\n        sib[u] = child[v];\n        child[v] = u;\n        parent[u] = v;\n    }\n}\n\n#define LAMBDA 0\n\nstatic void\nsv_tables_build_index(sv_tables_t *self)\n{\n    const tsk_id_t *restrict child = self->child;\n    const tsk_id_t *restrict parent = self->parent;\n    const tsk_id_t *restrict sib = self->sib;\n    tsk_id_t *restrict lambda = self->lambda;\n    tsk_id_t *restrict pi = self->pi;\n    tsk_id_t *restrict tau = self->tau;\n    tsk_id_t *restrict beta = self->beta;\n    tsk_id_t *restrict alpha = self->alpha;\n    tsk_id_t a, n, p, h;\n\n    p = child[LAMBDA];\n    n = 0;\n    lambda[0] = -1;\n    while (p != LAMBDA) {\n        while (true) {\n            n++;\n            pi[p] = n;\n            tau[n] = LAMBDA;\n            lambda[n] = 1 + lambda[n >> 1];\n            if (child[p] != LAMBDA) {\n                p = child[p];\n            } else {\n                break;\n            }\n        }\n        beta[p] = n;\n        while (true) {\n            tau[beta[p]] = parent[p];\n            if (sib[p] != LAMBDA) {\n                p = sib[p];\n                break;\n            } else {\n                p = parent[p];\n                if (p != LAMBDA) {\n                    h = lambda[n & -pi[p]];\n                    beta[p] = ((n >> h) | 1) << h;\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    /* Begin the second traversal */\n    lambda[0] = lambda[n];\n    pi[LAMBDA] = 0;\n    beta[LAMBDA] = 0;\n    alpha[LAMBDA] = 0;\n    p = child[LAMBDA];\n    while (p != LAMBDA) {\n        while (true) {\n            a = alpha[parent[p]] | (beta[p] & -beta[p]);\n            alpha[p] = a;\n            if (child[p] != LAMBDA) {\n                p = child[p];\n            } else {\n                break;\n            }\n        }\n        while (true) {\n            if (sib[p] != LAMBDA) {\n                p = sib[p];\n                break;\n            } else {\n                p = parent[p];\n                if (p == LAMBDA) {\n                    break;\n                }\n            }\n        }\n    }\n}\n\nstatic void\nsv_tables_build(sv_tables_t *self, tsk_tree_t *tree)\n{\n    sv_tables_reset(self, tree);\n    sv_tables_convert_tree(self, tree);\n    sv_tables_build_index(self);\n}\n\nstatic tsk_id_t\nsv_tables_mrca_one_based(const sv_tables_t *self, tsk_id_t x, tsk_id_t y)\n{\n    const tsk_id_t *restrict lambda = self->lambda;\n    const tsk_id_t *restrict pi = self->pi;\n    const tsk_id_t *restrict tau = self->tau;\n    const tsk_id_t *restrict beta = self->beta;\n    const tsk_id_t *restrict alpha = self->alpha;\n    tsk_id_t h, k, xhat, yhat, ell, j, z;\n\n    if (beta[x] <= beta[y]) {\n        h = lambda[beta[y] & -beta[x]];\n    } else {\n        h = lambda[beta[x] & -beta[y]];\n    }\n    k = alpha[x] & alpha[y] & -(1 << h);\n    h = lambda[k & -k];\n    j = ((beta[x] >> h) | 1) << h;\n    if (j == beta[x]) {\n        xhat = x;\n    } else {\n        ell = lambda[alpha[x] & ((1 << h) - 1)];\n        xhat = tau[((beta[x] >> ell) | 1) << ell];\n    }\n    if (j == beta[y]) {\n        yhat = y;\n    } else {\n        ell = lambda[alpha[y] & ((1 << h) - 1)];\n        yhat = tau[((beta[y] >> ell) | 1) << ell];\n    }\n    if (pi[xhat] <= pi[yhat]) {\n        z = xhat;\n    } else {\n        z = yhat;\n    }\n    return z;\n}\n\nstatic tsk_id_t\nsv_tables_mrca(const sv_tables_t *self, tsk_id_t x, tsk_id_t y)\n{\n    /* Convert to 1-based indexes and back */\n    return sv_tables_mrca_one_based(self, x + 1, y + 1) - 1;\n}\n\nstatic int\ntsk_treeseq_divergence_matrix_branch(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *restrict sample_set_sizes,\n    const tsk_id_t *restrict sample_sets, tsk_size_t num_windows,\n    const double *restrict windows, tsk_flags_t options, double *restrict result)\n{\n    int ret = 0;\n    tsk_tree_t tree;\n    const double *restrict nodes_time = self->tables->nodes.time;\n    const tsk_size_t N = num_sample_sets;\n    tsk_size_t i, j, k, offset, sj, sk;\n    tsk_id_t u, v, w, u_root, v_root;\n    double tu, tv, d, span, left, right, span_left, span_right;\n    double *restrict D;\n    sv_tables_t sv;\n    tsk_size_t *ss_offsets = tsk_malloc((num_sample_sets + 1) * sizeof(*ss_offsets));\n\n    memset(&sv, 0, sizeof(sv));\n    ret = tsk_tree_init(&tree, self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = sv_tables_init(&sv, self->tables->nodes.num_rows + 1);\n    if (ret != 0) {\n        goto out;\n    }\n    if (ss_offsets == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    if (self->time_uncalibrated && !(options & TSK_STAT_ALLOW_TIME_UNCALIBRATED)) {\n        ret = tsk_trace_error(TSK_ERR_TIME_UNCALIBRATED);\n        goto out;\n    }\n\n    ss_offsets[0] = 0;\n    offset = 0;\n    for (j = 0; j < N; j++) {\n        offset += sample_set_sizes[j];\n        ss_offsets[j + 1] = offset;\n    }\n\n    for (i = 0; i < num_windows; i++) {\n        left = windows[i];\n        right = windows[i + 1];\n        D = result + i * N * N;\n        ret = tsk_tree_seek(&tree, left, 0);\n        if (ret != 0) {\n            goto out;\n        }\n        while (tree.interval.left < right && tree.index != -1) {\n            span_left = TSK_MAX(tree.interval.left, left);\n            span_right = TSK_MIN(tree.interval.right, right);\n            span = span_right - span_left;\n            sv_tables_build(&sv, &tree);\n            for (sj = 0; sj < N; sj++) {\n                for (j = ss_offsets[sj]; j < ss_offsets[sj + 1]; j++) {\n                    u = sample_sets[j];\n                    for (sk = sj; sk < N; sk++) {\n                        for (k = ss_offsets[sk]; k < ss_offsets[sk + 1]; k++) {\n                            v = sample_sets[k];\n                            if (u == v) {\n                                /* This case contributes zero to divergence, so\n                                 * short-circuit to save time.\n                                 * TODO is there a better way to do this? */\n                                continue;\n                            }\n                            w = sv_tables_mrca(&sv, u, v);\n                            if (w != TSK_NULL) {\n                                u_root = w;\n                                v_root = w;\n                            } else {\n                                /* Slow path - only happens for nodes in disconnected\n                                 * subtrees in a tree with multiple roots */\n                                u_root = tsk_tree_get_node_root(&tree, u);\n                                v_root = tsk_tree_get_node_root(&tree, v);\n                            }\n                            tu = nodes_time[u_root] - nodes_time[u];\n                            tv = nodes_time[v_root] - nodes_time[v];\n                            d = (tu + tv) * span;\n                            D[sj * N + sk] += d;\n                        }\n                    }\n                }\n            }\n            ret = tsk_tree_next(&tree);\n            if (ret < 0) {\n                goto out;\n            }\n        }\n    }\n    ret = 0;\nout:\n    tsk_tree_free(&tree);\n    sv_tables_free(&sv);\n    tsk_safe_free(ss_offsets);\n    return ret;\n}\n\n// FIXME see #2817\n// Just including this here for now as it's the simplest option. Everything\n// will probably move to stats.[c,h] in the near future though, and it\n// can pull in ``genotypes.h`` without issues.\n#include <tskit/genotypes.h>\n\nstatic void\nupdate_site_divergence(const tsk_variant_t *var, const tsk_id_t *restrict A,\n    const tsk_size_t *restrict offsets, const tsk_size_t num_sample_sets, double *D)\n\n{\n    const tsk_size_t num_alleles = var->num_alleles;\n    tsk_size_t a, b, j, k;\n    tsk_id_t u, v;\n    double increment;\n\n    for (a = 0; a < num_alleles; a++) {\n        for (b = a + 1; b < num_alleles; b++) {\n            for (j = offsets[a]; j < offsets[a + 1]; j++) {\n                for (k = offsets[b]; k < offsets[b + 1]; k++) {\n                    u = A[j];\n                    v = A[k];\n                    /* Only increment the upper triangle to (hopefully) improve memory\n                     * access patterns */\n                    if (u > v) {\n                        u = A[k];\n                        v = A[j];\n                    }\n                    increment = 1;\n                    if (u == v) {\n                        increment = 2;\n                    }\n                    D[u * (tsk_id_t) num_sample_sets + v] += increment;\n                }\n            }\n        }\n    }\n}\n\nstatic void\ngroup_alleles(const tsk_variant_t *var, tsk_id_t *restrict A, tsk_size_t *offsets)\n{\n    const tsk_size_t n = var->num_samples;\n    const int32_t *restrict genotypes = var->genotypes;\n    tsk_id_t a;\n    tsk_size_t j, k;\n\n    k = 0;\n    offsets[0] = 0;\n    for (a = 0; a < (tsk_id_t) var->num_alleles; a++) {\n        offsets[a + 1] = offsets[a];\n        for (j = 0; j < n; j++) {\n            if (genotypes[j] == a) {\n                offsets[a + 1]++;\n                A[k] = (tsk_id_t) j;\n                k++;\n            }\n        }\n    }\n}\n\nstatic void\nremap_to_sample_sets(const tsk_size_t num_samples, const tsk_id_t *restrict samples,\n    const tsk_id_t *restrict sample_set_index_map, tsk_id_t *restrict A)\n{\n    tsk_size_t j;\n    tsk_id_t u;\n    for (j = 0; j < num_samples; j++) {\n        u = samples[A[j]];\n        tsk_bug_assert(u >= 0);\n        tsk_bug_assert(sample_set_index_map[u] >= 0);\n        A[j] = sample_set_index_map[u];\n    }\n}\n\nstatic int\ntsk_treeseq_divergence_matrix_site(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_id_t *restrict sample_set_index_map, const tsk_size_t num_samples,\n    const tsk_id_t *restrict samples, tsk_size_t num_windows,\n    const double *restrict windows, tsk_flags_t TSK_UNUSED(options),\n    double *restrict result)\n{\n    int ret = 0;\n    tsk_size_t i;\n    tsk_id_t site_id;\n    double left, right;\n    double *restrict D;\n    const tsk_id_t num_sites = (tsk_id_t) self->tables->sites.num_rows;\n    const double *restrict sites_position = self->tables->sites.position;\n    tsk_id_t *A = tsk_malloc(num_samples * sizeof(*A));\n    /* Allocate the allele offsets at the first variant */\n    tsk_size_t max_alleles = 0;\n    tsk_size_t *allele_offsets = NULL;\n    tsk_variant_t variant;\n\n    /* FIXME it's not clear that using TSK_ISOLATED_NOT_MISSING is\n     * correct here */\n    ret = tsk_variant_init(\n        &variant, self, samples, num_samples, NULL, TSK_ISOLATED_NOT_MISSING);\n    if (ret != 0) {\n        goto out;\n    }\n    if (A == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    site_id = 0;\n    while (site_id < num_sites && sites_position[site_id] < windows[0]) {\n        site_id++;\n    }\n\n    for (i = 0; i < num_windows; i++) {\n        left = windows[i];\n        right = windows[i + 1];\n        D = result + i * num_sample_sets * num_sample_sets;\n\n        if (site_id < num_sites) {\n            tsk_bug_assert(sites_position[site_id] >= left);\n        }\n        while (site_id < num_sites && sites_position[site_id] < right) {\n            ret = tsk_variant_decode(&variant, site_id, 0);\n            if (ret != 0) {\n                goto out;\n            }\n            if (variant.num_alleles > max_alleles) {\n                /* could do some kind of doubling here, but there's no\n                 * point - just keep it simple for testing. */\n                max_alleles = variant.num_alleles;\n                tsk_safe_free(allele_offsets);\n                allele_offsets = tsk_malloc((max_alleles + 1) * sizeof(*allele_offsets));\n                if (allele_offsets == NULL) {\n                    ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                    goto out;\n                }\n            }\n            group_alleles(&variant, A, allele_offsets);\n            remap_to_sample_sets(num_samples, samples, sample_set_index_map, A);\n            update_site_divergence(&variant, A, allele_offsets, num_sample_sets, D);\n            site_id++;\n        }\n    }\n    ret = 0;\nout:\n    tsk_variant_free(&variant);\n    tsk_safe_free(A);\n    tsk_safe_free(allele_offsets);\n    return ret;\n}\n\n/* Return the mapping from node IDs to the index of the sample set\n * they belong to, or -1 of none. Error if a node is in more than one\n * set.\n */\nstatic int\nget_sample_set_index_map(const tsk_treeseq_t *self, const tsk_size_t num_sample_sets,\n    const tsk_size_t *restrict sample_set_sizes, const tsk_id_t *restrict sample_sets,\n    tsk_size_t *ret_total_samples, tsk_id_t *restrict node_index_map)\n{\n    int ret = 0;\n    tsk_size_t i, j, k;\n    tsk_id_t u;\n    tsk_size_t total_samples = 0;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const tsk_flags_t *restrict node_flags = self->tables->nodes.flags;\n\n    for (j = 0; j < num_nodes; j++) {\n        node_index_map[j] = TSK_NULL;\n    }\n    i = 0;\n    for (j = 0; j < num_sample_sets; j++) {\n        total_samples += sample_set_sizes[j];\n        for (k = 0; k < sample_set_sizes[j]; k++) {\n            u = sample_sets[i];\n            i++;\n            if (u < 0 || u >= (tsk_id_t) num_nodes) {\n                ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n                goto out;\n            }\n            /* Note: we require nodes to be samples because we have to think\n             * about how to normalise by the length of genome that the node\n             * is 'in' the tree for each window otherwise. */\n            if (!(node_flags[u] & TSK_NODE_IS_SAMPLE)) {\n                ret = tsk_trace_error(TSK_ERR_BAD_SAMPLES);\n                goto out;\n            }\n            if (node_index_map[u] != TSK_NULL) {\n                ret = tsk_trace_error(TSK_ERR_DUPLICATE_SAMPLE);\n                goto out;\n            }\n            node_index_map[u] = (tsk_id_t) j;\n        }\n    }\n    *ret_total_samples = total_samples;\nout:\n    return ret;\n}\n\nstatic void\nfill_lower_triangle_count_normalise(const tsk_size_t num_windows, const tsk_size_t n,\n    const tsk_size_t *set_sizes, double *restrict result)\n{\n    tsk_size_t i, j, k;\n    double denom;\n    double *restrict D;\n\n    /* TODO there's probably a better striding pattern that could be used here */\n    for (i = 0; i < num_windows; i++) {\n        D = result + i * n * n;\n        for (j = 0; j < n; j++) {\n            denom = (double) set_sizes[j] * (double) (set_sizes[j] - 1);\n            if (denom != 0) {\n                D[j * n + j] /= denom;\n            }\n            for (k = j + 1; k < n; k++) {\n                denom = (double) set_sizes[j] * (double) set_sizes[k];\n                D[j * n + k] /= denom;\n                D[k * n + j] = D[j * n + k];\n            }\n        }\n    }\n}\n\nint\ntsk_treeseq_divergence_matrix(const tsk_treeseq_t *self, tsk_size_t num_sample_sets_in,\n    const tsk_size_t *sample_set_sizes_in, const tsk_id_t *sample_sets_in,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    tsk_size_t N, total_samples;\n    const tsk_size_t *sample_set_sizes;\n    const tsk_id_t *sample_sets;\n    tsk_size_t *tmp_sample_set_sizes = NULL;\n    const double default_windows[] = { 0, self->tables->sequence_length };\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    bool stat_site = !!(options & TSK_STAT_SITE);\n    bool stat_branch = !!(options & TSK_STAT_BRANCH);\n    bool stat_node = !!(options & TSK_STAT_NODE);\n    tsk_id_t *sample_set_index_map\n        = tsk_malloc(num_nodes * sizeof(*sample_set_index_map));\n    tsk_size_t j;\n\n    if (stat_node) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_STAT_MODE);\n        goto out;\n    }\n    /* If no mode is specified, we default to site mode */\n    if (!(stat_site || stat_branch)) {\n        stat_site = true;\n    }\n    /* It's an error to specify more than one mode */\n    if (stat_site + stat_branch > 1) {\n        ret = tsk_trace_error(TSK_ERR_MULTIPLE_STAT_MODES);\n        goto out;\n    }\n\n    if (options & TSK_STAT_POLARISED) {\n        ret = tsk_trace_error(TSK_ERR_STAT_POLARISED_UNSUPPORTED);\n        goto out;\n    }\n\n    if (windows == NULL) {\n        num_windows = 1;\n        windows = default_windows;\n    } else {\n        ret = tsk_treeseq_check_windows(self, num_windows, windows, 0);\n        if (ret != 0) {\n            goto out;\n        }\n    }\n\n    /* If sample_sets is NULL, use self->samples and ignore input\n     * num_sample_sets */\n    sample_sets = sample_sets_in;\n    N = num_sample_sets_in;\n    if (sample_sets_in == NULL) {\n        sample_sets = self->samples;\n        if (sample_set_sizes_in == NULL) {\n            N = self->num_samples;\n        }\n    }\n    sample_set_sizes = sample_set_sizes_in;\n    /* If sample_set_sizes is NULL, assume its N 1S */\n    if (sample_set_sizes_in == NULL) {\n        tmp_sample_set_sizes = tsk_malloc(N * sizeof(*tmp_sample_set_sizes));\n        if (tmp_sample_set_sizes == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        for (j = 0; j < N; j++) {\n            tmp_sample_set_sizes[j] = 1;\n        }\n        sample_set_sizes = tmp_sample_set_sizes;\n    }\n\n    ret = get_sample_set_index_map(\n        self, N, sample_set_sizes, sample_sets, &total_samples, sample_set_index_map);\n    if (ret != 0) {\n        goto out;\n    }\n\n    tsk_memset(result, 0, num_windows * N * N * sizeof(*result));\n\n    if (stat_branch) {\n        ret = tsk_treeseq_divergence_matrix_branch(self, N, sample_set_sizes,\n            sample_sets, num_windows, windows, options, result);\n    } else {\n        tsk_bug_assert(stat_site);\n        ret = tsk_treeseq_divergence_matrix_site(self, N, sample_set_index_map,\n            total_samples, sample_sets, num_windows, windows, options, result);\n    }\n    if (ret != 0) {\n        goto out;\n    }\n    fill_lower_triangle_count_normalise(num_windows, N, sample_set_sizes, result);\n\n    if (options & TSK_STAT_SPAN_NORMALISE) {\n        span_normalise(num_windows, windows, N * N, result);\n    }\nout:\n    tsk_safe_free(sample_set_index_map);\n    tsk_safe_free(tmp_sample_set_sizes);\n    return ret;\n}\n\n/* ======================================================== *\n * Extend haplotypes\n * ======================================================== */\n\ntypedef struct _edge_list_t {\n    tsk_id_t edge;\n    // the `extended` flags records whether we have decided to extend\n    // this entry to the current tree?\n    int extended;\n    struct _edge_list_t *next;\n} edge_list_t;\n\nstatic void\nedge_list_print(edge_list_t **head, tsk_edge_table_t *edges, FILE *out)\n{\n    int n = 0;\n    edge_list_t *px;\n    fprintf(out, \"Edge list:\\n\");\n    for (px = *head; px != NULL; px = px->next) {\n        fprintf(out, \"  %d: %d (%d); \", n, (int) px->edge, px->extended);\n        if (px->edge >= 0 && edges != NULL) {\n            fprintf(out, \"%d->%d on [%.1f, %.1f)\", (int) edges->child[px->edge],\n                (int) edges->parent[px->edge], edges->left[px->edge],\n                edges->right[px->edge]);\n        } else {\n            fprintf(out, \"(null)\");\n        }\n        fprintf(out, \"\\n\");\n        n += 1;\n    }\n    fprintf(out, \"length = %d\\n\", n);\n}\n\nstatic void\nedge_list_append_entry(\n    edge_list_t **head, edge_list_t **tail, edge_list_t *x, tsk_id_t edge, int extended)\n{\n    x->edge = edge;\n    x->extended = extended;\n    x->next = NULL;\n\n    if (*tail == NULL) {\n        *head = x;\n    } else {\n        (*tail)->next = x;\n    }\n    *tail = x;\n}\n\nstatic void\nremove_unextended(edge_list_t **head, edge_list_t **tail)\n{\n    edge_list_t *px, *x;\n\n    px = *head;\n    while (px != NULL && px->extended == 0) {\n        px = px->next;\n    }\n    *head = px;\n    if (px != NULL) {\n        px->extended = 0;\n        x = px->next;\n        while (x != NULL) {\n            if (x->extended > 0) {\n                x->extended = 0;\n                px->next = x;\n                px = x;\n            }\n            x = x->next;\n        }\n        px->next = NULL;\n    }\n    *tail = px;\n}\n\nstatic void\nedge_list_set_extended(edge_list_t **head, tsk_id_t edge_id)\n{\n    // finds the entry with edge 'edge_id'\n    // and sets its 'extended' flag to 1\n    edge_list_t *px;\n    px = *head;\n    tsk_bug_assert(px != NULL);\n    while (px->edge != edge_id) {\n        px = px->next;\n        tsk_bug_assert(px != NULL);\n    }\n    tsk_bug_assert(px->edge == edge_id);\n    px->extended = 1;\n}\n\nstatic int\ntsk_treeseq_slide_mutation_nodes_up(\n    const tsk_treeseq_t *self, tsk_mutation_table_t *mutations)\n{\n    int ret = 0;\n    double t;\n    tsk_id_t c, p, next_mut;\n    const tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const double *sites_position = self->tables->sites.position;\n    const double *nodes_time = self->tables->nodes.time;\n    tsk_tree_t tree;\n\n    ret = tsk_tree_init(&tree, self, TSK_NO_SAMPLE_COUNTS);\n    if (ret != 0) {\n        goto out;\n    }\n\n    next_mut = 0;\n    for (ret = tsk_tree_first(&tree); ret == TSK_TREE_OK; ret = tsk_tree_next(&tree)) {\n        while (next_mut < (tsk_id_t) mutations->num_rows\n               && sites_position[mutations->site[next_mut]] < tree.interval.right) {\n            t = mutations->time[next_mut];\n            if (tsk_is_unknown_time(t)) {\n                ret = tsk_trace_error(TSK_ERR_DISALLOWED_UNKNOWN_MUTATION_TIME);\n                goto out;\n            }\n            c = mutations->node[next_mut];\n            tsk_bug_assert(c < (tsk_id_t) num_nodes);\n            p = tree.parent[c];\n            while (p != TSK_NULL && nodes_time[p] <= t) {\n                c = p;\n                p = tree.parent[c];\n            }\n            tsk_bug_assert(nodes_time[c] <= t);\n            mutations->node[next_mut] = c;\n            next_mut++;\n        }\n    }\n    if (ret != 0) {\n        goto out;\n    }\n\nout:\n    tsk_tree_free(&tree);\n\n    return ret;\n}\n\ntypedef struct {\n    const tsk_treeseq_t *ts;\n    tsk_edge_table_t *edges;\n    int direction;\n    tsk_id_t *last_degree, *next_degree;\n    tsk_id_t *last_nodes_edge, *next_nodes_edge;\n    tsk_id_t *parent_out, *parent_in;\n    bool *not_sample;\n    double *near_side, *far_side;\n    edge_list_t *edges_out_head, *edges_out_tail;\n    edge_list_t *edges_in_head, *edges_in_tail;\n    tsk_blkalloc_t edge_list_heap;\n} haplotype_extender_t;\n\nstatic int\nhaplotype_extender_init(haplotype_extender_t *self, const tsk_treeseq_t *ts,\n    int direction, tsk_edge_table_t *edges)\n{\n    int ret = 0;\n    tsk_id_t tj;\n    tsk_size_t num_nodes = tsk_treeseq_get_num_nodes(ts);\n\n    tsk_memset(self, 0, sizeof(haplotype_extender_t));\n\n    self->ts = ts;\n    self->edges = edges;\n    ret = tsk_edge_table_copy(&ts->tables->edges, self->edges, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n\n    self->direction = direction;\n    if (direction == TSK_DIR_FORWARD) {\n        self->near_side = self->edges->left;\n        self->far_side = self->edges->right;\n    } else {\n        self->near_side = self->edges->right;\n        self->far_side = self->edges->left;\n    }\n\n    self->edges_in_head = NULL;\n    self->edges_in_tail = NULL;\n    self->edges_out_head = NULL;\n    self->edges_out_tail = NULL;\n\n    ret = tsk_blkalloc_init(&self->edge_list_heap, 8192);\n    if (ret != 0) {\n        goto out;\n    }\n\n    self->last_degree = tsk_calloc(num_nodes, sizeof(*self->last_degree));\n    self->next_degree = tsk_calloc(num_nodes, sizeof(*self->next_degree));\n    self->last_nodes_edge = tsk_malloc(num_nodes * sizeof(*self->last_nodes_edge));\n    self->next_nodes_edge = tsk_malloc(num_nodes * sizeof(*self->next_nodes_edge));\n    self->parent_out = tsk_malloc(num_nodes * sizeof(*self->parent_out));\n    self->parent_in = tsk_malloc(num_nodes * sizeof(*self->parent_in));\n    self->not_sample = tsk_malloc(num_nodes * sizeof(*self->not_sample));\n\n    if (self->last_degree == NULL || self->next_degree == NULL\n        || self->last_nodes_edge == NULL || self->next_nodes_edge == NULL\n        || self->parent_out == NULL || self->parent_in == NULL\n        || self->not_sample == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    tsk_memset(self->last_nodes_edge, 0xff, num_nodes * sizeof(*self->last_nodes_edge));\n    tsk_memset(self->next_nodes_edge, 0xff, num_nodes * sizeof(*self->next_nodes_edge));\n    tsk_memset(self->parent_out, 0xff, num_nodes * sizeof(*self->parent_out));\n    tsk_memset(self->parent_in, 0xff, num_nodes * sizeof(*self->parent_in));\n\n    for (tj = 0; tj < (tsk_id_t) num_nodes; tj++) {\n        self->not_sample[tj] = ((ts->tables->nodes.flags[tj] & TSK_NODE_IS_SAMPLE) == 0);\n    }\n\nout:\n    return ret;\n}\n\nstatic void\nhaplotype_extender_print_state(haplotype_extender_t *self, FILE *out)\n{\n    fprintf(out, \"\\n======= haplotype extender ===========\\n\");\n    fprintf(out, \"parent in:\\n\");\n    for (int j = 0; j < (int) self->ts->tables->nodes.num_rows; j++) {\n        fprintf(out, \"   %d: %d\\n\", j, (int) self->parent_in[j]);\n    }\n    fprintf(out, \"parent out:\\n\");\n    for (int j = 0; j < (int) self->ts->tables->nodes.num_rows; j++) {\n        fprintf(out, \"   %d: %d\\n\", j, (int) self->parent_out[j]);\n    }\n    fprintf(out, \"last nodes edge:\\n\");\n    for (int j = 0; j < (int) self->ts->tables->nodes.num_rows; j++) {\n        tsk_id_t ej = self->last_nodes_edge[j];\n        fprintf(out, \"   %d: %d, \", j, (int) ej);\n        if (self->last_nodes_edge[j] != TSK_NULL) {\n            fprintf(out, \"(%d->%d, %.1f-%.1f)\", (int) self->edges->child[ej],\n                (int) self->edges->parent[ej], self->edges->left[ej],\n                self->edges->right[ej]);\n        } else {\n            fprintf(out, \"(null);\");\n        }\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"next nodes edge:\\n\");\n    for (int j = 0; j < (int) self->ts->tables->nodes.num_rows; j++) {\n        tsk_id_t ej = self->next_nodes_edge[j];\n        fprintf(out, \"   %d: %d, \", j, (int) ej);\n        if (self->next_nodes_edge[j] != TSK_NULL) {\n            fprintf(out, \"(%d->%d, %.1f-%.1f)\", (int) self->edges->child[ej],\n                (int) self->edges->parent[ej], self->edges->left[ej],\n                self->edges->right[ej]);\n        } else {\n            fprintf(out, \"(null);\");\n        }\n        fprintf(out, \"\\n\");\n    }\n    fprintf(out, \"edges out:\\n\");\n    edge_list_print(&self->edges_out_head, self->edges, out);\n    fprintf(out, \"edges in:\\n\");\n    edge_list_print(&self->edges_in_head, self->edges, out);\n}\n\nstatic int\nhaplotype_extender_free(haplotype_extender_t *self)\n{\n    tsk_blkalloc_free(&self->edge_list_heap);\n    tsk_safe_free(self->last_degree);\n    tsk_safe_free(self->next_degree);\n    tsk_safe_free(self->last_nodes_edge);\n    tsk_safe_free(self->next_nodes_edge);\n    tsk_safe_free(self->parent_out);\n    tsk_safe_free(self->parent_in);\n    tsk_safe_free(self->not_sample);\n    return 0;\n}\n\nstatic int\nhaplotype_extender_next_tree(haplotype_extender_t *self, tsk_tree_position_t *tree_pos)\n{\n    int ret = 0;\n    tsk_id_t tj, e;\n    edge_list_t *ex_out, *ex_in;\n    edge_list_t *new_ex;\n    const tsk_id_t *edges_child = self->edges->child;\n    const tsk_id_t *edges_parent = self->edges->parent;\n\n    for (ex_out = self->edges_out_head; ex_out != NULL; ex_out = ex_out->next) {\n        e = ex_out->edge;\n        self->parent_out[edges_child[e]] = TSK_NULL;\n        // note we only adjust near_side of edges_in, not edges_out,\n        // so no need to check for zero-length edges\n        if (ex_out->extended > 1) {\n            // this is needed to catch newly-created edges\n            self->last_nodes_edge[edges_child[e]] = e;\n            self->last_degree[edges_child[e]] += 1;\n            self->last_degree[edges_parent[e]] += 1;\n        } else if (ex_out->extended == 0) {\n            self->last_nodes_edge[edges_child[e]] = TSK_NULL;\n            self->last_degree[edges_child[e]] -= 1;\n            self->last_degree[edges_parent[e]] -= 1;\n        }\n    }\n    remove_unextended(&self->edges_out_head, &self->edges_out_tail);\n    for (ex_in = self->edges_in_head; ex_in != NULL; ex_in = ex_in->next) {\n        e = ex_in->edge;\n        self->parent_in[edges_child[e]] = TSK_NULL;\n        if (ex_in->extended == 0 && self->near_side[e] != self->far_side[e]) {\n            self->last_nodes_edge[edges_child[e]] = e;\n            self->last_degree[edges_child[e]] += 1;\n            self->last_degree[edges_parent[e]] += 1;\n        }\n    }\n    remove_unextended(&self->edges_in_head, &self->edges_in_tail);\n\n    // done cleanup from last tree transition;\n    // now we set the state up for this tree transition\n    for (tj = tree_pos->out.start; tj != tree_pos->out.stop; tj += self->direction) {\n        e = tree_pos->out.order[tj];\n        if (self->near_side[e] != self->far_side[e]) {\n            new_ex = tsk_blkalloc_get(&self->edge_list_heap, sizeof(*new_ex));\n            if (new_ex == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            edge_list_append_entry(\n                &self->edges_out_head, &self->edges_out_tail, new_ex, e, 0);\n        }\n    }\n    for (ex_out = self->edges_out_head; ex_out != NULL; ex_out = ex_out->next) {\n        e = ex_out->edge;\n        self->parent_out[edges_child[e]] = edges_parent[e];\n        self->next_nodes_edge[edges_child[e]] = TSK_NULL;\n        self->next_degree[edges_child[e]] -= 1;\n        self->next_degree[edges_parent[e]] -= 1;\n    }\n\n    for (tj = tree_pos->in.start; tj != tree_pos->in.stop; tj += self->direction) {\n        e = tree_pos->in.order[tj];\n        // add edge to pending_in\n        new_ex = tsk_blkalloc_get(&self->edge_list_heap, sizeof(*new_ex));\n        if (new_ex == NULL) {\n            ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n            goto out;\n        }\n        edge_list_append_entry(&self->edges_in_head, &self->edges_in_tail, new_ex, e, 0);\n    }\n    for (ex_in = self->edges_in_head; ex_in != NULL; ex_in = ex_in->next) {\n        e = ex_in->edge;\n        self->parent_in[edges_child[e]] = edges_parent[e];\n        self->next_nodes_edge[edges_child[e]] = e;\n        self->next_degree[edges_child[e]] += 1;\n        self->next_degree[edges_parent[e]] += 1;\n    }\n\nout:\n    return ret;\n}\n\nstatic int\nhaplotype_extender_add_or_extend_edge(haplotype_extender_t *self, tsk_id_t new_parent,\n    tsk_id_t child, double left, double right)\n{\n    int ret = 0;\n    double there;\n    tsk_id_t old_edge, e_out, old_parent;\n    edge_list_t *ex_in;\n    edge_list_t *new_ex = NULL;\n    tsk_id_t e_in;\n\n    there = (self->direction == TSK_DIR_FORWARD) ? right : left;\n    old_edge = self->next_nodes_edge[child];\n    if (old_edge != TSK_NULL) {\n        old_parent = self->edges->parent[old_edge];\n    } else {\n        old_parent = TSK_NULL;\n    }\n    if (new_parent != old_parent) {\n        if (self->parent_out[child] == new_parent) {\n            // if our new edge is in edges_out, it should be extended\n            e_out = self->last_nodes_edge[child];\n            self->far_side[e_out] = there;\n            edge_list_set_extended(&self->edges_out_head, e_out);\n        } else {\n            e_out = tsk_edge_table_add_row(\n                self->edges, left, right, new_parent, child, NULL, 0);\n            if (e_out < 0) {\n                ret = (int) e_out;\n                goto out;\n            }\n            /* pointers to left/right might have changed! */\n            if (self->direction == TSK_DIR_FORWARD) {\n                self->near_side = self->edges->left;\n                self->far_side = self->edges->right;\n            } else {\n                self->near_side = self->edges->right;\n                self->far_side = self->edges->left;\n            }\n            new_ex = tsk_blkalloc_get(&self->edge_list_heap, sizeof(*new_ex));\n            if (new_ex == NULL) {\n                ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n                goto out;\n            }\n            edge_list_append_entry(\n                &self->edges_out_head, &self->edges_out_tail, new_ex, e_out, 2);\n        }\n        self->next_nodes_edge[child] = e_out;\n        self->next_degree[child] += 1;\n        self->next_degree[new_parent] += 1;\n        self->parent_out[child] = TSK_NULL;\n        if (old_edge != TSK_NULL) {\n            for (ex_in = self->edges_in_head; ex_in != NULL; ex_in = ex_in->next) {\n                e_in = ex_in->edge;\n                if (e_in == old_edge) {\n                    self->near_side[e_in] = there;\n                    if (self->far_side[e_in] != there) {\n                        ex_in->extended = 1;\n                    }\n                    self->next_degree[child] -= 1;\n                    self->next_degree[self->parent_in[child]] -= 1;\n                    self->parent_in[child] = TSK_NULL;\n                }\n            }\n        }\n    }\nout:\n    return ret;\n}\n\nstatic float\nhaplotype_extender_mergeable(haplotype_extender_t *self, tsk_id_t c)\n{\n    // returns the number of new edges needed\n    // if the paths in parent_in and parent_out\n    // up through nodes that aren't in the other tree\n    // end at the same place and don't have conflicting times;\n    // otherwise, return infinity\n    tsk_id_t p_in, p_out, child;\n    float num_new_edges; // needs to be float so we can have infinity\n    int num_extended;\n    double t_in, t_out;\n    bool climb_in, climb_out;\n    const double *nodes_time = self->ts->tables->nodes.time;\n\n    p_out = self->parent_out[c];\n    p_in = self->parent_in[c];\n    t_out = (p_out == TSK_NULL) ? INFINITY : nodes_time[p_out];\n    t_in = (p_in == TSK_NULL) ? INFINITY : nodes_time[p_in];\n    child = c;\n    num_new_edges = 0;\n    num_extended = 0;\n    while (true) {\n        climb_in = (p_in != TSK_NULL && self->last_degree[p_in] == 0\n                    && self->not_sample[p_in] && t_in < t_out);\n        climb_out = (p_out != TSK_NULL && self->next_degree[p_out] == 0\n                     && self->not_sample[p_out] && t_out < t_in);\n        if (climb_in) {\n            if (self->parent_in[child] != p_in) {\n                num_new_edges += 1;\n            }\n            child = p_in;\n            p_in = self->parent_in[p_in];\n            t_in = (p_in == TSK_NULL) ? INFINITY : nodes_time[p_in];\n        } else if (climb_out) {\n            if (self->parent_out[child] != p_out) {\n                num_new_edges += 1;\n            }\n            child = p_out;\n            p_out = self->parent_out[p_out];\n            t_out = (p_out == TSK_NULL) ? INFINITY : nodes_time[p_out];\n            num_extended += 1;\n        } else {\n            break;\n        }\n    }\n    if ((num_extended == 0) || (p_in != p_out) || (p_in == TSK_NULL)) {\n        num_new_edges = INFINITY;\n    }\n    return num_new_edges;\n}\n\nstatic int\nhaplotype_extender_merge_paths(\n    haplotype_extender_t *self, tsk_id_t c, double left, double right)\n{\n    int ret = 0;\n    tsk_id_t p_in, p_out, child;\n    double t_in, t_out;\n    bool climb_in, climb_out;\n    const double *nodes_time = self->ts->tables->nodes.time;\n\n    p_out = self->parent_out[c];\n    p_in = self->parent_in[c];\n    t_out = nodes_time[p_out];\n    t_in = nodes_time[p_in];\n    child = c;\n    while (true) {\n        climb_in = (p_in != TSK_NULL && self->last_degree[p_in] == 0\n                    && self->not_sample[p_in] && t_in < t_out);\n        climb_out = (p_out != TSK_NULL && self->next_degree[p_out] == 0\n                     && self->not_sample[p_out] && t_out < t_in);\n        if (climb_in) {\n            ret = haplotype_extender_add_or_extend_edge(self, p_in, child, left, right);\n            if (ret != 0) {\n                goto out;\n            }\n            child = p_in;\n            p_in = self->parent_in[p_in];\n            t_in = (p_in == TSK_NULL) ? INFINITY : nodes_time[p_in];\n        } else if (climb_out) {\n            ret = haplotype_extender_add_or_extend_edge(self, p_out, child, left, right);\n            if (ret != 0) {\n                goto out;\n            }\n            child = p_out;\n            p_out = self->parent_out[p_out];\n            t_out = (p_out == TSK_NULL) ? INFINITY : nodes_time[p_out];\n        } else {\n            break;\n        }\n    }\n    tsk_bug_assert(p_out == p_in);\n    ret = haplotype_extender_add_or_extend_edge(self, p_out, child, left, right);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\nhaplotype_extender_extend_paths(haplotype_extender_t *self)\n{\n    int ret = 0;\n    bool valid;\n    double left, right;\n    float ne, max_new_edges, next_max_new_edges;\n    tsk_tree_position_t tree_pos;\n    edge_list_t *ex_in;\n    tsk_id_t e_in, c, e;\n    tsk_size_t num_edges;\n    tsk_bool_t *keep = NULL;\n\n    tsk_memset(&tree_pos, 0, sizeof(tree_pos));\n    ret = tsk_tree_position_init(&tree_pos, self->ts, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (self->direction == TSK_DIR_FORWARD) {\n        valid = tsk_tree_position_next(&tree_pos);\n    } else {\n        valid = tsk_tree_position_prev(&tree_pos);\n    }\n\n    while (valid) {\n        left = tree_pos.interval.left;\n        right = tree_pos.interval.right;\n        ret = haplotype_extender_next_tree(self, &tree_pos);\n        if (ret != 0) {\n            goto out;\n        }\n        max_new_edges = 0;\n        next_max_new_edges = INFINITY;\n        while (max_new_edges < INFINITY) {\n            for (ex_in = self->edges_in_head; ex_in != NULL; ex_in = ex_in->next) {\n                e_in = ex_in->edge;\n                c = self->edges->child[e_in];\n                if (self->last_degree[c] > 0) {\n                    ne = haplotype_extender_mergeable(self, c);\n                    if (ne <= max_new_edges) {\n                        ret = haplotype_extender_merge_paths(self, c, left, right);\n                        if (ret != 0) {\n                            goto out;\n                        }\n                    } else {\n                        next_max_new_edges = TSK_MIN(ne, next_max_new_edges);\n                    }\n                }\n            }\n            max_new_edges = next_max_new_edges;\n            next_max_new_edges = INFINITY;\n        }\n        if (self->direction == TSK_DIR_FORWARD) {\n            valid = tsk_tree_position_next(&tree_pos);\n        } else {\n            valid = tsk_tree_position_prev(&tree_pos);\n        }\n    }\n    /* Get rid of adjacent, identical edges */\n    /* note: we need to calloc this here instead of at the start\n     * because we don't know how big it will need to be until now */\n    num_edges = self->edges->num_rows;\n    keep = tsk_calloc(num_edges, sizeof(*keep));\n    if (keep == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (e = 0; e < (tsk_id_t) num_edges - 1; e++) {\n        if (self->edges->parent[e] == self->edges->parent[e + 1]\n            && self->edges->child[e] == self->edges->child[e + 1]\n            && self->edges->right[e] == self->edges->left[e + 1]) {\n            self->edges->right[e] = self->edges->right[e + 1];\n            self->edges->left[e + 1] = self->edges->right[e + 1];\n        }\n    }\n    for (e = 0; e < (tsk_id_t) num_edges; e++) {\n        keep[e] = self->edges->left[e] < self->edges->right[e];\n    }\n    ret = tsk_edge_table_keep_rows(self->edges, keep, 0, NULL);\nout:\n    tsk_tree_position_free(&tree_pos);\n    tsk_safe_free(keep);\n    return ret;\n}\n\nstatic int\nextend_haplotypes_iter(const tsk_treeseq_t *self, int direction, tsk_edge_table_t *edges,\n    tsk_flags_t options)\n{\n    int ret = 0;\n    haplotype_extender_t haplotype_extender;\n    tsk_memset(&haplotype_extender, 0, sizeof(haplotype_extender));\n    ret = haplotype_extender_init(&haplotype_extender, self, direction, edges);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = haplotype_extender_extend_paths(&haplotype_extender);\n    if (ret != 0) {\n        goto out;\n    }\n\n    if (!!(options & TSK_DEBUG)) {\n        haplotype_extender_print_state(&haplotype_extender, tsk_get_debug_stream());\n    }\n\nout:\n    haplotype_extender_free(&haplotype_extender);\n    return ret;\n}\n\nint TSK_WARN_UNUSED\ntsk_treeseq_extend_haplotypes(\n    const tsk_treeseq_t *self, int max_iter, tsk_flags_t options, tsk_treeseq_t *output)\n{\n    int ret = 0;\n    tsk_table_collection_t tables;\n    tsk_treeseq_t ts;\n    int iter, j;\n    tsk_size_t last_num_edges;\n    tsk_bookmark_t sort_start;\n    const int direction[] = { TSK_DIR_FORWARD, TSK_DIR_REVERSE };\n\n    tsk_memset(&tables, 0, sizeof(tables));\n    tsk_memset(&ts, 0, sizeof(ts));\n    tsk_memset(output, 0, sizeof(*output));\n\n    if (max_iter <= 0) {\n        ret = tsk_trace_error(TSK_ERR_EXTEND_EDGES_BAD_MAXITER);\n        goto out;\n    }\n    if (tsk_treeseq_get_num_migrations(self) != 0) {\n        ret = tsk_trace_error(TSK_ERR_MIGRATIONS_NOT_SUPPORTED);\n        goto out;\n    }\n\n    /* Note: there is a fair bit of copying of table data in this implementation\n     * currently, as we create a new tree sequence for each iteration, which\n     * takes a full copy of the input tables. We could streamline this by\n     * adding a flag to treeseq_init which says \"steal a reference to these\n     * tables and *don't* free them at the end\". Then, we would only need\n     * one copy of the full tables, and could pass in a standalone edge\n     * table to use for in-place updating.\n     */\n    ret = tsk_table_collection_copy(self->tables, &tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_mutation_table_clear(&tables.mutations);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_init(&ts, &tables, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    last_num_edges = tsk_treeseq_get_num_edges(&ts);\n    for (iter = 0; iter < max_iter; iter++) {\n        for (j = 0; j < 2; j++) {\n            ret = extend_haplotypes_iter(&ts, direction[j], &tables.edges, options);\n            if (ret != 0) {\n                goto out;\n            }\n            /* We're done with the current ts now */\n            tsk_treeseq_free(&ts);\n            /* no need to sort sites and mutations */\n            memset(&sort_start, 0, sizeof(sort_start));\n            sort_start.sites = tables.sites.num_rows;\n            sort_start.mutations = tables.mutations.num_rows;\n            ret = tsk_table_collection_sort(&tables, &sort_start, 0);\n            if (ret != 0) {\n                goto out;\n            }\n            ret = tsk_treeseq_init(&ts, &tables, TSK_TS_INIT_BUILD_INDEXES);\n            if (ret != 0) {\n                goto out;\n            }\n        }\n        if (last_num_edges == tsk_treeseq_get_num_edges(&ts)) {\n            break;\n        }\n        last_num_edges = tsk_treeseq_get_num_edges(&ts);\n    }\n\n    /* Remap mutation nodes */\n    ret = tsk_mutation_table_copy(\n        &self->tables->mutations, &tables.mutations, TSK_NO_INIT);\n    if (ret != 0) {\n        goto out;\n    }\n    /* Note: to allow migrations we'd also have to do this same operation\n     * on the migration nodes; however it's a can of worms because the interval\n     * covering the migration might no longer make sense. */\n    ret = tsk_treeseq_slide_mutation_nodes_up(&ts, &tables.mutations);\n    if (ret != 0) {\n        goto out;\n    }\n    tsk_treeseq_free(&ts);\n    ret = tsk_treeseq_init(&ts, &tables, TSK_TS_INIT_BUILD_INDEXES);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* Hand ownership of the tree sequence to the calling code */\n    tsk_memcpy(output, &ts, sizeof(ts));\n    tsk_memset(&ts, 0, sizeof(*output));\nout:\n    tsk_treeseq_free(&ts);\n    tsk_table_collection_free(&tables);\n    return ret;\n}\n\n/* ======================================================== *\n * Pair coalescence\n * ======================================================== */\n\nstatic int\ncheck_node_bin_map(\n    const tsk_size_t num_nodes, const tsk_size_t num_bins, const tsk_id_t *node_bin_map)\n{\n    int ret = 0;\n    tsk_id_t max_index, index;\n    tsk_size_t i;\n\n    max_index = TSK_NULL;\n    for (i = 0; i < num_nodes; i++) {\n        index = node_bin_map[i];\n        if (index < TSK_NULL) {\n            ret = tsk_trace_error(TSK_ERR_BAD_NODE_BIN_MAP);\n            goto out;\n        }\n        if (index > max_index) {\n            max_index = index;\n        }\n    }\n    if (num_bins < 1 || (tsk_id_t) num_bins < max_index + 1) {\n        ret = tsk_trace_error(TSK_ERR_BAD_NODE_BIN_MAP_DIM);\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic inline void\nTRANSPOSE_2D(tsk_size_t rows, tsk_size_t cols, const double *source, double *dest)\n{\n    tsk_size_t i, j;\n    for (i = 0; i < rows; ++i) {\n        for (j = 0; j < cols; ++j) {\n            dest[j * rows + i] = source[i * cols + j];\n        }\n    }\n}\n\nstatic inline void\npair_coalescence_count(tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_sample_sets, const double *parent_count, const double *child_count,\n    const double *parent_state, const double *inside, double *outside, double *result)\n{\n    tsk_size_t i;\n    tsk_id_t j, k;\n    for (i = 0; i < num_sample_sets; i++) {\n        outside[i] = parent_count[i] - child_count[i] - parent_state[i];\n    }\n    for (i = 0; i < num_set_indexes; i++) {\n        j = set_indexes[2 * i];\n        k = set_indexes[2 * i + 1];\n        result[i] = outside[j] * inside[k];\n        if (j != k) {\n            result[i] += outside[k] * inside[j];\n        }\n    }\n}\n\nint\ntsk_treeseq_pair_coalescence_stat(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_set_indexes, const tsk_id_t *set_indexes, tsk_size_t num_windows,\n    const double *windows, tsk_size_t num_bins, const tsk_id_t *node_bin_map,\n    pair_coalescence_stat_func_t *summary_func, tsk_size_t summary_func_dim,\n    void *summary_func_args, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    double left, right, remaining_span, missing_span, window_span, denominator, x, t;\n    tsk_id_t e, p, c, u, v, w, i, j;\n    tsk_size_t num_samples, num_edges;\n    tsk_tree_position_t tree_pos;\n    const tsk_table_collection_t *tables = self->tables;\n    const tsk_size_t num_nodes = tables->nodes.num_rows;\n    const double *restrict nodes_time = self->tables->nodes.time;\n    const double sequence_length = tables->sequence_length;\n    const tsk_size_t num_outputs = summary_func_dim;\n\n    /* buffers */\n    bool *visited = NULL;\n    tsk_id_t *nodes_sample_set = NULL;\n    tsk_id_t *nodes_parent = NULL;\n    double *coalescing_pairs = NULL;\n    double *coalescence_time = NULL;\n    double *nodes_sample = NULL;\n    double *sample_count = NULL;\n    double *bin_weight = NULL;\n    double *bin_values = NULL;\n    double *pair_count = NULL;\n    double *total_pair = NULL;\n    double *outside = NULL;\n\n    /* row pointers */\n    double *inside = NULL;\n    double *weight = NULL;\n    double *values = NULL;\n    double *output = NULL;\n    double *above = NULL;\n    double *below = NULL;\n    double *state = NULL;\n    double *pairs = NULL;\n    double *times = NULL;\n\n    tsk_memset(&tree_pos, 0, sizeof(tree_pos));\n\n    /* check inputs */\n    ret = tsk_treeseq_check_windows(self, num_windows, windows, TSK_REQUIRE_FULL_SPAN);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_set_indexes(num_sample_sets, 2 * num_set_indexes, set_indexes);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = tsk_treeseq_check_sample_sets(\n        self, num_sample_sets, sample_set_sizes, sample_sets);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_node_bin_map(num_nodes, num_bins, node_bin_map);\n    if (ret != 0) {\n        goto out;\n    }\n\n    /* map nodes to sample sets */\n    nodes_sample_set = tsk_malloc(num_nodes * sizeof(*nodes_sample_set));\n    if (nodes_sample_set == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    ret = get_sample_set_index_map(self, num_sample_sets, sample_set_sizes, sample_sets,\n        &num_samples, nodes_sample_set);\n    if (ret != 0) {\n        goto out;\n    }\n\n    visited = tsk_malloc(num_nodes * sizeof(*visited));\n    outside = tsk_malloc(num_sample_sets * sizeof(*outside));\n    nodes_parent = tsk_malloc(num_nodes * sizeof(*nodes_parent));\n    nodes_sample = tsk_calloc(num_nodes * num_sample_sets, sizeof(*nodes_sample));\n    sample_count = tsk_malloc(num_nodes * num_sample_sets * sizeof(*sample_count));\n    coalescing_pairs = tsk_calloc(num_bins * num_set_indexes, sizeof(*coalescing_pairs));\n    coalescence_time = tsk_calloc(num_bins * num_set_indexes, sizeof(*coalescence_time));\n    bin_weight = tsk_malloc(num_bins * num_set_indexes * sizeof(*bin_weight));\n    bin_values = tsk_malloc(num_bins * num_set_indexes * sizeof(*bin_values));\n    pair_count = tsk_malloc(num_set_indexes * sizeof(*pair_count));\n    total_pair = tsk_malloc(num_set_indexes * sizeof(*total_pair));\n    if (nodes_parent == NULL || nodes_sample == NULL || sample_count == NULL\n        || coalescing_pairs == NULL || bin_weight == NULL || bin_values == NULL\n        || outside == NULL || pair_count == NULL || visited == NULL\n        || total_pair == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (i = 0; i < (tsk_id_t) num_set_indexes; i++) {\n        u = set_indexes[2 * i];\n        v = set_indexes[2 * i + 1];\n        total_pair[i] = (double) sample_set_sizes[u] * (double) sample_set_sizes[v];\n        if (u == v) {\n            total_pair[i] -= (double) sample_set_sizes[v];\n            total_pair[i] /= 2;\n        }\n    }\n\n    /* initialize internal state */\n    for (c = 0; c < (tsk_id_t) num_nodes; c++) {\n        i = nodes_sample_set[c];\n        if (i != TSK_NULL) {\n            state = GET_2D_ROW(nodes_sample, num_sample_sets, c);\n            state[i] = 1.0;\n        }\n        nodes_parent[c] = TSK_NULL;\n        visited[c] = false;\n    }\n    tsk_memcpy(\n        sample_count, nodes_sample, num_nodes * num_sample_sets * sizeof(*sample_count));\n\n    ret = tsk_tree_position_init(&tree_pos, self, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    num_edges = 0;\n    missing_span = 0.0;\n    w = 0;\n    while (true) {\n        tsk_tree_position_next(&tree_pos);\n        if (tree_pos.index == TSK_NULL) {\n            break;\n        }\n\n        left = tree_pos.interval.left;\n        right = tree_pos.interval.right;\n        remaining_span = sequence_length - left;\n\n        for (u = tree_pos.out.start; u != tree_pos.out.stop; u++) {\n            e = tree_pos.out.order[u];\n            p = tables->edges.parent[e];\n            c = tables->edges.child[e];\n            nodes_parent[c] = TSK_NULL;\n            inside = GET_2D_ROW(sample_count, num_sample_sets, c);\n            while (p != TSK_NULL) { /* downdate statistic */\n                v = node_bin_map[p];\n                t = nodes_time[p];\n                if (v != TSK_NULL) {\n                    above = GET_2D_ROW(sample_count, num_sample_sets, p);\n                    below = GET_2D_ROW(sample_count, num_sample_sets, c);\n                    state = GET_2D_ROW(nodes_sample, num_sample_sets, p);\n                    pairs = GET_2D_ROW(coalescing_pairs, num_set_indexes, v);\n                    times = GET_2D_ROW(coalescence_time, num_set_indexes, v);\n                    pair_coalescence_count(num_set_indexes, set_indexes, num_sample_sets,\n                        above, below, state, inside, outside, pair_count);\n                    for (i = 0; i < (tsk_id_t) num_set_indexes; i++) {\n                        x = pair_count[i] * remaining_span;\n                        pairs[i] -= x;\n                        times[i] -= t * x;\n                    }\n                }\n                c = p;\n                p = nodes_parent[c];\n            }\n            p = tables->edges.parent[e];\n            while (p != TSK_NULL) { /* downdate state */\n                above = GET_2D_ROW(sample_count, num_sample_sets, p);\n                for (i = 0; i < (tsk_id_t) num_sample_sets; i++) {\n                    above[i] -= inside[i];\n                }\n                p = nodes_parent[p];\n            }\n            num_edges -= 1;\n        }\n\n        for (u = tree_pos.in.start; u != tree_pos.in.stop; u++) {\n            e = tree_pos.in.order[u];\n            p = tables->edges.parent[e];\n            c = tables->edges.child[e];\n            nodes_parent[c] = p;\n            inside = GET_2D_ROW(sample_count, num_sample_sets, c);\n            while (p != TSK_NULL) { /* update state */\n                above = GET_2D_ROW(sample_count, num_sample_sets, p);\n                for (i = 0; i < (tsk_id_t) num_sample_sets; i++) {\n                    above[i] += inside[i];\n                }\n                p = nodes_parent[p];\n            }\n            p = tables->edges.parent[e];\n            while (p != TSK_NULL) { /* update statistic */\n                v = node_bin_map[p];\n                t = nodes_time[p];\n                if (v != TSK_NULL) {\n                    above = GET_2D_ROW(sample_count, num_sample_sets, p);\n                    below = GET_2D_ROW(sample_count, num_sample_sets, c);\n                    state = GET_2D_ROW(nodes_sample, num_sample_sets, p);\n                    pairs = GET_2D_ROW(coalescing_pairs, num_set_indexes, v);\n                    times = GET_2D_ROW(coalescence_time, num_set_indexes, v);\n                    pair_coalescence_count(num_set_indexes, set_indexes, num_sample_sets,\n                        above, below, state, inside, outside, pair_count);\n                    for (i = 0; i < (tsk_id_t) num_set_indexes; i++) {\n                        x = pair_count[i] * remaining_span;\n                        pairs[i] += x;\n                        times[i] += t * x;\n                    }\n                }\n                c = p;\n                p = nodes_parent[c];\n            }\n            num_edges += 1;\n        }\n\n        if (num_edges == 0) {\n            missing_span += right - left;\n        }\n\n        /* flush windows */\n        while (w < (tsk_id_t) num_windows && windows[w + 1] <= right) {\n            TRANSPOSE_2D(num_bins, num_set_indexes, coalescing_pairs, bin_weight);\n            TRANSPOSE_2D(num_bins, num_set_indexes, coalescence_time, bin_values);\n            tsk_memset(coalescing_pairs, 0,\n                num_bins * num_set_indexes * sizeof(*coalescing_pairs));\n            tsk_memset(coalescence_time, 0,\n                num_bins * num_set_indexes * sizeof(*coalescence_time));\n            remaining_span = sequence_length - windows[w + 1];\n            for (j = 0; j < (tsk_id_t) num_samples; j++) { /* truncate at tree */\n                c = sample_sets[j];\n                p = nodes_parent[c];\n                while (!visited[c] && p != TSK_NULL) {\n                    v = node_bin_map[p];\n                    t = nodes_time[p];\n                    if (v != TSK_NULL) {\n                        above = GET_2D_ROW(sample_count, num_sample_sets, p);\n                        below = GET_2D_ROW(sample_count, num_sample_sets, c);\n                        state = GET_2D_ROW(nodes_sample, num_sample_sets, p);\n                        pairs = GET_2D_ROW(coalescing_pairs, num_set_indexes, v);\n                        times = GET_2D_ROW(coalescence_time, num_set_indexes, v);\n                        pair_coalescence_count(num_set_indexes, set_indexes,\n                            num_sample_sets, above, below, state, below, outside,\n                            pair_count);\n                        for (i = 0; i < (tsk_id_t) num_set_indexes; i++) {\n                            weight = GET_2D_ROW(bin_weight, num_bins, i);\n                            values = GET_2D_ROW(bin_values, num_bins, i);\n                            x = pair_count[i] * remaining_span / 2;\n                            pairs[i] += x;\n                            times[i] += t * x;\n                            weight[v] -= x;\n                            values[v] -= t * x;\n                        }\n                    }\n                    visited[c] = true;\n                    c = p;\n                    p = nodes_parent[c];\n                }\n            }\n            for (j = 0; j < (tsk_id_t) num_samples; j++) { /* reset tree */\n                c = sample_sets[j];\n                p = nodes_parent[c];\n                while (visited[c] && p != TSK_NULL) {\n                    visited[c] = false;\n                    c = p;\n                    p = nodes_parent[c];\n                }\n            }\n            for (i = 0; i < (tsk_id_t) num_set_indexes; i++) { /* normalise values */\n                weight = GET_2D_ROW(bin_weight, num_bins, i);\n                values = GET_2D_ROW(bin_values, num_bins, i);\n                for (v = 0; v < (tsk_id_t) num_bins; v++) {\n                    values[v] /= weight[v];\n                }\n            }\n            /* normalise weights */\n            if (options & (TSK_STAT_SPAN_NORMALISE | TSK_STAT_PAIR_NORMALISE)) {\n                window_span = windows[w + 1] - windows[w] - missing_span;\n                missing_span = 0.0;\n                if (num_edges == 0) {\n                    /* missing interval, so remove overcounted missing span */\n                    remaining_span = right - windows[w + 1];\n                    window_span += remaining_span;\n                    missing_span += remaining_span;\n                }\n                for (i = 0; i < (tsk_id_t) num_set_indexes; i++) {\n                    denominator = 1.0;\n                    if (options & TSK_STAT_SPAN_NORMALISE) {\n                        denominator *= window_span;\n                    }\n                    if (options & TSK_STAT_PAIR_NORMALISE) {\n                        denominator *= total_pair[i];\n                    }\n                    weight = GET_2D_ROW(bin_weight, num_bins, i);\n                    for (v = 0; v < (tsk_id_t) num_bins; v++) {\n                        weight[v] *= denominator == 0.0 ? 0.0 : 1 / denominator;\n                    }\n                }\n            }\n            for (i = 0; i < (tsk_id_t) num_set_indexes; i++) { /* summarise bins */\n                weight = GET_2D_ROW(bin_weight, num_bins, i);\n                values = GET_2D_ROW(bin_values, num_bins, i);\n                output = GET_3D_ROW(\n                    result, num_set_indexes, num_outputs, (tsk_size_t) w, i);\n                ret = summary_func(\n                    num_bins, weight, values, num_outputs, output, summary_func_args);\n                if (ret != 0) {\n                    goto out;\n                }\n            };\n            w += 1;\n        }\n    }\nout:\n    tsk_tree_position_free(&tree_pos);\n    tsk_safe_free(nodes_sample_set);\n    tsk_safe_free(coalescing_pairs);\n    tsk_safe_free(coalescence_time);\n    tsk_safe_free(nodes_parent);\n    tsk_safe_free(nodes_sample);\n    tsk_safe_free(sample_count);\n    tsk_safe_free(bin_weight);\n    tsk_safe_free(bin_values);\n    tsk_safe_free(pair_count);\n    tsk_safe_free(total_pair);\n    tsk_safe_free(visited);\n    tsk_safe_free(outside);\n    return ret;\n}\n\nstatic int\npair_coalescence_weights(tsk_size_t TSK_UNUSED(input_dim), const double *weight,\n    const double *TSK_UNUSED(values), tsk_size_t output_dim, double *output,\n    void *TSK_UNUSED(params))\n{\n    int ret = 0;\n    tsk_memcpy(output, weight, output_dim * sizeof(*output));\n    return ret;\n}\n\nint\ntsk_treeseq_pair_coalescence_counts(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_bins,\n    const tsk_id_t *node_bin_map, tsk_flags_t options, double *result)\n{\n    return tsk_treeseq_pair_coalescence_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_set_indexes, set_indexes, num_windows, windows, num_bins,\n        node_bin_map, pair_coalescence_weights, num_bins, NULL, options, result);\n}\n\nstatic int\npair_coalescence_quantiles(tsk_size_t input_dim, const double *weight,\n    const double *values, tsk_size_t output_dim, double *output, void *params)\n{\n    int ret = 0;\n    double coalesced, timepoint;\n    double *quantiles = (double *) params;\n    tsk_size_t i, j;\n    j = 0;\n    coalesced = 0.0;\n    timepoint = TSK_UNKNOWN_TIME;\n    for (i = 0; i < output_dim; i++) {\n        output[i] = NAN;\n    }\n    for (i = 0; i < input_dim; i++) {\n        if (weight[i] > 0) {\n            coalesced += weight[i];\n            timepoint = values[i];\n            while (j < output_dim && quantiles[j] <= coalesced) {\n                output[j] = timepoint;\n                j += 1;\n            }\n        }\n    }\n    if (quantiles[output_dim - 1] == 1.0) {\n        output[output_dim - 1] = timepoint;\n    }\n    return ret;\n}\n\nstatic int\ncheck_quantiles(const tsk_size_t num_quantiles, const double *quantiles)\n{\n    int ret = 0;\n    tsk_size_t i;\n    double last = -INFINITY;\n    for (i = 0; i < num_quantiles; i++) {\n        if (quantiles[i] <= last || quantiles[i] < 0.0 || quantiles[i] > 1.0) {\n            ret = tsk_trace_error(TSK_ERR_BAD_QUANTILES);\n            goto out;\n        }\n        last = quantiles[i];\n    }\nout:\n    return ret;\n}\n\nstatic int\ncheck_sorted_node_bin_map(\n    const tsk_treeseq_t *self, tsk_size_t num_bins, const tsk_id_t *node_bin_map)\n{\n    int ret = 0;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    const double *nodes_time = self->tables->nodes.time;\n    double last;\n    tsk_id_t i, j;\n    double *min_time = tsk_malloc(num_bins * sizeof(*min_time));\n    double *max_time = tsk_malloc(num_bins * sizeof(*max_time));\n    if (min_time == NULL || max_time == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n    for (j = 0; j < (tsk_id_t) num_bins; j++) {\n        min_time[j] = TSK_UNKNOWN_TIME;\n        max_time[j] = TSK_UNKNOWN_TIME;\n    }\n    for (i = 0; i < (tsk_id_t) num_nodes; i++) {\n        j = node_bin_map[i];\n        if (j < 0 || j >= (tsk_id_t) num_bins) {\n            continue;\n        }\n        if (tsk_is_unknown_time(max_time[j]) || nodes_time[i] > max_time[j]) {\n            max_time[j] = nodes_time[i];\n        }\n        if (tsk_is_unknown_time(min_time[j]) || nodes_time[i] < min_time[j]) {\n            min_time[j] = nodes_time[i];\n        }\n    }\n    last = -INFINITY;\n    for (j = 0; j < (tsk_id_t) num_bins; j++) {\n        if (tsk_is_unknown_time(min_time[j])) {\n            continue;\n        }\n        if (min_time[j] < last) {\n            ret = tsk_trace_error(TSK_ERR_UNSORTED_TIMES);\n            goto out;\n        } else {\n            last = max_time[j];\n        }\n    }\nout:\n    tsk_safe_free(min_time);\n    tsk_safe_free(max_time);\n    return ret;\n}\n\nint\ntsk_treeseq_pair_coalescence_quantiles(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_bins,\n    const tsk_id_t *node_bin_map, tsk_size_t num_quantiles, double *quantiles,\n    tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    void *params = (void *) quantiles;\n    ret = check_quantiles(num_quantiles, quantiles);\n    if (ret != 0) {\n        goto out;\n    }\n    ret = check_sorted_node_bin_map(self, num_bins, node_bin_map);\n    if (ret != 0) {\n        goto out;\n    }\n    options |= TSK_STAT_SPAN_NORMALISE | TSK_STAT_PAIR_NORMALISE;\n    ret = tsk_treeseq_pair_coalescence_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_set_indexes, set_indexes, num_windows, windows, num_bins,\n        node_bin_map, pair_coalescence_quantiles, num_quantiles, params, options,\n        result);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\nstatic int\npair_coalescence_rates(tsk_size_t input_dim, const double *weight, const double *values,\n    tsk_size_t output_dim, double *output, void *params)\n{\n    int ret = 0;\n    double coalesced, rate, waiting_time, a, b;\n    double *time_windows = (double *) params;\n    tsk_id_t i, j;\n    tsk_bug_assert(input_dim == output_dim);\n    for (j = (tsk_id_t) output_dim; j > 0; j--) { /* find last window with data */\n        if (weight[j - 1] == 0) {\n            output[j - 1] = NAN; /* TODO: should fill value be zero instead? */\n        } else {\n            break;\n        }\n    }\n    coalesced = 0.0;\n    for (i = 0; i < j; i++) {\n        a = time_windows[i];\n        b = time_windows[i + 1];\n        if (i + 1 == j) {\n            waiting_time = values[i] < a ? 0.0 : values[i] - a;\n            rate = 1 / waiting_time;\n        } else {\n            rate = log(1 - weight[i] / (1 - coalesced)) / (a - b);\n        }\n        // avoid tiny negative values from fp error\n        output[i] = rate > 0 ? rate : 0;\n        coalesced += weight[i];\n    }\n    return ret;\n}\n\nstatic int\ncheck_coalescence_rate_time_windows(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_time_windows,\n    const tsk_id_t *node_time_window, const double *time_windows)\n{\n    int ret = 0;\n    double timepoint;\n    const double *nodes_time = self->tables->nodes.time;\n    tsk_size_t num_nodes = self->tables->nodes.num_rows;\n    tsk_id_t i, j, k;\n    tsk_id_t n;\n    if (num_time_windows == 0) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TIME_WINDOWS_DIM);\n        goto out;\n    }\n    /* time windows are sorted */\n    timepoint = time_windows[0];\n    for (i = 0; i < (tsk_id_t) num_time_windows; i++) {\n        if (time_windows[i + 1] <= timepoint) {\n            ret = tsk_trace_error(TSK_ERR_BAD_TIME_WINDOWS);\n            goto out;\n        }\n        timepoint = time_windows[i + 1];\n    }\n    if (timepoint != INFINITY) {\n        ret = tsk_trace_error(TSK_ERR_BAD_TIME_WINDOWS_END);\n        goto out;\n    }\n    /* all sample times align with start of first time window */\n    k = 0;\n    for (i = 0; i < (tsk_id_t) num_sample_sets; i++) {\n        for (j = 0; j < (tsk_id_t) sample_set_sizes[i]; j++) {\n            n = sample_sets[k++];\n            if (nodes_time[n] != time_windows[0]) {\n                ret = tsk_trace_error(TSK_ERR_BAD_SAMPLE_PAIR_TIMES);\n                goto out;\n            }\n        }\n    }\n    /* nodes are correctly assigned to time windows */\n    for (i = 0; i < (tsk_id_t) num_nodes; i++) {\n        j = node_time_window[i];\n        if (j < 0) {\n            continue;\n        }\n        if (j >= (tsk_id_t) num_time_windows) {\n            ret = tsk_trace_error(TSK_ERR_BAD_NODE_BIN_MAP_DIM);\n            goto out;\n        }\n        if (nodes_time[i] < time_windows[j] || nodes_time[i] >= time_windows[j + 1]) {\n            ret = tsk_trace_error(TSK_ERR_BAD_NODE_TIME_WINDOW);\n            goto out;\n        }\n    }\nout:\n    return ret;\n}\n\nint\ntsk_treeseq_pair_coalescence_rates(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_set_indexes, const tsk_id_t *set_indexes, tsk_size_t num_windows,\n    const double *windows, tsk_size_t num_time_windows, const tsk_id_t *node_time_window,\n    double *time_windows, tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    void *params = (void *) time_windows;\n    ret = check_coalescence_rate_time_windows(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_time_windows, node_time_window, time_windows);\n    if (ret != 0) {\n        goto out;\n    }\n    options |= TSK_STAT_SPAN_NORMALISE | TSK_STAT_PAIR_NORMALISE;\n    ret = tsk_treeseq_pair_coalescence_stat(self, num_sample_sets, sample_set_sizes,\n        sample_sets, num_set_indexes, set_indexes, num_windows, windows,\n        num_time_windows, node_time_window, pair_coalescence_rates, num_time_windows,\n        params, options, result);\n    if (ret != 0) {\n        goto out;\n    }\nout:\n    return ret;\n}\n\n/* ======================================================== *\n * Relatedness matrix-vector product\n * ======================================================== */\n\ntypedef struct {\n    const tsk_treeseq_t *ts;\n    tsk_size_t num_weights;\n    const double *weights;\n    tsk_size_t num_windows;\n    const double *windows;\n    tsk_size_t num_focal_nodes;\n    const tsk_id_t *focal_nodes;\n    tsk_flags_t options;\n    double *result;\n    tsk_tree_position_t tree_pos;\n    double position;\n    tsk_size_t num_nodes;\n    tsk_id_t *parent;\n    double *x;\n    double *w;\n    double *v;\n} tsk_matvec_calculator_t;\n\nstatic void\ntsk_matvec_calculator_print_state(const tsk_matvec_calculator_t *self, FILE *out)\n{\n    tsk_id_t j;\n    tsk_size_t num_samples = tsk_treeseq_get_num_samples(self->ts);\n\n    fprintf(out, \"Matvec state:\\n\");\n    fprintf(out, \"options = %d\\n\", self->options);\n    fprintf(out, \"position = %f\\n\", self->position);\n    fprintf(out, \"focal nodes = %lld: [\", (long long) self->num_focal_nodes);\n    fprintf(out, \"tree_pos:\\n\");\n    tsk_tree_position_print_state(&self->tree_pos, out);\n    fprintf(out, \"samples = %lld: [\", (long long) num_samples);\n    fprintf(out, \"]\\n\");\n    fprintf(out, \"node\\tparent\\tx\\tv\\tw\");\n    fprintf(out, \"\\n\");\n\n    for (j = 0; j < (tsk_id_t) self->num_nodes; j++) {\n        fprintf(out, \"%lld\\t\", (long long) j);\n        fprintf(out, \"%lld\\t%g\\t%g\\t%g\\n\", (long long) self->parent[j], self->x[j],\n            self->v[j], self->w[j]);\n    }\n}\n\nstatic int\ntsk_matvec_calculator_init(tsk_matvec_calculator_t *self, const tsk_treeseq_t *ts,\n    tsk_size_t num_weights, const double *weights, tsk_size_t num_windows,\n    const double *windows, tsk_size_t num_focal_nodes, const tsk_id_t *focal_nodes,\n    tsk_flags_t options, double *result)\n{\n    int ret = 0;\n    tsk_size_t num_samples = tsk_treeseq_get_num_samples(ts);\n    const tsk_size_t num_nodes = ts->tables->nodes.num_rows;\n    const double *row;\n    double *new_row;\n    tsk_size_t k;\n    tsk_id_t index, u, j;\n    double *weight_means = tsk_malloc(num_weights * sizeof(*weight_means));\n    const tsk_size_t num_trees = ts->num_trees;\n    const double *restrict breakpoints = ts->breakpoints;\n\n    self->ts = ts;\n    self->num_weights = num_weights;\n    self->weights = weights;\n    self->num_windows = num_windows;\n    self->windows = windows;\n    self->num_focal_nodes = num_focal_nodes;\n    self->focal_nodes = focal_nodes;\n    self->options = options;\n    self->result = result;\n    self->num_nodes = num_nodes;\n    self->position = windows[0];\n\n    self->parent = tsk_malloc(num_nodes * sizeof(*self->parent));\n    self->x = tsk_calloc(num_nodes, sizeof(*self->x));\n    self->v = tsk_calloc(num_nodes * num_weights, sizeof(*self->v));\n    self->w = tsk_calloc(num_nodes * num_weights, sizeof(*self->w));\n\n    if (self->parent == NULL || self->x == NULL || self->w == NULL || self->v == NULL\n        || weight_means == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    tsk_memset(result, 0, num_windows * num_focal_nodes * num_weights * sizeof(*result));\n    tsk_memset(self->parent, TSK_NULL, num_nodes * sizeof(*self->parent));\n\n    for (j = 0; j < (tsk_id_t) num_focal_nodes; j++) {\n        if (focal_nodes[j] < 0 || (tsk_size_t) focal_nodes[j] >= num_nodes) {\n            ret = tsk_trace_error(TSK_ERR_NODE_OUT_OF_BOUNDS);\n            goto out;\n        }\n    }\n\n    ret = tsk_tree_position_init(&self->tree_pos, ts, 0);\n    if (ret != 0) {\n        goto out;\n    }\n    /* seek to the first window */\n    index = (tsk_id_t) tsk_search_sorted(breakpoints, num_trees + 1, windows[0]);\n    if (breakpoints[index] > windows[0]) {\n        index--;\n    }\n    ret = tsk_tree_position_seek_forward(&self->tree_pos, index);\n    if (ret != 0) {\n        goto out;\n    }\n\n    for (k = 0; k < num_weights; k++) {\n        weight_means[k] = 0.0;\n    }\n    /* centre the input */\n    if (!(options & TSK_STAT_NONCENTRED)) {\n        for (j = 0; j < (tsk_id_t) num_samples; j++) {\n            row = GET_2D_ROW(weights, num_weights, j);\n            for (k = 0; k < num_weights; k++) {\n                weight_means[k] += row[k];\n            }\n        }\n        for (k = 0; k < num_weights; k++) {\n            weight_means[k] /= (double) num_samples;\n        }\n    }\n\n    /* set the initial state */\n    for (j = 0; j < (tsk_id_t) num_samples; j++) {\n        u = ts->samples[j];\n        row = GET_2D_ROW(weights, num_weights, j);\n        new_row = GET_2D_ROW(self->w, num_weights, u);\n        for (k = 0; k < num_weights; k++) {\n            new_row[k] = row[k] - weight_means[k];\n        }\n    }\nout:\n    tsk_safe_free(weight_means);\n    return ret;\n}\n\nstatic int\ntsk_matvec_calculator_free(tsk_matvec_calculator_t *self)\n{\n    tsk_safe_free(self->parent);\n    tsk_safe_free(self->x);\n    tsk_safe_free(self->w);\n    tsk_safe_free(self->v);\n    tsk_tree_position_free(&self->tree_pos);\n\n    /* Make this safe for multiple free calls */\n    memset(self, 0, sizeof(*self));\n    return 0;\n}\n\nstatic inline void\ntsk_matvec_calculator_add_z(tsk_id_t u, tsk_id_t p, const double position,\n    double *restrict x, const tsk_size_t num_weights, double *restrict w,\n    double *restrict v, const double *restrict nodes_time)\n{\n    double t, span;\n    tsk_size_t j;\n    double *restrict v_row, *restrict w_row;\n\n    if (p != TSK_NULL) {\n        t = nodes_time[p] - nodes_time[u];\n        span = position - x[u];\n        // do this: self->v[u] += t * span * self->w[u];\n        w_row = GET_2D_ROW(w, num_weights, u);\n        v_row = GET_2D_ROW(v, num_weights, u);\n        for (j = 0; j < num_weights; j++) {\n            v_row[j] += t * span * w_row[j];\n        }\n    }\n    x[u] = position;\n}\n\nstatic void\ntsk_matvec_calculator_adjust_path_up(\n    tsk_matvec_calculator_t *self, tsk_id_t p, tsk_id_t c, double sign)\n{\n    tsk_size_t j;\n    double *p_row, *c_row;\n    const tsk_id_t *restrict parent = self->parent;\n    const double position = self->position;\n    double *restrict x = self->x;\n    const tsk_size_t num_weights = self->num_weights;\n    double *restrict w = self->w;\n    double *restrict v = self->v;\n    const double *restrict nodes_time = self->ts->tables->nodes.time;\n\n    // sign = -1 for removing edges, +1 for adding\n    while (p != TSK_NULL) {\n        tsk_matvec_calculator_add_z(\n            p, parent[p], position, x, num_weights, w, v, nodes_time);\n        // do this: self->v[c] -= sign * self->v[p];\n        p_row = GET_2D_ROW(v, num_weights, p);\n        c_row = GET_2D_ROW(v, num_weights, c);\n        for (j = 0; j < num_weights; j++) {\n            c_row[j] -= sign * p_row[j];\n        }\n        // do this: self->w[p] += sign * self->w[c];\n        p_row = GET_2D_ROW(w, num_weights, p);\n        c_row = GET_2D_ROW(w, num_weights, c);\n        for (j = 0; j < num_weights; j++) {\n            p_row[j] += sign * c_row[j];\n        }\n        p = parent[p];\n    }\n}\n\nstatic void\ntsk_matvec_calculator_remove_edge(tsk_matvec_calculator_t *self, tsk_id_t p, tsk_id_t c)\n{\n    tsk_id_t *parent = self->parent;\n    const double position = self->position;\n    double *restrict x = self->x;\n    const tsk_size_t num_weights = self->num_weights;\n    double *restrict w = self->w;\n    double *restrict v = self->v;\n    const double *restrict nodes_time = self->ts->tables->nodes.time;\n\n    tsk_matvec_calculator_add_z(\n        c, parent[c], position, x, num_weights, w, v, nodes_time);\n    parent[c] = TSK_NULL;\n    tsk_matvec_calculator_adjust_path_up(self, p, c, -1);\n}\n\nstatic void\ntsk_matvec_calculator_insert_edge(tsk_matvec_calculator_t *self, tsk_id_t p, tsk_id_t c)\n{\n    tsk_id_t *parent = self->parent;\n\n    tsk_matvec_calculator_adjust_path_up(self, p, c, +1);\n    self->x[c] = self->position;\n    parent[c] = p;\n}\n\nstatic int\ntsk_matvec_calculator_write_output(tsk_matvec_calculator_t *self, double *restrict y)\n{\n    int ret = 0;\n    tsk_id_t u;\n    tsk_size_t j, k;\n    const tsk_size_t n = self->num_focal_nodes;\n    const tsk_size_t num_weights = self->num_weights;\n    const double position = self->position;\n    double *u_row, *out_row;\n    double *out_means = tsk_malloc(num_weights * sizeof(*out_means));\n    const tsk_id_t *restrict parent = self->parent;\n    const double *restrict nodes_time = self->ts->tables->nodes.time;\n    double *restrict x = self->x;\n    double *restrict w = self->w;\n    double *restrict v = self->v;\n    const tsk_id_t *restrict focal_nodes = self->focal_nodes;\n\n    if (out_means == NULL) {\n        ret = tsk_trace_error(TSK_ERR_NO_MEMORY);\n        goto out;\n    }\n\n    for (j = 0; j < n; j++) {\n        out_row = GET_2D_ROW(y, num_weights, j);\n        u = focal_nodes[j];\n        while (u != TSK_NULL) {\n            if (x[u] != position) {\n                tsk_matvec_calculator_add_z(\n                    u, parent[u], position, x, num_weights, w, v, nodes_time);\n            }\n            u_row = GET_2D_ROW(v, num_weights, u);\n            for (k = 0; k < num_weights; k++) {\n                out_row[k] += u_row[k];\n            }\n            u = parent[u];\n        }\n    }\n\n    if (!(self->options & TSK_STAT_NONCENTRED)) {\n        for (k = 0; k < num_weights; k++) {\n            out_means[k] = 0.0;\n        }\n        for (j = 0; j < n; j++) {\n            out_row = GET_2D_ROW(y, num_weights, j);\n            for (k = 0; k < num_weights; k++) {\n                out_means[k] += out_row[k];\n            }\n        }\n        for (k = 0; k < num_weights; k++) {\n            out_means[k] /= (double) n;\n        }\n        for (j = 0; j < n; j++) {\n            out_row = GET_2D_ROW(y, num_weights, j);\n            for (k = 0; k < num_weights; k++) {\n                out_row[k] -= out_means[k];\n            }\n        }\n    }\n    /* zero out v */\n    tsk_memset(self->v, 0, self->num_nodes * num_weights * sizeof(*self->v));\nout:\n    tsk_safe_free(out_means);\n    return ret;\n}\n\nstatic int\ntsk_matvec_calculator_run(tsk_matvec_calculator_t *self)\n{\n    int ret = 0;\n    tsk_size_t j, k, m;\n    tsk_id_t e, p, c;\n    const tsk_size_t out_size = self->num_weights * self->num_focal_nodes;\n    const tsk_size_t num_edges = self->ts->tables->edges.num_rows;\n    const double *restrict edge_right = self->ts->tables->edges.right;\n    const double *restrict edge_left = self->ts->tables->edges.left;\n    const tsk_id_t *restrict edge_child = self->ts->tables->edges.child;\n    const tsk_id_t *restrict edge_parent = self->ts->tables->edges.parent;\n    const double *restrict windows = self->windows;\n    double *restrict out;\n    tsk_tree_position_t tree_pos = self->tree_pos;\n    const tsk_id_t *restrict in_order = tree_pos.in.order;\n    const tsk_id_t *restrict out_order = tree_pos.out.order;\n    bool valid;\n    double next_position;\n\n    m = 0;\n    self->position = windows[0];\n\n    for (j = (tsk_size_t) tree_pos.in.start; j != (tsk_size_t) tree_pos.in.stop; j++) {\n        e = in_order[j];\n        tsk_bug_assert(edge_left[e] <= self->position);\n        if (self->position < edge_right[e]) {\n            p = edge_parent[e];\n            c = edge_child[e];\n            tsk_matvec_calculator_insert_edge(self, p, c);\n        }\n    }\n\n    valid = tsk_tree_position_next(&tree_pos);\n    j = (tsk_size_t) tree_pos.in.start;\n    k = (tsk_size_t) tree_pos.out.start;\n    while (m < self->num_windows) {\n        if (valid && self->position == tree_pos.interval.left) {\n            for (k = (tsk_size_t) tree_pos.out.start;\n                 k != (tsk_size_t) tree_pos.out.stop; k++) {\n                e = out_order[k];\n                p = edge_parent[e];\n                c = edge_child[e];\n                tsk_matvec_calculator_remove_edge(self, p, c);\n            }\n            for (j = (tsk_size_t) tree_pos.in.start; j != (tsk_size_t) tree_pos.in.stop;\n                 j++) {\n                e = in_order[j];\n                p = edge_parent[e];\n                c = edge_child[e];\n                tsk_matvec_calculator_insert_edge(self, p, c);\n            }\n            valid = tsk_tree_position_next(&tree_pos);\n        }\n        next_position = windows[m + 1];\n        if (j < num_edges) {\n            next_position = TSK_MIN(next_position, edge_left[in_order[j]]);\n        }\n        if (k < num_edges) {\n            next_position = TSK_MIN(next_position, edge_right[out_order[k]]);\n        }\n        tsk_bug_assert(self->position < next_position);\n        self->position = next_position;\n        if (self->position == windows[m + 1]) {\n            out = GET_2D_ROW(self->result, out_size, m);\n            tsk_matvec_calculator_write_output(self, out);\n            m += 1;\n        }\n        if (self->options & TSK_DEBUG) {\n            tsk_matvec_calculator_print_state(self, tsk_get_debug_stream());\n        }\n    }\n    if (!!(self->options & TSK_STAT_SPAN_NORMALISE)) {\n        span_normalise(self->num_windows, windows, out_size, self->result);\n    }\n\n    /* out: */\n    return ret;\n}\n\nint\ntsk_treeseq_genetic_relatedness_vector(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_size_t num_focal_nodes, const tsk_id_t *focal_nodes, double *result,\n    tsk_flags_t options)\n{\n    int ret = 0;\n    bool stat_site = !!(options & TSK_STAT_SITE);\n    bool stat_node = !!(options & TSK_STAT_NODE);\n    tsk_matvec_calculator_t calc;\n\n    memset(&calc, 0, sizeof(calc));\n\n    if (stat_node || stat_site) {\n        ret = tsk_trace_error(TSK_ERR_UNSUPPORTED_STAT_MODE);\n        goto out;\n    }\n    ret = tsk_treeseq_check_windows(self, num_windows, windows, 0);\n    if (ret != 0) {\n        goto out;\n    }\n\n    ret = tsk_matvec_calculator_init(&calc, self, num_weights, weights, num_windows,\n        windows, num_focal_nodes, focal_nodes, options, result);\n    if (ret != 0) {\n        goto out;\n    }\n    if (options & TSK_DEBUG) {\n        tsk_matvec_calculator_print_state(&calc, tsk_get_debug_stream());\n    }\n    ret = tsk_matvec_calculator_run(&calc);\nout:\n    tsk_matvec_calculator_free(&calc);\n    return ret;\n}\n"
  },
  {
    "path": "treerec/tskit/trees.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2019-2024 Tskit Developers\n * Copyright (c) 2015-2018 University of Oxford\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @file trees.h\n * @brief Tskit core tree sequence operations.\n */\n#ifndef TSK_TREES_H\n#define TSK_TREES_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <tskit/tables.h>\n\n// clang-format off\n\n/*\n * These are both undocumented options for tsk_tree_init\n */\n#define TSK_SAMPLE_LISTS            (1 << 1)\n#define TSK_NO_SAMPLE_COUNTS        (1 << 2)\n\n#define TSK_STAT_SITE               (1 << 0)\n#define TSK_STAT_BRANCH             (1 << 1)\n#define TSK_STAT_NODE               (1 << 2)\n\n/* Leave room for other stat types */\n#define TSK_STAT_POLARISED               (1 << 10)\n#define TSK_STAT_SPAN_NORMALISE          (1 << 11)\n#define TSK_STAT_ALLOW_TIME_UNCALIBRATED (1 << 12)\n#define TSK_STAT_PAIR_NORMALISE          (1 << 13)\n#define TSK_STAT_NONCENTRED              (1 << 14)\n\n/* Options for map_mutations */\n#define TSK_MM_FIXED_ANCESTRAL_STATE (1 << 0)\n\n#define TSK_DIR_FORWARD 1\n#define TSK_DIR_REVERSE -1\n\n/**\n@defgroup API_FLAGS_TS_INIT_GROUP :c:func:`tsk_treeseq_init` specific flags.\n@{\n*/\n/**\nIf specified edge indexes will be built and stored in the table collection\nwhen the tree sequence is initialised. Indexes are required for a valid\ntree sequence, and are not built by default for performance reasons.\n*/\n#define TSK_TS_INIT_BUILD_INDEXES (1 << 0)\n/**\nIf specified, mutation parents in the table collection will be overwritten\nwith those computed from the topology when the tree sequence is initialised.\n*/\n#define TSK_TS_INIT_COMPUTE_MUTATION_PARENTS (1 << 1)\n/** @} */\n\n// clang-format on\n\n/**\n@brief The tree sequence object.\n*/\ntypedef struct {\n    tsk_size_t num_trees;\n    tsk_size_t num_samples;\n    tsk_id_t *samples;\n    /* Does this tree sequence have time_units == \"uncalibrated\" */\n    bool time_uncalibrated;\n    /* Are all genome coordinates discrete? */\n    bool discrete_genome;\n    /* Are all time values discrete? */\n    bool discrete_time;\n    /* Min and max time in node table and mutation table */\n    double min_time;\n    double max_time;\n    /* Breakpoints along the sequence, including 0 and L. */\n    double *breakpoints;\n    /* If a node is a sample, map to its index in the samples list */\n    tsk_id_t *sample_index_map;\n    /* Map individuals to the list of nodes that reference them */\n    tsk_id_t *individual_nodes_mem;\n    tsk_id_t **individual_nodes;\n    tsk_size_t *individual_nodes_length;\n    /* For each tree, a list of sites on that tree */\n    tsk_site_t *tree_sites_mem;\n    tsk_site_t **tree_sites;\n    tsk_size_t *tree_sites_length;\n    /* For each site, a list of mutations at that site */\n    tsk_mutation_t *site_mutations_mem;\n    tsk_mutation_t **site_mutations;\n    tsk_size_t *site_mutations_length;\n    /** @brief  The table collection underlying this tree sequence, This table\n     *  collection must be treated as read-only, and any changes to it will\n     *  lead to undefined behaviour. */\n    tsk_table_collection_t *tables;\n} tsk_treeseq_t;\n\ntypedef struct {\n    tsk_id_t index;\n    struct {\n        double left;\n        double right;\n    } interval;\n    struct {\n        tsk_id_t start;\n        tsk_id_t stop;\n        const tsk_id_t *order;\n    } in;\n    struct {\n        tsk_id_t start;\n        tsk_id_t stop;\n        const tsk_id_t *order;\n    } out;\n    tsk_id_t left_current_index;\n    tsk_id_t right_current_index;\n    int direction;\n    const tsk_treeseq_t *tree_sequence;\n} tsk_tree_position_t;\n\n/**\n@brief A single tree in a tree sequence.\n\n@rst\nA ``tsk_tree_t`` object has two basic functions:\n\n1. Represent the state of a single tree in a tree sequence;\n2. Provide methods to transform this state into different trees in the sequence.\n\nThe state of a single tree in the tree sequence is represented using the\nquintuply linked encoding: please see the\n:ref:`data model <sec_data_model_tree_structure>` section for details on\nhow this works. The left-to-right ordering of nodes in this encoding\nis arbitrary, and may change depending on the order in which trees are\naccessed within the sequence. Please see the\n:ref:`sec_c_api_examples_tree_traversals` examples for recommended\nusage.\n\nOn initialisation, a tree is in the :ref:`null state<sec_c_api_trees_null>` and\nwe must call one of the :ref:`seeking<sec_c_api_trees_seeking>` methods to make\nthe state of the tree object correspond to a particular tree in the sequence.\nPlease see the :ref:`sec_c_api_examples_tree_iteration` examples for\nrecommended usage.\n\n@endrst\n */\ntypedef struct {\n    /**\n     * @brief The parent tree sequence.\n     */\n    const tsk_treeseq_t *tree_sequence;\n    /**\n     @brief The ID of the \"virtual root\" whose children are the roots of the\n     tree.\n     */\n    tsk_id_t virtual_root;\n    /**\n     @brief The parent of node u is parent[u]. Equal to ``TSK_NULL`` if node u is\n     a root or is not a node in the current tree.\n     */\n    tsk_id_t *parent;\n    /**\n     @brief The leftmost child of node u is left_child[u]. Equal to ``TSK_NULL``\n     if node u is a leaf or is not a node in the current tree.\n     */\n    tsk_id_t *left_child;\n    /**\n     @brief The rightmost child of node u is right_child[u]. Equal to ``TSK_NULL``\n     if node u is a leaf or is not a node in the current tree.\n     */\n    tsk_id_t *right_child;\n    /**\n     @brief The sibling to the left of node u is left_sib[u]. Equal to\n     ``TSK_NULL`` if node u has no siblings to its left.\n     */\n    tsk_id_t *left_sib;\n    /**\n     @brief The sibling to the right of node u is right_sib[u]. Equal to\n     ``TSK_NULL`` if node u has no siblings to its right.\n     */\n    tsk_id_t *right_sib;\n    /**\n     @brief The number of children of node u is num_children[u].\n     */\n    tsk_id_t *num_children;\n    /**\n     @brief Array of edge ids where ``edge[u]`` is the edge that encodes the\n     relationship between the child node ``u`` and its parent. Equal to\n     ``TSK_NULL`` if node ``u`` is a root, virtual root or is not a node in the\n     current tree.\n     */\n    tsk_id_t *edge;\n    /**\n     @brief The total number of edges defining the topology of this tree.\n     This is equal to the number of tree sequence edges that intersect with\n     the tree's genomic interval.\n     */\n    tsk_size_t num_edges;\n    /**\n     @brief Left and right coordinates of the genomic interval that this\n     tree covers. The left coordinate is inclusive and the right coordinate\n     exclusive.\n\n    @rst\n\n    Example:\n\n    .. code-block:: c\n\n        tsk_tree_t tree;\n        int ret;\n        // initialise etc\n        ret = tsk_tree_first(&tree);\n        // Check for error\n        assert(ret == TSK_TREE_OK);\n        printf(\"Coordinates covered by first tree are left=%f, right=%f\\n\",\n            tree.interval.left, tree.interval.right);\n\n    @endrst\n\n     */\n    struct {\n        double left;\n        double right;\n    } interval;\n    /**\n     @brief The index of this tree in the tree sequence.\n\n     @rst\n     This attribute provides the zero-based index of the tree represented by the\n     current state of the struct within the parent tree sequence. For example,\n     immediately after we call ``tsk_tree_first(&tree)``, ``tree.index`` will\n     be zero, and after we call ``tsk_tree_last(&tree)``, ``tree.index`` will\n     be the number of trees - 1 (see :c:func:`tsk_treeseq_get_num_trees`)\n     When the tree is in the null state (immediately after initialisation,\n     or after, e.g., calling :c:func:`tsk_tree_prev` on the first tree)\n     the value of the ``index`` is -1.\n     @endrst\n     */\n    tsk_id_t index;\n    /* Attributes below are private and should not be used in client code. */\n    tsk_size_t num_nodes;\n    tsk_flags_t options;\n    tsk_size_t root_threshold;\n    const tsk_id_t *samples;\n    /*\n    These are involved in the optional sample tracking; num_samples counts\n    all samples below a give node, and num_tracked_samples counts those\n    from a specific subset. By default sample counts are tracked and roots\n    maintained. If ``TSK_NO_SAMPLE_COUNTS`` is specified, then neither sample\n    counts or roots are available.\n    */\n    tsk_size_t *num_samples;\n    tsk_size_t *num_tracked_samples;\n    /* These are for the optional sample list tracking. */\n    tsk_id_t *left_sample;\n    tsk_id_t *right_sample;\n    tsk_id_t *next_sample;\n    /* The sites on this tree */\n    const tsk_site_t *sites;\n    tsk_size_t sites_length;\n    /* Counters needed for next() and prev() transformations. */\n    int direction;\n    tsk_id_t left_index;\n    tsk_id_t right_index;\n    tsk_tree_position_t tree_pos;\n} tsk_tree_t;\n\n/****************************************************************************/\n/* Tree sequence.*/\n/****************************************************************************/\n\n/**\n@defgroup TREESEQ_API_GROUP Tree sequence API\n@{\n*/\n\n/**\n@brief Initialises the tree sequence based on the specified table collection.\n\n@rst\nThis method will copy the supplied table collection unless :c:macro:`TSK_TAKE_OWNERSHIP`\nis specified. The table collection will be checked for integrity and index maps built.\n\nThis must be called before any operations are performed on the tree sequence.\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n\nIf specified, TSK_TAKE_OWNERSHIP takes immediate ownership of the tables, regardless\nof error conditions.\n\n**Options**\n\n- :c:macro:`TSK_TS_INIT_BUILD_INDEXES`\n- :c:macro:`TSK_TAKE_OWNERSHIP` (applies to the table collection).\n@endrst\n\n@param self A pointer to an uninitialised tsk_table_collection_t object.\n@param tables A pointer to a tsk_table_collection_t object.\n@param options Allocation time options. See above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_init(\n    tsk_treeseq_t *self, tsk_table_collection_t *tables, tsk_flags_t options);\n\n/**\n@brief Load a tree sequence from a file path.\n\n@rst\nLoads the data from the specified file into this tree sequence.\nThe tree sequence is also initialised.\nThe resources allocated must be freed using\n:c:func:`tsk_treeseq_free` even in error conditions.\n\nWorks similarly to :c:func:`tsk_table_collection_load` please see\nthat function's documentation for details and options.\n\n**Examples**\n\n.. code-block:: c\n\n    int ret;\n    tsk_treeseq_t ts;\n    ret = tsk_treeseq_load(&ts, \"data.trees\", 0);\n    if (ret != 0) {\n        fprintf(stderr, \"Load error:%s\\n\", tsk_strerror(ret));\n        exit(EXIT_FAILURE);\n    }\n\n@endrst\n\n@param self A pointer to an uninitialised tsk_treeseq_t object\n@param filename A NULL terminated string containing the filename.\n@param options Bitwise options. See above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_load(tsk_treeseq_t *self, const char *filename, tsk_flags_t options);\n\n/**\n@brief Load a tree sequence from a stream.\n\n@rst\nLoads a tree sequence from the specified file stream. The tree sequence\nis also initialised. The resources allocated must be freed using\n:c:func:`tsk_treeseq_free` even in error conditions.\n\nWorks similarly to :c:func:`tsk_table_collection_loadf` please\nsee that function's documentation for details and options.\n\n@endrst\n\n@param self A pointer to an uninitialised tsk_treeseq_t object.\n@param file A FILE stream opened in an appropriate mode for reading (e.g.\n    \"r\", \"r+\" or \"w+\") positioned at the beginning of a tree sequence\n    definition.\n@param options Bitwise options. See above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_loadf(tsk_treeseq_t *self, FILE *file, tsk_flags_t options);\n\n/**\n@brief Write a tree sequence to file.\n\n@rst\nWrites the data from this tree sequence to the specified file.\n\nIf an error occurs the file path is deleted, ensuring that only complete\nand well formed files will be written.\n@endrst\n\n@param self A pointer to an initialised tsk_treeseq_t object.\n@param filename A NULL terminated string containing the filename.\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_dump(\n    const tsk_treeseq_t *self, const char *filename, tsk_flags_t options);\n\n/**\n@brief Write a tree sequence to a stream.\n\n@rst\nWrites the data from this tree sequence to the specified FILE stream.\nSemantics are identical to :c:func:`tsk_treeseq_dump`.\n\nPlease see the :ref:`sec_c_api_examples_file_streaming` section for an example\nof how to sequentially dump and load tree sequences from a stream.\n@endrst\n\n@param self A pointer to an initialised tsk_treeseq_t object.\n@param file A FILE stream opened in an appropriate mode for writing (e.g.\n    \"w\", \"a\", \"r+\" or \"w+\").\n@param options Bitwise options. Currently unused; should be\n    set to zero to ensure compatibility with later versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_dumpf(const tsk_treeseq_t *self, FILE *file, tsk_flags_t options);\n\n/**\n@brief Copies the state of the table collection underlying this tree sequence\ninto the specified destination table collection.\n\n@rst\nBy default the method initialises the specified destination table collection. If the\ndestination is already initialised, the :c:macro:`TSK_NO_INIT` option should\nbe supplied to avoid leaking memory.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@param tables A pointer to a tsk_table_collection_t object. If the TSK_NO_INIT\noption is specified, this must be an initialised table collection. If not, it must be an\nuninitialised table collection.\n@param options Bitwise option flags.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_copy_tables(\n    const tsk_treeseq_t *self, tsk_table_collection_t *tables, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified tree sequence.\n\n@param self A pointer to an initialised tsk_treeseq_t object.\n@return Always returns 0.\n*/\nint tsk_treeseq_free(tsk_treeseq_t *self);\n\n/**\n@brief Print out the state of this tree sequence to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_treeseq_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_treeseq_print_state(const tsk_treeseq_t *self, FILE *out);\n\n/**\n@brief Get the number of nodes\n\n@rst\nReturns the number of nodes in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of nodes.\n*/\ntsk_size_t tsk_treeseq_get_num_nodes(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of edges\n\n@rst\nReturns the number of edges in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of edges.\n*/\n\ntsk_size_t tsk_treeseq_get_num_edges(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of migrations\n\n@rst\nReturns the number of migrations in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of migrations.\n*/\ntsk_size_t tsk_treeseq_get_num_migrations(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of sites\n\n@rst\nReturns the number of sites in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of sites.\n*/\ntsk_size_t tsk_treeseq_get_num_sites(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of mutations\n\n@rst\nReturns the number of mutations in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of mutations.\n*/\ntsk_size_t tsk_treeseq_get_num_mutations(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of provenances\n\n@rst\nReturns the number of provenances in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of provenances.\n*/\ntsk_size_t tsk_treeseq_get_num_provenances(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of populations\n\n@rst\nReturns the number of populations in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of populations.\n*/\ntsk_size_t tsk_treeseq_get_num_populations(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of individuals\n\n@rst\nReturns the number of individuals in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of individuals.\n*/\ntsk_size_t tsk_treeseq_get_num_individuals(const tsk_treeseq_t *self);\n\n/**\n@brief Return the number of trees in this tree sequence.\n\n@rst\nThis is a constant time operation.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return The number of trees in the tree sequence.\n*/\ntsk_size_t tsk_treeseq_get_num_trees(const tsk_treeseq_t *self);\n\n/**\n@brief Get the number of samples\n\n@rst\nReturns the number of nodes marked as samples in this tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the number of samples.\n*/\ntsk_size_t tsk_treeseq_get_num_samples(const tsk_treeseq_t *self);\n\n/**\n@brief Get the top-level tree sequence metadata.\n\n@rst\nReturns a pointer to the metadata string, which is owned by the tree sequence and\nnot null-terminated.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns a pointer to the metadata.\n*/\nconst char *tsk_treeseq_get_metadata(const tsk_treeseq_t *self);\n\n/**\n@brief Get the length of top-level tree sequence metadata\n\n@rst\nReturns the length of the metadata string.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the length of the metadata.\n*/\ntsk_size_t tsk_treeseq_get_metadata_length(const tsk_treeseq_t *self);\n\n/**\n@brief Get the top-level tree sequence metadata schema.\n\n@rst\nReturns a pointer to the metadata schema string, which is owned by the tree sequence and\nnot null-terminated.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns a pointer to the metadata schema.\n*/\nconst char *tsk_treeseq_get_metadata_schema(const tsk_treeseq_t *self);\n\n/**\n@brief Get the length of the top-level tree sequence metadata schema.\n\n@rst\nReturns the length of the metadata schema string.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the length of the metadata schema.\n*/\ntsk_size_t tsk_treeseq_get_metadata_schema_length(const tsk_treeseq_t *self);\n\n/**\n@brief Get the time units string\n\n@rst\nReturns a pointer to the time units string, which is owned by the tree sequence and\nnot null-terminated.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns a pointer to the time units.\n*/\nconst char *tsk_treeseq_get_time_units(const tsk_treeseq_t *self);\n\n/**\n@brief Get the length of time units string\n@rst\nReturns the length of the time units string.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the length of the time units.\n*/\ntsk_size_t tsk_treeseq_get_time_units_length(const tsk_treeseq_t *self);\n\n/**\n@brief Get the file uuid\n\n@rst\nReturns a pointer to the null-terminated file uuid string, which is owned by the tree\nsequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns a pointer to the time units.\n*/\nconst char *tsk_treeseq_get_file_uuid(const tsk_treeseq_t *self);\n\n/**\n@brief Get the sequence length\n\n@rst\nReturns the sequence length of this tree sequence\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the sequence length.\n*/\ndouble tsk_treeseq_get_sequence_length(const tsk_treeseq_t *self);\n\n/**\n@brief Get the breakpoints\n\n@rst\nReturns an array of breakpoint locations, the array is owned by the tree sequence.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the pointer to the breakpoint array.\n*/\nconst double *tsk_treeseq_get_breakpoints(const tsk_treeseq_t *self);\n\n/**\n@brief Get the samples\n\n@rst\nReturns an array of ids of sample nodes in this tree sequence.\nI.e. nodes that have the :c:macro:`TSK_NODE_IS_SAMPLE` flag set.\nThe array is owned by the tree sequence and should not be modified or free'd.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the pointer to the sample node id array.\n*/\nconst tsk_id_t *tsk_treeseq_get_samples(const tsk_treeseq_t *self);\n\n/**\n@brief Get the map of node id to sample index\n\n@rst\nReturns the location of each node in the list of samples or\n:c:macro:`TSK_NULL` for nodes that are not samples.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the pointer to the array of sample indexes.\n*/\nconst tsk_id_t *tsk_treeseq_get_sample_index_map(const tsk_treeseq_t *self);\n\n/**\n@brief Check if a node is a sample\n\n@rst\nReturns the sample status of a given node id.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param u The id of the node to be checked.\n@return Returns true if the node is a sample.\n*/\nbool tsk_treeseq_is_sample(const tsk_treeseq_t *self, tsk_id_t u);\n\n/**\n@brief Get the discrete genome status\n\n@rst\nIf all the genomic locations in the tree sequence are discrete integer values\nthen this flag will be true.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns true if all genomic locations are discrete.\n*/\nbool tsk_treeseq_get_discrete_genome(const tsk_treeseq_t *self);\n\n/**\n@brief Get the discrete time status\n\n@rst\nIf all times in the tree sequence are discrete integer values\nthen this flag will be true\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns true if all times are discrete.\n*/\nbool tsk_treeseq_get_discrete_time(const tsk_treeseq_t *self);\n\n/**\n@brief Get the min time in node table and mutation table\n\n@rst\nThe times stored in both the node and mutation tables are considered.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the min time of all nodes and mutations.\n*/\ndouble tsk_treeseq_get_min_time(const tsk_treeseq_t *self);\n\n/**\n@brief Get the max time in node table and mutation table\n\n@rst\nThe times stored in both the node and mutation tables are considered.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@return Returns the max time of all nodes and mutations.\n*/\ndouble tsk_treeseq_get_max_time(const tsk_treeseq_t *self);\n\n/**\n@brief Get a node by its index\n\n@rst\nCopies a node from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The node index to copy\n@param node A pointer to a tsk_node_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_node(const tsk_treeseq_t *self, tsk_id_t index, tsk_node_t *node);\n\n/**\n@brief Get a edge by its index\n\n@rst\nCopies a edge from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The edge index to copy\n@param edge A pointer to a tsk_edge_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_edge(const tsk_treeseq_t *self, tsk_id_t index, tsk_edge_t *edge);\n\n/**\n@brief Get a edge by its index\n\n@rst\nCopies a migration from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The migration index to copy\n@param migration A pointer to a tsk_migration_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_migration(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_migration_t *migration);\n\n/**\n@brief Get a site by its index\n\n@rst\nCopies a site from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The site index to copy\n@param site A pointer to a tsk_site_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_site(const tsk_treeseq_t *self, tsk_id_t index, tsk_site_t *site);\n\n/**\n@brief Get a mutation by its index\n\n@rst\nCopies a mutation from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The mutation index to copy\n@param mutation A pointer to a tsk_mutation_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_mutation(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_mutation_t *mutation);\n\n/**\n@brief Get a provenance by its index\n\n@rst\nCopies a provenance from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The provenance index to copy\n@param provenance A pointer to a tsk_provenance_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_provenance(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_provenance_t *provenance);\n\n/**\n@brief Get a population by its index\n\n@rst\nCopies a population from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The population index to copy\n@param population A pointer to a tsk_population_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_population(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_population_t *population);\n\n/**\n@brief Get a individual by its index\n\n@rst\nCopies a individual from this tree sequence to the specified destination.\n@endrst\n@param self A pointer to a tsk_treeseq_t object.\n@param index The individual index to copy\n@param individual A pointer to a tsk_individual_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_get_individual(\n    const tsk_treeseq_t *self, tsk_id_t index, tsk_individual_t *individual);\n\n/**\n@brief Create a simplified instance of this tree sequence\n\n@rst\nCopies this tree sequence to the specified destination and performs simplification.\nThe destination tree sequence should be uninitialised.\nSimplification transforms the tables to remove redundancy and canonicalise\ntree sequence data. See the :ref:`simplification <sec_simplification>` tutorial for\nmore details.\n\nFor full details and flags see :c:func:`tsk_table_collection_simplify` which performs\nthe same operation in place.\n\n@endrst\n@param self A pointer to a uninitialised tsk_treeseq_t object.\n@param samples Either NULL or an array of num_samples distinct and valid node IDs.\n    If non-null the nodes in this array will be marked as samples in the output.\n    If NULL, the num_samples parameter is ignored and the samples in the output\n    will be the same as the samples in the input. This is equivalent to populating\n    the samples array with all of the sample nodes in the input in increasing\n    order of ID.\n@param num_samples The number of node IDs in the input samples array. Ignored\n    if the samples array is NULL.\n@param options Simplify options; see above for the available bitwise flags.\n    For the default behaviour, a value of 0 should be provided.\n@param output A pointer to an uninitialised tsk_treeseq_t object.\n@param node_map If not NULL, this array will be filled to define the mapping\n    between nodes IDs in the table collection before and after simplification.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_simplify(const tsk_treeseq_t *self, const tsk_id_t *samples,\n    tsk_size_t num_samples, tsk_flags_t options, tsk_treeseq_t *output,\n    tsk_id_t *node_map);\n\n/**\n@brief Extends haplotypes\n\nReturns a new tree sequence in which the span covered by ancestral nodes\nis \"extended\" to regions of the genome according to the following rule:\nIf an ancestral segment corresponding to node `n` has ancestor `p` and\ndescendant `c` on some portion of the genome, and on an adjacent segment of\ngenome `p` is still an ancestor of `c`, then `n` is inserted into the\npath from `p` to `c`. For instance, if `p` is the parent of `n` and `n`\nis the parent of `c`, then the span of the edges from `p` to `n` and\n`n` to `c` are extended, and the span of the edge from `p` to `c` is\nreduced. However, any edges whose child node is a sample are not\nmodified.  See Fritze et al. (2025):\nhttps://doi.org/10.1093/genetics/iyaf198 for more details.\n\nThe method works by iterating over the genome to look for edges that can\nbe extended in this way; the maximum number of such iterations is\ncontrolled by ``max_iter``.\n\nThe `node` of certain mutations may also be remapped; to do this\nunambiguously we need to know mutation times. If mutations times are unknown,\nuse `tsk_table_collection_compute_mutation_times` first.\n\nThe method will not affect any tables except the edge table, or the node\ncolumn in the mutation table.\n\n@rst\n\n**Options**: None currently defined.\n@endrst\n\n@param self A pointer to a tsk_treeseq_t object.\n@param max_iter The maximum number of iterations over the tree sequence.\n@param options Bitwise option flags. (UNUSED)\n@param output A pointer to an uninitialised tsk_treeseq_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_extend_haplotypes(\n    const tsk_treeseq_t *self, int max_iter, tsk_flags_t options, tsk_treeseq_t *output);\n\n/** @} */\n\nint tsk_treeseq_split_edges(const tsk_treeseq_t *self, double time, tsk_flags_t flags,\n    tsk_id_t population, const char *metadata, tsk_size_t metadata_length,\n    tsk_flags_t options, tsk_treeseq_t *output);\n\nbool tsk_treeseq_has_reference_sequence(const tsk_treeseq_t *self);\n\n/**\n@brief Decode full-length alignments for specified nodes over an interval.\n\n@rst\nFills a caller-provided buffer with per-node sequence alignments for the interval\n``[left, right)``. Each row is exactly ``L = right - left`` bytes with no trailing\nterminator, and rows are tightly packed in row-major order in the output buffer.\n\nThe output at non-site positions comes from the provided ``ref_seq`` slice\n(``ref_seq[left:right]``); per-site alleles are overlaid onto this for each node.\n\nIf the :c:macro:`TSK_ISOLATED_NOT_MISSING` option is\nnot set, nodes that are isolated (no parent and no children) within a tree\ninterval in ``[left, right)`` are rendered as the ``missing_data_character`` for\nthat interval. At site positions, decoded genotypes override any previous value;\nif a genotype is missing (``TSK_MISSING_DATA``), the ``missing_data_character`` is\noverlaid onto the reference base.\n\nRequirements and validation:\n\n- The tree sequence must have a discrete genome.\n- ``left`` and ``right`` must be integers with ``0 <= left < right <= sequence_length``.\n- ``ref_seq`` must be non-NULL and ``ref_seq_length == sequence_length``.\n- Each allele at a site must be exactly one byte; alleles equal to\n  ``missing_data_character`` are not permitted.\n\n@endrst\n\n@param self A pointer to a :c:type:`tsk_treeseq_t` object.\n@param ref_seq Pointer to a reference sequence buffer of length ``ref_seq_length``.\n@param ref_seq_length The total length of ``ref_seq``; must equal the tree sequence\nlength.\n@param nodes Array of node IDs to decode (may include non-samples).\n@param num_nodes The number of nodes in ``nodes`` and rows in the output.\n@param left The inclusive-left genomic coordinate of the output interval.\n@param right The exclusive-right genomic coordinate of the output interval.\n@param missing_data_character The byte to use for missing data.\n@param alignments_out Output buffer of size at least ``num_nodes * (right - left)``.\n@param options Bitwise option flags; supports :c:macro:`TSK_ISOLATED_NOT_MISSING`.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_treeseq_decode_alignments(const tsk_treeseq_t *self, const char *ref_seq,\n    tsk_size_t ref_seq_length, const tsk_id_t *nodes, tsk_size_t num_nodes, double left,\n    double right, char missing_data_character, char *alignments_out,\n    tsk_flags_t options);\n\nint tsk_treeseq_get_individuals_population(const tsk_treeseq_t *self, tsk_id_t *output);\nint tsk_treeseq_get_individuals_time(const tsk_treeseq_t *self, double *output);\n\nint tsk_treeseq_kc_distance(const tsk_treeseq_t *self, const tsk_treeseq_t *other,\n    double lambda_, double *result);\n\nint tsk_treeseq_genealogical_nearest_neighbours(const tsk_treeseq_t *self,\n    const tsk_id_t *focal, tsk_size_t num_focal, const tsk_id_t *const *reference_sets,\n    const tsk_size_t *reference_set_size, tsk_size_t num_reference_sets,\n    tsk_flags_t options, double *ret_array);\nint tsk_treeseq_mean_descendants(const tsk_treeseq_t *self,\n    const tsk_id_t *const *reference_sets, const tsk_size_t *reference_set_size,\n    tsk_size_t num_reference_sets, tsk_flags_t options, double *ret_array);\n\ntypedef int general_stat_func_t(tsk_size_t state_dim, const double *state,\n    tsk_size_t result_dim, double *result, void *params);\n\nint tsk_treeseq_general_stat(const tsk_treeseq_t *self, tsk_size_t K, const double *W,\n    tsk_size_t M, general_stat_func_t *f, void *f_params, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\n\ntypedef int norm_func_t(tsk_size_t result_dim, const double *hap_weights, tsk_size_t n_a,\n    tsk_size_t n_b, double *result, void *params);\n\nint tsk_treeseq_two_locus_count_stat(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t result_dim, const tsk_id_t *set_indexes,\n    general_stat_func_t *f, norm_func_t *norm_f, tsk_size_t out_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t out_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\n\n/* One way weighted stats */\n\ntypedef int one_way_weighted_method(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result);\n\nint tsk_treeseq_trait_covariance(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result);\nint tsk_treeseq_trait_correlation(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result);\n\n/* One way weighted stats with covariates */\n\ntypedef int one_way_covariates_method(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_covariates, const double *covariates,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\n\nint tsk_treeseq_trait_linear_model(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_covariates, const double *covariates,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\n\n/* Two way weighted stats with covariates */\n\ntypedef int two_way_weighted_method(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_index_tuples, const tsk_id_t *index_tuples,\n    tsk_size_t num_windows, const double *windows, double *result, tsk_flags_t options);\n\nint tsk_treeseq_genetic_relatedness_weighted(const tsk_treeseq_t *self,\n    tsk_size_t num_weights, const double *weights, tsk_size_t num_index_tuples,\n    const tsk_id_t *index_tuples, tsk_size_t num_windows, const double *windows,\n    double *result, tsk_flags_t options);\n\n/* One way weighted stats with vector output */\n\ntypedef int weighted_vector_method(const tsk_treeseq_t *self, tsk_size_t num_weights,\n    const double *weights, tsk_size_t num_windows, const double *windows,\n    tsk_size_t num_focal_nodes, const tsk_id_t *focal_nodes, double *result,\n    tsk_flags_t options);\n\nint tsk_treeseq_genetic_relatedness_vector(const tsk_treeseq_t *self,\n    tsk_size_t num_weights, const double *weights, tsk_size_t num_windows,\n    const double *windows, tsk_size_t num_focal_nodes, const tsk_id_t *focal_nodes,\n    double *result, tsk_flags_t options);\n\n/* One way sample set stats */\n\ntypedef int one_way_sample_stat_method(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result);\n\nint tsk_treeseq_diversity(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_segregating_sites(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_Y1(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_allele_frequency_spectrum(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_windows, const double *windows,\n    tsk_size_t num_time_windows, const double *time_windows, tsk_flags_t options,\n    double *result);\n\ntypedef int general_sample_stat_method(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_indexes, const tsk_id_t *indexes,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\n\ntypedef int two_locus_count_stat_method(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_rows, const tsk_id_t *row_sites,\n    const double *row_positions, tsk_size_t num_cols, const tsk_id_t *col_sites,\n    const double *col_positions, tsk_flags_t options, double *result);\n\nint tsk_treeseq_D(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_D2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_r2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_D_prime(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_r(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_Dz(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_pi2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_D2_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_Dz_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_pi2_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\n\ntypedef int k_way_two_locus_count_stat_method(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_index_tuples,\n    const tsk_id_t *index_tuples, tsk_size_t num_rows, const tsk_id_t *row_sites,\n    const double *row_positions, tsk_size_t num_cols, const tsk_id_t *col_sites,\n    const double *col_positions, tsk_flags_t options, double *result);\n\n/* Two way sample set stats */\n\nint tsk_treeseq_divergence(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_Y2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_f2(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_genetic_relatedness(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_index_tuples,\n    const tsk_id_t *index_tuples, tsk_size_t num_windows, const double *windows,\n    tsk_flags_t options, double *result);\nint tsk_treeseq_D2_ij(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_D2_ij_unbiased(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_r2_ij(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_rows,\n    const tsk_id_t *row_sites, const double *row_positions, tsk_size_t num_cols,\n    const tsk_id_t *col_sites, const double *col_positions, tsk_flags_t options,\n    double *result);\n\n/* Three way sample set stats */\nint tsk_treeseq_Y3(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\nint tsk_treeseq_f3(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\n\n/* Four way sample set stats */\nint tsk_treeseq_f4(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_index_tuples, const tsk_id_t *index_tuples, tsk_size_t num_windows,\n    const double *windows, tsk_flags_t options, double *result);\n\nint tsk_treeseq_divergence_matrix(const tsk_treeseq_t *self, tsk_size_t num_sample_sets,\n    const tsk_size_t *sample_set_sizes, const tsk_id_t *sample_sets,\n    tsk_size_t num_windows, const double *windows, tsk_flags_t options, double *result);\n\n/* Coalescence rates */\ntypedef int pair_coalescence_stat_func_t(tsk_size_t input_dim, const double *atoms,\n    const double *weights, tsk_size_t result_dim, double *result, void *params);\nint tsk_treeseq_pair_coalescence_stat(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_bins,\n    const tsk_id_t *node_bin_map, pair_coalescence_stat_func_t *summary_func,\n    tsk_size_t summary_func_dim, void *summary_func_args, tsk_flags_t options,\n    double *result);\nint tsk_treeseq_pair_coalescence_counts(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_bins,\n    const tsk_id_t *node_bin_map, tsk_flags_t options, double *result);\nint tsk_treeseq_pair_coalescence_quantiles(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_bins,\n    const tsk_id_t *node_bin_map, tsk_size_t num_quantiles, double *quantiles,\n    tsk_flags_t options, double *result);\nint tsk_treeseq_pair_coalescence_rates(const tsk_treeseq_t *self,\n    tsk_size_t num_sample_sets, const tsk_size_t *sample_set_sizes,\n    const tsk_id_t *sample_sets, tsk_size_t num_set_indexes, const tsk_id_t *set_indexes,\n    tsk_size_t num_windows, const double *windows, tsk_size_t num_time_windows,\n    const tsk_id_t *node_time_window, double *time_windows, tsk_flags_t options,\n    double *result);\n\n/****************************************************************************/\n/* Tree */\n/****************************************************************************/\n\n/**\n@defgroup TREE_API_LIFECYCLE_GROUP Tree lifecycle\n@{\n*/\n\n/**\n@brief Initialises the tree by allocating internal memory and associating\n    with the specified tree sequence.\n\n@rst\nThis must be called before any operations are performed on the tree.\n\nThe specified tree sequence object must be initialised, and must be\nvalid for the full lifetime of this tree.\n\nSee the :ref:`sec_c_api_overview_structure` for details on how objects\nare initialised and freed.\n\nThe ``options`` parameter is provided to support future expansions\nof the API. A number of undocumented internal features are controlled\nvia this parameter, and it **must** be set to 0 to ensure that operations\nwork as expected and for compatibility with future versions of tskit.\n@endrst\n\n@param self A pointer to an uninitialised tsk_tree_t object.\n@param tree_sequence A pointer to an initialised tsk_treeseq_t object.\n@param options Allocation time options. Must be 0, or behaviour is undefined.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_tree_init(\n    tsk_tree_t *self, const tsk_treeseq_t *tree_sequence, tsk_flags_t options);\n\n/**\n@brief Free the internal memory for the specified tree.\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Always returns 0.\n*/\nint tsk_tree_free(tsk_tree_t *self);\n\n/**\n@brief Copies the state of this tree into the specified destination.\n\n@rst\nBy default (``options`` = 0) the method initialises the specified destination\ntree by calling :c:func:`tsk_tree_init`. If the destination is already\ninitialised, the :c:macro:`TSK_NO_INIT` option should be supplied to avoid\nleaking memory. If :c:macro:`TSK_NO_INIT` is supplied and the tree sequence associated\nwith the ``dest`` tree is not equal to the tree sequence associated\nwith ``self``, an error is raised.\n\nThe destination tree will keep a reference to the tree sequence object\nassociated with the source tree, and this tree sequence must be\nvalid for the full lifetime of the destination tree.\n\n**Options**\n\n- :c:macro:`TSK_NO_INIT`\n\nIf :c:macro:`TSK_NO_INIT` is not specified, options for :c:func:`tsk_tree_init`\ncan be provided and will be passed on.\n\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@param dest A pointer to a tsk_tree_t object. If the TSK_NO_INIT option\n    is specified, this must be an initialised tree. If not, it must\n    be an uninitialised tree.\n@param options Copy and allocation time options. See the notes above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_tree_copy(const tsk_tree_t *self, tsk_tree_t *dest, tsk_flags_t options);\n\n/** @} */\n\n/**\n@defgroup TREE_API_SEEKING_GROUP Seeking along the sequence\n@{\n*/\n\n/** @brief Option to seek by skipping to the target tree, adding and removing as few\n   edges as possible. If not specified, a linear time algorithm is used instead.\n\n    @ingroup TREE_API_SEEKING_GROUP\n*/\n#define TSK_SEEK_SKIP (1 << 0)\n\n/**\n@brief Seek to the first tree in the sequence.\n\n@rst\nSet the state of this tree to reflect the first tree in parent\ntree sequence.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Return TSK_TREE_OK on success; or a negative value if an error occurs.\n*/\nint tsk_tree_first(tsk_tree_t *self);\n\n/**\n@brief Seek to the last tree in the sequence.\n\n@rst\nSet the state of this tree to reflect the last tree in parent\ntree sequence.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Return TSK_TREE_OK on success; or a negative value if an error occurs.\n*/\nint tsk_tree_last(tsk_tree_t *self);\n\n/**\n@brief Seek to the next tree in the sequence.\n\n@rst\nSet the state of this tree to reflect the next tree in parent\ntree sequence. If the index of the current tree is ``j``,\nthen the after this operation the index will be ``j + 1``.\n\nCalling :c:func:`tsk_tree_next` a tree in the\n:ref:`null state<sec_c_api_trees_null>` is equivalent to calling\n:c:func:`tsk_tree_first`.\n\nCalling :c:func:`tsk_tree_next` on the last tree in the\nsequence will transform it into the\n:ref:`null state<sec_c_api_trees_null>` (equivalent to\ncalling :c:func:`tsk_tree_clear`).\n\nPlease see the :ref:`sec_c_api_examples_tree_iteration` examples for\nrecommended usage.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Return TSK_TREE_OK on successfully transforming to a\nnon-null tree; 0 on successfully transforming into the null\ntree; or a negative value if an error occurs.\n*/\nint tsk_tree_next(tsk_tree_t *self);\n\n/**\n@brief Seek to the previous tree in the sequence.\n\n@rst\nSet the state of this tree to reflect the previous tree in parent\ntree sequence. If the index of the current tree is ``j``,\nthen the after this operation the index will be ``j - 1``.\n\nCalling :c:func:`tsk_tree_prev` a tree in the\n:ref:`null state<sec_c_api_trees_null>` is equivalent to calling\n:c:func:`tsk_tree_last`.\n\nCalling :c:func:`tsk_tree_prev` on the first tree in the\nsequence will transform it into the\n:ref:`null state<sec_c_api_trees_null>` (equivalent to\ncalling :c:func:`tsk_tree_clear`).\n\nPlease see the :ref:`sec_c_api_examples_tree_iteration` examples for\nrecommended usage.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Return TSK_TREE_OK on successfully transforming to a\nnon-null tree; 0 on successfully transforming into the null\ntree; or a negative value if an error occurs.\n*/\nint tsk_tree_prev(tsk_tree_t *self);\n\n/**\n@brief Set the tree into the null state.\n\n@rst\nTransform this tree into the :ref:`null state<sec_c_api_trees_null>`.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_tree_clear(tsk_tree_t *self);\n\n/**\n@brief Seek to a particular position on the genome.\n\n@rst\nSet the state of this tree to reflect the tree in parent\ntree sequence covering the specified ``position``. That is, on success\nwe will have ``tree.interval.left <= position`` and\nwe will have ``position < tree.interval.right``.\n\nSeeking to a position currently covered by the tree is\na constant time operation.\n\nSeeking to a position from a non-null tree uses a linear time\nalgorithm by default, unless the option :c:macro:`TSK_SEEK_SKIP`\nis specified. In this case, a faster algorithm is employed which skips\nto the target tree by removing and adding the minimal number of edges\npossible. However, this approach does not guarantee that edges are\ninserted and removed in time-sorted order.\n\n.. warning:: Using the :c:macro:`TSK_SEEK_SKIP` option\n    may lead to edges not being inserted or removed in time-sorted order.\n\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@param position The position in genome coordinates\n@param options Seek options. See the notes above for details.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_tree_seek(tsk_tree_t *self, double position, tsk_flags_t options);\n\n/**\n@brief Seek to a specific tree in a tree sequence.\n\n@rst\nSet the state of this tree to reflect the tree in parent\ntree sequence whose index is ``0 <= tree < num_trees``.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@param tree The target tree index.\n@param options Seek options. Currently unused. Set to 0 for compatibility\n    with future versions of tskit.\n@return Return 0 on success or a negative value on failure.\n*/\nint tsk_tree_seek_index(tsk_tree_t *self, tsk_id_t tree, tsk_flags_t options);\n\n/** @} */\n\n/**\n@defgroup TREE_API_TREE_QUERY_GROUP Tree Queries\n@{\n*/\n\n/**\n@brief Returns the number of roots in this tree.\n\n@rst\nSee the :ref:`sec_data_model_tree_roots` section for more information\non how the roots of a tree are defined.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Returns the number roots in this tree.\n*/\ntsk_size_t tsk_tree_get_num_roots(const tsk_tree_t *self);\n\n/**\n@brief Returns the leftmost root in this tree.\n\n@rst\nSee the :ref:`sec_data_model_tree_roots` section for more information\non how the roots of a tree are defined.\n\nThis function is equivalent to ``tree.left_child[tree.virtual_root]``.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Returns the leftmost root in the tree.\n*/\ntsk_id_t tsk_tree_get_left_root(const tsk_tree_t *self);\n\n/**\n@brief Returns the rightmost root in this tree.\n\n@rst\nSee the :ref:`sec_data_model_tree_roots` section for more information\non how the roots of a tree are defined.\n\nThis function is equivalent to ``tree.right_child[tree.virtual_root]``.\n@endrst\n\n@param self A pointer to an initialised tsk_tree_t object.\n@return Returns the rightmost root in the tree.\n*/\ntsk_id_t tsk_tree_get_right_root(const tsk_tree_t *self);\n\n/**\n@brief Get the list of sites for this tree.\n\n@rst\nGets the list of :c:data:`tsk_site_t` objects in the parent tree sequence\nfor which the position lies within this tree's genomic interval.\n\nThe memory pointed to by the ``sites`` parameter is managed by the\n``tsk_tree_t`` object and must not be altered or freed by client code.\n\n.. code-block:: c\n\n    static void\n    print_sites(const tsk_tree_t *tree)\n    {\n        int ret;\n        tsk_size_t j, num_sites;\n        const tsk_site_t *sites;\n\n        ret = tsk_tree_get_sites(tree, &sites, &num_sites);\n        check_tsk_error(ret);\n        for (j = 0; j < num_sites; j++) {\n            printf(\"position = %f\\n\", sites[j].position);\n        }\n    }\n\nThis is a constant time operation.\n\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param sites The destination pointer for the list of sites.\n@param sites_length A pointer to a tsk_size_t value in which the number\n    of sites is stored.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_sites(\n    const tsk_tree_t *self, const tsk_site_t **sites, tsk_size_t *sites_length);\n\n/**\n@brief Return an upper bound on the number of nodes reachable\n    from the roots of this tree.\n\n@rst\nThis function provides an upper bound on the number of nodes that\ncan be reached in tree traversals, and is intended to be used\nfor memory allocation purposes. If ``num_nodes`` is the number\nof nodes visited in a tree traversal from the\n:ref:`virtual root<sec_data_model_tree_roots>`\n(e.g., ``tsk_tree_preorder_from(tree, tree->virtual_root, nodes,\n&num_nodes)``), the bound ``N`` returned here is guaranteed to\nbe greater than or equal to ``num_nodes``.\n\n.. warning:: The precise value returned is not defined and should\n    not be depended on, as it may change from version-to-version.\n\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@return An upper bound on the number nodes reachable from the roots\n    of this tree, or zero if this tree has not been initialised.\n*/\ntsk_size_t tsk_tree_get_size_bound(const tsk_tree_t *self);\n\n/**\n@brief Print out the state of this tree to the specified stream.\n\nThis method is intended for debugging purposes and should not be used\nin production code. The format of the output should **not** be depended\non and may change arbitrarily between versions.\n\n@param self A pointer to a tsk_tree_t object.\n@param out The stream to write the summary to.\n*/\nvoid tsk_tree_print_state(const tsk_tree_t *self, FILE *out);\n\n/** @} */\n\n/**\n@defgroup TREE_API_NODE_QUERY_GROUP Node Queries\n@{\n*/\n\n/**\n@brief Returns the parent of the specified node.\n\n@rst\nEquivalent to ``tree.parent[u]`` with bounds checking for the node u.\nPerformance sensitive code which can guarantee that the node u is\nvalid should use the direct array access in preference to this method.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The tree node.\n@param parent A tsk_id_t pointer to store the returned parent node.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_parent(const tsk_tree_t *self, tsk_id_t u, tsk_id_t *parent);\n\n/**\n@brief Returns the time of the specified node.\n\n@rst\nEquivalent to ``tables->nodes.time[u]`` with bounds checking for the node u.\nPerformance sensitive code which can guarantee that the node u is\nvalid should use the direct array access in preference to this method,\nfor example:\n\n.. code-block:: c\n\n    static void\n    print_times(const tsk_tree_t *tree)\n    {\n        int ret;\n        tsk_size_t num_nodes, j;\n        const double *node_time = tree->tree_sequence->tables->nodes.time;\n        tsk_id_t *nodes = malloc(tsk_tree_get_size_bound(tree) * sizeof(*nodes));\n\n        if (nodes == NULL) {\n            errx(EXIT_FAILURE, \"Out of memory\");\n        }\n        ret = tsk_tree_preorder(tree, nodes, &num_nodes);\n        check_tsk_error(ret);\n        for (j = 0; j < num_nodes; j++) {\n            printf(\"time = %f\\n\", node_time[nodes[j]]);\n        }\n        free(nodes);\n    }\n\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The tree node.\n@param ret_time A double pointer to store the returned node time.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_time(const tsk_tree_t *self, tsk_id_t u, double *ret_time);\n\n/**\n@brief Return number of nodes on the path from the specified node to root.\n\n@rst\nReturn the number of nodes on the path from u to root, not including u.\nThe depth of a root is therefore zero.\n\nAs a special case, the depth of the\n:ref:`virtual root <sec_data_model_tree_roots>` is defined as -1.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The tree node.\n@param ret_depth An int pointer to store the returned node depth.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_depth(const tsk_tree_t *self, tsk_id_t u, int *ret_depth);\n\n/**\n@brief Return the length of the branch ancestral to the specified node.\n\n@rst\nReturn the length of the branch ancestral to the specified node.\nBranch length is defined as difference between the time\nof a node and its parent. The branch length of a root is zero.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The tree node.\n@param ret_branch_length A double pointer to store the returned branch length.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_branch_length(\n    const tsk_tree_t *self, tsk_id_t u, double *ret_branch_length);\n\n/**\n@brief Computes the sum of the lengths of all branches reachable from\n    the specified node, or from all roots if ``u=TSK_NULL``.\n\n@rst\nReturn the total branch length in a particular subtree or of the\nentire tree. If the specified node is :c:macro:`TSK_NULL` (or the\n:ref:`virtual root<sec_data_model_tree_roots>`)\nthe sum of the lengths of all branches reachable from roots\nis returned. Branch length is defined as difference between the time\nof a node and its parent. The branch length of a root is zero.\n\nNote that if the specified node is internal its branch length is\n*not* included, so that, e.g., the total branch length of a\nleaf node is zero.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The root of the subtree of interest, or ``TSK_NULL`` to return the\n    total branch length of the tree.\n@param ret_tbl A double pointer to store the returned total branch length.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_total_branch_length(\n    const tsk_tree_t *self, tsk_id_t u, double *ret_tbl);\n\n/**\n@brief Counts the number of samples in the subtree rooted at a node.\n\n@rst\nReturns the number of samples descending from a particular node,\nincluding the node itself.\n\nThis is a constant time operation.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The tree node.\n@param ret_num_samples A tsk_size_t pointer to store the returned\n    number of samples.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_num_samples(\n    const tsk_tree_t *self, tsk_id_t u, tsk_size_t *ret_num_samples);\n\n/**\n@brief Compute the most recent common ancestor of two nodes.\n\n@rst\nIf two nodes do not share a common ancestor in the current tree, the MRCA\nnode is :c:macro:`TSK_NULL`.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u A tree node.\n@param v A tree node.\n@param mrca A tsk_id_t pointer to store the returned most recent common ancestor node.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_get_mrca(const tsk_tree_t *self, tsk_id_t u, tsk_id_t v, tsk_id_t *mrca);\n\n/**\n@brief Returns true if u is a descendant of v.\n\n@rst\nReturns true if u and v are both valid nodes in the tree sequence\nand v lies on the path from u to root, and false otherwise.\n\nAny node is a descendant of itself.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param u The descendant node.\n@param v The ancestral node.\n@return true if u is a descendant of v, and false otherwise.\n*/\nbool tsk_tree_is_descendant(const tsk_tree_t *self, tsk_id_t u, tsk_id_t v);\n\n/** @} */\n\n/**\n@defgroup TREE_API_TRAVERSAL_GROUP Traversal orders.\n@{\n*/\n\n/**\n@brief Fill an array with the nodes of this tree in preorder.\n\n@rst\nPopulate an array with the nodes in this tree in preorder. The array\nmust be pre-allocated and be sufficiently large to hold the array\nof nodes visited. The recommended approach is to use the\n:c:func:`tsk_tree_get_size_bound` function, as in the following example:\n\n.. code-block:: c\n\n    static void\n    print_preorder(tsk_tree_t *tree)\n    {\n        int ret;\n        tsk_size_t num_nodes, j;\n        tsk_id_t *nodes = malloc(tsk_tree_get_size_bound(tree) * sizeof(*nodes));\n\n        if (nodes == NULL) {\n            errx(EXIT_FAILURE, \"Out of memory\");\n        }\n        ret = tsk_tree_preorder(tree, nodes, &num_nodes);\n        check_tsk_error(ret);\n        for (j = 0; j < num_nodes; j++) {\n            printf(\"Visit preorder %lld\\n\", (long long) nodes[j]);\n        }\n        free(nodes);\n    }\n\n.. seealso::\n    See the :ref:`sec_c_api_examples_tree_traversals` section for\n    more examples.\n\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param nodes The tsk_id_t array to store nodes in. See notes above for\n    details.\n@param num_nodes A pointer to a tsk_size_t value where we store the number\n    of nodes in the traversal.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_preorder(const tsk_tree_t *self, tsk_id_t *nodes, tsk_size_t *num_nodes);\n\n/**\n@brief Fill an array with the nodes of this tree starting from a particular node.\n\n@rst\nAs for :c:func:`tsk_tree_preorder` but starting the traversal at a particular node\n(which will be the first node in the traversal list). The\n:ref:`virtual root<sec_data_model_tree_roots>` is a valid input for this function\nand will be treated like any other tree node. The value ``-1`` is a special case,\nin which we visit all nodes reachable from the roots, and equivalent to\ncalling :c:func:`tsk_tree_preorder`.\n\nSee :c:func:`tsk_tree_preorder` for details the requirements for the ``nodes``\narray.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param root The root of the subtree to traverse, or -1 to visit all nodes.\n@param nodes The tsk_id_t array to store nodes in.\n@param num_nodes A pointer to a tsk_size_t value where we store the number\n    of nodes in the traversal.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_preorder_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes);\n\n/**\n@brief Fill an array with the nodes of this tree in postorder.\n\n@rst\nPopulate an array with the nodes in this tree in postorder. The array\nmust be pre-allocated and be sufficiently large to hold the array\nof nodes visited. The recommended approach is to use the\n:c:func:`tsk_tree_get_size_bound` function, as in the following example:\n\n.. code-block:: c\n\n    static void\n    print_postorder(tsk_tree_t *tree)\n    {\n        int ret;\n        tsk_size_t num_nodes, j;\n        tsk_id_t *nodes = malloc(tsk_tree_get_size_bound(tree) * sizeof(*nodes));\n\n        if (nodes == NULL) {\n            errx(EXIT_FAILURE, \"Out of memory\");\n        }\n        ret = tsk_tree_postorder(tree, nodes, &num_nodes);\n        check_tsk_error(ret);\n        for (j = 0; j < num_nodes; j++) {\n            printf(\"Visit postorder %lld\\n\", (long long) nodes[j]);\n        }\n        free(nodes);\n    }\n\n.. seealso::\n    See the :ref:`sec_c_api_examples_tree_traversals` section for\n    more examples.\n\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param nodes The tsk_id_t array to store nodes in. See notes above for\n    details.\n@param num_nodes A pointer to a tsk_size_t value where we store the number\n    of nodes in the traversal.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_postorder(const tsk_tree_t *self, tsk_id_t *nodes, tsk_size_t *num_nodes);\n\n/**\n@brief Fill an array with the nodes of this tree starting from a particular node.\n\n@rst\nAs for :c:func:`tsk_tree_postorder` but starting the traversal at a particular node\n(which will be the last node in the traversal list). The\n:ref:`virtual root<sec_data_model_tree_roots>` is a valid input for this function\nand will be treated like any other tree node. The value ``-1`` is a special case,\nin which we visit all nodes reachable from the roots, and equivalent to\ncalling :c:func:`tsk_tree_postorder`.\n\nSee :c:func:`tsk_tree_postorder` for details the requirements for the ``nodes``\narray.\n@endrst\n\n@param self A pointer to a tsk_tree_t object.\n@param root The root of the subtree to traverse, or -1 to visit all nodes.\n@param nodes The tsk_id_t array to store nodes in. See\n    :c:func:`tsk_tree_postorder` for more details.\n@param num_nodes A pointer to a tsk_size_t value where we store the number\n    of nodes in the traversal.\n@return 0 on success or a negative value on failure.\n*/\nint tsk_tree_postorder_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes);\n\n/** @} */\n\n/* Undocumented for now */\n\nint tsk_tree_preorder_samples_from(\n    const tsk_tree_t *self, tsk_id_t root, tsk_id_t *nodes, tsk_size_t *num_nodes);\n\nint tsk_tree_set_root_threshold(tsk_tree_t *self, tsk_size_t root_threshold);\ntsk_size_t tsk_tree_get_root_threshold(const tsk_tree_t *self);\n\nbool tsk_tree_has_sample_counts(const tsk_tree_t *self);\nbool tsk_tree_has_sample_lists(const tsk_tree_t *self);\n\nint tsk_tree_get_num_tracked_samples(\n    const tsk_tree_t *self, tsk_id_t u, tsk_size_t *num_tracked_samples);\nint tsk_tree_set_tracked_samples(\n    tsk_tree_t *self, tsk_size_t num_tracked_samples, const tsk_id_t *tracked_samples);\nint tsk_tree_track_descendant_samples(tsk_tree_t *self, tsk_id_t node);\n\ntypedef struct {\n    tsk_id_t node;\n    tsk_id_t parent;\n    int32_t state;\n} tsk_state_transition_t;\n\nint tsk_tree_map_mutations(tsk_tree_t *self, int32_t *genotypes, double *cost_matrix,\n    tsk_flags_t options, int32_t *ancestral_state, tsk_size_t *num_transitions,\n    tsk_state_transition_t **transitions);\n\nint tsk_tree_kc_distance(\n    const tsk_tree_t *self, const tsk_tree_t *other, double lambda, double *result);\n\n/* Don't document these balance metrics for now so it doesn't get in the way of\n * C API 1.0, but should be straightforward to document based on Python docs. */\nint tsk_tree_sackin_index(const tsk_tree_t *self, tsk_size_t *result);\nint tsk_tree_colless_index(const tsk_tree_t *self, tsk_size_t *result);\nint tsk_tree_b1_index(const tsk_tree_t *self, double *result);\n/* NOTE: if we document this as part of the C API we'll have to be more careful\n * about the error behaviour on bad log bases. At the moment we're just returning\n * the resulting value which can be nan, inf etc, but some surprising results\n * happen like a base 0 seems to return a finite value. */\nint tsk_tree_b2_index(const tsk_tree_t *self, double base, double *result);\n\nint tsk_tree_num_lineages(const tsk_tree_t *self, double t, tsk_size_t *result);\n\n/* Things to consider removing: */\n\n/* This is redundant, really */\nbool tsk_tree_is_sample(const tsk_tree_t *self, tsk_id_t u);\n\n/* Not terribly useful, since the definition is\n * return (self->tree_sequence == other->tree_sequence) && (self->index == other->index)\n * Remove?\n */\nbool tsk_tree_equals(const tsk_tree_t *self, const tsk_tree_t *other);\n\nint tsk_tree_position_init(\n    tsk_tree_position_t *self, const tsk_treeseq_t *tree_sequence, tsk_flags_t options);\nint tsk_tree_position_free(tsk_tree_position_t *self);\nint tsk_tree_position_print_state(const tsk_tree_position_t *self, FILE *out);\nbool tsk_tree_position_next(tsk_tree_position_t *self);\nbool tsk_tree_position_prev(tsk_tree_position_t *self);\nint tsk_tree_position_seek_forward(tsk_tree_position_t *self, tsk_id_t index);\nint tsk_tree_position_seek_backward(tsk_tree_position_t *self, tsk_id_t index);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "treerec/tskit/tskit.pro",
    "content": "#-------------------------------------------------\n#\n# Project created by QtCreator 2019-07-10T22:41:14\n#\n#-------------------------------------------------\n\nQT       -= core gui\n\nTEMPLATE = lib\nCONFIG += staticlib\n\n\n# Uncomment this line for a production build, to build for both Intel and Apple Silicon.  This only works with Qt6;\n# Qt5 for macOS is built for Intel only.  Uncomment this for all components or you will get link errors.\n#QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64\n\n\n# Uncomment the lines below to enable ASAN (Address Sanitizer), for debugging of memory issues, in every\n# .pro file project-wide.  See https://clang.llvm.org/docs/AddressSanitizer.html for discussion of ASAN\n# Also set the ASAN_OPTIONS env. variable, in the Run Settings section of the Project tab in Qt Creator, to\n# strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n# This also enables undefined behavior sanitizing, in conjunction with ASAN, because why not.\n#CONFIG += sanitizer sanitize_address sanitize_undefined\n\n\nCONFIG -= qt\nCONFIG += c11\nQMAKE_CFLAGS += -std=c11\nQMAKE_CFLAGS_DEBUG += -g -Og -DDEBUG=1\nQMAKE_CFLAGS_RELEASE += -O3\n\n# get rid of spurious errors on Ubuntu, for now\nlinux-*: {\n    QMAKE_CFLAGS += -Wno-unknown-pragmas -Wno-attributes -Wno-unused-parameter -Wno-unused-but-set-parameter\n}\n\nINCLUDEPATH = . .. kastore\n\n\n# prevent link dependency cycles\nQMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF\n\n\nSOURCES += \\\n    convert.c \\\n    core.c \\\n    genotypes.c \\\n    stats.c \\\n    tables.c \\\n    text_input.c \\\n    trees.c \\\n    kastore/kastore.c\n\nHEADERS += \\\n    convert.h \\\n    core.h \\\n    genotypes.h \\\n    stats.h \\\n    tables.h \\\n    text_input.h \\\n    trees.h \\\n    kastore/kastore.h\n\n"
  },
  {
    "path": "windows_compat/gnulib/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in.\n\nAUTOMAKE_OPTIONS = 1.11 foreign\n\nSUBDIRS = gllib glm4\n\nACLOCAL_AMFLAGS = -I glm4\n"
  },
  {
    "path": "windows_compat/gnulib/Makefile.in",
    "content": "# Makefile.in generated by automake 1.16.3 from Makefile.am.\n# @configure_input@\n\n# Copyright (C) 1994-2020 Free Software Foundation, Inc.\n\n# This Makefile.in is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY, to the extent permitted by law; without\n# even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n# PARTICULAR PURPOSE.\n\n@SET_MAKE@\nVPATH = @srcdir@\nam__is_gnu_make = { \\\n  if test -z '$(MAKELEVEL)'; then \\\n    false; \\\n  elif test -n '$(MAKE_HOST)'; then \\\n    true; \\\n  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \\\n    true; \\\n  else \\\n    false; \\\n  fi; \\\n}\nam__make_running_with_option = \\\n  case $${target_option-} in \\\n      ?) ;; \\\n      *) echo \"am__make_running_with_option: internal error: invalid\" \\\n              \"target option '$${target_option-}' specified\" >&2; \\\n         exit 1;; \\\n  esac; \\\n  has_opt=no; \\\n  sane_makeflags=$$MAKEFLAGS; \\\n  if $(am__is_gnu_make); then \\\n    sane_makeflags=$$MFLAGS; \\\n  else \\\n    case $$MAKEFLAGS in \\\n      *\\\\[\\ \\\t]*) \\\n        bs=\\\\; \\\n        sane_makeflags=`printf '%s\\n' \"$$MAKEFLAGS\" \\\n          | sed \"s/$$bs$$bs[$$bs $$bs\t]*//g\"`;; \\\n    esac; \\\n  fi; \\\n  skip_next=no; \\\n  strip_trailopt () \\\n  { \\\n    flg=`printf '%s\\n' \"$$flg\" | sed \"s/$$1.*$$//\"`; \\\n  }; \\\n  for flg in $$sane_makeflags; do \\\n    test $$skip_next = yes && { skip_next=no; continue; }; \\\n    case $$flg in \\\n      *=*|--*) continue;; \\\n        -*I) strip_trailopt 'I'; skip_next=yes;; \\\n      -*I?*) strip_trailopt 'I';; \\\n        -*O) strip_trailopt 'O'; skip_next=yes;; \\\n      -*O?*) strip_trailopt 'O';; \\\n        -*l) strip_trailopt 'l'; skip_next=yes;; \\\n      -*l?*) strip_trailopt 'l';; \\\n      -[dEDm]) skip_next=yes;; \\\n      -[JT]) skip_next=yes;; \\\n    esac; \\\n    case $$flg in \\\n      *$$target_option*) has_opt=yes; break;; \\\n    esac; \\\n  done; \\\n  test $$has_opt = yes\nam__make_dryrun = (target_option=n; $(am__make_running_with_option))\nam__make_keepgoing = (target_option=k; $(am__make_running_with_option))\npkgdatadir = $(datadir)/@PACKAGE@\npkgincludedir = $(includedir)/@PACKAGE@\npkglibdir = $(libdir)/@PACKAGE@\npkglibexecdir = $(libexecdir)/@PACKAGE@\nam__cd = CDPATH=\"$${ZSH_VERSION+.}$(PATH_SEPARATOR)\" && cd\ninstall_sh_DATA = $(install_sh) -c -m 644\ninstall_sh_PROGRAM = $(install_sh) -c\ninstall_sh_SCRIPT = $(install_sh) -c\nINSTALL_HEADER = $(INSTALL_DATA)\ntransform = $(program_transform_name)\nNORMAL_INSTALL = :\nPRE_INSTALL = :\nPOST_INSTALL = :\nNORMAL_UNINSTALL = :\nPRE_UNINSTALL = :\nPOST_UNINSTALL = :\nbuild_triplet = @build@\nhost_triplet = @host@\nsubdir = .\nACLOCAL_M4 = $(top_srcdir)/aclocal.m4\nam__aclocal_m4_deps = $(top_srcdir)/glm4/00gnulib.m4 \\\n\t$(top_srcdir)/glm4/__inline.m4 \\\n\t$(top_srcdir)/glm4/absolute-header.m4 \\\n\t$(top_srcdir)/glm4/errno_h.m4 $(top_srcdir)/glm4/execinfo.m4 \\\n\t$(top_srcdir)/glm4/extensions.m4 \\\n\t$(top_srcdir)/glm4/extern-inline.m4 \\\n\t$(top_srcdir)/glm4/getdelim.m4 \\\n\t$(top_srcdir)/glm4/gethostname.m4 \\\n\t$(top_srcdir)/glm4/getline.m4 \\\n\t$(top_srcdir)/glm4/gettimeofday.m4 \\\n\t$(top_srcdir)/glm4/gnulib-common.m4 \\\n\t$(top_srcdir)/glm4/include_next.m4 \\\n\t$(top_srcdir)/glm4/limits-h.m4 \\\n\t$(top_srcdir)/glm4/msvc-inval.m4 \\\n\t$(top_srcdir)/glm4/msvc-nothrow.m4 \\\n\t$(top_srcdir)/glm4/multiarch.m4 $(top_srcdir)/glm4/off_t.m4 \\\n\t$(top_srcdir)/glm4/random.m4 $(top_srcdir)/glm4/random_r.m4 \\\n\t$(top_srcdir)/glm4/socketlib.m4 $(top_srcdir)/glm4/sockets.m4 \\\n\t$(top_srcdir)/glm4/socklen.m4 $(top_srcdir)/glm4/ssize_t.m4 \\\n\t$(top_srcdir)/glm4/stdalign.m4 $(top_srcdir)/glm4/stddef_h.m4 \\\n\t$(top_srcdir)/glm4/stdint.m4 $(top_srcdir)/glm4/stdio_h.m4 \\\n\t$(top_srcdir)/glm4/stdlib_h.m4 \\\n\t$(top_srcdir)/glm4/sys_resource_h.m4 \\\n\t$(top_srcdir)/glm4/sys_socket_h.m4 \\\n\t$(top_srcdir)/glm4/sys_stat_h.m4 \\\n\t$(top_srcdir)/glm4/sys_time_h.m4 \\\n\t$(top_srcdir)/glm4/sys_types_h.m4 \\\n\t$(top_srcdir)/glm4/sys_uio_h.m4 \\\n\t$(top_srcdir)/glm4/sys_utsname_h.m4 \\\n\t$(top_srcdir)/glm4/time_h.m4 $(top_srcdir)/glm4/time_r.m4 \\\n\t$(top_srcdir)/glm4/uname.m4 $(top_srcdir)/glm4/unistd_h.m4 \\\n\t$(top_srcdir)/glm4/warn-on-use.m4 \\\n\t$(top_srcdir)/glm4/wchar_t.m4 $(top_srcdir)/glm4/wint_t.m4 \\\n\t$(top_srcdir)/glm4/zzgnulib.m4 $(top_srcdir)/configure.ac\nam__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \\\n\t$(ACLOCAL_M4)\nDIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \\\n\t$(am__configure_deps) $(am__DIST_COMMON)\nam__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \\\n configure.lineno config.status.lineno\nmkinstalldirs = $(install_sh) -d\nCONFIG_HEADER = config.h\nCONFIG_CLEAN_FILES =\nCONFIG_CLEAN_VPATH_FILES =\nAM_V_P = $(am__v_P_@AM_V@)\nam__v_P_ = $(am__v_P_@AM_DEFAULT_V@)\nam__v_P_0 = false\nam__v_P_1 = :\nAM_V_GEN = $(am__v_GEN_@AM_V@)\nam__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)\nam__v_GEN_0 = @echo \"  GEN     \" $@;\nam__v_GEN_1 = \nAM_V_at = $(am__v_at_@AM_V@)\nam__v_at_ = $(am__v_at_@AM_DEFAULT_V@)\nam__v_at_0 = @\nam__v_at_1 = \nSOURCES =\nDIST_SOURCES =\nRECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \\\n\tctags-recursive dvi-recursive html-recursive info-recursive \\\n\tinstall-data-recursive install-dvi-recursive \\\n\tinstall-exec-recursive install-html-recursive \\\n\tinstall-info-recursive install-pdf-recursive \\\n\tinstall-ps-recursive install-recursive installcheck-recursive \\\n\tinstalldirs-recursive pdf-recursive ps-recursive \\\n\ttags-recursive uninstall-recursive\nam__can_run_installinfo = \\\n  case $$AM_UPDATE_INFO_DIR in \\\n    n|no|NO) false;; \\\n    *) (install-info --version) >/dev/null 2>&1;; \\\n  esac\nRECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive\t\\\n  distclean-recursive maintainer-clean-recursive\nam__recursive_targets = \\\n  $(RECURSIVE_TARGETS) \\\n  $(RECURSIVE_CLEAN_TARGETS) \\\n  $(am__extra_recursive_targets)\nAM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \\\n\tcscope distdir distdir-am dist dist-all distcheck\nam__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \\\n\tconfig.h.in\n# Read a list of newline-separated strings from the standard input,\n# and print each of them once, without duplicates.  Input order is\n# *not* preserved.\nam__uniquify_input = $(AWK) '\\\n  BEGIN { nonempty = 0; } \\\n  { items[$$0] = 1; nonempty = 1; } \\\n  END { if (nonempty) { for (i in items) print i; }; } \\\n'\n# Make sure the list of sources is unique.  This is necessary because,\n# e.g., the same source file might be shared among _SOURCES variables\n# for different programs/libraries.\nam__define_uniq_tagged_files = \\\n  list='$(am__tagged_files)'; \\\n  unique=`for i in $$list; do \\\n    if test -f \"$$i\"; then echo $$i; else echo $(srcdir)/$$i; fi; \\\n  done | $(am__uniquify_input)`\nETAGS = etags\nCTAGS = ctags\nCSCOPE = cscope\nDIST_SUBDIRS = $(SUBDIRS)\nam__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \\\n\t$(top_srcdir)/build-aux/compile \\\n\t$(top_srcdir)/build-aux/config.guess \\\n\t$(top_srcdir)/build-aux/config.sub \\\n\t$(top_srcdir)/build-aux/install-sh \\\n\t$(top_srcdir)/build-aux/missing build-aux/compile \\\n\tbuild-aux/config.guess build-aux/config.sub \\\n\tbuild-aux/install-sh build-aux/missing\nDISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)\ndistdir = $(PACKAGE)-$(VERSION)\ntop_distdir = $(distdir)\nam__remove_distdir = \\\n  if test -d \"$(distdir)\"; then \\\n    find \"$(distdir)\" -type d ! -perm -200 -exec chmod u+w {} ';' \\\n      && rm -rf \"$(distdir)\" \\\n      || { sleep 5 && rm -rf \"$(distdir)\"; }; \\\n  else :; fi\nam__post_remove_distdir = $(am__remove_distdir)\nam__relativize = \\\n  dir0=`pwd`; \\\n  sed_first='s,^\\([^/]*\\)/.*$$,\\1,'; \\\n  sed_rest='s,^[^/]*/*,,'; \\\n  sed_last='s,^.*/\\([^/]*\\)$$,\\1,'; \\\n  sed_butlast='s,/*[^/]*$$,,'; \\\n  while test -n \"$$dir1\"; do \\\n    first=`echo \"$$dir1\" | sed -e \"$$sed_first\"`; \\\n    if test \"$$first\" != \".\"; then \\\n      if test \"$$first\" = \"..\"; then \\\n        dir2=`echo \"$$dir0\" | sed -e \"$$sed_last\"`/\"$$dir2\"; \\\n        dir0=`echo \"$$dir0\" | sed -e \"$$sed_butlast\"`; \\\n      else \\\n        first2=`echo \"$$dir2\" | sed -e \"$$sed_first\"`; \\\n        if test \"$$first2\" = \"$$first\"; then \\\n          dir2=`echo \"$$dir2\" | sed -e \"$$sed_rest\"`; \\\n        else \\\n          dir2=\"../$$dir2\"; \\\n        fi; \\\n        dir0=\"$$dir0\"/\"$$first\"; \\\n      fi; \\\n    fi; \\\n    dir1=`echo \"$$dir1\" | sed -e \"$$sed_rest\"`; \\\n  done; \\\n  reldir=\"$$dir2\"\nDIST_ARCHIVES = $(distdir).tar.gz\nGZIP_ENV = --best\nDIST_TARGETS = dist-gzip\n# Exists only to be overridden by the user if desired.\nAM_DISTCHECK_DVI_TARGET = dvi\ndistuninstallcheck_listfiles = find . -type f -print\nam__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \\\n  | sed 's|^\\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'\ndistcleancheck_listfiles = find . -type f -print\nACLOCAL = @ACLOCAL@\nAMTAR = @AMTAR@\nAM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@\nAPPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@\nAR = @AR@\nARFLAGS = @ARFLAGS@\nAUTOCONF = @AUTOCONF@\nAUTOHEADER = @AUTOHEADER@\nAUTOMAKE = @AUTOMAKE@\nAWK = @AWK@\nBITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@\nBITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@\nBITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@\nBITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@\nBITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@\nCC = @CC@\nCCDEPMODE = @CCDEPMODE@\nCFLAGS = @CFLAGS@\nCPP = @CPP@\nCPPFLAGS = @CPPFLAGS@\nCYGPATH_W = @CYGPATH_W@\nDEFS = @DEFS@\nDEPDIR = @DEPDIR@\nECHO_C = @ECHO_C@\nECHO_N = @ECHO_N@\nECHO_T = @ECHO_T@\nEGREP = @EGREP@\nEMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@\nEMULTIHOP_VALUE = @EMULTIHOP_VALUE@\nENOLINK_HIDDEN = @ENOLINK_HIDDEN@\nENOLINK_VALUE = @ENOLINK_VALUE@\nEOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@\nEOVERFLOW_VALUE = @EOVERFLOW_VALUE@\nERRNO_H = @ERRNO_H@\nEXECINFO_H = @EXECINFO_H@\nEXEEXT = @EXEEXT@\nGETHOSTNAME_LIB = @GETHOSTNAME_LIB@\nGL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@\nGL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@\nGL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@\nGL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@\nGL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@\nGL_GNULIB_BIND = @GL_GNULIB_BIND@\nGL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@\nGL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@\nGL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@\nGL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@\nGL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@\nGL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@\nGL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@\nGL_GNULIB_CTIME = @GL_GNULIB_CTIME@\nGL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@\nGL_GNULIB_DUP = @GL_GNULIB_DUP@\nGL_GNULIB_DUP2 = @GL_GNULIB_DUP2@\nGL_GNULIB_DUP3 = @GL_GNULIB_DUP3@\nGL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@\nGL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@\nGL_GNULIB_EXECL = @GL_GNULIB_EXECL@\nGL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@\nGL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@\nGL_GNULIB_EXECV = @GL_GNULIB_EXECV@\nGL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@\nGL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@\nGL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@\nGL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@\nGL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@\nGL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@\nGL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@\nGL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@\nGL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@\nGL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@\nGL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@\nGL_GNULIB_FGETC = @GL_GNULIB_FGETC@\nGL_GNULIB_FGETS = @GL_GNULIB_FGETS@\nGL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@\nGL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@\nGL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@\nGL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@\nGL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@\nGL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@\nGL_GNULIB_FREAD = @GL_GNULIB_FREAD@\nGL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@\nGL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@\nGL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@\nGL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@\nGL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@\nGL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@\nGL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@\nGL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@\nGL_GNULIB_FTELL = @GL_GNULIB_FTELL@\nGL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@\nGL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@\nGL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@\nGL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@\nGL_GNULIB_GETC = @GL_GNULIB_GETC@\nGL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@\nGL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@\nGL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@\nGL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@\nGL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@\nGL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@\nGL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@\nGL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@\nGL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@\nGL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@\nGL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@\nGL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@\nGL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@\nGL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@\nGL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@\nGL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@\nGL_GNULIB_GETRUSAGE = @GL_GNULIB_GETRUSAGE@\nGL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@\nGL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@\nGL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@\nGL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@\nGL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@\nGL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@\nGL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@\nGL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@\nGL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@\nGL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@\nGL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@\nGL_GNULIB_LINK = @GL_GNULIB_LINK@\nGL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@\nGL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@\nGL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@\nGL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@\nGL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@\nGL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@\nGL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@\nGL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@\nGL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@\nGL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@\nGL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@\nGL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@\nGL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@\nGL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@\nGL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@\nGL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@\nGL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@\nGL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@\nGL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@\nGL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@\nGL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@\nGL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@\nGL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@\nGL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@\nGL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@\nGL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@\nGL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@\nGL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@\nGL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@\nGL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@\nGL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@\nGL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@\nGL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@\nGL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@\nGL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@\nGL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@\nGL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@\nGL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@\nGL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@\nGL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@\nGL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@\nGL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@\nGL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@\nGL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@\nGL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@\nGL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@\nGL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@\nGL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@\nGL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@\nGL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@\nGL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@\nGL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@\nGL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@\nGL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@\nGL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@\nGL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@\nGL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@\nGL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@\nGL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@\nGL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@\nGL_GNULIB_PERROR = @GL_GNULIB_PERROR@\nGL_GNULIB_PIPE = @GL_GNULIB_PIPE@\nGL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@\nGL_GNULIB_POPEN = @GL_GNULIB_POPEN@\nGL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@\nGL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@\nGL_GNULIB_PREAD = @GL_GNULIB_PREAD@\nGL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@\nGL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@\nGL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@\nGL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@\nGL_GNULIB_PUTC = @GL_GNULIB_PUTC@\nGL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@\nGL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@\nGL_GNULIB_PUTS = @GL_GNULIB_PUTS@\nGL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@\nGL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@\nGL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@\nGL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@\nGL_GNULIB_READ = @GL_GNULIB_READ@\nGL_GNULIB_READLINK = @GL_GNULIB_READLINK@\nGL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@\nGL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@\nGL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@\nGL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@\nGL_GNULIB_RECV = @GL_GNULIB_RECV@\nGL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@\nGL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@\nGL_GNULIB_RENAME = @GL_GNULIB_RENAME@\nGL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@\nGL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@\nGL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@\nGL_GNULIB_SCANF = @GL_GNULIB_SCANF@\nGL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@\nGL_GNULIB_SEND = @GL_GNULIB_SEND@\nGL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@\nGL_GNULIB_SETENV = @GL_GNULIB_SETENV@\nGL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@\nGL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@\nGL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@\nGL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@\nGL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@\nGL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@\nGL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@\nGL_GNULIB_STAT = @GL_GNULIB_STAT@\nGL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@\nGL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@\nGL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@\nGL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@\nGL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@\nGL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@\nGL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@\nGL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@\nGL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@\nGL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@\nGL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@\nGL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@\nGL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@\nGL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@\nGL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@\nGL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@\nGL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@\nGL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@\nGL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@\nGL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@\nGL_GNULIB_TZSET = @GL_GNULIB_TZSET@\nGL_GNULIB_UNAME = @GL_GNULIB_UNAME@\nGL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@\nGL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@\nGL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@\nGL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@\nGL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@\nGL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@\nGL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@\nGL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@\nGL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@\nGL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@\nGL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@\nGL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@\nGL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@\nGL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@\nGL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@\nGL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@\nGL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@\nGL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@\nGL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@\nGL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@\nGL_GNULIB_WRITE = @GL_GNULIB_WRITE@\nGL_GNULIB__EXIT = @GL_GNULIB__EXIT@\nGNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@\nGNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@\nGREP = @GREP@\nHAVE_ACCEPT4 = @HAVE_ACCEPT4@\nHAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@\nHAVE_ATOLL = @HAVE_ATOLL@\nHAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@\nHAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@\nHAVE_CHOWN = @HAVE_CHOWN@\nHAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@\nHAVE_DECL_ECVT = @HAVE_DECL_ECVT@\nHAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@\nHAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@\nHAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@\nHAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@\nHAVE_DECL_FCVT = @HAVE_DECL_FCVT@\nHAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@\nHAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@\nHAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@\nHAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@\nHAVE_DECL_GCVT = @HAVE_DECL_GCVT@\nHAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@\nHAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@\nHAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@\nHAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@\nHAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@\nHAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@\nHAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@\nHAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@\nHAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@\nHAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@\nHAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@\nHAVE_DECL_SETENV = @HAVE_DECL_SETENV@\nHAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@\nHAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@\nHAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@\nHAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@\nHAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@\nHAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@\nHAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@\nHAVE_DPRINTF = @HAVE_DPRINTF@\nHAVE_DUP3 = @HAVE_DUP3@\nHAVE_EUIDACCESS = @HAVE_EUIDACCESS@\nHAVE_EXECVPE = @HAVE_EXECVPE@\nHAVE_FACCESSAT = @HAVE_FACCESSAT@\nHAVE_FCHDIR = @HAVE_FCHDIR@\nHAVE_FCHMODAT = @HAVE_FCHMODAT@\nHAVE_FCHOWNAT = @HAVE_FCHOWNAT@\nHAVE_FDATASYNC = @HAVE_FDATASYNC@\nHAVE_FSEEKO = @HAVE_FSEEKO@\nHAVE_FSTATAT = @HAVE_FSTATAT@\nHAVE_FSYNC = @HAVE_FSYNC@\nHAVE_FTELLO = @HAVE_FTELLO@\nHAVE_FTRUNCATE = @HAVE_FTRUNCATE@\nHAVE_FUTIMENS = @HAVE_FUTIMENS@\nHAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@\nHAVE_GETENTROPY = @HAVE_GETENTROPY@\nHAVE_GETGROUPS = @HAVE_GETGROUPS@\nHAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@\nHAVE_GETLOGIN = @HAVE_GETLOGIN@\nHAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@\nHAVE_GETPASS = @HAVE_GETPASS@\nHAVE_GETRUSAGE = @HAVE_GETRUSAGE@\nHAVE_GETSUBOPT = @HAVE_GETSUBOPT@\nHAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@\nHAVE_GETUMASK = @HAVE_GETUMASK@\nHAVE_GRANTPT = @HAVE_GRANTPT@\nHAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@\nHAVE_INITSTATE = @HAVE_INITSTATE@\nHAVE_INTTYPES_H = @HAVE_INTTYPES_H@\nHAVE_LCHMOD = @HAVE_LCHMOD@\nHAVE_LCHOWN = @HAVE_LCHOWN@\nHAVE_LINK = @HAVE_LINK@\nHAVE_LINKAT = @HAVE_LINKAT@\nHAVE_LSTAT = @HAVE_LSTAT@\nHAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@\nHAVE_MBTOWC = @HAVE_MBTOWC@\nHAVE_MKDIRAT = @HAVE_MKDIRAT@\nHAVE_MKDTEMP = @HAVE_MKDTEMP@\nHAVE_MKFIFO = @HAVE_MKFIFO@\nHAVE_MKFIFOAT = @HAVE_MKFIFOAT@\nHAVE_MKNOD = @HAVE_MKNOD@\nHAVE_MKNODAT = @HAVE_MKNODAT@\nHAVE_MKOSTEMP = @HAVE_MKOSTEMP@\nHAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@\nHAVE_MKSTEMP = @HAVE_MKSTEMP@\nHAVE_MKSTEMPS = @HAVE_MKSTEMPS@\nHAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@\nHAVE_NANOSLEEP = @HAVE_NANOSLEEP@\nHAVE_OS_H = @HAVE_OS_H@\nHAVE_PCLOSE = @HAVE_PCLOSE@\nHAVE_PIPE = @HAVE_PIPE@\nHAVE_PIPE2 = @HAVE_PIPE2@\nHAVE_POPEN = @HAVE_POPEN@\nHAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@\nHAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@\nHAVE_PREAD = @HAVE_PREAD@\nHAVE_PTSNAME = @HAVE_PTSNAME@\nHAVE_PTSNAME_R = @HAVE_PTSNAME_R@\nHAVE_PWRITE = @HAVE_PWRITE@\nHAVE_QSORT_R = @HAVE_QSORT_R@\nHAVE_RANDOM = @HAVE_RANDOM@\nHAVE_RANDOM_H = @HAVE_RANDOM_H@\nHAVE_RANDOM_R = @HAVE_RANDOM_R@\nHAVE_READLINK = @HAVE_READLINK@\nHAVE_READLINKAT = @HAVE_READLINKAT@\nHAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@\nHAVE_REALPATH = @HAVE_REALPATH@\nHAVE_RENAMEAT = @HAVE_RENAMEAT@\nHAVE_RPMATCH = @HAVE_RPMATCH@\nHAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@\nHAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@\nHAVE_SETENV = @HAVE_SETENV@\nHAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@\nHAVE_SETSTATE = @HAVE_SETSTATE@\nHAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@\nHAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@\nHAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@\nHAVE_SLEEP = @HAVE_SLEEP@\nHAVE_STDINT_H = @HAVE_STDINT_H@\nHAVE_STRPTIME = @HAVE_STRPTIME@\nHAVE_STRTOD = @HAVE_STRTOD@\nHAVE_STRTOL = @HAVE_STRTOL@\nHAVE_STRTOLD = @HAVE_STRTOLD@\nHAVE_STRTOLL = @HAVE_STRTOLL@\nHAVE_STRTOUL = @HAVE_STRTOUL@\nHAVE_STRTOULL = @HAVE_STRTOULL@\nHAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@\nHAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@\nHAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@\nHAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@\nHAVE_STRUCT_UTSNAME = @HAVE_STRUCT_UTSNAME@\nHAVE_SYMLINK = @HAVE_SYMLINK@\nHAVE_SYMLINKAT = @HAVE_SYMLINKAT@\nHAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@\nHAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@\nHAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@\nHAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@\nHAVE_SYS_RESOURCE_H = @HAVE_SYS_RESOURCE_H@\nHAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@\nHAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@\nHAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@\nHAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@\nHAVE_SYS_UTSNAME_H = @HAVE_SYS_UTSNAME_H@\nHAVE_TIMEGM = @HAVE_TIMEGM@\nHAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@\nHAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@\nHAVE_UNAME = @HAVE_UNAME@\nHAVE_UNISTD_H = @HAVE_UNISTD_H@\nHAVE_UNLINKAT = @HAVE_UNLINKAT@\nHAVE_UNLOCKPT = @HAVE_UNLOCKPT@\nHAVE_USLEEP = @HAVE_USLEEP@\nHAVE_UTIMENSAT = @HAVE_UTIMENSAT@\nHAVE_VASPRINTF = @HAVE_VASPRINTF@\nHAVE_VDPRINTF = @HAVE_VDPRINTF@\nHAVE_WCHAR_H = @HAVE_WCHAR_H@\nHAVE_WCHAR_T = @HAVE_WCHAR_T@\nHAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@\nHAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@\nHAVE__EXIT = @HAVE__EXIT@\nINCLUDE_NEXT = @INCLUDE_NEXT@\nINCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@\nINSTALL = @INSTALL@\nINSTALL_DATA = @INSTALL_DATA@\nINSTALL_PROGRAM = @INSTALL_PROGRAM@\nINSTALL_SCRIPT = @INSTALL_SCRIPT@\nINSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@\nLDFLAGS = @LDFLAGS@\nLIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@\nLIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@\nLIBOBJS = @LIBOBJS@\nLIBS = @LIBS@\nLIBSOCKET = @LIBSOCKET@\nLIB_EXECINFO = @LIB_EXECINFO@\nLIMITS_H = @LIMITS_H@\nLTLIBOBJS = @LTLIBOBJS@\nMAKEINFO = @MAKEINFO@\nMKDIR_P = @MKDIR_P@\nNEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@\nNEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@\nNEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@\nNEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@\nNEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@\nNEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H@\nNEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@\nNEXT_ERRNO_H = @NEXT_ERRNO_H@\nNEXT_LIMITS_H = @NEXT_LIMITS_H@\nNEXT_STDDEF_H = @NEXT_STDDEF_H@\nNEXT_STDINT_H = @NEXT_STDINT_H@\nNEXT_STDIO_H = @NEXT_STDIO_H@\nNEXT_STDLIB_H = @NEXT_STDLIB_H@\nNEXT_SYS_RESOURCE_H = @NEXT_SYS_RESOURCE_H@\nNEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@\nNEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@\nNEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@\nNEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@\nNEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@\nNEXT_SYS_UTSNAME_H = @NEXT_SYS_UTSNAME_H@\nNEXT_TIME_H = @NEXT_TIME_H@\nNEXT_UNISTD_H = @NEXT_UNISTD_H@\nOBJEXT = @OBJEXT@\nPACKAGE = @PACKAGE@\nPACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@\nPACKAGE_NAME = @PACKAGE_NAME@\nPACKAGE_STRING = @PACKAGE_STRING@\nPACKAGE_TARNAME = @PACKAGE_TARNAME@\nPACKAGE_URL = @PACKAGE_URL@\nPACKAGE_VERSION = @PACKAGE_VERSION@\nPATH_SEPARATOR = @PATH_SEPARATOR@\nPRAGMA_COLUMNS = @PRAGMA_COLUMNS@\nPRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@\nPTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@\nPTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@\nRANLIB = @RANLIB@\nREPLACE_ACCESS = @REPLACE_ACCESS@\nREPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@\nREPLACE_CALLOC = @REPLACE_CALLOC@\nREPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@\nREPLACE_CHOWN = @REPLACE_CHOWN@\nREPLACE_CLOSE = @REPLACE_CLOSE@\nREPLACE_CTIME = @REPLACE_CTIME@\nREPLACE_DPRINTF = @REPLACE_DPRINTF@\nREPLACE_DUP = @REPLACE_DUP@\nREPLACE_DUP2 = @REPLACE_DUP2@\nREPLACE_EXECL = @REPLACE_EXECL@\nREPLACE_EXECLE = @REPLACE_EXECLE@\nREPLACE_EXECLP = @REPLACE_EXECLP@\nREPLACE_EXECV = @REPLACE_EXECV@\nREPLACE_EXECVE = @REPLACE_EXECVE@\nREPLACE_EXECVP = @REPLACE_EXECVP@\nREPLACE_EXECVPE = @REPLACE_EXECVPE@\nREPLACE_FACCESSAT = @REPLACE_FACCESSAT@\nREPLACE_FCHMODAT = @REPLACE_FCHMODAT@\nREPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@\nREPLACE_FCLOSE = @REPLACE_FCLOSE@\nREPLACE_FDOPEN = @REPLACE_FDOPEN@\nREPLACE_FFLUSH = @REPLACE_FFLUSH@\nREPLACE_FOPEN = @REPLACE_FOPEN@\nREPLACE_FPRINTF = @REPLACE_FPRINTF@\nREPLACE_FPURGE = @REPLACE_FPURGE@\nREPLACE_FREE = @REPLACE_FREE@\nREPLACE_FREOPEN = @REPLACE_FREOPEN@\nREPLACE_FSEEK = @REPLACE_FSEEK@\nREPLACE_FSEEKO = @REPLACE_FSEEKO@\nREPLACE_FSTAT = @REPLACE_FSTAT@\nREPLACE_FSTATAT = @REPLACE_FSTATAT@\nREPLACE_FTELL = @REPLACE_FTELL@\nREPLACE_FTELLO = @REPLACE_FTELLO@\nREPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@\nREPLACE_FUTIMENS = @REPLACE_FUTIMENS@\nREPLACE_GETCWD = @REPLACE_GETCWD@\nREPLACE_GETDELIM = @REPLACE_GETDELIM@\nREPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@\nREPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@\nREPLACE_GETGROUPS = @REPLACE_GETGROUPS@\nREPLACE_GETLINE = @REPLACE_GETLINE@\nREPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@\nREPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@\nREPLACE_GETPASS = @REPLACE_GETPASS@\nREPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@\nREPLACE_GMTIME = @REPLACE_GMTIME@\nREPLACE_INITSTATE = @REPLACE_INITSTATE@\nREPLACE_ISATTY = @REPLACE_ISATTY@\nREPLACE_LCHOWN = @REPLACE_LCHOWN@\nREPLACE_LINK = @REPLACE_LINK@\nREPLACE_LINKAT = @REPLACE_LINKAT@\nREPLACE_LOCALTIME = @REPLACE_LOCALTIME@\nREPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@\nREPLACE_LSEEK = @REPLACE_LSEEK@\nREPLACE_LSTAT = @REPLACE_LSTAT@\nREPLACE_MALLOC = @REPLACE_MALLOC@\nREPLACE_MBTOWC = @REPLACE_MBTOWC@\nREPLACE_MKDIR = @REPLACE_MKDIR@\nREPLACE_MKFIFO = @REPLACE_MKFIFO@\nREPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@\nREPLACE_MKNOD = @REPLACE_MKNOD@\nREPLACE_MKNODAT = @REPLACE_MKNODAT@\nREPLACE_MKSTEMP = @REPLACE_MKSTEMP@\nREPLACE_MKTIME = @REPLACE_MKTIME@\nREPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@\nREPLACE_NULL = @REPLACE_NULL@\nREPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@\nREPLACE_PERROR = @REPLACE_PERROR@\nREPLACE_POPEN = @REPLACE_POPEN@\nREPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@\nREPLACE_PREAD = @REPLACE_PREAD@\nREPLACE_PRINTF = @REPLACE_PRINTF@\nREPLACE_PTSNAME = @REPLACE_PTSNAME@\nREPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@\nREPLACE_PUTENV = @REPLACE_PUTENV@\nREPLACE_PWRITE = @REPLACE_PWRITE@\nREPLACE_QSORT_R = @REPLACE_QSORT_R@\nREPLACE_RANDOM = @REPLACE_RANDOM@\nREPLACE_RANDOM_R = @REPLACE_RANDOM_R@\nREPLACE_READ = @REPLACE_READ@\nREPLACE_READLINK = @REPLACE_READLINK@\nREPLACE_READLINKAT = @REPLACE_READLINKAT@\nREPLACE_REALLOC = @REPLACE_REALLOC@\nREPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@\nREPLACE_REALPATH = @REPLACE_REALPATH@\nREPLACE_REMOVE = @REPLACE_REMOVE@\nREPLACE_RENAME = @REPLACE_RENAME@\nREPLACE_RENAMEAT = @REPLACE_RENAMEAT@\nREPLACE_RMDIR = @REPLACE_RMDIR@\nREPLACE_SETENV = @REPLACE_SETENV@\nREPLACE_SETSTATE = @REPLACE_SETSTATE@\nREPLACE_SLEEP = @REPLACE_SLEEP@\nREPLACE_SNPRINTF = @REPLACE_SNPRINTF@\nREPLACE_SPRINTF = @REPLACE_SPRINTF@\nREPLACE_STAT = @REPLACE_STAT@\nREPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@\nREPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@\nREPLACE_STRFTIME = @REPLACE_STRFTIME@\nREPLACE_STRTOD = @REPLACE_STRTOD@\nREPLACE_STRTOL = @REPLACE_STRTOL@\nREPLACE_STRTOLD = @REPLACE_STRTOLD@\nREPLACE_STRTOLL = @REPLACE_STRTOLL@\nREPLACE_STRTOUL = @REPLACE_STRTOUL@\nREPLACE_STRTOULL = @REPLACE_STRTOULL@\nREPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@\nREPLACE_SYMLINK = @REPLACE_SYMLINK@\nREPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@\nREPLACE_TIMEGM = @REPLACE_TIMEGM@\nREPLACE_TMPFILE = @REPLACE_TMPFILE@\nREPLACE_TRUNCATE = @REPLACE_TRUNCATE@\nREPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@\nREPLACE_TZSET = @REPLACE_TZSET@\nREPLACE_UNLINK = @REPLACE_UNLINK@\nREPLACE_UNLINKAT = @REPLACE_UNLINKAT@\nREPLACE_UNSETENV = @REPLACE_UNSETENV@\nREPLACE_USLEEP = @REPLACE_USLEEP@\nREPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@\nREPLACE_VASPRINTF = @REPLACE_VASPRINTF@\nREPLACE_VDPRINTF = @REPLACE_VDPRINTF@\nREPLACE_VFPRINTF = @REPLACE_VFPRINTF@\nREPLACE_VPRINTF = @REPLACE_VPRINTF@\nREPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@\nREPLACE_VSPRINTF = @REPLACE_VSPRINTF@\nREPLACE_WCTOMB = @REPLACE_WCTOMB@\nREPLACE_WRITE = @REPLACE_WRITE@\nSET_MAKE = @SET_MAKE@\nSHELL = @SHELL@\nSIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@\nSIZE_T_SUFFIX = @SIZE_T_SUFFIX@\nSTDALIGN_H = @STDALIGN_H@\nSTDDEF_H = @STDDEF_H@\nSTDINT_H = @STDINT_H@\nSTRIP = @STRIP@\nSYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@\nUNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@\nUNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@\nUNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@\nUNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@\nVERSION = @VERSION@\nWCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@\nWINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@\nWINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@\nWINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@\nWINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@\nWINT_T_SUFFIX = @WINT_T_SUFFIX@\nabs_builddir = @abs_builddir@\nabs_srcdir = @abs_srcdir@\nabs_top_builddir = @abs_top_builddir@\nabs_top_srcdir = @abs_top_srcdir@\nac_ct_CC = @ac_ct_CC@\nam__include = @am__include@\nam__leading_dot = @am__leading_dot@\nam__quote = @am__quote@\nam__tar = @am__tar@\nam__untar = @am__untar@\nbindir = @bindir@\nbuild = @build@\nbuild_alias = @build_alias@\nbuild_cpu = @build_cpu@\nbuild_os = @build_os@\nbuild_vendor = @build_vendor@\nbuilddir = @builddir@\ndatadir = @datadir@\ndatarootdir = @datarootdir@\ndocdir = @docdir@\ndvidir = @dvidir@\nexec_prefix = @exec_prefix@\ngl_LIBOBJS = @gl_LIBOBJS@\ngl_LTLIBOBJS = @gl_LTLIBOBJS@\nhost = @host@\nhost_alias = @host_alias@\nhost_cpu = @host_cpu@\nhost_os = @host_os@\nhost_vendor = @host_vendor@\nhtmldir = @htmldir@\nincludedir = @includedir@\ninfodir = @infodir@\ninstall_sh = @install_sh@\nlibdir = @libdir@\nlibexecdir = @libexecdir@\nlocaledir = @localedir@\nlocalstatedir = @localstatedir@\nmandir = @mandir@\nmkdir_p = @mkdir_p@\noldincludedir = @oldincludedir@\npdfdir = @pdfdir@\nprefix = @prefix@\nprogram_transform_name = @program_transform_name@\npsdir = @psdir@\nrunstatedir = @runstatedir@\nsbindir = @sbindir@\nsharedstatedir = @sharedstatedir@\nsrcdir = @srcdir@\nsysconfdir = @sysconfdir@\ntarget_alias = @target_alias@\ntop_build_prefix = @top_build_prefix@\ntop_builddir = @top_builddir@\ntop_srcdir = @top_srcdir@\nAUTOMAKE_OPTIONS = 1.11 foreign\nSUBDIRS = gllib glm4\nACLOCAL_AMFLAGS = -I glm4\nall: config.h\n\t$(MAKE) $(AM_MAKEFLAGS) all-recursive\n\n.SUFFIXES:\nam--refresh: Makefile\n\t@:\n$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)\n\t@for dep in $?; do \\\n\t  case '$(am__configure_deps)' in \\\n\t    *$$dep*) \\\n\t      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \\\n\t      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \\\n\t\t&& exit 0; \\\n\t      exit 1;; \\\n\t  esac; \\\n\tdone; \\\n\techo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \\\n\t$(am__cd) $(top_srcdir) && \\\n\t  $(AUTOMAKE) --foreign Makefile\nMakefile: $(srcdir)/Makefile.in $(top_builddir)/config.status\n\t@case '$?' in \\\n\t  *config.status*) \\\n\t    echo ' $(SHELL) ./config.status'; \\\n\t    $(SHELL) ./config.status;; \\\n\t  *) \\\n\t    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \\\n\t    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \\\n\tesac;\n\n$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)\n\t$(SHELL) ./config.status --recheck\n\n$(top_srcdir)/configure:  $(am__configure_deps)\n\t$(am__cd) $(srcdir) && $(AUTOCONF)\n$(ACLOCAL_M4):  $(am__aclocal_m4_deps)\n\t$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)\n$(am__aclocal_m4_deps):\n\nconfig.h: stamp-h1\n\t@test -f $@ || rm -f stamp-h1\n\t@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1\n\nstamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status\n\t@rm -f stamp-h1\n\tcd $(top_builddir) && $(SHELL) ./config.status config.h\n$(srcdir)/config.h.in:  $(am__configure_deps) \n\t($(am__cd) $(top_srcdir) && $(AUTOHEADER))\n\trm -f stamp-h1\n\ttouch $@\n\ndistclean-hdr:\n\t-rm -f config.h stamp-h1\n\n# This directory's subdirectories are mostly independent; you can cd\n# into them and run 'make' without going through this Makefile.\n# To change the values of 'make' variables: instead of editing Makefiles,\n# (1) if the variable is set in 'config.status', edit 'config.status'\n#     (which will cause the Makefiles to be regenerated when you run 'make');\n# (2) otherwise, pass the desired values on the 'make' command line.\n$(am__recursive_targets):\n\t@fail=; \\\n\tif $(am__make_keepgoing); then \\\n\t  failcom='fail=yes'; \\\n\telse \\\n\t  failcom='exit 1'; \\\n\tfi; \\\n\tdot_seen=no; \\\n\ttarget=`echo $@ | sed s/-recursive//`; \\\n\tcase \"$@\" in \\\n\t  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \\\n\t  *) list='$(SUBDIRS)' ;; \\\n\tesac; \\\n\tfor subdir in $$list; do \\\n\t  echo \"Making $$target in $$subdir\"; \\\n\t  if test \"$$subdir\" = \".\"; then \\\n\t    dot_seen=yes; \\\n\t    local_target=\"$$target-am\"; \\\n\t  else \\\n\t    local_target=\"$$target\"; \\\n\t  fi; \\\n\t  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \\\n\t  || eval $$failcom; \\\n\tdone; \\\n\tif test \"$$dot_seen\" = \"no\"; then \\\n\t  $(MAKE) $(AM_MAKEFLAGS) \"$$target-am\" || exit 1; \\\n\tfi; test -z \"$$fail\"\n\nID: $(am__tagged_files)\n\t$(am__define_uniq_tagged_files); mkid -fID $$unique\ntags: tags-recursive\nTAGS: tags\n\ntags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)\n\tset x; \\\n\there=`pwd`; \\\n\tif ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \\\n\t  include_option=--etags-include; \\\n\t  empty_fix=.; \\\n\telse \\\n\t  include_option=--include; \\\n\t  empty_fix=; \\\n\tfi; \\\n\tlist='$(SUBDIRS)'; for subdir in $$list; do \\\n\t  if test \"$$subdir\" = .; then :; else \\\n\t    test ! -f $$subdir/TAGS || \\\n\t      set \"$$@\" \"$$include_option=$$here/$$subdir/TAGS\"; \\\n\t  fi; \\\n\tdone; \\\n\t$(am__define_uniq_tagged_files); \\\n\tshift; \\\n\tif test -z \"$(ETAGS_ARGS)$$*$$unique\"; then :; else \\\n\t  test -n \"$$unique\" || unique=$$empty_fix; \\\n\t  if test $$# -gt 0; then \\\n\t    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \\\n\t      \"$$@\" $$unique; \\\n\t  else \\\n\t    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \\\n\t      $$unique; \\\n\t  fi; \\\n\tfi\nctags: ctags-recursive\n\nCTAGS: ctags\nctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)\n\t$(am__define_uniq_tagged_files); \\\n\ttest -z \"$(CTAGS_ARGS)$$unique\" \\\n\t  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \\\n\t     $$unique\n\nGTAGS:\n\there=`$(am__cd) $(top_builddir) && pwd` \\\n\t  && $(am__cd) $(top_srcdir) \\\n\t  && gtags -i $(GTAGS_ARGS) \"$$here\"\ncscope: cscope.files\n\ttest ! -s cscope.files \\\n\t  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)\nclean-cscope:\n\t-rm -f cscope.files\ncscope.files: clean-cscope cscopelist\ncscopelist: cscopelist-recursive\n\ncscopelist-am: $(am__tagged_files)\n\tlist='$(am__tagged_files)'; \\\n\tcase \"$(srcdir)\" in \\\n\t  [\\\\/]* | ?:[\\\\/]*) sdir=\"$(srcdir)\" ;; \\\n\t  *) sdir=$(subdir)/$(srcdir) ;; \\\n\tesac; \\\n\tfor i in $$list; do \\\n\t  if test -f \"$$i\"; then \\\n\t    echo \"$(subdir)/$$i\"; \\\n\t  else \\\n\t    echo \"$$sdir/$$i\"; \\\n\t  fi; \\\n\tdone >> $(top_builddir)/cscope.files\n\ndistclean-tags:\n\t-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags\n\t-rm -f cscope.out cscope.in.out cscope.po.out cscope.files\n\ndistdir: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) distdir-am\n\ndistdir-am: $(DISTFILES)\n\t$(am__remove_distdir)\n\ttest -d \"$(distdir)\" || mkdir \"$(distdir)\"\n\t@srcdirstrip=`echo \"$(srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\ttopsrcdirstrip=`echo \"$(top_srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\tlist='$(DISTFILES)'; \\\n\t  dist_files=`for file in $$list; do echo $$file; done | \\\n\t  sed -e \"s|^$$srcdirstrip/||;t\" \\\n\t      -e \"s|^$$topsrcdirstrip/|$(top_builddir)/|;t\"`; \\\n\tcase $$dist_files in \\\n\t  */*) $(MKDIR_P) `echo \"$$dist_files\" | \\\n\t\t\t   sed '/\\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \\\n\t\t\t   sort -u` ;; \\\n\tesac; \\\n\tfor file in $$dist_files; do \\\n\t  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \\\n\t  if test -d $$d/$$file; then \\\n\t    dir=`echo \"/$$file\" | sed -e 's,/[^/]*$$,,'`; \\\n\t    if test -d \"$(distdir)/$$file\"; then \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \\\n\t      cp -fpR $(srcdir)/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    cp -fpR $$d/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t  else \\\n\t    test -f \"$(distdir)/$$file\" \\\n\t    || cp -p $$d/$$file \"$(distdir)/$$file\" \\\n\t    || exit 1; \\\n\t  fi; \\\n\tdone\n\t@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \\\n\t  if test \"$$subdir\" = .; then :; else \\\n\t    $(am__make_dryrun) \\\n\t      || test -d \"$(distdir)/$$subdir\" \\\n\t      || $(MKDIR_P) \"$(distdir)/$$subdir\" \\\n\t      || exit 1; \\\n\t    dir1=$$subdir; dir2=\"$(distdir)/$$subdir\"; \\\n\t    $(am__relativize); \\\n\t    new_distdir=$$reldir; \\\n\t    dir1=$$subdir; dir2=\"$(top_distdir)\"; \\\n\t    $(am__relativize); \\\n\t    new_top_distdir=$$reldir; \\\n\t    echo \" (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=\"$$new_top_distdir\" distdir=\"$$new_distdir\" \\\\\"; \\\n\t    echo \"     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)\"; \\\n\t    ($(am__cd) $$subdir && \\\n\t      $(MAKE) $(AM_MAKEFLAGS) \\\n\t        top_distdir=\"$$new_top_distdir\" \\\n\t        distdir=\"$$new_distdir\" \\\n\t\tam__remove_distdir=: \\\n\t\tam__skip_length_check=: \\\n\t\tam__skip_mode_fix=: \\\n\t        distdir) \\\n\t      || exit 1; \\\n\t  fi; \\\n\tdone\n\t-test -n \"$(am__skip_mode_fix)\" \\\n\t|| find \"$(distdir)\" -type d ! -perm -755 \\\n\t\t-exec chmod u+rwx,go+rx {} \\; -o \\\n\t  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \\; -o \\\n\t  ! -type d ! -perm -400 -exec chmod a+r {} \\; -o \\\n\t  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \\; \\\n\t|| chmod -R a+r \"$(distdir)\"\ndist-gzip: distdir\n\ttardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz\n\t$(am__post_remove_distdir)\n\ndist-bzip2: distdir\n\ttardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2\n\t$(am__post_remove_distdir)\n\ndist-lzip: distdir\n\ttardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz\n\t$(am__post_remove_distdir)\n\ndist-xz: distdir\n\ttardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz\n\t$(am__post_remove_distdir)\n\ndist-zstd: distdir\n\ttardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst\n\t$(am__post_remove_distdir)\n\ndist-tarZ: distdir\n\t@echo WARNING: \"Support for distribution archives compressed with\" \\\n\t\t       \"legacy program 'compress' is deprecated.\" >&2\n\t@echo WARNING: \"It will be removed altogether in Automake 2.0\" >&2\n\ttardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z\n\t$(am__post_remove_distdir)\n\ndist-shar: distdir\n\t@echo WARNING: \"Support for shar distribution archives is\" \\\n\t               \"deprecated.\" >&2\n\t@echo WARNING: \"It will be removed altogether in Automake 2.0\" >&2\n\tshar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz\n\t$(am__post_remove_distdir)\n\ndist-zip: distdir\n\t-rm -f $(distdir).zip\n\tzip -rq $(distdir).zip $(distdir)\n\t$(am__post_remove_distdir)\n\ndist dist-all:\n\t$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'\n\t$(am__post_remove_distdir)\n\n# This target untars the dist file and tries a VPATH configuration.  Then\n# it guarantees that the distribution is self-contained by making another\n# tarfile.\ndistcheck: dist\n\tcase '$(DIST_ARCHIVES)' in \\\n\t*.tar.gz*) \\\n\t  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\\\n\t*.tar.bz2*) \\\n\t  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\\\n\t*.tar.lz*) \\\n\t  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\\\n\t*.tar.xz*) \\\n\t  xz -dc $(distdir).tar.xz | $(am__untar) ;;\\\n\t*.tar.Z*) \\\n\t  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\\\n\t*.shar.gz*) \\\n\t  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\\\n\t*.zip*) \\\n\t  unzip $(distdir).zip ;;\\\n\t*.tar.zst*) \\\n\t  zstd -dc $(distdir).tar.zst | $(am__untar) ;;\\\n\tesac\n\tchmod -R a-w $(distdir)\n\tchmod u+w $(distdir)\n\tmkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst\n\tchmod a-w $(distdir)\n\ttest -d $(distdir)/_build || exit 0; \\\n\tdc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\\\/]:[\\\\/],/,'` \\\n\t  && dc_destdir=\"$${TMPDIR-/tmp}/am-dc-$$$$/\" \\\n\t  && am__cwd=`pwd` \\\n\t  && $(am__cd) $(distdir)/_build/sub \\\n\t  && ../../configure \\\n\t    $(AM_DISTCHECK_CONFIGURE_FLAGS) \\\n\t    $(DISTCHECK_CONFIGURE_FLAGS) \\\n\t    --srcdir=../.. --prefix=\"$$dc_install_base\" \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) check \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) install \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) installcheck \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) uninstall \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir=\"$$dc_install_base\" \\\n\t        distuninstallcheck \\\n\t  && chmod -R a-w \"$$dc_install_base\" \\\n\t  && ({ \\\n\t       (cd ../.. && umask 077 && mkdir \"$$dc_destdir\") \\\n\t       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR=\"$$dc_destdir\" install \\\n\t       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR=\"$$dc_destdir\" uninstall \\\n\t       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR=\"$$dc_destdir\" \\\n\t            distuninstallcheck_dir=\"$$dc_destdir\" distuninstallcheck; \\\n\t      } || { rm -rf \"$$dc_destdir\"; exit 1; }) \\\n\t  && rm -rf \"$$dc_destdir\" \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) dist \\\n\t  && rm -rf $(DIST_ARCHIVES) \\\n\t  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \\\n\t  && cd \"$$am__cwd\" \\\n\t  || exit 1\n\t$(am__post_remove_distdir)\n\t@(echo \"$(distdir) archives ready for distribution: \"; \\\n\t  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \\\n\t  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'\ndistuninstallcheck:\n\t@test -n '$(distuninstallcheck_dir)' || { \\\n\t  echo 'ERROR: trying to run $@ with an empty' \\\n\t       '$$(distuninstallcheck_dir)' >&2; \\\n\t  exit 1; \\\n\t}; \\\n\t$(am__cd) '$(distuninstallcheck_dir)' || { \\\n\t  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \\\n\t  exit 1; \\\n\t}; \\\n\ttest `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \\\n\t   || { echo \"ERROR: files left after uninstall:\" ; \\\n\t        if test -n \"$(DESTDIR)\"; then \\\n\t          echo \"  (check DESTDIR support)\"; \\\n\t        fi ; \\\n\t        $(distuninstallcheck_listfiles) ; \\\n\t        exit 1; } >&2\ndistcleancheck: distclean\n\t@if test '$(srcdir)' = . ; then \\\n\t  echo \"ERROR: distcleancheck can only run from a VPATH build\" ; \\\n\t  exit 1 ; \\\n\tfi\n\t@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \\\n\t  || { echo \"ERROR: files left in build directory after distclean:\" ; \\\n\t       $(distcleancheck_listfiles) ; \\\n\t       exit 1; } >&2\ncheck-am: all-am\ncheck: check-recursive\nall-am: Makefile config.h\ninstalldirs: installdirs-recursive\ninstalldirs-am:\ninstall: install-recursive\ninstall-exec: install-exec-recursive\ninstall-data: install-data-recursive\nuninstall: uninstall-recursive\n\ninstall-am: all-am\n\t@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am\n\ninstallcheck: installcheck-recursive\ninstall-strip:\n\tif test -z '$(STRIP)'; then \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t      install; \\\n\telse \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t    \"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'\" install; \\\n\tfi\nmostlyclean-generic:\n\nclean-generic:\n\ndistclean-generic:\n\t-test -z \"$(CONFIG_CLEAN_FILES)\" || rm -f $(CONFIG_CLEAN_FILES)\n\t-test . = \"$(srcdir)\" || test -z \"$(CONFIG_CLEAN_VPATH_FILES)\" || rm -f $(CONFIG_CLEAN_VPATH_FILES)\n\nmaintainer-clean-generic:\n\t@echo \"This command is intended for maintainers to use\"\n\t@echo \"it deletes files that may require special tools to rebuild.\"\nclean: clean-recursive\n\nclean-am: clean-generic mostlyclean-am\n\ndistclean: distclean-recursive\n\t-rm -f $(am__CONFIG_DISTCLEAN_FILES)\n\t-rm -f Makefile\ndistclean-am: clean-am distclean-generic distclean-hdr distclean-tags\n\ndvi: dvi-recursive\n\ndvi-am:\n\nhtml: html-recursive\n\nhtml-am:\n\ninfo: info-recursive\n\ninfo-am:\n\ninstall-data-am:\n\ninstall-dvi: install-dvi-recursive\n\ninstall-dvi-am:\n\ninstall-exec-am:\n\ninstall-html: install-html-recursive\n\ninstall-html-am:\n\ninstall-info: install-info-recursive\n\ninstall-info-am:\n\ninstall-man:\n\ninstall-pdf: install-pdf-recursive\n\ninstall-pdf-am:\n\ninstall-ps: install-ps-recursive\n\ninstall-ps-am:\n\ninstallcheck-am:\n\nmaintainer-clean: maintainer-clean-recursive\n\t-rm -f $(am__CONFIG_DISTCLEAN_FILES)\n\t-rm -rf $(top_srcdir)/autom4te.cache\n\t-rm -f Makefile\nmaintainer-clean-am: distclean-am maintainer-clean-generic\n\nmostlyclean: mostlyclean-recursive\n\nmostlyclean-am: mostlyclean-generic\n\npdf: pdf-recursive\n\npdf-am:\n\nps: ps-recursive\n\nps-am:\n\nuninstall-am:\n\n.MAKE: $(am__recursive_targets) all install-am install-strip\n\n.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \\\n\tam--refresh check check-am clean clean-cscope clean-generic \\\n\tcscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \\\n\tdist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \\\n\tdist-zstd distcheck distclean distclean-generic distclean-hdr \\\n\tdistclean-tags distcleancheck distdir distuninstallcheck dvi \\\n\tdvi-am html html-am info info-am install install-am \\\n\tinstall-data install-data-am install-dvi install-dvi-am \\\n\tinstall-exec install-exec-am install-html install-html-am \\\n\tinstall-info install-info-am install-man install-pdf \\\n\tinstall-pdf-am install-ps install-ps-am install-strip \\\n\tinstallcheck installcheck-am installdirs installdirs-am \\\n\tmaintainer-clean maintainer-clean-generic mostlyclean \\\n\tmostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \\\n\tuninstall-am\n\n.PRECIOUS: Makefile\n\n\n# Tell versions [3.59,3.63) of GNU make to not export all variables.\n# Otherwise a system limit (for SysV at least) may be exceeded.\n.NOEXPORT:\n"
  },
  {
    "path": "windows_compat/gnulib/aclocal.m4",
    "content": "# generated automatically by aclocal 1.16.3 -*- Autoconf -*-\n\n# Copyright (C) 1996-2020 Free Software Foundation, Inc.\n\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY, to the extent permitted by law; without\n# even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n# PARTICULAR PURPOSE.\n\nm4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])\nm4_ifndef([AC_AUTOCONF_VERSION],\n  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl\nm4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],,\n[m4_warning([this file was generated for autoconf 2.71.\nYou have another version of autoconf.  It may work, but is not guaranteed to.\nIf you have problems, you may need to regenerate the build system entirely.\nTo do so, use the procedure documented by the package, typically 'autoreconf'.])])\n\n# Copyright (C) 2002-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_AUTOMAKE_VERSION(VERSION)\n# ----------------------------\n# Automake X.Y traces this macro to ensure aclocal.m4 has been\n# generated from the m4 files accompanying Automake X.Y.\n# (This private macro should not be called outside this file.)\nAC_DEFUN([AM_AUTOMAKE_VERSION],\n[am__api_version='1.16'\ndnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to\ndnl require some minimum version.  Point them to the right macro.\nm4_if([$1], [1.16.3], [],\n      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl\n])\n\n# _AM_AUTOCONF_VERSION(VERSION)\n# -----------------------------\n# aclocal traces this macro to find the Autoconf version.\n# This is a private macro too.  Using m4_define simplifies\n# the logic in aclocal, which can simply ignore this definition.\nm4_define([_AM_AUTOCONF_VERSION], [])\n\n# AM_SET_CURRENT_AUTOMAKE_VERSION\n# -------------------------------\n# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.\n# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.\nAC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],\n[AM_AUTOMAKE_VERSION([1.16.3])dnl\nm4_ifndef([AC_AUTOCONF_VERSION],\n  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl\n_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])\n\n# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets\n# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to\n# '$srcdir', '$srcdir/..', or '$srcdir/../..'.\n#\n# Of course, Automake must honor this variable whenever it calls a\n# tool from the auxiliary directory.  The problem is that $srcdir (and\n# therefore $ac_aux_dir as well) can be either absolute or relative,\n# depending on how configure is run.  This is pretty annoying, since\n# it makes $ac_aux_dir quite unusable in subdirectories: in the top\n# source directory, any form will work fine, but in subdirectories a\n# relative path needs to be adjusted first.\n#\n# $ac_aux_dir/missing\n#    fails when called from a subdirectory if $ac_aux_dir is relative\n# $top_srcdir/$ac_aux_dir/missing\n#    fails if $ac_aux_dir is absolute,\n#    fails when called from a subdirectory in a VPATH build with\n#          a relative $ac_aux_dir\n#\n# The reason of the latter failure is that $top_srcdir and $ac_aux_dir\n# are both prefixed by $srcdir.  In an in-source build this is usually\n# harmless because $srcdir is '.', but things will broke when you\n# start a VPATH build or use an absolute $srcdir.\n#\n# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,\n# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:\n#   am_aux_dir='\\$(top_srcdir)/'`expr \"$ac_aux_dir\" : \"$srcdir//*\\(.*\\)\"`\n# and then we would define $MISSING as\n#   MISSING=\"\\${SHELL} $am_aux_dir/missing\"\n# This will work as long as MISSING is not called from configure, because\n# unfortunately $(top_srcdir) has no meaning in configure.\n# However there are other variables, like CC, which are often used in\n# configure, and could therefore not use this \"fixed\" $ac_aux_dir.\n#\n# Another solution, used here, is to always expand $ac_aux_dir to an\n# absolute PATH.  The drawback is that using absolute paths prevent a\n# configured tree to be moved without reconfiguration.\n\nAC_DEFUN([AM_AUX_DIR_EXPAND],\n[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl\n# Expand $ac_aux_dir to an absolute path.\nam_aux_dir=`cd \"$ac_aux_dir\" && pwd`\n])\n\n# AM_CONDITIONAL                                            -*- Autoconf -*-\n\n# Copyright (C) 1997-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_CONDITIONAL(NAME, SHELL-CONDITION)\n# -------------------------------------\n# Define a conditional.\nAC_DEFUN([AM_CONDITIONAL],\n[AC_PREREQ([2.52])dnl\n m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],\n       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl\nAC_SUBST([$1_TRUE])dnl\nAC_SUBST([$1_FALSE])dnl\n_AM_SUBST_NOTMAKE([$1_TRUE])dnl\n_AM_SUBST_NOTMAKE([$1_FALSE])dnl\nm4_define([_AM_COND_VALUE_$1], [$2])dnl\nif $2; then\n  $1_TRUE=\n  $1_FALSE='#'\nelse\n  $1_TRUE='#'\n  $1_FALSE=\nfi\nAC_CONFIG_COMMANDS_PRE(\n[if test -z \"${$1_TRUE}\" && test -z \"${$1_FALSE}\"; then\n  AC_MSG_ERROR([[conditional \"$1\" was never defined.\nUsually this means the macro was only invoked conditionally.]])\nfi])])\n\n# Copyright (C) 1999-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n\n# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be\n# written in clear, in which case automake, when reading aclocal.m4,\n# will think it sees a *use*, and therefore will trigger all it's\n# C support machinery.  Also note that it means that autoscan, seeing\n# CC etc. in the Makefile, will ask for an AC_PROG_CC use...\n\n\n# _AM_DEPENDENCIES(NAME)\n# ----------------------\n# See how the compiler implements dependency checking.\n# NAME is \"CC\", \"CXX\", \"OBJC\", \"OBJCXX\", \"UPC\", or \"GJC\".\n# We try a few techniques and use that to set a single cache variable.\n#\n# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was\n# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular\n# dependency, and given that the user is not expected to run this macro,\n# just rely on AC_PROG_CC.\nAC_DEFUN([_AM_DEPENDENCIES],\n[AC_REQUIRE([AM_SET_DEPDIR])dnl\nAC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl\nAC_REQUIRE([AM_MAKE_INCLUDE])dnl\nAC_REQUIRE([AM_DEP_TRACK])dnl\n\nm4_if([$1], [CC],   [depcc=\"$CC\"   am_compiler_list=],\n      [$1], [CXX],  [depcc=\"$CXX\"  am_compiler_list=],\n      [$1], [OBJC], [depcc=\"$OBJC\" am_compiler_list='gcc3 gcc'],\n      [$1], [OBJCXX], [depcc=\"$OBJCXX\" am_compiler_list='gcc3 gcc'],\n      [$1], [UPC],  [depcc=\"$UPC\"  am_compiler_list=],\n      [$1], [GCJ],  [depcc=\"$GCJ\"  am_compiler_list='gcc3 gcc'],\n                    [depcc=\"$$1\"   am_compiler_list=])\n\nAC_CACHE_CHECK([dependency style of $depcc],\n               [am_cv_$1_dependencies_compiler_type],\n[if test -z \"$AMDEP_TRUE\" && test -f \"$am_depcomp\"; then\n  # We make a subdir and do the tests there.  Otherwise we can end up\n  # making bogus files that we don't know about and never remove.  For\n  # instance it was reported that on HP-UX the gcc test will end up\n  # making a dummy file named 'D' -- because '-MD' means \"put the output\n  # in D\".\n  rm -rf conftest.dir\n  mkdir conftest.dir\n  # Copy depcomp to subdir because otherwise we won't find it if we're\n  # using a relative directory.\n  cp \"$am_depcomp\" conftest.dir\n  cd conftest.dir\n  # We will build objects and dependencies in a subdirectory because\n  # it helps to detect inapplicable dependency modes.  For instance\n  # both Tru64's cc and ICC support -MD to output dependencies as a\n  # side effect of compilation, but ICC will put the dependencies in\n  # the current directory while Tru64 will put them in the object\n  # directory.\n  mkdir sub\n\n  am_cv_$1_dependencies_compiler_type=none\n  if test \"$am_compiler_list\" = \"\"; then\n     am_compiler_list=`sed -n ['s/^#*\\([a-zA-Z0-9]*\\))$/\\1/p'] < ./depcomp`\n  fi\n  am__universal=false\n  m4_case([$1], [CC],\n    [case \" $depcc \" in #(\n     *\\ -arch\\ *\\ -arch\\ *) am__universal=true ;;\n     esac],\n    [CXX],\n    [case \" $depcc \" in #(\n     *\\ -arch\\ *\\ -arch\\ *) am__universal=true ;;\n     esac])\n\n  for depmode in $am_compiler_list; do\n    # Setup a source with many dependencies, because some compilers\n    # like to wrap large dependency lists on column 80 (with \\), and\n    # we should not choose a depcomp mode which is confused by this.\n    #\n    # We need to recreate these files for each test, as the compiler may\n    # overwrite some of them when testing with obscure command lines.\n    # This happens at least with the AIX C compiler.\n    : > sub/conftest.c\n    for i in 1 2 3 4 5 6; do\n      echo '#include \"conftst'$i'.h\"' >> sub/conftest.c\n      # Using \": > sub/conftst$i.h\" creates only sub/conftst1.h with\n      # Solaris 10 /bin/sh.\n      echo '/* dummy */' > sub/conftst$i.h\n    done\n    echo \"${am__include} ${am__quote}sub/conftest.Po${am__quote}\" > confmf\n\n    # We check with '-c' and '-o' for the sake of the \"dashmstdout\"\n    # mode.  It turns out that the SunPro C++ compiler does not properly\n    # handle '-M -o', and we need to detect this.  Also, some Intel\n    # versions had trouble with output in subdirs.\n    am__obj=sub/conftest.${OBJEXT-o}\n    am__minus_obj=\"-o $am__obj\"\n    case $depmode in\n    gcc)\n      # This depmode causes a compiler race in universal mode.\n      test \"$am__universal\" = false || continue\n      ;;\n    nosideeffect)\n      # After this tag, mechanisms are not by side-effect, so they'll\n      # only be used when explicitly requested.\n      if test \"x$enable_dependency_tracking\" = xyes; then\n\tcontinue\n      else\n\tbreak\n      fi\n      ;;\n    msvc7 | msvc7msys | msvisualcpp | msvcmsys)\n      # This compiler won't grok '-c -o', but also, the minuso test has\n      # not run yet.  These depmodes are late enough in the game, and\n      # so weak that their functioning should not be impacted.\n      am__obj=conftest.${OBJEXT-o}\n      am__minus_obj=\n      ;;\n    none) break ;;\n    esac\n    if depmode=$depmode \\\n       source=sub/conftest.c object=$am__obj \\\n       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \\\n       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \\\n         >/dev/null 2>conftest.err &&\n       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&\n       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&\n       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&\n       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then\n      # icc doesn't choke on unknown options, it will just issue warnings\n      # or remarks (even with -Werror).  So we grep stderr for any message\n      # that says an option was ignored or not supported.\n      # When given -MP, icc 7.0 and 7.1 complain thusly:\n      #   icc: Command line warning: ignoring option '-M'; no argument required\n      # The diagnosis changed in icc 8.0:\n      #   icc: Command line remark: option '-MP' not supported\n      if (grep 'ignoring option' conftest.err ||\n          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else\n        am_cv_$1_dependencies_compiler_type=$depmode\n        break\n      fi\n    fi\n  done\n\n  cd ..\n  rm -rf conftest.dir\nelse\n  am_cv_$1_dependencies_compiler_type=none\nfi\n])\nAC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])\nAM_CONDITIONAL([am__fastdep$1], [\n  test \"x$enable_dependency_tracking\" != xno \\\n  && test \"$am_cv_$1_dependencies_compiler_type\" = gcc3])\n])\n\n\n# AM_SET_DEPDIR\n# -------------\n# Choose a directory name for dependency files.\n# This macro is AC_REQUIREd in _AM_DEPENDENCIES.\nAC_DEFUN([AM_SET_DEPDIR],\n[AC_REQUIRE([AM_SET_LEADING_DOT])dnl\nAC_SUBST([DEPDIR], [\"${am__leading_dot}deps\"])dnl\n])\n\n\n# AM_DEP_TRACK\n# ------------\nAC_DEFUN([AM_DEP_TRACK],\n[AC_ARG_ENABLE([dependency-tracking], [dnl\nAS_HELP_STRING(\n  [--enable-dependency-tracking],\n  [do not reject slow dependency extractors])\nAS_HELP_STRING(\n  [--disable-dependency-tracking],\n  [speeds up one-time build])])\nif test \"x$enable_dependency_tracking\" != xno; then\n  am_depcomp=\"$ac_aux_dir/depcomp\"\n  AMDEPBACKSLASH='\\'\n  am__nodep='_no'\nfi\nAM_CONDITIONAL([AMDEP], [test \"x$enable_dependency_tracking\" != xno])\nAC_SUBST([AMDEPBACKSLASH])dnl\n_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl\nAC_SUBST([am__nodep])dnl\n_AM_SUBST_NOTMAKE([am__nodep])dnl\n])\n\n# Generate code to set up dependency tracking.              -*- Autoconf -*-\n\n# Copyright (C) 1999-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# _AM_OUTPUT_DEPENDENCY_COMMANDS\n# ------------------------------\nAC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],\n[{\n  # Older Autoconf quotes --file arguments for eval, but not when files\n  # are listed without --file.  Let's play safe and only enable the eval\n  # if we detect the quoting.\n  # TODO: see whether this extra hack can be removed once we start\n  # requiring Autoconf 2.70 or later.\n  AS_CASE([$CONFIG_FILES],\n          [*\\'*], [eval set x \"$CONFIG_FILES\"],\n          [*], [set x $CONFIG_FILES])\n  shift\n  # Used to flag and report bootstrapping failures.\n  am_rc=0\n  for am_mf\n  do\n    # Strip MF so we end up with the name of the file.\n    am_mf=`AS_ECHO([\"$am_mf\"]) | sed -e 's/:.*$//'`\n    # Check whether this is an Automake generated Makefile which includes\n    # dependency-tracking related rules and includes.\n    # Grep'ing the whole file directly is not great: AIX grep has a line\n    # limit of 2048, but all sed's we know have understand at least 4000.\n    sed -n 's,^am--depfiles:.*,X,p' \"$am_mf\" | grep X >/dev/null 2>&1 \\\n      || continue\n    am_dirpart=`AS_DIRNAME([\"$am_mf\"])`\n    am_filepart=`AS_BASENAME([\"$am_mf\"])`\n    AM_RUN_LOG([cd \"$am_dirpart\" \\\n      && sed -e '/# am--include-marker/d' \"$am_filepart\" \\\n        | $MAKE -f - am--depfiles]) || am_rc=$?\n  done\n  if test $am_rc -ne 0; then\n    AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments\n    for automatic dependency tracking.  If GNU make was not used, consider\n    re-running the configure script with MAKE=\"gmake\" (or whatever is\n    necessary).  You can also try re-running configure with the\n    '--disable-dependency-tracking' option to at least be able to build\n    the package (albeit without support for automatic dependency tracking).])\n  fi\n  AS_UNSET([am_dirpart])\n  AS_UNSET([am_filepart])\n  AS_UNSET([am_mf])\n  AS_UNSET([am_rc])\n  rm -f conftest-deps.mk\n}\n])# _AM_OUTPUT_DEPENDENCY_COMMANDS\n\n\n# AM_OUTPUT_DEPENDENCY_COMMANDS\n# -----------------------------\n# This macro should only be invoked once -- use via AC_REQUIRE.\n#\n# This code is only required when automatic dependency tracking is enabled.\n# This creates each '.Po' and '.Plo' makefile fragment that we'll need in\n# order to bootstrap the dependency handling code.\nAC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],\n[AC_CONFIG_COMMANDS([depfiles],\n     [test x\"$AMDEP_TRUE\" != x\"\" || _AM_OUTPUT_DEPENDENCY_COMMANDS],\n     [AMDEP_TRUE=\"$AMDEP_TRUE\" MAKE=\"${MAKE-make}\"])])\n\n# Do all the work for Automake.                             -*- Autoconf -*-\n\n# Copyright (C) 1996-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This macro actually does too much.  Some checks are only needed if\n# your package does certain things.  But this isn't really a big deal.\n\ndnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.\nm4_define([AC_PROG_CC],\nm4_defn([AC_PROG_CC])\n[_AM_PROG_CC_C_O\n])\n\n# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])\n# AM_INIT_AUTOMAKE([OPTIONS])\n# -----------------------------------------------\n# The call with PACKAGE and VERSION arguments is the old style\n# call (pre autoconf-2.50), which is being phased out.  PACKAGE\n# and VERSION should now be passed to AC_INIT and removed from\n# the call to AM_INIT_AUTOMAKE.\n# We support both call styles for the transition.  After\n# the next Automake release, Autoconf can make the AC_INIT\n# arguments mandatory, and then we can depend on a new Autoconf\n# release and drop the old call support.\nAC_DEFUN([AM_INIT_AUTOMAKE],\n[AC_PREREQ([2.65])dnl\ndnl Autoconf wants to disallow AM_ names.  We explicitly allow\ndnl the ones we care about.\nm4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl\nAC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl\nAC_REQUIRE([AC_PROG_INSTALL])dnl\nif test \"`cd $srcdir && pwd`\" != \"`pwd`\"; then\n  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output\n  # is not polluted with repeated \"-I.\"\n  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl\n  # test to see if srcdir already configured\n  if test -f $srcdir/config.status; then\n    AC_MSG_ERROR([source directory already configured; run \"make distclean\" there first])\n  fi\nfi\n\n# test whether we have cygpath\nif test -z \"$CYGPATH_W\"; then\n  if (cygpath --version) >/dev/null 2>/dev/null; then\n    CYGPATH_W='cygpath -w'\n  else\n    CYGPATH_W=echo\n  fi\nfi\nAC_SUBST([CYGPATH_W])\n\n# Define the identity of the package.\ndnl Distinguish between old-style and new-style calls.\nm4_ifval([$2],\n[AC_DIAGNOSE([obsolete],\n             [$0: two- and three-arguments forms are deprecated.])\nm4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl\n AC_SUBST([PACKAGE], [$1])dnl\n AC_SUBST([VERSION], [$2])],\n[_AM_SET_OPTIONS([$1])dnl\ndnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.\nm4_if(\n  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),\n  [ok:ok],,\n  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl\n AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl\n AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl\n\n_AM_IF_OPTION([no-define],,\n[AC_DEFINE_UNQUOTED([PACKAGE], [\"$PACKAGE\"], [Name of package])\n AC_DEFINE_UNQUOTED([VERSION], [\"$VERSION\"], [Version number of package])])dnl\n\n# Some tools Automake needs.\nAC_REQUIRE([AM_SANITY_CHECK])dnl\nAC_REQUIRE([AC_ARG_PROGRAM])dnl\nAM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])\nAM_MISSING_PROG([AUTOCONF], [autoconf])\nAM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])\nAM_MISSING_PROG([AUTOHEADER], [autoheader])\nAM_MISSING_PROG([MAKEINFO], [makeinfo])\nAC_REQUIRE([AM_PROG_INSTALL_SH])dnl\nAC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl\nAC_REQUIRE([AC_PROG_MKDIR_P])dnl\n# For better backward compatibility.  To be removed once Automake 1.9.x\n# dies out for good.  For more background, see:\n# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>\n# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>\nAC_SUBST([mkdir_p], ['$(MKDIR_P)'])\n# We need awk for the \"check\" target (and possibly the TAP driver).  The\n# system \"awk\" is bad on some platforms.\nAC_REQUIRE([AC_PROG_AWK])dnl\nAC_REQUIRE([AC_PROG_MAKE_SET])dnl\nAC_REQUIRE([AM_SET_LEADING_DOT])dnl\n_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],\n\t      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],\n\t\t\t     [_AM_PROG_TAR([v7])])])\n_AM_IF_OPTION([no-dependencies],,\n[AC_PROVIDE_IFELSE([AC_PROG_CC],\n\t\t  [_AM_DEPENDENCIES([CC])],\n\t\t  [m4_define([AC_PROG_CC],\n\t\t\t     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl\nAC_PROVIDE_IFELSE([AC_PROG_CXX],\n\t\t  [_AM_DEPENDENCIES([CXX])],\n\t\t  [m4_define([AC_PROG_CXX],\n\t\t\t     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl\nAC_PROVIDE_IFELSE([AC_PROG_OBJC],\n\t\t  [_AM_DEPENDENCIES([OBJC])],\n\t\t  [m4_define([AC_PROG_OBJC],\n\t\t\t     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl\nAC_PROVIDE_IFELSE([AC_PROG_OBJCXX],\n\t\t  [_AM_DEPENDENCIES([OBJCXX])],\n\t\t  [m4_define([AC_PROG_OBJCXX],\n\t\t\t     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl\n])\nAC_REQUIRE([AM_SILENT_RULES])dnl\ndnl The testsuite driver may need to know about EXEEXT, so add the\ndnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This\ndnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.\nAC_CONFIG_COMMANDS_PRE(dnl\n[m4_provide_if([_AM_COMPILER_EXEEXT],\n  [AM_CONDITIONAL([am__EXEEXT], [test -n \"$EXEEXT\"])])])dnl\n\n# POSIX will say in a future version that running \"rm -f\" with no argument\n# is OK; and we want to be able to make that assumption in our Makefile\n# recipes.  So use an aggressive probe to check that the usage we want is\n# actually supported \"in the wild\" to an acceptable degree.\n# See automake bug#10828.\n# To make any issue more visible, cause the running configure to be aborted\n# by default if the 'rm' program in use doesn't match our expectations; the\n# user can still override this though.\nif rm -f && rm -fr && rm -rf; then : OK; else\n  cat >&2 <<'END'\nOops!\n\nYour 'rm' program seems unable to run without file operands specified\non the command line, even when the '-f' option is present.  This is contrary\nto the behaviour of most rm programs out there, and not conforming with\nthe upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>\n\nPlease tell bug-automake@gnu.org about your system, including the value\nof your $PATH and any error possibly output before this message.  This\ncan help us improve future automake versions.\n\nEND\n  if test x\"$ACCEPT_INFERIOR_RM_PROGRAM\" = x\"yes\"; then\n    echo 'Configuration will proceed anyway, since you have set the' >&2\n    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to \"yes\"' >&2\n    echo >&2\n  else\n    cat >&2 <<'END'\nAborting the configuration process, to ensure you take notice of the issue.\n\nYou can download and install GNU coreutils to get an 'rm' implementation\nthat behaves properly: <https://www.gnu.org/software/coreutils/>.\n\nIf you want to complete the configuration process using your problematic\n'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM\nto \"yes\", and re-run configure.\n\nEND\n    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])\n  fi\nfi\ndnl The trailing newline in this macro's definition is deliberate, for\ndnl backward compatibility and to allow trailing 'dnl'-style comments\ndnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.\n])\n\ndnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not\ndnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further\ndnl mangled by Autoconf and run in a shell conditional statement.\nm4_define([_AC_COMPILER_EXEEXT],\nm4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])\n\n# When config.status generates a header, we must update the stamp-h file.\n# This file resides in the same directory as the config header\n# that is generated.  The stamp files are numbered to have different names.\n\n# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the\n# loop where config.status creates the headers, so we can generate\n# our stamp files there.\nAC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],\n[# Compute $1's index in $config_headers.\n_am_arg=$1\n_am_stamp_count=1\nfor _am_header in $config_headers :; do\n  case $_am_header in\n    $_am_arg | $_am_arg:* )\n      break ;;\n    * )\n      _am_stamp_count=`expr $_am_stamp_count + 1` ;;\n  esac\ndone\necho \"timestamp for $_am_arg\" >`AS_DIRNAME([\"$_am_arg\"])`/stamp-h[]$_am_stamp_count])\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_PROG_INSTALL_SH\n# ------------------\n# Define $install_sh.\nAC_DEFUN([AM_PROG_INSTALL_SH],\n[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl\nif test x\"${install_sh+set}\" != xset; then\n  case $am_aux_dir in\n  *\\ * | *\\\t*)\n    install_sh=\"\\${SHELL} '$am_aux_dir/install-sh'\" ;;\n  *)\n    install_sh=\"\\${SHELL} $am_aux_dir/install-sh\"\n  esac\nfi\nAC_SUBST([install_sh])])\n\n# Copyright (C) 2003-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# Check whether the underlying file-system supports filenames\n# with a leading dot.  For instance MS-DOS doesn't.\nAC_DEFUN([AM_SET_LEADING_DOT],\n[rm -rf .tst 2>/dev/null\nmkdir .tst 2>/dev/null\nif test -d .tst; then\n  am__leading_dot=.\nelse\n  am__leading_dot=_\nfi\nrmdir .tst 2>/dev/null\nAC_SUBST([am__leading_dot])])\n\n# Check to see how 'make' treats includes.\t            -*- Autoconf -*-\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_MAKE_INCLUDE()\n# -----------------\n# Check whether make has an 'include' directive that can support all\n# the idioms we need for our automatic dependency tracking code.\nAC_DEFUN([AM_MAKE_INCLUDE],\n[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive])\ncat > confinc.mk << 'END'\nam__doit:\n\t@echo this is the am__doit target >confinc.out\n.PHONY: am__doit\nEND\nam__include=\"#\"\nam__quote=\n# BSD make does it like this.\necho '.include \"confinc.mk\" # ignored' > confmf.BSD\n# Other make implementations (GNU, Solaris 10, AIX) do it like this.\necho 'include confinc.mk # ignored' > confmf.GNU\n_am_result=no\nfor s in GNU BSD; do\n  AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out])\n  AS_CASE([$?:`cat confinc.out 2>/dev/null`],\n      ['0:this is the am__doit target'],\n      [AS_CASE([$s],\n          [BSD], [am__include='.include' am__quote='\"'],\n          [am__include='include' am__quote=''])])\n  if test \"$am__include\" != \"#\"; then\n    _am_result=\"yes ($s style)\"\n    break\n  fi\ndone\nrm -f confinc.* confmf.*\nAC_MSG_RESULT([${_am_result}])\nAC_SUBST([am__include])])\nAC_SUBST([am__quote])])\n\n# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-\n\n# Copyright (C) 1997-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_MISSING_PROG(NAME, PROGRAM)\n# ------------------------------\nAC_DEFUN([AM_MISSING_PROG],\n[AC_REQUIRE([AM_MISSING_HAS_RUN])\n$1=${$1-\"${am_missing_run}$2\"}\nAC_SUBST($1)])\n\n# AM_MISSING_HAS_RUN\n# ------------------\n# Define MISSING if not defined so far and test if it is modern enough.\n# If it is, set am_missing_run to use it, otherwise, to nothing.\nAC_DEFUN([AM_MISSING_HAS_RUN],\n[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl\nAC_REQUIRE_AUX_FILE([missing])dnl\nif test x\"${MISSING+set}\" != xset; then\n  MISSING=\"\\${SHELL} '$am_aux_dir/missing'\"\nfi\n# Use eval to expand $SHELL\nif eval \"$MISSING --is-lightweight\"; then\n  am_missing_run=\"$MISSING \"\nelse\n  am_missing_run=\n  AC_MSG_WARN(['missing' script is too old or missing])\nfi\n])\n\n# Helper functions for option handling.                     -*- Autoconf -*-\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# _AM_MANGLE_OPTION(NAME)\n# -----------------------\nAC_DEFUN([_AM_MANGLE_OPTION],\n[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])\n\n# _AM_SET_OPTION(NAME)\n# --------------------\n# Set option NAME.  Presently that only means defining a flag for this option.\nAC_DEFUN([_AM_SET_OPTION],\n[m4_define(_AM_MANGLE_OPTION([$1]), [1])])\n\n# _AM_SET_OPTIONS(OPTIONS)\n# ------------------------\n# OPTIONS is a space-separated list of Automake options.\nAC_DEFUN([_AM_SET_OPTIONS],\n[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])\n\n# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])\n# -------------------------------------------\n# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.\nAC_DEFUN([_AM_IF_OPTION],\n[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])\n\n# Copyright (C) 1999-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# _AM_PROG_CC_C_O\n# ---------------\n# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC\n# to automatically call this.\nAC_DEFUN([_AM_PROG_CC_C_O],\n[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl\nAC_REQUIRE_AUX_FILE([compile])dnl\nAC_LANG_PUSH([C])dnl\nAC_CACHE_CHECK(\n  [whether $CC understands -c and -o together],\n  [am_cv_prog_cc_c_o],\n  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])\n  # Make sure it works both with $CC and with simple cc.\n  # Following AC_PROG_CC_C_O, we do the test twice because some\n  # compilers refuse to overwrite an existing .o file with -o,\n  # though they will create one.\n  am_cv_prog_cc_c_o=yes\n  for am_i in 1 2; do\n    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \\\n         && test -f conftest2.$ac_objext; then\n      : OK\n    else\n      am_cv_prog_cc_c_o=no\n      break\n    fi\n  done\n  rm -f core conftest*\n  unset am_i])\nif test \"$am_cv_prog_cc_c_o\" != yes; then\n   # Losing compiler, so override with the script.\n   # FIXME: It is wrong to rewrite CC.\n   # But if we don't then we get into trouble of one sort or another.\n   # A longer-term fix would be to have automake use am__CC in this case,\n   # and then we could set am__CC=\"\\$(top_srcdir)/compile \\$(CC)\"\n   CC=\"$am_aux_dir/compile $CC\"\nfi\nAC_LANG_POP([C])])\n\n# For backward compatibility.\nAC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_RUN_LOG(COMMAND)\n# -------------------\n# Run COMMAND, save the exit status in ac_status, and log it.\n# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)\nAC_DEFUN([AM_RUN_LOG],\n[{ echo \"$as_me:$LINENO: $1\" >&AS_MESSAGE_LOG_FD\n   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD\n   ac_status=$?\n   echo \"$as_me:$LINENO: \\$? = $ac_status\" >&AS_MESSAGE_LOG_FD\n   (exit $ac_status); }])\n\n# Check to make sure that the build environment is sane.    -*- Autoconf -*-\n\n# Copyright (C) 1996-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_SANITY_CHECK\n# ---------------\nAC_DEFUN([AM_SANITY_CHECK],\n[AC_MSG_CHECKING([whether build environment is sane])\n# Reject unsafe characters in $srcdir or the absolute working directory\n# name.  Accept space and tab only in the latter.\nam_lf='\n'\ncase `pwd` in\n  *[[\\\\\\\"\\#\\$\\&\\'\\`$am_lf]]*)\n    AC_MSG_ERROR([unsafe absolute working directory name]);;\nesac\ncase $srcdir in\n  *[[\\\\\\\"\\#\\$\\&\\'\\`$am_lf\\ \\\t]]*)\n    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;\nesac\n\n# Do 'set' in a subshell so we don't clobber the current shell's\n# arguments.  Must try -L first in case configure is actually a\n# symlink; some systems play weird games with the mod time of symlinks\n# (eg FreeBSD returns the mod time of the symlink's containing\n# directory).\nif (\n   am_has_slept=no\n   for am_try in 1 2; do\n     echo \"timestamp, slept: $am_has_slept\" > conftest.file\n     set X `ls -Lt \"$srcdir/configure\" conftest.file 2> /dev/null`\n     if test \"$[*]\" = \"X\"; then\n\t# -L didn't work.\n\tset X `ls -t \"$srcdir/configure\" conftest.file`\n     fi\n     if test \"$[*]\" != \"X $srcdir/configure conftest.file\" \\\n\t&& test \"$[*]\" != \"X conftest.file $srcdir/configure\"; then\n\n\t# If neither matched, then we have a broken ls.  This can happen\n\t# if, for instance, CONFIG_SHELL is bash and it inherits a\n\t# broken ls alias from the environment.  This has actually\n\t# happened.  Such a system could not be considered \"sane\".\n\tAC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken\n  alias in your environment])\n     fi\n     if test \"$[2]\" = conftest.file || test $am_try -eq 2; then\n       break\n     fi\n     # Just in case.\n     sleep 1\n     am_has_slept=yes\n   done\n   test \"$[2]\" = conftest.file\n   )\nthen\n   # Ok.\n   :\nelse\n   AC_MSG_ERROR([newly created file is older than distributed files!\nCheck your system clock])\nfi\nAC_MSG_RESULT([yes])\n# If we didn't sleep, we still need to ensure time stamps of config.status and\n# generated files are strictly newer.\nam_sleep_pid=\nif grep 'slept: no' conftest.file >/dev/null 2>&1; then\n  ( sleep 1 ) &\n  am_sleep_pid=$!\nfi\nAC_CONFIG_COMMANDS_PRE(\n  [AC_MSG_CHECKING([that generated files are newer than configure])\n   if test -n \"$am_sleep_pid\"; then\n     # Hide warnings about reused PIDs.\n     wait $am_sleep_pid 2>/dev/null\n   fi\n   AC_MSG_RESULT([done])])\nrm -f conftest.file\n])\n\n# Copyright (C) 2009-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_SILENT_RULES([DEFAULT])\n# --------------------------\n# Enable less verbose build rules; with the default set to DEFAULT\n# (\"yes\" being less verbose, \"no\" or empty being verbose).\nAC_DEFUN([AM_SILENT_RULES],\n[AC_ARG_ENABLE([silent-rules], [dnl\nAS_HELP_STRING(\n  [--enable-silent-rules],\n  [less verbose build output (undo: \"make V=1\")])\nAS_HELP_STRING(\n  [--disable-silent-rules],\n  [verbose build output (undo: \"make V=0\")])dnl\n])\ncase $enable_silent_rules in @%:@ (((\n  yes) AM_DEFAULT_VERBOSITY=0;;\n   no) AM_DEFAULT_VERBOSITY=1;;\n    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;\nesac\ndnl\ndnl A few 'make' implementations (e.g., NonStop OS and NextStep)\ndnl do not support nested variable expansions.\ndnl See automake bug#9928 and bug#10237.\nam_make=${MAKE-make}\nAC_CACHE_CHECK([whether $am_make supports nested variables],\n   [am_cv_make_support_nested_variables],\n   [if AS_ECHO([['TRUE=$(BAR$(V))\nBAR0=false\nBAR1=true\nV=1\nam__doit:\n\t@$(TRUE)\n.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then\n  am_cv_make_support_nested_variables=yes\nelse\n  am_cv_make_support_nested_variables=no\nfi])\nif test $am_cv_make_support_nested_variables = yes; then\n  dnl Using '$V' instead of '$(V)' breaks IRIX make.\n  AM_V='$(V)'\n  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'\nelse\n  AM_V=$AM_DEFAULT_VERBOSITY\n  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY\nfi\nAC_SUBST([AM_V])dnl\nAM_SUBST_NOTMAKE([AM_V])dnl\nAC_SUBST([AM_DEFAULT_V])dnl\nAM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl\nAC_SUBST([AM_DEFAULT_VERBOSITY])dnl\nAM_BACKSLASH='\\'\nAC_SUBST([AM_BACKSLASH])dnl\n_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl\n])\n\n# Copyright (C) 2001-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# AM_PROG_INSTALL_STRIP\n# ---------------------\n# One issue with vendor 'install' (even GNU) is that you can't\n# specify the program used to strip binaries.  This is especially\n# annoying in cross-compiling environments, where the build's strip\n# is unlikely to handle the host's binaries.\n# Fortunately install-sh will honor a STRIPPROG variable, so we\n# always use install-sh in \"make install-strip\", and initialize\n# STRIPPROG with the value of the STRIP variable (set by the user).\nAC_DEFUN([AM_PROG_INSTALL_STRIP],\n[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl\n# Installed binaries are usually stripped using 'strip' when the user\n# run \"make install-strip\".  However 'strip' might not be the right\n# tool to use in cross-compilation environments, therefore Automake\n# will honor the 'STRIP' environment variable to overrule this program.\ndnl Don't test for $cross_compiling = yes, because it might be 'maybe'.\nif test \"$cross_compiling\" != no; then\n  AC_CHECK_TOOL([STRIP], [strip], :)\nfi\nINSTALL_STRIP_PROGRAM=\"\\$(install_sh) -c -s\"\nAC_SUBST([INSTALL_STRIP_PROGRAM])])\n\n# Copyright (C) 2006-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# _AM_SUBST_NOTMAKE(VARIABLE)\n# ---------------------------\n# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.\n# This macro is traced by Automake.\nAC_DEFUN([_AM_SUBST_NOTMAKE])\n\n# AM_SUBST_NOTMAKE(VARIABLE)\n# --------------------------\n# Public sister of _AM_SUBST_NOTMAKE.\nAC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])\n\n# Check how to create a tarball.                            -*- Autoconf -*-\n\n# Copyright (C) 2004-2020 Free Software Foundation, Inc.\n#\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# _AM_PROG_TAR(FORMAT)\n# --------------------\n# Check how to create a tarball in format FORMAT.\n# FORMAT should be one of 'v7', 'ustar', or 'pax'.\n#\n# Substitute a variable $(am__tar) that is a command\n# writing to stdout a FORMAT-tarball containing the directory\n# $tardir.\n#     tardir=directory && $(am__tar) > result.tar\n#\n# Substitute a variable $(am__untar) that extract such\n# a tarball read from stdin.\n#     $(am__untar) < result.tar\n#\nAC_DEFUN([_AM_PROG_TAR],\n[# Always define AMTAR for backward compatibility.  Yes, it's still used\n# in the wild :-(  We should find a proper way to deprecate it ...\nAC_SUBST([AMTAR], ['$${TAR-tar}'])\n\n# We'll loop over all known methods to create a tar archive until one works.\n_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'\n\nm4_if([$1], [v7],\n  [am__tar='$${TAR-tar} chof - \"$$tardir\"' am__untar='$${TAR-tar} xf -'],\n\n  [m4_case([$1],\n    [ustar],\n     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.\n      # There is notably a 21 bits limit for the UID and the GID.  In fact,\n      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343\n      # and bug#13588).\n      am_max_uid=2097151 # 2^21 - 1\n      am_max_gid=$am_max_uid\n      # The $UID and $GID variables are not portable, so we need to resort\n      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls\n      # below are definitely unexpected, so allow the users to see them\n      # (that is, avoid stderr redirection).\n      am_uid=`id -u || echo unknown`\n      am_gid=`id -g || echo unknown`\n      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])\n      if test $am_uid -le $am_max_uid; then\n         AC_MSG_RESULT([yes])\n      else\n         AC_MSG_RESULT([no])\n         _am_tools=none\n      fi\n      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])\n      if test $am_gid -le $am_max_gid; then\n         AC_MSG_RESULT([yes])\n      else\n        AC_MSG_RESULT([no])\n        _am_tools=none\n      fi],\n\n  [pax],\n    [],\n\n  [m4_fatal([Unknown tar format])])\n\n  AC_MSG_CHECKING([how to create a $1 tar archive])\n\n  # Go ahead even if we have the value already cached.  We do so because we\n  # need to set the values for the 'am__tar' and 'am__untar' variables.\n  _am_tools=${am_cv_prog_tar_$1-$_am_tools}\n\n  for _am_tool in $_am_tools; do\n    case $_am_tool in\n    gnutar)\n      for _am_tar in tar gnutar gtar; do\n        AM_RUN_LOG([$_am_tar --version]) && break\n      done\n      am__tar=\"$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - \"'\"$$tardir\"'\n      am__tar_=\"$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - \"'\"$tardir\"'\n      am__untar=\"$_am_tar -xf -\"\n      ;;\n    plaintar)\n      # Must skip GNU tar: if it does not support --format= it doesn't create\n      # ustar tarball either.\n      (tar --version) >/dev/null 2>&1 && continue\n      am__tar='tar chf - \"$$tardir\"'\n      am__tar_='tar chf - \"$tardir\"'\n      am__untar='tar xf -'\n      ;;\n    pax)\n      am__tar='pax -L -x $1 -w \"$$tardir\"'\n      am__tar_='pax -L -x $1 -w \"$tardir\"'\n      am__untar='pax -r'\n      ;;\n    cpio)\n      am__tar='find \"$$tardir\" -print | cpio -o -H $1 -L'\n      am__tar_='find \"$tardir\" -print | cpio -o -H $1 -L'\n      am__untar='cpio -i -H $1 -d'\n      ;;\n    none)\n      am__tar=false\n      am__tar_=false\n      am__untar=false\n      ;;\n    esac\n\n    # If the value was cached, stop now.  We just wanted to have am__tar\n    # and am__untar set.\n    test -n \"${am_cv_prog_tar_$1}\" && break\n\n    # tar/untar a dummy directory, and stop if the command works.\n    rm -rf conftest.dir\n    mkdir conftest.dir\n    echo GrepMe > conftest.dir/file\n    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])\n    rm -rf conftest.dir\n    if test -s conftest.tar; then\n      AM_RUN_LOG([$am__untar <conftest.tar])\n      AM_RUN_LOG([cat conftest.dir/file])\n      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break\n    fi\n  done\n  rm -rf conftest.dir\n\n  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])\n  AC_MSG_RESULT([$am_cv_prog_tar_$1])])\n\nAC_SUBST([am__tar])\nAC_SUBST([am__untar])\n]) # _AM_PROG_TAR\n\nm4_include([glm4/00gnulib.m4])\nm4_include([glm4/__inline.m4])\nm4_include([glm4/absolute-header.m4])\nm4_include([glm4/errno_h.m4])\nm4_include([glm4/execinfo.m4])\nm4_include([glm4/extensions.m4])\nm4_include([glm4/extern-inline.m4])\nm4_include([glm4/getdelim.m4])\nm4_include([glm4/gethostname.m4])\nm4_include([glm4/getline.m4])\nm4_include([glm4/gettimeofday.m4])\nm4_include([glm4/gnulib-common.m4])\nm4_include([glm4/include_next.m4])\nm4_include([glm4/limits-h.m4])\nm4_include([glm4/msvc-inval.m4])\nm4_include([glm4/msvc-nothrow.m4])\nm4_include([glm4/multiarch.m4])\nm4_include([glm4/off_t.m4])\nm4_include([glm4/random.m4])\nm4_include([glm4/random_r.m4])\nm4_include([glm4/socketlib.m4])\nm4_include([glm4/sockets.m4])\nm4_include([glm4/socklen.m4])\nm4_include([glm4/ssize_t.m4])\nm4_include([glm4/stdalign.m4])\nm4_include([glm4/stddef_h.m4])\nm4_include([glm4/stdint.m4])\nm4_include([glm4/stdio_h.m4])\nm4_include([glm4/stdlib_h.m4])\nm4_include([glm4/sys_resource_h.m4])\nm4_include([glm4/sys_socket_h.m4])\nm4_include([glm4/sys_stat_h.m4])\nm4_include([glm4/sys_time_h.m4])\nm4_include([glm4/sys_types_h.m4])\nm4_include([glm4/sys_uio_h.m4])\nm4_include([glm4/sys_utsname_h.m4])\nm4_include([glm4/time_h.m4])\nm4_include([glm4/time_r.m4])\nm4_include([glm4/uname.m4])\nm4_include([glm4/unistd_h.m4])\nm4_include([glm4/warn-on-use.m4])\nm4_include([glm4/wchar_t.m4])\nm4_include([glm4/wint_t.m4])\nm4_include([glm4/zzgnulib.m4])\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/compile",
    "content": "#! /bin/sh\n# Wrapper for compilers which do not understand '-c -o'.\n\nscriptversion=2018-03-07.03; # UTC\n\n# Copyright (C) 1999-2020 Free Software Foundation, Inc.\n# Written by Tom Tromey <tromey@cygnus.com>.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2, or (at your option)\n# any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that program.\n\n# This file is maintained in Automake, please report\n# bugs to <bug-automake@gnu.org> or send patches to\n# <automake-patches@gnu.org>.\n\nnl='\n'\n\n# We need space, tab and new line, in precisely that order.  Quoting is\n# there to prevent tools from complaining about whitespace usage.\nIFS=\" \"\"\t$nl\"\n\nfile_conv=\n\n# func_file_conv build_file lazy\n# Convert a $build file to $host form and store it in $file\n# Currently only supports Windows hosts. If the determined conversion\n# type is listed in (the comma separated) LAZY, no conversion will\n# take place.\nfunc_file_conv ()\n{\n  file=$1\n  case $file in\n    / | /[!/]*) # absolute file, and not a UNC file\n      if test -z \"$file_conv\"; then\n\t# lazily determine how to convert abs files\n\tcase `uname -s` in\n\t  MINGW*)\n\t    file_conv=mingw\n\t    ;;\n\t  CYGWIN* | MSYS*)\n\t    file_conv=cygwin\n\t    ;;\n\t  *)\n\t    file_conv=wine\n\t    ;;\n\tesac\n      fi\n      case $file_conv/,$2, in\n\t*,$file_conv,*)\n\t  ;;\n\tmingw/*)\n\t  file=`cmd //C echo \"$file \" | sed -e 's/\"\\(.*\\) \" *$/\\1/'`\n\t  ;;\n\tcygwin/* | msys/*)\n\t  file=`cygpath -m \"$file\" || echo \"$file\"`\n\t  ;;\n\twine/*)\n\t  file=`winepath -w \"$file\" || echo \"$file\"`\n\t  ;;\n      esac\n      ;;\n  esac\n}\n\n# func_cl_dashL linkdir\n# Make cl look for libraries in LINKDIR\nfunc_cl_dashL ()\n{\n  func_file_conv \"$1\"\n  if test -z \"$lib_path\"; then\n    lib_path=$file\n  else\n    lib_path=\"$lib_path;$file\"\n  fi\n  linker_opts=\"$linker_opts -LIBPATH:$file\"\n}\n\n# func_cl_dashl library\n# Do a library search-path lookup for cl\nfunc_cl_dashl ()\n{\n  lib=$1\n  found=no\n  save_IFS=$IFS\n  IFS=';'\n  for dir in $lib_path $LIB\n  do\n    IFS=$save_IFS\n    if $shared && test -f \"$dir/$lib.dll.lib\"; then\n      found=yes\n      lib=$dir/$lib.dll.lib\n      break\n    fi\n    if test -f \"$dir/$lib.lib\"; then\n      found=yes\n      lib=$dir/$lib.lib\n      break\n    fi\n    if test -f \"$dir/lib$lib.a\"; then\n      found=yes\n      lib=$dir/lib$lib.a\n      break\n    fi\n  done\n  IFS=$save_IFS\n\n  if test \"$found\" != yes; then\n    lib=$lib.lib\n  fi\n}\n\n# func_cl_wrapper cl arg...\n# Adjust compile command to suit cl\nfunc_cl_wrapper ()\n{\n  # Assume a capable shell\n  lib_path=\n  shared=:\n  linker_opts=\n  for arg\n  do\n    if test -n \"$eat\"; then\n      eat=\n    else\n      case $1 in\n\t-o)\n\t  # configure might choose to run compile as 'compile cc -o foo foo.c'.\n\t  eat=1\n\t  case $2 in\n\t    *.o | *.[oO][bB][jJ])\n\t      func_file_conv \"$2\"\n\t      set x \"$@\" -Fo\"$file\"\n\t      shift\n\t      ;;\n\t    *)\n\t      func_file_conv \"$2\"\n\t      set x \"$@\" -Fe\"$file\"\n\t      shift\n\t      ;;\n\t  esac\n\t  ;;\n\t-I)\n\t  eat=1\n\t  func_file_conv \"$2\" mingw\n\t  set x \"$@\" -I\"$file\"\n\t  shift\n\t  ;;\n\t-I*)\n\t  func_file_conv \"${1#-I}\" mingw\n\t  set x \"$@\" -I\"$file\"\n\t  shift\n\t  ;;\n\t-l)\n\t  eat=1\n\t  func_cl_dashl \"$2\"\n\t  set x \"$@\" \"$lib\"\n\t  shift\n\t  ;;\n\t-l*)\n\t  func_cl_dashl \"${1#-l}\"\n\t  set x \"$@\" \"$lib\"\n\t  shift\n\t  ;;\n\t-L)\n\t  eat=1\n\t  func_cl_dashL \"$2\"\n\t  ;;\n\t-L*)\n\t  func_cl_dashL \"${1#-L}\"\n\t  ;;\n\t-static)\n\t  shared=false\n\t  ;;\n\t-Wl,*)\n\t  arg=${1#-Wl,}\n\t  save_ifs=\"$IFS\"; IFS=','\n\t  for flag in $arg; do\n\t    IFS=\"$save_ifs\"\n\t    linker_opts=\"$linker_opts $flag\"\n\t  done\n\t  IFS=\"$save_ifs\"\n\t  ;;\n\t-Xlinker)\n\t  eat=1\n\t  linker_opts=\"$linker_opts $2\"\n\t  ;;\n\t-*)\n\t  set x \"$@\" \"$1\"\n\t  shift\n\t  ;;\n\t*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)\n\t  func_file_conv \"$1\"\n\t  set x \"$@\" -Tp\"$file\"\n\t  shift\n\t  ;;\n\t*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])\n\t  func_file_conv \"$1\" mingw\n\t  set x \"$@\" \"$file\"\n\t  shift\n\t  ;;\n\t*)\n\t  set x \"$@\" \"$1\"\n\t  shift\n\t  ;;\n      esac\n    fi\n    shift\n  done\n  if test -n \"$linker_opts\"; then\n    linker_opts=\"-link$linker_opts\"\n  fi\n  exec \"$@\" $linker_opts\n  exit 1\n}\n\neat=\n\ncase $1 in\n  '')\n     echo \"$0: No command.  Try '$0 --help' for more information.\" 1>&2\n     exit 1;\n     ;;\n  -h | --h*)\n    cat <<\\EOF\nUsage: compile [--help] [--version] PROGRAM [ARGS]\n\nWrapper for compilers which do not understand '-c -o'.\nRemove '-o dest.o' from ARGS, run PROGRAM with the remaining\narguments, and rename the output as expected.\n\nIf you are trying to build a whole package this is not the\nright script to run: please start by reading the file 'INSTALL'.\n\nReport bugs to <bug-automake@gnu.org>.\nEOF\n    exit $?\n    ;;\n  -v | --v*)\n    echo \"compile $scriptversion\"\n    exit $?\n    ;;\n  cl | *[/\\\\]cl | cl.exe | *[/\\\\]cl.exe | \\\n  icl | *[/\\\\]icl | icl.exe | *[/\\\\]icl.exe )\n    func_cl_wrapper \"$@\"      # Doesn't return...\n    ;;\nesac\n\nofile=\ncfile=\n\nfor arg\ndo\n  if test -n \"$eat\"; then\n    eat=\n  else\n    case $1 in\n      -o)\n\t# configure might choose to run compile as 'compile cc -o foo foo.c'.\n\t# So we strip '-o arg' only if arg is an object.\n\teat=1\n\tcase $2 in\n\t  *.o | *.obj)\n\t    ofile=$2\n\t    ;;\n\t  *)\n\t    set x \"$@\" -o \"$2\"\n\t    shift\n\t    ;;\n\tesac\n\t;;\n      *.c)\n\tcfile=$1\n\tset x \"$@\" \"$1\"\n\tshift\n\t;;\n      *)\n\tset x \"$@\" \"$1\"\n\tshift\n\t;;\n    esac\n  fi\n  shift\ndone\n\nif test -z \"$ofile\" || test -z \"$cfile\"; then\n  # If no '-o' option was seen then we might have been invoked from a\n  # pattern rule where we don't need one.  That is ok -- this is a\n  # normal compilation that the losing compiler can handle.  If no\n  # '.c' file was seen then we are probably linking.  That is also\n  # ok.\n  exec \"$@\"\nfi\n\n# Name of file we expect compiler to create.\ncofile=`echo \"$cfile\" | sed 's|^.*[\\\\/]||; s|^[a-zA-Z]:||; s/\\.c$/.o/'`\n\n# Create the lock directory.\n# Note: use '[/\\\\:.-]' here to ensure that we don't use the same name\n# that we are using for the .o file.  Also, base the name on the expected\n# object file name, since that is what matters with a parallel build.\nlockdir=`echo \"$cofile\" | sed -e 's|[/\\\\:.-]|_|g'`.d\nwhile true; do\n  if mkdir \"$lockdir\" >/dev/null 2>&1; then\n    break\n  fi\n  sleep 1\ndone\n# FIXME: race condition here if user kills between mkdir and trap.\ntrap \"rmdir '$lockdir'; exit 1\" 1 2 15\n\n# Run the compile.\n\"$@\"\nret=$?\n\nif test -f \"$cofile\"; then\n  test \"$cofile\" = \"$ofile\" || mv \"$cofile\" \"$ofile\"\nelif test -f \"${cofile}bj\"; then\n  test \"${cofile}bj\" = \"$ofile\" || mv \"${cofile}bj\" \"$ofile\"\nfi\n\nrmdir \"$lockdir\"\nexit $ret\n\n# Local Variables:\n# mode: shell-script\n# sh-indentation: 2\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"scriptversion=\"\n# time-stamp-format: \"%:y-%02m-%02d.%02H\"\n# time-stamp-time-zone: \"UTC0\"\n# time-stamp-end: \"; # UTC\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/config.guess",
    "content": "#! /bin/sh\n# Attempt to guess a canonical system name.\n#   Copyright 1992-2021 Free Software Foundation, Inc.\n\n# shellcheck disable=SC2006,SC2268 # see below for rationale\n\ntimestamp='2021-06-03'\n\n# This file is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that\n# program.  This Exception is an additional permission under section 7\n# of the GNU General Public License, version 3 (\"GPLv3\").\n#\n# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.\n#\n# You can get the latest version of this script from:\n# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess\n#\n# Please send patches to <config-patches@gnu.org>.\n\n\n# The \"shellcheck disable\" line above the timestamp inhibits complaints\n# about features and limitations of the classic Bourne shell that were\n# superseded or lifted in POSIX.  However, this script identifies a wide\n# variety of pre-POSIX systems that do not have POSIX shells at all, and\n# even some reasonably current systems (Solaris 10 as case-in-point) still\n# have a pre-POSIX /bin/sh.\n\n\nme=`echo \"$0\" | sed -e 's,.*/,,'`\n\nusage=\"\\\nUsage: $0 [OPTION]\n\nOutput the configuration name of the system \\`$me' is run on.\n\nOptions:\n  -h, --help         print this help, then exit\n  -t, --time-stamp   print date of last modification, then exit\n  -v, --version      print version number, then exit\n\nReport bugs and patches to <config-patches@gnu.org>.\"\n\nversion=\"\\\nGNU config.guess ($timestamp)\n\nOriginally written by Per Bothner.\nCopyright 1992-2021 Free Software Foundation, Inc.\n\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\"\n\nhelp=\"\nTry \\`$me --help' for more information.\"\n\n# Parse command line\nwhile test $# -gt 0 ; do\n  case $1 in\n    --time-stamp | --time* | -t )\n       echo \"$timestamp\" ; exit ;;\n    --version | -v )\n       echo \"$version\" ; exit ;;\n    --help | --h* | -h )\n       echo \"$usage\"; exit ;;\n    -- )     # Stop option processing\n       shift; break ;;\n    - )\t# Use stdin as input.\n       break ;;\n    -* )\n       echo \"$me: invalid option $1$help\" >&2\n       exit 1 ;;\n    * )\n       break ;;\n  esac\ndone\n\nif test $# != 0; then\n  echo \"$me: too many arguments$help\" >&2\n  exit 1\nfi\n\n# Just in case it came from the environment.\nGUESS=\n\n# CC_FOR_BUILD -- compiler used by this script. Note that the use of a\n# compiler to aid in system detection is discouraged as it requires\n# temporary files to be created and, as you can see below, it is a\n# headache to deal with in a portable fashion.\n\n# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still\n# use `HOST_CC' if defined, but it is deprecated.\n\n# Portable tmp directory creation inspired by the Autoconf team.\n\ntmp=\n# shellcheck disable=SC2172\ntrap 'test -z \"$tmp\" || rm -fr \"$tmp\"' 0 1 2 13 15\n\nset_cc_for_build() {\n    # prevent multiple calls if $tmp is already set\n    test \"$tmp\" && return 0\n    : \"${TMPDIR=/tmp}\"\n    # shellcheck disable=SC2039,SC3028\n    { tmp=`(umask 077 && mktemp -d \"$TMPDIR/cgXXXXXX\") 2>/dev/null` && test -n \"$tmp\" && test -d \"$tmp\" ; } ||\n\t{ test -n \"$RANDOM\" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir \"$tmp\" 2>/dev/null) ; } ||\n\t{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir \"$tmp\" 2>/dev/null) && echo \"Warning: creating insecure temp directory\" >&2 ; } ||\n\t{ echo \"$me: cannot create a temporary directory in $TMPDIR\" >&2 ; exit 1 ; }\n    dummy=$tmp/dummy\n    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in\n\t,,)    echo \"int x;\" > \"$dummy.c\"\n\t       for driver in cc gcc c89 c99 ; do\n\t\t   if ($driver -c -o \"$dummy.o\" \"$dummy.c\") >/dev/null 2>&1 ; then\n\t\t       CC_FOR_BUILD=$driver\n\t\t       break\n\t\t   fi\n\t       done\n\t       if test x\"$CC_FOR_BUILD\" = x ; then\n\t\t   CC_FOR_BUILD=no_compiler_found\n\t       fi\n\t       ;;\n\t,,*)   CC_FOR_BUILD=$CC ;;\n\t,*,*)  CC_FOR_BUILD=$HOST_CC ;;\n    esac\n}\n\n# This is needed to find uname on a Pyramid OSx when run in the BSD universe.\n# (ghazi@noc.rutgers.edu 1994-08-24)\nif test -f /.attbin/uname ; then\n\tPATH=$PATH:/.attbin ; export PATH\nfi\n\nUNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown\nUNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown\nUNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown\nUNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown\n\ncase $UNAME_SYSTEM in\nLinux|GNU|GNU/*)\n\tLIBC=unknown\n\n\tset_cc_for_build\n\tcat <<-EOF > \"$dummy.c\"\n\t#include <features.h>\n\t#if defined(__UCLIBC__)\n\tLIBC=uclibc\n\t#elif defined(__dietlibc__)\n\tLIBC=dietlibc\n\t#elif defined(__GLIBC__)\n\tLIBC=gnu\n\t#else\n\t#include <stdarg.h>\n\t/* First heuristic to detect musl libc.  */\n\t#ifdef __DEFINED_va_list\n\tLIBC=musl\n\t#endif\n\t#endif\n\tEOF\n\tcc_set_libc=`$CC_FOR_BUILD -E \"$dummy.c\" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`\n\teval \"$cc_set_libc\"\n\n\t# Second heuristic to detect musl libc.\n\tif [ \"$LIBC\" = unknown ] &&\n\t   command -v ldd >/dev/null &&\n\t   ldd --version 2>&1 | grep -q ^musl; then\n\t\tLIBC=musl\n\tfi\n\n\t# If the system lacks a compiler, then just pick glibc.\n\t# We could probably try harder.\n\tif [ \"$LIBC\" = unknown ]; then\n\t\tLIBC=gnu\n\tfi\n\t;;\nesac\n\n# Note: order is significant - the case branches are not exclusive.\n\ncase $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in\n    *:NetBSD:*:*)\n\t# NetBSD (nbsd) targets should (where applicable) match one or\n\t# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,\n\t# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently\n\t# switched to ELF, *-*-netbsd* would select the old\n\t# object file format.  This provides both forward\n\t# compatibility and a consistent mechanism for selecting the\n\t# object file format.\n\t#\n\t# Note: NetBSD doesn't particularly care about the vendor\n\t# portion of the name.  We always set it to \"unknown\".\n\tUNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \\\n\t    /sbin/sysctl -n hw.machine_arch 2>/dev/null || \\\n\t    /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \\\n\t    echo unknown)`\n\tcase $UNAME_MACHINE_ARCH in\n\t    aarch64eb) machine=aarch64_be-unknown ;;\n\t    armeb) machine=armeb-unknown ;;\n\t    arm*) machine=arm-unknown ;;\n\t    sh3el) machine=shl-unknown ;;\n\t    sh3eb) machine=sh-unknown ;;\n\t    sh5el) machine=sh5le-unknown ;;\n\t    earmv*)\n\t\tarch=`echo \"$UNAME_MACHINE_ARCH\" | sed -e 's,^e\\(armv[0-9]\\).*$,\\1,'`\n\t\tendian=`echo \"$UNAME_MACHINE_ARCH\" | sed -ne 's,^.*\\(eb\\)$,\\1,p'`\n\t\tmachine=${arch}${endian}-unknown\n\t\t;;\n\t    *) machine=$UNAME_MACHINE_ARCH-unknown ;;\n\tesac\n\t# The Operating System including object format, if it has switched\n\t# to ELF recently (or will in the future) and ABI.\n\tcase $UNAME_MACHINE_ARCH in\n\t    earm*)\n\t\tos=netbsdelf\n\t\t;;\n\t    arm*|i386|m68k|ns32k|sh3*|sparc|vax)\n\t\tset_cc_for_build\n\t\tif echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t\t\t| grep -q __ELF__\n\t\tthen\n\t\t    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).\n\t\t    # Return netbsd for either.  FIX?\n\t\t    os=netbsd\n\t\telse\n\t\t    os=netbsdelf\n\t\tfi\n\t\t;;\n\t    *)\n\t\tos=netbsd\n\t\t;;\n\tesac\n\t# Determine ABI tags.\n\tcase $UNAME_MACHINE_ARCH in\n\t    earm*)\n\t\texpr='s/^earmv[0-9]/-eabi/;s/eb$//'\n\t\tabi=`echo \"$UNAME_MACHINE_ARCH\" | sed -e \"$expr\"`\n\t\t;;\n\tesac\n\t# The OS release\n\t# Debian GNU/NetBSD machines have a different userland, and\n\t# thus, need a distinct triplet. However, they do not need\n\t# kernel version information, so it can be replaced with a\n\t# suitable tag, in the style of linux-gnu.\n\tcase $UNAME_VERSION in\n\t    Debian*)\n\t\trelease='-gnu'\n\t\t;;\n\t    *)\n\t\trelease=`echo \"$UNAME_RELEASE\" | sed -e 's/[-_].*//' | cut -d. -f1,2`\n\t\t;;\n\tesac\n\t# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:\n\t# contains redundant information, the shorter form:\n\t# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.\n\tGUESS=$machine-${os}${release}${abi-}\n\t;;\n    *:Bitrig:*:*)\n\tUNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`\n\tGUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE\n\t;;\n    *:OpenBSD:*:*)\n\tUNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`\n\tGUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE\n\t;;\n    *:SecBSD:*:*)\n\tUNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`\n\tGUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE\n\t;;\n    *:LibertyBSD:*:*)\n\tUNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\\.//'`\n\tGUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE\n\t;;\n    *:MidnightBSD:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE\n\t;;\n    *:ekkoBSD:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE\n\t;;\n    *:SolidBSD:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE\n\t;;\n    *:OS108:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE\n\t;;\n    macppc:MirBSD:*:*)\n\tGUESS=powerpc-unknown-mirbsd$UNAME_RELEASE\n\t;;\n    *:MirBSD:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE\n\t;;\n    *:Sortix:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-sortix\n\t;;\n    *:Twizzler:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-twizzler\n\t;;\n    *:Redox:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-redox\n\t;;\n    mips:OSF1:*.*)\n\tGUESS=mips-dec-osf1\n\t;;\n    alpha:OSF1:*:*)\n\t# Reset EXIT trap before exiting to avoid spurious non-zero exit code.\n\ttrap '' 0\n\tcase $UNAME_RELEASE in\n\t*4.0)\n\t\tUNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`\n\t\t;;\n\t*5.*)\n\t\tUNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`\n\t\t;;\n\tesac\n\t# According to Compaq, /usr/sbin/psrinfo has been available on\n\t# OSF/1 and Tru64 systems produced since 1995.  I hope that\n\t# covers most systems running today.  This code pipes the CPU\n\t# types through head -n 1, so we only detect the type of CPU 0.\n\tALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \\(.*\\) processor.*$/\\1/p' | head -n 1`\n\tcase $ALPHA_CPU_TYPE in\n\t    \"EV4 (21064)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"EV4.5 (21064)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"LCA4 (21066/21068)\")\n\t\tUNAME_MACHINE=alpha ;;\n\t    \"EV5 (21164)\")\n\t\tUNAME_MACHINE=alphaev5 ;;\n\t    \"EV5.6 (21164A)\")\n\t\tUNAME_MACHINE=alphaev56 ;;\n\t    \"EV5.6 (21164PC)\")\n\t\tUNAME_MACHINE=alphapca56 ;;\n\t    \"EV5.7 (21164PC)\")\n\t\tUNAME_MACHINE=alphapca57 ;;\n\t    \"EV6 (21264)\")\n\t\tUNAME_MACHINE=alphaev6 ;;\n\t    \"EV6.7 (21264A)\")\n\t\tUNAME_MACHINE=alphaev67 ;;\n\t    \"EV6.8CB (21264C)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.8AL (21264B)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.8CX (21264D)\")\n\t\tUNAME_MACHINE=alphaev68 ;;\n\t    \"EV6.9A (21264/EV69A)\")\n\t\tUNAME_MACHINE=alphaev69 ;;\n\t    \"EV7 (21364)\")\n\t\tUNAME_MACHINE=alphaev7 ;;\n\t    \"EV7.9 (21364A)\")\n\t\tUNAME_MACHINE=alphaev79 ;;\n\tesac\n\t# A Pn.n version is a patched version.\n\t# A Vn.n version is a released version.\n\t# A Tn.n version is a released field test version.\n\t# A Xn.n version is an unreleased experimental baselevel.\n\t# 1.2 uses \"1.2\" for uname -r.\n\tOSF_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`\n\tGUESS=$UNAME_MACHINE-dec-osf$OSF_REL\n\t;;\n    Amiga*:UNIX_System_V:4.0:*)\n\tGUESS=m68k-unknown-sysv4\n\t;;\n    *:[Aa]miga[Oo][Ss]:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-amigaos\n\t;;\n    *:[Mm]orph[Oo][Ss]:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-morphos\n\t;;\n    *:OS/390:*:*)\n\tGUESS=i370-ibm-openedition\n\t;;\n    *:z/VM:*:*)\n\tGUESS=s390-ibm-zvmoe\n\t;;\n    *:OS400:*:*)\n\tGUESS=powerpc-ibm-os400\n\t;;\n    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)\n\tGUESS=arm-acorn-riscix$UNAME_RELEASE\n\t;;\n    arm*:riscos:*:*|arm*:RISCOS:*:*)\n\tGUESS=arm-unknown-riscos\n\t;;\n    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)\n\tGUESS=hppa1.1-hitachi-hiuxmpp\n\t;;\n    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)\n\t# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.\n\tcase `(/bin/universe) 2>/dev/null` in\n\t    att) GUESS=pyramid-pyramid-sysv3 ;;\n\t    *)   GUESS=pyramid-pyramid-bsd   ;;\n\tesac\n\t;;\n    NILE*:*:*:dcosx)\n\tGUESS=pyramid-pyramid-svr4\n\t;;\n    DRS?6000:unix:4.0:6*)\n\tGUESS=sparc-icl-nx6\n\t;;\n    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)\n\tcase `/usr/bin/uname -p` in\n\t    sparc) GUESS=sparc-icl-nx7 ;;\n\tesac\n\t;;\n    s390x:SunOS:*:*)\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL\n\t;;\n    sun4H:SunOS:5.*:*)\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=sparc-hal-solaris2$SUN_REL\n\t;;\n    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=sparc-sun-solaris2$SUN_REL\n\t;;\n    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)\n\tGUESS=i386-pc-auroraux$UNAME_RELEASE\n\t;;\n    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)\n\tset_cc_for_build\n\tSUN_ARCH=i386\n\t# If there is a compiler, see if it is configured for 64-bit objects.\n\t# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.\n\t# This test works for both compilers.\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \\\n\t\t(CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\tgrep IS_64BIT_ARCH >/dev/null\n\t    then\n\t\tSUN_ARCH=x86_64\n\t    fi\n\tfi\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=$SUN_ARCH-pc-solaris2$SUN_REL\n\t;;\n    sun4*:SunOS:6*:*)\n\t# According to config.sub, this is the proper way to canonicalize\n\t# SunOS6.  Hard to guess exactly what SunOS6 will be like, but\n\t# it's likely to be more like Solaris than SunOS4.\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=sparc-sun-solaris3$SUN_REL\n\t;;\n    sun4*:SunOS:*:*)\n\tcase `/usr/bin/arch -k` in\n\t    Series*|S4*)\n\t\tUNAME_RELEASE=`uname -v`\n\t\t;;\n\tesac\n\t# Japanese Language versions have a version number like `4.1.3-JL'.\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/-/_/'`\n\tGUESS=sparc-sun-sunos$SUN_REL\n\t;;\n    sun3*:SunOS:*:*)\n\tGUESS=m68k-sun-sunos$UNAME_RELEASE\n\t;;\n    sun*:*:4.2BSD:*)\n\tUNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`\n\ttest \"x$UNAME_RELEASE\" = x && UNAME_RELEASE=3\n\tcase `/bin/arch` in\n\t    sun3)\n\t\tGUESS=m68k-sun-sunos$UNAME_RELEASE\n\t\t;;\n\t    sun4)\n\t\tGUESS=sparc-sun-sunos$UNAME_RELEASE\n\t\t;;\n\tesac\n\t;;\n    aushp:SunOS:*:*)\n\tGUESS=sparc-auspex-sunos$UNAME_RELEASE\n\t;;\n    # The situation for MiNT is a little confusing.  The machine name\n    # can be virtually everything (everything which is not\n    # \"atarist\" or \"atariste\" at least should have a processor\n    # > m68000).  The system name ranges from \"MiNT\" over \"FreeMiNT\"\n    # to the lowercase version \"mint\" (or \"freemint\").  Finally\n    # the system name \"TOS\" denotes a system which is actually not\n    # MiNT.  But MiNT is downward compatible to TOS, so this should\n    # be no problem.\n    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)\n\tGUESS=m68k-atari-mint$UNAME_RELEASE\n\t;;\n    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)\n\tGUESS=m68k-atari-mint$UNAME_RELEASE\n\t;;\n    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)\n\tGUESS=m68k-atari-mint$UNAME_RELEASE\n\t;;\n    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)\n\tGUESS=m68k-milan-mint$UNAME_RELEASE\n\t;;\n    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)\n\tGUESS=m68k-hades-mint$UNAME_RELEASE\n\t;;\n    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)\n\tGUESS=m68k-unknown-mint$UNAME_RELEASE\n\t;;\n    m68k:machten:*:*)\n\tGUESS=m68k-apple-machten$UNAME_RELEASE\n\t;;\n    powerpc:machten:*:*)\n\tGUESS=powerpc-apple-machten$UNAME_RELEASE\n\t;;\n    RISC*:Mach:*:*)\n\tGUESS=mips-dec-mach_bsd4.3\n\t;;\n    RISC*:ULTRIX:*:*)\n\tGUESS=mips-dec-ultrix$UNAME_RELEASE\n\t;;\n    VAX*:ULTRIX*:*:*)\n\tGUESS=vax-dec-ultrix$UNAME_RELEASE\n\t;;\n    2020:CLIX:*:* | 2430:CLIX:*:*)\n\tGUESS=clipper-intergraph-clix$UNAME_RELEASE\n\t;;\n    mips:*:*:UMIPS | mips:*:*:RISCos)\n\tset_cc_for_build\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n#ifdef __cplusplus\n#include <stdio.h>  /* for printf() prototype */\n\tint main (int argc, char *argv[]) {\n#else\n\tint main (argc, argv) int argc; char *argv[]; {\n#endif\n\t#if defined (host_mips) && defined (MIPSEB)\n\t#if defined (SYSTYPE_SYSV)\n\t  printf (\"mips-mips-riscos%ssysv\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#if defined (SYSTYPE_SVR4)\n\t  printf (\"mips-mips-riscos%ssvr4\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)\n\t  printf (\"mips-mips-riscos%sbsd\\\\n\", argv[1]); exit (0);\n\t#endif\n\t#endif\n\t  exit (-1);\n\t}\nEOF\n\t$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" &&\n\t  dummyarg=`echo \"$UNAME_RELEASE\" | sed -n 's/\\([0-9]*\\).*/\\1/p'` &&\n\t  SYSTEM_NAME=`\"$dummy\" \"$dummyarg\"` &&\n\t    { echo \"$SYSTEM_NAME\"; exit; }\n\tGUESS=mips-mips-riscos$UNAME_RELEASE\n\t;;\n    Motorola:PowerMAX_OS:*:*)\n\tGUESS=powerpc-motorola-powermax\n\t;;\n    Motorola:*:4.3:PL8-*)\n\tGUESS=powerpc-harris-powermax\n\t;;\n    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)\n\tGUESS=powerpc-harris-powermax\n\t;;\n    Night_Hawk:Power_UNIX:*:*)\n\tGUESS=powerpc-harris-powerunix\n\t;;\n    m88k:CX/UX:7*:*)\n\tGUESS=m88k-harris-cxux7\n\t;;\n    m88k:*:4*:R4*)\n\tGUESS=m88k-motorola-sysv4\n\t;;\n    m88k:*:3*:R3*)\n\tGUESS=m88k-motorola-sysv3\n\t;;\n    AViiON:dgux:*:*)\n\t# DG/UX returns AViiON for all architectures\n\tUNAME_PROCESSOR=`/usr/bin/uname -p`\n\tif test \"$UNAME_PROCESSOR\" = mc88100 || test \"$UNAME_PROCESSOR\" = mc88110\n\tthen\n\t    if test \"$TARGET_BINARY_INTERFACE\"x = m88kdguxelfx || \\\n\t       test \"$TARGET_BINARY_INTERFACE\"x = x\n\t    then\n\t\tGUESS=m88k-dg-dgux$UNAME_RELEASE\n\t    else\n\t\tGUESS=m88k-dg-dguxbcs$UNAME_RELEASE\n\t    fi\n\telse\n\t    GUESS=i586-dg-dgux$UNAME_RELEASE\n\tfi\n\t;;\n    M88*:DolphinOS:*:*)\t# DolphinOS (SVR3)\n\tGUESS=m88k-dolphin-sysv3\n\t;;\n    M88*:*:R3*:*)\n\t# Delta 88k system running SVR3\n\tGUESS=m88k-motorola-sysv3\n\t;;\n    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)\n\tGUESS=m88k-tektronix-sysv3\n\t;;\n    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)\n\tGUESS=m68k-tektronix-bsd\n\t;;\n    *:IRIX*:*:*)\n\tIRIX_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/-/_/g'`\n\tGUESS=mips-sgi-irix$IRIX_REL\n\t;;\n    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.\n\tGUESS=romp-ibm-aix    # uname -m gives an 8 hex-code CPU id\n\t;;                    # Note that: echo \"'`uname -s`'\" gives 'AIX '\n    i*86:AIX:*:*)\n\tGUESS=i386-ibm-aix\n\t;;\n    ia64:AIX:*:*)\n\tif test -x /usr/bin/oslevel ; then\n\t\tIBM_REV=`/usr/bin/oslevel`\n\telse\n\t\tIBM_REV=$UNAME_VERSION.$UNAME_RELEASE\n\tfi\n\tGUESS=$UNAME_MACHINE-ibm-aix$IBM_REV\n\t;;\n    *:AIX:2:3)\n\tif grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then\n\t\tset_cc_for_build\n\t\tsed 's/^\t\t//' << EOF > \"$dummy.c\"\n\t\t#include <sys/systemcfg.h>\n\n\t\tmain()\n\t\t\t{\n\t\t\tif (!__power_pc())\n\t\t\t\texit(1);\n\t\t\tputs(\"powerpc-ibm-aix3.2.5\");\n\t\t\texit(0);\n\t\t\t}\nEOF\n\t\tif $CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" && SYSTEM_NAME=`\"$dummy\"`\n\t\tthen\n\t\t\tGUESS=$SYSTEM_NAME\n\t\telse\n\t\t\tGUESS=rs6000-ibm-aix3.2.5\n\t\tfi\n\telif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then\n\t\tGUESS=rs6000-ibm-aix3.2.4\n\telse\n\t\tGUESS=rs6000-ibm-aix3.2\n\tfi\n\t;;\n    *:AIX:*:[4567])\n\tIBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`\n\tif /usr/sbin/lsattr -El \"$IBM_CPU_ID\" | grep ' POWER' >/dev/null 2>&1; then\n\t\tIBM_ARCH=rs6000\n\telse\n\t\tIBM_ARCH=powerpc\n\tfi\n\tif test -x /usr/bin/lslpp ; then\n\t\tIBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \\\n\t\t\t   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`\n\telse\n\t\tIBM_REV=$UNAME_VERSION.$UNAME_RELEASE\n\tfi\n\tGUESS=$IBM_ARCH-ibm-aix$IBM_REV\n\t;;\n    *:AIX:*:*)\n\tGUESS=rs6000-ibm-aix\n\t;;\n    ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)\n\tGUESS=romp-ibm-bsd4.4\n\t;;\n    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and\n\tGUESS=romp-ibm-bsd$UNAME_RELEASE    # 4.3 with uname added to\n\t;;                                  # report: romp-ibm BSD 4.3\n    *:BOSX:*:*)\n\tGUESS=rs6000-bull-bosx\n\t;;\n    DPX/2?00:B.O.S.:*:*)\n\tGUESS=m68k-bull-sysv3\n\t;;\n    9000/[34]??:4.3bsd:1.*:*)\n\tGUESS=m68k-hp-bsd\n\t;;\n    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)\n\tGUESS=m68k-hp-bsd4.4\n\t;;\n    9000/[34678]??:HP-UX:*:*)\n\tHPUX_REV=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*.[0B]*//'`\n\tcase $UNAME_MACHINE in\n\t    9000/31?)            HP_ARCH=m68000 ;;\n\t    9000/[34]??)         HP_ARCH=m68k ;;\n\t    9000/[678][0-9][0-9])\n\t\tif test -x /usr/bin/getconf; then\n\t\t    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`\n\t\t    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`\n\t\t    case $sc_cpu_version in\n\t\t      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0\n\t\t      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1\n\t\t      532)                      # CPU_PA_RISC2_0\n\t\t\tcase $sc_kernel_bits in\n\t\t\t  32) HP_ARCH=hppa2.0n ;;\n\t\t\t  64) HP_ARCH=hppa2.0w ;;\n\t\t\t  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20\n\t\t\tesac ;;\n\t\t    esac\n\t\tfi\n\t\tif test \"$HP_ARCH\" = \"\"; then\n\t\t    set_cc_for_build\n\t\t    sed 's/^\t\t//' << EOF > \"$dummy.c\"\n\n\t\t#define _HPUX_SOURCE\n\t\t#include <stdlib.h>\n\t\t#include <unistd.h>\n\n\t\tint main ()\n\t\t{\n\t\t#if defined(_SC_KERNEL_BITS)\n\t\t    long bits = sysconf(_SC_KERNEL_BITS);\n\t\t#endif\n\t\t    long cpu  = sysconf (_SC_CPU_VERSION);\n\n\t\t    switch (cpu)\n\t\t\t{\n\t\t\tcase CPU_PA_RISC1_0: puts (\"hppa1.0\"); break;\n\t\t\tcase CPU_PA_RISC1_1: puts (\"hppa1.1\"); break;\n\t\t\tcase CPU_PA_RISC2_0:\n\t\t#if defined(_SC_KERNEL_BITS)\n\t\t\t    switch (bits)\n\t\t\t\t{\n\t\t\t\tcase 64: puts (\"hppa2.0w\"); break;\n\t\t\t\tcase 32: puts (\"hppa2.0n\"); break;\n\t\t\t\tdefault: puts (\"hppa2.0\"); break;\n\t\t\t\t} break;\n\t\t#else  /* !defined(_SC_KERNEL_BITS) */\n\t\t\t    puts (\"hppa2.0\"); break;\n\t\t#endif\n\t\t\tdefault: puts (\"hppa1.0\"); break;\n\t\t\t}\n\t\t    exit (0);\n\t\t}\nEOF\n\t\t    (CCOPTS=\"\" $CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" 2>/dev/null) && HP_ARCH=`\"$dummy\"`\n\t\t    test -z \"$HP_ARCH\" && HP_ARCH=hppa\n\t\tfi ;;\n\tesac\n\tif test \"$HP_ARCH\" = hppa2.0w\n\tthen\n\t    set_cc_for_build\n\n\t    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating\n\t    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler\n\t    # generating 64-bit code.  GNU and HP use different nomenclature:\n\t    #\n\t    # $ CC_FOR_BUILD=cc ./config.guess\n\t    # => hppa2.0w-hp-hpux11.23\n\t    # $ CC_FOR_BUILD=\"cc +DA2.0w\" ./config.guess\n\t    # => hppa64-hp-hpux11.23\n\n\t    if echo __LP64__ | (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) |\n\t\tgrep -q __LP64__\n\t    then\n\t\tHP_ARCH=hppa2.0w\n\t    else\n\t\tHP_ARCH=hppa64\n\t    fi\n\tfi\n\tGUESS=$HP_ARCH-hp-hpux$HPUX_REV\n\t;;\n    ia64:HP-UX:*:*)\n\tHPUX_REV=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*.[0B]*//'`\n\tGUESS=ia64-hp-hpux$HPUX_REV\n\t;;\n    3050*:HI-UX:*:*)\n\tset_cc_for_build\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n\t#include <unistd.h>\n\tint\n\tmain ()\n\t{\n\t  long cpu = sysconf (_SC_CPU_VERSION);\n\t  /* The order matters, because CPU_IS_HP_MC68K erroneously returns\n\t     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct\n\t     results, however.  */\n\t  if (CPU_IS_PA_RISC (cpu))\n\t    {\n\t      switch (cpu)\n\t\t{\n\t\t  case CPU_PA_RISC1_0: puts (\"hppa1.0-hitachi-hiuxwe2\"); break;\n\t\t  case CPU_PA_RISC1_1: puts (\"hppa1.1-hitachi-hiuxwe2\"); break;\n\t\t  case CPU_PA_RISC2_0: puts (\"hppa2.0-hitachi-hiuxwe2\"); break;\n\t\t  default: puts (\"hppa-hitachi-hiuxwe2\"); break;\n\t\t}\n\t    }\n\t  else if (CPU_IS_HP_MC68K (cpu))\n\t    puts (\"m68k-hitachi-hiuxwe2\");\n\t  else puts (\"unknown-hitachi-hiuxwe2\");\n\t  exit (0);\n\t}\nEOF\n\t$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" && SYSTEM_NAME=`\"$dummy\"` &&\n\t\t{ echo \"$SYSTEM_NAME\"; exit; }\n\tGUESS=unknown-hitachi-hiuxwe2\n\t;;\n    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)\n\tGUESS=hppa1.1-hp-bsd\n\t;;\n    9000/8??:4.3bsd:*:*)\n\tGUESS=hppa1.0-hp-bsd\n\t;;\n    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)\n\tGUESS=hppa1.0-hp-mpeix\n\t;;\n    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)\n\tGUESS=hppa1.1-hp-osf\n\t;;\n    hp8??:OSF1:*:*)\n\tGUESS=hppa1.0-hp-osf\n\t;;\n    i*86:OSF1:*:*)\n\tif test -x /usr/sbin/sysversion ; then\n\t    GUESS=$UNAME_MACHINE-unknown-osf1mk\n\telse\n\t    GUESS=$UNAME_MACHINE-unknown-osf1\n\tfi\n\t;;\n    parisc*:Lites*:*:*)\n\tGUESS=hppa1.1-hp-lites\n\t;;\n    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)\n\tGUESS=c1-convex-bsd\n\t;;\n    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)\n\tif getsysinfo -f scalar_acc\n\tthen echo c32-convex-bsd\n\telse echo c2-convex-bsd\n\tfi\n\texit ;;\n    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)\n\tGUESS=c34-convex-bsd\n\t;;\n    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)\n\tGUESS=c38-convex-bsd\n\t;;\n    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)\n\tGUESS=c4-convex-bsd\n\t;;\n    CRAY*Y-MP:*:*:*)\n\tCRAY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'`\n\tGUESS=ymp-cray-unicos$CRAY_REL\n\t;;\n    CRAY*[A-Z]90:*:*:*)\n\techo \"$UNAME_MACHINE\"-cray-unicos\"$UNAME_RELEASE\" \\\n\t| sed -e 's/CRAY.*\\([A-Z]90\\)/\\1/' \\\n\t      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \\\n\t      -e 's/\\.[^.]*$/.X/'\n\texit ;;\n    CRAY*TS:*:*:*)\n\tCRAY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'`\n\tGUESS=t90-cray-unicos$CRAY_REL\n\t;;\n    CRAY*T3E:*:*:*)\n\tCRAY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'`\n\tGUESS=alphaev5-cray-unicosmk$CRAY_REL\n\t;;\n    CRAY*SV1:*:*:*)\n\tCRAY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'`\n\tGUESS=sv1-cray-unicos$CRAY_REL\n\t;;\n    *:UNICOS/mp:*:*)\n\tCRAY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/\\.[^.]*$/.X/'`\n\tGUESS=craynv-cray-unicosmp$CRAY_REL\n\t;;\n    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)\n\tFUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`\n\tFUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\\///'`\n\tFUJITSU_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/ /_/'`\n\tGUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}\n\t;;\n    5000:UNIX_System_V:4.*:*)\n\tFUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\\///'`\n\tFUJITSU_REL=`echo \"$UNAME_RELEASE\" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`\n\tGUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}\n\t;;\n    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\\ Embedded/OS:*:*)\n\tGUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE\n\t;;\n    sparc*:BSD/OS:*:*)\n\tGUESS=sparc-unknown-bsdi$UNAME_RELEASE\n\t;;\n    *:BSD/OS:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE\n\t;;\n    arm:FreeBSD:*:*)\n\tUNAME_PROCESSOR=`uname -p`\n\tset_cc_for_build\n\tif echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t    | grep -q __ARM_PCS_VFP\n\tthen\n\t    FREEBSD_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[-(].*//'`\n\t    GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi\n\telse\n\t    FREEBSD_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[-(].*//'`\n\t    GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf\n\tfi\n\t;;\n    *:FreeBSD:*:*)\n\tUNAME_PROCESSOR=`/usr/bin/uname -p`\n\tcase $UNAME_PROCESSOR in\n\t    amd64)\n\t\tUNAME_PROCESSOR=x86_64 ;;\n\t    i386)\n\t\tUNAME_PROCESSOR=i586 ;;\n\tesac\n\tFREEBSD_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[-(].*//'`\n\tGUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL\n\t;;\n    i*:CYGWIN*:*)\n\tGUESS=$UNAME_MACHINE-pc-cygwin\n\t;;\n    *:MINGW64*:*)\n\tGUESS=$UNAME_MACHINE-pc-mingw64\n\t;;\n    *:MINGW*:*)\n\tGUESS=$UNAME_MACHINE-pc-mingw32\n\t;;\n    *:MSYS*:*)\n\tGUESS=$UNAME_MACHINE-pc-msys\n\t;;\n    i*:PW*:*)\n\tGUESS=$UNAME_MACHINE-pc-pw32\n\t;;\n    *:Interix*:*)\n\tcase $UNAME_MACHINE in\n\t    x86)\n\t\tGUESS=i586-pc-interix$UNAME_RELEASE\n\t\t;;\n\t    authenticamd | genuineintel | EM64T)\n\t\tGUESS=x86_64-unknown-interix$UNAME_RELEASE\n\t\t;;\n\t    IA64)\n\t\tGUESS=ia64-unknown-interix$UNAME_RELEASE\n\t\t;;\n\tesac ;;\n    i*:UWIN*:*)\n\tGUESS=$UNAME_MACHINE-pc-uwin\n\t;;\n    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)\n\tGUESS=x86_64-pc-cygwin\n\t;;\n    prep*:SunOS:5.*:*)\n\tSUN_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[^.]*//'`\n\tGUESS=powerpcle-unknown-solaris2$SUN_REL\n\t;;\n    *:GNU:*:*)\n\t# the GNU system\n\tGNU_ARCH=`echo \"$UNAME_MACHINE\" | sed -e 's,[-/].*$,,'`\n\tGNU_REL=`echo \"$UNAME_RELEASE\" | sed -e 's,/.*$,,'`\n\tGUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL\n\t;;\n    *:GNU/*:*:*)\n\t# other systems with GNU libc and userland\n\tGNU_SYS=`echo \"$UNAME_SYSTEM\" | sed 's,^[^/]*/,,' | tr \"[:upper:]\" \"[:lower:]\"`\n\tGNU_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[-(].*//'`\n\tGUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC\n\t;;\n    *:Minix:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-minix\n\t;;\n    aarch64:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    aarch64_be:Linux:*:*)\n\tUNAME_MACHINE=aarch64_be\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    alpha:Linux:*:*)\n\tcase `sed -n '/^cpu model/s/^.*: \\(.*\\)/\\1/p' /proc/cpuinfo 2>/dev/null` in\n\t  EV5)   UNAME_MACHINE=alphaev5 ;;\n\t  EV56)  UNAME_MACHINE=alphaev56 ;;\n\t  PCA56) UNAME_MACHINE=alphapca56 ;;\n\t  PCA57) UNAME_MACHINE=alphapca56 ;;\n\t  EV6)   UNAME_MACHINE=alphaev6 ;;\n\t  EV67)  UNAME_MACHINE=alphaev67 ;;\n\t  EV68*) UNAME_MACHINE=alphaev68 ;;\n\tesac\n\tobjdump --private-headers /bin/sh | grep -q ld.so.1\n\tif test \"$?\" = 0 ; then LIBC=gnulibc1 ; fi\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    arm*:Linux:*:*)\n\tset_cc_for_build\n\tif echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t    | grep -q __ARM_EABI__\n\tthen\n\t    GUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\telse\n\t    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \\\n\t\t| grep -q __ARM_PCS_VFP\n\t    then\n\t\tGUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi\n\t    else\n\t\tGUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf\n\t    fi\n\tfi\n\t;;\n    avr32*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    cris:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-axis-linux-$LIBC\n\t;;\n    crisv32:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-axis-linux-$LIBC\n\t;;\n    e2k:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    frv:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    hexagon:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    i*86:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-pc-linux-$LIBC\n\t;;\n    ia64:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    k1om:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    m32r*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    m68*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    mips:Linux:*:* | mips64:Linux:*:*)\n\tset_cc_for_build\n\tIS_GLIBC=0\n\ttest x\"${LIBC}\" = xgnu && IS_GLIBC=1\n\tsed 's/^\t//' << EOF > \"$dummy.c\"\n\t#undef CPU\n\t#undef mips\n\t#undef mipsel\n\t#undef mips64\n\t#undef mips64el\n\t#if ${IS_GLIBC} && defined(_ABI64)\n\tLIBCABI=gnuabi64\n\t#else\n\t#if ${IS_GLIBC} && defined(_ABIN32)\n\tLIBCABI=gnuabin32\n\t#else\n\tLIBCABI=${LIBC}\n\t#endif\n\t#endif\n\n\t#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6\n\tCPU=mipsisa64r6\n\t#else\n\t#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6\n\tCPU=mipsisa32r6\n\t#else\n\t#if defined(__mips64)\n\tCPU=mips64\n\t#else\n\tCPU=mips\n\t#endif\n\t#endif\n\t#endif\n\n\t#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)\n\tMIPS_ENDIAN=el\n\t#else\n\t#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)\n\tMIPS_ENDIAN=\n\t#else\n\tMIPS_ENDIAN=\n\t#endif\n\t#endif\nEOF\n\tcc_set_vars=`$CC_FOR_BUILD -E \"$dummy.c\" 2>/dev/null | grep '^CPU\\|^MIPS_ENDIAN\\|^LIBCABI'`\n\teval \"$cc_set_vars\"\n\ttest \"x$CPU\" != x && { echo \"$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI\"; exit; }\n\t;;\n    mips64el:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    openrisc*:Linux:*:*)\n\tGUESS=or1k-unknown-linux-$LIBC\n\t;;\n    or32:Linux:*:* | or1k*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    padre:Linux:*:*)\n\tGUESS=sparc-unknown-linux-$LIBC\n\t;;\n    parisc64:Linux:*:* | hppa64:Linux:*:*)\n\tGUESS=hppa64-unknown-linux-$LIBC\n\t;;\n    parisc:Linux:*:* | hppa:Linux:*:*)\n\t# Look for CPU level\n\tcase `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in\n\t  PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;\n\t  PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;\n\t  *)    GUESS=hppa-unknown-linux-$LIBC ;;\n\tesac\n\t;;\n    ppc64:Linux:*:*)\n\tGUESS=powerpc64-unknown-linux-$LIBC\n\t;;\n    ppc:Linux:*:*)\n\tGUESS=powerpc-unknown-linux-$LIBC\n\t;;\n    ppc64le:Linux:*:*)\n\tGUESS=powerpc64le-unknown-linux-$LIBC\n\t;;\n    ppcle:Linux:*:*)\n\tGUESS=powerpcle-unknown-linux-$LIBC\n\t;;\n    riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    s390:Linux:*:* | s390x:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-ibm-linux-$LIBC\n\t;;\n    sh64*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    sh*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    sparc:Linux:*:* | sparc64:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    tile*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    vax:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-dec-linux-$LIBC\n\t;;\n    x86_64:Linux:*:*)\n\tset_cc_for_build\n\tLIBCABI=$LIBC\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \\\n\t\t(CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\tgrep IS_X32 >/dev/null\n\t    then\n\t\tLIBCABI=${LIBC}x32\n\t    fi\n\tfi\n\tGUESS=$UNAME_MACHINE-pc-linux-$LIBCABI\n\t;;\n    xtensa*:Linux:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-linux-$LIBC\n\t;;\n    i*86:DYNIX/ptx:4*:*)\n\t# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.\n\t# earlier versions are messed up and put the nodename in both\n\t# sysname and nodename.\n\tGUESS=i386-sequent-sysv4\n\t;;\n    i*86:UNIX_SV:4.2MP:2.*)\n\t# Unixware is an offshoot of SVR4, but it has its own version\n\t# number series starting with 2...\n\t# I am not positive that other SVR4 systems won't match this,\n\t# I just have to hope.  -- rms.\n\t# Use sysv4.2uw... so that sysv4* matches it.\n\tGUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION\n\t;;\n    i*86:OS/2:*:*)\n\t# If we were able to find `uname', then EMX Unix compatibility\n\t# is probably installed.\n\tGUESS=$UNAME_MACHINE-pc-os2-emx\n\t;;\n    i*86:XTS-300:*:STOP)\n\tGUESS=$UNAME_MACHINE-unknown-stop\n\t;;\n    i*86:atheos:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-atheos\n\t;;\n    i*86:syllable:*:*)\n\tGUESS=$UNAME_MACHINE-pc-syllable\n\t;;\n    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)\n\tGUESS=i386-unknown-lynxos$UNAME_RELEASE\n\t;;\n    i*86:*DOS:*:*)\n\tGUESS=$UNAME_MACHINE-pc-msdosdjgpp\n\t;;\n    i*86:*:4.*:*)\n\tUNAME_REL=`echo \"$UNAME_RELEASE\" | sed 's/\\/MP$//'`\n\tif grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then\n\t\tGUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL\n\telse\n\t\tGUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL\n\tfi\n\t;;\n    i*86:*:5:[678]*)\n\t# UnixWare 7.x, OpenUNIX and OpenServer 6.\n\tcase `/bin/uname -X | grep \"^Machine\"` in\n\t    *486*)\t     UNAME_MACHINE=i486 ;;\n\t    *Pentium)\t     UNAME_MACHINE=i586 ;;\n\t    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;\n\tesac\n\tGUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}\n\t;;\n    i*86:*:3.2:*)\n\tif test -f /usr/options/cb.name; then\n\t\tUNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`\n\t\tGUESS=$UNAME_MACHINE-pc-isc$UNAME_REL\n\telif /bin/uname -X 2>/dev/null >/dev/null ; then\n\t\tUNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`\n\t\t(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486\n\t\t(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i586\n\t\t(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i686\n\t\t(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \\\n\t\t\t&& UNAME_MACHINE=i686\n\t\tGUESS=$UNAME_MACHINE-pc-sco$UNAME_REL\n\telse\n\t\tGUESS=$UNAME_MACHINE-pc-sysv32\n\tfi\n\t;;\n    pc:*:*:*)\n\t# Left here for compatibility:\n\t# uname -m prints for DJGPP always 'pc', but it prints nothing about\n\t# the processor, so we play safe by assuming i586.\n\t# Note: whatever this is, it MUST be the same as what config.sub\n\t# prints for the \"djgpp\" host, or else GDB configure will decide that\n\t# this is a cross-build.\n\tGUESS=i586-pc-msdosdjgpp\n\t;;\n    Intel:Mach:3*:*)\n\tGUESS=i386-pc-mach3\n\t;;\n    paragon:*:*:*)\n\tGUESS=i860-intel-osf1\n\t;;\n    i860:*:4.*:*) # i860-SVR4\n\tif grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then\n\t  GUESS=i860-stardent-sysv$UNAME_RELEASE    # Stardent Vistra i860-SVR4\n\telse # Add other i860-SVR4 vendors below as they are discovered.\n\t  GUESS=i860-unknown-sysv$UNAME_RELEASE     # Unknown i860-SVR4\n\tfi\n\t;;\n    mini*:CTIX:SYS*5:*)\n\t# \"miniframe\"\n\tGUESS=m68010-convergent-sysv\n\t;;\n    mc68k:UNIX:SYSTEM5:3.51m)\n\tGUESS=m68k-convergent-sysv\n\t;;\n    M680?0:D-NIX:5.3:*)\n\tGUESS=m68k-diab-dnix\n\t;;\n    M68*:*:R3V[5678]*:*)\n\ttest -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;\n    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)\n\tOS_REL=''\n\ttest -r /etc/.relid \\\n\t&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \\([0-9][0-9]\\).*/\\1/p' < /etc/.relid`\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t  && { echo i486-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \\\n\t  && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; } ;;\n    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t  && { echo i486-ncr-sysv4; exit; } ;;\n    NCR*:*:4.2:* | MPRAS*:*:4.2:*)\n\tOS_REL='.3'\n\ttest -r /etc/.relid \\\n\t    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \\([0-9][0-9]\\).*/\\1/p' < /etc/.relid`\n\t/bin/uname -p 2>/dev/null | grep 86 >/dev/null \\\n\t    && { echo i486-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \\\n\t    && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; }\n\t/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \\\n\t    && { echo i586-ncr-sysv4.3\"$OS_REL\"; exit; } ;;\n    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)\n\tGUESS=m68k-unknown-lynxos$UNAME_RELEASE\n\t;;\n    mc68030:UNIX_System_V:4.*:*)\n\tGUESS=m68k-atari-sysv4\n\t;;\n    TSUNAMI:LynxOS:2.*:*)\n\tGUESS=sparc-unknown-lynxos$UNAME_RELEASE\n\t;;\n    rs6000:LynxOS:2.*:*)\n\tGUESS=rs6000-unknown-lynxos$UNAME_RELEASE\n\t;;\n    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)\n\tGUESS=powerpc-unknown-lynxos$UNAME_RELEASE\n\t;;\n    SM[BE]S:UNIX_SV:*:*)\n\tGUESS=mips-dde-sysv$UNAME_RELEASE\n\t;;\n    RM*:ReliantUNIX-*:*:*)\n\tGUESS=mips-sni-sysv4\n\t;;\n    RM*:SINIX-*:*:*)\n\tGUESS=mips-sni-sysv4\n\t;;\n    *:SINIX-*:*:*)\n\tif uname -p 2>/dev/null >/dev/null ; then\n\t\tUNAME_MACHINE=`(uname -p) 2>/dev/null`\n\t\tGUESS=$UNAME_MACHINE-sni-sysv4\n\telse\n\t\tGUESS=ns32k-sni-sysv\n\tfi\n\t;;\n    PENTIUM:*:4.0*:*)\t# Unisys `ClearPath HMP IX 4000' SVR4/MP effort\n\t\t\t# says <Richard.M.Bartel@ccMail.Census.GOV>\n\tGUESS=i586-unisys-sysv4\n\t;;\n    *:UNIX_System_V:4*:FTX*)\n\t# From Gerald Hewes <hewes@openmarket.com>.\n\t# How about differentiating between stratus architectures? -djm\n\tGUESS=hppa1.1-stratus-sysv4\n\t;;\n    *:*:*:FTX*)\n\t# From seanf@swdc.stratus.com.\n\tGUESS=i860-stratus-sysv4\n\t;;\n    i*86:VOS:*:*)\n\t# From Paul.Green@stratus.com.\n\tGUESS=$UNAME_MACHINE-stratus-vos\n\t;;\n    *:VOS:*:*)\n\t# From Paul.Green@stratus.com.\n\tGUESS=hppa1.1-stratus-vos\n\t;;\n    mc68*:A/UX:*:*)\n\tGUESS=m68k-apple-aux$UNAME_RELEASE\n\t;;\n    news*:NEWS-OS:6*:*)\n\tGUESS=mips-sony-newsos6\n\t;;\n    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)\n\tif test -d /usr/nec; then\n\t\tGUESS=mips-nec-sysv$UNAME_RELEASE\n\telse\n\t\tGUESS=mips-unknown-sysv$UNAME_RELEASE\n\tfi\n\t;;\n    BeBox:BeOS:*:*)\t# BeOS running on hardware made by Be, PPC only.\n\tGUESS=powerpc-be-beos\n\t;;\n    BeMac:BeOS:*:*)\t# BeOS running on Mac or Mac clone, PPC only.\n\tGUESS=powerpc-apple-beos\n\t;;\n    BePC:BeOS:*:*)\t# BeOS running on Intel PC compatible.\n\tGUESS=i586-pc-beos\n\t;;\n    BePC:Haiku:*:*)\t# Haiku running on Intel PC compatible.\n\tGUESS=i586-pc-haiku\n\t;;\n    x86_64:Haiku:*:*)\n\tGUESS=x86_64-unknown-haiku\n\t;;\n    SX-4:SUPER-UX:*:*)\n\tGUESS=sx4-nec-superux$UNAME_RELEASE\n\t;;\n    SX-5:SUPER-UX:*:*)\n\tGUESS=sx5-nec-superux$UNAME_RELEASE\n\t;;\n    SX-6:SUPER-UX:*:*)\n\tGUESS=sx6-nec-superux$UNAME_RELEASE\n\t;;\n    SX-7:SUPER-UX:*:*)\n\tGUESS=sx7-nec-superux$UNAME_RELEASE\n\t;;\n    SX-8:SUPER-UX:*:*)\n\tGUESS=sx8-nec-superux$UNAME_RELEASE\n\t;;\n    SX-8R:SUPER-UX:*:*)\n\tGUESS=sx8r-nec-superux$UNAME_RELEASE\n\t;;\n    SX-ACE:SUPER-UX:*:*)\n\tGUESS=sxace-nec-superux$UNAME_RELEASE\n\t;;\n    Power*:Rhapsody:*:*)\n\tGUESS=powerpc-apple-rhapsody$UNAME_RELEASE\n\t;;\n    *:Rhapsody:*:*)\n\tGUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE\n\t;;\n    arm64:Darwin:*:*)\n\tGUESS=aarch64-apple-darwin$UNAME_RELEASE\n\t;;\n    *:Darwin:*:*)\n\tUNAME_PROCESSOR=`uname -p`\n\tcase $UNAME_PROCESSOR in\n\t    unknown) UNAME_PROCESSOR=powerpc ;;\n\tesac\n\tif command -v xcode-select > /dev/null 2> /dev/null && \\\n\t\t! xcode-select --print-path > /dev/null 2> /dev/null ; then\n\t    # Avoid executing cc if there is no toolchain installed as\n\t    # cc will be a stub that puts up a graphical alert\n\t    # prompting the user to install developer tools.\n\t    CC_FOR_BUILD=no_compiler_found\n\telse\n\t    set_cc_for_build\n\tfi\n\tif test \"$CC_FOR_BUILD\" != no_compiler_found; then\n\t    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \\\n\t\t   (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\t   grep IS_64BIT_ARCH >/dev/null\n\t    then\n\t\tcase $UNAME_PROCESSOR in\n\t\t    i386) UNAME_PROCESSOR=x86_64 ;;\n\t\t    powerpc) UNAME_PROCESSOR=powerpc64 ;;\n\t\tesac\n\t    fi\n\t    # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc\n\t    if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \\\n\t\t   (CCOPTS=\"\" $CC_FOR_BUILD -E - 2>/dev/null) | \\\n\t\t   grep IS_PPC >/dev/null\n\t    then\n\t\tUNAME_PROCESSOR=powerpc\n\t    fi\n\telif test \"$UNAME_PROCESSOR\" = i386 ; then\n\t    # uname -m returns i386 or x86_64\n\t    UNAME_PROCESSOR=$UNAME_MACHINE\n\tfi\n\tGUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE\n\t;;\n    *:procnto*:*:* | *:QNX:[0123456789]*:*)\n\tUNAME_PROCESSOR=`uname -p`\n\tif test \"$UNAME_PROCESSOR\" = x86; then\n\t\tUNAME_PROCESSOR=i386\n\t\tUNAME_MACHINE=pc\n\tfi\n\tGUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE\n\t;;\n    *:QNX:*:4*)\n\tGUESS=i386-pc-qnx\n\t;;\n    NEO-*:NONSTOP_KERNEL:*:*)\n\tGUESS=neo-tandem-nsk$UNAME_RELEASE\n\t;;\n    NSE-*:NONSTOP_KERNEL:*:*)\n\tGUESS=nse-tandem-nsk$UNAME_RELEASE\n\t;;\n    NSR-*:NONSTOP_KERNEL:*:*)\n\tGUESS=nsr-tandem-nsk$UNAME_RELEASE\n\t;;\n    NSV-*:NONSTOP_KERNEL:*:*)\n\tGUESS=nsv-tandem-nsk$UNAME_RELEASE\n\t;;\n    NSX-*:NONSTOP_KERNEL:*:*)\n\tGUESS=nsx-tandem-nsk$UNAME_RELEASE\n\t;;\n    *:NonStop-UX:*:*)\n\tGUESS=mips-compaq-nonstopux\n\t;;\n    BS2000:POSIX*:*:*)\n\tGUESS=bs2000-siemens-sysv\n\t;;\n    DS/*:UNIX_System_V:*:*)\n\tGUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE\n\t;;\n    *:Plan9:*:*)\n\t# \"uname -m\" is not consistent, so use $cputype instead. 386\n\t# is converted to i386 for consistency with other x86\n\t# operating systems.\n\tif test \"${cputype-}\" = 386; then\n\t    UNAME_MACHINE=i386\n\telif test \"x${cputype-}\" != x; then\n\t    UNAME_MACHINE=$cputype\n\tfi\n\tGUESS=$UNAME_MACHINE-unknown-plan9\n\t;;\n    *:TOPS-10:*:*)\n\tGUESS=pdp10-unknown-tops10\n\t;;\n    *:TENEX:*:*)\n\tGUESS=pdp10-unknown-tenex\n\t;;\n    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)\n\tGUESS=pdp10-dec-tops20\n\t;;\n    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)\n\tGUESS=pdp10-xkl-tops20\n\t;;\n    *:TOPS-20:*:*)\n\tGUESS=pdp10-unknown-tops20\n\t;;\n    *:ITS:*:*)\n\tGUESS=pdp10-unknown-its\n\t;;\n    SEI:*:*:SEIUX)\n\tGUESS=mips-sei-seiux$UNAME_RELEASE\n\t;;\n    *:DragonFly:*:*)\n\tDRAGONFLY_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/[-(].*//'`\n\tGUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL\n\t;;\n    *:*VMS:*:*)\n\tUNAME_MACHINE=`(uname -p) 2>/dev/null`\n\tcase $UNAME_MACHINE in\n\t    A*) GUESS=alpha-dec-vms ;;\n\t    I*) GUESS=ia64-dec-vms ;;\n\t    V*) GUESS=vax-dec-vms ;;\n\tesac ;;\n    *:XENIX:*:SysV)\n\tGUESS=i386-pc-xenix\n\t;;\n    i*86:skyos:*:*)\n\tSKYOS_REL=`echo \"$UNAME_RELEASE\" | sed -e 's/ .*$//'`\n\tGUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL\n\t;;\n    i*86:rdos:*:*)\n\tGUESS=$UNAME_MACHINE-pc-rdos\n\t;;\n    *:AROS:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-aros\n\t;;\n    x86_64:VMkernel:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-esx\n\t;;\n    amd64:Isilon\\ OneFS:*:*)\n\tGUESS=x86_64-unknown-onefs\n\t;;\n    *:Unleashed:*:*)\n\tGUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE\n\t;;\nesac\n\n# Do we have a guess based on uname results?\nif test \"x$GUESS\" != x; then\n    echo \"$GUESS\"\n    exit\nfi\n\n# No uname command or uname output not recognized.\nset_cc_for_build\ncat > \"$dummy.c\" <<EOF\n#ifdef _SEQUENT_\n#include <sys/types.h>\n#include <sys/utsname.h>\n#endif\n#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)\n#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)\n#include <signal.h>\n#if defined(_SIZE_T_) || defined(SIGLOST)\n#include <sys/utsname.h>\n#endif\n#endif\n#endif\nmain ()\n{\n#if defined (sony)\n#if defined (MIPSEB)\n  /* BFD wants \"bsd\" instead of \"newsos\".  Perhaps BFD should be changed,\n     I don't know....  */\n  printf (\"mips-sony-bsd\\n\"); exit (0);\n#else\n#include <sys/param.h>\n  printf (\"m68k-sony-newsos%s\\n\",\n#ifdef NEWSOS4\n  \"4\"\n#else\n  \"\"\n#endif\n  ); exit (0);\n#endif\n#endif\n\n#if defined (NeXT)\n#if !defined (__ARCHITECTURE__)\n#define __ARCHITECTURE__ \"m68k\"\n#endif\n  int version;\n  version=`(hostinfo | sed -n 's/.*NeXT Mach \\([0-9]*\\).*/\\1/p') 2>/dev/null`;\n  if (version < 4)\n    printf (\"%s-next-nextstep%d\\n\", __ARCHITECTURE__, version);\n  else\n    printf (\"%s-next-openstep%d\\n\", __ARCHITECTURE__, version);\n  exit (0);\n#endif\n\n#if defined (MULTIMAX) || defined (n16)\n#if defined (UMAXV)\n  printf (\"ns32k-encore-sysv\\n\"); exit (0);\n#else\n#if defined (CMU)\n  printf (\"ns32k-encore-mach\\n\"); exit (0);\n#else\n  printf (\"ns32k-encore-bsd\\n\"); exit (0);\n#endif\n#endif\n#endif\n\n#if defined (__386BSD__)\n  printf (\"i386-pc-bsd\\n\"); exit (0);\n#endif\n\n#if defined (sequent)\n#if defined (i386)\n  printf (\"i386-sequent-dynix\\n\"); exit (0);\n#endif\n#if defined (ns32000)\n  printf (\"ns32k-sequent-dynix\\n\"); exit (0);\n#endif\n#endif\n\n#if defined (_SEQUENT_)\n  struct utsname un;\n\n  uname(&un);\n  if (strncmp(un.version, \"V2\", 2) == 0) {\n    printf (\"i386-sequent-ptx2\\n\"); exit (0);\n  }\n  if (strncmp(un.version, \"V1\", 2) == 0) { /* XXX is V1 correct? */\n    printf (\"i386-sequent-ptx1\\n\"); exit (0);\n  }\n  printf (\"i386-sequent-ptx\\n\"); exit (0);\n#endif\n\n#if defined (vax)\n#if !defined (ultrix)\n#include <sys/param.h>\n#if defined (BSD)\n#if BSD == 43\n  printf (\"vax-dec-bsd4.3\\n\"); exit (0);\n#else\n#if BSD == 199006\n  printf (\"vax-dec-bsd4.3reno\\n\"); exit (0);\n#else\n  printf (\"vax-dec-bsd\\n\"); exit (0);\n#endif\n#endif\n#else\n  printf (\"vax-dec-bsd\\n\"); exit (0);\n#endif\n#else\n#if defined(_SIZE_T_) || defined(SIGLOST)\n  struct utsname un;\n  uname (&un);\n  printf (\"vax-dec-ultrix%s\\n\", un.release); exit (0);\n#else\n  printf (\"vax-dec-ultrix\\n\"); exit (0);\n#endif\n#endif\n#endif\n#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)\n#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)\n#if defined(_SIZE_T_) || defined(SIGLOST)\n  struct utsname *un;\n  uname (&un);\n  printf (\"mips-dec-ultrix%s\\n\", un.release); exit (0);\n#else\n  printf (\"mips-dec-ultrix\\n\"); exit (0);\n#endif\n#endif\n#endif\n\n#if defined (alliant) && defined (i860)\n  printf (\"i860-alliant-bsd\\n\"); exit (0);\n#endif\n\n  exit (1);\n}\nEOF\n\n$CC_FOR_BUILD -o \"$dummy\" \"$dummy.c\" 2>/dev/null && SYSTEM_NAME=`\"$dummy\"` &&\n\t{ echo \"$SYSTEM_NAME\"; exit; }\n\n# Apollos put the system type in the environment.\ntest -d /usr/apollo && { echo \"$ISP-apollo-$SYSTYPE\"; exit; }\n\necho \"$0: unable to guess system type\" >&2\n\ncase $UNAME_MACHINE:$UNAME_SYSTEM in\n    mips:Linux | mips64:Linux)\n\t# If we got here on MIPS GNU/Linux, output extra information.\n\tcat >&2 <<EOF\n\nNOTE: MIPS GNU/Linux systems require a C compiler to fully recognize\nthe system type. Please install a C compiler and try again.\nEOF\n\t;;\nesac\n\ncat >&2 <<EOF\n\nThis script (version $timestamp), has failed to recognize the\noperating system you are using. If your script is old, overwrite *all*\ncopies of config.guess and config.sub with the latest versions from:\n\n  https://git.savannah.gnu.org/cgit/config.git/plain/config.guess\nand\n  https://git.savannah.gnu.org/cgit/config.git/plain/config.sub\nEOF\n\nour_year=`echo $timestamp | sed 's,-.*,,'`\nthisyear=`date +%Y`\n# shellcheck disable=SC2003\nscript_age=`expr \"$thisyear\" - \"$our_year\"`\nif test \"$script_age\" -lt 3 ; then\n   cat >&2 <<EOF\n\nIf $0 has already been updated, send the following data and any\ninformation you think might be pertinent to config-patches@gnu.org to\nprovide the necessary information to handle your system.\n\nconfig.guess timestamp = $timestamp\n\nuname -m = `(uname -m) 2>/dev/null || echo unknown`\nuname -r = `(uname -r) 2>/dev/null || echo unknown`\nuname -s = `(uname -s) 2>/dev/null || echo unknown`\nuname -v = `(uname -v) 2>/dev/null || echo unknown`\n\n/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`\n/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`\n\nhostinfo               = `(hostinfo) 2>/dev/null`\n/bin/universe          = `(/bin/universe) 2>/dev/null`\n/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`\n/bin/arch              = `(/bin/arch) 2>/dev/null`\n/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`\n/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`\n\nUNAME_MACHINE = \"$UNAME_MACHINE\"\nUNAME_RELEASE = \"$UNAME_RELEASE\"\nUNAME_SYSTEM  = \"$UNAME_SYSTEM\"\nUNAME_VERSION = \"$UNAME_VERSION\"\nEOF\nfi\n\nexit 1\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"timestamp='\"\n# time-stamp-format: \"%:y-%02m-%02d\"\n# time-stamp-end: \"'\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/config.sub",
    "content": "#! /bin/sh\n# Configuration validation subroutine script.\n#   Copyright 1992-2021 Free Software Foundation, Inc.\n\n# shellcheck disable=SC2006,SC2268 # see below for rationale\n\ntimestamp='2021-08-14'\n\n# This file is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that\n# program.  This Exception is an additional permission under section 7\n# of the GNU General Public License, version 3 (\"GPLv3\").\n\n\n# Please send patches to <config-patches@gnu.org>.\n#\n# Configuration subroutine to validate and canonicalize a configuration type.\n# Supply the specified configuration type as an argument.\n# If it is invalid, we print an error message on stderr and exit with code 1.\n# Otherwise, we print the canonical config type on stdout and succeed.\n\n# You can get the latest version of this script from:\n# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub\n\n# This file is supposed to be the same for all GNU packages\n# and recognize all the CPU types, system types and aliases\n# that are meaningful with *any* GNU software.\n# Each package is responsible for reporting which valid configurations\n# it does not support.  The user should be able to distinguish\n# a failure to support a valid configuration from a meaningless\n# configuration.\n\n# The goal of this file is to map all the various variations of a given\n# machine specification into a single specification in the form:\n#\tCPU_TYPE-MANUFACTURER-OPERATING_SYSTEM\n# or in some cases, the newer four-part form:\n#\tCPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM\n# It is wrong to echo any other type of specification.\n\n# The \"shellcheck disable\" line above the timestamp inhibits complaints\n# about features and limitations of the classic Bourne shell that were\n# superseded or lifted in POSIX.  However, this script identifies a wide\n# variety of pre-POSIX systems that do not have POSIX shells at all, and\n# even some reasonably current systems (Solaris 10 as case-in-point) still\n# have a pre-POSIX /bin/sh.\n\nme=`echo \"$0\" | sed -e 's,.*/,,'`\n\nusage=\"\\\nUsage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS\n\nCanonicalize a configuration name.\n\nOptions:\n  -h, --help         print this help, then exit\n  -t, --time-stamp   print date of last modification, then exit\n  -v, --version      print version number, then exit\n\nReport bugs and patches to <config-patches@gnu.org>.\"\n\nversion=\"\\\nGNU config.sub ($timestamp)\n\nCopyright 1992-2021 Free Software Foundation, Inc.\n\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\"\n\nhelp=\"\nTry \\`$me --help' for more information.\"\n\n# Parse command line\nwhile test $# -gt 0 ; do\n  case $1 in\n    --time-stamp | --time* | -t )\n       echo \"$timestamp\" ; exit ;;\n    --version | -v )\n       echo \"$version\" ; exit ;;\n    --help | --h* | -h )\n       echo \"$usage\"; exit ;;\n    -- )     # Stop option processing\n       shift; break ;;\n    - )\t# Use stdin as input.\n       break ;;\n    -* )\n       echo \"$me: invalid option $1$help\" >&2\n       exit 1 ;;\n\n    *local*)\n       # First pass through any local machine types.\n       echo \"$1\"\n       exit ;;\n\n    * )\n       break ;;\n  esac\ndone\n\ncase $# in\n 0) echo \"$me: missing argument$help\" >&2\n    exit 1;;\n 1) ;;\n *) echo \"$me: too many arguments$help\" >&2\n    exit 1;;\nesac\n\n# Split fields of configuration type\n# shellcheck disable=SC2162\nsaved_IFS=$IFS\nIFS=\"-\" read field1 field2 field3 field4 <<EOF\n$1\nEOF\nIFS=$saved_IFS\n\n# Separate into logical components for further validation\ncase $1 in\n\t*-*-*-*-*)\n\t\techo Invalid configuration \\`\"$1\"\\': more than four components >&2\n\t\texit 1\n\t\t;;\n\t*-*-*-*)\n\t\tbasic_machine=$field1-$field2\n\t\tbasic_os=$field3-$field4\n\t\t;;\n\t*-*-*)\n\t\t# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two\n\t\t# parts\n\t\tmaybe_os=$field2-$field3\n\t\tcase $maybe_os in\n\t\t\tnto-qnx* | linux-* | uclinux-uclibc* \\\n\t\t\t| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \\\n\t\t\t| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \\\n\t\t\t| storm-chaos* | os2-emx* | rtmk-nova*)\n\t\t\t\tbasic_machine=$field1\n\t\t\t\tbasic_os=$maybe_os\n\t\t\t\t;;\n\t\t\tandroid-linux)\n\t\t\t\tbasic_machine=$field1-unknown\n\t\t\t\tbasic_os=linux-android\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\tbasic_machine=$field1-$field2\n\t\t\t\tbasic_os=$field3\n\t\t\t\t;;\n\t\tesac\n\t\t;;\n\t*-*)\n\t\t# A lone config we happen to match not fitting any pattern\n\t\tcase $field1-$field2 in\n\t\t\tdecstation-3100)\n\t\t\t\tbasic_machine=mips-dec\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\t*-*)\n\t\t\t\t# Second component is usually, but not always the OS\n\t\t\t\tcase $field2 in\n\t\t\t\t\t# Prevent following clause from handling this valid os\n\t\t\t\t\tsun*os*)\n\t\t\t\t\t\tbasic_machine=$field1\n\t\t\t\t\t\tbasic_os=$field2\n\t\t\t\t\t\t;;\n\t\t\t\t\tzephyr*)\n\t\t\t\t\t\tbasic_machine=$field1-unknown\n\t\t\t\t\t\tbasic_os=$field2\n\t\t\t\t\t\t;;\n\t\t\t\t\t# Manufacturers\n\t\t\t\t\tdec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \\\n\t\t\t\t\t| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \\\n\t\t\t\t\t| unicom* | ibm* | next | hp | isi* | apollo | altos* \\\n\t\t\t\t\t| convergent* | ncr* | news | 32* | 3600* | 3100* \\\n\t\t\t\t\t| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \\\n\t\t\t\t\t| ultra | tti* | harris | dolphin | highlevel | gould \\\n\t\t\t\t\t| cbm | ns | masscomp | apple | axis | knuth | cray \\\n\t\t\t\t\t| microblaze* | sim | cisco \\\n\t\t\t\t\t| oki | wec | wrs | winbond)\n\t\t\t\t\t\tbasic_machine=$field1-$field2\n\t\t\t\t\t\tbasic_os=\n\t\t\t\t\t\t;;\n\t\t\t\t\t*)\n\t\t\t\t\t\tbasic_machine=$field1\n\t\t\t\t\t\tbasic_os=$field2\n\t\t\t\t\t\t;;\n\t\t\t\tesac\n\t\t\t;;\n\t\tesac\n\t\t;;\n\t*)\n\t\t# Convert single-component short-hands not valid as part of\n\t\t# multi-component configurations.\n\t\tcase $field1 in\n\t\t\t386bsd)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\ta29khif)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tadobe68k)\n\t\t\t\tbasic_machine=m68010-adobe\n\t\t\t\tbasic_os=scout\n\t\t\t\t;;\n\t\t\talliant)\n\t\t\t\tbasic_machine=fx80-alliant\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\taltos | altos3068)\n\t\t\t\tbasic_machine=m68k-altos\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tam29k)\n\t\t\t\tbasic_machine=a29k-none\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tamdahl)\n\t\t\t\tbasic_machine=580-amdahl\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tamiga)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tamigaos | amigados)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=amigaos\n\t\t\t\t;;\n\t\t\tamigaunix | amix)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tapollo68)\n\t\t\t\tbasic_machine=m68k-apollo\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tapollo68bsd)\n\t\t\t\tbasic_machine=m68k-apollo\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\taros)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=aros\n\t\t\t\t;;\n\t\t\taux)\n\t\t\t\tbasic_machine=m68k-apple\n\t\t\t\tbasic_os=aux\n\t\t\t\t;;\n\t\t\tbalance)\n\t\t\t\tbasic_machine=ns32k-sequent\n\t\t\t\tbasic_os=dynix\n\t\t\t\t;;\n\t\t\tblackfin)\n\t\t\t\tbasic_machine=bfin-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tcegcc)\n\t\t\t\tbasic_machine=arm-unknown\n\t\t\t\tbasic_os=cegcc\n\t\t\t\t;;\n\t\t\tconvex-c1)\n\t\t\t\tbasic_machine=c1-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c2)\n\t\t\t\tbasic_machine=c2-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c32)\n\t\t\t\tbasic_machine=c32-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c34)\n\t\t\t\tbasic_machine=c34-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tconvex-c38)\n\t\t\t\tbasic_machine=c38-convex\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\tcray)\n\t\t\t\tbasic_machine=j90-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tcrds | unos)\n\t\t\t\tbasic_machine=m68k-crds\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tda30)\n\t\t\t\tbasic_machine=m68k-da30\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tdecstation | pmax | pmin | dec3100 | decstatn)\n\t\t\t\tbasic_machine=mips-dec\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tdelta88)\n\t\t\t\tbasic_machine=m88k-motorola\n\t\t\t\tbasic_os=sysv3\n\t\t\t\t;;\n\t\t\tdicos)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=dicos\n\t\t\t\t;;\n\t\t\tdjgpp)\n\t\t\t\tbasic_machine=i586-pc\n\t\t\t\tbasic_os=msdosdjgpp\n\t\t\t\t;;\n\t\t\tebmon29k)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=ebmon\n\t\t\t\t;;\n\t\t\tes1800 | OSE68k | ose68k | ose | OSE)\n\t\t\t\tbasic_machine=m68k-ericsson\n\t\t\t\tbasic_os=ose\n\t\t\t\t;;\n\t\t\tgmicro)\n\t\t\t\tbasic_machine=tron-gmicro\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tgo32)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=go32\n\t\t\t\t;;\n\t\t\th8300hms)\n\t\t\t\tbasic_machine=h8300-hitachi\n\t\t\t\tbasic_os=hms\n\t\t\t\t;;\n\t\t\th8300xray)\n\t\t\t\tbasic_machine=h8300-hitachi\n\t\t\t\tbasic_os=xray\n\t\t\t\t;;\n\t\t\th8500hms)\n\t\t\t\tbasic_machine=h8500-hitachi\n\t\t\t\tbasic_os=hms\n\t\t\t\t;;\n\t\t\tharris)\n\t\t\t\tbasic_machine=m88k-harris\n\t\t\t\tbasic_os=sysv3\n\t\t\t\t;;\n\t\t\thp300 | hp300hpux)\n\t\t\t\tbasic_machine=m68k-hp\n\t\t\t\tbasic_os=hpux\n\t\t\t\t;;\n\t\t\thp300bsd)\n\t\t\t\tbasic_machine=m68k-hp\n\t\t\t\tbasic_os=bsd\n\t\t\t\t;;\n\t\t\thppaosf)\n\t\t\t\tbasic_machine=hppa1.1-hp\n\t\t\t\tbasic_os=osf\n\t\t\t\t;;\n\t\t\thppro)\n\t\t\t\tbasic_machine=hppa1.1-hp\n\t\t\t\tbasic_os=proelf\n\t\t\t\t;;\n\t\t\ti386mach)\n\t\t\t\tbasic_machine=i386-mach\n\t\t\t\tbasic_os=mach\n\t\t\t\t;;\n\t\t\tisi68 | isi)\n\t\t\t\tbasic_machine=m68k-isi\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tm68knommu)\n\t\t\t\tbasic_machine=m68k-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tmagnum | m3230)\n\t\t\t\tbasic_machine=mips-mips\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tmerlin)\n\t\t\t\tbasic_machine=ns32k-utek\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tmingw64)\n\t\t\t\tbasic_machine=x86_64-pc\n\t\t\t\tbasic_os=mingw64\n\t\t\t\t;;\n\t\t\tmingw32)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=mingw32\n\t\t\t\t;;\n\t\t\tmingw32ce)\n\t\t\t\tbasic_machine=arm-unknown\n\t\t\t\tbasic_os=mingw32ce\n\t\t\t\t;;\n\t\t\tmonitor)\n\t\t\t\tbasic_machine=m68k-rom68k\n\t\t\t\tbasic_os=coff\n\t\t\t\t;;\n\t\t\tmorphos)\n\t\t\t\tbasic_machine=powerpc-unknown\n\t\t\t\tbasic_os=morphos\n\t\t\t\t;;\n\t\t\tmoxiebox)\n\t\t\t\tbasic_machine=moxie-unknown\n\t\t\t\tbasic_os=moxiebox\n\t\t\t\t;;\n\t\t\tmsdos)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=msdos\n\t\t\t\t;;\n\t\t\tmsys)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=msys\n\t\t\t\t;;\n\t\t\tmvs)\n\t\t\t\tbasic_machine=i370-ibm\n\t\t\t\tbasic_os=mvs\n\t\t\t\t;;\n\t\t\tnacl)\n\t\t\t\tbasic_machine=le32-unknown\n\t\t\t\tbasic_os=nacl\n\t\t\t\t;;\n\t\t\tncr3000)\n\t\t\t\tbasic_machine=i486-ncr\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tnetbsd386)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=netbsd\n\t\t\t\t;;\n\t\t\tnetwinder)\n\t\t\t\tbasic_machine=armv4l-rebel\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tnews | news700 | news800 | news900)\n\t\t\t\tbasic_machine=m68k-sony\n\t\t\t\tbasic_os=newsos\n\t\t\t\t;;\n\t\t\tnews1000)\n\t\t\t\tbasic_machine=m68030-sony\n\t\t\t\tbasic_os=newsos\n\t\t\t\t;;\n\t\t\tnecv70)\n\t\t\t\tbasic_machine=v70-nec\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tnh3000)\n\t\t\t\tbasic_machine=m68k-harris\n\t\t\t\tbasic_os=cxux\n\t\t\t\t;;\n\t\t\tnh[45]000)\n\t\t\t\tbasic_machine=m88k-harris\n\t\t\t\tbasic_os=cxux\n\t\t\t\t;;\n\t\t\tnindy960)\n\t\t\t\tbasic_machine=i960-intel\n\t\t\t\tbasic_os=nindy\n\t\t\t\t;;\n\t\t\tmon960)\n\t\t\t\tbasic_machine=i960-intel\n\t\t\t\tbasic_os=mon960\n\t\t\t\t;;\n\t\t\tnonstopux)\n\t\t\t\tbasic_machine=mips-compaq\n\t\t\t\tbasic_os=nonstopux\n\t\t\t\t;;\n\t\t\tos400)\n\t\t\t\tbasic_machine=powerpc-ibm\n\t\t\t\tbasic_os=os400\n\t\t\t\t;;\n\t\t\tOSE68000 | ose68000)\n\t\t\t\tbasic_machine=m68000-ericsson\n\t\t\t\tbasic_os=ose\n\t\t\t\t;;\n\t\t\tos68k)\n\t\t\t\tbasic_machine=m68k-none\n\t\t\t\tbasic_os=os68k\n\t\t\t\t;;\n\t\t\tparagon)\n\t\t\t\tbasic_machine=i860-intel\n\t\t\t\tbasic_os=osf\n\t\t\t\t;;\n\t\t\tparisc)\n\t\t\t\tbasic_machine=hppa-unknown\n\t\t\t\tbasic_os=linux\n\t\t\t\t;;\n\t\t\tpsp)\n\t\t\t\tbasic_machine=mipsallegrexel-sony\n\t\t\t\tbasic_os=psp\n\t\t\t\t;;\n\t\t\tpw32)\n\t\t\t\tbasic_machine=i586-unknown\n\t\t\t\tbasic_os=pw32\n\t\t\t\t;;\n\t\t\trdos | rdos64)\n\t\t\t\tbasic_machine=x86_64-pc\n\t\t\t\tbasic_os=rdos\n\t\t\t\t;;\n\t\t\trdos32)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=rdos\n\t\t\t\t;;\n\t\t\trom68k)\n\t\t\t\tbasic_machine=m68k-rom68k\n\t\t\t\tbasic_os=coff\n\t\t\t\t;;\n\t\t\tsa29200)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tsei)\n\t\t\t\tbasic_machine=mips-sei\n\t\t\t\tbasic_os=seiux\n\t\t\t\t;;\n\t\t\tsequent)\n\t\t\t\tbasic_machine=i386-sequent\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsps7)\n\t\t\t\tbasic_machine=m68k-bull\n\t\t\t\tbasic_os=sysv2\n\t\t\t\t;;\n\t\t\tst2000)\n\t\t\t\tbasic_machine=m68k-tandem\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tstratus)\n\t\t\t\tbasic_machine=i860-stratus\n\t\t\t\tbasic_os=sysv4\n\t\t\t\t;;\n\t\t\tsun2)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun2os3)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun2os4)\n\t\t\t\tbasic_machine=m68000-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun3)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun3os3)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun3os4)\n\t\t\t\tbasic_machine=m68k-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun4)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsun4os3)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=sunos3\n\t\t\t\t;;\n\t\t\tsun4os4)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=sunos4\n\t\t\t\t;;\n\t\t\tsun4sol2)\n\t\t\t\tbasic_machine=sparc-sun\n\t\t\t\tbasic_os=solaris2\n\t\t\t\t;;\n\t\t\tsun386 | sun386i | roadrunner)\n\t\t\t\tbasic_machine=i386-sun\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\t\tsv1)\n\t\t\t\tbasic_machine=sv1-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tsymmetry)\n\t\t\t\tbasic_machine=i386-sequent\n\t\t\t\tbasic_os=dynix\n\t\t\t\t;;\n\t\t\tt3e)\n\t\t\t\tbasic_machine=alphaev5-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\tt90)\n\t\t\t\tbasic_machine=t90-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\ttoad1)\n\t\t\t\tbasic_machine=pdp10-xkl\n\t\t\t\tbasic_os=tops20\n\t\t\t\t;;\n\t\t\ttpf)\n\t\t\t\tbasic_machine=s390x-ibm\n\t\t\t\tbasic_os=tpf\n\t\t\t\t;;\n\t\t\tudi29k)\n\t\t\t\tbasic_machine=a29k-amd\n\t\t\t\tbasic_os=udi\n\t\t\t\t;;\n\t\t\tultra3)\n\t\t\t\tbasic_machine=a29k-nyu\n\t\t\t\tbasic_os=sym1\n\t\t\t\t;;\n\t\t\tv810 | necv810)\n\t\t\t\tbasic_machine=v810-nec\n\t\t\t\tbasic_os=none\n\t\t\t\t;;\n\t\t\tvaxv)\n\t\t\t\tbasic_machine=vax-dec\n\t\t\t\tbasic_os=sysv\n\t\t\t\t;;\n\t\t\tvms)\n\t\t\t\tbasic_machine=vax-dec\n\t\t\t\tbasic_os=vms\n\t\t\t\t;;\n\t\t\tvsta)\n\t\t\t\tbasic_machine=i386-pc\n\t\t\t\tbasic_os=vsta\n\t\t\t\t;;\n\t\t\tvxworks960)\n\t\t\t\tbasic_machine=i960-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\tvxworks68)\n\t\t\t\tbasic_machine=m68k-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\tvxworks29k)\n\t\t\t\tbasic_machine=a29k-wrs\n\t\t\t\tbasic_os=vxworks\n\t\t\t\t;;\n\t\t\txbox)\n\t\t\t\tbasic_machine=i686-pc\n\t\t\t\tbasic_os=mingw32\n\t\t\t\t;;\n\t\t\tymp)\n\t\t\t\tbasic_machine=ymp-cray\n\t\t\t\tbasic_os=unicos\n\t\t\t\t;;\n\t\t\t*)\n\t\t\t\tbasic_machine=$1\n\t\t\t\tbasic_os=\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\n# Decode 1-component or ad-hoc basic machines\ncase $basic_machine in\n\t# Here we handle the default manufacturer of certain CPU types.  It is in\n\t# some cases the only manufacturer, in others, it is the most popular.\n\tw89k)\n\t\tcpu=hppa1.1\n\t\tvendor=winbond\n\t\t;;\n\top50n)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\t;;\n\top60c)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\t;;\n\tibm*)\n\t\tcpu=i370\n\t\tvendor=ibm\n\t\t;;\n\torion105)\n\t\tcpu=clipper\n\t\tvendor=highlevel\n\t\t;;\n\tmac | mpw | mac-mpw)\n\t\tcpu=m68k\n\t\tvendor=apple\n\t\t;;\n\tpmac | pmac-mpw)\n\t\tcpu=powerpc\n\t\tvendor=apple\n\t\t;;\n\n\t# Recognize the various machine names and aliases which stand\n\t# for a CPU type and a company and sometimes even an OS.\n\t3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)\n\t\tcpu=m68000\n\t\tvendor=att\n\t\t;;\n\t3b*)\n\t\tcpu=we32k\n\t\tvendor=att\n\t\t;;\n\tbluegene*)\n\t\tcpu=powerpc\n\t\tvendor=ibm\n\t\tbasic_os=cnk\n\t\t;;\n\tdecsystem10* | dec10*)\n\t\tcpu=pdp10\n\t\tvendor=dec\n\t\tbasic_os=tops10\n\t\t;;\n\tdecsystem20* | dec20*)\n\t\tcpu=pdp10\n\t\tvendor=dec\n\t\tbasic_os=tops20\n\t\t;;\n\tdelta | 3300 | motorola-3300 | motorola-delta \\\n\t      | 3300-motorola | delta-motorola)\n\t\tcpu=m68k\n\t\tvendor=motorola\n\t\t;;\n\tdpx2*)\n\t\tcpu=m68k\n\t\tvendor=bull\n\t\tbasic_os=sysv3\n\t\t;;\n\tencore | umax | mmax)\n\t\tcpu=ns32k\n\t\tvendor=encore\n\t\t;;\n\telxsi)\n\t\tcpu=elxsi\n\t\tvendor=elxsi\n\t\tbasic_os=${basic_os:-bsd}\n\t\t;;\n\tfx2800)\n\t\tcpu=i860\n\t\tvendor=alliant\n\t\t;;\n\tgenix)\n\t\tcpu=ns32k\n\t\tvendor=ns\n\t\t;;\n\th3050r* | hiux*)\n\t\tcpu=hppa1.1\n\t\tvendor=hitachi\n\t\tbasic_os=hiuxwe2\n\t\t;;\n\thp3k9[0-9][0-9] | hp9[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\thp9k2[0-9][0-9] | hp9k31[0-9])\n\t\tcpu=m68000\n\t\tvendor=hp\n\t\t;;\n\thp9k3[2-9][0-9])\n\t\tcpu=m68k\n\t\tvendor=hp\n\t\t;;\n\thp9k6[0-9][0-9] | hp6[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\thp9k7[0-79][0-9] | hp7[0-79][0-9])\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k78[0-9] | hp78[0-9])\n\t\t# FIXME: really hppa2.0-hp\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)\n\t\t# FIXME: really hppa2.0-hp\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[0-9][13679] | hp8[0-9][13679])\n\t\tcpu=hppa1.1\n\t\tvendor=hp\n\t\t;;\n\thp9k8[0-9][0-9] | hp8[0-9][0-9])\n\t\tcpu=hppa1.0\n\t\tvendor=hp\n\t\t;;\n\ti*86v32)\n\t\tcpu=`echo \"$1\" | sed -e 's/86.*/86/'`\n\t\tvendor=pc\n\t\tbasic_os=sysv32\n\t\t;;\n\ti*86v4*)\n\t\tcpu=`echo \"$1\" | sed -e 's/86.*/86/'`\n\t\tvendor=pc\n\t\tbasic_os=sysv4\n\t\t;;\n\ti*86v)\n\t\tcpu=`echo \"$1\" | sed -e 's/86.*/86/'`\n\t\tvendor=pc\n\t\tbasic_os=sysv\n\t\t;;\n\ti*86sol2)\n\t\tcpu=`echo \"$1\" | sed -e 's/86.*/86/'`\n\t\tvendor=pc\n\t\tbasic_os=solaris2\n\t\t;;\n\tj90 | j90-cray)\n\t\tcpu=j90\n\t\tvendor=cray\n\t\tbasic_os=${basic_os:-unicos}\n\t\t;;\n\tiris | iris4d)\n\t\tcpu=mips\n\t\tvendor=sgi\n\t\tcase $basic_os in\n\t\t    irix*)\n\t\t\t;;\n\t\t    *)\n\t\t\tbasic_os=irix4\n\t\t\t;;\n\t\tesac\n\t\t;;\n\tminiframe)\n\t\tcpu=m68000\n\t\tvendor=convergent\n\t\t;;\n\t*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)\n\t\tcpu=m68k\n\t\tvendor=atari\n\t\tbasic_os=mint\n\t\t;;\n\tnews-3600 | risc-news)\n\t\tcpu=mips\n\t\tvendor=sony\n\t\tbasic_os=newsos\n\t\t;;\n\tnext | m*-next)\n\t\tcpu=m68k\n\t\tvendor=next\n\t\tcase $basic_os in\n\t\t    openstep*)\n\t\t        ;;\n\t\t    nextstep*)\n\t\t\t;;\n\t\t    ns2*)\n\t\t      basic_os=nextstep2\n\t\t\t;;\n\t\t    *)\n\t\t      basic_os=nextstep3\n\t\t\t;;\n\t\tesac\n\t\t;;\n\tnp1)\n\t\tcpu=np1\n\t\tvendor=gould\n\t\t;;\n\top50n-* | op60c-*)\n\t\tcpu=hppa1.1\n\t\tvendor=oki\n\t\tbasic_os=proelf\n\t\t;;\n\tpa-hitachi)\n\t\tcpu=hppa1.1\n\t\tvendor=hitachi\n\t\tbasic_os=hiuxwe2\n\t\t;;\n\tpbd)\n\t\tcpu=sparc\n\t\tvendor=tti\n\t\t;;\n\tpbb)\n\t\tcpu=m68k\n\t\tvendor=tti\n\t\t;;\n\tpc532)\n\t\tcpu=ns32k\n\t\tvendor=pc532\n\t\t;;\n\tpn)\n\t\tcpu=pn\n\t\tvendor=gould\n\t\t;;\n\tpower)\n\t\tcpu=power\n\t\tvendor=ibm\n\t\t;;\n\tps2)\n\t\tcpu=i386\n\t\tvendor=ibm\n\t\t;;\n\trm[46]00)\n\t\tcpu=mips\n\t\tvendor=siemens\n\t\t;;\n\trtpc | rtpc-*)\n\t\tcpu=romp\n\t\tvendor=ibm\n\t\t;;\n\tsde)\n\t\tcpu=mipsisa32\n\t\tvendor=sde\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tsimso-wrs)\n\t\tcpu=sparclite\n\t\tvendor=wrs\n\t\tbasic_os=vxworks\n\t\t;;\n\ttower | tower-32)\n\t\tcpu=m68k\n\t\tvendor=ncr\n\t\t;;\n\tvpp*|vx|vx-*)\n\t\tcpu=f301\n\t\tvendor=fujitsu\n\t\t;;\n\tw65)\n\t\tcpu=w65\n\t\tvendor=wdc\n\t\t;;\n\tw89k-*)\n\t\tcpu=hppa1.1\n\t\tvendor=winbond\n\t\tbasic_os=proelf\n\t\t;;\n\tnone)\n\t\tcpu=none\n\t\tvendor=none\n\t\t;;\n\tleon|leon[3-9])\n\t\tcpu=sparc\n\t\tvendor=$basic_machine\n\t\t;;\n\tleon-*|leon[3-9]-*)\n\t\tcpu=sparc\n\t\tvendor=`echo \"$basic_machine\" | sed 's/-.*//'`\n\t\t;;\n\n\t*-*)\n\t\t# shellcheck disable=SC2162\n\t\tsaved_IFS=$IFS\n\t\tIFS=\"-\" read cpu vendor <<EOF\n$basic_machine\nEOF\n\t\tIFS=$saved_IFS\n\t\t;;\n\t# We use `pc' rather than `unknown'\n\t# because (1) that's what they normally are, and\n\t# (2) the word \"unknown\" tends to confuse beginning users.\n\ti*86 | x86_64)\n\t\tcpu=$basic_machine\n\t\tvendor=pc\n\t\t;;\n\t# These rules are duplicated from below for sake of the special case above;\n\t# i.e. things that normalized to x86 arches should also default to \"pc\"\n\tpc98)\n\t\tcpu=i386\n\t\tvendor=pc\n\t\t;;\n\tx64 | amd64)\n\t\tcpu=x86_64\n\t\tvendor=pc\n\t\t;;\n\t# Recognize the basic CPU types without company name.\n\t*)\n\t\tcpu=$basic_machine\n\t\tvendor=unknown\n\t\t;;\nesac\n\nunset -v basic_machine\n\n# Decode basic machines in the full and proper CPU-Company form.\ncase $cpu-$vendor in\n\t# Here we handle the default manufacturer of certain CPU types in canonical form. It is in\n\t# some cases the only manufacturer, in others, it is the most popular.\n\tcraynv-unknown)\n\t\tvendor=cray\n\t\tbasic_os=${basic_os:-unicosmp}\n\t\t;;\n\tc90-unknown | c90-cray)\n\t\tvendor=cray\n\t\tbasic_os=${Basic_os:-unicos}\n\t\t;;\n\tfx80-unknown)\n\t\tvendor=alliant\n\t\t;;\n\tromp-unknown)\n\t\tvendor=ibm\n\t\t;;\n\tmmix-unknown)\n\t\tvendor=knuth\n\t\t;;\n\tmicroblaze-unknown | microblazeel-unknown)\n\t\tvendor=xilinx\n\t\t;;\n\trs6000-unknown)\n\t\tvendor=ibm\n\t\t;;\n\tvax-unknown)\n\t\tvendor=dec\n\t\t;;\n\tpdp11-unknown)\n\t\tvendor=dec\n\t\t;;\n\twe32k-unknown)\n\t\tvendor=att\n\t\t;;\n\tcydra-unknown)\n\t\tvendor=cydrome\n\t\t;;\n\ti370-ibm*)\n\t\tvendor=ibm\n\t\t;;\n\torion-unknown)\n\t\tvendor=highlevel\n\t\t;;\n\txps-unknown | xps100-unknown)\n\t\tcpu=xps100\n\t\tvendor=honeywell\n\t\t;;\n\n\t# Here we normalize CPU types with a missing or matching vendor\n\tdpx20-unknown | dpx20-bull)\n\t\tcpu=rs6000\n\t\tvendor=bull\n\t\tbasic_os=${basic_os:-bosx}\n\t\t;;\n\n\t# Here we normalize CPU types irrespective of the vendor\n\tamd64-*)\n\t\tcpu=x86_64\n\t\t;;\n\tblackfin-*)\n\t\tcpu=bfin\n\t\tbasic_os=linux\n\t\t;;\n\tc54x-*)\n\t\tcpu=tic54x\n\t\t;;\n\tc55x-*)\n\t\tcpu=tic55x\n\t\t;;\n\tc6x-*)\n\t\tcpu=tic6x\n\t\t;;\n\te500v[12]-*)\n\t\tcpu=powerpc\n\t\tbasic_os=${basic_os}\"spe\"\n\t\t;;\n\tmips3*-*)\n\t\tcpu=mips64\n\t\t;;\n\tms1-*)\n\t\tcpu=mt\n\t\t;;\n\tm68knommu-*)\n\t\tcpu=m68k\n\t\tbasic_os=linux\n\t\t;;\n\tm9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)\n\t\tcpu=s12z\n\t\t;;\n\topenrisc-*)\n\t\tcpu=or32\n\t\t;;\n\tparisc-*)\n\t\tcpu=hppa\n\t\tbasic_os=linux\n\t\t;;\n\tpentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)\n\t\tcpu=i586\n\t\t;;\n\tpentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)\n\t\tcpu=i686\n\t\t;;\n\tpentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)\n\t\tcpu=i686\n\t\t;;\n\tpentium4-*)\n\t\tcpu=i786\n\t\t;;\n\tpc98-*)\n\t\tcpu=i386\n\t\t;;\n\tppc-* | ppcbe-*)\n\t\tcpu=powerpc\n\t\t;;\n\tppcle-* | powerpclittle-*)\n\t\tcpu=powerpcle\n\t\t;;\n\tppc64-*)\n\t\tcpu=powerpc64\n\t\t;;\n\tppc64le-* | powerpc64little-*)\n\t\tcpu=powerpc64le\n\t\t;;\n\tsb1-*)\n\t\tcpu=mipsisa64sb1\n\t\t;;\n\tsb1el-*)\n\t\tcpu=mipsisa64sb1el\n\t\t;;\n\tsh5e[lb]-*)\n\t\tcpu=`echo \"$cpu\" | sed 's/^\\(sh.\\)e\\(.\\)$/\\1\\2e/'`\n\t\t;;\n\tspur-*)\n\t\tcpu=spur\n\t\t;;\n\tstrongarm-* | thumb-*)\n\t\tcpu=arm\n\t\t;;\n\ttx39-*)\n\t\tcpu=mipstx39\n\t\t;;\n\ttx39el-*)\n\t\tcpu=mipstx39el\n\t\t;;\n\tx64-*)\n\t\tcpu=x86_64\n\t\t;;\n\txscale-* | xscalee[bl]-*)\n\t\tcpu=`echo \"$cpu\" | sed 's/^xscale/arm/'`\n\t\t;;\n\tarm64-*)\n\t\tcpu=aarch64\n\t\t;;\n\n\t# Recognize the canonical CPU Types that limit and/or modify the\n\t# company names they are paired with.\n\tcr16-*)\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tcrisv32-* | etraxfs*-*)\n\t\tcpu=crisv32\n\t\tvendor=axis\n\t\t;;\n\tcris-* | etrax*-*)\n\t\tcpu=cris\n\t\tvendor=axis\n\t\t;;\n\tcrx-*)\n\t\tbasic_os=${basic_os:-elf}\n\t\t;;\n\tneo-tandem)\n\t\tcpu=neo\n\t\tvendor=tandem\n\t\t;;\n\tnse-tandem)\n\t\tcpu=nse\n\t\tvendor=tandem\n\t\t;;\n\tnsr-tandem)\n\t\tcpu=nsr\n\t\tvendor=tandem\n\t\t;;\n\tnsv-tandem)\n\t\tcpu=nsv\n\t\tvendor=tandem\n\t\t;;\n\tnsx-tandem)\n\t\tcpu=nsx\n\t\tvendor=tandem\n\t\t;;\n\tmipsallegrexel-sony)\n\t\tcpu=mipsallegrexel\n\t\tvendor=sony\n\t\t;;\n\ttile*-*)\n\t\tbasic_os=${basic_os:-linux-gnu}\n\t\t;;\n\n\t*)\n\t\t# Recognize the canonical CPU types that are allowed with any\n\t\t# company name.\n\t\tcase $cpu in\n\t\t\t1750a | 580 \\\n\t\t\t| a29k \\\n\t\t\t| aarch64 | aarch64_be \\\n\t\t\t| abacus \\\n\t\t\t| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \\\n\t\t\t| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \\\n\t\t\t| alphapca5[67] | alpha64pca5[67] \\\n\t\t\t| am33_2.0 \\\n\t\t\t| amdgcn \\\n\t\t\t| arc | arceb | arc32 | arc64 \\\n\t\t\t| arm | arm[lb]e | arme[lb] | armv* \\\n\t\t\t| avr | avr32 \\\n\t\t\t| asmjs \\\n\t\t\t| ba \\\n\t\t\t| be32 | be64 \\\n\t\t\t| bfin | bpf | bs2000 \\\n\t\t\t| c[123]* | c30 | [cjt]90 | c4x \\\n\t\t\t| c8051 | clipper | craynv | csky | cydra \\\n\t\t\t| d10v | d30v | dlx | dsp16xx \\\n\t\t\t| e2k | elxsi | epiphany \\\n\t\t\t| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \\\n\t\t\t| h8300 | h8500 \\\n\t\t\t| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \\\n\t\t\t| hexagon \\\n\t\t\t| i370 | i*86 | i860 | i960 | ia16 | ia64 \\\n\t\t\t| ip2k | iq2000 \\\n\t\t\t| k1om \\\n\t\t\t| le32 | le64 \\\n\t\t\t| lm32 \\\n\t\t\t| loongarch32 | loongarch64 | loongarchx32 \\\n\t\t\t| m32c | m32r | m32rle \\\n\t\t\t| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \\\n\t\t\t| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \\\n\t\t\t| m88110 | m88k | maxq | mb | mcore | mep | metag \\\n\t\t\t| microblaze | microblazeel \\\n\t\t\t| mips | mipsbe | mipseb | mipsel | mipsle \\\n\t\t\t| mips16 \\\n\t\t\t| mips64 | mips64eb | mips64el \\\n\t\t\t| mips64octeon | mips64octeonel \\\n\t\t\t| mips64orion | mips64orionel \\\n\t\t\t| mips64r5900 | mips64r5900el \\\n\t\t\t| mips64vr | mips64vrel \\\n\t\t\t| mips64vr4100 | mips64vr4100el \\\n\t\t\t| mips64vr4300 | mips64vr4300el \\\n\t\t\t| mips64vr5000 | mips64vr5000el \\\n\t\t\t| mips64vr5900 | mips64vr5900el \\\n\t\t\t| mipsisa32 | mipsisa32el \\\n\t\t\t| mipsisa32r2 | mipsisa32r2el \\\n\t\t\t| mipsisa32r3 | mipsisa32r3el \\\n\t\t\t| mipsisa32r5 | mipsisa32r5el \\\n\t\t\t| mipsisa32r6 | mipsisa32r6el \\\n\t\t\t| mipsisa64 | mipsisa64el \\\n\t\t\t| mipsisa64r2 | mipsisa64r2el \\\n\t\t\t| mipsisa64r3 | mipsisa64r3el \\\n\t\t\t| mipsisa64r5 | mipsisa64r5el \\\n\t\t\t| mipsisa64r6 | mipsisa64r6el \\\n\t\t\t| mipsisa64sb1 | mipsisa64sb1el \\\n\t\t\t| mipsisa64sr71k | mipsisa64sr71kel \\\n\t\t\t| mipsr5900 | mipsr5900el \\\n\t\t\t| mipstx39 | mipstx39el \\\n\t\t\t| mmix \\\n\t\t\t| mn10200 | mn10300 \\\n\t\t\t| moxie \\\n\t\t\t| mt \\\n\t\t\t| msp430 \\\n\t\t\t| nds32 | nds32le | nds32be \\\n\t\t\t| nfp \\\n\t\t\t| nios | nios2 | nios2eb | nios2el \\\n\t\t\t| none | np1 | ns16k | ns32k | nvptx \\\n\t\t\t| open8 \\\n\t\t\t| or1k* \\\n\t\t\t| or32 \\\n\t\t\t| orion \\\n\t\t\t| picochip \\\n\t\t\t| pdp10 | pdp11 | pj | pjl | pn | power \\\n\t\t\t| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \\\n\t\t\t| pru \\\n\t\t\t| pyramid \\\n\t\t\t| riscv | riscv32 | riscv32be | riscv64 | riscv64be \\\n\t\t\t| rl78 | romp | rs6000 | rx \\\n\t\t\t| s390 | s390x \\\n\t\t\t| score \\\n\t\t\t| sh | shl \\\n\t\t\t| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \\\n\t\t\t| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \\\n\t\t\t| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \\\n\t\t\t| sparclite \\\n\t\t\t| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \\\n\t\t\t| spu \\\n\t\t\t| tahoe \\\n\t\t\t| thumbv7* \\\n\t\t\t| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \\\n\t\t\t| tron \\\n\t\t\t| ubicom32 \\\n\t\t\t| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \\\n\t\t\t| vax \\\n\t\t\t| visium \\\n\t\t\t| w65 \\\n\t\t\t| wasm32 | wasm64 \\\n\t\t\t| we32k \\\n\t\t\t| x86 | x86_64 | xc16x | xgate | xps100 \\\n\t\t\t| xstormy16 | xtensa* \\\n\t\t\t| ymp \\\n\t\t\t| z8k | z80)\n\t\t\t\t;;\n\n\t\t\t*)\n\t\t\t\techo Invalid configuration \\`\"$1\"\\': machine \\`\"$cpu-$vendor\"\\' not recognized 1>&2\n\t\t\t\texit 1\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\n# Here we canonicalize certain aliases for manufacturers.\ncase $vendor in\n\tdigital*)\n\t\tvendor=dec\n\t\t;;\n\tcommodore*)\n\t\tvendor=cbm\n\t\t;;\n\t*)\n\t\t;;\nesac\n\n# Decode manufacturer-specific aliases for certain operating systems.\n\nif test x$basic_os != x\nthen\n\n# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just\n# set os.\ncase $basic_os in\n\tgnu/linux*)\n\t\tkernel=linux\n\t\tos=`echo \"$basic_os\" | sed -e 's|gnu/linux|gnu|'`\n\t\t;;\n\tos2-emx)\n\t\tkernel=os2\n\t\tos=`echo \"$basic_os\" | sed -e 's|os2-emx|emx|'`\n\t\t;;\n\tnto-qnx*)\n\t\tkernel=nto\n\t\tos=`echo \"$basic_os\" | sed -e 's|nto-qnx|qnx|'`\n\t\t;;\n\t*-*)\n\t\t# shellcheck disable=SC2162\n\t\tsaved_IFS=$IFS\n\t\tIFS=\"-\" read kernel os <<EOF\n$basic_os\nEOF\n\t\tIFS=$saved_IFS\n\t\t;;\n\t# Default OS when just kernel was specified\n\tnto*)\n\t\tkernel=nto\n\t\tos=`echo \"$basic_os\" | sed -e 's|nto|qnx|'`\n\t\t;;\n\tlinux*)\n\t\tkernel=linux\n\t\tos=`echo \"$basic_os\" | sed -e 's|linux|gnu|'`\n\t\t;;\n\t*)\n\t\tkernel=\n\t\tos=$basic_os\n\t\t;;\nesac\n\n# Now, normalize the OS (knowing we just have one component, it's not a kernel,\n# etc.)\ncase $os in\n\t# First match some system type aliases that might get confused\n\t# with valid system types.\n\t# solaris* is a basic system type, with this one exception.\n\tauroraux)\n\t\tos=auroraux\n\t\t;;\n\tbluegene*)\n\t\tos=cnk\n\t\t;;\n\tsolaris1 | solaris1.*)\n\t\tos=`echo \"$os\" | sed -e 's|solaris1|sunos4|'`\n\t\t;;\n\tsolaris)\n\t\tos=solaris2\n\t\t;;\n\tunixware*)\n\t\tos=sysv4.2uw\n\t\t;;\n\t# es1800 is here to avoid being matched by es* (a different OS)\n\tes1800*)\n\t\tos=ose\n\t\t;;\n\t# Some version numbers need modification\n\tchorusos*)\n\t\tos=chorusos\n\t\t;;\n\tisc)\n\t\tos=isc2.2\n\t\t;;\n\tsco6)\n\t\tos=sco5v6\n\t\t;;\n\tsco5)\n\t\tos=sco3.2v5\n\t\t;;\n\tsco4)\n\t\tos=sco3.2v4\n\t\t;;\n\tsco3.2.[4-9]*)\n\t\tos=`echo \"$os\" | sed -e 's/sco3.2./sco3.2v/'`\n\t\t;;\n\tsco*v* | scout)\n\t\t# Don't match below\n\t\t;;\n\tsco*)\n\t\tos=sco3.2v2\n\t\t;;\n\tpsos*)\n\t\tos=psos\n\t\t;;\n\tqnx*)\n\t\tos=qnx\n\t\t;;\n\thiux*)\n\t\tos=hiuxwe2\n\t\t;;\n\tlynx*178)\n\t\tos=lynxos178\n\t\t;;\n\tlynx*5)\n\t\tos=lynxos5\n\t\t;;\n\tlynxos*)\n\t\t# don't get caught up in next wildcard\n\t\t;;\n\tlynx*)\n\t\tos=lynxos\n\t\t;;\n\tmac[0-9]*)\n\t\tos=`echo \"$os\" | sed -e 's|mac|macos|'`\n\t\t;;\n\topened*)\n\t\tos=openedition\n\t\t;;\n\tos400*)\n\t\tos=os400\n\t\t;;\n\tsunos5*)\n\t\tos=`echo \"$os\" | sed -e 's|sunos5|solaris2|'`\n\t\t;;\n\tsunos6*)\n\t\tos=`echo \"$os\" | sed -e 's|sunos6|solaris3|'`\n\t\t;;\n\twince*)\n\t\tos=wince\n\t\t;;\n\tutek*)\n\t\tos=bsd\n\t\t;;\n\tdynix*)\n\t\tos=bsd\n\t\t;;\n\tacis*)\n\t\tos=aos\n\t\t;;\n\tatheos*)\n\t\tos=atheos\n\t\t;;\n\tsyllable*)\n\t\tos=syllable\n\t\t;;\n\t386bsd)\n\t\tos=bsd\n\t\t;;\n\tctix* | uts*)\n\t\tos=sysv\n\t\t;;\n\tnova*)\n\t\tos=rtmk-nova\n\t\t;;\n\tns2)\n\t\tos=nextstep2\n\t\t;;\n\t# Preserve the version number of sinix5.\n\tsinix5.*)\n\t\tos=`echo \"$os\" | sed -e 's|sinix|sysv|'`\n\t\t;;\n\tsinix*)\n\t\tos=sysv4\n\t\t;;\n\ttpf*)\n\t\tos=tpf\n\t\t;;\n\ttriton*)\n\t\tos=sysv3\n\t\t;;\n\toss*)\n\t\tos=sysv3\n\t\t;;\n\tsvr4*)\n\t\tos=sysv4\n\t\t;;\n\tsvr3)\n\t\tos=sysv3\n\t\t;;\n\tsysvr4)\n\t\tos=sysv4\n\t\t;;\n\tose*)\n\t\tos=ose\n\t\t;;\n\t*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)\n\t\tos=mint\n\t\t;;\n\tdicos*)\n\t\tos=dicos\n\t\t;;\n\tpikeos*)\n\t\t# Until real need of OS specific support for\n\t\t# particular features comes up, bare metal\n\t\t# configurations are quite functional.\n\t\tcase $cpu in\n\t\t    arm*)\n\t\t\tos=eabi\n\t\t\t;;\n\t\t    *)\n\t\t\tos=elf\n\t\t\t;;\n\t\tesac\n\t\t;;\n\t*)\n\t\t# No normalization, but not necessarily accepted, that comes below.\n\t\t;;\nesac\n\nelse\n\n# Here we handle the default operating systems that come with various machines.\n# The value should be what the vendor currently ships out the door with their\n# machine or put another way, the most popular os provided with the machine.\n\n# Note that if you're going to try to match \"-MANUFACTURER\" here (say,\n# \"-sun\"), then you have to tell the case statement up towards the top\n# that MANUFACTURER isn't an operating system.  Otherwise, code above\n# will signal an error saying that MANUFACTURER isn't an operating\n# system, and we'll never get to this point.\n\nkernel=\ncase $cpu-$vendor in\n\tscore-*)\n\t\tos=elf\n\t\t;;\n\tspu-*)\n\t\tos=elf\n\t\t;;\n\t*-acorn)\n\t\tos=riscix1.2\n\t\t;;\n\tarm*-rebel)\n\t\tkernel=linux\n\t\tos=gnu\n\t\t;;\n\tarm*-semi)\n\t\tos=aout\n\t\t;;\n\tc4x-* | tic4x-*)\n\t\tos=coff\n\t\t;;\n\tc8051-*)\n\t\tos=elf\n\t\t;;\n\tclipper-intergraph)\n\t\tos=clix\n\t\t;;\n\thexagon-*)\n\t\tos=elf\n\t\t;;\n\ttic54x-*)\n\t\tos=coff\n\t\t;;\n\ttic55x-*)\n\t\tos=coff\n\t\t;;\n\ttic6x-*)\n\t\tos=coff\n\t\t;;\n\t# This must come before the *-dec entry.\n\tpdp10-*)\n\t\tos=tops20\n\t\t;;\n\tpdp11-*)\n\t\tos=none\n\t\t;;\n\t*-dec | vax-*)\n\t\tos=ultrix4.2\n\t\t;;\n\tm68*-apollo)\n\t\tos=domain\n\t\t;;\n\ti386-sun)\n\t\tos=sunos4.0.2\n\t\t;;\n\tm68000-sun)\n\t\tos=sunos3\n\t\t;;\n\tm68*-cisco)\n\t\tos=aout\n\t\t;;\n\tmep-*)\n\t\tos=elf\n\t\t;;\n\tmips*-cisco)\n\t\tos=elf\n\t\t;;\n\tmips*-*)\n\t\tos=elf\n\t\t;;\n\tor32-*)\n\t\tos=coff\n\t\t;;\n\t*-tti)\t# must be before sparc entry or we get the wrong os.\n\t\tos=sysv3\n\t\t;;\n\tsparc-* | *-sun)\n\t\tos=sunos4.1.1\n\t\t;;\n\tpru-*)\n\t\tos=elf\n\t\t;;\n\t*-be)\n\t\tos=beos\n\t\t;;\n\t*-ibm)\n\t\tos=aix\n\t\t;;\n\t*-knuth)\n\t\tos=mmixware\n\t\t;;\n\t*-wec)\n\t\tos=proelf\n\t\t;;\n\t*-winbond)\n\t\tos=proelf\n\t\t;;\n\t*-oki)\n\t\tos=proelf\n\t\t;;\n\t*-hp)\n\t\tos=hpux\n\t\t;;\n\t*-hitachi)\n\t\tos=hiux\n\t\t;;\n\ti860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)\n\t\tos=sysv\n\t\t;;\n\t*-cbm)\n\t\tos=amigaos\n\t\t;;\n\t*-dg)\n\t\tos=dgux\n\t\t;;\n\t*-dolphin)\n\t\tos=sysv3\n\t\t;;\n\tm68k-ccur)\n\t\tos=rtu\n\t\t;;\n\tm88k-omron*)\n\t\tos=luna\n\t\t;;\n\t*-next)\n\t\tos=nextstep\n\t\t;;\n\t*-sequent)\n\t\tos=ptx\n\t\t;;\n\t*-crds)\n\t\tos=unos\n\t\t;;\n\t*-ns)\n\t\tos=genix\n\t\t;;\n\ti370-*)\n\t\tos=mvs\n\t\t;;\n\t*-gould)\n\t\tos=sysv\n\t\t;;\n\t*-highlevel)\n\t\tos=bsd\n\t\t;;\n\t*-encore)\n\t\tos=bsd\n\t\t;;\n\t*-sgi)\n\t\tos=irix\n\t\t;;\n\t*-siemens)\n\t\tos=sysv4\n\t\t;;\n\t*-masscomp)\n\t\tos=rtu\n\t\t;;\n\tf30[01]-fujitsu | f700-fujitsu)\n\t\tos=uxpv\n\t\t;;\n\t*-rom68k)\n\t\tos=coff\n\t\t;;\n\t*-*bug)\n\t\tos=coff\n\t\t;;\n\t*-apple)\n\t\tos=macos\n\t\t;;\n\t*-atari*)\n\t\tos=mint\n\t\t;;\n\t*-wrs)\n\t\tos=vxworks\n\t\t;;\n\t*)\n\t\tos=none\n\t\t;;\nesac\n\nfi\n\n# Now, validate our (potentially fixed-up) OS.\ncase $os in\n\t# Sometimes we do \"kernel-libc\", so those need to count as OSes.\n\tmusl* | newlib* | relibc* | uclibc*)\n\t\t;;\n\t# Likewise for \"kernel-abi\"\n\teabi* | gnueabi*)\n\t\t;;\n\t# VxWorks passes extra cpu info in the 4th filed.\n\tsimlinux | simwindows | spe)\n\t\t;;\n\t# Now accept the basic system types.\n\t# The portable systems comes first.\n\t# Each alternative MUST end in a * to match a version number.\n\tgnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \\\n\t     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \\\n\t     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \\\n\t     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \\\n\t     | hiux* | abug | nacl* | netware* | windows* \\\n\t     | os9* | macos* | osx* | ios* \\\n\t     | mpw* | magic* | mmixware* | mon960* | lnews* \\\n\t     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \\\n\t     | aos* | aros* | cloudabi* | sortix* | twizzler* \\\n\t     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \\\n\t     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \\\n\t     | mirbsd* | netbsd* | dicos* | openedition* | ose* \\\n\t     | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \\\n\t     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \\\n\t     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \\\n\t     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \\\n\t     | udi* | lites* | ieee* | go32* | aux* | hcos* \\\n\t     | chorusrdb* | cegcc* | glidix* | serenity* \\\n\t     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \\\n\t     | midipix* | mingw32* | mingw64* | mint* \\\n\t     | uxpv* | beos* | mpeix* | udk* | moxiebox* \\\n\t     | interix* | uwin* | mks* | rhapsody* | darwin* \\\n\t     | openstep* | oskit* | conix* | pw32* | nonstopux* \\\n\t     | storm-chaos* | tops10* | tenex* | tops20* | its* \\\n\t     | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \\\n\t     | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \\\n\t     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \\\n\t     | skyos* | haiku* | rdos* | toppers* | drops* | es* \\\n\t     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \\\n\t     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \\\n\t     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*)\n\t\t;;\n\t# This one is extra strict with allowed versions\n\tsco3.2v2 | sco3.2v[4-9]* | sco5v6*)\n\t\t# Don't forget version if it is 3.2v4 or newer.\n\t\t;;\n\tnone)\n\t\t;;\n\t*)\n\t\techo Invalid configuration \\`\"$1\"\\': OS \\`\"$os\"\\' not recognized 1>&2\n\t\texit 1\n\t\t;;\nesac\n\n# As a final step for OS-related things, validate the OS-kernel combination\n# (given a valid OS), if there is a kernel.\ncase $kernel-$os in\n\tlinux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \\\n\t\t   | linux-musl* | linux-relibc* | linux-uclibc* )\n\t\t;;\n\tuclinux-uclibc* )\n\t\t;;\n\t-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )\n\t\t# These are just libc implementations, not actual OSes, and thus\n\t\t# require a kernel.\n\t\techo \"Invalid configuration \\`$1': libc \\`$os' needs explicit kernel.\" 1>&2\n\t\texit 1\n\t\t;;\n\tkfreebsd*-gnu* | kopensolaris*-gnu*)\n\t\t;;\n\tvxworks-simlinux | vxworks-simwindows | vxworks-spe)\n\t\t;;\n\tnto-qnx*)\n\t\t;;\n\tos2-emx)\n\t\t;;\n\t*-eabi* | *-gnueabi*)\n\t\t;;\n\t-*)\n\t\t# Blank kernel with real OS is always fine.\n\t\t;;\n\t*-*)\n\t\techo \"Invalid configuration \\`$1': Kernel \\`$kernel' not known to work with OS \\`$os'.\" 1>&2\n\t\texit 1\n\t\t;;\nesac\n\n# Here we handle the case where we know the os, and the CPU type, but not the\n# manufacturer.  We pick the logical manufacturer.\ncase $vendor in\n\tunknown)\n\t\tcase $cpu-$os in\n\t\t\t*-riscix*)\n\t\t\t\tvendor=acorn\n\t\t\t\t;;\n\t\t\t*-sunos*)\n\t\t\t\tvendor=sun\n\t\t\t\t;;\n\t\t\t*-cnk* | *-aix*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-beos*)\n\t\t\t\tvendor=be\n\t\t\t\t;;\n\t\t\t*-hpux*)\n\t\t\t\tvendor=hp\n\t\t\t\t;;\n\t\t\t*-mpeix*)\n\t\t\t\tvendor=hp\n\t\t\t\t;;\n\t\t\t*-hiux*)\n\t\t\t\tvendor=hitachi\n\t\t\t\t;;\n\t\t\t*-unos*)\n\t\t\t\tvendor=crds\n\t\t\t\t;;\n\t\t\t*-dgux*)\n\t\t\t\tvendor=dg\n\t\t\t\t;;\n\t\t\t*-luna*)\n\t\t\t\tvendor=omron\n\t\t\t\t;;\n\t\t\t*-genix*)\n\t\t\t\tvendor=ns\n\t\t\t\t;;\n\t\t\t*-clix*)\n\t\t\t\tvendor=intergraph\n\t\t\t\t;;\n\t\t\t*-mvs* | *-opened*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-os400*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\ts390-* | s390x-*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-ptx*)\n\t\t\t\tvendor=sequent\n\t\t\t\t;;\n\t\t\t*-tpf*)\n\t\t\t\tvendor=ibm\n\t\t\t\t;;\n\t\t\t*-vxsim* | *-vxworks* | *-windiss*)\n\t\t\t\tvendor=wrs\n\t\t\t\t;;\n\t\t\t*-aux*)\n\t\t\t\tvendor=apple\n\t\t\t\t;;\n\t\t\t*-hms*)\n\t\t\t\tvendor=hitachi\n\t\t\t\t;;\n\t\t\t*-mpw* | *-macos*)\n\t\t\t\tvendor=apple\n\t\t\t\t;;\n\t\t\t*-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)\n\t\t\t\tvendor=atari\n\t\t\t\t;;\n\t\t\t*-vos*)\n\t\t\t\tvendor=stratus\n\t\t\t\t;;\n\t\tesac\n\t\t;;\nesac\n\necho \"$cpu-$vendor-${kernel:+$kernel-}$os\"\nexit\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"timestamp='\"\n# time-stamp-format: \"%:y-%02m-%02d\"\n# time-stamp-end: \"'\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/depcomp",
    "content": "#! /bin/sh\n# depcomp - compile a program generating dependencies as side-effects\n\nscriptversion=2018-03-07.03; # UTC\n\n# Copyright (C) 1999-2020 Free Software Foundation, Inc.\n\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2, or (at your option)\n# any later version.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that program.\n\n# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.\n\ncase $1 in\n  '')\n    echo \"$0: No command.  Try '$0 --help' for more information.\" 1>&2\n    exit 1;\n    ;;\n  -h | --h*)\n    cat <<\\EOF\nUsage: depcomp [--help] [--version] PROGRAM [ARGS]\n\nRun PROGRAMS ARGS to compile a file, generating dependencies\nas side-effects.\n\nEnvironment variables:\n  depmode     Dependency tracking mode.\n  source      Source file read by 'PROGRAMS ARGS'.\n  object      Object file output by 'PROGRAMS ARGS'.\n  DEPDIR      directory where to store dependencies.\n  depfile     Dependency file to output.\n  tmpdepfile  Temporary file to use when outputting dependencies.\n  libtool     Whether libtool is used (yes/no).\n\nReport bugs to <bug-automake@gnu.org>.\nEOF\n    exit $?\n    ;;\n  -v | --v*)\n    echo \"depcomp $scriptversion\"\n    exit $?\n    ;;\nesac\n\n# Get the directory component of the given path, and save it in the\n# global variables '$dir'.  Note that this directory component will\n# be either empty or ending with a '/' character.  This is deliberate.\nset_dir_from ()\n{\n  case $1 in\n    */*) dir=`echo \"$1\" | sed -e 's|/[^/]*$|/|'`;;\n      *) dir=;;\n  esac\n}\n\n# Get the suffix-stripped basename of the given path, and save it the\n# global variable '$base'.\nset_base_from ()\n{\n  base=`echo \"$1\" | sed -e 's|^.*/||' -e 's/\\.[^.]*$//'`\n}\n\n# If no dependency file was actually created by the compiler invocation,\n# we still have to create a dummy depfile, to avoid errors with the\n# Makefile \"include basename.Plo\" scheme.\nmake_dummy_depfile ()\n{\n  echo \"#dummy\" > \"$depfile\"\n}\n\n# Factor out some common post-processing of the generated depfile.\n# Requires the auxiliary global variable '$tmpdepfile' to be set.\naix_post_process_depfile ()\n{\n  # If the compiler actually managed to produce a dependency file,\n  # post-process it.\n  if test -f \"$tmpdepfile\"; then\n    # Each line is of the form 'foo.o: dependency.h'.\n    # Do two passes, one to just change these to\n    #   $object: dependency.h\n    # and one to simply output\n    #   dependency.h:\n    # which is needed to avoid the deleted-header problem.\n    { sed -e \"s,^.*\\.[$lower]*:,$object:,\" < \"$tmpdepfile\"\n      sed -e \"s,^.*\\.[$lower]*:[$tab ]*,,\" -e 's,$,:,' < \"$tmpdepfile\"\n    } > \"$depfile\"\n    rm -f \"$tmpdepfile\"\n  else\n    make_dummy_depfile\n  fi\n}\n\n# A tabulation character.\ntab='\t'\n# A newline character.\nnl='\n'\n# Character ranges might be problematic outside the C locale.\n# These definitions help.\nupper=ABCDEFGHIJKLMNOPQRSTUVWXYZ\nlower=abcdefghijklmnopqrstuvwxyz\ndigits=0123456789\nalpha=${upper}${lower}\n\nif test -z \"$depmode\" || test -z \"$source\" || test -z \"$object\"; then\n  echo \"depcomp: Variables source, object and depmode must be set\" 1>&2\n  exit 1\nfi\n\n# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.\ndepfile=${depfile-`echo \"$object\" |\n  sed 's|[^\\\\/]*$|'${DEPDIR-.deps}'/&|;s|\\.\\([^.]*\\)$|.P\\1|;s|Pobj$|Po|'`}\ntmpdepfile=${tmpdepfile-`echo \"$depfile\" | sed 's/\\.\\([^.]*\\)$/.T\\1/'`}\n\nrm -f \"$tmpdepfile\"\n\n# Avoid interferences from the environment.\ngccflag= dashmflag=\n\n# Some modes work just like other modes, but use different flags.  We\n# parameterize here, but still list the modes in the big case below,\n# to make depend.m4 easier to write.  Note that we *cannot* use a case\n# here, because this file can only contain one case statement.\nif test \"$depmode\" = hp; then\n  # HP compiler uses -M and no extra arg.\n  gccflag=-M\n  depmode=gcc\nfi\n\nif test \"$depmode\" = dashXmstdout; then\n  # This is just like dashmstdout with a different argument.\n  dashmflag=-xM\n  depmode=dashmstdout\nfi\n\ncygpath_u=\"cygpath -u -f -\"\nif test \"$depmode\" = msvcmsys; then\n  # This is just like msvisualcpp but w/o cygpath translation.\n  # Just convert the backslash-escaped backslashes to single forward\n  # slashes to satisfy depend.m4\n  cygpath_u='sed s,\\\\\\\\,/,g'\n  depmode=msvisualcpp\nfi\n\nif test \"$depmode\" = msvc7msys; then\n  # This is just like msvc7 but w/o cygpath translation.\n  # Just convert the backslash-escaped backslashes to single forward\n  # slashes to satisfy depend.m4\n  cygpath_u='sed s,\\\\\\\\,/,g'\n  depmode=msvc7\nfi\n\nif test \"$depmode\" = xlc; then\n  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.\n  gccflag=-qmakedep=gcc,-MF\n  depmode=gcc\nfi\n\ncase \"$depmode\" in\ngcc3)\n## gcc 3 implements dependency tracking that does exactly what\n## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like\n## it if -MD -MP comes after the -MF stuff.  Hmm.\n## Unfortunately, FreeBSD c89 acceptance of flags depends upon\n## the command line argument order; so add the flags where they\n## appear in depend2.am.  Note that the slowdown incurred here\n## affects only configure: in makefiles, %FASTDEP% shortcuts this.\n  for arg\n  do\n    case $arg in\n    -c) set fnord \"$@\" -MT \"$object\" -MD -MP -MF \"$tmpdepfile\" \"$arg\" ;;\n    *)  set fnord \"$@\" \"$arg\" ;;\n    esac\n    shift # fnord\n    shift # $arg\n  done\n  \"$@\"\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  mv \"$tmpdepfile\" \"$depfile\"\n  ;;\n\ngcc)\n## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.\n## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.\n## (see the conditional assignment to $gccflag above).\n## There are various ways to get dependency output from gcc.  Here's\n## why we pick this rather obscure method:\n## - Don't want to use -MD because we'd like the dependencies to end\n##   up in a subdir.  Having to rename by hand is ugly.\n##   (We might end up doing this anyway to support other compilers.)\n## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like\n##   -MM, not -M (despite what the docs say).  Also, it might not be\n##   supported by the other compilers which use the 'gcc' depmode.\n## - Using -M directly means running the compiler twice (even worse\n##   than renaming).\n  if test -z \"$gccflag\"; then\n    gccflag=-MD,\n  fi\n  \"$@\" -Wp,\"$gccflag$tmpdepfile\"\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  rm -f \"$depfile\"\n  echo \"$object : \\\\\" > \"$depfile\"\n  # The second -e expression handles DOS-style file names with drive\n  # letters.\n  sed -e 's/^[^:]*: / /' \\\n      -e 's/^['$alpha']:\\/[^:]*: / /' < \"$tmpdepfile\" >> \"$depfile\"\n## This next piece of magic avoids the \"deleted header file\" problem.\n## The problem is that when a header file which appears in a .P file\n## is deleted, the dependency causes make to die (because there is\n## typically no way to rebuild the header).  We avoid this by adding\n## dummy dependencies for each header file.  Too bad gcc doesn't do\n## this for us directly.\n## Some versions of gcc put a space before the ':'.  On the theory\n## that the space means something, we add a space to the output as\n## well.  hp depmode also adds that space, but also prefixes the VPATH\n## to the object.  Take care to not repeat it in the output.\n## Some versions of the HPUX 10.20 sed can't process this invocation\n## correctly.  Breaking it into two sed invocations is a workaround.\n  tr ' ' \"$nl\" < \"$tmpdepfile\" \\\n    | sed -e 's/^\\\\$//' -e '/^$/d' -e \"s|.*$object$||\" -e '/:$/d' \\\n    | sed -e 's/$/ :/' >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\nhp)\n  # This case exists only to let depend.m4 do its work.  It works by\n  # looking at the text of this script.  This case will never be run,\n  # since it is checked for above.\n  exit 1\n  ;;\n\nsgi)\n  if test \"$libtool\" = yes; then\n    \"$@\" \"-Wp,-MDupdate,$tmpdepfile\"\n  else\n    \"$@\" -MDupdate \"$tmpdepfile\"\n  fi\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  rm -f \"$depfile\"\n\n  if test -f \"$tmpdepfile\"; then  # yes, the sourcefile depend on other files\n    echo \"$object : \\\\\" > \"$depfile\"\n    # Clip off the initial element (the dependent).  Don't try to be\n    # clever and replace this with sed code, as IRIX sed won't handle\n    # lines with more than a fixed number of characters (4096 in\n    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;\n    # the IRIX cc adds comments like '#:fec' to the end of the\n    # dependency line.\n    tr ' ' \"$nl\" < \"$tmpdepfile\" \\\n      | sed -e 's/^.*\\.o://' -e 's/#.*$//' -e '/^$/ d' \\\n      | tr \"$nl\" ' ' >> \"$depfile\"\n    echo >> \"$depfile\"\n    # The second pass generates a dummy entry for each header file.\n    tr ' ' \"$nl\" < \"$tmpdepfile\" \\\n      | sed -e 's/^.*\\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \\\n      >> \"$depfile\"\n  else\n    make_dummy_depfile\n  fi\n  rm -f \"$tmpdepfile\"\n  ;;\n\nxlc)\n  # This case exists only to let depend.m4 do its work.  It works by\n  # looking at the text of this script.  This case will never be run,\n  # since it is checked for above.\n  exit 1\n  ;;\n\naix)\n  # The C for AIX Compiler uses -M and outputs the dependencies\n  # in a .u file.  In older versions, this file always lives in the\n  # current directory.  Also, the AIX compiler puts '$object:' at the\n  # start of each line; $object doesn't have directory information.\n  # Version 6 uses the directory in both cases.\n  set_dir_from \"$object\"\n  set_base_from \"$object\"\n  if test \"$libtool\" = yes; then\n    tmpdepfile1=$dir$base.u\n    tmpdepfile2=$base.u\n    tmpdepfile3=$dir.libs/$base.u\n    \"$@\" -Wc,-M\n  else\n    tmpdepfile1=$dir$base.u\n    tmpdepfile2=$dir$base.u\n    tmpdepfile3=$dir$base.u\n    \"$@\" -M\n  fi\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile1\" \"$tmpdepfile2\" \"$tmpdepfile3\"\n    exit $stat\n  fi\n\n  for tmpdepfile in \"$tmpdepfile1\" \"$tmpdepfile2\" \"$tmpdepfile3\"\n  do\n    test -f \"$tmpdepfile\" && break\n  done\n  aix_post_process_depfile\n  ;;\n\ntcc)\n  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26\n  # FIXME: That version still under development at the moment of writing.\n  #        Make that this statement remains true also for stable, released\n  #        versions.\n  # It will wrap lines (doesn't matter whether long or short) with a\n  # trailing '\\', as in:\n  #\n  #   foo.o : \\\n  #    foo.c \\\n  #    foo.h \\\n  #\n  # It will put a trailing '\\' even on the last line, and will use leading\n  # spaces rather than leading tabs (at least since its commit 0394caf7\n  # \"Emit spaces for -MD\").\n  \"$@\" -MD -MF \"$tmpdepfile\"\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  rm -f \"$depfile\"\n  # Each non-empty line is of the form 'foo.o : \\' or ' dep.h \\'.\n  # We have to change lines of the first kind to '$object: \\'.\n  sed -e \"s|.*:|$object :|\" < \"$tmpdepfile\" > \"$depfile\"\n  # And for each line of the second kind, we have to emit a 'dep.h:'\n  # dummy dependency, to avoid the deleted-header problem.\n  sed -n -e 's|^  *\\(.*\\) *\\\\$|\\1:|p' < \"$tmpdepfile\" >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\n## The order of this option in the case statement is important, since the\n## shell code in configure will try each of these formats in the order\n## listed in this file.  A plain '-MD' option would be understood by many\n## compilers, so we must ensure this comes after the gcc and icc options.\npgcc)\n  # Portland's C compiler understands '-MD'.\n  # Will always output deps to 'file.d' where file is the root name of the\n  # source file under compilation, even if file resides in a subdirectory.\n  # The object file name does not affect the name of the '.d' file.\n  # pgcc 10.2 will output\n  #    foo.o: sub/foo.c sub/foo.h\n  # and will wrap long lines using '\\' :\n  #    foo.o: sub/foo.c ... \\\n  #     sub/foo.h ... \\\n  #     ...\n  set_dir_from \"$object\"\n  # Use the source, not the object, to determine the base name, since\n  # that's sadly what pgcc will do too.\n  set_base_from \"$source\"\n  tmpdepfile=$base.d\n\n  # For projects that build the same source file twice into different object\n  # files, the pgcc approach of using the *source* file root name can cause\n  # problems in parallel builds.  Use a locking strategy to avoid stomping on\n  # the same $tmpdepfile.\n  lockdir=$base.d-lock\n  trap \"\n    echo '$0: caught signal, cleaning up...' >&2\n    rmdir '$lockdir'\n    exit 1\n  \" 1 2 13 15\n  numtries=100\n  i=$numtries\n  while test $i -gt 0; do\n    # mkdir is a portable test-and-set.\n    if mkdir \"$lockdir\" 2>/dev/null; then\n      # This process acquired the lock.\n      \"$@\" -MD\n      stat=$?\n      # Release the lock.\n      rmdir \"$lockdir\"\n      break\n    else\n      # If the lock is being held by a different process, wait\n      # until the winning process is done or we timeout.\n      while test -d \"$lockdir\" && test $i -gt 0; do\n        sleep 1\n        i=`expr $i - 1`\n      done\n    fi\n    i=`expr $i - 1`\n  done\n  trap - 1 2 13 15\n  if test $i -le 0; then\n    echo \"$0: failed to acquire lock after $numtries attempts\" >&2\n    echo \"$0: check lockdir '$lockdir'\" >&2\n    exit 1\n  fi\n\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  rm -f \"$depfile\"\n  # Each line is of the form `foo.o: dependent.h',\n  # or `foo.o: dep1.h dep2.h \\', or ` dep3.h dep4.h \\'.\n  # Do two passes, one to just change these to\n  # `$object: dependent.h' and one to simply `dependent.h:'.\n  sed \"s,^[^:]*:,$object :,\" < \"$tmpdepfile\" > \"$depfile\"\n  # Some versions of the HPUX 10.20 sed can't process this invocation\n  # correctly.  Breaking it into two sed invocations is a workaround.\n  sed 's,^[^:]*: \\(.*\\)$,\\1,;s/^\\\\$//;/^$/d;/:$/d' < \"$tmpdepfile\" \\\n    | sed -e 's/$/ :/' >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\nhp2)\n  # The \"hp\" stanza above does not work with aCC (C++) and HP's ia64\n  # compilers, which have integrated preprocessors.  The correct option\n  # to use with these is +Maked; it writes dependencies to a file named\n  # 'foo.d', which lands next to the object file, wherever that\n  # happens to be.\n  # Much of this is similar to the tru64 case; see comments there.\n  set_dir_from  \"$object\"\n  set_base_from \"$object\"\n  if test \"$libtool\" = yes; then\n    tmpdepfile1=$dir$base.d\n    tmpdepfile2=$dir.libs/$base.d\n    \"$@\" -Wc,+Maked\n  else\n    tmpdepfile1=$dir$base.d\n    tmpdepfile2=$dir$base.d\n    \"$@\" +Maked\n  fi\n  stat=$?\n  if test $stat -ne 0; then\n     rm -f \"$tmpdepfile1\" \"$tmpdepfile2\"\n     exit $stat\n  fi\n\n  for tmpdepfile in \"$tmpdepfile1\" \"$tmpdepfile2\"\n  do\n    test -f \"$tmpdepfile\" && break\n  done\n  if test -f \"$tmpdepfile\"; then\n    sed -e \"s,^.*\\.[$lower]*:,$object:,\" \"$tmpdepfile\" > \"$depfile\"\n    # Add 'dependent.h:' lines.\n    sed -ne '2,${\n               s/^ *//\n               s/ \\\\*$//\n               s/$/:/\n               p\n             }' \"$tmpdepfile\" >> \"$depfile\"\n  else\n    make_dummy_depfile\n  fi\n  rm -f \"$tmpdepfile\" \"$tmpdepfile2\"\n  ;;\n\ntru64)\n  # The Tru64 compiler uses -MD to generate dependencies as a side\n  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.\n  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put\n  # dependencies in 'foo.d' instead, so we check for that too.\n  # Subdirectories are respected.\n  set_dir_from  \"$object\"\n  set_base_from \"$object\"\n\n  if test \"$libtool\" = yes; then\n    # Libtool generates 2 separate objects for the 2 libraries.  These\n    # two compilations output dependencies in $dir.libs/$base.o.d and\n    # in $dir$base.o.d.  We have to check for both files, because\n    # one of the two compilations can be disabled.  We should prefer\n    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is\n    # automatically cleaned when .libs/ is deleted, while ignoring\n    # the former would cause a distcleancheck panic.\n    tmpdepfile1=$dir$base.o.d          # libtool 1.5\n    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.\n    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504\n    \"$@\" -Wc,-MD\n  else\n    tmpdepfile1=$dir$base.d\n    tmpdepfile2=$dir$base.d\n    tmpdepfile3=$dir$base.d\n    \"$@\" -MD\n  fi\n\n  stat=$?\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile1\" \"$tmpdepfile2\" \"$tmpdepfile3\"\n    exit $stat\n  fi\n\n  for tmpdepfile in \"$tmpdepfile1\" \"$tmpdepfile2\" \"$tmpdepfile3\"\n  do\n    test -f \"$tmpdepfile\" && break\n  done\n  # Same post-processing that is required for AIX mode.\n  aix_post_process_depfile\n  ;;\n\nmsvc7)\n  if test \"$libtool\" = yes; then\n    showIncludes=-Wc,-showIncludes\n  else\n    showIncludes=-showIncludes\n  fi\n  \"$@\" $showIncludes > \"$tmpdepfile\"\n  stat=$?\n  grep -v '^Note: including file: ' \"$tmpdepfile\"\n  if test $stat -ne 0; then\n    rm -f \"$tmpdepfile\"\n    exit $stat\n  fi\n  rm -f \"$depfile\"\n  echo \"$object : \\\\\" > \"$depfile\"\n  # The first sed program below extracts the file names and escapes\n  # backslashes for cygpath.  The second sed program outputs the file\n  # name when reading, but also accumulates all include files in the\n  # hold buffer in order to output them again at the end.  This only\n  # works with sed implementations that can handle large buffers.\n  sed < \"$tmpdepfile\" -n '\n/^Note: including file:  *\\(.*\\)/ {\n  s//\\1/\n  s/\\\\/\\\\\\\\/g\n  p\n}' | $cygpath_u | sort -u | sed -n '\ns/ /\\\\ /g\ns/\\(.*\\)/'\"$tab\"'\\1 \\\\/p\ns/.\\(.*\\) \\\\/\\1:/\nH\n$ {\n  s/.*/'\"$tab\"'/\n  G\n  p\n}' >> \"$depfile\"\n  echo >> \"$depfile\" # make sure the fragment doesn't end with a backslash\n  rm -f \"$tmpdepfile\"\n  ;;\n\nmsvc7msys)\n  # This case exists only to let depend.m4 do its work.  It works by\n  # looking at the text of this script.  This case will never be run,\n  # since it is checked for above.\n  exit 1\n  ;;\n\n#nosideeffect)\n  # This comment above is used by automake to tell side-effect\n  # dependency tracking mechanisms from slower ones.\n\ndashmstdout)\n  # Important note: in order to support this mode, a compiler *must*\n  # always write the preprocessed file to stdout, regardless of -o.\n  \"$@\" || exit $?\n\n  # Remove the call to Libtool.\n  if test \"$libtool\" = yes; then\n    while test \"X$1\" != 'X--mode=compile'; do\n      shift\n    done\n    shift\n  fi\n\n  # Remove '-o $object'.\n  IFS=\" \"\n  for arg\n  do\n    case $arg in\n    -o)\n      shift\n      ;;\n    $object)\n      shift\n      ;;\n    *)\n      set fnord \"$@\" \"$arg\"\n      shift # fnord\n      shift # $arg\n      ;;\n    esac\n  done\n\n  test -z \"$dashmflag\" && dashmflag=-M\n  # Require at least two characters before searching for ':'\n  # in the target name.  This is to cope with DOS-style filenames:\n  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.\n  \"$@\" $dashmflag |\n    sed \"s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |\" > \"$tmpdepfile\"\n  rm -f \"$depfile\"\n  cat < \"$tmpdepfile\" > \"$depfile\"\n  # Some versions of the HPUX 10.20 sed can't process this sed invocation\n  # correctly.  Breaking it into two sed invocations is a workaround.\n  tr ' ' \"$nl\" < \"$tmpdepfile\" \\\n    | sed -e 's/^\\\\$//' -e '/^$/d' -e '/:$/d' \\\n    | sed -e 's/$/ :/' >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\ndashXmstdout)\n  # This case only exists to satisfy depend.m4.  It is never actually\n  # run, as this mode is specially recognized in the preamble.\n  exit 1\n  ;;\n\nmakedepend)\n  \"$@\" || exit $?\n  # Remove any Libtool call\n  if test \"$libtool\" = yes; then\n    while test \"X$1\" != 'X--mode=compile'; do\n      shift\n    done\n    shift\n  fi\n  # X makedepend\n  shift\n  cleared=no eat=no\n  for arg\n  do\n    case $cleared in\n    no)\n      set \"\"; shift\n      cleared=yes ;;\n    esac\n    if test $eat = yes; then\n      eat=no\n      continue\n    fi\n    case \"$arg\" in\n    -D*|-I*)\n      set fnord \"$@\" \"$arg\"; shift ;;\n    # Strip any option that makedepend may not understand.  Remove\n    # the object too, otherwise makedepend will parse it as a source file.\n    -arch)\n      eat=yes ;;\n    -*|$object)\n      ;;\n    *)\n      set fnord \"$@\" \"$arg\"; shift ;;\n    esac\n  done\n  obj_suffix=`echo \"$object\" | sed 's/^.*\\././'`\n  touch \"$tmpdepfile\"\n  ${MAKEDEPEND-makedepend} -o\"$obj_suffix\" -f\"$tmpdepfile\" \"$@\"\n  rm -f \"$depfile\"\n  # makedepend may prepend the VPATH from the source file name to the object.\n  # No need to regex-escape $object, excess matching of '.' is harmless.\n  sed \"s|^.*\\($object *:\\)|\\1|\" \"$tmpdepfile\" > \"$depfile\"\n  # Some versions of the HPUX 10.20 sed can't process the last invocation\n  # correctly.  Breaking it into two sed invocations is a workaround.\n  sed '1,2d' \"$tmpdepfile\" \\\n    | tr ' ' \"$nl\" \\\n    | sed -e 's/^\\\\$//' -e '/^$/d' -e '/:$/d' \\\n    | sed -e 's/$/ :/' >> \"$depfile\"\n  rm -f \"$tmpdepfile\" \"$tmpdepfile\".bak\n  ;;\n\ncpp)\n  # Important note: in order to support this mode, a compiler *must*\n  # always write the preprocessed file to stdout.\n  \"$@\" || exit $?\n\n  # Remove the call to Libtool.\n  if test \"$libtool\" = yes; then\n    while test \"X$1\" != 'X--mode=compile'; do\n      shift\n    done\n    shift\n  fi\n\n  # Remove '-o $object'.\n  IFS=\" \"\n  for arg\n  do\n    case $arg in\n    -o)\n      shift\n      ;;\n    $object)\n      shift\n      ;;\n    *)\n      set fnord \"$@\" \"$arg\"\n      shift # fnord\n      shift # $arg\n      ;;\n    esac\n  done\n\n  \"$@\" -E \\\n    | sed -n -e '/^# [0-9][0-9]* \"\\([^\"]*\\)\".*/ s:: \\1 \\\\:p' \\\n             -e '/^#line [0-9][0-9]* \"\\([^\"]*\\)\".*/ s:: \\1 \\\\:p' \\\n    | sed '$ s: \\\\$::' > \"$tmpdepfile\"\n  rm -f \"$depfile\"\n  echo \"$object : \\\\\" > \"$depfile\"\n  cat < \"$tmpdepfile\" >> \"$depfile\"\n  sed < \"$tmpdepfile\" '/^$/d;s/^ //;s/ \\\\$//;s/$/ :/' >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\nmsvisualcpp)\n  # Important note: in order to support this mode, a compiler *must*\n  # always write the preprocessed file to stdout.\n  \"$@\" || exit $?\n\n  # Remove the call to Libtool.\n  if test \"$libtool\" = yes; then\n    while test \"X$1\" != 'X--mode=compile'; do\n      shift\n    done\n    shift\n  fi\n\n  IFS=\" \"\n  for arg\n  do\n    case \"$arg\" in\n    -o)\n      shift\n      ;;\n    $object)\n      shift\n      ;;\n    \"-Gm\"|\"/Gm\"|\"-Gi\"|\"/Gi\"|\"-ZI\"|\"/ZI\")\n        set fnord \"$@\"\n        shift\n        shift\n        ;;\n    *)\n        set fnord \"$@\" \"$arg\"\n        shift\n        shift\n        ;;\n    esac\n  done\n  \"$@\" -E 2>/dev/null |\n  sed -n '/^#line [0-9][0-9]* \"\\([^\"]*\\)\"/ s::\\1:p' | $cygpath_u | sort -u > \"$tmpdepfile\"\n  rm -f \"$depfile\"\n  echo \"$object : \\\\\" > \"$depfile\"\n  sed < \"$tmpdepfile\" -n -e 's% %\\\\ %g' -e '/^\\(.*\\)$/ s::'\"$tab\"'\\1 \\\\:p' >> \"$depfile\"\n  echo \"$tab\" >> \"$depfile\"\n  sed < \"$tmpdepfile\" -n -e 's% %\\\\ %g' -e '/^\\(.*\\)$/ s::\\1\\::p' >> \"$depfile\"\n  rm -f \"$tmpdepfile\"\n  ;;\n\nmsvcmsys)\n  # This case exists only to let depend.m4 do its work.  It works by\n  # looking at the text of this script.  This case will never be run,\n  # since it is checked for above.\n  exit 1\n  ;;\n\nnone)\n  exec \"$@\"\n  ;;\n\n*)\n  echo \"Unknown depmode $depmode\" 1>&2\n  exit 1\n  ;;\nesac\n\nexit 0\n\n# Local Variables:\n# mode: shell-script\n# sh-indentation: 2\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"scriptversion=\"\n# time-stamp-format: \"%:y-%02m-%02d.%02H\"\n# time-stamp-time-zone: \"UTC0\"\n# time-stamp-end: \"; # UTC\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/install-sh",
    "content": "#!/bin/sh\n# install - install a program, script, or datafile\n\nscriptversion=2020-11-14.01; # UTC\n\n# This originates from X11R5 (mit/util/scripts/install.sh), which was\n# later released in X11R6 (xc/config/util/install.sh) with the\n# following copyright and license.\n#\n# Copyright (C) 1994 X Consortium\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to\n# deal in the Software without restriction, including without limitation the\n# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n# sell copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\n# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN\n# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-\n# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n#\n# Except as contained in this notice, the name of the X Consortium shall not\n# be used in advertising or otherwise to promote the sale, use or other deal-\n# ings in this Software without prior written authorization from the X Consor-\n# tium.\n#\n#\n# FSF changes to this file are in the public domain.\n#\n# Calling this script install-sh is preferred over install.sh, to prevent\n# 'make' implicit rules from creating a file called install from it\n# when there is no Makefile.\n#\n# This script is compatible with the BSD install script, but was written\n# from scratch.\n\ntab='\t'\nnl='\n'\nIFS=\" $tab$nl\"\n\n# Set DOITPROG to \"echo\" to test this script.\n\ndoit=${DOITPROG-}\ndoit_exec=${doit:-exec}\n\n# Put in absolute file names if you don't have them in your path;\n# or use environment vars.\n\nchgrpprog=${CHGRPPROG-chgrp}\nchmodprog=${CHMODPROG-chmod}\nchownprog=${CHOWNPROG-chown}\ncmpprog=${CMPPROG-cmp}\ncpprog=${CPPROG-cp}\nmkdirprog=${MKDIRPROG-mkdir}\nmvprog=${MVPROG-mv}\nrmprog=${RMPROG-rm}\nstripprog=${STRIPPROG-strip}\n\nposix_mkdir=\n\n# Desired mode of installed file.\nmode=0755\n\n# Create dirs (including intermediate dirs) using mode 755.\n# This is like GNU 'install' as of coreutils 8.32 (2020).\nmkdir_umask=22\n\nbackupsuffix=\nchgrpcmd=\nchmodcmd=$chmodprog\nchowncmd=\nmvcmd=$mvprog\nrmcmd=\"$rmprog -f\"\nstripcmd=\n\nsrc=\ndst=\ndir_arg=\ndst_arg=\n\ncopy_on_change=false\nis_target_a_directory=possibly\n\nusage=\"\\\nUsage: $0 [OPTION]... [-T] SRCFILE DSTFILE\n   or: $0 [OPTION]... SRCFILES... DIRECTORY\n   or: $0 [OPTION]... -t DIRECTORY SRCFILES...\n   or: $0 [OPTION]... -d DIRECTORIES...\n\nIn the 1st form, copy SRCFILE to DSTFILE.\nIn the 2nd and 3rd, copy all SRCFILES to DIRECTORY.\nIn the 4th, create DIRECTORIES.\n\nOptions:\n     --help     display this help and exit.\n     --version  display version info and exit.\n\n  -c            (ignored)\n  -C            install only if different (preserve data modification time)\n  -d            create directories instead of installing files.\n  -g GROUP      $chgrpprog installed files to GROUP.\n  -m MODE       $chmodprog installed files to MODE.\n  -o USER       $chownprog installed files to USER.\n  -p            pass -p to $cpprog.\n  -s            $stripprog installed files.\n  -S SUFFIX     attempt to back up existing files, with suffix SUFFIX.\n  -t DIRECTORY  install into DIRECTORY.\n  -T            report an error if DSTFILE is a directory.\n\nEnvironment variables override the default commands:\n  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG\n  RMPROG STRIPPROG\n\nBy default, rm is invoked with -f; when overridden with RMPROG,\nit's up to you to specify -f if you want it.\n\nIf -S is not specified, no backups are attempted.\n\nEmail bug reports to bug-automake@gnu.org.\nAutomake home page: https://www.gnu.org/software/automake/\n\"\n\nwhile test $# -ne 0; do\n  case $1 in\n    -c) ;;\n\n    -C) copy_on_change=true;;\n\n    -d) dir_arg=true;;\n\n    -g) chgrpcmd=\"$chgrpprog $2\"\n        shift;;\n\n    --help) echo \"$usage\"; exit $?;;\n\n    -m) mode=$2\n        case $mode in\n          *' '* | *\"$tab\"* | *\"$nl\"* | *'*'* | *'?'* | *'['*)\n            echo \"$0: invalid mode: $mode\" >&2\n            exit 1;;\n        esac\n        shift;;\n\n    -o) chowncmd=\"$chownprog $2\"\n        shift;;\n\n    -p) cpprog=\"$cpprog -p\";;\n\n    -s) stripcmd=$stripprog;;\n\n    -S) backupsuffix=\"$2\"\n        shift;;\n\n    -t)\n        is_target_a_directory=always\n        dst_arg=$2\n        # Protect names problematic for 'test' and other utilities.\n        case $dst_arg in\n          -* | [=\\(\\)!]) dst_arg=./$dst_arg;;\n        esac\n        shift;;\n\n    -T) is_target_a_directory=never;;\n\n    --version) echo \"$0 $scriptversion\"; exit $?;;\n\n    --) shift\n        break;;\n\n    -*) echo \"$0: invalid option: $1\" >&2\n        exit 1;;\n\n    *)  break;;\n  esac\n  shift\ndone\n\n# We allow the use of options -d and -T together, by making -d\n# take the precedence; this is for compatibility with GNU install.\n\nif test -n \"$dir_arg\"; then\n  if test -n \"$dst_arg\"; then\n    echo \"$0: target directory not allowed when installing a directory.\" >&2\n    exit 1\n  fi\nfi\n\nif test $# -ne 0 && test -z \"$dir_arg$dst_arg\"; then\n  # When -d is used, all remaining arguments are directories to create.\n  # When -t is used, the destination is already specified.\n  # Otherwise, the last argument is the destination.  Remove it from $@.\n  for arg\n  do\n    if test -n \"$dst_arg\"; then\n      # $@ is not empty: it contains at least $arg.\n      set fnord \"$@\" \"$dst_arg\"\n      shift # fnord\n    fi\n    shift # arg\n    dst_arg=$arg\n    # Protect names problematic for 'test' and other utilities.\n    case $dst_arg in\n      -* | [=\\(\\)!]) dst_arg=./$dst_arg;;\n    esac\n  done\nfi\n\nif test $# -eq 0; then\n  if test -z \"$dir_arg\"; then\n    echo \"$0: no input file specified.\" >&2\n    exit 1\n  fi\n  # It's OK to call 'install-sh -d' without argument.\n  # This can happen when creating conditional directories.\n  exit 0\nfi\n\nif test -z \"$dir_arg\"; then\n  if test $# -gt 1 || test \"$is_target_a_directory\" = always; then\n    if test ! -d \"$dst_arg\"; then\n      echo \"$0: $dst_arg: Is not a directory.\" >&2\n      exit 1\n    fi\n  fi\nfi\n\nif test -z \"$dir_arg\"; then\n  do_exit='(exit $ret); exit $ret'\n  trap \"ret=129; $do_exit\" 1\n  trap \"ret=130; $do_exit\" 2\n  trap \"ret=141; $do_exit\" 13\n  trap \"ret=143; $do_exit\" 15\n\n  # Set umask so as not to create temps with too-generous modes.\n  # However, 'strip' requires both read and write access to temps.\n  case $mode in\n    # Optimize common cases.\n    *644) cp_umask=133;;\n    *755) cp_umask=22;;\n\n    *[0-7])\n      if test -z \"$stripcmd\"; then\n        u_plus_rw=\n      else\n        u_plus_rw='% 200'\n      fi\n      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;\n    *)\n      if test -z \"$stripcmd\"; then\n        u_plus_rw=\n      else\n        u_plus_rw=,u+rw\n      fi\n      cp_umask=$mode$u_plus_rw;;\n  esac\nfi\n\nfor src\ndo\n  # Protect names problematic for 'test' and other utilities.\n  case $src in\n    -* | [=\\(\\)!]) src=./$src;;\n  esac\n\n  if test -n \"$dir_arg\"; then\n    dst=$src\n    dstdir=$dst\n    test -d \"$dstdir\"\n    dstdir_status=$?\n    # Don't chown directories that already exist.\n    if test $dstdir_status = 0; then\n      chowncmd=\"\"\n    fi\n  else\n\n    # Waiting for this to be detected by the \"$cpprog $src $dsttmp\" command\n    # might cause directories to be created, which would be especially bad\n    # if $src (and thus $dsttmp) contains '*'.\n    if test ! -f \"$src\" && test ! -d \"$src\"; then\n      echo \"$0: $src does not exist.\" >&2\n      exit 1\n    fi\n\n    if test -z \"$dst_arg\"; then\n      echo \"$0: no destination specified.\" >&2\n      exit 1\n    fi\n    dst=$dst_arg\n\n    # If destination is a directory, append the input filename.\n    if test -d \"$dst\"; then\n      if test \"$is_target_a_directory\" = never; then\n        echo \"$0: $dst_arg: Is a directory\" >&2\n        exit 1\n      fi\n      dstdir=$dst\n      dstbase=`basename \"$src\"`\n      case $dst in\n\t*/) dst=$dst$dstbase;;\n\t*)  dst=$dst/$dstbase;;\n      esac\n      dstdir_status=0\n    else\n      dstdir=`dirname \"$dst\"`\n      test -d \"$dstdir\"\n      dstdir_status=$?\n    fi\n  fi\n\n  case $dstdir in\n    */) dstdirslash=$dstdir;;\n    *)  dstdirslash=$dstdir/;;\n  esac\n\n  obsolete_mkdir_used=false\n\n  if test $dstdir_status != 0; then\n    case $posix_mkdir in\n      '')\n        # With -d, create the new directory with the user-specified mode.\n        # Otherwise, rely on $mkdir_umask.\n        if test -n \"$dir_arg\"; then\n          mkdir_mode=-m$mode\n        else\n          mkdir_mode=\n        fi\n\n        posix_mkdir=false\n\t# The $RANDOM variable is not portable (e.g., dash).  Use it\n\t# here however when possible just to lower collision chance.\n\ttmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$\n\n\ttrap '\n\t  ret=$?\n\t  rmdir \"$tmpdir/a/b\" \"$tmpdir/a\" \"$tmpdir\" 2>/dev/null\n\t  exit $ret\n\t' 0\n\n\t# Because \"mkdir -p\" follows existing symlinks and we likely work\n\t# directly in world-writeable /tmp, make sure that the '$tmpdir'\n\t# directory is successfully created first before we actually test\n\t# 'mkdir -p'.\n\tif (umask $mkdir_umask &&\n\t    $mkdirprog $mkdir_mode \"$tmpdir\" &&\n\t    exec $mkdirprog $mkdir_mode -p -- \"$tmpdir/a/b\") >/dev/null 2>&1\n\tthen\n\t  if test -z \"$dir_arg\" || {\n\t       # Check for POSIX incompatibilities with -m.\n\t       # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or\n\t       # other-writable bit of parent directory when it shouldn't.\n\t       # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.\n\t       test_tmpdir=\"$tmpdir/a\"\n\t       ls_ld_tmpdir=`ls -ld \"$test_tmpdir\"`\n\t       case $ls_ld_tmpdir in\n\t\t d????-?r-*) different_mode=700;;\n\t\t d????-?--*) different_mode=755;;\n\t\t *) false;;\n\t       esac &&\n\t       $mkdirprog -m$different_mode -p -- \"$test_tmpdir\" && {\n\t\t ls_ld_tmpdir_1=`ls -ld \"$test_tmpdir\"`\n\t\t test \"$ls_ld_tmpdir\" = \"$ls_ld_tmpdir_1\"\n\t       }\n\t     }\n\t  then posix_mkdir=:\n\t  fi\n\t  rmdir \"$tmpdir/a/b\" \"$tmpdir/a\" \"$tmpdir\"\n\telse\n\t  # Remove any dirs left behind by ancient mkdir implementations.\n\t  rmdir ./$mkdir_mode ./-p ./-- \"$tmpdir\" 2>/dev/null\n\tfi\n\ttrap '' 0;;\n    esac\n\n    if\n      $posix_mkdir && (\n        umask $mkdir_umask &&\n        $doit_exec $mkdirprog $mkdir_mode -p -- \"$dstdir\"\n      )\n    then :\n    else\n\n      # mkdir does not conform to POSIX,\n      # or it failed possibly due to a race condition.  Create the\n      # directory the slow way, step by step, checking for races as we go.\n\n      case $dstdir in\n        /*) prefix='/';;\n        [-=\\(\\)!]*) prefix='./';;\n        *)  prefix='';;\n      esac\n\n      oIFS=$IFS\n      IFS=/\n      set -f\n      set fnord $dstdir\n      shift\n      set +f\n      IFS=$oIFS\n\n      prefixes=\n\n      for d\n      do\n        test X\"$d\" = X && continue\n\n        prefix=$prefix$d\n        if test -d \"$prefix\"; then\n          prefixes=\n        else\n          if $posix_mkdir; then\n            (umask $mkdir_umask &&\n             $doit_exec $mkdirprog $mkdir_mode -p -- \"$dstdir\") && break\n            # Don't fail if two instances are running concurrently.\n            test -d \"$prefix\" || exit 1\n          else\n            case $prefix in\n              *\\'*) qprefix=`echo \"$prefix\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"`;;\n              *) qprefix=$prefix;;\n            esac\n            prefixes=\"$prefixes '$qprefix'\"\n          fi\n        fi\n        prefix=$prefix/\n      done\n\n      if test -n \"$prefixes\"; then\n        # Don't fail if two instances are running concurrently.\n        (umask $mkdir_umask &&\n         eval \"\\$doit_exec \\$mkdirprog $prefixes\") ||\n          test -d \"$dstdir\" || exit 1\n        obsolete_mkdir_used=true\n      fi\n    fi\n  fi\n\n  if test -n \"$dir_arg\"; then\n    { test -z \"$chowncmd\" || $doit $chowncmd \"$dst\"; } &&\n    { test -z \"$chgrpcmd\" || $doit $chgrpcmd \"$dst\"; } &&\n    { test \"$obsolete_mkdir_used$chowncmd$chgrpcmd\" = false ||\n      test -z \"$chmodcmd\" || $doit $chmodcmd $mode \"$dst\"; } || exit 1\n  else\n\n    # Make a couple of temp file names in the proper directory.\n    dsttmp=${dstdirslash}_inst.$$_\n    rmtmp=${dstdirslash}_rm.$$_\n\n    # Trap to clean up those temp files at exit.\n    trap 'ret=$?; rm -f \"$dsttmp\" \"$rmtmp\" && exit $ret' 0\n\n    # Copy the file name to the temp name.\n    (umask $cp_umask &&\n     { test -z \"$stripcmd\" || {\n\t # Create $dsttmp read-write so that cp doesn't create it read-only,\n\t # which would cause strip to fail.\n\t if test -z \"$doit\"; then\n\t   : >\"$dsttmp\" # No need to fork-exec 'touch'.\n\t else\n\t   $doit touch \"$dsttmp\"\n\t fi\n       }\n     } &&\n     $doit_exec $cpprog \"$src\" \"$dsttmp\") &&\n\n    # and set any options; do chmod last to preserve setuid bits.\n    #\n    # If any of these fail, we abort the whole thing.  If we want to\n    # ignore errors from any of these, just make sure not to ignore\n    # errors from the above \"$doit $cpprog $src $dsttmp\" command.\n    #\n    { test -z \"$chowncmd\" || $doit $chowncmd \"$dsttmp\"; } &&\n    { test -z \"$chgrpcmd\" || $doit $chgrpcmd \"$dsttmp\"; } &&\n    { test -z \"$stripcmd\" || $doit $stripcmd \"$dsttmp\"; } &&\n    { test -z \"$chmodcmd\" || $doit $chmodcmd $mode \"$dsttmp\"; } &&\n\n    # If -C, don't bother to copy if it wouldn't change the file.\n    if $copy_on_change &&\n       old=`LC_ALL=C ls -dlL \"$dst\"     2>/dev/null` &&\n       new=`LC_ALL=C ls -dlL \"$dsttmp\"  2>/dev/null` &&\n       set -f &&\n       set X $old && old=:$2:$4:$5:$6 &&\n       set X $new && new=:$2:$4:$5:$6 &&\n       set +f &&\n       test \"$old\" = \"$new\" &&\n       $cmpprog \"$dst\" \"$dsttmp\" >/dev/null 2>&1\n    then\n      rm -f \"$dsttmp\"\n    else\n      # If $backupsuffix is set, and the file being installed\n      # already exists, attempt a backup.  Don't worry if it fails,\n      # e.g., if mv doesn't support -f.\n      if test -n \"$backupsuffix\" && test -f \"$dst\"; then\n        $doit $mvcmd -f \"$dst\" \"$dst$backupsuffix\" 2>/dev/null\n      fi\n\n      # Rename the file to the real destination.\n      $doit $mvcmd -f \"$dsttmp\" \"$dst\" 2>/dev/null ||\n\n      # The rename failed, perhaps because mv can't rename something else\n      # to itself, or perhaps because mv is so ancient that it does not\n      # support -f.\n      {\n        # Now remove or move aside any old file at destination location.\n        # We try this two ways since rm can't unlink itself on some\n        # systems and the destination file might be busy for other\n        # reasons.  In this case, the final cleanup might fail but the new\n        # file should still install successfully.\n        {\n          test ! -f \"$dst\" ||\n          $doit $rmcmd \"$dst\" 2>/dev/null ||\n          { $doit $mvcmd -f \"$dst\" \"$rmtmp\" 2>/dev/null &&\n            { $doit $rmcmd \"$rmtmp\" 2>/dev/null; :; }\n          } ||\n          { echo \"$0: cannot unlink or rename $dst\" >&2\n            (exit 1); exit 1\n          }\n        } &&\n\n        # Now rename the file to the real destination.\n        $doit $mvcmd \"$dsttmp\" \"$dst\"\n      }\n    fi || exit 1\n\n    trap '' 0\n  fi\ndone\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"scriptversion=\"\n# time-stamp-format: \"%:y-%02m-%02d.%02H\"\n# time-stamp-time-zone: \"UTC0\"\n# time-stamp-end: \"; # UTC\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/build-aux/missing",
    "content": "#! /bin/sh\n# Common wrapper for a few potentially missing GNU programs.\n\nscriptversion=2018-03-07.03; # UTC\n\n# Copyright (C) 1996-2020 Free Software Foundation, Inc.\n# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.\n\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2, or (at your option)\n# any later version.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that program.\n\nif test $# -eq 0; then\n  echo 1>&2 \"Try '$0 --help' for more information\"\n  exit 1\nfi\n\ncase $1 in\n\n  --is-lightweight)\n    # Used by our autoconf macros to check whether the available missing\n    # script is modern enough.\n    exit 0\n    ;;\n\n  --run)\n    # Back-compat with the calling convention used by older automake.\n    shift\n    ;;\n\n  -h|--h|--he|--hel|--help)\n    echo \"\\\n$0 [OPTION]... PROGRAM [ARGUMENT]...\n\nRun 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due\nto PROGRAM being missing or too old.\n\nOptions:\n  -h, --help      display this help and exit\n  -v, --version   output version information and exit\n\nSupported PROGRAM values:\n  aclocal   autoconf  autoheader   autom4te  automake  makeinfo\n  bison     yacc      flex         lex       help2man\n\nVersion suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and\n'g' are ignored when checking the name.\n\nSend bug reports to <bug-automake@gnu.org>.\"\n    exit $?\n    ;;\n\n  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)\n    echo \"missing $scriptversion (GNU Automake)\"\n    exit $?\n    ;;\n\n  -*)\n    echo 1>&2 \"$0: unknown '$1' option\"\n    echo 1>&2 \"Try '$0 --help' for more information\"\n    exit 1\n    ;;\n\nesac\n\n# Run the given program, remember its exit status.\n\"$@\"; st=$?\n\n# If it succeeded, we are done.\ntest $st -eq 0 && exit 0\n\n# Also exit now if we it failed (or wasn't found), and '--version' was\n# passed; such an option is passed most likely to detect whether the\n# program is present and works.\ncase $2 in --version|--help) exit $st;; esac\n\n# Exit code 63 means version mismatch.  This often happens when the user\n# tries to use an ancient version of a tool on a file that requires a\n# minimum version.\nif test $st -eq 63; then\n  msg=\"probably too old\"\nelif test $st -eq 127; then\n  # Program was missing.\n  msg=\"missing on your system\"\nelse\n  # Program was found and executed, but failed.  Give up.\n  exit $st\nfi\n\nperl_URL=https://www.perl.org/\nflex_URL=https://github.com/westes/flex\ngnu_software_URL=https://www.gnu.org/software\n\nprogram_details ()\n{\n  case $1 in\n    aclocal|automake)\n      echo \"The '$1' program is part of the GNU Automake package:\"\n      echo \"<$gnu_software_URL/automake>\"\n      echo \"It also requires GNU Autoconf, GNU m4 and Perl in order to run:\"\n      echo \"<$gnu_software_URL/autoconf>\"\n      echo \"<$gnu_software_URL/m4/>\"\n      echo \"<$perl_URL>\"\n      ;;\n    autoconf|autom4te|autoheader)\n      echo \"The '$1' program is part of the GNU Autoconf package:\"\n      echo \"<$gnu_software_URL/autoconf/>\"\n      echo \"It also requires GNU m4 and Perl in order to run:\"\n      echo \"<$gnu_software_URL/m4/>\"\n      echo \"<$perl_URL>\"\n      ;;\n  esac\n}\n\ngive_advice ()\n{\n  # Normalize program name to check for.\n  normalized_program=`echo \"$1\" | sed '\n    s/^gnu-//; t\n    s/^gnu//; t\n    s/^g//; t'`\n\n  printf '%s\\n' \"'$1' is $msg.\"\n\n  configure_deps=\"'configure.ac' or m4 files included by 'configure.ac'\"\n  case $normalized_program in\n    autoconf*)\n      echo \"You should only need it if you modified 'configure.ac',\"\n      echo \"or m4 files included by it.\"\n      program_details 'autoconf'\n      ;;\n    autoheader*)\n      echo \"You should only need it if you modified 'acconfig.h' or\"\n      echo \"$configure_deps.\"\n      program_details 'autoheader'\n      ;;\n    automake*)\n      echo \"You should only need it if you modified 'Makefile.am' or\"\n      echo \"$configure_deps.\"\n      program_details 'automake'\n      ;;\n    aclocal*)\n      echo \"You should only need it if you modified 'acinclude.m4' or\"\n      echo \"$configure_deps.\"\n      program_details 'aclocal'\n      ;;\n   autom4te*)\n      echo \"You might have modified some maintainer files that require\"\n      echo \"the 'autom4te' program to be rebuilt.\"\n      program_details 'autom4te'\n      ;;\n    bison*|yacc*)\n      echo \"You should only need it if you modified a '.y' file.\"\n      echo \"You may want to install the GNU Bison package:\"\n      echo \"<$gnu_software_URL/bison/>\"\n      ;;\n    lex*|flex*)\n      echo \"You should only need it if you modified a '.l' file.\"\n      echo \"You may want to install the Fast Lexical Analyzer package:\"\n      echo \"<$flex_URL>\"\n      ;;\n    help2man*)\n      echo \"You should only need it if you modified a dependency\" \\\n           \"of a man page.\"\n      echo \"You may want to install the GNU Help2man package:\"\n      echo \"<$gnu_software_URL/help2man/>\"\n    ;;\n    makeinfo*)\n      echo \"You should only need it if you modified a '.texi' file, or\"\n      echo \"any other file indirectly affecting the aspect of the manual.\"\n      echo \"You might want to install the Texinfo package:\"\n      echo \"<$gnu_software_URL/texinfo/>\"\n      echo \"The spurious makeinfo call might also be the consequence of\"\n      echo \"using a buggy 'make' (AIX, DU, IRIX), in which case you might\"\n      echo \"want to install GNU make:\"\n      echo \"<$gnu_software_URL/make/>\"\n      ;;\n    *)\n      echo \"You might have modified some files without having the proper\"\n      echo \"tools for further handling them.  Check the 'README' file, it\"\n      echo \"often tells you about the needed prerequisites for installing\"\n      echo \"this package.  You may also peek at any GNU archive site, in\"\n      echo \"case some other package contains this missing '$1' program.\"\n      ;;\n  esac\n}\n\ngive_advice \"$1\" | sed -e '1s/^/WARNING: /' \\\n                       -e '2,$s/^/         /' >&2\n\n# Propagate the correct exit status (expected to be 127 for a program\n# not found, 63 for a program that failed due to version mismatch).\nexit $st\n\n# Local variables:\n# eval: (add-hook 'before-save-hook 'time-stamp)\n# time-stamp-start: \"scriptversion=\"\n# time-stamp-format: \"%:y-%02m-%02d.%02H\"\n# time-stamp-time-zone: \"UTC0\"\n# time-stamp-end: \"; # UTC\"\n# End:\n"
  },
  {
    "path": "windows_compat/gnulib/config.h.in",
    "content": "/* config.h.in.  Generated from configure.ac by autoheader.  */\n\n/* Define to the number of bits in type 'ptrdiff_t'. */\n#undef BITSIZEOF_PTRDIFF_T\n\n/* Define to the number of bits in type 'sig_atomic_t'. */\n#undef BITSIZEOF_SIG_ATOMIC_T\n\n/* Define to the number of bits in type 'size_t'. */\n#undef BITSIZEOF_SIZE_T\n\n/* Define to the number of bits in type 'wchar_t'. */\n#undef BITSIZEOF_WCHAR_T\n\n/* Define to the number of bits in type 'wint_t'. */\n#undef BITSIZEOF_WINT_T\n\n/* Define this to 'void' or 'struct timezone' to match the system's\n   declaration of the second argument to gettimeofday. */\n#undef GETTIMEOFDAY_TIMEZONE\n\n/* Define to a C preprocessor expression that evaluates to 1 or 0,\r depending\n   whether the gnulib module fscanf shall be considered present. */\n#undef GNULIB_FSCANF\n\n/* Define to a C preprocessor expression that evaluates to 1 or 0,\r depending\n   whether the gnulib module msvc-nothrow shall be considered present. */\n#undef GNULIB_MSVC_NOTHROW\n\n/* Define to 1 if printf and friends should be labeled with\r attribute\n   \"__gnu_printf__\" instead of \"__printf__\" */\n#undef GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU\n\n/* Define to a C preprocessor expression that evaluates to 1 or 0,\r depending\n   whether the gnulib module scanf shall be considered present. */\n#undef GNULIB_SCANF\n\n/* Define to 1 when the gnulib module fgetc should be tested. */\n#undef GNULIB_TEST_FGETC\n\n/* Define to 1 when the gnulib module fgets should be tested. */\n#undef GNULIB_TEST_FGETS\n\n/* Define to 1 when the gnulib module fprintf should be tested. */\n#undef GNULIB_TEST_FPRINTF\n\n/* Define to 1 when the gnulib module fputc should be tested. */\n#undef GNULIB_TEST_FPUTC\n\n/* Define to 1 when the gnulib module fputs should be tested. */\n#undef GNULIB_TEST_FPUTS\n\n/* Define to 1 when the gnulib module fread should be tested. */\n#undef GNULIB_TEST_FREAD\n\n/* Define to 1 when the gnulib module fscanf should be tested. */\n#undef GNULIB_TEST_FSCANF\n\n/* Define to 1 when the gnulib module fwrite should be tested. */\n#undef GNULIB_TEST_FWRITE\n\n/* Define to 1 when the gnulib module getc should be tested. */\n#undef GNULIB_TEST_GETC\n\n/* Define to 1 when the gnulib module getchar should be tested. */\n#undef GNULIB_TEST_GETCHAR\n\n/* Define to 1 when the gnulib module getdelim should be tested. */\n#undef GNULIB_TEST_GETDELIM\n\n/* Define to 1 when the gnulib module gethostname should be tested. */\n#undef GNULIB_TEST_GETHOSTNAME\n\n/* Define to 1 when the gnulib module getline should be tested. */\n#undef GNULIB_TEST_GETLINE\n\n/* Define to 1 when the gnulib module gettimeofday should be tested. */\n#undef GNULIB_TEST_GETTIMEOFDAY\n\n/* Define to 1 when the gnulib module printf should be tested. */\n#undef GNULIB_TEST_PRINTF\n\n/* Define to 1 when the gnulib module putc should be tested. */\n#undef GNULIB_TEST_PUTC\n\n/* Define to 1 when the gnulib module putchar should be tested. */\n#undef GNULIB_TEST_PUTCHAR\n\n/* Define to 1 when the gnulib module puts should be tested. */\n#undef GNULIB_TEST_PUTS\n\n/* Define to 1 when the gnulib module random should be tested. */\n#undef GNULIB_TEST_RANDOM\n\n/* Define to 1 when the gnulib module random_r should be tested. */\n#undef GNULIB_TEST_RANDOM_R\n\n/* Define to 1 when the gnulib module scanf should be tested. */\n#undef GNULIB_TEST_SCANF\n\n/* Define to 1 when the gnulib module time_r should be tested. */\n#undef GNULIB_TEST_TIME_R\n\n/* Define to 1 when the gnulib module vfprintf should be tested. */\n#undef GNULIB_TEST_VFPRINTF\n\n/* Define to 1 when the gnulib module vprintf should be tested. */\n#undef GNULIB_TEST_VPRINTF\n\n/* Define to 1 if you have the declaration of `ecvt', and to 0 if you don't.\n   */\n#undef HAVE_DECL_ECVT\n\n/* Define to 1 if you have the declaration of `execvpe', and to 0 if you\n   don't. */\n#undef HAVE_DECL_EXECVPE\n\n/* Define to 1 if you have the declaration of `fcloseall', and to 0 if you\n   don't. */\n#undef HAVE_DECL_FCLOSEALL\n\n/* Define to 1 if you have the declaration of `fcvt', and to 0 if you don't.\n   */\n#undef HAVE_DECL_FCVT\n\n/* Define to 1 if you have the declaration of `gcvt', and to 0 if you don't.\n   */\n#undef HAVE_DECL_GCVT\n\n/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you\n   don't. */\n#undef HAVE_DECL_GETC_UNLOCKED\n\n/* Define to 1 if you have the declaration of `getdelim', and to 0 if you\n   don't. */\n#undef HAVE_DECL_GETDELIM\n\n/* Define to 1 if you have the declaration of `getline', and to 0 if you\n   don't. */\n#undef HAVE_DECL_GETLINE\n\n/* Define to 1 if you have the declaration of `initstate', and to 0 if you\n   don't. */\n#undef HAVE_DECL_INITSTATE\n\n/* Define to 1 if you have the declaration of `localtime_r', and to 0 if you\n   don't. */\n#undef HAVE_DECL_LOCALTIME_R\n\n/* Define to 1 if you have the declaration of `setstate', and to 0 if you\n   don't. */\n#undef HAVE_DECL_SETSTATE\n\n/* Define to 1 if you have the <execinfo.h> header file. */\n#undef HAVE_EXECINFO_H\n\n/* Define to 1 if you have the `flockfile' function. */\n#undef HAVE_FLOCKFILE\n\n/* Define to 1 if you have the `funlockfile' function. */\n#undef HAVE_FUNLOCKFILE\n\n/* Define to 1 if you have the `getdelim' function. */\n#undef HAVE_GETDELIM\n\n/* Define to 1 if you have the `gethostname' function. */\n#undef HAVE_GETHOSTNAME\n\n/* Define to 1 if you have the `gettimeofday' function. */\n#undef HAVE_GETTIMEOFDAY\n\n/* Define to 1 if you have the `initstate' function. */\n#undef HAVE_INITSTATE\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#undef HAVE_INTTYPES_H\n\n/* Define to 1 if you have the <limits.h> header file. */\n#undef HAVE_LIMITS_H\n\n/* Define to 1 if you have the `localtime_r' function. */\n#undef HAVE_LOCALTIME_R\n\n/* Define to 1 if the system has the type 'long long int'. */\n#undef HAVE_LONG_LONG_INT\n\n/* Define to 1 if you have the <minix/config.h> header file. */\n#undef HAVE_MINIX_CONFIG_H\n\n/* Define to 1 on MSVC platforms that have the \"invalid parameter handler\"\n   concept. */\n#undef HAVE_MSVC_INVALID_PARAMETER_HANDLER\n\n/* Define to 1 if you have the <netdb.h> header file. */\n#undef HAVE_NETDB_H\n\n/* Define to 1 if you have the <random.h> header file. */\n#undef HAVE_RANDOM_H\n\n/* Define to 1 if you have the `random_r' function. */\n#undef HAVE_RANDOM_R\n\n/* Define to 1 if the system has the type `sa_family_t'. */\n#undef HAVE_SA_FAMILY_T\n\n/* Define to 1 if you have the `setstate' function. */\n#undef HAVE_SETSTATE\n\n/* Define to 1 if you have the `shutdown' function. */\n#undef HAVE_SHUTDOWN\n\n/* Define to 1 if 'sig_atomic_t' is a signed integer type. */\n#undef HAVE_SIGNED_SIG_ATOMIC_T\n\n/* Define to 1 if 'wchar_t' is a signed integer type. */\n#undef HAVE_SIGNED_WCHAR_T\n\n/* Define to 1 if 'wint_t' is a signed integer type. */\n#undef HAVE_SIGNED_WINT_T\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#undef HAVE_STDINT_H\n\n/* Define to 1 if you have the <stdio.h> header file. */\n#undef HAVE_STDIO_H\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#undef HAVE_STDLIB_H\n\n/* Define to 1 if you have the <strings.h> header file. */\n#undef HAVE_STRINGS_H\n\n/* Define to 1 if you have the <string.h> header file. */\n#undef HAVE_STRING_H\n\n/* Define to 1 if the system has the type `struct random_data'. */\n#undef HAVE_STRUCT_RANDOM_DATA\n\n/* Define to 1 if the system has the type `struct sockaddr_storage'. */\n#undef HAVE_STRUCT_SOCKADDR_STORAGE\n\n/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */\n#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY\n\n/* Define to 1 if the system has the type `struct utsname'. */\n#undef HAVE_STRUCT_UTSNAME\n\n/* Define to 1 if you have the <sys/bitypes.h> header file. */\n#undef HAVE_SYS_BITYPES_H\n\n/* Define to 1 if you have the <sys/inttypes.h> header file. */\n#undef HAVE_SYS_INTTYPES_H\n\n/* Define to 1 if you have the <sys/param.h> header file. */\n#undef HAVE_SYS_PARAM_H\n\n/* Define to 1 if you have the <sys/resource.h> header file. */\n#undef HAVE_SYS_RESOURCE_H\n\n/* Define to 1 if you have the <sys/socket.h> header file. */\n#undef HAVE_SYS_SOCKET_H\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#undef HAVE_SYS_STAT_H\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#undef HAVE_SYS_TIME_H\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#undef HAVE_SYS_TYPES_H\n\n/* Define to 1 if you have the <sys/uio.h> header file. */\n#undef HAVE_SYS_UIO_H\n\n/* Define to 1 if you have the <sys/utsname.h> header file. */\n#undef HAVE_SYS_UTSNAME_H\n\n/* Define to 1 if you have the `uname' function. */\n#undef HAVE_UNAME\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#undef HAVE_UNISTD_H\n\n/* Define to 1 if the system has the type 'unsigned long long int'. */\n#undef HAVE_UNSIGNED_LONG_LONG_INT\n\n/* Define to 1 if you have the <wchar.h> header file. */\n#undef HAVE_WCHAR_H\n\n/* Define if you have the 'wchar_t' type. */\n#undef HAVE_WCHAR_T\n\n/* Define to 1 if you have the <winsock2.h> header file. */\n#undef HAVE_WINSOCK2_H\n\n/* Define if you have the 'wint_t' type. */\n#undef HAVE_WINT_T\n\n/* Define to 1 if you have the <ws2tcpip.h> header file. */\n#undef HAVE_WS2TCPIP_H\n\n/* Define to 1 if you have the `_set_invalid_parameter_handler' function. */\n#undef HAVE__SET_INVALID_PARAMETER_HANDLER\n\n/* Define to 1 if the compiler supports the keyword '__inline'. */\n#undef HAVE___INLINE\n\n/* Define HOST_NAME_MAX when <limits.h> does not define it. */\n#undef HOST_NAME_MAX\n\n/* Use GNU style printf and scanf.  */\n#ifndef __USE_MINGW_ANSI_STDIO\n# undef __USE_MINGW_ANSI_STDIO\n#endif\n\n\n/* Name of package */\n#undef PACKAGE\n\n/* Define to the address where bug reports for this package should be sent. */\n#undef PACKAGE_BUGREPORT\n\n/* Define to the full name of this package. */\n#undef PACKAGE_NAME\n\n/* Define to the full name and version of this package. */\n#undef PACKAGE_STRING\n\n/* Define to the one symbol short name of this package. */\n#undef PACKAGE_TARNAME\n\n/* Define to the home page for this package. */\n#undef PACKAGE_URL\n\n/* Define to the version of this package. */\n#undef PACKAGE_VERSION\n\n/* Define to l, ll, u, ul, ull, etc., as suitable for\r constants of type\n   'ptrdiff_t'. */\n#undef PTRDIFF_T_SUFFIX\n\n/* Define to l, ll, u, ul, ull, etc., as suitable for\r constants of type\n   'sig_atomic_t'. */\n#undef SIG_ATOMIC_T_SUFFIX\n\n/* Define to l, ll, u, ul, ull, etc., as suitable for\r constants of type\n   'size_t'. */\n#undef SIZE_T_SUFFIX\n\n/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */\n#undef STAT_MACROS_BROKEN\n\n/* Define to 1 if all of the C90 standard headers exist (not just the ones\n   required in a freestanding environment). This macro is provided for\n   backward compatibility; new code need not use it. */\n#undef STDC_HEADERS\n\n/* Enable extensions on AIX 3, Interix.  */\n#ifndef _ALL_SOURCE\n# undef _ALL_SOURCE\n#endif\n/* Enable general extensions on macOS.  */\n#ifndef _DARWIN_C_SOURCE\n# undef _DARWIN_C_SOURCE\n#endif\n/* Enable general extensions on Solaris.  */\n#ifndef __EXTENSIONS__\n# undef __EXTENSIONS__\n#endif\n/* Enable GNU extensions on systems that have them.  */\n#ifndef _GNU_SOURCE\n# undef _GNU_SOURCE\n#endif\n/* Enable X/Open compliant socket functions that do not require linking\n   with -lxnet on HP-UX 11.11.  */\n#ifndef _HPUX_ALT_XOPEN_SOCKET_API\n# undef _HPUX_ALT_XOPEN_SOCKET_API\n#endif\n/* Identify the host operating system as Minix.\n   This macro does not affect the system headers' behavior.\n   A future release of Autoconf may stop defining this macro.  */\n#ifndef _MINIX\n# undef _MINIX\n#endif\n/* Enable general extensions on NetBSD.\n   Enable NetBSD compatibility extensions on Minix.  */\n#ifndef _NETBSD_SOURCE\n# undef _NETBSD_SOURCE\n#endif\n/* Enable OpenBSD compatibility extensions on NetBSD.\n   Oddly enough, this does nothing on OpenBSD.  */\n#ifndef _OPENBSD_SOURCE\n# undef _OPENBSD_SOURCE\n#endif\n/* Define to 1 if needed for POSIX-compatible behavior.  */\n#ifndef _POSIX_SOURCE\n# undef _POSIX_SOURCE\n#endif\n/* Define to 2 if needed for POSIX-compatible behavior.  */\n#ifndef _POSIX_1_SOURCE\n# undef _POSIX_1_SOURCE\n#endif\n/* Enable POSIX-compatible threading on Solaris.  */\n#ifndef _POSIX_PTHREAD_SEMANTICS\n# undef _POSIX_PTHREAD_SEMANTICS\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */\n#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__\n# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */\n#ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n# undef __STDC_WANT_IEC_60559_BFP_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */\n#ifndef __STDC_WANT_IEC_60559_DFP_EXT__\n# undef __STDC_WANT_IEC_60559_DFP_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */\n#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__\n# undef __STDC_WANT_IEC_60559_FUNCS_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-3:2015.  */\n#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__\n# undef __STDC_WANT_IEC_60559_TYPES_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */\n#ifndef __STDC_WANT_LIB_EXT2__\n# undef __STDC_WANT_LIB_EXT2__\n#endif\n/* Enable extensions specified by ISO/IEC 24747:2009.  */\n#ifndef __STDC_WANT_MATH_SPEC_FUNCS__\n# undef __STDC_WANT_MATH_SPEC_FUNCS__\n#endif\n/* Enable extensions on HP NonStop.  */\n#ifndef _TANDEM_SOURCE\n# undef _TANDEM_SOURCE\n#endif\n/* Enable X/Open extensions.  Define to 500 only if necessary\n   to make mbstate_t available.  */\n#ifndef _XOPEN_SOURCE\n# undef _XOPEN_SOURCE\n#endif\n\n\n/* Version number of package */\n#undef VERSION\n\n/* Define to l, ll, u, ul, ull, etc., as suitable for\r constants of type\n   'wchar_t'. */\n#undef WCHAR_T_SUFFIX\n\n/* Define if WSAStartup is needed. */\n#undef WINDOWS_SOCKETS\n\n/* Define to l, ll, u, ul, ull, etc., as suitable for\r constants of type\n   'wint_t'. */\n#undef WINT_T_SUFFIX\n\n/* True if the compiler says it groks GNU C version MAJOR.MINOR.  */\n#if defined __GNUC__ && defined __GNUC_MINOR__\n# define _GL_GNUC_PREREQ(major, minor) \\\n    ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__))\n#else\n# define _GL_GNUC_PREREQ(major, minor) 0\n#endif\n\n\n/* Define to enable the declarations of ISO C 11 types and functions. */\n#undef _ISOC11_SOURCE\n\n/* The _Noreturn keyword of C11.  */\n#ifndef _Noreturn\n# if (defined __cplusplus \\\n      && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \\\n          || (defined _MSC_VER && 1900 <= _MSC_VER)) \\\n      && 0)\n    /* [[noreturn]] is not practically usable, because with it the syntax\n         extern _Noreturn void func (...);\n       would not be valid; such a declaration would only be valid with 'extern'\n       and '_Noreturn' swapped, or without the 'extern' keyword.  However, some\n       AIX system header files and several gnulib header files use precisely\n       this syntax with 'extern'.  */\n#  define _Noreturn [[noreturn]]\n# elif ((!defined __cplusplus || defined __clang__) \\\n        && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \\\n            || (!defined __STRICT_ANSI__ \\\n                && (_GL_GNUC_PREREQ (4, 7) \\\n                    || (defined __apple_build_version__ \\\n                        ? 6000000 <= __apple_build_version__ \\\n                        : 3 < __clang_major__ + (5 <= __clang_minor__))))))\n   /* _Noreturn works as-is.  */\n# elif _GL_GNUC_PREREQ (2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C\n#  define _Noreturn __attribute__ ((__noreturn__))\n# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)\n#  define _Noreturn __declspec (noreturn)\n# else\n#  define _Noreturn\n# endif\n#endif\n\n\n/* Define to 1 in order to get the POSIX compatible declarations\r of socket\n   functions. */\n#undef _POSIX_PII_SOCKET\n\n/* For standard stat data types on VMS. */\n#undef _USE_STD_STAT\n\n/* Define to 1 if the system <stdint.h> predates C++11. */\n#undef __STDC_CONSTANT_MACROS\n\n/* Define to 1 if the system <stdint.h> predates C++11. */\n#undef __STDC_LIMIT_MACROS\n\n/* The _GL_ASYNC_SAFE marker should be attached to functions that are\n   signal handlers (for signals other than SIGABRT, SIGPIPE) or can be\n   invoked from such signal handlers.  Such functions have some restrictions:\n     * All functions that it calls should be marked _GL_ASYNC_SAFE as well,\n       or should be listed as async-signal-safe in POSIX\n       <https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04>\n       section 2.4.3.  Note that malloc(), sprintf(), and fwrite(), in\n       particular, are NOT async-signal-safe.\n     * All memory locations (variables and struct fields) that these functions\n       access must be marked 'volatile'.  This holds for both read and write\n       accesses.  Otherwise the compiler might optimize away stores to and\n       reads from such locations that occur in the program, depending on its\n       data flow analysis.  For example, when the program contains a loop\n       that is intended to inspect a variable set from within a signal handler\n           while (!signal_occurred)\n             ;\n       the compiler is allowed to transform this into an endless loop if the\n       variable 'signal_occurred' is not declared 'volatile'.\n   Additionally, recall that:\n     * A signal handler should not modify errno (except if it is a handler\n       for a fatal signal and ends by raising the same signal again, thus\n       provoking the termination of the process).  If it invokes a function\n       that may clobber errno, it needs to save and restore the value of\n       errno.  */\n#define _GL_ASYNC_SAFE\n\n\n/* Attributes.  */\n#if (defined __has_attribute \\\n     && (!defined __clang_minor__ \\\n         || 3 < __clang_major__ + (5 <= __clang_minor__)))\n# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__)\n#else\n# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr\n# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2)\n# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_cold _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_const _GL_GNUC_PREREQ (2, 95)\n# define _GL_ATTR_deprecated _GL_GNUC_PREREQ (3, 1)\n# define _GL_ATTR_diagnose_if 0\n# define _GL_ATTR_error _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_externally_visible _GL_GNUC_PREREQ (4, 1)\n# define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0)\n# define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6)\n# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)\n# ifdef _ICC\n#  define _GL_ATTR_may_alias 0\n# else\n#  define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3)\n# endif\n# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)\n# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)\n# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)\n# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3)\n# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96)\n# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9)\n# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0)\n# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)\n#endif\n\n#ifdef __has_c_attribute\n# define _GL_HAS_C_ATTRIBUTE(attr) __has_c_attribute (__##attr##__)\n#else\n# define _GL_HAS_C_ATTRIBUTE(attr) 0\n#endif\n\n\n/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function\n   is the size of the returned memory block.\n   _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied\n   by the Nth argument of the function is the size of the returned memory block.\n */\n/* Applies to: function, pointer to function, function types.  */\n#if _GL_HAS_ATTRIBUTE (alloc_size)\n# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))\n#else\n# define _GL_ATTRIBUTE_ALLOC_SIZE(args)\n#endif\n\n/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the\n   function and report an error if it cannot do so.  */\n/* Applies to: function.  */\n#if _GL_HAS_ATTRIBUTE (always_inline)\n# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__))\n#else\n# define _GL_ATTRIBUTE_ALWAYS_INLINE\n#endif\n\n/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show\n    in stack traces when debugging.  The compiler should omit the function from\n    stack traces.  */\n/* Applies to: function.  */\n#if _GL_HAS_ATTRIBUTE (artificial)\n# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__))\n#else\n# define _GL_ATTRIBUTE_ARTIFICIAL\n#endif\n\n/* _GL_ATTRIBUTE_COLD declares that the function is rarely executed.  */\n/* Applies to: functions.  */\n/* Avoid __attribute__ ((cold)) on MinGW; see thread starting at\n   <https://lists.gnu.org/r/emacs-devel/2019-04/msg01152.html>.\n   Also, Oracle Studio 12.6 requires 'cold' not '__cold__'.  */\n#if _GL_HAS_ATTRIBUTE (cold) && !defined __MINGW32__\n# ifndef __SUNPRO_C\n#  define _GL_ATTRIBUTE_COLD __attribute__ ((__cold__))\n# else\n#  define _GL_ATTRIBUTE_COLD __attribute__ ((cold))\n# endif\n#else\n# define _GL_ATTRIBUTE_COLD\n#endif\n\n/* _GL_ATTRIBUTE_CONST declares that it is OK for a compiler to omit duplicate\n   calls to the function with the same arguments.\n   This attribute is safe for a function that neither depends on nor affects\n   observable state, and always returns exactly once - e.g., does not loop\n   forever, and does not call longjmp.\n   (This attribute is stricter than _GL_ATTRIBUTE_PURE.)  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (const)\n# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__))\n#else\n# define _GL_ATTRIBUTE_CONST\n#endif\n\n/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers\n   that can be freed by passing them as the Ith argument to the\n   function F.\n   _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that\n   can be freed via 'free'; it can be used only after declaring 'free'.  */\n/* Applies to: functions.  Cannot be used on inline functions.  */\n#if _GL_GNUC_PREREQ (11, 0)\n# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))\n#else\n# define _GL_ATTRIBUTE_DEALLOC(f, i)\n#endif\n#define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)\n\n/* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated.\n   The compiler may warn if the entity is used.  */\n/* Applies to:\n     - function, variable,\n     - struct, union, struct/union member,\n     - enumeration, enumeration item,\n     - typedef,\n   in C++ also: namespace, class, template specialization.  */\n#if _GL_HAS_C_ATTRIBUTE (deprecated)\n# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]\n#elif _GL_HAS_ATTRIBUTE (deprecated)\n# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))\n#else\n# define _GL_ATTRIBUTE_DEPRECATED\n#endif\n\n/* _GL_ATTRIBUTE_ERROR(msg) requests an error if a function is called and\n   the function call is not optimized away.\n   _GL_ATTRIBUTE_WARNING(msg) requests a warning if a function is called and\n   the function call is not optimized away.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (error)\n# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg)))\n# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg)))\n#elif _GL_HAS_ATTRIBUTE (diagnose_if)\n# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__diagnose_if__ (1, msg, \"error\")))\n# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__diagnose_if__ (1, msg, \"warning\")))\n#else\n# define _GL_ATTRIBUTE_ERROR(msg)\n# define _GL_ATTRIBUTE_WARNING(msg)\n#endif\n\n/* _GL_ATTRIBUTE_EXTERNALLY_VISIBLE declares that the entity should remain\n   visible to debuggers etc., even with '-fwhole-program'.  */\n/* Applies to: functions, variables.  */\n#if _GL_HAS_ATTRIBUTE (externally_visible)\n# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE __attribute__ ((externally_visible))\n#else\n# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE\n#endif\n\n/* _GL_ATTRIBUTE_FALLTHROUGH declares that it is not a programming mistake if\n   the control flow falls through to the immediately following 'case' or\n   'default' label.  The compiler should not warn in this case.  */\n/* Applies to: Empty statement (;), inside a 'switch' statement.  */\n/* Always expands to something.  */\n#if _GL_HAS_C_ATTRIBUTE (fallthrough)\n# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]]\n#elif _GL_HAS_ATTRIBUTE (fallthrough)\n# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))\n#else\n# define _GL_ATTRIBUTE_FALLTHROUGH ((void) 0)\n#endif\n\n/* _GL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK))\n   declares that the STRING-INDEXth function argument is a format string of\n   style ARCHETYPE, which is one of:\n     printf, gnu_printf\n     scanf, gnu_scanf,\n     strftime, gnu_strftime,\n     strfmon,\n   or the same thing prefixed and suffixed with '__'.\n   If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK\n   are suitable for the format string.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (format)\n# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))\n#else\n# define _GL_ATTRIBUTE_FORMAT(spec)\n#endif\n\n/* _GL_ATTRIBUTE_LEAF declares that if the function is called from some other\n   compilation unit, it executes code from that unit only by return or by\n   exception handling.  This declaration lets the compiler optimize that unit\n   more aggressively.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (leaf)\n# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__))\n#else\n# define _GL_ATTRIBUTE_LEAF\n#endif\n\n/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly\n   allocated memory.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (malloc)\n# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))\n#else\n# define _GL_ATTRIBUTE_MALLOC\n#endif\n\n/* _GL_ATTRIBUTE_MAY_ALIAS declares that pointers to the type may point to the\n   same storage as pointers to other types.  Thus this declaration disables\n   strict aliasing optimization.  */\n/* Applies to: types.  */\n/* Oracle Studio 12.6 mishandles may_alias despite __has_attribute OK.  */\n#if _GL_HAS_ATTRIBUTE (may_alias) && !defined __SUNPRO_C\n# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__))\n#else\n# define _GL_ATTRIBUTE_MAY_ALIAS\n#endif\n\n/* _GL_ATTRIBUTE_MAYBE_UNUSED declares that it is not a programming mistake if\n   the entity is not used.  The compiler should not warn if the entity is not\n   used.  */\n/* Applies to:\n     - function, variable,\n     - struct, union, struct/union member,\n     - enumeration, enumeration item,\n     - typedef,\n   in C++ also: class.  */\n/* In C++ and C2x, this is spelled [[__maybe_unused__]].\n   GCC's syntax is __attribute__ ((__unused__)).\n   clang supports both syntaxes.  */\n#if _GL_HAS_C_ATTRIBUTE (maybe_unused)\n# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]\n#else\n# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED\n#endif\n/* Alternative spelling of this macro, for convenience.  */\n#define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED\n/* Earlier spellings of this macro.  */\n#define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED\n\n/* _GL_ATTRIBUTE_NODISCARD declares that the caller of the function should not\n   discard the return value.  The compiler may warn if the caller does not use\n   the return value, unless the caller uses something like ignore_value.  */\n/* Applies to: function, enumeration, class.  */\n#if _GL_HAS_C_ATTRIBUTE (nodiscard)\n# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]\n#elif _GL_HAS_ATTRIBUTE (warn_unused_result)\n# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__))\n#else\n# define _GL_ATTRIBUTE_NODISCARD\n#endif\n\n/* _GL_ATTRIBUTE_NOINLINE tells that the compiler should not inline the\n   function.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (noinline)\n# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__))\n#else\n# define _GL_ATTRIBUTE_NOINLINE\n#endif\n\n/* _GL_ATTRIBUTE_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,...\n   must not be NULL.\n   _GL_ATTRIBUTE_NONNULL () declares that all pointer arguments must not be\n   null.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (nonnull)\n# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args))\n#else\n# define _GL_ATTRIBUTE_NONNULL(args)\n#endif\n\n/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is\n   not meant to be NUL-terminated.  */\n/* Applies to: struct/union members and variables that are arrays of element\n   type '[[un]signed] char'.  */\n#if _GL_HAS_ATTRIBUTE (nonstring)\n# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))\n#else\n# define _GL_ATTRIBUTE_NONSTRING\n#endif\n\n/* There is no _GL_ATTRIBUTE_NORETURN; use _Noreturn instead.  */\n\n/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.\n */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (nothrow) && !defined __cplusplus\n# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))\n#else\n# define _GL_ATTRIBUTE_NOTHROW\n#endif\n\n/* _GL_ATTRIBUTE_PACKED declares:\n   For struct members: The member has the smallest possible alignment.\n   For struct, union, class: All members have the smallest possible alignment,\n   minimizing the memory required.  */\n/* Applies to: struct members, struct, union,\n   in C++ also: class.  */\n#if _GL_HAS_ATTRIBUTE (packed)\n# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))\n#else\n# define _GL_ATTRIBUTE_PACKED\n#endif\n\n/* _GL_ATTRIBUTE_PURE declares that It is OK for a compiler to omit duplicate\n   calls to the function with the same arguments if observable state is not\n   changed between calls.\n   This attribute is safe for a function that does not affect\n   observable state, and always returns exactly once.\n   (This attribute is looser than _GL_ATTRIBUTE_CONST.)  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (pure)\n# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))\n#else\n# define _GL_ATTRIBUTE_PURE\n#endif\n\n/* _GL_ATTRIBUTE_RETURNS_NONNULL declares that the function's return value is\n   a non-NULL pointer.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (returns_nonnull)\n# define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))\n#else\n# define _GL_ATTRIBUTE_RETURNS_NONNULL\n#endif\n\n/* _GL_ATTRIBUTE_SENTINEL(pos) declares that the variadic function expects a\n   trailing NULL argument.\n   _GL_ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99).\n   _GL_ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (sentinel)\n# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos))\n#else\n# define _GL_ATTRIBUTE_SENTINEL(pos)\n#endif\n\n/* A helper macro.  Don't use it directly.  */\n#if _GL_HAS_ATTRIBUTE (unused)\n# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__))\n#else\n# define _GL_ATTRIBUTE_UNUSED\n#endif\n\n\n/* _GL_UNUSED_LABEL; declares that it is not a programming mistake if the\n   immediately preceding label is not used.  The compiler should not warn\n   if the label is not used.  */\n/* Applies to: label (both in C and C++).  */\n/* Note that g++ < 4.5 does not support the '__attribute__ ((__unused__)) ;'\n   syntax.  But clang does.  */\n#if !(defined __cplusplus && !_GL_GNUC_PREREQ (4, 5)) || defined __clang__\n# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED\n#else\n# define _GL_UNUSED_LABEL\n#endif\n\n\n/* Please see the Gnulib manual for how to use these macros.\n\n   Suppress extern inline with HP-UX cc, as it appears to be broken; see\n   <https://lists.gnu.org/r/bug-texinfo/2013-02/msg00030.html>.\n\n   Suppress extern inline with Sun C in standards-conformance mode, as it\n   mishandles inline functions that call each other.  E.g., for 'inline void f\n   (void) { } inline void g (void) { f (); }', c99 incorrectly complains\n   'reference to static identifier \"f\" in extern inline function'.\n   This bug was observed with Oracle Developer Studio 12.6\n   (Sun C 5.15 SunOS_sparc 2017/05/30).\n\n   Suppress extern inline (with or without __attribute__ ((__gnu_inline__)))\n   on configurations that mistakenly use 'static inline' to implement\n   functions or macros in standard C headers like <ctype.h>.  For example,\n   if isdigit is mistakenly implemented via a static inline function,\n   a program containing an extern inline function that calls isdigit\n   may not work since the C standard prohibits extern inline functions\n   from calling static functions (ISO C 99 section 6.7.4.(3).\n   This bug is known to occur on:\n\n     OS X 10.8 and earlier; see:\n     https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html\n\n     DragonFly; see\n     http://muscles.dragonflybsd.org/bulk/clang-master-potential/20141111_102002/logs/ah-tty-0.3.12.log\n\n     FreeBSD; see:\n     https://lists.gnu.org/r/bug-gnulib/2014-07/msg00104.html\n\n   OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and\n   for clang but remains for g++; see <https://trac.macports.org/ticket/41033>.\n   Assume DragonFly and FreeBSD will be similar.\n\n   GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99\n   inline semantics, unless -fgnu89-inline is used.  It defines a macro\n   __GNUC_STDC_INLINE__ to indicate this situation or a macro\n   __GNUC_GNU_INLINE__ to indicate the opposite situation.\n   GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline\n   semantics but warns, unless -fgnu89-inline is used:\n     warning: C99 inline functions are not supported; using GNU89\n     warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute\n   It defines a macro __GNUC_GNU_INLINE__ to indicate this situation.\n */\n#if (((defined __APPLE__ && defined __MACH__) \\\n      || defined __DragonFly__ || defined __FreeBSD__) \\\n     && (defined __header_inline \\\n         ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ \\\n            && ! defined __clang__) \\\n         : ((! defined _DONT_USE_CTYPE_INLINE_ \\\n             && (defined __GNUC__ || defined __cplusplus)) \\\n            || (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE \\\n                && defined __GNUC__ && ! defined __cplusplus))))\n# define _GL_EXTERN_INLINE_STDHEADER_BUG\n#endif\n#if ((__GNUC__ \\\n      ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \\\n      : (199901L <= __STDC_VERSION__ \\\n         && !defined __HP_cc \\\n         && !defined __PGI \\\n         && !(defined __SUNPRO_C && __STDC__))) \\\n     && !defined _GL_EXTERN_INLINE_STDHEADER_BUG)\n# define _GL_INLINE inline\n# define _GL_EXTERN_INLINE extern inline\n# define _GL_EXTERN_INLINE_IN_USE\n#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \\\n       && !defined _GL_EXTERN_INLINE_STDHEADER_BUG)\n# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__\n   /* __gnu_inline__ suppresses a GCC 4.2 diagnostic.  */\n#  define _GL_INLINE extern inline __attribute__ ((__gnu_inline__))\n# else\n#  define _GL_INLINE extern inline\n# endif\n# define _GL_EXTERN_INLINE extern\n# define _GL_EXTERN_INLINE_IN_USE\n#else\n# define _GL_INLINE _GL_UNUSED static\n# define _GL_EXTERN_INLINE _GL_UNUSED static\n#endif\n\n/* In GCC 4.6 (inclusive) to 5.1 (exclusive),\n   suppress bogus \"no previous prototype for 'FOO'\"\n   and \"no previous declaration for 'FOO'\" diagnostics,\n   when FOO is an inline function in the header; see\n   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113> and\n   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63877>.  */\n#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__\n# if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__\n#  define _GL_INLINE_HEADER_CONST_PRAGMA\n# else\n#  define _GL_INLINE_HEADER_CONST_PRAGMA \\\n     _Pragma (\"GCC diagnostic ignored \\\"-Wsuggest-attribute=const\\\"\")\n# endif\n# define _GL_INLINE_HEADER_BEGIN \\\n    _Pragma (\"GCC diagnostic push\") \\\n    _Pragma (\"GCC diagnostic ignored \\\"-Wmissing-prototypes\\\"\") \\\n    _Pragma (\"GCC diagnostic ignored \\\"-Wmissing-declarations\\\"\") \\\n    _GL_INLINE_HEADER_CONST_PRAGMA\n# define _GL_INLINE_HEADER_END \\\n    _Pragma (\"GCC diagnostic pop\")\n#else\n# define _GL_INLINE_HEADER_BEGIN\n# define _GL_INLINE_HEADER_END\n#endif\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n#undef inline\n#endif\n\n/* Work around a bug in Apple GCC 4.0.1 build 5465: In C99 mode, it supports\n   the ISO C 99 semantics of 'extern inline' (unlike the GNU C semantics of\n   earlier versions), but does not display it by setting __GNUC_STDC_INLINE__.\n   __APPLE__ && __MACH__ test for Mac OS X.\n   __APPLE_CC__ tests for the Apple compiler and its version.\n   __STDC_VERSION__ tests for the C99 mode.  */\n#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && !defined __cplusplus && __STDC_VERSION__ >= 199901L && !defined __GNUC_STDC_INLINE__\n# define __GNUC_STDC_INLINE__ 1\n#endif\n\n/* _GL_CMP (n1, n2) performs a three-valued comparison on n1 vs. n2, where\n   n1 and n2 are expressions without side effects, that evaluate to real\n   numbers (excluding NaN).\n   It returns\n     1  if n1 > n2\n     0  if n1 == n2\n     -1 if n1 < n2\n   The naïve code   (n1 > n2 ? 1 : n1 < n2 ? -1 : 0)  produces a conditional\n   jump with nearly all GCC versions up to GCC 10.\n   This variant     (n1 < n2 ? -1 : n1 > n2)  produces a conditional with many\n   GCC versions up to GCC 9.\n   The better code  (n1 > n2) - (n1 < n2)  from Hacker's Delight § 2-9\n   avoids conditional jumps in all GCC versions >= 3.4.  */\n#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))\n\n\n/* Define to `int' if <sys/types.h> does not define. */\n#undef mode_t\n\n/* Define to the type of st_nlink in struct stat, or a supertype. */\n#undef nlink_t\n\n/* Define as a signed integer type capable of holding a process identifier. */\n#undef pid_t\n\n/* Define to the equivalent of the C99 'restrict' keyword, or to\n   nothing if this is not supported.  Do not define if restrict is\n   supported only directly.  */\n#undef restrict\n/* Work around a bug in older versions of Sun C++, which did not\n   #define __restrict__ or support _Restrict or __restrict__\n   even though the corresponding Sun C compiler ended up with\n   \"#define restrict _Restrict\" or \"#define restrict __restrict__\"\n   in the previous line.  This workaround can be removed once\n   we assume Oracle Developer Studio 12.5 (2016) or later.  */\n#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__\n# define _Restrict\n# define __restrict__\n#endif\n\n/* type to use in place of socklen_t if not defined */\n#undef socklen_t\n\n/* Define as a signed type of the same size as size_t. */\n#undef ssize_t\n"
  },
  {
    "path": "windows_compat/gnulib/configure",
    "content": "#! /bin/sh\n# Guess values for system-dependent variables and create Makefiles.\n# Generated by GNU Autoconf 2.71 for dummy 0.\n#\n#\n# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,\n# Inc.\n#\n#\n# This configure script is free software; the Free Software Foundation\n# gives unlimited permission to copy, distribute and modify it.\n## -------------------- ##\n## M4sh Initialization. ##\n## -------------------- ##\n\n# Be more Bourne compatible\nDUALCASE=1; export DUALCASE # for MKS sh\nas_nop=:\nif test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1\nthen :\n  emulate sh\n  NULLCMD=:\n  # Pre-4.2 versions of Zsh do word splitting on ${1+\"$@\"}, which\n  # is contrary to our usage.  Disable this feature.\n  alias -g '${1+\"$@\"}'='\"$@\"'\n  setopt NO_GLOB_SUBST\nelse $as_nop\n  case `(set -o) 2>/dev/null` in #(\n  *posix*) :\n    set -o posix ;; #(\n  *) :\n     ;;\nesac\nfi\n\n\n\n# Reset variables that may have inherited troublesome values from\n# the environment.\n\n# IFS needs to be set, to space, tab, and newline, in precisely that order.\n# (If _AS_PATH_WALK were called with IFS unset, it would have the\n# side effect of setting IFS to empty, thus disabling word splitting.)\n# Quoting is to prevent editors from complaining about space-tab.\nas_nl='\n'\nexport as_nl\nIFS=\" \"\"\t$as_nl\"\n\nPS1='$ '\nPS2='> '\nPS4='+ '\n\n# Ensure predictable behavior from utilities with locale-dependent output.\nLC_ALL=C\nexport LC_ALL\nLANGUAGE=C\nexport LANGUAGE\n\n# We cannot yet rely on \"unset\" to work, but we need these variables\n# to be unset--not just set to an empty or harmless value--now, to\n# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh).  This construct\n# also avoids known problems related to \"unset\" and subshell syntax\n# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).\nfor as_var in BASH_ENV ENV MAIL MAILPATH CDPATH\ndo eval test \\${$as_var+y} \\\n  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :\ndone\n\n# Ensure that fds 0, 1, and 2 are open.\nif (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi\nif (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi\nif (exec 3>&2)            ; then :; else exec 2>/dev/null; fi\n\n# The user is always right.\nif ${PATH_SEPARATOR+false} :; then\n  PATH_SEPARATOR=:\n  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {\n    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||\n      PATH_SEPARATOR=';'\n  }\nfi\n\n\n# Find who we are.  Look in the path if we contain no directory separator.\nas_myself=\ncase $0 in #((\n  *[\\\\/]* ) as_myself=$0 ;;\n  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    test -r \"$as_dir$0\" && as_myself=$as_dir$0 && break\n  done\nIFS=$as_save_IFS\n\n     ;;\nesac\n# We did not find ourselves, most probably we were run as `sh COMMAND'\n# in which case we are not to be found in the path.\nif test \"x$as_myself\" = x; then\n  as_myself=$0\nfi\nif test ! -f \"$as_myself\"; then\n  printf \"%s\\n\" \"$as_myself: error: cannot find myself; rerun with an absolute file name\" >&2\n  exit 1\nfi\n\n\n# Use a proper internal environment variable to ensure we don't fall\n  # into an infinite loop, continuously re-executing ourselves.\n  if test x\"${_as_can_reexec}\" != xno && test \"x$CONFIG_SHELL\" != x; then\n    _as_can_reexec=no; export _as_can_reexec;\n    # We cannot yet assume a decent shell, so we have to provide a\n# neutralization value for shells without unset; and this also\n# works around shells that cannot unset nonexistent variables.\n# Preserve -v and -x to the replacement shell.\nBASH_ENV=/dev/null\nENV=/dev/null\n(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV\ncase $- in # ((((\n  *v*x* | *x*v* ) as_opts=-vx ;;\n  *v* ) as_opts=-v ;;\n  *x* ) as_opts=-x ;;\n  * ) as_opts= ;;\nesac\nexec $CONFIG_SHELL $as_opts \"$as_myself\" ${1+\"$@\"}\n# Admittedly, this is quite paranoid, since all the known shells bail\n# out after a failed `exec'.\nprintf \"%s\\n\" \"$0: could not re-execute with $CONFIG_SHELL\" >&2\nexit 255\n  fi\n  # We don't want this to propagate to other subprocesses.\n          { _as_can_reexec=; unset _as_can_reexec;}\nif test \"x$CONFIG_SHELL\" = x; then\n  as_bourne_compatible=\"as_nop=:\nif test \\${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1\nthen :\n  emulate sh\n  NULLCMD=:\n  # Pre-4.2 versions of Zsh do word splitting on \\${1+\\\"\\$@\\\"}, which\n  # is contrary to our usage.  Disable this feature.\n  alias -g '\\${1+\\\"\\$@\\\"}'='\\\"\\$@\\\"'\n  setopt NO_GLOB_SUBST\nelse \\$as_nop\n  case \\`(set -o) 2>/dev/null\\` in #(\n  *posix*) :\n    set -o posix ;; #(\n  *) :\n     ;;\nesac\nfi\n\"\n  as_required=\"as_fn_return () { (exit \\$1); }\nas_fn_success () { as_fn_return 0; }\nas_fn_failure () { as_fn_return 1; }\nas_fn_ret_success () { return 0; }\nas_fn_ret_failure () { return 1; }\n\nexitcode=0\nas_fn_success || { exitcode=1; echo as_fn_success failed.; }\nas_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }\nas_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }\nas_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }\nif ( set x; as_fn_ret_success y && test x = \\\"\\$1\\\" )\nthen :\n\nelse \\$as_nop\n  exitcode=1; echo positional parameters were not saved.\nfi\ntest x\\$exitcode = x0 || exit 1\nblah=\\$(echo \\$(echo blah))\ntest x\\\"\\$blah\\\" = xblah || exit 1\ntest -x / || exit 1\"\n  as_suggested=\"  as_lineno_1=\";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested\" as_lineno_1a=\\$LINENO\n  as_lineno_2=\";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested\" as_lineno_2a=\\$LINENO\n  eval 'test \\\"x\\$as_lineno_1'\\$as_run'\\\" != \\\"x\\$as_lineno_2'\\$as_run'\\\" &&\n  test \\\"x\\`expr \\$as_lineno_1'\\$as_run' + 1\\`\\\" = \\\"x\\$as_lineno_2'\\$as_run'\\\"' || exit 1\ntest \\$(( 1 + 1 )) = 2 || exit 1\"\n  if (eval \"$as_required\") 2>/dev/null\nthen :\n  as_have_required=yes\nelse $as_nop\n  as_have_required=no\nfi\n  if test x$as_have_required = xyes && (eval \"$as_suggested\") 2>/dev/null\nthen :\n\nelse $as_nop\n  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nas_found=false\nfor as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n  as_found=:\n  case $as_dir in #(\n\t /*)\n\t   for as_base in sh bash ksh sh5; do\n\t     # Try only shells that exist, to save several forks.\n\t     as_shell=$as_dir$as_base\n\t     if { test -f \"$as_shell\" || test -f \"$as_shell.exe\"; } &&\n\t\t    as_run=a \"$as_shell\" -c \"$as_bourne_compatible\"\"$as_required\" 2>/dev/null\nthen :\n  CONFIG_SHELL=$as_shell as_have_required=yes\n\t\t   if as_run=a \"$as_shell\" -c \"$as_bourne_compatible\"\"$as_suggested\" 2>/dev/null\nthen :\n  break 2\nfi\nfi\n\t   done;;\n       esac\n  as_found=false\ndone\nIFS=$as_save_IFS\nif $as_found\nthen :\n\nelse $as_nop\n  if { test -f \"$SHELL\" || test -f \"$SHELL.exe\"; } &&\n\t      as_run=a \"$SHELL\" -c \"$as_bourne_compatible\"\"$as_required\" 2>/dev/null\nthen :\n  CONFIG_SHELL=$SHELL as_have_required=yes\nfi\nfi\n\n\n      if test \"x$CONFIG_SHELL\" != x\nthen :\n  export CONFIG_SHELL\n             # We cannot yet assume a decent shell, so we have to provide a\n# neutralization value for shells without unset; and this also\n# works around shells that cannot unset nonexistent variables.\n# Preserve -v and -x to the replacement shell.\nBASH_ENV=/dev/null\nENV=/dev/null\n(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV\ncase $- in # ((((\n  *v*x* | *x*v* ) as_opts=-vx ;;\n  *v* ) as_opts=-v ;;\n  *x* ) as_opts=-x ;;\n  * ) as_opts= ;;\nesac\nexec $CONFIG_SHELL $as_opts \"$as_myself\" ${1+\"$@\"}\n# Admittedly, this is quite paranoid, since all the known shells bail\n# out after a failed `exec'.\nprintf \"%s\\n\" \"$0: could not re-execute with $CONFIG_SHELL\" >&2\nexit 255\nfi\n\n    if test x$as_have_required = xno\nthen :\n  printf \"%s\\n\" \"$0: This script requires a shell more modern than all\"\n  printf \"%s\\n\" \"$0: the shells that I found on your system.\"\n  if test ${ZSH_VERSION+y} ; then\n    printf \"%s\\n\" \"$0: In particular, zsh $ZSH_VERSION has bugs and should\"\n    printf \"%s\\n\" \"$0: be upgraded to zsh 4.3.4 or later.\"\n  else\n    printf \"%s\\n\" \"$0: Please tell bug-autoconf@gnu.org about your system,\n$0: including any error possibly output before this\n$0: message. Then install a modern shell, or manually run\n$0: the script under such a shell if you do have one.\"\n  fi\n  exit 1\nfi\nfi\nfi\nSHELL=${CONFIG_SHELL-/bin/sh}\nexport SHELL\n# Unset more variables known to interfere with behavior of common tools.\nCLICOLOR_FORCE= GREP_OPTIONS=\nunset CLICOLOR_FORCE GREP_OPTIONS\n\n## --------------------- ##\n## M4sh Shell Functions. ##\n## --------------------- ##\n# as_fn_unset VAR\n# ---------------\n# Portably unset VAR.\nas_fn_unset ()\n{\n  { eval $1=; unset $1;}\n}\nas_unset=as_fn_unset\n\n\n# as_fn_set_status STATUS\n# -----------------------\n# Set $? to STATUS, without forking.\nas_fn_set_status ()\n{\n  return $1\n} # as_fn_set_status\n\n# as_fn_exit STATUS\n# -----------------\n# Exit the shell with STATUS, even in a \"trap 0\" or \"set -e\" context.\nas_fn_exit ()\n{\n  set +e\n  as_fn_set_status $1\n  exit $1\n} # as_fn_exit\n# as_fn_nop\n# ---------\n# Do nothing but, unlike \":\", preserve the value of $?.\nas_fn_nop ()\n{\n  return $?\n}\nas_nop=as_fn_nop\n\n# as_fn_mkdir_p\n# -------------\n# Create \"$as_dir\" as a directory, including parents if necessary.\nas_fn_mkdir_p ()\n{\n\n  case $as_dir in #(\n  -*) as_dir=./$as_dir;;\n  esac\n  test -d \"$as_dir\" || eval $as_mkdir_p || {\n    as_dirs=\n    while :; do\n      case $as_dir in #(\n      *\\'*) as_qdir=`printf \"%s\\n\" \"$as_dir\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"`;; #'(\n      *) as_qdir=$as_dir;;\n      esac\n      as_dirs=\"'$as_qdir' $as_dirs\"\n      as_dir=`$as_dirname -- \"$as_dir\" ||\n$as_expr X\"$as_dir\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$as_dir\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$as_dir\" : 'X\\(//\\)$' \\| \\\n\t X\"$as_dir\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$as_dir\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n      test -d \"$as_dir\" && break\n    done\n    test -z \"$as_dirs\" || eval \"mkdir $as_dirs\"\n  } || test -d \"$as_dir\" || as_fn_error $? \"cannot create directory $as_dir\"\n\n\n} # as_fn_mkdir_p\n\n# as_fn_executable_p FILE\n# -----------------------\n# Test if FILE is an executable regular file.\nas_fn_executable_p ()\n{\n  test -f \"$1\" && test -x \"$1\"\n} # as_fn_executable_p\n# as_fn_append VAR VALUE\n# ----------------------\n# Append the text in VALUE to the end of the definition contained in VAR. Take\n# advantage of any shell optimizations that allow amortized linear growth over\n# repeated appends, instead of the typical quadratic growth present in naive\n# implementations.\nif (eval \"as_var=1; as_var+=2; test x\\$as_var = x12\") 2>/dev/null\nthen :\n  eval 'as_fn_append ()\n  {\n    eval $1+=\\$2\n  }'\nelse $as_nop\n  as_fn_append ()\n  {\n    eval $1=\\$$1\\$2\n  }\nfi # as_fn_append\n\n# as_fn_arith ARG...\n# ------------------\n# Perform arithmetic evaluation on the ARGs, and store the result in the\n# global $as_val. Take advantage of shells that can avoid forks. The arguments\n# must be portable across $(()) and expr.\nif (eval \"test \\$(( 1 + 1 )) = 2\") 2>/dev/null\nthen :\n  eval 'as_fn_arith ()\n  {\n    as_val=$(( $* ))\n  }'\nelse $as_nop\n  as_fn_arith ()\n  {\n    as_val=`expr \"$@\" || test $? -eq 1`\n  }\nfi # as_fn_arith\n\n# as_fn_nop\n# ---------\n# Do nothing but, unlike \":\", preserve the value of $?.\nas_fn_nop ()\n{\n  return $?\n}\nas_nop=as_fn_nop\n\n# as_fn_error STATUS ERROR [LINENO LOG_FD]\n# ----------------------------------------\n# Output \"`basename $0`: error: ERROR\" to stderr. If LINENO and LOG_FD are\n# provided, also output the error to LOG_FD, referencing LINENO. Then exit the\n# script with STATUS, using 1 if that was 0.\nas_fn_error ()\n{\n  as_status=$1; test $as_status -eq 0 && as_status=1\n  if test \"$4\"; then\n    as_lineno=${as_lineno-\"$3\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: $2\" >&$4\n  fi\n  printf \"%s\\n\" \"$as_me: error: $2\" >&2\n  as_fn_exit $as_status\n} # as_fn_error\n\nif expr a : '\\(a\\)' >/dev/null 2>&1 &&\n   test \"X`expr 00001 : '.*\\(...\\)'`\" = X001; then\n  as_expr=expr\nelse\n  as_expr=false\nfi\n\nif (basename -- /) >/dev/null 2>&1 && test \"X`basename -- / 2>&1`\" = \"X/\"; then\n  as_basename=basename\nelse\n  as_basename=false\nfi\n\nif (as_dir=`dirname -- /` && test \"X$as_dir\" = X/) >/dev/null 2>&1; then\n  as_dirname=dirname\nelse\n  as_dirname=false\nfi\n\nas_me=`$as_basename -- \"$0\" ||\n$as_expr X/\"$0\" : '.*/\\([^/][^/]*\\)/*$' \\| \\\n\t X\"$0\" : 'X\\(//\\)$' \\| \\\n\t X\"$0\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X/\"$0\" |\n    sed '/^.*\\/\\([^/][^/]*\\)\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n\n# Avoid depending upon Character Ranges.\nas_cr_letters='abcdefghijklmnopqrstuvwxyz'\nas_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'\nas_cr_Letters=$as_cr_letters$as_cr_LETTERS\nas_cr_digits='0123456789'\nas_cr_alnum=$as_cr_Letters$as_cr_digits\n\n\n  as_lineno_1=$LINENO as_lineno_1a=$LINENO\n  as_lineno_2=$LINENO as_lineno_2a=$LINENO\n  eval 'test \"x$as_lineno_1'$as_run'\" != \"x$as_lineno_2'$as_run'\" &&\n  test \"x`expr $as_lineno_1'$as_run' + 1`\" = \"x$as_lineno_2'$as_run'\"' || {\n  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)\n  sed -n '\n    p\n    /[$]LINENO/=\n  ' <$as_myself |\n    sed '\n      s/[$]LINENO.*/&-/\n      t lineno\n      b\n      :lineno\n      N\n      :loop\n      s/[$]LINENO\\([^'$as_cr_alnum'_].*\\n\\)\\(.*\\)/\\2\\1\\2/\n      t loop\n      s/-\\n.*//\n    ' >$as_me.lineno &&\n  chmod +x \"$as_me.lineno\" ||\n    { printf \"%s\\n\" \"$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell\" >&2; as_fn_exit 1; }\n\n  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have\n  # already done that, so ensure we don't try to do so again and fall\n  # in an infinite loop.  This has already happened in practice.\n  _as_can_reexec=no; export _as_can_reexec\n  # Don't try to exec as it changes $[0], causing all sort of problems\n  # (the dirname of $[0] is not the place where we might find the\n  # original and so on.  Autoconf is especially sensitive to this).\n  . \"./$as_me.lineno\"\n  # Exit status is that of the last command.\n  exit\n}\n\n\n# Determine whether it's possible to make 'echo' print without a newline.\n# These variables are no longer used directly by Autoconf, but are AC_SUBSTed\n# for compatibility with existing Makefiles.\nECHO_C= ECHO_N= ECHO_T=\ncase `echo -n x` in #(((((\n-n*)\n  case `echo 'xy\\c'` in\n  *c*) ECHO_T='\t';;\t# ECHO_T is single tab character.\n  xy)  ECHO_C='\\c';;\n  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null\n       ECHO_T='\t';;\n  esac;;\n*)\n  ECHO_N='-n';;\nesac\n\n# For backward compatibility with old third-party macros, we provide\n# the shell variables $as_echo and $as_echo_n.  New code should use\n# AS_ECHO([\"message\"]) and AS_ECHO_N([\"message\"]), respectively.\nas_echo='printf %s\\n'\nas_echo_n='printf %s'\n\n\nrm -f conf$$ conf$$.exe conf$$.file\nif test -d conf$$.dir; then\n  rm -f conf$$.dir/conf$$.file\nelse\n  rm -f conf$$.dir\n  mkdir conf$$.dir 2>/dev/null\nfi\nif (echo >conf$$.file) 2>/dev/null; then\n  if ln -s conf$$.file conf$$ 2>/dev/null; then\n    as_ln_s='ln -s'\n    # ... but there are two gotchas:\n    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.\n    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.\n    # In both cases, we have to default to `cp -pR'.\n    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||\n      as_ln_s='cp -pR'\n  elif ln conf$$.file conf$$ 2>/dev/null; then\n    as_ln_s=ln\n  else\n    as_ln_s='cp -pR'\n  fi\nelse\n  as_ln_s='cp -pR'\nfi\nrm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file\nrmdir conf$$.dir 2>/dev/null\n\nif mkdir -p . 2>/dev/null; then\n  as_mkdir_p='mkdir -p \"$as_dir\"'\nelse\n  test -d ./-p && rmdir ./-p\n  as_mkdir_p=false\nfi\n\nas_test_x='test -x'\nas_executable_p=as_fn_executable_p\n\n# Sed expression to map a string onto a valid CPP name.\nas_tr_cpp=\"eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'\"\n\n# Sed expression to map a string onto a valid variable name.\nas_tr_sh=\"eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'\"\n\n\ntest -n \"$DJDIR\" || exec 7<&0 </dev/null\nexec 6>&1\n\n# Name of the host.\n# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,\n# so uname gets run too.\nac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`\n\n#\n# Initializations.\n#\nac_default_prefix=/usr/local\nac_clean_files=\nac_config_libobj_dir=.\nLIBOBJS=\ncross_compiling=no\nsubdirs=\nMFLAGS=\nMAKEFLAGS=\n\n# Identity of this package.\nPACKAGE_NAME='dummy'\nPACKAGE_TARNAME='dummy'\nPACKAGE_VERSION='0'\nPACKAGE_STRING='dummy 0'\nPACKAGE_BUGREPORT=''\nPACKAGE_URL=''\n\n# Factoring default headers for most tests.\nac_includes_default=\"\\\n#include <stddef.h>\n#ifdef HAVE_STDIO_H\n# include <stdio.h>\n#endif\n#ifdef HAVE_STDLIB_H\n# include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n# include <string.h>\n#endif\n#ifdef HAVE_INTTYPES_H\n# include <inttypes.h>\n#endif\n#ifdef HAVE_STDINT_H\n# include <stdint.h>\n#endif\n#ifdef HAVE_STRINGS_H\n# include <strings.h>\n#endif\n#ifdef HAVE_SYS_TYPES_H\n# include <sys/types.h>\n#endif\n#ifdef HAVE_SYS_STAT_H\n# include <sys/stat.h>\n#endif\n#ifdef HAVE_UNISTD_H\n# include <unistd.h>\n#endif\"\n\nac_header_c_list=\nac_func_c_list=\nac_subst_vars='gl_LTLIBOBJS\ngl_LIBOBJS\nam__EXEEXT_FALSE\nam__EXEEXT_TRUE\nLTLIBOBJS\nLIBOBJS\nLIBGNU_LTLIBDEPS\nLIBGNU_LIBDEPS\nHAVE_UNISTD_H\nNEXT_AS_FIRST_DIRECTIVE_UNISTD_H\nNEXT_UNISTD_H\nGL_GNULIB_MDA_TZSET\nGL_GNULIB_TZSET\nGL_GNULIB_TIME_RZ\nGL_GNULIB_TIME_R\nGL_GNULIB_TIMESPEC_GET\nGL_GNULIB_TIMEGM\nGL_GNULIB_STRPTIME\nGL_GNULIB_STRFTIME\nGL_GNULIB_NANOSLEEP\nGL_GNULIB_LOCALTIME\nGL_GNULIB_MKTIME\nGL_GNULIB_CTIME\nTIME_H_DEFINES_TIME_UTC\nUNISTD_H_DEFINES_STRUCT_TIMESPEC\nPTHREAD_H_DEFINES_STRUCT_TIMESPEC\nSYS_TIME_H_DEFINES_STRUCT_TIMESPEC\nTIME_H_DEFINES_STRUCT_TIMESPEC\nNEXT_AS_FIRST_DIRECTIVE_TIME_H\nNEXT_TIME_H\nREPLACE_LOCALTIME\nREPLACE_GMTIME\nGNULIB_GETTIMEOFDAY\nREPLACE_TZSET\nREPLACE_TIMEGM\nREPLACE_STRFTIME\nREPLACE_NANOSLEEP\nREPLACE_MKTIME\nREPLACE_LOCALTIME_R\nREPLACE_CTIME\nHAVE_TIMEZONE_T\nHAVE_TIMESPEC_GET\nHAVE_TIMEGM\nHAVE_STRPTIME\nHAVE_NANOSLEEP\nHAVE_DECL_LOCALTIME_R\nGL_GNULIB_UNAME\nHAVE_SYS_UTSNAME_H\nNEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H\nNEXT_SYS_UTSNAME_H\nHAVE_STRUCT_UTSNAME\nHAVE_UNAME\nHAVE_SYS_UIO_H\nNEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H\nNEXT_SYS_UIO_H\nWINDOWS_STAT_INODES\nWINDOWS_64_BIT_OFF_T\nNEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H\nNEXT_SYS_TYPES_H\nGL_GNULIB_MDA_UMASK\nGL_GNULIB_MDA_MKDIR\nGL_GNULIB_MDA_CHMOD\nGL_GNULIB_OVERRIDES_STRUCT_STAT\nGL_GNULIB_UTIMENSAT\nGL_GNULIB_STAT\nGL_GNULIB_MKNODAT\nGL_GNULIB_MKNOD\nGL_GNULIB_MKFIFOAT\nGL_GNULIB_MKFIFO\nGL_GNULIB_MKDIRAT\nGL_GNULIB_MKDIR\nGL_GNULIB_LSTAT\nGL_GNULIB_LCHMOD\nGL_GNULIB_GETUMASK\nGL_GNULIB_FUTIMENS\nGL_GNULIB_FSTATAT\nGL_GNULIB_FSTAT\nGL_GNULIB_FCHMODAT\nWINDOWS_64_BIT_ST_SIZE\nWINDOWS_STAT_TIMESPEC\nNEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H\nNEXT_SYS_STAT_H\nREPLACE_UTIMENSAT\nREPLACE_STAT\nREPLACE_MKNODAT\nREPLACE_MKNOD\nREPLACE_MKFIFOAT\nREPLACE_MKFIFO\nREPLACE_MKDIR\nREPLACE_LSTAT\nREPLACE_FUTIMENS\nREPLACE_FSTATAT\nREPLACE_FSTAT\nREPLACE_FCHMODAT\nHAVE_UTIMENSAT\nHAVE_MKNODAT\nHAVE_MKNOD\nHAVE_MKFIFOAT\nHAVE_MKFIFO\nHAVE_MKDIRAT\nHAVE_LSTAT\nHAVE_LCHMOD\nHAVE_GETUMASK\nHAVE_FUTIMENS\nHAVE_FSTATAT\nHAVE_FCHMODAT\nGL_GNULIB_ACCEPT4\nGL_GNULIB_SHUTDOWN\nGL_GNULIB_SETSOCKOPT\nGL_GNULIB_SENDTO\nGL_GNULIB_RECVFROM\nGL_GNULIB_SEND\nGL_GNULIB_RECV\nGL_GNULIB_LISTEN\nGL_GNULIB_GETSOCKOPT\nGL_GNULIB_GETSOCKNAME\nGL_GNULIB_GETPEERNAME\nGL_GNULIB_BIND\nGL_GNULIB_ACCEPT\nGL_GNULIB_CONNECT\nGL_GNULIB_SOCKET\nHAVE_WS2TCPIP_H\nHAVE_SYS_SOCKET_H\nNEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H\nNEXT_SYS_SOCKET_H\nHAVE_ACCEPT4\nHAVE_SA_FAMILY_T\nHAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY\nHAVE_STRUCT_SOCKADDR_STORAGE\nGL_GNULIB_GETRUSAGE\nHAVE_SYS_RESOURCE_H\nNEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H\nNEXT_SYS_RESOURCE_H\nHAVE_GETRUSAGE\nNEXT_AS_FIRST_DIRECTIVE_STDLIB_H\nNEXT_STDLIB_H\nNEXT_AS_FIRST_DIRECTIVE_STDIO_H\nNEXT_STDIO_H\nGL_GENERATE_STDINT_H_FALSE\nGL_GENERATE_STDINT_H_TRUE\nSTDINT_H\nHAVE_SYS_INTTYPES_H\nHAVE_SYS_BITYPES_H\nHAVE_C99_STDINT_H\nWINT_T_SUFFIX\nWCHAR_T_SUFFIX\nSIG_ATOMIC_T_SUFFIX\nSIZE_T_SUFFIX\nPTRDIFF_T_SUFFIX\nHAVE_SIGNED_WINT_T\nHAVE_SIGNED_WCHAR_T\nHAVE_SIGNED_SIG_ATOMIC_T\nBITSIZEOF_WINT_T\nBITSIZEOF_WCHAR_T\nBITSIZEOF_SIG_ATOMIC_T\nBITSIZEOF_SIZE_T\nBITSIZEOF_PTRDIFF_T\nHAVE_STDINT_H\nNEXT_AS_FIRST_DIRECTIVE_STDINT_H\nNEXT_STDINT_H\nHAVE_SYS_TYPES_H\nHAVE_INTTYPES_H\nHAVE_WCHAR_H\nGNULIBHEADERS_OVERRIDE_WINT_T\nNEXT_AS_FIRST_DIRECTIVE_STDDEF_H\nNEXT_STDDEF_H\nGL_GENERATE_STDDEF_H_FALSE\nGL_GENERATE_STDDEF_H_TRUE\nSTDDEF_H\nHAVE_WCHAR_T\nHAVE_MAX_ALIGN_T\nREPLACE_NULL\nGL_GENERATE_STDALIGN_H_FALSE\nGL_GENERATE_STDALIGN_H_TRUE\nSTDALIGN_H\nLIBSOCKET\nGL_GNULIB_MDA_PUTENV\nGL_GNULIB_MDA_MKTEMP\nGL_GNULIB_MDA_GCVT\nGL_GNULIB_MDA_FCVT\nGL_GNULIB_MDA_ECVT\nGL_GNULIB_WCTOMB\nGL_GNULIB_UNSETENV\nGL_GNULIB_UNLOCKPT\nGL_GNULIB_SYSTEM_POSIX\nGL_GNULIB_STRTOULL\nGL_GNULIB_STRTOUL\nGL_GNULIB_STRTOLL\nGL_GNULIB_STRTOLD\nGL_GNULIB_STRTOL\nGL_GNULIB_STRTOD\nGL_GNULIB_SETENV\nGL_GNULIB_SECURE_GETENV\nGL_GNULIB_RPMATCH\nGL_GNULIB_REALPATH\nGL_GNULIB_REALLOC_POSIX\nGL_GNULIB_REALLOCARRAY\nGL_GNULIB_RANDOM_R\nGL_GNULIB_RANDOM\nGL_GNULIB_QSORT_R\nGL_GNULIB_PUTENV\nGL_GNULIB_PTSNAME_R\nGL_GNULIB_PTSNAME\nGL_GNULIB_POSIX_OPENPT\nGL_GNULIB_POSIX_MEMALIGN\nGL_GNULIB_MKSTEMPS\nGL_GNULIB_MKSTEMP\nGL_GNULIB_MKOSTEMPS\nGL_GNULIB_MKOSTEMP\nGL_GNULIB_MKDTEMP\nGL_GNULIB_MBTOWC\nGL_GNULIB_MALLOC_POSIX\nGL_GNULIB_GRANTPT\nGL_GNULIB_GETSUBOPT\nGL_GNULIB_GETLOADAVG\nGL_GNULIB_FREE_POSIX\nGL_GNULIB_CANONICALIZE_FILE_NAME\nGL_GNULIB_CALLOC_POSIX\nGL_GNULIB_ATOLL\nGL_GNULIB_ALIGNED_ALLOC\nGL_GNULIB__EXIT\nREPLACE_WCTOMB\nREPLACE_UNSETENV\nREPLACE_STRTOULL\nREPLACE_STRTOUL\nREPLACE_STRTOLL\nREPLACE_STRTOLD\nREPLACE_STRTOL\nREPLACE_STRTOD\nREPLACE_SETSTATE\nREPLACE_SETENV\nREPLACE_REALPATH\nREPLACE_REALLOCARRAY\nREPLACE_REALLOC\nREPLACE_RANDOM_R\nREPLACE_RANDOM\nREPLACE_QSORT_R\nREPLACE_PUTENV\nREPLACE_PTSNAME_R\nREPLACE_PTSNAME\nREPLACE_POSIX_MEMALIGN\nREPLACE_MKSTEMP\nREPLACE_MBTOWC\nREPLACE_MALLOC\nREPLACE_INITSTATE\nREPLACE_FREE\nREPLACE_CANONICALIZE_FILE_NAME\nREPLACE_CALLOC\nREPLACE_ALIGNED_ALLOC\nHAVE_DECL_UNSETENV\nHAVE_UNLOCKPT\nHAVE_SYS_LOADAVG_H\nHAVE_STRUCT_RANDOM_DATA\nHAVE_STRTOULL\nHAVE_STRTOUL\nHAVE_STRTOLL\nHAVE_STRTOLD\nHAVE_STRTOL\nHAVE_STRTOD\nHAVE_DECL_SETSTATE\nHAVE_SETSTATE\nHAVE_DECL_SETENV\nHAVE_SETENV\nHAVE_SECURE_GETENV\nHAVE_RPMATCH\nHAVE_REALPATH\nHAVE_REALLOCARRAY\nHAVE_RANDOM_R\nHAVE_RANDOM_H\nHAVE_RANDOM\nHAVE_QSORT_R\nHAVE_PTSNAME_R\nHAVE_PTSNAME\nHAVE_POSIX_OPENPT\nHAVE_POSIX_MEMALIGN\nHAVE_MKSTEMPS\nHAVE_MKSTEMP\nHAVE_MKOSTEMPS\nHAVE_MKOSTEMP\nHAVE_MKDTEMP\nHAVE_MBTOWC\nHAVE_DECL_INITSTATE\nHAVE_INITSTATE\nHAVE_GRANTPT\nHAVE_GETSUBOPT\nHAVE_DECL_GETLOADAVG\nHAVE_DECL_GCVT\nHAVE_DECL_FCVT\nHAVE_DECL_ECVT\nHAVE_CANONICALIZE_FILE_NAME\nHAVE_ATOLL\nHAVE_ALIGNED_ALLOC\nHAVE__EXIT\nAPPLE_UNIVERSAL_BUILD\nHAVE_MSVC_INVALID_PARAMETER_HANDLER\nGL_GENERATE_LIMITS_H_FALSE\nGL_GENERATE_LIMITS_H_TRUE\nLIMITS_H\nNEXT_AS_FIRST_DIRECTIVE_LIMITS_H\nNEXT_LIMITS_H\nGL_GNULIB_GETTIMEOFDAY\nNEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H\nNEXT_SYS_TIME_H\nREPLACE_STRUCT_TIMEVAL\nREPLACE_GETTIMEOFDAY\nHAVE_SYS_TIME_H\nHAVE_STRUCT_TIMEVAL\nHAVE_GETTIMEOFDAY\nGL_GNULIB_MDA_WRITE\nGL_GNULIB_MDA_UNLINK\nGL_GNULIB_MDA_SWAB\nGL_GNULIB_MDA_RMDIR\nGL_GNULIB_MDA_READ\nGL_GNULIB_MDA_LSEEK\nGL_GNULIB_MDA_ISATTY\nGL_GNULIB_MDA_GETPID\nGL_GNULIB_MDA_GETCWD\nGL_GNULIB_MDA_EXECVPE\nGL_GNULIB_MDA_EXECVP\nGL_GNULIB_MDA_EXECVE\nGL_GNULIB_MDA_EXECV\nGL_GNULIB_MDA_EXECLP\nGL_GNULIB_MDA_EXECLE\nGL_GNULIB_MDA_EXECL\nGL_GNULIB_MDA_DUP2\nGL_GNULIB_MDA_DUP\nGL_GNULIB_MDA_CLOSE\nGL_GNULIB_MDA_CHDIR\nGL_GNULIB_MDA_ACCESS\nGL_GNULIB_WRITE\nGL_GNULIB_USLEEP\nGL_GNULIB_UNLINKAT\nGL_GNULIB_UNLINK\nGL_GNULIB_UNISTD_H_SIGPIPE\nGL_GNULIB_UNISTD_H_NONBLOCKING\nGL_GNULIB_UNISTD_H_GETOPT\nGL_GNULIB_TTYNAME_R\nGL_GNULIB_TRUNCATE\nGL_GNULIB_SYMLINKAT\nGL_GNULIB_SYMLINK\nGL_GNULIB_SLEEP\nGL_GNULIB_SETHOSTNAME\nGL_GNULIB_RMDIR\nGL_GNULIB_READLINKAT\nGL_GNULIB_READLINK\nGL_GNULIB_READ\nGL_GNULIB_PWRITE\nGL_GNULIB_PREAD\nGL_GNULIB_PIPE2\nGL_GNULIB_PIPE\nGL_GNULIB_LSEEK\nGL_GNULIB_LINKAT\nGL_GNULIB_LINK\nGL_GNULIB_LCHOWN\nGL_GNULIB_ISATTY\nGL_GNULIB_GROUP_MEMBER\nGL_GNULIB_GETUSERSHELL\nGL_GNULIB_GETPASS\nGL_GNULIB_GETPAGESIZE\nGL_GNULIB_GETOPT_POSIX\nGL_GNULIB_GETLOGIN_R\nGL_GNULIB_GETLOGIN\nGL_GNULIB_GETHOSTNAME\nGL_GNULIB_GETGROUPS\nGL_GNULIB_GETENTROPY\nGL_GNULIB_GETDTABLESIZE\nGL_GNULIB_GETDOMAINNAME\nGL_GNULIB_GETCWD\nGL_GNULIB_FTRUNCATE\nGL_GNULIB_FSYNC\nGL_GNULIB_FDATASYNC\nGL_GNULIB_FCHOWNAT\nGL_GNULIB_FCHDIR\nGL_GNULIB_FACCESSAT\nGL_GNULIB_EXECVPE\nGL_GNULIB_EXECVP\nGL_GNULIB_EXECVE\nGL_GNULIB_EXECV\nGL_GNULIB_EXECLP\nGL_GNULIB_EXECLE\nGL_GNULIB_EXECL\nGL_GNULIB_EUIDACCESS\nGL_GNULIB_ENVIRON\nGL_GNULIB_DUP3\nGL_GNULIB_DUP2\nGL_GNULIB_DUP\nGL_GNULIB_COPY_FILE_RANGE\nGL_GNULIB_CLOSE\nGL_GNULIB_CHOWN\nGL_GNULIB_CHDIR\nGL_GNULIB_ACCESS\nGETHOSTNAME_LIB\nHAVE_WINSOCK2_H\nUNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS\nUNISTD_H_HAVE_WINSOCK2_H\nUNISTD_H_HAVE_SYS_RANDOM_H\nREPLACE_WRITE\nREPLACE_USLEEP\nREPLACE_UNLINKAT\nREPLACE_UNLINK\nREPLACE_TTYNAME_R\nREPLACE_TRUNCATE\nREPLACE_SYMLINKAT\nREPLACE_SYMLINK\nREPLACE_SLEEP\nREPLACE_RMDIR\nREPLACE_READLINKAT\nREPLACE_READLINK\nREPLACE_READ\nREPLACE_PWRITE\nREPLACE_PREAD\nREPLACE_LSEEK\nREPLACE_LINKAT\nREPLACE_LINK\nREPLACE_LCHOWN\nREPLACE_ISATTY\nREPLACE_GETPASS\nREPLACE_GETPAGESIZE\nREPLACE_GETGROUPS\nREPLACE_GETLOGIN_R\nREPLACE_GETDTABLESIZE\nREPLACE_GETDOMAINNAME\nREPLACE_GETCWD\nREPLACE_FTRUNCATE\nREPLACE_FCHOWNAT\nREPLACE_FACCESSAT\nREPLACE_EXECVPE\nREPLACE_EXECVP\nREPLACE_EXECVE\nREPLACE_EXECV\nREPLACE_EXECLP\nREPLACE_EXECLE\nREPLACE_EXECL\nREPLACE_DUP2\nREPLACE_DUP\nREPLACE_CLOSE\nREPLACE_CHOWN\nREPLACE_ACCESS\nHAVE_SYS_PARAM_H\nHAVE_OS_H\nHAVE_DECL_TTYNAME_R\nHAVE_DECL_TRUNCATE\nHAVE_DECL_SETHOSTNAME\nHAVE_DECL_GETUSERSHELL\nHAVE_DECL_GETPAGESIZE\nHAVE_DECL_GETLOGIN_R\nHAVE_DECL_GETLOGIN\nHAVE_DECL_GETDOMAINNAME\nHAVE_DECL_FDATASYNC\nHAVE_DECL_FCHDIR\nHAVE_DECL_EXECVPE\nHAVE_DECL_ENVIRON\nHAVE_USLEEP\nHAVE_UNLINKAT\nHAVE_SYMLINKAT\nHAVE_SYMLINK\nHAVE_SLEEP\nHAVE_SETHOSTNAME\nHAVE_READLINKAT\nHAVE_READLINK\nHAVE_PWRITE\nHAVE_PREAD\nHAVE_PIPE2\nHAVE_PIPE\nHAVE_LINKAT\nHAVE_LINK\nHAVE_LCHOWN\nHAVE_GROUP_MEMBER\nHAVE_GETPASS\nHAVE_GETPAGESIZE\nHAVE_GETLOGIN\nHAVE_GETHOSTNAME\nHAVE_GETGROUPS\nHAVE_GETENTROPY\nHAVE_GETDTABLESIZE\nHAVE_FTRUNCATE\nHAVE_FSYNC\nHAVE_FDATASYNC\nHAVE_FCHOWNAT\nHAVE_FCHDIR\nHAVE_FACCESSAT\nHAVE_EXECVPE\nHAVE_EUIDACCESS\nHAVE_DUP3\nHAVE_COPY_FILE_RANGE\nHAVE_CHOWN\nGL_GNULIB_MDA_TEMPNAM\nGL_GNULIB_MDA_PUTW\nGL_GNULIB_MDA_GETW\nGL_GNULIB_MDA_FILENO\nGL_GNULIB_MDA_FDOPEN\nGL_GNULIB_MDA_FCLOSEALL\nGL_GNULIB_VSPRINTF_POSIX\nGL_GNULIB_VSNPRINTF\nGL_GNULIB_VPRINTF_POSIX\nGL_GNULIB_VPRINTF\nGL_GNULIB_VFPRINTF_POSIX\nGL_GNULIB_VFPRINTF\nGL_GNULIB_VDPRINTF\nGL_GNULIB_VSCANF\nGL_GNULIB_VFSCANF\nGL_GNULIB_VASPRINTF\nGL_GNULIB_TMPFILE\nGL_GNULIB_STDIO_H_SIGPIPE\nGL_GNULIB_STDIO_H_NONBLOCKING\nGL_GNULIB_SPRINTF_POSIX\nGL_GNULIB_SNPRINTF\nGL_GNULIB_SCANF\nGL_GNULIB_RENAMEAT\nGL_GNULIB_RENAME\nGL_GNULIB_REMOVE\nGL_GNULIB_PUTS\nGL_GNULIB_PUTCHAR\nGL_GNULIB_PUTC\nGL_GNULIB_PRINTF_POSIX\nGL_GNULIB_PRINTF\nGL_GNULIB_POPEN\nGL_GNULIB_PERROR\nGL_GNULIB_PCLOSE\nGL_GNULIB_OBSTACK_PRINTF_POSIX\nGL_GNULIB_OBSTACK_PRINTF\nGL_GNULIB_GETLINE\nGL_GNULIB_GETDELIM\nGL_GNULIB_GETCHAR\nGL_GNULIB_GETC\nGL_GNULIB_FWRITE\nGL_GNULIB_FTELLO\nGL_GNULIB_FTELL\nGL_GNULIB_FSEEKO\nGL_GNULIB_FSEEK\nGL_GNULIB_FSCANF\nGL_GNULIB_FREOPEN\nGL_GNULIB_FREAD\nGL_GNULIB_FPUTS\nGL_GNULIB_FPUTC\nGL_GNULIB_FPURGE\nGL_GNULIB_FPRINTF_POSIX\nGL_GNULIB_FPRINTF\nGL_GNULIB_FOPEN\nGL_GNULIB_FGETS\nGL_GNULIB_FGETC\nGL_GNULIB_FFLUSH\nGL_GNULIB_FDOPEN\nGL_GNULIB_FCLOSE\nGL_GNULIB_DPRINTF\nREPLACE_VSPRINTF\nREPLACE_VSNPRINTF\nREPLACE_VPRINTF\nREPLACE_VFPRINTF\nREPLACE_VDPRINTF\nREPLACE_VASPRINTF\nREPLACE_TMPFILE\nREPLACE_STDIO_WRITE_FUNCS\nREPLACE_STDIO_READ_FUNCS\nREPLACE_SPRINTF\nREPLACE_SNPRINTF\nREPLACE_RENAMEAT\nREPLACE_RENAME\nREPLACE_REMOVE\nREPLACE_PRINTF\nREPLACE_POPEN\nREPLACE_PERROR\nREPLACE_OBSTACK_PRINTF\nREPLACE_GETLINE\nREPLACE_GETDELIM\nREPLACE_FTELLO\nREPLACE_FTELL\nREPLACE_FSEEKO\nREPLACE_FSEEK\nREPLACE_FREOPEN\nREPLACE_FPURGE\nREPLACE_FPRINTF\nREPLACE_FOPEN\nREPLACE_FFLUSH\nREPLACE_FDOPEN\nREPLACE_FCLOSE\nREPLACE_DPRINTF\nHAVE_VDPRINTF\nHAVE_VASPRINTF\nHAVE_RENAMEAT\nHAVE_POPEN\nHAVE_PCLOSE\nHAVE_FTELLO\nHAVE_FSEEKO\nHAVE_DPRINTF\nHAVE_DECL_VSNPRINTF\nHAVE_DECL_SNPRINTF\nHAVE_DECL_OBSTACK_PRINTF\nHAVE_DECL_GETLINE\nHAVE_DECL_GETDELIM\nHAVE_DECL_FTELLO\nHAVE_DECL_FSEEKO\nHAVE_DECL_FPURGE\nHAVE_DECL_FCLOSEALL\nGL_GENERATE_EXECINFO_H_FALSE\nGL_GENERATE_EXECINFO_H_TRUE\nLIB_EXECINFO\nEXECINFO_H\nEOVERFLOW_VALUE\nEOVERFLOW_HIDDEN\nENOLINK_VALUE\nENOLINK_HIDDEN\nEMULTIHOP_VALUE\nEMULTIHOP_HIDDEN\nGL_GENERATE_ERRNO_H_FALSE\nGL_GENERATE_ERRNO_H_TRUE\nERRNO_H\nNEXT_AS_FIRST_DIRECTIVE_ERRNO_H\nNEXT_ERRNO_H\nPRAGMA_COLUMNS\nPRAGMA_SYSTEM_HEADER\nINCLUDE_NEXT_AS_FIRST_DIRECTIVE\nINCLUDE_NEXT\nGL_COND_LIBTOOL_FALSE\nGL_COND_LIBTOOL_TRUE\nRANLIB\nARFLAGS\nAR\nEGREP\nGREP\nCPP\nhost_os\nhost_vendor\nhost_cpu\nhost\nbuild_os\nbuild_vendor\nbuild_cpu\nbuild\nam__fastdepCC_FALSE\nam__fastdepCC_TRUE\nCCDEPMODE\nam__nodep\nAMDEPBACKSLASH\nAMDEP_FALSE\nAMDEP_TRUE\nam__include\nDEPDIR\nOBJEXT\nEXEEXT\nac_ct_CC\nCPPFLAGS\nLDFLAGS\nCFLAGS\nCC\nAM_BACKSLASH\nAM_DEFAULT_VERBOSITY\nAM_DEFAULT_V\nAM_V\nam__untar\nam__tar\nAMTAR\nam__leading_dot\nSET_MAKE\nAWK\nmkdir_p\nMKDIR_P\nINSTALL_STRIP_PROGRAM\nSTRIP\ninstall_sh\nMAKEINFO\nAUTOHEADER\nAUTOMAKE\nAUTOCONF\nACLOCAL\nVERSION\nPACKAGE\nCYGPATH_W\nam__isrc\nINSTALL_DATA\nINSTALL_SCRIPT\nINSTALL_PROGRAM\ntarget_alias\nhost_alias\nbuild_alias\nLIBS\nECHO_T\nECHO_N\nECHO_C\nDEFS\nmandir\nlocaledir\nlibdir\npsdir\npdfdir\ndvidir\nhtmldir\ninfodir\ndocdir\noldincludedir\nincludedir\nrunstatedir\nlocalstatedir\nsharedstatedir\nsysconfdir\ndatadir\ndatarootdir\nlibexecdir\nsbindir\nbindir\nprogram_transform_name\nprefix\nexec_prefix\nPACKAGE_URL\nPACKAGE_BUGREPORT\nPACKAGE_STRING\nPACKAGE_VERSION\nPACKAGE_TARNAME\nPACKAGE_NAME\nPATH_SEPARATOR\nSHELL\nam__quote'\nac_subst_files=''\nac_user_opts='\nenable_option_checking\nenable_silent_rules\nenable_dependency_tracking\nenable_cross_guesses\n'\n      ac_precious_vars='build_alias\nhost_alias\ntarget_alias\nCC\nCFLAGS\nLDFLAGS\nLIBS\nCPPFLAGS\nCPP'\n\n\n# Initialize some variables set by options.\nac_init_help=\nac_init_version=false\nac_unrecognized_opts=\nac_unrecognized_sep=\n# The variables have the same names as the options, with\n# dashes changed to underlines.\ncache_file=/dev/null\nexec_prefix=NONE\nno_create=\nno_recursion=\nprefix=NONE\nprogram_prefix=NONE\nprogram_suffix=NONE\nprogram_transform_name=s,x,x,\nsilent=\nsite=\nsrcdir=\nverbose=\nx_includes=NONE\nx_libraries=NONE\n\n# Installation directory options.\n# These are left unexpanded so users can \"make install exec_prefix=/foo\"\n# and all the variables that are supposed to be based on exec_prefix\n# by default will actually change.\n# Use braces instead of parens because sh, perl, etc. also accept them.\n# (The list follows the same order as the GNU Coding Standards.)\nbindir='${exec_prefix}/bin'\nsbindir='${exec_prefix}/sbin'\nlibexecdir='${exec_prefix}/libexec'\ndatarootdir='${prefix}/share'\ndatadir='${datarootdir}'\nsysconfdir='${prefix}/etc'\nsharedstatedir='${prefix}/com'\nlocalstatedir='${prefix}/var'\nrunstatedir='${localstatedir}/run'\nincludedir='${prefix}/include'\noldincludedir='/usr/include'\ndocdir='${datarootdir}/doc/${PACKAGE_TARNAME}'\ninfodir='${datarootdir}/info'\nhtmldir='${docdir}'\ndvidir='${docdir}'\npdfdir='${docdir}'\npsdir='${docdir}'\nlibdir='${exec_prefix}/lib'\nlocaledir='${datarootdir}/locale'\nmandir='${datarootdir}/man'\n\nac_prev=\nac_dashdash=\nfor ac_option\ndo\n  # If the previous option needs an argument, assign it.\n  if test -n \"$ac_prev\"; then\n    eval $ac_prev=\\$ac_option\n    ac_prev=\n    continue\n  fi\n\n  case $ac_option in\n  *=?*) ac_optarg=`expr \"X$ac_option\" : '[^=]*=\\(.*\\)'` ;;\n  *=)   ac_optarg= ;;\n  *)    ac_optarg=yes ;;\n  esac\n\n  case $ac_dashdash$ac_option in\n  --)\n    ac_dashdash=yes ;;\n\n  -bindir | --bindir | --bindi | --bind | --bin | --bi)\n    ac_prev=bindir ;;\n  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)\n    bindir=$ac_optarg ;;\n\n  -build | --build | --buil | --bui | --bu)\n    ac_prev=build_alias ;;\n  -build=* | --build=* | --buil=* | --bui=* | --bu=*)\n    build_alias=$ac_optarg ;;\n\n  -cache-file | --cache-file | --cache-fil | --cache-fi \\\n  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)\n    ac_prev=cache_file ;;\n  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \\\n  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)\n    cache_file=$ac_optarg ;;\n\n  --config-cache | -C)\n    cache_file=config.cache ;;\n\n  -datadir | --datadir | --datadi | --datad)\n    ac_prev=datadir ;;\n  -datadir=* | --datadir=* | --datadi=* | --datad=*)\n    datadir=$ac_optarg ;;\n\n  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \\\n  | --dataroo | --dataro | --datar)\n    ac_prev=datarootdir ;;\n  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \\\n  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)\n    datarootdir=$ac_optarg ;;\n\n  -disable-* | --disable-*)\n    ac_useropt=`expr \"x$ac_option\" : 'x-*disable-\\(.*\\)'`\n    # Reject names that are not valid shell variable names.\n    expr \"x$ac_useropt\" : \".*[^-+._$as_cr_alnum]\" >/dev/null &&\n      as_fn_error $? \"invalid feature name: \\`$ac_useropt'\"\n    ac_useropt_orig=$ac_useropt\n    ac_useropt=`printf \"%s\\n\" \"$ac_useropt\" | sed 's/[-+.]/_/g'`\n    case $ac_user_opts in\n      *\"\n\"enable_$ac_useropt\"\n\"*) ;;\n      *) ac_unrecognized_opts=\"$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig\"\n\t ac_unrecognized_sep=', ';;\n    esac\n    eval enable_$ac_useropt=no ;;\n\n  -docdir | --docdir | --docdi | --doc | --do)\n    ac_prev=docdir ;;\n  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)\n    docdir=$ac_optarg ;;\n\n  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)\n    ac_prev=dvidir ;;\n  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)\n    dvidir=$ac_optarg ;;\n\n  -enable-* | --enable-*)\n    ac_useropt=`expr \"x$ac_option\" : 'x-*enable-\\([^=]*\\)'`\n    # Reject names that are not valid shell variable names.\n    expr \"x$ac_useropt\" : \".*[^-+._$as_cr_alnum]\" >/dev/null &&\n      as_fn_error $? \"invalid feature name: \\`$ac_useropt'\"\n    ac_useropt_orig=$ac_useropt\n    ac_useropt=`printf \"%s\\n\" \"$ac_useropt\" | sed 's/[-+.]/_/g'`\n    case $ac_user_opts in\n      *\"\n\"enable_$ac_useropt\"\n\"*) ;;\n      *) ac_unrecognized_opts=\"$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig\"\n\t ac_unrecognized_sep=', ';;\n    esac\n    eval enable_$ac_useropt=\\$ac_optarg ;;\n\n  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \\\n  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \\\n  | --exec | --exe | --ex)\n    ac_prev=exec_prefix ;;\n  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \\\n  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \\\n  | --exec=* | --exe=* | --ex=*)\n    exec_prefix=$ac_optarg ;;\n\n  -gas | --gas | --ga | --g)\n    # Obsolete; use --with-gas.\n    with_gas=yes ;;\n\n  -help | --help | --hel | --he | -h)\n    ac_init_help=long ;;\n  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)\n    ac_init_help=recursive ;;\n  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)\n    ac_init_help=short ;;\n\n  -host | --host | --hos | --ho)\n    ac_prev=host_alias ;;\n  -host=* | --host=* | --hos=* | --ho=*)\n    host_alias=$ac_optarg ;;\n\n  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)\n    ac_prev=htmldir ;;\n  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \\\n  | --ht=*)\n    htmldir=$ac_optarg ;;\n\n  -includedir | --includedir | --includedi | --included | --include \\\n  | --includ | --inclu | --incl | --inc)\n    ac_prev=includedir ;;\n  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \\\n  | --includ=* | --inclu=* | --incl=* | --inc=*)\n    includedir=$ac_optarg ;;\n\n  -infodir | --infodir | --infodi | --infod | --info | --inf)\n    ac_prev=infodir ;;\n  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)\n    infodir=$ac_optarg ;;\n\n  -libdir | --libdir | --libdi | --libd)\n    ac_prev=libdir ;;\n  -libdir=* | --libdir=* | --libdi=* | --libd=*)\n    libdir=$ac_optarg ;;\n\n  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \\\n  | --libexe | --libex | --libe)\n    ac_prev=libexecdir ;;\n  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \\\n  | --libexe=* | --libex=* | --libe=*)\n    libexecdir=$ac_optarg ;;\n\n  -localedir | --localedir | --localedi | --localed | --locale)\n    ac_prev=localedir ;;\n  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)\n    localedir=$ac_optarg ;;\n\n  -localstatedir | --localstatedir | --localstatedi | --localstated \\\n  | --localstate | --localstat | --localsta | --localst | --locals)\n    ac_prev=localstatedir ;;\n  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \\\n  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)\n    localstatedir=$ac_optarg ;;\n\n  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)\n    ac_prev=mandir ;;\n  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)\n    mandir=$ac_optarg ;;\n\n  -nfp | --nfp | --nf)\n    # Obsolete; use --without-fp.\n    with_fp=no ;;\n\n  -no-create | --no-create | --no-creat | --no-crea | --no-cre \\\n  | --no-cr | --no-c | -n)\n    no_create=yes ;;\n\n  -no-recursion | --no-recursion | --no-recursio | --no-recursi \\\n  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)\n    no_recursion=yes ;;\n\n  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \\\n  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \\\n  | --oldin | --oldi | --old | --ol | --o)\n    ac_prev=oldincludedir ;;\n  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \\\n  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \\\n  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)\n    oldincludedir=$ac_optarg ;;\n\n  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)\n    ac_prev=prefix ;;\n  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)\n    prefix=$ac_optarg ;;\n\n  -program-prefix | --program-prefix | --program-prefi | --program-pref \\\n  | --program-pre | --program-pr | --program-p)\n    ac_prev=program_prefix ;;\n  -program-prefix=* | --program-prefix=* | --program-prefi=* \\\n  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)\n    program_prefix=$ac_optarg ;;\n\n  -program-suffix | --program-suffix | --program-suffi | --program-suff \\\n  | --program-suf | --program-su | --program-s)\n    ac_prev=program_suffix ;;\n  -program-suffix=* | --program-suffix=* | --program-suffi=* \\\n  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)\n    program_suffix=$ac_optarg ;;\n\n  -program-transform-name | --program-transform-name \\\n  | --program-transform-nam | --program-transform-na \\\n  | --program-transform-n | --program-transform- \\\n  | --program-transform | --program-transfor \\\n  | --program-transfo | --program-transf \\\n  | --program-trans | --program-tran \\\n  | --progr-tra | --program-tr | --program-t)\n    ac_prev=program_transform_name ;;\n  -program-transform-name=* | --program-transform-name=* \\\n  | --program-transform-nam=* | --program-transform-na=* \\\n  | --program-transform-n=* | --program-transform-=* \\\n  | --program-transform=* | --program-transfor=* \\\n  | --program-transfo=* | --program-transf=* \\\n  | --program-trans=* | --program-tran=* \\\n  | --progr-tra=* | --program-tr=* | --program-t=*)\n    program_transform_name=$ac_optarg ;;\n\n  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)\n    ac_prev=pdfdir ;;\n  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)\n    pdfdir=$ac_optarg ;;\n\n  -psdir | --psdir | --psdi | --psd | --ps)\n    ac_prev=psdir ;;\n  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)\n    psdir=$ac_optarg ;;\n\n  -q | -quiet | --quiet | --quie | --qui | --qu | --q \\\n  | -silent | --silent | --silen | --sile | --sil)\n    silent=yes ;;\n\n  -runstatedir | --runstatedir | --runstatedi | --runstated \\\n  | --runstate | --runstat | --runsta | --runst | --runs \\\n  | --run | --ru | --r)\n    ac_prev=runstatedir ;;\n  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \\\n  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \\\n  | --run=* | --ru=* | --r=*)\n    runstatedir=$ac_optarg ;;\n\n  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)\n    ac_prev=sbindir ;;\n  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \\\n  | --sbi=* | --sb=*)\n    sbindir=$ac_optarg ;;\n\n  -sharedstatedir | --sharedstatedir | --sharedstatedi \\\n  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \\\n  | --sharedst | --shareds | --shared | --share | --shar \\\n  | --sha | --sh)\n    ac_prev=sharedstatedir ;;\n  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \\\n  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \\\n  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \\\n  | --sha=* | --sh=*)\n    sharedstatedir=$ac_optarg ;;\n\n  -site | --site | --sit)\n    ac_prev=site ;;\n  -site=* | --site=* | --sit=*)\n    site=$ac_optarg ;;\n\n  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)\n    ac_prev=srcdir ;;\n  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)\n    srcdir=$ac_optarg ;;\n\n  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \\\n  | --syscon | --sysco | --sysc | --sys | --sy)\n    ac_prev=sysconfdir ;;\n  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \\\n  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)\n    sysconfdir=$ac_optarg ;;\n\n  -target | --target | --targe | --targ | --tar | --ta | --t)\n    ac_prev=target_alias ;;\n  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)\n    target_alias=$ac_optarg ;;\n\n  -v | -verbose | --verbose | --verbos | --verbo | --verb)\n    verbose=yes ;;\n\n  -version | --version | --versio | --versi | --vers | -V)\n    ac_init_version=: ;;\n\n  -with-* | --with-*)\n    ac_useropt=`expr \"x$ac_option\" : 'x-*with-\\([^=]*\\)'`\n    # Reject names that are not valid shell variable names.\n    expr \"x$ac_useropt\" : \".*[^-+._$as_cr_alnum]\" >/dev/null &&\n      as_fn_error $? \"invalid package name: \\`$ac_useropt'\"\n    ac_useropt_orig=$ac_useropt\n    ac_useropt=`printf \"%s\\n\" \"$ac_useropt\" | sed 's/[-+.]/_/g'`\n    case $ac_user_opts in\n      *\"\n\"with_$ac_useropt\"\n\"*) ;;\n      *) ac_unrecognized_opts=\"$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig\"\n\t ac_unrecognized_sep=', ';;\n    esac\n    eval with_$ac_useropt=\\$ac_optarg ;;\n\n  -without-* | --without-*)\n    ac_useropt=`expr \"x$ac_option\" : 'x-*without-\\(.*\\)'`\n    # Reject names that are not valid shell variable names.\n    expr \"x$ac_useropt\" : \".*[^-+._$as_cr_alnum]\" >/dev/null &&\n      as_fn_error $? \"invalid package name: \\`$ac_useropt'\"\n    ac_useropt_orig=$ac_useropt\n    ac_useropt=`printf \"%s\\n\" \"$ac_useropt\" | sed 's/[-+.]/_/g'`\n    case $ac_user_opts in\n      *\"\n\"with_$ac_useropt\"\n\"*) ;;\n      *) ac_unrecognized_opts=\"$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig\"\n\t ac_unrecognized_sep=', ';;\n    esac\n    eval with_$ac_useropt=no ;;\n\n  --x)\n    # Obsolete; use --with-x.\n    with_x=yes ;;\n\n  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \\\n  | --x-incl | --x-inc | --x-in | --x-i)\n    ac_prev=x_includes ;;\n  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \\\n  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)\n    x_includes=$ac_optarg ;;\n\n  -x-libraries | --x-libraries | --x-librarie | --x-librari \\\n  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)\n    ac_prev=x_libraries ;;\n  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \\\n  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)\n    x_libraries=$ac_optarg ;;\n\n  -*) as_fn_error $? \"unrecognized option: \\`$ac_option'\nTry \\`$0 --help' for more information\"\n    ;;\n\n  *=*)\n    ac_envvar=`expr \"x$ac_option\" : 'x\\([^=]*\\)='`\n    # Reject names that are not valid shell variable names.\n    case $ac_envvar in #(\n      '' | [0-9]* | *[!_$as_cr_alnum]* )\n      as_fn_error $? \"invalid variable name: \\`$ac_envvar'\" ;;\n    esac\n    eval $ac_envvar=\\$ac_optarg\n    export $ac_envvar ;;\n\n  *)\n    # FIXME: should be removed in autoconf 3.0.\n    printf \"%s\\n\" \"$as_me: WARNING: you should use --build, --host, --target\" >&2\n    expr \"x$ac_option\" : \".*[^-._$as_cr_alnum]\" >/dev/null &&\n      printf \"%s\\n\" \"$as_me: WARNING: invalid host type: $ac_option\" >&2\n    : \"${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}\"\n    ;;\n\n  esac\ndone\n\nif test -n \"$ac_prev\"; then\n  ac_option=--`echo $ac_prev | sed 's/_/-/g'`\n  as_fn_error $? \"missing argument to $ac_option\"\nfi\n\nif test -n \"$ac_unrecognized_opts\"; then\n  case $enable_option_checking in\n    no) ;;\n    fatal) as_fn_error $? \"unrecognized options: $ac_unrecognized_opts\" ;;\n    *)     printf \"%s\\n\" \"$as_me: WARNING: unrecognized options: $ac_unrecognized_opts\" >&2 ;;\n  esac\nfi\n\n# Check all directory arguments for consistency.\nfor ac_var in\texec_prefix prefix bindir sbindir libexecdir datarootdir \\\n\t\tdatadir sysconfdir sharedstatedir localstatedir includedir \\\n\t\toldincludedir docdir infodir htmldir dvidir pdfdir psdir \\\n\t\tlibdir localedir mandir runstatedir\ndo\n  eval ac_val=\\$$ac_var\n  # Remove trailing slashes.\n  case $ac_val in\n    */ )\n      ac_val=`expr \"X$ac_val\" : 'X\\(.*[^/]\\)' \\| \"X$ac_val\" : 'X\\(.*\\)'`\n      eval $ac_var=\\$ac_val;;\n  esac\n  # Be sure to have absolute directory names.\n  case $ac_val in\n    [\\\\/$]* | ?:[\\\\/]* )  continue;;\n    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;\n  esac\n  as_fn_error $? \"expected an absolute directory name for --$ac_var: $ac_val\"\ndone\n\n# There might be people who depend on the old broken behavior: `$host'\n# used to hold the argument of --host etc.\n# FIXME: To remove some day.\nbuild=$build_alias\nhost=$host_alias\ntarget=$target_alias\n\n# FIXME: To remove some day.\nif test \"x$host_alias\" != x; then\n  if test \"x$build_alias\" = x; then\n    cross_compiling=maybe\n  elif test \"x$build_alias\" != \"x$host_alias\"; then\n    cross_compiling=yes\n  fi\nfi\n\nac_tool_prefix=\ntest -n \"$host_alias\" && ac_tool_prefix=$host_alias-\n\ntest \"$silent\" = yes && exec 6>/dev/null\n\n\nac_pwd=`pwd` && test -n \"$ac_pwd\" &&\nac_ls_di=`ls -di .` &&\nac_pwd_ls_di=`cd \"$ac_pwd\" && ls -di .` ||\n  as_fn_error $? \"working directory cannot be determined\"\ntest \"X$ac_ls_di\" = \"X$ac_pwd_ls_di\" ||\n  as_fn_error $? \"pwd does not report name of working directory\"\n\n\n# Find the source files, if location was not specified.\nif test -z \"$srcdir\"; then\n  ac_srcdir_defaulted=yes\n  # Try the directory containing this script, then the parent directory.\n  ac_confdir=`$as_dirname -- \"$as_myself\" ||\n$as_expr X\"$as_myself\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$as_myself\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$as_myself\" : 'X\\(//\\)$' \\| \\\n\t X\"$as_myself\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$as_myself\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n  srcdir=$ac_confdir\n  if test ! -r \"$srcdir/$ac_unique_file\"; then\n    srcdir=..\n  fi\nelse\n  ac_srcdir_defaulted=no\nfi\nif test ! -r \"$srcdir/$ac_unique_file\"; then\n  test \"$ac_srcdir_defaulted\" = yes && srcdir=\"$ac_confdir or ..\"\n  as_fn_error $? \"cannot find sources ($ac_unique_file) in $srcdir\"\nfi\nac_msg=\"sources are in $srcdir, but \\`cd $srcdir' does not work\"\nac_abs_confdir=`(\n\tcd \"$srcdir\" && test -r \"./$ac_unique_file\" || as_fn_error $? \"$ac_msg\"\n\tpwd)`\n# When building in place, set srcdir=.\nif test \"$ac_abs_confdir\" = \"$ac_pwd\"; then\n  srcdir=.\nfi\n# Remove unnecessary trailing slashes from srcdir.\n# Double slashes in file names in object file debugging info\n# mess up M-x gdb in Emacs.\ncase $srcdir in\n*/) srcdir=`expr \"X$srcdir\" : 'X\\(.*[^/]\\)' \\| \"X$srcdir\" : 'X\\(.*\\)'`;;\nesac\nfor ac_var in $ac_precious_vars; do\n  eval ac_env_${ac_var}_set=\\${${ac_var}+set}\n  eval ac_env_${ac_var}_value=\\$${ac_var}\n  eval ac_cv_env_${ac_var}_set=\\${${ac_var}+set}\n  eval ac_cv_env_${ac_var}_value=\\$${ac_var}\ndone\n\n#\n# Report the --help message.\n#\nif test \"$ac_init_help\" = \"long\"; then\n  # Omit some internal or obsolete options to make the list less imposing.\n  # This message is too long to be a string in the A/UX 3.1 sh.\n  cat <<_ACEOF\n\\`configure' configures dummy 0 to adapt to many kinds of systems.\n\nUsage: $0 [OPTION]... [VAR=VALUE]...\n\nTo assign environment variables (e.g., CC, CFLAGS...), specify them as\nVAR=VALUE.  See below for descriptions of some of the useful variables.\n\nDefaults for the options are specified in brackets.\n\nConfiguration:\n  -h, --help              display this help and exit\n      --help=short        display options specific to this package\n      --help=recursive    display the short help of all the included packages\n  -V, --version           display version information and exit\n  -q, --quiet, --silent   do not print \\`checking ...' messages\n      --cache-file=FILE   cache test results in FILE [disabled]\n  -C, --config-cache      alias for \\`--cache-file=config.cache'\n  -n, --no-create         do not create output files\n      --srcdir=DIR        find the sources in DIR [configure dir or \\`..']\n\nInstallation directories:\n  --prefix=PREFIX         install architecture-independent files in PREFIX\n                          [$ac_default_prefix]\n  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX\n                          [PREFIX]\n\nBy default, \\`make install' will install all the files in\n\\`$ac_default_prefix/bin', \\`$ac_default_prefix/lib' etc.  You can specify\nan installation prefix other than \\`$ac_default_prefix' using \\`--prefix',\nfor instance \\`--prefix=\\$HOME'.\n\nFor better control, use the options below.\n\nFine tuning of the installation directories:\n  --bindir=DIR            user executables [EPREFIX/bin]\n  --sbindir=DIR           system admin executables [EPREFIX/sbin]\n  --libexecdir=DIR        program executables [EPREFIX/libexec]\n  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]\n  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]\n  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]\n  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]\n  --libdir=DIR            object code libraries [EPREFIX/lib]\n  --includedir=DIR        C header files [PREFIX/include]\n  --oldincludedir=DIR     C header files for non-gcc [/usr/include]\n  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]\n  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]\n  --infodir=DIR           info documentation [DATAROOTDIR/info]\n  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]\n  --mandir=DIR            man documentation [DATAROOTDIR/man]\n  --docdir=DIR            documentation root [DATAROOTDIR/doc/dummy]\n  --htmldir=DIR           html documentation [DOCDIR]\n  --dvidir=DIR            dvi documentation [DOCDIR]\n  --pdfdir=DIR            pdf documentation [DOCDIR]\n  --psdir=DIR             ps documentation [DOCDIR]\n_ACEOF\n\n  cat <<\\_ACEOF\n\nProgram names:\n  --program-prefix=PREFIX            prepend PREFIX to installed program names\n  --program-suffix=SUFFIX            append SUFFIX to installed program names\n  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names\n\nSystem types:\n  --build=BUILD     configure for building on BUILD [guessed]\n  --host=HOST       cross-compile to build programs to run on HOST [BUILD]\n_ACEOF\nfi\n\nif test -n \"$ac_init_help\"; then\n  case $ac_init_help in\n     short | recursive ) echo \"Configuration of dummy 0:\";;\n   esac\n  cat <<\\_ACEOF\n\nOptional Features:\n  --disable-option-checking  ignore unrecognized --enable/--with options\n  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)\n  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]\n  --enable-silent-rules   less verbose build output (undo: \"make V=1\")\n  --disable-silent-rules  verbose build output (undo: \"make V=0\")\n  --enable-dependency-tracking\n                          do not reject slow dependency extractors\n  --disable-dependency-tracking\n                          speeds up one-time build\n  --enable-cross-guesses={conservative|risky}\n                          specify policy for cross-compilation guesses\n\nSome influential environment variables:\n  CC          C compiler command\n  CFLAGS      C compiler flags\n  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a\n              nonstandard directory <lib dir>\n  LIBS        libraries to pass to the linker, e.g. -l<library>\n  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if\n              you have headers in a nonstandard directory <include dir>\n  CPP         C preprocessor\n\nUse these variables to override the choices made by `configure' or to help\nit to find libraries and programs with nonstandard names/locations.\n\nReport bugs to the package provider.\n_ACEOF\nac_status=$?\nfi\n\nif test \"$ac_init_help\" = \"recursive\"; then\n  # If there are subdirs, report their specific --help.\n  for ac_dir in : $ac_subdirs_all; do test \"x$ac_dir\" = x: && continue\n    test -d \"$ac_dir\" ||\n      { cd \"$srcdir\" && ac_pwd=`pwd` && srcdir=. && test -d \"$ac_dir\"; } ||\n      continue\n    ac_builddir=.\n\ncase \"$ac_dir\" in\n.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;\n*)\n  ac_dir_suffix=/`printf \"%s\\n\" \"$ac_dir\" | sed 's|^\\.[\\\\/]||'`\n  # A \"..\" for each directory in $ac_dir_suffix.\n  ac_top_builddir_sub=`printf \"%s\\n\" \"$ac_dir_suffix\" | sed 's|/[^\\\\/]*|/..|g;s|/||'`\n  case $ac_top_builddir_sub in\n  \"\") ac_top_builddir_sub=. ac_top_build_prefix= ;;\n  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;\n  esac ;;\nesac\nac_abs_top_builddir=$ac_pwd\nac_abs_builddir=$ac_pwd$ac_dir_suffix\n# for backward compatibility:\nac_top_builddir=$ac_top_build_prefix\n\ncase $srcdir in\n  .)  # We are building in place.\n    ac_srcdir=.\n    ac_top_srcdir=$ac_top_builddir_sub\n    ac_abs_top_srcdir=$ac_pwd ;;\n  [\\\\/]* | ?:[\\\\/]* )  # Absolute name.\n    ac_srcdir=$srcdir$ac_dir_suffix;\n    ac_top_srcdir=$srcdir\n    ac_abs_top_srcdir=$srcdir ;;\n  *) # Relative name.\n    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix\n    ac_top_srcdir=$ac_top_build_prefix$srcdir\n    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;\nesac\nac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix\n\n    cd \"$ac_dir\" || { ac_status=$?; continue; }\n    # Check for configure.gnu first; this name is used for a wrapper for\n    # Metaconfig's \"Configure\" on case-insensitive file systems.\n    if test -f \"$ac_srcdir/configure.gnu\"; then\n      echo &&\n      $SHELL \"$ac_srcdir/configure.gnu\" --help=recursive\n    elif test -f \"$ac_srcdir/configure\"; then\n      echo &&\n      $SHELL \"$ac_srcdir/configure\" --help=recursive\n    else\n      printf \"%s\\n\" \"$as_me: WARNING: no configuration information is in $ac_dir\" >&2\n    fi || ac_status=$?\n    cd \"$ac_pwd\" || { ac_status=$?; break; }\n  done\nfi\n\ntest -n \"$ac_init_help\" && exit $ac_status\nif $ac_init_version; then\n  cat <<\\_ACEOF\ndummy configure 0\ngenerated by GNU Autoconf 2.71\n\nCopyright (C) 2021 Free Software Foundation, Inc.\nThis configure script is free software; the Free Software Foundation\ngives unlimited permission to copy, distribute and modify it.\n_ACEOF\n  exit\nfi\n\n## ------------------------ ##\n## Autoconf initialization. ##\n## ------------------------ ##\n\n# ac_fn_c_try_compile LINENO\n# --------------------------\n# Try to compile conftest.$ac_ext, and return whether this succeeded.\nac_fn_c_try_compile ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  rm -f conftest.$ac_objext conftest.beam\n  if { { ac_try=\"$ac_compile\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_compile\") 2>conftest.err\n  ac_status=$?\n  if test -s conftest.err; then\n    grep -v '^ *+' conftest.err >conftest.er1\n    cat conftest.er1 >&5\n    mv -f conftest.er1 conftest.err\n  fi\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; } && {\n\t test -z \"$ac_c_werror_flag\" ||\n\t test ! -s conftest.err\n       } && test -s conftest.$ac_objext\nthen :\n  ac_retval=0\nelse $as_nop\n  printf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n\tac_retval=1\nfi\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  as_fn_set_status $ac_retval\n\n} # ac_fn_c_try_compile\n\n# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES\n# -------------------------------------------------------\n# Tests whether HEADER exists and can be compiled using the include files in\n# INCLUDES, setting the cache variable VAR accordingly.\nac_fn_c_check_header_compile ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $2\" >&5\nprintf %s \"checking for $2... \" >&6; }\nif eval test \\${$3+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\n#include <$2>\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval \"$3=yes\"\nelse $as_nop\n  eval \"$3=no\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\neval ac_res=\\$$3\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n\n} # ac_fn_c_check_header_compile\n\n# ac_fn_c_try_cpp LINENO\n# ----------------------\n# Try to preprocess conftest.$ac_ext, and return whether this succeeded.\nac_fn_c_try_cpp ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  if { { ac_try=\"$ac_cpp conftest.$ac_ext\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_cpp conftest.$ac_ext\") 2>conftest.err\n  ac_status=$?\n  if test -s conftest.err; then\n    grep -v '^ *+' conftest.err >conftest.er1\n    cat conftest.er1 >&5\n    mv -f conftest.er1 conftest.err\n  fi\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; } > conftest.i && {\n\t test -z \"$ac_c_preproc_warn_flag$ac_c_werror_flag\" ||\n\t test ! -s conftest.err\n       }\nthen :\n  ac_retval=0\nelse $as_nop\n  printf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n    ac_retval=1\nfi\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  as_fn_set_status $ac_retval\n\n} # ac_fn_c_try_cpp\n\n# ac_fn_c_try_run LINENO\n# ----------------------\n# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that\n# executables *can* be run.\nac_fn_c_try_run ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  if { { ac_try=\"$ac_link\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_link\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'\n  { { case \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_try\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }; }\nthen :\n  ac_retval=0\nelse $as_nop\n  printf \"%s\\n\" \"$as_me: program exited with status $ac_status\" >&5\n       printf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n       ac_retval=$ac_status\nfi\n  rm -rf conftest.dSYM conftest_ipa8_conftest.oo\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  as_fn_set_status $ac_retval\n\n} # ac_fn_c_try_run\n\n# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES\n# --------------------------------------------\n# Tries to find the compile-time value of EXPR in a program that includes\n# INCLUDES, setting VAR accordingly. Returns whether the value could be\n# computed\nac_fn_c_compute_int ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  if test \"$cross_compiling\" = yes; then\n    # Depending upon the size, compute the lo and hi bounds.\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nstatic int test_array [1 - 2 * !(($2) >= 0)];\ntest_array [0] = 0;\nreturn test_array [0];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_lo=0 ac_mid=0\n  while :; do\n    cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nstatic int test_array [1 - 2 * !(($2) <= $ac_mid)];\ntest_array [0] = 0;\nreturn test_array [0];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_hi=$ac_mid; break\nelse $as_nop\n  as_fn_arith $ac_mid + 1 && ac_lo=$as_val\n\t\t\tif test $ac_lo -le $ac_mid; then\n\t\t\t  ac_lo= ac_hi=\n\t\t\t  break\n\t\t\tfi\n\t\t\tas_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n  done\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nstatic int test_array [1 - 2 * !(($2) < 0)];\ntest_array [0] = 0;\nreturn test_array [0];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_hi=-1 ac_mid=-1\n  while :; do\n    cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nstatic int test_array [1 - 2 * !(($2) >= $ac_mid)];\ntest_array [0] = 0;\nreturn test_array [0];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_lo=$ac_mid; break\nelse $as_nop\n  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val\n\t\t\tif test $ac_mid -le $ac_hi; then\n\t\t\t  ac_lo= ac_hi=\n\t\t\t  break\n\t\t\tfi\n\t\t\tas_fn_arith 2 '*' $ac_mid && ac_mid=$as_val\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n  done\nelse $as_nop\n  ac_lo= ac_hi=\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n# Binary search between lo and hi bounds.\nwhile test \"x$ac_lo\" != \"x$ac_hi\"; do\n  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nstatic int test_array [1 - 2 * !(($2) <= $ac_mid)];\ntest_array [0] = 0;\nreturn test_array [0];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_hi=$ac_mid\nelse $as_nop\n  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\ndone\ncase $ac_lo in #((\n?*) eval \"$3=\\$ac_lo\"; ac_retval=0 ;;\n'') ac_retval=1 ;;\nesac\n  else\n    cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nstatic long int longval (void) { return $2; }\nstatic unsigned long int ulongval (void) { return $2; }\n#include <stdio.h>\n#include <stdlib.h>\nint\nmain (void)\n{\n\n  FILE *f = fopen (\"conftest.val\", \"w\");\n  if (! f)\n    return 1;\n  if (($2) < 0)\n    {\n      long int i = longval ();\n      if (i != ($2))\n\treturn 1;\n      fprintf (f, \"%ld\", i);\n    }\n  else\n    {\n      unsigned long int i = ulongval ();\n      if (i != ($2))\n\treturn 1;\n      fprintf (f, \"%lu\", i);\n    }\n  /* Do not output a trailing newline, as this causes \\r\\n confusion\n     on some platforms.  */\n  return ferror (f) || fclose (f) != 0;\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_run \"$LINENO\"\nthen :\n  echo >>conftest.val; read $3 <conftest.val; ac_retval=0\nelse $as_nop\n  ac_retval=1\nfi\nrm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \\\n  conftest.$ac_objext conftest.beam conftest.$ac_ext\nrm -f conftest.val\n\n  fi\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  as_fn_set_status $ac_retval\n\n} # ac_fn_c_compute_int\n\n# ac_fn_c_try_link LINENO\n# -----------------------\n# Try to link conftest.$ac_ext, and return whether this succeeded.\nac_fn_c_try_link ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext\n  if { { ac_try=\"$ac_link\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_link\") 2>conftest.err\n  ac_status=$?\n  if test -s conftest.err; then\n    grep -v '^ *+' conftest.err >conftest.er1\n    cat conftest.er1 >&5\n    mv -f conftest.er1 conftest.err\n  fi\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; } && {\n\t test -z \"$ac_c_werror_flag\" ||\n\t test ! -s conftest.err\n       } && test -s conftest$ac_exeext && {\n\t test \"$cross_compiling\" = yes ||\n\t test -x conftest$ac_exeext\n       }\nthen :\n  ac_retval=0\nelse $as_nop\n  printf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n\tac_retval=1\nfi\n  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information\n  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would\n  # interfere with the next link command; also delete a directory that is\n  # left behind by Apple's compiler.  We do this before executing the actions.\n  rm -rf conftest.dSYM conftest_ipa8_conftest.oo\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  as_fn_set_status $ac_retval\n\n} # ac_fn_c_try_link\n\n# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR\n# ------------------------------------------------------------------\n# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR\n# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.\nac_fn_check_decl ()\n{\n  ac_save_ac_compile=\"$ac_compile\"\n  if test -n \"$ac_compile_for_check_decl\"; then\n    ac_compile=\"$ac_compile_for_check_decl\"\n  fi\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  as_decl_name=`echo $2|sed 's/ *(.*//'`\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared\" >&5\nprintf %s \"checking whether $as_decl_name is declared... \" >&6; }\nif eval test \\${$3+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`\n  eval ac_save_FLAGS=\\$$6\n  as_fn_append $6 \" $5\"\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\n#ifndef $as_decl_name\n#ifdef __cplusplus\n  (void) $as_decl_use;\n#else\n  (void) $as_decl_name;\n#endif\n#endif\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval \"$3=yes\"\nelse $as_nop\n  eval \"$3=no\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n  eval $6=\\$ac_save_FLAGS\n\nfi\neval ac_res=\\$$3\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n  ac_compile=\"$ac_save_ac_compile\"\n\n} # ac_fn_check_decl\n\n# ac_fn_c_check_func LINENO FUNC VAR\n# ----------------------------------\n# Tests whether FUNC exists, setting the cache variable VAR accordingly\nac_fn_c_check_func ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $2\" >&5\nprintf %s \"checking for $2... \" >&6; }\nif eval test \\${$3+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n/* Define $2 to an innocuous variant, in case <limits.h> declares $2.\n   For example, HP-UX 11i <limits.h> declares gettimeofday.  */\n#define $2 innocuous_$2\n\n/* System header to define __stub macros and hopefully few prototypes,\n   which can conflict with char $2 (); below.  */\n\n#include <limits.h>\n#undef $2\n\n/* Override any GCC internal prototype to avoid an error.\n   Use char because int might match the return type of a GCC\n   builtin and then its argument prototype would still apply.  */\n#ifdef __cplusplus\nextern \"C\"\n#endif\nchar $2 ();\n/* The GNU C library defines this for functions which it implements\n    to always fail with ENOSYS.  Some functions are actually named\n    something starting with __ and the normal name is an alias.  */\n#if defined __stub_$2 || defined __stub___$2\nchoke me\n#endif\n\nint\nmain (void)\n{\nreturn $2 ();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  eval \"$3=yes\"\nelse $as_nop\n  eval \"$3=no\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\nfi\neval ac_res=\\$$3\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n\n} # ac_fn_c_check_func\n\n# ac_fn_c_check_type LINENO TYPE VAR INCLUDES\n# -------------------------------------------\n# Tests whether TYPE exists after having included INCLUDES, setting cache\n# variable VAR accordingly.\nac_fn_c_check_type ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $2\" >&5\nprintf %s \"checking for $2... \" >&6; }\nif eval test \\${$3+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  eval \"$3=no\"\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nif (sizeof ($2))\n\t return 0;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$4\nint\nmain (void)\n{\nif (sizeof (($2)))\n\t    return 0;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n\nelse $as_nop\n  eval \"$3=yes\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\neval ac_res=\\$$3\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n\n} # ac_fn_c_check_type\n\n# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES\n# ----------------------------------------------------\n# Tries to find if the field MEMBER exists in type AGGR, after including\n# INCLUDES, setting cache variable VAR accordingly.\nac_fn_c_check_member ()\n{\n  as_lineno=${as_lineno-\"$1\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $2.$3\" >&5\nprintf %s \"checking for $2.$3... \" >&6; }\nif eval test \\${$4+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$5\nint\nmain (void)\n{\nstatic $2 ac_aggr;\nif (ac_aggr.$3)\nreturn 0;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval \"$4=yes\"\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$5\nint\nmain (void)\n{\nstatic $2 ac_aggr;\nif (sizeof ac_aggr.$3)\nreturn 0;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval \"$4=yes\"\nelse $as_nop\n  eval \"$4=no\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\neval ac_res=\\$$4\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno\n\n} # ac_fn_c_check_member\nac_configure_args_raw=\nfor ac_arg\ndo\n  case $ac_arg in\n  *\\'*)\n    ac_arg=`printf \"%s\\n\" \"$ac_arg\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"` ;;\n  esac\n  as_fn_append ac_configure_args_raw \" '$ac_arg'\"\ndone\n\ncase $ac_configure_args_raw in\n  *$as_nl*)\n    ac_safe_unquote= ;;\n  *)\n    ac_unsafe_z='|&;<>()$`\\\\\"*?[ ''\t' # This string ends in space, tab.\n    ac_unsafe_a=\"$ac_unsafe_z#~\"\n    ac_safe_unquote=\"s/ '\\\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\\\)'/ \\\\1/g\"\n    ac_configure_args_raw=`      printf \"%s\\n\" \"$ac_configure_args_raw\" | sed \"$ac_safe_unquote\"`;;\nesac\n\ncat >config.log <<_ACEOF\nThis file contains any messages produced by compilers while\nrunning configure, to aid debugging if configure makes a mistake.\n\nIt was created by dummy $as_me 0, which was\ngenerated by GNU Autoconf 2.71.  Invocation command line was\n\n  $ $0$ac_configure_args_raw\n\n_ACEOF\nexec 5>>config.log\n{\ncat <<_ASUNAME\n## --------- ##\n## Platform. ##\n## --------- ##\n\nhostname = `(hostname || uname -n) 2>/dev/null | sed 1q`\nuname -m = `(uname -m) 2>/dev/null || echo unknown`\nuname -r = `(uname -r) 2>/dev/null || echo unknown`\nuname -s = `(uname -s) 2>/dev/null || echo unknown`\nuname -v = `(uname -v) 2>/dev/null || echo unknown`\n\n/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`\n/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`\n\n/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`\n/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`\n/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`\n/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`\n/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`\n/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`\n/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`\n\n_ASUNAME\n\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    printf \"%s\\n\" \"PATH: $as_dir\"\n  done\nIFS=$as_save_IFS\n\n} >&5\n\ncat >&5 <<_ACEOF\n\n\n## ----------- ##\n## Core tests. ##\n## ----------- ##\n\n_ACEOF\n\n\n# Keep a trace of the command line.\n# Strip out --no-create and --no-recursion so they do not pile up.\n# Strip out --silent because we don't want to record it for future runs.\n# Also quote any args containing shell meta-characters.\n# Make two passes to allow for proper duplicate-argument suppression.\nac_configure_args=\nac_configure_args0=\nac_configure_args1=\nac_must_keep_next=false\nfor ac_pass in 1 2\ndo\n  for ac_arg\n  do\n    case $ac_arg in\n    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;\n    -q | -quiet | --quiet | --quie | --qui | --qu | --q \\\n    | -silent | --silent | --silen | --sile | --sil)\n      continue ;;\n    *\\'*)\n      ac_arg=`printf \"%s\\n\" \"$ac_arg\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"` ;;\n    esac\n    case $ac_pass in\n    1) as_fn_append ac_configure_args0 \" '$ac_arg'\" ;;\n    2)\n      as_fn_append ac_configure_args1 \" '$ac_arg'\"\n      if test $ac_must_keep_next = true; then\n\tac_must_keep_next=false # Got value, back to normal.\n      else\n\tcase $ac_arg in\n\t  *=* | --config-cache | -C | -disable-* | --disable-* \\\n\t  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \\\n\t  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \\\n\t  | -with-* | --with-* | -without-* | --without-* | --x)\n\t    case \"$ac_configure_args0 \" in\n\t      \"$ac_configure_args1\"*\" '$ac_arg' \"* ) continue ;;\n\t    esac\n\t    ;;\n\t  -* ) ac_must_keep_next=true ;;\n\tesac\n      fi\n      as_fn_append ac_configure_args \" '$ac_arg'\"\n      ;;\n    esac\n  done\ndone\n{ ac_configure_args0=; unset ac_configure_args0;}\n{ ac_configure_args1=; unset ac_configure_args1;}\n\n# When interrupted or exit'd, cleanup temporary files, and complete\n# config.log.  We remove comments because anyway the quotes in there\n# would cause problems or look ugly.\n# WARNING: Use '\\'' to represent an apostrophe within the trap.\n# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.\ntrap 'exit_status=$?\n  # Sanitize IFS.\n  IFS=\" \"\"\t$as_nl\"\n  # Save into config.log some information that might help in debugging.\n  {\n    echo\n\n    printf \"%s\\n\" \"## ---------------- ##\n## Cache variables. ##\n## ---------------- ##\"\n    echo\n    # The following way of writing the cache mishandles newlines in values,\n(\n  for ac_var in `(set) 2>&1 | sed -n '\\''s/^\\([a-zA-Z_][a-zA-Z0-9_]*\\)=.*/\\1/p'\\''`; do\n    eval ac_val=\\$$ac_var\n    case $ac_val in #(\n    *${as_nl}*)\n      case $ac_var in #(\n      *_cv_*) { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: cache variable $ac_var contains a newline\" >&2;} ;;\n      esac\n      case $ac_var in #(\n      _ | IFS | as_nl) ;; #(\n      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(\n      *) { eval $ac_var=; unset $ac_var;} ;;\n      esac ;;\n    esac\n  done\n  (set) 2>&1 |\n    case $as_nl`(ac_space='\\'' '\\''; set) 2>&1` in #(\n    *${as_nl}ac_space=\\ *)\n      sed -n \\\n\t\"s/'\\''/'\\''\\\\\\\\'\\'''\\''/g;\n\t  s/^\\\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\\\)=\\\\(.*\\\\)/\\\\1='\\''\\\\2'\\''/p\"\n      ;; #(\n    *)\n      sed -n \"/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p\"\n      ;;\n    esac |\n    sort\n)\n    echo\n\n    printf \"%s\\n\" \"## ----------------- ##\n## Output variables. ##\n## ----------------- ##\"\n    echo\n    for ac_var in $ac_subst_vars\n    do\n      eval ac_val=\\$$ac_var\n      case $ac_val in\n      *\\'\\''*) ac_val=`printf \"%s\\n\" \"$ac_val\" | sed \"s/'\\''/'\\''\\\\\\\\\\\\\\\\'\\'''\\''/g\"`;;\n      esac\n      printf \"%s\\n\" \"$ac_var='\\''$ac_val'\\''\"\n    done | sort\n    echo\n\n    if test -n \"$ac_subst_files\"; then\n      printf \"%s\\n\" \"## ------------------- ##\n## File substitutions. ##\n## ------------------- ##\"\n      echo\n      for ac_var in $ac_subst_files\n      do\n\teval ac_val=\\$$ac_var\n\tcase $ac_val in\n\t*\\'\\''*) ac_val=`printf \"%s\\n\" \"$ac_val\" | sed \"s/'\\''/'\\''\\\\\\\\\\\\\\\\'\\'''\\''/g\"`;;\n\tesac\n\tprintf \"%s\\n\" \"$ac_var='\\''$ac_val'\\''\"\n      done | sort\n      echo\n    fi\n\n    if test -s confdefs.h; then\n      printf \"%s\\n\" \"## ----------- ##\n## confdefs.h. ##\n## ----------- ##\"\n      echo\n      cat confdefs.h\n      echo\n    fi\n    test \"$ac_signal\" != 0 &&\n      printf \"%s\\n\" \"$as_me: caught signal $ac_signal\"\n    printf \"%s\\n\" \"$as_me: exit $exit_status\"\n  } >&5\n  rm -f core *.core core.conftest.* &&\n    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&\n    exit $exit_status\n' 0\nfor ac_signal in 1 2 13 15; do\n  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal\ndone\nac_signal=0\n\n# confdefs.h avoids OS command line length limits that DEFS can exceed.\nrm -f -r conftest* confdefs.h\n\nprintf \"%s\\n\" \"/* confdefs.h */\" > confdefs.h\n\n# Predefined preprocessor variables.\n\nprintf \"%s\\n\" \"#define PACKAGE_NAME \\\"$PACKAGE_NAME\\\"\" >>confdefs.h\n\nprintf \"%s\\n\" \"#define PACKAGE_TARNAME \\\"$PACKAGE_TARNAME\\\"\" >>confdefs.h\n\nprintf \"%s\\n\" \"#define PACKAGE_VERSION \\\"$PACKAGE_VERSION\\\"\" >>confdefs.h\n\nprintf \"%s\\n\" \"#define PACKAGE_STRING \\\"$PACKAGE_STRING\\\"\" >>confdefs.h\n\nprintf \"%s\\n\" \"#define PACKAGE_BUGREPORT \\\"$PACKAGE_BUGREPORT\\\"\" >>confdefs.h\n\nprintf \"%s\\n\" \"#define PACKAGE_URL \\\"$PACKAGE_URL\\\"\" >>confdefs.h\n\n\n# Let the site file select an alternate cache file if it wants to.\n# Prefer an explicitly selected file to automatically selected ones.\nif test -n \"$CONFIG_SITE\"; then\n  ac_site_files=\"$CONFIG_SITE\"\nelif test \"x$prefix\" != xNONE; then\n  ac_site_files=\"$prefix/share/config.site $prefix/etc/config.site\"\nelse\n  ac_site_files=\"$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site\"\nfi\n\nfor ac_site_file in $ac_site_files\ndo\n  case $ac_site_file in #(\n  */*) :\n     ;; #(\n  *) :\n    ac_site_file=./$ac_site_file ;;\nesac\n  if test -f \"$ac_site_file\" && test -r \"$ac_site_file\"; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file\" >&5\nprintf \"%s\\n\" \"$as_me: loading site script $ac_site_file\" >&6;}\n    sed 's/^/| /' \"$ac_site_file\" >&5\n    . \"$ac_site_file\" \\\n      || { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"failed to load site script $ac_site_file\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\n  fi\ndone\n\nif test -r \"$cache_file\"; then\n  # Some versions of bash will fail to source /dev/null (special files\n  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.\n  if test /dev/null != \"$cache_file\" && test -f \"$cache_file\"; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: loading cache $cache_file\" >&5\nprintf \"%s\\n\" \"$as_me: loading cache $cache_file\" >&6;}\n    case $cache_file in\n      [\\\\/]* | ?:[\\\\/]* ) . \"$cache_file\";;\n      *)                      . \"./$cache_file\";;\n    esac\n  fi\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: creating cache $cache_file\" >&5\nprintf \"%s\\n\" \"$as_me: creating cache $cache_file\" >&6;}\n  >$cache_file\nfi\n\n# Test code for whether the C compiler supports C89 (global declarations)\nac_c_conftest_c89_globals='\n/* Does the compiler advertise C89 conformance?\n   Do not test the value of __STDC__, because some compilers set it to 0\n   while being otherwise adequately conformant. */\n#if !defined __STDC__\n# error \"Compiler does not advertise C89 conformance\"\n#endif\n\n#include <stddef.h>\n#include <stdarg.h>\nstruct stat;\n/* Most of the following tests are stolen from RCS 5.7 src/conf.sh.  */\nstruct buf { int x; };\nstruct buf * (*rcsopen) (struct buf *, struct stat *, int);\nstatic char *e (p, i)\n     char **p;\n     int i;\n{\n  return p[i];\n}\nstatic char *f (char * (*g) (char **, int), char **p, ...)\n{\n  char *s;\n  va_list v;\n  va_start (v,p);\n  s = g (p, va_arg (v,int));\n  va_end (v);\n  return s;\n}\n\n/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has\n   function prototypes and stuff, but not \\xHH hex character constants.\n   These do not provoke an error unfortunately, instead are silently treated\n   as an \"x\".  The following induces an error, until -std is added to get\n   proper ANSI mode.  Curiously \\x00 != x always comes out true, for an\n   array size at least.  It is necessary to write \\x00 == 0 to get something\n   that is true only with -std.  */\nint osf4_cc_array ['\\''\\x00'\\'' == 0 ? 1 : -1];\n\n/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters\n   inside strings and character constants.  */\n#define FOO(x) '\\''x'\\''\nint xlc6_cc_array[FOO(a) == '\\''x'\\'' ? 1 : -1];\n\nint test (int i, double x);\nstruct s1 {int (*f) (int a);};\nstruct s2 {int (*f) (double a);};\nint pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),\n               int, int);'\n\n# Test code for whether the C compiler supports C89 (body of main).\nac_c_conftest_c89_main='\nok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);\n'\n\n# Test code for whether the C compiler supports C99 (global declarations)\nac_c_conftest_c99_globals='\n// Does the compiler advertise C99 conformance?\n#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L\n# error \"Compiler does not advertise C99 conformance\"\n#endif\n\n#include <stdbool.h>\nextern int puts (const char *);\nextern int printf (const char *, ...);\nextern int dprintf (int, const char *, ...);\nextern void *malloc (size_t);\n\n// Check varargs macros.  These examples are taken from C99 6.10.3.5.\n// dprintf is used instead of fprintf to avoid needing to declare\n// FILE and stderr.\n#define debug(...) dprintf (2, __VA_ARGS__)\n#define showlist(...) puts (#__VA_ARGS__)\n#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))\nstatic void\ntest_varargs_macros (void)\n{\n  int x = 1234;\n  int y = 5678;\n  debug (\"Flag\");\n  debug (\"X = %d\\n\", x);\n  showlist (The first, second, and third items.);\n  report (x>y, \"x is %d but y is %d\", x, y);\n}\n\n// Check long long types.\n#define BIG64 18446744073709551615ull\n#define BIG32 4294967295ul\n#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)\n#if !BIG_OK\n  #error \"your preprocessor is broken\"\n#endif\n#if BIG_OK\n#else\n  #error \"your preprocessor is broken\"\n#endif\nstatic long long int bignum = -9223372036854775807LL;\nstatic unsigned long long int ubignum = BIG64;\n\nstruct incomplete_array\n{\n  int datasize;\n  double data[];\n};\n\nstruct named_init {\n  int number;\n  const wchar_t *name;\n  double average;\n};\n\ntypedef const char *ccp;\n\nstatic inline int\ntest_restrict (ccp restrict text)\n{\n  // See if C++-style comments work.\n  // Iterate through items via the restricted pointer.\n  // Also check for declarations in for loops.\n  for (unsigned int i = 0; *(text+i) != '\\''\\0'\\''; ++i)\n    continue;\n  return 0;\n}\n\n// Check varargs and va_copy.\nstatic bool\ntest_varargs (const char *format, ...)\n{\n  va_list args;\n  va_start (args, format);\n  va_list args_copy;\n  va_copy (args_copy, args);\n\n  const char *str = \"\";\n  int number = 0;\n  float fnumber = 0;\n\n  while (*format)\n    {\n      switch (*format++)\n\t{\n\tcase '\\''s'\\'': // string\n\t  str = va_arg (args_copy, const char *);\n\t  break;\n\tcase '\\''d'\\'': // int\n\t  number = va_arg (args_copy, int);\n\t  break;\n\tcase '\\''f'\\'': // float\n\t  fnumber = va_arg (args_copy, double);\n\t  break;\n\tdefault:\n\t  break;\n\t}\n    }\n  va_end (args_copy);\n  va_end (args);\n\n  return *str && number && fnumber;\n}\n'\n\n# Test code for whether the C compiler supports C99 (body of main).\nac_c_conftest_c99_main='\n  // Check bool.\n  _Bool success = false;\n  success |= (argc != 0);\n\n  // Check restrict.\n  if (test_restrict (\"String literal\") == 0)\n    success = true;\n  char *restrict newvar = \"Another string\";\n\n  // Check varargs.\n  success &= test_varargs (\"s, d'\\'' f .\", \"string\", 65, 34.234);\n  test_varargs_macros ();\n\n  // Check flexible array members.\n  struct incomplete_array *ia =\n    malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));\n  ia->datasize = 10;\n  for (int i = 0; i < ia->datasize; ++i)\n    ia->data[i] = i * 1.234;\n\n  // Check named initializers.\n  struct named_init ni = {\n    .number = 34,\n    .name = L\"Test wide string\",\n    .average = 543.34343,\n  };\n\n  ni.number = 58;\n\n  int dynamic_array[ni.number];\n  dynamic_array[0] = argv[0][0];\n  dynamic_array[ni.number - 1] = 543;\n\n  // work around unused variable warnings\n  ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\\''x'\\''\n\t || dynamic_array[ni.number - 1] != 543);\n'\n\n# Test code for whether the C compiler supports C11 (global declarations)\nac_c_conftest_c11_globals='\n// Does the compiler advertise C11 conformance?\n#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L\n# error \"Compiler does not advertise C11 conformance\"\n#endif\n\n// Check _Alignas.\nchar _Alignas (double) aligned_as_double;\nchar _Alignas (0) no_special_alignment;\nextern char aligned_as_int;\nchar _Alignas (0) _Alignas (int) aligned_as_int;\n\n// Check _Alignof.\nenum\n{\n  int_alignment = _Alignof (int),\n  int_array_alignment = _Alignof (int[100]),\n  char_alignment = _Alignof (char)\n};\n_Static_assert (0 < -_Alignof (int), \"_Alignof is signed\");\n\n// Check _Noreturn.\nint _Noreturn does_not_return (void) { for (;;) continue; }\n\n// Check _Static_assert.\nstruct test_static_assert\n{\n  int x;\n  _Static_assert (sizeof (int) <= sizeof (long int),\n                  \"_Static_assert does not work in struct\");\n  long int y;\n};\n\n// Check UTF-8 literals.\n#define u8 syntax error!\nchar const utf8_literal[] = u8\"happens to be ASCII\" \"another string\";\n\n// Check duplicate typedefs.\ntypedef long *long_ptr;\ntypedef long int *long_ptr;\ntypedef long_ptr long_ptr;\n\n// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.\nstruct anonymous\n{\n  union {\n    struct { int i; int j; };\n    struct { int k; long int l; } w;\n  };\n  int m;\n} v1;\n'\n\n# Test code for whether the C compiler supports C11 (body of main).\nac_c_conftest_c11_main='\n  _Static_assert ((offsetof (struct anonymous, i)\n\t\t   == offsetof (struct anonymous, w.k)),\n\t\t  \"Anonymous union alignment botch\");\n  v1.i = 2;\n  v1.w.k = 5;\n  ok |= v1.i != 5;\n'\n\n# Test code for whether the C compiler supports C11 (complete).\nac_c_conftest_c11_program=\"${ac_c_conftest_c89_globals}\n${ac_c_conftest_c99_globals}\n${ac_c_conftest_c11_globals}\n\nint\nmain (int argc, char **argv)\n{\n  int ok = 0;\n  ${ac_c_conftest_c89_main}\n  ${ac_c_conftest_c99_main}\n  ${ac_c_conftest_c11_main}\n  return ok;\n}\n\"\n\n# Test code for whether the C compiler supports C99 (complete).\nac_c_conftest_c99_program=\"${ac_c_conftest_c89_globals}\n${ac_c_conftest_c99_globals}\n\nint\nmain (int argc, char **argv)\n{\n  int ok = 0;\n  ${ac_c_conftest_c89_main}\n  ${ac_c_conftest_c99_main}\n  return ok;\n}\n\"\n\n# Test code for whether the C compiler supports C89 (complete).\nac_c_conftest_c89_program=\"${ac_c_conftest_c89_globals}\n\nint\nmain (int argc, char **argv)\n{\n  int ok = 0;\n  ${ac_c_conftest_c89_main}\n  return ok;\n}\n\"\n\nas_fn_append ac_header_c_list \" stdio.h stdio_h HAVE_STDIO_H\"\nas_fn_append ac_header_c_list \" stdlib.h stdlib_h HAVE_STDLIB_H\"\nas_fn_append ac_header_c_list \" string.h string_h HAVE_STRING_H\"\nas_fn_append ac_header_c_list \" inttypes.h inttypes_h HAVE_INTTYPES_H\"\nas_fn_append ac_header_c_list \" stdint.h stdint_h HAVE_STDINT_H\"\nas_fn_append ac_header_c_list \" strings.h strings_h HAVE_STRINGS_H\"\nas_fn_append ac_header_c_list \" sys/stat.h sys_stat_h HAVE_SYS_STAT_H\"\nas_fn_append ac_header_c_list \" sys/types.h sys_types_h HAVE_SYS_TYPES_H\"\nas_fn_append ac_header_c_list \" unistd.h unistd_h HAVE_UNISTD_H\"\nas_fn_append ac_header_c_list \" wchar.h wchar_h HAVE_WCHAR_H\"\nas_fn_append ac_header_c_list \" minix/config.h minix_config_h HAVE_MINIX_CONFIG_H\"\nas_fn_append ac_header_c_list \" execinfo.h execinfo_h HAVE_EXECINFO_H\"\nas_fn_append ac_func_c_list \" getdelim HAVE_GETDELIM\"\nas_fn_append ac_header_c_list \" sys/socket.h sys_socket_h HAVE_SYS_SOCKET_H\"\nas_fn_append ac_header_c_list \" sys/param.h sys_param_h HAVE_SYS_PARAM_H\"\nas_fn_append ac_header_c_list \" netdb.h netdb_h HAVE_NETDB_H\"\nas_fn_append ac_header_c_list \" sys/time.h sys_time_h HAVE_SYS_TIME_H\"\nas_fn_append ac_func_c_list \" gettimeofday HAVE_GETTIMEOFDAY\"\nas_fn_append ac_header_c_list \" limits.h limits_h HAVE_LIMITS_H\"\nas_fn_append ac_func_c_list \" _set_invalid_parameter_handler HAVE__SET_INVALID_PARAMETER_HANDLER\"\nas_fn_append ac_header_c_list \" sys/resource.h sys_resource_h HAVE_SYS_RESOURCE_H\"\nas_fn_append ac_header_c_list \" sys/uio.h sys_uio_h HAVE_SYS_UIO_H\"\nas_fn_append ac_header_c_list \" sys/utsname.h sys_utsname_h HAVE_SYS_UTSNAME_H\"\nas_fn_append ac_func_c_list \" localtime_r HAVE_LOCALTIME_R\"\n\n# Auxiliary files required by this configure script.\nac_aux_files=\"config.guess config.sub compile missing install-sh\"\n\n# Locations in which to look for auxiliary files.\nac_aux_dir_candidates=\"${srcdir}/build-aux\"\n\n# Search for a directory containing all of the required auxiliary files,\n# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.\n# If we don't find one directory that contains all the files we need,\n# we report the set of missing files from the *first* directory in\n# $ac_aux_dir_candidates and give up.\nac_missing_aux_files=\"\"\nac_first_candidate=:\nprintf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files\" >&5\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nas_found=false\nfor as_dir in $ac_aux_dir_candidates\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n  as_found=:\n\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:  trying $as_dir\" >&5\n  ac_aux_dir_found=yes\n  ac_install_sh=\n  for ac_aux in $ac_aux_files\n  do\n    # As a special case, if \"install-sh\" is required, that requirement\n    # can be satisfied by any of \"install-sh\", \"install.sh\", or \"shtool\",\n    # and $ac_install_sh is set appropriately for whichever one is found.\n    if test x\"$ac_aux\" = x\"install-sh\"\n    then\n      if test -f \"${as_dir}install-sh\"; then\n        printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   ${as_dir}install-sh found\" >&5\n        ac_install_sh=\"${as_dir}install-sh -c\"\n      elif test -f \"${as_dir}install.sh\"; then\n        printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   ${as_dir}install.sh found\" >&5\n        ac_install_sh=\"${as_dir}install.sh -c\"\n      elif test -f \"${as_dir}shtool\"; then\n        printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   ${as_dir}shtool found\" >&5\n        ac_install_sh=\"${as_dir}shtool install -c\"\n      else\n        ac_aux_dir_found=no\n        if $ac_first_candidate; then\n          ac_missing_aux_files=\"${ac_missing_aux_files} install-sh\"\n        else\n          break\n        fi\n      fi\n    else\n      if test -f \"${as_dir}${ac_aux}\"; then\n        printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   ${as_dir}${ac_aux} found\" >&5\n      else\n        ac_aux_dir_found=no\n        if $ac_first_candidate; then\n          ac_missing_aux_files=\"${ac_missing_aux_files} ${ac_aux}\"\n        else\n          break\n        fi\n      fi\n    fi\n  done\n  if test \"$ac_aux_dir_found\" = yes; then\n    ac_aux_dir=\"$as_dir\"\n    break\n  fi\n  ac_first_candidate=false\n\n  as_found=false\ndone\nIFS=$as_save_IFS\nif $as_found\nthen :\n\nelse $as_nop\n  as_fn_error $? \"cannot find required auxiliary files:$ac_missing_aux_files\" \"$LINENO\" 5\nfi\n\n\n# These three variables are undocumented and unsupported,\n# and are intended to be withdrawn in a future Autoconf release.\n# They can cause serious problems if a builder's source tree is in a directory\n# whose full name contains unusual characters.\nif test -f \"${ac_aux_dir}config.guess\"; then\n  ac_config_guess=\"$SHELL ${ac_aux_dir}config.guess\"\nfi\nif test -f \"${ac_aux_dir}config.sub\"; then\n  ac_config_sub=\"$SHELL ${ac_aux_dir}config.sub\"\nfi\nif test -f \"$ac_aux_dir/configure\"; then\n  ac_configure=\"$SHELL ${ac_aux_dir}configure\"\nfi\n\n# Check that the precious variables saved in the cache have kept the same\n# value.\nac_cache_corrupted=false\nfor ac_var in $ac_precious_vars; do\n  eval ac_old_set=\\$ac_cv_env_${ac_var}_set\n  eval ac_new_set=\\$ac_env_${ac_var}_set\n  eval ac_old_val=\\$ac_cv_env_${ac_var}_value\n  eval ac_new_val=\\$ac_env_${ac_var}_value\n  case $ac_old_set,$ac_new_set in\n    set,)\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: \\`$ac_var' was set to \\`$ac_old_val' in the previous run\" >&5\nprintf \"%s\\n\" \"$as_me: error: \\`$ac_var' was set to \\`$ac_old_val' in the previous run\" >&2;}\n      ac_cache_corrupted=: ;;\n    ,set)\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: \\`$ac_var' was not set in the previous run\" >&5\nprintf \"%s\\n\" \"$as_me: error: \\`$ac_var' was not set in the previous run\" >&2;}\n      ac_cache_corrupted=: ;;\n    ,);;\n    *)\n      if test \"x$ac_old_val\" != \"x$ac_new_val\"; then\n\t# differences in whitespace do not lead to failure.\n\tac_old_val_w=`echo x $ac_old_val`\n\tac_new_val_w=`echo x $ac_new_val`\n\tif test \"$ac_old_val_w\" != \"$ac_new_val_w\"; then\n\t  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: \\`$ac_var' has changed since the previous run:\" >&5\nprintf \"%s\\n\" \"$as_me: error: \\`$ac_var' has changed since the previous run:\" >&2;}\n\t  ac_cache_corrupted=:\n\telse\n\t  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \\`$ac_var' since the previous run:\" >&5\nprintf \"%s\\n\" \"$as_me: warning: ignoring whitespace changes in \\`$ac_var' since the previous run:\" >&2;}\n\t  eval $ac_var=\\$ac_old_val\n\tfi\n\t{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   former value:  \\`$ac_old_val'\" >&5\nprintf \"%s\\n\" \"$as_me:   former value:  \\`$ac_old_val'\" >&2;}\n\t{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}:   current value: \\`$ac_new_val'\" >&5\nprintf \"%s\\n\" \"$as_me:   current value: \\`$ac_new_val'\" >&2;}\n      fi;;\n  esac\n  # Pass precious variables to config.status.\n  if test \"$ac_new_set\" = set; then\n    case $ac_new_val in\n    *\\'*) ac_arg=$ac_var=`printf \"%s\\n\" \"$ac_new_val\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"` ;;\n    *) ac_arg=$ac_var=$ac_new_val ;;\n    esac\n    case \" $ac_configure_args \" in\n      *\" '$ac_arg' \"*) ;; # Avoid dups.  Use of quotes ensures accuracy.\n      *) as_fn_append ac_configure_args \" '$ac_arg'\" ;;\n    esac\n  fi\ndone\nif $ac_cache_corrupted; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build\" >&5\nprintf \"%s\\n\" \"$as_me: error: changes in the environment can compromise the build\" >&2;}\n  as_fn_error $? \"run \\`${MAKE-make} distclean' and/or \\`rm $cache_file'\n\t    and start over\" \"$LINENO\" 5\nfi\n## -------------------- ##\n## Main body of script. ##\n## -------------------- ##\n\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n\n\n\nam__api_version='1.16'\n\n\n\n  # Find a good install program.  We prefer a C program (faster),\n# so one script is as good as another.  But avoid the broken or\n# incompatible versions:\n# SysV /etc/install, /usr/sbin/install\n# SunOS /usr/etc/install\n# IRIX /sbin/install\n# AIX /bin/install\n# AmigaOS /C/install, which installs bootblocks on floppy discs\n# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag\n# AFS /usr/afsws/bin/install, which mishandles nonexistent args\n# SVR4 /usr/ucb/install, which tries to use the nonexistent group \"staff\"\n# OS/2's system install, which has a completely different semantic\n# ./install, which can be erroneously created by make from ./install.sh.\n# Reject install programs that cannot install multiple files.\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install\" >&5\nprintf %s \"checking for a BSD-compatible install... \" >&6; }\nif test -z \"$INSTALL\"; then\nif test ${ac_cv_path_install+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    # Account for fact that we put trailing slashes in our PATH walk.\ncase $as_dir in #((\n  ./ | /[cC]/* | \\\n  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \\\n  ?:[\\\\/]os2[\\\\/]install[\\\\/]* | ?:[\\\\/]OS2[\\\\/]INSTALL[\\\\/]* | \\\n  /usr/ucb/* ) ;;\n  *)\n    # OSF1 and SCO ODT 3.0 have their own names for install.\n    # Don't use installbsd from OSF since it installs stuff as root\n    # by default.\n    for ac_prog in ginstall scoinst install; do\n      for ac_exec_ext in '' $ac_executable_extensions; do\n\tif as_fn_executable_p \"$as_dir$ac_prog$ac_exec_ext\"; then\n\t  if test $ac_prog = install &&\n\t    grep dspmsg \"$as_dir$ac_prog$ac_exec_ext\" >/dev/null 2>&1; then\n\t    # AIX install.  It has an incompatible calling convention.\n\t    :\n\t  elif test $ac_prog = install &&\n\t    grep pwplus \"$as_dir$ac_prog$ac_exec_ext\" >/dev/null 2>&1; then\n\t    # program-specific install script used by HP pwplus--don't use.\n\t    :\n\t  else\n\t    rm -rf conftest.one conftest.two conftest.dir\n\t    echo one > conftest.one\n\t    echo two > conftest.two\n\t    mkdir conftest.dir\n\t    if \"$as_dir$ac_prog$ac_exec_ext\" -c conftest.one conftest.two \"`pwd`/conftest.dir/\" &&\n\t      test -s conftest.one && test -s conftest.two &&\n\t      test -s conftest.dir/conftest.one &&\n\t      test -s conftest.dir/conftest.two\n\t    then\n\t      ac_cv_path_install=\"$as_dir$ac_prog$ac_exec_ext -c\"\n\t      break 3\n\t    fi\n\t  fi\n\tfi\n      done\n    done\n    ;;\nesac\n\n  done\nIFS=$as_save_IFS\n\nrm -rf conftest.one conftest.two conftest.dir\n\nfi\n  if test ${ac_cv_path_install+y}; then\n    INSTALL=$ac_cv_path_install\n  else\n    # As a last resort, use the slow shell script.  Don't cache a\n    # value for INSTALL within a source directory, because that will\n    # break other packages using the cache if that directory is\n    # removed, or if the value is a relative name.\n    INSTALL=$ac_install_sh\n  fi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $INSTALL\" >&5\nprintf \"%s\\n\" \"$INSTALL\" >&6; }\n\n# Use test -z because SunOS4 sh mishandles braces in ${var-val}.\n# It thinks the first close brace ends the variable substitution.\ntest -z \"$INSTALL_PROGRAM\" && INSTALL_PROGRAM='${INSTALL}'\n\ntest -z \"$INSTALL_SCRIPT\" && INSTALL_SCRIPT='${INSTALL}'\n\ntest -z \"$INSTALL_DATA\" && INSTALL_DATA='${INSTALL} -m 644'\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether build environment is sane\" >&5\nprintf %s \"checking whether build environment is sane... \" >&6; }\n# Reject unsafe characters in $srcdir or the absolute working directory\n# name.  Accept space and tab only in the latter.\nam_lf='\n'\ncase `pwd` in\n  *[\\\\\\\"\\#\\$\\&\\'\\`$am_lf]*)\n    as_fn_error $? \"unsafe absolute working directory name\" \"$LINENO\" 5;;\nesac\ncase $srcdir in\n  *[\\\\\\\"\\#\\$\\&\\'\\`$am_lf\\ \\\t]*)\n    as_fn_error $? \"unsafe srcdir value: '$srcdir'\" \"$LINENO\" 5;;\nesac\n\n# Do 'set' in a subshell so we don't clobber the current shell's\n# arguments.  Must try -L first in case configure is actually a\n# symlink; some systems play weird games with the mod time of symlinks\n# (eg FreeBSD returns the mod time of the symlink's containing\n# directory).\nif (\n   am_has_slept=no\n   for am_try in 1 2; do\n     echo \"timestamp, slept: $am_has_slept\" > conftest.file\n     set X `ls -Lt \"$srcdir/configure\" conftest.file 2> /dev/null`\n     if test \"$*\" = \"X\"; then\n\t# -L didn't work.\n\tset X `ls -t \"$srcdir/configure\" conftest.file`\n     fi\n     if test \"$*\" != \"X $srcdir/configure conftest.file\" \\\n\t&& test \"$*\" != \"X conftest.file $srcdir/configure\"; then\n\n\t# If neither matched, then we have a broken ls.  This can happen\n\t# if, for instance, CONFIG_SHELL is bash and it inherits a\n\t# broken ls alias from the environment.  This has actually\n\t# happened.  Such a system could not be considered \"sane\".\n\tas_fn_error $? \"ls -t appears to fail.  Make sure there is not a broken\n  alias in your environment\" \"$LINENO\" 5\n     fi\n     if test \"$2\" = conftest.file || test $am_try -eq 2; then\n       break\n     fi\n     # Just in case.\n     sleep 1\n     am_has_slept=yes\n   done\n   test \"$2\" = conftest.file\n   )\nthen\n   # Ok.\n   :\nelse\n   as_fn_error $? \"newly created file is older than distributed files!\nCheck your system clock\" \"$LINENO\" 5\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: yes\" >&5\nprintf \"%s\\n\" \"yes\" >&6; }\n# If we didn't sleep, we still need to ensure time stamps of config.status and\n# generated files are strictly newer.\nam_sleep_pid=\nif grep 'slept: no' conftest.file >/dev/null 2>&1; then\n  ( sleep 1 ) &\n  am_sleep_pid=$!\nfi\n\nrm -f conftest.file\n\ntest \"$program_prefix\" != NONE &&\n  program_transform_name=\"s&^&$program_prefix&;$program_transform_name\"\n# Use a double $ so make ignores it.\ntest \"$program_suffix\" != NONE &&\n  program_transform_name=\"s&\\$&$program_suffix&;$program_transform_name\"\n# Double any \\ or $.\n# By default was `s,x,x', remove it if useless.\nac_script='s/[\\\\$]/&&/g;s/;s,x,x,$//'\nprogram_transform_name=`printf \"%s\\n\" \"$program_transform_name\" | sed \"$ac_script\"`\n\n\n# Expand $ac_aux_dir to an absolute path.\nam_aux_dir=`cd \"$ac_aux_dir\" && pwd`\n\n\n  if test x\"${MISSING+set}\" != xset; then\n  MISSING=\"\\${SHELL} '$am_aux_dir/missing'\"\nfi\n# Use eval to expand $SHELL\nif eval \"$MISSING --is-lightweight\"; then\n  am_missing_run=\"$MISSING \"\nelse\n  am_missing_run=\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: 'missing' script is too old or missing\" >&2;}\nfi\n\nif test x\"${install_sh+set}\" != xset; then\n  case $am_aux_dir in\n  *\\ * | *\\\t*)\n    install_sh=\"\\${SHELL} '$am_aux_dir/install-sh'\" ;;\n  *)\n    install_sh=\"\\${SHELL} $am_aux_dir/install-sh\"\n  esac\nfi\n\n# Installed binaries are usually stripped using 'strip' when the user\n# run \"make install-strip\".  However 'strip' might not be the right\n# tool to use in cross-compilation environments, therefore Automake\n# will honor the 'STRIP' environment variable to overrule this program.\nif test \"$cross_compiling\" != no; then\n  if test -n \"$ac_tool_prefix\"; then\n  # Extract the first word of \"${ac_tool_prefix}strip\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}strip; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_STRIP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$STRIP\"; then\n  ac_cv_prog_STRIP=\"$STRIP\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_STRIP=\"${ac_tool_prefix}strip\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nSTRIP=$ac_cv_prog_STRIP\nif test -n \"$STRIP\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $STRIP\" >&5\nprintf \"%s\\n\" \"$STRIP\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$ac_cv_prog_STRIP\"; then\n  ac_ct_STRIP=$STRIP\n  # Extract the first word of \"strip\", so it can be a program name with args.\nset dummy strip; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_STRIP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_STRIP\"; then\n  ac_cv_prog_ac_ct_STRIP=\"$ac_ct_STRIP\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_STRIP=\"strip\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP\nif test -n \"$ac_ct_STRIP\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP\" >&5\nprintf \"%s\\n\" \"$ac_ct_STRIP\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n  if test \"x$ac_ct_STRIP\" = x; then\n    STRIP=\":\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    STRIP=$ac_ct_STRIP\n  fi\nelse\n  STRIP=\"$ac_cv_prog_STRIP\"\nfi\n\nfi\nINSTALL_STRIP_PROGRAM=\"\\$(install_sh) -c -s\"\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p\" >&5\nprintf %s \"checking for a race-free mkdir -p... \" >&6; }\nif test -z \"$MKDIR_P\"; then\n  if test ${ac_cv_path_mkdir+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_prog in mkdir gmkdir; do\n\t for ac_exec_ext in '' $ac_executable_extensions; do\n\t   as_fn_executable_p \"$as_dir$ac_prog$ac_exec_ext\" || continue\n\t   case `\"$as_dir$ac_prog$ac_exec_ext\" --version 2>&1` in #(\n\t     'mkdir ('*'coreutils) '* | \\\n\t     'BusyBox '* | \\\n\t     'mkdir (fileutils) '4.1*)\n\t       ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext\n\t       break 3;;\n\t   esac\n\t done\n       done\n  done\nIFS=$as_save_IFS\n\nfi\n\n  test -d ./--version && rmdir ./--version\n  if test ${ac_cv_path_mkdir+y}; then\n    MKDIR_P=\"$ac_cv_path_mkdir -p\"\n  else\n    # As a last resort, use the slow shell script.  Don't cache a\n    # value for MKDIR_P within a source directory, because that will\n    # break other packages using the cache if that directory is\n    # removed, or if the value is a relative name.\n    MKDIR_P=\"$ac_install_sh -d\"\n  fi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $MKDIR_P\" >&5\nprintf \"%s\\n\" \"$MKDIR_P\" >&6; }\n\nfor ac_prog in gawk mawk nawk awk\ndo\n  # Extract the first word of \"$ac_prog\", so it can be a program name with args.\nset dummy $ac_prog; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_AWK+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$AWK\"; then\n  ac_cv_prog_AWK=\"$AWK\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_AWK=\"$ac_prog\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nAWK=$ac_cv_prog_AWK\nif test -n \"$AWK\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $AWK\" >&5\nprintf \"%s\\n\" \"$AWK\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\n  test -n \"$AWK\" && break\ndone\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \\$(MAKE)\" >&5\nprintf %s \"checking whether ${MAKE-make} sets \\$(MAKE)... \" >&6; }\nset x ${MAKE-make}\nac_make=`printf \"%s\\n\" \"$2\" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`\nif eval test \\${ac_cv_prog_make_${ac_make}_set+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat >conftest.make <<\\_ACEOF\nSHELL = /bin/sh\nall:\n\t@echo '@@@%%%=$(MAKE)=@@@%%%'\n_ACEOF\n# GNU make sometimes prints \"make[1]: Entering ...\", which would confuse us.\ncase `${MAKE-make} -f conftest.make 2>/dev/null` in\n  *@@@%%%=?*=@@@%%%*)\n    eval ac_cv_prog_make_${ac_make}_set=yes;;\n  *)\n    eval ac_cv_prog_make_${ac_make}_set=no;;\nesac\nrm -f conftest.make\nfi\nif eval test \\$ac_cv_prog_make_${ac_make}_set = yes; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: yes\" >&5\nprintf \"%s\\n\" \"yes\" >&6; }\n  SET_MAKE=\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\n  SET_MAKE=\"MAKE=${MAKE-make}\"\nfi\n\nrm -rf .tst 2>/dev/null\nmkdir .tst 2>/dev/null\nif test -d .tst; then\n  am__leading_dot=.\nelse\n  am__leading_dot=_\nfi\nrmdir .tst 2>/dev/null\n\n# Check whether --enable-silent-rules was given.\nif test ${enable_silent_rules+y}\nthen :\n  enableval=$enable_silent_rules;\nfi\n\ncase $enable_silent_rules in # (((\n  yes) AM_DEFAULT_VERBOSITY=0;;\n   no) AM_DEFAULT_VERBOSITY=1;;\n    *) AM_DEFAULT_VERBOSITY=1;;\nesac\nam_make=${MAKE-make}\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables\" >&5\nprintf %s \"checking whether $am_make supports nested variables... \" >&6; }\nif test ${am_cv_make_support_nested_variables+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if printf \"%s\\n\" 'TRUE=$(BAR$(V))\nBAR0=false\nBAR1=true\nV=1\nam__doit:\n\t@$(TRUE)\n.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then\n  am_cv_make_support_nested_variables=yes\nelse\n  am_cv_make_support_nested_variables=no\nfi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables\" >&5\nprintf \"%s\\n\" \"$am_cv_make_support_nested_variables\" >&6; }\nif test $am_cv_make_support_nested_variables = yes; then\n    AM_V='$(V)'\n  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'\nelse\n  AM_V=$AM_DEFAULT_VERBOSITY\n  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY\nfi\nAM_BACKSLASH='\\'\n\nif test \"`cd $srcdir && pwd`\" != \"`pwd`\"; then\n  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output\n  # is not polluted with repeated \"-I.\"\n  am__isrc=' -I$(srcdir)'\n  # test to see if srcdir already configured\n  if test -f $srcdir/config.status; then\n    as_fn_error $? \"source directory already configured; run \\\"make distclean\\\" there first\" \"$LINENO\" 5\n  fi\nfi\n\n# test whether we have cygpath\nif test -z \"$CYGPATH_W\"; then\n  if (cygpath --version) >/dev/null 2>/dev/null; then\n    CYGPATH_W='cygpath -w'\n  else\n    CYGPATH_W=echo\n  fi\nfi\n\n\n# Define the identity of the package.\n PACKAGE='dummy'\n VERSION='0'\n\n\nprintf \"%s\\n\" \"#define PACKAGE \\\"$PACKAGE\\\"\" >>confdefs.h\n\n\nprintf \"%s\\n\" \"#define VERSION \\\"$VERSION\\\"\" >>confdefs.h\n\n# Some tools Automake needs.\n\nACLOCAL=${ACLOCAL-\"${am_missing_run}aclocal-${am__api_version}\"}\n\n\nAUTOCONF=${AUTOCONF-\"${am_missing_run}autoconf\"}\n\n\nAUTOMAKE=${AUTOMAKE-\"${am_missing_run}automake-${am__api_version}\"}\n\n\nAUTOHEADER=${AUTOHEADER-\"${am_missing_run}autoheader\"}\n\n\nMAKEINFO=${MAKEINFO-\"${am_missing_run}makeinfo\"}\n\n# For better backward compatibility.  To be removed once Automake 1.9.x\n# dies out for good.  For more background, see:\n# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>\n# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>\nmkdir_p='$(MKDIR_P)'\n\n# We need awk for the \"check\" target (and possibly the TAP driver).  The\n# system \"awk\" is bad on some platforms.\n# Always define AMTAR for backward compatibility.  Yes, it's still used\n# in the wild :-(  We should find a proper way to deprecate it ...\nAMTAR='$${TAR-tar}'\n\n\n# We'll loop over all known methods to create a tar archive until one works.\n_am_tools='gnutar  pax cpio none'\n\nam__tar='$${TAR-tar} chof - \"$$tardir\"' am__untar='$${TAR-tar} xf -'\n\n\n\n\n\n\n# POSIX will say in a future version that running \"rm -f\" with no argument\n# is OK; and we want to be able to make that assumption in our Makefile\n# recipes.  So use an aggressive probe to check that the usage we want is\n# actually supported \"in the wild\" to an acceptable degree.\n# See automake bug#10828.\n# To make any issue more visible, cause the running configure to be aborted\n# by default if the 'rm' program in use doesn't match our expectations; the\n# user can still override this though.\nif rm -f && rm -fr && rm -rf; then : OK; else\n  cat >&2 <<'END'\nOops!\n\nYour 'rm' program seems unable to run without file operands specified\non the command line, even when the '-f' option is present.  This is contrary\nto the behaviour of most rm programs out there, and not conforming with\nthe upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>\n\nPlease tell bug-automake@gnu.org about your system, including the value\nof your $PATH and any error possibly output before this message.  This\ncan help us improve future automake versions.\n\nEND\n  if test x\"$ACCEPT_INFERIOR_RM_PROGRAM\" = x\"yes\"; then\n    echo 'Configuration will proceed anyway, since you have set the' >&2\n    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to \"yes\"' >&2\n    echo >&2\n  else\n    cat >&2 <<'END'\nAborting the configuration process, to ensure you take notice of the issue.\n\nYou can download and install GNU coreutils to get an 'rm' implementation\nthat behaves properly: <https://www.gnu.org/software/coreutils/>.\n\nIf you want to complete the configuration process using your problematic\n'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM\nto \"yes\", and re-run configure.\n\nEND\n    as_fn_error $? \"Your 'rm' program is bad, sorry.\" \"$LINENO\" 5\n  fi\nfi\n\n\nac_config_headers=\"$ac_config_headers config.h\"\n\n\n\n\n\n\n\n\n\n\n\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\nif test -n \"$ac_tool_prefix\"; then\n  # Extract the first word of \"${ac_tool_prefix}gcc\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}gcc; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$CC\"; then\n  ac_cv_prog_CC=\"$CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_CC=\"${ac_tool_prefix}gcc\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nCC=$ac_cv_prog_CC\nif test -n \"$CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CC\" >&5\nprintf \"%s\\n\" \"$CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$ac_cv_prog_CC\"; then\n  ac_ct_CC=$CC\n  # Extract the first word of \"gcc\", so it can be a program name with args.\nset dummy gcc; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_CC\"; then\n  ac_cv_prog_ac_ct_CC=\"$ac_ct_CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_CC=\"gcc\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_CC=$ac_cv_prog_ac_ct_CC\nif test -n \"$ac_ct_CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC\" >&5\nprintf \"%s\\n\" \"$ac_ct_CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n  if test \"x$ac_ct_CC\" = x; then\n    CC=\"\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    CC=$ac_ct_CC\n  fi\nelse\n  CC=\"$ac_cv_prog_CC\"\nfi\n\nif test -z \"$CC\"; then\n          if test -n \"$ac_tool_prefix\"; then\n    # Extract the first word of \"${ac_tool_prefix}cc\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}cc; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$CC\"; then\n  ac_cv_prog_CC=\"$CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_CC=\"${ac_tool_prefix}cc\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nCC=$ac_cv_prog_CC\nif test -n \"$CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CC\" >&5\nprintf \"%s\\n\" \"$CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\n  fi\nfi\nif test -z \"$CC\"; then\n  # Extract the first word of \"cc\", so it can be a program name with args.\nset dummy cc; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$CC\"; then\n  ac_cv_prog_CC=\"$CC\" # Let the user override the test.\nelse\n  ac_prog_rejected=no\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    if test \"$as_dir$ac_word$ac_exec_ext\" = \"/usr/ucb/cc\"; then\n       ac_prog_rejected=yes\n       continue\n     fi\n    ac_cv_prog_CC=\"cc\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nif test $ac_prog_rejected = yes; then\n  # We found a bogon in the path, so make sure we never use it.\n  set dummy $ac_cv_prog_CC\n  shift\n  if test $# != 0; then\n    # We chose a different compiler from the bogus one.\n    # However, it has the same basename, so the bogon will be chosen\n    # first if we set CC to just the basename; use the full file name.\n    shift\n    ac_cv_prog_CC=\"$as_dir$ac_word${1+' '}$@\"\n  fi\nfi\nfi\nfi\nCC=$ac_cv_prog_CC\nif test -n \"$CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CC\" >&5\nprintf \"%s\\n\" \"$CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$CC\"; then\n  if test -n \"$ac_tool_prefix\"; then\n  for ac_prog in cl.exe\n  do\n    # Extract the first word of \"$ac_tool_prefix$ac_prog\", so it can be a program name with args.\nset dummy $ac_tool_prefix$ac_prog; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$CC\"; then\n  ac_cv_prog_CC=\"$CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_CC=\"$ac_tool_prefix$ac_prog\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nCC=$ac_cv_prog_CC\nif test -n \"$CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CC\" >&5\nprintf \"%s\\n\" \"$CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\n    test -n \"$CC\" && break\n  done\nfi\nif test -z \"$CC\"; then\n  ac_ct_CC=$CC\n  for ac_prog in cl.exe\ndo\n  # Extract the first word of \"$ac_prog\", so it can be a program name with args.\nset dummy $ac_prog; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_CC\"; then\n  ac_cv_prog_ac_ct_CC=\"$ac_ct_CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_CC=\"$ac_prog\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_CC=$ac_cv_prog_ac_ct_CC\nif test -n \"$ac_ct_CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC\" >&5\nprintf \"%s\\n\" \"$ac_ct_CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\n  test -n \"$ac_ct_CC\" && break\ndone\n\n  if test \"x$ac_ct_CC\" = x; then\n    CC=\"\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    CC=$ac_ct_CC\n  fi\nfi\n\nfi\nif test -z \"$CC\"; then\n  if test -n \"$ac_tool_prefix\"; then\n  # Extract the first word of \"${ac_tool_prefix}clang\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}clang; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$CC\"; then\n  ac_cv_prog_CC=\"$CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_CC=\"${ac_tool_prefix}clang\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nCC=$ac_cv_prog_CC\nif test -n \"$CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CC\" >&5\nprintf \"%s\\n\" \"$CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$ac_cv_prog_CC\"; then\n  ac_ct_CC=$CC\n  # Extract the first word of \"clang\", so it can be a program name with args.\nset dummy clang; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_CC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_CC\"; then\n  ac_cv_prog_ac_ct_CC=\"$ac_ct_CC\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_CC=\"clang\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_CC=$ac_cv_prog_ac_ct_CC\nif test -n \"$ac_ct_CC\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC\" >&5\nprintf \"%s\\n\" \"$ac_ct_CC\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n  if test \"x$ac_ct_CC\" = x; then\n    CC=\"\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    CC=$ac_ct_CC\n  fi\nelse\n  CC=\"$ac_cv_prog_CC\"\nfi\n\nfi\n\n\ntest -z \"$CC\" && { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"no acceptable C compiler found in \\$PATH\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\n\n# Provide some information about the compiler.\nprintf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for C compiler version\" >&5\nset X $ac_compile\nac_compiler=$2\nfor ac_option in --version -v -V -qversion -version; do\n  { { ac_try=\"$ac_compiler $ac_option >&5\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_compiler $ac_option >&5\") 2>conftest.err\n  ac_status=$?\n  if test -s conftest.err; then\n    sed '10a\\\n... rest of stderr output deleted ...\n         10q' conftest.err >conftest.er1\n    cat conftest.er1 >&5\n  fi\n  rm -f conftest.er1 conftest.err\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }\ndone\n\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nac_clean_files_save=$ac_clean_files\nac_clean_files=\"$ac_clean_files a.out a.out.dSYM a.exe b.out\"\n# Try to create an executable without -o first, disregard a.out.\n# It will help us diagnose broken compilers, and finding out an intuition\n# of exeext.\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the C compiler works\" >&5\nprintf %s \"checking whether the C compiler works... \" >&6; }\nac_link_default=`printf \"%s\\n\" \"$ac_link\" | sed 's/ -o *conftest[^ ]*//'`\n\n# The possible output files:\nac_files=\"a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*\"\n\nac_rmfiles=\nfor ac_file in $ac_files\ndo\n  case $ac_file in\n    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;\n    * ) ac_rmfiles=\"$ac_rmfiles $ac_file\";;\n  esac\ndone\nrm -f $ac_rmfiles\n\nif { { ac_try=\"$ac_link_default\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_link_default\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }\nthen :\n  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.\n# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'\n# in a Makefile.  We should not override ac_cv_exeext if it was cached,\n# so that the user can short-circuit this test for compilers unknown to\n# Autoconf.\nfor ac_file in $ac_files ''\ndo\n  test -f \"$ac_file\" || continue\n  case $ac_file in\n    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )\n\t;;\n    [ab].out )\n\t# We found the default executable, but exeext='' is most\n\t# certainly right.\n\tbreak;;\n    *.* )\n\tif test ${ac_cv_exeext+y} && test \"$ac_cv_exeext\" != no;\n\tthen :; else\n\t   ac_cv_exeext=`expr \"$ac_file\" : '[^.]*\\(\\..*\\)'`\n\tfi\n\t# We set ac_cv_exeext here because the later test for it is not\n\t# safe: cross compilers may not add the suffix if given an `-o'\n\t# argument, so we may need to know it at that point already.\n\t# Even if this section looks crufty: it has the advantage of\n\t# actually working.\n\tbreak;;\n    * )\n\tbreak;;\n  esac\ndone\ntest \"$ac_cv_exeext\" = no && ac_cv_exeext=\n\nelse $as_nop\n  ac_file=''\nfi\nif test -z \"$ac_file\"\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nprintf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n{ { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error 77 \"C compiler cannot create executables\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\nelse $as_nop\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: yes\" >&5\nprintf \"%s\\n\" \"yes\" >&6; }\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name\" >&5\nprintf %s \"checking for C compiler default output file name... \" >&6; }\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_file\" >&5\nprintf \"%s\\n\" \"$ac_file\" >&6; }\nac_exeext=$ac_cv_exeext\n\nrm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out\nac_clean_files=$ac_clean_files_save\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for suffix of executables\" >&5\nprintf %s \"checking for suffix of executables... \" >&6; }\nif { { ac_try=\"$ac_link\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_link\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }\nthen :\n  # If both `conftest.exe' and `conftest' are `present' (well, observable)\n# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will\n# work properly (i.e., refer to `conftest.exe'), while it won't with\n# `rm'.\nfor ac_file in conftest.exe conftest conftest.*; do\n  test -f \"$ac_file\" || continue\n  case $ac_file in\n    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;\n    *.* ) ac_cv_exeext=`expr \"$ac_file\" : '[^.]*\\(\\..*\\)'`\n\t  break;;\n    * ) break;;\n  esac\ndone\nelse $as_nop\n  { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"cannot compute suffix of executables: cannot compile and link\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\nfi\nrm -f conftest conftest$ac_cv_exeext\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext\" >&5\nprintf \"%s\\n\" \"$ac_cv_exeext\" >&6; }\n\nrm -f conftest.$ac_ext\nEXEEXT=$ac_cv_exeext\nac_exeext=$EXEEXT\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdio.h>\nint\nmain (void)\n{\nFILE *f = fopen (\"conftest.out\", \"w\");\n return ferror (f) || fclose (f) != 0;\n\n  ;\n  return 0;\n}\n_ACEOF\nac_clean_files=\"$ac_clean_files conftest.out\"\n# Check that the compiler produces executables we can run.  If not, either\n# the compiler is broken, or we cross compile.\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling\" >&5\nprintf %s \"checking whether we are cross compiling... \" >&6; }\nif test \"$cross_compiling\" != yes; then\n  { { ac_try=\"$ac_link\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_link\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }\n  if { ac_try='./conftest$ac_cv_exeext'\n  { { case \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_try\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }; }; then\n    cross_compiling=no\n  else\n    if test \"$cross_compiling\" = maybe; then\n\tcross_compiling=yes\n    else\n\t{ { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error 77 \"cannot run C compiled programs.\nIf you meant to cross compile, use \\`--host'.\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\n    fi\n  fi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $cross_compiling\" >&5\nprintf \"%s\\n\" \"$cross_compiling\" >&6; }\n\nrm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out\nac_clean_files=$ac_clean_files_save\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for suffix of object files\" >&5\nprintf %s \"checking for suffix of object files... \" >&6; }\nif test ${ac_cv_objext+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nrm -f conftest.o conftest.obj\nif { { ac_try=\"$ac_compile\"\ncase \"(($ac_try\" in\n  *\\\"* | *\\`* | *\\\\*) ac_try_echo=\\$ac_try;;\n  *) ac_try_echo=$ac_try;;\nesac\neval ac_try_echo=\"\\\"\\$as_me:${as_lineno-$LINENO}: $ac_try_echo\\\"\"\nprintf \"%s\\n\" \"$ac_try_echo\"; } >&5\n  (eval \"$ac_compile\") 2>&5\n  ac_status=$?\n  printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: \\$? = $ac_status\" >&5\n  test $ac_status = 0; }\nthen :\n  for ac_file in conftest.o conftest.obj conftest.*; do\n  test -f \"$ac_file\" || continue;\n  case $ac_file in\n    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;\n    *) ac_cv_objext=`expr \"$ac_file\" : '.*\\.\\(.*\\)'`\n       break;;\n  esac\ndone\nelse $as_nop\n  printf \"%s\\n\" \"$as_me: failed program was:\" >&5\nsed 's/^/| /' conftest.$ac_ext >&5\n\n{ { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"cannot compute suffix of object files: cannot compile\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\nfi\nrm -f conftest.$ac_cv_objext conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext\" >&5\nprintf \"%s\\n\" \"$ac_cv_objext\" >&6; }\nOBJEXT=$ac_cv_objext\nac_objext=$OBJEXT\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C\" >&5\nprintf %s \"checking whether the compiler supports GNU C... \" >&6; }\nif test ${ac_cv_c_compiler_gnu+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n#ifndef __GNUC__\n       choke me\n#endif\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_compiler_gnu=yes\nelse $as_nop\n  ac_compiler_gnu=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nac_cv_c_compiler_gnu=$ac_compiler_gnu\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu\" >&5\nprintf \"%s\\n\" \"$ac_cv_c_compiler_gnu\" >&6; }\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n\nif test $ac_compiler_gnu = yes; then\n  GCC=yes\nelse\n  GCC=\nfi\nac_test_CFLAGS=${CFLAGS+y}\nac_save_CFLAGS=$CFLAGS\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g\" >&5\nprintf %s \"checking whether $CC accepts -g... \" >&6; }\nif test ${ac_cv_prog_cc_g+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_save_c_werror_flag=$ac_c_werror_flag\n   ac_c_werror_flag=yes\n   ac_cv_prog_cc_g=no\n   CFLAGS=\"-g\"\n   cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_prog_cc_g=yes\nelse $as_nop\n  CFLAGS=\"\"\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n\nelse $as_nop\n  ac_c_werror_flag=$ac_save_c_werror_flag\n\t CFLAGS=\"-g\"\n\t cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_prog_cc_g=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n   ac_c_werror_flag=$ac_save_c_werror_flag\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g\" >&5\nprintf \"%s\\n\" \"$ac_cv_prog_cc_g\" >&6; }\nif test $ac_test_CFLAGS; then\n  CFLAGS=$ac_save_CFLAGS\nelif test $ac_cv_prog_cc_g = yes; then\n  if test \"$GCC\" = yes; then\n    CFLAGS=\"-g -O2\"\n  else\n    CFLAGS=\"-g\"\n  fi\nelse\n  if test \"$GCC\" = yes; then\n    CFLAGS=\"-O2\"\n  else\n    CFLAGS=\n  fi\nfi\nac_prog_cc_stdc=no\nif test x$ac_prog_cc_stdc = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features\" >&5\nprintf %s \"checking for $CC option to enable C11 features... \" >&6; }\nif test ${ac_cv_prog_cc_c11+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_prog_cc_c11=no\nac_save_CC=$CC\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$ac_c_conftest_c11_program\n_ACEOF\nfor ac_arg in '' -std=gnu11\ndo\n  CC=\"$ac_save_CC $ac_arg\"\n  if ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_prog_cc_c11=$ac_arg\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam\n  test \"x$ac_cv_prog_cc_c11\" != \"xno\" && break\ndone\nrm -f conftest.$ac_ext\nCC=$ac_save_CC\nfi\n\nif test \"x$ac_cv_prog_cc_c11\" = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: unsupported\" >&5\nprintf \"%s\\n\" \"unsupported\" >&6; }\nelse $as_nop\n  if test \"x$ac_cv_prog_cc_c11\" = x\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: none needed\" >&5\nprintf \"%s\\n\" \"none needed\" >&6; }\nelse $as_nop\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11\" >&5\nprintf \"%s\\n\" \"$ac_cv_prog_cc_c11\" >&6; }\n     CC=\"$CC $ac_cv_prog_cc_c11\"\nfi\n  ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11\n  ac_prog_cc_stdc=c11\nfi\nfi\nif test x$ac_prog_cc_stdc = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features\" >&5\nprintf %s \"checking for $CC option to enable C99 features... \" >&6; }\nif test ${ac_cv_prog_cc_c99+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_prog_cc_c99=no\nac_save_CC=$CC\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$ac_c_conftest_c99_program\n_ACEOF\nfor ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=\ndo\n  CC=\"$ac_save_CC $ac_arg\"\n  if ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_prog_cc_c99=$ac_arg\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam\n  test \"x$ac_cv_prog_cc_c99\" != \"xno\" && break\ndone\nrm -f conftest.$ac_ext\nCC=$ac_save_CC\nfi\n\nif test \"x$ac_cv_prog_cc_c99\" = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: unsupported\" >&5\nprintf \"%s\\n\" \"unsupported\" >&6; }\nelse $as_nop\n  if test \"x$ac_cv_prog_cc_c99\" = x\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: none needed\" >&5\nprintf \"%s\\n\" \"none needed\" >&6; }\nelse $as_nop\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99\" >&5\nprintf \"%s\\n\" \"$ac_cv_prog_cc_c99\" >&6; }\n     CC=\"$CC $ac_cv_prog_cc_c99\"\nfi\n  ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99\n  ac_prog_cc_stdc=c99\nfi\nfi\nif test x$ac_prog_cc_stdc = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features\" >&5\nprintf %s \"checking for $CC option to enable C89 features... \" >&6; }\nif test ${ac_cv_prog_cc_c89+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_prog_cc_c89=no\nac_save_CC=$CC\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n$ac_c_conftest_c89_program\n_ACEOF\nfor ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae \"-Aa -D_HPUX_SOURCE\" \"-Xc -D__EXTENSIONS__\"\ndo\n  CC=\"$ac_save_CC $ac_arg\"\n  if ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_prog_cc_c89=$ac_arg\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam\n  test \"x$ac_cv_prog_cc_c89\" != \"xno\" && break\ndone\nrm -f conftest.$ac_ext\nCC=$ac_save_CC\nfi\n\nif test \"x$ac_cv_prog_cc_c89\" = xno\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: unsupported\" >&5\nprintf \"%s\\n\" \"unsupported\" >&6; }\nelse $as_nop\n  if test \"x$ac_cv_prog_cc_c89\" = x\nthen :\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: none needed\" >&5\nprintf \"%s\\n\" \"none needed\" >&6; }\nelse $as_nop\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89\" >&5\nprintf \"%s\\n\" \"$ac_cv_prog_cc_c89\" >&6; }\n     CC=\"$CC $ac_cv_prog_cc_c89\"\nfi\n  ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89\n  ac_prog_cc_stdc=c89\nfi\nfi\n\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n\n\n  ac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together\" >&5\nprintf %s \"checking whether $CC understands -c and -o together... \" >&6; }\nif test ${am_cv_prog_cc_c_o+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\n  # Make sure it works both with $CC and with simple cc.\n  # Following AC_PROG_CC_C_O, we do the test twice because some\n  # compilers refuse to overwrite an existing .o file with -o,\n  # though they will create one.\n  am_cv_prog_cc_c_o=yes\n  for am_i in 1 2; do\n    if { echo \"$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext\" >&5\n   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5\n   ac_status=$?\n   echo \"$as_me:$LINENO: \\$? = $ac_status\" >&5\n   (exit $ac_status); } \\\n         && test -f conftest2.$ac_objext; then\n      : OK\n    else\n      am_cv_prog_cc_c_o=no\n      break\n    fi\n  done\n  rm -f core conftest*\n  unset am_i\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o\" >&5\nprintf \"%s\\n\" \"$am_cv_prog_cc_c_o\" >&6; }\nif test \"$am_cv_prog_cc_c_o\" != yes; then\n   # Losing compiler, so override with the script.\n   # FIXME: It is wrong to rewrite CC.\n   # But if we don't then we get into trouble of one sort or another.\n   # A longer-term fix would be to have automake use am__CC in this case,\n   # and then we could set am__CC=\"\\$(top_srcdir)/compile \\$(CC)\"\n   CC=\"$am_aux_dir/compile $CC\"\nfi\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the compiler is clang\" >&5\nprintf %s \"checking whether the compiler is clang... \" >&6; }\nif test ${gl_cv_compiler_clang+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n                 cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n           #ifdef __clang__\n           barfbarf\n           #endif\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_compiler_clang=no\nelse $as_nop\n  gl_cv_compiler_clang=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_clang\" >&5\nprintf \"%s\\n\" \"$gl_cv_compiler_clang\" >&6; }\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for compiler option needed when checking for declarations\" >&5\nprintf %s \"checking for compiler option needed when checking for declarations... \" >&6; }\nif test ${gl_cv_compiler_check_decl_option+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test $gl_cv_compiler_clang = yes; then\n                     save_ac_compile=\"$ac_compile\"\n       ac_compile=\"$ac_compile -Werror=implicit-function-declaration\"\n                     cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_compiler_check_decl_option='-Werror=implicit-function-declaration'\nelse $as_nop\n  gl_cv_compiler_check_decl_option=none\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n       ac_compile=\"$save_ac_compile\"\n     else\n       gl_cv_compiler_check_decl_option=none\n     fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_check_decl_option\" >&5\nprintf \"%s\\n\" \"$gl_cv_compiler_check_decl_option\" >&6; }\n  if test \"x$gl_cv_compiler_check_decl_option\" != xnone; then\n    ac_compile_for_check_decl=\"$ac_compile $gl_cv_compiler_check_decl_option\"\n  else\n    ac_compile_for_check_decl=\"$ac_compile\"\n  fi\n\nDEPDIR=\"${am__leading_dot}deps\"\n\nac_config_commands=\"$ac_config_commands depfiles\"\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive\" >&5\nprintf %s \"checking whether ${MAKE-make} supports the include directive... \" >&6; }\ncat > confinc.mk << 'END'\nam__doit:\n\t@echo this is the am__doit target >confinc.out\n.PHONY: am__doit\nEND\nam__include=\"#\"\nam__quote=\n# BSD make does it like this.\necho '.include \"confinc.mk\" # ignored' > confmf.BSD\n# Other make implementations (GNU, Solaris 10, AIX) do it like this.\necho 'include confinc.mk # ignored' > confmf.GNU\n_am_result=no\nfor s in GNU BSD; do\n  { echo \"$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out\" >&5\n   (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5\n   ac_status=$?\n   echo \"$as_me:$LINENO: \\$? = $ac_status\" >&5\n   (exit $ac_status); }\n  case $?:`cat confinc.out 2>/dev/null` in #(\n  '0:this is the am__doit target') :\n    case $s in #(\n  BSD) :\n    am__include='.include' am__quote='\"' ;; #(\n  *) :\n    am__include='include' am__quote='' ;;\nesac ;; #(\n  *) :\n     ;;\nesac\n  if test \"$am__include\" != \"#\"; then\n    _am_result=\"yes ($s style)\"\n    break\n  fi\ndone\nrm -f confinc.* confmf.*\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: ${_am_result}\" >&5\nprintf \"%s\\n\" \"${_am_result}\" >&6; }\n\n# Check whether --enable-dependency-tracking was given.\nif test ${enable_dependency_tracking+y}\nthen :\n  enableval=$enable_dependency_tracking;\nfi\n\nif test \"x$enable_dependency_tracking\" != xno; then\n  am_depcomp=\"$ac_aux_dir/depcomp\"\n  AMDEPBACKSLASH='\\'\n  am__nodep='_no'\nfi\n if test \"x$enable_dependency_tracking\" != xno; then\n  AMDEP_TRUE=\n  AMDEP_FALSE='#'\nelse\n  AMDEP_TRUE='#'\n  AMDEP_FALSE=\nfi\n\n\n\ndepcc=\"$CC\"   am_compiler_list=\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc\" >&5\nprintf %s \"checking dependency style of $depcc... \" >&6; }\nif test ${am_cv_CC_dependencies_compiler_type+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -z \"$AMDEP_TRUE\" && test -f \"$am_depcomp\"; then\n  # We make a subdir and do the tests there.  Otherwise we can end up\n  # making bogus files that we don't know about and never remove.  For\n  # instance it was reported that on HP-UX the gcc test will end up\n  # making a dummy file named 'D' -- because '-MD' means \"put the output\n  # in D\".\n  rm -rf conftest.dir\n  mkdir conftest.dir\n  # Copy depcomp to subdir because otherwise we won't find it if we're\n  # using a relative directory.\n  cp \"$am_depcomp\" conftest.dir\n  cd conftest.dir\n  # We will build objects and dependencies in a subdirectory because\n  # it helps to detect inapplicable dependency modes.  For instance\n  # both Tru64's cc and ICC support -MD to output dependencies as a\n  # side effect of compilation, but ICC will put the dependencies in\n  # the current directory while Tru64 will put them in the object\n  # directory.\n  mkdir sub\n\n  am_cv_CC_dependencies_compiler_type=none\n  if test \"$am_compiler_list\" = \"\"; then\n     am_compiler_list=`sed -n 's/^#*\\([a-zA-Z0-9]*\\))$/\\1/p' < ./depcomp`\n  fi\n  am__universal=false\n  case \" $depcc \" in #(\n     *\\ -arch\\ *\\ -arch\\ *) am__universal=true ;;\n     esac\n\n  for depmode in $am_compiler_list; do\n    # Setup a source with many dependencies, because some compilers\n    # like to wrap large dependency lists on column 80 (with \\), and\n    # we should not choose a depcomp mode which is confused by this.\n    #\n    # We need to recreate these files for each test, as the compiler may\n    # overwrite some of them when testing with obscure command lines.\n    # This happens at least with the AIX C compiler.\n    : > sub/conftest.c\n    for i in 1 2 3 4 5 6; do\n      echo '#include \"conftst'$i'.h\"' >> sub/conftest.c\n      # Using \": > sub/conftst$i.h\" creates only sub/conftst1.h with\n      # Solaris 10 /bin/sh.\n      echo '/* dummy */' > sub/conftst$i.h\n    done\n    echo \"${am__include} ${am__quote}sub/conftest.Po${am__quote}\" > confmf\n\n    # We check with '-c' and '-o' for the sake of the \"dashmstdout\"\n    # mode.  It turns out that the SunPro C++ compiler does not properly\n    # handle '-M -o', and we need to detect this.  Also, some Intel\n    # versions had trouble with output in subdirs.\n    am__obj=sub/conftest.${OBJEXT-o}\n    am__minus_obj=\"-o $am__obj\"\n    case $depmode in\n    gcc)\n      # This depmode causes a compiler race in universal mode.\n      test \"$am__universal\" = false || continue\n      ;;\n    nosideeffect)\n      # After this tag, mechanisms are not by side-effect, so they'll\n      # only be used when explicitly requested.\n      if test \"x$enable_dependency_tracking\" = xyes; then\n\tcontinue\n      else\n\tbreak\n      fi\n      ;;\n    msvc7 | msvc7msys | msvisualcpp | msvcmsys)\n      # This compiler won't grok '-c -o', but also, the minuso test has\n      # not run yet.  These depmodes are late enough in the game, and\n      # so weak that their functioning should not be impacted.\n      am__obj=conftest.${OBJEXT-o}\n      am__minus_obj=\n      ;;\n    none) break ;;\n    esac\n    if depmode=$depmode \\\n       source=sub/conftest.c object=$am__obj \\\n       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \\\n       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \\\n         >/dev/null 2>conftest.err &&\n       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&\n       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&\n       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&\n       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then\n      # icc doesn't choke on unknown options, it will just issue warnings\n      # or remarks (even with -Werror).  So we grep stderr for any message\n      # that says an option was ignored or not supported.\n      # When given -MP, icc 7.0 and 7.1 complain thusly:\n      #   icc: Command line warning: ignoring option '-M'; no argument required\n      # The diagnosis changed in icc 8.0:\n      #   icc: Command line remark: option '-MP' not supported\n      if (grep 'ignoring option' conftest.err ||\n          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else\n        am_cv_CC_dependencies_compiler_type=$depmode\n        break\n      fi\n    fi\n  done\n\n  cd ..\n  rm -rf conftest.dir\nelse\n  am_cv_CC_dependencies_compiler_type=none\nfi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type\" >&5\nprintf \"%s\\n\" \"$am_cv_CC_dependencies_compiler_type\" >&6; }\nCCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type\n\n if\n  test \"x$enable_dependency_tracking\" != xno \\\n  && test \"$am_cv_CC_dependencies_compiler_type\" = gcc3; then\n  am__fastdepCC_TRUE=\n  am__fastdepCC_FALSE='#'\nelse\n  am__fastdepCC_TRUE='#'\n  am__fastdepCC_FALSE=\nfi\n\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \\$(MAKE)\" >&5\nprintf %s \"checking whether ${MAKE-make} sets \\$(MAKE)... \" >&6; }\nset x ${MAKE-make}\nac_make=`printf \"%s\\n\" \"$2\" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`\nif eval test \\${ac_cv_prog_make_${ac_make}_set+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat >conftest.make <<\\_ACEOF\nSHELL = /bin/sh\nall:\n\t@echo '@@@%%%=$(MAKE)=@@@%%%'\n_ACEOF\n# GNU make sometimes prints \"make[1]: Entering ...\", which would confuse us.\ncase `${MAKE-make} -f conftest.make 2>/dev/null` in\n  *@@@%%%=?*=@@@%%%*)\n    eval ac_cv_prog_make_${ac_make}_set=yes;;\n  *)\n    eval ac_cv_prog_make_${ac_make}_set=no;;\nesac\nrm -f conftest.make\nfi\nif eval test \\$ac_cv_prog_make_${ac_make}_set = yes; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: yes\" >&5\nprintf \"%s\\n\" \"yes\" >&6; }\n  SET_MAKE=\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\n  SET_MAKE=\"MAKE=${MAKE-make}\"\nfi\n\n\n# For autobuild.\n\n\n  # Make sure we can run config.sub.\n$SHELL \"${ac_aux_dir}config.sub\" sun4 >/dev/null 2>&1 ||\n  as_fn_error $? \"cannot run $SHELL ${ac_aux_dir}config.sub\" \"$LINENO\" 5\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking build system type\" >&5\nprintf %s \"checking build system type... \" >&6; }\nif test ${ac_cv_build+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_build_alias=$build_alias\ntest \"x$ac_build_alias\" = x &&\n  ac_build_alias=`$SHELL \"${ac_aux_dir}config.guess\"`\ntest \"x$ac_build_alias\" = x &&\n  as_fn_error $? \"cannot guess build type; you must specify one\" \"$LINENO\" 5\nac_cv_build=`$SHELL \"${ac_aux_dir}config.sub\" $ac_build_alias` ||\n  as_fn_error $? \"$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed\" \"$LINENO\" 5\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_build\" >&5\nprintf \"%s\\n\" \"$ac_cv_build\" >&6; }\ncase $ac_cv_build in\n*-*-*) ;;\n*) as_fn_error $? \"invalid value of canonical build\" \"$LINENO\" 5;;\nesac\nbuild=$ac_cv_build\nac_save_IFS=$IFS; IFS='-'\nset x $ac_cv_build\nshift\nbuild_cpu=$1\nbuild_vendor=$2\nshift; shift\n# Remember, the first character of IFS is used to create $*,\n# except with old shells:\nbuild_os=$*\nIFS=$ac_save_IFS\ncase $build_os in *\\ *) build_os=`echo \"$build_os\" | sed 's/ /-/g'`;; esac\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking host system type\" >&5\nprintf %s \"checking host system type... \" >&6; }\nif test ${ac_cv_host+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test \"x$host_alias\" = x; then\n  ac_cv_host=$ac_cv_build\nelse\n  ac_cv_host=`$SHELL \"${ac_aux_dir}config.sub\" $host_alias` ||\n    as_fn_error $? \"$SHELL ${ac_aux_dir}config.sub $host_alias failed\" \"$LINENO\" 5\nfi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_host\" >&5\nprintf \"%s\\n\" \"$ac_cv_host\" >&6; }\ncase $ac_cv_host in\n*-*-*) ;;\n*) as_fn_error $? \"invalid value of canonical host\" \"$LINENO\" 5;;\nesac\nhost=$ac_cv_host\nac_save_IFS=$IFS; IFS='-'\nset x $ac_cv_host\nshift\nhost_cpu=$1\nhost_vendor=$2\nshift; shift\n# Remember, the first character of IFS is used to create $*,\n# except with old shells:\nhost_os=$*\nIFS=$ac_save_IFS\ncase $host_os in *\\ *) host_os=`echo \"$host_os\" | sed 's/ /-/g'`;; esac\n\n\n\n\n# Pre-early section.\n\nac_header= ac_cache=\nfor ac_item in $ac_header_c_list\ndo\n  if test $ac_cache; then\n    ac_fn_c_check_header_compile \"$LINENO\" $ac_header ac_cv_header_$ac_cache \"$ac_includes_default\"\n    if eval test \\\"x\\$ac_cv_header_$ac_cache\\\" = xyes; then\n      printf \"%s\\n\" \"#define $ac_item 1\" >> confdefs.h\n    fi\n    ac_header= ac_cache=\n  elif test $ac_header; then\n    ac_cache=$ac_item\n  else\n    ac_header=$ac_item\n  fi\ndone\n\n\n\n\n\n\n\n\nif test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes\nthen :\n\nprintf \"%s\\n\" \"#define STDC_HEADERS 1\" >>confdefs.h\n\nfi\n\n\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__\" >&5\nprintf %s \"checking whether it is safe to define __EXTENSIONS__... \" >&6; }\nif test ${ac_cv_safe_to_define___extensions__+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#         define __EXTENSIONS__ 1\n          $ac_includes_default\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_safe_to_define___extensions__=yes\nelse $as_nop\n  ac_cv_safe_to_define___extensions__=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__\" >&5\nprintf \"%s\\n\" \"$ac_cv_safe_to_define___extensions__\" >&6; }\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined\" >&5\nprintf %s \"checking whether _XOPEN_SOURCE should be defined... \" >&6; }\nif test ${ac_cv_should_define__xopen_source+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_should_define__xopen_source=no\n    if test $ac_cv_header_wchar_h = yes\nthen :\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n          #include <wchar.h>\n          mbstate_t x;\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n            #define _XOPEN_SOURCE 500\n            #include <wchar.h>\n            mbstate_t x;\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_should_define__xopen_source=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source\" >&5\nprintf \"%s\\n\" \"$ac_cv_should_define__xopen_source\" >&6; }\n\n  printf \"%s\\n\" \"#define _ALL_SOURCE 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _DARWIN_C_SOURCE 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _GNU_SOURCE 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _HPUX_ALT_XOPEN_SOCKET_API 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _NETBSD_SOURCE 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _OPENBSD_SOURCE 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _POSIX_PTHREAD_SEMANTICS 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_IEC_60559_BFP_EXT__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_IEC_60559_DFP_EXT__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_LIB_EXT2__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define __STDC_WANT_MATH_SPEC_FUNCS__ 1\" >>confdefs.h\n\n  printf \"%s\\n\" \"#define _TANDEM_SOURCE 1\" >>confdefs.h\n\n  if test $ac_cv_header_minix_config_h = yes\nthen :\n  MINIX=yes\n    printf \"%s\\n\" \"#define _MINIX 1\" >>confdefs.h\n\n    printf \"%s\\n\" \"#define _POSIX_SOURCE 1\" >>confdefs.h\n\n    printf \"%s\\n\" \"#define _POSIX_1_SOURCE 2\" >>confdefs.h\n\nelse $as_nop\n  MINIX=\nfi\n  if test $ac_cv_safe_to_define___extensions__ = yes\nthen :\n  printf \"%s\\n\" \"#define __EXTENSIONS__ 1\" >>confdefs.h\n\nfi\n  if test $ac_cv_should_define__xopen_source = yes\nthen :\n  printf \"%s\\n\" \"#define _XOPEN_SOURCE 500\" >>confdefs.h\n\nfi\n\n\n\n\n\n  case \"$host_os\" in\n    openbsd*)\n\nprintf \"%s\\n\" \"#define _ISOC11_SOURCE 1\" >>confdefs.h\n\n      ;;\n  esac\n\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor\" >&5\nprintf %s \"checking how to run the C preprocessor... \" >&6; }\n# On Suns, sometimes $CPP names a directory.\nif test -n \"$CPP\" && test -d \"$CPP\"; then\n  CPP=\nfi\nif test -z \"$CPP\"; then\n  if test ${ac_cv_prog_CPP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n      # Double quotes because $CC needs to be expanded\n    for CPP in \"$CC -E\" \"$CC -E -traditional-cpp\" cpp /lib/cpp\n    do\n      ac_preproc_ok=false\nfor ac_c_preproc_warn_flag in '' yes\ndo\n  # Use a header file that comes with gcc, so configuring glibc\n  # with a fresh cross-compiler works.\n  # On the NeXT, cc -E runs the code through the compiler's parser,\n  # not just through cpp. \"Syntax error\" is here to catch this case.\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <limits.h>\n\t\t     Syntax error\n_ACEOF\nif ac_fn_c_try_cpp \"$LINENO\"\nthen :\n\nelse $as_nop\n  # Broken: fails on valid input.\ncontinue\nfi\nrm -f conftest.err conftest.i conftest.$ac_ext\n\n  # OK, works on sane cases.  Now check whether nonexistent headers\n  # can be detected and how.\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <ac_nonexistent.h>\n_ACEOF\nif ac_fn_c_try_cpp \"$LINENO\"\nthen :\n  # Broken: success on invalid input.\ncontinue\nelse $as_nop\n  # Passes both tests.\nac_preproc_ok=:\nbreak\nfi\nrm -f conftest.err conftest.i conftest.$ac_ext\n\ndone\n# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.\nrm -f conftest.i conftest.err conftest.$ac_ext\nif $ac_preproc_ok\nthen :\n  break\nfi\n\n    done\n    ac_cv_prog_CPP=$CPP\n\nfi\n  CPP=$ac_cv_prog_CPP\nelse\n  ac_cv_prog_CPP=$CPP\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $CPP\" >&5\nprintf \"%s\\n\" \"$CPP\" >&6; }\nac_preproc_ok=false\nfor ac_c_preproc_warn_flag in '' yes\ndo\n  # Use a header file that comes with gcc, so configuring glibc\n  # with a fresh cross-compiler works.\n  # On the NeXT, cc -E runs the code through the compiler's parser,\n  # not just through cpp. \"Syntax error\" is here to catch this case.\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <limits.h>\n\t\t     Syntax error\n_ACEOF\nif ac_fn_c_try_cpp \"$LINENO\"\nthen :\n\nelse $as_nop\n  # Broken: fails on valid input.\ncontinue\nfi\nrm -f conftest.err conftest.i conftest.$ac_ext\n\n  # OK, works on sane cases.  Now check whether nonexistent headers\n  # can be detected and how.\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <ac_nonexistent.h>\n_ACEOF\nif ac_fn_c_try_cpp \"$LINENO\"\nthen :\n  # Broken: success on invalid input.\ncontinue\nelse $as_nop\n  # Passes both tests.\nac_preproc_ok=:\nbreak\nfi\nrm -f conftest.err conftest.i conftest.$ac_ext\n\ndone\n# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.\nrm -f conftest.i conftest.err conftest.$ac_ext\nif $ac_preproc_ok\nthen :\n\nelse $as_nop\n  { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"C preprocessor \\\"$CPP\\\" fails sanity check\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\nfi\n\nac_ext=c\nac_cpp='$CPP $CPPFLAGS'\nac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'\nac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'\nac_compiler_gnu=$ac_cv_c_compiler_gnu\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e\" >&5\nprintf %s \"checking for grep that handles long lines and -e... \" >&6; }\nif test ${ac_cv_path_GREP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -z \"$GREP\"; then\n  ac_path_GREP_found=false\n  # Loop through the user's path and test for each of PROGNAME-LIST\n  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_prog in grep ggrep\n   do\n    for ac_exec_ext in '' $ac_executable_extensions; do\n      ac_path_GREP=\"$as_dir$ac_prog$ac_exec_ext\"\n      as_fn_executable_p \"$ac_path_GREP\" || continue\n# Check for GNU ac_path_GREP and select it if it is found.\n  # Check for GNU $ac_path_GREP\ncase `\"$ac_path_GREP\" --version 2>&1` in\n*GNU*)\n  ac_cv_path_GREP=\"$ac_path_GREP\" ac_path_GREP_found=:;;\n*)\n  ac_count=0\n  printf %s 0123456789 >\"conftest.in\"\n  while :\n  do\n    cat \"conftest.in\" \"conftest.in\" >\"conftest.tmp\"\n    mv \"conftest.tmp\" \"conftest.in\"\n    cp \"conftest.in\" \"conftest.nl\"\n    printf \"%s\\n\" 'GREP' >> \"conftest.nl\"\n    \"$ac_path_GREP\" -e 'GREP$' -e '-(cannot match)-' < \"conftest.nl\" >\"conftest.out\" 2>/dev/null || break\n    diff \"conftest.out\" \"conftest.nl\" >/dev/null 2>&1 || break\n    as_fn_arith $ac_count + 1 && ac_count=$as_val\n    if test $ac_count -gt ${ac_path_GREP_max-0}; then\n      # Best one so far, save it but keep looking for a better one\n      ac_cv_path_GREP=\"$ac_path_GREP\"\n      ac_path_GREP_max=$ac_count\n    fi\n    # 10*(2^10) chars as input seems more than enough\n    test $ac_count -gt 10 && break\n  done\n  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;\nesac\n\n      $ac_path_GREP_found && break 3\n    done\n  done\n  done\nIFS=$as_save_IFS\n  if test -z \"$ac_cv_path_GREP\"; then\n    as_fn_error $? \"no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin\" \"$LINENO\" 5\n  fi\nelse\n  ac_cv_path_GREP=$GREP\nfi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP\" >&5\nprintf \"%s\\n\" \"$ac_cv_path_GREP\" >&6; }\n GREP=\"$ac_cv_path_GREP\"\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for egrep\" >&5\nprintf %s \"checking for egrep... \" >&6; }\nif test ${ac_cv_path_EGREP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1\n   then ac_cv_path_EGREP=\"$GREP -E\"\n   else\n     if test -z \"$EGREP\"; then\n  ac_path_EGREP_found=false\n  # Loop through the user's path and test for each of PROGNAME-LIST\n  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_prog in egrep\n   do\n    for ac_exec_ext in '' $ac_executable_extensions; do\n      ac_path_EGREP=\"$as_dir$ac_prog$ac_exec_ext\"\n      as_fn_executable_p \"$ac_path_EGREP\" || continue\n# Check for GNU ac_path_EGREP and select it if it is found.\n  # Check for GNU $ac_path_EGREP\ncase `\"$ac_path_EGREP\" --version 2>&1` in\n*GNU*)\n  ac_cv_path_EGREP=\"$ac_path_EGREP\" ac_path_EGREP_found=:;;\n*)\n  ac_count=0\n  printf %s 0123456789 >\"conftest.in\"\n  while :\n  do\n    cat \"conftest.in\" \"conftest.in\" >\"conftest.tmp\"\n    mv \"conftest.tmp\" \"conftest.in\"\n    cp \"conftest.in\" \"conftest.nl\"\n    printf \"%s\\n\" 'EGREP' >> \"conftest.nl\"\n    \"$ac_path_EGREP\" 'EGREP$' < \"conftest.nl\" >\"conftest.out\" 2>/dev/null || break\n    diff \"conftest.out\" \"conftest.nl\" >/dev/null 2>&1 || break\n    as_fn_arith $ac_count + 1 && ac_count=$as_val\n    if test $ac_count -gt ${ac_path_EGREP_max-0}; then\n      # Best one so far, save it but keep looking for a better one\n      ac_cv_path_EGREP=\"$ac_path_EGREP\"\n      ac_path_EGREP_max=$ac_count\n    fi\n    # 10*(2^10) chars as input seems more than enough\n    test $ac_count -gt 10 && break\n  done\n  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;\nesac\n\n      $ac_path_EGREP_found && break 3\n    done\n  done\n  done\nIFS=$as_save_IFS\n  if test -z \"$ac_cv_path_EGREP\"; then\n    as_fn_error $? \"no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin\" \"$LINENO\" 5\n  fi\nelse\n  ac_cv_path_EGREP=$EGREP\nfi\n\n   fi\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP\" >&5\nprintf \"%s\\n\" \"$ac_cv_path_EGREP\" >&6; }\n EGREP=\"$ac_cv_path_EGREP\"\n\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for Minix Amsterdam compiler\" >&5\nprintf %s \"checking for Minix Amsterdam compiler... \" >&6; }\nif test ${gl_cv_c_amsterdam_compiler+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#ifdef __ACK__\nAmsterdam\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"Amsterdam\" >/dev/null 2>&1\nthen :\n  gl_cv_c_amsterdam_compiler=yes\nelse $as_nop\n  gl_cv_c_amsterdam_compiler=no\nfi\nrm -rf conftest*\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_amsterdam_compiler\" >&5\nprintf \"%s\\n\" \"$gl_cv_c_amsterdam_compiler\" >&6; }\n\n      if test $gl_cv_c_amsterdam_compiler = yes; then\n    if test -z \"$AR\"; then\n      AR='cc -c.a'\n    fi\n    if test -z \"$ARFLAGS\"; then\n      ARFLAGS='-o'\n    fi\n  else\n                                                :\n  fi\n\n        if test -n \"$ac_tool_prefix\"; then\n  # Extract the first word of \"${ac_tool_prefix}ar\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}ar; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_AR+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$AR\"; then\n  ac_cv_prog_AR=\"$AR\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_AR=\"${ac_tool_prefix}ar\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nAR=$ac_cv_prog_AR\nif test -n \"$AR\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $AR\" >&5\nprintf \"%s\\n\" \"$AR\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$ac_cv_prog_AR\"; then\n  ac_ct_AR=$AR\n  # Extract the first word of \"ar\", so it can be a program name with args.\nset dummy ar; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_AR+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_AR\"; then\n  ac_cv_prog_ac_ct_AR=\"$ac_ct_AR\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_AR=\"ar\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_AR=$ac_cv_prog_ac_ct_AR\nif test -n \"$ac_ct_AR\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR\" >&5\nprintf \"%s\\n\" \"$ac_ct_AR\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n  if test \"x$ac_ct_AR\" = x; then\n    AR=\"ar\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    AR=$ac_ct_AR\n  fi\nelse\n  AR=\"$ac_cv_prog_AR\"\nfi\n\n  if test -z \"$ARFLAGS\"; then\n    ARFLAGS='cr'\n  fi\n\n\n\n  if test -z \"$RANLIB\"; then\n    if test $gl_cv_c_amsterdam_compiler = yes; then\n      RANLIB=':'\n    else\n            if test -n \"$ac_tool_prefix\"; then\n  # Extract the first word of \"${ac_tool_prefix}ranlib\", so it can be a program name with args.\nset dummy ${ac_tool_prefix}ranlib; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_RANLIB+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$RANLIB\"; then\n  ac_cv_prog_RANLIB=\"$RANLIB\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_RANLIB=\"${ac_tool_prefix}ranlib\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nRANLIB=$ac_cv_prog_RANLIB\nif test -n \"$RANLIB\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $RANLIB\" >&5\nprintf \"%s\\n\" \"$RANLIB\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n\nfi\nif test -z \"$ac_cv_prog_RANLIB\"; then\n  ac_ct_RANLIB=$RANLIB\n  # Extract the first word of \"ranlib\", so it can be a program name with args.\nset dummy ranlib; ac_word=$2\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $ac_word\" >&5\nprintf %s \"checking for $ac_word... \" >&6; }\nif test ${ac_cv_prog_ac_ct_RANLIB+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if test -n \"$ac_ct_RANLIB\"; then\n  ac_cv_prog_ac_ct_RANLIB=\"$ac_ct_RANLIB\" # Let the user override the test.\nelse\nas_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    for ac_exec_ext in '' $ac_executable_extensions; do\n  if as_fn_executable_p \"$as_dir$ac_word$ac_exec_ext\"; then\n    ac_cv_prog_ac_ct_RANLIB=\"ranlib\"\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext\" >&5\n    break 2\n  fi\ndone\n  done\nIFS=$as_save_IFS\n\nfi\nfi\nac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB\nif test -n \"$ac_ct_RANLIB\"; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB\" >&5\nprintf \"%s\\n\" \"$ac_ct_RANLIB\" >&6; }\nelse\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: no\" >&5\nprintf \"%s\\n\" \"no\" >&6; }\nfi\n\n  if test \"x$ac_ct_RANLIB\" = x; then\n    RANLIB=\":\"\n  else\n    case $cross_compiling:$ac_tool_warned in\nyes:)\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: using cross tools not prefixed with host triplet\" >&2;}\nac_tool_warned=yes ;;\nesac\n    RANLIB=$ac_ct_RANLIB\n  fi\nelse\n  RANLIB=\"$ac_cv_prog_RANLIB\"\nfi\n\n    fi\n  fi\n\n\n\n if false; then\n  GL_COND_LIBTOOL_TRUE=\n  GL_COND_LIBTOOL_FALSE='#'\nelse\n  GL_COND_LIBTOOL_TRUE='#'\n  GL_COND_LIBTOOL_FALSE=\nfi\n\ngl_cond_libtool=false\ngl_libdeps=\ngl_ltlibdeps=\n\n\n# Like AC_LIBOBJ, except that the module name goes\n# into gl_LIBOBJS instead of into LIBOBJS.\n\n\n# Like AC_REPLACE_FUNCS, except that the module name goes\n# into gl_LIBOBJS instead of into LIBOBJS.\n\n\n# Like AC_LIBSOURCES, except the directory where the source file is\n# expected is derived from the gnulib-tool parameterization,\n# and alloca is special cased (for the alloca-opt module).\n# We could also entirely rely on EXTRA_lib..._SOURCES.\n\n\n\n\n\n\n\n\n\n\n                        # Check whether --enable-cross-guesses was given.\nif test ${enable_cross_guesses+y}\nthen :\n  enableval=$enable_cross_guesses; if test \"x$enableval\" != xconservative && test \"x$enableval\" != xrisky; then\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-cross-guesses\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: invalid argument supplied to --enable-cross-guesses\" >&2;}\n       enableval=conservative\n     fi\n     gl_cross_guesses=\"$enableval\"\nelse $as_nop\n  gl_cross_guesses=conservative\nfi\n\n  if test $gl_cross_guesses = risky; then\n    gl_cross_guess_normal=\"guessing yes\"\n    gl_cross_guess_inverted=\"guessing no\"\n  else\n    gl_cross_guess_normal=\"guessing no\"\n    gl_cross_guess_inverted=\"guessing yes\"\n  fi\n          LIBC_FATAL_STDERR_=1\n  export LIBC_FATAL_STDERR_\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the preprocessor supports include_next\" >&5\nprintf %s \"checking whether the preprocessor supports include_next... \" >&6; }\nif test ${gl_cv_have_include_next+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  rm -rf conftestd1a conftestd1b conftestd2\n     mkdir conftestd1a conftestd1b conftestd2\n                                                  cat <<EOF > conftestd1a/conftest.h\n#define DEFINED_IN_CONFTESTD1\n#include_next <conftest.h>\n#ifdef DEFINED_IN_CONFTESTD2\nint foo;\n#else\n#error \"include_next doesn't work\"\n#endif\nEOF\n     cat <<EOF > conftestd1b/conftest.h\n#define DEFINED_IN_CONFTESTD1\n#include <stdio.h>\n#include_next <conftest.h>\n#ifdef DEFINED_IN_CONFTESTD2\nint foo;\n#else\n#error \"include_next doesn't work\"\n#endif\nEOF\n     cat <<EOF > conftestd2/conftest.h\n#ifndef DEFINED_IN_CONFTESTD1\n#error \"include_next test doesn't work\"\n#endif\n#define DEFINED_IN_CONFTESTD2\nEOF\n     gl_save_CPPFLAGS=\"$CPPFLAGS\"\n     CPPFLAGS=\"$gl_save_CPPFLAGS -Iconftestd1b -Iconftestd2\"\n     cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <conftest.h>\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_have_include_next=yes\nelse $as_nop\n  CPPFLAGS=\"$gl_save_CPPFLAGS -Iconftestd1a -Iconftestd2\"\n        cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <conftest.h>\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_have_include_next=buggy\nelse $as_nop\n  gl_cv_have_include_next=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n     CPPFLAGS=\"$gl_save_CPPFLAGS\"\n     rm -rf conftestd1a conftestd1b conftestd2\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_include_next\" >&5\nprintf \"%s\\n\" \"$gl_cv_have_include_next\" >&6; }\n  PRAGMA_SYSTEM_HEADER=\n  if test $gl_cv_have_include_next = yes; then\n    INCLUDE_NEXT=include_next\n    INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include_next\n    if test -n \"$GCC\"; then\n      PRAGMA_SYSTEM_HEADER='#pragma GCC system_header'\n    fi\n  else\n    if test $gl_cv_have_include_next = buggy; then\n      INCLUDE_NEXT=include\n      INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include_next\n    else\n      INCLUDE_NEXT=include\n      INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include\n    fi\n  fi\n\n\n\n\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether source code line length is unlimited\" >&5\nprintf %s \"checking whether source code line length is unlimited... \" >&6; }\nif test ${gl_cv_source_line_length_unlimited+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#ifdef __TANDEM\nchoke me\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"choke me\" >/dev/null 2>&1\nthen :\n  gl_cv_source_line_length_unlimited=no\nelse $as_nop\n  gl_cv_source_line_length_unlimited=yes\nfi\nrm -rf conftest*\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_source_line_length_unlimited\" >&5\nprintf \"%s\\n\" \"$gl_cv_source_line_length_unlimited\" >&6; }\n  if test $gl_cv_source_line_length_unlimited = no; then\n    PRAGMA_COLUMNS=\"#pragma COLUMNS 10000\"\n  else\n    PRAGMA_COLUMNS=\n  fi\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for complete errno.h\" >&5\nprintf %s \"checking for complete errno.h... \" >&6; }\nif test ${gl_cv_header_errno_h_complete+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n    cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <errno.h>\n#if !defined ETXTBSY\nbooboo\n#endif\n#if !defined ENOMSG\nbooboo\n#endif\n#if !defined EIDRM\nbooboo\n#endif\n#if !defined ENOLINK\nbooboo\n#endif\n#if !defined EPROTO\nbooboo\n#endif\n#if !defined EMULTIHOP\nbooboo\n#endif\n#if !defined EBADMSG\nbooboo\n#endif\n#if !defined EOVERFLOW\nbooboo\n#endif\n#if !defined ENOTSUP\nbooboo\n#endif\n#if !defined ENETRESET\nbooboo\n#endif\n#if !defined ECONNABORTED\nbooboo\n#endif\n#if !defined ESTALE\nbooboo\n#endif\n#if !defined EDQUOT\nbooboo\n#endif\n#if !defined ECANCELED\nbooboo\n#endif\n#if !defined EOWNERDEAD\nbooboo\n#endif\n#if !defined ENOTRECOVERABLE\nbooboo\n#endif\n#if !defined EILSEQ\nbooboo\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"booboo\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_complete=no\nelse $as_nop\n  gl_cv_header_errno_h_complete=yes\nfi\nrm -rf conftest*\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_complete\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_errno_h_complete\" >&6; }\n  if test $gl_cv_header_errno_h_complete = yes; then\n    ERRNO_H=''\n  else\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_errno_h='<'errno.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <errno.h>\" >&5\nprintf %s \"checking absolute name of <errno.h>... \" >&6; }\nif test ${gl_cv_next_errno_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <errno.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'errno.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_errno_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_errno_h\n           gl_cv_next_errno_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_errno_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_errno_h\" >&6; }\n     fi\n     NEXT_ERRNO_H=$gl_cv_next_errno_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'errno.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_errno_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_ERRNO_H=$gl_next_as_first_directive\n\n\n\n\n    ERRNO_H='errno.h'\n  fi\n\n   if test -n \"$ERRNO_H\"; then\n  GL_GENERATE_ERRNO_H_TRUE=\n  GL_GENERATE_ERRNO_H_FALSE='#'\nelse\n  GL_GENERATE_ERRNO_H_TRUE='#'\n  GL_GENERATE_ERRNO_H_FALSE=\nfi\n\n\n  if test -n \"$ERRNO_H\"; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for EMULTIHOP value\" >&5\nprintf %s \"checking for EMULTIHOP value... \" >&6; }\nif test ${gl_cv_header_errno_h_EMULTIHOP+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <errno.h>\n#ifdef EMULTIHOP\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_EMULTIHOP=yes\nelse $as_nop\n  gl_cv_header_errno_h_EMULTIHOP=no\nfi\nrm -rf conftest*\n\n      if test $gl_cv_header_errno_h_EMULTIHOP = no; then\n        cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n#ifdef EMULTIHOP\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_EMULTIHOP=hidden\nfi\nrm -rf conftest*\n\n        if test $gl_cv_header_errno_h_EMULTIHOP = hidden; then\n                              if ac_fn_c_compute_int \"$LINENO\" \"EMULTIHOP\" \"gl_cv_header_errno_h_EMULTIHOP\"        \"\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n/* The following two lines are a workaround against an autoconf-2.52 bug.  */\n#include <stdio.h>\n#include <stdlib.h>\n\"\nthen :\n\nfi\n\n        fi\n      fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EMULTIHOP\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_errno_h_EMULTIHOP\" >&6; }\n    case $gl_cv_header_errno_h_EMULTIHOP in\n      yes | no)\n        EMULTIHOP_HIDDEN=0; EMULTIHOP_VALUE=\n        ;;\n      *)\n        EMULTIHOP_HIDDEN=1; EMULTIHOP_VALUE=\"$gl_cv_header_errno_h_EMULTIHOP\"\n        ;;\n    esac\n\n\n  fi\n\n\n  if test -n \"$ERRNO_H\"; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for ENOLINK value\" >&5\nprintf %s \"checking for ENOLINK value... \" >&6; }\nif test ${gl_cv_header_errno_h_ENOLINK+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <errno.h>\n#ifdef ENOLINK\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_ENOLINK=yes\nelse $as_nop\n  gl_cv_header_errno_h_ENOLINK=no\nfi\nrm -rf conftest*\n\n      if test $gl_cv_header_errno_h_ENOLINK = no; then\n        cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n#ifdef ENOLINK\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_ENOLINK=hidden\nfi\nrm -rf conftest*\n\n        if test $gl_cv_header_errno_h_ENOLINK = hidden; then\n                              if ac_fn_c_compute_int \"$LINENO\" \"ENOLINK\" \"gl_cv_header_errno_h_ENOLINK\"        \"\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n/* The following two lines are a workaround against an autoconf-2.52 bug.  */\n#include <stdio.h>\n#include <stdlib.h>\n\"\nthen :\n\nfi\n\n        fi\n      fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_ENOLINK\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_errno_h_ENOLINK\" >&6; }\n    case $gl_cv_header_errno_h_ENOLINK in\n      yes | no)\n        ENOLINK_HIDDEN=0; ENOLINK_VALUE=\n        ;;\n      *)\n        ENOLINK_HIDDEN=1; ENOLINK_VALUE=\"$gl_cv_header_errno_h_ENOLINK\"\n        ;;\n    esac\n\n\n  fi\n\n\n  if test -n \"$ERRNO_H\"; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for EOVERFLOW value\" >&5\nprintf %s \"checking for EOVERFLOW value... \" >&6; }\nif test ${gl_cv_header_errno_h_EOVERFLOW+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <errno.h>\n#ifdef EOVERFLOW\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_EOVERFLOW=yes\nelse $as_nop\n  gl_cv_header_errno_h_EOVERFLOW=no\nfi\nrm -rf conftest*\n\n      if test $gl_cv_header_errno_h_EOVERFLOW = no; then\n        cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n#ifdef EOVERFLOW\nyes\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"yes\" >/dev/null 2>&1\nthen :\n  gl_cv_header_errno_h_EOVERFLOW=hidden\nfi\nrm -rf conftest*\n\n        if test $gl_cv_header_errno_h_EOVERFLOW = hidden; then\n                              if ac_fn_c_compute_int \"$LINENO\" \"EOVERFLOW\" \"gl_cv_header_errno_h_EOVERFLOW\"        \"\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n/* The following two lines are a workaround against an autoconf-2.52 bug.  */\n#include <stdio.h>\n#include <stdlib.h>\n\"\nthen :\n\nfi\n\n        fi\n      fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EOVERFLOW\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_errno_h_EOVERFLOW\" >&6; }\n    case $gl_cv_header_errno_h_EOVERFLOW in\n      yes | no)\n        EOVERFLOW_HIDDEN=0; EOVERFLOW_VALUE=\n        ;;\n      *)\n        EOVERFLOW_HIDDEN=1; EOVERFLOW_VALUE=\"$gl_cv_header_errno_h_EOVERFLOW\"\n        ;;\n    esac\n\n\n  fi\n\n\n\n\n\n\n\n    HAVE_DECL_FCLOSEALL=1;\n  HAVE_DECL_FPURGE=1;\n  HAVE_DECL_FSEEKO=1;\n  HAVE_DECL_FTELLO=1;\n  HAVE_DECL_GETDELIM=1;\n  HAVE_DECL_GETLINE=1;\n  HAVE_DECL_OBSTACK_PRINTF=1;\n  HAVE_DECL_SNPRINTF=1;\n  HAVE_DECL_VSNPRINTF=1;\n  HAVE_DPRINTF=1;\n  HAVE_FSEEKO=1;\n  HAVE_FTELLO=1;\n  HAVE_PCLOSE=1;\n  HAVE_POPEN=1;\n  HAVE_RENAMEAT=1;\n  HAVE_VASPRINTF=1;\n  HAVE_VDPRINTF=1;\n  REPLACE_DPRINTF=0;\n  REPLACE_FCLOSE=0;\n  REPLACE_FDOPEN=0;\n  REPLACE_FFLUSH=0;\n  REPLACE_FOPEN=0;\n  REPLACE_FPRINTF=0;\n  REPLACE_FPURGE=0;\n  REPLACE_FREOPEN=0;\n  REPLACE_FSEEK=0;\n  REPLACE_FSEEKO=0;\n  REPLACE_FTELL=0;\n  REPLACE_FTELLO=0;\n  REPLACE_GETDELIM=0;\n  REPLACE_GETLINE=0;\n  REPLACE_OBSTACK_PRINTF=0;\n  REPLACE_PERROR=0;\n  REPLACE_POPEN=0;\n  REPLACE_PRINTF=0;\n  REPLACE_REMOVE=0;\n  REPLACE_RENAME=0;\n  REPLACE_RENAMEAT=0;\n  REPLACE_SNPRINTF=0;\n  REPLACE_SPRINTF=0;\n  REPLACE_STDIO_READ_FUNCS=0;\n  REPLACE_STDIO_WRITE_FUNCS=0;\n  REPLACE_TMPFILE=0;\n  REPLACE_VASPRINTF=0;\n  REPLACE_VDPRINTF=0;\n  REPLACE_VFPRINTF=0;\n  REPLACE_VPRINTF=0;\n  REPLACE_VSNPRINTF=0;\n  REPLACE_VSPRINTF=0;\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions\" >&5\nprintf %s \"checking for $CC options needed to detect all undeclared functions... \" >&6; }\nif test ${ac_cv_c_undeclared_builtin_options+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_save_CFLAGS=$CFLAGS\n   ac_cv_c_undeclared_builtin_options='cannot detect'\n   for ac_arg in '' -fno-builtin; do\n     CFLAGS=\"$ac_save_CFLAGS $ac_arg\"\n     # This test program should *not* compile successfully.\n     cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\nint\nmain (void)\n{\n(void) strchr;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n\nelse $as_nop\n  # This test program should compile successfully.\n        # No library function is consistently available on\n        # freestanding implementations, so test against a dummy\n        # declaration.  Include always-available headers on the\n        # off chance that they somehow elicit warnings.\n        cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <float.h>\n#include <limits.h>\n#include <stdarg.h>\n#include <stddef.h>\nextern void ac_decl (int, char *);\n\nint\nmain (void)\n{\n(void) ac_decl (0, (char *) 0);\n  (void) ac_decl;\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  if test x\"$ac_arg\" = x\nthen :\n  ac_cv_c_undeclared_builtin_options='none needed'\nelse $as_nop\n  ac_cv_c_undeclared_builtin_options=$ac_arg\nfi\n          break\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n    done\n    CFLAGS=$ac_save_CFLAGS\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options\" >&5\nprintf \"%s\\n\" \"$ac_cv_c_undeclared_builtin_options\" >&6; }\n  case $ac_cv_c_undeclared_builtin_options in #(\n  'cannot detect') :\n    { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"cannot make $CC report undeclared builtins\nSee \\`config.log' for more details\" \"$LINENO\" 5; } ;; #(\n  'none needed') :\n    ac_c_undeclared_builtin_options='' ;; #(\n  *) :\n    ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;\nesac\n\nac_fn_check_decl \"$LINENO\" \"getdelim\" \"ac_cv_have_decl_getdelim\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_getdelim\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_GETDELIM $ac_have_decl\" >>confdefs.h\n\nac_func=\nfor ac_item in $ac_func_c_list\ndo\n  if test $ac_func; then\n    ac_fn_c_check_func \"$LINENO\" $ac_func ac_cv_func_$ac_func\n    if eval test \\\"x\\$ac_cv_func_$ac_func\\\" = xyes; then\n      echo \"#define $ac_item 1\" >> confdefs.h\n    fi\n    ac_func=\n  else\n    ac_func=$ac_item\n  fi\ndone\n\n\n  GL_GNULIB_DPRINTF=0\n\n\n\n  GL_GNULIB_FCLOSE=0\n\n\n\n  GL_GNULIB_FDOPEN=0\n\n\n\n  GL_GNULIB_FFLUSH=0\n\n\n\n  GL_GNULIB_FGETC=0\n\n\n\n  GL_GNULIB_FGETS=0\n\n\n\n  GL_GNULIB_FOPEN=0\n\n\n\n  GL_GNULIB_FPRINTF=0\n\n\n\n  GL_GNULIB_FPRINTF_POSIX=0\n\n\n\n  GL_GNULIB_FPURGE=0\n\n\n\n  GL_GNULIB_FPUTC=0\n\n\n\n  GL_GNULIB_FPUTS=0\n\n\n\n  GL_GNULIB_FREAD=0\n\n\n\n  GL_GNULIB_FREOPEN=0\n\n\n\n  GL_GNULIB_FSCANF=0\n\n\n\n  GL_GNULIB_FSEEK=0\n\n\n\n  GL_GNULIB_FSEEKO=0\n\n\n\n  GL_GNULIB_FTELL=0\n\n\n\n  GL_GNULIB_FTELLO=0\n\n\n\n  GL_GNULIB_FWRITE=0\n\n\n\n  GL_GNULIB_GETC=0\n\n\n\n  GL_GNULIB_GETCHAR=0\n\n\n\n  GL_GNULIB_GETDELIM=0\n\n\n\n  GL_GNULIB_GETLINE=0\n\n\n\n  GL_GNULIB_OBSTACK_PRINTF=0\n\n\n\n  GL_GNULIB_OBSTACK_PRINTF_POSIX=0\n\n\n\n  GL_GNULIB_PCLOSE=0\n\n\n\n  GL_GNULIB_PERROR=0\n\n\n\n  GL_GNULIB_POPEN=0\n\n\n\n  GL_GNULIB_PRINTF=0\n\n\n\n  GL_GNULIB_PRINTF_POSIX=0\n\n\n\n  GL_GNULIB_PUTC=0\n\n\n\n  GL_GNULIB_PUTCHAR=0\n\n\n\n  GL_GNULIB_PUTS=0\n\n\n\n  GL_GNULIB_REMOVE=0\n\n\n\n  GL_GNULIB_RENAME=0\n\n\n\n  GL_GNULIB_RENAMEAT=0\n\n\n\n  GL_GNULIB_SCANF=0\n\n\n\n  GL_GNULIB_SNPRINTF=0\n\n\n\n  GL_GNULIB_SPRINTF_POSIX=0\n\n\n\n  GL_GNULIB_STDIO_H_NONBLOCKING=0\n\n\n\n  GL_GNULIB_STDIO_H_SIGPIPE=0\n\n\n\n  GL_GNULIB_TMPFILE=0\n\n\n\n  GL_GNULIB_VASPRINTF=0\n\n\n\n  GL_GNULIB_VFSCANF=0\n\n\n\n  GL_GNULIB_VSCANF=0\n\n\n\n  GL_GNULIB_VDPRINTF=0\n\n\n\n  GL_GNULIB_VFPRINTF=0\n\n\n\n  GL_GNULIB_VFPRINTF_POSIX=0\n\n\n\n  GL_GNULIB_VPRINTF=0\n\n\n\n  GL_GNULIB_VPRINTF_POSIX=0\n\n\n\n  GL_GNULIB_VSNPRINTF=0\n\n\n\n  GL_GNULIB_VSPRINTF_POSIX=0\n\n\n\n  GL_GNULIB_MDA_FCLOSEALL=1\n\n\n\n  GL_GNULIB_MDA_FDOPEN=1\n\n\n\n  GL_GNULIB_MDA_FILENO=1\n\n\n\n  GL_GNULIB_MDA_GETW=1\n\n\n\n  GL_GNULIB_MDA_PUTW=1\n\n\n\n  GL_GNULIB_MDA_TEMPNAM=1\n\n\n\n\n    HAVE_CHOWN=1;\n  HAVE_COPY_FILE_RANGE=1;\n  HAVE_DUP3=1;\n  HAVE_EUIDACCESS=1;\n  HAVE_EXECVPE=1;\n  HAVE_FACCESSAT=1;\n  HAVE_FCHDIR=1;\n  HAVE_FCHOWNAT=1;\n  HAVE_FDATASYNC=1;\n  HAVE_FSYNC=1;\n  HAVE_FTRUNCATE=1;\n  HAVE_GETDTABLESIZE=1;\n  HAVE_GETENTROPY=1;\n  HAVE_GETGROUPS=1;\n  HAVE_GETHOSTNAME=1;\n  HAVE_GETLOGIN=1;\n  HAVE_GETPAGESIZE=1;\n  HAVE_GETPASS=1;\n  HAVE_GROUP_MEMBER=1;\n  HAVE_LCHOWN=1;\n  HAVE_LINK=1;\n  HAVE_LINKAT=1;\n  HAVE_PIPE=1;\n  HAVE_PIPE2=1;\n  HAVE_PREAD=1;\n  HAVE_PWRITE=1;\n  HAVE_READLINK=1;\n  HAVE_READLINKAT=1;\n  HAVE_SETHOSTNAME=1;\n  HAVE_SLEEP=1;\n  HAVE_SYMLINK=1;\n  HAVE_SYMLINKAT=1;\n  HAVE_UNLINKAT=1;\n  HAVE_USLEEP=1;\n  HAVE_DECL_ENVIRON=1;\n  HAVE_DECL_EXECVPE=1;\n  HAVE_DECL_FCHDIR=1;\n  HAVE_DECL_FDATASYNC=1;\n  HAVE_DECL_GETDOMAINNAME=1;\n  HAVE_DECL_GETLOGIN=1;\n  HAVE_DECL_GETLOGIN_R=1;\n  HAVE_DECL_GETPAGESIZE=1;\n  HAVE_DECL_GETUSERSHELL=1;\n  HAVE_DECL_SETHOSTNAME=1;\n  HAVE_DECL_TRUNCATE=1;\n  HAVE_DECL_TTYNAME_R=1;\n  HAVE_OS_H=0;\n  HAVE_SYS_PARAM_H=0;\n  REPLACE_ACCESS=0;\n  REPLACE_CHOWN=0;\n  REPLACE_CLOSE=0;\n  REPLACE_DUP=0;\n  REPLACE_DUP2=0;\n  REPLACE_EXECL=0;\n  REPLACE_EXECLE=0;\n  REPLACE_EXECLP=0;\n  REPLACE_EXECV=0;\n  REPLACE_EXECVE=0;\n  REPLACE_EXECVP=0;\n  REPLACE_EXECVPE=0;\n  REPLACE_FACCESSAT=0;\n  REPLACE_FCHOWNAT=0;\n  REPLACE_FTRUNCATE=0;\n  REPLACE_GETCWD=0;\n  REPLACE_GETDOMAINNAME=0;\n  REPLACE_GETDTABLESIZE=0;\n  REPLACE_GETLOGIN_R=0;\n  REPLACE_GETGROUPS=0;\n  REPLACE_GETPAGESIZE=0;\n  REPLACE_GETPASS=0;\n  REPLACE_ISATTY=0;\n  REPLACE_LCHOWN=0;\n  REPLACE_LINK=0;\n  REPLACE_LINKAT=0;\n  REPLACE_LSEEK=0;\n  REPLACE_PREAD=0;\n  REPLACE_PWRITE=0;\n  REPLACE_READ=0;\n  REPLACE_READLINK=0;\n  REPLACE_READLINKAT=0;\n  REPLACE_RMDIR=0;\n  REPLACE_SLEEP=0;\n  REPLACE_SYMLINK=0;\n  REPLACE_SYMLINKAT=0;\n  REPLACE_TRUNCATE=0;\n  REPLACE_TTYNAME_R=0;\n  REPLACE_UNLINK=0;\n  REPLACE_UNLINKAT=0;\n  REPLACE_USLEEP=0;\n  REPLACE_WRITE=0;\n  UNISTD_H_HAVE_SYS_RANDOM_H=0;\n  UNISTD_H_HAVE_WINSOCK2_H=0;\n  UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS=0;\n\n\n\n\n\n\n\n  GL_GNULIB_ACCESS=0\n\n\n\n  GL_GNULIB_CHDIR=0\n\n\n\n  GL_GNULIB_CHOWN=0\n\n\n\n  GL_GNULIB_CLOSE=0\n\n\n\n  GL_GNULIB_COPY_FILE_RANGE=0\n\n\n\n  GL_GNULIB_DUP=0\n\n\n\n  GL_GNULIB_DUP2=0\n\n\n\n  GL_GNULIB_DUP3=0\n\n\n\n  GL_GNULIB_ENVIRON=0\n\n\n\n  GL_GNULIB_EUIDACCESS=0\n\n\n\n  GL_GNULIB_EXECL=0\n\n\n\n  GL_GNULIB_EXECLE=0\n\n\n\n  GL_GNULIB_EXECLP=0\n\n\n\n  GL_GNULIB_EXECV=0\n\n\n\n  GL_GNULIB_EXECVE=0\n\n\n\n  GL_GNULIB_EXECVP=0\n\n\n\n  GL_GNULIB_EXECVPE=0\n\n\n\n  GL_GNULIB_FACCESSAT=0\n\n\n\n  GL_GNULIB_FCHDIR=0\n\n\n\n  GL_GNULIB_FCHOWNAT=0\n\n\n\n  GL_GNULIB_FDATASYNC=0\n\n\n\n  GL_GNULIB_FSYNC=0\n\n\n\n  GL_GNULIB_FTRUNCATE=0\n\n\n\n  GL_GNULIB_GETCWD=0\n\n\n\n  GL_GNULIB_GETDOMAINNAME=0\n\n\n\n  GL_GNULIB_GETDTABLESIZE=0\n\n\n\n  GL_GNULIB_GETENTROPY=0\n\n\n\n  GL_GNULIB_GETGROUPS=0\n\n\n\n  GL_GNULIB_GETHOSTNAME=0\n\n\n\n  GL_GNULIB_GETLOGIN=0\n\n\n\n  GL_GNULIB_GETLOGIN_R=0\n\n\n\n  GL_GNULIB_GETOPT_POSIX=0\n\n\n\n  GL_GNULIB_GETPAGESIZE=0\n\n\n\n  GL_GNULIB_GETPASS=0\n\n\n\n  GL_GNULIB_GETUSERSHELL=0\n\n\n\n  GL_GNULIB_GROUP_MEMBER=0\n\n\n\n  GL_GNULIB_ISATTY=0\n\n\n\n  GL_GNULIB_LCHOWN=0\n\n\n\n  GL_GNULIB_LINK=0\n\n\n\n  GL_GNULIB_LINKAT=0\n\n\n\n  GL_GNULIB_LSEEK=0\n\n\n\n  GL_GNULIB_PIPE=0\n\n\n\n  GL_GNULIB_PIPE2=0\n\n\n\n  GL_GNULIB_PREAD=0\n\n\n\n  GL_GNULIB_PWRITE=0\n\n\n\n  GL_GNULIB_READ=0\n\n\n\n  GL_GNULIB_READLINK=0\n\n\n\n  GL_GNULIB_READLINKAT=0\n\n\n\n  GL_GNULIB_RMDIR=0\n\n\n\n  GL_GNULIB_SETHOSTNAME=0\n\n\n\n  GL_GNULIB_SLEEP=0\n\n\n\n  GL_GNULIB_SYMLINK=0\n\n\n\n  GL_GNULIB_SYMLINKAT=0\n\n\n\n  GL_GNULIB_TRUNCATE=0\n\n\n\n  GL_GNULIB_TTYNAME_R=0\n\n\n\n  GL_GNULIB_UNISTD_H_GETOPT=0\n\n\n\n  GL_GNULIB_UNISTD_H_NONBLOCKING=0\n\n\n\n  GL_GNULIB_UNISTD_H_SIGPIPE=0\n\n\n\n  GL_GNULIB_UNLINK=0\n\n\n\n  GL_GNULIB_UNLINKAT=0\n\n\n\n  GL_GNULIB_USLEEP=0\n\n\n\n  GL_GNULIB_WRITE=0\n\n\n\n  GL_GNULIB_MDA_ACCESS=1\n\n\n\n  GL_GNULIB_MDA_CHDIR=1\n\n\n\n  GL_GNULIB_MDA_CLOSE=1\n\n\n\n  GL_GNULIB_MDA_DUP=1\n\n\n\n  GL_GNULIB_MDA_DUP2=1\n\n\n\n  GL_GNULIB_MDA_EXECL=1\n\n\n\n  GL_GNULIB_MDA_EXECLE=1\n\n\n\n  GL_GNULIB_MDA_EXECLP=1\n\n\n\n  GL_GNULIB_MDA_EXECV=1\n\n\n\n  GL_GNULIB_MDA_EXECVE=1\n\n\n\n  GL_GNULIB_MDA_EXECVP=1\n\n\n\n  GL_GNULIB_MDA_EXECVPE=1\n\n\n\n  GL_GNULIB_MDA_GETCWD=1\n\n\n\n  GL_GNULIB_MDA_GETPID=1\n\n\n\n  GL_GNULIB_MDA_ISATTY=1\n\n\n\n  GL_GNULIB_MDA_LSEEK=1\n\n\n\n  GL_GNULIB_MDA_READ=1\n\n\n\n  GL_GNULIB_MDA_RMDIR=1\n\n\n\n  GL_GNULIB_MDA_SWAB=1\n\n\n\n  GL_GNULIB_MDA_UNLINK=1\n\n\n\n  GL_GNULIB_MDA_WRITE=1\n\n\n\nac_fn_check_decl \"$LINENO\" \"getline\" \"ac_cv_have_decl_getline\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_getline\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_GETLINE $ac_have_decl\" >>confdefs.h\n\n\n    HAVE_GETTIMEOFDAY=1;\n  HAVE_STRUCT_TIMEVAL=1;\n  HAVE_SYS_TIME_H=1;\n  REPLACE_GETTIMEOFDAY=0;\n  REPLACE_STRUCT_TIMEVAL=0;\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword\" >&5\nprintf %s \"checking for C/C++ restrict keyword... \" >&6; }\nif test ${ac_cv_c_restrict+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_c_restrict=no\n   # Put '__restrict__' first, to avoid problems with glibc and non-GCC; see:\n   # https://lists.gnu.org/archive/html/bug-autoconf/2016-02/msg00006.html\n   # Put 'restrict' last, because C++ lacks it.\n   for ac_kw in __restrict__ __restrict _Restrict restrict; do\n     cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\ntypedef int *int_ptr;\n\t   int foo (int_ptr $ac_kw ip) { return ip[0]; }\n\t   int bar (int [$ac_kw]); /* Catch GCC bug 14050.  */\n\t   int bar (int ip[$ac_kw]) { return ip[0]; }\n\nint\nmain (void)\n{\nint s[1];\n\t   int *$ac_kw t = s;\n\t   t[0] = 0;\n\t   return foo (t) + bar (t);\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_c_restrict=$ac_kw\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n     test \"$ac_cv_c_restrict\" != no && break\n   done\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict\" >&5\nprintf \"%s\\n\" \"$ac_cv_c_restrict\" >&6; }\n\n case $ac_cv_c_restrict in\n   restrict) ;;\n   no) printf \"%s\\n\" \"#define restrict /**/\" >>confdefs.h\n ;;\n   *)  printf \"%s\\n\" \"#define restrict $ac_cv_c_restrict\" >>confdefs.h\n ;;\n esac\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_time_h='<'sys/time.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/time.h>\" >&5\nprintf %s \"checking absolute name of <sys/time.h>... \" >&6; }\nif test ${gl_cv_next_sys_time_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_time_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/time.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/time.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_time_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_time_h\n           gl_cv_next_sys_time_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_time_h='<'sys/time.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_time_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_time_h\" >&6; }\n     fi\n     NEXT_SYS_TIME_H=$gl_cv_next_sys_time_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/time.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_time_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H=$gl_next_as_first_directive\n\n\n\n\n\n  if test $ac_cv_header_sys_time_h != yes; then\n    HAVE_SYS_TIME_H=0\n  fi\n\n\n\n\n\n  if test $ac_cv_header_sys_socket_h != yes; then\n                    ac_fn_c_check_header_compile \"$LINENO\" \"winsock2.h\" \"ac_cv_header_winsock2_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_winsock2_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_WINSOCK2_H 1\" >>confdefs.h\n\nfi\n\n  fi\n  if test \"$ac_cv_header_winsock2_h\" = yes; then\n    HAVE_WINSOCK2_H=1\n    UNISTD_H_HAVE_WINSOCK2_H=1\n    SYS_IOCTL_H_HAVE_WINSOCK2_H=1\n  else\n    HAVE_WINSOCK2_H=0\n  fi\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for struct timeval\" >&5\nprintf %s \"checking for struct timeval... \" >&6; }\nif test ${gl_cv_sys_struct_timeval+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#if HAVE_SYS_TIME_H\n             #include <sys/time.h>\n            #endif\n            #include <time.h>\n            #if HAVE_WINSOCK2_H\n            # include <winsock2.h>\n            #endif\n\nint\nmain (void)\n{\nstatic struct timeval x; x.tv_sec = x.tv_usec;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timeval=yes\nelse $as_nop\n  gl_cv_sys_struct_timeval=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timeval\" >&6; }\n  if test $gl_cv_sys_struct_timeval != yes; then\n    HAVE_STRUCT_TIMEVAL=0\n  else\n                            { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for wide-enough struct timeval.tv_sec member\" >&5\nprintf %s \"checking for wide-enough struct timeval.tv_sec member... \" >&6; }\nif test ${gl_cv_sys_struct_timeval_tv_sec+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#if HAVE_SYS_TIME_H\n               #include <sys/time.h>\n              #endif\n              #include <time.h>\n              #if HAVE_WINSOCK2_H\n              # include <winsock2.h>\n              #endif\n\nint\nmain (void)\n{\nstatic struct timeval x;\n              typedef int verify_tv_sec_type[\n                sizeof (time_t) <= sizeof x.tv_sec ? 1 : -1\n              ];\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timeval_tv_sec=yes\nelse $as_nop\n  gl_cv_sys_struct_timeval_tv_sec=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval_tv_sec\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timeval_tv_sec\" >&6; }\n    if test $gl_cv_sys_struct_timeval_tv_sec != yes; then\n      REPLACE_STRUCT_TIMEVAL=1\n    fi\n  fi\n\n\n\n\n\n\n\n\n  GL_GNULIB_GETTIMEOFDAY=0\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_limits_h='<'limits.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <limits.h>\" >&5\nprintf %s \"checking absolute name of <limits.h>... \" >&6; }\nif test ${gl_cv_next_limits_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_limits_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <limits.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'limits.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_limits_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_limits_h\n           gl_cv_next_limits_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_limits_h='<'limits.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_limits_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_limits_h\" >&6; }\n     fi\n     NEXT_LIMITS_H=$gl_cv_next_limits_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'limits.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_limits_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_LIMITS_H=$gl_next_as_first_directive\n\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether limits.h has WORD_BIT, BOOL_WIDTH etc.\" >&5\nprintf %s \"checking whether limits.h has WORD_BIT, BOOL_WIDTH etc.... \" >&6; }\nif test ${gl_cv_header_limits_width+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n             #define __STDC_WANT_IEC_60559_BFP_EXT__ 1\n            #endif\n            #include <limits.h>\n            long long llm = LLONG_MAX;\n            int wb = WORD_BIT;\n            int ullw = ULLONG_WIDTH;\n            int bw = BOOL_WIDTH;\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_limits_width=yes\nelse $as_nop\n  gl_cv_header_limits_width=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_limits_width\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_limits_width\" >&6; }\n  if test \"$gl_cv_header_limits_width\" = yes; then\n    LIMITS_H=\n  else\n    LIMITS_H=limits.h\n  fi\n\n   if test -n \"$LIMITS_H\"; then\n  GL_GENERATE_LIMITS_H_TRUE=\n  GL_GENERATE_LIMITS_H_FALSE='#'\nelse\n  GL_GENERATE_LIMITS_H_TRUE='#'\n  GL_GENERATE_LIMITS_H_FALSE=\nfi\n\n\n\n\n\n  if test $ac_cv_func__set_invalid_parameter_handler = yes; then\n    HAVE_MSVC_INVALID_PARAMETER_HANDLER=1\n\nprintf \"%s\\n\" \"#define HAVE_MSVC_INVALID_PARAMETER_HANDLER 1\" >>confdefs.h\n\n  else\n    HAVE_MSVC_INVALID_PARAMETER_HANDLER=0\n  fi\n\n\n\n\n\n\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the compiler produces multi-arch binaries\" >&5\nprintf %s \"checking whether the compiler produces multi-arch binaries... \" >&6; }\nif test ${gl_cv_c_multiarch+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  gl_cv_c_multiarch=no\n     cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#ifndef __APPLE_CC__\n            not a universal capable compiler\n           #endif\n           typedef int dummy;\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n\n                        arch=\n        prev=\n        for word in ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}; do\n          if test -n \"$prev\"; then\n            case $word in\n              i?86 | x86_64 | ppc | ppc64 | arm | arm64)\n                if test -z \"$arch\" || test \"$arch\" = \"$word\"; then\n                  arch=\"$word\"\n                else\n                  gl_cv_c_multiarch=yes\n                fi\n                ;;\n            esac\n            prev=\n          else\n            if test \"x$word\" = \"x-arch\"; then\n              prev=arch\n            fi\n          fi\n        done\n\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_multiarch\" >&5\nprintf \"%s\\n\" \"$gl_cv_c_multiarch\" >&6; }\n  if test $gl_cv_c_multiarch = yes; then\n    APPLE_UNIVERSAL_BUILD=1\n  else\n    APPLE_UNIVERSAL_BUILD=0\n  fi\n\n\n\n    HAVE__EXIT=1;\n  HAVE_ALIGNED_ALLOC=1;\n  HAVE_ATOLL=1;\n  HAVE_CANONICALIZE_FILE_NAME=1;\n  HAVE_DECL_ECVT=1;\n  HAVE_DECL_FCVT=1;\n  HAVE_DECL_GCVT=1;\n  HAVE_DECL_GETLOADAVG=1;\n  HAVE_GETSUBOPT=1;\n  HAVE_GRANTPT=1;\n  HAVE_INITSTATE=1;\n  HAVE_DECL_INITSTATE=1;\n  HAVE_MBTOWC=1;\n  HAVE_MKDTEMP=1;\n  HAVE_MKOSTEMP=1;\n  HAVE_MKOSTEMPS=1;\n  HAVE_MKSTEMP=1;\n  HAVE_MKSTEMPS=1;\n  HAVE_POSIX_MEMALIGN=1;\n  HAVE_POSIX_OPENPT=1;\n  HAVE_PTSNAME=1;\n  HAVE_PTSNAME_R=1;\n  HAVE_QSORT_R=1;\n  HAVE_RANDOM=1;\n  HAVE_RANDOM_H=1;\n  HAVE_RANDOM_R=1;\n  HAVE_REALLOCARRAY=1;\n  HAVE_REALPATH=1;\n  HAVE_RPMATCH=1;\n  HAVE_SECURE_GETENV=1;\n  HAVE_SETENV=1;\n  HAVE_DECL_SETENV=1;\n  HAVE_SETSTATE=1;\n  HAVE_DECL_SETSTATE=1;\n  HAVE_STRTOD=1;\n  HAVE_STRTOL=1;\n  HAVE_STRTOLD=1;\n  HAVE_STRTOLL=1;\n  HAVE_STRTOUL=1;\n  HAVE_STRTOULL=1;\n  HAVE_STRUCT_RANDOM_DATA=1;\n  HAVE_SYS_LOADAVG_H=0;\n  HAVE_UNLOCKPT=1;\n  HAVE_DECL_UNSETENV=1;\n  REPLACE_ALIGNED_ALLOC=0;\n  REPLACE_CALLOC=0;\n  REPLACE_CANONICALIZE_FILE_NAME=0;\n  REPLACE_FREE=0;\n  REPLACE_INITSTATE=0;\n  REPLACE_MALLOC=0;\n  REPLACE_MBTOWC=0;\n  REPLACE_MKSTEMP=0;\n  REPLACE_POSIX_MEMALIGN=0;\n  REPLACE_PTSNAME=0;\n  REPLACE_PTSNAME_R=0;\n  REPLACE_PUTENV=0;\n  REPLACE_QSORT_R=0;\n  REPLACE_RANDOM=0;\n  REPLACE_RANDOM_R=0;\n  REPLACE_REALLOC=0;\n  REPLACE_REALLOCARRAY=0;\n  REPLACE_REALPATH=0;\n  REPLACE_SETENV=0;\n  REPLACE_SETSTATE=0;\n  REPLACE_STRTOD=0;\n  REPLACE_STRTOL=0;\n  REPLACE_STRTOLD=0;\n  REPLACE_STRTOLL=0;\n  REPLACE_STRTOUL=0;\n  REPLACE_STRTOULL=0;\n  REPLACE_UNSETENV=0;\n  REPLACE_WCTOMB=0;\n\nac_fn_check_decl \"$LINENO\" \"initstate\" \"ac_cv_have_decl_initstate\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_initstate\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_INITSTATE $ac_have_decl\" >>confdefs.h\n\nac_fn_check_decl \"$LINENO\" \"setstate\" \"ac_cv_have_decl_setstate\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_setstate\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_SETSTATE $ac_have_decl\" >>confdefs.h\n\n\n\n  GL_GNULIB__EXIT=0\n\n\n\n  GL_GNULIB_ALIGNED_ALLOC=0\n\n\n\n  GL_GNULIB_ATOLL=0\n\n\n\n  GL_GNULIB_CALLOC_POSIX=0\n\n\n\n  GL_GNULIB_CANONICALIZE_FILE_NAME=0\n\n\n\n  GL_GNULIB_FREE_POSIX=0\n\n\n\n  GL_GNULIB_GETLOADAVG=0\n\n\n\n  GL_GNULIB_GETSUBOPT=0\n\n\n\n  GL_GNULIB_GRANTPT=0\n\n\n\n  GL_GNULIB_MALLOC_POSIX=0\n\n\n\n  GL_GNULIB_MBTOWC=0\n\n\n\n  GL_GNULIB_MKDTEMP=0\n\n\n\n  GL_GNULIB_MKOSTEMP=0\n\n\n\n  GL_GNULIB_MKOSTEMPS=0\n\n\n\n  GL_GNULIB_MKSTEMP=0\n\n\n\n  GL_GNULIB_MKSTEMPS=0\n\n\n\n  GL_GNULIB_POSIX_MEMALIGN=0\n\n\n\n  GL_GNULIB_POSIX_OPENPT=0\n\n\n\n  GL_GNULIB_PTSNAME=0\n\n\n\n  GL_GNULIB_PTSNAME_R=0\n\n\n\n  GL_GNULIB_PUTENV=0\n\n\n\n  GL_GNULIB_QSORT_R=0\n\n\n\n  GL_GNULIB_RANDOM=0\n\n\n\n  GL_GNULIB_RANDOM_R=0\n\n\n\n  GL_GNULIB_REALLOCARRAY=0\n\n\n\n  GL_GNULIB_REALLOC_POSIX=0\n\n\n\n  GL_GNULIB_REALPATH=0\n\n\n\n  GL_GNULIB_RPMATCH=0\n\n\n\n  GL_GNULIB_SECURE_GETENV=0\n\n\n\n  GL_GNULIB_SETENV=0\n\n\n\n  GL_GNULIB_STRTOD=0\n\n\n\n  GL_GNULIB_STRTOL=0\n\n\n\n  GL_GNULIB_STRTOLD=0\n\n\n\n  GL_GNULIB_STRTOLL=0\n\n\n\n  GL_GNULIB_STRTOUL=0\n\n\n\n  GL_GNULIB_STRTOULL=0\n\n\n\n  GL_GNULIB_SYSTEM_POSIX=0\n\n\n\n  GL_GNULIB_UNLOCKPT=0\n\n\n\n  GL_GNULIB_UNSETENV=0\n\n\n\n  GL_GNULIB_WCTOMB=0\n\n\n\n  GL_GNULIB_MDA_ECVT=1\n\n\n\n  GL_GNULIB_MDA_FCVT=1\n\n\n\n  GL_GNULIB_MDA_GCVT=1\n\n\n\n  GL_GNULIB_MDA_MKTEMP=1\n\n\n\n  GL_GNULIB_MDA_PUTENV=1\n\n\n\n\n\n\n\n\n  if test $ac_cv_header_sys_socket_h != yes; then\n                    ac_fn_c_check_header_compile \"$LINENO\" \"winsock2.h\" \"ac_cv_header_winsock2_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_winsock2_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_WINSOCK2_H 1\" >>confdefs.h\n\nfi\n\n  fi\n  if test \"$ac_cv_header_winsock2_h\" = yes; then\n    HAVE_WINSOCK2_H=1\n    UNISTD_H_HAVE_WINSOCK2_H=1\n    SYS_IOCTL_H_HAVE_WINSOCK2_H=1\n  else\n    HAVE_WINSOCK2_H=0\n  fi\n\n   LIBSOCKET=\n  if test $HAVE_WINSOCK2_H = 1; then\n                { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for WSAStartup\" >&5\nprintf %s \"checking for WSAStartup... \" >&6; }\nif test ${gl_cv_func_wsastartup+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n       gl_save_LIBS=\"$LIBS\"\n       LIBS=\"$LIBS -lws2_32\"\n       cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#ifdef HAVE_WINSOCK2_H\n# include <winsock2.h>\n#endif\nint\nmain (void)\n{\n\n            WORD wVersionRequested = MAKEWORD(1, 1);\n            WSADATA wsaData;\n            int err = WSAStartup(wVersionRequested, &wsaData);\n            WSACleanup ();\n\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_func_wsastartup=yes\nelse $as_nop\n  gl_cv_func_wsastartup=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n       LIBS=\"$gl_save_LIBS\"\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_wsastartup\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_wsastartup\" >&6; }\n    if test \"$gl_cv_func_wsastartup\" = \"yes\"; then\n\nprintf \"%s\\n\" \"#define WINDOWS_SOCKETS 1\" >>confdefs.h\n\n      LIBSOCKET='-lws2_32'\n    fi\n  else\n                                    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for library containing setsockopt\" >&5\nprintf %s \"checking for library containing setsockopt... \" >&6; }\nif test ${gl_cv_lib_socket+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      gl_cv_lib_socket=\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\nextern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();\nint\nmain (void)\n{\nsetsockopt();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n\nelse $as_nop\n  gl_save_LIBS=\"$LIBS\"\n         LIBS=\"$gl_save_LIBS -lsocket\"\n         cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\nextern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();\nint\nmain (void)\n{\nsetsockopt();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_lib_socket=\"-lsocket\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n         if test -z \"$gl_cv_lib_socket\"; then\n           LIBS=\"$gl_save_LIBS -lnetwork\"\n           cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\nextern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();\nint\nmain (void)\n{\nsetsockopt();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_lib_socket=\"-lnetwork\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n           if test -z \"$gl_cv_lib_socket\"; then\n             LIBS=\"$gl_save_LIBS -lnet\"\n             cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\nextern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();\nint\nmain (void)\n{\nsetsockopt();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_lib_socket=\"-lnet\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n           fi\n         fi\n         LIBS=\"$gl_save_LIBS\"\n\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n      if test -z \"$gl_cv_lib_socket\"; then\n        gl_cv_lib_socket=\"none needed\"\n      fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_lib_socket\" >&5\nprintf \"%s\\n\" \"$gl_cv_lib_socket\" >&6; }\n    if test \"$gl_cv_lib_socket\" != \"none needed\"; then\n      LIBSOCKET=\"$gl_cv_lib_socket\"\n    fi\n  fi\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for inline\" >&5\nprintf %s \"checking for inline... \" >&6; }\nif test ${ac_cv_c_inline+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_cv_c_inline=no\nfor ac_kw in inline __inline__ __inline; do\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#ifndef __cplusplus\ntypedef int foo_t;\nstatic $ac_kw foo_t static_foo (void) {return 0; }\n$ac_kw foo_t foo (void) {return 0; }\n#endif\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_c_inline=$ac_kw\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n  test \"$ac_cv_c_inline\" != no && break\ndone\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline\" >&5\nprintf \"%s\\n\" \"$ac_cv_c_inline\" >&6; }\n\ncase $ac_cv_c_inline in\n  inline | yes) ;;\n  *)\n    case $ac_cv_c_inline in\n      no) ac_val=;;\n      *) ac_val=$ac_cv_c_inline;;\n    esac\n    cat >>confdefs.h <<_ACEOF\n#ifndef __cplusplus\n#define inline $ac_val\n#endif\n_ACEOF\n    ;;\nesac\n\n\n\n\n\n  :\n\n\n\n   if test $ac_cv_header_sys_socket_h = no; then\n                         ac_fn_c_check_header_compile \"$LINENO\" \"ws2tcpip.h\" \"ac_cv_header_ws2tcpip_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_ws2tcpip_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_WS2TCPIP_H 1\" >>confdefs.h\n\nfi\n\n   fi\n\n\n    REPLACE_NULL=0;\n  HAVE_MAX_ALIGN_T=1;\n  HAVE_WCHAR_T=1;\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for wchar_t\" >&5\nprintf %s \"checking for wchar_t... \" >&6; }\nif test ${gt_cv_c_wchar_t+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stddef.h>\n            wchar_t foo = (wchar_t)'\\0';\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gt_cv_c_wchar_t=yes\nelse $as_nop\n  gt_cv_c_wchar_t=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wchar_t\" >&5\nprintf \"%s\\n\" \"$gt_cv_c_wchar_t\" >&6; }\n  if test $gt_cv_c_wchar_t = yes; then\n\nprintf \"%s\\n\" \"#define HAVE_WCHAR_T 1\" >>confdefs.h\n\n  fi\n\n\n\n\n\n\n\n  STDDEF_H=\n\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for good max_align_t\" >&5\nprintf %s \"checking for good max_align_t... \" >&6; }\nif test ${gl_cv_type_max_align_t+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stddef.h>\n            unsigned int s = sizeof (max_align_t);\n            #if defined __GNUC__ || defined __clang__ || defined __IBM__ALIGNOF__\n            int check1[2 * (__alignof__ (double) <= __alignof__ (max_align_t)) - 1];\n            int check2[2 * (__alignof__ (long double) <= __alignof__ (max_align_t)) - 1];\n            #endif\n            typedef struct { char a; max_align_t b; } max_helper;\n            typedef struct { char a; long b; } long_helper;\n            typedef struct { char a; double b; } double_helper;\n            typedef struct { char a; long double b; } long_double_helper;\n            int check3[2 * (offsetof (long_helper, b) <= offsetof (max_helper, b)) - 1];\n            int check4[2 * (offsetof (double_helper, b) <= offsetof (max_helper, b)) - 1];\n            int check5[2 * (offsetof (long_double_helper, b) <= offsetof (max_helper, b)) - 1];\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_type_max_align_t=yes\nelse $as_nop\n  gl_cv_type_max_align_t=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_max_align_t\" >&5\nprintf \"%s\\n\" \"$gl_cv_type_max_align_t\" >&6; }\n  if test $gl_cv_type_max_align_t = no; then\n    HAVE_MAX_ALIGN_T=0\n    STDDEF_H=stddef.h\n  fi\n\n  if test $gt_cv_c_wchar_t = no; then\n    HAVE_WCHAR_T=0\n    STDDEF_H=stddef.h\n  fi\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether NULL can be used in arbitrary expressions\" >&5\nprintf %s \"checking whether NULL can be used in arbitrary expressions... \" >&6; }\nif test ${gl_cv_decl_null_works+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stddef.h>\n      int test[2 * (sizeof NULL == sizeof (void *)) -1];\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_decl_null_works=yes\nelse $as_nop\n  gl_cv_decl_null_works=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_null_works\" >&5\nprintf \"%s\\n\" \"$gl_cv_decl_null_works\" >&6; }\n  if test $gl_cv_decl_null_works = no; then\n    REPLACE_NULL=1\n    STDDEF_H=stddef.h\n  fi\n\n\n   if test -n \"$STDDEF_H\"; then\n  GL_GENERATE_STDDEF_H_TRUE=\n  GL_GENERATE_STDDEF_H_FALSE='#'\nelse\n  GL_GENERATE_STDDEF_H_TRUE='#'\n  GL_GENERATE_STDDEF_H_FALSE=\nfi\n\n  if test -n \"$STDDEF_H\"; then\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_stddef_h='<'stddef.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <stddef.h>\" >&5\nprintf %s \"checking absolute name of <stddef.h>... \" >&6; }\nif test ${gl_cv_next_stddef_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stddef.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'stddef.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_stddef_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_stddef_h\n           gl_cv_next_stddef_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stddef_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_stddef_h\" >&6; }\n     fi\n     NEXT_STDDEF_H=$gl_cv_next_stddef_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'stddef.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_stddef_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_STDDEF_H=$gl_next_as_first_directive\n\n\n\n\n  fi\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for wint_t\" >&5\nprintf %s \"checking for wint_t... \" >&6; }\nif test ${gt_cv_c_wint_t+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <wchar.h>\n            wint_t foo = (wchar_t)'\\0';\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gt_cv_c_wint_t=yes\nelse $as_nop\n  gt_cv_c_wint_t=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wint_t\" >&5\nprintf \"%s\\n\" \"$gt_cv_c_wint_t\" >&6; }\n  if test $gt_cv_c_wint_t = yes; then\n\nprintf \"%s\\n\" \"#define HAVE_WINT_T 1\" >>confdefs.h\n\n\n            { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether wint_t is large enough\" >&5\nprintf %s \"checking whether wint_t is large enough... \" >&6; }\nif test ${gl_cv_type_wint_t_large_enough+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <wchar.h>\n              int verify[sizeof (wint_t) < sizeof (int) ? -1 : 1];\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_type_wint_t_large_enough=yes\nelse $as_nop\n  gl_cv_type_wint_t_large_enough=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wint_t_large_enough\" >&5\nprintf \"%s\\n\" \"$gl_cv_type_wint_t_large_enough\" >&6; }\n    if test $gl_cv_type_wint_t_large_enough = no; then\n      GNULIBHEADERS_OVERRIDE_WINT_T=1\n    else\n      GNULIBHEADERS_OVERRIDE_WINT_T=0\n    fi\n  else\n    GNULIBHEADERS_OVERRIDE_WINT_T=0\n  fi\n\n\n\n\n\n\n\n\nprintf \"%s\\n\" \"#define HAVE_LONG_LONG_INT 1\" >>confdefs.h\n\n\nprintf \"%s\\n\" \"#define HAVE_UNSIGNED_LONG_LONG_INT 1\" >>confdefs.h\n\n\n\n  if test $ac_cv_header_wchar_h = yes; then\n    HAVE_WCHAR_H=1\n  else\n    HAVE_WCHAR_H=0\n  fi\n\n\n\n  if test $ac_cv_header_inttypes_h = yes; then\n    HAVE_INTTYPES_H=1\n  else\n    HAVE_INTTYPES_H=0\n  fi\n\n\n\n  if test $ac_cv_header_sys_types_h = yes; then\n    HAVE_SYS_TYPES_H=1\n  else\n    HAVE_SYS_TYPES_H=0\n  fi\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_stdint_h='<'stdint.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <stdint.h>\" >&5\nprintf %s \"checking absolute name of <stdint.h>... \" >&6; }\nif test ${gl_cv_next_stdint_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_stdint_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdint.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'stdint.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_stdint_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_stdint_h\n           gl_cv_next_stdint_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_stdint_h='<'stdint.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdint_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_stdint_h\" >&6; }\n     fi\n     NEXT_STDINT_H=$gl_cv_next_stdint_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'stdint.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_stdint_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_STDINT_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_stdint_h = yes; then\n    HAVE_STDINT_H=1\n  else\n    HAVE_STDINT_H=0\n  fi\n\n\n    if test $ac_cv_header_stdint_h = yes; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether stdint.h conforms to C99\" >&5\nprintf %s \"checking whether stdint.h conforms to C99... \" >&6; }\nif test ${gl_cv_header_working_stdint_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  gl_cv_header_working_stdint_h=no\n       cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#define __STDC_CONSTANT_MACROS 1\n#define __STDC_LIMIT_MACROS 1\n#include <stdint.h>\n/* Dragonfly defines WCHAR_MIN, WCHAR_MAX only in <wchar.h>.  */\n#if !(defined WCHAR_MIN && defined WCHAR_MAX)\n#error \"WCHAR_MIN, WCHAR_MAX not defined in <stdint.h>\"\n#endif\n\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n\n#ifdef INT8_MAX\nint8_t a1 = INT8_MAX;\nint8_t a1min = INT8_MIN;\n#endif\n#ifdef INT16_MAX\nint16_t a2 = INT16_MAX;\nint16_t a2min = INT16_MIN;\n#endif\n#ifdef INT32_MAX\nint32_t a3 = INT32_MAX;\nint32_t a3min = INT32_MIN;\n#endif\n#ifdef INT64_MAX\nint64_t a4 = INT64_MAX;\nint64_t a4min = INT64_MIN;\n#endif\n#ifdef UINT8_MAX\nuint8_t b1 = UINT8_MAX;\n#else\ntypedef int b1[(unsigned char) -1 != 255 ? 1 : -1];\n#endif\n#ifdef UINT16_MAX\nuint16_t b2 = UINT16_MAX;\n#endif\n#ifdef UINT32_MAX\nuint32_t b3 = UINT32_MAX;\n#endif\n#ifdef UINT64_MAX\nuint64_t b4 = UINT64_MAX;\n#endif\nint_least8_t c1 = INT8_C (0x7f);\nint_least8_t c1max = INT_LEAST8_MAX;\nint_least8_t c1min = INT_LEAST8_MIN;\nint_least16_t c2 = INT16_C (0x7fff);\nint_least16_t c2max = INT_LEAST16_MAX;\nint_least16_t c2min = INT_LEAST16_MIN;\nint_least32_t c3 = INT32_C (0x7fffffff);\nint_least32_t c3max = INT_LEAST32_MAX;\nint_least32_t c3min = INT_LEAST32_MIN;\nint_least64_t c4 = INT64_C (0x7fffffffffffffff);\nint_least64_t c4max = INT_LEAST64_MAX;\nint_least64_t c4min = INT_LEAST64_MIN;\nuint_least8_t d1 = UINT8_C (0xff);\nuint_least8_t d1max = UINT_LEAST8_MAX;\nuint_least16_t d2 = UINT16_C (0xffff);\nuint_least16_t d2max = UINT_LEAST16_MAX;\nuint_least32_t d3 = UINT32_C (0xffffffff);\nuint_least32_t d3max = UINT_LEAST32_MAX;\nuint_least64_t d4 = UINT64_C (0xffffffffffffffff);\nuint_least64_t d4max = UINT_LEAST64_MAX;\nint_fast8_t e1 = INT_FAST8_MAX;\nint_fast8_t e1min = INT_FAST8_MIN;\nint_fast16_t e2 = INT_FAST16_MAX;\nint_fast16_t e2min = INT_FAST16_MIN;\nint_fast32_t e3 = INT_FAST32_MAX;\nint_fast32_t e3min = INT_FAST32_MIN;\nint_fast64_t e4 = INT_FAST64_MAX;\nint_fast64_t e4min = INT_FAST64_MIN;\nuint_fast8_t f1 = UINT_FAST8_MAX;\nuint_fast16_t f2 = UINT_FAST16_MAX;\nuint_fast32_t f3 = UINT_FAST32_MAX;\nuint_fast64_t f4 = UINT_FAST64_MAX;\n#ifdef INTPTR_MAX\nintptr_t g = INTPTR_MAX;\nintptr_t gmin = INTPTR_MIN;\n#endif\n#ifdef UINTPTR_MAX\nuintptr_t h = UINTPTR_MAX;\n#endif\nintmax_t i = INTMAX_MAX;\nuintmax_t j = UINTMAX_MAX;\n\n/* Check that SIZE_MAX has the correct type, if possible.  */\n#if 201112 <= __STDC_VERSION__\nint k = _Generic (SIZE_MAX, size_t: 0);\n#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \\\n       || (0x5110 <= __SUNPRO_C && !__STDC__))\nextern size_t k;\nextern __typeof__ (SIZE_MAX) k;\n#endif\n\n#include <limits.h> /* for CHAR_BIT */\n#define TYPE_MINIMUM(t) \\\n  ((t) ((t) 0 < (t) -1 ? (t) 0 : ~ TYPE_MAXIMUM (t)))\n#define TYPE_MAXIMUM(t) \\\n  ((t) ((t) 0 < (t) -1 \\\n        ? (t) -1 \\\n        : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))\nstruct s {\n  int check_PTRDIFF:\n      PTRDIFF_MIN == TYPE_MINIMUM (ptrdiff_t)\n      && PTRDIFF_MAX == TYPE_MAXIMUM (ptrdiff_t)\n      ? 1 : -1;\n  /* Detect bug in FreeBSD 6.0/ia64 and FreeBSD 13.0/arm64.  */\n  int check_SIG_ATOMIC:\n      SIG_ATOMIC_MIN == TYPE_MINIMUM (sig_atomic_t)\n      && SIG_ATOMIC_MAX == TYPE_MAXIMUM (sig_atomic_t)\n      ? 1 : -1;\n  int check_SIZE: SIZE_MAX == TYPE_MAXIMUM (size_t) ? 1 : -1;\n  int check_WCHAR:\n      WCHAR_MIN == TYPE_MINIMUM (wchar_t)\n      && WCHAR_MAX == TYPE_MAXIMUM (wchar_t)\n      ? 1 : -1;\n  /* Detect bug in mingw.  */\n  int check_WINT:\n      WINT_MIN == TYPE_MINIMUM (wint_t)\n      && WINT_MAX == TYPE_MAXIMUM (wint_t)\n      ? 1 : -1;\n\n  /* Detect bugs in glibc 2.4 and Solaris 10 stdint.h, among others.  */\n  int check_UINT8_C:\n        (-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1;\n  int check_UINT16_C:\n        (-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1;\n\n  /* Detect bugs in OpenBSD 3.9 stdint.h.  */\n#ifdef UINT8_MAX\n  int check_uint8: (uint8_t) -1 == UINT8_MAX ? 1 : -1;\n#endif\n#ifdef UINT16_MAX\n  int check_uint16: (uint16_t) -1 == UINT16_MAX ? 1 : -1;\n#endif\n#ifdef UINT32_MAX\n  int check_uint32: (uint32_t) -1 == UINT32_MAX ? 1 : -1;\n#endif\n#ifdef UINT64_MAX\n  int check_uint64: (uint64_t) -1 == UINT64_MAX ? 1 : -1;\n#endif\n  int check_uint_least8: (uint_least8_t) -1 == UINT_LEAST8_MAX ? 1 : -1;\n  int check_uint_least16: (uint_least16_t) -1 == UINT_LEAST16_MAX ? 1 : -1;\n  int check_uint_least32: (uint_least32_t) -1 == UINT_LEAST32_MAX ? 1 : -1;\n  int check_uint_least64: (uint_least64_t) -1 == UINT_LEAST64_MAX ? 1 : -1;\n  int check_uint_fast8: (uint_fast8_t) -1 == UINT_FAST8_MAX ? 1 : -1;\n  int check_uint_fast16: (uint_fast16_t) -1 == UINT_FAST16_MAX ? 1 : -1;\n  int check_uint_fast32: (uint_fast32_t) -1 == UINT_FAST32_MAX ? 1 : -1;\n  int check_uint_fast64: (uint_fast64_t) -1 == UINT_FAST64_MAX ? 1 : -1;\n  int check_uintptr: (uintptr_t) -1 == UINTPTR_MAX ? 1 : -1;\n  int check_uintmax: (uintmax_t) -1 == UINTMAX_MAX ? 1 : -1;\n  int check_size: (size_t) -1 == SIZE_MAX ? 1 : -1;\n};\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n                                                    if test \"$cross_compiling\" = yes\nthen :\n  case \"$host_os\" in\n                         # Guess yes on native Windows.\n                 mingw*) gl_cv_header_working_stdint_h=\"guessing yes\" ;;\n                         # In general, assume it works.\n                 *)      gl_cv_header_working_stdint_h=\"guessing yes\" ;;\n               esac\n\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#define __STDC_CONSTANT_MACROS 1\n#define __STDC_LIMIT_MACROS 1\n#include <stdint.h>\n\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n\n#include <stdio.h>\n#include <string.h>\n#define MVAL(macro) MVAL1(macro)\n#define MVAL1(expression) #expression\nstatic const char *macro_values[] =\n  {\n#ifdef INT8_MAX\n    MVAL (INT8_MAX),\n#endif\n#ifdef INT16_MAX\n    MVAL (INT16_MAX),\n#endif\n#ifdef INT32_MAX\n    MVAL (INT32_MAX),\n#endif\n#ifdef INT64_MAX\n    MVAL (INT64_MAX),\n#endif\n#ifdef UINT8_MAX\n    MVAL (UINT8_MAX),\n#endif\n#ifdef UINT16_MAX\n    MVAL (UINT16_MAX),\n#endif\n#ifdef UINT32_MAX\n    MVAL (UINT32_MAX),\n#endif\n#ifdef UINT64_MAX\n    MVAL (UINT64_MAX),\n#endif\n    NULL\n  };\n\nint\nmain (void)\n{\n\n  const char **mv;\n  for (mv = macro_values; *mv != NULL; mv++)\n    {\n      const char *value = *mv;\n      /* Test whether it looks like a cast expression.  */\n      if (strncmp (value, \"((unsigned int)\"/*)*/, 15) == 0\n          || strncmp (value, \"((unsigned short)\"/*)*/, 17) == 0\n          || strncmp (value, \"((unsigned char)\"/*)*/, 16) == 0\n          || strncmp (value, \"((int)\"/*)*/, 6) == 0\n          || strncmp (value, \"((signed short)\"/*)*/, 15) == 0\n          || strncmp (value, \"((signed char)\"/*)*/, 14) == 0)\n        return mv - macro_values + 1;\n    }\n  return 0;\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_run \"$LINENO\"\nthen :\n  gl_cv_header_working_stdint_h=yes\nfi\nrm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \\\n  conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n\n\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdint_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_working_stdint_h\" >&6; }\n  fi\n\n  HAVE_C99_STDINT_H=0\n  HAVE_SYS_BITYPES_H=0\n  HAVE_SYS_INTTYPES_H=0\n  STDINT_H=stdint.h\n  case \"$gl_cv_header_working_stdint_h\" in\n    *yes)\n      HAVE_C99_STDINT_H=1\n                        { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether stdint.h works without ISO C predefines\" >&5\nprintf %s \"checking whether stdint.h works without ISO C predefines... \" >&6; }\nif test ${gl_cv_header_stdint_without_STDC_macros+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  gl_cv_header_stdint_without_STDC_macros=no\n         cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#include <stdint.h>\n\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n\nintmax_t im = INTMAX_MAX;\nint32_t i32 = INT32_C (0x7fffffff);\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_stdint_without_STDC_macros=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_without_STDC_macros\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_stdint_without_STDC_macros\" >&6; }\n\n      if test $gl_cv_header_stdint_without_STDC_macros = no; then\n\nprintf \"%s\\n\" \"#define __STDC_CONSTANT_MACROS 1\" >>confdefs.h\n\n\nprintf \"%s\\n\" \"#define __STDC_LIMIT_MACROS 1\" >>confdefs.h\n\n      fi\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether stdint.h has UINTMAX_WIDTH etc.\" >&5\nprintf %s \"checking whether stdint.h has UINTMAX_WIDTH etc.... \" >&6; }\nif test ${gl_cv_header_stdint_width+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  gl_cv_header_stdint_width=no\n         cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n              /* Work if build is not clean.  */\n              #define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1\n              #ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n               #define __STDC_WANT_IEC_60559_BFP_EXT__ 1\n              #endif\n              #include <stdint.h>\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n              int iw = UINTMAX_WIDTH;\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_stdint_width=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_width\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_stdint_width\" >&6; }\n      if test \"$gl_cv_header_stdint_width\" = yes; then\n        STDINT_H=\n      fi\n      ;;\n    *)\n                  ac_fn_c_check_header_compile \"$LINENO\" \"sys/inttypes.h\" \"ac_cv_header_sys_inttypes_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_sys_inttypes_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_SYS_INTTYPES_H 1\" >>confdefs.h\n\nfi\nac_fn_c_check_header_compile \"$LINENO\" \"sys/bitypes.h\" \"ac_cv_header_sys_bitypes_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_sys_bitypes_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_SYS_BITYPES_H 1\" >>confdefs.h\n\nfi\n\n      if test $ac_cv_header_sys_inttypes_h = yes; then\n        HAVE_SYS_INTTYPES_H=1\n      fi\n      if test $ac_cv_header_sys_bitypes_h = yes; then\n        HAVE_SYS_BITYPES_H=1\n      fi\n\n\n  if test $APPLE_UNIVERSAL_BUILD = 0; then\n\n\n  for gltype in ptrdiff_t size_t ; do\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype\" >&5\nprintf %s \"checking for bit size of $gltype... \" >&6; }\nif eval test \\${gl_cv_bitsizeof_${gltype}+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if ac_fn_c_compute_int \"$LINENO\" \"sizeof ($gltype) * CHAR_BIT\" \"result\"        \"\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n#include <limits.h>\"\nthen :\n\nelse $as_nop\n  result=unknown\nfi\n\n       eval gl_cv_bitsizeof_${gltype}=\\$result\n\nfi\neval ac_res=\\$gl_cv_bitsizeof_${gltype}\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n    eval result=\\$gl_cv_bitsizeof_${gltype}\n    if test $result = unknown; then\n                                                result=0\n    fi\n    GLTYPE=`echo \"$gltype\" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    printf \"%s\\n\" \"#define BITSIZEOF_${GLTYPE} $result\" >>confdefs.h\n\n    eval BITSIZEOF_${GLTYPE}=\\$result\n  done\n\n\n  fi\n\n\n  for gltype in sig_atomic_t wchar_t wint_t ; do\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype\" >&5\nprintf %s \"checking for bit size of $gltype... \" >&6; }\nif eval test \\${gl_cv_bitsizeof_${gltype}+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  if ac_fn_c_compute_int \"$LINENO\" \"sizeof ($gltype) * CHAR_BIT\" \"result\"        \"\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n#include <limits.h>\"\nthen :\n\nelse $as_nop\n  result=unknown\nfi\n\n       eval gl_cv_bitsizeof_${gltype}=\\$result\n\nfi\neval ac_res=\\$gl_cv_bitsizeof_${gltype}\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n    eval result=\\$gl_cv_bitsizeof_${gltype}\n    if test $result = unknown; then\n                                                result=0\n    fi\n    GLTYPE=`echo \"$gltype\" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    printf \"%s\\n\" \"#define BITSIZEOF_${GLTYPE} $result\" >>confdefs.h\n\n    eval BITSIZEOF_${GLTYPE}=\\$result\n  done\n\n\n\n\n  for gltype in sig_atomic_t wchar_t wint_t ; do\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether $gltype is signed\" >&5\nprintf %s \"checking whether $gltype is signed... \" >&6; }\nif eval test \\${gl_cv_type_${gltype}_signed+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n            int verify[2 * (($gltype) -1 < ($gltype) 0) - 1];\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  result=yes\nelse $as_nop\n  result=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n       eval gl_cv_type_${gltype}_signed=\\$result\n\nfi\neval ac_res=\\$gl_cv_type_${gltype}_signed\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n    eval result=\\$gl_cv_type_${gltype}_signed\n    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    if test \"$result\" = yes; then\n      printf \"%s\\n\" \"#define HAVE_SIGNED_${GLTYPE} 1\" >>confdefs.h\n\n      eval HAVE_SIGNED_${GLTYPE}=1\n    else\n      eval HAVE_SIGNED_${GLTYPE}=0\n    fi\n  done\n\n\n  gl_cv_type_ptrdiff_t_signed=yes\n  gl_cv_type_size_t_signed=no\n  if test $APPLE_UNIVERSAL_BUILD = 0; then\n\n\n  for gltype in ptrdiff_t size_t ; do\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix\" >&5\nprintf %s \"checking for $gltype integer literal suffix... \" >&6; }\nif eval test \\${gl_cv_type_${gltype}_suffix+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  eval gl_cv_type_${gltype}_suffix=no\n       eval result=\\$gl_cv_type_${gltype}_signed\n       if test \"$result\" = yes; then\n         glsufu=\n       else\n         glsufu=u\n       fi\n       for glsuf in \"$glsufu\" ${glsufu}l ${glsufu}ll ${glsufu}i64; do\n         case $glsuf in\n           '')  gltype1='int';;\n           l)   gltype1='long int';;\n           ll)  gltype1='long long int';;\n           i64) gltype1='__int64';;\n           u)   gltype1='unsigned int';;\n           ul)  gltype1='unsigned long int';;\n           ull) gltype1='unsigned long long int';;\n           ui64)gltype1='unsigned __int64';;\n         esac\n         cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n              extern $gltype foo;\n              extern $gltype1 foo;\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval gl_cv_type_${gltype}_suffix=\\$glsuf\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n         eval result=\\$gl_cv_type_${gltype}_suffix\n         test \"$result\" != no && break\n       done\nfi\neval ac_res=\\$gl_cv_type_${gltype}_suffix\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    eval result=\\$gl_cv_type_${gltype}_suffix\n    test \"$result\" = no && result=\n    eval ${GLTYPE}_SUFFIX=\\$result\n    printf \"%s\\n\" \"#define ${GLTYPE}_SUFFIX $result\" >>confdefs.h\n\n  done\n\n\n  fi\n\n\n  for gltype in sig_atomic_t wchar_t wint_t ; do\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix\" >&5\nprintf %s \"checking for $gltype integer literal suffix... \" >&6; }\nif eval test \\${gl_cv_type_${gltype}_suffix+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  eval gl_cv_type_${gltype}_suffix=no\n       eval result=\\$gl_cv_type_${gltype}_signed\n       if test \"$result\" = yes; then\n         glsufu=\n       else\n         glsufu=u\n       fi\n       for glsuf in \"$glsufu\" ${glsufu}l ${glsufu}ll ${glsufu}i64; do\n         case $glsuf in\n           '')  gltype1='int';;\n           l)   gltype1='long int';;\n           ll)  gltype1='long long int';;\n           i64) gltype1='__int64';;\n           u)   gltype1='unsigned int';;\n           ul)  gltype1='unsigned long int';;\n           ull) gltype1='unsigned long long int';;\n           ui64)gltype1='unsigned __int64';;\n         esac\n         cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n\n              extern $gltype foo;\n              extern $gltype1 foo;\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  eval gl_cv_type_${gltype}_suffix=\\$glsuf\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n         eval result=\\$gl_cv_type_${gltype}_suffix\n         test \"$result\" != no && break\n       done\nfi\neval ac_res=\\$gl_cv_type_${gltype}_suffix\n\t       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_res\" >&5\nprintf \"%s\\n\" \"$ac_res\" >&6; }\n    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    eval result=\\$gl_cv_type_${gltype}_suffix\n    test \"$result\" = no && result=\n    eval ${GLTYPE}_SUFFIX=\\$result\n    printf \"%s\\n\" \"#define ${GLTYPE}_SUFFIX $result\" >>confdefs.h\n\n  done\n\n\n\n          if test $GNULIBHEADERS_OVERRIDE_WINT_T = 1; then\n    BITSIZEOF_WINT_T=32\n  fi\n\n      ;;\n  esac\n\n\n\n  LIMITS_H='limits.h'\n   if test -n \"$LIMITS_H\"; then\n  GL_GENERATE_LIMITS_H_TRUE=\n  GL_GENERATE_LIMITS_H_FALSE='#'\nelse\n  GL_GENERATE_LIMITS_H_TRUE='#'\n  GL_GENERATE_LIMITS_H_FALSE=\nfi\n\n\n\n\n\n\n\n   if test -n \"$STDINT_H\"; then\n  GL_GENERATE_STDINT_H_TRUE=\n  GL_GENERATE_STDINT_H_FALSE='#'\nelse\n  GL_GENERATE_STDINT_H_TRUE='#'\n  GL_GENERATE_STDINT_H_FALSE=\nfi\n\n\nac_fn_check_decl \"$LINENO\" \"fcloseall\" \"ac_cv_have_decl_fcloseall\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_fcloseall\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_FCLOSEALL $ac_have_decl\" >>confdefs.h\n\n\n\n\n  printf \"%s\\n\" \"#define __USE_MINGW_ANSI_STDIO 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_stdio_h='<'stdio.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <stdio.h>\" >&5\nprintf %s \"checking absolute name of <stdio.h>... \" >&6; }\nif test ${gl_cv_next_stdio_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdio.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'stdio.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_stdio_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_stdio_h\n           gl_cv_next_stdio_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdio_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_stdio_h\" >&6; }\n     fi\n     NEXT_STDIO_H=$gl_cv_next_stdio_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'stdio.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_stdio_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_STDIO_H=$gl_next_as_first_directive\n\n\n\n\n\n        { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking which flavor of printf attribute matches inttypes macros\" >&5\nprintf %s \"checking which flavor of printf attribute matches inttypes macros... \" >&6; }\nif test ${gl_cv_func_printf_attribute_flavor+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n       #define __STDC_FORMAT_MACROS 1\n       #include <stdio.h>\n       #include <inttypes.h>\n       /* For non-mingw systems, compilation will trivially succeed.\n          For mingw, compilation will succeed for older mingw (system\n          printf, \"I64d\") and fail for newer mingw (gnu printf, \"lld\"). */\n       #if (defined _WIN32 && ! defined __CYGWIN__) && \\\n         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))\n       extern char PRIdMAX_probe[sizeof PRIdMAX == sizeof \"I64d\" ? 1 : -1];\n       #endif\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_func_printf_attribute_flavor=system\nelse $as_nop\n  gl_cv_func_printf_attribute_flavor=gnu\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_attribute_flavor\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_printf_attribute_flavor\" >&6; }\n  if test \"$gl_cv_func_printf_attribute_flavor\" = gnu; then\n\nprintf \"%s\\n\" \"#define GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU 1\" >>confdefs.h\n\n  fi\n\n\n\n\n\n\n\n\n\n\n\n\n\n  if test $ac_cv_have_decl_fcloseall = no; then\n    HAVE_DECL_FCLOSEALL=0\n  fi\n\nac_fn_check_decl \"$LINENO\" \"ecvt\" \"ac_cv_have_decl_ecvt\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_ecvt\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_ECVT $ac_have_decl\" >>confdefs.h\n\nac_fn_check_decl \"$LINENO\" \"fcvt\" \"ac_cv_have_decl_fcvt\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_fcvt\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_FCVT $ac_have_decl\" >>confdefs.h\n\nac_fn_check_decl \"$LINENO\" \"gcvt\" \"ac_cv_have_decl_gcvt\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_gcvt\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_GCVT $ac_have_decl\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_stdlib_h='<'stdlib.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <stdlib.h>\" >&5\nprintf %s \"checking absolute name of <stdlib.h>... \" >&6; }\nif test ${gl_cv_next_stdlib_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdlib.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'stdlib.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_stdlib_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_stdlib_h\n           gl_cv_next_stdlib_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdlib_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_stdlib_h\" >&6; }\n     fi\n     NEXT_STDLIB_H=$gl_cv_next_stdlib_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'stdlib.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_stdlib_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_STDLIB_H=$gl_next_as_first_directive\n\n\n\n\n\n\n\n\n\n\n\n\n  if test $ac_cv_have_decl_ecvt = no; then\n    HAVE_DECL_ECVT=0\n  fi\n\n  if test $ac_cv_have_decl_fcvt = no; then\n    HAVE_DECL_FCVT=0\n  fi\n\n  if test $ac_cv_have_decl_gcvt = no; then\n    HAVE_DECL_GCVT=0\n  fi\n\n\n    HAVE_GETRUSAGE=1;\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_resource_h='<'sys/resource.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/resource.h>\" >&5\nprintf %s \"checking absolute name of <sys/resource.h>... \" >&6; }\nif test ${gl_cv_next_sys_resource_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_resource_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/resource.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/resource.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_resource_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_resource_h\n           gl_cv_next_sys_resource_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_resource_h='<'sys/resource.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_resource_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_resource_h\" >&6; }\n     fi\n     NEXT_SYS_RESOURCE_H=$gl_cv_next_sys_resource_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/resource.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_resource_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_sys_resource_h = yes; then\n    HAVE_SYS_RESOURCE_H=1\n  else\n    HAVE_SYS_RESOURCE_H=0\n  fi\n\n\n\n\n\n\n\n\n  GL_GNULIB_GETRUSAGE=0\n\n\n\n\n  HAVE_STRUCT_SOCKADDR_STORAGE=1;\n  HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=1;\n\n  HAVE_SA_FAMILY_T=1;\n  HAVE_ACCEPT4=1;\n\n\n\n\n\n        case \"$host_os\" in\n    osf*)\n\nprintf \"%s\\n\" \"#define _POSIX_PII_SOCKET 1\" >>confdefs.h\n\n      ;;\n  esac\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether <sys/socket.h> is self-contained\" >&5\nprintf %s \"checking whether <sys/socket.h> is self-contained... \" >&6; }\nif test ${gl_cv_header_sys_socket_h_selfcontained+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/socket.h>\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_sys_socket_h_selfcontained=yes\nelse $as_nop\n  gl_cv_header_sys_socket_h_selfcontained=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_sys_socket_h_selfcontained\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_sys_socket_h_selfcontained\" >&6; }\n  if test $gl_cv_header_sys_socket_h_selfcontained = yes; then\n            ac_fn_c_check_func \"$LINENO\" \"shutdown\" \"ac_cv_func_shutdown\"\nif test \"x$ac_cv_func_shutdown\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_SHUTDOWN 1\" >>confdefs.h\n\nfi\n\n    if test $ac_cv_func_shutdown = yes; then\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether <sys/socket.h> defines the SHUT_* macros\" >&5\nprintf %s \"checking whether <sys/socket.h> defines the SHUT_* macros... \" >&6; }\nif test ${gl_cv_header_sys_socket_h_shut+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n          cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/socket.h>\nint\nmain (void)\n{\nint a[] = { SHUT_RD, SHUT_WR, SHUT_RDWR };\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_sys_socket_h_shut=yes\nelse $as_nop\n  gl_cv_header_sys_socket_h_shut=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_sys_socket_h_shut\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_sys_socket_h_shut\" >&6; }\n      if test $gl_cv_header_sys_socket_h_shut = no; then\n        SYS_SOCKET_H='sys/socket.h'\n      fi\n    fi\n  fi\n  # We need to check for ws2tcpip.h now.\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_socket_h='<'sys/socket.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/socket.h>\" >&5\nprintf %s \"checking absolute name of <sys/socket.h>... \" >&6; }\nif test ${gl_cv_next_sys_socket_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_socket_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/socket.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/socket.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_socket_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_socket_h\n           gl_cv_next_sys_socket_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_socket_h='<'sys/socket.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_socket_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_socket_h\" >&6; }\n     fi\n     NEXT_SYS_SOCKET_H=$gl_cv_next_sys_socket_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/socket.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_socket_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_sys_socket_h = yes; then\n    HAVE_SYS_SOCKET_H=1\n  else\n    HAVE_SYS_SOCKET_H=0\n  fi\n\n\n\n  if test $ac_cv_header_sys_socket_h = yes; then\n    HAVE_WS2TCPIP_H=0\n  else\n    if test $ac_cv_header_ws2tcpip_h = yes; then\n      HAVE_WS2TCPIP_H=1\n    else\n      HAVE_WS2TCPIP_H=0\n    fi\n  fi\n\n\n\n  ac_fn_c_check_type \"$LINENO\" \"struct sockaddr_storage\" \"ac_cv_type_struct_sockaddr_storage\" \"\n  /* sys/types.h is not needed according to POSIX, but the\n     sys/socket.h in i386-unknown-freebsd4.10 and\n     powerpc-apple-darwin5.5 required it. */\n#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_WS2TCPIP_H\n#include <ws2tcpip.h>\n#endif\n\n\"\nif test \"x$ac_cv_type_struct_sockaddr_storage\" = xyes\nthen :\n\nprintf \"%s\\n\" \"#define HAVE_STRUCT_SOCKADDR_STORAGE 1\" >>confdefs.h\n\n\nfi\nac_fn_c_check_type \"$LINENO\" \"sa_family_t\" \"ac_cv_type_sa_family_t\" \"\n  /* sys/types.h is not needed according to POSIX, but the\n     sys/socket.h in i386-unknown-freebsd4.10 and\n     powerpc-apple-darwin5.5 required it. */\n#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_WS2TCPIP_H\n#include <ws2tcpip.h>\n#endif\n\n\"\nif test \"x$ac_cv_type_sa_family_t\" = xyes\nthen :\n\nprintf \"%s\\n\" \"#define HAVE_SA_FAMILY_T 1\" >>confdefs.h\n\n\nfi\n\n  if test $ac_cv_type_struct_sockaddr_storage = no; then\n    HAVE_STRUCT_SOCKADDR_STORAGE=0\n  fi\n  if test $ac_cv_type_sa_family_t = no; then\n    HAVE_SA_FAMILY_T=0\n  fi\n  if test $ac_cv_type_struct_sockaddr_storage != no; then\n    ac_fn_c_check_member \"$LINENO\" \"struct sockaddr_storage\" \"ss_family\" \"ac_cv_member_struct_sockaddr_storage_ss_family\" \"#include <sys/types.h>\n       #ifdef HAVE_SYS_SOCKET_H\n       #include <sys/socket.h>\n       #endif\n       #ifdef HAVE_WS2TCPIP_H\n       #include <ws2tcpip.h>\n       #endif\n\n\"\nif test \"x$ac_cv_member_struct_sockaddr_storage_ss_family\" = xyes\nthen :\n\nprintf \"%s\\n\" \"#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1\" >>confdefs.h\n\n\nelse $as_nop\n  HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=0\nfi\n\n  fi\n  if test $HAVE_STRUCT_SOCKADDR_STORAGE = 0 || test $HAVE_SA_FAMILY_T = 0 \\\n     || test $HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = 0; then\n    SYS_SOCKET_H='sys/socket.h'\n  fi\n\n\n\n\n  if test $ac_cv_header_sys_socket_h != yes; then\n                    ac_fn_c_check_header_compile \"$LINENO\" \"winsock2.h\" \"ac_cv_header_winsock2_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_winsock2_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_WINSOCK2_H 1\" >>confdefs.h\n\nfi\n\n  fi\n  if test \"$ac_cv_header_winsock2_h\" = yes; then\n    HAVE_WINSOCK2_H=1\n    UNISTD_H_HAVE_WINSOCK2_H=1\n    SYS_IOCTL_H_HAVE_WINSOCK2_H=1\n  else\n    HAVE_WINSOCK2_H=0\n  fi\n\n\n\n\n\n\n\n\n\n\n\n  GL_GNULIB_SOCKET=0\n\n\n\n  GL_GNULIB_CONNECT=0\n\n\n\n  GL_GNULIB_ACCEPT=0\n\n\n\n  GL_GNULIB_BIND=0\n\n\n\n  GL_GNULIB_GETPEERNAME=0\n\n\n\n  GL_GNULIB_GETSOCKNAME=0\n\n\n\n  GL_GNULIB_GETSOCKOPT=0\n\n\n\n  GL_GNULIB_LISTEN=0\n\n\n\n  GL_GNULIB_RECV=0\n\n\n\n  GL_GNULIB_SEND=0\n\n\n\n  GL_GNULIB_RECVFROM=0\n\n\n\n  GL_GNULIB_SENDTO=0\n\n\n\n  GL_GNULIB_SETSOCKOPT=0\n\n\n\n  GL_GNULIB_SHUTDOWN=0\n\n\n\n  GL_GNULIB_ACCEPT4=0\n\n\n\n\n    HAVE_FCHMODAT=1;\n  HAVE_FSTATAT=1;\n  HAVE_FUTIMENS=1;\n  HAVE_GETUMASK=1;\n  HAVE_LCHMOD=1;\n  HAVE_LSTAT=1;\n  HAVE_MKDIRAT=1;\n  HAVE_MKFIFO=1;\n  HAVE_MKFIFOAT=1;\n  HAVE_MKNOD=1;\n  HAVE_MKNODAT=1;\n  HAVE_UTIMENSAT=1;\n  REPLACE_FCHMODAT=0;\n  REPLACE_FSTAT=0;\n  REPLACE_FSTATAT=0;\n  REPLACE_FUTIMENS=0;\n  REPLACE_LSTAT=0;\n  REPLACE_MKDIR=0;\n  REPLACE_MKFIFO=0;\n  REPLACE_MKFIFOAT=0;\n  REPLACE_MKNOD=0;\n  REPLACE_MKNODAT=0;\n  REPLACE_STAT=0;\n  REPLACE_UTIMENSAT=0;\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken\" >&5\nprintf %s \"checking whether stat file-mode macros are broken... \" >&6; }\nif test ${ac_cv_header_stat_broken+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/types.h>\n#include <sys/stat.h>\n\n#if defined S_ISBLK && defined S_IFDIR\nextern char c1[S_ISBLK (S_IFDIR) ? -1 : 1];\n#endif\n\n#if defined S_ISBLK && defined S_IFCHR\nextern char c2[S_ISBLK (S_IFCHR) ? -1 : 1];\n#endif\n\n#if defined S_ISLNK && defined S_IFREG\nextern char c3[S_ISLNK (S_IFREG) ? -1 : 1];\n#endif\n\n#if defined S_ISSOCK && defined S_IFREG\nextern char c4[S_ISSOCK (S_IFREG) ? -1 : 1];\n#endif\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_cv_header_stat_broken=no\nelse $as_nop\n  ac_cv_header_stat_broken=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken\" >&5\nprintf \"%s\\n\" \"$ac_cv_header_stat_broken\" >&6; }\nif test $ac_cv_header_stat_broken = yes; then\n\nprintf \"%s\\n\" \"#define STAT_MACROS_BROKEN 1\" >>confdefs.h\n\nfi\n\nac_fn_c_check_type \"$LINENO\" \"mode_t\" \"ac_cv_type_mode_t\" \"$ac_includes_default\"\nif test \"x$ac_cv_type_mode_t\" = xyes\nthen :\n\nelse $as_nop\n\nprintf \"%s\\n\" \"#define mode_t int\" >>confdefs.h\n\nfi\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_stat_h='<'sys/stat.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/stat.h>\" >&5\nprintf %s \"checking absolute name of <sys/stat.h>... \" >&6; }\nif test ${gl_cv_next_sys_stat_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_stat_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/stat.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/stat.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_stat_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_stat_h\n           gl_cv_next_sys_stat_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_stat_h='<'sys/stat.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_stat_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_stat_h\" >&6; }\n     fi\n     NEXT_SYS_STAT_H=$gl_cv_next_sys_stat_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/stat.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_stat_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H=$gl_next_as_first_directive\n\n\n\n\n\n\n\n\n    WINDOWS_STAT_TIMESPEC=0\n\n\n\n\n    WINDOWS_64_BIT_ST_SIZE=0\n\n\n\n      ac_fn_c_check_type \"$LINENO\" \"nlink_t\" \"ac_cv_type_nlink_t\" \"#include <sys/types.h>\n     #include <sys/stat.h>\n\"\nif test \"x$ac_cv_type_nlink_t\" = xyes\nthen :\n\nelse $as_nop\n\nprintf \"%s\\n\" \"#define nlink_t int\" >>confdefs.h\n\nfi\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  GL_GNULIB_FCHMODAT=0\n\n\n\n  GL_GNULIB_FSTAT=0\n\n\n\n  GL_GNULIB_FSTATAT=0\n\n\n\n  GL_GNULIB_FUTIMENS=0\n\n\n\n  GL_GNULIB_GETUMASK=0\n\n\n\n  GL_GNULIB_LCHMOD=0\n\n\n\n  GL_GNULIB_LSTAT=0\n\n\n\n  GL_GNULIB_MKDIR=0\n\n\n\n  GL_GNULIB_MKDIRAT=0\n\n\n\n  GL_GNULIB_MKFIFO=0\n\n\n\n  GL_GNULIB_MKFIFOAT=0\n\n\n\n  GL_GNULIB_MKNOD=0\n\n\n\n  GL_GNULIB_MKNODAT=0\n\n\n\n  GL_GNULIB_STAT=0\n\n\n\n  GL_GNULIB_UTIMENSAT=0\n\n\n\n  GL_GNULIB_OVERRIDES_STRUCT_STAT=0\n\n\n\n  GL_GNULIB_MDA_CHMOD=1\n\n\n\n  GL_GNULIB_MDA_MKDIR=1\n\n\n\n  GL_GNULIB_MDA_UMASK=1\n\n\n\n\n\n\n  ac_fn_c_check_type \"$LINENO\" \"pid_t\" \"ac_cv_type_pid_t\" \"$ac_includes_default\n\"\nif test \"x$ac_cv_type_pid_t\" = xyes\nthen :\n\nelse $as_nop\n                                          cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n          #if defined _WIN64 && !defined __CYGWIN__\n          LLP64\n          #endif\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  ac_pid_type='int'\nelse $as_nop\n  ac_pid_type='__int64'\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nprintf \"%s\\n\" \"#define pid_t $ac_pid_type\" >>confdefs.h\n\n\nfi\n\n\n\n\n    WINDOWS_64_BIT_OFF_T=0\n\n\n\n\n\n\n\nprintf \"%s\\n\" \"#define _USE_STD_STAT 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_types_h='<'sys/types.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/types.h>\" >&5\nprintf %s \"checking absolute name of <sys/types.h>... \" >&6; }\nif test ${gl_cv_next_sys_types_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/types.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/types.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_types_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_types_h\n           gl_cv_next_sys_types_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_types_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_types_h\" >&6; }\n     fi\n     NEXT_SYS_TYPES_H=$gl_cv_next_sys_types_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/types.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_types_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H=$gl_next_as_first_directive\n\n\n\n\n\n\n\n\n\n\n\n\n    WINDOWS_STAT_INODES=0\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_uio_h='<'sys/uio.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/uio.h>\" >&5\nprintf %s \"checking absolute name of <sys/uio.h>... \" >&6; }\nif test ${gl_cv_next_sys_uio_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_uio_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/uio.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/uio.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_uio_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_uio_h\n           gl_cv_next_sys_uio_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_uio_h='<'sys/uio.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_uio_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_uio_h\" >&6; }\n     fi\n     NEXT_SYS_UIO_H=$gl_cv_next_sys_uio_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/uio.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_uio_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_sys_uio_h = yes; then\n    HAVE_SYS_UIO_H=1\n  else\n    HAVE_SYS_UIO_H=0\n  fi\n\n\n\n\n\n    HAVE_UNAME=1;\n  HAVE_STRUCT_UTSNAME=1;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_sys_utsname_h='<'sys/utsname.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <sys/utsname.h>\" >&5\nprintf %s \"checking absolute name of <sys/utsname.h>... \" >&6; }\nif test ${gl_cv_next_sys_utsname_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_sys_utsname_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/utsname.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'sys/utsname.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_sys_utsname_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_sys_utsname_h\n           gl_cv_next_sys_utsname_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_sys_utsname_h='<'sys/utsname.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_utsname_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_sys_utsname_h\" >&6; }\n     fi\n     NEXT_SYS_UTSNAME_H=$gl_cv_next_sys_utsname_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'sys/utsname.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_sys_utsname_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_sys_utsname_h != yes; then\n    HAVE_SYS_UTSNAME_H=0\n    HAVE_STRUCT_UTSNAME=0\n  else\n    HAVE_SYS_UTSNAME_H=1\n    ac_fn_c_check_type \"$LINENO\" \"struct utsname\" \"ac_cv_type_struct_utsname\" \"\n/* Minix 3.1.8 has a bug: <stddef.h> must be included before\n   <sys/utsname.h>.  */\n#include <stddef.h>\n#include <sys/utsname.h>\n\n\"\nif test \"x$ac_cv_type_struct_utsname\" = xyes\nthen :\n\nprintf \"%s\\n\" \"#define HAVE_STRUCT_UTSNAME 1\" >>confdefs.h\n\n\nelse $as_nop\n  HAVE_STRUCT_UTSNAME=0\nfi\n\n  fi\n\n\n\n\n\n\n\n\n  GL_GNULIB_UNAME=0\n\n\n\n\n    HAVE_DECL_LOCALTIME_R=1;\n  HAVE_NANOSLEEP=1;\n  HAVE_STRPTIME=1;\n  HAVE_TIMEGM=1;\n  HAVE_TIMESPEC_GET=1;\n    HAVE_TIMEZONE_T=0;\n        REPLACE_CTIME=GNULIB_PORTCHECK;\n  REPLACE_LOCALTIME_R=GNULIB_PORTCHECK;\n  REPLACE_MKTIME=GNULIB_PORTCHECK;\n  REPLACE_NANOSLEEP=GNULIB_PORTCHECK;\n  REPLACE_STRFTIME=GNULIB_PORTCHECK;\n  REPLACE_TIMEGM=GNULIB_PORTCHECK;\n  REPLACE_TZSET=GNULIB_PORTCHECK;\n\n      : ${GNULIB_GETTIMEOFDAY=0};\n        REPLACE_GMTIME=0;\n  REPLACE_LOCALTIME=0;\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for struct timespec in <time.h>\" >&5\nprintf %s \"checking for struct timespec in <time.h>... \" >&6; }\nif test ${gl_cv_sys_struct_timespec_in_time_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <time.h>\n\nint\nmain (void)\n{\nstatic struct timespec x; x.tv_sec = x.tv_nsec;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timespec_in_time_h=yes\nelse $as_nop\n  gl_cv_sys_struct_timespec_in_time_h=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_time_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timespec_in_time_h\" >&6; }\n\n  TIME_H_DEFINES_STRUCT_TIMESPEC=0\n  SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0\n  PTHREAD_H_DEFINES_STRUCT_TIMESPEC=0\n  UNISTD_H_DEFINES_STRUCT_TIMESPEC=0\n  if test $gl_cv_sys_struct_timespec_in_time_h = yes; then\n    TIME_H_DEFINES_STRUCT_TIMESPEC=1\n  else\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for struct timespec in <sys/time.h>\" >&5\nprintf %s \"checking for struct timespec in <sys/time.h>... \" >&6; }\nif test ${gl_cv_sys_struct_timespec_in_sys_time_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/time.h>\n\nint\nmain (void)\n{\nstatic struct timespec x; x.tv_sec = x.tv_nsec;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timespec_in_sys_time_h=yes\nelse $as_nop\n  gl_cv_sys_struct_timespec_in_sys_time_h=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_sys_time_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timespec_in_sys_time_h\" >&6; }\n    if test $gl_cv_sys_struct_timespec_in_sys_time_h = yes; then\n      SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1\n    else\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for struct timespec in <pthread.h>\" >&5\nprintf %s \"checking for struct timespec in <pthread.h>... \" >&6; }\nif test ${gl_cv_sys_struct_timespec_in_pthread_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <pthread.h>\n\nint\nmain (void)\n{\nstatic struct timespec x; x.tv_sec = x.tv_nsec;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timespec_in_pthread_h=yes\nelse $as_nop\n  gl_cv_sys_struct_timespec_in_pthread_h=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_pthread_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timespec_in_pthread_h\" >&6; }\n      if test $gl_cv_sys_struct_timespec_in_pthread_h = yes; then\n        PTHREAD_H_DEFINES_STRUCT_TIMESPEC=1\n      else\n        { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for struct timespec in <unistd.h>\" >&5\nprintf %s \"checking for struct timespec in <unistd.h>... \" >&6; }\nif test ${gl_cv_sys_struct_timespec_in_unistd_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <unistd.h>\n\nint\nmain (void)\n{\nstatic struct timespec x; x.tv_sec = x.tv_nsec;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_sys_struct_timespec_in_unistd_h=yes\nelse $as_nop\n  gl_cv_sys_struct_timespec_in_unistd_h=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_unistd_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_sys_struct_timespec_in_unistd_h\" >&6; }\n        if test $gl_cv_sys_struct_timespec_in_unistd_h = yes; then\n          UNISTD_H_DEFINES_STRUCT_TIMESPEC=1\n        fi\n      fi\n    fi\n  fi\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_time_h='<'time.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <time.h>\" >&5\nprintf %s \"checking absolute name of <time.h>... \" >&6; }\nif test ${gl_cv_next_time_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <time.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'time.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_time_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_time_h\n           gl_cv_next_time_h='\"'$gl_header'\"'\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_time_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_time_h\" >&6; }\n     fi\n     NEXT_TIME_H=$gl_cv_next_time_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'time.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_time_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_TIME_H=$gl_next_as_first_directive\n\n\n\n\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for TIME_UTC in <time.h>\" >&5\nprintf %s \"checking for TIME_UTC in <time.h>... \" >&6; }\nif test ${gl_cv_time_h_has_TIME_UTC+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <time.h>\n\nint\nmain (void)\n{\nstatic int x = TIME_UTC; x++;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_time_h_has_TIME_UTC=yes\nelse $as_nop\n  gl_cv_time_h_has_TIME_UTC=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_time_h_has_TIME_UTC\" >&5\nprintf \"%s\\n\" \"$gl_cv_time_h_has_TIME_UTC\" >&6; }\n  if test $gl_cv_time_h_has_TIME_UTC = yes; then\n    TIME_H_DEFINES_TIME_UTC=1\n  else\n    TIME_H_DEFINES_TIME_UTC=0\n  fi\n\n\n\n\n  GL_GNULIB_CTIME=0\n\n\n\n  GL_GNULIB_MKTIME=0\n\n\n\n  GL_GNULIB_LOCALTIME=0\n\n\n\n  GL_GNULIB_NANOSLEEP=0\n\n\n\n  GL_GNULIB_STRFTIME=0\n\n\n\n  GL_GNULIB_STRPTIME=0\n\n\n\n  GL_GNULIB_TIMEGM=0\n\n\n\n  GL_GNULIB_TIMESPEC_GET=0\n\n\n\n  GL_GNULIB_TIME_R=0\n\n\n\n  GL_GNULIB_TIME_RZ=0\n\n\n\n  GL_GNULIB_TZSET=0\n\n\n\n  GL_GNULIB_MDA_TZSET=1\n\n\n\n\nac_fn_check_decl \"$LINENO\" \"execvpe\" \"ac_cv_have_decl_execvpe\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_execvpe\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_EXECVPE $ac_have_decl\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n\n     if test $gl_cv_have_include_next = yes; then\n       gl_cv_next_unistd_h='<'unistd.h'>'\n     else\n       { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking absolute name of <unistd.h>\" >&5\nprintf %s \"checking absolute name of <unistd.h>... \" >&6; }\nif test ${gl_cv_next_unistd_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n             if test $ac_cv_header_unistd_h = yes; then\n\n\n\n\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <unistd.h>\n_ACEOF\n                case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\n\n  case \"$host_os\" in\n    mingw*)\n                                          gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n      gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo 'unistd.h' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\n\n        gl_cv_absolute_unistd_h=`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&5 |\n  sed -n \"$gl_absolute_header_sed\"`\n\n           gl_header=$gl_cv_absolute_unistd_h\n           gl_cv_next_unistd_h='\"'$gl_header'\"'\n          else\n               gl_cv_next_unistd_h='<'unistd.h'>'\n             fi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_unistd_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_next_unistd_h\" >&6; }\n     fi\n     NEXT_UNISTD_H=$gl_cv_next_unistd_h\n\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'unistd.h'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=$gl_cv_next_unistd_h\n     fi\n     NEXT_AS_FIRST_DIRECTIVE_UNISTD_H=$gl_next_as_first_directive\n\n\n\n\n  if test $ac_cv_header_unistd_h = yes; then\n    HAVE_UNISTD_H=1\n  else\n    HAVE_UNISTD_H=0\n  fi\n\n\n\n\n\n\n\n\n\n\n\n\n\n  if test $ac_cv_have_decl_execvpe = no; then\n    HAVE_DECL_EXECVPE=0\n  fi\n\n\ngl_m4_base='glm4'\n\n\n\n\n\n\n\n\n\n\n\n\ngl_source_base='gllib'\n\n\n\n\n  LIB_EXECINFO=''\n  EXECINFO_H='execinfo.h'\n\n  if test $ac_cv_header_execinfo_h = yes; then\n    gl_saved_libs=$LIBS\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for library containing backtrace_symbols_fd\" >&5\nprintf %s \"checking for library containing backtrace_symbols_fd... \" >&6; }\nif test ${ac_cv_search_backtrace_symbols_fd+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  ac_func_search_save_LIBS=$LIBS\ncat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n/* Override any GCC internal prototype to avoid an error.\n   Use char because int might match the return type of a GCC\n   builtin and then its argument prototype would still apply.  */\nchar backtrace_symbols_fd ();\nint\nmain (void)\n{\nreturn backtrace_symbols_fd ();\n  ;\n  return 0;\n}\n_ACEOF\nfor ac_lib in '' execinfo\ndo\n  if test -z \"$ac_lib\"; then\n    ac_res=\"none required\"\n  else\n    ac_res=-l$ac_lib\n    LIBS=\"-l$ac_lib  $ac_func_search_save_LIBS\"\n  fi\n  if ac_fn_c_try_link \"$LINENO\"\nthen :\n  ac_cv_search_backtrace_symbols_fd=$ac_res\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext\n  if test ${ac_cv_search_backtrace_symbols_fd+y}\nthen :\n  break\nfi\ndone\nif test ${ac_cv_search_backtrace_symbols_fd+y}\nthen :\n\nelse $as_nop\n  ac_cv_search_backtrace_symbols_fd=no\nfi\nrm conftest.$ac_ext\nLIBS=$ac_func_search_save_LIBS\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace_symbols_fd\" >&5\nprintf \"%s\\n\" \"$ac_cv_search_backtrace_symbols_fd\" >&6; }\nac_res=$ac_cv_search_backtrace_symbols_fd\nif test \"$ac_res\" != no\nthen :\n  test \"$ac_res\" = \"none required\" || LIBS=\"$ac_res $LIBS\"\n  test \"$ac_cv_search_backtrace_symbols_fd\" = \"none required\" ||\n         LIB_EXECINFO=$ac_cv_search_backtrace_symbols_fd\nfi\n\n    LIBS=$gl_saved_libs\n    test \"$ac_cv_search_backtrace_symbols_fd\" = no || EXECINFO_H=''\n  fi\n\n  if test -n \"$EXECINFO_H\"; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS execinfo.$ac_objext\"\n\n  fi\n\n\n\n   if test -n \"$EXECINFO_H\"; then\n  GL_GENERATE_EXECINFO_H_TRUE=\n  GL_GENERATE_EXECINFO_H_FALSE='#'\nelse\n  GL_GENERATE_EXECINFO_H_TRUE='#'\n  GL_GENERATE_EXECINFO_H_FALSE=\nfi\n\n\n\n\n\n\n\n\n\n\n\n  if test $ac_cv_func_getdelim = yes; then\n    HAVE_GETDELIM=1\n        { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for working getdelim function\" >&5\nprintf %s \"checking for working getdelim function... \" >&6; }\nif test ${gl_cv_func_working_getdelim+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  echo fooNbarN | tr -d '\\012' | tr N '\\012' > conftest.data\n       if test \"$cross_compiling\" = yes\nthen :\n                      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <features.h>\n#ifdef __GNU_LIBRARY__\n #if (__GLIBC__ >= 2) && !defined __UCLIBC__\n  Lucky GNU user\n #endif\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"Lucky GNU user\" >/dev/null 2>&1\nthen :\n  gl_cv_func_working_getdelim=\"guessing yes\"\nelse $as_nop\n  case \"$host_os\" in\n               *-musl*) gl_cv_func_working_getdelim=\"guessing yes\" ;;\n               *)       gl_cv_func_working_getdelim=\"$gl_cross_guess_normal\" ;;\n             esac\n\nfi\nrm -rf conftest*\n\n\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#    include <stdio.h>\n#    include <stdlib.h>\n#    include <string.h>\n    int main ()\n    {\n      FILE *in = fopen (\"./conftest.data\", \"r\");\n      if (!in)\n        return 1;\n      {\n        /* Test result for a NULL buffer and a zero size.\n           Based on a test program from Karl Heuer.  */\n        char *line = NULL;\n        size_t siz = 0;\n        int len = getdelim (&line, &siz, '\\n', in);\n        if (!(len == 4 && line && strcmp (line, \"foo\\n\") == 0))\n          { free (line); fclose (in); return 2; }\n        free (line);\n      }\n      {\n        /* Test result for a NULL buffer and a non-zero size.\n           This crashes on FreeBSD 8.0.  */\n        char *line = NULL;\n        size_t siz = (size_t)(~0) / 4;\n        if (getdelim (&line, &siz, '\\n', in) == -1)\n          { fclose (in); return 3; }\n        free (line);\n      }\n      fclose (in);\n      return 0;\n    }\n\n_ACEOF\nif ac_fn_c_try_run \"$LINENO\"\nthen :\n  gl_cv_func_working_getdelim=yes\nelse $as_nop\n  gl_cv_func_working_getdelim=no\nfi\nrm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \\\n  conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_working_getdelim\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_working_getdelim\" >&6; }\n    case \"$gl_cv_func_working_getdelim\" in\n      *yes) ;;\n      *) REPLACE_GETDELIM=1 ;;\n    esac\n  else\n    HAVE_GETDELIM=0\n  fi\n\n  if test $ac_cv_have_decl_getdelim = no; then\n    HAVE_DECL_GETDELIM=0\n  fi\n\n  if test $HAVE_GETDELIM = 0 || test $REPLACE_GETDELIM = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS getdelim.$ac_objext\"\n\n\n  ac_fn_c_check_func \"$LINENO\" \"flockfile\" \"ac_cv_func_flockfile\"\nif test \"x$ac_cv_func_flockfile\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_FLOCKFILE 1\" >>confdefs.h\n\nfi\nac_fn_c_check_func \"$LINENO\" \"funlockfile\" \"ac_cv_func_funlockfile\"\nif test \"x$ac_cv_func_funlockfile\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_FUNLOCKFILE 1\" >>confdefs.h\n\nfi\n\n  ac_fn_check_decl \"$LINENO\" \"getc_unlocked\" \"ac_cv_have_decl_getc_unlocked\" \"$ac_includes_default\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_getc_unlocked\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl\" >>confdefs.h\n\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETDELIM=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETDELIM 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n  if test $ac_cv_header_sys_socket_h != yes; then\n                    ac_fn_c_check_header_compile \"$LINENO\" \"winsock2.h\" \"ac_cv_header_winsock2_h\" \"$ac_includes_default\"\nif test \"x$ac_cv_header_winsock2_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_WINSOCK2_H 1\" >>confdefs.h\n\nfi\n\n  fi\n  if test \"$ac_cv_header_winsock2_h\" = yes; then\n    HAVE_WINSOCK2_H=1\n    UNISTD_H_HAVE_WINSOCK2_H=1\n    SYS_IOCTL_H_HAVE_WINSOCK2_H=1\n  else\n    HAVE_WINSOCK2_H=0\n  fi\n\n\n\n        GETHOSTNAME_LIB=\n\n  for ac_func in gethostname\ndo :\n  ac_fn_c_check_func \"$LINENO\" \"gethostname\" \"ac_cv_func_gethostname\"\nif test \"x$ac_cv_func_gethostname\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_GETHOSTNAME 1\" >>confdefs.h\n\nelse $as_nop\n\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for gethostname in winsock2.h and -lws2_32\" >&5\nprintf %s \"checking for gethostname in winsock2.h and -lws2_32... \" >&6; }\nif test ${gl_cv_w32_gethostname+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  gl_cv_w32_gethostname=no\n       gl_save_LIBS=\"$LIBS\"\n       LIBS=\"$LIBS -lws2_32\"\n       cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#ifdef HAVE_WINSOCK2_H\n#include <winsock2.h>\n#endif\n#include <stddef.h>\n\nint\nmain (void)\n{\ngethostname(NULL, 0);\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_w32_gethostname=yes\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n       LIBS=\"$gl_save_LIBS\"\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_w32_gethostname\" >&5\nprintf \"%s\\n\" \"$gl_cv_w32_gethostname\" >&6; }\n    if test \"$gl_cv_w32_gethostname\" = \"yes\"; then\n      GETHOSTNAME_LIB=\"-lws2_32\"\n    fi\n\nfi\n\ndone\n\n\n  if test \"$ac_cv_func_gethostname\" = no; then\n    HAVE_GETHOSTNAME=0\n  fi\n\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for HOST_NAME_MAX\" >&5\nprintf %s \"checking for HOST_NAME_MAX... \" >&6; }\nif test ${gl_cv_decl_HOST_NAME_MAX+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n\n    gl_cv_decl_HOST_NAME_MAX=\n    cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <limits.h>\n#ifdef HOST_NAME_MAX\nlucky\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"lucky\" >/dev/null 2>&1\nthen :\n  gl_cv_decl_HOST_NAME_MAX=yes\nfi\nrm -rf conftest*\n\n    if test -z \"$gl_cv_decl_HOST_NAME_MAX\"; then\n            if test \"$gl_cv_w32_gethostname\" = yes; then\n                gl_cv_decl_HOST_NAME_MAX=256\n      else\n        if ac_fn_c_compute_int \"$LINENO\" \"MAXHOSTNAMELEN\" \"gl_cv_decl_HOST_NAME_MAX\"        \"\n#include <sys/types.h>\n#if HAVE_SYS_PARAM_H\n# include <sys/param.h>\n#endif\n#if HAVE_SYS_SOCKET_H\n# include <sys/socket.h>\n#endif\n#if HAVE_NETDB_H\n# include <netdb.h>\n#endif\n\"\nthen :\n\nelse $as_nop\n                        gl_cv_decl_HOST_NAME_MAX=256\n\nfi\n\n      fi\n    fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_HOST_NAME_MAX\" >&5\nprintf \"%s\\n\" \"$gl_cv_decl_HOST_NAME_MAX\" >&6; }\n  if test \"$gl_cv_decl_HOST_NAME_MAX\" != yes; then\n\nprintf \"%s\\n\" \"#define HOST_NAME_MAX $gl_cv_decl_HOST_NAME_MAX\" >>confdefs.h\n\n  fi\n\n\n  if test $HAVE_GETHOSTNAME = 0; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS gethostname.$ac_objext\"\n\n\n  if test \"$gl_cv_w32_gethostname\" != \"yes\"; then\n    ac_fn_c_check_func \"$LINENO\" \"uname\" \"ac_cv_func_uname\"\nif test \"x$ac_cv_func_uname\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_UNAME 1\" >>confdefs.h\n\nfi\n\n  fi\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETHOSTNAME=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETHOSTNAME 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n  gl_getline_needs_run_time_check=no\n  ac_fn_c_check_func \"$LINENO\" \"getline\" \"ac_cv_func_getline\"\nif test \"x$ac_cv_func_getline\" = xyes\nthen :\n                   gl_getline_needs_run_time_check=yes\nelse $as_nop\n  am_cv_func_working_getline=no\nfi\n\n  if test $gl_getline_needs_run_time_check = yes; then\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for working getline function\" >&5\nprintf %s \"checking for working getline function... \" >&6; }\nif test ${am_cv_func_working_getline+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  echo fooNbarN | tr -d '\\012' | tr N '\\012' > conftest.data\n       if test \"$cross_compiling\" = yes\nthen :\n                      cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#include <features.h>\n#ifdef __GNU_LIBRARY__\n #if (__GLIBC__ >= 2) && !defined __UCLIBC__\n  Lucky GNU user\n #endif\n#endif\n\n_ACEOF\nif (eval \"$ac_cpp conftest.$ac_ext\") 2>&5 |\n  $EGREP \"Lucky GNU user\" >/dev/null 2>&1\nthen :\n  am_cv_func_working_getline=\"guessing yes\"\nelse $as_nop\n  case \"$host_os\" in\n               *-musl*) am_cv_func_working_getline=\"guessing yes\" ;;\n               *)       am_cv_func_working_getline=\"$gl_cross_guess_normal\" ;;\n             esac\n\nfi\nrm -rf conftest*\n\n\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n\n#    include <stdio.h>\n#    include <stdlib.h>\n#    include <string.h>\n    int main ()\n    {\n      FILE *in = fopen (\"./conftest.data\", \"r\");\n      if (!in)\n        return 1;\n      {\n        /* Test result for a NULL buffer and a zero size.\n           Based on a test program from Karl Heuer.  */\n        char *line = NULL;\n        size_t siz = 0;\n        int len = getline (&line, &siz, in);\n        if (!(len == 4 && line && strcmp (line, \"foo\\n\") == 0))\n          { free (line); fclose (in); return 2; }\n        free (line);\n      }\n      {\n        /* Test result for a NULL buffer and a non-zero size.\n           This crashes on FreeBSD 8.0.  */\n        char *line = NULL;\n        size_t siz = (size_t)(~0) / 4;\n        if (getline (&line, &siz, in) == -1)\n          { fclose (in); return 3; }\n        free (line);\n      }\n      fclose (in);\n      return 0;\n    }\n\n_ACEOF\nif ac_fn_c_try_run \"$LINENO\"\nthen :\n  am_cv_func_working_getline=yes\nelse $as_nop\n  am_cv_func_working_getline=no\nfi\nrm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \\\n  conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $am_cv_func_working_getline\" >&5\nprintf \"%s\\n\" \"$am_cv_func_working_getline\" >&6; }\n  fi\n\n  if test $ac_cv_have_decl_getline = no; then\n    HAVE_DECL_GETLINE=0\n  fi\n\n  case \"$am_cv_func_working_getline\" in\n    *yes) ;;\n    *)\n                        REPLACE_GETLINE=1\n      ;;\n  esac\n\n  if test $REPLACE_GETLINE = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS getline.$ac_objext\"\n\n\n  :\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETLINE=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETLINE 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n  gl_gettimeofday_timezone=void\n  if test $ac_cv_func_gettimeofday != yes; then\n    HAVE_GETTIMEOFDAY=0\n  else\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for gettimeofday with POSIX signature\" >&5\nprintf %s \"checking for gettimeofday with POSIX signature... \" >&6; }\nif test ${gl_cv_func_gettimeofday_posix_signature+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/time.h>\n              struct timeval c;\n              int gettimeofday (struct timeval *restrict, void *restrict);\n\nint\nmain (void)\n{\n/* glibc uses struct timezone * rather than the POSIX void *\n                 if _GNU_SOURCE is defined.  However, since the only portable\n                 use of gettimeofday uses NULL as the second parameter, and\n                 since the glibc definition is actually more typesafe, it is\n                 not worth wrapping this to get a compliant signature.  */\n              int (*f) (struct timeval *restrict, void *restrict)\n                = gettimeofday;\n              int x = f (&c, 0);\n              return !(x | c.tv_sec | c.tv_usec);\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_func_gettimeofday_posix_signature=yes\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/time.h>\nint gettimeofday (struct timeval *restrict, struct timezone *restrict);\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_func_gettimeofday_posix_signature=almost\nelse $as_nop\n  gl_cv_func_gettimeofday_posix_signature=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_gettimeofday_posix_signature\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_gettimeofday_posix_signature\" >&6; }\n    if test $gl_cv_func_gettimeofday_posix_signature = almost; then\n      gl_gettimeofday_timezone='struct timezone'\n    elif test $gl_cv_func_gettimeofday_posix_signature != yes; then\n      REPLACE_GETTIMEOFDAY=1\n    fi\n        if test $REPLACE_STRUCT_TIMEVAL = 1; then\n      REPLACE_GETTIMEOFDAY=1\n    fi\n            case \"$host_os\" in\n      mingw*) REPLACE_GETTIMEOFDAY=1 ;;\n    esac\n  fi\n\nprintf \"%s\\n\" \"#define GETTIMEOFDAY_TIMEZONE $gl_gettimeofday_timezone\" >>confdefs.h\n\n\n  if test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS gettimeofday.$ac_objext\"\n\n    :\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETTIMEOFDAY=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETTIMEOFDAY 1\" >>confdefs.h\n\n\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the __inline keyword\" >&5\nprintf %s \"checking whether the compiler supports the __inline keyword... \" >&6; }\nif test ${gl_cv_c___inline+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\ntypedef int foo_t;\n           static __inline foo_t foo (void) { return 0; }\nint\nmain (void)\n{\nreturn foo ();\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_c___inline=yes\nelse $as_nop\n  gl_cv_c___inline=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_c___inline\" >&5\nprintf \"%s\\n\" \"$gl_cv_c___inline\" >&6; }\n  if test $gl_cv_c___inline = yes; then\n\nprintf \"%s\\n\" \"#define HAVE___INLINE 1\" >>confdefs.h\n\n  fi\n\n\n\n  if test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS msvc-inval.$ac_objext\"\n\n  fi\n\n  if test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS msvc-nothrow.$ac_objext\"\n\n  fi\n\n\nprintf \"%s\\n\" \"#define GNULIB_MSVC_NOTHROW 1\" >>confdefs.h\n\n\n\n\n\n\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for random\" >&5\nprintf %s \"checking for random... \" >&6; }\nif test ${gl_cv_func_random+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdlib.h>\nint\nmain (void)\n{\nreturn random() == 0;\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_func_random=yes\nelse $as_nop\n  gl_cv_func_random=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_random\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_random\" >&6; }\n  if test $gl_cv_func_random = no; then\n    HAVE_RANDOM=0\n    HAVE_INITSTATE=0\n    HAVE_SETSTATE=0\n  else\n    ac_fn_c_check_func \"$LINENO\" \"initstate\" \"ac_cv_func_initstate\"\nif test \"x$ac_cv_func_initstate\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_INITSTATE 1\" >>confdefs.h\n\nfi\nac_fn_c_check_func \"$LINENO\" \"setstate\" \"ac_cv_func_setstate\"\nif test \"x$ac_cv_func_setstate\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_SETSTATE 1\" >>confdefs.h\n\nfi\n\n    if test $ac_cv_func_initstate = no; then\n      HAVE_INITSTATE=0\n    fi\n    if test $ac_cv_func_setstate = no; then\n      HAVE_SETSTATE=0\n    fi\n    if test $ac_cv_func_initstate = no || test $ac_cv_func_setstate = no; then\n                  REPLACE_RANDOM=1\n      if test $ac_cv_func_initstate = yes; then\n        REPLACE_INITSTATE=1\n      fi\n      if test $ac_cv_func_setstate = yes; then\n        REPLACE_SETSTATE=1\n      fi\n    fi\n  fi\n\n\n  if test $ac_cv_have_decl_initstate = no; then\n    HAVE_DECL_INITSTATE=0\n  fi\n\n\n  if test $ac_cv_have_decl_setstate = no; then\n    HAVE_DECL_SETSTATE=0\n  fi\n\n  if test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS random.$ac_objext\"\n\n\n  :\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_RANDOM=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_RANDOM 1\" >>confdefs.h\n\n\n\n\n\n\n\n  ac_fn_c_check_header_compile \"$LINENO\" \"random.h\" \"ac_cv_header_random_h\" \"$ac_includes_default\n\"\nif test \"x$ac_cv_header_random_h\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_RANDOM_H 1\" >>confdefs.h\n\nfi\n\n  if test $ac_cv_header_random_h = no; then\n    HAVE_RANDOM_H=0\n  fi\n\n  ac_fn_c_check_type \"$LINENO\" \"struct random_data\" \"ac_cv_type_struct_random_data\" \"#include <stdlib.h>\n      #if HAVE_RANDOM_H\n      # include <random.h>\n      #endif\n\n\"\nif test \"x$ac_cv_type_struct_random_data\" = xyes\nthen :\n\nprintf \"%s\\n\" \"#define HAVE_STRUCT_RANDOM_DATA 1\" >>confdefs.h\n\n\nelse $as_nop\n  HAVE_STRUCT_RANDOM_DATA=0\nfi\n\n\n      case \"$host_os\" in\n    aix* | osf*)\n      REPLACE_RANDOM_R=1\n      ;;\n    *)\n      ac_fn_c_check_func \"$LINENO\" \"random_r\" \"ac_cv_func_random_r\"\nif test \"x$ac_cv_func_random_r\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_RANDOM_R 1\" >>confdefs.h\n\nfi\n\n      if test $ac_cv_func_random_r = no; then\n        HAVE_RANDOM_R=0\n      fi\n      ;;\n  esac\n\n  if test $HAVE_RANDOM_R = 0 || test $REPLACE_RANDOM_R = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS random_r.$ac_objext\"\n\n\n  :\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_RANDOM_R=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_RANDOM_R 1\" >>confdefs.h\n\n\n\n\n\n     ac_fn_c_check_type \"$LINENO\" \"socklen_t\" \"ac_cv_type_socklen_t\" \"\n/* <sys/types.h> is not needed according to POSIX, but the\n   <sys/socket.h> in i386-unknown-freebsd4.10 and\n   powerpc-apple-darwin5.5 required it. */\n#include <sys/types.h>\n#if HAVE_SYS_SOCKET_H\n# include <sys/socket.h>\n#elif HAVE_WS2TCPIP_H\n# include <ws2tcpip.h>\n#endif\n\n\"\nif test \"x$ac_cv_type_socklen_t\" = xyes\nthen :\n\nelse $as_nop\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent\" >&5\nprintf %s \"checking for socklen_t equivalent... \" >&6; }\nif test ${gl_cv_socklen_t_equiv+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  # Systems have either \"struct sockaddr *\" or\n         # \"void *\" as the second argument to getpeername\n         gl_cv_socklen_t_equiv=\n         for arg2 in \"struct sockaddr\" void; do\n           for t in int size_t \"unsigned int\" \"long int\" \"unsigned long int\"; do\n             cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/types.h>\n                   #include <sys/socket.h>\n\n                   int getpeername (int, $arg2 *, $t *);\nint\nmain (void)\n{\n$t len;\n                  getpeername (0, 0, &len);\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_socklen_t_equiv=\"$t\"\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n             test \"$gl_cv_socklen_t_equiv\" != \"\" && break\n           done\n           test \"$gl_cv_socklen_t_equiv\" != \"\" && break\n         done\n         if test \"$gl_cv_socklen_t_equiv\" = \"\"; then\n           as_fn_error $? \"Cannot find a type to use in place of socklen_t\" \"$LINENO\" 5\n         fi\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_socklen_t_equiv\" >&5\nprintf \"%s\\n\" \"$gl_cv_socklen_t_equiv\" >&6; }\n\nprintf \"%s\\n\" \"#define socklen_t $gl_cv_socklen_t_equiv\" >>confdefs.h\n\nfi\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for ssize_t\" >&5\nprintf %s \"checking for ssize_t... \" >&6; }\nif test ${gt_cv_ssize_t+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <sys/types.h>\nint\nmain (void)\n{\nint x = sizeof (ssize_t *) + sizeof (ssize_t);\n            return !x;\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gt_cv_ssize_t=yes\nelse $as_nop\n  gt_cv_ssize_t=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gt_cv_ssize_t\" >&5\nprintf \"%s\\n\" \"$gt_cv_ssize_t\" >&6; }\n  if test $gt_cv_ssize_t = no; then\n\nprintf \"%s\\n\" \"#define ssize_t int\" >>confdefs.h\n\n  fi\n\n\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking for working stdalign.h\" >&5\nprintf %s \"checking for working stdalign.h... \" >&6; }\nif test ${gl_cv_header_working_stdalign_h+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n#include <stdint.h>\n            #include <stdalign.h>\n            #include <stddef.h>\n\n            /* Test that alignof yields a result consistent with offsetof.\n               This catches GCC bug 52023\n               <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.  */\n            #ifdef __cplusplus\n               template <class t> struct alignof_helper { char a; t b; };\n            # define ao(type) offsetof (alignof_helper<type>, b)\n            #else\n            # define ao(type) offsetof (struct { char a; type b; }, b)\n            #endif\n            char test_double[ao (double) % _Alignof (double) == 0 ? 1 : -1];\n            char test_long[ao (long int) % _Alignof (long int) == 0 ? 1 : -1];\n            char test_alignof[alignof (double) == _Alignof (double) ? 1 : -1];\n\n            /* Test _Alignas only on platforms where gnulib can help.  */\n            #if \\\n                ((defined __cplusplus && 201103 <= __cplusplus) \\\n                 || (__TINYC__ && defined __attribute__) \\\n                 || (defined __APPLE__ && defined __MACH__ \\\n                     ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \\\n                     : __GNUC__) \\\n                 || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \\\n                 || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__ \\\n                 || 1300 <= _MSC_VER)\n              struct alignas_test { char c; char alignas (8) alignas_8; };\n              char test_alignas[offsetof (struct alignas_test, alignas_8) == 8\n                                ? 1 : -1];\n            #endif\n\nint\nmain (void)\n{\n\n  ;\n  return 0;\n}\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_header_working_stdalign_h=yes\nelse $as_nop\n  gl_cv_header_working_stdalign_h=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdalign_h\" >&5\nprintf \"%s\\n\" \"$gl_cv_header_working_stdalign_h\" >&6; }\n\n  if test $gl_cv_header_working_stdalign_h = yes; then\n    STDALIGN_H=''\n  else\n    STDALIGN_H='stdalign.h'\n  fi\n\n\n   if test -n \"$STDALIGN_H\"; then\n  GL_GENERATE_STDALIGN_H_TRUE=\n  GL_GENERATE_STDALIGN_H_FALSE='#'\nelse\n  GL_GENERATE_STDALIGN_H_TRUE='#'\n  GL_GENERATE_STDALIGN_H_FALSE=\nfi\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FSCANF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FSCANF 1\" >>confdefs.h\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_FSCANF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_SCANF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_SCANF 1\" >>confdefs.h\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_SCANF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FGETC=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FGETC 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETC=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETC 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_GETCHAR=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_GETCHAR 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FGETS=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FGETS 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FREAD=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FREAD 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FPRINTF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FPRINTF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_PRINTF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_PRINTF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_VFPRINTF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_VFPRINTF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_VPRINTF=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_VPRINTF 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FPUTC=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FPUTC 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_PUTC=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_PUTC 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_PUTCHAR=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_PUTCHAR 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FPUTS=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FPUTS 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_PUTS=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_PUTS 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_FWRITE=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_FWRITE 1\" >>confdefs.h\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n      ac_fn_check_decl \"$LINENO\" \"localtime_r\" \"ac_cv_have_decl_localtime_r\" \"/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n         gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n         been included before.  */\n      #if defined __MINGW32__\n      # include <unistd.h>\n      #endif\n      #include <time.h>\n\n\" \"$ac_c_undeclared_builtin_options\" \"CFLAGS\"\nif test \"x$ac_cv_have_decl_localtime_r\" = xyes\nthen :\n  ac_have_decl=1\nelse $as_nop\n  ac_have_decl=0\nfi\nprintf \"%s\\n\" \"#define HAVE_DECL_LOCALTIME_R $ac_have_decl\" >>confdefs.h\n\n  if test $ac_cv_have_decl_localtime_r = no; then\n    HAVE_DECL_LOCALTIME_R=0\n  fi\n\n\n  if test $ac_cv_func_localtime_r = yes; then\n    HAVE_LOCALTIME_R=1\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether localtime_r is compatible with its POSIX signature\" >&5\nprintf %s \"checking whether localtime_r is compatible with its POSIX signature... \" >&6; }\nif test ${gl_cv_time_r_posix+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n                 gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n                 been included before.  */\n              #if defined __MINGW32__\n              # include <unistd.h>\n              #endif\n              #include <time.h>\n\nint\nmain (void)\n{\n/* We don't need to append 'restrict's to the argument types,\n                 even though the POSIX signature has the 'restrict's,\n                 since C99 says they can't affect type compatibility.  */\n              struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;\n              if (ptr) return 0;\n              /* Check the return type is a pointer.\n                 On HP-UX 10 it is 'int'.  */\n              *localtime_r (0, 0);\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_compile \"$LINENO\"\nthen :\n  gl_cv_time_r_posix=yes\nelse $as_nop\n  gl_cv_time_r_posix=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_time_r_posix\" >&5\nprintf \"%s\\n\" \"$gl_cv_time_r_posix\" >&6; }\n    if test $gl_cv_time_r_posix = yes; then\n      REPLACE_LOCALTIME_R=0\n    else\n      REPLACE_LOCALTIME_R=1\n    fi\n  else\n    HAVE_LOCALTIME_R=0\n                { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking whether localtime_r exists as an inline function\" >&5\nprintf %s \"checking whether localtime_r exists as an inline function... \" >&6; }\nif test ${gl_cv_func_localtime_r_inline+y}\nthen :\n  printf %s \"(cached) \" >&6\nelse $as_nop\n  cat confdefs.h - <<_ACEOF >conftest.$ac_ext\n/* end confdefs.h.  */\n/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n                 gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n                 been included before.  */\n              #if defined __MINGW32__\n              # include <unistd.h>\n              #endif\n              #include <time.h>\n\nint\nmain (void)\n{\ntime_t a;\n              struct tm r;\n              localtime_r (&a, &r);\n\n  ;\n  return 0;\n}\n\n_ACEOF\nif ac_fn_c_try_link \"$LINENO\"\nthen :\n  gl_cv_func_localtime_r_inline=yes\nelse $as_nop\n  gl_cv_func_localtime_r_inline=no\nfi\nrm -f core conftest.err conftest.$ac_objext conftest.beam \\\n    conftest$ac_exeext conftest.$ac_ext\n\nfi\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_localtime_r_inline\" >&5\nprintf \"%s\\n\" \"$gl_cv_func_localtime_r_inline\" >&6; }\n    if test $gl_cv_func_localtime_r_inline = yes; then\n      REPLACE_LOCALTIME_R=1\n    fi\n  fi\n\n  if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS time_r.$ac_objext\"\n\n\n  :\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_TIME_R=1\n\n\n\n\n\nprintf \"%s\\n\" \"#define GNULIB_TEST_TIME_R 1\" >>confdefs.h\n\n\n\n\n\n  ac_fn_c_check_func \"$LINENO\" \"uname\" \"ac_cv_func_uname\"\nif test \"x$ac_cv_func_uname\" = xyes\nthen :\n  printf \"%s\\n\" \"#define HAVE_UNAME 1\" >>confdefs.h\n\nfi\n\n  if test $ac_cv_func_uname = no; then\n    HAVE_UNAME=0\n  fi\n\n  if test $HAVE_UNAME = 0; then\n\n\n\n\n\n\n\n\n  gl_LIBOBJS=\"$gl_LIBOBJS uname.$ac_objext\"\n\n\n  :\n\n  fi\n\n\n\n\n\n\n\n\n\n          GL_GNULIB_UNAME=1\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n  LIBGNU_LIBDEPS=\"$gl_libdeps\"\n\n  LIBGNU_LTLIBDEPS=\"$gl_ltlibdeps\"\n\n\n\nac_config_files=\"$ac_config_files Makefile gllib/Makefile glm4/Makefile\"\n\ncat >confcache <<\\_ACEOF\n# This file is a shell script that caches the results of configure\n# tests run on this system so they can be shared between configure\n# scripts and configure runs, see configure's option --config-cache.\n# It is not useful on other systems.  If it contains results you don't\n# want to keep, you may remove or edit it.\n#\n# config.status only pays attention to the cache file if you give it\n# the --recheck option to rerun configure.\n#\n# `ac_cv_env_foo' variables (set or unset) will be overridden when\n# loading this file, other *unset* `ac_cv_foo' will be assigned the\n# following values.\n\n_ACEOF\n\n# The following way of writing the cache mishandles newlines in values,\n# but we know of no workaround that is simple, portable, and efficient.\n# So, we kill variables containing newlines.\n# Ultrix sh set writes to stderr and can't be redirected directly,\n# and sets the high bit in the cache file unless we assign to the vars.\n(\n  for ac_var in `(set) 2>&1 | sed -n 's/^\\([a-zA-Z_][a-zA-Z0-9_]*\\)=.*/\\1/p'`; do\n    eval ac_val=\\$$ac_var\n    case $ac_val in #(\n    *${as_nl}*)\n      case $ac_var in #(\n      *_cv_*) { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: cache variable $ac_var contains a newline\" >&2;} ;;\n      esac\n      case $ac_var in #(\n      _ | IFS | as_nl) ;; #(\n      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(\n      *) { eval $ac_var=; unset $ac_var;} ;;\n      esac ;;\n    esac\n  done\n\n  (set) 2>&1 |\n    case $as_nl`(ac_space=' '; set) 2>&1` in #(\n    *${as_nl}ac_space=\\ *)\n      # `set' does not quote correctly, so add quotes: double-quote\n      # substitution turns \\\\\\\\ into \\\\, and sed turns \\\\ into \\.\n      sed -n \\\n\t\"s/'/'\\\\\\\\''/g;\n\t  s/^\\\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\\\)=\\\\(.*\\\\)/\\\\1='\\\\2'/p\"\n      ;; #(\n    *)\n      # `set' quotes correctly as required by POSIX, so do not add quotes.\n      sed -n \"/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p\"\n      ;;\n    esac |\n    sort\n) |\n  sed '\n     /^ac_cv_env_/b end\n     t clear\n     :clear\n     s/^\\([^=]*\\)=\\(.*[{}].*\\)$/test ${\\1+y} || &/\n     t end\n     s/^\\([^=]*\\)=\\(.*\\)$/\\1=${\\1=\\2}/\n     :end' >>confcache\nif diff \"$cache_file\" confcache >/dev/null 2>&1; then :; else\n  if test -w \"$cache_file\"; then\n    if test \"x$cache_file\" != \"x/dev/null\"; then\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: updating cache $cache_file\" >&5\nprintf \"%s\\n\" \"$as_me: updating cache $cache_file\" >&6;}\n      if test ! -f \"$cache_file\" || test -h \"$cache_file\"; then\n\tcat confcache >\"$cache_file\"\n      else\n        case $cache_file in #(\n        */* | ?:*)\n\t  mv -f confcache \"$cache_file\"$$ &&\n\t  mv -f \"$cache_file\"$$ \"$cache_file\" ;; #(\n        *)\n\t  mv -f confcache \"$cache_file\" ;;\n\tesac\n      fi\n    fi\n  else\n    { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file\" >&5\nprintf \"%s\\n\" \"$as_me: not updating unwritable cache $cache_file\" >&6;}\n  fi\nfi\nrm -f confcache\n\ntest \"x$prefix\" = xNONE && prefix=$ac_default_prefix\n# Let make expand exec_prefix.\ntest \"x$exec_prefix\" = xNONE && exec_prefix='${prefix}'\n\nDEFS=-DHAVE_CONFIG_H\n\nac_libobjs=\nac_ltlibobjs=\nU=\nfor ac_i in : $LIBOBJS; do test \"x$ac_i\" = x: && continue\n  # 1. Remove the extension, and $U if already installed.\n  ac_script='s/\\$U\\././;s/\\.o$//;s/\\.obj$//'\n  ac_i=`printf \"%s\\n\" \"$ac_i\" | sed \"$ac_script\"`\n  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR\n  #    will be set to the directory where LIBOBJS objects are built.\n  as_fn_append ac_libobjs \" \\${LIBOBJDIR}$ac_i\\$U.$ac_objext\"\n  as_fn_append ac_ltlibobjs \" \\${LIBOBJDIR}$ac_i\"'$U.lo'\ndone\nLIBOBJS=$ac_libobjs\n\nLTLIBOBJS=$ac_ltlibobjs\n\n\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure\" >&5\nprintf %s \"checking that generated files are newer than configure... \" >&6; }\n   if test -n \"$am_sleep_pid\"; then\n     # Hide warnings about reused PIDs.\n     wait $am_sleep_pid 2>/dev/null\n   fi\n   { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: result: done\" >&5\nprintf \"%s\\n\" \"done\" >&6; }\n if test -n \"$EXEEXT\"; then\n  am__EXEEXT_TRUE=\n  am__EXEEXT_FALSE='#'\nelse\n  am__EXEEXT_TRUE='#'\n  am__EXEEXT_FALSE=\nfi\n\nif test -z \"${AMDEP_TRUE}\" && test -z \"${AMDEP_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"AMDEP\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${am__fastdepCC_TRUE}\" && test -z \"${am__fastdepCC_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"am__fastdepCC\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_COND_LIBTOOL_TRUE}\" && test -z \"${GL_COND_LIBTOOL_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_COND_LIBTOOL\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_ERRNO_H_TRUE}\" && test -z \"${GL_GENERATE_ERRNO_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_ERRNO_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_EXECINFO_H_TRUE}\" && test -z \"${GL_GENERATE_EXECINFO_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_EXECINFO_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_LIMITS_H_TRUE}\" && test -z \"${GL_GENERATE_LIMITS_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_LIMITS_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_STDALIGN_H_TRUE}\" && test -z \"${GL_GENERATE_STDALIGN_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_STDALIGN_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_STDDEF_H_TRUE}\" && test -z \"${GL_GENERATE_STDDEF_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_STDDEF_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_LIMITS_H_TRUE}\" && test -z \"${GL_GENERATE_LIMITS_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_LIMITS_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\nif test -z \"${GL_GENERATE_STDINT_H_TRUE}\" && test -z \"${GL_GENERATE_STDINT_H_FALSE}\"; then\n  as_fn_error $? \"conditional \\\"GL_GENERATE_STDINT_H\\\" was never defined.\nUsually this means the macro was only invoked conditionally.\" \"$LINENO\" 5\nfi\n\n    gl_libobjs=\n    gl_ltlibobjs=\n    if test -n \"$gl_LIBOBJS\"; then\n      # Remove the extension.\n      sed_drop_objext='s/\\.o$//;s/\\.obj$//'\n      for i in `for i in $gl_LIBOBJS; do echo \"$i\"; done | sed -e \"$sed_drop_objext\" | sort | uniq`; do\n        gl_libobjs=\"$gl_libobjs $i.$ac_objext\"\n        gl_ltlibobjs=\"$gl_ltlibobjs $i.lo\"\n      done\n    fi\n    gl_LIBOBJS=$gl_libobjs\n\n    gl_LTLIBOBJS=$gl_ltlibobjs\n\n\n\n: \"${CONFIG_STATUS=./config.status}\"\nac_write_fail=0\nac_clean_files_save=$ac_clean_files\nac_clean_files=\"$ac_clean_files $CONFIG_STATUS\"\n{ printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS\" >&5\nprintf \"%s\\n\" \"$as_me: creating $CONFIG_STATUS\" >&6;}\nas_write_fail=0\ncat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1\n#! $SHELL\n# Generated by $as_me.\n# Run this file to recreate the current configuration.\n# Compiler output produced by configure, useful for debugging\n# configure, is in config.log if it exists.\n\ndebug=false\nac_cs_recheck=false\nac_cs_silent=false\n\nSHELL=\\${CONFIG_SHELL-$SHELL}\nexport SHELL\n_ASEOF\ncat >>$CONFIG_STATUS <<\\_ASEOF || as_write_fail=1\n## -------------------- ##\n## M4sh Initialization. ##\n## -------------------- ##\n\n# Be more Bourne compatible\nDUALCASE=1; export DUALCASE # for MKS sh\nas_nop=:\nif test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1\nthen :\n  emulate sh\n  NULLCMD=:\n  # Pre-4.2 versions of Zsh do word splitting on ${1+\"$@\"}, which\n  # is contrary to our usage.  Disable this feature.\n  alias -g '${1+\"$@\"}'='\"$@\"'\n  setopt NO_GLOB_SUBST\nelse $as_nop\n  case `(set -o) 2>/dev/null` in #(\n  *posix*) :\n    set -o posix ;; #(\n  *) :\n     ;;\nesac\nfi\n\n\n\n# Reset variables that may have inherited troublesome values from\n# the environment.\n\n# IFS needs to be set, to space, tab, and newline, in precisely that order.\n# (If _AS_PATH_WALK were called with IFS unset, it would have the\n# side effect of setting IFS to empty, thus disabling word splitting.)\n# Quoting is to prevent editors from complaining about space-tab.\nas_nl='\n'\nexport as_nl\nIFS=\" \"\"\t$as_nl\"\n\nPS1='$ '\nPS2='> '\nPS4='+ '\n\n# Ensure predictable behavior from utilities with locale-dependent output.\nLC_ALL=C\nexport LC_ALL\nLANGUAGE=C\nexport LANGUAGE\n\n# We cannot yet rely on \"unset\" to work, but we need these variables\n# to be unset--not just set to an empty or harmless value--now, to\n# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh).  This construct\n# also avoids known problems related to \"unset\" and subshell syntax\n# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).\nfor as_var in BASH_ENV ENV MAIL MAILPATH CDPATH\ndo eval test \\${$as_var+y} \\\n  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :\ndone\n\n# Ensure that fds 0, 1, and 2 are open.\nif (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi\nif (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi\nif (exec 3>&2)            ; then :; else exec 2>/dev/null; fi\n\n# The user is always right.\nif ${PATH_SEPARATOR+false} :; then\n  PATH_SEPARATOR=:\n  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {\n    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||\n      PATH_SEPARATOR=';'\n  }\nfi\n\n\n# Find who we are.  Look in the path if we contain no directory separator.\nas_myself=\ncase $0 in #((\n  *[\\\\/]* ) as_myself=$0 ;;\n  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR\nfor as_dir in $PATH\ndo\n  IFS=$as_save_IFS\n  case $as_dir in #(((\n    '') as_dir=./ ;;\n    */) ;;\n    *) as_dir=$as_dir/ ;;\n  esac\n    test -r \"$as_dir$0\" && as_myself=$as_dir$0 && break\n  done\nIFS=$as_save_IFS\n\n     ;;\nesac\n# We did not find ourselves, most probably we were run as `sh COMMAND'\n# in which case we are not to be found in the path.\nif test \"x$as_myself\" = x; then\n  as_myself=$0\nfi\nif test ! -f \"$as_myself\"; then\n  printf \"%s\\n\" \"$as_myself: error: cannot find myself; rerun with an absolute file name\" >&2\n  exit 1\nfi\n\n\n\n# as_fn_error STATUS ERROR [LINENO LOG_FD]\n# ----------------------------------------\n# Output \"`basename $0`: error: ERROR\" to stderr. If LINENO and LOG_FD are\n# provided, also output the error to LOG_FD, referencing LINENO. Then exit the\n# script with STATUS, using 1 if that was 0.\nas_fn_error ()\n{\n  as_status=$1; test $as_status -eq 0 && as_status=1\n  if test \"$4\"; then\n    as_lineno=${as_lineno-\"$3\"} as_lineno_stack=as_lineno_stack=$as_lineno_stack\n    printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: $2\" >&$4\n  fi\n  printf \"%s\\n\" \"$as_me: error: $2\" >&2\n  as_fn_exit $as_status\n} # as_fn_error\n\n\n\n# as_fn_set_status STATUS\n# -----------------------\n# Set $? to STATUS, without forking.\nas_fn_set_status ()\n{\n  return $1\n} # as_fn_set_status\n\n# as_fn_exit STATUS\n# -----------------\n# Exit the shell with STATUS, even in a \"trap 0\" or \"set -e\" context.\nas_fn_exit ()\n{\n  set +e\n  as_fn_set_status $1\n  exit $1\n} # as_fn_exit\n\n# as_fn_unset VAR\n# ---------------\n# Portably unset VAR.\nas_fn_unset ()\n{\n  { eval $1=; unset $1;}\n}\nas_unset=as_fn_unset\n\n# as_fn_append VAR VALUE\n# ----------------------\n# Append the text in VALUE to the end of the definition contained in VAR. Take\n# advantage of any shell optimizations that allow amortized linear growth over\n# repeated appends, instead of the typical quadratic growth present in naive\n# implementations.\nif (eval \"as_var=1; as_var+=2; test x\\$as_var = x12\") 2>/dev/null\nthen :\n  eval 'as_fn_append ()\n  {\n    eval $1+=\\$2\n  }'\nelse $as_nop\n  as_fn_append ()\n  {\n    eval $1=\\$$1\\$2\n  }\nfi # as_fn_append\n\n# as_fn_arith ARG...\n# ------------------\n# Perform arithmetic evaluation on the ARGs, and store the result in the\n# global $as_val. Take advantage of shells that can avoid forks. The arguments\n# must be portable across $(()) and expr.\nif (eval \"test \\$(( 1 + 1 )) = 2\") 2>/dev/null\nthen :\n  eval 'as_fn_arith ()\n  {\n    as_val=$(( $* ))\n  }'\nelse $as_nop\n  as_fn_arith ()\n  {\n    as_val=`expr \"$@\" || test $? -eq 1`\n  }\nfi # as_fn_arith\n\n\nif expr a : '\\(a\\)' >/dev/null 2>&1 &&\n   test \"X`expr 00001 : '.*\\(...\\)'`\" = X001; then\n  as_expr=expr\nelse\n  as_expr=false\nfi\n\nif (basename -- /) >/dev/null 2>&1 && test \"X`basename -- / 2>&1`\" = \"X/\"; then\n  as_basename=basename\nelse\n  as_basename=false\nfi\n\nif (as_dir=`dirname -- /` && test \"X$as_dir\" = X/) >/dev/null 2>&1; then\n  as_dirname=dirname\nelse\n  as_dirname=false\nfi\n\nas_me=`$as_basename -- \"$0\" ||\n$as_expr X/\"$0\" : '.*/\\([^/][^/]*\\)/*$' \\| \\\n\t X\"$0\" : 'X\\(//\\)$' \\| \\\n\t X\"$0\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X/\"$0\" |\n    sed '/^.*\\/\\([^/][^/]*\\)\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n\n# Avoid depending upon Character Ranges.\nas_cr_letters='abcdefghijklmnopqrstuvwxyz'\nas_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'\nas_cr_Letters=$as_cr_letters$as_cr_LETTERS\nas_cr_digits='0123456789'\nas_cr_alnum=$as_cr_Letters$as_cr_digits\n\n\n# Determine whether it's possible to make 'echo' print without a newline.\n# These variables are no longer used directly by Autoconf, but are AC_SUBSTed\n# for compatibility with existing Makefiles.\nECHO_C= ECHO_N= ECHO_T=\ncase `echo -n x` in #(((((\n-n*)\n  case `echo 'xy\\c'` in\n  *c*) ECHO_T='\t';;\t# ECHO_T is single tab character.\n  xy)  ECHO_C='\\c';;\n  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null\n       ECHO_T='\t';;\n  esac;;\n*)\n  ECHO_N='-n';;\nesac\n\n# For backward compatibility with old third-party macros, we provide\n# the shell variables $as_echo and $as_echo_n.  New code should use\n# AS_ECHO([\"message\"]) and AS_ECHO_N([\"message\"]), respectively.\nas_echo='printf %s\\n'\nas_echo_n='printf %s'\n\nrm -f conf$$ conf$$.exe conf$$.file\nif test -d conf$$.dir; then\n  rm -f conf$$.dir/conf$$.file\nelse\n  rm -f conf$$.dir\n  mkdir conf$$.dir 2>/dev/null\nfi\nif (echo >conf$$.file) 2>/dev/null; then\n  if ln -s conf$$.file conf$$ 2>/dev/null; then\n    as_ln_s='ln -s'\n    # ... but there are two gotchas:\n    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.\n    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.\n    # In both cases, we have to default to `cp -pR'.\n    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||\n      as_ln_s='cp -pR'\n  elif ln conf$$.file conf$$ 2>/dev/null; then\n    as_ln_s=ln\n  else\n    as_ln_s='cp -pR'\n  fi\nelse\n  as_ln_s='cp -pR'\nfi\nrm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file\nrmdir conf$$.dir 2>/dev/null\n\n\n# as_fn_mkdir_p\n# -------------\n# Create \"$as_dir\" as a directory, including parents if necessary.\nas_fn_mkdir_p ()\n{\n\n  case $as_dir in #(\n  -*) as_dir=./$as_dir;;\n  esac\n  test -d \"$as_dir\" || eval $as_mkdir_p || {\n    as_dirs=\n    while :; do\n      case $as_dir in #(\n      *\\'*) as_qdir=`printf \"%s\\n\" \"$as_dir\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"`;; #'(\n      *) as_qdir=$as_dir;;\n      esac\n      as_dirs=\"'$as_qdir' $as_dirs\"\n      as_dir=`$as_dirname -- \"$as_dir\" ||\n$as_expr X\"$as_dir\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$as_dir\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$as_dir\" : 'X\\(//\\)$' \\| \\\n\t X\"$as_dir\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$as_dir\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n      test -d \"$as_dir\" && break\n    done\n    test -z \"$as_dirs\" || eval \"mkdir $as_dirs\"\n  } || test -d \"$as_dir\" || as_fn_error $? \"cannot create directory $as_dir\"\n\n\n} # as_fn_mkdir_p\nif mkdir -p . 2>/dev/null; then\n  as_mkdir_p='mkdir -p \"$as_dir\"'\nelse\n  test -d ./-p && rmdir ./-p\n  as_mkdir_p=false\nfi\n\n\n# as_fn_executable_p FILE\n# -----------------------\n# Test if FILE is an executable regular file.\nas_fn_executable_p ()\n{\n  test -f \"$1\" && test -x \"$1\"\n} # as_fn_executable_p\nas_test_x='test -x'\nas_executable_p=as_fn_executable_p\n\n# Sed expression to map a string onto a valid CPP name.\nas_tr_cpp=\"eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'\"\n\n# Sed expression to map a string onto a valid variable name.\nas_tr_sh=\"eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'\"\n\n\nexec 6>&1\n## ----------------------------------- ##\n## Main body of $CONFIG_STATUS script. ##\n## ----------------------------------- ##\n_ASEOF\ntest $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n# Save the log message, to keep $0 and so on meaningful, and to\n# report actual input values of CONFIG_FILES etc. instead of their\n# values after options handling.\nac_log=\"\nThis file was extended by dummy $as_me 0, which was\ngenerated by GNU Autoconf 2.71.  Invocation command line was\n\n  CONFIG_FILES    = $CONFIG_FILES\n  CONFIG_HEADERS  = $CONFIG_HEADERS\n  CONFIG_LINKS    = $CONFIG_LINKS\n  CONFIG_COMMANDS = $CONFIG_COMMANDS\n  $ $0 $@\n\non `(hostname || uname -n) 2>/dev/null | sed 1q`\n\"\n\n_ACEOF\n\ncase $ac_config_files in *\"\n\"*) set x $ac_config_files; shift; ac_config_files=$*;;\nesac\n\ncase $ac_config_headers in *\"\n\"*) set x $ac_config_headers; shift; ac_config_headers=$*;;\nesac\n\n\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\n# Files that config.status was made for.\nconfig_files=\"$ac_config_files\"\nconfig_headers=\"$ac_config_headers\"\nconfig_commands=\"$ac_config_commands\"\n\n_ACEOF\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\nac_cs_usage=\"\\\n\\`$as_me' instantiates files and other configuration actions\nfrom templates according to the current configuration.  Unless the files\nand actions are specified as TAGs, all are instantiated by default.\n\nUsage: $0 [OPTION]... [TAG]...\n\n  -h, --help       print this help, then exit\n  -V, --version    print version number and configuration settings, then exit\n      --config     print configuration, then exit\n  -q, --quiet, --silent\n                   do not print progress messages\n  -d, --debug      don't remove temporary files\n      --recheck    update $as_me by reconfiguring in the same conditions\n      --file=FILE[:TEMPLATE]\n                   instantiate the configuration file FILE\n      --header=FILE[:TEMPLATE]\n                   instantiate the configuration header FILE\n\nConfiguration files:\n$config_files\n\nConfiguration headers:\n$config_headers\n\nConfiguration commands:\n$config_commands\n\nReport bugs to the package provider.\"\n\n_ACEOF\nac_cs_config=`printf \"%s\\n\" \"$ac_configure_args\" | sed \"$ac_safe_unquote\"`\nac_cs_config_escaped=`printf \"%s\\n\" \"$ac_cs_config\" | sed \"s/^ //; s/'/'\\\\\\\\\\\\\\\\''/g\"`\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\nac_cs_config='$ac_cs_config_escaped'\nac_cs_version=\"\\\\\ndummy config.status 0\nconfigured by $0, generated by GNU Autoconf 2.71,\n  with options \\\\\"\\$ac_cs_config\\\\\"\n\nCopyright (C) 2021 Free Software Foundation, Inc.\nThis config.status script is free software; the Free Software Foundation\ngives unlimited permission to copy, distribute and modify it.\"\n\nac_pwd='$ac_pwd'\nsrcdir='$srcdir'\nINSTALL='$INSTALL'\nMKDIR_P='$MKDIR_P'\nAWK='$AWK'\ntest -n \"\\$AWK\" || AWK=awk\n_ACEOF\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n# The default lists apply if the user does not specify any file.\nac_need_defaults=:\nwhile test $# != 0\ndo\n  case $1 in\n  --*=?*)\n    ac_option=`expr \"X$1\" : 'X\\([^=]*\\)='`\n    ac_optarg=`expr \"X$1\" : 'X[^=]*=\\(.*\\)'`\n    ac_shift=:\n    ;;\n  --*=)\n    ac_option=`expr \"X$1\" : 'X\\([^=]*\\)='`\n    ac_optarg=\n    ac_shift=:\n    ;;\n  *)\n    ac_option=$1\n    ac_optarg=$2\n    ac_shift=shift\n    ;;\n  esac\n\n  case $ac_option in\n  # Handling of the options.\n  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)\n    ac_cs_recheck=: ;;\n  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )\n    printf \"%s\\n\" \"$ac_cs_version\"; exit ;;\n  --config | --confi | --conf | --con | --co | --c )\n    printf \"%s\\n\" \"$ac_cs_config\"; exit ;;\n  --debug | --debu | --deb | --de | --d | -d )\n    debug=: ;;\n  --file | --fil | --fi | --f )\n    $ac_shift\n    case $ac_optarg in\n    *\\'*) ac_optarg=`printf \"%s\\n\" \"$ac_optarg\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"` ;;\n    '') as_fn_error $? \"missing file argument\" ;;\n    esac\n    as_fn_append CONFIG_FILES \" '$ac_optarg'\"\n    ac_need_defaults=false;;\n  --header | --heade | --head | --hea )\n    $ac_shift\n    case $ac_optarg in\n    *\\'*) ac_optarg=`printf \"%s\\n\" \"$ac_optarg\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"` ;;\n    esac\n    as_fn_append CONFIG_HEADERS \" '$ac_optarg'\"\n    ac_need_defaults=false;;\n  --he | --h)\n    # Conflict between --help and --header\n    as_fn_error $? \"ambiguous option: \\`$1'\nTry \\`$0 --help' for more information.\";;\n  --help | --hel | -h )\n    printf \"%s\\n\" \"$ac_cs_usage\"; exit ;;\n  -q | -quiet | --quiet | --quie | --qui | --qu | --q \\\n  | -silent | --silent | --silen | --sile | --sil | --si | --s)\n    ac_cs_silent=: ;;\n\n  # This is an error.\n  -*) as_fn_error $? \"unrecognized option: \\`$1'\nTry \\`$0 --help' for more information.\" ;;\n\n  *) as_fn_append ac_config_targets \" $1\"\n     ac_need_defaults=false ;;\n\n  esac\n  shift\ndone\n\nac_configure_extra_args=\n\nif $ac_cs_silent; then\n  exec 6>/dev/null\n  ac_configure_extra_args=\"$ac_configure_extra_args --silent\"\nfi\n\n_ACEOF\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\nif \\$ac_cs_recheck; then\n  set X $SHELL '$0' $ac_configure_args \\$ac_configure_extra_args --no-create --no-recursion\n  shift\n  \\printf \"%s\\n\" \"running CONFIG_SHELL=$SHELL \\$*\" >&6\n  CONFIG_SHELL='$SHELL'\n  export CONFIG_SHELL\n  exec \"\\$@\"\nfi\n\n_ACEOF\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\nexec 5>>config.log\n{\n  echo\n  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX\n## Running $as_me. ##\n_ASBOX\n  printf \"%s\\n\" \"$ac_log\"\n} >&5\n\n_ACEOF\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\n#\n# INIT-COMMANDS\n#\nAMDEP_TRUE=\"$AMDEP_TRUE\" MAKE=\"${MAKE-make}\"\n\n_ACEOF\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n\n# Handling of arguments.\nfor ac_config_target in $ac_config_targets\ndo\n  case $ac_config_target in\n    \"config.h\") CONFIG_HEADERS=\"$CONFIG_HEADERS config.h\" ;;\n    \"depfiles\") CONFIG_COMMANDS=\"$CONFIG_COMMANDS depfiles\" ;;\n    \"Makefile\") CONFIG_FILES=\"$CONFIG_FILES Makefile\" ;;\n    \"gllib/Makefile\") CONFIG_FILES=\"$CONFIG_FILES gllib/Makefile\" ;;\n    \"glm4/Makefile\") CONFIG_FILES=\"$CONFIG_FILES glm4/Makefile\" ;;\n\n  *) as_fn_error $? \"invalid argument: \\`$ac_config_target'\" \"$LINENO\" 5;;\n  esac\ndone\n\n\n# If the user did not use the arguments to specify the items to instantiate,\n# then the envvar interface is used.  Set only those that are not.\n# We use the long form for the default assignment because of an extremely\n# bizarre bug on SunOS 4.1.3.\nif $ac_need_defaults; then\n  test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files\n  test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers\n  test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands\nfi\n\n# Have a temporary directory for convenience.  Make it in the build tree\n# simply because there is no reason against having it here, and in addition,\n# creating and moving files from /tmp can sometimes cause problems.\n# Hook for its removal unless debugging.\n# Note that there is a small window in which the directory will not be cleaned:\n# after its creation but before its name has been assigned to `$tmp'.\n$debug ||\n{\n  tmp= ac_tmp=\n  trap 'exit_status=$?\n  : \"${ac_tmp:=$tmp}\"\n  { test ! -d \"$ac_tmp\" || rm -fr \"$ac_tmp\"; } && exit $exit_status\n' 0\n  trap 'as_fn_exit 1' 1 2 13 15\n}\n# Create a (secure) tmp directory for tmp files.\n\n{\n  tmp=`(umask 077 && mktemp -d \"./confXXXXXX\") 2>/dev/null` &&\n  test -d \"$tmp\"\n}  ||\n{\n  tmp=./conf$$-$RANDOM\n  (umask 077 && mkdir \"$tmp\")\n} || as_fn_error $? \"cannot create a temporary directory in .\" \"$LINENO\" 5\nac_tmp=$tmp\n\n# Set up the scripts for CONFIG_FILES section.\n# No need to generate them if there are no CONFIG_FILES.\n# This happens for instance with `./config.status config.h'.\nif test -n \"$CONFIG_FILES\"; then\n\n\nac_cr=`echo X | tr X '\\015'`\n# On cygwin, bash can eat \\r inside `` if the user requested igncr.\n# But we know of no other shell where ac_cr would be empty at this\n# point, so we can use a bashism as a fallback.\nif test \"x$ac_cr\" = x; then\n  eval ac_cr=\\$\\'\\\\r\\'\nfi\nac_cs_awk_cr=`$AWK 'BEGIN { print \"a\\rb\" }' </dev/null 2>/dev/null`\nif test \"$ac_cs_awk_cr\" = \"a${ac_cr}b\"; then\n  ac_cs_awk_cr='\\\\r'\nelse\n  ac_cs_awk_cr=$ac_cr\nfi\n\necho 'BEGIN {' >\"$ac_tmp/subs1.awk\" &&\n_ACEOF\n\n\n{\n  echo \"cat >conf$$subs.awk <<_ACEOF\" &&\n  echo \"$ac_subst_vars\" | sed 's/.*/&!$&$ac_delim/' &&\n  echo \"_ACEOF\"\n} >conf$$subs.sh ||\n  as_fn_error $? \"could not make $CONFIG_STATUS\" \"$LINENO\" 5\nac_delim_num=`echo \"$ac_subst_vars\" | grep -c '^'`\nac_delim='%!_!# '\nfor ac_last_try in false false false false false :; do\n  . ./conf$$subs.sh ||\n    as_fn_error $? \"could not make $CONFIG_STATUS\" \"$LINENO\" 5\n\n  ac_delim_n=`sed -n \"s/.*$ac_delim\\$/X/p\" conf$$subs.awk | grep -c X`\n  if test $ac_delim_n = $ac_delim_num; then\n    break\n  elif $ac_last_try; then\n    as_fn_error $? \"could not make $CONFIG_STATUS\" \"$LINENO\" 5\n  else\n    ac_delim=\"$ac_delim!$ac_delim _$ac_delim!! \"\n  fi\ndone\nrm -f conf$$subs.sh\n\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\ncat >>\"\\$ac_tmp/subs1.awk\" <<\\\\_ACAWK &&\n_ACEOF\nsed -n '\nh\ns/^/S[\"/; s/!.*/\"]=/\np\ng\ns/^[^!]*!//\n:repl\nt repl\ns/'\"$ac_delim\"'$//\nt delim\n:nl\nh\ns/\\(.\\{148\\}\\)..*/\\1/\nt more1\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\\\\n\"\\\\/\np\nn\nb repl\n:more1\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\"\\\\/\np\ng\ns/.\\{148\\}//\nt nl\n:delim\nh\ns/\\(.\\{148\\}\\)..*/\\1/\nt more2\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\"/\np\nb\n:more2\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\"\\\\/\np\ng\ns/.\\{148\\}//\nt delim\n' <conf$$subs.awk | sed '\n/^[^\"\"]/{\n  N\n  s/\\n//\n}\n' >>$CONFIG_STATUS || ac_write_fail=1\nrm -f conf$$subs.awk\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\n_ACAWK\ncat >>\"\\$ac_tmp/subs1.awk\" <<_ACAWK &&\n  for (key in S) S_is_set[key] = 1\n  FS = \"\u0007\"\n\n}\n{\n  line = $ 0\n  nfields = split(line, field, \"@\")\n  substed = 0\n  len = length(field[1])\n  for (i = 2; i < nfields; i++) {\n    key = field[i]\n    keylen = length(key)\n    if (S_is_set[key]) {\n      value = S[key]\n      line = substr(line, 1, len) \"\" value \"\" substr(line, len + keylen + 3)\n      len += length(value) + length(field[++i])\n      substed = 1\n    } else\n      len += 1 + keylen\n  }\n\n  print line\n}\n\n_ACAWK\n_ACEOF\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\nif sed \"s/$ac_cr//\" < /dev/null > /dev/null 2>&1; then\n  sed \"s/$ac_cr\\$//; s/$ac_cr/$ac_cs_awk_cr/g\"\nelse\n  cat\nfi < \"$ac_tmp/subs1.awk\" > \"$ac_tmp/subs.awk\" \\\n  || as_fn_error $? \"could not setup config files machinery\" \"$LINENO\" 5\n_ACEOF\n\n# VPATH may cause trouble with some makes, so we remove sole $(srcdir),\n# ${srcdir} and @srcdir@ entries from VPATH if srcdir is \".\", strip leading and\n# trailing colons and then remove the whole line if VPATH becomes empty\n# (actually we leave an empty line to preserve line numbers).\nif test \"x$srcdir\" = x.; then\n  ac_vpsub='/^[\t ]*VPATH[\t ]*=[\t ]*/{\nh\ns///\ns/^/:/\ns/[\t ]*$/:/\ns/:\\$(srcdir):/:/g\ns/:\\${srcdir}:/:/g\ns/:@srcdir@:/:/g\ns/^:*//\ns/:*$//\nx\ns/\\(=[\t ]*\\).*/\\1/\nG\ns/\\n//\ns/^[^=]*=[\t ]*$//\n}'\nfi\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\nfi # test -n \"$CONFIG_FILES\"\n\n# Set up the scripts for CONFIG_HEADERS section.\n# No need to generate them if there are no CONFIG_HEADERS.\n# This happens for instance with `./config.status Makefile'.\nif test -n \"$CONFIG_HEADERS\"; then\ncat >\"$ac_tmp/defines.awk\" <<\\_ACAWK ||\nBEGIN {\n_ACEOF\n\n# Transform confdefs.h into an awk script `defines.awk', embedded as\n# here-document in config.status, that substitutes the proper values into\n# config.h.in to produce config.h.\n\n# Create a delimiter string that does not exist in confdefs.h, to ease\n# handling of long lines.\nac_delim='%!_!# '\nfor ac_last_try in false false :; do\n  ac_tt=`sed -n \"/$ac_delim/p\" confdefs.h`\n  if test -z \"$ac_tt\"; then\n    break\n  elif $ac_last_try; then\n    as_fn_error $? \"could not make $CONFIG_HEADERS\" \"$LINENO\" 5\n  else\n    ac_delim=\"$ac_delim!$ac_delim _$ac_delim!! \"\n  fi\ndone\n\n# For the awk script, D is an array of macro values keyed by name,\n# likewise P contains macro parameters if any.  Preserve backslash\n# newline sequences.\n\nac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*\nsed -n '\ns/.\\{148\\}/&'\"$ac_delim\"'/g\nt rset\n:rset\ns/^[\t ]*#[\t ]*define[\t ][\t ]*/ /\nt def\nd\n:def\ns/\\\\$//\nt bsnl\ns/[\"\\\\]/\\\\&/g\ns/^ \\('\"$ac_word_re\"'\\)\\(([^()]*)\\)[\t ]*\\(.*\\)/P[\"\\1\"]=\"\\2\"\\\nD[\"\\1\"]=\" \\3\"/p\ns/^ \\('\"$ac_word_re\"'\\)[\t ]*\\(.*\\)/D[\"\\1\"]=\" \\2\"/p\nd\n:bsnl\ns/[\"\\\\]/\\\\&/g\ns/^ \\('\"$ac_word_re\"'\\)\\(([^()]*)\\)[\t ]*\\(.*\\)/P[\"\\1\"]=\"\\2\"\\\nD[\"\\1\"]=\" \\3\\\\\\\\\\\\n\"\\\\/p\nt cont\ns/^ \\('\"$ac_word_re\"'\\)[\t ]*\\(.*\\)/D[\"\\1\"]=\" \\2\\\\\\\\\\\\n\"\\\\/p\nt cont\nd\n:cont\nn\ns/.\\{148\\}/&'\"$ac_delim\"'/g\nt clear\n:clear\ns/\\\\$//\nt bsnlc\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\"/p\nd\n:bsnlc\ns/[\"\\\\]/\\\\&/g; s/^/\"/; s/$/\\\\\\\\\\\\n\"\\\\/p\nb cont\n' <confdefs.h | sed '\ns/'\"$ac_delim\"'/\"\\\\\\\n\"/g' >>$CONFIG_STATUS || ac_write_fail=1\n\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\n  for (key in D) D_is_set[key] = 1\n  FS = \"\u0007\"\n}\n/^[\\t ]*#[\\t ]*(define|undef)[\\t ]+$ac_word_re([\\t (]|\\$)/ {\n  line = \\$ 0\n  split(line, arg, \" \")\n  if (arg[1] == \"#\") {\n    defundef = arg[2]\n    mac1 = arg[3]\n  } else {\n    defundef = substr(arg[1], 2)\n    mac1 = arg[2]\n  }\n  split(mac1, mac2, \"(\") #)\n  macro = mac2[1]\n  prefix = substr(line, 1, index(line, defundef) - 1)\n  if (D_is_set[macro]) {\n    # Preserve the white space surrounding the \"#\".\n    print prefix \"define\", macro P[macro] D[macro]\n    next\n  } else {\n    # Replace #undef with comments.  This is necessary, for example,\n    # in the case of _POSIX_SOURCE, which is predefined and required\n    # on some systems where configure will not decide to define it.\n    if (defundef == \"undef\") {\n      print \"/*\", prefix defundef, macro, \"*/\"\n      next\n    }\n  }\n}\n{ print }\n_ACAWK\n_ACEOF\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n  as_fn_error $? \"could not setup config headers machinery\" \"$LINENO\" 5\nfi # test -n \"$CONFIG_HEADERS\"\n\n\neval set X \"  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS\"\nshift\nfor ac_tag\ndo\n  case $ac_tag in\n  :[FHLC]) ac_mode=$ac_tag; continue;;\n  esac\n  case $ac_mode$ac_tag in\n  :[FHL]*:*);;\n  :L* | :C*:*) as_fn_error $? \"invalid tag \\`$ac_tag'\" \"$LINENO\" 5;;\n  :[FH]-) ac_tag=-:-;;\n  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;\n  esac\n  ac_save_IFS=$IFS\n  IFS=:\n  set x $ac_tag\n  IFS=$ac_save_IFS\n  shift\n  ac_file=$1\n  shift\n\n  case $ac_mode in\n  :L) ac_source=$1;;\n  :[FH])\n    ac_file_inputs=\n    for ac_f\n    do\n      case $ac_f in\n      -) ac_f=\"$ac_tmp/stdin\";;\n      *) # Look for the file first in the build tree, then in the source tree\n\t # (if the path is not absolute).  The absolute path cannot be DOS-style,\n\t # because $ac_f cannot contain `:'.\n\t test -f \"$ac_f\" ||\n\t   case $ac_f in\n\t   [\\\\/$]*) false;;\n\t   *) test -f \"$srcdir/$ac_f\" && ac_f=\"$srcdir/$ac_f\";;\n\t   esac ||\n\t   as_fn_error 1 \"cannot find input file: \\`$ac_f'\" \"$LINENO\" 5;;\n      esac\n      case $ac_f in *\\'*) ac_f=`printf \"%s\\n\" \"$ac_f\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g\"`;; esac\n      as_fn_append ac_file_inputs \" '$ac_f'\"\n    done\n\n    # Let's still pretend it is `configure' which instantiates (i.e., don't\n    # use $as_me), people would be surprised to read:\n    #    /* config.h.  Generated by config.status.  */\n    configure_input='Generated from '`\n\t  printf \"%s\\n\" \"$*\" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'\n\t`' by configure.'\n    if test x\"$ac_file\" != x-; then\n      configure_input=\"$ac_file.  $configure_input\"\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: creating $ac_file\" >&5\nprintf \"%s\\n\" \"$as_me: creating $ac_file\" >&6;}\n    fi\n    # Neutralize special characters interpreted by sed in replacement strings.\n    case $configure_input in #(\n    *\\&* | *\\|* | *\\\\* )\n       ac_sed_conf_input=`printf \"%s\\n\" \"$configure_input\" |\n       sed 's/[\\\\\\\\&|]/\\\\\\\\&/g'`;; #(\n    *) ac_sed_conf_input=$configure_input;;\n    esac\n\n    case $ac_tag in\n    *:-:* | *:-) cat >\"$ac_tmp/stdin\" \\\n      || as_fn_error $? \"could not create $ac_file\" \"$LINENO\" 5 ;;\n    esac\n    ;;\n  esac\n\n  ac_dir=`$as_dirname -- \"$ac_file\" ||\n$as_expr X\"$ac_file\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$ac_file\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$ac_file\" : 'X\\(//\\)$' \\| \\\n\t X\"$ac_file\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$ac_file\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n  as_dir=\"$ac_dir\"; as_fn_mkdir_p\n  ac_builddir=.\n\ncase \"$ac_dir\" in\n.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;\n*)\n  ac_dir_suffix=/`printf \"%s\\n\" \"$ac_dir\" | sed 's|^\\.[\\\\/]||'`\n  # A \"..\" for each directory in $ac_dir_suffix.\n  ac_top_builddir_sub=`printf \"%s\\n\" \"$ac_dir_suffix\" | sed 's|/[^\\\\/]*|/..|g;s|/||'`\n  case $ac_top_builddir_sub in\n  \"\") ac_top_builddir_sub=. ac_top_build_prefix= ;;\n  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;\n  esac ;;\nesac\nac_abs_top_builddir=$ac_pwd\nac_abs_builddir=$ac_pwd$ac_dir_suffix\n# for backward compatibility:\nac_top_builddir=$ac_top_build_prefix\n\ncase $srcdir in\n  .)  # We are building in place.\n    ac_srcdir=.\n    ac_top_srcdir=$ac_top_builddir_sub\n    ac_abs_top_srcdir=$ac_pwd ;;\n  [\\\\/]* | ?:[\\\\/]* )  # Absolute name.\n    ac_srcdir=$srcdir$ac_dir_suffix;\n    ac_top_srcdir=$srcdir\n    ac_abs_top_srcdir=$srcdir ;;\n  *) # Relative name.\n    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix\n    ac_top_srcdir=$ac_top_build_prefix$srcdir\n    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;\nesac\nac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix\n\n\n  case $ac_mode in\n  :F)\n  #\n  # CONFIG_FILE\n  #\n\n  case $INSTALL in\n  [\\\\/$]* | ?:[\\\\/]* ) ac_INSTALL=$INSTALL ;;\n  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;\n  esac\n  ac_MKDIR_P=$MKDIR_P\n  case $MKDIR_P in\n  [\\\\/$]* | ?:[\\\\/]* ) ;;\n  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;\n  esac\n_ACEOF\n\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n# If the template does not know about datarootdir, expand it.\n# FIXME: This hack should be removed a few years after 2.60.\nac_datarootdir_hack=; ac_datarootdir_seen=\nac_sed_dataroot='\n/datarootdir/ {\n  p\n  q\n}\n/@datadir@/p\n/@docdir@/p\n/@infodir@/p\n/@localedir@/p\n/@mandir@/p'\ncase `eval \"sed -n \\\"\\$ac_sed_dataroot\\\" $ac_file_inputs\"` in\n*datarootdir*) ac_datarootdir_seen=yes;;\n*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting\" >&2;}\n_ACEOF\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\n  ac_datarootdir_hack='\n  s&@datadir@&$datadir&g\n  s&@docdir@&$docdir&g\n  s&@infodir@&$infodir&g\n  s&@localedir@&$localedir&g\n  s&@mandir@&$mandir&g\n  s&\\\\\\${datarootdir}&$datarootdir&g' ;;\nesac\n_ACEOF\n\n# Neutralize VPATH when `$srcdir' = `.'.\n# Shell code in configure.ac might set extrasub.\n# FIXME: do we really want to maintain this feature?\ncat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1\nac_sed_extra=\"$ac_vpsub\n$extrasub\n_ACEOF\ncat >>$CONFIG_STATUS <<\\_ACEOF || ac_write_fail=1\n:t\n/@[a-zA-Z_][a-zA-Z_0-9]*@/!b\ns|@configure_input@|$ac_sed_conf_input|;t t\ns&@top_builddir@&$ac_top_builddir_sub&;t t\ns&@top_build_prefix@&$ac_top_build_prefix&;t t\ns&@srcdir@&$ac_srcdir&;t t\ns&@abs_srcdir@&$ac_abs_srcdir&;t t\ns&@top_srcdir@&$ac_top_srcdir&;t t\ns&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t\ns&@builddir@&$ac_builddir&;t t\ns&@abs_builddir@&$ac_abs_builddir&;t t\ns&@abs_top_builddir@&$ac_abs_top_builddir&;t t\ns&@INSTALL@&$ac_INSTALL&;t t\ns&@MKDIR_P@&$ac_MKDIR_P&;t t\n$ac_datarootdir_hack\n\"\neval sed \\\"\\$ac_sed_extra\\\" \"$ac_file_inputs\" | $AWK -f \"$ac_tmp/subs.awk\" \\\n  >$ac_tmp/out || as_fn_error $? \"could not create $ac_file\" \"$LINENO\" 5\n\ntest -z \"$ac_datarootdir_hack$ac_datarootdir_seen\" &&\n  { ac_out=`sed -n '/\\${datarootdir}/p' \"$ac_tmp/out\"`; test -n \"$ac_out\"; } &&\n  { ac_out=`sed -n '/^[\t ]*datarootdir[\t ]*:*=/p' \\\n      \"$ac_tmp/out\"`; test -z \"$ac_out\"; } &&\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \\`datarootdir'\nwhich seems to be undefined.  Please make sure it is defined\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: $ac_file contains a reference to the variable \\`datarootdir'\nwhich seems to be undefined.  Please make sure it is defined\" >&2;}\n\n  rm -f \"$ac_tmp/stdin\"\n  case $ac_file in\n  -) cat \"$ac_tmp/out\" && rm -f \"$ac_tmp/out\";;\n  *) rm -f \"$ac_file\" && mv \"$ac_tmp/out\" \"$ac_file\";;\n  esac \\\n  || as_fn_error $? \"could not create $ac_file\" \"$LINENO\" 5\n ;;\n  :H)\n  #\n  # CONFIG_HEADER\n  #\n  if test x\"$ac_file\" != x-; then\n    {\n      printf \"%s\\n\" \"/* $configure_input  */\" >&1 \\\n      && eval '$AWK -f \"$ac_tmp/defines.awk\"' \"$ac_file_inputs\"\n    } >\"$ac_tmp/config.h\" \\\n      || as_fn_error $? \"could not create $ac_file\" \"$LINENO\" 5\n    if diff \"$ac_file\" \"$ac_tmp/config.h\" >/dev/null 2>&1; then\n      { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: $ac_file is unchanged\" >&5\nprintf \"%s\\n\" \"$as_me: $ac_file is unchanged\" >&6;}\n    else\n      rm -f \"$ac_file\"\n      mv \"$ac_tmp/config.h\" \"$ac_file\" \\\n\t|| as_fn_error $? \"could not create $ac_file\" \"$LINENO\" 5\n    fi\n  else\n    printf \"%s\\n\" \"/* $configure_input  */\" >&1 \\\n      && eval '$AWK -f \"$ac_tmp/defines.awk\"' \"$ac_file_inputs\" \\\n      || as_fn_error $? \"could not create -\" \"$LINENO\" 5\n  fi\n# Compute \"$ac_file\"'s index in $config_headers.\n_am_arg=\"$ac_file\"\n_am_stamp_count=1\nfor _am_header in $config_headers :; do\n  case $_am_header in\n    $_am_arg | $_am_arg:* )\n      break ;;\n    * )\n      _am_stamp_count=`expr $_am_stamp_count + 1` ;;\n  esac\ndone\necho \"timestamp for $_am_arg\" >`$as_dirname -- \"$_am_arg\" ||\n$as_expr X\"$_am_arg\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$_am_arg\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$_am_arg\" : 'X\\(//\\)$' \\| \\\n\t X\"$_am_arg\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$_am_arg\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`/stamp-h$_am_stamp_count\n ;;\n\n  :C)  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: executing $ac_file commands\" >&5\nprintf \"%s\\n\" \"$as_me: executing $ac_file commands\" >&6;}\n ;;\n  esac\n\n\n  case $ac_file$ac_mode in\n    \"depfiles\":C) test x\"$AMDEP_TRUE\" != x\"\" || {\n  # Older Autoconf quotes --file arguments for eval, but not when files\n  # are listed without --file.  Let's play safe and only enable the eval\n  # if we detect the quoting.\n  # TODO: see whether this extra hack can be removed once we start\n  # requiring Autoconf 2.70 or later.\n  case $CONFIG_FILES in #(\n  *\\'*) :\n    eval set x \"$CONFIG_FILES\" ;; #(\n  *) :\n    set x $CONFIG_FILES ;; #(\n  *) :\n     ;;\nesac\n  shift\n  # Used to flag and report bootstrapping failures.\n  am_rc=0\n  for am_mf\n  do\n    # Strip MF so we end up with the name of the file.\n    am_mf=`printf \"%s\\n\" \"$am_mf\" | sed -e 's/:.*$//'`\n    # Check whether this is an Automake generated Makefile which includes\n    # dependency-tracking related rules and includes.\n    # Grep'ing the whole file directly is not great: AIX grep has a line\n    # limit of 2048, but all sed's we know have understand at least 4000.\n    sed -n 's,^am--depfiles:.*,X,p' \"$am_mf\" | grep X >/dev/null 2>&1 \\\n      || continue\n    am_dirpart=`$as_dirname -- \"$am_mf\" ||\n$as_expr X\"$am_mf\" : 'X\\(.*[^/]\\)//*[^/][^/]*/*$' \\| \\\n\t X\"$am_mf\" : 'X\\(//\\)[^/]' \\| \\\n\t X\"$am_mf\" : 'X\\(//\\)$' \\| \\\n\t X\"$am_mf\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X\"$am_mf\" |\n    sed '/^X\\(.*[^/]\\)\\/\\/*[^/][^/]*\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)[^/].*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n    am_filepart=`$as_basename -- \"$am_mf\" ||\n$as_expr X/\"$am_mf\" : '.*/\\([^/][^/]*\\)/*$' \\| \\\n\t X\"$am_mf\" : 'X\\(//\\)$' \\| \\\n\t X\"$am_mf\" : 'X\\(/\\)' \\| . 2>/dev/null ||\nprintf \"%s\\n\" X/\"$am_mf\" |\n    sed '/^.*\\/\\([^/][^/]*\\)\\/*$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\/\\)$/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  /^X\\/\\(\\/\\).*/{\n\t    s//\\1/\n\t    q\n\t  }\n\t  s/.*/./; q'`\n    { echo \"$as_me:$LINENO: cd \"$am_dirpart\" \\\n      && sed -e '/# am--include-marker/d' \"$am_filepart\" \\\n        | $MAKE -f - am--depfiles\" >&5\n   (cd \"$am_dirpart\" \\\n      && sed -e '/# am--include-marker/d' \"$am_filepart\" \\\n        | $MAKE -f - am--depfiles) >&5 2>&5\n   ac_status=$?\n   echo \"$as_me:$LINENO: \\$? = $ac_status\" >&5\n   (exit $ac_status); } || am_rc=$?\n  done\n  if test $am_rc -ne 0; then\n    { { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: error: in \\`$ac_pwd':\" >&5\nprintf \"%s\\n\" \"$as_me: error: in \\`$ac_pwd':\" >&2;}\nas_fn_error $? \"Something went wrong bootstrapping makefile fragments\n    for automatic dependency tracking.  If GNU make was not used, consider\n    re-running the configure script with MAKE=\\\"gmake\\\" (or whatever is\n    necessary).  You can also try re-running configure with the\n    '--disable-dependency-tracking' option to at least be able to build\n    the package (albeit without support for automatic dependency tracking).\nSee \\`config.log' for more details\" \"$LINENO\" 5; }\n  fi\n  { am_dirpart=; unset am_dirpart;}\n  { am_filepart=; unset am_filepart;}\n  { am_mf=; unset am_mf;}\n  { am_rc=; unset am_rc;}\n  rm -f conftest-deps.mk\n}\n ;;\n\n  esac\ndone # for ac_tag\n\n\nas_fn_exit 0\n_ACEOF\nac_clean_files=$ac_clean_files_save\n\ntest $ac_write_fail = 0 ||\n  as_fn_error $? \"write failure creating $CONFIG_STATUS\" \"$LINENO\" 5\n\n\n# configure is writing to config.log, and then calls config.status.\n# config.status does its own redirection, appending to config.log.\n# Unfortunately, on DOS this fails, as config.log is still kept open\n# by configure, so config.status won't be able to write to it; its\n# output is simply discarded.  So we exec the FD to /dev/null,\n# effectively closing config.log, so it can be properly (re)opened and\n# appended to by config.status.  When coming back to configure, we\n# need to make the FD available again.\nif test \"$no_create\" != yes; then\n  ac_cs_success=:\n  ac_config_status_args=\n  test \"$silent\" = yes &&\n    ac_config_status_args=\"$ac_config_status_args --quiet\"\n  exec 5>/dev/null\n  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false\n  exec 5>>config.log\n  # Use ||, not &&, to avoid exiting from the if with $? = 1, which\n  # would make configure fail if this is the last instruction.\n  $ac_cs_success || as_fn_exit 1\nfi\nif test -n \"$ac_unrecognized_opts\" && test \"$enable_option_checking\" != no; then\n  { printf \"%s\\n\" \"$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts\" >&5\nprintf \"%s\\n\" \"$as_me: WARNING: unrecognized options: $ac_unrecognized_opts\" >&2;}\nfi\n\n\n"
  },
  {
    "path": "windows_compat/gnulib/configure.ac",
    "content": "# Process this file with autoconf to produce a configure script.\nAC_INIT([dummy], [0])\nAC_CONFIG_AUX_DIR([build-aux])\nAM_INIT_AUTOMAKE\n\nAC_CONFIG_HEADERS([config.h])\n\nAC_PROG_CC\nAC_PROG_INSTALL\nAC_PROG_MAKE_SET\n\n# For autobuild.\nAC_CANONICAL_BUILD\nAC_CANONICAL_HOST\n\nm4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace\nm4_pattern_allow([^gl_ES$])dnl a valid locale name\nm4_pattern_allow([^gl_LIBOBJS$])dnl a variable\nm4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable\n\n# Pre-early section.\ngl_USE_SYSTEM_EXTENSIONS\ngl_PROG_AR_RANLIB\n\nAM_CONDITIONAL([GL_COND_LIBTOOL], [false])\ngl_cond_libtool=false\ngl_libdeps=\ngl_ltlibdeps=\nAC_DEFUN([gl_INIT], [\ngl_m4_base='glm4'\n  m4_pushdef([AC_LIBOBJ], m4_defn([gl_LIBOBJ]))\n  m4_pushdef([AC_REPLACE_FUNCS], m4_defn([gl_REPLACE_FUNCS]))\n  m4_pushdef([AC_LIBSOURCES], m4_defn([gl_LIBSOURCES]))\n  m4_pushdef([gl_LIBSOURCES_LIST], [])\n  m4_pushdef([gl_LIBSOURCES_DIR], [])\n  m4_pushdef([GL_MACRO_PREFIX], [gl])\n  m4_pushdef([GL_MODULE_INDICATOR_PREFIX], [GL])\n  gl_COMMON\ngl_source_base='gllib'\n  gl_HEADER_ERRNO_H\n  gl_EXECINFO_H\n  AC_REQUIRE([gl_EXTERN_INLINE])\n  gl_FUNC_GETDELIM\n  if test $HAVE_GETDELIM = 0 || test $REPLACE_GETDELIM = 1; then\n    AC_LIBOBJ([getdelim])\n    gl_PREREQ_GETDELIM\n  fi\n  gl_STDIO_MODULE_INDICATOR([getdelim])\n  gl_FUNC_GETHOSTNAME\n  if test $HAVE_GETHOSTNAME = 0; then\n    AC_LIBOBJ([gethostname])\n    gl_PREREQ_GETHOSTNAME\n  fi\n  gl_UNISTD_MODULE_INDICATOR([gethostname])\n  gl_FUNC_GETLINE\n  if test $REPLACE_GETLINE = 1; then\n    AC_LIBOBJ([getline])\n    gl_PREREQ_GETLINE\n  fi\n  gl_STDIO_MODULE_INDICATOR([getline])\n  gl_FUNC_GETTIMEOFDAY\n  if test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1; then\n    AC_LIBOBJ([gettimeofday])\n    gl_PREREQ_GETTIMEOFDAY\n  fi\n  gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])\n  gl___INLINE\n  gl_LIMITS_H\n  AC_REQUIRE([gl_MSVC_INVAL])\n  if test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1; then\n    AC_LIBOBJ([msvc-inval])\n  fi\n  AC_REQUIRE([gl_MSVC_NOTHROW])\n  if test $HAVE_MSVC_INVALID_PARAMETER_HANDLER = 1; then\n    AC_LIBOBJ([msvc-nothrow])\n  fi\n  gl_MODULE_INDICATOR([msvc-nothrow])\n  gl_MULTIARCH\n  gl_FUNC_RANDOM\n  if test $HAVE_RANDOM = 0 || test $REPLACE_RANDOM = 1 || test $REPLACE_INITSTATE = 1 || test $REPLACE_SETSTATE = 1; then\n    AC_LIBOBJ([random])\n    gl_PREREQ_RANDOM\n  fi\n  gl_STDLIB_MODULE_INDICATOR([random])\n  gl_FUNC_RANDOM_R\n  if test $HAVE_RANDOM_R = 0 || test $REPLACE_RANDOM_R = 1; then\n    AC_LIBOBJ([random_r])\n    gl_PREREQ_RANDOM_R\n  fi\n  gl_STDLIB_MODULE_INDICATOR([random_r])\n  AC_REQUIRE([gl_SOCKETLIB])\n  AC_REQUIRE([gl_SOCKETS])\n  gl_TYPE_SOCKLEN_T\n  gt_TYPE_SSIZE_T\n  gl_STDALIGN_H\n  gl_STDDEF_H\n  gl_STDDEF_H_REQUIRE_DEFAULTS\n  gl_STDINT_H\n  gl_STDIO_H\n  gl_STDIO_H_REQUIRE_DEFAULTS\n  dnl No need to create extra modules for these functions. Everyone who uses\n  dnl <stdio.h> likely needs them.\n  gl_STDIO_MODULE_INDICATOR([fscanf])\n  gl_MODULE_INDICATOR([fscanf])\n  gl_STDIO_MODULE_INDICATOR([scanf])\n  gl_MODULE_INDICATOR([scanf])\n  gl_STDIO_MODULE_INDICATOR([fgetc])\n  gl_STDIO_MODULE_INDICATOR([getc])\n  gl_STDIO_MODULE_INDICATOR([getchar])\n  gl_STDIO_MODULE_INDICATOR([fgets])\n  gl_STDIO_MODULE_INDICATOR([fread])\n  dnl No need to create extra modules for these functions. Everyone who uses\n  dnl <stdio.h> likely needs them.\n  gl_STDIO_MODULE_INDICATOR([fprintf])\n  gl_STDIO_MODULE_INDICATOR([printf])\n  gl_STDIO_MODULE_INDICATOR([vfprintf])\n  gl_STDIO_MODULE_INDICATOR([vprintf])\n  gl_STDIO_MODULE_INDICATOR([fputc])\n  gl_STDIO_MODULE_INDICATOR([putc])\n  gl_STDIO_MODULE_INDICATOR([putchar])\n  gl_STDIO_MODULE_INDICATOR([fputs])\n  gl_STDIO_MODULE_INDICATOR([puts])\n  gl_STDIO_MODULE_INDICATOR([fwrite])\n  gl_STDLIB_H\n  gl_STDLIB_H_REQUIRE_DEFAULTS\n  gl_SYS_RESOURCE_H\n  gl_SYS_RESOURCE_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_SOCKET_H\n  gl_SYS_SOCKET_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_STAT_H\n  gl_SYS_STAT_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_TIME_H\n  gl_SYS_TIME_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_TYPES_H\n  gl_SYS_TYPES_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_UIO_H\n  gl_SYS_UIO_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_SYS_UTSNAME_H\n  gl_SYS_UTSNAME_H_REQUIRE_DEFAULTS\n  AC_PROG_MKDIR_P\n  gl_TIME_H\n  gl_TIME_H_REQUIRE_DEFAULTS\n  gl_TIME_R\n  if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then\n    AC_LIBOBJ([time_r])\n    gl_PREREQ_TIME_R\n  fi\n  gl_TIME_MODULE_INDICATOR([time_r])\n  gl_FUNC_UNAME\n  if test $HAVE_UNAME = 0; then\n    AC_LIBOBJ([uname])\n    gl_PREREQ_UNAME\n  fi\n  gl_SYS_UTSNAME_MODULE_INDICATOR([uname])\n  gl_UNISTD_H\n  gl_UNISTD_H_REQUIRE_DEFAULTS\n  m4_ifval(gl_LIBSOURCES_LIST, [\n    m4_syscmd([test ! -d ]m4_defn([gl_LIBSOURCES_DIR])[ ||\n      for gl_file in ]gl_LIBSOURCES_LIST[ ; do\n        if test ! -r ]m4_defn([gl_LIBSOURCES_DIR])[/$gl_file ; then\n          echo \"missing file ]m4_defn([gl_LIBSOURCES_DIR])[/$gl_file\" >&2\n          exit 1\n        fi\n      done])dnl\n      m4_if(m4_sysval, [0], [],\n        [AC_FATAL([expected source file, required through AC_LIBSOURCES, not found])])\n  ])\n  m4_popdef([GL_MODULE_INDICATOR_PREFIX])\n  m4_popdef([GL_MACRO_PREFIX])\n  m4_popdef([gl_LIBSOURCES_DIR])\n  m4_popdef([gl_LIBSOURCES_LIST])\n  m4_popdef([AC_LIBSOURCES])\n  m4_popdef([AC_REPLACE_FUNCS])\n  m4_popdef([AC_LIBOBJ])\n  AC_CONFIG_COMMANDS_PRE([\n    gl_libobjs=\n    gl_ltlibobjs=\n    if test -n \"$gl_LIBOBJS\"; then\n      # Remove the extension.\n      sed_drop_objext='s/\\.o$//;s/\\.obj$//'\n      for i in `for i in $gl_LIBOBJS; do echo \"$i\"; done | sed -e \"$sed_drop_objext\" | sort | uniq`; do\n        gl_libobjs=\"$gl_libobjs $i.$ac_objext\"\n        gl_ltlibobjs=\"$gl_ltlibobjs $i.lo\"\n      done\n    fi\n    AC_SUBST([gl_LIBOBJS], [$gl_libobjs])\n    AC_SUBST([gl_LTLIBOBJS], [$gl_ltlibobjs])\n  ])\n  LIBGNU_LIBDEPS=\"$gl_libdeps\"\n  AC_SUBST([LIBGNU_LIBDEPS])\n  LIBGNU_LTLIBDEPS=\"$gl_ltlibdeps\"\n  AC_SUBST([LIBGNU_LTLIBDEPS])\n])\n\n# Like AC_LIBOBJ, except that the module name goes\n# into gl_LIBOBJS instead of into LIBOBJS.\nAC_DEFUN([gl_LIBOBJ], [\n  AS_LITERAL_IF([$1], [gl_LIBSOURCES([$1.c])])dnl\n  gl_LIBOBJS=\"$gl_LIBOBJS $1.$ac_objext\"\n])\n\n# Like AC_REPLACE_FUNCS, except that the module name goes\n# into gl_LIBOBJS instead of into LIBOBJS.\nAC_DEFUN([gl_REPLACE_FUNCS], [\n  m4_foreach_w([gl_NAME], [$1], [AC_LIBSOURCES(gl_NAME[.c])])dnl\n  AC_CHECK_FUNCS([$1], , [gl_LIBOBJ($ac_func)])\n])\n\n# Like AC_LIBSOURCES, except the directory where the source file is\n# expected is derived from the gnulib-tool parameterization,\n# and alloca is special cased (for the alloca-opt module).\n# We could also entirely rely on EXTRA_lib..._SOURCES.\nAC_DEFUN([gl_LIBSOURCES], [\n  m4_foreach([_gl_NAME], [$1], [\n    m4_if(_gl_NAME, [alloca.c], [], [\n      m4_define([gl_LIBSOURCES_DIR], [gllib])\n      m4_append([gl_LIBSOURCES_LIST], _gl_NAME, [ ])\n    ])\n  ])\n])\n\ngl_INIT\n\nAC_CONFIG_FILES([Makefile gllib/Makefile glm4/Makefile])\nAC_OUTPUT\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/Makefile.am",
    "content": "## DO NOT EDIT! GENERATED AUTOMATICALLY!\n## Process this file with automake to produce Makefile.in.\n# Copyright (C) 2002-2021 Free Software Foundation, Inc.\n#\n# This file is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This file is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this file.  If not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License,\n# this file may be distributed as part of a program that\n# contains a configuration script generated by Autoconf, under\n# the same distribution terms as the rest of that program.\n#\n# Generated by gnulib-tool.\n\nAUTOMAKE_OPTIONS = 1.11 gnits\n\nSUBDIRS =\nnoinst_HEADERS =\nnoinst_LIBRARIES =\nnoinst_LTLIBRARIES =\nEXTRA_DIST =\nBUILT_SOURCES =\nSUFFIXES =\nMOSTLYCLEANFILES = core *.stackdump\nMOSTLYCLEANDIRS =\nCLEANFILES =\nDISTCLEANFILES =\nMAINTAINERCLEANFILES =\n# No GNU Make output.\n\nAM_CPPFLAGS = -DGNULIB_STRICT_CHECKING=1\nAM_CFLAGS =\n\nnoinst_LIBRARIES += libgnu.a\n\nlibgnu_a_SOURCES =\nlibgnu_a_LIBADD = $(gl_LIBOBJS)\nlibgnu_a_DEPENDENCIES = $(gl_LIBOBJS)\nEXTRA_libgnu_a_SOURCES =\n\n## begin gnulib module absolute-header\n\n# Use this preprocessor expression to decide whether #include_next works.\n# Do not rely on a 'configure'-time test for this, since the expression\n# might appear in an installed header, which is used by some other compiler.\nHAVE_INCLUDE_NEXT = (__GNUC__ || __clang__ || 60000000 <= __DECC_VER)\n\n## end   gnulib module absolute-header\n\n## begin gnulib module errno\n\nBUILT_SOURCES += $(ERRNO_H)\n\n# We need the following in order to create <errno.h> when the system\n# doesn't have one that is POSIX compliant.\nif GL_GENERATE_ERRNO_H\nerrno.h: errno.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_ERRNO_H''@|$(NEXT_ERRNO_H)|g' \\\n\t      -e 's|@''EMULTIHOP_HIDDEN''@|$(EMULTIHOP_HIDDEN)|g' \\\n\t      -e 's|@''EMULTIHOP_VALUE''@|$(EMULTIHOP_VALUE)|g' \\\n\t      -e 's|@''ENOLINK_HIDDEN''@|$(ENOLINK_HIDDEN)|g' \\\n\t      -e 's|@''ENOLINK_VALUE''@|$(ENOLINK_VALUE)|g' \\\n\t      -e 's|@''EOVERFLOW_HIDDEN''@|$(EOVERFLOW_HIDDEN)|g' \\\n\t      -e 's|@''EOVERFLOW_VALUE''@|$(EOVERFLOW_VALUE)|g' \\\n\t      < $(srcdir)/errno.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nerrno.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += errno.h errno.h-t\n\nEXTRA_DIST += errno.in.h\n\n## end   gnulib module errno\n\n## begin gnulib module execinfo\n\nBUILT_SOURCES += $(EXECINFO_H)\n\n# We need the following in order to create <execinfo.h> when the system\n# doesn't have one that works.\nif GL_GENERATE_EXECINFO_H\nexecinfo.h: execinfo.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  cat $(srcdir)/execinfo.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nexecinfo.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += execinfo.h execinfo.h-t\n\nEXTRA_DIST += execinfo.c execinfo.in.h\n\nEXTRA_libgnu_a_SOURCES += execinfo.c\n\n## end   gnulib module execinfo\n\n## begin gnulib module fd-hook\n\nlibgnu_a_SOURCES += fd-hook.c\n\nEXTRA_DIST += fd-hook.h\n\n## end   gnulib module fd-hook\n\n## begin gnulib module getdelim\n\n\nEXTRA_DIST += getdelim.c\n\nEXTRA_libgnu_a_SOURCES += getdelim.c\n\n## end   gnulib module getdelim\n\n## begin gnulib module gethostname\n\n\nEXTRA_DIST += gethostname.c w32sock.h\n\nEXTRA_libgnu_a_SOURCES += gethostname.c\n\n## end   gnulib module gethostname\n\n## begin gnulib module getline\n\n\nEXTRA_DIST += getline.c\n\nEXTRA_libgnu_a_SOURCES += getline.c\n\n## end   gnulib module getline\n\n## begin gnulib module gettimeofday\n\n\nEXTRA_DIST += gettimeofday.c\n\nEXTRA_libgnu_a_SOURCES += gettimeofday.c\n\n## end   gnulib module gettimeofday\n\n## begin gnulib module libc-config\n\n\nEXTRA_DIST += cdefs.h libc-config.h\n\n## end   gnulib module libc-config\n\n## begin gnulib module limits-h\n\nBUILT_SOURCES += $(LIMITS_H)\n\n# We need the following in order to create <limits.h> when the system\n# doesn't have one that is compatible with GNU.\nif GL_GENERATE_LIMITS_H\nlimits.h: limits.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_LIMITS_H''@|$(NEXT_LIMITS_H)|g' \\\n\t      < $(srcdir)/limits.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nlimits.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += limits.h limits.h-t\n\nEXTRA_DIST += limits.in.h\n\n## end   gnulib module limits-h\n\n## begin gnulib module msvc-inval\n\n\nEXTRA_DIST += msvc-inval.c msvc-inval.h\n\nEXTRA_libgnu_a_SOURCES += msvc-inval.c\n\n## end   gnulib module msvc-inval\n\n## begin gnulib module msvc-nothrow\n\n\nEXTRA_DIST += msvc-nothrow.c msvc-nothrow.h\n\nEXTRA_libgnu_a_SOURCES += msvc-nothrow.c\n\n## end   gnulib module msvc-nothrow\n\n## begin gnulib module random\n\n\nEXTRA_DIST += random.c\n\nEXTRA_libgnu_a_SOURCES += random.c\n\n## end   gnulib module random\n\n## begin gnulib module random_r\n\n\nEXTRA_DIST += random_r.c\n\nEXTRA_libgnu_a_SOURCES += random_r.c\n\n## end   gnulib module random_r\n\n## begin gnulib module snippet/_Noreturn\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\n\n_NORETURN_H=$(srcdir)/_Noreturn.h\n\nEXTRA_DIST += _Noreturn.h\n\n## end   gnulib module snippet/_Noreturn\n\n## begin gnulib module snippet/arg-nonnull\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\n\nARG_NONNULL_H=$(srcdir)/arg-nonnull.h\n\nEXTRA_DIST += arg-nonnull.h\n\n## end   gnulib module snippet/arg-nonnull\n\n## begin gnulib module snippet/c++defs\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\n\nCXXDEFS_H=$(srcdir)/c++defs.h\n\nEXTRA_DIST += c++defs.h\n\n## end   gnulib module snippet/c++defs\n\n## begin gnulib module snippet/warn-on-use\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\n\nWARN_ON_USE_H=$(srcdir)/warn-on-use.h\n\nEXTRA_DIST += warn-on-use.h\n\n## end   gnulib module snippet/warn-on-use\n\n## begin gnulib module sockets\n\nlibgnu_a_SOURCES += sockets.h sockets.c\n\nEXTRA_DIST += w32sock.h\n\n## end   gnulib module sockets\n\n## begin gnulib module stdalign\n\nBUILT_SOURCES += $(STDALIGN_H)\n\n# We need the following in order to create <stdalign.h> when the system\n# doesn't have one that works.\nif GL_GENERATE_STDALIGN_H\nstdalign.h: stdalign.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  cat $(srcdir)/stdalign.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nstdalign.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += stdalign.h stdalign.h-t\n\nEXTRA_DIST += stdalign.in.h\n\n## end   gnulib module stdalign\n\n## begin gnulib module stddef\n\nBUILT_SOURCES += $(STDDEF_H)\n\n# We need the following in order to create <stddef.h> when the system\n# doesn't have one that works with the given compiler.\nif GL_GENERATE_STDDEF_H\nstddef.h: stddef.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDDEF_H''@|$(NEXT_STDDEF_H)|g' \\\n\t      -e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \\\n\t      -e 's|@''HAVE_WCHAR_T''@|$(HAVE_WCHAR_T)|g' \\\n\t      -e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \\\n\t      < $(srcdir)/stddef.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nstddef.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += stddef.h stddef.h-t\n\nEXTRA_DIST += stddef.in.h\n\n## end   gnulib module stddef\n\n## begin gnulib module stdint\n\nBUILT_SOURCES += $(STDINT_H)\n\n# We need the following in order to create <stdint.h> when the system\n# doesn't have one that works with the given compiler.\nif GL_GENERATE_STDINT_H\nstdint.h: stdint.in.h $(top_builddir)/config.status\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's/@''HAVE_STDINT_H''@/$(HAVE_STDINT_H)/g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDINT_H''@|$(NEXT_STDINT_H)|g' \\\n\t      -e 's/@''HAVE_C99_STDINT_H''@/$(HAVE_C99_STDINT_H)/g' \\\n\t      -e 's/@''HAVE_SYS_TYPES_H''@/$(HAVE_SYS_TYPES_H)/g' \\\n\t      -e 's/@''HAVE_INTTYPES_H''@/$(HAVE_INTTYPES_H)/g' \\\n\t      -e 's/@''HAVE_SYS_INTTYPES_H''@/$(HAVE_SYS_INTTYPES_H)/g' \\\n\t      -e 's/@''HAVE_SYS_BITYPES_H''@/$(HAVE_SYS_BITYPES_H)/g' \\\n\t      -e 's/@''HAVE_WCHAR_H''@/$(HAVE_WCHAR_H)/g' \\\n\t      -e 's/@''APPLE_UNIVERSAL_BUILD''@/$(APPLE_UNIVERSAL_BUILD)/g' \\\n\t      -e 's/@''BITSIZEOF_PTRDIFF_T''@/$(BITSIZEOF_PTRDIFF_T)/g' \\\n\t      -e 's/@''PTRDIFF_T_SUFFIX''@/$(PTRDIFF_T_SUFFIX)/g' \\\n\t      -e 's/@''BITSIZEOF_SIG_ATOMIC_T''@/$(BITSIZEOF_SIG_ATOMIC_T)/g' \\\n\t      -e 's/@''HAVE_SIGNED_SIG_ATOMIC_T''@/$(HAVE_SIGNED_SIG_ATOMIC_T)/g' \\\n\t      -e 's/@''SIG_ATOMIC_T_SUFFIX''@/$(SIG_ATOMIC_T_SUFFIX)/g' \\\n\t      -e 's/@''BITSIZEOF_SIZE_T''@/$(BITSIZEOF_SIZE_T)/g' \\\n\t      -e 's/@''SIZE_T_SUFFIX''@/$(SIZE_T_SUFFIX)/g' \\\n\t      -e 's/@''BITSIZEOF_WCHAR_T''@/$(BITSIZEOF_WCHAR_T)/g' \\\n\t      -e 's/@''HAVE_SIGNED_WCHAR_T''@/$(HAVE_SIGNED_WCHAR_T)/g' \\\n\t      -e 's/@''WCHAR_T_SUFFIX''@/$(WCHAR_T_SUFFIX)/g' \\\n\t      -e 's/@''BITSIZEOF_WINT_T''@/$(BITSIZEOF_WINT_T)/g' \\\n\t      -e 's/@''HAVE_SIGNED_WINT_T''@/$(HAVE_SIGNED_WINT_T)/g' \\\n\t      -e 's/@''WINT_T_SUFFIX''@/$(WINT_T_SUFFIX)/g' \\\n\t      -e 's/@''GNULIBHEADERS_OVERRIDE_WINT_T''@/$(GNULIBHEADERS_OVERRIDE_WINT_T)/g' \\\n\t      < $(srcdir)/stdint.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nelse\nstdint.h: $(top_builddir)/config.status\n\trm -f $@\nendif\nMOSTLYCLEANFILES += stdint.h stdint.h-t\n\nEXTRA_DIST += stdint.in.h\n\n## end   gnulib module stdint\n\n## begin gnulib module stdio\n\nBUILT_SOURCES += stdio.h\n\n# We need the following in order to create <stdio.h> when the system\n# doesn't have one that works with the given compiler.\nstdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \\\n\t      -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \\\n\t      -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \\\n\t      -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \\\n\t      -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \\\n\t      -e 's/@''GNULIB_FGETC''@/$(GL_GNULIB_FGETC)/g' \\\n\t      -e 's/@''GNULIB_FGETS''@/$(GL_GNULIB_FGETS)/g' \\\n\t      -e 's/@''GNULIB_FOPEN''@/$(GL_GNULIB_FOPEN)/g' \\\n\t      -e 's/@''GNULIB_FPRINTF''@/$(GL_GNULIB_FPRINTF)/g' \\\n\t      -e 's/@''GNULIB_FPRINTF_POSIX''@/$(GL_GNULIB_FPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_FPURGE''@/$(GL_GNULIB_FPURGE)/g' \\\n\t      -e 's/@''GNULIB_FPUTC''@/$(GL_GNULIB_FPUTC)/g' \\\n\t      -e 's/@''GNULIB_FPUTS''@/$(GL_GNULIB_FPUTS)/g' \\\n\t      -e 's/@''GNULIB_FREAD''@/$(GL_GNULIB_FREAD)/g' \\\n\t      -e 's/@''GNULIB_FREOPEN''@/$(GL_GNULIB_FREOPEN)/g' \\\n\t      -e 's/@''GNULIB_FSCANF''@/$(GL_GNULIB_FSCANF)/g' \\\n\t      -e 's/@''GNULIB_FSEEK''@/$(GL_GNULIB_FSEEK)/g' \\\n\t      -e 's/@''GNULIB_FSEEKO''@/$(GL_GNULIB_FSEEKO)/g' \\\n\t      -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \\\n\t      -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \\\n\t      -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \\\n\t      -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \\\n\t      -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \\\n\t      -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \\\n\t      -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \\\n\t      -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \\\n\t      -e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \\\n\t      -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \\\n\t      -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \\\n\t      -e 's/@''GNULIB_PRINTF''@/$(GL_GNULIB_PRINTF)/g' \\\n\t      -e 's/@''GNULIB_PRINTF_POSIX''@/$(GL_GNULIB_PRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_PUTC''@/$(GL_GNULIB_PUTC)/g' \\\n\t      -e 's/@''GNULIB_PUTCHAR''@/$(GL_GNULIB_PUTCHAR)/g' \\\n\t      -e 's/@''GNULIB_PUTS''@/$(GL_GNULIB_PUTS)/g' \\\n\t      -e 's/@''GNULIB_REMOVE''@/$(GL_GNULIB_REMOVE)/g' \\\n\t      -e 's/@''GNULIB_RENAME''@/$(GL_GNULIB_RENAME)/g' \\\n\t      -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \\\n\t      -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \\\n\t      -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \\\n\t      -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \\\n\t      -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \\\n\t      -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \\\n\t      -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \\\n\t      -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \\\n\t      -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \\\n\t      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \\\n\t      -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \\\n\t      -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \\\n\t      -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \\\n\t      < $(srcdir)/stdio.in.h | \\\n\t  sed -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \\\n\t      -e 's|@''HAVE_DECL_FPURGE''@|$(HAVE_DECL_FPURGE)|g' \\\n\t      -e 's|@''HAVE_DECL_FSEEKO''@|$(HAVE_DECL_FSEEKO)|g' \\\n\t      -e 's|@''HAVE_DECL_FTELLO''@|$(HAVE_DECL_FTELLO)|g' \\\n\t      -e 's|@''HAVE_DECL_GETDELIM''@|$(HAVE_DECL_GETDELIM)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLINE''@|$(HAVE_DECL_GETLINE)|g' \\\n\t      -e 's|@''HAVE_DECL_OBSTACK_PRINTF''@|$(HAVE_DECL_OBSTACK_PRINTF)|g' \\\n\t      -e 's|@''HAVE_DECL_SNPRINTF''@|$(HAVE_DECL_SNPRINTF)|g' \\\n\t      -e 's|@''HAVE_DECL_VSNPRINTF''@|$(HAVE_DECL_VSNPRINTF)|g' \\\n\t      -e 's|@''HAVE_DPRINTF''@|$(HAVE_DPRINTF)|g' \\\n\t      -e 's|@''HAVE_FSEEKO''@|$(HAVE_FSEEKO)|g' \\\n\t      -e 's|@''HAVE_FTELLO''@|$(HAVE_FTELLO)|g' \\\n\t      -e 's|@''HAVE_PCLOSE''@|$(HAVE_PCLOSE)|g' \\\n\t      -e 's|@''HAVE_POPEN''@|$(HAVE_POPEN)|g' \\\n\t      -e 's|@''HAVE_RENAMEAT''@|$(HAVE_RENAMEAT)|g' \\\n\t      -e 's|@''HAVE_VASPRINTF''@|$(HAVE_VASPRINTF)|g' \\\n\t      -e 's|@''HAVE_VDPRINTF''@|$(HAVE_VDPRINTF)|g' \\\n\t      -e 's|@''REPLACE_DPRINTF''@|$(REPLACE_DPRINTF)|g' \\\n\t      -e 's|@''REPLACE_FCLOSE''@|$(REPLACE_FCLOSE)|g' \\\n\t      -e 's|@''REPLACE_FDOPEN''@|$(REPLACE_FDOPEN)|g' \\\n\t      -e 's|@''REPLACE_FFLUSH''@|$(REPLACE_FFLUSH)|g' \\\n\t      -e 's|@''REPLACE_FOPEN''@|$(REPLACE_FOPEN)|g' \\\n\t      -e 's|@''REPLACE_FPRINTF''@|$(REPLACE_FPRINTF)|g' \\\n\t      -e 's|@''REPLACE_FPURGE''@|$(REPLACE_FPURGE)|g' \\\n\t      -e 's|@''REPLACE_FREOPEN''@|$(REPLACE_FREOPEN)|g' \\\n\t      -e 's|@''REPLACE_FSEEK''@|$(REPLACE_FSEEK)|g' \\\n\t      -e 's|@''REPLACE_FSEEKO''@|$(REPLACE_FSEEKO)|g' \\\n\t      -e 's|@''REPLACE_FTELL''@|$(REPLACE_FTELL)|g' \\\n\t      -e 's|@''REPLACE_FTELLO''@|$(REPLACE_FTELLO)|g' \\\n\t      -e 's|@''REPLACE_GETDELIM''@|$(REPLACE_GETDELIM)|g' \\\n\t      -e 's|@''REPLACE_GETLINE''@|$(REPLACE_GETLINE)|g' \\\n\t      -e 's|@''REPLACE_OBSTACK_PRINTF''@|$(REPLACE_OBSTACK_PRINTF)|g' \\\n\t      -e 's|@''REPLACE_PERROR''@|$(REPLACE_PERROR)|g' \\\n\t      -e 's|@''REPLACE_POPEN''@|$(REPLACE_POPEN)|g' \\\n\t      -e 's|@''REPLACE_PRINTF''@|$(REPLACE_PRINTF)|g' \\\n\t      -e 's|@''REPLACE_REMOVE''@|$(REPLACE_REMOVE)|g' \\\n\t      -e 's|@''REPLACE_RENAME''@|$(REPLACE_RENAME)|g' \\\n\t      -e 's|@''REPLACE_RENAMEAT''@|$(REPLACE_RENAMEAT)|g' \\\n\t      -e 's|@''REPLACE_SNPRINTF''@|$(REPLACE_SNPRINTF)|g' \\\n\t      -e 's|@''REPLACE_SPRINTF''@|$(REPLACE_SPRINTF)|g' \\\n\t      -e 's|@''REPLACE_STDIO_READ_FUNCS''@|$(REPLACE_STDIO_READ_FUNCS)|g' \\\n\t      -e 's|@''REPLACE_STDIO_WRITE_FUNCS''@|$(REPLACE_STDIO_WRITE_FUNCS)|g' \\\n\t      -e 's|@''REPLACE_TMPFILE''@|$(REPLACE_TMPFILE)|g' \\\n\t      -e 's|@''REPLACE_VASPRINTF''@|$(REPLACE_VASPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VDPRINTF''@|$(REPLACE_VDPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VFPRINTF''@|$(REPLACE_VFPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VPRINTF''@|$(REPLACE_VPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VSNPRINTF''@|$(REPLACE_VSNPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VSPRINTF''@|$(REPLACE_VSPRINTF)|g' \\\n\t      -e 's|@''ASM_SYMBOL_PREFIX''@|$(ASM_SYMBOL_PREFIX)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += stdio.h stdio.h-t\n\nEXTRA_DIST += stdio.in.h\n\n## end   gnulib module stdio\n\n## begin gnulib module stdlib\n\nBUILT_SOURCES += stdlib.h\n\n# We need the following in order to create <stdlib.h> when the system\n# doesn't have one that works with the given compiler.\nstdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \\\n  $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \\\n\t      -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \\\n\t      -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \\\n\t      -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \\\n\t      -e 's/@''GNULIB_CALLOC_POSIX''@/$(GL_GNULIB_CALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GL_GNULIB_CANONICALIZE_FILE_NAME)/g' \\\n\t      -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \\\n\t      -e 's/@''GNULIB_GETLOADAVG''@/$(GL_GNULIB_GETLOADAVG)/g' \\\n\t      -e 's/@''GNULIB_GETSUBOPT''@/$(GL_GNULIB_GETSUBOPT)/g' \\\n\t      -e 's/@''GNULIB_GRANTPT''@/$(GL_GNULIB_GRANTPT)/g' \\\n\t      -e 's/@''GNULIB_MALLOC_POSIX''@/$(GL_GNULIB_MALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_MBTOWC''@/$(GL_GNULIB_MBTOWC)/g' \\\n\t      -e 's/@''GNULIB_MKDTEMP''@/$(GL_GNULIB_MKDTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKOSTEMP''@/$(GL_GNULIB_MKOSTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKOSTEMPS''@/$(GL_GNULIB_MKOSTEMPS)/g' \\\n\t      -e 's/@''GNULIB_MKSTEMP''@/$(GL_GNULIB_MKSTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKSTEMPS''@/$(GL_GNULIB_MKSTEMPS)/g' \\\n\t      -e 's/@''GNULIB_POSIX_MEMALIGN''@/$(GL_GNULIB_POSIX_MEMALIGN)/g' \\\n\t      -e 's/@''GNULIB_POSIX_OPENPT''@/$(GL_GNULIB_POSIX_OPENPT)/g' \\\n\t      -e 's/@''GNULIB_PTSNAME''@/$(GL_GNULIB_PTSNAME)/g' \\\n\t      -e 's/@''GNULIB_PTSNAME_R''@/$(GL_GNULIB_PTSNAME_R)/g' \\\n\t      -e 's/@''GNULIB_PUTENV''@/$(GL_GNULIB_PUTENV)/g' \\\n\t      -e 's/@''GNULIB_QSORT_R''@/$(GL_GNULIB_QSORT_R)/g' \\\n\t      -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \\\n\t      -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \\\n\t      -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \\\n\t      -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \\\n\t      -e 's/@''GNULIB_RPMATCH''@/$(GL_GNULIB_RPMATCH)/g' \\\n\t      -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \\\n\t      -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \\\n\t      -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \\\n\t      -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \\\n\t      -e 's/@''GNULIB_STRTOLD''@/$(GL_GNULIB_STRTOLD)/g' \\\n\t      -e 's/@''GNULIB_STRTOLL''@/$(GL_GNULIB_STRTOLL)/g' \\\n\t      -e 's/@''GNULIB_STRTOUL''@/$(GL_GNULIB_STRTOUL)/g' \\\n\t      -e 's/@''GNULIB_STRTOULL''@/$(GL_GNULIB_STRTOULL)/g' \\\n\t      -e 's/@''GNULIB_SYSTEM_POSIX''@/$(GL_GNULIB_SYSTEM_POSIX)/g' \\\n\t      -e 's/@''GNULIB_UNLOCKPT''@/$(GL_GNULIB_UNLOCKPT)/g' \\\n\t      -e 's/@''GNULIB_UNSETENV''@/$(GL_GNULIB_UNSETENV)/g' \\\n\t      -e 's/@''GNULIB_WCTOMB''@/$(GL_GNULIB_WCTOMB)/g' \\\n\t      -e 's/@''GNULIB_MDA_ECVT''@/$(GL_GNULIB_MDA_ECVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_FCVT''@/$(GL_GNULIB_MDA_FCVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_GCVT''@/$(GL_GNULIB_MDA_GCVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_MKTEMP''@/$(GL_GNULIB_MDA_MKTEMP)/g' \\\n\t      -e 's/@''GNULIB_MDA_PUTENV''@/$(GL_GNULIB_MDA_PUTENV)/g' \\\n\t      < $(srcdir)/stdlib.in.h | \\\n\t  sed -e 's|@''HAVE__EXIT''@|$(HAVE__EXIT)|g' \\\n\t      -e 's|@''HAVE_ALIGNED_ALLOC''@|$(HAVE_ALIGNED_ALLOC)|g' \\\n\t      -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \\\n\t      -e 's|@''HAVE_CANONICALIZE_FILE_NAME''@|$(HAVE_CANONICALIZE_FILE_NAME)|g' \\\n\t      -e 's|@''HAVE_DECL_ECVT''@|$(HAVE_DECL_ECVT)|g' \\\n\t      -e 's|@''HAVE_DECL_FCVT''@|$(HAVE_DECL_FCVT)|g' \\\n\t      -e 's|@''HAVE_DECL_GCVT''@|$(HAVE_DECL_GCVT)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \\\n\t      -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \\\n\t      -e 's|@''HAVE_GRANTPT''@|$(HAVE_GRANTPT)|g' \\\n\t      -e 's|@''HAVE_INITSTATE''@|$(HAVE_INITSTATE)|g' \\\n\t      -e 's|@''HAVE_DECL_INITSTATE''@|$(HAVE_DECL_INITSTATE)|g' \\\n\t      -e 's|@''HAVE_MBTOWC''@|$(HAVE_MBTOWC)|g' \\\n\t      -e 's|@''HAVE_MKDTEMP''@|$(HAVE_MKDTEMP)|g' \\\n\t      -e 's|@''HAVE_MKOSTEMP''@|$(HAVE_MKOSTEMP)|g' \\\n\t      -e 's|@''HAVE_MKOSTEMPS''@|$(HAVE_MKOSTEMPS)|g' \\\n\t      -e 's|@''HAVE_MKSTEMP''@|$(HAVE_MKSTEMP)|g' \\\n\t      -e 's|@''HAVE_MKSTEMPS''@|$(HAVE_MKSTEMPS)|g' \\\n\t      -e 's|@''HAVE_POSIX_MEMALIGN''@|$(HAVE_POSIX_MEMALIGN)|g' \\\n\t      -e 's|@''HAVE_POSIX_OPENPT''@|$(HAVE_POSIX_OPENPT)|g' \\\n\t      -e 's|@''HAVE_PTSNAME''@|$(HAVE_PTSNAME)|g' \\\n\t      -e 's|@''HAVE_PTSNAME_R''@|$(HAVE_PTSNAME_R)|g' \\\n\t      -e 's|@''HAVE_QSORT_R''@|$(HAVE_QSORT_R)|g' \\\n\t      -e 's|@''HAVE_RANDOM''@|$(HAVE_RANDOM)|g' \\\n\t      -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \\\n\t      -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \\\n\t      -e 's|@''HAVE_REALLOCARRAY''@|$(HAVE_REALLOCARRAY)|g' \\\n\t      -e 's|@''HAVE_REALPATH''@|$(HAVE_REALPATH)|g' \\\n\t      -e 's|@''HAVE_RPMATCH''@|$(HAVE_RPMATCH)|g' \\\n\t      -e 's|@''HAVE_SECURE_GETENV''@|$(HAVE_SECURE_GETENV)|g' \\\n\t      -e 's|@''HAVE_DECL_SETENV''@|$(HAVE_DECL_SETENV)|g' \\\n\t      -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \\\n\t      -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \\\n\t      -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \\\n\t      -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \\\n\t      -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \\\n\t      -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \\\n\t      -e 's|@''HAVE_STRTOUL''@|$(HAVE_STRTOUL)|g' \\\n\t      -e 's|@''HAVE_STRTOULL''@|$(HAVE_STRTOULL)|g' \\\n\t      -e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' \\\n\t      -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \\\n\t      -e 's|@''HAVE_UNLOCKPT''@|$(HAVE_UNLOCKPT)|g' \\\n\t      -e 's|@''HAVE_DECL_UNSETENV''@|$(HAVE_DECL_UNSETENV)|g' \\\n\t      -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \\\n\t      -e 's|@''REPLACE_CALLOC''@|$(REPLACE_CALLOC)|g' \\\n\t      -e 's|@''REPLACE_CANONICALIZE_FILE_NAME''@|$(REPLACE_CANONICALIZE_FILE_NAME)|g' \\\n\t      -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \\\n\t      -e 's|@''REPLACE_INITSTATE''@|$(REPLACE_INITSTATE)|g' \\\n\t      -e 's|@''REPLACE_MALLOC''@|$(REPLACE_MALLOC)|g' \\\n\t      -e 's|@''REPLACE_MBTOWC''@|$(REPLACE_MBTOWC)|g' \\\n\t      -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \\\n\t      -e 's|@''REPLACE_POSIX_MEMALIGN''@|$(REPLACE_POSIX_MEMALIGN)|g' \\\n\t      -e 's|@''REPLACE_PTSNAME''@|$(REPLACE_PTSNAME)|g' \\\n\t      -e 's|@''REPLACE_PTSNAME_R''@|$(REPLACE_PTSNAME_R)|g' \\\n\t      -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \\\n\t      -e 's|@''REPLACE_QSORT_R''@|$(REPLACE_QSORT_R)|g' \\\n\t      -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \\\n\t      -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \\\n\t      -e 's|@''REPLACE_REALLOC''@|$(REPLACE_REALLOC)|g' \\\n\t      -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \\\n\t      -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \\\n\t      -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \\\n\t      -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \\\n\t      -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \\\n\t      -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \\\n\t      -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \\\n\t      -e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \\\n\t      -e 's|@''REPLACE_STRTOUL''@|$(REPLACE_STRTOUL)|g' \\\n\t      -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \\\n\t      -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \\\n\t      -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _Noreturn/r $(_NORETURN_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += stdlib.h stdlib.h-t\n\nEXTRA_DIST += stdlib.in.h\n\n## end   gnulib module stdlib\n\n## begin gnulib module sys_resource\n\nBUILT_SOURCES += sys/resource.h\n\n# We need the following in order to create <sys/resource.h> when the system\n# doesn't have one.\nsys/resource.h: sys_resource.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_RESOURCE_H''@|$(NEXT_SYS_RESOURCE_H)|g' \\\n\t      -e 's|@''HAVE_SYS_RESOURCE_H''@|$(HAVE_SYS_RESOURCE_H)|g' \\\n\t      -e 's/@''GNULIB_GETRUSAGE''@/$(GL_GNULIB_GETRUSAGE)/g' \\\n\t      -e 's/@''HAVE_GETRUSAGE''@/$(HAVE_GETRUSAGE)/g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_resource.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\nMOSTLYCLEANFILES += sys/resource.h sys/resource.h-t\nMOSTLYCLEANDIRS += sys\n\nEXTRA_DIST += sys_resource.in.h\n\n## end   gnulib module sys_resource\n\n## begin gnulib module sys_socket\n\nBUILT_SOURCES += sys/socket.h\nlibgnu_a_SOURCES += sys_socket.c\n\n# We need the following in order to create <sys/socket.h> when the system\n# doesn't have one that works with the given compiler.\nsys/socket.h: sys_socket.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H) $(ARG_NONNULL_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_SOCKET_H''@|$(NEXT_SYS_SOCKET_H)|g' \\\n\t      -e 's|@''HAVE_SYS_SOCKET_H''@|$(HAVE_SYS_SOCKET_H)|g' \\\n\t      -e 's/@''GNULIB_CLOSE''@/$(GL_GNULIB_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_SOCKET''@/$(GL_GNULIB_SOCKET)/g' \\\n\t      -e 's/@''GNULIB_CONNECT''@/$(GL_GNULIB_CONNECT)/g' \\\n\t      -e 's/@''GNULIB_ACCEPT''@/$(GL_GNULIB_ACCEPT)/g' \\\n\t      -e 's/@''GNULIB_BIND''@/$(GL_GNULIB_BIND)/g' \\\n\t      -e 's/@''GNULIB_GETPEERNAME''@/$(GL_GNULIB_GETPEERNAME)/g' \\\n\t      -e 's/@''GNULIB_GETSOCKNAME''@/$(GL_GNULIB_GETSOCKNAME)/g' \\\n\t      -e 's/@''GNULIB_GETSOCKOPT''@/$(GL_GNULIB_GETSOCKOPT)/g' \\\n\t      -e 's/@''GNULIB_LISTEN''@/$(GL_GNULIB_LISTEN)/g' \\\n\t      -e 's/@''GNULIB_RECV''@/$(GL_GNULIB_RECV)/g' \\\n\t      -e 's/@''GNULIB_SEND''@/$(GL_GNULIB_SEND)/g' \\\n\t      -e 's/@''GNULIB_RECVFROM''@/$(GL_GNULIB_RECVFROM)/g' \\\n\t      -e 's/@''GNULIB_SENDTO''@/$(GL_GNULIB_SENDTO)/g' \\\n\t      -e 's/@''GNULIB_SETSOCKOPT''@/$(GL_GNULIB_SETSOCKOPT)/g' \\\n\t      -e 's/@''GNULIB_SHUTDOWN''@/$(GL_GNULIB_SHUTDOWN)/g' \\\n\t      -e 's/@''GNULIB_ACCEPT4''@/$(GL_GNULIB_ACCEPT4)/g' \\\n\t      -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \\\n\t      -e 's|@''HAVE_WS2TCPIP_H''@|$(HAVE_WS2TCPIP_H)|g' \\\n\t      -e 's|@''HAVE_STRUCT_SOCKADDR_STORAGE''@|$(HAVE_STRUCT_SOCKADDR_STORAGE)|g' \\\n\t      -e 's|@''HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY''@|$(HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY)|g' \\\n\t      -e 's|@''HAVE_SA_FAMILY_T''@|$(HAVE_SA_FAMILY_T)|g' \\\n\t      -e 's|@''HAVE_ACCEPT4''@|$(HAVE_ACCEPT4)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_socket.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\nMOSTLYCLEANFILES += sys/socket.h sys/socket.h-t\nMOSTLYCLEANDIRS += sys\n\nEXTRA_DIST += sys_socket.in.h\n\n## end   gnulib module sys_socket\n\n## begin gnulib module sys_stat\n\nBUILT_SOURCES += sys/stat.h\n\n# We need the following in order to create <sys/stat.h> when the system\n# has one that is incomplete.\nsys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \\\n\t      -e 's|@''WINDOWS_STAT_TIMESPEC''@|$(WINDOWS_STAT_TIMESPEC)|g' \\\n\t      -e 's/@''GNULIB_FCHMODAT''@/$(GL_GNULIB_FCHMODAT)/g' \\\n\t      -e 's/@''GNULIB_FSTAT''@/$(GL_GNULIB_FSTAT)/g' \\\n\t      -e 's/@''GNULIB_FSTATAT''@/$(GL_GNULIB_FSTATAT)/g' \\\n\t      -e 's/@''GNULIB_FUTIMENS''@/$(GL_GNULIB_FUTIMENS)/g' \\\n\t      -e 's/@''GNULIB_GETUMASK''@/$(GL_GNULIB_GETUMASK)/g' \\\n\t      -e 's/@''GNULIB_LCHMOD''@/$(GL_GNULIB_LCHMOD)/g' \\\n\t      -e 's/@''GNULIB_LSTAT''@/$(GL_GNULIB_LSTAT)/g' \\\n\t      -e 's/@''GNULIB_MKDIR''@/$(GL_GNULIB_MKDIR)/g' \\\n\t      -e 's/@''GNULIB_MKDIRAT''@/$(GL_GNULIB_MKDIRAT)/g' \\\n\t      -e 's/@''GNULIB_MKFIFO''@/$(GL_GNULIB_MKFIFO)/g' \\\n\t      -e 's/@''GNULIB_MKFIFOAT''@/$(GL_GNULIB_MKFIFOAT)/g' \\\n\t      -e 's/@''GNULIB_MKNOD''@/$(GL_GNULIB_MKNOD)/g' \\\n\t      -e 's/@''GNULIB_MKNODAT''@/$(GL_GNULIB_MKNODAT)/g' \\\n\t      -e 's/@''GNULIB_STAT''@/$(GL_GNULIB_STAT)/g' \\\n\t      -e 's/@''GNULIB_UTIMENSAT''@/$(GL_GNULIB_UTIMENSAT)/g' \\\n\t      -e 's/@''GNULIB_OVERRIDES_STRUCT_STAT''@/$(GL_GNULIB_OVERRIDES_STRUCT_STAT)/g' \\\n\t      -e 's/@''GNULIB_MDA_CHMOD''@/$(GL_GNULIB_MDA_CHMOD)/g' \\\n\t      -e 's/@''GNULIB_MDA_MKDIR''@/$(GL_GNULIB_MDA_MKDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_UMASK''@/$(GL_GNULIB_MDA_UMASK)/g' \\\n\t      -e 's|@''HAVE_FCHMODAT''@|$(HAVE_FCHMODAT)|g' \\\n\t      -e 's|@''HAVE_FSTATAT''@|$(HAVE_FSTATAT)|g' \\\n\t      -e 's|@''HAVE_FUTIMENS''@|$(HAVE_FUTIMENS)|g' \\\n\t      -e 's|@''HAVE_GETUMASK''@|$(HAVE_GETUMASK)|g' \\\n\t      -e 's|@''HAVE_LCHMOD''@|$(HAVE_LCHMOD)|g' \\\n\t      -e 's|@''HAVE_LSTAT''@|$(HAVE_LSTAT)|g' \\\n\t      -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \\\n\t      -e 's|@''HAVE_MKFIFO''@|$(HAVE_MKFIFO)|g' \\\n\t      -e 's|@''HAVE_MKFIFOAT''@|$(HAVE_MKFIFOAT)|g' \\\n\t      -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \\\n\t      -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \\\n\t      -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \\\n\t      -e 's|@''REPLACE_FCHMODAT''@|$(REPLACE_FCHMODAT)|g' \\\n\t      -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \\\n\t      -e 's|@''REPLACE_FSTATAT''@|$(REPLACE_FSTATAT)|g' \\\n\t      -e 's|@''REPLACE_FUTIMENS''@|$(REPLACE_FUTIMENS)|g' \\\n\t      -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \\\n\t      -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \\\n\t      -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \\\n\t      -e 's|@''REPLACE_MKFIFOAT''@|$(REPLACE_MKFIFOAT)|g' \\\n\t      -e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \\\n\t      -e 's|@''REPLACE_MKNODAT''@|$(REPLACE_MKNODAT)|g' \\\n\t      -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \\\n\t      -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_stat.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += sys/stat.h sys/stat.h-t\nMOSTLYCLEANDIRS += sys\n\nEXTRA_DIST += sys_stat.in.h\n\n## end   gnulib module sys_stat\n\n## begin gnulib module sys_time\n\nBUILT_SOURCES += sys/time.h\n\n# We need the following in order to create <sys/time.h> when the system\n# doesn't have one that works with the given compiler.\nsys/time.h: sys_time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's/@''HAVE_SYS_TIME_H''@/$(HAVE_SYS_TIME_H)/g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_TIME_H''@|$(NEXT_SYS_TIME_H)|g' \\\n\t      -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GL_GNULIB_GETTIMEOFDAY)/g' \\\n\t      -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \\\n\t      -e 's/@''HAVE_GETTIMEOFDAY''@/$(HAVE_GETTIMEOFDAY)/g' \\\n\t      -e 's/@''HAVE_STRUCT_TIMEVAL''@/$(HAVE_STRUCT_TIMEVAL)/g' \\\n\t      -e 's/@''REPLACE_GETTIMEOFDAY''@/$(REPLACE_GETTIMEOFDAY)/g' \\\n\t      -e 's/@''REPLACE_STRUCT_TIMEVAL''@/$(REPLACE_STRUCT_TIMEVAL)/g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_time.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += sys/time.h sys/time.h-t\n\nEXTRA_DIST += sys_time.in.h\n\n## end   gnulib module sys_time\n\n## begin gnulib module sys_types\n\nBUILT_SOURCES += sys/types.h\n\n# We need the following in order to create <sys/types.h> when the system\n# doesn't have one that works with the given compiler.\nsys/types.h: sys_types.in.h $(top_builddir)/config.status\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_TYPES_H''@|$(NEXT_SYS_TYPES_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \\\n\t      -e 's|@''WINDOWS_STAT_INODES''@|$(WINDOWS_STAT_INODES)|g' \\\n\t      < $(srcdir)/sys_types.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += sys/types.h sys/types.h-t\n\nEXTRA_DIST += sys_types.in.h\n\n## end   gnulib module sys_types\n\n## begin gnulib module sys_uio\n\nBUILT_SOURCES += sys/uio.h\n\n# We need the following in order to create <sys/uio.h> when the system\n# doesn't have one that works with the given compiler.\nsys/uio.h: sys_uio.in.h $(top_builddir)/config.status\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_UIO_H''@|$(NEXT_SYS_UIO_H)|g' \\\n\t      -e 's|@''HAVE_SYS_UIO_H''@|$(HAVE_SYS_UIO_H)|g' \\\n\t      < $(srcdir)/sys_uio.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\nMOSTLYCLEANFILES += sys/uio.h sys/uio.h-t\nMOSTLYCLEANDIRS += sys\n\nEXTRA_DIST += sys_uio.in.h\n\n## end   gnulib module sys_uio\n\n## begin gnulib module sys_utsname\n\nBUILT_SOURCES += sys/utsname.h\n\n# We need the following in order to create <sys/utsname.h> when the system\n# does not have one.\nsys/utsname.h: sys_utsname.in.h $(top_builddir)/config.status $(WARN_ON_USE_H) $(ARG_NONNULL_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's/@''HAVE_SYS_UTSNAME_H''@/$(HAVE_SYS_UTSNAME_H)/g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_UTSNAME_H''@|$(NEXT_SYS_UTSNAME_H)|g' \\\n\t      -e 's/@''GNULIB_UNAME''@/$(GL_GNULIB_UNAME)/g' \\\n\t      -e 's|@''HAVE_STRUCT_UTSNAME''@|$(HAVE_STRUCT_UTSNAME)|g' \\\n\t      -e 's|@''HAVE_UNAME''@|$(HAVE_UNAME)|g' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_utsname.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += sys/utsname.h sys/utsname.h-t\nMOSTLYCLEANDIRS += sys\n\nEXTRA_DIST += sys_utsname.in.h\n\n## end   gnulib module sys_utsname\n\n## begin gnulib module time\n\nBUILT_SOURCES += time.h\n\n# We need the following in order to create <time.h> when the system\n# doesn't have one that works with the given compiler.\ntime.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \\\n\t      -e 's/@''GNULIB_CTIME''@/$(GL_GNULIB_CTIME)/g' \\\n\t      -e 's/@''GNULIB_LOCALTIME''@/$(GL_GNULIB_LOCALTIME)/g' \\\n\t      -e 's/@''GNULIB_MKTIME''@/$(GL_GNULIB_MKTIME)/g' \\\n\t      -e 's/@''GNULIB_NANOSLEEP''@/$(GL_GNULIB_NANOSLEEP)/g' \\\n\t      -e 's/@''GNULIB_STRFTIME''@/$(GL_GNULIB_STRFTIME)/g' \\\n\t      -e 's/@''GNULIB_STRPTIME''@/$(GL_GNULIB_STRPTIME)/g' \\\n\t      -e 's/@''GNULIB_TIMEGM''@/$(GL_GNULIB_TIMEGM)/g' \\\n\t      -e 's/@''GNULIB_TIMESPEC_GET''@/$(GL_GNULIB_TIMESPEC_GET)/g' \\\n\t      -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \\\n\t      -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \\\n\t      -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \\\n\t      -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \\\n\t      -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \\\n\t      -e 's|@''HAVE_NANOSLEEP''@|$(HAVE_NANOSLEEP)|g' \\\n\t      -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \\\n\t      -e 's|@''HAVE_TIMEGM''@|$(HAVE_TIMEGM)|g' \\\n\t      -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \\\n\t      -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \\\n\t      -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \\\n\t      -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \\\n\t      -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \\\n\t      -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \\\n\t      -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \\\n\t      -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \\\n\t      -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \\\n\t      -e 's|@''REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \\\n\t      -e 's|@''REPLACE_TZSET''@|$(REPLACE_TZSET)|g' \\\n\t      -e 's|@''PTHREAD_H_DEFINES_STRUCT_TIMESPEC''@|$(PTHREAD_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''UNISTD_H_DEFINES_STRUCT_TIMESPEC''@|$(UNISTD_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''TIME_H_DEFINES_TIME_UTC''@|$(TIME_H_DEFINES_TIME_UTC)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/time.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += time.h time.h-t\n\nEXTRA_DIST += time.in.h\n\n## end   gnulib module time\n\n## begin gnulib module time_r\n\n\nEXTRA_DIST += time_r.c\n\nEXTRA_libgnu_a_SOURCES += time_r.c\n\n## end   gnulib module time_r\n\n## begin gnulib module uname\n\n\nEXTRA_DIST += uname.c\n\nEXTRA_libgnu_a_SOURCES += uname.c\n\n## end   gnulib module uname\n\n## begin gnulib module unistd\n\nBUILT_SOURCES += unistd.h\nlibgnu_a_SOURCES += unistd.c\n\n# We need the following in order to create an empty placeholder for\n# <unistd.h> when the system doesn't have one.\nunistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''HAVE_UNISTD_H''@|$(HAVE_UNISTD_H)|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_UNISTD_H''@|$(NEXT_UNISTD_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \\\n\t      -e 's/@''GNULIB_ACCESS''@/$(GL_GNULIB_ACCESS)/g' \\\n\t      -e 's/@''GNULIB_CHDIR''@/$(GL_GNULIB_CHDIR)/g' \\\n\t      -e 's/@''GNULIB_CHOWN''@/$(GL_GNULIB_CHOWN)/g' \\\n\t      -e 's/@''GNULIB_CLOSE''@/$(GL_GNULIB_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_COPY_FILE_RANGE''@/$(GL_GNULIB_COPY_FILE_RANGE)/g' \\\n\t      -e 's/@''GNULIB_DUP''@/$(GL_GNULIB_DUP)/g' \\\n\t      -e 's/@''GNULIB_DUP2''@/$(GL_GNULIB_DUP2)/g' \\\n\t      -e 's/@''GNULIB_DUP3''@/$(GL_GNULIB_DUP3)/g' \\\n\t      -e 's/@''GNULIB_ENVIRON''@/$(GL_GNULIB_ENVIRON)/g' \\\n\t      -e 's/@''GNULIB_EUIDACCESS''@/$(GL_GNULIB_EUIDACCESS)/g' \\\n\t      -e 's/@''GNULIB_EXECL''@/$(GL_GNULIB_EXECL)/g' \\\n\t      -e 's/@''GNULIB_EXECLE''@/$(GL_GNULIB_EXECLE)/g' \\\n\t      -e 's/@''GNULIB_EXECLP''@/$(GL_GNULIB_EXECLP)/g' \\\n\t      -e 's/@''GNULIB_EXECV''@/$(GL_GNULIB_EXECV)/g' \\\n\t      -e 's/@''GNULIB_EXECVE''@/$(GL_GNULIB_EXECVE)/g' \\\n\t      -e 's/@''GNULIB_EXECVP''@/$(GL_GNULIB_EXECVP)/g' \\\n\t      -e 's/@''GNULIB_EXECVPE''@/$(GL_GNULIB_EXECVPE)/g' \\\n\t      -e 's/@''GNULIB_FACCESSAT''@/$(GL_GNULIB_FACCESSAT)/g' \\\n\t      -e 's/@''GNULIB_FCHDIR''@/$(GL_GNULIB_FCHDIR)/g' \\\n\t      -e 's/@''GNULIB_FCHOWNAT''@/$(GL_GNULIB_FCHOWNAT)/g' \\\n\t      -e 's/@''GNULIB_FDATASYNC''@/$(GL_GNULIB_FDATASYNC)/g' \\\n\t      -e 's/@''GNULIB_FSYNC''@/$(GL_GNULIB_FSYNC)/g' \\\n\t      -e 's/@''GNULIB_FTRUNCATE''@/$(GL_GNULIB_FTRUNCATE)/g' \\\n\t      -e 's/@''GNULIB_GETCWD''@/$(GL_GNULIB_GETCWD)/g' \\\n\t      -e 's/@''GNULIB_GETDOMAINNAME''@/$(GL_GNULIB_GETDOMAINNAME)/g' \\\n\t      -e 's/@''GNULIB_GETDTABLESIZE''@/$(GL_GNULIB_GETDTABLESIZE)/g' \\\n\t      -e 's/@''GNULIB_GETENTROPY''@/$(GL_GNULIB_GETENTROPY)/g' \\\n\t      -e 's/@''GNULIB_GETGROUPS''@/$(GL_GNULIB_GETGROUPS)/g' \\\n\t      -e 's/@''GNULIB_GETHOSTNAME''@/$(GL_GNULIB_GETHOSTNAME)/g' \\\n\t      -e 's/@''GNULIB_GETLOGIN''@/$(GL_GNULIB_GETLOGIN)/g' \\\n\t      -e 's/@''GNULIB_GETLOGIN_R''@/$(GL_GNULIB_GETLOGIN_R)/g' \\\n\t      -e 's/@''GNULIB_GETOPT_POSIX''@/$(GL_GNULIB_GETOPT_POSIX)/g' \\\n\t      -e 's/@''GNULIB_GETPAGESIZE''@/$(GL_GNULIB_GETPAGESIZE)/g' \\\n\t      -e 's/@''GNULIB_GETPASS''@/$(GL_GNULIB_GETPASS)/g' \\\n\t      -e 's/@''GNULIB_GETUSERSHELL''@/$(GL_GNULIB_GETUSERSHELL)/g' \\\n\t      -e 's/@''GNULIB_GROUP_MEMBER''@/$(GL_GNULIB_GROUP_MEMBER)/g' \\\n\t      -e 's/@''GNULIB_ISATTY''@/$(GL_GNULIB_ISATTY)/g' \\\n\t      -e 's/@''GNULIB_LCHOWN''@/$(GL_GNULIB_LCHOWN)/g' \\\n\t      -e 's/@''GNULIB_LINK''@/$(GL_GNULIB_LINK)/g' \\\n\t      -e 's/@''GNULIB_LINKAT''@/$(GL_GNULIB_LINKAT)/g' \\\n\t      -e 's/@''GNULIB_LSEEK''@/$(GL_GNULIB_LSEEK)/g' \\\n\t      -e 's/@''GNULIB_PIPE''@/$(GL_GNULIB_PIPE)/g' \\\n\t      -e 's/@''GNULIB_PIPE2''@/$(GL_GNULIB_PIPE2)/g' \\\n\t      -e 's/@''GNULIB_PREAD''@/$(GL_GNULIB_PREAD)/g' \\\n\t      -e 's/@''GNULIB_PWRITE''@/$(GL_GNULIB_PWRITE)/g' \\\n\t      -e 's/@''GNULIB_READ''@/$(GL_GNULIB_READ)/g' \\\n\t      -e 's/@''GNULIB_READLINK''@/$(GL_GNULIB_READLINK)/g' \\\n\t      -e 's/@''GNULIB_READLINKAT''@/$(GL_GNULIB_READLINKAT)/g' \\\n\t      -e 's/@''GNULIB_RMDIR''@/$(GL_GNULIB_RMDIR)/g' \\\n\t      -e 's/@''GNULIB_SETHOSTNAME''@/$(GL_GNULIB_SETHOSTNAME)/g' \\\n\t      -e 's/@''GNULIB_SLEEP''@/$(GL_GNULIB_SLEEP)/g' \\\n\t      -e 's/@''GNULIB_SYMLINK''@/$(GL_GNULIB_SYMLINK)/g' \\\n\t      -e 's/@''GNULIB_SYMLINKAT''@/$(GL_GNULIB_SYMLINKAT)/g' \\\n\t      -e 's/@''GNULIB_TRUNCATE''@/$(GL_GNULIB_TRUNCATE)/g' \\\n\t      -e 's/@''GNULIB_TTYNAME_R''@/$(GL_GNULIB_TTYNAME_R)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_GETOPT''@/0$(GL_GNULIB_UNISTD_H_GETOPT)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_NONBLOCKING''@/$(GL_GNULIB_UNISTD_H_NONBLOCKING)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_SIGPIPE''@/$(GL_GNULIB_UNISTD_H_SIGPIPE)/g' \\\n\t      -e 's/@''GNULIB_UNLINK''@/$(GL_GNULIB_UNLINK)/g' \\\n\t      -e 's/@''GNULIB_UNLINKAT''@/$(GL_GNULIB_UNLINKAT)/g' \\\n\t      -e 's/@''GNULIB_USLEEP''@/$(GL_GNULIB_USLEEP)/g' \\\n\t      -e 's/@''GNULIB_WRITE''@/$(GL_GNULIB_WRITE)/g' \\\n\t      -e 's/@''GNULIB_MDA_ACCESS''@/$(GL_GNULIB_MDA_ACCESS)/g' \\\n\t      -e 's/@''GNULIB_MDA_CHDIR''@/$(GL_GNULIB_MDA_CHDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_CLOSE''@/$(GL_GNULIB_MDA_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_MDA_DUP''@/$(GL_GNULIB_MDA_DUP)/g' \\\n\t      -e 's/@''GNULIB_MDA_DUP2''@/$(GL_GNULIB_MDA_DUP2)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECL''@/$(GL_GNULIB_MDA_EXECL)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECLE''@/$(GL_GNULIB_MDA_EXECLE)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECLP''@/$(GL_GNULIB_MDA_EXECLP)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECV''@/$(GL_GNULIB_MDA_EXECV)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVE''@/$(GL_GNULIB_MDA_EXECVE)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVP''@/$(GL_GNULIB_MDA_EXECVP)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVPE''@/$(GL_GNULIB_MDA_EXECVPE)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETCWD''@/$(GL_GNULIB_MDA_GETCWD)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETPID''@/$(GL_GNULIB_MDA_GETPID)/g' \\\n\t      -e 's/@''GNULIB_MDA_ISATTY''@/$(GL_GNULIB_MDA_ISATTY)/g' \\\n\t      -e 's/@''GNULIB_MDA_LSEEK''@/$(GL_GNULIB_MDA_LSEEK)/g' \\\n\t      -e 's/@''GNULIB_MDA_READ''@/$(GL_GNULIB_MDA_READ)/g' \\\n\t      -e 's/@''GNULIB_MDA_RMDIR''@/$(GL_GNULIB_MDA_RMDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_SWAB''@/$(GL_GNULIB_MDA_SWAB)/g' \\\n\t      -e 's/@''GNULIB_MDA_UNLINK''@/$(GL_GNULIB_MDA_UNLINK)/g' \\\n\t      -e 's/@''GNULIB_MDA_WRITE''@/$(GL_GNULIB_MDA_WRITE)/g' \\\n\t      < $(srcdir)/unistd.in.h | \\\n\t  sed -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \\\n\t      -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \\\n\t      -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \\\n\t      -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \\\n\t      -e 's|@''HAVE_EXECVPE''@|$(HAVE_EXECVPE)|g' \\\n\t      -e 's|@''HAVE_FACCESSAT''@|$(HAVE_FACCESSAT)|g' \\\n\t      -e 's|@''HAVE_FCHDIR''@|$(HAVE_FCHDIR)|g' \\\n\t      -e 's|@''HAVE_FCHOWNAT''@|$(HAVE_FCHOWNAT)|g' \\\n\t      -e 's|@''HAVE_FDATASYNC''@|$(HAVE_FDATASYNC)|g' \\\n\t      -e 's|@''HAVE_FSYNC''@|$(HAVE_FSYNC)|g' \\\n\t      -e 's|@''HAVE_FTRUNCATE''@|$(HAVE_FTRUNCATE)|g' \\\n\t      -e 's|@''HAVE_GETDTABLESIZE''@|$(HAVE_GETDTABLESIZE)|g' \\\n\t      -e 's|@''HAVE_GETENTROPY''@|$(HAVE_GETENTROPY)|g' \\\n\t      -e 's|@''HAVE_GETGROUPS''@|$(HAVE_GETGROUPS)|g' \\\n\t      -e 's|@''HAVE_GETHOSTNAME''@|$(HAVE_GETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_GETPAGESIZE''@|$(HAVE_GETPAGESIZE)|g' \\\n\t      -e 's|@''HAVE_GETPASS''@|$(HAVE_GETPASS)|g' \\\n\t      -e 's|@''HAVE_GROUP_MEMBER''@|$(HAVE_GROUP_MEMBER)|g' \\\n\t      -e 's|@''HAVE_LCHOWN''@|$(HAVE_LCHOWN)|g' \\\n\t      -e 's|@''HAVE_LINK''@|$(HAVE_LINK)|g' \\\n\t      -e 's|@''HAVE_LINKAT''@|$(HAVE_LINKAT)|g' \\\n\t      -e 's|@''HAVE_PIPE''@|$(HAVE_PIPE)|g' \\\n\t      -e 's|@''HAVE_PIPE2''@|$(HAVE_PIPE2)|g' \\\n\t      -e 's|@''HAVE_PREAD''@|$(HAVE_PREAD)|g' \\\n\t      -e 's|@''HAVE_PWRITE''@|$(HAVE_PWRITE)|g' \\\n\t      -e 's|@''HAVE_READLINK''@|$(HAVE_READLINK)|g' \\\n\t      -e 's|@''HAVE_READLINKAT''@|$(HAVE_READLINKAT)|g' \\\n\t      -e 's|@''HAVE_SETHOSTNAME''@|$(HAVE_SETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_SLEEP''@|$(HAVE_SLEEP)|g' \\\n\t      -e 's|@''HAVE_SYMLINK''@|$(HAVE_SYMLINK)|g' \\\n\t      -e 's|@''HAVE_SYMLINKAT''@|$(HAVE_SYMLINKAT)|g' \\\n\t      -e 's|@''HAVE_UNLINKAT''@|$(HAVE_UNLINKAT)|g' \\\n\t      -e 's|@''HAVE_USLEEP''@|$(HAVE_USLEEP)|g' \\\n\t      -e 's|@''HAVE_DECL_ENVIRON''@|$(HAVE_DECL_ENVIRON)|g' \\\n\t      -e 's|@''HAVE_DECL_EXECVPE''@|$(HAVE_DECL_EXECVPE)|g' \\\n\t      -e 's|@''HAVE_DECL_FCHDIR''@|$(HAVE_DECL_FCHDIR)|g' \\\n\t      -e 's|@''HAVE_DECL_FDATASYNC''@|$(HAVE_DECL_FDATASYNC)|g' \\\n\t      -e 's|@''HAVE_DECL_GETDOMAINNAME''@|$(HAVE_DECL_GETDOMAINNAME)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOGIN''@|$(HAVE_DECL_GETLOGIN)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOGIN_R''@|$(HAVE_DECL_GETLOGIN_R)|g' \\\n\t      -e 's|@''HAVE_DECL_GETPAGESIZE''@|$(HAVE_DECL_GETPAGESIZE)|g' \\\n\t      -e 's|@''HAVE_DECL_GETUSERSHELL''@|$(HAVE_DECL_GETUSERSHELL)|g' \\\n\t      -e 's|@''HAVE_DECL_SETHOSTNAME''@|$(HAVE_DECL_SETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_DECL_TRUNCATE''@|$(HAVE_DECL_TRUNCATE)|g' \\\n\t      -e 's|@''HAVE_DECL_TTYNAME_R''@|$(HAVE_DECL_TTYNAME_R)|g' \\\n\t      -e 's|@''HAVE_OS_H''@|$(HAVE_OS_H)|g' \\\n\t      -e 's|@''HAVE_SYS_PARAM_H''@|$(HAVE_SYS_PARAM_H)|g' \\\n\t  | \\\n\t  sed -e 's|@''REPLACE_ACCESS''@|$(REPLACE_ACCESS)|g' \\\n\t      -e 's|@''REPLACE_CHOWN''@|$(REPLACE_CHOWN)|g' \\\n\t      -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \\\n\t      -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \\\n\t      -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \\\n\t      -e 's|@''REPLACE_EXECL''@|$(REPLACE_EXECL)|g' \\\n\t      -e 's|@''REPLACE_EXECLE''@|$(REPLACE_EXECLE)|g' \\\n\t      -e 's|@''REPLACE_EXECLP''@|$(REPLACE_EXECLP)|g' \\\n\t      -e 's|@''REPLACE_EXECV''@|$(REPLACE_EXECV)|g' \\\n\t      -e 's|@''REPLACE_EXECVE''@|$(REPLACE_EXECVE)|g' \\\n\t      -e 's|@''REPLACE_EXECVP''@|$(REPLACE_EXECVP)|g' \\\n\t      -e 's|@''REPLACE_EXECVPE''@|$(REPLACE_EXECVPE)|g' \\\n\t      -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \\\n\t      -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \\\n\t      -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \\\n\t      -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \\\n\t      -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \\\n\t      -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \\\n\t      -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \\\n\t      -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \\\n\t      -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \\\n\t      -e 's|@''REPLACE_GETPASS''@|$(REPLACE_GETPASS)|g' \\\n\t      -e 's|@''REPLACE_ISATTY''@|$(REPLACE_ISATTY)|g' \\\n\t      -e 's|@''REPLACE_LCHOWN''@|$(REPLACE_LCHOWN)|g' \\\n\t      -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \\\n\t      -e 's|@''REPLACE_LINKAT''@|$(REPLACE_LINKAT)|g' \\\n\t      -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \\\n\t      -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \\\n\t      -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \\\n\t      -e 's|@''REPLACE_READ''@|$(REPLACE_READ)|g' \\\n\t      -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \\\n\t      -e 's|@''REPLACE_READLINKAT''@|$(REPLACE_READLINKAT)|g' \\\n\t      -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \\\n\t      -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \\\n\t      -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \\\n\t      -e 's|@''REPLACE_SYMLINKAT''@|$(REPLACE_SYMLINKAT)|g' \\\n\t      -e 's|@''REPLACE_TRUNCATE''@|$(REPLACE_TRUNCATE)|g' \\\n\t      -e 's|@''REPLACE_TTYNAME_R''@|$(REPLACE_TTYNAME_R)|g' \\\n\t      -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \\\n\t      -e 's|@''REPLACE_UNLINKAT''@|$(REPLACE_UNLINKAT)|g' \\\n\t      -e 's|@''REPLACE_USLEEP''@|$(REPLACE_USLEEP)|g' \\\n\t      -e 's|@''REPLACE_WRITE''@|$(REPLACE_WRITE)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_SYS_RANDOM_H''@|$(UNISTD_H_HAVE_SYS_RANDOM_H)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_WINSOCK2_H''@|$(UNISTD_H_HAVE_WINSOCK2_H)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS''@|$(UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\nMOSTLYCLEANFILES += unistd.h unistd.h-t\n\nEXTRA_DIST += unistd.in.h\n\n## end   gnulib module unistd\n\n\nmostlyclean-local: mostlyclean-generic\n\t@for dir in '' $(MOSTLYCLEANDIRS); do \\\n\t  if test -n \"$$dir\" && test -d $$dir; then \\\n\t    echo \"rmdir $$dir\"; rmdir $$dir; \\\n\t  fi; \\\n\tdone; \\\n\t:\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/Makefile.in",
    "content": "# Makefile.in generated by automake 1.16.3 from Makefile.am.\n# @configure_input@\n\n# Copyright (C) 1994-2020 Free Software Foundation, Inc.\n\n# This Makefile.in is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY, to the extent permitted by law; without\n# even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n# PARTICULAR PURPOSE.\n\n@SET_MAKE@\n\n# Copyright (C) 2002-2021 Free Software Foundation, Inc.\n#\n# This file is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This file is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this file.  If not, see <https://www.gnu.org/licenses/>.\n#\n# As a special exception to the GNU General Public License,\n# this file may be distributed as part of a program that\n# contains a configuration script generated by Autoconf, under\n# the same distribution terms as the rest of that program.\n#\n# Generated by gnulib-tool.\n\n\n\nVPATH = @srcdir@\nam__is_gnu_make = { \\\n  if test -z '$(MAKELEVEL)'; then \\\n    false; \\\n  elif test -n '$(MAKE_HOST)'; then \\\n    true; \\\n  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \\\n    true; \\\n  else \\\n    false; \\\n  fi; \\\n}\nam__make_running_with_option = \\\n  case $${target_option-} in \\\n      ?) ;; \\\n      *) echo \"am__make_running_with_option: internal error: invalid\" \\\n              \"target option '$${target_option-}' specified\" >&2; \\\n         exit 1;; \\\n  esac; \\\n  has_opt=no; \\\n  sane_makeflags=$$MAKEFLAGS; \\\n  if $(am__is_gnu_make); then \\\n    sane_makeflags=$$MFLAGS; \\\n  else \\\n    case $$MAKEFLAGS in \\\n      *\\\\[\\ \\\t]*) \\\n        bs=\\\\; \\\n        sane_makeflags=`printf '%s\\n' \"$$MAKEFLAGS\" \\\n          | sed \"s/$$bs$$bs[$$bs $$bs\t]*//g\"`;; \\\n    esac; \\\n  fi; \\\n  skip_next=no; \\\n  strip_trailopt () \\\n  { \\\n    flg=`printf '%s\\n' \"$$flg\" | sed \"s/$$1.*$$//\"`; \\\n  }; \\\n  for flg in $$sane_makeflags; do \\\n    test $$skip_next = yes && { skip_next=no; continue; }; \\\n    case $$flg in \\\n      *=*|--*) continue;; \\\n        -*I) strip_trailopt 'I'; skip_next=yes;; \\\n      -*I?*) strip_trailopt 'I';; \\\n        -*O) strip_trailopt 'O'; skip_next=yes;; \\\n      -*O?*) strip_trailopt 'O';; \\\n        -*l) strip_trailopt 'l'; skip_next=yes;; \\\n      -*l?*) strip_trailopt 'l';; \\\n      -[dEDm]) skip_next=yes;; \\\n      -[JT]) skip_next=yes;; \\\n    esac; \\\n    case $$flg in \\\n      *$$target_option*) has_opt=yes; break;; \\\n    esac; \\\n  done; \\\n  test $$has_opt = yes\nam__make_dryrun = (target_option=n; $(am__make_running_with_option))\nam__make_keepgoing = (target_option=k; $(am__make_running_with_option))\npkgdatadir = $(datadir)/@PACKAGE@\npkgincludedir = $(includedir)/@PACKAGE@\npkglibdir = $(libdir)/@PACKAGE@\npkglibexecdir = $(libexecdir)/@PACKAGE@\nam__cd = CDPATH=\"$${ZSH_VERSION+.}$(PATH_SEPARATOR)\" && cd\ninstall_sh_DATA = $(install_sh) -c -m 644\ninstall_sh_PROGRAM = $(install_sh) -c\ninstall_sh_SCRIPT = $(install_sh) -c\nINSTALL_HEADER = $(INSTALL_DATA)\ntransform = $(program_transform_name)\nNORMAL_INSTALL = :\nPRE_INSTALL = :\nPOST_INSTALL = :\nNORMAL_UNINSTALL = :\nPRE_UNINSTALL = :\nPOST_UNINSTALL = :\nbuild_triplet = @build@\nhost_triplet = @host@\nsubdir = gllib\nACLOCAL_M4 = $(top_srcdir)/aclocal.m4\nam__aclocal_m4_deps = $(top_srcdir)/glm4/00gnulib.m4 \\\n\t$(top_srcdir)/glm4/__inline.m4 \\\n\t$(top_srcdir)/glm4/absolute-header.m4 \\\n\t$(top_srcdir)/glm4/errno_h.m4 $(top_srcdir)/glm4/execinfo.m4 \\\n\t$(top_srcdir)/glm4/extensions.m4 \\\n\t$(top_srcdir)/glm4/extern-inline.m4 \\\n\t$(top_srcdir)/glm4/getdelim.m4 \\\n\t$(top_srcdir)/glm4/gethostname.m4 \\\n\t$(top_srcdir)/glm4/getline.m4 \\\n\t$(top_srcdir)/glm4/gettimeofday.m4 \\\n\t$(top_srcdir)/glm4/gnulib-common.m4 \\\n\t$(top_srcdir)/glm4/include_next.m4 \\\n\t$(top_srcdir)/glm4/limits-h.m4 \\\n\t$(top_srcdir)/glm4/msvc-inval.m4 \\\n\t$(top_srcdir)/glm4/msvc-nothrow.m4 \\\n\t$(top_srcdir)/glm4/multiarch.m4 $(top_srcdir)/glm4/off_t.m4 \\\n\t$(top_srcdir)/glm4/random.m4 $(top_srcdir)/glm4/random_r.m4 \\\n\t$(top_srcdir)/glm4/socketlib.m4 $(top_srcdir)/glm4/sockets.m4 \\\n\t$(top_srcdir)/glm4/socklen.m4 $(top_srcdir)/glm4/ssize_t.m4 \\\n\t$(top_srcdir)/glm4/stdalign.m4 $(top_srcdir)/glm4/stddef_h.m4 \\\n\t$(top_srcdir)/glm4/stdint.m4 $(top_srcdir)/glm4/stdio_h.m4 \\\n\t$(top_srcdir)/glm4/stdlib_h.m4 \\\n\t$(top_srcdir)/glm4/sys_resource_h.m4 \\\n\t$(top_srcdir)/glm4/sys_socket_h.m4 \\\n\t$(top_srcdir)/glm4/sys_stat_h.m4 \\\n\t$(top_srcdir)/glm4/sys_time_h.m4 \\\n\t$(top_srcdir)/glm4/sys_types_h.m4 \\\n\t$(top_srcdir)/glm4/sys_uio_h.m4 \\\n\t$(top_srcdir)/glm4/sys_utsname_h.m4 \\\n\t$(top_srcdir)/glm4/time_h.m4 $(top_srcdir)/glm4/time_r.m4 \\\n\t$(top_srcdir)/glm4/uname.m4 $(top_srcdir)/glm4/unistd_h.m4 \\\n\t$(top_srcdir)/glm4/warn-on-use.m4 \\\n\t$(top_srcdir)/glm4/wchar_t.m4 $(top_srcdir)/glm4/wint_t.m4 \\\n\t$(top_srcdir)/glm4/zzgnulib.m4 $(top_srcdir)/configure.ac\nam__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \\\n\t$(ACLOCAL_M4)\nDIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \\\n\t$(am__DIST_COMMON)\nmkinstalldirs = $(install_sh) -d\nCONFIG_HEADER = $(top_builddir)/config.h\nCONFIG_CLEAN_FILES =\nCONFIG_CLEAN_VPATH_FILES =\nLIBRARIES = $(noinst_LIBRARIES)\nLTLIBRARIES = $(noinst_LTLIBRARIES)\nAM_V_AR = $(am__v_AR_@AM_V@)\nam__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)\nam__v_AR_0 = @echo \"  AR      \" $@;\nam__v_AR_1 = \nlibgnu_a_AR = $(AR) $(ARFLAGS)\nam__DEPENDENCIES_1 =\nam_libgnu_a_OBJECTS = fd-hook.$(OBJEXT) sockets.$(OBJEXT) \\\n\tsys_socket.$(OBJEXT) unistd.$(OBJEXT)\nlibgnu_a_OBJECTS = $(am_libgnu_a_OBJECTS)\nAM_V_P = $(am__v_P_@AM_V@)\nam__v_P_ = $(am__v_P_@AM_DEFAULT_V@)\nam__v_P_0 = false\nam__v_P_1 = :\nAM_V_GEN = $(am__v_GEN_@AM_V@)\nam__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)\nam__v_GEN_0 = @echo \"  GEN     \" $@;\nam__v_GEN_1 = \nAM_V_at = $(am__v_at_@AM_V@)\nam__v_at_ = $(am__v_at_@AM_DEFAULT_V@)\nam__v_at_0 = @\nam__v_at_1 = \nDEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)\ndepcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp\nam__maybe_remake_depfiles = depfiles\nam__depfiles_remade = ./$(DEPDIR)/execinfo.Po ./$(DEPDIR)/fd-hook.Po \\\n\t./$(DEPDIR)/getdelim.Po ./$(DEPDIR)/gethostname.Po \\\n\t./$(DEPDIR)/getline.Po ./$(DEPDIR)/gettimeofday.Po \\\n\t./$(DEPDIR)/msvc-inval.Po ./$(DEPDIR)/msvc-nothrow.Po \\\n\t./$(DEPDIR)/random.Po ./$(DEPDIR)/random_r.Po \\\n\t./$(DEPDIR)/sockets.Po ./$(DEPDIR)/sys_socket.Po \\\n\t./$(DEPDIR)/time_r.Po ./$(DEPDIR)/uname.Po \\\n\t./$(DEPDIR)/unistd.Po\nam__mv = mv -f\nCOMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \\\n\t$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)\nAM_V_CC = $(am__v_CC_@AM_V@)\nam__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)\nam__v_CC_0 = @echo \"  CC      \" $@;\nam__v_CC_1 = \nCCLD = $(CC)\nLINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@\nAM_V_CCLD = $(am__v_CCLD_@AM_V@)\nam__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)\nam__v_CCLD_0 = @echo \"  CCLD    \" $@;\nam__v_CCLD_1 = \nSOURCES = $(libgnu_a_SOURCES) $(EXTRA_libgnu_a_SOURCES)\nDIST_SOURCES = $(libgnu_a_SOURCES) $(EXTRA_libgnu_a_SOURCES)\nRECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \\\n\tctags-recursive dvi-recursive html-recursive info-recursive \\\n\tinstall-data-recursive install-dvi-recursive \\\n\tinstall-exec-recursive install-html-recursive \\\n\tinstall-info-recursive install-pdf-recursive \\\n\tinstall-ps-recursive install-recursive installcheck-recursive \\\n\tinstalldirs-recursive pdf-recursive ps-recursive \\\n\ttags-recursive uninstall-recursive\nam__can_run_installinfo = \\\n  case $$AM_UPDATE_INFO_DIR in \\\n    n|no|NO) false;; \\\n    *) (install-info --version) >/dev/null 2>&1;; \\\n  esac\nHEADERS = $(noinst_HEADERS)\nRECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive\t\\\n  distclean-recursive maintainer-clean-recursive\nam__recursive_targets = \\\n  $(RECURSIVE_TARGETS) \\\n  $(RECURSIVE_CLEAN_TARGETS) \\\n  $(am__extra_recursive_targets)\nAM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \\\n\tdistdir distdir-am\nam__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)\n# Read a list of newline-separated strings from the standard input,\n# and print each of them once, without duplicates.  Input order is\n# *not* preserved.\nam__uniquify_input = $(AWK) '\\\n  BEGIN { nonempty = 0; } \\\n  { items[$$0] = 1; nonempty = 1; } \\\n  END { if (nonempty) { for (i in items) print i; }; } \\\n'\n# Make sure the list of sources is unique.  This is necessary because,\n# e.g., the same source file might be shared among _SOURCES variables\n# for different programs/libraries.\nam__define_uniq_tagged_files = \\\n  list='$(am__tagged_files)'; \\\n  unique=`for i in $$list; do \\\n    if test -f \"$$i\"; then echo $$i; else echo $(srcdir)/$$i; fi; \\\n  done | $(am__uniquify_input)`\nETAGS = etags\nCTAGS = ctags\nDIST_SUBDIRS = $(SUBDIRS)\nam__DIST_COMMON = $(srcdir)/Makefile.in \\\n\t$(top_srcdir)/build-aux/depcomp\nDISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)\nam__relativize = \\\n  dir0=`pwd`; \\\n  sed_first='s,^\\([^/]*\\)/.*$$,\\1,'; \\\n  sed_rest='s,^[^/]*/*,,'; \\\n  sed_last='s,^.*/\\([^/]*\\)$$,\\1,'; \\\n  sed_butlast='s,/*[^/]*$$,,'; \\\n  while test -n \"$$dir1\"; do \\\n    first=`echo \"$$dir1\" | sed -e \"$$sed_first\"`; \\\n    if test \"$$first\" != \".\"; then \\\n      if test \"$$first\" = \"..\"; then \\\n        dir2=`echo \"$$dir0\" | sed -e \"$$sed_last\"`/\"$$dir2\"; \\\n        dir0=`echo \"$$dir0\" | sed -e \"$$sed_butlast\"`; \\\n      else \\\n        first2=`echo \"$$dir2\" | sed -e \"$$sed_first\"`; \\\n        if test \"$$first2\" = \"$$first\"; then \\\n          dir2=`echo \"$$dir2\" | sed -e \"$$sed_rest\"`; \\\n        else \\\n          dir2=\"../$$dir2\"; \\\n        fi; \\\n        dir0=\"$$dir0\"/\"$$first\"; \\\n      fi; \\\n    fi; \\\n    dir1=`echo \"$$dir1\" | sed -e \"$$sed_rest\"`; \\\n  done; \\\n  reldir=\"$$dir2\"\nACLOCAL = @ACLOCAL@\nAMTAR = @AMTAR@\nAM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@\nAPPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@\nAR = @AR@\nARFLAGS = @ARFLAGS@\nAUTOCONF = @AUTOCONF@\nAUTOHEADER = @AUTOHEADER@\nAUTOMAKE = @AUTOMAKE@\nAWK = @AWK@\nBITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@\nBITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@\nBITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@\nBITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@\nBITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@\nCC = @CC@\nCCDEPMODE = @CCDEPMODE@\nCFLAGS = @CFLAGS@\nCPP = @CPP@\nCPPFLAGS = @CPPFLAGS@\nCYGPATH_W = @CYGPATH_W@\nDEFS = @DEFS@\nDEPDIR = @DEPDIR@\nECHO_C = @ECHO_C@\nECHO_N = @ECHO_N@\nECHO_T = @ECHO_T@\nEGREP = @EGREP@\nEMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@\nEMULTIHOP_VALUE = @EMULTIHOP_VALUE@\nENOLINK_HIDDEN = @ENOLINK_HIDDEN@\nENOLINK_VALUE = @ENOLINK_VALUE@\nEOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@\nEOVERFLOW_VALUE = @EOVERFLOW_VALUE@\nERRNO_H = @ERRNO_H@\nEXECINFO_H = @EXECINFO_H@\nEXEEXT = @EXEEXT@\nGETHOSTNAME_LIB = @GETHOSTNAME_LIB@\nGL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@\nGL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@\nGL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@\nGL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@\nGL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@\nGL_GNULIB_BIND = @GL_GNULIB_BIND@\nGL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@\nGL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@\nGL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@\nGL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@\nGL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@\nGL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@\nGL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@\nGL_GNULIB_CTIME = @GL_GNULIB_CTIME@\nGL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@\nGL_GNULIB_DUP = @GL_GNULIB_DUP@\nGL_GNULIB_DUP2 = @GL_GNULIB_DUP2@\nGL_GNULIB_DUP3 = @GL_GNULIB_DUP3@\nGL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@\nGL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@\nGL_GNULIB_EXECL = @GL_GNULIB_EXECL@\nGL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@\nGL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@\nGL_GNULIB_EXECV = @GL_GNULIB_EXECV@\nGL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@\nGL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@\nGL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@\nGL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@\nGL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@\nGL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@\nGL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@\nGL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@\nGL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@\nGL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@\nGL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@\nGL_GNULIB_FGETC = @GL_GNULIB_FGETC@\nGL_GNULIB_FGETS = @GL_GNULIB_FGETS@\nGL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@\nGL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@\nGL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@\nGL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@\nGL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@\nGL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@\nGL_GNULIB_FREAD = @GL_GNULIB_FREAD@\nGL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@\nGL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@\nGL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@\nGL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@\nGL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@\nGL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@\nGL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@\nGL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@\nGL_GNULIB_FTELL = @GL_GNULIB_FTELL@\nGL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@\nGL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@\nGL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@\nGL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@\nGL_GNULIB_GETC = @GL_GNULIB_GETC@\nGL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@\nGL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@\nGL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@\nGL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@\nGL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@\nGL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@\nGL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@\nGL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@\nGL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@\nGL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@\nGL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@\nGL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@\nGL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@\nGL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@\nGL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@\nGL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@\nGL_GNULIB_GETRUSAGE = @GL_GNULIB_GETRUSAGE@\nGL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@\nGL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@\nGL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@\nGL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@\nGL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@\nGL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@\nGL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@\nGL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@\nGL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@\nGL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@\nGL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@\nGL_GNULIB_LINK = @GL_GNULIB_LINK@\nGL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@\nGL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@\nGL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@\nGL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@\nGL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@\nGL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@\nGL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@\nGL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@\nGL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@\nGL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@\nGL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@\nGL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@\nGL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@\nGL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@\nGL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@\nGL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@\nGL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@\nGL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@\nGL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@\nGL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@\nGL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@\nGL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@\nGL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@\nGL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@\nGL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@\nGL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@\nGL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@\nGL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@\nGL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@\nGL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@\nGL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@\nGL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@\nGL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@\nGL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@\nGL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@\nGL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@\nGL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@\nGL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@\nGL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@\nGL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@\nGL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@\nGL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@\nGL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@\nGL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@\nGL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@\nGL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@\nGL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@\nGL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@\nGL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@\nGL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@\nGL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@\nGL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@\nGL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@\nGL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@\nGL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@\nGL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@\nGL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@\nGL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@\nGL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@\nGL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@\nGL_GNULIB_PERROR = @GL_GNULIB_PERROR@\nGL_GNULIB_PIPE = @GL_GNULIB_PIPE@\nGL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@\nGL_GNULIB_POPEN = @GL_GNULIB_POPEN@\nGL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@\nGL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@\nGL_GNULIB_PREAD = @GL_GNULIB_PREAD@\nGL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@\nGL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@\nGL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@\nGL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@\nGL_GNULIB_PUTC = @GL_GNULIB_PUTC@\nGL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@\nGL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@\nGL_GNULIB_PUTS = @GL_GNULIB_PUTS@\nGL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@\nGL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@\nGL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@\nGL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@\nGL_GNULIB_READ = @GL_GNULIB_READ@\nGL_GNULIB_READLINK = @GL_GNULIB_READLINK@\nGL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@\nGL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@\nGL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@\nGL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@\nGL_GNULIB_RECV = @GL_GNULIB_RECV@\nGL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@\nGL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@\nGL_GNULIB_RENAME = @GL_GNULIB_RENAME@\nGL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@\nGL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@\nGL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@\nGL_GNULIB_SCANF = @GL_GNULIB_SCANF@\nGL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@\nGL_GNULIB_SEND = @GL_GNULIB_SEND@\nGL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@\nGL_GNULIB_SETENV = @GL_GNULIB_SETENV@\nGL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@\nGL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@\nGL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@\nGL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@\nGL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@\nGL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@\nGL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@\nGL_GNULIB_STAT = @GL_GNULIB_STAT@\nGL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@\nGL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@\nGL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@\nGL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@\nGL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@\nGL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@\nGL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@\nGL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@\nGL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@\nGL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@\nGL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@\nGL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@\nGL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@\nGL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@\nGL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@\nGL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@\nGL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@\nGL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@\nGL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@\nGL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@\nGL_GNULIB_TZSET = @GL_GNULIB_TZSET@\nGL_GNULIB_UNAME = @GL_GNULIB_UNAME@\nGL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@\nGL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@\nGL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@\nGL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@\nGL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@\nGL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@\nGL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@\nGL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@\nGL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@\nGL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@\nGL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@\nGL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@\nGL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@\nGL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@\nGL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@\nGL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@\nGL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@\nGL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@\nGL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@\nGL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@\nGL_GNULIB_WRITE = @GL_GNULIB_WRITE@\nGL_GNULIB__EXIT = @GL_GNULIB__EXIT@\nGNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@\nGNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@\nGREP = @GREP@\nHAVE_ACCEPT4 = @HAVE_ACCEPT4@\nHAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@\nHAVE_ATOLL = @HAVE_ATOLL@\nHAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@\nHAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@\nHAVE_CHOWN = @HAVE_CHOWN@\nHAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@\nHAVE_DECL_ECVT = @HAVE_DECL_ECVT@\nHAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@\nHAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@\nHAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@\nHAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@\nHAVE_DECL_FCVT = @HAVE_DECL_FCVT@\nHAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@\nHAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@\nHAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@\nHAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@\nHAVE_DECL_GCVT = @HAVE_DECL_GCVT@\nHAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@\nHAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@\nHAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@\nHAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@\nHAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@\nHAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@\nHAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@\nHAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@\nHAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@\nHAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@\nHAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@\nHAVE_DECL_SETENV = @HAVE_DECL_SETENV@\nHAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@\nHAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@\nHAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@\nHAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@\nHAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@\nHAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@\nHAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@\nHAVE_DPRINTF = @HAVE_DPRINTF@\nHAVE_DUP3 = @HAVE_DUP3@\nHAVE_EUIDACCESS = @HAVE_EUIDACCESS@\nHAVE_EXECVPE = @HAVE_EXECVPE@\nHAVE_FACCESSAT = @HAVE_FACCESSAT@\nHAVE_FCHDIR = @HAVE_FCHDIR@\nHAVE_FCHMODAT = @HAVE_FCHMODAT@\nHAVE_FCHOWNAT = @HAVE_FCHOWNAT@\nHAVE_FDATASYNC = @HAVE_FDATASYNC@\nHAVE_FSEEKO = @HAVE_FSEEKO@\nHAVE_FSTATAT = @HAVE_FSTATAT@\nHAVE_FSYNC = @HAVE_FSYNC@\nHAVE_FTELLO = @HAVE_FTELLO@\nHAVE_FTRUNCATE = @HAVE_FTRUNCATE@\nHAVE_FUTIMENS = @HAVE_FUTIMENS@\nHAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@\nHAVE_GETENTROPY = @HAVE_GETENTROPY@\nHAVE_GETGROUPS = @HAVE_GETGROUPS@\nHAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@\nHAVE_GETLOGIN = @HAVE_GETLOGIN@\nHAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@\nHAVE_GETPASS = @HAVE_GETPASS@\nHAVE_GETRUSAGE = @HAVE_GETRUSAGE@\nHAVE_GETSUBOPT = @HAVE_GETSUBOPT@\nHAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@\nHAVE_GETUMASK = @HAVE_GETUMASK@\nHAVE_GRANTPT = @HAVE_GRANTPT@\nHAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@\nHAVE_INITSTATE = @HAVE_INITSTATE@\nHAVE_INTTYPES_H = @HAVE_INTTYPES_H@\nHAVE_LCHMOD = @HAVE_LCHMOD@\nHAVE_LCHOWN = @HAVE_LCHOWN@\nHAVE_LINK = @HAVE_LINK@\nHAVE_LINKAT = @HAVE_LINKAT@\nHAVE_LSTAT = @HAVE_LSTAT@\nHAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@\nHAVE_MBTOWC = @HAVE_MBTOWC@\nHAVE_MKDIRAT = @HAVE_MKDIRAT@\nHAVE_MKDTEMP = @HAVE_MKDTEMP@\nHAVE_MKFIFO = @HAVE_MKFIFO@\nHAVE_MKFIFOAT = @HAVE_MKFIFOAT@\nHAVE_MKNOD = @HAVE_MKNOD@\nHAVE_MKNODAT = @HAVE_MKNODAT@\nHAVE_MKOSTEMP = @HAVE_MKOSTEMP@\nHAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@\nHAVE_MKSTEMP = @HAVE_MKSTEMP@\nHAVE_MKSTEMPS = @HAVE_MKSTEMPS@\nHAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@\nHAVE_NANOSLEEP = @HAVE_NANOSLEEP@\nHAVE_OS_H = @HAVE_OS_H@\nHAVE_PCLOSE = @HAVE_PCLOSE@\nHAVE_PIPE = @HAVE_PIPE@\nHAVE_PIPE2 = @HAVE_PIPE2@\nHAVE_POPEN = @HAVE_POPEN@\nHAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@\nHAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@\nHAVE_PREAD = @HAVE_PREAD@\nHAVE_PTSNAME = @HAVE_PTSNAME@\nHAVE_PTSNAME_R = @HAVE_PTSNAME_R@\nHAVE_PWRITE = @HAVE_PWRITE@\nHAVE_QSORT_R = @HAVE_QSORT_R@\nHAVE_RANDOM = @HAVE_RANDOM@\nHAVE_RANDOM_H = @HAVE_RANDOM_H@\nHAVE_RANDOM_R = @HAVE_RANDOM_R@\nHAVE_READLINK = @HAVE_READLINK@\nHAVE_READLINKAT = @HAVE_READLINKAT@\nHAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@\nHAVE_REALPATH = @HAVE_REALPATH@\nHAVE_RENAMEAT = @HAVE_RENAMEAT@\nHAVE_RPMATCH = @HAVE_RPMATCH@\nHAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@\nHAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@\nHAVE_SETENV = @HAVE_SETENV@\nHAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@\nHAVE_SETSTATE = @HAVE_SETSTATE@\nHAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@\nHAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@\nHAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@\nHAVE_SLEEP = @HAVE_SLEEP@\nHAVE_STDINT_H = @HAVE_STDINT_H@\nHAVE_STRPTIME = @HAVE_STRPTIME@\nHAVE_STRTOD = @HAVE_STRTOD@\nHAVE_STRTOL = @HAVE_STRTOL@\nHAVE_STRTOLD = @HAVE_STRTOLD@\nHAVE_STRTOLL = @HAVE_STRTOLL@\nHAVE_STRTOUL = @HAVE_STRTOUL@\nHAVE_STRTOULL = @HAVE_STRTOULL@\nHAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@\nHAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@\nHAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@\nHAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@\nHAVE_STRUCT_UTSNAME = @HAVE_STRUCT_UTSNAME@\nHAVE_SYMLINK = @HAVE_SYMLINK@\nHAVE_SYMLINKAT = @HAVE_SYMLINKAT@\nHAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@\nHAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@\nHAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@\nHAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@\nHAVE_SYS_RESOURCE_H = @HAVE_SYS_RESOURCE_H@\nHAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@\nHAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@\nHAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@\nHAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@\nHAVE_SYS_UTSNAME_H = @HAVE_SYS_UTSNAME_H@\nHAVE_TIMEGM = @HAVE_TIMEGM@\nHAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@\nHAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@\nHAVE_UNAME = @HAVE_UNAME@\nHAVE_UNISTD_H = @HAVE_UNISTD_H@\nHAVE_UNLINKAT = @HAVE_UNLINKAT@\nHAVE_UNLOCKPT = @HAVE_UNLOCKPT@\nHAVE_USLEEP = @HAVE_USLEEP@\nHAVE_UTIMENSAT = @HAVE_UTIMENSAT@\nHAVE_VASPRINTF = @HAVE_VASPRINTF@\nHAVE_VDPRINTF = @HAVE_VDPRINTF@\nHAVE_WCHAR_H = @HAVE_WCHAR_H@\nHAVE_WCHAR_T = @HAVE_WCHAR_T@\nHAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@\nHAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@\nHAVE__EXIT = @HAVE__EXIT@\nINCLUDE_NEXT = @INCLUDE_NEXT@\nINCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@\nINSTALL = @INSTALL@\nINSTALL_DATA = @INSTALL_DATA@\nINSTALL_PROGRAM = @INSTALL_PROGRAM@\nINSTALL_SCRIPT = @INSTALL_SCRIPT@\nINSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@\nLDFLAGS = @LDFLAGS@\nLIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@\nLIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@\nLIBOBJS = @LIBOBJS@\nLIBS = @LIBS@\nLIBSOCKET = @LIBSOCKET@\nLIB_EXECINFO = @LIB_EXECINFO@\nLIMITS_H = @LIMITS_H@\nLTLIBOBJS = @LTLIBOBJS@\nMAKEINFO = @MAKEINFO@\nMKDIR_P = @MKDIR_P@\nNEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@\nNEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@\nNEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@\nNEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@\nNEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@\nNEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H@\nNEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@\nNEXT_ERRNO_H = @NEXT_ERRNO_H@\nNEXT_LIMITS_H = @NEXT_LIMITS_H@\nNEXT_STDDEF_H = @NEXT_STDDEF_H@\nNEXT_STDINT_H = @NEXT_STDINT_H@\nNEXT_STDIO_H = @NEXT_STDIO_H@\nNEXT_STDLIB_H = @NEXT_STDLIB_H@\nNEXT_SYS_RESOURCE_H = @NEXT_SYS_RESOURCE_H@\nNEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@\nNEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@\nNEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@\nNEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@\nNEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@\nNEXT_SYS_UTSNAME_H = @NEXT_SYS_UTSNAME_H@\nNEXT_TIME_H = @NEXT_TIME_H@\nNEXT_UNISTD_H = @NEXT_UNISTD_H@\nOBJEXT = @OBJEXT@\nPACKAGE = @PACKAGE@\nPACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@\nPACKAGE_NAME = @PACKAGE_NAME@\nPACKAGE_STRING = @PACKAGE_STRING@\nPACKAGE_TARNAME = @PACKAGE_TARNAME@\nPACKAGE_URL = @PACKAGE_URL@\nPACKAGE_VERSION = @PACKAGE_VERSION@\nPATH_SEPARATOR = @PATH_SEPARATOR@\nPRAGMA_COLUMNS = @PRAGMA_COLUMNS@\nPRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@\nPTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@\nPTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@\nRANLIB = @RANLIB@\nREPLACE_ACCESS = @REPLACE_ACCESS@\nREPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@\nREPLACE_CALLOC = @REPLACE_CALLOC@\nREPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@\nREPLACE_CHOWN = @REPLACE_CHOWN@\nREPLACE_CLOSE = @REPLACE_CLOSE@\nREPLACE_CTIME = @REPLACE_CTIME@\nREPLACE_DPRINTF = @REPLACE_DPRINTF@\nREPLACE_DUP = @REPLACE_DUP@\nREPLACE_DUP2 = @REPLACE_DUP2@\nREPLACE_EXECL = @REPLACE_EXECL@\nREPLACE_EXECLE = @REPLACE_EXECLE@\nREPLACE_EXECLP = @REPLACE_EXECLP@\nREPLACE_EXECV = @REPLACE_EXECV@\nREPLACE_EXECVE = @REPLACE_EXECVE@\nREPLACE_EXECVP = @REPLACE_EXECVP@\nREPLACE_EXECVPE = @REPLACE_EXECVPE@\nREPLACE_FACCESSAT = @REPLACE_FACCESSAT@\nREPLACE_FCHMODAT = @REPLACE_FCHMODAT@\nREPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@\nREPLACE_FCLOSE = @REPLACE_FCLOSE@\nREPLACE_FDOPEN = @REPLACE_FDOPEN@\nREPLACE_FFLUSH = @REPLACE_FFLUSH@\nREPLACE_FOPEN = @REPLACE_FOPEN@\nREPLACE_FPRINTF = @REPLACE_FPRINTF@\nREPLACE_FPURGE = @REPLACE_FPURGE@\nREPLACE_FREE = @REPLACE_FREE@\nREPLACE_FREOPEN = @REPLACE_FREOPEN@\nREPLACE_FSEEK = @REPLACE_FSEEK@\nREPLACE_FSEEKO = @REPLACE_FSEEKO@\nREPLACE_FSTAT = @REPLACE_FSTAT@\nREPLACE_FSTATAT = @REPLACE_FSTATAT@\nREPLACE_FTELL = @REPLACE_FTELL@\nREPLACE_FTELLO = @REPLACE_FTELLO@\nREPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@\nREPLACE_FUTIMENS = @REPLACE_FUTIMENS@\nREPLACE_GETCWD = @REPLACE_GETCWD@\nREPLACE_GETDELIM = @REPLACE_GETDELIM@\nREPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@\nREPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@\nREPLACE_GETGROUPS = @REPLACE_GETGROUPS@\nREPLACE_GETLINE = @REPLACE_GETLINE@\nREPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@\nREPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@\nREPLACE_GETPASS = @REPLACE_GETPASS@\nREPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@\nREPLACE_GMTIME = @REPLACE_GMTIME@\nREPLACE_INITSTATE = @REPLACE_INITSTATE@\nREPLACE_ISATTY = @REPLACE_ISATTY@\nREPLACE_LCHOWN = @REPLACE_LCHOWN@\nREPLACE_LINK = @REPLACE_LINK@\nREPLACE_LINKAT = @REPLACE_LINKAT@\nREPLACE_LOCALTIME = @REPLACE_LOCALTIME@\nREPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@\nREPLACE_LSEEK = @REPLACE_LSEEK@\nREPLACE_LSTAT = @REPLACE_LSTAT@\nREPLACE_MALLOC = @REPLACE_MALLOC@\nREPLACE_MBTOWC = @REPLACE_MBTOWC@\nREPLACE_MKDIR = @REPLACE_MKDIR@\nREPLACE_MKFIFO = @REPLACE_MKFIFO@\nREPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@\nREPLACE_MKNOD = @REPLACE_MKNOD@\nREPLACE_MKNODAT = @REPLACE_MKNODAT@\nREPLACE_MKSTEMP = @REPLACE_MKSTEMP@\nREPLACE_MKTIME = @REPLACE_MKTIME@\nREPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@\nREPLACE_NULL = @REPLACE_NULL@\nREPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@\nREPLACE_PERROR = @REPLACE_PERROR@\nREPLACE_POPEN = @REPLACE_POPEN@\nREPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@\nREPLACE_PREAD = @REPLACE_PREAD@\nREPLACE_PRINTF = @REPLACE_PRINTF@\nREPLACE_PTSNAME = @REPLACE_PTSNAME@\nREPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@\nREPLACE_PUTENV = @REPLACE_PUTENV@\nREPLACE_PWRITE = @REPLACE_PWRITE@\nREPLACE_QSORT_R = @REPLACE_QSORT_R@\nREPLACE_RANDOM = @REPLACE_RANDOM@\nREPLACE_RANDOM_R = @REPLACE_RANDOM_R@\nREPLACE_READ = @REPLACE_READ@\nREPLACE_READLINK = @REPLACE_READLINK@\nREPLACE_READLINKAT = @REPLACE_READLINKAT@\nREPLACE_REALLOC = @REPLACE_REALLOC@\nREPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@\nREPLACE_REALPATH = @REPLACE_REALPATH@\nREPLACE_REMOVE = @REPLACE_REMOVE@\nREPLACE_RENAME = @REPLACE_RENAME@\nREPLACE_RENAMEAT = @REPLACE_RENAMEAT@\nREPLACE_RMDIR = @REPLACE_RMDIR@\nREPLACE_SETENV = @REPLACE_SETENV@\nREPLACE_SETSTATE = @REPLACE_SETSTATE@\nREPLACE_SLEEP = @REPLACE_SLEEP@\nREPLACE_SNPRINTF = @REPLACE_SNPRINTF@\nREPLACE_SPRINTF = @REPLACE_SPRINTF@\nREPLACE_STAT = @REPLACE_STAT@\nREPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@\nREPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@\nREPLACE_STRFTIME = @REPLACE_STRFTIME@\nREPLACE_STRTOD = @REPLACE_STRTOD@\nREPLACE_STRTOL = @REPLACE_STRTOL@\nREPLACE_STRTOLD = @REPLACE_STRTOLD@\nREPLACE_STRTOLL = @REPLACE_STRTOLL@\nREPLACE_STRTOUL = @REPLACE_STRTOUL@\nREPLACE_STRTOULL = @REPLACE_STRTOULL@\nREPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@\nREPLACE_SYMLINK = @REPLACE_SYMLINK@\nREPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@\nREPLACE_TIMEGM = @REPLACE_TIMEGM@\nREPLACE_TMPFILE = @REPLACE_TMPFILE@\nREPLACE_TRUNCATE = @REPLACE_TRUNCATE@\nREPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@\nREPLACE_TZSET = @REPLACE_TZSET@\nREPLACE_UNLINK = @REPLACE_UNLINK@\nREPLACE_UNLINKAT = @REPLACE_UNLINKAT@\nREPLACE_UNSETENV = @REPLACE_UNSETENV@\nREPLACE_USLEEP = @REPLACE_USLEEP@\nREPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@\nREPLACE_VASPRINTF = @REPLACE_VASPRINTF@\nREPLACE_VDPRINTF = @REPLACE_VDPRINTF@\nREPLACE_VFPRINTF = @REPLACE_VFPRINTF@\nREPLACE_VPRINTF = @REPLACE_VPRINTF@\nREPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@\nREPLACE_VSPRINTF = @REPLACE_VSPRINTF@\nREPLACE_WCTOMB = @REPLACE_WCTOMB@\nREPLACE_WRITE = @REPLACE_WRITE@\nSET_MAKE = @SET_MAKE@\nSHELL = @SHELL@\nSIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@\nSIZE_T_SUFFIX = @SIZE_T_SUFFIX@\nSTDALIGN_H = @STDALIGN_H@\nSTDDEF_H = @STDDEF_H@\nSTDINT_H = @STDINT_H@\nSTRIP = @STRIP@\nSYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@\nUNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@\nUNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@\nUNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@\nUNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@\nVERSION = @VERSION@\nWCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@\nWINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@\nWINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@\nWINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@\nWINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@\nWINT_T_SUFFIX = @WINT_T_SUFFIX@\nabs_builddir = @abs_builddir@\nabs_srcdir = @abs_srcdir@\nabs_top_builddir = @abs_top_builddir@\nabs_top_srcdir = @abs_top_srcdir@\nac_ct_CC = @ac_ct_CC@\nam__include = @am__include@\nam__leading_dot = @am__leading_dot@\nam__quote = @am__quote@\nam__tar = @am__tar@\nam__untar = @am__untar@\nbindir = @bindir@\nbuild = @build@\nbuild_alias = @build_alias@\nbuild_cpu = @build_cpu@\nbuild_os = @build_os@\nbuild_vendor = @build_vendor@\nbuilddir = @builddir@\ndatadir = @datadir@\ndatarootdir = @datarootdir@\ndocdir = @docdir@\ndvidir = @dvidir@\nexec_prefix = @exec_prefix@\ngl_LIBOBJS = @gl_LIBOBJS@\ngl_LTLIBOBJS = @gl_LTLIBOBJS@\nhost = @host@\nhost_alias = @host_alias@\nhost_cpu = @host_cpu@\nhost_os = @host_os@\nhost_vendor = @host_vendor@\nhtmldir = @htmldir@\nincludedir = @includedir@\ninfodir = @infodir@\ninstall_sh = @install_sh@\nlibdir = @libdir@\nlibexecdir = @libexecdir@\nlocaledir = @localedir@\nlocalstatedir = @localstatedir@\nmandir = @mandir@\nmkdir_p = @mkdir_p@\noldincludedir = @oldincludedir@\npdfdir = @pdfdir@\nprefix = @prefix@\nprogram_transform_name = @program_transform_name@\npsdir = @psdir@\nrunstatedir = @runstatedir@\nsbindir = @sbindir@\nsharedstatedir = @sharedstatedir@\nsrcdir = @srcdir@\nsysconfdir = @sysconfdir@\ntarget_alias = @target_alias@\ntop_build_prefix = @top_build_prefix@\ntop_builddir = @top_builddir@\ntop_srcdir = @top_srcdir@\nAUTOMAKE_OPTIONS = 1.11 gnits\nSUBDIRS = \nnoinst_HEADERS = \nnoinst_LIBRARIES = libgnu.a\nnoinst_LTLIBRARIES = \nEXTRA_DIST = errno.in.h execinfo.c execinfo.in.h fd-hook.h getdelim.c \\\n\tgethostname.c w32sock.h getline.c gettimeofday.c cdefs.h \\\n\tlibc-config.h limits.in.h msvc-inval.c msvc-inval.h \\\n\tmsvc-nothrow.c msvc-nothrow.h random.c random_r.c _Noreturn.h \\\n\targ-nonnull.h c++defs.h warn-on-use.h w32sock.h stdalign.in.h \\\n\tstddef.in.h stdint.in.h stdio.in.h stdlib.in.h \\\n\tsys_resource.in.h sys_socket.in.h sys_stat.in.h sys_time.in.h \\\n\tsys_types.in.h sys_uio.in.h sys_utsname.in.h time.in.h \\\n\ttime_r.c uname.c unistd.in.h\nBUILT_SOURCES = $(ERRNO_H) $(EXECINFO_H) $(LIMITS_H) $(STDALIGN_H) \\\n\t$(STDDEF_H) $(STDINT_H) stdio.h stdlib.h sys/resource.h \\\n\tsys/socket.h sys/stat.h sys/time.h sys/types.h sys/uio.h \\\n\tsys/utsname.h time.h unistd.h\nSUFFIXES = \nMOSTLYCLEANFILES = core *.stackdump errno.h errno.h-t execinfo.h \\\n\texecinfo.h-t limits.h limits.h-t stdalign.h stdalign.h-t \\\n\tstddef.h stddef.h-t stdint.h stdint.h-t stdio.h stdio.h-t \\\n\tstdlib.h stdlib.h-t sys/resource.h sys/resource.h-t \\\n\tsys/socket.h sys/socket.h-t sys/stat.h sys/stat.h-t sys/time.h \\\n\tsys/time.h-t sys/types.h sys/types.h-t sys/uio.h sys/uio.h-t \\\n\tsys/utsname.h sys/utsname.h-t time.h time.h-t unistd.h \\\n\tunistd.h-t\nMOSTLYCLEANDIRS = sys sys sys sys sys\nCLEANFILES = \nDISTCLEANFILES = \nMAINTAINERCLEANFILES = \n# No GNU Make output.\nAM_CPPFLAGS = -DGNULIB_STRICT_CHECKING=1\nAM_CFLAGS = \nlibgnu_a_SOURCES = fd-hook.c sockets.h sockets.c sys_socket.c unistd.c\nlibgnu_a_LIBADD = $(gl_LIBOBJS)\nlibgnu_a_DEPENDENCIES = $(gl_LIBOBJS)\nEXTRA_libgnu_a_SOURCES = execinfo.c getdelim.c gethostname.c getline.c \\\n\tgettimeofday.c msvc-inval.c msvc-nothrow.c random.c random_r.c \\\n\ttime_r.c uname.c\n\n# Use this preprocessor expression to decide whether #include_next works.\n# Do not rely on a 'configure'-time test for this, since the expression\n# might appear in an installed header, which is used by some other compiler.\nHAVE_INCLUDE_NEXT = (__GNUC__ || __clang__ || 60000000 <= __DECC_VER)\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\n_NORETURN_H = $(srcdir)/_Noreturn.h\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\nARG_NONNULL_H = $(srcdir)/arg-nonnull.h\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\nCXXDEFS_H = $(srcdir)/c++defs.h\n\n# Because this Makefile snippet defines a variable used by other\n# gnulib Makefile snippets, it must be present in all makefiles that\n# need it. This is ensured by the applicability 'all' defined above.\nWARN_ON_USE_H = $(srcdir)/warn-on-use.h\nall: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) all-recursive\n\n.SUFFIXES:\n.SUFFIXES: .c .o .obj\n$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)\n\t@for dep in $?; do \\\n\t  case '$(am__configure_deps)' in \\\n\t    *$$dep*) \\\n\t      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \\\n\t        && { if test -f $@; then exit 0; else break; fi; }; \\\n\t      exit 1;; \\\n\t  esac; \\\n\tdone; \\\n\techo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits gllib/Makefile'; \\\n\t$(am__cd) $(top_srcdir) && \\\n\t  $(AUTOMAKE) --gnits gllib/Makefile\nMakefile: $(srcdir)/Makefile.in $(top_builddir)/config.status\n\t@case '$?' in \\\n\t  *config.status*) \\\n\t    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \\\n\t  *) \\\n\t    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \\\n\t    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \\\n\tesac;\n\n$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n\n$(top_srcdir)/configure:  $(am__configure_deps)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n$(ACLOCAL_M4):  $(am__aclocal_m4_deps)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n$(am__aclocal_m4_deps):\n\nclean-noinstLIBRARIES:\n\t-test -z \"$(noinst_LIBRARIES)\" || rm -f $(noinst_LIBRARIES)\n\nclean-noinstLTLIBRARIES:\n\t-test -z \"$(noinst_LTLIBRARIES)\" || rm -f $(noinst_LTLIBRARIES)\n\t@list='$(noinst_LTLIBRARIES)'; \\\n\tlocs=`for p in $$list; do echo $$p; done | \\\n\t      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \\\n\t      sort -u`; \\\n\ttest -z \"$$locs\" || { \\\n\t  echo rm -f $${locs}; \\\n\t  rm -f $${locs}; \\\n\t}\n\nlibgnu.a: $(libgnu_a_OBJECTS) $(libgnu_a_DEPENDENCIES) $(EXTRA_libgnu_a_DEPENDENCIES) \n\t$(AM_V_at)-rm -f libgnu.a\n\t$(AM_V_AR)$(libgnu_a_AR) libgnu.a $(libgnu_a_OBJECTS) $(libgnu_a_LIBADD)\n\t$(AM_V_at)$(RANLIB) libgnu.a\n\nmostlyclean-compile:\n\t-rm -f *.$(OBJEXT)\n\ndistclean-compile:\n\t-rm -f *.tab.c\n\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execinfo.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fd-hook.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdelim.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gethostname.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getline.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettimeofday.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msvc-inval.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msvc-nothrow.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random_r.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockets.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_socket.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time_r.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uname.Po@am__quote@ # am--include-marker\n@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unistd.Po@am__quote@ # am--include-marker\n\n$(am__depfiles_remade):\n\t@$(MKDIR_P) $(@D)\n\t@echo '# dummy' >$@-t && $(am__mv) $@-t $@\n\nam--depfiles: $(am__depfiles_remade)\n\n.c.o:\n@am__fastdepCC_TRUE@\t$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<\n@am__fastdepCC_TRUE@\t$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po\n@AMDEP_TRUE@@am__fastdepCC_FALSE@\t$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@\n@AMDEP_TRUE@@am__fastdepCC_FALSE@\tDEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@\n@am__fastdepCC_FALSE@\t$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<\n\n.c.obj:\n@am__fastdepCC_TRUE@\t$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`\n@am__fastdepCC_TRUE@\t$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po\n@AMDEP_TRUE@@am__fastdepCC_FALSE@\t$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@\n@AMDEP_TRUE@@am__fastdepCC_FALSE@\tDEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@\n@am__fastdepCC_FALSE@\t$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`\n\n# This directory's subdirectories are mostly independent; you can cd\n# into them and run 'make' without going through this Makefile.\n# To change the values of 'make' variables: instead of editing Makefiles,\n# (1) if the variable is set in 'config.status', edit 'config.status'\n#     (which will cause the Makefiles to be regenerated when you run 'make');\n# (2) otherwise, pass the desired values on the 'make' command line.\n$(am__recursive_targets):\n\t@fail=; \\\n\tif $(am__make_keepgoing); then \\\n\t  failcom='fail=yes'; \\\n\telse \\\n\t  failcom='exit 1'; \\\n\tfi; \\\n\tdot_seen=no; \\\n\ttarget=`echo $@ | sed s/-recursive//`; \\\n\tcase \"$@\" in \\\n\t  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \\\n\t  *) list='$(SUBDIRS)' ;; \\\n\tesac; \\\n\tfor subdir in $$list; do \\\n\t  echo \"Making $$target in $$subdir\"; \\\n\t  if test \"$$subdir\" = \".\"; then \\\n\t    dot_seen=yes; \\\n\t    local_target=\"$$target-am\"; \\\n\t  else \\\n\t    local_target=\"$$target\"; \\\n\t  fi; \\\n\t  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \\\n\t  || eval $$failcom; \\\n\tdone; \\\n\tif test \"$$dot_seen\" = \"no\"; then \\\n\t  $(MAKE) $(AM_MAKEFLAGS) \"$$target-am\" || exit 1; \\\n\tfi; test -z \"$$fail\"\n\nID: $(am__tagged_files)\n\t$(am__define_uniq_tagged_files); mkid -fID $$unique\ntags: tags-recursive\nTAGS: tags\n\ntags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)\n\tset x; \\\n\there=`pwd`; \\\n\tif ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \\\n\t  include_option=--etags-include; \\\n\t  empty_fix=.; \\\n\telse \\\n\t  include_option=--include; \\\n\t  empty_fix=; \\\n\tfi; \\\n\tlist='$(SUBDIRS)'; for subdir in $$list; do \\\n\t  if test \"$$subdir\" = .; then :; else \\\n\t    test ! -f $$subdir/TAGS || \\\n\t      set \"$$@\" \"$$include_option=$$here/$$subdir/TAGS\"; \\\n\t  fi; \\\n\tdone; \\\n\t$(am__define_uniq_tagged_files); \\\n\tshift; \\\n\tif test -z \"$(ETAGS_ARGS)$$*$$unique\"; then :; else \\\n\t  test -n \"$$unique\" || unique=$$empty_fix; \\\n\t  if test $$# -gt 0; then \\\n\t    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \\\n\t      \"$$@\" $$unique; \\\n\t  else \\\n\t    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \\\n\t      $$unique; \\\n\t  fi; \\\n\tfi\nctags: ctags-recursive\n\nCTAGS: ctags\nctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)\n\t$(am__define_uniq_tagged_files); \\\n\ttest -z \"$(CTAGS_ARGS)$$unique\" \\\n\t  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \\\n\t     $$unique\n\nGTAGS:\n\there=`$(am__cd) $(top_builddir) && pwd` \\\n\t  && $(am__cd) $(top_srcdir) \\\n\t  && gtags -i $(GTAGS_ARGS) \"$$here\"\ncscopelist: cscopelist-recursive\n\ncscopelist-am: $(am__tagged_files)\n\tlist='$(am__tagged_files)'; \\\n\tcase \"$(srcdir)\" in \\\n\t  [\\\\/]* | ?:[\\\\/]*) sdir=\"$(srcdir)\" ;; \\\n\t  *) sdir=$(subdir)/$(srcdir) ;; \\\n\tesac; \\\n\tfor i in $$list; do \\\n\t  if test -f \"$$i\"; then \\\n\t    echo \"$(subdir)/$$i\"; \\\n\t  else \\\n\t    echo \"$$sdir/$$i\"; \\\n\t  fi; \\\n\tdone >> $(top_builddir)/cscope.files\n\ndistclean-tags:\n\t-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags\n\ndistdir: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) distdir-am\n\ndistdir-am: $(DISTFILES)\n\t@srcdirstrip=`echo \"$(srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\ttopsrcdirstrip=`echo \"$(top_srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\tlist='$(DISTFILES)'; \\\n\t  dist_files=`for file in $$list; do echo $$file; done | \\\n\t  sed -e \"s|^$$srcdirstrip/||;t\" \\\n\t      -e \"s|^$$topsrcdirstrip/|$(top_builddir)/|;t\"`; \\\n\tcase $$dist_files in \\\n\t  */*) $(MKDIR_P) `echo \"$$dist_files\" | \\\n\t\t\t   sed '/\\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \\\n\t\t\t   sort -u` ;; \\\n\tesac; \\\n\tfor file in $$dist_files; do \\\n\t  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \\\n\t  if test -d $$d/$$file; then \\\n\t    dir=`echo \"/$$file\" | sed -e 's,/[^/]*$$,,'`; \\\n\t    if test -d \"$(distdir)/$$file\"; then \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \\\n\t      cp -fpR $(srcdir)/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    cp -fpR $$d/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t  else \\\n\t    test -f \"$(distdir)/$$file\" \\\n\t    || cp -p $$d/$$file \"$(distdir)/$$file\" \\\n\t    || exit 1; \\\n\t  fi; \\\n\tdone\n\t@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \\\n\t  if test \"$$subdir\" = .; then :; else \\\n\t    $(am__make_dryrun) \\\n\t      || test -d \"$(distdir)/$$subdir\" \\\n\t      || $(MKDIR_P) \"$(distdir)/$$subdir\" \\\n\t      || exit 1; \\\n\t    dir1=$$subdir; dir2=\"$(distdir)/$$subdir\"; \\\n\t    $(am__relativize); \\\n\t    new_distdir=$$reldir; \\\n\t    dir1=$$subdir; dir2=\"$(top_distdir)\"; \\\n\t    $(am__relativize); \\\n\t    new_top_distdir=$$reldir; \\\n\t    echo \" (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=\"$$new_top_distdir\" distdir=\"$$new_distdir\" \\\\\"; \\\n\t    echo \"     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)\"; \\\n\t    ($(am__cd) $$subdir && \\\n\t      $(MAKE) $(AM_MAKEFLAGS) \\\n\t        top_distdir=\"$$new_top_distdir\" \\\n\t        distdir=\"$$new_distdir\" \\\n\t\tam__remove_distdir=: \\\n\t\tam__skip_length_check=: \\\n\t\tam__skip_mode_fix=: \\\n\t        distdir) \\\n\t      || exit 1; \\\n\t  fi; \\\n\tdone\ncheck-am: all-am\ncheck: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) check-recursive\nall-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(HEADERS)\ninstalldirs: installdirs-recursive\ninstalldirs-am:\ninstall: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) install-recursive\ninstall-exec: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) install-exec-recursive\ninstall-data: install-data-recursive\nuninstall: uninstall-recursive\n\ninstall-am: all-am\n\t@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am\n\ninstallcheck: installcheck-recursive\ninstall-strip:\n\tif test -z '$(STRIP)'; then \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t      install; \\\n\telse \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t    \"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'\" install; \\\n\tfi\nmostlyclean-generic:\n\t-test -z \"$(MOSTLYCLEANFILES)\" || rm -f $(MOSTLYCLEANFILES)\n\nclean-generic:\n\t-test -z \"$(CLEANFILES)\" || rm -f $(CLEANFILES)\n\ndistclean-generic:\n\t-test -z \"$(CONFIG_CLEAN_FILES)\" || rm -f $(CONFIG_CLEAN_FILES)\n\t-test . = \"$(srcdir)\" || test -z \"$(CONFIG_CLEAN_VPATH_FILES)\" || rm -f $(CONFIG_CLEAN_VPATH_FILES)\n\t-test -z \"$(DISTCLEANFILES)\" || rm -f $(DISTCLEANFILES)\n\nmaintainer-clean-generic:\n\t@echo \"This command is intended for maintainers to use\"\n\t@echo \"it deletes files that may require special tools to rebuild.\"\n\t-test -z \"$(BUILT_SOURCES)\" || rm -f $(BUILT_SOURCES)\n\t-test -z \"$(MAINTAINERCLEANFILES)\" || rm -f $(MAINTAINERCLEANFILES)\nclean: clean-recursive\n\nclean-am: clean-generic clean-noinstLIBRARIES clean-noinstLTLIBRARIES \\\n\tmostlyclean-am\n\ndistclean: distclean-recursive\n\t\t-rm -f ./$(DEPDIR)/execinfo.Po\n\t-rm -f ./$(DEPDIR)/fd-hook.Po\n\t-rm -f ./$(DEPDIR)/getdelim.Po\n\t-rm -f ./$(DEPDIR)/gethostname.Po\n\t-rm -f ./$(DEPDIR)/getline.Po\n\t-rm -f ./$(DEPDIR)/gettimeofday.Po\n\t-rm -f ./$(DEPDIR)/msvc-inval.Po\n\t-rm -f ./$(DEPDIR)/msvc-nothrow.Po\n\t-rm -f ./$(DEPDIR)/random.Po\n\t-rm -f ./$(DEPDIR)/random_r.Po\n\t-rm -f ./$(DEPDIR)/sockets.Po\n\t-rm -f ./$(DEPDIR)/sys_socket.Po\n\t-rm -f ./$(DEPDIR)/time_r.Po\n\t-rm -f ./$(DEPDIR)/uname.Po\n\t-rm -f ./$(DEPDIR)/unistd.Po\n\t-rm -f Makefile\ndistclean-am: clean-am distclean-compile distclean-generic \\\n\tdistclean-tags\n\ndvi: dvi-recursive\n\ndvi-am:\n\nhtml: html-recursive\n\nhtml-am:\n\ninfo: info-recursive\n\ninfo-am:\n\ninstall-data-am:\n\ninstall-dvi: install-dvi-recursive\n\ninstall-dvi-am:\n\ninstall-exec-am:\n\ninstall-html: install-html-recursive\n\ninstall-html-am:\n\ninstall-info: install-info-recursive\n\ninstall-info-am:\n\ninstall-man:\n\ninstall-pdf: install-pdf-recursive\n\ninstall-pdf-am:\n\ninstall-ps: install-ps-recursive\n\ninstall-ps-am:\n\ninstallcheck-am:\n\nmaintainer-clean: maintainer-clean-recursive\n\t\t-rm -f ./$(DEPDIR)/execinfo.Po\n\t-rm -f ./$(DEPDIR)/fd-hook.Po\n\t-rm -f ./$(DEPDIR)/getdelim.Po\n\t-rm -f ./$(DEPDIR)/gethostname.Po\n\t-rm -f ./$(DEPDIR)/getline.Po\n\t-rm -f ./$(DEPDIR)/gettimeofday.Po\n\t-rm -f ./$(DEPDIR)/msvc-inval.Po\n\t-rm -f ./$(DEPDIR)/msvc-nothrow.Po\n\t-rm -f ./$(DEPDIR)/random.Po\n\t-rm -f ./$(DEPDIR)/random_r.Po\n\t-rm -f ./$(DEPDIR)/sockets.Po\n\t-rm -f ./$(DEPDIR)/sys_socket.Po\n\t-rm -f ./$(DEPDIR)/time_r.Po\n\t-rm -f ./$(DEPDIR)/uname.Po\n\t-rm -f ./$(DEPDIR)/unistd.Po\n\t-rm -f Makefile\nmaintainer-clean-am: distclean-am maintainer-clean-generic\n\nmostlyclean: mostlyclean-recursive\n\nmostlyclean-am: mostlyclean-compile mostlyclean-generic \\\n\tmostlyclean-local\n\npdf: pdf-recursive\n\npdf-am:\n\nps: ps-recursive\n\nps-am:\n\nuninstall-am:\n\n.MAKE: $(am__recursive_targets) all check install install-am \\\n\tinstall-exec install-strip\n\n.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \\\n\tam--depfiles check check-am clean clean-generic \\\n\tclean-noinstLIBRARIES clean-noinstLTLIBRARIES cscopelist-am \\\n\tctags ctags-am distclean distclean-compile distclean-generic \\\n\tdistclean-tags distdir dvi dvi-am html html-am info info-am \\\n\tinstall install-am install-data install-data-am install-dvi \\\n\tinstall-dvi-am install-exec install-exec-am install-html \\\n\tinstall-html-am install-info install-info-am install-man \\\n\tinstall-pdf install-pdf-am install-ps install-ps-am \\\n\tinstall-strip installcheck installcheck-am installdirs \\\n\tinstalldirs-am maintainer-clean maintainer-clean-generic \\\n\tmostlyclean mostlyclean-compile mostlyclean-generic \\\n\tmostlyclean-local pdf pdf-am ps ps-am tags tags-am uninstall \\\n\tuninstall-am\n\n.PRECIOUS: Makefile\n\n\n# We need the following in order to create <errno.h> when the system\n# doesn't have one that is POSIX compliant.\n@GL_GENERATE_ERRNO_H_TRUE@errno.h: errno.in.h $(top_builddir)/config.status\n@GL_GENERATE_ERRNO_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_ERRNO_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n@GL_GENERATE_ERRNO_H_TRUE@\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''NEXT_ERRNO_H''@|$(NEXT_ERRNO_H)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''EMULTIHOP_HIDDEN''@|$(EMULTIHOP_HIDDEN)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''EMULTIHOP_VALUE''@|$(EMULTIHOP_VALUE)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''ENOLINK_HIDDEN''@|$(ENOLINK_HIDDEN)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''ENOLINK_VALUE''@|$(ENOLINK_VALUE)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''EOVERFLOW_HIDDEN''@|$(EOVERFLOW_HIDDEN)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      -e 's|@''EOVERFLOW_VALUE''@|$(EOVERFLOW_VALUE)|g' \\\n@GL_GENERATE_ERRNO_H_TRUE@\t      < $(srcdir)/errno.in.h; \\\n@GL_GENERATE_ERRNO_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_ERRNO_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_ERRNO_H_FALSE@errno.h: $(top_builddir)/config.status\n@GL_GENERATE_ERRNO_H_FALSE@\trm -f $@\n\n# We need the following in order to create <execinfo.h> when the system\n# doesn't have one that works.\n@GL_GENERATE_EXECINFO_H_TRUE@execinfo.h: execinfo.in.h $(top_builddir)/config.status\n@GL_GENERATE_EXECINFO_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_EXECINFO_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n@GL_GENERATE_EXECINFO_H_TRUE@\t  cat $(srcdir)/execinfo.in.h; \\\n@GL_GENERATE_EXECINFO_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_EXECINFO_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_EXECINFO_H_FALSE@execinfo.h: $(top_builddir)/config.status\n@GL_GENERATE_EXECINFO_H_FALSE@\trm -f $@\n\n# We need the following in order to create <limits.h> when the system\n# doesn't have one that is compatible with GNU.\n@GL_GENERATE_LIMITS_H_TRUE@limits.h: limits.in.h $(top_builddir)/config.status\n@GL_GENERATE_LIMITS_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_LIMITS_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n@GL_GENERATE_LIMITS_H_TRUE@\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n@GL_GENERATE_LIMITS_H_TRUE@\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n@GL_GENERATE_LIMITS_H_TRUE@\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n@GL_GENERATE_LIMITS_H_TRUE@\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n@GL_GENERATE_LIMITS_H_TRUE@\t      -e 's|@''NEXT_LIMITS_H''@|$(NEXT_LIMITS_H)|g' \\\n@GL_GENERATE_LIMITS_H_TRUE@\t      < $(srcdir)/limits.in.h; \\\n@GL_GENERATE_LIMITS_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_LIMITS_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_LIMITS_H_FALSE@limits.h: $(top_builddir)/config.status\n@GL_GENERATE_LIMITS_H_FALSE@\trm -f $@\n\n# We need the following in order to create <stdalign.h> when the system\n# doesn't have one that works.\n@GL_GENERATE_STDALIGN_H_TRUE@stdalign.h: stdalign.in.h $(top_builddir)/config.status\n@GL_GENERATE_STDALIGN_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_STDALIGN_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n@GL_GENERATE_STDALIGN_H_TRUE@\t  cat $(srcdir)/stdalign.in.h; \\\n@GL_GENERATE_STDALIGN_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_STDALIGN_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_STDALIGN_H_FALSE@stdalign.h: $(top_builddir)/config.status\n@GL_GENERATE_STDALIGN_H_FALSE@\trm -f $@\n\n# We need the following in order to create <stddef.h> when the system\n# doesn't have one that works with the given compiler.\n@GL_GENERATE_STDDEF_H_TRUE@stddef.h: stddef.in.h $(top_builddir)/config.status\n@GL_GENERATE_STDDEF_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_STDDEF_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n@GL_GENERATE_STDDEF_H_TRUE@\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''NEXT_STDDEF_H''@|$(NEXT_STDDEF_H)|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''HAVE_WCHAR_T''@|$(HAVE_WCHAR_T)|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      -e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \\\n@GL_GENERATE_STDDEF_H_TRUE@\t      < $(srcdir)/stddef.in.h; \\\n@GL_GENERATE_STDDEF_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_STDDEF_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_STDDEF_H_FALSE@stddef.h: $(top_builddir)/config.status\n@GL_GENERATE_STDDEF_H_FALSE@\trm -f $@\n\n# We need the following in order to create <stdint.h> when the system\n# doesn't have one that works with the given compiler.\n@GL_GENERATE_STDINT_H_TRUE@stdint.h: stdint.in.h $(top_builddir)/config.status\n@GL_GENERATE_STDINT_H_TRUE@\t$(AM_V_GEN)rm -f $@-t $@ && \\\n@GL_GENERATE_STDINT_H_TRUE@\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n@GL_GENERATE_STDINT_H_TRUE@\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_STDINT_H''@/$(HAVE_STDINT_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's|@''NEXT_STDINT_H''@|$(NEXT_STDINT_H)|g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_C99_STDINT_H''@/$(HAVE_C99_STDINT_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SYS_TYPES_H''@/$(HAVE_SYS_TYPES_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_INTTYPES_H''@/$(HAVE_INTTYPES_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SYS_INTTYPES_H''@/$(HAVE_SYS_INTTYPES_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SYS_BITYPES_H''@/$(HAVE_SYS_BITYPES_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_WCHAR_H''@/$(HAVE_WCHAR_H)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''APPLE_UNIVERSAL_BUILD''@/$(APPLE_UNIVERSAL_BUILD)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''BITSIZEOF_PTRDIFF_T''@/$(BITSIZEOF_PTRDIFF_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''PTRDIFF_T_SUFFIX''@/$(PTRDIFF_T_SUFFIX)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''BITSIZEOF_SIG_ATOMIC_T''@/$(BITSIZEOF_SIG_ATOMIC_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SIGNED_SIG_ATOMIC_T''@/$(HAVE_SIGNED_SIG_ATOMIC_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''SIG_ATOMIC_T_SUFFIX''@/$(SIG_ATOMIC_T_SUFFIX)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''BITSIZEOF_SIZE_T''@/$(BITSIZEOF_SIZE_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''SIZE_T_SUFFIX''@/$(SIZE_T_SUFFIX)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''BITSIZEOF_WCHAR_T''@/$(BITSIZEOF_WCHAR_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SIGNED_WCHAR_T''@/$(HAVE_SIGNED_WCHAR_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''WCHAR_T_SUFFIX''@/$(WCHAR_T_SUFFIX)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''BITSIZEOF_WINT_T''@/$(BITSIZEOF_WINT_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''HAVE_SIGNED_WINT_T''@/$(HAVE_SIGNED_WINT_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''WINT_T_SUFFIX''@/$(WINT_T_SUFFIX)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      -e 's/@''GNULIBHEADERS_OVERRIDE_WINT_T''@/$(GNULIBHEADERS_OVERRIDE_WINT_T)/g' \\\n@GL_GENERATE_STDINT_H_TRUE@\t      < $(srcdir)/stdint.in.h; \\\n@GL_GENERATE_STDINT_H_TRUE@\t} > $@-t && \\\n@GL_GENERATE_STDINT_H_TRUE@\tmv $@-t $@\n@GL_GENERATE_STDINT_H_FALSE@stdint.h: $(top_builddir)/config.status\n@GL_GENERATE_STDINT_H_FALSE@\trm -f $@\n\n# We need the following in order to create <stdio.h> when the system\n# doesn't have one that works with the given compiler.\nstdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \\\n\t      -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \\\n\t      -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \\\n\t      -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \\\n\t      -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \\\n\t      -e 's/@''GNULIB_FGETC''@/$(GL_GNULIB_FGETC)/g' \\\n\t      -e 's/@''GNULIB_FGETS''@/$(GL_GNULIB_FGETS)/g' \\\n\t      -e 's/@''GNULIB_FOPEN''@/$(GL_GNULIB_FOPEN)/g' \\\n\t      -e 's/@''GNULIB_FPRINTF''@/$(GL_GNULIB_FPRINTF)/g' \\\n\t      -e 's/@''GNULIB_FPRINTF_POSIX''@/$(GL_GNULIB_FPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_FPURGE''@/$(GL_GNULIB_FPURGE)/g' \\\n\t      -e 's/@''GNULIB_FPUTC''@/$(GL_GNULIB_FPUTC)/g' \\\n\t      -e 's/@''GNULIB_FPUTS''@/$(GL_GNULIB_FPUTS)/g' \\\n\t      -e 's/@''GNULIB_FREAD''@/$(GL_GNULIB_FREAD)/g' \\\n\t      -e 's/@''GNULIB_FREOPEN''@/$(GL_GNULIB_FREOPEN)/g' \\\n\t      -e 's/@''GNULIB_FSCANF''@/$(GL_GNULIB_FSCANF)/g' \\\n\t      -e 's/@''GNULIB_FSEEK''@/$(GL_GNULIB_FSEEK)/g' \\\n\t      -e 's/@''GNULIB_FSEEKO''@/$(GL_GNULIB_FSEEKO)/g' \\\n\t      -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \\\n\t      -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \\\n\t      -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \\\n\t      -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \\\n\t      -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \\\n\t      -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \\\n\t      -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \\\n\t      -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \\\n\t      -e 's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \\\n\t      -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \\\n\t      -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \\\n\t      -e 's/@''GNULIB_PRINTF''@/$(GL_GNULIB_PRINTF)/g' \\\n\t      -e 's/@''GNULIB_PRINTF_POSIX''@/$(GL_GNULIB_PRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_PUTC''@/$(GL_GNULIB_PUTC)/g' \\\n\t      -e 's/@''GNULIB_PUTCHAR''@/$(GL_GNULIB_PUTCHAR)/g' \\\n\t      -e 's/@''GNULIB_PUTS''@/$(GL_GNULIB_PUTS)/g' \\\n\t      -e 's/@''GNULIB_REMOVE''@/$(GL_GNULIB_REMOVE)/g' \\\n\t      -e 's/@''GNULIB_RENAME''@/$(GL_GNULIB_RENAME)/g' \\\n\t      -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \\\n\t      -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \\\n\t      -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \\\n\t      -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \\\n\t      -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \\\n\t      -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \\\n\t      -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \\\n\t      -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \\\n\t      -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \\\n\t      -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \\\n\t      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \\\n\t      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \\\n\t      -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \\\n\t      -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \\\n\t      -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \\\n\t      < $(srcdir)/stdio.in.h | \\\n\t  sed -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \\\n\t      -e 's|@''HAVE_DECL_FPURGE''@|$(HAVE_DECL_FPURGE)|g' \\\n\t      -e 's|@''HAVE_DECL_FSEEKO''@|$(HAVE_DECL_FSEEKO)|g' \\\n\t      -e 's|@''HAVE_DECL_FTELLO''@|$(HAVE_DECL_FTELLO)|g' \\\n\t      -e 's|@''HAVE_DECL_GETDELIM''@|$(HAVE_DECL_GETDELIM)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLINE''@|$(HAVE_DECL_GETLINE)|g' \\\n\t      -e 's|@''HAVE_DECL_OBSTACK_PRINTF''@|$(HAVE_DECL_OBSTACK_PRINTF)|g' \\\n\t      -e 's|@''HAVE_DECL_SNPRINTF''@|$(HAVE_DECL_SNPRINTF)|g' \\\n\t      -e 's|@''HAVE_DECL_VSNPRINTF''@|$(HAVE_DECL_VSNPRINTF)|g' \\\n\t      -e 's|@''HAVE_DPRINTF''@|$(HAVE_DPRINTF)|g' \\\n\t      -e 's|@''HAVE_FSEEKO''@|$(HAVE_FSEEKO)|g' \\\n\t      -e 's|@''HAVE_FTELLO''@|$(HAVE_FTELLO)|g' \\\n\t      -e 's|@''HAVE_PCLOSE''@|$(HAVE_PCLOSE)|g' \\\n\t      -e 's|@''HAVE_POPEN''@|$(HAVE_POPEN)|g' \\\n\t      -e 's|@''HAVE_RENAMEAT''@|$(HAVE_RENAMEAT)|g' \\\n\t      -e 's|@''HAVE_VASPRINTF''@|$(HAVE_VASPRINTF)|g' \\\n\t      -e 's|@''HAVE_VDPRINTF''@|$(HAVE_VDPRINTF)|g' \\\n\t      -e 's|@''REPLACE_DPRINTF''@|$(REPLACE_DPRINTF)|g' \\\n\t      -e 's|@''REPLACE_FCLOSE''@|$(REPLACE_FCLOSE)|g' \\\n\t      -e 's|@''REPLACE_FDOPEN''@|$(REPLACE_FDOPEN)|g' \\\n\t      -e 's|@''REPLACE_FFLUSH''@|$(REPLACE_FFLUSH)|g' \\\n\t      -e 's|@''REPLACE_FOPEN''@|$(REPLACE_FOPEN)|g' \\\n\t      -e 's|@''REPLACE_FPRINTF''@|$(REPLACE_FPRINTF)|g' \\\n\t      -e 's|@''REPLACE_FPURGE''@|$(REPLACE_FPURGE)|g' \\\n\t      -e 's|@''REPLACE_FREOPEN''@|$(REPLACE_FREOPEN)|g' \\\n\t      -e 's|@''REPLACE_FSEEK''@|$(REPLACE_FSEEK)|g' \\\n\t      -e 's|@''REPLACE_FSEEKO''@|$(REPLACE_FSEEKO)|g' \\\n\t      -e 's|@''REPLACE_FTELL''@|$(REPLACE_FTELL)|g' \\\n\t      -e 's|@''REPLACE_FTELLO''@|$(REPLACE_FTELLO)|g' \\\n\t      -e 's|@''REPLACE_GETDELIM''@|$(REPLACE_GETDELIM)|g' \\\n\t      -e 's|@''REPLACE_GETLINE''@|$(REPLACE_GETLINE)|g' \\\n\t      -e 's|@''REPLACE_OBSTACK_PRINTF''@|$(REPLACE_OBSTACK_PRINTF)|g' \\\n\t      -e 's|@''REPLACE_PERROR''@|$(REPLACE_PERROR)|g' \\\n\t      -e 's|@''REPLACE_POPEN''@|$(REPLACE_POPEN)|g' \\\n\t      -e 's|@''REPLACE_PRINTF''@|$(REPLACE_PRINTF)|g' \\\n\t      -e 's|@''REPLACE_REMOVE''@|$(REPLACE_REMOVE)|g' \\\n\t      -e 's|@''REPLACE_RENAME''@|$(REPLACE_RENAME)|g' \\\n\t      -e 's|@''REPLACE_RENAMEAT''@|$(REPLACE_RENAMEAT)|g' \\\n\t      -e 's|@''REPLACE_SNPRINTF''@|$(REPLACE_SNPRINTF)|g' \\\n\t      -e 's|@''REPLACE_SPRINTF''@|$(REPLACE_SPRINTF)|g' \\\n\t      -e 's|@''REPLACE_STDIO_READ_FUNCS''@|$(REPLACE_STDIO_READ_FUNCS)|g' \\\n\t      -e 's|@''REPLACE_STDIO_WRITE_FUNCS''@|$(REPLACE_STDIO_WRITE_FUNCS)|g' \\\n\t      -e 's|@''REPLACE_TMPFILE''@|$(REPLACE_TMPFILE)|g' \\\n\t      -e 's|@''REPLACE_VASPRINTF''@|$(REPLACE_VASPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VDPRINTF''@|$(REPLACE_VDPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VFPRINTF''@|$(REPLACE_VFPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VPRINTF''@|$(REPLACE_VPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VSNPRINTF''@|$(REPLACE_VSNPRINTF)|g' \\\n\t      -e 's|@''REPLACE_VSPRINTF''@|$(REPLACE_VSPRINTF)|g' \\\n\t      -e 's|@''ASM_SYMBOL_PREFIX''@|$(ASM_SYMBOL_PREFIX)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <stdlib.h> when the system\n# doesn't have one that works with the given compiler.\nstdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \\\n  $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \\\n\t      -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \\\n\t      -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \\\n\t      -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \\\n\t      -e 's/@''GNULIB_CALLOC_POSIX''@/$(GL_GNULIB_CALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GL_GNULIB_CANONICALIZE_FILE_NAME)/g' \\\n\t      -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \\\n\t      -e 's/@''GNULIB_GETLOADAVG''@/$(GL_GNULIB_GETLOADAVG)/g' \\\n\t      -e 's/@''GNULIB_GETSUBOPT''@/$(GL_GNULIB_GETSUBOPT)/g' \\\n\t      -e 's/@''GNULIB_GRANTPT''@/$(GL_GNULIB_GRANTPT)/g' \\\n\t      -e 's/@''GNULIB_MALLOC_POSIX''@/$(GL_GNULIB_MALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_MBTOWC''@/$(GL_GNULIB_MBTOWC)/g' \\\n\t      -e 's/@''GNULIB_MKDTEMP''@/$(GL_GNULIB_MKDTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKOSTEMP''@/$(GL_GNULIB_MKOSTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKOSTEMPS''@/$(GL_GNULIB_MKOSTEMPS)/g' \\\n\t      -e 's/@''GNULIB_MKSTEMP''@/$(GL_GNULIB_MKSTEMP)/g' \\\n\t      -e 's/@''GNULIB_MKSTEMPS''@/$(GL_GNULIB_MKSTEMPS)/g' \\\n\t      -e 's/@''GNULIB_POSIX_MEMALIGN''@/$(GL_GNULIB_POSIX_MEMALIGN)/g' \\\n\t      -e 's/@''GNULIB_POSIX_OPENPT''@/$(GL_GNULIB_POSIX_OPENPT)/g' \\\n\t      -e 's/@''GNULIB_PTSNAME''@/$(GL_GNULIB_PTSNAME)/g' \\\n\t      -e 's/@''GNULIB_PTSNAME_R''@/$(GL_GNULIB_PTSNAME_R)/g' \\\n\t      -e 's/@''GNULIB_PUTENV''@/$(GL_GNULIB_PUTENV)/g' \\\n\t      -e 's/@''GNULIB_QSORT_R''@/$(GL_GNULIB_QSORT_R)/g' \\\n\t      -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \\\n\t      -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \\\n\t      -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \\\n\t      -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \\\n\t      -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \\\n\t      -e 's/@''GNULIB_RPMATCH''@/$(GL_GNULIB_RPMATCH)/g' \\\n\t      -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \\\n\t      -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \\\n\t      -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \\\n\t      -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \\\n\t      -e 's/@''GNULIB_STRTOLD''@/$(GL_GNULIB_STRTOLD)/g' \\\n\t      -e 's/@''GNULIB_STRTOLL''@/$(GL_GNULIB_STRTOLL)/g' \\\n\t      -e 's/@''GNULIB_STRTOUL''@/$(GL_GNULIB_STRTOUL)/g' \\\n\t      -e 's/@''GNULIB_STRTOULL''@/$(GL_GNULIB_STRTOULL)/g' \\\n\t      -e 's/@''GNULIB_SYSTEM_POSIX''@/$(GL_GNULIB_SYSTEM_POSIX)/g' \\\n\t      -e 's/@''GNULIB_UNLOCKPT''@/$(GL_GNULIB_UNLOCKPT)/g' \\\n\t      -e 's/@''GNULIB_UNSETENV''@/$(GL_GNULIB_UNSETENV)/g' \\\n\t      -e 's/@''GNULIB_WCTOMB''@/$(GL_GNULIB_WCTOMB)/g' \\\n\t      -e 's/@''GNULIB_MDA_ECVT''@/$(GL_GNULIB_MDA_ECVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_FCVT''@/$(GL_GNULIB_MDA_FCVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_GCVT''@/$(GL_GNULIB_MDA_GCVT)/g' \\\n\t      -e 's/@''GNULIB_MDA_MKTEMP''@/$(GL_GNULIB_MDA_MKTEMP)/g' \\\n\t      -e 's/@''GNULIB_MDA_PUTENV''@/$(GL_GNULIB_MDA_PUTENV)/g' \\\n\t      < $(srcdir)/stdlib.in.h | \\\n\t  sed -e 's|@''HAVE__EXIT''@|$(HAVE__EXIT)|g' \\\n\t      -e 's|@''HAVE_ALIGNED_ALLOC''@|$(HAVE_ALIGNED_ALLOC)|g' \\\n\t      -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \\\n\t      -e 's|@''HAVE_CANONICALIZE_FILE_NAME''@|$(HAVE_CANONICALIZE_FILE_NAME)|g' \\\n\t      -e 's|@''HAVE_DECL_ECVT''@|$(HAVE_DECL_ECVT)|g' \\\n\t      -e 's|@''HAVE_DECL_FCVT''@|$(HAVE_DECL_FCVT)|g' \\\n\t      -e 's|@''HAVE_DECL_GCVT''@|$(HAVE_DECL_GCVT)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \\\n\t      -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \\\n\t      -e 's|@''HAVE_GRANTPT''@|$(HAVE_GRANTPT)|g' \\\n\t      -e 's|@''HAVE_INITSTATE''@|$(HAVE_INITSTATE)|g' \\\n\t      -e 's|@''HAVE_DECL_INITSTATE''@|$(HAVE_DECL_INITSTATE)|g' \\\n\t      -e 's|@''HAVE_MBTOWC''@|$(HAVE_MBTOWC)|g' \\\n\t      -e 's|@''HAVE_MKDTEMP''@|$(HAVE_MKDTEMP)|g' \\\n\t      -e 's|@''HAVE_MKOSTEMP''@|$(HAVE_MKOSTEMP)|g' \\\n\t      -e 's|@''HAVE_MKOSTEMPS''@|$(HAVE_MKOSTEMPS)|g' \\\n\t      -e 's|@''HAVE_MKSTEMP''@|$(HAVE_MKSTEMP)|g' \\\n\t      -e 's|@''HAVE_MKSTEMPS''@|$(HAVE_MKSTEMPS)|g' \\\n\t      -e 's|@''HAVE_POSIX_MEMALIGN''@|$(HAVE_POSIX_MEMALIGN)|g' \\\n\t      -e 's|@''HAVE_POSIX_OPENPT''@|$(HAVE_POSIX_OPENPT)|g' \\\n\t      -e 's|@''HAVE_PTSNAME''@|$(HAVE_PTSNAME)|g' \\\n\t      -e 's|@''HAVE_PTSNAME_R''@|$(HAVE_PTSNAME_R)|g' \\\n\t      -e 's|@''HAVE_QSORT_R''@|$(HAVE_QSORT_R)|g' \\\n\t      -e 's|@''HAVE_RANDOM''@|$(HAVE_RANDOM)|g' \\\n\t      -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \\\n\t      -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \\\n\t      -e 's|@''HAVE_REALLOCARRAY''@|$(HAVE_REALLOCARRAY)|g' \\\n\t      -e 's|@''HAVE_REALPATH''@|$(HAVE_REALPATH)|g' \\\n\t      -e 's|@''HAVE_RPMATCH''@|$(HAVE_RPMATCH)|g' \\\n\t      -e 's|@''HAVE_SECURE_GETENV''@|$(HAVE_SECURE_GETENV)|g' \\\n\t      -e 's|@''HAVE_DECL_SETENV''@|$(HAVE_DECL_SETENV)|g' \\\n\t      -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \\\n\t      -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \\\n\t      -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \\\n\t      -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \\\n\t      -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \\\n\t      -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \\\n\t      -e 's|@''HAVE_STRTOUL''@|$(HAVE_STRTOUL)|g' \\\n\t      -e 's|@''HAVE_STRTOULL''@|$(HAVE_STRTOULL)|g' \\\n\t      -e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' \\\n\t      -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \\\n\t      -e 's|@''HAVE_UNLOCKPT''@|$(HAVE_UNLOCKPT)|g' \\\n\t      -e 's|@''HAVE_DECL_UNSETENV''@|$(HAVE_DECL_UNSETENV)|g' \\\n\t      -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \\\n\t      -e 's|@''REPLACE_CALLOC''@|$(REPLACE_CALLOC)|g' \\\n\t      -e 's|@''REPLACE_CANONICALIZE_FILE_NAME''@|$(REPLACE_CANONICALIZE_FILE_NAME)|g' \\\n\t      -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \\\n\t      -e 's|@''REPLACE_INITSTATE''@|$(REPLACE_INITSTATE)|g' \\\n\t      -e 's|@''REPLACE_MALLOC''@|$(REPLACE_MALLOC)|g' \\\n\t      -e 's|@''REPLACE_MBTOWC''@|$(REPLACE_MBTOWC)|g' \\\n\t      -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \\\n\t      -e 's|@''REPLACE_POSIX_MEMALIGN''@|$(REPLACE_POSIX_MEMALIGN)|g' \\\n\t      -e 's|@''REPLACE_PTSNAME''@|$(REPLACE_PTSNAME)|g' \\\n\t      -e 's|@''REPLACE_PTSNAME_R''@|$(REPLACE_PTSNAME_R)|g' \\\n\t      -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \\\n\t      -e 's|@''REPLACE_QSORT_R''@|$(REPLACE_QSORT_R)|g' \\\n\t      -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \\\n\t      -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \\\n\t      -e 's|@''REPLACE_REALLOC''@|$(REPLACE_REALLOC)|g' \\\n\t      -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \\\n\t      -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \\\n\t      -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \\\n\t      -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \\\n\t      -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \\\n\t      -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \\\n\t      -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \\\n\t      -e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \\\n\t      -e 's|@''REPLACE_STRTOUL''@|$(REPLACE_STRTOUL)|g' \\\n\t      -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \\\n\t      -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \\\n\t      -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _Noreturn/r $(_NORETURN_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <sys/resource.h> when the system\n# doesn't have one.\nsys/resource.h: sys_resource.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_RESOURCE_H''@|$(NEXT_SYS_RESOURCE_H)|g' \\\n\t      -e 's|@''HAVE_SYS_RESOURCE_H''@|$(HAVE_SYS_RESOURCE_H)|g' \\\n\t      -e 's/@''GNULIB_GETRUSAGE''@/$(GL_GNULIB_GETRUSAGE)/g' \\\n\t      -e 's/@''HAVE_GETRUSAGE''@/$(HAVE_GETRUSAGE)/g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_resource.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\n\n# We need the following in order to create <sys/socket.h> when the system\n# doesn't have one that works with the given compiler.\nsys/socket.h: sys_socket.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H) $(ARG_NONNULL_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_SOCKET_H''@|$(NEXT_SYS_SOCKET_H)|g' \\\n\t      -e 's|@''HAVE_SYS_SOCKET_H''@|$(HAVE_SYS_SOCKET_H)|g' \\\n\t      -e 's/@''GNULIB_CLOSE''@/$(GL_GNULIB_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_SOCKET''@/$(GL_GNULIB_SOCKET)/g' \\\n\t      -e 's/@''GNULIB_CONNECT''@/$(GL_GNULIB_CONNECT)/g' \\\n\t      -e 's/@''GNULIB_ACCEPT''@/$(GL_GNULIB_ACCEPT)/g' \\\n\t      -e 's/@''GNULIB_BIND''@/$(GL_GNULIB_BIND)/g' \\\n\t      -e 's/@''GNULIB_GETPEERNAME''@/$(GL_GNULIB_GETPEERNAME)/g' \\\n\t      -e 's/@''GNULIB_GETSOCKNAME''@/$(GL_GNULIB_GETSOCKNAME)/g' \\\n\t      -e 's/@''GNULIB_GETSOCKOPT''@/$(GL_GNULIB_GETSOCKOPT)/g' \\\n\t      -e 's/@''GNULIB_LISTEN''@/$(GL_GNULIB_LISTEN)/g' \\\n\t      -e 's/@''GNULIB_RECV''@/$(GL_GNULIB_RECV)/g' \\\n\t      -e 's/@''GNULIB_SEND''@/$(GL_GNULIB_SEND)/g' \\\n\t      -e 's/@''GNULIB_RECVFROM''@/$(GL_GNULIB_RECVFROM)/g' \\\n\t      -e 's/@''GNULIB_SENDTO''@/$(GL_GNULIB_SENDTO)/g' \\\n\t      -e 's/@''GNULIB_SETSOCKOPT''@/$(GL_GNULIB_SETSOCKOPT)/g' \\\n\t      -e 's/@''GNULIB_SHUTDOWN''@/$(GL_GNULIB_SHUTDOWN)/g' \\\n\t      -e 's/@''GNULIB_ACCEPT4''@/$(GL_GNULIB_ACCEPT4)/g' \\\n\t      -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \\\n\t      -e 's|@''HAVE_WS2TCPIP_H''@|$(HAVE_WS2TCPIP_H)|g' \\\n\t      -e 's|@''HAVE_STRUCT_SOCKADDR_STORAGE''@|$(HAVE_STRUCT_SOCKADDR_STORAGE)|g' \\\n\t      -e 's|@''HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY''@|$(HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY)|g' \\\n\t      -e 's|@''HAVE_SA_FAMILY_T''@|$(HAVE_SA_FAMILY_T)|g' \\\n\t      -e 's|@''HAVE_ACCEPT4''@|$(HAVE_ACCEPT4)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_socket.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\n\n# We need the following in order to create <sys/stat.h> when the system\n# has one that is incomplete.\nsys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \\\n\t      -e 's|@''WINDOWS_STAT_TIMESPEC''@|$(WINDOWS_STAT_TIMESPEC)|g' \\\n\t      -e 's/@''GNULIB_FCHMODAT''@/$(GL_GNULIB_FCHMODAT)/g' \\\n\t      -e 's/@''GNULIB_FSTAT''@/$(GL_GNULIB_FSTAT)/g' \\\n\t      -e 's/@''GNULIB_FSTATAT''@/$(GL_GNULIB_FSTATAT)/g' \\\n\t      -e 's/@''GNULIB_FUTIMENS''@/$(GL_GNULIB_FUTIMENS)/g' \\\n\t      -e 's/@''GNULIB_GETUMASK''@/$(GL_GNULIB_GETUMASK)/g' \\\n\t      -e 's/@''GNULIB_LCHMOD''@/$(GL_GNULIB_LCHMOD)/g' \\\n\t      -e 's/@''GNULIB_LSTAT''@/$(GL_GNULIB_LSTAT)/g' \\\n\t      -e 's/@''GNULIB_MKDIR''@/$(GL_GNULIB_MKDIR)/g' \\\n\t      -e 's/@''GNULIB_MKDIRAT''@/$(GL_GNULIB_MKDIRAT)/g' \\\n\t      -e 's/@''GNULIB_MKFIFO''@/$(GL_GNULIB_MKFIFO)/g' \\\n\t      -e 's/@''GNULIB_MKFIFOAT''@/$(GL_GNULIB_MKFIFOAT)/g' \\\n\t      -e 's/@''GNULIB_MKNOD''@/$(GL_GNULIB_MKNOD)/g' \\\n\t      -e 's/@''GNULIB_MKNODAT''@/$(GL_GNULIB_MKNODAT)/g' \\\n\t      -e 's/@''GNULIB_STAT''@/$(GL_GNULIB_STAT)/g' \\\n\t      -e 's/@''GNULIB_UTIMENSAT''@/$(GL_GNULIB_UTIMENSAT)/g' \\\n\t      -e 's/@''GNULIB_OVERRIDES_STRUCT_STAT''@/$(GL_GNULIB_OVERRIDES_STRUCT_STAT)/g' \\\n\t      -e 's/@''GNULIB_MDA_CHMOD''@/$(GL_GNULIB_MDA_CHMOD)/g' \\\n\t      -e 's/@''GNULIB_MDA_MKDIR''@/$(GL_GNULIB_MDA_MKDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_UMASK''@/$(GL_GNULIB_MDA_UMASK)/g' \\\n\t      -e 's|@''HAVE_FCHMODAT''@|$(HAVE_FCHMODAT)|g' \\\n\t      -e 's|@''HAVE_FSTATAT''@|$(HAVE_FSTATAT)|g' \\\n\t      -e 's|@''HAVE_FUTIMENS''@|$(HAVE_FUTIMENS)|g' \\\n\t      -e 's|@''HAVE_GETUMASK''@|$(HAVE_GETUMASK)|g' \\\n\t      -e 's|@''HAVE_LCHMOD''@|$(HAVE_LCHMOD)|g' \\\n\t      -e 's|@''HAVE_LSTAT''@|$(HAVE_LSTAT)|g' \\\n\t      -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \\\n\t      -e 's|@''HAVE_MKFIFO''@|$(HAVE_MKFIFO)|g' \\\n\t      -e 's|@''HAVE_MKFIFOAT''@|$(HAVE_MKFIFOAT)|g' \\\n\t      -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \\\n\t      -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \\\n\t      -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \\\n\t      -e 's|@''REPLACE_FCHMODAT''@|$(REPLACE_FCHMODAT)|g' \\\n\t      -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \\\n\t      -e 's|@''REPLACE_FSTATAT''@|$(REPLACE_FSTATAT)|g' \\\n\t      -e 's|@''REPLACE_FUTIMENS''@|$(REPLACE_FUTIMENS)|g' \\\n\t      -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \\\n\t      -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \\\n\t      -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \\\n\t      -e 's|@''REPLACE_MKFIFOAT''@|$(REPLACE_MKFIFOAT)|g' \\\n\t      -e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \\\n\t      -e 's|@''REPLACE_MKNODAT''@|$(REPLACE_MKNODAT)|g' \\\n\t      -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \\\n\t      -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_stat.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <sys/time.h> when the system\n# doesn't have one that works with the given compiler.\nsys/time.h: sys_time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's/@''HAVE_SYS_TIME_H''@/$(HAVE_SYS_TIME_H)/g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_TIME_H''@|$(NEXT_SYS_TIME_H)|g' \\\n\t      -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GL_GNULIB_GETTIMEOFDAY)/g' \\\n\t      -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \\\n\t      -e 's/@''HAVE_GETTIMEOFDAY''@/$(HAVE_GETTIMEOFDAY)/g' \\\n\t      -e 's/@''HAVE_STRUCT_TIMEVAL''@/$(HAVE_STRUCT_TIMEVAL)/g' \\\n\t      -e 's/@''REPLACE_GETTIMEOFDAY''@/$(REPLACE_GETTIMEOFDAY)/g' \\\n\t      -e 's/@''REPLACE_STRUCT_TIMEVAL''@/$(REPLACE_STRUCT_TIMEVAL)/g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_time.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <sys/types.h> when the system\n# doesn't have one that works with the given compiler.\nsys/types.h: sys_types.in.h $(top_builddir)/config.status\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_TYPES_H''@|$(NEXT_SYS_TYPES_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \\\n\t      -e 's|@''WINDOWS_STAT_INODES''@|$(WINDOWS_STAT_INODES)|g' \\\n\t      < $(srcdir)/sys_types.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <sys/uio.h> when the system\n# doesn't have one that works with the given compiler.\nsys/uio.h: sys_uio.in.h $(top_builddir)/config.status\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_UIO_H''@|$(NEXT_SYS_UIO_H)|g' \\\n\t      -e 's|@''HAVE_SYS_UIO_H''@|$(HAVE_SYS_UIO_H)|g' \\\n\t      < $(srcdir)/sys_uio.in.h; \\\n\t} > $@-t && \\\n\tmv -f $@-t $@\n\n# We need the following in order to create <sys/utsname.h> when the system\n# does not have one.\nsys/utsname.h: sys_utsname.in.h $(top_builddir)/config.status $(WARN_ON_USE_H) $(ARG_NONNULL_H)\n\t$(AM_V_at)$(MKDIR_P) sys\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's/@''HAVE_SYS_UTSNAME_H''@/$(HAVE_SYS_UTSNAME_H)/g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_SYS_UTSNAME_H''@|$(NEXT_SYS_UTSNAME_H)|g' \\\n\t      -e 's/@''GNULIB_UNAME''@/$(GL_GNULIB_UNAME)/g' \\\n\t      -e 's|@''HAVE_STRUCT_UTSNAME''@|$(HAVE_STRUCT_UTSNAME)|g' \\\n\t      -e 's|@''HAVE_UNAME''@|$(HAVE_UNAME)|g' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/sys_utsname.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create <time.h> when the system\n# doesn't have one that works with the given compiler.\ntime.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \\\n\t      -e 's/@''GNULIB_CTIME''@/$(GL_GNULIB_CTIME)/g' \\\n\t      -e 's/@''GNULIB_LOCALTIME''@/$(GL_GNULIB_LOCALTIME)/g' \\\n\t      -e 's/@''GNULIB_MKTIME''@/$(GL_GNULIB_MKTIME)/g' \\\n\t      -e 's/@''GNULIB_NANOSLEEP''@/$(GL_GNULIB_NANOSLEEP)/g' \\\n\t      -e 's/@''GNULIB_STRFTIME''@/$(GL_GNULIB_STRFTIME)/g' \\\n\t      -e 's/@''GNULIB_STRPTIME''@/$(GL_GNULIB_STRPTIME)/g' \\\n\t      -e 's/@''GNULIB_TIMEGM''@/$(GL_GNULIB_TIMEGM)/g' \\\n\t      -e 's/@''GNULIB_TIMESPEC_GET''@/$(GL_GNULIB_TIMESPEC_GET)/g' \\\n\t      -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \\\n\t      -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \\\n\t      -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \\\n\t      -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \\\n\t      -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \\\n\t      -e 's|@''HAVE_NANOSLEEP''@|$(HAVE_NANOSLEEP)|g' \\\n\t      -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \\\n\t      -e 's|@''HAVE_TIMEGM''@|$(HAVE_TIMEGM)|g' \\\n\t      -e 's|@''HAVE_TIMESPEC_GET''@|$(HAVE_TIMESPEC_GET)|g' \\\n\t      -e 's|@''HAVE_TIMEZONE_T''@|$(HAVE_TIMEZONE_T)|g' \\\n\t      -e 's|@''REPLACE_CTIME''@|$(REPLACE_CTIME)|g' \\\n\t      -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \\\n\t      -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \\\n\t      -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \\\n\t      -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \\\n\t      -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \\\n\t      -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \\\n\t      -e 's|@''REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \\\n\t      -e 's|@''REPLACE_TZSET''@|$(REPLACE_TZSET)|g' \\\n\t      -e 's|@''PTHREAD_H_DEFINES_STRUCT_TIMESPEC''@|$(PTHREAD_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''UNISTD_H_DEFINES_STRUCT_TIMESPEC''@|$(UNISTD_H_DEFINES_STRUCT_TIMESPEC)|g' \\\n\t      -e 's|@''TIME_H_DEFINES_TIME_UTC''@|$(TIME_H_DEFINES_TIME_UTC)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \\\n\t      < $(srcdir)/time.in.h; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\n# We need the following in order to create an empty placeholder for\n# <unistd.h> when the system doesn't have one.\nunistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)\n\t$(AM_V_GEN)rm -f $@-t $@ && \\\n\t{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \\\n\t  sed -e 's|@''GUARD_PREFIX''@|GL|g' \\\n\t      -e 's|@''HAVE_UNISTD_H''@|$(HAVE_UNISTD_H)|g' \\\n\t      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \\\n\t      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \\\n\t      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \\\n\t      -e 's|@''NEXT_UNISTD_H''@|$(NEXT_UNISTD_H)|g' \\\n\t      -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \\\n\t      -e 's/@''GNULIB_ACCESS''@/$(GL_GNULIB_ACCESS)/g' \\\n\t      -e 's/@''GNULIB_CHDIR''@/$(GL_GNULIB_CHDIR)/g' \\\n\t      -e 's/@''GNULIB_CHOWN''@/$(GL_GNULIB_CHOWN)/g' \\\n\t      -e 's/@''GNULIB_CLOSE''@/$(GL_GNULIB_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_COPY_FILE_RANGE''@/$(GL_GNULIB_COPY_FILE_RANGE)/g' \\\n\t      -e 's/@''GNULIB_DUP''@/$(GL_GNULIB_DUP)/g' \\\n\t      -e 's/@''GNULIB_DUP2''@/$(GL_GNULIB_DUP2)/g' \\\n\t      -e 's/@''GNULIB_DUP3''@/$(GL_GNULIB_DUP3)/g' \\\n\t      -e 's/@''GNULIB_ENVIRON''@/$(GL_GNULIB_ENVIRON)/g' \\\n\t      -e 's/@''GNULIB_EUIDACCESS''@/$(GL_GNULIB_EUIDACCESS)/g' \\\n\t      -e 's/@''GNULIB_EXECL''@/$(GL_GNULIB_EXECL)/g' \\\n\t      -e 's/@''GNULIB_EXECLE''@/$(GL_GNULIB_EXECLE)/g' \\\n\t      -e 's/@''GNULIB_EXECLP''@/$(GL_GNULIB_EXECLP)/g' \\\n\t      -e 's/@''GNULIB_EXECV''@/$(GL_GNULIB_EXECV)/g' \\\n\t      -e 's/@''GNULIB_EXECVE''@/$(GL_GNULIB_EXECVE)/g' \\\n\t      -e 's/@''GNULIB_EXECVP''@/$(GL_GNULIB_EXECVP)/g' \\\n\t      -e 's/@''GNULIB_EXECVPE''@/$(GL_GNULIB_EXECVPE)/g' \\\n\t      -e 's/@''GNULIB_FACCESSAT''@/$(GL_GNULIB_FACCESSAT)/g' \\\n\t      -e 's/@''GNULIB_FCHDIR''@/$(GL_GNULIB_FCHDIR)/g' \\\n\t      -e 's/@''GNULIB_FCHOWNAT''@/$(GL_GNULIB_FCHOWNAT)/g' \\\n\t      -e 's/@''GNULIB_FDATASYNC''@/$(GL_GNULIB_FDATASYNC)/g' \\\n\t      -e 's/@''GNULIB_FSYNC''@/$(GL_GNULIB_FSYNC)/g' \\\n\t      -e 's/@''GNULIB_FTRUNCATE''@/$(GL_GNULIB_FTRUNCATE)/g' \\\n\t      -e 's/@''GNULIB_GETCWD''@/$(GL_GNULIB_GETCWD)/g' \\\n\t      -e 's/@''GNULIB_GETDOMAINNAME''@/$(GL_GNULIB_GETDOMAINNAME)/g' \\\n\t      -e 's/@''GNULIB_GETDTABLESIZE''@/$(GL_GNULIB_GETDTABLESIZE)/g' \\\n\t      -e 's/@''GNULIB_GETENTROPY''@/$(GL_GNULIB_GETENTROPY)/g' \\\n\t      -e 's/@''GNULIB_GETGROUPS''@/$(GL_GNULIB_GETGROUPS)/g' \\\n\t      -e 's/@''GNULIB_GETHOSTNAME''@/$(GL_GNULIB_GETHOSTNAME)/g' \\\n\t      -e 's/@''GNULIB_GETLOGIN''@/$(GL_GNULIB_GETLOGIN)/g' \\\n\t      -e 's/@''GNULIB_GETLOGIN_R''@/$(GL_GNULIB_GETLOGIN_R)/g' \\\n\t      -e 's/@''GNULIB_GETOPT_POSIX''@/$(GL_GNULIB_GETOPT_POSIX)/g' \\\n\t      -e 's/@''GNULIB_GETPAGESIZE''@/$(GL_GNULIB_GETPAGESIZE)/g' \\\n\t      -e 's/@''GNULIB_GETPASS''@/$(GL_GNULIB_GETPASS)/g' \\\n\t      -e 's/@''GNULIB_GETUSERSHELL''@/$(GL_GNULIB_GETUSERSHELL)/g' \\\n\t      -e 's/@''GNULIB_GROUP_MEMBER''@/$(GL_GNULIB_GROUP_MEMBER)/g' \\\n\t      -e 's/@''GNULIB_ISATTY''@/$(GL_GNULIB_ISATTY)/g' \\\n\t      -e 's/@''GNULIB_LCHOWN''@/$(GL_GNULIB_LCHOWN)/g' \\\n\t      -e 's/@''GNULIB_LINK''@/$(GL_GNULIB_LINK)/g' \\\n\t      -e 's/@''GNULIB_LINKAT''@/$(GL_GNULIB_LINKAT)/g' \\\n\t      -e 's/@''GNULIB_LSEEK''@/$(GL_GNULIB_LSEEK)/g' \\\n\t      -e 's/@''GNULIB_PIPE''@/$(GL_GNULIB_PIPE)/g' \\\n\t      -e 's/@''GNULIB_PIPE2''@/$(GL_GNULIB_PIPE2)/g' \\\n\t      -e 's/@''GNULIB_PREAD''@/$(GL_GNULIB_PREAD)/g' \\\n\t      -e 's/@''GNULIB_PWRITE''@/$(GL_GNULIB_PWRITE)/g' \\\n\t      -e 's/@''GNULIB_READ''@/$(GL_GNULIB_READ)/g' \\\n\t      -e 's/@''GNULIB_READLINK''@/$(GL_GNULIB_READLINK)/g' \\\n\t      -e 's/@''GNULIB_READLINKAT''@/$(GL_GNULIB_READLINKAT)/g' \\\n\t      -e 's/@''GNULIB_RMDIR''@/$(GL_GNULIB_RMDIR)/g' \\\n\t      -e 's/@''GNULIB_SETHOSTNAME''@/$(GL_GNULIB_SETHOSTNAME)/g' \\\n\t      -e 's/@''GNULIB_SLEEP''@/$(GL_GNULIB_SLEEP)/g' \\\n\t      -e 's/@''GNULIB_SYMLINK''@/$(GL_GNULIB_SYMLINK)/g' \\\n\t      -e 's/@''GNULIB_SYMLINKAT''@/$(GL_GNULIB_SYMLINKAT)/g' \\\n\t      -e 's/@''GNULIB_TRUNCATE''@/$(GL_GNULIB_TRUNCATE)/g' \\\n\t      -e 's/@''GNULIB_TTYNAME_R''@/$(GL_GNULIB_TTYNAME_R)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_GETOPT''@/0$(GL_GNULIB_UNISTD_H_GETOPT)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_NONBLOCKING''@/$(GL_GNULIB_UNISTD_H_NONBLOCKING)/g' \\\n\t      -e 's/@''GNULIB_UNISTD_H_SIGPIPE''@/$(GL_GNULIB_UNISTD_H_SIGPIPE)/g' \\\n\t      -e 's/@''GNULIB_UNLINK''@/$(GL_GNULIB_UNLINK)/g' \\\n\t      -e 's/@''GNULIB_UNLINKAT''@/$(GL_GNULIB_UNLINKAT)/g' \\\n\t      -e 's/@''GNULIB_USLEEP''@/$(GL_GNULIB_USLEEP)/g' \\\n\t      -e 's/@''GNULIB_WRITE''@/$(GL_GNULIB_WRITE)/g' \\\n\t      -e 's/@''GNULIB_MDA_ACCESS''@/$(GL_GNULIB_MDA_ACCESS)/g' \\\n\t      -e 's/@''GNULIB_MDA_CHDIR''@/$(GL_GNULIB_MDA_CHDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_CLOSE''@/$(GL_GNULIB_MDA_CLOSE)/g' \\\n\t      -e 's/@''GNULIB_MDA_DUP''@/$(GL_GNULIB_MDA_DUP)/g' \\\n\t      -e 's/@''GNULIB_MDA_DUP2''@/$(GL_GNULIB_MDA_DUP2)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECL''@/$(GL_GNULIB_MDA_EXECL)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECLE''@/$(GL_GNULIB_MDA_EXECLE)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECLP''@/$(GL_GNULIB_MDA_EXECLP)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECV''@/$(GL_GNULIB_MDA_EXECV)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVE''@/$(GL_GNULIB_MDA_EXECVE)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVP''@/$(GL_GNULIB_MDA_EXECVP)/g' \\\n\t      -e 's/@''GNULIB_MDA_EXECVPE''@/$(GL_GNULIB_MDA_EXECVPE)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETCWD''@/$(GL_GNULIB_MDA_GETCWD)/g' \\\n\t      -e 's/@''GNULIB_MDA_GETPID''@/$(GL_GNULIB_MDA_GETPID)/g' \\\n\t      -e 's/@''GNULIB_MDA_ISATTY''@/$(GL_GNULIB_MDA_ISATTY)/g' \\\n\t      -e 's/@''GNULIB_MDA_LSEEK''@/$(GL_GNULIB_MDA_LSEEK)/g' \\\n\t      -e 's/@''GNULIB_MDA_READ''@/$(GL_GNULIB_MDA_READ)/g' \\\n\t      -e 's/@''GNULIB_MDA_RMDIR''@/$(GL_GNULIB_MDA_RMDIR)/g' \\\n\t      -e 's/@''GNULIB_MDA_SWAB''@/$(GL_GNULIB_MDA_SWAB)/g' \\\n\t      -e 's/@''GNULIB_MDA_UNLINK''@/$(GL_GNULIB_MDA_UNLINK)/g' \\\n\t      -e 's/@''GNULIB_MDA_WRITE''@/$(GL_GNULIB_MDA_WRITE)/g' \\\n\t      < $(srcdir)/unistd.in.h | \\\n\t  sed -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \\\n\t      -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \\\n\t      -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \\\n\t      -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \\\n\t      -e 's|@''HAVE_EXECVPE''@|$(HAVE_EXECVPE)|g' \\\n\t      -e 's|@''HAVE_FACCESSAT''@|$(HAVE_FACCESSAT)|g' \\\n\t      -e 's|@''HAVE_FCHDIR''@|$(HAVE_FCHDIR)|g' \\\n\t      -e 's|@''HAVE_FCHOWNAT''@|$(HAVE_FCHOWNAT)|g' \\\n\t      -e 's|@''HAVE_FDATASYNC''@|$(HAVE_FDATASYNC)|g' \\\n\t      -e 's|@''HAVE_FSYNC''@|$(HAVE_FSYNC)|g' \\\n\t      -e 's|@''HAVE_FTRUNCATE''@|$(HAVE_FTRUNCATE)|g' \\\n\t      -e 's|@''HAVE_GETDTABLESIZE''@|$(HAVE_GETDTABLESIZE)|g' \\\n\t      -e 's|@''HAVE_GETENTROPY''@|$(HAVE_GETENTROPY)|g' \\\n\t      -e 's|@''HAVE_GETGROUPS''@|$(HAVE_GETGROUPS)|g' \\\n\t      -e 's|@''HAVE_GETHOSTNAME''@|$(HAVE_GETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_GETPAGESIZE''@|$(HAVE_GETPAGESIZE)|g' \\\n\t      -e 's|@''HAVE_GETPASS''@|$(HAVE_GETPASS)|g' \\\n\t      -e 's|@''HAVE_GROUP_MEMBER''@|$(HAVE_GROUP_MEMBER)|g' \\\n\t      -e 's|@''HAVE_LCHOWN''@|$(HAVE_LCHOWN)|g' \\\n\t      -e 's|@''HAVE_LINK''@|$(HAVE_LINK)|g' \\\n\t      -e 's|@''HAVE_LINKAT''@|$(HAVE_LINKAT)|g' \\\n\t      -e 's|@''HAVE_PIPE''@|$(HAVE_PIPE)|g' \\\n\t      -e 's|@''HAVE_PIPE2''@|$(HAVE_PIPE2)|g' \\\n\t      -e 's|@''HAVE_PREAD''@|$(HAVE_PREAD)|g' \\\n\t      -e 's|@''HAVE_PWRITE''@|$(HAVE_PWRITE)|g' \\\n\t      -e 's|@''HAVE_READLINK''@|$(HAVE_READLINK)|g' \\\n\t      -e 's|@''HAVE_READLINKAT''@|$(HAVE_READLINKAT)|g' \\\n\t      -e 's|@''HAVE_SETHOSTNAME''@|$(HAVE_SETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_SLEEP''@|$(HAVE_SLEEP)|g' \\\n\t      -e 's|@''HAVE_SYMLINK''@|$(HAVE_SYMLINK)|g' \\\n\t      -e 's|@''HAVE_SYMLINKAT''@|$(HAVE_SYMLINKAT)|g' \\\n\t      -e 's|@''HAVE_UNLINKAT''@|$(HAVE_UNLINKAT)|g' \\\n\t      -e 's|@''HAVE_USLEEP''@|$(HAVE_USLEEP)|g' \\\n\t      -e 's|@''HAVE_DECL_ENVIRON''@|$(HAVE_DECL_ENVIRON)|g' \\\n\t      -e 's|@''HAVE_DECL_EXECVPE''@|$(HAVE_DECL_EXECVPE)|g' \\\n\t      -e 's|@''HAVE_DECL_FCHDIR''@|$(HAVE_DECL_FCHDIR)|g' \\\n\t      -e 's|@''HAVE_DECL_FDATASYNC''@|$(HAVE_DECL_FDATASYNC)|g' \\\n\t      -e 's|@''HAVE_DECL_GETDOMAINNAME''@|$(HAVE_DECL_GETDOMAINNAME)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOGIN''@|$(HAVE_DECL_GETLOGIN)|g' \\\n\t      -e 's|@''HAVE_DECL_GETLOGIN_R''@|$(HAVE_DECL_GETLOGIN_R)|g' \\\n\t      -e 's|@''HAVE_DECL_GETPAGESIZE''@|$(HAVE_DECL_GETPAGESIZE)|g' \\\n\t      -e 's|@''HAVE_DECL_GETUSERSHELL''@|$(HAVE_DECL_GETUSERSHELL)|g' \\\n\t      -e 's|@''HAVE_DECL_SETHOSTNAME''@|$(HAVE_DECL_SETHOSTNAME)|g' \\\n\t      -e 's|@''HAVE_DECL_TRUNCATE''@|$(HAVE_DECL_TRUNCATE)|g' \\\n\t      -e 's|@''HAVE_DECL_TTYNAME_R''@|$(HAVE_DECL_TTYNAME_R)|g' \\\n\t      -e 's|@''HAVE_OS_H''@|$(HAVE_OS_H)|g' \\\n\t      -e 's|@''HAVE_SYS_PARAM_H''@|$(HAVE_SYS_PARAM_H)|g' \\\n\t  | \\\n\t  sed -e 's|@''REPLACE_ACCESS''@|$(REPLACE_ACCESS)|g' \\\n\t      -e 's|@''REPLACE_CHOWN''@|$(REPLACE_CHOWN)|g' \\\n\t      -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \\\n\t      -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \\\n\t      -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \\\n\t      -e 's|@''REPLACE_EXECL''@|$(REPLACE_EXECL)|g' \\\n\t      -e 's|@''REPLACE_EXECLE''@|$(REPLACE_EXECLE)|g' \\\n\t      -e 's|@''REPLACE_EXECLP''@|$(REPLACE_EXECLP)|g' \\\n\t      -e 's|@''REPLACE_EXECV''@|$(REPLACE_EXECV)|g' \\\n\t      -e 's|@''REPLACE_EXECVE''@|$(REPLACE_EXECVE)|g' \\\n\t      -e 's|@''REPLACE_EXECVP''@|$(REPLACE_EXECVP)|g' \\\n\t      -e 's|@''REPLACE_EXECVPE''@|$(REPLACE_EXECVPE)|g' \\\n\t      -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \\\n\t      -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \\\n\t      -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \\\n\t      -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \\\n\t      -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \\\n\t      -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \\\n\t      -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \\\n\t      -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \\\n\t      -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \\\n\t      -e 's|@''REPLACE_GETPASS''@|$(REPLACE_GETPASS)|g' \\\n\t      -e 's|@''REPLACE_ISATTY''@|$(REPLACE_ISATTY)|g' \\\n\t      -e 's|@''REPLACE_LCHOWN''@|$(REPLACE_LCHOWN)|g' \\\n\t      -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \\\n\t      -e 's|@''REPLACE_LINKAT''@|$(REPLACE_LINKAT)|g' \\\n\t      -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \\\n\t      -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \\\n\t      -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \\\n\t      -e 's|@''REPLACE_READ''@|$(REPLACE_READ)|g' \\\n\t      -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \\\n\t      -e 's|@''REPLACE_READLINKAT''@|$(REPLACE_READLINKAT)|g' \\\n\t      -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \\\n\t      -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \\\n\t      -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \\\n\t      -e 's|@''REPLACE_SYMLINKAT''@|$(REPLACE_SYMLINKAT)|g' \\\n\t      -e 's|@''REPLACE_TRUNCATE''@|$(REPLACE_TRUNCATE)|g' \\\n\t      -e 's|@''REPLACE_TTYNAME_R''@|$(REPLACE_TTYNAME_R)|g' \\\n\t      -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \\\n\t      -e 's|@''REPLACE_UNLINKAT''@|$(REPLACE_UNLINKAT)|g' \\\n\t      -e 's|@''REPLACE_USLEEP''@|$(REPLACE_USLEEP)|g' \\\n\t      -e 's|@''REPLACE_WRITE''@|$(REPLACE_WRITE)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_SYS_RANDOM_H''@|$(UNISTD_H_HAVE_SYS_RANDOM_H)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_WINSOCK2_H''@|$(UNISTD_H_HAVE_WINSOCK2_H)|g' \\\n\t      -e 's|@''UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS''@|$(UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS)|g' \\\n\t      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \\\n\t      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \\\n\t      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \\\n\t} > $@-t && \\\n\tmv $@-t $@\n\nmostlyclean-local: mostlyclean-generic\n\t@for dir in '' $(MOSTLYCLEANDIRS); do \\\n\t  if test -n \"$$dir\" && test -d $$dir; then \\\n\t    echo \"rmdir $$dir\"; rmdir $$dir; \\\n\t  fi; \\\n\tdone; \\\n\t:\n\n# Tell versions [3.59,3.63) of GNU make to not export all variables.\n# Otherwise a system limit (for SysV at least) may be exceeded.\n.NOEXPORT:\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/_Noreturn.h",
    "content": "/* A C macro for declaring that a function does not return.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This program is free software: you can redistribute it and/or modify it\n   under the terms of the GNU Lesser General Public License as published\n   by the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _Noreturn\n# if (defined __cplusplus \\\n      && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \\\n          || (defined _MSC_VER && 1900 <= _MSC_VER)) \\\n      && 0)\n    /* [[noreturn]] is not practically usable, because with it the syntax\n         extern _Noreturn void func (...);\n       would not be valid; such a declaration would only be valid with 'extern'\n       and '_Noreturn' swapped, or without the 'extern' keyword.  However, some\n       AIX system header files and several gnulib header files use precisely\n       this syntax with 'extern'.  */\n#  define _Noreturn [[noreturn]]\n# elif ((!defined __cplusplus || defined __clang__) \\\n        && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \\\n            || (!defined __STRICT_ANSI__ \\\n                && (4 < __GNUC__ + (7 <= __GNUC_MINOR__) \\\n                    || (defined __apple_build_version__ \\\n                        ? 6000000 <= __apple_build_version__ \\\n                        : 3 < __clang_major__ + (5 <= __clang_minor__))))))\n   /* _Noreturn works as-is.  */\n# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \\\n        || 0x5110 <= __SUNPRO_C)\n#  define _Noreturn __attribute__ ((__noreturn__))\n# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)\n#  define _Noreturn __declspec (noreturn)\n# else\n#  define _Noreturn\n# endif\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/arg-nonnull.h",
    "content": "/* A C macro for declaring that specific arguments must not be NULL.\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n\n   This program is free software: you can redistribute it and/or modify it\n   under the terms of the GNU Lesser General Public License as published\n   by the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools\n   that the values passed as arguments n, ..., m must be non-NULL pointers.\n   n = 1 stands for the first argument, n = 2 for the second argument etc.  */\n#ifndef _GL_ARG_NONNULL\n# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || defined __clang__\n#  define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))\n# else\n#  define _GL_ARG_NONNULL(params)\n# endif\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/c++defs.h",
    "content": "/* C++ compatible function declaration macros.\n   Copyright (C) 2010-2021 Free Software Foundation, Inc.\n\n   This program is free software: you can redistribute it and/or modify it\n   under the terms of the GNU Lesser General Public License as published\n   by the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _GL_CXXDEFS_H\n#define _GL_CXXDEFS_H\n\n/* Begin/end the GNULIB_NAMESPACE namespace.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {\n# define _GL_END_NAMESPACE }\n#else\n# define _GL_BEGIN_NAMESPACE\n# define _GL_END_NAMESPACE\n#endif\n\n/* The three most frequent use cases of these macros are:\n\n   * For providing a substitute for a function that is missing on some\n     platforms, but is declared and works fine on the platforms on which\n     it exists:\n\n       #if @GNULIB_FOO@\n       # if !@HAVE_FOO@\n       _GL_FUNCDECL_SYS (foo, ...);\n       # endif\n       _GL_CXXALIAS_SYS (foo, ...);\n       _GL_CXXALIASWARN (foo);\n       #elif defined GNULIB_POSIXCHECK\n       ...\n       #endif\n\n   * For providing a replacement for a function that exists on all platforms,\n     but is broken/insufficient and needs to be replaced on some platforms:\n\n       #if @GNULIB_FOO@\n       # if @REPLACE_FOO@\n       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n       #   undef foo\n       #   define foo rpl_foo\n       #  endif\n       _GL_FUNCDECL_RPL (foo, ...);\n       _GL_CXXALIAS_RPL (foo, ...);\n       # else\n       _GL_CXXALIAS_SYS (foo, ...);\n       # endif\n       _GL_CXXALIASWARN (foo);\n       #elif defined GNULIB_POSIXCHECK\n       ...\n       #endif\n\n   * For providing a replacement for a function that exists on some platforms\n     but is broken/insufficient and needs to be replaced on some of them and\n     is additionally either missing or undeclared on some other platforms:\n\n       #if @GNULIB_FOO@\n       # if @REPLACE_FOO@\n       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n       #   undef foo\n       #   define foo rpl_foo\n       #  endif\n       _GL_FUNCDECL_RPL (foo, ...);\n       _GL_CXXALIAS_RPL (foo, ...);\n       # else\n       #  if !@HAVE_FOO@   or   if !@HAVE_DECL_FOO@\n       _GL_FUNCDECL_SYS (foo, ...);\n       #  endif\n       _GL_CXXALIAS_SYS (foo, ...);\n       # endif\n       _GL_CXXALIASWARN (foo);\n       #elif defined GNULIB_POSIXCHECK\n       ...\n       #endif\n*/\n\n/* _GL_EXTERN_C declaration;\n   performs the declaration with C linkage.  */\n#if defined __cplusplus\n# define _GL_EXTERN_C extern \"C\"\n#else\n# define _GL_EXTERN_C extern\n#endif\n\n/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);\n   declares a replacement function, named rpl_func, with the given prototype,\n   consisting of return type, parameters, and attributes.\n   Example:\n     _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)\n                                  _GL_ARG_NONNULL ((1)));\n */\n#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \\\n  _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)\n#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \\\n  _GL_EXTERN_C rettype rpl_func parameters_and_attributes\n\n/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);\n   declares the system function, named func, with the given prototype,\n   consisting of return type, parameters, and attributes.\n   Example:\n     _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)\n                                  _GL_ARG_NONNULL ((1)));\n */\n#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \\\n  _GL_EXTERN_C rettype func parameters_and_attributes\n\n/* _GL_CXXALIAS_RPL (func, rettype, parameters);\n   declares a C++ alias called GNULIB_NAMESPACE::func\n   that redirects to rpl_func, if GNULIB_NAMESPACE is defined.\n   Example:\n     _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));\n\n   Wrapping rpl_func in an object with an inline conversion operator\n   avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is\n   actually used in the program.  */\n#define _GL_CXXALIAS_RPL(func,rettype,parameters) \\\n  _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \\\n    namespace GNULIB_NAMESPACE                                \\\n    {                                                         \\\n      static const struct _gl_ ## func ## _wrapper            \\\n      {                                                       \\\n        typedef rettype (*type) parameters;                   \\\n                                                              \\\n        inline operator type () const                         \\\n        {                                                     \\\n          return ::rpl_func;                                  \\\n        }                                                     \\\n      } func = {};                                            \\\n    }                                                         \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#else\n# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIAS_MDA (func, rettype, parameters);\n   is to be used when func is a Microsoft deprecated alias, on native Windows.\n   It declares a C++ alias called GNULIB_NAMESPACE::func\n   that redirects to _func, if GNULIB_NAMESPACE is defined.\n   Example:\n     _GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...));\n */\n#define _GL_CXXALIAS_MDA(func,rettype,parameters) \\\n  _GL_CXXALIAS_RPL_1 (func, _##func, rettype, parameters)\n\n/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);\n   is like  _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);\n   except that the C function rpl_func may have a slightly different\n   declaration.  A cast is used to silence the \"invalid conversion\" error\n   that would otherwise occur.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \\\n    namespace GNULIB_NAMESPACE                                     \\\n    {                                                              \\\n      static const struct _gl_ ## func ## _wrapper                 \\\n      {                                                            \\\n        typedef rettype (*type) parameters;                        \\\n                                                                   \\\n        inline operator type () const                              \\\n        {                                                          \\\n          return reinterpret_cast<type>(::rpl_func);               \\\n        }                                                          \\\n      } func = {};                                                 \\\n    }                                                              \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#else\n# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIAS_MDA_CAST (func, rettype, parameters);\n   is like  _GL_CXXALIAS_MDA (func, rettype, parameters);\n   except that the C function func may have a slightly different declaration.\n   A cast is used to silence the \"invalid conversion\" error that would\n   otherwise occur.  */\n#define _GL_CXXALIAS_MDA_CAST(func,rettype,parameters) \\\n  _GL_CXXALIAS_RPL_CAST_1 (func, _##func, rettype, parameters)\n\n/* _GL_CXXALIAS_SYS (func, rettype, parameters);\n   declares a C++ alias called GNULIB_NAMESPACE::func\n   that redirects to the system provided function func, if GNULIB_NAMESPACE\n   is defined.\n   Example:\n     _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));\n\n   Wrapping func in an object with an inline conversion operator\n   avoids a reference to func unless GNULIB_NAMESPACE::func is\n   actually used in the program.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIAS_SYS(func,rettype,parameters)            \\\n    namespace GNULIB_NAMESPACE                                \\\n    {                                                         \\\n      static const struct _gl_ ## func ## _wrapper            \\\n      {                                                       \\\n        typedef rettype (*type) parameters;                   \\\n                                                              \\\n        inline operator type () const                         \\\n        {                                                     \\\n          return ::func;                                      \\\n        }                                                     \\\n      } func = {};                                            \\\n    }                                                         \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#else\n# define _GL_CXXALIAS_SYS(func,rettype,parameters) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);\n   is like  _GL_CXXALIAS_SYS (func, rettype, parameters);\n   except that the C function func may have a slightly different declaration.\n   A cast is used to silence the \"invalid conversion\" error that would\n   otherwise occur.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \\\n    namespace GNULIB_NAMESPACE                          \\\n    {                                                   \\\n      static const struct _gl_ ## func ## _wrapper      \\\n      {                                                 \\\n        typedef rettype (*type) parameters;             \\\n                                                        \\\n        inline operator type () const                   \\\n        {                                               \\\n          return reinterpret_cast<type>(::func);        \\\n        }                                               \\\n      } func = {};                                      \\\n    }                                                   \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#else\n# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);\n   is like  _GL_CXXALIAS_SYS (func, rettype, parameters);\n   except that the C function is picked among a set of overloaded functions,\n   namely the one with rettype2 and parameters2.  Two consecutive casts\n   are used to silence the \"cannot find a match\" and \"invalid conversion\"\n   errors that would otherwise occur.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n  /* The outer cast must be a reinterpret_cast.\n     The inner cast: When the function is defined as a set of overloaded\n     functions, it works as a static_cast<>, choosing the designated variant.\n     When the function is defined as a single variant, it works as a\n     reinterpret_cast<>. The parenthesized cast syntax works both ways.  */\n# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \\\n    namespace GNULIB_NAMESPACE                                                \\\n    {                                                                         \\\n      static const struct _gl_ ## func ## _wrapper                            \\\n      {                                                                       \\\n        typedef rettype (*type) parameters;                                   \\\n                                                                              \\\n        inline operator type () const                                         \\\n        {                                                                     \\\n          return reinterpret_cast<type>((rettype2 (*) parameters2)(::func));  \\\n        }                                                                     \\\n      } func = {};                                                            \\\n    }                                                                         \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#else\n# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIASWARN (func);\n   causes a warning to be emitted when ::func is used but not when\n   GNULIB_NAMESPACE::func is used.  func must be defined without overloaded\n   variants.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIASWARN(func) \\\n   _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)\n# define _GL_CXXALIASWARN_1(func,namespace) \\\n   _GL_CXXALIASWARN_2 (func, namespace)\n/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,\n   we enable the warning only when not optimizing.  */\n# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)\n#  define _GL_CXXALIASWARN_2(func,namespace) \\\n    _GL_WARN_ON_USE (func, \\\n                     \"The symbol ::\" #func \" refers to the system function. \" \\\n                     \"Use \" #namespace \"::\" #func \" instead.\")\n# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING\n#  define _GL_CXXALIASWARN_2(func,namespace) \\\n     extern __typeof__ (func) func\n# else\n#  define _GL_CXXALIASWARN_2(func,namespace) \\\n     _GL_EXTERN_C int _gl_cxxalias_dummy\n# endif\n#else\n# define _GL_CXXALIASWARN(func) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);\n   causes a warning to be emitted when the given overloaded variant of ::func\n   is used but not when GNULIB_NAMESPACE::func is used.  */\n#if defined __cplusplus && defined GNULIB_NAMESPACE\n# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \\\n   _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \\\n                        GNULIB_NAMESPACE)\n# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \\\n   _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)\n/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,\n   we enable the warning only when not optimizing.  */\n# if !(defined __GNUC__ && !defined __clang__ && __OPTIMIZE__)\n#  define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \\\n    _GL_WARN_ON_USE_CXX (func, rettype, rettype, parameters_and_attributes, \\\n                         \"The symbol ::\" #func \" refers to the system function. \" \\\n                         \"Use \" #namespace \"::\" #func \" instead.\")\n# else\n#  define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \\\n     _GL_EXTERN_C int _gl_cxxalias_dummy\n# endif\n#else\n# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \\\n    _GL_EXTERN_C int _gl_cxxalias_dummy\n#endif\n\n#endif /* _GL_CXXDEFS_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/cdefs.h",
    "content": "/* Copyright (C) 1992-2021 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with the GNU C Library; if not, see\n   <https://www.gnu.org/licenses/>.  */\n\n#ifndef\t_SYS_CDEFS_H\n#define\t_SYS_CDEFS_H\t1\n\n/* We are almost always included from features.h. */\n#ifndef _FEATURES_H\n# include <features.h>\n#endif\n\n/* The GNU libc does not support any K&R compilers or the traditional mode\n   of ISO C compilers anymore.  Check for some of the combinations not\n   supported anymore.  */\n#if defined __GNUC__ && !defined __STDC__\n# error \"You need a ISO C conforming compiler to use the glibc headers\"\n#endif\n\n/* Some user header file might have defined this before.  */\n#undef\t__P\n#undef\t__PMT\n\n/* Compilers that lack __has_attribute may object to\n       #if defined __has_attribute && __has_attribute (...)\n   even though they do not need to evaluate the right-hand side of the &&.\n   Similarly for __has_builtin, etc.  */\n#if (defined __has_attribute \\\n     && (!defined __clang_minor__ \\\n         || 3 < __clang_major__ + (5 <= __clang_minor__)))\n# define __glibc_has_attribute(attr) __has_attribute (attr)\n#else\n# define __glibc_has_attribute(attr) 0\n#endif\n#ifdef __has_builtin\n# define __glibc_has_builtin(name) __has_builtin (name)\n#else\n# define __glibc_has_builtin(name) 0\n#endif\n#ifdef __has_extension\n# define __glibc_has_extension(ext) __has_extension (ext)\n#else\n# define __glibc_has_extension(ext) 0\n#endif\n\n#if defined __GNUC__ || defined __clang__\n\n/* All functions, except those with callbacks or those that\n   synchronize memory, are leaf functions.  */\n# if __GNUC_PREREQ (4, 6) && !defined _LIBC\n#  define __LEAF , __leaf__\n#  define __LEAF_ATTR __attribute__ ((__leaf__))\n# else\n#  define __LEAF\n#  define __LEAF_ATTR\n# endif\n\n/* GCC can always grok prototypes.  For C++ programs we add throw()\n   to help it optimize the function calls.  But this only works with\n   gcc 2.8.x and egcs.  For gcc 3.4 and up we even mark C functions\n   as non-throwing using a function attribute since programs can use\n   the -fexceptions options for C code as well.  */\n# if !defined __cplusplus \\\n     && (__GNUC_PREREQ (3, 4) || __glibc_has_attribute (__nothrow__))\n#  define __THROW\t__attribute__ ((__nothrow__ __LEAF))\n#  define __THROWNL\t__attribute__ ((__nothrow__))\n#  define __NTH(fct)\t__attribute__ ((__nothrow__ __LEAF)) fct\n#  define __NTHNL(fct)  __attribute__ ((__nothrow__)) fct\n# else\n#  if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major >= 4)\n#   if __cplusplus >= 201103L\n#    define __THROW\tnoexcept (true)\n#   else\n#    define __THROW\tthrow ()\n#   endif\n#   define __THROWNL\t__THROW\n#   define __NTH(fct)\t__LEAF_ATTR fct __THROW\n#   define __NTHNL(fct) fct __THROW\n#  else\n#   define __THROW\n#   define __THROWNL\n#   define __NTH(fct)\tfct\n#   define __NTHNL(fct) fct\n#  endif\n# endif\n\n#else\t/* Not GCC or clang.  */\n\n# if (defined __cplusplus\t\t\t\t\t\t\\\n      || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))\n#  define __inline\tinline\n# else\n#  define __inline\t\t/* No inline functions.  */\n# endif\n\n# define __THROW\n# define __THROWNL\n# define __NTH(fct)\tfct\n\n#endif\t/* GCC || clang.  */\n\n/* These two macros are not used in glibc anymore.  They are kept here\n   only because some other projects expect the macros to be defined.  */\n#define __P(args)\targs\n#define __PMT(args)\targs\n\n/* For these things, GCC behaves the ANSI way normally,\n   and the non-ANSI way under -traditional.  */\n\n#define __CONCAT(x,y)\tx ## y\n#define __STRING(x)\t#x\n\n/* This is not a typedef so `const __ptr_t' does the right thing.  */\n#define __ptr_t void *\n\n\n/* C++ needs to know that types and declarations are C, not C++.  */\n#ifdef\t__cplusplus\n# define __BEGIN_DECLS\textern \"C\" {\n# define __END_DECLS\t}\n#else\n# define __BEGIN_DECLS\n# define __END_DECLS\n#endif\n\n\n/* Fortify support.  */\n#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)\n#define __bos0(ptr) __builtin_object_size (ptr, 0)\n\n/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available.  */\n#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0)\n# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)\n# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)\n#else\n# define __glibc_objsize0(__o) __bos0 (__o)\n# define __glibc_objsize(__o) __bos (__o)\n#endif\n\n#if __GNUC_PREREQ (4,3)\n# define __warnattr(msg) __attribute__((__warning__ (msg)))\n# define __errordecl(name, msg) \\\n  extern void name (void) __attribute__((__error__ (msg)))\n#else\n# define __warnattr(msg)\n# define __errordecl(name, msg) extern void name (void)\n#endif\n\n/* Support for flexible arrays.\n   Headers that should use flexible arrays only if they're \"real\"\n   (e.g. only if they won't affect sizeof()) should test\n   #if __glibc_c99_flexarr_available.  */\n#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L && !defined __HP_cc\n# define __flexarr\t[]\n# define __glibc_c99_flexarr_available 1\n#elif __GNUC_PREREQ (2,97) || defined __clang__\n/* GCC 2.97 and clang support C99 flexible array members as an extension,\n   even when in C89 mode or compiling C++ (any version).  */\n# define __flexarr\t[]\n# define __glibc_c99_flexarr_available 1\n#elif defined __GNUC__\n/* Pre-2.97 GCC did not support C99 flexible arrays but did have\n   an equivalent extension with slightly different notation.  */\n# define __flexarr\t[0]\n# define __glibc_c99_flexarr_available 1\n#else\n/* Some other non-C99 compiler.  Approximate with [1].  */\n# define __flexarr\t[1]\n# define __glibc_c99_flexarr_available 0\n#endif\n\n\n/* __asm__ (\"xyz\") is used throughout the headers to rename functions\n   at the assembly language level.  This is wrapped by the __REDIRECT\n   macro, in order to support compilers that can do this some other\n   way.  When compilers don't support asm-names at all, we have to do\n   preprocessor tricks instead (which don't have exactly the right\n   semantics, but it's the best we can do).\n\n   Example:\n   int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */\n\n#if (defined __GNUC__ && __GNUC__ >= 2) || (__clang_major__ >= 4)\n\n# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))\n# ifdef __cplusplus\n#  define __REDIRECT_NTH(name, proto, alias) \\\n     name proto __THROW __asm__ (__ASMNAME (#alias))\n#  define __REDIRECT_NTHNL(name, proto, alias) \\\n     name proto __THROWNL __asm__ (__ASMNAME (#alias))\n# else\n#  define __REDIRECT_NTH(name, proto, alias) \\\n     name proto __asm__ (__ASMNAME (#alias)) __THROW\n#  define __REDIRECT_NTHNL(name, proto, alias) \\\n     name proto __asm__ (__ASMNAME (#alias)) __THROWNL\n# endif\n# define __ASMNAME(cname)  __ASMNAME2 (__USER_LABEL_PREFIX__, cname)\n# define __ASMNAME2(prefix, cname) __STRING (prefix) cname\n\n/*\n#elif __SOME_OTHER_COMPILER__\n\n# define __REDIRECT(name, proto, alias) name proto; \\\n\t_Pragma(\"let \" #name \" = \" #alias)\n*/\n#endif\n\n/* GCC and clang have various useful declarations that can be made with\n   the '__attribute__' syntax.  All of the ways we use this do fine if\n   they are omitted for compilers that don't understand it.  */\n#if !(defined __GNUC__ || defined __clang__)\n# define __attribute__(xyz)\t/* Ignore */\n#endif\n\n/* At some point during the gcc 2.96 development the `malloc' attribute\n   for functions was introduced.  We don't want to use it unconditionally\n   (although this would be possible) since it generates warnings.  */\n#if __GNUC_PREREQ (2,96) || __glibc_has_attribute (__malloc__)\n# define __attribute_malloc__ __attribute__ ((__malloc__))\n#else\n# define __attribute_malloc__ /* Ignore */\n#endif\n\n/* Tell the compiler which arguments to an allocation function\n   indicate the size of the allocation.  */\n#if __GNUC_PREREQ (4, 3)\n# define __attribute_alloc_size__(params) \\\n  __attribute__ ((__alloc_size__ params))\n#else\n# define __attribute_alloc_size__(params) /* Ignore.  */\n#endif\n\n/* At some point during the gcc 2.96 development the `pure' attribute\n   for functions was introduced.  We don't want to use it unconditionally\n   (although this would be possible) since it generates warnings.  */\n#if __GNUC_PREREQ (2,96) || __glibc_has_attribute (__pure__)\n# define __attribute_pure__ __attribute__ ((__pure__))\n#else\n# define __attribute_pure__ /* Ignore */\n#endif\n\n/* This declaration tells the compiler that the value is constant.  */\n#if __GNUC_PREREQ (2,5) || __glibc_has_attribute (__const__)\n# define __attribute_const__ __attribute__ ((__const__))\n#else\n# define __attribute_const__ /* Ignore */\n#endif\n\n#if __GNUC_PREREQ (2,7) || __glibc_has_attribute (__unused__)\n# define __attribute_maybe_unused__ __attribute__ ((__unused__))\n#else\n# define __attribute_maybe_unused__ /* Ignore */\n#endif\n\n/* At some point during the gcc 3.1 development the `used' attribute\n   for functions was introduced.  We don't want to use it unconditionally\n   (although this would be possible) since it generates warnings.  */\n#if __GNUC_PREREQ (3,1) || __glibc_has_attribute (__used__)\n# define __attribute_used__ __attribute__ ((__used__))\n# define __attribute_noinline__ __attribute__ ((__noinline__))\n#else\n# define __attribute_used__ __attribute__ ((__unused__))\n# define __attribute_noinline__ /* Ignore */\n#endif\n\n/* Since version 3.2, gcc allows marking deprecated functions.  */\n#if __GNUC_PREREQ (3,2) || __glibc_has_attribute (__deprecated__)\n# define __attribute_deprecated__ __attribute__ ((__deprecated__))\n#else\n# define __attribute_deprecated__ /* Ignore */\n#endif\n\n/* Since version 4.5, gcc also allows one to specify the message printed\n   when a deprecated function is used.  clang claims to be gcc 4.2, but\n   may also support this feature.  */\n#if __GNUC_PREREQ (4,5) \\\n    || __glibc_has_extension (__attribute_deprecated_with_message__)\n# define __attribute_deprecated_msg__(msg) \\\n\t __attribute__ ((__deprecated__ (msg)))\n#else\n# define __attribute_deprecated_msg__(msg) __attribute_deprecated__\n#endif\n\n/* At some point during the gcc 2.8 development the `format_arg' attribute\n   for functions was introduced.  We don't want to use it unconditionally\n   (although this would be possible) since it generates warnings.\n   If several `format_arg' attributes are given for the same function, in\n   gcc-3.0 and older, all but the last one are ignored.  In newer gccs,\n   all designated arguments are considered.  */\n#if __GNUC_PREREQ (2,8) || __glibc_has_attribute (__format_arg__)\n# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x)))\n#else\n# define __attribute_format_arg__(x) /* Ignore */\n#endif\n\n/* At some point during the gcc 2.97 development the `strfmon' format\n   attribute for functions was introduced.  We don't want to use it\n   unconditionally (although this would be possible) since it\n   generates warnings.  */\n#if __GNUC_PREREQ (2,97) || __glibc_has_attribute (__format__)\n# define __attribute_format_strfmon__(a,b) \\\n  __attribute__ ((__format__ (__strfmon__, a, b)))\n#else\n# define __attribute_format_strfmon__(a,b) /* Ignore */\n#endif\n\n/* The nonnull function attribute marks pointer parameters that\n   must not be NULL.  This has the name __nonnull in glibc,\n   and __attribute_nonnull__ in files shared with Gnulib to avoid\n   collision with a different __nonnull in DragonFlyBSD 5.9.  */\n#ifndef __attribute_nonnull__\n# if __GNUC_PREREQ (3,3) || __glibc_has_attribute (__nonnull__)\n#  define __attribute_nonnull__(params) __attribute__ ((__nonnull__ params))\n# else\n#  define __attribute_nonnull__(params)\n# endif\n#endif\n#ifndef __nonnull\n# define __nonnull(params) __attribute_nonnull__ (params)\n#endif\n\n/* The returns_nonnull function attribute marks the return type of the function\n   as always being non-null.  */\n#ifndef __returns_nonnull\n# if __GNUC_PREREQ (4, 9) || __glibc_has_attribute (__returns_nonnull__)\n# define __returns_nonnull __attribute__ ((__returns_nonnull__))\n# else\n# define __returns_nonnull\n# endif\n#endif\n\n/* If fortification mode, we warn about unused results of certain\n   function calls which can lead to problems.  */\n#if __GNUC_PREREQ (3,4) || __glibc_has_attribute (__warn_unused_result__)\n# define __attribute_warn_unused_result__ \\\n   __attribute__ ((__warn_unused_result__))\n# if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0\n#  define __wur __attribute_warn_unused_result__\n# endif\n#else\n# define __attribute_warn_unused_result__ /* empty */\n#endif\n#ifndef __wur\n# define __wur /* Ignore */\n#endif\n\n/* Forces a function to be always inlined.  */\n#if __GNUC_PREREQ (3,2) || __glibc_has_attribute (__always_inline__)\n/* The Linux kernel defines __always_inline in stddef.h (283d7573), and\n   it conflicts with this definition.  Therefore undefine it first to\n   allow either header to be included first.  */\n# undef __always_inline\n# define __always_inline __inline __attribute__ ((__always_inline__))\n#else\n# undef __always_inline\n# define __always_inline __inline\n#endif\n\n/* Associate error messages with the source location of the call site rather\n   than with the source location inside the function.  */\n#if __GNUC_PREREQ (4,3) || __glibc_has_attribute (__artificial__)\n# define __attribute_artificial__ __attribute__ ((__artificial__))\n#else\n# define __attribute_artificial__ /* Ignore */\n#endif\n\n/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99\n   inline semantics, unless -fgnu89-inline is used.  Using __GNUC_STDC_INLINE__\n   or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions\n   older than 4.3 may define these macros and still not guarantee GNU inlining\n   semantics.\n\n   clang++ identifies itself as gcc-4.2, but has support for GNU inlining\n   semantics, that can be checked for by using the __GNUC_STDC_INLINE_ and\n   __GNUC_GNU_INLINE__ macro definitions.  */\n#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \\\n     || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \\\n\t\t\t       || defined __GNUC_GNU_INLINE__)))\n# if defined __GNUC_STDC_INLINE__ || defined __cplusplus\n#  define __extern_inline extern __inline __attribute__ ((__gnu_inline__))\n#  define __extern_always_inline \\\n  extern __always_inline __attribute__ ((__gnu_inline__))\n# else\n#  define __extern_inline extern __inline\n#  define __extern_always_inline extern __always_inline\n# endif\n#endif\n\n#ifdef __extern_always_inline\n# define __fortify_function __extern_always_inline __attribute_artificial__\n#endif\n\n/* GCC 4.3 and above allow passing all anonymous arguments of an\n   __extern_always_inline function to some other vararg function.  */\n#if __GNUC_PREREQ (4,3)\n# define __va_arg_pack() __builtin_va_arg_pack ()\n# define __va_arg_pack_len() __builtin_va_arg_pack_len ()\n#endif\n\n/* It is possible to compile containing GCC extensions even if GCC is\n   run in pedantic mode if the uses are carefully marked using the\n   `__extension__' keyword.  But this is not generally available before\n   version 2.8.  */\n#if !(__GNUC_PREREQ (2,8) || defined __clang__)\n# define __extension__\t\t/* Ignore */\n#endif\n\n/* __restrict is known in EGCS 1.2 and above, and in clang.\n   It works also in C++ mode (outside of arrays), but only when spelled\n   as '__restrict', not 'restrict'.  */\n#if !(__GNUC_PREREQ (2,92) || __clang_major__ >= 3)\n# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L\n#  define __restrict\trestrict\n# else\n#  define __restrict\t/* Ignore */\n# endif\n#endif\n\n/* ISO C99 also allows to declare arrays as non-overlapping.  The syntax is\n     array_name[restrict]\n   GCC 3.1 and clang support this.\n   This syntax is not usable in C++ mode.  */\n#if (__GNUC_PREREQ (3,1) || __clang_major__ >= 3) && !defined __cplusplus\n# define __restrict_arr\t__restrict\n#else\n# ifdef __GNUC__\n#  define __restrict_arr\t/* Not supported in old GCC.  */\n# else\n#  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L\n#   define __restrict_arr\trestrict\n#  else\n/* Some other non-C99 compiler.  */\n#   define __restrict_arr\t/* Not supported.  */\n#  endif\n# endif\n#endif\n\n#if (__GNUC__ >= 3) || __glibc_has_builtin (__builtin_expect)\n# define __glibc_unlikely(cond)\t__builtin_expect ((cond), 0)\n# define __glibc_likely(cond)\t__builtin_expect ((cond), 1)\n#else\n# define __glibc_unlikely(cond)\t(cond)\n# define __glibc_likely(cond)\t(cond)\n#endif\n\n#if (!defined _Noreturn \\\n     && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \\\n     &&  !(__GNUC_PREREQ (4,7) \\\n           || (3 < __clang_major__ + (5 <= __clang_minor__))))\n# if __GNUC_PREREQ (2,8)\n#  define _Noreturn __attribute__ ((__noreturn__))\n# else\n#  define _Noreturn\n# endif\n#endif\n\n#if __GNUC_PREREQ (8, 0)\n/* Describes a char array whose address can safely be passed as the first\n   argument to strncpy and strncat, as the char array is not necessarily\n   a NUL-terminated string.  */\n# define __attribute_nonstring__ __attribute__ ((__nonstring__))\n#else\n# define __attribute_nonstring__\n#endif\n\n/* Undefine (also defined in libc-symbols.h).  */\n#undef __attribute_copy__\n#if __GNUC_PREREQ (9, 0)\n/* Copies attributes from the declaration or type referenced by\n   the argument.  */\n# define __attribute_copy__(arg) __attribute__ ((__copy__ (arg)))\n#else\n# define __attribute_copy__(arg)\n#endif\n\n#if (!defined _Static_assert && !defined __cplusplus \\\n     && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \\\n     && (!(__GNUC_PREREQ (4, 6) || __clang_major__ >= 4) \\\n         || defined __STRICT_ANSI__))\n# define _Static_assert(expr, diagnostic) \\\n    extern int (*__Static_assert_function (void)) \\\n      [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]\n#endif\n\n/* Gnulib avoids including these, as they don't work on non-glibc or\n   older glibc platforms.  */\n#ifndef __GNULIB_CDEFS\n# include <bits/wordsize.h>\n# include <bits/long-double.h>\n#endif\n\n#if __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1\n# ifdef __REDIRECT\n\n/* Alias name defined automatically.  */\n#  define __LDBL_REDIR(name, proto) ... unused__ldbl_redir\n#  define __LDBL_REDIR_DECL(name) \\\n  extern __typeof (name) name __asm (__ASMNAME (\"__\" #name \"ieee128\"));\n\n/* Alias name defined automatically, with leading underscores.  */\n#  define __LDBL_REDIR2_DECL(name) \\\n  extern __typeof (__##name) __##name \\\n    __asm (__ASMNAME (\"__\" #name \"ieee128\"));\n\n/* Alias name defined manually.  */\n#  define __LDBL_REDIR1(name, proto, alias) ... unused__ldbl_redir1\n#  define __LDBL_REDIR1_DECL(name, alias) \\\n  extern __typeof (name) name __asm (__ASMNAME (#alias));\n\n#  define __LDBL_REDIR1_NTH(name, proto, alias) \\\n  __REDIRECT_NTH (name, proto, alias)\n#  define __REDIRECT_NTH_LDBL(name, proto, alias) \\\n  __LDBL_REDIR1_NTH (name, proto, __##alias##ieee128)\n\n/* Unused.  */\n#  define __REDIRECT_LDBL(name, proto, alias) ... unused__redirect_ldbl\n#  define __LDBL_REDIR_NTH(name, proto) ... unused__ldbl_redir_nth\n\n# else\n_Static_assert (0, \"IEEE 128-bits long double requires redirection on this platform\");\n# endif\n#elif defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH\n# define __LDBL_COMPAT 1\n# ifdef __REDIRECT\n#  define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias)\n#  define __LDBL_REDIR(name, proto) \\\n  __LDBL_REDIR1 (name, proto, __nldbl_##name)\n#  define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias)\n#  define __LDBL_REDIR_NTH(name, proto) \\\n  __LDBL_REDIR1_NTH (name, proto, __nldbl_##name)\n#  define __LDBL_REDIR2_DECL(name) \\\n  extern __typeof (__##name) __##name __asm (__ASMNAME (\"__nldbl___\" #name));\n#  define __LDBL_REDIR1_DECL(name, alias) \\\n  extern __typeof (name) name __asm (__ASMNAME (#alias));\n#  define __LDBL_REDIR_DECL(name) \\\n  extern __typeof (name) name __asm (__ASMNAME (\"__nldbl_\" #name));\n#  define __REDIRECT_LDBL(name, proto, alias) \\\n  __LDBL_REDIR1 (name, proto, __nldbl_##alias)\n#  define __REDIRECT_NTH_LDBL(name, proto, alias) \\\n  __LDBL_REDIR1_NTH (name, proto, __nldbl_##alias)\n# endif\n#endif\n#if (!defined __LDBL_COMPAT && __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 0) \\\n    || !defined __REDIRECT\n# define __LDBL_REDIR1(name, proto, alias) name proto\n# define __LDBL_REDIR(name, proto) name proto\n# define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW\n# define __LDBL_REDIR_NTH(name, proto) name proto __THROW\n# define __LDBL_REDIR2_DECL(name)\n# define __LDBL_REDIR_DECL(name)\n# ifdef __REDIRECT\n#  define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias)\n#  define __REDIRECT_NTH_LDBL(name, proto, alias) \\\n  __REDIRECT_NTH (name, proto, alias)\n# endif\n#endif\n\n/* __glibc_macro_warning (MESSAGE) issues warning MESSAGE.  This is\n   intended for use in preprocessor macros.\n\n   Note: MESSAGE must be a _single_ string; concatenation of string\n   literals is not supported.  */\n#if __GNUC_PREREQ (4,8) || __glibc_clang_prereq (3,5)\n# define __glibc_macro_warning1(message) _Pragma (#message)\n# define __glibc_macro_warning(message) \\\n  __glibc_macro_warning1 (GCC warning message)\n#else\n# define __glibc_macro_warning(msg)\n#endif\n\n/* Generic selection (ISO C11) is a C-only feature, available in GCC\n   since version 4.9.  Previous versions do not provide generic\n   selection, even though they might set __STDC_VERSION__ to 201112L,\n   when in -std=c11 mode.  Thus, we must check for !defined __GNUC__\n   when testing __STDC_VERSION__ for generic selection support.\n   On the other hand, Clang also defines __GNUC__, so a clang-specific\n   check is required to enable the use of generic selection.  */\n#if !defined __cplusplus \\\n    && (__GNUC_PREREQ (4, 9) \\\n\t|| __glibc_has_extension (c_generic_selections) \\\n\t|| (!defined __GNUC__ && defined __STDC_VERSION__ \\\n\t    && __STDC_VERSION__ >= 201112L))\n# define __HAVE_GENERIC_SELECTION 1\n#else\n# define __HAVE_GENERIC_SELECTION 0\n#endif\n\n#if __GNUC_PREREQ (10, 0)\n/* Designates a 1-based positional argument ref-index of pointer type\n   that can be used to access size-index elements of the pointed-to\n   array according to access mode, or at least one element when\n   size-index is not provided:\n     access (access-mode, <ref-index> [, <size-index>])  */\n#  define __attr_access(x) __attribute__ ((__access__ x))\n#  if __GNUC_PREREQ (11, 0)\n#    define __attr_access_none(argno) __attribute__ ((__access__ (__none__, argno)))\n#  else\n#    define __attr_access_none(argno)\n#  endif\n#else\n#  define __attr_access(x)\n#  define __attr_access_none(argno)\n#endif\n\n#if __GNUC_PREREQ (11, 0)\n/* Designates dealloc as a function to call to deallocate objects\n   allocated by the declared function.  */\n# define __attr_dealloc(dealloc, argno) \\\n    __attribute__ ((__malloc__ (dealloc, argno)))\n# define __attr_dealloc_free __attr_dealloc (__builtin_free, 1)\n#else\n# define __attr_dealloc(dealloc, argno)\n# define __attr_dealloc_free\n#endif\n\n/* Specify that a function such as setjmp or vfork may return\n   twice.  */\n#if __GNUC_PREREQ (4, 1)\n# define __attribute_returns_twice__ __attribute__ ((__returns_twice__))\n#else\n# define __attribute_returns_twice__ /* Ignore.  */\n#endif\n\n#endif\t /* sys/cdefs.h */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/errno.in.h",
    "content": "/* A POSIX-like <errno.h>.\n\n   Copyright (C) 2008-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _@GUARD_PREFIX@_ERRNO_H\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n/* The include_next requires a split double-inclusion guard.  */\n#@INCLUDE_NEXT@ @NEXT_ERRNO_H@\n\n#ifndef _@GUARD_PREFIX@_ERRNO_H\n#define _@GUARD_PREFIX@_ERRNO_H\n\n\n/* On native Windows platforms, many macros are not defined.  */\n# if defined _WIN32 && ! defined __CYGWIN__\n\n/* These are the same values as defined by MSVC 10, for interoperability.  */\n\n#  ifndef ENOMSG\n#   define ENOMSG    122\n#   define GNULIB_defined_ENOMSG 1\n#  endif\n\n#  ifndef EIDRM\n#   define EIDRM     111\n#   define GNULIB_defined_EIDRM 1\n#  endif\n\n#  ifndef ENOLINK\n#   define ENOLINK   121\n#   define GNULIB_defined_ENOLINK 1\n#  endif\n\n#  ifndef EPROTO\n#   define EPROTO    134\n#   define GNULIB_defined_EPROTO 1\n#  endif\n\n#  ifndef EBADMSG\n#   define EBADMSG   104\n#   define GNULIB_defined_EBADMSG 1\n#  endif\n\n#  ifndef EOVERFLOW\n#   define EOVERFLOW 132\n#   define GNULIB_defined_EOVERFLOW 1\n#  endif\n\n#  ifndef ENOTSUP\n#   define ENOTSUP   129\n#   define GNULIB_defined_ENOTSUP 1\n#  endif\n\n#  ifndef ENETRESET\n#   define ENETRESET 117\n#   define GNULIB_defined_ENETRESET 1\n#  endif\n\n#  ifndef ECONNABORTED\n#   define ECONNABORTED 106\n#   define GNULIB_defined_ECONNABORTED 1\n#  endif\n\n#  ifndef ECANCELED\n#   define ECANCELED 105\n#   define GNULIB_defined_ECANCELED 1\n#  endif\n\n#  ifndef EOWNERDEAD\n#   define EOWNERDEAD 133\n#   define GNULIB_defined_EOWNERDEAD 1\n#  endif\n\n#  ifndef ENOTRECOVERABLE\n#   define ENOTRECOVERABLE 127\n#   define GNULIB_defined_ENOTRECOVERABLE 1\n#  endif\n\n#  ifndef EINPROGRESS\n#   define EINPROGRESS     112\n#   define EALREADY        103\n#   define ENOTSOCK        128\n#   define EDESTADDRREQ    109\n#   define EMSGSIZE        115\n#   define EPROTOTYPE      136\n#   define ENOPROTOOPT     123\n#   define EPROTONOSUPPORT 135\n#   define EOPNOTSUPP      130\n#   define EAFNOSUPPORT    102\n#   define EADDRINUSE      100\n#   define EADDRNOTAVAIL   101\n#   define ENETDOWN        116\n#   define ENETUNREACH     118\n#   define ECONNRESET      108\n#   define ENOBUFS         119\n#   define EISCONN         113\n#   define ENOTCONN        126\n#   define ETIMEDOUT       138\n#   define ECONNREFUSED    107\n#   define ELOOP           114\n#   define EHOSTUNREACH    110\n#   define EWOULDBLOCK     140\n#   define GNULIB_defined_ESOCK 1\n#  endif\n\n#  ifndef ETXTBSY\n#   define ETXTBSY         139\n#   define ENODATA         120  /* not required by POSIX */\n#   define ENOSR           124  /* not required by POSIX */\n#   define ENOSTR          125  /* not required by POSIX */\n#   define ETIME           137  /* not required by POSIX */\n#   define EOTHER          131  /* not required by POSIX */\n#   define GNULIB_defined_ESTREAMS 1\n#  endif\n\n/* These are intentionally the same values as the WSA* error numbers, defined\n   in <winsock2.h>.  */\n#  define ESOCKTNOSUPPORT 10044  /* not required by POSIX */\n#  define EPFNOSUPPORT    10046  /* not required by POSIX */\n#  define ESHUTDOWN       10058  /* not required by POSIX */\n#  define ETOOMANYREFS    10059  /* not required by POSIX */\n#  define EHOSTDOWN       10064  /* not required by POSIX */\n#  define EPROCLIM        10067  /* not required by POSIX */\n#  define EUSERS          10068  /* not required by POSIX */\n#  define EDQUOT          10069\n#  define ESTALE          10070\n#  define EREMOTE         10071  /* not required by POSIX */\n#  define GNULIB_defined_EWINSOCK 1\n\n# endif\n\n\n/* On OSF/1 5.1, when _XOPEN_SOURCE_EXTENDED is not defined, the macros\n   EMULTIHOP, ENOLINK, EOVERFLOW are not defined.  */\n# if @EMULTIHOP_HIDDEN@\n#  define EMULTIHOP @EMULTIHOP_VALUE@\n#  define GNULIB_defined_EMULTIHOP 1\n# endif\n# if @ENOLINK_HIDDEN@\n#  define ENOLINK   @ENOLINK_VALUE@\n#  define GNULIB_defined_ENOLINK 1\n# endif\n# if @EOVERFLOW_HIDDEN@\n#  define EOVERFLOW @EOVERFLOW_VALUE@\n#  define GNULIB_defined_EOVERFLOW 1\n# endif\n\n\n/* On OpenBSD 4.0 and on native Windows, the macros ENOMSG, EIDRM, ENOLINK,\n   EPROTO, EMULTIHOP, EBADMSG, EOVERFLOW, ENOTSUP, ECANCELED are not defined.\n   Likewise, on NonStop Kernel, EDQUOT is not defined.\n   Define them here.  Values >= 2000 seem safe to use: Solaris ESTALE = 151,\n   HP-UX EWOULDBLOCK = 246, IRIX EDQUOT = 1133.\n\n   Note: When one of these systems defines some of these macros some day,\n   binaries will have to be recompiled so that they recognizes the new\n   errno values from the system.  */\n\n# ifndef ENOMSG\n#  define ENOMSG    2000\n#  define GNULIB_defined_ENOMSG 1\n# endif\n\n# ifndef EIDRM\n#  define EIDRM     2001\n#  define GNULIB_defined_EIDRM 1\n# endif\n\n# ifndef ENOLINK\n#  define ENOLINK   2002\n#  define GNULIB_defined_ENOLINK 1\n# endif\n\n# ifndef EPROTO\n#  define EPROTO    2003\n#  define GNULIB_defined_EPROTO 1\n# endif\n\n# ifndef EMULTIHOP\n#  define EMULTIHOP 2004\n#  define GNULIB_defined_EMULTIHOP 1\n# endif\n\n# ifndef EBADMSG\n#  define EBADMSG   2005\n#  define GNULIB_defined_EBADMSG 1\n# endif\n\n# ifndef EOVERFLOW\n#  define EOVERFLOW 2006\n#  define GNULIB_defined_EOVERFLOW 1\n# endif\n\n# ifndef ENOTSUP\n#  define ENOTSUP   2007\n#  define GNULIB_defined_ENOTSUP 1\n# endif\n\n# ifndef ENETRESET\n#  define ENETRESET 2011\n#  define GNULIB_defined_ENETRESET 1\n# endif\n\n# ifndef ECONNABORTED\n#  define ECONNABORTED 2012\n#  define GNULIB_defined_ECONNABORTED 1\n# endif\n\n# ifndef ESTALE\n#  define ESTALE    2009\n#  define GNULIB_defined_ESTALE 1\n# endif\n\n# ifndef EDQUOT\n#  define EDQUOT 2010\n#  define GNULIB_defined_EDQUOT 1\n# endif\n\n# ifndef ECANCELED\n#  define ECANCELED 2008\n#  define GNULIB_defined_ECANCELED 1\n# endif\n\n/* On many platforms, the macros EOWNERDEAD and ENOTRECOVERABLE are not\n   defined.  */\n\n# ifndef EOWNERDEAD\n#  if defined __sun\n    /* Use the same values as defined for Solaris >= 8, for\n       interoperability.  */\n#   define EOWNERDEAD      58\n#   define ENOTRECOVERABLE 59\n#  elif defined _WIN32 && ! defined __CYGWIN__\n    /* We have a conflict here: pthreads-win32 defines these values\n       differently than MSVC 10.  It's hairy to decide which one to use.  */\n#   if defined __MINGW32__ && !defined USE_WINDOWS_THREADS\n     /* Use the same values as defined by pthreads-win32, for\n        interoperability.  */\n#    define EOWNERDEAD      43\n#    define ENOTRECOVERABLE 44\n#   else\n     /* Use the same values as defined by MSVC 10, for\n        interoperability.  */\n#    define EOWNERDEAD      133\n#    define ENOTRECOVERABLE 127\n#   endif\n#  else\n#   define EOWNERDEAD      2013\n#   define ENOTRECOVERABLE 2014\n#  endif\n#  define GNULIB_defined_EOWNERDEAD 1\n#  define GNULIB_defined_ENOTRECOVERABLE 1\n# endif\n\n# ifndef EILSEQ\n#  define EILSEQ 2015\n#  define GNULIB_defined_EILSEQ 1\n# endif\n\n#endif /* _@GUARD_PREFIX@_ERRNO_H */\n#endif /* _@GUARD_PREFIX@_ERRNO_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/execinfo.c",
    "content": "/* Information about executables.\n\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n#define _GL_EXECINFO_INLINE _GL_EXTERN_INLINE\n#include \"execinfo.h\"\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/execinfo.in.h",
    "content": "/* Information about executables.\n\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n\n   This program is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as published by\n   the Free Software Foundation; either version 2.1 of the License, or\n   (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paul Eggert.  */\n\n#ifndef _GL_EXECINFO_H\n#define _GL_EXECINFO_H\n\n#ifndef _GL_INLINE_HEADER_BEGIN\n #error \"Please include config.h first.\"\n#endif\n_GL_INLINE_HEADER_BEGIN\n#ifndef _GL_EXECINFO_INLINE\n# define _GL_EXECINFO_INLINE _GL_INLINE\n#endif\n\n_GL_EXECINFO_INLINE int\nbacktrace (void **buffer, int size)\n{\n  (void) buffer;\n  (void) size;\n  return 0;\n}\n\n_GL_EXECINFO_INLINE char **\nbacktrace_symbols (void *const *buffer, int size)\n{\n  (void) buffer;\n  (void) size;\n  return 0;\n}\n\n_GL_EXECINFO_INLINE void\nbacktrace_symbols_fd (void *const *buffer, int size, int fd)\n{\n  (void) buffer;\n  (void) size;\n  (void) fd;\n}\n\n_GL_INLINE_HEADER_END\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/fd-hook.c",
    "content": "/* Hook for making file descriptor functions close(), ioctl() extensible.\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n   Written by Bruno Haible <bruno@clisp.org>, 2009.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n/* Specification.  */\n#include \"fd-hook.h\"\n\n#include <stdlib.h>\n\n/* Currently, this entire code is only needed for the handling of sockets\n   on native Windows platforms.  */\n#if WINDOWS_SOCKETS\n\n/* The first and last link in the doubly linked list.\n   Initially the list is empty.  */\nstatic struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };\n\nint\nexecute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,\n                     int fd)\n{\n  if (remaining_list == &anchor)\n    /* End of list reached.  */\n    return primary (fd);\n  else\n    return remaining_list->private_close_fn (remaining_list->private_next,\n                                             primary, fd);\n}\n\nint\nexecute_all_close_hooks (gl_close_fn primary, int fd)\n{\n  return execute_close_hooks (anchor.private_next, primary, fd);\n}\n\nint\nexecute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,\n                     int fd, int request, void *arg)\n{\n  if (remaining_list == &anchor)\n    /* End of list reached.  */\n    return primary (fd, request, arg);\n  else\n    return remaining_list->private_ioctl_fn (remaining_list->private_next,\n                                             primary, fd, request, arg);\n}\n\nint\nexecute_all_ioctl_hooks (gl_ioctl_fn primary,\n                         int fd, int request, void *arg)\n{\n  return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);\n}\n\nvoid\nregister_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)\n{\n  if (close_hook == NULL)\n    close_hook = execute_close_hooks;\n  if (ioctl_hook == NULL)\n    ioctl_hook = execute_ioctl_hooks;\n\n  if (link->private_next == NULL && link->private_prev == NULL)\n    {\n      /* Add the link to the doubly linked list.  */\n      link->private_next = anchor.private_next;\n      link->private_prev = &anchor;\n      link->private_close_fn = close_hook;\n      link->private_ioctl_fn = ioctl_hook;\n      anchor.private_next->private_prev = link;\n      anchor.private_next = link;\n    }\n  else\n    {\n      /* The link is already in use.  */\n      if (link->private_close_fn != close_hook\n          || link->private_ioctl_fn != ioctl_hook)\n        abort ();\n    }\n}\n\nvoid\nunregister_fd_hook (struct fd_hook *link)\n{\n  struct fd_hook *next = link->private_next;\n  struct fd_hook *prev = link->private_prev;\n\n  if (next != NULL && prev != NULL)\n    {\n      /* The link is in use.  Remove it from the doubly linked list.  */\n      prev->private_next = next;\n      next->private_prev = prev;\n      /* Clear the link, to mark it unused.  */\n      link->private_next = NULL;\n      link->private_prev = NULL;\n      link->private_close_fn = NULL;\n      link->private_ioctl_fn = NULL;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/fd-hook.h",
    "content": "/* Hook for making file descriptor functions close(), ioctl() extensible.\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n\n#ifndef FD_HOOK_H\n#define FD_HOOK_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/* Currently, this entire code is only needed for the handling of sockets\n   on native Windows platforms.  */\n#if WINDOWS_SOCKETS\n\n\n/* Type of function that closes FD.  */\ntypedef int (*gl_close_fn) (int fd);\n\n/* Type of function that applies a control request to FD.  */\ntypedef int (*gl_ioctl_fn) (int fd, int request, void *arg);\n\n/* An element of the list of file descriptor hooks.\n   In CLOS (Common Lisp Object System) speak, it consists of an \"around\"\n   method for the close() function and an \"around\" method for the ioctl()\n   function.\n   The fields of this structure are considered private.  */\nstruct fd_hook\n{\n  /* Doubly linked list.  */\n  struct fd_hook *private_next;\n  struct fd_hook *private_prev;\n  /* Function that treats the types of FD that it knows about and calls\n     execute_close_hooks (REMAINING_LIST, PRIMARY, FD) as a fallback.  */\n  int (*private_close_fn) (const struct fd_hook *remaining_list,\n                           gl_close_fn primary,\n                           int fd);\n  /* Function that treats the types of FD that it knows about and calls\n     execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG) as a\n     fallback.  */\n  int (*private_ioctl_fn) (const struct fd_hook *remaining_list,\n                           gl_ioctl_fn primary,\n                           int fd, int request, void *arg);\n};\n\n/* This type of function closes FD, applying special knowledge for the FD\n   types it knows about, and calls\n   execute_close_hooks (REMAINING_LIST, PRIMARY, FD)\n   for the other FD types.\n   In CLOS speak, REMAINING_LIST is the remaining list of \"around\" methods,\n   and PRIMARY is the \"primary\" method for close().  */\ntypedef int (*close_hook_fn) (const struct fd_hook *remaining_list,\n                              gl_close_fn primary,\n                              int fd);\n\n/* Execute the close hooks in REMAINING_LIST, with PRIMARY as \"primary\" method.\n   Return 0 or -1, like close() would do.  */\nextern int execute_close_hooks (const struct fd_hook *remaining_list,\n                                gl_close_fn primary,\n                                int fd);\n\n/* Execute all close hooks, with PRIMARY as \"primary\" method.\n   Return 0 or -1, like close() would do.  */\nextern int execute_all_close_hooks (gl_close_fn primary, int fd);\n\n/* This type of function applies a control request to FD, applying special\n   knowledge for the FD types it knows about, and calls\n   execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG)\n   for the other FD types.\n   In CLOS speak, REMAINING_LIST is the remaining list of \"around\" methods,\n   and PRIMARY is the \"primary\" method for ioctl().  */\ntypedef int (*ioctl_hook_fn) (const struct fd_hook *remaining_list,\n                              gl_ioctl_fn primary,\n                              int fd, int request, void *arg);\n\n/* Execute the ioctl hooks in REMAINING_LIST, with PRIMARY as \"primary\" method.\n   Return 0 or -1, like ioctl() would do.  */\nextern int execute_ioctl_hooks (const struct fd_hook *remaining_list,\n                                gl_ioctl_fn primary,\n                                int fd, int request, void *arg);\n\n/* Execute all ioctl hooks, with PRIMARY as \"primary\" method.\n   Return 0 or -1, like ioctl() would do.  */\nextern int execute_all_ioctl_hooks (gl_ioctl_fn primary,\n                                    int fd, int request, void *arg);\n\n/* Add a function pair to the list of file descriptor hooks.\n   CLOSE_HOOK and IOCTL_HOOK may be NULL, indicating no change.\n   The LINK variable points to a piece of memory which is guaranteed to be\n   accessible until the corresponding call to unregister_fd_hook.  */\nextern void register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook,\n                              struct fd_hook *link);\n\n/* Removes a hook from the list of file descriptor hooks.  */\nextern void unregister_fd_hook (struct fd_hook *link);\n\n\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* FD_HOOK_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/getdelim.c",
    "content": "/* getdelim.c --- Implementation of replacement getdelim function.\n   Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2021 Free Software\n   Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Ported from glibc by Simon Josefsson. */\n\n/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc\n   optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below.  */\n#define _GL_ARG_NONNULL(params)\n\n#include <config.h>\n\n#include <stdio.h>\n\n#include <limits.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <errno.h>\n\n#ifndef SSIZE_MAX\n# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))\n#endif\n\n#if USE_UNLOCKED_IO\n# include \"unlocked-io.h\"\n# define getc_maybe_unlocked(fp)        getc(fp)\n#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED\n# undef flockfile\n# undef funlockfile\n# define flockfile(x) ((void) 0)\n# define funlockfile(x) ((void) 0)\n# define getc_maybe_unlocked(fp)        getc(fp)\n#else\n# define getc_maybe_unlocked(fp)        getc_unlocked(fp)\n#endif\n\nstatic void\nalloc_failed (void)\n{\n#if defined _WIN32 && ! defined __CYGWIN__\n  /* Avoid errno problem without using the realloc module; see:\n     https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html  */\n  errno = ENOMEM;\n#endif\n}\n\n/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and\n   NUL-terminate it).  *LINEPTR is a pointer returned from malloc (or\n   NULL), pointing to *N characters of space.  It is realloc'ed as\n   necessary.  Returns the number of characters read (not including\n   the null terminator), or -1 on error or EOF.  */\n\nssize_t\ngetdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)\n{\n  ssize_t result;\n  size_t cur_len = 0;\n\n  if (lineptr == NULL || n == NULL || fp == NULL)\n    {\n      errno = EINVAL;\n      return -1;\n    }\n\n  flockfile (fp);\n\n  if (*lineptr == NULL || *n == 0)\n    {\n      char *new_lineptr;\n      *n = 120;\n      new_lineptr = (char *) realloc (*lineptr, *n);\n      if (new_lineptr == NULL)\n        {\n          alloc_failed ();\n          result = -1;\n          goto unlock_return;\n        }\n      *lineptr = new_lineptr;\n    }\n\n  for (;;)\n    {\n      int i;\n\n      i = getc_maybe_unlocked (fp);\n      if (i == EOF)\n        {\n          result = -1;\n          break;\n        }\n\n      /* Make enough space for len+1 (for final NUL) bytes.  */\n      if (cur_len + 1 >= *n)\n        {\n          size_t needed_max =\n            SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;\n          size_t needed = 2 * *n + 1;   /* Be generous. */\n          char *new_lineptr;\n\n          if (needed_max < needed)\n            needed = needed_max;\n          if (cur_len + 1 >= needed)\n            {\n              result = -1;\n              errno = EOVERFLOW;\n              goto unlock_return;\n            }\n\n          new_lineptr = (char *) realloc (*lineptr, needed);\n          if (new_lineptr == NULL)\n            {\n              alloc_failed ();\n              result = -1;\n              goto unlock_return;\n            }\n\n          *lineptr = new_lineptr;\n          *n = needed;\n        }\n\n      (*lineptr)[cur_len] = i;\n      cur_len++;\n\n      if (i == delimiter)\n        break;\n    }\n  (*lineptr)[cur_len] = '\\0';\n  result = cur_len ? cur_len : result;\n\n unlock_return:\n  funlockfile (fp); /* doesn't set errno */\n\n  return result;\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/gethostname.c",
    "content": "/* gethostname emulation for SysV and POSIX.1.\n\n   Copyright (C) 1992, 2003, 2006, 2008-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* David MacKenzie <djm@gnu.ai.mit.edu>\n   Windows port by Simon Josefsson <simon@josefsson.org> */\n\n#include <config.h>\n\n#if !(defined _WIN32 && !defined __CYGWIN__)\n/* Unix API.  */\n\n/* Specification.  */\n#include <unistd.h>\n\n#ifdef HAVE_UNAME\n# include <sys/utsname.h>\n#endif\n\n#include <string.h>\n\n/* Put up to LEN chars of the host name into NAME.\n   Null terminate it if the name is shorter than LEN.\n   Return 0 if ok, -1 if error.  */\n\n#include <stddef.h>\n\nint\ngethostname (char *name, size_t len)\n{\n#ifdef HAVE_UNAME\n  struct utsname uts;\n\n  if (uname (&uts) == -1)\n    return -1;\n  if (len > sizeof (uts.nodename))\n    {\n      /* More space than we need is available.  */\n      name[sizeof (uts.nodename)] = '\\0';\n      len = sizeof (uts.nodename);\n    }\n  strncpy (name, uts.nodename, len);\n#else\n  strcpy (name, \"\");            /* Hardcode your system name if you want.  */\n#endif\n  return 0;\n}\n\n#else\n/* Native Windows API.  Which primitive to choose?\n   - gethostname() requires linking with -lws2_32.\n   - GetComputerName() does not return the right kind of hostname.\n   - GetComputerNameEx(ComputerNameDnsHostname,...) returns the right hostname,\n     but it is hard to use portably:\n       - It requires defining _WIN32_WINNT to at least 0x0500.\n       - With mingw, it also requires\n         \"#define GetComputerNameEx GetComputerNameExA\".\n       - With older versions of mingw, none of the declarations are present at\n         all, not even of the enum value ComputerNameDnsHostname.\n   So we use gethostname().  Linking with -lws2_32 is the least evil.  */\n\n#define WIN32_LEAN_AND_MEAN\n/* Get winsock2.h. */\n#include <unistd.h>\n\n/* Get INT_MAX.  */\n#include <limits.h>\n\n/* Get set_winsock_errno. */\n#include \"w32sock.h\"\n\n#include \"sockets.h\"\n\n#undef gethostname\n\nint\nrpl_gethostname (char *name, size_t len)\n{\n  int r;\n\n  if (len > INT_MAX)\n    len = INT_MAX;\n  gl_sockets_startup (SOCKETS_1_1);\n  r = gethostname (name, (int) len);\n  if (r < 0)\n    set_winsock_errno ();\n\n  return r;\n}\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/getline.c",
    "content": "/* getline.c --- Implementation of replacement getline function.\n   Copyright (C) 2005-2007, 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Simon Josefsson. */\n\n#include <config.h>\n\n#include <stdio.h>\n\nssize_t\ngetline (char **lineptr, size_t *n, FILE *stream)\n{\n  return getdelim (lineptr, n, '\\n', stream);\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/gettimeofday.c",
    "content": "/* Provide gettimeofday for systems that don't have it or for which it's broken.\n\n   Copyright (C) 2001-2003, 2005-2007, 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* written by Jim Meyering */\n\n#include <config.h>\n\n/* Specification.  */\n#include <sys/time.h>\n\n#include <time.h>\n\n#if defined _WIN32 && ! defined __CYGWIN__\n# define WINDOWS_NATIVE\n# include <windows.h>\n#endif\n\n#ifdef WINDOWS_NATIVE\n\n/* Don't assume that UNICODE is not defined.  */\n# undef LoadLibrary\n# define LoadLibrary LoadLibraryA\n\n# if !(_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n\n/* Avoid warnings from gcc -Wcast-function-type.  */\n#  define GetProcAddress \\\n    (void *) GetProcAddress\n\n/* GetSystemTimePreciseAsFileTime was introduced only in Windows 8.  */\ntypedef void (WINAPI * GetSystemTimePreciseAsFileTimeFuncType) (FILETIME *lpTime);\nstatic GetSystemTimePreciseAsFileTimeFuncType GetSystemTimePreciseAsFileTimeFunc = NULL;\nstatic BOOL initialized = FALSE;\n\nstatic void\ninitialize (void)\n{\n  HMODULE kernel32 = LoadLibrary (\"kernel32.dll\");\n  if (kernel32 != NULL)\n    {\n      GetSystemTimePreciseAsFileTimeFunc =\n        (GetSystemTimePreciseAsFileTimeFuncType) GetProcAddress (kernel32, \"GetSystemTimePreciseAsFileTime\");\n    }\n  initialized = TRUE;\n}\n\n# else\n\n#  define GetSystemTimePreciseAsFileTimeFunc GetSystemTimePreciseAsFileTime\n\n# endif\n\n#endif\n\n/* This is a wrapper for gettimeofday.  It is used only on systems\n   that lack this function, or whose implementation of this function\n   causes problems.\n   Work around the bug in some systems whereby gettimeofday clobbers\n   the static buffer that localtime uses for its return value.  The\n   gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has\n   this problem.  */\n\nint\ngettimeofday (struct timeval *restrict tv, void *restrict tz)\n{\n#undef gettimeofday\n#ifdef WINDOWS_NATIVE\n\n  /* On native Windows, there are two ways to get the current time:\n     GetSystemTimeAsFileTime\n     <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>\n     or\n     GetSystemTimePreciseAsFileTime\n     <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>.\n     GetSystemTimeAsFileTime produces values that jump by increments of\n     15.627 milliseconds (!) on average.\n     Whereas GetSystemTimePreciseAsFileTime values usually jump by 1 or 2\n     microseconds.\n     More discussion on this topic:\n     <http://www.windowstimestamp.com/description>.  */\n  FILETIME current_time;\n\n# if !(_WIN32_WINNT >= _WIN32_WINNT_WIN8)\n  if (!initialized)\n    initialize ();\n# endif\n  if (GetSystemTimePreciseAsFileTimeFunc != NULL)\n    GetSystemTimePreciseAsFileTimeFunc (&current_time);\n  else\n    GetSystemTimeAsFileTime (&current_time);\n\n  /* Convert from FILETIME to 'struct timeval'.  */\n  /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */\n  ULONGLONG since_1601 =\n    ((ULONGLONG) current_time.dwHighDateTime << 32)\n    | (ULONGLONG) current_time.dwLowDateTime;\n  /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 leap\n     years, in total 134774 days.  */\n  ULONGLONG since_1970 =\n    since_1601 - (ULONGLONG) 134774 * (ULONGLONG) 86400 * (ULONGLONG) 10000000;\n  ULONGLONG microseconds_since_1970 = since_1970 / (ULONGLONG) 10;\n  tv->tv_sec = microseconds_since_1970 / (ULONGLONG) 1000000;\n  tv->tv_usec = microseconds_since_1970 % (ULONGLONG) 1000000;\n\n  return 0;\n\n#else\n\n# if HAVE_GETTIMEOFDAY\n\n#  if defined timeval /* 'struct timeval' overridden by gnulib?  */\n#   undef timeval\n  struct timeval otv;\n  int result = gettimeofday (&otv, (struct timezone *) tz);\n  if (result == 0)\n    {\n      tv->tv_sec = otv.tv_sec;\n      tv->tv_usec = otv.tv_usec;\n    }\n#  else\n  int result = gettimeofday (tv, (struct timezone *) tz);\n#  endif\n\n  return result;\n\n# else\n\n#  if !defined OK_TO_USE_1S_CLOCK\n#   error \"Only 1-second nominal clock resolution found.  Is that intended?\" \\\n          \"If so, compile with the -DOK_TO_USE_1S_CLOCK option.\"\n#  endif\n  tv->tv_sec = time (NULL);\n  tv->tv_usec = 0;\n\n  return 0;\n\n# endif\n#endif\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/libc-config.h",
    "content": "/* System definitions for code taken from the GNU C Library\n\n   Copyright 2017-2021 Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with this program; if not, see\n   <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paul Eggert.  */\n\n/* This is intended to be a good-enough substitute for glibc system\n   macros like those defined in <sys/cdefs.h>, so that Gnulib code\n   shared with glibc can do this as the first #include:\n\n     #ifndef _LIBC\n     # include <libc-config.h>\n     #endif\n\n   When compiled as part of glibc this is a no-op; when compiled as\n   part of Gnulib this includes Gnulib's <config.h> and defines macros\n   that glibc library code would normally assume.\n\n   Note: This header file MUST NOT be included by public header files\n   of Gnulib.  */\n\n#include <config.h>\n\n/* On glibc this includes <features.h> and <sys/cdefs.h> and #defines\n   _FEATURES_H, __WORDSIZE, and __set_errno.  On FreeBSD 11 and\n   DragonFlyBSD 5.9 it includes <sys/cdefs.h> which defines __nonnull.\n   Elsewhere it is harmless.  */\n#include <errno.h>\n\n/* From glibc <errno.h>.  */\n#ifndef __set_errno\n# define __set_errno(val) (errno = (val))\n#endif\n\n/* From glibc <features.h>.  */\n\n#ifndef __GNUC_PREREQ\n# if defined __GNUC__ && defined __GNUC_MINOR__\n#  define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__))\n# else\n#  define __GNUC_PREREQ(maj, min) 0\n# endif\n#endif\n\n#ifndef __glibc_clang_prereq\n# if defined __clang_major__ && defined __clang_minor__\n#  ifdef __apple_build_version__\n/* Apple for some reason renumbers __clang_major__ and __clang_minor__.\n   Gnulib code uses only __glibc_clang_prereq (3, 5); map it to\n   6000000 <= __apple_build_version__.  Support for other calls to\n   __glibc_clang_prereq can be added here as needed.  */\n#   define __glibc_clang_prereq(maj, min) \\\n      ((maj) == 3 && (min) == 5 ? 6000000 <= __apple_build_version__ : 0)\n#  else\n#   define __glibc_clang_prereq(maj, min) \\\n      ((maj) < __clang_major__ + ((min) <= __clang_minor__))\n#  endif\n# else\n#  define __glibc_clang_prereq(maj, min) 0\n# endif\n#endif\n\n#ifndef __attribute_nonnull__\n/* <sys/cdefs.h> either does not exist, or is too old for Gnulib.\n   Prepare to include <cdefs.h>, which is Gnulib's version of a\n   more-recent glibc <sys/cdefs.h>.  */\n\n/* Define _FEATURES_H so that <cdefs.h> does not include <features.h>.  */\n# ifndef _FEATURES_H\n#  define _FEATURES_H 1\n# endif\n/* Define __GNULIB_CDEFS so that <cdefs.h> does not attempt to include\n   nonexistent files.  */\n# define __GNULIB_CDEFS\n/* Undef the macros unconditionally defined by our copy of glibc\n   <sys/cdefs.h>, so that they do not clash with any system-defined\n   versions.  */\n# undef _SYS_CDEFS_H\n# undef __ASMNAME\n# undef __ASMNAME2\n# undef __BEGIN_DECLS\n# undef __CONCAT\n# undef __END_DECLS\n# undef __HAVE_GENERIC_SELECTION\n# undef __LDBL_COMPAT\n# undef __LDBL_REDIR\n# undef __LDBL_REDIR1\n# undef __LDBL_REDIR1_DECL\n# undef __LDBL_REDIR1_NTH\n# undef __LDBL_REDIR2_DECL\n# undef __LDBL_REDIR_DECL\n# undef __LDBL_REDIR_NTH\n# undef __LEAF\n# undef __LEAF_ATTR\n# undef __NTH\n# undef __NTHNL\n# undef __REDIRECT\n# undef __REDIRECT_LDBL\n# undef __REDIRECT_NTH\n# undef __REDIRECT_NTHNL\n# undef __REDIRECT_NTH_LDBL\n# undef __STRING\n# undef __THROW\n# undef __THROWNL\n# undef __attr_access\n# undef __attr_access_none\n# undef __attr_dealloc\n# undef __attr_dealloc_free\n# undef __attribute__\n# undef __attribute_alloc_size__\n# undef __attribute_artificial__\n# undef __attribute_const__\n# undef __attribute_deprecated__\n# undef __attribute_deprecated_msg__\n# undef __attribute_format_arg__\n# undef __attribute_format_strfmon__\n# undef __attribute_malloc__\n# undef __attribute_noinline__\n# undef __attribute_nonstring__\n# undef __attribute_pure__\n# undef __attribute_returns_twice__\n# undef __attribute_used__\n# undef __attribute_warn_unused_result__\n# undef __bos\n# undef __bos0\n# undef __errordecl\n# undef __extension__\n# undef __extern_always_inline\n# undef __extern_inline\n# undef __flexarr\n# undef __fortify_function\n# undef __glibc_c99_flexarr_available\n# undef __glibc_has_attribute\n# undef __glibc_has_builtin\n# undef __glibc_has_extension\n# undef __glibc_macro_warning\n# undef __glibc_macro_warning1\n# undef __glibc_objsize\n# undef __glibc_objsize0\n# undef __glibc_unlikely\n# undef __inline\n# undef __ptr_t\n# undef __restrict\n# undef __restrict_arr\n# undef __va_arg_pack\n# undef __va_arg_pack_len\n# undef __warnattr\n\n/* Include our copy of glibc <sys/cdefs.h>.  */\n# include <cdefs.h>\n\n/* <cdefs.h> __inline is too pessimistic for non-GCC.  */\n# undef __inline\n# ifndef HAVE___INLINE\n#  if 199901 <= __STDC_VERSION__ || defined inline\n#   define __inline inline\n#  else\n#   define __inline\n#  endif\n# endif\n\n#endif /* defined __glibc_likely */\n\n\n/* A substitute for glibc <libc-symbols.h>, good enough for Gnulib.  */\n#define attribute_hidden\n#define libc_hidden_proto(name)\n#define libc_hidden_def(name)\n#define libc_hidden_weak(name)\n#define libc_hidden_ver(local, name)\n#define strong_alias(name, aliasname)\n#define weak_alias(name, aliasname)\n\n/* A substitute for glibc <shlib-compat.h>, good enough for Gnulib.  */\n#define SHLIB_COMPAT(lib, introduced, obsoleted) 0\n#define compat_symbol(lib, local, symbol, version) extern int dummy\n#define versioned_symbol(lib, local, symbol, version) extern int dummy\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/limits.in.h",
    "content": "/* A GNU-like <limits.h>.\n\n   Copyright 2016-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined _GL_ALREADY_INCLUDING_LIMITS_H\n/* Special invocation convention:\n   On Haiku/x86_64, we have a sequence of nested includes\n   <limits.h> -> <syslimits.h> -> <limits.h>.\n   In this situation, LONG_MAX and INT_MAX are not yet defined,\n   therefore we should not attempt to define LONG_BIT.  */\n\n#@INCLUDE_NEXT@ @NEXT_LIMITS_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_LIMITS_H\n\n# define _GL_ALREADY_INCLUDING_LIMITS_H\n\n/* The include_next requires a split double-inclusion guard.  */\n# @INCLUDE_NEXT@ @NEXT_LIMITS_H@\n\n# undef _GL_ALREADY_INCLUDING_LIMITS_H\n\n#ifndef _@GUARD_PREFIX@_LIMITS_H\n#define _@GUARD_PREFIX@_LIMITS_H\n\n#ifndef LLONG_MIN\n# if defined LONG_LONG_MIN /* HP-UX 11.31 */\n#  define LLONG_MIN LONG_LONG_MIN\n# elif defined LONGLONG_MIN /* IRIX 6.5 */\n#  define LLONG_MIN LONGLONG_MIN\n# elif defined __GNUC__\n#  define LLONG_MIN (- __LONG_LONG_MAX__ - 1LL)\n# endif\n#endif\n#ifndef LLONG_MAX\n# if defined LONG_LONG_MAX /* HP-UX 11.31 */\n#  define LLONG_MAX LONG_LONG_MAX\n# elif defined LONGLONG_MAX /* IRIX 6.5 */\n#  define LLONG_MAX LONGLONG_MAX\n# elif defined __GNUC__\n#  define LLONG_MAX __LONG_LONG_MAX__\n# endif\n#endif\n#ifndef ULLONG_MAX\n# if defined ULONG_LONG_MAX /* HP-UX 11.31 */\n#  define ULLONG_MAX ULONG_LONG_MAX\n# elif defined ULONGLONG_MAX /* IRIX 6.5 */\n#  define ULLONG_MAX ULONGLONG_MAX\n# elif defined __GNUC__\n#  define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL)\n# endif\n#endif\n\n/* The number of usable bits in an unsigned or signed integer type\n   with minimum value MIN and maximum value MAX, as an int expression\n   suitable in #if.  Cover all known practical hosts.  This\n   implementation exploits the fact that MAX is 1 less than a power of\n   2, and merely counts the number of 1 bits in MAX; \"COBn\" means\n   \"count the number of 1 bits in the low-order n bits\").  */\n#define _GL_INTEGER_WIDTH(min, max) (((min) < 0) + _GL_COB128 (max))\n#define _GL_COB128(n) (_GL_COB64 ((n) >> 31 >> 31 >> 2) + _GL_COB64 (n))\n#define _GL_COB64(n) (_GL_COB32 ((n) >> 31 >> 1) + _GL_COB32 (n))\n#define _GL_COB32(n) (_GL_COB16 ((n) >> 16) + _GL_COB16 (n))\n#define _GL_COB16(n) (_GL_COB8 ((n) >> 8) + _GL_COB8 (n))\n#define _GL_COB8(n) (_GL_COB4 ((n) >> 4) + _GL_COB4 (n))\n#define _GL_COB4(n) (!!((n) & 8) + !!((n) & 4) + !!((n) & 2) + !!((n) & 1))\n\n#ifndef WORD_BIT\n/* Assume 'int' is 32 bits wide.  */\n# define WORD_BIT 32\n#endif\n#ifndef LONG_BIT\n/* Assume 'long' is 32 or 64 bits wide.  */\n# if LONG_MAX == INT_MAX\n#  define LONG_BIT 32\n# else\n#  define LONG_BIT 64\n# endif\n#endif\n\n/* Macros specified by C2x and by ISO/IEC TS 18661-1:2014.  */\n\n#if (! defined ULLONG_WIDTH                                             \\\n     && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__ \\\n         || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__)))\n# define CHAR_WIDTH _GL_INTEGER_WIDTH (CHAR_MIN, CHAR_MAX)\n# define SCHAR_WIDTH _GL_INTEGER_WIDTH (SCHAR_MIN, SCHAR_MAX)\n# define UCHAR_WIDTH _GL_INTEGER_WIDTH (0, UCHAR_MAX)\n# define SHRT_WIDTH _GL_INTEGER_WIDTH (SHRT_MIN, SHRT_MAX)\n# define USHRT_WIDTH _GL_INTEGER_WIDTH (0, USHRT_MAX)\n# define INT_WIDTH _GL_INTEGER_WIDTH (INT_MIN, INT_MAX)\n# define UINT_WIDTH _GL_INTEGER_WIDTH (0, UINT_MAX)\n# define LONG_WIDTH _GL_INTEGER_WIDTH (LONG_MIN, LONG_MAX)\n# define ULONG_WIDTH _GL_INTEGER_WIDTH (0, ULONG_MAX)\n# define LLONG_WIDTH _GL_INTEGER_WIDTH (LLONG_MIN, LLONG_MAX)\n# define ULLONG_WIDTH _GL_INTEGER_WIDTH (0, ULLONG_MAX)\n#endif\n\n/* Macros specified by C2x.  */\n\n#if (! defined BOOL_WIDTH \\\n     && (defined _GNU_SOURCE \\\n         || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__)))\n# define BOOL_MAX 1\n# define BOOL_WIDTH 1\n#endif\n\n#endif /* _@GUARD_PREFIX@_LIMITS_H */\n#endif /* _@GUARD_PREFIX@_LIMITS_H */\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/msvc-inval.c",
    "content": "/* Invalid parameter handler for MSVC runtime libraries.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n/* Specification.  */\n#include \"msvc-inval.h\"\n\n#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \\\n    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)\n\n/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler\n   declaration.  */\n# include <stdlib.h>\n\n# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING\n\nstatic void __cdecl\ngl_msvc_invalid_parameter_handler (const wchar_t *expression,\n                                   const wchar_t *function,\n                                   const wchar_t *file,\n                                   unsigned int line,\n                                   uintptr_t dummy)\n{\n}\n\n# else\n\n/* Get declarations of the native Windows API functions.  */\n#  define WIN32_LEAN_AND_MEAN\n#  include <windows.h>\n\n#  if defined _MSC_VER\n\nstatic void __cdecl\ngl_msvc_invalid_parameter_handler (const wchar_t *expression,\n                                   const wchar_t *function,\n                                   const wchar_t *file,\n                                   unsigned int line,\n                                   uintptr_t dummy)\n{\n  RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);\n}\n\n#  else\n\n/* An index to thread-local storage.  */\nstatic DWORD tls_index;\nstatic int tls_initialized /* = 0 */;\n\n/* Used as a fallback only.  */\nstatic struct gl_msvc_inval_per_thread not_per_thread;\n\nstruct gl_msvc_inval_per_thread *\ngl_msvc_inval_current (void)\n{\n  if (!tls_initialized)\n    {\n      tls_index = TlsAlloc ();\n      tls_initialized = 1;\n    }\n  if (tls_index == TLS_OUT_OF_INDEXES)\n    /* TlsAlloc had failed.  */\n    return &not_per_thread;\n  else\n    {\n      struct gl_msvc_inval_per_thread *pointer =\n        (struct gl_msvc_inval_per_thread *) TlsGetValue (tls_index);\n      if (pointer == NULL)\n        {\n          /* First call.  Allocate a new 'struct gl_msvc_inval_per_thread'.  */\n          pointer =\n            (struct gl_msvc_inval_per_thread *)\n            malloc (sizeof (struct gl_msvc_inval_per_thread));\n          if (pointer == NULL)\n            /* Could not allocate memory.  Use the global storage.  */\n            pointer = &not_per_thread;\n          TlsSetValue (tls_index, pointer);\n        }\n      return pointer;\n    }\n}\n\nstatic void __cdecl\ngl_msvc_invalid_parameter_handler (const wchar_t *expression,\n                                   const wchar_t *function,\n                                   const wchar_t *file,\n                                   unsigned int line,\n                                   uintptr_t dummy)\n{\n  struct gl_msvc_inval_per_thread *current = gl_msvc_inval_current ();\n  if (current->restart_valid)\n    longjmp (current->restart, 1);\n  else\n    /* An invalid parameter notification from outside the gnulib code.\n       Give the caller a chance to intervene.  */\n    RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);\n}\n\n#  endif\n\n# endif\n\nstatic int gl_msvc_inval_initialized /* = 0 */;\n\nvoid\ngl_msvc_inval_ensure_handler (void)\n{\n  if (gl_msvc_inval_initialized == 0)\n    {\n      _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);\n      gl_msvc_inval_initialized = 1;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/msvc-inval.h",
    "content": "/* Invalid parameter handler for MSVC runtime libraries.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _MSVC_INVAL_H\n#define _MSVC_INVAL_H\n\n/* With MSVC runtime libraries with the \"invalid parameter handler\" concept,\n   functions like fprintf(), dup2(), or close() crash when the caller passes\n   an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)\n   instead.\n   This file defines macros that turn such an invalid parameter notification\n   into a non-local exit.  An error code can then be produced at the target\n   of this exit.  You can thus write code like\n\n     TRY_MSVC_INVAL\n       {\n         <Code that can trigger an invalid parameter notification\n          but does not do 'return', 'break', 'continue', nor 'goto'.>\n       }\n     CATCH_MSVC_INVAL\n       {\n         <Code that handles an invalid parameter notification\n          but does not do 'return', 'break', 'continue', nor 'goto'.>\n       }\n     DONE_MSVC_INVAL;\n\n   This entire block expands to a single statement.\n\n   The handling of invalid parameters can be done in three ways:\n\n     * The default way, which is reasonable for programs (not libraries):\n       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])\n\n     * The way for libraries that make \"hairy\" calls (like close(-1), or\n       fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):\n       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])\n\n     * The way for libraries that make no \"hairy\" calls:\n       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])\n */\n\n#define DEFAULT_HANDLING       0\n#define HAIRY_LIBRARY_HANDLING 1\n#define SANE_LIBRARY_HANDLING  2\n\n#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \\\n    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)\n/* A native Windows platform with the \"invalid parameter handler\" concept,\n   and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */\n\n# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING\n/* Default handling.  */\n\n#  ifdef __cplusplus\nextern \"C\" {\n#  endif\n\n/* Ensure that the invalid parameter handler in installed that just returns.\n   Because we assume no other part of the program installs a different\n   invalid parameter handler, this solution is multithread-safe.  */\nextern void gl_msvc_inval_ensure_handler (void);\n\n#  ifdef __cplusplus\n}\n#  endif\n\n#  define TRY_MSVC_INVAL \\\n     do                                                                        \\\n       {                                                                       \\\n         gl_msvc_inval_ensure_handler ();                                      \\\n         if (1)\n#  define CATCH_MSVC_INVAL \\\n         else\n#  define DONE_MSVC_INVAL \\\n       }                                                                       \\\n     while (0)\n\n# else\n/* Handling for hairy libraries.  */\n\n#  include <excpt.h>\n\n/* Gnulib can define its own status codes, as described in the page\n   \"Raising Software Exceptions\" on microsoft.com\n   <https://docs.microsoft.com/en-us/cpp/cpp/raising-software-exceptions>.\n   Our status codes are composed of\n     - 0xE0000000, mandatory for all user-defined status codes,\n     - 0x474E550, a API identifier (\"GNU\"),\n     - 0, 1, 2, ..., used to distinguish different status codes from the\n       same API.  */\n#  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)\n\n#  if defined _MSC_VER\n/* A compiler that supports __try/__except, as described in the page\n   \"try-except statement\" on microsoft.com\n   <https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement>.\n   With __try/__except, we can use the multithread-safe exception handling.  */\n\n#   ifdef __cplusplus\nextern \"C\" {\n#   endif\n\n/* Ensure that the invalid parameter handler in installed that raises a\n   software exception with code STATUS_GNULIB_INVALID_PARAMETER.\n   Because we assume no other part of the program installs a different\n   invalid parameter handler, this solution is multithread-safe.  */\nextern void gl_msvc_inval_ensure_handler (void);\n\n#   ifdef __cplusplus\n}\n#   endif\n\n#   define TRY_MSVC_INVAL \\\n      do                                                                       \\\n        {                                                                      \\\n          gl_msvc_inval_ensure_handler ();                                     \\\n          __try\n#   define CATCH_MSVC_INVAL \\\n          __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \\\n                    ? EXCEPTION_EXECUTE_HANDLER                                \\\n                    : EXCEPTION_CONTINUE_SEARCH)\n#   define DONE_MSVC_INVAL \\\n        }                                                                      \\\n      while (0)\n\n#  else\n/* Any compiler.\n   We can only use setjmp/longjmp.  */\n\n#   include <setjmp.h>\n\n#   ifdef __cplusplus\nextern \"C\" {\n#   endif\n\nstruct gl_msvc_inval_per_thread\n{\n  /* The restart that will resume execution at the code between\n     CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between\n     TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */\n  jmp_buf restart;\n\n  /* Tells whether the contents of restart is valid.  */\n  int restart_valid;\n};\n\n/* Ensure that the invalid parameter handler in installed that passes\n   control to the gl_msvc_inval_restart if it is valid, or raises a\n   software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.\n   Because we assume no other part of the program installs a different\n   invalid parameter handler, this solution is multithread-safe.  */\nextern void gl_msvc_inval_ensure_handler (void);\n\n/* Return a pointer to the per-thread data for the current thread.  */\nextern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);\n\n#   ifdef __cplusplus\n}\n#   endif\n\n#   define TRY_MSVC_INVAL \\\n      do                                                                       \\\n        {                                                                      \\\n          struct gl_msvc_inval_per_thread *msvc_inval_current;                 \\\n          gl_msvc_inval_ensure_handler ();                                     \\\n          msvc_inval_current = gl_msvc_inval_current ();                       \\\n          /* First, initialize gl_msvc_inval_restart.  */                      \\\n          if (setjmp (msvc_inval_current->restart) == 0)                       \\\n            {                                                                  \\\n              /* Then, mark it as valid.  */                                   \\\n              msvc_inval_current->restart_valid = 1;\n#   define CATCH_MSVC_INVAL \\\n              /* Execution completed.                                          \\\n                 Mark gl_msvc_inval_restart as invalid.  */                    \\\n              msvc_inval_current->restart_valid = 0;                           \\\n            }                                                                  \\\n          else                                                                 \\\n            {                                                                  \\\n              /* Execution triggered an invalid parameter notification.        \\\n                 Mark gl_msvc_inval_restart as invalid.  */                    \\\n              msvc_inval_current->restart_valid = 0;\n#   define DONE_MSVC_INVAL \\\n            }                                                                  \\\n        }                                                                      \\\n      while (0)\n\n#  endif\n\n# endif\n\n#else\n/* A platform that does not need to the invalid parameter handler,\n   or when SANE_LIBRARY_HANDLING is desired.  */\n\n/* The braces here avoid GCC warnings like\n   \"warning: suggest explicit braces to avoid ambiguous 'else'\".  */\n# define TRY_MSVC_INVAL \\\n    do                                                                         \\\n      {                                                                        \\\n        if (1)\n# define CATCH_MSVC_INVAL \\\n        else\n# define DONE_MSVC_INVAL \\\n      }                                                                        \\\n    while (0)\n\n#endif\n\n#endif /* _MSVC_INVAL_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/msvc-nothrow.c",
    "content": "/* Wrappers that don't throw invalid parameter notifications\n   with MSVC runtime libraries.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n/* Specification.  */\n#include \"msvc-nothrow.h\"\n\n/* Get declarations of the native Windows API functions.  */\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\n#if HAVE_MSVC_INVALID_PARAMETER_HANDLER\n# include \"msvc-inval.h\"\n#endif\n\n#undef _get_osfhandle\n\n#if HAVE_MSVC_INVALID_PARAMETER_HANDLER\nintptr_t\n_gl_nothrow_get_osfhandle (int fd)\n{\n  intptr_t result;\n\n  TRY_MSVC_INVAL\n    {\n      result = _get_osfhandle (fd);\n    }\n  CATCH_MSVC_INVAL\n    {\n      result = (intptr_t) INVALID_HANDLE_VALUE;\n    }\n  DONE_MSVC_INVAL;\n\n  return result;\n}\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/msvc-nothrow.h",
    "content": "/* Wrappers that don't throw invalid parameter notifications\n   with MSVC runtime libraries.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _MSVC_NOTHROW_H\n#define _MSVC_NOTHROW_H\n\n/* With MSVC runtime libraries with the \"invalid parameter handler\" concept,\n   functions like fprintf(), dup2(), or close() crash when the caller passes\n   an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)\n   instead.\n   This file defines wrappers that turn such an invalid parameter notification\n   into an error code.  */\n\n#if defined _WIN32 && ! defined __CYGWIN__\n\n/* Get original declaration of _get_osfhandle.  */\n# include <io.h>\n\n# if HAVE_MSVC_INVALID_PARAMETER_HANDLER\n\n/* Override _get_osfhandle.  */\nextern intptr_t _gl_nothrow_get_osfhandle (int fd);\n#  define _get_osfhandle _gl_nothrow_get_osfhandle\n\n# endif\n\n#endif\n\n#endif /* _MSVC_NOTHROW_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/random.c",
    "content": "/* Copyright (C) 1995-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 3 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/*\n * This is derived from the Berkeley source:\n *      @(#)random.c    5.5 (Berkeley) 7/6/88\n * It was reworked for the GNU C Library by Roland McGrath.\n * Rewritten to use reentrant functions by Ulrich Drepper, 1995.\n */\n\n/*\n   Copyright (C) 1983 Regents of the University of California.\n   All rights reserved.\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   1. Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n   2. Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n   4. Neither the name of the University nor the names of its contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS \"AS IS\" AND\n   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n   ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n   SUCH DAMAGE.*/\n\n#ifndef _LIBC\n# include <libc-config.h>\n# define __srandom srandom\n# define __initstate initstate\n# define __setstate setstate\n# define __random random\n# define __srandom_r srandom_r\n# define __initstate_r initstate_r\n# define __setstate_r setstate_r\n# define __random_r random_r\n#endif\n\n/* Specification.  */\n#include <stdlib.h>\n\n#ifdef _LIBC\n# include <libc-lock.h>\n#else\n/* Allow memory races; that's random enough.  */\n# define __libc_lock_define_initialized(class, name)\n# define __libc_lock_lock(name) ((void) 0)\n# define __libc_lock_unlock(name) ((void) 0)\n#endif\n\n/* An improved random number generation package.  In addition to the standard\n   rand()/srand() like interface, this package also has a special state info\n   interface.  The initstate() routine is called with a seed, an array of\n   bytes, and a count of how many bytes are being passed in; this array is\n   then initialized to contain information for random number generation with\n   that much state information.  Good sizes for the amount of state\n   information are 32, 64, 128, and 256 bytes.  The state can be switched by\n   calling the setstate() function with the same array as was initialized\n   with initstate().  By default, the package runs with 128 bytes of state\n   information and generates far better random numbers than a linear\n   congruential generator.  If the amount of state information is less than\n   32 bytes, a simple linear congruential R.N.G. is used.  Internally, the\n   state information is treated as an array of longs; the zeroth element of\n   the array is the type of R.N.G. being used (small integer); the remainder\n   of the array is the state information for the R.N.G.  Thus, 32 bytes of\n   state information will give 7 longs worth of state information, which will\n   allow a degree seven polynomial.  (Note: The zeroth word of state\n   information also has some other information stored in it; see setstate\n   for details).  The random number generation technique is a linear feedback\n   shift register approach, employing trinomials (since there are fewer terms\n   to sum up that way).  In this approach, the least significant bit of all\n   the numbers in the state table will act as a linear feedback shift register,\n   and will have period 2^deg - 1 (where deg is the degree of the polynomial\n   being used, assuming that the polynomial is irreducible and primitive).\n   The higher order bits will have longer periods, since their values are\n   also influenced by pseudo-random carries out of the lower bits.  The\n   total period of the generator is approximately deg*(2**deg - 1); thus\n   doubling the amount of state information has a vast influence on the\n   period of the generator.  Note: The deg*(2**deg - 1) is an approximation\n   only good for large deg, when the period of the shift register is the\n   dominant factor.  With deg equal to seven, the period is actually much\n   longer than the 7*(2**7 - 1) predicted by this formula.  */\n\n\n\n/* For each of the currently supported random number generators, we have a\n   break value on the amount of state information (you need at least this many\n   bytes of state info to support this random number generator), a degree for\n   the polynomial (actually a trinomial) that the R.N.G. is based on, and\n   separation between the two lower order coefficients of the trinomial.  */\n\n/* Linear congruential.  */\n#define TYPE_0          0\n#define BREAK_0         8\n#define DEG_0           0\n#define SEP_0           0\n\n/* x**7 + x**3 + 1.  */\n#define TYPE_1          1\n#define BREAK_1         32\n#define DEG_1           7\n#define SEP_1           3\n\n/* x**15 + x + 1.  */\n#define TYPE_2          2\n#define BREAK_2         64\n#define DEG_2           15\n#define SEP_2           1\n\n/* x**31 + x**3 + 1.  */\n#define TYPE_3          3\n#define BREAK_3         128\n#define DEG_3           31\n#define SEP_3           3\n\n/* x**63 + x + 1.  */\n#define TYPE_4          4\n#define BREAK_4         256\n#define DEG_4           63\n#define SEP_4           1\n\n\n/* Array versions of the above information to make code run faster.\n   Relies on fact that TYPE_i == i.  */\n\n#define MAX_TYPES       5       /* Max number of types above.  */\n\n\n/* Initially, everything is set up as if from:\n        initstate(1, randtbl, 128);\n   Note that this initialization takes advantage of the fact that srandom\n   advances the front and rear pointers 10*rand_deg times, and hence the\n   rear pointer which starts at 0 will also end up at zero; thus the zeroth\n   element of the state information, which contains info about the current\n   position of the rear pointer is just\n        (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3.  */\n\nstatic int32_t randtbl[DEG_3 + 1] =\n  {\n    TYPE_3,\n\n    -1726662223, 379960547, 1735697613, 1040273694, 1313901226,\n    1627687941, -179304937, -2073333483, 1780058412, -1989503057,\n    -615974602, 344556628, 939512070, -1249116260, 1507946756,\n    -812545463, 154635395, 1388815473, -1926676823, 525320961,\n    -1009028674, 968117788, -123449607, 1284210865, 435012392,\n    -2017506339, -911064859, -370259173, 1132637927, 1398500161,\n    -205601318,\n  };\n\n\nstatic struct random_data unsafe_state =\n  {\n/* FPTR and RPTR are two pointers into the state info, a front and a rear\n   pointer.  These two pointers are always rand_sep places apart, as they\n   cycle through the state information.  (Yes, this does mean we could get\n   away with just one pointer, but the code for random is more efficient\n   this way).  The pointers are left positioned as they would be from the call:\n        initstate(1, randtbl, 128);\n   (The position of the rear pointer, rptr, is really 0 (as explained above\n   in the initialization of randtbl) because the state table pointer is set\n   to point to randtbl[1] (as explained below).)  */\n\n    .fptr = &randtbl[SEP_3 + 1],\n    .rptr = &randtbl[1],\n\n/* The following things are the pointer to the state information table,\n   the type of the current generator, the degree of the current polynomial\n   being used, and the separation between the two pointers.\n   Note that for efficiency of random, we remember the first location of\n   the state information, not the zeroth.  Hence it is valid to access\n   state[-1], which is used to store the type of the R.N.G.\n   Also, we remember the last location, since this is more efficient than\n   indexing every time to find the address of the last element to see if\n   the front and rear pointers have wrapped.  */\n\n    .state = &randtbl[1],\n\n    .rand_type = TYPE_3,\n    .rand_deg = DEG_3,\n    .rand_sep = SEP_3,\n\n    .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]\n};\n\f\n/* POSIX.1c requires that there is mutual exclusion for the 'rand' and\n   'srand' functions to prevent concurrent calls from modifying common\n   data.  */\n__libc_lock_define_initialized (static, lock)\n\f\n/* Initialize the random number generator based on the given seed.  If the\n   type is the trivial no-state-information type, just remember the seed.\n   Otherwise, initializes state[] based on the given \"seed\" via a linear\n   congruential generator.  Then, the pointers are set to known locations\n   that are exactly rand_sep places apart.  Lastly, it cycles the state\n   information a given number of times to get rid of any initial dependencies\n   introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]\n   for default usage relies on values produced by this routine.  */\nvoid\n__srandom (unsigned int x)\n{\n  __libc_lock_lock (lock);\n  (void) __srandom_r (x, &unsafe_state);\n  __libc_lock_unlock (lock);\n}\n\nweak_alias (__srandom, srandom)\nweak_alias (__srandom, srand)\n\f\n/* Initialize the state information in the given array of N bytes for\n   future random number generation.  Based on the number of bytes we\n   are given, and the break values for the different R.N.G.'s, we choose\n   the best (largest) one we can and set things up for it.  srandom is\n   then called to initialize the state information.  Note that on return\n   from srandom, we set state[-1] to be the type multiplexed with the current\n   value of the rear pointer; this is so successive calls to initstate won't\n   lose this information and will be able to restart with setstate.\n   Note: The first thing we do is save the current state, if any, just like\n   setstate so that it doesn't matter when initstate is called.\n   Returns a pointer to the old state.  */\nchar *\n__initstate (unsigned int seed, char *arg_state, size_t n)\n{\n  int32_t *ostate;\n  int ret;\n\n  __libc_lock_lock (lock);\n\n  ostate = &unsafe_state.state[-1];\n\n  ret = __initstate_r (seed, arg_state, n, &unsafe_state);\n\n  __libc_lock_unlock (lock);\n\n  return ret == -1 ? NULL : (char *) ostate;\n}\n\nweak_alias (__initstate, initstate)\n\f\n/* Restore the state from the given state array.\n   Note: It is important that we also remember the locations of the pointers\n   in the current state information, and restore the locations of the pointers\n   from the old state information.  This is done by multiplexing the pointer\n   location into the zeroth word of the state information. Note that due\n   to the order in which things are done, it is OK to call setstate with the\n   same state as the current state\n   Returns a pointer to the old state information.  */\nchar *\n__setstate (char *arg_state)\n{\n  int32_t *ostate;\n\n  __libc_lock_lock (lock);\n\n  ostate = &unsafe_state.state[-1];\n\n  if (__setstate_r (arg_state, &unsafe_state) < 0)\n    ostate = NULL;\n\n  __libc_lock_unlock (lock);\n\n  return (char *) ostate;\n}\n\nweak_alias (__setstate, setstate)\n\f\n/* If we are using the trivial TYPE_0 R.N.G., just do the old linear\n   congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the\n   same in all the other cases due to all the global variables that have been\n   set up.  The basic operation is to add the number at the rear pointer into\n   the one at the front pointer.  Then both pointers are advanced to the next\n   location cyclically in the table.  The value returned is the sum generated,\n   reduced to 31 bits by throwing away the \"least random\" low bit.\n   Note: The code takes advantage of the fact that both the front and\n   rear pointers can't wrap on the same call by not testing the rear\n   pointer if the front one has wrapped.  Returns a 31-bit random number.  */\n\nlong int\n__random (void)\n{\n  int32_t retval;\n\n  __libc_lock_lock (lock);\n\n  (void) __random_r (&unsafe_state, &retval);\n\n  __libc_lock_unlock (lock);\n\n  return retval;\n}\n\nweak_alias (__random, random)\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/random_r.c",
    "content": "/*\n   Copyright (C) 1995-2021 Free Software Foundation, Inc.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with the GNU C Library; if not, see\n   <https://www.gnu.org/licenses/>.  */\n\n/*\n   Copyright (C) 1983 Regents of the University of California.\n   All rights reserved.\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   1. Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n   2. Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n   4. Neither the name of the University nor the names of its contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS \"AS IS\" AND\n   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n   ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n   SUCH DAMAGE.*/\n\n/*\n * This is derived from the Berkeley source:\n *      @(#)random.c    5.5 (Berkeley) 7/6/88\n * It was reworked for the GNU C Library by Roland McGrath.\n * Rewritten to be reentrant by Ulrich Drepper, 1995\n */\n\n#ifndef _LIBC\n/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc\n   optimizes away the buf == NULL, arg_state == NULL, result == NULL tests\n   below.  */\n# define _GL_ARG_NONNULL(params)\n\n# include <libc-config.h>\n# define __srandom_r srandom_r\n# define __initstate_r initstate_r\n# define __setstate_r setstate_r\n# define __random_r random_r\n#endif\n\n/* Specification.  */\n#include <stdlib.h>\n\n#include <errno.h>\n#include <stddef.h>\n#include <string.h>\n\n\n/* An improved random number generation package.  In addition to the standard\n   rand()/srand() like interface, this package also has a special state info\n   interface.  The initstate() routine is called with a seed, an array of\n   bytes, and a count of how many bytes are being passed in; this array is\n   then initialized to contain information for random number generation with\n   that much state information.  Good sizes for the amount of state\n   information are 32, 64, 128, and 256 bytes.  The state can be switched by\n   calling the setstate() function with the same array as was initialized\n   with initstate().  By default, the package runs with 128 bytes of state\n   information and generates far better random numbers than a linear\n   congruential generator.  If the amount of state information is less than\n   32 bytes, a simple linear congruential R.N.G. is used.  Internally, the\n   state information is treated as an array of longs; the zeroth element of\n   the array is the type of R.N.G. being used (small integer); the remainder\n   of the array is the state information for the R.N.G.  Thus, 32 bytes of\n   state information will give 7 longs worth of state information, which will\n   allow a degree seven polynomial.  (Note: The zeroth word of state\n   information also has some other information stored in it; see setstate\n   for details).  The random number generation technique is a linear feedback\n   shift register approach, employing trinomials (since there are fewer terms\n   to sum up that way).  In this approach, the least significant bit of all\n   the numbers in the state table will act as a linear feedback shift register,\n   and will have period 2^deg - 1 (where deg is the degree of the polynomial\n   being used, assuming that the polynomial is irreducible and primitive).\n   The higher order bits will have longer periods, since their values are\n   also influenced by pseudo-random carries out of the lower bits.  The\n   total period of the generator is approximately deg*(2**deg - 1); thus\n   doubling the amount of state information has a vast influence on the\n   period of the generator.  Note: The deg*(2**deg - 1) is an approximation\n   only good for large deg, when the period of the shift register is the\n   dominant factor.  With deg equal to seven, the period is actually much\n   longer than the 7*(2**7 - 1) predicted by this formula.  */\n\n\n\n/* For each of the currently supported random number generators, we have a\n   break value on the amount of state information (you need at least this many\n   bytes of state info to support this random number generator), a degree for\n   the polynomial (actually a trinomial) that the R.N.G. is based on, and\n   separation between the two lower order coefficients of the trinomial.  */\n\n/* Linear congruential.  */\n#define TYPE_0          0\n#define BREAK_0         8\n#define DEG_0           0\n#define SEP_0           0\n\n/* x**7 + x**3 + 1.  */\n#define TYPE_1          1\n#define BREAK_1         32\n#define DEG_1           7\n#define SEP_1           3\n\n/* x**15 + x + 1.  */\n#define TYPE_2          2\n#define BREAK_2         64\n#define DEG_2           15\n#define SEP_2           1\n\n/* x**31 + x**3 + 1.  */\n#define TYPE_3          3\n#define BREAK_3         128\n#define DEG_3           31\n#define SEP_3           3\n\n/* x**63 + x + 1.  */\n#define TYPE_4          4\n#define BREAK_4         256\n#define DEG_4           63\n#define SEP_4           1\n\n\n/* Array versions of the above information to make code run faster.\n   Relies on fact that TYPE_i == i.  */\n\n#define MAX_TYPES       5       /* Max number of types above.  */\n\nstruct random_poly_info\n{\n  int seps[MAX_TYPES];\n  int degrees[MAX_TYPES];\n};\n\nstatic const struct random_poly_info random_poly_info =\n{\n  { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 },\n  { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }\n};\n\nstatic int32_t\nget_int32 (void *p)\n{\n  int32_t v;\n  memcpy (&v, p, sizeof v);\n  return v;\n}\n\nstatic void\nset_int32 (void *p, int32_t v)\n{\n  memcpy (p, &v, sizeof v);\n}\n\n\f\n/* Initialize the random number generator based on the given seed.  If the\n   type is the trivial no-state-information type, just remember the seed.\n   Otherwise, initializes state[] based on the given \"seed\" via a linear\n   congruential generator.  Then, the pointers are set to known locations\n   that are exactly rand_sep places apart.  Lastly, it cycles the state\n   information a given number of times to get rid of any initial dependencies\n   introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]\n   for default usage relies on values produced by this routine.  */\nint\n__srandom_r (unsigned int seed, struct random_data *buf)\n{\n  int type;\n  int32_t *state;\n  long int i;\n  int32_t word;\n  int32_t *dst;\n  int kc;\n\n  if (buf == NULL)\n    goto fail;\n  type = buf->rand_type;\n  if ((unsigned int) type >= MAX_TYPES)\n    goto fail;\n\n  state = buf->state;\n  /* We must make sure the seed is not 0.  Take arbitrarily 1 in this case.  */\n  if (seed == 0)\n    seed = 1;\n  set_int32 (&state[0], seed);\n  if (type == TYPE_0)\n    goto done;\n\n  dst = state;\n  word = seed;\n  kc = buf->rand_deg;\n  for (i = 1; i < kc; ++i)\n    {\n      /* This does:\n           state[i] = (16807 * state[i - 1]) % 2147483647;\n         but avoids overflowing 31 bits.  */\n      long int hi = word / 127773;\n      long int lo = word % 127773;\n      word = 16807 * lo - 2836 * hi;\n      if (word < 0)\n        word += 2147483647;\n      set_int32 (++dst, word);\n    }\n\n  buf->fptr = &state[buf->rand_sep];\n  buf->rptr = &state[0];\n  kc *= 10;\n  while (--kc >= 0)\n    {\n      int32_t discard;\n      (void) __random_r (buf, &discard);\n    }\n\n done:\n  return 0;\n\n fail:\n  return -1;\n}\n\nweak_alias (__srandom_r, srandom_r)\n\f\n/* Initialize the state information in the given array of N bytes for\n   future random number generation.  Based on the number of bytes we\n   are given, and the break values for the different R.N.G.'s, we choose\n   the best (largest) one we can and set things up for it.  srandom is\n   then called to initialize the state information.  Note that on return\n   from srandom, we set state[-1] to be the type multiplexed with the current\n   value of the rear pointer; this is so successive calls to initstate won't\n   lose this information and will be able to restart with setstate.\n   Note: The first thing we do is save the current state, if any, just like\n   setstate so that it doesn't matter when initstate is called.\n   Returns 0 on success, non-zero on failure.  */\nint\n__initstate_r (unsigned int seed, char *arg_state, size_t n,\n               struct random_data *buf)\n{\n  if (buf == NULL)\n    goto fail;\n\n  int32_t *old_state = buf->state;\n  if (old_state != NULL)\n    {\n      int old_type = buf->rand_type;\n      set_int32 (&old_state[-1],\n                 (old_type == TYPE_0\n                  ? TYPE_0\n                  : (MAX_TYPES * (buf->rptr - old_state)) + old_type));\n    }\n\n  int type;\n  if (n >= BREAK_3)\n    type = n < BREAK_4 ? TYPE_3 : TYPE_4;\n  else if (n < BREAK_1)\n    {\n      if (n < BREAK_0)\n        goto fail;\n\n      type = TYPE_0;\n    }\n  else\n    type = n < BREAK_2 ? TYPE_1 : TYPE_2;\n\n  int degree = random_poly_info.degrees[type];\n  int separation = random_poly_info.seps[type];\n\n  buf->rand_type = type;\n  buf->rand_sep = separation;\n  buf->rand_deg = degree;\n  int32_t *state = &((int32_t *) arg_state)[1]; /* First location.  */\n  /* Must set END_PTR before srandom.  */\n  buf->end_ptr = &state[degree];\n\n  buf->state = state;\n\n  __srandom_r (seed, buf);\n\n  set_int32 (&state[-1],\n             type == TYPE_0 ? TYPE_0 : (buf->rptr - state) * MAX_TYPES + type);\n\n  return 0;\n\n fail:\n  __set_errno (EINVAL);\n  return -1;\n}\n\nweak_alias (__initstate_r, initstate_r)\n\f\n/* Restore the state from the given state array.\n   Note: It is important that we also remember the locations of the pointers\n   in the current state information, and restore the locations of the pointers\n   from the old state information.  This is done by multiplexing the pointer\n   location into the zeroth word of the state information. Note that due\n   to the order in which things are done, it is OK to call setstate with the\n   same state as the current state\n   Returns 0 on success, non-zero on failure.  */\nint\n__setstate_r (char *arg_state, struct random_data *buf)\n{\n  int32_t *new_state = 1 + (int32_t *) arg_state;\n  int type;\n  int old_type;\n  int32_t *old_state;\n  int degree;\n  int separation;\n\n  if (arg_state == NULL || buf == NULL)\n    goto fail;\n\n  old_type = buf->rand_type;\n  old_state = buf->state;\n  set_int32 (&old_state[-1],\n             (old_type == TYPE_0\n              ? TYPE_0\n              : (MAX_TYPES * (buf->rptr - old_state)) + old_type));\n\n  type = get_int32 (&new_state[-1]) % MAX_TYPES;\n  if (type < TYPE_0 || type > TYPE_4)\n    goto fail;\n\n  buf->rand_deg = degree = random_poly_info.degrees[type];\n  buf->rand_sep = separation = random_poly_info.seps[type];\n  buf->rand_type = type;\n\n  if (type != TYPE_0)\n    {\n      int rear = get_int32 (&new_state[-1]) / MAX_TYPES;\n      buf->rptr = &new_state[rear];\n      buf->fptr = &new_state[(rear + separation) % degree];\n    }\n  buf->state = new_state;\n  /* Set end_ptr too.  */\n  buf->end_ptr = &new_state[degree];\n\n  return 0;\n\n fail:\n  __set_errno (EINVAL);\n  return -1;\n}\n\nweak_alias (__setstate_r, setstate_r)\n\f\n/* If we are using the trivial TYPE_0 R.N.G., just do the old linear\n   congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the\n   same in all the other cases due to all the global variables that have been\n   set up.  The basic operation is to add the number at the rear pointer into\n   the one at the front pointer.  Then both pointers are advanced to the next\n   location cyclically in the table.  The value returned is the sum generated,\n   reduced to 31 bits by throwing away the \"least random\" low bit.\n   Note: The code takes advantage of the fact that both the front and\n   rear pointers can't wrap on the same call by not testing the rear\n   pointer if the front one has wrapped.  Returns a 31-bit random number.  */\n\nint\n__random_r (struct random_data *buf, int32_t *result)\n{\n  int32_t *state;\n\n  if (buf == NULL || result == NULL)\n    goto fail;\n\n  state = buf->state;\n\n  if (buf->rand_type == TYPE_0)\n    {\n      int32_t val = (((get_int32 (&state[0]) * 1103515245U) + 12345U)\n                     & 0x7fffffff);\n      set_int32 (&state[0], val);\n      *result = val;\n    }\n  else\n    {\n      int32_t *fptr = buf->fptr;\n      int32_t *rptr = buf->rptr;\n      int32_t *end_ptr = buf->end_ptr;\n      /* F and R are unsigned int, not uint32_t, to avoid undefined\n         overflow behavior on platforms where INT_MAX == UINT32_MAX.  */\n      unsigned int f = get_int32 (fptr);\n      unsigned int r = get_int32 (rptr);\n      uint32_t val = f + r;\n      set_int32 (fptr, val);\n      /* Chucking least random bit.  */\n      *result = val >> 1;\n      ++fptr;\n      if (fptr >= end_ptr)\n        {\n          fptr = state;\n          ++rptr;\n        }\n      else\n        {\n          ++rptr;\n          if (rptr >= end_ptr)\n            rptr = state;\n        }\n      buf->fptr = fptr;\n      buf->rptr = rptr;\n    }\n  return 0;\n\n fail:\n  __set_errno (EINVAL);\n  return -1;\n}\n\nweak_alias (__random_r, random_r)\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sockets.c",
    "content": "/* sockets.c --- wrappers for Windows socket functions\n\n   Copyright (C) 2008-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Simon Josefsson */\n\n#include <config.h>\n\n/* Specification.  */\n#include \"sockets.h\"\n\n#if WINDOWS_SOCKETS\n\n/* This includes winsock2.h on MinGW. */\n# include <sys/socket.h>\n\n# include \"fd-hook.h\"\n# if GNULIB_MSVC_NOTHROW\n#  include \"msvc-nothrow.h\"\n# else\n#  include <io.h>\n# endif\n\n/* Get set_winsock_errno, FD_TO_SOCKET etc. */\n# include \"w32sock.h\"\n\nstatic int\nclose_fd_maybe_socket (const struct fd_hook *remaining_list,\n                       gl_close_fn primary,\n                       int fd)\n{\n  /* Note about multithread-safety: There is a race condition where, between\n     our calls to closesocket() and the primary close(), some other thread\n     could make system calls that allocate precisely the same HANDLE value\n     as sock; then the primary close() would call CloseHandle() on it.  */\n  SOCKET sock;\n  WSANETWORKEVENTS ev;\n\n  /* Test whether fd refers to a socket.  */\n  sock = FD_TO_SOCKET (fd);\n  ev.lNetworkEvents = 0xDEADBEEF;\n  WSAEnumNetworkEvents (sock, NULL, &ev);\n  if (ev.lNetworkEvents != 0xDEADBEEF)\n    {\n      /* fd refers to a socket.  */\n      /* FIXME: other applications, like squid, use an undocumented\n         _free_osfhnd free function.  But this is not enough: The 'osfile'\n         flags for fd also needs to be cleared, but it is hard to access it.\n         Instead, here we just close twice the file descriptor.  */\n      if (closesocket (sock))\n        {\n          set_winsock_errno ();\n          return -1;\n        }\n      else\n        {\n          /* This call frees the file descriptor and does a\n             CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails.  */\n          _close (fd);\n          return 0;\n        }\n    }\n  else\n    /* Some other type of file descriptor.  */\n    return execute_close_hooks (remaining_list, primary, fd);\n}\n\nstatic int\nioctl_fd_maybe_socket (const struct fd_hook *remaining_list,\n                       gl_ioctl_fn primary,\n                       int fd, int request, void *arg)\n{\n  SOCKET sock;\n  WSANETWORKEVENTS ev;\n\n  /* Test whether fd refers to a socket.  */\n  sock = FD_TO_SOCKET (fd);\n  ev.lNetworkEvents = 0xDEADBEEF;\n  WSAEnumNetworkEvents (sock, NULL, &ev);\n  if (ev.lNetworkEvents != 0xDEADBEEF)\n    {\n      /* fd refers to a socket.  */\n      if (ioctlsocket (sock, request, arg) < 0)\n        {\n          set_winsock_errno ();\n          return -1;\n        }\n      else\n        return 0;\n    }\n  else\n    /* Some other type of file descriptor.  */\n    return execute_ioctl_hooks (remaining_list, primary, fd, request, arg);\n}\n\nstatic struct fd_hook fd_sockets_hook;\n\nstatic int initialized_sockets_version /* = 0 */;\n\n#endif /* WINDOWS_SOCKETS */\n\nint\ngl_sockets_startup (_GL_UNUSED int version)\n{\n#if WINDOWS_SOCKETS\n  if (version > initialized_sockets_version)\n    {\n      WSADATA data;\n      int err;\n\n      err = WSAStartup (version, &data);\n      if (err != 0)\n        return 1;\n\n      if (data.wVersion != version)\n        {\n          WSACleanup ();\n          return 2;\n        }\n\n      if (initialized_sockets_version == 0)\n        register_fd_hook (close_fd_maybe_socket, ioctl_fd_maybe_socket,\n                          &fd_sockets_hook);\n\n      initialized_sockets_version = version;\n    }\n#endif\n\n  return 0;\n}\n\nint\ngl_sockets_cleanup (void)\n{\n#if WINDOWS_SOCKETS\n  int err;\n\n  initialized_sockets_version = 0;\n\n  unregister_fd_hook (&fd_sockets_hook);\n\n  err = WSACleanup ();\n  if (err != 0)\n    return 1;\n#endif\n\n  return 0;\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sockets.h",
    "content": "/* sockets.h - wrappers for Windows socket functions\n\n   Copyright (C) 2008-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Simon Josefsson */\n\n#ifndef SOCKETS_H\n#define SOCKETS_H 1\n\n#define SOCKETS_1_0 0x0001\n#define SOCKETS_1_1 0x0101\n#define SOCKETS_2_0 0x0002\n#define SOCKETS_2_1 0x0102\n#define SOCKETS_2_2 0x0202\n\nint gl_sockets_startup (int version)\n#ifndef WINDOWS_SOCKETS\n  _GL_ATTRIBUTE_CONST\n#endif\n  ;\n\nint gl_sockets_cleanup (void)\n#ifndef WINDOWS_SOCKETS\n  _GL_ATTRIBUTE_CONST\n#endif\n  ;\n\n/* This function is useful it you create a socket using gnulib's\n   Winsock wrappers but needs to pass on the socket handle to some\n   other library that only accepts sockets. */\n#ifdef WINDOWS_SOCKETS\n\n# include <sys/socket.h>\n\n# if GNULIB_MSVC_NOTHROW\n#  include \"msvc-nothrow.h\"\n# else\n#  include <io.h>\n# endif\n\nstatic inline SOCKET\ngl_fd_to_handle (int fd)\n{\n  return _get_osfhandle (fd);\n}\n\n#else\n\n# define gl_fd_to_handle(x) (x)\n\n#endif /* WINDOWS_SOCKETS */\n\n#endif /* SOCKETS_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/stdalign.in.h",
    "content": "/* A substitute for ISO C11 <stdalign.h>.\n\n   Copyright 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paul Eggert and Bruno Haible.  */\n\n#ifndef _GL_STDALIGN_H\n#define _GL_STDALIGN_H\n\n/* ISO C11 <stdalign.h> for platforms that lack it.\n\n   References:\n   ISO C11 (latest free draft\n   <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>)\n   sections 6.5.3.4, 6.7.5, 7.15.\n   C++11 (latest free draft\n   <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)\n   section 18.10. */\n\n/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment\n   requirement of a structure member (i.e., slot or field) that is of\n   type TYPE, as an integer constant expression.\n\n   This differs from GCC's and clang's __alignof__ operator, which can\n   yield a better-performing alignment for an object of that type.  For\n   example, on x86 with GCC and on Linux/x86 with clang,\n   __alignof__ (double) and __alignof__ (long long) are 8, whereas\n   alignof (double) and alignof (long long) are 4 unless the option\n   '-malign-double' is used.\n\n   The result cannot be used as a value for an 'enum' constant, if you\n   want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc.\n\n   Include <stddef.h> for offsetof.  */\n#include <stddef.h>\n\n/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other\n   standard headers, defines conflicting implementations of _Alignas\n   and _Alignof that are no better than ours; override them.  */\n#undef _Alignas\n#undef _Alignof\n\n/* GCC releases before GCC 4.9 had a bug in _Alignof.  See GCC bug 52023\n   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.\n   clang versions < 8.0.0 have the same bug.  */\n#if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \\\n     || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \\\n         && !defined __clang__) \\\n     || (defined __clang__ && __clang_major__ < 8))\n# ifdef __cplusplus\n#  if 201103 <= __cplusplus\n#   define _Alignof(type) alignof (type)\n#  else\n   template <class __t> struct __alignof_helper { char __a; __t __b; };\n#   define _Alignof(type) offsetof (__alignof_helper<type>, __b)\n#  endif\n# else\n#  define _Alignof(type) offsetof (struct { char __a; type __b; }, __b)\n# endif\n#endif\n#if ! (defined __cplusplus && 201103 <= __cplusplus)\n# define alignof _Alignof\n#endif\n#define __alignof_is_defined 1\n\n/* alignas (A), also known as _Alignas (A), aligns a variable or type\n   to the alignment A, where A is an integer constant expression.  For\n   example:\n\n      int alignas (8) foo;\n      struct s { int a; int alignas (8) bar; };\n\n   aligns the address of FOO and the offset of BAR to be multiples of 8.\n\n   A should be a power of two that is at least the type's alignment\n   and at most the implementation's alignment limit.  This limit is\n   2**28 on typical GNUish hosts, and 2**13 on MSVC.  To be portable\n   to MSVC through at least version 10.0, A should be an integer\n   constant, as MSVC does not support expressions such as 1 << 3.\n   To be portable to Sun C 5.11, do not align auto variables to\n   anything stricter than their default alignment.\n\n   The following C11 requirements are not supported here:\n\n     - If A is zero, alignas has no effect.\n     - alignas can be used multiple times; the strictest one wins.\n     - alignas (TYPE) is equivalent to alignas (alignof (TYPE)).\n\n   */\n\n#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112\n# if defined __cplusplus && 201103 <= __cplusplus\n#  define _Alignas(a) alignas (a)\n# elif (!defined __attribute__ \\\n        && ((defined __APPLE__ && defined __MACH__ \\\n             ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \\\n             : __GNUC__ && !defined __ibmxl__) \\\n            || (4 <= __clang_major__) \\\n            || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \\\n            || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))\n#  define _Alignas(a) __attribute__ ((__aligned__ (a)))\n# elif 1300 <= _MSC_VER\n#  define _Alignas(a) __declspec (align (a))\n# endif\n#endif\n#if ((defined _Alignas && ! (defined __cplusplus && 201103 <= __cplusplus)) \\\n     || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))\n# define alignas _Alignas\n#endif\n#if defined alignas || (defined __cplusplus && 201103 <= __cplusplus)\n# define __alignas_is_defined 1\n#endif\n\n#endif /* _GL_STDALIGN_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/stddef.in.h",
    "content": "/* A substitute for POSIX 2008 <stddef.h>, for platforms that have issues.\n\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Eric Blake.  */\n\n/*\n * POSIX 2008 <stddef.h> for platforms that have issues.\n * <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html>\n */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined __need_wchar_t || defined __need_size_t  \\\n  || defined __need_ptrdiff_t || defined __need_NULL \\\n  || defined __need_wint_t\n/* Special invocation convention inside gcc header files.  In\n   particular, gcc provides a version of <stddef.h> that blindly\n   redefines NULL even when __need_wint_t was defined, even though\n   wint_t is not normally provided by <stddef.h>.  Hence, we must\n   remember if special invocation has ever been used to obtain wint_t,\n   in which case we need to clean up NULL yet again.  */\n\n# if !(defined _@GUARD_PREFIX@_STDDEF_H && defined _GL_STDDEF_WINT_T)\n#  ifdef __need_wint_t\n#   define _GL_STDDEF_WINT_T\n#  endif\n#  @INCLUDE_NEXT@ @NEXT_STDDEF_H@\n   /* On TinyCC, make sure that the macros that indicate the special invocation\n      convention get undefined.  */\n#  undef __need_wchar_t\n#  undef __need_size_t\n#  undef __need_ptrdiff_t\n#  undef __need_NULL\n#  undef __need_wint_t\n# endif\n\n#else\n/* Normal invocation convention.  */\n\n# ifndef _@GUARD_PREFIX@_STDDEF_H\n\n/* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a\n   type with alignment 4, but 'long' has alignment 8.  */\n#  if defined _AIX && defined __LP64__\n#   if !GNULIB_defined_max_align_t\n#    ifdef _MAX_ALIGN_T\n/* /usr/include/stddef.h has already defined max_align_t.  Override it.  */\ntypedef long rpl_max_align_t;\n#     define max_align_t rpl_max_align_t\n#    else\n/* Prevent /usr/include/stddef.h from defining max_align_t.  */\ntypedef long max_align_t;\n#     define _MAX_ALIGN_T\n#    endif\n#    define GNULIB_defined_max_align_t 1\n#   endif\n#  endif\n\n/* The include_next requires a split double-inclusion guard.  */\n\n#  @INCLUDE_NEXT@ @NEXT_STDDEF_H@\n\n/* On NetBSD 5.0, the definition of NULL lacks proper parentheses.  */\n#  if (@REPLACE_NULL@ \\\n       && (!defined _@GUARD_PREFIX@_STDDEF_H || defined _GL_STDDEF_WINT_T))\n#   undef NULL\n#   ifdef __cplusplus\n   /* ISO C++ says that the macro NULL must expand to an integer constant\n      expression, hence '((void *) 0)' is not allowed in C++.  */\n#    if __GNUG__ >= 3\n    /* GNU C++ has a __null macro that behaves like an integer ('int' or\n       'long') but has the same size as a pointer.  Use that, to avoid\n       warnings.  */\n#     define NULL __null\n#    else\n#     define NULL 0L\n#    endif\n#   else\n#    define NULL ((void *) 0)\n#   endif\n#  endif\n\n#  ifndef _@GUARD_PREFIX@_STDDEF_H\n#   define _@GUARD_PREFIX@_STDDEF_H\n\n/* Some platforms lack wchar_t.  */\n#if !@HAVE_WCHAR_T@\n# define wchar_t int\n#endif\n\n/* Some platforms lack max_align_t.  The check for _GCC_MAX_ALIGN_T is\n   a hack in case the configure-time test was done with g++ even though\n   we are currently compiling with gcc.\n   On MSVC, max_align_t is defined only in C++ mode, after <cstddef> was\n   included.  Its definition is good since it has an alignment of 8 (on x86\n   and x86_64).\n   Similarly on OS/2 kLIBC.  */\n#if (defined _MSC_VER || (defined __KLIBC__ && !defined __LIBCN__)) \\\n    && defined __cplusplus\n# include <cstddef>\n#else\n# if ! (@HAVE_MAX_ALIGN_T@ || (defined _GCC_MAX_ALIGN_T && !defined __clang__))\n#  if !GNULIB_defined_max_align_t\n/* On the x86, the maximum storage alignment of double, long, etc. is 4,\n   but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8,\n   and the C11 standard allows this.  Work around this problem by\n   using __alignof__ (which returns 8 for double) rather than _Alignof\n   (which returns 4), and align each union member accordingly.  */\n#   if defined __GNUC__ || (__clang_major__ >= 4)\n#    define _GL_STDDEF_ALIGNAS(type) \\\n       __attribute__ ((__aligned__ (__alignof__ (type))))\n#   else\n#    define _GL_STDDEF_ALIGNAS(type) /* */\n#   endif\ntypedef union\n{\n  char *__p _GL_STDDEF_ALIGNAS (char *);\n  double __d _GL_STDDEF_ALIGNAS (double);\n  long double __ld _GL_STDDEF_ALIGNAS (long double);\n  long int __i _GL_STDDEF_ALIGNAS (long int);\n} rpl_max_align_t;\n#   define max_align_t rpl_max_align_t\n#   define GNULIB_defined_max_align_t 1\n#  endif\n# endif\n#endif\n\n#  endif /* _@GUARD_PREFIX@_STDDEF_H */\n# endif /* _@GUARD_PREFIX@_STDDEF_H */\n#endif /* __need_XXX */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/stdint.in.h",
    "content": "/* Copyright (C) 2001-2002, 2004-2021 Free Software Foundation, Inc.\n   Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood.\n   This file is part of gnulib.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/*\n * ISO C 99 <stdint.h> for platforms that lack it.\n * <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html>\n */\n\n#ifndef _@GUARD_PREFIX@_STDINT_H\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n/* When including a system file that in turn includes <inttypes.h>,\n   use the system <inttypes.h>, not our substitute.  This avoids\n   problems with (for example) VMS, whose <sys/bitypes.h> includes\n   <inttypes.h>.  */\n#define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H\n\n/* On Android (Bionic libc), <sys/types.h> includes this file before\n   having defined 'time_t'.  Therefore in this case avoid including\n   other system header files; just include the system's <stdint.h>.\n   Ideally we should test __BIONIC__ here, but it is only defined after\n   <sys/cdefs.h> has been included; hence test __ANDROID__ instead.  */\n#if defined __ANDROID__ && defined _GL_INCLUDING_SYS_TYPES_H\n# @INCLUDE_NEXT@ @NEXT_STDINT_H@\n#else\n\n/* Get those types that are already defined in other system include\n   files, so that we can \"#define int8_t signed char\" below without\n   worrying about a later system include file containing a \"typedef\n   signed char int8_t;\" that will get messed up by our macro.  Our\n   macros should all be consistent with the system versions, except\n   for the \"fast\" types and macros, which we recommend against using\n   in public interfaces due to compiler differences.  */\n\n#if @HAVE_STDINT_H@\n# if defined __sgi && ! defined __c99\n   /* Bypass IRIX's <stdint.h> if in C89 mode, since it merely annoys users\n      with \"This header file is to be used only for c99 mode compilations\"\n      diagnostics.  */\n#  define __STDINT_H__\n# endif\n\n  /* Some pre-C++11 <stdint.h> implementations need this.  */\n# ifdef __cplusplus\n#  ifndef __STDC_CONSTANT_MACROS\n#   define __STDC_CONSTANT_MACROS 1\n#  endif\n#  ifndef __STDC_LIMIT_MACROS\n#   define __STDC_LIMIT_MACROS 1\n#  endif\n# endif\n\n  /* Other systems may have an incomplete or buggy <stdint.h>.\n     Include it before <inttypes.h>, since any \"#include <stdint.h>\"\n     in <inttypes.h> would reinclude us, skipping our contents because\n     _@GUARD_PREFIX@_STDINT_H is defined.\n     The include_next requires a split double-inclusion guard.  */\n# @INCLUDE_NEXT@ @NEXT_STDINT_H@\n#endif\n\n#if ! defined _@GUARD_PREFIX@_STDINT_H && ! defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H\n#define _@GUARD_PREFIX@_STDINT_H\n\n/* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX,\n   LONG_MIN, LONG_MAX, ULONG_MAX, _GL_INTEGER_WIDTH.  */\n#include <limits.h>\n\n/* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides\n   wint_t.  */\n#if @GNULIBHEADERS_OVERRIDE_WINT_T@\n# undef WINT_MIN\n# undef WINT_MAX\n# define WINT_MIN 0x0U\n# define WINT_MAX 0xffffffffU\n#endif\n\n#if ! @HAVE_C99_STDINT_H@\n\n/* <sys/types.h> defines some of the stdint.h types as well, on glibc,\n   IRIX 6.5, and OpenBSD 3.8 (via <machine/types.h>).\n   AIX 5.2 <sys/types.h> isn't needed and causes troubles.\n   Mac OS X 10.4.6 <sys/types.h> includes <stdint.h> (which is us), but\n   relies on the system <stdint.h> definitions, so include\n   <sys/types.h> after @NEXT_STDINT_H@.  */\n# if @HAVE_SYS_TYPES_H@ && ! defined _AIX\n#  include <sys/types.h>\n# endif\n\n# if @HAVE_INTTYPES_H@\n  /* In OpenBSD 3.8, <inttypes.h> includes <machine/types.h>, which defines\n     int{8,16,32,64}_t, uint{8,16,32,64}_t and __BIT_TYPES_DEFINED__.\n     <inttypes.h> also defines intptr_t and uintptr_t.  */\n#  include <inttypes.h>\n# elif @HAVE_SYS_INTTYPES_H@\n  /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and\n     the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX.  */\n#  include <sys/inttypes.h>\n# endif\n\n# if @HAVE_SYS_BITYPES_H@ && ! defined __BIT_TYPES_DEFINED__\n  /* Linux libc4 >= 4.6.7 and libc5 have a <sys/bitypes.h> that defines\n     int{8,16,32,64}_t and __BIT_TYPES_DEFINED__.  In libc5 >= 5.2.2 it is\n     included by <sys/types.h>.  */\n#  include <sys/bitypes.h>\n# endif\n\n# undef _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H\n\n/* Minimum and maximum values for an integer type under the usual assumption.\n   Return an unspecified value if BITS == 0, adding a check to pacify\n   picky compilers.  */\n\n/* These are separate macros, because if you try to merge these macros into\n   a single one, HP-UX cc rejects the resulting expression in constant\n   expressions.  */\n# define _STDINT_UNSIGNED_MIN(bits, zero) \\\n    (zero)\n# define _STDINT_SIGNED_MIN(bits, zero) \\\n    (~ _STDINT_MAX (1, bits, zero))\n\n# define _STDINT_MAX(signed, bits, zero) \\\n    (((((zero) + 1) << ((bits) ? (bits) - 1 - (signed) : 0)) - 1) * 2 + 1)\n\n#if !GNULIB_defined_stdint_types\n\n/* 7.18.1.1. Exact-width integer types */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits.  */\n\n# undef int8_t\n# undef uint8_t\ntypedef signed char gl_int8_t;\ntypedef unsigned char gl_uint8_t;\n# define int8_t gl_int8_t\n# define uint8_t gl_uint8_t\n\n# undef int16_t\n# undef uint16_t\ntypedef short int gl_int16_t;\ntypedef unsigned short int gl_uint16_t;\n# define int16_t gl_int16_t\n# define uint16_t gl_uint16_t\n\n# undef int32_t\n# undef uint32_t\ntypedef int gl_int32_t;\ntypedef unsigned int gl_uint32_t;\n# define int32_t gl_int32_t\n# define uint32_t gl_uint32_t\n\n/* If the system defines INT64_MAX, assume int64_t works.  That way,\n   if the underlying platform defines int64_t to be a 64-bit long long\n   int, the code below won't mistakenly define it to be a 64-bit long\n   int, which would mess up C++ name mangling.  We must use #ifdef\n   rather than #if, to avoid an error with HP-UX 10.20 cc.  */\n\n# ifdef INT64_MAX\n#  define GL_INT64_T\n# else\n/* Do not undefine int64_t if gnulib is not being used with 64-bit\n   types, since otherwise it breaks platforms like Tandem/NSK.  */\n#  if LONG_MAX >> 31 >> 31 == 1\n#   undef int64_t\ntypedef long int gl_int64_t;\n#   define int64_t gl_int64_t\n#   define GL_INT64_T\n#  elif defined _MSC_VER\n#   undef int64_t\ntypedef __int64 gl_int64_t;\n#   define int64_t gl_int64_t\n#   define GL_INT64_T\n#  else\n#   undef int64_t\ntypedef long long int gl_int64_t;\n#   define int64_t gl_int64_t\n#   define GL_INT64_T\n#  endif\n# endif\n\n# ifdef UINT64_MAX\n#  define GL_UINT64_T\n# else\n#  if ULONG_MAX >> 31 >> 31 >> 1 == 1\n#   undef uint64_t\ntypedef unsigned long int gl_uint64_t;\n#   define uint64_t gl_uint64_t\n#   define GL_UINT64_T\n#  elif defined _MSC_VER\n#   undef uint64_t\ntypedef unsigned __int64 gl_uint64_t;\n#   define uint64_t gl_uint64_t\n#   define GL_UINT64_T\n#  else\n#   undef uint64_t\ntypedef unsigned long long int gl_uint64_t;\n#   define uint64_t gl_uint64_t\n#   define GL_UINT64_T\n#  endif\n# endif\n\n/* Avoid collision with Solaris 2.5.1 <pthread.h> etc.  */\n# define _UINT8_T\n# define _UINT32_T\n# define _UINT64_T\n\n\n/* 7.18.1.2. Minimum-width integer types */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types\n   are the same as the corresponding N_t types.  */\n\n# undef int_least8_t\n# undef uint_least8_t\n# undef int_least16_t\n# undef uint_least16_t\n# undef int_least32_t\n# undef uint_least32_t\n# undef int_least64_t\n# undef uint_least64_t\n# define int_least8_t int8_t\n# define uint_least8_t uint8_t\n# define int_least16_t int16_t\n# define uint_least16_t uint16_t\n# define int_least32_t int32_t\n# define uint_least32_t uint32_t\n# ifdef GL_INT64_T\n#  define int_least64_t int64_t\n# endif\n# ifdef GL_UINT64_T\n#  define uint_least64_t uint64_t\n# endif\n\n/* 7.18.1.3. Fastest minimum-width integer types */\n\n/* Note: Other <stdint.h> substitutes may define these types differently.\n   It is not recommended to use these types in public header files. */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types\n   are taken from the same list of types.  The following code normally\n   uses types consistent with glibc, as that lessens the chance of\n   incompatibility with older GNU hosts.  */\n\n# undef int_fast8_t\n# undef uint_fast8_t\n# undef int_fast16_t\n# undef uint_fast16_t\n# undef int_fast32_t\n# undef uint_fast32_t\n# undef int_fast64_t\n# undef uint_fast64_t\ntypedef signed char gl_int_fast8_t;\ntypedef unsigned char gl_uint_fast8_t;\n\n# ifdef __sun\n/* Define types compatible with SunOS 5.10, so that code compiled under\n   earlier SunOS versions works with code compiled under SunOS 5.10.  */\ntypedef int gl_int_fast32_t;\ntypedef unsigned int gl_uint_fast32_t;\n# else\ntypedef long int gl_int_fast32_t;\ntypedef unsigned long int gl_uint_fast32_t;\n# endif\ntypedef gl_int_fast32_t gl_int_fast16_t;\ntypedef gl_uint_fast32_t gl_uint_fast16_t;\n\n# define int_fast8_t gl_int_fast8_t\n# define uint_fast8_t gl_uint_fast8_t\n# define int_fast16_t gl_int_fast16_t\n# define uint_fast16_t gl_uint_fast16_t\n# define int_fast32_t gl_int_fast32_t\n# define uint_fast32_t gl_uint_fast32_t\n# ifdef GL_INT64_T\n#  define int_fast64_t int64_t\n# endif\n# ifdef GL_UINT64_T\n#  define uint_fast64_t uint64_t\n# endif\n\n/* 7.18.1.4. Integer types capable of holding object pointers */\n\n/* kLIBC's <stdint.h> defines _INTPTR_T_DECLARED and needs its own\n   definitions of intptr_t and uintptr_t (which use int and unsigned)\n   to avoid clashes with declarations of system functions like sbrk.\n   Similarly, MinGW WSL-5.4.1 <stdint.h> needs its own intptr_t and\n   uintptr_t to avoid conflicting declarations of system functions like\n   _findclose in <io.h>.  */\n# if !((defined __KLIBC__ && defined _INTPTR_T_DECLARED) \\\n       || defined __MINGW32__)\n#  undef intptr_t\n#  undef uintptr_t\n#  ifdef _WIN64\ntypedef long long int gl_intptr_t;\ntypedef unsigned long long int gl_uintptr_t;\n#  else\ntypedef long int gl_intptr_t;\ntypedef unsigned long int gl_uintptr_t;\n#  endif\n#  define intptr_t gl_intptr_t\n#  define uintptr_t gl_uintptr_t\n# endif\n\n/* 7.18.1.5. Greatest-width integer types */\n\n/* Note: These types are compiler dependent. It may be unwise to use them in\n   public header files. */\n\n/* If the system defines INTMAX_MAX, assume that intmax_t works, and\n   similarly for UINTMAX_MAX and uintmax_t.  This avoids problems with\n   assuming one type where another is used by the system.  */\n\n# ifndef INTMAX_MAX\n#  undef INTMAX_C\n#  undef intmax_t\n#  if LONG_MAX >> 30 == 1\ntypedef long long int gl_intmax_t;\n#   define intmax_t gl_intmax_t\n#  elif defined GL_INT64_T\n#   define intmax_t int64_t\n#  else\ntypedef long int gl_intmax_t;\n#   define intmax_t gl_intmax_t\n#  endif\n# endif\n\n# ifndef UINTMAX_MAX\n#  undef UINTMAX_C\n#  undef uintmax_t\n#  if ULONG_MAX >> 31 == 1\ntypedef unsigned long long int gl_uintmax_t;\n#   define uintmax_t gl_uintmax_t\n#  elif defined GL_UINT64_T\n#   define uintmax_t uint64_t\n#  else\ntypedef unsigned long int gl_uintmax_t;\n#   define uintmax_t gl_uintmax_t\n#  endif\n# endif\n\n/* Verify that intmax_t and uintmax_t have the same size.  Too much code\n   breaks if this is not the case.  If this check fails, the reason is likely\n   to be found in the autoconf macros.  */\ntypedef int _verify_intmax_size[sizeof (intmax_t) == sizeof (uintmax_t)\n                                ? 1 : -1];\n\n# define GNULIB_defined_stdint_types 1\n# endif /* !GNULIB_defined_stdint_types */\n\n/* 7.18.2. Limits of specified-width integer types */\n\n/* 7.18.2.1. Limits of exact-width integer types */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits.  */\n\n# undef INT8_MIN\n# undef INT8_MAX\n# undef UINT8_MAX\n# define INT8_MIN  (~ INT8_MAX)\n# define INT8_MAX  127\n# define UINT8_MAX  255\n\n# undef INT16_MIN\n# undef INT16_MAX\n# undef UINT16_MAX\n# define INT16_MIN  (~ INT16_MAX)\n# define INT16_MAX  32767\n# define UINT16_MAX  65535\n\n# undef INT32_MIN\n# undef INT32_MAX\n# undef UINT32_MAX\n# define INT32_MIN  (~ INT32_MAX)\n# define INT32_MAX  2147483647\n# define UINT32_MAX  4294967295U\n\n# if defined GL_INT64_T && ! defined INT64_MAX\n/* Prefer (- INTMAX_C (1) << 63) over (~ INT64_MAX) because SunPRO C 5.0\n   evaluates the latter incorrectly in preprocessor expressions.  */\n#  define INT64_MIN  (- INTMAX_C (1) << 63)\n#  define INT64_MAX  INTMAX_C (9223372036854775807)\n# endif\n\n# if defined GL_UINT64_T && ! defined UINT64_MAX\n#  define UINT64_MAX  UINTMAX_C (18446744073709551615)\n# endif\n\n/* 7.18.2.2. Limits of minimum-width integer types */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types\n   are the same as the corresponding N_t types.  */\n\n# undef INT_LEAST8_MIN\n# undef INT_LEAST8_MAX\n# undef UINT_LEAST8_MAX\n# define INT_LEAST8_MIN  INT8_MIN\n# define INT_LEAST8_MAX  INT8_MAX\n# define UINT_LEAST8_MAX  UINT8_MAX\n\n# undef INT_LEAST16_MIN\n# undef INT_LEAST16_MAX\n# undef UINT_LEAST16_MAX\n# define INT_LEAST16_MIN  INT16_MIN\n# define INT_LEAST16_MAX  INT16_MAX\n# define UINT_LEAST16_MAX  UINT16_MAX\n\n# undef INT_LEAST32_MIN\n# undef INT_LEAST32_MAX\n# undef UINT_LEAST32_MAX\n# define INT_LEAST32_MIN  INT32_MIN\n# define INT_LEAST32_MAX  INT32_MAX\n# define UINT_LEAST32_MAX  UINT32_MAX\n\n# undef INT_LEAST64_MIN\n# undef INT_LEAST64_MAX\n# ifdef GL_INT64_T\n#  define INT_LEAST64_MIN  INT64_MIN\n#  define INT_LEAST64_MAX  INT64_MAX\n# endif\n\n# undef UINT_LEAST64_MAX\n# ifdef GL_UINT64_T\n#  define UINT_LEAST64_MAX  UINT64_MAX\n# endif\n\n/* 7.18.2.3. Limits of fastest minimum-width integer types */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types\n   are taken from the same list of types.  */\n\n# undef INT_FAST8_MIN\n# undef INT_FAST8_MAX\n# undef UINT_FAST8_MAX\n# define INT_FAST8_MIN  SCHAR_MIN\n# define INT_FAST8_MAX  SCHAR_MAX\n# define UINT_FAST8_MAX  UCHAR_MAX\n\n# undef INT_FAST16_MIN\n# undef INT_FAST16_MAX\n# undef UINT_FAST16_MAX\n# define INT_FAST16_MIN  INT_FAST32_MIN\n# define INT_FAST16_MAX  INT_FAST32_MAX\n# define UINT_FAST16_MAX  UINT_FAST32_MAX\n\n# undef INT_FAST32_MIN\n# undef INT_FAST32_MAX\n# undef UINT_FAST32_MAX\n# ifdef __sun\n#  define INT_FAST32_MIN  INT_MIN\n#  define INT_FAST32_MAX  INT_MAX\n#  define UINT_FAST32_MAX  UINT_MAX\n# else\n#  define INT_FAST32_MIN  LONG_MIN\n#  define INT_FAST32_MAX  LONG_MAX\n#  define UINT_FAST32_MAX  ULONG_MAX\n# endif\n\n# undef INT_FAST64_MIN\n# undef INT_FAST64_MAX\n# ifdef GL_INT64_T\n#  define INT_FAST64_MIN  INT64_MIN\n#  define INT_FAST64_MAX  INT64_MAX\n# endif\n\n# undef UINT_FAST64_MAX\n# ifdef GL_UINT64_T\n#  define UINT_FAST64_MAX  UINT64_MAX\n# endif\n\n/* 7.18.2.4. Limits of integer types capable of holding object pointers */\n\n# undef INTPTR_MIN\n# undef INTPTR_MAX\n# undef UINTPTR_MAX\n# ifdef _WIN64\n#  define INTPTR_MIN  LLONG_MIN\n#  define INTPTR_MAX  LLONG_MAX\n#  define UINTPTR_MAX  ULLONG_MAX\n# else\n#  define INTPTR_MIN  LONG_MIN\n#  define INTPTR_MAX  LONG_MAX\n#  define UINTPTR_MAX  ULONG_MAX\n# endif\n\n/* 7.18.2.5. Limits of greatest-width integer types */\n\n# ifndef INTMAX_MAX\n#  undef INTMAX_MIN\n#  ifdef INT64_MAX\n#   define INTMAX_MIN  INT64_MIN\n#   define INTMAX_MAX  INT64_MAX\n#  else\n#   define INTMAX_MIN  INT32_MIN\n#   define INTMAX_MAX  INT32_MAX\n#  endif\n# endif\n\n# ifndef UINTMAX_MAX\n#  ifdef UINT64_MAX\n#   define UINTMAX_MAX  UINT64_MAX\n#  else\n#   define UINTMAX_MAX  UINT32_MAX\n#  endif\n# endif\n\n/* 7.18.3. Limits of other integer types */\n\n/* ptrdiff_t limits */\n# undef PTRDIFF_MIN\n# undef PTRDIFF_MAX\n# if @APPLE_UNIVERSAL_BUILD@\n#  ifdef _LP64\n#   define PTRDIFF_MIN  _STDINT_SIGNED_MIN (64, 0l)\n#   define PTRDIFF_MAX  _STDINT_MAX (1, 64, 0l)\n#  else\n#   define PTRDIFF_MIN  _STDINT_SIGNED_MIN (32, 0)\n#   define PTRDIFF_MAX  _STDINT_MAX (1, 32, 0)\n#  endif\n# else\n#  define PTRDIFF_MIN  \\\n    _STDINT_SIGNED_MIN (@BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@)\n#  define PTRDIFF_MAX  \\\n    _STDINT_MAX (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@)\n# endif\n\n/* sig_atomic_t limits */\n# undef SIG_ATOMIC_MIN\n# undef SIG_ATOMIC_MAX\n# if @HAVE_SIGNED_SIG_ATOMIC_T@\n#  define SIG_ATOMIC_MIN  \\\n    _STDINT_SIGNED_MIN (@BITSIZEOF_SIG_ATOMIC_T@, 0@SIG_ATOMIC_T_SUFFIX@)\n# else\n#  define SIG_ATOMIC_MIN  \\\n    _STDINT_UNSIGNED_MIN (@BITSIZEOF_SIG_ATOMIC_T@, 0@SIG_ATOMIC_T_SUFFIX@)\n# endif\n# define SIG_ATOMIC_MAX  \\\n   _STDINT_MAX (@HAVE_SIGNED_SIG_ATOMIC_T@, @BITSIZEOF_SIG_ATOMIC_T@, \\\n                0@SIG_ATOMIC_T_SUFFIX@)\n\n\n/* size_t limit */\n# undef SIZE_MAX\n# if @APPLE_UNIVERSAL_BUILD@\n#  ifdef _LP64\n#   define SIZE_MAX  _STDINT_MAX (0, 64, 0ul)\n#  else\n#   define SIZE_MAX  _STDINT_MAX (0, 32, 0ul)\n#  endif\n# else\n#  define SIZE_MAX  _STDINT_MAX (0, @BITSIZEOF_SIZE_T@, 0@SIZE_T_SUFFIX@)\n# endif\n\n/* wchar_t limits */\n/* Get WCHAR_MIN, WCHAR_MAX.\n   This include is not on the top, above, because on OSF/1 4.0 we have a\n   sequence of nested includes\n   <wchar.h> -> <stdio.h> -> <getopt.h> -> <stdlib.h>, and the latter includes\n   <stdint.h> and assumes its types are already defined.  */\n# if @HAVE_WCHAR_H@ && ! (defined WCHAR_MIN && defined WCHAR_MAX)\n#  define _GL_JUST_INCLUDE_SYSTEM_WCHAR_H\n#  include <wchar.h>\n#  undef _GL_JUST_INCLUDE_SYSTEM_WCHAR_H\n# endif\n# undef WCHAR_MIN\n# undef WCHAR_MAX\n# if @HAVE_SIGNED_WCHAR_T@\n#  define WCHAR_MIN  \\\n    _STDINT_SIGNED_MIN (@BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@)\n# else\n#  define WCHAR_MIN  \\\n    _STDINT_UNSIGNED_MIN (@BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@)\n# endif\n# define WCHAR_MAX  \\\n   _STDINT_MAX (@HAVE_SIGNED_WCHAR_T@, @BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@)\n\n/* wint_t limits */\n/* If gnulib's <wchar.h> or <wctype.h> overrides wint_t, @WINT_T_SUFFIX@ is not\n   accurate, therefore use the definitions from above.  */\n# if !@GNULIBHEADERS_OVERRIDE_WINT_T@\n#  undef WINT_MIN\n#  undef WINT_MAX\n#  if @HAVE_SIGNED_WINT_T@\n#   define WINT_MIN  \\\n     _STDINT_SIGNED_MIN (@BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@)\n#  else\n#   define WINT_MIN  \\\n     _STDINT_UNSIGNED_MIN (@BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@)\n#  endif\n#  define WINT_MAX  \\\n    _STDINT_MAX (@HAVE_SIGNED_WINT_T@, @BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@)\n# endif\n\n/* 7.18.4. Macros for integer constants */\n\n/* 7.18.4.1. Macros for minimum-width integer constants */\n/* According to ISO C 99 Technical Corrigendum 1 */\n\n/* Here we assume a standard architecture where the hardware integer\n   types have 8, 16, 32, optionally 64 bits, and int is 32 bits.  */\n\n# undef INT8_C\n# undef UINT8_C\n# define INT8_C(x) x\n# define UINT8_C(x) x\n\n# undef INT16_C\n# undef UINT16_C\n# define INT16_C(x) x\n# define UINT16_C(x) x\n\n# undef INT32_C\n# undef UINT32_C\n# define INT32_C(x) x\n# define UINT32_C(x) x ## U\n\n# undef INT64_C\n# undef UINT64_C\n# if LONG_MAX >> 31 >> 31 == 1\n#  define INT64_C(x) x##L\n# elif defined _MSC_VER\n#  define INT64_C(x) x##i64\n# else\n#  define INT64_C(x) x##LL\n# endif\n# if ULONG_MAX >> 31 >> 31 >> 1 == 1\n#  define UINT64_C(x) x##UL\n# elif defined _MSC_VER\n#  define UINT64_C(x) x##ui64\n# else\n#  define UINT64_C(x) x##ULL\n# endif\n\n/* 7.18.4.2. Macros for greatest-width integer constants */\n\n# ifndef INTMAX_C\n#  if LONG_MAX >> 30 == 1\n#   define INTMAX_C(x)   x##LL\n#  elif defined GL_INT64_T\n#   define INTMAX_C(x)   INT64_C(x)\n#  else\n#   define INTMAX_C(x)   x##L\n#  endif\n# endif\n\n# ifndef UINTMAX_C\n#  if ULONG_MAX >> 31 == 1\n#   define UINTMAX_C(x)  x##ULL\n#  elif defined GL_UINT64_T\n#   define UINTMAX_C(x)  UINT64_C(x)\n#  else\n#   define UINTMAX_C(x)  x##UL\n#  endif\n# endif\n\n#endif /* !@HAVE_C99_STDINT_H@ */\n\n/* Macros specified by ISO/IEC TS 18661-1:2014.  */\n\n#if (!defined UINTMAX_WIDTH \\\n     && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__))\n# ifdef INT8_MAX\n#  define INT8_WIDTH _GL_INTEGER_WIDTH (INT8_MIN, INT8_MAX)\n# endif\n# ifdef UINT8_MAX\n#  define UINT8_WIDTH _GL_INTEGER_WIDTH (0, UINT8_MAX)\n# endif\n# ifdef INT16_MAX\n#  define INT16_WIDTH _GL_INTEGER_WIDTH (INT16_MIN, INT16_MAX)\n# endif\n# ifdef UINT16_MAX\n#  define UINT16_WIDTH _GL_INTEGER_WIDTH (0, UINT16_MAX)\n# endif\n# ifdef INT32_MAX\n#  define INT32_WIDTH _GL_INTEGER_WIDTH (INT32_MIN, INT32_MAX)\n# endif\n# ifdef UINT32_MAX\n#  define UINT32_WIDTH _GL_INTEGER_WIDTH (0, UINT32_MAX)\n# endif\n# ifdef INT64_MAX\n#  define INT64_WIDTH _GL_INTEGER_WIDTH (INT64_MIN, INT64_MAX)\n# endif\n# ifdef UINT64_MAX\n#  define UINT64_WIDTH _GL_INTEGER_WIDTH (0, UINT64_MAX)\n# endif\n# define INT_LEAST8_WIDTH _GL_INTEGER_WIDTH (INT_LEAST8_MIN, INT_LEAST8_MAX)\n# define UINT_LEAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST8_MAX)\n# define INT_LEAST16_WIDTH _GL_INTEGER_WIDTH (INT_LEAST16_MIN, INT_LEAST16_MAX)\n# define UINT_LEAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST16_MAX)\n# define INT_LEAST32_WIDTH _GL_INTEGER_WIDTH (INT_LEAST32_MIN, INT_LEAST32_MAX)\n# define UINT_LEAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST32_MAX)\n# define INT_LEAST64_WIDTH _GL_INTEGER_WIDTH (INT_LEAST64_MIN, INT_LEAST64_MAX)\n# define UINT_LEAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST64_MAX)\n# define INT_FAST8_WIDTH _GL_INTEGER_WIDTH (INT_FAST8_MIN, INT_FAST8_MAX)\n# define UINT_FAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST8_MAX)\n# define INT_FAST16_WIDTH _GL_INTEGER_WIDTH (INT_FAST16_MIN, INT_FAST16_MAX)\n# define UINT_FAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST16_MAX)\n# define INT_FAST32_WIDTH _GL_INTEGER_WIDTH (INT_FAST32_MIN, INT_FAST32_MAX)\n# define UINT_FAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST32_MAX)\n# define INT_FAST64_WIDTH _GL_INTEGER_WIDTH (INT_FAST64_MIN, INT_FAST64_MAX)\n# define UINT_FAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST64_MAX)\n# define INTPTR_WIDTH _GL_INTEGER_WIDTH (INTPTR_MIN, INTPTR_MAX)\n# define UINTPTR_WIDTH _GL_INTEGER_WIDTH (0, UINTPTR_MAX)\n# define INTMAX_WIDTH _GL_INTEGER_WIDTH (INTMAX_MIN, INTMAX_MAX)\n# define UINTMAX_WIDTH _GL_INTEGER_WIDTH (0, UINTMAX_MAX)\n# define PTRDIFF_WIDTH _GL_INTEGER_WIDTH (PTRDIFF_MIN, PTRDIFF_MAX)\n# define SIZE_WIDTH _GL_INTEGER_WIDTH (0, SIZE_MAX)\n# define WCHAR_WIDTH _GL_INTEGER_WIDTH (WCHAR_MIN, WCHAR_MAX)\n# ifdef WINT_MAX\n#  define WINT_WIDTH _GL_INTEGER_WIDTH (WINT_MIN, WINT_MAX)\n# endif\n# ifdef SIG_ATOMIC_MAX\n#  define SIG_ATOMIC_WIDTH _GL_INTEGER_WIDTH (SIG_ATOMIC_MIN, SIG_ATOMIC_MAX)\n# endif\n#endif /* !WINT_WIDTH && (_GNU_SOURCE || __STDC_WANT_IEC_60559_BFP_EXT__) */\n\n#endif /* _@GUARD_PREFIX@_STDINT_H */\n#endif /* !(defined __ANDROID__ && ...) */\n#endif /* !defined _@GUARD_PREFIX@_STDINT_H && !defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/stdio.in.h",
    "content": "/* A GNU-like <stdio.h>.\n\n   Copyright (C) 2004, 2007-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined __need_FILE || defined __need___FILE || defined _GL_ALREADY_INCLUDING_STDIO_H\n/* Special invocation convention:\n   - Inside glibc header files.\n   - On OSF/1 5.1 we have a sequence of nested includes\n     <stdio.h> -> <getopt.h> -> <ctype.h> -> <sys/localedef.h> ->\n     <sys/lc_core.h> -> <nl_types.h> -> <mesg.h> -> <stdio.h>.\n     In this situation, the functions are not yet declared, therefore we cannot\n     provide the C++ aliases.  */\n\n#@INCLUDE_NEXT@ @NEXT_STDIO_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_STDIO_H\n\n#define _GL_ALREADY_INCLUDING_STDIO_H\n\n/* The include_next requires a split double-inclusion guard.  */\n#@INCLUDE_NEXT@ @NEXT_STDIO_H@\n\n#undef _GL_ALREADY_INCLUDING_STDIO_H\n\n#ifndef _@GUARD_PREFIX@_STDIO_H\n#define _@GUARD_PREFIX@_STDIO_H\n\n/* Get va_list.  Needed on many systems, including glibc 2.8.  */\n#include <stdarg.h>\n\n#include <stddef.h>\n\n/* Get off_t and ssize_t.  Needed on many systems, including glibc 2.8\n   and eglibc 2.11.2.\n   May also define off_t to a 64-bit type on native Windows.  */\n#include <sys/types.h>\n\n/* Solaris 10 and NetBSD 7.0 declare renameat in <unistd.h>, not in <stdio.h>.  */\n/* But in any case avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && (defined __sun || defined __NetBSD__) \\\n    && ! defined __GLIBC__\n# include <unistd.h>\n#endif\n\n/* Android 4.3 declares renameat in <sys/stat.h>, not in <stdio.h>.  */\n/* But in any case avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \\\n    && ! defined __GLIBC__\n# include <sys/stat.h>\n#endif\n\n/* MSVC declares 'perror' in <stdlib.h>, not in <stdio.h>.  We must include\n   it before we  #define perror rpl_perror.  */\n/* But in any case avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_PERROR@ || defined GNULIB_POSIXCHECK) \\\n    && (defined _WIN32 && ! defined __CYGWIN__) \\\n    && ! defined __GLIBC__\n# include <stdlib.h>\n#endif\n\n/* MSVC declares 'remove' in <io.h>, not in <stdio.h>.  We must include\n   it before we  #define remove rpl_remove.  */\n/* MSVC declares 'rename' in <io.h>, not in <stdio.h>.  We must include\n   it before we  #define rename rpl_rename.  */\n/* But in any case avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_REMOVE@ || @GNULIB_RENAME@ || defined GNULIB_POSIXCHECK) \\\n    && (defined _WIN32 && ! defined __CYGWIN__) \\\n    && ! defined __GLIBC__\n# include <io.h>\n#endif\n\n\n/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers\n   that can be freed by passing them as the Ith argument to the\n   function F.  */\n#ifndef _GL_ATTRIBUTE_DEALLOC\n# if __GNUC__ >= 11\n#  define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))\n# else\n#  define _GL_ATTRIBUTE_DEALLOC(f, i)\n# endif\n#endif\n\n/* The __attribute__ feature is available in gcc versions 2.5 and later.\n   The __-protected variants of the attributes 'format' and 'printf' are\n   accepted by gcc versions 2.6.4 (effectively 2.7) and later.\n   We enable _GL_ATTRIBUTE_FORMAT only if these are supported too, because\n   gnulib and libintl do '#define printf __printf__' when they override\n   the 'printf' function.  */\n#ifndef _GL_ATTRIBUTE_FORMAT\n# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) || defined __clang__\n#  define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))\n# else\n#  define _GL_ATTRIBUTE_FORMAT(spec) /* empty */\n# endif\n#endif\n\n/* An __attribute__ __format__ specifier for a function that takes a format\n   string and arguments, where the format string directives are the ones\n   standardized by ISO C99 and POSIX.\n   _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD  */\n/* __gnu_printf__ is supported in GCC >= 4.4.  */\n#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)\n# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __gnu_printf__\n#else\n# define _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD __printf__\n#endif\n\n/* An __attribute__ __format__ specifier for a function that takes a format\n   string and arguments, where the format string directives are the ones of the\n   system printf(), rather than the ones standardized by ISO C99 and POSIX.\n   _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM  */\n/* On mingw, Gnulib sets __USE_MINGW_ANSI_STDIO in order to get closer to\n   the standards.  The macro GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU indicates\n   whether this change is effective.  On older mingw, it is not.  */\n#if GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU\n# define _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD\n#else\n# define _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM __printf__\n#endif\n\n/* _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD\n   indicates to GCC that the function takes a format string and arguments,\n   where the format string directives are the ones standardized by ISO C99\n   and POSIX.  */\n#define _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(formatstring_parameter, first_argument) \\\n  _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, formatstring_parameter, first_argument))\n\n/* _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM is like _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD,\n   except that it indicates to GCC that the supported format string directives\n   are the ones of the system printf(), rather than the ones standardized by\n   ISO C99 and POSIX.  */\n#define _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM(formatstring_parameter, first_argument) \\\n  _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM, formatstring_parameter, first_argument))\n\n/* _GL_ATTRIBUTE_FORMAT_SCANF\n   indicates to GCC that the function takes a format string and arguments,\n   where the format string directives are the ones standardized by ISO C99\n   and POSIX.  */\n#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)\n# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \\\n   _GL_ATTRIBUTE_FORMAT ((__gnu_scanf__, formatstring_parameter, first_argument))\n#else\n# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \\\n   _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument))\n#endif\n\n/* _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM is like _GL_ATTRIBUTE_FORMAT_SCANF,\n   except that it indicates to GCC that the supported format string directives\n   are the ones of the system scanf(), rather than the ones standardized by\n   ISO C99 and POSIX.  */\n#define _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM(formatstring_parameter, first_argument) \\\n  _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument))\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n/* Macros for stringification.  */\n#define _GL_STDIO_STRINGIZE(token) #token\n#define _GL_STDIO_MACROEXPAND_AND_STRINGIZE(token) _GL_STDIO_STRINGIZE(token)\n\n/* When also using extern inline, suppress the use of static inline in\n   standard headers of problematic Apple configurations, as Libc at\n   least through Libc-825.26 (2013-04-09) mishandles it; see, e.g.,\n   <https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html>.\n   Perhaps Apple will fix this some day.  */\n#if (defined _GL_EXTERN_INLINE_IN_USE && defined __APPLE__ \\\n     && defined __GNUC__ && defined __STDC__)\n# undef putc_unlocked\n#endif\n\n#if @GNULIB_DPRINTF@\n# if @REPLACE_DPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define dprintf rpl_dprintf\n#  endif\n_GL_FUNCDECL_RPL (dprintf, int, (int fd, const char *restrict format, ...)\n                                _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                                _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (dprintf, int, (int fd, const char *restrict format, ...));\n# else\n#  if !@HAVE_DPRINTF@\n_GL_FUNCDECL_SYS (dprintf, int, (int fd, const char *restrict format, ...)\n                                _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                                _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (dprintf, int, (int fd, const char *restrict format, ...));\n# endif\n_GL_CXXALIASWARN (dprintf);\n#elif defined GNULIB_POSIXCHECK\n# undef dprintf\n# if HAVE_RAW_DECL_DPRINTF\n_GL_WARN_ON_USE (dprintf, \"dprintf is unportable - \"\n                 \"use gnulib module dprintf for portability\");\n# endif\n#endif\n\n#if @GNULIB_FCLOSE@\n/* Close STREAM and its underlying file descriptor.  */\n# if @REPLACE_FCLOSE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define fclose rpl_fclose\n#  endif\n_GL_FUNCDECL_RPL (fclose, int, (FILE *stream) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (fclose, int, (FILE *stream));\n# else\n_GL_CXXALIAS_SYS (fclose, int, (FILE *stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fclose);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef fclose\n/* Assume fclose is always declared.  */\n_GL_WARN_ON_USE (fclose, \"fclose is not always POSIX compliant - \"\n                 \"use gnulib module fclose for portable POSIX compliance\");\n#endif\n\n#if @GNULIB_MDA_FCLOSEALL@\n/* On native Windows, map 'fcloseall' to '_fcloseall', so that -loldnames is\n   not required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::fcloseall on all platforms that have\n   it.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fcloseall\n#   define fcloseall _fcloseall\n#  endif\n_GL_CXXALIAS_MDA (fcloseall, int, (void));\n# else\n#  if @HAVE_DECL_FCLOSEALL@\n#   if defined __FreeBSD__ || defined __DragonFly__\n_GL_CXXALIAS_SYS (fcloseall, void, (void));\n#   else\n_GL_CXXALIAS_SYS (fcloseall, int, (void));\n#   endif\n#  endif\n# endif\n# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_DECL_FCLOSEALL@\n_GL_CXXALIASWARN (fcloseall);\n# endif\n#endif\n\n#if @GNULIB_FDOPEN@\n# if @REPLACE_FDOPEN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fdopen\n#   define fdopen rpl_fdopen\n#  endif\n_GL_FUNCDECL_RPL (fdopen, FILE *,\n                  (int fd, const char *mode)\n                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fdopen\n#   define fdopen _fdopen\n#  endif\n_GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (fdopen, FILE *,\n                  (int fd, const char *mode)\n                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n#  endif\n_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));\n# endif\n_GL_CXXALIASWARN (fdopen);\n#else\n# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fdopen\n/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (fdopen, FILE *,\n                  (int fd, const char *mode)\n                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef fdopen\n/* Assume fdopen is always declared.  */\n_GL_WARN_ON_USE (fdopen, \"fdopen on native Windows platforms is not POSIX compliant - \"\n                 \"use gnulib module fdopen for portability\");\n# elif @GNULIB_MDA_FDOPEN@\n/* On native Windows, map 'fdopen' to '_fdopen', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::fdopen always.  */\n#  if defined _WIN32 && !defined __CYGWIN__\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef fdopen\n#    define fdopen _fdopen\n#   endif\n_GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));\n#  else\n_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));\n#  endif\n_GL_CXXALIASWARN (fdopen);\n# endif\n#endif\n\n#if @GNULIB_FFLUSH@\n/* Flush all pending data on STREAM according to POSIX rules.  Both\n   output and seekable input streams are supported.\n   Note! LOSS OF DATA can occur if fflush is applied on an input stream\n   that is _not_seekable_ or on an update stream that is _not_seekable_\n   and in which the most recent operation was input.  Seekability can\n   be tested with lseek(fileno(fp),0,SEEK_CUR).  */\n# if @REPLACE_FFLUSH@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define fflush rpl_fflush\n#  endif\n_GL_FUNCDECL_RPL (fflush, int, (FILE *gl_stream));\n_GL_CXXALIAS_RPL (fflush, int, (FILE *gl_stream));\n# else\n_GL_CXXALIAS_SYS (fflush, int, (FILE *gl_stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fflush);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef fflush\n/* Assume fflush is always declared.  */\n_GL_WARN_ON_USE (fflush, \"fflush is not always POSIX compliant - \"\n                 \"use gnulib module fflush for portable POSIX compliance\");\n#endif\n\n#if @GNULIB_FGETC@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fgetc\n#   define fgetc rpl_fgetc\n#  endif\n_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (fgetc, int, (FILE *stream));\n# else\n_GL_CXXALIAS_SYS (fgetc, int, (FILE *stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fgetc);\n# endif\n#endif\n\n#if @GNULIB_FGETS@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fgets\n#   define fgets rpl_fgets\n#  endif\n_GL_FUNCDECL_RPL (fgets, char *,\n                  (char *restrict s, int n, FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 3)));\n_GL_CXXALIAS_RPL (fgets, char *,\n                  (char *restrict s, int n, FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (fgets, char *,\n                  (char *restrict s, int n, FILE *restrict stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fgets);\n# endif\n#endif\n\n#if @GNULIB_MDA_FILENO@\n/* On native Windows, map 'fileno' to '_fileno', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::fileno always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fileno\n#   define fileno _fileno\n#  endif\n_GL_CXXALIAS_MDA (fileno, int, (FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (fileno, int, (FILE *restrict stream));\n# endif\n_GL_CXXALIASWARN (fileno);\n#endif\n\n#if @GNULIB_FOPEN@\n# if @REPLACE_FOPEN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fopen\n#   define fopen rpl_fopen\n#  endif\n_GL_FUNCDECL_RPL (fopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n_GL_CXXALIAS_RPL (fopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (fopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n#  endif\n_GL_CXXALIAS_SYS (fopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fopen);\n# endif\n#else\n# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fopen\n/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (fopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef fopen\n/* Assume fopen is always declared.  */\n_GL_WARN_ON_USE (fopen, \"fopen on native Windows platforms is not POSIX compliant - \"\n                 \"use gnulib module fopen for portability\");\n# endif\n#endif\n\n#if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@\n# if (@GNULIB_FPRINTF_POSIX@ && @REPLACE_FPRINTF@) \\\n     || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define fprintf rpl_fprintf\n#  endif\n#  define GNULIB_overrides_fprintf 1\n#  if @GNULIB_FPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@\n_GL_FUNCDECL_RPL (fprintf, int,\n                  (FILE *restrict fp, const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  else\n_GL_FUNCDECL_RPL (fprintf, int,\n                  (FILE *restrict fp, const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_RPL (fprintf, int,\n                  (FILE *restrict fp, const char *restrict format, ...));\n# else\n_GL_CXXALIAS_SYS (fprintf, int,\n                  (FILE *restrict fp, const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fprintf);\n# endif\n#endif\n#if !@GNULIB_FPRINTF_POSIX@ && defined GNULIB_POSIXCHECK\n# if !GNULIB_overrides_fprintf\n#  undef fprintf\n# endif\n/* Assume fprintf is always declared.  */\n_GL_WARN_ON_USE (fprintf, \"fprintf is not always POSIX compliant - \"\n                 \"use gnulib module fprintf-posix for portable \"\n                 \"POSIX compliance\");\n#endif\n\n#if @GNULIB_FPURGE@\n/* Discard all pending buffered I/O data on STREAM.\n   STREAM must not be wide-character oriented.\n   When discarding pending output, the file position is set back to where it\n   was before the write calls.  When discarding pending input, the file\n   position is advanced to match the end of the previously read input.\n   Return 0 if successful.  Upon error, return -1 and set errno.  */\n# if @REPLACE_FPURGE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define fpurge rpl_fpurge\n#  endif\n_GL_FUNCDECL_RPL (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (fpurge, int, (FILE *gl_stream));\n# else\n#  if !@HAVE_DECL_FPURGE@\n_GL_FUNCDECL_SYS (fpurge, int, (FILE *gl_stream) _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (fpurge, int, (FILE *gl_stream));\n# endif\n_GL_CXXALIASWARN (fpurge);\n#elif defined GNULIB_POSIXCHECK\n# undef fpurge\n# if HAVE_RAW_DECL_FPURGE\n_GL_WARN_ON_USE (fpurge, \"fpurge is not always present - \"\n                 \"use gnulib module fpurge for portability\");\n# endif\n#endif\n\n#if @GNULIB_FPUTC@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fputc\n#   define fputc rpl_fputc\n#  endif\n_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (fputc, int, (int c, FILE *stream));\n# else\n_GL_CXXALIAS_SYS (fputc, int, (int c, FILE *stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fputc);\n# endif\n#endif\n\n#if @GNULIB_FPUTS@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fputs\n#   define fputs rpl_fputs\n#  endif\n_GL_FUNCDECL_RPL (fputs, int,\n                  (const char *restrict string, FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (fputs, int,\n                  (const char *restrict string, FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (fputs, int,\n                  (const char *restrict string, FILE *restrict stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fputs);\n# endif\n#endif\n\n#if @GNULIB_FREAD@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fread\n#   define fread rpl_fread\n#  endif\n_GL_FUNCDECL_RPL (fread, size_t,\n                  (void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((4)));\n_GL_CXXALIAS_RPL (fread, size_t,\n                  (void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (fread, size_t,\n                  (void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fread);\n# endif\n#endif\n\n#if @GNULIB_FREOPEN@\n# if @REPLACE_FREOPEN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef freopen\n#   define freopen rpl_freopen\n#  endif\n_GL_FUNCDECL_RPL (freopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_RPL (freopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode,\n                   FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (freopen, FILE *,\n                  (const char *restrict filename, const char *restrict mode,\n                   FILE *restrict stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (freopen);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef freopen\n/* Assume freopen is always declared.  */\n_GL_WARN_ON_USE (freopen,\n                 \"freopen on native Windows platforms is not POSIX compliant - \"\n                 \"use gnulib module freopen for portability\");\n#endif\n\n#if @GNULIB_FSCANF@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fscanf\n#   define fscanf rpl_fscanf\n#  endif\n_GL_FUNCDECL_RPL (fscanf, int,\n                  (FILE *restrict stream, const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (fscanf, int,\n                  (FILE *restrict stream, const char *restrict format, ...));\n# else\n_GL_CXXALIAS_SYS (fscanf, int,\n                  (FILE *restrict stream, const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fscanf);\n# endif\n#endif\n\n\n/* Set up the following warnings, based on which modules are in use.\n   GNU Coding Standards discourage the use of fseek, since it imposes\n   an arbitrary limitation on some 32-bit hosts.  Remember that the\n   fseek module depends on the fseeko module, so we only have three\n   cases to consider:\n\n   1. The developer is not using either module.  Issue a warning under\n   GNULIB_POSIXCHECK for both functions, to remind them that both\n   functions have bugs on some systems.  _GL_NO_LARGE_FILES has no\n   impact on this warning.\n\n   2. The developer is using both modules.  They may be unaware of the\n   arbitrary limitations of fseek, so issue a warning under\n   GNULIB_POSIXCHECK.  On the other hand, they may be using both\n   modules intentionally, so the developer can define\n   _GL_NO_LARGE_FILES in the compilation units where the use of fseek\n   is safe, to silence the warning.\n\n   3. The developer is using the fseeko module, but not fseek.  Gnulib\n   guarantees that fseek will still work around platform bugs in that\n   case, but we presume that the developer is aware of the pitfalls of\n   fseek and was trying to avoid it, so issue a warning even when\n   GNULIB_POSIXCHECK is undefined.  Again, _GL_NO_LARGE_FILES can be\n   defined to silence the warning in particular compilation units.\n   In C++ compilations with GNULIB_NAMESPACE, in order to avoid that\n   fseek gets defined as a macro, it is recommended that the developer\n   uses the fseek module, even if he is not calling the fseek function.\n\n   Most gnulib clients that perform stream operations should fall into\n   category 3.  */\n\n#if @GNULIB_FSEEK@\n# if defined GNULIB_POSIXCHECK && !defined _GL_NO_LARGE_FILES\n#  define _GL_FSEEK_WARN /* Category 2, above.  */\n#  undef fseek\n# endif\n# if @REPLACE_FSEEK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fseek\n#   define fseek rpl_fseek\n#  endif\n_GL_FUNCDECL_RPL (fseek, int, (FILE *fp, long offset, int whence)\n                              _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (fseek, int, (FILE *fp, long offset, int whence));\n# else\n_GL_CXXALIAS_SYS (fseek, int, (FILE *fp, long offset, int whence));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fseek);\n# endif\n#endif\n\n#if @GNULIB_FSEEKO@\n# if !@GNULIB_FSEEK@ && !defined _GL_NO_LARGE_FILES\n#  define _GL_FSEEK_WARN /* Category 3, above.  */\n#  undef fseek\n# endif\n# if @REPLACE_FSEEKO@\n/* Provide an fseeko function that is aware of a preceding fflush(), and which\n   detects pipes.  */\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fseeko\n#   define fseeko rpl_fseeko\n#  endif\n_GL_FUNCDECL_RPL (fseeko, int, (FILE *fp, off_t offset, int whence)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (fseeko, int, (FILE *fp, off_t offset, int whence));\n# else\n#  if ! @HAVE_DECL_FSEEKO@\n_GL_FUNCDECL_SYS (fseeko, int, (FILE *fp, off_t offset, int whence)\n                               _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (fseeko, int, (FILE *fp, off_t offset, int whence));\n# endif\n_GL_CXXALIASWARN (fseeko);\n#elif defined GNULIB_POSIXCHECK\n# define _GL_FSEEK_WARN /* Category 1, above.  */\n# undef fseek\n# undef fseeko\n# if HAVE_RAW_DECL_FSEEKO\n_GL_WARN_ON_USE (fseeko, \"fseeko is unportable - \"\n                 \"use gnulib module fseeko for portability\");\n# endif\n#endif\n\n#ifdef _GL_FSEEK_WARN\n# undef _GL_FSEEK_WARN\n/* Here, either fseek is undefined (but C89 guarantees that it is\n   declared), or it is defined as rpl_fseek (declared above).  */\n_GL_WARN_ON_USE (fseek, \"fseek cannot handle files larger than 4 GB \"\n                 \"on 32-bit platforms - \"\n                 \"use fseeko function for handling of large files\");\n#endif\n\n\n/* ftell, ftello.  See the comments on fseek/fseeko.  */\n\n#if @GNULIB_FTELL@\n# if defined GNULIB_POSIXCHECK && !defined _GL_NO_LARGE_FILES\n#  define _GL_FTELL_WARN /* Category 2, above.  */\n#  undef ftell\n# endif\n# if @REPLACE_FTELL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ftell\n#   define ftell rpl_ftell\n#  endif\n_GL_FUNCDECL_RPL (ftell, long, (FILE *fp) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (ftell, long, (FILE *fp));\n# else\n_GL_CXXALIAS_SYS (ftell, long, (FILE *fp));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (ftell);\n# endif\n#endif\n\n#if @GNULIB_FTELLO@\n# if !@GNULIB_FTELL@ && !defined _GL_NO_LARGE_FILES\n#  define _GL_FTELL_WARN /* Category 3, above.  */\n#  undef ftell\n# endif\n# if @REPLACE_FTELLO@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ftello\n#   define ftello rpl_ftello\n#  endif\n_GL_FUNCDECL_RPL (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (ftello, off_t, (FILE *fp));\n# else\n#  if ! @HAVE_DECL_FTELLO@\n_GL_FUNCDECL_SYS (ftello, off_t, (FILE *fp) _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (ftello, off_t, (FILE *fp));\n# endif\n_GL_CXXALIASWARN (ftello);\n#elif defined GNULIB_POSIXCHECK\n# define _GL_FTELL_WARN /* Category 1, above.  */\n# undef ftell\n# undef ftello\n# if HAVE_RAW_DECL_FTELLO\n_GL_WARN_ON_USE (ftello, \"ftello is unportable - \"\n                 \"use gnulib module ftello for portability\");\n# endif\n#endif\n\n#ifdef _GL_FTELL_WARN\n# undef _GL_FTELL_WARN\n/* Here, either ftell is undefined (but C89 guarantees that it is\n   declared), or it is defined as rpl_ftell (declared above).  */\n_GL_WARN_ON_USE (ftell, \"ftell cannot handle files larger than 4 GB \"\n                 \"on 32-bit platforms - \"\n                 \"use ftello function for handling of large files\");\n#endif\n\n\n#if @GNULIB_FWRITE@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fwrite\n#   define fwrite rpl_fwrite\n#  endif\n_GL_FUNCDECL_RPL (fwrite, size_t,\n                  (const void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 4)));\n_GL_CXXALIAS_RPL (fwrite, size_t,\n                  (const void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (fwrite, size_t,\n                  (const void *restrict ptr, size_t s, size_t n,\n                   FILE *restrict stream));\n\n/* Work around bug 11959 when fortifying glibc 2.4 through 2.15\n   <https://sourceware.org/bugzilla/show_bug.cgi?id=11959>,\n   which sometimes causes an unwanted diagnostic for fwrite calls.\n   This affects only function declaration attributes under certain\n   versions of gcc and clang, and is not needed for C++.  */\n#  if (0 < __USE_FORTIFY_LEVEL                                          \\\n       && __GLIBC__ == 2 && 4 <= __GLIBC_MINOR__ && __GLIBC_MINOR__ <= 15 \\\n       && 3 < __GNUC__ + (4 <= __GNUC_MINOR__)                          \\\n       && !defined __cplusplus)\n#   undef fwrite\n#   undef fwrite_unlocked\nextern size_t __REDIRECT (rpl_fwrite,\n                          (const void *__restrict, size_t, size_t,\n                           FILE *__restrict),\n                          fwrite);\nextern size_t __REDIRECT (rpl_fwrite_unlocked,\n                          (const void *__restrict, size_t, size_t,\n                           FILE *__restrict),\n                          fwrite_unlocked);\n#   define fwrite rpl_fwrite\n#   define fwrite_unlocked rpl_fwrite_unlocked\n#  endif\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fwrite);\n# endif\n#endif\n\n#if @GNULIB_GETC@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getc\n#   define getc rpl_fgetc\n#  endif\n_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL_1 (getc, rpl_fgetc, int, (FILE *stream));\n# else\n_GL_CXXALIAS_SYS (getc, int, (FILE *stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (getc);\n# endif\n#endif\n\n#if @GNULIB_GETCHAR@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getchar\n#   define getchar rpl_getchar\n#  endif\n_GL_FUNCDECL_RPL (getchar, int, (void));\n_GL_CXXALIAS_RPL (getchar, int, (void));\n# else\n_GL_CXXALIAS_SYS (getchar, int, (void));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (getchar);\n# endif\n#endif\n\n#if @GNULIB_GETDELIM@\n/* Read input, up to (and including) the next occurrence of DELIMITER, from\n   STREAM, store it in *LINEPTR (and NUL-terminate it).\n   *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE\n   bytes of space.  It is realloc'd as necessary.\n   Return the number of bytes read and stored at *LINEPTR (not including the\n   NUL terminator), or -1 on error or EOF.  */\n# if @REPLACE_GETDELIM@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getdelim\n#   define getdelim rpl_getdelim\n#  endif\n_GL_FUNCDECL_RPL (getdelim, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   int delimiter,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 2, 4)));\n_GL_CXXALIAS_RPL (getdelim, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   int delimiter,\n                   FILE *restrict stream));\n# else\n#  if !@HAVE_DECL_GETDELIM@\n_GL_FUNCDECL_SYS (getdelim, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   int delimiter,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 2, 4)));\n#  endif\n_GL_CXXALIAS_SYS (getdelim, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   int delimiter,\n                   FILE *restrict stream));\n# endif\n_GL_CXXALIASWARN (getdelim);\n#elif defined GNULIB_POSIXCHECK\n# undef getdelim\n# if HAVE_RAW_DECL_GETDELIM\n_GL_WARN_ON_USE (getdelim, \"getdelim is unportable - \"\n                 \"use gnulib module getdelim for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETLINE@\n/* Read a line, up to (and including) the next newline, from STREAM, store it\n   in *LINEPTR (and NUL-terminate it).\n   *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE\n   bytes of space.  It is realloc'd as necessary.\n   Return the number of bytes read and stored at *LINEPTR (not including the\n   NUL terminator), or -1 on error or EOF.  */\n# if @REPLACE_GETLINE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getline\n#   define getline rpl_getline\n#  endif\n_GL_FUNCDECL_RPL (getline, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 2, 3)));\n_GL_CXXALIAS_RPL (getline, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   FILE *restrict stream));\n# else\n#  if !@HAVE_DECL_GETLINE@\n_GL_FUNCDECL_SYS (getline, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   FILE *restrict stream)\n                  _GL_ARG_NONNULL ((1, 2, 3)));\n#  endif\n_GL_CXXALIAS_SYS (getline, ssize_t,\n                  (char **restrict lineptr, size_t *restrict linesize,\n                   FILE *restrict stream));\n# endif\n# if @HAVE_DECL_GETLINE@\n_GL_CXXALIASWARN (getline);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef getline\n# if HAVE_RAW_DECL_GETLINE\n_GL_WARN_ON_USE (getline, \"getline is unportable - \"\n                 \"use gnulib module getline for portability\");\n# endif\n#endif\n\n/* It is very rare that the developer ever has full control of stdin,\n   so any use of gets warrants an unconditional warning; besides, C11\n   removed it.  */\n#undef gets\n#if HAVE_RAW_DECL_GETS && !defined __cplusplus\n_GL_WARN_ON_USE (gets, \"gets is a security hole - use fgets instead\");\n#endif\n\n#if @GNULIB_MDA_GETW@\n/* On native Windows, map 'getw' to '_getw', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::getw always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getw\n#   define getw _getw\n#  endif\n_GL_CXXALIAS_MDA (getw, int, (FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream));\n# endif\n_GL_CXXALIASWARN (getw);\n#endif\n\n#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@\nstruct obstack;\n/* Grow an obstack with formatted output.  Return the number of\n   bytes added to OBS.  No trailing nul byte is added, and the\n   object should be closed with obstack_finish before use.  Upon\n   memory allocation error, call obstack_alloc_failed_handler.  Upon\n   other error, return -1.  */\n# if @REPLACE_OBSTACK_PRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define obstack_printf rpl_obstack_printf\n#  endif\n_GL_FUNCDECL_RPL (obstack_printf, int,\n                  (struct obstack *obs, const char *format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (obstack_printf, int,\n                  (struct obstack *obs, const char *format, ...));\n# else\n#  if !@HAVE_DECL_OBSTACK_PRINTF@\n_GL_FUNCDECL_SYS (obstack_printf, int,\n                  (struct obstack *obs, const char *format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (obstack_printf, int,\n                  (struct obstack *obs, const char *format, ...));\n# endif\n_GL_CXXALIASWARN (obstack_printf);\n# if @REPLACE_OBSTACK_PRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define obstack_vprintf rpl_obstack_vprintf\n#  endif\n_GL_FUNCDECL_RPL (obstack_vprintf, int,\n                  (struct obstack *obs, const char *format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (obstack_vprintf, int,\n                  (struct obstack *obs, const char *format, va_list args));\n# else\n#  if !@HAVE_DECL_OBSTACK_PRINTF@\n_GL_FUNCDECL_SYS (obstack_vprintf, int,\n                  (struct obstack *obs, const char *format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (obstack_vprintf, int,\n                  (struct obstack *obs, const char *format, va_list args));\n# endif\n_GL_CXXALIASWARN (obstack_vprintf);\n#endif\n\n#if @GNULIB_PCLOSE@\n# if !@HAVE_PCLOSE@\n_GL_FUNCDECL_SYS (pclose, int, (FILE *stream) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (pclose, int, (FILE *stream));\n_GL_CXXALIASWARN (pclose);\n#elif defined GNULIB_POSIXCHECK\n# undef pclose\n# if HAVE_RAW_DECL_PCLOSE\n_GL_WARN_ON_USE (pclose, \"pclose is unportable - \"\n                 \"use gnulib module pclose for more portability\");\n# endif\n#endif\n\n#if @GNULIB_PERROR@\n/* Print a message to standard error, describing the value of ERRNO,\n   (if STRING is not NULL and not empty) prefixed with STRING and \": \",\n   and terminated with a newline.  */\n# if @REPLACE_PERROR@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define perror rpl_perror\n#  endif\n_GL_FUNCDECL_RPL (perror, void, (const char *string));\n_GL_CXXALIAS_RPL (perror, void, (const char *string));\n# else\n_GL_CXXALIAS_SYS (perror, void, (const char *string));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (perror);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef perror\n/* Assume perror is always declared.  */\n_GL_WARN_ON_USE (perror, \"perror is not always POSIX compliant - \"\n                 \"use gnulib module perror for portability\");\n#endif\n\n#if @GNULIB_POPEN@\n# if @REPLACE_POPEN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef popen\n#   define popen rpl_popen\n#  endif\n_GL_FUNCDECL_RPL (popen, FILE *,\n                  (const char *cmd, const char *mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));\n_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode));\n# else\n#  if !@HAVE_POPEN@ || __GNUC__ >= 11\n_GL_FUNCDECL_SYS (popen, FILE *,\n                  (const char *cmd, const char *mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));\n#  endif\n_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode));\n# endif\n_GL_CXXALIASWARN (popen);\n#else\n# if @GNULIB_PCLOSE@ && __GNUC__ >= 11 && !defined popen\n/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose.  */\n_GL_FUNCDECL_SYS (popen, FILE *,\n                  (const char *cmd, const char *mode)\n                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef popen\n#  if HAVE_RAW_DECL_POPEN\n_GL_WARN_ON_USE (popen, \"popen is buggy on some platforms - \"\n                 \"use gnulib module popen or pipe for more portability\");\n#  endif\n# endif\n#endif\n\n#if @GNULIB_PRINTF_POSIX@ || @GNULIB_PRINTF@\n# if (@GNULIB_PRINTF_POSIX@ && @REPLACE_PRINTF@) \\\n     || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))\n#  if defined __GNUC__ || defined __clang__\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n/* Don't break __attribute__((format(printf,M,N))).  */\n#    define printf __printf__\n#   endif\n#   if @GNULIB_PRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@\n_GL_FUNCDECL_RPL_1 (__printf__, int,\n                    (const char *restrict format, ...)\n                    __asm__ (@ASM_SYMBOL_PREFIX@\n                             _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf))\n                    _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)\n                    _GL_ARG_NONNULL ((1)));\n#   else\n_GL_FUNCDECL_RPL_1 (__printf__, int,\n                    (const char *restrict format, ...)\n                    __asm__ (@ASM_SYMBOL_PREFIX@\n                             _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_printf))\n                    _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 2)\n                    _GL_ARG_NONNULL ((1)));\n#   endif\n_GL_CXXALIAS_RPL_1 (printf, __printf__, int, (const char *format, ...));\n#  else\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    define printf rpl_printf\n#   endif\n_GL_FUNCDECL_RPL (printf, int,\n                  (const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (printf, int, (const char *restrict format, ...));\n#  endif\n#  define GNULIB_overrides_printf 1\n# else\n_GL_CXXALIAS_SYS (printf, int, (const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (printf);\n# endif\n#endif\n#if !@GNULIB_PRINTF_POSIX@ && defined GNULIB_POSIXCHECK\n# if !GNULIB_overrides_printf\n#  undef printf\n# endif\n/* Assume printf is always declared.  */\n_GL_WARN_ON_USE (printf, \"printf is not always POSIX compliant - \"\n                 \"use gnulib module printf-posix for portable \"\n                 \"POSIX compliance\");\n#endif\n\n#if @GNULIB_PUTC@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putc\n#   define putc rpl_fputc\n#  endif\n_GL_FUNCDECL_RPL (fputc, int, (int c, FILE *stream) _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL_1 (putc, rpl_fputc, int, (int c, FILE *stream));\n# else\n_GL_CXXALIAS_SYS (putc, int, (int c, FILE *stream));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (putc);\n# endif\n#endif\n\n#if @GNULIB_PUTCHAR@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putchar\n#   define putchar rpl_putchar\n#  endif\n_GL_FUNCDECL_RPL (putchar, int, (int c));\n_GL_CXXALIAS_RPL (putchar, int, (int c));\n# else\n_GL_CXXALIAS_SYS (putchar, int, (int c));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (putchar);\n# endif\n#endif\n\n#if @GNULIB_PUTS@\n# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef puts\n#   define puts rpl_puts\n#  endif\n_GL_FUNCDECL_RPL (puts, int, (const char *string) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (puts, int, (const char *string));\n# else\n_GL_CXXALIAS_SYS (puts, int, (const char *string));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (puts);\n# endif\n#endif\n\n#if @GNULIB_MDA_PUTW@\n/* On native Windows, map 'putw' to '_putw', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::putw always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putw\n#   define putw _putw\n#  endif\n_GL_CXXALIAS_MDA (putw, int, (int w, FILE *restrict stream));\n# else\n_GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream));\n# endif\n_GL_CXXALIASWARN (putw);\n#endif\n\n#if @GNULIB_REMOVE@\n# if @REPLACE_REMOVE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef remove\n#   define remove rpl_remove\n#  endif\n_GL_FUNCDECL_RPL (remove, int, (const char *name) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (remove, int, (const char *name));\n# else\n_GL_CXXALIAS_SYS (remove, int, (const char *name));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (remove);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef remove\n/* Assume remove is always declared.  */\n_GL_WARN_ON_USE (remove, \"remove cannot handle directories on some platforms - \"\n                 \"use gnulib module remove for more portability\");\n#endif\n\n#if @GNULIB_RENAME@\n# if @REPLACE_RENAME@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef rename\n#   define rename rpl_rename\n#  endif\n_GL_FUNCDECL_RPL (rename, int,\n                  (const char *old_filename, const char *new_filename)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (rename, int,\n                  (const char *old_filename, const char *new_filename));\n# else\n_GL_CXXALIAS_SYS (rename, int,\n                  (const char *old_filename, const char *new_filename));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (rename);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef rename\n/* Assume rename is always declared.  */\n_GL_WARN_ON_USE (rename, \"rename is buggy on some platforms - \"\n                 \"use gnulib module rename for more portability\");\n#endif\n\n#if @GNULIB_RENAMEAT@\n# if @REPLACE_RENAMEAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef renameat\n#   define renameat rpl_renameat\n#  endif\n_GL_FUNCDECL_RPL (renameat, int,\n                  (int fd1, char const *file1, int fd2, char const *file2)\n                  _GL_ARG_NONNULL ((2, 4)));\n_GL_CXXALIAS_RPL (renameat, int,\n                  (int fd1, char const *file1, int fd2, char const *file2));\n# else\n#  if !@HAVE_RENAMEAT@\n_GL_FUNCDECL_SYS (renameat, int,\n                  (int fd1, char const *file1, int fd2, char const *file2)\n                  _GL_ARG_NONNULL ((2, 4)));\n#  endif\n_GL_CXXALIAS_SYS (renameat, int,\n                  (int fd1, char const *file1, int fd2, char const *file2));\n# endif\n_GL_CXXALIASWARN (renameat);\n#elif defined GNULIB_POSIXCHECK\n# undef renameat\n# if HAVE_RAW_DECL_RENAMEAT\n_GL_WARN_ON_USE (renameat, \"renameat is not portable - \"\n                 \"use gnulib module renameat for portability\");\n# endif\n#endif\n\n#if @GNULIB_SCANF@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if defined __GNUC__ || defined __clang__\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef scanf\n/* Don't break __attribute__((format(scanf,M,N))).  */\n#    define scanf __scanf__\n#   endif\n_GL_FUNCDECL_RPL_1 (__scanf__, int,\n                    (const char *restrict format, ...)\n                    __asm__ (@ASM_SYMBOL_PREFIX@\n                             _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_scanf))\n                    _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)\n                    _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL_1 (scanf, __scanf__, int, (const char *restrict format, ...));\n#  else\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef scanf\n#    define scanf rpl_scanf\n#   endif\n_GL_FUNCDECL_RPL (scanf, int, (const char *restrict format, ...)\n                              _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)\n                              _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (scanf, int, (const char *restrict format, ...));\n#  endif\n# else\n_GL_CXXALIAS_SYS (scanf, int, (const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (scanf);\n# endif\n#endif\n\n#if @GNULIB_SNPRINTF@\n# if @REPLACE_SNPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define snprintf rpl_snprintf\n#  endif\n#  define GNULIB_overrides_snprintf 1\n_GL_FUNCDECL_RPL (snprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)\n                  _GL_ARG_NONNULL ((3)));\n_GL_CXXALIAS_RPL (snprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, ...));\n# else\n#  if !@HAVE_DECL_SNPRINTF@\n_GL_FUNCDECL_SYS (snprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)\n                  _GL_ARG_NONNULL ((3)));\n#  endif\n_GL_CXXALIAS_SYS (snprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (snprintf);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef snprintf\n# if HAVE_RAW_DECL_SNPRINTF\n_GL_WARN_ON_USE (snprintf, \"snprintf is unportable - \"\n                 \"use gnulib module snprintf for portability\");\n# endif\n#endif\n\n/* Some people would argue that all sprintf uses should be warned about\n   (for example, OpenBSD issues a link warning for it),\n   since it can cause security holes due to buffer overruns.\n   However, we believe that sprintf can be used safely, and is more\n   efficient than snprintf in those safe cases; and as proof of our\n   belief, we use sprintf in several gnulib modules.  So this header\n   intentionally avoids adding a warning to sprintf except when\n   GNULIB_POSIXCHECK is defined.  */\n\n#if @GNULIB_SPRINTF_POSIX@\n# if @REPLACE_SPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define sprintf rpl_sprintf\n#  endif\n#  define GNULIB_overrides_sprintf 1\n_GL_FUNCDECL_RPL (sprintf, int,\n                  (char *restrict str, const char *restrict format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (sprintf, int,\n                  (char *restrict str, const char *restrict format, ...));\n# else\n_GL_CXXALIAS_SYS (sprintf, int,\n                  (char *restrict str, const char *restrict format, ...));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (sprintf);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef sprintf\n/* Assume sprintf is always declared.  */\n_GL_WARN_ON_USE (sprintf, \"sprintf is not always POSIX compliant - \"\n                 \"use gnulib module sprintf-posix for portable \"\n                 \"POSIX compliance\");\n#endif\n\n#if @GNULIB_MDA_TEMPNAM@\n/* On native Windows, map 'tempnam' to '_tempnam', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::tempnam always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef tempnam\n#   define tempnam _tempnam\n#  endif\n_GL_CXXALIAS_MDA (tempnam, char *, (const char *dir, const char *prefix));\n# else\n_GL_CXXALIAS_SYS (tempnam, char *, (const char *dir, const char *prefix));\n# endif\n_GL_CXXALIASWARN (tempnam);\n#endif\n\n#if @GNULIB_TMPFILE@\n# if @REPLACE_TMPFILE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define tmpfile rpl_tmpfile\n#  endif\n_GL_FUNCDECL_RPL (tmpfile, FILE *, (void)\n                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n_GL_CXXALIAS_RPL (tmpfile, FILE *, (void));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)\n                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n#  endif\n_GL_CXXALIAS_SYS (tmpfile, FILE *, (void));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (tmpfile);\n# endif\n#else\n# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined tmpfile\n/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose.  */\n_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)\n                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef tmpfile\n#  if HAVE_RAW_DECL_TMPFILE\n_GL_WARN_ON_USE (tmpfile, \"tmpfile is not usable on mingw - \"\n                 \"use gnulib module tmpfile for portability\");\n#  endif\n# endif\n#endif\n\n#if @GNULIB_VASPRINTF@\n/* Write formatted output to a string dynamically allocated with malloc().\n   If the memory allocation succeeds, store the address of the string in\n   *RESULT and return the number of resulting bytes, excluding the trailing\n   NUL.  Upon memory allocation error, or some other error, return -1.  */\n# if @REPLACE_VASPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define asprintf rpl_asprintf\n#  endif\n#  define GNULIB_overrides_asprintf\n_GL_FUNCDECL_RPL (asprintf, int,\n                  (char **result, const char *format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (asprintf, int,\n                  (char **result, const char *format, ...));\n# else\n#  if !@HAVE_VASPRINTF@\n_GL_FUNCDECL_SYS (asprintf, int,\n                  (char **result, const char *format, ...)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (asprintf, int,\n                  (char **result, const char *format, ...));\n# endif\n_GL_CXXALIASWARN (asprintf);\n# if @REPLACE_VASPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vasprintf rpl_vasprintf\n#  endif\n#  define GNULIB_overrides_vasprintf 1\n_GL_FUNCDECL_RPL (vasprintf, int,\n                  (char **result, const char *format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (vasprintf, int,\n                  (char **result, const char *format, va_list args));\n# else\n#  if !@HAVE_VASPRINTF@\n_GL_FUNCDECL_SYS (vasprintf, int,\n                  (char **result, const char *format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (vasprintf, int,\n                  (char **result, const char *format, va_list args));\n# endif\n_GL_CXXALIASWARN (vasprintf);\n#endif\n\n#if @GNULIB_VDPRINTF@\n# if @REPLACE_VDPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vdprintf rpl_vdprintf\n#  endif\n_GL_FUNCDECL_RPL (vdprintf, int,\n                  (int fd, const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (vdprintf, int,\n                  (int fd, const char *restrict format, va_list args));\n# else\n#  if !@HAVE_VDPRINTF@\n_GL_FUNCDECL_SYS (vdprintf, int,\n                  (int fd, const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n/* Need to cast, because on Solaris, the third parameter will likely be\n                                                    __va_list args.  */\n_GL_CXXALIAS_SYS_CAST (vdprintf, int,\n                       (int fd, const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vdprintf);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef vdprintf\n# if HAVE_RAW_DECL_VDPRINTF\n_GL_WARN_ON_USE (vdprintf, \"vdprintf is unportable - \"\n                 \"use gnulib module vdprintf for portability\");\n# endif\n#endif\n\n#if @GNULIB_VFPRINTF_POSIX@ || @GNULIB_VFPRINTF@\n# if (@GNULIB_VFPRINTF_POSIX@ && @REPLACE_VFPRINTF@) \\\n     || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vfprintf rpl_vfprintf\n#  endif\n#  define GNULIB_overrides_vfprintf 1\n#  if @GNULIB_VFPRINTF_POSIX@\n_GL_FUNCDECL_RPL (vfprintf, int,\n                  (FILE *restrict fp,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  else\n_GL_FUNCDECL_RPL (vfprintf, int,\n                  (FILE *restrict fp,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_RPL (vfprintf, int,\n                  (FILE *restrict fp,\n                   const char *restrict format, va_list args));\n# else\n/* Need to cast, because on Solaris, the third parameter is\n                                                      __va_list args\n   and GCC's fixincludes did not change this to __gnuc_va_list.  */\n_GL_CXXALIAS_SYS_CAST (vfprintf, int,\n                       (FILE *restrict fp,\n                        const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vfprintf);\n# endif\n#endif\n#if !@GNULIB_VFPRINTF_POSIX@ && defined GNULIB_POSIXCHECK\n# if !GNULIB_overrides_vfprintf\n#  undef vfprintf\n# endif\n/* Assume vfprintf is always declared.  */\n_GL_WARN_ON_USE (vfprintf, \"vfprintf is not always POSIX compliant - \"\n                 \"use gnulib module vfprintf-posix for portable \"\n                      \"POSIX compliance\");\n#endif\n\n#if @GNULIB_VFSCANF@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef vfscanf\n#   define vfscanf rpl_vfscanf\n#  endif\n_GL_FUNCDECL_RPL (vfscanf, int,\n                  (FILE *restrict stream,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (vfscanf, int,\n                  (FILE *restrict stream,\n                   const char *restrict format, va_list args));\n# else\n_GL_CXXALIAS_SYS (vfscanf, int,\n                  (FILE *restrict stream,\n                   const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vfscanf);\n# endif\n#endif\n\n#if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@\n# if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \\\n     || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vprintf rpl_vprintf\n#  endif\n#  define GNULIB_overrides_vprintf 1\n#  if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VFPRINTF_POSIX@\n_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args)\n                                _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)\n                                _GL_ARG_NONNULL ((1)));\n#  else\n_GL_FUNCDECL_RPL (vprintf, int, (const char *restrict format, va_list args)\n                                _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM (1, 0)\n                                _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_RPL (vprintf, int, (const char *restrict format, va_list args));\n# else\n/* Need to cast, because on Solaris, the second parameter is\n                                                          __va_list args\n   and GCC's fixincludes did not change this to __gnuc_va_list.  */\n_GL_CXXALIAS_SYS_CAST (vprintf, int,\n                       (const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vprintf);\n# endif\n#endif\n#if !@GNULIB_VPRINTF_POSIX@ && defined GNULIB_POSIXCHECK\n# if !GNULIB_overrides_vprintf\n#  undef vprintf\n# endif\n/* Assume vprintf is always declared.  */\n_GL_WARN_ON_USE (vprintf, \"vprintf is not always POSIX compliant - \"\n                 \"use gnulib module vprintf-posix for portable \"\n                 \"POSIX compliance\");\n#endif\n\n#if @GNULIB_VSCANF@\n# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef vscanf\n#   define vscanf rpl_vscanf\n#  endif\n_GL_FUNCDECL_RPL (vscanf, int, (const char *restrict format, va_list args)\n                               _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 0)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (vscanf, int, (const char *restrict format, va_list args));\n# else\n_GL_CXXALIAS_SYS (vscanf, int, (const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vscanf);\n# endif\n#endif\n\n#if @GNULIB_VSNPRINTF@\n# if @REPLACE_VSNPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vsnprintf rpl_vsnprintf\n#  endif\n#  define GNULIB_overrides_vsnprintf 1\n_GL_FUNCDECL_RPL (vsnprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)\n                  _GL_ARG_NONNULL ((3)));\n_GL_CXXALIAS_RPL (vsnprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, va_list args));\n# else\n#  if !@HAVE_DECL_VSNPRINTF@\n_GL_FUNCDECL_SYS (vsnprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)\n                  _GL_ARG_NONNULL ((3)));\n#  endif\n_GL_CXXALIAS_SYS (vsnprintf, int,\n                  (char *restrict str, size_t size,\n                   const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vsnprintf);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef vsnprintf\n# if HAVE_RAW_DECL_VSNPRINTF\n_GL_WARN_ON_USE (vsnprintf, \"vsnprintf is unportable - \"\n                 \"use gnulib module vsnprintf for portability\");\n# endif\n#endif\n\n#if @GNULIB_VSPRINTF_POSIX@\n# if @REPLACE_VSPRINTF@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define vsprintf rpl_vsprintf\n#  endif\n#  define GNULIB_overrides_vsprintf 1\n_GL_FUNCDECL_RPL (vsprintf, int,\n                  (char *restrict str,\n                   const char *restrict format, va_list args)\n                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (vsprintf, int,\n                  (char *restrict str,\n                   const char *restrict format, va_list args));\n# else\n/* Need to cast, because on Solaris, the third parameter is\n                                                       __va_list args\n   and GCC's fixincludes did not change this to __gnuc_va_list.  */\n_GL_CXXALIAS_SYS_CAST (vsprintf, int,\n                       (char *restrict str,\n                        const char *restrict format, va_list args));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (vsprintf);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef vsprintf\n/* Assume vsprintf is always declared.  */\n_GL_WARN_ON_USE (vsprintf, \"vsprintf is not always POSIX compliant - \"\n                 \"use gnulib module vsprintf-posix for portable \"\n                      \"POSIX compliance\");\n#endif\n\n#endif /* _@GUARD_PREFIX@_STDIO_H */\n#endif /* _@GUARD_PREFIX@_STDIO_H */\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/stdlib.in.h",
    "content": "/* A GNU-like <stdlib.h>.\n\n   Copyright (C) 1995, 2001-2004, 2006-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined __need_system_stdlib_h || defined __need_malloc_and_calloc\n/* Special invocation conventions inside some gnulib header files,\n   and inside some glibc header files, respectively.  */\n\n#@INCLUDE_NEXT@ @NEXT_STDLIB_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_STDLIB_H\n\n/* The include_next requires a split double-inclusion guard.  */\n#@INCLUDE_NEXT@ @NEXT_STDLIB_H@\n\n#ifndef _@GUARD_PREFIX@_STDLIB_H\n#define _@GUARD_PREFIX@_STDLIB_H\n\n/* NetBSD 5.0 mis-defines NULL.  */\n#include <stddef.h>\n\n/* MirBSD 10 defines WEXITSTATUS in <sys/wait.h>, not in <stdlib.h>.  */\n#if @GNULIB_SYSTEM_POSIX@ && !defined WEXITSTATUS\n# include <sys/wait.h>\n#endif\n\n/* Solaris declares getloadavg() in <sys/loadavg.h>.  */\n#if (@GNULIB_GETLOADAVG@ || defined GNULIB_POSIXCHECK) && @HAVE_SYS_LOADAVG_H@\n/* OpenIndiana has a bug: <sys/time.h> must be included before\n   <sys/loadavg.h>.  */\n# include <sys/time.h>\n# include <sys/loadavg.h>\n#endif\n\n/* Native Windows platforms declare _mktemp() in <io.h>.  */\n#if defined _WIN32 && !defined __CYGWIN__\n# include <io.h>\n#endif\n\n#if @GNULIB_RANDOM_R@\n\n/* OSF/1 5.1 declares 'struct random_data' in <random.h>, which is included\n   from <stdlib.h> if _REENTRANT is defined.  Include it whenever we need\n   'struct random_data'.  */\n# if @HAVE_RANDOM_H@\n#  include <random.h>\n# endif\n\n# if !@HAVE_STRUCT_RANDOM_DATA@ || @REPLACE_RANDOM_R@ || !@HAVE_RANDOM_R@\n#  include <stdint.h>\n# endif\n\n# if !@HAVE_STRUCT_RANDOM_DATA@\n/* Define 'struct random_data'.\n   But allow multiple gnulib generated <stdlib.h> replacements to coexist.  */\n#  if !GNULIB_defined_struct_random_data\nstruct random_data\n{\n  int32_t *fptr;                /* Front pointer.  */\n  int32_t *rptr;                /* Rear pointer.  */\n  int32_t *state;               /* Array of state values.  */\n  int rand_type;                /* Type of random number generator.  */\n  int rand_deg;                 /* Degree of random number generator.  */\n  int rand_sep;                 /* Distance between front and rear.  */\n  int32_t *end_ptr;             /* Pointer behind state table.  */\n};\n#   define GNULIB_defined_struct_random_data 1\n#  endif\n# endif\n#endif\n\n#if (@GNULIB_MKSTEMP@ || @GNULIB_MKSTEMPS@ || @GNULIB_MKOSTEMP@ || @GNULIB_MKOSTEMPS@ || @GNULIB_GETSUBOPT@ || defined GNULIB_POSIXCHECK) && ! defined __GLIBC__ && !(defined _WIN32 && ! defined __CYGWIN__)\n/* On Mac OS X 10.3, only <unistd.h> declares mkstemp.  */\n/* On Mac OS X 10.5, only <unistd.h> declares mkstemps.  */\n/* On Mac OS X 10.13, only <unistd.h> declares mkostemp and mkostemps.  */\n/* On Cygwin 1.7.1, only <unistd.h> declares getsubopt.  */\n/* But avoid namespace pollution on glibc systems and native Windows.  */\n# include <unistd.h>\n#endif\n\n/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers\n   that can be freed by passing them as the Ith argument to the\n   function F.  */\n#ifndef _GL_ATTRIBUTE_DEALLOC\n# if __GNUC__ >= 11\n#  define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))\n# else\n#  define _GL_ATTRIBUTE_DEALLOC(f, i)\n# endif\n#endif\n\n/* _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that\n   can be freed via 'free'; it can be used only after declaring 'free'.  */\n/* Applies to: functions.  Cannot be used on inline functions.  */\n#ifndef _GL_ATTRIBUTE_DEALLOC_FREE\n# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)\n#endif\n\n/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly\n   allocated memory.  */\n/* Applies to: functions.  */\n#ifndef _GL_ATTRIBUTE_MALLOC\n# if __GNUC__ >= 3 || defined __clang__\n#  define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))\n# else\n#  define _GL_ATTRIBUTE_MALLOC\n# endif\n#endif\n\n/* The __attribute__ feature is available in gcc versions 2.5 and later.\n   The attribute __pure__ was added in gcc 2.96.  */\n#ifndef _GL_ATTRIBUTE_PURE\n# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined __clang__\n#  define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))\n# else\n#  define _GL_ATTRIBUTE_PURE /* empty */\n# endif\n#endif\n\n/* The definition of _Noreturn is copied here.  */\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n\n/* Some systems do not define EXIT_*, despite otherwise supporting C89.  */\n#ifndef EXIT_SUCCESS\n# define EXIT_SUCCESS 0\n#endif\n/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere\n   with proper operation of xargs.  */\n#ifndef EXIT_FAILURE\n# define EXIT_FAILURE 1\n#elif EXIT_FAILURE != 1\n# undef EXIT_FAILURE\n# define EXIT_FAILURE 1\n#endif\n\n\n#if @GNULIB__EXIT@\n/* Terminate the current process with the given return code, without running\n   the 'atexit' handlers.  */\n# if !@HAVE__EXIT@\n_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status));\n# endif\n_GL_CXXALIAS_SYS (_Exit, void, (int status));\n_GL_CXXALIASWARN (_Exit);\n#elif defined GNULIB_POSIXCHECK\n# undef _Exit\n# if HAVE_RAW_DECL__EXIT\n_GL_WARN_ON_USE (_Exit, \"_Exit is unportable - \"\n                 \"use gnulib module _Exit for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FREE_POSIX@\n# if @REPLACE_FREE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef free\n#   define free rpl_free\n#  endif\n_GL_FUNCDECL_RPL (free, void, (void *ptr));\n_GL_CXXALIAS_RPL (free, void, (void *ptr));\n# else\n_GL_CXXALIAS_SYS (free, void, (void *ptr));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (free);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef free\n/* Assume free is always declared.  */\n_GL_WARN_ON_USE (free, \"free is not future POSIX compliant everywhere - \"\n                 \"use gnulib module free for portability\");\n#endif\n\n\n/* Allocate memory with indefinite extent and specified alignment.  */\n#if @GNULIB_ALIGNED_ALLOC@\n# if @REPLACE_ALIGNED_ALLOC@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef aligned_alloc\n#   define aligned_alloc rpl_aligned_alloc\n#  endif\n_GL_FUNCDECL_RPL (aligned_alloc, void *,\n                  (size_t alignment, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n_GL_CXXALIAS_RPL (aligned_alloc, void *, (size_t alignment, size_t size));\n# else\n#  if @HAVE_ALIGNED_ALLOC@\n#   if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (aligned_alloc, void *,\n                  (size_t alignment, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n#   endif\n_GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size));\n#  endif\n# endif\n# if @HAVE_ALIGNED_ALLOC@\n_GL_CXXALIASWARN (aligned_alloc);\n# endif\n#else\n# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined aligned_alloc\n/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (aligned_alloc, void *,\n                  (size_t alignment, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef aligned_alloc\n#  if HAVE_RAW_DECL_ALIGNED_ALLOC\n_GL_WARN_ON_USE (aligned_alloc, \"aligned_alloc is not portable - \"\n                 \"use gnulib module aligned_alloc for portability\");\n#  endif\n# endif\n#endif\n\n#if @GNULIB_ATOLL@\n/* Parse a signed decimal integer.\n   Returns the value of the integer.  Errors are not detected.  */\n# if !@HAVE_ATOLL@\n_GL_FUNCDECL_SYS (atoll, long long, (const char *string)\n                                    _GL_ATTRIBUTE_PURE\n                                    _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (atoll, long long, (const char *string));\n_GL_CXXALIASWARN (atoll);\n#elif defined GNULIB_POSIXCHECK\n# undef atoll\n# if HAVE_RAW_DECL_ATOLL\n_GL_WARN_ON_USE (atoll, \"atoll is unportable - \"\n                 \"use gnulib module atoll for portability\");\n# endif\n#endif\n\n#if @GNULIB_CALLOC_POSIX@\n# if @REPLACE_CALLOC@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef calloc\n#   define calloc rpl_calloc\n#  endif\n_GL_FUNCDECL_RPL (calloc, void *,\n                  (size_t nmemb, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n_GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (calloc, void *,\n                  (size_t nmemb, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n#  endif\n_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (calloc);\n# endif\n#else\n# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined calloc\n/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (calloc, void *,\n                  (size_t nmemb, size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef calloc\n/* Assume calloc is always declared.  */\n_GL_WARN_ON_USE (calloc, \"calloc is not POSIX compliant everywhere - \"\n                 \"use gnulib module calloc-posix for portability\");\n# endif\n#endif\n\n#if @GNULIB_CANONICALIZE_FILE_NAME@\n# if @REPLACE_CANONICALIZE_FILE_NAME@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define canonicalize_file_name rpl_canonicalize_file_name\n#  endif\n_GL_FUNCDECL_RPL (canonicalize_file_name, char *,\n                  (const char *name)\n                  _GL_ARG_NONNULL ((1))\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name));\n# else\n#  if !@HAVE_CANONICALIZE_FILE_NAME@ || __GNUC__ >= 11\n_GL_FUNCDECL_SYS (canonicalize_file_name, char *,\n                  (const char *name)\n                  _GL_ARG_NONNULL ((1))\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n#  endif\n_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name));\n# endif\n# ifndef GNULIB_defined_canonicalize_file_name\n#  define GNULIB_defined_canonicalize_file_name \\\n     (!@HAVE_CANONICALIZE_FILE_NAME@ || @REPLACE_CANONICALIZE_FILE_NAME@)\n# endif\n_GL_CXXALIASWARN (canonicalize_file_name);\n#else\n# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined canonicalize_file_name\n/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or\n   rpl_free.  */\n_GL_FUNCDECL_SYS (canonicalize_file_name, char *,\n                  (const char *name)\n                  _GL_ARG_NONNULL ((1))\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef canonicalize_file_name\n#  if HAVE_RAW_DECL_CANONICALIZE_FILE_NAME\n_GL_WARN_ON_USE (canonicalize_file_name,\n                 \"canonicalize_file_name is unportable - \"\n                 \"use gnulib module canonicalize-lgpl for portability\");\n#  endif\n# endif\n#endif\n\n#if @GNULIB_MDA_ECVT@\n/* On native Windows, map 'ecvt' to '_ecvt', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::ecvt on all platforms that have\n   it.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ecvt\n#   define ecvt _ecvt\n#  endif\n_GL_CXXALIAS_MDA (ecvt, char *,\n                  (double number, int ndigits, int *decptp, int *signp));\n# else\n#  if @HAVE_DECL_ECVT@\n_GL_CXXALIAS_SYS (ecvt, char *,\n                  (double number, int ndigits, int *decptp, int *signp));\n#  endif\n# endif\n# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_DECL_ECVT@\n_GL_CXXALIASWARN (ecvt);\n# endif\n#endif\n\n#if @GNULIB_MDA_FCVT@\n/* On native Windows, map 'fcvt' to '_fcvt', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::fcvt on all platforms that have\n   it.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fcvt\n#   define fcvt _fcvt\n#  endif\n_GL_CXXALIAS_MDA (fcvt, char *,\n                  (double number, int ndigits, int *decptp, int *signp));\n# else\n#  if @HAVE_DECL_FCVT@\n_GL_CXXALIAS_SYS (fcvt, char *,\n                  (double number, int ndigits, int *decptp, int *signp));\n#  endif\n# endif\n# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_DECL_FCVT@\n_GL_CXXALIASWARN (fcvt);\n# endif\n#endif\n\n#if @GNULIB_MDA_GCVT@\n/* On native Windows, map 'gcvt' to '_gcvt', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::gcvt on all platforms that have\n   it.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef gcvt\n#   define gcvt _gcvt\n#  endif\n_GL_CXXALIAS_MDA (gcvt, char *, (double number, int ndigits, char *buf));\n# else\n#  if @HAVE_DECL_GCVT@\n_GL_CXXALIAS_SYS (gcvt, char *, (double number, int ndigits, char *buf));\n#  endif\n# endif\n# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_DECL_GCVT@\n_GL_CXXALIASWARN (gcvt);\n# endif\n#endif\n\n#if @GNULIB_GETLOADAVG@\n/* Store max(NELEM,3) load average numbers in LOADAVG[].\n   The three numbers are the load average of the last 1 minute, the last 5\n   minutes, and the last 15 minutes, respectively.\n   LOADAVG is an array of NELEM numbers.  */\n# if !@HAVE_DECL_GETLOADAVG@\n_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem)\n                                   _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem));\n_GL_CXXALIASWARN (getloadavg);\n#elif defined GNULIB_POSIXCHECK\n# undef getloadavg\n# if HAVE_RAW_DECL_GETLOADAVG\n_GL_WARN_ON_USE (getloadavg, \"getloadavg is not portable - \"\n                 \"use gnulib module getloadavg for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETSUBOPT@\n/* Assuming *OPTIONP is a comma separated list of elements of the form\n   \"token\" or \"token=value\", getsubopt parses the first of these elements.\n   If the first element refers to a \"token\" that is member of the given\n   NULL-terminated array of tokens:\n     - It replaces the comma with a NUL byte, updates *OPTIONP to point past\n       the first option and the comma, sets *VALUEP to the value of the\n       element (or NULL if it doesn't contain an \"=\" sign),\n     - It returns the index of the \"token\" in the given array of tokens.\n   Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined.\n   For more details see the POSIX specification.\n   https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html */\n# if !@HAVE_GETSUBOPT@\n_GL_FUNCDECL_SYS (getsubopt, int,\n                  (char **optionp, char *const *tokens, char **valuep)\n                  _GL_ARG_NONNULL ((1, 2, 3)));\n# endif\n_GL_CXXALIAS_SYS (getsubopt, int,\n                  (char **optionp, char *const *tokens, char **valuep));\n_GL_CXXALIASWARN (getsubopt);\n#elif defined GNULIB_POSIXCHECK\n# undef getsubopt\n# if HAVE_RAW_DECL_GETSUBOPT\n_GL_WARN_ON_USE (getsubopt, \"getsubopt is unportable - \"\n                 \"use gnulib module getsubopt for portability\");\n# endif\n#endif\n\n#if @GNULIB_GRANTPT@\n/* Change the ownership and access permission of the slave side of the\n   pseudo-terminal whose master side is specified by FD.  */\n# if !@HAVE_GRANTPT@\n_GL_FUNCDECL_SYS (grantpt, int, (int fd));\n# endif\n_GL_CXXALIAS_SYS (grantpt, int, (int fd));\n_GL_CXXALIASWARN (grantpt);\n#elif defined GNULIB_POSIXCHECK\n# undef grantpt\n# if HAVE_RAW_DECL_GRANTPT\n_GL_WARN_ON_USE (grantpt, \"grantpt is not portable - \"\n                 \"use gnulib module grantpt for portability\");\n# endif\n#endif\n\n/* If _GL_USE_STDLIB_ALLOC is nonzero, the including module does not\n   rely on GNU or POSIX semantics for malloc and realloc (for example,\n   by never specifying a zero size), so it does not need malloc or\n   realloc to be redefined.  */\n#if @GNULIB_MALLOC_POSIX@\n# if @REPLACE_MALLOC@\n#  if !((defined __cplusplus && defined GNULIB_NAMESPACE) \\\n        || _GL_USE_STDLIB_ALLOC)\n#   undef malloc\n#   define malloc rpl_malloc\n#  endif\n_GL_FUNCDECL_RPL (malloc, void *,\n                  (size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n_GL_CXXALIAS_RPL (malloc, void *, (size_t size));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (malloc, void *,\n                  (size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n#  endif\n_GL_CXXALIAS_SYS (malloc, void *, (size_t size));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (malloc);\n# endif\n#else\n# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined malloc\n/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (malloc, void *,\n                  (size_t size)\n                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);\n# endif\n# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC\n#  undef malloc\n/* Assume malloc is always declared.  */\n_GL_WARN_ON_USE (malloc, \"malloc is not POSIX compliant everywhere - \"\n                 \"use gnulib module malloc-posix for portability\");\n# endif\n#endif\n\n/* Convert a multibyte character to a wide character.  */\n#if @GNULIB_MBTOWC@\n# if @REPLACE_MBTOWC@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mbtowc\n#   define mbtowc rpl_mbtowc\n#  endif\n_GL_FUNCDECL_RPL (mbtowc, int,\n                  (wchar_t *restrict pwc, const char *restrict s, size_t n));\n_GL_CXXALIAS_RPL (mbtowc, int,\n                  (wchar_t *restrict pwc, const char *restrict s, size_t n));\n# else\n#  if !@HAVE_MBTOWC@\n_GL_FUNCDECL_SYS (mbtowc, int,\n                  (wchar_t *restrict pwc, const char *restrict s, size_t n));\n#  endif\n_GL_CXXALIAS_SYS (mbtowc, int,\n                  (wchar_t *restrict pwc, const char *restrict s, size_t n));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (mbtowc);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef mbtowc\n# if HAVE_RAW_DECL_MBTOWC\n_GL_WARN_ON_USE (mbtowc, \"mbtowc is not portable - \"\n                 \"use gnulib module mbtowc for portability\");\n# endif\n#endif\n\n#if @GNULIB_MKDTEMP@\n/* Create a unique temporary directory from TEMPLATE.\n   The last six characters of TEMPLATE must be \"XXXXXX\";\n   they are replaced with a string that makes the directory name unique.\n   Returns TEMPLATE, or a null pointer if it cannot get a unique name.\n   The directory is created mode 700.  */\n# if !@HAVE_MKDTEMP@\n_GL_FUNCDECL_SYS (mkdtemp, char *, (char * /*template*/) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (mkdtemp, char *, (char * /*template*/));\n_GL_CXXALIASWARN (mkdtemp);\n#elif defined GNULIB_POSIXCHECK\n# undef mkdtemp\n# if HAVE_RAW_DECL_MKDTEMP\n_GL_WARN_ON_USE (mkdtemp, \"mkdtemp is unportable - \"\n                 \"use gnulib module mkdtemp for portability\");\n# endif\n#endif\n\n#if @GNULIB_MKOSTEMP@\n/* Create a unique temporary file from TEMPLATE.\n   The last six characters of TEMPLATE must be \"XXXXXX\";\n   they are replaced with a string that makes the file name unique.\n   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>)\n   and O_TEXT, O_BINARY (defined in \"binary-io.h\").\n   The file is then created, with the specified flags, ensuring it didn't exist\n   before.\n   The file is created read-write (mask at least 0600 & ~umask), but it may be\n   world-readable and world-writable (mask 0666 & ~umask), depending on the\n   implementation.\n   Returns the open file descriptor if successful, otherwise -1 and errno\n   set.  */\n# if !@HAVE_MKOSTEMP@\n_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/)\n                                 _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/));\n_GL_CXXALIASWARN (mkostemp);\n#elif defined GNULIB_POSIXCHECK\n# undef mkostemp\n# if HAVE_RAW_DECL_MKOSTEMP\n_GL_WARN_ON_USE (mkostemp, \"mkostemp is unportable - \"\n                 \"use gnulib module mkostemp for portability\");\n# endif\n#endif\n\n#if @GNULIB_MKOSTEMPS@\n/* Create a unique temporary file from TEMPLATE.\n   The last six characters of TEMPLATE before a suffix of length\n   SUFFIXLEN must be \"XXXXXX\";\n   they are replaced with a string that makes the file name unique.\n   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>)\n   and O_TEXT, O_BINARY (defined in \"binary-io.h\").\n   The file is then created, with the specified flags, ensuring it didn't exist\n   before.\n   The file is created read-write (mask at least 0600 & ~umask), but it may be\n   world-readable and world-writable (mask 0666 & ~umask), depending on the\n   implementation.\n   Returns the open file descriptor if successful, otherwise -1 and errno\n   set.  */\n# if !@HAVE_MKOSTEMPS@\n_GL_FUNCDECL_SYS (mkostemps, int,\n                  (char * /*template*/, int /*suffixlen*/, int /*flags*/)\n                  _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (mkostemps, int,\n                  (char * /*template*/, int /*suffixlen*/, int /*flags*/));\n_GL_CXXALIASWARN (mkostemps);\n#elif defined GNULIB_POSIXCHECK\n# undef mkostemps\n# if HAVE_RAW_DECL_MKOSTEMPS\n_GL_WARN_ON_USE (mkostemps, \"mkostemps is unportable - \"\n                 \"use gnulib module mkostemps for portability\");\n# endif\n#endif\n\n#if @GNULIB_MKSTEMP@\n/* Create a unique temporary file from TEMPLATE.\n   The last six characters of TEMPLATE must be \"XXXXXX\";\n   they are replaced with a string that makes the file name unique.\n   The file is then created, ensuring it didn't exist before.\n   The file is created read-write (mask at least 0600 & ~umask), but it may be\n   world-readable and world-writable (mask 0666 & ~umask), depending on the\n   implementation.\n   Returns the open file descriptor if successful, otherwise -1 and errno\n   set.  */\n# if @REPLACE_MKSTEMP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define mkstemp rpl_mkstemp\n#  endif\n_GL_FUNCDECL_RPL (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (mkstemp, int, (char * /*template*/));\n# else\n#  if ! @HAVE_MKSTEMP@\n_GL_FUNCDECL_SYS (mkstemp, int, (char * /*template*/) _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (mkstemp, int, (char * /*template*/));\n# endif\n_GL_CXXALIASWARN (mkstemp);\n#elif defined GNULIB_POSIXCHECK\n# undef mkstemp\n# if HAVE_RAW_DECL_MKSTEMP\n_GL_WARN_ON_USE (mkstemp, \"mkstemp is unportable - \"\n                 \"use gnulib module mkstemp for portability\");\n# endif\n#endif\n\n#if @GNULIB_MKSTEMPS@\n/* Create a unique temporary file from TEMPLATE.\n   The last six characters of TEMPLATE prior to a suffix of length\n   SUFFIXLEN must be \"XXXXXX\";\n   they are replaced with a string that makes the file name unique.\n   The file is then created, ensuring it didn't exist before.\n   The file is created read-write (mask at least 0600 & ~umask), but it may be\n   world-readable and world-writable (mask 0666 & ~umask), depending on the\n   implementation.\n   Returns the open file descriptor if successful, otherwise -1 and errno\n   set.  */\n# if !@HAVE_MKSTEMPS@\n_GL_FUNCDECL_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/)\n                                 _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (mkstemps, int, (char * /*template*/, int /*suffixlen*/));\n_GL_CXXALIASWARN (mkstemps);\n#elif defined GNULIB_POSIXCHECK\n# undef mkstemps\n# if HAVE_RAW_DECL_MKSTEMPS\n_GL_WARN_ON_USE (mkstemps, \"mkstemps is unportable - \"\n                 \"use gnulib module mkstemps for portability\");\n# endif\n#endif\n\n#if @GNULIB_MDA_MKTEMP@\n/* On native Windows, map 'mktemp' to '_mktemp', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::mktemp always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mktemp\n#   define mktemp _mktemp\n#  endif\n_GL_CXXALIAS_MDA (mktemp, char *, (char * /*template*/));\n# else\n_GL_CXXALIAS_SYS (mktemp, char *, (char * /*template*/));\n# endif\n_GL_CXXALIASWARN (mktemp);\n#endif\n\n/* Allocate memory with indefinite extent and specified alignment.  */\n#if @GNULIB_POSIX_MEMALIGN@\n# if @REPLACE_POSIX_MEMALIGN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef posix_memalign\n#   define posix_memalign rpl_posix_memalign\n#  endif\n_GL_FUNCDECL_RPL (posix_memalign, int,\n                  (void **memptr, size_t alignment, size_t size)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (posix_memalign, int,\n                  (void **memptr, size_t alignment, size_t size));\n# else\n#  if @HAVE_POSIX_MEMALIGN@\n_GL_CXXALIAS_SYS (posix_memalign, int,\n                  (void **memptr, size_t alignment, size_t size));\n#  endif\n# endif\n# if @HAVE_POSIX_MEMALIGN@\n_GL_CXXALIASWARN (posix_memalign);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef posix_memalign\n# if HAVE_RAW_DECL_POSIX_MEMALIGN\n_GL_WARN_ON_USE (posix_memalign, \"posix_memalign is not portable - \"\n                 \"use gnulib module posix_memalign for portability\");\n# endif\n#endif\n\n#if @GNULIB_POSIX_OPENPT@\n/* Return an FD open to the master side of a pseudo-terminal.  Flags should\n   include O_RDWR, and may also include O_NOCTTY.  */\n# if !@HAVE_POSIX_OPENPT@\n_GL_FUNCDECL_SYS (posix_openpt, int, (int flags));\n# endif\n_GL_CXXALIAS_SYS (posix_openpt, int, (int flags));\n_GL_CXXALIASWARN (posix_openpt);\n#elif defined GNULIB_POSIXCHECK\n# undef posix_openpt\n# if HAVE_RAW_DECL_POSIX_OPENPT\n_GL_WARN_ON_USE (posix_openpt, \"posix_openpt is not portable - \"\n                 \"use gnulib module posix_openpt for portability\");\n# endif\n#endif\n\n#if @GNULIB_PTSNAME@\n/* Return the pathname of the pseudo-terminal slave associated with\n   the master FD is open on, or NULL on errors.  */\n# if @REPLACE_PTSNAME@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ptsname\n#   define ptsname rpl_ptsname\n#  endif\n_GL_FUNCDECL_RPL (ptsname, char *, (int fd));\n_GL_CXXALIAS_RPL (ptsname, char *, (int fd));\n# else\n#  if !@HAVE_PTSNAME@\n_GL_FUNCDECL_SYS (ptsname, char *, (int fd));\n#  endif\n_GL_CXXALIAS_SYS (ptsname, char *, (int fd));\n# endif\n_GL_CXXALIASWARN (ptsname);\n#elif defined GNULIB_POSIXCHECK\n# undef ptsname\n# if HAVE_RAW_DECL_PTSNAME\n_GL_WARN_ON_USE (ptsname, \"ptsname is not portable - \"\n                 \"use gnulib module ptsname for portability\");\n# endif\n#endif\n\n#if @GNULIB_PTSNAME_R@\n/* Set the pathname of the pseudo-terminal slave associated with\n   the master FD is open on and return 0, or set errno and return\n   non-zero on errors.  */\n# if @REPLACE_PTSNAME_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ptsname_r\n#   define ptsname_r rpl_ptsname_r\n#  endif\n_GL_FUNCDECL_RPL (ptsname_r, int, (int fd, char *buf, size_t len));\n_GL_CXXALIAS_RPL (ptsname_r, int, (int fd, char *buf, size_t len));\n# else\n#  if !@HAVE_PTSNAME_R@\n_GL_FUNCDECL_SYS (ptsname_r, int, (int fd, char *buf, size_t len));\n#  endif\n_GL_CXXALIAS_SYS (ptsname_r, int, (int fd, char *buf, size_t len));\n# endif\n# ifndef GNULIB_defined_ptsname_r\n#  define GNULIB_defined_ptsname_r (!@HAVE_PTSNAME_R@ || @REPLACE_PTSNAME_R@)\n# endif\n_GL_CXXALIASWARN (ptsname_r);\n#elif defined GNULIB_POSIXCHECK\n# undef ptsname_r\n# if HAVE_RAW_DECL_PTSNAME_R\n_GL_WARN_ON_USE (ptsname_r, \"ptsname_r is not portable - \"\n                 \"use gnulib module ptsname_r for portability\");\n# endif\n#endif\n\n#if @GNULIB_PUTENV@\n# if @REPLACE_PUTENV@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putenv\n#   define putenv rpl_putenv\n#  endif\n_GL_FUNCDECL_RPL (putenv, int, (char *string) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (putenv, int, (char *string));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putenv\n#   define putenv _putenv\n#  endif\n_GL_CXXALIAS_MDA (putenv, int, (char *string));\n# else\n_GL_CXXALIAS_SYS (putenv, int, (char *string));\n# endif\n_GL_CXXALIASWARN (putenv);\n#elif @GNULIB_MDA_PUTENV@\n/* On native Windows, map 'putenv' to '_putenv', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::putenv always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef putenv\n#   define putenv _putenv\n#  endif\n/* Need to cast, because on mingw, the parameter is either\n   'const char *string' or 'char *string'.  */\n_GL_CXXALIAS_MDA_CAST (putenv, int, (char *string));\n# else\n_GL_CXXALIAS_SYS (putenv, int, (char *string));\n# endif\n_GL_CXXALIASWARN (putenv);\n#endif\n\n#if @GNULIB_QSORT_R@\n/* Sort an array of NMEMB elements, starting at address BASE, each element\n   occupying SIZE bytes, in ascending order according to the comparison\n   function COMPARE.  */\n# if @REPLACE_QSORT_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef qsort_r\n#   define qsort_r rpl_qsort_r\n#  endif\n_GL_FUNCDECL_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,\n                                  int (*compare) (void const *, void const *,\n                                                  void *),\n                                  void *arg) _GL_ARG_NONNULL ((1, 4)));\n_GL_CXXALIAS_RPL (qsort_r, void, (void *base, size_t nmemb, size_t size,\n                                  int (*compare) (void const *, void const *,\n                                                  void *),\n                                  void *arg));\n# else\n#  if !@HAVE_QSORT_R@\n_GL_FUNCDECL_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,\n                                  int (*compare) (void const *, void const *,\n                                                  void *),\n                                  void *arg) _GL_ARG_NONNULL ((1, 4)));\n#  endif\n_GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,\n                                  int (*compare) (void const *, void const *,\n                                                  void *),\n                                  void *arg));\n# endif\n_GL_CXXALIASWARN (qsort_r);\n#elif defined GNULIB_POSIXCHECK\n# undef qsort_r\n# if HAVE_RAW_DECL_QSORT_R\n_GL_WARN_ON_USE (qsort_r, \"qsort_r is not portable - \"\n                 \"use gnulib module qsort_r for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_RANDOM_R@\n# if !@HAVE_RANDOM_R@\n#  ifndef RAND_MAX\n#   define RAND_MAX 2147483647\n#  endif\n# endif\n#endif\n\n\n#if @GNULIB_RANDOM@\n# if @REPLACE_RANDOM@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef random\n#   define random rpl_random\n#  endif\n_GL_FUNCDECL_RPL (random, long, (void));\n_GL_CXXALIAS_RPL (random, long, (void));\n# else\n#  if !@HAVE_RANDOM@\n_GL_FUNCDECL_SYS (random, long, (void));\n#  endif\n/* Need to cast, because on Haiku, the return type is\n                               int.  */\n_GL_CXXALIAS_SYS_CAST (random, long, (void));\n# endif\n_GL_CXXALIASWARN (random);\n#elif defined GNULIB_POSIXCHECK\n# undef random\n# if HAVE_RAW_DECL_RANDOM\n_GL_WARN_ON_USE (random, \"random is unportable - \"\n                 \"use gnulib module random for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM@\n# if @REPLACE_RANDOM@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef srandom\n#   define srandom rpl_srandom\n#  endif\n_GL_FUNCDECL_RPL (srandom, void, (unsigned int seed));\n_GL_CXXALIAS_RPL (srandom, void, (unsigned int seed));\n# else\n#  if !@HAVE_RANDOM@\n_GL_FUNCDECL_SYS (srandom, void, (unsigned int seed));\n#  endif\n/* Need to cast, because on FreeBSD, the first parameter is\n                                       unsigned long seed.  */\n_GL_CXXALIAS_SYS_CAST (srandom, void, (unsigned int seed));\n# endif\n_GL_CXXALIASWARN (srandom);\n#elif defined GNULIB_POSIXCHECK\n# undef srandom\n# if HAVE_RAW_DECL_SRANDOM\n_GL_WARN_ON_USE (srandom, \"srandom is unportable - \"\n                 \"use gnulib module random for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM@\n# if @REPLACE_INITSTATE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef initstate\n#   define initstate rpl_initstate\n#  endif\n_GL_FUNCDECL_RPL (initstate, char *,\n                  (unsigned int seed, char *buf, size_t buf_size)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (initstate, char *,\n                  (unsigned int seed, char *buf, size_t buf_size));\n# else\n#  if !@HAVE_INITSTATE@ || !@HAVE_DECL_INITSTATE@\n_GL_FUNCDECL_SYS (initstate, char *,\n                  (unsigned int seed, char *buf, size_t buf_size)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n/* Need to cast, because on FreeBSD, the first parameter is\n                        unsigned long seed.  */\n_GL_CXXALIAS_SYS_CAST (initstate, char *,\n                       (unsigned int seed, char *buf, size_t buf_size));\n# endif\n_GL_CXXALIASWARN (initstate);\n#elif defined GNULIB_POSIXCHECK\n# undef initstate\n# if HAVE_RAW_DECL_INITSTATE\n_GL_WARN_ON_USE (initstate, \"initstate is unportable - \"\n                 \"use gnulib module random for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM@\n# if @REPLACE_SETSTATE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef setstate\n#   define setstate rpl_setstate\n#  endif\n_GL_FUNCDECL_RPL (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (setstate, char *, (char *arg_state));\n# else\n#  if !@HAVE_SETSTATE@ || !@HAVE_DECL_SETSTATE@\n_GL_FUNCDECL_SYS (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1)));\n#  endif\n/* Need to cast, because on Mac OS X 10.13, HP-UX, Solaris the first parameter\n   is                                     const char *arg_state.  */\n_GL_CXXALIAS_SYS_CAST (setstate, char *, (char *arg_state));\n# endif\n_GL_CXXALIASWARN (setstate);\n#elif defined GNULIB_POSIXCHECK\n# undef setstate\n# if HAVE_RAW_DECL_SETSTATE\n_GL_WARN_ON_USE (setstate, \"setstate is unportable - \"\n                 \"use gnulib module random for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_RANDOM_R@\n# if @REPLACE_RANDOM_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef random_r\n#   define random_r rpl_random_r\n#  endif\n_GL_FUNCDECL_RPL (random_r, int, (struct random_data *buf, int32_t *result)\n                                 _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (random_r, int, (struct random_data *buf, int32_t *result));\n# else\n#  if !@HAVE_RANDOM_R@\n_GL_FUNCDECL_SYS (random_r, int, (struct random_data *buf, int32_t *result)\n                                 _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (random_r, int, (struct random_data *buf, int32_t *result));\n# endif\n_GL_CXXALIASWARN (random_r);\n#elif defined GNULIB_POSIXCHECK\n# undef random_r\n# if HAVE_RAW_DECL_RANDOM_R\n_GL_WARN_ON_USE (random_r, \"random_r is unportable - \"\n                 \"use gnulib module random_r for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM_R@\n# if @REPLACE_RANDOM_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef srandom_r\n#   define srandom_r rpl_srandom_r\n#  endif\n_GL_FUNCDECL_RPL (srandom_r, int,\n                  (unsigned int seed, struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (srandom_r, int,\n                  (unsigned int seed, struct random_data *rand_state));\n# else\n#  if !@HAVE_RANDOM_R@\n_GL_FUNCDECL_SYS (srandom_r, int,\n                  (unsigned int seed, struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (srandom_r, int,\n                  (unsigned int seed, struct random_data *rand_state));\n# endif\n_GL_CXXALIASWARN (srandom_r);\n#elif defined GNULIB_POSIXCHECK\n# undef srandom_r\n# if HAVE_RAW_DECL_SRANDOM_R\n_GL_WARN_ON_USE (srandom_r, \"srandom_r is unportable - \"\n                 \"use gnulib module random_r for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM_R@\n# if @REPLACE_RANDOM_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef initstate_r\n#   define initstate_r rpl_initstate_r\n#  endif\n_GL_FUNCDECL_RPL (initstate_r, int,\n                  (unsigned int seed, char *buf, size_t buf_size,\n                   struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((2, 4)));\n_GL_CXXALIAS_RPL (initstate_r, int,\n                  (unsigned int seed, char *buf, size_t buf_size,\n                   struct random_data *rand_state));\n# else\n#  if !@HAVE_RANDOM_R@\n_GL_FUNCDECL_SYS (initstate_r, int,\n                  (unsigned int seed, char *buf, size_t buf_size,\n                   struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((2, 4)));\n#  endif\n/* Need to cast, because on Haiku, the third parameter is\n                                                     unsigned long buf_size.  */\n_GL_CXXALIAS_SYS_CAST (initstate_r, int,\n                       (unsigned int seed, char *buf, size_t buf_size,\n                        struct random_data *rand_state));\n# endif\n_GL_CXXALIASWARN (initstate_r);\n#elif defined GNULIB_POSIXCHECK\n# undef initstate_r\n# if HAVE_RAW_DECL_INITSTATE_R\n_GL_WARN_ON_USE (initstate_r, \"initstate_r is unportable - \"\n                 \"use gnulib module random_r for portability\");\n# endif\n#endif\n\n#if @GNULIB_RANDOM_R@\n# if @REPLACE_RANDOM_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef setstate_r\n#   define setstate_r rpl_setstate_r\n#  endif\n_GL_FUNCDECL_RPL (setstate_r, int,\n                  (char *arg_state, struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (setstate_r, int,\n                  (char *arg_state, struct random_data *rand_state));\n# else\n#  if !@HAVE_RANDOM_R@\n_GL_FUNCDECL_SYS (setstate_r, int,\n                  (char *arg_state, struct random_data *rand_state)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n/* Need to cast, because on Haiku, the first parameter is\n                        void *arg_state.  */\n_GL_CXXALIAS_SYS_CAST (setstate_r, int,\n                       (char *arg_state, struct random_data *rand_state));\n# endif\n_GL_CXXALIASWARN (setstate_r);\n#elif defined GNULIB_POSIXCHECK\n# undef setstate_r\n# if HAVE_RAW_DECL_SETSTATE_R\n_GL_WARN_ON_USE (setstate_r, \"setstate_r is unportable - \"\n                 \"use gnulib module random_r for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_REALLOC_POSIX@\n# if @REPLACE_REALLOC@\n#  if !((defined __cplusplus && defined GNULIB_NAMESPACE) \\\n        || _GL_USE_STDLIB_ALLOC)\n#   undef realloc\n#   define realloc rpl_realloc\n#  endif\n_GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size)\n                                   _GL_ATTRIBUTE_DEALLOC_FREE);\n_GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size));\n# else\n#  if __GNUC__ >= 11\n/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size)\n                                   _GL_ATTRIBUTE_DEALLOC_FREE);\n#  endif\n_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (realloc);\n# endif\n#else\n# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined realloc\n/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free.  */\n_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size)\n                                   _GL_ATTRIBUTE_DEALLOC_FREE);\n# endif\n# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC\n#  undef realloc\n/* Assume realloc is always declared.  */\n_GL_WARN_ON_USE (realloc, \"realloc is not POSIX compliant everywhere - \"\n                 \"use gnulib module realloc-posix for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_REALLOCARRAY@\n# if @REPLACE_REALLOCARRAY@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef reallocarray\n#   define reallocarray rpl_reallocarray\n#  endif\n_GL_FUNCDECL_RPL (reallocarray, void *,\n                  (void *ptr, size_t nmemb, size_t size));\n_GL_CXXALIAS_RPL (reallocarray, void *,\n                  (void *ptr, size_t nmemb, size_t size));\n# else\n#  if ! @HAVE_REALLOCARRAY@\n_GL_FUNCDECL_SYS (reallocarray, void *,\n                  (void *ptr, size_t nmemb, size_t size));\n#  endif\n_GL_CXXALIAS_SYS (reallocarray, void *,\n                  (void *ptr, size_t nmemb, size_t size));\n# endif\n_GL_CXXALIASWARN (reallocarray);\n#elif defined GNULIB_POSIXCHECK\n# undef reallocarray\n# if HAVE_RAW_DECL_REALLOCARRAY\n_GL_WARN_ON_USE (reallocarray, \"reallocarray is not portable - \"\n                 \"use gnulib module reallocarray for portability\");\n# endif\n#endif\n\n#if @GNULIB_REALPATH@\n# if @REPLACE_REALPATH@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define realpath rpl_realpath\n#  endif\n_GL_FUNCDECL_RPL (realpath, char *,\n                  (const char *restrict name, char *restrict resolved)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (realpath, char *,\n                  (const char *restrict name, char *restrict resolved));\n# else\n#  if !@HAVE_REALPATH@\n_GL_FUNCDECL_SYS (realpath, char *,\n                  (const char *restrict name, char *restrict resolved)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (realpath, char *,\n                  (const char *restrict name, char *restrict resolved));\n# endif\n_GL_CXXALIASWARN (realpath);\n#elif defined GNULIB_POSIXCHECK\n# undef realpath\n# if HAVE_RAW_DECL_REALPATH\n_GL_WARN_ON_USE (realpath, \"realpath is unportable - use gnulib module \"\n                 \"canonicalize or canonicalize-lgpl for portability\");\n# endif\n#endif\n\n#if @GNULIB_RPMATCH@\n/* Test a user response to a question.\n   Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear.  */\n# if !@HAVE_RPMATCH@\n_GL_FUNCDECL_SYS (rpmatch, int, (const char *response) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (rpmatch, int, (const char *response));\n_GL_CXXALIASWARN (rpmatch);\n#elif defined GNULIB_POSIXCHECK\n# undef rpmatch\n# if HAVE_RAW_DECL_RPMATCH\n_GL_WARN_ON_USE (rpmatch, \"rpmatch is unportable - \"\n                 \"use gnulib module rpmatch for portability\");\n# endif\n#endif\n\n#if @GNULIB_SECURE_GETENV@\n/* Look up NAME in the environment, returning 0 in insecure situations.  */\n# if !@HAVE_SECURE_GETENV@\n_GL_FUNCDECL_SYS (secure_getenv, char *,\n                  (char const *name) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (secure_getenv, char *, (char const *name));\n_GL_CXXALIASWARN (secure_getenv);\n#elif defined GNULIB_POSIXCHECK\n# undef secure_getenv\n# if HAVE_RAW_DECL_SECURE_GETENV\n_GL_WARN_ON_USE (secure_getenv, \"secure_getenv is unportable - \"\n                 \"use gnulib module secure_getenv for portability\");\n# endif\n#endif\n\n#if @GNULIB_SETENV@\n/* Set NAME to VALUE in the environment.\n   If REPLACE is nonzero, overwrite an existing value.  */\n# if @REPLACE_SETENV@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef setenv\n#   define setenv rpl_setenv\n#  endif\n_GL_FUNCDECL_RPL (setenv, int,\n                  (const char *name, const char *value, int replace)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (setenv, int,\n                  (const char *name, const char *value, int replace));\n# else\n#  if !@HAVE_DECL_SETENV@\n_GL_FUNCDECL_SYS (setenv, int,\n                  (const char *name, const char *value, int replace)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (setenv, int,\n                  (const char *name, const char *value, int replace));\n# endif\n# if !(@REPLACE_SETENV@ && !@HAVE_DECL_SETENV@)\n_GL_CXXALIASWARN (setenv);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef setenv\n# if HAVE_RAW_DECL_SETENV\n_GL_WARN_ON_USE (setenv, \"setenv is unportable - \"\n                 \"use gnulib module setenv for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOD@\n /* Parse a double from STRING, updating ENDP if appropriate.  */\n# if @REPLACE_STRTOD@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtod rpl_strtod\n#  endif\n#  define GNULIB_defined_strtod_function 1\n_GL_FUNCDECL_RPL (strtod, double,\n                  (const char *restrict str, char **restrict endp)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtod, double,\n                  (const char *restrict str, char **restrict endp));\n# else\n#  if !@HAVE_STRTOD@\n_GL_FUNCDECL_SYS (strtod, double,\n                  (const char *restrict str, char **restrict endp)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtod, double,\n                  (const char *restrict str, char **restrict endp));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (strtod);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef strtod\n# if HAVE_RAW_DECL_STRTOD\n_GL_WARN_ON_USE (strtod, \"strtod is unportable - \"\n                 \"use gnulib module strtod for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOLD@\n /* Parse a 'long double' from STRING, updating ENDP if appropriate.  */\n# if @REPLACE_STRTOLD@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtold rpl_strtold\n#  endif\n#  define GNULIB_defined_strtold_function 1\n_GL_FUNCDECL_RPL (strtold, long double,\n                  (const char *restrict str, char **restrict endp)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtold, long double,\n                  (const char *restrict str, char **restrict endp));\n# else\n#  if !@HAVE_STRTOLD@\n_GL_FUNCDECL_SYS (strtold, long double,\n                  (const char *restrict str, char **restrict endp)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtold, long double,\n                  (const char *restrict str, char **restrict endp));\n# endif\n_GL_CXXALIASWARN (strtold);\n#elif defined GNULIB_POSIXCHECK\n# undef strtold\n# if HAVE_RAW_DECL_STRTOLD\n_GL_WARN_ON_USE (strtold, \"strtold is unportable - \"\n                 \"use gnulib module strtold for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOL@\n/* Parse a signed integer whose textual representation starts at STRING.\n   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,\n   it may be decimal or octal (with prefix \"0\") or hexadecimal (with prefix\n   \"0x\").\n   If ENDPTR is not NULL, the address of the first byte after the integer is\n   stored in *ENDPTR.\n   Upon overflow, the return value is LONG_MAX or LONG_MIN, and errno is set\n   to ERANGE.  */\n# if @REPLACE_STRTOL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtol rpl_strtol\n#  endif\n#  define GNULIB_defined_strtol_function 1\n_GL_FUNCDECL_RPL (strtol, long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtol, long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# else\n#  if !@HAVE_STRTOL@\n_GL_FUNCDECL_SYS (strtol, long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtol, long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# endif\n_GL_CXXALIASWARN (strtol);\n#elif defined GNULIB_POSIXCHECK\n# undef strtol\n# if HAVE_RAW_DECL_STRTOL\n_GL_WARN_ON_USE (strtol, \"strtol is unportable - \"\n                 \"use gnulib module strtol for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOLL@\n/* Parse a signed integer whose textual representation starts at STRING.\n   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,\n   it may be decimal or octal (with prefix \"0\") or hexadecimal (with prefix\n   \"0x\").\n   If ENDPTR is not NULL, the address of the first byte after the integer is\n   stored in *ENDPTR.\n   Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set\n   to ERANGE.  */\n# if @REPLACE_STRTOLL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtoll rpl_strtoll\n#  endif\n#  define GNULIB_defined_strtoll_function 1\n_GL_FUNCDECL_RPL (strtoll, long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtoll, long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# else\n#  if !@HAVE_STRTOLL@\n_GL_FUNCDECL_SYS (strtoll, long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtoll, long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# endif\n_GL_CXXALIASWARN (strtoll);\n#elif defined GNULIB_POSIXCHECK\n# undef strtoll\n# if HAVE_RAW_DECL_STRTOLL\n_GL_WARN_ON_USE (strtoll, \"strtoll is unportable - \"\n                 \"use gnulib module strtoll for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOUL@\n/* Parse an unsigned integer whose textual representation starts at STRING.\n   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,\n   it may be decimal or octal (with prefix \"0\") or hexadecimal (with prefix\n   \"0x\").\n   If ENDPTR is not NULL, the address of the first byte after the integer is\n   stored in *ENDPTR.\n   Upon overflow, the return value is ULONG_MAX, and errno is set to ERANGE.  */\n# if @REPLACE_STRTOUL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtoul rpl_strtoul\n#  endif\n#  define GNULIB_defined_strtoul_function 1\n_GL_FUNCDECL_RPL (strtoul, unsigned long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtoul, unsigned long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# else\n#  if !@HAVE_STRTOUL@\n_GL_FUNCDECL_SYS (strtoul, unsigned long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtoul, unsigned long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# endif\n_GL_CXXALIASWARN (strtoul);\n#elif defined GNULIB_POSIXCHECK\n# undef strtoul\n# if HAVE_RAW_DECL_STRTOUL\n_GL_WARN_ON_USE (strtoul, \"strtoul is unportable - \"\n                 \"use gnulib module strtoul for portability\");\n# endif\n#endif\n\n#if @GNULIB_STRTOULL@\n/* Parse an unsigned integer whose textual representation starts at STRING.\n   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,\n   it may be decimal or octal (with prefix \"0\") or hexadecimal (with prefix\n   \"0x\").\n   If ENDPTR is not NULL, the address of the first byte after the integer is\n   stored in *ENDPTR.\n   Upon overflow, the return value is ULLONG_MAX, and errno is set to\n   ERANGE.  */\n# if @REPLACE_STRTOULL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define strtoull rpl_strtoull\n#  endif\n#  define GNULIB_defined_strtoull_function 1\n_GL_FUNCDECL_RPL (strtoull, unsigned long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (strtoull, unsigned long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# else\n#  if !@HAVE_STRTOULL@\n_GL_FUNCDECL_SYS (strtoull, unsigned long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (strtoull, unsigned long long,\n                  (const char *restrict string, char **restrict endptr,\n                   int base));\n# endif\n_GL_CXXALIASWARN (strtoull);\n#elif defined GNULIB_POSIXCHECK\n# undef strtoull\n# if HAVE_RAW_DECL_STRTOULL\n_GL_WARN_ON_USE (strtoull, \"strtoull is unportable - \"\n                 \"use gnulib module strtoull for portability\");\n# endif\n#endif\n\n#if @GNULIB_UNLOCKPT@\n/* Unlock the slave side of the pseudo-terminal whose master side is specified\n   by FD, so that it can be opened.  */\n# if !@HAVE_UNLOCKPT@\n_GL_FUNCDECL_SYS (unlockpt, int, (int fd));\n# endif\n_GL_CXXALIAS_SYS (unlockpt, int, (int fd));\n_GL_CXXALIASWARN (unlockpt);\n#elif defined GNULIB_POSIXCHECK\n# undef unlockpt\n# if HAVE_RAW_DECL_UNLOCKPT\n_GL_WARN_ON_USE (unlockpt, \"unlockpt is not portable - \"\n                 \"use gnulib module unlockpt for portability\");\n# endif\n#endif\n\n#if @GNULIB_UNSETENV@\n/* Remove the variable NAME from the environment.  */\n# if @REPLACE_UNSETENV@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef unsetenv\n#   define unsetenv rpl_unsetenv\n#  endif\n_GL_FUNCDECL_RPL (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (unsetenv, int, (const char *name));\n# else\n#  if !@HAVE_DECL_UNSETENV@\n_GL_FUNCDECL_SYS (unsetenv, int, (const char *name) _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (unsetenv, int, (const char *name));\n# endif\n# if !(@REPLACE_UNSETENV@ && !@HAVE_DECL_UNSETENV@)\n_GL_CXXALIASWARN (unsetenv);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef unsetenv\n# if HAVE_RAW_DECL_UNSETENV\n_GL_WARN_ON_USE (unsetenv, \"unsetenv is unportable - \"\n                 \"use gnulib module unsetenv for portability\");\n# endif\n#endif\n\n/* Convert a wide character to a multibyte character.  */\n#if @GNULIB_WCTOMB@\n# if @REPLACE_WCTOMB@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef wctomb\n#   define wctomb rpl_wctomb\n#  endif\n_GL_FUNCDECL_RPL (wctomb, int, (char *s, wchar_t wc));\n_GL_CXXALIAS_RPL (wctomb, int, (char *s, wchar_t wc));\n# else\n_GL_CXXALIAS_SYS (wctomb, int, (char *s, wchar_t wc));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (wctomb);\n# endif\n#endif\n\n\n#endif /* _@GUARD_PREFIX@_STDLIB_H */\n#endif /* _@GUARD_PREFIX@_STDLIB_H */\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_resource.in.h",
    "content": "/* Substitute for <sys/resource.h>.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n# if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n# endif\n@PRAGMA_COLUMNS@\n\n#ifndef _@GUARD_PREFIX@_SYS_RESOURCE_H\n\n#if @HAVE_SYS_RESOURCE_H@\n\n/* On FreeBSD 5.0, <sys/resource.h> assumes prior inclusion of <sys/types.h>\n   and <sys/time.h>.  */\n# include <sys/types.h>\n# include <sys/time.h>\n\n/* The include_next requires a split double-inclusion guard.  */\n# @INCLUDE_NEXT@ @NEXT_SYS_RESOURCE_H@\n\n#endif\n\n#ifndef _@GUARD_PREFIX@_SYS_RESOURCE_H\n#define _@GUARD_PREFIX@_SYS_RESOURCE_H\n\n#if !@HAVE_SYS_RESOURCE_H@\n/* A platform that lacks <sys/resource.h>.  */\n\n/* Get 'struct timeval'.  */\n# include <sys/time.h>\n\n/* Define the RUSAGE_* constants.  */\n# define RUSAGE_SELF 0\n# define RUSAGE_CHILDREN -1\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n# if !GNULIB_defined_struct_rusage\n/* All known platforms that lack <sys/resource.h> also lack any declaration\n   of struct rusage in any other header.  */\nstruct rusage\n{\n  struct timeval ru_utime;      /* CPU time used in user mode */\n  struct timeval ru_stime;      /* CPU time used in system mode (kernel) */\n  long ru_maxrss;\n  long ru_ixrss;\n  long ru_idrss;\n  long ru_isrss;\n  long ru_minflt;\n  long ru_majflt;\n  long ru_nswap;\n  long ru_inblock;\n  long ru_oublock;\n  long ru_msgsnd;\n  long ru_msgrcv;\n  long ru_nsignals;\n  long ru_nvcsw;\n  long ru_nivcsw;\n};\n#  define GNULIB_defined_struct_rusage 1\n# endif\n\n# ifdef __cplusplus\n}\n# endif\n\n#else\n\n# ifdef __VMS                      /* OpenVMS */\n/* Define the RUSAGE_* constants.  */\n#  ifndef RUSAGE_SELF\n#   define RUSAGE_SELF 0\n#  endif\n#  ifndef RUSAGE_CHILDREN\n#   define RUSAGE_CHILDREN -1\n#  endif\n# endif\n\n#endif\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n\n/* Declare overridden functions.  */\n\n\n#if @GNULIB_GETRUSAGE@\n# if !@HAVE_GETRUSAGE@\n_GL_FUNCDECL_SYS (getrusage, int, (int who, struct rusage *usage_p)\n                                  _GL_ARG_NONNULL ((2)));\n# endif\n_GL_CXXALIAS_SYS (getrusage, int, (int who, struct rusage *usage_p));\n_GL_CXXALIASWARN (getrusage);\n#elif defined GNULIB_POSIXCHECK\n# undef getrusage\n# if HAVE_RAW_DECL_GETRUSAGE\n_GL_WARN_ON_USE (getrusage, \"getrusage is unportable - \"\n                 \"use gnulib module getrusage for portability\");\n# endif\n#endif\n\n\n#endif /* _@GUARD_PREFIX@_SYS_RESOURCE_H */\n#endif /* _@GUARD_PREFIX@_SYS_RESOURCE_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_socket.c",
    "content": "/* Inline functions for <sys/socket.h>.\n\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n#define _GL_SYS_SOCKET_INLINE _GL_EXTERN_INLINE\n#include \"sys/socket.h\"\ntypedef int dummy;\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_socket.in.h",
    "content": "/* Provide a sys/socket header file for systems lacking it (read: MinGW)\n   and for systems where it is incomplete.\n   Copyright (C) 2005-2021 Free Software Foundation, Inc.\n   Written by Simon Josefsson.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* This file is supposed to be used on platforms that lack <sys/socket.h>,\n   on platforms where <sys/socket.h> cannot be included standalone, and on\n   platforms where <sys/socket.h> does not provide all necessary definitions.\n   It is intended to provide definitions and prototypes needed by an\n   application.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined _GL_ALREADY_INCLUDING_SYS_SOCKET_H\n/* Special invocation convention:\n   - On Cygwin 1.5.x we have a sequence of nested includes\n     <sys/socket.h> -> <cygwin/socket.h> -> <asm/socket.h> -> <cygwin/if.h>,\n     and the latter includes <sys/socket.h>.  In this situation, the functions\n     are not yet declared, therefore we cannot provide the C++ aliases.  */\n\n#@INCLUDE_NEXT@ @NEXT_SYS_SOCKET_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_SYS_SOCKET_H\n\n#if @HAVE_SYS_SOCKET_H@\n\n# define _GL_ALREADY_INCLUDING_SYS_SOCKET_H\n\n/* On many platforms, <sys/socket.h> assumes prior inclusion of\n   <sys/types.h>.  */\n# include <sys/types.h>\n\n/* On FreeBSD 6.4, <sys/socket.h> defines some macros that assume that NULL\n   is defined.  */\n# include <stddef.h>\n\n/* The include_next requires a split double-inclusion guard.  */\n# @INCLUDE_NEXT@ @NEXT_SYS_SOCKET_H@\n\n# undef _GL_ALREADY_INCLUDING_SYS_SOCKET_H\n\n#endif\n\n#ifndef _@GUARD_PREFIX@_SYS_SOCKET_H\n#define _@GUARD_PREFIX@_SYS_SOCKET_H\n\n#ifndef _GL_INLINE_HEADER_BEGIN\n #error \"Please include config.h first.\"\n#endif\n_GL_INLINE_HEADER_BEGIN\n#ifndef _GL_SYS_SOCKET_INLINE\n# define _GL_SYS_SOCKET_INLINE _GL_INLINE\n#endif\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n#if !@HAVE_SA_FAMILY_T@\n# if !GNULIB_defined_sa_family_t\n/* On OS/2 kLIBC, sa_family_t is unsigned char unless TCPV40HDRS is defined. */\n#  if !defined __KLIBC__ || defined TCPV40HDRS\ntypedef unsigned short  sa_family_t;\n#  else\ntypedef unsigned char   sa_family_t;\n#  endif\n#  define GNULIB_defined_sa_family_t 1\n# endif\n#endif\n\n#if @HAVE_STRUCT_SOCKADDR_STORAGE@\n/* Make the 'struct sockaddr_storage' field 'ss_family' visible on AIX 7.1.  */\n# if !@HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@\n#  ifndef ss_family\n#   define ss_family __ss_family\n#  endif\n# endif\n#else\n# include <stdalign.h>\n/* Code taken from glibc sysdeps/unix/sysv/linux/bits/socket.h on\n   2009-05-08, licensed under LGPLv2.1+, plus portability fixes. */\n# define __ss_aligntype unsigned long int\n# define _SS_SIZE 256\n# define _SS_PADSIZE \\\n    (_SS_SIZE - ((sizeof (sa_family_t) >= alignof (__ss_aligntype)      \\\n                  ? sizeof (sa_family_t)                                \\\n                  : alignof (__ss_aligntype))                           \\\n                 + sizeof (__ss_aligntype)))\n\n# if !GNULIB_defined_struct_sockaddr_storage\nstruct sockaddr_storage\n{\n  sa_family_t ss_family;      /* Address family, etc.  */\n  __ss_aligntype __ss_align;  /* Force desired alignment.  */\n  char __ss_padding[_SS_PADSIZE];\n};\n#  define GNULIB_defined_struct_sockaddr_storage 1\n# endif\n\n#endif\n\n/* Get struct iovec.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if ! defined __GLIBC__\n# include <sys/uio.h>\n#endif\n\n#if @HAVE_SYS_SOCKET_H@\n\n/* A platform that has <sys/socket.h>.  */\n\n/* For shutdown().  */\n# if !defined SHUT_RD\n#  define SHUT_RD 0\n# endif\n# if !defined SHUT_WR\n#  define SHUT_WR 1\n# endif\n# if !defined SHUT_RDWR\n#  define SHUT_RDWR 2\n# endif\n\n# ifdef __VMS                        /* OpenVMS */\n#  ifndef CMSG_SPACE\n#   define CMSG_SPACE(length) _CMSG_SPACE(length)\n#  endif\n#  ifndef CMSG_LEN\n#   define CMSG_LEN(length) _CMSG_LEN(length)\n#  endif\n# endif\n\n#else\n\n# ifdef __CYGWIN__\n#  error \"Cygwin does have a sys/socket.h, doesn't it?!?\"\n# endif\n\n/* A platform that lacks <sys/socket.h>.\n\n   Currently only MinGW is supported.  See the gnulib manual regarding\n   Windows sockets.  MinGW has the header files winsock2.h and\n   ws2tcpip.h that declare the sys/socket.h definitions we need.  Note\n   that you can influence which definitions you get by setting the\n   WINVER symbol before including these two files.  For example,\n   getaddrinfo is only available if _WIN32_WINNT >= 0x0501 (that\n   symbol is set indirectly through WINVER).  You can set this by\n   adding AC_DEFINE(WINVER, 0x0501) to configure.ac.  Note that your\n   code may not run on older Windows releases then.  My Windows 2000\n   box was not able to run the code, for example.  The situation is\n   slightly confusing because\n   <https://docs.microsoft.com/en-us/windows/desktop/api/ws2tcpip/nf-ws2tcpip-getaddrinfo>\n   suggests that getaddrinfo should be available on all Windows\n   releases. */\n\n# if @HAVE_WINSOCK2_H@\n#  include <winsock2.h>\n# endif\n# if @HAVE_WS2TCPIP_H@\n#  include <ws2tcpip.h>\n# endif\n\n/* For shutdown(). */\n# if !defined SHUT_RD && defined SD_RECEIVE\n#  define SHUT_RD SD_RECEIVE\n# endif\n# if !defined SHUT_WR && defined SD_SEND\n#  define SHUT_WR SD_SEND\n# endif\n# if !defined SHUT_RDWR && defined SD_BOTH\n#  define SHUT_RDWR SD_BOTH\n# endif\n\n# if @HAVE_WINSOCK2_H@\n/* Include headers needed by the emulation code.  */\n#  include <sys/types.h>\n#  include <io.h>\n/* If these headers don't define socklen_t, <config.h> does.  */\n# endif\n\n/* Rudimentary 'struct msghdr'; this works as long as you don't try to\n   access msg_control or msg_controllen.  */\nstruct msghdr {\n  void *msg_name;\n  socklen_t msg_namelen;\n  struct iovec *msg_iov;\n  int msg_iovlen;\n  int msg_flags;\n};\n\n#endif\n\n/* Ensure SO_REUSEPORT is defined.  */\n/* For the subtle differences between SO_REUSEPORT and SO_REUSEADDR, see\n   https://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t\n   and https://lwn.net/Articles/542629/\n */\n#ifndef SO_REUSEPORT\n# define SO_REUSEPORT SO_REUSEADDR\n#endif\n\n/* Fix some definitions from <winsock2.h>.  */\n\n#if @HAVE_WINSOCK2_H@\n\n# if !GNULIB_defined_rpl_fd_isset\n\n/* Re-define FD_ISSET to avoid a WSA call while we are not using\n   network sockets.  */\n_GL_SYS_SOCKET_INLINE int\nrpl_fd_isset (SOCKET fd, fd_set * set)\n{\n  u_int i;\n  if (set == NULL)\n    return 0;\n\n  for (i = 0; i < set->fd_count; i++)\n    if (set->fd_array[i] == fd)\n      return 1;\n\n  return 0;\n}\n\n#  define GNULIB_defined_rpl_fd_isset 1\n# endif\n\n# undef FD_ISSET\n# define FD_ISSET(fd, set) rpl_fd_isset(fd, set)\n\n#endif\n\n/* Hide some function declarations from <winsock2.h>.  */\n\n#if @HAVE_WINSOCK2_H@\n# if !defined _@GUARD_PREFIX@_UNISTD_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef close\n#   define close close_used_without_including_unistd_h\n#  elif !defined __clang__\n    _GL_WARN_ON_USE (close,\n                     \"close() used without including <unistd.h>\");\n#  endif\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef gethostname\n#   define gethostname gethostname_used_without_including_unistd_h\n#  else\n    _GL_WARN_ON_USE (gethostname,\n                     \"gethostname() used without including <unistd.h>\");\n#  endif\n# endif\n# if !defined _@GUARD_PREFIX@_SYS_SELECT_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef select\n#   define select select_used_without_including_sys_select_h\n#  else\n    _GL_WARN_ON_USE (select,\n                     \"select() used without including <sys/select.h>\");\n#  endif\n# endif\n#endif\n\n/* Wrap everything else to use libc file descriptors for sockets.  */\n\n#if @GNULIB_SOCKET@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef socket\n#   define socket rpl_socket\n#  endif\n_GL_FUNCDECL_RPL (socket, int, (int domain, int type, int protocol));\n_GL_CXXALIAS_RPL (socket, int, (int domain, int type, int protocol));\n# else\n_GL_CXXALIAS_SYS (socket, int, (int domain, int type, int protocol));\n# endif\n_GL_CXXALIASWARN (socket);\n#elif @HAVE_WINSOCK2_H@\n# undef socket\n# define socket socket_used_without_requesting_gnulib_module_socket\n#elif defined GNULIB_POSIXCHECK\n# undef socket\n# if HAVE_RAW_DECL_SOCKET\n_GL_WARN_ON_USE (socket, \"socket is not always POSIX compliant - \"\n                 \"use gnulib module socket for portability\");\n# endif\n#endif\n\n#if @GNULIB_CONNECT@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef connect\n#   define connect rpl_connect\n#  endif\n_GL_FUNCDECL_RPL (connect, int,\n                  (int fd, const struct sockaddr *addr, socklen_t addrlen)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (connect, int,\n                  (int fd, const struct sockaddr *addr, socklen_t addrlen));\n# else\n/* Need to cast, because on NonStop Kernel, the third parameter is\n                                                     size_t addrlen.  */\n_GL_CXXALIAS_SYS_CAST (connect, int,\n                       (int fd,\n                        const struct sockaddr *addr, socklen_t addrlen));\n# endif\n_GL_CXXALIASWARN (connect);\n#elif @HAVE_WINSOCK2_H@\n# undef connect\n# define connect socket_used_without_requesting_gnulib_module_connect\n#elif defined GNULIB_POSIXCHECK\n# undef connect\n# if HAVE_RAW_DECL_CONNECT\n_GL_WARN_ON_USE (connect, \"connect is not always POSIX compliant - \"\n                 \"use gnulib module connect for portability\");\n# endif\n#endif\n\n#if @GNULIB_ACCEPT@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef accept\n#   define accept rpl_accept\n#  endif\n_GL_FUNCDECL_RPL (accept, int,\n                  (int fd,\n                   struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen));\n_GL_CXXALIAS_RPL (accept, int,\n                  (int fd,\n                   struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen));\n# else\n/* Need to cast, because on Solaris 10 systems, the third parameter is\n                        void *addrlen.  */\n_GL_CXXALIAS_SYS_CAST (accept, int,\n                       (int fd,\n                        struct sockaddr *restrict addr,\n                        socklen_t *restrict addrlen));\n# endif\n_GL_CXXALIASWARN (accept);\n#elif @HAVE_WINSOCK2_H@\n# undef accept\n# define accept accept_used_without_requesting_gnulib_module_accept\n#elif defined GNULIB_POSIXCHECK\n# undef accept\n# if HAVE_RAW_DECL_ACCEPT\n_GL_WARN_ON_USE (accept, \"accept is not always POSIX compliant - \"\n                 \"use gnulib module accept for portability\");\n# endif\n#endif\n\n#if @GNULIB_BIND@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef bind\n#   define bind rpl_bind\n#  endif\n_GL_FUNCDECL_RPL (bind, int,\n                  (int fd, const struct sockaddr *addr, socklen_t addrlen)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (bind, int,\n                  (int fd, const struct sockaddr *addr, socklen_t addrlen));\n# else\n/* Need to cast, because on NonStop Kernel, the third parameter is\n                                                     size_t addrlen.  */\n_GL_CXXALIAS_SYS_CAST (bind, int,\n                       (int fd,\n                        const struct sockaddr *addr, socklen_t addrlen));\n# endif\n_GL_CXXALIASWARN (bind);\n#elif @HAVE_WINSOCK2_H@\n# undef bind\n# define bind bind_used_without_requesting_gnulib_module_bind\n#elif defined GNULIB_POSIXCHECK\n# undef bind\n# if HAVE_RAW_DECL_BIND\n_GL_WARN_ON_USE (bind, \"bind is not always POSIX compliant - \"\n                 \"use gnulib module bind for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETPEERNAME@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getpeername\n#   define getpeername rpl_getpeername\n#  endif\n_GL_FUNCDECL_RPL (getpeername, int,\n                  (int fd, struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen)\n                  _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_RPL (getpeername, int,\n                  (int fd, struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen));\n# else\n/* Need to cast, because on Solaris 10 systems, the third parameter is\n                        void *addrlen.  */\n_GL_CXXALIAS_SYS_CAST (getpeername, int,\n                       (int fd, struct sockaddr *restrict addr,\n                        socklen_t *restrict addrlen));\n# endif\n_GL_CXXALIASWARN (getpeername);\n#elif @HAVE_WINSOCK2_H@\n# undef getpeername\n# define getpeername getpeername_used_without_requesting_gnulib_module_getpeername\n#elif defined GNULIB_POSIXCHECK\n# undef getpeername\n# if HAVE_RAW_DECL_GETPEERNAME\n_GL_WARN_ON_USE (getpeername, \"getpeername is not always POSIX compliant - \"\n                 \"use gnulib module getpeername for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETSOCKNAME@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getsockname\n#   define getsockname rpl_getsockname\n#  endif\n_GL_FUNCDECL_RPL (getsockname, int,\n                  (int fd, struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen)\n                  _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_RPL (getsockname, int,\n                  (int fd, struct sockaddr *restrict addr,\n                   socklen_t *restrict addrlen));\n# else\n/* Need to cast, because on Solaris 10 systems, the third parameter is\n                        void *addrlen.  */\n_GL_CXXALIAS_SYS_CAST (getsockname, int,\n                       (int fd, struct sockaddr *restrict addr,\n                        socklen_t *restrict addrlen));\n# endif\n_GL_CXXALIASWARN (getsockname);\n#elif @HAVE_WINSOCK2_H@\n# undef getsockname\n# define getsockname getsockname_used_without_requesting_gnulib_module_getsockname\n#elif defined GNULIB_POSIXCHECK\n# undef getsockname\n# if HAVE_RAW_DECL_GETSOCKNAME\n_GL_WARN_ON_USE (getsockname, \"getsockname is not always POSIX compliant - \"\n                 \"use gnulib module getsockname for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETSOCKOPT@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getsockopt\n#   define getsockopt rpl_getsockopt\n#  endif\n_GL_FUNCDECL_RPL (getsockopt, int,\n                  (int fd, int level, int optname,\n                   void *restrict optval, socklen_t *restrict optlen)\n                  _GL_ARG_NONNULL ((4, 5)));\n_GL_CXXALIAS_RPL (getsockopt, int,\n                  (int fd, int level, int optname,\n                   void *restrict optval, socklen_t *restrict optlen));\n# else\n/* Need to cast, because on Solaris 10 systems, the fifth parameter is\n                                                       void *optlen.  */\n_GL_CXXALIAS_SYS_CAST (getsockopt, int,\n                       (int fd, int level, int optname,\n                        void *restrict optval, socklen_t *restrict optlen));\n# endif\n_GL_CXXALIASWARN (getsockopt);\n#elif @HAVE_WINSOCK2_H@\n# undef getsockopt\n# define getsockopt getsockopt_used_without_requesting_gnulib_module_getsockopt\n#elif defined GNULIB_POSIXCHECK\n# undef getsockopt\n# if HAVE_RAW_DECL_GETSOCKOPT\n_GL_WARN_ON_USE (getsockopt, \"getsockopt is not always POSIX compliant - \"\n                 \"use gnulib module getsockopt for portability\");\n# endif\n#endif\n\n#if @GNULIB_LISTEN@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef listen\n#   define listen rpl_listen\n#  endif\n_GL_FUNCDECL_RPL (listen, int, (int fd, int backlog));\n_GL_CXXALIAS_RPL (listen, int, (int fd, int backlog));\n# else\n_GL_CXXALIAS_SYS (listen, int, (int fd, int backlog));\n# endif\n_GL_CXXALIASWARN (listen);\n#elif @HAVE_WINSOCK2_H@\n# undef listen\n# define listen listen_used_without_requesting_gnulib_module_listen\n#elif defined GNULIB_POSIXCHECK\n# undef listen\n# if HAVE_RAW_DECL_LISTEN\n_GL_WARN_ON_USE (listen, \"listen is not always POSIX compliant - \"\n                 \"use gnulib module listen for portability\");\n# endif\n#endif\n\n#if @GNULIB_RECV@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef recv\n#   define recv rpl_recv\n#  endif\n_GL_FUNCDECL_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags)\n                                 _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (recv, ssize_t, (int fd, void *buf, size_t len, int flags));\n# else\n/* Need to cast, because on HP-UX 11.31 the return type may be\n                             int,\n   depending on compiler options.  */\n_GL_CXXALIAS_SYS_CAST (recv, ssize_t, (int fd, void *buf, size_t len, int flags));\n# endif\n_GL_CXXALIASWARN (recv);\n#elif @HAVE_WINSOCK2_H@\n# undef recv\n# define recv recv_used_without_requesting_gnulib_module_recv\n#elif defined GNULIB_POSIXCHECK\n# undef recv\n# if HAVE_RAW_DECL_RECV\n_GL_WARN_ON_USE (recv, \"recv is not always POSIX compliant - \"\n                 \"use gnulib module recv for portability\");\n# endif\n#endif\n\n#if @GNULIB_SEND@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef send\n#   define send rpl_send\n#  endif\n_GL_FUNCDECL_RPL (send, ssize_t,\n                  (int fd, const void *buf, size_t len, int flags)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (send, ssize_t,\n                  (int fd, const void *buf, size_t len, int flags));\n# else\n/* Need to cast, because on HP-UX 11.31 the return type may be\n                             int,\n   depending on compiler options.  */\n_GL_CXXALIAS_SYS_CAST (send, ssize_t,\n                       (int fd, const void *buf, size_t len, int flags));\n# endif\n_GL_CXXALIASWARN (send);\n#elif @HAVE_WINSOCK2_H@\n# undef send\n# define send send_used_without_requesting_gnulib_module_send\n#elif defined GNULIB_POSIXCHECK\n# undef send\n# if HAVE_RAW_DECL_SEND\n_GL_WARN_ON_USE (send, \"send is not always POSIX compliant - \"\n                 \"use gnulib module send for portability\");\n# endif\n#endif\n\n#if @GNULIB_RECVFROM@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef recvfrom\n#   define recvfrom rpl_recvfrom\n#  endif\n_GL_FUNCDECL_RPL (recvfrom, ssize_t,\n                  (int fd, void *restrict buf, size_t len, int flags,\n                   struct sockaddr *restrict from,\n                   socklen_t *restrict fromlen)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (recvfrom, ssize_t,\n                  (int fd, void *restrict buf, size_t len, int flags,\n                   struct sockaddr *restrict from,\n                   socklen_t *restrict fromlen));\n# else\n/* Need to cast, because on Solaris 10 systems, the sixth parameter is\n                                               void *fromlen.  */\n_GL_CXXALIAS_SYS_CAST (recvfrom, ssize_t,\n                       (int fd, void *restrict buf, size_t len, int flags,\n                        struct sockaddr *restrict from,\n                        socklen_t *restrict fromlen));\n# endif\n_GL_CXXALIASWARN (recvfrom);\n#elif @HAVE_WINSOCK2_H@\n# undef recvfrom\n# define recvfrom recvfrom_used_without_requesting_gnulib_module_recvfrom\n#elif defined GNULIB_POSIXCHECK\n# undef recvfrom\n# if HAVE_RAW_DECL_RECVFROM\n_GL_WARN_ON_USE (recvfrom, \"recvfrom is not always POSIX compliant - \"\n                 \"use gnulib module recvfrom for portability\");\n# endif\n#endif\n\n#if @GNULIB_SENDTO@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef sendto\n#   define sendto rpl_sendto\n#  endif\n_GL_FUNCDECL_RPL (sendto, ssize_t,\n                  (int fd, const void *buf, size_t len, int flags,\n                   const struct sockaddr *to, socklen_t tolen)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (sendto, ssize_t,\n                  (int fd, const void *buf, size_t len, int flags,\n                   const struct sockaddr *to, socklen_t tolen));\n# else\n/* Need to cast, because on NonStop Kernel, the sixth parameter is\n                                                   size_t tolen.  */\n_GL_CXXALIAS_SYS_CAST (sendto, ssize_t,\n                       (int fd, const void *buf, size_t len, int flags,\n                        const struct sockaddr *to, socklen_t tolen));\n# endif\n_GL_CXXALIASWARN (sendto);\n#elif @HAVE_WINSOCK2_H@\n# undef sendto\n# define sendto sendto_used_without_requesting_gnulib_module_sendto\n#elif defined GNULIB_POSIXCHECK\n# undef sendto\n# if HAVE_RAW_DECL_SENDTO\n_GL_WARN_ON_USE (sendto, \"sendto is not always POSIX compliant - \"\n                 \"use gnulib module sendto for portability\");\n# endif\n#endif\n\n#if @GNULIB_SETSOCKOPT@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef setsockopt\n#   define setsockopt rpl_setsockopt\n#  endif\n_GL_FUNCDECL_RPL (setsockopt, int, (int fd, int level, int optname,\n                                    const void * optval, socklen_t optlen)\n                                   _GL_ARG_NONNULL ((4)));\n_GL_CXXALIAS_RPL (setsockopt, int, (int fd, int level, int optname,\n                                    const void * optval, socklen_t optlen));\n# else\n/* Need to cast, because on NonStop Kernel, the fifth parameter is\n                                             size_t optlen.  */\n_GL_CXXALIAS_SYS_CAST (setsockopt, int,\n                       (int fd, int level, int optname,\n                        const void * optval, socklen_t optlen));\n# endif\n_GL_CXXALIASWARN (setsockopt);\n#elif @HAVE_WINSOCK2_H@\n# undef setsockopt\n# define setsockopt setsockopt_used_without_requesting_gnulib_module_setsockopt\n#elif defined GNULIB_POSIXCHECK\n# undef setsockopt\n# if HAVE_RAW_DECL_SETSOCKOPT\n_GL_WARN_ON_USE (setsockopt, \"setsockopt is not always POSIX compliant - \"\n                 \"use gnulib module setsockopt for portability\");\n# endif\n#endif\n\n#if @GNULIB_SHUTDOWN@\n# if @HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef shutdown\n#   define shutdown rpl_shutdown\n#  endif\n_GL_FUNCDECL_RPL (shutdown, int, (int fd, int how));\n_GL_CXXALIAS_RPL (shutdown, int, (int fd, int how));\n# else\n_GL_CXXALIAS_SYS (shutdown, int, (int fd, int how));\n# endif\n_GL_CXXALIASWARN (shutdown);\n#elif @HAVE_WINSOCK2_H@\n# undef shutdown\n# define shutdown shutdown_used_without_requesting_gnulib_module_shutdown\n#elif defined GNULIB_POSIXCHECK\n# undef shutdown\n# if HAVE_RAW_DECL_SHUTDOWN\n_GL_WARN_ON_USE (shutdown, \"shutdown is not always POSIX compliant - \"\n                 \"use gnulib module shutdown for portability\");\n# endif\n#endif\n\n#if @GNULIB_ACCEPT4@\n/* Accept a connection on a socket, with specific opening flags.\n   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>)\n   and O_TEXT, O_BINARY (defined in \"binary-io.h\").\n   See also the Linux man page at\n   <https://www.kernel.org/doc/man-pages/online/pages/man2/accept4.2.html>.  */\n# if @HAVE_ACCEPT4@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define accept4 rpl_accept4\n#  endif\n_GL_FUNCDECL_RPL (accept4, int,\n                  (int sockfd, struct sockaddr *addr, socklen_t *addrlen,\n                   int flags));\n_GL_CXXALIAS_RPL (accept4, int,\n                  (int sockfd, struct sockaddr *addr, socklen_t *addrlen,\n                   int flags));\n# else\n_GL_FUNCDECL_SYS (accept4, int,\n                  (int sockfd, struct sockaddr *addr, socklen_t *addrlen,\n                   int flags));\n_GL_CXXALIAS_SYS (accept4, int,\n                  (int sockfd, struct sockaddr *addr, socklen_t *addrlen,\n                   int flags));\n# endif\n_GL_CXXALIASWARN (accept4);\n#elif defined GNULIB_POSIXCHECK\n# undef accept4\n# if HAVE_RAW_DECL_ACCEPT4\n_GL_WARN_ON_USE (accept4, \"accept4 is unportable - \"\n                 \"use gnulib module accept4 for portability\");\n# endif\n#endif\n\n_GL_INLINE_HEADER_END\n\n#endif /* _@GUARD_PREFIX@_SYS_SOCKET_H */\n#endif /* _@GUARD_PREFIX@_SYS_SOCKET_H */\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_stat.in.h",
    "content": "/* Provide a more complete sys/stat.h header file.\n   Copyright (C) 2005-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Eric Blake, Paul Eggert, and Jim Meyering.  */\n\n/* This file is supposed to be used on platforms where <sys/stat.h> is\n   incomplete.  It is intended to provide definitions and prototypes\n   needed by an application.  Start with what the system provides.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined __need_system_sys_stat_h\n/* Special invocation convention.  */\n\n#@INCLUDE_NEXT@ @NEXT_SYS_STAT_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_SYS_STAT_H\n\n/* Get nlink_t.\n   May also define off_t to a 64-bit type on native Windows.  */\n#include <sys/types.h>\n\n/* Get struct timespec.  */\n#include <time.h>\n\n/* The include_next requires a split double-inclusion guard.  */\n#@INCLUDE_NEXT@ @NEXT_SYS_STAT_H@\n\n#ifndef _@GUARD_PREFIX@_SYS_STAT_H\n#define _@GUARD_PREFIX@_SYS_STAT_H\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n/* Before doing \"#define mknod rpl_mknod\" below, we need to include all\n   headers that may declare mknod().  OS/2 kLIBC declares mknod() in\n   <unistd.h>, not in <sys/stat.h>.  */\n#ifdef __KLIBC__\n# include <unistd.h>\n#endif\n\n/* Before doing \"#define mkdir rpl_mkdir\" below, we need to include all\n   headers that may declare mkdir().  Native Windows platforms declare mkdir\n   in <io.h> and/or <direct.h>, not in <sys/stat.h>.  */\n#if defined _WIN32 && ! defined __CYGWIN__\n# include <io.h>     /* mingw32, mingw64 */\n# include <direct.h> /* mingw64, MSVC 9 */\n#endif\n\n/* Native Windows platforms declare umask() in <io.h>.  */\n#if 0 && (defined _WIN32 && ! defined __CYGWIN__)\n# include <io.h>\n#endif\n\n/* Large File Support on native Windows.  */\n#if @WINDOWS_64_BIT_ST_SIZE@\n# define stat _stati64\n#endif\n\n/* Optionally, override 'struct stat' on native Windows.  */\n#if @GNULIB_OVERRIDES_STRUCT_STAT@\n\n# undef stat\n# if @GNULIB_STAT@\n#  define stat rpl_stat\n# else\n   /* Provoke a clear link error if stat() is used as a function and\n      module 'stat' is not in use.  */\n#  define stat stat_used_without_requesting_gnulib_module_stat\n# endif\n\n# if !GNULIB_defined_struct_stat\nstruct stat\n{\n  dev_t st_dev;\n  ino_t st_ino;\n  mode_t st_mode;\n  nlink_t st_nlink;\n#  if 0\n  uid_t st_uid;\n#  else /* uid_t is not defined by default on native Windows.  */\n  short st_uid;\n#  endif\n#  if 0\n  gid_t st_gid;\n#  else /* gid_t is not defined by default on native Windows.  */\n  short st_gid;\n#  endif\n  dev_t st_rdev;\n  off_t st_size;\n#  if 0\n  blksize_t st_blksize;\n  blkcnt_t st_blocks;\n#  endif\n\n#  if @WINDOWS_STAT_TIMESPEC@\n  struct timespec st_atim;\n  struct timespec st_mtim;\n  struct timespec st_ctim;\n#  else\n  time_t st_atime;\n  time_t st_mtime;\n  time_t st_ctime;\n#  endif\n};\n#  if @WINDOWS_STAT_TIMESPEC@\n#   define st_atime st_atim.tv_sec\n#   define st_mtime st_mtim.tv_sec\n#   define st_ctime st_ctim.tv_sec\n    /* Indicator, for gnulib internal purposes.  */\n#   define _GL_WINDOWS_STAT_TIMESPEC 1\n#  endif\n#  define GNULIB_defined_struct_stat 1\n# endif\n\n/* Other possible values of st_mode.  */\n# if 0\n#  define _S_IFBLK  0x6000\n# endif\n# if 0\n#  define _S_IFLNK  0xA000\n# endif\n# if 0\n#  define _S_IFSOCK 0xC000\n# endif\n\n#endif\n\n#ifndef S_IFIFO\n# ifdef _S_IFIFO\n#  define S_IFIFO _S_IFIFO\n# endif\n#endif\n\n#ifndef S_IFMT\n# define S_IFMT 0170000\n#endif\n\n#if STAT_MACROS_BROKEN\n# undef S_ISBLK\n# undef S_ISCHR\n# undef S_ISDIR\n# undef S_ISFIFO\n# undef S_ISLNK\n# undef S_ISNAM\n# undef S_ISMPB\n# undef S_ISMPC\n# undef S_ISNWK\n# undef S_ISREG\n# undef S_ISSOCK\n#endif\n\n#ifndef S_ISBLK\n# ifdef S_IFBLK\n#  define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)\n# else\n#  define S_ISBLK(m) 0\n# endif\n#endif\n\n#ifndef S_ISCHR\n# ifdef S_IFCHR\n#  define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)\n# else\n#  define S_ISCHR(m) 0\n# endif\n#endif\n\n#ifndef S_ISDIR\n# ifdef S_IFDIR\n#  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)\n# else\n#  define S_ISDIR(m) 0\n# endif\n#endif\n\n#ifndef S_ISDOOR /* Solaris 2.5 and up */\n# define S_ISDOOR(m) 0\n#endif\n\n#ifndef S_ISFIFO\n# ifdef S_IFIFO\n#  define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)\n# else\n#  define S_ISFIFO(m) 0\n# endif\n#endif\n\n#ifndef S_ISLNK\n# ifdef S_IFLNK\n#  define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)\n# else\n#  define S_ISLNK(m) 0\n# endif\n#endif\n\n#ifndef S_ISMPB /* V7 */\n# ifdef S_IFMPB\n#  define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)\n#  define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)\n# else\n#  define S_ISMPB(m) 0\n#  define S_ISMPC(m) 0\n# endif\n#endif\n\n#ifndef S_ISMPX /* AIX */\n# define S_ISMPX(m) 0\n#endif\n\n#ifndef S_ISNAM /* Xenix */\n# ifdef S_IFNAM\n#  define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM)\n# else\n#  define S_ISNAM(m) 0\n# endif\n#endif\n\n#ifndef S_ISNWK /* HP/UX */\n# ifdef S_IFNWK\n#  define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)\n# else\n#  define S_ISNWK(m) 0\n# endif\n#endif\n\n#ifndef S_ISPORT /* Solaris 10 and up */\n# define S_ISPORT(m) 0\n#endif\n\n#ifndef S_ISREG\n# ifdef S_IFREG\n#  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)\n# else\n#  define S_ISREG(m) 0\n# endif\n#endif\n\n#ifndef S_ISSOCK\n# ifdef S_IFSOCK\n#  define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)\n# else\n#  define S_ISSOCK(m) 0\n# endif\n#endif\n\n\n#ifndef S_TYPEISMQ\n# define S_TYPEISMQ(p) 0\n#endif\n\n#ifndef S_TYPEISTMO\n# define S_TYPEISTMO(p) 0\n#endif\n\n\n#ifndef S_TYPEISSEM\n# ifdef S_INSEM\n#  define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM)\n# else\n#  define S_TYPEISSEM(p) 0\n# endif\n#endif\n\n#ifndef S_TYPEISSHM\n# ifdef S_INSHD\n#  define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD)\n# else\n#  define S_TYPEISSHM(p) 0\n# endif\n#endif\n\n/* high performance (\"contiguous data\") */\n#ifndef S_ISCTG\n# define S_ISCTG(p) 0\n#endif\n\n/* Cray DMF (data migration facility): off line, with data  */\n#ifndef S_ISOFD\n# define S_ISOFD(p) 0\n#endif\n\n/* Cray DMF (data migration facility): off line, with no data  */\n#ifndef S_ISOFL\n# define S_ISOFL(p) 0\n#endif\n\n/* 4.4BSD whiteout */\n#ifndef S_ISWHT\n# define S_ISWHT(m) 0\n#endif\n\n/* If any of the following are undefined,\n   define them to their de facto standard values.  */\n#if !S_ISUID\n# define S_ISUID 04000\n#endif\n#if !S_ISGID\n# define S_ISGID 02000\n#endif\n\n/* S_ISVTX is a common extension to POSIX.  */\n#ifndef S_ISVTX\n# define S_ISVTX 01000\n#endif\n\n#if !S_IRUSR && S_IREAD\n# define S_IRUSR S_IREAD\n#endif\n#if !S_IRUSR\n# define S_IRUSR 00400\n#endif\n#if !S_IRGRP\n# define S_IRGRP (S_IRUSR >> 3)\n#endif\n#if !S_IROTH\n# define S_IROTH (S_IRUSR >> 6)\n#endif\n\n#if !S_IWUSR && S_IWRITE\n# define S_IWUSR S_IWRITE\n#endif\n#if !S_IWUSR\n# define S_IWUSR 00200\n#endif\n#if !S_IWGRP\n# define S_IWGRP (S_IWUSR >> 3)\n#endif\n#if !S_IWOTH\n# define S_IWOTH (S_IWUSR >> 6)\n#endif\n\n#if !S_IXUSR && S_IEXEC\n# define S_IXUSR S_IEXEC\n#endif\n#if !S_IXUSR\n# define S_IXUSR 00100\n#endif\n#if !S_IXGRP\n# define S_IXGRP (S_IXUSR >> 3)\n#endif\n#if !S_IXOTH\n# define S_IXOTH (S_IXUSR >> 6)\n#endif\n\n#if !S_IRWXU\n# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)\n#endif\n#if !S_IRWXG\n# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)\n#endif\n#if !S_IRWXO\n# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)\n#endif\n\n/* Although S_IXUGO and S_IRWXUGO are not specified by POSIX and are\n   not implemented in GNU/Linux, some Gnulib-using apps use the macros.  */\n#if !S_IXUGO\n# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)\n#endif\n#ifndef S_IRWXUGO\n# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)\n#endif\n\n/* Macros for futimens and utimensat.  */\n#ifndef UTIME_NOW\n# define UTIME_NOW (-1)\n# define UTIME_OMIT (-2)\n#endif\n\n\n#if @GNULIB_MDA_CHMOD@\n/* On native Windows, map 'chmod' to '_chmod', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::chmod always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef chmod\n#   define chmod _chmod\n#  endif\n/* Need to cast, because in mingw the last argument is 'int mode'.  */\n_GL_CXXALIAS_MDA_CAST (chmod, int, (const char *filename, mode_t mode));\n# else\n_GL_CXXALIAS_SYS (chmod, int, (const char *filename, mode_t mode));\n# endif\n_GL_CXXALIASWARN (chmod);\n#endif\n\n\n#if @GNULIB_FCHMODAT@\n# if @REPLACE_FCHMODAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fchmodat\n#   define fchmodat rpl_fchmodat\n#  endif\n_GL_FUNCDECL_RPL (fchmodat, int,\n                  (int fd, char const *file, mode_t mode, int flag)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (fchmodat, int,\n                  (int fd, char const *file, mode_t mode, int flag));\n# else\n#  if !@HAVE_FCHMODAT@\n_GL_FUNCDECL_SYS (fchmodat, int,\n                  (int fd, char const *file, mode_t mode, int flag)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (fchmodat, int,\n                  (int fd, char const *file, mode_t mode, int flag));\n# endif\n_GL_CXXALIASWARN (fchmodat);\n#elif defined GNULIB_POSIXCHECK\n# undef fchmodat\n# if HAVE_RAW_DECL_FCHMODAT\n_GL_WARN_ON_USE (fchmodat, \"fchmodat is not portable - \"\n                 \"use gnulib module openat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FSTAT@\n# if @REPLACE_FSTAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fstat\n#   define fstat rpl_fstat\n#  endif\n_GL_FUNCDECL_RPL (fstat, int, (int fd, struct stat *buf) _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (fstat, int, (int fd, struct stat *buf));\n# else\n_GL_CXXALIAS_SYS (fstat, int, (int fd, struct stat *buf));\n# endif\n# if __GLIBC__ >= 2\n_GL_CXXALIASWARN (fstat);\n# endif\n#elif @GNULIB_OVERRIDES_STRUCT_STAT@\n# undef fstat\n# define fstat fstat_used_without_requesting_gnulib_module_fstat\n#elif @WINDOWS_64_BIT_ST_SIZE@\n/* Above, we define stat to _stati64.  */\n# define fstat _fstati64\n#elif defined GNULIB_POSIXCHECK\n# undef fstat\n# if HAVE_RAW_DECL_FSTAT\n_GL_WARN_ON_USE (fstat, \"fstat has portability problems - \"\n                 \"use gnulib module fstat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FSTATAT@\n# if @REPLACE_FSTATAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fstatat\n#   define fstatat rpl_fstatat\n#  endif\n_GL_FUNCDECL_RPL (fstatat, int,\n                  (int fd, char const *restrict name, struct stat *restrict st,\n                   int flags)\n                  _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_RPL (fstatat, int,\n                  (int fd, char const *restrict name, struct stat *restrict st,\n                   int flags));\n# else\n#  if !@HAVE_FSTATAT@\n_GL_FUNCDECL_SYS (fstatat, int,\n                  (int fd, char const *restrict name, struct stat *restrict st,\n                   int flags)\n                  _GL_ARG_NONNULL ((2, 3)));\n#  endif\n_GL_CXXALIAS_SYS (fstatat, int,\n                  (int fd, char const *restrict name, struct stat *restrict st,\n                   int flags));\n# endif\n_GL_CXXALIASWARN (fstatat);\n#elif @GNULIB_OVERRIDES_STRUCT_STAT@\n# undef fstatat\n# define fstatat fstatat_used_without_requesting_gnulib_module_fstatat\n#elif defined GNULIB_POSIXCHECK\n# undef fstatat\n# if HAVE_RAW_DECL_FSTATAT\n_GL_WARN_ON_USE (fstatat, \"fstatat is not portable - \"\n                 \"use gnulib module openat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FUTIMENS@\n/* Use the rpl_ prefix also on Solaris <= 9, because on Solaris 9 our futimens\n   implementation relies on futimesat, which on Solaris 10 makes an invocation\n   to futimens that is meant to invoke the libc's futimens(), not gnulib's\n   futimens().  */\n# if @REPLACE_FUTIMENS@ || (!@HAVE_FUTIMENS@ && defined __sun)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef futimens\n#   define futimens rpl_futimens\n#  endif\n_GL_FUNCDECL_RPL (futimens, int, (int fd, struct timespec const times[2]));\n_GL_CXXALIAS_RPL (futimens, int, (int fd, struct timespec const times[2]));\n# else\n#  if !@HAVE_FUTIMENS@\n_GL_FUNCDECL_SYS (futimens, int, (int fd, struct timespec const times[2]));\n#  endif\n_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2]));\n# endif\n# if @HAVE_FUTIMENS@\n_GL_CXXALIASWARN (futimens);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef futimens\n# if HAVE_RAW_DECL_FUTIMENS\n_GL_WARN_ON_USE (futimens, \"futimens is not portable - \"\n                 \"use gnulib module futimens for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETUMASK@\n# if !@HAVE_GETUMASK@\n_GL_FUNCDECL_SYS (getumask, mode_t, (void));\n# endif\n_GL_CXXALIAS_SYS (getumask, mode_t, (void));\n# if @HAVE_GETUMASK@\n_GL_CXXALIASWARN (getumask);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef getumask\n# if HAVE_RAW_DECL_GETUMASK\n_GL_WARN_ON_USE (getumask, \"getumask is not portable - \"\n                 \"use gnulib module getumask for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_LCHMOD@\n/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME\n   denotes a symbolic link.  */\n# if !@HAVE_LCHMOD@ || defined __hpux\n_GL_FUNCDECL_SYS (lchmod, int, (const char *filename, mode_t mode)\n                               _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (lchmod, int, (const char *filename, mode_t mode));\n_GL_CXXALIASWARN (lchmod);\n#elif defined GNULIB_POSIXCHECK\n# undef lchmod\n# if HAVE_RAW_DECL_LCHMOD\n_GL_WARN_ON_USE (lchmod, \"lchmod is unportable - \"\n                 \"use gnulib module lchmod for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_LSTAT@\n# if ! @HAVE_LSTAT@\n/* mingw does not support symlinks, therefore it does not have lstat.  But\n   without links, stat does just fine.  */\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define lstat stat\n#  endif\n_GL_CXXALIAS_RPL_1 (lstat, stat, int,\n                    (const char *restrict name, struct stat *restrict buf));\n# elif @REPLACE_LSTAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef lstat\n#   define lstat rpl_lstat\n#  endif\n_GL_FUNCDECL_RPL (lstat, int,\n                  (const char *restrict name, struct stat *restrict buf)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (lstat, int,\n                  (const char *restrict name, struct stat *restrict buf));\n# else\n_GL_CXXALIAS_SYS (lstat, int,\n                  (const char *restrict name, struct stat *restrict buf));\n# endif\n# if @HAVE_LSTAT@\n_GL_CXXALIASWARN (lstat);\n# endif\n#elif @GNULIB_OVERRIDES_STRUCT_STAT@\n# undef lstat\n# define lstat lstat_used_without_requesting_gnulib_module_lstat\n#elif defined GNULIB_POSIXCHECK\n# undef lstat\n# if HAVE_RAW_DECL_LSTAT\n_GL_WARN_ON_USE (lstat, \"lstat is unportable - \"\n                 \"use gnulib module lstat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MKDIR@\n# if @REPLACE_MKDIR@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mkdir\n#   define mkdir rpl_mkdir\n#  endif\n_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));\n# elif defined _WIN32 && !defined __CYGWIN__\n/* mingw's _mkdir() function has 1 argument, but we pass 2 arguments.\n   Additionally, it declares _mkdir (and depending on compile flags, an\n   alias mkdir), only in the nonstandard includes <direct.h> and <io.h>,\n   which are included above.  */\n#  if !GNULIB_defined_rpl_mkdir\nstatic int\nrpl_mkdir (char const *name, mode_t mode)\n{\n  return _mkdir (name);\n}\n#   define GNULIB_defined_rpl_mkdir 1\n#  endif\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mkdir\n#   define mkdir rpl_mkdir\n#  endif\n_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));\n# else\n_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode));\n# endif\n_GL_CXXALIASWARN (mkdir);\n#elif defined GNULIB_POSIXCHECK\n# undef mkdir\n# if HAVE_RAW_DECL_MKDIR\n_GL_WARN_ON_USE (mkdir, \"mkdir does not always support two parameters - \"\n                 \"use gnulib module mkdir for portability\");\n# endif\n#elif @GNULIB_MDA_MKDIR@\n/* On native Windows, map 'mkdir' to '_mkdir', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::mkdir always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !GNULIB_defined_rpl_mkdir\nstatic int\nrpl_mkdir (char const *name, mode_t mode)\n{\n  return _mkdir (name);\n}\n#   define GNULIB_defined_rpl_mkdir 1\n#  endif\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mkdir\n#   define mkdir rpl_mkdir\n#  endif\n_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));\n# else\n_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode));\n# endif\n_GL_CXXALIASWARN (mkdir);\n#endif\n\n\n#if @GNULIB_MKDIRAT@\n# if !@HAVE_MKDIRAT@\n_GL_FUNCDECL_SYS (mkdirat, int, (int fd, char const *file, mode_t mode)\n                                _GL_ARG_NONNULL ((2)));\n# endif\n_GL_CXXALIAS_SYS (mkdirat, int, (int fd, char const *file, mode_t mode));\n_GL_CXXALIASWARN (mkdirat);\n#elif defined GNULIB_POSIXCHECK\n# undef mkdirat\n# if HAVE_RAW_DECL_MKDIRAT\n_GL_WARN_ON_USE (mkdirat, \"mkdirat is not portable - \"\n                 \"use gnulib module openat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MKFIFO@\n# if @REPLACE_MKFIFO@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mkfifo\n#   define mkfifo rpl_mkfifo\n#  endif\n_GL_FUNCDECL_RPL (mkfifo, int, (char const *file, mode_t mode)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (mkfifo, int, (char const *file, mode_t mode));\n# else\n#  if !@HAVE_MKFIFO@\n_GL_FUNCDECL_SYS (mkfifo, int, (char const *file, mode_t mode)\n                               _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (mkfifo, int, (char const *file, mode_t mode));\n# endif\n_GL_CXXALIASWARN (mkfifo);\n#elif defined GNULIB_POSIXCHECK\n# undef mkfifo\n# if HAVE_RAW_DECL_MKFIFO\n_GL_WARN_ON_USE (mkfifo, \"mkfifo is not portable - \"\n                 \"use gnulib module mkfifo for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MKFIFOAT@\n# if @REPLACE_MKFIFOAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mkfifoat\n#   define mkfifoat rpl_mkfifoat\n#  endif\n_GL_FUNCDECL_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode)\n                                 _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (mkfifoat, int, (int fd, char const *file, mode_t mode));\n# else\n#  if !@HAVE_MKFIFOAT@\n_GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)\n                                 _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode));\n# endif\n_GL_CXXALIASWARN (mkfifoat);\n#elif defined GNULIB_POSIXCHECK\n# undef mkfifoat\n# if HAVE_RAW_DECL_MKFIFOAT\n_GL_WARN_ON_USE (mkfifoat, \"mkfifoat is not portable - \"\n                 \"use gnulib module mkfifoat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MKNOD@\n# if @REPLACE_MKNOD@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mknod\n#   define mknod rpl_mknod\n#  endif\n_GL_FUNCDECL_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev)\n                              _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev));\n# else\n#  if !@HAVE_MKNOD@\n_GL_FUNCDECL_SYS (mknod, int, (char const *file, mode_t mode, dev_t dev)\n                              _GL_ARG_NONNULL ((1)));\n#  endif\n/* Need to cast, because on OSF/1 5.1, the third parameter is '...'.  */\n_GL_CXXALIAS_SYS_CAST (mknod, int, (char const *file, mode_t mode, dev_t dev));\n# endif\n_GL_CXXALIASWARN (mknod);\n#elif defined GNULIB_POSIXCHECK\n# undef mknod\n# if HAVE_RAW_DECL_MKNOD\n_GL_WARN_ON_USE (mknod, \"mknod is not portable - \"\n                 \"use gnulib module mknod for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MKNODAT@\n# if @REPLACE_MKNODAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef mknodat\n#   define mknodat rpl_mknodat\n#  endif\n_GL_FUNCDECL_RPL (mknodat, int,\n                  (int fd, char const *file, mode_t mode, dev_t dev)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (mknodat, int,\n                  (int fd, char const *file, mode_t mode, dev_t dev));\n# else\n#  if !@HAVE_MKNODAT@\n_GL_FUNCDECL_SYS (mknodat, int,\n                  (int fd, char const *file, mode_t mode, dev_t dev)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (mknodat, int,\n                  (int fd, char const *file, mode_t mode, dev_t dev));\n# endif\n_GL_CXXALIASWARN (mknodat);\n#elif defined GNULIB_POSIXCHECK\n# undef mknodat\n# if HAVE_RAW_DECL_MKNODAT\n_GL_WARN_ON_USE (mknodat, \"mknodat is not portable - \"\n                 \"use gnulib module mkfifoat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_STAT@\n# if @REPLACE_STAT@\n#  if !@GNULIB_OVERRIDES_STRUCT_STAT@\n    /* We can't use the object-like #define stat rpl_stat, because of\n       struct stat.  This means that rpl_stat will not be used if the user\n       does (stat)(a,b).  Oh well.  */\n#   if defined _AIX && defined stat && defined _LARGE_FILES\n     /* With _LARGE_FILES defined, AIX (only) defines stat to stat64,\n        so we have to replace stat64() instead of stat(). */\n#    undef stat64\n#    define stat64(name, st) rpl_stat (name, st)\n#   elif @WINDOWS_64_BIT_ST_SIZE@\n     /* Above, we define stat to _stati64.  */\n#    if defined __MINGW32__ && defined _stati64\n#     ifndef _USE_32BIT_TIME_T\n       /* The system headers define _stati64 to _stat64.  */\n#      undef _stat64\n#      define _stat64(name, st) rpl_stat (name, st)\n#     endif\n#    elif defined _MSC_VER && defined _stati64\n#     ifdef _USE_32BIT_TIME_T\n       /* The system headers define _stati64 to _stat32i64.  */\n#      undef _stat32i64\n#      define _stat32i64(name, st) rpl_stat (name, st)\n#     else\n       /* The system headers define _stati64 to _stat64.  */\n#      undef _stat64\n#      define _stat64(name, st) rpl_stat (name, st)\n#     endif\n#    else\n#     undef _stati64\n#     define _stati64(name, st) rpl_stat (name, st)\n#    endif\n#   elif defined __MINGW32__ && defined stat\n#    ifdef _USE_32BIT_TIME_T\n      /* The system headers define stat to _stat32i64.  */\n#     undef _stat32i64\n#     define _stat32i64(name, st) rpl_stat (name, st)\n#    else\n      /* The system headers define stat to _stat64.  */\n#     undef _stat64\n#     define _stat64(name, st) rpl_stat (name, st)\n#    endif\n#   elif defined _MSC_VER && defined stat\n#    ifdef _USE_32BIT_TIME_T\n      /* The system headers define stat to _stat32.  */\n#     undef _stat32\n#     define _stat32(name, st) rpl_stat (name, st)\n#    else\n      /* The system headers define stat to _stat64i32.  */\n#     undef _stat64i32\n#     define _stat64i32(name, st) rpl_stat (name, st)\n#    endif\n#   else /* !(_AIX || __MINGW32__ || _MSC_VER) */\n#    undef stat\n#    define stat(name, st) rpl_stat (name, st)\n#   endif /* !_LARGE_FILES */\n#  endif /* !@GNULIB_OVERRIDES_STRUCT_STAT@ */\n_GL_EXTERN_C int stat (const char *restrict name, struct stat *restrict buf)\n                      _GL_ARG_NONNULL ((1, 2));\n# endif\n#elif @GNULIB_OVERRIDES_STRUCT_STAT@\n/* see above:\n  #define stat stat_used_without_requesting_gnulib_module_stat\n */\n#elif defined GNULIB_POSIXCHECK\n# undef stat\n# if HAVE_RAW_DECL_STAT\n_GL_WARN_ON_USE (stat, \"stat is unportable - \"\n                 \"use gnulib module stat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MDA_UMASK@\n/* On native Windows, map 'umask' to '_umask', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::umask always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef umask\n#   define umask _umask\n#  endif\n/* Need to cast, because in mingw the last argument is 'int mode'.  */\n_GL_CXXALIAS_MDA_CAST (umask, mode_t, (mode_t mask));\n# else\n_GL_CXXALIAS_SYS (umask, mode_t, (mode_t mask));\n# endif\n_GL_CXXALIASWARN (umask);\n#endif\n\n\n#if @GNULIB_UTIMENSAT@\n/* Use the rpl_ prefix also on Solaris <= 9, because on Solaris 9 our utimensat\n   implementation relies on futimesat, which on Solaris 10 makes an invocation\n   to utimensat that is meant to invoke the libc's utimensat(), not gnulib's\n   utimensat().  */\n# if @REPLACE_UTIMENSAT@ || (!@HAVE_UTIMENSAT@ && defined __sun)\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef utimensat\n#   define utimensat rpl_utimensat\n#  endif\n_GL_FUNCDECL_RPL (utimensat, int, (int fd, char const *name,\n                                   struct timespec const times[2], int flag)\n                                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (utimensat, int, (int fd, char const *name,\n                                   struct timespec const times[2], int flag));\n# else\n#  if !@HAVE_UTIMENSAT@\n_GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name,\n                                   struct timespec const times[2], int flag)\n                                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name,\n                                   struct timespec const times[2], int flag));\n# endif\n# if @HAVE_UTIMENSAT@\n_GL_CXXALIASWARN (utimensat);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef utimensat\n# if HAVE_RAW_DECL_UTIMENSAT\n_GL_WARN_ON_USE (utimensat, \"utimensat is not portable - \"\n                 \"use gnulib module utimensat for portability\");\n# endif\n#endif\n\n\n#endif /* _@GUARD_PREFIX@_SYS_STAT_H */\n#endif /* _@GUARD_PREFIX@_SYS_STAT_H */\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_time.in.h",
    "content": "/* Provide a more complete sys/time.h.\n\n   Copyright (C) 2007-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paul Eggert.  */\n\n#ifndef _@GUARD_PREFIX@_SYS_TIME_H\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n/* On Cygwin and on many BSDish systems, <sys/time.h> includes itself\n   recursively via <sys/select.h>.\n   Simply delegate to the system's header in this case; it is a no-op.\n   Without this extra ifdef, the C++ gettimeofday declaration below\n   would be a forward declaration in gnulib's nested <sys/time.h>.  */\n#if defined _CYGWIN_SYS_TIME_H || defined _SYS_TIME_H || defined _SYS_TIME_H_\n# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@\n#else\n\n/* The include_next requires a split double-inclusion guard.  */\n#if @HAVE_SYS_TIME_H@\n# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@\n#endif\n\n#ifndef _@GUARD_PREFIX@_SYS_TIME_H\n#define _@GUARD_PREFIX@_SYS_TIME_H\n\n#if ! @HAVE_SYS_TIME_H@\n# include <time.h>\n#endif\n\n/* On native Windows with MSVC, get the 'struct timeval' type.\n   Also, on native Windows with a 64-bit time_t, where we are overriding the\n   'struct timeval' type, get all declarations of system functions whose\n   signature contains 'struct timeval'.  */\n#if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H\n# define _GL_INCLUDING_WINSOCK2_H\n# include <winsock2.h>\n# undef _GL_INCLUDING_WINSOCK2_H\n#endif\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@\n\n# if @REPLACE_STRUCT_TIMEVAL@\n#  define timeval rpl_timeval\n# endif\n\n# if !GNULIB_defined_struct_timeval\nstruct timeval\n{\n  time_t tv_sec;\n  long int tv_usec;\n};\n#  define GNULIB_defined_struct_timeval 1\n# endif\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#if @GNULIB_GETTIMEOFDAY@\n# if @REPLACE_GETTIMEOFDAY@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef gettimeofday\n#   define gettimeofday rpl_gettimeofday\n#  endif\n_GL_FUNCDECL_RPL (gettimeofday, int,\n                  (struct timeval *restrict, void *restrict)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (gettimeofday, int,\n                  (struct timeval *restrict, void *restrict));\n# else\n#  if !@HAVE_GETTIMEOFDAY@\n_GL_FUNCDECL_SYS (gettimeofday, int,\n                  (struct timeval *restrict, void *restrict)\n                  _GL_ARG_NONNULL ((1)));\n#  endif\n/* Need to cast, because on glibc systems, by default, the second argument is\n                                                  struct timezone *.  */\n_GL_CXXALIAS_SYS_CAST (gettimeofday, int,\n                       (struct timeval *restrict, void *restrict));\n# endif\n_GL_CXXALIASWARN (gettimeofday);\n# if defined __cplusplus && defined GNULIB_NAMESPACE\nnamespace GNULIB_NAMESPACE {\n  typedef ::timeval\n#  undef timeval\n    timeval;\n#  if @REPLACE_STRUCT_TIMEVAL@\n#   define timeval rpl_timeval\n  typedef ::timeval timeval;\n#  endif\n}\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef gettimeofday\n# if HAVE_RAW_DECL_GETTIMEOFDAY\n_GL_WARN_ON_USE (gettimeofday, \"gettimeofday is unportable - \"\n                 \"use gnulib module gettimeofday for portability\");\n# endif\n#endif\n\n/* Hide some function declarations from <winsock2.h>.  */\n\n#if defined _MSC_VER && @HAVE_WINSOCK2_H@\n# if !defined _@GUARD_PREFIX@_UNISTD_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef close\n#   define close close_used_without_including_unistd_h\n#  elif !defined __clang__\n     _GL_WARN_ON_USE (close,\n                      \"close() used without including <unistd.h>\");\n#  endif\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef gethostname\n#   define gethostname gethostname_used_without_including_unistd_h\n#  else\n     _GL_WARN_ON_USE (gethostname,\n                      \"gethostname() used without including <unistd.h>\");\n#  endif\n# endif\n# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef socket\n#   define socket              socket_used_without_including_sys_socket_h\n#   undef connect\n#   define connect             connect_used_without_including_sys_socket_h\n#   undef accept\n#   define accept              accept_used_without_including_sys_socket_h\n#   undef bind\n#   define bind                bind_used_without_including_sys_socket_h\n#   undef getpeername\n#   define getpeername         getpeername_used_without_including_sys_socket_h\n#   undef getsockname\n#   define getsockname         getsockname_used_without_including_sys_socket_h\n#   undef getsockopt\n#   define getsockopt          getsockopt_used_without_including_sys_socket_h\n#   undef listen\n#   define listen              listen_used_without_including_sys_socket_h\n#   undef recv\n#   define recv                recv_used_without_including_sys_socket_h\n#   undef send\n#   define send                send_used_without_including_sys_socket_h\n#   undef recvfrom\n#   define recvfrom            recvfrom_used_without_including_sys_socket_h\n#   undef sendto\n#   define sendto              sendto_used_without_including_sys_socket_h\n#   undef setsockopt\n#   define setsockopt          setsockopt_used_without_including_sys_socket_h\n#   undef shutdown\n#   define shutdown            shutdown_used_without_including_sys_socket_h\n#  else\n     _GL_WARN_ON_USE (socket,\n                      \"socket() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (connect,\n                      \"connect() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (accept,\n                      \"accept() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (bind,\n                      \"bind() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (getpeername,\n                      \"getpeername() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (getsockname,\n                      \"getsockname() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (getsockopt,\n                      \"getsockopt() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (listen,\n                      \"listen() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (recv,\n                      \"recv() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (send,\n                      \"send() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (recvfrom,\n                      \"recvfrom() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (sendto,\n                      \"sendto() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (setsockopt,\n                      \"setsockopt() used without including <sys/socket.h>\");\n     _GL_WARN_ON_USE (shutdown,\n                      \"shutdown() used without including <sys/socket.h>\");\n#  endif\n# endif\n# if !defined _@GUARD_PREFIX@_SYS_SELECT_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef select\n#   define select select_used_without_including_sys_select_h\n#  else\n     _GL_WARN_ON_USE (select,\n                      \"select() used without including <sys/select.h>\");\n#  endif\n# endif\n#endif\n\n#endif /* _@GUARD_PREFIX@_SYS_TIME_H */\n#endif /* _CYGWIN_SYS_TIME_H */\n#endif /* _@GUARD_PREFIX@_SYS_TIME_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_types.in.h",
    "content": "/* Provide a more complete sys/types.h.\n\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if defined _WIN32 && !defined __CYGWIN__ \\\n    && (defined __need_off_t || defined __need___off64_t \\\n        || defined __need_ssize_t || defined __need_time_t)\n\n/* Special invocation convention inside mingw header files.  */\n\n#@INCLUDE_NEXT@ @NEXT_SYS_TYPES_H@\n\n#else\n/* Normal invocation convention.  */\n\n#ifndef _@GUARD_PREFIX@_SYS_TYPES_H\n\n/* The include_next requires a split double-inclusion guard.  */\n# define _GL_INCLUDING_SYS_TYPES_H\n#@INCLUDE_NEXT@ @NEXT_SYS_TYPES_H@\n# undef _GL_INCLUDING_SYS_TYPES_H\n\n#ifndef _@GUARD_PREFIX@_SYS_TYPES_H\n#define _@GUARD_PREFIX@_SYS_TYPES_H\n\n/* Override off_t if Large File Support is requested on native Windows.  */\n#if @WINDOWS_64_BIT_OFF_T@\n/* Same as int64_t in <stdint.h>.  */\n# if defined _MSC_VER\n#  define off_t __int64\n# else\n#  define off_t long long int\n# endif\n/* Indicator, for gnulib internal purposes.  */\n# define _GL_WINDOWS_64_BIT_OFF_T 1\n#endif\n\n/* Override dev_t and ino_t if distinguishable inodes support is requested\n   on native Windows.  */\n#if @WINDOWS_STAT_INODES@\n\n# if @WINDOWS_STAT_INODES@ == 2\n/* Experimental, not useful in Windows 10.  */\n\n/* Define dev_t to a 64-bit type.  */\n#  if !defined GNULIB_defined_dev_t\ntypedef unsigned long long int rpl_dev_t;\n#   undef dev_t\n#   define dev_t rpl_dev_t\n#   define GNULIB_defined_dev_t 1\n#  endif\n\n/* Define ino_t to a 128-bit type.  */\n#  if !defined GNULIB_defined_ino_t\n/* MSVC does not have a 128-bit integer type.\n   GCC has a 128-bit integer type __int128, but only on 64-bit targets.  */\ntypedef struct { unsigned long long int _gl_ino[2]; } rpl_ino_t;\n#   undef ino_t\n#   define ino_t rpl_ino_t\n#   define GNULIB_defined_ino_t 1\n#  endif\n\n# else /* @WINDOWS_STAT_INODES@ == 1 */\n\n/* Define ino_t to a 64-bit type.  */\n#  if !defined GNULIB_defined_ino_t\ntypedef unsigned long long int rpl_ino_t;\n#   undef ino_t\n#   define ino_t rpl_ino_t\n#   define GNULIB_defined_ino_t 1\n#  endif\n\n# endif\n\n/* Indicator, for gnulib internal purposes.  */\n# define _GL_WINDOWS_STAT_INODES @WINDOWS_STAT_INODES@\n\n#endif\n\n/* MSVC 9 defines size_t in <stddef.h>, not in <sys/types.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if (defined _WIN32 && ! defined __CYGWIN__) && ! defined __GLIBC__\n# include <stddef.h>\n#endif\n\n#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */\n#endif /* _@GUARD_PREFIX@_SYS_TYPES_H */\n#endif /* __need_XXX */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_uio.in.h",
    "content": "/* Substitute for <sys/uio.h>.\n   Copyright (C) 2011-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n# if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n# endif\n@PRAGMA_COLUMNS@\n\n#ifndef _@GUARD_PREFIX@_SYS_UIO_H\n\n#if @HAVE_SYS_UIO_H@\n\n/* On OpenBSD 4.4, <sys/uio.h> assumes prior inclusion of <sys/types.h>.  */\n# include <sys/types.h>\n\n/* The include_next requires a split double-inclusion guard.  */\n# @INCLUDE_NEXT@ @NEXT_SYS_UIO_H@\n\n#endif\n\n#ifndef _@GUARD_PREFIX@_SYS_UIO_H\n#define _@GUARD_PREFIX@_SYS_UIO_H\n\n#if !@HAVE_SYS_UIO_H@\n/* A platform that lacks <sys/uio.h>.  */\n/* Get 'size_t' and 'ssize_t'.  */\n# include <sys/types.h>\n\n# ifdef __cplusplus\nextern \"C\" {\n# endif\n\n# if !GNULIB_defined_struct_iovec\n/* All known platforms that lack <sys/uio.h> also lack any declaration\n   of struct iovec in any other header.  */\nstruct iovec {\n  void *iov_base;\n  size_t iov_len;\n};\n#  define GNULIB_defined_struct_iovec 1\n# endif\n\n# ifdef __cplusplus\n}\n# endif\n\n#endif\n\n#endif /* _@GUARD_PREFIX@_SYS_UIO_H */\n#endif /* _@GUARD_PREFIX@_SYS_UIO_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/sys_utsname.in.h",
    "content": "/* Substitute for <sys/utsname.h>.\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _@GUARD_PREFIX@_SYS_UTSNAME_H\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if @HAVE_SYS_UTSNAME_H@\n\n/* Minix 3.1.8 has a bug: <stddef.h> must be included before <sys/utsname.h>.\n   But avoid namespace pollution on glibc systems.  */\n# if defined __minix && !defined __GLIBC__\n#  include <stddef.h>\n# endif\n\n# @INCLUDE_NEXT@ @NEXT_SYS_UTSNAME_H@\n\n#endif\n\n#define _@GUARD_PREFIX@_SYS_UTSNAME_H\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if !@HAVE_STRUCT_UTSNAME@\n/* Length of the entries in 'struct utsname' is 256.  */\n# define _UTSNAME_LENGTH 256\n\n# ifndef _UTSNAME_NODENAME_LENGTH\n#  define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH\n# endif\n# ifndef _UTSNAME_SYSNAME_LENGTH\n#  define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH\n# endif\n# ifndef _UTSNAME_RELEASE_LENGTH\n#  define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH\n# endif\n# ifndef _UTSNAME_VERSION_LENGTH\n#  define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH\n# endif\n# ifndef _UTSNAME_MACHINE_LENGTH\n#  define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH\n# endif\n\n# if !GNULIB_defined_struct_utsname\n/* Structure describing the system and machine.  */\nstruct utsname\n  {\n    /* Name of this node on the network.  */\n    char nodename[_UTSNAME_NODENAME_LENGTH];\n\n    /* Name of the implementation of the operating system.  */\n    char sysname[_UTSNAME_SYSNAME_LENGTH];\n    /* Current release level of this implementation.  */\n    char release[_UTSNAME_RELEASE_LENGTH];\n    /* Current version level of this release.  */\n    char version[_UTSNAME_VERSION_LENGTH];\n\n    /* Name of the hardware type the system is running on.  */\n    char machine[_UTSNAME_MACHINE_LENGTH];\n  };\n#  define GNULIB_defined_struct_utsname 1\n# endif\n\n#endif /* !@HAVE_STRUCT_UTSNAME@ */\n\n\n#if @GNULIB_UNAME@\n# if !@HAVE_UNAME@\nextern int uname (struct utsname *buf) _GL_ARG_NONNULL ((1));\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef uname\n# if HAVE_RAW_DECL_UNAME\n_GL_WARN_ON_USE (uname, \"uname is unportable - \"\n                 \"use gnulib module uname for portability\");\n# endif\n#endif\n\n\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif /* _@GUARD_PREFIX@_SYS_UTSNAME_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/time.in.h",
    "content": "/* A more-standard <time.h>.\n\n   Copyright (C) 2007-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n/* Don't get in the way of glibc when it includes time.h merely to\n   declare a few standard symbols, rather than to declare all the\n   symbols.  (However, skip this for MinGW as it treats __need_time_t\n   incompatibly.)  Also, Solaris 8 <time.h> eventually includes itself\n   recursively; if that is happening, just include the system <time.h>\n   without adding our own declarations.  */\n#if (((defined __need_time_t || defined __need_clock_t \\\n       || defined __need_timespec)                     \\\n      && !defined __MINGW32__)                         \\\n     || defined _@GUARD_PREFIX@_TIME_H)\n\n# @INCLUDE_NEXT@ @NEXT_TIME_H@\n\n#else\n\n# define _@GUARD_PREFIX@_TIME_H\n\n/* mingw's <time.h> provides the functions asctime_r, ctime_r, gmtime_r,\n   localtime_r only if <unistd.h> or <pthread.h> has been included before.  */\n# if defined __MINGW32__\n#  include <unistd.h>\n# endif\n\n# @INCLUDE_NEXT@ @NEXT_TIME_H@\n\n/* NetBSD 5.0 mis-defines NULL.  */\n# include <stddef.h>\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n/* Some systems don't define struct timespec (e.g., AIX 4.1).\n   Or they define it with the wrong member names or define it in <sys/time.h>\n   (e.g., FreeBSD circa 1997).  Stock Mingw prior to 3.0 does not define it,\n   but the pthreads-win32 library defines it in <pthread.h>.  */\n# if ! @TIME_H_DEFINES_STRUCT_TIMESPEC@\n#  if @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@\n#   include <sys/time.h>\n#  elif @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@\n#   include <pthread.h>\n#  elif @UNISTD_H_DEFINES_STRUCT_TIMESPEC@\n#   include <unistd.h>\n#  else\n\n#   ifdef __cplusplus\nextern \"C\" {\n#   endif\n\n#   if !GNULIB_defined_struct_timespec\n#    undef timespec\n#    define timespec rpl_timespec\nstruct timespec\n{\n  time_t tv_sec;\n  long int tv_nsec;\n};\n#    define GNULIB_defined_struct_timespec 1\n#   endif\n\n#   ifdef __cplusplus\n}\n#   endif\n\n#  endif\n# endif\n\n# if !GNULIB_defined_struct_time_t_must_be_integral\n/* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html\n   requires time_t to be an integer type, even though C99 permits floating\n   point.  We don't know of any implementation that uses floating\n   point, and it is much easier to write code that doesn't have to\n   worry about that corner case, so we force the issue.  */\nstruct __time_t_must_be_integral {\n  unsigned int __floating_time_t_unsupported : (time_t) 1;\n};\n#  define GNULIB_defined_struct_time_t_must_be_integral 1\n# endif\n\n/* Define TIME_UTC, a positive integer constant used for timespec_get().  */\n# if ! @TIME_H_DEFINES_TIME_UTC@\n#  if !GNULIB_defined_TIME_UTC\n#   define TIME_UTC 1\n#   define GNULIB_defined_TIME_UTC 1\n#  endif\n# endif\n\n/* Set *TS to the current time, and return BASE.\n   Upon failure, return 0.  */\n# if @GNULIB_TIMESPEC_GET@\n#  if ! @HAVE_TIMESPEC_GET@\n_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base)\n                                     _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base));\n_GL_CXXALIASWARN (timespec_get);\n# endif\n\n/* Sleep for at least RQTP seconds unless interrupted,  If interrupted,\n   return -1 and store the remaining time into RMTP.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html>.  */\n# if @GNULIB_NANOSLEEP@\n#  if @REPLACE_NANOSLEEP@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    define nanosleep rpl_nanosleep\n#   endif\n_GL_FUNCDECL_RPL (nanosleep, int,\n                  (struct timespec const *__rqtp, struct timespec *__rmtp)\n                  _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (nanosleep, int,\n                  (struct timespec const *__rqtp, struct timespec *__rmtp));\n#  else\n#   if ! @HAVE_NANOSLEEP@\n_GL_FUNCDECL_SYS (nanosleep, int,\n                  (struct timespec const *__rqtp, struct timespec *__rmtp)\n                  _GL_ARG_NONNULL ((1)));\n#   endif\n_GL_CXXALIAS_SYS (nanosleep, int,\n                  (struct timespec const *__rqtp, struct timespec *__rmtp));\n#  endif\n_GL_CXXALIASWARN (nanosleep);\n# endif\n\n/* Initialize time conversion information.  */\n# if @GNULIB_TZSET@\n#  if @REPLACE_TZSET@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef tzset\n#    define tzset rpl_tzset\n#   endif\n_GL_FUNCDECL_RPL (tzset, void, (void));\n_GL_CXXALIAS_RPL (tzset, void, (void));\n#  elif defined _WIN32 && !defined __CYGWIN__\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef tzset\n#    define tzset _tzset\n#   endif\n_GL_CXXALIAS_MDA (tzset, void, (void));\n#  else\n_GL_CXXALIAS_SYS (tzset, void, (void));\n#  endif\n_GL_CXXALIASWARN (tzset);\n# elif @GNULIB_MDA_TZSET@\n/* On native Windows, map 'tzset' to '_tzset', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::tzset always.  */\n#  if defined _WIN32 && !defined __CYGWIN__\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef tzset\n#    define tzset _tzset\n#   endif\n_GL_CXXALIAS_MDA (tzset, void, (void));\n#  else\n_GL_CXXALIAS_SYS (tzset, void, (void));\n#  endif\n_GL_CXXALIASWARN (tzset);\n# endif\n\n/* Return the 'time_t' representation of TP and normalize TP.  */\n# if @GNULIB_MKTIME@\n#  if @REPLACE_MKTIME@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    define mktime rpl_mktime\n#   endif\n_GL_FUNCDECL_RPL (mktime, time_t, (struct tm *__tp) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (mktime, time_t, (struct tm *__tp));\n#  else\n_GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp));\n#  endif\n#  if __GLIBC__ >= 2\n_GL_CXXALIASWARN (mktime);\n#  endif\n# endif\n\n/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime_r.html> and\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime_r.html>.  */\n# if @GNULIB_TIME_R@\n#  if @REPLACE_LOCALTIME_R@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef localtime_r\n#    define localtime_r rpl_localtime_r\n#   endif\n_GL_FUNCDECL_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,\n                                             struct tm *restrict __result)\n                                            _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,\n                                             struct tm *restrict __result));\n#  else\n#   if ! @HAVE_DECL_LOCALTIME_R@\n_GL_FUNCDECL_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,\n                                             struct tm *restrict __result)\n                                            _GL_ARG_NONNULL ((1, 2)));\n#   endif\n_GL_CXXALIAS_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,\n                                             struct tm *restrict __result));\n#  endif\n#  if @HAVE_DECL_LOCALTIME_R@\n_GL_CXXALIASWARN (localtime_r);\n#  endif\n#  if @REPLACE_LOCALTIME_R@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef gmtime_r\n#    define gmtime_r rpl_gmtime_r\n#   endif\n_GL_FUNCDECL_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,\n                                          struct tm *restrict __result)\n                                         _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,\n                                          struct tm *restrict __result));\n#  else\n#   if ! @HAVE_DECL_LOCALTIME_R@\n_GL_FUNCDECL_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,\n                                          struct tm *restrict __result)\n                                         _GL_ARG_NONNULL ((1, 2)));\n#   endif\n_GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,\n                                          struct tm *restrict __result));\n#  endif\n#  if @HAVE_DECL_LOCALTIME_R@\n_GL_CXXALIASWARN (gmtime_r);\n#  endif\n# endif\n\n/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime.html> and\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime.html>.  */\n# if @GNULIB_LOCALTIME@ || @REPLACE_LOCALTIME@\n#  if @REPLACE_LOCALTIME@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef localtime\n#    define localtime rpl_localtime\n#   endif\n_GL_FUNCDECL_RPL (localtime, struct tm *, (time_t const *__timer)\n                                          _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (localtime, struct tm *, (time_t const *__timer));\n#  else\n_GL_CXXALIAS_SYS (localtime, struct tm *, (time_t const *__timer));\n#  endif\n#  if __GLIBC__ >= 2\n_GL_CXXALIASWARN (localtime);\n#  endif\n# endif\n\n# if 0 || @REPLACE_GMTIME@\n#  if @REPLACE_GMTIME@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef gmtime\n#    define gmtime rpl_gmtime\n#   endif\n_GL_FUNCDECL_RPL (gmtime, struct tm *, (time_t const *__timer)\n                                       _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (gmtime, struct tm *, (time_t const *__timer));\n#  else\n_GL_CXXALIAS_SYS (gmtime, struct tm *, (time_t const *__timer));\n#  endif\n_GL_CXXALIASWARN (gmtime);\n# endif\n\n/* Parse BUF as a timestamp, assuming FORMAT specifies its layout, and store\n   the resulting broken-down time into TM.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html>.  */\n# if @GNULIB_STRPTIME@\n#  if ! @HAVE_STRPTIME@\n_GL_FUNCDECL_SYS (strptime, char *, (char const *restrict __buf,\n                                     char const *restrict __format,\n                                     struct tm *restrict __tm)\n                                    _GL_ARG_NONNULL ((1, 2, 3)));\n#  endif\n_GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf,\n                                     char const *restrict __format,\n                                     struct tm *restrict __tm));\n_GL_CXXALIASWARN (strptime);\n# endif\n\n/* Convert *TP to a date and time string.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime.html>.  */\n# if @GNULIB_CTIME@\n#  if @REPLACE_CTIME@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    define ctime rpl_ctime\n#   endif\n_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp)\n                                 _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp));\n#  else\n_GL_CXXALIAS_SYS (ctime, char *, (time_t const *__tp));\n#  endif\n#  if __GLIBC__ >= 2\n_GL_CXXALIASWARN (ctime);\n#  endif\n# endif\n\n/* Convert *TP to a date and time string.  See\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html>.  */\n# if @GNULIB_STRFTIME@\n#  if @REPLACE_STRFTIME@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    define strftime rpl_strftime\n#   endif\n_GL_FUNCDECL_RPL (strftime, size_t,\n                  (char *restrict __buf, size_t __bufsize,\n                   const char *restrict __fmt, const struct tm *restrict __tp)\n                  _GL_ARG_NONNULL ((1, 3, 4)));\n_GL_CXXALIAS_RPL (strftime, size_t,\n                  (char *restrict __buf, size_t __bufsize,\n                   const char *restrict __fmt, const struct tm *restrict __tp));\n#  else\n_GL_CXXALIAS_SYS (strftime, size_t,\n                  (char *restrict __buf, size_t __bufsize,\n                   const char *restrict __fmt, const struct tm *restrict __tp));\n#  endif\n#  if __GLIBC__ >= 2\n_GL_CXXALIASWARN (strftime);\n#  endif\n# endif\n\n# if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@\n/* Functions that use a first-class time zone data type, instead of\n   relying on an implicit global time zone.\n   Inspired by NetBSD.  */\n\n/* Represents a time zone.\n   (timezone_t) NULL stands for UTC.  */\ntypedef struct tm_zone *timezone_t;\n\n/* tzalloc (name)\n   Returns a time zone object for the given time zone NAME.  This object\n   represents the time zone that other functions would use it the TZ\n   environment variable was set to NAME.\n   If NAME is NULL, the result represents the time zone that other functions\n   would use it the TZ environment variable was unset.\n   May return NULL if NAME is invalid (this is platform dependent) or\n   upon memory allocation failure.  */\n_GL_FUNCDECL_SYS (tzalloc, timezone_t, (char const *__name));\n_GL_CXXALIAS_SYS (tzalloc, timezone_t, (char const *__name));\n\n/* tzfree (tz)\n   Frees a time zone object.\n   The argument must have been returned by tzalloc().  */\n_GL_FUNCDECL_SYS (tzfree, void, (timezone_t __tz));\n_GL_CXXALIAS_SYS (tzfree, void, (timezone_t __tz));\n\n/* localtime_rz (tz, &t, &result)\n   Converts an absolute time T to a broken-down time RESULT, assuming the\n   time zone TZ.\n   This function is like 'localtime_r', but relies on the argument TZ instead\n   of an implicit global time zone.  */\n_GL_FUNCDECL_SYS (localtime_rz, struct tm *,\n                  (timezone_t __tz, time_t const *restrict __timer,\n                   struct tm *restrict __result) _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_SYS (localtime_rz, struct tm *,\n                  (timezone_t __tz, time_t const *restrict __timer,\n                   struct tm *restrict __result));\n\n/* mktime_z (tz, &tm)\n   Normalizes the broken-down time TM and converts it to an absolute time,\n   assuming the time zone TZ.  Returns the absolute time.\n   This function is like 'mktime', but relies on the argument TZ instead\n   of an implicit global time zone.  */\n_GL_FUNCDECL_SYS (mktime_z, time_t,\n                  (timezone_t __tz, struct tm *restrict __tm)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_SYS (mktime_z, time_t,\n                  (timezone_t __tz, struct tm *restrict __tm));\n\n/* Time zone abbreviation strings (returned by 'localtime_rz' or 'mktime_z'\n   in the 'tm_zone' member of 'struct tm') are valid as long as\n     - the 'struct tm' argument is not destroyed or overwritten,\n   and\n     - the 'timezone_t' argument is not freed through tzfree().  */\n\n# endif\n\n/* Convert TM to a time_t value, assuming UTC.  */\n# if @GNULIB_TIMEGM@\n#  if @REPLACE_TIMEGM@\n#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#    undef timegm\n#    define timegm rpl_timegm\n#   endif\n_GL_FUNCDECL_RPL (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (timegm, time_t, (struct tm *__tm));\n#  else\n#   if ! @HAVE_TIMEGM@\n_GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));\n#   endif\n_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm));\n#  endif\n_GL_CXXALIASWARN (timegm);\n# endif\n\n/* Encourage applications to avoid unsafe functions that can overrun\n   buffers when given outlandish struct tm values.  Portable\n   applications should use strftime (or even sprintf) instead.  */\n# if defined GNULIB_POSIXCHECK\n#  undef asctime\n_GL_WARN_ON_USE (asctime, \"asctime can overrun buffers in some cases - \"\n                 \"better use strftime (or even sprintf) instead\");\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef asctime_r\n_GL_WARN_ON_USE (asctime_r, \"asctime_r can overrun buffers in some cases - \"\n                 \"better use strftime (or even sprintf) instead\");\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef ctime\n_GL_WARN_ON_USE (ctime, \"ctime can overrun buffers in some cases - \"\n                 \"better use strftime (or even sprintf) instead\");\n# endif\n# if defined GNULIB_POSIXCHECK\n#  undef ctime_r\n_GL_WARN_ON_USE (ctime_r, \"ctime_r can overrun buffers in some cases - \"\n                 \"better use strftime (or even sprintf) instead\");\n# endif\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/time_r.c",
    "content": "/* Reentrant time functions like localtime_r.\n\n   Copyright (C) 2003, 2006-2007, 2010-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paul Eggert.  */\n\n#include <config.h>\n\n#include <time.h>\n\nstatic struct tm *\ncopy_tm_result (struct tm *dest, struct tm const *src)\n{\n  if (! src)\n    return 0;\n  *dest = *src;\n  return dest;\n}\n\n\nstruct tm *\ngmtime_r (time_t const * restrict t, struct tm * restrict tp)\n{\n  return copy_tm_result (tp, gmtime (t));\n}\n\nstruct tm *\nlocaltime_r (time_t const * restrict t, struct tm * restrict tp)\n{\n  return copy_tm_result (tp, localtime (t));\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/uname.c",
    "content": "/* uname replacement.\n   Copyright (C) 2009-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n/* Specification.  */\n#include <sys/utsname.h>\n\n/* This file provides an implementation only for the native Windows API.  */\n#if defined _WIN32 && ! defined __CYGWIN__\n\n# include <stdio.h>\n# include <stdlib.h>\n# include <string.h>\n# include <unistd.h>\n# include <windows.h>\n\n/* Mingw headers don't have all the platform codes.  */\n# ifndef VER_PLATFORM_WIN32_CE\n#  define VER_PLATFORM_WIN32_CE 3\n# endif\n\n/* Some headers don't have all the processor architecture codes.  */\n# ifndef PROCESSOR_ARCHITECTURE_AMD64\n#  define PROCESSOR_ARCHITECTURE_AMD64 9\n# endif\n# ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64\n#  define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10\n# endif\n\n/* Mingw headers don't have the latest processor codes.  */\n# ifndef PROCESSOR_AMD_X8664\n#  define PROCESSOR_AMD_X8664 8664\n# endif\n\n/* Don't assume that UNICODE is not defined.  */\n# undef OSVERSIONINFO\n# define OSVERSIONINFO OSVERSIONINFOA\n# undef GetVersionEx\n# define GetVersionEx GetVersionExA\n\nint\nuname (struct utsname *buf)\n{\n  OSVERSIONINFO version;\n  OSVERSIONINFOEX versionex;\n  BOOL have_versionex; /* indicates whether versionex is filled */\n  const char *super_version;\n\n  /* Preparation: Fill version and, if possible, also versionex.\n     But try to call GetVersionEx only once in the common case.  */\n  versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);\n  have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex);\n  if (have_versionex)\n    {\n      /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX.  */\n      memcpy (&version, &versionex, sizeof (OSVERSIONINFO));\n    }\n  else\n    {\n      version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);\n      if (!GetVersionEx (&version))\n        abort ();\n    }\n\n  /* Fill in nodename.  */\n  if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0)\n    strcpy (buf->nodename, \"localhost\");\n\n  /* Determine major-major Windows version.  */\n  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)\n    {\n      /* Windows NT or newer.  */\n      super_version = \"NT\";\n    }\n  else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)\n    {\n      /* Windows CE or Embedded CE.  */\n      super_version = \"CE\";\n    }\n  else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)\n    {\n      /* Windows 95/98/ME.  */\n      switch (version.dwMinorVersion)\n        {\n        case 0:\n          super_version = \"95\";\n          break;\n        case 10:\n          super_version = \"98\";\n          break;\n        case 90:\n          super_version = \"ME\";\n          break;\n        default:\n          super_version = \"\";\n          break;\n        }\n    }\n  else\n    super_version = \"\";\n\n  /* Fill in sysname.  */\n# ifdef __MINGW32__\n  /* Returns a string compatible with the MSYS uname.exe program,\n     so that no further changes are needed to GNU config.guess.\n     For example,\n       $ ./uname.exe -s      => MINGW32_NT-5.1\n   */\n  sprintf (buf->sysname, \"MINGW32_%s-%u.%u\", super_version,\n           (unsigned int) version.dwMajorVersion,\n           (unsigned int) version.dwMinorVersion);\n# else\n  sprintf (buf->sysname, \"Windows%s\", super_version);\n# endif\n\n  /* Fill in release, version.  */\n  /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime:\n       $ ./uname.exe -r      => 1.0.11(0.46/3/2)\n       $ ./uname.exe -v      => 2008-08-25 23:40\n     There is no point in imitating this behaviour.  */\n  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)\n    {\n      /* Windows NT or newer.  */\n      struct windows_version\n        {\n          int major;\n          int minor;\n          unsigned int server_offset;\n          const char *name;\n        };\n\n      /* Storing the workstation and server version names in a single\n         stream does not waste memory when they are the same.  These\n         macros abstract the representation.  VERSION1 is used if\n         version.wProductType does not matter, VERSION2 if it does.  */\n      #define VERSION1(major, minor, name) \\\n        { major, minor, 0, name }\n      #define VERSION2(major, minor, workstation, server) \\\n        { major, minor, sizeof workstation, workstation \"\\0\" server }\n      static const struct windows_version versions[] =\n        {\n          VERSION2 (3, -1, \"Windows NT Workstation\", \"Windows NT Server\"),\n          VERSION2 (4, -1, \"Windows NT Workstation\", \"Windows NT Server\"),\n          VERSION1 (5, 0, \"Windows 2000\"),\n          VERSION1 (5, 1, \"Windows XP\"),\n          VERSION1 (5, 2, \"Windows Server 2003\"),\n          VERSION2 (6, 0, \"Windows Vista\", \"Windows Server 2008\"),\n          VERSION2 (6, 1, \"Windows 7\", \"Windows Server 2008 R2\"),\n          VERSION2 (-1, -1, \"Windows\", \"Windows Server\")\n        };\n      const char *base;\n      const struct windows_version *v = versions;\n\n      /* Find a version that matches ours.  The last element is a\n         wildcard that always ends the loop.  */\n      while ((v->major != version.dwMajorVersion && v->major != -1)\n             || (v->minor != version.dwMinorVersion && v->minor != -1))\n        v++;\n\n      if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION)\n        base = v->name + v->server_offset;\n      else\n        base = v->name;\n      if (v->major == -1 || v->minor == -1)\n        sprintf (buf->release, \"%s %u.%u\",\n                 base,\n                 (unsigned int) version.dwMajorVersion,\n                 (unsigned int) version.dwMinorVersion);\n      else\n        strcpy (buf->release, base);\n    }\n  else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE)\n    {\n      /* Windows CE or Embedded CE.  */\n      sprintf (buf->release, \"Windows CE %u.%u\",\n               (unsigned int) version.dwMajorVersion,\n               (unsigned int) version.dwMinorVersion);\n    }\n  else\n    {\n      /* Windows 95/98/ME.  */\n      sprintf (buf->release, \"Windows %s\", super_version);\n    }\n  strcpy (buf->version, version.szCSDVersion);\n\n  /* Fill in machine.  */\n  {\n    SYSTEM_INFO info;\n\n    GetSystemInfo (&info);\n    /* Check for Windows NT or CE, since the info.wProcessorLevel is\n       garbage on Windows 95. */\n    if (version.dwPlatformId == VER_PLATFORM_WIN32_NT\n        || version.dwPlatformId == VER_PLATFORM_WIN32_CE)\n      {\n        /* Windows NT or newer, or Windows CE or Embedded CE.  */\n        switch (info.wProcessorArchitecture)\n          {\n          case PROCESSOR_ARCHITECTURE_AMD64:\n            strcpy (buf->machine, \"x86_64\");\n            break;\n          case PROCESSOR_ARCHITECTURE_IA64:\n            strcpy (buf->machine, \"ia64\");\n            break;\n          case PROCESSOR_ARCHITECTURE_INTEL:\n            strcpy (buf->machine, \"i386\");\n            if (info.wProcessorLevel >= 3)\n              buf->machine[1] =\n                '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6);\n            break;\n          case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:\n            strcpy (buf->machine, \"i686\");\n            break;\n          case PROCESSOR_ARCHITECTURE_MIPS:\n            strcpy (buf->machine, \"mips\");\n            break;\n          case PROCESSOR_ARCHITECTURE_ALPHA:\n          case PROCESSOR_ARCHITECTURE_ALPHA64:\n            strcpy (buf->machine, \"alpha\");\n            break;\n          case PROCESSOR_ARCHITECTURE_PPC:\n            strcpy (buf->machine, \"powerpc\");\n            break;\n          case PROCESSOR_ARCHITECTURE_SHX:\n            strcpy (buf->machine, \"sh\");\n            break;\n          case PROCESSOR_ARCHITECTURE_ARM:\n            strcpy (buf->machine, \"arm\");\n            break;\n          default:\n            strcpy (buf->machine, \"unknown\");\n            break;\n          }\n      }\n    else\n      {\n        /* Windows 95/98/ME.  */\n        switch (info.dwProcessorType)\n          {\n          case PROCESSOR_AMD_X8664:\n            strcpy (buf->machine, \"x86_64\");\n            break;\n          case PROCESSOR_INTEL_IA64:\n            strcpy (buf->machine, \"ia64\");\n            break;\n          default:\n            if (info.dwProcessorType % 100 == 86)\n              sprintf (buf->machine, \"i%u\",\n                       (unsigned int) info.dwProcessorType);\n            else\n              strcpy (buf->machine, \"unknown\");\n            break;\n          }\n      }\n  }\n\n  return 0;\n}\n\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/unistd.c",
    "content": "/* Inline functions for <unistd.h>.\n\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#include <config.h>\n\n#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE\n#include \"unistd.h\"\ntypedef int dummy;\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/unistd.in.h",
    "content": "/* Substitute for and wrapper around <unistd.h>.\n   Copyright (C) 2003-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n#ifndef _@GUARD_PREFIX@_UNISTD_H\n\n#if __GNUC__ >= 3\n@PRAGMA_SYSTEM_HEADER@\n#endif\n@PRAGMA_COLUMNS@\n\n#if @HAVE_UNISTD_H@ && defined _GL_INCLUDING_UNISTD_H\n/* Special invocation convention:\n   - On Mac OS X 10.3.9 we have a sequence of nested includes\n     <unistd.h> -> <signal.h> -> <pthread.h> -> <unistd.h>\n     In this situation, the functions are not yet declared, therefore we cannot\n     provide the C++ aliases.  */\n\n#@INCLUDE_NEXT@ @NEXT_UNISTD_H@\n\n#else\n/* Normal invocation convention.  */\n\n/* The include_next requires a split double-inclusion guard.  */\n#if @HAVE_UNISTD_H@\n# define _GL_INCLUDING_UNISTD_H\n# @INCLUDE_NEXT@ @NEXT_UNISTD_H@\n# undef _GL_INCLUDING_UNISTD_H\n#endif\n\n/* Get all possible declarations of gethostname().  */\n#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ \\\n  && !defined _GL_INCLUDING_WINSOCK2_H\n# define _GL_INCLUDING_WINSOCK2_H\n# include <winsock2.h>\n# undef _GL_INCLUDING_WINSOCK2_H\n#endif\n\n#if !defined _@GUARD_PREFIX@_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H\n#define _@GUARD_PREFIX@_UNISTD_H\n\n/* NetBSD 5.0 mis-defines NULL.  Also get size_t.  */\n/* But avoid namespace pollution on glibc systems.  */\n#ifndef __GLIBC__\n# include <stddef.h>\n#endif\n\n/* mingw doesn't define the SEEK_* or *_FILENO macros in <unistd.h>.  */\n/* MSVC declares 'unlink' in <stdio.h>, not in <unistd.h>.  We must include\n   it before we  #define unlink rpl_unlink.  */\n/* Cygwin 1.7.1 declares symlinkat in <stdio.h>, not in <unistd.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if (!(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET) \\\n     || ((@GNULIB_UNLINK@ || defined GNULIB_POSIXCHECK) \\\n         && (defined _WIN32 && ! defined __CYGWIN__)) \\\n     || ((@GNULIB_SYMLINKAT@ || defined GNULIB_POSIXCHECK) \\\n         && defined __CYGWIN__)) \\\n    && ! defined __GLIBC__\n# include <stdio.h>\n#endif\n\n/* Cygwin 1.7.1 and Android 4.3 declare unlinkat in <fcntl.h>, not in\n   <unistd.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_UNLINKAT@ || defined GNULIB_POSIXCHECK) \\\n    && (defined __CYGWIN__ || defined __ANDROID__) \\\n    && ! defined __GLIBC__\n# include <fcntl.h>\n#endif\n\n/* mingw fails to declare _exit in <unistd.h>.  */\n/* mingw, MSVC, BeOS, Haiku declare environ in <stdlib.h>, not in\n   <unistd.h>.  */\n/* Solaris declares getcwd not only in <unistd.h> but also in <stdlib.h>.  */\n/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system <stdlib.h> is\n   included here.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if !defined __GLIBC__ && !defined __osf__\n# define __need_system_stdlib_h\n# include <stdlib.h>\n# undef __need_system_stdlib_h\n#endif\n\n/* Native Windows platforms declare _chdir, _getcwd, _rmdir in\n   <io.h> and/or <direct.h>, not in <unistd.h>.\n   They also declare _access(), _chmod(), _close(), _dup(), _dup2(), _isatty(),\n   _lseek(), _read(), _unlink(), _write() in <io.h>.  */\n#if defined _WIN32 && !defined __CYGWIN__\n# include <io.h>\n# include <direct.h>\n#endif\n\n/* Native Windows platforms declare _execl*, _execv* in <process.h>.  */\n#if defined _WIN32 && !defined __CYGWIN__\n# include <process.h>\n#endif\n\n/* AIX and OSF/1 5.1 declare getdomainname in <netdb.h>, not in <unistd.h>.\n   NonStop Kernel declares gethostname in <netdb.h>, not in <unistd.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if ((@GNULIB_GETDOMAINNAME@ && (defined _AIX || defined __osf__)) \\\n     || (@GNULIB_GETHOSTNAME@ && defined __TANDEM)) \\\n    && !defined __GLIBC__\n# include <netdb.h>\n#endif\n\n/* Mac OS X 10.13, Solaris 11.4, and Android 9.0 declare getentropy in\n   <sys/random.h>, not in <unistd.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_GETENTROPY@ || defined GNULIB_POSIXCHECK) \\\n    && ((defined __APPLE__ && defined __MACH__) || defined __sun \\\n        || defined __ANDROID__) \\\n    && @UNISTD_H_HAVE_SYS_RANDOM_H@ \\\n    && !defined __GLIBC__\n# include <sys/random.h>\n#endif\n\n/* Android 4.3 declares fchownat in <sys/stat.h>, not in <unistd.h>.  */\n/* But avoid namespace pollution on glibc systems.  */\n#if (@GNULIB_FCHOWNAT@ || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \\\n    && !defined __GLIBC__\n# include <sys/stat.h>\n#endif\n\n/* MSVC defines off_t in <sys/types.h>.\n   May also define off_t to a 64-bit type on native Windows.  */\n/* Get off_t, ssize_t, mode_t.  */\n#include <sys/types.h>\n\n/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */\n\n/* The definition of _GL_ARG_NONNULL is copied here.  */\n\n/* The definition of _GL_WARN_ON_USE is copied here.  */\n\n\n/* Get getopt(), optarg, optind, opterr, optopt.  */\n#if @GNULIB_GETOPT_POSIX@ && @GNULIB_UNISTD_H_GETOPT@ && !defined _GL_SYSTEM_GETOPT\n# include <getopt-cdefs.h>\n# include <getopt-pfx-core.h>\n#endif\n\n#ifndef _GL_INLINE_HEADER_BEGIN\n #error \"Please include config.h first.\"\n#endif\n_GL_INLINE_HEADER_BEGIN\n#ifndef _GL_UNISTD_INLINE\n# define _GL_UNISTD_INLINE _GL_INLINE\n#endif\n\n/* Hide some function declarations from <winsock2.h>.  */\n\n#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@\n# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef socket\n#   define socket              socket_used_without_including_sys_socket_h\n#   undef connect\n#   define connect             connect_used_without_including_sys_socket_h\n#   undef accept\n#   define accept              accept_used_without_including_sys_socket_h\n#   undef bind\n#   define bind                bind_used_without_including_sys_socket_h\n#   undef getpeername\n#   define getpeername         getpeername_used_without_including_sys_socket_h\n#   undef getsockname\n#   define getsockname         getsockname_used_without_including_sys_socket_h\n#   undef getsockopt\n#   define getsockopt          getsockopt_used_without_including_sys_socket_h\n#   undef listen\n#   define listen              listen_used_without_including_sys_socket_h\n#   undef recv\n#   define recv                recv_used_without_including_sys_socket_h\n#   undef send\n#   define send                send_used_without_including_sys_socket_h\n#   undef recvfrom\n#   define recvfrom            recvfrom_used_without_including_sys_socket_h\n#   undef sendto\n#   define sendto              sendto_used_without_including_sys_socket_h\n#   undef setsockopt\n#   define setsockopt          setsockopt_used_without_including_sys_socket_h\n#   undef shutdown\n#   define shutdown            shutdown_used_without_including_sys_socket_h\n#  else\n    _GL_WARN_ON_USE (socket,\n                     \"socket() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (connect,\n                     \"connect() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (accept,\n                     \"accept() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (bind,\n                     \"bind() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (getpeername,\n                     \"getpeername() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (getsockname,\n                     \"getsockname() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (getsockopt,\n                     \"getsockopt() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (listen,\n                     \"listen() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (recv,\n                     \"recv() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (send,\n                     \"send() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (recvfrom,\n                     \"recvfrom() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (sendto,\n                     \"sendto() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (setsockopt,\n                     \"setsockopt() used without including <sys/socket.h>\");\n    _GL_WARN_ON_USE (shutdown,\n                     \"shutdown() used without including <sys/socket.h>\");\n#  endif\n# endif\n# if !defined _@GUARD_PREFIX@_SYS_SELECT_H\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef select\n#   define select              select_used_without_including_sys_select_h\n#  else\n    _GL_WARN_ON_USE (select,\n                     \"select() used without including <sys/select.h>\");\n#  endif\n# endif\n#endif\n\n\n/* OS/2 EMX lacks these macros.  */\n#ifndef STDIN_FILENO\n# define STDIN_FILENO 0\n#endif\n#ifndef STDOUT_FILENO\n# define STDOUT_FILENO 1\n#endif\n#ifndef STDERR_FILENO\n# define STDERR_FILENO 2\n#endif\n\n/* Ensure *_OK macros exist.  */\n#ifndef F_OK\n# define F_OK 0\n# define X_OK 1\n# define W_OK 2\n# define R_OK 4\n#endif\n\n\n/* Declare overridden functions.  */\n\n\n#if @GNULIB_ACCESS@\n# if @REPLACE_ACCESS@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef access\n#   define access rpl_access\n#  endif\n_GL_FUNCDECL_RPL (access, int, (const char *file, int mode)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (access, int, (const char *file, int mode));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef access\n#   define access _access\n#  endif\n_GL_CXXALIAS_MDA (access, int, (const char *file, int mode));\n# else\n_GL_CXXALIAS_SYS (access, int, (const char *file, int mode));\n# endif\n_GL_CXXALIASWARN (access);\n#elif defined GNULIB_POSIXCHECK\n# undef access\n# if HAVE_RAW_DECL_ACCESS\n/* The access() function is a security risk.  */\n_GL_WARN_ON_USE (access, \"access does not always support X_OK - \"\n                 \"use gnulib module access for portability; \"\n                 \"also, this function is a security risk - \"\n                 \"use the gnulib module faccessat instead\");\n# endif\n#elif @GNULIB_MDA_ACCESS@\n/* On native Windows, map 'access' to '_access', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::access always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef access\n#   define access _access\n#  endif\n_GL_CXXALIAS_MDA (access, int, (const char *file, int mode));\n# else\n_GL_CXXALIAS_SYS (access, int, (const char *file, int mode));\n# endif\n_GL_CXXALIASWARN (access);\n#endif\n\n\n#if @GNULIB_CHDIR@\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef chdir\n#   define chdir _chdir\n#  endif\n_GL_CXXALIAS_MDA (chdir, int, (const char *file));\n# else\n_GL_CXXALIAS_SYS (chdir, int, (const char *file) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIASWARN (chdir);\n#elif defined GNULIB_POSIXCHECK\n# undef chdir\n# if HAVE_RAW_DECL_CHDIR\n_GL_WARN_ON_USE (chown, \"chdir is not always in <unistd.h> - \"\n                 \"use gnulib module chdir for portability\");\n# endif\n#elif @GNULIB_MDA_CHDIR@\n/* On native Windows, map 'chdir' to '_chdir', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::chdir always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef chdir\n#   define chdir _chdir\n#  endif\n_GL_CXXALIAS_MDA (chdir, int, (const char *file));\n# else\n_GL_CXXALIAS_SYS (chdir, int, (const char *file) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIASWARN (chdir);\n#endif\n\n\n#if @GNULIB_CHOWN@\n/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE\n   to GID (if GID is not -1).  Follow symbolic links.\n   Return 0 if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html.  */\n# if @REPLACE_CHOWN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef chown\n#   define chown rpl_chown\n#  endif\n_GL_FUNCDECL_RPL (chown, int, (const char *file, uid_t uid, gid_t gid)\n                              _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (chown, int, (const char *file, uid_t uid, gid_t gid));\n# else\n#  if !@HAVE_CHOWN@\n_GL_FUNCDECL_SYS (chown, int, (const char *file, uid_t uid, gid_t gid)\n                              _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (chown, int, (const char *file, uid_t uid, gid_t gid));\n# endif\n_GL_CXXALIASWARN (chown);\n#elif defined GNULIB_POSIXCHECK\n# undef chown\n# if HAVE_RAW_DECL_CHOWN\n_GL_WARN_ON_USE (chown, \"chown fails to follow symlinks on some systems and \"\n                 \"doesn't treat a uid or gid of -1 on some systems - \"\n                 \"use gnulib module chown for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_CLOSE@\n# if @REPLACE_CLOSE@\n/* Automatically included by modules that need a replacement for close.  */\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef close\n#   define close rpl_close\n#  endif\n_GL_FUNCDECL_RPL (close, int, (int fd));\n_GL_CXXALIAS_RPL (close, int, (int fd));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef close\n#   define close _close\n#  endif\n_GL_CXXALIAS_MDA (close, int, (int fd));\n# else\n_GL_CXXALIAS_SYS (close, int, (int fd));\n# endif\n_GL_CXXALIASWARN (close);\n#elif @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@\n# undef close\n# define close close_used_without_requesting_gnulib_module_close\n#elif defined GNULIB_POSIXCHECK\n# undef close\n/* Assume close is always declared.  */\n_GL_WARN_ON_USE (close, \"close does not portably work on sockets - \"\n                 \"use gnulib module close for portability\");\n#elif @GNULIB_MDA_CLOSE@\n/* On native Windows, map 'close' to '_close', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::close always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef close\n#   define close _close\n#  endif\n_GL_CXXALIAS_MDA (close, int, (int fd));\n# else\n_GL_CXXALIAS_SYS (close, int, (int fd));\n# endif\n_GL_CXXALIASWARN (close);\n#endif\n\n\n#if @GNULIB_COPY_FILE_RANGE@\n# if !@HAVE_COPY_FILE_RANGE@\n_GL_FUNCDECL_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos,\n                                             int ofd, off_t *opos,\n                                             size_t len, unsigned flags));\n_GL_CXXALIAS_SYS (copy_file_range, ssize_t, (int ifd, off_t *ipos,\n                                             int ofd, off_t *opos,\n                                             size_t len, unsigned flags));\n# endif\n_GL_CXXALIASWARN (copy_file_range);\n#elif defined GNULIB_POSIXCHECK\n# if HAVE_RAW_DECL_COPY_FILE_RANGE\n_GL_WARN_ON_USE (copy_file_range,\n                 \"copy_file_range is unportable - \"\n                 \"use gnulib module copy_file_range for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_DUP@\n# if @REPLACE_DUP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define dup rpl_dup\n#  endif\n_GL_FUNCDECL_RPL (dup, int, (int oldfd));\n_GL_CXXALIAS_RPL (dup, int, (int oldfd));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef dup\n#   define dup _dup\n#  endif\n_GL_CXXALIAS_MDA (dup, int, (int oldfd));\n# else\n_GL_CXXALIAS_SYS (dup, int, (int oldfd));\n# endif\n_GL_CXXALIASWARN (dup);\n#elif defined GNULIB_POSIXCHECK\n# undef dup\n# if HAVE_RAW_DECL_DUP\n_GL_WARN_ON_USE (dup, \"dup is unportable - \"\n                 \"use gnulib module dup for portability\");\n# endif\n#elif @GNULIB_MDA_DUP@\n/* On native Windows, map 'dup' to '_dup', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::dup always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef dup\n#   define dup _dup\n#  endif\n_GL_CXXALIAS_MDA (dup, int, (int oldfd));\n# else\n_GL_CXXALIAS_SYS (dup, int, (int oldfd));\n# endif\n_GL_CXXALIASWARN (dup);\n#endif\n\n\n#if @GNULIB_DUP2@\n/* Copy the file descriptor OLDFD into file descriptor NEWFD.  Do nothing if\n   NEWFD = OLDFD, otherwise close NEWFD first if it is open.\n   Return newfd if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html>.  */\n# if @REPLACE_DUP2@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define dup2 rpl_dup2\n#  endif\n_GL_FUNCDECL_RPL (dup2, int, (int oldfd, int newfd));\n_GL_CXXALIAS_RPL (dup2, int, (int oldfd, int newfd));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef dup2\n#   define dup2 _dup2\n#  endif\n_GL_CXXALIAS_MDA (dup2, int, (int oldfd, int newfd));\n# else\n_GL_CXXALIAS_SYS (dup2, int, (int oldfd, int newfd));\n# endif\n_GL_CXXALIASWARN (dup2);\n#elif defined GNULIB_POSIXCHECK\n# undef dup2\n# if HAVE_RAW_DECL_DUP2\n_GL_WARN_ON_USE (dup2, \"dup2 is unportable - \"\n                 \"use gnulib module dup2 for portability\");\n# endif\n#elif @GNULIB_MDA_DUP2@\n/* On native Windows, map 'dup2' to '_dup2', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::dup2 always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef dup2\n#   define dup2 _dup2\n#  endif\n_GL_CXXALIAS_MDA (dup2, int, (int oldfd, int newfd));\n# else\n_GL_CXXALIAS_SYS (dup2, int, (int oldfd, int newfd));\n# endif\n_GL_CXXALIASWARN (dup2);\n#endif\n\n\n#if @GNULIB_DUP3@\n/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the\n   specified flags.\n   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>)\n   and O_TEXT, O_BINARY (defined in \"binary-io.h\").\n   Close NEWFD first if it is open.\n   Return newfd if successful, otherwise -1 and errno set.\n   See the Linux man page at\n   <https://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>.  */\n# if @HAVE_DUP3@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define dup3 rpl_dup3\n#  endif\n_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags));\n_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags));\n# else\n_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags));\n_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags));\n# endif\n_GL_CXXALIASWARN (dup3);\n#elif defined GNULIB_POSIXCHECK\n# undef dup3\n# if HAVE_RAW_DECL_DUP3\n_GL_WARN_ON_USE (dup3, \"dup3 is unportable - \"\n                 \"use gnulib module dup3 for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_ENVIRON@\n# if defined __CYGWIN__ && !defined __i386__\n/* The 'environ' variable is defined in a DLL. Therefore its declaration needs\n   the '__declspec(dllimport)' attribute, but the system's <unistd.h> lacks it.\n   This leads to a link error on 64-bit Cygwin when the option\n   -Wl,--disable-auto-import is in use.  */\n_GL_EXTERN_C __declspec(dllimport) char **environ;\n# endif\n# if !@HAVE_DECL_ENVIRON@\n/* Set of environment variables and values.  An array of strings of the form\n   \"VARIABLE=VALUE\", terminated with a NULL.  */\n#  if defined __APPLE__ && defined __MACH__\n#   include <TargetConditionals.h>\n#   if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR\n#    define _GL_USE_CRT_EXTERNS\n#   endif\n#  endif\n#  ifdef _GL_USE_CRT_EXTERNS\n#   include <crt_externs.h>\n#   define environ (*_NSGetEnviron ())\n#  else\n#   ifdef __cplusplus\nextern \"C\" {\n#   endif\nextern char **environ;\n#   ifdef __cplusplus\n}\n#   endif\n#  endif\n# endif\n#elif defined GNULIB_POSIXCHECK\n# if HAVE_RAW_DECL_ENVIRON\n_GL_UNISTD_INLINE char ***\n_GL_WARN_ON_USE_ATTRIBUTE (\"environ is unportable - \"\n                           \"use gnulib module environ for portability\")\nrpl_environ (void)\n{\n  return &environ;\n}\n#  undef environ\n#  define environ (*rpl_environ ())\n# endif\n#endif\n\n\n#if @GNULIB_EUIDACCESS@\n/* Like access(), except that it uses the effective user id and group id of\n   the current process.  */\n# if !@HAVE_EUIDACCESS@\n_GL_FUNCDECL_SYS (euidaccess, int, (const char *filename, int mode)\n                                   _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (euidaccess, int, (const char *filename, int mode));\n_GL_CXXALIASWARN (euidaccess);\n# if defined GNULIB_POSIXCHECK\n/* Like access(), this function is a security risk.  */\n_GL_WARN_ON_USE (euidaccess, \"the euidaccess function is a security risk - \"\n                 \"use the gnulib module faccessat instead\");\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef euidaccess\n# if HAVE_RAW_DECL_EUIDACCESS\n_GL_WARN_ON_USE (euidaccess, \"euidaccess is unportable - \"\n                 \"use gnulib module euidaccess for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_EXECL@\n# if @REPLACE_EXECL@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execl\n#   define execl rpl_execl\n#  endif\n_GL_FUNCDECL_RPL (execl, int, (const char *program, const char *arg, ...)\n                              _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (execl, int, (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execl, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execl);\n#elif defined GNULIB_POSIXCHECK\n# undef execl\n# if HAVE_RAW_DECL_EXECL\n_GL_WARN_ON_USE (execl, \"execl behaves very differently on mingw - \"\n                 \"use gnulib module execl for portability\");\n# endif\n#elif @GNULIB_MDA_EXECL@\n/* On native Windows, map 'execl' to '_execl', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execl always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execl\n#   define execl _execl\n#  endif\n_GL_CXXALIAS_MDA (execl, intptr_t, (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execl, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execl);\n#endif\n\n#if @GNULIB_EXECLE@\n# if @REPLACE_EXECLE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execle\n#   define execle rpl_execle\n#  endif\n_GL_FUNCDECL_RPL (execle, int, (const char *program, const char *arg, ...)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (execle, int, (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execle, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execle);\n#elif defined GNULIB_POSIXCHECK\n# undef execle\n# if HAVE_RAW_DECL_EXECLE\n_GL_WARN_ON_USE (execle, \"execle behaves very differently on mingw - \"\n                 \"use gnulib module execle for portability\");\n# endif\n#elif @GNULIB_MDA_EXECLE@\n/* On native Windows, map 'execle' to '_execle', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execle always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execle\n#   define execle _execle\n#  endif\n_GL_CXXALIAS_MDA (execle, intptr_t,\n                  (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execle, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execle);\n#endif\n\n#if @GNULIB_EXECLP@\n# if @REPLACE_EXECLP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execlp\n#   define execlp rpl_execlp\n#  endif\n_GL_FUNCDECL_RPL (execlp, int, (const char *program, const char *arg, ...)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (execlp, int, (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execlp, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execlp);\n#elif defined GNULIB_POSIXCHECK\n# undef execlp\n# if HAVE_RAW_DECL_EXECLP\n_GL_WARN_ON_USE (execlp, \"execlp behaves very differently on mingw - \"\n                 \"use gnulib module execlp for portability\");\n# endif\n#elif @GNULIB_MDA_EXECLP@\n/* On native Windows, map 'execlp' to '_execlp', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execlp always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execlp\n#   define execlp _execlp\n#  endif\n_GL_CXXALIAS_MDA (execlp, intptr_t,\n                  (const char *program, const char *arg, ...));\n# else\n_GL_CXXALIAS_SYS (execlp, int, (const char *program, const char *arg, ...));\n# endif\n_GL_CXXALIASWARN (execlp);\n#endif\n\n\n#if @GNULIB_EXECV@\n# if @REPLACE_EXECV@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execv\n#   define execv rpl_execv\n#  endif\n_GL_FUNCDECL_RPL (execv, int, (const char *program, char * const *argv)\n                              _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (execv, int, (const char *program, char * const *argv));\n# else\n_GL_CXXALIAS_SYS (execv, int, (const char *program, char * const *argv));\n# endif\n_GL_CXXALIASWARN (execv);\n#elif defined GNULIB_POSIXCHECK\n# undef execv\n# if HAVE_RAW_DECL_EXECV\n_GL_WARN_ON_USE (execv, \"execv behaves very differently on mingw - \"\n                 \"use gnulib module execv for portability\");\n# endif\n#elif @GNULIB_MDA_EXECV@\n/* On native Windows, map 'execv' to '_execv', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execv always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execv\n#   define execv _execv\n#  endif\n_GL_CXXALIAS_MDA_CAST (execv, intptr_t,\n                       (const char *program, char * const *argv));\n# else\n_GL_CXXALIAS_SYS (execv, int, (const char *program, char * const *argv));\n# endif\n_GL_CXXALIASWARN (execv);\n#endif\n\n#if @GNULIB_EXECVE@\n# if @REPLACE_EXECVE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execve\n#   define execve rpl_execve\n#  endif\n_GL_FUNCDECL_RPL (execve, int,\n                  (const char *program, char * const *argv, char * const *env)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (execve, int,\n                  (const char *program, char * const *argv, char * const *env));\n# else\n_GL_CXXALIAS_SYS (execve, int,\n                  (const char *program, char * const *argv, char * const *env));\n# endif\n_GL_CXXALIASWARN (execve);\n#elif defined GNULIB_POSIXCHECK\n# undef execve\n# if HAVE_RAW_DECL_EXECVE\n_GL_WARN_ON_USE (execve, \"execve behaves very differently on mingw - \"\n                 \"use gnulib module execve for portability\");\n# endif\n#elif @GNULIB_MDA_EXECVE@\n/* On native Windows, map 'execve' to '_execve', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execve always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execve\n#   define execve _execve\n#  endif\n_GL_CXXALIAS_MDA_CAST (execve, intptr_t,\n                       (const char *program, char * const *argv,\n                        char * const *env));\n# else\n_GL_CXXALIAS_SYS (execve, int,\n                  (const char *program, char * const *argv, char * const *env));\n# endif\n_GL_CXXALIASWARN (execve);\n#endif\n\n#if @GNULIB_EXECVP@\n# if @REPLACE_EXECVP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execvp\n#   define execvp rpl_execvp\n#  endif\n_GL_FUNCDECL_RPL (execvp, int, (const char *program, char * const *argv)\n                               _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (execvp, int, (const char *program, char * const *argv));\n# else\n_GL_CXXALIAS_SYS (execvp, int, (const char *program, char * const *argv));\n# endif\n_GL_CXXALIASWARN (execvp);\n#elif defined GNULIB_POSIXCHECK\n# undef execvp\n# if HAVE_RAW_DECL_EXECVP\n_GL_WARN_ON_USE (execvp, \"execvp behaves very differently on mingw - \"\n                 \"use gnulib module execvp for portability\");\n# endif\n#elif @GNULIB_MDA_EXECVP@\n/* On native Windows, map 'execvp' to '_execvp', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execvp always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execvp\n#   define execvp _execvp\n#  endif\n_GL_CXXALIAS_MDA_CAST (execvp, intptr_t,\n                       (const char *program, char * const *argv));\n# else\n_GL_CXXALIAS_SYS (execvp, int, (const char *program, char * const *argv));\n# endif\n_GL_CXXALIASWARN (execvp);\n#endif\n\n#if @GNULIB_EXECVPE@\n# if @REPLACE_EXECVPE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execvpe\n#   define execvpe rpl_execvpe\n#  endif\n_GL_FUNCDECL_RPL (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env));\n# else\n#  if !@HAVE_DECL_EXECVPE@\n_GL_FUNCDECL_SYS (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env));\n# endif\n_GL_CXXALIASWARN (execvpe);\n#elif defined GNULIB_POSIXCHECK\n# undef execvpe\n# if HAVE_RAW_DECL_EXECVPE\n_GL_WARN_ON_USE (execvpe, \"execvpe behaves very differently on mingw - \"\n                 \"use gnulib module execvpe for portability\");\n# endif\n#elif @GNULIB_MDA_EXECVPE@\n/* On native Windows, map 'execvpe' to '_execvpe', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::execvpe on all platforms that have\n   it.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef execvpe\n#   define execvpe _execvpe\n#  endif\n_GL_CXXALIAS_MDA_CAST (execvpe, intptr_t,\n                       (const char *program, char * const *argv,\n                        char * const *env));\n# elif @HAVE_EXECVPE@\n#  if !@HAVE_DECL_EXECVPE@\n_GL_FUNCDECL_SYS (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (execvpe, int,\n                  (const char *program, char * const *argv, char * const *env));\n# endif\n# if (defined _WIN32 && !defined __CYGWIN__) || @HAVE_EXECVPE@\n_GL_CXXALIASWARN (execvpe);\n# endif\n#endif\n\n\n#if @GNULIB_FACCESSAT@\n# if @REPLACE_FACCESSAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef faccessat\n#   define faccessat rpl_faccessat\n#  endif\n_GL_FUNCDECL_RPL (faccessat, int,\n                  (int fd, char const *name, int mode, int flag)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (faccessat, int,\n                  (int fd, char const *name, int mode, int flag));\n# else\n#  if !@HAVE_FACCESSAT@\n_GL_FUNCDECL_SYS (faccessat, int,\n                  (int fd, char const *file, int mode, int flag)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (faccessat, int,\n                  (int fd, char const *file, int mode, int flag));\n# endif\n_GL_CXXALIASWARN (faccessat);\n#elif defined GNULIB_POSIXCHECK\n# undef faccessat\n# if HAVE_RAW_DECL_FACCESSAT\n_GL_WARN_ON_USE (faccessat, \"faccessat is not portable - \"\n                 \"use gnulib module faccessat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FCHDIR@\n/* Change the process' current working directory to the directory on which\n   the given file descriptor is open.\n   Return 0 if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html>.  */\n# if ! @HAVE_FCHDIR@\n_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/));\n\n/* Gnulib internal hooks needed to maintain the fchdir metadata.  */\n_GL_EXTERN_C int _gl_register_fd (int fd, const char *filename)\n     _GL_ARG_NONNULL ((2));\n_GL_EXTERN_C void _gl_unregister_fd (int fd);\n_GL_EXTERN_C int _gl_register_dup (int oldfd, int newfd);\n_GL_EXTERN_C const char *_gl_directory_name (int fd);\n\n# else\n#  if !@HAVE_DECL_FCHDIR@\n_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/));\n#  endif\n# endif\n_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/));\n_GL_CXXALIASWARN (fchdir);\n#elif defined GNULIB_POSIXCHECK\n# undef fchdir\n# if HAVE_RAW_DECL_FCHDIR\n_GL_WARN_ON_USE (fchdir, \"fchdir is unportable - \"\n                 \"use gnulib module fchdir for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FCHOWNAT@\n# if @REPLACE_FCHOWNAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef fchownat\n#   define fchownat rpl_fchownat\n#  endif\n_GL_FUNCDECL_RPL (fchownat, int, (int fd, char const *file,\n                                  uid_t owner, gid_t group, int flag)\n                                 _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (fchownat, int, (int fd, char const *file,\n                                  uid_t owner, gid_t group, int flag));\n# else\n#  if !@HAVE_FCHOWNAT@\n_GL_FUNCDECL_SYS (fchownat, int, (int fd, char const *file,\n                                  uid_t owner, gid_t group, int flag)\n                                 _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (fchownat, int, (int fd, char const *file,\n                                  uid_t owner, gid_t group, int flag));\n# endif\n_GL_CXXALIASWARN (fchownat);\n#elif defined GNULIB_POSIXCHECK\n# undef fchownat\n# if HAVE_RAW_DECL_FCHOWNAT\n_GL_WARN_ON_USE (fchownat, \"fchownat is not portable - \"\n                 \"use gnulib module fchownat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FDATASYNC@\n/* Synchronize changes to a file.\n   Return 0 if successful, otherwise -1 and errno set.\n   See POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html>.  */\n# if !@HAVE_FDATASYNC@ || !@HAVE_DECL_FDATASYNC@\n_GL_FUNCDECL_SYS (fdatasync, int, (int fd));\n# endif\n_GL_CXXALIAS_SYS (fdatasync, int, (int fd));\n_GL_CXXALIASWARN (fdatasync);\n#elif defined GNULIB_POSIXCHECK\n# undef fdatasync\n# if HAVE_RAW_DECL_FDATASYNC\n_GL_WARN_ON_USE (fdatasync, \"fdatasync is unportable - \"\n                 \"use gnulib module fdatasync for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FSYNC@\n/* Synchronize changes, including metadata, to a file.\n   Return 0 if successful, otherwise -1 and errno set.\n   See POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html>.  */\n# if !@HAVE_FSYNC@\n_GL_FUNCDECL_SYS (fsync, int, (int fd));\n# endif\n_GL_CXXALIAS_SYS (fsync, int, (int fd));\n_GL_CXXALIASWARN (fsync);\n#elif defined GNULIB_POSIXCHECK\n# undef fsync\n# if HAVE_RAW_DECL_FSYNC\n_GL_WARN_ON_USE (fsync, \"fsync is unportable - \"\n                 \"use gnulib module fsync for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_FTRUNCATE@\n/* Change the size of the file to which FD is opened to become equal to LENGTH.\n   Return 0 if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html>.  */\n# if @REPLACE_FTRUNCATE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ftruncate\n#   define ftruncate rpl_ftruncate\n#  endif\n_GL_FUNCDECL_RPL (ftruncate, int, (int fd, off_t length));\n_GL_CXXALIAS_RPL (ftruncate, int, (int fd, off_t length));\n# else\n#  if !@HAVE_FTRUNCATE@\n_GL_FUNCDECL_SYS (ftruncate, int, (int fd, off_t length));\n#  endif\n_GL_CXXALIAS_SYS (ftruncate, int, (int fd, off_t length));\n# endif\n_GL_CXXALIASWARN (ftruncate);\n#elif defined GNULIB_POSIXCHECK\n# undef ftruncate\n# if HAVE_RAW_DECL_FTRUNCATE\n_GL_WARN_ON_USE (ftruncate, \"ftruncate is unportable - \"\n                 \"use gnulib module ftruncate for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETCWD@\n/* Get the name of the current working directory, and put it in SIZE bytes\n   of BUF.\n   Return BUF if successful, or NULL if the directory couldn't be determined\n   or SIZE was too small.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html>.\n   Additionally, the gnulib module 'getcwd' guarantees the following GNU\n   extension: If BUF is NULL, an array is allocated with 'malloc'; the array\n   is SIZE bytes long, unless SIZE == 0, in which case it is as big as\n   necessary.  */\n# if @REPLACE_GETCWD@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define getcwd rpl_getcwd\n#  endif\n_GL_FUNCDECL_RPL (getcwd, char *, (char *buf, size_t size));\n_GL_CXXALIAS_RPL (getcwd, char *, (char *buf, size_t size));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getcwd\n#   define getcwd _getcwd\n#  endif\n_GL_CXXALIAS_MDA (getcwd, char *, (char *buf, size_t size));\n# else\n/* Need to cast, because on mingw, the second parameter is\n                                                   int size.  */\n_GL_CXXALIAS_SYS_CAST (getcwd, char *, (char *buf, size_t size));\n# endif\n_GL_CXXALIASWARN (getcwd);\n#elif defined GNULIB_POSIXCHECK\n# undef getcwd\n# if HAVE_RAW_DECL_GETCWD\n_GL_WARN_ON_USE (getcwd, \"getcwd is unportable - \"\n                 \"use gnulib module getcwd for portability\");\n# endif\n#elif @GNULIB_MDA_GETCWD@\n/* On native Windows, map 'getcwd' to '_getcwd', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::getcwd always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getcwd\n#   define getcwd _getcwd\n#  endif\n/* Need to cast, because on mingw, the second parameter is either\n   'int size' or 'size_t size'.  */\n_GL_CXXALIAS_MDA_CAST (getcwd, char *, (char *buf, size_t size));\n# else\n_GL_CXXALIAS_SYS_CAST (getcwd, char *, (char *buf, size_t size));\n# endif\n_GL_CXXALIASWARN (getcwd);\n#endif\n\n\n#if @GNULIB_GETDOMAINNAME@\n/* Return the NIS domain name of the machine.\n   WARNING! The NIS domain name is unrelated to the fully qualified host name\n            of the machine.  It is also unrelated to email addresses.\n   WARNING! The NIS domain name is usually the empty string or \"(none)\" when\n            not using NIS.\n\n   Put up to LEN bytes of the NIS domain name into NAME.\n   Null terminate it if the name is shorter than LEN.\n   If the NIS domain name is longer than LEN, set errno = EINVAL and return -1.\n   Return 0 if successful, otherwise set errno and return -1.  */\n# if @REPLACE_GETDOMAINNAME@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getdomainname\n#   define getdomainname rpl_getdomainname\n#  endif\n_GL_FUNCDECL_RPL (getdomainname, int, (char *name, size_t len)\n                                      _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (getdomainname, int, (char *name, size_t len));\n# else\n#  if !@HAVE_DECL_GETDOMAINNAME@\n_GL_FUNCDECL_SYS (getdomainname, int, (char *name, size_t len)\n                                      _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (getdomainname, int, (char *name, size_t len));\n# endif\n_GL_CXXALIASWARN (getdomainname);\n#elif defined GNULIB_POSIXCHECK\n# undef getdomainname\n# if HAVE_RAW_DECL_GETDOMAINNAME\n_GL_WARN_ON_USE (getdomainname, \"getdomainname is unportable - \"\n                 \"use gnulib module getdomainname for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETDTABLESIZE@\n/* Return the maximum number of file descriptors in the current process.\n   In POSIX, this is same as sysconf (_SC_OPEN_MAX).  */\n# if @REPLACE_GETDTABLESIZE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getdtablesize\n#   define getdtablesize rpl_getdtablesize\n#  endif\n_GL_FUNCDECL_RPL (getdtablesize, int, (void));\n_GL_CXXALIAS_RPL (getdtablesize, int, (void));\n# else\n#  if !@HAVE_GETDTABLESIZE@\n_GL_FUNCDECL_SYS (getdtablesize, int, (void));\n#  endif\n/* Need to cast, because on AIX, the parameter list is\n                                           (...).  */\n_GL_CXXALIAS_SYS_CAST (getdtablesize, int, (void));\n# endif\n_GL_CXXALIASWARN (getdtablesize);\n#elif defined GNULIB_POSIXCHECK\n# undef getdtablesize\n# if HAVE_RAW_DECL_GETDTABLESIZE\n_GL_WARN_ON_USE (getdtablesize, \"getdtablesize is unportable - \"\n                 \"use gnulib module getdtablesize for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETENTROPY@\n/* Fill a buffer with random bytes.  */\n# if !@HAVE_GETENTROPY@\n_GL_FUNCDECL_SYS (getentropy, int, (void *buffer, size_t length));\n# endif\n_GL_CXXALIAS_SYS (getentropy, int, (void *buffer, size_t length));\n_GL_CXXALIASWARN (getentropy);\n#elif defined GNULIB_POSIXCHECK\n# undef getentropy\n# if HAVE_RAW_DECL_GETENTROPY\n_GL_WARN_ON_USE (getentropy, \"getentropy is unportable - \"\n                 \"use gnulib module getentropy for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETGROUPS@\n/* Return the supplemental groups that the current process belongs to.\n   It is unspecified whether the effective group id is in the list.\n   If N is 0, return the group count; otherwise, N describes how many\n   entries are available in GROUPS.  Return -1 and set errno if N is\n   not 0 and not large enough.  Fails with ENOSYS on some systems.  */\n# if @REPLACE_GETGROUPS@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getgroups\n#   define getgroups rpl_getgroups\n#  endif\n_GL_FUNCDECL_RPL (getgroups, int, (int n, gid_t *groups));\n_GL_CXXALIAS_RPL (getgroups, int, (int n, gid_t *groups));\n# else\n#  if !@HAVE_GETGROUPS@\n_GL_FUNCDECL_SYS (getgroups, int, (int n, gid_t *groups));\n#  endif\n_GL_CXXALIAS_SYS (getgroups, int, (int n, gid_t *groups));\n# endif\n_GL_CXXALIASWARN (getgroups);\n#elif defined GNULIB_POSIXCHECK\n# undef getgroups\n# if HAVE_RAW_DECL_GETGROUPS\n_GL_WARN_ON_USE (getgroups, \"getgroups is unportable - \"\n                 \"use gnulib module getgroups for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETHOSTNAME@\n/* Return the standard host name of the machine.\n   WARNING! The host name may or may not be fully qualified.\n\n   Put up to LEN bytes of the host name into NAME.\n   Null terminate it if the name is shorter than LEN.\n   If the host name is longer than LEN, set errno = EINVAL and return -1.\n   Return 0 if successful, otherwise set errno and return -1.  */\n# if @UNISTD_H_HAVE_WINSOCK2_H@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef gethostname\n#   define gethostname rpl_gethostname\n#  endif\n_GL_FUNCDECL_RPL (gethostname, int, (char *name, size_t len)\n                                    _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (gethostname, int, (char *name, size_t len));\n# else\n#  if !@HAVE_GETHOSTNAME@\n_GL_FUNCDECL_SYS (gethostname, int, (char *name, size_t len)\n                                    _GL_ARG_NONNULL ((1)));\n#  endif\n/* Need to cast, because on Solaris 10 and OSF/1 5.1 systems, the second\n   parameter is\n                                                      int len.  */\n_GL_CXXALIAS_SYS_CAST (gethostname, int, (char *name, size_t len));\n# endif\n_GL_CXXALIASWARN (gethostname);\n#elif @UNISTD_H_HAVE_WINSOCK2_H@\n# undef gethostname\n# define gethostname gethostname_used_without_requesting_gnulib_module_gethostname\n#elif defined GNULIB_POSIXCHECK\n# undef gethostname\n# if HAVE_RAW_DECL_GETHOSTNAME\n_GL_WARN_ON_USE (gethostname, \"gethostname is unportable - \"\n                 \"use gnulib module gethostname for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETLOGIN@\n/* Returns the user's login name, or NULL if it cannot be found.  Upon error,\n   returns NULL with errno set.\n\n   See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getlogin.html>.\n\n   Most programs don't need to use this function, because the information is\n   available through environment variables:\n     ${LOGNAME-$USER}        on Unix platforms,\n     $USERNAME               on native Windows platforms.\n */\n# if !@HAVE_DECL_GETLOGIN@\n_GL_FUNCDECL_SYS (getlogin, char *, (void));\n# endif\n_GL_CXXALIAS_SYS (getlogin, char *, (void));\n_GL_CXXALIASWARN (getlogin);\n#elif defined GNULIB_POSIXCHECK\n# undef getlogin\n# if HAVE_RAW_DECL_GETLOGIN\n_GL_WARN_ON_USE (getlogin, \"getlogin is unportable - \"\n                 \"use gnulib module getlogin for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETLOGIN_R@\n/* Copies the user's login name to NAME.\n   The array pointed to by NAME has room for SIZE bytes.\n\n   Returns 0 if successful.  Upon error, an error number is returned, or -1 in\n   the case that the login name cannot be found but no specific error is\n   provided (this case is hopefully rare but is left open by the POSIX spec).\n\n   See <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getlogin.html>.\n\n   Most programs don't need to use this function, because the information is\n   available through environment variables:\n     ${LOGNAME-$USER}        on Unix platforms,\n     $USERNAME               on native Windows platforms.\n */\n# if @REPLACE_GETLOGIN_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define getlogin_r rpl_getlogin_r\n#  endif\n_GL_FUNCDECL_RPL (getlogin_r, int, (char *name, size_t size)\n                                   _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (getlogin_r, int, (char *name, size_t size));\n# else\n#  if !@HAVE_DECL_GETLOGIN_R@\n_GL_FUNCDECL_SYS (getlogin_r, int, (char *name, size_t size)\n                                   _GL_ARG_NONNULL ((1)));\n#  endif\n/* Need to cast, because on Solaris 10 systems, the second argument is\n                                                     int size.  */\n_GL_CXXALIAS_SYS_CAST (getlogin_r, int, (char *name, size_t size));\n# endif\n_GL_CXXALIASWARN (getlogin_r);\n#elif defined GNULIB_POSIXCHECK\n# undef getlogin_r\n# if HAVE_RAW_DECL_GETLOGIN_R\n_GL_WARN_ON_USE (getlogin_r, \"getlogin_r is unportable - \"\n                 \"use gnulib module getlogin_r for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETPAGESIZE@\n# if @REPLACE_GETPAGESIZE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define getpagesize rpl_getpagesize\n#  endif\n_GL_FUNCDECL_RPL (getpagesize, int, (void));\n_GL_CXXALIAS_RPL (getpagesize, int, (void));\n# else\n/* On HP-UX, getpagesize exists, but it is not declared in <unistd.h> even if\n   the compiler options -D_HPUX_SOURCE -D_XOPEN_SOURCE=600 are used.  */\n#  if defined __hpux\n_GL_FUNCDECL_SYS (getpagesize, int, (void));\n#  endif\n#  if !@HAVE_GETPAGESIZE@\n#   if !defined getpagesize\n/* This is for POSIX systems.  */\n#    if !defined _gl_getpagesize && defined _SC_PAGESIZE\n#     if ! (defined __VMS && __VMS_VER < 70000000)\n#      define _gl_getpagesize() sysconf (_SC_PAGESIZE)\n#     endif\n#    endif\n/* This is for older VMS.  */\n#    if !defined _gl_getpagesize && defined __VMS\n#     ifdef __ALPHA\n#      define _gl_getpagesize() 8192\n#     else\n#      define _gl_getpagesize() 512\n#     endif\n#    endif\n/* This is for BeOS.  */\n#    if !defined _gl_getpagesize && @HAVE_OS_H@\n#     include <OS.h>\n#     if defined B_PAGE_SIZE\n#      define _gl_getpagesize() B_PAGE_SIZE\n#     endif\n#    endif\n/* This is for AmigaOS4.0.  */\n#    if !defined _gl_getpagesize && defined __amigaos4__\n#     define _gl_getpagesize() 2048\n#    endif\n/* This is for older Unix systems.  */\n#    if !defined _gl_getpagesize && @HAVE_SYS_PARAM_H@\n#     include <sys/param.h>\n#     ifdef EXEC_PAGESIZE\n#      define _gl_getpagesize() EXEC_PAGESIZE\n#     else\n#      ifdef NBPG\n#       ifndef CLSIZE\n#        define CLSIZE 1\n#       endif\n#       define _gl_getpagesize() (NBPG * CLSIZE)\n#      else\n#       ifdef NBPC\n#        define _gl_getpagesize() NBPC\n#       endif\n#      endif\n#     endif\n#    endif\n#    if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#     define getpagesize() _gl_getpagesize ()\n#    else\n#     if !GNULIB_defined_getpagesize_function\n_GL_UNISTD_INLINE int\ngetpagesize ()\n{\n  return _gl_getpagesize ();\n}\n#      define GNULIB_defined_getpagesize_function 1\n#     endif\n#    endif\n#   endif\n#  endif\n/* Need to cast, because on Cygwin 1.5.x systems, the return type is size_t.  */\n_GL_CXXALIAS_SYS_CAST (getpagesize, int, (void));\n# endif\n# if @HAVE_DECL_GETPAGESIZE@\n_GL_CXXALIASWARN (getpagesize);\n# endif\n#elif defined GNULIB_POSIXCHECK\n# undef getpagesize\n# if HAVE_RAW_DECL_GETPAGESIZE\n_GL_WARN_ON_USE (getpagesize, \"getpagesize is unportable - \"\n                 \"use gnulib module getpagesize for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GETPASS@\n/* Function getpass() from module 'getpass':\n     Read a password from /dev/tty or stdin.\n   Function getpass() from module 'getpass-gnu':\n     Read a password of arbitrary length from /dev/tty or stdin.  */\n# if @REPLACE_GETPASS@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getpass\n#   define getpass rpl_getpass\n#  endif\n_GL_FUNCDECL_RPL (getpass, char *, (const char *prompt)\n                                   _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (getpass, char *, (const char *prompt));\n# else\n#  if !@HAVE_GETPASS@\n_GL_FUNCDECL_SYS (getpass, char *, (const char *prompt)\n                                   _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (getpass, char *, (const char *prompt));\n# endif\n_GL_CXXALIASWARN (getpass);\n#elif defined GNULIB_POSIXCHECK\n# undef getpass\n# if HAVE_RAW_DECL_GETPASS\n_GL_WARN_ON_USE (getpass, \"getpass is unportable - \"\n                 \"use gnulib module getpass or getpass-gnu for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MDA_GETPID@\n/* On native Windows, map 'getpid' to '_getpid', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::getpid always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef getpid\n#   define getpid _getpid\n#  endif\n_GL_CXXALIAS_MDA (getpid, int, (void));\n# else\n_GL_CXXALIAS_SYS (getpid, pid_t, (void));\n# endif\n_GL_CXXALIASWARN (getpid);\n#endif\n\n\n#if @GNULIB_GETUSERSHELL@\n/* Return the next valid login shell on the system, or NULL when the end of\n   the list has been reached.  */\n# if !@HAVE_DECL_GETUSERSHELL@\n_GL_FUNCDECL_SYS (getusershell, char *, (void));\n# endif\n_GL_CXXALIAS_SYS (getusershell, char *, (void));\n_GL_CXXALIASWARN (getusershell);\n#elif defined GNULIB_POSIXCHECK\n# undef getusershell\n# if HAVE_RAW_DECL_GETUSERSHELL\n_GL_WARN_ON_USE (getusershell, \"getusershell is unportable - \"\n                 \"use gnulib module getusershell for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETUSERSHELL@\n/* Rewind to pointer that is advanced at each getusershell() call.  */\n# if !@HAVE_DECL_GETUSERSHELL@\n_GL_FUNCDECL_SYS (setusershell, void, (void));\n# endif\n_GL_CXXALIAS_SYS (setusershell, void, (void));\n_GL_CXXALIASWARN (setusershell);\n#elif defined GNULIB_POSIXCHECK\n# undef setusershell\n# if HAVE_RAW_DECL_SETUSERSHELL\n_GL_WARN_ON_USE (setusershell, \"setusershell is unportable - \"\n                 \"use gnulib module getusershell for portability\");\n# endif\n#endif\n\n#if @GNULIB_GETUSERSHELL@\n/* Free the pointer that is advanced at each getusershell() call and\n   associated resources.  */\n# if !@HAVE_DECL_GETUSERSHELL@\n_GL_FUNCDECL_SYS (endusershell, void, (void));\n# endif\n_GL_CXXALIAS_SYS (endusershell, void, (void));\n_GL_CXXALIASWARN (endusershell);\n#elif defined GNULIB_POSIXCHECK\n# undef endusershell\n# if HAVE_RAW_DECL_ENDUSERSHELL\n_GL_WARN_ON_USE (endusershell, \"endusershell is unportable - \"\n                 \"use gnulib module getusershell for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_GROUP_MEMBER@\n/* Determine whether group id is in calling user's group list.  */\n# if !@HAVE_GROUP_MEMBER@\n_GL_FUNCDECL_SYS (group_member, int, (gid_t gid));\n# endif\n_GL_CXXALIAS_SYS (group_member, int, (gid_t gid));\n_GL_CXXALIASWARN (group_member);\n#elif defined GNULIB_POSIXCHECK\n# undef group_member\n# if HAVE_RAW_DECL_GROUP_MEMBER\n_GL_WARN_ON_USE (group_member, \"group_member is unportable - \"\n                 \"use gnulib module group-member for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_ISATTY@\n# if @REPLACE_ISATTY@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef isatty\n#   define isatty rpl_isatty\n#  endif\n#  define GNULIB_defined_isatty 1\n_GL_FUNCDECL_RPL (isatty, int, (int fd));\n_GL_CXXALIAS_RPL (isatty, int, (int fd));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef isatty\n#   define isatty _isatty\n#  endif\n_GL_CXXALIAS_MDA (isatty, int, (int fd));\n# else\n_GL_CXXALIAS_SYS (isatty, int, (int fd));\n# endif\n_GL_CXXALIASWARN (isatty);\n#elif defined GNULIB_POSIXCHECK\n# undef isatty\n# if HAVE_RAW_DECL_ISATTY\n_GL_WARN_ON_USE (isatty, \"isatty has portability problems on native Windows - \"\n                 \"use gnulib module isatty for portability\");\n# endif\n#elif @GNULIB_MDA_ISATTY@\n/* On native Windows, map 'isatty' to '_isatty', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::isatty always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef isatty\n#   define isatty _isatty\n#  endif\n_GL_CXXALIAS_MDA (isatty, int, (int fd));\n# else\n_GL_CXXALIAS_SYS (isatty, int, (int fd));\n# endif\n_GL_CXXALIASWARN (isatty);\n#endif\n\n\n#if @GNULIB_LCHOWN@\n/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE\n   to GID (if GID is not -1).  Do not follow symbolic links.\n   Return 0 if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html>.  */\n# if @REPLACE_LCHOWN@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef lchown\n#   define lchown rpl_lchown\n#  endif\n_GL_FUNCDECL_RPL (lchown, int, (char const *file, uid_t owner, gid_t group)\n                               _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (lchown, int, (char const *file, uid_t owner, gid_t group));\n# else\n#  if !@HAVE_LCHOWN@\n_GL_FUNCDECL_SYS (lchown, int, (char const *file, uid_t owner, gid_t group)\n                               _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (lchown, int, (char const *file, uid_t owner, gid_t group));\n# endif\n_GL_CXXALIASWARN (lchown);\n#elif defined GNULIB_POSIXCHECK\n# undef lchown\n# if HAVE_RAW_DECL_LCHOWN\n_GL_WARN_ON_USE (lchown, \"lchown is unportable to pre-POSIX.1-2001 systems - \"\n                 \"use gnulib module lchown for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_LINK@\n/* Create a new hard link for an existing file.\n   Return 0 if successful, otherwise -1 and errno set.\n   See POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html>.  */\n# if @REPLACE_LINK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define link rpl_link\n#  endif\n_GL_FUNCDECL_RPL (link, int, (const char *path1, const char *path2)\n                             _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (link, int, (const char *path1, const char *path2));\n# else\n#  if !@HAVE_LINK@\n_GL_FUNCDECL_SYS (link, int, (const char *path1, const char *path2)\n                             _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (link, int, (const char *path1, const char *path2));\n# endif\n_GL_CXXALIASWARN (link);\n#elif defined GNULIB_POSIXCHECK\n# undef link\n# if HAVE_RAW_DECL_LINK\n_GL_WARN_ON_USE (link, \"link is unportable - \"\n                 \"use gnulib module link for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_LINKAT@\n/* Create a new hard link for an existing file, relative to two\n   directories.  FLAG controls whether symlinks are followed.\n   Return 0 if successful, otherwise -1 and errno set.  */\n# if @REPLACE_LINKAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef linkat\n#   define linkat rpl_linkat\n#  endif\n_GL_FUNCDECL_RPL (linkat, int,\n                  (int fd1, const char *path1, int fd2, const char *path2,\n                   int flag)\n                  _GL_ARG_NONNULL ((2, 4)));\n_GL_CXXALIAS_RPL (linkat, int,\n                  (int fd1, const char *path1, int fd2, const char *path2,\n                   int flag));\n# else\n#  if !@HAVE_LINKAT@\n_GL_FUNCDECL_SYS (linkat, int,\n                  (int fd1, const char *path1, int fd2, const char *path2,\n                   int flag)\n                  _GL_ARG_NONNULL ((2, 4)));\n#  endif\n_GL_CXXALIAS_SYS (linkat, int,\n                  (int fd1, const char *path1, int fd2, const char *path2,\n                   int flag));\n# endif\n_GL_CXXALIASWARN (linkat);\n#elif defined GNULIB_POSIXCHECK\n# undef linkat\n# if HAVE_RAW_DECL_LINKAT\n_GL_WARN_ON_USE (linkat, \"linkat is unportable - \"\n                 \"use gnulib module linkat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_LSEEK@\n/* Set the offset of FD relative to SEEK_SET, SEEK_CUR, or SEEK_END.\n   Return the new offset if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html>.  */\n# if @REPLACE_LSEEK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define lseek rpl_lseek\n#  endif\n_GL_FUNCDECL_RPL (lseek, off_t, (int fd, off_t offset, int whence));\n_GL_CXXALIAS_RPL (lseek, off_t, (int fd, off_t offset, int whence));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef lseek\n#   define lseek _lseek\n#  endif\n_GL_CXXALIAS_MDA (lseek, off_t, (int fd, off_t offset, int whence));\n# else\n_GL_CXXALIAS_SYS (lseek, off_t, (int fd, off_t offset, int whence));\n# endif\n_GL_CXXALIASWARN (lseek);\n#elif defined GNULIB_POSIXCHECK\n# undef lseek\n# if HAVE_RAW_DECL_LSEEK\n_GL_WARN_ON_USE (lseek, \"lseek does not fail with ESPIPE on pipes on some \"\n                 \"systems - use gnulib module lseek for portability\");\n# endif\n#elif @GNULIB_MDA_LSEEK@\n/* On native Windows, map 'lseek' to '_lseek', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::lseek always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef lseek\n#   define lseek _lseek\n#  endif\n_GL_CXXALIAS_MDA (lseek, long, (int fd, long offset, int whence));\n# else\n_GL_CXXALIAS_SYS (lseek, off_t, (int fd, off_t offset, int whence));\n# endif\n_GL_CXXALIASWARN (lseek);\n#endif\n\n\n#if @GNULIB_PIPE@\n/* Create a pipe, defaulting to O_BINARY mode.\n   Store the read-end as fd[0] and the write-end as fd[1].\n   Return 0 upon success, or -1 with errno set upon failure.  */\n# if !@HAVE_PIPE@\n_GL_FUNCDECL_SYS (pipe, int, (int fd[2]) _GL_ARG_NONNULL ((1)));\n# endif\n_GL_CXXALIAS_SYS (pipe, int, (int fd[2]));\n_GL_CXXALIASWARN (pipe);\n#elif defined GNULIB_POSIXCHECK\n# undef pipe\n# if HAVE_RAW_DECL_PIPE\n_GL_WARN_ON_USE (pipe, \"pipe is unportable - \"\n                 \"use gnulib module pipe-posix for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_PIPE2@\n/* Create a pipe, applying the given flags when opening the read-end of the\n   pipe and the write-end of the pipe.\n   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>)\n   and O_TEXT, O_BINARY (defined in \"binary-io.h\").\n   Store the read-end as fd[0] and the write-end as fd[1].\n   Return 0 upon success, or -1 with errno set upon failure.\n   See also the Linux man page at\n   <https://www.kernel.org/doc/man-pages/online/pages/man2/pipe2.2.html>.  */\n# if @HAVE_PIPE2@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define pipe2 rpl_pipe2\n#  endif\n_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (pipe2, int, (int fd[2], int flags));\n# else\n_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags));\n# endif\n_GL_CXXALIASWARN (pipe2);\n#elif defined GNULIB_POSIXCHECK\n# undef pipe2\n# if HAVE_RAW_DECL_PIPE2\n_GL_WARN_ON_USE (pipe2, \"pipe2 is unportable - \"\n                 \"use gnulib module pipe2 for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_PREAD@\n/* Read at most BUFSIZE bytes from FD into BUF, starting at OFFSET.\n   Return the number of bytes placed into BUF if successful, otherwise\n   set errno and return -1.  0 indicates EOF.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html>.  */\n# if @REPLACE_PREAD@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef pread\n#   define pread rpl_pread\n#  endif\n_GL_FUNCDECL_RPL (pread, ssize_t,\n                  (int fd, void *buf, size_t bufsize, off_t offset)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (pread, ssize_t,\n                  (int fd, void *buf, size_t bufsize, off_t offset));\n# else\n#  if !@HAVE_PREAD@\n_GL_FUNCDECL_SYS (pread, ssize_t,\n                  (int fd, void *buf, size_t bufsize, off_t offset)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (pread, ssize_t,\n                  (int fd, void *buf, size_t bufsize, off_t offset));\n# endif\n_GL_CXXALIASWARN (pread);\n#elif defined GNULIB_POSIXCHECK\n# undef pread\n# if HAVE_RAW_DECL_PREAD\n_GL_WARN_ON_USE (pread, \"pread is unportable - \"\n                 \"use gnulib module pread for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_PWRITE@\n/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET.\n   Return the number of bytes written if successful, otherwise\n   set errno and return -1.  0 indicates nothing written.  See the\n   POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html>.  */\n# if @REPLACE_PWRITE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef pwrite\n#   define pwrite rpl_pwrite\n#  endif\n_GL_FUNCDECL_RPL (pwrite, ssize_t,\n                  (int fd, const void *buf, size_t bufsize, off_t offset)\n                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (pwrite, ssize_t,\n                  (int fd, const void *buf, size_t bufsize, off_t offset));\n# else\n#  if !@HAVE_PWRITE@\n_GL_FUNCDECL_SYS (pwrite, ssize_t,\n                  (int fd, const void *buf, size_t bufsize, off_t offset)\n                  _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (pwrite, ssize_t,\n                  (int fd, const void *buf, size_t bufsize, off_t offset));\n# endif\n_GL_CXXALIASWARN (pwrite);\n#elif defined GNULIB_POSIXCHECK\n# undef pwrite\n# if HAVE_RAW_DECL_PWRITE\n_GL_WARN_ON_USE (pwrite, \"pwrite is unportable - \"\n                 \"use gnulib module pwrite for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_READ@\n/* Read up to COUNT bytes from file descriptor FD into the buffer starting\n   at BUF.  See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html>.  */\n# if @REPLACE_READ@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef read\n#   define read rpl_read\n#  endif\n_GL_FUNCDECL_RPL (read, ssize_t, (int fd, void *buf, size_t count)\n                                 _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (read, ssize_t, (int fd, void *buf, size_t count));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef read\n#   define read _read\n#  endif\n_GL_CXXALIAS_MDA (read, ssize_t, (int fd, void *buf, size_t count));\n# else\n_GL_CXXALIAS_SYS (read, ssize_t, (int fd, void *buf, size_t count));\n# endif\n_GL_CXXALIASWARN (read);\n#elif @GNULIB_MDA_READ@\n/* On native Windows, map 'read' to '_read', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::read always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef read\n#   define read _read\n#  endif\n#  ifdef __MINGW32__\n_GL_CXXALIAS_MDA (read, int, (int fd, void *buf, unsigned int count));\n#  else\n_GL_CXXALIAS_MDA (read, ssize_t, (int fd, void *buf, unsigned int count));\n#  endif\n# else\n_GL_CXXALIAS_SYS (read, ssize_t, (int fd, void *buf, size_t count));\n# endif\n_GL_CXXALIASWARN (read);\n#endif\n\n\n#if @GNULIB_READLINK@\n/* Read the contents of the symbolic link FILE and place the first BUFSIZE\n   bytes of it into BUF.  Return the number of bytes placed into BUF if\n   successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>.  */\n# if @REPLACE_READLINK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define readlink rpl_readlink\n#  endif\n_GL_FUNCDECL_RPL (readlink, ssize_t,\n                  (const char *restrict file,\n                   char *restrict buf, size_t bufsize)\n                  _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (readlink, ssize_t,\n                  (const char *restrict file,\n                   char *restrict buf, size_t bufsize));\n# else\n#  if !@HAVE_READLINK@\n_GL_FUNCDECL_SYS (readlink, ssize_t,\n                  (const char *restrict file,\n                   char *restrict buf, size_t bufsize)\n                  _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (readlink, ssize_t,\n                  (const char *restrict file,\n                   char *restrict buf, size_t bufsize));\n# endif\n_GL_CXXALIASWARN (readlink);\n#elif defined GNULIB_POSIXCHECK\n# undef readlink\n# if HAVE_RAW_DECL_READLINK\n_GL_WARN_ON_USE (readlink, \"readlink is unportable - \"\n                 \"use gnulib module readlink for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_READLINKAT@\n# if @REPLACE_READLINKAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define readlinkat rpl_readlinkat\n#  endif\n_GL_FUNCDECL_RPL (readlinkat, ssize_t,\n                  (int fd, char const *restrict file,\n                   char *restrict buf, size_t len)\n                  _GL_ARG_NONNULL ((2, 3)));\n_GL_CXXALIAS_RPL (readlinkat, ssize_t,\n                  (int fd, char const *restrict file,\n                   char *restrict buf, size_t len));\n# else\n#  if !@HAVE_READLINKAT@\n_GL_FUNCDECL_SYS (readlinkat, ssize_t,\n                  (int fd, char const *restrict file,\n                   char *restrict buf, size_t len)\n                  _GL_ARG_NONNULL ((2, 3)));\n#  endif\n_GL_CXXALIAS_SYS (readlinkat, ssize_t,\n                  (int fd, char const *restrict file,\n                   char *restrict buf, size_t len));\n# endif\n_GL_CXXALIASWARN (readlinkat);\n#elif defined GNULIB_POSIXCHECK\n# undef readlinkat\n# if HAVE_RAW_DECL_READLINKAT\n_GL_WARN_ON_USE (readlinkat, \"readlinkat is not portable - \"\n                 \"use gnulib module readlinkat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_RMDIR@\n/* Remove the directory DIR.  */\n# if @REPLACE_RMDIR@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   define rmdir rpl_rmdir\n#  endif\n_GL_FUNCDECL_RPL (rmdir, int, (char const *name) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (rmdir, int, (char const *name));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef rmdir\n#   define rmdir _rmdir\n#  endif\n_GL_CXXALIAS_MDA (rmdir, int, (char const *name));\n# else\n_GL_CXXALIAS_SYS (rmdir, int, (char const *name));\n# endif\n_GL_CXXALIASWARN (rmdir);\n#elif defined GNULIB_POSIXCHECK\n# undef rmdir\n# if HAVE_RAW_DECL_RMDIR\n_GL_WARN_ON_USE (rmdir, \"rmdir is unportable - \"\n                 \"use gnulib module rmdir for portability\");\n# endif\n#elif @GNULIB_MDA_RMDIR@\n/* On native Windows, map 'rmdir' to '_rmdir', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::rmdir always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef rmdir\n#   define rmdir _rmdir\n#  endif\n_GL_CXXALIAS_MDA (rmdir, int, (char const *name));\n# else\n_GL_CXXALIAS_SYS (rmdir, int, (char const *name));\n# endif\n_GL_CXXALIASWARN (rmdir);\n#endif\n\n\n#if @GNULIB_SETHOSTNAME@\n/* Set the host name of the machine.\n   The host name may or may not be fully qualified.\n\n   Put LEN bytes of NAME into the host name.\n   Return 0 if successful, otherwise, set errno and return -1.\n\n   Platforms with no ability to set the hostname return -1 and set\n   errno = ENOSYS.  */\n# if !@HAVE_SETHOSTNAME@ || !@HAVE_DECL_SETHOSTNAME@\n_GL_FUNCDECL_SYS (sethostname, int, (const char *name, size_t len)\n                                    _GL_ARG_NONNULL ((1)));\n# endif\n/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5\n   and FreeBSD 6.4 the second parameter is int.  On Solaris 11\n   2011-10, the first parameter is not const.  */\n_GL_CXXALIAS_SYS_CAST (sethostname, int, (const char *name, size_t len));\n_GL_CXXALIASWARN (sethostname);\n#elif defined GNULIB_POSIXCHECK\n# undef sethostname\n# if HAVE_RAW_DECL_SETHOSTNAME\n_GL_WARN_ON_USE (sethostname, \"sethostname is unportable - \"\n                 \"use gnulib module sethostname for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_SLEEP@\n/* Pause the execution of the current thread for N seconds.\n   Returns the number of seconds left to sleep.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html>.  */\n# if @REPLACE_SLEEP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef sleep\n#   define sleep rpl_sleep\n#  endif\n_GL_FUNCDECL_RPL (sleep, unsigned int, (unsigned int n));\n_GL_CXXALIAS_RPL (sleep, unsigned int, (unsigned int n));\n# else\n#  if !@HAVE_SLEEP@\n_GL_FUNCDECL_SYS (sleep, unsigned int, (unsigned int n));\n#  endif\n_GL_CXXALIAS_SYS (sleep, unsigned int, (unsigned int n));\n# endif\n_GL_CXXALIASWARN (sleep);\n#elif defined GNULIB_POSIXCHECK\n# undef sleep\n# if HAVE_RAW_DECL_SLEEP\n_GL_WARN_ON_USE (sleep, \"sleep is unportable - \"\n                 \"use gnulib module sleep for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_MDA_SWAB@\n/* On native Windows, map 'swab' to '_swab', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::swab always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef swab\n#   define swab _swab\n#  endif\n/* Need to cast, because in old mingw the arguments are\n                             (const char *from, char *to, size_t n).  */\n_GL_CXXALIAS_MDA_CAST (swab, void, (char *from, char *to, int n));\n# else\n#  if defined __hpux /* HP-UX */\n_GL_CXXALIAS_SYS (swab, void, (const char *from, char *to, int n));\n#  elif defined __sun && !defined _XPG4 /* Solaris */\n_GL_CXXALIAS_SYS (swab, void, (const char *from, char *to, ssize_t n));\n#  else\n_GL_CXXALIAS_SYS (swab, void, (const void *from, void *to, ssize_t n));\n#  endif\n# endif\n_GL_CXXALIASWARN (swab);\n#endif\n\n\n#if @GNULIB_SYMLINK@\n# if @REPLACE_SYMLINK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef symlink\n#   define symlink rpl_symlink\n#  endif\n_GL_FUNCDECL_RPL (symlink, int, (char const *contents, char const *file)\n                                _GL_ARG_NONNULL ((1, 2)));\n_GL_CXXALIAS_RPL (symlink, int, (char const *contents, char const *file));\n# else\n#  if !@HAVE_SYMLINK@\n_GL_FUNCDECL_SYS (symlink, int, (char const *contents, char const *file)\n                                _GL_ARG_NONNULL ((1, 2)));\n#  endif\n_GL_CXXALIAS_SYS (symlink, int, (char const *contents, char const *file));\n# endif\n_GL_CXXALIASWARN (symlink);\n#elif defined GNULIB_POSIXCHECK\n# undef symlink\n# if HAVE_RAW_DECL_SYMLINK\n_GL_WARN_ON_USE (symlink, \"symlink is not portable - \"\n                 \"use gnulib module symlink for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_SYMLINKAT@\n# if @REPLACE_SYMLINKAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef symlinkat\n#   define symlinkat rpl_symlinkat\n#  endif\n_GL_FUNCDECL_RPL (symlinkat, int,\n                  (char const *contents, int fd, char const *file)\n                  _GL_ARG_NONNULL ((1, 3)));\n_GL_CXXALIAS_RPL (symlinkat, int,\n                  (char const *contents, int fd, char const *file));\n# else\n#  if !@HAVE_SYMLINKAT@\n_GL_FUNCDECL_SYS (symlinkat, int,\n                  (char const *contents, int fd, char const *file)\n                  _GL_ARG_NONNULL ((1, 3)));\n#  endif\n_GL_CXXALIAS_SYS (symlinkat, int,\n                  (char const *contents, int fd, char const *file));\n# endif\n_GL_CXXALIASWARN (symlinkat);\n#elif defined GNULIB_POSIXCHECK\n# undef symlinkat\n# if HAVE_RAW_DECL_SYMLINKAT\n_GL_WARN_ON_USE (symlinkat, \"symlinkat is not portable - \"\n                 \"use gnulib module symlinkat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_TRUNCATE@\n/* Change the size of the file designated by FILENAME to become equal to LENGTH.\n   Return 0 if successful, otherwise -1 and errno set.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html>.  */\n# if @REPLACE_TRUNCATE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef truncate\n#   define truncate rpl_truncate\n#  endif\n_GL_FUNCDECL_RPL (truncate, int, (const char *filename, off_t length)\n                                 _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (truncate, int, (const char *filename, off_t length));\n# else\n#  if !@HAVE_DECL_TRUNCATE@\n_GL_FUNCDECL_SYS (truncate, int, (const char *filename, off_t length)\n                                 _GL_ARG_NONNULL ((1)));\n#  endif\n_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length));\n# endif\n_GL_CXXALIASWARN (truncate);\n#elif defined GNULIB_POSIXCHECK\n# undef truncate\n# if HAVE_RAW_DECL_TRUNCATE\n_GL_WARN_ON_USE (truncate, \"truncate is unportable - \"\n                 \"use gnulib module truncate for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_TTYNAME_R@\n/* Store at most BUFLEN characters of the pathname of the terminal FD is\n   open on in BUF.  Return 0 on success, otherwise an error number.  */\n# if @REPLACE_TTYNAME_R@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef ttyname_r\n#   define ttyname_r rpl_ttyname_r\n#  endif\n_GL_FUNCDECL_RPL (ttyname_r, int,\n                  (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (ttyname_r, int,\n                  (int fd, char *buf, size_t buflen));\n# else\n#  if !@HAVE_DECL_TTYNAME_R@\n_GL_FUNCDECL_SYS (ttyname_r, int,\n                  (int fd, char *buf, size_t buflen) _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (ttyname_r, int,\n                  (int fd, char *buf, size_t buflen));\n# endif\n_GL_CXXALIASWARN (ttyname_r);\n#elif defined GNULIB_POSIXCHECK\n# undef ttyname_r\n# if HAVE_RAW_DECL_TTYNAME_R\n_GL_WARN_ON_USE (ttyname_r, \"ttyname_r is not portable - \"\n                 \"use gnulib module ttyname_r for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_UNLINK@\n# if @REPLACE_UNLINK@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef unlink\n#   define unlink rpl_unlink\n#  endif\n_GL_FUNCDECL_RPL (unlink, int, (char const *file) _GL_ARG_NONNULL ((1)));\n_GL_CXXALIAS_RPL (unlink, int, (char const *file));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef unlink\n#   define unlink _unlink\n#  endif\n_GL_CXXALIAS_MDA (unlink, int, (char const *file));\n# else\n_GL_CXXALIAS_SYS (unlink, int, (char const *file));\n# endif\n_GL_CXXALIASWARN (unlink);\n#elif defined GNULIB_POSIXCHECK\n# undef unlink\n# if HAVE_RAW_DECL_UNLINK\n_GL_WARN_ON_USE (unlink, \"unlink is not portable - \"\n                 \"use gnulib module unlink for portability\");\n# endif\n#elif @GNULIB_MDA_UNLINK@\n/* On native Windows, map 'unlink' to '_unlink', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::unlink always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef unlink\n#   define unlink _unlink\n#  endif\n_GL_CXXALIAS_MDA (unlink, int, (char const *file));\n# else\n_GL_CXXALIAS_SYS (unlink, int, (char const *file));\n# endif\n_GL_CXXALIASWARN (unlink);\n#endif\n\n\n#if @GNULIB_UNLINKAT@\n# if @REPLACE_UNLINKAT@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef unlinkat\n#   define unlinkat rpl_unlinkat\n#  endif\n_GL_FUNCDECL_RPL (unlinkat, int, (int fd, char const *file, int flag)\n                                 _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (unlinkat, int, (int fd, char const *file, int flag));\n# else\n#  if !@HAVE_UNLINKAT@\n_GL_FUNCDECL_SYS (unlinkat, int, (int fd, char const *file, int flag)\n                                 _GL_ARG_NONNULL ((2)));\n#  endif\n_GL_CXXALIAS_SYS (unlinkat, int, (int fd, char const *file, int flag));\n# endif\n_GL_CXXALIASWARN (unlinkat);\n#elif defined GNULIB_POSIXCHECK\n# undef unlinkat\n# if HAVE_RAW_DECL_UNLINKAT\n_GL_WARN_ON_USE (unlinkat, \"unlinkat is not portable - \"\n                 \"use gnulib module unlinkat for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_USLEEP@\n/* Pause the execution of the current thread for N microseconds.\n   Returns 0 on completion, or -1 on range error.\n   See the POSIX:2001 specification\n   <https://pubs.opengroup.org/onlinepubs/009695399/functions/usleep.html>.  */\n# if @REPLACE_USLEEP@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef usleep\n#   define usleep rpl_usleep\n#  endif\n_GL_FUNCDECL_RPL (usleep, int, (useconds_t n));\n_GL_CXXALIAS_RPL (usleep, int, (useconds_t n));\n# else\n#  if !@HAVE_USLEEP@\n_GL_FUNCDECL_SYS (usleep, int, (useconds_t n));\n#  endif\n/* Need to cast, because on Haiku, the first parameter is\n                                     unsigned int n.  */\n_GL_CXXALIAS_SYS_CAST (usleep, int, (useconds_t n));\n# endif\n_GL_CXXALIASWARN (usleep);\n#elif defined GNULIB_POSIXCHECK\n# undef usleep\n# if HAVE_RAW_DECL_USLEEP\n_GL_WARN_ON_USE (usleep, \"usleep is unportable - \"\n                 \"use gnulib module usleep for portability\");\n# endif\n#endif\n\n\n#if @GNULIB_WRITE@\n/* Write up to COUNT bytes starting at BUF to file descriptor FD.\n   See the POSIX:2008 specification\n   <https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html>.  */\n# if @REPLACE_WRITE@\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef write\n#   define write rpl_write\n#  endif\n_GL_FUNCDECL_RPL (write, ssize_t, (int fd, const void *buf, size_t count)\n                                  _GL_ARG_NONNULL ((2)));\n_GL_CXXALIAS_RPL (write, ssize_t, (int fd, const void *buf, size_t count));\n# elif defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef write\n#   define write _write\n#  endif\n_GL_CXXALIAS_MDA (write, ssize_t, (int fd, const void *buf, size_t count));\n# else\n_GL_CXXALIAS_SYS (write, ssize_t, (int fd, const void *buf, size_t count));\n# endif\n_GL_CXXALIASWARN (write);\n#elif @GNULIB_MDA_WRITE@\n/* On native Windows, map 'write' to '_write', so that -loldnames is not\n   required.  In C++ with GNULIB_NAMESPACE, avoid differences between\n   platforms by defining GNULIB_NAMESPACE::write always.  */\n# if defined _WIN32 && !defined __CYGWIN__\n#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)\n#   undef write\n#   define write _write\n#  endif\n#  ifdef __MINGW32__\n_GL_CXXALIAS_MDA (write, int, (int fd, const void *buf, unsigned int count));\n#  else\n_GL_CXXALIAS_MDA (write, ssize_t, (int fd, const void *buf, unsigned int count));\n#  endif\n# else\n_GL_CXXALIAS_SYS (write, ssize_t, (int fd, const void *buf, size_t count));\n# endif\n_GL_CXXALIASWARN (write);\n#endif\n\n_GL_INLINE_HEADER_END\n\n#endif /* _@GUARD_PREFIX@_UNISTD_H */\n#endif /* _GL_INCLUDING_UNISTD_H */\n#endif /* _@GUARD_PREFIX@_UNISTD_H */\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/w32sock.h",
    "content": "/* w32sock.h --- internal auxiliary functions for Windows socket functions\n\n   Copyright (C) 2008-2021 Free Software Foundation, Inc.\n\n   This file is free software: you can redistribute it and/or modify\n   it under the terms of the GNU Lesser General Public License as\n   published by the Free Software Foundation; either version 2.1 of the\n   License, or (at your option) any later version.\n\n   This file is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* Written by Paolo Bonzini */\n\n#include <errno.h>\n\n/* Get O_RDWR and O_BINARY.  */\n#include <fcntl.h>\n\n/* Get _open_osfhandle().  */\n#include <io.h>\n\n/* Get _get_osfhandle().  */\n#if GNULIB_MSVC_NOTHROW\n# include \"msvc-nothrow.h\"\n#else\n# include <io.h>\n#endif\n\n#define FD_TO_SOCKET(fd)   ((SOCKET) _get_osfhandle ((fd)))\n#define SOCKET_TO_FD(fh)   (_open_osfhandle ((intptr_t) (fh), O_RDWR | O_BINARY))\n\nstatic inline void\nset_winsock_errno (void)\n{\n  int err = WSAGetLastError ();\n\n  /* Map some WSAE* errors to the runtime library's error codes.  */\n  switch (err)\n    {\n    case WSA_INVALID_HANDLE:\n      errno = EBADF;\n      break;\n    case WSA_NOT_ENOUGH_MEMORY:\n      errno = ENOMEM;\n      break;\n    case WSA_INVALID_PARAMETER:\n      errno = EINVAL;\n      break;\n    case WSAENAMETOOLONG:\n      errno = ENAMETOOLONG;\n      break;\n    case WSAENOTEMPTY:\n      errno = ENOTEMPTY;\n      break;\n    case WSAEWOULDBLOCK:\n      errno = EWOULDBLOCK;\n      break;\n    case WSAEINPROGRESS:\n      errno = EINPROGRESS;\n      break;\n    case WSAEALREADY:\n      errno = EALREADY;\n      break;\n    case WSAENOTSOCK:\n      errno = ENOTSOCK;\n      break;\n    case WSAEDESTADDRREQ:\n      errno = EDESTADDRREQ;\n      break;\n    case WSAEMSGSIZE:\n      errno = EMSGSIZE;\n      break;\n    case WSAEPROTOTYPE:\n      errno = EPROTOTYPE;\n      break;\n    case WSAENOPROTOOPT:\n      errno = ENOPROTOOPT;\n      break;\n    case WSAEPROTONOSUPPORT:\n      errno = EPROTONOSUPPORT;\n      break;\n    case WSAEOPNOTSUPP:\n      errno = EOPNOTSUPP;\n      break;\n    case WSAEAFNOSUPPORT:\n      errno = EAFNOSUPPORT;\n      break;\n    case WSAEADDRINUSE:\n      errno = EADDRINUSE;\n      break;\n    case WSAEADDRNOTAVAIL:\n      errno = EADDRNOTAVAIL;\n      break;\n    case WSAENETDOWN:\n      errno = ENETDOWN;\n      break;\n    case WSAENETUNREACH:\n      errno = ENETUNREACH;\n      break;\n    case WSAENETRESET:\n      errno = ENETRESET;\n      break;\n    case WSAECONNABORTED:\n      errno = ECONNABORTED;\n      break;\n    case WSAECONNRESET:\n      errno = ECONNRESET;\n      break;\n    case WSAENOBUFS:\n      errno = ENOBUFS;\n      break;\n    case WSAEISCONN:\n      errno = EISCONN;\n      break;\n    case WSAENOTCONN:\n      errno = ENOTCONN;\n      break;\n    case WSAETIMEDOUT:\n      errno = ETIMEDOUT;\n      break;\n    case WSAECONNREFUSED:\n      errno = ECONNREFUSED;\n      break;\n    case WSAELOOP:\n      errno = ELOOP;\n      break;\n    case WSAEHOSTUNREACH:\n      errno = EHOSTUNREACH;\n      break;\n    default:\n      errno = (err > 10000 && err < 10025) ? err - 10000 : err;\n      break;\n    }\n}\n"
  },
  {
    "path": "windows_compat/gnulib/gllib/warn-on-use.h",
    "content": "/* A C macro for emitting warnings if a function is used.\n   Copyright (C) 2010-2021 Free Software Foundation, Inc.\n\n   This program is free software: you can redistribute it and/or modify it\n   under the terms of the GNU Lesser General Public License as published\n   by the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public License\n   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */\n\n/* _GL_WARN_ON_USE (function, \"literal string\") issues a declaration\n   for FUNCTION which will then trigger a compiler warning containing\n   the text of \"literal string\" anywhere that function is called, if\n   supported by the compiler.  If the compiler does not support this\n   feature, the macro expands to an unused extern declaration.\n\n   _GL_WARN_ON_USE_ATTRIBUTE (\"literal string\") expands to the\n   attribute used in _GL_WARN_ON_USE.  If the compiler does not support\n   this feature, it expands to empty.\n\n   These macros are useful for marking a function as a potential\n   portability trap, with the intent that \"literal string\" include\n   instructions on the replacement function that should be used\n   instead.\n   _GL_WARN_ON_USE is for functions with 'extern' linkage.\n   _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'\n   linkage.\n\n   However, one of the reasons that a function is a portability trap is\n   if it has the wrong signature.  Declaring FUNCTION with a different\n   signature in C is a compilation error, so this macro must use the\n   same type as any existing declaration so that programs that avoid\n   the problematic FUNCTION do not fail to compile merely because they\n   included a header that poisoned the function.  But this implies that\n   _GL_WARN_ON_USE is only safe to use if FUNCTION is known to already\n   have a declaration.  Use of this macro implies that there must not\n   be any other macro hiding the declaration of FUNCTION; but\n   undefining FUNCTION first is part of the poisoning process anyway\n   (although for symbols that are provided only via a macro, the result\n   is a compilation error rather than a warning containing\n   \"literal string\").  Also note that in C++, it is only safe to use if\n   FUNCTION has no overloads.\n\n   For an example, it is possible to poison 'getline' by:\n   - adding a call to gl_WARN_ON_USE_PREPARE([[#include <stdio.h>]],\n     [getline]) in configure.ac, which potentially defines\n     HAVE_RAW_DECL_GETLINE\n   - adding this code to a header that wraps the system <stdio.h>:\n     #undef getline\n     #if HAVE_RAW_DECL_GETLINE\n     _GL_WARN_ON_USE (getline, \"getline is required by POSIX 2008, but\"\n       \"not universally present; use the gnulib module getline\");\n     #endif\n\n   It is not possible to directly poison global variables.  But it is\n   possible to write a wrapper accessor function, and poison that\n   (less common usage, like &environ, will cause a compilation error\n   rather than issue the nice warning, but the end result of informing\n   the developer about their portability problem is still achieved):\n     #if HAVE_RAW_DECL_ENVIRON\n     static char ***\n     rpl_environ (void) { return &environ; }\n     _GL_WARN_ON_USE (rpl_environ, \"environ is not always properly declared\");\n     # undef environ\n     # define environ (*rpl_environ ())\n     #endif\n   or better (avoiding contradictory use of 'static' and 'extern'):\n     #if HAVE_RAW_DECL_ENVIRON\n     static char ***\n     _GL_WARN_ON_USE_ATTRIBUTE (\"environ is not always properly declared\")\n     rpl_environ (void) { return &environ; }\n     # undef environ\n     # define environ (*rpl_environ ())\n     #endif\n   */\n#ifndef _GL_WARN_ON_USE\n\n# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)\n/* A compiler attribute is available in gcc versions 4.3.0 and later.  */\n#  define _GL_WARN_ON_USE(function, message) \\\nextern __typeof__ (function) function __attribute__ ((__warning__ (message)))\n#  define _GL_WARN_ON_USE_ATTRIBUTE(message) \\\n  __attribute__ ((__warning__ (message)))\n# elif __clang_major__ >= 4\n/* Another compiler attribute is available in clang.  */\n#  define _GL_WARN_ON_USE(function, message) \\\nextern __typeof__ (function) function \\\n  __attribute__ ((__diagnose_if__ (1, message, \"warning\")))\n#  define _GL_WARN_ON_USE_ATTRIBUTE(message) \\\n  __attribute__ ((__diagnose_if__ (1, message, \"warning\")))\n# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING\n/* Verify the existence of the function.  */\n#  define _GL_WARN_ON_USE(function, message) \\\nextern __typeof__ (function) function\n#  define _GL_WARN_ON_USE_ATTRIBUTE(message)\n# else /* Unsupported.  */\n#  define _GL_WARN_ON_USE(function, message) \\\n_GL_WARN_EXTERN_C int _gl_warn_on_use\n#  define _GL_WARN_ON_USE_ATTRIBUTE(message)\n# endif\n#endif\n\n/* _GL_WARN_ON_USE_CXX (function, rettype_gcc, rettype_clang, parameters_and_attributes, \"message\")\n   is like _GL_WARN_ON_USE (function, \"message\"), except that in C++ mode the\n   function is declared with the given prototype, consisting of return type,\n   parameters, and attributes.\n   This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does\n   not work in this case.  */\n#ifndef _GL_WARN_ON_USE_CXX\n# if !defined __cplusplus\n#  define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \\\n     _GL_WARN_ON_USE (function, msg)\n# else\n#  if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)\n/* A compiler attribute is available in gcc versions 4.3.0 and later.  */\n#   define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \\\nextern rettype_gcc function parameters_and_attributes \\\n  __attribute__ ((__warning__ (msg)))\n#  elif __clang_major__ >= 4\n/* Another compiler attribute is available in clang.  */\n#   define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \\\nextern rettype_clang function parameters_and_attributes \\\n  __attribute__ ((__diagnose_if__ (1, msg, \"warning\")))\n#  elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING\n/* Verify the existence of the function.  */\n#   define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \\\nextern rettype_gcc function parameters_and_attributes\n#  else /* Unsupported.  */\n#   define _GL_WARN_ON_USE_CXX(function,rettype_gcc,rettype_clang,parameters_and_attributes,msg) \\\n_GL_WARN_EXTERN_C int _gl_warn_on_use\n#  endif\n# endif\n#endif\n\n/* _GL_WARN_EXTERN_C declaration;\n   performs the declaration with C linkage.  */\n#ifndef _GL_WARN_EXTERN_C\n# if defined __cplusplus\n#  define _GL_WARN_EXTERN_C extern \"C\"\n# else\n#  define _GL_WARN_EXTERN_C extern\n# endif\n#endif\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/00gnulib.m4",
    "content": "# 00gnulib.m4 serial 8\ndnl Copyright (C) 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl This file must be named something that sorts before all other\ndnl gnulib-provided .m4 files.  It is needed until the clang fix has\ndnl been included in Autoconf.\n\n# The following definitions arrange to use a compiler option\n# -Werror=implicit-function-declaration in AC_CHECK_DECL, when the\n# compiler is clang.  Without it, clang implicitly declares \"known\"\n# library functions in C mode, but not in C++ mode, which would cause\n# Gnulib to omit a declaration and thus later produce an error in C++\n# mode.  As of clang 9.0, these \"known\" functions are identified through\n# LIBBUILTIN invocations in the LLVM source file\n# llvm/tools/clang/include/clang/Basic/Builtins.def.\n# It's not possible to AC_REQUIRE the extra tests from AC_CHECK_DECL,\n# because AC_CHECK_DECL, like other Autoconf built-ins, is not supposed\n# to AC_REQUIRE anything: some configure.ac files have their first\n# AC_CHECK_DECL executed conditionally.  Therefore append the extra tests\n# to AC_PROG_CC.\nAC_DEFUN([gl_COMPILER_CLANG],\n[\ndnl AC_REQUIRE([AC_PROG_CC])\n  AC_CACHE_CHECK([whether the compiler is clang],\n    [gl_cv_compiler_clang],\n    [dnl Use _AC_COMPILE_IFELSE instead of AC_EGREP_CPP, to avoid error\n     dnl \"circular dependency of AC_LANG_COMPILER(C)\" if AC_PROG_CC has\n     dnl not yet been invoked.\n     _AC_COMPILE_IFELSE(\n        [AC_LANG_PROGRAM([[\n           #ifdef __clang__\n           barfbarf\n           #endif\n           ]],[[]])\n        ],\n        [gl_cv_compiler_clang=no],\n        [gl_cv_compiler_clang=yes])\n    ])\n])\nAC_DEFUN([gl_COMPILER_PREPARE_CHECK_DECL],\n[\ndnl AC_REQUIRE([AC_PROG_CC])\ndnl AC_REQUIRE([gl_COMPILER_CLANG])\n  AC_CACHE_CHECK([for compiler option needed when checking for declarations],\n    [gl_cv_compiler_check_decl_option],\n    [if test $gl_cv_compiler_clang = yes; then\n       dnl Test whether the compiler supports the option\n       dnl '-Werror=implicit-function-declaration'.\n       save_ac_compile=\"$ac_compile\"\n       ac_compile=\"$ac_compile -Werror=implicit-function-declaration\"\n       dnl Use _AC_COMPILE_IFELSE instead of AC_COMPILE_IFELSE, to avoid a\n       dnl warning \"AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS\".\n       _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])],\n         [gl_cv_compiler_check_decl_option='-Werror=implicit-function-declaration'],\n         [gl_cv_compiler_check_decl_option=none])\n       ac_compile=\"$save_ac_compile\"\n     else\n       gl_cv_compiler_check_decl_option=none\n     fi\n    ])\n  if test \"x$gl_cv_compiler_check_decl_option\" != xnone; then\n    ac_compile_for_check_decl=\"$ac_compile $gl_cv_compiler_check_decl_option\"\n  else\n    ac_compile_for_check_decl=\"$ac_compile\"\n  fi\n])\ndnl Redefine _AC_CHECK_DECL_BODY so that it references ac_compile_for_check_decl\ndnl instead of ac_compile.  If, for whatever reason, the override of AC_PROG_CC\ndnl in zzgnulib.m4 is inactive, use the original ac_compile.\nm4_define([_AC_CHECK_DECL_BODY],\n[  ac_save_ac_compile=\"$ac_compile\"\n  if test -n \"$ac_compile_for_check_decl\"; then\n    ac_compile=\"$ac_compile_for_check_decl\"\n  fi]\nm4_defn([_AC_CHECK_DECL_BODY])[  ac_compile=\"$ac_save_ac_compile\"\n])\n\n# gl_00GNULIB\n# -----------\n# Witness macro that this file has been included.  Needed to force\n# Automake to include this file prior to all other gnulib .m4 files.\nAC_DEFUN([gl_00GNULIB])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in.\n\nEXTRA_DIST =\nEXTRA_DIST += 00gnulib.m4\nEXTRA_DIST += __inline.m4\nEXTRA_DIST += absolute-header.m4\nEXTRA_DIST += errno_h.m4\nEXTRA_DIST += execinfo.m4\nEXTRA_DIST += extensions.m4\nEXTRA_DIST += extern-inline.m4\nEXTRA_DIST += getdelim.m4\nEXTRA_DIST += gethostname.m4\nEXTRA_DIST += getline.m4\nEXTRA_DIST += gettimeofday.m4\nEXTRA_DIST += gnulib-common.m4\nEXTRA_DIST += include_next.m4\nEXTRA_DIST += limits-h.m4\nEXTRA_DIST += msvc-inval.m4\nEXTRA_DIST += msvc-nothrow.m4\nEXTRA_DIST += multiarch.m4\nEXTRA_DIST += off_t.m4\nEXTRA_DIST += pid_t.m4\nEXTRA_DIST += random.m4\nEXTRA_DIST += random_r.m4\nEXTRA_DIST += socketlib.m4\nEXTRA_DIST += sockets.m4\nEXTRA_DIST += socklen.m4\nEXTRA_DIST += sockpfaf.m4\nEXTRA_DIST += ssize_t.m4\nEXTRA_DIST += std-gnu11.m4\nEXTRA_DIST += stdalign.m4\nEXTRA_DIST += stddef_h.m4\nEXTRA_DIST += stdint.m4\nEXTRA_DIST += stdio_h.m4\nEXTRA_DIST += stdlib_h.m4\nEXTRA_DIST += sys_resource_h.m4\nEXTRA_DIST += sys_socket_h.m4\nEXTRA_DIST += sys_stat_h.m4\nEXTRA_DIST += sys_time_h.m4\nEXTRA_DIST += sys_types_h.m4\nEXTRA_DIST += sys_uio_h.m4\nEXTRA_DIST += sys_utsname_h.m4\nEXTRA_DIST += time_h.m4\nEXTRA_DIST += time_r.m4\nEXTRA_DIST += uname.m4\nEXTRA_DIST += unistd_h.m4\nEXTRA_DIST += warn-on-use.m4\nEXTRA_DIST += wchar_t.m4\nEXTRA_DIST += wint_t.m4\nEXTRA_DIST += zzgnulib.m4\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/Makefile.in",
    "content": "# Makefile.in generated by automake 1.16.3 from Makefile.am.\n# @configure_input@\n\n# Copyright (C) 1994-2020 Free Software Foundation, Inc.\n\n# This Makefile.in is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY, to the extent permitted by law; without\n# even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n# PARTICULAR PURPOSE.\n\n@SET_MAKE@\nVPATH = @srcdir@\nam__is_gnu_make = { \\\n  if test -z '$(MAKELEVEL)'; then \\\n    false; \\\n  elif test -n '$(MAKE_HOST)'; then \\\n    true; \\\n  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \\\n    true; \\\n  else \\\n    false; \\\n  fi; \\\n}\nam__make_running_with_option = \\\n  case $${target_option-} in \\\n      ?) ;; \\\n      *) echo \"am__make_running_with_option: internal error: invalid\" \\\n              \"target option '$${target_option-}' specified\" >&2; \\\n         exit 1;; \\\n  esac; \\\n  has_opt=no; \\\n  sane_makeflags=$$MAKEFLAGS; \\\n  if $(am__is_gnu_make); then \\\n    sane_makeflags=$$MFLAGS; \\\n  else \\\n    case $$MAKEFLAGS in \\\n      *\\\\[\\ \\\t]*) \\\n        bs=\\\\; \\\n        sane_makeflags=`printf '%s\\n' \"$$MAKEFLAGS\" \\\n          | sed \"s/$$bs$$bs[$$bs $$bs\t]*//g\"`;; \\\n    esac; \\\n  fi; \\\n  skip_next=no; \\\n  strip_trailopt () \\\n  { \\\n    flg=`printf '%s\\n' \"$$flg\" | sed \"s/$$1.*$$//\"`; \\\n  }; \\\n  for flg in $$sane_makeflags; do \\\n    test $$skip_next = yes && { skip_next=no; continue; }; \\\n    case $$flg in \\\n      *=*|--*) continue;; \\\n        -*I) strip_trailopt 'I'; skip_next=yes;; \\\n      -*I?*) strip_trailopt 'I';; \\\n        -*O) strip_trailopt 'O'; skip_next=yes;; \\\n      -*O?*) strip_trailopt 'O';; \\\n        -*l) strip_trailopt 'l'; skip_next=yes;; \\\n      -*l?*) strip_trailopt 'l';; \\\n      -[dEDm]) skip_next=yes;; \\\n      -[JT]) skip_next=yes;; \\\n    esac; \\\n    case $$flg in \\\n      *$$target_option*) has_opt=yes; break;; \\\n    esac; \\\n  done; \\\n  test $$has_opt = yes\nam__make_dryrun = (target_option=n; $(am__make_running_with_option))\nam__make_keepgoing = (target_option=k; $(am__make_running_with_option))\npkgdatadir = $(datadir)/@PACKAGE@\npkgincludedir = $(includedir)/@PACKAGE@\npkglibdir = $(libdir)/@PACKAGE@\npkglibexecdir = $(libexecdir)/@PACKAGE@\nam__cd = CDPATH=\"$${ZSH_VERSION+.}$(PATH_SEPARATOR)\" && cd\ninstall_sh_DATA = $(install_sh) -c -m 644\ninstall_sh_PROGRAM = $(install_sh) -c\ninstall_sh_SCRIPT = $(install_sh) -c\nINSTALL_HEADER = $(INSTALL_DATA)\ntransform = $(program_transform_name)\nNORMAL_INSTALL = :\nPRE_INSTALL = :\nPOST_INSTALL = :\nNORMAL_UNINSTALL = :\nPRE_UNINSTALL = :\nPOST_UNINSTALL = :\nbuild_triplet = @build@\nhost_triplet = @host@\nsubdir = glm4\nACLOCAL_M4 = $(top_srcdir)/aclocal.m4\nam__aclocal_m4_deps = $(top_srcdir)/glm4/00gnulib.m4 \\\n\t$(top_srcdir)/glm4/__inline.m4 \\\n\t$(top_srcdir)/glm4/absolute-header.m4 \\\n\t$(top_srcdir)/glm4/errno_h.m4 $(top_srcdir)/glm4/execinfo.m4 \\\n\t$(top_srcdir)/glm4/extensions.m4 \\\n\t$(top_srcdir)/glm4/extern-inline.m4 \\\n\t$(top_srcdir)/glm4/getdelim.m4 \\\n\t$(top_srcdir)/glm4/gethostname.m4 \\\n\t$(top_srcdir)/glm4/getline.m4 \\\n\t$(top_srcdir)/glm4/gettimeofday.m4 \\\n\t$(top_srcdir)/glm4/gnulib-common.m4 \\\n\t$(top_srcdir)/glm4/include_next.m4 \\\n\t$(top_srcdir)/glm4/limits-h.m4 \\\n\t$(top_srcdir)/glm4/msvc-inval.m4 \\\n\t$(top_srcdir)/glm4/msvc-nothrow.m4 \\\n\t$(top_srcdir)/glm4/multiarch.m4 $(top_srcdir)/glm4/off_t.m4 \\\n\t$(top_srcdir)/glm4/random.m4 $(top_srcdir)/glm4/random_r.m4 \\\n\t$(top_srcdir)/glm4/socketlib.m4 $(top_srcdir)/glm4/sockets.m4 \\\n\t$(top_srcdir)/glm4/socklen.m4 $(top_srcdir)/glm4/ssize_t.m4 \\\n\t$(top_srcdir)/glm4/stdalign.m4 $(top_srcdir)/glm4/stddef_h.m4 \\\n\t$(top_srcdir)/glm4/stdint.m4 $(top_srcdir)/glm4/stdio_h.m4 \\\n\t$(top_srcdir)/glm4/stdlib_h.m4 \\\n\t$(top_srcdir)/glm4/sys_resource_h.m4 \\\n\t$(top_srcdir)/glm4/sys_socket_h.m4 \\\n\t$(top_srcdir)/glm4/sys_stat_h.m4 \\\n\t$(top_srcdir)/glm4/sys_time_h.m4 \\\n\t$(top_srcdir)/glm4/sys_types_h.m4 \\\n\t$(top_srcdir)/glm4/sys_uio_h.m4 \\\n\t$(top_srcdir)/glm4/sys_utsname_h.m4 \\\n\t$(top_srcdir)/glm4/time_h.m4 $(top_srcdir)/glm4/time_r.m4 \\\n\t$(top_srcdir)/glm4/uname.m4 $(top_srcdir)/glm4/unistd_h.m4 \\\n\t$(top_srcdir)/glm4/warn-on-use.m4 \\\n\t$(top_srcdir)/glm4/wchar_t.m4 $(top_srcdir)/glm4/wint_t.m4 \\\n\t$(top_srcdir)/glm4/zzgnulib.m4 $(top_srcdir)/configure.ac\nam__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \\\n\t$(ACLOCAL_M4)\nDIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)\nmkinstalldirs = $(install_sh) -d\nCONFIG_HEADER = $(top_builddir)/config.h\nCONFIG_CLEAN_FILES =\nCONFIG_CLEAN_VPATH_FILES =\nAM_V_P = $(am__v_P_@AM_V@)\nam__v_P_ = $(am__v_P_@AM_DEFAULT_V@)\nam__v_P_0 = false\nam__v_P_1 = :\nAM_V_GEN = $(am__v_GEN_@AM_V@)\nam__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)\nam__v_GEN_0 = @echo \"  GEN     \" $@;\nam__v_GEN_1 = \nAM_V_at = $(am__v_at_@AM_V@)\nam__v_at_ = $(am__v_at_@AM_DEFAULT_V@)\nam__v_at_0 = @\nam__v_at_1 = \nSOURCES =\nDIST_SOURCES =\nam__can_run_installinfo = \\\n  case $$AM_UPDATE_INFO_DIR in \\\n    n|no|NO) false;; \\\n    *) (install-info --version) >/dev/null 2>&1;; \\\n  esac\nam__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)\nam__DIST_COMMON = $(srcdir)/Makefile.in\nDISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)\nACLOCAL = @ACLOCAL@\nAMTAR = @AMTAR@\nAM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@\nAPPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@\nAR = @AR@\nARFLAGS = @ARFLAGS@\nAUTOCONF = @AUTOCONF@\nAUTOHEADER = @AUTOHEADER@\nAUTOMAKE = @AUTOMAKE@\nAWK = @AWK@\nBITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@\nBITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@\nBITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@\nBITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@\nBITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@\nCC = @CC@\nCCDEPMODE = @CCDEPMODE@\nCFLAGS = @CFLAGS@\nCPP = @CPP@\nCPPFLAGS = @CPPFLAGS@\nCYGPATH_W = @CYGPATH_W@\nDEFS = @DEFS@\nDEPDIR = @DEPDIR@\nECHO_C = @ECHO_C@\nECHO_N = @ECHO_N@\nECHO_T = @ECHO_T@\nEGREP = @EGREP@\nEMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@\nEMULTIHOP_VALUE = @EMULTIHOP_VALUE@\nENOLINK_HIDDEN = @ENOLINK_HIDDEN@\nENOLINK_VALUE = @ENOLINK_VALUE@\nEOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@\nEOVERFLOW_VALUE = @EOVERFLOW_VALUE@\nERRNO_H = @ERRNO_H@\nEXECINFO_H = @EXECINFO_H@\nEXEEXT = @EXEEXT@\nGETHOSTNAME_LIB = @GETHOSTNAME_LIB@\nGL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@\nGL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@\nGL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@\nGL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@\nGL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@\nGL_GNULIB_BIND = @GL_GNULIB_BIND@\nGL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@\nGL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@\nGL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@\nGL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@\nGL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@\nGL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@\nGL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@\nGL_GNULIB_CTIME = @GL_GNULIB_CTIME@\nGL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@\nGL_GNULIB_DUP = @GL_GNULIB_DUP@\nGL_GNULIB_DUP2 = @GL_GNULIB_DUP2@\nGL_GNULIB_DUP3 = @GL_GNULIB_DUP3@\nGL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@\nGL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@\nGL_GNULIB_EXECL = @GL_GNULIB_EXECL@\nGL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@\nGL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@\nGL_GNULIB_EXECV = @GL_GNULIB_EXECV@\nGL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@\nGL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@\nGL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@\nGL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@\nGL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@\nGL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@\nGL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@\nGL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@\nGL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@\nGL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@\nGL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@\nGL_GNULIB_FGETC = @GL_GNULIB_FGETC@\nGL_GNULIB_FGETS = @GL_GNULIB_FGETS@\nGL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@\nGL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@\nGL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@\nGL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@\nGL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@\nGL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@\nGL_GNULIB_FREAD = @GL_GNULIB_FREAD@\nGL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@\nGL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@\nGL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@\nGL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@\nGL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@\nGL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@\nGL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@\nGL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@\nGL_GNULIB_FTELL = @GL_GNULIB_FTELL@\nGL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@\nGL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@\nGL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@\nGL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@\nGL_GNULIB_GETC = @GL_GNULIB_GETC@\nGL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@\nGL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@\nGL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@\nGL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@\nGL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@\nGL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@\nGL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@\nGL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@\nGL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@\nGL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@\nGL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@\nGL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@\nGL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@\nGL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@\nGL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@\nGL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@\nGL_GNULIB_GETRUSAGE = @GL_GNULIB_GETRUSAGE@\nGL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@\nGL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@\nGL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@\nGL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@\nGL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@\nGL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@\nGL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@\nGL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@\nGL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@\nGL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@\nGL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@\nGL_GNULIB_LINK = @GL_GNULIB_LINK@\nGL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@\nGL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@\nGL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@\nGL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@\nGL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@\nGL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@\nGL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@\nGL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@\nGL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@\nGL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@\nGL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@\nGL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@\nGL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@\nGL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@\nGL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@\nGL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@\nGL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@\nGL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@\nGL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@\nGL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@\nGL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@\nGL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@\nGL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@\nGL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@\nGL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@\nGL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@\nGL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@\nGL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@\nGL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@\nGL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@\nGL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@\nGL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@\nGL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@\nGL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@\nGL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@\nGL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@\nGL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@\nGL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@\nGL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@\nGL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@\nGL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@\nGL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@\nGL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@\nGL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@\nGL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@\nGL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@\nGL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@\nGL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@\nGL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@\nGL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@\nGL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@\nGL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@\nGL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@\nGL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@\nGL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@\nGL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@\nGL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@\nGL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@\nGL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@\nGL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@\nGL_GNULIB_PERROR = @GL_GNULIB_PERROR@\nGL_GNULIB_PIPE = @GL_GNULIB_PIPE@\nGL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@\nGL_GNULIB_POPEN = @GL_GNULIB_POPEN@\nGL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@\nGL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@\nGL_GNULIB_PREAD = @GL_GNULIB_PREAD@\nGL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@\nGL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@\nGL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@\nGL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@\nGL_GNULIB_PUTC = @GL_GNULIB_PUTC@\nGL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@\nGL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@\nGL_GNULIB_PUTS = @GL_GNULIB_PUTS@\nGL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@\nGL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@\nGL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@\nGL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@\nGL_GNULIB_READ = @GL_GNULIB_READ@\nGL_GNULIB_READLINK = @GL_GNULIB_READLINK@\nGL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@\nGL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@\nGL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@\nGL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@\nGL_GNULIB_RECV = @GL_GNULIB_RECV@\nGL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@\nGL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@\nGL_GNULIB_RENAME = @GL_GNULIB_RENAME@\nGL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@\nGL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@\nGL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@\nGL_GNULIB_SCANF = @GL_GNULIB_SCANF@\nGL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@\nGL_GNULIB_SEND = @GL_GNULIB_SEND@\nGL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@\nGL_GNULIB_SETENV = @GL_GNULIB_SETENV@\nGL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@\nGL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@\nGL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@\nGL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@\nGL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@\nGL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@\nGL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@\nGL_GNULIB_STAT = @GL_GNULIB_STAT@\nGL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@\nGL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@\nGL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@\nGL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@\nGL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@\nGL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@\nGL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@\nGL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@\nGL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@\nGL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@\nGL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@\nGL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@\nGL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@\nGL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@\nGL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@\nGL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@\nGL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@\nGL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@\nGL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@\nGL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@\nGL_GNULIB_TZSET = @GL_GNULIB_TZSET@\nGL_GNULIB_UNAME = @GL_GNULIB_UNAME@\nGL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@\nGL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@\nGL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@\nGL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@\nGL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@\nGL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@\nGL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@\nGL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@\nGL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@\nGL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@\nGL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@\nGL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@\nGL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@\nGL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@\nGL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@\nGL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@\nGL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@\nGL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@\nGL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@\nGL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@\nGL_GNULIB_WRITE = @GL_GNULIB_WRITE@\nGL_GNULIB__EXIT = @GL_GNULIB__EXIT@\nGNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@\nGNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@\nGREP = @GREP@\nHAVE_ACCEPT4 = @HAVE_ACCEPT4@\nHAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@\nHAVE_ATOLL = @HAVE_ATOLL@\nHAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@\nHAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@\nHAVE_CHOWN = @HAVE_CHOWN@\nHAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@\nHAVE_DECL_ECVT = @HAVE_DECL_ECVT@\nHAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@\nHAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@\nHAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@\nHAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@\nHAVE_DECL_FCVT = @HAVE_DECL_FCVT@\nHAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@\nHAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@\nHAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@\nHAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@\nHAVE_DECL_GCVT = @HAVE_DECL_GCVT@\nHAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@\nHAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@\nHAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@\nHAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@\nHAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@\nHAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@\nHAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@\nHAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@\nHAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@\nHAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@\nHAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@\nHAVE_DECL_SETENV = @HAVE_DECL_SETENV@\nHAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@\nHAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@\nHAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@\nHAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@\nHAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@\nHAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@\nHAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@\nHAVE_DPRINTF = @HAVE_DPRINTF@\nHAVE_DUP3 = @HAVE_DUP3@\nHAVE_EUIDACCESS = @HAVE_EUIDACCESS@\nHAVE_EXECVPE = @HAVE_EXECVPE@\nHAVE_FACCESSAT = @HAVE_FACCESSAT@\nHAVE_FCHDIR = @HAVE_FCHDIR@\nHAVE_FCHMODAT = @HAVE_FCHMODAT@\nHAVE_FCHOWNAT = @HAVE_FCHOWNAT@\nHAVE_FDATASYNC = @HAVE_FDATASYNC@\nHAVE_FSEEKO = @HAVE_FSEEKO@\nHAVE_FSTATAT = @HAVE_FSTATAT@\nHAVE_FSYNC = @HAVE_FSYNC@\nHAVE_FTELLO = @HAVE_FTELLO@\nHAVE_FTRUNCATE = @HAVE_FTRUNCATE@\nHAVE_FUTIMENS = @HAVE_FUTIMENS@\nHAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@\nHAVE_GETENTROPY = @HAVE_GETENTROPY@\nHAVE_GETGROUPS = @HAVE_GETGROUPS@\nHAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@\nHAVE_GETLOGIN = @HAVE_GETLOGIN@\nHAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@\nHAVE_GETPASS = @HAVE_GETPASS@\nHAVE_GETRUSAGE = @HAVE_GETRUSAGE@\nHAVE_GETSUBOPT = @HAVE_GETSUBOPT@\nHAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@\nHAVE_GETUMASK = @HAVE_GETUMASK@\nHAVE_GRANTPT = @HAVE_GRANTPT@\nHAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@\nHAVE_INITSTATE = @HAVE_INITSTATE@\nHAVE_INTTYPES_H = @HAVE_INTTYPES_H@\nHAVE_LCHMOD = @HAVE_LCHMOD@\nHAVE_LCHOWN = @HAVE_LCHOWN@\nHAVE_LINK = @HAVE_LINK@\nHAVE_LINKAT = @HAVE_LINKAT@\nHAVE_LSTAT = @HAVE_LSTAT@\nHAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@\nHAVE_MBTOWC = @HAVE_MBTOWC@\nHAVE_MKDIRAT = @HAVE_MKDIRAT@\nHAVE_MKDTEMP = @HAVE_MKDTEMP@\nHAVE_MKFIFO = @HAVE_MKFIFO@\nHAVE_MKFIFOAT = @HAVE_MKFIFOAT@\nHAVE_MKNOD = @HAVE_MKNOD@\nHAVE_MKNODAT = @HAVE_MKNODAT@\nHAVE_MKOSTEMP = @HAVE_MKOSTEMP@\nHAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@\nHAVE_MKSTEMP = @HAVE_MKSTEMP@\nHAVE_MKSTEMPS = @HAVE_MKSTEMPS@\nHAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@\nHAVE_NANOSLEEP = @HAVE_NANOSLEEP@\nHAVE_OS_H = @HAVE_OS_H@\nHAVE_PCLOSE = @HAVE_PCLOSE@\nHAVE_PIPE = @HAVE_PIPE@\nHAVE_PIPE2 = @HAVE_PIPE2@\nHAVE_POPEN = @HAVE_POPEN@\nHAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@\nHAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@\nHAVE_PREAD = @HAVE_PREAD@\nHAVE_PTSNAME = @HAVE_PTSNAME@\nHAVE_PTSNAME_R = @HAVE_PTSNAME_R@\nHAVE_PWRITE = @HAVE_PWRITE@\nHAVE_QSORT_R = @HAVE_QSORT_R@\nHAVE_RANDOM = @HAVE_RANDOM@\nHAVE_RANDOM_H = @HAVE_RANDOM_H@\nHAVE_RANDOM_R = @HAVE_RANDOM_R@\nHAVE_READLINK = @HAVE_READLINK@\nHAVE_READLINKAT = @HAVE_READLINKAT@\nHAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@\nHAVE_REALPATH = @HAVE_REALPATH@\nHAVE_RENAMEAT = @HAVE_RENAMEAT@\nHAVE_RPMATCH = @HAVE_RPMATCH@\nHAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@\nHAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@\nHAVE_SETENV = @HAVE_SETENV@\nHAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@\nHAVE_SETSTATE = @HAVE_SETSTATE@\nHAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@\nHAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@\nHAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@\nHAVE_SLEEP = @HAVE_SLEEP@\nHAVE_STDINT_H = @HAVE_STDINT_H@\nHAVE_STRPTIME = @HAVE_STRPTIME@\nHAVE_STRTOD = @HAVE_STRTOD@\nHAVE_STRTOL = @HAVE_STRTOL@\nHAVE_STRTOLD = @HAVE_STRTOLD@\nHAVE_STRTOLL = @HAVE_STRTOLL@\nHAVE_STRTOUL = @HAVE_STRTOUL@\nHAVE_STRTOULL = @HAVE_STRTOULL@\nHAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@\nHAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@\nHAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@\nHAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@\nHAVE_STRUCT_UTSNAME = @HAVE_STRUCT_UTSNAME@\nHAVE_SYMLINK = @HAVE_SYMLINK@\nHAVE_SYMLINKAT = @HAVE_SYMLINKAT@\nHAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@\nHAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@\nHAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@\nHAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@\nHAVE_SYS_RESOURCE_H = @HAVE_SYS_RESOURCE_H@\nHAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@\nHAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@\nHAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@\nHAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@\nHAVE_SYS_UTSNAME_H = @HAVE_SYS_UTSNAME_H@\nHAVE_TIMEGM = @HAVE_TIMEGM@\nHAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@\nHAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@\nHAVE_UNAME = @HAVE_UNAME@\nHAVE_UNISTD_H = @HAVE_UNISTD_H@\nHAVE_UNLINKAT = @HAVE_UNLINKAT@\nHAVE_UNLOCKPT = @HAVE_UNLOCKPT@\nHAVE_USLEEP = @HAVE_USLEEP@\nHAVE_UTIMENSAT = @HAVE_UTIMENSAT@\nHAVE_VASPRINTF = @HAVE_VASPRINTF@\nHAVE_VDPRINTF = @HAVE_VDPRINTF@\nHAVE_WCHAR_H = @HAVE_WCHAR_H@\nHAVE_WCHAR_T = @HAVE_WCHAR_T@\nHAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@\nHAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@\nHAVE__EXIT = @HAVE__EXIT@\nINCLUDE_NEXT = @INCLUDE_NEXT@\nINCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@\nINSTALL = @INSTALL@\nINSTALL_DATA = @INSTALL_DATA@\nINSTALL_PROGRAM = @INSTALL_PROGRAM@\nINSTALL_SCRIPT = @INSTALL_SCRIPT@\nINSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@\nLDFLAGS = @LDFLAGS@\nLIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@\nLIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@\nLIBOBJS = @LIBOBJS@\nLIBS = @LIBS@\nLIBSOCKET = @LIBSOCKET@\nLIB_EXECINFO = @LIB_EXECINFO@\nLIMITS_H = @LIMITS_H@\nLTLIBOBJS = @LTLIBOBJS@\nMAKEINFO = @MAKEINFO@\nMKDIR_P = @MKDIR_P@\nNEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@\nNEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@\nNEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@\nNEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@\nNEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@\nNEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RESOURCE_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@\nNEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UTSNAME_H@\nNEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@\nNEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@\nNEXT_ERRNO_H = @NEXT_ERRNO_H@\nNEXT_LIMITS_H = @NEXT_LIMITS_H@\nNEXT_STDDEF_H = @NEXT_STDDEF_H@\nNEXT_STDINT_H = @NEXT_STDINT_H@\nNEXT_STDIO_H = @NEXT_STDIO_H@\nNEXT_STDLIB_H = @NEXT_STDLIB_H@\nNEXT_SYS_RESOURCE_H = @NEXT_SYS_RESOURCE_H@\nNEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@\nNEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@\nNEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@\nNEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@\nNEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@\nNEXT_SYS_UTSNAME_H = @NEXT_SYS_UTSNAME_H@\nNEXT_TIME_H = @NEXT_TIME_H@\nNEXT_UNISTD_H = @NEXT_UNISTD_H@\nOBJEXT = @OBJEXT@\nPACKAGE = @PACKAGE@\nPACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@\nPACKAGE_NAME = @PACKAGE_NAME@\nPACKAGE_STRING = @PACKAGE_STRING@\nPACKAGE_TARNAME = @PACKAGE_TARNAME@\nPACKAGE_URL = @PACKAGE_URL@\nPACKAGE_VERSION = @PACKAGE_VERSION@\nPATH_SEPARATOR = @PATH_SEPARATOR@\nPRAGMA_COLUMNS = @PRAGMA_COLUMNS@\nPRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@\nPTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@\nPTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@\nRANLIB = @RANLIB@\nREPLACE_ACCESS = @REPLACE_ACCESS@\nREPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@\nREPLACE_CALLOC = @REPLACE_CALLOC@\nREPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@\nREPLACE_CHOWN = @REPLACE_CHOWN@\nREPLACE_CLOSE = @REPLACE_CLOSE@\nREPLACE_CTIME = @REPLACE_CTIME@\nREPLACE_DPRINTF = @REPLACE_DPRINTF@\nREPLACE_DUP = @REPLACE_DUP@\nREPLACE_DUP2 = @REPLACE_DUP2@\nREPLACE_EXECL = @REPLACE_EXECL@\nREPLACE_EXECLE = @REPLACE_EXECLE@\nREPLACE_EXECLP = @REPLACE_EXECLP@\nREPLACE_EXECV = @REPLACE_EXECV@\nREPLACE_EXECVE = @REPLACE_EXECVE@\nREPLACE_EXECVP = @REPLACE_EXECVP@\nREPLACE_EXECVPE = @REPLACE_EXECVPE@\nREPLACE_FACCESSAT = @REPLACE_FACCESSAT@\nREPLACE_FCHMODAT = @REPLACE_FCHMODAT@\nREPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@\nREPLACE_FCLOSE = @REPLACE_FCLOSE@\nREPLACE_FDOPEN = @REPLACE_FDOPEN@\nREPLACE_FFLUSH = @REPLACE_FFLUSH@\nREPLACE_FOPEN = @REPLACE_FOPEN@\nREPLACE_FPRINTF = @REPLACE_FPRINTF@\nREPLACE_FPURGE = @REPLACE_FPURGE@\nREPLACE_FREE = @REPLACE_FREE@\nREPLACE_FREOPEN = @REPLACE_FREOPEN@\nREPLACE_FSEEK = @REPLACE_FSEEK@\nREPLACE_FSEEKO = @REPLACE_FSEEKO@\nREPLACE_FSTAT = @REPLACE_FSTAT@\nREPLACE_FSTATAT = @REPLACE_FSTATAT@\nREPLACE_FTELL = @REPLACE_FTELL@\nREPLACE_FTELLO = @REPLACE_FTELLO@\nREPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@\nREPLACE_FUTIMENS = @REPLACE_FUTIMENS@\nREPLACE_GETCWD = @REPLACE_GETCWD@\nREPLACE_GETDELIM = @REPLACE_GETDELIM@\nREPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@\nREPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@\nREPLACE_GETGROUPS = @REPLACE_GETGROUPS@\nREPLACE_GETLINE = @REPLACE_GETLINE@\nREPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@\nREPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@\nREPLACE_GETPASS = @REPLACE_GETPASS@\nREPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@\nREPLACE_GMTIME = @REPLACE_GMTIME@\nREPLACE_INITSTATE = @REPLACE_INITSTATE@\nREPLACE_ISATTY = @REPLACE_ISATTY@\nREPLACE_LCHOWN = @REPLACE_LCHOWN@\nREPLACE_LINK = @REPLACE_LINK@\nREPLACE_LINKAT = @REPLACE_LINKAT@\nREPLACE_LOCALTIME = @REPLACE_LOCALTIME@\nREPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@\nREPLACE_LSEEK = @REPLACE_LSEEK@\nREPLACE_LSTAT = @REPLACE_LSTAT@\nREPLACE_MALLOC = @REPLACE_MALLOC@\nREPLACE_MBTOWC = @REPLACE_MBTOWC@\nREPLACE_MKDIR = @REPLACE_MKDIR@\nREPLACE_MKFIFO = @REPLACE_MKFIFO@\nREPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@\nREPLACE_MKNOD = @REPLACE_MKNOD@\nREPLACE_MKNODAT = @REPLACE_MKNODAT@\nREPLACE_MKSTEMP = @REPLACE_MKSTEMP@\nREPLACE_MKTIME = @REPLACE_MKTIME@\nREPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@\nREPLACE_NULL = @REPLACE_NULL@\nREPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@\nREPLACE_PERROR = @REPLACE_PERROR@\nREPLACE_POPEN = @REPLACE_POPEN@\nREPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@\nREPLACE_PREAD = @REPLACE_PREAD@\nREPLACE_PRINTF = @REPLACE_PRINTF@\nREPLACE_PTSNAME = @REPLACE_PTSNAME@\nREPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@\nREPLACE_PUTENV = @REPLACE_PUTENV@\nREPLACE_PWRITE = @REPLACE_PWRITE@\nREPLACE_QSORT_R = @REPLACE_QSORT_R@\nREPLACE_RANDOM = @REPLACE_RANDOM@\nREPLACE_RANDOM_R = @REPLACE_RANDOM_R@\nREPLACE_READ = @REPLACE_READ@\nREPLACE_READLINK = @REPLACE_READLINK@\nREPLACE_READLINKAT = @REPLACE_READLINKAT@\nREPLACE_REALLOC = @REPLACE_REALLOC@\nREPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@\nREPLACE_REALPATH = @REPLACE_REALPATH@\nREPLACE_REMOVE = @REPLACE_REMOVE@\nREPLACE_RENAME = @REPLACE_RENAME@\nREPLACE_RENAMEAT = @REPLACE_RENAMEAT@\nREPLACE_RMDIR = @REPLACE_RMDIR@\nREPLACE_SETENV = @REPLACE_SETENV@\nREPLACE_SETSTATE = @REPLACE_SETSTATE@\nREPLACE_SLEEP = @REPLACE_SLEEP@\nREPLACE_SNPRINTF = @REPLACE_SNPRINTF@\nREPLACE_SPRINTF = @REPLACE_SPRINTF@\nREPLACE_STAT = @REPLACE_STAT@\nREPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@\nREPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@\nREPLACE_STRFTIME = @REPLACE_STRFTIME@\nREPLACE_STRTOD = @REPLACE_STRTOD@\nREPLACE_STRTOL = @REPLACE_STRTOL@\nREPLACE_STRTOLD = @REPLACE_STRTOLD@\nREPLACE_STRTOLL = @REPLACE_STRTOLL@\nREPLACE_STRTOUL = @REPLACE_STRTOUL@\nREPLACE_STRTOULL = @REPLACE_STRTOULL@\nREPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@\nREPLACE_SYMLINK = @REPLACE_SYMLINK@\nREPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@\nREPLACE_TIMEGM = @REPLACE_TIMEGM@\nREPLACE_TMPFILE = @REPLACE_TMPFILE@\nREPLACE_TRUNCATE = @REPLACE_TRUNCATE@\nREPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@\nREPLACE_TZSET = @REPLACE_TZSET@\nREPLACE_UNLINK = @REPLACE_UNLINK@\nREPLACE_UNLINKAT = @REPLACE_UNLINKAT@\nREPLACE_UNSETENV = @REPLACE_UNSETENV@\nREPLACE_USLEEP = @REPLACE_USLEEP@\nREPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@\nREPLACE_VASPRINTF = @REPLACE_VASPRINTF@\nREPLACE_VDPRINTF = @REPLACE_VDPRINTF@\nREPLACE_VFPRINTF = @REPLACE_VFPRINTF@\nREPLACE_VPRINTF = @REPLACE_VPRINTF@\nREPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@\nREPLACE_VSPRINTF = @REPLACE_VSPRINTF@\nREPLACE_WCTOMB = @REPLACE_WCTOMB@\nREPLACE_WRITE = @REPLACE_WRITE@\nSET_MAKE = @SET_MAKE@\nSHELL = @SHELL@\nSIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@\nSIZE_T_SUFFIX = @SIZE_T_SUFFIX@\nSTDALIGN_H = @STDALIGN_H@\nSTDDEF_H = @STDDEF_H@\nSTDINT_H = @STDINT_H@\nSTRIP = @STRIP@\nSYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@\nTIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@\nUNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@\nUNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@\nUNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@\nUNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@\nVERSION = @VERSION@\nWCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@\nWINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@\nWINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@\nWINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@\nWINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@\nWINT_T_SUFFIX = @WINT_T_SUFFIX@\nabs_builddir = @abs_builddir@\nabs_srcdir = @abs_srcdir@\nabs_top_builddir = @abs_top_builddir@\nabs_top_srcdir = @abs_top_srcdir@\nac_ct_CC = @ac_ct_CC@\nam__include = @am__include@\nam__leading_dot = @am__leading_dot@\nam__quote = @am__quote@\nam__tar = @am__tar@\nam__untar = @am__untar@\nbindir = @bindir@\nbuild = @build@\nbuild_alias = @build_alias@\nbuild_cpu = @build_cpu@\nbuild_os = @build_os@\nbuild_vendor = @build_vendor@\nbuilddir = @builddir@\ndatadir = @datadir@\ndatarootdir = @datarootdir@\ndocdir = @docdir@\ndvidir = @dvidir@\nexec_prefix = @exec_prefix@\ngl_LIBOBJS = @gl_LIBOBJS@\ngl_LTLIBOBJS = @gl_LTLIBOBJS@\nhost = @host@\nhost_alias = @host_alias@\nhost_cpu = @host_cpu@\nhost_os = @host_os@\nhost_vendor = @host_vendor@\nhtmldir = @htmldir@\nincludedir = @includedir@\ninfodir = @infodir@\ninstall_sh = @install_sh@\nlibdir = @libdir@\nlibexecdir = @libexecdir@\nlocaledir = @localedir@\nlocalstatedir = @localstatedir@\nmandir = @mandir@\nmkdir_p = @mkdir_p@\noldincludedir = @oldincludedir@\npdfdir = @pdfdir@\nprefix = @prefix@\nprogram_transform_name = @program_transform_name@\npsdir = @psdir@\nrunstatedir = @runstatedir@\nsbindir = @sbindir@\nsharedstatedir = @sharedstatedir@\nsrcdir = @srcdir@\nsysconfdir = @sysconfdir@\ntarget_alias = @target_alias@\ntop_build_prefix = @top_build_prefix@\ntop_builddir = @top_builddir@\ntop_srcdir = @top_srcdir@\nEXTRA_DIST = 00gnulib.m4 __inline.m4 absolute-header.m4 errno_h.m4 \\\n\texecinfo.m4 extensions.m4 extern-inline.m4 getdelim.m4 \\\n\tgethostname.m4 getline.m4 gettimeofday.m4 gnulib-common.m4 \\\n\tinclude_next.m4 limits-h.m4 msvc-inval.m4 msvc-nothrow.m4 \\\n\tmultiarch.m4 off_t.m4 pid_t.m4 random.m4 random_r.m4 \\\n\tsocketlib.m4 sockets.m4 socklen.m4 sockpfaf.m4 ssize_t.m4 \\\n\tstd-gnu11.m4 stdalign.m4 stddef_h.m4 stdint.m4 stdio_h.m4 \\\n\tstdlib_h.m4 sys_resource_h.m4 sys_socket_h.m4 sys_stat_h.m4 \\\n\tsys_time_h.m4 sys_types_h.m4 sys_uio_h.m4 sys_utsname_h.m4 \\\n\ttime_h.m4 time_r.m4 uname.m4 unistd_h.m4 warn-on-use.m4 \\\n\twchar_t.m4 wint_t.m4 zzgnulib.m4\nall: all-am\n\n.SUFFIXES:\n$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)\n\t@for dep in $?; do \\\n\t  case '$(am__configure_deps)' in \\\n\t    *$$dep*) \\\n\t      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \\\n\t        && { if test -f $@; then exit 0; else break; fi; }; \\\n\t      exit 1;; \\\n\t  esac; \\\n\tdone; \\\n\techo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu glm4/Makefile'; \\\n\t$(am__cd) $(top_srcdir) && \\\n\t  $(AUTOMAKE) --gnu glm4/Makefile\nMakefile: $(srcdir)/Makefile.in $(top_builddir)/config.status\n\t@case '$?' in \\\n\t  *config.status*) \\\n\t    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \\\n\t  *) \\\n\t    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \\\n\t    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \\\n\tesac;\n\n$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n\n$(top_srcdir)/configure:  $(am__configure_deps)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n$(ACLOCAL_M4):  $(am__aclocal_m4_deps)\n\tcd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh\n$(am__aclocal_m4_deps):\ntags TAGS:\n\nctags CTAGS:\n\ncscope cscopelist:\n\n\ndistdir: $(BUILT_SOURCES)\n\t$(MAKE) $(AM_MAKEFLAGS) distdir-am\n\ndistdir-am: $(DISTFILES)\n\t@srcdirstrip=`echo \"$(srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\ttopsrcdirstrip=`echo \"$(top_srcdir)\" | sed 's/[].[^$$\\\\*]/\\\\\\\\&/g'`; \\\n\tlist='$(DISTFILES)'; \\\n\t  dist_files=`for file in $$list; do echo $$file; done | \\\n\t  sed -e \"s|^$$srcdirstrip/||;t\" \\\n\t      -e \"s|^$$topsrcdirstrip/|$(top_builddir)/|;t\"`; \\\n\tcase $$dist_files in \\\n\t  */*) $(MKDIR_P) `echo \"$$dist_files\" | \\\n\t\t\t   sed '/\\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \\\n\t\t\t   sort -u` ;; \\\n\tesac; \\\n\tfor file in $$dist_files; do \\\n\t  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \\\n\t  if test -d $$d/$$file; then \\\n\t    dir=`echo \"/$$file\" | sed -e 's,/[^/]*$$,,'`; \\\n\t    if test -d \"$(distdir)/$$file\"; then \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \\\n\t      cp -fpR $(srcdir)/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t      find \"$(distdir)/$$file\" -type d ! -perm -700 -exec chmod u+rwx {} \\;; \\\n\t    fi; \\\n\t    cp -fpR $$d/$$file \"$(distdir)$$dir\" || exit 1; \\\n\t  else \\\n\t    test -f \"$(distdir)/$$file\" \\\n\t    || cp -p $$d/$$file \"$(distdir)/$$file\" \\\n\t    || exit 1; \\\n\t  fi; \\\n\tdone\ncheck-am: all-am\ncheck: check-am\nall-am: Makefile\ninstalldirs:\ninstall: install-am\ninstall-exec: install-exec-am\ninstall-data: install-data-am\nuninstall: uninstall-am\n\ninstall-am: all-am\n\t@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am\n\ninstallcheck: installcheck-am\ninstall-strip:\n\tif test -z '$(STRIP)'; then \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t      install; \\\n\telse \\\n\t  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" \\\n\t    install_sh_PROGRAM=\"$(INSTALL_STRIP_PROGRAM)\" INSTALL_STRIP_FLAG=-s \\\n\t    \"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'\" install; \\\n\tfi\nmostlyclean-generic:\n\nclean-generic:\n\ndistclean-generic:\n\t-test -z \"$(CONFIG_CLEAN_FILES)\" || rm -f $(CONFIG_CLEAN_FILES)\n\t-test . = \"$(srcdir)\" || test -z \"$(CONFIG_CLEAN_VPATH_FILES)\" || rm -f $(CONFIG_CLEAN_VPATH_FILES)\n\nmaintainer-clean-generic:\n\t@echo \"This command is intended for maintainers to use\"\n\t@echo \"it deletes files that may require special tools to rebuild.\"\nclean: clean-am\n\nclean-am: clean-generic mostlyclean-am\n\ndistclean: distclean-am\n\t-rm -f Makefile\ndistclean-am: clean-am distclean-generic\n\ndvi: dvi-am\n\ndvi-am:\n\nhtml: html-am\n\nhtml-am:\n\ninfo: info-am\n\ninfo-am:\n\ninstall-data-am:\n\ninstall-dvi: install-dvi-am\n\ninstall-dvi-am:\n\ninstall-exec-am:\n\ninstall-html: install-html-am\n\ninstall-html-am:\n\ninstall-info: install-info-am\n\ninstall-info-am:\n\ninstall-man:\n\ninstall-pdf: install-pdf-am\n\ninstall-pdf-am:\n\ninstall-ps: install-ps-am\n\ninstall-ps-am:\n\ninstallcheck-am:\n\nmaintainer-clean: maintainer-clean-am\n\t-rm -f Makefile\nmaintainer-clean-am: distclean-am maintainer-clean-generic\n\nmostlyclean: mostlyclean-am\n\nmostlyclean-am: mostlyclean-generic\n\npdf: pdf-am\n\npdf-am:\n\nps: ps-am\n\nps-am:\n\nuninstall-am:\n\n.MAKE: install-am install-strip\n\n.PHONY: all all-am check check-am clean clean-generic cscopelist-am \\\n\tctags-am distclean distclean-generic distdir dvi dvi-am html \\\n\thtml-am info info-am install install-am install-data \\\n\tinstall-data-am install-dvi install-dvi-am install-exec \\\n\tinstall-exec-am install-html install-html-am install-info \\\n\tinstall-info-am install-man install-pdf install-pdf-am \\\n\tinstall-ps install-ps-am install-strip installcheck \\\n\tinstallcheck-am installdirs maintainer-clean \\\n\tmaintainer-clean-generic mostlyclean mostlyclean-generic pdf \\\n\tpdf-am ps ps-am tags-am uninstall uninstall-am\n\n.PRECIOUS: Makefile\n\n\n# Tell versions [3.59,3.63) of GNU make to not export all variables.\n# Otherwise a system limit (for SysV at least) may be exceeded.\n.NOEXPORT:\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/__inline.m4",
    "content": "# Test for __inline keyword\ndnl Copyright 2017-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl___INLINE],\n[\n  AC_CACHE_CHECK([whether the compiler supports the __inline keyword],\n    [gl_cv_c___inline],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n         [[typedef int foo_t;\n           static __inline foo_t foo (void) { return 0; }]],\n         [[return foo ();]])],\n       [gl_cv_c___inline=yes],\n       [gl_cv_c___inline=no])])\n  if test $gl_cv_c___inline = yes; then\n    AC_DEFINE([HAVE___INLINE], [1],\n      [Define to 1 if the compiler supports the keyword '__inline'.])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/absolute-header.m4",
    "content": "# absolute-header.m4 serial 17\ndnl Copyright (C) 2006-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Derek Price.\n\n# gl_ABSOLUTE_HEADER(HEADER1 HEADER2 ...)\n# ---------------------------------------\n# Find the absolute name of a header file, testing first if the header exists.\n# If the header were sys/inttypes.h, this macro would define\n# ABSOLUTE_SYS_INTTYPES_H to the '\"\"' quoted absolute name of sys/inttypes.h\n# in config.h\n# (e.g. '#define ABSOLUTE_SYS_INTTYPES_H \"///usr/include/sys/inttypes.h\"').\n# The three \"///\" are to pacify Sun C 5.8, which otherwise would say\n# \"warning: #include of /usr/include/... may be non-portable\".\n# Use '\"\"', not '<>', so that the /// cannot be confused with a C99 comment.\n# Note: This macro assumes that the header file is not empty after\n# preprocessing, i.e. it does not only define preprocessor macros but also\n# provides some type/enum definitions or function/variable declarations.\nAC_DEFUN([gl_ABSOLUTE_HEADER],\n[AC_REQUIRE([AC_CANONICAL_HOST])\nAC_LANG_PREPROC_REQUIRE()dnl\nm4_foreach_w([gl_HEADER_NAME], [$1],\n  [AS_VAR_PUSHDEF([gl_absolute_header],\n                  [gl_cv_absolute_]m4_defn([gl_HEADER_NAME]))dnl\n  AC_CACHE_CHECK([absolute name of <]m4_defn([gl_HEADER_NAME])[>],\n    [gl_absolute_header],\n    [AS_VAR_PUSHDEF([ac_header_exists],\n                    [ac_cv_header_]m4_defn([gl_HEADER_NAME]))dnl\n    AC_CHECK_HEADERS_ONCE(m4_defn([gl_HEADER_NAME]))dnl\n    if test AS_VAR_GET([ac_header_exists]) = yes; then\n      gl_ABSOLUTE_HEADER_ONE(m4_defn([gl_HEADER_NAME]))\n    fi\n    AS_VAR_POPDEF([ac_header_exists])dnl\n    ])dnl\n  AC_DEFINE_UNQUOTED(AS_TR_CPP([ABSOLUTE_]m4_defn([gl_HEADER_NAME])),\n                     [\"AS_VAR_GET([gl_absolute_header])\"],\n                     [Define this to an absolute name of <]m4_defn([gl_HEADER_NAME])[>.])\n  AS_VAR_POPDEF([gl_absolute_header])dnl\n])dnl\n])# gl_ABSOLUTE_HEADER\n\n# gl_ABSOLUTE_HEADER_ONE(HEADER)\n# ------------------------------\n# Like gl_ABSOLUTE_HEADER, except that:\n#   - it assumes that the header exists,\n#   - it uses the current CPPFLAGS,\n#   - it does not cache the result,\n#   - it is silent.\nAC_DEFUN([gl_ABSOLUTE_HEADER_ONE],\n[\n  AC_REQUIRE([AC_CANONICAL_HOST])\n  AC_LANG_CONFTEST([AC_LANG_SOURCE([[#include <]]m4_dquote([$1])[[>]])])\n  dnl AIX \"xlc -E\" and \"cc -E\" omit #line directives for header files\n  dnl that contain only a #include of other header files and no\n  dnl non-comment tokens of their own. This leads to a failure to\n  dnl detect the absolute name of <dirent.h>, <signal.h>, <poll.h>\n  dnl and others. The workaround is to force preservation of comments\n  dnl through option -C. This ensures all necessary #line directives\n  dnl are present. GCC supports option -C as well.\n  case \"$host_os\" in\n    aix*) gl_absname_cpp=\"$ac_cpp -C\" ;;\n    *)    gl_absname_cpp=\"$ac_cpp\" ;;\n  esac\nchangequote(,)\n  case \"$host_os\" in\n    mingw*)\n      dnl For the sake of native Windows compilers (excluding gcc),\n      dnl treat backslash as a directory separator, like /.\n      dnl Actually, these compilers use a double-backslash as\n      dnl directory separator, inside the\n      dnl   # line \"filename\"\n      dnl directives.\n      gl_dirsep_regex='[/\\\\]'\n      ;;\n    *)\n      gl_dirsep_regex='\\/'\n      ;;\n  esac\n  dnl A sed expression that turns a string into a basic regular\n  dnl expression, for use within \"/.../\".\n  gl_make_literal_regex_sed='s,[]$^\\\\.*/[],\\\\&,g'\n  gl_header_literal_regex=`echo '$1' \\\n                           | sed -e \"$gl_make_literal_regex_sed\"`\n  gl_absolute_header_sed=\"/${gl_dirsep_regex}${gl_header_literal_regex}/\"'{\n      s/.*\"\\(.*'\"${gl_dirsep_regex}${gl_header_literal_regex}\"'\\)\".*/\\1/\n      s|^/[^/]|//&|\n      p\n      q\n    }'\nchangequote([,])\n  dnl eval is necessary to expand gl_absname_cpp.\n  dnl Ultrix and Pyramid sh refuse to redirect output of eval,\n  dnl so use subshell.\n  AS_VAR_SET([gl_cv_absolute_]AS_TR_SH([[$1]]),\n[`(eval \"$gl_absname_cpp conftest.$ac_ext\") 2>&AS_MESSAGE_LOG_FD |\n  sed -n \"$gl_absolute_header_sed\"`])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/errno_h.m4",
    "content": "# errno_h.m4 serial 13\ndnl Copyright (C) 2004, 2006, 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_PREREQ([2.61])\n\nAC_DEFUN_ONCE([gl_HEADER_ERRNO_H],\n[\n  AC_REQUIRE([AC_PROG_CC])\n  AC_CACHE_CHECK([for complete errno.h], [gl_cv_header_errno_h_complete], [\n    AC_EGREP_CPP([booboo],[\n#include <errno.h>\n#if !defined ETXTBSY\nbooboo\n#endif\n#if !defined ENOMSG\nbooboo\n#endif\n#if !defined EIDRM\nbooboo\n#endif\n#if !defined ENOLINK\nbooboo\n#endif\n#if !defined EPROTO\nbooboo\n#endif\n#if !defined EMULTIHOP\nbooboo\n#endif\n#if !defined EBADMSG\nbooboo\n#endif\n#if !defined EOVERFLOW\nbooboo\n#endif\n#if !defined ENOTSUP\nbooboo\n#endif\n#if !defined ENETRESET\nbooboo\n#endif\n#if !defined ECONNABORTED\nbooboo\n#endif\n#if !defined ESTALE\nbooboo\n#endif\n#if !defined EDQUOT\nbooboo\n#endif\n#if !defined ECANCELED\nbooboo\n#endif\n#if !defined EOWNERDEAD\nbooboo\n#endif\n#if !defined ENOTRECOVERABLE\nbooboo\n#endif\n#if !defined EILSEQ\nbooboo\n#endif\n      ],\n      [gl_cv_header_errno_h_complete=no],\n      [gl_cv_header_errno_h_complete=yes])\n  ])\n  if test $gl_cv_header_errno_h_complete = yes; then\n    ERRNO_H=''\n  else\n    gl_NEXT_HEADERS([errno.h])\n    ERRNO_H='errno.h'\n  fi\n  AC_SUBST([ERRNO_H])\n  AM_CONDITIONAL([GL_GENERATE_ERRNO_H], [test -n \"$ERRNO_H\"])\n  gl_REPLACE_ERRNO_VALUE([EMULTIHOP])\n  gl_REPLACE_ERRNO_VALUE([ENOLINK])\n  gl_REPLACE_ERRNO_VALUE([EOVERFLOW])\n])\n\n# Assuming $1 = EOVERFLOW.\n# The EOVERFLOW errno value ought to be defined in <errno.h>, according to\n# POSIX.  But some systems (like OpenBSD 4.0 or AIX 3) don't define it, and\n# some systems (like OSF/1) define it when _XOPEN_SOURCE_EXTENDED is defined.\n# Check for the value of EOVERFLOW.\n# Set the variables EOVERFLOW_HIDDEN and EOVERFLOW_VALUE.\nAC_DEFUN([gl_REPLACE_ERRNO_VALUE],\n[\n  if test -n \"$ERRNO_H\"; then\n    AC_CACHE_CHECK([for ]$1[ value], [gl_cv_header_errno_h_]$1, [\n      AC_EGREP_CPP([yes],[\n#include <errno.h>\n#ifdef ]$1[\nyes\n#endif\n      ],\n      [gl_cv_header_errno_h_]$1[=yes],\n      [gl_cv_header_errno_h_]$1[=no])\n      if test $gl_cv_header_errno_h_]$1[ = no; then\n        AC_EGREP_CPP([yes],[\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n#ifdef ]$1[\nyes\n#endif\n          ], [gl_cv_header_errno_h_]$1[=hidden])\n        if test $gl_cv_header_errno_h_]$1[ = hidden; then\n          dnl The macro exists but is hidden.\n          dnl Define it to the same value.\n          AC_COMPUTE_INT([gl_cv_header_errno_h_]$1, $1, [\n#define _XOPEN_SOURCE_EXTENDED 1\n#include <errno.h>\n/* The following two lines are a workaround against an autoconf-2.52 bug.  */\n#include <stdio.h>\n#include <stdlib.h>\n])\n        fi\n      fi\n    ])\n    case $gl_cv_header_errno_h_]$1[ in\n      yes | no)\n        ]$1[_HIDDEN=0; ]$1[_VALUE=\n        ;;\n      *)\n        ]$1[_HIDDEN=1; ]$1[_VALUE=\"$gl_cv_header_errno_h_]$1[\"\n        ;;\n    esac\n    AC_SUBST($1[_HIDDEN])\n    AC_SUBST($1[_VALUE])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/execinfo.m4",
    "content": "# Check for GNU-style execinfo.h.\n\ndnl Copyright 2012-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_EXECINFO_H],\n[\n  AC_CHECK_HEADERS_ONCE([execinfo.h])\n\n  LIB_EXECINFO=''\n  EXECINFO_H='execinfo.h'\n\n  if test $ac_cv_header_execinfo_h = yes; then\n    gl_saved_libs=$LIBS\n      AC_SEARCH_LIBS([backtrace_symbols_fd], [execinfo],\n        [test \"$ac_cv_search_backtrace_symbols_fd\" = \"none required\" ||\n         LIB_EXECINFO=$ac_cv_search_backtrace_symbols_fd])\n    LIBS=$gl_saved_libs\n    test \"$ac_cv_search_backtrace_symbols_fd\" = no || EXECINFO_H=''\n  fi\n\n  if test -n \"$EXECINFO_H\"; then\n    AC_LIBOBJ([execinfo])\n  fi\n\n  AC_SUBST([EXECINFO_H])\n  AC_SUBST([LIB_EXECINFO])\n  AM_CONDITIONAL([GL_GENERATE_EXECINFO_H], [test -n \"$EXECINFO_H\"])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/extensions.m4",
    "content": "# serial 22  -*- Autoconf -*-\n# Enable extensions on systems that normally disable them.\n\n# Copyright (C) 2003, 2006-2021 Free Software Foundation, Inc.\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\ndnl Define to empty for the benefit of Autoconf 2.69 and earlier, so that\ndnl AC_USE_SYSTEM_EXTENSIONS (below) can be used unchanged from Autoconf 2.70+.\nm4_ifndef([AC_CHECK_INCLUDES_DEFAULT],\n  [AC_DEFUN([AC_CHECK_INCLUDES_DEFAULT], [])])\n\n# This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from git\n# Autoconf.  Perhaps we can remove this once we can assume Autoconf\n# is recent-enough everywhere, but since Autoconf mutates rapidly\n# enough in this area it's likely we'll need to redefine\n# AC_USE_SYSTEM_EXTENSIONS for quite some time.\n\n# If autoconf reports a warning\n#     warning: AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS\n# or  warning: AC_RUN_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS\n# the fix is\n#   1) to ensure that AC_USE_SYSTEM_EXTENSIONS is never directly invoked\n#      but always AC_REQUIREd,\n#   2) to ensure that for each occurrence of\n#        AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])\n#      or\n#        AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])\n#      the corresponding gnulib module description has 'extensions' among\n#      its dependencies. This will ensure that the gl_USE_SYSTEM_EXTENSIONS\n#      invocation occurs in gl_EARLY, not in gl_INIT.\n\nm4_version_prereq([2.70.1], [], [\n\n# AC_USE_SYSTEM_EXTENSIONS\n# ------------------------\n# Enable extensions on systems that normally disable them,\n# typically due to standards-conformance issues.\n# We unconditionally define as many of the known feature-enabling\n# as possible, reserving conditional behavior for macros that are\n# known to cause problems on some platforms (such as __EXTENSIONS__).\nAC_DEFUN_ONCE([AC_USE_SYSTEM_EXTENSIONS],\n[AC_BEFORE([$0], [AC_PREPROC_IFELSE])dnl\nAC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl\nAC_BEFORE([$0], [AC_LINK_IFELSE])dnl\nAC_BEFORE([$0], [AC_RUN_IFELSE])dnl\nAC_BEFORE([$0], [AC_CHECK_INCLUDES_DEFAULT])dnl\ndnl #undef in AH_VERBATIM gets replaced with #define by AC_DEFINE.\ndnl Use a different key than __EXTENSIONS__, as that name broke existing\ndnl configure.ac when using autoheader 2.62.\ndnl The macros below are in alphabetical order ignoring leading _ or __\ndnl prefixes.\nAH_VERBATIM([USE_SYSTEM_EXTENSIONS],\n[/* Enable extensions on AIX 3, Interix.  */\n#ifndef _ALL_SOURCE\n# undef _ALL_SOURCE\n#endif\n/* Enable general extensions on macOS.  */\n#ifndef _DARWIN_C_SOURCE\n# undef _DARWIN_C_SOURCE\n#endif\n/* Enable general extensions on Solaris.  */\n#ifndef __EXTENSIONS__\n# undef __EXTENSIONS__\n#endif\n/* Enable GNU extensions on systems that have them.  */\n#ifndef _GNU_SOURCE\n# undef _GNU_SOURCE\n#endif\n/* Enable X/Open compliant socket functions that do not require linking\n   with -lxnet on HP-UX 11.11.  */\n#ifndef _HPUX_ALT_XOPEN_SOCKET_API\n# undef _HPUX_ALT_XOPEN_SOCKET_API\n#endif\n/* Identify the host operating system as Minix.\n   This macro does not affect the system headers' behavior.\n   A future release of Autoconf may stop defining this macro.  */\n#ifndef _MINIX\n# undef _MINIX\n#endif\n/* Enable general extensions on NetBSD.\n   Enable NetBSD compatibility extensions on Minix.  */\n#ifndef _NETBSD_SOURCE\n# undef _NETBSD_SOURCE\n#endif\n/* Enable OpenBSD compatibility extensions on NetBSD.\n   Oddly enough, this does nothing on OpenBSD.  */\n#ifndef _OPENBSD_SOURCE\n# undef _OPENBSD_SOURCE\n#endif\n/* Define to 1 if needed for POSIX-compatible behavior.  */\n#ifndef _POSIX_SOURCE\n# undef _POSIX_SOURCE\n#endif\n/* Define to 2 if needed for POSIX-compatible behavior.  */\n#ifndef _POSIX_1_SOURCE\n# undef _POSIX_1_SOURCE\n#endif\n/* Enable POSIX-compatible threading on Solaris.  */\n#ifndef _POSIX_PTHREAD_SEMANTICS\n# undef _POSIX_PTHREAD_SEMANTICS\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-5:2014.  */\n#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__\n# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-1:2014.  */\n#ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n# undef __STDC_WANT_IEC_60559_BFP_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-2:2015.  */\n#ifndef __STDC_WANT_IEC_60559_DFP_EXT__\n# undef __STDC_WANT_IEC_60559_DFP_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-4:2015.  */\n#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__\n# undef __STDC_WANT_IEC_60559_FUNCS_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TS 18661-3:2015.  */\n#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__\n# undef __STDC_WANT_IEC_60559_TYPES_EXT__\n#endif\n/* Enable extensions specified by ISO/IEC TR 24731-2:2010.  */\n#ifndef __STDC_WANT_LIB_EXT2__\n# undef __STDC_WANT_LIB_EXT2__\n#endif\n/* Enable extensions specified by ISO/IEC 24747:2009.  */\n#ifndef __STDC_WANT_MATH_SPEC_FUNCS__\n# undef __STDC_WANT_MATH_SPEC_FUNCS__\n#endif\n/* Enable extensions on HP NonStop.  */\n#ifndef _TANDEM_SOURCE\n# undef _TANDEM_SOURCE\n#endif\n/* Enable X/Open extensions.  Define to 500 only if necessary\n   to make mbstate_t available.  */\n#ifndef _XOPEN_SOURCE\n# undef _XOPEN_SOURCE\n#endif\n])dnl\n\n  AC_REQUIRE([AC_CHECK_INCLUDES_DEFAULT])dnl\n  _AC_CHECK_HEADER_ONCE([wchar.h])\n  _AC_CHECK_HEADER_ONCE([minix/config.h])\n\ndnl Defining __EXTENSIONS__ may break the system headers on some systems.\ndnl (FIXME: Which ones?)\n  AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],\n    [ac_cv_safe_to_define___extensions__],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM([[\n#         define __EXTENSIONS__ 1\n          ]AC_INCLUDES_DEFAULT])],\n       [ac_cv_safe_to_define___extensions__=yes],\n       [ac_cv_safe_to_define___extensions__=no])])\n\ndnl HP-UX 11.11 defines mbstate_t only if _XOPEN_SOURCE is defined to\ndnl 500, regardless of whether compiling with -Ae or -D_HPUX_SOURCE=1.\ndnl But defining _XOPEN_SOURCE may turn *off* extensions on platforms\ndnl not covered by turn-on-extensions macros (notably Dragonfly, Free,\ndnl and OpenBSD, which don't have any equivalent of _NETBSD_SOURCE) so\ndnl it should only be defined when necessary.\n  AC_CACHE_CHECK([whether _XOPEN_SOURCE should be defined],\n    [ac_cv_should_define__xopen_source],\n    [ac_cv_should_define__xopen_source=no\n    AS_IF([test $ac_cv_header_wchar_h = yes],\n      [AC_COMPILE_IFELSE(\n        [AC_LANG_PROGRAM([[\n          #include <wchar.h>\n          mbstate_t x;]])],\n        [],\n        [AC_COMPILE_IFELSE(\n          [AC_LANG_PROGRAM([[\n            #define _XOPEN_SOURCE 500\n            #include <wchar.h>\n            mbstate_t x;]])],\n          [ac_cv_should_define__xopen_source=yes])])])])\n\n  AC_DEFINE([_ALL_SOURCE])\n  AC_DEFINE([_DARWIN_C_SOURCE])\n  AC_DEFINE([_GNU_SOURCE])\n  AC_DEFINE([_HPUX_ALT_XOPEN_SOCKET_API])\n  AC_DEFINE([_NETBSD_SOURCE])\n  AC_DEFINE([_OPENBSD_SOURCE])\n  AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])\n  AC_DEFINE([__STDC_WANT_IEC_60559_ATTRIBS_EXT__])\n  AC_DEFINE([__STDC_WANT_IEC_60559_BFP_EXT__])\n  AC_DEFINE([__STDC_WANT_IEC_60559_DFP_EXT__])\n  AC_DEFINE([__STDC_WANT_IEC_60559_FUNCS_EXT__])\n  AC_DEFINE([__STDC_WANT_IEC_60559_TYPES_EXT__])\n  AC_DEFINE([__STDC_WANT_LIB_EXT2__])\n  AC_DEFINE([__STDC_WANT_MATH_SPEC_FUNCS__])\n  AC_DEFINE([_TANDEM_SOURCE])\n  AS_IF([test $ac_cv_header_minix_config_h = yes],\n    [MINIX=yes\n    AC_DEFINE([_MINIX])\n    AC_DEFINE([_POSIX_SOURCE])\n    AC_DEFINE([_POSIX_1_SOURCE], [2])],\n    [MINIX=])\n  AS_IF([test $ac_cv_safe_to_define___extensions__ = yes],\n    [AC_DEFINE([__EXTENSIONS__])])\n  AS_IF([test $ac_cv_should_define__xopen_source = yes],\n    [AC_DEFINE([_XOPEN_SOURCE], [500])])\n])# AC_USE_SYSTEM_EXTENSIONS\n])\n\n# gl_USE_SYSTEM_EXTENSIONS\n# ------------------------\n# Enable extensions on systems that normally disable them,\n# typically due to standards-conformance issues.\nAC_DEFUN_ONCE([gl_USE_SYSTEM_EXTENSIONS],\n[\n  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])\n\n  dnl On OpenBSD 6.8 with GCC, the include files contain a couple of\n  dnl definitions that are only activated with an explicit -D_ISOC11_SOURCE.\n  dnl That's because this version of GCC (4.2.1) supports the option\n  dnl '-std=gnu99' but not the option '-std=gnu11'.\n  AC_REQUIRE([AC_CANONICAL_HOST])\n  case \"$host_os\" in\n    openbsd*)\n      AC_DEFINE([_ISOC11_SOURCE], [1],\n        [Define to enable the declarations of ISO C 11 types and functions.])\n      ;;\n  esac\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/extern-inline.m4",
    "content": "dnl 'extern inline' a la ISO C99.\n\ndnl Copyright 2012-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_EXTERN_INLINE],\n[\n  AH_VERBATIM([extern_inline],\n[/* Please see the Gnulib manual for how to use these macros.\n\n   Suppress extern inline with HP-UX cc, as it appears to be broken; see\n   <https://lists.gnu.org/r/bug-texinfo/2013-02/msg00030.html>.\n\n   Suppress extern inline with Sun C in standards-conformance mode, as it\n   mishandles inline functions that call each other.  E.g., for 'inline void f\n   (void) { } inline void g (void) { f (); }', c99 incorrectly complains\n   'reference to static identifier \"f\" in extern inline function'.\n   This bug was observed with Oracle Developer Studio 12.6\n   (Sun C 5.15 SunOS_sparc 2017/05/30).\n\n   Suppress extern inline (with or without __attribute__ ((__gnu_inline__)))\n   on configurations that mistakenly use 'static inline' to implement\n   functions or macros in standard C headers like <ctype.h>.  For example,\n   if isdigit is mistakenly implemented via a static inline function,\n   a program containing an extern inline function that calls isdigit\n   may not work since the C standard prohibits extern inline functions\n   from calling static functions (ISO C 99 section 6.7.4.(3).\n   This bug is known to occur on:\n\n     OS X 10.8 and earlier; see:\n     https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html\n\n     DragonFly; see\n     http://muscles.dragonflybsd.org/bulk/clang-master-potential/20141111_102002/logs/ah-tty-0.3.12.log\n\n     FreeBSD; see:\n     https://lists.gnu.org/r/bug-gnulib/2014-07/msg00104.html\n\n   OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and\n   for clang but remains for g++; see <https://trac.macports.org/ticket/41033>.\n   Assume DragonFly and FreeBSD will be similar.\n\n   GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99\n   inline semantics, unless -fgnu89-inline is used.  It defines a macro\n   __GNUC_STDC_INLINE__ to indicate this situation or a macro\n   __GNUC_GNU_INLINE__ to indicate the opposite situation.\n   GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline\n   semantics but warns, unless -fgnu89-inline is used:\n     warning: C99 inline functions are not supported; using GNU89\n     warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute\n   It defines a macro __GNUC_GNU_INLINE__ to indicate this situation.\n */\n#if (((defined __APPLE__ && defined __MACH__) \\\n      || defined __DragonFly__ || defined __FreeBSD__) \\\n     && (defined __header_inline \\\n         ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ \\\n            && ! defined __clang__) \\\n         : ((! defined _DONT_USE_CTYPE_INLINE_ \\\n             && (defined __GNUC__ || defined __cplusplus)) \\\n            || (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE \\\n                && defined __GNUC__ && ! defined __cplusplus))))\n# define _GL_EXTERN_INLINE_STDHEADER_BUG\n#endif\n#if ((__GNUC__ \\\n      ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \\\n      : (199901L <= __STDC_VERSION__ \\\n         && !defined __HP_cc \\\n         && !defined __PGI \\\n         && !(defined __SUNPRO_C && __STDC__))) \\\n     && !defined _GL_EXTERN_INLINE_STDHEADER_BUG)\n# define _GL_INLINE inline\n# define _GL_EXTERN_INLINE extern inline\n# define _GL_EXTERN_INLINE_IN_USE\n#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \\\n       && !defined _GL_EXTERN_INLINE_STDHEADER_BUG)\n# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__\n   /* __gnu_inline__ suppresses a GCC 4.2 diagnostic.  */\n#  define _GL_INLINE extern inline __attribute__ ((__gnu_inline__))\n# else\n#  define _GL_INLINE extern inline\n# endif\n# define _GL_EXTERN_INLINE extern\n# define _GL_EXTERN_INLINE_IN_USE\n#else\n# define _GL_INLINE _GL_UNUSED static\n# define _GL_EXTERN_INLINE _GL_UNUSED static\n#endif\n\n/* In GCC 4.6 (inclusive) to 5.1 (exclusive),\n   suppress bogus \"no previous prototype for 'FOO'\"\n   and \"no previous declaration for 'FOO'\" diagnostics,\n   when FOO is an inline function in the header; see\n   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113> and\n   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63877>.  */\n#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__\n# if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__\n#  define _GL_INLINE_HEADER_CONST_PRAGMA\n# else\n#  define _GL_INLINE_HEADER_CONST_PRAGMA \\\n     _Pragma (\"GCC diagnostic ignored \\\"-Wsuggest-attribute=const\\\"\")\n# endif\n# define _GL_INLINE_HEADER_BEGIN \\\n    _Pragma (\"GCC diagnostic push\") \\\n    _Pragma (\"GCC diagnostic ignored \\\"-Wmissing-prototypes\\\"\") \\\n    _Pragma (\"GCC diagnostic ignored \\\"-Wmissing-declarations\\\"\") \\\n    _GL_INLINE_HEADER_CONST_PRAGMA\n# define _GL_INLINE_HEADER_END \\\n    _Pragma (\"GCC diagnostic pop\")\n#else\n# define _GL_INLINE_HEADER_BEGIN\n# define _GL_INLINE_HEADER_END\n#endif])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/getdelim.m4",
    "content": "# getdelim.m4 serial 15\n\ndnl Copyright (C) 2005-2007, 2009-2021 Free Software Foundation, Inc.\ndnl\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_PREREQ([2.59])\n\nAC_DEFUN([gl_FUNC_GETDELIM],\n[\n  AC_REQUIRE([gl_STDIO_H_DEFAULTS])\n  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles\n\n  dnl Persuade glibc <stdio.h> to declare getdelim().\n  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])\n\n  AC_CHECK_DECLS_ONCE([getdelim])\n\n  AC_CHECK_FUNCS_ONCE([getdelim])\n  if test $ac_cv_func_getdelim = yes; then\n    HAVE_GETDELIM=1\n    dnl Found it in some library.  Verify that it works.\n    AC_CACHE_CHECK([for working getdelim function],\n      [gl_cv_func_working_getdelim],\n      [echo fooNbarN | tr -d '\\012' | tr N '\\012' > conftest.data\n       AC_RUN_IFELSE([AC_LANG_SOURCE([[\n#    include <stdio.h>\n#    include <stdlib.h>\n#    include <string.h>\n    int main ()\n    {\n      FILE *in = fopen (\"./conftest.data\", \"r\");\n      if (!in)\n        return 1;\n      {\n        /* Test result for a NULL buffer and a zero size.\n           Based on a test program from Karl Heuer.  */\n        char *line = NULL;\n        size_t siz = 0;\n        int len = getdelim (&line, &siz, '\\n', in);\n        if (!(len == 4 && line && strcmp (line, \"foo\\n\") == 0))\n          { free (line); fclose (in); return 2; }\n        free (line);\n      }\n      {\n        /* Test result for a NULL buffer and a non-zero size.\n           This crashes on FreeBSD 8.0.  */\n        char *line = NULL;\n        size_t siz = (size_t)(~0) / 4;\n        if (getdelim (&line, &siz, '\\n', in) == -1)\n          { fclose (in); return 3; }\n        free (line);\n      }\n      fclose (in);\n      return 0;\n    }\n    ]])],\n         [gl_cv_func_working_getdelim=yes],\n         [gl_cv_func_working_getdelim=no],\n         [dnl We're cross compiling.\n          dnl Guess it works on glibc2 systems and musl systems.\n          AC_EGREP_CPP([Lucky GNU user],\n            [\n#include <features.h>\n#ifdef __GNU_LIBRARY__\n #if (__GLIBC__ >= 2) && !defined __UCLIBC__\n  Lucky GNU user\n #endif\n#endif\n            ],\n            [gl_cv_func_working_getdelim=\"guessing yes\"],\n            [case \"$host_os\" in\n               *-musl*) gl_cv_func_working_getdelim=\"guessing yes\" ;;\n               *)       gl_cv_func_working_getdelim=\"$gl_cross_guess_normal\" ;;\n             esac\n            ])\n         ])\n      ])\n    case \"$gl_cv_func_working_getdelim\" in\n      *yes) ;;\n      *) REPLACE_GETDELIM=1 ;;\n    esac\n  else\n    HAVE_GETDELIM=0\n  fi\n\n  if test $ac_cv_have_decl_getdelim = no; then\n    HAVE_DECL_GETDELIM=0\n  fi\n])\n\n# Prerequisites of lib/getdelim.c.\nAC_DEFUN([gl_PREREQ_GETDELIM],\n[\n  AC_CHECK_FUNCS([flockfile funlockfile])\n  AC_CHECK_DECLS([getc_unlocked])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/gethostname.m4",
    "content": "# gethostname.m4 serial 15\ndnl Copyright (C) 2002, 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\n# Ensure\n# - the gethostname() function,\n# - the HOST_NAME_MAX macro in <limits.h>.\nAC_DEFUN([gl_FUNC_GETHOSTNAME],\n[\n  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])\n  gl_PREREQ_SYS_H_WINSOCK2\n\n  dnl Where is gethostname() defined?\n  dnl - On native Windows, it is in ws2_32.dll.\n  dnl - Otherwise it is in libc.\n  GETHOSTNAME_LIB=\n  AC_CHECK_FUNCS([gethostname], , [\n    AC_CACHE_CHECK([for gethostname in winsock2.h and -lws2_32],\n      [gl_cv_w32_gethostname],\n      [gl_cv_w32_gethostname=no\n       gl_save_LIBS=\"$LIBS\"\n       LIBS=\"$LIBS -lws2_32\"\n       AC_LINK_IFELSE([AC_LANG_PROGRAM([[\n#ifdef HAVE_WINSOCK2_H\n#include <winsock2.h>\n#endif\n#include <stddef.h>\n]], [[gethostname(NULL, 0);]])], [gl_cv_w32_gethostname=yes])\n       LIBS=\"$gl_save_LIBS\"\n      ])\n    if test \"$gl_cv_w32_gethostname\" = \"yes\"; then\n      GETHOSTNAME_LIB=\"-lws2_32\"\n    fi\n  ])\n  AC_SUBST([GETHOSTNAME_LIB])\n\n  if test \"$ac_cv_func_gethostname\" = no; then\n    HAVE_GETHOSTNAME=0\n  fi\n\n  gl_PREREQ_HOST_NAME_MAX\n])\n\n# Provide HOST_NAME_MAX when <limits.h> lacks it.\nAC_DEFUN([gl_PREREQ_HOST_NAME_MAX], [\n  dnl - On most Unix systems, use MAXHOSTNAMELEN from <sys/param.h> instead.\n  dnl - On Solaris, Cygwin, BeOS, use MAXHOSTNAMELEN from <netdb.h> instead.\n  dnl - On mingw, use 256, because\n  dnl   <https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-gethostname> says:\n  dnl   \"if a buffer of 256 bytes is passed in the name parameter and\n  dnl    the namelen parameter is set to 256, the buffer size will always\n  dnl    be adequate.\"\n  dnl With this, there is no need to use sysconf (_SC_HOST_NAME_MAX), which\n  dnl is not a compile-time constant.\n  dnl We cannot override <limits.h> using the usual technique, because\n  dnl gl_CHECK_NEXT_HEADERS does not work for <limits.h>. Therefore retrieve\n  dnl the value of HOST_NAME_MAX at configure time.\n  AC_CHECK_HEADERS_ONCE([sys/param.h])\n  AC_CHECK_HEADERS_ONCE([sys/socket.h])\n  AC_CHECK_HEADERS_ONCE([netdb.h])\n  AC_CACHE_CHECK([for HOST_NAME_MAX], [gl_cv_decl_HOST_NAME_MAX], [\n    gl_cv_decl_HOST_NAME_MAX=\n    AC_EGREP_CPP([lucky], [\n#include <limits.h>\n#ifdef HOST_NAME_MAX\nlucky\n#endif\n      ], [gl_cv_decl_HOST_NAME_MAX=yes])\n    if test -z \"$gl_cv_decl_HOST_NAME_MAX\"; then\n      dnl It's not defined in <limits.h>. Substitute it.\n      if test \"$gl_cv_w32_gethostname\" = yes; then\n        dnl mingw.\n        gl_cv_decl_HOST_NAME_MAX=256\n      else\n        AC_COMPUTE_INT([gl_cv_decl_HOST_NAME_MAX], [MAXHOSTNAMELEN], [\n#include <sys/types.h>\n#if HAVE_SYS_PARAM_H\n# include <sys/param.h>\n#endif\n#if HAVE_SYS_SOCKET_H\n# include <sys/socket.h>\n#endif\n#if HAVE_NETDB_H\n# include <netdb.h>\n#endif\n],\n          [dnl The system does not define MAXHOSTNAMELEN in any of the common\n           dnl headers. Use a safe fallback.\n           gl_cv_decl_HOST_NAME_MAX=256\n          ])\n      fi\n    fi\n  ])\n  if test \"$gl_cv_decl_HOST_NAME_MAX\" != yes; then\n    AC_DEFINE_UNQUOTED([HOST_NAME_MAX], [$gl_cv_decl_HOST_NAME_MAX],\n      [Define HOST_NAME_MAX when <limits.h> does not define it.])\n  fi\n])\n\n# Prerequisites of lib/gethostname.c.\nAC_DEFUN([gl_PREREQ_GETHOSTNAME], [\n  if test \"$gl_cv_w32_gethostname\" != \"yes\"; then\n    AC_CHECK_FUNCS([uname])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/getline.m4",
    "content": "# getline.m4 serial 30\n\ndnl Copyright (C) 1998-2003, 2005-2007, 2009-2021 Free Software Foundation,\ndnl Inc.\ndnl\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_PREREQ([2.59])\n\ndnl See if there's a working, system-supplied version of the getline function.\ndnl We can't just do AC_REPLACE_FUNCS([getline]) because some systems\ndnl have a function by that name in -linet that doesn't have anything\ndnl to do with the function we need.\nAC_DEFUN([gl_FUNC_GETLINE],\n[\n  AC_REQUIRE([gl_STDIO_H_DEFAULTS])\n  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles\n\n  dnl Persuade glibc <stdio.h> to declare getline().\n  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])\n\n  AC_CHECK_DECLS_ONCE([getline])\n\n  gl_getline_needs_run_time_check=no\n  AC_CHECK_FUNC([getline],\n                [dnl Found it in some library.  Verify that it works.\n                 gl_getline_needs_run_time_check=yes],\n                [am_cv_func_working_getline=no])\n  if test $gl_getline_needs_run_time_check = yes; then\n    AC_CACHE_CHECK([for working getline function],\n      [am_cv_func_working_getline],\n      [echo fooNbarN | tr -d '\\012' | tr N '\\012' > conftest.data\n       AC_RUN_IFELSE([AC_LANG_SOURCE([[\n#    include <stdio.h>\n#    include <stdlib.h>\n#    include <string.h>\n    int main ()\n    {\n      FILE *in = fopen (\"./conftest.data\", \"r\");\n      if (!in)\n        return 1;\n      {\n        /* Test result for a NULL buffer and a zero size.\n           Based on a test program from Karl Heuer.  */\n        char *line = NULL;\n        size_t siz = 0;\n        int len = getline (&line, &siz, in);\n        if (!(len == 4 && line && strcmp (line, \"foo\\n\") == 0))\n          { free (line); fclose (in); return 2; }\n        free (line);\n      }\n      {\n        /* Test result for a NULL buffer and a non-zero size.\n           This crashes on FreeBSD 8.0.  */\n        char *line = NULL;\n        size_t siz = (size_t)(~0) / 4;\n        if (getline (&line, &siz, in) == -1)\n          { fclose (in); return 3; }\n        free (line);\n      }\n      fclose (in);\n      return 0;\n    }\n    ]])],\n         [am_cv_func_working_getline=yes],\n         [am_cv_func_working_getline=no],\n         [dnl We're cross compiling.\n          dnl Guess it works on glibc2 systems and musl systems.\n          AC_EGREP_CPP([Lucky GNU user],\n            [\n#include <features.h>\n#ifdef __GNU_LIBRARY__\n #if (__GLIBC__ >= 2) && !defined __UCLIBC__\n  Lucky GNU user\n #endif\n#endif\n            ],\n            [am_cv_func_working_getline=\"guessing yes\"],\n            [case \"$host_os\" in\n               *-musl*) am_cv_func_working_getline=\"guessing yes\" ;;\n               *)       am_cv_func_working_getline=\"$gl_cross_guess_normal\" ;;\n             esac\n            ])\n         ])\n      ])\n  fi\n\n  if test $ac_cv_have_decl_getline = no; then\n    HAVE_DECL_GETLINE=0\n  fi\n\n  case \"$am_cv_func_working_getline\" in\n    *yes) ;;\n    *)\n      dnl Set REPLACE_GETLINE always: Even if we have not found the broken\n      dnl getline function among $LIBS, it may exist in libinet and the\n      dnl executable may be linked with -linet.\n      REPLACE_GETLINE=1\n      ;;\n  esac\n])\n\n# Prerequisites of lib/getline.c.\nAC_DEFUN([gl_PREREQ_GETLINE],\n[\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/gettimeofday.m4",
    "content": "# serial 29\n\n# Copyright (C) 2001-2003, 2005, 2007, 2009-2021 Free Software Foundation, Inc.\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\ndnl From Jim Meyering.\n\nAC_DEFUN([gl_FUNC_GETTIMEOFDAY],\n[\n  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])\n  AC_REQUIRE([AC_C_RESTRICT])\n  AC_REQUIRE([AC_CANONICAL_HOST])\n  AC_REQUIRE([gl_SYS_TIME_H])\n  AC_CHECK_FUNCS_ONCE([gettimeofday])\n\n  gl_gettimeofday_timezone=void\n  if test $ac_cv_func_gettimeofday != yes; then\n    HAVE_GETTIMEOFDAY=0\n  else\n    AC_CACHE_CHECK([for gettimeofday with POSIX signature],\n      [gl_cv_func_gettimeofday_posix_signature],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[#include <sys/time.h>\n              struct timeval c;\n              int gettimeofday (struct timeval *restrict, void *restrict);\n            ]],\n            [[/* glibc uses struct timezone * rather than the POSIX void *\n                 if _GNU_SOURCE is defined.  However, since the only portable\n                 use of gettimeofday uses NULL as the second parameter, and\n                 since the glibc definition is actually more typesafe, it is\n                 not worth wrapping this to get a compliant signature.  */\n              int (*f) (struct timeval *restrict, void *restrict)\n                = gettimeofday;\n              int x = f (&c, 0);\n              return !(x | c.tv_sec | c.tv_usec);\n            ]])],\n          [gl_cv_func_gettimeofday_posix_signature=yes],\n          [AC_COMPILE_IFELSE(\n            [AC_LANG_PROGRAM(\n              [[#include <sys/time.h>\nint gettimeofday (struct timeval *restrict, struct timezone *restrict);\n              ]])],\n            [gl_cv_func_gettimeofday_posix_signature=almost],\n            [gl_cv_func_gettimeofday_posix_signature=no])])])\n    if test $gl_cv_func_gettimeofday_posix_signature = almost; then\n      gl_gettimeofday_timezone='struct timezone'\n    elif test $gl_cv_func_gettimeofday_posix_signature != yes; then\n      REPLACE_GETTIMEOFDAY=1\n    fi\n    dnl If we override 'struct timeval', we also have to override gettimeofday.\n    if test $REPLACE_STRUCT_TIMEVAL = 1; then\n      REPLACE_GETTIMEOFDAY=1\n    fi\n    dnl On mingw, the original gettimeofday has only a precision of 15.6\n    dnl milliseconds. So override it.\n    case \"$host_os\" in\n      mingw*) REPLACE_GETTIMEOFDAY=1 ;;\n    esac\n  fi\n  AC_DEFINE_UNQUOTED([GETTIMEOFDAY_TIMEZONE], [$gl_gettimeofday_timezone],\n    [Define this to 'void' or 'struct timezone' to match the system's\n     declaration of the second argument to gettimeofday.])\n])\n\n# Prerequisites of lib/gettimeofday.c.\nAC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [:])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/gnulib-common.m4",
    "content": "# gnulib-common.m4 serial 67\ndnl Copyright (C) 2007-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_PREREQ([2.62])\n\n# gl_COMMON\n# is expanded unconditionally through gnulib-tool magic.\nAC_DEFUN([gl_COMMON], [\n  dnl Use AC_REQUIRE here, so that the code is expanded once only.\n  AC_REQUIRE([gl_00GNULIB])\n  AC_REQUIRE([gl_COMMON_BODY])\n  AC_REQUIRE([gl_ZZGNULIB])\n])\nAC_DEFUN([gl_COMMON_BODY], [\n  AH_VERBATIM([_GL_GNUC_PREREQ],\n[/* True if the compiler says it groks GNU C version MAJOR.MINOR.  */\n#if defined __GNUC__ && defined __GNUC_MINOR__\n# define _GL_GNUC_PREREQ(major, minor) \\\n    ((major) < __GNUC__ + ((minor) <= __GNUC_MINOR__))\n#else\n# define _GL_GNUC_PREREQ(major, minor) 0\n#endif\n])\n  AH_VERBATIM([_Noreturn],\n[/* The _Noreturn keyword of C11.  */\n#ifndef _Noreturn\n# if (defined __cplusplus \\\n      && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \\\n          || (defined _MSC_VER && 1900 <= _MSC_VER)) \\\n      && 0)\n    /* [[noreturn]] is not practically usable, because with it the syntax\n         extern _Noreturn void func (...);\n       would not be valid; such a declaration would only be valid with 'extern'\n       and '_Noreturn' swapped, or without the 'extern' keyword.  However, some\n       AIX system header files and several gnulib header files use precisely\n       this syntax with 'extern'.  */\n#  define _Noreturn [[noreturn]]\n# elif ((!defined __cplusplus || defined __clang__) \\\n        && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \\\n            || (!defined __STRICT_ANSI__ \\\n                && (_GL_GNUC_PREREQ (4, 7) \\\n                    || (defined __apple_build_version__ \\\n                        ? 6000000 <= __apple_build_version__ \\\n                        : 3 < __clang_major__ + (5 <= __clang_minor__))))))\n   /* _Noreturn works as-is.  */\n# elif _GL_GNUC_PREREQ (2, 8) || defined __clang__ || 0x5110 <= __SUNPRO_C\n#  define _Noreturn __attribute__ ((__noreturn__))\n# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)\n#  define _Noreturn __declspec (noreturn)\n# else\n#  define _Noreturn\n# endif\n#endif\n])\n  AH_VERBATIM([isoc99_inline],\n[/* Work around a bug in Apple GCC 4.0.1 build 5465: In C99 mode, it supports\n   the ISO C 99 semantics of 'extern inline' (unlike the GNU C semantics of\n   earlier versions), but does not display it by setting __GNUC_STDC_INLINE__.\n   __APPLE__ && __MACH__ test for Mac OS X.\n   __APPLE_CC__ tests for the Apple compiler and its version.\n   __STDC_VERSION__ tests for the C99 mode.  */\n#if defined __APPLE__ && defined __MACH__ && __APPLE_CC__ >= 5465 && !defined __cplusplus && __STDC_VERSION__ >= 199901L && !defined __GNUC_STDC_INLINE__\n# define __GNUC_STDC_INLINE__ 1\n#endif])\n  AH_VERBATIM([attribute],\n[/* Attributes.  */\n#if (defined __has_attribute \\\n     && (!defined __clang_minor__ \\\n         || 3 < __clang_major__ + (5 <= __clang_minor__)))\n# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__)\n#else\n# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr\n# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2)\n# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_cold _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_const _GL_GNUC_PREREQ (2, 95)\n# define _GL_ATTR_deprecated _GL_GNUC_PREREQ (3, 1)\n# define _GL_ATTR_diagnose_if 0\n# define _GL_ATTR_error _GL_GNUC_PREREQ (4, 3)\n# define _GL_ATTR_externally_visible _GL_GNUC_PREREQ (4, 1)\n# define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0)\n# define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6)\n# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)\n# ifdef _ICC\n#  define _GL_ATTR_may_alias 0\n# else\n#  define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3)\n# endif\n# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)\n# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)\n# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)\n# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3)\n# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96)\n# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9)\n# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0)\n# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7)\n# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)\n#endif\n\n#ifdef __has_c_attribute\n# define _GL_HAS_C_ATTRIBUTE(attr) __has_c_attribute (__##attr##__)\n#else\n# define _GL_HAS_C_ATTRIBUTE(attr) 0\n#endif\n\n]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's _Alignas instead.\n[\n/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function\n   is the size of the returned memory block.\n   _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied\n   by the Nth argument of the function is the size of the returned memory block.\n */\n/* Applies to: function, pointer to function, function types.  */\n#if _GL_HAS_ATTRIBUTE (alloc_size)\n# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))\n#else\n# define _GL_ATTRIBUTE_ALLOC_SIZE(args)\n#endif\n\n/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the\n   function and report an error if it cannot do so.  */\n/* Applies to: function.  */\n#if _GL_HAS_ATTRIBUTE (always_inline)\n# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__))\n#else\n# define _GL_ATTRIBUTE_ALWAYS_INLINE\n#endif\n\n/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show\n    in stack traces when debugging.  The compiler should omit the function from\n    stack traces.  */\n/* Applies to: function.  */\n#if _GL_HAS_ATTRIBUTE (artificial)\n# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__))\n#else\n# define _GL_ATTRIBUTE_ARTIFICIAL\n#endif\n\n/* _GL_ATTRIBUTE_COLD declares that the function is rarely executed.  */\n/* Applies to: functions.  */\n/* Avoid __attribute__ ((cold)) on MinGW; see thread starting at\n   <https://lists.gnu.org/r/emacs-devel/2019-04/msg01152.html>.\n   Also, Oracle Studio 12.6 requires 'cold' not '__cold__'.  */\n#if _GL_HAS_ATTRIBUTE (cold) && !defined __MINGW32__\n# ifndef __SUNPRO_C\n#  define _GL_ATTRIBUTE_COLD __attribute__ ((__cold__))\n# else\n#  define _GL_ATTRIBUTE_COLD __attribute__ ((cold))\n# endif\n#else\n# define _GL_ATTRIBUTE_COLD\n#endif\n\n/* _GL_ATTRIBUTE_CONST declares that it is OK for a compiler to omit duplicate\n   calls to the function with the same arguments.\n   This attribute is safe for a function that neither depends on nor affects\n   observable state, and always returns exactly once - e.g., does not loop\n   forever, and does not call longjmp.\n   (This attribute is stricter than _GL_ATTRIBUTE_PURE.)  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (const)\n# define _GL_ATTRIBUTE_CONST __attribute__ ((__const__))\n#else\n# define _GL_ATTRIBUTE_CONST\n#endif\n\n/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers\n   that can be freed by passing them as the Ith argument to the\n   function F.\n   _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that\n   can be freed via 'free'; it can be used only after declaring 'free'.  */\n/* Applies to: functions.  Cannot be used on inline functions.  */\n#if _GL_GNUC_PREREQ (11, 0)\n# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))\n#else\n# define _GL_ATTRIBUTE_DEALLOC(f, i)\n#endif\n#define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)\n\n/* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated.\n   The compiler may warn if the entity is used.  */\n/* Applies to:\n     - function, variable,\n     - struct, union, struct/union member,\n     - enumeration, enumeration item,\n     - typedef,\n   in C++ also: namespace, class, template specialization.  */\n#if _GL_HAS_C_ATTRIBUTE (deprecated)\n# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]\n#elif _GL_HAS_ATTRIBUTE (deprecated)\n# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))\n#else\n# define _GL_ATTRIBUTE_DEPRECATED\n#endif\n\n/* _GL_ATTRIBUTE_ERROR(msg) requests an error if a function is called and\n   the function call is not optimized away.\n   _GL_ATTRIBUTE_WARNING(msg) requests a warning if a function is called and\n   the function call is not optimized away.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (error)\n# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg)))\n# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg)))\n#elif _GL_HAS_ATTRIBUTE (diagnose_if)\n# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__diagnose_if__ (1, msg, \"error\")))\n# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__diagnose_if__ (1, msg, \"warning\")))\n#else\n# define _GL_ATTRIBUTE_ERROR(msg)\n# define _GL_ATTRIBUTE_WARNING(msg)\n#endif\n\n/* _GL_ATTRIBUTE_EXTERNALLY_VISIBLE declares that the entity should remain\n   visible to debuggers etc., even with '-fwhole-program'.  */\n/* Applies to: functions, variables.  */\n#if _GL_HAS_ATTRIBUTE (externally_visible)\n# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE __attribute__ ((externally_visible))\n#else\n# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE\n#endif\n\n/* _GL_ATTRIBUTE_FALLTHROUGH declares that it is not a programming mistake if\n   the control flow falls through to the immediately following 'case' or\n   'default' label.  The compiler should not warn in this case.  */\n/* Applies to: Empty statement (;), inside a 'switch' statement.  */\n/* Always expands to something.  */\n#if _GL_HAS_C_ATTRIBUTE (fallthrough)\n# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]]\n#elif _GL_HAS_ATTRIBUTE (fallthrough)\n# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))\n#else\n# define _GL_ATTRIBUTE_FALLTHROUGH ((void) 0)\n#endif\n\n/* _GL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK))\n   declares that the STRING-INDEXth function argument is a format string of\n   style ARCHETYPE, which is one of:\n     printf, gnu_printf\n     scanf, gnu_scanf,\n     strftime, gnu_strftime,\n     strfmon,\n   or the same thing prefixed and suffixed with '__'.\n   If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK\n   are suitable for the format string.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (format)\n# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))\n#else\n# define _GL_ATTRIBUTE_FORMAT(spec)\n#endif\n\n/* _GL_ATTRIBUTE_LEAF declares that if the function is called from some other\n   compilation unit, it executes code from that unit only by return or by\n   exception handling.  This declaration lets the compiler optimize that unit\n   more aggressively.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (leaf)\n# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__))\n#else\n# define _GL_ATTRIBUTE_LEAF\n#endif\n\n/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly\n   allocated memory.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (malloc)\n# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))\n#else\n# define _GL_ATTRIBUTE_MALLOC\n#endif\n\n/* _GL_ATTRIBUTE_MAY_ALIAS declares that pointers to the type may point to the\n   same storage as pointers to other types.  Thus this declaration disables\n   strict aliasing optimization.  */\n/* Applies to: types.  */\n/* Oracle Studio 12.6 mishandles may_alias despite __has_attribute OK.  */\n#if _GL_HAS_ATTRIBUTE (may_alias) && !defined __SUNPRO_C\n# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__))\n#else\n# define _GL_ATTRIBUTE_MAY_ALIAS\n#endif\n\n/* _GL_ATTRIBUTE_MAYBE_UNUSED declares that it is not a programming mistake if\n   the entity is not used.  The compiler should not warn if the entity is not\n   used.  */\n/* Applies to:\n     - function, variable,\n     - struct, union, struct/union member,\n     - enumeration, enumeration item,\n     - typedef,\n   in C++ also: class.  */\n/* In C++ and C2x, this is spelled [[__maybe_unused__]].\n   GCC's syntax is __attribute__ ((__unused__)).\n   clang supports both syntaxes.  */\n#if _GL_HAS_C_ATTRIBUTE (maybe_unused)\n# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]\n#else\n# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED\n#endif\n/* Alternative spelling of this macro, for convenience.  */\n#define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED\n/* Earlier spellings of this macro.  */\n#define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED\n\n/* _GL_ATTRIBUTE_NODISCARD declares that the caller of the function should not\n   discard the return value.  The compiler may warn if the caller does not use\n   the return value, unless the caller uses something like ignore_value.  */\n/* Applies to: function, enumeration, class.  */\n#if _GL_HAS_C_ATTRIBUTE (nodiscard)\n# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]\n#elif _GL_HAS_ATTRIBUTE (warn_unused_result)\n# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__))\n#else\n# define _GL_ATTRIBUTE_NODISCARD\n#endif\n\n/* _GL_ATTRIBUTE_NOINLINE tells that the compiler should not inline the\n   function.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (noinline)\n# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__))\n#else\n# define _GL_ATTRIBUTE_NOINLINE\n#endif\n\n/* _GL_ATTRIBUTE_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,...\n   must not be NULL.\n   _GL_ATTRIBUTE_NONNULL () declares that all pointer arguments must not be\n   null.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (nonnull)\n# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args))\n#else\n# define _GL_ATTRIBUTE_NONNULL(args)\n#endif\n\n/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is\n   not meant to be NUL-terminated.  */\n/* Applies to: struct/union members and variables that are arrays of element\n   type '[[un]signed] char'.  */\n#if _GL_HAS_ATTRIBUTE (nonstring)\n# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))\n#else\n# define _GL_ATTRIBUTE_NONSTRING\n#endif\n\n/* There is no _GL_ATTRIBUTE_NORETURN; use _Noreturn instead.  */\n\n/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.\n */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (nothrow) && !defined __cplusplus\n# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))\n#else\n# define _GL_ATTRIBUTE_NOTHROW\n#endif\n\n/* _GL_ATTRIBUTE_PACKED declares:\n   For struct members: The member has the smallest possible alignment.\n   For struct, union, class: All members have the smallest possible alignment,\n   minimizing the memory required.  */\n/* Applies to: struct members, struct, union,\n   in C++ also: class.  */\n#if _GL_HAS_ATTRIBUTE (packed)\n# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))\n#else\n# define _GL_ATTRIBUTE_PACKED\n#endif\n\n/* _GL_ATTRIBUTE_PURE declares that It is OK for a compiler to omit duplicate\n   calls to the function with the same arguments if observable state is not\n   changed between calls.\n   This attribute is safe for a function that does not affect\n   observable state, and always returns exactly once.\n   (This attribute is looser than _GL_ATTRIBUTE_CONST.)  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (pure)\n# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))\n#else\n# define _GL_ATTRIBUTE_PURE\n#endif\n\n/* _GL_ATTRIBUTE_RETURNS_NONNULL declares that the function's return value is\n   a non-NULL pointer.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (returns_nonnull)\n# define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))\n#else\n# define _GL_ATTRIBUTE_RETURNS_NONNULL\n#endif\n\n/* _GL_ATTRIBUTE_SENTINEL(pos) declares that the variadic function expects a\n   trailing NULL argument.\n   _GL_ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99).\n   _GL_ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL.  */\n/* Applies to: functions.  */\n#if _GL_HAS_ATTRIBUTE (sentinel)\n# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos))\n#else\n# define _GL_ATTRIBUTE_SENTINEL(pos)\n#endif\n\n/* A helper macro.  Don't use it directly.  */\n#if _GL_HAS_ATTRIBUTE (unused)\n# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__))\n#else\n# define _GL_ATTRIBUTE_UNUSED\n#endif\n\n]dnl There is no _GL_ATTRIBUTE_VISIBILITY; see m4/visibility.m4 instead.\n[\n/* _GL_UNUSED_LABEL; declares that it is not a programming mistake if the\n   immediately preceding label is not used.  The compiler should not warn\n   if the label is not used.  */\n/* Applies to: label (both in C and C++).  */\n/* Note that g++ < 4.5 does not support the '__attribute__ ((__unused__)) ;'\n   syntax.  But clang does.  */\n#if !(defined __cplusplus && !_GL_GNUC_PREREQ (4, 5)) || defined __clang__\n# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED\n#else\n# define _GL_UNUSED_LABEL\n#endif\n])\n  AH_VERBATIM([async_safe],\n[/* The _GL_ASYNC_SAFE marker should be attached to functions that are\n   signal handlers (for signals other than SIGABRT, SIGPIPE) or can be\n   invoked from such signal handlers.  Such functions have some restrictions:\n     * All functions that it calls should be marked _GL_ASYNC_SAFE as well,\n       or should be listed as async-signal-safe in POSIX\n       <https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04>\n       section 2.4.3.  Note that malloc(), sprintf(), and fwrite(), in\n       particular, are NOT async-signal-safe.\n     * All memory locations (variables and struct fields) that these functions\n       access must be marked 'volatile'.  This holds for both read and write\n       accesses.  Otherwise the compiler might optimize away stores to and\n       reads from such locations that occur in the program, depending on its\n       data flow analysis.  For example, when the program contains a loop\n       that is intended to inspect a variable set from within a signal handler\n           while (!signal_occurred)\n             ;\n       the compiler is allowed to transform this into an endless loop if the\n       variable 'signal_occurred' is not declared 'volatile'.\n   Additionally, recall that:\n     * A signal handler should not modify errno (except if it is a handler\n       for a fatal signal and ends by raising the same signal again, thus\n       provoking the termination of the process).  If it invokes a function\n       that may clobber errno, it needs to save and restore the value of\n       errno.  */\n#define _GL_ASYNC_SAFE\n])\n  AH_VERBATIM([micro_optimizations],\n[/* _GL_CMP (n1, n2) performs a three-valued comparison on n1 vs. n2, where\n   n1 and n2 are expressions without side effects, that evaluate to real\n   numbers (excluding NaN).\n   It returns\n     1  if n1 > n2\n     0  if n1 == n2\n     -1 if n1 < n2\n   The naïve code   (n1 > n2 ? 1 : n1 < n2 ? -1 : 0)  produces a conditional\n   jump with nearly all GCC versions up to GCC 10.\n   This variant     (n1 < n2 ? -1 : n1 > n2)  produces a conditional with many\n   GCC versions up to GCC 9.\n   The better code  (n1 > n2) - (n1 < n2)  from Hacker's Delight § 2-9\n   avoids conditional jumps in all GCC versions >= 3.4.  */\n#define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))\n])\n  dnl Hint which direction to take regarding cross-compilation guesses:\n  dnl When a user installs a program on a platform they are not intimately\n  dnl familiar with, --enable-cross-guesses=conservative is the appropriate\n  dnl choice.  It implements the \"If we don't know, assume the worst\" principle.\n  dnl However, when an operating system developer (on a platform which is not\n  dnl yet known to gnulib) builds packages for their platform, they want to\n  dnl expose, not hide, possible platform bugs; in this case,\n  dnl --enable-cross-guesses=risky is the appropriate choice.\n  dnl Sets the variables\n  dnl gl_cross_guess_normal    (to be used when 'yes' is good and 'no' is bad),\n  dnl gl_cross_guess_inverted  (to be used when 'no' is good and 'yes' is bad).\n  AC_ARG_ENABLE([cross-guesses],\n    [AS_HELP_STRING([--enable-cross-guesses={conservative|risky}],\n       [specify policy for cross-compilation guesses])],\n    [if test \"x$enableval\" != xconservative && test \"x$enableval\" != xrisky; then\n       AC_MSG_WARN([invalid argument supplied to --enable-cross-guesses])\n       enableval=conservative\n     fi\n     gl_cross_guesses=\"$enableval\"],\n    [gl_cross_guesses=conservative])\n  if test $gl_cross_guesses = risky; then\n    gl_cross_guess_normal=\"guessing yes\"\n    gl_cross_guess_inverted=\"guessing no\"\n  else\n    gl_cross_guess_normal=\"guessing no\"\n    gl_cross_guess_inverted=\"guessing yes\"\n  fi\n  dnl Preparation for running test programs:\n  dnl Tell glibc to write diagnostics from -D_FORTIFY_SOURCE=2 to stderr, not\n  dnl to /dev/tty, so they can be redirected to log files.  Such diagnostics\n  dnl arise e.g., in the macros gl_PRINTF_DIRECTIVE_N, gl_SNPRINTF_DIRECTIVE_N.\n  LIBC_FATAL_STDERR_=1\n  export LIBC_FATAL_STDERR_\n])\n\n# gl_MODULE_INDICATOR_INIT_VARIABLE([variablename])\n# gl_MODULE_INDICATOR_INIT_VARIABLE([variablename], [initialvalue])\n# initializes the shell variable that indicates the presence of the given module\n# as a C preprocessor expression.\nAC_DEFUN([gl_MODULE_INDICATOR_INIT_VARIABLE],\n[\n  GL_MODULE_INDICATOR_PREFIX[]_[$1]=m4_if([$2], , [0], [$2])\n  AC_SUBST(GL_MODULE_INDICATOR_PREFIX[]_[$1])\n])\n\n# gl_MODULE_INDICATOR_CONDITION\n# expands to a C preprocessor expression that evaluates to 1 or 0, depending\n# whether a gnulib module that has been requested shall be considered present\n# or not.\nm4_define([gl_MODULE_INDICATOR_CONDITION], [1])\n\n# gl_MODULE_INDICATOR_SET_VARIABLE([modulename])\n# sets the shell variable that indicates the presence of the given module to\n# a C preprocessor expression that will evaluate to 1.\nAC_DEFUN([gl_MODULE_INDICATOR_SET_VARIABLE],\n[\n  gl_MODULE_INDICATOR_SET_VARIABLE_AUX(\n    [GL_MODULE_INDICATOR_PREFIX[]_GNULIB_[]m4_translit([[$1]],\n                                                       [abcdefghijklmnopqrstuvwxyz./-],\n                                                       [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])],\n    [gl_MODULE_INDICATOR_CONDITION])\n])\n\n# gl_MODULE_INDICATOR_SET_VARIABLE_AUX([variable])\n# modifies the shell variable to include the gl_MODULE_INDICATOR_CONDITION.\n# The shell variable's value is a C preprocessor expression that evaluates\n# to 0 or 1.\nAC_DEFUN([gl_MODULE_INDICATOR_SET_VARIABLE_AUX],\n[\n  m4_if(m4_defn([gl_MODULE_INDICATOR_CONDITION]), [1],\n    [\n     dnl Simplify the expression VALUE || 1 to 1.\n     $1=1\n    ],\n    [gl_MODULE_INDICATOR_SET_VARIABLE_AUX_OR([$1],\n                                             [gl_MODULE_INDICATOR_CONDITION])])\n])\n\n# gl_MODULE_INDICATOR_SET_VARIABLE_AUX_OR([variable], [condition])\n# modifies the shell variable to include the given condition.  The shell\n# variable's value is a C preprocessor expression that evaluates to 0 or 1.\nAC_DEFUN([gl_MODULE_INDICATOR_SET_VARIABLE_AUX_OR],\n[\n  dnl Simplify the expression 1 || CONDITION to 1.\n  if test \"$[]$1\" != 1; then\n    dnl Simplify the expression 0 || CONDITION to CONDITION.\n    if test \"$[]$1\" = 0; then\n      $1=$2\n    else\n      $1=\"($[]$1 || $2)\"\n    fi\n  fi\n])\n\n# gl_MODULE_INDICATOR([modulename])\n# defines a C macro indicating the presence of the given module\n# in a location where it can be used.\n#                                             |  Value  |   Value   |\n#                                             | in lib/ | in tests/ |\n# --------------------------------------------+---------+-----------+\n# Module present among main modules:          |    1    |     1     |\n# --------------------------------------------+---------+-----------+\n# Module present among tests-related modules: |    0    |     1     |\n# --------------------------------------------+---------+-----------+\n# Module not present at all:                  |    0    |     0     |\n# --------------------------------------------+---------+-----------+\nAC_DEFUN([gl_MODULE_INDICATOR],\n[\n  AC_DEFINE_UNQUOTED([GNULIB_]m4_translit([[$1]],\n      [abcdefghijklmnopqrstuvwxyz./-],\n      [ABCDEFGHIJKLMNOPQRSTUVWXYZ___]),\n    [gl_MODULE_INDICATOR_CONDITION],\n    [Define to a C preprocessor expression that evaluates to 1 or 0,\n     depending whether the gnulib module $1 shall be considered present.])\n])\n\n# gl_MODULE_INDICATOR_FOR_TESTS([modulename])\n# defines a C macro indicating the presence of the given module\n# in lib or tests. This is useful to determine whether the module\n# should be tested.\n#                                             |  Value  |   Value   |\n#                                             | in lib/ | in tests/ |\n# --------------------------------------------+---------+-----------+\n# Module present among main modules:          |    1    |     1     |\n# --------------------------------------------+---------+-----------+\n# Module present among tests-related modules: |    1    |     1     |\n# --------------------------------------------+---------+-----------+\n# Module not present at all:                  |    0    |     0     |\n# --------------------------------------------+---------+-----------+\nAC_DEFUN([gl_MODULE_INDICATOR_FOR_TESTS],\n[\n  AC_DEFINE([GNULIB_TEST_]m4_translit([[$1]],\n      [abcdefghijklmnopqrstuvwxyz./-],\n      [ABCDEFGHIJKLMNOPQRSTUVWXYZ___]), [1],\n    [Define to 1 when the gnulib module $1 should be tested.])\n])\n\n# gl_ASSERT_NO_GNULIB_POSIXCHECK\n# asserts that there will never be a need to #define GNULIB_POSIXCHECK.\n# and thereby enables an optimization of configure and config.h.\n# Used by Emacs.\nAC_DEFUN([gl_ASSERT_NO_GNULIB_POSIXCHECK],\n[\n  dnl Override gl_WARN_ON_USE_PREPARE.\n  dnl But hide this definition from 'aclocal'.\n  AC_DEFUN([gl_W][ARN_ON_USE_PREPARE], [])\n])\n\n# gl_ASSERT_NO_GNULIB_TESTS\n# asserts that there will be no gnulib tests in the scope of the configure.ac\n# and thereby enables an optimization of config.h.\n# Used by Emacs.\nAC_DEFUN([gl_ASSERT_NO_GNULIB_TESTS],\n[\n  dnl Override gl_MODULE_INDICATOR_FOR_TESTS.\n  AC_DEFUN([gl_MODULE_INDICATOR_FOR_TESTS], [])\n])\n\n# Test whether <features.h> exists.\n# Set HAVE_FEATURES_H.\nAC_DEFUN([gl_FEATURES_H],\n[\n  AC_CHECK_HEADERS_ONCE([features.h])\n  if test $ac_cv_header_features_h = yes; then\n    HAVE_FEATURES_H=1\n  else\n    HAVE_FEATURES_H=0\n  fi\n  AC_SUBST([HAVE_FEATURES_H])\n])\n\n# gl_PROG_CC_C99\n# Modifies the value of the shell variable CC in an attempt to make $CC\n# understand ISO C99 source code.\nAC_DEFUN([gl_PROG_CC_C99],\n[\n  dnl Just use AC_PROG_CC_C99.\n  dnl When AC_PROG_CC_C99 and AC_PROG_CC_STDC are used together, the substituted\n  dnl value of CC will contain the C99 enabling options twice. But this is only\n  dnl a cosmetic problem.\n  dnl With Autoconf >= 2.70, use AC_PROG_CC since it implies AC_PROG_CC_C99;\n  dnl this avoids a \"warning: The macro `AC_PROG_CC_C99' is obsolete.\"\n  m4_version_prereq([2.70],\n    [AC_REQUIRE([AC_PROG_CC])],\n    [AC_REQUIRE([AC_PROG_CC_C99])])\n])\n\n# gl_PROG_AR_RANLIB\n# Determines the values for AR, ARFLAGS, RANLIB that fit with the compiler.\n# The user can set the variables AR, ARFLAGS, RANLIB if he wants to override\n# the values.\nAC_DEFUN([gl_PROG_AR_RANLIB],\n[\n  dnl Minix 3 comes with two toolchains: The Amsterdam Compiler Kit compiler\n  dnl as \"cc\", and GCC as \"gcc\". They have different object file formats and\n  dnl library formats. In particular, the GNU binutils programs ar and ranlib\n  dnl produce libraries that work only with gcc, not with cc.\n  AC_REQUIRE([AC_PROG_CC])\n  dnl The '][' hides this use from 'aclocal'.\n  AC_BEFORE([$0], [A][M_PROG_AR])\n  AC_CACHE_CHECK([for Minix Amsterdam compiler], [gl_cv_c_amsterdam_compiler],\n    [\n      AC_EGREP_CPP([Amsterdam],\n        [\n#ifdef __ACK__\nAmsterdam\n#endif\n        ],\n        [gl_cv_c_amsterdam_compiler=yes],\n        [gl_cv_c_amsterdam_compiler=no])\n    ])\n\n  dnl Don't compete with AM_PROG_AR's decision about AR/ARFLAGS if we are not\n  dnl building with __ACK__.\n  if test $gl_cv_c_amsterdam_compiler = yes; then\n    if test -z \"$AR\"; then\n      AR='cc -c.a'\n    fi\n    if test -z \"$ARFLAGS\"; then\n      ARFLAGS='-o'\n    fi\n  else\n    dnl AM_PROG_AR was added in automake v1.11.2.  AM_PROG_AR does not AC_SUBST\n    dnl ARFLAGS variable (it is filed into Makefile.in directly by automake\n    dnl script on-demand, if not specified by ./configure of course).\n    dnl Don't AC_REQUIRE the AM_PROG_AR otherwise the code for __ACK__ above\n    dnl will be ignored.  Also, pay attention to call AM_PROG_AR in else block\n    dnl because AM_PROG_AR is written so it could re-set AR variable even for\n    dnl __ACK__.  It may seem like its easier to avoid calling the macro here,\n    dnl but we need to AC_SUBST both AR/ARFLAGS (thus those must have some good\n    dnl default value and automake should usually know them).\n    dnl\n    dnl The '][' hides this use from 'aclocal'.\n    m4_ifdef([A][M_PROG_AR], [A][M_PROG_AR], [:])\n  fi\n\n  dnl In case the code above has not helped with setting AR/ARFLAGS, use\n  dnl Automake-documented default values for AR and ARFLAGS, but prefer\n  dnl ${host}-ar over ar (useful for cross-compiling).\n  AC_CHECK_TOOL([AR], [ar], [ar])\n  if test -z \"$ARFLAGS\"; then\n    ARFLAGS='cr'\n  fi\n\n  AC_SUBST([AR])\n  AC_SUBST([ARFLAGS])\n  if test -z \"$RANLIB\"; then\n    if test $gl_cv_c_amsterdam_compiler = yes; then\n      RANLIB=':'\n    else\n      dnl Use the ranlib program if it is available.\n      AC_PROG_RANLIB\n    fi\n  fi\n  AC_SUBST([RANLIB])\n])\n\n# AC_C_RESTRICT\n# This definition is copied from post-2.70 Autoconf and overrides the\n# AC_C_RESTRICT macro from autoconf 2.60..2.70.\nm4_version_prereq([2.70.1], [], [\nAC_DEFUN([AC_C_RESTRICT],\n[AC_CACHE_CHECK([for C/C++ restrict keyword], [ac_cv_c_restrict],\n  [ac_cv_c_restrict=no\n   # Put '__restrict__' first, to avoid problems with glibc and non-GCC; see:\n   # https://lists.gnu.org/archive/html/bug-autoconf/2016-02/msg00006.html\n   # Put 'restrict' last, because C++ lacks it.\n   for ac_kw in __restrict__ __restrict _Restrict restrict; do\n     AC_COMPILE_IFELSE(\n      [AC_LANG_PROGRAM(\n         [[typedef int *int_ptr;\n           int foo (int_ptr $ac_kw ip) { return ip[0]; }\n           int bar (int [$ac_kw]); /* Catch GCC bug 14050.  */\n           int bar (int ip[$ac_kw]) { return ip[0]; }\n         ]],\n         [[int s[1];\n           int *$ac_kw t = s;\n           t[0] = 0;\n           return foo (t) + bar (t);\n         ]])],\n      [ac_cv_c_restrict=$ac_kw])\n     test \"$ac_cv_c_restrict\" != no && break\n   done\n  ])\n AH_VERBATIM([restrict],\n[/* Define to the equivalent of the C99 'restrict' keyword, or to\n   nothing if this is not supported.  Do not define if restrict is\n   supported only directly.  */\n#undef restrict\n/* Work around a bug in older versions of Sun C++, which did not\n   #define __restrict__ or support _Restrict or __restrict__\n   even though the corresponding Sun C compiler ended up with\n   \"#define restrict _Restrict\" or \"#define restrict __restrict__\"\n   in the previous line.  This workaround can be removed once\n   we assume Oracle Developer Studio 12.5 (2016) or later.  */\n#if defined __SUNPRO_CC && !defined __RESTRICT && !defined __restrict__\n# define _Restrict\n# define __restrict__\n#endif])\n case $ac_cv_c_restrict in\n   restrict) ;;\n   no) AC_DEFINE([restrict], []) ;;\n   *)  AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;;\n esac\n])# AC_C_RESTRICT\n])\n\n# gl_BIGENDIAN\n# is like AC_C_BIGENDIAN, except that it can be AC_REQUIREd.\n# Note that AC_REQUIRE([AC_C_BIGENDIAN]) does not work reliably because some\n# macros invoke AC_C_BIGENDIAN with arguments.\nAC_DEFUN([gl_BIGENDIAN],\n[\n  AC_C_BIGENDIAN\n])\n\n# A temporary file descriptor.\n# Must be less than 10, because dash 0.5.8 does not support redirections\n# with multi-digit file descriptors.\nm4_define([GL_TMP_FD], 9)\n\n# gl_SILENT(command)\n# executes command, but without the normal configure output.\n# This is useful when you want to invoke AC_CACHE_CHECK (or AC_CHECK_FUNC etc.)\n# inside another AC_CACHE_CHECK.\nAC_DEFUN([gl_SILENT],\n[\n  exec GL_TMP_FD>&AS_MESSAGE_FD AS_MESSAGE_FD>/dev/null\n  $1\n  exec AS_MESSAGE_FD>&GL_TMP_FD GL_TMP_FD>&-\n])\n\n# gl_CACHE_VAL_SILENT(cache-id, command-to-set-it)\n# is like AC_CACHE_VAL(cache-id, command-to-set-it), except that it does not\n# output a spurious \"(cached)\" mark in the midst of other configure output.\n# This macro should be used instead of AC_CACHE_VAL when it is not surrounded\n# by an AC_MSG_CHECKING/AC_MSG_RESULT pair.\nAC_DEFUN([gl_CACHE_VAL_SILENT],\n[\n  gl_SILENT([\n    AC_CACHE_VAL([$1], [$2])\n  ])\n])\n\n# gl_CC_ALLOW_WARNINGS\n# sets and substitutes a variable GL_CFLAG_ALLOW_WARNINGS, to a $(CC) option\n# that reverts a preceding '-Werror' option, if available.\n# This is expected to be '-Wno-error' on gcc, clang (except clang/MSVC), xlclang\n# and empty otherwise.\nAC_DEFUN([gl_CC_ALLOW_WARNINGS],\n[\n  AC_REQUIRE([AC_PROG_CC])\n  AC_CACHE_CHECK([for C compiler option to allow warnings],\n    [gl_cv_cc_wallow],\n    [rm -f conftest*\n     echo 'int dummy;' > conftest.c\n     AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c 2>conftest1.err]) >/dev/null\n     AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Wno-error -c conftest.c 2>conftest2.err]) >/dev/null\n     dnl Test the number of error output lines, because AIX xlc accepts the\n     dnl option '-Wno-error', just to produce a warning\n     dnl \"Option -Wno-error was incorrectly specified. The option will be ignored.\"\n     dnl afterwards.\n     if test $? = 0 && test `wc -l < conftest1.err` = `wc -l < conftest2.err`; then\n       gl_cv_cc_wallow='-Wno-error'\n     else\n       gl_cv_cc_wallow=none\n     fi\n     rm -f conftest*\n    ])\n  case \"$gl_cv_cc_wallow\" in\n    none) GL_CFLAG_ALLOW_WARNINGS='' ;;\n    *)    GL_CFLAG_ALLOW_WARNINGS=\"$gl_cv_cc_wallow\" ;;\n  esac\n  AC_SUBST([GL_CFLAG_ALLOW_WARNINGS])\n])\n\n# gl_CXX_ALLOW_WARNINGS\n# sets and substitutes a variable GL_CXXFLAG_ALLOW_WARNINGS, to a $(CC) option\n# that reverts a preceding '-Werror' option, if available.\nAC_DEFUN([gl_CXX_ALLOW_WARNINGS],\n[\n  dnl Requires AC_PROG_CXX or gl_PROG_ANSI_CXX.\n  if test -n \"$CXX\" && test \"$CXX\" != no; then\n    AC_CACHE_CHECK([for C++ compiler option to allow warnings],\n      [gl_cv_cxx_wallow],\n      [rm -f conftest*\n       echo 'int dummy;' > conftest.cc\n       AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -c conftest.cc 2>conftest1.err]) >/dev/null\n       AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -Wno-error -c conftest.cc 2>conftest2.err]) >/dev/null\n       dnl Test the number of error output lines, because AIX xlC accepts the\n       dnl option '-Wno-error', just to produce a warning\n       dnl \"Option -Wno-error was incorrectly specified. The option will be ignored.\"\n       dnl afterwards.\n       if test $? = 0 && test `wc -l < conftest1.err` = `wc -l < conftest2.err`; then\n         gl_cv_cxx_wallow='-Wno-error'\n       else\n         gl_cv_cxx_wallow=none\n       fi\n       rm -f conftest*\n      ])\n    case \"$gl_cv_cxx_wallow\" in\n      none) GL_CXXFLAG_ALLOW_WARNINGS='' ;;\n      *)    GL_CXXFLAG_ALLOW_WARNINGS=\"$gl_cv_cxx_wallow\" ;;\n    esac\n  else\n    GL_CXXFLAG_ALLOW_WARNINGS=''\n  fi\n  AC_SUBST([GL_CXXFLAG_ALLOW_WARNINGS])\n])\n\ndnl Expands to some code for use in .c programs that, on native Windows, defines\ndnl the Microsoft deprecated alias function names to the underscore-prefixed\ndnl actual function names. With this macro, these function names are available\ndnl without linking with '-loldnames' and without generating warnings.\ndnl Usage: Use it after all system header files are included.\ndnl          #include <...>\ndnl          #include <...>\ndnl          ]GL_MDA_DEFINES[\ndnl          ...\nAC_DEFUN([GL_MDA_DEFINES],[\nAC_REQUIRE([_GL_MDA_DEFINES])\n[$gl_mda_defines]\n])\nAC_DEFUN([_GL_MDA_DEFINES],\n[gl_mda_defines='\n#if defined _WIN32 && !defined __CYGWIN__\n#define access    _access\n#define chdir     _chdir\n#define chmod     _chmod\n#define close     _close\n#define creat     _creat\n#define dup       _dup\n#define dup2      _dup2\n#define ecvt      _ecvt\n#define execl     _execl\n#define execle    _execle\n#define execlp    _execlp\n#define execv     _execv\n#define execve    _execve\n#define execvp    _execvp\n#define execvpe   _execvpe\n#define fcloseall _fcloseall\n#define fcvt      _fcvt\n#define fdopen    _fdopen\n#define fileno    _fileno\n#define gcvt      _gcvt\n#define getcwd    _getcwd\n#define getpid    _getpid\n#define getw      _getw\n#define isatty    _isatty\n#define j0        _j0\n#define j1        _j1\n#define jn        _jn\n#define lfind     _lfind\n#define lsearch   _lsearch\n#define lseek     _lseek\n#define memccpy   _memccpy\n#define mkdir     _mkdir\n#define mktemp    _mktemp\n#define open      _open\n#define putenv    _putenv\n#define putw      _putw\n#define read      _read\n#define rmdir     _rmdir\n#define strdup    _strdup\n#define swab      _swab\n#define tempnam   _tempnam\n#define tzset     _tzset\n#define umask     _umask\n#define unlink    _unlink\n#define utime     _utime\n#define wcsdup    _wcsdup\n#define write     _write\n#define y0        _y0\n#define y1        _y1\n#define yn        _yn\n#endif\n'\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/include_next.m4",
    "content": "# include_next.m4 serial 26\ndnl Copyright (C) 2006-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Paul Eggert and Derek Price.\n\ndnl Sets INCLUDE_NEXT, INCLUDE_NEXT_AS_FIRST_DIRECTIVE, PRAGMA_SYSTEM_HEADER,\ndnl and PRAGMA_COLUMNS.\ndnl\ndnl INCLUDE_NEXT expands to 'include_next' if the compiler supports it, or to\ndnl 'include' otherwise.\ndnl\ndnl INCLUDE_NEXT_AS_FIRST_DIRECTIVE expands to 'include_next' if the compiler\ndnl supports it in the special case that it is the first include directive in\ndnl the given file, or to 'include' otherwise.\ndnl\ndnl PRAGMA_SYSTEM_HEADER can be used in files that contain #include_next,\ndnl so as to avoid GCC warnings when the gcc option -pedantic is used.\ndnl '#pragma GCC system_header' has the same effect as if the file was found\ndnl through the include search path specified with '-isystem' options (as\ndnl opposed to the search path specified with '-I' options). Namely, gcc\ndnl does not warn about some things, and on some systems (Solaris and Interix)\ndnl __STDC__ evaluates to 0 instead of to 1. The latter is an undesired side\ndnl effect; we are therefore careful to use 'defined __STDC__' or '1' instead\ndnl of plain '__STDC__'.\ndnl\ndnl PRAGMA_COLUMNS can be used in files that override system header files, so\ndnl as to avoid compilation errors on HP NonStop systems when the gnulib file\ndnl is included by a system header file that does a \"#pragma COLUMNS 80\" (which\ndnl has the effect of truncating the lines of that file and all files that it\ndnl includes to 80 columns) and the gnulib file has lines longer than 80\ndnl columns.\n\nAC_DEFUN([gl_INCLUDE_NEXT],\n[\n  AC_LANG_PREPROC_REQUIRE()\n  AC_CACHE_CHECK([whether the preprocessor supports include_next],\n    [gl_cv_have_include_next],\n    [rm -rf conftestd1a conftestd1b conftestd2\n     mkdir conftestd1a conftestd1b conftestd2\n     dnl IBM C 9.0, 10.1 (original versions, prior to the 2009-01 updates) on\n     dnl AIX 6.1 support include_next when used as first preprocessor directive\n     dnl in a file, but not when preceded by another include directive. Check\n     dnl for this bug by including <stdio.h>.\n     dnl Additionally, with this same compiler, include_next is a no-op when\n     dnl used in a header file that was included by specifying its absolute\n     dnl file name. Despite these two bugs, include_next is used in the\n     dnl compiler's <math.h>. By virtue of the second bug, we need to use\n     dnl include_next as well in this case.\n     cat <<EOF > conftestd1a/conftest.h\n#define DEFINED_IN_CONFTESTD1\n#include_next <conftest.h>\n#ifdef DEFINED_IN_CONFTESTD2\nint foo;\n#else\n#error \"include_next doesn't work\"\n#endif\nEOF\n     cat <<EOF > conftestd1b/conftest.h\n#define DEFINED_IN_CONFTESTD1\n#include <stdio.h>\n#include_next <conftest.h>\n#ifdef DEFINED_IN_CONFTESTD2\nint foo;\n#else\n#error \"include_next doesn't work\"\n#endif\nEOF\n     cat <<EOF > conftestd2/conftest.h\n#ifndef DEFINED_IN_CONFTESTD1\n#error \"include_next test doesn't work\"\n#endif\n#define DEFINED_IN_CONFTESTD2\nEOF\n     gl_save_CPPFLAGS=\"$CPPFLAGS\"\n     CPPFLAGS=\"$gl_save_CPPFLAGS -Iconftestd1b -Iconftestd2\"\ndnl We intentionally avoid using AC_LANG_SOURCE here.\n     AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]],\n       [gl_cv_have_include_next=yes],\n       [CPPFLAGS=\"$gl_save_CPPFLAGS -Iconftestd1a -Iconftestd2\"\n        AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]],\n          [gl_cv_have_include_next=buggy],\n          [gl_cv_have_include_next=no])\n       ])\n     CPPFLAGS=\"$gl_save_CPPFLAGS\"\n     rm -rf conftestd1a conftestd1b conftestd2\n    ])\n  PRAGMA_SYSTEM_HEADER=\n  if test $gl_cv_have_include_next = yes; then\n    INCLUDE_NEXT=include_next\n    INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include_next\n    if test -n \"$GCC\"; then\n      PRAGMA_SYSTEM_HEADER='#pragma GCC system_header'\n    fi\n  else\n    if test $gl_cv_have_include_next = buggy; then\n      INCLUDE_NEXT=include\n      INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include_next\n    else\n      INCLUDE_NEXT=include\n      INCLUDE_NEXT_AS_FIRST_DIRECTIVE=include\n    fi\n  fi\n  AC_SUBST([INCLUDE_NEXT])\n  AC_SUBST([INCLUDE_NEXT_AS_FIRST_DIRECTIVE])\n  AC_SUBST([PRAGMA_SYSTEM_HEADER])\n\n  dnl HP NonStop systems, which define __TANDEM, limit the line length\n  dnl after including some system header files.\n  AC_CACHE_CHECK([whether source code line length is unlimited],\n    [gl_cv_source_line_length_unlimited],\n    [AC_EGREP_CPP([choke me],\n       [\n#ifdef __TANDEM\nchoke me\n#endif\n       ],\n       [gl_cv_source_line_length_unlimited=no],\n       [gl_cv_source_line_length_unlimited=yes])\n    ])\n  if test $gl_cv_source_line_length_unlimited = no; then\n    PRAGMA_COLUMNS=\"#pragma COLUMNS 10000\"\n  else\n    PRAGMA_COLUMNS=\n  fi\n  AC_SUBST([PRAGMA_COLUMNS])\n])\n\n# gl_CHECK_NEXT_HEADERS(HEADER1 HEADER2 ...)\n# ------------------------------------------\n# For each arg foo.h, if #include_next works, define NEXT_FOO_H to be\n# '<foo.h>'; otherwise define it to be\n# '\"///usr/include/foo.h\"', or whatever other absolute file name is suitable.\n# Also, if #include_next works as first preprocessing directive in a file,\n# define NEXT_AS_FIRST_DIRECTIVE_FOO_H to be '<foo.h>'; otherwise define it to\n# be\n# '\"///usr/include/foo.h\"', or whatever other absolute file name is suitable.\n# That way, a header file with the following line:\n#       #@INCLUDE_NEXT@ @NEXT_FOO_H@\n# or\n#       #@INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ @NEXT_AS_FIRST_DIRECTIVE_FOO_H@\n# behaves (after sed substitution) as if it contained\n#       #include_next <foo.h>\n# even if the compiler does not support include_next.\n# The three \"///\" are to pacify Sun C 5.8, which otherwise would say\n# \"warning: #include of /usr/include/... may be non-portable\".\n# Use '\"\"', not '<>', so that the /// cannot be confused with a C99 comment.\n# Note: This macro assumes that the header file is not empty after\n# preprocessing, i.e. it does not only define preprocessor macros but also\n# provides some type/enum definitions or function/variable declarations.\n#\n# This macro also checks whether each header exists, by invoking\n# AC_CHECK_HEADERS_ONCE or AC_CHECK_HEADERS on each argument.\nAC_DEFUN([gl_CHECK_NEXT_HEADERS],\n[\n  gl_NEXT_HEADERS_INTERNAL([$1], [check])\n])\n\n# gl_NEXT_HEADERS(HEADER1 HEADER2 ...)\n# ------------------------------------\n# Like gl_CHECK_NEXT_HEADERS, except do not check whether the headers exist.\n# This is suitable for headers like <stddef.h> that are standardized by C89\n# and therefore can be assumed to exist.\nAC_DEFUN([gl_NEXT_HEADERS],\n[\n  gl_NEXT_HEADERS_INTERNAL([$1], [assume])\n])\n\n# The guts of gl_CHECK_NEXT_HEADERS and gl_NEXT_HEADERS.\nAC_DEFUN([gl_NEXT_HEADERS_INTERNAL],\n[\n  AC_REQUIRE([gl_INCLUDE_NEXT])\n  AC_REQUIRE([AC_CANONICAL_HOST])\n\n  m4_if([$2], [check],\n    [AC_CHECK_HEADERS_ONCE([$1])\n    ])\n\n  m4_foreach_w([gl_HEADER_NAME], [$1],\n    [AS_VAR_PUSHDEF([gl_next_header],\n                    [gl_cv_next_]m4_defn([gl_HEADER_NAME]))\n     if test $gl_cv_have_include_next = yes; then\n       AS_VAR_SET([gl_next_header], ['<'gl_HEADER_NAME'>'])\n     else\n       AC_CACHE_CHECK(\n         [absolute name of <]m4_defn([gl_HEADER_NAME])[>],\n         [gl_next_header],\n         [m4_if([$2], [check],\n            [AS_VAR_PUSHDEF([gl_header_exists],\n                            [ac_cv_header_]m4_defn([gl_HEADER_NAME]))\n             if test AS_VAR_GET([gl_header_exists]) = yes; then\n             AS_VAR_POPDEF([gl_header_exists])\n            ])\n           gl_ABSOLUTE_HEADER_ONE(gl_HEADER_NAME)\n           AS_VAR_COPY([gl_header], [gl_cv_absolute_]AS_TR_SH(gl_HEADER_NAME))\n           AS_VAR_SET([gl_next_header], ['\"'$gl_header'\"'])\n          m4_if([$2], [check],\n            [else\n               AS_VAR_SET([gl_next_header], ['<'gl_HEADER_NAME'>'])\n             fi\n            ])\n         ])\n     fi\n     AC_SUBST(\n       AS_TR_CPP([NEXT_]m4_defn([gl_HEADER_NAME])),\n       [AS_VAR_GET([gl_next_header])])\n     if test $gl_cv_have_include_next = yes || test $gl_cv_have_include_next = buggy; then\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include_next'\n       gl_next_as_first_directive='<'gl_HEADER_NAME'>'\n     else\n       # INCLUDE_NEXT_AS_FIRST_DIRECTIVE='include'\n       gl_next_as_first_directive=AS_VAR_GET([gl_next_header])\n     fi\n     AC_SUBST(\n       AS_TR_CPP([NEXT_AS_FIRST_DIRECTIVE_]m4_defn([gl_HEADER_NAME])),\n       [$gl_next_as_first_directive])\n     AS_VAR_POPDEF([gl_next_header])])\n])\n\n# Autoconf 2.68 added warnings for our use of AC_COMPILE_IFELSE;\n# this fallback is safe for all earlier autoconf versions.\nm4_define_default([AC_LANG_DEFINES_PROVIDED])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/limits-h.m4",
    "content": "dnl Check whether limits.h has needed features.\n\ndnl Copyright 2016-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Paul Eggert.\n\nAC_DEFUN_ONCE([gl_LIMITS_H],\n[\n  gl_CHECK_NEXT_HEADERS([limits.h])\n\n  AC_CACHE_CHECK([whether limits.h has WORD_BIT, BOOL_WIDTH etc.],\n    [gl_cv_header_limits_width],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n             #define __STDC_WANT_IEC_60559_BFP_EXT__ 1\n            #endif\n            #include <limits.h>\n            long long llm = LLONG_MAX;\n            int wb = WORD_BIT;\n            int ullw = ULLONG_WIDTH;\n            int bw = BOOL_WIDTH;\n          ]])],\n       [gl_cv_header_limits_width=yes],\n       [gl_cv_header_limits_width=no])])\n  if test \"$gl_cv_header_limits_width\" = yes; then\n    LIMITS_H=\n  else\n    LIMITS_H=limits.h\n  fi\n  AC_SUBST([LIMITS_H])\n  AM_CONDITIONAL([GL_GENERATE_LIMITS_H], [test -n \"$LIMITS_H\"])\n])\n\ndnl Unconditionally enables the replacement of <limits.h>.\nAC_DEFUN([gl_REPLACE_LIMITS_H],\n[\n  AC_REQUIRE([gl_LIMITS_H])\n  LIMITS_H='limits.h'\n  AM_CONDITIONAL([GL_GENERATE_LIMITS_H], [test -n \"$LIMITS_H\"])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/msvc-inval.m4",
    "content": "# msvc-inval.m4 serial 1\ndnl Copyright (C) 2011-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_MSVC_INVAL],\n[\n  AC_CHECK_FUNCS_ONCE([_set_invalid_parameter_handler])\n  if test $ac_cv_func__set_invalid_parameter_handler = yes; then\n    HAVE_MSVC_INVALID_PARAMETER_HANDLER=1\n    AC_DEFINE([HAVE_MSVC_INVALID_PARAMETER_HANDLER], [1],\n      [Define to 1 on MSVC platforms that have the \"invalid parameter handler\"\n       concept.])\n  else\n    HAVE_MSVC_INVALID_PARAMETER_HANDLER=0\n  fi\n  AC_SUBST([HAVE_MSVC_INVALID_PARAMETER_HANDLER])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/msvc-nothrow.m4",
    "content": "# msvc-nothrow.m4 serial 1\ndnl Copyright (C) 2011-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_MSVC_NOTHROW],\n[\n  AC_REQUIRE([gl_MSVC_INVAL])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/multiarch.m4",
    "content": "# multiarch.m4 serial 9\ndnl Copyright (C) 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\n# Determine whether the compiler is or may be producing universal binaries.\n#\n# On Mac OS X 10.5 and later systems, the user can create libraries and\n# executables that work on multiple system types--known as \"fat\" or\n# \"universal\" binaries--by specifying multiple '-arch' options to the\n# compiler but only a single '-arch' option to the preprocessor.  Like\n# this:\n#\n#     ./configure CC=\"gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64\" \\\n#                 CXX=\"g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64\" \\\n#                 CPP=\"gcc -E\" CXXCPP=\"g++ -E\"\n#\n# Detect this situation and set APPLE_UNIVERSAL_BUILD accordingly.\n\nAC_DEFUN_ONCE([gl_MULTIARCH],\n[\n  dnl Code similar to autoconf-2.63 AC_C_BIGENDIAN.\n  AC_CACHE_CHECK([whether the compiler produces multi-arch binaries],\n    [gl_cv_c_multiarch],\n    [gl_cv_c_multiarch=no\n     AC_COMPILE_IFELSE(\n       [AC_LANG_SOURCE(\n         [[#ifndef __APPLE_CC__\n            not a universal capable compiler\n           #endif\n           typedef int dummy;\n         ]])],\n       [\n        dnl Check for potential -arch flags.  It is not universal unless\n        dnl there are at least two -arch flags with different values.\n        arch=\n        prev=\n        for word in ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}; do\n          if test -n \"$prev\"; then\n            case $word in\n              i?86 | x86_64 | ppc | ppc64 | arm | arm64)\n                if test -z \"$arch\" || test \"$arch\" = \"$word\"; then\n                  arch=\"$word\"\n                else\n                  gl_cv_c_multiarch=yes\n                fi\n                ;;\n            esac\n            prev=\n          else\n            if test \"x$word\" = \"x-arch\"; then\n              prev=arch\n            fi\n          fi\n        done\n       ])\n    ])\n  if test $gl_cv_c_multiarch = yes; then\n    APPLE_UNIVERSAL_BUILD=1\n  else\n    APPLE_UNIVERSAL_BUILD=0\n  fi\n  AC_SUBST([APPLE_UNIVERSAL_BUILD])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/off_t.m4",
    "content": "# off_t.m4 serial 1\ndnl Copyright (C) 2012-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl Check whether to override the 'off_t' type.\ndnl Set WINDOWS_64_BIT_OFF_T.\n\nAC_DEFUN([gl_TYPE_OFF_T],\n[\n  m4_ifdef([gl_LARGEFILE], [\n    AC_REQUIRE([gl_LARGEFILE])\n  ], [\n    WINDOWS_64_BIT_OFF_T=0\n  ])\n  AC_SUBST([WINDOWS_64_BIT_OFF_T])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/pid_t.m4",
    "content": "# pid_t.m4 serial 4\ndnl Copyright (C) 2020-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\n# The following implementation works around a problem in autoconf <= 2.69.\nm4_version_prereq([2.70], [], [\n\ndnl Define pid_t if the headers don't define it.\nAC_DEFUN([AC_TYPE_PID_T],\n[\n  AC_CHECK_TYPE([pid_t],\n    [],\n    [dnl On 64-bit native Windows, define it to the equivalent of 'intptr_t'\n     dnl (= 'long long' = '__int64'), because that is the return type\n     dnl of the _spawnv* functions\n     dnl <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/spawnvp-wspawnvp>\n     dnl and the argument type of the _cwait function\n     dnl <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/cwait>.\n     dnl Otherwise (on 32-bit Windows and on old Unix platforms), define it\n     dnl to 'int'.\n     AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM([[\n          #if defined _WIN64 && !defined __CYGWIN__\n          LLP64\n          #endif\n          ]])\n       ],\n       [gl_pid_type='int'],\n       [gl_pid_type='__int64'])\n     AC_DEFINE_UNQUOTED([pid_t], [$gl_pid_type],\n       [Define as a signed integer type capable of holding a process identifier.])\n    ],\n    [AC_INCLUDES_DEFAULT])\n])\n\n])# m4_version_prereq 2.70\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/random.m4",
    "content": "# random.m4 serial 4\ndnl Copyright (C) 2012-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_FUNC_RANDOM],\n[\n  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])\n\n  dnl We can't use AC_CHECK_FUNC here, because random() is defined as a\n  dnl static inline function when compiling for Android 4.4 or older.\n  AC_CACHE_CHECK([for random], [gl_cv_func_random],\n    [AC_LINK_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <stdlib.h>]],\n          [[return random() == 0;]])\n       ],\n       [gl_cv_func_random=yes],\n       [gl_cv_func_random=no])\n    ])\n  if test $gl_cv_func_random = no; then\n    HAVE_RANDOM=0\n    HAVE_INITSTATE=0\n    HAVE_SETSTATE=0\n  else\n    AC_CHECK_FUNCS([initstate setstate])\n    if test $ac_cv_func_initstate = no; then\n      HAVE_INITSTATE=0\n    fi\n    if test $ac_cv_func_setstate = no; then\n      HAVE_SETSTATE=0\n    fi\n    if test $ac_cv_func_initstate = no || test $ac_cv_func_setstate = no; then\n      dnl In order to define initstate or setstate, we need to define all the\n      dnl functions at once.\n      REPLACE_RANDOM=1\n      if test $ac_cv_func_initstate = yes; then\n        REPLACE_INITSTATE=1\n      fi\n      if test $ac_cv_func_setstate = yes; then\n        REPLACE_SETSTATE=1\n      fi\n    fi\n  fi\n\n  AC_CHECK_DECLS_ONCE([initstate])\n  if test $ac_cv_have_decl_initstate = no; then\n    HAVE_DECL_INITSTATE=0\n  fi\n\n  AC_CHECK_DECLS_ONCE([setstate])\n  if test $ac_cv_have_decl_setstate = no; then\n    HAVE_DECL_SETSTATE=0\n  fi\n])\n\n# Prerequisites of lib/random.c.\nAC_DEFUN([gl_PREREQ_RANDOM], [\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/random_r.m4",
    "content": "# serial 5\ndnl Copyright (C) 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_FUNC_RANDOM_R],\n[\n  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])\n  AC_REQUIRE([AC_CANONICAL_HOST])\n\n  AC_CHECK_HEADERS([random.h], [], [], [AC_INCLUDES_DEFAULT])\n  if test $ac_cv_header_random_h = no; then\n    HAVE_RANDOM_H=0\n  fi\n\n  AC_CHECK_TYPES([struct random_data],\n    [], [HAVE_STRUCT_RANDOM_DATA=0],\n    [[#include <stdlib.h>\n      #if HAVE_RANDOM_H\n      # include <random.h>\n      #endif\n    ]])\n\n  dnl On AIX and OSF/1, these functions exist, but with different declarations.\n  dnl Override them all.\n  case \"$host_os\" in\n    aix* | osf*)\n      REPLACE_RANDOM_R=1\n      ;;\n    *)\n      AC_CHECK_FUNCS([random_r])\n      if test $ac_cv_func_random_r = no; then\n        HAVE_RANDOM_R=0\n      fi\n      ;;\n  esac\n])\n\n# Prerequisites of lib/random_r.c.\nAC_DEFUN([gl_PREREQ_RANDOM_R], [\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/socketlib.m4",
    "content": "# socketlib.m4 serial 3\ndnl Copyright (C) 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl gl_SOCKETLIB\ndnl Determines the library to use for socket functions.\ndnl Sets and AC_SUBSTs LIBSOCKET.\n\nAC_DEFUN([gl_SOCKETLIB],\n[\n  gl_PREREQ_SYS_H_WINSOCK2 dnl for HAVE_WINSOCK2_H\n  LIBSOCKET=\n  if test $HAVE_WINSOCK2_H = 1; then\n    dnl Native Windows API (not Cygwin).\n    dnl If the function WSAStartup exists (declared in <winsock2.h> and\n    dnl defined through -lws2_32), we need to call it.\n    AC_CACHE_CHECK([for WSAStartup],\n      [gl_cv_func_wsastartup], [\n       gl_save_LIBS=\"$LIBS\"\n       LIBS=\"$LIBS -lws2_32\"\n       AC_LINK_IFELSE(\n         [AC_LANG_PROGRAM([[\n#ifdef HAVE_WINSOCK2_H\n# include <winsock2.h>\n#endif]], [[\n            WORD wVersionRequested = MAKEWORD(1, 1);\n            WSADATA wsaData;\n            int err = WSAStartup(wVersionRequested, &wsaData);\n            WSACleanup ();\n            ]])\n         ],\n         [gl_cv_func_wsastartup=yes],\n         [gl_cv_func_wsastartup=no])\n       LIBS=\"$gl_save_LIBS\"\n      ])\n    if test \"$gl_cv_func_wsastartup\" = \"yes\"; then\n      AC_DEFINE([WINDOWS_SOCKETS], [1], [Define if WSAStartup is needed.])\n      LIBSOCKET='-lws2_32'\n    fi\n  else\n    dnl Unix API.\n    dnl Solaris has most socket functions in libsocket.\n    dnl Haiku has most socket functions in libnetwork.\n    dnl BeOS has most socket functions in libnet.\n    dnl On HP-UX, do NOT link with libxnet, because in 64-bit mode this would\n    dnl break code (e.g. in libraries) that invokes accept(), getpeername(),\n    dnl getsockname(), getsockopt(), or recvfrom() with a 32-bit addrlen. See\n    dnl \"man xopen_networking\" for details.\n    AC_CACHE_CHECK([for library containing setsockopt], [gl_cv_lib_socket], [\n      gl_cv_lib_socket=\n      AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();]], [[setsockopt();]])],\n        [],\n        [gl_save_LIBS=\"$LIBS\"\n         LIBS=\"$gl_save_LIBS -lsocket\"\n         AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();]], [[setsockopt();]])],\n           [gl_cv_lib_socket=\"-lsocket\"])\n         if test -z \"$gl_cv_lib_socket\"; then\n           LIBS=\"$gl_save_LIBS -lnetwork\"\n           AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();]], [[setsockopt();]])],\n             [gl_cv_lib_socket=\"-lnetwork\"])\n           if test -z \"$gl_cv_lib_socket\"; then\n             LIBS=\"$gl_save_LIBS -lnet\"\n             AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern\n#ifdef __cplusplus\n\"C\"\n#endif\nchar setsockopt();]], [[setsockopt();]])],\n               [gl_cv_lib_socket=\"-lnet\"])\n           fi\n         fi\n         LIBS=\"$gl_save_LIBS\"\n        ])\n      if test -z \"$gl_cv_lib_socket\"; then\n        gl_cv_lib_socket=\"none needed\"\n      fi\n    ])\n    if test \"$gl_cv_lib_socket\" != \"none needed\"; then\n      LIBSOCKET=\"$gl_cv_lib_socket\"\n    fi\n  fi\n  AC_SUBST([LIBSOCKET])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sockets.m4",
    "content": "# sockets.m4 serial 7\ndnl Copyright (C) 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_SOCKETS],\n[\n  AC_REQUIRE([AC_C_INLINE])\n  AC_REQUIRE([gl_SOCKETLIB])\n  gl_PREREQ_SOCKETS\n])\n\n# Prerequisites of lib/sockets.c.\nAC_DEFUN([gl_PREREQ_SOCKETS], [\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/socklen.m4",
    "content": "# socklen.m4 serial 11\ndnl Copyright (C) 2005-2007, 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Albert Chin, Windows fixes from Simon Josefsson.\n\ndnl Check for socklen_t: historically on BSD it is an int, and in\ndnl POSIX 1g it is a type of its own, but some platforms use different\ndnl types for the argument to getsockopt, getpeername, etc.:\ndnl HP-UX 10.20, IRIX 6.5, OSF/1 4.0, Interix 3.5, BeOS.\ndnl So we have to test to find something that will work.\n\nAC_DEFUN([gl_TYPE_SOCKLEN_T],\n  [AC_REQUIRE([gl_CHECK_SOCKET_HEADERS])dnl\n   AC_CHECK_TYPE([socklen_t], ,\n     [AC_CACHE_CHECK([for socklen_t equivalent],\n        [gl_cv_socklen_t_equiv],\n        [# Systems have either \"struct sockaddr *\" or\n         # \"void *\" as the second argument to getpeername\n         gl_cv_socklen_t_equiv=\n         for arg2 in \"struct sockaddr\" void; do\n           for t in int size_t \"unsigned int\" \"long int\" \"unsigned long int\"; do\n             AC_COMPILE_IFELSE([AC_LANG_PROGRAM(\n                 [[#include <sys/types.h>\n                   #include <sys/socket.h>\n\n                   int getpeername (int, $arg2 *, $t *);]],\n                 [[$t len;\n                  getpeername (0, 0, &len);]])],\n               [gl_cv_socklen_t_equiv=\"$t\"])\n             test \"$gl_cv_socklen_t_equiv\" != \"\" && break\n           done\n           test \"$gl_cv_socklen_t_equiv\" != \"\" && break\n         done\n         if test \"$gl_cv_socklen_t_equiv\" = \"\"; then\n           AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])\n         fi\n        ])\n      AC_DEFINE_UNQUOTED([socklen_t], [$gl_cv_socklen_t_equiv],\n        [type to use in place of socklen_t if not defined])],\n     [gl_SOCKET_HEADERS])])\n\ndnl On mingw32, socklen_t is in ws2tcpip.h ('int'), so we try to find\ndnl it there too.  But on Cygwin, wc2tcpip.h must not be included.  Users\ndnl of this module should use the same include pattern as gl_SOCKET_HEADERS.\ndnl When you change this macro, keep also in sync:\ndnl   - gl_CHECK_SOCKET_HEADERS,\ndnl   - the Include section of modules/socklen.\nAC_DEFUN([gl_SOCKET_HEADERS],\n[\n/* <sys/types.h> is not needed according to POSIX, but the\n   <sys/socket.h> in i386-unknown-freebsd4.10 and\n   powerpc-apple-darwin5.5 required it. */\n#include <sys/types.h>\n#if HAVE_SYS_SOCKET_H\n# include <sys/socket.h>\n#elif HAVE_WS2TCPIP_H\n# include <ws2tcpip.h>\n#endif\n])\n\ndnl Tests for the existence of the header for socket facilities.\ndnl Defines the C macros HAVE_SYS_SOCKET_H, HAVE_WS2TCPIP_H.\ndnl This macro must match gl_SOCKET_HEADERS.\nAC_DEFUN([gl_CHECK_SOCKET_HEADERS],\n  [AC_CHECK_HEADERS_ONCE([sys/socket.h])\n   if test $ac_cv_header_sys_socket_h = no; then\n     dnl We cannot use AC_CHECK_HEADERS_ONCE here, because that would make\n     dnl the check for those headers unconditional; yet cygwin reports\n     dnl that the headers are present but cannot be compiled (since on\n     dnl cygwin, all socket information should come from sys/socket.h).\n     AC_CHECK_HEADERS([ws2tcpip.h])\n   fi\n  ])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sockpfaf.m4",
    "content": "# sockpfaf.m4 serial 10\ndnl Copyright (C) 2004, 2006, 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl Test for some common socket protocol families (PF_INET, PF_INET6, ...)\ndnl and some common address families (AF_INET, AF_INET6, ...).\ndnl This test assumes that a system supports an address family if and only if\ndnl it supports the corresponding protocol family.\n\ndnl From Bruno Haible.\n\nAC_DEFUN([gl_SOCKET_FAMILIES],\n[\n  AC_REQUIRE([gl_SYS_SOCKET_H])\n  AC_CHECK_HEADERS_ONCE([netinet/in.h])\n\n  AC_CACHE_CHECK([for IPv4 sockets],\n    [gl_cv_socket_ipv4],\n    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#endif\n#ifdef HAVE_WINSOCK2_H\n#include <winsock2.h>\n#endif]],\n[[int x = AF_INET; struct in_addr y; struct sockaddr_in z;\n if (&x && &y && &z) return 0;]])],\n       gl_cv_socket_ipv4=yes, gl_cv_socket_ipv4=no)])\n  if test $gl_cv_socket_ipv4 = yes; then\n    AC_DEFINE([HAVE_IPV4], [1], [Define to 1 if <sys/socket.h> defines AF_INET.])\n  fi\n\n  AC_CACHE_CHECK([for IPv6 sockets],\n    [gl_cv_socket_ipv6],\n    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#endif\n#ifdef HAVE_WINSOCK2_H\n#include <winsock2.h>\n#endif\n#ifdef HAVE_WS2TCPIP_H\n#include <ws2tcpip.h>\n#endif]],\n[[int x = AF_INET6; struct in6_addr y; struct sockaddr_in6 z;\n if (&x && &y && &z) return 0;]])],\n       gl_cv_socket_ipv6=yes, gl_cv_socket_ipv6=no)])\n  if test $gl_cv_socket_ipv6 = yes; then\n    AC_DEFINE([HAVE_IPV6], [1], [Define to 1 if <sys/socket.h> defines AF_INET6.])\n  fi\n])\n\nAC_DEFUN([gl_SOCKET_FAMILY_UNIX],\n[\n  AC_REQUIRE([gl_SYS_SOCKET_H])\n  AC_CHECK_HEADERS_ONCE([sys/un.h])\n\n  AC_CACHE_CHECK([for UNIX domain sockets],\n    [gl_cv_socket_unix],\n    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_SYS_UN_H\n#include <sys/un.h>\n#endif\n#ifdef HAVE_WINSOCK2_H\n#include <winsock2.h>\n#endif]],\n[[int x = AF_UNIX; struct sockaddr_un y;\n if (&x && &y) return 0;]])],\n       gl_cv_socket_unix=yes, gl_cv_socket_unix=no)])\n  if test $gl_cv_socket_unix = yes; then\n    AC_DEFINE([HAVE_UNIXSOCKET], [1], [Define to 1 if <sys/socket.h> defines AF_UNIX.])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/ssize_t.m4",
    "content": "# ssize_t.m4 serial 5 (gettext-0.18.2)\ndnl Copyright (C) 2001-2003, 2006, 2010-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Bruno Haible.\ndnl Test whether ssize_t is defined.\n\nAC_DEFUN([gt_TYPE_SSIZE_T],\n[\n  AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <sys/types.h>]],\n          [[int x = sizeof (ssize_t *) + sizeof (ssize_t);\n            return !x;]])],\n       [gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])])\n  if test $gt_cv_ssize_t = no; then\n    AC_DEFINE([ssize_t], [int],\n              [Define as a signed type of the same size as size_t.])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/std-gnu11.m4",
    "content": "# Prefer GNU C11 and C++11 to earlier versions.  -*- coding: utf-8 -*-\n\n# This implementation is taken from GNU Autoconf lib/autoconf/c.m4\n# commit 017d5ddd82854911f0119691d91ea8a1438824d6\n# dated Sun Apr 3 13:57:17 2016 -0700\n# This implementation will be obsolete once we can assume Autoconf 2.70\n# or later is installed everywhere a Gnulib program might be developed.\n\nm4_version_prereq([2.70], [], [\n\n\n# Copyright (C) 2001-2021 Free Software Foundation, Inc.\n\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n# Written by David MacKenzie, with help from\n# Akim Demaille, Paul Eggert,\n# François Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor,\n# Roland McGrath, Noah Friedman, david d zuhn, and many others.\n\n\n# AC_PROG_CC([COMPILER ...])\n# --------------------------\n# COMPILER ... is a space separated list of C compilers to search for.\n# This just gives the user an opportunity to specify an alternative\n# search list for the C compiler.\nAC_DEFUN_ONCE([AC_PROG_CC],\n[AC_LANG_PUSH(C)dnl\nAC_ARG_VAR([CC],     [C compiler command])dnl\nAC_ARG_VAR([CFLAGS], [C compiler flags])dnl\n_AC_ARG_VAR_LDFLAGS()dnl\n_AC_ARG_VAR_LIBS()dnl\n_AC_ARG_VAR_CPPFLAGS()dnl\nm4_ifval([$1],\n      [AC_CHECK_TOOLS(CC, [$1])],\n[AC_CHECK_TOOL(CC, gcc)\nif test -z \"$CC\"; then\n  dnl Here we want:\n  dnl\tAC_CHECK_TOOL(CC, cc)\n  dnl but without the check for a tool without the prefix.\n  dnl Until the check is removed from there, copy the code:\n  if test -n \"$ac_tool_prefix\"; then\n    AC_CHECK_PROG(CC, [${ac_tool_prefix}cc], [${ac_tool_prefix}cc])\n  fi\nfi\nif test -z \"$CC\"; then\n  AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc)\nfi\nif test -z \"$CC\"; then\n  AC_CHECK_TOOLS(CC, cl.exe)\nfi\nif test -z \"$CC\"; then\n  AC_CHECK_TOOL(CC, clang)\nfi\n])\n\ntest -z \"$CC\" && AC_MSG_FAILURE([no acceptable C compiler found in \\$PATH])\n\n# Provide some information about the compiler.\n_AS_ECHO_LOG([checking for _AC_LANG compiler version])\nset X $ac_compile\nac_compiler=$[2]\nfor ac_option in --version -v -V -qversion -version; do\n  _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])\ndone\n\nm4_expand_once([_AC_COMPILER_EXEEXT])[]dnl\nm4_expand_once([_AC_COMPILER_OBJEXT])[]dnl\n_AC_LANG_COMPILER_GNU\nif test $ac_compiler_gnu = yes; then\n  GCC=yes\nelse\n  GCC=\nfi\n_AC_PROG_CC_G\ndnl\ndnl Set ac_prog_cc_stdc to the supported C version.\ndnl Also set the documented variable ac_cv_prog_cc_stdc;\ndnl its name was chosen when it was cached, but it is no longer cached.\n_AC_PROG_CC_C11([ac_prog_cc_stdc=c11\n\t\t ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11],\n  [_AC_PROG_CC_C99([ac_prog_cc_stdc=c99\n\t\t    ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99],\n     [_AC_PROG_CC_C89([ac_prog_cc_stdc=c89\n\t\t       ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89],\n\t\t      [ac_prog_cc_stdc=no\n\t\t       ac_cv_prog_cc_stdc=no])])])\ndnl\nAC_LANG_POP(C)dnl\n])# AC_PROG_CC\n\n\n\n# AC_PROG_CXX([LIST-OF-COMPILERS])\n# --------------------------------\n# LIST-OF-COMPILERS is a space separated list of C++ compilers to search\n# for (if not specified, a default list is used).  This just gives the\n# user an opportunity to specify an alternative search list for the C++\n# compiler.\n# aCC\tHP-UX C++ compiler much better than `CC', so test before.\n# FCC   Fujitsu C++ compiler\n# KCC\tKAI C++ compiler\n# RCC\tRational C++\n# xlC_r\tAIX C Set++ (with support for reentrant code)\n# xlC\tAIX C Set++\nAC_DEFUN([AC_PROG_CXX],\n[AC_LANG_PUSH(C++)dnl\nAC_ARG_VAR([CXX],      [C++ compiler command])dnl\nAC_ARG_VAR([CXXFLAGS], [C++ compiler flags])dnl\n_AC_ARG_VAR_LDFLAGS()dnl\n_AC_ARG_VAR_LIBS()dnl\n_AC_ARG_VAR_CPPFLAGS()dnl\n_AC_ARG_VAR_PRECIOUS([CCC])dnl\nif test -z \"$CXX\"; then\n  if test -n \"$CCC\"; then\n    CXX=$CCC\n  else\n    AC_CHECK_TOOLS(CXX,\n\t\t   [m4_default([$1],\n\t\t\t       [g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++])],\n\t\t   g++)\n  fi\nfi\n# Provide some information about the compiler.\n_AS_ECHO_LOG([checking for _AC_LANG compiler version])\nset X $ac_compile\nac_compiler=$[2]\nfor ac_option in --version -v -V -qversion; do\n  _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])\ndone\n\nm4_expand_once([_AC_COMPILER_EXEEXT])[]dnl\nm4_expand_once([_AC_COMPILER_OBJEXT])[]dnl\n_AC_LANG_COMPILER_GNU\nif test $ac_compiler_gnu = yes; then\n  GXX=yes\nelse\n  GXX=\nfi\n_AC_PROG_CXX_G\n_AC_PROG_CXX_CXX11([ac_prog_cxx_stdcxx=cxx11\n\t\t    ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11\n\t\t    ac_cv_prog_cxx_cxx98=$ac_cv_prog_cxx_cxx11],\n   [_AC_PROG_CXX_CXX98([ac_prog_cxx_stdcxx=cxx98\n\t\t        ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98],\n\t\t       [ac_prog_cxx_stdcxx=no\n\t\t        ac_cv_prog_cxx_stdcxx=no])])\nAC_LANG_POP(C++)dnl\n])# AC_PROG_CXX\n\n\n# _AC_C_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,\n#\t\tACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)\n# --------------------------------------------------------------\n# Check whether the C compiler accepts features of STANDARD (e.g `c89', `c99')\n# by trying to compile a program of TEST-PROLOGUE and TEST-BODY.  If this fails,\n# try again with each compiler option in the space-separated OPTION-LIST; if one\n# helps, append it to CC.  If eventually successful, run ACTION-IF-AVAILABLE,\n# else ACTION-IF-UNAVAILABLE.\nAC_DEFUN([_AC_C_STD_TRY],\n[AC_MSG_CHECKING([for $CC option to enable ]m4_translit($1, [c], [C])[ features])\nAC_CACHE_VAL(ac_cv_prog_cc_$1,\n[ac_cv_prog_cc_$1=no\nac_save_CC=$CC\nAC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])\nfor ac_arg in '' $4\ndo\n  CC=\"$ac_save_CC $ac_arg\"\n  _AC_COMPILE_IFELSE([], [ac_cv_prog_cc_$1=$ac_arg])\n  test \"x$ac_cv_prog_cc_$1\" != \"xno\" && break\ndone\nrm -f conftest.$ac_ext\nCC=$ac_save_CC\n])# AC_CACHE_VAL\nac_prog_cc_stdc_options=\ncase \"x$ac_cv_prog_cc_$1\" in\n  x)\n    AC_MSG_RESULT([none needed]) ;;\n  xno)\n    AC_MSG_RESULT([unsupported]) ;;\n  *)\n    ac_prog_cc_stdc_options=\" $ac_cv_prog_cc_$1\"\n    CC=$CC$ac_prog_cc_stdc_options\n    AC_MSG_RESULT([$ac_cv_prog_cc_$1]) ;;\nesac\nAS_IF([test \"x$ac_cv_prog_cc_$1\" != xno], [$5], [$6])\n])# _AC_C_STD_TRY\n\n# _AC_C_C99_TEST_HEADER\n# ---------------------\n# A C header suitable for testing for C99.\nAC_DEFUN([_AC_C_C99_TEST_HEADER],\n[[#include <stdarg.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <wchar.h>\n#include <stdio.h>\n\n// Check varargs macros.  These examples are taken from C99 6.10.3.5.\n#define debug(...) fprintf (stderr, __VA_ARGS__)\n#define showlist(...) puts (#__VA_ARGS__)\n#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))\nstatic void\ntest_varargs_macros (void)\n{\n  int x = 1234;\n  int y = 5678;\n  debug (\"Flag\");\n  debug (\"X = %d\\n\", x);\n  showlist (The first, second, and third items.);\n  report (x>y, \"x is %d but y is %d\", x, y);\n}\n\n// Check long long types.\n#define BIG64 18446744073709551615ull\n#define BIG32 4294967295ul\n#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)\n#if !BIG_OK\n  your preprocessor is broken;\n#endif\n#if BIG_OK\n#else\n  your preprocessor is broken;\n#endif\nstatic long long int bignum = -9223372036854775807LL;\nstatic unsigned long long int ubignum = BIG64;\n\nstruct incomplete_array\n{\n  int datasize;\n  double data[];\n};\n\nstruct named_init {\n  int number;\n  const wchar_t *name;\n  double average;\n};\n\ntypedef const char *ccp;\n\nstatic inline int\ntest_restrict (ccp restrict text)\n{\n  // See if C++-style comments work.\n  // Iterate through items via the restricted pointer.\n  // Also check for declarations in for loops.\n  for (unsigned int i = 0; *(text+i) != '\\0'; ++i)\n    continue;\n  return 0;\n}\n\n// Check varargs and va_copy.\nstatic bool\ntest_varargs (const char *format, ...)\n{\n  va_list args;\n  va_start (args, format);\n  va_list args_copy;\n  va_copy (args_copy, args);\n\n  const char *str = \"\";\n  int number = 0;\n  float fnumber = 0;\n\n  while (*format)\n    {\n      switch (*format++)\n\t{\n\tcase 's': // string\n\t  str = va_arg (args_copy, const char *);\n\t  break;\n\tcase 'd': // int\n\t  number = va_arg (args_copy, int);\n\t  break;\n\tcase 'f': // float\n\t  fnumber = va_arg (args_copy, double);\n\t  break;\n\tdefault:\n\t  break;\n\t}\n    }\n  va_end (args_copy);\n  va_end (args);\n\n  return *str && number && fnumber;\n}]])# _AC_C_C99_TEST_HEADER\n\n# _AC_C_C99_TEST_BODY\n# -------------------\n# A C body suitable for testing for C99, assuming the corresponding header.\nAC_DEFUN([_AC_C_C99_TEST_BODY],\n[[\n  // Check bool.\n  _Bool success = false;\n\n  // Check restrict.\n  if (test_restrict (\"String literal\") == 0)\n    success = true;\n  char *restrict newvar = \"Another string\";\n\n  // Check varargs.\n  success &= test_varargs (\"s, d' f .\", \"string\", 65, 34.234);\n  test_varargs_macros ();\n\n  // Check flexible array members.\n  struct incomplete_array *ia =\n    malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));\n  ia->datasize = 10;\n  for (int i = 0; i < ia->datasize; ++i)\n    ia->data[i] = i * 1.234;\n\n  // Check named initializers.\n  struct named_init ni = {\n    .number = 34,\n    .name = L\"Test wide string\",\n    .average = 543.34343,\n  };\n\n  ni.number = 58;\n\n  int dynamic_array[ni.number];\n  dynamic_array[ni.number - 1] = 543;\n\n  // work around unused variable warnings\n  return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'\n\t  || dynamic_array[ni.number - 1] != 543);\n]])\n\n# _AC_PROG_CC_C99 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])\n# ----------------------------------------------------------------\n# If the C compiler is not in ISO C99 mode by default, try to add an\n# option to output variable CC to make it so.  This macro tries\n# various options that select ISO C99 on some system or another.  It\n# considers the compiler to be in ISO C99 mode if it handles _Bool,\n# // comments, flexible array members, inline, long long int, mixed\n# code and declarations, named initialization of structs, restrict,\n# va_copy, varargs macros, variable declarations in for loops and\n# variable length arrays.\nAC_DEFUN([_AC_PROG_CC_C99],\n[_AC_C_STD_TRY([c99],\n[_AC_C_C99_TEST_HEADER],\n[_AC_C_C99_TEST_BODY],\ndnl Try\ndnl GCC\t\t-std=gnu99 (unused restrictive modes: -std=c99 -std=iso9899:1999)\ndnl IBM XL C\t-qlanglvl=extc1x (V12.1; does not pass C11 test)\ndnl IBM XL C\t-qlanglvl=extc99\ndnl\t\t(pre-V12.1; unused restrictive mode: -qlanglvl=stdc99)\ndnl HP cc\t-AC99\ndnl Intel ICC\t-std=c99, -c99 (deprecated)\ndnl IRIX\t-c99\ndnl Solaris\t-D_STDC_C99=\ndnl\t\tcc's -xc99 option uses linker magic to define the external\ndnl\t\tsymbol __xpg4 as if by \"int __xpg4 = 1;\", which enables C99\ndnl\t\tbehavior for C library functions.  This is not wanted here,\ndnl\t\tbecause it means that a single module compiled with -xc99\ndnl\t\talters C runtime behavior for the entire program, not for\ndnl\t\tjust the module.  Instead, define the (private) symbol\ndnl\t\t_STDC_C99, which suppresses a bogus failure in <stdbool.h>.\ndnl\t\tThe resulting compiler passes the test case here, and that's\ndnl\t\tgood enough.  For more, please see the thread starting at:\ndnl            https://lists.gnu.org/r/autoconf/2010-12/msg00059.html\ndnl Tru64\t-c99\ndnl with extended modes being tried first.\n[[-std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc1x -qlanglvl=extc99]], [$1], [$2])[]dnl\n])# _AC_PROG_CC_C99\n\n\n# _AC_PROG_CC_C11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])\n# ----------------------------------------------------------------\n# If the C compiler is not in ISO C11 mode by default, try to add an\n# option to output variable CC to make it so.  This macro tries\n# various options that select ISO C11 on some system or another.  It\n# considers the compiler to be in ISO C11 mode if it handles _Alignas,\n# _Alignof, _Noreturn, _Static_assert, UTF-8 string literals,\n# duplicate typedefs, and anonymous structures and unions.\nAC_DEFUN([_AC_PROG_CC_C11],\n[_AC_C_STD_TRY([c11],\n[_AC_C_C99_TEST_HEADER[\n// Check _Alignas.\nchar _Alignas (double) aligned_as_double;\nchar _Alignas (0) no_special_alignment;\nextern char aligned_as_int;\nchar _Alignas (0) _Alignas (int) aligned_as_int;\n\n// Check _Alignof.\nenum\n{\n  int_alignment = _Alignof (int),\n  int_array_alignment = _Alignof (int[100]),\n  char_alignment = _Alignof (char)\n};\n_Static_assert (0 < -_Alignof (int), \"_Alignof is signed\");\n\n// Check _Noreturn.\nint _Noreturn does_not_return (void) { for (;;) continue; }\n\n// Check _Static_assert.\nstruct test_static_assert\n{\n  int x;\n  _Static_assert (sizeof (int) <= sizeof (long int),\n                  \"_Static_assert does not work in struct\");\n  long int y;\n};\n\n// Check UTF-8 literals.\n#define u8 syntax error!\nchar const utf8_literal[] = u8\"happens to be ASCII\" \"another string\";\n\n// Check duplicate typedefs.\ntypedef long *long_ptr;\ntypedef long int *long_ptr;\ntypedef long_ptr long_ptr;\n\n// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.\nstruct anonymous\n{\n  union {\n    struct { int i; int j; };\n    struct { int k; long int l; } w;\n  };\n  int m;\n} v1;\n]],\n[_AC_C_C99_TEST_BODY[\n  v1.i = 2;\n  v1.w.k = 5;\n  _Static_assert ((offsetof (struct anonymous, i)\n\t\t   == offsetof (struct anonymous, w.k)),\n\t\t  \"Anonymous union alignment botch\");\n]],\ndnl Try\ndnl GCC\t\t-std=gnu11 (unused restrictive mode: -std=c11)\ndnl with extended modes being tried first.\ndnl\ndnl Do not try -qlanglvl=extc1x, because IBM XL C V12.1 (the latest version as\ndnl of September 2012) does not pass the C11 test.  For now, try extc1x when\ndnl compiling the C99 test instead, since it enables _Static_assert and\ndnl _Noreturn, which is a win.  If -qlanglvl=extc11 or -qlanglvl=extc1x passes\ndnl the C11 test in some future version of IBM XL C, we'll add it here,\ndnl preferably extc11.\n[[-std=gnu11]], [$1], [$2])[]dnl\n])# _AC_PROG_CC_C11\n\n\n# AC_PROG_CC_C89\n# --------------\n# Do not use AU_ALIAS here and in AC_PROG_CC_C99 and AC_PROG_CC_STDC,\n# as that'd be incompatible with how Automake redefines AC_PROG_CC.  See\n# <https://lists.gnu.org/r/autoconf/2012-10/msg00048.html>.\nAU_DEFUN([AC_PROG_CC_C89],\n  [AC_REQUIRE([AC_PROG_CC])],\n  [$0 is obsolete; use AC_PROG_CC]\n)\n\n# AC_PROG_CC_C99\n# --------------\nAU_DEFUN([AC_PROG_CC_C99],\n  [AC_REQUIRE([AC_PROG_CC])],\n  [$0 is obsolete; use AC_PROG_CC]\n)\n\n# AC_PROG_CC_STDC\n# ---------------\nAU_DEFUN([AC_PROG_CC_STDC],\n  [AC_REQUIRE([AC_PROG_CC])],\n  [$0 is obsolete; use AC_PROG_CC]\n)\n\n\n# AC_C_PROTOTYPES\n# ---------------\n# Check if the C compiler supports prototypes, included if it needs\n# options.\nAC_DEFUN([AC_C_PROTOTYPES],\n[AC_REQUIRE([AC_PROG_CC])dnl\nif test \"$ac_prog_cc_stdc\" != no; then\n  AC_DEFINE(PROTOTYPES, 1,\n\t    [Define to 1 if the C compiler supports function prototypes.])\n  AC_DEFINE(__PROTOTYPES, 1,\n\t    [Define like PROTOTYPES; this can be used by system headers.])\nfi\n])# AC_C_PROTOTYPES\n\n\n# _AC_CXX_STD_TRY(STANDARD, TEST-PROLOGUE, TEST-BODY, OPTION-LIST,\n#\t\t  ACTION-IF-AVAILABLE, ACTION-IF-UNAVAILABLE)\n# ----------------------------------------------------------------\n# Check whether the C++ compiler accepts features of STANDARD (e.g\n# `cxx98', `cxx11') by trying to compile a program of TEST-PROLOGUE\n# and TEST-BODY.  If this fails, try again with each compiler option\n# in the space-separated OPTION-LIST; if one helps, append it to CXX.\n# If eventually successful, run ACTION-IF-AVAILABLE, else\n# ACTION-IF-UNAVAILABLE.\nAC_DEFUN([_AC_CXX_STD_TRY],\n[AC_MSG_CHECKING([for $CXX option to enable ]m4_translit(m4_translit($1, [x], [+]), [a-z], [A-Z])[ features])\nAC_LANG_PUSH(C++)dnl\nAC_CACHE_VAL(ac_cv_prog_cxx_$1,\n[ac_cv_prog_cxx_$1=no\nac_save_CXX=$CXX\nAC_LANG_CONFTEST([AC_LANG_PROGRAM([$2], [$3])])\nfor ac_arg in '' $4\ndo\n  CXX=\"$ac_save_CXX $ac_arg\"\n  _AC_COMPILE_IFELSE([], [ac_cv_prog_cxx_$1=$ac_arg])\n  test \"x$ac_cv_prog_cxx_$1\" != \"xno\" && break\ndone\nrm -f conftest.$ac_ext\nCXX=$ac_save_CXX\n])# AC_CACHE_VAL\nac_prog_cxx_stdcxx_options=\ncase \"x$ac_cv_prog_cxx_$1\" in\n  x)\n    AC_MSG_RESULT([none needed]) ;;\n  xno)\n    AC_MSG_RESULT([unsupported]) ;;\n  *)\n    ac_prog_cxx_stdcxx_options=\" $ac_cv_prog_cxx_$1\"\n    CXX=$CXX$ac_prog_cxx_stdcxx_options\n    AC_MSG_RESULT([$ac_cv_prog_cxx_$1]) ;;\nesac\nAC_LANG_POP(C++)dnl\nAS_IF([test \"x$ac_cv_prog_cxx_$1\" != xno], [$5], [$6])\n])# _AC_CXX_STD_TRY\n\n# _AC_CXX_CXX98_TEST_HEADER\n# -------------------------\n# A C++ header suitable for testing for CXX98.\nAC_DEFUN([_AC_CXX_CXX98_TEST_HEADER],\n[[\n#include <algorithm>\n#include <cstdlib>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <list>\n#include <map>\n#include <set>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace test {\n  typedef std::vector<std::string> string_vec;\n  typedef std::pair<int,bool> map_value;\n  typedef std::map<std::string,map_value> map_type;\n  typedef std::set<int> set_type;\n\n  template<typename T>\n  class printer {\n  public:\n    printer(std::ostringstream& os): os(os) {}\n    void operator() (T elem) { os << elem << std::endl; }\n  private:\n    std::ostringstream& os;\n  };\n}\n]])# _AC_CXX_CXX98_TEST_HEADER\n\n# _AC_CXX_CXX98_TEST_BODY\n# -----------------------\n# A C++ body suitable for testing for CXX98, assuming the corresponding header.\nAC_DEFUN([_AC_CXX_CXX98_TEST_BODY],\n[[\n\ntry {\n  // Basic string.\n  std::string teststr(\"ASCII text\");\n  teststr += \" string\";\n\n  // Simple vector.\n  test::string_vec testvec;\n  testvec.push_back(teststr);\n  testvec.push_back(\"foo\");\n  testvec.push_back(\"bar\");\n  if (testvec.size() != 3) {\n    throw std::runtime_error(\"vector size is not 1\");\n  }\n\n  // Dump vector into stringstream and obtain string.\n  std::ostringstream os;\n  for (test::string_vec::const_iterator i = testvec.begin();\n       i != testvec.end(); ++i) {\n    if (i + 1 != testvec.end()) {\n      os << teststr << '\\n';\n    }\n  }\n  // Check algorithms work.\n  std::for_each(testvec.begin(), testvec.end(), test::printer<std::string>(os));\n  std::string os_out = os.str();\n\n  // Test pair and map.\n  test::map_type testmap;\n  testmap.insert(std::make_pair(std::string(\"key\"),\n                                std::make_pair(53,false)));\n\n  // Test set.\n  int values[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};\n  test::set_type testset(values, values + sizeof(values)/sizeof(values[0]));\n  std::list<int> testlist(testset.begin(), testset.end());\n  std::copy(testset.begin(), testset.end(), std::back_inserter(testlist));\n} catch (const std::exception& e) {\n  std::cerr << \"Caught exception: \" << e.what() << std::endl;\n\n  // Test fstream\n  std::ofstream of(\"test.txt\");\n  of << \"Test ASCII text\\n\" << std::flush;\n  of << \"N= \" << std::hex << std::setw(8) << std::left << 534 << std::endl;\n  of.close();\n}\nstd::exit(0);\n]])\n\n# _AC_CXX_CXX11_TEST_HEADER\n# -------------------------\n# A C++ header suitable for testing for CXX11.\nAC_DEFUN([_AC_CXX_CXX11_TEST_HEADER],\n[[\n#include <deque>\n#include <functional>\n#include <memory>\n#include <tuple>\n#include <array>\n#include <regex>\n#include <iostream>\n\nnamespace cxx11test\n{\n  typedef std::shared_ptr<std::string> sptr;\n  typedef std::weak_ptr<std::string> wptr;\n\n  typedef std::tuple<std::string,int,double> tp;\n  typedef std::array<int, 20> int_array;\n\n  constexpr int get_val() { return 20; }\n\n  struct testinit\n  {\n    int i;\n    double d;\n  };\n\n  class delegate  {\n  public:\n    delegate(int n) : n(n) {}\n    delegate(): delegate(2354) {}\n\n    virtual int getval() { return this->n; };\n  protected:\n    int n;\n  };\n\n  class overridden : public delegate {\n  public:\n    overridden(int n): delegate(n) {}\n    virtual int getval() override final { return this->n * 2; }\n  };\n\n  class nocopy {\n  public:\n    nocopy(int i): i(i) {}\n    nocopy() = default;\n    nocopy(const nocopy&) = delete;\n    nocopy & operator=(const nocopy&) = delete;\n  private:\n    int i;\n  };\n}\n]])# _AC_CXX_CXX11_TEST_HEADER\n\n# _AC_CXX_CXX11_TEST_BODY\n# -----------------------\n# A C++ body suitable for testing for CXX11, assuming the corresponding header.\nAC_DEFUN([_AC_CXX_CXX11_TEST_BODY],\n[[\n{\n  // Test auto and decltype\n  std::deque<int> d;\n  d.push_front(43);\n  d.push_front(484);\n  d.push_front(3);\n  d.push_front(844);\n  int total = 0;\n  for (auto i = d.begin(); i != d.end(); ++i) { total += *i; }\n\n  auto a1 = 6538;\n  auto a2 = 48573953.4;\n  auto a3 = \"String literal\";\n\n  decltype(a2) a4 = 34895.034;\n}\n{\n  // Test constexpr\n  short sa[cxx11test::get_val()] = { 0 };\n}\n{\n  // Test initializer lists\n  cxx11test::testinit il = { 4323, 435234.23544 };\n}\n{\n  // Test range-based for and lambda\n  cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};\n  for (int &x : array) { x += 23; }\n  std::for_each(array.begin(), array.end(), [](int v1){ std::cout << v1; });\n}\n{\n  using cxx11test::sptr;\n  using cxx11test::wptr;\n\n  sptr sp(new std::string(\"ASCII string\"));\n  wptr wp(sp);\n  sptr sp2(wp);\n}\n{\n  cxx11test::tp tuple(\"test\", 54, 45.53434);\n  double d = std::get<2>(tuple);\n  std::string s;\n  int i;\n  std::tie(s,i,d) = tuple;\n}\n{\n  static std::regex filename_regex(\"^_?([a-z0-9_.]+-)+[a-z0-9]+$\");\n  std::string testmatch(\"Test if this string matches\");\n  bool match = std::regex_search(testmatch, filename_regex);\n}\n{\n  cxx11test::int_array array = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1};\n  cxx11test::int_array::size_type size = array.size();\n}\n{\n  // Test constructor delegation\n  cxx11test::delegate d1;\n  cxx11test::delegate d2();\n  cxx11test::delegate d3(45);\n}\n{\n  // Test override and final\n  cxx11test::overridden o1(55464);\n}\n{\n  // Test nullptr\n  char *c = nullptr;\n}\n{\n  // Test template brackets\n  std::vector<std::pair<int,char*>> v1;\n}\n{\n  // Unicode literals\n  char const *utf8 = u8\"UTF-8 string \\u2500\";\n  char16_t const *utf16 = u\"UTF-8 string \\u2500\";\n  char32_t const *utf32 = U\"UTF-32 string \\u2500\";\n}\n]])\n\n# _AC_PROG_CXX_CXX98 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])\n# -------------------------------------------------------------------\n\n# If the C++ compiler is not in ISO C++98 mode by default, try to add\n# an option to output variable CXX to make it so.  This macro tries\n# various options that select ISO C++98 on some system or another.  It\n# considers the compiler to be in ISO C++98 mode if it handles basic\n# features of the std namespace including: string, containers (list,\n# map, set, vector), streams (fstreams, iostreams, stringstreams,\n# iomanip), pair, exceptions and algorithms.\n\n\nAC_DEFUN([_AC_PROG_CXX_CXX98],\n[_AC_CXX_STD_TRY([cxx98],\n[_AC_CXX_CXX98_TEST_HEADER],\n[_AC_CXX_CXX98_TEST_BODY],\ndnl Try\ndnl GCC\t\t-std=gnu++98 (unused restrictive mode: -std=c++98)\ndnl IBM XL C\t-qlanglvl=extended\ndnl HP aC++\t-AA\ndnl Intel ICC\t-std=gnu++98\ndnl Solaris\tN/A (default)\ndnl Tru64\tN/A (default, but -std gnu could be used)\ndnl with extended modes being tried first.\n[[-std=gnu++98 -std=c++98 -qlanglvl=extended -AA]], [$1], [$2])[]dnl\n])# _AC_PROG_CXX_CXX98\n\n# _AC_PROG_CXX_CXX11 ([ACTION-IF-AVAILABLE], [ACTION-IF-UNAVAILABLE])\n# -------------------------------------------------------------------\n# If the C++ compiler is not in ISO CXX11 mode by default, try to add\n# an option to output variable CXX to make it so.  This macro tries\n# various options that select ISO C++11 on some system or another.  It\n# considers the compiler to be in ISO C++11 mode if it handles all the\n# tests from the C++98 checks, plus the following: Language features\n# (auto, constexpr, decltype, default/deleted constructors, delegate\n# constructors, final, initializer lists, lambda functions, nullptr,\n# override, range-based for loops, template brackets without spaces,\n# unicode literals) and library features (array, memory (shared_ptr,\n# weak_ptr), regex and tuple types).\nAC_DEFUN([_AC_PROG_CXX_CXX11],\n[_AC_CXX_STD_TRY([cxx11],\n[_AC_CXX_CXX11_TEST_HEADER\n_AC_CXX_CXX98_TEST_HEADER],\n[_AC_CXX_CXX11_TEST_BODY\n_AC_CXX_CXX98_TEST_BODY],\ndnl Try\ndnl GCC\t\t-std=gnu++11 (unused restrictive mode: -std=c++11) [and 0x variants]\ndnl IBM XL C\t-qlanglvl=extended0x\ndnl\t\t(pre-V12.1; unused restrictive mode: -qlanglvl=stdcxx11)\ndnl HP aC++\t-AA\ndnl Intel ICC\t-std=c++11 -std=c++0x\ndnl Solaris\tN/A (no support)\ndnl Tru64\tN/A (no support)\ndnl with extended modes being tried first.\n[[-std=gnu++11 -std=c++11 -std=gnu++0x -std=c++0x -qlanglvl=extended0x -AA]], [$1], [$2])[]dnl\n])# _AC_PROG_CXX_CXX11\n\n\n])# m4_version_prereq\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/stdalign.m4",
    "content": "# Check for stdalign.h that conforms to C11.\n\ndnl Copyright 2011-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\n# Prepare for substituting <stdalign.h> if it is not supported.\n\nAC_DEFUN([gl_STDALIGN_H],\n[\n  AC_CACHE_CHECK([for working stdalign.h],\n    [gl_cv_header_working_stdalign_h],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <stdint.h>\n            #include <stdalign.h>\n            #include <stddef.h>\n\n            /* Test that alignof yields a result consistent with offsetof.\n               This catches GCC bug 52023\n               <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.  */\n            #ifdef __cplusplus\n               template <class t> struct alignof_helper { char a; t b; };\n            # define ao(type) offsetof (alignof_helper<type>, b)\n            #else\n            # define ao(type) offsetof (struct { char a; type b; }, b)\n            #endif\n            char test_double[ao (double) % _Alignof (double) == 0 ? 1 : -1];\n            char test_long[ao (long int) % _Alignof (long int) == 0 ? 1 : -1];\n            char test_alignof[alignof (double) == _Alignof (double) ? 1 : -1];\n\n            /* Test _Alignas only on platforms where gnulib can help.  */\n            #if \\\n                ((defined __cplusplus && 201103 <= __cplusplus) \\\n                 || (__TINYC__ && defined __attribute__) \\\n                 || (defined __APPLE__ && defined __MACH__ \\\n                     ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \\\n                     : __GNUC__) \\\n                 || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \\\n                 || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__ \\\n                 || 1300 <= _MSC_VER)\n              struct alignas_test { char c; char alignas (8) alignas_8; };\n              char test_alignas[offsetof (struct alignas_test, alignas_8) == 8\n                                ? 1 : -1];\n            #endif\n          ]])],\n       [gl_cv_header_working_stdalign_h=yes],\n       [gl_cv_header_working_stdalign_h=no])])\n\n  if test $gl_cv_header_working_stdalign_h = yes; then\n    STDALIGN_H=''\n  else\n    STDALIGN_H='stdalign.h'\n  fi\n\n  AC_SUBST([STDALIGN_H])\n  AM_CONDITIONAL([GL_GENERATE_STDALIGN_H], [test -n \"$STDALIGN_H\"])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/stddef_h.m4",
    "content": "# stddef_h.m4 serial 11\ndnl Copyright (C) 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl A placeholder for <stddef.h>, for platforms that have issues.\n\nAC_DEFUN_ONCE([gl_STDDEF_H],\n[\n  AC_REQUIRE([gl_STDDEF_H_DEFAULTS])\n  AC_REQUIRE([gt_TYPE_WCHAR_T])\n\n  dnl Persuade OpenBSD <stddef.h> to declare max_align_t.\n  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])\n\n  STDDEF_H=\n\n  dnl Test whether the type max_align_t exists and whether its alignment\n  dnl \"is as great as is supported by the implementation in all contexts\".\n  AC_CACHE_CHECK([for good max_align_t],\n    [gl_cv_type_max_align_t],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <stddef.h>\n            unsigned int s = sizeof (max_align_t);\n            #if defined __GNUC__ || defined __clang__ || defined __IBM__ALIGNOF__\n            int check1[2 * (__alignof__ (double) <= __alignof__ (max_align_t)) - 1];\n            int check2[2 * (__alignof__ (long double) <= __alignof__ (max_align_t)) - 1];\n            #endif\n            typedef struct { char a; max_align_t b; } max_helper;\n            typedef struct { char a; long b; } long_helper;\n            typedef struct { char a; double b; } double_helper;\n            typedef struct { char a; long double b; } long_double_helper;\n            int check3[2 * (offsetof (long_helper, b) <= offsetof (max_helper, b)) - 1];\n            int check4[2 * (offsetof (double_helper, b) <= offsetof (max_helper, b)) - 1];\n            int check5[2 * (offsetof (long_double_helper, b) <= offsetof (max_helper, b)) - 1];\n          ]])],\n       [gl_cv_type_max_align_t=yes],\n       [gl_cv_type_max_align_t=no])\n    ])\n  if test $gl_cv_type_max_align_t = no; then\n    HAVE_MAX_ALIGN_T=0\n    STDDEF_H=stddef.h\n  fi\n\n  if test $gt_cv_c_wchar_t = no; then\n    HAVE_WCHAR_T=0\n    STDDEF_H=stddef.h\n  fi\n\n  AC_CACHE_CHECK([whether NULL can be used in arbitrary expressions],\n    [gl_cv_decl_null_works],\n    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h>\n      int test[2 * (sizeof NULL == sizeof (void *)) -1];\n]])],\n      [gl_cv_decl_null_works=yes],\n      [gl_cv_decl_null_works=no])])\n  if test $gl_cv_decl_null_works = no; then\n    REPLACE_NULL=1\n    STDDEF_H=stddef.h\n  fi\n\n  AC_SUBST([STDDEF_H])\n  AM_CONDITIONAL([GL_GENERATE_STDDEF_H], [test -n \"$STDDEF_H\"])\n  if test -n \"$STDDEF_H\"; then\n    gl_NEXT_HEADERS([stddef.h])\n  fi\n])\n\n# gl_STDDEF_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_STDDEF_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_STDDEF_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_STDDEF_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDDEF_H_MODULE_INDICATOR_DEFAULTS], [\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDDEF_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_STDDEF_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_STDDEF_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  REPLACE_NULL=0;                AC_SUBST([REPLACE_NULL])\n  HAVE_MAX_ALIGN_T=1;            AC_SUBST([HAVE_MAX_ALIGN_T])\n  HAVE_WCHAR_T=1;                AC_SUBST([HAVE_WCHAR_T])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/stdint.m4",
    "content": "# stdint.m4 serial 60\ndnl Copyright (C) 2001-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Paul Eggert and Bruno Haible.\ndnl Test whether <stdint.h> is supported or must be substituted.\n\nAC_PREREQ([2.61])\n\nAC_DEFUN_ONCE([gl_STDINT_H],\n[\n  AC_PREREQ([2.59])dnl\n  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles\n\n  AC_REQUIRE([gl_LIMITS_H])\n  AC_REQUIRE([gt_TYPE_WINT_T])\n\n  dnl For backward compatibility. Some packages may still be testing these\n  dnl macros.\n  AC_DEFINE([HAVE_LONG_LONG_INT], [1],\n    [Define to 1 if the system has the type 'long long int'.])\n  AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],\n    [Define to 1 if the system has the type 'unsigned long long int'.])\n\n  dnl Check for <wchar.h>, in the same way as gl_WCHAR_H does.\n  AC_CHECK_HEADERS_ONCE([wchar.h])\n  if test $ac_cv_header_wchar_h = yes; then\n    HAVE_WCHAR_H=1\n  else\n    HAVE_WCHAR_H=0\n  fi\n  AC_SUBST([HAVE_WCHAR_H])\n\n  dnl Check for <inttypes.h>.\n  AC_CHECK_HEADERS_ONCE([inttypes.h])\n  if test $ac_cv_header_inttypes_h = yes; then\n    HAVE_INTTYPES_H=1\n  else\n    HAVE_INTTYPES_H=0\n  fi\n  AC_SUBST([HAVE_INTTYPES_H])\n\n  dnl Check for <sys/types.h>.\n  AC_CHECK_HEADERS_ONCE([sys/types.h])\n  if test $ac_cv_header_sys_types_h = yes; then\n    HAVE_SYS_TYPES_H=1\n  else\n    HAVE_SYS_TYPES_H=0\n  fi\n  AC_SUBST([HAVE_SYS_TYPES_H])\n\n  gl_CHECK_NEXT_HEADERS([stdint.h])\n  if test $ac_cv_header_stdint_h = yes; then\n    HAVE_STDINT_H=1\n  else\n    HAVE_STDINT_H=0\n  fi\n  AC_SUBST([HAVE_STDINT_H])\n\n  dnl Now see whether we need a substitute <stdint.h>.\n  if test $ac_cv_header_stdint_h = yes; then\n    AC_CACHE_CHECK([whether stdint.h conforms to C99],\n      [gl_cv_header_working_stdint_h],\n      [gl_cv_header_working_stdint_h=no\n       AC_COMPILE_IFELSE([\n         AC_LANG_PROGRAM([[\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#define __STDC_CONSTANT_MACROS 1\n#define __STDC_LIMIT_MACROS 1\n#include <stdint.h>\n/* Dragonfly defines WCHAR_MIN, WCHAR_MAX only in <wchar.h>.  */\n#if !(defined WCHAR_MIN && defined WCHAR_MAX)\n#error \"WCHAR_MIN, WCHAR_MAX not defined in <stdint.h>\"\n#endif\n]\ngl_STDINT_INCLUDES\n[\n#ifdef INT8_MAX\nint8_t a1 = INT8_MAX;\nint8_t a1min = INT8_MIN;\n#endif\n#ifdef INT16_MAX\nint16_t a2 = INT16_MAX;\nint16_t a2min = INT16_MIN;\n#endif\n#ifdef INT32_MAX\nint32_t a3 = INT32_MAX;\nint32_t a3min = INT32_MIN;\n#endif\n#ifdef INT64_MAX\nint64_t a4 = INT64_MAX;\nint64_t a4min = INT64_MIN;\n#endif\n#ifdef UINT8_MAX\nuint8_t b1 = UINT8_MAX;\n#else\ntypedef int b1[(unsigned char) -1 != 255 ? 1 : -1];\n#endif\n#ifdef UINT16_MAX\nuint16_t b2 = UINT16_MAX;\n#endif\n#ifdef UINT32_MAX\nuint32_t b3 = UINT32_MAX;\n#endif\n#ifdef UINT64_MAX\nuint64_t b4 = UINT64_MAX;\n#endif\nint_least8_t c1 = INT8_C (0x7f);\nint_least8_t c1max = INT_LEAST8_MAX;\nint_least8_t c1min = INT_LEAST8_MIN;\nint_least16_t c2 = INT16_C (0x7fff);\nint_least16_t c2max = INT_LEAST16_MAX;\nint_least16_t c2min = INT_LEAST16_MIN;\nint_least32_t c3 = INT32_C (0x7fffffff);\nint_least32_t c3max = INT_LEAST32_MAX;\nint_least32_t c3min = INT_LEAST32_MIN;\nint_least64_t c4 = INT64_C (0x7fffffffffffffff);\nint_least64_t c4max = INT_LEAST64_MAX;\nint_least64_t c4min = INT_LEAST64_MIN;\nuint_least8_t d1 = UINT8_C (0xff);\nuint_least8_t d1max = UINT_LEAST8_MAX;\nuint_least16_t d2 = UINT16_C (0xffff);\nuint_least16_t d2max = UINT_LEAST16_MAX;\nuint_least32_t d3 = UINT32_C (0xffffffff);\nuint_least32_t d3max = UINT_LEAST32_MAX;\nuint_least64_t d4 = UINT64_C (0xffffffffffffffff);\nuint_least64_t d4max = UINT_LEAST64_MAX;\nint_fast8_t e1 = INT_FAST8_MAX;\nint_fast8_t e1min = INT_FAST8_MIN;\nint_fast16_t e2 = INT_FAST16_MAX;\nint_fast16_t e2min = INT_FAST16_MIN;\nint_fast32_t e3 = INT_FAST32_MAX;\nint_fast32_t e3min = INT_FAST32_MIN;\nint_fast64_t e4 = INT_FAST64_MAX;\nint_fast64_t e4min = INT_FAST64_MIN;\nuint_fast8_t f1 = UINT_FAST8_MAX;\nuint_fast16_t f2 = UINT_FAST16_MAX;\nuint_fast32_t f3 = UINT_FAST32_MAX;\nuint_fast64_t f4 = UINT_FAST64_MAX;\n#ifdef INTPTR_MAX\nintptr_t g = INTPTR_MAX;\nintptr_t gmin = INTPTR_MIN;\n#endif\n#ifdef UINTPTR_MAX\nuintptr_t h = UINTPTR_MAX;\n#endif\nintmax_t i = INTMAX_MAX;\nuintmax_t j = UINTMAX_MAX;\n\n/* Check that SIZE_MAX has the correct type, if possible.  */\n#if 201112 <= __STDC_VERSION__\nint k = _Generic (SIZE_MAX, size_t: 0);\n#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \\\n       || (0x5110 <= __SUNPRO_C && !__STDC__))\nextern size_t k;\nextern __typeof__ (SIZE_MAX) k;\n#endif\n\n#include <limits.h> /* for CHAR_BIT */\n#define TYPE_MINIMUM(t) \\\n  ((t) ((t) 0 < (t) -1 ? (t) 0 : ~ TYPE_MAXIMUM (t)))\n#define TYPE_MAXIMUM(t) \\\n  ((t) ((t) 0 < (t) -1 \\\n        ? (t) -1 \\\n        : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))\nstruct s {\n  int check_PTRDIFF:\n      PTRDIFF_MIN == TYPE_MINIMUM (ptrdiff_t)\n      && PTRDIFF_MAX == TYPE_MAXIMUM (ptrdiff_t)\n      ? 1 : -1;\n  /* Detect bug in FreeBSD 6.0/ia64 and FreeBSD 13.0/arm64.  */\n  int check_SIG_ATOMIC:\n      SIG_ATOMIC_MIN == TYPE_MINIMUM (sig_atomic_t)\n      && SIG_ATOMIC_MAX == TYPE_MAXIMUM (sig_atomic_t)\n      ? 1 : -1;\n  int check_SIZE: SIZE_MAX == TYPE_MAXIMUM (size_t) ? 1 : -1;\n  int check_WCHAR:\n      WCHAR_MIN == TYPE_MINIMUM (wchar_t)\n      && WCHAR_MAX == TYPE_MAXIMUM (wchar_t)\n      ? 1 : -1;\n  /* Detect bug in mingw.  */\n  int check_WINT:\n      WINT_MIN == TYPE_MINIMUM (wint_t)\n      && WINT_MAX == TYPE_MAXIMUM (wint_t)\n      ? 1 : -1;\n\n  /* Detect bugs in glibc 2.4 and Solaris 10 stdint.h, among others.  */\n  int check_UINT8_C:\n        (-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1;\n  int check_UINT16_C:\n        (-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1;\n\n  /* Detect bugs in OpenBSD 3.9 stdint.h.  */\n#ifdef UINT8_MAX\n  int check_uint8: (uint8_t) -1 == UINT8_MAX ? 1 : -1;\n#endif\n#ifdef UINT16_MAX\n  int check_uint16: (uint16_t) -1 == UINT16_MAX ? 1 : -1;\n#endif\n#ifdef UINT32_MAX\n  int check_uint32: (uint32_t) -1 == UINT32_MAX ? 1 : -1;\n#endif\n#ifdef UINT64_MAX\n  int check_uint64: (uint64_t) -1 == UINT64_MAX ? 1 : -1;\n#endif\n  int check_uint_least8: (uint_least8_t) -1 == UINT_LEAST8_MAX ? 1 : -1;\n  int check_uint_least16: (uint_least16_t) -1 == UINT_LEAST16_MAX ? 1 : -1;\n  int check_uint_least32: (uint_least32_t) -1 == UINT_LEAST32_MAX ? 1 : -1;\n  int check_uint_least64: (uint_least64_t) -1 == UINT_LEAST64_MAX ? 1 : -1;\n  int check_uint_fast8: (uint_fast8_t) -1 == UINT_FAST8_MAX ? 1 : -1;\n  int check_uint_fast16: (uint_fast16_t) -1 == UINT_FAST16_MAX ? 1 : -1;\n  int check_uint_fast32: (uint_fast32_t) -1 == UINT_FAST32_MAX ? 1 : -1;\n  int check_uint_fast64: (uint_fast64_t) -1 == UINT_FAST64_MAX ? 1 : -1;\n  int check_uintptr: (uintptr_t) -1 == UINTPTR_MAX ? 1 : -1;\n  int check_uintmax: (uintmax_t) -1 == UINTMAX_MAX ? 1 : -1;\n  int check_size: (size_t) -1 == SIZE_MAX ? 1 : -1;\n};\n         ]])],\n         [dnl Determine whether the various *_MIN, *_MAX macros are usable\n          dnl in preprocessor expression. We could do it by compiling a test\n          dnl program for each of these macros. It is faster to run a program\n          dnl that inspects the macro expansion.\n          dnl This detects a bug on HP-UX 11.23/ia64.\n          AC_RUN_IFELSE([\n            AC_LANG_PROGRAM([[\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#define __STDC_CONSTANT_MACROS 1\n#define __STDC_LIMIT_MACROS 1\n#include <stdint.h>\n]\ngl_STDINT_INCLUDES\n[\n#include <stdio.h>\n#include <string.h>\n#define MVAL(macro) MVAL1(macro)\n#define MVAL1(expression) #expression\nstatic const char *macro_values[] =\n  {\n#ifdef INT8_MAX\n    MVAL (INT8_MAX),\n#endif\n#ifdef INT16_MAX\n    MVAL (INT16_MAX),\n#endif\n#ifdef INT32_MAX\n    MVAL (INT32_MAX),\n#endif\n#ifdef INT64_MAX\n    MVAL (INT64_MAX),\n#endif\n#ifdef UINT8_MAX\n    MVAL (UINT8_MAX),\n#endif\n#ifdef UINT16_MAX\n    MVAL (UINT16_MAX),\n#endif\n#ifdef UINT32_MAX\n    MVAL (UINT32_MAX),\n#endif\n#ifdef UINT64_MAX\n    MVAL (UINT64_MAX),\n#endif\n    NULL\n  };\n]], [[\n  const char **mv;\n  for (mv = macro_values; *mv != NULL; mv++)\n    {\n      const char *value = *mv;\n      /* Test whether it looks like a cast expression.  */\n      if (strncmp (value, \"((unsigned int)\"/*)*/, 15) == 0\n          || strncmp (value, \"((unsigned short)\"/*)*/, 17) == 0\n          || strncmp (value, \"((unsigned char)\"/*)*/, 16) == 0\n          || strncmp (value, \"((int)\"/*)*/, 6) == 0\n          || strncmp (value, \"((signed short)\"/*)*/, 15) == 0\n          || strncmp (value, \"((signed char)\"/*)*/, 14) == 0)\n        return mv - macro_values + 1;\n    }\n  return 0;\n]])],\n              [gl_cv_header_working_stdint_h=yes],\n              [],\n              [case \"$host_os\" in\n                         # Guess yes on native Windows.\n                 mingw*) gl_cv_header_working_stdint_h=\"guessing yes\" ;;\n                         # In general, assume it works.\n                 *)      gl_cv_header_working_stdint_h=\"guessing yes\" ;;\n               esac\n              ])\n         ])\n      ])\n  fi\n\n  HAVE_C99_STDINT_H=0\n  HAVE_SYS_BITYPES_H=0\n  HAVE_SYS_INTTYPES_H=0\n  STDINT_H=stdint.h\n  case \"$gl_cv_header_working_stdint_h\" in\n    *yes)\n      HAVE_C99_STDINT_H=1\n      dnl Now see whether the system <stdint.h> works without\n      dnl __STDC_CONSTANT_MACROS/__STDC_LIMIT_MACROS defined.\n      dnl If not, there would be problems when stdint.h is included from C++.\n      AC_CACHE_CHECK([whether stdint.h works without ISO C predefines],\n        [gl_cv_header_stdint_without_STDC_macros],\n        [gl_cv_header_stdint_without_STDC_macros=no\n         AC_COMPILE_IFELSE([\n           AC_LANG_PROGRAM([[\n#define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1 /* work if build isn't clean */\n#include <stdint.h>\n]\ngl_STDINT_INCLUDES\n[\nintmax_t im = INTMAX_MAX;\nint32_t i32 = INT32_C (0x7fffffff);\n           ]])],\n           [gl_cv_header_stdint_without_STDC_macros=yes])\n        ])\n\n      if test $gl_cv_header_stdint_without_STDC_macros = no; then\n        AC_DEFINE([__STDC_CONSTANT_MACROS], [1],\n          [Define to 1 if the system <stdint.h> predates C++11.])\n        AC_DEFINE([__STDC_LIMIT_MACROS], [1],\n          [Define to 1 if the system <stdint.h> predates C++11.])\n      fi\n      AC_CACHE_CHECK([whether stdint.h has UINTMAX_WIDTH etc.],\n        [gl_cv_header_stdint_width],\n        [gl_cv_header_stdint_width=no\n         AC_COMPILE_IFELSE(\n           [AC_LANG_PROGRAM([[\n              /* Work if build is not clean.  */\n              #define _GL_JUST_INCLUDE_SYSTEM_STDINT_H 1\n              #ifndef __STDC_WANT_IEC_60559_BFP_EXT__\n               #define __STDC_WANT_IEC_60559_BFP_EXT__ 1\n              #endif\n              #include <stdint.h>\n              ]gl_STDINT_INCLUDES[\n              int iw = UINTMAX_WIDTH;\n              ]])],\n           [gl_cv_header_stdint_width=yes])])\n      if test \"$gl_cv_header_stdint_width\" = yes; then\n        STDINT_H=\n      fi\n      ;;\n    *)\n      dnl Check for <sys/inttypes.h>, and for\n      dnl <sys/bitypes.h> (used in Linux libc4 >= 4.6.7 and libc5).\n      AC_CHECK_HEADERS([sys/inttypes.h sys/bitypes.h])\n      if test $ac_cv_header_sys_inttypes_h = yes; then\n        HAVE_SYS_INTTYPES_H=1\n      fi\n      if test $ac_cv_header_sys_bitypes_h = yes; then\n        HAVE_SYS_BITYPES_H=1\n      fi\n      gl_STDINT_TYPE_PROPERTIES\n      ;;\n  esac\n\n  dnl The substitute stdint.h needs the substitute limit.h's _GL_INTEGER_WIDTH.\n  gl_REPLACE_LIMITS_H\n\n  AC_SUBST([HAVE_C99_STDINT_H])\n  AC_SUBST([HAVE_SYS_BITYPES_H])\n  AC_SUBST([HAVE_SYS_INTTYPES_H])\n  AC_SUBST([STDINT_H])\n  AM_CONDITIONAL([GL_GENERATE_STDINT_H], [test -n \"$STDINT_H\"])\n])\n\ndnl gl_STDINT_BITSIZEOF(TYPES, INCLUDES)\ndnl Determine the size of each of the given types in bits.\nAC_DEFUN([gl_STDINT_BITSIZEOF],\n[\n  dnl Use a shell loop, to avoid bloating configure, and\n  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into\n  dnl   config.h.in,\n  dnl - extra AC_SUBST calls, so that the right substitutions are made.\n  m4_foreach_w([gltype], [$1],\n    [AH_TEMPLATE([BITSIZEOF_]m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]),\n       [Define to the number of bits in type ']gltype['.])])\n  for gltype in $1 ; do\n    AC_CACHE_CHECK([for bit size of $gltype], [gl_cv_bitsizeof_${gltype}],\n      [AC_COMPUTE_INT([result], [sizeof ($gltype) * CHAR_BIT],\n         [$2\n#include <limits.h>], [result=unknown])\n       eval gl_cv_bitsizeof_${gltype}=\\$result\n      ])\n    eval result=\\$gl_cv_bitsizeof_${gltype}\n    if test $result = unknown; then\n      dnl Use a nonempty default, because some compilers, such as IRIX 5 cc,\n      dnl do a syntax check even on unused #if conditions and give an error\n      dnl on valid C code like this:\n      dnl   #if 0\n      dnl   # if  > 32\n      dnl   # endif\n      dnl   #endif\n      result=0\n    fi\n    GLTYPE=`echo \"$gltype\" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    AC_DEFINE_UNQUOTED([BITSIZEOF_${GLTYPE}], [$result])\n    eval BITSIZEOF_${GLTYPE}=\\$result\n  done\n  m4_foreach_w([gltype], [$1],\n    [AC_SUBST([BITSIZEOF_]m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))])\n])\n\ndnl gl_CHECK_TYPES_SIGNED(TYPES, INCLUDES)\ndnl Determine the signedness of each of the given types.\ndnl Define HAVE_SIGNED_TYPE if type is signed.\nAC_DEFUN([gl_CHECK_TYPES_SIGNED],\n[\n  dnl Use a shell loop, to avoid bloating configure, and\n  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into\n  dnl   config.h.in,\n  dnl - extra AC_SUBST calls, so that the right substitutions are made.\n  m4_foreach_w([gltype], [$1],\n    [AH_TEMPLATE([HAVE_SIGNED_]m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]),\n       [Define to 1 if ']gltype[' is a signed integer type.])])\n  for gltype in $1 ; do\n    AC_CACHE_CHECK([whether $gltype is signed], [gl_cv_type_${gltype}_signed],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM([$2[\n            int verify[2 * (($gltype) -1 < ($gltype) 0) - 1];]])],\n         result=yes, result=no)\n       eval gl_cv_type_${gltype}_signed=\\$result\n      ])\n    eval result=\\$gl_cv_type_${gltype}_signed\n    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    if test \"$result\" = yes; then\n      AC_DEFINE_UNQUOTED([HAVE_SIGNED_${GLTYPE}], [1])\n      eval HAVE_SIGNED_${GLTYPE}=1\n    else\n      eval HAVE_SIGNED_${GLTYPE}=0\n    fi\n  done\n  m4_foreach_w([gltype], [$1],\n    [AC_SUBST([HAVE_SIGNED_]m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))])\n])\n\ndnl gl_INTEGER_TYPE_SUFFIX(TYPES, INCLUDES)\ndnl Determine the suffix to use for integer constants of the given types.\ndnl Define t_SUFFIX for each such type.\nAC_DEFUN([gl_INTEGER_TYPE_SUFFIX],\n[\n  dnl Use a shell loop, to avoid bloating configure, and\n  dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into\n  dnl   config.h.in,\n  dnl - extra AC_SUBST calls, so that the right substitutions are made.\n  m4_foreach_w([gltype], [$1],\n    [AH_TEMPLATE(m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX],\n       [Define to l, ll, u, ul, ull, etc., as suitable for\n        constants of type ']gltype['.])])\n  for gltype in $1 ; do\n    AC_CACHE_CHECK([for $gltype integer literal suffix],\n      [gl_cv_type_${gltype}_suffix],\n      [eval gl_cv_type_${gltype}_suffix=no\n       eval result=\\$gl_cv_type_${gltype}_signed\n       if test \"$result\" = yes; then\n         glsufu=\n       else\n         glsufu=u\n       fi\n       for glsuf in \"$glsufu\" ${glsufu}l ${glsufu}ll ${glsufu}i64; do\n         case $glsuf in\n           '')  gltype1='int';;\n           l)   gltype1='long int';;\n           ll)  gltype1='long long int';;\n           i64) gltype1='__int64';;\n           u)   gltype1='unsigned int';;\n           ul)  gltype1='unsigned long int';;\n           ull) gltype1='unsigned long long int';;\n           ui64)gltype1='unsigned __int64';;\n         esac\n         AC_COMPILE_IFELSE(\n           [AC_LANG_PROGRAM([$2[\n              extern $gltype foo;\n              extern $gltype1 foo;]])],\n           [eval gl_cv_type_${gltype}_suffix=\\$glsuf])\n         eval result=\\$gl_cv_type_${gltype}_suffix\n         test \"$result\" != no && break\n       done])\n    GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'`\n    eval result=\\$gl_cv_type_${gltype}_suffix\n    test \"$result\" = no && result=\n    eval ${GLTYPE}_SUFFIX=\\$result\n    AC_DEFINE_UNQUOTED([${GLTYPE}_SUFFIX], [$result])\n  done\n  m4_foreach_w([gltype], [$1],\n    [AC_SUBST(m4_translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX])])\n])\n\ndnl gl_STDINT_INCLUDES\nAC_DEFUN([gl_STDINT_INCLUDES],\n[[\n  #include <stddef.h>\n  #include <signal.h>\n  #if HAVE_WCHAR_H\n  # include <wchar.h>\n  #endif\n]])\n\ndnl gl_STDINT_TYPE_PROPERTIES\ndnl Compute HAVE_SIGNED_t, BITSIZEOF_t and t_SUFFIX, for all the types t\ndnl of interest to stdint.in.h.\nAC_DEFUN([gl_STDINT_TYPE_PROPERTIES],\n[\n  AC_REQUIRE([gl_MULTIARCH])\n  if test $APPLE_UNIVERSAL_BUILD = 0; then\n    gl_STDINT_BITSIZEOF([ptrdiff_t size_t],\n      [gl_STDINT_INCLUDES])\n  fi\n  gl_STDINT_BITSIZEOF([sig_atomic_t wchar_t wint_t],\n    [gl_STDINT_INCLUDES])\n  gl_CHECK_TYPES_SIGNED([sig_atomic_t wchar_t wint_t],\n    [gl_STDINT_INCLUDES])\n  gl_cv_type_ptrdiff_t_signed=yes\n  gl_cv_type_size_t_signed=no\n  if test $APPLE_UNIVERSAL_BUILD = 0; then\n    gl_INTEGER_TYPE_SUFFIX([ptrdiff_t size_t],\n      [gl_STDINT_INCLUDES])\n  fi\n  gl_INTEGER_TYPE_SUFFIX([sig_atomic_t wchar_t wint_t],\n    [gl_STDINT_INCLUDES])\n\n  dnl If wint_t is smaller than 'int', it cannot satisfy the ISO C 99\n  dnl requirement that wint_t is \"unchanged by default argument promotions\".\n  dnl In this case gnulib's <wchar.h> and <wctype.h> override wint_t.\n  dnl Set the variable BITSIZEOF_WINT_T accordingly.\n  if test $GNULIBHEADERS_OVERRIDE_WINT_T = 1; then\n    BITSIZEOF_WINT_T=32\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/stdio_h.m4",
    "content": "# stdio_h.m4 serial 56\ndnl Copyright (C) 2007-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN_ONCE([gl_STDIO_H],\n[\n  AC_REQUIRE([gl_STDIO_H_DEFAULTS])\n  AH_VERBATIM([MINGW_ANSI_STDIO],\n[/* Use GNU style printf and scanf.  */\n#ifndef __USE_MINGW_ANSI_STDIO\n# undef __USE_MINGW_ANSI_STDIO\n#endif\n])\n  AC_DEFINE([__USE_MINGW_ANSI_STDIO])\n  gl_NEXT_HEADERS([stdio.h])\n\n  dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and\n  dnl inttypes.h behave like gnu instead of system; we must give our\n  dnl printf wrapper the right attribute to match.\n  AC_CACHE_CHECK([which flavor of printf attribute matches inttypes macros],\n    [gl_cv_func_printf_attribute_flavor],\n    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[\n       #define __STDC_FORMAT_MACROS 1\n       #include <stdio.h>\n       #include <inttypes.h>\n       /* For non-mingw systems, compilation will trivially succeed.\n          For mingw, compilation will succeed for older mingw (system\n          printf, \"I64d\") and fail for newer mingw (gnu printf, \"lld\"). */\n       #if (defined _WIN32 && ! defined __CYGWIN__) && \\\n         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))\n       extern char PRIdMAX_probe[sizeof PRIdMAX == sizeof \"I64d\" ? 1 : -1];\n       #endif\n      ]])], [gl_cv_func_printf_attribute_flavor=system],\n      [gl_cv_func_printf_attribute_flavor=gnu])])\n  if test \"$gl_cv_func_printf_attribute_flavor\" = gnu; then\n    AC_DEFINE([GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU], [1],\n      [Define to 1 if printf and friends should be labeled with\n       attribute \"__gnu_printf__\" instead of \"__printf__\"])\n  fi\n\n  dnl This ifdef is necessary to avoid an error \"missing file lib/stdio-read.c\"\n  dnl \"expected source file, required through AC_LIBSOURCES, not found\". It is\n  dnl also an optimization, to avoid performing a configure check whose result\n  dnl is not used. But it does not make the test of GNULIB_STDIO_H_NONBLOCKING\n  dnl or GNULIB_NONBLOCKING redundant.\n  m4_ifdef([gl_NONBLOCKING_IO], [\n    gl_NONBLOCKING_IO\n    if test $gl_cv_have_nonblocking != yes; then\n      REPLACE_STDIO_READ_FUNCS=1\n      AC_LIBOBJ([stdio-read])\n    fi\n  ])\n\n  dnl This ifdef is necessary to avoid an error \"missing file lib/stdio-write.c\"\n  dnl \"expected source file, required through AC_LIBSOURCES, not found\". It is\n  dnl also an optimization, to avoid performing a configure check whose result\n  dnl is not used. But it does not make the test of GNULIB_STDIO_H_SIGPIPE or\n  dnl GNULIB_SIGPIPE redundant.\n  m4_ifdef([gl_SIGNAL_SIGPIPE], [\n    gl_SIGNAL_SIGPIPE\n    if test $gl_cv_header_signal_h_SIGPIPE != yes; then\n      REPLACE_STDIO_WRITE_FUNCS=1\n      AC_LIBOBJ([stdio-write])\n    fi\n  ])\n  dnl This ifdef is necessary to avoid an error \"missing file lib/stdio-write.c\"\n  dnl \"expected source file, required through AC_LIBSOURCES, not found\". It is\n  dnl also an optimization, to avoid performing a configure check whose result\n  dnl is not used. But it does not make the test of GNULIB_STDIO_H_NONBLOCKING\n  dnl or GNULIB_NONBLOCKING redundant.\n  m4_ifdef([gl_NONBLOCKING_IO], [\n    gl_NONBLOCKING_IO\n    if test $gl_cv_have_nonblocking != yes; then\n      REPLACE_STDIO_WRITE_FUNCS=1\n      AC_LIBOBJ([stdio-write])\n    fi\n  ])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use, and which is not\n  dnl guaranteed by both C89 and C11.\n  gl_WARN_ON_USE_PREPARE([[#include <stdio.h>\n    ]], [dprintf fpurge fseeko ftello getdelim getline gets pclose popen\n    renameat snprintf tmpfile vdprintf vsnprintf])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n\n  AC_CHECK_DECLS_ONCE([fcloseall])\n  if test $ac_cv_have_decl_fcloseall = no; then\n    HAVE_DECL_FCLOSEALL=0\n  fi\n])\n\n# gl_STDIO_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_STDIO_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_STDIO_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCLOSE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPEN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFLUSH])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FGETC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FGETS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FOPEN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPURGE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPUTC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPUTS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREAD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREOPEN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSCANF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSEEK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSEEKO])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELLO])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FWRITE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCHAR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDELIM])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTCHAR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REMOVE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAMEAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SPRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_NONBLOCKING])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])\n    dnl Support Microsoft deprecated alias function names by default.\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FILENO], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETW], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_PUTW], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TEMPNAM], [1])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_STDIO_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_STDIO_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_DECL_FCLOSEALL=1;         AC_SUBST([HAVE_DECL_FCLOSEALL])\n  HAVE_DECL_FPURGE=1;            AC_SUBST([HAVE_DECL_FPURGE])\n  HAVE_DECL_FSEEKO=1;            AC_SUBST([HAVE_DECL_FSEEKO])\n  HAVE_DECL_FTELLO=1;            AC_SUBST([HAVE_DECL_FTELLO])\n  HAVE_DECL_GETDELIM=1;          AC_SUBST([HAVE_DECL_GETDELIM])\n  HAVE_DECL_GETLINE=1;           AC_SUBST([HAVE_DECL_GETLINE])\n  HAVE_DECL_OBSTACK_PRINTF=1;    AC_SUBST([HAVE_DECL_OBSTACK_PRINTF])\n  HAVE_DECL_SNPRINTF=1;          AC_SUBST([HAVE_DECL_SNPRINTF])\n  HAVE_DECL_VSNPRINTF=1;         AC_SUBST([HAVE_DECL_VSNPRINTF])\n  HAVE_DPRINTF=1;                AC_SUBST([HAVE_DPRINTF])\n  HAVE_FSEEKO=1;                 AC_SUBST([HAVE_FSEEKO])\n  HAVE_FTELLO=1;                 AC_SUBST([HAVE_FTELLO])\n  HAVE_PCLOSE=1;                 AC_SUBST([HAVE_PCLOSE])\n  HAVE_POPEN=1;                  AC_SUBST([HAVE_POPEN])\n  HAVE_RENAMEAT=1;               AC_SUBST([HAVE_RENAMEAT])\n  HAVE_VASPRINTF=1;              AC_SUBST([HAVE_VASPRINTF])\n  HAVE_VDPRINTF=1;               AC_SUBST([HAVE_VDPRINTF])\n  REPLACE_DPRINTF=0;             AC_SUBST([REPLACE_DPRINTF])\n  REPLACE_FCLOSE=0;              AC_SUBST([REPLACE_FCLOSE])\n  REPLACE_FDOPEN=0;              AC_SUBST([REPLACE_FDOPEN])\n  REPLACE_FFLUSH=0;              AC_SUBST([REPLACE_FFLUSH])\n  REPLACE_FOPEN=0;               AC_SUBST([REPLACE_FOPEN])\n  REPLACE_FPRINTF=0;             AC_SUBST([REPLACE_FPRINTF])\n  REPLACE_FPURGE=0;              AC_SUBST([REPLACE_FPURGE])\n  REPLACE_FREOPEN=0;             AC_SUBST([REPLACE_FREOPEN])\n  REPLACE_FSEEK=0;               AC_SUBST([REPLACE_FSEEK])\n  REPLACE_FSEEKO=0;              AC_SUBST([REPLACE_FSEEKO])\n  REPLACE_FTELL=0;               AC_SUBST([REPLACE_FTELL])\n  REPLACE_FTELLO=0;              AC_SUBST([REPLACE_FTELLO])\n  REPLACE_GETDELIM=0;            AC_SUBST([REPLACE_GETDELIM])\n  REPLACE_GETLINE=0;             AC_SUBST([REPLACE_GETLINE])\n  REPLACE_OBSTACK_PRINTF=0;      AC_SUBST([REPLACE_OBSTACK_PRINTF])\n  REPLACE_PERROR=0;              AC_SUBST([REPLACE_PERROR])\n  REPLACE_POPEN=0;               AC_SUBST([REPLACE_POPEN])\n  REPLACE_PRINTF=0;              AC_SUBST([REPLACE_PRINTF])\n  REPLACE_REMOVE=0;              AC_SUBST([REPLACE_REMOVE])\n  REPLACE_RENAME=0;              AC_SUBST([REPLACE_RENAME])\n  REPLACE_RENAMEAT=0;            AC_SUBST([REPLACE_RENAMEAT])\n  REPLACE_SNPRINTF=0;            AC_SUBST([REPLACE_SNPRINTF])\n  REPLACE_SPRINTF=0;             AC_SUBST([REPLACE_SPRINTF])\n  REPLACE_STDIO_READ_FUNCS=0;    AC_SUBST([REPLACE_STDIO_READ_FUNCS])\n  REPLACE_STDIO_WRITE_FUNCS=0;   AC_SUBST([REPLACE_STDIO_WRITE_FUNCS])\n  REPLACE_TMPFILE=0;             AC_SUBST([REPLACE_TMPFILE])\n  REPLACE_VASPRINTF=0;           AC_SUBST([REPLACE_VASPRINTF])\n  REPLACE_VDPRINTF=0;            AC_SUBST([REPLACE_VDPRINTF])\n  REPLACE_VFPRINTF=0;            AC_SUBST([REPLACE_VFPRINTF])\n  REPLACE_VPRINTF=0;             AC_SUBST([REPLACE_VPRINTF])\n  REPLACE_VSNPRINTF=0;           AC_SUBST([REPLACE_VSNPRINTF])\n  REPLACE_VSPRINTF=0;            AC_SUBST([REPLACE_VSPRINTF])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/stdlib_h.m4",
    "content": "# stdlib_h.m4 serial 63\ndnl Copyright (C) 2007-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN_ONCE([gl_STDLIB_H],\n[\n  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])\n  gl_NEXT_HEADERS([stdlib.h])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use, and which is not\n  dnl guaranteed by C89.\n  gl_WARN_ON_USE_PREPARE([[#include <stdlib.h>\n#if HAVE_SYS_LOADAVG_H\n/* OpenIndiana has a bug: <sys/time.h> must be included before\n   <sys/loadavg.h>.  */\n# include <sys/time.h>\n# include <sys/loadavg.h>\n#endif\n#if HAVE_RANDOM_H\n# include <random.h>\n#endif\n    ]], [_Exit aligned_alloc atoll canonicalize_file_name free\n    getloadavg getsubopt grantpt\n    initstate initstate_r mbtowc mkdtemp mkostemp mkostemps mkstemp mkstemps\n    posix_memalign posix_openpt ptsname ptsname_r qsort_r\n    random random_r reallocarray realpath rpmatch secure_getenv setenv\n    setstate setstate_r srandom srandom_r\n    strtod strtol strtold strtoll strtoul strtoull unlockpt unsetenv])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n\n  AC_CHECK_DECLS_ONCE([ecvt])\n  if test $ac_cv_have_decl_ecvt = no; then\n    HAVE_DECL_ECVT=0\n  fi\n  AC_CHECK_DECLS_ONCE([fcvt])\n  if test $ac_cv_have_decl_fcvt = no; then\n    HAVE_DECL_FCVT=0\n  fi\n  AC_CHECK_DECLS_ONCE([gcvt])\n  if test $ac_cv_have_decl_gcvt = no; then\n    HAVE_DECL_GCVT=0\n  fi\n])\n\n# gl_STDLIB_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_STDLIB_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_STDLIB_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB__EXIT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALIGNED_ALLOC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ATOLL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CALLOC_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CANONICALIZE_FILE_NAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREE_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOADAVG])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSUBOPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GRANTPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBTOWC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDTEMP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMPS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKSTEMP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKSTEMPS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POSIX_MEMALIGN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POSIX_OPENPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTENV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_QSORT_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOC_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALPATH])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RPMATCH])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOUL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOULL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYSTEM_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLOCKPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNSETENV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTOMB])\n    dnl Support Microsoft deprecated alias function names by default.\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ECVT], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCVT], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GCVT], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_MKTEMP], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_PUTENV], [1])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_STDLIB_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE__EXIT=1;              AC_SUBST([HAVE__EXIT])\n  HAVE_ALIGNED_ALLOC=1;      AC_SUBST([HAVE_ALIGNED_ALLOC])\n  HAVE_ATOLL=1;              AC_SUBST([HAVE_ATOLL])\n  HAVE_CANONICALIZE_FILE_NAME=1;  AC_SUBST([HAVE_CANONICALIZE_FILE_NAME])\n  HAVE_DECL_ECVT=1;          AC_SUBST([HAVE_DECL_ECVT])\n  HAVE_DECL_FCVT=1;          AC_SUBST([HAVE_DECL_FCVT])\n  HAVE_DECL_GCVT=1;          AC_SUBST([HAVE_DECL_GCVT])\n  HAVE_DECL_GETLOADAVG=1;    AC_SUBST([HAVE_DECL_GETLOADAVG])\n  HAVE_GETSUBOPT=1;          AC_SUBST([HAVE_GETSUBOPT])\n  HAVE_GRANTPT=1;            AC_SUBST([HAVE_GRANTPT])\n  HAVE_INITSTATE=1;          AC_SUBST([HAVE_INITSTATE])\n  HAVE_DECL_INITSTATE=1;     AC_SUBST([HAVE_DECL_INITSTATE])\n  HAVE_MBTOWC=1;             AC_SUBST([HAVE_MBTOWC])\n  HAVE_MKDTEMP=1;            AC_SUBST([HAVE_MKDTEMP])\n  HAVE_MKOSTEMP=1;           AC_SUBST([HAVE_MKOSTEMP])\n  HAVE_MKOSTEMPS=1;          AC_SUBST([HAVE_MKOSTEMPS])\n  HAVE_MKSTEMP=1;            AC_SUBST([HAVE_MKSTEMP])\n  HAVE_MKSTEMPS=1;           AC_SUBST([HAVE_MKSTEMPS])\n  HAVE_POSIX_MEMALIGN=1;     AC_SUBST([HAVE_POSIX_MEMALIGN])\n  HAVE_POSIX_OPENPT=1;       AC_SUBST([HAVE_POSIX_OPENPT])\n  HAVE_PTSNAME=1;            AC_SUBST([HAVE_PTSNAME])\n  HAVE_PTSNAME_R=1;          AC_SUBST([HAVE_PTSNAME_R])\n  HAVE_QSORT_R=1;            AC_SUBST([HAVE_QSORT_R])\n  HAVE_RANDOM=1;             AC_SUBST([HAVE_RANDOM])\n  HAVE_RANDOM_H=1;           AC_SUBST([HAVE_RANDOM_H])\n  HAVE_RANDOM_R=1;           AC_SUBST([HAVE_RANDOM_R])\n  HAVE_REALLOCARRAY=1;       AC_SUBST([HAVE_REALLOCARRAY])\n  HAVE_REALPATH=1;           AC_SUBST([HAVE_REALPATH])\n  HAVE_RPMATCH=1;            AC_SUBST([HAVE_RPMATCH])\n  HAVE_SECURE_GETENV=1;      AC_SUBST([HAVE_SECURE_GETENV])\n  HAVE_SETENV=1;             AC_SUBST([HAVE_SETENV])\n  HAVE_DECL_SETENV=1;        AC_SUBST([HAVE_DECL_SETENV])\n  HAVE_SETSTATE=1;           AC_SUBST([HAVE_SETSTATE])\n  HAVE_DECL_SETSTATE=1;      AC_SUBST([HAVE_DECL_SETSTATE])\n  HAVE_STRTOD=1;             AC_SUBST([HAVE_STRTOD])\n  HAVE_STRTOL=1;             AC_SUBST([HAVE_STRTOL])\n  HAVE_STRTOLD=1;            AC_SUBST([HAVE_STRTOLD])\n  HAVE_STRTOLL=1;            AC_SUBST([HAVE_STRTOLL])\n  HAVE_STRTOUL=1;            AC_SUBST([HAVE_STRTOUL])\n  HAVE_STRTOULL=1;           AC_SUBST([HAVE_STRTOULL])\n  HAVE_STRUCT_RANDOM_DATA=1; AC_SUBST([HAVE_STRUCT_RANDOM_DATA])\n  HAVE_SYS_LOADAVG_H=0;      AC_SUBST([HAVE_SYS_LOADAVG_H])\n  HAVE_UNLOCKPT=1;           AC_SUBST([HAVE_UNLOCKPT])\n  HAVE_DECL_UNSETENV=1;      AC_SUBST([HAVE_DECL_UNSETENV])\n  REPLACE_ALIGNED_ALLOC=0;   AC_SUBST([REPLACE_ALIGNED_ALLOC])\n  REPLACE_CALLOC=0;          AC_SUBST([REPLACE_CALLOC])\n  REPLACE_CANONICALIZE_FILE_NAME=0;  AC_SUBST([REPLACE_CANONICALIZE_FILE_NAME])\n  REPLACE_FREE=0;            AC_SUBST([REPLACE_FREE])\n  REPLACE_INITSTATE=0;       AC_SUBST([REPLACE_INITSTATE])\n  REPLACE_MALLOC=0;          AC_SUBST([REPLACE_MALLOC])\n  REPLACE_MBTOWC=0;          AC_SUBST([REPLACE_MBTOWC])\n  REPLACE_MKSTEMP=0;         AC_SUBST([REPLACE_MKSTEMP])\n  REPLACE_POSIX_MEMALIGN=0;  AC_SUBST([REPLACE_POSIX_MEMALIGN])\n  REPLACE_PTSNAME=0;         AC_SUBST([REPLACE_PTSNAME])\n  REPLACE_PTSNAME_R=0;       AC_SUBST([REPLACE_PTSNAME_R])\n  REPLACE_PUTENV=0;          AC_SUBST([REPLACE_PUTENV])\n  REPLACE_QSORT_R=0;         AC_SUBST([REPLACE_QSORT_R])\n  REPLACE_RANDOM=0;          AC_SUBST([REPLACE_RANDOM])\n  REPLACE_RANDOM_R=0;        AC_SUBST([REPLACE_RANDOM_R])\n  REPLACE_REALLOC=0;         AC_SUBST([REPLACE_REALLOC])\n  REPLACE_REALLOCARRAY=0;    AC_SUBST([REPLACE_REALLOCARRAY])\n  REPLACE_REALPATH=0;        AC_SUBST([REPLACE_REALPATH])\n  REPLACE_SETENV=0;          AC_SUBST([REPLACE_SETENV])\n  REPLACE_SETSTATE=0;        AC_SUBST([REPLACE_SETSTATE])\n  REPLACE_STRTOD=0;          AC_SUBST([REPLACE_STRTOD])\n  REPLACE_STRTOL=0;          AC_SUBST([REPLACE_STRTOL])\n  REPLACE_STRTOLD=0;         AC_SUBST([REPLACE_STRTOLD])\n  REPLACE_STRTOLL=0;         AC_SUBST([REPLACE_STRTOLL])\n  REPLACE_STRTOUL=0;         AC_SUBST([REPLACE_STRTOUL])\n  REPLACE_STRTOULL=0;        AC_SUBST([REPLACE_STRTOULL])\n  REPLACE_UNSETENV=0;        AC_SUBST([REPLACE_UNSETENV])\n  REPLACE_WCTOMB=0;          AC_SUBST([REPLACE_WCTOMB])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_resource_h.m4",
    "content": "# sys_resource_h.m4 serial 5\ndnl Copyright (C) 2012-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN_ONCE([gl_SYS_RESOURCE_H],\n[\n  AC_REQUIRE([gl_SYS_RESOURCE_H_DEFAULTS])\n  dnl <sys/resource.h> is always overridden, because of GNULIB_POSIXCHECK.\n  gl_CHECK_NEXT_HEADERS([sys/resource.h])\n  if test $ac_cv_header_sys_resource_h = yes; then\n    HAVE_SYS_RESOURCE_H=1\n  else\n    HAVE_SYS_RESOURCE_H=0\n  fi\n  AC_SUBST([HAVE_SYS_RESOURCE_H])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[\n#if HAVE_SYS_RESOURCE_H\n/* At least FreeBSD 5.0 needs extra headers before <sys/resource.h>\n   will compile.  */\n# include <sys/types.h>\n# include <sys/time.h>\n# include <sys/resource.h>\n#endif\n    ]],\n    [getrusage])\n])\n\n# gl_SYS_RESOURCE_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_RESOURCE_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_RESOURCE_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_RESOURCE_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_RESOURCE_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETRUSAGE])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_RESOURCE_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_RESOURCE_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_RESOURCE_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_GETRUSAGE=1;       AC_SUBST([HAVE_GETRUSAGE])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_socket_h.m4",
    "content": "# sys_socket_h.m4 serial 28\ndnl Copyright (C) 2005-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Simon Josefsson.\n\nAC_DEFUN_ONCE([gl_SYS_SOCKET_H],\n[\n  AC_REQUIRE([gl_SYS_SOCKET_H_DEFAULTS])\n  AC_REQUIRE([AC_CANONICAL_HOST])\n\n  dnl On OSF/1, the functions recv(), send(), recvfrom(), sendto() have\n  dnl old-style declarations (with return type 'int' instead of 'ssize_t')\n  dnl unless _POSIX_PII_SOCKET is defined.\n  case \"$host_os\" in\n    osf*)\n      AC_DEFINE([_POSIX_PII_SOCKET], [1],\n        [Define to 1 in order to get the POSIX compatible declarations\n         of socket functions.])\n      ;;\n  esac\n\n  AC_CACHE_CHECK([whether <sys/socket.h> is self-contained],\n    [gl_cv_header_sys_socket_h_selfcontained],\n    [\n      AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]], [[]])],\n        [gl_cv_header_sys_socket_h_selfcontained=yes],\n        [gl_cv_header_sys_socket_h_selfcontained=no])\n    ])\n  if test $gl_cv_header_sys_socket_h_selfcontained = yes; then\n    dnl If the shutdown function exists, <sys/socket.h> should define\n    dnl SHUT_RD, SHUT_WR, SHUT_RDWR.\n    AC_CHECK_FUNCS([shutdown])\n    if test $ac_cv_func_shutdown = yes; then\n      AC_CACHE_CHECK([whether <sys/socket.h> defines the SHUT_* macros],\n        [gl_cv_header_sys_socket_h_shut],\n        [\n          AC_COMPILE_IFELSE(\n            [AC_LANG_PROGRAM([[#include <sys/socket.h>]],\n               [[int a[] = { SHUT_RD, SHUT_WR, SHUT_RDWR };]])],\n            [gl_cv_header_sys_socket_h_shut=yes],\n            [gl_cv_header_sys_socket_h_shut=no])\n        ])\n      if test $gl_cv_header_sys_socket_h_shut = no; then\n        SYS_SOCKET_H='sys/socket.h'\n      fi\n    fi\n  fi\n  # We need to check for ws2tcpip.h now.\n  gl_PREREQ_SYS_H_SOCKET\n  AC_CHECK_TYPES([struct sockaddr_storage, sa_family_t],,,[\n  /* sys/types.h is not needed according to POSIX, but the\n     sys/socket.h in i386-unknown-freebsd4.10 and\n     powerpc-apple-darwin5.5 required it. */\n#include <sys/types.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n#ifdef HAVE_WS2TCPIP_H\n#include <ws2tcpip.h>\n#endif\n])\n  if test $ac_cv_type_struct_sockaddr_storage = no; then\n    HAVE_STRUCT_SOCKADDR_STORAGE=0\n  fi\n  if test $ac_cv_type_sa_family_t = no; then\n    HAVE_SA_FAMILY_T=0\n  fi\n  if test $ac_cv_type_struct_sockaddr_storage != no; then\n    AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family],\n      [],\n      [HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=0],\n      [#include <sys/types.h>\n       #ifdef HAVE_SYS_SOCKET_H\n       #include <sys/socket.h>\n       #endif\n       #ifdef HAVE_WS2TCPIP_H\n       #include <ws2tcpip.h>\n       #endif\n      ])\n  fi\n  if test $HAVE_STRUCT_SOCKADDR_STORAGE = 0 || test $HAVE_SA_FAMILY_T = 0 \\\n     || test $HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = 0; then\n    SYS_SOCKET_H='sys/socket.h'\n  fi\n  gl_PREREQ_SYS_H_WINSOCK2\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[\n/* Some systems require prerequisite headers.  */\n#include <sys/types.h>\n#include <sys/socket.h>\n    ]], [socket connect accept bind getpeername getsockname getsockopt\n    listen recv send recvfrom sendto setsockopt shutdown accept4])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n])\n\nAC_DEFUN([gl_PREREQ_SYS_H_SOCKET],\n[\n  dnl Check prerequisites of the <sys/socket.h> replacement.\n  AC_REQUIRE([gl_CHECK_SOCKET_HEADERS])\n  gl_CHECK_NEXT_HEADERS([sys/socket.h])\n  if test $ac_cv_header_sys_socket_h = yes; then\n    HAVE_SYS_SOCKET_H=1\n  else\n    HAVE_SYS_SOCKET_H=0\n  fi\n  AC_SUBST([HAVE_SYS_SOCKET_H])\n  gl_PREREQ_SYS_H_WS2TCPIP\n])\n\n# Common prerequisites of the <sys/socket.h> replacement and of the\n# <sys/select.h> replacement.\n# Sets and substitutes HAVE_WINSOCK2_H.\nAC_DEFUN([gl_PREREQ_SYS_H_WINSOCK2],\n[\n  m4_ifdef([gl_UNISTD_H_DEFAULTS], [AC_REQUIRE([gl_UNISTD_H_DEFAULTS])])\n  m4_ifdef([gl_SYS_IOCTL_H_DEFAULTS], [AC_REQUIRE([gl_SYS_IOCTL_H_DEFAULTS])])\n  AC_CHECK_HEADERS_ONCE([sys/socket.h])\n  if test $ac_cv_header_sys_socket_h != yes; then\n    dnl We cannot use AC_CHECK_HEADERS_ONCE here, because that would make\n    dnl the check for those headers unconditional; yet cygwin reports\n    dnl that the headers are present but cannot be compiled (since on\n    dnl cygwin, all socket information should come from sys/socket.h).\n    AC_CHECK_HEADERS([winsock2.h])\n  fi\n  if test \"$ac_cv_header_winsock2_h\" = yes; then\n    HAVE_WINSOCK2_H=1\n    UNISTD_H_HAVE_WINSOCK2_H=1\n    SYS_IOCTL_H_HAVE_WINSOCK2_H=1\n  else\n    HAVE_WINSOCK2_H=0\n  fi\n  AC_SUBST([HAVE_WINSOCK2_H])\n])\n\n# Common prerequisites of the <sys/socket.h> replacement and of the\n# <arpa/inet.h> replacement.\n# Sets and substitutes HAVE_WS2TCPIP_H.\nAC_DEFUN([gl_PREREQ_SYS_H_WS2TCPIP],\n[\n  AC_REQUIRE([gl_CHECK_SOCKET_HEADERS])\n  if test $ac_cv_header_sys_socket_h = yes; then\n    HAVE_WS2TCPIP_H=0\n  else\n    if test $ac_cv_header_ws2tcpip_h = yes; then\n      HAVE_WS2TCPIP_H=1\n    else\n      HAVE_WS2TCPIP_H=0\n    fi\n  fi\n  AC_SUBST([HAVE_WS2TCPIP_H])\n])\n\n# gl_SYS_SOCKET_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_SOCKET_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_SOCKET_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_SOCKET_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_SOCKET_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SOCKET])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CONNECT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCEPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_BIND])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPEERNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSOCKNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSOCKOPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LISTEN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RECV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SEND])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RECVFROM])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SENDTO])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETSOCKOPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SHUTDOWN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCEPT4])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_SOCKET_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_SOCKET_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_SOCKET_H_DEFAULTS],\n[\n  HAVE_STRUCT_SOCKADDR_STORAGE=1; AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE])\n  HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=1;\n                        AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY])\n  HAVE_SA_FAMILY_T=1;   AC_SUBST([HAVE_SA_FAMILY_T])\n  HAVE_ACCEPT4=1;       AC_SUBST([HAVE_ACCEPT4])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_stat_h.m4",
    "content": "# sys_stat_h.m4 serial 41   -*- Autoconf -*-\ndnl Copyright (C) 2006-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Eric Blake.\ndnl Provide a GNU-like <sys/stat.h>.\n\nAC_DEFUN_ONCE([gl_SYS_STAT_H],\n[\n  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])\n\n  dnl Check for broken stat macros.\n  AC_REQUIRE([AC_HEADER_STAT])\n\n  gl_CHECK_NEXT_HEADERS([sys/stat.h])\n\n  dnl Ensure the type mode_t gets defined.\n  AC_REQUIRE([AC_TYPE_MODE_T])\n\n  dnl Whether to enable precise timestamps in 'struct stat'.\n  m4_ifdef([gl_WINDOWS_STAT_TIMESPEC], [\n    AC_REQUIRE([gl_WINDOWS_STAT_TIMESPEC])\n  ], [\n    WINDOWS_STAT_TIMESPEC=0\n  ])\n  AC_SUBST([WINDOWS_STAT_TIMESPEC])\n\n  dnl Whether to ensure that struct stat.st_size is 64-bit wide.\n  m4_ifdef([gl_LARGEFILE], [\n    AC_REQUIRE([gl_LARGEFILE])\n  ], [\n    WINDOWS_64_BIT_ST_SIZE=0\n  ])\n  AC_SUBST([WINDOWS_64_BIT_ST_SIZE])\n\n  dnl Define types that are supposed to be defined in <sys/types.h> or\n  dnl <sys/stat.h>.\n  AC_CHECK_TYPE([nlink_t], [],\n    [AC_DEFINE([nlink_t], [int],\n       [Define to the type of st_nlink in struct stat, or a supertype.])],\n    [#include <sys/types.h>\n     #include <sys/stat.h>])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[#include <sys/stat.h>\n    ]], [fchmodat fstat fstatat futimens getumask lchmod lstat\n    mkdirat mkfifo mkfifoat mknod mknodat stat utimensat])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n])\n\n# gl_SYS_STAT_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_STAT_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_STAT_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_STAT_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_UNISTD_H_REQUIRE_DEFAULTS dnl for REPLACE_FCHDIR\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHMODAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTATAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FUTIMENS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETUMASK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LCHMOD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LSTAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDIR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDIRAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKFIFO])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKFIFOAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKNOD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKNODAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UTIMENSAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OVERRIDES_STRUCT_STAT])\n    dnl Support Microsoft deprecated alias function names by default.\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CHMOD], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_MKDIR], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_UMASK], [1])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_STAT_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_FCHMODAT=1;      AC_SUBST([HAVE_FCHMODAT])\n  HAVE_FSTATAT=1;       AC_SUBST([HAVE_FSTATAT])\n  HAVE_FUTIMENS=1;      AC_SUBST([HAVE_FUTIMENS])\n  HAVE_GETUMASK=1;      AC_SUBST([HAVE_GETUMASK])\n  HAVE_LCHMOD=1;        AC_SUBST([HAVE_LCHMOD])\n  HAVE_LSTAT=1;         AC_SUBST([HAVE_LSTAT])\n  HAVE_MKDIRAT=1;       AC_SUBST([HAVE_MKDIRAT])\n  HAVE_MKFIFO=1;        AC_SUBST([HAVE_MKFIFO])\n  HAVE_MKFIFOAT=1;      AC_SUBST([HAVE_MKFIFOAT])\n  HAVE_MKNOD=1;         AC_SUBST([HAVE_MKNOD])\n  HAVE_MKNODAT=1;       AC_SUBST([HAVE_MKNODAT])\n  HAVE_UTIMENSAT=1;     AC_SUBST([HAVE_UTIMENSAT])\n  REPLACE_FCHMODAT=0;   AC_SUBST([REPLACE_FCHMODAT])\n  REPLACE_FSTAT=0;      AC_SUBST([REPLACE_FSTAT])\n  REPLACE_FSTATAT=0;    AC_SUBST([REPLACE_FSTATAT])\n  REPLACE_FUTIMENS=0;   AC_SUBST([REPLACE_FUTIMENS])\n  REPLACE_LSTAT=0;      AC_SUBST([REPLACE_LSTAT])\n  REPLACE_MKDIR=0;      AC_SUBST([REPLACE_MKDIR])\n  REPLACE_MKFIFO=0;     AC_SUBST([REPLACE_MKFIFO])\n  REPLACE_MKFIFOAT=0;   AC_SUBST([REPLACE_MKFIFOAT])\n  REPLACE_MKNOD=0;      AC_SUBST([REPLACE_MKNOD])\n  REPLACE_MKNODAT=0;    AC_SUBST([REPLACE_MKNODAT])\n  REPLACE_STAT=0;       AC_SUBST([REPLACE_STAT])\n  REPLACE_UTIMENSAT=0;  AC_SUBST([REPLACE_UTIMENSAT])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_time_h.m4",
    "content": "# Configure a replacement for <sys/time.h>.\n# serial 12\n\n# Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# Written by Paul Eggert and Martin Lambers.\n\nAC_DEFUN_ONCE([gl_SYS_TIME_H],\n[\n  dnl Use AC_REQUIRE here, so that the REPLACE_GETTIMEOFDAY=0 statement\n  dnl below is expanded once only, before all REPLACE_GETTIMEOFDAY=1\n  dnl statements that occur in other macros.\n  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])\n  AC_REQUIRE([AC_C_RESTRICT])\n  AC_CHECK_HEADERS_ONCE([sys/time.h])\n  gl_CHECK_NEXT_HEADERS([sys/time.h])\n\n  if test $ac_cv_header_sys_time_h != yes; then\n    HAVE_SYS_TIME_H=0\n  fi\n\n  dnl On native Windows with MSVC, 'struct timeval' is defined in <winsock2.h>\n  dnl only. So include that header in the list.\n  gl_PREREQ_SYS_H_WINSOCK2\n  AC_CACHE_CHECK([for struct timeval], [gl_cv_sys_struct_timeval],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#if HAVE_SYS_TIME_H\n             #include <sys/time.h>\n            #endif\n            #include <time.h>\n            #if HAVE_WINSOCK2_H\n            # include <winsock2.h>\n            #endif\n          ]],\n          [[static struct timeval x; x.tv_sec = x.tv_usec;]])],\n       [gl_cv_sys_struct_timeval=yes],\n       [gl_cv_sys_struct_timeval=no])\n    ])\n  if test $gl_cv_sys_struct_timeval != yes; then\n    HAVE_STRUCT_TIMEVAL=0\n  else\n    dnl On native Windows with a 64-bit 'time_t', 'struct timeval' is defined\n    dnl (in <sys/time.h> and <winsock2.h> for mingw64, in <winsock2.h> only\n    dnl for MSVC) with a tv_sec field of type 'long' (32-bit!), which is\n    dnl smaller than the 'time_t' type mandated by POSIX.\n    dnl On OpenBSD 5.1 amd64, tv_sec is 64 bits and time_t 32 bits, but\n    dnl that is good enough.\n    AC_CACHE_CHECK([for wide-enough struct timeval.tv_sec member],\n      [gl_cv_sys_struct_timeval_tv_sec],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[#if HAVE_SYS_TIME_H\n               #include <sys/time.h>\n              #endif\n              #include <time.h>\n              #if HAVE_WINSOCK2_H\n              # include <winsock2.h>\n              #endif\n            ]],\n            [[static struct timeval x;\n              typedef int verify_tv_sec_type[\n                sizeof (time_t) <= sizeof x.tv_sec ? 1 : -1\n              ];\n            ]])],\n         [gl_cv_sys_struct_timeval_tv_sec=yes],\n         [gl_cv_sys_struct_timeval_tv_sec=no])\n      ])\n    if test $gl_cv_sys_struct_timeval_tv_sec != yes; then\n      REPLACE_STRUCT_TIMEVAL=1\n    fi\n  fi\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[\n#if HAVE_SYS_TIME_H\n# include <sys/time.h>\n#endif\n#include <time.h>\n    ]], [gettimeofday])\n])\n\n# gl_SYS_TIME_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_TIME_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_TIME_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_TIME_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_TIME_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETTIMEOFDAY])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_TIME_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_TIME_H_DEFAULTS],\n[\n  dnl Assume POSIX behavior unless another module says otherwise.\n  HAVE_GETTIMEOFDAY=1;       AC_SUBST([HAVE_GETTIMEOFDAY])\n  HAVE_STRUCT_TIMEVAL=1;     AC_SUBST([HAVE_STRUCT_TIMEVAL])\n  HAVE_SYS_TIME_H=1;         AC_SUBST([HAVE_SYS_TIME_H])\n  REPLACE_GETTIMEOFDAY=0;    AC_SUBST([REPLACE_GETTIMEOFDAY])\n  REPLACE_STRUCT_TIMEVAL=0;  AC_SUBST([REPLACE_STRUCT_TIMEVAL])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_types_h.m4",
    "content": "# sys_types_h.m4 serial 13\ndnl Copyright (C) 2011-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN_ONCE([gl_SYS_TYPES_H],\n[\n  AC_REQUIRE([gl_SYS_TYPES_H_DEFAULTS])\n\n  dnl Use sane struct stat types in OpenVMS 8.2 and later.\n  AC_DEFINE([_USE_STD_STAT], 1, [For standard stat data types on VMS.])\n\n  gl_NEXT_HEADERS([sys/types.h])\n\n  dnl Ensure the type pid_t gets defined.\n  AC_REQUIRE([AC_TYPE_PID_T])\n\n  dnl Ensure the type mode_t gets defined.\n  AC_REQUIRE([AC_TYPE_MODE_T])\n\n  dnl Whether to override the 'off_t' type.\n  AC_REQUIRE([gl_TYPE_OFF_T])\n\n  dnl Whether to override the 'dev_t' and 'ino_t' types.\n  m4_ifdef([gl_WINDOWS_STAT_INODES], [\n    AC_REQUIRE([gl_WINDOWS_STAT_INODES])\n  ], [\n    WINDOWS_STAT_INODES=0\n  ])\n  AC_SUBST([WINDOWS_STAT_INODES])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_TYPES_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_TYPE_H_MODULE_INDICATOR_DEFAULTS], [\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_TYPE_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_TYPES_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_TYPES_H_DEFAULTS],\n[\n])\n\n# This works around a buggy version in autoconf <= 2.69.\n# See <https://lists.gnu.org/r/autoconf/2016-08/msg00014.html>\n# The 2.70 version isn't quoted properly, so override it too.\n\nm4_version_prereq([2.70.1], [], [\n\nm4_undefine([AC_HEADER_MAJOR])\nAC_DEFUN([AC_HEADER_MAJOR],\n[AC_CHECK_HEADERS_ONCE([sys/types.h])\nAC_CHECK_HEADER([sys/mkdev.h],\n                [AC_DEFINE([MAJOR_IN_MKDEV], [1],\n                           [Define to 1 if `major', `minor', and `makedev' are\n                            declared in <mkdev.h>.])])\nif test $ac_cv_header_sys_mkdev_h = no; then\n  AC_CHECK_HEADER([sys/sysmacros.h],\n                  [AC_DEFINE([MAJOR_IN_SYSMACROS], [1],\n                             [Define to 1 if `major', `minor', and `makedev'\n                              are declared in <sysmacros.h>.])])\nfi\n])# AC_HEADER_MAJOR\n\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_uio_h.m4",
    "content": "# sys_uio_h.m4 serial 3\ndnl Copyright (C) 2011-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN_ONCE([gl_SYS_UIO_H],\n[\n  AC_REQUIRE([gl_SYS_UIO_H_DEFAULTS])\n  dnl <sys/uio.h> is always overridden, because of GNULIB_POSIXCHECK.\n  gl_CHECK_NEXT_HEADERS([sys/uio.h])\n  if test $ac_cv_header_sys_uio_h = yes; then\n    HAVE_SYS_UIO_H=1\n  else\n    HAVE_SYS_UIO_H=0\n  fi\n  AC_SUBST([HAVE_SYS_UIO_H])\n])\n\n# gl_SYS_UIO_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_UIO_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_UIO_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_UIO_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_UIO_H_MODULE_INDICATOR_DEFAULTS], [\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_UIO_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_UIO_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_UIO_H_DEFAULTS],\n[\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/sys_utsname_h.m4",
    "content": "# sys_utsname_h.m4 serial 11\ndnl Copyright (C) 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl Written by Bruno Haible.\n\nAC_DEFUN_ONCE([gl_SYS_UTSNAME_H],\n[\n  dnl Ensure to expand the default settings once only, before all statements\n  dnl that occur in other macros.\n  AC_REQUIRE([gl_SYS_UTSNAME_H_DEFAULTS])\n\n  dnl <sys/utsname.h> is always overridden, because of GNULIB_POSIXCHECK.\n  gl_CHECK_NEXT_HEADERS([sys/utsname.h])\n  if test $ac_cv_header_sys_utsname_h != yes; then\n    HAVE_SYS_UTSNAME_H=0\n    HAVE_STRUCT_UTSNAME=0\n  else\n    HAVE_SYS_UTSNAME_H=1\n    AC_CHECK_TYPES([struct utsname], [], [HAVE_STRUCT_UTSNAME=0], [[\n/* Minix 3.1.8 has a bug: <stddef.h> must be included before\n   <sys/utsname.h>.  */\n#include <stddef.h>\n#include <sys/utsname.h>\n      ]])\n  fi\n  AC_SUBST([HAVE_SYS_UTSNAME_H])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[\n    /* Minix 3.1.8 has a bug: <stddef.h> must be included before\n       <sys/utsname.h>.  */\n    #include <stddef.h>\n    #include <sys/utsname.h>\n    ]], [uname])\n])\n\n# gl_SYS_UTSNAME_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_SYS_UTSNAME_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_SYS_UTSNAME_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_SYS_UTSNAME_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_UTSNAME_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNAME])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_UTSNAME_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_SYS_UTSNAME_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_SYS_UTSNAME_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_UNAME=1;           AC_SUBST([HAVE_UNAME])\n  HAVE_STRUCT_UTSNAME=1;  AC_SUBST([HAVE_STRUCT_UTSNAME])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/time_h.m4",
    "content": "# Configure a more-standard replacement for <time.h>.\n\n# Copyright (C) 2000-2001, 2003-2007, 2009-2021 Free Software Foundation, Inc.\n\n# serial 18\n\n# This file is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# Written by Paul Eggert and Jim Meyering.\n\nAC_DEFUN_ONCE([gl_TIME_H],\n[\n  dnl Ensure to expand the default settings once only, before all statements\n  dnl that occur in other macros.\n  AC_REQUIRE([gl_TIME_H_DEFAULTS])\n\n  gl_NEXT_HEADERS([time.h])\n  AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n\n  AC_CACHE_CHECK([for TIME_UTC in <time.h>],\n    [gl_cv_time_h_has_TIME_UTC],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <time.h>\n          ]],\n          [[static int x = TIME_UTC; x++;]])],\n       [gl_cv_time_h_has_TIME_UTC=yes],\n       [gl_cv_time_h_has_TIME_UTC=no])])\n  if test $gl_cv_time_h_has_TIME_UTC = yes; then\n    TIME_H_DEFINES_TIME_UTC=1\n  else\n    TIME_H_DEFINES_TIME_UTC=0\n  fi\n  AC_SUBST([TIME_H_DEFINES_TIME_UTC])\n])\n\ndnl Check whether 'struct timespec' is declared\ndnl in time.h, sys/time.h, pthread.h, or unistd.h.\n\nAC_DEFUN([gl_CHECK_TYPE_STRUCT_TIMESPEC],\n[\n  AC_CHECK_HEADERS_ONCE([sys/time.h])\n  AC_CACHE_CHECK([for struct timespec in <time.h>],\n    [gl_cv_sys_struct_timespec_in_time_h],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <time.h>\n          ]],\n          [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],\n       [gl_cv_sys_struct_timespec_in_time_h=yes],\n       [gl_cv_sys_struct_timespec_in_time_h=no])])\n\n  TIME_H_DEFINES_STRUCT_TIMESPEC=0\n  SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0\n  PTHREAD_H_DEFINES_STRUCT_TIMESPEC=0\n  UNISTD_H_DEFINES_STRUCT_TIMESPEC=0\n  if test $gl_cv_sys_struct_timespec_in_time_h = yes; then\n    TIME_H_DEFINES_STRUCT_TIMESPEC=1\n  else\n    AC_CACHE_CHECK([for struct timespec in <sys/time.h>],\n      [gl_cv_sys_struct_timespec_in_sys_time_h],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[#include <sys/time.h>\n            ]],\n            [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],\n         [gl_cv_sys_struct_timespec_in_sys_time_h=yes],\n         [gl_cv_sys_struct_timespec_in_sys_time_h=no])])\n    if test $gl_cv_sys_struct_timespec_in_sys_time_h = yes; then\n      SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1\n    else\n      AC_CACHE_CHECK([for struct timespec in <pthread.h>],\n        [gl_cv_sys_struct_timespec_in_pthread_h],\n        [AC_COMPILE_IFELSE(\n           [AC_LANG_PROGRAM(\n              [[#include <pthread.h>\n              ]],\n              [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],\n           [gl_cv_sys_struct_timespec_in_pthread_h=yes],\n           [gl_cv_sys_struct_timespec_in_pthread_h=no])])\n      if test $gl_cv_sys_struct_timespec_in_pthread_h = yes; then\n        PTHREAD_H_DEFINES_STRUCT_TIMESPEC=1\n      else\n        AC_CACHE_CHECK([for struct timespec in <unistd.h>],\n          [gl_cv_sys_struct_timespec_in_unistd_h],\n          [AC_COMPILE_IFELSE(\n             [AC_LANG_PROGRAM(\n                [[#include <unistd.h>\n                ]],\n                [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],\n             [gl_cv_sys_struct_timespec_in_unistd_h=yes],\n             [gl_cv_sys_struct_timespec_in_unistd_h=no])])\n        if test $gl_cv_sys_struct_timespec_in_unistd_h = yes; then\n          UNISTD_H_DEFINES_STRUCT_TIMESPEC=1\n        fi\n      fi\n    fi\n  fi\n  AC_SUBST([TIME_H_DEFINES_STRUCT_TIMESPEC])\n  AC_SUBST([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC])\n  AC_SUBST([PTHREAD_H_DEFINES_STRUCT_TIMESPEC])\n  AC_SUBST([UNISTD_H_DEFINES_STRUCT_TIMESPEC])\n])\n\n# gl_TIME_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_TIME_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_TIME_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_TIME_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CTIME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKTIME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALTIME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NANOSLEEP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRFTIME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPTIME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMEGM])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GET])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_RZ])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZSET])\n    dnl Support Microsoft deprecated alias function names by default.\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TZSET], [1])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_TIME_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_TIME_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_TIME_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_DECL_LOCALTIME_R=1;               AC_SUBST([HAVE_DECL_LOCALTIME_R])\n  HAVE_NANOSLEEP=1;                      AC_SUBST([HAVE_NANOSLEEP])\n  HAVE_STRPTIME=1;                       AC_SUBST([HAVE_STRPTIME])\n  HAVE_TIMEGM=1;                         AC_SUBST([HAVE_TIMEGM])\n  HAVE_TIMESPEC_GET=1;                   AC_SUBST([HAVE_TIMESPEC_GET])\n  dnl Even GNU libc does not have timezone_t yet.\n  HAVE_TIMEZONE_T=0;                     AC_SUBST([HAVE_TIMEZONE_T])\n  dnl If another module says to replace or to not replace, do that.\n  dnl Otherwise, replace only if someone compiles with -DGNULIB_PORTCHECK;\n  dnl this lets maintainers check for portability.\n  REPLACE_CTIME=GNULIB_PORTCHECK;        AC_SUBST([REPLACE_CTIME])\n  REPLACE_LOCALTIME_R=GNULIB_PORTCHECK;  AC_SUBST([REPLACE_LOCALTIME_R])\n  REPLACE_MKTIME=GNULIB_PORTCHECK;       AC_SUBST([REPLACE_MKTIME])\n  REPLACE_NANOSLEEP=GNULIB_PORTCHECK;    AC_SUBST([REPLACE_NANOSLEEP])\n  REPLACE_STRFTIME=GNULIB_PORTCHECK;     AC_SUBST([REPLACE_STRFTIME])\n  REPLACE_TIMEGM=GNULIB_PORTCHECK;       AC_SUBST([REPLACE_TIMEGM])\n  REPLACE_TZSET=GNULIB_PORTCHECK;        AC_SUBST([REPLACE_TZSET])\n\n  dnl Hack so that the time module doesn't depend on the sys_time module.\n  dnl First, default GNULIB_GETTIMEOFDAY to 0 if sys_time is absent.\n  : ${GNULIB_GETTIMEOFDAY=0};            AC_SUBST([GNULIB_GETTIMEOFDAY])\n  dnl Second, it's OK to not use GNULIB_PORTCHECK for REPLACE_GMTIME\n  dnl and REPLACE_LOCALTIME, as portability to Solaris 2.6 and earlier\n  dnl is no longer a big deal.\n  REPLACE_GMTIME=0;                      AC_SUBST([REPLACE_GMTIME])\n  REPLACE_LOCALTIME=0;                   AC_SUBST([REPLACE_LOCALTIME])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/time_r.m4",
    "content": "dnl Reentrant time functions: localtime_r, gmtime_r.\n\ndnl Copyright (C) 2003, 2006-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl Written by Paul Eggert.\n\nAC_DEFUN([gl_TIME_R],\n[\n  dnl Persuade glibc and Solaris <time.h> to declare localtime_r.\n  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])\n\n  AC_REQUIRE([gl_TIME_H_DEFAULTS])\n  AC_REQUIRE([AC_C_RESTRICT])\n\n  dnl Some systems don't declare localtime_r() and gmtime_r() if _REENTRANT is\n  dnl not defined.\n  AC_CHECK_DECLS([localtime_r], [], [],\n    [[/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n         gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n         been included before.  */\n      #if defined __MINGW32__\n      # include <unistd.h>\n      #endif\n      #include <time.h>\n    ]])\n  if test $ac_cv_have_decl_localtime_r = no; then\n    HAVE_DECL_LOCALTIME_R=0\n  fi\n\n  AC_CHECK_FUNCS_ONCE([localtime_r])\n  if test $ac_cv_func_localtime_r = yes; then\n    HAVE_LOCALTIME_R=1\n    AC_CACHE_CHECK([whether localtime_r is compatible with its POSIX signature],\n      [gl_cv_time_r_posix],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n                 gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n                 been included before.  */\n              #if defined __MINGW32__\n              # include <unistd.h>\n              #endif\n              #include <time.h>\n            ]],\n            [[/* We don't need to append 'restrict's to the argument types,\n                 even though the POSIX signature has the 'restrict's,\n                 since C99 says they can't affect type compatibility.  */\n              struct tm * (*ptr) (time_t const *, struct tm *) = localtime_r;\n              if (ptr) return 0;\n              /* Check the return type is a pointer.\n                 On HP-UX 10 it is 'int'.  */\n              *localtime_r (0, 0);]])\n         ],\n         [gl_cv_time_r_posix=yes],\n         [gl_cv_time_r_posix=no])\n      ])\n    if test $gl_cv_time_r_posix = yes; then\n      REPLACE_LOCALTIME_R=0\n    else\n      REPLACE_LOCALTIME_R=1\n    fi\n  else\n    HAVE_LOCALTIME_R=0\n    dnl On mingw, localtime_r() is defined as an inline function; use through a\n    dnl direct function call works but the use as a function pointer leads to a\n    dnl link error.\n    AC_CACHE_CHECK([whether localtime_r exists as an inline function],\n      [gl_cv_func_localtime_r_inline],\n      [AC_LINK_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[/* mingw's <time.h> provides the functions asctime_r, ctime_r,\n                 gmtime_r, localtime_r only if <unistd.h> or <pthread.h> has\n                 been included before.  */\n              #if defined __MINGW32__\n              # include <unistd.h>\n              #endif\n              #include <time.h>\n            ]],\n            [[time_t a;\n              struct tm r;\n              localtime_r (&a, &r);\n            ]])\n         ],\n         [gl_cv_func_localtime_r_inline=yes],\n         [gl_cv_func_localtime_r_inline=no])\n      ])\n    if test $gl_cv_func_localtime_r_inline = yes; then\n      REPLACE_LOCALTIME_R=1\n    fi\n  fi\n])\n\n# Prerequisites of lib/time_r.c.\nAC_DEFUN([gl_PREREQ_TIME_R], [\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/uname.m4",
    "content": "# uname.m4 serial 11\ndnl Copyright (C) 2009-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\nAC_DEFUN([gl_FUNC_UNAME],\n[\n  AC_REQUIRE([gl_SYS_UTSNAME_H_DEFAULTS])\n  AC_CHECK_FUNCS([uname])\n  if test $ac_cv_func_uname = no; then\n    HAVE_UNAME=0\n  fi\n])\n\n# Prerequisites of lib/uname.c.\nAC_DEFUN([gl_PREREQ_UNAME], [\n  :\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/unistd_h.m4",
    "content": "# unistd_h.m4 serial 89\ndnl Copyright (C) 2006-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl Written by Simon Josefsson, Bruno Haible.\n\nAC_DEFUN_ONCE([gl_UNISTD_H],\n[\n  dnl Ensure to expand the default settings once only, before all statements\n  dnl that occur in other macros.\n  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])\n\n  gl_CHECK_NEXT_HEADERS([unistd.h])\n  if test $ac_cv_header_unistd_h = yes; then\n    HAVE_UNISTD_H=1\n  else\n    HAVE_UNISTD_H=0\n  fi\n  AC_SUBST([HAVE_UNISTD_H])\n\n  dnl Ensure the type pid_t gets defined.\n  AC_REQUIRE([AC_TYPE_PID_T])\n\n  dnl Determine WINDOWS_64_BIT_OFF_T.\n  AC_REQUIRE([gl_TYPE_OFF_T])\n\n  dnl Check for declarations of anything we want to poison if the\n  dnl corresponding gnulib module is not in use.\n  gl_WARN_ON_USE_PREPARE([[\n#if HAVE_UNISTD_H\n# include <unistd.h>\n#endif\n/* Some systems declare various items in the wrong headers.  */\n#if !(defined __GLIBC__ && !defined __UCLIBC__)\n# include <fcntl.h>\n# include <stdio.h>\n# include <stdlib.h>\n# if defined _WIN32 && ! defined __CYGWIN__\n#  include <io.h>\n# endif\n#endif\n    ]], [access chdir chown copy_file_range dup dup2 dup3 environ euidaccess\n    execl execle execlp execv execve execvp execvpe\n    faccessat fchdir\n    fchownat fdatasync fsync ftruncate getcwd getdomainname getdtablesize\n    getentropy getgroups gethostname getlogin getlogin_r getpagesize getpass\n    getusershell setusershell endusershell\n    group_member isatty lchown link linkat lseek pipe pipe2 pread pwrite\n    readlink readlinkat rmdir sethostname sleep symlink symlinkat\n    truncate ttyname_r unlink unlinkat usleep])\n\n  AC_REQUIRE([AC_C_RESTRICT])\n\n  AC_CHECK_DECLS_ONCE([execvpe])\n  if test $ac_cv_have_decl_execvpe = no; then\n    HAVE_DECL_EXECVPE=0\n  fi\n])\n\n# gl_UNISTD_MODULE_INDICATOR([modulename])\n# sets the shell variable that indicates the presence of the given module\n# to a C preprocessor expression that will evaluate to 1.\n# This macro invocation must not occur in macros that are AC_REQUIREd.\nAC_DEFUN([gl_UNISTD_MODULE_INDICATOR],\n[\n  dnl Ensure to expand the default settings once only.\n  gl_UNISTD_H_REQUIRE_DEFAULTS\n  gl_MODULE_INDICATOR_SET_VARIABLE([$1])\n  dnl Define it also as a C macro, for the benefit of the unit tests.\n  gl_MODULE_INDICATOR_FOR_TESTS([$1])\n])\n\n# Initializes the default values for AC_SUBSTed shell variables.\n# This macro must not be AC_REQUIREd.  It must only be invoked, and only\n# outside of macros or in macros that are not AC_REQUIREd.\nAC_DEFUN([gl_UNISTD_H_REQUIRE_DEFAULTS],\n[\n  m4_defun(GL_MODULE_INDICATOR_PREFIX[_UNISTD_H_MODULE_INDICATOR_DEFAULTS], [\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCESS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHDIR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHOWN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CLOSE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_COPY_FILE_RANGE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP2])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP3])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ENVIRON])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EUIDACCESS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECLE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECLP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECV])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVPE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FACCESSAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHDIR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHOWNAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDATASYNC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSYNC])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTRUNCATE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCWD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDOMAINNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDTABLESIZE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETENTROPY])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETGROUPS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETHOSTNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOGIN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOGIN_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETOPT_POSIX])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAGESIZE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPASS])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETUSERSHELL])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GROUP_MEMBER])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISATTY])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LCHOWN])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LINK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LINKAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LSEEK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PIPE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PIPE2])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PREAD])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PWRITE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READ])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READLINK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READLINKAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RMDIR])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETHOSTNAME])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SLEEP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYMLINK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYMLINKAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCATE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TTYNAME_R])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_GETOPT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_NONBLOCKING])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_SIGPIPE])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLINK])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLINKAT])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_USLEEP])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WRITE])\n    dnl Support Microsoft deprecated alias function names by default.\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ACCESS], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CHDIR], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CLOSE], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_DUP], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_DUP2], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECL], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECLE], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECLP], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECV], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVE], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVP], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVPE], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETCWD], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETPID], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ISATTY], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LSEEK], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_READ], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_RMDIR], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_SWAB], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_UNLINK], [1])\n    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_WRITE], [1])\n  ])\n  m4_require(GL_MODULE_INDICATOR_PREFIX[_UNISTD_H_MODULE_INDICATOR_DEFAULTS])\n  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])\n])\n\nAC_DEFUN([gl_UNISTD_H_DEFAULTS],\n[\n  dnl Assume proper GNU behavior unless another module says otherwise.\n  HAVE_CHOWN=1;           AC_SUBST([HAVE_CHOWN])\n  HAVE_COPY_FILE_RANGE=1; AC_SUBST([HAVE_COPY_FILE_RANGE])\n  HAVE_DUP3=1;            AC_SUBST([HAVE_DUP3])\n  HAVE_EUIDACCESS=1;      AC_SUBST([HAVE_EUIDACCESS])\n  HAVE_EXECVPE=1;         AC_SUBST([HAVE_EXECVPE])\n  HAVE_FACCESSAT=1;       AC_SUBST([HAVE_FACCESSAT])\n  HAVE_FCHDIR=1;          AC_SUBST([HAVE_FCHDIR])\n  HAVE_FCHOWNAT=1;        AC_SUBST([HAVE_FCHOWNAT])\n  HAVE_FDATASYNC=1;       AC_SUBST([HAVE_FDATASYNC])\n  HAVE_FSYNC=1;           AC_SUBST([HAVE_FSYNC])\n  HAVE_FTRUNCATE=1;       AC_SUBST([HAVE_FTRUNCATE])\n  HAVE_GETDTABLESIZE=1;   AC_SUBST([HAVE_GETDTABLESIZE])\n  HAVE_GETENTROPY=1;      AC_SUBST([HAVE_GETENTROPY])\n  HAVE_GETGROUPS=1;       AC_SUBST([HAVE_GETGROUPS])\n  HAVE_GETHOSTNAME=1;     AC_SUBST([HAVE_GETHOSTNAME])\n  HAVE_GETLOGIN=1;        AC_SUBST([HAVE_GETLOGIN])\n  HAVE_GETPAGESIZE=1;     AC_SUBST([HAVE_GETPAGESIZE])\n  HAVE_GETPASS=1;         AC_SUBST([HAVE_GETPASS])\n  HAVE_GROUP_MEMBER=1;    AC_SUBST([HAVE_GROUP_MEMBER])\n  HAVE_LCHOWN=1;          AC_SUBST([HAVE_LCHOWN])\n  HAVE_LINK=1;            AC_SUBST([HAVE_LINK])\n  HAVE_LINKAT=1;          AC_SUBST([HAVE_LINKAT])\n  HAVE_PIPE=1;            AC_SUBST([HAVE_PIPE])\n  HAVE_PIPE2=1;           AC_SUBST([HAVE_PIPE2])\n  HAVE_PREAD=1;           AC_SUBST([HAVE_PREAD])\n  HAVE_PWRITE=1;          AC_SUBST([HAVE_PWRITE])\n  HAVE_READLINK=1;        AC_SUBST([HAVE_READLINK])\n  HAVE_READLINKAT=1;      AC_SUBST([HAVE_READLINKAT])\n  HAVE_SETHOSTNAME=1;     AC_SUBST([HAVE_SETHOSTNAME])\n  HAVE_SLEEP=1;           AC_SUBST([HAVE_SLEEP])\n  HAVE_SYMLINK=1;         AC_SUBST([HAVE_SYMLINK])\n  HAVE_SYMLINKAT=1;       AC_SUBST([HAVE_SYMLINKAT])\n  HAVE_UNLINKAT=1;        AC_SUBST([HAVE_UNLINKAT])\n  HAVE_USLEEP=1;          AC_SUBST([HAVE_USLEEP])\n  HAVE_DECL_ENVIRON=1;    AC_SUBST([HAVE_DECL_ENVIRON])\n  HAVE_DECL_EXECVPE=1;    AC_SUBST([HAVE_DECL_EXECVPE])\n  HAVE_DECL_FCHDIR=1;     AC_SUBST([HAVE_DECL_FCHDIR])\n  HAVE_DECL_FDATASYNC=1;  AC_SUBST([HAVE_DECL_FDATASYNC])\n  HAVE_DECL_GETDOMAINNAME=1; AC_SUBST([HAVE_DECL_GETDOMAINNAME])\n  HAVE_DECL_GETLOGIN=1;   AC_SUBST([HAVE_DECL_GETLOGIN])\n  HAVE_DECL_GETLOGIN_R=1; AC_SUBST([HAVE_DECL_GETLOGIN_R])\n  HAVE_DECL_GETPAGESIZE=1; AC_SUBST([HAVE_DECL_GETPAGESIZE])\n  HAVE_DECL_GETUSERSHELL=1; AC_SUBST([HAVE_DECL_GETUSERSHELL])\n  HAVE_DECL_SETHOSTNAME=1; AC_SUBST([HAVE_DECL_SETHOSTNAME])\n  HAVE_DECL_TRUNCATE=1;   AC_SUBST([HAVE_DECL_TRUNCATE])\n  HAVE_DECL_TTYNAME_R=1;  AC_SUBST([HAVE_DECL_TTYNAME_R])\n  HAVE_OS_H=0;            AC_SUBST([HAVE_OS_H])\n  HAVE_SYS_PARAM_H=0;     AC_SUBST([HAVE_SYS_PARAM_H])\n  REPLACE_ACCESS=0;       AC_SUBST([REPLACE_ACCESS])\n  REPLACE_CHOWN=0;        AC_SUBST([REPLACE_CHOWN])\n  REPLACE_CLOSE=0;        AC_SUBST([REPLACE_CLOSE])\n  REPLACE_DUP=0;          AC_SUBST([REPLACE_DUP])\n  REPLACE_DUP2=0;         AC_SUBST([REPLACE_DUP2])\n  REPLACE_EXECL=0;        AC_SUBST([REPLACE_EXECL])\n  REPLACE_EXECLE=0;       AC_SUBST([REPLACE_EXECLE])\n  REPLACE_EXECLP=0;       AC_SUBST([REPLACE_EXECLP])\n  REPLACE_EXECV=0;        AC_SUBST([REPLACE_EXECV])\n  REPLACE_EXECVE=0;       AC_SUBST([REPLACE_EXECVE])\n  REPLACE_EXECVP=0;       AC_SUBST([REPLACE_EXECVP])\n  REPLACE_EXECVPE=0;      AC_SUBST([REPLACE_EXECVPE])\n  REPLACE_FACCESSAT=0;    AC_SUBST([REPLACE_FACCESSAT])\n  REPLACE_FCHOWNAT=0;     AC_SUBST([REPLACE_FCHOWNAT])\n  REPLACE_FTRUNCATE=0;    AC_SUBST([REPLACE_FTRUNCATE])\n  REPLACE_GETCWD=0;       AC_SUBST([REPLACE_GETCWD])\n  REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME])\n  REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE])\n  REPLACE_GETLOGIN_R=0;   AC_SUBST([REPLACE_GETLOGIN_R])\n  REPLACE_GETGROUPS=0;    AC_SUBST([REPLACE_GETGROUPS])\n  REPLACE_GETPAGESIZE=0;  AC_SUBST([REPLACE_GETPAGESIZE])\n  REPLACE_GETPASS=0;      AC_SUBST([REPLACE_GETPASS])\n  REPLACE_ISATTY=0;       AC_SUBST([REPLACE_ISATTY])\n  REPLACE_LCHOWN=0;       AC_SUBST([REPLACE_LCHOWN])\n  REPLACE_LINK=0;         AC_SUBST([REPLACE_LINK])\n  REPLACE_LINKAT=0;       AC_SUBST([REPLACE_LINKAT])\n  REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])\n  REPLACE_PREAD=0;        AC_SUBST([REPLACE_PREAD])\n  REPLACE_PWRITE=0;       AC_SUBST([REPLACE_PWRITE])\n  REPLACE_READ=0;         AC_SUBST([REPLACE_READ])\n  REPLACE_READLINK=0;     AC_SUBST([REPLACE_READLINK])\n  REPLACE_READLINKAT=0;   AC_SUBST([REPLACE_READLINKAT])\n  REPLACE_RMDIR=0;        AC_SUBST([REPLACE_RMDIR])\n  REPLACE_SLEEP=0;        AC_SUBST([REPLACE_SLEEP])\n  REPLACE_SYMLINK=0;      AC_SUBST([REPLACE_SYMLINK])\n  REPLACE_SYMLINKAT=0;    AC_SUBST([REPLACE_SYMLINKAT])\n  REPLACE_TRUNCATE=0;     AC_SUBST([REPLACE_TRUNCATE])\n  REPLACE_TTYNAME_R=0;    AC_SUBST([REPLACE_TTYNAME_R])\n  REPLACE_UNLINK=0;       AC_SUBST([REPLACE_UNLINK])\n  REPLACE_UNLINKAT=0;     AC_SUBST([REPLACE_UNLINKAT])\n  REPLACE_USLEEP=0;       AC_SUBST([REPLACE_USLEEP])\n  REPLACE_WRITE=0;        AC_SUBST([REPLACE_WRITE])\n  UNISTD_H_HAVE_SYS_RANDOM_H=0; AC_SUBST([UNISTD_H_HAVE_SYS_RANDOM_H])\n  UNISTD_H_HAVE_WINSOCK2_H=0; AC_SUBST([UNISTD_H_HAVE_WINSOCK2_H])\n  UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS=0;\n                           AC_SUBST([UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/warn-on-use.m4",
    "content": "# warn-on-use.m4 serial 9\ndnl Copyright (C) 2010-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\n# gl_WARN_ON_USE_PREPARE(INCLUDES, NAMES)\n# ---------------------------------------\n# If the module 'posixcheck' is in use:\n#\n# For each whitespace-separated element in the list of NAMES, define\n# HAVE_RAW_DECL_name if the function has a declaration among INCLUDES\n# even after being undefined as a macro.\n#\n# See warn-on-use.h for some hints on how to poison function names, as\n# well as ideas on poisoning global variables and macros.  NAMES may\n# include global variables, but remember that only functions work with\n# _GL_WARN_ON_USE.  Typically, INCLUDES only needs to list a single\n# header, but if the replacement header pulls in other headers because\n# some systems declare functions in the wrong header, then INCLUDES\n# should do likewise.\n#\n# It is generally safe to assume declarations for functions declared\n# in the intersection of C89 and C11 (such as printf) without\n# needing gl_WARN_ON_USE_PREPARE.\nAC_DEFUN([gl_WARN_ON_USE_PREPARE],\n[\n  m4_ifdef([gl_POSIXCHECK],\n    [m4_foreach_w([gl_decl], [$2],\n       [AH_TEMPLATE([HAVE_RAW_DECL_]AS_TR_CPP(m4_defn([gl_decl])),\n         [Define to 1 if ]m4_defn([gl_decl])[ is declared even after\n          undefining macros.])])dnl\n     for gl_func in m4_flatten([$2]); do\n       AS_VAR_PUSHDEF([gl_Symbol], [gl_cv_have_raw_decl_$gl_func])dnl\n       AC_CACHE_CHECK([whether $gl_func is declared without a macro],\n         [gl_Symbol],\n         [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$1],\n[[#undef $gl_func\n  (void) $gl_func;]])],\n           [AS_VAR_SET([gl_Symbol], [yes])], [AS_VAR_SET([gl_Symbol], [no])])])\n       AS_VAR_IF([gl_Symbol], [yes],\n         [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_RAW_DECL_$gl_func]), [1])\n          dnl shortcut - if the raw declaration exists, then set a cache\n          dnl variable to allow skipping any later AC_CHECK_DECL efforts\n          eval ac_cv_have_decl_$gl_func=yes])\n       AS_VAR_POPDEF([gl_Symbol])dnl\n     done\n    ])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/wchar_t.m4",
    "content": "# wchar_t.m4 serial 4 (gettext-0.18.2)\ndnl Copyright (C) 2002-2003, 2008-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Bruno Haible.\ndnl Test whether <stddef.h> has the 'wchar_t' type.\ndnl Prerequisite: AC_PROG_CC\n\nAC_DEFUN([gt_TYPE_WCHAR_T],\n[\n  AC_CACHE_CHECK([for wchar_t], [gt_cv_c_wchar_t],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <stddef.h>\n            wchar_t foo = (wchar_t)'\\0';]],\n          [[]])],\n       [gt_cv_c_wchar_t=yes],\n       [gt_cv_c_wchar_t=no])])\n  if test $gt_cv_c_wchar_t = yes; then\n    AC_DEFINE([HAVE_WCHAR_T], [1], [Define if you have the 'wchar_t' type.])\n  fi\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/wint_t.m4",
    "content": "# wint_t.m4 serial 11\ndnl Copyright (C) 2003, 2007-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Bruno Haible.\ndnl Test whether <wchar.h> has the 'wint_t' type and whether gnulib's\ndnl <wchar.h> or <wctype.h> would, if present, override 'wint_t'.\ndnl Prerequisite: AC_PROG_CC\n\nAC_DEFUN([gt_TYPE_WINT_T],\n[\n  AC_CACHE_CHECK([for wint_t], [gt_cv_c_wint_t],\n    [AC_COMPILE_IFELSE(\n       [AC_LANG_PROGRAM(\n          [[#include <wchar.h>\n            wint_t foo = (wchar_t)'\\0';]],\n          [[]])],\n       [gt_cv_c_wint_t=yes],\n       [gt_cv_c_wint_t=no])])\n  if test $gt_cv_c_wint_t = yes; then\n    AC_DEFINE([HAVE_WINT_T], [1], [Define if you have the 'wint_t' type.])\n\n    dnl Determine whether gnulib's <wchar.h> or <wctype.h> would, if present,\n    dnl override 'wint_t'.\n    AC_CACHE_CHECK([whether wint_t is large enough],\n      [gl_cv_type_wint_t_large_enough],\n      [AC_COMPILE_IFELSE(\n         [AC_LANG_PROGRAM(\n            [[#include <wchar.h>\n              int verify[sizeof (wint_t) < sizeof (int) ? -1 : 1];\n            ]])],\n         [gl_cv_type_wint_t_large_enough=yes],\n         [gl_cv_type_wint_t_large_enough=no])])\n    if test $gl_cv_type_wint_t_large_enough = no; then\n      GNULIBHEADERS_OVERRIDE_WINT_T=1\n    else\n      GNULIBHEADERS_OVERRIDE_WINT_T=0\n    fi\n  else\n    GNULIBHEADERS_OVERRIDE_WINT_T=0\n  fi\n  AC_SUBST([GNULIBHEADERS_OVERRIDE_WINT_T])\n])\n\ndnl Prerequisites of the 'wint_t' override.\nAC_DEFUN([gl_TYPE_WINT_T_PREREQ],\n[\n  AC_CHECK_HEADERS_ONCE([crtdefs.h])\n  if test $ac_cv_header_crtdefs_h = yes; then\n    HAVE_CRTDEFS_H=1\n  else\n    HAVE_CRTDEFS_H=0\n  fi\n  AC_SUBST([HAVE_CRTDEFS_H])\n])\n"
  },
  {
    "path": "windows_compat/gnulib/glm4/zzgnulib.m4",
    "content": "# zzgnulib.m4 serial 1\ndnl Copyright (C) 2020-2021 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl This file must be named something that sorts after all other\ndnl package- or gnulib-provided .m4 files - at least for those packages\ndnl that redefine AC_PROG_CC.\n\ndnl Redefine AC_PROG_CC so that it ends with invocations of gl_COMPILER_CLANG\ndnl and gl_COMPILER_PREPARE_CHECK_DECL.\nm4_define([AC_PROG_CC],\n  m4_defn([AC_PROG_CC])[\ngl_COMPILER_CLANG\ngl_COMPILER_PREPARE_CHECK_DECL\n])\n\n# gl_ZZGNULIB\n# -----------\n# Witness macro that this file has been included.  Needed to force\n# Automake to include this file after all other gnulib .m4 files.\nAC_DEFUN([gl_ZZGNULIB])\n"
  },
  {
    "path": "windows_compat/notes.txt",
    "content": "gnulib modules needed:\ngetline: getline module\nuname: uname module\nlocaltime_r: time_r module, sys_time module\nbacktrace: execinfo module (provides a stub)\n<sys/resource.h>: sys_resource module\nmkdir: sys_stat module\ngettimeofday: gettimeofday module\n\ngnulib doesn't fix:\n<pwd.h>, getrlimit, getuid - Functions using these were disabled and edited to throw an error or warning in Windows  \nstrtoq not defined -- Instead I converted to strtoll\n\nLooks like I need to enable GNULIB_NAMESPACE for eidos to avoid linker errors\n- okay that is done and works.\n\nNow QtSLiM:\n- problem: automoc creates .cpp files with #include <memory> as the first line..\n  I somehow need to #include <config.h> from gnulib before this, to get the\n  correct gnulib defines...\n\ngnulib-tool command:\n/c/gnulib/gnulib-tool --create-testdir --dir=gnulib --without-tests --no-conditional-dependencies getline uname execinfo sys_resource sys_stat gettimeofday random time_r\n"
  }
]